summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore56
-rw-r--r--.style.cfg9
-rw-r--r--.style.yapf2
-rw-r--r--AUTHORS.txt35
-rw-r--r--BUILD.gn2340
-rw-r--r--CHROMIUM_BUILD_COMPATIBILITY.txt12
-rw-r--r--CHROMIUM_UPDATE.txt63
-rw-r--r--CMakeLists.txt.in255
-rw-r--r--DEPS7
-rw-r--r--Doxyfile2782
-rw-r--r--LICENSE254
-rw-r--r--LICENSE.txt29
-rw-r--r--METADATA21
-rw-r--r--MODULE_LICENSE_APACHE20
-rw-r--r--MODULE_LICENSE_BSD30
-rw-r--r--MODULE_LICENSE_MIT0
-rw-r--r--OWNERS2
-rw-r--r--README.md83
-rw-r--r--VERSION.in1
-rw-r--r--cef_create_projects.bat2
-rwxr-xr-xcef_create_projects.sh2
-rw-r--r--cef_paths.gypi881
-rw-r--r--cef_paths2.gypi663
-rw-r--r--cmake/FindCEF.cmake.in39
-rw-r--r--cmake/cef_macros.cmake.in387
-rw-r--r--cmake/cef_variables.cmake.in584
-rw-r--r--include/base/cef_atomic_flag.h97
-rw-r--r--include/base/cef_atomic_ref_count.h123
-rw-r--r--include/base/cef_auto_reset.h90
-rw-r--r--include/base/cef_basictypes.h86
-rw-r--r--include/base/cef_bind.h391
-rw-r--r--include/base/cef_build.h263
-rw-r--r--include/base/cef_callback.h250
-rw-r--r--include/base/cef_callback_forward.h63
-rw-r--r--include/base/cef_callback_helpers.h261
-rw-r--r--include/base/cef_callback_list.h403
-rw-r--r--include/base/cef_cancelable_callback.h195
-rw-r--r--include/base/cef_compiler_specific.h389
-rw-r--r--include/base/cef_lock.h182
-rw-r--r--include/base/cef_logging.h778
-rw-r--r--include/base/cef_macros.h63
-rw-r--r--include/base/cef_platform_thread.h111
-rw-r--r--include/base/cef_ptr_util.h60
-rw-r--r--include/base/cef_ref_counted.h512
-rw-r--r--include/base/cef_scoped_refptr.h420
-rw-r--r--include/base/cef_scoped_typeref_mac.h190
-rw-r--r--include/base/cef_template_util.h417
-rw-r--r--include/base/cef_thread_checker.h125
-rw-r--r--include/base/cef_trace_event.h463
-rw-r--r--include/base/cef_tuple.h152
-rw-r--r--include/base/cef_weak_ptr.h469
-rw-r--r--include/base/internal/cef_bind_internal.h1415
-rw-r--r--include/base/internal/cef_callback_internal.h275
-rw-r--r--include/base/internal/cef_lock_impl.h87
-rw-r--r--include/base/internal/cef_net_error_list.h8
-rw-r--r--include/base/internal/cef_raw_scoped_refptr_mismatch_checker.h75
-rw-r--r--include/base/internal/cef_scoped_block_mac.h67
-rw-r--r--include/base/internal/cef_scoped_policy.h53
-rw-r--r--include/base/internal/cef_thread_checker_impl.h72
-rw-r--r--include/capi/cef_accessibility_handler_capi.h81
-rw-r--r--include/capi/cef_app_capi.h190
-rw-r--r--include/capi/cef_audio_handler_capi.h121
-rw-r--r--include/capi/cef_auth_callback_capi.h76
-rw-r--r--include/capi/cef_base_capi.h107
-rw-r--r--include/capi/cef_browser_capi.h952
-rw-r--r--include/capi/cef_browser_process_handler_capi.h141
-rw-r--r--include/capi/cef_callback_capi.h88
-rw-r--r--include/capi/cef_client_capi.h210
-rw-r--r--include/capi/cef_command_handler_capi.h80
-rw-r--r--include/capi/cef_command_line_capi.h215
-rw-r--r--include/capi/cef_context_menu_handler_capi.h367
-rw-r--r--include/capi/cef_cookie_capi.h199
-rw-r--r--include/capi/cef_crash_util_capi.h154
-rw-r--r--include/capi/cef_devtools_message_observer_capi.h148
-rw-r--r--include/capi/cef_dialog_handler_capi.h111
-rw-r--r--include/capi/cef_display_handler_capi.h173
-rw-r--r--include/capi/cef_dom_capi.h346
-rw-r--r--include/capi/cef_download_handler_capi.h150
-rw-r--r--include/capi/cef_download_item_capi.h163
-rw-r--r--include/capi/cef_drag_data_capi.h233
-rw-r--r--include/capi/cef_drag_handler_capi.h92
-rw-r--r--include/capi/cef_extension_capi.h130
-rw-r--r--include/capi/cef_extension_handler_capi.h212
-rw-r--r--include/capi/cef_file_util_capi.h132
-rw-r--r--include/capi/cef_find_handler_capi.h82
-rw-r--r--include/capi/cef_focus_handler_capi.h93
-rw-r--r--include/capi/cef_frame_capi.h263
-rw-r--r--include/capi/cef_frame_handler_capi.h202
-rw-r--r--include/capi/cef_i18n_util_capi.h58
-rw-r--r--include/capi/cef_image_capi.h206
-rw-r--r--include/capi/cef_jsdialog_handler_capi.h141
-rw-r--r--include/capi/cef_keyboard_handler_capi.h90
-rw-r--r--include/capi/cef_life_span_handler_capi.h225
-rw-r--r--include/capi/cef_load_handler_capi.h126
-rw-r--r--include/capi/cef_media_access_handler_capi.h108
-rw-r--r--include/capi/cef_media_router_capi.h342
-rw-r--r--include/capi/cef_menu_model_capi.h517
-rw-r--r--include/capi/cef_menu_model_delegate_capi.h123
-rw-r--r--include/capi/cef_navigation_entry_capi.h133
-rw-r--r--include/capi/cef_origin_whitelist_capi.h112
-rw-r--r--include/capi/cef_parser_capi.h184
-rw-r--r--include/capi/cef_path_util_capi.h59
-rw-r--r--include/capi/cef_permission_handler_capi.h164
-rw-r--r--include/capi/cef_preference_capi.h148
-rw-r--r--include/capi/cef_preference_manager_capi.h116
-rw-r--r--include/capi/cef_print_handler_capi.h160
-rw-r--r--include/capi/cef_print_settings_capi.h202
-rw-r--r--include/capi/cef_process_message_capi.h111
-rw-r--r--include/capi/cef_process_util_capi.h65
-rw-r--r--include/capi/cef_registration_capi.h63
-rw-r--r--include/capi/cef_render_handler_capi.h261
-rw-r--r--include/capi/cef_render_process_handler_capi.h168
-rw-r--r--include/capi/cef_request_capi.h355
-rw-r--r--include/capi/cef_request_context_capi.h331
-rw-r--r--include/capi/cef_request_context_handler_capi.h108
-rw-r--r--include/capi/cef_request_handler_capi.h247
-rw-r--r--include/capi/cef_resource_bundle_capi.h104
-rw-r--r--include/capi/cef_resource_bundle_handler_capi.h105
-rw-r--r--include/capi/cef_resource_handler_capi.h210
-rw-r--r--include/capi/cef_resource_request_handler_capi.h255
-rw-r--r--include/capi/cef_response_capi.h177
-rw-r--r--include/capi/cef_response_filter_capi.h110
-rw-r--r--include/capi/cef_scheme_capi.h140
-rw-r--r--include/capi/cef_server_capi.h328
-rw-r--r--include/capi/cef_shared_memory_region_capi.h79
-rw-r--r--include/capi/cef_shared_process_message_builder_capi.h101
-rw-r--r--include/capi/cef_ssl_info_capi.h82
-rw-r--r--include/capi/cef_ssl_status_capi.h95
-rw-r--r--include/capi/cef_stream_capi.h263
-rw-r--r--include/capi/cef_string_visitor_capi.h69
-rw-r--r--include/capi/cef_task_capi.h158
-rw-r--r--include/capi/cef_thread_capi.h117
-rw-r--r--include/capi/cef_trace_capi.h118
-rw-r--r--include/capi/cef_urlrequest_capi.h211
-rw-r--r--include/capi/cef_v8_capi.h1014
-rw-r--r--include/capi/cef_values_capi.h755
-rw-r--r--include/capi/cef_waitable_event_capi.h117
-rw-r--r--include/capi/cef_x509_certificate_capi.h213
-rw-r--r--include/capi/cef_xml_reader_capi.h274
-rw-r--r--include/capi/cef_zip_reader_capi.h148
-rw-r--r--include/capi/test/cef_test_helpers_capi.h74
-rw-r--r--include/capi/test/cef_test_server_capi.h197
-rw-r--r--include/capi/test/cef_translator_test_capi.h763
-rw-r--r--include/capi/views/cef_box_layout_capi.h88
-rw-r--r--include/capi/views/cef_browser_view_capi.h117
-rw-r--r--include/capi/views/cef_browser_view_delegate_capi.h129
-rw-r--r--include/capi/views/cef_button_capi.h104
-rw-r--r--include/capi/views/cef_button_delegate_capi.h80
-rw-r--r--include/capi/views/cef_display_capi.h175
-rw-r--r--include/capi/views/cef_fill_layout_capi.h65
-rw-r--r--include/capi/views/cef_label_button_capi.h162
-rw-r--r--include/capi/views/cef_layout_capi.h85
-rw-r--r--include/capi/views/cef_menu_button_capi.h99
-rw-r--r--include/capi/views/cef_menu_button_delegate_capi.h89
-rw-r--r--include/capi/views/cef_overlay_controller_capi.h217
-rw-r--r--include/capi/views/cef_panel_capi.h151
-rw-r--r--include/capi/views/cef_panel_delegate_capi.h65
-rw-r--r--include/capi/views/cef_scroll_view_capi.h112
-rw-r--r--include/capi/views/cef_textfield_capi.h274
-rw-r--r--include/capi/views/cef_textfield_delegate_capi.h83
-rw-r--r--include/capi/views/cef_view_capi.h413
-rw-r--r--include/capi/views/cef_view_delegate_capi.h149
-rw-r--r--include/capi/views/cef_window_capi.h349
-rw-r--r--include/capi/views/cef_window_delegate_capi.h207
-rw-r--r--include/cef_accessibility_handler.h66
-rw-r--r--include/cef_api_hash.h71
-rw-r--r--include/cef_app.h190
-rw-r--r--include/cef_application_mac.h110
-rw-r--r--include/cef_audio_handler.h111
-rw-r--r--include/cef_auth_callback.h64
-rw-r--r--include/cef_base.h149
-rw-r--r--include/cef_browser.h946
-rw-r--r--include/cef_browser_process_handler.h127
-rw-r--r--include/cef_callback.h75
-rw-r--r--include/cef_client.h202
-rw-r--r--include/cef_command_handler.h68
-rw-r--r--include/cef_command_line.h210
-rw-r--r--include/cef_context_menu_handler.h347
-rw-r--r--include/cef_cookie.h179
-rw-r--r--include/cef_crash_util.h145
-rw-r--r--include/cef_devtools_message_observer.h132
-rw-r--r--include/cef_dialog_handler.h100
-rw-r--r--include/cef_display_handler.h163
-rw-r--r--include/cef_dom.h333
-rw-r--r--include/cef_download_handler.h134
-rw-r--r--include/cef_download_item.h154
-rw-r--r--include/cef_drag_data.h225
-rw-r--r--include/cef_drag_handler.h82
-rw-r--r--include/cef_extension.h118
-rw-r--r--include/cef_extension_handler.h200
-rw-r--r--include/cef_file_util.h130
-rw-r--r--include/cef_find_handler.h68
-rw-r--r--include/cef_focus_handler.h81
-rw-r--r--include/cef_frame.h263
-rw-r--r--include/cef_frame_handler.h177
-rw-r--r--include/cef_i18n_util.h49
-rw-r--r--include/cef_image.h192
-rw-r--r--include/cef_jsdialog_handler.h127
-rw-r--r--include/cef_keyboard_handler.h80
-rw-r--r--include/cef_life_span_handler.h214
-rw-r--r--include/cef_load_handler.h117
-rw-r--r--include/cef_media_router.h317
-rw-r--r--include/cef_menu_model.h491
-rw-r--r--include/cef_menu_model_delegate.h108
-rw-r--r--include/cef_navigation_entry.h121
-rw-r--r--include/cef_origin_whitelist.h103
-rw-r--r--include/cef_parser.h175
-rw-r--r--include/cef_path_util.h52
-rw-r--r--include/cef_permission_handler.h149
-rw-r--r--include/cef_preference.h134
-rw-r--r--include/cef_print_handler.h142
-rw-r--r--include/cef_print_settings.h201
-rw-r--r--include/cef_process_message.h101
-rw-r--r--include/cef_process_util.h57
-rw-r--r--include/cef_registration.h49
-rw-r--r--include/cef_render_handler.h255
-rw-r--r--include/cef_render_process_handler.h150
-rw-r--r--include/cef_request.h354
-rw-r--r--include/cef_request_context.h319
-rw-r--r--include/cef_request_context_handler.h96
-rw-r--r--include/cef_request_handler.h241
-rw-r--r--include/cef_resource_bundle.h91
-rw-r--r--include/cef_resource_bundle_handler.h90
-rw-r--r--include/cef_resource_handler.h206
-rw-r--r--include/cef_resource_request_handler.h250
-rw-r--r--include/cef_response.h167
-rw-r--r--include/cef_response_filter.h99
-rw-r--r--include/cef_sandbox_mac.h93
-rw-r--r--include/cef_sandbox_win.h91
-rw-r--r--include/cef_scheme.h122
-rw-r--r--include/cef_server.h316
-rw-r--r--include/cef_shared_memory_region.h69
-rw-r--r--include/cef_shared_process_message_builder.h87
-rw-r--r--include/cef_ssl_info.h72
-rw-r--r--include/cef_ssl_status.h83
-rw-r--r--include/cef_stream.h241
-rw-r--r--include/cef_string_visitor.h55
-rw-r--r--include/cef_task.h148
-rw-r--r--include/cef_thread.h117
-rw-r--r--include/cef_trace.h111
-rw-r--r--include/cef_urlrequest.h198
-rw-r--r--include/cef_v8.h1038
-rw-r--r--include/cef_values.h750
-rw-r--r--include/cef_waitable_event.h109
-rw-r--r--include/cef_x509_certificate.h188
-rw-r--r--include/cef_xml_reader.h266
-rw-r--r--include/cef_zip_reader.h140
-rw-r--r--include/internal/cef_app_win.h107
-rw-r--r--include/internal/cef_export.h59
-rw-r--r--include/internal/cef_linux.h116
-rw-r--r--include/internal/cef_logging_internal.h68
-rw-r--r--include/internal/cef_mac.h118
-rw-r--r--include/internal/cef_ptr.h176
-rw-r--r--include/internal/cef_string.h112
-rw-r--r--include/internal/cef_string_list.h89
-rw-r--r--include/internal/cef_string_map.h98
-rw-r--r--include/internal/cef_string_multimap.h106
-rw-r--r--include/internal/cef_string_types.h212
-rw-r--r--include/internal/cef_string_wrappers.h865
-rw-r--r--include/internal/cef_thread_internal.h78
-rw-r--r--include/internal/cef_time.h152
-rw-r--r--include/internal/cef_time_wrappers.h111
-rw-r--r--include/internal/cef_trace_event_internal.h124
-rw-r--r--include/internal/cef_types.h3450
-rw-r--r--include/internal/cef_types_geometry.h78
-rw-r--r--include/internal/cef_types_linux.h146
-rw-r--r--include/internal/cef_types_mac.h145
-rw-r--r--include/internal/cef_types_win.h113
-rw-r--r--include/internal/cef_types_wrappers.h742
-rw-r--r--include/internal/cef_win.h184
-rw-r--r--include/test/cef_test_helpers.h70
-rw-r--r--include/test/cef_test_server.h184
-rw-r--r--include/test/cef_translator_test.h808
-rw-r--r--include/views/cef_box_layout.h74
-rw-r--r--include/views/cef_browser_view.h107
-rw-r--r--include/views/cef_browser_view_delegate.h119
-rw-r--r--include/views/cef_button.h92
-rw-r--r--include/views/cef_button_delegate.h65
-rw-r--r--include/views/cef_display.h172
-rw-r--r--include/views/cef_fill_layout.h51
-rw-r--r--include/views/cef_label_button.h149
-rw-r--r--include/views/cef_layout.h73
-rw-r--r--include/views/cef_menu_button.h88
-rw-r--r--include/views/cef_menu_button_delegate.h72
-rw-r--r--include/views/cef_overlay_controller.h210
-rw-r--r--include/views/cef_panel.h141
-rw-r--r--include/views/cef_panel_delegate.h50
-rw-r--r--include/views/cef_scroll_view.h102
-rw-r--r--include/views/cef_textfield.h269
-rw-r--r--include/views/cef_textfield_delegate.h71
-rw-r--r--include/views/cef_view.h427
-rw-r--r--include/views/cef_view_delegate.h136
-rw-r--r--include/views/cef_window.h353
-rw-r--r--include/views/cef_window_delegate.h201
-rw-r--r--include/wrapper/cef_byte_read_handler.h80
-rw-r--r--include/wrapper/cef_closure_task.h117
-rw-r--r--include/wrapper/cef_helpers.h165
-rw-r--r--include/wrapper/cef_library_loader.h133
-rw-r--r--include/wrapper/cef_message_router.h439
-rw-r--r--include/wrapper/cef_resource_manager.h374
-rw-r--r--include/wrapper/cef_scoped_temp_dir.h118
-rw-r--r--include/wrapper/cef_stream_resource_handler.h89
-rw-r--r--include/wrapper/cef_xml_object.h195
-rw-r--r--include/wrapper/cef_zip_archive.h143
-rw-r--r--libcef/browser/alloy/alloy_browser_context.cc486
-rw-r--r--libcef/browser/alloy/alloy_browser_context.h152
-rw-r--r--libcef/browser/alloy/alloy_browser_host_impl.cc1528
-rw-r--r--libcef/browser/alloy/alloy_browser_host_impl.h348
-rw-r--r--libcef/browser/alloy/alloy_browser_main.cc350
-rw-r--r--libcef/browser/alloy/alloy_browser_main.h104
-rw-r--r--libcef/browser/alloy/alloy_browser_main_win.cc27
-rw-r--r--libcef/browser/alloy/alloy_content_browser_client.cc1419
-rw-r--r--libcef/browser/alloy/alloy_content_browser_client.h264
-rw-r--r--libcef/browser/alloy/alloy_download_util.cc16
-rw-r--r--libcef/browser/alloy/alloy_download_util.h23
-rw-r--r--libcef/browser/alloy/alloy_web_contents_view_delegate.cc22
-rw-r--r--libcef/browser/alloy/alloy_web_contents_view_delegate.h33
-rw-r--r--libcef/browser/alloy/browser_platform_delegate_alloy.cc450
-rw-r--r--libcef/browser/alloy/browser_platform_delegate_alloy.h121
-rw-r--r--libcef/browser/alloy/chrome_browser_process_alloy.cc428
-rw-r--r--libcef/browser/alloy/chrome_browser_process_alloy.h141
-rw-r--r--libcef/browser/alloy/chrome_profile_alloy.cc168
-rw-r--r--libcef/browser/alloy/chrome_profile_alloy.h61
-rw-r--r--libcef/browser/alloy/chrome_profile_manager_alloy.cc59
-rw-r--r--libcef/browser/alloy/chrome_profile_manager_alloy.h28
-rw-r--r--libcef/browser/alloy/dialogs/alloy_constrained_window_views_client.cc76
-rw-r--r--libcef/browser/alloy/dialogs/alloy_constrained_window_views_client.h17
-rw-r--r--libcef/browser/alloy/dialogs/alloy_javascript_dialog_manager_delegate.cc58
-rw-r--r--libcef/browser/alloy/dialogs/alloy_javascript_dialog_manager_delegate.h18
-rw-r--r--libcef/browser/alloy/dialogs/alloy_web_contents_dialog_helper.cc98
-rw-r--r--libcef/browser/alloy/dialogs/alloy_web_contents_dialog_helper.h52
-rw-r--r--libcef/browser/audio_capturer.cc132
-rw-r--r--libcef/browser/audio_capturer.h51
-rw-r--r--libcef/browser/audio_loopback_stream_creator.cc135
-rw-r--r--libcef/browser/audio_loopback_stream_creator.h53
-rw-r--r--libcef/browser/browser_contents_delegate.cc720
-rw-r--r--libcef/browser/browser_contents_delegate.h206
-rw-r--r--libcef/browser/browser_context.cc445
-rw-r--r--libcef/browser/browser_context.h243
-rw-r--r--libcef/browser/browser_context_keyed_service_factories.cc45
-rw-r--r--libcef/browser/browser_context_keyed_service_factories.h17
-rw-r--r--libcef/browser/browser_frame.cc82
-rw-r--r--libcef/browser/browser_frame.h55
-rw-r--r--libcef/browser/browser_host_base.cc1137
-rw-r--r--libcef/browser/browser_host_base.h382
-rw-r--r--libcef/browser/browser_host_create.cc174
-rw-r--r--libcef/browser/browser_info.cc563
-rw-r--r--libcef/browser/browser_info.h259
-rw-r--r--libcef/browser/browser_info_manager.cc629
-rw-r--r--libcef/browser/browser_info_manager.h263
-rw-r--r--libcef/browser/browser_manager.cc58
-rw-r--r--libcef/browser/browser_manager.h56
-rw-r--r--libcef/browser/browser_message_loop.cc128
-rw-r--r--libcef/browser/browser_message_loop.h10
-rw-r--r--libcef/browser/browser_platform_delegate.cc454
-rw-r--r--libcef/browser/browser_platform_delegate.h386
-rw-r--r--libcef/browser/browser_platform_delegate_create.cc143
-rw-r--r--libcef/browser/browser_util.cc73
-rw-r--r--libcef/browser/browser_util.h30
-rw-r--r--libcef/browser/certificate_query.cc130
-rw-r--r--libcef/browser/certificate_query.h42
-rw-r--r--libcef/browser/chrome/browser_delegate.h80
-rw-r--r--libcef/browser/chrome/browser_platform_delegate_chrome.cc148
-rw-r--r--libcef/browser/chrome/browser_platform_delegate_chrome.h66
-rw-r--r--libcef/browser/chrome/chrome_browser_context.cc184
-rw-r--r--libcef/browser/chrome/chrome_browser_context.h55
-rw-r--r--libcef/browser/chrome/chrome_browser_delegate.cc358
-rw-r--r--libcef/browser/chrome/chrome_browser_delegate.h119
-rw-r--r--libcef/browser/chrome/chrome_browser_host_impl.cc566
-rw-r--r--libcef/browser/chrome/chrome_browser_host_impl.h162
-rw-r--r--libcef/browser/chrome/chrome_browser_main_extra_parts_cef.cc52
-rw-r--r--libcef/browser/chrome/chrome_browser_main_extra_parts_cef.h57
-rw-r--r--libcef/browser/chrome/chrome_content_browser_client_cef.cc502
-rw-r--r--libcef/browser/chrome/chrome_content_browser_client_cef.h137
-rw-r--r--libcef/browser/chrome/chrome_context_menu_handler.cc214
-rw-r--r--libcef/browser/chrome/chrome_context_menu_handler.h16
-rw-r--r--libcef/browser/chrome/extensions/chrome_mime_handler_view_guest_delegate_cef.cc48
-rw-r--r--libcef/browser/chrome/extensions/chrome_mime_handler_view_guest_delegate_cef.h37
-rw-r--r--libcef/browser/chrome/views/browser_platform_delegate_chrome_child_window.cc29
-rw-r--r--libcef/browser/chrome/views/browser_platform_delegate_chrome_child_window.h29
-rw-r--r--libcef/browser/chrome/views/browser_platform_delegate_chrome_views.cc175
-rw-r--r--libcef/browser/chrome/views/browser_platform_delegate_chrome_views.h48
-rw-r--r--libcef/browser/chrome/views/chrome_browser_frame.cc35
-rw-r--r--libcef/browser/chrome/views/chrome_browser_frame.h109
-rw-r--r--libcef/browser/chrome/views/chrome_browser_view.cc99
-rw-r--r--libcef/browser/chrome/views/chrome_browser_view.h67
-rw-r--r--libcef/browser/chrome/views/chrome_child_window.cc203
-rw-r--r--libcef/browser/chrome/views/chrome_child_window.h24
-rw-r--r--libcef/browser/chrome/views/chrome_views_util.cc15
-rw-r--r--libcef/browser/chrome/views/chrome_views_util.h20
-rw-r--r--libcef/browser/chrome/views/toolbar_view_impl.cc40
-rw-r--r--libcef/browser/chrome/views/toolbar_view_impl.h57
-rw-r--r--libcef/browser/chrome/views/toolbar_view_view.cc11
-rw-r--r--libcef/browser/chrome/views/toolbar_view_view.h27
-rw-r--r--libcef/browser/chrome_crash_reporter_client_stub.cc15
-rw-r--r--libcef/browser/context.cc624
-rw-r--r--libcef/browser/context.h123
-rw-r--r--libcef/browser/context_menu_params_impl.cc158
-rw-r--r--libcef/browser/context_menu_params_impl.h46
-rw-r--r--libcef/browser/devtools/devtools_controller.cc143
-rw-r--r--libcef/browser/devtools/devtools_controller.h81
-rw-r--r--libcef/browser/devtools/devtools_file_manager.cc206
-rw-r--r--libcef/browser/devtools/devtools_file_manager.h82
-rw-r--r--libcef/browser/devtools/devtools_frontend.cc665
-rw-r--r--libcef/browser/devtools/devtools_frontend.h114
-rw-r--r--libcef/browser/devtools/devtools_manager.cc216
-rw-r--r--libcef/browser/devtools/devtools_manager.h71
-rw-r--r--libcef/browser/devtools/devtools_manager_delegate.cc145
-rw-r--r--libcef/browser/devtools/devtools_manager_delegate.h35
-rw-r--r--libcef/browser/devtools/devtools_util.cc141
-rw-r--r--libcef/browser/devtools/devtools_util.h72
-rw-r--r--libcef/browser/devtools/devtools_util_unittest.cc220
-rw-r--r--libcef/browser/download_item_impl.cc105
-rw-r--r--libcef/browser/download_item_impl.h45
-rw-r--r--libcef/browser/download_manager_delegate.cc485
-rw-r--r--libcef/browser/download_manager_delegate.h67
-rw-r--r--libcef/browser/extension_impl.cc117
-rw-r--r--libcef/browser/extension_impl.h60
-rw-r--r--libcef/browser/extensions/alloy_extensions_util.cc21
-rw-r--r--libcef/browser/extensions/alloy_extensions_util.h21
-rw-r--r--libcef/browser/extensions/api/file_system/cef_file_system_delegate.cc89
-rw-r--r--libcef/browser/extensions/api/file_system/cef_file_system_delegate.h58
-rw-r--r--libcef/browser/extensions/api/storage/sync_value_store_cache.cc105
-rw-r--r--libcef/browser/extensions/api/storage/sync_value_store_cache.h60
-rw-r--r--libcef/browser/extensions/api/tabs/tabs_api.cc544
-rw-r--r--libcef/browser/extensions/api/tabs/tabs_api.h187
-rw-r--r--libcef/browser/extensions/browser_extensions_util.cc180
-rw-r--r--libcef/browser/extensions/browser_extensions_util.h70
-rw-r--r--libcef/browser/extensions/browser_platform_delegate_background.cc121
-rw-r--r--libcef/browser/extensions/browser_platform_delegate_background.h55
-rw-r--r--libcef/browser/extensions/chrome_api_registration.cc114
-rw-r--r--libcef/browser/extensions/chrome_api_registration.h29
-rw-r--r--libcef/browser/extensions/component_extension_resource_manager.cc81
-rw-r--r--libcef/browser/extensions/component_extension_resource_manager.h54
-rw-r--r--libcef/browser/extensions/extension_background_host.cc46
-rw-r--r--libcef/browser/extensions/extension_background_host.h50
-rw-r--r--libcef/browser/extensions/extension_function_details.cc475
-rw-r--r--libcef/browser/extensions/extension_function_details.h151
-rw-r--r--libcef/browser/extensions/extension_host_delegate.cc72
-rw-r--r--libcef/browser/extensions/extension_host_delegate.h47
-rw-r--r--libcef/browser/extensions/extension_system.cc725
-rw-r--r--libcef/browser/extensions/extension_system.h201
-rw-r--r--libcef/browser/extensions/extension_system_factory.cc55
-rw-r--r--libcef/browser/extensions/extension_system_factory.h42
-rw-r--r--libcef/browser/extensions/extension_view_host.cc100
-rw-r--r--libcef/browser/extensions/extension_view_host.h67
-rw-r--r--libcef/browser/extensions/extension_web_contents_observer.cc60
-rw-r--r--libcef/browser/extensions/extension_web_contents_observer.h50
-rw-r--r--libcef/browser/extensions/extensions_api_client.cc84
-rw-r--r--libcef/browser/extensions/extensions_api_client.h47
-rw-r--r--libcef/browser/extensions/extensions_browser_api_provider.cc27
-rw-r--r--libcef/browser/extensions/extensions_browser_api_provider.h28
-rw-r--r--libcef/browser/extensions/extensions_browser_client.cc416
-rw-r--r--libcef/browser/extensions/extensions_browser_client.h134
-rw-r--r--libcef/browser/extensions/mime_handler_view_guest_delegate.cc76
-rw-r--r--libcef/browser/extensions/mime_handler_view_guest_delegate.h44
-rw-r--r--libcef/browser/extensions/value_store/cef_value_store.cc141
-rw-r--r--libcef/browser/extensions/value_store/cef_value_store.h65
-rw-r--r--libcef/browser/extensions/value_store/cef_value_store_factory.cc75
-rw-r--r--libcef/browser/extensions/value_store/cef_value_store_factory.h61
-rw-r--r--libcef/browser/file_dialog_manager.cc572
-rw-r--r--libcef/browser/file_dialog_manager.h99
-rw-r--r--libcef/browser/file_dialog_runner.cc165
-rw-r--r--libcef/browser/file_dialog_runner.h17
-rw-r--r--libcef/browser/frame_host_impl.cc730
-rw-r--r--libcef/browser/frame_host_impl.h197
-rw-r--r--libcef/browser/frame_service_base.h126
-rw-r--r--libcef/browser/global_preference_manager_impl.cc54
-rw-r--r--libcef/browser/global_preference_manager_impl.h35
-rw-r--r--libcef/browser/gpu/external_texture_manager.cc341
-rw-r--r--libcef/browser/gpu/external_texture_manager.h46
-rw-r--r--libcef/browser/image_impl.cc427
-rw-r--r--libcef/browser/image_impl.h129
-rw-r--r--libcef/browser/iothread_state.cc129
-rw-r--r--libcef/browser/iothread_state.h68
-rw-r--r--libcef/browser/javascript_dialog_manager.cc311
-rw-r--r--libcef/browser/javascript_dialog_manager.h75
-rw-r--r--libcef/browser/javascript_dialog_runner.h46
-rw-r--r--libcef/browser/main_runner.cc541
-rw-r--r--libcef/browser/main_runner.h95
-rw-r--r--libcef/browser/media_access_query.cc359
-rw-r--r--libcef/browser/media_access_query.h37
-rw-r--r--libcef/browser/media_capture_devices_dispatcher.cc133
-rw-r--r--libcef/browser/media_capture_devices_dispatcher.h70
-rw-r--r--libcef/browser/media_router/media_route_impl.cc89
-rw-r--r--libcef/browser/media_router/media_route_impl.h42
-rw-r--r--libcef/browser/media_router/media_router_impl.cc335
-rw-r--r--libcef/browser/media_router/media_router_impl.h66
-rw-r--r--libcef/browser/media_router/media_router_manager.cc303
-rw-r--r--libcef/browser/media_router/media_router_manager.h128
-rw-r--r--libcef/browser/media_router/media_sink_impl.cc139
-rw-r--r--libcef/browser/media_router/media_sink_impl.h43
-rw-r--r--libcef/browser/media_router/media_source_impl.cc24
-rw-r--r--libcef/browser/media_router/media_source_impl.h36
-rw-r--r--libcef/browser/media_stream_registrar.cc110
-rw-r--r--libcef/browser/media_stream_registrar.h56
-rw-r--r--libcef/browser/menu_manager.cc507
-rw-r--r--libcef/browser/menu_manager.h81
-rw-r--r--libcef/browser/menu_model_impl.cc1117
-rw-r--r--libcef/browser/menu_model_impl.h237
-rw-r--r--libcef/browser/menu_runner.h38
-rw-r--r--libcef/browser/native/browser_platform_delegate_native.cc29
-rw-r--r--libcef/browser/native/browser_platform_delegate_native.h75
-rw-r--r--libcef/browser/native/browser_platform_delegate_native_aura.cc300
-rw-r--r--libcef/browser/native/browser_platform_delegate_native_aura.h96
-rw-r--r--libcef/browser/native/browser_platform_delegate_native_linux.cc299
-rw-r--r--libcef/browser/native/browser_platform_delegate_native_linux.h52
-rw-r--r--libcef/browser/native/browser_platform_delegate_native_mac.h73
-rw-r--r--libcef/browser/native/browser_platform_delegate_native_mac.mm661
-rw-r--r--libcef/browser/native/browser_platform_delegate_native_win.cc706
-rw-r--r--libcef/browser/native/browser_platform_delegate_native_win.h56
-rw-r--r--libcef/browser/native/cursor_util.cc42
-rw-r--r--libcef/browser/native/cursor_util.h38
-rw-r--r--libcef/browser/native/cursor_util_aura.cc153
-rw-r--r--libcef/browser/native/cursor_util_mac.mm38
-rw-r--r--libcef/browser/native/javascript_dialog_runner_mac.h49
-rw-r--r--libcef/browser/native/javascript_dialog_runner_mac.mm188
-rw-r--r--libcef/browser/native/menu_runner_mac.h34
-rw-r--r--libcef/browser/native/menu_runner_mac.mm92
-rw-r--r--libcef/browser/native/menu_runner_views_aura.cc53
-rw-r--r--libcef/browser/native/menu_runner_views_aura.h28
-rw-r--r--libcef/browser/native/window_delegate_view.cc98
-rw-r--r--libcef/browser/native/window_delegate_view.h60
-rw-r--r--libcef/browser/native/window_x11.cc475
-rw-r--r--libcef/browser/native/window_x11.h97
-rw-r--r--libcef/browser/navigation_entry_impl.cc71
-rw-r--r--libcef/browser/navigation_entry_impl.h38
-rw-r--r--libcef/browser/net/chrome_scheme_handler.cc724
-rw-r--r--libcef/browser/net/chrome_scheme_handler.h44
-rw-r--r--libcef/browser/net/crlset_file_util_impl.cc46
-rw-r--r--libcef/browser/net/devtools_scheme_handler.cc50
-rw-r--r--libcef/browser/net/devtools_scheme_handler.h20
-rw-r--r--libcef/browser/net/internal_scheme_handler.cc220
-rw-r--r--libcef/browser/net/internal_scheme_handler.h59
-rw-r--r--libcef/browser/net/scheme_handler.cc26
-rw-r--r--libcef/browser/net/scheme_handler.h23
-rw-r--r--libcef/browser/net/throttle_handler.cc103
-rw-r--r--libcef/browser/net/throttle_handler.h27
-rw-r--r--libcef/browser/net_service/browser_urlrequest_impl.cc702
-rw-r--r--libcef/browser/net_service/browser_urlrequest_impl.h61
-rw-r--r--libcef/browser/net_service/cookie_helper.cc321
-rw-r--r--libcef/browser/net_service/cookie_helper.h65
-rw-r--r--libcef/browser/net_service/cookie_manager_impl.cc409
-rw-r--r--libcef/browser/net_service/cookie_manager_impl.h69
-rw-r--r--libcef/browser/net_service/login_delegate.cc174
-rw-r--r--libcef/browser/net_service/login_delegate.h50
-rw-r--r--libcef/browser/net_service/proxy_url_loader_factory.cc1439
-rw-r--r--libcef/browser/net_service/proxy_url_loader_factory.h229
-rw-r--r--libcef/browser/net_service/resource_handler_wrapper.cc523
-rw-r--r--libcef/browser/net_service/resource_handler_wrapper.h24
-rw-r--r--libcef/browser/net_service/resource_request_handler_wrapper.cc1432
-rw-r--r--libcef/browser/net_service/resource_request_handler_wrapper.h50
-rw-r--r--libcef/browser/net_service/response_filter_wrapper.cc302
-rw-r--r--libcef/browser/net_service/response_filter_wrapper.h27
-rw-r--r--libcef/browser/net_service/stream_reader_url_loader.cc855
-rw-r--r--libcef/browser/net_service/stream_reader_url_loader.h194
-rw-r--r--libcef/browser/net_service/url_loader_factory_getter.cc136
-rw-r--r--libcef/browser/net_service/url_loader_factory_getter.h79
-rw-r--r--libcef/browser/origin_whitelist_impl.cc311
-rw-r--r--libcef/browser/origin_whitelist_impl.h35
-rw-r--r--libcef/browser/osr/browser_platform_delegate_osr.cc658
-rw-r--r--libcef/browser/osr/browser_platform_delegate_osr.h135
-rw-r--r--libcef/browser/osr/browser_platform_delegate_osr_linux.cc19
-rw-r--r--libcef/browser/osr/browser_platform_delegate_osr_linux.h22
-rw-r--r--libcef/browser/osr/browser_platform_delegate_osr_mac.h20
-rw-r--r--libcef/browser/osr/browser_platform_delegate_osr_mac.mm17
-rw-r--r--libcef/browser/osr/browser_platform_delegate_osr_win.cc19
-rw-r--r--libcef/browser/osr/browser_platform_delegate_osr_win.h22
-rw-r--r--libcef/browser/osr/host_display_client_osr.cc143
-rw-r--r--libcef/browser/osr/host_display_client_osr.h49
-rw-r--r--libcef/browser/osr/motion_event_osr.cc259
-rw-r--r--libcef/browser/osr/motion_event_osr.h61
-rw-r--r--libcef/browser/osr/osr_accessibility_util.cc558
-rw-r--r--libcef/browser/osr/osr_accessibility_util.h29
-rw-r--r--libcef/browser/osr/osr_util.cc24
-rw-r--r--libcef/browser/osr/osr_util.h14
-rw-r--r--libcef/browser/osr/render_widget_host_view_osr.cc1831
-rw-r--r--libcef/browser/osr/render_widget_host_view_osr.h457
-rw-r--r--libcef/browser/osr/software_output_device_proxy.cc151
-rw-r--r--libcef/browser/osr/software_output_device_proxy.h56
-rw-r--r--libcef/browser/osr/synthetic_gesture_target_osr.cc60
-rw-r--r--libcef/browser/osr/synthetic_gesture_target_osr.h42
-rw-r--r--libcef/browser/osr/touch_handle_drawable_osr.cc132
-rw-r--r--libcef/browser/osr/touch_handle_drawable_osr.h59
-rw-r--r--libcef/browser/osr/touch_selection_controller_client_osr.cc529
-rw-r--r--libcef/browser/osr/touch_selection_controller_client_osr.h156
-rw-r--r--libcef/browser/osr/video_consumer_osr.cc142
-rw-r--r--libcef/browser/osr/video_consumer_osr.h45
-rw-r--r--libcef/browser/osr/web_contents_view_osr.cc223
-rw-r--r--libcef/browser/osr/web_contents_view_osr.h100
-rw-r--r--libcef/browser/path_util_impl.cc57
-rw-r--r--libcef/browser/permission_prompt.cc298
-rw-r--r--libcef/browser/permission_prompt.h15
-rw-r--r--libcef/browser/prefs/browser_prefs.cc377
-rw-r--r--libcef/browser/prefs/browser_prefs.h45
-rw-r--r--libcef/browser/prefs/pref_helper.cc118
-rw-r--r--libcef/browser/prefs/pref_helper.h33
-rw-r--r--libcef/browser/prefs/pref_registrar.cc96
-rw-r--r--libcef/browser/prefs/pref_registrar.h19
-rw-r--r--libcef/browser/prefs/pref_store.cc217
-rw-r--r--libcef/browser/prefs/pref_store.h118
-rw-r--r--libcef/browser/prefs/renderer_prefs.cc451
-rw-r--r--libcef/browser/prefs/renderer_prefs.h61
-rw-r--r--libcef/browser/print_settings_impl.cc165
-rw-r--r--libcef/browser/print_settings_impl.h53
-rw-r--r--libcef/browser/printing/print_dialog_linux.cc340
-rw-r--r--libcef/browser/printing/print_dialog_linux.h106
-rw-r--r--libcef/browser/printing/print_util.cc149
-rw-r--r--libcef/browser/printing/print_util.h28
-rw-r--r--libcef/browser/process_util_impl.cc31
-rw-r--r--libcef/browser/request_context_handler_map.cc51
-rw-r--r--libcef/browser/request_context_handler_map.h52
-rw-r--r--libcef/browser/request_context_impl.cc704
-rw-r--r--libcef/browser/request_context_impl.h179
-rw-r--r--libcef/browser/scheme_impl.cc32
-rw-r--r--libcef/browser/screen_util.cc44
-rw-r--r--libcef/browser/screen_util.h20
-rw-r--r--libcef/browser/screen_util_unittest.cc83
-rw-r--r--libcef/browser/server_impl.cc699
-rw-r--r--libcef/browser/server_impl.h115
-rw-r--r--libcef/browser/simple_menu_model_impl.cc570
-rw-r--r--libcef/browser/simple_menu_model_impl.h172
-rw-r--r--libcef/browser/speech_recognition_manager_delegate.cc90
-rw-r--r--libcef/browser/speech_recognition_manager_delegate.h60
-rw-r--r--libcef/browser/ssl_host_state_delegate.cc120
-rw-r--r--libcef/browser/ssl_host_state_delegate.h85
-rw-r--r--libcef/browser/ssl_info_impl.cc28
-rw-r--r--libcef/browser/ssl_info_impl.h32
-rw-r--r--libcef/browser/ssl_status_impl.cc40
-rw-r--r--libcef/browser/ssl_status_impl.h40
-rw-r--r--libcef/browser/stream_impl.cc322
-rw-r--r--libcef/browser/stream_impl.h159
-rw-r--r--libcef/browser/test/test_helpers_impl.cc14
-rw-r--r--libcef/browser/test/test_server_impl.cc293
-rw-r--r--libcef/browser/test/test_server_impl.h40
-rw-r--r--libcef/browser/thread_util.h119
-rw-r--r--libcef/browser/trace_impl.cc54
-rw-r--r--libcef/browser/trace_subscriber.cc148
-rw-r--r--libcef/browser/trace_subscriber.h36
-rw-r--r--libcef/browser/views/basic_label_button_impl.cc40
-rw-r--r--libcef/browser/views/basic_label_button_impl.h47
-rw-r--r--libcef/browser/views/basic_label_button_view.cc9
-rw-r--r--libcef/browser/views/basic_label_button_view.h43
-rw-r--r--libcef/browser/views/basic_panel_impl.cc33
-rw-r--r--libcef/browser/views/basic_panel_impl.h44
-rw-r--r--libcef/browser/views/basic_panel_view.cc8
-rw-r--r--libcef/browser/views/basic_panel_view.h24
-rw-r--r--libcef/browser/views/box_layout_impl.cc82
-rw-r--r--libcef/browser/views/box_layout_impl.h44
-rw-r--r--libcef/browser/views/browser_platform_delegate_views.cc303
-rw-r--r--libcef/browser/views/browser_platform_delegate_views.h81
-rw-r--r--libcef/browser/views/browser_view_impl.cc315
-rw-r--r--libcef/browser/views/browser_view_impl.h123
-rw-r--r--libcef/browser/views/browser_view_view.cc40
-rw-r--r--libcef/browser/views/browser_view_view.h63
-rw-r--r--libcef/browser/views/button_impl.h110
-rw-r--r--libcef/browser/views/button_view.h78
-rw-r--r--libcef/browser/views/display_impl.cc155
-rw-r--r--libcef/browser/views/display_impl.h40
-rw-r--r--libcef/browser/views/fill_layout_impl.cc21
-rw-r--r--libcef/browser/views/fill_layout_impl.h34
-rw-r--r--libcef/browser/views/label_button_impl.h137
-rw-r--r--libcef/browser/views/label_button_view.h52
-rw-r--r--libcef/browser/views/layout_adapter.cc21
-rw-r--r--libcef/browser/views/layout_adapter.h38
-rw-r--r--libcef/browser/views/layout_impl.h77
-rw-r--r--libcef/browser/views/layout_util.cc75
-rw-r--r--libcef/browser/views/layout_util.h32
-rw-r--r--libcef/browser/views/menu_button_impl.cc73
-rw-r--r--libcef/browser/views/menu_button_impl.h61
-rw-r--r--libcef/browser/views/menu_button_view.cc61
-rw-r--r--libcef/browser/views/menu_button_view.h55
-rw-r--r--libcef/browser/views/menu_runner_views.cc40
-rw-r--r--libcef/browser/views/menu_runner_views.h29
-rw-r--r--libcef/browser/views/native_widget_mac.h39
-rw-r--r--libcef/browser/views/native_widget_mac.mm54
-rw-r--r--libcef/browser/views/ns_window.h20
-rw-r--r--libcef/browser/views/ns_window.mm104
-rw-r--r--libcef/browser/views/overlay_view_host.cc336
-rw-r--r--libcef/browser/views/overlay_view_host.h78
-rw-r--r--libcef/browser/views/panel_impl.h219
-rw-r--r--libcef/browser/views/panel_view.h42
-rw-r--r--libcef/browser/views/scroll_view_impl.cc90
-rw-r--r--libcef/browser/views/scroll_view_impl.h55
-rw-r--r--libcef/browser/views/scroll_view_view.cc8
-rw-r--r--libcef/browser/views/scroll_view_view.h27
-rw-r--r--libcef/browser/views/textfield_impl.cc234
-rw-r--r--libcef/browser/views/textfield_impl.h84
-rw-r--r--libcef/browser/views/textfield_view.cc42
-rw-r--r--libcef/browser/views/textfield_view.h45
-rw-r--r--libcef/browser/views/view_adapter.cc60
-rw-r--r--libcef/browser/views/view_adapter.h55
-rw-r--r--libcef/browser/views/view_impl.h760
-rw-r--r--libcef/browser/views/view_util.cc336
-rw-r--r--libcef/browser/views/view_util.h157
-rw-r--r--libcef/browser/views/view_util_aura.cc52
-rw-r--r--libcef/browser/views/view_util_mac.mm54
-rw-r--r--libcef/browser/views/view_view.h257
-rw-r--r--libcef/browser/views/window_impl.cc717
-rw-r--r--libcef/browser/views/window_impl.h168
-rw-r--r--libcef/browser/views/window_view.cc663
-rw-r--r--libcef/browser/views/window_view.h138
-rw-r--r--libcef/browser/x509_cert_principal_impl.cc67
-rw-r--r--libcef/browser/x509_cert_principal_impl.h38
-rw-r--r--libcef/browser/x509_certificate_impl.cc140
-rw-r--r--libcef/browser/x509_certificate_impl.h55
-rw-r--r--libcef/browser/xml_reader_impl.cc494
-rw-r--r--libcef/browser/xml_reader_impl.h74
-rw-r--r--libcef/browser/zip_reader_impl.cc303
-rw-r--r--libcef/browser/zip_reader_impl.h55
-rw-r--r--libcef/common/alloy/alloy_content_client.cc160
-rw-r--r--libcef/common/alloy/alloy_content_client.h33
-rw-r--r--libcef/common/alloy/alloy_main_delegate.cc599
-rw-r--r--libcef/common/alloy/alloy_main_delegate.h95
-rw-r--r--libcef/common/alloy/alloy_main_runner_delegate.cc63
-rw-r--r--libcef/common/alloy/alloy_main_runner_delegate.h48
-rw-r--r--libcef/common/app_manager.cc112
-rw-r--r--libcef/common/app_manager.h72
-rw-r--r--libcef/common/base_impl.cc341
-rw-r--r--libcef/common/cdm_host_file_path.cc119
-rw-r--r--libcef/common/cdm_host_file_path.h20
-rw-r--r--libcef/common/cef_crash_report_upload_thread.cc220
-rw-r--r--libcef/common/cef_crash_report_upload_thread.h47
-rw-r--r--libcef/common/cef_crash_report_utils.cc58
-rw-r--r--libcef/common/cef_crash_report_utils.h19
-rw-r--r--libcef/common/cef_switches.cc124
-rw-r--r--libcef/common/cef_switches.h61
-rw-r--r--libcef/common/chrome/chrome_content_client_cef.cc36
-rw-r--r--libcef/common/chrome/chrome_content_client_cef.h23
-rw-r--r--libcef/common/chrome/chrome_main_delegate_cef.cc346
-rw-r--r--libcef/common/chrome/chrome_main_delegate_cef.h86
-rw-r--r--libcef/common/chrome/chrome_main_runner_delegate.cc90
-rw-r--r--libcef/common/chrome/chrome_main_runner_delegate.h54
-rw-r--r--libcef/common/command_line_impl.cc179
-rw-r--r--libcef/common/command_line_impl.h52
-rw-r--r--libcef/common/crash_reporter_client.cc805
-rw-r--r--libcef/common/crash_reporter_client.h116
-rw-r--r--libcef/common/crash_reporting.cc267
-rw-r--r--libcef/common/crash_reporting.h37
-rw-r--r--libcef/common/drag_data_impl.cc217
-rw-r--r--libcef/common/drag_data_impl.h73
-rw-r--r--libcef/common/extensions/api/BUILD.gn39
-rw-r--r--libcef/common/extensions/api/README.txt66
-rw-r--r--libcef/common/extensions/api/_api_features.json46
-rw-r--r--libcef/common/extensions/api/_permission_features.json43
-rw-r--r--libcef/common/extensions/chrome_generated_schemas.cc33
-rw-r--r--libcef/common/extensions/chrome_generated_schemas.h34
-rw-r--r--libcef/common/extensions/extensions_api_provider.cc89
-rw-r--r--libcef/common/extensions/extensions_api_provider.h33
-rw-r--r--libcef/common/extensions/extensions_client.cc102
-rw-r--r--libcef/common/extensions/extensions_client.h58
-rw-r--r--libcef/common/extensions/extensions_util.cc46
-rw-r--r--libcef/common/extensions/extensions_util.h21
-rw-r--r--libcef/common/file_util_impl.cc97
-rw-r--r--libcef/common/frame_util.cc39
-rw-r--r--libcef/common/frame_util.h84
-rw-r--r--libcef/common/i18n_util_impl.cc11
-rw-r--r--libcef/common/json_impl.cc91
-rw-r--r--libcef/common/main_runner_delegate.h38
-rw-r--r--libcef/common/main_runner_handler.h24
-rw-r--r--libcef/common/mojom/BUILD.gn29
-rw-r--r--libcef/common/mojom/cef.mojom139
-rw-r--r--libcef/common/net/http_header_utils.cc62
-rw-r--r--libcef/common/net/http_header_utils.h30
-rw-r--r--libcef/common/net/net_resource_provider.cc17
-rw-r--r--libcef/common/net/net_resource_provider.h14
-rw-r--r--libcef/common/net/scheme_info.h53
-rw-r--r--libcef/common/net/scheme_registration.cc100
-rw-r--r--libcef/common/net/scheme_registration.h30
-rw-r--r--libcef/common/net/url_util.cc42
-rw-r--r--libcef/common/net/url_util.h27
-rw-r--r--libcef/common/net_service/net_service_util.cc287
-rw-r--r--libcef/common/net_service/net_service_util.h76
-rw-r--r--libcef/common/parser_impl.cc169
-rw-r--r--libcef/common/process_message_impl.cc65
-rw-r--r--libcef/common/process_message_impl.h54
-rw-r--r--libcef/common/process_message_smr_impl.cc90
-rw-r--r--libcef/common/process_message_smr_impl.h58
-rw-r--r--libcef/common/request_impl.cc1229
-rw-r--r--libcef/common/request_impl.h282
-rw-r--r--libcef/common/resource_bundle_delegate.cc85
-rw-r--r--libcef/common/resource_bundle_delegate.h46
-rw-r--r--libcef/common/resource_bundle_impl.cc45
-rw-r--r--libcef/common/resource_bundle_impl.h29
-rw-r--r--libcef/common/resource_util.cc245
-rw-r--r--libcef/common/resource_util.h44
-rw-r--r--libcef/common/response_impl.cc241
-rw-r--r--libcef/common/response_impl.h69
-rw-r--r--libcef/common/scheme_registrar_impl.cc81
-rw-r--r--libcef/common/scheme_registrar_impl.h33
-rw-r--r--libcef/common/string_list_impl.cc62
-rw-r--r--libcef/common/string_map_impl.cc100
-rw-r--r--libcef/common/string_multimap_impl.cc125
-rw-r--r--libcef/common/string_types_impl.cc336
-rw-r--r--libcef/common/string_util.cc72
-rw-r--r--libcef/common/string_util.h44
-rw-r--r--libcef/common/task_impl.cc49
-rw-r--r--libcef/common/task_runner_impl.cc146
-rw-r--r--libcef/common/task_runner_impl.h40
-rw-r--r--libcef/common/task_runner_manager.cc28
-rw-r--r--libcef/common/task_runner_manager.h37
-rw-r--r--libcef/common/test/translator_test_impl.cc601
-rw-r--r--libcef/common/thread_impl.cc152
-rw-r--r--libcef/common/thread_impl.h45
-rw-r--r--libcef/common/time_impl.cc172
-rw-r--r--libcef/common/time_util.h16
-rw-r--r--libcef/common/tracker.cc80
-rw-r--r--libcef/common/tracker.h77
-rw-r--r--libcef/common/urlrequest_impl.cc43
-rw-r--r--libcef/common/util_linux.cc35
-rw-r--r--libcef/common/util_linux.h16
-rw-r--r--libcef/common/util_mac.h62
-rw-r--r--libcef/common/util_mac.mm161
-rw-r--r--libcef/common/value_base.cc242
-rw-r--r--libcef/common/value_base.h442
-rw-r--r--libcef/common/values_impl.cc1554
-rw-r--r--libcef/common/values_impl.h363
-rw-r--r--libcef/common/waitable_event_impl.cc63
-rw-r--r--libcef/common/waitable_event_impl.h33
-rw-r--r--libcef/features/BUILD.gn101
-rw-r--r--libcef/features/features.gni14
-rw-r--r--libcef/features/runtime.h47
-rw-r--r--libcef/features/runtime_checks.h18
-rw-r--r--libcef/renderer/alloy/alloy_content_renderer_client.cc584
-rw-r--r--libcef/renderer/alloy/alloy_content_renderer_client.h152
-rw-r--r--libcef/renderer/alloy/alloy_render_thread_observer.cc69
-rw-r--r--libcef/renderer/alloy/alloy_render_thread_observer.h59
-rw-r--r--libcef/renderer/alloy/url_loader_throttle_provider_impl.cc67
-rw-r--r--libcef/renderer/alloy/url_loader_throttle_provider_impl.h45
-rw-r--r--libcef/renderer/blink_glue.cc338
-rw-r--r--libcef/renderer/blink_glue.h142
-rw-r--r--libcef/renderer/browser_impl.cc434
-rw-r--r--libcef/renderer/browser_impl.h134
-rw-r--r--libcef/renderer/chrome/chrome_content_renderer_client_cef.cc103
-rw-r--r--libcef/renderer/chrome/chrome_content_renderer_client_cef.h55
-rw-r--r--libcef/renderer/dom_document_impl.cc278
-rw-r--r--libcef/renderer/dom_document_impl.h63
-rw-r--r--libcef/renderer/dom_node_impl.cc454
-rw-r--r--libcef/renderer/dom_node_impl.h62
-rw-r--r--libcef/renderer/extensions/extensions_dispatcher_delegate.cc21
-rw-r--r--libcef/renderer/extensions/extensions_dispatcher_delegate.h29
-rw-r--r--libcef/renderer/extensions/extensions_renderer_client.cc146
-rw-r--r--libcef/renderer/extensions/extensions_renderer_client.h88
-rw-r--r--libcef/renderer/extensions/print_render_frame_helper_delegate.cc72
-rw-r--r--libcef/renderer/extensions/print_render_frame_helper_delegate.h29
-rw-r--r--libcef/renderer/frame_impl.cc863
-rw-r--r--libcef/renderer/frame_impl.h214
-rw-r--r--libcef/renderer/render_frame_observer.cc270
-rw-r--r--libcef/renderer/render_frame_observer.h70
-rw-r--r--libcef/renderer/render_frame_util.cc45
-rw-r--r--libcef/renderer/render_frame_util.h24
-rw-r--r--libcef/renderer/render_manager.cc411
-rw-r--r--libcef/renderer/render_manager.h131
-rw-r--r--libcef/renderer/render_urlrequest_impl.cc501
-rw-r--r--libcef/renderer/render_urlrequest_impl.h44
-rw-r--r--libcef/renderer/thread_util.h59
-rw-r--r--libcef/renderer/v8_impl.cc2731
-rw-r--r--libcef/renderer/v8_impl.h416
-rw-r--r--libcef/resources/about_version.html120
-rw-r--r--libcef/resources/cef_resources.grd20
-rw-r--r--libcef/resources/cef_strings.grd129
-rw-r--r--libcef/resources/devtools_discovery_page.html54
-rw-r--r--libcef/resources/framework-Info.plist18
-rw-r--r--libcef_dll/CMakeLists.txt.in50
-rw-r--r--libcef_dll/base/cef_atomic_flag.cc31
-rw-r--r--libcef_dll/base/cef_callback_helpers.cc44
-rw-r--r--libcef_dll/base/cef_callback_internal.cc101
-rw-r--r--libcef_dll/base/cef_lock.cc45
-rw-r--r--libcef_dll/base/cef_lock_impl.cc92
-rw-r--r--libcef_dll/base/cef_logging.cc267
-rw-r--r--libcef_dll/base/cef_ref_counted.cc98
-rw-r--r--libcef_dll/base/cef_thread_checker_impl.cc35
-rw-r--r--libcef_dll/base/cef_weak_ptr.cc101
-rw-r--r--libcef_dll/cpptoc/accessibility_handler_cpptoc.cc99
-rw-r--r--libcef_dll/cpptoc/accessibility_handler_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/app_cpptoc.cc150
-rw-r--r--libcef_dll/cpptoc/app_cpptoc.h36
-rw-r--r--libcef_dll/cpptoc/audio_handler_cpptoc.cc206
-rw-r--r--libcef_dll/cpptoc/audio_handler_cpptoc.h37
-rw-r--r--libcef_dll/cpptoc/auth_callback_cpptoc.cc83
-rw-r--r--libcef_dll/cpptoc/auth_callback_cpptoc.h37
-rw-r--r--libcef_dll/cpptoc/base_ref_counted_cpptoc.cc23
-rw-r--r--libcef_dll/cpptoc/base_ref_counted_cpptoc.h26
-rw-r--r--libcef_dll/cpptoc/base_scoped_cpptoc.cc29
-rw-r--r--libcef_dll/cpptoc/base_scoped_cpptoc.h25
-rw-r--r--libcef_dll/cpptoc/before_download_callback_cpptoc.cc70
-rw-r--r--libcef_dll/cpptoc/before_download_callback_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/binary_value_cpptoc.cc218
-rw-r--r--libcef_dll/cpptoc/binary_value_cpptoc.h37
-rw-r--r--libcef_dll/cpptoc/browser_cpptoc.cc462
-rw-r--r--libcef_dll/cpptoc/browser_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/browser_host_cpptoc.cc1481
-rw-r--r--libcef_dll/cpptoc/browser_host_cpptoc.h39
-rw-r--r--libcef_dll/cpptoc/browser_process_handler_cpptoc.cc150
-rw-r--r--libcef_dll/cpptoc/browser_process_handler_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/callback_cpptoc.cc76
-rw-r--r--libcef_dll/cpptoc/callback_cpptoc.h37
-rw-r--r--libcef_dll/cpptoc/client_cpptoc.cc426
-rw-r--r--libcef_dll/cpptoc/client_cpptoc.h36
-rw-r--r--libcef_dll/cpptoc/command_handler_cpptoc.cc78
-rw-r--r--libcef_dll/cpptoc/command_handler_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/command_line_cpptoc.cc465
-rw-r--r--libcef_dll/cpptoc/command_line_cpptoc.h37
-rw-r--r--libcef_dll/cpptoc/completion_callback_cpptoc.cc65
-rw-r--r--libcef_dll/cpptoc/completion_callback_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/context_menu_handler_cpptoc.cc346
-rw-r--r--libcef_dll/cpptoc/context_menu_handler_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/context_menu_params_cpptoc.cc458
-rw-r--r--libcef_dll/cpptoc/context_menu_params_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/cookie_access_filter_cpptoc.cc146
-rw-r--r--libcef_dll/cpptoc/cookie_access_filter_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/cookie_manager_cpptoc.cc208
-rw-r--r--libcef_dll/cpptoc/cookie_manager_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/cookie_visitor_cpptoc.cc100
-rw-r--r--libcef_dll/cpptoc/cookie_visitor_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/cpptoc_ref_counted.h210
-rw-r--r--libcef_dll/cpptoc/cpptoc_scoped.h236
-rw-r--r--libcef_dll/cpptoc/delete_cookies_callback_cpptoc.cc68
-rw-r--r--libcef_dll/cpptoc/delete_cookies_callback_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/dev_tools_message_observer_cpptoc.cc196
-rw-r--r--libcef_dll/cpptoc/dev_tools_message_observer_cpptoc.h40
-rw-r--r--libcef_dll/cpptoc/dialog_handler_cpptoc.cc95
-rw-r--r--libcef_dll/cpptoc/dialog_handler_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/dictionary_value_cpptoc.cc803
-rw-r--r--libcef_dll/cpptoc/dictionary_value_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/display_handler_cpptoc.cc378
-rw-r--r--libcef_dll/cpptoc/display_handler_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/domdocument_cpptoc.cc330
-rw-r--r--libcef_dll/cpptoc/domdocument_cpptoc.h37
-rw-r--r--libcef_dll/cpptoc/domnode_cpptoc.cc585
-rw-r--r--libcef_dll/cpptoc/domnode_cpptoc.h36
-rw-r--r--libcef_dll/cpptoc/domvisitor_cpptoc.cc69
-rw-r--r--libcef_dll/cpptoc/domvisitor_cpptoc.h37
-rw-r--r--libcef_dll/cpptoc/download_handler_cpptoc.cc172
-rw-r--r--libcef_dll/cpptoc/download_handler_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/download_image_callback_cpptoc.cc79
-rw-r--r--libcef_dll/cpptoc/download_image_callback_cpptoc.h40
-rw-r--r--libcef_dll/cpptoc/download_item_callback_cpptoc.cc98
-rw-r--r--libcef_dll/cpptoc/download_item_callback_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/download_item_cpptoc.cc368
-rw-r--r--libcef_dll/cpptoc/download_item_cpptoc.h37
-rw-r--r--libcef_dll/cpptoc/drag_data_cpptoc.cc555
-rw-r--r--libcef_dll/cpptoc/drag_data_cpptoc.h37
-rw-r--r--libcef_dll/cpptoc/drag_handler_cpptoc.cc129
-rw-r--r--libcef_dll/cpptoc/drag_handler_cpptoc.h37
-rw-r--r--libcef_dll/cpptoc/end_tracing_callback_cpptoc.cc73
-rw-r--r--libcef_dll/cpptoc/end_tracing_callback_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/extension_cpptoc.cc206
-rw-r--r--libcef_dll/cpptoc/extension_cpptoc.h41
-rw-r--r--libcef_dll/cpptoc/extension_handler_cpptoc.cc427
-rw-r--r--libcef_dll/cpptoc/extension_handler_cpptoc.h40
-rw-r--r--libcef_dll/cpptoc/file_dialog_callback_cpptoc.cc88
-rw-r--r--libcef_dll/cpptoc/file_dialog_callback_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/find_handler_cpptoc.cc84
-rw-r--r--libcef_dll/cpptoc/find_handler_cpptoc.h37
-rw-r--r--libcef_dll/cpptoc/focus_handler_cpptoc.cc120
-rw-r--r--libcef_dll/cpptoc/focus_handler_cpptoc.h37
-rw-r--r--libcef_dll/cpptoc/frame_cpptoc.cc526
-rw-r--r--libcef_dll/cpptoc/frame_cpptoc.h42
-rw-r--r--libcef_dll/cpptoc/frame_handler_cpptoc.cc167
-rw-r--r--libcef_dll/cpptoc/frame_handler_cpptoc.h37
-rw-r--r--libcef_dll/cpptoc/get_extension_resource_callback_cpptoc.cc88
-rw-r--r--libcef_dll/cpptoc/get_extension_resource_callback_cpptoc.h40
-rw-r--r--libcef_dll/cpptoc/image_cpptoc.cc469
-rw-r--r--libcef_dll/cpptoc/image_cpptoc.h36
-rw-r--r--libcef_dll/cpptoc/jsdialog_callback_cpptoc.cc68
-rw-r--r--libcef_dll/cpptoc/jsdialog_callback_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/jsdialog_handler_cpptoc.cc188
-rw-r--r--libcef_dll/cpptoc/jsdialog_handler_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/keyboard_handler_cpptoc.cc137
-rw-r--r--libcef_dll/cpptoc/keyboard_handler_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/life_span_handler_cpptoc.cc272
-rw-r--r--libcef_dll/cpptoc/life_span_handler_cpptoc.h40
-rw-r--r--libcef_dll/cpptoc/list_value_cpptoc.cc641
-rw-r--r--libcef_dll/cpptoc/list_value_cpptoc.h37
-rw-r--r--libcef_dll/cpptoc/load_handler_cpptoc.cc175
-rw-r--r--libcef_dll/cpptoc/load_handler_cpptoc.h37
-rw-r--r--libcef_dll/cpptoc/media_access_callback_cpptoc.cc83
-rw-r--r--libcef_dll/cpptoc/media_access_callback_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/media_observer_cpptoc.cc170
-rw-r--r--libcef_dll/cpptoc/media_observer_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/media_route_cpptoc.cc145
-rw-r--r--libcef_dll/cpptoc/media_route_cpptoc.h37
-rw-r--r--libcef_dll/cpptoc/media_route_create_callback_cpptoc.cc73
-rw-r--r--libcef_dll/cpptoc/media_route_create_callback_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/media_router_cpptoc.cc192
-rw-r--r--libcef_dll/cpptoc/media_router_cpptoc.h37
-rw-r--r--libcef_dll/cpptoc/media_sink_cpptoc.cc192
-rw-r--r--libcef_dll/cpptoc/media_sink_cpptoc.h37
-rw-r--r--libcef_dll/cpptoc/media_sink_device_info_callback_cpptoc.cc86
-rw-r--r--libcef_dll/cpptoc/media_sink_device_info_callback_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/media_source_cpptoc.cc102
-rw-r--r--libcef_dll/cpptoc/media_source_cpptoc.h37
-rw-r--r--libcef_dll/cpptoc/menu_model_cpptoc.cc1389
-rw-r--r--libcef_dll/cpptoc/menu_model_cpptoc.h37
-rw-r--r--libcef_dll/cpptoc/menu_model_delegate_cpptoc.cc238
-rw-r--r--libcef_dll/cpptoc/menu_model_delegate_cpptoc.h40
-rw-r--r--libcef_dll/cpptoc/navigation_entry_cpptoc.cc243
-rw-r--r--libcef_dll/cpptoc/navigation_entry_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/navigation_entry_visitor_cpptoc.cc81
-rw-r--r--libcef_dll/cpptoc/navigation_entry_visitor_cpptoc.h40
-rw-r--r--libcef_dll/cpptoc/pdf_print_callback_cpptoc.cc73
-rw-r--r--libcef_dll/cpptoc/pdf_print_callback_cpptoc.h40
-rw-r--r--libcef_dll/cpptoc/permission_handler_cpptoc.cc170
-rw-r--r--libcef_dll/cpptoc/permission_handler_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/permission_prompt_callback_cpptoc.cc67
-rw-r--r--libcef_dll/cpptoc/permission_prompt_callback_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/post_data_cpptoc.cc207
-rw-r--r--libcef_dll/cpptoc/post_data_cpptoc.h37
-rw-r--r--libcef_dll/cpptoc/post_data_element_cpptoc.cc206
-rw-r--r--libcef_dll/cpptoc/post_data_element_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/preference_manager_cpptoc.cc193
-rw-r--r--libcef_dll/cpptoc/preference_manager_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/preference_registrar_cpptoc.cc85
-rw-r--r--libcef_dll/cpptoc/preference_registrar_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/print_dialog_callback_cpptoc.cc90
-rw-r--r--libcef_dll/cpptoc/print_dialog_callback_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/print_handler_cpptoc.cc236
-rw-r--r--libcef_dll/cpptoc/print_handler_cpptoc.h37
-rw-r--r--libcef_dll/cpptoc/print_job_callback_cpptoc.cc65
-rw-r--r--libcef_dll/cpptoc/print_job_callback_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/print_settings_cpptoc.cc519
-rw-r--r--libcef_dll/cpptoc/print_settings_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/process_message_cpptoc.cc190
-rw-r--r--libcef_dll/cpptoc/process_message_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/read_handler_cpptoc.cc147
-rw-r--r--libcef_dll/cpptoc/read_handler_cpptoc.h37
-rw-r--r--libcef_dll/cpptoc/registration_cpptoc.cc42
-rw-r--r--libcef_dll/cpptoc/registration_cpptoc.h37
-rw-r--r--libcef_dll/cpptoc/render_handler_cpptoc.cc655
-rw-r--r--libcef_dll/cpptoc/render_handler_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/render_process_handler_cpptoc.cc317
-rw-r--r--libcef_dll/cpptoc/render_process_handler_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/request_context_cpptoc.cc654
-rw-r--r--libcef_dll/cpptoc/request_context_cpptoc.h42
-rw-r--r--libcef_dll/cpptoc/request_context_handler_cpptoc.cc126
-rw-r--r--libcef_dll/cpptoc/request_context_handler_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/request_cpptoc.cc484
-rw-r--r--libcef_dll/cpptoc/request_cpptoc.h36
-rw-r--r--libcef_dll/cpptoc/request_handler_cpptoc.cc433
-rw-r--r--libcef_dll/cpptoc/request_handler_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/resolve_callback_cpptoc.cc74
-rw-r--r--libcef_dll/cpptoc/resolve_callback_cpptoc.h42
-rw-r--r--libcef_dll/cpptoc/resource_bundle_cpptoc.cc119
-rw-r--r--libcef_dll/cpptoc/resource_bundle_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/resource_bundle_handler_cpptoc.cc179
-rw-r--r--libcef_dll/cpptoc/resource_bundle_handler_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/resource_handler_cpptoc.cc329
-rw-r--r--libcef_dll/cpptoc/resource_handler_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/resource_read_callback_cpptoc.cc67
-rw-r--r--libcef_dll/cpptoc/resource_read_callback_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/resource_request_handler_cpptoc.cc344
-rw-r--r--libcef_dll/cpptoc/resource_request_handler_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/resource_skip_callback_cpptoc.cc67
-rw-r--r--libcef_dll/cpptoc/resource_skip_callback_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/response_cpptoc.cc357
-rw-r--r--libcef_dll/cpptoc/response_cpptoc.h37
-rw-r--r--libcef_dll/cpptoc/response_filter_cpptoc.cc126
-rw-r--r--libcef_dll/cpptoc/response_filter_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/run_context_menu_callback_cpptoc.cc84
-rw-r--r--libcef_dll/cpptoc/run_context_menu_callback_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/run_file_dialog_callback_cpptoc.cc75
-rw-r--r--libcef_dll/cpptoc/run_file_dialog_callback_cpptoc.h40
-rw-r--r--libcef_dll/cpptoc/run_quick_menu_callback_cpptoc.cc85
-rw-r--r--libcef_dll/cpptoc/run_quick_menu_callback_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/scheme_handler_factory_cpptoc.cc86
-rw-r--r--libcef_dll/cpptoc/scheme_handler_factory_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/scheme_registrar_cpptoc.cc81
-rw-r--r--libcef_dll/cpptoc/scheme_registrar_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/select_client_certificate_callback_cpptoc.cc73
-rw-r--r--libcef_dll/cpptoc/select_client_certificate_callback_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/server_cpptoc.cc350
-rw-r--r--libcef_dll/cpptoc/server_cpptoc.h36
-rw-r--r--libcef_dll/cpptoc/server_handler_cpptoc.cc281
-rw-r--r--libcef_dll/cpptoc/server_handler_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/set_cookie_callback_cpptoc.cc66
-rw-r--r--libcef_dll/cpptoc/set_cookie_callback_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/shared_memory_region_cpptoc.cc106
-rw-r--r--libcef_dll/cpptoc/shared_memory_region_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/shared_process_message_builder_cpptoc.cc150
-rw-r--r--libcef_dll/cpptoc/shared_process_message_builder_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/sslinfo_cpptoc.cc87
-rw-r--r--libcef_dll/cpptoc/sslinfo_cpptoc.h36
-rw-r--r--libcef_dll/cpptoc/sslstatus_cpptoc.cc144
-rw-r--r--libcef_dll/cpptoc/sslstatus_cpptoc.h37
-rw-r--r--libcef_dll/cpptoc/stream_reader_cpptoc.cc212
-rw-r--r--libcef_dll/cpptoc/stream_reader_cpptoc.h37
-rw-r--r--libcef_dll/cpptoc/stream_writer_cpptoc.cc192
-rw-r--r--libcef_dll/cpptoc/stream_writer_cpptoc.h37
-rw-r--r--libcef_dll/cpptoc/string_visitor_cpptoc.cc66
-rw-r--r--libcef_dll/cpptoc/string_visitor_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/task_cpptoc.cc57
-rw-r--r--libcef_dll/cpptoc/task_cpptoc.h36
-rw-r--r--libcef_dll/cpptoc/task_runner_cpptoc.cc190
-rw-r--r--libcef_dll/cpptoc/task_runner_cpptoc.h37
-rw-r--r--libcef_dll/cpptoc/test/test_server_connection_cpptoc.cc161
-rw-r--r--libcef_dll/cpptoc/test/test_server_connection_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/test/test_server_cpptoc.cc108
-rw-r--r--libcef_dll/cpptoc/test/test_server_cpptoc.h37
-rw-r--r--libcef_dll/cpptoc/test/test_server_handler_cpptoc.cc92
-rw-r--r--libcef_dll/cpptoc/test/test_server_handler_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/test/translator_test_cpptoc.cc1758
-rw-r--r--libcef_dll/cpptoc/test/translator_test_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/test/translator_test_ref_ptr_client_child_cpptoc.cc96
-rw-r--r--libcef_dll/cpptoc/test/translator_test_ref_ptr_client_child_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/test/translator_test_ref_ptr_client_cpptoc.cc75
-rw-r--r--libcef_dll/cpptoc/test/translator_test_ref_ptr_client_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/test/translator_test_ref_ptr_library_child_child_cpptoc.cc204
-rw-r--r--libcef_dll/cpptoc/test/translator_test_ref_ptr_library_child_child_cpptoc.h39
-rw-r--r--libcef_dll/cpptoc/test/translator_test_ref_ptr_library_child_cpptoc.cc155
-rw-r--r--libcef_dll/cpptoc/test/translator_test_ref_ptr_library_child_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/test/translator_test_ref_ptr_library_cpptoc.cc114
-rw-r--r--libcef_dll/cpptoc/test/translator_test_ref_ptr_library_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/test/translator_test_scoped_client_child_cpptoc.cc100
-rw-r--r--libcef_dll/cpptoc/test/translator_test_scoped_client_child_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/test/translator_test_scoped_client_cpptoc.cc85
-rw-r--r--libcef_dll/cpptoc/test/translator_test_scoped_client_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/test/translator_test_scoped_library_child_child_cpptoc.cc197
-rw-r--r--libcef_dll/cpptoc/test/translator_test_scoped_library_child_child_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/test/translator_test_scoped_library_child_cpptoc.cc156
-rw-r--r--libcef_dll/cpptoc/test/translator_test_scoped_library_child_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/test/translator_test_scoped_library_cpptoc.cc123
-rw-r--r--libcef_dll/cpptoc/test/translator_test_scoped_library_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/thread_cpptoc.cc143
-rw-r--r--libcef_dll/cpptoc/thread_cpptoc.h36
-rw-r--r--libcef_dll/cpptoc/urlrequest_client_cpptoc.cc197
-rw-r--r--libcef_dll/cpptoc/urlrequest_client_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/urlrequest_cpptoc.cc215
-rw-r--r--libcef_dll/cpptoc/urlrequest_cpptoc.h37
-rw-r--r--libcef_dll/cpptoc/v8accessor_cpptoc.cc151
-rw-r--r--libcef_dll/cpptoc/v8accessor_cpptoc.h37
-rw-r--r--libcef_dll/cpptoc/v8array_buffer_release_callback_cpptoc.cc69
-rw-r--r--libcef_dll/cpptoc/v8array_buffer_release_callback_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/v8context_cpptoc.cc293
-rw-r--r--libcef_dll/cpptoc/v8context_cpptoc.h37
-rw-r--r--libcef_dll/cpptoc/v8exception_cpptoc.cc176
-rw-r--r--libcef_dll/cpptoc/v8exception_cpptoc.h37
-rw-r--r--libcef_dll/cpptoc/v8handler_cpptoc.cc122
-rw-r--r--libcef_dll/cpptoc/v8handler_cpptoc.h37
-rw-r--r--libcef_dll/cpptoc/v8interceptor_cpptoc.cc259
-rw-r--r--libcef_dll/cpptoc/v8interceptor_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/v8stack_frame_cpptoc.cc181
-rw-r--r--libcef_dll/cpptoc/v8stack_frame_cpptoc.h37
-rw-r--r--libcef_dll/cpptoc/v8stack_trace_cpptoc.cc121
-rw-r--r--libcef_dll/cpptoc/v8stack_trace_cpptoc.h37
-rw-r--r--libcef_dll/cpptoc/v8value_cpptoc.cc1181
-rw-r--r--libcef_dll/cpptoc/v8value_cpptoc.h36
-rw-r--r--libcef_dll/cpptoc/value_cpptoc.cc501
-rw-r--r--libcef_dll/cpptoc/value_cpptoc.h36
-rw-r--r--libcef_dll/cpptoc/views/box_layout_cpptoc.cc155
-rw-r--r--libcef_dll/cpptoc/views/box_layout_cpptoc.h39
-rw-r--r--libcef_dll/cpptoc/views/browser_view_cpptoc.cc1295
-rw-r--r--libcef_dll/cpptoc/views/browser_view_cpptoc.h37
-rw-r--r--libcef_dll/cpptoc/views/browser_view_delegate_cpptoc.cc507
-rw-r--r--libcef_dll/cpptoc/views/browser_view_delegate_cpptoc.h42
-rw-r--r--libcef_dll/cpptoc/views/button_cpptoc.cc1249
-rw-r--r--libcef_dll/cpptoc/views/button_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/views/button_delegate_cpptoc.cc376
-rw-r--r--libcef_dll/cpptoc/views/button_delegate_cpptoc.h40
-rw-r--r--libcef_dll/cpptoc/views/display_cpptoc.cc393
-rw-r--r--libcef_dll/cpptoc/views/display_cpptoc.h36
-rw-r--r--libcef_dll/cpptoc/views/fill_layout_cpptoc.cc110
-rw-r--r--libcef_dll/cpptoc/views/fill_layout_cpptoc.h37
-rw-r--r--libcef_dll/cpptoc/views/label_button_cpptoc.cc1550
-rw-r--r--libcef_dll/cpptoc/views/label_button_cpptoc.h39
-rw-r--r--libcef_dll/cpptoc/views/layout_cpptoc.cc110
-rw-r--r--libcef_dll/cpptoc/views/layout_cpptoc.h40
-rw-r--r--libcef_dll/cpptoc/views/menu_button_cpptoc.cc1604
-rw-r--r--libcef_dll/cpptoc/views/menu_button_cpptoc.h37
-rw-r--r--libcef_dll/cpptoc/views/menu_button_delegate_cpptoc.cc429
-rw-r--r--libcef_dll/cpptoc/views/menu_button_delegate_cpptoc.h40
-rw-r--r--libcef_dll/cpptoc/views/menu_button_pressed_lock_cpptoc.cc43
-rw-r--r--libcef_dll/cpptoc/views/menu_button_pressed_lock_cpptoc.h40
-rw-r--r--libcef_dll/cpptoc/views/overlay_controller_cpptoc.cc440
-rw-r--r--libcef_dll/cpptoc/views/overlay_controller_cpptoc.h42
-rw-r--r--libcef_dll/cpptoc/views/panel_cpptoc.cc1388
-rw-r--r--libcef_dll/cpptoc/views/panel_cpptoc.h44
-rw-r--r--libcef_dll/cpptoc/views/panel_delegate_cpptoc.cc328
-rw-r--r--libcef_dll/cpptoc/views/panel_delegate_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/views/scroll_view_cpptoc.cc1320
-rw-r--r--libcef_dll/cpptoc/views/scroll_view_cpptoc.h37
-rw-r--r--libcef_dll/cpptoc/views/textfield_cpptoc.cc1772
-rw-r--r--libcef_dll/cpptoc/views/textfield_cpptoc.h37
-rw-r--r--libcef_dll/cpptoc/views/textfield_delegate_cpptoc.cc389
-rw-r--r--libcef_dll/cpptoc/views/textfield_delegate_cpptoc.h40
-rw-r--r--libcef_dll/cpptoc/views/view_cpptoc.cc1092
-rw-r--r--libcef_dll/cpptoc/views/view_cpptoc.h48
-rw-r--r--libcef_dll/cpptoc/views/view_delegate_cpptoc.cc345
-rw-r--r--libcef_dll/cpptoc/views/view_delegate_cpptoc.h39
-rw-r--r--libcef_dll/cpptoc/views/window_cpptoc.cc2097
-rw-r--r--libcef_dll/cpptoc/views/window_cpptoc.h36
-rw-r--r--libcef_dll/cpptoc/views/window_delegate_cpptoc.cc809
-rw-r--r--libcef_dll/cpptoc/views/window_delegate_cpptoc.h40
-rw-r--r--libcef_dll/cpptoc/waitable_event_cpptoc.cc149
-rw-r--r--libcef_dll/cpptoc/waitable_event_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/write_handler_cpptoc.cc149
-rw-r--r--libcef_dll/cpptoc/write_handler_cpptoc.h37
-rw-r--r--libcef_dll/cpptoc/x509cert_principal_cpptoc.cc270
-rw-r--r--libcef_dll/cpptoc/x509cert_principal_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/x509certificate_cpptoc.cc294
-rw-r--r--libcef_dll/cpptoc/x509certificate_cpptoc.h38
-rw-r--r--libcef_dll/cpptoc/xml_reader_cpptoc.cc671
-rw-r--r--libcef_dll/cpptoc/xml_reader_cpptoc.h37
-rw-r--r--libcef_dll/cpptoc/zip_reader_cpptoc.cc305
-rw-r--r--libcef_dll/cpptoc/zip_reader_cpptoc.h37
-rw-r--r--libcef_dll/ctocpp/accessibility_handler_ctocpp.cc90
-rw-r--r--libcef_dll/ctocpp/accessibility_handler_ctocpp.h42
-rw-r--r--libcef_dll/ctocpp/app_ctocpp.cc141
-rw-r--r--libcef_dll/ctocpp/app_ctocpp.h46
-rw-r--r--libcef_dll/ctocpp/audio_handler_ctocpp.cc176
-rw-r--r--libcef_dll/ctocpp/audio_handler_ctocpp.h51
-rw-r--r--libcef_dll/ctocpp/auth_callback_ctocpp.cc76
-rw-r--r--libcef_dll/ctocpp/auth_callback_ctocpp.h41
-rw-r--r--libcef_dll/ctocpp/base_ref_counted_ctocpp.cc23
-rw-r--r--libcef_dll/ctocpp/base_ref_counted_ctocpp.h26
-rw-r--r--libcef_dll/ctocpp/base_scoped_ctocpp.cc29
-rw-r--r--libcef_dll/ctocpp/base_scoped_ctocpp.h25
-rw-r--r--libcef_dll/ctocpp/before_download_callback_ctocpp.cc64
-rw-r--r--libcef_dll/ctocpp/before_download_callback_ctocpp.h41
-rw-r--r--libcef_dll/ctocpp/binary_value_ctocpp.cc207
-rw-r--r--libcef_dll/ctocpp/binary_value_ctocpp.h46
-rw-r--r--libcef_dll/ctocpp/browser_ctocpp.cc436
-rw-r--r--libcef_dll/ctocpp/browser_ctocpp.h62
-rw-r--r--libcef_dll/ctocpp/browser_host_ctocpp.cc1204
-rw-r--r--libcef_dll/ctocpp/browser_host_ctocpp.h136
-rw-r--r--libcef_dll/ctocpp/browser_process_handler_ctocpp.cc134
-rw-r--r--libcef_dll/ctocpp/browser_process_handler_ctocpp.h48
-rw-r--r--libcef_dll/ctocpp/callback_ctocpp.cc69
-rw-r--r--libcef_dll/ctocpp/callback_ctocpp.h41
-rw-r--r--libcef_dll/ctocpp/client_ctocpp.cc386
-rw-r--r--libcef_dll/ctocpp/client_ctocpp.h60
-rw-r--r--libcef_dll/ctocpp/command_handler_ctocpp.cc73
-rw-r--r--libcef_dll/ctocpp/command_handler_ctocpp.h43
-rw-r--r--libcef_dll/ctocpp/command_line_ctocpp.cc470
-rw-r--r--libcef_dll/ctocpp/command_line_ctocpp.h61
-rw-r--r--libcef_dll/ctocpp/completion_callback_ctocpp.cc58
-rw-r--r--libcef_dll/ctocpp/completion_callback_ctocpp.h41
-rw-r--r--libcef_dll/ctocpp/context_menu_handler_ctocpp.cc322
-rw-r--r--libcef_dll/ctocpp/context_menu_handler_ctocpp.h68
-rw-r--r--libcef_dll/ctocpp/context_menu_params_ctocpp.cc432
-rw-r--r--libcef_dll/ctocpp/context_menu_params_ctocpp.h61
-rw-r--r--libcef_dll/ctocpp/cookie_access_filter_ctocpp.cc108
-rw-r--r--libcef_dll/ctocpp/cookie_access_filter_ctocpp.h49
-rw-r--r--libcef_dll/ctocpp/cookie_manager_ctocpp.cc188
-rw-r--r--libcef_dll/ctocpp/cookie_manager_ctocpp.h51
-rw-r--r--libcef_dll/ctocpp/cookie_visitor_ctocpp.cc72
-rw-r--r--libcef_dll/ctocpp/cookie_visitor_ctocpp.h44
-rw-r--r--libcef_dll/ctocpp/ctocpp_ref_counted.h182
-rw-r--r--libcef_dll/ctocpp/ctocpp_scoped.h205
-rw-r--r--libcef_dll/ctocpp/delete_cookies_callback_ctocpp.cc60
-rw-r--r--libcef_dll/ctocpp/delete_cookies_callback_ctocpp.h41
-rw-r--r--libcef_dll/ctocpp/dev_tools_message_observer_ctocpp.cc186
-rw-r--r--libcef_dll/ctocpp/dev_tools_message_observer_ctocpp.h56
-rw-r--r--libcef_dll/ctocpp/dialog_handler_ctocpp.cc98
-rw-r--r--libcef_dll/ctocpp/dialog_handler_ctocpp.h47
-rw-r--r--libcef_dll/ctocpp/dictionary_value_ctocpp.cc767
-rw-r--r--libcef_dll/ctocpp/dictionary_value_ctocpp.h71
-rw-r--r--libcef_dll/ctocpp/display_handler_ctocpp.cc352
-rw-r--r--libcef_dll/ctocpp/display_handler_ctocpp.h69
-rw-r--r--libcef_dll/ctocpp/domdocument_ctocpp.cc310
-rw-r--r--libcef_dll/ctocpp/domdocument_ctocpp.h53
-rw-r--r--libcef_dll/ctocpp/domnode_ctocpp.cc562
-rw-r--r--libcef_dll/ctocpp/domnode_ctocpp.h65
-rw-r--r--libcef_dll/ctocpp/domvisitor_ctocpp.cc64
-rw-r--r--libcef_dll/ctocpp/domvisitor_ctocpp.h40
-rw-r--r--libcef_dll/ctocpp/download_handler_ctocpp.cc165
-rw-r--r--libcef_dll/ctocpp/download_handler_ctocpp.h50
-rw-r--r--libcef_dll/ctocpp/download_image_callback_ctocpp.cc73
-rw-r--r--libcef_dll/ctocpp/download_image_callback_ctocpp.h45
-rw-r--r--libcef_dll/ctocpp/download_item_callback_ctocpp.cc86
-rw-r--r--libcef_dll/ctocpp/download_item_callback_ctocpp.h43
-rw-r--r--libcef_dll/ctocpp/download_item_ctocpp.cc347
-rw-r--r--libcef_dll/ctocpp/download_item_ctocpp.h56
-rw-r--r--libcef_dll/ctocpp/drag_data_ctocpp.cc534
-rw-r--r--libcef_dll/ctocpp/drag_data_ctocpp.h66
-rw-r--r--libcef_dll/ctocpp/drag_handler_ctocpp.cc126
-rw-r--r--libcef_dll/ctocpp/drag_handler_ctocpp.h47
-rw-r--r--libcef_dll/ctocpp/end_tracing_callback_ctocpp.cc66
-rw-r--r--libcef_dll/ctocpp/end_tracing_callback_ctocpp.h41
-rw-r--r--libcef_dll/ctocpp/extension_ctocpp.cc192
-rw-r--r--libcef_dll/ctocpp/extension_ctocpp.h51
-rw-r--r--libcef_dll/ctocpp/extension_handler_ctocpp.cc346
-rw-r--r--libcef_dll/ctocpp/extension_handler_ctocpp.h70
-rw-r--r--libcef_dll/ctocpp/file_dialog_callback_ctocpp.cc89
-rw-r--r--libcef_dll/ctocpp/file_dialog_callback_ctocpp.h43
-rw-r--r--libcef_dll/ctocpp/find_handler_ctocpp.cc71
-rw-r--r--libcef_dll/ctocpp/find_handler_ctocpp.h45
-rw-r--r--libcef_dll/ctocpp/focus_handler_ctocpp.cc114
-rw-r--r--libcef_dll/ctocpp/focus_handler_ctocpp.h42
-rw-r--r--libcef_dll/ctocpp/frame_ctocpp.cc505
-rw-r--r--libcef_dll/ctocpp/frame_ctocpp.h74
-rw-r--r--libcef_dll/ctocpp/frame_handler_ctocpp.cc157
-rw-r--r--libcef_dll/ctocpp/frame_handler_ctocpp.h49
-rw-r--r--libcef_dll/ctocpp/get_extension_resource_callback_ctocpp.cc80
-rw-r--r--libcef_dll/ctocpp/get_extension_resource_callback_ctocpp.h44
-rw-r--r--libcef_dll/ctocpp/image_ctocpp.cc344
-rw-r--r--libcef_dll/ctocpp/image_ctocpp.h74
-rw-r--r--libcef_dll/ctocpp/jsdialog_callback_ctocpp.cc62
-rw-r--r--libcef_dll/ctocpp/jsdialog_callback_ctocpp.h41
-rw-r--r--libcef_dll/ctocpp/jsdialog_handler_ctocpp.cc171
-rw-r--r--libcef_dll/ctocpp/jsdialog_handler_ctocpp.h53
-rw-r--r--libcef_dll/ctocpp/keyboard_handler_ctocpp.cc115
-rw-r--r--libcef_dll/ctocpp/keyboard_handler_ctocpp.h47
-rw-r--r--libcef_dll/ctocpp/life_span_handler_ctocpp.cc202
-rw-r--r--libcef_dll/ctocpp/life_span_handler_ctocpp.h57
-rw-r--r--libcef_dll/ctocpp/list_value_ctocpp.cc596
-rw-r--r--libcef_dll/ctocpp/list_value_ctocpp.h68
-rw-r--r--libcef_dll/ctocpp/load_handler_ctocpp.cc165
-rw-r--r--libcef_dll/ctocpp/load_handler_ctocpp.h54
-rw-r--r--libcef_dll/ctocpp/media_access_callback_ctocpp.cc73
-rw-r--r--libcef_dll/ctocpp/media_access_callback_ctocpp.h42
-rw-r--r--libcef_dll/ctocpp/media_observer_ctocpp.cc167
-rw-r--r--libcef_dll/ctocpp/media_observer_ctocpp.h48
-rw-r--r--libcef_dll/ctocpp/media_route_create_callback_ctocpp.cc67
-rw-r--r--libcef_dll/ctocpp/media_route_create_callback_ctocpp.h43
-rw-r--r--libcef_dll/ctocpp/media_route_ctocpp.cc135
-rw-r--r--libcef_dll/ctocpp/media_route_ctocpp.h44
-rw-r--r--libcef_dll/ctocpp/media_router_ctocpp.cc182
-rw-r--r--libcef_dll/ctocpp/media_router_ctocpp.h47
-rw-r--r--libcef_dll/ctocpp/media_sink_ctocpp.cc182
-rw-r--r--libcef_dll/ctocpp/media_sink_ctocpp.h47
-rw-r--r--libcef_dll/ctocpp/media_sink_device_info_callback_ctocpp.cc61
-rw-r--r--libcef_dll/ctocpp/media_sink_device_info_callback_ctocpp.h42
-rw-r--r--libcef_dll/ctocpp/media_source_ctocpp.cc95
-rw-r--r--libcef_dll/ctocpp/media_source_ctocpp.h42
-rw-r--r--libcef_dll/ctocpp/menu_model_ctocpp.cc1206
-rw-r--r--libcef_dll/ctocpp/menu_model_ctocpp.h131
-rw-r--r--libcef_dll/ctocpp/menu_model_delegate_ctocpp.cc212
-rw-r--r--libcef_dll/ctocpp/menu_model_delegate_ctocpp.h55
-rw-r--r--libcef_dll/ctocpp/navigation_entry_ctocpp.cc227
-rw-r--r--libcef_dll/ctocpp/navigation_entry_ctocpp.h50
-rw-r--r--libcef_dll/ctocpp/navigation_entry_visitor_ctocpp.cc75
-rw-r--r--libcef_dll/ctocpp/navigation_entry_visitor_ctocpp.h46
-rw-r--r--libcef_dll/ctocpp/pdf_print_callback_ctocpp.cc66
-rw-r--r--libcef_dll/ctocpp/pdf_print_callback_ctocpp.h43
-rw-r--r--libcef_dll/ctocpp/permission_handler_ctocpp.cc162
-rw-r--r--libcef_dll/ctocpp/permission_handler_ctocpp.h56
-rw-r--r--libcef_dll/ctocpp/permission_prompt_callback_ctocpp.cc61
-rw-r--r--libcef_dll/ctocpp/permission_prompt_callback_ctocpp.h41
-rw-r--r--libcef_dll/ctocpp/post_data_ctocpp.cc195
-rw-r--r--libcef_dll/ctocpp/post_data_ctocpp.h46
-rw-r--r--libcef_dll/ctocpp/post_data_element_ctocpp.cc189
-rw-r--r--libcef_dll/ctocpp/post_data_element_ctocpp.h48
-rw-r--r--libcef_dll/ctocpp/preference_manager_ctocpp.cc175
-rw-r--r--libcef_dll/ctocpp/preference_manager_ctocpp.h48
-rw-r--r--libcef_dll/ctocpp/preference_registrar_ctocpp.cc80
-rw-r--r--libcef_dll/ctocpp/preference_registrar_ctocpp.h42
-rw-r--r--libcef_dll/ctocpp/print_dialog_callback_ctocpp.cc81
-rw-r--r--libcef_dll/ctocpp/print_dialog_callback_ctocpp.h42
-rw-r--r--libcef_dll/ctocpp/print_handler_ctocpp.cc226
-rw-r--r--libcef_dll/ctocpp/print_handler_ctocpp.h53
-rw-r--r--libcef_dll/ctocpp/print_job_callback_ctocpp.cc58
-rw-r--r--libcef_dll/ctocpp/print_job_callback_ctocpp.h41
-rw-r--r--libcef_dll/ctocpp/print_settings_ctocpp.cc464
-rw-r--r--libcef_dll/ctocpp/print_settings_ctocpp.h64
-rw-r--r--libcef_dll/ctocpp/process_message_ctocpp.cc176
-rw-r--r--libcef_dll/ctocpp/process_message_ctocpp.h46
-rw-r--r--libcef_dll/ctocpp/read_handler_ctocpp.cc135
-rw-r--r--libcef_dll/ctocpp/read_handler_ctocpp.h44
-rw-r--r--libcef_dll/ctocpp/registration_ctocpp.cc42
-rw-r--r--libcef_dll/ctocpp/registration_ctocpp.h39
-rw-r--r--libcef_dll/ctocpp/render_handler_ctocpp.cc540
-rw-r--r--libcef_dll/ctocpp/render_handler_ctocpp.h85
-rw-r--r--libcef_dll/ctocpp/render_process_handler_ctocpp.cc300
-rw-r--r--libcef_dll/ctocpp/render_process_handler_ctocpp.h63
-rw-r--r--libcef_dll/ctocpp/request_context_ctocpp.cc601
-rw-r--r--libcef_dll/ctocpp/request_context_ctocpp.h83
-rw-r--r--libcef_dll/ctocpp/request_context_handler_ctocpp.cc109
-rw-r--r--libcef_dll/ctocpp/request_context_handler_ctocpp.h50
-rw-r--r--libcef_dll/ctocpp/request_ctocpp.cc470
-rw-r--r--libcef_dll/ctocpp/request_ctocpp.h66
-rw-r--r--libcef_dll/ctocpp/request_handler_ctocpp.cc414
-rw-r--r--libcef_dll/ctocpp/request_handler_ctocpp.h82
-rw-r--r--libcef_dll/ctocpp/resolve_callback_ctocpp.cc76
-rw-r--r--libcef_dll/ctocpp/resolve_callback_ctocpp.h47
-rw-r--r--libcef_dll/ctocpp/resource_bundle_ctocpp.cc111
-rw-r--r--libcef_dll/ctocpp/resource_bundle_ctocpp.h45
-rw-r--r--libcef_dll/ctocpp/resource_bundle_handler_ctocpp.cc109
-rw-r--r--libcef_dll/ctocpp/resource_bundle_handler_ctocpp.h48
-rw-r--r--libcef_dll/ctocpp/resource_handler_ctocpp.cc256
-rw-r--r--libcef_dll/ctocpp/resource_handler_ctocpp.h60
-rw-r--r--libcef_dll/ctocpp/resource_read_callback_ctocpp.cc59
-rw-r--r--libcef_dll/ctocpp/resource_read_callback_ctocpp.h41
-rw-r--r--libcef_dll/ctocpp/resource_request_handler_ctocpp.cc312
-rw-r--r--libcef_dll/ctocpp/resource_request_handler_ctocpp.h76
-rw-r--r--libcef_dll/ctocpp/resource_skip_callback_ctocpp.cc59
-rw-r--r--libcef_dll/ctocpp/resource_skip_callback_ctocpp.h41
-rw-r--r--libcef_dll/ctocpp/response_ctocpp.cc348
-rw-r--r--libcef_dll/ctocpp/response_ctocpp.h58
-rw-r--r--libcef_dll/ctocpp/response_filter_ctocpp.cc94
-rw-r--r--libcef_dll/ctocpp/response_filter_ctocpp.h47
-rw-r--r--libcef_dll/ctocpp/run_context_menu_callback_ctocpp.cc76
-rw-r--r--libcef_dll/ctocpp/run_context_menu_callback_ctocpp.h42
-rw-r--r--libcef_dll/ctocpp/run_file_dialog_callback_ctocpp.cc77
-rw-r--r--libcef_dll/ctocpp/run_file_dialog_callback_ctocpp.h44
-rw-r--r--libcef_dll/ctocpp/run_quick_menu_callback_ctocpp.cc75
-rw-r--r--libcef_dll/ctocpp/run_quick_menu_callback_ctocpp.h42
-rw-r--r--libcef_dll/ctocpp/scheme_handler_factory_ctocpp.cc79
-rw-r--r--libcef_dll/ctocpp/scheme_handler_factory_ctocpp.h44
-rw-r--r--libcef_dll/ctocpp/scheme_registrar_ctocpp.cc75
-rw-r--r--libcef_dll/ctocpp/scheme_registrar_ctocpp.h41
-rw-r--r--libcef_dll/ctocpp/select_client_certificate_callback_ctocpp.cc66
-rw-r--r--libcef_dll/ctocpp/select_client_certificate_callback_ctocpp.h41
-rw-r--r--libcef_dll/ctocpp/server_ctocpp.cc343
-rw-r--r--libcef_dll/ctocpp/server_ctocpp.h63
-rw-r--r--libcef_dll/ctocpp/server_handler_ctocpp.cc268
-rw-r--r--libcef_dll/ctocpp/server_handler_ctocpp.h61
-rw-r--r--libcef_dll/ctocpp/set_cookie_callback_ctocpp.cc59
-rw-r--r--libcef_dll/ctocpp/set_cookie_callback_ctocpp.h41
-rw-r--r--libcef_dll/ctocpp/shared_memory_region_ctocpp.cc95
-rw-r--r--libcef_dll/ctocpp/shared_memory_region_ctocpp.h43
-rw-r--r--libcef_dll/ctocpp/shared_process_message_builder_ctocpp.cc137
-rw-r--r--libcef_dll/ctocpp/shared_process_message_builder_ctocpp.h44
-rw-r--r--libcef_dll/ctocpp/sslinfo_ctocpp.cc78
-rw-r--r--libcef_dll/ctocpp/sslinfo_ctocpp.h40
-rw-r--r--libcef_dll/ctocpp/sslstatus_ctocpp.cc130
-rw-r--r--libcef_dll/ctocpp/sslstatus_ctocpp.h44
-rw-r--r--libcef_dll/ctocpp/stream_reader_ctocpp.cc202
-rw-r--r--libcef_dll/ctocpp/stream_reader_ctocpp.h44
-rw-r--r--libcef_dll/ctocpp/stream_writer_ctocpp.cc182
-rw-r--r--libcef_dll/ctocpp/stream_writer_ctocpp.h44
-rw-r--r--libcef_dll/ctocpp/string_visitor_ctocpp.cc61
-rw-r--r--libcef_dll/ctocpp/string_visitor_ctocpp.h41
-rw-r--r--libcef_dll/ctocpp/task_ctocpp.cc51
-rw-r--r--libcef_dll/ctocpp/task_ctocpp.h39
-rw-r--r--libcef_dll/ctocpp/task_runner_ctocpp.cc180
-rw-r--r--libcef_dll/ctocpp/task_runner_ctocpp.h44
-rw-r--r--libcef_dll/ctocpp/test/test_server_connection_ctocpp.cc157
-rw-r--r--libcef_dll/ctocpp/test/test_server_connection_ctocpp.h50
-rw-r--r--libcef_dll/ctocpp/test/test_server_ctocpp.cc103
-rw-r--r--libcef_dll/ctocpp/test/test_server_ctocpp.h41
-rw-r--r--libcef_dll/ctocpp/test/test_server_handler_ctocpp.cc87
-rw-r--r--libcef_dll/ctocpp/test/test_server_handler_ctocpp.h44
-rw-r--r--libcef_dll/ctocpp/test/translator_test_ctocpp.cc1663
-rw-r--r--libcef_dll/ctocpp/test/translator_test_ctocpp.h136
-rw-r--r--libcef_dll/ctocpp/test/translator_test_ref_ptr_client_child_ctocpp.cc84
-rw-r--r--libcef_dll/ctocpp/test/translator_test_ref_ptr_client_child_ctocpp.h44
-rw-r--r--libcef_dll/ctocpp/test/translator_test_ref_ptr_client_ctocpp.cc68
-rw-r--r--libcef_dll/ctocpp/test/translator_test_ref_ptr_client_ctocpp.h41
-rw-r--r--libcef_dll/ctocpp/test/translator_test_ref_ptr_library_child_child_ctocpp.cc174
-rw-r--r--libcef_dll/ctocpp/test/translator_test_ref_ptr_library_child_child_ctocpp.h51
-rw-r--r--libcef_dll/ctocpp/test/translator_test_ref_ptr_library_child_ctocpp.cc138
-rw-r--r--libcef_dll/ctocpp/test/translator_test_ref_ptr_library_child_ctocpp.h46
-rw-r--r--libcef_dll/ctocpp/test/translator_test_ref_ptr_library_ctocpp.cc106
-rw-r--r--libcef_dll/ctocpp/test/translator_test_ref_ptr_library_ctocpp.h42
-rw-r--r--libcef_dll/ctocpp/test/translator_test_scoped_client_child_ctocpp.cc89
-rw-r--r--libcef_dll/ctocpp/test/translator_test_scoped_client_child_ctocpp.h44
-rw-r--r--libcef_dll/ctocpp/test/translator_test_scoped_client_ctocpp.cc83
-rw-r--r--libcef_dll/ctocpp/test/translator_test_scoped_client_ctocpp.h41
-rw-r--r--libcef_dll/ctocpp/test/translator_test_scoped_library_child_child_ctocpp.cc168
-rw-r--r--libcef_dll/ctocpp/test/translator_test_scoped_library_child_child_ctocpp.h50
-rw-r--r--libcef_dll/ctocpp/test/translator_test_scoped_library_child_ctocpp.cc146
-rw-r--r--libcef_dll/ctocpp/test/translator_test_scoped_library_child_ctocpp.h46
-rw-r--r--libcef_dll/ctocpp/test/translator_test_scoped_library_ctocpp.cc126
-rw-r--r--libcef_dll/ctocpp/test/translator_test_scoped_library_ctocpp.h42
-rw-r--r--libcef_dll/ctocpp/thread_ctocpp.cc133
-rw-r--r--libcef_dll/ctocpp/thread_ctocpp.h42
-rw-r--r--libcef_dll/ctocpp/urlrequest_client_ctocpp.cc190
-rw-r--r--libcef_dll/ctocpp/urlrequest_client_ctocpp.h56
-rw-r--r--libcef_dll/ctocpp/urlrequest_ctocpp.cc200
-rw-r--r--libcef_dll/ctocpp/urlrequest_ctocpp.h46
-rw-r--r--libcef_dll/ctocpp/v8accessor_ctocpp.cc125
-rw-r--r--libcef_dll/ctocpp/v8accessor_ctocpp.h47
-rw-r--r--libcef_dll/ctocpp/v8array_buffer_release_callback_ctocpp.cc63
-rw-r--r--libcef_dll/ctocpp/v8array_buffer_release_callback_ctocpp.h41
-rw-r--r--libcef_dll/ctocpp/v8context_ctocpp.cc265
-rw-r--r--libcef_dll/ctocpp/v8context_ctocpp.h52
-rw-r--r--libcef_dll/ctocpp/v8exception_ctocpp.cc166
-rw-r--r--libcef_dll/ctocpp/v8exception_ctocpp.h47
-rw-r--r--libcef_dll/ctocpp/v8handler_ctocpp.cc105
-rw-r--r--libcef_dll/ctocpp/v8handler_ctocpp.h44
-rw-r--r--libcef_dll/ctocpp/v8interceptor_ctocpp.cc212
-rw-r--r--libcef_dll/ctocpp/v8interceptor_ctocpp.h56
-rw-r--r--libcef_dll/ctocpp/v8stack_frame_ctocpp.cc169
-rw-r--r--libcef_dll/ctocpp/v8stack_frame_ctocpp.h47
-rw-r--r--libcef_dll/ctocpp/v8stack_trace_ctocpp.cc112
-rw-r--r--libcef_dll/ctocpp/v8stack_trace_ctocpp.h42
-rw-r--r--libcef_dll/ctocpp/v8value_ctocpp.cc1139
-rw-r--r--libcef_dll/ctocpp/v8value_ctocpp.h99
-rw-r--r--libcef_dll/ctocpp/value_ctocpp.cc475
-rw-r--r--libcef_dll/ctocpp/value_ctocpp.h60
-rw-r--r--libcef_dll/ctocpp/views/box_layout_ctocpp.cc139
-rw-r--r--libcef_dll/ctocpp/views/box_layout_ctocpp.h48
-rw-r--r--libcef_dll/ctocpp/views/browser_view_ctocpp.cc1013
-rw-r--r--libcef_dll/ctocpp/views/browser_view_ctocpp.h94
-rw-r--r--libcef_dll/ctocpp/views/browser_view_delegate_ctocpp.cc451
-rw-r--r--libcef_dll/ctocpp/views/browser_view_delegate_ctocpp.h74
-rw-r--r--libcef_dll/ctocpp/views/button_ctocpp.cc1017
-rw-r--r--libcef_dll/ctocpp/views/button_ctocpp.h98
-rw-r--r--libcef_dll/ctocpp/views/button_delegate_ctocpp.cc350
-rw-r--r--libcef_dll/ctocpp/views/button_delegate_ctocpp.h61
-rw-r--r--libcef_dll/ctocpp/views/display_ctocpp.cc304
-rw-r--r--libcef_dll/ctocpp/views/display_ctocpp.h45
-rw-r--r--libcef_dll/ctocpp/views/fill_layout_ctocpp.cc96
-rw-r--r--libcef_dll/ctocpp/views/fill_layout_ctocpp.h44
-rw-r--r--libcef_dll/ctocpp/views/label_button_ctocpp.cc1242
-rw-r--r--libcef_dll/ctocpp/views/label_button_ctocpp.h113
-rw-r--r--libcef_dll/ctocpp/views/layout_ctocpp.cc104
-rw-r--r--libcef_dll/ctocpp/views/layout_ctocpp.h45
-rw-r--r--libcef_dll/ctocpp/views/menu_button_ctocpp.cc1285
-rw-r--r--libcef_dll/ctocpp/views/menu_button_ctocpp.h117
-rw-r--r--libcef_dll/ctocpp/views/menu_button_delegate_ctocpp.cc380
-rw-r--r--libcef_dll/ctocpp/views/menu_button_delegate_ctocpp.h67
-rw-r--r--libcef_dll/ctocpp/views/menu_button_pressed_lock_ctocpp.cc44
-rw-r--r--libcef_dll/ctocpp/views/menu_button_pressed_lock_ctocpp.h42
-rw-r--r--libcef_dll/ctocpp/views/overlay_controller_ctocpp.cc366
-rw-r--r--libcef_dll/ctocpp/views/overlay_controller_ctocpp.h63
-rw-r--r--libcef_dll/ctocpp/views/panel_ctocpp.cc1156
-rw-r--r--libcef_dll/ctocpp/views/panel_ctocpp.h111
-rw-r--r--libcef_dll/ctocpp/views/panel_delegate_ctocpp.cc306
-rw-r--r--libcef_dll/ctocpp/views/panel_delegate_ctocpp.h57
-rw-r--r--libcef_dll/ctocpp/views/scroll_view_ctocpp.cc1050
-rw-r--r--libcef_dll/ctocpp/views/scroll_view_ctocpp.h98
-rw-r--r--libcef_dll/ctocpp/views/textfield_ctocpp.cc1458
-rw-r--r--libcef_dll/ctocpp/views/textfield_ctocpp.h124
-rw-r--r--libcef_dll/ctocpp/views/textfield_delegate_ctocpp.cc350
-rw-r--r--libcef_dll/ctocpp/views/textfield_delegate_ctocpp.h62
-rw-r--r--libcef_dll/ctocpp/views/view_ctocpp.cc934
-rw-r--r--libcef_dll/ctocpp/views/view_ctocpp.h100
-rw-r--r--libcef_dll/ctocpp/views/view_delegate_ctocpp.cc325
-rw-r--r--libcef_dll/ctocpp/views/view_delegate_ctocpp.h56
-rw-r--r--libcef_dll/ctocpp/views/window_ctocpp.cc1790
-rw-r--r--libcef_dll/ctocpp/views/window_ctocpp.h154
-rw-r--r--libcef_dll/ctocpp/views/window_delegate_ctocpp.cc744
-rw-r--r--libcef_dll/ctocpp/views/window_delegate_ctocpp.h84
-rw-r--r--libcef_dll/ctocpp/waitable_event_ctocpp.cc138
-rw-r--r--libcef_dll/ctocpp/waitable_event_ctocpp.h45
-rw-r--r--libcef_dll/ctocpp/write_handler_ctocpp.cc137
-rw-r--r--libcef_dll/ctocpp/write_handler_ctocpp.h44
-rw-r--r--libcef_dll/ctocpp/x509cert_principal_ctocpp.cc264
-rw-r--r--libcef_dll/ctocpp/x509cert_principal_ctocpp.h50
-rw-r--r--libcef_dll/ctocpp/x509certificate_ctocpp.cc273
-rw-r--r--libcef_dll/ctocpp/x509certificate_ctocpp.h50
-rw-r--r--libcef_dll/ctocpp/xml_reader_ctocpp.cc648
-rw-r--r--libcef_dll/ctocpp/xml_reader_ctocpp.h70
-rw-r--r--libcef_dll/ctocpp/zip_reader_ctocpp.cc291
-rw-r--r--libcef_dll/ctocpp/zip_reader_ctocpp.h51
-rw-r--r--libcef_dll/libcef.dll.manifest8
-rw-r--r--libcef_dll/libcef.lst9
-rw-r--r--libcef_dll/libcef_dll.cc940
-rw-r--r--libcef_dll/libcef_dll.rc143
-rw-r--r--libcef_dll/libcef_dll2.cc78
-rw-r--r--libcef_dll/resource.h25
-rw-r--r--libcef_dll/sandbox/sandbox_mac.mm66
-rw-r--r--libcef_dll/sandbox/sandbox_win.cc57
-rw-r--r--libcef_dll/shutdown_checker.cc45
-rw-r--r--libcef_dll/shutdown_checker.h19
-rw-r--r--libcef_dll/template_util.h37
-rw-r--r--libcef_dll/transfer_util.cc66
-rw-r--r--libcef_dll/transfer_util.h36
-rw-r--r--libcef_dll/wrapper/cef_browser_info_map.h281
-rw-r--r--libcef_dll/wrapper/cef_byte_read_handler.cc69
-rw-r--r--libcef_dll/wrapper/cef_closure_task.cc80
-rw-r--r--libcef_dll/wrapper/cef_library_loader_mac.mm77
-rw-r--r--libcef_dll/wrapper/cef_message_router.cc1270
-rw-r--r--libcef_dll/wrapper/cef_resource_manager.cc784
-rw-r--r--libcef_dll/wrapper/cef_scoped_temp_dir.cc95
-rw-r--r--libcef_dll/wrapper/cef_stream_resource_handler.cc87
-rw-r--r--libcef_dll/wrapper/cef_xml_object.cc467
-rw-r--r--libcef_dll/wrapper/cef_zip_archive.cc177
-rw-r--r--libcef_dll/wrapper/libcef_dll_dylib.cc1816
-rw-r--r--libcef_dll/wrapper/libcef_dll_wrapper.cc877
-rw-r--r--libcef_dll/wrapper/libcef_dll_wrapper2.cc62
-rw-r--r--libcef_dll/wrapper_types.h189
-rw-r--r--patch/README.txt15
-rw-r--r--patch/patch.cfg628
-rw-r--r--patch/patches/base_command_line_1872.patch17
-rw-r--r--patch/patches/base_sandbox_2743.patch229
-rw-r--r--patch/patches/browser_scheduler.patch13
-rw-r--r--patch/patches/browser_security_policy_1081397.patch65
-rw-r--r--patch/patches/browser_web_ui_controller_factory.patch29
-rw-r--r--patch/patches/build.patch13
-rw-r--r--patch/patches/chrome_browser.patch40
-rw-r--r--patch/patches/chrome_browser_background_mode_1100085.patch72
-rw-r--r--patch/patches/chrome_browser_browser.patch465
-rw-r--r--patch/patches/chrome_browser_content_settings.patch70
-rw-r--r--patch/patches/chrome_browser_context_menus.patch194
-rw-r--r--patch/patches/chrome_browser_dialogs_native.patch352
-rw-r--r--patch/patches/chrome_browser_dialogs_widget.patch219
-rw-r--r--patch/patches/chrome_browser_extensions.patch35
-rw-r--r--patch/patches/chrome_browser_net_proxy.patch33
-rw-r--r--patch/patches/chrome_browser_permission_prompt.patch206
-rw-r--r--patch/patches/chrome_browser_privacy_1119417.patch59
-rw-r--r--patch/patches/chrome_browser_profile_menu.patch75
-rw-r--r--patch/patches/chrome_browser_profiles.patch158
-rw-r--r--patch/patches/chrome_browser_safe_browsing.patch12
-rw-r--r--patch/patches/chrome_browser_themes.patch82
-rw-r--r--patch/patches/chrome_plugins.patch141
-rw-r--r--patch/patches/chrome_pref_watcher.patch16
-rw-r--r--patch/patches/chrome_renderer.patch31
-rw-r--r--patch/patches/chrome_runtime.patch384
-rw-r--r--patch/patches/chrome_runtime_views.patch515
-rw-r--r--patch/patches/chrome_utility_client.patch22
-rw-r--r--patch/patches/component_build.patch124
-rw-r--r--patch/patches/content_2015.patch214
-rw-r--r--patch/patches/content_main_654986.patch184
-rw-r--r--patch/patches/crashpad_1995.patch540
-rw-r--r--patch/patches/crashpad_tp_1995.patch361
-rw-r--r--patch/patches/embedder_product_override.patch38
-rw-r--r--patch/patches/extensions_1947.patch264
-rw-r--r--patch/patches/font_family_cache_1501.patch13
-rw-r--r--patch/patches/gn_config.patch175
-rw-r--r--patch/patches/gritsettings.patch20
-rw-r--r--patch/patches/libxml_visibility.patch12
-rw-r--r--patch/patches/linux_assets_path_1936.patch39
-rw-r--r--patch/patches/linux_atk_1123214.patch26
-rw-r--r--patch/patches/linux_blink_thread_local.patch13
-rw-r--r--patch/patches/linux_bluetooth_1319006.patch21
-rw-r--r--patch/patches/linux_chrome_widevine_3149.patch58
-rw-r--r--patch/patches/linux_glib_deprecated_volatile.patch28
-rw-r--r--patch/patches/linux_printing_context.patch136
-rw-r--r--patch/patches/mac_event_observer_2539.patch22
-rw-r--r--patch/patches/mac_fling_scheduler_2540.patch15
-rw-r--r--patch/patches/mac_gpu.patch18
-rw-r--r--patch/patches/message_loop.patch75
-rw-r--r--patch/patches/message_pump_mac_2495.patch24
-rw-r--r--patch/patches/mime_handler_view_guest_1565_2727.patch100
-rw-r--r--patch/patches/net_cookie_flags.patch39
-rw-r--r--patch/patches/net_test_server_3798752.patch22
-rw-r--r--patch/patches/osr_fling_2745.patch70
-rw-r--r--patch/patches/pdfium_103501.patch12
-rw-r--r--patch/patches/print_preview_123.patch140
-rw-r--r--patch/patches/printing_context_2196.patch41
-rw-r--r--patch/patches/renderer_host_1070713.patch13
-rw-r--r--patch/patches/resource_bundle_2512.patch45
-rw-r--r--patch/patches/runhooks.patch68
-rw-r--r--patch/patches/rwh_background_color_1984.patch46
-rw-r--r--patch/patches/services_network_2622.patch244
-rw-r--r--patch/patches/services_network_2718.patch57
-rw-r--r--patch/patches/set_resize_background_color.patch30
-rw-r--r--patch/patches/storage_incognito_2289.patch72
-rw-r--r--patch/patches/trace_event.patch13
-rw-r--r--patch/patches/ui_dragdrop_355390.patch14
-rw-r--r--patch/patches/underlay_1051.patch13
-rw-r--r--patch/patches/views_1749_2102_3330.patch739
-rw-r--r--patch/patches/views_widget.patch491
-rw-r--r--patch/patches/viz_osr_2575.patch271
-rw-r--r--patch/patches/web_contents_1257_1565.patch145
-rw-r--r--patch/patches/web_url_loader_cancel_1617042.patch21
-rw-r--r--patch/patches/webkit_plugin_info_2015.patch44
-rw-r--r--patch/patches/webkit_popups.patch76
-rw-r--r--patch/patches/webkit_runtime_enabled_features.patch21
-rw-r--r--patch/patches/webui_2037.patch76
-rw-r--r--patch/patches/win_cpp17_msvc_sandbox_2819.patch28
-rw-r--r--patch/patches/win_power_monitor_4219163.patch22
-rw-r--r--patch/patches/win_sandbox_3210.patch18
-rw-r--r--patch/patches/win_shell_dialogs_3294.patch29
-rw-r--r--tests/cefclient/CMakeLists.txt.in318
-rw-r--r--tests/cefclient/browser/binding_test.cc58
-rw-r--r--tests/cefclient/browser/binding_test.h20
-rw-r--r--tests/cefclient/browser/browser_window.cc96
-rw-r--r--tests/cefclient/browser/browser_window.h146
-rw-r--r--tests/cefclient/browser/browser_window_osr_gtk.cc2099
-rw-r--r--tests/cefclient/browser/browser_window_osr_gtk.h215
-rw-r--r--tests/cefclient/browser/browser_window_osr_mac.h104
-rw-r--r--tests/cefclient/browser/browser_window_osr_mac.mm1986
-rw-r--r--tests/cefclient/browser/browser_window_osr_win.cc136
-rw-r--r--tests/cefclient/browser/browser_window_osr_win.h68
-rw-r--r--tests/cefclient/browser/browser_window_std_gtk.cc191
-rw-r--r--tests/cefclient/browser/browser_window_std_gtk.h56
-rw-r--r--tests/cefclient/browser/browser_window_std_mac.h51
-rw-r--r--tests/cefclient/browser/browser_window_std_mac.mm95
-rw-r--r--tests/cefclient/browser/browser_window_std_win.cc123
-rw-r--r--tests/cefclient/browser/browser_window_std_win.h51
-rw-r--r--tests/cefclient/browser/bytes_write_handler.cc100
-rw-r--r--tests/cefclient/browser/bytes_write_handler.h44
-rw-r--r--tests/cefclient/browser/client_app_delegates_browser.cc20
-rw-r--r--tests/cefclient/browser/client_browser.cc85
-rw-r--r--tests/cefclient/browser/client_browser.h21
-rw-r--r--tests/cefclient/browser/client_handler.cc1498
-rw-r--r--tests/cefclient/browser/client_handler.h457
-rw-r--r--tests/cefclient/browser/client_handler_osr.cc200
-rw-r--r--tests/cefclient/browser/client_handler_osr.h152
-rw-r--r--tests/cefclient/browser/client_handler_std.cc14
-rw-r--r--tests/cefclient/browser/client_handler_std.h29
-rw-r--r--tests/cefclient/browser/client_prefs.cc206
-rw-r--r--tests/cefclient/browser/client_prefs.h29
-rw-r--r--tests/cefclient/browser/client_types.h29
-rw-r--r--tests/cefclient/browser/default_client_handler.cc60
-rw-r--r--tests/cefclient/browser/default_client_handler.h61
-rw-r--r--tests/cefclient/browser/dialog_handler_gtk.cc456
-rw-r--r--tests/cefclient/browser/dialog_handler_gtk.h82
-rw-r--r--tests/cefclient/browser/dialog_test.cc178
-rw-r--r--tests/cefclient/browser/dialog_test.h20
-rw-r--r--tests/cefclient/browser/image_cache.cc319
-rw-r--r--tests/cefclient/browser/image_cache.h127
-rw-r--r--tests/cefclient/browser/main_context.cc32
-rw-r--r--tests/cefclient/browser/main_context.h75
-rw-r--r--tests/cefclient/browser/main_context_impl.cc282
-rw-r--r--tests/cefclient/browser/main_context_impl.h95
-rw-r--r--tests/cefclient/browser/main_context_impl_posix.cc28
-rw-r--r--tests/cefclient/browser/main_context_impl_win.cc39
-rw-r--r--tests/cefclient/browser/main_message_loop_multithreaded_gtk.cc152
-rw-r--r--tests/cefclient/browser/main_message_loop_multithreaded_gtk.h54
-rw-r--r--tests/cefclient/browser/main_message_loop_multithreaded_win.cc172
-rw-r--r--tests/cefclient/browser/main_message_loop_multithreaded_win.h63
-rw-r--r--tests/cefclient/browser/media_router_test.cc602
-rw-r--r--tests/cefclient/browser/media_router_test.h20
-rw-r--r--tests/cefclient/browser/osr_accessibility_helper.cc269
-rw-r--r--tests/cefclient/browser/osr_accessibility_helper.h81
-rw-r--r--tests/cefclient/browser/osr_accessibility_node.cc181
-rw-r--r--tests/cefclient/browser/osr_accessibility_node.h123
-rw-r--r--tests/cefclient/browser/osr_accessibility_node_mac.mm612
-rw-r--r--tests/cefclient/browser/osr_accessibility_node_win.cc739
-rw-r--r--tests/cefclient/browser/osr_d3d11_win.cc936
-rw-r--r--tests/cefclient/browser/osr_d3d11_win.h330
-rw-r--r--tests/cefclient/browser/osr_dragdrop_events.h37
-rw-r--r--tests/cefclient/browser/osr_dragdrop_win.cc677
-rw-r--r--tests/cefclient/browser/osr_dragdrop_win.h193
-rw-r--r--tests/cefclient/browser/osr_ime_handler_win.cc404
-rw-r--r--tests/cefclient/browser/osr_ime_handler_win.h115
-rw-r--r--tests/cefclient/browser/osr_render_handler_win.cc83
-rw-r--r--tests/cefclient/browser/osr_render_handler_win.h82
-rw-r--r--tests/cefclient/browser/osr_render_handler_win_d3d11.cc229
-rw-r--r--tests/cefclient/browser/osr_render_handler_win_d3d11.h90
-rw-r--r--tests/cefclient/browser/osr_render_handler_win_gl.cc199
-rw-r--r--tests/cefclient/browser/osr_render_handler_win_gl.h57
-rw-r--r--tests/cefclient/browser/osr_renderer.cc412
-rw-r--r--tests/cefclient/browser/osr_renderer.h75
-rw-r--r--tests/cefclient/browser/osr_renderer_settings.h38
-rw-r--r--tests/cefclient/browser/osr_window_win.cc1230
-rw-r--r--tests/cefclient/browser/osr_window_win.h215
-rw-r--r--tests/cefclient/browser/preferences_test.cc346
-rw-r--r--tests/cefclient/browser/preferences_test.h20
-rw-r--r--tests/cefclient/browser/print_handler_gtk.cc649
-rw-r--r--tests/cefclient/browser/print_handler_gtk.h48
-rw-r--r--tests/cefclient/browser/resource.h87
-rw-r--r--tests/cefclient/browser/resource_util_linux.cc37
-rw-r--r--tests/cefclient/browser/resource_util_win_idmap.cc60
-rw-r--r--tests/cefclient/browser/response_filter_test.cc246
-rw-r--r--tests/cefclient/browser/response_filter_test.h27
-rw-r--r--tests/cefclient/browser/root_window.cc42
-rw-r--r--tests/cefclient/browser/root_window.h205
-rw-r--r--tests/cefclient/browser/root_window_create.cc36
-rw-r--r--tests/cefclient/browser/root_window_gtk.cc987
-rw-r--r--tests/cefclient/browser/root_window_gtk.h167
-rw-r--r--tests/cefclient/browser/root_window_mac.h78
-rw-r--r--tests/cefclient/browser/root_window_mac.mm1108
-rw-r--r--tests/cefclient/browser/root_window_manager.cc458
-rw-r--r--tests/cefclient/browser/root_window_manager.h145
-rw-r--r--tests/cefclient/browser/root_window_views.cc588
-rw-r--r--tests/cefclient/browser/root_window_views.h129
-rw-r--r--tests/cefclient/browser/root_window_win.cc1314
-rw-r--r--tests/cefclient/browser/root_window_win.h174
-rw-r--r--tests/cefclient/browser/scheme_test.cc154
-rw-r--r--tests/cefclient/browser/scheme_test.h20
-rw-r--r--tests/cefclient/browser/server_test.cc395
-rw-r--r--tests/cefclient/browser/server_test.h20
-rw-r--r--tests/cefclient/browser/temp_window.h31
-rw-r--r--tests/cefclient/browser/temp_window_mac.h38
-rw-r--r--tests/cefclient/browser/temp_window_mac.mm59
-rw-r--r--tests/cefclient/browser/temp_window_win.cc57
-rw-r--r--tests/cefclient/browser/temp_window_win.h36
-rw-r--r--tests/cefclient/browser/temp_window_x11.cc66
-rw-r--r--tests/cefclient/browser/temp_window_x11.h36
-rw-r--r--tests/cefclient/browser/test_runner.cc871
-rw-r--r--tests/cefclient/browser/test_runner.h69
-rw-r--r--tests/cefclient/browser/text_input_client_osr_mac.h78
-rw-r--r--tests/cefclient/browser/text_input_client_osr_mac.mm363
-rw-r--r--tests/cefclient/browser/urlrequest_test.cc188
-rw-r--r--tests/cefclient/browser/urlrequest_test.h20
-rw-r--r--tests/cefclient/browser/util_gtk.cc33
-rw-r--r--tests/cefclient/browser/util_gtk.h41
-rw-r--r--tests/cefclient/browser/views_menu_bar.cc322
-rw-r--r--tests/cefclient/browser/views_menu_bar.h124
-rw-r--r--tests/cefclient/browser/views_overlay_controls.cc230
-rw-r--r--tests/cefclient/browser/views_overlay_controls.h72
-rw-r--r--tests/cefclient/browser/views_style.cc118
-rw-r--r--tests/cefclient/browser/views_style.h32
-rw-r--r--tests/cefclient/browser/views_window.cc1288
-rw-r--r--tests/cefclient/browser/views_window.h287
-rw-r--r--tests/cefclient/browser/views_window_mac.mm24
-rw-r--r--tests/cefclient/browser/window_test.cc134
-rw-r--r--tests/cefclient/browser/window_test.h20
-rw-r--r--tests/cefclient/browser/window_test_runner.cc45
-rw-r--r--tests/cefclient/browser/window_test_runner.h42
-rw-r--r--tests/cefclient/browser/window_test_runner_gtk.cc142
-rw-r--r--tests/cefclient/browser/window_test_runner_gtk.h32
-rw-r--r--tests/cefclient/browser/window_test_runner_mac.h32
-rw-r--r--tests/cefclient/browser/window_test_runner_mac.mm95
-rw-r--r--tests/cefclient/browser/window_test_runner_views.cc79
-rw-r--r--tests/cefclient/browser/window_test_runner_views.h34
-rw-r--r--tests/cefclient/browser/window_test_runner_win.cc145
-rw-r--r--tests/cefclient/browser/window_test_runner_win.h33
-rw-r--r--tests/cefclient/cefclient_gtk.cc170
-rw-r--r--tests/cefclient/cefclient_mac.mm445
-rw-r--r--tests/cefclient/cefclient_win.cc154
-rw-r--r--tests/cefclient/common/client_app_delegates_common.cc15
-rw-r--r--tests/cefclient/common/scheme_test_common.cc18
-rw-r--r--tests/cefclient/common/scheme_test_common.h25
-rw-r--r--tests/cefclient/renderer/client_app_delegates_renderer.cc19
-rw-r--r--tests/cefclient/renderer/client_renderer.cc99
-rw-r--r--tests/cefclient/renderer/client_renderer.h21
-rw-r--r--tests/cefclient/renderer/ipc_performance_test.cc249
-rw-r--r--tests/cefclient/renderer/ipc_performance_test.h19
-rw-r--r--tests/cefclient/renderer/performance_test.cc162
-rw-r--r--tests/cefclient/renderer/performance_test.h20
-rw-r--r--tests/cefclient/renderer/performance_test_setup.h102
-rw-r--r--tests/cefclient/renderer/performance_test_tests.cc396
-rw-r--r--tests/cefclient/resources/binding.html41
-rw-r--r--tests/cefclient/resources/dialogs.html80
-rw-r--r--tests/cefclient/resources/draggable.html55
-rw-r--r--tests/cefclient/resources/extensions/set_page_color/README.md17
-rw-r--r--tests/cefclient/resources/extensions/set_page_color/icon.pngbin0 -> 103 bytes
-rw-r--r--tests/cefclient/resources/extensions/set_page_color/manifest.json14
-rw-r--r--tests/cefclient/resources/extensions/set_page_color/popup.html55
-rw-r--r--tests/cefclient/resources/extensions/set_page_color/popup.js16
-rw-r--r--tests/cefclient/resources/ipc_performance.html448
-rw-r--r--tests/cefclient/resources/localstorage.html24
-rw-r--r--tests/cefclient/resources/logo.pngbin0 -> 24025 bytes
-rw-r--r--tests/cefclient/resources/mac/English.lproj/InfoPlist.strings3
-rw-r--r--tests/cefclient/resources/mac/English.lproj/MainMenu.xib427
-rw-r--r--tests/cefclient/resources/mac/Info.plist39
-rw-r--r--tests/cefclient/resources/mac/cefclient.icnsbin0 -> 55080 bytes
-rw-r--r--tests/cefclient/resources/mac/helper-Info.plist37
-rw-r--r--tests/cefclient/resources/media_router.html592
-rw-r--r--tests/cefclient/resources/menu_icon.1x.pngbin0 -> 616 bytes
-rw-r--r--tests/cefclient/resources/menu_icon.2x.pngbin0 -> 715 bytes
-rw-r--r--tests/cefclient/resources/other_tests.html45
-rw-r--r--tests/cefclient/resources/performance.html293
-rw-r--r--tests/cefclient/resources/performance2.html442
-rw-r--r--tests/cefclient/resources/preferences.html338
-rw-r--r--tests/cefclient/resources/response_filter.html142
-rw-r--r--tests/cefclient/resources/server.html104
-rw-r--r--tests/cefclient/resources/transparency.html63
-rw-r--r--tests/cefclient/resources/urlrequest.html42
-rw-r--r--tests/cefclient/resources/websocket.html107
-rw-r--r--tests/cefclient/resources/win/cefclient.exe.manifest20
-rw-r--r--tests/cefclient/resources/win/cefclient.icobin0 -> 23558 bytes
-rw-r--r--tests/cefclient/resources/win/cefclient.rc231
-rw-r--r--tests/cefclient/resources/win/small.icobin0 -> 23558 bytes
-rw-r--r--tests/cefclient/resources/window.html76
-rw-r--r--tests/cefclient/resources/xmlhttprequest.html39
-rw-r--r--tests/cefsimple/CMakeLists.txt.in214
-rw-r--r--tests/cefsimple/cefsimple.exe.manifest20
-rw-r--r--tests/cefsimple/cefsimple.rc79
-rw-r--r--tests/cefsimple/cefsimple_linux.cc91
-rw-r--r--tests/cefsimple/cefsimple_mac.mm186
-rw-r--r--tests/cefsimple/cefsimple_win.cc105
-rw-r--r--tests/cefsimple/mac/English.lproj/InfoPlist.strings3
-rw-r--r--tests/cefsimple/mac/English.lproj/MainMenu.xib330
-rw-r--r--tests/cefsimple/mac/Info.plist37
-rw-r--r--tests/cefsimple/mac/cefsimple.icnsbin0 -> 55080 bytes
-rw-r--r--tests/cefsimple/mac/helper-Info.plist35
-rw-r--r--tests/cefsimple/process_helper_mac.cc37
-rw-r--r--tests/cefsimple/res/cefsimple.icobin0 -> 23558 bytes
-rw-r--r--tests/cefsimple/res/small.icobin0 -> 23558 bytes
-rw-r--r--tests/cefsimple/resource.h26
-rw-r--r--tests/cefsimple/simple_app.cc136
-rw-r--r--tests/cefsimple/simple_app.h29
-rw-r--r--tests/cefsimple/simple_handler.cc161
-rw-r--r--tests/cefsimple/simple_handler.h74
-rw-r--r--tests/cefsimple/simple_handler_linux.cc52
-rw-r--r--tests/cefsimple/simple_handler_mac.mm19
-rw-r--r--tests/cefsimple/simple_handler_win.cc18
-rw-r--r--tests/ceftests/CMakeLists.txt.in251
-rw-r--r--tests/ceftests/audio_output_unittest.cc1096
-rw-r--r--tests/ceftests/browser_info_map_unittest.cc712
-rw-r--r--tests/ceftests/certificate_error_unittest.cc521
-rw-r--r--tests/ceftests/client_app_delegates.cc154
-rw-r--r--tests/ceftests/command_line_unittest.cc152
-rw-r--r--tests/ceftests/cookie_unittest.cc2322
-rw-r--r--tests/ceftests/cors_unittest.cc1854
-rw-r--r--tests/ceftests/devtools_message_unittest.cc377
-rw-r--r--tests/ceftests/dialog_unittest.cc318
-rw-r--r--tests/ceftests/display_unittest.cc532
-rw-r--r--tests/ceftests/dom_unittest.cc379
-rw-r--r--tests/ceftests/download_unittest.cc600
-rw-r--r--tests/ceftests/draggable_regions_unittest.cc267
-rw-r--r--tests/ceftests/extensions/background_unittest.cc294
-rw-r--r--tests/ceftests/extensions/chrome_alarms_unittest.cc340
-rw-r--r--tests/ceftests/extensions/chrome_storage_unittest.cc480
-rw-r--r--tests/ceftests/extensions/chrome_tabs_unittest.cc1223
-rw-r--r--tests/ceftests/extensions/extension_test_handler.cc240
-rw-r--r--tests/ceftests/extensions/extension_test_handler.h238
-rw-r--r--tests/ceftests/extensions/view_unittest.cc245
-rw-r--r--tests/ceftests/file_util_unittest.cc60
-rw-r--r--tests/ceftests/frame_handler_unittest.cc1722
-rw-r--r--tests/ceftests/frame_unittest.cc2326
-rw-r--r--tests/ceftests/hsts_redirect_unittest.cc317
-rw-r--r--tests/ceftests/image_unittest.cc284
-rw-r--r--tests/ceftests/image_util.cc39
-rw-r--r--tests/ceftests/image_util.h27
-rw-r--r--tests/ceftests/jsdialog_unittest.cc450
-rw-r--r--tests/ceftests/life_span_unittest.cc347
-rw-r--r--tests/ceftests/media_access_unittest.cc725
-rw-r--r--tests/ceftests/message_router_harness_unittest.cc81
-rw-r--r--tests/ceftests/message_router_multi_query_unittest.cc2013
-rw-r--r--tests/ceftests/message_router_single_query_unittest.cc629
-rw-r--r--tests/ceftests/message_router_threshold_unittest.cc225
-rw-r--r--tests/ceftests/message_router_unittest_utils.cc260
-rw-r--r--tests/ceftests/message_router_unittest_utils.h137
-rw-r--r--tests/ceftests/navigation_unittest.cc3670
-rw-r--r--tests/ceftests/os_rendering_unittest.cc1912
-rw-r--r--tests/ceftests/os_rendering_unittest_mac.h16
-rw-r--r--tests/ceftests/os_rendering_unittest_mac.mm18
-rw-r--r--tests/ceftests/osr_accessibility_unittest.cc463
-rw-r--r--tests/ceftests/osr_display_unittest.cc398
-rw-r--r--tests/ceftests/parser_unittest.cc496
-rw-r--r--tests/ceftests/pdf_viewer_unittest.cc233
-rw-r--r--tests/ceftests/permission_prompt_unittest.cc484
-rw-r--r--tests/ceftests/preference_unittest.cc650
-rw-r--r--tests/ceftests/print_unittest.cc70
-rw-r--r--tests/ceftests/process_message_unittest.cc201
-rw-r--r--tests/ceftests/request_context_unittest.cc916
-rw-r--r--tests/ceftests/request_handler_unittest.cc539
-rw-r--r--tests/ceftests/request_unittest.cc632
-rw-r--r--tests/ceftests/resource.h26
-rw-r--r--tests/ceftests/resource_manager_unittest.cc1930
-rw-r--r--tests/ceftests/resource_request_handler_unittest.cc4007
-rw-r--r--tests/ceftests/resource_util_linux.cc37
-rw-r--r--tests/ceftests/resource_util_win_dir.cc36
-rw-r--r--tests/ceftests/resource_util_win_idmap.cc33
-rw-r--r--tests/ceftests/resources/mac/English.lproj/InfoPlist.strings3
-rw-r--r--tests/ceftests/resources/mac/English.lproj/MainMenu.xib330
-rw-r--r--tests/ceftests/resources/mac/Info.plist37
-rw-r--r--tests/ceftests/resources/mac/ceftests.icnsbin0 -> 55080 bytes
-rw-r--r--tests/ceftests/resources/mac/helper-Info.plist35
-rw-r--r--tests/ceftests/resources/win/ceftests.exe.manifest20
-rw-r--r--tests/ceftests/resources/win/ceftests.icobin0 -> 23558 bytes
-rw-r--r--tests/ceftests/resources/win/ceftests.rc126
-rw-r--r--tests/ceftests/resources/win/small.icobin0 -> 23558 bytes
-rw-r--r--tests/ceftests/response_unittest.cc71
-rw-r--r--tests/ceftests/routing_test_handler.cc108
-rw-r--r--tests/ceftests/routing_test_handler.h42
-rw-r--r--tests/ceftests/run_all_unittests.cc277
-rw-r--r--tests/ceftests/run_all_unittests_mac.mm44
-rw-r--r--tests/ceftests/scheme_handler_unittest.cc2620
-rw-r--r--tests/ceftests/scoped_temp_dir_unittest.cc90
-rw-r--r--tests/ceftests/send_shared_process_message_unittest.cc173
-rw-r--r--tests/ceftests/server_unittest.cc1498
-rw-r--r--tests/ceftests/shared_process_message_unittest.cc94
-rw-r--r--tests/ceftests/stream_resource_handler_unittest.cc180
-rw-r--r--tests/ceftests/stream_unittest.cc367
-rw-r--r--tests/ceftests/string_unittest.cc485
-rw-r--r--tests/ceftests/task_unittest.cc332
-rw-r--r--tests/ceftests/test_handler.cc494
-rw-r--r--tests/ceftests/test_handler.h352
-rw-r--r--tests/ceftests/test_request.cc206
-rw-r--r--tests/ceftests/test_request.h97
-rw-r--r--tests/ceftests/test_server.cc58
-rw-r--r--tests/ceftests/test_server.h50
-rw-r--r--tests/ceftests/test_server_manager.cc303
-rw-r--r--tests/ceftests/test_server_manager.h101
-rw-r--r--tests/ceftests/test_server_observer.cc57
-rw-r--r--tests/ceftests/test_server_observer.h84
-rw-r--r--tests/ceftests/test_server_observer_unittest.cc232
-rw-r--r--tests/ceftests/test_server_runner.cc33
-rw-r--r--tests/ceftests/test_server_runner.h69
-rw-r--r--tests/ceftests/test_server_runner_normal.cc196
-rw-r--r--tests/ceftests/test_server_runner_test.cc155
-rw-r--r--tests/ceftests/test_server_unittest.cc977
-rw-r--r--tests/ceftests/test_suite.cc222
-rw-r--r--tests/ceftests/test_suite.h60
-rw-r--r--tests/ceftests/test_util.cc414
-rw-r--r--tests/ceftests/test_util.h209
-rw-r--r--tests/ceftests/thread_helper.cc54
-rw-r--r--tests/ceftests/thread_helper.h73
-rw-r--r--tests/ceftests/thread_unittest.cc445
-rw-r--r--tests/ceftests/time_unittest.cc85
-rw-r--r--tests/ceftests/tracing_unittest.cc436
-rw-r--r--tests/ceftests/track_callback.h21
-rw-r--r--tests/ceftests/translator_unittest.cc736
-rw-r--r--tests/ceftests/urlrequest_unittest.cc3467
-rw-r--r--tests/ceftests/v8_unittest.cc3371
-rw-r--r--tests/ceftests/values_unittest.cc1379
-rw-r--r--tests/ceftests/version_unittest.cc24
-rw-r--r--tests/ceftests/views/button_unittest.cc662
-rw-r--r--tests/ceftests/views/panel_unittest.cc1394
-rw-r--r--tests/ceftests/views/scroll_view_unittest.cc155
-rw-r--r--tests/ceftests/views/test_window_delegate.cc230
-rw-r--r--tests/ceftests/views/test_window_delegate.h81
-rw-r--r--tests/ceftests/views/textfield_unittest.cc312
-rw-r--r--tests/ceftests/views/window_unittest.cc520
-rw-r--r--tests/ceftests/waitable_event_unittest.cc79
-rw-r--r--tests/ceftests/webui_unittest.cc206
-rw-r--r--tests/ceftests/xml_reader_unittest.cc640
-rw-r--r--tests/ceftests/zip_reader_unittest.cc252
-rw-r--r--tests/gtest/CMakeLists.txt.in34
-rw-r--r--tests/gtest/include/gtest/gtest.h9
-rw-r--r--tests/gtest/teamcity/README.cef14
-rw-r--r--tests/gtest/teamcity/include/teamcity_gtest.h55
-rw-r--r--tests/gtest/teamcity/src/teamcity_gtest.cpp85
-rw-r--r--tests/gtest/teamcity/src/teamcity_messages.cpp215
-rw-r--r--tests/gtest/teamcity/src/teamcity_messages.h75
-rw-r--r--tests/shared/browser/client_app_browser.cc131
-rw-r--r--tests/shared/browser/client_app_browser.h90
-rw-r--r--tests/shared/browser/extension_util.cc257
-rw-r--r--tests/shared/browser/extension_util.h80
-rw-r--r--tests/shared/browser/file_util.cc133
-rw-r--r--tests/shared/browser/file_util.h45
-rw-r--r--tests/shared/browser/geometry_util.cc45
-rw-r--r--tests/shared/browser/geometry_util.h25
-rw-r--r--tests/shared/browser/main_message_loop.cc41
-rw-r--r--tests/shared/browser/main_message_loop.h109
-rw-r--r--tests/shared/browser/main_message_loop_external_pump.cc108
-rw-r--r--tests/shared/browser/main_message_loop_external_pump.h70
-rw-r--r--tests/shared/browser/main_message_loop_external_pump_linux.cc306
-rw-r--r--tests/shared/browser/main_message_loop_external_pump_mac.mm183
-rw-r--r--tests/shared/browser/main_message_loop_external_pump_win.cc155
-rw-r--r--tests/shared/browser/main_message_loop_std.cc37
-rw-r--r--tests/shared/browser/main_message_loop_std.h35
-rw-r--r--tests/shared/browser/resource_util.h37
-rw-r--r--tests/shared/browser/resource_util_linux.cc37
-rw-r--r--tests/shared/browser/resource_util_mac.mm53
-rw-r--r--tests/shared/browser/resource_util_posix.cc69
-rw-r--r--tests/shared/browser/resource_util_win.cc130
-rw-r--r--tests/shared/browser/util_win.cc194
-rw-r--r--tests/shared/browser/util_win.h44
-rw-r--r--tests/shared/common/binary_value_utils.cc44
-rw-r--r--tests/shared/common/binary_value_utils.h47
-rw-r--r--tests/shared/common/client_app.cc50
-rw-r--r--tests/shared/common/client_app.h44
-rw-r--r--tests/shared/common/client_app_other.cc13
-rw-r--r--tests/shared/common/client_app_other.h25
-rw-r--r--tests/shared/common/client_switches.cc58
-rw-r--r--tests/shared/common/client_switches.h54
-rw-r--r--tests/shared/common/string_util.cc34
-rw-r--r--tests/shared/common/string_util.h23
-rw-r--r--tests/shared/process_helper_mac.cc60
-rw-r--r--tests/shared/renderer/client_app_renderer.cc106
-rw-r--r--tests/shared/renderer/client_app_renderer.h122
-rw-r--r--tests/shared/resources/osr_test.html205
-rw-r--r--tests/shared/resources/pdf.html9
-rw-r--r--tests/shared/resources/pdf.pdfbin0 -> 30110 bytes
-rw-r--r--tests/shared/resources/window_icon.1x.pngbin0 -> 603 bytes
-rw-r--r--tests/shared/resources/window_icon.2x.pngbin0 -> 212 bytes
-rw-r--r--tools/automate/automate-git.py1638
-rw-r--r--tools/cef_api_hash.py299
-rw-r--r--tools/cef_parser.py2125
-rw-r--r--tools/cef_version.py275
-rw-r--r--tools/cefbuilds/cef_json_builder.py498
-rw-r--r--tools/cefbuilds/cef_json_builder_example.py149
-rw-r--r--tools/cefbuilds/cef_json_builder_test.py435
-rw-r--r--tools/clang_util.py35
-rw-r--r--tools/combine_libs.py121
-rw-r--r--tools/compile_ib_files.py56
-rw-r--r--tools/crash_server.py339
-rw-r--r--tools/date_util.py16
-rw-r--r--tools/distrib/README-TRANSFER.txt5
-rw-r--r--tools/distrib/README.client.txt12
-rw-r--r--tools/distrib/README.footer.txt8
-rw-r--r--tools/distrib/README.header.txt14
-rw-r--r--tools/distrib/gtest/LICENSE28
-rw-r--r--tools/distrib/gtest/README.cef17
-rw-r--r--tools/distrib/gtest/gtest-all.cc12501
-rw-r--r--tools/distrib/gtest/gtest.h12380
-rw-r--r--tools/distrib/linux/README.minimal.txt28
-rw-r--r--tools/distrib/linux/README.redistrib.txt63
-rw-r--r--tools/distrib/linux/README.standard.txt52
-rw-r--r--tools/distrib/mac/README.minimal.txt25
-rw-r--r--tools/distrib/mac/README.redistrib.txt106
-rw-r--r--tools/distrib/mac/README.sandbox.txt14
-rw-r--r--tools/distrib/mac/README.standard.txt46
-rw-r--r--tools/distrib/transfer.cfg17
-rw-r--r--tools/distrib/transfer_standard.cfg29
-rw-r--r--tools/distrib/win/README.minimal.txt29
-rw-r--r--tools/distrib/win/README.redistrib.txt72
-rw-r--r--tools/distrib/win/README.sandbox.txt14
-rw-r--r--tools/distrib/win/README.standard.txt52
-rw-r--r--tools/distrib/win/transfer_standard.cfg25
-rw-r--r--tools/distrib/win/x64/d3dcompiler_47.dllbin0 -> 4891080 bytes
-rw-r--r--tools/distrib/win/x86/d3dcompiler_47.dllbin0 -> 4108752 bytes
-rw-r--r--tools/exec_util.py41
-rw-r--r--tools/file_util.py201
-rw-r--r--tools/fix_style.bat2
-rw-r--r--tools/fix_style.py145
-rwxr-xr-xtools/fix_style.sh2
-rw-r--r--tools/gclient_hook.py148
-rw-r--r--tools/gclient_util.py42
-rw-r--r--tools/git_util.py172
-rw-r--r--tools/gn_args.py646
-rw-r--r--tools/gypi_to_gn.py206
-rw-r--r--tools/issue_1999.py107
-rw-r--r--tools/make_api_hash_header.py95
-rw-r--r--tools/make_capi_header.py227
-rw-r--r--tools/make_cmake.py254
-rw-r--r--tools/make_config_header.py60
-rw-r--r--tools/make_cppdocs.bat44
-rwxr-xr-xtools/make_cppdocs.sh27
-rw-r--r--tools/make_cpptoc_header.py109
-rw-r--r--tools/make_cpptoc_impl.py765
-rw-r--r--tools/make_ctocpp_header.py154
-rw-r--r--tools/make_ctocpp_impl.py753
-rw-r--r--tools/make_distrib.bat2
-rw-r--r--tools/make_distrib.py1310
-rwxr-xr-xtools/make_distrib.sh2
-rw-r--r--tools/make_gypi_file.py108
-rw-r--r--tools/make_libcef_dll_dylib_impl.py210
-rw-r--r--tools/make_pack_header.py134
-rw-r--r--tools/make_version_header.bat2
-rw-r--r--tools/make_version_header.py109
-rwxr-xr-xtools/make_version_header.sh2
-rw-r--r--tools/make_wrapper_types_header.py50
-rw-r--r--tools/msvs_env.bat73
-rw-r--r--tools/patch.bat2
-rwxr-xr-xtools/patch.sh2
-rw-r--r--tools/patch_updater.bat2
-rw-r--r--tools/patch_updater.py336
-rwxr-xr-xtools/patch_updater.sh2
-rw-r--r--tools/patcher.README.txt18
-rw-r--r--tools/patcher.py120
-rw-r--r--tools/translator.README.txt1697
-rw-r--r--tools/translator.bat3
-rw-r--r--tools/translator.py242
-rwxr-xr-xtools/translator.sh2
-rw-r--r--tools/yapf/LICENSE202
-rw-r--r--tools/yapf/README.cef14
-rw-r--r--tools/yapf/__main__.py16
-rw-r--r--tools/yapf/yapf/__init__.py303
-rw-r--r--tools/yapf/yapf/yapflib/__init__.py13
-rw-r--r--tools/yapf/yapf/yapflib/blank_line_calculator.py183
-rw-r--r--tools/yapf/yapf/yapflib/comment_splicer.py374
-rw-r--r--tools/yapf/yapf/yapflib/continuation_splicer.py52
-rw-r--r--tools/yapf/yapf/yapflib/errors.py23
-rw-r--r--tools/yapf/yapf/yapflib/file_resources.py169
-rw-r--r--tools/yapf/yapf/yapflib/format_decision_state.py799
-rw-r--r--tools/yapf/yapf/yapflib/format_token.py283
-rw-r--r--tools/yapf/yapf/yapflib/line_joiner.py109
-rw-r--r--tools/yapf/yapf/yapflib/py3compat.py113
-rw-r--r--tools/yapf/yapf/yapflib/pytree_unwrapper.py376
-rw-r--r--tools/yapf/yapf/yapflib/pytree_utils.py297
-rw-r--r--tools/yapf/yapf/yapflib/pytree_visitor.py135
-rw-r--r--tools/yapf/yapf/yapflib/reformatter.py588
-rw-r--r--tools/yapf/yapf/yapflib/split_penalty.py559
-rw-r--r--tools/yapf/yapf/yapflib/style.py489
-rw-r--r--tools/yapf/yapf/yapflib/subtype_assigner.py416
-rw-r--r--tools/yapf/yapf/yapflib/unwrapped_line.py497
-rw-r--r--tools/yapf/yapf/yapflib/verifier.py93
-rw-r--r--tools/yapf/yapf/yapflib/yapf_api.py295
-rw-r--r--tools/yapf_util.py28
2131 files changed, 445607 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..c2f0cec2
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,56 @@
+*.gypcmd
+*.mk
+*.ncb
+*.opensdf
+*.props
+*.pyc
+*.rules
+*.sdf
+*.sln
+*.sublime-project
+*.sublime-workspace
+*.suo
+*.targets
+*.user
+*.vcproj
+*.vcxproj
+*.vcxproj.filters
+*.vpj
+*.vpw
+*.vpwhistu
+*.vtg
+*.xcodeproj
+*.xcworkspace
+*_proto.xml
+*_proto_cpp.xml
+*~
+!Android.mk
+.*.sw?
+.DS_Store
+.classpath
+.cproject
+.gdb_history
+.gdbinit
+.landmines
+.metadata
+.project
+.pydevproject
+.vscode
+# Settings directory for eclipse
+/.settings
+.checkstyle
+cscope.*
+Session.vim
+tags
+Thumbs.db
+# IDE's
+.vs/
+.kdev4/
+*.kdev4
+# CEF generated directories
+/binary_distrib
+/docs
+# CEF generated files
+/include/cef_config.h
+/include/cef_version.h
+.ccls-cache/
diff --git a/.style.cfg b/.style.cfg
new file mode 100644
index 00000000..f39eb037
--- /dev/null
+++ b/.style.cfg
@@ -0,0 +1,9 @@
+# Copyright (c) 2017 The Chromium Embedded Framework Authors. All rights
+# reserved. Use of this source code is governed by a BSD-style license that
+# can be found in the LICENSE file
+
+# Configuration settings for tools/fix_style.py
+{
+ # Directories containing these path components will be ignored.
+ 'ignore_directories': ['yapf'],
+}
diff --git a/.style.yapf b/.style.yapf
new file mode 100644
index 00000000..de0c6a70
--- /dev/null
+++ b/.style.yapf
@@ -0,0 +1,2 @@
+[style]
+based_on_style = chromium
diff --git a/AUTHORS.txt b/AUTHORS.txt
new file mode 100644
index 00000000..a5dced5e
--- /dev/null
+++ b/AUTHORS.txt
@@ -0,0 +1,35 @@
+# This file is an addendum to the Chromium AUTHORS file. It lists authors
+# through March 16, 2015 when Git was introduced for source code management.
+# A list of additional authors added after that date can be found by executing
+# this command on a local Git checkout:
+# git log --all --format="%aN <%aE>" | sort -u
+
+Marshall Greenblatt <magreenblatt@gmail.com>
+Jamie Kirkpatrick <jkp@spotify.com>
+Johan Lindström <johanl@spotify.com>
+Igor Pavlov <igor.arabesc.pavlov@gmail.com>
+Yanko Yankov <yyankov@gmail.com>
+Emerick Rogul <emerick@gmail.com>
+Valve Corporation <mac@valvesoftware.com>
+Anthony Taranto <anthony.taranto@gmail.com>
+Joe Andrieu <joe@joeandrieu.com>
+Keith Poole <platima@gmail.com>
+Aviv Rind <avivrind@gmail.com>
+Michael Kaminski <mikeyk730@gmail.com>
+ADInstruments Ltd. <dev.team@adinstruments.com>
+Gus Verdun <gusverdun@gmail.com>
+Joinerysoft Ltd. <cpinfold@joinerysoft.com>
+Johan Björk <phb@spotify.com>
+Dmitry Azaraev <dmitry.azaraev@gmail.com>
+David Xue <ddxue27@gmail.com>
+Russell (Rusty) Richards <fe3o4y@gmail.com>
+Brian Power <powerbf.it@gmail.com>
+Corey Lucier <clucier@adobe.com>
+Mihai Tica <mitica@adobe.com>
+Czarek Tomczak <czarek.tomczak@gmail.com>
+Felix Bruns <felixbruns@spotify.com>
+YuTeh Shen <shenyute@gmail.com>
+Andrei Kurushin <ajax16384@gmail.com>
+Gonzo Berman <gberman@factset.com>
+Jakub Trzebiatowski <kuba.trzebiatowski@gmail.com>
+Nishant Kaushik <nishantk@adobe.com>
diff --git a/BUILD.gn b/BUILD.gn
new file mode 100644
index 00000000..fa93fa62
--- /dev/null
+++ b/BUILD.gn
@@ -0,0 +1,2340 @@
+# Copyright 2016 The Chromium Embedded Framework Authors. Portions copyright
+# 2014 the Chromium Authors. All rights reserved. Use of this source code is
+# governed by a BSD-style license that can be found in the LICENSE file.
+#
+# This file provides the GN configuration for the CEF project. This is not a
+# stand-alone configuration -- it must be built from inside the Chromium source
+# tree. See https://bitbucket.org/chromiumembedded/cef/wiki/BranchesAndBuilding
+# for complete CEF build instructions. See below for links to additional GN
+# documentation.
+#
+# GN Setup:
+#
+# Optionally configure GN by setting the `GN_DEFINES` and/or `GN_ARGUMENTS`
+# environment variables.
+#
+# Example A: Create an official build on Windows:
+#
+# > set GN_DEFINES=is_official_build=true
+#
+# Example B: Generate VS2017 project files in addition to the default Ninja
+# build files on Windows:
+#
+# > set GN_ARGUMENTS=--ide=vs2017 --sln=cef --filters=//cef/*
+#
+# After completing the "GN Automated Build" or "GN Manual Build" section
+# open "out\<build_dir>\cef.sln" for editing and debugging. Building must
+# still be performed using the Ninja command-line.
+#
+# GN Automated Build:
+#
+# Run the `automate-git.py` script as described on the BranchesAndBuilding
+# Wiki page. GN, unlike GYP, supports parallel build configurations. The
+# following command-line flags have special meaning with GN builds:
+#
+# --x64-build Perform an x64 build if specified (requires out/*_GN_x64
+# directories), otherwise perform an x86 build (requires
+# out/*_GN_x86 directories).
+#
+# Directories are created subject to your platform and `GN_DEFINES` settings.
+# See Step 1B in the "GN Manual Build" section below for details.
+#
+# GN Manual Build:
+#
+# 1. Run the `cef_create_projects.[bin|sh]` script. Upon successful completion
+# proceed to Step 2.
+#
+# The `cef_create_projects.[bin|sh]` script will automatically do all of the
+# following:
+#
+# A. Apply patch files to the Chromium source tree. This includes
+# `patch/patches/gn_config.patch` which is required for GN integration.
+#
+# B. Create multiple build output directories appropriate to your platform
+# and `GN_DEFINES` settings. For example:
+#
+# x86 debug build -> out/Debug_GN_x86
+# x86 release build -> out/Release_GN_x86
+# x64 debug build -> out/Debug_GN_x64
+# x64 release build -> out/Release_GN_x64
+#
+# Build output directories will be created subject to the following rules
+# (defined in `tools/gn_args.py` GetAllPlatformConfigs):
+#
+# - Debug and Release directories will be created on all platforms by
+# default. Debug directories will not be created when `is_asan=true`.
+# - x64 directories will always be created on all platforms.
+# - x86 directories will always be created on Windows.
+# - x86 directories will be created on Linux when `use_sysroot=true`.
+#
+# C. Write the `args.gn` file for each build output directory using the
+# `tools/gn_args.py` script to determine the GN arguments. Some arguments
+# are required and some are optional. See script output for details in
+# case of conflicts or recommendations.
+#
+# D. Run `gn gen` for each build output directory to generate project files.
+# Ninja files will be generated by default. Additional command-line
+# arguments (including other project formats) can be specified via the
+# `GN_ARGUMENTS` environment variable. Run `gn gen --help` for a list of
+# supported arguments.
+#
+# 2. Run Ninja from the command-line to build. If the build configuration has
+# changed it will automatically re-run `gn gen` with the same arguments.
+#
+# > ninja -C out/<build_dir> cefclient cefsimple ceftests
+#
+# GN Manual Packaging:
+#
+# Run the `make_distrib.[bat|sh]` script as described on the
+# BranchesAndBuilding Wiki page.
+#
+# Additional GN documentation:
+# http://www.chromium.org/developers/gn-build-configuration
+# https://chromium.googlesource.com/chromium/src/+/master/tools/gn/docs/language.md
+#
+
+import("//base/allocator/allocator.gni")
+import("//build/config/features.gni")
+import("//build/config/locales.gni")
+import("//build/config/ozone.gni")
+import("//build/config/sanitizers/sanitizers.gni")
+import("//build/config/ui.gni")
+import("//chrome/common/features.gni")
+import("//content/public/app/mac_helpers.gni")
+import("//extensions/buildflags/buildflags.gni")
+import("//media/media_options.gni")
+import("//mojo/public/tools/bindings/mojom.gni")
+import("//ppapi/buildflags/buildflags.gni")
+import("//printing/buildflags/buildflags.gni")
+import("//rlz/buildflags/buildflags.gni")
+import("//testing/test.gni")
+import("//third_party/icu/config.gni")
+import("//third_party/widevine/cdm/widevine.gni")
+import("//tools/grit/repack.gni")
+import("//tools/grit/grit_rule.gni")
+import("//tools/v8_context_snapshot/v8_context_snapshot.gni")
+import("//ui/gl/features.gni")
+import("//v8/gni/v8.gni")
+if (is_clang) {
+ import("//build/config/clang/clang.gni")
+}
+if (is_linux) {
+ import("//build/config/linux/pkg_config.gni")
+ import("//third_party/fontconfig/fontconfig.gni")
+}
+if (is_mac) {
+ import("//build/apple/tweak_info_plist.gni")
+ import("//build/config/mac/rules.gni")
+ import("//chrome/version.gni")
+ import("//media/cdm/library_cdm/cdm_paths.gni")
+
+ # Template to compile .xib and .storyboard files.
+ #
+ # Arguments
+ #
+ # sources:
+ # list of string, sources to compile
+ #
+ # ibtool_flags:
+ # (optional) list of string, additional flags to pass to the ibtool
+ template("compile_ib_files") {
+ action_foreach(target_name) {
+ forward_variables_from(invoker,
+ [
+ "testonly",
+ "visibility",
+ ])
+ assert(defined(invoker.sources),
+ "sources must be specified for $target_name")
+ assert(defined(invoker.output_extension),
+ "output_extension must be specified for $target_name")
+
+ ibtool_flags = []
+ if (defined(invoker.ibtool_flags)) {
+ ibtool_flags = invoker.ibtool_flags
+ }
+
+ _output_extension = invoker.output_extension
+
+ script = "//cef/tools/compile_ib_files.py"
+ sources = invoker.sources
+ outputs = [
+ "$target_gen_dir/$target_name/{{source_name_part}}.$_output_extension",
+ ]
+ args = [
+ "--input",
+ "{{source}}",
+ "--output",
+ rebase_path(
+ "$target_gen_dir/$target_name/{{source_name_part}}.$_output_extension",
+ root_build_dir),
+ ]
+ if (!use_system_xcode) {
+ args += [
+ "--developer_dir",
+ hermetic_xcode_path,
+ ]
+ }
+ args += ibtool_flags
+ }
+ }
+
+ # Template to compile and package Mac XIB files as bundle data.
+ #
+ # Arguments
+ #
+ # sources:
+ # list of string, sources to comiple
+ #
+ # output_path:
+ # (optional) string, the path to use for the outputs list in the
+ # bundle_data step. If unspecified, defaults to bundle_resources_dir.
+ template("mac_xib_bundle_data") {
+ _target_name = target_name
+ _compile_target_name = _target_name + "_compile_ibtool"
+
+ compile_ib_files(_compile_target_name) {
+ forward_variables_from(invoker, [ "testonly" ])
+ visibility = [ ":$_target_name" ]
+ sources = invoker.sources
+ output_extension = "nib"
+ ibtool_flags = [
+ "--minimum-deployment-target",
+ mac_deployment_target,
+
+ # TODO(rsesek): Enable this once all the bots are on Xcode 7+.
+ # "--target-device",
+ # "mac",
+ ]
+ }
+
+ bundle_data(_target_name) {
+ forward_variables_from(invoker,
+ [
+ "testonly",
+ "visibility",
+ ])
+
+ public_deps = [
+ ":$_compile_target_name",
+ ]
+ sources = get_target_outputs(":$_compile_target_name")
+
+ _output_path = "{{bundle_resources_dir}}"
+ if (defined(invoker.output_path)) {
+ _output_path = invoker.output_path
+ }
+
+ outputs = [
+ "$_output_path/{{source_file_part}}",
+ ]
+ }
+ }
+}
+if (is_win) {
+ import("//build/config/win/console_app.gni")
+ import("//build/config/win/manifest.gni")
+}
+
+if (is_linux) {
+ declare_args() {
+ # The cefclient target depends on GTK packages that are not available in the
+ # default sysroot environment. So we should only use them when we are not
+ # using the sysroot. Alternatively, the developer might not want to use the
+ # GTK dependencies at all, in which case they can set `cef_use_gtk=false`.
+ cef_use_gtk = !use_sysroot
+ }
+}
+
+#
+# Verify required global arguments configured via `gn args`.
+# Set by GetRequiredArgs() in //cef/tools/gn_args.py.
+#
+
+# Set ENABLE_PRINTING=1 ENABLE_BASIC_PRINTING=1.
+assert(enable_basic_printing)
+assert(enable_print_preview)
+
+# Enable support for Widevine CDM.
+assert(enable_widevine)
+
+if (is_mac || is_win) {
+ # Enable Widevine CDM host verification and storage ID.
+ assert(enable_cdm_host_verification)
+ assert(enable_cdm_storage_id)
+ assert(alternate_cdm_storage_id_key != "")
+ assert(enable_rlz)
+}
+
+# Enable Views UI framework.
+assert(toolkit_views)
+
+if (is_clang) {
+ # Don't use the chrome style plugin.
+ assert(!clang_use_chrome_plugins)
+}
+
+
+#
+# Local variables.
+#
+
+if (is_mac) {
+ # The tweak_info_plist.py script requires a version number with 4 parts. CEF
+ # uses a version number with 3 parts so just set the last part to 0.
+ cef_plist_version = exec_script(
+ "//cef/tools/cef_version.py", [ "plist" ], "trim string", [])
+
+ # Need to be creative to match dylib version formatting requirements.
+ cef_dylib_version = exec_script(
+ "//cef/tools/cef_version.py", [ "dylib" ], "trim string", [])
+}
+
+# Read file lists from gypi files. The gypi_to_gn.py script does not support
+# variable references so all required variables must be explicitly specified in
+# the below configurations.
+gypi_paths = exec_script("//cef/tools/gypi_to_gn.py",
+ [ rebase_path("cef_paths.gypi") ],
+ "scope",
+ [ "cef_paths.gypi" ])
+gypi_paths2 = exec_script("//cef/tools/gypi_to_gn.py",
+ [ rebase_path("cef_paths2.gypi") ],
+ "scope",
+ [ "cef_paths2.gypi" ])
+
+includes_common = gypi_paths2.includes_common + gypi_paths2.includes_common_capi
+includes_mac = gypi_paths2.includes_mac + gypi_paths2.includes_mac_capi
+includes_linux = gypi_paths2.includes_linux + gypi_paths2.includes_linux_capi
+includes_win = gypi_paths2.includes_win + gypi_paths2.includes_win_capi
+
+#
+# Targets that will be built when depending on "//cef".
+#
+
+group("cef") {
+ testonly = true
+ deps = [
+ ":cefsimple",
+ ":ceftests",
+ ":libcef_static_unittests",
+ ]
+
+ if (!is_linux || ozone_platform_x11) {
+ deps += [ ":cefclient" ]
+ }
+}
+
+
+if (is_win) {
+ # Target for building code that accesses chrome_elf internals. Included from
+ # the //chrome_elf:crash target. Defined as a static_library instead of a
+ # source_set because (a) the source files don't export any symbols and (b)
+ # *_switches.cc duplication otherwise causes linker errors.
+ static_library("chrome_elf_set") {
+ sources = [
+ "libcef/common/crash_reporter_client.cc",
+ "libcef/common/crash_reporter_client.h",
+
+ # Required for crash_keys::GetChromeCrashKeys.
+ # Otherwise we need to copy this array into CEF, which would be difficult
+ # to maintain.
+ "//chrome/common/crash_keys.cc",
+ "//chrome/common/chrome_switches.cc",
+ "//components/flags_ui/flags_ui_switches.cc",
+ "//content/public/common/content_switches.cc",
+ ]
+
+ configs += [
+ "libcef/features:config",
+ "//build/config:precompiled_headers",
+ ]
+
+ if (is_component_build) {
+ # Avoid linker errors with content_switches.cc in component build by not
+ # defining CONTENT_EXPORT.
+ defines = ["COMPILE_CONTENT_STATICALLY"]
+ }
+
+ deps = [
+ "//components/crash/core/common", # crash_keys
+
+ # Required by chrome_switches.cc
+ "//chrome/common:buildflags",
+ "//ppapi/buildflags:buildflags",
+ "//printing/buildflags:buildflags",
+ "//ui/base:buildflags",
+
+ # Required by content_switches.cc
+ "//media:media_buildflags",
+
+ # Required by crash_keys.cc (from base/stl_util.h)
+ "//third_party/abseil-cpp:absl",
+ ]
+ }
+}
+
+
+#
+# Test support targets.
+#
+
+# Source files that are linked into libcef and cef_framework and tested by
+# libcef_static_unittests. These sources provide libcef-internal functionality
+# that is limited in scope (e.g. utility classes/methods).
+source_set("libcef_static_unittested") {
+ sources = [
+ "libcef/browser/devtools/devtools_util.cc",
+ "libcef/browser/devtools/devtools_util.h",
+ "libcef/browser/screen_util.h",
+ "libcef/browser/screen_util.cc",
+ ]
+
+ deps = [
+ "//base",
+ ]
+
+ configs += [
+ "libcef/features:config",
+ "//build/config:precompiled_headers",
+ ]
+}
+
+# Executable target that provides test coverage for libcef_static_unittested
+# source files.
+test("libcef_static_unittests") {
+ testonly = true
+
+ sources = [
+ "libcef/browser/devtools/devtools_util_unittest.cc",
+ "libcef/browser/screen_util_unittest.cc",
+ ]
+
+ deps = [
+ ":libcef_static_unittested",
+ "//base/test:run_all_unittests",
+ "//testing/gtest",
+ ]
+
+ configs += [
+ "libcef/features:config",
+ "//build/config:precompiled_headers",
+ ]
+}
+
+# Source files that are linked into libcef and cef_framework and implement
+# interfaces exposed to ceftests via the include/test directory. These sources
+# may access Chromium/CEF internals. This is defined as a separate target from
+# libcef_static to avoid introducing testonly dependencies there.
+source_set("libcef_test_support") {
+ testonly = true
+
+ sources = [
+ "libcef/browser/test/test_helpers_impl.cc",
+ "libcef/browser/test/test_server_impl.cc",
+ "libcef/browser/test/test_server_impl.h",
+ "libcef/common/test/translator_test_impl.cc",
+ ]
+
+ deps = [
+ ":libcef_static",
+ "//net:test_support",
+
+ # Support for UI input events.
+ "//ui/views:test_support",
+ ]
+}
+
+
+#
+# libcef_static target.
+#
+
+source_set("libcef_static") {
+ sources = includes_common +
+ gypi_paths.autogen_cpp_includes + [
+ "libcef/browser/alloy/alloy_browser_context.cc",
+ "libcef/browser/alloy/alloy_browser_context.h",
+ "libcef/browser/alloy/alloy_browser_host_impl.cc",
+ "libcef/browser/alloy/alloy_browser_host_impl.h",
+ "libcef/browser/alloy/alloy_browser_main.cc",
+ "libcef/browser/alloy/alloy_browser_main.h",
+ "libcef/browser/alloy/alloy_content_browser_client.cc",
+ "libcef/browser/alloy/alloy_content_browser_client.h",
+ "libcef/browser/alloy/alloy_download_util.cc",
+ "libcef/browser/alloy/alloy_download_util.h",
+ "libcef/browser/alloy/alloy_web_contents_view_delegate.cc",
+ "libcef/browser/alloy/alloy_web_contents_view_delegate.h",
+ "libcef/browser/alloy/browser_platform_delegate_alloy.cc",
+ "libcef/browser/alloy/browser_platform_delegate_alloy.h",
+ "libcef/browser/alloy/dialogs/alloy_constrained_window_views_client.cc",
+ "libcef/browser/alloy/dialogs/alloy_constrained_window_views_client.h",
+ "libcef/browser/alloy/dialogs/alloy_javascript_dialog_manager_delegate.cc",
+ "libcef/browser/alloy/dialogs/alloy_javascript_dialog_manager_delegate.h",
+ "libcef/browser/alloy/dialogs/alloy_web_contents_dialog_helper.cc",
+ "libcef/browser/alloy/dialogs/alloy_web_contents_dialog_helper.h",
+ "libcef/browser/alloy/chrome_browser_process_alloy.cc",
+ "libcef/browser/alloy/chrome_browser_process_alloy.h",
+ "libcef/browser/alloy/chrome_profile_manager_alloy.cc",
+ "libcef/browser/alloy/chrome_profile_manager_alloy.h",
+ "libcef/browser/alloy/chrome_profile_alloy.cc",
+ "libcef/browser/alloy/chrome_profile_alloy.h",
+ "libcef/browser/audio_capturer.cc",
+ "libcef/browser/audio_capturer.h",
+ "libcef/browser/audio_loopback_stream_creator.cc",
+ "libcef/browser/audio_loopback_stream_creator.h",
+ "libcef/browser/browser_contents_delegate.cc",
+ "libcef/browser/browser_contents_delegate.h",
+ "libcef/browser/browser_context.cc",
+ "libcef/browser/browser_context.h",
+ "libcef/browser/browser_context_keyed_service_factories.cc",
+ "libcef/browser/browser_context_keyed_service_factories.h",
+ "libcef/browser/browser_frame.cc",
+ "libcef/browser/browser_frame.h",
+ "libcef/browser/browser_host_base.cc",
+ "libcef/browser/browser_host_base.h",
+ "libcef/browser/browser_host_create.cc",
+ "libcef/browser/browser_info.cc",
+ "libcef/browser/browser_info.h",
+ "libcef/browser/browser_info_manager.cc",
+ "libcef/browser/browser_info_manager.h",
+ "libcef/browser/browser_manager.cc",
+ "libcef/browser/browser_manager.h",
+ "libcef/browser/browser_message_loop.cc",
+ "libcef/browser/browser_message_loop.h",
+ "libcef/browser/browser_platform_delegate.cc",
+ "libcef/browser/browser_platform_delegate.h",
+ "libcef/browser/browser_platform_delegate_create.cc",
+ "libcef/browser/browser_util.cc",
+ "libcef/browser/browser_util.h",
+ "libcef/browser/certificate_query.cc",
+ "libcef/browser/certificate_query.h",
+ "libcef/browser/chrome/browser_delegate.h",
+ "libcef/browser/chrome/browser_platform_delegate_chrome.cc",
+ "libcef/browser/chrome/browser_platform_delegate_chrome.h",
+ "libcef/browser/chrome/chrome_browser_context.cc",
+ "libcef/browser/chrome/chrome_browser_context.h",
+ "libcef/browser/chrome/chrome_browser_delegate.cc",
+ "libcef/browser/chrome/chrome_browser_delegate.h",
+ "libcef/browser/chrome/chrome_browser_host_impl.cc",
+ "libcef/browser/chrome/chrome_browser_host_impl.h",
+ "libcef/browser/chrome/chrome_browser_main_extra_parts_cef.cc",
+ "libcef/browser/chrome/chrome_browser_main_extra_parts_cef.h",
+ "libcef/browser/chrome/chrome_content_browser_client_cef.cc",
+ "libcef/browser/chrome/chrome_content_browser_client_cef.h",
+ "libcef/browser/chrome/chrome_context_menu_handler.cc",
+ "libcef/browser/chrome/chrome_context_menu_handler.h",
+ "libcef/browser/chrome_crash_reporter_client_stub.cc",
+ "libcef/browser/chrome/extensions/chrome_mime_handler_view_guest_delegate_cef.cc",
+ "libcef/browser/chrome/extensions/chrome_mime_handler_view_guest_delegate_cef.h",
+ "libcef/browser/chrome/views/browser_platform_delegate_chrome_child_window.cc",
+ "libcef/browser/chrome/views/browser_platform_delegate_chrome_child_window.h",
+ "libcef/browser/chrome/views/browser_platform_delegate_chrome_views.cc",
+ "libcef/browser/chrome/views/browser_platform_delegate_chrome_views.h",
+ "libcef/browser/chrome/views/chrome_browser_frame.cc",
+ "libcef/browser/chrome/views/chrome_browser_frame.h",
+ "libcef/browser/chrome/views/chrome_browser_view.cc",
+ "libcef/browser/chrome/views/chrome_browser_view.h",
+ "libcef/browser/chrome/views/chrome_child_window.cc",
+ "libcef/browser/chrome/views/chrome_child_window.h",
+ "libcef/browser/chrome/views/chrome_views_util.cc",
+ "libcef/browser/chrome/views/chrome_views_util.h",
+ "libcef/browser/chrome/views/toolbar_view_impl.cc",
+ "libcef/browser/chrome/views/toolbar_view_impl.h",
+ "libcef/browser/chrome/views/toolbar_view_view.cc",
+ "libcef/browser/chrome/views/toolbar_view_view.h",
+ "libcef/browser/context.cc",
+ "libcef/browser/context.h",
+ "libcef/browser/context_menu_params_impl.cc",
+ "libcef/browser/context_menu_params_impl.h",
+ "libcef/browser/devtools/devtools_controller.cc",
+ "libcef/browser/devtools/devtools_controller.h",
+ "libcef/browser/devtools/devtools_file_manager.cc",
+ "libcef/browser/devtools/devtools_file_manager.h",
+ "libcef/browser/devtools/devtools_frontend.cc",
+ "libcef/browser/devtools/devtools_frontend.h",
+ "libcef/browser/devtools/devtools_manager.cc",
+ "libcef/browser/devtools/devtools_manager.h",
+ "libcef/browser/devtools/devtools_manager_delegate.cc",
+ "libcef/browser/devtools/devtools_manager_delegate.h",
+ "libcef/browser/download_item_impl.cc",
+ "libcef/browser/download_item_impl.h",
+ "libcef/browser/download_manager_delegate.cc",
+ "libcef/browser/download_manager_delegate.h",
+ "libcef/browser/extension_impl.cc",
+ "libcef/browser/extension_impl.h",
+ "libcef/browser/extensions/api/file_system/cef_file_system_delegate.cc",
+ "libcef/browser/extensions/api/file_system/cef_file_system_delegate.h",
+ "libcef/browser/extensions/api/storage/sync_value_store_cache.cc",
+ "libcef/browser/extensions/api/storage/sync_value_store_cache.h",
+ "libcef/browser/extensions/api/tabs/tabs_api.cc",
+ "libcef/browser/extensions/api/tabs/tabs_api.h",
+ "libcef/browser/extensions/alloy_extensions_util.cc",
+ "libcef/browser/extensions/alloy_extensions_util.h",
+ "libcef/browser/extensions/browser_extensions_util.cc",
+ "libcef/browser/extensions/browser_extensions_util.h",
+ "libcef/browser/extensions/browser_platform_delegate_background.cc",
+ "libcef/browser/extensions/browser_platform_delegate_background.h",
+ "libcef/browser/extensions/chrome_api_registration.cc",
+ "libcef/browser/extensions/chrome_api_registration.h",
+ "libcef/browser/extensions/component_extension_resource_manager.cc",
+ "libcef/browser/extensions/component_extension_resource_manager.h",
+ "libcef/browser/extensions/extensions_api_client.cc",
+ "libcef/browser/extensions/extensions_api_client.h",
+ "libcef/browser/extensions/extensions_browser_api_provider.cc",
+ "libcef/browser/extensions/extensions_browser_api_provider.h",
+ "libcef/browser/extensions/extensions_browser_client.cc",
+ "libcef/browser/extensions/extensions_browser_client.h",
+ "libcef/browser/extensions/extension_background_host.cc",
+ "libcef/browser/extensions/extension_background_host.h",
+ "libcef/browser/extensions/extension_function_details.cc",
+ "libcef/browser/extensions/extension_function_details.h",
+ "libcef/browser/extensions/extension_host_delegate.cc",
+ "libcef/browser/extensions/extension_host_delegate.h",
+ "libcef/browser/extensions/extension_system.cc",
+ "libcef/browser/extensions/extension_system.h",
+ "libcef/browser/extensions/extension_system_factory.cc",
+ "libcef/browser/extensions/extension_system_factory.h",
+ "libcef/browser/extensions/extension_view_host.cc",
+ "libcef/browser/extensions/extension_view_host.h",
+ "libcef/browser/extensions/extension_web_contents_observer.cc",
+ "libcef/browser/extensions/extension_web_contents_observer.h",
+ "libcef/browser/extensions/mime_handler_view_guest_delegate.cc",
+ "libcef/browser/extensions/mime_handler_view_guest_delegate.h",
+ "libcef/browser/extensions/value_store/cef_value_store.cc",
+ "libcef/browser/extensions/value_store/cef_value_store.h",
+ "libcef/browser/extensions/value_store/cef_value_store_factory.cc",
+ "libcef/browser/extensions/value_store/cef_value_store_factory.h",
+ "libcef/browser/file_dialog_manager.cc",
+ "libcef/browser/file_dialog_manager.h",
+ "libcef/browser/file_dialog_runner.cc",
+ "libcef/browser/file_dialog_runner.h",
+ "libcef/browser/frame_host_impl.cc",
+ "libcef/browser/frame_host_impl.h",
+ "libcef/browser/frame_service_base.h",
+ "libcef/browser/global_preference_manager_impl.cc",
+ "libcef/browser/global_preference_manager_impl.h",
+ "libcef/browser/image_impl.cc",
+ "libcef/browser/image_impl.h",
+ "libcef/browser/iothread_state.cc",
+ "libcef/browser/iothread_state.h",
+ "libcef/browser/javascript_dialog_runner.h",
+ "libcef/browser/javascript_dialog_manager.cc",
+ "libcef/browser/javascript_dialog_manager.h",
+ "libcef/browser/main_runner.cc",
+ "libcef/browser/main_runner.h",
+ "libcef/browser/media_access_query.cc",
+ "libcef/browser/media_access_query.h",
+ "libcef/browser/media_capture_devices_dispatcher.cc",
+ "libcef/browser/media_capture_devices_dispatcher.h",
+ "libcef/browser/media_router/media_route_impl.cc",
+ "libcef/browser/media_router/media_route_impl.h",
+ "libcef/browser/media_router/media_router_impl.cc",
+ "libcef/browser/media_router/media_router_impl.h",
+ "libcef/browser/media_router/media_router_manager.cc",
+ "libcef/browser/media_router/media_router_manager.h",
+ "libcef/browser/media_router/media_sink_impl.cc",
+ "libcef/browser/media_router/media_sink_impl.h",
+ "libcef/browser/media_router/media_source_impl.cc",
+ "libcef/browser/media_router/media_source_impl.h",
+ "libcef/browser/media_stream_registrar.cc",
+ "libcef/browser/media_stream_registrar.h",
+ "libcef/browser/menu_manager.cc",
+ "libcef/browser/menu_manager.h",
+ "libcef/browser/menu_model_impl.cc",
+ "libcef/browser/menu_model_impl.h",
+ "libcef/browser/menu_runner.h",
+ "libcef/browser/native/browser_platform_delegate_native.cc",
+ "libcef/browser/native/browser_platform_delegate_native.h",
+ "libcef/browser/native/cursor_util.h",
+ "libcef/browser/native/cursor_util.cc",
+ "libcef/browser/native/window_delegate_view.cc",
+ "libcef/browser/native/window_delegate_view.h",
+ "libcef/browser/navigation_entry_impl.cc",
+ "libcef/browser/navigation_entry_impl.h",
+ "libcef/browser/net/chrome_scheme_handler.cc",
+ "libcef/browser/net/chrome_scheme_handler.h",
+ "libcef/browser/net/crlset_file_util_impl.cc",
+ "libcef/browser/net/devtools_scheme_handler.cc",
+ "libcef/browser/net/devtools_scheme_handler.h",
+ "libcef/browser/net/internal_scheme_handler.cc",
+ "libcef/browser/net/internal_scheme_handler.h",
+ "libcef/browser/net/scheme_handler.cc",
+ "libcef/browser/net/scheme_handler.h",
+ "libcef/browser/net/throttle_handler.cc",
+ "libcef/browser/net/throttle_handler.h",
+ "libcef/browser/net_service/browser_urlrequest_impl.cc",
+ "libcef/browser/net_service/browser_urlrequest_impl.h",
+ "libcef/browser/net_service/cookie_helper.cc",
+ "libcef/browser/net_service/cookie_helper.h",
+ "libcef/browser/net_service/cookie_manager_impl.cc",
+ "libcef/browser/net_service/cookie_manager_impl.h",
+ "libcef/browser/net_service/login_delegate.cc",
+ "libcef/browser/net_service/login_delegate.h",
+ "libcef/browser/net_service/proxy_url_loader_factory.cc",
+ "libcef/browser/net_service/proxy_url_loader_factory.h",
+ "libcef/browser/net_service/resource_handler_wrapper.cc",
+ "libcef/browser/net_service/resource_handler_wrapper.h",
+ "libcef/browser/net_service/resource_request_handler_wrapper.cc",
+ "libcef/browser/net_service/resource_request_handler_wrapper.h",
+ "libcef/browser/net_service/response_filter_wrapper.cc",
+ "libcef/browser/net_service/response_filter_wrapper.h",
+ "libcef/browser/net_service/stream_reader_url_loader.cc",
+ "libcef/browser/net_service/stream_reader_url_loader.h",
+ "libcef/browser/net_service/url_loader_factory_getter.cc",
+ "libcef/browser/net_service/url_loader_factory_getter.h",
+ "libcef/browser/origin_whitelist_impl.cc",
+ "libcef/browser/origin_whitelist_impl.h",
+ "libcef/browser/osr/browser_platform_delegate_osr.cc",
+ "libcef/browser/osr/browser_platform_delegate_osr.h",
+ "libcef/browser/osr/host_display_client_osr.cc",
+ "libcef/browser/osr/host_display_client_osr.h",
+ "libcef/browser/osr/motion_event_osr.cc",
+ "libcef/browser/osr/motion_event_osr.h",
+ "libcef/browser/osr/osr_accessibility_util.cc",
+ "libcef/browser/osr/osr_accessibility_util.h",
+ "libcef/browser/osr/osr_util.cc",
+ "libcef/browser/osr/osr_util.h",
+ "libcef/browser/osr/render_widget_host_view_osr.cc",
+ "libcef/browser/osr/render_widget_host_view_osr.h",
+ "libcef/browser/osr/synthetic_gesture_target_osr.cc",
+ "libcef/browser/osr/synthetic_gesture_target_osr.h",
+ "libcef/browser/osr/touch_handle_drawable_osr.cc",
+ "libcef/browser/osr/touch_handle_drawable_osr.h",
+ "libcef/browser/osr/touch_selection_controller_client_osr.cc",
+ "libcef/browser/osr/touch_selection_controller_client_osr.h",
+ "libcef/browser/osr/video_consumer_osr.cc",
+ "libcef/browser/osr/video_consumer_osr.h",
+ "libcef/browser/osr/web_contents_view_osr.cc",
+ "libcef/browser/osr/web_contents_view_osr.h",
+ "libcef/browser/path_util_impl.cc",
+ "libcef/browser/permission_prompt.cc",
+ "libcef/browser/permission_prompt.h",
+ "libcef/browser/prefs/browser_prefs.cc",
+ "libcef/browser/prefs/browser_prefs.h",
+ "libcef/browser/prefs/pref_helper.cc",
+ "libcef/browser/prefs/pref_helper.h",
+ "libcef/browser/prefs/pref_registrar.cc",
+ "libcef/browser/prefs/pref_registrar.h",
+ "libcef/browser/prefs/pref_store.cc",
+ "libcef/browser/prefs/pref_store.h",
+ "libcef/browser/prefs/renderer_prefs.cc",
+ "libcef/browser/prefs/renderer_prefs.h",
+ "libcef/browser/print_settings_impl.cc",
+ "libcef/browser/print_settings_impl.h",
+ "libcef/browser/printing/print_util.cc",
+ "libcef/browser/printing/print_util.h",
+ "libcef/browser/process_util_impl.cc",
+ "libcef/browser/request_context_handler_map.cc",
+ "libcef/browser/request_context_handler_map.h",
+ "libcef/browser/request_context_impl.cc",
+ "libcef/browser/request_context_impl.h",
+ "libcef/browser/scheme_impl.cc",
+ "libcef/browser/server_impl.cc",
+ "libcef/browser/server_impl.h",
+ "libcef/browser/simple_menu_model_impl.cc",
+ "libcef/browser/simple_menu_model_impl.h",
+ "libcef/browser/speech_recognition_manager_delegate.cc",
+ "libcef/browser/speech_recognition_manager_delegate.h",
+ "libcef/browser/ssl_host_state_delegate.cc",
+ "libcef/browser/ssl_host_state_delegate.h",
+ "libcef/browser/ssl_info_impl.cc",
+ "libcef/browser/ssl_info_impl.h",
+ "libcef/browser/ssl_status_impl.cc",
+ "libcef/browser/ssl_status_impl.h",
+ "libcef/browser/stream_impl.cc",
+ "libcef/browser/stream_impl.h",
+ "libcef/browser/trace_impl.cc",
+ "libcef/browser/trace_subscriber.cc",
+ "libcef/browser/trace_subscriber.h",
+ "libcef/browser/thread_util.h",
+ "libcef/browser/views/basic_label_button_impl.cc",
+ "libcef/browser/views/basic_label_button_impl.h",
+ "libcef/browser/views/basic_label_button_view.cc",
+ "libcef/browser/views/basic_label_button_view.h",
+ "libcef/browser/views/basic_panel_impl.cc",
+ "libcef/browser/views/basic_panel_impl.h",
+ "libcef/browser/views/basic_panel_view.cc",
+ "libcef/browser/views/basic_panel_view.h",
+ "libcef/browser/views/box_layout_impl.cc",
+ "libcef/browser/views/box_layout_impl.h",
+ "libcef/browser/views/browser_platform_delegate_views.cc",
+ "libcef/browser/views/browser_platform_delegate_views.h",
+ "libcef/browser/views/browser_view_impl.cc",
+ "libcef/browser/views/browser_view_impl.h",
+ "libcef/browser/views/browser_view_view.cc",
+ "libcef/browser/views/browser_view_view.h",
+ "libcef/browser/views/button_impl.h",
+ "libcef/browser/views/button_view.h",
+ "libcef/browser/views/display_impl.cc",
+ "libcef/browser/views/display_impl.h",
+ "libcef/browser/views/fill_layout_impl.cc",
+ "libcef/browser/views/fill_layout_impl.h",
+ "libcef/browser/views/label_button_impl.h",
+ "libcef/browser/views/label_button_view.h",
+ "libcef/browser/views/layout_impl.h",
+ "libcef/browser/views/layout_adapter.cc",
+ "libcef/browser/views/layout_adapter.h",
+ "libcef/browser/views/layout_util.cc",
+ "libcef/browser/views/layout_util.h",
+ "libcef/browser/views/menu_button_impl.cc",
+ "libcef/browser/views/menu_button_impl.h",
+ "libcef/browser/views/menu_button_view.cc",
+ "libcef/browser/views/menu_button_view.h",
+ "libcef/browser/views/menu_runner_views.cc",
+ "libcef/browser/views/menu_runner_views.h",
+ "libcef/browser/views/overlay_view_host.cc",
+ "libcef/browser/views/overlay_view_host.h",
+ "libcef/browser/views/panel_impl.h",
+ "libcef/browser/views/panel_view.h",
+ "libcef/browser/views/scroll_view_impl.cc",
+ "libcef/browser/views/scroll_view_impl.h",
+ "libcef/browser/views/scroll_view_view.cc",
+ "libcef/browser/views/scroll_view_view.h",
+ "libcef/browser/views/textfield_impl.cc",
+ "libcef/browser/views/textfield_impl.h",
+ "libcef/browser/views/textfield_view.cc",
+ "libcef/browser/views/textfield_view.h",
+ "libcef/browser/views/view_adapter.cc",
+ "libcef/browser/views/view_adapter.h",
+ "libcef/browser/views/view_impl.h",
+ "libcef/browser/views/view_util.cc",
+ "libcef/browser/views/view_util.h",
+ "libcef/browser/views/view_view.h",
+ "libcef/browser/views/window_impl.cc",
+ "libcef/browser/views/window_impl.h",
+ "libcef/browser/views/window_view.cc",
+ "libcef/browser/views/window_view.h",
+ "libcef/browser/x509_certificate_impl.cc",
+ "libcef/browser/x509_certificate_impl.h",
+ "libcef/browser/x509_cert_principal_impl.cc",
+ "libcef/browser/x509_cert_principal_impl.h",
+ "libcef/browser/xml_reader_impl.cc",
+ "libcef/browser/xml_reader_impl.h",
+ "libcef/browser/zip_reader_impl.cc",
+ "libcef/browser/zip_reader_impl.h",
+ "libcef/common/alloy/alloy_content_client.cc",
+ "libcef/common/alloy/alloy_content_client.h",
+ "libcef/common/alloy/alloy_main_delegate.cc",
+ "libcef/common/alloy/alloy_main_delegate.h",
+ "libcef/common/alloy/alloy_main_runner_delegate.cc",
+ "libcef/common/alloy/alloy_main_runner_delegate.h",
+ "libcef/common/app_manager.cc",
+ "libcef/common/app_manager.h",
+ "libcef/common/base_impl.cc",
+ "libcef/common/cef_switches.cc",
+ "libcef/common/cef_switches.h",
+ "libcef/common/chrome/chrome_content_client_cef.cc",
+ "libcef/common/chrome/chrome_content_client_cef.h",
+ "libcef/common/chrome/chrome_main_delegate_cef.cc",
+ "libcef/common/chrome/chrome_main_delegate_cef.h",
+ "libcef/common/chrome/chrome_main_runner_delegate.cc",
+ "libcef/common/chrome/chrome_main_runner_delegate.h",
+ "libcef/common/command_line_impl.cc",
+ "libcef/common/command_line_impl.h",
+ "libcef/common/crash_reporter_client.cc",
+ "libcef/common/crash_reporter_client.h",
+ "libcef/common/crash_reporting.cc",
+ "libcef/common/crash_reporting.h",
+ "libcef/common/drag_data_impl.cc",
+ "libcef/common/drag_data_impl.h",
+ "libcef/common/extensions/chrome_generated_schemas.cc",
+ "libcef/common/extensions/chrome_generated_schemas.h",
+ "libcef/common/extensions/extensions_api_provider.cc",
+ "libcef/common/extensions/extensions_api_provider.h",
+ "libcef/common/extensions/extensions_client.cc",
+ "libcef/common/extensions/extensions_client.h",
+ "libcef/common/extensions/extensions_util.cc",
+ "libcef/common/extensions/extensions_util.h",
+ "libcef/common/file_util_impl.cc",
+ "libcef/common/frame_util.cc",
+ "libcef/common/frame_util.h",
+ "libcef/common/i18n_util_impl.cc",
+ "libcef/common/json_impl.cc",
+ "libcef/common/main_runner_delegate.h",
+ "libcef/common/main_runner_handler.h",
+ "libcef/common/net/http_header_utils.cc",
+ "libcef/common/net/http_header_utils.h",
+ "libcef/common/net/net_resource_provider.cc",
+ "libcef/common/net/net_resource_provider.h",
+ "libcef/common/net/scheme_registration.cc",
+ "libcef/common/net/scheme_registration.h",
+ "libcef/common/net/url_util.cc",
+ "libcef/common/net/url_util.h",
+ "libcef/common/net_service/net_service_util.cc",
+ "libcef/common/net_service/net_service_util.h",
+ "libcef/common/parser_impl.cc",
+ "libcef/common/process_message_impl.cc",
+ "libcef/common/process_message_impl.h",
+ "libcef/common/process_message_smr_impl.cc",
+ "libcef/common/process_message_smr_impl.h",
+ "libcef/common/request_impl.cc",
+ "libcef/common/request_impl.h",
+ "libcef/common/resource_bundle_delegate.cc",
+ "libcef/common/resource_bundle_delegate.h",
+ "libcef/common/resource_bundle_impl.cc",
+ "libcef/common/resource_bundle_impl.h",
+ "libcef/common/resource_util.cc",
+ "libcef/common/resource_util.h",
+ "libcef/common/response_impl.cc",
+ "libcef/common/response_impl.h",
+ "libcef/common/scheme_registrar_impl.cc",
+ "libcef/common/scheme_registrar_impl.h",
+ "libcef/common/string_list_impl.cc",
+ "libcef/common/string_map_impl.cc",
+ "libcef/common/string_multimap_impl.cc",
+ "libcef/common/string_types_impl.cc",
+ "libcef/common/string_util.cc",
+ "libcef/common/string_util.h",
+ "libcef/common/task_impl.cc",
+ "libcef/common/task_runner_impl.cc",
+ "libcef/common/task_runner_impl.h",
+ "libcef/common/task_runner_manager.cc",
+ "libcef/common/task_runner_manager.h",
+ "libcef/common/thread_impl.cc",
+ "libcef/common/thread_impl.h",
+ "libcef/common/time_impl.cc",
+ "libcef/common/time_util.h",
+ "libcef/common/tracker.cc",
+ "libcef/common/tracker.h",
+ "libcef/common/urlrequest_impl.cc",
+ "libcef/common/value_base.cc",
+ "libcef/common/value_base.h",
+ "libcef/common/values_impl.cc",
+ "libcef/common/values_impl.h",
+ "libcef/common/waitable_event_impl.cc",
+ "libcef/common/waitable_event_impl.h",
+ "libcef/features/runtime.h",
+ "libcef/features/runtime_checks.h",
+ "libcef/renderer/alloy/alloy_content_renderer_client.cc",
+ "libcef/renderer/alloy/alloy_content_renderer_client.h",
+ "libcef/renderer/alloy/alloy_render_thread_observer.cc",
+ "libcef/renderer/alloy/alloy_render_thread_observer.h",
+ "libcef/renderer/alloy/url_loader_throttle_provider_impl.cc",
+ "libcef/renderer/alloy/url_loader_throttle_provider_impl.h",
+ "libcef/renderer/browser_impl.cc",
+ "libcef/renderer/browser_impl.h",
+ "libcef/renderer/chrome/chrome_content_renderer_client_cef.cc",
+ "libcef/renderer/chrome/chrome_content_renderer_client_cef.h",
+ "libcef/renderer/dom_document_impl.cc",
+ "libcef/renderer/dom_document_impl.h",
+ "libcef/renderer/dom_node_impl.cc",
+ "libcef/renderer/dom_node_impl.h",
+ "libcef/renderer/extensions/extensions_dispatcher_delegate.cc",
+ "libcef/renderer/extensions/extensions_dispatcher_delegate.h",
+ "libcef/renderer/extensions/extensions_renderer_client.cc",
+ "libcef/renderer/extensions/extensions_renderer_client.h",
+ "libcef/renderer/extensions/print_render_frame_helper_delegate.cc",
+ "libcef/renderer/extensions/print_render_frame_helper_delegate.h",
+ "libcef/renderer/frame_impl.cc",
+ "libcef/renderer/frame_impl.h",
+ "libcef/renderer/render_frame_observer.cc",
+ "libcef/renderer/render_frame_observer.h",
+ "libcef/renderer/render_frame_util.cc",
+ "libcef/renderer/render_frame_util.h",
+ "libcef/renderer/render_manager.cc",
+ "libcef/renderer/render_manager.h",
+ "libcef/renderer/render_urlrequest_impl.cc",
+ "libcef/renderer/render_urlrequest_impl.h",
+ "libcef/renderer/thread_util.h",
+ "libcef/renderer/v8_impl.cc",
+ "libcef/renderer/v8_impl.h",
+
+ # For Chrome runtime support.
+ "//chrome/app/chrome_main_delegate.cc",
+ "//chrome/app/chrome_main_delegate.h",
+ ]
+
+ configs += [
+ "libcef/features:config",
+ "//build/config:precompiled_headers",
+ ]
+
+ public_configs = [
+ "libcef/features:config",
+ ]
+
+ include_dirs = [
+ # Crashpad code uses paths relative to this directory.
+ "//third_party/crashpad/crashpad",
+ ]
+
+ public_deps = [
+ # Bring in feature flag defines.
+ "//cef/libcef/features",
+ # Support relative include paths.
+ "//third_party/abseil-cpp:absl",
+ ]
+
+ deps = [
+ ":cef_make_headers",
+ "libcef/common/mojom",
+
+ ":libcef_static_unittested",
+
+ # Generate API bindings for extensions.
+ # TODO(cef): Enable if/when CEF exposes its own Mojo APIs. See
+ # libcef/common/extensions/api/README.txt for details.
+ #"libcef/common/extensions/api",
+ #"libcef/common/extensions/api:api_registration",
+ "libcef/common/extensions/api:extensions_features",
+
+ # Normal build dependencies. Should be sorted alphabetically.
+ "//base",
+ "//base:base_static",
+ "//base/third_party/dynamic_annotations",
+ "//cc",
+ "//chrome:dependencies",
+ "//chrome:packed_resources",
+ "//chrome:resources",
+ "//chrome:strings",
+ "//chrome/common:buildflags",
+ "//chrome/services/printing:lib",
+ "//components/cdm/renderer",
+ "//components/certificate_transparency",
+ "//components/component_updater",
+ "//components/content_settings/core/browser",
+ "//components/content_settings/core/common",
+ "//components/crx_file",
+ "//components/google/core/common",
+ "//components/keyed_service/content:content",
+ "//components/keyed_service/core:core",
+ "//components/media_router/common/mojom:media_router",
+ "//components/navigation_interception",
+ "//components/network_session_configurator/common",
+ "//components/pdf/browser",
+ "//components/pdf/renderer",
+ "//components/plugins/renderer",
+ "//components/pref_registry",
+ "//components/printing/browser",
+ "//components/printing/common",
+ "//components/printing/renderer",
+ "//components/proxy_config",
+ "//components/services/print_compositor/public/cpp",
+ "//components/services/print_compositor/public/mojom",
+ "//components/update_client",
+ "//components/url_formatter",
+ "//components/user_prefs",
+ "//components/version_info",
+ "//components/visitedlink/browser",
+ "//components/visitedlink/common",
+ "//components/visitedlink/renderer",
+ "//components/viz/service",
+ "//components/web_cache/renderer",
+ "//content/public/app",
+ "//content/public/browser",
+ "//content/public/child",
+ "//content/public/common",
+ "//content/public/gpu",
+ "//content/public/renderer",
+ "//content/public/utility",
+ "//crypto",
+ "//device/base",
+ "//extensions/browser",
+ "//extensions/buildflags",
+ "//extensions/common/api",
+ "//extensions/common:core_api_provider",
+ "//extensions/renderer",
+ "//gpu",
+ "//ipc",
+ "//media",
+ "//net",
+ "//pdf",
+ "//ppapi/buildflags",
+ "//printing/buildflags",
+ "//services/network:network_service",
+ "//services/network/public/cpp",
+ "//services/service_manager/public/cpp",
+ "//skia",
+ "//storage/browser",
+ "//third_party/blink/public:blink",
+ "//third_party/brotli:dec",
+ "//third_party/cld_3/src/src:cld_3",
+ "//third_party/crashpad/crashpad/handler",
+ "//third_party/hunspell",
+ "//third_party/leveldatabase",
+ "//third_party/libxml:libxml",
+ "//third_party/widevine/cdm:headers",
+ "//third_party/widevine/cdm",
+ "//third_party/icu",
+ "//third_party/zlib:minizip",
+ "//ui/base",
+ "//ui/base/ime",
+ "//ui/events",
+ "//ui/events:events_base",
+ "//ui/gfx",
+ "//ui/gfx/geometry",
+ "//ui/gfx/ipc",
+ "//ui/gfx/ipc/geometry",
+ "//ui/gfx/ipc/skia",
+ "//ui/gl",
+ "//ui/strings",
+ "//ui/views",
+ "//ui/views/controls/webview",
+ "//url",
+ "//v8",
+ ]
+
+ if (is_win) {
+ sources += includes_win + [
+ "libcef/browser/alloy/alloy_browser_main_win.cc",
+ "libcef/browser/native/browser_platform_delegate_native_win.cc",
+ "libcef/browser/native/browser_platform_delegate_native_win.h",
+ "libcef/browser/osr/browser_platform_delegate_osr_win.cc",
+ "libcef/browser/osr/browser_platform_delegate_osr_win.h",
+ ]
+
+ deps += [
+ "//chrome/install_static:secondary_module",
+ "//chrome/chrome_elf",
+ ]
+
+ if (is_component_build) {
+ deps += [ "//content:sandbox_helper_win" ]
+ }
+
+ libs = [
+ "comctl32.lib",
+ # For D3D11_DECODER_PROFILE_H264_VLD_NOFGT.
+ "dxguid.lib",
+ ]
+
+ data_deps = [
+ "//chrome/elevation_service",
+ ]
+ }
+
+ if (is_linux) {
+ sources += includes_linux + [
+ "libcef/browser/native/browser_platform_delegate_native_linux.cc",
+ "libcef/browser/native/browser_platform_delegate_native_linux.h",
+ "libcef/browser/osr/browser_platform_delegate_osr_linux.cc",
+ "libcef/browser/osr/browser_platform_delegate_osr_linux.h",
+ "libcef/browser/printing/print_dialog_linux.cc",
+ "libcef/browser/printing/print_dialog_linux.h",
+ "libcef/common/util_linux.h",
+ "libcef/common/util_linux.cc",
+ ]
+
+ if (ozone_platform_x11) {
+ sources += [
+ "libcef/browser/native/window_x11.cc",
+ "libcef/browser/native/window_x11.h",
+ ]
+ }
+
+ deps += [
+ "//build/config/freetype",
+ "//third_party/fontconfig",
+ ]
+
+ if (is_linux && !ozone_platform_x11) {
+ deps += [
+ "//third_party/angle:libEGL",
+ ]
+ }
+ }
+
+ if (is_mac) {
+ sources += includes_mac + [
+ "libcef/browser/native/browser_platform_delegate_native_mac.h",
+ "libcef/browser/native/browser_platform_delegate_native_mac.mm",
+ "libcef/browser/native/cursor_util_mac.mm",
+ "libcef/browser/native/javascript_dialog_runner_mac.h",
+ "libcef/browser/native/javascript_dialog_runner_mac.mm",
+ "libcef/browser/native/menu_runner_mac.h",
+ "libcef/browser/native/menu_runner_mac.mm",
+ "libcef/browser/osr/browser_platform_delegate_osr_mac.h",
+ "libcef/browser/osr/browser_platform_delegate_osr_mac.mm",
+ "libcef/browser/views/native_widget_mac.h",
+ "libcef/browser/views/native_widget_mac.mm",
+ "libcef/browser/views/ns_window.h",
+ "libcef/browser/views/ns_window.mm",
+ "libcef/browser/views/view_util_mac.mm",
+ "libcef/common/util_mac.h",
+ "libcef/common/util_mac.mm",
+
+ # For Chrome runtime support.
+ "//chrome/app/chrome_main_mac.h",
+ "//chrome/app/chrome_main_mac.mm",
+ ]
+ }
+
+ if (ozone_platform_x11) {
+ deps += [ "//ui/events/devices/x11" ]
+ }
+
+ if (v8_use_external_startup_data && use_v8_context_snapshot) {
+ deps += [ "//tools/v8_context_snapshot" ]
+ }
+
+ if (use_aura) {
+ sources += [
+ "libcef/browser/native/browser_platform_delegate_native_aura.cc",
+ "libcef/browser/native/browser_platform_delegate_native_aura.h",
+ "libcef/browser/native/cursor_util_aura.cc",
+ "libcef/browser/native/menu_runner_views_aura.cc",
+ "libcef/browser/native/menu_runner_views_aura.h",
+ "libcef/browser/views/view_util_aura.cc",
+ ]
+
+ deps += [
+ "//ui/aura",
+ "//ui/wm",
+ "//ui/wm/public",
+ ]
+ }
+
+ if (enable_cdm_host_verification) {
+ sources += [
+ "libcef/common/cdm_host_file_path.cc",
+ "libcef/common/cdm_host_file_path.h",
+ ]
+ }
+}
+
+
+#
+# libcef_dll_wrapper static targets.
+#
+
+# Configuration that will be applied to all targets that build autogen files.
+config("libcef_autogen_config") {
+ if (is_clang) {
+ cflags = [
+ # Disable clang warnings related to CEF's translation layer templates.
+ "-Wno-undefined-var-template",
+ ]
+ }
+}
+
+# Configuration that will be applied to all targets that depend on
+# libcef_dll_wrapper.
+config("libcef_dll_wrapper_config") {
+ include_dirs = [
+ # CEF sources use include paths relative to the CEF root directory.
+ ".",
+ # CEF generates some header files that also need to be discoverable.
+ # They will be copied to the include/ directory in the binary distribution.
+ "$root_out_dir/includes",
+ ]
+
+ configs = [ ":libcef_autogen_config" ]
+
+ if (is_win) {
+ if (current_cpu == "x86") {
+ # Set the initial stack size to 0.5MiB, instead of the 1.5MiB minimum
+ # needed by CEF's main thread. This saves significant memory on threads
+ # (like those in the Windows thread pool, and others) whose stack size we
+ # can only control through this setting. The main thread (in 32-bit builds
+ # only) uses fibers to switch to a 4MiB stack at runtime via
+ # CefRunWinMainWithPreferredStackSize().
+ ldflags = [ "/STACK:0x80000" ]
+ } else {
+ # Increase the initial stack size to 8MiB from the default 1MiB.
+ ldflags = [ "/STACK:0x800000" ]
+ }
+ }
+}
+
+# libcef_dll_wrapper target.
+static_library("libcef_dll_wrapper") {
+ sources = includes_common +
+ gypi_paths.autogen_cpp_includes +
+ gypi_paths2.includes_capi +
+ gypi_paths.autogen_capi_includes +
+ gypi_paths2.includes_wrapper +
+ gypi_paths2.libcef_dll_wrapper_sources_base +
+ gypi_paths2.libcef_dll_wrapper_sources_common +
+ gypi_paths.autogen_client_side
+
+ if (is_mac) {
+ sources += gypi_paths2.libcef_dll_wrapper_sources_mac
+ }
+
+ defines = [ "WRAPPING_CEF_SHARED" ]
+
+ configs += [ ":libcef_dll_wrapper_config" ]
+ public_configs = [ ":libcef_dll_wrapper_config" ]
+
+ deps = [ ":cef_make_headers" ]
+}
+
+
+#
+# cef_sandbox target.
+#
+
+if (is_win) {
+ static_library("cef_sandbox") {
+ sources = [ "libcef_dll/sandbox/sandbox_win.cc" ]
+ # CEF sources use include paths relative to the CEF root directory.
+ include_dirs = [ "." ]
+ deps = [ "libcef/features", "//sandbox" ]
+ }
+}
+
+if (is_mac) {
+ static_library("cef_sandbox") {
+ sources = [ "libcef_dll/sandbox/sandbox_mac.mm" ]
+ # CEF sources use include paths relative to the CEF root directory.
+ include_dirs = [ "." ]
+ deps = [
+ "//build/config:executable_deps",
+ "//sandbox/mac:seatbelt"
+ ]
+ }
+}
+
+#
+# Resource grit/pack targets.
+#
+
+# Included in locales/*.pak via //chrome/chrome_repack_locales.gni.
+grit("cef_strings") {
+ source = "libcef/resources/cef_strings.grd"
+ outputs = [
+ "grit/cef_strings.h",
+ ]
+ all_locales = platform_pak_locales + [ "fake-bidi" ]
+ foreach(locale, all_locales) {
+ outputs += [ "cef_strings_${locale}.pak" ]
+ }
+}
+
+# Included in resources.pak via //chrome/chrome_paks.gni.
+grit("cef_resources") {
+ source = "libcef/resources/cef_resources.grd"
+ outputs = [
+ "grit/cef_resources.h",
+ "cef_resources.pak",
+ ]
+ grit_flags = [
+ "-E",
+ "root_gen_dir=" + rebase_path(root_gen_dir, root_build_dir),
+ ]
+}
+
+# Helper for generating pack header files.
+template("make_pack_header") {
+ assert(defined(invoker.header))
+ assert(defined(invoker.inputs))
+
+ action("make_pack_header_${target_name}") {
+ script = "tools/make_pack_header.py"
+
+ inputs = invoker.inputs
+ outputs = [ invoker.header ]
+
+ args = rebase_path(outputs, root_build_dir) +
+ rebase_path(inputs, root_build_dir)
+
+ if (defined(invoker.deps)) {
+ deps = invoker.deps
+ }
+ }
+}
+
+# Generate cef_pack_resources.h.
+make_pack_header("resources") {
+ header = "$root_out_dir/includes/include/cef_pack_resources.h"
+ inputs = [
+ "$root_gen_dir/base/tracing/protos/grit/tracing_proto_resources.h",
+ "$root_gen_dir/cef/grit/cef_resources.h",
+ "$root_gen_dir/chrome/grit/browser_resources.h",
+ "$root_gen_dir/chrome/grit/common_resources.h",
+ "$root_gen_dir/chrome/grit/component_extension_resources.h",
+ "$root_gen_dir/chrome/grit/dev_ui_browser_resources.h",
+ "$root_gen_dir/chrome/grit/pdf_resources.h",
+ "$root_gen_dir/chrome/grit/renderer_resources.h",
+ "$root_gen_dir/components/grit/components_resources.h",
+ "$root_gen_dir/components/grit/dev_ui_components_resources.h",
+ "$root_gen_dir/content/browser/devtools/grit/devtools_resources.h",
+ "$root_gen_dir/content/browser/tracing/grit/tracing_resources.h",
+ "$root_gen_dir/content/browser/webrtc/resources/grit/webrtc_internals_resources.h",
+ "$root_gen_dir/content/grit/content_resources.h",
+ "$root_gen_dir/content/grit/dev_ui_content_resources.h",
+ "$root_gen_dir/extensions/grit/extensions_browser_resources.h",
+ "$root_gen_dir/extensions/grit/extensions_renderer_resources.h",
+ "$root_gen_dir/extensions/grit/extensions_resources.h",
+ "$root_gen_dir/mojo/public/js/grit/mojo_bindings_resources.h",
+ "$root_gen_dir/net/grit/net_resources.h",
+ "$root_gen_dir/third_party/blink/public/resources/grit/blink_resources.h",
+ "$root_gen_dir/ui/resources/grit/ui_resources.h",
+ "$root_gen_dir/ui/resources/grit/webui_resources.h",
+ "$root_gen_dir/ui/views/resources/grit/views_resources.h",
+ ]
+
+ deps = [
+ ":cef_resources",
+ "//base/tracing/protos:chrome_track_event_resources",
+ "//chrome/browser:dev_ui_browser_resources",
+ "//chrome/browser:resources",
+ "//chrome/browser/resources:component_extension_resources",
+ "//chrome/browser/resources/pdf:resources",
+ "//chrome/common:resources",
+ "//chrome/renderer:resources",
+ "//components/resources:components_resources",
+ "//components/resources:dev_ui_components_resources",
+ "//content/browser/devtools:devtools_resources",
+ "//content/browser/tracing:resources",
+ "//content/browser/webrtc/resources",
+ "//content:content_resources",
+ "//content:dev_ui_content_resources",
+ "//extensions:extensions_browser_resources",
+ "//extensions:extensions_renderer_resources",
+ "//extensions:extensions_resources_grd",
+ "//mojo/public/js:resources",
+ "//net:net_resources",
+ "//third_party/blink/public:resources",
+ "//ui/resources:ui_resources_grd",
+ "//ui/resources:webui_resources_grd",
+ "//ui/views/resources:resources_grd",
+ ]
+}
+
+# Generate cef_pack_strings.h.
+make_pack_header("strings") {
+ header = "$root_out_dir/includes/include/cef_pack_strings.h"
+ inputs = [
+ "$root_gen_dir/cef/grit/cef_strings.h",
+ "$root_gen_dir/chrome/grit/chromium_strings.h",
+ "$root_gen_dir/chrome/grit/generated_resources.h",
+ "$root_gen_dir/chrome/grit/locale_settings.h",
+ "$root_gen_dir/chrome/grit/platform_locale_settings.h",
+ "$root_gen_dir/components/omnibox/resources/grit/omnibox_pedal_synonyms.h",
+ "$root_gen_dir/components/strings/grit/components_chromium_strings.h",
+ "$root_gen_dir/components/strings/grit/components_strings.h",
+ "$root_gen_dir/extensions/strings/grit/extensions_strings.h",
+ "$root_gen_dir/services/strings/grit/services_strings.h",
+ "$root_gen_dir/third_party/blink/public/strings/grit/blink_accessibility_strings.h",
+ "$root_gen_dir/third_party/blink/public/strings/grit/blink_strings.h",
+ "$root_gen_dir/ui/strings/grit/ui_strings.h",
+ ]
+
+ deps = [
+ ":cef_strings",
+ "//chrome/app:chromium_strings",
+ "//chrome/app:generated_resources",
+ "//chrome/app/resources:locale_settings",
+ "//chrome/app/resources:platform_locale_settings",
+ "//components/omnibox/resources:omnibox_pedal_synonyms",
+ "//components/strings:components_chromium_strings",
+ "//components/strings:components_locale_settings",
+ "//components/strings:components_strings",
+ "//extensions/strings",
+ "//services/strings",
+ "//third_party/blink/public/strings",
+ "//third_party/blink/public/strings:accessibility_strings",
+ "//ui/strings:app_locale_settings",
+ "//ui/strings:ui_strings",
+ ]
+}
+
+# Generate cef_command_ids.h.
+make_pack_header("command_ids") {
+ header = "$root_out_dir/includes/include/cef_command_ids.h"
+ inputs = [
+ "//chrome/app/chrome_command_ids.h",
+ ]
+}
+
+# Generate cef_api_hash.h.
+action("make_api_hash_header") {
+ script = "tools/make_api_hash_header.py"
+
+ # List of all C API files that will be checked for changes by cef_api_hash.py.
+ inputs = gypi_paths2.includes_common_capi +
+ gypi_paths2.includes_linux_capi +
+ gypi_paths2.includes_mac_capi +
+ gypi_paths2.includes_win_capi +
+ gypi_paths2.includes_capi +
+ gypi_paths.autogen_capi_includes
+ include_dir = [ "include" ]
+ outputs = [ "$root_out_dir/includes/include/cef_api_hash.h" ]
+
+ args = rebase_path(outputs + include_dir, root_build_dir)
+}
+
+# Generate cef_config.h.
+action("make_config_header") {
+ script = "tools/make_config_header.py"
+
+ outputs = [ "$root_out_dir/includes/include/cef_config.h" ]
+
+ args = rebase_path(outputs + [ "$root_out_dir/args.gn" ], root_build_dir)
+}
+
+# Generate pack files and associated CEF header files.
+group("cef_make_headers") {
+ deps = [
+ ":make_pack_header_resources",
+ ":make_pack_header_strings",
+ ":make_pack_header_command_ids",
+ ":make_api_hash_header",
+ ":make_config_header",
+ ]
+}
+
+
+#
+# libcef dll/framework target.
+#
+
+if (is_mac) {
+ cef_framework_name = "Chromium Embedded Framework"
+
+ tweak_info_plist("cef_framework_plist") {
+ info_plist = "libcef/resources/framework-Info.plist"
+ args = [
+ "--breakpad=0",
+ "--keystone=0",
+ "--scm=1",
+ "--version",
+ cef_plist_version,
+ "--branding",
+ cef_framework_name,
+ ]
+ }
+
+ bundle_data("cef_framework_resources") {
+ sources = []
+ public_deps = []
+
+ if (icu_use_data_file) {
+ sources += [ "$root_out_dir/icudtl.dat" ]
+ public_deps += [ "//third_party/icu:icudata", ]
+ }
+
+ if (v8_use_external_startup_data) {
+ sources += [
+ "$root_out_dir/snapshot_blob.bin",
+ ]
+ public_deps += [ "//v8" ]
+ if (use_v8_context_snapshot) {
+ sources += [ "$root_out_dir/$v8_context_snapshot_filename" ]
+ public_deps += [ "//tools/v8_context_snapshot" ]
+ }
+ }
+
+ outputs = [
+ "{{bundle_resources_dir}}/{{source_file_part}}",
+ ]
+ }
+
+ if (use_egl) {
+ # Add the ANGLE .dylibs in the MODULE_DIR of the Framework app bundle.
+ bundle_data("cef_framework_angle_binaries") {
+ sources = [
+ "$root_out_dir/egl_intermediates/libEGL.dylib",
+ "$root_out_dir/egl_intermediates/libGLESv2.dylib",
+ ]
+ outputs = [
+ "{{bundle_contents_dir}}/Libraries/{{source_file_part}}",
+ ]
+ public_deps = [
+ "//ui/gl:angle_library_copy",
+ ]
+ }
+
+ # Add the SwiftShader .dylibs in the MODULE_DIR of the Framework app bundle.
+ bundle_data("cef_framework_swiftshader_binaries") {
+ sources = [
+ "$root_out_dir/vk_intermediates/libvk_swiftshader.dylib",
+ "$root_out_dir/vk_intermediates/vk_swiftshader_icd.json",
+ ]
+ outputs = [
+ "{{bundle_contents_dir}}/Libraries/{{source_file_part}}",
+ ]
+ public_deps = [
+ "//ui/gl:swiftshader_vk_library_copy",
+ ]
+ }
+ }
+
+ group("cef_framework_angle_library") {
+ if (use_egl) {
+ deps = [
+ ":cef_framework_angle_binaries",
+ ]
+ }
+ }
+
+ group("cef_framework_swiftshader_library") {
+ if (use_egl) {
+ deps = [
+ ":cef_framework_swiftshader_binaries",
+ ]
+ }
+ }
+
+ mac_framework_bundle("cef_framework") {
+ # Necessary because the libcef_test_support target is testonly.
+ testonly = true
+
+ output_name = cef_framework_name
+
+ framework_version = "A"
+ framework_contents = [
+ "Libraries",
+ "Resources",
+ ]
+
+ sources = includes_common +
+ includes_mac +
+ gypi_paths.autogen_cpp_includes +
+ gypi_paths2.includes_capi +
+ gypi_paths.autogen_capi_includes +
+ gypi_paths2.libcef_sources_common +
+ gypi_paths.autogen_library_side
+
+ deps = [
+ ":cef_framework_angle_library",
+ ":cef_framework_resources",
+ ":cef_framework_swiftshader_library",
+ ":libcef_static",
+ ":libcef_test_support",
+ ]
+
+ configs += [
+ ":libcef_autogen_config",
+ ]
+
+ # We don't link the framework so just use the path from the main executable.
+ ldflags = [
+ "-Wl,-install_name,@executable_path/../Frameworks/$output_name.framework/$output_name",
+ "-compatibility_version",
+ cef_dylib_version,
+ "-current_version",
+ cef_dylib_version,
+ ]
+
+ if (is_component_build) {
+ # Set up the rpath for the framework so that it can find dylibs in the
+ # root output directory. The framework is at
+ # $app_name.app/Contents/Frameworks/$output_name.framework/Versions/A/$output_name
+ # so use loader_path to go back to the root output directory.
+ ldflags += [
+ "-rpath",
+ "@loader_path/../../../../../..",
+ ]
+ }
+
+ info_plist_target = ":cef_framework_plist"
+ }
+} else {
+ config("pdb_larger_than_4gb") {
+ if (is_win && symbol_level == 2) {
+ # These binaries create PDBs larger than 4 GiB. Increasing the PDB page
+ # size allows larger PDBs, but not all tools can handle such large PDBs
+ # yet.
+ ldflags = [ "/pdbpagesize:8192" ]
+ }
+ }
+
+ shared_library("libcef") {
+ # Necessary because the libcef_test_support target is testonly.
+ testonly = true
+
+ sources = includes_common +
+ gypi_paths.autogen_cpp_includes +
+ gypi_paths2.includes_capi +
+ gypi_paths.autogen_capi_includes +
+ gypi_paths2.libcef_sources_common +
+ gypi_paths.autogen_library_side
+
+ deps = [
+ ":libcef_static",
+ ":libcef_test_support",
+ ]
+
+ configs += [
+ ":libcef_autogen_config",
+ ":pdb_larger_than_4gb",
+ ]
+
+ if (is_win) {
+ sources += includes_win + [
+ "libcef_dll/libcef_dll.rc",
+ ]
+
+ deps += [
+ # Bring in ui_unscaled_resources.rc which contains custom cursors.
+ # TODO(cef): Remove this once custom cursors can be loaded via
+ # ResourceBundle. See crbug.com/147663.
+ "//ui/resources:ui_unscaled_resources_grd",
+ ]
+ }
+
+ if (is_linux && !is_debug && !use_partition_alloc_as_malloc) {
+ # Only export necessary symbols from libcef.so.
+ # Don't do this in Debug builds because it causes the resulting
+ # application to crash.
+ # Also need to do this for ASAN builds to work around
+ # https://crbug.com/832808.
+ ldflags = [ "-Wl,--version-script=" +
+ rebase_path("//cef/libcef_dll/libcef.lst") ]
+ }
+ }
+}
+
+
+#
+# Executable/app targets.
+#
+
+# Source files for TeamCity GTest integration.
+# See tests/gtest/teamcity/README.cef for details.
+source_set("gtest_teamcity") {
+ testonly = true
+
+ sources = [
+ "tests/gtest/teamcity/include/teamcity_gtest.h",
+ "tests/gtest/teamcity/src/teamcity_gtest.cpp",
+ "tests/gtest/teamcity/src/teamcity_gtest.h",
+ "tests/gtest/teamcity/src/teamcity_messages.cpp",
+ "tests/gtest/teamcity/src/teamcity_messages.h",
+ ]
+
+ deps = [
+ "//testing/gtest",
+ ]
+
+ configs += [
+ "libcef/features:config",
+ "//build/config:precompiled_headers",
+ ]
+}
+
+if (is_mac) {
+ # Helper for generating the CEF app bundle.
+ template("cef_app") {
+ assert(defined(invoker.helper_info_plist))
+ assert(defined(invoker.helper_sources))
+ assert(defined(invoker.info_plist))
+ assert(defined(invoker.sources))
+
+ app_name = target_name
+ app_helper_name = "$app_name Helper"
+ app_testonly = defined(invoker.testonly) && invoker.testonly
+
+ tweak_info_plist("${app_name}_helper_plist") {
+ testonly = app_testonly
+ info_plist = invoker.helper_info_plist
+ args = [
+ "--breakpad=0",
+ "--keystone=0",
+ "--scm=0",
+ "--version",
+ cef_plist_version,
+ ]
+ }
+
+ template("cef_helper_app") {
+ mac_app_bundle(target_name) {
+ assert(defined(invoker.helper_sources))
+ assert(defined(invoker.helper_name_suffix))
+ assert(defined(invoker.helper_bundle_id_suffix))
+
+ testonly = app_testonly
+ output_name = app_helper_name + invoker.helper_name_suffix
+
+ sources = invoker.helper_sources
+
+ extra_substitutions = [
+ "BUNDLE_ID_SUFFIX=${invoker.helper_bundle_id_suffix}",
+ ]
+
+ deps = [
+ ":cef_make_headers",
+ ":cef_sandbox",
+ ":libcef_dll_wrapper",
+ ]
+ if (defined(invoker.helper_deps)) {
+ deps += invoker.helper_deps
+ }
+
+ ldflags = [
+ # The helper is in $app_name.app/Contents/Frameworks/$app_name Helper.app/Contents/MacOS/
+ # so set rpath up to the base.
+ "-rpath",
+ "@executable_path/../../../../../..",
+ ]
+
+ info_plist_target = ":${app_name}_helper_plist"
+
+ if (defined(invoker.helper_frameworks)) {
+ frameworks = invoker.helper_frameworks
+ }
+
+ if (defined(invoker.helper_defines)) {
+ defines = invoker.helper_defines
+ }
+ }
+ }
+
+ foreach(helper_params, content_mac_helpers) {
+ _helper_target = helper_params[0]
+ _helper_bundle_id = helper_params[1]
+ _helper_suffix = helper_params[2]
+ cef_helper_app("${app_name}_helper_app_${_helper_target}") {
+ helper_sources = invoker.helper_sources
+ if (defined(invoker.helper_deps)) {
+ helper_deps = invoker.helper_deps
+ }
+ if (defined(invoker.helper_frameworks)) {
+ helper_frameworks = invoker.helper_frameworks
+ }
+ if (defined(invoker.helper_defines)) {
+ helper_defines = invoker.helper_defines
+ }
+
+ helper_name_suffix = _helper_suffix
+ helper_bundle_id_suffix = _helper_bundle_id
+ }
+ }
+
+ bundle_data("${app_name}_framework_bundle_data") {
+ testonly = app_testonly
+ sources = [
+ "$root_out_dir/$cef_framework_name.framework",
+ ]
+
+ public_deps = [
+ ":cef_framework",
+ ]
+
+ foreach(helper_params, content_mac_helpers) {
+ sources += [
+ "$root_out_dir/${app_helper_name}${helper_params[2]}.app",
+ ]
+ public_deps += [ ":${app_name}_helper_app_${helper_params[0]}" ]
+ }
+
+ outputs = [
+ "{{bundle_contents_dir}}/Frameworks/{{source_file_part}}",
+ ]
+ }
+
+ tweak_info_plist("${app_name}_plist") {
+ testonly = app_testonly
+ info_plist = invoker.info_plist
+ args = [
+ "--scm=1",
+ "--version",
+ cef_plist_version,
+ ]
+ }
+
+ mac_app_bundle(app_name) {
+ testonly = app_testonly
+ output_name = app_name
+
+ sources = invoker.sources
+
+ public_deps = [ ":libcef_dll_wrapper" ]
+ deps = [
+ ":cef_make_headers",
+ ":libcef_dll_wrapper",
+ ":${app_name}_framework_bundle_data",
+ ]
+ if (defined(invoker.deps)) {
+ deps += invoker.deps
+ }
+
+ if (defined(invoker.frameworks)) {
+ frameworks = invoker.frameworks
+ }
+
+ if (defined(invoker.defines)) {
+ defines = invoker.defines
+ }
+
+ info_plist_target = ":${app_name}_plist"
+ }
+ }
+
+
+ #
+ # cefclient app targets.
+ #
+
+ bundle_data("cefclient_resources_bundle_data") {
+ sources = gypi_paths2.shared_sources_resources +
+ gypi_paths2.cefclient_sources_resources + [
+ "tests/cefclient/resources/mac/cefclient.icns",
+ ]
+
+ outputs = [
+ "{{bundle_resources_dir}}/{{source_file_part}}",
+ ]
+ }
+
+ bundle_data("cefclient_resources_bundle_data_extensions_set_page_color") {
+ sources = gypi_paths2.cefclient_sources_resources_extensions_set_page_color
+ outputs = [
+ "{{bundle_resources_dir}}/extensions/set_page_color/{{source_file_part}}",
+ ]
+ }
+
+ bundle_data("cefclient_resources_bundle_data_english") {
+ sources = [
+ "tests/cefclient/resources/mac/English.lproj/InfoPlist.strings",
+ ]
+
+ outputs = [
+ "{{bundle_resources_dir}}/English.lproj/{{source_file_part}}",
+ ]
+ }
+
+ mac_xib_bundle_data("cefclient_xibs") {
+ sources = [
+ "tests/cefclient/resources/mac/English.lproj/MainMenu.xib",
+ ]
+
+ output_path = "{{bundle_resources_dir}}/English.lproj"
+ }
+
+ cef_app("cefclient") {
+ # Necessary because the cef_framework target is testonly.
+ testonly = true
+
+ helper_info_plist = "tests/cefclient/resources/mac/helper-Info.plist"
+ helper_sources = includes_common +
+ includes_mac +
+ gypi_paths2.includes_wrapper +
+ gypi_paths2.includes_wrapper_mac +
+ gypi_paths2.shared_sources_common +
+ gypi_paths2.shared_sources_renderer +
+ gypi_paths2.shared_sources_mac_helper +
+ gypi_paths2.cefclient_sources_common +
+ gypi_paths2.cefclient_sources_renderer
+ helper_defines = [
+ "CEF_USE_SANDBOX",
+ ]
+
+ info_plist = "tests/cefclient/resources/mac/Info.plist"
+ sources = includes_common +
+ includes_mac +
+ gypi_paths2.includes_wrapper +
+ gypi_paths2.includes_wrapper_mac +
+ gypi_paths2.shared_sources_browser +
+ gypi_paths2.shared_sources_common +
+ gypi_paths2.shared_sources_mac +
+ gypi_paths2.cefclient_sources_browser +
+ gypi_paths2.cefclient_sources_common +
+ gypi_paths2.cefclient_sources_mac
+ deps = [
+ ":cefclient_resources_bundle_data",
+ ":cefclient_resources_bundle_data_extensions_set_page_color",
+ ":cefclient_resources_bundle_data_english",
+ ":cefclient_xibs",
+ ]
+ frameworks = [
+ "AppKit.framework",
+ "OpenGL.framework",
+ ]
+ defines = [
+ "CEF_USE_SANDBOX",
+ ]
+ }
+
+
+ #
+ # cefsimple app targets.
+ #
+
+ bundle_data("cefsimple_resources_bundle_data") {
+ sources = [
+ "tests/cefsimple/mac/cefsimple.icns",
+ ]
+
+ outputs = [
+ "{{bundle_resources_dir}}/{{source_file_part}}",
+ ]
+ }
+
+ bundle_data("cefsimple_resources_bundle_data_english") {
+ sources = [
+ "tests/cefsimple/mac/English.lproj/InfoPlist.strings",
+ ]
+
+ outputs = [
+ "{{bundle_resources_dir}}/English.lproj/{{source_file_part}}",
+ ]
+ }
+
+ mac_xib_bundle_data("cefsimple_xibs") {
+ sources = [
+ "tests/cefsimple/mac/English.lproj/MainMenu.xib",
+ ]
+ output_path = "{{bundle_resources_dir}}/English.lproj"
+ }
+
+ cef_app("cefsimple") {
+ # Necessary because the cef_framework target is testonly.
+ testonly = true
+
+ helper_info_plist = "tests/cefsimple/mac/helper-Info.plist"
+ helper_sources = includes_common +
+ includes_mac +
+ gypi_paths2.includes_wrapper +
+ gypi_paths2.includes_wrapper_mac +
+ gypi_paths2.cefsimple_sources_mac_helper
+ helper_defines = [
+ "CEF_USE_SANDBOX",
+ ]
+
+ info_plist = "tests/cefsimple/mac/Info.plist"
+ sources = includes_common +
+ includes_mac +
+ gypi_paths2.includes_wrapper +
+ gypi_paths2.includes_wrapper_mac +
+ gypi_paths2.cefsimple_sources_common +
+ gypi_paths2.cefsimple_sources_mac
+ deps = [
+ ":cefsimple_resources_bundle_data",
+ ":cefsimple_resources_bundle_data_english",
+ ":cefsimple_xibs",
+ ]
+ frameworks = [
+ "AppKit.framework",
+ ]
+ defines = [
+ "CEF_USE_SANDBOX",
+ ]
+ }
+
+
+ #
+ # ceftests app targets.
+ #
+
+ bundle_data("ceftests_resources_bundle_data") {
+ sources = gypi_paths2.shared_sources_resources + [
+ "tests/ceftests/resources/mac/ceftests.icns",
+ ]
+
+ outputs = [
+ "{{bundle_resources_dir}}/{{source_file_part}}",
+ ]
+ }
+
+ bundle_data("ceftests_resources_bundle_data_english") {
+ sources = [
+ "tests/ceftests/resources/mac/English.lproj/InfoPlist.strings",
+ ]
+
+ outputs = [
+ "{{bundle_resources_dir}}/English.lproj/{{source_file_part}}",
+ ]
+ }
+
+ mac_xib_bundle_data("ceftests_xibs") {
+ sources = [
+ "tests/ceftests/resources/mac/English.lproj/MainMenu.xib",
+ ]
+ output_path = "{{bundle_resources_dir}}/English.lproj"
+ }
+
+ cef_app("ceftests") {
+ testonly = true
+
+ helper_info_plist = "tests/ceftests/resources/mac/helper-Info.plist"
+ helper_sources = gypi_paths2.shared_sources_common +
+ gypi_paths2.shared_sources_renderer +
+ gypi_paths2.shared_sources_mac_helper +
+ gypi_paths2.ceftests_sources_mac_helper
+ helper_deps = [
+ ":gtest_teamcity",
+ "//testing/gtest",
+ ]
+ helper_frameworks = [
+ "AppKit.framework",
+ ]
+ helper_defines = [
+ "CEF_USE_SANDBOX",
+ "CEF_TESTS_IN_SRC_DIRECTORY",
+ ]
+
+ info_plist = "tests/ceftests/resources/mac/Info.plist"
+ sources = includes_common +
+ includes_mac +
+ gypi_paths2.includes_wrapper +
+ gypi_paths2.includes_wrapper_mac +
+ gypi_paths2.shared_sources_browser +
+ gypi_paths2.shared_sources_common +
+ gypi_paths2.shared_sources_mac +
+ gypi_paths2.ceftests_sources_common +
+ gypi_paths2.ceftests_sources_mac
+ deps = [
+ ":ceftests_resources_bundle_data",
+ ":ceftests_resources_bundle_data_english",
+ ":ceftests_xibs",
+ ":gtest_teamcity",
+ "//testing/gtest",
+ ]
+ frameworks = [
+ "AppKit.framework",
+ ]
+ defines = [
+ "CEF_USE_SANDBOX",
+ "CEF_TESTS_IN_SRC_DIRECTORY",
+ ]
+ }
+} else {
+ #
+ # cefclient targets.
+ #
+
+ # The cefclient target depends on packages that are not available in the
+ # default sysroot environment.
+ if (is_linux && !use_sysroot) {
+ pkg_config("glib") {
+ packages = [
+ "glib-2.0",
+ ]
+ }
+ }
+
+ if (is_linux && cef_use_gtk) {
+ pkg_config("gtk") {
+ packages = [
+ "gmodule-2.0",
+ "gtk+-3.0",
+ "gthread-2.0",
+ "gtk+-unix-print-3.0",
+ "xi",
+ ]
+ }
+ }
+
+ if (is_linux) {
+ copy("copy_cefclient_files") {
+ sources = gypi_paths2.shared_sources_resources +
+ gypi_paths2.cefclient_sources_resources
+ outputs = [ "${root_out_dir}/cefclient_files/{{source_file_part}}" ]
+ }
+
+ copy("copy_cefclient_files_extensions_set_page_color") {
+ sources = gypi_paths2.cefclient_sources_resources_extensions_set_page_color
+ outputs = [ "${root_out_dir}/cefclient_files/extensions/set_page_color/{{source_file_part}}" ]
+ }
+ }
+
+ executable("cefclient") {
+ # Necessary because the libcef target is testonly.
+ testonly = true
+
+ sources = includes_common +
+ gypi_paths2.includes_wrapper +
+ gypi_paths2.shared_sources_browser +
+ gypi_paths2.shared_sources_common +
+ gypi_paths2.shared_sources_renderer +
+ gypi_paths2.cefclient_sources_browser +
+ gypi_paths2.cefclient_sources_common +
+ gypi_paths2.cefclient_sources_renderer
+
+ deps = [
+ ":libcef",
+ ":libcef_dll_wrapper",
+ ]
+
+ defines = [
+ "CEF_USE_SANDBOX",
+ ]
+
+ if (is_win) {
+ sources += includes_win +
+ gypi_paths2.shared_sources_win +
+ gypi_paths2.cefclient_sources_win
+
+ # Set /SUBSYSTEM:WINDOWS.
+ configs -= [ "//build/config/win:console" ]
+ configs += [ "//build/config/win:windowed" ]
+
+ defines += [
+ "CEF_USE_ATL",
+ ]
+
+ deps += [
+ ":cef_sandbox",
+ "//build/win:default_exe_manifest",
+ ]
+
+ libs = [
+ "comctl32.lib",
+ "d3d11.lib",
+ "imm32.lib",
+ "oleacc.lib",
+ "rpcrt4.lib",
+ "shlwapi.lib",
+ ]
+
+ if (target_cpu != "arm64") {
+ libs += [
+ "opengl32.lib",
+ "glu32.lib"
+ ]
+ }
+ }
+
+ if (is_linux) {
+ sources += includes_linux +
+ gypi_paths2.shared_sources_linux +
+ gypi_paths2.cefclient_sources_linux
+
+ deps += [
+ ":copy_cefclient_files",
+ ":copy_cefclient_files_extensions_set_page_color",
+ ]
+
+ libs = [
+ "GL",
+ "X11",
+ ]
+
+ if (cef_use_gtk) {
+ configs += [
+ ":gtk",
+ ]
+ cflags = [
+ # Don't warn about deprecated GDK/GTK functions.
+ "-Wno-deprecated-declarations",
+ ]
+ }
+
+ if (!is_component_build) {
+ # Set rpath to find our own libfreetype even in a non-component build.
+ configs += [ "//build/config/gcc:rpath_for_built_shared_libraries" ]
+ }
+ }
+ }
+
+
+ #
+ # cefsimple targets.
+ #
+
+ executable("cefsimple") {
+ # Necessary because the libcef target is testonly.
+ testonly = true
+
+ sources = includes_common +
+ gypi_paths2.includes_wrapper +
+ gypi_paths2.cefsimple_sources_common
+
+ deps = [
+ ":libcef",
+ ":libcef_dll_wrapper",
+ ]
+
+ defines = [
+ "CEF_USE_SANDBOX",
+ ]
+
+ if (is_win) {
+ sources += includes_win +
+ gypi_paths2.cefsimple_sources_win
+
+ # Set /SUBSYSTEM:WINDOWS.
+ configs -= [ "//build/config/win:console" ]
+ configs += [ "//build/config/win:windowed" ]
+
+ deps += [
+ ":cef_sandbox",
+ "//build/win:default_exe_manifest",
+ ]
+
+ libs = [
+ "comctl32.lib",
+ "shlwapi.lib",
+ "rpcrt4.lib",
+ ]
+ }
+
+ if (is_linux) {
+ sources += includes_linux +
+ gypi_paths2.cefsimple_sources_linux
+
+ if (ozone_platform_x11) {
+ libs = [
+ "X11",
+ ]
+ }
+
+ if (!is_component_build) {
+ # Set rpath to find our own libfreetype even in a non-component build.
+ configs += [ "//build/config/gcc:rpath_for_built_shared_libraries" ]
+ }
+ }
+ }
+
+
+ #
+ # ceftests targets.
+ #
+
+ if (is_linux) {
+ copy("copy_ceftests_files") {
+ sources = gypi_paths2.shared_sources_resources
+ outputs = [ "${root_out_dir}/ceftests_files/{{source_file_part}}" ]
+ }
+ }
+
+ executable("ceftests") {
+ testonly = true
+
+ sources = includes_common +
+ gypi_paths2.includes_wrapper +
+ gypi_paths2.shared_sources_browser +
+ gypi_paths2.shared_sources_common +
+ gypi_paths2.shared_sources_renderer +
+ gypi_paths2.ceftests_sources_common
+
+ deps = [
+ ":libcef",
+ ":libcef_dll_wrapper",
+ ":gtest_teamcity",
+ "//testing/gtest",
+ ]
+
+ defines = [
+ "CEF_USE_SANDBOX",
+ "CEF_TESTS_IN_SRC_DIRECTORY",
+ ]
+
+ if (is_win) {
+ sources += gypi_paths2.shared_sources_win +
+ gypi_paths2.ceftests_sources_win
+
+ deps += [
+ ":cef_sandbox",
+ "//build/win:default_exe_manifest",
+ ]
+ }
+
+ if (is_linux) {
+ sources += gypi_paths2.shared_sources_linux +
+ gypi_paths2.ceftests_sources_linux
+
+ if (ozone_platform_x11) {
+ libs = [
+ "X11",
+ ]
+ } else {
+ if (!use_sysroot) {
+ configs += [ ":glib" ]
+ }
+ }
+
+ deps += [
+ ":copy_ceftests_files",
+ ]
+ }
+
+ if (is_linux && !is_component_build) {
+ # Set rpath to find our own libfreetype even in a non-component build.
+ configs += [ "//build/config/gcc:rpath_for_built_shared_libraries" ]
+ }
+ }
+}
diff --git a/CHROMIUM_BUILD_COMPATIBILITY.txt b/CHROMIUM_BUILD_COMPATIBILITY.txt
new file mode 100644
index 00000000..db9d5fdb
--- /dev/null
+++ b/CHROMIUM_BUILD_COMPATIBILITY.txt
@@ -0,0 +1,12 @@
+# The Chromium Embedded Framework (CEF) project is built on top of the Chromium
+# project source tree. Chromium should be updated to the URL and revision listed
+# below before building CEF. Chromium compatibility information for older CEF
+# revisions is available by viewing this file's change history.
+#
+# Instructions for building CEF are available at:
+# https://bitbucket.org/chromiumembedded/cef/wiki/BranchesAndBuilding
+
+{
+ 'chromium_checkout': 'refs/tags/111.0.5563.148',
+ 'depot_tools_checkout': '963e01c76c'
+}
diff --git a/CHROMIUM_UPDATE.txt b/CHROMIUM_UPDATE.txt
new file mode 100644
index 00000000..5bac2ff8
--- /dev/null
+++ b/CHROMIUM_UPDATE.txt
@@ -0,0 +1,63 @@
+# The Chromium Embedded Framework (CEF) project is built on top of the Chromium
+# project source tree. When updating Chromium to a new version certain files and
+# patterns should be observed for changes. If changes are detected then the CEF
+# source code or patch files will likely need to be updated.
+#
+# Add `--log-chromium-changes` to the automate-git.py command-line to output
+# the following files in the <download-dir>:
+#
+# * chromium_update_changes.diff
+# Files in the chromium/src directory that have changed. See the 'files'
+# section below.
+#
+# * chromium_update_patterns.txt
+# Files in the chromium/src directory that contain invalid/unexpected
+# patterns. See the 'patterns' section below. Failure of this step is
+# considered a fatal error during update.
+#
+# * chromium_update_patches.txt
+# Output from attempting to update existing Chromium patch files using the
+# patch_updater.py tool. Failure of this step is considered a fatal error
+# during update.
+#
+# For complete update instructions see:
+# https://bitbucket.org/chromiumembedded/cef/wiki/ChromiumUpdate.md
+
+{
+ # Files in the chromium/src directory that should be evaluated for changes.
+ # Similar changes may need to be applied to the CEF source code.
+ 'files': [
+ 'chrome/browser/browser_process.h',
+ 'chrome/browser/extensions/api/tabs/tabs_api.*',
+ 'chrome/browser/extensions/chrome_component_extension_resource_manager.*',
+ 'chrome/browser/extensions/chrome_extension_web_contents_observer.*',
+ 'chrome/browser/extensions/component_loader.*',
+ 'chrome/browser/extensions/extension_service.*',
+ 'chrome/browser/profiles/profile.h',
+ 'chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.*',
+ 'chrome/common/extensions/api/*_features.json',
+ 'chrome/renderer/chrome_content_renderer_client.*',
+ 'chrome/renderer/extensions/chrome_extensions_renderer_client.*',
+ 'content/browser/renderer_host/render_widget_host_view_base.*',
+ 'content/public/browser/content_browser_client.*',
+ 'content/public/browser/render_widget_host_view.h',
+ 'content/public/browser/web_contents_delegate.h',
+ 'content/public/common/content_features.cc',
+ 'content/shell/BUILD.gn',
+ 'content/shell/app/*',
+ 'content/shell/browser/shell_*',
+ 'content/shell/browser/renderer_host/shell_*',
+ 'content/shell/common/shell_*',
+ 'content/shell/gpu/shell_*',
+ 'content/shell/renderer/shell_*',
+ 'content/shell/utility/shell_*',
+ 'extensions/shell/*',
+ 'net/base/features.cc',
+ 'net/cookies/cookie_store.h',
+ 'services/network/public/cpp/features.cc',
+ 'ui/base/ui_base_features.cc',
+ ],
+ # Patterns that should not be found in the chromium/src directory after
+ # applying patch files.
+ 'patterns': [],
+}
diff --git a/CMakeLists.txt.in b/CMakeLists.txt.in
new file mode 100644
index 00000000..facd8d3f
--- /dev/null
+++ b/CMakeLists.txt.in
@@ -0,0 +1,255 @@
+# Copyright (c) 2014 The Chromium Embedded Framework Authors. All rights
+# reserved. Use of this source code is governed by a BSD-style license that
+# can be found in the LICENSE file.
+
+# OVERVIEW
+#
+# CMake is a cross-platform open-source build system that can generate project
+# files in many different formats. It can be downloaded from
+# http://www.cmake.org or installed via a platform package manager.
+#
+# CMake-generated project formats that have been tested with this CEF binary
+# distribution include:
+#
+# Linux: Ninja, GCC 7.5.0+, Unix Makefiles
+# MacOS: Ninja, Xcode 12.2 to 13.0
+# Windows: Ninja, Visual Studio 2019+
+#
+# Ninja is a cross-platform open-source tool for running fast builds using
+# pre-installed platform toolchains (GNU, clang, Xcode or MSVC). It can be
+# downloaded from http://martine.github.io/ninja/ or installed via a platform
+# package manager.
+#
+# CMAKE STRUCTURE
+#
+# This CEF binary distribution includes the following CMake files:
+#
+# CMakeLists.txt Bootstrap that sets up the CMake environment.
+# cmake/*.cmake CEF configuration files shared by all targets.
+# libcef_dll/CMakeLists.txt Defines the libcef_dll_wrapper target.
+# tests/*/CMakeLists.txt Defines the test application target.
+#
+# See the "TODO:" comments below for guidance on how to integrate this CEF
+# binary distribution into a new or existing CMake project.
+#
+# BUILD REQUIREMENTS
+#
+# The below requirements must be met to build this CEF binary distribution.
+#
+# - CMake version 3.19 or newer.
+#
+# - Linux requirements:
+# Currently supported distributions include Debian 10 (Buster), Ubuntu 18
+# (Bionic Beaver), and related. Ubuntu 18.04 64-bit with GCC 7.5.0+ is
+# recommended. Newer versions will likely also work but may not have been
+# tested.
+# Required packages include:
+# build-essential
+# libgtk3.0-dev (required by the cefclient target only)
+#
+# - MacOS requirements:
+# Xcode 12.2 to 13.4 building on MacOS 10.15.4 (Catalina) or newer. Only
+# 64-bit builds are supported. The Xcode command-line tools must also be
+# installed. Newer Xcode versions may not have been been tested and are not
+# recommended.
+#
+# - Windows requirements:
+# Visual Studio 2019 or newer building on Windows 10 or newer. Windows 10
+# 64-bit is recommended. Newer versions will likely also work but may not have
+# been tested.
+#
+# BUILD EXAMPLES
+#
+# The below commands will generate project files and create a Debug build of all
+# CEF targets using CMake and the platform toolchain.
+#
+# Start by creating and entering the CMake build output directory:
+# > cd path/to/cef_binary_*
+# > mkdir build && cd build
+#
+# To perform a Linux build using a 32-bit CEF binary distribution on a 32-bit
+# Linux platform or a 64-bit CEF binary distribution on a 64-bit Linux platform:
+# Using Unix Makefiles:
+# > cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Debug ..
+# > make -j4 cefclient cefsimple
+#
+# Using Ninja:
+# > cmake -G "Ninja" -DCMAKE_BUILD_TYPE=Debug ..
+# > ninja cefclient cefsimple
+#
+# To perform a MacOS build using a 64-bit CEF binary distribution:
+# Using the Xcode IDE:
+# > cmake -G "Xcode" -DPROJECT_ARCH="x86_64" ..
+# Open build\cef.xcodeproj in Xcode and select Product > Build.
+#
+# Using Ninja:
+# > cmake -G "Ninja" -DPROJECT_ARCH="x86_64" -DCMAKE_BUILD_TYPE=Debug ..
+# > ninja cefclient cefsimple
+#
+# To perform a MacOS build using an ARM64 CEF binary distribution:
+# Using the Xcode IDE:
+# > cmake -G "Xcode" -DPROJECT_ARCH="arm64" ..
+# Open build\cef.xcodeproj in Xcode and select Product > Build.
+#
+# Using Ninja:
+# > cmake -G "Ninja" -DPROJECT_ARCH="arm64" -DCMAKE_BUILD_TYPE=Debug ..
+# > ninja cefclient cefsimple
+#
+# To perform a Windows build using a 32-bit CEF binary distribution:
+# Using the Visual Studio 2019 IDE:
+# > cmake -G "Visual Studio 16" -A Win32 ..
+# Open build\cef.sln in Visual Studio and select Build > Build Solution.
+#
+# Using Ninja with Visual Studio 2019 command-line tools:
+# (this path may be different depending on your Visual Studio installation)
+# > "C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Auxiliary\Build\vcvars32.bat"
+# > cmake -G "Ninja" -DCMAKE_BUILD_TYPE=Debug ..
+# > ninja cefclient cefsimple
+#
+# To perform a Windows build using a 64-bit CEF binary distribution:
+# Using the Visual Studio 2019 IDE:
+# > cmake -G "Visual Studio 16" -A x64 ..
+# Open build\cef.sln in Visual Studio and select Build > Build Solution.
+#
+# Using Ninja with Visual Studio 2019 command-line tools:
+# (this path may be different depending on your Visual Studio installation)
+# > "C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Auxiliary\Build\vcvars64.bat"
+# > cmake -G "Ninja" -DCMAKE_BUILD_TYPE=Debug ..
+# > ninja cefclient cefsimple
+#
+# To perform a Windows build using an ARM64 CEF binary distribution:
+# Using the Visual Studio 2019 IDE:
+# > cmake -G "Visual Studio 16" -A arm64 ..
+# Open build\cef.sln in Visual Studio and select Build > Build Solution.
+#
+# Using Ninja with Visual Studio 2019 command-line tools:
+# (this path may be different depending on your Visual Studio installation)
+# > "C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Auxiliary\Build\vcvarsamd64_arm64.bat"
+# > cmake -G "Ninja" -DCMAKE_BUILD_TYPE=Debug ..
+# > ninja cefsimple
+
+#
+# Global setup.
+#
+
+# For VS2019 and Xcode 12+ support.
+cmake_minimum_required(VERSION 3.19)
+
+# Only generate Debug and Release configuration types.
+set(CMAKE_CONFIGURATION_TYPES Debug Release)
+
+# Project name.
+# TODO: Change this line to match your project name when you copy this file.
+project(cef)
+
+# Use folders in the resulting project files.
+set_property(GLOBAL PROPERTY OS_FOLDERS ON)
+
+
+#
+# CEF_ROOT setup.
+# This variable must be set to locate the binary distribution.
+# TODO: Choose one of the below examples and comment out the rest.
+#
+
+# Example 1: The current directory contains both the complete binary
+# distribution and your project.
+# A. Comment in these lines:
+#
+set(CEF_ROOT "${CMAKE_CURRENT_SOURCE_DIR}")
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CEF_ROOT}/cmake")
+
+# Example 2: The binary distribution is in a separate directory from your
+# project. Locate the binary distribution using the CEF_ROOT CMake
+# variable.
+# A. Create a directory structure for your project like the following:
+# myproject/
+# CMakeLists.txt <= top-level CMake configuration
+# mytarget/
+# CMakeLists.txt <= CMake configuration for `mytarget`
+# ... other `mytarget` source files
+# B. Copy this file to "myproject/CMakeLists.txt" as the top-level CMake
+# configuration.
+# C. Create the target-specific "myproject/mytarget/CMakeLists.txt" file for
+# your application. See the included cefclient and cefsimple CMakeLists.txt
+# files as an example.
+# D. Comment in these lines:
+#
+# set(CEF_ROOT "c:/path/to/cef_binary_3.2704.xxxx.gyyyyyyy_windows32")
+# set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CEF_ROOT}/cmake")
+
+# Example 3: The binary distribution is in a separate directory from your
+# project. Locate the binary distribution using the CEF_ROOT
+# environment variable.
+# A. Create a directory structure for your project like the following:
+# myproject/
+# CMakeLists.txt <= top-level CMake configuration
+# cmake/
+# FindCEF.cmake <= CEF CMake configuration entry point
+# mytarget/
+# CMakeLists.txt <= CMake configuration for `mytarget`
+# ... other `mytarget` source files
+# B. Copy this file to "myproject/CMakeLists.txt" as the top-level CMake
+# configuration.
+# C. Copy the cmake/FindCEF.cmake file to "myproject/cmake/FindCEF.cmake".
+# D. Create the target-specific "myproject/mytarget/CMakeLists.txt" file for
+# your application. See the included cefclient and cefsimple CMakeLists.txt
+# files as an example.
+# E. Set the CEF_ROOT environment variable before executing CMake. For example:
+# > set CEF_ROOT=c:\path\to\cef_binary_3.2704.xxxx.gyyyyyyy_windows32
+# F. Comment in these lines:
+#
+# set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
+
+
+#
+# Load the CEF configuration.
+#
+
+# Execute FindCEF.cmake which must exist in CMAKE_MODULE_PATH.
+find_package(CEF REQUIRED)
+
+
+#
+# Define CEF-based targets.
+#
+
+# Include the libcef_dll_wrapper target.
+# Comes from the libcef_dll/CMakeLists.txt file in the binary distribution
+# directory.
+add_subdirectory(${CEF_LIBCEF_DLL_WRAPPER_PATH} libcef_dll_wrapper)
+
+# Include application targets.
+# Comes from the <target>/CMakeLists.txt file in the current directory.
+# TODO: Change these lines to match your project target when you copy this file.
+if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/tests")
+ add_subdirectory(tests/cefsimple)
+ add_subdirectory(tests/gtest)
+ add_subdirectory(tests/ceftests)
+endif()
+
+if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/tests/cefclient")
+ add_subdirectory(tests/cefclient)
+endif()
+
+# Display configuration settings.
+PRINT_CEF_CONFIG()
+
+
+#
+# Define the API documentation target.
+#
+
+find_package(Doxygen)
+if(DOXYGEN_FOUND)
+ add_custom_target(apidocs ALL
+ # Generate documentation in the docs/html directory.
+ COMMAND "${DOXYGEN_EXECUTABLE}" Doxyfile
+ # Write a docs/index.html file.
+ COMMAND ${CMAKE_COMMAND} -E echo "<html><head><meta http-equiv=\"refresh\" content=\"0;URL='html/index.html'\"/></head></html>" > docs/index.html
+ WORKING_DIRECTORY "${CEF_ROOT}"
+ COMMENT "Generating API documentation with Doxygen..."
+ VERBATIM )
+else()
+ message(WARNING "Doxygen must be installed to generate API documentation.")
+endif()
diff --git a/DEPS b/DEPS
new file mode 100644
index 00000000..0a7dc22e
--- /dev/null
+++ b/DEPS
@@ -0,0 +1,7 @@
+hooks = [
+ {
+ # A change to a .gyp, .gypi, or to GYP itself should run the generator.
+ "pattern": ".",
+ "action": ["python", "src/cef/tools/gclient_hook.py"],
+ },
+]
diff --git a/Doxyfile b/Doxyfile
new file mode 100644
index 00000000..affddfb2
--- /dev/null
+++ b/Doxyfile
@@ -0,0 +1,2782 @@
+# Doxyfile 1.9.5
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+#
+# Note:
+#
+# Use doxygen to compare the used configuration file with the template
+# configuration file:
+# doxygen -x [configFile]
+# Use doxygen to compare the used configuration file with the template
+# configuration file without replacing the environment variables or CMake type
+# replacement variables:
+# doxygen -x_noenv [configFile]
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the configuration
+# file that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# https://www.gnu.org/software/libiconv/ for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME = "Chromium Embedded Framework (CEF)"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER = $(PROJECT_NUMBER)
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF =
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = docs
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create up to 4096
+# sub-directories (in 2 levels) under the output directory of each output format
+# and will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system. Adapt CREATE_SUBDIRS_LEVEL to
+# control the number of sub-directories.
+# The default value is: NO.
+
+CREATE_SUBDIRS = NO
+
+# Controls the number of sub-directories that will be created when
+# CREATE_SUBDIRS tag is set to YES. Level 0 represents 16 directories, and every
+# level increment doubles the number of directories, resulting in 4096
+# directories at level 8 which is the default and also the maximum value. The
+# sub-directories are organized in 2 levels, the first level always has a fixed
+# numer of 16 directories.
+# Minimum value: 0, maximum value: 8, default value: 8.
+# This tag requires that the tag CREATE_SUBDIRS is set to YES.
+
+CREATE_SUBDIRS_LEVEL = 8
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Bulgarian,
+# Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, English
+# (United States), Esperanto, Farsi (Persian), Finnish, French, German, Greek,
+# Hindi, Hungarian, Indonesian, Italian, Japanese, Japanese-en (Japanese with
+# English messages), Korean, Korean-en (Korean with English messages), Latvian,
+# Lithuanian, Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese,
+# Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish,
+# Swedish, Turkish, Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH = .
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF = YES
+
+# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line
+# such as
+# /***************
+# as being the beginning of a Javadoc-style comment "banner". If set to NO, the
+# Javadoc-style will behave just like regular comments and it will not be
+# interpreted by doxygen.
+# The default value is: NO.
+
+JAVADOC_BANNER = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# By default Python docstrings are displayed as preformatted text and doxygen's
+# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the
+# doxygen's special commands can be used and the contents of the docstring
+# documentation blocks is shown as doxygen documentation.
+# The default value is: YES.
+
+PYTHON_DOCSTRING = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE = 2
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:^^"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". Note that you cannot put \n's in the value part of an alias
+# to insert newlines (in the resulting output). You can put ^^ in the value part
+# of an alias to insert a newline as if a physical newline was in the original
+# file. When you need a literal { or } or , in the value part of an alias you
+# have to escape them by means of a backslash (\), this can lead to conflicts
+# with the commands \{ and \} for these it is advised to use the version @{ and
+# @} or use a double escape (\\{ and \\})
+
+ALIASES =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice
+# sources only. Doxygen will then generate output that is more tailored for that
+# language. For instance, namespaces will be presented as modules, types will be
+# separated into more groups, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_SLICE = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, JavaScript,
+# Csharp (C#), C, C++, Lex, D, PHP, md (Markdown), Objective-C, Python, Slice,
+# VHDL, Fortran (fixed format Fortran: FortranFixed, free formatted Fortran:
+# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser
+# tries to guess whether the code is fixed or free formatted code, this is the
+# default for Fortran type files). For instance to make doxygen treat .inc files
+# as Fortran files (default is PHP), and .f files as C (default is Fortran),
+# use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen. When specifying no_extension you should add
+# * to the FILE_PATTERNS.
+#
+# Note see also the list of default file extension mappings.
+
+EXTENSION_MAPPING =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See https://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT = YES
+
+# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up
+# to that level are automatically included in the table of contents, even if
+# they do not have an id attribute.
+# Note: This feature currently applies only to Markdown headings.
+# Minimum value: 0, maximum value: 99, default value: 5.
+# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
+
+TOC_INCLUDE_HEADINGS = 5
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# If one adds a struct or class to a group and this option is enabled, then also
+# any nested class or struct is added to the same group. By default this option
+# is disabled and one has to add nested compounds explicitly via \ingroup.
+# The default value is: NO.
+
+GROUP_NESTED_COMPOUNDS = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT = YES
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE = 0
+
+# The NUM_PROC_THREADS specifies the number of threads doxygen is allowed to use
+# during processing. When set to 0 doxygen will based this on the number of
+# cores available in the system. You can set it explicitly to a value larger
+# than 0 to get more control over the balance between CPU load and processing
+# speed. At this moment only the input processing can be done using multiple
+# threads. Since this is still an experimental feature the default is set to 1,
+# which effectively disables parallel processing. Please report any issues you
+# encounter. Generating dot graphs in parallel is controlled by the
+# DOT_NUM_THREADS setting.
+# Minimum value: 0, maximum value: 32, default value: 1.
+
+NUM_PROC_THREADS = 1
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual
+# methods of a class will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIV_VIRTUAL = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE = NO
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If this flag is set to YES, the name of an unnamed parameter in a declaration
+# will be determined by the corresponding definition. By default unnamed
+# parameters remain unnamed in the output.
+# The default value is: YES.
+
+RESOLVE_UNNAMED_PARAMS = YES
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# declarations. If set to NO, these declarations will be included in the
+# documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS = NO
+
+# With the correct setting of option CASE_SENSE_NAMES doxygen will better be
+# able to match the capabilities of the underlying filesystem. In case the
+# filesystem is case sensitive (i.e. it supports files in the same directory
+# whose names only differ in casing), the option must be set to YES to properly
+# deal with such files in case they appear in the input. For filesystems that
+# are not case sensitive the option should be set to NO to properly deal with
+# output files written for symbols that only differ in casing, such as for two
+# classes, one named CLASS and the other named Class, and to also support
+# references to files without having to specify the exact matching casing. On
+# Windows (including Cygwin) and MacOS, users should typically set this option
+# to NO, whereas on Linux or other Unix flavors it should typically be set to
+# YES.
+# Possible values are: SYSTEM, NO and YES.
+# The default value is: SYSTEM.
+
+CASE_SENSE_NAMES = SYSTEM
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
+# append additional text to a page's title, such as Class Reference. If set to
+# YES the compound reference will be hidden.
+# The default value is: NO.
+
+HIDE_COMPOUND_REFERENCE= NO
+
+# If the SHOW_HEADERFILE tag is set to YES then the documentation for a class
+# will show which file needs to be included to use the class.
+# The default value is: YES.
+
+SHOW_HEADERFILE = YES
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES = YES
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file. See also section "Changing the
+# layout of pages" for information.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as documenting some parameters in
+# a documented function twice, or documenting parameters that don't exist or
+# using markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR = YES
+
+# If WARN_IF_INCOMPLETE_DOC is set to YES, doxygen will warn about incomplete
+# function parameter documentation. If set to NO, doxygen will accept that some
+# parameters have no documentation without warning.
+# The default value is: YES.
+
+WARN_IF_INCOMPLETE_DOC = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong parameter
+# documentation, but not about the absence of documentation. If EXTRACT_ALL is
+# set to YES then this flag will automatically be disabled. See also
+# WARN_IF_INCOMPLETE_DOC
+# The default value is: NO.
+
+WARN_NO_PARAMDOC = NO
+
+# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
+# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS
+# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but
+# at the end of the doxygen process doxygen will return with a non-zero status.
+# Possible values are: NO, YES and FAIL_ON_WARNINGS.
+# The default value is: NO.
+
+WARN_AS_ERROR = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# See also: WARN_LINE_FORMAT
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# In the $text part of the WARN_FORMAT command it is possible that a reference
+# to a more specific place is given. To make it easier to jump to this place
+# (outside of doxygen) the user can define a custom "cut" / "paste" string.
+# Example:
+# WARN_LINE_FORMAT = "'vi $file +$line'"
+# See also: WARN_FORMAT
+# The default value is: at line $line of file $file.
+
+WARN_LINE_FORMAT = "at line $line of file $file"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr). In case the file specified cannot be opened for writing the
+# warning and error messages are written to standard error. When as file - is
+# specified the warning and error messages are written to standard output
+# (stdout).
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
+# Note: If this tag is empty the current directory is searched.
+
+INPUT = README.md \
+ include
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see:
+# https://www.gnu.org/software/libiconv/) for the list of possible encodings.
+# See also: INPUT_FILE_ENCODING
+# The default value is: UTF-8.
+
+INPUT_ENCODING = UTF-8
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses The INPUT_FILE_ENCODING tag can be used to specify
+# character encoding on a per file pattern basis. Doxygen will compare the file
+# name with each pattern and apply the encoding instead of the default
+# INPUT_ENCODING) if there is a match. The character encodings are a list of the
+# form: pattern=encoding (like *.php=ISO-8859-1). See cfg_input_encoding
+# "INPUT_ENCODING" for further information on supported encodings.
+
+INPUT_FILE_ENCODING =
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# read by doxygen.
+#
+# Note the list of default checked file patterns might differ from the list of
+# default file extension mappings.
+#
+# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
+# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
+# *.hh, *.hxx, *.hpp, *.h++, *.l, *.cs, *.d, *.php, *.php4, *.php5, *.phtml,
+# *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C
+# comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd,
+# *.vhdl, *.ucf, *.qsf and *.ice.
+
+FILE_PATTERNS = *.c \
+ *.cc \
+ *.cxx \
+ *.cpp \
+ *.c++ \
+ *.java \
+ *.ii \
+ *.ixx \
+ *.ipp \
+ *.i++ \
+ *.inl \
+ *.idl \
+ *.ddl \
+ *.odl \
+ *.h \
+ *.hh \
+ *.hxx \
+ *.hpp \
+ *.h++ \
+ *.l \
+ *.cs \
+ *.d \
+ *.php \
+ *.php4 \
+ *.php5 \
+ *.phtml \
+ *.inc \
+ *.m \
+ *.markdown \
+ *.md \
+ *.mm \
+ *.dox \
+ *.py \
+ *.pyw \
+ *.f90 \
+ *.f95 \
+ *.f03 \
+ *.f08 \
+ *.f18 \
+ *.f \
+ *.for \
+ *.vhd \
+ *.vhdl \
+ *.ucf \
+ *.qsf \
+ *.ice
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE = include/capi \
+ include/test \
+ include/base/internal
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS = *_internal.h
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# ANamespace::AClass, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS = base::cef_subtle \
+ base::internal \
+ cef_trace_event \
+ cef::logging
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+#
+# Note that doxygen will use the data processed and written to standard output
+# for further processing, therefore nothing else, like debug statements or used
+# commands (so in case of a Windows batch file always use @echo OFF), should be
+# written to standard output.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE = README.md
+
+# The Fortran standard specifies that for fixed formatted Fortran code all
+# characters from position 72 are to be considered as comment. A common
+# extension is to allow longer lines before the automatic comment starts. The
+# setting FORTRAN_COMMENT_AFTER will also make it possible that longer lines can
+# be processed before the automatic comment starts.
+# Minimum value: 7, maximum value: 10000, default value: 72.
+
+FORTRAN_COMMENT_AFTER = 72
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS = NO
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# entity all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = NO
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see https://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS = NO
+
+# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the
+# clang parser (see:
+# http://clang.llvm.org/) for more accurate parsing at the cost of reduced
+# performance. This can be particularly helpful with template rich C++ code for
+# which doxygen's built-in parser lacks the necessary type information.
+# Note: The availability of this option depends on whether or not doxygen was
+# generated with the -Duse_libclang=ON option for CMake.
+# The default value is: NO.
+
+CLANG_ASSISTED_PARSING = NO
+
+# If the CLANG_ASSISTED_PARSING tag is set to YES and the CLANG_ADD_INC_PATHS
+# tag is set to YES then doxygen will add the directory of each input to the
+# include path.
+# The default value is: YES.
+# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
+
+CLANG_ADD_INC_PATHS = YES
+
+# If clang assisted parsing is enabled you can provide the compiler with command
+# line options that you would normally use when invoking the compiler. Note that
+# the include paths will already be set by doxygen for the files and directories
+# specified with INPUT and INCLUDE_PATH.
+# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
+
+CLANG_OPTIONS =
+
+# If clang assisted parsing is enabled you can provide the clang parser with the
+# path to the directory containing a file called compile_commands.json. This
+# file is the compilation database (see:
+# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) containing the
+# options used when the source files were built. This is equivalent to
+# specifying the -p option to a clang tool, such as clang-check. These options
+# will then be passed to the parser. Any options specified with CLANG_OPTIONS
+# will be added as well.
+# Note: The availability of this option depends on whether or not doxygen was
+# generated with the -Duse_libclang=ON option for CMake.
+
+CLANG_DATABASE_PATH =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX = YES
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX = Cef \
+ cef_
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES =
+
+# The HTML_COLORSTYLE tag can be used to specify if the generated HTML output
+# should be rendered with a dark or light theme. Default setting AUTO_LIGHT
+# enables light output unless the user preference is dark output. Other options
+# are DARK to always use dark mode, LIGHT to always use light mode, AUTO_DARK to
+# default to dark mode unless the user prefers light mode, and TOGGLE to let the
+# user toggle between dark and light mode via a button.
+# Possible values are: LIGHT Always generate light output., DARK Always generate
+# dark output., AUTO_LIGHT Automatically set the mode according to the user
+# preference, use light mode if no preference is set (the default)., AUTO_DARK
+# Automatically set the mode according to the user preference, use dark mode if
+# no preference is set. and TOGGLE Allow to user to switch between light and
+# dark mode via a button..
+# The default value is: AUTO_LIGHT.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE = AUTO_LIGHT
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the style sheet and background images according to
+# this color. Hue is specified as an angle on a color-wheel, see
+# https://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use gray-scales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to YES can help to show when doxygen was last run and thus if the
+# documentation is up to date.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP = NO
+
+# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML
+# documentation will contain a main index with vertical navigation menus that
+# are dynamically created via JavaScript. If disabled, the navigation index will
+# consists of multiple levels of tabs that are statically embedded in every HTML
+# page. Disable this option to support browsers that do not have JavaScript,
+# like the Qt help browser.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_MENUS = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see:
+# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To
+# create a documentation set, doxygen will generate a Makefile in the HTML
+# output directory. Running make will produce the docset in that directory and
+# running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy
+# genXcode/_index.html for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# This tag determines the URL of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDURL =
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# on Windows. In the beginning of 2021 Microsoft took the original page, with
+# a.o. the download links, offline the HTML help workshop was already many years
+# in maintenance mode). You can download the HTML help workshop from the web
+# archives at Installation executable (see:
+# http://web.archive.org/web/20160201063255/http://download.microsoft.com/downlo
+# ad/0/A/9/0A939EF6-E31C-430F-A3DF-DFAE7960D564/htmlhelp.exe).
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the main .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS =
+
+# The QHG_LOCATION tag can be used to specify the location (absolute path
+# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to
+# run qhelpgenerator on the generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX = YES
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine tune the look of the index (see "Fine-tuning the output"). As an
+# example, the default style sheet generated by doxygen has an example that
+# shows how to put an image at the root of the tree instead of the PROJECT_NAME.
+# Since the tree basically has the same information as the tab index, you could
+# consider setting DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW = YES
+
+# When both GENERATE_TREEVIEW and DISABLE_INDEX are set to YES, then the
+# FULL_SIDEBAR option determines if the side bar is limited to only the treeview
+# area (value NO) or if it should extend to the full height of the window (value
+# YES). Setting this to YES gives a layout similar to
+# https://docs.readthedocs.io with more room for contents, but less room for the
+# project logo, title, and description. If either GENERATE_TREEVIEW or
+# DISABLE_INDEX is set to NO, this option has no effect.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FULL_SIDEBAR = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# If the OBFUSCATE_EMAILS tag is set to YES, doxygen will obfuscate email
+# addresses.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+OBFUSCATE_EMAILS = YES
+
+# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg
+# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see
+# https://inkscape.org) to generate formulas as SVG images instead of PNGs for
+# the HTML output. These images will generally look nicer at scaled resolutions.
+# Possible values are: png (the default) and svg (looks nicer but requires the
+# pdf2svg or inkscape tool).
+# The default value is: png.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FORMULA_FORMAT = png
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE = 10
+
+# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands
+# to create new LaTeX commands to be used in formulas as building blocks. See
+# the section "Including formulas" for details.
+
+FORMULA_MACROFILE =
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# https://www.mathjax.org) which uses client side JavaScript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX = NO
+
+# With MATHJAX_VERSION it is possible to specify the MathJax version to be used.
+# Note that the different versions of MathJax have different requirements with
+# regards to the different settings, so it is possible that also other MathJax
+# settings have to be changed when switching between the different MathJax
+# versions.
+# Possible values are: MathJax_2 and MathJax_3.
+# The default value is: MathJax_2.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_VERSION = MathJax_2
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. For more details about the output format see MathJax
+# version 2 (see:
+# http://docs.mathjax.org/en/v2.7-latest/output.html) and MathJax version 3
+# (see:
+# http://docs.mathjax.org/en/latest/web/components/output.html).
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility. This is the name for Mathjax version 2, for MathJax version 3
+# this will be translated into chtml), NativeMML (i.e. MathML. Only supported
+# for NathJax 2. For MathJax version 3 chtml will be used instead.), chtml (This
+# is the name for Mathjax version 3, for MathJax version 2 this will be
+# translated into HTML-CSS) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from https://www.mathjax.org before deployment. The default value is:
+# - in case of MathJax version 2: https://cdn.jsdelivr.net/npm/mathjax@2
+# - in case of MathJax version 3: https://cdn.jsdelivr.net/npm/mathjax@3
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH =
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# for MathJax version 2 (see
+# https://docs.mathjax.org/en/v2.7-latest/tex.html#tex-and-latex-extensions):
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# For example for MathJax version 3 (see
+# http://docs.mathjax.org/en/latest/input/tex/extensions/index.html):
+# MATHJAX_EXTENSIONS = ams
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see:
+# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE = NO
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using JavaScript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see:
+# https://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see:
+# https://xapian.org/). See the section "External Indexing and Searching" for
+# details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when not enabling USE_PDFLATEX the default is latex when enabling
+# USE_PDFLATEX the default is pdflatex and when in the later case latex is
+# chosen this is overwritten by pdflatex. For specific output languages the
+# default can have been set differently, this depends on the implementation of
+# the output language.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME =
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# Note: This tag is used in the Makefile / make.bat.
+# See also: LATEX_MAKEINDEX_CMD for the part in the generated output file
+# (.tex).
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to
+# generate index for LaTeX. In case there is no backslash (\) as first character
+# it will be automatically added in the LaTeX code.
+# Note: This tag is used in the generated output file (.tex).
+# See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat.
+# The default value is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_MAKEINDEX_CMD = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. The package can be specified just
+# by its name or with the correct syntax as to be used with the LaTeX
+# \usepackage command. To get the times font for instance you can specify :
+# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}
+# To use the option intlimits with the amsmath package you can specify:
+# EXTRA_PACKAGES=[intlimits]{amsmath}
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a user-defined LaTeX header for
+# the generated LaTeX document. The header should contain everything until the
+# first chapter. If it is left blank doxygen will generate a standard header. It
+# is highly recommended to start with a default header using
+# doxygen -w latex new_header.tex new_footer.tex new_stylesheet.sty
+# and then modify the file new_header.tex. See also section "Doxygen usage" for
+# information on how to generate the default header that doxygen normally uses.
+#
+# Note: Only use a user-defined header if you know what you are doing!
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. The following
+# commands have a special meaning inside the header (and footer): For a
+# description of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER =
+
+# The LATEX_FOOTER tag can be used to specify a user-defined LaTeX footer for
+# the generated LaTeX document. The footer should contain everything after the
+# last chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer. See also section "Doxygen
+# usage" for information on how to generate the default footer that doxygen
+# normally uses. Note: Only use a user-defined footer if you know what you are
+# doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER =
+
+# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# LaTeX style sheets that are included after the standard style sheets created
+# by doxygen. Using this option one can overrule certain style aspects. Doxygen
+# will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_STYLESHEET =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use the engine as
+# specified with LATEX_CMD_NAME to generate the PDF file directly from the LaTeX
+# files. Set this option to YES, to get a higher quality PDF documentation.
+#
+# See also section LATEX_CMD_NAME for selecting the engine.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# https://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE = plain
+
+# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_TIMESTAMP = NO
+
+# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute)
+# path from which the emoji images will be read. If a relative path is entered,
+# it will be relative to the LATEX_OUTPUT directory. If left blank the
+# LATEX_OUTPUT directory will be used.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EMOJI_DIRECTORY =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# configuration file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's configuration file. A template extensions file can be
+# generated using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING = YES
+
+# If the XML_NS_MEMB_FILE_SCOPE tag is set to YES, doxygen will include
+# namespace members in file scope as well, matching the HTML output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_NS_MEMB_FILE_SCOPE = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT = docbook
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures
+# the structure of the code including all documentation. Note that this feature
+# is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to Sqlite3 output
+#---------------------------------------------------------------------------
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor. Note that the INCLUDE_PATH is not recursive, so the setting of
+# RECURSIVE has no effect here.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED = USING_CEF_SHARED \
+ __cplusplus \
+ OS_WIN \
+ OS_LINUX \
+ CEF_X11 \
+ OS_MAC \
+ ARCH_CPU_32_BITS
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH =
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS = 0
+
+# DOT_COMMON_ATTR is common attributes for nodes, edges and labels of
+# subgraphs. When you want a differently looking font in the dot files that
+# doxygen generates you can specify fontname, fontcolor and fontsize attributes.
+# For details please see <a href=https://graphviz.org/doc/info/attrs.html>Node,
+# Edge and Graph Attributes specification</a> You need to make sure dot is able
+# to find the font, which can be done by putting it in a standard location or by
+# setting the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the
+# directory containing the font. Default graphviz fontsize is 14.
+# The default value is: fontname=Helvetica,fontsize=10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_COMMON_ATTR = "fontname=Helvetica,fontsize=10"
+
+# DOT_EDGE_ATTR is concatenated with DOT_COMMON_ATTR. For elegant style you can
+# add 'arrowhead=open, arrowtail=open, arrowsize=0.5'. <a
+# href=https://graphviz.org/doc/info/arrows.html>Complete documentation about
+# arrows shapes.</a>
+# The default value is: labelfontname=Helvetica,labelfontsize=10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_EDGE_ATTR = "labelfontname=Helvetica,labelfontsize=10"
+
+# DOT_NODE_ATTR is concatenated with DOT_COMMON_ATTR. For view without boxes
+# around nodes set 'shape=plain' or 'shape=plaintext' <a
+# href=https://www.graphviz.org/doc/info/shapes.html>Shapes specification</a>
+# The default value is: shape=box,height=0.2,width=0.4.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NODE_ATTR = "shape=box,height=0.2,width=0.4"
+
+# You can set the path where dot can find font specified with fontname in
+# DOT_COMMON_ATTR and others dot attributes.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH tag is set to YES (or GRAPH) then doxygen will generate a
+# graph for each documented class showing the direct and indirect inheritance
+# relations. In case HAVE_DOT is set as well dot will be used to draw the graph,
+# otherwise the built-in generator will be used. If the CLASS_GRAPH tag is set
+# to TEXT the direct and indirect inheritance relations will be shown as texts /
+# links.
+# Possible values are: NO, YES, TEXT and GRAPH.
+# The default value is: YES.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies. See also the chapter Grouping
+# in the manual.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag UML_LOOK is set to YES.
+
+UML_LIMIT_NUM_FIELDS = 10
+
+# If the DOT_UML_DETAILS tag is set to NO, doxygen will show attributes and
+# methods without types and arguments in the UML graphs. If the DOT_UML_DETAILS
+# tag is set to YES, doxygen will add type and arguments for attributes and
+# methods in the UML graphs. If the DOT_UML_DETAILS tag is set to NONE, doxygen
+# will not generate fields with class member information in the UML graphs. The
+# class diagrams will look similar to the default class diagrams but using UML
+# notation for the relationships.
+# Possible values are: NO, YES and NONE.
+# The default value is: NO.
+# This tag requires that the tag UML_LOOK is set to YES.
+
+DOT_UML_DETAILS = NO
+
+# The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters
+# to display on a single line. If the actual line length exceeds this threshold
+# significantly it will wrapped across multiple lines. Some heuristics are apply
+# to avoid ugly line breaks.
+# Minimum value: 0, maximum value: 1000, default value: 17.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_WRAP_THRESHOLD = 17
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command. Disabling a call graph can be
+# accomplished by means of the command \hidecallgraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command. Disabling a caller graph can be
+# accomplished by means of the command \hidecallergraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH = YES
+
+# The DIR_GRAPH_MAX_DEPTH tag can be used to limit the maximum number of levels
+# of child directories generated in directory dependency graphs by dot.
+# Minimum value: 1, maximum value: 25, default value: 1.
+# This tag requires that the tag DIRECTORY_GRAPH is set to YES.
+
+DIR_GRAPH_MAX_DEPTH = 1
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. For an explanation of the image formats see the section
+# output formats in the documentation of the dot tool (Graphviz (see:
+# http://www.graphviz.org/)).
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo,
+# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
+# png:gdiplus:gdiplus.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file or to the filename of jar file
+# to be used. If left blank, it is assumed PlantUML is not used or called during
+# a preprocessing step. Doxygen will generate a warning when it encounters a
+# \startuml command in this case and will not generate output for the diagram.
+
+PLANTUML_JAR_PATH =
+
+# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a
+# configuration file for plantuml.
+
+PLANTUML_CFG_FILE =
+
+# When using plantuml, the specified paths are searched for files specified by
+# the !include statement in a plantuml block.
+
+PLANTUML_INCLUDE_PATH =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# Note: This tag requires that UML_LOOK isn't set, i.e. the doxygen internal
+# graphical representation for inheritance and collaboration diagrams is used.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate
+# files that are used to generate the various graphs.
+#
+# Note: This setting is not only used for dot files but also for msc temporary
+# files.
+# The default value is: YES.
+
+DOT_CLEANUP = YES
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 00000000..4762abc2
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,254 @@
+// Copyright (c) 2008-2020 Marshall A. Greenblatt. Portions Copyright (c)
+// 2006-2009 Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+-----------------------------------------------------------
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-----------------------------------------------------------
+The MIT License:
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 00000000..b55d613d
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,29 @@
+// Copyright (c) 2008-2020 Marshall A. Greenblatt. Portions Copyright (c)
+// 2006-2009 Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/METADATA b/METADATA
new file mode 100644
index 00000000..2c368173
--- /dev/null
+++ b/METADATA
@@ -0,0 +1,21 @@
+name: "cef"
+description:
+ "Chromium Embedded Framework (CEF). A simple framework for "
+ "embedding Chromium-based browsers in other applications."
+
+third_party: {
+ type: PACKAGE # `type` defaults to `PACKAGE`, so typically this line is omitted
+ identifier {
+ type: "Git"
+ value: "https://bitbucket.org/chromiumembedded/cef"
+ version: "ebf5d6ab43c61ebd6ece0c504e15fe73b8da59d6" # upstream cef does not use tags (instead they use branches)
+ primary_source: true
+ }
+ version: "111.0.5563.148"
+ last_upgrade_date {
+ year: 2023
+ month: 12
+ day: 6
+ }
+ license_type: NOTICE
+}
diff --git a/MODULE_LICENSE_APACHE2 b/MODULE_LICENSE_APACHE2
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/MODULE_LICENSE_APACHE2
diff --git a/MODULE_LICENSE_BSD3 b/MODULE_LICENSE_BSD3
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/MODULE_LICENSE_BSD3
diff --git a/MODULE_LICENSE_MIT b/MODULE_LICENSE_MIT
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/MODULE_LICENSE_MIT
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 00000000..d83f0d44
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1,2 @@
+jlogs@google.com
+yakavets@google.com
diff --git a/README.md b/README.md
new file mode 100644
index 00000000..cd85b7ca
--- /dev/null
+++ b/README.md
@@ -0,0 +1,83 @@
+The Chromium Embedded Framework (CEF) is a simple framework for embedding Chromium-based browsers in other applications.
+
+# Quick Links
+
+* Project Page - https://bitbucket.org/chromiumembedded/cef
+* Tutorial - https://bitbucket.org/chromiumembedded/cef/wiki/Tutorial
+* General Usage - https://bitbucket.org/chromiumembedded/cef/wiki/GeneralUsage
+* Master Build Quick-Start - https://bitbucket.org/chromiumembedded/cef/wiki/MasterBuildQuickStart
+* Branches and Building - https://bitbucket.org/chromiumembedded/cef/wiki/BranchesAndBuilding
+* Announcements - https://groups.google.com/forum/#!forum/cef-announce
+* Support Forum - http://www.magpcss.org/ceforum/
+* Issue Tracker - https://github.com/chromiumembedded/cef/issues
+* C++ API Docs - [Stable release docs](https://cef-builds.spotifycdn.com/docs/stable.html) / [Beta release docs](https://cef-builds.spotifycdn.com/docs/beta.html)
+* Downloads - https://cef-builds.spotifycdn.com/index.html
+* Donations - http://www.magpcss.org/ceforum/donate.php
+
+# Introduction
+
+CEF is a BSD-licensed open source project founded by Marshall Greenblatt in 2008 and based on the [Google Chromium](http://www.chromium.org/Home) project. Unlike the Chromium project itself, which focuses mainly on Google Chrome application development, CEF focuses on facilitating embedded browser use cases in third-party applications. CEF insulates the user from the underlying Chromium and Blink code complexity by offering production-quality stable APIs, release branches tracking specific Chromium releases, and binary distributions. Most features in CEF have default implementations that provide rich functionality while requiring little or no integration work from the user. There are currently over 100 million installed instances of CEF around the world embedded in products from a wide range of companies and industries. A partial list of companies and products using CEF is available on the [CEF Wikipedia page](http://en.wikipedia.org/wiki/Chromium_Embedded_Framework#Applications_using_CEF). Some use cases for CEF include:
+
+* Embedding an HTML5-compliant Web browser control in an existing native application.
+* Creating a light-weight native “shell” application that hosts a user interface developed primarily using Web technologies.
+* Rendering Web content “off-screen” in applications that have their own custom drawing frameworks.
+* Acting as a host for automated testing of existing Web properties and applications.
+
+CEF supports a wide range of programming languages and operating systems and can be easily integrated into both new and existing applications. It was designed from the ground up with both performance and ease of use in mind. The base framework includes C and C++ programming interfaces exposed via native libraries that insulate the host application from Chromium and Blink implementation details. It provides close integration between the browser and the host application including support for custom plugins, protocols, JavaScript objects and JavaScript extensions. The host application can optionally control resource loading, navigation, context menus, printing and more, while taking advantage of the same performance and HTML5 technologies available in the Google Chrome Web browser.
+
+Numerous individuals and organizations contribute time and resources to support CEF development, but more involvement from the community is always welcome. This includes support for both the core CEF project and external projects that integrate CEF with additional programming languages and frameworks (see the "External Projects" section below). If you are interested in donating time to help with CEF development please see the "Helping Out" section below. If you are interested in donating money to support general CEF development and infrastructure efforts please visit the [CEF Donations](http://www.magpcss.org/ceforum/donate.php) page.
+
+# Getting Started
+
+Users new to CEF development should start by reading the [Tutorial](https://bitbucket.org/chromiumembedded/cef/wiki/Tutorial) Wiki page for an overview of CEF usage and then proceed to the [GeneralUsage](https://bitbucket.org/chromiumembedded/cef/wiki/GeneralUsage) Wiki page for a more in-depth discussion or architectural and usage issues. Complete API documentation is available [here](https://cef-builds.spotifycdn.com/docs/stable.html). CEF support and related discussion is available on the [CEF Forum](http://www.magpcss.org/ceforum/).
+
+# Binary Distributions
+
+Binary distributions, which include all files necessary to build a CEF-based application, are available on the [Downloads](https://cef-builds.spotifycdn.com/index.html) page. Binary distributions are stand-alone and do not require the download of CEF or Chromium source code. Symbol files for debugging binary distributions of libcef can also be downloaded from the above links.
+
+# Source Distributions
+
+The CEF project is an extension of the Chromium project. CEF maintains development and release branches that track Chromium branches. CEF source code can be downloaded, built and packaged manually or with automated tools. Visit the [BranchesAndBuilding](https://bitbucket.org/chromiumembedded/cef/wiki/BranchesAndBuilding) Wiki page for more information.
+
+# External Projects
+
+The base CEF framework includes support for the C and C++ programming languages. Thanks to the hard work of external maintainers CEF can integrate with a number of other programming languages and frameworks. These external projects are not maintained by CEF so please contact the respective project maintainer if you have any questions or issues.
+
+* .Net (CEF3) - https://github.com/cefsharp/CefSharp
+* .Net (CEF1) - https://bitbucket.org/fddima/cefglue
+* .Net/Mono (CEF3) - https://gitlab.com/xiliumhq/chromiumembedded/cefglue
+* Delphi - https://github.com/hgourvest/dcef3
+* Delphi - https://github.com/salvadordf/CEF4Delphi
+* Go - https://github.com/CzarekTomczak/cef2go
+* Java - https://bitbucket.org/chromiumembedded/java-cef
+* Python - http://code.google.com/p/cefpython/
+
+If you're the maintainer of a project not listed above and would like your project listed here please either post to the [CEF Forum](http://www.magpcss.org/ceforum/) or contact Marshall directly.
+
+# Helping Out
+
+CEF is still very much a work in progress. Some ways that you can help out:
+
+\- Vote for issues in the [CEF issue tracker](https://github.com/chromiumembedded/cef/issues) that are important to you. This helps with development prioritization.
+
+\- Report any bugs that you find or feature requests that are important to you. Make sure to first search for existing issues before creating new ones. Please use the [CEF Forum](http://magpcss.org/ceforum) and not the issue tracker for usage questions. Each CEF issue should:
+
+* Include the CEF revision or binary distribution version.
+* Include information about your OS and compiler version.
+* If the issue is a bug please provide detailed reproduction information.
+* If the issue is a feature please describe why the feature is beneficial.
+
+\- Write unit tests for new or existing functionality.
+
+\- Pull requests and patches are welcome. View open issues in the [CEF issue tracker](https://github.com/chromiumembedded/cef/issues) or search for TODO(cef) in the source code for ideas.
+
+If you would like to contribute source code changes to CEF please follow the below guidelines:
+
+\- Create or find an appropriate issue for each distinct bug, feature or change.
+
+\- Submit a [pull request](https://bitbucket.org/chromiumembedded/cef/wiki/ContributingWithGit) or create a patch with your changes and attach it to the CEF issue. Changes should:
+
+* Be submitted against the current [CEF master branch](https://bitbucket.org/chromiumembedded/cef/src/?at=master) unless explicitly fixing a bug in a CEF release branch.
+* Follow the style of existing CEF source files. In general CEF uses the [Chromium C++ style guide](https://chromium.googlesource.com/chromium/src/+/master/styleguide/c++/c++.md).
+* Include new or modified unit tests as appropriate to the functionality.
+* Not include unnecessary or unrelated changes.
diff --git a/VERSION.in b/VERSION.in
new file mode 100644
index 00000000..2ecb9806
--- /dev/null
+++ b/VERSION.in
@@ -0,0 +1 @@
+CEF_MAJOR=3
diff --git a/cef_create_projects.bat b/cef_create_projects.bat
new file mode 100644
index 00000000..8dc77845
--- /dev/null
+++ b/cef_create_projects.bat
@@ -0,0 +1,2 @@
+@echo off
+python.bat tools\gclient_hook.py
diff --git a/cef_create_projects.sh b/cef_create_projects.sh
new file mode 100755
index 00000000..d77c9a1a
--- /dev/null
+++ b/cef_create_projects.sh
@@ -0,0 +1,2 @@
+#!/bin/sh
+python3 tools/gclient_hook.py
diff --git a/cef_paths.gypi b/cef_paths.gypi
new file mode 100644
index 00000000..6adc1387
--- /dev/null
+++ b/cef_paths.gypi
@@ -0,0 +1,881 @@
+# Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+# reserved. Use of this source code is governed by a BSD-style license that
+# can be found in the LICENSE file.
+#
+# ---------------------------------------------------------------------------
+#
+# This file was generated by the CEF translator tool and should not edited
+# by hand. See the translator.README.txt file in the tools directory for
+# more information.
+#
+# $hash=ab931540f6f4d80336123acea6cf51e701f5a63a$
+#
+
+{
+ 'variables': {
+ 'autogen_cpp_includes': [
+ 'include/cef_accessibility_handler.h',
+ 'include/cef_app.h',
+ 'include/cef_audio_handler.h',
+ 'include/cef_auth_callback.h',
+ 'include/cef_browser.h',
+ 'include/cef_browser_process_handler.h',
+ 'include/cef_callback.h',
+ 'include/cef_client.h',
+ 'include/cef_command_handler.h',
+ 'include/cef_command_line.h',
+ 'include/cef_context_menu_handler.h',
+ 'include/cef_cookie.h',
+ 'include/cef_crash_util.h',
+ 'include/cef_devtools_message_observer.h',
+ 'include/cef_dialog_handler.h',
+ 'include/cef_display_handler.h',
+ 'include/cef_dom.h',
+ 'include/cef_download_handler.h',
+ 'include/cef_download_item.h',
+ 'include/cef_drag_data.h',
+ 'include/cef_drag_handler.h',
+ 'include/cef_extension.h',
+ 'include/cef_extension_handler.h',
+ 'include/cef_file_util.h',
+ 'include/cef_find_handler.h',
+ 'include/cef_focus_handler.h',
+ 'include/cef_frame.h',
+ 'include/cef_frame_handler.h',
+ 'include/cef_i18n_util.h',
+ 'include/cef_image.h',
+ 'include/cef_jsdialog_handler.h',
+ 'include/cef_keyboard_handler.h',
+ 'include/cef_life_span_handler.h',
+ 'include/cef_load_handler.h',
+ 'include/cef_media_router.h',
+ 'include/cef_menu_model.h',
+ 'include/cef_menu_model_delegate.h',
+ 'include/cef_navigation_entry.h',
+ 'include/cef_origin_whitelist.h',
+ 'include/cef_parser.h',
+ 'include/cef_path_util.h',
+ 'include/cef_permission_handler.h',
+ 'include/cef_preference.h',
+ 'include/cef_print_handler.h',
+ 'include/cef_print_settings.h',
+ 'include/cef_process_message.h',
+ 'include/cef_process_util.h',
+ 'include/cef_registration.h',
+ 'include/cef_render_handler.h',
+ 'include/cef_render_process_handler.h',
+ 'include/cef_request.h',
+ 'include/cef_request_context.h',
+ 'include/cef_request_context_handler.h',
+ 'include/cef_request_handler.h',
+ 'include/cef_resource_bundle.h',
+ 'include/cef_resource_bundle_handler.h',
+ 'include/cef_resource_handler.h',
+ 'include/cef_resource_request_handler.h',
+ 'include/cef_response.h',
+ 'include/cef_response_filter.h',
+ 'include/cef_scheme.h',
+ 'include/cef_server.h',
+ 'include/cef_shared_memory_region.h',
+ 'include/cef_shared_process_message_builder.h',
+ 'include/cef_ssl_info.h',
+ 'include/cef_ssl_status.h',
+ 'include/cef_stream.h',
+ 'include/cef_string_visitor.h',
+ 'include/cef_task.h',
+ 'include/cef_thread.h',
+ 'include/cef_trace.h',
+ 'include/cef_urlrequest.h',
+ 'include/cef_v8.h',
+ 'include/cef_values.h',
+ 'include/cef_waitable_event.h',
+ 'include/cef_x509_certificate.h',
+ 'include/cef_xml_reader.h',
+ 'include/cef_zip_reader.h',
+ 'include/test/cef_test_helpers.h',
+ 'include/test/cef_test_server.h',
+ 'include/test/cef_translator_test.h',
+ 'include/views/cef_box_layout.h',
+ 'include/views/cef_browser_view.h',
+ 'include/views/cef_browser_view_delegate.h',
+ 'include/views/cef_button.h',
+ 'include/views/cef_button_delegate.h',
+ 'include/views/cef_display.h',
+ 'include/views/cef_fill_layout.h',
+ 'include/views/cef_label_button.h',
+ 'include/views/cef_layout.h',
+ 'include/views/cef_menu_button.h',
+ 'include/views/cef_menu_button_delegate.h',
+ 'include/views/cef_overlay_controller.h',
+ 'include/views/cef_panel.h',
+ 'include/views/cef_panel_delegate.h',
+ 'include/views/cef_scroll_view.h',
+ 'include/views/cef_textfield.h',
+ 'include/views/cef_textfield_delegate.h',
+ 'include/views/cef_view.h',
+ 'include/views/cef_view_delegate.h',
+ 'include/views/cef_window.h',
+ 'include/views/cef_window_delegate.h',
+ ],
+ 'autogen_capi_includes': [
+ 'include/capi/cef_accessibility_handler_capi.h',
+ 'include/capi/cef_app_capi.h',
+ 'include/capi/cef_audio_handler_capi.h',
+ 'include/capi/cef_auth_callback_capi.h',
+ 'include/capi/cef_browser_capi.h',
+ 'include/capi/cef_browser_process_handler_capi.h',
+ 'include/capi/cef_callback_capi.h',
+ 'include/capi/cef_client_capi.h',
+ 'include/capi/cef_command_handler_capi.h',
+ 'include/capi/cef_command_line_capi.h',
+ 'include/capi/cef_context_menu_handler_capi.h',
+ 'include/capi/cef_cookie_capi.h',
+ 'include/capi/cef_crash_util_capi.h',
+ 'include/capi/cef_devtools_message_observer_capi.h',
+ 'include/capi/cef_dialog_handler_capi.h',
+ 'include/capi/cef_display_handler_capi.h',
+ 'include/capi/cef_dom_capi.h',
+ 'include/capi/cef_download_handler_capi.h',
+ 'include/capi/cef_download_item_capi.h',
+ 'include/capi/cef_drag_data_capi.h',
+ 'include/capi/cef_drag_handler_capi.h',
+ 'include/capi/cef_extension_capi.h',
+ 'include/capi/cef_extension_handler_capi.h',
+ 'include/capi/cef_file_util_capi.h',
+ 'include/capi/cef_find_handler_capi.h',
+ 'include/capi/cef_focus_handler_capi.h',
+ 'include/capi/cef_frame_capi.h',
+ 'include/capi/cef_frame_handler_capi.h',
+ 'include/capi/cef_i18n_util_capi.h',
+ 'include/capi/cef_image_capi.h',
+ 'include/capi/cef_jsdialog_handler_capi.h',
+ 'include/capi/cef_keyboard_handler_capi.h',
+ 'include/capi/cef_life_span_handler_capi.h',
+ 'include/capi/cef_load_handler_capi.h',
+ 'include/capi/cef_media_router_capi.h',
+ 'include/capi/cef_menu_model_capi.h',
+ 'include/capi/cef_menu_model_delegate_capi.h',
+ 'include/capi/cef_navigation_entry_capi.h',
+ 'include/capi/cef_origin_whitelist_capi.h',
+ 'include/capi/cef_parser_capi.h',
+ 'include/capi/cef_path_util_capi.h',
+ 'include/capi/cef_permission_handler_capi.h',
+ 'include/capi/cef_preference_capi.h',
+ 'include/capi/cef_print_handler_capi.h',
+ 'include/capi/cef_print_settings_capi.h',
+ 'include/capi/cef_process_message_capi.h',
+ 'include/capi/cef_process_util_capi.h',
+ 'include/capi/cef_registration_capi.h',
+ 'include/capi/cef_render_handler_capi.h',
+ 'include/capi/cef_render_process_handler_capi.h',
+ 'include/capi/cef_request_capi.h',
+ 'include/capi/cef_request_context_capi.h',
+ 'include/capi/cef_request_context_handler_capi.h',
+ 'include/capi/cef_request_handler_capi.h',
+ 'include/capi/cef_resource_bundle_capi.h',
+ 'include/capi/cef_resource_bundle_handler_capi.h',
+ 'include/capi/cef_resource_handler_capi.h',
+ 'include/capi/cef_resource_request_handler_capi.h',
+ 'include/capi/cef_response_capi.h',
+ 'include/capi/cef_response_filter_capi.h',
+ 'include/capi/cef_scheme_capi.h',
+ 'include/capi/cef_server_capi.h',
+ 'include/capi/cef_shared_memory_region_capi.h',
+ 'include/capi/cef_shared_process_message_builder_capi.h',
+ 'include/capi/cef_ssl_info_capi.h',
+ 'include/capi/cef_ssl_status_capi.h',
+ 'include/capi/cef_stream_capi.h',
+ 'include/capi/cef_string_visitor_capi.h',
+ 'include/capi/cef_task_capi.h',
+ 'include/capi/cef_thread_capi.h',
+ 'include/capi/cef_trace_capi.h',
+ 'include/capi/cef_urlrequest_capi.h',
+ 'include/capi/cef_v8_capi.h',
+ 'include/capi/cef_values_capi.h',
+ 'include/capi/cef_waitable_event_capi.h',
+ 'include/capi/cef_x509_certificate_capi.h',
+ 'include/capi/cef_xml_reader_capi.h',
+ 'include/capi/cef_zip_reader_capi.h',
+ 'include/capi/test/cef_test_helpers_capi.h',
+ 'include/capi/test/cef_test_server_capi.h',
+ 'include/capi/test/cef_translator_test_capi.h',
+ 'include/capi/views/cef_box_layout_capi.h',
+ 'include/capi/views/cef_browser_view_capi.h',
+ 'include/capi/views/cef_browser_view_delegate_capi.h',
+ 'include/capi/views/cef_button_capi.h',
+ 'include/capi/views/cef_button_delegate_capi.h',
+ 'include/capi/views/cef_display_capi.h',
+ 'include/capi/views/cef_fill_layout_capi.h',
+ 'include/capi/views/cef_label_button_capi.h',
+ 'include/capi/views/cef_layout_capi.h',
+ 'include/capi/views/cef_menu_button_capi.h',
+ 'include/capi/views/cef_menu_button_delegate_capi.h',
+ 'include/capi/views/cef_overlay_controller_capi.h',
+ 'include/capi/views/cef_panel_capi.h',
+ 'include/capi/views/cef_panel_delegate_capi.h',
+ 'include/capi/views/cef_scroll_view_capi.h',
+ 'include/capi/views/cef_textfield_capi.h',
+ 'include/capi/views/cef_textfield_delegate_capi.h',
+ 'include/capi/views/cef_view_capi.h',
+ 'include/capi/views/cef_view_delegate_capi.h',
+ 'include/capi/views/cef_window_capi.h',
+ 'include/capi/views/cef_window_delegate_capi.h',
+ ],
+ 'autogen_library_side': [
+ 'libcef_dll/ctocpp/accessibility_handler_ctocpp.cc',
+ 'libcef_dll/ctocpp/accessibility_handler_ctocpp.h',
+ 'libcef_dll/ctocpp/app_ctocpp.cc',
+ 'libcef_dll/ctocpp/app_ctocpp.h',
+ 'libcef_dll/ctocpp/audio_handler_ctocpp.cc',
+ 'libcef_dll/ctocpp/audio_handler_ctocpp.h',
+ 'libcef_dll/cpptoc/auth_callback_cpptoc.cc',
+ 'libcef_dll/cpptoc/auth_callback_cpptoc.h',
+ 'libcef_dll/cpptoc/before_download_callback_cpptoc.cc',
+ 'libcef_dll/cpptoc/before_download_callback_cpptoc.h',
+ 'libcef_dll/cpptoc/binary_value_cpptoc.cc',
+ 'libcef_dll/cpptoc/binary_value_cpptoc.h',
+ 'libcef_dll/cpptoc/views/box_layout_cpptoc.cc',
+ 'libcef_dll/cpptoc/views/box_layout_cpptoc.h',
+ 'libcef_dll/cpptoc/browser_cpptoc.cc',
+ 'libcef_dll/cpptoc/browser_cpptoc.h',
+ 'libcef_dll/cpptoc/browser_host_cpptoc.cc',
+ 'libcef_dll/cpptoc/browser_host_cpptoc.h',
+ 'libcef_dll/ctocpp/browser_process_handler_ctocpp.cc',
+ 'libcef_dll/ctocpp/browser_process_handler_ctocpp.h',
+ 'libcef_dll/cpptoc/views/browser_view_cpptoc.cc',
+ 'libcef_dll/cpptoc/views/browser_view_cpptoc.h',
+ 'libcef_dll/ctocpp/views/browser_view_delegate_ctocpp.cc',
+ 'libcef_dll/ctocpp/views/browser_view_delegate_ctocpp.h',
+ 'libcef_dll/cpptoc/views/button_cpptoc.cc',
+ 'libcef_dll/cpptoc/views/button_cpptoc.h',
+ 'libcef_dll/ctocpp/views/button_delegate_ctocpp.cc',
+ 'libcef_dll/ctocpp/views/button_delegate_ctocpp.h',
+ 'libcef_dll/cpptoc/callback_cpptoc.cc',
+ 'libcef_dll/cpptoc/callback_cpptoc.h',
+ 'libcef_dll/ctocpp/client_ctocpp.cc',
+ 'libcef_dll/ctocpp/client_ctocpp.h',
+ 'libcef_dll/ctocpp/command_handler_ctocpp.cc',
+ 'libcef_dll/ctocpp/command_handler_ctocpp.h',
+ 'libcef_dll/cpptoc/command_line_cpptoc.cc',
+ 'libcef_dll/cpptoc/command_line_cpptoc.h',
+ 'libcef_dll/ctocpp/completion_callback_ctocpp.cc',
+ 'libcef_dll/ctocpp/completion_callback_ctocpp.h',
+ 'libcef_dll/ctocpp/context_menu_handler_ctocpp.cc',
+ 'libcef_dll/ctocpp/context_menu_handler_ctocpp.h',
+ 'libcef_dll/cpptoc/context_menu_params_cpptoc.cc',
+ 'libcef_dll/cpptoc/context_menu_params_cpptoc.h',
+ 'libcef_dll/ctocpp/cookie_access_filter_ctocpp.cc',
+ 'libcef_dll/ctocpp/cookie_access_filter_ctocpp.h',
+ 'libcef_dll/cpptoc/cookie_manager_cpptoc.cc',
+ 'libcef_dll/cpptoc/cookie_manager_cpptoc.h',
+ 'libcef_dll/ctocpp/cookie_visitor_ctocpp.cc',
+ 'libcef_dll/ctocpp/cookie_visitor_ctocpp.h',
+ 'libcef_dll/cpptoc/domdocument_cpptoc.cc',
+ 'libcef_dll/cpptoc/domdocument_cpptoc.h',
+ 'libcef_dll/cpptoc/domnode_cpptoc.cc',
+ 'libcef_dll/cpptoc/domnode_cpptoc.h',
+ 'libcef_dll/ctocpp/domvisitor_ctocpp.cc',
+ 'libcef_dll/ctocpp/domvisitor_ctocpp.h',
+ 'libcef_dll/ctocpp/delete_cookies_callback_ctocpp.cc',
+ 'libcef_dll/ctocpp/delete_cookies_callback_ctocpp.h',
+ 'libcef_dll/ctocpp/dev_tools_message_observer_ctocpp.cc',
+ 'libcef_dll/ctocpp/dev_tools_message_observer_ctocpp.h',
+ 'libcef_dll/ctocpp/dialog_handler_ctocpp.cc',
+ 'libcef_dll/ctocpp/dialog_handler_ctocpp.h',
+ 'libcef_dll/cpptoc/dictionary_value_cpptoc.cc',
+ 'libcef_dll/cpptoc/dictionary_value_cpptoc.h',
+ 'libcef_dll/cpptoc/views/display_cpptoc.cc',
+ 'libcef_dll/cpptoc/views/display_cpptoc.h',
+ 'libcef_dll/ctocpp/display_handler_ctocpp.cc',
+ 'libcef_dll/ctocpp/display_handler_ctocpp.h',
+ 'libcef_dll/ctocpp/download_handler_ctocpp.cc',
+ 'libcef_dll/ctocpp/download_handler_ctocpp.h',
+ 'libcef_dll/ctocpp/download_image_callback_ctocpp.cc',
+ 'libcef_dll/ctocpp/download_image_callback_ctocpp.h',
+ 'libcef_dll/cpptoc/download_item_cpptoc.cc',
+ 'libcef_dll/cpptoc/download_item_cpptoc.h',
+ 'libcef_dll/cpptoc/download_item_callback_cpptoc.cc',
+ 'libcef_dll/cpptoc/download_item_callback_cpptoc.h',
+ 'libcef_dll/cpptoc/drag_data_cpptoc.cc',
+ 'libcef_dll/cpptoc/drag_data_cpptoc.h',
+ 'libcef_dll/ctocpp/drag_handler_ctocpp.cc',
+ 'libcef_dll/ctocpp/drag_handler_ctocpp.h',
+ 'libcef_dll/ctocpp/end_tracing_callback_ctocpp.cc',
+ 'libcef_dll/ctocpp/end_tracing_callback_ctocpp.h',
+ 'libcef_dll/cpptoc/extension_cpptoc.cc',
+ 'libcef_dll/cpptoc/extension_cpptoc.h',
+ 'libcef_dll/ctocpp/extension_handler_ctocpp.cc',
+ 'libcef_dll/ctocpp/extension_handler_ctocpp.h',
+ 'libcef_dll/cpptoc/file_dialog_callback_cpptoc.cc',
+ 'libcef_dll/cpptoc/file_dialog_callback_cpptoc.h',
+ 'libcef_dll/cpptoc/views/fill_layout_cpptoc.cc',
+ 'libcef_dll/cpptoc/views/fill_layout_cpptoc.h',
+ 'libcef_dll/ctocpp/find_handler_ctocpp.cc',
+ 'libcef_dll/ctocpp/find_handler_ctocpp.h',
+ 'libcef_dll/ctocpp/focus_handler_ctocpp.cc',
+ 'libcef_dll/ctocpp/focus_handler_ctocpp.h',
+ 'libcef_dll/cpptoc/frame_cpptoc.cc',
+ 'libcef_dll/cpptoc/frame_cpptoc.h',
+ 'libcef_dll/ctocpp/frame_handler_ctocpp.cc',
+ 'libcef_dll/ctocpp/frame_handler_ctocpp.h',
+ 'libcef_dll/cpptoc/get_extension_resource_callback_cpptoc.cc',
+ 'libcef_dll/cpptoc/get_extension_resource_callback_cpptoc.h',
+ 'libcef_dll/cpptoc/image_cpptoc.cc',
+ 'libcef_dll/cpptoc/image_cpptoc.h',
+ 'libcef_dll/cpptoc/jsdialog_callback_cpptoc.cc',
+ 'libcef_dll/cpptoc/jsdialog_callback_cpptoc.h',
+ 'libcef_dll/ctocpp/jsdialog_handler_ctocpp.cc',
+ 'libcef_dll/ctocpp/jsdialog_handler_ctocpp.h',
+ 'libcef_dll/ctocpp/keyboard_handler_ctocpp.cc',
+ 'libcef_dll/ctocpp/keyboard_handler_ctocpp.h',
+ 'libcef_dll/cpptoc/views/label_button_cpptoc.cc',
+ 'libcef_dll/cpptoc/views/label_button_cpptoc.h',
+ 'libcef_dll/cpptoc/views/layout_cpptoc.cc',
+ 'libcef_dll/cpptoc/views/layout_cpptoc.h',
+ 'libcef_dll/ctocpp/life_span_handler_ctocpp.cc',
+ 'libcef_dll/ctocpp/life_span_handler_ctocpp.h',
+ 'libcef_dll/cpptoc/list_value_cpptoc.cc',
+ 'libcef_dll/cpptoc/list_value_cpptoc.h',
+ 'libcef_dll/ctocpp/load_handler_ctocpp.cc',
+ 'libcef_dll/ctocpp/load_handler_ctocpp.h',
+ 'libcef_dll/cpptoc/media_access_callback_cpptoc.cc',
+ 'libcef_dll/cpptoc/media_access_callback_cpptoc.h',
+ 'libcef_dll/ctocpp/media_observer_ctocpp.cc',
+ 'libcef_dll/ctocpp/media_observer_ctocpp.h',
+ 'libcef_dll/cpptoc/media_route_cpptoc.cc',
+ 'libcef_dll/cpptoc/media_route_cpptoc.h',
+ 'libcef_dll/ctocpp/media_route_create_callback_ctocpp.cc',
+ 'libcef_dll/ctocpp/media_route_create_callback_ctocpp.h',
+ 'libcef_dll/cpptoc/media_router_cpptoc.cc',
+ 'libcef_dll/cpptoc/media_router_cpptoc.h',
+ 'libcef_dll/cpptoc/media_sink_cpptoc.cc',
+ 'libcef_dll/cpptoc/media_sink_cpptoc.h',
+ 'libcef_dll/ctocpp/media_sink_device_info_callback_ctocpp.cc',
+ 'libcef_dll/ctocpp/media_sink_device_info_callback_ctocpp.h',
+ 'libcef_dll/cpptoc/media_source_cpptoc.cc',
+ 'libcef_dll/cpptoc/media_source_cpptoc.h',
+ 'libcef_dll/cpptoc/views/menu_button_cpptoc.cc',
+ 'libcef_dll/cpptoc/views/menu_button_cpptoc.h',
+ 'libcef_dll/ctocpp/views/menu_button_delegate_ctocpp.cc',
+ 'libcef_dll/ctocpp/views/menu_button_delegate_ctocpp.h',
+ 'libcef_dll/cpptoc/views/menu_button_pressed_lock_cpptoc.cc',
+ 'libcef_dll/cpptoc/views/menu_button_pressed_lock_cpptoc.h',
+ 'libcef_dll/cpptoc/menu_model_cpptoc.cc',
+ 'libcef_dll/cpptoc/menu_model_cpptoc.h',
+ 'libcef_dll/ctocpp/menu_model_delegate_ctocpp.cc',
+ 'libcef_dll/ctocpp/menu_model_delegate_ctocpp.h',
+ 'libcef_dll/cpptoc/navigation_entry_cpptoc.cc',
+ 'libcef_dll/cpptoc/navigation_entry_cpptoc.h',
+ 'libcef_dll/ctocpp/navigation_entry_visitor_ctocpp.cc',
+ 'libcef_dll/ctocpp/navigation_entry_visitor_ctocpp.h',
+ 'libcef_dll/cpptoc/views/overlay_controller_cpptoc.cc',
+ 'libcef_dll/cpptoc/views/overlay_controller_cpptoc.h',
+ 'libcef_dll/cpptoc/views/panel_cpptoc.cc',
+ 'libcef_dll/cpptoc/views/panel_cpptoc.h',
+ 'libcef_dll/ctocpp/views/panel_delegate_ctocpp.cc',
+ 'libcef_dll/ctocpp/views/panel_delegate_ctocpp.h',
+ 'libcef_dll/ctocpp/pdf_print_callback_ctocpp.cc',
+ 'libcef_dll/ctocpp/pdf_print_callback_ctocpp.h',
+ 'libcef_dll/ctocpp/permission_handler_ctocpp.cc',
+ 'libcef_dll/ctocpp/permission_handler_ctocpp.h',
+ 'libcef_dll/cpptoc/permission_prompt_callback_cpptoc.cc',
+ 'libcef_dll/cpptoc/permission_prompt_callback_cpptoc.h',
+ 'libcef_dll/cpptoc/post_data_cpptoc.cc',
+ 'libcef_dll/cpptoc/post_data_cpptoc.h',
+ 'libcef_dll/cpptoc/post_data_element_cpptoc.cc',
+ 'libcef_dll/cpptoc/post_data_element_cpptoc.h',
+ 'libcef_dll/cpptoc/preference_manager_cpptoc.cc',
+ 'libcef_dll/cpptoc/preference_manager_cpptoc.h',
+ 'libcef_dll/cpptoc/preference_registrar_cpptoc.cc',
+ 'libcef_dll/cpptoc/preference_registrar_cpptoc.h',
+ 'libcef_dll/cpptoc/print_dialog_callback_cpptoc.cc',
+ 'libcef_dll/cpptoc/print_dialog_callback_cpptoc.h',
+ 'libcef_dll/ctocpp/print_handler_ctocpp.cc',
+ 'libcef_dll/ctocpp/print_handler_ctocpp.h',
+ 'libcef_dll/cpptoc/print_job_callback_cpptoc.cc',
+ 'libcef_dll/cpptoc/print_job_callback_cpptoc.h',
+ 'libcef_dll/cpptoc/print_settings_cpptoc.cc',
+ 'libcef_dll/cpptoc/print_settings_cpptoc.h',
+ 'libcef_dll/cpptoc/process_message_cpptoc.cc',
+ 'libcef_dll/cpptoc/process_message_cpptoc.h',
+ 'libcef_dll/ctocpp/read_handler_ctocpp.cc',
+ 'libcef_dll/ctocpp/read_handler_ctocpp.h',
+ 'libcef_dll/cpptoc/registration_cpptoc.cc',
+ 'libcef_dll/cpptoc/registration_cpptoc.h',
+ 'libcef_dll/ctocpp/render_handler_ctocpp.cc',
+ 'libcef_dll/ctocpp/render_handler_ctocpp.h',
+ 'libcef_dll/ctocpp/render_process_handler_ctocpp.cc',
+ 'libcef_dll/ctocpp/render_process_handler_ctocpp.h',
+ 'libcef_dll/cpptoc/request_cpptoc.cc',
+ 'libcef_dll/cpptoc/request_cpptoc.h',
+ 'libcef_dll/cpptoc/request_context_cpptoc.cc',
+ 'libcef_dll/cpptoc/request_context_cpptoc.h',
+ 'libcef_dll/ctocpp/request_context_handler_ctocpp.cc',
+ 'libcef_dll/ctocpp/request_context_handler_ctocpp.h',
+ 'libcef_dll/ctocpp/request_handler_ctocpp.cc',
+ 'libcef_dll/ctocpp/request_handler_ctocpp.h',
+ 'libcef_dll/ctocpp/resolve_callback_ctocpp.cc',
+ 'libcef_dll/ctocpp/resolve_callback_ctocpp.h',
+ 'libcef_dll/cpptoc/resource_bundle_cpptoc.cc',
+ 'libcef_dll/cpptoc/resource_bundle_cpptoc.h',
+ 'libcef_dll/ctocpp/resource_bundle_handler_ctocpp.cc',
+ 'libcef_dll/ctocpp/resource_bundle_handler_ctocpp.h',
+ 'libcef_dll/ctocpp/resource_handler_ctocpp.cc',
+ 'libcef_dll/ctocpp/resource_handler_ctocpp.h',
+ 'libcef_dll/cpptoc/resource_read_callback_cpptoc.cc',
+ 'libcef_dll/cpptoc/resource_read_callback_cpptoc.h',
+ 'libcef_dll/ctocpp/resource_request_handler_ctocpp.cc',
+ 'libcef_dll/ctocpp/resource_request_handler_ctocpp.h',
+ 'libcef_dll/cpptoc/resource_skip_callback_cpptoc.cc',
+ 'libcef_dll/cpptoc/resource_skip_callback_cpptoc.h',
+ 'libcef_dll/cpptoc/response_cpptoc.cc',
+ 'libcef_dll/cpptoc/response_cpptoc.h',
+ 'libcef_dll/ctocpp/response_filter_ctocpp.cc',
+ 'libcef_dll/ctocpp/response_filter_ctocpp.h',
+ 'libcef_dll/cpptoc/run_context_menu_callback_cpptoc.cc',
+ 'libcef_dll/cpptoc/run_context_menu_callback_cpptoc.h',
+ 'libcef_dll/ctocpp/run_file_dialog_callback_ctocpp.cc',
+ 'libcef_dll/ctocpp/run_file_dialog_callback_ctocpp.h',
+ 'libcef_dll/cpptoc/run_quick_menu_callback_cpptoc.cc',
+ 'libcef_dll/cpptoc/run_quick_menu_callback_cpptoc.h',
+ 'libcef_dll/cpptoc/sslinfo_cpptoc.cc',
+ 'libcef_dll/cpptoc/sslinfo_cpptoc.h',
+ 'libcef_dll/cpptoc/sslstatus_cpptoc.cc',
+ 'libcef_dll/cpptoc/sslstatus_cpptoc.h',
+ 'libcef_dll/ctocpp/scheme_handler_factory_ctocpp.cc',
+ 'libcef_dll/ctocpp/scheme_handler_factory_ctocpp.h',
+ 'libcef_dll/cpptoc/scheme_registrar_cpptoc.cc',
+ 'libcef_dll/cpptoc/scheme_registrar_cpptoc.h',
+ 'libcef_dll/cpptoc/views/scroll_view_cpptoc.cc',
+ 'libcef_dll/cpptoc/views/scroll_view_cpptoc.h',
+ 'libcef_dll/cpptoc/select_client_certificate_callback_cpptoc.cc',
+ 'libcef_dll/cpptoc/select_client_certificate_callback_cpptoc.h',
+ 'libcef_dll/cpptoc/server_cpptoc.cc',
+ 'libcef_dll/cpptoc/server_cpptoc.h',
+ 'libcef_dll/ctocpp/server_handler_ctocpp.cc',
+ 'libcef_dll/ctocpp/server_handler_ctocpp.h',
+ 'libcef_dll/ctocpp/set_cookie_callback_ctocpp.cc',
+ 'libcef_dll/ctocpp/set_cookie_callback_ctocpp.h',
+ 'libcef_dll/cpptoc/shared_memory_region_cpptoc.cc',
+ 'libcef_dll/cpptoc/shared_memory_region_cpptoc.h',
+ 'libcef_dll/cpptoc/shared_process_message_builder_cpptoc.cc',
+ 'libcef_dll/cpptoc/shared_process_message_builder_cpptoc.h',
+ 'libcef_dll/cpptoc/stream_reader_cpptoc.cc',
+ 'libcef_dll/cpptoc/stream_reader_cpptoc.h',
+ 'libcef_dll/cpptoc/stream_writer_cpptoc.cc',
+ 'libcef_dll/cpptoc/stream_writer_cpptoc.h',
+ 'libcef_dll/ctocpp/string_visitor_ctocpp.cc',
+ 'libcef_dll/ctocpp/string_visitor_ctocpp.h',
+ 'libcef_dll/ctocpp/task_ctocpp.cc',
+ 'libcef_dll/ctocpp/task_ctocpp.h',
+ 'libcef_dll/cpptoc/task_runner_cpptoc.cc',
+ 'libcef_dll/cpptoc/task_runner_cpptoc.h',
+ 'libcef_dll/cpptoc/test/test_server_cpptoc.cc',
+ 'libcef_dll/cpptoc/test/test_server_cpptoc.h',
+ 'libcef_dll/cpptoc/test/test_server_connection_cpptoc.cc',
+ 'libcef_dll/cpptoc/test/test_server_connection_cpptoc.h',
+ 'libcef_dll/ctocpp/test/test_server_handler_ctocpp.cc',
+ 'libcef_dll/ctocpp/test/test_server_handler_ctocpp.h',
+ 'libcef_dll/cpptoc/views/textfield_cpptoc.cc',
+ 'libcef_dll/cpptoc/views/textfield_cpptoc.h',
+ 'libcef_dll/ctocpp/views/textfield_delegate_ctocpp.cc',
+ 'libcef_dll/ctocpp/views/textfield_delegate_ctocpp.h',
+ 'libcef_dll/cpptoc/thread_cpptoc.cc',
+ 'libcef_dll/cpptoc/thread_cpptoc.h',
+ 'libcef_dll/cpptoc/test/translator_test_cpptoc.cc',
+ 'libcef_dll/cpptoc/test/translator_test_cpptoc.h',
+ 'libcef_dll/ctocpp/test/translator_test_ref_ptr_client_ctocpp.cc',
+ 'libcef_dll/ctocpp/test/translator_test_ref_ptr_client_ctocpp.h',
+ 'libcef_dll/ctocpp/test/translator_test_ref_ptr_client_child_ctocpp.cc',
+ 'libcef_dll/ctocpp/test/translator_test_ref_ptr_client_child_ctocpp.h',
+ 'libcef_dll/cpptoc/test/translator_test_ref_ptr_library_cpptoc.cc',
+ 'libcef_dll/cpptoc/test/translator_test_ref_ptr_library_cpptoc.h',
+ 'libcef_dll/cpptoc/test/translator_test_ref_ptr_library_child_cpptoc.cc',
+ 'libcef_dll/cpptoc/test/translator_test_ref_ptr_library_child_cpptoc.h',
+ 'libcef_dll/cpptoc/test/translator_test_ref_ptr_library_child_child_cpptoc.cc',
+ 'libcef_dll/cpptoc/test/translator_test_ref_ptr_library_child_child_cpptoc.h',
+ 'libcef_dll/ctocpp/test/translator_test_scoped_client_ctocpp.cc',
+ 'libcef_dll/ctocpp/test/translator_test_scoped_client_ctocpp.h',
+ 'libcef_dll/ctocpp/test/translator_test_scoped_client_child_ctocpp.cc',
+ 'libcef_dll/ctocpp/test/translator_test_scoped_client_child_ctocpp.h',
+ 'libcef_dll/cpptoc/test/translator_test_scoped_library_cpptoc.cc',
+ 'libcef_dll/cpptoc/test/translator_test_scoped_library_cpptoc.h',
+ 'libcef_dll/cpptoc/test/translator_test_scoped_library_child_cpptoc.cc',
+ 'libcef_dll/cpptoc/test/translator_test_scoped_library_child_cpptoc.h',
+ 'libcef_dll/cpptoc/test/translator_test_scoped_library_child_child_cpptoc.cc',
+ 'libcef_dll/cpptoc/test/translator_test_scoped_library_child_child_cpptoc.h',
+ 'libcef_dll/cpptoc/urlrequest_cpptoc.cc',
+ 'libcef_dll/cpptoc/urlrequest_cpptoc.h',
+ 'libcef_dll/ctocpp/urlrequest_client_ctocpp.cc',
+ 'libcef_dll/ctocpp/urlrequest_client_ctocpp.h',
+ 'libcef_dll/ctocpp/v8accessor_ctocpp.cc',
+ 'libcef_dll/ctocpp/v8accessor_ctocpp.h',
+ 'libcef_dll/ctocpp/v8array_buffer_release_callback_ctocpp.cc',
+ 'libcef_dll/ctocpp/v8array_buffer_release_callback_ctocpp.h',
+ 'libcef_dll/cpptoc/v8context_cpptoc.cc',
+ 'libcef_dll/cpptoc/v8context_cpptoc.h',
+ 'libcef_dll/cpptoc/v8exception_cpptoc.cc',
+ 'libcef_dll/cpptoc/v8exception_cpptoc.h',
+ 'libcef_dll/ctocpp/v8handler_ctocpp.cc',
+ 'libcef_dll/ctocpp/v8handler_ctocpp.h',
+ 'libcef_dll/ctocpp/v8interceptor_ctocpp.cc',
+ 'libcef_dll/ctocpp/v8interceptor_ctocpp.h',
+ 'libcef_dll/cpptoc/v8stack_frame_cpptoc.cc',
+ 'libcef_dll/cpptoc/v8stack_frame_cpptoc.h',
+ 'libcef_dll/cpptoc/v8stack_trace_cpptoc.cc',
+ 'libcef_dll/cpptoc/v8stack_trace_cpptoc.h',
+ 'libcef_dll/cpptoc/v8value_cpptoc.cc',
+ 'libcef_dll/cpptoc/v8value_cpptoc.h',
+ 'libcef_dll/cpptoc/value_cpptoc.cc',
+ 'libcef_dll/cpptoc/value_cpptoc.h',
+ 'libcef_dll/cpptoc/views/view_cpptoc.cc',
+ 'libcef_dll/cpptoc/views/view_cpptoc.h',
+ 'libcef_dll/ctocpp/views/view_delegate_ctocpp.cc',
+ 'libcef_dll/ctocpp/views/view_delegate_ctocpp.h',
+ 'libcef_dll/cpptoc/waitable_event_cpptoc.cc',
+ 'libcef_dll/cpptoc/waitable_event_cpptoc.h',
+ 'libcef_dll/cpptoc/views/window_cpptoc.cc',
+ 'libcef_dll/cpptoc/views/window_cpptoc.h',
+ 'libcef_dll/ctocpp/views/window_delegate_ctocpp.cc',
+ 'libcef_dll/ctocpp/views/window_delegate_ctocpp.h',
+ 'libcef_dll/ctocpp/write_handler_ctocpp.cc',
+ 'libcef_dll/ctocpp/write_handler_ctocpp.h',
+ 'libcef_dll/cpptoc/x509cert_principal_cpptoc.cc',
+ 'libcef_dll/cpptoc/x509cert_principal_cpptoc.h',
+ 'libcef_dll/cpptoc/x509certificate_cpptoc.cc',
+ 'libcef_dll/cpptoc/x509certificate_cpptoc.h',
+ 'libcef_dll/cpptoc/xml_reader_cpptoc.cc',
+ 'libcef_dll/cpptoc/xml_reader_cpptoc.h',
+ 'libcef_dll/cpptoc/zip_reader_cpptoc.cc',
+ 'libcef_dll/cpptoc/zip_reader_cpptoc.h',
+ ],
+ 'autogen_client_side': [
+ 'libcef_dll/cpptoc/accessibility_handler_cpptoc.cc',
+ 'libcef_dll/cpptoc/accessibility_handler_cpptoc.h',
+ 'libcef_dll/cpptoc/app_cpptoc.cc',
+ 'libcef_dll/cpptoc/app_cpptoc.h',
+ 'libcef_dll/cpptoc/audio_handler_cpptoc.cc',
+ 'libcef_dll/cpptoc/audio_handler_cpptoc.h',
+ 'libcef_dll/ctocpp/auth_callback_ctocpp.cc',
+ 'libcef_dll/ctocpp/auth_callback_ctocpp.h',
+ 'libcef_dll/ctocpp/before_download_callback_ctocpp.cc',
+ 'libcef_dll/ctocpp/before_download_callback_ctocpp.h',
+ 'libcef_dll/ctocpp/binary_value_ctocpp.cc',
+ 'libcef_dll/ctocpp/binary_value_ctocpp.h',
+ 'libcef_dll/ctocpp/views/box_layout_ctocpp.cc',
+ 'libcef_dll/ctocpp/views/box_layout_ctocpp.h',
+ 'libcef_dll/ctocpp/browser_ctocpp.cc',
+ 'libcef_dll/ctocpp/browser_ctocpp.h',
+ 'libcef_dll/ctocpp/browser_host_ctocpp.cc',
+ 'libcef_dll/ctocpp/browser_host_ctocpp.h',
+ 'libcef_dll/cpptoc/browser_process_handler_cpptoc.cc',
+ 'libcef_dll/cpptoc/browser_process_handler_cpptoc.h',
+ 'libcef_dll/ctocpp/views/browser_view_ctocpp.cc',
+ 'libcef_dll/ctocpp/views/browser_view_ctocpp.h',
+ 'libcef_dll/cpptoc/views/browser_view_delegate_cpptoc.cc',
+ 'libcef_dll/cpptoc/views/browser_view_delegate_cpptoc.h',
+ 'libcef_dll/ctocpp/views/button_ctocpp.cc',
+ 'libcef_dll/ctocpp/views/button_ctocpp.h',
+ 'libcef_dll/cpptoc/views/button_delegate_cpptoc.cc',
+ 'libcef_dll/cpptoc/views/button_delegate_cpptoc.h',
+ 'libcef_dll/ctocpp/callback_ctocpp.cc',
+ 'libcef_dll/ctocpp/callback_ctocpp.h',
+ 'libcef_dll/cpptoc/client_cpptoc.cc',
+ 'libcef_dll/cpptoc/client_cpptoc.h',
+ 'libcef_dll/cpptoc/command_handler_cpptoc.cc',
+ 'libcef_dll/cpptoc/command_handler_cpptoc.h',
+ 'libcef_dll/ctocpp/command_line_ctocpp.cc',
+ 'libcef_dll/ctocpp/command_line_ctocpp.h',
+ 'libcef_dll/cpptoc/completion_callback_cpptoc.cc',
+ 'libcef_dll/cpptoc/completion_callback_cpptoc.h',
+ 'libcef_dll/cpptoc/context_menu_handler_cpptoc.cc',
+ 'libcef_dll/cpptoc/context_menu_handler_cpptoc.h',
+ 'libcef_dll/ctocpp/context_menu_params_ctocpp.cc',
+ 'libcef_dll/ctocpp/context_menu_params_ctocpp.h',
+ 'libcef_dll/cpptoc/cookie_access_filter_cpptoc.cc',
+ 'libcef_dll/cpptoc/cookie_access_filter_cpptoc.h',
+ 'libcef_dll/ctocpp/cookie_manager_ctocpp.cc',
+ 'libcef_dll/ctocpp/cookie_manager_ctocpp.h',
+ 'libcef_dll/cpptoc/cookie_visitor_cpptoc.cc',
+ 'libcef_dll/cpptoc/cookie_visitor_cpptoc.h',
+ 'libcef_dll/ctocpp/domdocument_ctocpp.cc',
+ 'libcef_dll/ctocpp/domdocument_ctocpp.h',
+ 'libcef_dll/ctocpp/domnode_ctocpp.cc',
+ 'libcef_dll/ctocpp/domnode_ctocpp.h',
+ 'libcef_dll/cpptoc/domvisitor_cpptoc.cc',
+ 'libcef_dll/cpptoc/domvisitor_cpptoc.h',
+ 'libcef_dll/cpptoc/delete_cookies_callback_cpptoc.cc',
+ 'libcef_dll/cpptoc/delete_cookies_callback_cpptoc.h',
+ 'libcef_dll/cpptoc/dev_tools_message_observer_cpptoc.cc',
+ 'libcef_dll/cpptoc/dev_tools_message_observer_cpptoc.h',
+ 'libcef_dll/cpptoc/dialog_handler_cpptoc.cc',
+ 'libcef_dll/cpptoc/dialog_handler_cpptoc.h',
+ 'libcef_dll/ctocpp/dictionary_value_ctocpp.cc',
+ 'libcef_dll/ctocpp/dictionary_value_ctocpp.h',
+ 'libcef_dll/ctocpp/views/display_ctocpp.cc',
+ 'libcef_dll/ctocpp/views/display_ctocpp.h',
+ 'libcef_dll/cpptoc/display_handler_cpptoc.cc',
+ 'libcef_dll/cpptoc/display_handler_cpptoc.h',
+ 'libcef_dll/cpptoc/download_handler_cpptoc.cc',
+ 'libcef_dll/cpptoc/download_handler_cpptoc.h',
+ 'libcef_dll/cpptoc/download_image_callback_cpptoc.cc',
+ 'libcef_dll/cpptoc/download_image_callback_cpptoc.h',
+ 'libcef_dll/ctocpp/download_item_ctocpp.cc',
+ 'libcef_dll/ctocpp/download_item_ctocpp.h',
+ 'libcef_dll/ctocpp/download_item_callback_ctocpp.cc',
+ 'libcef_dll/ctocpp/download_item_callback_ctocpp.h',
+ 'libcef_dll/ctocpp/drag_data_ctocpp.cc',
+ 'libcef_dll/ctocpp/drag_data_ctocpp.h',
+ 'libcef_dll/cpptoc/drag_handler_cpptoc.cc',
+ 'libcef_dll/cpptoc/drag_handler_cpptoc.h',
+ 'libcef_dll/cpptoc/end_tracing_callback_cpptoc.cc',
+ 'libcef_dll/cpptoc/end_tracing_callback_cpptoc.h',
+ 'libcef_dll/ctocpp/extension_ctocpp.cc',
+ 'libcef_dll/ctocpp/extension_ctocpp.h',
+ 'libcef_dll/cpptoc/extension_handler_cpptoc.cc',
+ 'libcef_dll/cpptoc/extension_handler_cpptoc.h',
+ 'libcef_dll/ctocpp/file_dialog_callback_ctocpp.cc',
+ 'libcef_dll/ctocpp/file_dialog_callback_ctocpp.h',
+ 'libcef_dll/ctocpp/views/fill_layout_ctocpp.cc',
+ 'libcef_dll/ctocpp/views/fill_layout_ctocpp.h',
+ 'libcef_dll/cpptoc/find_handler_cpptoc.cc',
+ 'libcef_dll/cpptoc/find_handler_cpptoc.h',
+ 'libcef_dll/cpptoc/focus_handler_cpptoc.cc',
+ 'libcef_dll/cpptoc/focus_handler_cpptoc.h',
+ 'libcef_dll/ctocpp/frame_ctocpp.cc',
+ 'libcef_dll/ctocpp/frame_ctocpp.h',
+ 'libcef_dll/cpptoc/frame_handler_cpptoc.cc',
+ 'libcef_dll/cpptoc/frame_handler_cpptoc.h',
+ 'libcef_dll/ctocpp/get_extension_resource_callback_ctocpp.cc',
+ 'libcef_dll/ctocpp/get_extension_resource_callback_ctocpp.h',
+ 'libcef_dll/ctocpp/image_ctocpp.cc',
+ 'libcef_dll/ctocpp/image_ctocpp.h',
+ 'libcef_dll/ctocpp/jsdialog_callback_ctocpp.cc',
+ 'libcef_dll/ctocpp/jsdialog_callback_ctocpp.h',
+ 'libcef_dll/cpptoc/jsdialog_handler_cpptoc.cc',
+ 'libcef_dll/cpptoc/jsdialog_handler_cpptoc.h',
+ 'libcef_dll/cpptoc/keyboard_handler_cpptoc.cc',
+ 'libcef_dll/cpptoc/keyboard_handler_cpptoc.h',
+ 'libcef_dll/ctocpp/views/label_button_ctocpp.cc',
+ 'libcef_dll/ctocpp/views/label_button_ctocpp.h',
+ 'libcef_dll/ctocpp/views/layout_ctocpp.cc',
+ 'libcef_dll/ctocpp/views/layout_ctocpp.h',
+ 'libcef_dll/cpptoc/life_span_handler_cpptoc.cc',
+ 'libcef_dll/cpptoc/life_span_handler_cpptoc.h',
+ 'libcef_dll/ctocpp/list_value_ctocpp.cc',
+ 'libcef_dll/ctocpp/list_value_ctocpp.h',
+ 'libcef_dll/cpptoc/load_handler_cpptoc.cc',
+ 'libcef_dll/cpptoc/load_handler_cpptoc.h',
+ 'libcef_dll/ctocpp/media_access_callback_ctocpp.cc',
+ 'libcef_dll/ctocpp/media_access_callback_ctocpp.h',
+ 'libcef_dll/cpptoc/media_observer_cpptoc.cc',
+ 'libcef_dll/cpptoc/media_observer_cpptoc.h',
+ 'libcef_dll/ctocpp/media_route_ctocpp.cc',
+ 'libcef_dll/ctocpp/media_route_ctocpp.h',
+ 'libcef_dll/cpptoc/media_route_create_callback_cpptoc.cc',
+ 'libcef_dll/cpptoc/media_route_create_callback_cpptoc.h',
+ 'libcef_dll/ctocpp/media_router_ctocpp.cc',
+ 'libcef_dll/ctocpp/media_router_ctocpp.h',
+ 'libcef_dll/ctocpp/media_sink_ctocpp.cc',
+ 'libcef_dll/ctocpp/media_sink_ctocpp.h',
+ 'libcef_dll/cpptoc/media_sink_device_info_callback_cpptoc.cc',
+ 'libcef_dll/cpptoc/media_sink_device_info_callback_cpptoc.h',
+ 'libcef_dll/ctocpp/media_source_ctocpp.cc',
+ 'libcef_dll/ctocpp/media_source_ctocpp.h',
+ 'libcef_dll/ctocpp/views/menu_button_ctocpp.cc',
+ 'libcef_dll/ctocpp/views/menu_button_ctocpp.h',
+ 'libcef_dll/cpptoc/views/menu_button_delegate_cpptoc.cc',
+ 'libcef_dll/cpptoc/views/menu_button_delegate_cpptoc.h',
+ 'libcef_dll/ctocpp/views/menu_button_pressed_lock_ctocpp.cc',
+ 'libcef_dll/ctocpp/views/menu_button_pressed_lock_ctocpp.h',
+ 'libcef_dll/ctocpp/menu_model_ctocpp.cc',
+ 'libcef_dll/ctocpp/menu_model_ctocpp.h',
+ 'libcef_dll/cpptoc/menu_model_delegate_cpptoc.cc',
+ 'libcef_dll/cpptoc/menu_model_delegate_cpptoc.h',
+ 'libcef_dll/ctocpp/navigation_entry_ctocpp.cc',
+ 'libcef_dll/ctocpp/navigation_entry_ctocpp.h',
+ 'libcef_dll/cpptoc/navigation_entry_visitor_cpptoc.cc',
+ 'libcef_dll/cpptoc/navigation_entry_visitor_cpptoc.h',
+ 'libcef_dll/ctocpp/views/overlay_controller_ctocpp.cc',
+ 'libcef_dll/ctocpp/views/overlay_controller_ctocpp.h',
+ 'libcef_dll/ctocpp/views/panel_ctocpp.cc',
+ 'libcef_dll/ctocpp/views/panel_ctocpp.h',
+ 'libcef_dll/cpptoc/views/panel_delegate_cpptoc.cc',
+ 'libcef_dll/cpptoc/views/panel_delegate_cpptoc.h',
+ 'libcef_dll/cpptoc/pdf_print_callback_cpptoc.cc',
+ 'libcef_dll/cpptoc/pdf_print_callback_cpptoc.h',
+ 'libcef_dll/cpptoc/permission_handler_cpptoc.cc',
+ 'libcef_dll/cpptoc/permission_handler_cpptoc.h',
+ 'libcef_dll/ctocpp/permission_prompt_callback_ctocpp.cc',
+ 'libcef_dll/ctocpp/permission_prompt_callback_ctocpp.h',
+ 'libcef_dll/ctocpp/post_data_ctocpp.cc',
+ 'libcef_dll/ctocpp/post_data_ctocpp.h',
+ 'libcef_dll/ctocpp/post_data_element_ctocpp.cc',
+ 'libcef_dll/ctocpp/post_data_element_ctocpp.h',
+ 'libcef_dll/ctocpp/preference_manager_ctocpp.cc',
+ 'libcef_dll/ctocpp/preference_manager_ctocpp.h',
+ 'libcef_dll/ctocpp/preference_registrar_ctocpp.cc',
+ 'libcef_dll/ctocpp/preference_registrar_ctocpp.h',
+ 'libcef_dll/ctocpp/print_dialog_callback_ctocpp.cc',
+ 'libcef_dll/ctocpp/print_dialog_callback_ctocpp.h',
+ 'libcef_dll/cpptoc/print_handler_cpptoc.cc',
+ 'libcef_dll/cpptoc/print_handler_cpptoc.h',
+ 'libcef_dll/ctocpp/print_job_callback_ctocpp.cc',
+ 'libcef_dll/ctocpp/print_job_callback_ctocpp.h',
+ 'libcef_dll/ctocpp/print_settings_ctocpp.cc',
+ 'libcef_dll/ctocpp/print_settings_ctocpp.h',
+ 'libcef_dll/ctocpp/process_message_ctocpp.cc',
+ 'libcef_dll/ctocpp/process_message_ctocpp.h',
+ 'libcef_dll/cpptoc/read_handler_cpptoc.cc',
+ 'libcef_dll/cpptoc/read_handler_cpptoc.h',
+ 'libcef_dll/ctocpp/registration_ctocpp.cc',
+ 'libcef_dll/ctocpp/registration_ctocpp.h',
+ 'libcef_dll/cpptoc/render_handler_cpptoc.cc',
+ 'libcef_dll/cpptoc/render_handler_cpptoc.h',
+ 'libcef_dll/cpptoc/render_process_handler_cpptoc.cc',
+ 'libcef_dll/cpptoc/render_process_handler_cpptoc.h',
+ 'libcef_dll/ctocpp/request_ctocpp.cc',
+ 'libcef_dll/ctocpp/request_ctocpp.h',
+ 'libcef_dll/ctocpp/request_context_ctocpp.cc',
+ 'libcef_dll/ctocpp/request_context_ctocpp.h',
+ 'libcef_dll/cpptoc/request_context_handler_cpptoc.cc',
+ 'libcef_dll/cpptoc/request_context_handler_cpptoc.h',
+ 'libcef_dll/cpptoc/request_handler_cpptoc.cc',
+ 'libcef_dll/cpptoc/request_handler_cpptoc.h',
+ 'libcef_dll/cpptoc/resolve_callback_cpptoc.cc',
+ 'libcef_dll/cpptoc/resolve_callback_cpptoc.h',
+ 'libcef_dll/ctocpp/resource_bundle_ctocpp.cc',
+ 'libcef_dll/ctocpp/resource_bundle_ctocpp.h',
+ 'libcef_dll/cpptoc/resource_bundle_handler_cpptoc.cc',
+ 'libcef_dll/cpptoc/resource_bundle_handler_cpptoc.h',
+ 'libcef_dll/cpptoc/resource_handler_cpptoc.cc',
+ 'libcef_dll/cpptoc/resource_handler_cpptoc.h',
+ 'libcef_dll/ctocpp/resource_read_callback_ctocpp.cc',
+ 'libcef_dll/ctocpp/resource_read_callback_ctocpp.h',
+ 'libcef_dll/cpptoc/resource_request_handler_cpptoc.cc',
+ 'libcef_dll/cpptoc/resource_request_handler_cpptoc.h',
+ 'libcef_dll/ctocpp/resource_skip_callback_ctocpp.cc',
+ 'libcef_dll/ctocpp/resource_skip_callback_ctocpp.h',
+ 'libcef_dll/ctocpp/response_ctocpp.cc',
+ 'libcef_dll/ctocpp/response_ctocpp.h',
+ 'libcef_dll/cpptoc/response_filter_cpptoc.cc',
+ 'libcef_dll/cpptoc/response_filter_cpptoc.h',
+ 'libcef_dll/ctocpp/run_context_menu_callback_ctocpp.cc',
+ 'libcef_dll/ctocpp/run_context_menu_callback_ctocpp.h',
+ 'libcef_dll/cpptoc/run_file_dialog_callback_cpptoc.cc',
+ 'libcef_dll/cpptoc/run_file_dialog_callback_cpptoc.h',
+ 'libcef_dll/ctocpp/run_quick_menu_callback_ctocpp.cc',
+ 'libcef_dll/ctocpp/run_quick_menu_callback_ctocpp.h',
+ 'libcef_dll/ctocpp/sslinfo_ctocpp.cc',
+ 'libcef_dll/ctocpp/sslinfo_ctocpp.h',
+ 'libcef_dll/ctocpp/sslstatus_ctocpp.cc',
+ 'libcef_dll/ctocpp/sslstatus_ctocpp.h',
+ 'libcef_dll/cpptoc/scheme_handler_factory_cpptoc.cc',
+ 'libcef_dll/cpptoc/scheme_handler_factory_cpptoc.h',
+ 'libcef_dll/ctocpp/scheme_registrar_ctocpp.cc',
+ 'libcef_dll/ctocpp/scheme_registrar_ctocpp.h',
+ 'libcef_dll/ctocpp/views/scroll_view_ctocpp.cc',
+ 'libcef_dll/ctocpp/views/scroll_view_ctocpp.h',
+ 'libcef_dll/ctocpp/select_client_certificate_callback_ctocpp.cc',
+ 'libcef_dll/ctocpp/select_client_certificate_callback_ctocpp.h',
+ 'libcef_dll/ctocpp/server_ctocpp.cc',
+ 'libcef_dll/ctocpp/server_ctocpp.h',
+ 'libcef_dll/cpptoc/server_handler_cpptoc.cc',
+ 'libcef_dll/cpptoc/server_handler_cpptoc.h',
+ 'libcef_dll/cpptoc/set_cookie_callback_cpptoc.cc',
+ 'libcef_dll/cpptoc/set_cookie_callback_cpptoc.h',
+ 'libcef_dll/ctocpp/shared_memory_region_ctocpp.cc',
+ 'libcef_dll/ctocpp/shared_memory_region_ctocpp.h',
+ 'libcef_dll/ctocpp/shared_process_message_builder_ctocpp.cc',
+ 'libcef_dll/ctocpp/shared_process_message_builder_ctocpp.h',
+ 'libcef_dll/ctocpp/stream_reader_ctocpp.cc',
+ 'libcef_dll/ctocpp/stream_reader_ctocpp.h',
+ 'libcef_dll/ctocpp/stream_writer_ctocpp.cc',
+ 'libcef_dll/ctocpp/stream_writer_ctocpp.h',
+ 'libcef_dll/cpptoc/string_visitor_cpptoc.cc',
+ 'libcef_dll/cpptoc/string_visitor_cpptoc.h',
+ 'libcef_dll/cpptoc/task_cpptoc.cc',
+ 'libcef_dll/cpptoc/task_cpptoc.h',
+ 'libcef_dll/ctocpp/task_runner_ctocpp.cc',
+ 'libcef_dll/ctocpp/task_runner_ctocpp.h',
+ 'libcef_dll/ctocpp/test/test_server_ctocpp.cc',
+ 'libcef_dll/ctocpp/test/test_server_ctocpp.h',
+ 'libcef_dll/ctocpp/test/test_server_connection_ctocpp.cc',
+ 'libcef_dll/ctocpp/test/test_server_connection_ctocpp.h',
+ 'libcef_dll/cpptoc/test/test_server_handler_cpptoc.cc',
+ 'libcef_dll/cpptoc/test/test_server_handler_cpptoc.h',
+ 'libcef_dll/ctocpp/views/textfield_ctocpp.cc',
+ 'libcef_dll/ctocpp/views/textfield_ctocpp.h',
+ 'libcef_dll/cpptoc/views/textfield_delegate_cpptoc.cc',
+ 'libcef_dll/cpptoc/views/textfield_delegate_cpptoc.h',
+ 'libcef_dll/ctocpp/thread_ctocpp.cc',
+ 'libcef_dll/ctocpp/thread_ctocpp.h',
+ 'libcef_dll/ctocpp/test/translator_test_ctocpp.cc',
+ 'libcef_dll/ctocpp/test/translator_test_ctocpp.h',
+ 'libcef_dll/cpptoc/test/translator_test_ref_ptr_client_cpptoc.cc',
+ 'libcef_dll/cpptoc/test/translator_test_ref_ptr_client_cpptoc.h',
+ 'libcef_dll/cpptoc/test/translator_test_ref_ptr_client_child_cpptoc.cc',
+ 'libcef_dll/cpptoc/test/translator_test_ref_ptr_client_child_cpptoc.h',
+ 'libcef_dll/ctocpp/test/translator_test_ref_ptr_library_ctocpp.cc',
+ 'libcef_dll/ctocpp/test/translator_test_ref_ptr_library_ctocpp.h',
+ 'libcef_dll/ctocpp/test/translator_test_ref_ptr_library_child_ctocpp.cc',
+ 'libcef_dll/ctocpp/test/translator_test_ref_ptr_library_child_ctocpp.h',
+ 'libcef_dll/ctocpp/test/translator_test_ref_ptr_library_child_child_ctocpp.cc',
+ 'libcef_dll/ctocpp/test/translator_test_ref_ptr_library_child_child_ctocpp.h',
+ 'libcef_dll/cpptoc/test/translator_test_scoped_client_cpptoc.cc',
+ 'libcef_dll/cpptoc/test/translator_test_scoped_client_cpptoc.h',
+ 'libcef_dll/cpptoc/test/translator_test_scoped_client_child_cpptoc.cc',
+ 'libcef_dll/cpptoc/test/translator_test_scoped_client_child_cpptoc.h',
+ 'libcef_dll/ctocpp/test/translator_test_scoped_library_ctocpp.cc',
+ 'libcef_dll/ctocpp/test/translator_test_scoped_library_ctocpp.h',
+ 'libcef_dll/ctocpp/test/translator_test_scoped_library_child_ctocpp.cc',
+ 'libcef_dll/ctocpp/test/translator_test_scoped_library_child_ctocpp.h',
+ 'libcef_dll/ctocpp/test/translator_test_scoped_library_child_child_ctocpp.cc',
+ 'libcef_dll/ctocpp/test/translator_test_scoped_library_child_child_ctocpp.h',
+ 'libcef_dll/ctocpp/urlrequest_ctocpp.cc',
+ 'libcef_dll/ctocpp/urlrequest_ctocpp.h',
+ 'libcef_dll/cpptoc/urlrequest_client_cpptoc.cc',
+ 'libcef_dll/cpptoc/urlrequest_client_cpptoc.h',
+ 'libcef_dll/cpptoc/v8accessor_cpptoc.cc',
+ 'libcef_dll/cpptoc/v8accessor_cpptoc.h',
+ 'libcef_dll/cpptoc/v8array_buffer_release_callback_cpptoc.cc',
+ 'libcef_dll/cpptoc/v8array_buffer_release_callback_cpptoc.h',
+ 'libcef_dll/ctocpp/v8context_ctocpp.cc',
+ 'libcef_dll/ctocpp/v8context_ctocpp.h',
+ 'libcef_dll/ctocpp/v8exception_ctocpp.cc',
+ 'libcef_dll/ctocpp/v8exception_ctocpp.h',
+ 'libcef_dll/cpptoc/v8handler_cpptoc.cc',
+ 'libcef_dll/cpptoc/v8handler_cpptoc.h',
+ 'libcef_dll/cpptoc/v8interceptor_cpptoc.cc',
+ 'libcef_dll/cpptoc/v8interceptor_cpptoc.h',
+ 'libcef_dll/ctocpp/v8stack_frame_ctocpp.cc',
+ 'libcef_dll/ctocpp/v8stack_frame_ctocpp.h',
+ 'libcef_dll/ctocpp/v8stack_trace_ctocpp.cc',
+ 'libcef_dll/ctocpp/v8stack_trace_ctocpp.h',
+ 'libcef_dll/ctocpp/v8value_ctocpp.cc',
+ 'libcef_dll/ctocpp/v8value_ctocpp.h',
+ 'libcef_dll/ctocpp/value_ctocpp.cc',
+ 'libcef_dll/ctocpp/value_ctocpp.h',
+ 'libcef_dll/ctocpp/views/view_ctocpp.cc',
+ 'libcef_dll/ctocpp/views/view_ctocpp.h',
+ 'libcef_dll/cpptoc/views/view_delegate_cpptoc.cc',
+ 'libcef_dll/cpptoc/views/view_delegate_cpptoc.h',
+ 'libcef_dll/ctocpp/waitable_event_ctocpp.cc',
+ 'libcef_dll/ctocpp/waitable_event_ctocpp.h',
+ 'libcef_dll/ctocpp/views/window_ctocpp.cc',
+ 'libcef_dll/ctocpp/views/window_ctocpp.h',
+ 'libcef_dll/cpptoc/views/window_delegate_cpptoc.cc',
+ 'libcef_dll/cpptoc/views/window_delegate_cpptoc.h',
+ 'libcef_dll/cpptoc/write_handler_cpptoc.cc',
+ 'libcef_dll/cpptoc/write_handler_cpptoc.h',
+ 'libcef_dll/ctocpp/x509cert_principal_ctocpp.cc',
+ 'libcef_dll/ctocpp/x509cert_principal_ctocpp.h',
+ 'libcef_dll/ctocpp/x509certificate_ctocpp.cc',
+ 'libcef_dll/ctocpp/x509certificate_ctocpp.h',
+ 'libcef_dll/ctocpp/xml_reader_ctocpp.cc',
+ 'libcef_dll/ctocpp/xml_reader_ctocpp.h',
+ 'libcef_dll/ctocpp/zip_reader_ctocpp.cc',
+ 'libcef_dll/ctocpp/zip_reader_ctocpp.h',
+ ],
+ },
+}
diff --git a/cef_paths2.gypi b/cef_paths2.gypi
new file mode 100644
index 00000000..38718e4b
--- /dev/null
+++ b/cef_paths2.gypi
@@ -0,0 +1,663 @@
+# Copyright (c) 2011 The Chromium Embedded Framework Authors. All rights
+# reserved. Use of this source code is governed by a BSD-style license that
+# can be found in the LICENSE file.
+
+{
+ 'variables': {
+ 'includes_common': [
+ 'include/base/cef_atomic_flag.h',
+ 'include/base/cef_atomic_ref_count.h',
+ 'include/base/cef_auto_reset.h',
+ 'include/base/cef_basictypes.h',
+ 'include/base/cef_bind.h',
+ 'include/base/cef_build.h',
+ 'include/base/cef_callback.h',
+ 'include/base/cef_callback_forward.h',
+ 'include/base/cef_callback_helpers.h',
+ 'include/base/cef_callback_list.h',
+ 'include/base/cef_cancelable_callback.h',
+ 'include/base/cef_compiler_specific.h',
+ 'include/base/cef_lock.h',
+ 'include/base/cef_logging.h',
+ 'include/base/cef_macros.h',
+ 'include/base/cef_platform_thread.h',
+ 'include/base/cef_ptr_util.h',
+ 'include/base/cef_ref_counted.h',
+ 'include/base/cef_scoped_refptr.h',
+ 'include/base/cef_template_util.h',
+ 'include/base/cef_thread_checker.h',
+ 'include/base/cef_trace_event.h',
+ 'include/base/cef_tuple.h',
+ 'include/base/cef_weak_ptr.h',
+ 'include/base/internal/cef_bind_internal.h',
+ 'include/base/internal/cef_callback_internal.h',
+ 'include/base/internal/cef_lock_impl.h',
+ 'include/base/internal/cef_raw_scoped_refptr_mismatch_checker.h',
+ 'include/base/internal/cef_scoped_policy.h',
+ 'include/base/internal/cef_thread_checker_impl.h',
+ 'include/cef_api_hash.h',
+ 'include/cef_base.h',
+ 'include/cef_version.h',
+ 'include/internal/cef_export.h',
+ 'include/internal/cef_ptr.h',
+ 'include/internal/cef_string_wrappers.h',
+ 'include/internal/cef_time_wrappers.h',
+ 'include/internal/cef_types_wrappers.h',
+ ],
+ 'includes_common_capi': [
+ 'include/internal/cef_logging_internal.h',
+ 'include/internal/cef_string.h',
+ 'include/internal/cef_string_list.h',
+ 'include/internal/cef_string_map.h',
+ 'include/internal/cef_string_multimap.h',
+ 'include/internal/cef_string_types.h',
+ 'include/internal/cef_thread_internal.h',
+ 'include/internal/cef_time.h',
+ 'include/internal/cef_trace_event_internal.h',
+ 'include/internal/cef_types.h',
+ 'include/internal/cef_types_geometry.h',
+ ],
+ 'includes_capi': [
+ 'include/capi/cef_base_capi.h',
+ ],
+ 'includes_wrapper': [
+ 'include/wrapper/cef_byte_read_handler.h',
+ 'include/wrapper/cef_closure_task.h',
+ 'include/wrapper/cef_helpers.h',
+ 'include/wrapper/cef_message_router.h',
+ 'include/wrapper/cef_resource_manager.h',
+ 'include/wrapper/cef_scoped_temp_dir.h',
+ 'include/wrapper/cef_stream_resource_handler.h',
+ 'include/wrapper/cef_xml_object.h',
+ 'include/wrapper/cef_zip_archive.h',
+ ],
+ 'includes_wrapper_mac': [
+ 'include/wrapper/cef_library_loader.h',
+ ],
+ 'includes_win': [
+ 'include/cef_sandbox_win.h',
+ 'include/internal/cef_win.h',
+ ],
+ 'includes_win_capi': [
+ 'include/internal/cef_app_win.h',
+ 'include/internal/cef_types_win.h',
+ ],
+ 'includes_mac': [
+ 'include/base/cef_scoped_typeref_mac.h',
+ 'include/base/internal/cef_scoped_block_mac.h',
+ 'include/cef_application_mac.h',
+ 'include/cef_sandbox_mac.h',
+ 'include/internal/cef_mac.h',
+ ],
+ 'includes_mac_capi': [
+ 'include/internal/cef_types_mac.h',
+ ],
+ 'includes_linux': [
+ 'include/internal/cef_linux.h',
+ ],
+ 'includes_linux_capi': [
+ 'include/internal/cef_types_linux.h',
+ ],
+ 'libcef_sources_common': [
+ 'libcef_dll/cpptoc/cpptoc_ref_counted.h',
+ 'libcef_dll/cpptoc/cpptoc_scoped.h',
+ 'libcef_dll/ctocpp/base_ref_counted_ctocpp.cc',
+ 'libcef_dll/ctocpp/base_ref_counted_ctocpp.h',
+ 'libcef_dll/ctocpp/base_scoped_ctocpp.cc',
+ 'libcef_dll/ctocpp/base_scoped_ctocpp.h',
+ 'libcef_dll/ctocpp/ctocpp_ref_counted.h',
+ 'libcef_dll/ctocpp/ctocpp_scoped.h',
+ 'libcef_dll/libcef_dll.cc',
+ 'libcef_dll/libcef_dll2.cc',
+ 'libcef_dll/ptr_util.h',
+ 'libcef_dll/resource.h',
+ 'libcef_dll/shutdown_checker.cc',
+ 'libcef_dll/shutdown_checker.h',
+ 'libcef_dll/template_util.h',
+ 'libcef_dll/transfer_util.cc',
+ 'libcef_dll/transfer_util.h',
+ 'libcef_dll/wrapper_types.h',
+ ],
+ 'libcef_dll_wrapper_sources_base': [
+ 'libcef_dll/base/cef_atomic_flag.cc',
+ 'libcef_dll/base/cef_callback_helpers.cc',
+ 'libcef_dll/base/cef_callback_internal.cc',
+ 'libcef_dll/base/cef_lock.cc',
+ 'libcef_dll/base/cef_lock_impl.cc',
+ 'libcef_dll/base/cef_logging.cc',
+ 'libcef_dll/base/cef_ref_counted.cc',
+ 'libcef_dll/base/cef_thread_checker_impl.cc',
+ 'libcef_dll/base/cef_weak_ptr.cc',
+ ],
+ 'libcef_dll_wrapper_sources_common': [
+ 'libcef_dll/cpptoc/base_ref_counted_cpptoc.cc',
+ 'libcef_dll/cpptoc/base_ref_counted_cpptoc.h',
+ 'libcef_dll/cpptoc/base_scoped_cpptoc.cc',
+ 'libcef_dll/cpptoc/base_scoped_cpptoc.h',
+ 'libcef_dll/cpptoc/cpptoc_ref_counted.h',
+ 'libcef_dll/cpptoc/cpptoc_scoped.h',
+ 'libcef_dll/ctocpp/ctocpp_ref_counted.h',
+ 'libcef_dll/ctocpp/ctocpp_scoped.h',
+ 'libcef_dll/shutdown_checker.cc',
+ 'libcef_dll/shutdown_checker.h',
+ 'libcef_dll/template_util.h',
+ 'libcef_dll/transfer_util.cc',
+ 'libcef_dll/transfer_util.h',
+ 'libcef_dll/wrapper_types.h',
+ 'libcef_dll/wrapper/cef_browser_info_map.h',
+ 'libcef_dll/wrapper/cef_byte_read_handler.cc',
+ 'libcef_dll/wrapper/cef_closure_task.cc',
+ 'libcef_dll/wrapper/cef_message_router.cc',
+ 'libcef_dll/wrapper/cef_resource_manager.cc',
+ 'libcef_dll/wrapper/cef_scoped_temp_dir.cc',
+ 'libcef_dll/wrapper/cef_stream_resource_handler.cc',
+ 'libcef_dll/wrapper/cef_xml_object.cc',
+ 'libcef_dll/wrapper/cef_zip_archive.cc',
+ 'libcef_dll/wrapper/libcef_dll_wrapper.cc',
+ 'libcef_dll/wrapper/libcef_dll_wrapper2.cc',
+ ],
+ 'libcef_dll_wrapper_sources_mac': [
+ 'libcef_dll/wrapper/cef_library_loader_mac.mm',
+ 'libcef_dll/wrapper/libcef_dll_dylib.cc',
+ ],
+ 'shared_sources_browser': [
+ 'tests/shared/browser/client_app_browser.cc',
+ 'tests/shared/browser/client_app_browser.h',
+ 'tests/shared/browser/extension_util.cc',
+ 'tests/shared/browser/extension_util.h',
+ 'tests/shared/browser/file_util.cc',
+ 'tests/shared/browser/file_util.h',
+ 'tests/shared/browser/geometry_util.cc',
+ 'tests/shared/browser/geometry_util.h',
+ 'tests/shared/browser/main_message_loop.cc',
+ 'tests/shared/browser/main_message_loop.h',
+ 'tests/shared/browser/main_message_loop_external_pump.cc',
+ 'tests/shared/browser/main_message_loop_external_pump.h',
+ 'tests/shared/browser/main_message_loop_std.cc',
+ 'tests/shared/browser/main_message_loop_std.h',
+ 'tests/shared/browser/resource_util.h',
+ ],
+ 'shared_sources_common': [
+ 'tests/shared/common/binary_value_utils.cc',
+ 'tests/shared/common/binary_value_utils.h',
+ 'tests/shared/common/client_app.cc',
+ 'tests/shared/common/client_app.h',
+ 'tests/shared/common/client_app_other.cc',
+ 'tests/shared/common/client_app_other.h',
+ 'tests/shared/common/client_switches.cc',
+ 'tests/shared/common/client_switches.h',
+ 'tests/shared/common/string_util.cc',
+ 'tests/shared/common/string_util.h',
+ ],
+ 'shared_sources_renderer': [
+ 'tests/shared/renderer/client_app_renderer.cc',
+ 'tests/shared/renderer/client_app_renderer.h',
+ ],
+ 'shared_sources_resources': [
+ 'tests/shared/resources/osr_test.html',
+ 'tests/shared/resources/pdf.html',
+ 'tests/shared/resources/pdf.pdf',
+ 'tests/shared/resources/window_icon.1x.png',
+ 'tests/shared/resources/window_icon.2x.png',
+ ],
+ 'shared_sources_linux': [
+ 'tests/shared/browser/main_message_loop_external_pump_linux.cc',
+ 'tests/shared/browser/resource_util_posix.cc',
+ ],
+ 'shared_sources_mac': [
+ 'tests/shared/browser/main_message_loop_external_pump_mac.mm',
+ 'tests/shared/browser/resource_util_mac.mm',
+ 'tests/shared/browser/resource_util_posix.cc',
+ ],
+ 'shared_sources_mac_helper': [
+ 'tests/shared/process_helper_mac.cc',
+ ],
+ 'shared_sources_win': [
+ 'tests/shared/browser/main_message_loop_external_pump_win.cc',
+ 'tests/shared/browser/resource_util_win.cc',
+ 'tests/shared/browser/util_win.cc',
+ 'tests/shared/browser/util_win.h',
+ ],
+ 'cefclient_sources_browser': [
+ 'tests/cefclient/browser/binding_test.cc',
+ 'tests/cefclient/browser/binding_test.h',
+ 'tests/cefclient/browser/browser_window.cc',
+ 'tests/cefclient/browser/browser_window.h',
+ 'tests/cefclient/browser/bytes_write_handler.cc',
+ 'tests/cefclient/browser/bytes_write_handler.h',
+ 'tests/cefclient/browser/client_app_delegates_browser.cc',
+ 'tests/cefclient/browser/client_browser.cc',
+ 'tests/cefclient/browser/client_browser.h',
+ 'tests/cefclient/browser/client_handler.cc',
+ 'tests/cefclient/browser/client_handler.h',
+ 'tests/cefclient/browser/client_handler_osr.cc',
+ 'tests/cefclient/browser/client_handler_osr.h',
+ 'tests/cefclient/browser/client_handler_std.cc',
+ 'tests/cefclient/browser/client_handler_std.h',
+ 'tests/cefclient/browser/client_prefs.cc',
+ 'tests/cefclient/browser/client_prefs.h',
+ 'tests/cefclient/browser/client_types.h',
+ 'tests/cefclient/browser/default_client_handler.cc',
+ 'tests/cefclient/browser/default_client_handler.h',
+ 'tests/cefclient/browser/dialog_test.cc',
+ 'tests/cefclient/browser/dialog_test.h',
+ 'tests/cefclient/browser/image_cache.cc',
+ 'tests/cefclient/browser/image_cache.h',
+ 'tests/cefclient/browser/main_context.cc',
+ 'tests/cefclient/browser/main_context.h',
+ 'tests/cefclient/browser/main_context_impl.cc',
+ 'tests/cefclient/browser/main_context_impl.h',
+ 'tests/cefclient/browser/media_router_test.cc',
+ 'tests/cefclient/browser/media_router_test.h',
+ 'tests/cefclient/browser/osr_dragdrop_events.h',
+ 'tests/cefclient/browser/osr_renderer.h',
+ 'tests/cefclient/browser/osr_renderer.cc',
+ 'tests/cefclient/browser/osr_renderer_settings.h',
+ 'tests/cefclient/browser/preferences_test.cc',
+ 'tests/cefclient/browser/preferences_test.h',
+ 'tests/cefclient/browser/resource.h',
+ 'tests/cefclient/browser/response_filter_test.cc',
+ 'tests/cefclient/browser/response_filter_test.h',
+ 'tests/cefclient/browser/root_window.cc',
+ 'tests/cefclient/browser/root_window.h',
+ 'tests/cefclient/browser/root_window_create.cc',
+ 'tests/cefclient/browser/root_window_manager.cc',
+ 'tests/cefclient/browser/root_window_manager.h',
+ 'tests/cefclient/browser/root_window_views.cc',
+ 'tests/cefclient/browser/root_window_views.h',
+ 'tests/cefclient/browser/scheme_test.cc',
+ 'tests/cefclient/browser/scheme_test.h',
+ 'tests/cefclient/browser/server_test.cc',
+ 'tests/cefclient/browser/server_test.h',
+ 'tests/cefclient/browser/temp_window.h',
+ 'tests/cefclient/browser/test_runner.cc',
+ 'tests/cefclient/browser/test_runner.h',
+ 'tests/cefclient/browser/urlrequest_test.cc',
+ 'tests/cefclient/browser/urlrequest_test.h',
+ 'tests/cefclient/browser/views_menu_bar.cc',
+ 'tests/cefclient/browser/views_menu_bar.h',
+ 'tests/cefclient/browser/views_overlay_controls.cc',
+ 'tests/cefclient/browser/views_overlay_controls.h',
+ 'tests/cefclient/browser/views_style.cc',
+ 'tests/cefclient/browser/views_style.h',
+ 'tests/cefclient/browser/views_window.cc',
+ 'tests/cefclient/browser/views_window.h',
+ 'tests/cefclient/browser/window_test.cc',
+ 'tests/cefclient/browser/window_test.h',
+ 'tests/cefclient/browser/window_test_runner.cc',
+ 'tests/cefclient/browser/window_test_runner.h',
+ 'tests/cefclient/browser/window_test_runner_views.cc',
+ 'tests/cefclient/browser/window_test_runner_views.h',
+ ],
+ 'cefclient_sources_common': [
+ 'tests/cefclient/common/client_app_delegates_common.cc',
+ 'tests/cefclient/common/scheme_test_common.cc',
+ 'tests/cefclient/common/scheme_test_common.h',
+ ],
+ 'cefclient_sources_renderer': [
+ 'tests/cefclient/renderer/client_app_delegates_renderer.cc',
+ 'tests/cefclient/renderer/client_renderer.cc',
+ 'tests/cefclient/renderer/client_renderer.h',
+ 'tests/cefclient/renderer/ipc_performance_test.cc',
+ 'tests/cefclient/renderer/ipc_performance_test.h',
+ 'tests/cefclient/renderer/performance_test.cc',
+ 'tests/cefclient/renderer/performance_test.h',
+ 'tests/cefclient/renderer/performance_test_setup.h',
+ 'tests/cefclient/renderer/performance_test_tests.cc',
+ ],
+ 'cefclient_sources_resources': [
+ 'tests/cefclient/resources/binding.html',
+ 'tests/cefclient/resources/dialogs.html',
+ 'tests/cefclient/resources/draggable.html',
+ 'tests/cefclient/resources/ipc_performance.html',
+ 'tests/cefclient/resources/localstorage.html',
+ 'tests/cefclient/resources/logo.png',
+ 'tests/cefclient/resources/media_router.html',
+ 'tests/cefclient/resources/menu_icon.1x.png',
+ 'tests/cefclient/resources/menu_icon.2x.png',
+ 'tests/cefclient/resources/other_tests.html',
+ 'tests/cefclient/resources/performance.html',
+ 'tests/cefclient/resources/performance2.html',
+ 'tests/cefclient/resources/preferences.html',
+ 'tests/cefclient/resources/response_filter.html',
+ 'tests/cefclient/resources/server.html',
+ 'tests/cefclient/resources/transparency.html',
+ 'tests/cefclient/resources/urlrequest.html',
+ 'tests/cefclient/resources/websocket.html',
+ 'tests/cefclient/resources/window.html',
+ 'tests/cefclient/resources/xmlhttprequest.html',
+ ],
+ 'cefclient_sources_resources_extensions_set_page_color': [
+ 'tests/cefclient/resources/extensions/set_page_color/icon.png',
+ 'tests/cefclient/resources/extensions/set_page_color/manifest.json',
+ 'tests/cefclient/resources/extensions/set_page_color/popup.html',
+ 'tests/cefclient/resources/extensions/set_page_color/popup.js',
+ 'tests/cefclient/resources/extensions/set_page_color/README.md',
+ ],
+ 'cefclient_sources_win': [
+ 'tests/cefclient/browser/browser_window_osr_win.cc',
+ 'tests/cefclient/browser/browser_window_osr_win.h',
+ 'tests/cefclient/browser/browser_window_std_win.cc',
+ 'tests/cefclient/browser/browser_window_std_win.h',
+ 'tests/cefclient/browser/main_context_impl_win.cc',
+ 'tests/cefclient/browser/main_message_loop_multithreaded_win.cc',
+ 'tests/cefclient/browser/main_message_loop_multithreaded_win.h',
+ 'tests/cefclient/browser/osr_accessibility_helper.cc',
+ 'tests/cefclient/browser/osr_accessibility_helper.h',
+ 'tests/cefclient/browser/osr_accessibility_node.cc',
+ 'tests/cefclient/browser/osr_accessibility_node.h',
+ 'tests/cefclient/browser/osr_accessibility_node_win.cc',
+ 'tests/cefclient/browser/osr_dragdrop_win.cc',
+ 'tests/cefclient/browser/osr_dragdrop_win.h',
+ 'tests/cefclient/browser/osr_ime_handler_win.cc',
+ 'tests/cefclient/browser/osr_ime_handler_win.h',
+ 'tests/cefclient/browser/osr_d3d11_win.cc',
+ 'tests/cefclient/browser/osr_d3d11_win.h',
+ 'tests/cefclient/browser/osr_render_handler_win.cc',
+ 'tests/cefclient/browser/osr_render_handler_win.h',
+ 'tests/cefclient/browser/osr_render_handler_win_d3d11.cc',
+ 'tests/cefclient/browser/osr_render_handler_win_d3d11.h',
+ 'tests/cefclient/browser/osr_render_handler_win_gl.cc',
+ 'tests/cefclient/browser/osr_render_handler_win_gl.h',
+ 'tests/cefclient/browser/osr_window_win.cc',
+ 'tests/cefclient/browser/osr_window_win.h',
+ 'tests/cefclient/browser/resource_util_win_idmap.cc',
+ 'tests/cefclient/browser/root_window_win.cc',
+ 'tests/cefclient/browser/root_window_win.h',
+ 'tests/cefclient/browser/temp_window_win.cc',
+ 'tests/cefclient/browser/temp_window_win.h',
+ 'tests/cefclient/browser/window_test_runner_win.cc',
+ 'tests/cefclient/browser/window_test_runner_win.h',
+ 'tests/cefclient/cefclient_win.cc',
+ 'tests/cefclient/resources/win/cefclient.rc',
+ ],
+ 'cefclient_sources_resources_win': [
+ 'tests/cefclient/resources/win/cefclient.exe.manifest',
+ 'tests/cefclient/resources/win/cefclient.ico',
+ 'tests/cefclient/resources/win/small.ico',
+ ],
+ 'cefclient_sources_mac': [
+ 'tests/cefclient/browser/browser_window_osr_mac.h',
+ 'tests/cefclient/browser/browser_window_osr_mac.mm',
+ 'tests/cefclient/browser/browser_window_std_mac.h',
+ 'tests/cefclient/browser/browser_window_std_mac.mm',
+ 'tests/cefclient/browser/main_context_impl_posix.cc',
+ 'tests/cefclient/browser/osr_accessibility_helper.cc',
+ 'tests/cefclient/browser/osr_accessibility_helper.h',
+ 'tests/cefclient/browser/osr_accessibility_node.cc',
+ 'tests/cefclient/browser/osr_accessibility_node.h',
+ 'tests/cefclient/browser/osr_accessibility_node_mac.mm',
+ 'tests/cefclient/browser/root_window_mac.h',
+ 'tests/cefclient/browser/root_window_mac.mm',
+ 'tests/cefclient/browser/temp_window_mac.h',
+ 'tests/cefclient/browser/temp_window_mac.mm',
+ 'tests/cefclient/browser/text_input_client_osr_mac.h',
+ 'tests/cefclient/browser/text_input_client_osr_mac.mm',
+ 'tests/cefclient/browser/views_window_mac.mm',
+ 'tests/cefclient/browser/window_test_runner_mac.h',
+ 'tests/cefclient/browser/window_test_runner_mac.mm',
+ 'tests/cefclient/cefclient_mac.mm',
+ ],
+ 'cefclient_bundle_resources_mac': [
+ 'tests/cefclient/resources/mac/cefclient.icns',
+ 'tests/cefclient/resources/mac/English.lproj/InfoPlist.strings',
+ 'tests/cefclient/resources/mac/English.lproj/MainMenu.xib',
+ 'tests/cefclient/resources/mac/Info.plist',
+ ],
+ 'cefclient_sources_linux': [
+ 'tests/cefclient/browser/browser_window_osr_gtk.cc',
+ 'tests/cefclient/browser/browser_window_osr_gtk.h',
+ 'tests/cefclient/browser/browser_window_std_gtk.cc',
+ 'tests/cefclient/browser/browser_window_std_gtk.h',
+ 'tests/cefclient/browser/dialog_handler_gtk.cc',
+ 'tests/cefclient/browser/dialog_handler_gtk.h',
+ 'tests/cefclient/browser/main_context_impl_posix.cc',
+ 'tests/cefclient/browser/main_message_loop_multithreaded_gtk.cc',
+ 'tests/cefclient/browser/main_message_loop_multithreaded_gtk.h',
+ 'tests/cefclient/browser/print_handler_gtk.cc',
+ 'tests/cefclient/browser/print_handler_gtk.h',
+ 'tests/cefclient/browser/resource_util_linux.cc',
+ 'tests/cefclient/browser/root_window_gtk.cc',
+ 'tests/cefclient/browser/root_window_gtk.h',
+ 'tests/cefclient/browser/temp_window_x11.cc',
+ 'tests/cefclient/browser/temp_window_x11.h',
+ 'tests/cefclient/browser/util_gtk.cc',
+ 'tests/cefclient/browser/util_gtk.h',
+ 'tests/cefclient/browser/window_test_runner_gtk.cc',
+ 'tests/cefclient/browser/window_test_runner_gtk.h',
+ 'tests/cefclient/cefclient_gtk.cc',
+ ],
+ 'cefsimple_sources_common': [
+ 'tests/cefsimple/simple_app.cc',
+ 'tests/cefsimple/simple_app.h',
+ 'tests/cefsimple/simple_handler.cc',
+ 'tests/cefsimple/simple_handler.h',
+ ],
+ 'cefsimple_sources_win': [
+ 'tests/cefsimple/cefsimple.rc',
+ 'tests/cefsimple/cefsimple_win.cc',
+ 'tests/cefsimple/simple_handler_win.cc',
+ 'tests/cefsimple/resource.h',
+ ],
+ 'cefsimple_sources_resources_win': [
+ 'tests/cefsimple/cefsimple.exe.manifest',
+ 'tests/cefsimple/res/cefsimple.ico',
+ 'tests/cefsimple/res/small.ico',
+ ],
+ 'cefsimple_sources_mac': [
+ 'tests/cefsimple/cefsimple_mac.mm',
+ 'tests/cefsimple/simple_handler_mac.mm',
+ ],
+ 'cefsimple_sources_mac_helper': [
+ 'tests/cefsimple/process_helper_mac.cc',
+ ],
+ 'cefsimple_bundle_resources_mac': [
+ 'tests/cefsimple/mac/cefsimple.icns',
+ 'tests/cefsimple/mac/English.lproj/InfoPlist.strings',
+ 'tests/cefsimple/mac/English.lproj/MainMenu.xib',
+ 'tests/cefsimple/mac/Info.plist',
+ ],
+ 'cefsimple_sources_linux': [
+ 'tests/cefsimple/cefsimple_linux.cc',
+ 'tests/cefsimple/simple_handler_linux.cc',
+ ],
+ 'ceftests_data_resources': [
+ 'tests/ceftests/resources/net/data/ssl/certificates/expired_cert.pem',
+ 'tests/ceftests/resources/net/data/ssl/certificates/localhost_cert.pem',
+ 'tests/ceftests/resources/net/data/ssl/certificates/ok_cert.pem',
+ 'tests/ceftests/resources/net/data/ssl/certificates/root_ca_cert.pem',
+ ],
+ 'ceftests_sources_common': [
+ 'tests/ceftests/audio_output_unittest.cc',
+ 'tests/ceftests/browser_info_map_unittest.cc',
+ 'tests/ceftests/certificate_error_unittest.cc',
+ 'tests/ceftests/command_line_unittest.cc',
+ 'tests/ceftests/cookie_unittest.cc',
+ 'tests/ceftests/cors_unittest.cc',
+ 'tests/ceftests/devtools_message_unittest.cc',
+ 'tests/ceftests/dialog_unittest.cc',
+ 'tests/ceftests/display_unittest.cc',
+ 'tests/ceftests/dom_unittest.cc',
+ 'tests/ceftests/download_unittest.cc',
+ 'tests/ceftests/draggable_regions_unittest.cc',
+ 'tests/ceftests/extensions/background_unittest.cc',
+ 'tests/ceftests/extensions/chrome_alarms_unittest.cc',
+ 'tests/ceftests/extensions/chrome_storage_unittest.cc',
+ 'tests/ceftests/extensions/chrome_tabs_unittest.cc',
+ 'tests/ceftests/extensions/extension_test_handler.cc',
+ 'tests/ceftests/extensions/extension_test_handler.h',
+ 'tests/ceftests/extensions/view_unittest.cc',
+ 'tests/ceftests/file_util_unittest.cc',
+ 'tests/ceftests/frame_handler_unittest.cc',
+ 'tests/ceftests/frame_unittest.cc',
+ 'tests/ceftests/hsts_redirect_unittest.cc',
+ 'tests/ceftests/image_unittest.cc',
+ 'tests/ceftests/image_util.cc',
+ 'tests/ceftests/image_util.h',
+ 'tests/ceftests/jsdialog_unittest.cc',
+ 'tests/ceftests/life_span_unittest.cc',
+ 'tests/ceftests/media_access_unittest.cc',
+ 'tests/ceftests/message_router_harness_unittest.cc',
+ 'tests/ceftests/message_router_multi_query_unittest.cc',
+ 'tests/ceftests/message_router_single_query_unittest.cc',
+ 'tests/ceftests/message_router_threshold_unittest.cc',
+ 'tests/ceftests/message_router_unittest_utils.cc',
+ 'tests/ceftests/message_router_unittest_utils.h',
+ 'tests/ceftests/navigation_unittest.cc',
+ 'tests/ceftests/os_rendering_unittest.cc',
+ 'tests/ceftests/osr_accessibility_unittest.cc',
+ 'tests/ceftests/osr_display_unittest.cc',
+ 'tests/ceftests/parser_unittest.cc',
+ 'tests/ceftests/pdf_viewer_unittest.cc',
+ 'tests/ceftests/permission_prompt_unittest.cc',
+ 'tests/ceftests/preference_unittest.cc',
+ 'tests/ceftests/print_unittest.cc',
+ 'tests/ceftests/process_message_unittest.cc',
+ 'tests/ceftests/request_context_unittest.cc',
+ 'tests/ceftests/request_handler_unittest.cc',
+ 'tests/ceftests/request_unittest.cc',
+ 'tests/ceftests/response_unittest.cc',
+ 'tests/ceftests/resource.h',
+ 'tests/ceftests/resource_manager_unittest.cc',
+ 'tests/ceftests/resource_request_handler_unittest.cc',
+ 'tests/ceftests/routing_test_handler.cc',
+ 'tests/ceftests/routing_test_handler.h',
+ 'tests/ceftests/run_all_unittests.cc',
+ 'tests/ceftests/scheme_handler_unittest.cc',
+ 'tests/ceftests/scoped_temp_dir_unittest.cc',
+ 'tests/ceftests/server_unittest.cc',
+ 'tests/ceftests/send_shared_process_message_unittest.cc',
+ "tests/ceftests/shared_process_message_unittest.cc",
+ 'tests/ceftests/stream_unittest.cc',
+ 'tests/ceftests/stream_resource_handler_unittest.cc',
+ 'tests/ceftests/string_unittest.cc',
+ 'tests/ceftests/client_app_delegates.cc',
+ 'tests/ceftests/task_unittest.cc',
+ 'tests/ceftests/test_handler.cc',
+ 'tests/ceftests/test_handler.h',
+ 'tests/ceftests/test_request.cc',
+ 'tests/ceftests/test_request.h',
+ 'tests/ceftests/test_server.cc',
+ 'tests/ceftests/test_server.h',
+ 'tests/ceftests/test_server_observer.h',
+ 'tests/ceftests/test_server_observer.cc',
+ 'tests/ceftests/test_server_observer_unittest.cc',
+ 'tests/ceftests/test_server_manager.h',
+ 'tests/ceftests/test_server_manager.cc',
+ 'tests/ceftests/test_server_runner.h',
+ 'tests/ceftests/test_server_runner.cc',
+ 'tests/ceftests/test_server_runner_normal.cc',
+ 'tests/ceftests/test_server_runner_test.cc',
+ 'tests/ceftests/test_server_unittest.cc',
+ 'tests/ceftests/test_suite.cc',
+ 'tests/ceftests/test_suite.h',
+ 'tests/ceftests/test_util.cc',
+ 'tests/ceftests/test_util.h',
+ 'tests/ceftests/time_unittest.cc',
+ 'tests/ceftests/thread_helper.cc',
+ 'tests/ceftests/thread_helper.h',
+ 'tests/ceftests/thread_unittest.cc',
+ 'tests/ceftests/tracing_unittest.cc',
+ 'tests/ceftests/track_callback.h',
+ 'tests/ceftests/translator_unittest.cc',
+ 'tests/ceftests/urlrequest_unittest.cc',
+ 'tests/ceftests/v8_unittest.cc',
+ 'tests/ceftests/values_unittest.cc',
+ 'tests/ceftests/version_unittest.cc',
+ 'tests/ceftests/views/button_unittest.cc',
+ 'tests/ceftests/views/panel_unittest.cc',
+ 'tests/ceftests/views/scroll_view_unittest.cc',
+ 'tests/ceftests/views/test_window_delegate.cc',
+ 'tests/ceftests/views/test_window_delegate.h',
+ 'tests/ceftests/views/textfield_unittest.cc',
+ 'tests/ceftests/views/window_unittest.cc',
+ 'tests/ceftests/waitable_event_unittest.cc',
+ 'tests/ceftests/webui_unittest.cc',
+ 'tests/ceftests/xml_reader_unittest.cc',
+ 'tests/ceftests/zip_reader_unittest.cc',
+ ],
+ 'ceftests_sources_win': [
+ 'tests/ceftests/resource_util_win_dir.cc',
+ 'tests/ceftests/resource_util_win_idmap.cc',
+ 'tests/ceftests/resources/win/ceftests.rc',
+ ],
+ 'ceftests_sources_resources_win': [
+ 'tests/ceftests/resources/win/ceftests.exe.manifest',
+ 'tests/ceftests/resources/win/ceftests.ico',
+ 'tests/ceftests/resources/win/small.ico',
+ ],
+ 'ceftests_sources_mac': [
+ 'tests/ceftests/os_rendering_unittest_mac.h',
+ 'tests/ceftests/os_rendering_unittest_mac.mm',
+ 'tests/ceftests/run_all_unittests_mac.mm',
+ ],
+ 'ceftests_sources_mac_helper': [
+ 'tests/shared/browser/file_util.cc',
+ 'tests/shared/browser/file_util.h',
+ 'tests/shared/browser/resource_util.h',
+ 'tests/shared/browser/resource_util_mac.mm',
+ 'tests/shared/browser/resource_util_posix.cc',
+ 'tests/ceftests/audio_output_unittest.cc',
+ 'tests/ceftests/client_app_delegates.cc',
+ 'tests/ceftests/cookie_unittest.cc',
+ 'tests/ceftests/cors_unittest.cc',
+ 'tests/ceftests/dom_unittest.cc',
+ 'tests/ceftests/frame_unittest.cc',
+ 'tests/ceftests/media_access_unittest.cc',
+ 'tests/ceftests/message_router_harness_unittest.cc',
+ 'tests/ceftests/message_router_multi_query_unittest.cc',
+ 'tests/ceftests/message_router_single_query_unittest.cc',
+ 'tests/ceftests/message_router_threshold_unittest.cc',
+ 'tests/ceftests/message_router_unittest_utils.cc',
+ 'tests/ceftests/message_router_unittest_utils.h',
+ 'tests/ceftests/navigation_unittest.cc',
+ 'tests/ceftests/pdf_viewer_unittest.cc',
+ 'tests/ceftests/permission_prompt_unittest.cc',
+ 'tests/ceftests/preference_unittest.cc',
+ 'tests/ceftests/process_message_unittest.cc',
+ 'tests/ceftests/request_handler_unittest.cc',
+ 'tests/ceftests/request_unittest.cc',
+ 'tests/ceftests/response_unittest.cc',
+ 'tests/ceftests/resource_request_handler_unittest.cc',
+ 'tests/ceftests/routing_test_handler.cc',
+ 'tests/ceftests/routing_test_handler.h',
+ 'tests/ceftests/scheme_handler_unittest.cc',
+ 'tests/ceftests/send_shared_process_message_unittest.cc',
+ "tests/ceftests/shared_process_message_unittest.cc",
+ 'tests/ceftests/urlrequest_unittest.cc',
+ 'tests/ceftests/test_handler.cc',
+ 'tests/ceftests/test_handler.h',
+ 'tests/ceftests/test_request.cc',
+ 'tests/ceftests/test_request.h',
+ 'tests/ceftests/test_server.cc',
+ 'tests/ceftests/test_server.h',
+ 'tests/ceftests/test_server_observer.h',
+ 'tests/ceftests/test_server_observer.cc',
+ 'tests/ceftests/test_server_manager.h',
+ 'tests/ceftests/test_server_manager.cc',
+ 'tests/ceftests/test_server_runner.h',
+ 'tests/ceftests/test_server_runner.cc',
+ 'tests/ceftests/test_server_runner_normal.cc',
+ 'tests/ceftests/test_server_runner_test.cc',
+ 'tests/ceftests/test_suite.cc',
+ 'tests/ceftests/test_suite.h',
+ 'tests/ceftests/test_util.cc',
+ 'tests/ceftests/test_util.h',
+ 'tests/ceftests/track_callback.h',
+ 'tests/ceftests/thread_helper.cc',
+ 'tests/ceftests/thread_helper.h',
+ 'tests/ceftests/thread_unittest.cc',
+ 'tests/ceftests/tracing_unittest.cc',
+ 'tests/ceftests/v8_unittest.cc',
+ ],
+ 'ceftests_bundle_resources_mac': [
+ 'tests/ceftests/resources/mac/ceftests.icns',
+ 'tests/ceftests/resources/mac/English.lproj/InfoPlist.strings',
+ 'tests/ceftests/resources/mac/English.lproj/MainMenu.xib',
+ 'tests/ceftests/resources/mac/Info.plist',
+ ],
+ 'ceftests_sources_linux': [
+ 'tests/ceftests/resource_util_linux.cc',
+ ],
+ },
+}
diff --git a/cmake/FindCEF.cmake.in b/cmake/FindCEF.cmake.in
new file mode 100644
index 00000000..cd33a7dd
--- /dev/null
+++ b/cmake/FindCEF.cmake.in
@@ -0,0 +1,39 @@
+# Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights
+# reserved. Use of this source code is governed by a BSD-style license that
+# can be found in the LICENSE file.
+
+#
+# This file is the CEF CMake configuration entry point and should be loaded
+# using `find_package(CEF REQUIRED)`. See the top-level CMakeLists.txt file
+# included with the CEF binary distribution for usage information.
+#
+
+# Find the CEF binary distribution root directory.
+set(_CEF_ROOT "")
+if(CEF_ROOT AND IS_DIRECTORY "${CEF_ROOT}")
+ set(_CEF_ROOT "${CEF_ROOT}")
+ set(_CEF_ROOT_EXPLICIT 1)
+else()
+ set(_ENV_CEF_ROOT "")
+ if(DEFINED ENV{CEF_ROOT})
+ file(TO_CMAKE_PATH "$ENV{CEF_ROOT}" _ENV_CEF_ROOT)
+ endif()
+ if(_ENV_CEF_ROOT AND IS_DIRECTORY "${_ENV_CEF_ROOT}")
+ set(_CEF_ROOT "${_ENV_CEF_ROOT}")
+ set(_CEF_ROOT_EXPLICIT 1)
+ endif()
+ unset(_ENV_CEF_ROOT)
+endif()
+
+if(NOT DEFINED _CEF_ROOT_EXPLICIT)
+ message(FATAL_ERROR "Must specify a CEF_ROOT value via CMake or environment variable.")
+endif()
+
+if(NOT IS_DIRECTORY "${_CEF_ROOT}/cmake")
+ message(FATAL_ERROR "No CMake bootstrap found for CEF binary distribution at: ${CEF_ROOT}.")
+endif()
+
+# Execute additional cmake files from the CEF binary distribution.
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${_CEF_ROOT}/cmake")
+include("cef_variables")
+include("cef_macros")
diff --git a/cmake/cef_macros.cmake.in b/cmake/cef_macros.cmake.in
new file mode 100644
index 00000000..f357d06f
--- /dev/null
+++ b/cmake/cef_macros.cmake.in
@@ -0,0 +1,387 @@
+# Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights
+# reserved. Use of this source code is governed by a BSD-style license that
+# can be found in the LICENSE file.
+
+# Must be loaded via FindCEF.cmake.
+if(NOT DEFINED _CEF_ROOT_EXPLICIT)
+ message(FATAL_ERROR "Use find_package(CEF) to load this file.")
+endif()
+
+
+#
+# Shared macros.
+#
+
+# Print the current CEF configuration.
+macro(PRINT_CEF_CONFIG)
+ message(STATUS "*** CEF CONFIGURATION SETTINGS ***")
+ message(STATUS "Generator: ${CMAKE_GENERATOR}")
+ message(STATUS "Platform: ${CMAKE_SYSTEM_NAME}")
+ message(STATUS "Project architecture: ${PROJECT_ARCH}")
+
+ if(GEN_NINJA OR GEN_MAKEFILES)
+ message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
+ endif()
+
+ message(STATUS "Binary distribution root: ${_CEF_ROOT}")
+
+ if(OS_MAC)
+ message(STATUS "Base SDK: ${CMAKE_OSX_SYSROOT}")
+ message(STATUS "Target SDK: ${CEF_TARGET_SDK}")
+ endif()
+
+ if(OS_WINDOWS)
+ message(STATUS "Visual Studio ATL support: ${USE_ATL}")
+ endif()
+
+ message(STATUS "CEF sandbox: ${USE_SANDBOX}")
+
+ set(_libraries ${CEF_STANDARD_LIBS})
+ if(OS_WINDOWS AND USE_SANDBOX)
+ list(APPEND _libraries ${CEF_SANDBOX_STANDARD_LIBS})
+ endif()
+ message(STATUS "Standard libraries: ${_libraries}")
+
+ message(STATUS "Compile defines: ${CEF_COMPILER_DEFINES}")
+ message(STATUS "Compile defines (Debug): ${CEF_COMPILER_DEFINES_DEBUG}")
+ message(STATUS "Compile defines (Release): ${CEF_COMPILER_DEFINES_RELEASE}")
+ message(STATUS "C compile flags: ${CEF_COMPILER_FLAGS} ${CEF_C_COMPILER_FLAGS}")
+ message(STATUS "C compile flags (Debug): ${CEF_COMPILER_FLAGS_DEBUG} ${CEF_C_COMPILER_FLAGS_DEBUG}")
+ message(STATUS "C compile flags (Release): ${CEF_COMPILER_FLAGS_RELEASE} ${CEF_C_COMPILER_FLAGS_RELEASE}")
+ message(STATUS "C++ compile flags: ${CEF_COMPILER_FLAGS} ${CEF_CXX_COMPILER_FLAGS}")
+ message(STATUS "C++ compile flags (Debug): ${CEF_COMPILER_FLAGS_DEBUG} ${CEF_CXX_COMPILER_FLAGS_DEBUG}")
+ message(STATUS "C++ compile flags (Release): ${CEF_COMPILER_FLAGS_RELEASE} ${CEF_CXX_COMPILER_FLAGS_RELEASE}")
+ message(STATUS "Exe link flags: ${CEF_LINKER_FLAGS} ${CEF_EXE_LINKER_FLAGS}")
+ message(STATUS "Exe link flags (Debug): ${CEF_LINKER_FLAGS_DEBUG} ${CEF_EXE_LINKER_FLAGS_DEBUG}")
+ message(STATUS "Exe link flags (Release): ${CEF_LINKER_FLAGS_RELEASE} ${CEF_EXE_LINKER_FLAGS_RELEASE}")
+ message(STATUS "Shared link flags: ${CEF_LINKER_FLAGS} ${CEF_SHARED_LINKER_FLAGS}")
+ message(STATUS "Shared link flags (Debug): ${CEF_LINKER_FLAGS_DEBUG} ${CEF_SHARED_LINKER_FLAGS_DEBUG}")
+ message(STATUS "Shared link flags (Release): ${CEF_LINKER_FLAGS_RELEASE} ${CEF_SHARED_LINKER_FLAGS_RELEASE}")
+
+ if(OS_LINUX OR OS_WINDOWS)
+ message(STATUS "CEF Binary files: ${CEF_BINARY_FILES}")
+ message(STATUS "CEF Resource files: ${CEF_RESOURCE_FILES}")
+ endif()
+endmacro()
+
+# Append platform specific sources to a list of sources.
+macro(APPEND_PLATFORM_SOURCES name_of_list)
+ if(OS_LINUX AND ${name_of_list}_LINUX)
+ list(APPEND ${name_of_list} ${${name_of_list}_LINUX})
+ endif()
+ if(OS_POSIX AND ${name_of_list}_POSIX)
+ list(APPEND ${name_of_list} ${${name_of_list}_POSIX})
+ endif()
+ if(OS_WINDOWS AND ${name_of_list}_WINDOWS)
+ list(APPEND ${name_of_list} ${${name_of_list}_WINDOWS})
+ endif()
+ if(OS_MAC AND ${name_of_list}_MAC)
+ list(APPEND ${name_of_list} ${${name_of_list}_MAC})
+ endif()
+endmacro()
+
+# Determine the target output directory based on platform and generator.
+macro(SET_CEF_TARGET_OUT_DIR)
+ if(GEN_NINJA OR GEN_MAKEFILES)
+ # By default Ninja and Make builds don't create a subdirectory named after
+ # the configuration.
+ set(CEF_TARGET_OUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}")
+
+ # Output binaries (executables, libraries) to the correct directory.
+ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CEF_TARGET_OUT_DIR})
+ set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CEF_TARGET_OUT_DIR})
+ else()
+ set(CEF_TARGET_OUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIGURATION>")
+ endif()
+endmacro()
+
+# Copy a list of files from one directory to another. Relative file paths are maintained.
+macro(COPY_FILES target file_list source_dir target_dir)
+ foreach(FILENAME ${file_list})
+ set(source_file ${source_dir}/${FILENAME})
+
+ # Remove the target file path component.
+ get_filename_component(target_name ${FILENAME} NAME)
+ set(target_file ${target_dir}/${target_name})
+
+ COPY_SINGLE_FILE(${target} ${source_file} ${target_file})
+ endforeach()
+endmacro()
+
+# Copy a list of files from one directory to another. Relative file paths are maintained.
+macro(COPY_RESOURCES target file_list prefix_list source_dir target_dir)
+ foreach(FILENAME ${file_list})
+ set(source_file ${source_dir}/${FILENAME})
+
+ # Remove one or more prefixes from the source paths.
+ set(TARGET_FILENAME "${FILENAME}")
+ foreach(PREFIX ${prefix_list})
+ string(REGEX REPLACE "^.*${PREFIX}" "" TARGET_FILENAME ${TARGET_FILENAME})
+ endforeach()
+ set(target_file ${target_dir}/${TARGET_FILENAME})
+
+ COPY_SINGLE_FILE(${target} ${source_file} ${target_file})
+ endforeach()
+endmacro()
+
+macro(COPY_SINGLE_FILE target source_file target_file)
+ string(FIND ${source_file} "$<CONFIGURATION>" _pos)
+ if(NOT ${_pos} EQUAL -1)
+ # Must test with an actual configuration directory.
+ string(REPLACE "$<CONFIGURATION>" "Release" existing_source_file ${source_file})
+ if(NOT EXISTS ${existing_source_file})
+ string(REPLACE "$<CONFIGURATION>" "Debug" existing_source_file ${source_file})
+ endif()
+ else()
+ set(existing_source_file ${source_file})
+ endif()
+
+ if(IS_DIRECTORY ${existing_source_file})
+ add_custom_command(
+ TARGET ${target}
+ POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy_directory "${source_file}" "${target_file}"
+ VERBATIM
+ )
+ else()
+ add_custom_command(
+ TARGET ${target}
+ POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different "${source_file}" "${target_file}"
+ VERBATIM
+ )
+ endif()
+endmacro()
+
+
+#
+# Linux macros.
+#
+
+if(OS_LINUX)
+
+# Use pkg-config to find Linux libraries and update compiler/linker variables.
+macro(FIND_LINUX_LIBRARIES libraries)
+ # Read pkg-config info into variables.
+ execute_process(COMMAND pkg-config --cflags ${libraries} OUTPUT_VARIABLE FLL_CFLAGS)
+ execute_process(COMMAND pkg-config --libs-only-L --libs-only-other ${libraries} OUTPUT_VARIABLE FLL_LDFLAGS)
+ execute_process(COMMAND pkg-config --libs-only-l ${libraries} OUTPUT_VARIABLE FLL_LIBS)
+
+ # Strip leading and trailing whitepspace.
+ STRING(STRIP "${FLL_CFLAGS}" FLL_CFLAGS)
+ STRING(STRIP "${FLL_LDFLAGS}" FLL_LDFLAGS)
+ STRING(STRIP "${FLL_LIBS}" FLL_LIBS)
+
+ # Convert to a list.
+ separate_arguments(FLL_CFLAGS)
+ separate_arguments(FLL_LDFLAGS)
+ separate_arguments(FLL_LIBS)
+
+ # Update build variables.
+ list(APPEND CEF_C_COMPILER_FLAGS ${FLL_CFLAGS})
+ list(APPEND CEF_CXX_COMPILER_FLAGS ${FLL_CFLAGS})
+ list(APPEND CEF_EXE_LINKER_FLAGS ${FLL_LDFLAGS})
+ list(APPEND CEF_SHARED_LINKER_FLAGS ${FLL_LDFLAGS})
+ list(APPEND CEF_STANDARD_LIBS ${FLL_LIBS})
+endmacro()
+
+# Set SUID permissions on the specified executable.
+macro(SET_LINUX_SUID_PERMISSIONS target executable)
+ add_custom_command(
+ TARGET ${target}
+ POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E echo ""
+ COMMAND ${CMAKE_COMMAND} -E echo "*** Run the following command manually to set SUID permissions ***"
+ COMMAND ${CMAKE_COMMAND} -E echo "EXE=\"${executable}\" && sudo -- chown root:root $EXE && sudo -- chmod 4755 $EXE"
+ COMMAND ${CMAKE_COMMAND} -E echo ""
+ VERBATIM
+ )
+endmacro()
+
+endif(OS_LINUX)
+
+
+#
+# Mac OS X macros.
+#
+
+if(OS_MAC)
+
+# Manually process and copy over resource files.
+macro(COPY_MAC_RESOURCES resource_list prefix_list target source_dir app_path)
+ foreach(FILENAME ${resource_list})
+ # Remove one or more prefixes from the source paths.
+ set(TARGET_FILENAME "${FILENAME}")
+ foreach(PREFIX ${prefix_list})
+ string(REGEX REPLACE "^.*${PREFIX}" "" TARGET_FILENAME ${TARGET_FILENAME})
+ endforeach()
+
+ # Determine the absolute source and target paths.
+ set(TARGET_PATH "${app_path}/Contents/Resources/${TARGET_FILENAME}")
+ if(IS_ABSOLUTE ${FILENAME})
+ set(SOURCE_PATH ${FILENAME})
+ else()
+ set(SOURCE_PATH "${source_dir}/${FILENAME}")
+ endif()
+
+ if(${FILENAME} MATCHES ".xib$")
+ # Change the target file extension.
+ string(REGEX REPLACE ".xib$" ".nib" TARGET_PATH ${TARGET_PATH})
+
+ get_filename_component(TARGET_DIRECTORY ${TARGET_PATH} PATH)
+ add_custom_command(
+ TARGET ${target}
+ POST_BUILD
+ # Create the target directory.
+ COMMAND ${CMAKE_COMMAND} -E make_directory "${TARGET_DIRECTORY}"
+ # Compile the XIB file to a NIB.
+ COMMAND /usr/bin/ibtool --output-format binary1 --compile "${TARGET_PATH}" "${SOURCE_PATH}"
+ VERBATIM
+ )
+ elseif(NOT ${TARGET_FILENAME} STREQUAL "Info.plist")
+ # Copy the file as-is.
+ add_custom_command(
+ TARGET ${target}
+ POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy "${SOURCE_PATH}" "${TARGET_PATH}"
+ VERBATIM
+ )
+ endif()
+ endforeach()
+endmacro()
+
+endif(OS_MAC)
+
+
+#
+# Windows macros.
+#
+
+if(OS_WINDOWS)
+
+# Add custom manifest files to an executable target.
+macro(ADD_WINDOWS_MANIFEST manifest_path target extension)
+ add_custom_command(
+ TARGET ${target}
+ POST_BUILD
+ COMMAND "mt.exe" -nologo
+ -manifest \"${manifest_path}/${target}.${extension}.manifest\" \"${manifest_path}/compatibility.manifest\"
+ -outputresource:"${CEF_TARGET_OUT_DIR}/${target}.${extension}"\;\#1
+ COMMENT "Adding manifest..."
+ )
+endmacro()
+
+endif(OS_WINDOWS)
+
+
+#
+# Target configuration macros.
+#
+
+# Add a logical target that can be used to link the specified libraries into an
+# executable target.
+macro(ADD_LOGICAL_TARGET target debug_lib release_lib)
+ add_library(${target} ${CEF_LIBTYPE} IMPORTED)
+ set_target_properties(${target} PROPERTIES
+ IMPORTED_LOCATION "${release_lib}"
+ IMPORTED_LOCATION_DEBUG "${debug_lib}"
+ IMPORTED_LOCATION_RELEASE "${release_lib}"
+ )
+endmacro()
+
+# Set common target properties. Use SET_LIBRARY_TARGET_PROPERTIES() or
+# SET_EXECUTABLE_TARGET_PROPERTIES() instead of calling this macro directly.
+macro(SET_COMMON_TARGET_PROPERTIES target)
+ # Compile flags.
+ target_compile_options(${target} PRIVATE ${CEF_COMPILER_FLAGS} ${CEF_CXX_COMPILER_FLAGS})
+ target_compile_options(${target} PRIVATE $<$<CONFIG:Debug>:${CEF_COMPILER_FLAGS_DEBUG} ${CEF_CXX_COMPILER_FLAGS_DEBUG}>)
+ target_compile_options(${target} PRIVATE $<$<CONFIG:Release>:${CEF_COMPILER_FLAGS_RELEASE} ${CEF_CXX_COMPILER_FLAGS_RELEASE}>)
+
+ # Compile definitions.
+ target_compile_definitions(${target} PRIVATE ${CEF_COMPILER_DEFINES})
+ target_compile_definitions(${target} PRIVATE $<$<CONFIG:Debug>:${CEF_COMPILER_DEFINES_DEBUG}>)
+ target_compile_definitions(${target} PRIVATE $<$<CONFIG:Release>:${CEF_COMPILER_DEFINES_RELEASE}>)
+
+ # Include directories.
+ target_include_directories(${target} PRIVATE ${CEF_INCLUDE_PATH})
+
+ # Linker flags.
+ if(CEF_LINKER_FLAGS)
+ string(REPLACE ";" " " _flags_str "${CEF_LINKER_FLAGS}")
+ set_property(TARGET ${target} PROPERTY LINK_FLAGS ${_flags_str})
+ endif()
+ if(CEF_LINKER_FLAGS_DEBUG)
+ string(REPLACE ";" " " _flags_str "${CEF_LINKER_FLAGS_DEBUG}")
+ set_property(TARGET ${target} PROPERTY LINK_FLAGS_DEBUG ${_flags_str})
+ endif()
+ if(CEF_LINKER_FLAGS_RELEASE)
+ string(REPLACE ";" " " _flags_str "${CEF_LINKER_FLAGS_RELEASE}")
+ set_property(TARGET ${target} PROPERTY LINK_FLAGS_RELEASE ${_flags_str})
+ endif()
+
+ if(OS_MAC)
+ # Set Xcode target properties.
+ set_target_properties(${target} PROPERTIES
+ XCODE_ATTRIBUTE_ALWAYS_SEARCH_USER_PATHS NO
+ XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "gnu++11" # -std=gnu++11
+ XCODE_ATTRIBUTE_CLANG_LINK_OBJC_RUNTIME NO # -fno-objc-link-runtime
+ XCODE_ATTRIBUTE_CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS YES # -Wobjc-missing-property-synthesis
+ XCODE_ATTRIBUTE_COPY_PHASE_STRIP NO
+ XCODE_ATTRIBUTE_DEAD_CODE_STRIPPING[variant=Release] YES # -Wl,-dead_strip
+ XCODE_ATTRIBUTE_GCC_C_LANGUAGE_STANDARD "c99" # -std=c99
+ XCODE_ATTRIBUTE_GCC_CW_ASM_SYNTAX NO # No -fasm-blocks
+ XCODE_ATTRIBUTE_GCC_DYNAMIC_NO_PIC NO
+ XCODE_ATTRIBUTE_GCC_ENABLE_CPP_EXCEPTIONS NO # -fno-exceptions
+ XCODE_ATTRIBUTE_GCC_ENABLE_CPP_RTTI NO # -fno-rtti
+ XCODE_ATTRIBUTE_GCC_ENABLE_PASCAL_STRINGS NO # No -mpascal-strings
+ XCODE_ATTRIBUTE_GCC_INLINES_ARE_PRIVATE_EXTERN YES # -fvisibility-inlines-hidden
+ XCODE_ATTRIBUTE_GCC_OBJC_CALL_CXX_CDTORS YES # -fobjc-call-cxx-cdtors
+ XCODE_ATTRIBUTE_GCC_SYMBOLS_PRIVATE_EXTERN YES # -fvisibility=hidden
+ XCODE_ATTRIBUTE_GCC_THREADSAFE_STATICS NO # -fno-threadsafe-statics
+ XCODE_ATTRIBUTE_GCC_TREAT_WARNINGS_AS_ERRORS YES # -Werror
+ XCODE_ATTRIBUTE_GCC_VERSION "com.apple.compilers.llvm.clang.1_0"
+ XCODE_ATTRIBUTE_GCC_WARN_ABOUT_MISSING_NEWLINE YES # -Wnewline-eof
+ XCODE_ATTRIBUTE_USE_HEADERMAP NO
+ OSX_ARCHITECTURES_DEBUG "${CMAKE_OSX_ARCHITECTURES}"
+ OSX_ARCHITECTURES_RELEASE "${CMAKE_OSX_ARCHITECTURES}"
+ )
+ endif()
+endmacro()
+
+# Set library-specific properties.
+macro(SET_LIBRARY_TARGET_PROPERTIES target)
+ SET_COMMON_TARGET_PROPERTIES(${target})
+
+ # Shared library linker flags.
+ if(CEF_SHARED_LINKER_FLAGS)
+ string(REPLACE ";" " " _flags_str "${CEF_SHARED_LINKER_FLAGS}")
+ set_property(TARGET ${target} PROPERTY LINK_FLAGS ${_flags_str})
+ endif()
+ if(CEF_SHARED_LINKER_FLAGS_DEBUG)
+ string(REPLACE ";" " " _flags_str "${CEF_SHARED_LINKER_FLAGS_DEBUG}")
+ set_property(TARGET ${target} PROPERTY LINK_FLAGS_DEBUG ${_flags_str})
+ endif()
+ if(CEF_SHARED_LINKER_FLAGS_RELEASE)
+ string(REPLACE ";" " " _flags_str "${CEF_SHARED_LINKER_FLAGS_RELEASE}")
+ set_property(TARGET ${target} PROPERTY LINK_FLAGS_RELEASE ${_flags_str})
+ endif()
+endmacro()
+
+# Set executable-specific properties.
+macro(SET_EXECUTABLE_TARGET_PROPERTIES target)
+ SET_COMMON_TARGET_PROPERTIES(${target})
+
+ # Executable linker flags.
+ if(CEF_EXE_LINKER_FLAGS)
+ string(REPLACE ";" " " _flags_str "${CEF_EXE_LINKER_FLAGS}")
+ set_property(TARGET ${target} PROPERTY LINK_FLAGS ${_flags_str})
+ endif()
+ if(CEF_EXE_LINKER_FLAGS_DEBUG)
+ string(REPLACE ";" " " _flags_str "${CEF_EXE_LINKER_FLAGS_DEBUG}")
+ set_property(TARGET ${target} PROPERTY LINK_FLAGS_DEBUG ${_flags_str})
+ endif()
+ if(CEF_EXE_LINKER_FLAGS_RELEASE)
+ string(REPLACE ";" " " _flags_str "${CEF_EXE_LINKER_FLAGS_RELEASE}")
+ set_property(TARGET ${target} PROPERTY LINK_FLAGS_RELEASE ${_flags_str})
+ endif()
+endmacro()
diff --git a/cmake/cef_variables.cmake.in b/cmake/cef_variables.cmake.in
new file mode 100644
index 00000000..fc329321
--- /dev/null
+++ b/cmake/cef_variables.cmake.in
@@ -0,0 +1,584 @@
+# Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights
+# reserved. Use of this source code is governed by a BSD-style license that
+# can be found in the LICENSE file.
+
+# Must be loaded via FindCEF.cmake.
+if(NOT DEFINED _CEF_ROOT_EXPLICIT)
+ message(FATAL_ERROR "Use find_package(CEF) to load this file.")
+endif()
+
+
+#
+# Shared configuration.
+#
+
+# Determine the platform.
+if("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin")
+ set(OS_MAC 1)
+ set(OS_MACOSX 1) # For backwards compatibility.
+ set(OS_POSIX 1)
+elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
+ set(OS_LINUX 1)
+ set(OS_POSIX 1)
+elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Windows")
+ set(OS_WINDOWS 1)
+endif()
+
+# Determine the project architecture.
+if(NOT DEFINED PROJECT_ARCH)
+ if(("${CMAKE_HOST_SYSTEM_PROCESSOR}" STREQUAL "arm64") OR
+ ("${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}" STREQUAL "ARM64"))
+ set(PROJECT_ARCH "arm64")
+ elseif(CMAKE_SIZEOF_VOID_P MATCHES 8)
+ set(PROJECT_ARCH "x86_64")
+ else()
+ set(PROJECT_ARCH "x86")
+ endif()
+endif()
+
+if(${CMAKE_GENERATOR} STREQUAL "Ninja")
+ set(GEN_NINJA 1)
+elseif(${CMAKE_GENERATOR} STREQUAL "Unix Makefiles")
+ set(GEN_MAKEFILES 1)
+endif()
+
+# Determine the build type.
+if(NOT CMAKE_BUILD_TYPE AND (GEN_NINJA OR GEN_MAKEFILES))
+ # CMAKE_BUILD_TYPE should be specified when using Ninja or Unix Makefiles.
+ set(CMAKE_BUILD_TYPE Release)
+ message(WARNING "No CMAKE_BUILD_TYPE value selected, using ${CMAKE_BUILD_TYPE}")
+endif()
+
+
+# Path to the include directory.
+set(CEF_INCLUDE_PATH "${_CEF_ROOT}")
+
+# Path to the libcef_dll_wrapper target.
+set(CEF_LIBCEF_DLL_WRAPPER_PATH "${_CEF_ROOT}/libcef_dll")
+
+
+# Shared compiler/linker flags.
+list(APPEND CEF_COMPILER_DEFINES
+ # Allow C++ programs to use stdint.h macros specified in the C99 standard that aren't
+ # in the C++ standard (e.g. UINT8_MAX, INT64_MIN, etc)
+ __STDC_CONSTANT_MACROS __STDC_FORMAT_MACROS
+ )
+
+
+# Configure use of the sandbox.
+option(USE_SANDBOX "Enable or disable use of the sandbox." ON)
+
+
+#
+# Linux configuration.
+#
+
+if(OS_LINUX)
+ # Platform-specific compiler/linker flags.
+ set(CEF_LIBTYPE SHARED)
+ list(APPEND CEF_COMPILER_FLAGS
+ -fno-strict-aliasing # Avoid assumptions regarding non-aliasing of objects of different types
+ -fPIC # Generate position-independent code for shared libraries
+ -fstack-protector # Protect some vulnerable functions from stack-smashing (security feature)
+ -funwind-tables # Support stack unwinding for backtrace()
+ -fvisibility=hidden # Give hidden visibility to declarations that are not explicitly marked as visible
+ --param=ssp-buffer-size=4 # Set the minimum buffer size protected by SSP (security feature, related to stack-protector)
+ -pipe # Use pipes rather than temporary files for communication between build stages
+ -pthread # Use the pthread library
+ -Wall # Enable all warnings
+ -Werror # Treat warnings as errors
+ -Wno-missing-field-initializers # Don't warn about missing field initializers
+ -Wno-unused-parameter # Don't warn about unused parameters
+ -Wno-error=comment # Don't warn about code in comments
+ -Wno-comment # Don't warn about code in comments
+ -Wno-deprecated-declarations # Don't warn about using deprecated methods
+ )
+ list(APPEND CEF_C_COMPILER_FLAGS
+ -std=c99 # Use the C99 language standard
+ )
+ list(APPEND CEF_CXX_COMPILER_FLAGS
+ -fno-exceptions # Disable exceptions
+ -fno-rtti # Disable real-time type information
+ -fno-threadsafe-statics # Don't generate thread-safe statics
+ -fvisibility-inlines-hidden # Give hidden visibility to inlined class member functions
+ -std=c++17 # Use the C++17 language standard
+ -Wsign-compare # Warn about mixed signed/unsigned type comparisons
+ )
+ list(APPEND CEF_COMPILER_FLAGS_DEBUG
+ -O0 # Disable optimizations
+ -g # Generate debug information
+ )
+ list(APPEND CEF_COMPILER_FLAGS_RELEASE
+ -O2 # Optimize for maximum speed
+ -fdata-sections # Enable linker optimizations to improve locality of reference for data sections
+ -ffunction-sections # Enable linker optimizations to improve locality of reference for function sections
+ -fno-ident # Ignore the #ident directive
+ -U_FORTIFY_SOURCE # Undefine _FORTIFY_SOURCE in case it was previously defined
+ -D_FORTIFY_SOURCE=2 # Add memory and string function protection (security feature, related to stack-protector)
+ )
+ list(APPEND CEF_LINKER_FLAGS
+ -fPIC # Generate position-independent code for shared libraries
+ -pthread # Use the pthread library
+ -Wl,--disable-new-dtags # Don't generate new-style dynamic tags in ELF
+ -Wl,--fatal-warnings # Treat warnings as errors
+ -Wl,-rpath,. # Set rpath so that libraries can be placed next to the executable
+ -Wl,-z,noexecstack # Mark the stack as non-executable (security feature)
+ -Wl,-z,now # Resolve symbols on program start instead of on first use (security feature)
+ -Wl,-z,relro # Mark relocation sections as read-only (security feature)
+ )
+ list(APPEND CEF_LINKER_FLAGS_RELEASE
+ -Wl,-O1 # Enable linker optimizations
+ -Wl,--as-needed # Only link libraries that export symbols used by the binary
+ -Wl,--gc-sections # Remove unused code resulting from -fdata-sections and -function-sections
+ )
+ list(APPEND CEF_COMPILER_DEFINES
+ _FILE_OFFSET_BITS=64 # Allow the Large File Support (LFS) interface to replace the old interface
+ )
+ list(APPEND CEF_COMPILER_DEFINES_RELEASE
+ NDEBUG # Not a debug build
+ )
+
+ include(CheckCCompilerFlag)
+ include(CheckCXXCompilerFlag)
+
+ CHECK_CXX_COMPILER_FLAG(-Wno-undefined-var-template COMPILER_SUPPORTS_NO_UNDEFINED_VAR_TEMPLATE)
+ if(COMPILER_SUPPORTS_NO_UNDEFINED_VAR_TEMPLATE)
+ list(APPEND CEF_CXX_COMPILER_FLAGS
+ -Wno-undefined-var-template # Don't warn about potentially uninstantiated static members
+ )
+ endif()
+
+ CHECK_C_COMPILER_FLAG(-Wno-unused-local-typedefs COMPILER_SUPPORTS_NO_UNUSED_LOCAL_TYPEDEFS)
+ if(COMPILER_SUPPORTS_NO_UNUSED_LOCAL_TYPEDEFS)
+ list(APPEND CEF_C_COMPILER_FLAGS
+ -Wno-unused-local-typedefs # Don't warn about unused local typedefs
+ )
+ endif()
+
+ CHECK_CXX_COMPILER_FLAG(-Wno-literal-suffix COMPILER_SUPPORTS_NO_LITERAL_SUFFIX)
+ if(COMPILER_SUPPORTS_NO_LITERAL_SUFFIX)
+ list(APPEND CEF_CXX_COMPILER_FLAGS
+ -Wno-literal-suffix # Don't warn about invalid suffixes on literals
+ )
+ endif()
+
+ CHECK_CXX_COMPILER_FLAG(-Wno-narrowing COMPILER_SUPPORTS_NO_NARROWING)
+ if(COMPILER_SUPPORTS_NO_NARROWING)
+ list(APPEND CEF_CXX_COMPILER_FLAGS
+ -Wno-narrowing # Don't warn about type narrowing
+ )
+ endif()
+
+ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
+ list(APPEND CEF_CXX_COMPILER_FLAGS
+ -Wno-attributes # The cfi-icall attribute is not supported by the GNU C++ compiler
+ )
+ endif()
+
+ if(PROJECT_ARCH STREQUAL "x86_64")
+ # 64-bit architecture.
+ list(APPEND CEF_COMPILER_FLAGS
+ -m64
+ -march=x86-64
+ )
+ list(APPEND CEF_LINKER_FLAGS
+ -m64
+ )
+ elseif(PROJECT_ARCH STREQUAL "x86")
+ # 32-bit architecture.
+ list(APPEND CEF_COMPILER_FLAGS
+ -msse2
+ -mfpmath=sse
+ -mmmx
+ -m32
+ )
+ list(APPEND CEF_LINKER_FLAGS
+ -m32
+ )
+ endif()
+
+ # Standard libraries.
+ set(CEF_STANDARD_LIBS
+ X11
+ )
+
+ # CEF directory paths.
+ set(CEF_RESOURCE_DIR "${_CEF_ROOT}/Resources")
+ set(CEF_BINARY_DIR "${_CEF_ROOT}/${CMAKE_BUILD_TYPE}")
+ set(CEF_BINARY_DIR_DEBUG "${_CEF_ROOT}/Debug")
+ set(CEF_BINARY_DIR_RELEASE "${_CEF_ROOT}/Release")
+
+ # CEF library paths.
+ set(CEF_LIB_DEBUG "${CEF_BINARY_DIR_DEBUG}/libcef.so")
+ set(CEF_LIB_RELEASE "${CEF_BINARY_DIR_RELEASE}/libcef.so")
+
+ # List of CEF binary files.
+ set(CEF_BINARY_FILES
+ chrome-sandbox
+ libcef.so
+ libEGL.so
+ libGLESv2.so
+ libvk_swiftshader.so
+ libvulkan.so.1
+ snapshot_blob.bin
+ v8_context_snapshot.bin
+ vk_swiftshader_icd.json
+ )
+
+ # List of CEF resource files.
+ set(CEF_RESOURCE_FILES
+ chrome_100_percent.pak
+ chrome_200_percent.pak
+ resources.pak
+ icudtl.dat
+ locales
+ )
+
+ if(USE_SANDBOX)
+ list(APPEND CEF_COMPILER_DEFINES
+ CEF_USE_SANDBOX # Used by apps to test if the sandbox is enabled
+ )
+ endif()
+endif()
+
+
+#
+# Mac OS X configuration.
+#
+
+if(OS_MAC)
+ # Platform-specific compiler/linker flags.
+ # See also Xcode target properties in cef_macros.cmake.
+ set(CEF_LIBTYPE SHARED)
+ list(APPEND CEF_COMPILER_FLAGS
+ -fno-strict-aliasing # Avoid assumptions regarding non-aliasing of objects of different types
+ -fstack-protector # Protect some vulnerable functions from stack-smashing (security feature)
+ -funwind-tables # Support stack unwinding for backtrace()
+ -fvisibility=hidden # Give hidden visibility to declarations that are not explicitly marked as visible
+ -Wall # Enable all warnings
+ -Werror # Treat warnings as errors
+ -Wextra # Enable additional warnings
+ -Wendif-labels # Warn whenever an #else or an #endif is followed by text
+ -Wnewline-eof # Warn about no newline at end of file
+ -Wno-missing-field-initializers # Don't warn about missing field initializers
+ -Wno-unused-parameter # Don't warn about unused parameters
+ )
+ list(APPEND CEF_C_COMPILER_FLAGS
+ -std=c99 # Use the C99 language standard
+ )
+ list(APPEND CEF_CXX_COMPILER_FLAGS
+ -fno-exceptions # Disable exceptions
+ -fno-rtti # Disable real-time type information
+ -fno-threadsafe-statics # Don't generate thread-safe statics
+ -fobjc-call-cxx-cdtors # Call the constructor/destructor of C++ instance variables in ObjC objects
+ -fvisibility-inlines-hidden # Give hidden visibility to inlined class member functions
+ -std=c++17 # Use the C++17 language standard
+ -Wno-narrowing # Don't warn about type narrowing
+ -Wsign-compare # Warn about mixed signed/unsigned type comparisons
+ )
+ list(APPEND CEF_COMPILER_FLAGS_DEBUG
+ -O0 # Disable optimizations
+ -g # Generate debug information
+ )
+ list(APPEND CEF_COMPILER_FLAGS_RELEASE
+ -O3 # Optimize for maximum speed plus a few extras
+ )
+ list(APPEND CEF_LINKER_FLAGS
+ -Wl,-search_paths_first # Search for static or shared library versions in the same pass
+ -Wl,-ObjC # Support creation of ObjC static libraries
+ -Wl,-pie # Generate position-independent code suitable for executables only
+ )
+ list(APPEND CEF_LINKER_FLAGS_RELEASE
+ -Wl,-dead_strip # Strip dead code
+ )
+
+ include(CheckCXXCompilerFlag)
+
+ CHECK_CXX_COMPILER_FLAG(-Wno-undefined-var-template COMPILER_SUPPORTS_NO_UNDEFINED_VAR_TEMPLATE)
+ if(COMPILER_SUPPORTS_NO_UNDEFINED_VAR_TEMPLATE)
+ list(APPEND CEF_CXX_COMPILER_FLAGS
+ -Wno-undefined-var-template # Don't warn about potentially uninstantiated static members
+ )
+ endif()
+
+ # Standard libraries.
+ set(CEF_STANDARD_LIBS
+ -lpthread
+ "-framework Cocoa"
+ "-framework AppKit"
+ )
+
+ # Find the newest available base SDK.
+ execute_process(COMMAND xcode-select --print-path OUTPUT_VARIABLE XCODE_PATH OUTPUT_STRIP_TRAILING_WHITESPACE)
+ foreach(OS_VERSION 10.15 10.14 10.13)
+ set(SDK "${XCODE_PATH}/Platforms/MacOSX.platform/Developer/SDKs/MacOSX${OS_VERSION}.sdk")
+ if(NOT "${CMAKE_OSX_SYSROOT}" AND EXISTS "${SDK}" AND IS_DIRECTORY "${SDK}")
+ set(CMAKE_OSX_SYSROOT ${SDK})
+ endif()
+ endforeach()
+
+ # Target SDK.
+ set(CEF_TARGET_SDK "10.13")
+ list(APPEND CEF_COMPILER_FLAGS
+ -mmacosx-version-min=${CEF_TARGET_SDK}
+ )
+ set(CMAKE_OSX_DEPLOYMENT_TARGET ${CEF_TARGET_SDK})
+
+ # Target architecture.
+ if(PROJECT_ARCH STREQUAL "x86_64")
+ set(CMAKE_OSX_ARCHITECTURES "x86_64")
+ elseif(PROJECT_ARCH STREQUAL "arm64")
+ set(CMAKE_OSX_ARCHITECTURES "arm64")
+ else()
+ set(CMAKE_OSX_ARCHITECTURES "i386")
+ endif()
+
+ # Prevent Xcode 11 from doing automatic codesigning.
+ set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "")
+
+ # CEF directory paths.
+ set(CEF_BINARY_DIR "${_CEF_ROOT}/$<CONFIGURATION>")
+ set(CEF_BINARY_DIR_DEBUG "${_CEF_ROOT}/Debug")
+ set(CEF_BINARY_DIR_RELEASE "${_CEF_ROOT}/Release")
+
+ if(USE_SANDBOX)
+ list(APPEND CEF_COMPILER_DEFINES
+ CEF_USE_SANDBOX # Used by apps to test if the sandbox is enabled
+ )
+
+ list(APPEND CEF_STANDARD_LIBS
+ -lsandbox
+ )
+
+ # CEF sandbox library paths.
+ set(CEF_SANDBOX_LIB_DEBUG "${CEF_BINARY_DIR_DEBUG}/cef_sandbox.a")
+ set(CEF_SANDBOX_LIB_RELEASE "${CEF_BINARY_DIR_RELEASE}/cef_sandbox.a")
+ endif()
+
+ # CEF Helper app suffixes.
+ # Format is "<name suffix>:<target suffix>:<plist suffix>".
+ set(CEF_HELPER_APP_SUFFIXES
+ "::"
+ " (GPU):_gpu:.gpu"
+ " (Plugin):_plugin:.plugin"
+ " (Renderer):_renderer:.renderer"
+ )
+endif()
+
+
+#
+# Windows configuration.
+#
+
+if(OS_WINDOWS)
+ if (GEN_NINJA)
+ # When using the Ninja generator clear the CMake defaults to avoid excessive
+ # console warnings (see issue #2120).
+ set(CMAKE_CXX_FLAGS "")
+ set(CMAKE_CXX_FLAGS_DEBUG "")
+ set(CMAKE_CXX_FLAGS_RELEASE "")
+ endif()
+
+ if(USE_SANDBOX)
+ # Check if the current MSVC version is compatible with the cef_sandbox.lib
+ # static library. We require VS2015 or newer.
+ if(MSVC_VERSION LESS 1900)
+ message(WARNING "CEF sandbox is not compatible with the current MSVC version (${MSVC_VERSION})")
+ set(USE_SANDBOX OFF)
+ endif()
+ endif()
+
+ # Consumers who run into LNK4099 warnings can pass /Z7 instead (see issue #385).
+ set(CEF_DEBUG_INFO_FLAG "/Zi" CACHE STRING "Optional flag specifying specific /Z flag to use")
+
+ # Consumers using different runtime types may want to pass different flags
+ set(CEF_RUNTIME_LIBRARY_FLAG "/MT" CACHE STRING "Optional flag specifying which runtime to use")
+ if (CEF_RUNTIME_LIBRARY_FLAG)
+ list(APPEND CEF_COMPILER_FLAGS_DEBUG ${CEF_RUNTIME_LIBRARY_FLAG}d)
+ list(APPEND CEF_COMPILER_FLAGS_RELEASE ${CEF_RUNTIME_LIBRARY_FLAG})
+ endif()
+
+ # Platform-specific compiler/linker flags.
+ set(CEF_LIBTYPE STATIC)
+ list(APPEND CEF_COMPILER_FLAGS
+ /MP # Multiprocess compilation
+ /Gy # Enable function-level linking
+ /GR- # Disable run-time type information
+ /W4 # Warning level 4
+ /WX # Treat warnings as errors
+ /wd4100 # Ignore "unreferenced formal parameter" warning
+ /wd4127 # Ignore "conditional expression is constant" warning
+ /wd4244 # Ignore "conversion possible loss of data" warning
+ /wd4324 # Ignore "structure was padded due to alignment specifier" warning
+ /wd4481 # Ignore "nonstandard extension used: override" warning
+ /wd4512 # Ignore "assignment operator could not be generated" warning
+ /wd4701 # Ignore "potentially uninitialized local variable" warning
+ /wd4702 # Ignore "unreachable code" warning
+ /wd4996 # Ignore "function or variable may be unsafe" warning
+ ${CEF_DEBUG_INFO_FLAG}
+ )
+ list(APPEND CEF_COMPILER_FLAGS_DEBUG
+ /RTC1 # Disable optimizations
+ /Od # Enable basic run-time checks
+ )
+ list(APPEND CEF_COMPILER_FLAGS_RELEASE
+ /O2 # Optimize for maximum speed
+ /Ob2 # Inline any suitable function
+ /GF # Enable string pooling
+ )
+ list(APPEND CEF_CXX_COMPILER_FLAGS
+ /std:c++17 # Use the C++17 language standard
+ )
+ list(APPEND CEF_LINKER_FLAGS_DEBUG
+ /DEBUG # Generate debug information
+ )
+ list(APPEND CEF_EXE_LINKER_FLAGS
+ /MANIFEST:NO # No default manifest (see ADD_WINDOWS_MANIFEST macro usage)
+ /LARGEADDRESSAWARE # Allow 32-bit processes to access 3GB of RAM
+ )
+ list(APPEND CEF_COMPILER_DEFINES
+ WIN32 _WIN32 _WINDOWS # Windows platform
+ UNICODE _UNICODE # Unicode build
+ # Targeting Windows 10. We can't say `=_WIN32_WINNT_WIN10` here because
+ # some files do `#if WINVER < 0x0600` without including windows.h before,
+ # and then _WIN32_WINNT_WIN10 isn't yet known to be 0x0A00.
+ WINVER=0x0A00
+ _WIN32_WINNT=0x0A00
+ NTDDI_VERSION=NTDDI_WIN10_FE
+ NOMINMAX # Use the standard's templated min/max
+ WIN32_LEAN_AND_MEAN # Exclude less common API declarations
+ _HAS_EXCEPTIONS=0 # Disable exceptions
+ )
+ list(APPEND CEF_COMPILER_DEFINES_RELEASE
+ NDEBUG _NDEBUG # Not a debug build
+ )
+
+ if(PROJECT_ARCH STREQUAL "x86")
+ # Set the initial stack size to 0.5MiB, instead of the 1.5MiB minimum
+ # needed by CEF's main thread. This saves significant memory on threads
+ # (like those in the Windows thread pool, and others) whose stack size we
+ # can only control through this setting. The main thread (in 32-bit builds
+ # only) uses fibers to switch to a 4MiB stack at runtime via
+ # CefRunWinMainWithPreferredStackSize().
+ list(APPEND CEF_EXE_LINKER_FLAGS
+ /STACK:0x8000
+ )
+ else()
+ # Increase the initial stack size to 8MiB from the default 1MiB.
+ list(APPEND CEF_EXE_LINKER_FLAGS
+ /STACK:0x800000
+ )
+ endif()
+
+ # Standard libraries.
+ set(CEF_STANDARD_LIBS
+ comctl32.lib
+ gdi32.lib
+ rpcrt4.lib
+ shlwapi.lib
+ ws2_32.lib
+ )
+
+ # CEF directory paths.
+ set(CEF_RESOURCE_DIR "${_CEF_ROOT}/Resources")
+ set(CEF_BINARY_DIR "${_CEF_ROOT}/$<CONFIGURATION>")
+ set(CEF_BINARY_DIR_DEBUG "${_CEF_ROOT}/Debug")
+ set(CEF_BINARY_DIR_RELEASE "${_CEF_ROOT}/Release")
+
+ # CEF library paths.
+ set(CEF_LIB_DEBUG "${CEF_BINARY_DIR_DEBUG}/libcef.lib")
+ set(CEF_LIB_RELEASE "${CEF_BINARY_DIR_RELEASE}/libcef.lib")
+
+ # List of CEF binary files.
+ set(CEF_BINARY_FILES
+ chrome_elf.dll
+ libcef.dll
+ libEGL.dll
+ libGLESv2.dll
+ snapshot_blob.bin
+ v8_context_snapshot.bin
+ vk_swiftshader.dll
+ vk_swiftshader_icd.json
+ vulkan-1.dll
+ )
+
+ if(NOT PROJECT_ARCH STREQUAL "arm64")
+ list(APPEND CEF_BINARY_FILES
+ d3dcompiler_47.dll
+ )
+ endif()
+
+ # List of CEF resource files.
+ set(CEF_RESOURCE_FILES
+ chrome_100_percent.pak
+ chrome_200_percent.pak
+ resources.pak
+ icudtl.dat
+ locales
+ )
+
+ if(USE_SANDBOX)
+ list(APPEND CEF_COMPILER_DEFINES
+ PSAPI_VERSION=1 # Required by cef_sandbox.lib
+ CEF_USE_SANDBOX # Used by apps to test if the sandbox is enabled
+ )
+ list(APPEND CEF_COMPILER_DEFINES_DEBUG
+ _HAS_ITERATOR_DEBUGGING=0 # Disable iterator debugging
+ )
+
+ # Libraries required by cef_sandbox.lib.
+ set(CEF_SANDBOX_STANDARD_LIBS
+ Advapi32.lib
+ dbghelp.lib
+ Delayimp.lib
+ ntdll.lib
+ OleAut32.lib
+ PowrProf.lib
+ Propsys.lib
+ psapi.lib
+ SetupAPI.lib
+ Shell32.lib
+ Userenv.lib
+ version.lib
+ wbemuuid.lib
+ winmm.lib
+ )
+
+ # CEF sandbox library paths.
+ set(CEF_SANDBOX_LIB_DEBUG "${CEF_BINARY_DIR_DEBUG}/cef_sandbox.lib")
+ set(CEF_SANDBOX_LIB_RELEASE "${CEF_BINARY_DIR_RELEASE}/cef_sandbox.lib")
+ endif()
+
+ # Configure use of ATL.
+ option(USE_ATL "Enable or disable use of ATL." ON)
+ if(USE_ATL)
+ # Locate the atlmfc directory if it exists. It may be at any depth inside
+ # the VC directory. The cl.exe path returned by CMAKE_CXX_COMPILER may also
+ # be at different depths depending on the toolchain version
+ # (e.g. "VC/bin/cl.exe", "VC/bin/amd64_x86/cl.exe",
+ # "VC/Tools/MSVC/14.10.25017/bin/HostX86/x86/cl.exe", etc).
+ set(HAS_ATLMFC 0)
+ get_filename_component(VC_DIR ${CMAKE_CXX_COMPILER} DIRECTORY)
+ get_filename_component(VC_DIR_NAME ${VC_DIR} NAME)
+ while(NOT ${VC_DIR_NAME} STREQUAL "VC")
+ get_filename_component(VC_DIR ${VC_DIR} DIRECTORY)
+ if(IS_DIRECTORY "${VC_DIR}/atlmfc")
+ set(HAS_ATLMFC 1)
+ break()
+ endif()
+ get_filename_component(VC_DIR_NAME ${VC_DIR} NAME)
+ endwhile()
+
+ # Determine if the Visual Studio install supports ATL.
+ if(NOT HAS_ATLMFC)
+ message(WARNING "ATL is not supported by your VC installation.")
+ set(USE_ATL OFF)
+ endif()
+ endif()
+
+ if(USE_ATL)
+ list(APPEND CEF_COMPILER_DEFINES
+ CEF_USE_ATL # Used by apps to test if ATL support is enabled
+ )
+ endif()
+endif()
diff --git a/include/base/cef_atomic_flag.h b/include/base/cef_atomic_flag.h
new file mode 100644
index 00000000..3a2fdbc1
--- /dev/null
+++ b/include/base/cef_atomic_flag.h
@@ -0,0 +1,97 @@
+// Copyright (c) 2014 Marshall A. Greenblatt. Portions copyright (c) 2011
+// Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CEF_INCLUDE_BASE_CEF_ATOMIC_FLAG_H_
+#define CEF_INCLUDE_BASE_CEF_ATOMIC_FLAG_H_
+#pragma once
+
+#if defined(USING_CHROMIUM_INCLUDES)
+// When building CEF include the Chromium header directly.
+#include "base/synchronization/atomic_flag.h"
+
+#else // !USING_CHROMIUM_INCLUDES
+// The following is substantially similar to the Chromium implementation.
+// If the Chromium implementation diverges the below implementation should be
+// updated to match.
+
+#include <stdint.h>
+
+#include <atomic>
+
+#include "include/base/cef_thread_checker.h"
+
+namespace base {
+
+///
+/// A flag that can safely be set from one thread and read from other threads.
+///
+/// This class IS NOT intended for synchronization between threads.
+///
+class AtomicFlag {
+ public:
+ AtomicFlag();
+
+ AtomicFlag(const AtomicFlag&) = delete;
+ AtomicFlag& operator=(const AtomicFlag&) = delete;
+
+ ~AtomicFlag();
+
+ ///
+ /// Set the flag. Must always be called from the same thread.
+ ///
+ void Set();
+
+ ///
+ /// Returns true iff the flag was set. If this returns true, the current
+ /// thread is guaranteed to be synchronized with all memory operations on the
+ /// thread which invoked Set() up until at least the first call to Set() on
+ /// it.
+ ///
+ bool IsSet() const {
+ // Inline here: this has a measurable performance impact on base::WeakPtr.
+ return flag_.load(std::memory_order_acquire) != 0;
+ }
+
+ ///
+ /// Resets the flag. Be careful when using this: callers might not expect
+ /// IsSet() to return false after returning true once.
+ ///
+ void UnsafeResetForTesting();
+
+ private:
+ std::atomic<uint_fast8_t> flag_{0};
+ base::ThreadChecker set_thread_checker_;
+};
+
+} // namespace base
+
+#endif // !USING_CHROMIUM_INCLUDES
+
+#endif // CEF_INCLUDE_BASE_CEF_ATOMIC_FLAG_H_
diff --git a/include/base/cef_atomic_ref_count.h b/include/base/cef_atomic_ref_count.h
new file mode 100644
index 00000000..38e8f93b
--- /dev/null
+++ b/include/base/cef_atomic_ref_count.h
@@ -0,0 +1,123 @@
+// Copyright (c) 2014 Marshall A. Greenblatt. Portions copyright (c) 2011
+// Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This is a low level implementation of atomic semantics for reference
+// counting. Please use cef_ref_counted.h directly instead.
+//
+// The Chromium implementation includes annotations to avoid some false
+// positives when using data race detection tools. Annotations are not
+// currently supported by the CEF implementation.
+
+#ifndef CEF_INCLUDE_BASE_CEF_ATOMIC_REF_COUNT_H_
+#define CEF_INCLUDE_BASE_CEF_ATOMIC_REF_COUNT_H_
+#pragma once
+
+#if defined(USING_CHROMIUM_INCLUDES)
+// When building CEF include the Chromium header directly.
+#include "base/atomic_ref_count.h"
+
+#else // !USING_CHROMIUM_INCLUDES
+// The following is substantially similar to the Chromium implementation.
+// If the Chromium implementation diverges the below implementation should be
+// updated to match.
+
+#include <atomic>
+
+namespace base {
+
+class AtomicRefCount {
+ public:
+ constexpr AtomicRefCount() : ref_count_(0) {}
+ explicit constexpr AtomicRefCount(int initial_value)
+ : ref_count_(initial_value) {}
+
+ ///
+ /// Increment a reference count.
+ /// Returns the previous value of the count.
+ ///
+ int Increment() { return Increment(1); }
+
+ ///
+ /// Increment a reference count by "increment", which must exceed 0.
+ /// Returns the previous value of the count.
+ ///
+ int Increment(int increment) {
+ return ref_count_.fetch_add(increment, std::memory_order_relaxed);
+ }
+
+ ///
+ /// Decrement a reference count, and return whether the result is non-zero.
+ /// Insert barriers to ensure that state written before the reference count
+ /// became zero will be visible to a thread that has just made the count zero.
+ ///
+ bool Decrement() {
+ // TODO(jbroman): Technically this doesn't need to be an acquire operation
+ // unless the result is 1 (i.e., the ref count did indeed reach zero).
+ // However, there are toolchain issues that make that not work as well at
+ // present (notably TSAN doesn't like it).
+ return ref_count_.fetch_sub(1, std::memory_order_acq_rel) != 1;
+ }
+
+ ///
+ /// Return whether the reference count is one. If the reference count is used
+ /// in the conventional way, a refrerence count of 1 implies that the current
+ /// thread owns the reference and no other thread shares it. This call
+ /// performs the test for a reference count of one, and performs the memory
+ /// barrier needed for the owning thread to act on the object, knowing that it
+ /// has exclusive access to the object.
+ ///
+ bool IsOne() const { return ref_count_.load(std::memory_order_acquire) == 1; }
+
+ ///
+ /// Return whether the reference count is zero. With conventional object
+ /// referencing counting, the object will be destroyed, so the reference count
+ /// should never be zero. Hence this is generally used for a debug check.
+ ///
+ bool IsZero() const {
+ return ref_count_.load(std::memory_order_acquire) == 0;
+ }
+
+ ///
+ /// Returns the current reference count (with no barriers). This is subtle,
+ /// and should be used only for debugging.
+ ///
+ int SubtleRefCountForDebug() const {
+ return ref_count_.load(std::memory_order_relaxed);
+ }
+
+ private:
+ std::atomic_int ref_count_;
+};
+
+} // namespace base
+
+#endif // !USING_CHROMIUM_INCLUDES
+
+#endif // CEF_INCLUDE_BASE_CEF_ATOMIC_REF_COUNT_H_
diff --git a/include/base/cef_auto_reset.h b/include/base/cef_auto_reset.h
new file mode 100644
index 00000000..be3a05da
--- /dev/null
+++ b/include/base/cef_auto_reset.h
@@ -0,0 +1,90 @@
+// Copyright (c) 2014 Marshall A. Greenblatt. Portions copyright (c) 2011
+// Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// base::AutoReset<> is useful for setting a variable to a new value only within
+// a particular scope. An base::AutoReset<> object resets a variable to its
+// original value upon destruction, making it an alternative to writing
+// "var = false;" or "var = old_val;" at all of a block's exit points.
+//
+// This should be obvious, but note that an base::AutoReset<> instance should
+// have a shorter lifetime than its scoped_variable, to prevent invalid memory
+// writes when the base::AutoReset<> object is destroyed.
+
+#ifndef CEF_INCLUDE_BASE_CEF_AUTO_RESET_H_
+#define CEF_INCLUDE_BASE_CEF_AUTO_RESET_H_
+#pragma once
+
+#if defined(USING_CHROMIUM_INCLUDES)
+// When building CEF include the Chromium header directly.
+#include "base/auto_reset.h"
+#else // !USING_CHROMIUM_INCLUDES
+// The following is substantially similar to the Chromium implementation.
+// If the Chromium implementation diverges the below implementation should be
+// updated to match.
+
+#include <utility>
+
+namespace base {
+
+template <typename T>
+class AutoReset {
+ public:
+ template <typename U>
+ AutoReset(T* scoped_variable, U&& new_value)
+ : scoped_variable_(scoped_variable),
+ original_value_(
+ std::exchange(*scoped_variable_, std::forward<U>(new_value))) {}
+
+ AutoReset(AutoReset&& other)
+ : scoped_variable_(std::exchange(other.scoped_variable_, nullptr)),
+ original_value_(std::move(other.original_value_)) {}
+
+ AutoReset& operator=(AutoReset&& rhs) {
+ scoped_variable_ = std::exchange(rhs.scoped_variable_, nullptr);
+ original_value_ = std::move(rhs.original_value_);
+ return *this;
+ }
+
+ ~AutoReset() {
+ if (scoped_variable_) {
+ *scoped_variable_ = std::move(original_value_);
+ }
+ }
+
+ private:
+ T* scoped_variable_;
+ T original_value_;
+};
+
+} // namespace base
+
+#endif // !USING_CHROMIUM_INCLUDES
+
+#endif // CEF_INCLUDE_BASE_CEF_AUTO_RESET_H_
diff --git a/include/base/cef_basictypes.h b/include/base/cef_basictypes.h
new file mode 100644
index 00000000..4f39e83c
--- /dev/null
+++ b/include/base/cef_basictypes.h
@@ -0,0 +1,86 @@
+// Copyright (c) 2014 Marshall A. Greenblatt. Portions copyright (c) 2012
+// Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CEF_INCLUDE_BASE_CEF_BASICTYPES_H_
+#define CEF_INCLUDE_BASE_CEF_BASICTYPES_H_
+#pragma once
+
+#include <limits.h> // For UINT_MAX
+#include <stddef.h> // For size_t
+
+#include "include/base/cef_build.h"
+
+// The NSPR system headers define 64-bit as |long| when possible, except on
+// Mac OS X. In order to not have typedef mismatches, we do the same on LP64.
+//
+// On Mac OS X, |long long| is used for 64-bit types for compatibility with
+// <inttypes.h> format macros even in the LP64 model.
+#if defined(__LP64__) && !defined(OS_MAC) && !defined(OS_OPENBSD)
+typedef long int64;
+typedef unsigned long uint64;
+#else
+typedef long long int64;
+typedef unsigned long long uint64;
+#endif
+
+// TODO: Remove these type guards. These are to avoid conflicts with
+// obsolete/protypes.h in the Gecko SDK.
+#ifndef _INT32
+#define _INT32
+typedef int int32;
+#endif
+
+// TODO: Remove these type guards. These are to avoid conflicts with
+// obsolete/protypes.h in the Gecko SDK.
+#ifndef _UINT32
+#define _UINT32
+typedef unsigned int uint32;
+#endif
+
+#ifndef _INT16
+#define _INT16
+typedef short int16;
+#endif
+
+#ifndef _UINT16
+#define _UINT16
+typedef unsigned short uint16;
+#endif
+
+// UTF-16 character type.
+#ifndef char16
+#if defined(WCHAR_T_IS_UTF16)
+typedef wchar_t char16;
+#elif defined(WCHAR_T_IS_UTF32)
+typedef unsigned short char16;
+#endif
+#endif
+
+#endif // CEF_INCLUDE_BASE_CEF_BASICTYPES_H_
diff --git a/include/base/cef_bind.h b/include/base/cef_bind.h
new file mode 100644
index 00000000..770e373e
--- /dev/null
+++ b/include/base/cef_bind.h
@@ -0,0 +1,391 @@
+// Copyright (c) 2014 Marshall A. Greenblatt. Portions copyright (c) 2011
+// Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+///
+/// \file
+/// base::BindOnce() and base::BindRepeating() are helpers for creating
+/// base::OnceCallback and base::RepeatingCallback objects respectively.
+///
+/// For a runnable object of n-arity, the base::Bind*() family allows partial
+/// application of the first m arguments. The remaining n - m arguments must be
+/// passed when invoking the callback with Run().
+///
+/// <pre>
+/// // The first argument is bound at callback creation; the remaining
+/// // two must be passed when calling Run() on the callback object.
+/// base::OnceCallback<long(int, long)> cb = base::BindOnce(
+/// [](short x, int y, long z) { return x * y * z; }, 42);
+/// </pre>
+///
+/// When binding to a method, the receiver object must also be specified at
+/// callback creation time. When Run() is invoked, the method will be invoked on
+/// the specified receiver object.
+///
+/// <pre>
+/// class C : public base::RefCounted<C> { void F(); };
+/// auto instance = base::MakeRefCounted<C>();
+/// auto cb = base::BindOnce(&C::F, instance);
+/// std::move(cb).Run(); // Identical to instance->F()
+/// </pre>
+///
+/// See https://chromium.googlesource.com/chromium/src/+/lkgr/docs/callback.md
+/// for the full documentation.
+///
+
+// Implementation notes
+//
+// If you're reading the implementation, before proceeding further, you should
+// read the top comment of base/internal/cef_bind_internal.h for a definition
+// of common terms and concepts.
+
+#ifndef CEF_INCLUDE_BASE_CEF_BIND_H_
+#define CEF_INCLUDE_BASE_CEF_BIND_H_
+#pragma once
+
+#if defined(USING_CHROMIUM_INCLUDES)
+// When building CEF include the Chromium header directly.
+#include "base/functional/bind.h"
+#else // !USING_CHROMIUM_INCLUDES
+// The following is substantially similar to the Chromium implementation.
+// If the Chromium implementation diverges the below implementation should be
+// updated to match.
+
+#include <functional>
+#include <memory>
+#include <type_traits>
+#include <utility>
+
+#include "include/base/cef_build.h"
+#include "include/base/cef_compiler_specific.h"
+#include "include/base/cef_template_util.h"
+#include "include/base/internal/cef_bind_internal.h"
+
+#if defined(OS_APPLE) && !HAS_FEATURE(objc_arc)
+#include "include/base/internal/cef_scoped_block_mac.h"
+#endif
+
+namespace base {
+
+///
+/// Bind as OnceCallback.
+///
+template <typename Functor, typename... Args>
+inline OnceCallback<cef_internal::MakeUnboundRunType<Functor, Args...>>
+BindOnce(Functor&& functor, Args&&... args) {
+ static_assert(!cef_internal::IsOnceCallback<std::decay_t<Functor>>() ||
+ (std::is_rvalue_reference<Functor&&>() &&
+ !std::is_const<std::remove_reference_t<Functor>>()),
+ "BindOnce requires non-const rvalue for OnceCallback binding."
+ " I.e.: base::BindOnce(std::move(callback)).");
+ static_assert(
+ conjunction<cef_internal::AssertBindArgIsNotBasePassed<
+ std::decay_t<Args>>...>::value,
+ "Use std::move() instead of base::Passed() with base::BindOnce()");
+
+ return cef_internal::BindImpl<OnceCallback>(std::forward<Functor>(functor),
+ std::forward<Args>(args)...);
+}
+
+///
+/// Bind as RepeatingCallback.
+///
+template <typename Functor, typename... Args>
+inline RepeatingCallback<cef_internal::MakeUnboundRunType<Functor, Args...>>
+BindRepeating(Functor&& functor, Args&&... args) {
+ static_assert(
+ !cef_internal::IsOnceCallback<std::decay_t<Functor>>(),
+ "BindRepeating cannot bind OnceCallback. Use BindOnce with std::move().");
+
+ return cef_internal::BindImpl<RepeatingCallback>(
+ std::forward<Functor>(functor), std::forward<Args>(args)...);
+}
+
+///
+/// Special cases for binding to a base::Callback without extra bound arguments.
+/// We CHECK() the validity of callback to guard against null pointers
+/// accidentally ending up in posted tasks, causing hard-to-debug crashes.
+///
+template <typename Signature>
+OnceCallback<Signature> BindOnce(OnceCallback<Signature> callback) {
+ CHECK(callback);
+ return callback;
+}
+
+template <typename Signature>
+OnceCallback<Signature> BindOnce(RepeatingCallback<Signature> callback) {
+ CHECK(callback);
+ return callback;
+}
+
+template <typename Signature>
+RepeatingCallback<Signature> BindRepeating(
+ RepeatingCallback<Signature> callback) {
+ CHECK(callback);
+ return callback;
+}
+
+///
+/// Unretained() allows binding a non-refcounted class, and to disable
+/// refcounting on arguments that are refcounted objects.
+///
+/// EXAMPLE OF Unretained():
+///
+/// <pre>
+/// class Foo {
+/// public:
+/// void func() { cout << "Foo:f" << endl; }
+/// };
+///
+/// // In some function somewhere.
+/// Foo foo;
+/// OnceClosure foo_callback =
+/// BindOnce(&Foo::func, Unretained(&foo));
+/// std::move(foo_callback).Run(); // Prints "Foo:f".
+/// </pre>
+///
+/// Without the Unretained() wrapper on |&foo|, the above call would fail
+/// to compile because Foo does not support the AddRef() and Release() methods.
+///
+template <typename T>
+inline cef_internal::UnretainedWrapper<T> Unretained(T* o) {
+ return cef_internal::UnretainedWrapper<T>(o);
+}
+
+///
+/// RetainedRef() accepts a ref counted object and retains a reference to it.
+/// When the callback is called, the object is passed as a raw pointer.
+///
+/// EXAMPLE OF RetainedRef():
+///
+/// <pre>
+/// void foo(RefCountedBytes* bytes) {}
+///
+/// scoped_refptr<RefCountedBytes> bytes = ...;
+/// OnceClosure callback = BindOnce(&foo, base::RetainedRef(bytes));
+/// std::move(callback).Run();
+/// </pre>
+///
+/// Without RetainedRef, the scoped_refptr would try to implicitly convert to
+/// a raw pointer and fail compilation:
+///
+/// <pre>
+/// OnceClosure callback = BindOnce(&foo, bytes); // ERROR!
+/// </pre>
+///
+template <typename T>
+inline cef_internal::RetainedRefWrapper<T> RetainedRef(T* o) {
+ return cef_internal::RetainedRefWrapper<T>(o);
+}
+template <typename T>
+inline cef_internal::RetainedRefWrapper<T> RetainedRef(scoped_refptr<T> o) {
+ return cef_internal::RetainedRefWrapper<T>(std::move(o));
+}
+
+///
+/// Owned() transfers ownership of an object to the callback resulting from
+/// bind; the object will be deleted when the callback is deleted.
+///
+/// EXAMPLE OF Owned():
+///
+/// <pre>
+/// void foo(int* arg) { cout << *arg << endl }
+///
+/// int* pn = new int(1);
+/// RepeatingClosure foo_callback = BindRepeating(&foo, Owned(pn));
+///
+/// foo_callback.Run(); // Prints "1"
+/// foo_callback.Run(); // Prints "1"
+/// *pn = 2;
+/// foo_callback.Run(); // Prints "2"
+///
+/// foo_callback.Reset(); // |pn| is deleted. Also will happen when
+/// // |foo_callback| goes out of scope.
+/// </pre>
+///
+/// Without Owned(), someone would have to know to delete |pn| when the last
+/// reference to the callback is deleted.
+///
+template <typename T>
+inline cef_internal::OwnedWrapper<T> Owned(T* o) {
+ return cef_internal::OwnedWrapper<T>(o);
+}
+
+template <typename T, typename Deleter>
+inline cef_internal::OwnedWrapper<T, Deleter> Owned(
+ std::unique_ptr<T, Deleter>&& ptr) {
+ return cef_internal::OwnedWrapper<T, Deleter>(std::move(ptr));
+}
+
+///
+/// OwnedRef() stores an object in the callback resulting from
+/// bind and passes a reference to the object to the bound function.
+///
+/// EXAMPLE OF OwnedRef():
+///
+/// <pre>
+/// void foo(int& arg) { cout << ++arg << endl }
+///
+/// int counter = 0;
+/// RepeatingClosure foo_callback = BindRepeating(&foo, OwnedRef(counter));
+///
+/// foo_callback.Run(); // Prints "1"
+/// foo_callback.Run(); // Prints "2"
+/// foo_callback.Run(); // Prints "3"
+///
+/// cout << counter; // Prints "0", OwnedRef creates a copy of counter.
+/// </pre>
+///
+/// Supports OnceCallbacks as well, useful to pass placeholder arguments:
+///
+/// <pre>
+/// void bar(int& ignore, const std::string& s) { cout << s << endl }
+///
+/// OnceClosure bar_callback = BindOnce(&bar, OwnedRef(0), "Hello");
+///
+/// std::move(bar_callback).Run(); // Prints "Hello"
+/// </pre>
+///
+/// Without OwnedRef() it would not be possible to pass a mutable reference to
+/// an object owned by the callback.
+///
+template <typename T>
+cef_internal::OwnedRefWrapper<std::decay_t<T>> OwnedRef(T&& t) {
+ return cef_internal::OwnedRefWrapper<std::decay_t<T>>(std::forward<T>(t));
+}
+
+///
+/// Passed() is for transferring movable-but-not-copyable types (eg. unique_ptr)
+/// through a RepeatingCallback. Logically, this signifies a destructive
+/// transfer of the state of the argument into the target function. Invoking
+/// RepeatingCallback::Run() twice on a callback that was created with a
+/// Passed() argument will CHECK() because the first invocation would have
+/// already transferred ownership to the target function.
+///
+/// Note that Passed() is not necessary with BindOnce(), as std::move() does the
+/// same thing. Avoid Passed() in favor of std::move() with BindOnce().
+///
+/// EXAMPLE OF Passed():
+///
+/// <pre>
+/// void TakesOwnership(std::unique_ptr<Foo> arg) { }
+/// std::unique_ptr<Foo> CreateFoo() { return std::make_unique<Foo>();
+/// }
+///
+/// auto f = std::make_unique<Foo>();
+///
+/// // |cb| is given ownership of Foo(). |f| is now NULL.
+/// // You can use std::move(f) in place of &f, but it's more verbose.
+/// RepeatingClosure cb = BindRepeating(&TakesOwnership, Passed(&f));
+///
+/// // Run was never called so |cb| still owns Foo() and deletes
+/// // it on Reset().
+/// cb.Reset();
+///
+/// // |cb| is given a new Foo created by CreateFoo().
+/// cb = BindRepeating(&TakesOwnership, Passed(CreateFoo()));
+///
+/// // |arg| in TakesOwnership() is given ownership of Foo(). |cb|
+/// // no longer owns Foo() and, if reset, would not delete Foo().
+/// cb.Run(); // Foo() is now transferred to |arg| and deleted.
+/// cb.Run(); // This CHECK()s since Foo() already been used once.
+/// </pre>
+///
+/// We offer 2 syntaxes for calling Passed(). The first takes an rvalue and is
+/// best suited for use with the return value of a function or other temporary
+/// rvalues. The second takes a pointer to the scoper and is just syntactic
+/// sugar to avoid having to write Passed(std::move(scoper)).
+///
+/// Both versions of Passed() prevent T from being an lvalue reference. The
+/// first via use of enable_if, and the second takes a T* which will not bind to
+/// T&.
+///
+template <typename T,
+ std::enable_if_t<!std::is_lvalue_reference<T>::value>* = nullptr>
+inline cef_internal::PassedWrapper<T> Passed(T&& scoper) {
+ return cef_internal::PassedWrapper<T>(std::move(scoper));
+}
+template <typename T>
+inline cef_internal::PassedWrapper<T> Passed(T* scoper) {
+ return cef_internal::PassedWrapper<T>(std::move(*scoper));
+}
+
+///
+/// IgnoreResult() is used to adapt a function or callback with a return type to
+/// one with a void return. This is most useful if you have a function with,
+/// say, a pesky ignorable bool return that you want to use with PostTask or
+/// something else that expect a callback with a void return.
+///
+/// EXAMPLE OF IgnoreResult():
+///
+/// <pre>
+/// int DoSomething(int arg) { cout << arg << endl; }
+///
+/// // Assign to a callback with a void return type.
+/// OnceCallback<void(int)> cb = BindOnce(IgnoreResult(&DoSomething));
+/// std::move(cb).Run(1); // Prints "1".
+///
+/// // Prints "2" on |ml|.
+/// ml->PostTask(FROM_HERE, BindOnce(IgnoreResult(&DoSomething), 2);
+/// </pre>
+///
+template <typename T>
+inline cef_internal::IgnoreResultHelper<T> IgnoreResult(T data) {
+ return cef_internal::IgnoreResultHelper<T>(std::move(data));
+}
+
+#if defined(OS_APPLE) && !HAS_FEATURE(objc_arc)
+
+///
+/// RetainBlock() is used to adapt an Objective-C block when Automated Reference
+/// Counting (ARC) is disabled. This is unnecessary when ARC is enabled, as the
+/// BindOnce and BindRepeating already support blocks then.
+///
+/// EXAMPLE OF RetainBlock():
+///
+/// <pre>
+/// // Wrap the block and bind it to a callback.
+/// OnceCallback<void(int)> cb =
+/// BindOnce(RetainBlock(^(int n) { NSLog(@"%d", n); }));
+/// std::move(cb).Run(1); // Logs "1".
+/// </pre>
+///
+template <typename R, typename... Args>
+base::mac::ScopedBlock<R (^)(Args...)> RetainBlock(R (^block)(Args...)) {
+ return base::mac::ScopedBlock<R (^)(Args...)>(block,
+ base::scoped_policy::RETAIN);
+}
+
+#endif // defined(OS_APPLE) && !HAS_FEATURE(objc_arc)
+
+} // namespace base
+
+#endif // !USING_CHROMIUM_INCLUDES
+
+#endif // CEF_INCLUDE_BASE_CEF_BIND_H_
diff --git a/include/base/cef_build.h b/include/base/cef_build.h
new file mode 100644
index 00000000..48a088cb
--- /dev/null
+++ b/include/base/cef_build.h
@@ -0,0 +1,263 @@
+// Copyright (c) 2011 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+/// \file
+/// This file adds defines about the platform we're currently building on.
+///
+/// <pre>
+/// Operating System:
+/// OS_AIX / OS_ANDROID / OS_ASMJS / OS_FREEBSD / OS_FUCHSIA / OS_IOS /
+/// OS_LINUX / OS_MAC / OS_NACL (SFI or NONSFI) / OS_NETBSD / OS_OPENBSD /
+/// OS_QNX / OS_SOLARIS / OS_WIN
+/// Operating System family:
+/// OS_APPLE: IOS or MAC
+/// OS_BSD: FREEBSD or NETBSD or OPENBSD
+/// OS_POSIX: AIX or ANDROID or ASMJS or CHROMEOS or FREEBSD or IOS or LINUX
+/// or MAC or NACL or NETBSD or OPENBSD or QNX or SOLARIS
+///
+/// /!\ Note: OS_CHROMEOS is set by the build system, not this file
+///
+/// Compiler:
+/// COMPILER_MSVC / COMPILER_GCC
+///
+/// Processor:
+/// ARCH_CPU_ARM64 / ARCH_CPU_ARMEL / ARCH_CPU_MIPS / ARCH_CPU_MIPS64 /
+/// ARCH_CPU_MIPS64EL / ARCH_CPU_MIPSEL / ARCH_CPU_PPC64 / ARCH_CPU_S390 /
+/// ARCH_CPU_S390X / ARCH_CPU_X86 / ARCH_CPU_X86_64
+/// Processor family:
+/// ARCH_CPU_ARM_FAMILY: ARMEL or ARM64
+/// ARCH_CPU_MIPS_FAMILY: MIPS64EL or MIPSEL or MIPS64 or MIPS
+/// ARCH_CPU_PPC64_FAMILY: PPC64
+/// ARCH_CPU_S390_FAMILY: S390 or S390X
+/// ARCH_CPU_X86_FAMILY: X86 or X86_64
+/// Processor features:
+/// ARCH_CPU_31_BITS / ARCH_CPU_32_BITS / ARCH_CPU_64_BITS
+/// ARCH_CPU_BIG_ENDIAN / ARCH_CPU_LITTLE_ENDIAN
+/// </pre>
+///
+
+#ifndef CEF_INCLUDE_BASE_CEF_BUILD_H_
+#define CEF_INCLUDE_BASE_CEF_BUILD_H_
+#pragma once
+
+#if defined(USING_CHROMIUM_INCLUDES)
+// When building CEF include the Chromium header directly.
+#include "build/build_config.h"
+#else // !USING_CHROMIUM_INCLUDES
+// The following is substantially similar to the Chromium implementation.
+// If the Chromium implementation diverges the below implementation should be
+// updated to match.
+
+// A set of macros to use for platform detection.
+#if defined(ANDROID)
+#define OS_ANDROID 1
+#elif defined(__APPLE__)
+// Only include TargetConditionals after testing ANDROID as some Android builds
+// on the Mac have this header available and it's not needed unless the target
+// is really an Apple platform.
+#include <TargetConditionals.h>
+#if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
+#define OS_IOS 1
+#else
+#define OS_MAC 1
+// For backwards compatibility.
+#define OS_MACOSX 1
+#endif // defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
+#elif defined(__linux__)
+#if !defined(OS_CHROMEOS)
+// Do not define OS_LINUX on Chrome OS build.
+// The OS_CHROMEOS macro is defined in GN.
+#define OS_LINUX 1
+#endif // !defined(OS_CHROMEOS)
+// Include a system header to pull in features.h for glibc/uclibc macros.
+#include <unistd.h>
+#if defined(__GLIBC__) && !defined(__UCLIBC__)
+// We really are using glibc, not uClibc pretending to be glibc.
+#define LIBC_GLIBC 1
+#endif
+#elif defined(_WIN32)
+#define OS_WIN 1
+#elif defined(__Fuchsia__)
+#define OS_FUCHSIA 1
+#elif defined(__FreeBSD__)
+#define OS_FREEBSD 1
+#elif defined(__NetBSD__)
+#define OS_NETBSD 1
+#elif defined(__OpenBSD__)
+#define OS_OPENBSD 1
+#elif defined(__sun)
+#define OS_SOLARIS 1
+#elif defined(__QNXNTO__)
+#define OS_QNX 1
+#elif defined(_AIX)
+#define OS_AIX 1
+#elif defined(__asmjs__) || defined(__wasm__)
+#define OS_ASMJS 1
+#else
+#error Please add support for your platform in include/base/cef_build.h
+#endif
+// NOTE: Adding a new port? Please follow
+// https://chromium.googlesource.com/chromium/src/+/master/docs/new_port_policy.md
+
+#if defined(OS_MAC) || defined(OS_IOS)
+#define OS_APPLE 1
+#endif
+
+// For access to standard BSD features, use OS_BSD instead of a
+// more specific macro.
+#if defined(OS_FREEBSD) || defined(OS_NETBSD) || defined(OS_OPENBSD)
+#define OS_BSD 1
+#endif
+
+// For access to standard POSIXish features, use OS_POSIX instead of a
+// more specific macro.
+#if defined(OS_AIX) || defined(OS_ANDROID) || defined(OS_ASMJS) || \
+ defined(OS_FREEBSD) || defined(OS_IOS) || defined(OS_LINUX) || \
+ defined(OS_CHROMEOS) || defined(OS_MAC) || defined(OS_NACL) || \
+ defined(OS_NETBSD) || defined(OS_OPENBSD) || defined(OS_QNX) || \
+ defined(OS_SOLARIS)
+#define OS_POSIX 1
+#endif
+
+// Compiler detection. Note: clang masquerades as GCC on POSIX and as MSVC on
+// Windows.
+#if defined(__GNUC__)
+#define COMPILER_GCC 1
+#elif defined(_MSC_VER)
+#define COMPILER_MSVC 1
+#else
+#error Please add support for your compiler in build/build_config.h
+#endif
+
+// Processor architecture detection. For more info on what's defined, see:
+// http://msdn.microsoft.com/en-us/library/b0084kay.aspx
+// http://www.agner.org/optimize/calling_conventions.pdf
+// or with gcc, run: "echo | gcc -E -dM -"
+#if defined(_M_X64) || defined(__x86_64__)
+#define ARCH_CPU_X86_FAMILY 1
+#define ARCH_CPU_X86_64 1
+#define ARCH_CPU_64_BITS 1
+#define ARCH_CPU_LITTLE_ENDIAN 1
+#elif defined(_M_IX86) || defined(__i386__)
+#define ARCH_CPU_X86_FAMILY 1
+#define ARCH_CPU_X86 1
+#define ARCH_CPU_32_BITS 1
+#define ARCH_CPU_LITTLE_ENDIAN 1
+#elif defined(__s390x__)
+#define ARCH_CPU_S390_FAMILY 1
+#define ARCH_CPU_S390X 1
+#define ARCH_CPU_64_BITS 1
+#define ARCH_CPU_BIG_ENDIAN 1
+#elif defined(__s390__)
+#define ARCH_CPU_S390_FAMILY 1
+#define ARCH_CPU_S390 1
+#define ARCH_CPU_31_BITS 1
+#define ARCH_CPU_BIG_ENDIAN 1
+#elif (defined(__PPC64__) || defined(__PPC__)) && defined(__BIG_ENDIAN__)
+#define ARCH_CPU_PPC64_FAMILY 1
+#define ARCH_CPU_PPC64 1
+#define ARCH_CPU_64_BITS 1
+#define ARCH_CPU_BIG_ENDIAN 1
+#elif defined(__PPC64__)
+#define ARCH_CPU_PPC64_FAMILY 1
+#define ARCH_CPU_PPC64 1
+#define ARCH_CPU_64_BITS 1
+#define ARCH_CPU_LITTLE_ENDIAN 1
+#elif defined(__ARMEL__)
+#define ARCH_CPU_ARM_FAMILY 1
+#define ARCH_CPU_ARMEL 1
+#define ARCH_CPU_32_BITS 1
+#define ARCH_CPU_LITTLE_ENDIAN 1
+#elif defined(__aarch64__) || defined(_M_ARM64)
+#define ARCH_CPU_ARM_FAMILY 1
+#define ARCH_CPU_ARM64 1
+#define ARCH_CPU_64_BITS 1
+#define ARCH_CPU_LITTLE_ENDIAN 1
+#elif defined(__pnacl__) || defined(__asmjs__) || defined(__wasm__)
+#define ARCH_CPU_32_BITS 1
+#define ARCH_CPU_LITTLE_ENDIAN 1
+#elif defined(__MIPSEL__)
+#if defined(__LP64__)
+#define ARCH_CPU_MIPS_FAMILY 1
+#define ARCH_CPU_MIPS64EL 1
+#define ARCH_CPU_64_BITS 1
+#define ARCH_CPU_LITTLE_ENDIAN 1
+#else
+#define ARCH_CPU_MIPS_FAMILY 1
+#define ARCH_CPU_MIPSEL 1
+#define ARCH_CPU_32_BITS 1
+#define ARCH_CPU_LITTLE_ENDIAN 1
+#endif
+#elif defined(__MIPSEB__)
+#if defined(__LP64__)
+#define ARCH_CPU_MIPS_FAMILY 1
+#define ARCH_CPU_MIPS64 1
+#define ARCH_CPU_64_BITS 1
+#define ARCH_CPU_BIG_ENDIAN 1
+#else
+#define ARCH_CPU_MIPS_FAMILY 1
+#define ARCH_CPU_MIPS 1
+#define ARCH_CPU_32_BITS 1
+#define ARCH_CPU_BIG_ENDIAN 1
+#endif
+#else
+#error Please add support for your architecture in include/base/cef_build.h
+#endif
+
+// Type detection for wchar_t.
+#if defined(OS_WIN)
+#define WCHAR_T_IS_UTF16
+#elif defined(OS_FUCHSIA)
+#define WCHAR_T_IS_UTF32
+#elif defined(OS_POSIX) && defined(COMPILER_GCC) && defined(__WCHAR_MAX__) && \
+ (__WCHAR_MAX__ == 0x7fffffff || __WCHAR_MAX__ == 0xffffffff)
+#define WCHAR_T_IS_UTF32
+#elif defined(OS_POSIX) && defined(COMPILER_GCC) && defined(__WCHAR_MAX__) && \
+ (__WCHAR_MAX__ == 0x7fff || __WCHAR_MAX__ == 0xffff)
+// On Posix, we'll detect short wchar_t, but projects aren't guaranteed to
+// compile in this mode (in particular, Chrome doesn't). This is intended for
+// other projects using base who manage their own dependencies and make sure
+// short wchar works for them.
+#define WCHAR_T_IS_UTF16
+#else
+#error Please add support for your compiler in include/base/cef_build.h
+#endif
+
+#if defined(OS_ANDROID)
+// The compiler thinks std::string::const_iterator and "const char*" are
+// equivalent types.
+#define STD_STRING_ITERATOR_IS_CHAR_POINTER
+// The compiler thinks std::u16string::const_iterator and "char16*" are
+// equivalent types.
+#define BASE_STRING16_ITERATOR_IS_CHAR16_POINTER
+#endif
+
+#endif // !USING_CHROMIUM_INCLUDES
+
+#endif // CEF_INCLUDE_BASE_CEF_BUILD_H_
diff --git a/include/base/cef_callback.h b/include/base/cef_callback.h
new file mode 100644
index 00000000..bcfe4992
--- /dev/null
+++ b/include/base/cef_callback.h
@@ -0,0 +1,250 @@
+// Copyright (c) 2014 Marshall A. Greenblatt. Portions copyright (c) 2012
+// Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+/// \file
+/// A callback is similar in concept to a function pointer: it wraps a runnable
+/// object such as a function, method, lambda, or even another callback,
+/// allowing the runnable object to be invoked later via the callback object.
+///
+/// Unlike function pointers, callbacks are created with base::BindOnce() or
+/// base::BindRepeating() and support partial function application.
+///
+/// A base::OnceCallback may be Run() at most once; a base::RepeatingCallback
+/// may be Run() any number of times. |is_null()| is guaranteed to return true
+/// for a moved-from callback.
+///
+/// <pre>
+/// // The lambda takes two arguments, but the first argument |x| is bound at
+/// // callback creation.
+/// base::OnceCallback<int(int)> cb = base::BindOnce([] (int x, int y) {
+/// return x + y;
+/// }, 1);
+/// // Run() only needs the remaining unbound argument |y|.
+/// printf("1 + 2 = %d\n", std::move(cb).Run(2)); // Prints 3
+/// printf("cb is null? %s\n",
+/// cb.is_null() ? "true" : "false"); // Prints true
+/// std::move(cb).Run(2); // Crashes since |cb| has already run.
+/// </pre>
+///
+/// Callbacks also support cancellation. A common use is binding the receiver
+/// object as a WeakPtr<T>. If that weak pointer is invalidated, calling Run()
+/// will be a no-op. Note that |IsCancelled()| and |is_null()| are distinct:
+/// simply cancelling a callback will not also make it null.
+///
+/// See https://chromium.googlesource.com/chromium/src/+/lkgr/docs/callback.md
+/// for the full documentation.
+
+#ifndef CEF_INCLUDE_BASE_CEF_CALLBACK_H_
+#define CEF_INCLUDE_BASE_CEF_CALLBACK_H_
+#pragma once
+
+#if defined(USING_CHROMIUM_INCLUDES)
+// When building CEF include the Chromium header directly.
+#include "base/functional/callback.h"
+#else // !USING_CHROMIUM_INCLUDES
+// The following is substantially similar to the Chromium implementation.
+// If the Chromium implementation diverges the below implementation should be
+// updated to match.
+
+#include <stddef.h>
+
+#include "include/base/cef_bind.h"
+#include "include/base/cef_callback_forward.h"
+#include "include/base/cef_logging.h"
+#include "include/base/internal/cef_callback_internal.h"
+
+namespace base {
+
+template <typename R, typename... Args>
+class OnceCallback<R(Args...)> : public cef_internal::CallbackBase {
+ public:
+ using ResultType = R;
+ using RunType = R(Args...);
+ using PolymorphicInvoke = R (*)(cef_internal::BindStateBase*,
+ cef_internal::PassingType<Args>...);
+
+ constexpr OnceCallback() = default;
+ OnceCallback(std::nullptr_t) = delete;
+
+ explicit OnceCallback(cef_internal::BindStateBase* bind_state)
+ : cef_internal::CallbackBase(bind_state) {}
+
+ OnceCallback(const OnceCallback&) = delete;
+ OnceCallback& operator=(const OnceCallback&) = delete;
+
+ OnceCallback(OnceCallback&&) noexcept = default;
+ OnceCallback& operator=(OnceCallback&&) noexcept = default;
+
+ OnceCallback(RepeatingCallback<RunType> other)
+ : cef_internal::CallbackBase(std::move(other)) {}
+
+ OnceCallback& operator=(RepeatingCallback<RunType> other) {
+ static_cast<cef_internal::CallbackBase&>(*this) = std::move(other);
+ return *this;
+ }
+
+ R Run(Args... args) const& {
+ static_assert(!sizeof(*this),
+ "OnceCallback::Run() may only be invoked on a non-const "
+ "rvalue, i.e. std::move(callback).Run().");
+ NOTREACHED();
+ }
+
+ R Run(Args... args) && {
+ // Move the callback instance into a local variable before the invocation,
+ // that ensures the internal state is cleared after the invocation.
+ // It's not safe to touch |this| after the invocation, since running the
+ // bound function may destroy |this|.
+ OnceCallback cb = std::move(*this);
+ PolymorphicInvoke f =
+ reinterpret_cast<PolymorphicInvoke>(cb.polymorphic_invoke());
+ return f(cb.bind_state_.get(), std::forward<Args>(args)...);
+ }
+
+ // Then() returns a new OnceCallback that receives the same arguments as
+ // |this|, and with the return type of |then|. The returned callback will:
+ // 1) Run the functor currently bound to |this| callback.
+ // 2) Run the |then| callback with the result from step 1 as its single
+ // argument.
+ // 3) Return the value from running the |then| callback.
+ //
+ // Since this method generates a callback that is a replacement for `this`,
+ // `this` will be consumed and reset to a null callback to ensure the
+ // originally-bound functor can be run at most once.
+ template <typename ThenR, typename... ThenArgs>
+ OnceCallback<ThenR(Args...)> Then(OnceCallback<ThenR(ThenArgs...)> then) && {
+ CHECK(then);
+ return BindOnce(
+ cef_internal::ThenHelper<
+ OnceCallback, OnceCallback<ThenR(ThenArgs...)>>::CreateTrampoline(),
+ std::move(*this), std::move(then));
+ }
+
+ // This overload is required; even though RepeatingCallback is implicitly
+ // convertible to OnceCallback, that conversion will not used when matching
+ // for template argument deduction.
+ template <typename ThenR, typename... ThenArgs>
+ OnceCallback<ThenR(Args...)> Then(
+ RepeatingCallback<ThenR(ThenArgs...)> then) && {
+ CHECK(then);
+ return BindOnce(
+ cef_internal::ThenHelper<
+ OnceCallback,
+ RepeatingCallback<ThenR(ThenArgs...)>>::CreateTrampoline(),
+ std::move(*this), std::move(then));
+ }
+};
+
+template <typename R, typename... Args>
+class RepeatingCallback<R(Args...)>
+ : public cef_internal::CallbackBaseCopyable {
+ public:
+ using ResultType = R;
+ using RunType = R(Args...);
+ using PolymorphicInvoke = R (*)(cef_internal::BindStateBase*,
+ cef_internal::PassingType<Args>...);
+
+ constexpr RepeatingCallback() = default;
+ RepeatingCallback(std::nullptr_t) = delete;
+
+ explicit RepeatingCallback(cef_internal::BindStateBase* bind_state)
+ : cef_internal::CallbackBaseCopyable(bind_state) {}
+
+ // Copyable and movable.
+ RepeatingCallback(const RepeatingCallback&) = default;
+ RepeatingCallback& operator=(const RepeatingCallback&) = default;
+ RepeatingCallback(RepeatingCallback&&) noexcept = default;
+ RepeatingCallback& operator=(RepeatingCallback&&) noexcept = default;
+
+ bool operator==(const RepeatingCallback& other) const {
+ return EqualsInternal(other);
+ }
+
+ bool operator!=(const RepeatingCallback& other) const {
+ return !operator==(other);
+ }
+
+ R Run(Args... args) const& {
+ PolymorphicInvoke f =
+ reinterpret_cast<PolymorphicInvoke>(this->polymorphic_invoke());
+ return f(this->bind_state_.get(), std::forward<Args>(args)...);
+ }
+
+ R Run(Args... args) && {
+ // Move the callback instance into a local variable before the invocation,
+ // that ensures the internal state is cleared after the invocation.
+ // It's not safe to touch |this| after the invocation, since running the
+ // bound function may destroy |this|.
+ RepeatingCallback cb = std::move(*this);
+ PolymorphicInvoke f =
+ reinterpret_cast<PolymorphicInvoke>(cb.polymorphic_invoke());
+ return f(std::move(cb).bind_state_.get(), std::forward<Args>(args)...);
+ }
+
+ // Then() returns a new RepeatingCallback that receives the same arguments as
+ // |this|, and with the return type of |then|. The
+ // returned callback will:
+ // 1) Run the functor currently bound to |this| callback.
+ // 2) Run the |then| callback with the result from step 1 as its single
+ // argument.
+ // 3) Return the value from running the |then| callback.
+ //
+ // If called on an rvalue (e.g. std::move(cb).Then(...)), this method
+ // generates a callback that is a replacement for `this`. Therefore, `this`
+ // will be consumed and reset to a null callback to ensure the
+ // originally-bound functor will be run at most once.
+ template <typename ThenR, typename... ThenArgs>
+ RepeatingCallback<ThenR(Args...)> Then(
+ RepeatingCallback<ThenR(ThenArgs...)> then) const& {
+ CHECK(then);
+ return BindRepeating(
+ cef_internal::ThenHelper<
+ RepeatingCallback,
+ RepeatingCallback<ThenR(ThenArgs...)>>::CreateTrampoline(),
+ *this, std::move(then));
+ }
+
+ template <typename ThenR, typename... ThenArgs>
+ RepeatingCallback<ThenR(Args...)> Then(
+ RepeatingCallback<ThenR(ThenArgs...)> then) && {
+ CHECK(then);
+ return BindRepeating(
+ cef_internal::ThenHelper<
+ RepeatingCallback,
+ RepeatingCallback<ThenR(ThenArgs...)>>::CreateTrampoline(),
+ std::move(*this), std::move(then));
+ }
+};
+
+} // namespace base
+
+#endif // !USING_CHROMIUM_INCLUDES
+
+#endif // CEF_INCLUDE_BASE_CEF_CALLBACK_H_
diff --git a/include/base/cef_callback_forward.h b/include/base/cef_callback_forward.h
new file mode 100644
index 00000000..2d227743
--- /dev/null
+++ b/include/base/cef_callback_forward.h
@@ -0,0 +1,63 @@
+// Copyright (c) 2014 Marshall A. Greenblatt. Portions copyright (c) 2011
+// Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef INCLUDE_BASE_CEF_CALLBACK_FORWARD_H_
+#define INCLUDE_BASE_CEF_CALLBACK_FORWARD_H_
+#pragma once
+
+#if defined(USING_CHROMIUM_INCLUDES)
+// When building CEF include the Chromium header directly.
+#include "base/functional/callback_forward.h"
+#else // !USING_CHROMIUM_INCLUDES
+// The following is substantially similar to the Chromium implementation.
+// If the Chromium implementation diverges the below implementation should be
+// updated to match.
+
+namespace base {
+
+template <typename Signature>
+class OnceCallback;
+
+template <typename Signature>
+class RepeatingCallback;
+
+///
+/// Syntactic sugar to make OnceClosure<void()> and RepeatingClosure<void()>
+/// easier to declare since they will be used in a lot of APIs with delayed
+/// execution.
+///
+using OnceClosure = OnceCallback<void()>;
+using RepeatingClosure = RepeatingCallback<void()>;
+
+} // namespace base
+
+#endif // !!USING_CHROMIUM_INCLUDES
+
+#endif // INCLUDE_BASE_CEF_CALLBACK_FORWARD_H_
diff --git a/include/base/cef_callback_helpers.h b/include/base/cef_callback_helpers.h
new file mode 100644
index 00000000..5e386440
--- /dev/null
+++ b/include/base/cef_callback_helpers.h
@@ -0,0 +1,261 @@
+// Copyright (c) 2014 Marshall A. Greenblatt. Portions copyright (c) 2012
+// Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This defines helpful methods for dealing with Callbacks. Because Callbacks
+// are implemented using templates, with a class per callback signature, adding
+// methods to Callback<> itself is unattractive (lots of extra code gets
+// generated). Instead, consider adding methods here.
+
+#ifndef CEF_INCLUDE_BASE_CEF_CALLBACK_HELPERS_H_
+#define CEF_INCLUDE_BASE_CEF_CALLBACK_HELPERS_H_
+#pragma once
+
+#if defined(USING_CHROMIUM_INCLUDES)
+// When building CEF include the Chromium header directly.
+#include "base/functional/callback_helpers.h"
+#else // !USING_CHROMIUM_INCLUDES
+// The following is substantially similar to the Chromium implementation.
+// If the Chromium implementation diverges the below implementation should be
+// updated to match.
+
+#include <atomic>
+#include <memory>
+#include <type_traits>
+#include <utility>
+
+#include "include/base/cef_bind.h"
+#include "include/base/cef_callback.h"
+#include "include/base/cef_logging.h"
+
+namespace base {
+
+namespace internal {
+
+template <typename T>
+struct IsBaseCallbackImpl : std::false_type {};
+
+template <typename R, typename... Args>
+struct IsBaseCallbackImpl<OnceCallback<R(Args...)>> : std::true_type {};
+
+template <typename R, typename... Args>
+struct IsBaseCallbackImpl<RepeatingCallback<R(Args...)>> : std::true_type {};
+
+template <typename T>
+struct IsOnceCallbackImpl : std::false_type {};
+
+template <typename R, typename... Args>
+struct IsOnceCallbackImpl<OnceCallback<R(Args...)>> : std::true_type {};
+
+} // namespace internal
+
+///
+/// IsBaseCallback<T>::value is true when T is any of the Closure or Callback
+/// family of types.
+///
+template <typename T>
+using IsBaseCallback = internal::IsBaseCallbackImpl<std::decay_t<T>>;
+
+///
+/// IsOnceCallback<T>::value is true when T is a OnceClosure or OnceCallback
+/// type.
+///
+template <typename T>
+using IsOnceCallback = internal::IsOnceCallbackImpl<std::decay_t<T>>;
+
+///
+/// SFINAE friendly enabler allowing to overload methods for both Repeating and
+/// OnceCallbacks.
+///
+/// Usage:
+/// <pre>
+/// template <template <typename> class CallbackType,
+/// ... other template args ...,
+/// typename = EnableIfIsBaseCallback<CallbackType>>
+/// void DoStuff(CallbackType<...> cb, ...);
+/// </pre>
+///
+template <template <typename> class CallbackType>
+using EnableIfIsBaseCallback =
+ std::enable_if_t<IsBaseCallback<CallbackType<void()>>::value>;
+
+namespace internal {
+
+template <typename... Args>
+class OnceCallbackHolder final {
+ public:
+ OnceCallbackHolder(OnceCallback<void(Args...)> callback,
+ bool ignore_extra_runs)
+ : callback_(std::move(callback)), ignore_extra_runs_(ignore_extra_runs) {
+ DCHECK(callback_);
+ }
+ OnceCallbackHolder(const OnceCallbackHolder&) = delete;
+ OnceCallbackHolder& operator=(const OnceCallbackHolder&) = delete;
+
+ void Run(Args... args) {
+ if (has_run_.exchange(true)) {
+ CHECK(ignore_extra_runs_) << "Both OnceCallbacks returned by "
+ "base::SplitOnceCallback() were run. "
+ "At most one of the pair should be run.";
+ return;
+ }
+ DCHECK(callback_);
+ std::move(callback_).Run(std::forward<Args>(args)...);
+ }
+
+ private:
+ volatile std::atomic_bool has_run_{false};
+ base::OnceCallback<void(Args...)> callback_;
+ const bool ignore_extra_runs_;
+};
+
+} // namespace internal
+
+///
+/// Wraps the given OnceCallback into a RepeatingCallback that relays its
+/// invocation to the original OnceCallback on the first invocation. The
+/// following invocations are just ignored.
+///
+/// Note that this deliberately subverts the Once/Repeating paradigm of
+/// Callbacks but helps ease the migration from old-style Callbacks. Avoid if
+/// possible; use if necessary for migration.
+///
+// TODO(tzik): Remove it. https://crbug.com/730593
+template <typename... Args>
+RepeatingCallback<void(Args...)> AdaptCallbackForRepeating(
+ OnceCallback<void(Args...)> callback) {
+ using Helper = internal::OnceCallbackHolder<Args...>;
+ return base::BindRepeating(
+ &Helper::Run, std::make_unique<Helper>(std::move(callback),
+ /*ignore_extra_runs=*/true));
+}
+
+///
+/// Wraps the given OnceCallback and returns two OnceCallbacks with an identical
+/// signature. On first invokation of either returned callbacks, the original
+/// callback is invoked. Invoking the remaining callback results in a crash.
+///
+template <typename... Args>
+std::pair<OnceCallback<void(Args...)>, OnceCallback<void(Args...)>>
+SplitOnceCallback(OnceCallback<void(Args...)> callback) {
+ using Helper = internal::OnceCallbackHolder<Args...>;
+ auto wrapped_once = base::BindRepeating(
+ &Helper::Run, std::make_unique<Helper>(std::move(callback),
+ /*ignore_extra_runs=*/false));
+ return std::make_pair(wrapped_once, wrapped_once);
+}
+
+///
+/// ScopedClosureRunner is akin to std::unique_ptr<> for Closures. It ensures
+/// that the Closure is executed no matter how the current scope exits.
+/// If you are looking for "ScopedCallback", "CallbackRunner", or
+/// "CallbackScoper" this is the class you want.
+///
+class ScopedClosureRunner {
+ public:
+ ScopedClosureRunner();
+ explicit ScopedClosureRunner(OnceClosure closure);
+ ScopedClosureRunner(ScopedClosureRunner&& other);
+ // Runs the current closure if it's set, then replaces it with the closure
+ // from |other|. This is akin to how unique_ptr frees the contained pointer in
+ // its move assignment operator. If you need to explicitly avoid running any
+ // current closure, use ReplaceClosure().
+ ScopedClosureRunner& operator=(ScopedClosureRunner&& other);
+ ~ScopedClosureRunner();
+
+ explicit operator bool() const { return !!closure_; }
+
+ // Calls the current closure and resets it, so it wont be called again.
+ void RunAndReset();
+
+ // Replaces closure with the new one releasing the old one without calling it.
+ void ReplaceClosure(OnceClosure closure);
+
+ // Releases the Closure without calling.
+ [[nodiscard]] OnceClosure Release();
+
+ private:
+ OnceClosure closure_;
+};
+
+///
+/// Creates a null callback.
+///
+class NullCallback {
+ public:
+ template <typename R, typename... Args>
+ operator RepeatingCallback<R(Args...)>() const {
+ return RepeatingCallback<R(Args...)>();
+ }
+ template <typename R, typename... Args>
+ operator OnceCallback<R(Args...)>() const {
+ return OnceCallback<R(Args...)>();
+ }
+};
+
+///
+/// Creates a callback that does nothing when called.
+///
+class DoNothing {
+ public:
+ template <typename... Args>
+ operator RepeatingCallback<void(Args...)>() const {
+ return Repeatedly<Args...>();
+ }
+ template <typename... Args>
+ operator OnceCallback<void(Args...)>() const {
+ return Once<Args...>();
+ }
+ // Explicit way of specifying a specific callback type when the compiler can't
+ // deduce it.
+ template <typename... Args>
+ static RepeatingCallback<void(Args...)> Repeatedly() {
+ return BindRepeating([](Args... args) {});
+ }
+ template <typename... Args>
+ static OnceCallback<void(Args...)> Once() {
+ return BindOnce([](Args... args) {});
+ }
+};
+
+///
+/// Useful for creating a Closure that will delete a pointer when invoked. Only
+/// use this when necessary. In most cases MessageLoop::DeleteSoon() is a better
+/// fit.
+///
+template <typename T>
+void DeletePointer(T* obj) {
+ delete obj;
+}
+
+} // namespace base
+
+#endif // !USING_CHROMIUM_INCLUDES
+
+#endif // CEF_INCLUDE_BASE_CEF_CALLBACK_HELPERS_H_
diff --git a/include/base/cef_callback_list.h b/include/base/cef_callback_list.h
new file mode 100644
index 00000000..2038acb7
--- /dev/null
+++ b/include/base/cef_callback_list.h
@@ -0,0 +1,403 @@
+// Copyright (c) 2014 Marshall A. Greenblatt. Portions copyright (c) 2013
+// Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+///
+/// \file
+/// A container for a list of callbacks. Provides callers the ability to
+/// manually or automatically unregister callbacks at any time, including during
+/// callback notification.
+///
+/// TYPICAL USAGE:
+///
+/// <pre>
+/// class MyWidget {
+/// public:
+/// using CallbackList = base::RepeatingCallbackList<void(const Foo&)>;
+///
+/// // Registers |cb| to be called whenever NotifyFoo() is executed.
+/// CallbackListSubscription RegisterCallback(CallbackList::CallbackType cb) {
+/// return callback_list_.Add(std::move(cb));
+/// }
+///
+/// private:
+/// // Calls all registered callbacks, with |foo| as the supplied arg.
+/// void NotifyFoo(const Foo& foo) {
+/// callback_list_.Notify(foo);
+/// }
+///
+/// CallbackList callback_list_;
+/// };
+///
+///
+/// class MyWidgetListener {
+/// private:
+/// void OnFoo(const Foo& foo) {
+/// // Called whenever MyWidget::NotifyFoo() is executed, unless
+/// // |foo_subscription_| has been destroyed.
+/// }
+///
+/// // Automatically deregisters the callback when deleted (e.g. in
+/// // ~MyWidgetListener()). Unretained(this) is safe here since the
+/// // ScopedClosureRunner does not outlive |this|.
+/// CallbackListSubscription foo_subscription_ =
+/// MyWidget::Get()->RegisterCallback(
+/// base::BindRepeating(&MyWidgetListener::OnFoo,
+/// base::Unretained(this)));
+/// };
+/// </pre>
+///
+/// UNSUPPORTED:
+///
+/// * Destroying the CallbackList during callback notification.
+///
+/// This is possible to support, but not currently necessary.
+///
+
+#ifndef CEF_INCLUDE_BASE_CEF_CALLBACK_LIST_H_
+#define CEF_INCLUDE_BASE_CEF_CALLBACK_LIST_H_
+#pragma once
+
+#if defined(USING_CHROMIUM_INCLUDES)
+// When building CEF include the Chromium header directly.
+#include "base/functional/callback_list.h"
+#else // !USING_CHROMIUM_INCLUDES
+// The following is substantially similar to the Chromium implementation.
+// If the Chromium implementation diverges the below implementation should be
+// updated to match.
+
+#include <algorithm>
+#include <list>
+#include <memory>
+#include <utility>
+
+#include "include/base/cef_auto_reset.h"
+#include "include/base/cef_bind.h"
+#include "include/base/cef_callback.h"
+#include "include/base/cef_callback_helpers.h"
+#include "include/base/cef_logging.h"
+#include "include/base/cef_weak_ptr.h"
+
+namespace base {
+namespace internal {
+template <typename CallbackListImpl>
+class CallbackListBase;
+} // namespace internal
+
+template <typename Signature>
+class OnceCallbackList;
+
+template <typename Signature>
+class RepeatingCallbackList;
+
+// A trimmed-down version of ScopedClosureRunner that can be used to guarantee a
+// closure is run on destruction. This is designed to be used by
+// CallbackListBase to run CancelCallback() when this subscription dies;
+// consumers can avoid callbacks on dead objects by ensuring the subscription
+// returned by CallbackListBase::Add() does not outlive the bound object in the
+// callback. A typical way to do this is to bind a callback to a member function
+// on `this` and store the returned subscription as a member variable.
+class CallbackListSubscription {
+ public:
+ CallbackListSubscription();
+ CallbackListSubscription(CallbackListSubscription&& subscription);
+ CallbackListSubscription& operator=(CallbackListSubscription&& subscription);
+ ~CallbackListSubscription();
+
+ explicit operator bool() const { return !!closure_; }
+
+ private:
+ template <typename T>
+ friend class internal::CallbackListBase;
+
+ explicit CallbackListSubscription(base::OnceClosure closure);
+
+ void Run();
+
+ OnceClosure closure_;
+};
+
+namespace internal {
+
+// From base/stl_util.h.
+template <class T, class Allocator, class Predicate>
+size_t EraseIf(std::list<T, Allocator>& container, Predicate pred) {
+ size_t old_size = container.size();
+ container.remove_if(pred);
+ return old_size - container.size();
+}
+
+// A traits class to break circular type dependencies between CallbackListBase
+// and its subclasses.
+template <typename CallbackList>
+struct CallbackListTraits;
+
+// NOTE: It's important that Callbacks provide iterator stability when items are
+// added to the end, so e.g. a std::vector<> is not suitable here.
+template <typename Signature>
+struct CallbackListTraits<OnceCallbackList<Signature>> {
+ using CallbackType = OnceCallback<Signature>;
+ using Callbacks = std::list<CallbackType>;
+};
+template <typename Signature>
+struct CallbackListTraits<RepeatingCallbackList<Signature>> {
+ using CallbackType = RepeatingCallback<Signature>;
+ using Callbacks = std::list<CallbackType>;
+};
+
+template <typename CallbackListImpl>
+class CallbackListBase {
+ public:
+ using CallbackType =
+ typename CallbackListTraits<CallbackListImpl>::CallbackType;
+ static_assert(IsBaseCallback<CallbackType>::value, "");
+
+ // TODO(crbug.com/1103086): Update references to use this directly and by
+ // value, then remove.
+ using Subscription = CallbackListSubscription;
+
+ CallbackListBase() = default;
+ CallbackListBase(const CallbackListBase&) = delete;
+ CallbackListBase& operator=(const CallbackListBase&) = delete;
+
+ ~CallbackListBase() {
+ // Destroying the list during iteration is unsupported and will cause a UAF.
+ CHECK(!iterating_);
+ }
+
+ // Registers |cb| for future notifications. Returns a CallbackListSubscription
+ // whose destruction will cancel |cb|.
+ [[nodiscard]] CallbackListSubscription Add(CallbackType cb) {
+ DCHECK(!cb.is_null());
+ return CallbackListSubscription(base::BindOnce(
+ &CallbackListBase::CancelCallback, weak_ptr_factory_.GetWeakPtr(),
+ callbacks_.insert(callbacks_.end(), std::move(cb))));
+ }
+
+ // Registers |cb| for future notifications. Provides no way for the caller to
+ // cancel, so this is only safe for cases where the callback is guaranteed to
+ // live at least as long as this list (e.g. if it's bound on the same object
+ // that owns the list).
+ // TODO(pkasting): Attempt to use Add() instead and see if callers can relax
+ // other lifetime/ordering mechanisms as a result.
+ void AddUnsafe(CallbackType cb) {
+ DCHECK(!cb.is_null());
+ callbacks_.push_back(std::move(cb));
+ }
+
+ // Registers |removal_callback| to be run after elements are removed from the
+ // list of registered callbacks.
+ void set_removal_callback(const RepeatingClosure& removal_callback) {
+ removal_callback_ = removal_callback;
+ }
+
+ // Returns whether the list of registered callbacks is empty (from an external
+ // perspective -- meaning no remaining callbacks are live).
+ bool empty() const {
+ return std::all_of(callbacks_.cbegin(), callbacks_.cend(),
+ [](const auto& callback) { return callback.is_null(); });
+ }
+
+ // Calls all registered callbacks that are not canceled beforehand. If any
+ // callbacks are unregistered, notifies any registered removal callback at the
+ // end.
+ //
+ // Arguments must be copyable, since they must be supplied to all callbacks.
+ // Move-only types would be destructively modified by passing them to the
+ // first callback and not reach subsequent callbacks as intended.
+ //
+ // Notify() may be called re-entrantly, in which case the nested call
+ // completes before the outer one continues. Callbacks are only ever added at
+ // the end and canceled callbacks are not pruned from the list until the
+ // outermost iteration completes, so existing iterators should never be
+ // invalidated. However, this does mean that a callback added during a nested
+ // call can be notified by outer calls -- meaning it will be notified about
+ // things that happened before it was added -- if its subscription outlives
+ // the reentrant Notify() call.
+ template <typename... RunArgs>
+ void Notify(RunArgs&&... args) {
+ if (empty()) {
+ return; // Nothing to do.
+ }
+
+ {
+ AutoReset<bool> iterating(&iterating_, true);
+
+ // Skip any callbacks that are canceled during iteration.
+ // NOTE: Since RunCallback() may call Add(), it's not safe to cache the
+ // value of callbacks_.end() across loop iterations.
+ const auto next_valid = [this](const auto it) {
+ return std::find_if_not(it, callbacks_.end(), [](const auto& callback) {
+ return callback.is_null();
+ });
+ };
+ for (auto it = next_valid(callbacks_.begin()); it != callbacks_.end();
+ it = next_valid(it)) {
+ // NOTE: Intentionally does not call std::forward<RunArgs>(args)...,
+ // since that would allow move-only arguments.
+ static_cast<CallbackListImpl*>(this)->RunCallback(it++, args...);
+ }
+ }
+
+ // Re-entrant invocations shouldn't prune anything from the list. This can
+ // invalidate iterators from underneath higher call frames. It's safe to
+ // simply do nothing, since the outermost frame will continue through here
+ // and prune all null callbacks below.
+ if (iterating_) {
+ return;
+ }
+
+ // Any null callbacks remaining in the list were canceled due to
+ // Subscription destruction during iteration, and can safely be erased now.
+ const size_t erased_callbacks =
+ EraseIf(callbacks_, [](const auto& cb) { return cb.is_null(); });
+
+ // Run |removal_callback_| if any callbacks were canceled. Note that we
+ // cannot simply compare list sizes before and after iterating, since
+ // notification may result in Add()ing new callbacks as well as canceling
+ // them. Also note that if this is a OnceCallbackList, the OnceCallbacks
+ // that were executed above have all been removed regardless of whether
+ // they're counted in |erased_callbacks_|.
+ if (removal_callback_ &&
+ (erased_callbacks || IsOnceCallback<CallbackType>::value)) {
+ removal_callback_.Run(); // May delete |this|!
+ }
+ }
+
+ protected:
+ using Callbacks = typename CallbackListTraits<CallbackListImpl>::Callbacks;
+
+ // Holds non-null callbacks, which will be called during Notify().
+ Callbacks callbacks_;
+
+ private:
+ // Cancels the callback pointed to by |it|, which is guaranteed to be valid.
+ void CancelCallback(const typename Callbacks::iterator& it) {
+ if (static_cast<CallbackListImpl*>(this)->CancelNullCallback(it)) {
+ return;
+ }
+
+ if (iterating_) {
+ // Calling erase() here is unsafe, since the loop in Notify() may be
+ // referencing this same iterator, e.g. if adjacent callbacks'
+ // Subscriptions are both destroyed when the first one is Run(). Just
+ // reset the callback and let Notify() clean it up at the end.
+ it->Reset();
+ } else {
+ callbacks_.erase(it);
+ if (removal_callback_) {
+ removal_callback_.Run(); // May delete |this|!
+ }
+ }
+ }
+
+ // Set while Notify() is traversing |callbacks_|. Used primarily to avoid
+ // invalidating iterators that may be in use.
+ bool iterating_ = false;
+
+ // Called after elements are removed from |callbacks_|.
+ RepeatingClosure removal_callback_;
+
+ WeakPtrFactory<CallbackListBase> weak_ptr_factory_{this};
+};
+
+} // namespace internal
+
+template <typename Signature>
+class OnceCallbackList
+ : public internal::CallbackListBase<OnceCallbackList<Signature>> {
+ private:
+ friend internal::CallbackListBase<OnceCallbackList>;
+ using Traits = internal::CallbackListTraits<OnceCallbackList>;
+
+ // Runs the current callback, which may cancel it or any other callbacks.
+ template <typename... RunArgs>
+ void RunCallback(typename Traits::Callbacks::iterator it, RunArgs&&... args) {
+ // OnceCallbacks still have Subscriptions with outstanding iterators;
+ // splice() removes them from |callbacks_| without invalidating those.
+ null_callbacks_.splice(null_callbacks_.end(), this->callbacks_, it);
+
+ // NOTE: Intentionally does not call std::forward<RunArgs>(args)...; see
+ // comments in Notify().
+ std::move(*it).Run(args...);
+ }
+
+ // If |it| refers to an already-canceled callback, does any necessary cleanup
+ // and returns true. Otherwise returns false.
+ bool CancelNullCallback(const typename Traits::Callbacks::iterator& it) {
+ if (it->is_null()) {
+ null_callbacks_.erase(it);
+ return true;
+ }
+ return false;
+ }
+
+ // Holds null callbacks whose Subscriptions are still alive, so the
+ // Subscriptions will still contain valid iterators. Only needed for
+ // OnceCallbacks, since RepeatingCallbacks are not canceled except by
+ // Subscription destruction.
+ typename Traits::Callbacks null_callbacks_;
+};
+
+template <typename Signature>
+class RepeatingCallbackList
+ : public internal::CallbackListBase<RepeatingCallbackList<Signature>> {
+ private:
+ friend internal::CallbackListBase<RepeatingCallbackList>;
+ using Traits = internal::CallbackListTraits<RepeatingCallbackList>;
+ // Runs the current callback, which may cancel it or any other callbacks.
+ template <typename... RunArgs>
+ void RunCallback(typename Traits::Callbacks::iterator it, RunArgs&&... args) {
+ // NOTE: Intentionally does not call std::forward<RunArgs>(args)...; see
+ // comments in Notify().
+ it->Run(args...);
+ }
+
+ // If |it| refers to an already-canceled callback, does any necessary cleanup
+ // and returns true. Otherwise returns false.
+ bool CancelNullCallback(const typename Traits::Callbacks::iterator& it) {
+ // Because at most one Subscription can point to a given callback, and
+ // RepeatingCallbacks are only reset by CancelCallback(), no one should be
+ // able to request cancellation of a canceled RepeatingCallback.
+ DCHECK(!it->is_null());
+ return false;
+ }
+};
+
+///
+/// Syntactic sugar to parallel that used for Callbacks.
+///
+using OnceClosureList = OnceCallbackList<void()>;
+using RepeatingClosureList = RepeatingCallbackList<void()>;
+
+} // namespace base
+
+#endif // !USING_CHROMIUM_INCLUDES
+
+#endif // CEF_INCLUDE_BASE_CEF_CALLBACK_LIST_H_
diff --git a/include/base/cef_cancelable_callback.h b/include/base/cef_cancelable_callback.h
new file mode 100644
index 00000000..35631491
--- /dev/null
+++ b/include/base/cef_cancelable_callback.h
@@ -0,0 +1,195 @@
+// Copyright (c) 2014 Marshall A. Greenblatt. Portions copyright (c) 2011
+// Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+///
+/// \file
+/// CancelableCallback is a wrapper around base::Callback that allows
+/// cancellation of a callback. CancelableCallback takes a reference on the
+/// wrapped callback until this object is destroyed or Reset()/Cancel() are
+/// called.
+///
+/// NOTE:
+///
+/// Calling CancelableCallback::Cancel() brings the object back to its natural,
+/// default-constructed state, i.e., CancelableCallback::callback() will return
+/// a null callback.
+///
+/// THREAD-SAFETY:
+///
+/// CancelableCallback objects must be created on, posted to, cancelled on, and
+/// destroyed on the same thread.
+///
+///
+/// EXAMPLE USAGE:
+///
+/// In the following example, the test is verifying that RunIntensiveTest()
+/// Quit()s the message loop within 4 seconds. The cancelable callback is posted
+/// to the message loop, the intensive test runs, the message loop is run,
+/// then the callback is cancelled.
+///
+/// <pre>
+/// RunLoop run_loop;
+///
+/// void TimeoutCallback(const std::string& timeout_message) {
+/// FAIL() << timeout_message;
+/// run_loop.QuitWhenIdle();
+/// }
+///
+/// CancelableOnceClosure timeout(
+/// base::BindOnce(&TimeoutCallback, "Test timed out."));
+/// ThreadTaskRunnerHandle::Get()->PostDelayedTask(FROM_HERE,
+/// timeout.callback(),
+/// TimeDelta::FromSeconds(4));
+/// RunIntensiveTest();
+/// run_loop.Run();
+/// // Hopefully this is hit before the timeout callback runs.
+/// timeout.Cancel();
+/// </pre>
+///
+
+#ifndef CEF_INCLUDE_BASE_CEF_CANCELABLE_CALLBACK_H_
+#define CEF_INCLUDE_BASE_CEF_CANCELABLE_CALLBACK_H_
+#pragma once
+
+#if defined(USING_CHROMIUM_INCLUDES)
+// When building CEF include the Chromium header directly.
+#include "base/cancelable_callback.h"
+#else // !USING_CHROMIUM_INCLUDES
+// The following is substantially similar to the Chromium implementation.
+// If the Chromium implementation diverges the below implementation should be
+// updated to match.
+
+#include <utility>
+
+#include "include/base/cef_bind.h"
+#include "include/base/cef_callback.h"
+#include "include/base/cef_compiler_specific.h"
+#include "include/base/cef_logging.h"
+#include "include/base/cef_weak_ptr.h"
+#include "include/base/internal/cef_callback_internal.h"
+
+namespace base {
+namespace internal {
+
+template <typename CallbackType>
+class CancelableCallbackImpl {
+ public:
+ CancelableCallbackImpl() = default;
+ CancelableCallbackImpl(const CancelableCallbackImpl&) = delete;
+ CancelableCallbackImpl& operator=(const CancelableCallbackImpl&) = delete;
+
+ // |callback| must not be null.
+ explicit CancelableCallbackImpl(CallbackType callback)
+ : callback_(std::move(callback)) {
+ DCHECK(callback_);
+ }
+
+ ~CancelableCallbackImpl() = default;
+
+ // Cancels and drops the reference to the wrapped callback.
+ void Cancel() {
+ weak_ptr_factory_.InvalidateWeakPtrs();
+ callback_.Reset();
+ }
+
+ // Returns true if the wrapped callback has been cancelled.
+ bool IsCancelled() const { return callback_.is_null(); }
+
+ // Sets |callback| as the closure that may be cancelled. |callback| may not
+ // be null. Outstanding and any previously wrapped callbacks are cancelled.
+ void Reset(CallbackType callback) {
+ DCHECK(callback);
+ // Outstanding tasks (e.g., posted to a message loop) must not be called.
+ Cancel();
+ callback_ = std::move(callback);
+ }
+
+ // Returns a callback that can be disabled by calling Cancel().
+ CallbackType callback() const {
+ if (!callback_) {
+ return CallbackType();
+ }
+ CallbackType forwarder;
+ MakeForwarder(&forwarder);
+ return forwarder;
+ }
+
+ private:
+ template <typename... Args>
+ void MakeForwarder(RepeatingCallback<void(Args...)>* out) const {
+ using ForwarderType = void (CancelableCallbackImpl::*)(Args...);
+ ForwarderType forwarder = &CancelableCallbackImpl::ForwardRepeating;
+ *out = BindRepeating(forwarder, weak_ptr_factory_.GetWeakPtr());
+ }
+
+ template <typename... Args>
+ void MakeForwarder(OnceCallback<void(Args...)>* out) const {
+ using ForwarderType = void (CancelableCallbackImpl::*)(Args...);
+ ForwarderType forwarder = &CancelableCallbackImpl::ForwardOnce;
+ *out = BindOnce(forwarder, weak_ptr_factory_.GetWeakPtr());
+ }
+
+ template <typename... Args>
+ void ForwardRepeating(Args... args) {
+ callback_.Run(std::forward<Args>(args)...);
+ }
+
+ template <typename... Args>
+ void ForwardOnce(Args... args) {
+ weak_ptr_factory_.InvalidateWeakPtrs();
+ std::move(callback_).Run(std::forward<Args>(args)...);
+ }
+
+ // The stored closure that may be cancelled.
+ CallbackType callback_;
+ mutable base::WeakPtrFactory<CancelableCallbackImpl> weak_ptr_factory_{this};
+};
+
+} // namespace internal
+
+///
+/// Consider using base::WeakPtr directly instead of base::CancelableCallback
+/// for the task cancellation.
+///
+template <typename Signature>
+using CancelableOnceCallback =
+ internal::CancelableCallbackImpl<OnceCallback<Signature>>;
+using CancelableOnceClosure = CancelableOnceCallback<void()>;
+
+template <typename Signature>
+using CancelableRepeatingCallback =
+ internal::CancelableCallbackImpl<RepeatingCallback<Signature>>;
+using CancelableRepeatingClosure = CancelableRepeatingCallback<void()>;
+
+} // namespace base
+
+#endif // !USING_CHROMIUM_INCLUDES
+
+#endif // CEF_INCLUDE_BASE_CEF_CANCELABLE_CALLBACK_H_
diff --git a/include/base/cef_compiler_specific.h b/include/base/cef_compiler_specific.h
new file mode 100644
index 00000000..06d1bbaa
--- /dev/null
+++ b/include/base/cef_compiler_specific.h
@@ -0,0 +1,389 @@
+// Copyright (c) 2021 Marshall A. Greenblatt. Portions copyright (c) 2012
+// Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CEF_INCLUDE_BASE_CEF_COMPILER_SPECIFIC_H_
+#define CEF_INCLUDE_BASE_CEF_COMPILER_SPECIFIC_H_
+#pragma once
+
+#if defined(USING_CHROMIUM_INCLUDES)
+// When building CEF include the Chromium header directly.
+#include "base/compiler_specific.h"
+#else // !USING_CHROMIUM_INCLUDES
+// The following is substantially similar to the Chromium implementation.
+// If the Chromium implementation diverges the below implementation should be
+// updated to match.
+
+#include "include/base/cef_build.h"
+
+// This is a wrapper around `__has_cpp_attribute`, which can be used to test for
+// the presence of an attribute. In case the compiler does not support this
+// macro it will simply evaluate to 0.
+//
+// References:
+// https://wg21.link/sd6#testing-for-the-presence-of-an-attribute-__has_cpp_attribute
+// https://wg21.link/cpp.cond#:__has_cpp_attribute
+#if defined(__has_cpp_attribute)
+#define HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)
+#else
+#define HAS_CPP_ATTRIBUTE(x) 0
+#endif
+
+// A wrapper around `__has_builtin`, similar to HAS_CPP_ATTRIBUTE.
+#if defined(__has_builtin)
+#define HAS_BUILTIN(x) __has_builtin(x)
+#else
+#define HAS_BUILTIN(x) 0
+#endif
+
+// __has_feature and __has_attribute don't exist for MSVC.
+#if !defined(__has_feature)
+#define __has_feature(x) 0
+#endif // !defined(__has_feature)
+
+#if !defined(__has_attribute)
+#define __has_attribute(x) 0
+#endif // !defined(__has_attribute)
+
+// Annotate a function indicating it should not be inlined.
+// Use like:
+// NOINLINE void DoStuff() { ... }
+#if defined(COMPILER_GCC)
+#define NOINLINE __attribute__((noinline))
+#elif defined(COMPILER_MSVC)
+#define NOINLINE __declspec(noinline)
+#else
+#define NOINLINE
+#endif
+
+#if defined(COMPILER_GCC) && defined(NDEBUG)
+#define ALWAYS_INLINE inline __attribute__((__always_inline__))
+#elif defined(COMPILER_MSVC) && defined(NDEBUG)
+#define ALWAYS_INLINE __forceinline
+#else
+#define ALWAYS_INLINE inline
+#endif
+
+// Annotate a function indicating it should never be tail called. Useful to make
+// sure callers of the annotated function are never omitted from call-stacks.
+// To provide the complementary behavior (prevent the annotated function from
+// being omitted) look at NOINLINE. Also note that this doesn't prevent code
+// folding of multiple identical caller functions into a single signature. To
+// prevent code folding, see NO_CODE_FOLDING() in base/debug/alias.h.
+// Use like:
+// void NOT_TAIL_CALLED FooBar();
+#if defined(__clang__) && __has_attribute(not_tail_called)
+#define NOT_TAIL_CALLED __attribute__((not_tail_called))
+#else
+#define NOT_TAIL_CALLED
+#endif
+
+// Specify memory alignment for structs, classes, etc.
+// Use like:
+// class ALIGNAS(16) MyClass { ... }
+// ALIGNAS(16) int array[4];
+//
+// In most places you can use the C++11 keyword "alignas", which is preferred.
+//
+// But compilers have trouble mixing __attribute__((...)) syntax with
+// alignas(...) syntax.
+//
+// Doesn't work in clang or gcc:
+// struct alignas(16) __attribute__((packed)) S { char c; };
+// Works in clang but not gcc:
+// struct __attribute__((packed)) alignas(16) S2 { char c; };
+// Works in clang and gcc:
+// struct alignas(16) S3 { char c; } __attribute__((packed));
+//
+// There are also some attributes that must be specified *before* a class
+// definition: visibility (used for exporting functions/classes) is one of
+// these attributes. This means that it is not possible to use alignas() with a
+// class that is marked as exported.
+#if defined(COMPILER_MSVC)
+#define ALIGNAS(byte_alignment) __declspec(align(byte_alignment))
+#elif defined(COMPILER_GCC)
+#define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment)))
+#endif
+
+// In case the compiler supports it NO_UNIQUE_ADDRESS evaluates to the C++20
+// attribute [[no_unique_address]]. This allows annotating data members so that
+// they need not have an address distinct from all other non-static data members
+// of its class.
+//
+// References:
+// * https://en.cppreference.com/w/cpp/language/attributes/no_unique_address
+// * https://wg21.link/dcl.attr.nouniqueaddr
+#if HAS_CPP_ATTRIBUTE(no_unique_address)
+#define NO_UNIQUE_ADDRESS [[no_unique_address]]
+#else
+#define NO_UNIQUE_ADDRESS
+#endif
+
+// Tell the compiler a function is using a printf-style format string.
+// |format_param| is the one-based index of the format string parameter;
+// |dots_param| is the one-based index of the "..." parameter.
+// For v*printf functions (which take a va_list), pass 0 for dots_param.
+// (This is undocumented but matches what the system C headers do.)
+// For member functions, the implicit this parameter counts as index 1.
+#if defined(COMPILER_GCC) || defined(__clang__)
+#define PRINTF_FORMAT(format_param, dots_param) \
+ __attribute__((format(printf, format_param, dots_param)))
+#else
+#define PRINTF_FORMAT(format_param, dots_param)
+#endif
+
+// WPRINTF_FORMAT is the same, but for wide format strings.
+// This doesn't appear to yet be implemented in any compiler.
+// See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=38308 .
+#define WPRINTF_FORMAT(format_param, dots_param)
+// If available, it would look like:
+// __attribute__((format(wprintf, format_param, dots_param)))
+
+// Sanitizers annotations.
+#if defined(__has_attribute)
+#if __has_attribute(no_sanitize)
+#define NO_SANITIZE(what) __attribute__((no_sanitize(what)))
+#endif
+#endif
+#if !defined(NO_SANITIZE)
+#define NO_SANITIZE(what)
+#endif
+
+// MemorySanitizer annotations.
+#if defined(MEMORY_SANITIZER) && !defined(OS_NACL)
+#include <sanitizer/msan_interface.h>
+
+// Mark a memory region fully initialized.
+// Use this to annotate code that deliberately reads uninitialized data, for
+// example a GC scavenging root set pointers from the stack.
+#define MSAN_UNPOISON(p, size) __msan_unpoison(p, size)
+
+// Check a memory region for initializedness, as if it was being used here.
+// If any bits are uninitialized, crash with an MSan report.
+// Use this to sanitize data which MSan won't be able to track, e.g. before
+// passing data to another process via shared memory.
+#define MSAN_CHECK_MEM_IS_INITIALIZED(p, size) \
+ __msan_check_mem_is_initialized(p, size)
+#else // MEMORY_SANITIZER
+#define MSAN_UNPOISON(p, size)
+#define MSAN_CHECK_MEM_IS_INITIALIZED(p, size)
+#endif // MEMORY_SANITIZER
+
+// DISABLE_CFI_PERF -- Disable Control Flow Integrity for perf reasons.
+#if !defined(DISABLE_CFI_PERF)
+#if defined(__clang__) && defined(OFFICIAL_BUILD)
+#define DISABLE_CFI_PERF __attribute__((no_sanitize("cfi")))
+#else
+#define DISABLE_CFI_PERF
+#endif
+#endif
+
+// DISABLE_CFI_ICALL -- Disable Control Flow Integrity indirect call checks.
+#if !defined(DISABLE_CFI_ICALL)
+#if defined(OS_WIN)
+// Windows also needs __declspec(guard(nocf)).
+#define DISABLE_CFI_ICALL NO_SANITIZE("cfi-icall") __declspec(guard(nocf))
+#else
+#define DISABLE_CFI_ICALL NO_SANITIZE("cfi-icall")
+#endif
+#endif
+#if !defined(DISABLE_CFI_ICALL)
+#define DISABLE_CFI_ICALL
+#endif
+
+// Macro useful for writing cross-platform function pointers.
+#if !defined(CDECL)
+#if defined(OS_WIN)
+#define CDECL __cdecl
+#else // defined(OS_WIN)
+#define CDECL
+#endif // defined(OS_WIN)
+#endif // !defined(CDECL)
+
+// Macro for hinting that an expression is likely to be false.
+#if !defined(UNLIKELY)
+#if defined(COMPILER_GCC) || defined(__clang__)
+#define UNLIKELY(x) __builtin_expect(!!(x), 0)
+#else
+#define UNLIKELY(x) (x)
+#endif // defined(COMPILER_GCC)
+#endif // !defined(UNLIKELY)
+
+#if !defined(LIKELY)
+#if defined(COMPILER_GCC) || defined(__clang__)
+#define LIKELY(x) __builtin_expect(!!(x), 1)
+#else
+#define LIKELY(x) (x)
+#endif // defined(COMPILER_GCC)
+#endif // !defined(LIKELY)
+
+// Compiler feature-detection.
+// clang.llvm.org/docs/LanguageExtensions.html#has-feature-and-has-extension
+#if defined(__has_feature)
+#define HAS_FEATURE(FEATURE) __has_feature(FEATURE)
+#else
+#define HAS_FEATURE(FEATURE) 0
+#endif
+
+// Macro for telling -Wimplicit-fallthrough that a fallthrough is intentional.
+#if defined(__clang__)
+#define FALLTHROUGH [[clang::fallthrough]]
+#else
+#define FALLTHROUGH
+#endif
+
+#if defined(COMPILER_GCC)
+#define PRETTY_FUNCTION __PRETTY_FUNCTION__
+#elif defined(COMPILER_MSVC)
+#define PRETTY_FUNCTION __FUNCSIG__
+#else
+// See https://en.cppreference.com/w/c/language/function_definition#func
+#define PRETTY_FUNCTION __func__
+#endif
+
+#if !defined(CPU_ARM_NEON)
+#if defined(__arm__)
+#if !defined(__ARMEB__) && !defined(__ARM_EABI__) && !defined(__EABI__) && \
+ !defined(__VFP_FP__) && !defined(_WIN32_WCE) && !defined(ANDROID)
+#error Chromium does not support middle endian architecture
+#endif
+#if defined(__ARM_NEON__)
+#define CPU_ARM_NEON 1
+#endif
+#endif // defined(__arm__)
+#endif // !defined(CPU_ARM_NEON)
+
+#if !defined(HAVE_MIPS_MSA_INTRINSICS)
+#if defined(__mips_msa) && defined(__mips_isa_rev) && (__mips_isa_rev >= 5)
+#define HAVE_MIPS_MSA_INTRINSICS 1
+#endif
+#endif
+
+#if defined(__clang__) && __has_attribute(uninitialized)
+// Attribute "uninitialized" disables -ftrivial-auto-var-init=pattern for
+// the specified variable.
+// Library-wide alternative is
+// 'configs -= [ "//build/config/compiler:default_init_stack_vars" ]' in .gn
+// file.
+//
+// See "init_stack_vars" in build/config/compiler/BUILD.gn and
+// http://crbug.com/977230
+// "init_stack_vars" is enabled for non-official builds and we hope to enable it
+// in official build in 2020 as well. The flag writes fixed pattern into
+// uninitialized parts of all local variables. In rare cases such initialization
+// is undesirable and attribute can be used:
+// 1. Degraded performance
+// In most cases compiler is able to remove additional stores. E.g. if memory is
+// never accessed or properly initialized later. Preserved stores mostly will
+// not affect program performance. However if compiler failed on some
+// performance critical code we can get a visible regression in a benchmark.
+// 2. memset, memcpy calls
+// Compiler may replaces some memory writes with memset or memcpy calls. This is
+// not -ftrivial-auto-var-init specific, but it can happen more likely with the
+// flag. It can be a problem if code is not linked with C run-time library.
+//
+// Note: The flag is security risk mitigation feature. So in future the
+// attribute uses should be avoided when possible. However to enable this
+// mitigation on the most of the code we need to be less strict now and minimize
+// number of exceptions later. So if in doubt feel free to use attribute, but
+// please document the problem for someone who is going to cleanup it later.
+// E.g. platform, bot, benchmark or test name in patch description or next to
+// the attribute.
+#define STACK_UNINITIALIZED __attribute__((uninitialized))
+#else
+#define STACK_UNINITIALIZED
+#endif
+
+// The ANALYZER_ASSUME_TRUE(bool arg) macro adds compiler-specific hints
+// to Clang which control what code paths are statically analyzed,
+// and is meant to be used in conjunction with assert & assert-like functions.
+// The expression is passed straight through if analysis isn't enabled.
+//
+// ANALYZER_SKIP_THIS_PATH() suppresses static analysis for the current
+// codepath and any other branching codepaths that might follow.
+#if defined(__clang_analyzer__)
+
+inline constexpr bool AnalyzerNoReturn() __attribute__((analyzer_noreturn)) {
+ return false;
+}
+
+inline constexpr bool AnalyzerAssumeTrue(bool arg) {
+ // AnalyzerNoReturn() is invoked and analysis is terminated if |arg| is
+ // false.
+ return arg || AnalyzerNoReturn();
+}
+
+#define ANALYZER_ASSUME_TRUE(arg) ::AnalyzerAssumeTrue(!!(arg))
+#define ANALYZER_SKIP_THIS_PATH() static_cast<void>(::AnalyzerNoReturn())
+#define ANALYZER_ALLOW_UNUSED(var) static_cast<void>(var);
+
+#else // !defined(__clang_analyzer__)
+
+#define ANALYZER_ASSUME_TRUE(arg) (arg)
+#define ANALYZER_SKIP_THIS_PATH()
+#define ANALYZER_ALLOW_UNUSED(var) static_cast<void>(var);
+
+#endif // defined(__clang_analyzer__)
+
+// Use nomerge attribute to disable optimization of merging multiple same calls.
+#if defined(__clang__) && __has_attribute(nomerge)
+#define NOMERGE [[clang::nomerge]]
+#else
+#define NOMERGE
+#endif
+
+// Marks a type as being eligible for the "trivial" ABI despite having a
+// non-trivial destructor or copy/move constructor. Such types can be relocated
+// after construction by simply copying their memory, which makes them eligible
+// to be passed in registers. The canonical example is std::unique_ptr.
+//
+// Use with caution; this has some subtle effects on constructor/destructor
+// ordering and will be very incorrect if the type relies on its address
+// remaining constant. When used as a function argument (by value), the value
+// may be constructed in the caller's stack frame, passed in a register, and
+// then used and destructed in the callee's stack frame. A similar thing can
+// occur when values are returned.
+//
+// TRIVIAL_ABI is not needed for types which have a trivial destructor and
+// copy/move constructors, such as base::TimeTicks and other POD.
+//
+// It is also not likely to be effective on types too large to be passed in one
+// or two registers on typical target ABIs.
+//
+// See also:
+// https://clang.llvm.org/docs/AttributeReference.html#trivial-abi
+// https://libcxx.llvm.org/docs/DesignDocs/UniquePtrTrivialAbi.html
+#if defined(__clang__) && __has_attribute(trivial_abi)
+#define TRIVIAL_ABI [[clang::trivial_abi]]
+#else
+#define TRIVIAL_ABI
+#endif
+
+#endif // !USING_CHROMIUM_INCLUDES
+#endif // CEF_INCLUDE_BASE_CEF_COMPILER_SPECIFIC_H_
diff --git a/include/base/cef_lock.h b/include/base/cef_lock.h
new file mode 100644
index 00000000..27af8aeb
--- /dev/null
+++ b/include/base/cef_lock.h
@@ -0,0 +1,182 @@
+// Copyright (c) 2014 Marshall A. Greenblatt. Portions copyright (c) 2011
+// Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CEF_INCLUDE_BASE_CEF_LOCK_H_
+#define CEF_INCLUDE_BASE_CEF_LOCK_H_
+#pragma once
+
+#if defined(USING_CHROMIUM_INCLUDES)
+// When building CEF include the Chromium header directly.
+#include "base/synchronization/lock.h"
+#else // !USING_CHROMIUM_INCLUDES
+// The following is substantially similar to the Chromium implementation.
+// If the Chromium implementation diverges the below implementation should be
+// updated to match.
+
+#include "include/base/cef_logging.h"
+#include "include/base/cef_platform_thread.h"
+#include "include/base/internal/cef_lock_impl.h"
+
+namespace base {
+namespace cef_internal {
+
+///
+/// A convenient wrapper for an OS specific critical section. The only real
+/// intelligence in this class is in debug mode for the support for the
+/// AssertAcquired() method.
+///
+class Lock {
+ public:
+#if !DCHECK_IS_ON() // Optimized wrapper implementation
+ Lock() : lock_() {}
+
+ Lock(const Lock&) = delete;
+ Lock& operator=(const Lock&) = delete;
+
+ ~Lock() {}
+ void Acquire() { lock_.Lock(); }
+ void Release() { lock_.Unlock(); }
+
+ ///
+ /// If the lock is not held, take it and return true. If the lock is already
+ /// held by another thread, immediately return false. This must not be called
+ /// by a thread already holding the lock (what happens is undefined and an
+ /// assertion may fail).
+ ///
+ bool Try() { return lock_.Try(); }
+
+ // Null implementation if not debug.
+ void AssertAcquired() const {}
+#else
+ Lock();
+ ~Lock();
+
+ // NOTE: Although windows critical sections support recursive locks, we do not
+ // allow this, and we will commonly fire a DCHECK() if a thread attempts to
+ // acquire the lock a second time (while already holding it).
+ void Acquire() {
+ lock_.Lock();
+ CheckUnheldAndMark();
+ }
+ void Release() {
+ CheckHeldAndUnmark();
+ lock_.Unlock();
+ }
+
+ bool Try() {
+ bool rv = lock_.Try();
+ if (rv) {
+ CheckUnheldAndMark();
+ }
+ return rv;
+ }
+
+ void AssertAcquired() const;
+#endif // !DCHECK_IS_ON()
+
+ private:
+#if DCHECK_IS_ON()
+ // Members and routines taking care of locks assertions.
+ // Note that this checks for recursive locks and allows them
+ // if the variable is set. This is allowed by the underlying implementation
+ // on windows but not on Posix, so we're doing unneeded checks on Posix.
+ // It's worth it to share the code.
+ void CheckHeldAndUnmark();
+ void CheckUnheldAndMark();
+
+ // All private data is implicitly protected by lock_.
+ // Be VERY careful to only access members under that lock.
+ base::PlatformThreadRef owning_thread_ref_;
+#endif // DCHECK_IS_ON()
+
+ // Platform specific underlying lock implementation.
+ LockImpl lock_;
+};
+
+///
+/// A helper class that acquires the given Lock while the AutoLock is in scope.
+///
+class AutoLock {
+ public:
+ struct AlreadyAcquired {};
+
+ explicit AutoLock(Lock& lock) : lock_(lock) { lock_.Acquire(); }
+
+ AutoLock(Lock& lock, const AlreadyAcquired&) : lock_(lock) {
+ lock_.AssertAcquired();
+ }
+
+ AutoLock(const AutoLock&) = delete;
+ AutoLock& operator=(const AutoLock&) = delete;
+
+ ~AutoLock() {
+ lock_.AssertAcquired();
+ lock_.Release();
+ }
+
+ private:
+ Lock& lock_;
+};
+
+///
+/// AutoUnlock is a helper that will Release() the |lock| argument in the
+/// constructor, and re-Acquire() it in the destructor.
+///
+class AutoUnlock {
+ public:
+ explicit AutoUnlock(Lock& lock) : lock_(lock) {
+ // We require our caller to have the lock.
+ lock_.AssertAcquired();
+ lock_.Release();
+ }
+
+ AutoUnlock(const AutoUnlock&) = delete;
+ AutoUnlock& operator=(const AutoUnlock&) = delete;
+
+ ~AutoUnlock() { lock_.Acquire(); }
+
+ private:
+ Lock& lock_;
+};
+
+} // namespace cef_internal
+
+// Implement classes in the cef_internal namespace and then expose them to the
+// base namespace. This avoids conflicts with the base.lib implementation when
+// linking sandbox support on Windows.
+using cef_internal::AutoLock;
+using cef_internal::AutoUnlock;
+using cef_internal::Lock;
+
+} // namespace base
+
+#endif // !USING_CHROMIUM_INCLUDES
+
+#endif // CEF_INCLUDE_BASE_CEF_LOCK_H_
diff --git a/include/base/cef_logging.h b/include/base/cef_logging.h
new file mode 100644
index 00000000..bae61c4f
--- /dev/null
+++ b/include/base/cef_logging.h
@@ -0,0 +1,778 @@
+// Copyright (c) 2014 Marshall A. Greenblatt. Portions copyright (c) 2012
+// Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+///
+/// \file
+/// A bunch of macros for logging.
+///
+/// NOTE: The contents of this file are only available to applications that link
+/// against the libcef_dll_wrapper target.
+///
+/// WARNING: Logging macros should not be used in the main/browser process
+/// before calling CefInitialize or in sub-processes before calling
+/// CefExecuteProcess.
+///
+/// INSTRUCTIONS:
+///
+/// The way to log things is to stream things to LOG(<a particular severity
+/// level>). E.g.,
+///
+/// <pre>
+/// LOG(INFO) << "Found " << num_cookies << " cookies";
+/// </pre>
+///
+/// You can also do conditional logging:
+///
+/// <pre>
+/// LOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
+/// </pre>
+///
+/// The CHECK(condition) macro is active in both debug and release builds and
+/// effectively performs a LOG(FATAL) which terminates the process and
+/// generates a crashdump unless a debugger is attached.
+///
+/// There are also "debug mode" logging macros like the ones above:
+///
+/// <pre>
+/// DLOG(INFO) << "Found cookies";
+///
+/// DLOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
+/// </pre>
+///
+/// All "debug mode" logging is compiled away to nothing for non-debug mode
+/// compiles. LOG_IF and development flags also work well together
+/// because the code can be compiled away sometimes.
+///
+/// We also have
+///
+/// <pre>
+/// LOG_ASSERT(assertion);
+/// DLOG_ASSERT(assertion);
+/// </pre>
+///
+/// which is syntactic sugar for "{,D}LOG_IF(FATAL, assert fails) << assertion;"
+///
+/// There are "verbose level" logging macros. They look like
+///
+/// <pre>
+/// VLOG(1) << "I'm printed when you run the program with --v=1 or more";
+/// VLOG(2) << "I'm printed when you run the program with --v=2 or more";
+/// </pre>
+///
+/// These always log at the INFO log level (when they log at all).
+/// The verbose logging can also be turned on module-by-module. For instance,
+/// <pre>
+/// --vmodule=profile=2,icon_loader=1,browser_*=3,*/chromeos/*=4 --v=0
+/// </pre>
+/// will cause:
+/// 1. VLOG(2) and lower messages to be printed from profile.{h,cc}
+/// 2. VLOG(1) and lower messages to be printed from icon_loader.{h,cc}
+/// 3. VLOG(3) and lower messages to be printed from files prefixed with
+/// "browser"
+/// 4. VLOG(4) and lower messages to be printed from files under a
+/// "chromeos" directory.
+/// 5. VLOG(0) and lower messages to be printed from elsewhere
+///
+/// The wildcarding functionality shown by (c) supports both '*' (match
+/// 0 or more characters) and '?' (match any single character)
+/// wildcards. Any pattern containing a forward or backward slash will
+/// be tested against the whole pathname and not just the module.
+/// E.g., "*/foo/bar/*=2" would change the logging level for all code
+/// in source files under a "foo/bar" directory.
+///
+/// There's also VLOG_IS_ON(n) "verbose level" condition macro. To be used as
+///
+/// <pre>
+/// if (VLOG_IS_ON(2)) {
+/// // do some logging preparation and logging
+/// // that can't be accomplished with just VLOG(2) << ...;
+/// }
+/// </pre>
+///
+/// There is also a VLOG_IF "verbose level" condition macro for sample
+/// cases, when some extra computation and preparation for logs is not
+/// needed.
+///
+/// <pre>
+/// VLOG_IF(1, (size > 1024))
+/// << "I'm printed when size is more than 1024 and when you run the "
+/// "program with --v=1 or more";
+/// </pre>
+///
+/// We also override the standard 'assert' to use 'DLOG_ASSERT'.
+///
+/// Lastly, there is:
+///
+/// <pre>
+/// PLOG(ERROR) << "Couldn't do foo";
+/// DPLOG(ERROR) << "Couldn't do foo";
+/// PLOG_IF(ERROR, cond) << "Couldn't do foo";
+/// DPLOG_IF(ERROR, cond) << "Couldn't do foo";
+/// PCHECK(condition) << "Couldn't do foo";
+/// DPCHECK(condition) << "Couldn't do foo";
+/// </pre>
+///
+/// which append the last system error to the message in string form (taken from
+/// GetLastError() on Windows and errno on POSIX).
+///
+/// The supported severity levels for macros that allow you to specify one
+/// are (in increasing order of severity) INFO, WARNING, ERROR, and FATAL.
+///
+/// Very important: logging a message at the FATAL severity level causes
+/// the program to terminate (after the message is logged).
+///
+/// There is the special severity of DFATAL, which logs FATAL in debug mode,
+/// ERROR in normal mode.
+///
+
+#ifndef CEF_INCLUDE_BASE_CEF_LOGGING_H_
+#define CEF_INCLUDE_BASE_CEF_LOGGING_H_
+#pragma once
+
+#if defined(USING_CHROMIUM_INCLUDES)
+// When building CEF include the Chromium header directly.
+#include "base/logging.h"
+#include "base/notreached.h"
+#elif defined(DCHECK)
+// Do nothing if the macros provided by this header already exist.
+// This can happen in cases where Chromium code is used directly by the
+// client application. When using Chromium code directly always include
+// the Chromium header first to avoid type conflicts.
+
+// Always define the DCHECK_IS_ON macro which is used from other CEF headers.
+#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
+#define DCHECK_IS_ON() false
+#else
+#define DCHECK_IS_ON() true
+#endif
+
+#else // !defined(DCHECK)
+// The following is substantially similar to the Chromium implementation.
+// If the Chromium implementation diverges the below implementation should be
+// updated to match.
+
+#include <cassert>
+#include <cstring>
+#include <sstream>
+#include <string>
+
+#include "include/base/cef_build.h"
+#include "include/internal/cef_logging_internal.h"
+
+namespace cef {
+namespace logging {
+
+// Gets the current log level.
+inline int GetMinLogLevel() {
+ return cef_get_min_log_level();
+}
+
+// Gets the current vlog level for the given file (usually taken from
+// __FILE__). Note that |N| is the size *with* the null terminator.
+template <size_t N>
+int GetVlogLevel(const char (&file)[N]) {
+ return cef_get_vlog_level(file, N);
+}
+
+typedef int LogSeverity;
+const LogSeverity LOG_VERBOSE = -1; // This is level 1 verbosity
+// Note: the log severities are used to index into the array of names,
+// see log_severity_names.
+const LogSeverity LOG_INFO = 0;
+const LogSeverity LOG_WARNING = 1;
+const LogSeverity LOG_ERROR = 2;
+const LogSeverity LOG_FATAL = 3;
+const LogSeverity LOG_NUM_SEVERITIES = 4;
+
+// LOG_DFATAL is LOG_FATAL in debug mode, ERROR in normal mode
+#ifdef NDEBUG
+const LogSeverity LOG_DFATAL = LOG_ERROR;
+#else
+const LogSeverity LOG_DFATAL = LOG_FATAL;
+#endif
+
+// A few definitions of macros that don't generate much code. These are used
+// by LOG() and LOG_IF, etc. Since these are used all over our code, it's
+// better to have compact code for these operations.
+#define COMPACT_GOOGLE_LOG_EX_INFO(ClassName, ...) \
+ ::cef::logging::ClassName(__FILE__, __LINE__, ::cef::logging::LOG_INFO, \
+ ##__VA_ARGS__)
+#define COMPACT_GOOGLE_LOG_EX_WARNING(ClassName, ...) \
+ ::cef::logging::ClassName(__FILE__, __LINE__, ::cef::logging::LOG_WARNING, \
+ ##__VA_ARGS__)
+#define COMPACT_GOOGLE_LOG_EX_ERROR(ClassName, ...) \
+ ::cef::logging::ClassName(__FILE__, __LINE__, ::cef::logging::LOG_ERROR, \
+ ##__VA_ARGS__)
+#define COMPACT_GOOGLE_LOG_EX_FATAL(ClassName, ...) \
+ ::cef::logging::ClassName(__FILE__, __LINE__, ::cef::logging::LOG_FATAL, \
+ ##__VA_ARGS__)
+#define COMPACT_GOOGLE_LOG_EX_DFATAL(ClassName, ...) \
+ ::cef::logging::ClassName(__FILE__, __LINE__, ::cef::logging::LOG_DFATAL, \
+ ##__VA_ARGS__)
+
+#define COMPACT_GOOGLE_LOG_INFO COMPACT_GOOGLE_LOG_EX_INFO(LogMessage)
+#define COMPACT_GOOGLE_LOG_WARNING COMPACT_GOOGLE_LOG_EX_WARNING(LogMessage)
+#define COMPACT_GOOGLE_LOG_ERROR COMPACT_GOOGLE_LOG_EX_ERROR(LogMessage)
+#define COMPACT_GOOGLE_LOG_FATAL COMPACT_GOOGLE_LOG_EX_FATAL(LogMessage)
+#define COMPACT_GOOGLE_LOG_DFATAL COMPACT_GOOGLE_LOG_EX_DFATAL(LogMessage)
+
+#if defined(OS_WIN)
+// wingdi.h defines ERROR to be 0. When we call LOG(ERROR), it gets
+// substituted with 0, and it expands to COMPACT_GOOGLE_LOG_0. To allow us
+// to keep using this syntax, we define this macro to do the same thing
+// as COMPACT_GOOGLE_LOG_ERROR, and also define ERROR the same way that
+// the Windows SDK does for consistency.
+#define ERROR 0
+#define COMPACT_GOOGLE_LOG_EX_0(ClassName, ...) \
+ COMPACT_GOOGLE_LOG_EX_ERROR(ClassName, ##__VA_ARGS__)
+#define COMPACT_GOOGLE_LOG_0 COMPACT_GOOGLE_LOG_ERROR
+// Needed for LOG_IS_ON(ERROR).
+const LogSeverity LOG_0 = LOG_ERROR;
+#endif
+
+// As special cases, we can assume that LOG_IS_ON(FATAL) always holds. Also,
+// LOG_IS_ON(DFATAL) always holds in debug mode. In particular, CHECK()s will
+// always fire if they fail.
+#define LOG_IS_ON(severity) \
+ ((::cef::logging::LOG_##severity) >= ::cef::logging::GetMinLogLevel())
+
+// We can't do any caching tricks with VLOG_IS_ON() like the
+// google-glog version since it requires GCC extensions. This means
+// that using the v-logging functions in conjunction with --vmodule
+// may be slow.
+#define VLOG_IS_ON(verboselevel) \
+ ((verboselevel) <= ::cef::logging::GetVlogLevel(__FILE__))
+
+// Helper macro which avoids evaluating the arguments to a stream if
+// the condition doesn't hold.
+#define LAZY_STREAM(stream, condition) \
+ !(condition) ? (void)0 : ::cef::logging::LogMessageVoidify() & (stream)
+
+// We use the preprocessor's merging operator, "##", so that, e.g.,
+// LOG(INFO) becomes the token COMPACT_GOOGLE_LOG_INFO. There's some funny
+// subtle difference between ostream member streaming functions (e.g.,
+// ostream::operator<<(int) and ostream non-member streaming functions
+// (e.g., ::operator<<(ostream&, string&): it turns out that it's
+// impossible to stream something like a string directly to an unnamed
+// ostream. We employ a neat hack by calling the stream() member
+// function of LogMessage which seems to avoid the problem.
+#define LOG_STREAM(severity) COMPACT_GOOGLE_LOG_##severity.stream()
+
+#define LOG(severity) LAZY_STREAM(LOG_STREAM(severity), LOG_IS_ON(severity))
+#define LOG_IF(severity, condition) \
+ LAZY_STREAM(LOG_STREAM(severity), LOG_IS_ON(severity) && (condition))
+
+#define SYSLOG(severity) LOG(severity)
+#define SYSLOG_IF(severity, condition) LOG_IF(severity, condition)
+
+// The VLOG macros log with negative verbosities.
+#define VLOG_STREAM(verbose_level) \
+ cef::logging::LogMessage(__FILE__, __LINE__, -verbose_level).stream()
+
+#define VLOG(verbose_level) \
+ LAZY_STREAM(VLOG_STREAM(verbose_level), VLOG_IS_ON(verbose_level))
+
+#define VLOG_IF(verbose_level, condition) \
+ LAZY_STREAM(VLOG_STREAM(verbose_level), \
+ VLOG_IS_ON(verbose_level) && (condition))
+
+#if defined(OS_WIN)
+#define VPLOG_STREAM(verbose_level) \
+ cef::logging::Win32ErrorLogMessage(__FILE__, __LINE__, -verbose_level, \
+ ::cef::logging::GetLastSystemErrorCode()) \
+ .stream()
+#elif defined(OS_POSIX)
+#define VPLOG_STREAM(verbose_level) \
+ cef::logging::ErrnoLogMessage(__FILE__, __LINE__, -verbose_level, \
+ ::cef::logging::GetLastSystemErrorCode()) \
+ .stream()
+#endif
+
+#define VPLOG(verbose_level) \
+ LAZY_STREAM(VPLOG_STREAM(verbose_level), VLOG_IS_ON(verbose_level))
+
+#define VPLOG_IF(verbose_level, condition) \
+ LAZY_STREAM(VPLOG_STREAM(verbose_level), \
+ VLOG_IS_ON(verbose_level) && (condition))
+
+// TODO(akalin): Add more VLOG variants, e.g. VPLOG.
+
+#define LOG_ASSERT(condition) \
+ LOG_IF(FATAL, !(condition)) << "Assert failed: " #condition ". "
+#define SYSLOG_ASSERT(condition) \
+ SYSLOG_IF(FATAL, !(condition)) << "Assert failed: " #condition ". "
+
+#if defined(OS_WIN)
+#define PLOG_STREAM(severity) \
+ COMPACT_GOOGLE_LOG_EX_##severity(Win32ErrorLogMessage, \
+ ::cef::logging::GetLastSystemErrorCode()) \
+ .stream()
+#elif defined(OS_POSIX)
+#define PLOG_STREAM(severity) \
+ COMPACT_GOOGLE_LOG_EX_##severity(ErrnoLogMessage, \
+ ::cef::logging::GetLastSystemErrorCode()) \
+ .stream()
+#endif
+
+#define PLOG(severity) LAZY_STREAM(PLOG_STREAM(severity), LOG_IS_ON(severity))
+
+#define PLOG_IF(severity, condition) \
+ LAZY_STREAM(PLOG_STREAM(severity), LOG_IS_ON(severity) && (condition))
+
+// The actual stream used isn't important.
+#define EAT_STREAM_PARAMETERS \
+ true ? (void)0 : ::cef::logging::LogMessageVoidify() & LOG_STREAM(FATAL)
+
+// CHECK dies with a fatal error if condition is not true. It is *not*
+// controlled by NDEBUG, so the check will be executed regardless of
+// compilation mode.
+//
+// We make sure CHECK et al. always evaluates their arguments, as
+// doing CHECK(FunctionWithSideEffect()) is a common idiom.
+
+#define CHECK(condition) \
+ LAZY_STREAM(LOG_STREAM(FATAL), !(condition)) \
+ << "Check failed: " #condition ". "
+
+#define PCHECK(condition) \
+ LAZY_STREAM(PLOG_STREAM(FATAL), !(condition)) \
+ << "Check failed: " #condition ". "
+
+// Helper macro for binary operators.
+// Don't use this macro directly in your code, use CHECK_EQ et al below.
+//
+// TODO(akalin): Rewrite this so that constructs like if (...)
+// CHECK_EQ(...) else { ... } work properly.
+#define CHECK_OP(name, op, val1, val2) \
+ if (std::string* _result = cef::logging::Check##name##Impl( \
+ (val1), (val2), #val1 " " #op " " #val2)) \
+ cef::logging::LogMessage(__FILE__, __LINE__, _result).stream()
+
+// Build the error message string. This is separate from the "Impl"
+// function template because it is not performance critical and so can
+// be out of line, while the "Impl" code should be inline. Caller
+// takes ownership of the returned string.
+template <class t1, class t2>
+std::string* MakeCheckOpString(const t1& v1, const t2& v2, const char* names) {
+ std::ostringstream ss;
+ ss << names << " (" << v1 << " vs. " << v2 << ")";
+ std::string* msg = new std::string(ss.str());
+ return msg;
+}
+
+// MSVC doesn't like complex extern templates and DLLs.
+#if !defined(COMPILER_MSVC)
+// Commonly used instantiations of MakeCheckOpString<>. Explicitly instantiated
+// in logging.cc.
+extern template std::string* MakeCheckOpString<int, int>(const int&,
+ const int&,
+ const char* names);
+extern template std::string* MakeCheckOpString<unsigned long, unsigned long>(
+ const unsigned long&,
+ const unsigned long&,
+ const char* names);
+extern template std::string* MakeCheckOpString<unsigned long, unsigned int>(
+ const unsigned long&,
+ const unsigned int&,
+ const char* names);
+extern template std::string* MakeCheckOpString<unsigned int, unsigned long>(
+ const unsigned int&,
+ const unsigned long&,
+ const char* names);
+extern template std::string* MakeCheckOpString<std::string, std::string>(
+ const std::string&,
+ const std::string&,
+ const char* name);
+#endif
+
+// Helper functions for CHECK_OP macro.
+// The (int, int) specialization works around the issue that the compiler
+// will not instantiate the template version of the function on values of
+// unnamed enum type - see comment below.
+#define DEFINE_CHECK_OP_IMPL(name, op) \
+ template <class t1, class t2> \
+ inline std::string* Check##name##Impl(const t1& v1, const t2& v2, \
+ const char* names) { \
+ if (v1 op v2) \
+ return NULL; \
+ else \
+ return MakeCheckOpString(v1, v2, names); \
+ } \
+ inline std::string* Check##name##Impl(int v1, int v2, const char* names) { \
+ if (v1 op v2) \
+ return NULL; \
+ else \
+ return MakeCheckOpString(v1, v2, names); \
+ }
+DEFINE_CHECK_OP_IMPL(EQ, ==)
+DEFINE_CHECK_OP_IMPL(NE, !=)
+DEFINE_CHECK_OP_IMPL(LE, <=)
+DEFINE_CHECK_OP_IMPL(LT, <)
+DEFINE_CHECK_OP_IMPL(GE, >=)
+DEFINE_CHECK_OP_IMPL(GT, >)
+#undef DEFINE_CHECK_OP_IMPL
+
+#define CHECK_EQ(val1, val2) CHECK_OP(EQ, ==, val1, val2)
+#define CHECK_NE(val1, val2) CHECK_OP(NE, !=, val1, val2)
+#define CHECK_LE(val1, val2) CHECK_OP(LE, <=, val1, val2)
+#define CHECK_LT(val1, val2) CHECK_OP(LT, <, val1, val2)
+#define CHECK_GE(val1, val2) CHECK_OP(GE, >=, val1, val2)
+#define CHECK_GT(val1, val2) CHECK_OP(GT, >, val1, val2)
+
+#if defined(NDEBUG)
+#define ENABLE_DLOG 0
+#else
+#define ENABLE_DLOG 1
+#endif
+
+#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
+#define DCHECK_IS_ON() 0
+#else
+#define DCHECK_IS_ON() 1
+#endif
+
+// Definitions for DLOG et al.
+
+#if ENABLE_DLOG
+
+#define DLOG_IS_ON(severity) LOG_IS_ON(severity)
+#define DLOG_IF(severity, condition) LOG_IF(severity, condition)
+#define DLOG_ASSERT(condition) LOG_ASSERT(condition)
+#define DPLOG_IF(severity, condition) PLOG_IF(severity, condition)
+#define DVLOG_IF(verboselevel, condition) VLOG_IF(verboselevel, condition)
+#define DVPLOG_IF(verboselevel, condition) VPLOG_IF(verboselevel, condition)
+
+#else // ENABLE_DLOG
+
+// If ENABLE_DLOG is off, we want to avoid emitting any references to
+// |condition| (which may reference a variable defined only if NDEBUG
+// is not defined). Contrast this with DCHECK et al., which has
+// different behavior.
+
+#define DLOG_IS_ON(severity) false
+#define DLOG_IF(severity, condition) EAT_STREAM_PARAMETERS
+#define DLOG_ASSERT(condition) EAT_STREAM_PARAMETERS
+#define DPLOG_IF(severity, condition) EAT_STREAM_PARAMETERS
+#define DVLOG_IF(verboselevel, condition) EAT_STREAM_PARAMETERS
+#define DVPLOG_IF(verboselevel, condition) EAT_STREAM_PARAMETERS
+
+#endif // ENABLE_DLOG
+
+// DEBUG_MODE is for uses like
+// if (DEBUG_MODE) foo.CheckThatFoo();
+// instead of
+// #ifndef NDEBUG
+// foo.CheckThatFoo();
+// #endif
+//
+// We tie its state to ENABLE_DLOG.
+enum { DEBUG_MODE = ENABLE_DLOG };
+
+#undef ENABLE_DLOG
+
+#define DLOG(severity) LAZY_STREAM(LOG_STREAM(severity), DLOG_IS_ON(severity))
+
+#define DPLOG(severity) LAZY_STREAM(PLOG_STREAM(severity), DLOG_IS_ON(severity))
+
+#define DVLOG(verboselevel) DVLOG_IF(verboselevel, VLOG_IS_ON(verboselevel))
+
+#define DVPLOG(verboselevel) DVPLOG_IF(verboselevel, VLOG_IS_ON(verboselevel))
+
+// Definitions for DCHECK et al.
+
+#if DCHECK_IS_ON()
+
+#define COMPACT_GOOGLE_LOG_EX_DCHECK(ClassName, ...) \
+ COMPACT_GOOGLE_LOG_EX_FATAL(ClassName, ##__VA_ARGS__)
+#define COMPACT_GOOGLE_LOG_DCHECK COMPACT_GOOGLE_LOG_FATAL
+const LogSeverity LOG_DCHECK = LOG_FATAL;
+
+#else // DCHECK_IS_ON()
+
+// These are just dummy values.
+#define COMPACT_GOOGLE_LOG_EX_DCHECK(ClassName, ...) \
+ COMPACT_GOOGLE_LOG_EX_INFO(ClassName, ##__VA_ARGS__)
+#define COMPACT_GOOGLE_LOG_DCHECK COMPACT_GOOGLE_LOG_INFO
+const LogSeverity LOG_DCHECK = LOG_INFO;
+
+#endif // DCHECK_IS_ON()
+
+// DCHECK et al. make sure to reference |condition| regardless of
+// whether DCHECKs are enabled; this is so that we don't get unused
+// variable warnings if the only use of a variable is in a DCHECK.
+// This behavior is different from DLOG_IF et al.
+
+#define DCHECK(condition) \
+ LAZY_STREAM(LOG_STREAM(DCHECK), DCHECK_IS_ON() && !(condition)) \
+ << "Check failed: " #condition ". "
+
+#define DPCHECK(condition) \
+ LAZY_STREAM(PLOG_STREAM(DCHECK), DCHECK_IS_ON() && !(condition)) \
+ << "Check failed: " #condition ". "
+
+// Helper macro for binary operators.
+// Don't use this macro directly in your code, use DCHECK_EQ et al below.
+#define DCHECK_OP(name, op, val1, val2) \
+ if (DCHECK_IS_ON()) \
+ if (std::string* _result = cef::logging::Check##name##Impl( \
+ (val1), (val2), #val1 " " #op " " #val2)) \
+ cef::logging::LogMessage(__FILE__, __LINE__, ::cef::logging::LOG_DCHECK, \
+ _result) \
+ .stream()
+
+// Equality/Inequality checks - compare two values, and log a
+// LOG_DCHECK message including the two values when the result is not
+// as expected. The values must have operator<<(ostream, ...)
+// defined.
+//
+// You may append to the error message like so:
+// DCHECK_NE(1, 2) << ": The world must be ending!";
+//
+// We are very careful to ensure that each argument is evaluated exactly
+// once, and that anything which is legal to pass as a function argument is
+// legal here. In particular, the arguments may be temporary expressions
+// which will end up being destroyed at the end of the apparent statement,
+// for example:
+// DCHECK_EQ(string("abc")[1], 'b');
+//
+// WARNING: These may not compile correctly if one of the arguments is a pointer
+// and the other is NULL. To work around this, simply static_cast NULL to the
+// type of the desired pointer.
+
+#define DCHECK_EQ(val1, val2) DCHECK_OP(EQ, ==, val1, val2)
+#define DCHECK_NE(val1, val2) DCHECK_OP(NE, !=, val1, val2)
+#define DCHECK_LE(val1, val2) DCHECK_OP(LE, <=, val1, val2)
+#define DCHECK_LT(val1, val2) DCHECK_OP(LT, <, val1, val2)
+#define DCHECK_GE(val1, val2) DCHECK_OP(GE, >=, val1, val2)
+#define DCHECK_GT(val1, val2) DCHECK_OP(GT, >, val1, val2)
+
+#define NOTREACHED() DCHECK(false)
+
+// Redefine the standard assert to use our nice log files
+#undef assert
+#define assert(x) DLOG_ASSERT(x)
+
+// This class more or less represents a particular log message. You
+// create an instance of LogMessage and then stream stuff to it.
+// When you finish streaming to it, ~LogMessage is called and the
+// full message gets streamed to the appropriate destination.
+//
+// You shouldn't actually use LogMessage's constructor to log things,
+// though. You should use the LOG() macro (and variants thereof)
+// above.
+class LogMessage {
+ public:
+ // Used for LOG(severity).
+ LogMessage(const char* file, int line, LogSeverity severity);
+
+ // Used for CHECK_EQ(), etc. Takes ownership of the given string.
+ // Implied severity = LOG_FATAL.
+ LogMessage(const char* file, int line, std::string* result);
+
+ // Used for DCHECK_EQ(), etc. Takes ownership of the given string.
+ LogMessage(const char* file,
+ int line,
+ LogSeverity severity,
+ std::string* result);
+
+ LogMessage(const LogMessage&) = delete;
+ LogMessage& operator=(const LogMessage&) = delete;
+
+ ~LogMessage();
+
+ std::ostream& stream() { return stream_; }
+
+ private:
+ LogSeverity severity_;
+ std::ostringstream stream_;
+
+ // The file and line information passed in to the constructor.
+ const char* file_;
+ const int line_;
+
+#if defined(OS_WIN)
+ // Stores the current value of GetLastError in the constructor and restores
+ // it in the destructor by calling SetLastError.
+ // This is useful since the LogMessage class uses a lot of Win32 calls
+ // that will lose the value of GLE and the code that called the log function
+ // will have lost the thread error value when the log call returns.
+ class SaveLastError {
+ public:
+ SaveLastError();
+ ~SaveLastError();
+
+ unsigned long get_error() const { return last_error_; }
+
+ protected:
+ unsigned long last_error_;
+ };
+
+ SaveLastError last_error_;
+#endif
+};
+
+// A non-macro interface to the log facility; (useful
+// when the logging level is not a compile-time constant).
+inline void LogAtLevel(int const log_level, std::string const& msg) {
+ LogMessage(__FILE__, __LINE__, log_level).stream() << msg;
+}
+
+// This class is used to explicitly ignore values in the conditional
+// logging macros. This avoids compiler warnings like "value computed
+// is not used" and "statement has no effect".
+class LogMessageVoidify {
+ public:
+ LogMessageVoidify() {}
+ // This has to be an operator with a precedence lower than << but
+ // higher than ?:
+ void operator&(std::ostream&) {}
+};
+
+#if defined(OS_WIN)
+typedef unsigned long SystemErrorCode;
+#elif defined(OS_POSIX)
+typedef int SystemErrorCode;
+#endif
+
+// Alias for ::GetLastError() on Windows and errno on POSIX. Avoids having to
+// pull in windows.h just for GetLastError() and DWORD.
+SystemErrorCode GetLastSystemErrorCode();
+std::string SystemErrorCodeToString(SystemErrorCode error_code);
+
+#if defined(OS_WIN)
+// Appends a formatted system message of the GetLastError() type.
+class Win32ErrorLogMessage {
+ public:
+ Win32ErrorLogMessage(const char* file,
+ int line,
+ LogSeverity severity,
+ SystemErrorCode err);
+
+ Win32ErrorLogMessage(const Win32ErrorLogMessage&) = delete;
+ Win32ErrorLogMessage& operator=(const Win32ErrorLogMessage&) = delete;
+
+ // Appends the error message before destructing the encapsulated class.
+ ~Win32ErrorLogMessage();
+
+ std::ostream& stream() { return log_message_.stream(); }
+
+ private:
+ SystemErrorCode err_;
+ LogMessage log_message_;
+};
+#elif defined(OS_POSIX)
+// Appends a formatted system message of the errno type
+class ErrnoLogMessage {
+ public:
+ ErrnoLogMessage(const char* file,
+ int line,
+ LogSeverity severity,
+ SystemErrorCode err);
+
+ ErrnoLogMessage(const ErrnoLogMessage&) = delete;
+ ErrnoLogMessage& operator=(const ErrnoLogMessage&) = delete;
+
+ // Appends the error message before destructing the encapsulated class.
+ ~ErrnoLogMessage();
+
+ std::ostream& stream() { return log_message_.stream(); }
+
+ private:
+ SystemErrorCode err_;
+ LogMessage log_message_;
+};
+#endif // OS_WIN
+
+} // namespace logging
+} // namespace cef
+
+// These functions are provided as a convenience for logging, which is where we
+// use streams (it is against Google style to use streams in other places). It
+// is designed to allow you to emit non-ASCII Unicode strings to the log file,
+// which is normally ASCII. It is relatively slow, so try not to use it for
+// common cases. Non-ASCII characters will be converted to UTF-8 by these
+// operators.
+std::ostream& operator<<(std::ostream& out, const wchar_t* wstr);
+inline std::ostream& operator<<(std::ostream& out, const std::wstring& wstr) {
+ return out << wstr.c_str();
+}
+
+// The NOTIMPLEMENTED() macro annotates codepaths which have
+// not been implemented yet.
+//
+// The implementation of this macro is controlled by NOTIMPLEMENTED_POLICY:
+// 0 -- Do nothing (stripped by compiler)
+// 1 -- Warn at compile time
+// 2 -- Fail at compile time
+// 3 -- Fail at runtime (DCHECK)
+// 4 -- [default] LOG(ERROR) at runtime
+// 5 -- LOG(ERROR) at runtime, only once per call-site
+
+#ifndef NOTIMPLEMENTED_POLICY
+#if defined(OS_ANDROID) && defined(OFFICIAL_BUILD)
+#define NOTIMPLEMENTED_POLICY 0
+#else
+// Select default policy: LOG(ERROR)
+#define NOTIMPLEMENTED_POLICY 4
+#endif
+#endif
+
+#if defined(COMPILER_GCC)
+// On Linux, with GCC, we can use __PRETTY_FUNCTION__ to get the demangled name
+// of the current function in the NOTIMPLEMENTED message.
+#define NOTIMPLEMENTED_MSG "Not implemented reached in " << __PRETTY_FUNCTION__
+#else
+#define NOTIMPLEMENTED_MSG "NOT IMPLEMENTED"
+#endif
+
+#if NOTIMPLEMENTED_POLICY == 0
+#define NOTIMPLEMENTED() EAT_STREAM_PARAMETERS
+#elif NOTIMPLEMENTED_POLICY == 1
+// TODO, figure out how to generate a warning
+#define NOTIMPLEMENTED() COMPILE_ASSERT(false, NOT_IMPLEMENTED)
+#elif NOTIMPLEMENTED_POLICY == 2
+#define NOTIMPLEMENTED() COMPILE_ASSERT(false, NOT_IMPLEMENTED)
+#elif NOTIMPLEMENTED_POLICY == 3
+#define NOTIMPLEMENTED() NOTREACHED()
+#elif NOTIMPLEMENTED_POLICY == 4
+#define NOTIMPLEMENTED() LOG(ERROR) << NOTIMPLEMENTED_MSG
+#elif NOTIMPLEMENTED_POLICY == 5
+#define NOTIMPLEMENTED() \
+ do { \
+ static bool logged_once = false; \
+ LOG_IF(ERROR, !logged_once) << NOTIMPLEMENTED_MSG; \
+ logged_once = true; \
+ } while (0); \
+ EAT_STREAM_PARAMETERS
+#endif
+
+#endif // !USING_CHROMIUM_INCLUDES
+
+#endif // CEF_INCLUDE_BASE_CEF_LOGGING_H_
diff --git a/include/base/cef_macros.h b/include/base/cef_macros.h
new file mode 100644
index 00000000..f5517f9c
--- /dev/null
+++ b/include/base/cef_macros.h
@@ -0,0 +1,63 @@
+// Copyright (c) 2014 Marshall A. Greenblatt. Portions copyright (c) 2012
+// Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CEF_INCLUDE_BASE_CEF_MACROS_H_
+#define CEF_INCLUDE_BASE_CEF_MACROS_H_
+#pragma once
+
+#if !defined(USING_CHROMIUM_INCLUDES)
+// The following is substantially similar to the Chromium implementation.
+// If the Chromium implementation diverges the below implementation should be
+// updated to match.
+
+// ALL DISALLOW_xxx MACROS ARE DEPRECATED; DO NOT USE IN NEW CODE.
+// Use explicit deletions instead. For more information see
+// https://chromium.googlesource.com/chromium/src/+/lkgr/styleguide/c++/c++-dos-and-donts.md#explicitly-declare-class-copyability_movability
+
+// DEPRECATED: See above. Makes a class uncopyable.
+#define DISALLOW_COPY(TypeName) TypeName(const TypeName&) = delete
+
+// DEPRECATED: See above. Makes a class unassignable.
+#define DISALLOW_ASSIGN(TypeName) TypeName& operator=(const TypeName&) = delete
+
+// DEPRECATED: See above. Makes a class uncopyable and unassignable.
+#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
+ DISALLOW_COPY(TypeName); \
+ DISALLOW_ASSIGN(TypeName)
+
+// DEPRECATED: See above. Disallow all implicit constructors, namely the
+// default constructor, copy constructor and operator= functions.
+#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
+ TypeName() = delete; \
+ DISALLOW_COPY_AND_ASSIGN(TypeName)
+
+#endif // !USING_CHROMIUM_INCLUDES
+
+#endif // CEF_INCLUDE_BASE_CEF_MACROS_H_
diff --git a/include/base/cef_platform_thread.h b/include/base/cef_platform_thread.h
new file mode 100644
index 00000000..e67eed41
--- /dev/null
+++ b/include/base/cef_platform_thread.h
@@ -0,0 +1,111 @@
+// Copyright (c) 2014 Marshall A. Greenblatt. Portions copyright (c) 2011
+// Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// WARNING: You should *NOT* be using this class directly. PlatformThread is
+// the low-level platform-specific abstraction to the OS's threading interface.
+// You should instead be using a message-loop driven Thread, see thread.h.
+
+#ifndef CEF_INCLUDE_BASE_PLATFORM_THREAD_H_
+#define CEF_INCLUDE_BASE_PLATFORM_THREAD_H_
+
+#if defined(USING_CHROMIUM_INCLUDES)
+// When building CEF include the Chromium header directly.
+#include "base/threading/platform_thread.h"
+#else // !USING_CHROMIUM_INCLUDES
+// The following is substantially similar to the Chromium implementation.
+// If the Chromium implementation diverges the below implementation should be
+// updated to match.
+
+#include "include/base/cef_basictypes.h"
+#include "include/base/cef_build.h"
+#include "include/internal/cef_thread_internal.h"
+
+namespace base {
+
+///
+/// Used for logging. Always an integer value.
+///
+typedef cef_platform_thread_id_t PlatformThreadId;
+
+///
+/// Used for thread checking and debugging.
+/// Meant to be as fast as possible.
+/// These are produced by PlatformThread::CurrentRef(), and used to later
+/// check if we are on the same thread or not by using ==. These are safe
+/// to copy between threads, but can't be copied to another process as they
+/// have no meaning there. Also, the internal identifier can be re-used
+/// after a thread dies, so a PlatformThreadRef cannot be reliably used
+/// to distinguish a new thread from an old, dead thread.
+///
+class PlatformThreadRef {
+ public:
+ typedef cef_platform_thread_handle_t RefType;
+
+ PlatformThreadRef() : id_(0) {}
+
+ explicit PlatformThreadRef(RefType id) : id_(id) {}
+
+ bool operator==(PlatformThreadRef other) const { return id_ == other.id_; }
+
+ bool is_null() const { return id_ == 0; }
+
+ private:
+ RefType id_;
+};
+
+///
+/// A namespace for low-level thread functions.
+/// Chromium uses a class with static methods but CEF uses an actual namespace
+/// to avoid linker problems with the sandbox libaries on Windows.
+///
+namespace PlatformThread {
+
+///
+/// Gets the current thread id, which may be useful for logging purposes.
+///
+inline PlatformThreadId CurrentId() {
+ return cef_get_current_platform_thread_id();
+}
+
+///
+/// Gets the current thread reference, which can be used to check if
+/// we're on the right thread quickly.
+///
+inline PlatformThreadRef CurrentRef() {
+ return PlatformThreadRef(cef_get_current_platform_thread_handle());
+}
+
+} // namespace PlatformThread
+
+} // namespace base
+
+#endif // !USING_CHROMIUM_INCLUDES
+
+#endif // CEF_INCLUDE_BASE_PLATFORM_THREAD_H_
diff --git a/include/base/cef_ptr_util.h b/include/base/cef_ptr_util.h
new file mode 100644
index 00000000..082b87af
--- /dev/null
+++ b/include/base/cef_ptr_util.h
@@ -0,0 +1,60 @@
+// Copyright (c) 2021 Marshall A. Greenblatt. Portions copyright (c) 2015
+// Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef INCLUDE_BASE_CEF_PTR_UTIL_H_
+#define INCLUDE_BASE_CEF_PTR_UTIL_H_
+#pragma once
+
+#if defined(USING_CHROMIUM_INCLUDES)
+// When building CEF include the Chromium header directly.
+#include "base/memory/ptr_util.h"
+#else // !USING_CHROMIUM_INCLUDES
+// The following is substantially similar to the Chromium implementation.
+// If the Chromium implementation diverges the below implementation should be
+// updated to match.
+
+#include <memory>
+#include <utility>
+
+namespace base {
+
+///
+/// Helper to transfer ownership of a raw pointer to a std::unique_ptr<T>.
+/// Note that std::unique_ptr<T> has very different semantics from
+/// std::unique_ptr<T[]>: do not use this helper for array allocations.
+///
+template <typename T>
+std::unique_ptr<T> WrapUnique(T* ptr) {
+ return std::unique_ptr<T>(ptr);
+}
+
+} // namespace base
+
+#endif // INCLUDE_BASE_CEF_PTR_UTIL_H_
diff --git a/include/base/cef_ref_counted.h b/include/base/cef_ref_counted.h
new file mode 100644
index 00000000..04d185bd
--- /dev/null
+++ b/include/base/cef_ref_counted.h
@@ -0,0 +1,512 @@
+// Copyright (c) 2014 Marshall A. Greenblatt. Portions copyright (c) 2012
+// Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+
+#ifndef CEF_INCLUDE_BASE_CEF_REF_COUNTED_H_
+#define CEF_INCLUDE_BASE_CEF_REF_COUNTED_H_
+#pragma once
+
+#if defined(USING_CHROMIUM_INCLUDES)
+// When building CEF include the Chromium header directly.
+#include "base/memory/ref_counted.h"
+#else // !USING_CHROMIUM_INCLUDES
+// The following is substantially similar to the Chromium implementation.
+// If the Chromium implementation diverges the below implementation should be
+// updated to match.
+
+#include <stddef.h>
+
+#include <utility>
+
+#include "include/base/cef_atomic_ref_count.h"
+#include "include/base/cef_build.h"
+#include "include/base/cef_compiler_specific.h"
+#include "include/base/cef_logging.h"
+#include "include/base/cef_scoped_refptr.h"
+#include "include/base/cef_template_util.h"
+#include "include/base/cef_thread_checker.h"
+
+namespace base {
+namespace cef_subtle {
+
+class RefCountedBase {
+ public:
+ bool HasOneRef() const { return ref_count_ == 1; }
+ bool HasAtLeastOneRef() const { return ref_count_ >= 1; }
+
+ protected:
+ explicit RefCountedBase(StartRefCountFromZeroTag) {
+#if DCHECK_IS_ON()
+ thread_checker_.DetachFromThread();
+#endif
+ }
+
+ explicit RefCountedBase(StartRefCountFromOneTag) : ref_count_(1) {
+#if DCHECK_IS_ON()
+ needs_adopt_ref_ = true;
+ thread_checker_.DetachFromThread();
+#endif
+ }
+
+ RefCountedBase(const RefCountedBase&) = delete;
+ RefCountedBase& operator=(const RefCountedBase&) = delete;
+
+ ~RefCountedBase() {
+#if DCHECK_IS_ON()
+ DCHECK(in_dtor_) << "RefCounted object deleted without calling Release()";
+#endif
+ }
+
+ void AddRef() const {
+#if DCHECK_IS_ON()
+ DCHECK(!in_dtor_);
+ DCHECK(!needs_adopt_ref_)
+ << "This RefCounted object is created with non-zero reference count."
+ << " The first reference to such a object has to be made by AdoptRef or"
+ << " MakeRefCounted.";
+ if (ref_count_ >= 1) {
+ DCHECK(CalledOnValidThread());
+ }
+#endif
+
+ AddRefImpl();
+ }
+
+ // Returns true if the object should self-delete.
+ bool Release() const {
+ ReleaseImpl();
+
+#if DCHECK_IS_ON()
+ DCHECK(!in_dtor_);
+ if (ref_count_ == 0) {
+ in_dtor_ = true;
+ }
+
+ if (ref_count_ >= 1) {
+ DCHECK(CalledOnValidThread());
+ }
+ if (ref_count_ == 1) {
+ thread_checker_.DetachFromThread();
+ }
+#endif
+
+ return ref_count_ == 0;
+ }
+
+ // Returns true if it is safe to read or write the object, from a thread
+ // safety standpoint. Should be DCHECK'd from the methods of RefCounted
+ // classes if there is a danger of objects being shared across threads.
+ //
+ // This produces fewer false positives than adding a separate ThreadChecker
+ // into the subclass, because it automatically detaches from the thread when
+ // the reference count is 1 (and never fails if there is only one reference).
+ //
+ // This means unlike a separate ThreadChecker, it will permit a singly
+ // referenced object to be passed between threads (not holding a reference on
+ // the sending thread), but will trap if the sending thread holds onto a
+ // reference, or if the object is accessed from multiple threads
+ // simultaneously.
+ bool IsOnValidThread() const {
+#if DCHECK_IS_ON()
+ return ref_count_ <= 1 || CalledOnValidThread();
+#else
+ return true;
+#endif
+ }
+
+ private:
+ template <typename U>
+ friend scoped_refptr<U> base::AdoptRef(U*);
+
+ void Adopted() const {
+#if DCHECK_IS_ON()
+ DCHECK(needs_adopt_ref_);
+ needs_adopt_ref_ = false;
+#endif
+ }
+
+#if defined(ARCH_CPU_64_BITS)
+ void AddRefImpl() const;
+ void ReleaseImpl() const;
+#else
+ void AddRefImpl() const { ++ref_count_; }
+ void ReleaseImpl() const { --ref_count_; }
+#endif
+
+#if DCHECK_IS_ON()
+ bool CalledOnValidThread() const;
+#endif
+
+ mutable uint32_t ref_count_ = 0;
+ static_assert(std::is_unsigned<decltype(ref_count_)>::value,
+ "ref_count_ must be an unsigned type.");
+
+#if DCHECK_IS_ON()
+ mutable bool needs_adopt_ref_ = false;
+ mutable bool in_dtor_ = false;
+ mutable ThreadChecker thread_checker_;
+#endif
+};
+
+class RefCountedThreadSafeBase {
+ public:
+ bool HasOneRef() const;
+ bool HasAtLeastOneRef() const;
+
+ protected:
+ explicit constexpr RefCountedThreadSafeBase(StartRefCountFromZeroTag) {}
+ explicit constexpr RefCountedThreadSafeBase(StartRefCountFromOneTag)
+ : ref_count_(1) {
+#if DCHECK_IS_ON()
+ needs_adopt_ref_ = true;
+#endif
+ }
+
+ RefCountedThreadSafeBase(const RefCountedThreadSafeBase&) = delete;
+ RefCountedThreadSafeBase& operator=(const RefCountedThreadSafeBase&) = delete;
+
+#if DCHECK_IS_ON()
+ ~RefCountedThreadSafeBase();
+#else
+ ~RefCountedThreadSafeBase() = default;
+#endif
+
+// Release and AddRef are suitable for inlining on X86 because they generate
+// very small code threads. On other platforms (ARM), it causes a size
+// regression and is probably not worth it.
+#if defined(ARCH_CPU_X86_FAMILY)
+ // Returns true if the object should self-delete.
+ bool Release() const { return ReleaseImpl(); }
+ void AddRef() const { AddRefImpl(); }
+ void AddRefWithCheck() const { AddRefWithCheckImpl(); }
+#else
+ // Returns true if the object should self-delete.
+ bool Release() const;
+ void AddRef() const;
+ void AddRefWithCheck() const;
+#endif
+
+ private:
+ template <typename U>
+ friend scoped_refptr<U> base::AdoptRef(U*);
+
+ void Adopted() const {
+#if DCHECK_IS_ON()
+ DCHECK(needs_adopt_ref_);
+ needs_adopt_ref_ = false;
+#endif
+ }
+
+ ALWAYS_INLINE void AddRefImpl() const {
+#if DCHECK_IS_ON()
+ DCHECK(!in_dtor_);
+ DCHECK(!needs_adopt_ref_)
+ << "This RefCounted object is created with non-zero reference count."
+ << " The first reference to such a object has to be made by AdoptRef or"
+ << " MakeRefCounted.";
+#endif
+ ref_count_.Increment();
+ }
+
+ ALWAYS_INLINE void AddRefWithCheckImpl() const {
+#if DCHECK_IS_ON()
+ DCHECK(!in_dtor_);
+ DCHECK(!needs_adopt_ref_)
+ << "This RefCounted object is created with non-zero reference count."
+ << " The first reference to such a object has to be made by AdoptRef or"
+ << " MakeRefCounted.";
+#endif
+ CHECK(ref_count_.Increment() > 0);
+ }
+
+ ALWAYS_INLINE bool ReleaseImpl() const {
+#if DCHECK_IS_ON()
+ DCHECK(!in_dtor_);
+ DCHECK(!ref_count_.IsZero());
+#endif
+ if (!ref_count_.Decrement()) {
+#if DCHECK_IS_ON()
+ in_dtor_ = true;
+#endif
+ return true;
+ }
+ return false;
+ }
+
+ mutable AtomicRefCount ref_count_{0};
+#if DCHECK_IS_ON()
+ mutable bool needs_adopt_ref_ = false;
+ mutable bool in_dtor_ = false;
+#endif
+};
+
+// ScopedAllowCrossThreadRefCountAccess disables the check documented on
+// RefCounted below for rare pre-existing use cases where thread-safety was
+// guaranteed through other means (e.g. explicit sequencing of calls across
+// execution threads when bouncing between threads in order). New callers
+// should refrain from using this (callsites handling thread-safety through
+// locks should use RefCountedThreadSafe per the overhead of its atomics being
+// negligible compared to locks anyways and callsites doing explicit sequencing
+// should properly std::move() the ref to avoid hitting this check).
+// TODO(tzik): Cleanup existing use cases and remove
+// ScopedAllowCrossThreadRefCountAccess.
+class ScopedAllowCrossThreadRefCountAccess final {
+ public:
+#if DCHECK_IS_ON()
+ ScopedAllowCrossThreadRefCountAccess();
+ ~ScopedAllowCrossThreadRefCountAccess();
+#else
+ ScopedAllowCrossThreadRefCountAccess() {}
+ ~ScopedAllowCrossThreadRefCountAccess() {}
+#endif
+};
+
+} // namespace cef_subtle
+
+using ScopedAllowCrossThreadRefCountAccess =
+ cef_subtle::ScopedAllowCrossThreadRefCountAccess;
+
+///
+/// The reference count starts from zero by default, and we intended to migrate
+/// to start-from-one ref count. Put REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE() to
+/// the ref counted class to opt-in.
+///
+/// If an object has start-from-one ref count, the first scoped_refptr need to
+/// be created by base::AdoptRef() or base::MakeRefCounted(). We can use
+/// base::MakeRefCounted() to create create both type of ref counted object.
+///
+/// The motivations to use start-from-one ref count are:
+/// - Start-from-one ref count doesn't need the ref count increment for the
+/// first reference.
+/// - It can detect an invalid object acquisition for a being-deleted object
+/// that has zero ref count. That tends to happen on custom deleter that
+/// delays the deletion.
+/// TODO(tzik): Implement invalid acquisition detection.
+/// - Behavior parity to Blink's WTF::RefCounted, whose count starts from one.
+/// And start-from-one ref count is a step to merge WTF::RefCounted into
+/// base::RefCounted.
+///
+#define REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE() \
+ static constexpr ::base::cef_subtle::StartRefCountFromOneTag \
+ kRefCountPreference = ::base::cef_subtle::kStartRefCountFromOneTag
+
+template <class T, typename Traits>
+class RefCounted;
+
+///
+/// Default traits for RefCounted<T>. Deletes the object when its ref count
+/// reaches 0. Overload to delete it on a different thread etc.
+///
+template <typename T>
+struct DefaultRefCountedTraits {
+ static void Destruct(const T* x) {
+ RefCounted<T, DefaultRefCountedTraits>::DeleteInternal(x);
+ }
+};
+
+///
+/// A base class for reference counted classes. Otherwise, known as a cheap
+/// knock-off of WebKit's RefCounted<T> class. To use this, just extend your
+/// class from it like so:
+///
+/// <pre>
+/// class MyFoo : public base::RefCounted<MyFoo> {
+/// ...
+/// private:
+/// friend class base::RefCounted<MyFoo>;
+/// ~MyFoo();
+/// };
+/// </pre>
+///
+/// Usage Notes:
+/// 1. You should always make your destructor non-public, to avoid any code
+/// deleting the object accidentally while there are references to it.
+/// 2. You should always make the ref-counted base class a friend of your class,
+/// so that it can access the destructor.
+///
+/// The ref count manipulation to RefCounted is NOT thread safe and has DCHECKs
+/// to trap unsafe cross thread usage. A subclass instance of RefCounted can be
+/// passed to another execution thread only when its ref count is 1. If the ref
+/// count is more than 1, the RefCounted class verifies the ref updates are made
+/// on the same execution thread as the previous ones. The subclass can also
+/// manually call IsOnValidThread to trap other non-thread-safe accesses; see
+/// the documentation for that method.
+///
+template <class T, typename Traits = DefaultRefCountedTraits<T>>
+class RefCounted : public cef_subtle::RefCountedBase {
+ public:
+ static constexpr cef_subtle::StartRefCountFromZeroTag kRefCountPreference =
+ cef_subtle::kStartRefCountFromZeroTag;
+
+ RefCounted() : cef_subtle::RefCountedBase(T::kRefCountPreference) {}
+
+ RefCounted(const RefCounted&) = delete;
+ RefCounted& operator=(const RefCounted&) = delete;
+
+ void AddRef() const { cef_subtle::RefCountedBase::AddRef(); }
+
+ void Release() const {
+ if (cef_subtle::RefCountedBase::Release()) {
+ // Prune the code paths which the static analyzer may take to simulate
+ // object destruction. Use-after-free errors aren't possible given the
+ // lifetime guarantees of the refcounting system.
+ ANALYZER_SKIP_THIS_PATH();
+
+ Traits::Destruct(static_cast<const T*>(this));
+ }
+ }
+
+ protected:
+ ~RefCounted() = default;
+
+ private:
+ friend struct DefaultRefCountedTraits<T>;
+ template <typename U>
+ static void DeleteInternal(const U* x) {
+ delete x;
+ }
+};
+
+// Forward declaration.
+template <class T, typename Traits>
+class RefCountedThreadSafe;
+
+///
+/// Default traits for RefCountedThreadSafe<T>. Deletes the object when its ref
+/// count reaches 0. Overload to delete it on a different thread etc.
+///
+template <typename T>
+struct DefaultRefCountedThreadSafeTraits {
+ static void Destruct(const T* x) {
+ // Delete through RefCountedThreadSafe to make child classes only need to be
+ // friend with RefCountedThreadSafe instead of this struct, which is an
+ // implementation detail.
+ RefCountedThreadSafe<T, DefaultRefCountedThreadSafeTraits>::DeleteInternal(
+ x);
+ }
+};
+
+///
+/// A thread-safe variant of RefCounted<T>
+///
+/// <pre>
+/// class MyFoo : public base::RefCountedThreadSafe<MyFoo> {
+/// ...
+/// };
+/// </pre>
+///
+/// If you're using the default trait, then you should add compile time
+/// asserts that no one else is deleting your object. i.e.
+/// <pre>
+/// private:
+/// friend class base::RefCountedThreadSafe<MyFoo>;
+/// ~MyFoo();
+/// </pre>
+///
+/// We can use REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE() with RefCountedThreadSafe
+/// too. See the comment above the RefCounted definition for details.
+///
+template <class T, typename Traits = DefaultRefCountedThreadSafeTraits<T>>
+class RefCountedThreadSafe : public cef_subtle::RefCountedThreadSafeBase {
+ public:
+ static constexpr cef_subtle::StartRefCountFromZeroTag kRefCountPreference =
+ cef_subtle::kStartRefCountFromZeroTag;
+
+ explicit RefCountedThreadSafe()
+ : cef_subtle::RefCountedThreadSafeBase(T::kRefCountPreference) {}
+
+ RefCountedThreadSafe(const RefCountedThreadSafe&) = delete;
+ RefCountedThreadSafe& operator=(const RefCountedThreadSafe&) = delete;
+
+ void AddRef() const { AddRefImpl(T::kRefCountPreference); }
+
+ void Release() const {
+ if (cef_subtle::RefCountedThreadSafeBase::Release()) {
+ ANALYZER_SKIP_THIS_PATH();
+ Traits::Destruct(static_cast<const T*>(this));
+ }
+ }
+
+ protected:
+ ~RefCountedThreadSafe() = default;
+
+ private:
+ friend struct DefaultRefCountedThreadSafeTraits<T>;
+ template <typename U>
+ static void DeleteInternal(const U* x) {
+ delete x;
+ }
+
+ void AddRefImpl(cef_subtle::StartRefCountFromZeroTag) const {
+ cef_subtle::RefCountedThreadSafeBase::AddRef();
+ }
+
+ void AddRefImpl(cef_subtle::StartRefCountFromOneTag) const {
+ cef_subtle::RefCountedThreadSafeBase::AddRefWithCheck();
+ }
+};
+
+///
+/// A thread-safe wrapper for some piece of data so we can place other
+/// things in scoped_refptrs<>.
+///
+template <typename T>
+class RefCountedData
+ : public base::RefCountedThreadSafe<base::RefCountedData<T>> {
+ public:
+ RefCountedData() : data() {}
+ RefCountedData(const T& in_value) : data(in_value) {}
+ RefCountedData(T&& in_value) : data(std::move(in_value)) {}
+ template <typename... Args>
+ explicit RefCountedData(in_place_t, Args&&... args)
+ : data(std::forward<Args>(args)...) {}
+
+ T data;
+
+ private:
+ friend class base::RefCountedThreadSafe<base::RefCountedData<T>>;
+ ~RefCountedData() = default;
+};
+
+template <typename T>
+bool operator==(const RefCountedData<T>& lhs, const RefCountedData<T>& rhs) {
+ return lhs.data == rhs.data;
+}
+
+template <typename T>
+bool operator!=(const RefCountedData<T>& lhs, const RefCountedData<T>& rhs) {
+ return !(lhs == rhs);
+}
+
+} // namespace base
+
+#endif // !USING_CHROMIUM_INCLUDES
+
+#endif // CEF_INCLUDE_BASE_CEF_REF_COUNTED_H_
diff --git a/include/base/cef_scoped_refptr.h b/include/base/cef_scoped_refptr.h
new file mode 100644
index 00000000..92690394
--- /dev/null
+++ b/include/base/cef_scoped_refptr.h
@@ -0,0 +1,420 @@
+// Copyright (c) 2017 Marshall A. Greenblatt. Portions copyright (c) 2011
+// Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CEF_INCLUDE_BASE_CEF_SCOPED_REFPTR_H_
+#define CEF_INCLUDE_BASE_CEF_SCOPED_REFPTR_H_
+#pragma once
+
+#if defined(USING_CHROMIUM_INCLUDES)
+// When building CEF include the Chromium header directly.
+#include "base/memory/scoped_refptr.h"
+#else // !USING_CHROMIUM_INCLUDES
+// The following is substantially similar to the Chromium implementation.
+// If the Chromium implementation diverges the below implementation should be
+// updated to match.
+
+#include <stddef.h>
+
+#include <iosfwd>
+#include <type_traits>
+#include <utility>
+
+#include "include/base/cef_logging.h"
+
+template <class T>
+class scoped_refptr;
+
+namespace base {
+
+template <class, typename>
+class RefCounted;
+template <class, typename>
+class RefCountedThreadSafe;
+class SequencedTaskRunner;
+class WrappedPromise;
+
+template <typename T>
+scoped_refptr<T> AdoptRef(T* t);
+
+namespace internal {
+
+class BasePromise;
+
+} // namespace internal
+
+namespace cef_subtle {
+
+enum AdoptRefTag { kAdoptRefTag };
+enum StartRefCountFromZeroTag { kStartRefCountFromZeroTag };
+enum StartRefCountFromOneTag { kStartRefCountFromOneTag };
+
+template <typename T, typename U, typename V>
+constexpr bool IsRefCountPreferenceOverridden(const T*,
+ const RefCounted<U, V>*) {
+ return !std::is_same<std::decay_t<decltype(T::kRefCountPreference)>,
+ std::decay_t<decltype(U::kRefCountPreference)>>::value;
+}
+
+template <typename T, typename U, typename V>
+constexpr bool IsRefCountPreferenceOverridden(
+ const T*,
+ const RefCountedThreadSafe<U, V>*) {
+ return !std::is_same<std::decay_t<decltype(T::kRefCountPreference)>,
+ std::decay_t<decltype(U::kRefCountPreference)>>::value;
+}
+
+constexpr bool IsRefCountPreferenceOverridden(...) {
+ return false;
+}
+
+} // namespace cef_subtle
+
+// Creates a scoped_refptr from a raw pointer without incrementing the reference
+// count. Use this only for a newly created object whose reference count starts
+// from 1 instead of 0.
+template <typename T>
+scoped_refptr<T> AdoptRef(T* obj) {
+ using Tag = std::decay_t<decltype(T::kRefCountPreference)>;
+ static_assert(std::is_same<cef_subtle::StartRefCountFromOneTag, Tag>::value,
+ "Use AdoptRef only if the reference count starts from one.");
+
+ DCHECK(obj);
+ DCHECK(obj->HasOneRef());
+ obj->Adopted();
+ return scoped_refptr<T>(obj, cef_subtle::kAdoptRefTag);
+}
+
+namespace cef_subtle {
+
+template <typename T>
+scoped_refptr<T> AdoptRefIfNeeded(T* obj, StartRefCountFromZeroTag) {
+ return scoped_refptr<T>(obj);
+}
+
+template <typename T>
+scoped_refptr<T> AdoptRefIfNeeded(T* obj, StartRefCountFromOneTag) {
+ return AdoptRef(obj);
+}
+
+} // namespace cef_subtle
+
+// Constructs an instance of T, which is a ref counted type, and wraps the
+// object into a scoped_refptr<T>.
+template <typename T, typename... Args>
+scoped_refptr<T> MakeRefCounted(Args&&... args) {
+ T* obj = new T(std::forward<Args>(args)...);
+ return cef_subtle::AdoptRefIfNeeded(obj, T::kRefCountPreference);
+}
+
+// Takes an instance of T, which is a ref counted type, and wraps the object
+// into a scoped_refptr<T>.
+template <typename T>
+scoped_refptr<T> WrapRefCounted(T* t) {
+ return scoped_refptr<T>(t);
+}
+
+} // namespace base
+
+///
+/// A smart pointer class for reference counted objects. Use this class instead
+/// of calling AddRef and Release manually on a reference counted object to
+/// avoid common memory leaks caused by forgetting to Release an object
+/// reference. Sample usage:
+///
+/// <pre>
+/// class MyFoo : public RefCounted<MyFoo> {
+/// ...
+/// private:
+/// friend class RefCounted<MyFoo>; // Allow destruction by RefCounted<>.
+/// ~MyFoo(); // Destructor must be
+/// private/protected.
+/// };
+///
+/// void some_function() {
+/// scoped_refptr<MyFoo> foo = MakeRefCounted<MyFoo>();
+/// foo->Method(param);
+/// // |foo| is released when this function returns
+/// }
+///
+/// void some_other_function() {
+/// scoped_refptr<MyFoo> foo = MakeRefCounted<MyFoo>();
+/// ...
+/// foo.reset(); // explicitly releases |foo|
+/// ...
+/// if (foo)
+/// foo->Method(param);
+/// }
+/// </pre>
+///
+/// The above examples show how scoped_refptr<T> acts like a pointer to T.
+/// Given two scoped_refptr<T> classes, it is also possible to exchange
+/// references between the two objects, like so:
+///
+/// <pre>
+/// {
+/// scoped_refptr<MyFoo> a = MakeRefCounted<MyFoo>();
+/// scoped_refptr<MyFoo> b;
+///
+/// b.swap(a);
+/// // now, |b| references the MyFoo object, and |a| references nullptr.
+/// }
+/// </pre>
+///
+/// To make both |a| and |b| in the above example reference the same MyFoo
+/// object, simply use the assignment operator:
+///
+/// <pre>
+/// {
+/// scoped_refptr<MyFoo> a = MakeRefCounted<MyFoo>();
+/// scoped_refptr<MyFoo> b;
+///
+/// b = a;
+/// // now, |a| and |b| each own a reference to the same MyFoo object.
+/// }
+/// </pre>
+///
+/// Also see Chromium's ownership and calling conventions:
+/// https://chromium.googlesource.com/chromium/src/+/lkgr/styleguide/c++/c++.md#object-ownership-and-calling-conventions
+/// Specifically:
+/// If the function (at least sometimes) takes a ref on a refcounted object,
+/// declare the param as scoped_refptr<T>. The caller can decide whether it
+/// wishes to transfer ownership (by calling std::move(t) when passing t) or
+/// retain its ref (by simply passing t directly).
+/// In other words, use scoped_refptr like you would a std::unique_ptr except
+/// in the odd case where it's required to hold on to a ref while handing one
+/// to another component (if a component merely needs to use t on the stack
+/// without keeping a ref: pass t as a raw T*).
+///
+template <class T>
+class TRIVIAL_ABI scoped_refptr {
+ public:
+ typedef T element_type;
+
+ constexpr scoped_refptr() = default;
+
+ // Allow implicit construction from nullptr.
+ constexpr scoped_refptr(std::nullptr_t) {}
+
+ // Constructs from a raw pointer. Note that this constructor allows implicit
+ // conversion from T* to scoped_refptr<T> which is strongly discouraged. If
+ // you are creating a new ref-counted object please use
+ // base::MakeRefCounted<T>() or base::WrapRefCounted<T>(). Otherwise you
+ // should move or copy construct from an existing scoped_refptr<T> to the
+ // ref-counted object.
+ scoped_refptr(T* p) : ptr_(p) {
+ if (ptr_) {
+ AddRef(ptr_);
+ }
+ }
+
+ // Copy constructor. This is required in addition to the copy conversion
+ // constructor below.
+ scoped_refptr(const scoped_refptr& r) : scoped_refptr(r.ptr_) {}
+
+ // Copy conversion constructor.
+ template <typename U,
+ typename = typename std::enable_if<
+ std::is_convertible<U*, T*>::value>::type>
+ scoped_refptr(const scoped_refptr<U>& r) : scoped_refptr(r.ptr_) {}
+
+ // Move constructor. This is required in addition to the move conversion
+ // constructor below.
+ scoped_refptr(scoped_refptr&& r) noexcept : ptr_(r.ptr_) { r.ptr_ = nullptr; }
+
+ // Move conversion constructor.
+ template <typename U,
+ typename = typename std::enable_if<
+ std::is_convertible<U*, T*>::value>::type>
+ scoped_refptr(scoped_refptr<U>&& r) noexcept : ptr_(r.ptr_) {
+ r.ptr_ = nullptr;
+ }
+
+ ~scoped_refptr() {
+ static_assert(!base::cef_subtle::IsRefCountPreferenceOverridden(
+ static_cast<T*>(nullptr), static_cast<T*>(nullptr)),
+ "It's unsafe to override the ref count preference."
+ " Please remove REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE"
+ " from subclasses.");
+ if (ptr_) {
+ Release(ptr_);
+ }
+ }
+
+ T* get() const { return ptr_; }
+
+ T& operator*() const {
+ DCHECK(ptr_);
+ return *ptr_;
+ }
+
+ T* operator->() const {
+ DCHECK(ptr_);
+ return ptr_;
+ }
+
+ scoped_refptr& operator=(std::nullptr_t) {
+ reset();
+ return *this;
+ }
+
+ scoped_refptr& operator=(T* p) { return *this = scoped_refptr(p); }
+
+ // Unified assignment operator.
+ scoped_refptr& operator=(scoped_refptr r) noexcept {
+ swap(r);
+ return *this;
+ }
+
+ // Sets managed object to null and releases reference to the previous managed
+ // object, if it existed.
+ void reset() { scoped_refptr().swap(*this); }
+
+ // Returns the owned pointer (if any), releasing ownership to the caller. The
+ // caller is responsible for managing the lifetime of the reference.
+ [[nodiscard]] T* release();
+
+ void swap(scoped_refptr& r) noexcept { std::swap(ptr_, r.ptr_); }
+
+ explicit operator bool() const { return ptr_ != nullptr; }
+
+ template <typename U>
+ bool operator==(const scoped_refptr<U>& rhs) const {
+ return ptr_ == rhs.get();
+ }
+
+ template <typename U>
+ bool operator!=(const scoped_refptr<U>& rhs) const {
+ return !operator==(rhs);
+ }
+
+ template <typename U>
+ bool operator<(const scoped_refptr<U>& rhs) const {
+ return ptr_ < rhs.get();
+ }
+
+ protected:
+ T* ptr_ = nullptr;
+
+ private:
+ template <typename U>
+ friend scoped_refptr<U> base::AdoptRef(U*);
+ friend class ::base::SequencedTaskRunner;
+
+ // Friend access so these classes can use the constructor below as part of a
+ // binary size optimization.
+ friend class ::base::internal::BasePromise;
+ friend class ::base::WrappedPromise;
+
+ scoped_refptr(T* p, base::cef_subtle::AdoptRefTag) : ptr_(p) {}
+
+ // Friend required for move constructors that set r.ptr_ to null.
+ template <typename U>
+ friend class scoped_refptr;
+
+ // Non-inline helpers to allow:
+ // class Opaque;
+ // extern template class scoped_refptr<Opaque>;
+ // Otherwise the compiler will complain that Opaque is an incomplete type.
+ static void AddRef(T* ptr);
+ static void Release(T* ptr);
+};
+
+template <typename T>
+T* scoped_refptr<T>::release() {
+ T* ptr = ptr_;
+ ptr_ = nullptr;
+ return ptr;
+}
+
+// static
+template <typename T>
+void scoped_refptr<T>::AddRef(T* ptr) {
+ ptr->AddRef();
+}
+
+// static
+template <typename T>
+void scoped_refptr<T>::Release(T* ptr) {
+ ptr->Release();
+}
+
+template <typename T, typename U>
+bool operator==(const scoped_refptr<T>& lhs, const U* rhs) {
+ return lhs.get() == rhs;
+}
+
+template <typename T, typename U>
+bool operator==(const T* lhs, const scoped_refptr<U>& rhs) {
+ return lhs == rhs.get();
+}
+
+template <typename T>
+bool operator==(const scoped_refptr<T>& lhs, std::nullptr_t null) {
+ return !static_cast<bool>(lhs);
+}
+
+template <typename T>
+bool operator==(std::nullptr_t null, const scoped_refptr<T>& rhs) {
+ return !static_cast<bool>(rhs);
+}
+
+template <typename T, typename U>
+bool operator!=(const scoped_refptr<T>& lhs, const U* rhs) {
+ return !operator==(lhs, rhs);
+}
+
+template <typename T, typename U>
+bool operator!=(const T* lhs, const scoped_refptr<U>& rhs) {
+ return !operator==(lhs, rhs);
+}
+
+template <typename T>
+bool operator!=(const scoped_refptr<T>& lhs, std::nullptr_t null) {
+ return !operator==(lhs, null);
+}
+
+template <typename T>
+bool operator!=(std::nullptr_t null, const scoped_refptr<T>& rhs) {
+ return !operator==(null, rhs);
+}
+
+template <typename T>
+std::ostream& operator<<(std::ostream& out, const scoped_refptr<T>& p) {
+ return out << p.get();
+}
+
+template <typename T>
+void swap(scoped_refptr<T>& lhs, scoped_refptr<T>& rhs) noexcept {
+ lhs.swap(rhs);
+}
+
+#endif // !USING_CHROMIUM_INCLUDES
+
+#endif // CEF_INCLUDE_BASE_CEF_SCOPED_REFPTR_H_
diff --git a/include/base/cef_scoped_typeref_mac.h b/include/base/cef_scoped_typeref_mac.h
new file mode 100644
index 00000000..65d16a1c
--- /dev/null
+++ b/include/base/cef_scoped_typeref_mac.h
@@ -0,0 +1,190 @@
+// Copyright (c) 2021 Marshall A. Greenblatt. Portions copyright (c) 2013
+// Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CEF_INCLUDE_BASE_CEF_SCOPED_TYPEREF_MAC_H_
+#define CEF_INCLUDE_BASE_CEF_SCOPED_TYPEREF_MAC_H_
+#pragma once
+
+#if defined(USING_CHROMIUM_INCLUDES)
+// When building CEF include the Chromium header directly.
+#include "base/mac/scoped_typeref.h"
+#else // !USING_CHROMIUM_INCLUDES
+// The following is substantially similar to the Chromium implementation.
+// If the Chromium implementation diverges the below implementation should be
+// updated to match.
+
+#include "include/base/cef_logging.h"
+#include "include/base/internal/cef_scoped_policy.h"
+
+namespace base {
+
+template <typename T>
+struct ScopedTypeRefTraits;
+
+///
+/// ScopedTypeRef<> is patterned after std::unique_ptr<>, but maintains
+/// ownership of a reference to any type that is maintained by Retain and
+/// Release methods.
+///
+/// The Traits structure must provide the Retain and Release methods for type T.
+/// A default ScopedTypeRefTraits is used but not defined, and should be defined
+/// for each type to use this interface. For example, an appropriate definition
+/// of ScopedTypeRefTraits for CGLContextObj would be:
+///
+/// <pre>
+/// template<>
+/// struct ScopedTypeRefTraits<CGLContextObj> {
+/// static CGLContextObj InvalidValue() { return nullptr; }
+/// static CGLContextObj Retain(CGLContextObj object) {
+/// CGLContextRetain(object);
+/// return object;
+/// }
+/// static void Release(CGLContextObj object) { CGLContextRelease(object); }
+/// };
+/// </pre>
+///
+/// For the many types that have pass-by-pointer create functions, the function
+/// InitializeInto() is provided to allow direct initialization and assumption
+/// of ownership of the object. For example, continuing to use the above
+/// CGLContextObj specialization:
+///
+/// <pre>
+/// base::ScopedTypeRef<CGLContextObj> context;
+/// CGLCreateContext(pixel_format, share_group, context.InitializeInto());
+/// </pre>
+///
+/// For initialization with an existing object, the caller may specify whether
+/// the ScopedTypeRef<> being initialized is assuming the caller's existing
+/// ownership of the object (and should not call Retain in initialization) or if
+/// it should not assume this ownership and must create its own (by calling
+/// Retain in initialization). This behavior is based on the |policy| parameter,
+/// with |ASSUME| for the former and |RETAIN| for the latter. The default policy
+/// is to |ASSUME|.
+///
+template <typename T, typename Traits = ScopedTypeRefTraits<T>>
+class ScopedTypeRef {
+ public:
+ using element_type = T;
+
+ explicit constexpr ScopedTypeRef(
+ element_type object = Traits::InvalidValue(),
+ base::scoped_policy::OwnershipPolicy policy = base::scoped_policy::ASSUME)
+ : object_(object) {
+ if (object_ && policy == base::scoped_policy::RETAIN) {
+ object_ = Traits::Retain(object_);
+ }
+ }
+
+ ScopedTypeRef(const ScopedTypeRef<T, Traits>& that) : object_(that.object_) {
+ if (object_) {
+ object_ = Traits::Retain(object_);
+ }
+ }
+
+ // This allows passing an object to a function that takes its superclass.
+ template <typename R, typename RTraits>
+ explicit ScopedTypeRef(const ScopedTypeRef<R, RTraits>& that_as_subclass)
+ : object_(that_as_subclass.get()) {
+ if (object_) {
+ object_ = Traits::Retain(object_);
+ }
+ }
+
+ ScopedTypeRef(ScopedTypeRef<T, Traits>&& that) : object_(that.object_) {
+ that.object_ = Traits::InvalidValue();
+ }
+
+ ~ScopedTypeRef() {
+ if (object_) {
+ Traits::Release(object_);
+ }
+ }
+
+ ScopedTypeRef& operator=(const ScopedTypeRef<T, Traits>& that) {
+ reset(that.get(), base::scoped_policy::RETAIN);
+ return *this;
+ }
+
+ // This is to be used only to take ownership of objects that are created
+ // by pass-by-pointer create functions. To enforce this, require that the
+ // object be reset to NULL before this may be used.
+ [[nodiscard]] element_type* InitializeInto() {
+ DCHECK(!object_);
+ return &object_;
+ }
+
+ void reset(const ScopedTypeRef<T, Traits>& that) {
+ reset(that.get(), base::scoped_policy::RETAIN);
+ }
+
+ void reset(element_type object = Traits::InvalidValue(),
+ base::scoped_policy::OwnershipPolicy policy =
+ base::scoped_policy::ASSUME) {
+ if (object && policy == base::scoped_policy::RETAIN) {
+ object = Traits::Retain(object);
+ }
+ if (object_) {
+ Traits::Release(object_);
+ }
+ object_ = object;
+ }
+
+ bool operator==(const element_type& that) const { return object_ == that; }
+
+ bool operator!=(const element_type& that) const { return object_ != that; }
+
+ operator element_type() const { return object_; }
+
+ element_type get() const { return object_; }
+
+ void swap(ScopedTypeRef& that) {
+ element_type temp = that.object_;
+ that.object_ = object_;
+ object_ = temp;
+ }
+
+ // ScopedTypeRef<>::release() is like std::unique_ptr<>::release. It is NOT
+ // a wrapper for Release(). To force a ScopedTypeRef<> object to call
+ // Release(), use ScopedTypeRef<>::reset().
+ [[nodiscard]] element_type release() {
+ element_type temp = object_;
+ object_ = Traits::InvalidValue();
+ return temp;
+ }
+
+ private:
+ element_type object_;
+};
+
+} // namespace base
+
+#endif // !USING_CHROMIUM_INCLUDES
+
+#endif // CEF_INCLUDE_BASE_CEF_SCOPED_TYPEREF_MAC_H_
diff --git a/include/base/cef_template_util.h b/include/base/cef_template_util.h
new file mode 100644
index 00000000..6661fc03
--- /dev/null
+++ b/include/base/cef_template_util.h
@@ -0,0 +1,417 @@
+// Copyright (c) 2014 Marshall A. Greenblatt. Portions copyright (c) 2011
+// Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CEF_INCLUDE_BASE_CEF_TEMPLATE_UTIL_H_
+#define CEF_INCLUDE_BASE_CEF_TEMPLATE_UTIL_H_
+#pragma once
+
+#if defined(USING_CHROMIUM_INCLUDES)
+// When building CEF include the Chromium header directly.
+#include "base/template_util.h"
+#else // !USING_CHROMIUM_INCLUDES
+// The following is substantially similar to the Chromium implementation.
+// If the Chromium implementation diverges the below implementation should be
+// updated to match.
+
+#include <stddef.h>
+#include <iosfwd>
+#include <iterator>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#include "include/base/cef_build.h"
+
+// Some versions of libstdc++ have partial support for type_traits, but misses
+// a smaller subset while removing some of the older non-standard stuff. Assume
+// that all versions below 5.0 fall in this category, along with one 5.0
+// experimental release. Test for this by consulting compiler major version,
+// the only reliable option available, so theoretically this could fail should
+// you attempt to mix an earlier version of libstdc++ with >= GCC5. But
+// that's unlikely to work out, especially as GCC5 changed ABI.
+#define CR_GLIBCXX_5_0_0 20150123
+#if (defined(__GNUC__) && __GNUC__ < 5) || \
+ (defined(__GLIBCXX__) && __GLIBCXX__ == CR_GLIBCXX_5_0_0)
+#define CR_USE_FALLBACKS_FOR_OLD_EXPERIMENTAL_GLIBCXX
+#endif
+
+// This hacks around using gcc with libc++ which has some incompatibilies.
+// - is_trivially_* doesn't work: https://llvm.org/bugs/show_bug.cgi?id=27538
+// TODO(danakj): Remove this when android builders are all using a newer version
+// of gcc, or the android ndk is updated to a newer libc++ that works with older
+// gcc versions.
+#if !defined(__clang__) && defined(_LIBCPP_VERSION)
+#define CR_USE_FALLBACKS_FOR_GCC_WITH_LIBCXX
+#endif
+
+namespace base {
+
+template <class T>
+struct is_non_const_reference : std::false_type {};
+template <class T>
+struct is_non_const_reference<T&> : std::true_type {};
+template <class T>
+struct is_non_const_reference<const T&> : std::false_type {};
+
+namespace internal {
+
+// Implementation detail of base::void_t below.
+template <typename...>
+struct make_void {
+ using type = void;
+};
+
+} // namespace internal
+
+// base::void_t is an implementation of std::void_t from C++17.
+//
+// We use |base::internal::make_void| as a helper struct to avoid a C++14
+// defect:
+// http://en.cppreference.com/w/cpp/types/void_t
+// http://open-std.org/JTC1/SC22/WG21/docs/cwg_defects.html#1558
+template <typename... Ts>
+using void_t = typename ::base::internal::make_void<Ts...>::type;
+
+namespace internal {
+
+// Uses expression SFINAE to detect whether using operator<< would work.
+template <typename T, typename = void>
+struct SupportsOstreamOperator : std::false_type {};
+template <typename T>
+struct SupportsOstreamOperator<T,
+ decltype(void(std::declval<std::ostream&>()
+ << std::declval<T>()))>
+ : std::true_type {};
+
+template <typename T, typename = void>
+struct SupportsToString : std::false_type {};
+template <typename T>
+struct SupportsToString<T, decltype(void(std::declval<T>().ToString()))>
+ : std::true_type {};
+
+// Used to detect whether the given type is an iterator. This is normally used
+// with std::enable_if to provide disambiguation for functions that take
+// templatzed iterators as input.
+template <typename T, typename = void>
+struct is_iterator : std::false_type {};
+
+template <typename T>
+struct is_iterator<T,
+ void_t<typename std::iterator_traits<T>::iterator_category>>
+ : std::true_type {};
+
+// Helper to express preferences in an overload set. If more than one overload
+// are available for a given set of parameters the overload with the higher
+// priority will be chosen.
+template <size_t I>
+struct priority_tag : priority_tag<I - 1> {};
+
+template <>
+struct priority_tag<0> {};
+
+} // namespace internal
+
+// is_trivially_copyable is especially hard to get right.
+// - Older versions of libstdc++ will fail to have it like they do for other
+// type traits. This has become a subset of the second point, but used to be
+// handled independently.
+// - An experimental release of gcc includes most of type_traits but misses
+// is_trivially_copyable, so we still have to avoid using libstdc++ in this
+// case, which is covered by CR_USE_FALLBACKS_FOR_OLD_EXPERIMENTAL_GLIBCXX.
+// - When compiling libc++ from before r239653, with a gcc compiler, the
+// std::is_trivially_copyable can fail. So we need to work around that by not
+// using the one in libc++ in this case. This is covered by the
+// CR_USE_FALLBACKS_FOR_GCC_WITH_LIBCXX define, and is discussed in
+// https://llvm.org/bugs/show_bug.cgi?id=27538#c1 where they point out that
+// in libc++'s commit r239653 this is fixed by libc++ checking for gcc 5.1.
+// - In both of the above cases we are using the gcc compiler. When defining
+// this ourselves on compiler intrinsics, the __is_trivially_copyable()
+// intrinsic is not available on gcc before version 5.1 (see the discussion in
+// https://llvm.org/bugs/show_bug.cgi?id=27538#c1 again), so we must check for
+// that version.
+// - When __is_trivially_copyable() is not available because we are on gcc older
+// than 5.1, we need to fall back to something, so we use __has_trivial_copy()
+// instead based on what was done one-off in bit_cast() previously.
+
+// TODO(crbug.com/554293): Remove this when all platforms have this in the std
+// namespace and it works with gcc as needed.
+#if defined(CR_USE_FALLBACKS_FOR_OLD_EXPERIMENTAL_GLIBCXX) || \
+ defined(CR_USE_FALLBACKS_FOR_GCC_WITH_LIBCXX)
+template <typename T>
+struct is_trivially_copyable {
+// TODO(danakj): Remove this when android builders are all using a newer version
+// of gcc, or the android ndk is updated to a newer libc++ that does this for
+// us.
+#if _GNUC_VER >= 501
+ static constexpr bool value = __is_trivially_copyable(T);
+#else
+ static constexpr bool value =
+ __has_trivial_copy(T) && __has_trivial_destructor(T);
+#endif
+};
+#else
+template <class T>
+using is_trivially_copyable = std::is_trivially_copyable<T>;
+#endif
+
+#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ <= 7
+// Workaround for g++7 and earlier family.
+// Due to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80654, without this
+// Optional<std::vector<T>> where T is non-copyable causes a compile error.
+// As we know it is not trivially copy constructible, explicitly declare so.
+template <typename T>
+struct is_trivially_copy_constructible
+ : std::is_trivially_copy_constructible<T> {};
+
+template <typename... T>
+struct is_trivially_copy_constructible<std::vector<T...>> : std::false_type {};
+#else
+// Otherwise use std::is_trivially_copy_constructible as is.
+template <typename T>
+using is_trivially_copy_constructible = std::is_trivially_copy_constructible<T>;
+#endif
+
+// base::in_place_t is an implementation of std::in_place_t from
+// C++17. A tag type used to request in-place construction in template vararg
+// constructors.
+
+// Specification:
+// https://en.cppreference.com/w/cpp/utility/in_place
+struct in_place_t {};
+constexpr in_place_t in_place = {};
+
+// base::in_place_type_t is an implementation of std::in_place_type_t from
+// C++17. A tag type used for in-place construction when the type to construct
+// needs to be specified, such as with base::unique_any, designed to be a
+// drop-in replacement.
+
+// Specification:
+// http://en.cppreference.com/w/cpp/utility/in_place
+template <typename T>
+struct in_place_type_t {};
+
+template <typename T>
+struct is_in_place_type_t {
+ static constexpr bool value = false;
+};
+
+template <typename... Ts>
+struct is_in_place_type_t<in_place_type_t<Ts...>> {
+ static constexpr bool value = true;
+};
+
+// C++14 implementation of C++17's std::bool_constant.
+//
+// Reference: https://en.cppreference.com/w/cpp/types/integral_constant
+// Specification: https://wg21.link/meta.type.synop
+template <bool B>
+using bool_constant = std::integral_constant<bool, B>;
+
+// C++14 implementation of C++17's std::conjunction.
+//
+// Reference: https://en.cppreference.com/w/cpp/types/conjunction
+// Specification: https://wg21.link/meta.logical#1.itemdecl:1
+template <typename...>
+struct conjunction : std::true_type {};
+
+template <typename B1>
+struct conjunction<B1> : B1 {};
+
+template <typename B1, typename... Bn>
+struct conjunction<B1, Bn...>
+ : std::conditional_t<static_cast<bool>(B1::value), conjunction<Bn...>, B1> {
+};
+
+// C++14 implementation of C++17's std::disjunction.
+//
+// Reference: https://en.cppreference.com/w/cpp/types/disjunction
+// Specification: https://wg21.link/meta.logical#itemdecl:2
+template <typename...>
+struct disjunction : std::false_type {};
+
+template <typename B1>
+struct disjunction<B1> : B1 {};
+
+template <typename B1, typename... Bn>
+struct disjunction<B1, Bn...>
+ : std::conditional_t<static_cast<bool>(B1::value), B1, disjunction<Bn...>> {
+};
+
+// C++14 implementation of C++17's std::negation.
+//
+// Reference: https://en.cppreference.com/w/cpp/types/negation
+// Specification: https://wg21.link/meta.logical#itemdecl:3
+template <typename B>
+struct negation : bool_constant<!static_cast<bool>(B::value)> {};
+
+// Implementation of C++17's invoke_result.
+//
+// This implementation adds references to `Functor` and `Args` to work around
+// some quirks of std::result_of. See the #Notes section of [1] for details.
+//
+// References:
+// [1] https://en.cppreference.com/w/cpp/types/result_of
+// [2] https://wg21.link/meta.trans.other#lib:invoke_result
+#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L)
+template <typename Functor, typename... Args>
+using invoke_result = std::invoke_result<Functor, Args...>;
+#else
+template <typename Functor, typename... Args>
+using invoke_result = std::result_of<Functor && (Args && ...)>;
+#endif
+
+// Implementation of C++17's std::invoke_result_t.
+//
+// Reference: https://wg21.link/meta.type.synop#lib:invoke_result_t
+template <typename Functor, typename... Args>
+using invoke_result_t = typename invoke_result<Functor, Args...>::type;
+
+namespace internal {
+
+// Base case, `InvokeResult` does not have a nested type member. This means `F`
+// could not be invoked with `Args...` and thus is not invocable.
+template <typename InvokeResult, typename R, typename = void>
+struct IsInvocableImpl : std::false_type {};
+
+// Happy case, `InvokeResult` does have a nested type member. Now check whether
+// `InvokeResult::type` is convertible to `R`. Short circuit in case
+// `std::is_void<R>`.
+template <typename InvokeResult, typename R>
+struct IsInvocableImpl<InvokeResult, R, void_t<typename InvokeResult::type>>
+ : disjunction<std::is_void<R>,
+ std::is_convertible<typename InvokeResult::type, R>> {};
+
+} // namespace internal
+
+// Implementation of C++17's std::is_invocable_r.
+//
+// Returns whether `F` can be invoked with `Args...` and the result is
+// convertible to `R`.
+//
+// Reference: https://wg21.link/meta.rel#lib:is_invocable_r
+template <typename R, typename F, typename... Args>
+struct is_invocable_r
+ : internal::IsInvocableImpl<invoke_result<F, Args...>, R> {};
+
+// Implementation of C++17's std::is_invocable.
+//
+// Returns whether `F` can be invoked with `Args...`.
+//
+// Reference: https://wg21.link/meta.rel#lib:is_invocable
+template <typename F, typename... Args>
+struct is_invocable : is_invocable_r<void, F, Args...> {};
+
+namespace internal {
+
+// The indirection with std::is_enum<T> is required, because instantiating
+// std::underlying_type_t<T> when T is not an enum is UB prior to C++20.
+template <typename T, bool = std::is_enum<T>::value>
+struct IsScopedEnumImpl : std::false_type {};
+
+template <typename T>
+struct IsScopedEnumImpl<T, /*std::is_enum<T>::value=*/true>
+ : negation<std::is_convertible<T, std::underlying_type_t<T>>> {};
+
+} // namespace internal
+
+// Implementation of C++23's std::is_scoped_enum
+//
+// Reference: https://en.cppreference.com/w/cpp/types/is_scoped_enum
+template <typename T>
+struct is_scoped_enum : internal::IsScopedEnumImpl<T> {};
+
+// Implementation of C++20's std::remove_cvref.
+//
+// References:
+// - https://en.cppreference.com/w/cpp/types/remove_cvref
+// - https://wg21.link/meta.trans.other#lib:remove_cvref
+template <typename T>
+struct remove_cvref {
+ using type = std::remove_cv_t<std::remove_reference_t<T>>;
+};
+
+// Implementation of C++20's std::remove_cvref_t.
+//
+// References:
+// - https://en.cppreference.com/w/cpp/types/remove_cvref
+// - https://wg21.link/meta.type.synop#lib:remove_cvref_t
+template <typename T>
+using remove_cvref_t = typename remove_cvref<T>::type;
+
+// Simplified implementation of C++20's std::iter_value_t.
+// As opposed to std::iter_value_t, this implementation does not restrict
+// the type of `Iter` and does not consider specializations of
+// `indirectly_readable_traits`.
+//
+// Reference: https://wg21.link/readable.traits#2
+template <typename Iter>
+using iter_value_t =
+ typename std::iterator_traits<remove_cvref_t<Iter>>::value_type;
+
+// Simplified implementation of C++20's std::iter_reference_t.
+// As opposed to std::iter_reference_t, this implementation does not restrict
+// the type of `Iter`.
+//
+// Reference: https://wg21.link/iterator.synopsis#:~:text=iter_reference_t
+template <typename Iter>
+using iter_reference_t = decltype(*std::declval<Iter&>());
+
+// Simplified implementation of C++20's std::indirect_result_t. As opposed to
+// std::indirect_result_t, this implementation does not restrict the type of
+// `Func` and `Iters`.
+//
+// Reference: https://wg21.link/iterator.synopsis#:~:text=indirect_result_t
+template <typename Func, typename... Iters>
+using indirect_result_t = invoke_result_t<Func, iter_reference_t<Iters>...>;
+
+// Simplified implementation of C++20's std::projected. As opposed to
+// std::projected, this implementation does not explicitly restrict the type of
+// `Iter` and `Proj`, but rather does so implicitly by requiring
+// `indirect_result_t<Proj, Iter>` is a valid type. This is required for SFINAE
+// friendliness.
+//
+// Reference: https://wg21.link/projected
+template <typename Iter,
+ typename Proj,
+ typename IndirectResultT = indirect_result_t<Proj, Iter>>
+struct projected {
+ using value_type = remove_cvref_t<IndirectResultT>;
+
+ IndirectResultT operator*() const; // not defined
+};
+
+} // namespace base
+
+#undef CR_USE_FALLBACKS_FOR_GCC_WITH_LIBCXX
+#undef CR_USE_FALLBACKS_FOR_OLD_EXPERIMENTAL_GLIBCXX
+
+#endif // !USING_CHROMIUM_INCLUDES
+
+#endif // CEF_INCLUDE_BASE_CEF_TEMPLATE_UTIL_H_
diff --git a/include/base/cef_thread_checker.h b/include/base/cef_thread_checker.h
new file mode 100644
index 00000000..6f21c697
--- /dev/null
+++ b/include/base/cef_thread_checker.h
@@ -0,0 +1,125 @@
+// Copyright (c) 2014 Marshall A. Greenblatt. Portions copyright (c) 2012
+// Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CEF_INCLUDE_BASE_THREAD_CHECKER_H_
+#define CEF_INCLUDE_BASE_THREAD_CHECKER_H_
+#pragma once
+
+#if defined(USING_CHROMIUM_INCLUDES)
+// When building CEF include the Chromium header directly.
+#include "base/threading/thread_checker.h"
+#else // !USING_CHROMIUM_INCLUDES
+// The following is substantially similar to the Chromium implementation.
+// If the Chromium implementation diverges the below implementation should be
+// updated to match.
+
+#include "include/base/cef_logging.h"
+#include "include/base/internal/cef_thread_checker_impl.h"
+
+///
+/// Apart from debug builds, we also enable the thread checker in
+/// builds with DCHECK_ALWAYS_ON so that trybots and waterfall bots
+/// with this define will get the same level of thread checking as
+/// debug bots.
+///
+#if DCHECK_IS_ON()
+#define ENABLE_THREAD_CHECKER 1
+#else
+#define ENABLE_THREAD_CHECKER 0
+#endif
+
+namespace base {
+
+namespace cef_internal {
+
+///
+/// Do nothing implementation, for use in release mode.
+///
+/// Note: You should almost always use the ThreadChecker class to get the
+/// right version for your build configuration.
+///
+class ThreadCheckerDoNothing {
+ public:
+ bool CalledOnValidThread() const { return true; }
+
+ void DetachFromThread() {}
+};
+
+} // namespace cef_internal
+
+///
+/// ThreadChecker is a helper class used to help verify that some methods of a
+/// class are called from the same thread. It provides identical functionality
+/// to base::NonThreadSafe, but it is meant to be held as a member variable,
+/// rather than inherited from base::NonThreadSafe.
+///
+/// While inheriting from base::NonThreadSafe may give a clear indication about
+/// the thread-safety of a class, it may also lead to violations of the style
+/// guide with regard to multiple inheritance. The choice between having a
+/// ThreadChecker member and inheriting from base::NonThreadSafe should be based
+/// on whether:
+/// - Derived classes need to know the thread they belong to, as opposed to
+/// having that functionality fully encapsulated in the base class.
+/// - Derived classes should be able to reassign the base class to another
+/// thread, via DetachFromThread.
+///
+/// If neither of these are true, then having a ThreadChecker member and calling
+/// CalledOnValidThread is the preferable solution.
+///
+/// Example:
+///
+/// <pre>
+/// class MyClass {
+/// public:
+/// void Foo() {
+/// DCHECK(thread_checker_.CalledOnValidThread());
+/// ... (do stuff) ...
+/// }
+///
+/// private:
+/// ThreadChecker thread_checker_;
+/// }
+/// </pre>
+///
+/// In Release mode, CalledOnValidThread will always return true.
+///
+#if ENABLE_THREAD_CHECKER
+class ThreadChecker : public cef_internal::ThreadCheckerImpl {};
+#else
+class ThreadChecker : public cef_internal::ThreadCheckerDoNothing {};
+#endif // ENABLE_THREAD_CHECKER
+
+#undef ENABLE_THREAD_CHECKER
+
+} // namespace base
+
+#endif // !USING_CHROMIUM_INCLUDES
+
+#endif // CEF_INCLUDE_BASE_THREAD_CHECKER_H_
diff --git a/include/base/cef_trace_event.h b/include/base/cef_trace_event.h
new file mode 100644
index 00000000..9f90217e
--- /dev/null
+++ b/include/base/cef_trace_event.h
@@ -0,0 +1,463 @@
+// Copyright (c) 2014 Marshall A. Greenblatt. Portions copyright (c) 2012
+// Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+///
+/// \file
+/// Trace events are for tracking application performance and resource usage.
+/// Macros are provided to track:
+/// Begin and end of function calls
+/// Counters
+///
+/// Events are issued against categories. Whereas LOG's categories are
+/// statically defined, TRACE categories are created implicitly with a string.
+/// For example: <pre>
+/// TRACE_EVENT_INSTANT0("MY_SUBSYSTEM", "SomeImportantEvent")
+/// </pre>
+///
+/// Events can be INSTANT, or can be pairs of BEGIN and END in the same scope:
+/// <pre>
+/// TRACE_EVENT_BEGIN0("MY_SUBSYSTEM", "SomethingCostly")
+/// doSomethingCostly()
+/// TRACE_EVENT_END0("MY_SUBSYSTEM", "SomethingCostly")
+/// </pre>
+/// Note: Our tools can't always determine the correct BEGIN/END pairs unless
+/// these are used in the same scope. Use ASYNC_BEGIN/ASYNC_END macros if you
+/// need them to be in separate scopes.
+///
+/// A common use case is to trace entire function scopes. This issues a trace
+/// BEGIN and END automatically:
+/// <pre>
+/// void doSomethingCostly() {
+/// TRACE_EVENT0("MY_SUBSYSTEM", "doSomethingCostly");
+/// ...
+/// }
+/// </pre>
+///
+/// Additional parameters can be associated with an event:
+/// <pre>
+/// void doSomethingCostly2(int howMuch) {
+/// TRACE_EVENT1("MY_SUBSYSTEM", "doSomethingCostly",
+/// "howMuch", howMuch);
+/// ...
+/// }
+/// </pre>
+///
+/// The trace system will automatically add to this information the current
+/// process id, thread id, and a timestamp in microseconds.
+///
+/// To trace an asynchronous procedure such as an IPC send/receive, use
+/// ASYNC_BEGIN and ASYNC_END:
+/// <pre>
+/// [single threaded sender code]
+/// static int send_count = 0;
+/// ++send_count;
+/// TRACE_EVENT_ASYNC_BEGIN0("ipc", "message", send_count);
+/// Send(new MyMessage(send_count));
+/// [receive code]
+/// void OnMyMessage(send_count) {
+/// TRACE_EVENT_ASYNC_END0("ipc", "message", send_count);
+/// }
+/// </pre>
+/// The third parameter is a unique ID to match ASYNC_BEGIN/ASYNC_END pairs.
+/// ASYNC_BEGIN and ASYNC_END can occur on any thread of any traced process.
+/// Pointers can be used for the ID parameter, and they will be mangled
+/// internally so that the same pointer on two different processes will not
+/// match. For example:
+/// <pre>
+/// class MyTracedClass {
+/// public:
+/// MyTracedClass() {
+/// TRACE_EVENT_ASYNC_BEGIN0("category", "MyTracedClass", this);
+/// }
+/// ~MyTracedClass() {
+/// TRACE_EVENT_ASYNC_END0("category", "MyTracedClass", this);
+/// }
+/// }
+/// </pre>
+///
+/// The trace event also supports counters, which is a way to track a quantity
+/// as it varies over time. Counters are created with the following macro:
+/// <pre>
+/// TRACE_COUNTER1("MY_SUBSYSTEM", "myCounter", g_myCounterValue);
+/// </pre>
+///
+/// Counters are process-specific. The macro itself can be issued from any
+/// thread, however.
+///
+/// Sometimes, you want to track two counters at once. You can do this with two
+/// counter macros:
+/// <pre>
+/// TRACE_COUNTER1("MY_SUBSYSTEM", "myCounter0", g_myCounterValue[0]);
+/// TRACE_COUNTER1("MY_SUBSYSTEM", "myCounter1", g_myCounterValue[1]);
+/// </pre>
+/// Or you can do it with a combined macro:
+/// <pre>
+/// TRACE_COUNTER2("MY_SUBSYSTEM", "myCounter",
+/// "bytesPinned", g_myCounterValue[0],
+/// "bytesAllocated", g_myCounterValue[1]);
+/// </pre>
+/// This indicates to the tracing UI that these counters should be displayed
+/// in a single graph, as a summed area chart.
+///
+/// Since counters are in a global namespace, you may want to disembiguate with
+/// a unique ID, by using the TRACE_COUNTER_ID* variations.
+///
+/// By default, trace collection is compiled in, but turned off at runtime.
+/// Collecting trace data is the responsibility of the embedding application. In
+/// CEF's case, calling BeginTracing will turn on tracing on all active
+/// processes.
+///
+///
+/// Memory scoping note:
+/// Tracing copies the pointers, not the string content, of the strings passed
+/// in for category, name, and arg_names. Thus, the following code will cause
+/// problems:
+/// <pre>
+/// char* str = strdup("impprtantName");
+/// TRACE_EVENT_INSTANT0("SUBSYSTEM", str); // BAD!
+/// free(str); // Trace system now has dangling pointer
+/// </pre>
+///
+/// To avoid this issue with the |name| and |arg_name| parameters, use the
+/// TRACE_EVENT_COPY_XXX overloads of the macros at additional runtime
+/// overhead.
+///
+/// Notes: The category must always be in a long-lived char* (i.e. static
+/// const). The |arg_values|, when used, are always deep copied with
+/// the _COPY macros.
+///
+///
+/// Thread Safety:
+/// All macros are thread safe and can be used from any process.
+///
+
+#ifndef CEF_INCLUDE_BASE_CEF_TRACE_EVENT_H_
+#define CEF_INCLUDE_BASE_CEF_TRACE_EVENT_H_
+#pragma once
+
+#if defined(USING_CHROMIUM_INCLUDES)
+/// When building CEF include the Chromium header directly.
+#include "base/trace_event/trace_event.h"
+#else // !USING_CHROMIUM_INCLUDES
+// The following is substantially similar to the Chromium implementation.
+// If the Chromium implementation diverges the below implementation should be
+// updated to match.
+
+#include "include/internal/cef_trace_event_internal.h"
+
+///
+/// Records a pair of begin and end events called "name" for the current
+/// scope, with 0, 1 or 2 associated arguments. If the category is not
+/// enabled, then this does nothing.
+/// - category and name strings must have application lifetime (statics or
+/// literals). They may not include " chars.
+///
+#define TRACE_EVENT0(category, name) \
+ cef_trace_event_begin(category, name, NULL, 0, NULL, 0, false); \
+ CEF_INTERNAL_TRACE_END_ON_SCOPE_CLOSE(category, name)
+#define TRACE_EVENT1(category, name, arg1_name, arg1_val) \
+ cef_trace_event_begin(category, name, arg1_name, arg1_val, NULL, 0, false); \
+ CEF_INTERNAL_TRACE_END_ON_SCOPE_CLOSE(category, name)
+#define TRACE_EVENT2(category, name, arg1_name, arg1_val, arg2_name, arg2_val) \
+ cef_trace_event_begin(category, name, arg1_name, arg1_val, arg2_name, \
+ arg2_val, false); \
+ CEF_INTERNAL_TRACE_END_ON_SCOPE_CLOSE(category, name)
+
+// Implementation detail: trace event macros create temporary variable names.
+// These macros give each temporary variable a unique name based on the line
+// number to prevent name collisions.
+#define CEF_INTERNAL_TRACE_EVENT_UID3(a, b) cef_trace_event_unique_##a##b
+#define CEF_INTERNAL_TRACE_EVENT_UID2(a, b) CEF_INTERNAL_TRACE_EVENT_UID3(a, b)
+#define CEF_INTERNAL_TRACE_EVENT_UID(name_prefix) \
+ CEF_INTERNAL_TRACE_EVENT_UID2(name_prefix, __LINE__)
+
+// Implementation detail: internal macro to end end event when the scope ends.
+#define CEF_INTERNAL_TRACE_END_ON_SCOPE_CLOSE(category, name) \
+ cef_trace_event::CefTraceEndOnScopeClose CEF_INTERNAL_TRACE_EVENT_UID( \
+ profileScope)(category, name)
+
+///
+/// Records a single event called "name" immediately, with 0, 1 or 2
+/// associated arguments. If the category is not enabled, then this
+/// does nothing.
+/// - category and name strings must have application lifetime (statics or
+/// literals). They may not include " chars.
+///
+#define TRACE_EVENT_INSTANT0(category, name) \
+ cef_trace_event_instant(category, name, NULL, 0, NULL, 0, false)
+#define TRACE_EVENT_INSTANT1(category, name, arg1_name, arg1_val) \
+ cef_trace_event_instant(category, name, arg1_name, arg1_val, NULL, 0, false)
+#define TRACE_EVENT_INSTANT2(category, name, arg1_name, arg1_val, arg2_name, \
+ arg2_val) \
+ cef_trace_event_instant(category, name, arg1_name, arg1_val, arg2_name, \
+ arg2_val, false)
+#define TRACE_EVENT_COPY_INSTANT0(category, name) \
+ cef_trace_event_instant(category, name, NULL, 0, NULL, 0, true)
+#define TRACE_EVENT_COPY_INSTANT1(category, name, arg1_name, arg1_val) \
+ cef_trace_event_instant(category, name, arg1_name, arg1_val, NULL, 0, true)
+#define TRACE_EVENT_COPY_INSTANT2(category, name, arg1_name, arg1_val, \
+ arg2_name, arg2_val) \
+ cef_trace_event_instant(category, name, arg1_name, arg1_val, arg2_name, \
+ arg2_val, true)
+
+///
+/// Records a single BEGIN event called "name" immediately, with 0, 1 or 2
+/// associated arguments. If the category is not enabled, then this
+/// does nothing.
+/// - category and name strings must have application lifetime (statics or
+/// literals). They may not include " chars.
+///
+#define TRACE_EVENT_BEGIN0(category, name) \
+ cef_trace_event_begin(category, name, NULL, 0, NULL, 0, false)
+#define TRACE_EVENT_BEGIN1(category, name, arg1_name, arg1_val) \
+ cef_trace_event_begin(category, name, arg1_name, arg1_val, NULL, 0, false)
+#define TRACE_EVENT_BEGIN2(category, name, arg1_name, arg1_val, arg2_name, \
+ arg2_val) \
+ cef_trace_event_begin(category, name, arg1_name, arg1_val, arg2_name, \
+ arg2_val, false)
+#define TRACE_EVENT_COPY_BEGIN0(category, name) \
+ cef_trace_event_begin(category, name, NULL, 0, NULL, 0, true)
+#define TRACE_EVENT_COPY_BEGIN1(category, name, arg1_name, arg1_val) \
+ cef_trace_event_begin(category, name, arg1_name, arg1_val, NULL, 0, true)
+#define TRACE_EVENT_COPY_BEGIN2(category, name, arg1_name, arg1_val, \
+ arg2_name, arg2_val) \
+ cef_trace_event_begin(category, name, arg1_name, arg1_val, arg2_name, \
+ arg2_val, true)
+
+///
+/// Records a single END event for "name" immediately. If the category
+/// is not enabled, then this does nothing.
+/// - category and name strings must have application lifetime (statics or
+/// literals). They may not include " chars.
+///
+#define TRACE_EVENT_END0(category, name) \
+ cef_trace_event_end(category, name, NULL, 0, NULL, 0, false)
+#define TRACE_EVENT_END1(category, name, arg1_name, arg1_val) \
+ cef_trace_event_end(category, name, arg1_name, arg1_val, NULL, 0, false)
+#define TRACE_EVENT_END2(category, name, arg1_name, arg1_val, arg2_name, \
+ arg2_val) \
+ cef_trace_event_end(category, name, arg1_name, arg1_val, arg2_name, \
+ arg2_val, false)
+#define TRACE_EVENT_COPY_END0(category, name) \
+ cef_trace_event_end(category, name, NULL, 0, NULL, 0, true)
+#define TRACE_EVENT_COPY_END1(category, name, arg1_name, arg1_val) \
+ cef_trace_event_end(category, name, arg1_name, arg1_val, NULL, 0, true)
+#define TRACE_EVENT_COPY_END2(category, name, arg1_name, arg1_val, arg2_name, \
+ arg2_val) \
+ cef_trace_event_end(category, name, arg1_name, arg1_val, arg2_name, \
+ arg2_val, true)
+
+///
+/// Records the value of a counter called "name" immediately. Value
+/// must be representable as a 32 bit integer.
+/// - category and name strings must have application lifetime (statics or
+/// literals). They may not include " chars.
+///
+#define TRACE_COUNTER1(category, name, value) \
+ cef_trace_counter(category, name, NULL, value, NULL, 0, false)
+#define TRACE_COPY_COUNTER1(category, name, value) \
+ cef_trace_counter(category, name, NULL, value, NULL, 0, true)
+
+///
+/// Records the values of a multi-parted counter called "name" immediately.
+/// The UI will treat value1 and value2 as parts of a whole, displaying their
+/// values as a stacked-bar chart.
+/// - category and name strings must have application lifetime (statics or
+/// literals). They may not include " chars.
+///
+#define TRACE_COUNTER2(category, name, value1_name, value1_val, value2_name, \
+ value2_val) \
+ cef_trace_counter(category, name, value1_name, value1_val, value2_name, \
+ value2_val, false)
+#define TRACE_COPY_COUNTER2(category, name, value1_name, value1_val, \
+ value2_name, value2_val) \
+ cef_trace_counter(category, name, value1_name, value1_val, value2_name, \
+ value2_val, true)
+
+///
+/// Records the value of a counter called "name" immediately. Value
+/// must be representable as a 32 bit integer.
+/// - category and name strings must have application lifetime (statics or
+/// literals). They may not include " chars.
+/// - |id| is used to disambiguate counters with the same name. It must either
+/// be a pointer or an integer value up to 64 bits. If it's a pointer, the
+/// bits will be xored with a hash of the process ID so that the same pointer
+/// on two different processes will not collide.
+///
+#define TRACE_COUNTER_ID1(category, name, id, value) \
+ cef_trace_counter_id(category, name, id, NULL, value, NULL, 0, false)
+#define TRACE_COPY_COUNTER_ID1(category, name, id, value) \
+ cef_trace_counter_id(category, name, id, NULL, value, NULL, 0, true)
+
+///
+/// Records the values of a multi-parted counter called "name" immediately.
+/// The UI will treat value1 and value2 as parts of a whole, displaying their
+/// values as a stacked-bar chart.
+/// - category and name strings must have application lifetime (statics or
+/// literals). They may not include " chars.
+/// - |id| is used to disambiguate counters with the same name. It must either
+/// be a pointer or an integer value up to 64 bits. If it's a pointer, the
+/// bits will be xored with a hash of the process ID so that the same pointer
+/// on two different processes will not collide.
+///
+#define TRACE_COUNTER_ID2(category, name, id, value1_name, value1_val, \
+ value2_name, value2_val) \
+ cef_trace_counter_id(category, name, id, value1_name, value1_val, \
+ value2_name, value2_val, false)
+#define TRACE_COPY_COUNTER_ID2(category, name, id, value1_name, value1_val, \
+ value2_name, value2_val) \
+ cef_trace_counter_id(category, name, id, value1_name, value1_val, \
+ value2_name, value2_val, true)
+
+///
+/// Records a single ASYNC_BEGIN event called "name" immediately, with 0, 1 or 2
+/// associated arguments. If the category is not enabled, then this
+/// does nothing.
+/// - category and name strings must have application lifetime (statics or
+/// literals). They may not include " chars.
+/// - |id| is used to match the ASYNC_BEGIN event with the ASYNC_END event.
+/// ASYNC events are considered to match if their category, name and id values
+/// all match. |id| must either be a pointer or an integer value up to 64
+/// bits. If it's a pointer, the bits will be xored with a hash of the process
+/// ID sothat the same pointer on two different processes will not collide.
+/// An asynchronous operation can consist of multiple phases. The first phase is
+/// defined by the ASYNC_BEGIN calls. Additional phases can be defined using the
+/// ASYNC_STEP_BEGIN macros. When the operation completes, call ASYNC_END.
+/// An async operation can span threads and processes, but all events in that
+/// operation must use the same |name| and |id|. Each event can have its own
+/// args.
+///
+#define TRACE_EVENT_ASYNC_BEGIN0(category, name, id) \
+ cef_trace_event_async_begin(category, name, id, NULL, 0, NULL, 0, false)
+#define TRACE_EVENT_ASYNC_BEGIN1(category, name, id, arg1_name, arg1_val) \
+ cef_trace_event_async_begin(category, name, id, arg1_name, arg1_val, NULL, \
+ 0, false)
+#define TRACE_EVENT_ASYNC_BEGIN2(category, name, id, arg1_name, arg1_val, \
+ arg2_name, arg2_val) \
+ cef_trace_event_async_begin(category, name, id, arg1_name, arg1_val, \
+ arg2_name, arg2_val, false)
+#define TRACE_EVENT_COPY_ASYNC_BEGIN0(category, name, id) \
+ cef_trace_event_async_begin(category, name, id, NULL, 0, NULL, 0, true)
+#define TRACE_EVENT_COPY_ASYNC_BEGIN1(category, name, id, arg1_name, arg1_val) \
+ cef_trace_event_async_begin(category, name, id, arg1_name, arg1_val, NULL, \
+ 0, true)
+#define TRACE_EVENT_COPY_ASYNC_BEGIN2(category, name, id, arg1_name, arg1_val, \
+ arg2_name, arg2_val) \
+ cef_trace_event_async_begin(category, name, id, arg1_name, arg1_val, \
+ arg2_name, arg2_val, true)
+
+///
+/// Records a single ASYNC_STEP_INTO event for |step| immediately. If the
+/// category is not enabled, then this does nothing. The |name| and |id| must
+/// match the ASYNC_BEGIN event above. The |step| param identifies this step
+/// within the async event. This should be called at the beginning of the next
+/// phase of an asynchronous operation. The ASYNC_BEGIN event must not have any
+/// ASYNC_STEP_PAST events.
+///
+#define TRACE_EVENT_ASYNC_STEP_INTO0(category, name, id, step) \
+ cef_trace_event_async_step_into(category, name, id, step, NULL, 0, false)
+#define TRACE_EVENT_ASYNC_STEP_INTO1(category, name, id, step, arg1_name, \
+ arg1_val) \
+ cef_trace_event_async_step_into(category, name, id, step, arg1_name, \
+ arg1_val, false)
+#define TRACE_EVENT_COPY_ASYNC_STEP_INTO0(category, name, id, step) \
+ cef_trace_event_async_step_into(category, name, id, step, NULL, 0, true)
+#define TRACE_EVENT_COPY_ASYNC_STEP_INTO1(category, name, id, step, arg1_name, \
+ arg1_val) \
+ cef_trace_event_async_step_into(category, name, id, step, arg1_name, \
+ arg1_val, true)
+
+///
+/// Records a single ASYNC_STEP_PAST event for |step| immediately. If the
+/// category is not enabled, then this does nothing. The |name| and |id| must
+/// match the ASYNC_BEGIN event above. The |step| param identifies this step
+/// within the async event. This should be called at the beginning of the next
+/// phase of an asynchronous operation. The ASYNC_BEGIN event must not have any
+/// ASYNC_STEP_INTO events.
+///
+#define TRACE_EVENT_ASYNC_STEP_PAST0(category, name, id, step) \
+ cef_trace_event_async_step_past(category, name, id, step, NULL, 0, false)
+#define TRACE_EVENT_ASYNC_STEP_PAST1(category, name, id, step, arg1_name, \
+ arg1_val) \
+ cef_trace_event_async_step_past(category, name, id, step, arg1_name, \
+ arg1_val, false)
+#define TRACE_EVENT_COPY_ASYNC_STEP_PAST0(category, name, id, step) \
+ cef_trace_event_async_step_past(category, name, id, step, NULL, 0, true)
+#define TRACE_EVENT_COPY_ASYNC_STEP_PAST1(category, name, id, step, arg1_name, \
+ arg1_val) \
+ cef_trace_event_async_step_past(category, name, id, step, arg1_name, \
+ arg1_val, true)
+
+///
+/// Records a single ASYNC_END event for "name" immediately. If the category
+/// is not enabled, then this does nothing.
+///
+#define TRACE_EVENT_ASYNC_END0(category, name, id) \
+ cef_trace_event_async_end(category, name, id, NULL, 0, NULL, 0, false)
+#define TRACE_EVENT_ASYNC_END1(category, name, id, arg1_name, arg1_val) \
+ cef_trace_event_async_end(category, name, id, arg1_name, arg1_val, NULL, 0, \
+ false)
+#define TRACE_EVENT_ASYNC_END2(category, name, id, arg1_name, arg1_val, \
+ arg2_name, arg2_val) \
+ cef_trace_event_async_end(category, name, id, arg1_name, arg1_val, \
+ arg2_name, arg2_val, false)
+#define TRACE_EVENT_COPY_ASYNC_END0(category, name, id) \
+ cef_trace_event_async_end(category, name, id, NULL, 0, NULL, 0, true)
+#define TRACE_EVENT_COPY_ASYNC_END1(category, name, id, arg1_name, arg1_val) \
+ cef_trace_event_async_end(category, name, id, arg1_name, arg1_val, NULL, 0, \
+ true)
+#define TRACE_EVENT_COPY_ASYNC_END2(category, name, id, arg1_name, arg1_val, \
+ arg2_name, arg2_val) \
+ cef_trace_event_async_end(category, name, id, arg1_name, arg1_val, \
+ arg2_name, arg2_val, true)
+
+namespace cef_trace_event {
+
+///
+/// Used by TRACE_EVENTx macro. Do not use directly.
+///
+class CefTraceEndOnScopeClose {
+ public:
+ CefTraceEndOnScopeClose(const char* category, const char* name)
+ : category_(category), name_(name) {}
+ ~CefTraceEndOnScopeClose() {
+ cef_trace_event_end(category_, name_, NULL, 0, NULL, 0, false);
+ }
+
+ private:
+ const char* category_;
+ const char* name_;
+};
+
+} // namespace cef_trace_event
+
+#endif // !USING_CHROMIUM_INCLUDES
+
+#endif // CEF_INCLUDE_BASE_CEF_TRACE_EVENT_H_
diff --git a/include/base/cef_tuple.h b/include/base/cef_tuple.h
new file mode 100644
index 00000000..ae438d39
--- /dev/null
+++ b/include/base/cef_tuple.h
@@ -0,0 +1,152 @@
+// Copyright (c) 2014 Marshall A. Greenblatt. Portions copyright (c) 2011
+// Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+///
+/// \file
+/// Use std::tuple as tuple type. This file contains helper functions for
+/// working with std::tuples.
+/// The functions DispatchToMethod and DispatchToFunction take a function
+/// pointer or instance and method pointer, and unpack a tuple into arguments to
+/// the call.
+///
+/// Example usage:
+/// <pre>
+/// // These two methods of creating a Tuple are identical.
+/// std::tuple<int, const char*> tuple_a(1, "wee");
+/// std::tuple<int, const char*> tuple_b = std::make_tuple(1, "wee");
+///
+/// void SomeFunc(int a, const char* b) { }
+/// DispatchToFunction(&SomeFunc, tuple_a); // SomeFunc(1, "wee")
+/// DispatchToFunction(
+/// &SomeFunc, std::make_tuple(10, "foo")); // SomeFunc(10, "foo")
+///
+/// struct { void SomeMeth(int a, int b, int c) { } } foo;
+/// DispatchToMethod(&foo, &Foo::SomeMeth, std::make_tuple(1, 2, 3));
+/// // foo->SomeMeth(1, 2, 3);
+/// </pre>
+///
+
+#ifndef CEF_INCLUDE_BASE_CEF_TUPLE_H_
+#define CEF_INCLUDE_BASE_CEF_TUPLE_H_
+#pragma once
+
+#if defined(USING_CHROMIUM_INCLUDES)
+// When building CEF include the Chromium header directly.
+#include "base/tuple.h"
+#else // !USING_CHROMIUM_INCLUDES
+// The following is substantially similar to the Chromium implementation.
+// If the Chromium implementation diverges the below implementation should be
+// updated to match.
+
+#include <stddef.h>
+#include <tuple>
+#include <utility>
+
+#include "include/base/cef_build.h"
+
+namespace base {
+
+// Dispatchers ----------------------------------------------------------------
+//
+// Helper functions that call the given method on an object, with the unpacked
+// tuple arguments. Notice that they all have the same number of arguments,
+// so you need only write:
+// DispatchToMethod(object, &Object::method, args);
+// This is very useful for templated dispatchers, since they don't need to know
+// what type |args| is.
+
+// Non-Static Dispatchers with no out params.
+
+template <typename ObjT, typename Method, typename Tuple, size_t... Ns>
+inline void DispatchToMethodImpl(const ObjT& obj,
+ Method method,
+ Tuple&& args,
+ std::index_sequence<Ns...>) {
+ (obj->*method)(std::get<Ns>(std::forward<Tuple>(args))...);
+}
+
+template <typename ObjT, typename Method, typename Tuple>
+inline void DispatchToMethod(const ObjT& obj, Method method, Tuple&& args) {
+ constexpr size_t size = std::tuple_size<std::decay_t<Tuple>>::value;
+ DispatchToMethodImpl(obj, method, std::forward<Tuple>(args),
+ std::make_index_sequence<size>());
+}
+
+// Static Dispatchers with no out params.
+
+template <typename Function, typename Tuple, size_t... Ns>
+inline void DispatchToFunctionImpl(Function function,
+ Tuple&& args,
+ std::index_sequence<Ns...>) {
+ (*function)(std::get<Ns>(std::forward<Tuple>(args))...);
+}
+
+template <typename Function, typename Tuple>
+inline void DispatchToFunction(Function function, Tuple&& args) {
+ constexpr size_t size = std::tuple_size<std::decay_t<Tuple>>::value;
+ DispatchToFunctionImpl(function, std::forward<Tuple>(args),
+ std::make_index_sequence<size>());
+}
+
+// Dispatchers with out parameters.
+
+template <typename ObjT,
+ typename Method,
+ typename InTuple,
+ typename OutTuple,
+ size_t... InNs,
+ size_t... OutNs>
+inline void DispatchToMethodImpl(const ObjT& obj,
+ Method method,
+ InTuple&& in,
+ OutTuple* out,
+ std::index_sequence<InNs...>,
+ std::index_sequence<OutNs...>) {
+ (obj->*method)(std::get<InNs>(std::forward<InTuple>(in))...,
+ &std::get<OutNs>(*out)...);
+}
+
+template <typename ObjT, typename Method, typename InTuple, typename OutTuple>
+inline void DispatchToMethod(const ObjT& obj,
+ Method method,
+ InTuple&& in,
+ OutTuple* out) {
+ constexpr size_t in_size = std::tuple_size<std::decay_t<InTuple>>::value;
+ constexpr size_t out_size = std::tuple_size<OutTuple>::value;
+ DispatchToMethodImpl(obj, method, std::forward<InTuple>(in), out,
+ std::make_index_sequence<in_size>(),
+ std::make_index_sequence<out_size>());
+}
+
+} // namespace base
+
+#endif // !USING_CHROMIUM_INCLUDES
+
+#endif // CEF_INCLUDE_BASE_CEF_TUPLE_H_
diff --git a/include/base/cef_weak_ptr.h b/include/base/cef_weak_ptr.h
new file mode 100644
index 00000000..63e1a742
--- /dev/null
+++ b/include/base/cef_weak_ptr.h
@@ -0,0 +1,469 @@
+// Copyright (c) 2014 Marshall A. Greenblatt. Portions copyright (c) 2012
+// Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+///
+/// \file
+/// Weak pointers are pointers to an object that do not affect its lifetime.
+/// They may be invalidated (i.e. reset to nullptr) by the object, or its
+/// owner, at any time, most commonly when the object is about to be deleted.
+///
+/// Weak pointers are useful when an object needs to be accessed safely by one
+/// or more objects other than its owner, and those callers can cope with the
+/// object vanishing and e.g. tasks posted to it being silently dropped.
+/// Reference-counting such an object would complicate the ownership graph and
+/// make it harder to reason about the object's lifetime.
+///
+/// EXAMPLE:
+///
+/// <pre>
+/// class Controller {
+/// public:
+/// void SpawnWorker() { Worker::StartNew(weak_factory_.GetWeakPtr()); }
+/// void WorkComplete(const Result& result) { ... }
+/// private:
+/// // Member variables should appear before the WeakPtrFactory, to ensure
+/// // that any WeakPtrs to Controller are invalidated before its members
+/// // variable's destructors are executed, rendering them invalid.
+/// WeakPtrFactory<Controller> weak_factory_{this};
+/// };
+///
+/// class Worker {
+/// public:
+/// static void StartNew(WeakPtr<Controller> controller) {
+/// Worker* worker = new Worker(std::move(controller));
+/// // Kick off asynchronous processing...
+/// }
+/// private:
+/// Worker(WeakPtr<Controller> controller)
+/// : controller_(std::move(controller)) {}
+/// void DidCompleteAsynchronousProcessing(const Result& result) {
+/// if (controller_)
+/// controller_->WorkComplete(result);
+/// }
+/// WeakPtr<Controller> controller_;
+/// };
+/// </pre>
+///
+/// With this implementation a caller may use SpawnWorker() to dispatch multiple
+/// Workers and subsequently delete the Controller, without waiting for all
+/// Workers to have completed.
+///
+/// <b>IMPORTANT: Thread-safety</b>
+///
+/// Weak pointers may be passed safely between threads, but must always be
+/// dereferenced and invalidated on the same ThreaddTaskRunner otherwise
+/// checking the pointer would be racey.
+///
+/// To ensure correct use, the first time a WeakPtr issued by a WeakPtrFactory
+/// is dereferenced, the factory and its WeakPtrs become bound to the calling
+/// thread or current ThreaddWorkerPool token, and cannot be dereferenced or
+/// invalidated on any other task runner. Bound WeakPtrs can still be handed
+/// off to other task runners, e.g. to use to post tasks back to object on the
+/// bound thread.
+///
+/// If all WeakPtr objects are destroyed or invalidated then the factory is
+/// unbound from the ThreadedTaskRunner/Thread. The WeakPtrFactory may then be
+/// destroyed, or new WeakPtr objects may be used, from a different thread.
+///
+/// Thus, at least one WeakPtr object must exist and have been dereferenced on
+/// the correct thread to enforce that other WeakPtr objects will enforce they
+/// are used on the desired thread.
+
+#ifndef CEF_INCLUDE_BASE_CEF_WEAK_PTR_H_
+#define CEF_INCLUDE_BASE_CEF_WEAK_PTR_H_
+#pragma once
+
+#if defined(USING_CHROMIUM_INCLUDES)
+// When building CEF include the Chromium header directly.
+#include "base/memory/weak_ptr.h"
+#else // !USING_CHROMIUM_INCLUDES
+// The following is substantially similar to the Chromium implementation.
+// If the Chromium implementation diverges the below implementation should be
+// updated to match.
+
+#include <cstddef>
+#include <type_traits>
+
+#include "include/base/cef_atomic_flag.h"
+#include "include/base/cef_logging.h"
+#include "include/base/cef_ref_counted.h"
+#include "include/base/cef_thread_checker.h"
+
+namespace base {
+
+template <typename T>
+class SupportsWeakPtr;
+template <typename T>
+class WeakPtr;
+
+namespace internal {
+// These classes are part of the WeakPtr implementation.
+// DO NOT USE THESE CLASSES DIRECTLY YOURSELF.
+
+class WeakReference {
+ public:
+ // Although Flag is bound to a specific ThreaddTaskRunner, it may be
+ // deleted from another via base::WeakPtr::~WeakPtr().
+ class Flag : public RefCountedThreadSafe<Flag> {
+ public:
+ Flag();
+
+ void Invalidate();
+ bool IsValid() const;
+
+ bool MaybeValid() const;
+
+ void DetachFromThread();
+
+ private:
+ friend class base::RefCountedThreadSafe<Flag>;
+
+ ~Flag();
+
+ base::ThreadChecker thread_checker_;
+ AtomicFlag invalidated_;
+ };
+
+ WeakReference();
+ explicit WeakReference(const scoped_refptr<Flag>& flag);
+ ~WeakReference();
+
+ WeakReference(WeakReference&& other) noexcept;
+ WeakReference(const WeakReference& other);
+ WeakReference& operator=(WeakReference&& other) noexcept = default;
+ WeakReference& operator=(const WeakReference& other) = default;
+
+ bool IsValid() const;
+ bool MaybeValid() const;
+
+ private:
+ scoped_refptr<const Flag> flag_;
+};
+
+class WeakReferenceOwner {
+ public:
+ WeakReferenceOwner();
+ ~WeakReferenceOwner();
+
+ WeakReference GetRef() const;
+
+ bool HasRefs() const { return !flag_->HasOneRef(); }
+
+ void Invalidate();
+
+ private:
+ scoped_refptr<WeakReference::Flag> flag_;
+};
+
+// This class simplifies the implementation of WeakPtr's type conversion
+// constructor by avoiding the need for a public accessor for ref_. A
+// WeakPtr<T> cannot access the private members of WeakPtr<U>, so this
+// base class gives us a way to access ref_ in a protected fashion.
+class WeakPtrBase {
+ public:
+ WeakPtrBase();
+ ~WeakPtrBase();
+
+ WeakPtrBase(const WeakPtrBase& other) = default;
+ WeakPtrBase(WeakPtrBase&& other) noexcept = default;
+ WeakPtrBase& operator=(const WeakPtrBase& other) = default;
+ WeakPtrBase& operator=(WeakPtrBase&& other) noexcept = default;
+
+ void reset() {
+ ref_ = internal::WeakReference();
+ ptr_ = 0;
+ }
+
+ protected:
+ WeakPtrBase(const WeakReference& ref, uintptr_t ptr);
+
+ WeakReference ref_;
+
+ // This pointer is only valid when ref_.is_valid() is true. Otherwise, its
+ // value is undefined (as opposed to nullptr).
+ uintptr_t ptr_;
+};
+
+// This class provides a common implementation of common functions that would
+// otherwise get instantiated separately for each distinct instantiation of
+// SupportsWeakPtr<>.
+class SupportsWeakPtrBase {
+ public:
+ // A safe static downcast of a WeakPtr<Base> to WeakPtr<Derived>. This
+ // conversion will only compile if there is exists a Base which inherits
+ // from SupportsWeakPtr<Base>. See base::AsWeakPtr() below for a helper
+ // function that makes calling this easier.
+ //
+ // Precondition: t != nullptr
+ template <typename Derived>
+ static WeakPtr<Derived> StaticAsWeakPtr(Derived* t) {
+ static_assert(
+ std::is_base_of<internal::SupportsWeakPtrBase, Derived>::value,
+ "AsWeakPtr argument must inherit from SupportsWeakPtr");
+ return AsWeakPtrImpl<Derived>(t);
+ }
+
+ private:
+ // This template function uses type inference to find a Base of Derived
+ // which is an instance of SupportsWeakPtr<Base>. We can then safely
+ // static_cast the Base* to a Derived*.
+ template <typename Derived, typename Base>
+ static WeakPtr<Derived> AsWeakPtrImpl(SupportsWeakPtr<Base>* t) {
+ WeakPtr<Base> ptr = t->AsWeakPtr();
+ return WeakPtr<Derived>(
+ ptr.ref_, static_cast<Derived*>(reinterpret_cast<Base*>(ptr.ptr_)));
+ }
+};
+
+} // namespace internal
+
+template <typename T>
+class WeakPtrFactory;
+
+///
+/// The WeakPtr class holds a weak reference to |T*|.
+///
+/// This class is designed to be used like a normal pointer. You should always
+/// null-test an object of this class before using it or invoking a method that
+/// may result in the underlying object being destroyed.
+///
+/// EXAMPLE:
+///
+/// <pre>
+/// class Foo { ... };
+/// WeakPtr<Foo> foo;
+/// if (foo)
+/// foo->method();
+/// </pre>
+///
+template <typename T>
+class WeakPtr : public internal::WeakPtrBase {
+ public:
+ WeakPtr() = default;
+ WeakPtr(std::nullptr_t) {}
+
+ ///
+ /// Allow conversion from U to T provided U "is a" T. Note that this
+ /// is separate from the (implicit) copy and move constructors.
+ ///
+ template <typename U>
+ WeakPtr(const WeakPtr<U>& other) : WeakPtrBase(other) {
+ // Need to cast from U* to T* to do pointer adjustment in case of multiple
+ // inheritance. This also enforces the "U is a T" rule.
+ T* t = reinterpret_cast<U*>(other.ptr_);
+ ptr_ = reinterpret_cast<uintptr_t>(t);
+ }
+ template <typename U>
+ WeakPtr(WeakPtr<U>&& other) noexcept : WeakPtrBase(std::move(other)) {
+ // Need to cast from U* to T* to do pointer adjustment in case of multiple
+ // inheritance. This also enforces the "U is a T" rule.
+ T* t = reinterpret_cast<U*>(other.ptr_);
+ ptr_ = reinterpret_cast<uintptr_t>(t);
+ }
+
+ T* get() const {
+ return ref_.IsValid() ? reinterpret_cast<T*>(ptr_) : nullptr;
+ }
+
+ T& operator*() const {
+ CHECK(ref_.IsValid());
+ return *get();
+ }
+ T* operator->() const {
+ CHECK(ref_.IsValid());
+ return get();
+ }
+
+ ///
+ /// Allow conditionals to test validity, e.g. `if (weak_ptr) {...}`;
+ ///
+ explicit operator bool() const { return get() != nullptr; }
+
+ ///
+ /// Returns false if the WeakPtr is confirmed to be invalid. This call is safe
+ /// to make from any thread, e.g. to optimize away unnecessary work, but
+ /// operator bool() must always be called, on the correct thread, before
+ /// actually using the pointer.
+ ///
+ /// Warning: as with any object, this call is only thread-safe if the WeakPtr
+ /// instance isn't being re-assigned or reset() racily with this call.
+ ///
+ bool MaybeValid() const { return ref_.MaybeValid(); }
+
+ ///
+ /// Returns whether the object |this| points to has been invalidated. This can
+ /// be used to distinguish a WeakPtr to a destroyed object from one that has
+ /// been explicitly set to null.
+ ///
+ bool WasInvalidated() const { return ptr_ && !ref_.IsValid(); }
+
+ private:
+ friend class internal::SupportsWeakPtrBase;
+ template <typename U>
+ friend class WeakPtr;
+ friend class SupportsWeakPtr<T>;
+ friend class WeakPtrFactory<T>;
+
+ WeakPtr(const internal::WeakReference& ref, T* ptr)
+ : WeakPtrBase(ref, reinterpret_cast<uintptr_t>(ptr)) {}
+};
+
+///
+/// Allow callers to compare WeakPtrs against nullptr to test validity.
+///
+template <class T>
+bool operator!=(const WeakPtr<T>& weak_ptr, std::nullptr_t) {
+ return !(weak_ptr == nullptr);
+}
+template <class T>
+bool operator!=(std::nullptr_t, const WeakPtr<T>& weak_ptr) {
+ return weak_ptr != nullptr;
+}
+template <class T>
+bool operator==(const WeakPtr<T>& weak_ptr, std::nullptr_t) {
+ return weak_ptr.get() == nullptr;
+}
+template <class T>
+bool operator==(std::nullptr_t, const WeakPtr<T>& weak_ptr) {
+ return weak_ptr == nullptr;
+}
+
+namespace internal {
+class WeakPtrFactoryBase {
+ protected:
+ WeakPtrFactoryBase(uintptr_t ptr);
+ ~WeakPtrFactoryBase();
+ internal::WeakReferenceOwner weak_reference_owner_;
+ uintptr_t ptr_;
+};
+} // namespace internal
+
+///
+/// A class may be composed of a WeakPtrFactory and thereby control how it
+/// exposes weak pointers to itself. This is helpful if you only need weak
+/// pointers within the implementation of a class. This class is also useful
+/// when working with primitive types. For example, you could have a
+/// WeakPtrFactory<bool> that is used to pass around a weak reference to a
+/// bool.
+///
+template <class T>
+class WeakPtrFactory : public internal::WeakPtrFactoryBase {
+ public:
+ WeakPtrFactory() = delete;
+
+ explicit WeakPtrFactory(T* ptr)
+ : WeakPtrFactoryBase(reinterpret_cast<uintptr_t>(ptr)) {}
+
+ WeakPtrFactory(const WeakPtrFactory&) = delete;
+ WeakPtrFactory& operator=(const WeakPtrFactory&) = delete;
+
+ ~WeakPtrFactory() = default;
+
+ WeakPtr<T> GetWeakPtr() const {
+ return WeakPtr<T>(weak_reference_owner_.GetRef(),
+ reinterpret_cast<T*>(ptr_));
+ }
+
+ ///
+ /// Call this method to invalidate all existing weak pointers.
+ ///
+ void InvalidateWeakPtrs() {
+ DCHECK(ptr_);
+ weak_reference_owner_.Invalidate();
+ }
+
+ ///
+ /// Call this method to determine if any weak pointers exist.
+ ///
+ bool HasWeakPtrs() const {
+ DCHECK(ptr_);
+ return weak_reference_owner_.HasRefs();
+ }
+};
+
+///
+/// A class may extend from SupportsWeakPtr to let others take weak pointers to
+/// it. This avoids the class itself implementing boilerplate to dispense weak
+/// pointers. However, since SupportsWeakPtr's destructor won't invalidate
+/// weak pointers to the class until after the derived class' members have been
+/// destroyed, its use can lead to subtle use-after-destroy issues.
+///
+template <class T>
+class SupportsWeakPtr : public internal::SupportsWeakPtrBase {
+ public:
+ SupportsWeakPtr() = default;
+
+ SupportsWeakPtr(const SupportsWeakPtr&) = delete;
+ SupportsWeakPtr& operator=(const SupportsWeakPtr&) = delete;
+
+ WeakPtr<T> AsWeakPtr() {
+ return WeakPtr<T>(weak_reference_owner_.GetRef(), static_cast<T*>(this));
+ }
+
+ protected:
+ ~SupportsWeakPtr() = default;
+
+ private:
+ internal::WeakReferenceOwner weak_reference_owner_;
+};
+
+///
+/// Helper function that uses type deduction to safely return a WeakPtr<Derived>
+/// when Derived doesn't directly extend SupportsWeakPtr<Derived>, instead it
+/// extends a Base that extends SupportsWeakPtr<Base>.
+///
+/// EXAMPLE:
+/// <pre>
+/// class Base : public base::SupportsWeakPtr<Producer> {};
+/// class Derived : public Base {};
+///
+/// Derived derived;
+/// base::WeakPtr<Derived> ptr = base::AsWeakPtr(&derived);
+/// </pre>
+///
+/// Note that the following doesn't work (invalid type conversion) since
+/// Derived::AsWeakPtr() is WeakPtr<Base> SupportsWeakPtr<Base>::AsWeakPtr(),
+/// and there's no way to safely cast WeakPtr<Base> to WeakPtr<Derived> at
+/// the caller.
+///
+/// <pre>
+/// base::WeakPtr<Derived> ptr = derived.AsWeakPtr(); // Fails.
+/// </pre>
+///
+template <typename Derived>
+WeakPtr<Derived> AsWeakPtr(Derived* t) {
+ return internal::SupportsWeakPtrBase::StaticAsWeakPtr<Derived>(t);
+}
+
+} // namespace base
+
+#endif // !USING_CHROMIUM_INCLUDES
+
+#endif // CEF_INCLUDE_BASE_CEF_WEAK_PTR_H_
diff --git a/include/base/internal/cef_bind_internal.h b/include/base/internal/cef_bind_internal.h
new file mode 100644
index 00000000..0c0b53d9
--- /dev/null
+++ b/include/base/internal/cef_bind_internal.h
@@ -0,0 +1,1415 @@
+// Copyright (c) 2011 Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Do not include this header file directly. Use base/cef_bind.h instead.
+
+// See base/cef_callback.h for user documentation.
+//
+//
+// CONCEPTS:
+// Functor -- A movable type representing something that should be called.
+// All function pointers and Callback<> are functors even if the
+// invocation syntax differs.
+// RunType -- A function type (as opposed to function _pointer_ type) for
+// a Callback<>::Run(). Usually just a convenience typedef.
+// (Bound)Args -- A set of types that stores the arguments.
+//
+// Types:
+// ForceVoidReturn<> -- Helper class for translating function signatures to
+// equivalent forms with a "void" return type.
+// FunctorTraits<> -- Type traits used to determine the correct RunType and
+// invocation manner for a Functor. This is where function
+// signature adapters are applied.
+// InvokeHelper<> -- Take a Functor + arguments and actully invokes it.
+// Handle the differing syntaxes needed for WeakPtr<>
+// support. This is separate from Invoker to avoid creating
+// multiple version of Invoker<>.
+// Invoker<> -- Unwraps the curried parameters and executes the Functor.
+// BindState<> -- Stores the curried parameters, and is the main entry point
+// into the Bind() system.
+
+#ifndef CEF_INCLUDE_BASE_INTERNAL_CEF_BIND_INTERNAL_H_
+#define CEF_INCLUDE_BASE_INTERNAL_CEF_BIND_INTERNAL_H_
+
+#include <stddef.h>
+
+#include <functional>
+#include <memory>
+#include <tuple>
+#include <type_traits>
+#include <utility>
+
+#include "include/base/cef_build.h"
+#include "include/base/cef_compiler_specific.h"
+#include "include/base/cef_logging.h"
+#include "include/base/cef_template_util.h"
+#include "include/base/cef_weak_ptr.h"
+#include "include/base/internal/cef_callback_internal.h"
+#include "include/base/internal/cef_raw_scoped_refptr_mismatch_checker.h"
+
+#if defined(OS_APPLE) && !HAS_FEATURE(objc_arc)
+#include "include/base/internal/cef_scoped_block_mac.h"
+#endif
+
+#if defined(OS_WIN)
+namespace Microsoft {
+namespace WRL {
+template <typename>
+class ComPtr;
+} // namespace WRL
+} // namespace Microsoft
+#endif
+
+namespace base {
+
+template <typename T>
+struct IsWeakReceiver;
+
+template <typename>
+struct BindUnwrapTraits;
+
+template <typename Functor, typename BoundArgsTuple, typename SFINAE = void>
+struct CallbackCancellationTraits;
+
+namespace cef_internal {
+
+template <typename Functor, typename SFINAE = void>
+struct FunctorTraits;
+
+template <typename T>
+class UnretainedWrapper {
+ public:
+ explicit UnretainedWrapper(T* o) : ptr_(o) {}
+ T* get() const { return ptr_; }
+
+ private:
+ T* ptr_;
+};
+
+template <typename T>
+class RetainedRefWrapper {
+ public:
+ explicit RetainedRefWrapper(T* o) : ptr_(o) {}
+ explicit RetainedRefWrapper(scoped_refptr<T> o) : ptr_(std::move(o)) {}
+ T* get() const { return ptr_.get(); }
+
+ private:
+ scoped_refptr<T> ptr_;
+};
+
+template <typename T>
+struct IgnoreResultHelper {
+ explicit IgnoreResultHelper(T functor) : functor_(std::move(functor)) {}
+ explicit operator bool() const { return !!functor_; }
+
+ T functor_;
+};
+
+template <typename T, typename Deleter = std::default_delete<T>>
+class OwnedWrapper {
+ public:
+ explicit OwnedWrapper(T* o) : ptr_(o) {}
+ explicit OwnedWrapper(std::unique_ptr<T, Deleter>&& ptr)
+ : ptr_(std::move(ptr)) {}
+ T* get() const { return ptr_.get(); }
+
+ private:
+ std::unique_ptr<T, Deleter> ptr_;
+};
+
+template <typename T>
+class OwnedRefWrapper {
+ public:
+ explicit OwnedRefWrapper(const T& t) : t_(t) {}
+ explicit OwnedRefWrapper(T&& t) : t_(std::move(t)) {}
+ T& get() const { return t_; }
+
+ private:
+ mutable T t_;
+};
+
+// PassedWrapper is a copyable adapter for a scoper that ignores const.
+//
+// It is needed to get around the fact that Bind() takes a const reference to
+// all its arguments. Because Bind() takes a const reference to avoid
+// unnecessary copies, it is incompatible with movable-but-not-copyable
+// types; doing a destructive "move" of the type into Bind() would violate
+// the const correctness.
+//
+// This conundrum cannot be solved without either C++11 rvalue references or
+// a O(2^n) blowup of Bind() templates to handle each combination of regular
+// types and movable-but-not-copyable types. Thus we introduce a wrapper type
+// that is copyable to transmit the correct type information down into
+// BindState<>. Ignoring const in this type makes sense because it is only
+// created when we are explicitly trying to do a destructive move.
+//
+// Two notes:
+// 1) PassedWrapper supports any type that has a move constructor, however
+// the type will need to be specifically allowed in order for it to be
+// bound to a Callback. We guard this explicitly at the call of Passed()
+// to make for clear errors. Things not given to Passed() will be forwarded
+// and stored by value which will not work for general move-only types.
+// 2) is_valid_ is distinct from NULL because it is valid to bind a "NULL"
+// scoper to a Callback and allow the Callback to execute once.
+template <typename T>
+class PassedWrapper {
+ public:
+ explicit PassedWrapper(T&& scoper)
+ : is_valid_(true), scoper_(std::move(scoper)) {}
+ PassedWrapper(PassedWrapper&& other)
+ : is_valid_(other.is_valid_), scoper_(std::move(other.scoper_)) {}
+ T Take() const {
+ CHECK(is_valid_);
+ is_valid_ = false;
+ return std::move(scoper_);
+ }
+
+ private:
+ mutable bool is_valid_;
+ mutable T scoper_;
+};
+
+template <typename T>
+using Unwrapper = BindUnwrapTraits<std::decay_t<T>>;
+
+template <typename T>
+decltype(auto) Unwrap(T&& o) {
+ return Unwrapper<T>::Unwrap(std::forward<T>(o));
+}
+
+// IsWeakMethod is a helper that determine if we are binding a WeakPtr<> to a
+// method. It is used internally by Bind() to select the correct
+// InvokeHelper that will no-op itself in the event the WeakPtr<> for
+// the target object is invalidated.
+//
+// The first argument should be the type of the object that will be received by
+// the method.
+template <bool is_method, typename... Args>
+struct IsWeakMethod : std::false_type {};
+
+template <typename T, typename... Args>
+struct IsWeakMethod<true, T, Args...> : IsWeakReceiver<T> {};
+
+// Packs a list of types to hold them in a single type.
+template <typename... Types>
+struct TypeList {};
+
+// Used for DropTypeListItem implementation.
+template <size_t n, typename List>
+struct DropTypeListItemImpl;
+
+// Do not use enable_if and SFINAE here to avoid MSVC2013 compile failure.
+template <size_t n, typename T, typename... List>
+struct DropTypeListItemImpl<n, TypeList<T, List...>>
+ : DropTypeListItemImpl<n - 1, TypeList<List...>> {};
+
+template <typename T, typename... List>
+struct DropTypeListItemImpl<0, TypeList<T, List...>> {
+ using Type = TypeList<T, List...>;
+};
+
+template <>
+struct DropTypeListItemImpl<0, TypeList<>> {
+ using Type = TypeList<>;
+};
+
+// A type-level function that drops |n| list item from given TypeList.
+template <size_t n, typename List>
+using DropTypeListItem = typename DropTypeListItemImpl<n, List>::Type;
+
+// Used for TakeTypeListItem implementation.
+template <size_t n, typename List, typename... Accum>
+struct TakeTypeListItemImpl;
+
+// Do not use enable_if and SFINAE here to avoid MSVC2013 compile failure.
+template <size_t n, typename T, typename... List, typename... Accum>
+struct TakeTypeListItemImpl<n, TypeList<T, List...>, Accum...>
+ : TakeTypeListItemImpl<n - 1, TypeList<List...>, Accum..., T> {};
+
+template <typename T, typename... List, typename... Accum>
+struct TakeTypeListItemImpl<0, TypeList<T, List...>, Accum...> {
+ using Type = TypeList<Accum...>;
+};
+
+template <typename... Accum>
+struct TakeTypeListItemImpl<0, TypeList<>, Accum...> {
+ using Type = TypeList<Accum...>;
+};
+
+// A type-level function that takes first |n| list item from given TypeList.
+// E.g. TakeTypeListItem<3, TypeList<A, B, C, D>> is evaluated to
+// TypeList<A, B, C>.
+template <size_t n, typename List>
+using TakeTypeListItem = typename TakeTypeListItemImpl<n, List>::Type;
+
+// Used for ConcatTypeLists implementation.
+template <typename List1, typename List2>
+struct ConcatTypeListsImpl;
+
+template <typename... Types1, typename... Types2>
+struct ConcatTypeListsImpl<TypeList<Types1...>, TypeList<Types2...>> {
+ using Type = TypeList<Types1..., Types2...>;
+};
+
+// A type-level function that concats two TypeLists.
+template <typename List1, typename List2>
+using ConcatTypeLists = typename ConcatTypeListsImpl<List1, List2>::Type;
+
+// Used for MakeFunctionType implementation.
+template <typename R, typename ArgList>
+struct MakeFunctionTypeImpl;
+
+template <typename R, typename... Args>
+struct MakeFunctionTypeImpl<R, TypeList<Args...>> {
+ // MSVC 2013 doesn't support Type Alias of function types.
+ // Revisit this after we update it to newer version.
+ typedef R Type(Args...);
+};
+
+// A type-level function that constructs a function type that has |R| as its
+// return type and has TypeLists items as its arguments.
+template <typename R, typename ArgList>
+using MakeFunctionType = typename MakeFunctionTypeImpl<R, ArgList>::Type;
+
+// Used for ExtractArgs and ExtractReturnType.
+template <typename Signature>
+struct ExtractArgsImpl;
+
+template <typename R, typename... Args>
+struct ExtractArgsImpl<R(Args...)> {
+ using ReturnType = R;
+ using ArgsList = TypeList<Args...>;
+};
+
+// A type-level function that extracts function arguments into a TypeList.
+// E.g. ExtractArgs<R(A, B, C)> is evaluated to TypeList<A, B, C>.
+template <typename Signature>
+using ExtractArgs = typename ExtractArgsImpl<Signature>::ArgsList;
+
+// A type-level function that extracts the return type of a function.
+// E.g. ExtractReturnType<R(A, B, C)> is evaluated to R.
+template <typename Signature>
+using ExtractReturnType = typename ExtractArgsImpl<Signature>::ReturnType;
+
+template <typename Callable,
+ typename Signature = decltype(&Callable::operator())>
+struct ExtractCallableRunTypeImpl;
+
+template <typename Callable, typename R, typename... Args>
+struct ExtractCallableRunTypeImpl<Callable, R (Callable::*)(Args...)> {
+ using Type = R(Args...);
+};
+
+template <typename Callable, typename R, typename... Args>
+struct ExtractCallableRunTypeImpl<Callable, R (Callable::*)(Args...) const> {
+ using Type = R(Args...);
+};
+
+// Evaluated to RunType of the given callable type.
+// Example:
+// auto f = [](int, char*) { return 0.1; };
+// ExtractCallableRunType<decltype(f)>
+// is evaluated to
+// double(int, char*);
+template <typename Callable>
+using ExtractCallableRunType =
+ typename ExtractCallableRunTypeImpl<Callable>::Type;
+
+// IsCallableObject<Functor> is std::true_type if |Functor| has operator().
+// Otherwise, it's std::false_type.
+// Example:
+// IsCallableObject<void(*)()>::value is false.
+//
+// struct Foo {};
+// IsCallableObject<void(Foo::*)()>::value is false.
+//
+// int i = 0;
+// auto f = [i]() {};
+// IsCallableObject<decltype(f)>::value is false.
+template <typename Functor, typename SFINAE = void>
+struct IsCallableObject : std::false_type {};
+
+template <typename Callable>
+struct IsCallableObject<Callable, void_t<decltype(&Callable::operator())>>
+ : std::true_type {};
+
+// HasRefCountedTypeAsRawPtr inherits from true_type when any of the |Args| is a
+// raw pointer to a RefCounted type.
+template <typename... Ts>
+struct HasRefCountedTypeAsRawPtr
+ : disjunction<NeedsScopedRefptrButGetsRawPtr<Ts>...> {};
+
+// ForceVoidReturn<>
+//
+// Set of templates that support forcing the function return type to void.
+template <typename Sig>
+struct ForceVoidReturn;
+
+template <typename R, typename... Args>
+struct ForceVoidReturn<R(Args...)> {
+ using RunType = void(Args...);
+};
+
+// FunctorTraits<>
+//
+// See description at top of file.
+template <typename Functor, typename SFINAE>
+struct FunctorTraits;
+
+// For empty callable types.
+// This specialization is intended to allow binding captureless lambdas, based
+// on the fact that captureless lambdas are empty while capturing lambdas are
+// not. This also allows any functors as far as it's an empty class.
+// Example:
+//
+// // Captureless lambdas are allowed.
+// []() {return 42;};
+//
+// // Capturing lambdas are *not* allowed.
+// int x;
+// [x]() {return x;};
+//
+// // Any empty class with operator() is allowed.
+// struct Foo {
+// void operator()() const {}
+// // No non-static member variable and no virtual functions.
+// };
+template <typename Functor>
+struct FunctorTraits<Functor,
+ std::enable_if_t<IsCallableObject<Functor>::value &&
+ std::is_empty<Functor>::value>> {
+ using RunType = ExtractCallableRunType<Functor>;
+ static constexpr bool is_method = false;
+ static constexpr bool is_nullable = false;
+ static constexpr bool is_callback = false;
+
+ template <typename RunFunctor, typename... RunArgs>
+ static ExtractReturnType<RunType> Invoke(RunFunctor&& functor,
+ RunArgs&&... args) {
+ return std::forward<RunFunctor>(functor)(std::forward<RunArgs>(args)...);
+ }
+};
+
+// For functions.
+template <typename R, typename... Args>
+struct FunctorTraits<R (*)(Args...)> {
+ using RunType = R(Args...);
+ static constexpr bool is_method = false;
+ static constexpr bool is_nullable = true;
+ static constexpr bool is_callback = false;
+
+ template <typename Function, typename... RunArgs>
+ static R Invoke(Function&& function, RunArgs&&... args) {
+ return std::forward<Function>(function)(std::forward<RunArgs>(args)...);
+ }
+};
+
+#if defined(OS_WIN) && !defined(ARCH_CPU_64_BITS)
+
+// For functions.
+template <typename R, typename... Args>
+struct FunctorTraits<R(__stdcall*)(Args...)> {
+ using RunType = R(Args...);
+ static constexpr bool is_method = false;
+ static constexpr bool is_nullable = true;
+ static constexpr bool is_callback = false;
+
+ template <typename... RunArgs>
+ static R Invoke(R(__stdcall* function)(Args...), RunArgs&&... args) {
+ return function(std::forward<RunArgs>(args)...);
+ }
+};
+
+// For functions.
+template <typename R, typename... Args>
+struct FunctorTraits<R(__fastcall*)(Args...)> {
+ using RunType = R(Args...);
+ static constexpr bool is_method = false;
+ static constexpr bool is_nullable = true;
+ static constexpr bool is_callback = false;
+
+ template <typename... RunArgs>
+ static R Invoke(R(__fastcall* function)(Args...), RunArgs&&... args) {
+ return function(std::forward<RunArgs>(args)...);
+ }
+};
+
+#endif // defined(OS_WIN) && !defined(ARCH_CPU_64_BITS)
+
+#if defined(OS_APPLE)
+
+// Support for Objective-C blocks. There are two implementation depending
+// on whether Automated Reference Counting (ARC) is enabled. When ARC is
+// enabled, then the block itself can be bound as the compiler will ensure
+// its lifetime will be correctly managed. Otherwise, require the block to
+// be wrapped in a base::mac::ScopedBlock (via base::RetainBlock) that will
+// correctly manage the block lifetime.
+//
+// The two implementation ensure that the One Definition Rule (ODR) is not
+// broken (it is not possible to write a template base::RetainBlock that would
+// work correctly both with ARC enabled and disabled).
+
+#if HAS_FEATURE(objc_arc)
+
+template <typename R, typename... Args>
+struct FunctorTraits<R (^)(Args...)> {
+ using RunType = R(Args...);
+ static constexpr bool is_method = false;
+ static constexpr bool is_nullable = true;
+ static constexpr bool is_callback = false;
+
+ template <typename BlockType, typename... RunArgs>
+ static R Invoke(BlockType&& block, RunArgs&&... args) {
+ // According to LLVM documentation (6.3), "local variables of automatic
+ // storage duration do not have precise lifetime." Use objc_precise_lifetime
+ // to ensure that the Objective-C block is not deallocated until it has
+ // finished executing even if the Callback<> is destroyed during the block
+ // execution.
+ // https://clang.llvm.org/docs/AutomaticReferenceCounting.html#precise-lifetime-semantics
+ __attribute__((objc_precise_lifetime)) R (^scoped_block)(Args...) = block;
+ return scoped_block(std::forward<RunArgs>(args)...);
+ }
+};
+
+#else // HAS_FEATURE(objc_arc)
+
+template <typename R, typename... Args>
+struct FunctorTraits<base::mac::ScopedBlock<R (^)(Args...)>> {
+ using RunType = R(Args...);
+ static constexpr bool is_method = false;
+ static constexpr bool is_nullable = true;
+ static constexpr bool is_callback = false;
+
+ template <typename BlockType, typename... RunArgs>
+ static R Invoke(BlockType&& block, RunArgs&&... args) {
+ // Copy the block to ensure that the Objective-C block is not deallocated
+ // until it has finished executing even if the Callback<> is destroyed
+ // during the block execution.
+ base::mac::ScopedBlock<R (^)(Args...)> scoped_block(block);
+ return scoped_block.get()(std::forward<RunArgs>(args)...);
+ }
+};
+
+#endif // HAS_FEATURE(objc_arc)
+#endif // defined(OS_APPLE)
+
+// For methods.
+template <typename R, typename Receiver, typename... Args>
+struct FunctorTraits<R (Receiver::*)(Args...)> {
+ using RunType = R(Receiver*, Args...);
+ static constexpr bool is_method = true;
+ static constexpr bool is_nullable = true;
+ static constexpr bool is_callback = false;
+
+ template <typename Method, typename ReceiverPtr, typename... RunArgs>
+ static R Invoke(Method method,
+ ReceiverPtr&& receiver_ptr,
+ RunArgs&&... args) {
+ return ((*receiver_ptr).*method)(std::forward<RunArgs>(args)...);
+ }
+};
+
+// For const methods.
+template <typename R, typename Receiver, typename... Args>
+struct FunctorTraits<R (Receiver::*)(Args...) const> {
+ using RunType = R(const Receiver*, Args...);
+ static constexpr bool is_method = true;
+ static constexpr bool is_nullable = true;
+ static constexpr bool is_callback = false;
+
+ template <typename Method, typename ReceiverPtr, typename... RunArgs>
+ static R Invoke(Method method,
+ ReceiverPtr&& receiver_ptr,
+ RunArgs&&... args) {
+ return ((*receiver_ptr).*method)(std::forward<RunArgs>(args)...);
+ }
+};
+
+#if defined(OS_WIN) && !defined(ARCH_CPU_64_BITS)
+
+// For __stdcall methods.
+template <typename R, typename Receiver, typename... Args>
+struct FunctorTraits<R (__stdcall Receiver::*)(Args...)> {
+ using RunType = R(Receiver*, Args...);
+ static constexpr bool is_method = true;
+ static constexpr bool is_nullable = true;
+ static constexpr bool is_callback = false;
+
+ template <typename Method, typename ReceiverPtr, typename... RunArgs>
+ static R Invoke(Method method,
+ ReceiverPtr&& receiver_ptr,
+ RunArgs&&... args) {
+ return ((*receiver_ptr).*method)(std::forward<RunArgs>(args)...);
+ }
+};
+
+// For __stdcall const methods.
+template <typename R, typename Receiver, typename... Args>
+struct FunctorTraits<R (__stdcall Receiver::*)(Args...) const> {
+ using RunType = R(const Receiver*, Args...);
+ static constexpr bool is_method = true;
+ static constexpr bool is_nullable = true;
+ static constexpr bool is_callback = false;
+
+ template <typename Method, typename ReceiverPtr, typename... RunArgs>
+ static R Invoke(Method method,
+ ReceiverPtr&& receiver_ptr,
+ RunArgs&&... args) {
+ return ((*receiver_ptr).*method)(std::forward<RunArgs>(args)...);
+ }
+};
+
+#endif // defined(OS_WIN) && !defined(ARCH_CPU_64_BITS)
+
+#ifdef __cpp_noexcept_function_type
+// noexcept makes a distinct function type in C++17.
+// I.e. `void(*)()` and `void(*)() noexcept` are same in pre-C++17, and
+// different in C++17.
+template <typename R, typename... Args>
+struct FunctorTraits<R (*)(Args...) noexcept> : FunctorTraits<R (*)(Args...)> {
+};
+
+template <typename R, typename Receiver, typename... Args>
+struct FunctorTraits<R (Receiver::*)(Args...) noexcept>
+ : FunctorTraits<R (Receiver::*)(Args...)> {};
+
+template <typename R, typename Receiver, typename... Args>
+struct FunctorTraits<R (Receiver::*)(Args...) const noexcept>
+ : FunctorTraits<R (Receiver::*)(Args...) const> {};
+#endif
+
+// For IgnoreResults.
+template <typename T>
+struct FunctorTraits<IgnoreResultHelper<T>> : FunctorTraits<T> {
+ using RunType =
+ typename ForceVoidReturn<typename FunctorTraits<T>::RunType>::RunType;
+
+ template <typename IgnoreResultType, typename... RunArgs>
+ static void Invoke(IgnoreResultType&& ignore_result_helper,
+ RunArgs&&... args) {
+ FunctorTraits<T>::Invoke(
+ std::forward<IgnoreResultType>(ignore_result_helper).functor_,
+ std::forward<RunArgs>(args)...);
+ }
+};
+
+// For OnceCallbacks.
+template <typename R, typename... Args>
+struct FunctorTraits<OnceCallback<R(Args...)>> {
+ using RunType = R(Args...);
+ static constexpr bool is_method = false;
+ static constexpr bool is_nullable = true;
+ static constexpr bool is_callback = true;
+
+ template <typename CallbackType, typename... RunArgs>
+ static R Invoke(CallbackType&& callback, RunArgs&&... args) {
+ DCHECK(!callback.is_null());
+ return std::forward<CallbackType>(callback).Run(
+ std::forward<RunArgs>(args)...);
+ }
+};
+
+// For RepeatingCallbacks.
+template <typename R, typename... Args>
+struct FunctorTraits<RepeatingCallback<R(Args...)>> {
+ using RunType = R(Args...);
+ static constexpr bool is_method = false;
+ static constexpr bool is_nullable = true;
+ static constexpr bool is_callback = true;
+
+ template <typename CallbackType, typename... RunArgs>
+ static R Invoke(CallbackType&& callback, RunArgs&&... args) {
+ DCHECK(!callback.is_null());
+ return std::forward<CallbackType>(callback).Run(
+ std::forward<RunArgs>(args)...);
+ }
+};
+
+template <typename Functor>
+using MakeFunctorTraits = FunctorTraits<std::decay_t<Functor>>;
+
+// InvokeHelper<>
+//
+// There are 2 logical InvokeHelper<> specializations: normal, WeakCalls.
+//
+// The normal type just calls the underlying runnable.
+//
+// WeakCalls need special syntax that is applied to the first argument to check
+// if they should no-op themselves.
+template <bool is_weak_call, typename ReturnType>
+struct InvokeHelper;
+
+template <typename ReturnType>
+struct InvokeHelper<false, ReturnType> {
+ template <typename Functor, typename... RunArgs>
+ static inline ReturnType MakeItSo(Functor&& functor, RunArgs&&... args) {
+ using Traits = MakeFunctorTraits<Functor>;
+ return Traits::Invoke(std::forward<Functor>(functor),
+ std::forward<RunArgs>(args)...);
+ }
+};
+
+template <typename ReturnType>
+struct InvokeHelper<true, ReturnType> {
+ // WeakCalls are only supported for functions with a void return type.
+ // Otherwise, the function result would be undefined if the WeakPtr<>
+ // is invalidated.
+ static_assert(std::is_void<ReturnType>::value,
+ "weak_ptrs can only bind to methods without return values");
+
+ template <typename Functor, typename BoundWeakPtr, typename... RunArgs>
+ static inline void MakeItSo(Functor&& functor,
+ BoundWeakPtr&& weak_ptr,
+ RunArgs&&... args) {
+ if (!weak_ptr) {
+ return;
+ }
+ using Traits = MakeFunctorTraits<Functor>;
+ Traits::Invoke(std::forward<Functor>(functor),
+ std::forward<BoundWeakPtr>(weak_ptr),
+ std::forward<RunArgs>(args)...);
+ }
+};
+
+// Invoker<>
+//
+// See description at the top of the file.
+template <typename StorageType, typename UnboundRunType>
+struct Invoker;
+
+template <typename StorageType, typename R, typename... UnboundArgs>
+struct Invoker<StorageType, R(UnboundArgs...)> {
+ static R RunOnce(BindStateBase* base,
+ PassingType<UnboundArgs>... unbound_args) {
+ // Local references to make debugger stepping easier. If in a debugger,
+ // you really want to warp ahead and step through the
+ // InvokeHelper<>::MakeItSo() call below.
+ StorageType* storage = static_cast<StorageType*>(base);
+ static constexpr size_t num_bound_args =
+ std::tuple_size<decltype(storage->bound_args_)>::value;
+ return RunImpl(std::move(storage->functor_),
+ std::move(storage->bound_args_),
+ std::make_index_sequence<num_bound_args>(),
+ std::forward<UnboundArgs>(unbound_args)...);
+ }
+
+ static R Run(BindStateBase* base, PassingType<UnboundArgs>... unbound_args) {
+ // Local references to make debugger stepping easier. If in a debugger,
+ // you really want to warp ahead and step through the
+ // InvokeHelper<>::MakeItSo() call below.
+ const StorageType* storage = static_cast<StorageType*>(base);
+ static constexpr size_t num_bound_args =
+ std::tuple_size<decltype(storage->bound_args_)>::value;
+ return RunImpl(storage->functor_, storage->bound_args_,
+ std::make_index_sequence<num_bound_args>(),
+ std::forward<UnboundArgs>(unbound_args)...);
+ }
+
+ private:
+ template <typename Functor, typename BoundArgsTuple, size_t... indices>
+ static inline R RunImpl(Functor&& functor,
+ BoundArgsTuple&& bound,
+ std::index_sequence<indices...>,
+ UnboundArgs&&... unbound_args) {
+ static constexpr bool is_method = MakeFunctorTraits<Functor>::is_method;
+
+ using DecayedArgsTuple = std::decay_t<BoundArgsTuple>;
+ static constexpr bool is_weak_call =
+ IsWeakMethod<is_method,
+ std::tuple_element_t<indices, DecayedArgsTuple>...>();
+
+ return InvokeHelper<is_weak_call, R>::MakeItSo(
+ std::forward<Functor>(functor),
+ Unwrap(std::get<indices>(std::forward<BoundArgsTuple>(bound)))...,
+ std::forward<UnboundArgs>(unbound_args)...);
+ }
+};
+
+// Extracts necessary type info from Functor and BoundArgs.
+// Used to implement MakeUnboundRunType, BindOnce and BindRepeating.
+template <typename Functor, typename... BoundArgs>
+struct BindTypeHelper {
+ static constexpr size_t num_bounds = sizeof...(BoundArgs);
+ using FunctorTraits = MakeFunctorTraits<Functor>;
+
+ // Example:
+ // When Functor is `double (Foo::*)(int, const std::string&)`, and BoundArgs
+ // is a template pack of `Foo*` and `int16_t`:
+ // - RunType is `double(Foo*, int, const std::string&)`,
+ // - ReturnType is `double`,
+ // - RunParamsList is `TypeList<Foo*, int, const std::string&>`,
+ // - BoundParamsList is `TypeList<Foo*, int>`,
+ // - UnboundParamsList is `TypeList<const std::string&>`,
+ // - BoundArgsList is `TypeList<Foo*, int16_t>`,
+ // - UnboundRunType is `double(const std::string&)`.
+ using RunType = typename FunctorTraits::RunType;
+ using ReturnType = ExtractReturnType<RunType>;
+
+ using RunParamsList = ExtractArgs<RunType>;
+ using BoundParamsList = TakeTypeListItem<num_bounds, RunParamsList>;
+ using UnboundParamsList = DropTypeListItem<num_bounds, RunParamsList>;
+
+ using BoundArgsList = TypeList<BoundArgs...>;
+
+ using UnboundRunType = MakeFunctionType<ReturnType, UnboundParamsList>;
+};
+
+template <typename Functor>
+std::enable_if_t<FunctorTraits<Functor>::is_nullable, bool> IsNull(
+ const Functor& functor) {
+ return !functor;
+}
+
+template <typename Functor>
+std::enable_if_t<!FunctorTraits<Functor>::is_nullable, bool> IsNull(
+ const Functor&) {
+ return false;
+}
+
+// Used by QueryCancellationTraits below.
+template <typename Functor, typename BoundArgsTuple, size_t... indices>
+bool QueryCancellationTraitsImpl(BindStateBase::CancellationQueryMode mode,
+ const Functor& functor,
+ const BoundArgsTuple& bound_args,
+ std::index_sequence<indices...>) {
+ switch (mode) {
+ case BindStateBase::IS_CANCELLED:
+ return CallbackCancellationTraits<Functor, BoundArgsTuple>::IsCancelled(
+ functor, std::get<indices>(bound_args)...);
+ case BindStateBase::MAYBE_VALID:
+ return CallbackCancellationTraits<Functor, BoundArgsTuple>::MaybeValid(
+ functor, std::get<indices>(bound_args)...);
+ }
+ NOTREACHED();
+ return false;
+}
+
+// Relays |base| to corresponding CallbackCancellationTraits<>::Run(). Returns
+// true if the callback |base| represents is canceled.
+template <typename BindStateType>
+bool QueryCancellationTraits(const BindStateBase* base,
+ BindStateBase::CancellationQueryMode mode) {
+ const BindStateType* storage = static_cast<const BindStateType*>(base);
+ static constexpr size_t num_bound_args =
+ std::tuple_size<decltype(storage->bound_args_)>::value;
+ return QueryCancellationTraitsImpl(
+ mode, storage->functor_, storage->bound_args_,
+ std::make_index_sequence<num_bound_args>());
+}
+
+// The base case of BanUnconstructedRefCountedReceiver that checks nothing.
+template <typename Functor, typename Receiver, typename... Unused>
+std::enable_if_t<
+ !(MakeFunctorTraits<Functor>::is_method &&
+ std::is_pointer<std::decay_t<Receiver>>::value &&
+ IsRefCountedType<std::remove_pointer_t<std::decay_t<Receiver>>>::value)>
+BanUnconstructedRefCountedReceiver(const Receiver& receiver, Unused&&...) {}
+
+template <typename Functor>
+void BanUnconstructedRefCountedReceiver() {}
+
+// Asserts that Callback is not the first owner of a ref-counted receiver.
+template <typename Functor, typename Receiver, typename... Unused>
+std::enable_if_t<
+ MakeFunctorTraits<Functor>::is_method &&
+ std::is_pointer<std::decay_t<Receiver>>::value &&
+ IsRefCountedType<std::remove_pointer_t<std::decay_t<Receiver>>>::value>
+BanUnconstructedRefCountedReceiver(const Receiver& receiver, Unused&&...) {
+ DCHECK(receiver);
+
+ // It's error prone to make the implicit first reference to ref-counted types.
+ // In the example below, base::BindOnce() makes the implicit first reference
+ // to the ref-counted Foo. If PostTask() failed or the posted task ran fast
+ // enough, the newly created instance can be destroyed before |oo| makes
+ // another reference.
+ // Foo::Foo() {
+ // base::PostTask(FROM_HERE, base::BindOnce(&Foo::Bar, this));
+ // }
+ //
+ // scoped_refptr<Foo> oo = new Foo();
+ //
+ // Instead of doing like above, please consider adding a static constructor,
+ // and keep the first reference alive explicitly.
+ // // static
+ // scoped_refptr<Foo> Foo::Create() {
+ // auto foo = base::WrapRefCounted(new Foo());
+ // base::PostTask(FROM_HERE, base::BindOnce(&Foo::Bar, foo));
+ // return foo;
+ // }
+ //
+ // Foo::Foo() {}
+ //
+ // scoped_refptr<Foo> oo = Foo::Create();
+ DCHECK(receiver->HasAtLeastOneRef())
+ << "base::Bind{Once,Repeating}() refuses to create the first reference "
+ "to ref-counted objects. That typically happens around PostTask() in "
+ "their constructor, and such objects can be destroyed before `new` "
+ "returns if the task resolves fast enough.";
+}
+
+// BindState<>
+//
+// This stores all the state passed into Bind().
+template <typename Functor, typename... BoundArgs>
+struct BindState final : BindStateBase {
+ using IsCancellable = bool_constant<
+ CallbackCancellationTraits<Functor,
+ std::tuple<BoundArgs...>>::is_cancellable>;
+ template <typename ForwardFunctor, typename... ForwardBoundArgs>
+ static BindState* Create(BindStateBase::InvokeFuncStorage invoke_func,
+ ForwardFunctor&& functor,
+ ForwardBoundArgs&&... bound_args) {
+ // Ban ref counted receivers that were not yet fully constructed to avoid
+ // a common pattern of racy situation.
+ BanUnconstructedRefCountedReceiver<ForwardFunctor>(bound_args...);
+
+ // IsCancellable is std::false_type if
+ // CallbackCancellationTraits<>::IsCancelled returns always false.
+ // Otherwise, it's std::true_type.
+ return new BindState(IsCancellable{}, invoke_func,
+ std::forward<ForwardFunctor>(functor),
+ std::forward<ForwardBoundArgs>(bound_args)...);
+ }
+
+ Functor functor_;
+ std::tuple<BoundArgs...> bound_args_;
+
+ private:
+ static constexpr bool is_nested_callback =
+ MakeFunctorTraits<Functor>::is_callback;
+
+ template <typename ForwardFunctor, typename... ForwardBoundArgs>
+ explicit BindState(std::true_type,
+ BindStateBase::InvokeFuncStorage invoke_func,
+ ForwardFunctor&& functor,
+ ForwardBoundArgs&&... bound_args)
+ : BindStateBase(invoke_func,
+ &Destroy,
+ &QueryCancellationTraits<BindState>),
+ functor_(std::forward<ForwardFunctor>(functor)),
+ bound_args_(std::forward<ForwardBoundArgs>(bound_args)...) {
+ // We check the validity of nested callbacks (e.g., Bind(callback, ...)) in
+ // release builds to avoid null pointers from ending up in posted tasks,
+ // causing hard-to-diagnose crashes. Ideally we'd do this for all functors
+ // here, but that would have a large binary size impact.
+ if (is_nested_callback) {
+ CHECK(!IsNull(functor_));
+ } else {
+ DCHECK(!IsNull(functor_));
+ }
+ }
+
+ template <typename ForwardFunctor, typename... ForwardBoundArgs>
+ explicit BindState(std::false_type,
+ BindStateBase::InvokeFuncStorage invoke_func,
+ ForwardFunctor&& functor,
+ ForwardBoundArgs&&... bound_args)
+ : BindStateBase(invoke_func, &Destroy),
+ functor_(std::forward<ForwardFunctor>(functor)),
+ bound_args_(std::forward<ForwardBoundArgs>(bound_args)...) {
+ // See above for CHECK/DCHECK rationale.
+ if (is_nested_callback) {
+ CHECK(!IsNull(functor_));
+ } else {
+ DCHECK(!IsNull(functor_));
+ }
+ }
+
+ ~BindState() = default;
+
+ static void Destroy(const BindStateBase* self) {
+ delete static_cast<const BindState*>(self);
+ }
+};
+
+// Used to implement MakeBindStateType.
+template <bool is_method, typename Functor, typename... BoundArgs>
+struct MakeBindStateTypeImpl;
+
+template <typename Functor, typename... BoundArgs>
+struct MakeBindStateTypeImpl<false, Functor, BoundArgs...> {
+ static_assert(!HasRefCountedTypeAsRawPtr<std::decay_t<BoundArgs>...>::value,
+ "A parameter is a refcounted type and needs scoped_refptr.");
+ using Type = BindState<std::decay_t<Functor>, std::decay_t<BoundArgs>...>;
+};
+
+template <typename Functor>
+struct MakeBindStateTypeImpl<true, Functor> {
+ using Type = BindState<std::decay_t<Functor>>;
+};
+
+template <typename Functor, typename Receiver, typename... BoundArgs>
+struct MakeBindStateTypeImpl<true, Functor, Receiver, BoundArgs...> {
+ private:
+ using DecayedReceiver = std::decay_t<Receiver>;
+
+ static_assert(!std::is_array<std::remove_reference_t<Receiver>>::value,
+ "First bound argument to a method cannot be an array.");
+ static_assert(
+ !std::is_pointer<DecayedReceiver>::value ||
+ IsRefCountedType<std::remove_pointer_t<DecayedReceiver>>::value,
+ "Receivers may not be raw pointers. If using a raw pointer here is safe"
+ " and has no lifetime concerns, use base::Unretained() and document why"
+ " it's safe.");
+ static_assert(!HasRefCountedTypeAsRawPtr<std::decay_t<BoundArgs>...>::value,
+ "A parameter is a refcounted type and needs scoped_refptr.");
+
+ public:
+ using Type = BindState<
+ std::decay_t<Functor>,
+ std::conditional_t<std::is_pointer<DecayedReceiver>::value,
+ scoped_refptr<std::remove_pointer_t<DecayedReceiver>>,
+ DecayedReceiver>,
+ std::decay_t<BoundArgs>...>;
+};
+
+template <typename Functor, typename... BoundArgs>
+using MakeBindStateType =
+ typename MakeBindStateTypeImpl<MakeFunctorTraits<Functor>::is_method,
+ Functor,
+ BoundArgs...>::Type;
+
+// Returns a RunType of bound functor.
+// E.g. MakeUnboundRunType<R(A, B, C), A, B> is evaluated to R(C).
+template <typename Functor, typename... BoundArgs>
+using MakeUnboundRunType =
+ typename BindTypeHelper<Functor, BoundArgs...>::UnboundRunType;
+
+// The implementation of TransformToUnwrappedType below.
+template <bool is_once, typename T>
+struct TransformToUnwrappedTypeImpl;
+
+template <typename T>
+struct TransformToUnwrappedTypeImpl<true, T> {
+ using StoredType = std::decay_t<T>;
+ using ForwardType = StoredType&&;
+ using Unwrapped = decltype(Unwrap(std::declval<ForwardType>()));
+};
+
+template <typename T>
+struct TransformToUnwrappedTypeImpl<false, T> {
+ using StoredType = std::decay_t<T>;
+ using ForwardType = const StoredType&;
+ using Unwrapped = decltype(Unwrap(std::declval<ForwardType>()));
+};
+
+// Transform |T| into `Unwrapped` type, which is passed to the target function.
+// Example:
+// In is_once == true case,
+// `int&&` -> `int&&`,
+// `const int&` -> `int&&`,
+// `OwnedWrapper<int>&` -> `int*&&`.
+// In is_once == false case,
+// `int&&` -> `const int&`,
+// `const int&` -> `const int&`,
+// `OwnedWrapper<int>&` -> `int* const &`.
+template <bool is_once, typename T>
+using TransformToUnwrappedType =
+ typename TransformToUnwrappedTypeImpl<is_once, T>::Unwrapped;
+
+// Transforms |Args| into `Unwrapped` types, and packs them into a TypeList.
+// If |is_method| is true, tries to dereference the first argument to support
+// smart pointers.
+template <bool is_once, bool is_method, typename... Args>
+struct MakeUnwrappedTypeListImpl {
+ using Type = TypeList<TransformToUnwrappedType<is_once, Args>...>;
+};
+
+// Performs special handling for this pointers.
+// Example:
+// int* -> int*,
+// std::unique_ptr<int> -> int*.
+template <bool is_once, typename Receiver, typename... Args>
+struct MakeUnwrappedTypeListImpl<is_once, true, Receiver, Args...> {
+ using UnwrappedReceiver = TransformToUnwrappedType<is_once, Receiver>;
+ using Type = TypeList<decltype(&*std::declval<UnwrappedReceiver>()),
+ TransformToUnwrappedType<is_once, Args>...>;
+};
+
+template <bool is_once, bool is_method, typename... Args>
+using MakeUnwrappedTypeList =
+ typename MakeUnwrappedTypeListImpl<is_once, is_method, Args...>::Type;
+
+// IsOnceCallback<T> is a std::true_type if |T| is a OnceCallback.
+template <typename T>
+struct IsOnceCallback : std::false_type {};
+
+template <typename Signature>
+struct IsOnceCallback<OnceCallback<Signature>> : std::true_type {};
+
+// Helpers to make error messages slightly more readable.
+template <int i>
+struct BindArgument {
+ template <typename ForwardingType>
+ struct ForwardedAs {
+ template <typename FunctorParamType>
+ struct ToParamWithType {
+ static constexpr bool kCanBeForwardedToBoundFunctor =
+ std::is_constructible<FunctorParamType, ForwardingType>::value;
+
+ // If the bound type can't be forwarded then test if `FunctorParamType` is
+ // a non-const lvalue reference and a reference to the unwrapped type
+ // *could* have been successfully forwarded.
+ static constexpr bool kNonConstRefParamMustBeWrapped =
+ kCanBeForwardedToBoundFunctor ||
+ !(std::is_lvalue_reference<FunctorParamType>::value &&
+ !std::is_const<std::remove_reference_t<FunctorParamType>>::value &&
+ std::is_convertible<std::decay_t<ForwardingType>&,
+ FunctorParamType>::value);
+
+ // Note that this intentionally drops the const qualifier from
+ // `ForwardingType`, to test if it *could* have been successfully
+ // forwarded if `Passed()` had been used.
+ static constexpr bool kMoveOnlyTypeMustUseBasePassed =
+ kCanBeForwardedToBoundFunctor ||
+ !std::is_constructible<FunctorParamType,
+ std::decay_t<ForwardingType>&&>::value;
+ };
+ };
+
+ template <typename BoundAsType>
+ struct BoundAs {
+ template <typename StorageType>
+ struct StoredAs {
+ static constexpr bool kBindArgumentCanBeCaptured =
+ std::is_constructible<StorageType, BoundAsType>::value;
+ // Note that this intentionally drops the const qualifier from
+ // `BoundAsType`, to test if it *could* have been successfully bound if
+ // `std::move()` had been used.
+ static constexpr bool kMoveOnlyTypeMustUseStdMove =
+ kBindArgumentCanBeCaptured ||
+ !std::is_constructible<StorageType,
+ std::decay_t<BoundAsType>&&>::value;
+ };
+ };
+};
+
+// Helper to assert that parameter |i| of type |Arg| can be bound, which means:
+// - |Arg| can be retained internally as |Storage|.
+// - |Arg| can be forwarded as |Unwrapped| to |Param|.
+template <int i,
+ typename Arg,
+ typename Storage,
+ typename Unwrapped,
+ typename Param>
+struct AssertConstructible {
+ private:
+ // With `BindRepeating`, there are two decision points for how to handle a
+ // move-only type:
+ //
+ // 1. Whether the move-only argument should be moved into the internal
+ // `BindState`. Either `std::move()` or `Passed` is sufficient to trigger
+ // move-only semantics.
+ // 2. Whether or not the bound, move-only argument should be moved to the
+ // bound functor when invoked. When the argument is bound with `Passed`,
+ // invoking the callback will destructively move the bound, move-only
+ // argument to the bound functor. In contrast, if the argument is bound
+ // with `std::move()`, `RepeatingCallback` will attempt to call the bound
+ // functor with a constant reference to the bound, move-only argument. This
+ // will fail if the bound functor accepts that argument by value, since the
+ // argument cannot be copied. It is this latter case that this
+ // static_assert aims to catch.
+ //
+ // In contrast, `BindOnce()` only has one decision point. Once a move-only
+ // type is captured by value into the internal `BindState`, the bound,
+ // move-only argument will always be moved to the functor when invoked.
+ // Failure to use std::move will simply fail the `kMoveOnlyTypeMustUseStdMove`
+ // assert below instead.
+ //
+ // Note: `Passed()` is a legacy of supporting move-only types when repeating
+ // callbacks were the only callback type. A `RepeatingCallback` with a
+ // `Passed()` argument is really a `OnceCallback` and should eventually be
+ // migrated.
+ static_assert(
+ BindArgument<i>::template ForwardedAs<Unwrapped>::
+ template ToParamWithType<Param>::kMoveOnlyTypeMustUseBasePassed,
+ "base::BindRepeating() argument is a move-only type. Use base::Passed() "
+ "instead of std::move() to transfer ownership from the callback to the "
+ "bound functor.");
+ static_assert(
+ BindArgument<i>::template ForwardedAs<Unwrapped>::
+ template ToParamWithType<Param>::kNonConstRefParamMustBeWrapped,
+ "Bound argument for non-const reference parameter must be wrapped in "
+ "std::ref() or base::OwnedRef().");
+ static_assert(
+ BindArgument<i>::template ForwardedAs<Unwrapped>::
+ template ToParamWithType<Param>::kCanBeForwardedToBoundFunctor,
+ "Type mismatch between bound argument and bound functor's parameter.");
+
+ static_assert(BindArgument<i>::template BoundAs<Arg>::template StoredAs<
+ Storage>::kMoveOnlyTypeMustUseStdMove,
+ "Attempting to bind a move-only type. Use std::move() to "
+ "transfer ownership to the created callback.");
+ // In practice, this static_assert should be quite rare as the storage type
+ // is deduced from the arguments passed to `BindOnce()`/`BindRepeating()`.
+ static_assert(
+ BindArgument<i>::template BoundAs<Arg>::template StoredAs<
+ Storage>::kBindArgumentCanBeCaptured,
+ "Cannot capture argument: is the argument copyable or movable?");
+};
+
+// Takes three same-length TypeLists, and applies AssertConstructible for each
+// triples.
+template <typename Index,
+ typename Args,
+ typename UnwrappedTypeList,
+ typename ParamsList>
+struct AssertBindArgsValidity;
+
+template <size_t... Ns,
+ typename... Args,
+ typename... Unwrapped,
+ typename... Params>
+struct AssertBindArgsValidity<std::index_sequence<Ns...>,
+ TypeList<Args...>,
+ TypeList<Unwrapped...>,
+ TypeList<Params...>>
+ : AssertConstructible<static_cast<int>(Ns),
+ Args,
+ std::decay_t<Args>,
+ Unwrapped,
+ Params>... {
+ static constexpr bool ok = true;
+};
+
+template <typename T>
+struct AssertBindArgIsNotBasePassed : public std::true_type {};
+
+template <typename T>
+struct AssertBindArgIsNotBasePassed<PassedWrapper<T>> : public std::false_type {
+};
+
+// Used below in BindImpl to determine whether to use Invoker::Run or
+// Invoker::RunOnce.
+// Note: Simply using `kIsOnce ? &Invoker::RunOnce : &Invoker::Run` does not
+// work, since the compiler needs to check whether both expressions are
+// well-formed. Using `Invoker::Run` with a OnceCallback triggers a
+// static_assert, which is why the ternary expression does not compile.
+// TODO(crbug.com/752720): Remove this indirection once we have `if constexpr`.
+template <typename Invoker>
+constexpr auto GetInvokeFunc(std::true_type) {
+ return Invoker::RunOnce;
+}
+
+template <typename Invoker>
+constexpr auto GetInvokeFunc(std::false_type) {
+ return Invoker::Run;
+}
+
+template <template <typename> class CallbackT,
+ typename Functor,
+ typename... Args>
+decltype(auto) BindImpl(Functor&& functor, Args&&... args) {
+ // This block checks if each |args| matches to the corresponding params of the
+ // target function. This check does not affect the behavior of Bind, but its
+ // error message should be more readable.
+ static constexpr bool kIsOnce = IsOnceCallback<CallbackT<void()>>::value;
+ using Helper = BindTypeHelper<Functor, Args...>;
+ using FunctorTraits = typename Helper::FunctorTraits;
+ using BoundArgsList = typename Helper::BoundArgsList;
+ using UnwrappedArgsList =
+ MakeUnwrappedTypeList<kIsOnce, FunctorTraits::is_method, Args&&...>;
+ using BoundParamsList = typename Helper::BoundParamsList;
+ static_assert(
+ AssertBindArgsValidity<std::make_index_sequence<Helper::num_bounds>,
+ BoundArgsList, UnwrappedArgsList,
+ BoundParamsList>::ok,
+ "The bound args need to be convertible to the target params.");
+
+ using BindState = MakeBindStateType<Functor, Args...>;
+ using UnboundRunType = MakeUnboundRunType<Functor, Args...>;
+ using Invoker = Invoker<BindState, UnboundRunType>;
+ using CallbackType = CallbackT<UnboundRunType>;
+
+ // Store the invoke func into PolymorphicInvoke before casting it to
+ // InvokeFuncStorage, so that we can ensure its type matches to
+ // PolymorphicInvoke, to which CallbackType will cast back.
+ using PolymorphicInvoke = typename CallbackType::PolymorphicInvoke;
+ PolymorphicInvoke invoke_func =
+ GetInvokeFunc<Invoker>(bool_constant<kIsOnce>());
+
+ using InvokeFuncStorage = BindStateBase::InvokeFuncStorage;
+ return CallbackType(BindState::Create(
+ reinterpret_cast<InvokeFuncStorage>(invoke_func),
+ std::forward<Functor>(functor), std::forward<Args>(args)...));
+}
+
+} // namespace cef_internal
+
+// An injection point to control |this| pointer behavior on a method invocation.
+// If IsWeakReceiver<> is true_type for |T| and |T| is used for a receiver of a
+// method, base::Bind cancels the method invocation if the receiver is tested as
+// false.
+// E.g. Foo::bar() is not called:
+// struct Foo : base::SupportsWeakPtr<Foo> {
+// void bar() {}
+// };
+//
+// WeakPtr<Foo> oo = nullptr;
+// base::BindOnce(&Foo::bar, oo).Run();
+template <typename T>
+struct IsWeakReceiver : std::false_type {};
+
+template <typename T>
+struct IsWeakReceiver<std::reference_wrapper<T>> : IsWeakReceiver<T> {};
+
+template <typename T>
+struct IsWeakReceiver<WeakPtr<T>> : std::true_type {};
+
+// An injection point to control how objects are checked for maybe validity,
+// which is an optimistic thread-safe check for full validity.
+template <typename>
+struct MaybeValidTraits {
+ template <typename T>
+ static bool MaybeValid(const T& o) {
+ return o.MaybeValid();
+ }
+};
+
+// An injection point to control how bound objects passed to the target
+// function. BindUnwrapTraits<>::Unwrap() is called for each bound objects right
+// before the target function is invoked.
+template <typename>
+struct BindUnwrapTraits {
+ template <typename T>
+ static T&& Unwrap(T&& o) {
+ return std::forward<T>(o);
+ }
+};
+
+template <typename T>
+struct BindUnwrapTraits<cef_internal::UnretainedWrapper<T>> {
+ static T* Unwrap(const cef_internal::UnretainedWrapper<T>& o) {
+ return o.get();
+ }
+};
+
+template <typename T>
+struct BindUnwrapTraits<cef_internal::RetainedRefWrapper<T>> {
+ static T* Unwrap(const cef_internal::RetainedRefWrapper<T>& o) {
+ return o.get();
+ }
+};
+
+template <typename T, typename Deleter>
+struct BindUnwrapTraits<cef_internal::OwnedWrapper<T, Deleter>> {
+ static T* Unwrap(const cef_internal::OwnedWrapper<T, Deleter>& o) {
+ return o.get();
+ }
+};
+
+template <typename T>
+struct BindUnwrapTraits<cef_internal::OwnedRefWrapper<T>> {
+ static T& Unwrap(const cef_internal::OwnedRefWrapper<T>& o) {
+ return o.get();
+ }
+};
+
+template <typename T>
+struct BindUnwrapTraits<cef_internal::PassedWrapper<T>> {
+ static T Unwrap(const cef_internal::PassedWrapper<T>& o) { return o.Take(); }
+};
+
+#if defined(OS_WIN)
+template <typename T>
+struct BindUnwrapTraits<Microsoft::WRL::ComPtr<T>> {
+ static T* Unwrap(const Microsoft::WRL::ComPtr<T>& ptr) { return ptr.Get(); }
+};
+#endif
+
+// CallbackCancellationTraits allows customization of Callback's cancellation
+// semantics. By default, callbacks are not cancellable. A specialization should
+// set is_cancellable = true and implement an IsCancelled() that returns if the
+// callback should be cancelled.
+template <typename Functor, typename BoundArgsTuple, typename SFINAE>
+struct CallbackCancellationTraits {
+ static constexpr bool is_cancellable = false;
+};
+
+// Specialization for method bound to weak pointer receiver.
+template <typename Functor, typename... BoundArgs>
+struct CallbackCancellationTraits<
+ Functor,
+ std::tuple<BoundArgs...>,
+ std::enable_if_t<cef_internal::IsWeakMethod<
+ cef_internal::FunctorTraits<Functor>::is_method,
+ BoundArgs...>::value>> {
+ static constexpr bool is_cancellable = true;
+
+ template <typename Receiver, typename... Args>
+ static bool IsCancelled(const Functor&,
+ const Receiver& receiver,
+ const Args&...) {
+ return !receiver;
+ }
+
+ template <typename Receiver, typename... Args>
+ static bool MaybeValid(const Functor&,
+ const Receiver& receiver,
+ const Args&...) {
+ return MaybeValidTraits<Receiver>::MaybeValid(receiver);
+ }
+};
+
+// Specialization for a nested bind.
+template <typename Signature, typename... BoundArgs>
+struct CallbackCancellationTraits<OnceCallback<Signature>,
+ std::tuple<BoundArgs...>> {
+ static constexpr bool is_cancellable = true;
+
+ template <typename Functor>
+ static bool IsCancelled(const Functor& functor, const BoundArgs&...) {
+ return functor.IsCancelled();
+ }
+
+ template <typename Functor>
+ static bool MaybeValid(const Functor& functor, const BoundArgs&...) {
+ return MaybeValidTraits<Functor>::MaybeValid(functor);
+ }
+};
+
+template <typename Signature, typename... BoundArgs>
+struct CallbackCancellationTraits<RepeatingCallback<Signature>,
+ std::tuple<BoundArgs...>> {
+ static constexpr bool is_cancellable = true;
+
+ template <typename Functor>
+ static bool IsCancelled(const Functor& functor, const BoundArgs&...) {
+ return functor.IsCancelled();
+ }
+
+ template <typename Functor>
+ static bool MaybeValid(const Functor& functor, const BoundArgs&...) {
+ return MaybeValidTraits<Functor>::MaybeValid(functor);
+ }
+};
+
+} // namespace base
+
+#endif // CEF_INCLUDE_BASE_INTERNAL_CEF_BIND_INTERNAL_H_
diff --git a/include/base/internal/cef_callback_internal.h b/include/base/internal/cef_callback_internal.h
new file mode 100644
index 00000000..f3435e9f
--- /dev/null
+++ b/include/base/internal/cef_callback_internal.h
@@ -0,0 +1,275 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Do not include this header file directly. Use base/cef_bind.h or
+// base/cef_callback.h instead.
+
+// This file contains utility functions and classes that help the
+// implementation, and management of the Callback objects.
+
+#ifndef CEF_INCLUDE_BASE_INTERNAL_CEF_CALLBACK_INTERNAL_H_
+#define CEF_INCLUDE_BASE_INTERNAL_CEF_CALLBACK_INTERNAL_H_
+
+#include "include/base/cef_callback_forward.h"
+#include "include/base/cef_ref_counted.h"
+
+namespace base {
+
+struct FakeBindState;
+
+namespace cef_internal {
+
+class BindStateBase;
+class FinallyExecutorCommon;
+class ThenAndCatchExecutorCommon;
+
+template <typename ReturnType>
+class PostTaskExecutor;
+
+template <typename Functor, typename... BoundArgs>
+struct BindState;
+
+class CallbackBase;
+class CallbackBaseCopyable;
+
+struct BindStateBaseRefCountTraits {
+ static void Destruct(const BindStateBase*);
+};
+
+template <typename T>
+using PassingType = std::conditional_t<std::is_scalar<T>::value, T, T&&>;
+
+// BindStateBase is used to provide an opaque handle that the Callback
+// class can use to represent a function object with bound arguments. It
+// behaves as an existential type that is used by a corresponding
+// DoInvoke function to perform the function execution. This allows
+// us to shield the Callback class from the types of the bound argument via
+// "type erasure."
+// At the base level, the only task is to add reference counting data. Avoid
+// using or inheriting any virtual functions. Creating a vtable for every
+// BindState template instantiation results in a lot of bloat. Its only task is
+// to call the destructor which can be done with a function pointer.
+class BindStateBase
+ : public RefCountedThreadSafe<BindStateBase, BindStateBaseRefCountTraits> {
+ public:
+ REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE();
+
+ enum CancellationQueryMode {
+ IS_CANCELLED,
+ MAYBE_VALID,
+ };
+
+ using InvokeFuncStorage = void (*)();
+
+ BindStateBase(const BindStateBase&) = delete;
+ BindStateBase& operator=(const BindStateBase&) = delete;
+
+ private:
+ BindStateBase(InvokeFuncStorage polymorphic_invoke,
+ void (*destructor)(const BindStateBase*));
+ BindStateBase(InvokeFuncStorage polymorphic_invoke,
+ void (*destructor)(const BindStateBase*),
+ bool (*query_cancellation_traits)(const BindStateBase*,
+ CancellationQueryMode mode));
+
+ ~BindStateBase() = default;
+
+ friend struct BindStateBaseRefCountTraits;
+ friend class RefCountedThreadSafe<BindStateBase, BindStateBaseRefCountTraits>;
+
+ friend class CallbackBase;
+ friend class CallbackBaseCopyable;
+
+ // Allowlist subclasses that access the destructor of BindStateBase.
+ template <typename Functor, typename... BoundArgs>
+ friend struct BindState;
+ friend struct ::base::FakeBindState;
+
+ bool IsCancelled() const {
+ return query_cancellation_traits_(this, IS_CANCELLED);
+ }
+
+ bool MaybeValid() const {
+ return query_cancellation_traits_(this, MAYBE_VALID);
+ }
+
+ // In C++, it is safe to cast function pointers to function pointers of
+ // another type. It is not okay to use void*. We create a InvokeFuncStorage
+ // that that can store our function pointer, and then cast it back to
+ // the original type on usage.
+ InvokeFuncStorage polymorphic_invoke_;
+
+ // Pointer to a function that will properly destroy |this|.
+ void (*destructor_)(const BindStateBase*);
+ bool (*query_cancellation_traits_)(const BindStateBase*,
+ CancellationQueryMode mode);
+};
+
+// Holds the Callback methods that don't require specialization to reduce
+// template bloat.
+// CallbackBase<MoveOnly> is a direct base class of MoveOnly callbacks, and
+// CallbackBase<Copyable> uses CallbackBase<MoveOnly> for its implementation.
+class CallbackBase {
+ public:
+ inline CallbackBase(CallbackBase&& c) noexcept;
+ CallbackBase& operator=(CallbackBase&& c) noexcept;
+
+ explicit CallbackBase(const CallbackBaseCopyable& c);
+ CallbackBase& operator=(const CallbackBaseCopyable& c);
+
+ explicit CallbackBase(CallbackBaseCopyable&& c) noexcept;
+ CallbackBase& operator=(CallbackBaseCopyable&& c) noexcept;
+
+ // Returns true if Callback is null (doesn't refer to anything).
+ bool is_null() const { return !bind_state_; }
+ explicit operator bool() const { return !is_null(); }
+
+ // Returns true if the callback invocation will be nop due to an cancellation.
+ // It's invalid to call this on uninitialized callback.
+ //
+ // Must be called on the Callback's destination sequence.
+ bool IsCancelled() const;
+
+ // If this returns false, the callback invocation will be a nop due to a
+ // cancellation. This may(!) still return true, even on a cancelled callback.
+ //
+ // This function is thread-safe.
+ bool MaybeValid() const;
+
+ // Returns the Callback into an uninitialized state.
+ void Reset();
+
+ protected:
+ friend class FinallyExecutorCommon;
+ friend class ThenAndCatchExecutorCommon;
+
+ template <typename ReturnType>
+ friend class PostTaskExecutor;
+
+ using InvokeFuncStorage = BindStateBase::InvokeFuncStorage;
+
+ // Returns true if this callback equals |other|. |other| may be null.
+ bool EqualsInternal(const CallbackBase& other) const;
+
+ constexpr inline CallbackBase();
+
+ // Allow initializing of |bind_state_| via the constructor to avoid default
+ // initialization of the scoped_refptr.
+ explicit inline CallbackBase(BindStateBase* bind_state);
+
+ InvokeFuncStorage polymorphic_invoke() const {
+ return bind_state_->polymorphic_invoke_;
+ }
+
+ // Force the destructor to be instantiated inside this translation unit so
+ // that our subclasses will not get inlined versions. Avoids more template
+ // bloat.
+ ~CallbackBase();
+
+ scoped_refptr<BindStateBase> bind_state_;
+};
+
+constexpr CallbackBase::CallbackBase() = default;
+CallbackBase::CallbackBase(CallbackBase&&) noexcept = default;
+CallbackBase::CallbackBase(BindStateBase* bind_state)
+ : bind_state_(AdoptRef(bind_state)) {}
+
+// CallbackBase<Copyable> is a direct base class of Copyable Callbacks.
+class CallbackBaseCopyable : public CallbackBase {
+ public:
+ CallbackBaseCopyable(const CallbackBaseCopyable& c);
+ CallbackBaseCopyable(CallbackBaseCopyable&& c) noexcept = default;
+ CallbackBaseCopyable& operator=(const CallbackBaseCopyable& c);
+ CallbackBaseCopyable& operator=(CallbackBaseCopyable&& c) noexcept;
+
+ protected:
+ constexpr CallbackBaseCopyable() = default;
+ explicit CallbackBaseCopyable(BindStateBase* bind_state)
+ : CallbackBase(bind_state) {}
+ ~CallbackBaseCopyable() = default;
+};
+
+// Helpers for the `Then()` implementation.
+template <typename OriginalCallback, typename ThenCallback>
+struct ThenHelper;
+
+// Specialization when original callback returns `void`.
+template <template <typename> class OriginalCallback,
+ template <typename>
+ class ThenCallback,
+ typename... OriginalArgs,
+ typename ThenR,
+ typename... ThenArgs>
+struct ThenHelper<OriginalCallback<void(OriginalArgs...)>,
+ ThenCallback<ThenR(ThenArgs...)>> {
+ static_assert(sizeof...(ThenArgs) == 0,
+ "|then| callback cannot accept parameters if |this| has a "
+ "void return type.");
+
+ static auto CreateTrampoline() {
+ return [](OriginalCallback<void(OriginalArgs...)> c1,
+ ThenCallback<ThenR(ThenArgs...)> c2, OriginalArgs... c1_args) {
+ std::move(c1).Run(std::forward<OriginalArgs>(c1_args)...);
+ return std::move(c2).Run();
+ };
+ }
+};
+
+// Specialization when original callback returns a non-void type.
+template <template <typename> class OriginalCallback,
+ template <typename>
+ class ThenCallback,
+ typename OriginalR,
+ typename... OriginalArgs,
+ typename ThenR,
+ typename... ThenArgs>
+struct ThenHelper<OriginalCallback<OriginalR(OriginalArgs...)>,
+ ThenCallback<ThenR(ThenArgs...)>> {
+ static_assert(sizeof...(ThenArgs) == 1,
+ "|then| callback must accept exactly one parameter if |this| "
+ "has a non-void return type.");
+ // TODO(dcheng): This should probably check is_convertible as well (same with
+ // `AssertBindArgsValidity`).
+ static_assert(std::is_constructible<ThenArgs..., OriginalR&&>::value,
+ "|then| callback's parameter must be constructible from "
+ "return type of |this|.");
+
+ static auto CreateTrampoline() {
+ return [](OriginalCallback<OriginalR(OriginalArgs...)> c1,
+ ThenCallback<ThenR(ThenArgs...)> c2, OriginalArgs... c1_args) {
+ return std::move(c2).Run(
+ std::move(c1).Run(std::forward<OriginalArgs>(c1_args)...));
+ };
+ }
+};
+
+} // namespace cef_internal
+} // namespace base
+
+#endif // CEF_INCLUDE_BASE_INTERNAL_CEF_CALLBACK_INTERNAL_H_
diff --git a/include/base/internal/cef_lock_impl.h b/include/base/internal/cef_lock_impl.h
new file mode 100644
index 00000000..606e5860
--- /dev/null
+++ b/include/base/internal/cef_lock_impl.h
@@ -0,0 +1,87 @@
+// Copyright (c) 2011 Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Do not include this header file directly. Use base/cef_lock.h instead.
+
+#ifndef CEF_INCLUDE_BASE_INTERNAL_CEF_LOCK_IMPL_H_
+#define CEF_INCLUDE_BASE_INTERNAL_CEF_LOCK_IMPL_H_
+
+#include "include/base/cef_build.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#elif defined(OS_POSIX)
+#include <pthread.h>
+#endif
+
+namespace base {
+namespace cef_internal {
+
+// This class implements the underlying platform-specific spin-lock mechanism
+// used for the Lock class. Most users should not use LockImpl directly, but
+// should instead use Lock.
+class LockImpl {
+ public:
+#if defined(OS_WIN)
+ typedef CRITICAL_SECTION NativeHandle;
+#elif defined(OS_POSIX)
+ typedef pthread_mutex_t NativeHandle;
+#endif
+
+ LockImpl();
+
+ LockImpl(const LockImpl&) = delete;
+ LockImpl& operator=(const LockImpl&) = delete;
+
+ ~LockImpl();
+
+ // If the lock is not held, take it and return true. If the lock is already
+ // held by something else, immediately return false.
+ bool Try();
+
+ // Take the lock, blocking until it is available if necessary.
+ void Lock();
+
+ // Release the lock. This must only be called by the lock's holder: after
+ // a successful call to Try, or a call to Lock.
+ void Unlock();
+
+ // Return the native underlying lock.
+ // TODO(awalker): refactor lock and condition variables so that this is
+ // unnecessary.
+ NativeHandle* native_handle() { return &native_handle_; }
+
+ private:
+ NativeHandle native_handle_;
+};
+
+} // namespace cef_internal
+} // namespace base
+
+#endif // CEF_INCLUDE_BASE_INTERNAL_CEF_LOCK_IMPL_H_
diff --git a/include/base/internal/cef_net_error_list.h b/include/base/internal/cef_net_error_list.h
new file mode 100644
index 00000000..b0445fba
--- /dev/null
+++ b/include/base/internal/cef_net_error_list.h
@@ -0,0 +1,8 @@
+// Copyright (c) 2019 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// Include net error codes from the Chromium source location. When creating a
+// CEF binary distribution this file will be replaced with the Chromium version.
+
+#include "net/base/net_error_list.h"
diff --git a/include/base/internal/cef_raw_scoped_refptr_mismatch_checker.h b/include/base/internal/cef_raw_scoped_refptr_mismatch_checker.h
new file mode 100644
index 00000000..124a329a
--- /dev/null
+++ b/include/base/internal/cef_raw_scoped_refptr_mismatch_checker.h
@@ -0,0 +1,75 @@
+// Copyright (c) 2011 Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Do not include this header file directly. Use base/cef_callback.h instead.
+
+#ifndef CEF_INCLUDE_BASE_INTERNAL_CEF_RAW_SCOPED_REFPTR_MISMATCH_CHECKER_H_
+#define CEF_INCLUDE_BASE_INTERNAL_CEF_RAW_SCOPED_REFPTR_MISMATCH_CHECKER_H_
+
+#include <type_traits>
+
+#include "include/base/cef_template_util.h"
+
+// It is dangerous to post a task with a T* argument where T is a subtype of
+// RefCounted(Base|ThreadSafeBase), since by the time the parameter is used, the
+// object may already have been deleted since it was not held with a
+// scoped_refptr. Example: http://crbug.com/27191
+// The following set of traits are designed to generate a compile error
+// whenever this antipattern is attempted.
+
+namespace base {
+
+// This is a base internal implementation file used by task.h and callback.h.
+// Not for public consumption, so we wrap it in namespace internal.
+namespace cef_internal {
+
+template <typename T, typename = void>
+struct IsRefCountedType : std::false_type {};
+
+template <typename T>
+struct IsRefCountedType<T,
+ void_t<decltype(std::declval<T*>()->AddRef()),
+ decltype(std::declval<T*>()->Release())>>
+ : std::true_type {};
+
+// Human readable translation: you needed to be a scoped_refptr if you are a raw
+// pointer type and are convertible to a RefCounted(Base|ThreadSafeBase) type.
+template <typename T>
+struct NeedsScopedRefptrButGetsRawPtr
+ : conjunction<std::is_pointer<T>,
+ IsRefCountedType<std::remove_pointer_t<T>>> {
+ static_assert(!std::is_reference<T>::value,
+ "NeedsScopedRefptrButGetsRawPtr requires non-reference type.");
+};
+
+} // namespace cef_internal
+
+} // namespace base
+
+#endif // CEF_INCLUDE_BASE_INTERNAL_CEF_RAW_SCOPED_REFPTR_MISMATCH_CHECKER_H_
diff --git a/include/base/internal/cef_scoped_block_mac.h b/include/base/internal/cef_scoped_block_mac.h
new file mode 100644
index 00000000..4e255d16
--- /dev/null
+++ b/include/base/internal/cef_scoped_block_mac.h
@@ -0,0 +1,67 @@
+// Copyright (c) 2013 Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Do not include this header file directly. Use base/mac/scoped_block.h
+// instead.
+
+#ifndef CEF_INCLUDE_BASE_INTERNAL_CEF_SCOPED_BLOCK_MAC_H_
+#define CEF_INCLUDE_BASE_INTERNAL_CEF_SCOPED_BLOCK_MAC_H_
+
+#include <Block.h>
+
+#include "include/base/cef_scoped_typeref_mac.h"
+
+#if defined(__has_feature) && __has_feature(objc_arc)
+#error \
+ "Cannot include include/base/internal/cef_scoped_block_mac.h in file built with ARC."
+#endif
+
+namespace base {
+namespace mac {
+
+namespace cef_internal {
+
+template <typename B>
+struct ScopedBlockTraits {
+ static B InvalidValue() { return nullptr; }
+ static B Retain(B block) { return Block_copy(block); }
+ static void Release(B block) { Block_release(block); }
+};
+
+} // namespace cef_internal
+
+// ScopedBlock<> is patterned after ScopedCFTypeRef<>, but uses Block_copy() and
+// Block_release() instead of CFRetain() and CFRelease().
+template <typename B>
+using ScopedBlock = ScopedTypeRef<B, cef_internal::ScopedBlockTraits<B>>;
+
+} // namespace mac
+} // namespace base
+
+#endif // CEF_INCLUDE_BASE_INTERNAL_CEF_SCOPED_BLOCK_MAC_H_
diff --git a/include/base/internal/cef_scoped_policy.h b/include/base/internal/cef_scoped_policy.h
new file mode 100644
index 00000000..8ef4fb2c
--- /dev/null
+++ b/include/base/internal/cef_scoped_policy.h
@@ -0,0 +1,53 @@
+// Copyright (c) 2012 Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Do not include this header file directly. Use base/memory/scoped_policy.h
+// instead.
+
+#ifndef CEF_INCLUDE_BASE_INTERNAL_CEF_SCOPED_POLICY_H_
+#define CEF_INCLUDE_BASE_INTERNAL_CEF_SCOPED_POLICY_H_
+
+namespace base {
+namespace scoped_policy {
+
+// Defines the ownership policy for a scoped object.
+enum OwnershipPolicy {
+ // The scoped object takes ownership of an object by taking over an existing
+ // ownership claim.
+ ASSUME,
+
+ // The scoped object will retain the object and any initial ownership is
+ // not changed.
+ RETAIN
+};
+
+} // namespace scoped_policy
+} // namespace base
+
+#endif // CEF_INCLUDE_BASE_INTERNAL_CEF_SCOPED_POLICY_H_
diff --git a/include/base/internal/cef_thread_checker_impl.h b/include/base/internal/cef_thread_checker_impl.h
new file mode 100644
index 00000000..26546981
--- /dev/null
+++ b/include/base/internal/cef_thread_checker_impl.h
@@ -0,0 +1,72 @@
+// Copyright (c) 2011 Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Do not include this header file directly. Use base/cef_thread_checker.h
+// instead.
+
+#ifndef CEF_INCLUDE_BASE_INTERNAL_THREAD_CHECKER_IMPL_H_
+#define CEF_INCLUDE_BASE_INTERNAL_THREAD_CHECKER_IMPL_H_
+
+#include "include/base/cef_lock.h"
+#include "include/base/cef_platform_thread.h"
+
+namespace base {
+namespace cef_internal {
+
+// Real implementation of ThreadChecker, for use in debug mode, or
+// for temporary use in release mode (e.g. to CHECK on a threading issue
+// seen only in the wild).
+//
+// Note: You should almost always use the ThreadChecker class to get the
+// right version for your build configuration.
+class ThreadCheckerImpl {
+ public:
+ ThreadCheckerImpl();
+ ~ThreadCheckerImpl();
+
+ bool CalledOnValidThread() const;
+
+ // Changes the thread that is checked for in CalledOnValidThread. This may
+ // be useful when an object may be created on one thread and then used
+ // exclusively on another thread.
+ void DetachFromThread();
+
+ private:
+ void EnsureThreadIdAssigned() const;
+
+ mutable base::Lock lock_;
+ // This is mutable so that CalledOnValidThread can set it.
+ // It's guarded by |lock_|.
+ mutable PlatformThreadRef valid_thread_id_;
+};
+
+} // namespace cef_internal
+} // namespace base
+
+#endif // CEF_INCLUDE_BASE_INTERNAL_THREAD_CHECKER_IMPL_H_
diff --git a/include/capi/cef_accessibility_handler_capi.h b/include/capi/cef_accessibility_handler_capi.h
new file mode 100644
index 00000000..120714ac
--- /dev/null
+++ b/include/capi/cef_accessibility_handler_capi.h
@@ -0,0 +1,81 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=0ac3c8ca887778a840c65108d56038d4d776e073$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_ACCESSIBILITY_HANDLER_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_ACCESSIBILITY_HANDLER_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_values_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Implement this structure to receive accessibility notification when
+/// accessibility events have been registered. The functions of this structure
+/// will be called on the UI thread.
+///
+typedef struct _cef_accessibility_handler_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Called after renderer process sends accessibility tree changes to the
+ /// browser process.
+ ///
+ void(CEF_CALLBACK* on_accessibility_tree_change)(
+ struct _cef_accessibility_handler_t* self,
+ struct _cef_value_t* value);
+
+ ///
+ /// Called after renderer process sends accessibility location changes to the
+ /// browser process.
+ ///
+ void(CEF_CALLBACK* on_accessibility_location_change)(
+ struct _cef_accessibility_handler_t* self,
+ struct _cef_value_t* value);
+} cef_accessibility_handler_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_ACCESSIBILITY_HANDLER_CAPI_H_
diff --git a/include/capi/cef_app_capi.h b/include/capi/cef_app_capi.h
new file mode 100644
index 00000000..f1b58c56
--- /dev/null
+++ b/include/capi/cef_app_capi.h
@@ -0,0 +1,190 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=9b523fbf312a8a0cb1c743a3c8aca7bc9cc22bbc$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_APP_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_APP_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+#include "include/capi/cef_browser_process_handler_capi.h"
+#include "include/capi/cef_command_line_capi.h"
+#include "include/capi/cef_render_process_handler_capi.h"
+#include "include/capi/cef_resource_bundle_handler_capi.h"
+#include "include/capi/cef_scheme_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _cef_app_t;
+
+///
+/// Implement this structure to provide handler implementations. Methods will be
+/// called by the process and/or thread indicated.
+///
+typedef struct _cef_app_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Provides an opportunity to view and/or modify command-line arguments
+ /// before processing by CEF and Chromium. The |process_type| value will be
+ /// NULL for the browser process. Do not keep a reference to the
+ /// cef_command_line_t object passed to this function. The
+ /// cef_settings_t.command_line_args_disabled value can be used to start with
+ /// an NULL command-line object. Any values specified in CefSettings that
+ /// equate to command-line arguments will be set before this function is
+ /// called. Be cautious when using this function to modify command-line
+ /// arguments for non-browser processes as this may result in undefined
+ /// behavior including crashes.
+ ///
+ void(CEF_CALLBACK* on_before_command_line_processing)(
+ struct _cef_app_t* self,
+ const cef_string_t* process_type,
+ struct _cef_command_line_t* command_line);
+
+ ///
+ /// Provides an opportunity to register custom schemes. Do not keep a
+ /// reference to the |registrar| object. This function is called on the main
+ /// thread for each process and the registered schemes should be the same
+ /// across all processes.
+ ///
+ void(CEF_CALLBACK* on_register_custom_schemes)(
+ struct _cef_app_t* self,
+ struct _cef_scheme_registrar_t* registrar);
+
+ ///
+ /// Return the handler for resource bundle events. If
+ /// cef_settings_t.pack_loading_disabled is true (1) a handler must be
+ /// returned. If no handler is returned resources will be loaded from pack
+ /// files. This function is called by the browser and render processes on
+ /// multiple threads.
+ ///
+ struct _cef_resource_bundle_handler_t*(
+ CEF_CALLBACK* get_resource_bundle_handler)(struct _cef_app_t* self);
+
+ ///
+ /// Return the handler for functionality specific to the browser process. This
+ /// function is called on multiple threads in the browser process.
+ ///
+ struct _cef_browser_process_handler_t*(
+ CEF_CALLBACK* get_browser_process_handler)(struct _cef_app_t* self);
+
+ ///
+ /// Return the handler for functionality specific to the render process. This
+ /// function is called on the render process main thread.
+ ///
+ struct _cef_render_process_handler_t*(
+ CEF_CALLBACK* get_render_process_handler)(struct _cef_app_t* self);
+} cef_app_t;
+
+///
+/// This function should be called from the application entry point function to
+/// execute a secondary process. It can be used to run secondary processes from
+/// the browser client executable (default behavior) or from a separate
+/// executable specified by the cef_settings_t.browser_subprocess_path value. If
+/// called for the browser process (identified by no "type" command-line value)
+/// it will return immediately with a value of -1. If called for a recognized
+/// secondary process it will block until the process should exit and then
+/// return the process exit code. The |application| parameter may be NULL. The
+/// |windows_sandbox_info| parameter is only used on Windows and may be NULL
+/// (see cef_sandbox_win.h for details).
+///
+CEF_EXPORT int cef_execute_process(const cef_main_args_t* args,
+ cef_app_t* application,
+ void* windows_sandbox_info);
+
+///
+/// This function should be called on the main application thread to initialize
+/// the CEF browser process. The |application| parameter may be NULL. A return
+/// value of true (1) indicates that it succeeded and false (0) indicates that
+/// it failed. The |windows_sandbox_info| parameter is only used on Windows and
+/// may be NULL (see cef_sandbox_win.h for details).
+///
+CEF_EXPORT int cef_initialize(const cef_main_args_t* args,
+ const struct _cef_settings_t* settings,
+ cef_app_t* application,
+ void* windows_sandbox_info);
+
+///
+/// This function should be called on the main application thread to shut down
+/// the CEF browser process before the application exits.
+///
+CEF_EXPORT void cef_shutdown(void);
+
+///
+/// Perform a single iteration of CEF message loop processing. This function is
+/// provided for cases where the CEF message loop must be integrated into an
+/// existing application message loop. Use of this function is not recommended
+/// for most users; use either the cef_run_message_loop() function or
+/// cef_settings_t.multi_threaded_message_loop if possible. When using this
+/// function care must be taken to balance performance against excessive CPU
+/// usage. It is recommended to enable the cef_settings_t.external_message_pump
+/// option when using this function so that
+/// cef_browser_process_handler_t::on_schedule_message_pump_work() callbacks can
+/// facilitate the scheduling process. This function should only be called on
+/// the main application thread and only if cef_initialize() is called with a
+/// cef_settings_t.multi_threaded_message_loop value of false (0). This function
+/// will not block.
+///
+CEF_EXPORT void cef_do_message_loop_work(void);
+
+///
+/// Run the CEF message loop. Use this function instead of an application-
+/// provided message loop to get the best balance between performance and CPU
+/// usage. This function should only be called on the main application thread
+/// and only if cef_initialize() is called with a
+/// cef_settings_t.multi_threaded_message_loop value of false (0). This function
+/// will block until a quit message is received by the system.
+///
+CEF_EXPORT void cef_run_message_loop(void);
+
+///
+/// Quit the CEF message loop that was started by calling
+/// cef_run_message_loop(). This function should only be called on the main
+/// application thread and only if cef_run_message_loop() was used.
+///
+CEF_EXPORT void cef_quit_message_loop(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_APP_CAPI_H_
diff --git a/include/capi/cef_audio_handler_capi.h b/include/capi/cef_audio_handler_capi.h
new file mode 100644
index 00000000..78af95dd
--- /dev/null
+++ b/include/capi/cef_audio_handler_capi.h
@@ -0,0 +1,121 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=936274d5539f225ff7adb7e0acba517fd9a8e2f8$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_AUDIO_HANDLER_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_AUDIO_HANDLER_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+#include "include/capi/cef_browser_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Implement this structure to handle audio events.
+///
+typedef struct _cef_audio_handler_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Called on the UI thread to allow configuration of audio stream parameters.
+ /// Return true (1) to proceed with audio stream capture, or false (0) to
+ /// cancel it. All members of |params| can optionally be configured here, but
+ /// they are also pre-filled with some sensible defaults.
+ ///
+ int(CEF_CALLBACK* get_audio_parameters)(struct _cef_audio_handler_t* self,
+ struct _cef_browser_t* browser,
+ cef_audio_parameters_t* params);
+
+ ///
+ /// Called on a browser audio capture thread when the browser starts streaming
+ /// audio. OnAudioStreamStopped will always be called after
+ /// OnAudioStreamStarted; both functions may be called multiple times for the
+ /// same browser. |params| contains the audio parameters like sample rate and
+ /// channel layout. |channels| is the number of channels.
+ ///
+ void(CEF_CALLBACK* on_audio_stream_started)(
+ struct _cef_audio_handler_t* self,
+ struct _cef_browser_t* browser,
+ const cef_audio_parameters_t* params,
+ int channels);
+
+ ///
+ /// Called on the audio stream thread when a PCM packet is received for the
+ /// stream. |data| is an array representing the raw PCM data as a floating
+ /// point type, i.e. 4-byte value(s). |frames| is the number of frames in the
+ /// PCM packet. |pts| is the presentation timestamp (in milliseconds since the
+ /// Unix Epoch) and represents the time at which the decompressed packet
+ /// should be presented to the user. Based on |frames| and the
+ /// |channel_layout| value passed to OnAudioStreamStarted you can calculate
+ /// the size of the |data| array in bytes.
+ ///
+ void(CEF_CALLBACK* on_audio_stream_packet)(struct _cef_audio_handler_t* self,
+ struct _cef_browser_t* browser,
+ const float** data,
+ int frames,
+ int64 pts);
+
+ ///
+ /// Called on the UI thread when the stream has stopped. OnAudioSteamStopped
+ /// will always be called after OnAudioStreamStarted; both functions may be
+ /// called multiple times for the same stream.
+ ///
+ void(CEF_CALLBACK* on_audio_stream_stopped)(struct _cef_audio_handler_t* self,
+ struct _cef_browser_t* browser);
+
+ ///
+ /// Called on the UI or audio stream thread when an error occurred. During the
+ /// stream creation phase this callback will be called on the UI thread while
+ /// in the capturing phase it will be called on the audio stream thread. The
+ /// stream will be stopped immediately.
+ ///
+ void(CEF_CALLBACK* on_audio_stream_error)(struct _cef_audio_handler_t* self,
+ struct _cef_browser_t* browser,
+ const cef_string_t* message);
+} cef_audio_handler_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_AUDIO_HANDLER_CAPI_H_
diff --git a/include/capi/cef_auth_callback_capi.h b/include/capi/cef_auth_callback_capi.h
new file mode 100644
index 00000000..6e74c0a4
--- /dev/null
+++ b/include/capi/cef_auth_callback_capi.h
@@ -0,0 +1,76 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=4b9c31ef9a23f899c6d8cd3da49934a41f1bd231$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_AUTH_CALLBACK_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_AUTH_CALLBACK_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Callback structure used for asynchronous continuation of authentication
+/// requests.
+///
+typedef struct _cef_auth_callback_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Continue the authentication request.
+ ///
+ void(CEF_CALLBACK* cont)(struct _cef_auth_callback_t* self,
+ const cef_string_t* username,
+ const cef_string_t* password);
+
+ ///
+ /// Cancel the authentication request.
+ ///
+ void(CEF_CALLBACK* cancel)(struct _cef_auth_callback_t* self);
+} cef_auth_callback_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_AUTH_CALLBACK_CAPI_H_
diff --git a/include/capi/cef_base_capi.h b/include/capi/cef_base_capi.h
new file mode 100644
index 00000000..dbd0b9f3
--- /dev/null
+++ b/include/capi/cef_base_capi.h
@@ -0,0 +1,107 @@
+// Copyright (c) 2014 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CEF_INCLUDE_CAPI_CEF_BASE_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_BASE_CAPI_H_
+
+#include <stdint.h>
+
+#include "include/internal/cef_export.h"
+#include "include/internal/cef_string.h"
+#include "include/internal/cef_string_list.h"
+#include "include/internal/cef_string_map.h"
+#include "include/internal/cef_string_multimap.h"
+#include "include/internal/cef_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+// All ref-counted framework structures must include this structure first.
+///
+typedef struct _cef_base_ref_counted_t {
+ ///
+ // Size of the data structure.
+ ///
+ size_t size;
+
+ ///
+ // Called to increment the reference count for the object. Should be called
+ // for every new copy of a pointer to a given object.
+ ///
+ void(CEF_CALLBACK* add_ref)(struct _cef_base_ref_counted_t* self);
+
+ ///
+ // Called to decrement the reference count for the object. If the reference
+ // count falls to 0 the object should self-delete. Returns true (1) if the
+ // resulting reference count is 0.
+ ///
+ int(CEF_CALLBACK* release)(struct _cef_base_ref_counted_t* self);
+
+ ///
+ // Returns true (1) if the current reference count is 1.
+ ///
+ int(CEF_CALLBACK* has_one_ref)(struct _cef_base_ref_counted_t* self);
+
+ ///
+ // Returns true (1) if the current reference count is at least 1.
+ ///
+ int(CEF_CALLBACK* has_at_least_one_ref)(struct _cef_base_ref_counted_t* self);
+} cef_base_ref_counted_t;
+
+///
+// All scoped framework structures must include this structure first.
+///
+typedef struct _cef_base_scoped_t {
+ ///
+ // Size of the data structure.
+ ///
+ size_t size;
+
+ ///
+ // Called to delete this object. May be NULL if the object is not owned.
+ ///
+ void(CEF_CALLBACK* del)(struct _cef_base_scoped_t* self);
+
+} cef_base_scoped_t;
+
+// Check that the structure |s|, which is defined with a size_t member at the
+// top, is large enough to contain the specified member |f|.
+#define CEF_MEMBER_EXISTS(s, f) \
+ ((intptr_t) & \
+ ((s)->f) - (intptr_t)(s) + sizeof((s)->f) <= *reinterpret_cast<size_t*>(s))
+
+#define CEF_MEMBER_MISSING(s, f) (!CEF_MEMBER_EXISTS(s, f) || !((s)->f))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_BASE_CAPI_H_
diff --git a/include/capi/cef_browser_capi.h b/include/capi/cef_browser_capi.h
new file mode 100644
index 00000000..244a20cd
--- /dev/null
+++ b/include/capi/cef_browser_capi.h
@@ -0,0 +1,952 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=7254c050cd7db2ff7d40a1f54c99e941dc592692$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_BROWSER_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_BROWSER_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+#include "include/capi/cef_devtools_message_observer_capi.h"
+#include "include/capi/cef_drag_data_capi.h"
+#include "include/capi/cef_frame_capi.h"
+#include "include/capi/cef_image_capi.h"
+#include "include/capi/cef_navigation_entry_capi.h"
+#include "include/capi/cef_registration_capi.h"
+#include "include/capi/cef_request_context_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _cef_browser_host_t;
+struct _cef_client_t;
+
+///
+/// Structure used to represent a browser. When used in the browser process the
+/// functions of this structure may be called on any thread unless otherwise
+/// indicated in the comments. When used in the render process the functions of
+/// this structure may only be called on the main thread.
+///
+typedef struct _cef_browser_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// True if this object is currently valid. This will return false (0) after
+ /// cef_life_span_handler_t::OnBeforeClose is called.
+ ///
+ int(CEF_CALLBACK* is_valid)(struct _cef_browser_t* self);
+
+ ///
+ /// Returns the browser host object. This function can only be called in the
+ /// browser process.
+ ///
+ struct _cef_browser_host_t*(CEF_CALLBACK* get_host)(
+ struct _cef_browser_t* self);
+
+ ///
+ /// Returns true (1) if the browser can navigate backwards.
+ ///
+ int(CEF_CALLBACK* can_go_back)(struct _cef_browser_t* self);
+
+ ///
+ /// Navigate backwards.
+ ///
+ void(CEF_CALLBACK* go_back)(struct _cef_browser_t* self);
+
+ ///
+ /// Returns true (1) if the browser can navigate forwards.
+ ///
+ int(CEF_CALLBACK* can_go_forward)(struct _cef_browser_t* self);
+
+ ///
+ /// Navigate forwards.
+ ///
+ void(CEF_CALLBACK* go_forward)(struct _cef_browser_t* self);
+
+ ///
+ /// Returns true (1) if the browser is currently loading.
+ ///
+ int(CEF_CALLBACK* is_loading)(struct _cef_browser_t* self);
+
+ ///
+ /// Reload the current page.
+ ///
+ void(CEF_CALLBACK* reload)(struct _cef_browser_t* self);
+
+ ///
+ /// Reload the current page ignoring any cached data.
+ ///
+ void(CEF_CALLBACK* reload_ignore_cache)(struct _cef_browser_t* self);
+
+ ///
+ /// Stop loading the page.
+ ///
+ void(CEF_CALLBACK* stop_load)(struct _cef_browser_t* self);
+
+ ///
+ /// Returns the globally unique identifier for this browser. This value is
+ /// also used as the tabId for extension APIs.
+ ///
+ int(CEF_CALLBACK* get_identifier)(struct _cef_browser_t* self);
+
+ ///
+ /// Returns true (1) if this object is pointing to the same handle as |that|
+ /// object.
+ ///
+ int(CEF_CALLBACK* is_same)(struct _cef_browser_t* self,
+ struct _cef_browser_t* that);
+
+ ///
+ /// Returns true (1) if the browser is a popup.
+ ///
+ int(CEF_CALLBACK* is_popup)(struct _cef_browser_t* self);
+
+ ///
+ /// Returns true (1) if a document has been loaded in the browser.
+ ///
+ int(CEF_CALLBACK* has_document)(struct _cef_browser_t* self);
+
+ ///
+ /// Returns the main (top-level) frame for the browser. In the browser process
+ /// this will return a valid object until after
+ /// cef_life_span_handler_t::OnBeforeClose is called. In the renderer process
+ /// this will return NULL if the main frame is hosted in a different renderer
+ /// process (e.g. for cross-origin sub-frames). The main frame object will
+ /// change during cross-origin navigation or re-navigation after renderer
+ /// process termination (due to crashes, etc).
+ ///
+ struct _cef_frame_t*(CEF_CALLBACK* get_main_frame)(
+ struct _cef_browser_t* self);
+
+ ///
+ /// Returns the focused frame for the browser.
+ ///
+ struct _cef_frame_t*(CEF_CALLBACK* get_focused_frame)(
+ struct _cef_browser_t* self);
+
+ ///
+ /// Returns the frame with the specified identifier, or NULL if not found.
+ ///
+ struct _cef_frame_t*(CEF_CALLBACK* get_frame_byident)(
+ struct _cef_browser_t* self,
+ int64 identifier);
+
+ ///
+ /// Returns the frame with the specified name, or NULL if not found.
+ ///
+ struct _cef_frame_t*(CEF_CALLBACK* get_frame)(struct _cef_browser_t* self,
+ const cef_string_t* name);
+
+ ///
+ /// Returns the number of frames that currently exist.
+ ///
+ size_t(CEF_CALLBACK* get_frame_count)(struct _cef_browser_t* self);
+
+ ///
+ /// Returns the identifiers of all existing frames.
+ ///
+ void(CEF_CALLBACK* get_frame_identifiers)(struct _cef_browser_t* self,
+ size_t* identifiersCount,
+ int64* identifiers);
+
+ ///
+ /// Returns the names of all existing frames.
+ ///
+ void(CEF_CALLBACK* get_frame_names)(struct _cef_browser_t* self,
+ cef_string_list_t names);
+} cef_browser_t;
+
+///
+/// Callback structure for cef_browser_host_t::RunFileDialog. The functions of
+/// this structure will be called on the browser process UI thread.
+///
+typedef struct _cef_run_file_dialog_callback_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Called asynchronously after the file dialog is dismissed. |file_paths|
+ /// will be a single value or a list of values depending on the dialog mode.
+ /// If the selection was cancelled |file_paths| will be NULL.
+ ///
+ void(CEF_CALLBACK* on_file_dialog_dismissed)(
+ struct _cef_run_file_dialog_callback_t* self,
+ cef_string_list_t file_paths);
+} cef_run_file_dialog_callback_t;
+
+///
+/// Callback structure for cef_browser_host_t::GetNavigationEntries. The
+/// functions of this structure will be called on the browser process UI thread.
+///
+typedef struct _cef_navigation_entry_visitor_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Method that will be executed. Do not keep a reference to |entry| outside
+ /// of this callback. Return true (1) to continue visiting entries or false
+ /// (0) to stop. |current| is true (1) if this entry is the currently loaded
+ /// navigation entry. |index| is the 0-based index of this entry and |total|
+ /// is the total number of entries.
+ ///
+ int(CEF_CALLBACK* visit)(struct _cef_navigation_entry_visitor_t* self,
+ struct _cef_navigation_entry_t* entry,
+ int current,
+ int index,
+ int total);
+} cef_navigation_entry_visitor_t;
+
+///
+/// Callback structure for cef_browser_host_t::PrintToPDF. The functions of this
+/// structure will be called on the browser process UI thread.
+///
+typedef struct _cef_pdf_print_callback_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Method that will be executed when the PDF printing has completed. |path|
+ /// is the output path. |ok| will be true (1) if the printing completed
+ /// successfully or false (0) otherwise.
+ ///
+ void(CEF_CALLBACK* on_pdf_print_finished)(
+ struct _cef_pdf_print_callback_t* self,
+ const cef_string_t* path,
+ int ok);
+} cef_pdf_print_callback_t;
+
+///
+/// Callback structure for cef_browser_host_t::DownloadImage. The functions of
+/// this structure will be called on the browser process UI thread.
+///
+typedef struct _cef_download_image_callback_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Method that will be executed when the image download has completed.
+ /// |image_url| is the URL that was downloaded and |http_status_code| is the
+ /// resulting HTTP status code. |image| is the resulting image, possibly at
+ /// multiple scale factors, or NULL if the download failed.
+ ///
+ void(CEF_CALLBACK* on_download_image_finished)(
+ struct _cef_download_image_callback_t* self,
+ const cef_string_t* image_url,
+ int http_status_code,
+ struct _cef_image_t* image);
+} cef_download_image_callback_t;
+
+///
+/// Structure used to represent the browser process aspects of a browser. The
+/// functions of this structure can only be called in the browser process. They
+/// may be called on any thread in that process unless otherwise indicated in
+/// the comments.
+///
+typedef struct _cef_browser_host_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Returns the hosted browser object.
+ ///
+ struct _cef_browser_t*(CEF_CALLBACK* get_browser)(
+ struct _cef_browser_host_t* self);
+
+ ///
+ /// Request that the browser close. The JavaScript 'onbeforeunload' event will
+ /// be fired. If |force_close| is false (0) the event handler, if any, will be
+ /// allowed to prompt the user and the user can optionally cancel the close.
+ /// If |force_close| is true (1) the prompt will not be displayed and the
+ /// close will proceed. Results in a call to
+ /// cef_life_span_handler_t::do_close() if the event handler allows the close
+ /// or if |force_close| is true (1). See cef_life_span_handler_t::do_close()
+ /// documentation for additional usage information.
+ ///
+ void(CEF_CALLBACK* close_browser)(struct _cef_browser_host_t* self,
+ int force_close);
+
+ ///
+ /// Helper for closing a browser. Call this function from the top-level window
+ /// close handler (if any). Internally this calls CloseBrowser(false (0)) if
+ /// the close has not yet been initiated. This function returns false (0)
+ /// while the close is pending and true (1) after the close has completed. See
+ /// close_browser() and cef_life_span_handler_t::do_close() documentation for
+ /// additional usage information. This function must be called on the browser
+ /// process UI thread.
+ ///
+ int(CEF_CALLBACK* try_close_browser)(struct _cef_browser_host_t* self);
+
+ ///
+ /// Set whether the browser is focused.
+ ///
+ void(CEF_CALLBACK* set_focus)(struct _cef_browser_host_t* self, int focus);
+
+ ///
+ /// Retrieve the window handle (if any) for this browser. If this browser is
+ /// wrapped in a cef_browser_view_t this function should be called on the
+ /// browser process UI thread and it will return the handle for the top-level
+ /// native window.
+ ///
+ cef_window_handle_t(CEF_CALLBACK* get_window_handle)(
+ struct _cef_browser_host_t* self);
+
+ ///
+ /// Retrieve the window handle (if any) of the browser that opened this
+ /// browser. Will return NULL for non-popup browsers or if this browser is
+ /// wrapped in a cef_browser_view_t. This function can be used in combination
+ /// with custom handling of modal windows.
+ ///
+ cef_window_handle_t(CEF_CALLBACK* get_opener_window_handle)(
+ struct _cef_browser_host_t* self);
+
+ ///
+ /// Returns true (1) if this browser is wrapped in a cef_browser_view_t.
+ ///
+ int(CEF_CALLBACK* has_view)(struct _cef_browser_host_t* self);
+
+ ///
+ /// Returns the client for this browser.
+ ///
+ struct _cef_client_t*(CEF_CALLBACK* get_client)(
+ struct _cef_browser_host_t* self);
+
+ ///
+ /// Returns the request context for this browser.
+ ///
+ struct _cef_request_context_t*(CEF_CALLBACK* get_request_context)(
+ struct _cef_browser_host_t* self);
+
+ ///
+ /// Get the current zoom level. The default zoom level is 0.0. This function
+ /// can only be called on the UI thread.
+ ///
+ double(CEF_CALLBACK* get_zoom_level)(struct _cef_browser_host_t* self);
+
+ ///
+ /// Change the zoom level to the specified value. Specify 0.0 to reset the
+ /// zoom level. If called on the UI thread the change will be applied
+ /// immediately. Otherwise, the change will be applied asynchronously on the
+ /// UI thread.
+ ///
+ void(CEF_CALLBACK* set_zoom_level)(struct _cef_browser_host_t* self,
+ double zoomLevel);
+
+ ///
+ /// Call to run a file chooser dialog. Only a single file chooser dialog may
+ /// be pending at any given time. |mode| represents the type of dialog to
+ /// display. |title| to the title to be used for the dialog and may be NULL to
+ /// show the default title ("Open" or "Save" depending on the mode).
+ /// |default_file_path| is the path with optional directory and/or file name
+ /// component that will be initially selected in the dialog. |accept_filters|
+ /// are used to restrict the selectable file types and may any combination of
+ /// (a) valid lower-cased MIME types (e.g. "text/*" or "image/*"), (b)
+ /// individual file extensions (e.g. ".txt" or ".png"), or (c) combined
+ /// description and file extension delimited using "|" and ";" (e.g. "Image
+ /// Types|.png;.gif;.jpg"). |callback| will be executed after the dialog is
+ /// dismissed or immediately if another dialog is already pending. The dialog
+ /// will be initiated asynchronously on the UI thread.
+ ///
+ void(CEF_CALLBACK* run_file_dialog)(
+ struct _cef_browser_host_t* self,
+ cef_file_dialog_mode_t mode,
+ const cef_string_t* title,
+ const cef_string_t* default_file_path,
+ cef_string_list_t accept_filters,
+ struct _cef_run_file_dialog_callback_t* callback);
+
+ ///
+ /// Download the file at |url| using cef_download_handler_t.
+ ///
+ void(CEF_CALLBACK* start_download)(struct _cef_browser_host_t* self,
+ const cef_string_t* url);
+
+ ///
+ /// Download |image_url| and execute |callback| on completion with the images
+ /// received from the renderer. If |is_favicon| is true (1) then cookies are
+ /// not sent and not accepted during download. Images with density independent
+ /// pixel (DIP) sizes larger than |max_image_size| are filtered out from the
+ /// image results. Versions of the image at different scale factors may be
+ /// downloaded up to the maximum scale factor supported by the system. If
+ /// there are no image results <= |max_image_size| then the smallest image is
+ /// resized to |max_image_size| and is the only result. A |max_image_size| of
+ /// 0 means unlimited. If |bypass_cache| is true (1) then |image_url| is
+ /// requested from the server even if it is present in the browser cache.
+ ///
+ void(CEF_CALLBACK* download_image)(
+ struct _cef_browser_host_t* self,
+ const cef_string_t* image_url,
+ int is_favicon,
+ uint32 max_image_size,
+ int bypass_cache,
+ struct _cef_download_image_callback_t* callback);
+
+ ///
+ /// Print the current browser contents.
+ ///
+ void(CEF_CALLBACK* print)(struct _cef_browser_host_t* self);
+
+ ///
+ /// Print the current browser contents to the PDF file specified by |path| and
+ /// execute |callback| on completion. The caller is responsible for deleting
+ /// |path| when done. For PDF printing to work on Linux you must implement the
+ /// cef_print_handler_t::GetPdfPaperSize function.
+ ///
+ void(CEF_CALLBACK* print_to_pdf)(
+ struct _cef_browser_host_t* self,
+ const cef_string_t* path,
+ const struct _cef_pdf_print_settings_t* settings,
+ struct _cef_pdf_print_callback_t* callback);
+
+ ///
+ /// Search for |searchText|. |forward| indicates whether to search forward or
+ /// backward within the page. |matchCase| indicates whether the search should
+ /// be case-sensitive. |findNext| indicates whether this is the first request
+ /// or a follow-up. The search will be restarted if |searchText| or
+ /// |matchCase| change. The search will be stopped if |searchText| is NULL.
+ /// The cef_find_handler_t instance, if any, returned via
+ /// cef_client_t::GetFindHandler will be called to report find results.
+ ///
+ void(CEF_CALLBACK* find)(struct _cef_browser_host_t* self,
+ const cef_string_t* searchText,
+ int forward,
+ int matchCase,
+ int findNext);
+
+ ///
+ /// Cancel all searches that are currently going on.
+ ///
+ void(CEF_CALLBACK* stop_finding)(struct _cef_browser_host_t* self,
+ int clearSelection);
+
+ ///
+ /// Open developer tools (DevTools) in its own browser. The DevTools browser
+ /// will remain associated with this browser. If the DevTools browser is
+ /// already open then it will be focused, in which case the |windowInfo|,
+ /// |client| and |settings| parameters will be ignored. If
+ /// |inspect_element_at| is non-NULL then the element at the specified (x,y)
+ /// location will be inspected. The |windowInfo| parameter will be ignored if
+ /// this browser is wrapped in a cef_browser_view_t.
+ ///
+ void(CEF_CALLBACK* show_dev_tools)(
+ struct _cef_browser_host_t* self,
+ const struct _cef_window_info_t* windowInfo,
+ struct _cef_client_t* client,
+ const struct _cef_browser_settings_t* settings,
+ const cef_point_t* inspect_element_at);
+
+ ///
+ /// Explicitly close the associated DevTools browser, if any.
+ ///
+ void(CEF_CALLBACK* close_dev_tools)(struct _cef_browser_host_t* self);
+
+ ///
+ /// Returns true (1) if this browser currently has an associated DevTools
+ /// browser. Must be called on the browser process UI thread.
+ ///
+ int(CEF_CALLBACK* has_dev_tools)(struct _cef_browser_host_t* self);
+
+ ///
+ /// Send a function call message over the DevTools protocol. |message| must be
+ /// a UTF8-encoded JSON dictionary that contains "id" (int), "function"
+ /// (string) and "params" (dictionary, optional) values. See the DevTools
+ /// protocol documentation at https://chromedevtools.github.io/devtools-
+ /// protocol/ for details of supported functions and the expected "params"
+ /// dictionary contents. |message| will be copied if necessary. This function
+ /// will return true (1) if called on the UI thread and the message was
+ /// successfully submitted for validation, otherwise false (0). Validation
+ /// will be applied asynchronously and any messages that fail due to
+ /// formatting errors or missing parameters may be discarded without
+ /// notification. Prefer ExecuteDevToolsMethod if a more structured approach
+ /// to message formatting is desired.
+ ///
+ /// Every valid function call will result in an asynchronous function result
+ /// or error message that references the sent message "id". Event messages are
+ /// received while notifications are enabled (for example, between function
+ /// calls for "Page.enable" and "Page.disable"). All received messages will be
+ /// delivered to the observer(s) registered with AddDevToolsMessageObserver.
+ /// See cef_dev_tools_message_observer_t::OnDevToolsMessage documentation for
+ /// details of received message contents.
+ ///
+ /// Usage of the SendDevToolsMessage, ExecuteDevToolsMethod and
+ /// AddDevToolsMessageObserver functions does not require an active DevTools
+ /// front-end or remote-debugging session. Other active DevTools sessions will
+ /// continue to function independently. However, any modification of global
+ /// browser state by one session may not be reflected in the UI of other
+ /// sessions.
+ ///
+ /// Communication with the DevTools front-end (when displayed) can be logged
+ /// for development purposes by passing the `--devtools-protocol-log-
+ /// file=<path>` command-line flag.
+ ///
+ int(CEF_CALLBACK* send_dev_tools_message)(struct _cef_browser_host_t* self,
+ const void* message,
+ size_t message_size);
+
+ ///
+ /// Execute a function call over the DevTools protocol. This is a more
+ /// structured version of SendDevToolsMessage. |message_id| is an incremental
+ /// number that uniquely identifies the message (pass 0 to have the next
+ /// number assigned automatically based on previous values). |function| is the
+ /// function name. |params| are the function parameters, which may be NULL.
+ /// See the DevTools protocol documentation (linked above) for details of
+ /// supported functions and the expected |params| dictionary contents. This
+ /// function will return the assigned message ID if called on the UI thread
+ /// and the message was successfully submitted for validation, otherwise 0.
+ /// See the SendDevToolsMessage documentation for additional usage
+ /// information.
+ ///
+ int(CEF_CALLBACK* execute_dev_tools_method)(
+ struct _cef_browser_host_t* self,
+ int message_id,
+ const cef_string_t* method,
+ struct _cef_dictionary_value_t* params);
+
+ ///
+ /// Add an observer for DevTools protocol messages (function results and
+ /// events). The observer will remain registered until the returned
+ /// Registration object is destroyed. See the SendDevToolsMessage
+ /// documentation for additional usage information.
+ ///
+ struct _cef_registration_t*(CEF_CALLBACK* add_dev_tools_message_observer)(
+ struct _cef_browser_host_t* self,
+ struct _cef_dev_tools_message_observer_t* observer);
+
+ ///
+ /// Retrieve a snapshot of current navigation entries as values sent to the
+ /// specified visitor. If |current_only| is true (1) only the current
+ /// navigation entry will be sent, otherwise all navigation entries will be
+ /// sent.
+ ///
+ void(CEF_CALLBACK* get_navigation_entries)(
+ struct _cef_browser_host_t* self,
+ struct _cef_navigation_entry_visitor_t* visitor,
+ int current_only);
+
+ ///
+ /// If a misspelled word is currently selected in an editable node calling
+ /// this function will replace it with the specified |word|.
+ ///
+ void(CEF_CALLBACK* replace_misspelling)(struct _cef_browser_host_t* self,
+ const cef_string_t* word);
+
+ ///
+ /// Add the specified |word| to the spelling dictionary.
+ ///
+ void(CEF_CALLBACK* add_word_to_dictionary)(struct _cef_browser_host_t* self,
+ const cef_string_t* word);
+
+ ///
+ /// Returns true (1) if window rendering is disabled.
+ ///
+ int(CEF_CALLBACK* is_window_rendering_disabled)(
+ struct _cef_browser_host_t* self);
+
+ ///
+ /// Notify the browser that the widget has been resized. The browser will
+ /// first call cef_render_handler_t::GetViewRect to get the new size and then
+ /// call cef_render_handler_t::OnPaint asynchronously with the updated
+ /// regions. This function is only used when window rendering is disabled.
+ ///
+ void(CEF_CALLBACK* was_resized)(struct _cef_browser_host_t* self);
+
+ ///
+ /// Notify the browser that it has been hidden or shown. Layouting and
+ /// cef_render_handler_t::OnPaint notification will stop when the browser is
+ /// hidden. This function is only used when window rendering is disabled.
+ ///
+ void(CEF_CALLBACK* was_hidden)(struct _cef_browser_host_t* self, int hidden);
+
+ ///
+ /// Send a notification to the browser that the screen info has changed. The
+ /// browser will then call cef_render_handler_t::GetScreenInfo to update the
+ /// screen information with the new values. This simulates moving the webview
+ /// window from one display to another, or changing the properties of the
+ /// current display. This function is only used when window rendering is
+ /// disabled.
+ ///
+ void(CEF_CALLBACK* notify_screen_info_changed)(
+ struct _cef_browser_host_t* self);
+
+ ///
+ /// Invalidate the view. The browser will call cef_render_handler_t::OnPaint
+ /// asynchronously. This function is only used when window rendering is
+ /// disabled.
+ ///
+ void(CEF_CALLBACK* invalidate)(struct _cef_browser_host_t* self,
+ cef_paint_element_type_t type);
+
+ ///
+ /// Issue a BeginFrame request to Chromium. Only valid when
+ /// cef_window_tInfo::external_begin_frame_enabled is set to true (1).
+ ///
+ void(CEF_CALLBACK* send_external_begin_frame)(
+ struct _cef_browser_host_t* self);
+
+ ///
+ /// Send a key event to the browser.
+ ///
+ void(CEF_CALLBACK* send_key_event)(struct _cef_browser_host_t* self,
+ const cef_key_event_t* event);
+
+ ///
+ /// Send a mouse click event to the browser. The |x| and |y| coordinates are
+ /// relative to the upper-left corner of the view.
+ ///
+ void(CEF_CALLBACK* send_mouse_click_event)(struct _cef_browser_host_t* self,
+ const cef_mouse_event_t* event,
+ cef_mouse_button_type_t type,
+ int mouseUp,
+ int clickCount);
+
+ ///
+ /// Send a mouse move event to the browser. The |x| and |y| coordinates are
+ /// relative to the upper-left corner of the view.
+ ///
+ void(CEF_CALLBACK* send_mouse_move_event)(struct _cef_browser_host_t* self,
+ const cef_mouse_event_t* event,
+ int mouseLeave);
+
+ ///
+ /// Send a mouse wheel event to the browser. The |x| and |y| coordinates are
+ /// relative to the upper-left corner of the view. The |deltaX| and |deltaY|
+ /// values represent the movement delta in the X and Y directions
+ /// respectively. In order to scroll inside select popups with window
+ /// rendering disabled cef_render_handler_t::GetScreenPoint should be
+ /// implemented properly.
+ ///
+ void(CEF_CALLBACK* send_mouse_wheel_event)(struct _cef_browser_host_t* self,
+ const cef_mouse_event_t* event,
+ int deltaX,
+ int deltaY);
+
+ ///
+ /// Send a touch event to the browser for a windowless browser.
+ ///
+ void(CEF_CALLBACK* send_touch_event)(struct _cef_browser_host_t* self,
+ const cef_touch_event_t* event);
+
+ ///
+ /// Send a capture lost event to the browser.
+ ///
+ void(CEF_CALLBACK* send_capture_lost_event)(struct _cef_browser_host_t* self);
+
+ ///
+ /// Notify the browser that the window hosting it is about to be moved or
+ /// resized. This function is only used on Windows and Linux.
+ ///
+ void(CEF_CALLBACK* notify_move_or_resize_started)(
+ struct _cef_browser_host_t* self);
+
+ ///
+ /// Returns the maximum rate in frames per second (fps) that
+ /// cef_render_handler_t::OnPaint will be called for a windowless browser. The
+ /// actual fps may be lower if the browser cannot generate frames at the
+ /// requested rate. The minimum value is 1 and the maximum value is 60
+ /// (default 30). This function can only be called on the UI thread.
+ ///
+ int(CEF_CALLBACK* get_windowless_frame_rate)(
+ struct _cef_browser_host_t* self);
+
+ ///
+ /// Set the maximum rate in frames per second (fps) that
+ /// cef_render_handler_t:: OnPaint will be called for a windowless browser.
+ /// The actual fps may be lower if the browser cannot generate frames at the
+ /// requested rate. The minimum value is 1 and the maximum value is 60
+ /// (default 30). Can also be set at browser creation via
+ /// cef_browser_tSettings.windowless_frame_rate.
+ ///
+ void(CEF_CALLBACK* set_windowless_frame_rate)(
+ struct _cef_browser_host_t* self,
+ int frame_rate);
+
+ ///
+ /// Begins a new composition or updates the existing composition. Blink has a
+ /// special node (a composition node) that allows the input function to change
+ /// text without affecting other DOM nodes. |text| is the optional text that
+ /// will be inserted into the composition node. |underlines| is an optional
+ /// set of ranges that will be underlined in the resulting text.
+ /// |replacement_range| is an optional range of the existing text that will be
+ /// replaced. |selection_range| is an optional range of the resulting text
+ /// that will be selected after insertion or replacement. The
+ /// |replacement_range| value is only used on OS X.
+ ///
+ /// This function may be called multiple times as the composition changes.
+ /// When the client is done making changes the composition should either be
+ /// canceled or completed. To cancel the composition call
+ /// ImeCancelComposition. To complete the composition call either
+ /// ImeCommitText or ImeFinishComposingText. Completion is usually signaled
+ /// when:
+ ///
+ /// 1. The client receives a WM_IME_COMPOSITION message with a GCS_RESULTSTR
+ /// flag (on Windows), or;
+ /// 2. The client receives a "commit" signal of GtkIMContext (on Linux), or;
+ /// 3. insertText of NSTextInput is called (on Mac).
+ ///
+ /// This function is only used when window rendering is disabled.
+ ///
+ void(CEF_CALLBACK* ime_set_composition)(
+ struct _cef_browser_host_t* self,
+ const cef_string_t* text,
+ size_t underlinesCount,
+ cef_composition_underline_t const* underlines,
+ const cef_range_t* replacement_range,
+ const cef_range_t* selection_range);
+
+ ///
+ /// Completes the existing composition by optionally inserting the specified
+ /// |text| into the composition node. |replacement_range| is an optional range
+ /// of the existing text that will be replaced. |relative_cursor_pos| is where
+ /// the cursor will be positioned relative to the current cursor position. See
+ /// comments on ImeSetComposition for usage. The |replacement_range| and
+ /// |relative_cursor_pos| values are only used on OS X. This function is only
+ /// used when window rendering is disabled.
+ ///
+ void(CEF_CALLBACK* ime_commit_text)(struct _cef_browser_host_t* self,
+ const cef_string_t* text,
+ const cef_range_t* replacement_range,
+ int relative_cursor_pos);
+
+ ///
+ /// Completes the existing composition by applying the current composition
+ /// node contents. If |keep_selection| is false (0) the current selection, if
+ /// any, will be discarded. See comments on ImeSetComposition for usage. This
+ /// function is only used when window rendering is disabled.
+ ///
+ void(CEF_CALLBACK* ime_finish_composing_text)(
+ struct _cef_browser_host_t* self,
+ int keep_selection);
+
+ ///
+ /// Cancels the existing composition and discards the composition node
+ /// contents without applying them. See comments on ImeSetComposition for
+ /// usage. This function is only used when window rendering is disabled.
+ ///
+ void(CEF_CALLBACK* ime_cancel_composition)(struct _cef_browser_host_t* self);
+
+ ///
+ /// Call this function when the user drags the mouse into the web view (before
+ /// calling DragTargetDragOver/DragTargetLeave/DragTargetDrop). |drag_data|
+ /// should not contain file contents as this type of data is not allowed to be
+ /// dragged into the web view. File contents can be removed using
+ /// cef_drag_data_t::ResetFileContents (for example, if |drag_data| comes from
+ /// cef_render_handler_t::StartDragging). This function is only used when
+ /// window rendering is disabled.
+ ///
+ void(CEF_CALLBACK* drag_target_drag_enter)(
+ struct _cef_browser_host_t* self,
+ struct _cef_drag_data_t* drag_data,
+ const cef_mouse_event_t* event,
+ cef_drag_operations_mask_t allowed_ops);
+
+ ///
+ /// Call this function each time the mouse is moved across the web view during
+ /// a drag operation (after calling DragTargetDragEnter and before calling
+ /// DragTargetDragLeave/DragTargetDrop). This function is only used when
+ /// window rendering is disabled.
+ ///
+ void(CEF_CALLBACK* drag_target_drag_over)(
+ struct _cef_browser_host_t* self,
+ const cef_mouse_event_t* event,
+ cef_drag_operations_mask_t allowed_ops);
+
+ ///
+ /// Call this function when the user drags the mouse out of the web view
+ /// (after calling DragTargetDragEnter). This function is only used when
+ /// window rendering is disabled.
+ ///
+ void(CEF_CALLBACK* drag_target_drag_leave)(struct _cef_browser_host_t* self);
+
+ ///
+ /// Call this function when the user completes the drag operation by dropping
+ /// the object onto the web view (after calling DragTargetDragEnter). The
+ /// object being dropped is |drag_data|, given as an argument to the previous
+ /// DragTargetDragEnter call. This function is only used when window rendering
+ /// is disabled.
+ ///
+ void(CEF_CALLBACK* drag_target_drop)(struct _cef_browser_host_t* self,
+ const cef_mouse_event_t* event);
+
+ ///
+ /// Call this function when the drag operation started by a
+ /// cef_render_handler_t::StartDragging call has ended either in a drop or by
+ /// being cancelled. |x| and |y| are mouse coordinates relative to the upper-
+ /// left corner of the view. If the web view is both the drag source and the
+ /// drag target then all DragTarget* functions should be called before
+ /// DragSource* mthods. This function is only used when window rendering is
+ /// disabled.
+ ///
+ void(CEF_CALLBACK* drag_source_ended_at)(struct _cef_browser_host_t* self,
+ int x,
+ int y,
+ cef_drag_operations_mask_t op);
+
+ ///
+ /// Call this function when the drag operation started by a
+ /// cef_render_handler_t::StartDragging call has completed. This function may
+ /// be called immediately without first calling DragSourceEndedAt to cancel a
+ /// drag operation. If the web view is both the drag source and the drag
+ /// target then all DragTarget* functions should be called before DragSource*
+ /// mthods. This function is only used when window rendering is disabled.
+ ///
+ void(CEF_CALLBACK* drag_source_system_drag_ended)(
+ struct _cef_browser_host_t* self);
+
+ ///
+ /// Returns the current visible navigation entry for this browser. This
+ /// function can only be called on the UI thread.
+ ///
+ struct _cef_navigation_entry_t*(CEF_CALLBACK* get_visible_navigation_entry)(
+ struct _cef_browser_host_t* self);
+
+ ///
+ /// Set accessibility state for all frames. |accessibility_state| may be
+ /// default, enabled or disabled. If |accessibility_state| is STATE_DEFAULT
+ /// then accessibility will be disabled by default and the state may be
+ /// further controlled with the "force-renderer-accessibility" and "disable-
+ /// renderer-accessibility" command-line switches. If |accessibility_state| is
+ /// STATE_ENABLED then accessibility will be enabled. If |accessibility_state|
+ /// is STATE_DISABLED then accessibility will be completely disabled.
+ ///
+ /// For windowed browsers accessibility will be enabled in Complete mode
+ /// (which corresponds to kAccessibilityModeComplete in Chromium). In this
+ /// mode all platform accessibility objects will be created and managed by
+ /// Chromium's internal implementation. The client needs only to detect the
+ /// screen reader and call this function appropriately. For example, on macOS
+ /// the client can handle the @"AXEnhancedUserStructure" accessibility
+ /// attribute to detect VoiceOver state changes and on Windows the client can
+ /// handle WM_GETOBJECT with OBJID_CLIENT to detect accessibility readers.
+ ///
+ /// For windowless browsers accessibility will be enabled in TreeOnly mode
+ /// (which corresponds to kAccessibilityModeWebContentsOnly in Chromium). In
+ /// this mode renderer accessibility is enabled, the full tree is computed,
+ /// and events are passed to CefAccessibiltyHandler, but platform
+ /// accessibility objects are not created. The client may implement platform
+ /// accessibility objects using CefAccessibiltyHandler callbacks if desired.
+ ///
+ void(CEF_CALLBACK* set_accessibility_state)(struct _cef_browser_host_t* self,
+ cef_state_t accessibility_state);
+
+ ///
+ /// Enable notifications of auto resize via
+ /// cef_display_handler_t::OnAutoResize. Notifications are disabled by
+ /// default. |min_size| and |max_size| define the range of allowed sizes.
+ ///
+ void(CEF_CALLBACK* set_auto_resize_enabled)(struct _cef_browser_host_t* self,
+ int enabled,
+ const cef_size_t* min_size,
+ const cef_size_t* max_size);
+
+ ///
+ /// Returns the extension hosted in this browser or NULL if no extension is
+ /// hosted. See cef_request_context_t::LoadExtension for details.
+ ///
+ struct _cef_extension_t*(CEF_CALLBACK* get_extension)(
+ struct _cef_browser_host_t* self);
+
+ ///
+ /// Returns true (1) if this browser is hosting an extension background
+ /// script. Background hosts do not have a window and are not displayable. See
+ /// cef_request_context_t::LoadExtension for details.
+ ///
+ int(CEF_CALLBACK* is_background_host)(struct _cef_browser_host_t* self);
+
+ ///
+ /// Set whether the browser's audio is muted.
+ ///
+ void(CEF_CALLBACK* set_audio_muted)(struct _cef_browser_host_t* self,
+ int mute);
+
+ ///
+ /// Returns true (1) if the browser's audio is muted. This function can only
+ /// be called on the UI thread.
+ ///
+ int(CEF_CALLBACK* is_audio_muted)(struct _cef_browser_host_t* self);
+} cef_browser_host_t;
+
+///
+/// Create a new browser using the window parameters specified by |windowInfo|.
+/// All values will be copied internally and the actual window (if any) will be
+/// created on the UI thread. If |request_context| is NULL the global request
+/// context will be used. This function can be called on any browser process
+/// thread and will not block. The optional |extra_info| parameter provides an
+/// opportunity to specify extra information specific to the created browser
+/// that will be passed to cef_render_process_handler_t::on_browser_created() in
+/// the render process.
+///
+CEF_EXPORT int cef_browser_host_create_browser(
+ const cef_window_info_t* windowInfo,
+ struct _cef_client_t* client,
+ const cef_string_t* url,
+ const struct _cef_browser_settings_t* settings,
+ struct _cef_dictionary_value_t* extra_info,
+ struct _cef_request_context_t* request_context);
+
+///
+/// Create a new browser using the window parameters specified by |windowInfo|.
+/// If |request_context| is NULL the global request context will be used. This
+/// function can only be called on the browser process UI thread. The optional
+/// |extra_info| parameter provides an opportunity to specify extra information
+/// specific to the created browser that will be passed to
+/// cef_render_process_handler_t::on_browser_created() in the render process.
+///
+CEF_EXPORT cef_browser_t* cef_browser_host_create_browser_sync(
+ const cef_window_info_t* windowInfo,
+ struct _cef_client_t* client,
+ const cef_string_t* url,
+ const struct _cef_browser_settings_t* settings,
+ struct _cef_dictionary_value_t* extra_info,
+ struct _cef_request_context_t* request_context);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_BROWSER_CAPI_H_
diff --git a/include/capi/cef_browser_process_handler_capi.h b/include/capi/cef_browser_process_handler_capi.h
new file mode 100644
index 00000000..043deb4d
--- /dev/null
+++ b/include/capi/cef_browser_process_handler_capi.h
@@ -0,0 +1,141 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=4ef8b73a5218531b370fdd76c23153a1f83b7f7b$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_BROWSER_PROCESS_HANDLER_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_BROWSER_PROCESS_HANDLER_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+#include "include/capi/cef_client_capi.h"
+#include "include/capi/cef_command_line_capi.h"
+#include "include/capi/cef_preference_capi.h"
+#include "include/capi/cef_values_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Structure used to implement browser process callbacks. The functions of this
+/// structure will be called on the browser process main thread unless otherwise
+/// indicated.
+///
+typedef struct _cef_browser_process_handler_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Provides an opportunity to register custom preferences prior to global and
+ /// request context initialization.
+ ///
+ /// If |type| is CEF_PREFERENCES_TYPE_GLOBAL the registered preferences can be
+ /// accessed via cef_preference_manager_t::GetGlobalPreferences after
+ /// OnContextInitialized is called. Global preferences are registered a single
+ /// time at application startup. See related cef_settings_t.cache_path and
+ /// cef_settings_t.persist_user_preferences configuration.
+ ///
+ /// If |type| is CEF_PREFERENCES_TYPE_REQUEST_CONTEXT the preferences can be
+ /// accessed via the cef_request_context_t after
+ /// cef_request_context_handler_t::OnRequestContextInitialized is called.
+ /// Request context preferences are registered each time a new
+ /// cef_request_context_t is created. It is intended but not required that all
+ /// request contexts have the same registered preferences. See related
+ /// cef_request_context_settings_t.cache_path and
+ /// cef_request_context_settings_t.persist_user_preferences configuration.
+ ///
+ /// Do not keep a reference to the |registrar| object. This function is called
+ /// on the browser process UI thread.
+ ///
+ void(CEF_CALLBACK* on_register_custom_preferences)(
+ struct _cef_browser_process_handler_t* self,
+ cef_preferences_type_t type,
+ struct _cef_preference_registrar_t* registrar);
+
+ ///
+ /// Called on the browser process UI thread immediately after the CEF context
+ /// has been initialized.
+ ///
+ void(CEF_CALLBACK* on_context_initialized)(
+ struct _cef_browser_process_handler_t* self);
+
+ ///
+ /// Called before a child process is launched. Will be called on the browser
+ /// process UI thread when launching a render process and on the browser
+ /// process IO thread when launching a GPU process. Provides an opportunity to
+ /// modify the child process command line. Do not keep a reference to
+ /// |command_line| outside of this function.
+ ///
+ void(CEF_CALLBACK* on_before_child_process_launch)(
+ struct _cef_browser_process_handler_t* self,
+ struct _cef_command_line_t* command_line);
+
+ ///
+ /// Called from any thread when work has been scheduled for the browser
+ /// process main (UI) thread. This callback is used in combination with
+ /// cef_settings_t.external_message_pump and cef_do_message_loop_work() in
+ /// cases where the CEF message loop must be integrated into an existing
+ /// application message loop (see additional comments and warnings on
+ /// CefDoMessageLoopWork). This callback should schedule a
+ /// cef_do_message_loop_work() call to happen on the main (UI) thread.
+ /// |delay_ms| is the requested delay in milliseconds. If |delay_ms| is <= 0
+ /// then the call should happen reasonably soon. If |delay_ms| is > 0 then the
+ /// call should be scheduled to happen after the specified delay and any
+ /// currently pending scheduled call should be cancelled.
+ ///
+ void(CEF_CALLBACK* on_schedule_message_pump_work)(
+ struct _cef_browser_process_handler_t* self,
+ int64 delay_ms);
+
+ ///
+ /// Return the default client for use with a newly created browser window. If
+ /// null is returned the browser will be unmanaged (no callbacks will be
+ /// executed for that browser) and application shutdown will be blocked until
+ /// the browser window is closed manually. This function is currently only
+ /// used with the chrome runtime.
+ ///
+ struct _cef_client_t*(CEF_CALLBACK* get_default_client)(
+ struct _cef_browser_process_handler_t* self);
+} cef_browser_process_handler_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_BROWSER_PROCESS_HANDLER_CAPI_H_
diff --git a/include/capi/cef_callback_capi.h b/include/capi/cef_callback_capi.h
new file mode 100644
index 00000000..d5086aab
--- /dev/null
+++ b/include/capi/cef_callback_capi.h
@@ -0,0 +1,88 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=4fd98ff68ecb42677c3344b75e26d4787161b0d2$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_CALLBACK_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_CALLBACK_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Generic callback structure used for asynchronous continuation.
+///
+typedef struct _cef_callback_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Continue processing.
+ ///
+ void(CEF_CALLBACK* cont)(struct _cef_callback_t* self);
+
+ ///
+ /// Cancel processing.
+ ///
+ void(CEF_CALLBACK* cancel)(struct _cef_callback_t* self);
+} cef_callback_t;
+
+///
+/// Generic callback structure used for asynchronous completion.
+///
+typedef struct _cef_completion_callback_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Method that will be called once the task is complete.
+ ///
+ void(CEF_CALLBACK* on_complete)(struct _cef_completion_callback_t* self);
+} cef_completion_callback_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_CALLBACK_CAPI_H_
diff --git a/include/capi/cef_client_capi.h b/include/capi/cef_client_capi.h
new file mode 100644
index 00000000..e85a33b3
--- /dev/null
+++ b/include/capi/cef_client_capi.h
@@ -0,0 +1,210 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=eb9dcb574252483dfab12834af93ba14138d4089$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_CLIENT_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_CLIENT_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_audio_handler_capi.h"
+#include "include/capi/cef_base_capi.h"
+#include "include/capi/cef_command_handler_capi.h"
+#include "include/capi/cef_context_menu_handler_capi.h"
+#include "include/capi/cef_dialog_handler_capi.h"
+#include "include/capi/cef_display_handler_capi.h"
+#include "include/capi/cef_download_handler_capi.h"
+#include "include/capi/cef_drag_handler_capi.h"
+#include "include/capi/cef_find_handler_capi.h"
+#include "include/capi/cef_focus_handler_capi.h"
+#include "include/capi/cef_frame_handler_capi.h"
+#include "include/capi/cef_jsdialog_handler_capi.h"
+#include "include/capi/cef_keyboard_handler_capi.h"
+#include "include/capi/cef_life_span_handler_capi.h"
+#include "include/capi/cef_load_handler_capi.h"
+#include "include/capi/cef_permission_handler_capi.h"
+#include "include/capi/cef_print_handler_capi.h"
+#include "include/capi/cef_process_message_capi.h"
+#include "include/capi/cef_render_handler_capi.h"
+#include "include/capi/cef_request_handler_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Implement this structure to provide handler implementations.
+///
+typedef struct _cef_client_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Return the handler for audio rendering events.
+ ///
+ struct _cef_audio_handler_t*(CEF_CALLBACK* get_audio_handler)(
+ struct _cef_client_t* self);
+
+ ///
+ /// Return the handler for commands. If no handler is provided the default
+ /// implementation will be used.
+ ///
+ struct _cef_command_handler_t*(CEF_CALLBACK* get_command_handler)(
+ struct _cef_client_t* self);
+
+ ///
+ /// Return the handler for context menus. If no handler is provided the
+ /// default implementation will be used.
+ ///
+ struct _cef_context_menu_handler_t*(CEF_CALLBACK* get_context_menu_handler)(
+ struct _cef_client_t* self);
+
+ ///
+ /// Return the handler for dialogs. If no handler is provided the default
+ /// implementation will be used.
+ ///
+ struct _cef_dialog_handler_t*(CEF_CALLBACK* get_dialog_handler)(
+ struct _cef_client_t* self);
+
+ ///
+ /// Return the handler for browser display state events.
+ ///
+ struct _cef_display_handler_t*(CEF_CALLBACK* get_display_handler)(
+ struct _cef_client_t* self);
+
+ ///
+ /// Return the handler for download events. If no handler is returned
+ /// downloads will not be allowed.
+ ///
+ struct _cef_download_handler_t*(CEF_CALLBACK* get_download_handler)(
+ struct _cef_client_t* self);
+
+ ///
+ /// Return the handler for drag events.
+ ///
+ struct _cef_drag_handler_t*(CEF_CALLBACK* get_drag_handler)(
+ struct _cef_client_t* self);
+
+ ///
+ /// Return the handler for find result events.
+ ///
+ struct _cef_find_handler_t*(CEF_CALLBACK* get_find_handler)(
+ struct _cef_client_t* self);
+
+ ///
+ /// Return the handler for focus events.
+ ///
+ struct _cef_focus_handler_t*(CEF_CALLBACK* get_focus_handler)(
+ struct _cef_client_t* self);
+
+ ///
+ /// Return the handler for events related to cef_frame_t lifespan. This
+ /// function will be called once during cef_browser_t creation and the result
+ /// will be cached for performance reasons.
+ ///
+ struct _cef_frame_handler_t*(CEF_CALLBACK* get_frame_handler)(
+ struct _cef_client_t* self);
+
+ ///
+ /// Return the handler for permission requests.
+ ///
+ struct _cef_permission_handler_t*(CEF_CALLBACK* get_permission_handler)(
+ struct _cef_client_t* self);
+
+ ///
+ /// Return the handler for JavaScript dialogs. If no handler is provided the
+ /// default implementation will be used.
+ ///
+ struct _cef_jsdialog_handler_t*(CEF_CALLBACK* get_jsdialog_handler)(
+ struct _cef_client_t* self);
+
+ ///
+ /// Return the handler for keyboard events.
+ ///
+ struct _cef_keyboard_handler_t*(CEF_CALLBACK* get_keyboard_handler)(
+ struct _cef_client_t* self);
+
+ ///
+ /// Return the handler for browser life span events.
+ ///
+ struct _cef_life_span_handler_t*(CEF_CALLBACK* get_life_span_handler)(
+ struct _cef_client_t* self);
+
+ ///
+ /// Return the handler for browser load status events.
+ ///
+ struct _cef_load_handler_t*(CEF_CALLBACK* get_load_handler)(
+ struct _cef_client_t* self);
+
+ ///
+ /// Return the handler for printing on Linux. If a print handler is not
+ /// provided then printing will not be supported on the Linux platform.
+ ///
+ struct _cef_print_handler_t*(CEF_CALLBACK* get_print_handler)(
+ struct _cef_client_t* self);
+
+ ///
+ /// Return the handler for off-screen rendering events.
+ ///
+ struct _cef_render_handler_t*(CEF_CALLBACK* get_render_handler)(
+ struct _cef_client_t* self);
+
+ ///
+ /// Return the handler for browser request events.
+ ///
+ struct _cef_request_handler_t*(CEF_CALLBACK* get_request_handler)(
+ struct _cef_client_t* self);
+
+ ///
+ /// Called when a new message is received from a different process. Return
+ /// true (1) if the message was handled or false (0) otherwise. It is safe to
+ /// keep a reference to |message| outside of this callback.
+ ///
+ int(CEF_CALLBACK* on_process_message_received)(
+ struct _cef_client_t* self,
+ struct _cef_browser_t* browser,
+ struct _cef_frame_t* frame,
+ cef_process_id_t source_process,
+ struct _cef_process_message_t* message);
+} cef_client_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_CLIENT_CAPI_H_
diff --git a/include/capi/cef_command_handler_capi.h b/include/capi/cef_command_handler_capi.h
new file mode 100644
index 00000000..862bff67
--- /dev/null
+++ b/include/capi/cef_command_handler_capi.h
@@ -0,0 +1,80 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=46817ef557307a55a9b7138134c4f5c32562f2d7$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_COMMAND_HANDLER_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_COMMAND_HANDLER_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+#include "include/capi/cef_browser_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Implement this structure to handle events related to commands. The functions
+/// of this structure will be called on the UI thread.
+///
+typedef struct _cef_command_handler_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Called to execute a Chrome command triggered via menu selection or
+ /// keyboard shortcut. Values for |command_id| can be found in the
+ /// cef_command_ids.h file. |disposition| provides information about the
+ /// intended command target. Return true (1) if the command was handled or
+ /// false (0) for the default implementation. For context menu commands this
+ /// will be called after cef_context_menu_handler_t::OnContextMenuCommand.
+ /// Only used with the Chrome runtime.
+ ///
+ int(CEF_CALLBACK* on_chrome_command)(
+ struct _cef_command_handler_t* self,
+ struct _cef_browser_t* browser,
+ int command_id,
+ cef_window_open_disposition_t disposition);
+} cef_command_handler_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_COMMAND_HANDLER_CAPI_H_
diff --git a/include/capi/cef_command_line_capi.h b/include/capi/cef_command_line_capi.h
new file mode 100644
index 00000000..3379baa3
--- /dev/null
+++ b/include/capi/cef_command_line_capi.h
@@ -0,0 +1,215 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=ac8fd3a7da20cff1fe2f20a75b045bf27c0312f2$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_COMMAND_LINE_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_COMMAND_LINE_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Structure used to create and/or parse command line arguments. Arguments with
+/// "--", "-" and, on Windows, "/" prefixes are considered switches. Switches
+/// will always precede any arguments without switch prefixes. Switches can
+/// optionally have a value specified using the "=" delimiter (e.g.
+/// "-switch=value"). An argument of "--" will terminate switch parsing with all
+/// subsequent tokens, regardless of prefix, being interpreted as non-switch
+/// arguments. Switch names should be lowercase ASCII and will be converted to
+/// such if necessary. Switch values will retain the original case and UTF8
+/// encoding. This structure can be used before cef_initialize() is called.
+///
+typedef struct _cef_command_line_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Returns true (1) if this object is valid. Do not call any other functions
+ /// if this function returns false (0).
+ ///
+ int(CEF_CALLBACK* is_valid)(struct _cef_command_line_t* self);
+
+ ///
+ /// Returns true (1) if the values of this object are read-only. Some APIs may
+ /// expose read-only objects.
+ ///
+ int(CEF_CALLBACK* is_read_only)(struct _cef_command_line_t* self);
+
+ ///
+ /// Returns a writable copy of this object.
+ ///
+ struct _cef_command_line_t*(CEF_CALLBACK* copy)(
+ struct _cef_command_line_t* self);
+
+ ///
+ /// Initialize the command line with the specified |argc| and |argv| values.
+ /// The first argument must be the name of the program. This function is only
+ /// supported on non-Windows platforms.
+ ///
+ void(CEF_CALLBACK* init_from_argv)(struct _cef_command_line_t* self,
+ int argc,
+ const char* const* argv);
+
+ ///
+ /// Initialize the command line with the string returned by calling
+ /// GetCommandLineW(). This function is only supported on Windows.
+ ///
+ void(CEF_CALLBACK* init_from_string)(struct _cef_command_line_t* self,
+ const cef_string_t* command_line);
+
+ ///
+ /// Reset the command-line switches and arguments but leave the program
+ /// component unchanged.
+ ///
+ void(CEF_CALLBACK* reset)(struct _cef_command_line_t* self);
+
+ ///
+ /// Retrieve the original command line string as a vector of strings. The argv
+ /// array: `{ program, [(--|-|/)switch[=value]]*, [--], [argument]* }`
+ ///
+ void(CEF_CALLBACK* get_argv)(struct _cef_command_line_t* self,
+ cef_string_list_t argv);
+
+ ///
+ /// Constructs and returns the represented command line string. Use this
+ /// function cautiously because quoting behavior is unclear.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_command_line_string)(
+ struct _cef_command_line_t* self);
+
+ ///
+ /// Get the program part of the command line string (the first item).
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_program)(
+ struct _cef_command_line_t* self);
+
+ ///
+ /// Set the program part of the command line string (the first item).
+ ///
+ void(CEF_CALLBACK* set_program)(struct _cef_command_line_t* self,
+ const cef_string_t* program);
+
+ ///
+ /// Returns true (1) if the command line has switches.
+ ///
+ int(CEF_CALLBACK* has_switches)(struct _cef_command_line_t* self);
+
+ ///
+ /// Returns true (1) if the command line contains the given switch.
+ ///
+ int(CEF_CALLBACK* has_switch)(struct _cef_command_line_t* self,
+ const cef_string_t* name);
+
+ ///
+ /// Returns the value associated with the given switch. If the switch has no
+ /// value or isn't present this function returns the NULL string.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_switch_value)(
+ struct _cef_command_line_t* self,
+ const cef_string_t* name);
+
+ ///
+ /// Returns the map of switch names and values. If a switch has no value an
+ /// NULL string is returned.
+ ///
+ void(CEF_CALLBACK* get_switches)(struct _cef_command_line_t* self,
+ cef_string_map_t switches);
+
+ ///
+ /// Add a switch to the end of the command line.
+ ///
+ void(CEF_CALLBACK* append_switch)(struct _cef_command_line_t* self,
+ const cef_string_t* name);
+
+ ///
+ /// Add a switch with the specified value to the end of the command line. If
+ /// the switch has no value pass an NULL value string.
+ ///
+ void(CEF_CALLBACK* append_switch_with_value)(struct _cef_command_line_t* self,
+ const cef_string_t* name,
+ const cef_string_t* value);
+
+ ///
+ /// True if there are remaining command line arguments.
+ ///
+ int(CEF_CALLBACK* has_arguments)(struct _cef_command_line_t* self);
+
+ ///
+ /// Get the remaining command line arguments.
+ ///
+ void(CEF_CALLBACK* get_arguments)(struct _cef_command_line_t* self,
+ cef_string_list_t arguments);
+
+ ///
+ /// Add an argument to the end of the command line.
+ ///
+ void(CEF_CALLBACK* append_argument)(struct _cef_command_line_t* self,
+ const cef_string_t* argument);
+
+ ///
+ /// Insert a command before the current command. Common for debuggers, like
+ /// "valgrind" or "gdb --args".
+ ///
+ void(CEF_CALLBACK* prepend_wrapper)(struct _cef_command_line_t* self,
+ const cef_string_t* wrapper);
+} cef_command_line_t;
+
+///
+/// Create a new cef_command_line_t instance.
+///
+CEF_EXPORT cef_command_line_t* cef_command_line_create(void);
+
+///
+/// Returns the singleton global cef_command_line_t object. The returned object
+/// will be read-only.
+///
+CEF_EXPORT cef_command_line_t* cef_command_line_get_global(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_COMMAND_LINE_CAPI_H_
diff --git a/include/capi/cef_context_menu_handler_capi.h b/include/capi/cef_context_menu_handler_capi.h
new file mode 100644
index 00000000..bc273334
--- /dev/null
+++ b/include/capi/cef_context_menu_handler_capi.h
@@ -0,0 +1,367 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=c82f41d81f5afa5ed6995693e012c13d2a609f88$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_CONTEXT_MENU_HANDLER_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_CONTEXT_MENU_HANDLER_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+#include "include/capi/cef_browser_capi.h"
+#include "include/capi/cef_frame_capi.h"
+#include "include/capi/cef_menu_model_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _cef_context_menu_params_t;
+
+///
+/// Callback structure used for continuation of custom context menu display.
+///
+typedef struct _cef_run_context_menu_callback_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Complete context menu display by selecting the specified |command_id| and
+ /// |event_flags|.
+ ///
+ void(CEF_CALLBACK* cont)(struct _cef_run_context_menu_callback_t* self,
+ int command_id,
+ cef_event_flags_t event_flags);
+
+ ///
+ /// Cancel context menu display.
+ ///
+ void(CEF_CALLBACK* cancel)(struct _cef_run_context_menu_callback_t* self);
+} cef_run_context_menu_callback_t;
+
+///
+/// Callback structure used for continuation of custom quick menu display.
+///
+typedef struct _cef_run_quick_menu_callback_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Complete quick menu display by selecting the specified |command_id| and
+ /// |event_flags|.
+ ///
+ void(CEF_CALLBACK* cont)(struct _cef_run_quick_menu_callback_t* self,
+ int command_id,
+ cef_event_flags_t event_flags);
+
+ ///
+ /// Cancel quick menu display.
+ ///
+ void(CEF_CALLBACK* cancel)(struct _cef_run_quick_menu_callback_t* self);
+} cef_run_quick_menu_callback_t;
+
+///
+/// Implement this structure to handle context menu events. The functions of
+/// this structure will be called on the UI thread.
+///
+typedef struct _cef_context_menu_handler_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Called before a context menu is displayed. |params| provides information
+ /// about the context menu state. |model| initially contains the default
+ /// context menu. The |model| can be cleared to show no context menu or
+ /// modified to show a custom menu. Do not keep references to |params| or
+ /// |model| outside of this callback.
+ ///
+ void(CEF_CALLBACK* on_before_context_menu)(
+ struct _cef_context_menu_handler_t* self,
+ struct _cef_browser_t* browser,
+ struct _cef_frame_t* frame,
+ struct _cef_context_menu_params_t* params,
+ struct _cef_menu_model_t* model);
+
+ ///
+ /// Called to allow custom display of the context menu. |params| provides
+ /// information about the context menu state. |model| contains the context
+ /// menu model resulting from OnBeforeContextMenu. For custom display return
+ /// true (1) and execute |callback| either synchronously or asynchronously
+ /// with the selected command ID. For default display return false (0). Do not
+ /// keep references to |params| or |model| outside of this callback.
+ ///
+ int(CEF_CALLBACK* run_context_menu)(
+ struct _cef_context_menu_handler_t* self,
+ struct _cef_browser_t* browser,
+ struct _cef_frame_t* frame,
+ struct _cef_context_menu_params_t* params,
+ struct _cef_menu_model_t* model,
+ struct _cef_run_context_menu_callback_t* callback);
+
+ ///
+ /// Called to execute a command selected from the context menu. Return true
+ /// (1) if the command was handled or false (0) for the default
+ /// implementation. See cef_menu_id_t for the command ids that have default
+ /// implementations. All user-defined command ids should be between
+ /// MENU_ID_USER_FIRST and MENU_ID_USER_LAST. |params| will have the same
+ /// values as what was passed to on_before_context_menu(). Do not keep a
+ /// reference to |params| outside of this callback.
+ ///
+ int(CEF_CALLBACK* on_context_menu_command)(
+ struct _cef_context_menu_handler_t* self,
+ struct _cef_browser_t* browser,
+ struct _cef_frame_t* frame,
+ struct _cef_context_menu_params_t* params,
+ int command_id,
+ cef_event_flags_t event_flags);
+
+ ///
+ /// Called when the context menu is dismissed irregardless of whether the menu
+ /// was canceled or a command was selected.
+ ///
+ void(CEF_CALLBACK* on_context_menu_dismissed)(
+ struct _cef_context_menu_handler_t* self,
+ struct _cef_browser_t* browser,
+ struct _cef_frame_t* frame);
+
+ ///
+ /// Called to allow custom display of the quick menu for a windowless browser.
+ /// |location| is the top left corner of the selected region. |size| is the
+ /// size of the selected region. |edit_state_flags| is a combination of flags
+ /// that represent the state of the quick menu. Return true (1) if the menu
+ /// will be handled and execute |callback| either synchronously or
+ /// asynchronously with the selected command ID. Return false (0) to cancel
+ /// the menu.
+ ///
+ int(CEF_CALLBACK* run_quick_menu)(
+ struct _cef_context_menu_handler_t* self,
+ struct _cef_browser_t* browser,
+ struct _cef_frame_t* frame,
+ const cef_point_t* location,
+ const cef_size_t* size,
+ cef_quick_menu_edit_state_flags_t edit_state_flags,
+ struct _cef_run_quick_menu_callback_t* callback);
+
+ ///
+ /// Called to execute a command selected from the quick menu for a windowless
+ /// browser. Return true (1) if the command was handled or false (0) for the
+ /// default implementation. See cef_menu_id_t for command IDs that have
+ /// default implementations.
+ ///
+ int(CEF_CALLBACK* on_quick_menu_command)(
+ struct _cef_context_menu_handler_t* self,
+ struct _cef_browser_t* browser,
+ struct _cef_frame_t* frame,
+ int command_id,
+ cef_event_flags_t event_flags);
+
+ ///
+ /// Called when the quick menu for a windowless browser is dismissed
+ /// irregardless of whether the menu was canceled or a command was selected.
+ ///
+ void(CEF_CALLBACK* on_quick_menu_dismissed)(
+ struct _cef_context_menu_handler_t* self,
+ struct _cef_browser_t* browser,
+ struct _cef_frame_t* frame);
+} cef_context_menu_handler_t;
+
+///
+/// Provides information about the context menu state. The functions of this
+/// structure can only be accessed on browser process the UI thread.
+///
+typedef struct _cef_context_menu_params_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Returns the X coordinate of the mouse where the context menu was invoked.
+ /// Coords are relative to the associated RenderView's origin.
+ ///
+ int(CEF_CALLBACK* get_xcoord)(struct _cef_context_menu_params_t* self);
+
+ ///
+ /// Returns the Y coordinate of the mouse where the context menu was invoked.
+ /// Coords are relative to the associated RenderView's origin.
+ ///
+ int(CEF_CALLBACK* get_ycoord)(struct _cef_context_menu_params_t* self);
+
+ ///
+ /// Returns flags representing the type of node that the context menu was
+ /// invoked on.
+ ///
+ cef_context_menu_type_flags_t(CEF_CALLBACK* get_type_flags)(
+ struct _cef_context_menu_params_t* self);
+
+ ///
+ /// Returns the URL of the link, if any, that encloses the node that the
+ /// context menu was invoked on.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_link_url)(
+ struct _cef_context_menu_params_t* self);
+
+ ///
+ /// Returns the link URL, if any, to be used ONLY for "copy link address". We
+ /// don't validate this field in the frontend process.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_unfiltered_link_url)(
+ struct _cef_context_menu_params_t* self);
+
+ ///
+ /// Returns the source URL, if any, for the element that the context menu was
+ /// invoked on. Example of elements with source URLs are img, audio, and
+ /// video.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_source_url)(
+ struct _cef_context_menu_params_t* self);
+
+ ///
+ /// Returns true (1) if the context menu was invoked on an image which has
+ /// non-NULL contents.
+ ///
+ int(CEF_CALLBACK* has_image_contents)(
+ struct _cef_context_menu_params_t* self);
+
+ ///
+ /// Returns the title text or the alt text if the context menu was invoked on
+ /// an image.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_title_text)(
+ struct _cef_context_menu_params_t* self);
+
+ ///
+ /// Returns the URL of the top level page that the context menu was invoked
+ /// on.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_page_url)(
+ struct _cef_context_menu_params_t* self);
+
+ ///
+ /// Returns the URL of the subframe that the context menu was invoked on.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_frame_url)(
+ struct _cef_context_menu_params_t* self);
+
+ ///
+ /// Returns the character encoding of the subframe that the context menu was
+ /// invoked on.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_frame_charset)(
+ struct _cef_context_menu_params_t* self);
+
+ ///
+ /// Returns the type of context node that the context menu was invoked on.
+ ///
+ cef_context_menu_media_type_t(CEF_CALLBACK* get_media_type)(
+ struct _cef_context_menu_params_t* self);
+
+ ///
+ /// Returns flags representing the actions supported by the media element, if
+ /// any, that the context menu was invoked on.
+ ///
+ cef_context_menu_media_state_flags_t(CEF_CALLBACK* get_media_state_flags)(
+ struct _cef_context_menu_params_t* self);
+
+ ///
+ /// Returns the text of the selection, if any, that the context menu was
+ /// invoked on.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_selection_text)(
+ struct _cef_context_menu_params_t* self);
+
+ ///
+ /// Returns the text of the misspelled word, if any, that the context menu was
+ /// invoked on.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_misspelled_word)(
+ struct _cef_context_menu_params_t* self);
+
+ ///
+ /// Returns true (1) if suggestions exist, false (0) otherwise. Fills in
+ /// |suggestions| from the spell check service for the misspelled word if
+ /// there is one.
+ ///
+ int(CEF_CALLBACK* get_dictionary_suggestions)(
+ struct _cef_context_menu_params_t* self,
+ cef_string_list_t suggestions);
+
+ ///
+ /// Returns true (1) if the context menu was invoked on an editable node.
+ ///
+ int(CEF_CALLBACK* is_editable)(struct _cef_context_menu_params_t* self);
+
+ ///
+ /// Returns true (1) if the context menu was invoked on an editable node where
+ /// spell-check is enabled.
+ ///
+ int(CEF_CALLBACK* is_spell_check_enabled)(
+ struct _cef_context_menu_params_t* self);
+
+ ///
+ /// Returns flags representing the actions supported by the editable node, if
+ /// any, that the context menu was invoked on.
+ ///
+ cef_context_menu_edit_state_flags_t(CEF_CALLBACK* get_edit_state_flags)(
+ struct _cef_context_menu_params_t* self);
+
+ ///
+ /// Returns true (1) if the context menu contains items specified by the
+ /// renderer process.
+ ///
+ int(CEF_CALLBACK* is_custom_menu)(struct _cef_context_menu_params_t* self);
+} cef_context_menu_params_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_CONTEXT_MENU_HANDLER_CAPI_H_
diff --git a/include/capi/cef_cookie_capi.h b/include/capi/cef_cookie_capi.h
new file mode 100644
index 00000000..1be978bf
--- /dev/null
+++ b/include/capi/cef_cookie_capi.h
@@ -0,0 +1,199 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=598c6f530b2e2553197d8c6a72ad9e2bf72b5443$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_COOKIE_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_COOKIE_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+#include "include/capi/cef_callback_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _cef_cookie_visitor_t;
+struct _cef_delete_cookies_callback_t;
+struct _cef_set_cookie_callback_t;
+
+///
+/// Structure used for managing cookies. The functions of this structure may be
+/// called on any thread unless otherwise indicated.
+///
+typedef struct _cef_cookie_manager_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Visit all cookies on the UI thread. The returned cookies are ordered by
+ /// longest path, then by earliest creation date. Returns false (0) if cookies
+ /// cannot be accessed.
+ ///
+ int(CEF_CALLBACK* visit_all_cookies)(struct _cef_cookie_manager_t* self,
+ struct _cef_cookie_visitor_t* visitor);
+
+ ///
+ /// Visit a subset of cookies on the UI thread. The results are filtered by
+ /// the given url scheme, host, domain and path. If |includeHttpOnly| is true
+ /// (1) HTTP-only cookies will also be included in the results. The returned
+ /// cookies are ordered by longest path, then by earliest creation date.
+ /// Returns false (0) if cookies cannot be accessed.
+ ///
+ int(CEF_CALLBACK* visit_url_cookies)(struct _cef_cookie_manager_t* self,
+ const cef_string_t* url,
+ int includeHttpOnly,
+ struct _cef_cookie_visitor_t* visitor);
+
+ ///
+ /// Sets a cookie given a valid URL and explicit user-provided cookie
+ /// attributes. This function expects each attribute to be well-formed. It
+ /// will check for disallowed characters (e.g. the ';' character is disallowed
+ /// within the cookie value attribute) and fail without setting the cookie if
+ /// such characters are found. If |callback| is non-NULL it will be executed
+ /// asnychronously on the UI thread after the cookie has been set. Returns
+ /// false (0) if an invalid URL is specified or if cookies cannot be accessed.
+ ///
+ int(CEF_CALLBACK* set_cookie)(struct _cef_cookie_manager_t* self,
+ const cef_string_t* url,
+ const struct _cef_cookie_t* cookie,
+ struct _cef_set_cookie_callback_t* callback);
+
+ ///
+ /// Delete all cookies that match the specified parameters. If both |url| and
+ /// |cookie_name| values are specified all host and domain cookies matching
+ /// both will be deleted. If only |url| is specified all host cookies (but not
+ /// domain cookies) irrespective of path will be deleted. If |url| is NULL all
+ /// cookies for all hosts and domains will be deleted. If |callback| is non-
+ /// NULL it will be executed asnychronously on the UI thread after the cookies
+ /// have been deleted. Returns false (0) if a non-NULL invalid URL is
+ /// specified or if cookies cannot be accessed. Cookies can alternately be
+ /// deleted using the Visit*Cookies() functions.
+ ///
+ int(CEF_CALLBACK* delete_cookies)(
+ struct _cef_cookie_manager_t* self,
+ const cef_string_t* url,
+ const cef_string_t* cookie_name,
+ struct _cef_delete_cookies_callback_t* callback);
+
+ ///
+ /// Flush the backing store (if any) to disk. If |callback| is non-NULL it
+ /// will be executed asnychronously on the UI thread after the flush is
+ /// complete. Returns false (0) if cookies cannot be accessed.
+ ///
+ int(CEF_CALLBACK* flush_store)(struct _cef_cookie_manager_t* self,
+ struct _cef_completion_callback_t* callback);
+} cef_cookie_manager_t;
+
+///
+/// Returns the global cookie manager. By default data will be stored at
+/// cef_settings_t.cache_path if specified or in memory otherwise. If |callback|
+/// is non-NULL it will be executed asnychronously on the UI thread after the
+/// manager's storage has been initialized. Using this function is equivalent to
+/// calling cef_request_context_t::cef_request_context_get_global_context()->Get
+/// DefaultCookieManager().
+///
+CEF_EXPORT cef_cookie_manager_t* cef_cookie_manager_get_global_manager(
+ struct _cef_completion_callback_t* callback);
+
+///
+/// Structure to implement for visiting cookie values. The functions of this
+/// structure will always be called on the UI thread.
+///
+typedef struct _cef_cookie_visitor_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Method that will be called once for each cookie. |count| is the 0-based
+ /// index for the current cookie. |total| is the total number of cookies. Set
+ /// |deleteCookie| to true (1) to delete the cookie currently being visited.
+ /// Return false (0) to stop visiting cookies. This function may never be
+ /// called if no cookies are found.
+ ///
+ int(CEF_CALLBACK* visit)(struct _cef_cookie_visitor_t* self,
+ const struct _cef_cookie_t* cookie,
+ int count,
+ int total,
+ int* deleteCookie);
+} cef_cookie_visitor_t;
+
+///
+/// Structure to implement to be notified of asynchronous completion via
+/// cef_cookie_manager_t::set_cookie().
+///
+typedef struct _cef_set_cookie_callback_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Method that will be called upon completion. |success| will be true (1) if
+ /// the cookie was set successfully.
+ ///
+ void(CEF_CALLBACK* on_complete)(struct _cef_set_cookie_callback_t* self,
+ int success);
+} cef_set_cookie_callback_t;
+
+///
+/// Structure to implement to be notified of asynchronous completion via
+/// cef_cookie_manager_t::delete_cookies().
+///
+typedef struct _cef_delete_cookies_callback_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Method that will be called upon completion. |num_deleted| will be the
+ /// number of cookies that were deleted.
+ ///
+ void(CEF_CALLBACK* on_complete)(struct _cef_delete_cookies_callback_t* self,
+ int num_deleted);
+} cef_delete_cookies_callback_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_COOKIE_CAPI_H_
diff --git a/include/capi/cef_crash_util_capi.h b/include/capi/cef_crash_util_capi.h
new file mode 100644
index 00000000..f6272ab0
--- /dev/null
+++ b/include/capi/cef_crash_util_capi.h
@@ -0,0 +1,154 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=5c6e0b9e37b8103a182f200fccdf5973104fcd70$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_CRASH_UTIL_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_CRASH_UTIL_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Crash reporting is configured using an INI-style config file named
+/// "crash_reporter.cfg". On Windows and Linux this file must be placed next to
+/// the main application executable. On macOS this file must be placed in the
+/// top-level app bundle Resources directory (e.g.
+/// "<appname>.app/Contents/Resources"). File contents are as follows:
+///
+/// <pre>
+/// # Comments start with a hash character and must be on their own line.
+///
+/// [Config]
+/// ProductName=<Value of the "prod" crash key; defaults to "cef">
+/// ProductVersion=<Value of the "ver" crash key; defaults to the CEF version>
+/// AppName=<Windows only; App-specific folder name component for storing crash
+/// information; default to "CEF">
+/// ExternalHandler=<Windows only; Name of the external handler exe to use
+/// instead of re-launching the main exe; default to empty>
+/// BrowserCrashForwardingEnabled=<macOS only; True if browser process crashes
+/// should be forwarded to the system crash
+/// reporter; default to false>
+/// ServerURL=<crash server URL; default to empty>
+/// RateLimitEnabled=<True if uploads should be rate limited; default to true>
+/// MaxUploadsPerDay=<Max uploads per 24 hours, used if rate limit is enabled;
+/// default to 5>
+/// MaxDatabaseSizeInMb=<Total crash report disk usage greater than this value
+/// will cause older reports to be deleted; default to 20>
+/// MaxDatabaseAgeInDays=<Crash reports older than this value will be deleted;
+/// default to 5>
+///
+/// [CrashKeys]
+/// my_key1=<small|medium|large>
+/// my_key2=<small|medium|large>
+/// </pre>
+///
+/// <b>Config section:</b>
+///
+/// If "ProductName" and/or "ProductVersion" are set then the specified values
+/// will be included in the crash dump metadata. On macOS if these values are
+/// set to NULL then they will be retrieved from the Info.plist file using the
+/// "CFBundleName" and "CFBundleShortVersionString" keys respectively.
+///
+/// If "AppName" is set on Windows then crash report information (metrics,
+/// database and dumps) will be stored locally on disk under the
+/// "C:\Users\[CurrentUser]\AppData\Local\[AppName]\User Data" folder. On other
+/// platforms the cef_settings_t.user_data_path value will be used.
+///
+/// If "ExternalHandler" is set on Windows then the specified exe will be
+/// launched as the crashpad-handler instead of re-launching the main process
+/// exe. The value can be an absolute path or a path relative to the main exe
+/// directory. On Linux the cef_settings_t.browser_subprocess_path value will be
+/// used. On macOS the existing subprocess app bundle will be used.
+///
+/// If "BrowserCrashForwardingEnabled" is set to true (1) on macOS then browser
+/// process crashes will be forwarded to the system crash reporter. This results
+/// in the crash UI dialog being displayed to the user and crash reports being
+/// logged under "~/Library/Logs/DiagnosticReports". Forwarding of crash reports
+/// from non-browser processes and Debug builds is always disabled.
+///
+/// If "ServerURL" is set then crashes will be uploaded as a multi-part POST
+/// request to the specified URL. Otherwise, reports will only be stored locally
+/// on disk.
+///
+/// If "RateLimitEnabled" is set to true (1) then crash report uploads will be
+/// rate limited as follows:
+/// 1. If "MaxUploadsPerDay" is set to a positive value then at most the
+/// specified number of crashes will be uploaded in each 24 hour period.
+/// 2. If crash upload fails due to a network or server error then an
+/// incremental backoff delay up to a maximum of 24 hours will be applied
+/// for retries.
+/// 3. If a backoff delay is applied and "MaxUploadsPerDay" is > 1 then the
+/// "MaxUploadsPerDay" value will be reduced to 1 until the client is
+/// restarted. This helps to avoid an upload flood when the network or
+/// server error is resolved.
+/// Rate limiting is not supported on Linux.
+///
+/// If "MaxDatabaseSizeInMb" is set to a positive value then crash report
+/// storage on disk will be limited to that size in megabytes. For example, on
+/// Windows each dump is about 600KB so a "MaxDatabaseSizeInMb" value of 20
+/// equates to about 34 crash reports stored on disk. Not supported on Linux.
+///
+/// If "MaxDatabaseAgeInDays" is set to a positive value then crash reports
+/// older than the specified age in days will be deleted. Not supported on
+/// Linux.
+///
+/// <b>CrashKeys section:</b>
+///
+/// A maximum of 26 crash keys of each size can be specified for use by the
+/// application. Crash key values will be truncated based on the specified size
+/// (small = 64 bytes, medium = 256 bytes, large = 1024 bytes). The value of
+/// crash keys can be set from any thread or process using the
+/// CefSetCrashKeyValue function. These key/value pairs will be sent to the
+/// crash server along with the crash dump file.
+///
+CEF_EXPORT int cef_crash_reporting_enabled(void);
+
+///
+/// Sets or clears a specific key-value pair from the crash metadata.
+///
+CEF_EXPORT void cef_set_crash_key_value(const cef_string_t* key,
+ const cef_string_t* value);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_CRASH_UTIL_CAPI_H_
diff --git a/include/capi/cef_devtools_message_observer_capi.h b/include/capi/cef_devtools_message_observer_capi.h
new file mode 100644
index 00000000..ee61835f
--- /dev/null
+++ b/include/capi/cef_devtools_message_observer_capi.h
@@ -0,0 +1,148 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=777485120b9a9df0f890579ee698d33f273819c5$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_DEVTOOLS_MESSAGE_OBSERVER_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_DEVTOOLS_MESSAGE_OBSERVER_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _cef_browser_t;
+
+///
+/// Callback structure for cef_browser_host_t::AddDevToolsMessageObserver. The
+/// functions of this structure will be called on the browser process UI thread.
+///
+typedef struct _cef_dev_tools_message_observer_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Method that will be called on receipt of a DevTools protocol message.
+ /// |browser| is the originating browser instance. |message| is a UTF8-encoded
+ /// JSON dictionary representing either a function result or an event.
+ /// |message| is only valid for the scope of this callback and should be
+ /// copied if necessary. Return true (1) if the message was handled or false
+ /// (0) if the message should be further processed and passed to the
+ /// OnDevToolsMethodResult or OnDevToolsEvent functions as appropriate.
+ ///
+ /// Method result dictionaries include an "id" (int) value that identifies the
+ /// orginating function call sent from
+ /// cef_browser_host_t::SendDevToolsMessage, and optionally either a "result"
+ /// (dictionary) or "error" (dictionary) value. The "error" dictionary will
+ /// contain "code" (int) and "message" (string) values. Event dictionaries
+ /// include a "function" (string) value and optionally a "params" (dictionary)
+ /// value. See the DevTools protocol documentation at
+ /// https://chromedevtools.github.io/devtools-protocol/ for details of
+ /// supported function calls and the expected "result" or "params" dictionary
+ /// contents. JSON dictionaries can be parsed using the CefParseJSON function
+ /// if desired, however be aware of performance considerations when parsing
+ /// large messages (some of which may exceed 1MB in size).
+ ///
+ int(CEF_CALLBACK* on_dev_tools_message)(
+ struct _cef_dev_tools_message_observer_t* self,
+ struct _cef_browser_t* browser,
+ const void* message,
+ size_t message_size);
+
+ ///
+ /// Method that will be called after attempted execution of a DevTools
+ /// protocol function. |browser| is the originating browser instance.
+ /// |message_id| is the "id" value that identifies the originating function
+ /// call message. If the function succeeded |success| will be true (1) and
+ /// |result| will be the UTF8-encoded JSON "result" dictionary value (which
+ /// may be NULL). If the function failed |success| will be false (0) and
+ /// |result| will be the UTF8-encoded JSON "error" dictionary value. |result|
+ /// is only valid for the scope of this callback and should be copied if
+ /// necessary. See the OnDevToolsMessage documentation for additional details
+ /// on |result| contents.
+ ///
+ void(CEF_CALLBACK* on_dev_tools_method_result)(
+ struct _cef_dev_tools_message_observer_t* self,
+ struct _cef_browser_t* browser,
+ int message_id,
+ int success,
+ const void* result,
+ size_t result_size);
+
+ ///
+ /// Method that will be called on receipt of a DevTools protocol event.
+ /// |browser| is the originating browser instance. |function| is the
+ /// "function" value. |params| is the UTF8-encoded JSON "params" dictionary
+ /// value (which may be NULL). |params| is only valid for the scope of this
+ /// callback and should be copied if necessary. See the OnDevToolsMessage
+ /// documentation for additional details on |params| contents.
+ ///
+ void(CEF_CALLBACK* on_dev_tools_event)(
+ struct _cef_dev_tools_message_observer_t* self,
+ struct _cef_browser_t* browser,
+ const cef_string_t* method,
+ const void* params,
+ size_t params_size);
+
+ ///
+ /// Method that will be called when the DevTools agent has attached. |browser|
+ /// is the originating browser instance. This will generally occur in response
+ /// to the first message sent while the agent is detached.
+ ///
+ void(CEF_CALLBACK* on_dev_tools_agent_attached)(
+ struct _cef_dev_tools_message_observer_t* self,
+ struct _cef_browser_t* browser);
+
+ ///
+ /// Method that will be called when the DevTools agent has detached. |browser|
+ /// is the originating browser instance. Any function results that were
+ /// pending before the agent became detached will not be delivered, and any
+ /// active event subscriptions will be canceled.
+ ///
+ void(CEF_CALLBACK* on_dev_tools_agent_detached)(
+ struct _cef_dev_tools_message_observer_t* self,
+ struct _cef_browser_t* browser);
+} cef_dev_tools_message_observer_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_DEVTOOLS_MESSAGE_OBSERVER_CAPI_H_
diff --git a/include/capi/cef_dialog_handler_capi.h b/include/capi/cef_dialog_handler_capi.h
new file mode 100644
index 00000000..82281ad9
--- /dev/null
+++ b/include/capi/cef_dialog_handler_capi.h
@@ -0,0 +1,111 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=69545645f079f4593d9cbb6d8a36535c209245f7$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_DIALOG_HANDLER_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_DIALOG_HANDLER_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+#include "include/capi/cef_browser_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Callback structure for asynchronous continuation of file dialog requests.
+///
+typedef struct _cef_file_dialog_callback_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Continue the file selection. |file_paths| should be a single value or a
+ /// list of values depending on the dialog mode. An NULL |file_paths| value is
+ /// treated the same as calling cancel().
+ ///
+ void(CEF_CALLBACK* cont)(struct _cef_file_dialog_callback_t* self,
+ cef_string_list_t file_paths);
+
+ ///
+ /// Cancel the file selection.
+ ///
+ void(CEF_CALLBACK* cancel)(struct _cef_file_dialog_callback_t* self);
+} cef_file_dialog_callback_t;
+
+///
+/// Implement this structure to handle dialog events. The functions of this
+/// structure will be called on the browser process UI thread.
+///
+typedef struct _cef_dialog_handler_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Called to run a file chooser dialog. |mode| represents the type of dialog
+ /// to display. |title| to the title to be used for the dialog and may be NULL
+ /// to show the default title ("Open" or "Save" depending on the mode).
+ /// |default_file_path| is the path with optional directory and/or file name
+ /// component that should be initially selected in the dialog.
+ /// |accept_filters| are used to restrict the selectable file types and may
+ /// any combination of (a) valid lower-cased MIME types (e.g. "text/*" or
+ /// "image/*"), (b) individual file extensions (e.g. ".txt" or ".png"), or (c)
+ /// combined description and file extension delimited using "|" and ";" (e.g.
+ /// "Image Types|.png;.gif;.jpg"). To display a custom dialog return true (1)
+ /// and execute |callback| either inline or at a later time. To display the
+ /// default dialog return false (0).
+ ///
+ int(CEF_CALLBACK* on_file_dialog)(
+ struct _cef_dialog_handler_t* self,
+ struct _cef_browser_t* browser,
+ cef_file_dialog_mode_t mode,
+ const cef_string_t* title,
+ const cef_string_t* default_file_path,
+ cef_string_list_t accept_filters,
+ struct _cef_file_dialog_callback_t* callback);
+} cef_dialog_handler_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_DIALOG_HANDLER_CAPI_H_
diff --git a/include/capi/cef_display_handler_capi.h b/include/capi/cef_display_handler_capi.h
new file mode 100644
index 00000000..b93421de
--- /dev/null
+++ b/include/capi/cef_display_handler_capi.h
@@ -0,0 +1,173 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=1de3354bd0a042cc28199f1f56753b1df9e279a2$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_DISPLAY_HANDLER_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_DISPLAY_HANDLER_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+#include "include/capi/cef_browser_capi.h"
+#include "include/capi/cef_frame_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Implement this structure to handle events related to browser display state.
+/// The functions of this structure will be called on the UI thread.
+///
+typedef struct _cef_display_handler_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Called when a frame's address has changed.
+ ///
+ void(CEF_CALLBACK* on_address_change)(struct _cef_display_handler_t* self,
+ struct _cef_browser_t* browser,
+ struct _cef_frame_t* frame,
+ const cef_string_t* url);
+
+ ///
+ /// Called when the page title changes.
+ ///
+ void(CEF_CALLBACK* on_title_change)(struct _cef_display_handler_t* self,
+ struct _cef_browser_t* browser,
+ const cef_string_t* title);
+
+ ///
+ /// Called when the page icon changes.
+ ///
+ void(CEF_CALLBACK* on_favicon_urlchange)(struct _cef_display_handler_t* self,
+ struct _cef_browser_t* browser,
+ cef_string_list_t icon_urls);
+
+ ///
+ /// Called when web content in the page has toggled fullscreen mode. If
+ /// |fullscreen| is true (1) the content will automatically be sized to fill
+ /// the browser content area. If |fullscreen| is false (0) the content will
+ /// automatically return to its original size and position. The client is
+ /// responsible for resizing the browser if desired.
+ ///
+ void(CEF_CALLBACK* on_fullscreen_mode_change)(
+ struct _cef_display_handler_t* self,
+ struct _cef_browser_t* browser,
+ int fullscreen);
+
+ ///
+ /// Called when the browser is about to display a tooltip. |text| contains the
+ /// text that will be displayed in the tooltip. To handle the display of the
+ /// tooltip yourself return true (1). Otherwise, you can optionally modify
+ /// |text| and then return false (0) to allow the browser to display the
+ /// tooltip. When window rendering is disabled the application is responsible
+ /// for drawing tooltips and the return value is ignored.
+ ///
+ int(CEF_CALLBACK* on_tooltip)(struct _cef_display_handler_t* self,
+ struct _cef_browser_t* browser,
+ cef_string_t* text);
+
+ ///
+ /// Called when the browser receives a status message. |value| contains the
+ /// text that will be displayed in the status message.
+ ///
+ void(CEF_CALLBACK* on_status_message)(struct _cef_display_handler_t* self,
+ struct _cef_browser_t* browser,
+ const cef_string_t* value);
+
+ ///
+ /// Called to display a console message. Return true (1) to stop the message
+ /// from being output to the console.
+ ///
+ int(CEF_CALLBACK* on_console_message)(struct _cef_display_handler_t* self,
+ struct _cef_browser_t* browser,
+ cef_log_severity_t level,
+ const cef_string_t* message,
+ const cef_string_t* source,
+ int line);
+
+ ///
+ /// Called when auto-resize is enabled via
+ /// cef_browser_host_t::SetAutoResizeEnabled and the contents have auto-
+ /// resized. |new_size| will be the desired size in view coordinates. Return
+ /// true (1) if the resize was handled or false (0) for default handling.
+ ///
+ int(CEF_CALLBACK* on_auto_resize)(struct _cef_display_handler_t* self,
+ struct _cef_browser_t* browser,
+ const cef_size_t* new_size);
+
+ ///
+ /// Called when the overall page loading progress has changed. |progress|
+ /// ranges from 0.0 to 1.0.
+ ///
+ void(CEF_CALLBACK* on_loading_progress_change)(
+ struct _cef_display_handler_t* self,
+ struct _cef_browser_t* browser,
+ double progress);
+
+ ///
+ /// Called when the browser's cursor has changed. If |type| is CT_CUSTOM then
+ /// |custom_cursor_info| will be populated with the custom cursor information.
+ /// Return true (1) if the cursor change was handled or false (0) for default
+ /// handling.
+ ///
+ int(CEF_CALLBACK* on_cursor_change)(
+ struct _cef_display_handler_t* self,
+ struct _cef_browser_t* browser,
+ cef_cursor_handle_t cursor,
+ cef_cursor_type_t type,
+ const cef_cursor_info_t* custom_cursor_info);
+
+ ///
+ /// Called when the browser's access to an audio and/or video source has
+ /// changed.
+ ///
+ void(CEF_CALLBACK* on_media_access_change)(
+ struct _cef_display_handler_t* self,
+ struct _cef_browser_t* browser,
+ int has_video_access,
+ int has_audio_access);
+} cef_display_handler_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_DISPLAY_HANDLER_CAPI_H_
diff --git a/include/capi/cef_dom_capi.h b/include/capi/cef_dom_capi.h
new file mode 100644
index 00000000..c895e3b7
--- /dev/null
+++ b/include/capi/cef_dom_capi.h
@@ -0,0 +1,346 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=d703b8af664ed9dfac8ad935616ef43fafc062e2$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_DOM_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_DOM_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _cef_domdocument_t;
+struct _cef_domnode_t;
+
+///
+/// Structure to implement for visiting the DOM. The functions of this structure
+/// will be called on the render process main thread.
+///
+typedef struct _cef_domvisitor_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Method executed for visiting the DOM. The document object passed to this
+ /// function represents a snapshot of the DOM at the time this function is
+ /// executed. DOM objects are only valid for the scope of this function. Do
+ /// not keep references to or attempt to access any DOM objects outside the
+ /// scope of this function.
+ ///
+ void(CEF_CALLBACK* visit)(struct _cef_domvisitor_t* self,
+ struct _cef_domdocument_t* document);
+} cef_domvisitor_t;
+
+///
+/// Structure used to represent a DOM document. The functions of this structure
+/// should only be called on the render process main thread thread.
+///
+typedef struct _cef_domdocument_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Returns the document type.
+ ///
+ cef_dom_document_type_t(CEF_CALLBACK* get_type)(
+ struct _cef_domdocument_t* self);
+
+ ///
+ /// Returns the root document node.
+ ///
+ struct _cef_domnode_t*(CEF_CALLBACK* get_document)(
+ struct _cef_domdocument_t* self);
+
+ ///
+ /// Returns the BODY node of an HTML document.
+ ///
+ struct _cef_domnode_t*(CEF_CALLBACK* get_body)(
+ struct _cef_domdocument_t* self);
+
+ ///
+ /// Returns the HEAD node of an HTML document.
+ ///
+ struct _cef_domnode_t*(CEF_CALLBACK* get_head)(
+ struct _cef_domdocument_t* self);
+
+ ///
+ /// Returns the title of an HTML document.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_title)(
+ struct _cef_domdocument_t* self);
+
+ ///
+ /// Returns the document element with the specified ID value.
+ ///
+ struct _cef_domnode_t*(CEF_CALLBACK* get_element_by_id)(
+ struct _cef_domdocument_t* self,
+ const cef_string_t* id);
+
+ ///
+ /// Returns the node that currently has keyboard focus.
+ ///
+ struct _cef_domnode_t*(CEF_CALLBACK* get_focused_node)(
+ struct _cef_domdocument_t* self);
+
+ ///
+ /// Returns true (1) if a portion of the document is selected.
+ ///
+ int(CEF_CALLBACK* has_selection)(struct _cef_domdocument_t* self);
+
+ ///
+ /// Returns the selection offset within the start node.
+ ///
+ int(CEF_CALLBACK* get_selection_start_offset)(
+ struct _cef_domdocument_t* self);
+
+ ///
+ /// Returns the selection offset within the end node.
+ ///
+ int(CEF_CALLBACK* get_selection_end_offset)(struct _cef_domdocument_t* self);
+
+ ///
+ /// Returns the contents of this selection as markup.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_selection_as_markup)(
+ struct _cef_domdocument_t* self);
+
+ ///
+ /// Returns the contents of this selection as text.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_selection_as_text)(
+ struct _cef_domdocument_t* self);
+
+ ///
+ /// Returns the base URL for the document.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_base_url)(
+ struct _cef_domdocument_t* self);
+
+ ///
+ /// Returns a complete URL based on the document base URL and the specified
+ /// partial URL.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_complete_url)(
+ struct _cef_domdocument_t* self,
+ const cef_string_t* partialURL);
+} cef_domdocument_t;
+
+///
+/// Structure used to represent a DOM node. The functions of this structure
+/// should only be called on the render process main thread.
+///
+typedef struct _cef_domnode_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Returns the type for this node.
+ ///
+ cef_dom_node_type_t(CEF_CALLBACK* get_type)(struct _cef_domnode_t* self);
+
+ ///
+ /// Returns true (1) if this is a text node.
+ ///
+ int(CEF_CALLBACK* is_text)(struct _cef_domnode_t* self);
+
+ ///
+ /// Returns true (1) if this is an element node.
+ ///
+ int(CEF_CALLBACK* is_element)(struct _cef_domnode_t* self);
+
+ ///
+ /// Returns true (1) if this is an editable node.
+ ///
+ int(CEF_CALLBACK* is_editable)(struct _cef_domnode_t* self);
+
+ ///
+ /// Returns true (1) if this is a form control element node.
+ ///
+ int(CEF_CALLBACK* is_form_control_element)(struct _cef_domnode_t* self);
+
+ ///
+ /// Returns the type of this form control element node.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_form_control_element_type)(
+ struct _cef_domnode_t* self);
+
+ ///
+ /// Returns true (1) if this object is pointing to the same handle as |that|
+ /// object.
+ ///
+ int(CEF_CALLBACK* is_same)(struct _cef_domnode_t* self,
+ struct _cef_domnode_t* that);
+
+ ///
+ /// Returns the name of this node.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_name)(struct _cef_domnode_t* self);
+
+ ///
+ /// Returns the value of this node.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_value)(struct _cef_domnode_t* self);
+
+ ///
+ /// Set the value of this node. Returns true (1) on success.
+ ///
+ int(CEF_CALLBACK* set_value)(struct _cef_domnode_t* self,
+ const cef_string_t* value);
+
+ ///
+ /// Returns the contents of this node as markup.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_as_markup)(
+ struct _cef_domnode_t* self);
+
+ ///
+ /// Returns the document associated with this node.
+ ///
+ struct _cef_domdocument_t*(CEF_CALLBACK* get_document)(
+ struct _cef_domnode_t* self);
+
+ ///
+ /// Returns the parent node.
+ ///
+ struct _cef_domnode_t*(CEF_CALLBACK* get_parent)(struct _cef_domnode_t* self);
+
+ ///
+ /// Returns the previous sibling node.
+ ///
+ struct _cef_domnode_t*(CEF_CALLBACK* get_previous_sibling)(
+ struct _cef_domnode_t* self);
+
+ ///
+ /// Returns the next sibling node.
+ ///
+ struct _cef_domnode_t*(CEF_CALLBACK* get_next_sibling)(
+ struct _cef_domnode_t* self);
+
+ ///
+ /// Returns true (1) if this node has child nodes.
+ ///
+ int(CEF_CALLBACK* has_children)(struct _cef_domnode_t* self);
+
+ ///
+ /// Return the first child node.
+ ///
+ struct _cef_domnode_t*(CEF_CALLBACK* get_first_child)(
+ struct _cef_domnode_t* self);
+
+ ///
+ /// Returns the last child node.
+ ///
+ struct _cef_domnode_t*(CEF_CALLBACK* get_last_child)(
+ struct _cef_domnode_t* self);
+
+ ///
+ /// Returns the tag name of this element.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_element_tag_name)(
+ struct _cef_domnode_t* self);
+
+ ///
+ /// Returns true (1) if this element has attributes.
+ ///
+ int(CEF_CALLBACK* has_element_attributes)(struct _cef_domnode_t* self);
+
+ ///
+ /// Returns true (1) if this element has an attribute named |attrName|.
+ ///
+ int(CEF_CALLBACK* has_element_attribute)(struct _cef_domnode_t* self,
+ const cef_string_t* attrName);
+
+ ///
+ /// Returns the element attribute named |attrName|.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_element_attribute)(
+ struct _cef_domnode_t* self,
+ const cef_string_t* attrName);
+
+ ///
+ /// Returns a map of all element attributes.
+ ///
+ void(CEF_CALLBACK* get_element_attributes)(struct _cef_domnode_t* self,
+ cef_string_map_t attrMap);
+
+ ///
+ /// Set the value for the element attribute named |attrName|. Returns true (1)
+ /// on success.
+ ///
+ int(CEF_CALLBACK* set_element_attribute)(struct _cef_domnode_t* self,
+ const cef_string_t* attrName,
+ const cef_string_t* value);
+
+ ///
+ /// Returns the inner text of the element.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_element_inner_text)(
+ struct _cef_domnode_t* self);
+
+ ///
+ /// Returns the bounds of the element in device pixels. Use
+ /// "window.devicePixelRatio" to convert to/from CSS pixels.
+ ///
+ cef_rect_t(CEF_CALLBACK* get_element_bounds)(struct _cef_domnode_t* self);
+} cef_domnode_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_DOM_CAPI_H_
diff --git a/include/capi/cef_download_handler_capi.h b/include/capi/cef_download_handler_capi.h
new file mode 100644
index 00000000..59795134
--- /dev/null
+++ b/include/capi/cef_download_handler_capi.h
@@ -0,0 +1,150 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=f1f6a110a7ce15611a7062b3d7fe8b5c630f2980$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_DOWNLOAD_HANDLER_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_DOWNLOAD_HANDLER_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+#include "include/capi/cef_browser_capi.h"
+#include "include/capi/cef_download_item_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Callback structure used to asynchronously continue a download.
+///
+typedef struct _cef_before_download_callback_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Call to continue the download. Set |download_path| to the full file path
+ /// for the download including the file name or leave blank to use the
+ /// suggested name and the default temp directory. Set |show_dialog| to true
+ /// (1) if you do wish to show the default "Save As" dialog.
+ ///
+ void(CEF_CALLBACK* cont)(struct _cef_before_download_callback_t* self,
+ const cef_string_t* download_path,
+ int show_dialog);
+} cef_before_download_callback_t;
+
+///
+/// Callback structure used to asynchronously cancel a download.
+///
+typedef struct _cef_download_item_callback_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Call to cancel the download.
+ ///
+ void(CEF_CALLBACK* cancel)(struct _cef_download_item_callback_t* self);
+
+ ///
+ /// Call to pause the download.
+ ///
+ void(CEF_CALLBACK* pause)(struct _cef_download_item_callback_t* self);
+
+ ///
+ /// Call to resume the download.
+ ///
+ void(CEF_CALLBACK* resume)(struct _cef_download_item_callback_t* self);
+} cef_download_item_callback_t;
+
+///
+/// Structure used to handle file downloads. The functions of this structure
+/// will called on the browser process UI thread.
+///
+typedef struct _cef_download_handler_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Called before a download begins in response to a user-initiated action
+ /// (e.g. alt + link click or link click that returns a `Content-Disposition:
+ /// attachment` response from the server). |url| is the target download URL
+ /// and |request_function| is the target function (GET, POST, etc). Return
+ /// true (1) to proceed with the download or false (0) to cancel the download.
+ ///
+ int(CEF_CALLBACK* can_download)(struct _cef_download_handler_t* self,
+ struct _cef_browser_t* browser,
+ const cef_string_t* url,
+ const cef_string_t* request_method);
+
+ ///
+ /// Called before a download begins. |suggested_name| is the suggested name
+ /// for the download file. By default the download will be canceled. Execute
+ /// |callback| either asynchronously or in this function to continue the
+ /// download if desired. Do not keep a reference to |download_item| outside of
+ /// this function.
+ ///
+ void(CEF_CALLBACK* on_before_download)(
+ struct _cef_download_handler_t* self,
+ struct _cef_browser_t* browser,
+ struct _cef_download_item_t* download_item,
+ const cef_string_t* suggested_name,
+ struct _cef_before_download_callback_t* callback);
+
+ ///
+ /// Called when a download's status or progress information has been updated.
+ /// This may be called multiple times before and after on_before_download().
+ /// Execute |callback| either asynchronously or in this function to cancel the
+ /// download if desired. Do not keep a reference to |download_item| outside of
+ /// this function.
+ ///
+ void(CEF_CALLBACK* on_download_updated)(
+ struct _cef_download_handler_t* self,
+ struct _cef_browser_t* browser,
+ struct _cef_download_item_t* download_item,
+ struct _cef_download_item_callback_t* callback);
+} cef_download_handler_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_DOWNLOAD_HANDLER_CAPI_H_
diff --git a/include/capi/cef_download_item_capi.h b/include/capi/cef_download_item_capi.h
new file mode 100644
index 00000000..d6986eb0
--- /dev/null
+++ b/include/capi/cef_download_item_capi.h
@@ -0,0 +1,163 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=332b9cb62b9c85573dc705aba4c9db3b34177e20$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_DOWNLOAD_ITEM_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_DOWNLOAD_ITEM_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Structure used to represent a download item.
+///
+typedef struct _cef_download_item_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Returns true (1) if this object is valid. Do not call any other functions
+ /// if this function returns false (0).
+ ///
+ int(CEF_CALLBACK* is_valid)(struct _cef_download_item_t* self);
+
+ ///
+ /// Returns true (1) if the download is in progress.
+ ///
+ int(CEF_CALLBACK* is_in_progress)(struct _cef_download_item_t* self);
+
+ ///
+ /// Returns true (1) if the download is complete.
+ ///
+ int(CEF_CALLBACK* is_complete)(struct _cef_download_item_t* self);
+
+ ///
+ /// Returns true (1) if the download has been canceled or interrupted.
+ ///
+ int(CEF_CALLBACK* is_canceled)(struct _cef_download_item_t* self);
+
+ ///
+ /// Returns a simple speed estimate in bytes/s.
+ ///
+ int64(CEF_CALLBACK* get_current_speed)(struct _cef_download_item_t* self);
+
+ ///
+ /// Returns the rough percent complete or -1 if the receive total size is
+ /// unknown.
+ ///
+ int(CEF_CALLBACK* get_percent_complete)(struct _cef_download_item_t* self);
+
+ ///
+ /// Returns the total number of bytes.
+ ///
+ int64(CEF_CALLBACK* get_total_bytes)(struct _cef_download_item_t* self);
+
+ ///
+ /// Returns the number of received bytes.
+ ///
+ int64(CEF_CALLBACK* get_received_bytes)(struct _cef_download_item_t* self);
+
+ ///
+ /// Returns the time that the download started.
+ ///
+ cef_basetime_t(CEF_CALLBACK* get_start_time)(
+ struct _cef_download_item_t* self);
+
+ ///
+ /// Returns the time that the download ended.
+ ///
+ cef_basetime_t(CEF_CALLBACK* get_end_time)(struct _cef_download_item_t* self);
+
+ ///
+ /// Returns the full path to the downloaded or downloading file.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_full_path)(
+ struct _cef_download_item_t* self);
+
+ ///
+ /// Returns the unique identifier for this download.
+ ///
+ uint32(CEF_CALLBACK* get_id)(struct _cef_download_item_t* self);
+
+ ///
+ /// Returns the URL.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_url)(
+ struct _cef_download_item_t* self);
+
+ ///
+ /// Returns the original URL before any redirections.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_original_url)(
+ struct _cef_download_item_t* self);
+
+ ///
+ /// Returns the suggested file name.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_suggested_file_name)(
+ struct _cef_download_item_t* self);
+
+ ///
+ /// Returns the content disposition.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_content_disposition)(
+ struct _cef_download_item_t* self);
+
+ ///
+ /// Returns the mime type.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_mime_type)(
+ struct _cef_download_item_t* self);
+} cef_download_item_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_DOWNLOAD_ITEM_CAPI_H_
diff --git a/include/capi/cef_drag_data_capi.h b/include/capi/cef_drag_data_capi.h
new file mode 100644
index 00000000..32eed2fe
--- /dev/null
+++ b/include/capi/cef_drag_data_capi.h
@@ -0,0 +1,233 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=a1ce746f0dd97d21973d4c80d8ef46391c0fd463$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_DRAG_DATA_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_DRAG_DATA_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+#include "include/capi/cef_image_capi.h"
+#include "include/capi/cef_stream_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Structure used to represent drag data. The functions of this structure may
+/// be called on any thread.
+///
+typedef struct _cef_drag_data_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Returns a copy of the current object.
+ ///
+ struct _cef_drag_data_t*(CEF_CALLBACK* clone)(struct _cef_drag_data_t* self);
+
+ ///
+ /// Returns true (1) if this object is read-only.
+ ///
+ int(CEF_CALLBACK* is_read_only)(struct _cef_drag_data_t* self);
+
+ ///
+ /// Returns true (1) if the drag data is a link.
+ ///
+ int(CEF_CALLBACK* is_link)(struct _cef_drag_data_t* self);
+
+ ///
+ /// Returns true (1) if the drag data is a text or html fragment.
+ ///
+ int(CEF_CALLBACK* is_fragment)(struct _cef_drag_data_t* self);
+
+ ///
+ /// Returns true (1) if the drag data is a file.
+ ///
+ int(CEF_CALLBACK* is_file)(struct _cef_drag_data_t* self);
+
+ ///
+ /// Return the link URL that is being dragged.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_link_url)(
+ struct _cef_drag_data_t* self);
+
+ ///
+ /// Return the title associated with the link being dragged.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_link_title)(
+ struct _cef_drag_data_t* self);
+
+ ///
+ /// Return the metadata, if any, associated with the link being dragged.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_link_metadata)(
+ struct _cef_drag_data_t* self);
+
+ ///
+ /// Return the plain text fragment that is being dragged.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_fragment_text)(
+ struct _cef_drag_data_t* self);
+
+ ///
+ /// Return the text/html fragment that is being dragged.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_fragment_html)(
+ struct _cef_drag_data_t* self);
+
+ ///
+ /// Return the base URL that the fragment came from. This value is used for
+ /// resolving relative URLs and may be NULL.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_fragment_base_url)(
+ struct _cef_drag_data_t* self);
+
+ ///
+ /// Return the name of the file being dragged out of the browser window.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_file_name)(
+ struct _cef_drag_data_t* self);
+
+ ///
+ /// Write the contents of the file being dragged out of the web view into
+ /// |writer|. Returns the number of bytes sent to |writer|. If |writer| is
+ /// NULL this function will return the size of the file contents in bytes.
+ /// Call get_file_name() to get a suggested name for the file.
+ ///
+ size_t(CEF_CALLBACK* get_file_contents)(struct _cef_drag_data_t* self,
+ struct _cef_stream_writer_t* writer);
+
+ ///
+ /// Retrieve the list of file names that are being dragged into the browser
+ /// window.
+ ///
+ int(CEF_CALLBACK* get_file_names)(struct _cef_drag_data_t* self,
+ cef_string_list_t names);
+
+ ///
+ /// Set the link URL that is being dragged.
+ ///
+ void(CEF_CALLBACK* set_link_url)(struct _cef_drag_data_t* self,
+ const cef_string_t* url);
+
+ ///
+ /// Set the title associated with the link being dragged.
+ ///
+ void(CEF_CALLBACK* set_link_title)(struct _cef_drag_data_t* self,
+ const cef_string_t* title);
+
+ ///
+ /// Set the metadata associated with the link being dragged.
+ ///
+ void(CEF_CALLBACK* set_link_metadata)(struct _cef_drag_data_t* self,
+ const cef_string_t* data);
+
+ ///
+ /// Set the plain text fragment that is being dragged.
+ ///
+ void(CEF_CALLBACK* set_fragment_text)(struct _cef_drag_data_t* self,
+ const cef_string_t* text);
+
+ ///
+ /// Set the text/html fragment that is being dragged.
+ ///
+ void(CEF_CALLBACK* set_fragment_html)(struct _cef_drag_data_t* self,
+ const cef_string_t* html);
+
+ ///
+ /// Set the base URL that the fragment came from.
+ ///
+ void(CEF_CALLBACK* set_fragment_base_url)(struct _cef_drag_data_t* self,
+ const cef_string_t* base_url);
+
+ ///
+ /// Reset the file contents. You should do this before calling
+ /// cef_browser_host_t::DragTargetDragEnter as the web view does not allow us
+ /// to drag in this kind of data.
+ ///
+ void(CEF_CALLBACK* reset_file_contents)(struct _cef_drag_data_t* self);
+
+ ///
+ /// Add a file that is being dragged into the webview.
+ ///
+ void(CEF_CALLBACK* add_file)(struct _cef_drag_data_t* self,
+ const cef_string_t* path,
+ const cef_string_t* display_name);
+
+ ///
+ /// Clear list of filenames.
+ ///
+ void(CEF_CALLBACK* clear_filenames)(struct _cef_drag_data_t* self);
+
+ ///
+ /// Get the image representation of drag data. May return NULL if no image
+ /// representation is available.
+ ///
+ struct _cef_image_t*(CEF_CALLBACK* get_image)(struct _cef_drag_data_t* self);
+
+ ///
+ /// Get the image hotspot (drag start location relative to image dimensions).
+ ///
+ cef_point_t(CEF_CALLBACK* get_image_hotspot)(struct _cef_drag_data_t* self);
+
+ ///
+ /// Returns true (1) if an image representation of drag data is available.
+ ///
+ int(CEF_CALLBACK* has_image)(struct _cef_drag_data_t* self);
+} cef_drag_data_t;
+
+///
+/// Create a new cef_drag_data_t object.
+///
+CEF_EXPORT cef_drag_data_t* cef_drag_data_create(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_DRAG_DATA_CAPI_H_
diff --git a/include/capi/cef_drag_handler_capi.h b/include/capi/cef_drag_handler_capi.h
new file mode 100644
index 00000000..a5023e00
--- /dev/null
+++ b/include/capi/cef_drag_handler_capi.h
@@ -0,0 +1,92 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=ad16b0f4320d7b363efb152a65e3ce142882b9d9$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_DRAG_HANDLER_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_DRAG_HANDLER_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+#include "include/capi/cef_browser_capi.h"
+#include "include/capi/cef_drag_data_capi.h"
+#include "include/capi/cef_frame_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Implement this structure to handle events related to dragging. The functions
+/// of this structure will be called on the UI thread.
+///
+typedef struct _cef_drag_handler_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Called when an external drag event enters the browser window. |dragData|
+ /// contains the drag event data and |mask| represents the type of drag
+ /// operation. Return false (0) for default drag handling behavior or true (1)
+ /// to cancel the drag event.
+ ///
+ int(CEF_CALLBACK* on_drag_enter)(struct _cef_drag_handler_t* self,
+ struct _cef_browser_t* browser,
+ struct _cef_drag_data_t* dragData,
+ cef_drag_operations_mask_t mask);
+
+ ///
+ /// Called whenever draggable regions for the browser window change. These can
+ /// be specified using the '-webkit-app-region: drag/no-drag' CSS-property. If
+ /// draggable regions are never defined in a document this function will also
+ /// never be called. If the last draggable region is removed from a document
+ /// this function will be called with an NULL vector.
+ ///
+ void(CEF_CALLBACK* on_draggable_regions_changed)(
+ struct _cef_drag_handler_t* self,
+ struct _cef_browser_t* browser,
+ struct _cef_frame_t* frame,
+ size_t regionsCount,
+ cef_draggable_region_t const* regions);
+} cef_drag_handler_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_DRAG_HANDLER_CAPI_H_
diff --git a/include/capi/cef_extension_capi.h b/include/capi/cef_extension_capi.h
new file mode 100644
index 00000000..a945b9bf
--- /dev/null
+++ b/include/capi/cef_extension_capi.h
@@ -0,0 +1,130 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=c81a74622b987483e5fcd2c508aec5c13e12389b$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_EXTENSION_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_EXTENSION_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+#include "include/capi/cef_values_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _cef_extension_handler_t;
+struct _cef_request_context_t;
+
+///
+/// Object representing an extension. Methods may be called on any thread unless
+/// otherwise indicated.
+///
+typedef struct _cef_extension_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Returns the unique extension identifier. This is calculated based on the
+ /// extension public key, if available, or on the extension path. See
+ /// https://developer.chrome.com/extensions/manifest/key for details.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_identifier)(
+ struct _cef_extension_t* self);
+
+ ///
+ /// Returns the absolute path to the extension directory on disk. This value
+ /// will be prefixed with PK_DIR_RESOURCES if a relative path was passed to
+ /// cef_request_context_t::LoadExtension.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_path)(struct _cef_extension_t* self);
+
+ ///
+ /// Returns the extension manifest contents as a cef_dictionary_value_t
+ /// object. See https://developer.chrome.com/extensions/manifest for details.
+ ///
+ struct _cef_dictionary_value_t*(CEF_CALLBACK* get_manifest)(
+ struct _cef_extension_t* self);
+
+ ///
+ /// Returns true (1) if this object is the same extension as |that| object.
+ /// Extensions are considered the same if identifier, path and loader context
+ /// match.
+ ///
+ int(CEF_CALLBACK* is_same)(struct _cef_extension_t* self,
+ struct _cef_extension_t* that);
+
+ ///
+ /// Returns the handler for this extension. Will return NULL for internal
+ /// extensions or if no handler was passed to
+ /// cef_request_context_t::LoadExtension.
+ ///
+ struct _cef_extension_handler_t*(CEF_CALLBACK* get_handler)(
+ struct _cef_extension_t* self);
+
+ ///
+ /// Returns the request context that loaded this extension. Will return NULL
+ /// for internal extensions or if the extension has been unloaded. See the
+ /// cef_request_context_t::LoadExtension documentation for more information
+ /// about loader contexts. Must be called on the browser process UI thread.
+ ///
+ struct _cef_request_context_t*(CEF_CALLBACK* get_loader_context)(
+ struct _cef_extension_t* self);
+
+ ///
+ /// Returns true (1) if this extension is currently loaded. Must be called on
+ /// the browser process UI thread.
+ ///
+ int(CEF_CALLBACK* is_loaded)(struct _cef_extension_t* self);
+
+ ///
+ /// Unload this extension if it is not an internal extension and is currently
+ /// loaded. Will result in a call to
+ /// cef_extension_handler_t::OnExtensionUnloaded on success.
+ ///
+ void(CEF_CALLBACK* unload)(struct _cef_extension_t* self);
+} cef_extension_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_EXTENSION_CAPI_H_
diff --git a/include/capi/cef_extension_handler_capi.h b/include/capi/cef_extension_handler_capi.h
new file mode 100644
index 00000000..ab29f349
--- /dev/null
+++ b/include/capi/cef_extension_handler_capi.h
@@ -0,0 +1,212 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=ad6d3845b150f22b88a71dafa601ef01c9579824$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_EXTENSION_HANDLER_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_EXTENSION_HANDLER_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+#include "include/capi/cef_browser_capi.h"
+#include "include/capi/cef_extension_capi.h"
+#include "include/capi/cef_stream_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _cef_client_t;
+
+///
+/// Callback structure used for asynchronous continuation of
+/// cef_extension_handler_t::GetExtensionResource.
+///
+typedef struct _cef_get_extension_resource_callback_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Continue the request. Read the resource contents from |stream|.
+ ///
+ void(CEF_CALLBACK* cont)(struct _cef_get_extension_resource_callback_t* self,
+ struct _cef_stream_reader_t* stream);
+
+ ///
+ /// Cancel the request.
+ ///
+ void(CEF_CALLBACK* cancel)(
+ struct _cef_get_extension_resource_callback_t* self);
+} cef_get_extension_resource_callback_t;
+
+///
+/// Implement this structure to handle events related to browser extensions. The
+/// functions of this structure will be called on the UI thread. See
+/// cef_request_context_t::LoadExtension for information about extension
+/// loading.
+///
+typedef struct _cef_extension_handler_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Called if the cef_request_context_t::LoadExtension request fails. |result|
+ /// will be the error code.
+ ///
+ void(CEF_CALLBACK* on_extension_load_failed)(
+ struct _cef_extension_handler_t* self,
+ cef_errorcode_t result);
+
+ ///
+ /// Called if the cef_request_context_t::LoadExtension request succeeds.
+ /// |extension| is the loaded extension.
+ ///
+ void(CEF_CALLBACK* on_extension_loaded)(struct _cef_extension_handler_t* self,
+ struct _cef_extension_t* extension);
+
+ ///
+ /// Called after the cef_extension_t::Unload request has completed.
+ ///
+ void(CEF_CALLBACK* on_extension_unloaded)(
+ struct _cef_extension_handler_t* self,
+ struct _cef_extension_t* extension);
+
+ ///
+ /// Called when an extension needs a browser to host a background script
+ /// specified via the "background" manifest key. The browser will have no
+ /// visible window and cannot be displayed. |extension| is the extension that
+ /// is loading the background script. |url| is an internally generated
+ /// reference to an HTML page that will be used to load the background script
+ /// via a "<script>" src attribute. To allow creation of the browser
+ /// optionally modify |client| and |settings| and return false (0). To cancel
+ /// creation of the browser (and consequently cancel load of the background
+ /// script) return true (1). Successful creation will be indicated by a call
+ /// to cef_life_span_handler_t::OnAfterCreated, and
+ /// cef_browser_host_t::IsBackgroundHost will return true (1) for the
+ /// resulting browser. See https://developer.chrome.com/extensions/event_pages
+ /// for more information about extension background script usage.
+ ///
+ int(CEF_CALLBACK* on_before_background_browser)(
+ struct _cef_extension_handler_t* self,
+ struct _cef_extension_t* extension,
+ const cef_string_t* url,
+ struct _cef_client_t** client,
+ struct _cef_browser_settings_t* settings);
+
+ ///
+ /// Called when an extension API (e.g. chrome.tabs.create) requests creation
+ /// of a new browser. |extension| and |browser| are the source of the API
+ /// call. |active_browser| may optionally be specified via the windowId
+ /// property or returned via the get_active_browser() callback and provides
+ /// the default |client| and |settings| values for the new browser. |index| is
+ /// the position value optionally specified via the index property. |url| is
+ /// the URL that will be loaded in the browser. |active| is true (1) if the
+ /// new browser should be active when opened. To allow creation of the
+ /// browser optionally modify |windowInfo|, |client| and |settings| and return
+ /// false (0). To cancel creation of the browser return true (1). Successful
+ /// creation will be indicated by a call to
+ /// cef_life_span_handler_t::OnAfterCreated. Any modifications to |windowInfo|
+ /// will be ignored if |active_browser| is wrapped in a cef_browser_view_t.
+ ///
+ int(CEF_CALLBACK* on_before_browser)(
+ struct _cef_extension_handler_t* self,
+ struct _cef_extension_t* extension,
+ struct _cef_browser_t* browser,
+ struct _cef_browser_t* active_browser,
+ int index,
+ const cef_string_t* url,
+ int active,
+ struct _cef_window_info_t* windowInfo,
+ struct _cef_client_t** client,
+ struct _cef_browser_settings_t* settings);
+
+ ///
+ /// Called when no tabId is specified to an extension API call that accepts a
+ /// tabId parameter (e.g. chrome.tabs.*). |extension| and |browser| are the
+ /// source of the API call. Return the browser that will be acted on by the
+ /// API call or return NULL to act on |browser|. The returned browser must
+ /// share the same cef_request_context_t as |browser|. Incognito browsers
+ /// should not be considered unless the source extension has incognito access
+ /// enabled, in which case |include_incognito| will be true (1).
+ ///
+ struct _cef_browser_t*(CEF_CALLBACK* get_active_browser)(
+ struct _cef_extension_handler_t* self,
+ struct _cef_extension_t* extension,
+ struct _cef_browser_t* browser,
+ int include_incognito);
+
+ ///
+ /// Called when the tabId associated with |target_browser| is specified to an
+ /// extension API call that accepts a tabId parameter (e.g. chrome.tabs.*).
+ /// |extension| and |browser| are the source of the API call. Return true (1)
+ /// to allow access of false (0) to deny access. Access to incognito browsers
+ /// should not be allowed unless the source extension has incognito access
+ /// enabled, in which case |include_incognito| will be true (1).
+ ///
+ int(CEF_CALLBACK* can_access_browser)(struct _cef_extension_handler_t* self,
+ struct _cef_extension_t* extension,
+ struct _cef_browser_t* browser,
+ int include_incognito,
+ struct _cef_browser_t* target_browser);
+
+ ///
+ /// Called to retrieve an extension resource that would normally be loaded
+ /// from disk (e.g. if a file parameter is specified to
+ /// chrome.tabs.executeScript). |extension| and |browser| are the source of
+ /// the resource request. |file| is the requested relative file path. To
+ /// handle the resource request return true (1) and execute |callback| either
+ /// synchronously or asynchronously. For the default behavior which reads the
+ /// resource from the extension directory on disk return false (0).
+ /// Localization substitutions will not be applied to resources handled via
+ /// this function.
+ ///
+ int(CEF_CALLBACK* get_extension_resource)(
+ struct _cef_extension_handler_t* self,
+ struct _cef_extension_t* extension,
+ struct _cef_browser_t* browser,
+ const cef_string_t* file,
+ struct _cef_get_extension_resource_callback_t* callback);
+} cef_extension_handler_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_EXTENSION_HANDLER_CAPI_H_
diff --git a/include/capi/cef_file_util_capi.h b/include/capi/cef_file_util_capi.h
new file mode 100644
index 00000000..daad7a52
--- /dev/null
+++ b/include/capi/cef_file_util_capi.h
@@ -0,0 +1,132 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=4e0e0abcb72327998df950e618b147b196e76b60$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_FILE_UTIL_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_FILE_UTIL_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Creates a directory and all parent directories if they don't already exist.
+/// Returns true (1) on successful creation or if the directory already exists.
+/// The directory is only readable by the current user. Calling this function on
+/// the browser process UI or IO threads is not allowed.
+///
+CEF_EXPORT int cef_create_directory(const cef_string_t* full_path);
+
+///
+/// Get the temporary directory provided by the system.
+///
+/// WARNING: In general, you should use the temp directory variants below
+/// instead of this function. Those variants will ensure that the proper
+/// permissions are set so that other users on the system can't edit them while
+/// they're open (which could lead to security issues).
+///
+CEF_EXPORT int cef_get_temp_directory(cef_string_t* temp_dir);
+
+///
+/// Creates a new directory. On Windows if |prefix| is provided the new
+/// directory name is in the format of "prefixyyyy". Returns true (1) on success
+/// and sets |new_temp_path| to the full path of the directory that was created.
+/// The directory is only readable by the current user. Calling this function on
+/// the browser process UI or IO threads is not allowed.
+///
+CEF_EXPORT int cef_create_new_temp_directory(const cef_string_t* prefix,
+ cef_string_t* new_temp_path);
+
+///
+/// Creates a directory within another directory. Extra characters will be
+/// appended to |prefix| to ensure that the new directory does not have the same
+/// name as an existing directory. Returns true (1) on success and sets
+/// |new_dir| to the full path of the directory that was created. The directory
+/// is only readable by the current user. Calling this function on the browser
+/// process UI or IO threads is not allowed.
+///
+CEF_EXPORT int cef_create_temp_directory_in_directory(
+ const cef_string_t* base_dir,
+ const cef_string_t* prefix,
+ cef_string_t* new_dir);
+
+///
+/// Returns true (1) if the given path exists and is a directory. Calling this
+/// function on the browser process UI or IO threads is not allowed.
+///
+CEF_EXPORT int cef_directory_exists(const cef_string_t* path);
+
+///
+/// Deletes the given path whether it's a file or a directory. If |path| is a
+/// directory all contents will be deleted. If |recursive| is true (1) any sub-
+/// directories and their contents will also be deleted (equivalent to executing
+/// "rm -rf", so use with caution). On POSIX environments if |path| is a
+/// symbolic link then only the symlink will be deleted. Returns true (1) on
+/// successful deletion or if |path| does not exist. Calling this function on
+/// the browser process UI or IO threads is not allowed.
+///
+CEF_EXPORT int cef_delete_file(const cef_string_t* path, int recursive);
+
+///
+/// Writes the contents of |src_dir| into a zip archive at |dest_file|. If
+/// |include_hidden_files| is true (1) files starting with "." will be included.
+/// Returns true (1) on success. Calling this function on the browser process
+/// UI or IO threads is not allowed.
+///
+CEF_EXPORT int cef_zip_directory(const cef_string_t* src_dir,
+ const cef_string_t* dest_file,
+ int include_hidden_files);
+
+///
+/// Loads the existing "Certificate Revocation Lists" file that is managed by
+/// Google Chrome. This file can generally be found in Chrome's User Data
+/// directory (e.g. "C:\Users\[User]\AppData\Local\Google\Chrome\User Data\" on
+/// Windows) and is updated periodically by Chrome's component updater service.
+/// Must be called in the browser process after the context has been
+/// initialized. See https://dev.chromium.org/Home/chromium-security/crlsets for
+/// background.
+///
+CEF_EXPORT void cef_load_crlsets_file(const cef_string_t* path);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_FILE_UTIL_CAPI_H_
diff --git a/include/capi/cef_find_handler_capi.h b/include/capi/cef_find_handler_capi.h
new file mode 100644
index 00000000..94450d29
--- /dev/null
+++ b/include/capi/cef_find_handler_capi.h
@@ -0,0 +1,82 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=8149c82dd6671d676ee62cb6749bf30b32a5832c$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_FIND_HANDLER_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_FIND_HANDLER_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+#include "include/capi/cef_browser_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Implement this structure to handle events related to find results. The
+/// functions of this structure will be called on the UI thread.
+///
+typedef struct _cef_find_handler_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Called to report find results returned by cef_browser_host_t::find().
+ /// |identifer| is a unique incremental identifier for the currently active
+ /// search, |count| is the number of matches currently identified,
+ /// |selectionRect| is the location of where the match was found (in window
+ /// coordinates), |activeMatchOrdinal| is the current position in the search
+ /// results, and |finalUpdate| is true (1) if this is the last find
+ /// notification.
+ ///
+ void(CEF_CALLBACK* on_find_result)(struct _cef_find_handler_t* self,
+ struct _cef_browser_t* browser,
+ int identifier,
+ int count,
+ const cef_rect_t* selectionRect,
+ int activeMatchOrdinal,
+ int finalUpdate);
+} cef_find_handler_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_FIND_HANDLER_CAPI_H_
diff --git a/include/capi/cef_focus_handler_capi.h b/include/capi/cef_focus_handler_capi.h
new file mode 100644
index 00000000..f7b699dc
--- /dev/null
+++ b/include/capi/cef_focus_handler_capi.h
@@ -0,0 +1,93 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=53ec33c8937c735f646f9e0a14a416218e32887c$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_FOCUS_HANDLER_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_FOCUS_HANDLER_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+#include "include/capi/cef_browser_capi.h"
+#include "include/capi/cef_dom_capi.h"
+#include "include/capi/cef_frame_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Implement this structure to handle events related to focus. The functions of
+/// this structure will be called on the UI thread.
+///
+typedef struct _cef_focus_handler_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Called when the browser component is about to loose focus. For instance,
+ /// if focus was on the last HTML element and the user pressed the TAB key.
+ /// |next| will be true (1) if the browser is giving focus to the next
+ /// component and false (0) if the browser is giving focus to the previous
+ /// component.
+ ///
+ void(CEF_CALLBACK* on_take_focus)(struct _cef_focus_handler_t* self,
+ struct _cef_browser_t* browser,
+ int next);
+
+ ///
+ /// Called when the browser component is requesting focus. |source| indicates
+ /// where the focus request is originating from. Return false (0) to allow the
+ /// focus to be set or true (1) to cancel setting the focus.
+ ///
+ int(CEF_CALLBACK* on_set_focus)(struct _cef_focus_handler_t* self,
+ struct _cef_browser_t* browser,
+ cef_focus_source_t source);
+
+ ///
+ /// Called when the browser component has received focus.
+ ///
+ void(CEF_CALLBACK* on_got_focus)(struct _cef_focus_handler_t* self,
+ struct _cef_browser_t* browser);
+} cef_focus_handler_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_FOCUS_HANDLER_CAPI_H_
diff --git a/include/capi/cef_frame_capi.h b/include/capi/cef_frame_capi.h
new file mode 100644
index 00000000..94069ced
--- /dev/null
+++ b/include/capi/cef_frame_capi.h
@@ -0,0 +1,263 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=b9b1308311999efcfd2aa678472f934ca783492c$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_FRAME_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_FRAME_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+#include "include/capi/cef_dom_capi.h"
+#include "include/capi/cef_process_message_capi.h"
+#include "include/capi/cef_request_capi.h"
+#include "include/capi/cef_stream_capi.h"
+#include "include/capi/cef_string_visitor_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _cef_browser_t;
+struct _cef_urlrequest_client_t;
+struct _cef_urlrequest_t;
+struct _cef_v8context_t;
+
+///
+/// Structure used to represent a frame in the browser window. When used in the
+/// browser process the functions of this structure may be called on any thread
+/// unless otherwise indicated in the comments. When used in the render process
+/// the functions of this structure may only be called on the main thread.
+///
+typedef struct _cef_frame_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// True if this object is currently attached to a valid frame.
+ ///
+ int(CEF_CALLBACK* is_valid)(struct _cef_frame_t* self);
+
+ ///
+ /// Execute undo in this frame.
+ ///
+ void(CEF_CALLBACK* undo)(struct _cef_frame_t* self);
+
+ ///
+ /// Execute redo in this frame.
+ ///
+ void(CEF_CALLBACK* redo)(struct _cef_frame_t* self);
+
+ ///
+ /// Execute cut in this frame.
+ ///
+ void(CEF_CALLBACK* cut)(struct _cef_frame_t* self);
+
+ ///
+ /// Execute copy in this frame.
+ ///
+ void(CEF_CALLBACK* copy)(struct _cef_frame_t* self);
+
+ ///
+ /// Execute paste in this frame.
+ ///
+ void(CEF_CALLBACK* paste)(struct _cef_frame_t* self);
+
+ ///
+ /// Execute delete in this frame.
+ ///
+ void(CEF_CALLBACK* del)(struct _cef_frame_t* self);
+
+ ///
+ /// Execute select all in this frame.
+ ///
+ void(CEF_CALLBACK* select_all)(struct _cef_frame_t* self);
+
+ ///
+ /// Save this frame's HTML source to a temporary file and open it in the
+ /// default text viewing application. This function can only be called from
+ /// the browser process.
+ ///
+ void(CEF_CALLBACK* view_source)(struct _cef_frame_t* self);
+
+ ///
+ /// Retrieve this frame's HTML source as a string sent to the specified
+ /// visitor.
+ ///
+ void(CEF_CALLBACK* get_source)(struct _cef_frame_t* self,
+ struct _cef_string_visitor_t* visitor);
+
+ ///
+ /// Retrieve this frame's display text as a string sent to the specified
+ /// visitor.
+ ///
+ void(CEF_CALLBACK* get_text)(struct _cef_frame_t* self,
+ struct _cef_string_visitor_t* visitor);
+
+ ///
+ /// Load the request represented by the |request| object.
+ ///
+ /// WARNING: This function will fail with "bad IPC message" reason
+ /// INVALID_INITIATOR_ORIGIN (213) unless you first navigate to the request
+ /// origin using some other mechanism (LoadURL, link click, etc).
+ ///
+ void(CEF_CALLBACK* load_request)(struct _cef_frame_t* self,
+ struct _cef_request_t* request);
+
+ ///
+ /// Load the specified |url|.
+ ///
+ void(CEF_CALLBACK* load_url)(struct _cef_frame_t* self,
+ const cef_string_t* url);
+
+ ///
+ /// Execute a string of JavaScript code in this frame. The |script_url|
+ /// parameter is the URL where the script in question can be found, if any.
+ /// The renderer may request this URL to show the developer the source of the
+ /// error. The |start_line| parameter is the base line number to use for
+ /// error reporting.
+ ///
+ void(CEF_CALLBACK* execute_java_script)(struct _cef_frame_t* self,
+ const cef_string_t* code,
+ const cef_string_t* script_url,
+ int start_line);
+
+ ///
+ /// Returns true (1) if this is the main (top-level) frame.
+ ///
+ int(CEF_CALLBACK* is_main)(struct _cef_frame_t* self);
+
+ ///
+ /// Returns true (1) if this is the focused frame.
+ ///
+ int(CEF_CALLBACK* is_focused)(struct _cef_frame_t* self);
+
+ ///
+ /// Returns the name for this frame. If the frame has an assigned name (for
+ /// example, set via the iframe "name" attribute) then that value will be
+ /// returned. Otherwise a unique name will be constructed based on the frame
+ /// parent hierarchy. The main (top-level) frame will always have an NULL name
+ /// value.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_name)(struct _cef_frame_t* self);
+
+ ///
+ /// Returns the globally unique identifier for this frame or < 0 if the
+ /// underlying frame does not yet exist.
+ ///
+ int64(CEF_CALLBACK* get_identifier)(struct _cef_frame_t* self);
+
+ ///
+ /// Returns the parent of this frame or NULL if this is the main (top-level)
+ /// frame.
+ ///
+ struct _cef_frame_t*(CEF_CALLBACK* get_parent)(struct _cef_frame_t* self);
+
+ ///
+ /// Returns the URL currently loaded in this frame.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_url)(struct _cef_frame_t* self);
+
+ ///
+ /// Returns the browser that this frame belongs to.
+ ///
+ struct _cef_browser_t*(CEF_CALLBACK* get_browser)(struct _cef_frame_t* self);
+
+ ///
+ /// Get the V8 context associated with the frame. This function can only be
+ /// called from the render process.
+ ///
+ struct _cef_v8context_t*(CEF_CALLBACK* get_v8context)(
+ struct _cef_frame_t* self);
+
+ ///
+ /// Visit the DOM document. This function can only be called from the render
+ /// process.
+ ///
+ void(CEF_CALLBACK* visit_dom)(struct _cef_frame_t* self,
+ struct _cef_domvisitor_t* visitor);
+
+ ///
+ /// Create a new URL request that will be treated as originating from this
+ /// frame and the associated browser. This request may be intercepted by the
+ /// client via cef_resource_request_handler_t or cef_scheme_handler_factory_t.
+ /// Use cef_urlrequest_t::Create instead if you do not want the request to
+ /// have this association, in which case it may be handled differently (see
+ /// documentation on that function). Requests may originate from both the
+ /// browser process and the render process.
+ ///
+ /// For requests originating from the browser process:
+ /// - POST data may only contain a single element of type PDE_TYPE_FILE or
+ /// PDE_TYPE_BYTES.
+ ///
+ /// For requests originating from the render process:
+ /// - POST data may only contain a single element of type PDE_TYPE_BYTES.
+ /// - If the response contains Content-Disposition or Mime-Type header
+ /// values that would not normally be rendered then the response may
+ /// receive special handling inside the browser (for example, via the
+ /// file download code path instead of the URL request code path).
+ ///
+ /// The |request| object will be marked as read-only after calling this
+ /// function.
+ ///
+ struct _cef_urlrequest_t*(CEF_CALLBACK* create_urlrequest)(
+ struct _cef_frame_t* self,
+ struct _cef_request_t* request,
+ struct _cef_urlrequest_client_t* client);
+
+ ///
+ /// Send a message to the specified |target_process|. Ownership of the message
+ /// contents will be transferred and the |message| reference will be
+ /// invalidated. Message delivery is not guaranteed in all cases (for example,
+ /// if the browser is closing, navigating, or if the target process crashes).
+ /// Send an ACK message back from the target process if confirmation is
+ /// required.
+ ///
+ void(CEF_CALLBACK* send_process_message)(
+ struct _cef_frame_t* self,
+ cef_process_id_t target_process,
+ struct _cef_process_message_t* message);
+} cef_frame_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_FRAME_CAPI_H_
diff --git a/include/capi/cef_frame_handler_capi.h b/include/capi/cef_frame_handler_capi.h
new file mode 100644
index 00000000..94b3b882
--- /dev/null
+++ b/include/capi/cef_frame_handler_capi.h
@@ -0,0 +1,202 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=4cdadeb6439415d60ec32249c3a0b6457dd586f7$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_FRAME_HANDLER_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_FRAME_HANDLER_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+#include "include/capi/cef_browser_capi.h"
+#include "include/capi/cef_frame_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Implement this structure to handle events related to cef_frame_t life span.
+/// The order of callbacks is:
+///
+/// (1) During initial cef_browser_host_t creation and navigation of the main
+/// frame: - cef_frame_handler_t::OnFrameCreated => The initial main frame
+/// object has been
+/// created. Any commands will be queued until the frame is attached.
+/// - cef_frame_handler_t::OnMainFrameChanged => The initial main frame object
+/// has
+/// been assigned to the browser.
+/// - cef_life_span_handler_t::OnAfterCreated => The browser is now valid and
+/// can be
+/// used.
+/// - cef_frame_handler_t::OnFrameAttached => The initial main frame object is
+/// now
+/// connected to its peer in the renderer process. Commands can be routed.
+///
+/// (2) During further cef_browser_host_t navigation/loading of the main frame
+/// and/or sub-frames:
+/// - cef_frame_handler_t::OnFrameCreated => A new main frame or sub-frame
+/// object
+/// has been created. Any commands will be queued until the frame is attached.
+/// - cef_frame_handler_t::OnFrameAttached => A new main frame or sub-frame
+/// object
+/// is now connected to its peer in the renderer process. Commands can be
+/// routed.
+/// - cef_frame_handler_t::OnFrameDetached => An existing main frame or sub-
+/// frame
+/// object has lost its connection to the renderer process. If multiple
+/// objects are detached at the same time then notifications will be sent for
+/// any sub-frame objects before the main frame object. Commands can no longer
+/// be routed and will be discarded.
+/// - cef_frame_handler_t::OnMainFrameChanged => A new main frame object has
+/// been
+/// assigned to the browser. This will only occur with cross-origin navigation
+/// or re-navigation after renderer process termination (due to crashes, etc).
+///
+/// (3) During final cef_browser_host_t destruction of the main frame: -
+/// cef_frame_handler_t::OnFrameDetached => Any sub-frame objects have lost
+/// their
+/// connection to the renderer process. Commands can no longer be routed and
+/// will be discarded.
+/// - cef_life_span_handler_t::OnBeforeClose => The browser has been destroyed.
+/// - cef_frame_handler_t::OnFrameDetached => The main frame object have lost
+/// its
+/// connection to the renderer process. Notifications will be sent for any
+/// sub-frame objects before the main frame object. Commands can no longer be
+/// routed and will be discarded.
+/// - cef_frame_handler_t::OnMainFrameChanged => The final main frame object has
+/// been removed from the browser.
+///
+/// Cross-origin navigation and/or loading receives special handling.
+///
+/// When the main frame navigates to a different origin the OnMainFrameChanged
+/// callback (2) will be executed with the old and new main frame objects.
+///
+/// When a new sub-frame is loaded in, or an existing sub-frame is navigated to,
+/// a different origin from the parent frame, a temporary sub-frame object will
+/// first be created in the parent's renderer process. That temporary sub-frame
+/// will then be discarded after the real cross-origin sub-frame is created in
+/// the new/target renderer process. The client will receive cross-origin
+/// navigation callbacks (2) for the transition from the temporary sub-frame to
+/// the real sub-frame. The temporary sub-frame will not recieve or execute
+/// commands during this transitional period (any sent commands will be
+/// discarded).
+///
+/// When a new popup browser is created in a different origin from the parent
+/// browser, a temporary main frame object for the popup will first be created
+/// in the parent's renderer process. That temporary main frame will then be
+/// discarded after the real cross-origin main frame is created in the
+/// new/target renderer process. The client will recieve creation and initial
+/// navigation callbacks (1) for the temporary main frame, followed by cross-
+/// origin navigation callbacks (2) for the transition from the temporary main
+/// frame to the real main frame. The temporary main frame may receive and
+/// execute commands during this transitional period (any sent commands may be
+/// executed, but the behavior is potentially undesirable since they execute in
+/// the parent browser's renderer process and not the new/target renderer
+/// process).
+///
+/// Callbacks will not be executed for placeholders that may be created during
+/// pre-commit navigation for sub-frames that do not yet exist in the renderer
+/// process. Placeholders will have cef_frame_t::get_identifier() == -4.
+///
+/// The functions of this structure will be called on the UI thread unless
+/// otherwise indicated.
+///
+typedef struct _cef_frame_handler_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Called when a new frame is created. This will be the first notification
+ /// that references |frame|. Any commands that require transport to the
+ /// associated renderer process (LoadRequest, SendProcessMessage, GetSource,
+ /// etc.) will be queued until OnFrameAttached is called for |frame|.
+ ///
+ void(CEF_CALLBACK* on_frame_created)(struct _cef_frame_handler_t* self,
+ struct _cef_browser_t* browser,
+ struct _cef_frame_t* frame);
+
+ ///
+ /// Called when a frame can begin routing commands to/from the associated
+ /// renderer process. |reattached| will be true (1) if the frame was re-
+ /// attached after exiting the BackForwardCache. Any commands that were queued
+ /// have now been dispatched.
+ ///
+ void(CEF_CALLBACK* on_frame_attached)(struct _cef_frame_handler_t* self,
+ struct _cef_browser_t* browser,
+ struct _cef_frame_t* frame,
+ int reattached);
+
+ ///
+ /// Called when a frame loses its connection to the renderer process and will
+ /// be destroyed. Any pending or future commands will be discarded and
+ /// cef_frame_t::is_valid() will now return false (0) for |frame|. If called
+ /// after cef_life_span_handler_t::on_before_close() during browser
+ /// destruction then cef_browser_t::is_valid() will return false (0) for
+ /// |browser|.
+ ///
+ void(CEF_CALLBACK* on_frame_detached)(struct _cef_frame_handler_t* self,
+ struct _cef_browser_t* browser,
+ struct _cef_frame_t* frame);
+
+ ///
+ /// Called when the main frame changes due to (a) initial browser creation,
+ /// (b) final browser destruction, (c) cross-origin navigation or (d) re-
+ /// navigation after renderer process termination (due to crashes, etc).
+ /// |old_frame| will be NULL and |new_frame| will be non-NULL when a main
+ /// frame is assigned to |browser| for the first time. |old_frame| will be
+ /// non-NULL and |new_frame| will be NULL and when a main frame is removed
+ /// from |browser| for the last time. Both |old_frame| and |new_frame| will be
+ /// non-NULL for cross-origin navigations or re-navigation after renderer
+ /// process termination. This function will be called after on_frame_created()
+ /// for |new_frame| and/or after on_frame_detached() for |old_frame|. If
+ /// called after cef_life_span_handler_t::on_before_close() during browser
+ /// destruction then cef_browser_t::is_valid() will return false (0) for
+ /// |browser|.
+ ///
+ void(CEF_CALLBACK* on_main_frame_changed)(struct _cef_frame_handler_t* self,
+ struct _cef_browser_t* browser,
+ struct _cef_frame_t* old_frame,
+ struct _cef_frame_t* new_frame);
+} cef_frame_handler_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_FRAME_HANDLER_CAPI_H_
diff --git a/include/capi/cef_i18n_util_capi.h b/include/capi/cef_i18n_util_capi.h
new file mode 100644
index 00000000..3aab714e
--- /dev/null
+++ b/include/capi/cef_i18n_util_capi.h
@@ -0,0 +1,58 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=c564ee1f32a0ef05fe49fc779af5bc0b0e1b36d6$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_I18N_UTIL_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_I18N_UTIL_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Returns true (1) if the application text direction is right-to-left.
+///
+CEF_EXPORT int cef_is_rtl(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_I18N_UTIL_CAPI_H_
diff --git a/include/capi/cef_image_capi.h b/include/capi/cef_image_capi.h
new file mode 100644
index 00000000..9d4a0a9c
--- /dev/null
+++ b/include/capi/cef_image_capi.h
@@ -0,0 +1,206 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=99c94b208f9b184985220493bba4ea08e6786046$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_IMAGE_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_IMAGE_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+#include "include/capi/cef_values_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Container for a single image represented at different scale factors. All
+/// image representations should be the same size in density independent pixel
+/// (DIP) units. For example, if the image at scale factor 1.0 is 100x100 pixels
+/// then the image at scale factor 2.0 should be 200x200 pixels -- both images
+/// will display with a DIP size of 100x100 units. The functions of this
+/// structure can be called on any browser process thread.
+///
+typedef struct _cef_image_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Returns true (1) if this Image is NULL.
+ ///
+ int(CEF_CALLBACK* is_empty)(struct _cef_image_t* self);
+
+ ///
+ /// Returns true (1) if this Image and |that| Image share the same underlying
+ /// storage. Will also return true (1) if both images are NULL.
+ ///
+ int(CEF_CALLBACK* is_same)(struct _cef_image_t* self,
+ struct _cef_image_t* that);
+
+ ///
+ /// Add a bitmap image representation for |scale_factor|. Only 32-bit
+ /// RGBA/BGRA formats are supported. |pixel_width| and |pixel_height| are the
+ /// bitmap representation size in pixel coordinates. |pixel_data| is the array
+ /// of pixel data and should be |pixel_width| x |pixel_height| x 4 bytes in
+ /// size. |color_type| and |alpha_type| values specify the pixel format.
+ ///
+ int(CEF_CALLBACK* add_bitmap)(struct _cef_image_t* self,
+ float scale_factor,
+ int pixel_width,
+ int pixel_height,
+ cef_color_type_t color_type,
+ cef_alpha_type_t alpha_type,
+ const void* pixel_data,
+ size_t pixel_data_size);
+
+ ///
+ /// Add a PNG image representation for |scale_factor|. |png_data| is the image
+ /// data of size |png_data_size|. Any alpha transparency in the PNG data will
+ /// be maintained.
+ ///
+ int(CEF_CALLBACK* add_png)(struct _cef_image_t* self,
+ float scale_factor,
+ const void* png_data,
+ size_t png_data_size);
+
+ ///
+ /// Create a JPEG image representation for |scale_factor|. |jpeg_data| is the
+ /// image data of size |jpeg_data_size|. The JPEG format does not support
+ /// transparency so the alpha byte will be set to 0xFF for all pixels.
+ ///
+ int(CEF_CALLBACK* add_jpeg)(struct _cef_image_t* self,
+ float scale_factor,
+ const void* jpeg_data,
+ size_t jpeg_data_size);
+
+ ///
+ /// Returns the image width in density independent pixel (DIP) units.
+ ///
+ size_t(CEF_CALLBACK* get_width)(struct _cef_image_t* self);
+
+ ///
+ /// Returns the image height in density independent pixel (DIP) units.
+ ///
+ size_t(CEF_CALLBACK* get_height)(struct _cef_image_t* self);
+
+ ///
+ /// Returns true (1) if this image contains a representation for
+ /// |scale_factor|.
+ ///
+ int(CEF_CALLBACK* has_representation)(struct _cef_image_t* self,
+ float scale_factor);
+
+ ///
+ /// Removes the representation for |scale_factor|. Returns true (1) on
+ /// success.
+ ///
+ int(CEF_CALLBACK* remove_representation)(struct _cef_image_t* self,
+ float scale_factor);
+
+ ///
+ /// Returns information for the representation that most closely matches
+ /// |scale_factor|. |actual_scale_factor| is the actual scale factor for the
+ /// representation. |pixel_width| and |pixel_height| are the representation
+ /// size in pixel coordinates. Returns true (1) on success.
+ ///
+ int(CEF_CALLBACK* get_representation_info)(struct _cef_image_t* self,
+ float scale_factor,
+ float* actual_scale_factor,
+ int* pixel_width,
+ int* pixel_height);
+
+ ///
+ /// Returns the bitmap representation that most closely matches
+ /// |scale_factor|. Only 32-bit RGBA/BGRA formats are supported. |color_type|
+ /// and |alpha_type| values specify the desired output pixel format.
+ /// |pixel_width| and |pixel_height| are the output representation size in
+ /// pixel coordinates. Returns a cef_binary_value_t containing the pixel data
+ /// on success or NULL on failure.
+ ///
+ struct _cef_binary_value_t*(CEF_CALLBACK* get_as_bitmap)(
+ struct _cef_image_t* self,
+ float scale_factor,
+ cef_color_type_t color_type,
+ cef_alpha_type_t alpha_type,
+ int* pixel_width,
+ int* pixel_height);
+
+ ///
+ /// Returns the PNG representation that most closely matches |scale_factor|.
+ /// If |with_transparency| is true (1) any alpha transparency in the image
+ /// will be represented in the resulting PNG data. |pixel_width| and
+ /// |pixel_height| are the output representation size in pixel coordinates.
+ /// Returns a cef_binary_value_t containing the PNG image data on success or
+ /// NULL on failure.
+ ///
+ struct _cef_binary_value_t*(CEF_CALLBACK* get_as_png)(
+ struct _cef_image_t* self,
+ float scale_factor,
+ int with_transparency,
+ int* pixel_width,
+ int* pixel_height);
+
+ ///
+ /// Returns the JPEG representation that most closely matches |scale_factor|.
+ /// |quality| determines the compression level with 0 == lowest and 100 ==
+ /// highest. The JPEG format does not support alpha transparency and the alpha
+ /// channel, if any, will be discarded. |pixel_width| and |pixel_height| are
+ /// the output representation size in pixel coordinates. Returns a
+ /// cef_binary_value_t containing the JPEG image data on success or NULL on
+ /// failure.
+ ///
+ struct _cef_binary_value_t*(CEF_CALLBACK* get_as_jpeg)(
+ struct _cef_image_t* self,
+ float scale_factor,
+ int quality,
+ int* pixel_width,
+ int* pixel_height);
+} cef_image_t;
+
+///
+/// Create a new cef_image_t. It will initially be NULL. Use the Add*()
+/// functions to add representations at different scale factors.
+///
+CEF_EXPORT cef_image_t* cef_image_create(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_IMAGE_CAPI_H_
diff --git a/include/capi/cef_jsdialog_handler_capi.h b/include/capi/cef_jsdialog_handler_capi.h
new file mode 100644
index 00000000..a490ddd8
--- /dev/null
+++ b/include/capi/cef_jsdialog_handler_capi.h
@@ -0,0 +1,141 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=e9fb0354243611f3a4de508923a4e01dab42f82d$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_JSDIALOG_HANDLER_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_JSDIALOG_HANDLER_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+#include "include/capi/cef_browser_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Callback structure used for asynchronous continuation of JavaScript dialog
+/// requests.
+///
+typedef struct _cef_jsdialog_callback_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Continue the JS dialog request. Set |success| to true (1) if the OK button
+ /// was pressed. The |user_input| value should be specified for prompt
+ /// dialogs.
+ ///
+ void(CEF_CALLBACK* cont)(struct _cef_jsdialog_callback_t* self,
+ int success,
+ const cef_string_t* user_input);
+} cef_jsdialog_callback_t;
+
+///
+/// Implement this structure to handle events related to JavaScript dialogs. The
+/// functions of this structure will be called on the UI thread.
+///
+typedef struct _cef_jsdialog_handler_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Called to run a JavaScript dialog. If |origin_url| is non-NULL it can be
+ /// passed to the CefFormatUrlForSecurityDisplay function to retrieve a secure
+ /// and user-friendly display string. The |default_prompt_text| value will be
+ /// specified for prompt dialogs only. Set |suppress_message| to true (1) and
+ /// return false (0) to suppress the message (suppressing messages is
+ /// preferable to immediately executing the callback as this is used to detect
+ /// presumably malicious behavior like spamming alert messages in
+ /// onbeforeunload). Set |suppress_message| to false (0) and return false (0)
+ /// to use the default implementation (the default implementation will show
+ /// one modal dialog at a time and suppress any additional dialog requests
+ /// until the displayed dialog is dismissed). Return true (1) if the
+ /// application will use a custom dialog or if the callback has been executed
+ /// immediately. Custom dialogs may be either modal or modeless. If a custom
+ /// dialog is used the application must execute |callback| once the custom
+ /// dialog is dismissed.
+ ///
+ int(CEF_CALLBACK* on_jsdialog)(struct _cef_jsdialog_handler_t* self,
+ struct _cef_browser_t* browser,
+ const cef_string_t* origin_url,
+ cef_jsdialog_type_t dialog_type,
+ const cef_string_t* message_text,
+ const cef_string_t* default_prompt_text,
+ struct _cef_jsdialog_callback_t* callback,
+ int* suppress_message);
+
+ ///
+ /// Called to run a dialog asking the user if they want to leave a page.
+ /// Return false (0) to use the default dialog implementation. Return true (1)
+ /// if the application will use a custom dialog or if the callback has been
+ /// executed immediately. Custom dialogs may be either modal or modeless. If a
+ /// custom dialog is used the application must execute |callback| once the
+ /// custom dialog is dismissed.
+ ///
+ int(CEF_CALLBACK* on_before_unload_dialog)(
+ struct _cef_jsdialog_handler_t* self,
+ struct _cef_browser_t* browser,
+ const cef_string_t* message_text,
+ int is_reload,
+ struct _cef_jsdialog_callback_t* callback);
+
+ ///
+ /// Called to cancel any pending dialogs and reset any saved dialog state.
+ /// Will be called due to events like page navigation irregardless of whether
+ /// any dialogs are currently pending.
+ ///
+ void(CEF_CALLBACK* on_reset_dialog_state)(
+ struct _cef_jsdialog_handler_t* self,
+ struct _cef_browser_t* browser);
+
+ ///
+ /// Called when the dialog is closed.
+ ///
+ void(CEF_CALLBACK* on_dialog_closed)(struct _cef_jsdialog_handler_t* self,
+ struct _cef_browser_t* browser);
+} cef_jsdialog_handler_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_JSDIALOG_HANDLER_CAPI_H_
diff --git a/include/capi/cef_keyboard_handler_capi.h b/include/capi/cef_keyboard_handler_capi.h
new file mode 100644
index 00000000..7ff37b46
--- /dev/null
+++ b/include/capi/cef_keyboard_handler_capi.h
@@ -0,0 +1,90 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=10fb708c5f550403205a976924abf1886bf3dfa7$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_KEYBOARD_HANDLER_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_KEYBOARD_HANDLER_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+#include "include/capi/cef_browser_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Implement this structure to handle events related to keyboard input. The
+/// functions of this structure will be called on the UI thread.
+///
+typedef struct _cef_keyboard_handler_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Called before a keyboard event is sent to the renderer. |event| contains
+ /// information about the keyboard event. |os_event| is the operating system
+ /// event message, if any. Return true (1) if the event was handled or false
+ /// (0) otherwise. If the event will be handled in on_key_event() as a
+ /// keyboard shortcut set |is_keyboard_shortcut| to true (1) and return false
+ /// (0).
+ ///
+ int(CEF_CALLBACK* on_pre_key_event)(struct _cef_keyboard_handler_t* self,
+ struct _cef_browser_t* browser,
+ const cef_key_event_t* event,
+ cef_event_handle_t os_event,
+ int* is_keyboard_shortcut);
+
+ ///
+ /// Called after the renderer and JavaScript in the page has had a chance to
+ /// handle the event. |event| contains information about the keyboard event.
+ /// |os_event| is the operating system event message, if any. Return true (1)
+ /// if the keyboard event was handled or false (0) otherwise.
+ ///
+ int(CEF_CALLBACK* on_key_event)(struct _cef_keyboard_handler_t* self,
+ struct _cef_browser_t* browser,
+ const cef_key_event_t* event,
+ cef_event_handle_t os_event);
+} cef_keyboard_handler_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_KEYBOARD_HANDLER_CAPI_H_
diff --git a/include/capi/cef_life_span_handler_capi.h b/include/capi/cef_life_span_handler_capi.h
new file mode 100644
index 00000000..f02ea6a4
--- /dev/null
+++ b/include/capi/cef_life_span_handler_capi.h
@@ -0,0 +1,225 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=1c807597b96889f44a1e5199e860e8db4948b473$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_LIFE_SPAN_HANDLER_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_LIFE_SPAN_HANDLER_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+#include "include/capi/cef_browser_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _cef_client_t;
+
+///
+/// Implement this structure to handle events related to browser life span. The
+/// functions of this structure will be called on the UI thread unless otherwise
+/// indicated.
+///
+typedef struct _cef_life_span_handler_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Called on the UI thread before a new popup browser is created. The
+ /// |browser| and |frame| values represent the source of the popup request.
+ /// The |target_url| and |target_frame_name| values indicate where the popup
+ /// browser should navigate and may be NULL if not specified with the request.
+ /// The |target_disposition| value indicates where the user intended to open
+ /// the popup (e.g. current tab, new tab, etc). The |user_gesture| value will
+ /// be true (1) if the popup was opened via explicit user gesture (e.g.
+ /// clicking a link) or false (0) if the popup opened automatically (e.g. via
+ /// the DomContentLoaded event). The |popupFeatures| structure contains
+ /// additional information about the requested popup window. To allow creation
+ /// of the popup browser optionally modify |windowInfo|, |client|, |settings|
+ /// and |no_javascript_access| and return false (0). To cancel creation of the
+ /// popup browser return true (1). The |client| and |settings| values will
+ /// default to the source browser's values. If the |no_javascript_access|
+ /// value is set to false (0) the new browser will not be scriptable and may
+ /// not be hosted in the same renderer process as the source browser. Any
+ /// modifications to |windowInfo| will be ignored if the parent browser is
+ /// wrapped in a cef_browser_view_t. Popup browser creation will be canceled
+ /// if the parent browser is destroyed before the popup browser creation
+ /// completes (indicated by a call to OnAfterCreated for the popup browser).
+ /// The |extra_info| parameter provides an opportunity to specify extra
+ /// information specific to the created popup browser that will be passed to
+ /// cef_render_process_handler_t::on_browser_created() in the render process.
+ ///
+ int(CEF_CALLBACK* on_before_popup)(
+ struct _cef_life_span_handler_t* self,
+ struct _cef_browser_t* browser,
+ struct _cef_frame_t* frame,
+ const cef_string_t* target_url,
+ const cef_string_t* target_frame_name,
+ cef_window_open_disposition_t target_disposition,
+ int user_gesture,
+ const cef_popup_features_t* popupFeatures,
+ struct _cef_window_info_t* windowInfo,
+ struct _cef_client_t** client,
+ struct _cef_browser_settings_t* settings,
+ struct _cef_dictionary_value_t** extra_info,
+ int* no_javascript_access);
+
+ ///
+ /// Called after a new browser is created. It is now safe to begin performing
+ /// actions with |browser|. cef_frame_handler_t callbacks related to initial
+ /// main frame creation will arrive before this callback. See
+ /// cef_frame_handler_t documentation for additional usage information.
+ ///
+ void(CEF_CALLBACK* on_after_created)(struct _cef_life_span_handler_t* self,
+ struct _cef_browser_t* browser);
+
+ ///
+ /// Called when a browser has recieved a request to close. This may result
+ /// directly from a call to cef_browser_host_t::*close_browser() or indirectly
+ /// if the browser is parented to a top-level window created by CEF and the
+ /// user attempts to close that window (by clicking the 'X', for example). The
+ /// do_close() function will be called after the JavaScript 'onunload' event
+ /// has been fired.
+ ///
+ /// An application should handle top-level owner window close notifications by
+ /// calling cef_browser_host_t::try_close_browser() or
+ /// cef_browser_host_t::CloseBrowser(false (0)) instead of allowing the window
+ /// to close immediately (see the examples below). This gives CEF an
+ /// opportunity to process the 'onbeforeunload' event and optionally cancel
+ /// the close before do_close() is called.
+ ///
+ /// When windowed rendering is enabled CEF will internally create a window or
+ /// view to host the browser. In that case returning false (0) from do_close()
+ /// will send the standard close notification to the browser's top-level owner
+ /// window (e.g. WM_CLOSE on Windows, performClose: on OS X, "delete_event" on
+ /// Linux or cef_window_delegate_t::can_close() callback from Views). If the
+ /// browser's host window/view has already been destroyed (via view hierarchy
+ /// tear-down, for example) then do_close() will not be called for that
+ /// browser since is no longer possible to cancel the close.
+ ///
+ /// When windowed rendering is disabled returning false (0) from do_close()
+ /// will cause the browser object to be destroyed immediately.
+ ///
+ /// If the browser's top-level owner window requires a non-standard close
+ /// notification then send that notification from do_close() and return true
+ /// (1).
+ ///
+ /// The cef_life_span_handler_t::on_before_close() function will be called
+ /// after do_close() (if do_close() is called) and immediately before the
+ /// browser object is destroyed. The application should only exit after
+ /// on_before_close() has been called for all existing browsers.
+ ///
+ /// The below examples describe what should happen during window close when
+ /// the browser is parented to an application-provided top-level window.
+ ///
+ /// Example 1: Using cef_browser_host_t::try_close_browser(). This is
+ /// recommended for clients using standard close handling and windows created
+ /// on the browser process UI thread. 1. User clicks the window close button
+ /// which sends a close notification
+ /// to the application's top-level window.
+ /// 2. Application's top-level window receives the close notification and
+ /// calls TryCloseBrowser() (which internally calls CloseBrowser(false)).
+ /// TryCloseBrowser() returns false so the client cancels the window
+ /// close.
+ /// 3. JavaScript 'onbeforeunload' handler executes and shows the close
+ /// confirmation dialog (which can be overridden via
+ /// CefJSDialogHandler::OnBeforeUnloadDialog()).
+ /// 4. User approves the close. 5. JavaScript 'onunload' handler executes.
+ /// 6. CEF sends a close notification to the application's top-level window
+ /// (because DoClose() returned false by default).
+ /// 7. Application's top-level window receives the close notification and
+ /// calls TryCloseBrowser(). TryCloseBrowser() returns true so the client
+ /// allows the window close.
+ /// 8. Application's top-level window is destroyed. 9. Application's
+ /// on_before_close() handler is called and the browser object
+ /// is destroyed.
+ /// 10. Application exits by calling cef_quit_message_loop() if no other
+ /// browsers
+ /// exist.
+ ///
+ /// Example 2: Using cef_browser_host_t::CloseBrowser(false (0)) and
+ /// implementing the do_close() callback. This is recommended for clients
+ /// using non-standard close handling or windows that were not created on the
+ /// browser process UI thread. 1. User clicks the window close button which
+ /// sends a close notification
+ /// to the application's top-level window.
+ /// 2. Application's top-level window receives the close notification and:
+ /// A. Calls CefBrowserHost::CloseBrowser(false).
+ /// B. Cancels the window close.
+ /// 3. JavaScript 'onbeforeunload' handler executes and shows the close
+ /// confirmation dialog (which can be overridden via
+ /// CefJSDialogHandler::OnBeforeUnloadDialog()).
+ /// 4. User approves the close. 5. JavaScript 'onunload' handler executes.
+ /// 6. Application's do_close() handler is called. Application will:
+ /// A. Set a flag to indicate that the next close attempt will be allowed.
+ /// B. Return false.
+ /// 7. CEF sends an close notification to the application's top-level window.
+ /// 8. Application's top-level window receives the close notification and
+ /// allows the window to close based on the flag from #6B.
+ /// 9. Application's top-level window is destroyed. 10. Application's
+ /// on_before_close() handler is called and the browser object
+ /// is destroyed.
+ /// 11. Application exits by calling cef_quit_message_loop() if no other
+ /// browsers
+ /// exist.
+ ///
+ int(CEF_CALLBACK* do_close)(struct _cef_life_span_handler_t* self,
+ struct _cef_browser_t* browser);
+
+ ///
+ /// Called just before a browser is destroyed. Release all references to the
+ /// browser object and do not attempt to execute any functions on the browser
+ /// object (other than IsValid, GetIdentifier or IsSame) after this callback
+ /// returns. cef_frame_handler_t callbacks related to final main frame
+ /// destruction will arrive after this callback and cef_browser_t::IsValid
+ /// will return false (0) at that time. Any in-progress network requests
+ /// associated with |browser| will be aborted when the browser is destroyed,
+ /// and cef_resource_request_handler_t callbacks related to those requests may
+ /// still arrive on the IO thread after this callback. See cef_frame_handler_t
+ /// and do_close() documentation for additional usage information.
+ ///
+ void(CEF_CALLBACK* on_before_close)(struct _cef_life_span_handler_t* self,
+ struct _cef_browser_t* browser);
+} cef_life_span_handler_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_LIFE_SPAN_HANDLER_CAPI_H_
diff --git a/include/capi/cef_load_handler_capi.h b/include/capi/cef_load_handler_capi.h
new file mode 100644
index 00000000..3667b868
--- /dev/null
+++ b/include/capi/cef_load_handler_capi.h
@@ -0,0 +1,126 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=1ee684174554f7d1cf8899992705d072c1c56ae7$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_LOAD_HANDLER_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_LOAD_HANDLER_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+#include "include/capi/cef_browser_capi.h"
+#include "include/capi/cef_frame_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Implement this structure to handle events related to browser load status.
+/// The functions of this structure will be called on the browser process UI
+/// thread or render process main thread (TID_RENDERER).
+///
+typedef struct _cef_load_handler_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Called when the loading state has changed. This callback will be executed
+ /// twice -- once when loading is initiated either programmatically or by user
+ /// action, and once when loading is terminated due to completion,
+ /// cancellation of failure. It will be called before any calls to OnLoadStart
+ /// and after all calls to OnLoadError and/or OnLoadEnd.
+ ///
+ void(CEF_CALLBACK* on_loading_state_change)(struct _cef_load_handler_t* self,
+ struct _cef_browser_t* browser,
+ int isLoading,
+ int canGoBack,
+ int canGoForward);
+
+ ///
+ /// Called after a navigation has been committed and before the browser begins
+ /// loading contents in the frame. The |frame| value will never be NULL --
+ /// call the is_main() function to check if this frame is the main frame.
+ /// |transition_type| provides information about the source of the navigation
+ /// and an accurate value is only available in the browser process. Multiple
+ /// frames may be loading at the same time. Sub-frames may start or continue
+ /// loading after the main frame load has ended. This function will not be
+ /// called for same page navigations (fragments, history state, etc.) or for
+ /// navigations that fail or are canceled before commit. For notification of
+ /// overall browser load status use OnLoadingStateChange instead.
+ ///
+ void(CEF_CALLBACK* on_load_start)(struct _cef_load_handler_t* self,
+ struct _cef_browser_t* browser,
+ struct _cef_frame_t* frame,
+ cef_transition_type_t transition_type);
+
+ ///
+ /// Called when the browser is done loading a frame. The |frame| value will
+ /// never be NULL -- call the is_main() function to check if this frame is the
+ /// main frame. Multiple frames may be loading at the same time. Sub-frames
+ /// may start or continue loading after the main frame load has ended. This
+ /// function will not be called for same page navigations (fragments, history
+ /// state, etc.) or for navigations that fail or are canceled before commit.
+ /// For notification of overall browser load status use OnLoadingStateChange
+ /// instead.
+ ///
+ void(CEF_CALLBACK* on_load_end)(struct _cef_load_handler_t* self,
+ struct _cef_browser_t* browser,
+ struct _cef_frame_t* frame,
+ int httpStatusCode);
+
+ ///
+ /// Called when a navigation fails or is canceled. This function may be called
+ /// by itself if before commit or in combination with OnLoadStart/OnLoadEnd if
+ /// after commit. |errorCode| is the error code number, |errorText| is the
+ /// error text and |failedUrl| is the URL that failed to load. See
+ /// net\base\net_error_list.h for complete descriptions of the error codes.
+ ///
+ void(CEF_CALLBACK* on_load_error)(struct _cef_load_handler_t* self,
+ struct _cef_browser_t* browser,
+ struct _cef_frame_t* frame,
+ cef_errorcode_t errorCode,
+ const cef_string_t* errorText,
+ const cef_string_t* failedUrl);
+} cef_load_handler_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_LOAD_HANDLER_CAPI_H_
diff --git a/include/capi/cef_media_access_handler_capi.h b/include/capi/cef_media_access_handler_capi.h
new file mode 100644
index 00000000..3b8c9a82
--- /dev/null
+++ b/include/capi/cef_media_access_handler_capi.h
@@ -0,0 +1,108 @@
+// Copyright (c) 2022 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=91101808168ec0faf1f39b1924579e31478a6616$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_MEDIA_ACCESS_HANDLER_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_MEDIA_ACCESS_HANDLER_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+#include "include/capi/cef_browser_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+// Callback structure used for asynchronous continuation of media access
+// permission requests.
+///
+typedef struct _cef_media_access_callback_t {
+ ///
+ // Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ // Call to allow or deny media access. If this callback was initiated in
+ // response to a getUserMedia (indicated by
+ // CEF_MEDIA_PERMISSION_DEVICE_AUDIO_CAPTURE and/or
+ // CEF_MEDIA_PERMISSION_DEVICE_VIDEO_CAPTURE being set) the
+ // |allowed_permissions| are required to match those given in
+ // |required_permissions| in the OnRequestMediaAccessPermission.
+ ///
+ void(CEF_CALLBACK* cont)(struct _cef_media_access_callback_t* self,
+ int allowed_permissions);
+
+ ///
+ // Cancel the media access request.
+ ///
+ void(CEF_CALLBACK* cancel)(struct _cef_media_access_callback_t* self);
+} cef_media_access_callback_t;
+
+///
+// Implement this structure to handle events related to media access permission
+// requests. The functions of this structure will be called on the browser
+// process UI thread.
+///
+typedef struct _cef_media_access_handler_t {
+ ///
+ // Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ // Called when a page requests permission to access media. |requesting_url| is
+ // the URL requesting permission. Return true (1) and call
+ // cef_media_access_callback_t::cont() either in this function or at a later
+ // time to continue or cancel the request. Return false (0) to cancel the
+ // request immediately.
+ ///
+ int(CEF_CALLBACK* on_request_media_access_permission)(
+ struct _cef_media_access_handler_t* self,
+ struct _cef_browser_t* browser,
+ struct _cef_frame_t* frame,
+ const cef_string_t* requesting_url,
+ int32_t requested_permissions,
+ struct _cef_media_access_callback_t* callback);
+} cef_media_access_handler_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_MEDIA_ACCESS_HANDLER_CAPI_H_
diff --git a/include/capi/cef_media_router_capi.h b/include/capi/cef_media_router_capi.h
new file mode 100644
index 00000000..27f9d0e1
--- /dev/null
+++ b/include/capi/cef_media_router_capi.h
@@ -0,0 +1,342 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=de4a9b856c6951231f446991a9b1efb89096ad3b$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_MEDIA_ROUTER_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_MEDIA_ROUTER_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+#include "include/capi/cef_callback_capi.h"
+#include "include/capi/cef_registration_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _cef_media_observer_t;
+struct _cef_media_route_create_callback_t;
+struct _cef_media_route_t;
+struct _cef_media_sink_device_info_callback_t;
+struct _cef_media_sink_t;
+struct _cef_media_source_t;
+
+///
+/// Supports discovery of and communication with media devices on the local
+/// network via the Cast and DIAL protocols. The functions of this structure may
+/// be called on any browser process thread unless otherwise indicated.
+///
+typedef struct _cef_media_router_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Add an observer for MediaRouter events. The observer will remain
+ /// registered until the returned Registration object is destroyed.
+ ///
+ struct _cef_registration_t*(CEF_CALLBACK* add_observer)(
+ struct _cef_media_router_t* self,
+ struct _cef_media_observer_t* observer);
+
+ ///
+ /// Returns a MediaSource object for the specified media source URN. Supported
+ /// URN schemes include "cast:" and "dial:", and will be already known by the
+ /// client application (e.g. "cast:<appId>?clientId=<clientId>").
+ ///
+ struct _cef_media_source_t*(CEF_CALLBACK* get_source)(
+ struct _cef_media_router_t* self,
+ const cef_string_t* urn);
+
+ ///
+ /// Trigger an asynchronous call to cef_media_observer_t::OnSinks on all
+ /// registered observers.
+ ///
+ void(CEF_CALLBACK* notify_current_sinks)(struct _cef_media_router_t* self);
+
+ ///
+ /// Create a new route between |source| and |sink|. Source and sink must be
+ /// valid, compatible (as reported by cef_media_sink_t::IsCompatibleWith), and
+ /// a route between them must not already exist. |callback| will be executed
+ /// on success or failure. If route creation succeeds it will also trigger an
+ /// asynchronous call to cef_media_observer_t::OnRoutes on all registered
+ /// observers.
+ ///
+ void(CEF_CALLBACK* create_route)(
+ struct _cef_media_router_t* self,
+ struct _cef_media_source_t* source,
+ struct _cef_media_sink_t* sink,
+ struct _cef_media_route_create_callback_t* callback);
+
+ ///
+ /// Trigger an asynchronous call to cef_media_observer_t::OnRoutes on all
+ /// registered observers.
+ ///
+ void(CEF_CALLBACK* notify_current_routes)(struct _cef_media_router_t* self);
+} cef_media_router_t;
+
+///
+/// Returns the MediaRouter object associated with the global request context.
+/// If |callback| is non-NULL it will be executed asnychronously on the UI
+/// thread after the manager's storage has been initialized. Equivalent to
+/// calling cef_request_context_t::cef_request_context_get_global_context()->get
+/// _media_router().
+///
+CEF_EXPORT cef_media_router_t* cef_media_router_get_global(
+ struct _cef_completion_callback_t* callback);
+
+///
+/// Implemented by the client to observe MediaRouter events and registered via
+/// cef_media_router_t::AddObserver. The functions of this structure will be
+/// called on the browser process UI thread.
+///
+typedef struct _cef_media_observer_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// The list of available media sinks has changed or
+ /// cef_media_router_t::NotifyCurrentSinks was called.
+ ///
+ void(CEF_CALLBACK* on_sinks)(struct _cef_media_observer_t* self,
+ size_t sinksCount,
+ struct _cef_media_sink_t* const* sinks);
+
+ ///
+ /// The list of available media routes has changed or
+ /// cef_media_router_t::NotifyCurrentRoutes was called.
+ ///
+ void(CEF_CALLBACK* on_routes)(struct _cef_media_observer_t* self,
+ size_t routesCount,
+ struct _cef_media_route_t* const* routes);
+
+ ///
+ /// The connection state of |route| has changed.
+ ///
+ void(CEF_CALLBACK* on_route_state_changed)(
+ struct _cef_media_observer_t* self,
+ struct _cef_media_route_t* route,
+ cef_media_route_connection_state_t state);
+
+ ///
+ /// A message was recieved over |route|. |message| is only valid for the scope
+ /// of this callback and should be copied if necessary.
+ ///
+ void(CEF_CALLBACK* on_route_message_received)(
+ struct _cef_media_observer_t* self,
+ struct _cef_media_route_t* route,
+ const void* message,
+ size_t message_size);
+} cef_media_observer_t;
+
+///
+/// Represents the route between a media source and sink. Instances of this
+/// object are created via cef_media_router_t::CreateRoute and retrieved via
+/// cef_media_observer_t::OnRoutes. Contains the status and metadata of a
+/// routing operation. The functions of this structure may be called on any
+/// browser process thread unless otherwise indicated.
+///
+typedef struct _cef_media_route_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Returns the ID for this route.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_id)(struct _cef_media_route_t* self);
+
+ ///
+ /// Returns the source associated with this route.
+ ///
+ struct _cef_media_source_t*(CEF_CALLBACK* get_source)(
+ struct _cef_media_route_t* self);
+
+ ///
+ /// Returns the sink associated with this route.
+ ///
+ struct _cef_media_sink_t*(CEF_CALLBACK* get_sink)(
+ struct _cef_media_route_t* self);
+
+ ///
+ /// Send a message over this route. |message| will be copied if necessary.
+ ///
+ void(CEF_CALLBACK* send_route_message)(struct _cef_media_route_t* self,
+ const void* message,
+ size_t message_size);
+
+ ///
+ /// Terminate this route. Will result in an asynchronous call to
+ /// cef_media_observer_t::OnRoutes on all registered observers.
+ ///
+ void(CEF_CALLBACK* terminate)(struct _cef_media_route_t* self);
+} cef_media_route_t;
+
+///
+/// Callback structure for cef_media_router_t::CreateRoute. The functions of
+/// this structure will be called on the browser process UI thread.
+///
+typedef struct _cef_media_route_create_callback_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Method that will be executed when the route creation has finished.
+ /// |result| will be CEF_MRCR_OK if the route creation succeeded. |error| will
+ /// be a description of the error if the route creation failed. |route| is the
+ /// resulting route, or NULL if the route creation failed.
+ ///
+ void(CEF_CALLBACK* on_media_route_create_finished)(
+ struct _cef_media_route_create_callback_t* self,
+ cef_media_route_create_result_t result,
+ const cef_string_t* error,
+ struct _cef_media_route_t* route);
+} cef_media_route_create_callback_t;
+
+///
+/// Represents a sink to which media can be routed. Instances of this object are
+/// retrieved via cef_media_observer_t::OnSinks. The functions of this structure
+/// may be called on any browser process thread unless otherwise indicated.
+///
+typedef struct _cef_media_sink_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Returns the ID for this sink.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_id)(struct _cef_media_sink_t* self);
+
+ ///
+ /// Returns the name of this sink.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_name)(struct _cef_media_sink_t* self);
+
+ ///
+ /// Returns the icon type for this sink.
+ ///
+ cef_media_sink_icon_type_t(CEF_CALLBACK* get_icon_type)(
+ struct _cef_media_sink_t* self);
+
+ ///
+ /// Asynchronously retrieves device info.
+ ///
+ void(CEF_CALLBACK* get_device_info)(
+ struct _cef_media_sink_t* self,
+ struct _cef_media_sink_device_info_callback_t* callback);
+
+ ///
+ /// Returns true (1) if this sink accepts content via Cast.
+ ///
+ int(CEF_CALLBACK* is_cast_sink)(struct _cef_media_sink_t* self);
+
+ ///
+ /// Returns true (1) if this sink accepts content via DIAL.
+ ///
+ int(CEF_CALLBACK* is_dial_sink)(struct _cef_media_sink_t* self);
+
+ ///
+ /// Returns true (1) if this sink is compatible with |source|.
+ ///
+ int(CEF_CALLBACK* is_compatible_with)(struct _cef_media_sink_t* self,
+ struct _cef_media_source_t* source);
+} cef_media_sink_t;
+
+///
+/// Callback structure for cef_media_sink_t::GetDeviceInfo. The functions of
+/// this structure will be called on the browser process UI thread.
+///
+typedef struct _cef_media_sink_device_info_callback_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Method that will be executed asyncronously once device information has
+ /// been retrieved.
+ ///
+ void(CEF_CALLBACK* on_media_sink_device_info)(
+ struct _cef_media_sink_device_info_callback_t* self,
+ const struct _cef_media_sink_device_info_t* device_info);
+} cef_media_sink_device_info_callback_t;
+
+///
+/// Represents a source from which media can be routed. Instances of this object
+/// are retrieved via cef_media_router_t::GetSource. The functions of this
+/// structure may be called on any browser process thread unless otherwise
+/// indicated.
+///
+typedef struct _cef_media_source_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Returns the ID (media source URN or URL) for this source.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_id)(struct _cef_media_source_t* self);
+
+ ///
+ /// Returns true (1) if this source outputs its content via Cast.
+ ///
+ int(CEF_CALLBACK* is_cast_source)(struct _cef_media_source_t* self);
+
+ ///
+ /// Returns true (1) if this source outputs its content via DIAL.
+ ///
+ int(CEF_CALLBACK* is_dial_source)(struct _cef_media_source_t* self);
+} cef_media_source_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_MEDIA_ROUTER_CAPI_H_
diff --git a/include/capi/cef_menu_model_capi.h b/include/capi/cef_menu_model_capi.h
new file mode 100644
index 00000000..8b5bd663
--- /dev/null
+++ b/include/capi/cef_menu_model_capi.h
@@ -0,0 +1,517 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=d70b78b8108bb08b4f53b2627ed4ebfdffece7c1$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_MENU_MODEL_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_MENU_MODEL_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+#include "include/capi/cef_menu_model_delegate_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Supports creation and modification of menus. See cef_menu_id_t for the
+/// command ids that have default implementations. All user-defined command ids
+/// should be between MENU_ID_USER_FIRST and MENU_ID_USER_LAST. The functions of
+/// this structure can only be accessed on the browser process the UI thread.
+///
+typedef struct _cef_menu_model_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Returns true (1) if this menu is a submenu.
+ ///
+ int(CEF_CALLBACK* is_sub_menu)(struct _cef_menu_model_t* self);
+
+ ///
+ /// Clears the menu. Returns true (1) on success.
+ ///
+ int(CEF_CALLBACK* clear)(struct _cef_menu_model_t* self);
+
+ ///
+ /// Returns the number of items in this menu.
+ ///
+ size_t(CEF_CALLBACK* get_count)(struct _cef_menu_model_t* self);
+
+ ///
+ /// Add a separator to the menu. Returns true (1) on success.
+ ///
+ int(CEF_CALLBACK* add_separator)(struct _cef_menu_model_t* self);
+
+ ///
+ /// Add an item to the menu. Returns true (1) on success.
+ ///
+ int(CEF_CALLBACK* add_item)(struct _cef_menu_model_t* self,
+ int command_id,
+ const cef_string_t* label);
+
+ ///
+ /// Add a check item to the menu. Returns true (1) on success.
+ ///
+ int(CEF_CALLBACK* add_check_item)(struct _cef_menu_model_t* self,
+ int command_id,
+ const cef_string_t* label);
+
+ ///
+ /// Add a radio item to the menu. Only a single item with the specified
+ /// |group_id| can be checked at a time. Returns true (1) on success.
+ ///
+ int(CEF_CALLBACK* add_radio_item)(struct _cef_menu_model_t* self,
+ int command_id,
+ const cef_string_t* label,
+ int group_id);
+
+ ///
+ /// Add a sub-menu to the menu. The new sub-menu is returned.
+ ///
+ struct _cef_menu_model_t*(CEF_CALLBACK* add_sub_menu)(
+ struct _cef_menu_model_t* self,
+ int command_id,
+ const cef_string_t* label);
+
+ ///
+ /// Insert a separator in the menu at the specified |index|. Returns true (1)
+ /// on success.
+ ///
+ int(CEF_CALLBACK* insert_separator_at)(struct _cef_menu_model_t* self,
+ size_t index);
+
+ ///
+ /// Insert an item in the menu at the specified |index|. Returns true (1) on
+ /// success.
+ ///
+ int(CEF_CALLBACK* insert_item_at)(struct _cef_menu_model_t* self,
+ size_t index,
+ int command_id,
+ const cef_string_t* label);
+
+ ///
+ /// Insert a check item in the menu at the specified |index|. Returns true (1)
+ /// on success.
+ ///
+ int(CEF_CALLBACK* insert_check_item_at)(struct _cef_menu_model_t* self,
+ size_t index,
+ int command_id,
+ const cef_string_t* label);
+
+ ///
+ /// Insert a radio item in the menu at the specified |index|. Only a single
+ /// item with the specified |group_id| can be checked at a time. Returns true
+ /// (1) on success.
+ ///
+ int(CEF_CALLBACK* insert_radio_item_at)(struct _cef_menu_model_t* self,
+ size_t index,
+ int command_id,
+ const cef_string_t* label,
+ int group_id);
+
+ ///
+ /// Insert a sub-menu in the menu at the specified |index|. The new sub-menu
+ /// is returned.
+ ///
+ struct _cef_menu_model_t*(CEF_CALLBACK* insert_sub_menu_at)(
+ struct _cef_menu_model_t* self,
+ size_t index,
+ int command_id,
+ const cef_string_t* label);
+
+ ///
+ /// Removes the item with the specified |command_id|. Returns true (1) on
+ /// success.
+ ///
+ int(CEF_CALLBACK* remove)(struct _cef_menu_model_t* self, int command_id);
+
+ ///
+ /// Removes the item at the specified |index|. Returns true (1) on success.
+ ///
+ int(CEF_CALLBACK* remove_at)(struct _cef_menu_model_t* self, size_t index);
+
+ ///
+ /// Returns the index associated with the specified |command_id| or -1 if not
+ /// found due to the command id not existing in the menu.
+ ///
+ int(CEF_CALLBACK* get_index_of)(struct _cef_menu_model_t* self,
+ int command_id);
+
+ ///
+ /// Returns the command id at the specified |index| or -1 if not found due to
+ /// invalid range or the index being a separator.
+ ///
+ int(CEF_CALLBACK* get_command_id_at)(struct _cef_menu_model_t* self,
+ size_t index);
+
+ ///
+ /// Sets the command id at the specified |index|. Returns true (1) on success.
+ ///
+ int(CEF_CALLBACK* set_command_id_at)(struct _cef_menu_model_t* self,
+ size_t index,
+ int command_id);
+
+ ///
+ /// Returns the label for the specified |command_id| or NULL if not found.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_label)(struct _cef_menu_model_t* self,
+ int command_id);
+
+ ///
+ /// Returns the label at the specified |index| or NULL if not found due to
+ /// invalid range or the index being a separator.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(
+ CEF_CALLBACK* get_label_at)(struct _cef_menu_model_t* self, size_t index);
+
+ ///
+ /// Sets the label for the specified |command_id|. Returns true (1) on
+ /// success.
+ ///
+ int(CEF_CALLBACK* set_label)(struct _cef_menu_model_t* self,
+ int command_id,
+ const cef_string_t* label);
+
+ ///
+ /// Set the label at the specified |index|. Returns true (1) on success.
+ ///
+ int(CEF_CALLBACK* set_label_at)(struct _cef_menu_model_t* self,
+ size_t index,
+ const cef_string_t* label);
+
+ ///
+ /// Returns the item type for the specified |command_id|.
+ ///
+ cef_menu_item_type_t(CEF_CALLBACK* get_type)(struct _cef_menu_model_t* self,
+ int command_id);
+
+ ///
+ /// Returns the item type at the specified |index|.
+ ///
+ cef_menu_item_type_t(
+ CEF_CALLBACK* get_type_at)(struct _cef_menu_model_t* self, size_t index);
+
+ ///
+ /// Returns the group id for the specified |command_id| or -1 if invalid.
+ ///
+ int(CEF_CALLBACK* get_group_id)(struct _cef_menu_model_t* self,
+ int command_id);
+
+ ///
+ /// Returns the group id at the specified |index| or -1 if invalid.
+ ///
+ int(CEF_CALLBACK* get_group_id_at)(struct _cef_menu_model_t* self,
+ size_t index);
+
+ ///
+ /// Sets the group id for the specified |command_id|. Returns true (1) on
+ /// success.
+ ///
+ int(CEF_CALLBACK* set_group_id)(struct _cef_menu_model_t* self,
+ int command_id,
+ int group_id);
+
+ ///
+ /// Sets the group id at the specified |index|. Returns true (1) on success.
+ ///
+ int(CEF_CALLBACK* set_group_id_at)(struct _cef_menu_model_t* self,
+ size_t index,
+ int group_id);
+
+ ///
+ /// Returns the submenu for the specified |command_id| or NULL if invalid.
+ ///
+ struct _cef_menu_model_t*(CEF_CALLBACK* get_sub_menu)(
+ struct _cef_menu_model_t* self,
+ int command_id);
+
+ ///
+ /// Returns the submenu at the specified |index| or NULL if invalid.
+ ///
+ struct _cef_menu_model_t*(CEF_CALLBACK* get_sub_menu_at)(
+ struct _cef_menu_model_t* self,
+ size_t index);
+
+ ///
+ /// Returns true (1) if the specified |command_id| is visible.
+ ///
+ int(CEF_CALLBACK* is_visible)(struct _cef_menu_model_t* self, int command_id);
+
+ ///
+ /// Returns true (1) if the specified |index| is visible.
+ ///
+ int(CEF_CALLBACK* is_visible_at)(struct _cef_menu_model_t* self,
+ size_t index);
+
+ ///
+ /// Change the visibility of the specified |command_id|. Returns true (1) on
+ /// success.
+ ///
+ int(CEF_CALLBACK* set_visible)(struct _cef_menu_model_t* self,
+ int command_id,
+ int visible);
+
+ ///
+ /// Change the visibility at the specified |index|. Returns true (1) on
+ /// success.
+ ///
+ int(CEF_CALLBACK* set_visible_at)(struct _cef_menu_model_t* self,
+ size_t index,
+ int visible);
+
+ ///
+ /// Returns true (1) if the specified |command_id| is enabled.
+ ///
+ int(CEF_CALLBACK* is_enabled)(struct _cef_menu_model_t* self, int command_id);
+
+ ///
+ /// Returns true (1) if the specified |index| is enabled.
+ ///
+ int(CEF_CALLBACK* is_enabled_at)(struct _cef_menu_model_t* self,
+ size_t index);
+
+ ///
+ /// Change the enabled status of the specified |command_id|. Returns true (1)
+ /// on success.
+ ///
+ int(CEF_CALLBACK* set_enabled)(struct _cef_menu_model_t* self,
+ int command_id,
+ int enabled);
+
+ ///
+ /// Change the enabled status at the specified |index|. Returns true (1) on
+ /// success.
+ ///
+ int(CEF_CALLBACK* set_enabled_at)(struct _cef_menu_model_t* self,
+ size_t index,
+ int enabled);
+
+ ///
+ /// Returns true (1) if the specified |command_id| is checked. Only applies to
+ /// check and radio items.
+ ///
+ int(CEF_CALLBACK* is_checked)(struct _cef_menu_model_t* self, int command_id);
+
+ ///
+ /// Returns true (1) if the specified |index| is checked. Only applies to
+ /// check and radio items.
+ ///
+ int(CEF_CALLBACK* is_checked_at)(struct _cef_menu_model_t* self,
+ size_t index);
+
+ ///
+ /// Check the specified |command_id|. Only applies to check and radio items.
+ /// Returns true (1) on success.
+ ///
+ int(CEF_CALLBACK* set_checked)(struct _cef_menu_model_t* self,
+ int command_id,
+ int checked);
+
+ ///
+ /// Check the specified |index|. Only applies to check and radio items.
+ /// Returns true (1) on success.
+ ///
+ int(CEF_CALLBACK* set_checked_at)(struct _cef_menu_model_t* self,
+ size_t index,
+ int checked);
+
+ ///
+ /// Returns true (1) if the specified |command_id| has a keyboard accelerator
+ /// assigned.
+ ///
+ int(CEF_CALLBACK* has_accelerator)(struct _cef_menu_model_t* self,
+ int command_id);
+
+ ///
+ /// Returns true (1) if the specified |index| has a keyboard accelerator
+ /// assigned.
+ ///
+ int(CEF_CALLBACK* has_accelerator_at)(struct _cef_menu_model_t* self,
+ size_t index);
+
+ ///
+ /// Set the keyboard accelerator for the specified |command_id|. |key_code|
+ /// can be any virtual key or character value. Returns true (1) on success.
+ ///
+ int(CEF_CALLBACK* set_accelerator)(struct _cef_menu_model_t* self,
+ int command_id,
+ int key_code,
+ int shift_pressed,
+ int ctrl_pressed,
+ int alt_pressed);
+
+ ///
+ /// Set the keyboard accelerator at the specified |index|. |key_code| can be
+ /// any virtual key or character value. Returns true (1) on success.
+ ///
+ int(CEF_CALLBACK* set_accelerator_at)(struct _cef_menu_model_t* self,
+ size_t index,
+ int key_code,
+ int shift_pressed,
+ int ctrl_pressed,
+ int alt_pressed);
+
+ ///
+ /// Remove the keyboard accelerator for the specified |command_id|. Returns
+ /// true (1) on success.
+ ///
+ int(CEF_CALLBACK* remove_accelerator)(struct _cef_menu_model_t* self,
+ int command_id);
+
+ ///
+ /// Remove the keyboard accelerator at the specified |index|. Returns true (1)
+ /// on success.
+ ///
+ int(CEF_CALLBACK* remove_accelerator_at)(struct _cef_menu_model_t* self,
+ size_t index);
+
+ ///
+ /// Retrieves the keyboard accelerator for the specified |command_id|. Returns
+ /// true (1) on success.
+ ///
+ int(CEF_CALLBACK* get_accelerator)(struct _cef_menu_model_t* self,
+ int command_id,
+ int* key_code,
+ int* shift_pressed,
+ int* ctrl_pressed,
+ int* alt_pressed);
+
+ ///
+ /// Retrieves the keyboard accelerator for the specified |index|. Returns true
+ /// (1) on success.
+ ///
+ int(CEF_CALLBACK* get_accelerator_at)(struct _cef_menu_model_t* self,
+ size_t index,
+ int* key_code,
+ int* shift_pressed,
+ int* ctrl_pressed,
+ int* alt_pressed);
+
+ ///
+ /// Set the explicit color for |command_id| and |color_type| to |color|.
+ /// Specify a |color| value of 0 to remove the explicit color. If no explicit
+ /// color or default color is set for |color_type| then the system color will
+ /// be used. Returns true (1) on success.
+ ///
+ int(CEF_CALLBACK* set_color)(struct _cef_menu_model_t* self,
+ int command_id,
+ cef_menu_color_type_t color_type,
+ cef_color_t color);
+
+ ///
+ /// Set the explicit color for |command_id| and |index| to |color|. Specify a
+ /// |color| value of 0 to remove the explicit color. Specify an |index| value
+ /// of -1 to set the default color for items that do not have an explicit
+ /// color set. If no explicit color or default color is set for |color_type|
+ /// then the system color will be used. Returns true (1) on success.
+ ///
+ int(CEF_CALLBACK* set_color_at)(struct _cef_menu_model_t* self,
+ int index,
+ cef_menu_color_type_t color_type,
+ cef_color_t color);
+
+ ///
+ /// Returns in |color| the color that was explicitly set for |command_id| and
+ /// |color_type|. If a color was not set then 0 will be returned in |color|.
+ /// Returns true (1) on success.
+ ///
+ int(CEF_CALLBACK* get_color)(struct _cef_menu_model_t* self,
+ int command_id,
+ cef_menu_color_type_t color_type,
+ cef_color_t* color);
+
+ ///
+ /// Returns in |color| the color that was explicitly set for |command_id| and
+ /// |color_type|. Specify an |index| value of -1 to return the default color
+ /// in |color|. If a color was not set then 0 will be returned in |color|.
+ /// Returns true (1) on success.
+ ///
+ int(CEF_CALLBACK* get_color_at)(struct _cef_menu_model_t* self,
+ int index,
+ cef_menu_color_type_t color_type,
+ cef_color_t* color);
+
+ ///
+ /// Sets the font list for the specified |command_id|. If |font_list| is NULL
+ /// the system font will be used. Returns true (1) on success. The format is
+ /// "<FONT_FAMILY_LIST>,[STYLES] <SIZE>", where: - FONT_FAMILY_LIST is a
+ /// comma-separated list of font family names, - STYLES is an optional space-
+ /// separated list of style names
+ /// (case-sensitive "Bold" and "Italic" are supported), and
+ /// - SIZE is an integer font size in pixels with the suffix "px".
+ ///
+ /// Here are examples of valid font description strings: - "Arial, Helvetica,
+ /// Bold Italic 14px" - "Arial, 14px"
+ ///
+ int(CEF_CALLBACK* set_font_list)(struct _cef_menu_model_t* self,
+ int command_id,
+ const cef_string_t* font_list);
+
+ ///
+ /// Sets the font list for the specified |index|. Specify an |index| value of
+ /// -1 to set the default font. If |font_list| is NULL the system font will be
+ /// used. Returns true (1) on success. The format is
+ /// "<FONT_FAMILY_LIST>,[STYLES] <SIZE>", where: - FONT_FAMILY_LIST is a
+ /// comma-separated list of font family names, - STYLES is an optional space-
+ /// separated list of style names
+ /// (case-sensitive "Bold" and "Italic" are supported), and
+ /// - SIZE is an integer font size in pixels with the suffix "px".
+ ///
+ /// Here are examples of valid font description strings: - "Arial, Helvetica,
+ /// Bold Italic 14px" - "Arial, 14px"
+ ///
+ int(CEF_CALLBACK* set_font_list_at)(struct _cef_menu_model_t* self,
+ int index,
+ const cef_string_t* font_list);
+} cef_menu_model_t;
+
+///
+/// Create a new MenuModel with the specified |delegate|.
+///
+CEF_EXPORT cef_menu_model_t* cef_menu_model_create(
+ struct _cef_menu_model_delegate_t* delegate);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_MENU_MODEL_CAPI_H_
diff --git a/include/capi/cef_menu_model_delegate_capi.h b/include/capi/cef_menu_model_delegate_capi.h
new file mode 100644
index 00000000..dd339c19
--- /dev/null
+++ b/include/capi/cef_menu_model_delegate_capi.h
@@ -0,0 +1,123 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=933a90dfb7b94a3aba7f2944e4540662dc8c79d7$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_MENU_MODEL_DELEGATE_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_MENU_MODEL_DELEGATE_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _cef_menu_model_t;
+
+///
+/// Implement this structure to handle menu model events. The functions of this
+/// structure will be called on the browser process UI thread unless otherwise
+/// indicated.
+///
+typedef struct _cef_menu_model_delegate_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Perform the action associated with the specified |command_id| and optional
+ /// |event_flags|.
+ ///
+ void(CEF_CALLBACK* execute_command)(struct _cef_menu_model_delegate_t* self,
+ struct _cef_menu_model_t* menu_model,
+ int command_id,
+ cef_event_flags_t event_flags);
+
+ ///
+ /// Called when the user moves the mouse outside the menu and over the owning
+ /// window.
+ ///
+ void(CEF_CALLBACK* mouse_outside_menu)(
+ struct _cef_menu_model_delegate_t* self,
+ struct _cef_menu_model_t* menu_model,
+ const cef_point_t* screen_point);
+
+ ///
+ /// Called on unhandled open submenu keyboard commands. |is_rtl| will be true
+ /// (1) if the menu is displaying a right-to-left language.
+ ///
+ void(CEF_CALLBACK* unhandled_open_submenu)(
+ struct _cef_menu_model_delegate_t* self,
+ struct _cef_menu_model_t* menu_model,
+ int is_rtl);
+
+ ///
+ /// Called on unhandled close submenu keyboard commands. |is_rtl| will be true
+ /// (1) if the menu is displaying a right-to-left language.
+ ///
+ void(CEF_CALLBACK* unhandled_close_submenu)(
+ struct _cef_menu_model_delegate_t* self,
+ struct _cef_menu_model_t* menu_model,
+ int is_rtl);
+
+ ///
+ /// The menu is about to show.
+ ///
+ void(CEF_CALLBACK* menu_will_show)(struct _cef_menu_model_delegate_t* self,
+ struct _cef_menu_model_t* menu_model);
+
+ ///
+ /// The menu has closed.
+ ///
+ void(CEF_CALLBACK* menu_closed)(struct _cef_menu_model_delegate_t* self,
+ struct _cef_menu_model_t* menu_model);
+
+ ///
+ /// Optionally modify a menu item label. Return true (1) if |label| was
+ /// modified.
+ ///
+ int(CEF_CALLBACK* format_label)(struct _cef_menu_model_delegate_t* self,
+ struct _cef_menu_model_t* menu_model,
+ cef_string_t* label);
+} cef_menu_model_delegate_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_MENU_MODEL_DELEGATE_CAPI_H_
diff --git a/include/capi/cef_navigation_entry_capi.h b/include/capi/cef_navigation_entry_capi.h
new file mode 100644
index 00000000..863c11d4
--- /dev/null
+++ b/include/capi/cef_navigation_entry_capi.h
@@ -0,0 +1,133 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=d33771c31b7b0964aa2ccf1c2bc2ca1226194977$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_NAVIGATION_ENTRY_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_NAVIGATION_ENTRY_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+#include "include/capi/cef_ssl_status_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Structure used to represent an entry in navigation history.
+///
+typedef struct _cef_navigation_entry_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Returns true (1) if this object is valid. Do not call any other functions
+ /// if this function returns false (0).
+ ///
+ int(CEF_CALLBACK* is_valid)(struct _cef_navigation_entry_t* self);
+
+ ///
+ /// Returns the actual URL of the page. For some pages this may be data: URL
+ /// or similar. Use get_display_url() to return a display-friendly version.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_url)(
+ struct _cef_navigation_entry_t* self);
+
+ ///
+ /// Returns a display-friendly version of the URL.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_display_url)(
+ struct _cef_navigation_entry_t* self);
+
+ ///
+ /// Returns the original URL that was entered by the user before any
+ /// redirects.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_original_url)(
+ struct _cef_navigation_entry_t* self);
+
+ ///
+ /// Returns the title set by the page. This value may be NULL.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_title)(
+ struct _cef_navigation_entry_t* self);
+
+ ///
+ /// Returns the transition type which indicates what the user did to move to
+ /// this page from the previous page.
+ ///
+ cef_transition_type_t(CEF_CALLBACK* get_transition_type)(
+ struct _cef_navigation_entry_t* self);
+
+ ///
+ /// Returns true (1) if this navigation includes post data.
+ ///
+ int(CEF_CALLBACK* has_post_data)(struct _cef_navigation_entry_t* self);
+
+ ///
+ /// Returns the time for the last known successful navigation completion. A
+ /// navigation may be completed more than once if the page is reloaded. May be
+ /// 0 if the navigation has not yet completed.
+ ///
+ cef_basetime_t(CEF_CALLBACK* get_completion_time)(
+ struct _cef_navigation_entry_t* self);
+
+ ///
+ /// Returns the HTTP status code for the last known successful navigation
+ /// response. May be 0 if the response has not yet been received or if the
+ /// navigation has not yet completed.
+ ///
+ int(CEF_CALLBACK* get_http_status_code)(struct _cef_navigation_entry_t* self);
+
+ ///
+ /// Returns the SSL information for this navigation entry.
+ ///
+ struct _cef_sslstatus_t*(CEF_CALLBACK* get_sslstatus)(
+ struct _cef_navigation_entry_t* self);
+} cef_navigation_entry_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_NAVIGATION_ENTRY_CAPI_H_
diff --git a/include/capi/cef_origin_whitelist_capi.h b/include/capi/cef_origin_whitelist_capi.h
new file mode 100644
index 00000000..9b57f38d
--- /dev/null
+++ b/include/capi/cef_origin_whitelist_capi.h
@@ -0,0 +1,112 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=b564dfe24017a0805e393854d12791a71c46c454$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_ORIGIN_WHITELIST_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_ORIGIN_WHITELIST_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Add an entry to the cross-origin access whitelist.
+///
+/// The same-origin policy restricts how scripts hosted from different origins
+/// (scheme + domain + port) can communicate. By default, scripts can only
+/// access resources with the same origin. Scripts hosted on the HTTP and HTTPS
+/// schemes (but no other schemes) can use the "Access-Control-Allow-Origin"
+/// header to allow cross-origin requests. For example,
+/// https://source.example.com can make XMLHttpRequest requests on
+/// http://target.example.com if the http://target.example.com request returns
+/// an "Access-Control-Allow-Origin: https://source.example.com" response
+/// header.
+///
+/// Scripts in separate frames or iframes and hosted from the same protocol and
+/// domain suffix can execute cross-origin JavaScript if both pages set the
+/// document.domain value to the same domain suffix. For example,
+/// scheme://foo.example.com and scheme://bar.example.com can communicate using
+/// JavaScript if both domains set document.domain="example.com".
+///
+/// This function is used to allow access to origins that would otherwise
+/// violate the same-origin policy. Scripts hosted underneath the fully
+/// qualified |source_origin| URL (like http://www.example.com) will be allowed
+/// access to all resources hosted on the specified |target_protocol| and
+/// |target_domain|. If |target_domain| is non-NULL and
+/// |allow_target_subdomains| if false (0) only exact domain matches will be
+/// allowed. If |target_domain| contains a top- level domain component (like
+/// "example.com") and |allow_target_subdomains| is true (1) sub-domain matches
+/// will be allowed. If |target_domain| is NULL and |allow_target_subdomains| if
+/// true (1) all domains and IP addresses will be allowed.
+///
+/// This function cannot be used to bypass the restrictions on local or display
+/// isolated schemes. See the comments on CefRegisterCustomScheme for more
+/// information.
+///
+/// This function may be called on any thread. Returns false (0) if
+/// |source_origin| is invalid or the whitelist cannot be accessed.
+///
+CEF_EXPORT int cef_add_cross_origin_whitelist_entry(
+ const cef_string_t* source_origin,
+ const cef_string_t* target_protocol,
+ const cef_string_t* target_domain,
+ int allow_target_subdomains);
+
+///
+/// Remove an entry from the cross-origin access whitelist. Returns false (0) if
+/// |source_origin| is invalid or the whitelist cannot be accessed.
+///
+CEF_EXPORT int cef_remove_cross_origin_whitelist_entry(
+ const cef_string_t* source_origin,
+ const cef_string_t* target_protocol,
+ const cef_string_t* target_domain,
+ int allow_target_subdomains);
+
+///
+/// Remove all entries from the cross-origin access whitelist. Returns false (0)
+/// if the whitelist cannot be accessed.
+///
+CEF_EXPORT int cef_clear_cross_origin_whitelist(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_ORIGIN_WHITELIST_CAPI_H_
diff --git a/include/capi/cef_parser_capi.h b/include/capi/cef_parser_capi.h
new file mode 100644
index 00000000..a6410c29
--- /dev/null
+++ b/include/capi/cef_parser_capi.h
@@ -0,0 +1,184 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=5d6dad4bfaeef0117d068b6e67a8da7490fe7c2d$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_PARSER_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_PARSER_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Combines specified |base_url| and |relative_url| into |resolved_url|.
+/// Returns false (0) if one of the URLs is NULL or invalid.
+///
+CEF_EXPORT int cef_resolve_url(const cef_string_t* base_url,
+ const cef_string_t* relative_url,
+ cef_string_t* resolved_url);
+
+///
+/// Parse the specified |url| into its component parts. Returns false (0) if the
+/// URL is NULL or invalid.
+///
+CEF_EXPORT int cef_parse_url(const cef_string_t* url,
+ struct _cef_urlparts_t* parts);
+
+///
+/// Creates a URL from the specified |parts|, which must contain a non-NULL spec
+/// or a non-NULL host and path (at a minimum), but not both. Returns false (0)
+/// if |parts| isn't initialized as described.
+///
+CEF_EXPORT int cef_create_url(const struct _cef_urlparts_t* parts,
+ cef_string_t* url);
+
+///
+/// This is a convenience function for formatting a URL in a concise and human-
+/// friendly way to help users make security-related decisions (or in other
+/// circumstances when people need to distinguish sites, origins, or otherwise-
+/// simplified URLs from each other). Internationalized domain names (IDN) may
+/// be presented in Unicode if the conversion is considered safe. The returned
+/// value will (a) omit the path for standard schemes, excepting file and
+/// filesystem, and (b) omit the port if it is the default for the scheme. Do
+/// not use this for URLs which will be parsed or sent to other applications.
+///
+// The resulting string must be freed by calling cef_string_userfree_free().
+CEF_EXPORT cef_string_userfree_t
+cef_format_url_for_security_display(const cef_string_t* origin_url);
+
+///
+/// Returns the mime type for the specified file extension or an NULL string if
+/// unknown.
+///
+// The resulting string must be freed by calling cef_string_userfree_free().
+CEF_EXPORT cef_string_userfree_t
+cef_get_mime_type(const cef_string_t* extension);
+
+///
+/// Get the extensions associated with the given mime type. This should be
+/// passed in lower case. There could be multiple extensions for a given mime
+/// type, like "html,htm" for "text/html", or "txt,text,html,..." for "text/*".
+/// Any existing elements in the provided vector will not be erased.
+///
+CEF_EXPORT void cef_get_extensions_for_mime_type(const cef_string_t* mime_type,
+ cef_string_list_t extensions);
+
+///
+/// Encodes |data| as a base64 string.
+///
+// The resulting string must be freed by calling cef_string_userfree_free().
+CEF_EXPORT cef_string_userfree_t cef_base64encode(const void* data,
+ size_t data_size);
+
+///
+/// Decodes the base64 encoded string |data|. The returned value will be NULL if
+/// the decoding fails.
+///
+CEF_EXPORT struct _cef_binary_value_t* cef_base64decode(
+ const cef_string_t* data);
+
+///
+/// Escapes characters in |text| which are unsuitable for use as a query
+/// parameter value. Everything except alphanumerics and -_.!~*'() will be
+/// converted to "%XX". If |use_plus| is true (1) spaces will change to "+". The
+/// result is basically the same as encodeURIComponent in Javacript.
+///
+// The resulting string must be freed by calling cef_string_userfree_free().
+CEF_EXPORT cef_string_userfree_t cef_uriencode(const cef_string_t* text,
+ int use_plus);
+
+///
+/// Unescapes |text| and returns the result. Unescaping consists of looking for
+/// the exact pattern "%XX" where each X is a hex digit and converting to the
+/// character with the numerical value of those digits (e.g. "i%20=%203%3b"
+/// unescapes to "i = 3;"). If |convert_to_utf8| is true (1) this function will
+/// attempt to interpret the initial decoded result as UTF-8. If the result is
+/// convertable into UTF-8 it will be returned as converted. Otherwise the
+/// initial decoded result will be returned. The |unescape_rule| parameter
+/// supports further customization the decoding process.
+///
+// The resulting string must be freed by calling cef_string_userfree_free().
+CEF_EXPORT cef_string_userfree_t
+cef_uridecode(const cef_string_t* text,
+ int convert_to_utf8,
+ cef_uri_unescape_rule_t unescape_rule);
+
+///
+/// Parses the specified |json_string| and returns a dictionary or list
+/// representation. If JSON parsing fails this function returns NULL.
+///
+CEF_EXPORT struct _cef_value_t* cef_parse_json(
+ const cef_string_t* json_string,
+ cef_json_parser_options_t options);
+
+///
+/// Parses the specified UTF8-encoded |json| buffer of size |json_size| and
+/// returns a dictionary or list representation. If JSON parsing fails this
+/// function returns NULL.
+///
+CEF_EXPORT struct _cef_value_t* cef_parse_json_buffer(
+ const void* json,
+ size_t json_size,
+ cef_json_parser_options_t options);
+
+///
+/// Parses the specified |json_string| and returns a dictionary or list
+/// representation. If JSON parsing fails this function returns NULL and
+/// populates |error_msg_out| with a formatted error message.
+///
+CEF_EXPORT struct _cef_value_t* cef_parse_jsonand_return_error(
+ const cef_string_t* json_string,
+ cef_json_parser_options_t options,
+ cef_string_t* error_msg_out);
+
+///
+/// Generates a JSON string from the specified root |node| which should be a
+/// dictionary or list value. Returns an NULL string on failure. This function
+/// requires exclusive access to |node| including any underlying data.
+///
+// The resulting string must be freed by calling cef_string_userfree_free().
+CEF_EXPORT cef_string_userfree_t
+cef_write_json(struct _cef_value_t* node, cef_json_writer_options_t options);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_PARSER_CAPI_H_
diff --git a/include/capi/cef_path_util_capi.h b/include/capi/cef_path_util_capi.h
new file mode 100644
index 00000000..5706b839
--- /dev/null
+++ b/include/capi/cef_path_util_capi.h
@@ -0,0 +1,59 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=70b306534b9cb8334c9ea260feacfd8f2f503292$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_PATH_UTIL_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_PATH_UTIL_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Retrieve the path associated with the specified |key|. Returns true (1) on
+/// success. Can be called on any thread in the browser process.
+///
+CEF_EXPORT int cef_get_path(cef_path_key_t key, cef_string_t* path);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_PATH_UTIL_CAPI_H_
diff --git a/include/capi/cef_permission_handler_capi.h b/include/capi/cef_permission_handler_capi.h
new file mode 100644
index 00000000..67d8f0b9
--- /dev/null
+++ b/include/capi/cef_permission_handler_capi.h
@@ -0,0 +1,164 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=bc44eb70b7f0b48e0646825e919cb9996ac99781$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_PERMISSION_HANDLER_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_PERMISSION_HANDLER_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+#include "include/capi/cef_browser_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Callback structure used for asynchronous continuation of media access
+/// permission requests.
+///
+typedef struct _cef_media_access_callback_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Call to allow or deny media access. If this callback was initiated in
+ /// response to a getUserMedia (indicated by
+ /// CEF_MEDIA_PERMISSION_DEVICE_AUDIO_CAPTURE and/or
+ /// CEF_MEDIA_PERMISSION_DEVICE_VIDEO_CAPTURE being set) then
+ /// |allowed_permissions| must match |required_permissions| passed to
+ /// OnRequestMediaAccessPermission.
+ ///
+ void(CEF_CALLBACK* cont)(struct _cef_media_access_callback_t* self,
+ uint32 allowed_permissions);
+
+ ///
+ /// Cancel the media access request.
+ ///
+ void(CEF_CALLBACK* cancel)(struct _cef_media_access_callback_t* self);
+} cef_media_access_callback_t;
+
+///
+/// Callback structure used for asynchronous continuation of permission prompts.
+///
+typedef struct _cef_permission_prompt_callback_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Complete the permissions request with the specified |result|.
+ ///
+ void(CEF_CALLBACK* cont)(struct _cef_permission_prompt_callback_t* self,
+ cef_permission_request_result_t result);
+} cef_permission_prompt_callback_t;
+
+///
+/// Implement this structure to handle events related to permission requests.
+/// The functions of this structure will be called on the browser process UI
+/// thread.
+///
+typedef struct _cef_permission_handler_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Called when a page requests permission to access media.
+ /// |requesting_origin| is the URL origin requesting permission.
+ /// |requested_permissions| is a combination of values from
+ /// cef_media_access_permission_types_t that represent the requested
+ /// permissions. Return true (1) and call cef_media_access_callback_t
+ /// functions either in this function or at a later time to continue or cancel
+ /// the request. Return false (0) to proceed with default handling. With the
+ /// Chrome runtime, default handling will display the permission request UI.
+ /// With the Alloy runtime, default handling will deny the request. This
+ /// function will not be called if the "--enable-media-stream" command-line
+ /// switch is used to grant all permissions.
+ ///
+ int(CEF_CALLBACK* on_request_media_access_permission)(
+ struct _cef_permission_handler_t* self,
+ struct _cef_browser_t* browser,
+ struct _cef_frame_t* frame,
+ const cef_string_t* requesting_origin,
+ uint32 requested_permissions,
+ struct _cef_media_access_callback_t* callback);
+
+ ///
+ /// Called when a page should show a permission prompt. |prompt_id| uniquely
+ /// identifies the prompt. |requesting_origin| is the URL origin requesting
+ /// permission. |requested_permissions| is a combination of values from
+ /// cef_permission_request_types_t that represent the requested permissions.
+ /// Return true (1) and call cef_permission_prompt_callback_t::Continue either
+ /// in this function or at a later time to continue or cancel the request.
+ /// Return false (0) to proceed with default handling. With the Chrome
+ /// runtime, default handling will display the permission prompt UI. With the
+ /// Alloy runtime, default handling is CEF_PERMISSION_RESULT_IGNORE.
+ ///
+ int(CEF_CALLBACK* on_show_permission_prompt)(
+ struct _cef_permission_handler_t* self,
+ struct _cef_browser_t* browser,
+ uint64 prompt_id,
+ const cef_string_t* requesting_origin,
+ uint32 requested_permissions,
+ struct _cef_permission_prompt_callback_t* callback);
+
+ ///
+ /// Called when a permission prompt handled via OnShowPermissionPrompt is
+ /// dismissed. |prompt_id| will match the value that was passed to
+ /// OnShowPermissionPrompt. |result| will be the value passed to
+ /// cef_permission_prompt_callback_t::Continue or CEF_PERMISSION_RESULT_IGNORE
+ /// if the dialog was dismissed for other reasons such as navigation, browser
+ /// closure, etc. This function will not be called if OnShowPermissionPrompt
+ /// returned false (0) for |prompt_id|.
+ ///
+ void(CEF_CALLBACK* on_dismiss_permission_prompt)(
+ struct _cef_permission_handler_t* self,
+ struct _cef_browser_t* browser,
+ uint64 prompt_id,
+ cef_permission_request_result_t result);
+} cef_permission_handler_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_PERMISSION_HANDLER_CAPI_H_
diff --git a/include/capi/cef_preference_capi.h b/include/capi/cef_preference_capi.h
new file mode 100644
index 00000000..fa6d9bd3
--- /dev/null
+++ b/include/capi/cef_preference_capi.h
@@ -0,0 +1,148 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=922659242ea25c52d02884a7cc5918d086cbfaca$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_PREFERENCE_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_PREFERENCE_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+#include "include/capi/cef_values_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Structure that manages custom preference registrations.
+///
+typedef struct _cef_preference_registrar_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_scoped_t base;
+
+ ///
+ /// Register a preference with the specified |name| and |default_value|. To
+ /// avoid conflicts with built-in preferences the |name| value should contain
+ /// an application-specific prefix followed by a period (e.g. "myapp.value").
+ /// The contents of |default_value| will be copied. The data type for the
+ /// preference will be inferred from |default_value|'s type and cannot be
+ /// changed after registration. Returns true (1) on success. Returns false (0)
+ /// if |name| is already registered or if |default_value| has an invalid type.
+ /// This function must be called from within the scope of the
+ /// cef_browser_process_handler_t::OnRegisterCustomPreferences callback.
+ ///
+ int(CEF_CALLBACK* add_preference)(struct _cef_preference_registrar_t* self,
+ const cef_string_t* name,
+ struct _cef_value_t* default_value);
+} cef_preference_registrar_t;
+
+///
+/// Manage access to preferences. Many built-in preferences are registered by
+/// Chromium. Custom preferences can be registered in
+/// cef_browser_process_handler_t::OnRegisterCustomPreferences.
+///
+typedef struct _cef_preference_manager_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Returns true (1) if a preference with the specified |name| exists. This
+ /// function must be called on the browser process UI thread.
+ ///
+ int(CEF_CALLBACK* has_preference)(struct _cef_preference_manager_t* self,
+ const cef_string_t* name);
+
+ ///
+ /// Returns the value for the preference with the specified |name|. Returns
+ /// NULL if the preference does not exist. The returned object contains a copy
+ /// of the underlying preference value and modifications to the returned
+ /// object will not modify the underlying preference value. This function must
+ /// be called on the browser process UI thread.
+ ///
+ struct _cef_value_t*(CEF_CALLBACK* get_preference)(
+ struct _cef_preference_manager_t* self,
+ const cef_string_t* name);
+
+ ///
+ /// Returns all preferences as a dictionary. If |include_defaults| is true (1)
+ /// then preferences currently at their default value will be included. The
+ /// returned object contains a copy of the underlying preference values and
+ /// modifications to the returned object will not modify the underlying
+ /// preference values. This function must be called on the browser process UI
+ /// thread.
+ ///
+ struct _cef_dictionary_value_t*(CEF_CALLBACK* get_all_preferences)(
+ struct _cef_preference_manager_t* self,
+ int include_defaults);
+
+ ///
+ /// Returns true (1) if the preference with the specified |name| can be
+ /// modified using SetPreference. As one example preferences set via the
+ /// command-line usually cannot be modified. This function must be called on
+ /// the browser process UI thread.
+ ///
+ int(CEF_CALLBACK* can_set_preference)(struct _cef_preference_manager_t* self,
+ const cef_string_t* name);
+
+ ///
+ /// Set the |value| associated with preference |name|. Returns true (1) if the
+ /// value is set successfully and false (0) otherwise. If |value| is NULL the
+ /// preference will be restored to its default value. If setting the
+ /// preference fails then |error| will be populated with a detailed
+ /// description of the problem. This function must be called on the browser
+ /// process UI thread.
+ ///
+ int(CEF_CALLBACK* set_preference)(struct _cef_preference_manager_t* self,
+ const cef_string_t* name,
+ struct _cef_value_t* value,
+ cef_string_t* error);
+} cef_preference_manager_t;
+
+///
+/// Returns the global preference manager object.
+///
+CEF_EXPORT cef_preference_manager_t* cef_preference_manager_get_global(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_PREFERENCE_CAPI_H_
diff --git a/include/capi/cef_preference_manager_capi.h b/include/capi/cef_preference_manager_capi.h
new file mode 100644
index 00000000..f3d979c2
--- /dev/null
+++ b/include/capi/cef_preference_manager_capi.h
@@ -0,0 +1,116 @@
+// Copyright (c) 2022 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=1f5dd49cfc5aeb4b673c10750de01768f5cd2694$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_PREFERENCE_MANAGER_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_PREFERENCE_MANAGER_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+#include "include/capi/cef_values_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Manage access to preferences.
+///
+typedef struct _cef_preference_manager_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Returns true (1) if a preference with the specified |name| exists. This
+ /// function must be called on the browser process UI thread.
+ ///
+ int(CEF_CALLBACK* has_preference)(struct _cef_preference_manager_t* self,
+ const cef_string_t* name);
+
+ ///
+ /// Returns the value for the preference with the specified |name|. Returns
+ /// NULL if the preference does not exist. The returned object contains a copy
+ /// of the underlying preference value and modifications to the returned
+ /// object will not modify the underlying preference value. This function must
+ /// be called on the browser process UI thread.
+ ///
+ struct _cef_value_t*(CEF_CALLBACK* get_preference)(
+ struct _cef_preference_manager_t* self,
+ const cef_string_t* name);
+
+ ///
+ /// Returns all preferences as a dictionary. If |include_defaults| is true (1)
+ /// then preferences currently at their default value will be included. The
+ /// returned object contains a copy of the underlying preference values and
+ /// modifications to the returned object will not modify the underlying
+ /// preference values. This function must be called on the browser process UI
+ /// thread.
+ ///
+ struct _cef_dictionary_value_t*(CEF_CALLBACK* get_all_preferences)(
+ struct _cef_preference_manager_t* self,
+ int include_defaults);
+
+ ///
+ /// Returns true (1) if the preference with the specified |name| can be
+ /// modified using SetPreference. As one example preferences set via the
+ /// command-line usually cannot be modified. This function must be called on
+ /// the browser process UI thread.
+ ///
+ int(CEF_CALLBACK* can_set_preference)(struct _cef_preference_manager_t* self,
+ const cef_string_t* name);
+
+ ///
+ /// Set the |value| associated with preference |name|. Returns true (1) if the
+ /// value is set successfully and false (0) otherwise. If |value| is NULL the
+ /// preference will be restored to its default value. If setting the
+ /// preference fails then |error| will be populated with a detailed
+ /// description of the problem. This function must be called on the browser
+ /// process UI thread.
+ ///
+ int(CEF_CALLBACK* set_preference)(struct _cef_preference_manager_t* self,
+ const cef_string_t* name,
+ struct _cef_value_t* value,
+ cef_string_t* error);
+} cef_preference_manager_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_PREFERENCE_MANAGER_CAPI_H_
diff --git a/include/capi/cef_print_handler_capi.h b/include/capi/cef_print_handler_capi.h
new file mode 100644
index 00000000..47e69b1d
--- /dev/null
+++ b/include/capi/cef_print_handler_capi.h
@@ -0,0 +1,160 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=d09937fb047debd9da39c4072a434659b3c5682c$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_PRINT_HANDLER_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_PRINT_HANDLER_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+#include "include/capi/cef_browser_capi.h"
+#include "include/capi/cef_print_settings_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Callback structure for asynchronous continuation of print dialog requests.
+///
+typedef struct _cef_print_dialog_callback_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Continue printing with the specified |settings|.
+ ///
+ void(CEF_CALLBACK* cont)(struct _cef_print_dialog_callback_t* self,
+ struct _cef_print_settings_t* settings);
+
+ ///
+ /// Cancel the printing.
+ ///
+ void(CEF_CALLBACK* cancel)(struct _cef_print_dialog_callback_t* self);
+} cef_print_dialog_callback_t;
+
+///
+/// Callback structure for asynchronous continuation of print job requests.
+///
+typedef struct _cef_print_job_callback_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Indicate completion of the print job.
+ ///
+ void(CEF_CALLBACK* cont)(struct _cef_print_job_callback_t* self);
+} cef_print_job_callback_t;
+
+///
+/// Implement this structure to handle printing on Linux. Each browser will have
+/// only one print job in progress at a time. The functions of this structure
+/// will be called on the browser process UI thread.
+///
+typedef struct _cef_print_handler_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Called when printing has started for the specified |browser|. This
+ /// function will be called before the other OnPrint*() functions and
+ /// irrespective of how printing was initiated (e.g.
+ /// cef_browser_host_t::print(), JavaScript window.print() or PDF extension
+ /// print button).
+ ///
+ void(CEF_CALLBACK* on_print_start)(struct _cef_print_handler_t* self,
+ struct _cef_browser_t* browser);
+
+ ///
+ /// Synchronize |settings| with client state. If |get_defaults| is true (1)
+ /// then populate |settings| with the default print settings. Do not keep a
+ /// reference to |settings| outside of this callback.
+ ///
+ void(CEF_CALLBACK* on_print_settings)(struct _cef_print_handler_t* self,
+ struct _cef_browser_t* browser,
+ struct _cef_print_settings_t* settings,
+ int get_defaults);
+
+ ///
+ /// Show the print dialog. Execute |callback| once the dialog is dismissed.
+ /// Return true (1) if the dialog will be displayed or false (0) to cancel the
+ /// printing immediately.
+ ///
+ int(CEF_CALLBACK* on_print_dialog)(
+ struct _cef_print_handler_t* self,
+ struct _cef_browser_t* browser,
+ int has_selection,
+ struct _cef_print_dialog_callback_t* callback);
+
+ ///
+ /// Send the print job to the printer. Execute |callback| once the job is
+ /// completed. Return true (1) if the job will proceed or false (0) to cancel
+ /// the job immediately.
+ ///
+ int(CEF_CALLBACK* on_print_job)(struct _cef_print_handler_t* self,
+ struct _cef_browser_t* browser,
+ const cef_string_t* document_name,
+ const cef_string_t* pdf_file_path,
+ struct _cef_print_job_callback_t* callback);
+
+ ///
+ /// Reset client state related to printing.
+ ///
+ void(CEF_CALLBACK* on_print_reset)(struct _cef_print_handler_t* self,
+ struct _cef_browser_t* browser);
+
+ ///
+ /// Return the PDF paper size in device units. Used in combination with
+ /// cef_browser_host_t::print_to_pdf().
+ ///
+ cef_size_t(CEF_CALLBACK* get_pdf_paper_size)(
+ struct _cef_print_handler_t* self,
+ struct _cef_browser_t* browser,
+ int device_units_per_inch);
+} cef_print_handler_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_PRINT_HANDLER_CAPI_H_
diff --git a/include/capi/cef_print_settings_capi.h b/include/capi/cef_print_settings_capi.h
new file mode 100644
index 00000000..14a52f30
--- /dev/null
+++ b/include/capi/cef_print_settings_capi.h
@@ -0,0 +1,202 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=46508464579e797d4684f4a7facdb39f9bdb312b$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_PRINT_SETTINGS_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_PRINT_SETTINGS_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Structure representing print settings.
+///
+typedef struct _cef_print_settings_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Returns true (1) if this object is valid. Do not call any other functions
+ /// if this function returns false (0).
+ ///
+ int(CEF_CALLBACK* is_valid)(struct _cef_print_settings_t* self);
+
+ ///
+ /// Returns true (1) if the values of this object are read-only. Some APIs may
+ /// expose read-only objects.
+ ///
+ int(CEF_CALLBACK* is_read_only)(struct _cef_print_settings_t* self);
+
+ ///
+ /// Set the page orientation.
+ ///
+ void(CEF_CALLBACK* set_orientation)(struct _cef_print_settings_t* self,
+ int landscape);
+
+ ///
+ /// Returns true (1) if the orientation is landscape.
+ ///
+ int(CEF_CALLBACK* is_landscape)(struct _cef_print_settings_t* self);
+
+ ///
+ /// Set the printer printable area in device units. Some platforms already
+ /// provide flipped area. Set |landscape_needs_flip| to false (0) on those
+ /// platforms to avoid double flipping.
+ ///
+ void(CEF_CALLBACK* set_printer_printable_area)(
+ struct _cef_print_settings_t* self,
+ const cef_size_t* physical_size_device_units,
+ const cef_rect_t* printable_area_device_units,
+ int landscape_needs_flip);
+
+ ///
+ /// Set the device name.
+ ///
+ void(CEF_CALLBACK* set_device_name)(struct _cef_print_settings_t* self,
+ const cef_string_t* name);
+
+ ///
+ /// Get the device name.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_device_name)(
+ struct _cef_print_settings_t* self);
+
+ ///
+ /// Set the DPI (dots per inch).
+ ///
+ void(CEF_CALLBACK* set_dpi)(struct _cef_print_settings_t* self, int dpi);
+
+ ///
+ /// Get the DPI (dots per inch).
+ ///
+ int(CEF_CALLBACK* get_dpi)(struct _cef_print_settings_t* self);
+
+ ///
+ /// Set the page ranges.
+ ///
+ void(CEF_CALLBACK* set_page_ranges)(struct _cef_print_settings_t* self,
+ size_t rangesCount,
+ cef_range_t const* ranges);
+
+ ///
+ /// Returns the number of page ranges that currently exist.
+ ///
+ size_t(CEF_CALLBACK* get_page_ranges_count)(
+ struct _cef_print_settings_t* self);
+
+ ///
+ /// Retrieve the page ranges.
+ ///
+ void(CEF_CALLBACK* get_page_ranges)(struct _cef_print_settings_t* self,
+ size_t* rangesCount,
+ cef_range_t* ranges);
+
+ ///
+ /// Set whether only the selection will be printed.
+ ///
+ void(CEF_CALLBACK* set_selection_only)(struct _cef_print_settings_t* self,
+ int selection_only);
+
+ ///
+ /// Returns true (1) if only the selection will be printed.
+ ///
+ int(CEF_CALLBACK* is_selection_only)(struct _cef_print_settings_t* self);
+
+ ///
+ /// Set whether pages will be collated.
+ ///
+ void(CEF_CALLBACK* set_collate)(struct _cef_print_settings_t* self,
+ int collate);
+
+ ///
+ /// Returns true (1) if pages will be collated.
+ ///
+ int(CEF_CALLBACK* will_collate)(struct _cef_print_settings_t* self);
+
+ ///
+ /// Set the color model.
+ ///
+ void(CEF_CALLBACK* set_color_model)(struct _cef_print_settings_t* self,
+ cef_color_model_t model);
+
+ ///
+ /// Get the color model.
+ ///
+ cef_color_model_t(CEF_CALLBACK* get_color_model)(
+ struct _cef_print_settings_t* self);
+
+ ///
+ /// Set the number of copies.
+ ///
+ void(CEF_CALLBACK* set_copies)(struct _cef_print_settings_t* self,
+ int copies);
+
+ ///
+ /// Get the number of copies.
+ ///
+ int(CEF_CALLBACK* get_copies)(struct _cef_print_settings_t* self);
+
+ ///
+ /// Set the duplex mode.
+ ///
+ void(CEF_CALLBACK* set_duplex_mode)(struct _cef_print_settings_t* self,
+ cef_duplex_mode_t mode);
+
+ ///
+ /// Get the duplex mode.
+ ///
+ cef_duplex_mode_t(CEF_CALLBACK* get_duplex_mode)(
+ struct _cef_print_settings_t* self);
+} cef_print_settings_t;
+
+///
+/// Create a new cef_print_settings_t object.
+///
+CEF_EXPORT cef_print_settings_t* cef_print_settings_create(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_PRINT_SETTINGS_CAPI_H_
diff --git a/include/capi/cef_process_message_capi.h b/include/capi/cef_process_message_capi.h
new file mode 100644
index 00000000..586014c3
--- /dev/null
+++ b/include/capi/cef_process_message_capi.h
@@ -0,0 +1,111 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=e20a8d6a5803dae5ba156adde40c8b964899b176$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_PROCESS_MESSAGE_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_PROCESS_MESSAGE_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+#include "include/capi/cef_shared_memory_region_capi.h"
+#include "include/capi/cef_values_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Structure representing a message. Can be used on any process and thread.
+///
+typedef struct _cef_process_message_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Returns true (1) if this object is valid. Do not call any other functions
+ /// if this function returns false (0).
+ ///
+ int(CEF_CALLBACK* is_valid)(struct _cef_process_message_t* self);
+
+ ///
+ /// Returns true (1) if the values of this object are read-only. Some APIs may
+ /// expose read-only objects.
+ ///
+ int(CEF_CALLBACK* is_read_only)(struct _cef_process_message_t* self);
+
+ ///
+ /// Returns a writable copy of this object. Returns nullptr when message
+ /// contains a shared memory region.
+ ///
+ struct _cef_process_message_t*(CEF_CALLBACK* copy)(
+ struct _cef_process_message_t* self);
+
+ ///
+ /// Returns the message name.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_name)(
+ struct _cef_process_message_t* self);
+
+ ///
+ /// Returns the list of arguments. Returns nullptr when message contains a
+ /// shared memory region.
+ ///
+ struct _cef_list_value_t*(CEF_CALLBACK* get_argument_list)(
+ struct _cef_process_message_t* self);
+
+ ///
+ /// Returns the shared memory region. Returns nullptr when message contains an
+ /// argument list.
+ ///
+ struct _cef_shared_memory_region_t*(CEF_CALLBACK* get_shared_memory_region)(
+ struct _cef_process_message_t* self);
+} cef_process_message_t;
+
+///
+/// Create a new cef_process_message_t object with the specified name.
+///
+CEF_EXPORT cef_process_message_t* cef_process_message_create(
+ const cef_string_t* name);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_PROCESS_MESSAGE_CAPI_H_
diff --git a/include/capi/cef_process_util_capi.h b/include/capi/cef_process_util_capi.h
new file mode 100644
index 00000000..2ae2c57c
--- /dev/null
+++ b/include/capi/cef_process_util_capi.h
@@ -0,0 +1,65 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=88c42c5f216798304b07bfe985296014cf65996c$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_PROCESS_UTIL_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_PROCESS_UTIL_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Launches the process specified via |command_line|. Returns true (1) upon
+/// success. Must be called on the browser process TID_PROCESS_LAUNCHER thread.
+///
+/// Unix-specific notes: - All file descriptors open in the parent process will
+/// be closed in the
+/// child process except for stdin, stdout, and stderr.
+/// - If the first argument on the command line does not contain a slash,
+/// PATH will be searched. (See man execvp.)
+///
+CEF_EXPORT int cef_launch_process(struct _cef_command_line_t* command_line);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_PROCESS_UTIL_CAPI_H_
diff --git a/include/capi/cef_registration_capi.h b/include/capi/cef_registration_capi.h
new file mode 100644
index 00000000..4ac84d67
--- /dev/null
+++ b/include/capi/cef_registration_capi.h
@@ -0,0 +1,63 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=b1b38a3171dd3626029e70e75b482dfa3531215b$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_REGISTRATION_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_REGISTRATION_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Generic callback structure used for managing the lifespan of a registration.
+///
+typedef struct _cef_registration_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+} cef_registration_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_REGISTRATION_CAPI_H_
diff --git a/include/capi/cef_render_handler_capi.h b/include/capi/cef_render_handler_capi.h
new file mode 100644
index 00000000..ccd3d238
--- /dev/null
+++ b/include/capi/cef_render_handler_capi.h
@@ -0,0 +1,261 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=32d8176f39b05487bae048990b2dee3212ae3b78$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_RENDER_HANDLER_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_RENDER_HANDLER_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_accessibility_handler_capi.h"
+#include "include/capi/cef_base_capi.h"
+#include "include/capi/cef_browser_capi.h"
+#include "include/capi/cef_drag_data_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Implement this structure to handle events when window rendering is disabled.
+/// The functions of this structure will be called on the UI thread.
+///
+typedef struct _cef_render_handler_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Return the handler for accessibility notifications. If no handler is
+ /// provided the default implementation will be used.
+ ///
+ struct _cef_accessibility_handler_t*(CEF_CALLBACK* get_accessibility_handler)(
+ struct _cef_render_handler_t* self);
+
+ ///
+ /// Called to retrieve the root window rectangle in screen DIP coordinates.
+ /// Return true (1) if the rectangle was provided. If this function returns
+ /// false (0) the rectangle from GetViewRect will be used.
+ ///
+ int(CEF_CALLBACK* get_root_screen_rect)(struct _cef_render_handler_t* self,
+ struct _cef_browser_t* browser,
+ cef_rect_t* rect);
+
+ ///
+ /// Called to retrieve the view rectangle in screen DIP coordinates. This
+ /// function must always provide a non-NULL rectangle.
+ ///
+ void(CEF_CALLBACK* get_view_rect)(struct _cef_render_handler_t* self,
+ struct _cef_browser_t* browser,
+ cef_rect_t* rect);
+
+ ///
+ /// Called to retrieve the translation from view DIP coordinates to screen
+ /// coordinates. Windows/Linux should provide screen device (pixel)
+ /// coordinates and MacOS should provide screen DIP coordinates. Return true
+ /// (1) if the requested coordinates were provided.
+ ///
+ int(CEF_CALLBACK* get_screen_point)(struct _cef_render_handler_t* self,
+ struct _cef_browser_t* browser,
+ int viewX,
+ int viewY,
+ int* screenX,
+ int* screenY);
+
+ ///
+ /// Called to allow the client to fill in the CefScreenInfo object with
+ /// appropriate values. Return true (1) if the |screen_info| structure has
+ /// been modified.
+ ///
+ /// If the screen info rectangle is left NULL the rectangle from GetViewRect
+ /// will be used. If the rectangle is still NULL or invalid popups may not be
+ /// drawn correctly.
+ ///
+ int(CEF_CALLBACK* get_screen_info)(struct _cef_render_handler_t* self,
+ struct _cef_browser_t* browser,
+ cef_screen_info_t* screen_info);
+
+ ///
+ /// Called when the browser wants to show or hide the popup widget. The popup
+ /// should be shown if |show| is true (1) and hidden if |show| is false (0).
+ ///
+ void(CEF_CALLBACK* on_popup_show)(struct _cef_render_handler_t* self,
+ struct _cef_browser_t* browser,
+ int show);
+
+ ///
+ /// Called when the browser wants to move or resize the popup widget. |rect|
+ /// contains the new location and size in view coordinates.
+ ///
+ void(CEF_CALLBACK* on_popup_size)(struct _cef_render_handler_t* self,
+ struct _cef_browser_t* browser,
+ const cef_rect_t* rect);
+
+ ///
+ /// Called when an element should be painted. Pixel values passed to this
+ /// function are scaled relative to view coordinates based on the value of
+ /// CefScreenInfo.device_scale_factor returned from GetScreenInfo. |type|
+ /// indicates whether the element is the view or the popup widget. |buffer|
+ /// contains the pixel data for the whole image. |dirtyRects| contains the set
+ /// of rectangles in pixel coordinates that need to be repainted. |buffer|
+ /// will be |width|*|height|*4 bytes in size and represents a BGRA image with
+ /// an upper-left origin. This function is only called when
+ /// cef_window_tInfo::shared_texture_enabled is set to false (0).
+ ///
+ void(CEF_CALLBACK* on_paint)(struct _cef_render_handler_t* self,
+ struct _cef_browser_t* browser,
+ cef_paint_element_type_t type,
+ size_t dirtyRectsCount,
+ cef_rect_t const* dirtyRects,
+ const void* buffer,
+ int width,
+ int height);
+
+ ///
+ /// Called when an element has been rendered to the shared texture handle.
+ /// |type| indicates whether the element is the view or the popup widget.
+ /// |dirtyRects| contains the set of rectangles in pixel coordinates that need
+ /// to be repainted. |shared_handle| is the handle for a D3D11 Texture2D that
+ /// can be accessed via ID3D11Device using the OpenSharedResource function.
+ /// This function is only called when cef_window_tInfo::shared_texture_enabled
+ /// is set to true (1), and is currently only supported on Windows.
+ ///
+ void(CEF_CALLBACK* on_accelerated_paint)(struct _cef_render_handler_t* self,
+ struct _cef_browser_t* browser,
+ cef_paint_element_type_t type,
+ size_t dirtyRectsCount,
+ cef_rect_t const* dirtyRects,
+ void* shared_handle);
+
+ ///
+ /// Called to retrieve the size of the touch handle for the specified
+ /// |orientation|.
+ ///
+ void(CEF_CALLBACK* get_touch_handle_size)(
+ struct _cef_render_handler_t* self,
+ struct _cef_browser_t* browser,
+ cef_horizontal_alignment_t orientation,
+ cef_size_t* size);
+
+ ///
+ /// Called when touch handle state is updated. The client is responsible for
+ /// rendering the touch handles.
+ ///
+ void(CEF_CALLBACK* on_touch_handle_state_changed)(
+ struct _cef_render_handler_t* self,
+ struct _cef_browser_t* browser,
+ const cef_touch_handle_state_t* state);
+
+ ///
+ /// Called when the user starts dragging content in the web view. Contextual
+ /// information about the dragged content is supplied by |drag_data|. (|x|,
+ /// |y|) is the drag start location in screen coordinates. OS APIs that run a
+ /// system message loop may be used within the StartDragging call.
+ ///
+ /// Return false (0) to abort the drag operation. Don't call any of
+ /// cef_browser_host_t::DragSource*Ended* functions after returning false (0).
+ ///
+ /// Return true (1) to handle the drag operation. Call
+ /// cef_browser_host_t::DragSourceEndedAt and DragSourceSystemDragEnded either
+ /// synchronously or asynchronously to inform the web view that the drag
+ /// operation has ended.
+ ///
+ int(CEF_CALLBACK* start_dragging)(struct _cef_render_handler_t* self,
+ struct _cef_browser_t* browser,
+ struct _cef_drag_data_t* drag_data,
+ cef_drag_operations_mask_t allowed_ops,
+ int x,
+ int y);
+
+ ///
+ /// Called when the web view wants to update the mouse cursor during a drag &
+ /// drop operation. |operation| describes the allowed operation (none, move,
+ /// copy, link).
+ ///
+ void(CEF_CALLBACK* update_drag_cursor)(struct _cef_render_handler_t* self,
+ struct _cef_browser_t* browser,
+ cef_drag_operations_mask_t operation);
+
+ ///
+ /// Called when the scroll offset has changed.
+ ///
+ void(CEF_CALLBACK* on_scroll_offset_changed)(
+ struct _cef_render_handler_t* self,
+ struct _cef_browser_t* browser,
+ double x,
+ double y);
+
+ ///
+ /// Called when the IME composition range has changed. |selected_range| is the
+ /// range of characters that have been selected. |character_bounds| is the
+ /// bounds of each character in view coordinates.
+ ///
+ void(CEF_CALLBACK* on_ime_composition_range_changed)(
+ struct _cef_render_handler_t* self,
+ struct _cef_browser_t* browser,
+ const cef_range_t* selected_range,
+ size_t character_boundsCount,
+ cef_rect_t const* character_bounds);
+
+ ///
+ /// Called when text selection has changed for the specified |browser|.
+ /// |selected_text| is the currently selected text and |selected_range| is the
+ /// character range.
+ ///
+ void(CEF_CALLBACK* on_text_selection_changed)(
+ struct _cef_render_handler_t* self,
+ struct _cef_browser_t* browser,
+ const cef_string_t* selected_text,
+ const cef_range_t* selected_range);
+
+ ///
+ /// Called when an on-screen keyboard should be shown or hidden for the
+ /// specified |browser|. |input_mode| specifies what kind of keyboard should
+ /// be opened. If |input_mode| is CEF_TEXT_INPUT_MODE_NONE, any existing
+ /// keyboard for this browser should be hidden.
+ ///
+ void(CEF_CALLBACK* on_virtual_keyboard_requested)(
+ struct _cef_render_handler_t* self,
+ struct _cef_browser_t* browser,
+ cef_text_input_mode_t input_mode);
+} cef_render_handler_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_RENDER_HANDLER_CAPI_H_
diff --git a/include/capi/cef_render_process_handler_capi.h b/include/capi/cef_render_process_handler_capi.h
new file mode 100644
index 00000000..f9c86c94
--- /dev/null
+++ b/include/capi/cef_render_process_handler_capi.h
@@ -0,0 +1,168 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=d807c7566ce3085243e9e7ea279fee7241acfc5f$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_RENDER_PROCESS_HANDLER_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_RENDER_PROCESS_HANDLER_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+#include "include/capi/cef_browser_capi.h"
+#include "include/capi/cef_dom_capi.h"
+#include "include/capi/cef_frame_capi.h"
+#include "include/capi/cef_load_handler_capi.h"
+#include "include/capi/cef_process_message_capi.h"
+#include "include/capi/cef_v8_capi.h"
+#include "include/capi/cef_values_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Structure used to implement render process callbacks. The functions of this
+/// structure will be called on the render process main thread (TID_RENDERER)
+/// unless otherwise indicated.
+///
+typedef struct _cef_render_process_handler_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Called after WebKit has been initialized.
+ ///
+ void(CEF_CALLBACK* on_web_kit_initialized)(
+ struct _cef_render_process_handler_t* self);
+
+ ///
+ /// Called after a browser has been created. When browsing cross-origin a new
+ /// browser will be created before the old browser with the same identifier is
+ /// destroyed. |extra_info| is an optional read-only value originating from
+ /// cef_browser_host_t::cef_browser_host_create_browser(),
+ /// cef_browser_host_t::cef_browser_host_create_browser_sync(),
+ /// cef_life_span_handler_t::on_before_popup() or
+ /// cef_browser_view_t::cef_browser_view_create().
+ ///
+ void(CEF_CALLBACK* on_browser_created)(
+ struct _cef_render_process_handler_t* self,
+ struct _cef_browser_t* browser,
+ struct _cef_dictionary_value_t* extra_info);
+
+ ///
+ /// Called before a browser is destroyed.
+ ///
+ void(CEF_CALLBACK* on_browser_destroyed)(
+ struct _cef_render_process_handler_t* self,
+ struct _cef_browser_t* browser);
+
+ ///
+ /// Return the handler for browser load status events.
+ ///
+ struct _cef_load_handler_t*(CEF_CALLBACK* get_load_handler)(
+ struct _cef_render_process_handler_t* self);
+
+ ///
+ /// Called immediately after the V8 context for a frame has been created. To
+ /// retrieve the JavaScript 'window' object use the
+ /// cef_v8context_t::get_global() function. V8 handles can only be accessed
+ /// from the thread on which they are created. A task runner for posting tasks
+ /// on the associated thread can be retrieved via the
+ /// cef_v8context_t::get_task_runner() function.
+ ///
+ void(CEF_CALLBACK* on_context_created)(
+ struct _cef_render_process_handler_t* self,
+ struct _cef_browser_t* browser,
+ struct _cef_frame_t* frame,
+ struct _cef_v8context_t* context);
+
+ ///
+ /// Called immediately before the V8 context for a frame is released. No
+ /// references to the context should be kept after this function is called.
+ ///
+ void(CEF_CALLBACK* on_context_released)(
+ struct _cef_render_process_handler_t* self,
+ struct _cef_browser_t* browser,
+ struct _cef_frame_t* frame,
+ struct _cef_v8context_t* context);
+
+ ///
+ /// Called for global uncaught exceptions in a frame. Execution of this
+ /// callback is disabled by default. To enable set
+ /// cef_settings_t.uncaught_exception_stack_size > 0.
+ ///
+ void(CEF_CALLBACK* on_uncaught_exception)(
+ struct _cef_render_process_handler_t* self,
+ struct _cef_browser_t* browser,
+ struct _cef_frame_t* frame,
+ struct _cef_v8context_t* context,
+ struct _cef_v8exception_t* exception,
+ struct _cef_v8stack_trace_t* stackTrace);
+
+ ///
+ /// Called when a new node in the the browser gets focus. The |node| value may
+ /// be NULL if no specific node has gained focus. The node object passed to
+ /// this function represents a snapshot of the DOM at the time this function
+ /// is executed. DOM objects are only valid for the scope of this function. Do
+ /// not keep references to or attempt to access any DOM objects outside the
+ /// scope of this function.
+ ///
+ void(CEF_CALLBACK* on_focused_node_changed)(
+ struct _cef_render_process_handler_t* self,
+ struct _cef_browser_t* browser,
+ struct _cef_frame_t* frame,
+ struct _cef_domnode_t* node);
+
+ ///
+ /// Called when a new message is received from a different process. Return
+ /// true (1) if the message was handled or false (0) otherwise. It is safe to
+ /// keep a reference to |message| outside of this callback.
+ ///
+ int(CEF_CALLBACK* on_process_message_received)(
+ struct _cef_render_process_handler_t* self,
+ struct _cef_browser_t* browser,
+ struct _cef_frame_t* frame,
+ cef_process_id_t source_process,
+ struct _cef_process_message_t* message);
+} cef_render_process_handler_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_RENDER_PROCESS_HANDLER_CAPI_H_
diff --git a/include/capi/cef_request_capi.h b/include/capi/cef_request_capi.h
new file mode 100644
index 00000000..9ac91657
--- /dev/null
+++ b/include/capi/cef_request_capi.h
@@ -0,0 +1,355 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=3339290cad3a77c8b0b07d422f0faf902a047838$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_REQUEST_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_REQUEST_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _cef_post_data_element_t;
+struct _cef_post_data_t;
+
+///
+/// Structure used to represent a web request. The functions of this structure
+/// may be called on any thread.
+///
+typedef struct _cef_request_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Returns true (1) if this object is read-only.
+ ///
+ int(CEF_CALLBACK* is_read_only)(struct _cef_request_t* self);
+
+ ///
+ /// Get the fully qualified URL.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_url)(struct _cef_request_t* self);
+
+ ///
+ /// Set the fully qualified URL.
+ ///
+ void(CEF_CALLBACK* set_url)(struct _cef_request_t* self,
+ const cef_string_t* url);
+
+ ///
+ /// Get the request function type. The value will default to POST if post data
+ /// is provided and GET otherwise.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_method)(struct _cef_request_t* self);
+
+ ///
+ /// Set the request function type.
+ ///
+ void(CEF_CALLBACK* set_method)(struct _cef_request_t* self,
+ const cef_string_t* method);
+
+ ///
+ /// Set the referrer URL and policy. If non-NULL the referrer URL must be
+ /// fully qualified with an HTTP or HTTPS scheme component. Any username,
+ /// password or ref component will be removed.
+ ///
+ void(CEF_CALLBACK* set_referrer)(struct _cef_request_t* self,
+ const cef_string_t* referrer_url,
+ cef_referrer_policy_t policy);
+
+ ///
+ /// Get the referrer URL.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_referrer_url)(
+ struct _cef_request_t* self);
+
+ ///
+ /// Get the referrer policy.
+ ///
+ cef_referrer_policy_t(CEF_CALLBACK* get_referrer_policy)(
+ struct _cef_request_t* self);
+
+ ///
+ /// Get the post data.
+ ///
+ struct _cef_post_data_t*(CEF_CALLBACK* get_post_data)(
+ struct _cef_request_t* self);
+
+ ///
+ /// Set the post data.
+ ///
+ void(CEF_CALLBACK* set_post_data)(struct _cef_request_t* self,
+ struct _cef_post_data_t* postData);
+
+ ///
+ /// Get the header values. Will not include the Referer value if any.
+ ///
+ void(CEF_CALLBACK* get_header_map)(struct _cef_request_t* self,
+ cef_string_multimap_t headerMap);
+
+ ///
+ /// Set the header values. If a Referer value exists in the header map it will
+ /// be removed and ignored.
+ ///
+ void(CEF_CALLBACK* set_header_map)(struct _cef_request_t* self,
+ cef_string_multimap_t headerMap);
+
+ ///
+ /// Returns the first header value for |name| or an NULL string if not found.
+ /// Will not return the Referer value if any. Use GetHeaderMap instead if
+ /// |name| might have multiple values.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_header_by_name)(
+ struct _cef_request_t* self,
+ const cef_string_t* name);
+
+ ///
+ /// Set the header |name| to |value|. If |overwrite| is true (1) any existing
+ /// values will be replaced with the new value. If |overwrite| is false (0)
+ /// any existing values will not be overwritten. The Referer value cannot be
+ /// set using this function.
+ ///
+ void(CEF_CALLBACK* set_header_by_name)(struct _cef_request_t* self,
+ const cef_string_t* name,
+ const cef_string_t* value,
+ int overwrite);
+
+ ///
+ /// Set all values at one time.
+ ///
+ void(CEF_CALLBACK* set)(struct _cef_request_t* self,
+ const cef_string_t* url,
+ const cef_string_t* method,
+ struct _cef_post_data_t* postData,
+ cef_string_multimap_t headerMap);
+
+ ///
+ /// Get the flags used in combination with cef_urlrequest_t. See
+ /// cef_urlrequest_flags_t for supported values.
+ ///
+ int(CEF_CALLBACK* get_flags)(struct _cef_request_t* self);
+
+ ///
+ /// Set the flags used in combination with cef_urlrequest_t. See
+ /// cef_urlrequest_flags_t for supported values.
+ ///
+ void(CEF_CALLBACK* set_flags)(struct _cef_request_t* self, int flags);
+
+ ///
+ /// Get the URL to the first party for cookies used in combination with
+ /// cef_urlrequest_t.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_first_party_for_cookies)(
+ struct _cef_request_t* self);
+
+ ///
+ /// Set the URL to the first party for cookies used in combination with
+ /// cef_urlrequest_t.
+ ///
+ void(CEF_CALLBACK* set_first_party_for_cookies)(struct _cef_request_t* self,
+ const cef_string_t* url);
+
+ ///
+ /// Get the resource type for this request. Only available in the browser
+ /// process.
+ ///
+ cef_resource_type_t(CEF_CALLBACK* get_resource_type)(
+ struct _cef_request_t* self);
+
+ ///
+ /// Get the transition type for this request. Only available in the browser
+ /// process and only applies to requests that represent a main frame or sub-
+ /// frame navigation.
+ ///
+ cef_transition_type_t(CEF_CALLBACK* get_transition_type)(
+ struct _cef_request_t* self);
+
+ ///
+ /// Returns the globally unique identifier for this request or 0 if not
+ /// specified. Can be used by cef_resource_request_handler_t implementations
+ /// in the browser process to track a single request across multiple
+ /// callbacks.
+ ///
+ uint64(CEF_CALLBACK* get_identifier)(struct _cef_request_t* self);
+} cef_request_t;
+
+///
+/// Create a new cef_request_t object.
+///
+CEF_EXPORT cef_request_t* cef_request_create(void);
+
+///
+/// Structure used to represent post data for a web request. The functions of
+/// this structure may be called on any thread.
+///
+typedef struct _cef_post_data_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Returns true (1) if this object is read-only.
+ ///
+ int(CEF_CALLBACK* is_read_only)(struct _cef_post_data_t* self);
+
+ ///
+ /// Returns true (1) if the underlying POST data includes elements that are
+ /// not represented by this cef_post_data_t object (for example, multi-part
+ /// file upload data). Modifying cef_post_data_t objects with excluded
+ /// elements may result in the request failing.
+ ///
+ int(CEF_CALLBACK* has_excluded_elements)(struct _cef_post_data_t* self);
+
+ ///
+ /// Returns the number of existing post data elements.
+ ///
+ size_t(CEF_CALLBACK* get_element_count)(struct _cef_post_data_t* self);
+
+ ///
+ /// Retrieve the post data elements.
+ ///
+ void(CEF_CALLBACK* get_elements)(struct _cef_post_data_t* self,
+ size_t* elementsCount,
+ struct _cef_post_data_element_t** elements);
+
+ ///
+ /// Remove the specified post data element. Returns true (1) if the removal
+ /// succeeds.
+ ///
+ int(CEF_CALLBACK* remove_element)(struct _cef_post_data_t* self,
+ struct _cef_post_data_element_t* element);
+
+ ///
+ /// Add the specified post data element. Returns true (1) if the add
+ /// succeeds.
+ ///
+ int(CEF_CALLBACK* add_element)(struct _cef_post_data_t* self,
+ struct _cef_post_data_element_t* element);
+
+ ///
+ /// Remove all existing post data elements.
+ ///
+ void(CEF_CALLBACK* remove_elements)(struct _cef_post_data_t* self);
+} cef_post_data_t;
+
+///
+/// Create a new cef_post_data_t object.
+///
+CEF_EXPORT cef_post_data_t* cef_post_data_create(void);
+
+///
+/// Structure used to represent a single element in the request post data. The
+/// functions of this structure may be called on any thread.
+///
+typedef struct _cef_post_data_element_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Returns true (1) if this object is read-only.
+ ///
+ int(CEF_CALLBACK* is_read_only)(struct _cef_post_data_element_t* self);
+
+ ///
+ /// Remove all contents from the post data element.
+ ///
+ void(CEF_CALLBACK* set_to_empty)(struct _cef_post_data_element_t* self);
+
+ ///
+ /// The post data element will represent a file.
+ ///
+ void(CEF_CALLBACK* set_to_file)(struct _cef_post_data_element_t* self,
+ const cef_string_t* fileName);
+
+ ///
+ /// The post data element will represent bytes. The bytes passed in will be
+ /// copied.
+ ///
+ void(CEF_CALLBACK* set_to_bytes)(struct _cef_post_data_element_t* self,
+ size_t size,
+ const void* bytes);
+
+ ///
+ /// Return the type of this post data element.
+ ///
+ cef_postdataelement_type_t(CEF_CALLBACK* get_type)(
+ struct _cef_post_data_element_t* self);
+
+ ///
+ /// Return the file name.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_file)(
+ struct _cef_post_data_element_t* self);
+
+ ///
+ /// Return the number of bytes.
+ ///
+ size_t(CEF_CALLBACK* get_bytes_count)(struct _cef_post_data_element_t* self);
+
+ ///
+ /// Read up to |size| bytes into |bytes| and return the number of bytes
+ /// actually read.
+ ///
+ size_t(CEF_CALLBACK* get_bytes)(struct _cef_post_data_element_t* self,
+ size_t size,
+ void* bytes);
+} cef_post_data_element_t;
+
+///
+/// Create a new cef_post_data_element_t object.
+///
+CEF_EXPORT cef_post_data_element_t* cef_post_data_element_create(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_REQUEST_CAPI_H_
diff --git a/include/capi/cef_request_context_capi.h b/include/capi/cef_request_context_capi.h
new file mode 100644
index 00000000..58f3ef2d
--- /dev/null
+++ b/include/capi/cef_request_context_capi.h
@@ -0,0 +1,331 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=c2a6265e8e9acce475a8b5755a8c58b97b495207$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_REQUEST_CONTEXT_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_REQUEST_CONTEXT_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_callback_capi.h"
+#include "include/capi/cef_cookie_capi.h"
+#include "include/capi/cef_extension_capi.h"
+#include "include/capi/cef_extension_handler_capi.h"
+#include "include/capi/cef_media_router_capi.h"
+#include "include/capi/cef_preference_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _cef_request_context_handler_t;
+struct _cef_scheme_handler_factory_t;
+
+///
+/// Callback structure for cef_request_context_t::ResolveHost.
+///
+typedef struct _cef_resolve_callback_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Called on the UI thread after the ResolveHost request has completed.
+ /// |result| will be the result code. |resolved_ips| will be the list of
+ /// resolved IP addresses or NULL if the resolution failed.
+ ///
+ void(CEF_CALLBACK* on_resolve_completed)(struct _cef_resolve_callback_t* self,
+ cef_errorcode_t result,
+ cef_string_list_t resolved_ips);
+} cef_resolve_callback_t;
+
+///
+/// A request context provides request handling for a set of related browser or
+/// URL request objects. A request context can be specified when creating a new
+/// browser via the cef_browser_host_t static factory functions or when creating
+/// a new URL request via the cef_urlrequest_t static factory functions. Browser
+/// objects with different request contexts will never be hosted in the same
+/// render process. Browser objects with the same request context may or may not
+/// be hosted in the same render process depending on the process model. Browser
+/// objects created indirectly via the JavaScript window.open function or
+/// targeted links will share the same render process and the same request
+/// context as the source browser. When running in single-process mode there is
+/// only a single render process (the main process) and so all browsers created
+/// in single-process mode will share the same request context. This will be the
+/// first request context passed into a cef_browser_host_t static factory
+/// function and all other request context objects will be ignored.
+///
+typedef struct _cef_request_context_t {
+ ///
+ /// Base structure.
+ ///
+ cef_preference_manager_t base;
+
+ ///
+ /// Returns true (1) if this object is pointing to the same context as |that|
+ /// object.
+ ///
+ int(CEF_CALLBACK* is_same)(struct _cef_request_context_t* self,
+ struct _cef_request_context_t* other);
+
+ ///
+ /// Returns true (1) if this object is sharing the same storage as |that|
+ /// object.
+ ///
+ int(CEF_CALLBACK* is_sharing_with)(struct _cef_request_context_t* self,
+ struct _cef_request_context_t* other);
+
+ ///
+ /// Returns true (1) if this object is the global context. The global context
+ /// is used by default when creating a browser or URL request with a NULL
+ /// context argument.
+ ///
+ int(CEF_CALLBACK* is_global)(struct _cef_request_context_t* self);
+
+ ///
+ /// Returns the handler for this context if any.
+ ///
+ struct _cef_request_context_handler_t*(CEF_CALLBACK* get_handler)(
+ struct _cef_request_context_t* self);
+
+ ///
+ /// Returns the cache path for this object. If NULL an "incognito mode" in-
+ /// memory cache is being used.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_cache_path)(
+ struct _cef_request_context_t* self);
+
+ ///
+ /// Returns the cookie manager for this object. If |callback| is non-NULL it
+ /// will be executed asnychronously on the UI thread after the manager's
+ /// storage has been initialized.
+ ///
+ struct _cef_cookie_manager_t*(CEF_CALLBACK* get_cookie_manager)(
+ struct _cef_request_context_t* self,
+ struct _cef_completion_callback_t* callback);
+
+ ///
+ /// Register a scheme handler factory for the specified |scheme_name| and
+ /// optional |domain_name|. An NULL |domain_name| value for a standard scheme
+ /// will cause the factory to match all domain names. The |domain_name| value
+ /// will be ignored for non-standard schemes. If |scheme_name| is a built-in
+ /// scheme and no handler is returned by |factory| then the built-in scheme
+ /// handler factory will be called. If |scheme_name| is a custom scheme then
+ /// you must also implement the cef_app_t::on_register_custom_schemes()
+ /// function in all processes. This function may be called multiple times to
+ /// change or remove the factory that matches the specified |scheme_name| and
+ /// optional |domain_name|. Returns false (0) if an error occurs. This
+ /// function may be called on any thread in the browser process.
+ ///
+ int(CEF_CALLBACK* register_scheme_handler_factory)(
+ struct _cef_request_context_t* self,
+ const cef_string_t* scheme_name,
+ const cef_string_t* domain_name,
+ struct _cef_scheme_handler_factory_t* factory);
+
+ ///
+ /// Clear all registered scheme handler factories. Returns false (0) on error.
+ /// This function may be called on any thread in the browser process.
+ ///
+ int(CEF_CALLBACK* clear_scheme_handler_factories)(
+ struct _cef_request_context_t* self);
+
+ ///
+ /// Clears all certificate exceptions that were added as part of handling
+ /// cef_request_handler_t::on_certificate_error(). If you call this it is
+ /// recommended that you also call close_all_connections() or you risk not
+ /// being prompted again for server certificates if you reconnect quickly. If
+ /// |callback| is non-NULL it will be executed on the UI thread after
+ /// completion.
+ ///
+ void(CEF_CALLBACK* clear_certificate_exceptions)(
+ struct _cef_request_context_t* self,
+ struct _cef_completion_callback_t* callback);
+
+ ///
+ /// Clears all HTTP authentication credentials that were added as part of
+ /// handling GetAuthCredentials. If |callback| is non-NULL it will be executed
+ /// on the UI thread after completion.
+ ///
+ void(CEF_CALLBACK* clear_http_auth_credentials)(
+ struct _cef_request_context_t* self,
+ struct _cef_completion_callback_t* callback);
+
+ ///
+ /// Clears all active and idle connections that Chromium currently has. This
+ /// is only recommended if you have released all other CEF objects but don't
+ /// yet want to call cef_shutdown(). If |callback| is non-NULL it will be
+ /// executed on the UI thread after completion.
+ ///
+ void(CEF_CALLBACK* close_all_connections)(
+ struct _cef_request_context_t* self,
+ struct _cef_completion_callback_t* callback);
+
+ ///
+ /// Attempts to resolve |origin| to a list of associated IP addresses.
+ /// |callback| will be executed on the UI thread after completion.
+ ///
+ void(CEF_CALLBACK* resolve_host)(struct _cef_request_context_t* self,
+ const cef_string_t* origin,
+ struct _cef_resolve_callback_t* callback);
+
+ ///
+ /// Load an extension.
+ ///
+ /// If extension resources will be read from disk using the default load
+ /// implementation then |root_directory| should be the absolute path to the
+ /// extension resources directory and |manifest| should be NULL. If extension
+ /// resources will be provided by the client (e.g. via cef_request_handler_t
+ /// and/or cef_extension_handler_t) then |root_directory| should be a path
+ /// component unique to the extension (if not absolute this will be internally
+ /// prefixed with the PK_DIR_RESOURCES path) and |manifest| should contain the
+ /// contents that would otherwise be read from the "manifest.json" file on
+ /// disk.
+ ///
+ /// The loaded extension will be accessible in all contexts sharing the same
+ /// storage (HasExtension returns true (1)). However, only the context on
+ /// which this function was called is considered the loader (DidLoadExtension
+ /// returns true (1)) and only the loader will receive
+ /// cef_request_context_handler_t callbacks for the extension.
+ ///
+ /// cef_extension_handler_t::OnExtensionLoaded will be called on load success
+ /// or cef_extension_handler_t::OnExtensionLoadFailed will be called on load
+ /// failure.
+ ///
+ /// If the extension specifies a background script via the "background"
+ /// manifest key then cef_extension_handler_t::OnBeforeBackgroundBrowser will
+ /// be called to create the background browser. See that function for
+ /// additional information about background scripts.
+ ///
+ /// For visible extension views the client application should evaluate the
+ /// manifest to determine the correct extension URL to load and then pass that
+ /// URL to the cef_browser_host_t::CreateBrowser* function after the extension
+ /// has loaded. For example, the client can look for the "browser_action"
+ /// manifest key as documented at
+ /// https://developer.chrome.com/extensions/browserAction. Extension URLs take
+ /// the form "chrome-extension://<extension_id>/<path>".
+ ///
+ /// Browsers that host extensions differ from normal browsers as follows:
+ /// - Can access chrome.* JavaScript APIs if allowed by the manifest. Visit
+ /// chrome://extensions-support for the list of extension APIs currently
+ /// supported by CEF.
+ /// - Main frame navigation to non-extension content is blocked.
+ /// - Pinch-zooming is disabled.
+ /// - CefBrowserHost::GetExtension returns the hosted extension.
+ /// - CefBrowserHost::IsBackgroundHost returns true for background hosts.
+ ///
+ /// See https://developer.chrome.com/extensions for extension implementation
+ /// and usage documentation.
+ ///
+ void(CEF_CALLBACK* load_extension)(struct _cef_request_context_t* self,
+ const cef_string_t* root_directory,
+ struct _cef_dictionary_value_t* manifest,
+ struct _cef_extension_handler_t* handler);
+
+ ///
+ /// Returns true (1) if this context was used to load the extension identified
+ /// by |extension_id|. Other contexts sharing the same storage will also have
+ /// access to the extension (see HasExtension). This function must be called
+ /// on the browser process UI thread.
+ ///
+ int(CEF_CALLBACK* did_load_extension)(struct _cef_request_context_t* self,
+ const cef_string_t* extension_id);
+
+ ///
+ /// Returns true (1) if this context has access to the extension identified by
+ /// |extension_id|. This may not be the context that was used to load the
+ /// extension (see DidLoadExtension). This function must be called on the
+ /// browser process UI thread.
+ ///
+ int(CEF_CALLBACK* has_extension)(struct _cef_request_context_t* self,
+ const cef_string_t* extension_id);
+
+ ///
+ /// Retrieve the list of all extensions that this context has access to (see
+ /// HasExtension). |extension_ids| will be populated with the list of
+ /// extension ID values. Returns true (1) on success. This function must be
+ /// called on the browser process UI thread.
+ ///
+ int(CEF_CALLBACK* get_extensions)(struct _cef_request_context_t* self,
+ cef_string_list_t extension_ids);
+
+ ///
+ /// Returns the extension matching |extension_id| or NULL if no matching
+ /// extension is accessible in this context (see HasExtension). This function
+ /// must be called on the browser process UI thread.
+ ///
+ struct _cef_extension_t*(CEF_CALLBACK* get_extension)(
+ struct _cef_request_context_t* self,
+ const cef_string_t* extension_id);
+
+ ///
+ /// Returns the MediaRouter object associated with this context. If
+ /// |callback| is non-NULL it will be executed asnychronously on the UI thread
+ /// after the manager's context has been initialized.
+ ///
+ struct _cef_media_router_t*(CEF_CALLBACK* get_media_router)(
+ struct _cef_request_context_t* self,
+ struct _cef_completion_callback_t* callback);
+} cef_request_context_t;
+
+///
+/// Returns the global context object.
+///
+CEF_EXPORT cef_request_context_t* cef_request_context_get_global_context(void);
+
+///
+/// Creates a new context object with the specified |settings| and optional
+/// |handler|.
+///
+CEF_EXPORT cef_request_context_t* cef_request_context_create_context(
+ const struct _cef_request_context_settings_t* settings,
+ struct _cef_request_context_handler_t* handler);
+
+///
+/// Creates a new context object that shares storage with |other| and uses an
+/// optional |handler|.
+///
+CEF_EXPORT cef_request_context_t* cef_create_context_shared(
+ cef_request_context_t* other,
+ struct _cef_request_context_handler_t* handler);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_REQUEST_CONTEXT_CAPI_H_
diff --git a/include/capi/cef_request_context_handler_capi.h b/include/capi/cef_request_context_handler_capi.h
new file mode 100644
index 00000000..d7e06f81
--- /dev/null
+++ b/include/capi/cef_request_context_handler_capi.h
@@ -0,0 +1,108 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=b0b532a12106d960adc446b980affeee12b93ae3$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_REQUEST_CONTEXT_HANDLER_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_REQUEST_CONTEXT_HANDLER_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+#include "include/capi/cef_browser_capi.h"
+#include "include/capi/cef_frame_capi.h"
+#include "include/capi/cef_preference_capi.h"
+#include "include/capi/cef_request_capi.h"
+#include "include/capi/cef_resource_request_handler_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Implement this structure to provide handler implementations. The handler
+/// instance will not be released until all objects related to the context have
+/// been destroyed.
+///
+typedef struct _cef_request_context_handler_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Called on the browser process UI thread immediately after the request
+ /// context has been initialized.
+ ///
+ void(CEF_CALLBACK* on_request_context_initialized)(
+ struct _cef_request_context_handler_t* self,
+ struct _cef_request_context_t* request_context);
+
+ ///
+ /// Called on the browser process IO thread before a resource request is
+ /// initiated. The |browser| and |frame| values represent the source of the
+ /// request, and may be NULL for requests originating from service workers or
+ /// cef_urlrequest_t. |request| represents the request contents and cannot be
+ /// modified in this callback. |is_navigation| will be true (1) if the
+ /// resource request is a navigation. |is_download| will be true (1) if the
+ /// resource request is a download. |request_initiator| is the origin (scheme
+ /// + domain) of the page that initiated the request. Set
+ /// |disable_default_handling| to true (1) to disable default handling of the
+ /// request, in which case it will need to be handled via
+ /// cef_resource_request_handler_t::GetResourceHandler or it will be canceled.
+ /// To allow the resource load to proceed with default handling return NULL.
+ /// To specify a handler for the resource return a
+ /// cef_resource_request_handler_t object. This function will not be called if
+ /// the client associated with |browser| returns a non-NULL value from
+ /// cef_request_handler_t::GetResourceRequestHandler for the same request
+ /// (identified by cef_request_t::GetIdentifier).
+ ///
+ struct _cef_resource_request_handler_t*(
+ CEF_CALLBACK* get_resource_request_handler)(
+ struct _cef_request_context_handler_t* self,
+ struct _cef_browser_t* browser,
+ struct _cef_frame_t* frame,
+ struct _cef_request_t* request,
+ int is_navigation,
+ int is_download,
+ const cef_string_t* request_initiator,
+ int* disable_default_handling);
+} cef_request_context_handler_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_REQUEST_CONTEXT_HANDLER_CAPI_H_
diff --git a/include/capi/cef_request_handler_capi.h b/include/capi/cef_request_handler_capi.h
new file mode 100644
index 00000000..9dd95a14
--- /dev/null
+++ b/include/capi/cef_request_handler_capi.h
@@ -0,0 +1,247 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=092d897e223273a940ed623547d82645f764519c$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_REQUEST_HANDLER_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_REQUEST_HANDLER_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_auth_callback_capi.h"
+#include "include/capi/cef_base_capi.h"
+#include "include/capi/cef_browser_capi.h"
+#include "include/capi/cef_callback_capi.h"
+#include "include/capi/cef_frame_capi.h"
+#include "include/capi/cef_request_capi.h"
+#include "include/capi/cef_resource_request_handler_capi.h"
+#include "include/capi/cef_ssl_info_capi.h"
+#include "include/capi/cef_x509_certificate_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Callback structure used to select a client certificate for authentication.
+///
+typedef struct _cef_select_client_certificate_callback_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Chooses the specified certificate for client certificate authentication.
+ /// NULL value means that no client certificate should be used.
+ ///
+ void(CEF_CALLBACK* select)(
+ struct _cef_select_client_certificate_callback_t* self,
+ struct _cef_x509certificate_t* cert);
+} cef_select_client_certificate_callback_t;
+
+///
+/// Implement this structure to handle events related to browser requests. The
+/// functions of this structure will be called on the thread indicated.
+///
+typedef struct _cef_request_handler_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Called on the UI thread before browser navigation. Return true (1) to
+ /// cancel the navigation or false (0) to allow the navigation to proceed. The
+ /// |request| object cannot be modified in this callback.
+ /// cef_load_handler_t::OnLoadingStateChange will be called twice in all
+ /// cases. If the navigation is allowed cef_load_handler_t::OnLoadStart and
+ /// cef_load_handler_t::OnLoadEnd will be called. If the navigation is
+ /// canceled cef_load_handler_t::OnLoadError will be called with an
+ /// |errorCode| value of ERR_ABORTED. The |user_gesture| value will be true
+ /// (1) if the browser navigated via explicit user gesture (e.g. clicking a
+ /// link) or false (0) if it navigated automatically (e.g. via the
+ /// DomContentLoaded event).
+ ///
+ int(CEF_CALLBACK* on_before_browse)(struct _cef_request_handler_t* self,
+ struct _cef_browser_t* browser,
+ struct _cef_frame_t* frame,
+ struct _cef_request_t* request,
+ int user_gesture,
+ int is_redirect);
+
+ ///
+ /// Called on the UI thread before OnBeforeBrowse in certain limited cases
+ /// where navigating a new or different browser might be desirable. This
+ /// includes user-initiated navigation that might open in a special way (e.g.
+ /// links clicked via middle-click or ctrl + left-click) and certain types of
+ /// cross-origin navigation initiated from the renderer process (e.g.
+ /// navigating the top-level frame to/from a file URL). The |browser| and
+ /// |frame| values represent the source of the navigation. The
+ /// |target_disposition| value indicates where the user intended to navigate
+ /// the browser based on standard Chromium behaviors (e.g. current tab, new
+ /// tab, etc). The |user_gesture| value will be true (1) if the browser
+ /// navigated via explicit user gesture (e.g. clicking a link) or false (0) if
+ /// it navigated automatically (e.g. via the DomContentLoaded event). Return
+ /// true (1) to cancel the navigation or false (0) to allow the navigation to
+ /// proceed in the source browser's top-level frame.
+ ///
+ int(CEF_CALLBACK* on_open_urlfrom_tab)(
+ struct _cef_request_handler_t* self,
+ struct _cef_browser_t* browser,
+ struct _cef_frame_t* frame,
+ const cef_string_t* target_url,
+ cef_window_open_disposition_t target_disposition,
+ int user_gesture);
+
+ ///
+ /// Called on the browser process IO thread before a resource request is
+ /// initiated. The |browser| and |frame| values represent the source of the
+ /// request. |request| represents the request contents and cannot be modified
+ /// in this callback. |is_navigation| will be true (1) if the resource request
+ /// is a navigation. |is_download| will be true (1) if the resource request is
+ /// a download. |request_initiator| is the origin (scheme + domain) of the
+ /// page that initiated the request. Set |disable_default_handling| to true
+ /// (1) to disable default handling of the request, in which case it will need
+ /// to be handled via cef_resource_request_handler_t::GetResourceHandler or it
+ /// will be canceled. To allow the resource load to proceed with default
+ /// handling return NULL. To specify a handler for the resource return a
+ /// cef_resource_request_handler_t object. If this callback returns NULL the
+ /// same function will be called on the associated
+ /// cef_request_context_handler_t, if any.
+ ///
+ struct _cef_resource_request_handler_t*(
+ CEF_CALLBACK* get_resource_request_handler)(
+ struct _cef_request_handler_t* self,
+ struct _cef_browser_t* browser,
+ struct _cef_frame_t* frame,
+ struct _cef_request_t* request,
+ int is_navigation,
+ int is_download,
+ const cef_string_t* request_initiator,
+ int* disable_default_handling);
+
+ ///
+ /// Called on the IO thread when the browser needs credentials from the user.
+ /// |origin_url| is the origin making this authentication request. |isProxy|
+ /// indicates whether the host is a proxy server. |host| contains the hostname
+ /// and |port| contains the port number. |realm| is the realm of the challenge
+ /// and may be NULL. |scheme| is the authentication scheme used, such as
+ /// "basic" or "digest", and will be NULL if the source of the request is an
+ /// FTP server. Return true (1) to continue the request and call
+ /// cef_auth_callback_t::cont() either in this function or at a later time
+ /// when the authentication information is available. Return false (0) to
+ /// cancel the request immediately.
+ ///
+ int(CEF_CALLBACK* get_auth_credentials)(
+ struct _cef_request_handler_t* self,
+ struct _cef_browser_t* browser,
+ const cef_string_t* origin_url,
+ int isProxy,
+ const cef_string_t* host,
+ int port,
+ const cef_string_t* realm,
+ const cef_string_t* scheme,
+ struct _cef_auth_callback_t* callback);
+
+ ///
+ /// Called on the UI thread to handle requests for URLs with an invalid SSL
+ /// certificate. Return true (1) and call cef_callback_t functions either in
+ /// this function or at a later time to continue or cancel the request. Return
+ /// false (0) to cancel the request immediately. If
+ /// cef_settings_t.ignore_certificate_errors is set all invalid certificates
+ /// will be accepted without calling this function.
+ ///
+ int(CEF_CALLBACK* on_certificate_error)(struct _cef_request_handler_t* self,
+ struct _cef_browser_t* browser,
+ cef_errorcode_t cert_error,
+ const cef_string_t* request_url,
+ struct _cef_sslinfo_t* ssl_info,
+ struct _cef_callback_t* callback);
+
+ ///
+ /// Called on the UI thread when a client certificate is being requested for
+ /// authentication. Return false (0) to use the default behavior and
+ /// automatically select the first certificate available. Return true (1) and
+ /// call cef_select_client_certificate_callback_t::Select either in this
+ /// function or at a later time to select a certificate. Do not call Select or
+ /// call it with NULL to continue without using any certificate. |isProxy|
+ /// indicates whether the host is an HTTPS proxy or the origin server. |host|
+ /// and |port| contains the hostname and port of the SSL server.
+ /// |certificates| is the list of certificates to choose from; this list has
+ /// already been pruned by Chromium so that it only contains certificates from
+ /// issuers that the server trusts.
+ ///
+ int(CEF_CALLBACK* on_select_client_certificate)(
+ struct _cef_request_handler_t* self,
+ struct _cef_browser_t* browser,
+ int isProxy,
+ const cef_string_t* host,
+ int port,
+ size_t certificatesCount,
+ struct _cef_x509certificate_t* const* certificates,
+ struct _cef_select_client_certificate_callback_t* callback);
+
+ ///
+ /// Called on the browser process UI thread when the render view associated
+ /// with |browser| is ready to receive/handle IPC messages in the render
+ /// process.
+ ///
+ void(CEF_CALLBACK* on_render_view_ready)(struct _cef_request_handler_t* self,
+ struct _cef_browser_t* browser);
+
+ ///
+ /// Called on the browser process UI thread when the render process terminates
+ /// unexpectedly. |status| indicates how the process terminated.
+ ///
+ void(CEF_CALLBACK* on_render_process_terminated)(
+ struct _cef_request_handler_t* self,
+ struct _cef_browser_t* browser,
+ cef_termination_status_t status);
+
+ ///
+ /// Called on the browser process UI thread when the window.document object of
+ /// the main frame has been created.
+ ///
+ void(CEF_CALLBACK* on_document_available_in_main_frame)(
+ struct _cef_request_handler_t* self,
+ struct _cef_browser_t* browser);
+} cef_request_handler_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_REQUEST_HANDLER_CAPI_H_
diff --git a/include/capi/cef_resource_bundle_capi.h b/include/capi/cef_resource_bundle_capi.h
new file mode 100644
index 00000000..b06728c1
--- /dev/null
+++ b/include/capi/cef_resource_bundle_capi.h
@@ -0,0 +1,104 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=e8e8dd2730a47aad9414f7bfc2e6ad96aba2c875$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_RESOURCE_BUNDLE_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_RESOURCE_BUNDLE_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+#include "include/capi/cef_values_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Structure used for retrieving resources from the resource bundle (*.pak)
+/// files loaded by CEF during startup or via the cef_resource_bundle_handler_t
+/// returned from cef_app_t::GetResourceBundleHandler. See CefSettings for
+/// additional options related to resource bundle loading. The functions of this
+/// structure may be called on any thread unless otherwise indicated.
+///
+typedef struct _cef_resource_bundle_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Returns the localized string for the specified |string_id| or an NULL
+ /// string if the value is not found. Include cef_pack_strings.h for a listing
+ /// of valid string ID values.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_localized_string)(
+ struct _cef_resource_bundle_t* self,
+ int string_id);
+
+ ///
+ /// Returns a cef_binary_value_t containing the decompressed contents of the
+ /// specified scale independent |resource_id| or NULL if not found. Include
+ /// cef_pack_resources.h for a listing of valid resource ID values.
+ ///
+ struct _cef_binary_value_t*(CEF_CALLBACK* get_data_resource)(
+ struct _cef_resource_bundle_t* self,
+ int resource_id);
+
+ ///
+ /// Returns a cef_binary_value_t containing the decompressed contents of the
+ /// specified |resource_id| nearest the scale factor |scale_factor| or NULL if
+ /// not found. Use a |scale_factor| value of SCALE_FACTOR_NONE for scale
+ /// independent resources or call GetDataResource instead.Include
+ /// cef_pack_resources.h for a listing of valid resource ID values.
+ ///
+ struct _cef_binary_value_t*(CEF_CALLBACK* get_data_resource_for_scale)(
+ struct _cef_resource_bundle_t* self,
+ int resource_id,
+ cef_scale_factor_t scale_factor);
+} cef_resource_bundle_t;
+
+///
+/// Returns the global resource bundle instance.
+///
+CEF_EXPORT cef_resource_bundle_t* cef_resource_bundle_get_global(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_RESOURCE_BUNDLE_CAPI_H_
diff --git a/include/capi/cef_resource_bundle_handler_capi.h b/include/capi/cef_resource_bundle_handler_capi.h
new file mode 100644
index 00000000..bc9eea52
--- /dev/null
+++ b/include/capi/cef_resource_bundle_handler_capi.h
@@ -0,0 +1,105 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=00023b2ec108ae6e4bd282d16e82032cdc99d548$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_RESOURCE_BUNDLE_HANDLER_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_RESOURCE_BUNDLE_HANDLER_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Structure used to implement a custom resource bundle structure. See
+/// CefSettings for additional options related to resource bundle loading. The
+/// functions of this structure may be called on multiple threads.
+///
+typedef struct _cef_resource_bundle_handler_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Called to retrieve a localized translation for the specified |string_id|.
+ /// To provide the translation set |string| to the translation string and
+ /// return true (1). To use the default translation return false (0). Include
+ /// cef_pack_strings.h for a listing of valid string ID values.
+ ///
+ int(CEF_CALLBACK* get_localized_string)(
+ struct _cef_resource_bundle_handler_t* self,
+ int string_id,
+ cef_string_t* string);
+
+ ///
+ /// Called to retrieve data for the specified scale independent |resource_id|.
+ /// To provide the resource data set |data| and |data_size| to the data
+ /// pointer and size respectively and return true (1). To use the default
+ /// resource data return false (0). The resource data will not be copied and
+ /// must remain resident in memory. Include cef_pack_resources.h for a listing
+ /// of valid resource ID values.
+ ///
+ int(CEF_CALLBACK* get_data_resource)(
+ struct _cef_resource_bundle_handler_t* self,
+ int resource_id,
+ void** data,
+ size_t* data_size);
+
+ ///
+ /// Called to retrieve data for the specified |resource_id| nearest the scale
+ /// factor |scale_factor|. To provide the resource data set |data| and
+ /// |data_size| to the data pointer and size respectively and return true (1).
+ /// To use the default resource data return false (0). The resource data will
+ /// not be copied and must remain resident in memory. Include
+ /// cef_pack_resources.h for a listing of valid resource ID values.
+ ///
+ int(CEF_CALLBACK* get_data_resource_for_scale)(
+ struct _cef_resource_bundle_handler_t* self,
+ int resource_id,
+ cef_scale_factor_t scale_factor,
+ void** data,
+ size_t* data_size);
+} cef_resource_bundle_handler_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_RESOURCE_BUNDLE_HANDLER_CAPI_H_
diff --git a/include/capi/cef_resource_handler_capi.h b/include/capi/cef_resource_handler_capi.h
new file mode 100644
index 00000000..bad0b85a
--- /dev/null
+++ b/include/capi/cef_resource_handler_capi.h
@@ -0,0 +1,210 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=93e5c4f5e93f56b63b5944208300669dcecba972$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_RESOURCE_HANDLER_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_RESOURCE_HANDLER_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+#include "include/capi/cef_browser_capi.h"
+#include "include/capi/cef_callback_capi.h"
+#include "include/capi/cef_cookie_capi.h"
+#include "include/capi/cef_request_capi.h"
+#include "include/capi/cef_response_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Callback for asynchronous continuation of cef_resource_handler_t::skip().
+///
+typedef struct _cef_resource_skip_callback_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Callback for asynchronous continuation of skip(). If |bytes_skipped| > 0
+ /// then either skip() will be called again until the requested number of
+ /// bytes have been skipped or the request will proceed. If |bytes_skipped| <=
+ /// 0 the request will fail with ERR_REQUEST_RANGE_NOT_SATISFIABLE.
+ ///
+ void(CEF_CALLBACK* cont)(struct _cef_resource_skip_callback_t* self,
+ int64 bytes_skipped);
+} cef_resource_skip_callback_t;
+
+///
+/// Callback for asynchronous continuation of cef_resource_handler_t::read().
+///
+typedef struct _cef_resource_read_callback_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Callback for asynchronous continuation of read(). If |bytes_read| == 0 the
+ /// response will be considered complete. If |bytes_read| > 0 then read() will
+ /// be called again until the request is complete (based on either the result
+ /// or the expected content length). If |bytes_read| < 0 then the request will
+ /// fail and the |bytes_read| value will be treated as the error code.
+ ///
+ void(CEF_CALLBACK* cont)(struct _cef_resource_read_callback_t* self,
+ int bytes_read);
+} cef_resource_read_callback_t;
+
+///
+/// Structure used to implement a custom request handler structure. The
+/// functions of this structure will be called on the IO thread unless otherwise
+/// indicated.
+///
+typedef struct _cef_resource_handler_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Open the response stream. To handle the request immediately set
+ /// |handle_request| to true (1) and return true (1). To decide at a later
+ /// time set |handle_request| to false (0), return true (1), and execute
+ /// |callback| to continue or cancel the request. To cancel the request
+ /// immediately set |handle_request| to true (1) and return false (0). This
+ /// function will be called in sequence but not from a dedicated thread. For
+ /// backwards compatibility set |handle_request| to false (0) and return false
+ /// (0) and the ProcessRequest function will be called.
+ ///
+ int(CEF_CALLBACK* open)(struct _cef_resource_handler_t* self,
+ struct _cef_request_t* request,
+ int* handle_request,
+ struct _cef_callback_t* callback);
+
+ ///
+ /// Begin processing the request. To handle the request return true (1) and
+ /// call cef_callback_t::cont() once the response header information is
+ /// available (cef_callback_t::cont() can also be called from inside this
+ /// function if header information is available immediately). To cancel the
+ /// request return false (0).
+ ///
+ /// WARNING: This function is deprecated. Use Open instead.
+ ///
+ int(CEF_CALLBACK* process_request)(struct _cef_resource_handler_t* self,
+ struct _cef_request_t* request,
+ struct _cef_callback_t* callback);
+
+ ///
+ /// Retrieve response header information. If the response length is not known
+ /// set |response_length| to -1 and read_response() will be called until it
+ /// returns false (0). If the response length is known set |response_length|
+ /// to a positive value and read_response() will be called until it returns
+ /// false (0) or the specified number of bytes have been read. Use the
+ /// |response| object to set the mime type, http status code and other
+ /// optional header values. To redirect the request to a new URL set
+ /// |redirectUrl| to the new URL. |redirectUrl| can be either a relative or
+ /// fully qualified URL. It is also possible to set |response| to a redirect
+ /// http status code and pass the new URL via a Location header. Likewise with
+ /// |redirectUrl| it is valid to set a relative or fully qualified URL as the
+ /// Location header value. If an error occured while setting up the request
+ /// you can call set_error() on |response| to indicate the error condition.
+ ///
+ void(CEF_CALLBACK* get_response_headers)(struct _cef_resource_handler_t* self,
+ struct _cef_response_t* response,
+ int64* response_length,
+ cef_string_t* redirectUrl);
+
+ ///
+ /// Skip response data when requested by a Range header. Skip over and discard
+ /// |bytes_to_skip| bytes of response data. If data is available immediately
+ /// set |bytes_skipped| to the number of bytes skipped and return true (1). To
+ /// read the data at a later time set |bytes_skipped| to 0, return true (1)
+ /// and execute |callback| when the data is available. To indicate failure set
+ /// |bytes_skipped| to < 0 (e.g. -2 for ERR_FAILED) and return false (0). This
+ /// function will be called in sequence but not from a dedicated thread.
+ ///
+ int(CEF_CALLBACK* skip)(struct _cef_resource_handler_t* self,
+ int64 bytes_to_skip,
+ int64* bytes_skipped,
+ struct _cef_resource_skip_callback_t* callback);
+
+ ///
+ /// Read response data. If data is available immediately copy up to
+ /// |bytes_to_read| bytes into |data_out|, set |bytes_read| to the number of
+ /// bytes copied, and return true (1). To read the data at a later time keep a
+ /// pointer to |data_out|, set |bytes_read| to 0, return true (1) and execute
+ /// |callback| when the data is available (|data_out| will remain valid until
+ /// the callback is executed). To indicate response completion set
+ /// |bytes_read| to 0 and return false (0). To indicate failure set
+ /// |bytes_read| to < 0 (e.g. -2 for ERR_FAILED) and return false (0). This
+ /// function will be called in sequence but not from a dedicated thread. For
+ /// backwards compatibility set |bytes_read| to -1 and return false (0) and
+ /// the ReadResponse function will be called.
+ ///
+ int(CEF_CALLBACK* read)(struct _cef_resource_handler_t* self,
+ void* data_out,
+ int bytes_to_read,
+ int* bytes_read,
+ struct _cef_resource_read_callback_t* callback);
+
+ ///
+ /// Read response data. If data is available immediately copy up to
+ /// |bytes_to_read| bytes into |data_out|, set |bytes_read| to the number of
+ /// bytes copied, and return true (1). To read the data at a later time set
+ /// |bytes_read| to 0, return true (1) and call cef_callback_t::cont() when
+ /// the data is available. To indicate response completion return false (0).
+ ///
+ /// WARNING: This function is deprecated. Use Skip and Read instead.
+ ///
+ int(CEF_CALLBACK* read_response)(struct _cef_resource_handler_t* self,
+ void* data_out,
+ int bytes_to_read,
+ int* bytes_read,
+ struct _cef_callback_t* callback);
+
+ ///
+ /// Request processing has been canceled.
+ ///
+ void(CEF_CALLBACK* cancel)(struct _cef_resource_handler_t* self);
+} cef_resource_handler_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_RESOURCE_HANDLER_CAPI_H_
diff --git a/include/capi/cef_resource_request_handler_capi.h b/include/capi/cef_resource_request_handler_capi.h
new file mode 100644
index 00000000..18405562
--- /dev/null
+++ b/include/capi/cef_resource_request_handler_capi.h
@@ -0,0 +1,255 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=70d6b393cbdc96a75864911d7ca3568cc8dcdebf$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_RESOURCE_REQUEST_HANDLER_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_RESOURCE_REQUEST_HANDLER_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+#include "include/capi/cef_browser_capi.h"
+#include "include/capi/cef_callback_capi.h"
+#include "include/capi/cef_frame_capi.h"
+#include "include/capi/cef_request_capi.h"
+#include "include/capi/cef_resource_handler_capi.h"
+#include "include/capi/cef_response_capi.h"
+#include "include/capi/cef_response_filter_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _cef_cookie_access_filter_t;
+
+///
+/// Implement this structure to handle events related to browser requests. The
+/// functions of this structure will be called on the IO thread unless otherwise
+/// indicated.
+///
+typedef struct _cef_resource_request_handler_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Called on the IO thread before a resource request is loaded. The |browser|
+ /// and |frame| values represent the source of the request, and may be NULL
+ /// for requests originating from service workers or cef_urlrequest_t. To
+ /// optionally filter cookies for the request return a
+ /// cef_cookie_access_filter_t object. The |request| object cannot not be
+ /// modified in this callback.
+ ///
+ struct _cef_cookie_access_filter_t*(CEF_CALLBACK* get_cookie_access_filter)(
+ struct _cef_resource_request_handler_t* self,
+ struct _cef_browser_t* browser,
+ struct _cef_frame_t* frame,
+ struct _cef_request_t* request);
+
+ ///
+ /// Called on the IO thread before a resource request is loaded. The |browser|
+ /// and |frame| values represent the source of the request, and may be NULL
+ /// for requests originating from service workers or cef_urlrequest_t. To
+ /// redirect or change the resource load optionally modify |request|.
+ /// Modification of the request URL will be treated as a redirect. Return
+ /// RV_CONTINUE to continue the request immediately. Return RV_CONTINUE_ASYNC
+ /// and call cef_callback_t functions at a later time to continue or cancel
+ /// the request asynchronously. Return RV_CANCEL to cancel the request
+ /// immediately.
+ ///
+ cef_return_value_t(CEF_CALLBACK* on_before_resource_load)(
+ struct _cef_resource_request_handler_t* self,
+ struct _cef_browser_t* browser,
+ struct _cef_frame_t* frame,
+ struct _cef_request_t* request,
+ struct _cef_callback_t* callback);
+
+ ///
+ /// Called on the IO thread before a resource is loaded. The |browser| and
+ /// |frame| values represent the source of the request, and may be NULL for
+ /// requests originating from service workers or cef_urlrequest_t. To allow
+ /// the resource to load using the default network loader return NULL. To
+ /// specify a handler for the resource return a cef_resource_handler_t object.
+ /// The |request| object cannot not be modified in this callback.
+ ///
+ struct _cef_resource_handler_t*(CEF_CALLBACK* get_resource_handler)(
+ struct _cef_resource_request_handler_t* self,
+ struct _cef_browser_t* browser,
+ struct _cef_frame_t* frame,
+ struct _cef_request_t* request);
+
+ ///
+ /// Called on the IO thread when a resource load is redirected. The |browser|
+ /// and |frame| values represent the source of the request, and may be NULL
+ /// for requests originating from service workers or cef_urlrequest_t. The
+ /// |request| parameter will contain the old URL and other request-related
+ /// information. The |response| parameter will contain the response that
+ /// resulted in the redirect. The |new_url| parameter will contain the new URL
+ /// and can be changed if desired. The |request| and |response| objects cannot
+ /// be modified in this callback.
+ ///
+ void(CEF_CALLBACK* on_resource_redirect)(
+ struct _cef_resource_request_handler_t* self,
+ struct _cef_browser_t* browser,
+ struct _cef_frame_t* frame,
+ struct _cef_request_t* request,
+ struct _cef_response_t* response,
+ cef_string_t* new_url);
+
+ ///
+ /// Called on the IO thread when a resource response is received. The
+ /// |browser| and |frame| values represent the source of the request, and may
+ /// be NULL for requests originating from service workers or cef_urlrequest_t.
+ /// To allow the resource load to proceed without modification return false
+ /// (0). To redirect or retry the resource load optionally modify |request|
+ /// and return true (1). Modification of the request URL will be treated as a
+ /// redirect. Requests handled using the default network loader cannot be
+ /// redirected in this callback. The |response| object cannot be modified in
+ /// this callback.
+ ///
+ /// WARNING: Redirecting using this function is deprecated. Use
+ /// OnBeforeResourceLoad or GetResourceHandler to perform redirects.
+ ///
+ int(CEF_CALLBACK* on_resource_response)(
+ struct _cef_resource_request_handler_t* self,
+ struct _cef_browser_t* browser,
+ struct _cef_frame_t* frame,
+ struct _cef_request_t* request,
+ struct _cef_response_t* response);
+
+ ///
+ /// Called on the IO thread to optionally filter resource response content.
+ /// The |browser| and |frame| values represent the source of the request, and
+ /// may be NULL for requests originating from service workers or
+ /// cef_urlrequest_t. |request| and |response| represent the request and
+ /// response respectively and cannot be modified in this callback.
+ ///
+ struct _cef_response_filter_t*(CEF_CALLBACK* get_resource_response_filter)(
+ struct _cef_resource_request_handler_t* self,
+ struct _cef_browser_t* browser,
+ struct _cef_frame_t* frame,
+ struct _cef_request_t* request,
+ struct _cef_response_t* response);
+
+ ///
+ /// Called on the IO thread when a resource load has completed. The |browser|
+ /// and |frame| values represent the source of the request, and may be NULL
+ /// for requests originating from service workers or cef_urlrequest_t.
+ /// |request| and |response| represent the request and response respectively
+ /// and cannot be modified in this callback. |status| indicates the load
+ /// completion status. |received_content_length| is the number of response
+ /// bytes actually read. This function will be called for all requests,
+ /// including requests that are aborted due to CEF shutdown or destruction of
+ /// the associated browser. In cases where the associated browser is destroyed
+ /// this callback may arrive after the cef_life_span_handler_t::OnBeforeClose
+ /// callback for that browser. The cef_frame_t::IsValid function can be used
+ /// to test for this situation, and care should be taken not to call |browser|
+ /// or |frame| functions that modify state (like LoadURL, SendProcessMessage,
+ /// etc.) if the frame is invalid.
+ ///
+ void(CEF_CALLBACK* on_resource_load_complete)(
+ struct _cef_resource_request_handler_t* self,
+ struct _cef_browser_t* browser,
+ struct _cef_frame_t* frame,
+ struct _cef_request_t* request,
+ struct _cef_response_t* response,
+ cef_urlrequest_status_t status,
+ int64 received_content_length);
+
+ ///
+ /// Called on the IO thread to handle requests for URLs with an unknown
+ /// protocol component. The |browser| and |frame| values represent the source
+ /// of the request, and may be NULL for requests originating from service
+ /// workers or cef_urlrequest_t. |request| cannot be modified in this
+ /// callback. Set |allow_os_execution| to true (1) to attempt execution via
+ /// the registered OS protocol handler, if any. SECURITY WARNING: YOU SHOULD
+ /// USE THIS METHOD TO ENFORCE RESTRICTIONS BASED ON SCHEME, HOST OR OTHER URL
+ /// ANALYSIS BEFORE ALLOWING OS EXECUTION.
+ ///
+ void(CEF_CALLBACK* on_protocol_execution)(
+ struct _cef_resource_request_handler_t* self,
+ struct _cef_browser_t* browser,
+ struct _cef_frame_t* frame,
+ struct _cef_request_t* request,
+ int* allow_os_execution);
+} cef_resource_request_handler_t;
+
+///
+/// Implement this structure to filter cookies that may be sent or received from
+/// resource requests. The functions of this structure will be called on the IO
+/// thread unless otherwise indicated.
+///
+typedef struct _cef_cookie_access_filter_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Called on the IO thread before a resource request is sent. The |browser|
+ /// and |frame| values represent the source of the request, and may be NULL
+ /// for requests originating from service workers or cef_urlrequest_t.
+ /// |request| cannot be modified in this callback. Return true (1) if the
+ /// specified cookie can be sent with the request or false (0) otherwise.
+ ///
+ int(CEF_CALLBACK* can_send_cookie)(struct _cef_cookie_access_filter_t* self,
+ struct _cef_browser_t* browser,
+ struct _cef_frame_t* frame,
+ struct _cef_request_t* request,
+ const struct _cef_cookie_t* cookie);
+
+ ///
+ /// Called on the IO thread after a resource response is received. The
+ /// |browser| and |frame| values represent the source of the request, and may
+ /// be NULL for requests originating from service workers or cef_urlrequest_t.
+ /// |request| cannot be modified in this callback. Return true (1) if the
+ /// specified cookie returned with the response can be saved or false (0)
+ /// otherwise.
+ ///
+ int(CEF_CALLBACK* can_save_cookie)(struct _cef_cookie_access_filter_t* self,
+ struct _cef_browser_t* browser,
+ struct _cef_frame_t* frame,
+ struct _cef_request_t* request,
+ struct _cef_response_t* response,
+ const struct _cef_cookie_t* cookie);
+} cef_cookie_access_filter_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_RESOURCE_REQUEST_HANDLER_CAPI_H_
diff --git a/include/capi/cef_response_capi.h b/include/capi/cef_response_capi.h
new file mode 100644
index 00000000..d8c4b655
--- /dev/null
+++ b/include/capi/cef_response_capi.h
@@ -0,0 +1,177 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=7fbcd399c08dc39e33a7d0400a49f2e3a551bd02$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_RESPONSE_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_RESPONSE_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Structure used to represent a web response. The functions of this structure
+/// may be called on any thread.
+///
+typedef struct _cef_response_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Returns true (1) if this object is read-only.
+ ///
+ int(CEF_CALLBACK* is_read_only)(struct _cef_response_t* self);
+
+ ///
+ /// Get the response error code. Returns ERR_NONE if there was no error.
+ ///
+ cef_errorcode_t(CEF_CALLBACK* get_error)(struct _cef_response_t* self);
+
+ ///
+ /// Set the response error code. This can be used by custom scheme handlers to
+ /// return errors during initial request processing.
+ ///
+ void(CEF_CALLBACK* set_error)(struct _cef_response_t* self,
+ cef_errorcode_t error);
+
+ ///
+ /// Get the response status code.
+ ///
+ int(CEF_CALLBACK* get_status)(struct _cef_response_t* self);
+
+ ///
+ /// Set the response status code.
+ ///
+ void(CEF_CALLBACK* set_status)(struct _cef_response_t* self, int status);
+
+ ///
+ /// Get the response status text.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_status_text)(
+ struct _cef_response_t* self);
+
+ ///
+ /// Set the response status text.
+ ///
+ void(CEF_CALLBACK* set_status_text)(struct _cef_response_t* self,
+ const cef_string_t* statusText);
+
+ ///
+ /// Get the response mime type.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_mime_type)(
+ struct _cef_response_t* self);
+
+ ///
+ /// Set the response mime type.
+ ///
+ void(CEF_CALLBACK* set_mime_type)(struct _cef_response_t* self,
+ const cef_string_t* mimeType);
+
+ ///
+ /// Get the response charset.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_charset)(
+ struct _cef_response_t* self);
+
+ ///
+ /// Set the response charset.
+ ///
+ void(CEF_CALLBACK* set_charset)(struct _cef_response_t* self,
+ const cef_string_t* charset);
+
+ ///
+ /// Get the value for the specified response header field.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_header_by_name)(
+ struct _cef_response_t* self,
+ const cef_string_t* name);
+
+ ///
+ /// Set the header |name| to |value|. If |overwrite| is true (1) any existing
+ /// values will be replaced with the new value. If |overwrite| is false (0)
+ /// any existing values will not be overwritten.
+ ///
+ void(CEF_CALLBACK* set_header_by_name)(struct _cef_response_t* self,
+ const cef_string_t* name,
+ const cef_string_t* value,
+ int overwrite);
+
+ ///
+ /// Get all response header fields.
+ ///
+ void(CEF_CALLBACK* get_header_map)(struct _cef_response_t* self,
+ cef_string_multimap_t headerMap);
+
+ ///
+ /// Set all response header fields.
+ ///
+ void(CEF_CALLBACK* set_header_map)(struct _cef_response_t* self,
+ cef_string_multimap_t headerMap);
+
+ ///
+ /// Get the resolved URL after redirects or changed as a result of HSTS.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_url)(struct _cef_response_t* self);
+
+ ///
+ /// Set the resolved URL after redirects or changed as a result of HSTS.
+ ///
+ void(CEF_CALLBACK* set_url)(struct _cef_response_t* self,
+ const cef_string_t* url);
+} cef_response_t;
+
+///
+/// Create a new cef_response_t object.
+///
+CEF_EXPORT cef_response_t* cef_response_create(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_RESPONSE_CAPI_H_
diff --git a/include/capi/cef_response_filter_capi.h b/include/capi/cef_response_filter_capi.h
new file mode 100644
index 00000000..c8a57de2
--- /dev/null
+++ b/include/capi/cef_response_filter_capi.h
@@ -0,0 +1,110 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=2c9b14a86ee6777e4834eadcfc95802f2dedb11a$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_RESPONSE_FILTER_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_RESPONSE_FILTER_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Implement this structure to filter resource response content. The functions
+/// of this structure will be called on the browser process IO thread.
+///
+typedef struct _cef_response_filter_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Initialize the response filter. Will only be called a single time. The
+ /// filter will not be installed if this function returns false (0).
+ ///
+ int(CEF_CALLBACK* init_filter)(struct _cef_response_filter_t* self);
+
+ ///
+ /// Called to filter a chunk of data. Expected usage is as follows:
+ ///
+ /// 1. Read input data from |data_in| and set |data_in_read| to the number of
+ /// bytes that were read up to a maximum of |data_in_size|. |data_in| will
+ /// be NULL if |data_in_size| is zero.
+ /// 2. Write filtered output data to |data_out| and set |data_out_written| to
+ /// the number of bytes that were written up to a maximum of
+ /// |data_out_size|. If no output data was written then all data must be
+ /// read from |data_in| (user must set |data_in_read| = |data_in_size|).
+ /// 3. Return RESPONSE_FILTER_DONE if all output data was written or
+ /// RESPONSE_FILTER_NEED_MORE_DATA if output data is still pending.
+ ///
+ /// This function will be called repeatedly until the input buffer has been
+ /// fully read (user sets |data_in_read| = |data_in_size|) and there is no
+ /// more input data to filter (the resource response is complete). This
+ /// function may then be called an additional time with an NULL input buffer
+ /// if the user filled the output buffer (set |data_out_written| =
+ /// |data_out_size|) and returned RESPONSE_FILTER_NEED_MORE_DATA to indicate
+ /// that output data is still pending.
+ ///
+ /// Calls to this function will stop when one of the following conditions is
+ /// met:
+ ///
+ /// 1. There is no more input data to filter (the resource response is
+ /// complete) and the user sets |data_out_written| = 0 or returns
+ /// RESPONSE_FILTER_DONE to indicate that all data has been written, or;
+ /// 2. The user returns RESPONSE_FILTER_ERROR to indicate an error.
+ ///
+ /// Do not keep a reference to the buffers passed to this function.
+ ///
+ cef_response_filter_status_t(CEF_CALLBACK* filter)(
+ struct _cef_response_filter_t* self,
+ void* data_in,
+ size_t data_in_size,
+ size_t* data_in_read,
+ void* data_out,
+ size_t data_out_size,
+ size_t* data_out_written);
+} cef_response_filter_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_RESPONSE_FILTER_CAPI_H_
diff --git a/include/capi/cef_scheme_capi.h b/include/capi/cef_scheme_capi.h
new file mode 100644
index 00000000..5f879628
--- /dev/null
+++ b/include/capi/cef_scheme_capi.h
@@ -0,0 +1,140 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=6b6a7f754abc9ee5d6f775ba9eee802d3244faf5$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_SCHEME_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_SCHEME_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+#include "include/capi/cef_browser_capi.h"
+#include "include/capi/cef_frame_capi.h"
+#include "include/capi/cef_request_capi.h"
+#include "include/capi/cef_resource_handler_capi.h"
+#include "include/capi/cef_response_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _cef_scheme_handler_factory_t;
+
+///
+/// Structure that manages custom scheme registrations.
+///
+typedef struct _cef_scheme_registrar_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_scoped_t base;
+
+ ///
+ /// Register a custom scheme. This function should not be called for the
+ /// built-in HTTP, HTTPS, FILE, FTP, ABOUT and DATA schemes.
+ ///
+ /// See cef_scheme_options_t for possible values for |options|.
+ ///
+ /// This function may be called on any thread. It should only be called once
+ /// per unique |scheme_name| value. If |scheme_name| is already registered or
+ /// if an error occurs this function will return false (0).
+ ///
+ int(CEF_CALLBACK* add_custom_scheme)(struct _cef_scheme_registrar_t* self,
+ const cef_string_t* scheme_name,
+ int options);
+} cef_scheme_registrar_t;
+
+///
+/// Structure that creates cef_resource_handler_t instances for handling scheme
+/// requests. The functions of this structure will always be called on the IO
+/// thread.
+///
+typedef struct _cef_scheme_handler_factory_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Return a new resource handler instance to handle the request or an NULL
+ /// reference to allow default handling of the request. |browser| and |frame|
+ /// will be the browser window and frame respectively that originated the
+ /// request or NULL if the request did not originate from a browser window
+ /// (for example, if the request came from cef_urlrequest_t). The |request|
+ /// object passed to this function cannot be modified.
+ ///
+ struct _cef_resource_handler_t*(CEF_CALLBACK* create)(
+ struct _cef_scheme_handler_factory_t* self,
+ struct _cef_browser_t* browser,
+ struct _cef_frame_t* frame,
+ const cef_string_t* scheme_name,
+ struct _cef_request_t* request);
+} cef_scheme_handler_factory_t;
+
+///
+/// Register a scheme handler factory with the global request context. An NULL
+/// |domain_name| value for a standard scheme will cause the factory to match
+/// all domain names. The |domain_name| value will be ignored for non-standard
+/// schemes. If |scheme_name| is a built-in scheme and no handler is returned by
+/// |factory| then the built-in scheme handler factory will be called. If
+/// |scheme_name| is a custom scheme then you must also implement the
+/// cef_app_t::on_register_custom_schemes() function in all processes. This
+/// function may be called multiple times to change or remove the factory that
+/// matches the specified |scheme_name| and optional |domain_name|. Returns
+/// false (0) if an error occurs. This function may be called on any thread in
+/// the browser process. Using this function is equivalent to calling cef_reques
+/// t_context_t::cef_request_context_get_global_context()->register_scheme_handl
+/// er_factory().
+///
+CEF_EXPORT int cef_register_scheme_handler_factory(
+ const cef_string_t* scheme_name,
+ const cef_string_t* domain_name,
+ cef_scheme_handler_factory_t* factory);
+
+///
+/// Clear all scheme handler factories registered with the global request
+/// context. Returns false (0) on error. This function may be called on any
+/// thread in the browser process. Using this function is equivalent to calling
+/// cef_request_context_t::cef_request_context_get_global_context()->clear_schem
+/// e_handler_factories().
+///
+CEF_EXPORT int cef_clear_scheme_handler_factories(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_SCHEME_CAPI_H_
diff --git a/include/capi/cef_server_capi.h b/include/capi/cef_server_capi.h
new file mode 100644
index 00000000..d1d2d943
--- /dev/null
+++ b/include/capi/cef_server_capi.h
@@ -0,0 +1,328 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=64e9ebc0e01acca0333ca3419e379d4053892270$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_SERVER_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_SERVER_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+#include "include/capi/cef_callback_capi.h"
+#include "include/capi/cef_request_capi.h"
+#include "include/capi/cef_task_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _cef_server_handler_t;
+
+///
+/// Structure representing a server that supports HTTP and WebSocket requests.
+/// Server capacity is limited and is intended to handle only a small number of
+/// simultaneous connections (e.g. for communicating between applications on
+/// localhost). The functions of this structure are safe to call from any thread
+/// in the brower process unless otherwise indicated.
+///
+typedef struct _cef_server_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Returns the task runner for the dedicated server thread.
+ ///
+ struct _cef_task_runner_t*(CEF_CALLBACK* get_task_runner)(
+ struct _cef_server_t* self);
+
+ ///
+ /// Stop the server and shut down the dedicated server thread. See
+ /// cef_server_handler_t::OnServerCreated documentation for a description of
+ /// server lifespan.
+ ///
+ void(CEF_CALLBACK* shutdown)(struct _cef_server_t* self);
+
+ ///
+ /// Returns true (1) if the server is currently running and accepting incoming
+ /// connections. See cef_server_handler_t::OnServerCreated documentation for a
+ /// description of server lifespan. This function must be called on the
+ /// dedicated server thread.
+ ///
+ int(CEF_CALLBACK* is_running)(struct _cef_server_t* self);
+
+ ///
+ /// Returns the server address including the port number.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_address)(struct _cef_server_t* self);
+
+ ///
+ /// Returns true (1) if the server currently has a connection. This function
+ /// must be called on the dedicated server thread.
+ ///
+ int(CEF_CALLBACK* has_connection)(struct _cef_server_t* self);
+
+ ///
+ /// Returns true (1) if |connection_id| represents a valid connection. This
+ /// function must be called on the dedicated server thread.
+ ///
+ int(CEF_CALLBACK* is_valid_connection)(struct _cef_server_t* self,
+ int connection_id);
+
+ ///
+ /// Send an HTTP 200 "OK" response to the connection identified by
+ /// |connection_id|. |content_type| is the response content type (e.g.
+ /// "text/html"), |data| is the response content, and |data_size| is the size
+ /// of |data| in bytes. The contents of |data| will be copied. The connection
+ /// will be closed automatically after the response is sent.
+ ///
+ void(CEF_CALLBACK* send_http200response)(struct _cef_server_t* self,
+ int connection_id,
+ const cef_string_t* content_type,
+ const void* data,
+ size_t data_size);
+
+ ///
+ /// Send an HTTP 404 "Not Found" response to the connection identified by
+ /// |connection_id|. The connection will be closed automatically after the
+ /// response is sent.
+ ///
+ void(CEF_CALLBACK* send_http404response)(struct _cef_server_t* self,
+ int connection_id);
+
+ ///
+ /// Send an HTTP 500 "Internal Server Error" response to the connection
+ /// identified by |connection_id|. |error_message| is the associated error
+ /// message. The connection will be closed automatically after the response is
+ /// sent.
+ ///
+ void(CEF_CALLBACK* send_http500response)(struct _cef_server_t* self,
+ int connection_id,
+ const cef_string_t* error_message);
+
+ ///
+ /// Send a custom HTTP response to the connection identified by
+ /// |connection_id|. |response_code| is the HTTP response code sent in the
+ /// status line (e.g. 200), |content_type| is the response content type sent
+ /// as the "Content-Type" header (e.g. "text/html"), |content_length| is the
+ /// expected content length, and |extra_headers| is the map of extra response
+ /// headers. If |content_length| is >= 0 then the "Content-Length" header will
+ /// be sent. If |content_length| is 0 then no content is expected and the
+ /// connection will be closed automatically after the response is sent. If
+ /// |content_length| is < 0 then no "Content-Length" header will be sent and
+ /// the client will continue reading until the connection is closed. Use the
+ /// SendRawData function to send the content, if applicable, and call
+ /// CloseConnection after all content has been sent.
+ ///
+ void(CEF_CALLBACK* send_http_response)(struct _cef_server_t* self,
+ int connection_id,
+ int response_code,
+ const cef_string_t* content_type,
+ int64 content_length,
+ cef_string_multimap_t extra_headers);
+
+ ///
+ /// Send raw data directly to the connection identified by |connection_id|.
+ /// |data| is the raw data and |data_size| is the size of |data| in bytes. The
+ /// contents of |data| will be copied. No validation of |data| is performed
+ /// internally so the client should be careful to send the amount indicated by
+ /// the "Content-Length" header, if specified. See SendHttpResponse
+ /// documentation for intended usage.
+ ///
+ void(CEF_CALLBACK* send_raw_data)(struct _cef_server_t* self,
+ int connection_id,
+ const void* data,
+ size_t data_size);
+
+ ///
+ /// Close the connection identified by |connection_id|. See SendHttpResponse
+ /// documentation for intended usage.
+ ///
+ void(CEF_CALLBACK* close_connection)(struct _cef_server_t* self,
+ int connection_id);
+
+ ///
+ /// Send a WebSocket message to the connection identified by |connection_id|.
+ /// |data| is the response content and |data_size| is the size of |data| in
+ /// bytes. The contents of |data| will be copied. See
+ /// cef_server_handler_t::OnWebSocketRequest documentation for intended usage.
+ ///
+ void(CEF_CALLBACK* send_web_socket_message)(struct _cef_server_t* self,
+ int connection_id,
+ const void* data,
+ size_t data_size);
+} cef_server_t;
+
+///
+/// Create a new server that binds to |address| and |port|. |address| must be a
+/// valid IPv4 or IPv6 address (e.g. 127.0.0.1 or ::1) and |port| must be a port
+/// number outside of the reserved range (e.g. between 1025 and 65535 on most
+/// platforms). |backlog| is the maximum number of pending connections. A new
+/// thread will be created for each CreateServer call (the "dedicated server
+/// thread"). It is therefore recommended to use a different
+/// cef_server_handler_t instance for each CreateServer call to avoid thread
+/// safety issues in the cef_server_handler_t implementation. The
+/// cef_server_handler_t::OnServerCreated function will be called on the
+/// dedicated server thread to report success or failure. See
+/// cef_server_handler_t::OnServerCreated documentation for a description of
+/// server lifespan.
+///
+CEF_EXPORT void cef_server_create(const cef_string_t* address,
+ uint16 port,
+ int backlog,
+ struct _cef_server_handler_t* handler);
+
+///
+/// Implement this structure to handle HTTP server requests. A new thread will
+/// be created for each cef_server_t::CreateServer call (the "dedicated server
+/// thread"), and the functions of this structure will be called on that thread.
+/// It is therefore recommended to use a different cef_server_handler_t instance
+/// for each cef_server_t::CreateServer call to avoid thread safety issues in
+/// the cef_server_handler_t implementation.
+///
+typedef struct _cef_server_handler_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Called when |server| is created. If the server was started successfully
+ /// then cef_server_t::IsRunning will return true (1). The server will
+ /// continue running until cef_server_t::Shutdown is called, after which time
+ /// OnServerDestroyed will be called. If the server failed to start then
+ /// OnServerDestroyed will be called immediately after this function returns.
+ ///
+ void(CEF_CALLBACK* on_server_created)(struct _cef_server_handler_t* self,
+ struct _cef_server_t* server);
+
+ ///
+ /// Called when |server| is destroyed. The server thread will be stopped after
+ /// this function returns. The client should release any references to
+ /// |server| when this function is called. See OnServerCreated documentation
+ /// for a description of server lifespan.
+ ///
+ void(CEF_CALLBACK* on_server_destroyed)(struct _cef_server_handler_t* self,
+ struct _cef_server_t* server);
+
+ ///
+ /// Called when a client connects to |server|. |connection_id| uniquely
+ /// identifies the connection. Each call to this function will have a matching
+ /// call to OnClientDisconnected.
+ ///
+ void(CEF_CALLBACK* on_client_connected)(struct _cef_server_handler_t* self,
+ struct _cef_server_t* server,
+ int connection_id);
+
+ ///
+ /// Called when a client disconnects from |server|. |connection_id| uniquely
+ /// identifies the connection. The client should release any data associated
+ /// with |connection_id| when this function is called and |connection_id|
+ /// should no longer be passed to cef_server_t functions. Disconnects can
+ /// originate from either the client or the server. For example, the server
+ /// will disconnect automatically after a cef_server_t::SendHttpXXXResponse
+ /// function is called.
+ ///
+ void(CEF_CALLBACK* on_client_disconnected)(struct _cef_server_handler_t* self,
+ struct _cef_server_t* server,
+ int connection_id);
+
+ ///
+ /// Called when |server| receives an HTTP request. |connection_id| uniquely
+ /// identifies the connection, |client_address| is the requesting IPv4 or IPv6
+ /// client address including port number, and |request| contains the request
+ /// contents (URL, function, headers and optional POST data). Call
+ /// cef_server_t functions either synchronously or asynchronusly to send a
+ /// response.
+ ///
+ void(CEF_CALLBACK* on_http_request)(struct _cef_server_handler_t* self,
+ struct _cef_server_t* server,
+ int connection_id,
+ const cef_string_t* client_address,
+ struct _cef_request_t* request);
+
+ ///
+ /// Called when |server| receives a WebSocket request. |connection_id|
+ /// uniquely identifies the connection, |client_address| is the requesting
+ /// IPv4 or IPv6 client address including port number, and |request| contains
+ /// the request contents (URL, function, headers and optional POST data).
+ /// Execute |callback| either synchronously or asynchronously to accept or
+ /// decline the WebSocket connection. If the request is accepted then
+ /// OnWebSocketConnected will be called after the WebSocket has connected and
+ /// incoming messages will be delivered to the OnWebSocketMessage callback. If
+ /// the request is declined then the client will be disconnected and
+ /// OnClientDisconnected will be called. Call the
+ /// cef_server_t::SendWebSocketMessage function after receiving the
+ /// OnWebSocketConnected callback to respond with WebSocket messages.
+ ///
+ void(CEF_CALLBACK* on_web_socket_request)(struct _cef_server_handler_t* self,
+ struct _cef_server_t* server,
+ int connection_id,
+ const cef_string_t* client_address,
+ struct _cef_request_t* request,
+ struct _cef_callback_t* callback);
+
+ ///
+ /// Called after the client has accepted the WebSocket connection for |server|
+ /// and |connection_id| via the OnWebSocketRequest callback. See
+ /// OnWebSocketRequest documentation for intended usage.
+ ///
+ void(CEF_CALLBACK* on_web_socket_connected)(
+ struct _cef_server_handler_t* self,
+ struct _cef_server_t* server,
+ int connection_id);
+
+ ///
+ /// Called when |server| receives an WebSocket message. |connection_id|
+ /// uniquely identifies the connection, |data| is the message content and
+ /// |data_size| is the size of |data| in bytes. Do not keep a reference to
+ /// |data| outside of this function. See OnWebSocketRequest documentation for
+ /// intended usage.
+ ///
+ void(CEF_CALLBACK* on_web_socket_message)(struct _cef_server_handler_t* self,
+ struct _cef_server_t* server,
+ int connection_id,
+ const void* data,
+ size_t data_size);
+} cef_server_handler_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_SERVER_CAPI_H_
diff --git a/include/capi/cef_shared_memory_region_capi.h b/include/capi/cef_shared_memory_region_capi.h
new file mode 100644
index 00000000..07be55e6
--- /dev/null
+++ b/include/capi/cef_shared_memory_region_capi.h
@@ -0,0 +1,79 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=08f64795d78bdad29a45222a7263e795ce77a52d$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_SHARED_MEMORY_REGION_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_SHARED_MEMORY_REGION_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Structure that wraps platform-dependent share memory region mapping.
+///
+typedef struct _cef_shared_memory_region_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Returns true (1) if the mapping is valid.
+ ///
+ int(CEF_CALLBACK* is_valid)(struct _cef_shared_memory_region_t* self);
+
+ ///
+ /// Returns the size of the mapping in bytes. Returns 0 for invalid instances.
+ ///
+ size_t(CEF_CALLBACK* size)(struct _cef_shared_memory_region_t* self);
+
+ ///
+ /// Returns the pointer to the memory. Returns nullptr for invalid instances.
+ /// The returned pointer is only valid for the life span of this object.
+ ///
+ const void*(CEF_CALLBACK* memory)(struct _cef_shared_memory_region_t* self);
+} cef_shared_memory_region_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_SHARED_MEMORY_REGION_CAPI_H_
diff --git a/include/capi/cef_shared_process_message_builder_capi.h b/include/capi/cef_shared_process_message_builder_capi.h
new file mode 100644
index 00000000..1b570648
--- /dev/null
+++ b/include/capi/cef_shared_process_message_builder_capi.h
@@ -0,0 +1,101 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=1a2d8806256d04362f181350db2835850cb3e0ae$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_SHARED_PROCESS_MESSAGE_BUILDER_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_SHARED_PROCESS_MESSAGE_BUILDER_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_process_message_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Structure that builds a cef_process_message_t containing a shared memory
+/// region. This structure is not thread-safe but may be used exclusively on a
+/// different thread from the one which constructed it.
+///
+typedef struct _cef_shared_process_message_builder_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Returns true (1) if the builder is valid.
+ ///
+ int(CEF_CALLBACK* is_valid)(
+ struct _cef_shared_process_message_builder_t* self);
+
+ ///
+ /// Returns the size of the shared memory region in bytes. Returns 0 for
+ /// invalid instances.
+ ///
+ size_t(CEF_CALLBACK* size)(
+ struct _cef_shared_process_message_builder_t* self);
+
+ ///
+ /// Returns the pointer to the writable memory. Returns nullptr for invalid
+ /// instances. The returned pointer is only valid for the life span of this
+ /// object.
+ ///
+ void*(CEF_CALLBACK* memory)(
+ struct _cef_shared_process_message_builder_t* self);
+
+ ///
+ /// Creates a new cef_process_message_t from the data provided to the builder.
+ /// Returns nullptr for invalid instances. Invalidates the builder instance.
+ ///
+ struct _cef_process_message_t*(CEF_CALLBACK* build)(
+ struct _cef_shared_process_message_builder_t* self);
+} cef_shared_process_message_builder_t;
+
+///
+/// Creates a new cef_shared_process_message_builder_t with the specified |name|
+/// and shared memory region of specified |byte_size|.
+///
+CEF_EXPORT cef_shared_process_message_builder_t*
+cef_shared_process_message_builder_create(const cef_string_t* name,
+ size_t byte_size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_SHARED_PROCESS_MESSAGE_BUILDER_CAPI_H_
diff --git a/include/capi/cef_ssl_info_capi.h b/include/capi/cef_ssl_info_capi.h
new file mode 100644
index 00000000..54b2009a
--- /dev/null
+++ b/include/capi/cef_ssl_info_capi.h
@@ -0,0 +1,82 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=99dff3042ea437ecf5771eff9b3cab4c22190534$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_SSL_INFO_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_SSL_INFO_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+#include "include/capi/cef_values_capi.h"
+#include "include/capi/cef_x509_certificate_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Structure representing SSL information.
+///
+typedef struct _cef_sslinfo_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Returns a bitmask containing any and all problems verifying the server
+ /// certificate.
+ ///
+ cef_cert_status_t(CEF_CALLBACK* get_cert_status)(struct _cef_sslinfo_t* self);
+
+ ///
+ /// Returns the X.509 certificate.
+ ///
+ struct _cef_x509certificate_t*(CEF_CALLBACK* get_x509certificate)(
+ struct _cef_sslinfo_t* self);
+} cef_sslinfo_t;
+
+///
+/// Returns true (1) if the certificate status represents an error.
+///
+CEF_EXPORT int cef_is_cert_status_error(cef_cert_status_t status);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_SSL_INFO_CAPI_H_
diff --git a/include/capi/cef_ssl_status_capi.h b/include/capi/cef_ssl_status_capi.h
new file mode 100644
index 00000000..0c6c4b79
--- /dev/null
+++ b/include/capi/cef_ssl_status_capi.h
@@ -0,0 +1,95 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=034a68aa4901cde95e12a7900cfc65753fbde345$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_SSL_STATUS_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_SSL_STATUS_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+#include "include/capi/cef_values_capi.h"
+#include "include/capi/cef_x509_certificate_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Structure representing the SSL information for a navigation entry.
+///
+typedef struct _cef_sslstatus_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Returns true (1) if the status is related to a secure SSL/TLS connection.
+ ///
+ int(CEF_CALLBACK* is_secure_connection)(struct _cef_sslstatus_t* self);
+
+ ///
+ /// Returns a bitmask containing any and all problems verifying the server
+ /// certificate.
+ ///
+ cef_cert_status_t(CEF_CALLBACK* get_cert_status)(
+ struct _cef_sslstatus_t* self);
+
+ ///
+ /// Returns the SSL version used for the SSL connection.
+ ///
+ cef_ssl_version_t(CEF_CALLBACK* get_sslversion)(
+ struct _cef_sslstatus_t* self);
+
+ ///
+ /// Returns a bitmask containing the page security content status.
+ ///
+ cef_ssl_content_status_t(CEF_CALLBACK* get_content_status)(
+ struct _cef_sslstatus_t* self);
+
+ ///
+ /// Returns the X.509 certificate.
+ ///
+ struct _cef_x509certificate_t*(CEF_CALLBACK* get_x509certificate)(
+ struct _cef_sslstatus_t* self);
+} cef_sslstatus_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_SSL_STATUS_CAPI_H_
diff --git a/include/capi/cef_stream_capi.h b/include/capi/cef_stream_capi.h
new file mode 100644
index 00000000..c425b1fe
--- /dev/null
+++ b/include/capi/cef_stream_capi.h
@@ -0,0 +1,263 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=bbb4153d5d7325ac9a410d7f85a8d47eadcfaf6e$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_STREAM_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_STREAM_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Structure the client can implement to provide a custom stream reader. The
+/// functions of this structure may be called on any thread.
+///
+typedef struct _cef_read_handler_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Read raw binary data.
+ ///
+ size_t(CEF_CALLBACK* read)(struct _cef_read_handler_t* self,
+ void* ptr,
+ size_t size,
+ size_t n);
+
+ ///
+ /// Seek to the specified offset position. |whence| may be any one of
+ /// SEEK_CUR, SEEK_END or SEEK_SET. Return zero on success and non-zero on
+ /// failure.
+ ///
+ int(CEF_CALLBACK* seek)(struct _cef_read_handler_t* self,
+ int64 offset,
+ int whence);
+
+ ///
+ /// Return the current offset position.
+ ///
+ int64(CEF_CALLBACK* tell)(struct _cef_read_handler_t* self);
+
+ ///
+ /// Return non-zero if at end of file.
+ ///
+ int(CEF_CALLBACK* eof)(struct _cef_read_handler_t* self);
+
+ ///
+ /// Return true (1) if this handler performs work like accessing the file
+ /// system which may block. Used as a hint for determining the thread to
+ /// access the handler from.
+ ///
+ int(CEF_CALLBACK* may_block)(struct _cef_read_handler_t* self);
+} cef_read_handler_t;
+
+///
+/// Structure used to read data from a stream. The functions of this structure
+/// may be called on any thread.
+///
+typedef struct _cef_stream_reader_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Read raw binary data.
+ ///
+ size_t(CEF_CALLBACK* read)(struct _cef_stream_reader_t* self,
+ void* ptr,
+ size_t size,
+ size_t n);
+
+ ///
+ /// Seek to the specified offset position. |whence| may be any one of
+ /// SEEK_CUR, SEEK_END or SEEK_SET. Returns zero on success and non-zero on
+ /// failure.
+ ///
+ int(CEF_CALLBACK* seek)(struct _cef_stream_reader_t* self,
+ int64 offset,
+ int whence);
+
+ ///
+ /// Return the current offset position.
+ ///
+ int64(CEF_CALLBACK* tell)(struct _cef_stream_reader_t* self);
+
+ ///
+ /// Return non-zero if at end of file.
+ ///
+ int(CEF_CALLBACK* eof)(struct _cef_stream_reader_t* self);
+
+ ///
+ /// Returns true (1) if this reader performs work like accessing the file
+ /// system which may block. Used as a hint for determining the thread to
+ /// access the reader from.
+ ///
+ int(CEF_CALLBACK* may_block)(struct _cef_stream_reader_t* self);
+} cef_stream_reader_t;
+
+///
+/// Create a new cef_stream_reader_t object from a file.
+///
+CEF_EXPORT cef_stream_reader_t* cef_stream_reader_create_for_file(
+ const cef_string_t* fileName);
+
+///
+/// Create a new cef_stream_reader_t object from data.
+///
+CEF_EXPORT cef_stream_reader_t* cef_stream_reader_create_for_data(void* data,
+ size_t size);
+
+///
+/// Create a new cef_stream_reader_t object from a custom handler.
+///
+CEF_EXPORT cef_stream_reader_t* cef_stream_reader_create_for_handler(
+ cef_read_handler_t* handler);
+
+///
+/// Structure the client can implement to provide a custom stream writer. The
+/// functions of this structure may be called on any thread.
+///
+typedef struct _cef_write_handler_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Write raw binary data.
+ ///
+ size_t(CEF_CALLBACK* write)(struct _cef_write_handler_t* self,
+ const void* ptr,
+ size_t size,
+ size_t n);
+
+ ///
+ /// Seek to the specified offset position. |whence| may be any one of
+ /// SEEK_CUR, SEEK_END or SEEK_SET. Return zero on success and non-zero on
+ /// failure.
+ ///
+ int(CEF_CALLBACK* seek)(struct _cef_write_handler_t* self,
+ int64 offset,
+ int whence);
+
+ ///
+ /// Return the current offset position.
+ ///
+ int64(CEF_CALLBACK* tell)(struct _cef_write_handler_t* self);
+
+ ///
+ /// Flush the stream.
+ ///
+ int(CEF_CALLBACK* flush)(struct _cef_write_handler_t* self);
+
+ ///
+ /// Return true (1) if this handler performs work like accessing the file
+ /// system which may block. Used as a hint for determining the thread to
+ /// access the handler from.
+ ///
+ int(CEF_CALLBACK* may_block)(struct _cef_write_handler_t* self);
+} cef_write_handler_t;
+
+///
+/// Structure used to write data to a stream. The functions of this structure
+/// may be called on any thread.
+///
+typedef struct _cef_stream_writer_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Write raw binary data.
+ ///
+ size_t(CEF_CALLBACK* write)(struct _cef_stream_writer_t* self,
+ const void* ptr,
+ size_t size,
+ size_t n);
+
+ ///
+ /// Seek to the specified offset position. |whence| may be any one of
+ /// SEEK_CUR, SEEK_END or SEEK_SET. Returns zero on success and non-zero on
+ /// failure.
+ ///
+ int(CEF_CALLBACK* seek)(struct _cef_stream_writer_t* self,
+ int64 offset,
+ int whence);
+
+ ///
+ /// Return the current offset position.
+ ///
+ int64(CEF_CALLBACK* tell)(struct _cef_stream_writer_t* self);
+
+ ///
+ /// Flush the stream.
+ ///
+ int(CEF_CALLBACK* flush)(struct _cef_stream_writer_t* self);
+
+ ///
+ /// Returns true (1) if this writer performs work like accessing the file
+ /// system which may block. Used as a hint for determining the thread to
+ /// access the writer from.
+ ///
+ int(CEF_CALLBACK* may_block)(struct _cef_stream_writer_t* self);
+} cef_stream_writer_t;
+
+///
+/// Create a new cef_stream_writer_t object for a file.
+///
+CEF_EXPORT cef_stream_writer_t* cef_stream_writer_create_for_file(
+ const cef_string_t* fileName);
+
+///
+/// Create a new cef_stream_writer_t object for a custom handler.
+///
+CEF_EXPORT cef_stream_writer_t* cef_stream_writer_create_for_handler(
+ cef_write_handler_t* handler);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_STREAM_CAPI_H_
diff --git a/include/capi/cef_string_visitor_capi.h b/include/capi/cef_string_visitor_capi.h
new file mode 100644
index 00000000..5ea9b38f
--- /dev/null
+++ b/include/capi/cef_string_visitor_capi.h
@@ -0,0 +1,69 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=6a22e5144c0254acb09656e6e41eedd05f2dd7e7$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_STRING_VISITOR_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_STRING_VISITOR_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Implement this structure to receive string values asynchronously.
+///
+typedef struct _cef_string_visitor_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Method that will be executed.
+ ///
+ void(CEF_CALLBACK* visit)(struct _cef_string_visitor_t* self,
+ const cef_string_t* string);
+} cef_string_visitor_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_STRING_VISITOR_CAPI_H_
diff --git a/include/capi/cef_task_capi.h b/include/capi/cef_task_capi.h
new file mode 100644
index 00000000..3a04e6bc
--- /dev/null
+++ b/include/capi/cef_task_capi.h
@@ -0,0 +1,158 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=273a6abfd4ac030701be00c45811c19e74e128bd$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_TASK_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_TASK_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Implement this structure for asynchronous task execution. If the task is
+/// posted successfully and if the associated message loop is still running then
+/// the execute() function will be called on the target thread. If the task
+/// fails to post then the task object may be destroyed on the source thread
+/// instead of the target thread. For this reason be cautious when performing
+/// work in the task object destructor.
+///
+typedef struct _cef_task_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Method that will be executed on the target thread.
+ ///
+ void(CEF_CALLBACK* execute)(struct _cef_task_t* self);
+} cef_task_t;
+
+///
+/// Structure that asynchronously executes tasks on the associated thread. It is
+/// safe to call the functions of this structure on any thread.
+///
+/// CEF maintains multiple internal threads that are used for handling different
+/// types of tasks in different processes. The cef_thread_id_t definitions in
+/// cef_types.h list the common CEF threads. Task runners are also available for
+/// other CEF threads as appropriate (for example, V8 WebWorker threads).
+///
+typedef struct _cef_task_runner_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Returns true (1) if this object is pointing to the same task runner as
+ /// |that| object.
+ ///
+ int(CEF_CALLBACK* is_same)(struct _cef_task_runner_t* self,
+ struct _cef_task_runner_t* that);
+
+ ///
+ /// Returns true (1) if this task runner belongs to the current thread.
+ ///
+ int(CEF_CALLBACK* belongs_to_current_thread)(struct _cef_task_runner_t* self);
+
+ ///
+ /// Returns true (1) if this task runner is for the specified CEF thread.
+ ///
+ int(CEF_CALLBACK* belongs_to_thread)(struct _cef_task_runner_t* self,
+ cef_thread_id_t threadId);
+
+ ///
+ /// Post a task for execution on the thread associated with this task runner.
+ /// Execution will occur asynchronously.
+ ///
+ int(CEF_CALLBACK* post_task)(struct _cef_task_runner_t* self,
+ struct _cef_task_t* task);
+
+ ///
+ /// Post a task for delayed execution on the thread associated with this task
+ /// runner. Execution will occur asynchronously. Delayed tasks are not
+ /// supported on V8 WebWorker threads and will be executed without the
+ /// specified delay.
+ ///
+ int(CEF_CALLBACK* post_delayed_task)(struct _cef_task_runner_t* self,
+ struct _cef_task_t* task,
+ int64 delay_ms);
+} cef_task_runner_t;
+
+///
+/// Returns the task runner for the current thread. Only CEF threads will have
+/// task runners. An NULL reference will be returned if this function is called
+/// on an invalid thread.
+///
+CEF_EXPORT cef_task_runner_t* cef_task_runner_get_for_current_thread(void);
+
+///
+/// Returns the task runner for the specified CEF thread.
+///
+CEF_EXPORT cef_task_runner_t* cef_task_runner_get_for_thread(
+ cef_thread_id_t threadId);
+
+///
+/// Returns true (1) if called on the specified thread. Equivalent to using
+/// cef_task_runner_t::GetForThread(threadId)->belongs_to_current_thread().
+///
+CEF_EXPORT int cef_currently_on(cef_thread_id_t threadId);
+
+///
+/// Post a task for execution on the specified thread. Equivalent to using
+/// cef_task_runner_t::GetForThread(threadId)->PostTask(task).
+///
+CEF_EXPORT int cef_post_task(cef_thread_id_t threadId, cef_task_t* task);
+
+///
+/// Post a task for delayed execution on the specified thread. Equivalent to
+/// using cef_task_runner_t::GetForThread(threadId)->PostDelayedTask(task,
+/// delay_ms).
+///
+CEF_EXPORT int cef_post_delayed_task(cef_thread_id_t threadId,
+ cef_task_t* task,
+ int64 delay_ms);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_TASK_CAPI_H_
diff --git a/include/capi/cef_thread_capi.h b/include/capi/cef_thread_capi.h
new file mode 100644
index 00000000..adfb79a0
--- /dev/null
+++ b/include/capi/cef_thread_capi.h
@@ -0,0 +1,117 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=b111114b291d3b91c526e6b3da5741959469ec4a$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_THREAD_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_THREAD_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_task_capi.h"
+#include "include/internal/cef_thread_internal.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// A simple thread abstraction that establishes a message loop on a new thread.
+/// The consumer uses cef_task_runner_t to execute code on the thread's message
+/// loop. The thread is terminated when the cef_thread_t object is destroyed or
+/// stop() is called. All pending tasks queued on the thread's message loop will
+/// run to completion before the thread is terminated. cef_thread_create() can
+/// be called on any valid CEF thread in either the browser or render process.
+/// This structure should only be used for tasks that require a dedicated
+/// thread. In most cases you can post tasks to an existing CEF thread instead
+/// of creating a new one; see cef_task.h for details.
+///
+typedef struct _cef_thread_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Returns the cef_task_runner_t that will execute code on this thread's
+ /// message loop. This function is safe to call from any thread.
+ ///
+ struct _cef_task_runner_t*(CEF_CALLBACK* get_task_runner)(
+ struct _cef_thread_t* self);
+
+ ///
+ /// Returns the platform thread ID. It will return the same value after stop()
+ /// is called. This function is safe to call from any thread.
+ ///
+ cef_platform_thread_id_t(CEF_CALLBACK* get_platform_thread_id)(
+ struct _cef_thread_t* self);
+
+ ///
+ /// Stop and join the thread. This function must be called from the same
+ /// thread that called cef_thread_create(). Do not call this function if
+ /// cef_thread_create() was called with a |stoppable| value of false (0).
+ ///
+ void(CEF_CALLBACK* stop)(struct _cef_thread_t* self);
+
+ ///
+ /// Returns true (1) if the thread is currently running. This function must be
+ /// called from the same thread that called cef_thread_create().
+ ///
+ int(CEF_CALLBACK* is_running)(struct _cef_thread_t* self);
+} cef_thread_t;
+
+///
+/// Create and start a new thread. This function does not block waiting for the
+/// thread to run initialization. |display_name| is the name that will be used
+/// to identify the thread. |priority| is the thread execution priority.
+/// |message_loop_type| indicates the set of asynchronous events that the thread
+/// can process. If |stoppable| is true (1) the thread will stopped and joined
+/// on destruction or when stop() is called; otherwise, the thread cannot be
+/// stopped and will be leaked on shutdown. On Windows the |com_init_mode| value
+/// specifies how COM will be initialized for the thread. If |com_init_mode| is
+/// set to COM_INIT_MODE_STA then |message_loop_type| must be set to ML_TYPE_UI.
+///
+CEF_EXPORT cef_thread_t* cef_thread_create(
+ const cef_string_t* display_name,
+ cef_thread_priority_t priority,
+ cef_message_loop_type_t message_loop_type,
+ int stoppable,
+ cef_com_init_mode_t com_init_mode);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_THREAD_CAPI_H_
diff --git a/include/capi/cef_trace_capi.h b/include/capi/cef_trace_capi.h
new file mode 100644
index 00000000..183ccdad
--- /dev/null
+++ b/include/capi/cef_trace_capi.h
@@ -0,0 +1,118 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=8d275bd73854b2b8d5a7a5bc55fa737e020705ee$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_TRACE_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_TRACE_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+#include "include/capi/cef_callback_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Implement this structure to receive notification when tracing has completed.
+/// The functions of this structure will be called on the browser process UI
+/// thread.
+///
+typedef struct _cef_end_tracing_callback_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Called after all processes have sent their trace data. |tracing_file| is
+ /// the path at which tracing data was written. The client is responsible for
+ /// deleting |tracing_file|.
+ ///
+ void(CEF_CALLBACK* on_end_tracing_complete)(
+ struct _cef_end_tracing_callback_t* self,
+ const cef_string_t* tracing_file);
+} cef_end_tracing_callback_t;
+
+///
+/// Start tracing events on all processes. Tracing is initialized asynchronously
+/// and |callback| will be executed on the UI thread after initialization is
+/// complete.
+///
+/// If CefBeginTracing was called previously, or if a CefEndTracingAsync call is
+/// pending, CefBeginTracing will fail and return false (0).
+///
+/// |categories| is a comma-delimited list of category wildcards. A category can
+/// have an optional '-' prefix to make it an excluded category. Having both
+/// included and excluded categories in the same list is not supported.
+///
+/// Examples: - "test_MyTest*" - "test_MyTest*,test_OtherStuff" -
+/// "-excluded_category1,-excluded_category2"
+///
+/// This function must be called on the browser process UI thread.
+///
+CEF_EXPORT int cef_begin_tracing(const cef_string_t* categories,
+ struct _cef_completion_callback_t* callback);
+
+///
+/// Stop tracing events on all processes.
+///
+/// This function will fail and return false (0) if a previous call to
+/// CefEndTracingAsync is already pending or if CefBeginTracing was not called.
+///
+/// |tracing_file| is the path at which tracing data will be written and
+/// |callback| is the callback that will be executed once all processes have
+/// sent their trace data. If |tracing_file| is NULL a new temporary file path
+/// will be used. If |callback| is NULL no trace data will be written.
+///
+/// This function must be called on the browser process UI thread.
+///
+CEF_EXPORT int cef_end_tracing(const cef_string_t* tracing_file,
+ cef_end_tracing_callback_t* callback);
+
+///
+/// Returns the current system trace time or, if none is defined, the current
+/// high-res time. Can be used by clients to synchronize with the time
+/// information in trace events.
+///
+CEF_EXPORT int64 cef_now_from_system_trace_time(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_TRACE_CAPI_H_
diff --git a/include/capi/cef_urlrequest_capi.h b/include/capi/cef_urlrequest_capi.h
new file mode 100644
index 00000000..d54ffb78
--- /dev/null
+++ b/include/capi/cef_urlrequest_capi.h
@@ -0,0 +1,211 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=91c121d4353a80d7fff3ef582c5a56ac86e0a34c$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_URLREQUEST_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_URLREQUEST_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_auth_callback_capi.h"
+#include "include/capi/cef_base_capi.h"
+#include "include/capi/cef_request_capi.h"
+#include "include/capi/cef_request_context_capi.h"
+#include "include/capi/cef_response_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _cef_urlrequest_client_t;
+
+///
+/// Structure used to make a URL request. URL requests are not associated with a
+/// browser instance so no cef_client_t callbacks will be executed. URL requests
+/// can be created on any valid CEF thread in either the browser or render
+/// process. Once created the functions of the URL request object must be
+/// accessed on the same thread that created it.
+///
+typedef struct _cef_urlrequest_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Returns the request object used to create this URL request. The returned
+ /// object is read-only and should not be modified.
+ ///
+ struct _cef_request_t*(CEF_CALLBACK* get_request)(
+ struct _cef_urlrequest_t* self);
+
+ ///
+ /// Returns the client.
+ ///
+ struct _cef_urlrequest_client_t*(CEF_CALLBACK* get_client)(
+ struct _cef_urlrequest_t* self);
+
+ ///
+ /// Returns the request status.
+ ///
+ cef_urlrequest_status_t(CEF_CALLBACK* get_request_status)(
+ struct _cef_urlrequest_t* self);
+
+ ///
+ /// Returns the request error if status is UR_CANCELED or UR_FAILED, or 0
+ /// otherwise.
+ ///
+ cef_errorcode_t(CEF_CALLBACK* get_request_error)(
+ struct _cef_urlrequest_t* self);
+
+ ///
+ /// Returns the response, or NULL if no response information is available.
+ /// Response information will only be available after the upload has
+ /// completed. The returned object is read-only and should not be modified.
+ ///
+ struct _cef_response_t*(CEF_CALLBACK* get_response)(
+ struct _cef_urlrequest_t* self);
+
+ ///
+ /// Returns true (1) if the response body was served from the cache. This
+ /// includes responses for which revalidation was required.
+ ///
+ int(CEF_CALLBACK* response_was_cached)(struct _cef_urlrequest_t* self);
+
+ ///
+ /// Cancel the request.
+ ///
+ void(CEF_CALLBACK* cancel)(struct _cef_urlrequest_t* self);
+} cef_urlrequest_t;
+
+///
+/// Create a new URL request that is not associated with a specific browser or
+/// frame. Use cef_frame_t::CreateURLRequest instead if you want the request to
+/// have this association, in which case it may be handled differently (see
+/// documentation on that function). A request created with this function may
+/// only originate from the browser process, and will behave as follows:
+/// - It may be intercepted by the client via CefResourceRequestHandler or
+/// CefSchemeHandlerFactory.
+/// - POST data may only contain only a single element of type PDE_TYPE_FILE
+/// or PDE_TYPE_BYTES.
+/// - If |request_context| is empty the global request context will be used.
+///
+/// The |request| object will be marked as read-only after calling this
+/// function.
+///
+CEF_EXPORT cef_urlrequest_t* cef_urlrequest_create(
+ struct _cef_request_t* request,
+ struct _cef_urlrequest_client_t* client,
+ struct _cef_request_context_t* request_context);
+
+///
+/// Structure that should be implemented by the cef_urlrequest_t client. The
+/// functions of this structure will be called on the same thread that created
+/// the request unless otherwise documented.
+///
+typedef struct _cef_urlrequest_client_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Notifies the client that the request has completed. Use the
+ /// cef_urlrequest_t::GetRequestStatus function to determine if the request
+ /// was successful or not.
+ ///
+ void(CEF_CALLBACK* on_request_complete)(struct _cef_urlrequest_client_t* self,
+ struct _cef_urlrequest_t* request);
+
+ ///
+ /// Notifies the client of upload progress. |current| denotes the number of
+ /// bytes sent so far and |total| is the total size of uploading data (or -1
+ /// if chunked upload is enabled). This function will only be called if the
+ /// UR_FLAG_REPORT_UPLOAD_PROGRESS flag is set on the request.
+ ///
+ void(CEF_CALLBACK* on_upload_progress)(struct _cef_urlrequest_client_t* self,
+ struct _cef_urlrequest_t* request,
+ int64 current,
+ int64 total);
+
+ ///
+ /// Notifies the client of download progress. |current| denotes the number of
+ /// bytes received up to the call and |total| is the expected total size of
+ /// the response (or -1 if not determined).
+ ///
+ void(CEF_CALLBACK* on_download_progress)(
+ struct _cef_urlrequest_client_t* self,
+ struct _cef_urlrequest_t* request,
+ int64 current,
+ int64 total);
+
+ ///
+ /// Called when some part of the response is read. |data| contains the current
+ /// bytes received since the last call. This function will not be called if
+ /// the UR_FLAG_NO_DOWNLOAD_DATA flag is set on the request.
+ ///
+ void(CEF_CALLBACK* on_download_data)(struct _cef_urlrequest_client_t* self,
+ struct _cef_urlrequest_t* request,
+ const void* data,
+ size_t data_length);
+
+ ///
+ /// Called on the IO thread when the browser needs credentials from the user.
+ /// |isProxy| indicates whether the host is a proxy server. |host| contains
+ /// the hostname and |port| contains the port number. Return true (1) to
+ /// continue the request and call cef_auth_callback_t::cont() when the
+ /// authentication information is available. If the request has an associated
+ /// browser/frame then returning false (0) will result in a call to
+ /// GetAuthCredentials on the cef_request_handler_t associated with that
+ /// browser, if any. Otherwise, returning false (0) will cancel the request
+ /// immediately. This function will only be called for requests initiated from
+ /// the browser process.
+ ///
+ int(CEF_CALLBACK* get_auth_credentials)(
+ struct _cef_urlrequest_client_t* self,
+ int isProxy,
+ const cef_string_t* host,
+ int port,
+ const cef_string_t* realm,
+ const cef_string_t* scheme,
+ struct _cef_auth_callback_t* callback);
+} cef_urlrequest_client_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_URLREQUEST_CAPI_H_
diff --git a/include/capi/cef_v8_capi.h b/include/capi/cef_v8_capi.h
new file mode 100644
index 00000000..7119475e
--- /dev/null
+++ b/include/capi/cef_v8_capi.h
@@ -0,0 +1,1014 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=0d787ac7676ba90d3a1fe68d5e2494b985b1db0e$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_V8_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_V8_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+#include "include/capi/cef_browser_capi.h"
+#include "include/capi/cef_frame_capi.h"
+#include "include/capi/cef_task_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _cef_v8exception_t;
+struct _cef_v8handler_t;
+struct _cef_v8stack_frame_t;
+struct _cef_v8value_t;
+
+///
+/// Structure representing a V8 context handle. V8 handles can only be accessed
+/// from the thread on which they are created. Valid threads for creating a V8
+/// handle include the render process main thread (TID_RENDERER) and WebWorker
+/// threads. A task runner for posting tasks on the associated thread can be
+/// retrieved via the cef_v8context_t::get_task_runner() function.
+///
+typedef struct _cef_v8context_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Returns the task runner associated with this context. V8 handles can only
+ /// be accessed from the thread on which they are created. This function can
+ /// be called on any render process thread.
+ ///
+ struct _cef_task_runner_t*(CEF_CALLBACK* get_task_runner)(
+ struct _cef_v8context_t* self);
+
+ ///
+ /// Returns true (1) if the underlying handle is valid and it can be accessed
+ /// on the current thread. Do not call any other functions if this function
+ /// returns false (0).
+ ///
+ int(CEF_CALLBACK* is_valid)(struct _cef_v8context_t* self);
+
+ ///
+ /// Returns the browser for this context. This function will return an NULL
+ /// reference for WebWorker contexts.
+ ///
+ struct _cef_browser_t*(CEF_CALLBACK* get_browser)(
+ struct _cef_v8context_t* self);
+
+ ///
+ /// Returns the frame for this context. This function will return an NULL
+ /// reference for WebWorker contexts.
+ ///
+ struct _cef_frame_t*(CEF_CALLBACK* get_frame)(struct _cef_v8context_t* self);
+
+ ///
+ /// Returns the global object for this context. The context must be entered
+ /// before calling this function.
+ ///
+ struct _cef_v8value_t*(CEF_CALLBACK* get_global)(
+ struct _cef_v8context_t* self);
+
+ ///
+ /// Enter this context. A context must be explicitly entered before creating a
+ /// V8 Object, Array, Function or Date asynchronously. exit() must be called
+ /// the same number of times as enter() before releasing this context. V8
+ /// objects belong to the context in which they are created. Returns true (1)
+ /// if the scope was entered successfully.
+ ///
+ int(CEF_CALLBACK* enter)(struct _cef_v8context_t* self);
+
+ ///
+ /// Exit this context. Call this function only after calling enter(). Returns
+ /// true (1) if the scope was exited successfully.
+ ///
+ int(CEF_CALLBACK* exit)(struct _cef_v8context_t* self);
+
+ ///
+ /// Returns true (1) if this object is pointing to the same handle as |that|
+ /// object.
+ ///
+ int(CEF_CALLBACK* is_same)(struct _cef_v8context_t* self,
+ struct _cef_v8context_t* that);
+
+ ///
+ /// Execute a string of JavaScript code in this V8 context. The |script_url|
+ /// parameter is the URL where the script in question can be found, if any.
+ /// The |start_line| parameter is the base line number to use for error
+ /// reporting. On success |retval| will be set to the return value, if any,
+ /// and the function will return true (1). On failure |exception| will be set
+ /// to the exception, if any, and the function will return false (0).
+ ///
+ int(CEF_CALLBACK* eval)(struct _cef_v8context_t* self,
+ const cef_string_t* code,
+ const cef_string_t* script_url,
+ int start_line,
+ struct _cef_v8value_t** retval,
+ struct _cef_v8exception_t** exception);
+} cef_v8context_t;
+
+///
+/// Returns the current (top) context object in the V8 context stack.
+///
+CEF_EXPORT cef_v8context_t* cef_v8context_get_current_context(void);
+
+///
+/// Returns the entered (bottom) context object in the V8 context stack.
+///
+CEF_EXPORT cef_v8context_t* cef_v8context_get_entered_context(void);
+
+///
+/// Returns true (1) if V8 is currently inside a context.
+///
+CEF_EXPORT int cef_v8context_in_context(void);
+
+///
+/// Structure that should be implemented to handle V8 function calls. The
+/// functions of this structure will be called on the thread associated with the
+/// V8 function.
+///
+typedef struct _cef_v8handler_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Handle execution of the function identified by |name|. |object| is the
+ /// receiver ('this' object) of the function. |arguments| is the list of
+ /// arguments passed to the function. If execution succeeds set |retval| to
+ /// the function return value. If execution fails set |exception| to the
+ /// exception that will be thrown. Return true (1) if execution was handled.
+ ///
+ int(CEF_CALLBACK* execute)(struct _cef_v8handler_t* self,
+ const cef_string_t* name,
+ struct _cef_v8value_t* object,
+ size_t argumentsCount,
+ struct _cef_v8value_t* const* arguments,
+ struct _cef_v8value_t** retval,
+ cef_string_t* exception);
+} cef_v8handler_t;
+
+///
+/// Structure that should be implemented to handle V8 accessor calls. Accessor
+/// identifiers are registered by calling cef_v8value_t::set_value(). The
+/// functions of this structure will be called on the thread associated with the
+/// V8 accessor.
+///
+typedef struct _cef_v8accessor_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Handle retrieval the accessor value identified by |name|. |object| is the
+ /// receiver ('this' object) of the accessor. If retrieval succeeds set
+ /// |retval| to the return value. If retrieval fails set |exception| to the
+ /// exception that will be thrown. Return true (1) if accessor retrieval was
+ /// handled.
+ ///
+ int(CEF_CALLBACK* get)(struct _cef_v8accessor_t* self,
+ const cef_string_t* name,
+ struct _cef_v8value_t* object,
+ struct _cef_v8value_t** retval,
+ cef_string_t* exception);
+
+ ///
+ /// Handle assignment of the accessor value identified by |name|. |object| is
+ /// the receiver ('this' object) of the accessor. |value| is the new value
+ /// being assigned to the accessor. If assignment fails set |exception| to the
+ /// exception that will be thrown. Return true (1) if accessor assignment was
+ /// handled.
+ ///
+ int(CEF_CALLBACK* set)(struct _cef_v8accessor_t* self,
+ const cef_string_t* name,
+ struct _cef_v8value_t* object,
+ struct _cef_v8value_t* value,
+ cef_string_t* exception);
+} cef_v8accessor_t;
+
+///
+/// Structure that should be implemented to handle V8 interceptor calls. The
+/// functions of this structure will be called on the thread associated with the
+/// V8 interceptor. Interceptor's named property handlers (with first argument
+/// of type CefString) are called when object is indexed by string. Indexed
+/// property handlers (with first argument of type int) are called when object
+/// is indexed by integer.
+///
+typedef struct _cef_v8interceptor_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Handle retrieval of the interceptor value identified by |name|. |object|
+ /// is the receiver ('this' object) of the interceptor. If retrieval succeeds,
+ /// set |retval| to the return value. If the requested value does not exist,
+ /// don't set either |retval| or |exception|. If retrieval fails, set
+ /// |exception| to the exception that will be thrown. If the property has an
+ /// associated accessor, it will be called only if you don't set |retval|.
+ /// Return true (1) if interceptor retrieval was handled, false (0) otherwise.
+ ///
+ int(CEF_CALLBACK* get_byname)(struct _cef_v8interceptor_t* self,
+ const cef_string_t* name,
+ struct _cef_v8value_t* object,
+ struct _cef_v8value_t** retval,
+ cef_string_t* exception);
+
+ ///
+ /// Handle retrieval of the interceptor value identified by |index|. |object|
+ /// is the receiver ('this' object) of the interceptor. If retrieval succeeds,
+ /// set |retval| to the return value. If the requested value does not exist,
+ /// don't set either |retval| or |exception|. If retrieval fails, set
+ /// |exception| to the exception that will be thrown. Return true (1) if
+ /// interceptor retrieval was handled, false (0) otherwise.
+ ///
+ int(CEF_CALLBACK* get_byindex)(struct _cef_v8interceptor_t* self,
+ int index,
+ struct _cef_v8value_t* object,
+ struct _cef_v8value_t** retval,
+ cef_string_t* exception);
+
+ ///
+ /// Handle assignment of the interceptor value identified by |name|. |object|
+ /// is the receiver ('this' object) of the interceptor. |value| is the new
+ /// value being assigned to the interceptor. If assignment fails, set
+ /// |exception| to the exception that will be thrown. This setter will always
+ /// be called, even when the property has an associated accessor. Return true
+ /// (1) if interceptor assignment was handled, false (0) otherwise.
+ ///
+ int(CEF_CALLBACK* set_byname)(struct _cef_v8interceptor_t* self,
+ const cef_string_t* name,
+ struct _cef_v8value_t* object,
+ struct _cef_v8value_t* value,
+ cef_string_t* exception);
+
+ ///
+ /// Handle assignment of the interceptor value identified by |index|. |object|
+ /// is the receiver ('this' object) of the interceptor. |value| is the new
+ /// value being assigned to the interceptor. If assignment fails, set
+ /// |exception| to the exception that will be thrown. Return true (1) if
+ /// interceptor assignment was handled, false (0) otherwise.
+ ///
+ int(CEF_CALLBACK* set_byindex)(struct _cef_v8interceptor_t* self,
+ int index,
+ struct _cef_v8value_t* object,
+ struct _cef_v8value_t* value,
+ cef_string_t* exception);
+} cef_v8interceptor_t;
+
+///
+/// Structure representing a V8 exception. The functions of this structure may
+/// be called on any render process thread.
+///
+typedef struct _cef_v8exception_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Returns the exception message.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_message)(
+ struct _cef_v8exception_t* self);
+
+ ///
+ /// Returns the line of source code that the exception occurred within.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_source_line)(
+ struct _cef_v8exception_t* self);
+
+ ///
+ /// Returns the resource name for the script from where the function causing
+ /// the error originates.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_script_resource_name)(
+ struct _cef_v8exception_t* self);
+
+ ///
+ /// Returns the 1-based number of the line where the error occurred or 0 if
+ /// the line number is unknown.
+ ///
+ int(CEF_CALLBACK* get_line_number)(struct _cef_v8exception_t* self);
+
+ ///
+ /// Returns the index within the script of the first character where the error
+ /// occurred.
+ ///
+ int(CEF_CALLBACK* get_start_position)(struct _cef_v8exception_t* self);
+
+ ///
+ /// Returns the index within the script of the last character where the error
+ /// occurred.
+ ///
+ int(CEF_CALLBACK* get_end_position)(struct _cef_v8exception_t* self);
+
+ ///
+ /// Returns the index within the line of the first character where the error
+ /// occurred.
+ ///
+ int(CEF_CALLBACK* get_start_column)(struct _cef_v8exception_t* self);
+
+ ///
+ /// Returns the index within the line of the last character where the error
+ /// occurred.
+ ///
+ int(CEF_CALLBACK* get_end_column)(struct _cef_v8exception_t* self);
+} cef_v8exception_t;
+
+///
+/// Callback structure that is passed to cef_v8value_t::CreateArrayBuffer.
+///
+typedef struct _cef_v8array_buffer_release_callback_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Called to release |buffer| when the ArrayBuffer JS object is garbage
+ /// collected. |buffer| is the value that was passed to CreateArrayBuffer
+ /// along with this object.
+ ///
+ void(CEF_CALLBACK* release_buffer)(
+ struct _cef_v8array_buffer_release_callback_t* self,
+ void* buffer);
+} cef_v8array_buffer_release_callback_t;
+
+///
+/// Structure representing a V8 value handle. V8 handles can only be accessed
+/// from the thread on which they are created. Valid threads for creating a V8
+/// handle include the render process main thread (TID_RENDERER) and WebWorker
+/// threads. A task runner for posting tasks on the associated thread can be
+/// retrieved via the cef_v8context_t::get_task_runner() function.
+///
+typedef struct _cef_v8value_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Returns true (1) if the underlying handle is valid and it can be accessed
+ /// on the current thread. Do not call any other functions if this function
+ /// returns false (0).
+ ///
+ int(CEF_CALLBACK* is_valid)(struct _cef_v8value_t* self);
+
+ ///
+ /// True if the value type is undefined.
+ ///
+ int(CEF_CALLBACK* is_undefined)(struct _cef_v8value_t* self);
+
+ ///
+ /// True if the value type is null.
+ ///
+ int(CEF_CALLBACK* is_null)(struct _cef_v8value_t* self);
+
+ ///
+ /// True if the value type is bool.
+ ///
+ int(CEF_CALLBACK* is_bool)(struct _cef_v8value_t* self);
+
+ ///
+ /// True if the value type is int.
+ ///
+ int(CEF_CALLBACK* is_int)(struct _cef_v8value_t* self);
+
+ ///
+ /// True if the value type is unsigned int.
+ ///
+ int(CEF_CALLBACK* is_uint)(struct _cef_v8value_t* self);
+
+ ///
+ /// True if the value type is double.
+ ///
+ int(CEF_CALLBACK* is_double)(struct _cef_v8value_t* self);
+
+ ///
+ /// True if the value type is Date.
+ ///
+ int(CEF_CALLBACK* is_date)(struct _cef_v8value_t* self);
+
+ ///
+ /// True if the value type is string.
+ ///
+ int(CEF_CALLBACK* is_string)(struct _cef_v8value_t* self);
+
+ ///
+ /// True if the value type is object.
+ ///
+ int(CEF_CALLBACK* is_object)(struct _cef_v8value_t* self);
+
+ ///
+ /// True if the value type is array.
+ ///
+ int(CEF_CALLBACK* is_array)(struct _cef_v8value_t* self);
+
+ ///
+ /// True if the value type is an ArrayBuffer.
+ ///
+ int(CEF_CALLBACK* is_array_buffer)(struct _cef_v8value_t* self);
+
+ ///
+ /// True if the value type is function.
+ ///
+ int(CEF_CALLBACK* is_function)(struct _cef_v8value_t* self);
+
+ ///
+ /// True if the value type is a Promise.
+ ///
+ int(CEF_CALLBACK* is_promise)(struct _cef_v8value_t* self);
+
+ ///
+ /// Returns true (1) if this object is pointing to the same handle as |that|
+ /// object.
+ ///
+ int(CEF_CALLBACK* is_same)(struct _cef_v8value_t* self,
+ struct _cef_v8value_t* that);
+
+ ///
+ /// Return a bool value.
+ ///
+ int(CEF_CALLBACK* get_bool_value)(struct _cef_v8value_t* self);
+
+ ///
+ /// Return an int value.
+ ///
+ int32(CEF_CALLBACK* get_int_value)(struct _cef_v8value_t* self);
+
+ ///
+ /// Return an unsigned int value.
+ ///
+ uint32(CEF_CALLBACK* get_uint_value)(struct _cef_v8value_t* self);
+
+ ///
+ /// Return a double value.
+ ///
+ double(CEF_CALLBACK* get_double_value)(struct _cef_v8value_t* self);
+
+ ///
+ /// Return a Date value.
+ ///
+ cef_basetime_t(CEF_CALLBACK* get_date_value)(struct _cef_v8value_t* self);
+
+ ///
+ /// Return a string value.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_string_value)(
+ struct _cef_v8value_t* self);
+
+ ///
+ /// Returns true (1) if this is a user created object.
+ ///
+ int(CEF_CALLBACK* is_user_created)(struct _cef_v8value_t* self);
+
+ ///
+ /// Returns true (1) if the last function call resulted in an exception. This
+ /// attribute exists only in the scope of the current CEF value object.
+ ///
+ int(CEF_CALLBACK* has_exception)(struct _cef_v8value_t* self);
+
+ ///
+ /// Returns the exception resulting from the last function call. This
+ /// attribute exists only in the scope of the current CEF value object.
+ ///
+ struct _cef_v8exception_t*(CEF_CALLBACK* get_exception)(
+ struct _cef_v8value_t* self);
+
+ ///
+ /// Clears the last exception and returns true (1) on success.
+ ///
+ int(CEF_CALLBACK* clear_exception)(struct _cef_v8value_t* self);
+
+ ///
+ /// Returns true (1) if this object will re-throw future exceptions. This
+ /// attribute exists only in the scope of the current CEF value object.
+ ///
+ int(CEF_CALLBACK* will_rethrow_exceptions)(struct _cef_v8value_t* self);
+
+ ///
+ /// Set whether this object will re-throw future exceptions. By default
+ /// exceptions are not re-thrown. If a exception is re-thrown the current
+ /// context should not be accessed again until after the exception has been
+ /// caught and not re-thrown. Returns true (1) on success. This attribute
+ /// exists only in the scope of the current CEF value object.
+ ///
+ int(CEF_CALLBACK* set_rethrow_exceptions)(struct _cef_v8value_t* self,
+ int rethrow);
+
+ ///
+ /// Returns true (1) if the object has a value with the specified identifier.
+ ///
+ int(CEF_CALLBACK* has_value_bykey)(struct _cef_v8value_t* self,
+ const cef_string_t* key);
+
+ ///
+ /// Returns true (1) if the object has a value with the specified identifier.
+ ///
+ int(CEF_CALLBACK* has_value_byindex)(struct _cef_v8value_t* self, int index);
+
+ ///
+ /// Deletes the value with the specified identifier and returns true (1) on
+ /// success. Returns false (0) if this function is called incorrectly or an
+ /// exception is thrown. For read-only and don't-delete values this function
+ /// will return true (1) even though deletion failed.
+ ///
+ int(CEF_CALLBACK* delete_value_bykey)(struct _cef_v8value_t* self,
+ const cef_string_t* key);
+
+ ///
+ /// Deletes the value with the specified identifier and returns true (1) on
+ /// success. Returns false (0) if this function is called incorrectly,
+ /// deletion fails or an exception is thrown. For read-only and don't-delete
+ /// values this function will return true (1) even though deletion failed.
+ ///
+ int(CEF_CALLBACK* delete_value_byindex)(struct _cef_v8value_t* self,
+ int index);
+
+ ///
+ /// Returns the value with the specified identifier on success. Returns NULL
+ /// if this function is called incorrectly or an exception is thrown.
+ ///
+ struct _cef_v8value_t*(CEF_CALLBACK* get_value_bykey)(
+ struct _cef_v8value_t* self,
+ const cef_string_t* key);
+
+ ///
+ /// Returns the value with the specified identifier on success. Returns NULL
+ /// if this function is called incorrectly or an exception is thrown.
+ ///
+ struct _cef_v8value_t*(
+ CEF_CALLBACK* get_value_byindex)(struct _cef_v8value_t* self, int index);
+
+ ///
+ /// Associates a value with the specified identifier and returns true (1) on
+ /// success. Returns false (0) if this function is called incorrectly or an
+ /// exception is thrown. For read-only values this function will return true
+ /// (1) even though assignment failed.
+ ///
+ int(CEF_CALLBACK* set_value_bykey)(struct _cef_v8value_t* self,
+ const cef_string_t* key,
+ struct _cef_v8value_t* value,
+ cef_v8_propertyattribute_t attribute);
+
+ ///
+ /// Associates a value with the specified identifier and returns true (1) on
+ /// success. Returns false (0) if this function is called incorrectly or an
+ /// exception is thrown. For read-only values this function will return true
+ /// (1) even though assignment failed.
+ ///
+ int(CEF_CALLBACK* set_value_byindex)(struct _cef_v8value_t* self,
+ int index,
+ struct _cef_v8value_t* value);
+
+ ///
+ /// Registers an identifier and returns true (1) on success. Access to the
+ /// identifier will be forwarded to the cef_v8accessor_t instance passed to
+ /// cef_v8value_t::cef_v8value_create_object(). Returns false (0) if this
+ /// function is called incorrectly or an exception is thrown. For read-only
+ /// values this function will return true (1) even though assignment failed.
+ ///
+ int(CEF_CALLBACK* set_value_byaccessor)(struct _cef_v8value_t* self,
+ const cef_string_t* key,
+ cef_v8_accesscontrol_t settings,
+ cef_v8_propertyattribute_t attribute);
+
+ ///
+ /// Read the keys for the object's values into the specified vector. Integer-
+ /// based keys will also be returned as strings.
+ ///
+ int(CEF_CALLBACK* get_keys)(struct _cef_v8value_t* self,
+ cef_string_list_t keys);
+
+ ///
+ /// Sets the user data for this object and returns true (1) on success.
+ /// Returns false (0) if this function is called incorrectly. This function
+ /// can only be called on user created objects.
+ ///
+ int(CEF_CALLBACK* set_user_data)(struct _cef_v8value_t* self,
+ struct _cef_base_ref_counted_t* user_data);
+
+ ///
+ /// Returns the user data, if any, assigned to this object.
+ ///
+ struct _cef_base_ref_counted_t*(CEF_CALLBACK* get_user_data)(
+ struct _cef_v8value_t* self);
+
+ ///
+ /// Returns the amount of externally allocated memory registered for the
+ /// object.
+ ///
+ int(CEF_CALLBACK* get_externally_allocated_memory)(
+ struct _cef_v8value_t* self);
+
+ ///
+ /// Adjusts the amount of registered external memory for the object. Used to
+ /// give V8 an indication of the amount of externally allocated memory that is
+ /// kept alive by JavaScript objects. V8 uses this information to decide when
+ /// to perform global garbage collection. Each cef_v8value_t tracks the amount
+ /// of external memory associated with it and automatically decreases the
+ /// global total by the appropriate amount on its destruction.
+ /// |change_in_bytes| specifies the number of bytes to adjust by. This
+ /// function returns the number of bytes associated with the object after the
+ /// adjustment. This function can only be called on user created objects.
+ ///
+ int(CEF_CALLBACK* adjust_externally_allocated_memory)(
+ struct _cef_v8value_t* self,
+ int change_in_bytes);
+
+ ///
+ /// Returns the number of elements in the array.
+ ///
+ int(CEF_CALLBACK* get_array_length)(struct _cef_v8value_t* self);
+
+ ///
+ /// Returns the ReleaseCallback object associated with the ArrayBuffer or NULL
+ /// if the ArrayBuffer was not created with CreateArrayBuffer.
+ ///
+ struct _cef_v8array_buffer_release_callback_t*(
+ CEF_CALLBACK* get_array_buffer_release_callback)(
+ struct _cef_v8value_t* self);
+
+ ///
+ /// Prevent the ArrayBuffer from using it's memory block by setting the length
+ /// to zero. This operation cannot be undone. If the ArrayBuffer was created
+ /// with CreateArrayBuffer then
+ /// cef_v8array_buffer_release_callback_t::ReleaseBuffer will be called to
+ /// release the underlying buffer.
+ ///
+ int(CEF_CALLBACK* neuter_array_buffer)(struct _cef_v8value_t* self);
+
+ ///
+ /// Returns the function name.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_function_name)(
+ struct _cef_v8value_t* self);
+
+ ///
+ /// Returns the function handler or NULL if not a CEF-created function.
+ ///
+ struct _cef_v8handler_t*(CEF_CALLBACK* get_function_handler)(
+ struct _cef_v8value_t* self);
+
+ ///
+ /// Execute the function using the current V8 context. This function should
+ /// only be called from within the scope of a cef_v8handler_t or
+ /// cef_v8accessor_t callback, or in combination with calling enter() and
+ /// exit() on a stored cef_v8context_t reference. |object| is the receiver
+ /// ('this' object) of the function. If |object| is NULL the current context's
+ /// global object will be used. |arguments| is the list of arguments that will
+ /// be passed to the function. Returns the function return value on success.
+ /// Returns NULL if this function is called incorrectly or an exception is
+ /// thrown.
+ ///
+ struct _cef_v8value_t*(CEF_CALLBACK* execute_function)(
+ struct _cef_v8value_t* self,
+ struct _cef_v8value_t* object,
+ size_t argumentsCount,
+ struct _cef_v8value_t* const* arguments);
+
+ ///
+ /// Execute the function using the specified V8 context. |object| is the
+ /// receiver ('this' object) of the function. If |object| is NULL the
+ /// specified context's global object will be used. |arguments| is the list of
+ /// arguments that will be passed to the function. Returns the function return
+ /// value on success. Returns NULL if this function is called incorrectly or
+ /// an exception is thrown.
+ ///
+ struct _cef_v8value_t*(CEF_CALLBACK* execute_function_with_context)(
+ struct _cef_v8value_t* self,
+ struct _cef_v8context_t* context,
+ struct _cef_v8value_t* object,
+ size_t argumentsCount,
+ struct _cef_v8value_t* const* arguments);
+
+ ///
+ /// Resolve the Promise using the current V8 context. This function should
+ /// only be called from within the scope of a cef_v8handler_t or
+ /// cef_v8accessor_t callback, or in combination with calling enter() and
+ /// exit() on a stored cef_v8context_t reference. |arg| is the argument passed
+ /// to the resolved promise. Returns true (1) on success. Returns false (0) if
+ /// this function is called incorrectly or an exception is thrown.
+ ///
+ int(CEF_CALLBACK* resolve_promise)(struct _cef_v8value_t* self,
+ struct _cef_v8value_t* arg);
+
+ ///
+ /// Reject the Promise using the current V8 context. This function should only
+ /// be called from within the scope of a cef_v8handler_t or cef_v8accessor_t
+ /// callback, or in combination with calling enter() and exit() on a stored
+ /// cef_v8context_t reference. Returns true (1) on success. Returns false (0)
+ /// if this function is called incorrectly or an exception is thrown.
+ ///
+ int(CEF_CALLBACK* reject_promise)(struct _cef_v8value_t* self,
+ const cef_string_t* errorMsg);
+} cef_v8value_t;
+
+///
+/// Create a new cef_v8value_t object of type undefined.
+///
+CEF_EXPORT cef_v8value_t* cef_v8value_create_undefined(void);
+
+///
+/// Create a new cef_v8value_t object of type null.
+///
+CEF_EXPORT cef_v8value_t* cef_v8value_create_null(void);
+
+///
+/// Create a new cef_v8value_t object of type bool.
+///
+CEF_EXPORT cef_v8value_t* cef_v8value_create_bool(int value);
+
+///
+/// Create a new cef_v8value_t object of type int.
+///
+CEF_EXPORT cef_v8value_t* cef_v8value_create_int(int32 value);
+
+///
+/// Create a new cef_v8value_t object of type unsigned int.
+///
+CEF_EXPORT cef_v8value_t* cef_v8value_create_uint(uint32 value);
+
+///
+/// Create a new cef_v8value_t object of type double.
+///
+CEF_EXPORT cef_v8value_t* cef_v8value_create_double(double value);
+
+///
+/// Create a new cef_v8value_t object of type Date. This function should only be
+/// called from within the scope of a cef_render_process_handler_t,
+/// cef_v8handler_t or cef_v8accessor_t callback, or in combination with calling
+/// enter() and exit() on a stored cef_v8context_t reference.
+///
+CEF_EXPORT cef_v8value_t* cef_v8value_create_date(cef_basetime_t date);
+
+///
+/// Create a new cef_v8value_t object of type string.
+///
+CEF_EXPORT cef_v8value_t* cef_v8value_create_string(const cef_string_t* value);
+
+///
+/// Create a new cef_v8value_t object of type object with optional accessor
+/// and/or interceptor. This function should only be called from within the
+/// scope of a cef_render_process_handler_t, cef_v8handler_t or cef_v8accessor_t
+/// callback, or in combination with calling enter() and exit() on a stored
+/// cef_v8context_t reference.
+///
+CEF_EXPORT cef_v8value_t* cef_v8value_create_object(
+ cef_v8accessor_t* accessor,
+ cef_v8interceptor_t* interceptor);
+
+///
+/// Create a new cef_v8value_t object of type array with the specified |length|.
+/// If |length| is negative the returned array will have length 0. This function
+/// should only be called from within the scope of a
+/// cef_render_process_handler_t, cef_v8handler_t or cef_v8accessor_t callback,
+/// or in combination with calling enter() and exit() on a stored
+/// cef_v8context_t reference.
+///
+CEF_EXPORT cef_v8value_t* cef_v8value_create_array(int length);
+
+///
+/// Create a new cef_v8value_t object of type ArrayBuffer which wraps the
+/// provided |buffer| of size |length| bytes. The ArrayBuffer is externalized,
+/// meaning that it does not own |buffer|. The caller is responsible for freeing
+/// |buffer| when requested via a call to
+/// cef_v8array_buffer_release_callback_t::ReleaseBuffer. This function should
+/// only be called from within the scope of a cef_render_process_handler_t,
+/// cef_v8handler_t or cef_v8accessor_t callback, or in combination with calling
+/// enter() and exit() on a stored cef_v8context_t reference.
+///
+CEF_EXPORT cef_v8value_t* cef_v8value_create_array_buffer(
+ void* buffer,
+ size_t length,
+ cef_v8array_buffer_release_callback_t* release_callback);
+
+///
+/// Create a new cef_v8value_t object of type function. This function should
+/// only be called from within the scope of a cef_render_process_handler_t,
+/// cef_v8handler_t or cef_v8accessor_t callback, or in combination with calling
+/// enter() and exit() on a stored cef_v8context_t reference.
+///
+CEF_EXPORT cef_v8value_t* cef_v8value_create_function(const cef_string_t* name,
+ cef_v8handler_t* handler);
+
+///
+/// Create a new cef_v8value_t object of type Promise. This function should only
+/// be called from within the scope of a cef_render_process_handler_t,
+/// cef_v8handler_t or cef_v8accessor_t callback, or in combination with calling
+/// enter() and exit() on a stored cef_v8context_t reference.
+///
+CEF_EXPORT cef_v8value_t* cef_v8value_create_promise(void);
+
+///
+/// Structure representing a V8 stack trace handle. V8 handles can only be
+/// accessed from the thread on which they are created. Valid threads for
+/// creating a V8 handle include the render process main thread (TID_RENDERER)
+/// and WebWorker threads. A task runner for posting tasks on the associated
+/// thread can be retrieved via the cef_v8context_t::get_task_runner() function.
+///
+typedef struct _cef_v8stack_trace_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Returns true (1) if the underlying handle is valid and it can be accessed
+ /// on the current thread. Do not call any other functions if this function
+ /// returns false (0).
+ ///
+ int(CEF_CALLBACK* is_valid)(struct _cef_v8stack_trace_t* self);
+
+ ///
+ /// Returns the number of stack frames.
+ ///
+ int(CEF_CALLBACK* get_frame_count)(struct _cef_v8stack_trace_t* self);
+
+ ///
+ /// Returns the stack frame at the specified 0-based index.
+ ///
+ struct _cef_v8stack_frame_t*(
+ CEF_CALLBACK* get_frame)(struct _cef_v8stack_trace_t* self, int index);
+} cef_v8stack_trace_t;
+
+///
+/// Returns the stack trace for the currently active context. |frame_limit| is
+/// the maximum number of frames that will be captured.
+///
+CEF_EXPORT cef_v8stack_trace_t* cef_v8stack_trace_get_current(int frame_limit);
+
+///
+/// Structure representing a V8 stack frame handle. V8 handles can only be
+/// accessed from the thread on which they are created. Valid threads for
+/// creating a V8 handle include the render process main thread (TID_RENDERER)
+/// and WebWorker threads. A task runner for posting tasks on the associated
+/// thread can be retrieved via the cef_v8context_t::get_task_runner() function.
+///
+typedef struct _cef_v8stack_frame_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Returns true (1) if the underlying handle is valid and it can be accessed
+ /// on the current thread. Do not call any other functions if this function
+ /// returns false (0).
+ ///
+ int(CEF_CALLBACK* is_valid)(struct _cef_v8stack_frame_t* self);
+
+ ///
+ /// Returns the name of the resource script that contains the function.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_script_name)(
+ struct _cef_v8stack_frame_t* self);
+
+ ///
+ /// Returns the name of the resource script that contains the function or the
+ /// sourceURL value if the script name is undefined and its source ends with a
+ /// "//@ sourceURL=..." string.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_script_name_or_source_url)(
+ struct _cef_v8stack_frame_t* self);
+
+ ///
+ /// Returns the name of the function.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_function_name)(
+ struct _cef_v8stack_frame_t* self);
+
+ ///
+ /// Returns the 1-based line number for the function call or 0 if unknown.
+ ///
+ int(CEF_CALLBACK* get_line_number)(struct _cef_v8stack_frame_t* self);
+
+ ///
+ /// Returns the 1-based column offset on the line for the function call or 0
+ /// if unknown.
+ ///
+ int(CEF_CALLBACK* get_column)(struct _cef_v8stack_frame_t* self);
+
+ ///
+ /// Returns true (1) if the function was compiled using eval().
+ ///
+ int(CEF_CALLBACK* is_eval)(struct _cef_v8stack_frame_t* self);
+
+ ///
+ /// Returns true (1) if the function was called as a constructor via "new".
+ ///
+ int(CEF_CALLBACK* is_constructor)(struct _cef_v8stack_frame_t* self);
+} cef_v8stack_frame_t;
+
+///
+/// Register a new V8 extension with the specified JavaScript extension code and
+/// handler. Functions implemented by the handler are prototyped using the
+/// keyword 'native'. The calling of a native function is restricted to the
+/// scope in which the prototype of the native function is defined. This
+/// function may only be called on the render process main thread.
+///
+/// Example JavaScript extension code: <pre>
+/// // create the 'example' global object if it doesn't already exist.
+/// if (!example)
+/// example = {};
+/// // create the 'example.test' global object if it doesn't already exist.
+/// if (!example.test)
+/// example.test = {};
+/// (function() {
+/// // Define the function 'example.test.myfunction'.
+/// example.test.myfunction = function() {
+/// // Call CefV8Handler::Execute() with the function name 'MyFunction'
+/// // and no arguments.
+/// native function MyFunction();
+/// return MyFunction();
+/// };
+/// // Define the getter function for parameter 'example.test.myparam'.
+/// example.test.__defineGetter__('myparam', function() {
+/// // Call CefV8Handler::Execute() with the function name 'GetMyParam'
+/// // and no arguments.
+/// native function GetMyParam();
+/// return GetMyParam();
+/// });
+/// // Define the setter function for parameter 'example.test.myparam'.
+/// example.test.__defineSetter__('myparam', function(b) {
+/// // Call CefV8Handler::Execute() with the function name 'SetMyParam'
+/// // and a single argument.
+/// native function SetMyParam();
+/// if(b) SetMyParam(b);
+/// });
+///
+/// // Extension definitions can also contain normal JavaScript variables
+/// // and functions.
+/// var myint = 0;
+/// example.test.increment = function() {
+/// myint += 1;
+/// return myint;
+/// };
+/// })();
+/// </pre>
+///
+/// Example usage in the page: <pre>
+/// // Call the function.
+/// example.test.myfunction();
+/// // Set the parameter.
+/// example.test.myparam = value;
+/// // Get the parameter.
+/// value = example.test.myparam;
+/// // Call another function.
+/// example.test.increment();
+/// </pre>
+///
+CEF_EXPORT int cef_register_extension(const cef_string_t* extension_name,
+ const cef_string_t* javascript_code,
+ cef_v8handler_t* handler);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_V8_CAPI_H_
diff --git a/include/capi/cef_values_capi.h b/include/capi/cef_values_capi.h
new file mode 100644
index 00000000..50abd75f
--- /dev/null
+++ b/include/capi/cef_values_capi.h
@@ -0,0 +1,755 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=1b8f7f620685c30b91c8fa656e1a01d182684ae6$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_VALUES_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_VALUES_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _cef_binary_value_t;
+struct _cef_dictionary_value_t;
+struct _cef_list_value_t;
+
+///
+/// Structure that wraps other data value types. Complex types (binary,
+/// dictionary and list) will be referenced but not owned by this object. Can be
+/// used on any process and thread.
+///
+typedef struct _cef_value_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Returns true (1) if the underlying data is valid. This will always be true
+ /// (1) for simple types. For complex types (binary, dictionary and list) the
+ /// underlying data may become invalid if owned by another object (e.g. list
+ /// or dictionary) and that other object is then modified or destroyed. This
+ /// value object can be re-used by calling Set*() even if the underlying data
+ /// is invalid.
+ ///
+ int(CEF_CALLBACK* is_valid)(struct _cef_value_t* self);
+
+ ///
+ /// Returns true (1) if the underlying data is owned by another object.
+ ///
+ int(CEF_CALLBACK* is_owned)(struct _cef_value_t* self);
+
+ ///
+ /// Returns true (1) if the underlying data is read-only. Some APIs may expose
+ /// read-only objects.
+ ///
+ int(CEF_CALLBACK* is_read_only)(struct _cef_value_t* self);
+
+ ///
+ /// Returns true (1) if this object and |that| object have the same underlying
+ /// data. If true (1) modifications to this object will also affect |that|
+ /// object and vice-versa.
+ ///
+ int(CEF_CALLBACK* is_same)(struct _cef_value_t* self,
+ struct _cef_value_t* that);
+
+ ///
+ /// Returns true (1) if this object and |that| object have an equivalent
+ /// underlying value but are not necessarily the same object.
+ ///
+ int(CEF_CALLBACK* is_equal)(struct _cef_value_t* self,
+ struct _cef_value_t* that);
+
+ ///
+ /// Returns a copy of this object. The underlying data will also be copied.
+ ///
+ struct _cef_value_t*(CEF_CALLBACK* copy)(struct _cef_value_t* self);
+
+ ///
+ /// Returns the underlying value type.
+ ///
+ cef_value_type_t(CEF_CALLBACK* get_type)(struct _cef_value_t* self);
+
+ ///
+ /// Returns the underlying value as type bool.
+ ///
+ int(CEF_CALLBACK* get_bool)(struct _cef_value_t* self);
+
+ ///
+ /// Returns the underlying value as type int.
+ ///
+ int(CEF_CALLBACK* get_int)(struct _cef_value_t* self);
+
+ ///
+ /// Returns the underlying value as type double.
+ ///
+ double(CEF_CALLBACK* get_double)(struct _cef_value_t* self);
+
+ ///
+ /// Returns the underlying value as type string.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_string)(struct _cef_value_t* self);
+
+ ///
+ /// Returns the underlying value as type binary. The returned reference may
+ /// become invalid if the value is owned by another object or if ownership is
+ /// transferred to another object in the future. To maintain a reference to
+ /// the value after assigning ownership to a dictionary or list pass this
+ /// object to the set_value() function instead of passing the returned
+ /// reference to set_binary().
+ ///
+ struct _cef_binary_value_t*(CEF_CALLBACK* get_binary)(
+ struct _cef_value_t* self);
+
+ ///
+ /// Returns the underlying value as type dictionary. The returned reference
+ /// may become invalid if the value is owned by another object or if ownership
+ /// is transferred to another object in the future. To maintain a reference to
+ /// the value after assigning ownership to a dictionary or list pass this
+ /// object to the set_value() function instead of passing the returned
+ /// reference to set_dictionary().
+ ///
+ struct _cef_dictionary_value_t*(CEF_CALLBACK* get_dictionary)(
+ struct _cef_value_t* self);
+
+ ///
+ /// Returns the underlying value as type list. The returned reference may
+ /// become invalid if the value is owned by another object or if ownership is
+ /// transferred to another object in the future. To maintain a reference to
+ /// the value after assigning ownership to a dictionary or list pass this
+ /// object to the set_value() function instead of passing the returned
+ /// reference to set_list().
+ ///
+ struct _cef_list_value_t*(CEF_CALLBACK* get_list)(struct _cef_value_t* self);
+
+ ///
+ /// Sets the underlying value as type null. Returns true (1) if the value was
+ /// set successfully.
+ ///
+ int(CEF_CALLBACK* set_null)(struct _cef_value_t* self);
+
+ ///
+ /// Sets the underlying value as type bool. Returns true (1) if the value was
+ /// set successfully.
+ ///
+ int(CEF_CALLBACK* set_bool)(struct _cef_value_t* self, int value);
+
+ ///
+ /// Sets the underlying value as type int. Returns true (1) if the value was
+ /// set successfully.
+ ///
+ int(CEF_CALLBACK* set_int)(struct _cef_value_t* self, int value);
+
+ ///
+ /// Sets the underlying value as type double. Returns true (1) if the value
+ /// was set successfully.
+ ///
+ int(CEF_CALLBACK* set_double)(struct _cef_value_t* self, double value);
+
+ ///
+ /// Sets the underlying value as type string. Returns true (1) if the value
+ /// was set successfully.
+ ///
+ int(CEF_CALLBACK* set_string)(struct _cef_value_t* self,
+ const cef_string_t* value);
+
+ ///
+ /// Sets the underlying value as type binary. Returns true (1) if the value
+ /// was set successfully. This object keeps a reference to |value| and
+ /// ownership of the underlying data remains unchanged.
+ ///
+ int(CEF_CALLBACK* set_binary)(struct _cef_value_t* self,
+ struct _cef_binary_value_t* value);
+
+ ///
+ /// Sets the underlying value as type dict. Returns true (1) if the value was
+ /// set successfully. This object keeps a reference to |value| and ownership
+ /// of the underlying data remains unchanged.
+ ///
+ int(CEF_CALLBACK* set_dictionary)(struct _cef_value_t* self,
+ struct _cef_dictionary_value_t* value);
+
+ ///
+ /// Sets the underlying value as type list. Returns true (1) if the value was
+ /// set successfully. This object keeps a reference to |value| and ownership
+ /// of the underlying data remains unchanged.
+ ///
+ int(CEF_CALLBACK* set_list)(struct _cef_value_t* self,
+ struct _cef_list_value_t* value);
+} cef_value_t;
+
+///
+/// Creates a new object.
+///
+CEF_EXPORT cef_value_t* cef_value_create(void);
+
+///
+/// Structure representing a binary value. Can be used on any process and
+/// thread.
+///
+typedef struct _cef_binary_value_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Returns true (1) if this object is valid. This object may become invalid
+ /// if the underlying data is owned by another object (e.g. list or
+ /// dictionary) and that other object is then modified or destroyed. Do not
+ /// call any other functions if this function returns false (0).
+ ///
+ int(CEF_CALLBACK* is_valid)(struct _cef_binary_value_t* self);
+
+ ///
+ /// Returns true (1) if this object is currently owned by another object.
+ ///
+ int(CEF_CALLBACK* is_owned)(struct _cef_binary_value_t* self);
+
+ ///
+ /// Returns true (1) if this object and |that| object have the same underlying
+ /// data.
+ ///
+ int(CEF_CALLBACK* is_same)(struct _cef_binary_value_t* self,
+ struct _cef_binary_value_t* that);
+
+ ///
+ /// Returns true (1) if this object and |that| object have an equivalent
+ /// underlying value but are not necessarily the same object.
+ ///
+ int(CEF_CALLBACK* is_equal)(struct _cef_binary_value_t* self,
+ struct _cef_binary_value_t* that);
+
+ ///
+ /// Returns a copy of this object. The data in this object will also be
+ /// copied.
+ ///
+ struct _cef_binary_value_t*(CEF_CALLBACK* copy)(
+ struct _cef_binary_value_t* self);
+
+ ///
+ /// Returns the data size.
+ ///
+ size_t(CEF_CALLBACK* get_size)(struct _cef_binary_value_t* self);
+
+ ///
+ /// Read up to |buffer_size| number of bytes into |buffer|. Reading begins at
+ /// the specified byte |data_offset|. Returns the number of bytes read.
+ ///
+ size_t(CEF_CALLBACK* get_data)(struct _cef_binary_value_t* self,
+ void* buffer,
+ size_t buffer_size,
+ size_t data_offset);
+} cef_binary_value_t;
+
+///
+/// Creates a new object that is not owned by any other object. The specified
+/// |data| will be copied.
+///
+CEF_EXPORT cef_binary_value_t* cef_binary_value_create(const void* data,
+ size_t data_size);
+
+///
+/// Structure representing a dictionary value. Can be used on any process and
+/// thread.
+///
+typedef struct _cef_dictionary_value_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Returns true (1) if this object is valid. This object may become invalid
+ /// if the underlying data is owned by another object (e.g. list or
+ /// dictionary) and that other object is then modified or destroyed. Do not
+ /// call any other functions if this function returns false (0).
+ ///
+ int(CEF_CALLBACK* is_valid)(struct _cef_dictionary_value_t* self);
+
+ ///
+ /// Returns true (1) if this object is currently owned by another object.
+ ///
+ int(CEF_CALLBACK* is_owned)(struct _cef_dictionary_value_t* self);
+
+ ///
+ /// Returns true (1) if the values of this object are read-only. Some APIs may
+ /// expose read-only objects.
+ ///
+ int(CEF_CALLBACK* is_read_only)(struct _cef_dictionary_value_t* self);
+
+ ///
+ /// Returns true (1) if this object and |that| object have the same underlying
+ /// data. If true (1) modifications to this object will also affect |that|
+ /// object and vice-versa.
+ ///
+ int(CEF_CALLBACK* is_same)(struct _cef_dictionary_value_t* self,
+ struct _cef_dictionary_value_t* that);
+
+ ///
+ /// Returns true (1) if this object and |that| object have an equivalent
+ /// underlying value but are not necessarily the same object.
+ ///
+ int(CEF_CALLBACK* is_equal)(struct _cef_dictionary_value_t* self,
+ struct _cef_dictionary_value_t* that);
+
+ ///
+ /// Returns a writable copy of this object. If |exclude_NULL_children| is true
+ /// (1) any NULL dictionaries or lists will be excluded from the copy.
+ ///
+ struct _cef_dictionary_value_t*(CEF_CALLBACK* copy)(
+ struct _cef_dictionary_value_t* self,
+ int exclude_empty_children);
+
+ ///
+ /// Returns the number of values.
+ ///
+ size_t(CEF_CALLBACK* get_size)(struct _cef_dictionary_value_t* self);
+
+ ///
+ /// Removes all values. Returns true (1) on success.
+ ///
+ int(CEF_CALLBACK* clear)(struct _cef_dictionary_value_t* self);
+
+ ///
+ /// Returns true (1) if the current dictionary has a value for the given key.
+ ///
+ int(CEF_CALLBACK* has_key)(struct _cef_dictionary_value_t* self,
+ const cef_string_t* key);
+
+ ///
+ /// Reads all keys for this dictionary into the specified vector.
+ ///
+ int(CEF_CALLBACK* get_keys)(struct _cef_dictionary_value_t* self,
+ cef_string_list_t keys);
+
+ ///
+ /// Removes the value at the specified key. Returns true (1) is the value was
+ /// removed successfully.
+ ///
+ int(CEF_CALLBACK* remove)(struct _cef_dictionary_value_t* self,
+ const cef_string_t* key);
+
+ ///
+ /// Returns the value type for the specified key.
+ ///
+ cef_value_type_t(CEF_CALLBACK* get_type)(struct _cef_dictionary_value_t* self,
+ const cef_string_t* key);
+
+ ///
+ /// Returns the value at the specified key. For simple types the returned
+ /// value will copy existing data and modifications to the value will not
+ /// modify this object. For complex types (binary, dictionary and list) the
+ /// returned value will reference existing data and modifications to the value
+ /// will modify this object.
+ ///
+ struct _cef_value_t*(CEF_CALLBACK* get_value)(
+ struct _cef_dictionary_value_t* self,
+ const cef_string_t* key);
+
+ ///
+ /// Returns the value at the specified key as type bool.
+ ///
+ int(CEF_CALLBACK* get_bool)(struct _cef_dictionary_value_t* self,
+ const cef_string_t* key);
+
+ ///
+ /// Returns the value at the specified key as type int.
+ ///
+ int(CEF_CALLBACK* get_int)(struct _cef_dictionary_value_t* self,
+ const cef_string_t* key);
+
+ ///
+ /// Returns the value at the specified key as type double.
+ ///
+ double(CEF_CALLBACK* get_double)(struct _cef_dictionary_value_t* self,
+ const cef_string_t* key);
+
+ ///
+ /// Returns the value at the specified key as type string.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_string)(
+ struct _cef_dictionary_value_t* self,
+ const cef_string_t* key);
+
+ ///
+ /// Returns the value at the specified key as type binary. The returned value
+ /// will reference existing data.
+ ///
+ struct _cef_binary_value_t*(CEF_CALLBACK* get_binary)(
+ struct _cef_dictionary_value_t* self,
+ const cef_string_t* key);
+
+ ///
+ /// Returns the value at the specified key as type dictionary. The returned
+ /// value will reference existing data and modifications to the value will
+ /// modify this object.
+ ///
+ struct _cef_dictionary_value_t*(CEF_CALLBACK* get_dictionary)(
+ struct _cef_dictionary_value_t* self,
+ const cef_string_t* key);
+
+ ///
+ /// Returns the value at the specified key as type list. The returned value
+ /// will reference existing data and modifications to the value will modify
+ /// this object.
+ ///
+ struct _cef_list_value_t*(CEF_CALLBACK* get_list)(
+ struct _cef_dictionary_value_t* self,
+ const cef_string_t* key);
+
+ ///
+ /// Sets the value at the specified key. Returns true (1) if the value was set
+ /// successfully. If |value| represents simple data then the underlying data
+ /// will be copied and modifications to |value| will not modify this object.
+ /// If |value| represents complex data (binary, dictionary or list) then the
+ /// underlying data will be referenced and modifications to |value| will
+ /// modify this object.
+ ///
+ int(CEF_CALLBACK* set_value)(struct _cef_dictionary_value_t* self,
+ const cef_string_t* key,
+ struct _cef_value_t* value);
+
+ ///
+ /// Sets the value at the specified key as type null. Returns true (1) if the
+ /// value was set successfully.
+ ///
+ int(CEF_CALLBACK* set_null)(struct _cef_dictionary_value_t* self,
+ const cef_string_t* key);
+
+ ///
+ /// Sets the value at the specified key as type bool. Returns true (1) if the
+ /// value was set successfully.
+ ///
+ int(CEF_CALLBACK* set_bool)(struct _cef_dictionary_value_t* self,
+ const cef_string_t* key,
+ int value);
+
+ ///
+ /// Sets the value at the specified key as type int. Returns true (1) if the
+ /// value was set successfully.
+ ///
+ int(CEF_CALLBACK* set_int)(struct _cef_dictionary_value_t* self,
+ const cef_string_t* key,
+ int value);
+
+ ///
+ /// Sets the value at the specified key as type double. Returns true (1) if
+ /// the value was set successfully.
+ ///
+ int(CEF_CALLBACK* set_double)(struct _cef_dictionary_value_t* self,
+ const cef_string_t* key,
+ double value);
+
+ ///
+ /// Sets the value at the specified key as type string. Returns true (1) if
+ /// the value was set successfully.
+ ///
+ int(CEF_CALLBACK* set_string)(struct _cef_dictionary_value_t* self,
+ const cef_string_t* key,
+ const cef_string_t* value);
+
+ ///
+ /// Sets the value at the specified key as type binary. Returns true (1) if
+ /// the value was set successfully. If |value| is currently owned by another
+ /// object then the value will be copied and the |value| reference will not
+ /// change. Otherwise, ownership will be transferred to this object and the
+ /// |value| reference will be invalidated.
+ ///
+ int(CEF_CALLBACK* set_binary)(struct _cef_dictionary_value_t* self,
+ const cef_string_t* key,
+ struct _cef_binary_value_t* value);
+
+ ///
+ /// Sets the value at the specified key as type dict. Returns true (1) if the
+ /// value was set successfully. If |value| is currently owned by another
+ /// object then the value will be copied and the |value| reference will not
+ /// change. Otherwise, ownership will be transferred to this object and the
+ /// |value| reference will be invalidated.
+ ///
+ int(CEF_CALLBACK* set_dictionary)(struct _cef_dictionary_value_t* self,
+ const cef_string_t* key,
+ struct _cef_dictionary_value_t* value);
+
+ ///
+ /// Sets the value at the specified key as type list. Returns true (1) if the
+ /// value was set successfully. If |value| is currently owned by another
+ /// object then the value will be copied and the |value| reference will not
+ /// change. Otherwise, ownership will be transferred to this object and the
+ /// |value| reference will be invalidated.
+ ///
+ int(CEF_CALLBACK* set_list)(struct _cef_dictionary_value_t* self,
+ const cef_string_t* key,
+ struct _cef_list_value_t* value);
+} cef_dictionary_value_t;
+
+///
+/// Creates a new object that is not owned by any other object.
+///
+CEF_EXPORT cef_dictionary_value_t* cef_dictionary_value_create(void);
+
+///
+/// Structure representing a list value. Can be used on any process and thread.
+///
+typedef struct _cef_list_value_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Returns true (1) if this object is valid. This object may become invalid
+ /// if the underlying data is owned by another object (e.g. list or
+ /// dictionary) and that other object is then modified or destroyed. Do not
+ /// call any other functions if this function returns false (0).
+ ///
+ int(CEF_CALLBACK* is_valid)(struct _cef_list_value_t* self);
+
+ ///
+ /// Returns true (1) if this object is currently owned by another object.
+ ///
+ int(CEF_CALLBACK* is_owned)(struct _cef_list_value_t* self);
+
+ ///
+ /// Returns true (1) if the values of this object are read-only. Some APIs may
+ /// expose read-only objects.
+ ///
+ int(CEF_CALLBACK* is_read_only)(struct _cef_list_value_t* self);
+
+ ///
+ /// Returns true (1) if this object and |that| object have the same underlying
+ /// data. If true (1) modifications to this object will also affect |that|
+ /// object and vice-versa.
+ ///
+ int(CEF_CALLBACK* is_same)(struct _cef_list_value_t* self,
+ struct _cef_list_value_t* that);
+
+ ///
+ /// Returns true (1) if this object and |that| object have an equivalent
+ /// underlying value but are not necessarily the same object.
+ ///
+ int(CEF_CALLBACK* is_equal)(struct _cef_list_value_t* self,
+ struct _cef_list_value_t* that);
+
+ ///
+ /// Returns a writable copy of this object.
+ ///
+ struct _cef_list_value_t*(CEF_CALLBACK* copy)(struct _cef_list_value_t* self);
+
+ ///
+ /// Sets the number of values. If the number of values is expanded all new
+ /// value slots will default to type null. Returns true (1) on success.
+ ///
+ int(CEF_CALLBACK* set_size)(struct _cef_list_value_t* self, size_t size);
+
+ ///
+ /// Returns the number of values.
+ ///
+ size_t(CEF_CALLBACK* get_size)(struct _cef_list_value_t* self);
+
+ ///
+ /// Removes all values. Returns true (1) on success.
+ ///
+ int(CEF_CALLBACK* clear)(struct _cef_list_value_t* self);
+
+ ///
+ /// Removes the value at the specified index.
+ ///
+ int(CEF_CALLBACK* remove)(struct _cef_list_value_t* self, size_t index);
+
+ ///
+ /// Returns the value type at the specified index.
+ ///
+ cef_value_type_t(CEF_CALLBACK* get_type)(struct _cef_list_value_t* self,
+ size_t index);
+
+ ///
+ /// Returns the value at the specified index. For simple types the returned
+ /// value will copy existing data and modifications to the value will not
+ /// modify this object. For complex types (binary, dictionary and list) the
+ /// returned value will reference existing data and modifications to the value
+ /// will modify this object.
+ ///
+ struct _cef_value_t*(CEF_CALLBACK* get_value)(struct _cef_list_value_t* self,
+ size_t index);
+
+ ///
+ /// Returns the value at the specified index as type bool.
+ ///
+ int(CEF_CALLBACK* get_bool)(struct _cef_list_value_t* self, size_t index);
+
+ ///
+ /// Returns the value at the specified index as type int.
+ ///
+ int(CEF_CALLBACK* get_int)(struct _cef_list_value_t* self, size_t index);
+
+ ///
+ /// Returns the value at the specified index as type double.
+ ///
+ double(CEF_CALLBACK* get_double)(struct _cef_list_value_t* self,
+ size_t index);
+
+ ///
+ /// Returns the value at the specified index as type string.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(
+ CEF_CALLBACK* get_string)(struct _cef_list_value_t* self, size_t index);
+
+ ///
+ /// Returns the value at the specified index as type binary. The returned
+ /// value will reference existing data.
+ ///
+ struct _cef_binary_value_t*(
+ CEF_CALLBACK* get_binary)(struct _cef_list_value_t* self, size_t index);
+
+ ///
+ /// Returns the value at the specified index as type dictionary. The returned
+ /// value will reference existing data and modifications to the value will
+ /// modify this object.
+ ///
+ struct _cef_dictionary_value_t*(CEF_CALLBACK* get_dictionary)(
+ struct _cef_list_value_t* self,
+ size_t index);
+
+ ///
+ /// Returns the value at the specified index as type list. The returned value
+ /// will reference existing data and modifications to the value will modify
+ /// this object.
+ ///
+ struct _cef_list_value_t*(
+ CEF_CALLBACK* get_list)(struct _cef_list_value_t* self, size_t index);
+
+ ///
+ /// Sets the value at the specified index. Returns true (1) if the value was
+ /// set successfully. If |value| represents simple data then the underlying
+ /// data will be copied and modifications to |value| will not modify this
+ /// object. If |value| represents complex data (binary, dictionary or list)
+ /// then the underlying data will be referenced and modifications to |value|
+ /// will modify this object.
+ ///
+ int(CEF_CALLBACK* set_value)(struct _cef_list_value_t* self,
+ size_t index,
+ struct _cef_value_t* value);
+
+ ///
+ /// Sets the value at the specified index as type null. Returns true (1) if
+ /// the value was set successfully.
+ ///
+ int(CEF_CALLBACK* set_null)(struct _cef_list_value_t* self, size_t index);
+
+ ///
+ /// Sets the value at the specified index as type bool. Returns true (1) if
+ /// the value was set successfully.
+ ///
+ int(CEF_CALLBACK* set_bool)(struct _cef_list_value_t* self,
+ size_t index,
+ int value);
+
+ ///
+ /// Sets the value at the specified index as type int. Returns true (1) if the
+ /// value was set successfully.
+ ///
+ int(CEF_CALLBACK* set_int)(struct _cef_list_value_t* self,
+ size_t index,
+ int value);
+
+ ///
+ /// Sets the value at the specified index as type double. Returns true (1) if
+ /// the value was set successfully.
+ ///
+ int(CEF_CALLBACK* set_double)(struct _cef_list_value_t* self,
+ size_t index,
+ double value);
+
+ ///
+ /// Sets the value at the specified index as type string. Returns true (1) if
+ /// the value was set successfully.
+ ///
+ int(CEF_CALLBACK* set_string)(struct _cef_list_value_t* self,
+ size_t index,
+ const cef_string_t* value);
+
+ ///
+ /// Sets the value at the specified index as type binary. Returns true (1) if
+ /// the value was set successfully. If |value| is currently owned by another
+ /// object then the value will be copied and the |value| reference will not
+ /// change. Otherwise, ownership will be transferred to this object and the
+ /// |value| reference will be invalidated.
+ ///
+ int(CEF_CALLBACK* set_binary)(struct _cef_list_value_t* self,
+ size_t index,
+ struct _cef_binary_value_t* value);
+
+ ///
+ /// Sets the value at the specified index as type dict. Returns true (1) if
+ /// the value was set successfully. If |value| is currently owned by another
+ /// object then the value will be copied and the |value| reference will not
+ /// change. Otherwise, ownership will be transferred to this object and the
+ /// |value| reference will be invalidated.
+ ///
+ int(CEF_CALLBACK* set_dictionary)(struct _cef_list_value_t* self,
+ size_t index,
+ struct _cef_dictionary_value_t* value);
+
+ ///
+ /// Sets the value at the specified index as type list. Returns true (1) if
+ /// the value was set successfully. If |value| is currently owned by another
+ /// object then the value will be copied and the |value| reference will not
+ /// change. Otherwise, ownership will be transferred to this object and the
+ /// |value| reference will be invalidated.
+ ///
+ int(CEF_CALLBACK* set_list)(struct _cef_list_value_t* self,
+ size_t index,
+ struct _cef_list_value_t* value);
+} cef_list_value_t;
+
+///
+/// Creates a new object that is not owned by any other object.
+///
+CEF_EXPORT cef_list_value_t* cef_list_value_create(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_VALUES_CAPI_H_
diff --git a/include/capi/cef_waitable_event_capi.h b/include/capi/cef_waitable_event_capi.h
new file mode 100644
index 00000000..1f5431c7
--- /dev/null
+++ b/include/capi/cef_waitable_event_capi.h
@@ -0,0 +1,117 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=683d592a2405ada0a9c46c004f003d640a3298ad$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_WAITABLE_EVENT_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_WAITABLE_EVENT_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// WaitableEvent is a thread synchronization tool that allows one thread to
+/// wait for another thread to finish some work. This is equivalent to using a
+/// Lock+ConditionVariable to protect a simple boolean value. However, using
+/// WaitableEvent in conjunction with a Lock to wait for a more complex state
+/// change (e.g., for an item to be added to a queue) is not recommended. In
+/// that case consider using a ConditionVariable instead of a WaitableEvent. It
+/// is safe to create and/or signal a WaitableEvent from any thread. Blocking on
+/// a WaitableEvent by calling the *wait() functions is not allowed on the
+/// browser process UI or IO threads.
+///
+typedef struct _cef_waitable_event_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Put the event in the un-signaled state.
+ ///
+ void(CEF_CALLBACK* reset)(struct _cef_waitable_event_t* self);
+
+ ///
+ /// Put the event in the signaled state. This causes any thread blocked on
+ /// Wait to be woken up.
+ ///
+ void(CEF_CALLBACK* signal)(struct _cef_waitable_event_t* self);
+
+ ///
+ /// Returns true (1) if the event is in the signaled state, else false (0). If
+ /// the event was created with |automatic_reset| set to true (1) then calling
+ /// this function will also cause a reset.
+ ///
+ int(CEF_CALLBACK* is_signaled)(struct _cef_waitable_event_t* self);
+
+ ///
+ /// Wait indefinitely for the event to be signaled. This function will not
+ /// return until after the call to signal() has completed. This function
+ /// cannot be called on the browser process UI or IO threads.
+ ///
+ void(CEF_CALLBACK* wait)(struct _cef_waitable_event_t* self);
+
+ ///
+ /// Wait up to |max_ms| milliseconds for the event to be signaled. Returns
+ /// true (1) if the event was signaled. A return value of false (0) does not
+ /// necessarily mean that |max_ms| was exceeded. This function will not return
+ /// until after the call to signal() has completed. This function cannot be
+ /// called on the browser process UI or IO threads.
+ ///
+ int(CEF_CALLBACK* timed_wait)(struct _cef_waitable_event_t* self,
+ int64 max_ms);
+} cef_waitable_event_t;
+
+///
+/// Create a new waitable event. If |automatic_reset| is true (1) then the event
+/// state is automatically reset to un-signaled after a single waiting thread
+/// has been released; otherwise, the state remains signaled until reset() is
+/// called manually. If |initially_signaled| is true (1) then the event will
+/// start in the signaled state.
+///
+CEF_EXPORT cef_waitable_event_t* cef_waitable_event_create(
+ int automatic_reset,
+ int initially_signaled);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_WAITABLE_EVENT_CAPI_H_
diff --git a/include/capi/cef_x509_certificate_capi.h b/include/capi/cef_x509_certificate_capi.h
new file mode 100644
index 00000000..bfd4700f
--- /dev/null
+++ b/include/capi/cef_x509_certificate_capi.h
@@ -0,0 +1,213 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=7a541729b4ac664b22cdea625f19f1dba1b6a685$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_X509_CERTIFICATE_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_X509_CERTIFICATE_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+#include "include/capi/cef_values_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Structure representing the issuer or subject field of an X.509 certificate.
+///
+typedef struct _cef_x509cert_principal_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Returns a name that can be used to represent the issuer. It tries in this
+ /// order: Common Name (CN), Organization Name (O) and Organizational Unit
+ /// Name (OU) and returns the first non-NULL one found.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_display_name)(
+ struct _cef_x509cert_principal_t* self);
+
+ ///
+ /// Returns the common name.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_common_name)(
+ struct _cef_x509cert_principal_t* self);
+
+ ///
+ /// Returns the locality name.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_locality_name)(
+ struct _cef_x509cert_principal_t* self);
+
+ ///
+ /// Returns the state or province name.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_state_or_province_name)(
+ struct _cef_x509cert_principal_t* self);
+
+ ///
+ /// Returns the country name.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_country_name)(
+ struct _cef_x509cert_principal_t* self);
+
+ ///
+ /// Retrieve the list of street addresses.
+ ///
+ void(CEF_CALLBACK* get_street_addresses)(
+ struct _cef_x509cert_principal_t* self,
+ cef_string_list_t addresses);
+
+ ///
+ /// Retrieve the list of organization names.
+ ///
+ void(CEF_CALLBACK* get_organization_names)(
+ struct _cef_x509cert_principal_t* self,
+ cef_string_list_t names);
+
+ ///
+ /// Retrieve the list of organization unit names.
+ ///
+ void(CEF_CALLBACK* get_organization_unit_names)(
+ struct _cef_x509cert_principal_t* self,
+ cef_string_list_t names);
+
+ ///
+ /// Retrieve the list of domain components.
+ ///
+ void(CEF_CALLBACK* get_domain_components)(
+ struct _cef_x509cert_principal_t* self,
+ cef_string_list_t components);
+} cef_x509cert_principal_t;
+
+///
+/// Structure representing a X.509 certificate.
+///
+typedef struct _cef_x509certificate_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Returns the subject of the X.509 certificate. For HTTPS server
+ /// certificates this represents the web server. The common name of the
+ /// subject should match the host name of the web server.
+ ///
+ struct _cef_x509cert_principal_t*(CEF_CALLBACK* get_subject)(
+ struct _cef_x509certificate_t* self);
+
+ ///
+ /// Returns the issuer of the X.509 certificate.
+ ///
+ struct _cef_x509cert_principal_t*(CEF_CALLBACK* get_issuer)(
+ struct _cef_x509certificate_t* self);
+
+ ///
+ /// Returns the DER encoded serial number for the X.509 certificate. The value
+ /// possibly includes a leading 00 byte.
+ ///
+ struct _cef_binary_value_t*(CEF_CALLBACK* get_serial_number)(
+ struct _cef_x509certificate_t* self);
+
+ ///
+ /// Returns the date before which the X.509 certificate is invalid.
+ /// CefBaseTime.GetTimeT() will return 0 if no date was specified.
+ ///
+ cef_basetime_t(CEF_CALLBACK* get_valid_start)(
+ struct _cef_x509certificate_t* self);
+
+ ///
+ /// Returns the date after which the X.509 certificate is invalid.
+ /// CefBaseTime.GetTimeT() will return 0 if no date was specified.
+ ///
+ cef_basetime_t(CEF_CALLBACK* get_valid_expiry)(
+ struct _cef_x509certificate_t* self);
+
+ ///
+ /// Returns the DER encoded data for the X.509 certificate.
+ ///
+ struct _cef_binary_value_t*(CEF_CALLBACK* get_derencoded)(
+ struct _cef_x509certificate_t* self);
+
+ ///
+ /// Returns the PEM encoded data for the X.509 certificate.
+ ///
+ struct _cef_binary_value_t*(CEF_CALLBACK* get_pemencoded)(
+ struct _cef_x509certificate_t* self);
+
+ ///
+ /// Returns the number of certificates in the issuer chain. If 0, the
+ /// certificate is self-signed.
+ ///
+ size_t(CEF_CALLBACK* get_issuer_chain_size)(
+ struct _cef_x509certificate_t* self);
+
+ ///
+ /// Returns the DER encoded data for the certificate issuer chain. If we
+ /// failed to encode a certificate in the chain it is still present in the
+ /// array but is an NULL string.
+ ///
+ void(CEF_CALLBACK* get_derencoded_issuer_chain)(
+ struct _cef_x509certificate_t* self,
+ size_t* chainCount,
+ struct _cef_binary_value_t** chain);
+
+ ///
+ /// Returns the PEM encoded data for the certificate issuer chain. If we
+ /// failed to encode a certificate in the chain it is still present in the
+ /// array but is an NULL string.
+ ///
+ void(CEF_CALLBACK* get_pemencoded_issuer_chain)(
+ struct _cef_x509certificate_t* self,
+ size_t* chainCount,
+ struct _cef_binary_value_t** chain);
+} cef_x509certificate_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_X509_CERTIFICATE_CAPI_H_
diff --git a/include/capi/cef_xml_reader_capi.h b/include/capi/cef_xml_reader_capi.h
new file mode 100644
index 00000000..3db9b94e
--- /dev/null
+++ b/include/capi/cef_xml_reader_capi.h
@@ -0,0 +1,274 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=366f872b03f7c25ef56677cc427a317bb529ad9c$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_XML_READER_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_XML_READER_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+#include "include/capi/cef_stream_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Structure that supports the reading of XML data via the libxml streaming
+/// API. The functions of this structure should only be called on the thread
+/// that creates the object.
+///
+typedef struct _cef_xml_reader_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Moves the cursor to the next node in the document. This function must be
+ /// called at least once to set the current cursor position. Returns true (1)
+ /// if the cursor position was set successfully.
+ ///
+ int(CEF_CALLBACK* move_to_next_node)(struct _cef_xml_reader_t* self);
+
+ ///
+ /// Close the document. This should be called directly to ensure that cleanup
+ /// occurs on the correct thread.
+ ///
+ int(CEF_CALLBACK* close)(struct _cef_xml_reader_t* self);
+
+ ///
+ /// Returns true (1) if an error has been reported by the XML parser.
+ ///
+ int(CEF_CALLBACK* has_error)(struct _cef_xml_reader_t* self);
+
+ ///
+ /// Returns the error string.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_error)(
+ struct _cef_xml_reader_t* self);
+
+ ///
+ /// Returns the node type.
+ ///
+ cef_xml_node_type_t(CEF_CALLBACK* get_type)(struct _cef_xml_reader_t* self);
+
+ ///
+ /// Returns the node depth. Depth starts at 0 for the root node.
+ ///
+ int(CEF_CALLBACK* get_depth)(struct _cef_xml_reader_t* self);
+
+ ///
+ /// Returns the local name. See http://www.w3.org/TR/REC-xml-names/#NT-
+ /// LocalPart for additional details.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_local_name)(
+ struct _cef_xml_reader_t* self);
+
+ ///
+ /// Returns the namespace prefix. See http://www.w3.org/TR/REC-xml-names/ for
+ /// additional details.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_prefix)(
+ struct _cef_xml_reader_t* self);
+
+ ///
+ /// Returns the qualified name, equal to (Prefix:)LocalName. See
+ /// http://www.w3.org/TR/REC-xml-names/#ns-qualnames for additional details.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_qualified_name)(
+ struct _cef_xml_reader_t* self);
+
+ ///
+ /// Returns the URI defining the namespace associated with the node. See
+ /// http://www.w3.org/TR/REC-xml-names/ for additional details.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_namespace_uri)(
+ struct _cef_xml_reader_t* self);
+
+ ///
+ /// Returns the base URI of the node. See http://www.w3.org/TR/xmlbase/ for
+ /// additional details.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_base_uri)(
+ struct _cef_xml_reader_t* self);
+
+ ///
+ /// Returns the xml:lang scope within which the node resides. See
+ /// http://www.w3.org/TR/REC-xml/#sec-lang-tag for additional details.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_xml_lang)(
+ struct _cef_xml_reader_t* self);
+
+ ///
+ /// Returns true (1) if the node represents an NULL element. "<a/>" is
+ /// considered NULL but "<a></a>" is not.
+ ///
+ int(CEF_CALLBACK* is_empty_element)(struct _cef_xml_reader_t* self);
+
+ ///
+ /// Returns true (1) if the node has a text value.
+ ///
+ int(CEF_CALLBACK* has_value)(struct _cef_xml_reader_t* self);
+
+ ///
+ /// Returns the text value.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_value)(
+ struct _cef_xml_reader_t* self);
+
+ ///
+ /// Returns true (1) if the node has attributes.
+ ///
+ int(CEF_CALLBACK* has_attributes)(struct _cef_xml_reader_t* self);
+
+ ///
+ /// Returns the number of attributes.
+ ///
+ size_t(CEF_CALLBACK* get_attribute_count)(struct _cef_xml_reader_t* self);
+
+ ///
+ /// Returns the value of the attribute at the specified 0-based index.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_attribute_byindex)(
+ struct _cef_xml_reader_t* self,
+ int index);
+
+ ///
+ /// Returns the value of the attribute with the specified qualified name.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_attribute_byqname)(
+ struct _cef_xml_reader_t* self,
+ const cef_string_t* qualifiedName);
+
+ ///
+ /// Returns the value of the attribute with the specified local name and
+ /// namespace URI.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_attribute_bylname)(
+ struct _cef_xml_reader_t* self,
+ const cef_string_t* localName,
+ const cef_string_t* namespaceURI);
+
+ ///
+ /// Returns an XML representation of the current node's children.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_inner_xml)(
+ struct _cef_xml_reader_t* self);
+
+ ///
+ /// Returns an XML representation of the current node including its children.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_outer_xml)(
+ struct _cef_xml_reader_t* self);
+
+ ///
+ /// Returns the line number for the current node.
+ ///
+ int(CEF_CALLBACK* get_line_number)(struct _cef_xml_reader_t* self);
+
+ ///
+ /// Moves the cursor to the attribute at the specified 0-based index. Returns
+ /// true (1) if the cursor position was set successfully.
+ ///
+ int(CEF_CALLBACK* move_to_attribute_byindex)(struct _cef_xml_reader_t* self,
+ int index);
+
+ ///
+ /// Moves the cursor to the attribute with the specified qualified name.
+ /// Returns true (1) if the cursor position was set successfully.
+ ///
+ int(CEF_CALLBACK* move_to_attribute_byqname)(
+ struct _cef_xml_reader_t* self,
+ const cef_string_t* qualifiedName);
+
+ ///
+ /// Moves the cursor to the attribute with the specified local name and
+ /// namespace URI. Returns true (1) if the cursor position was set
+ /// successfully.
+ ///
+ int(CEF_CALLBACK* move_to_attribute_bylname)(
+ struct _cef_xml_reader_t* self,
+ const cef_string_t* localName,
+ const cef_string_t* namespaceURI);
+
+ ///
+ /// Moves the cursor to the first attribute in the current element. Returns
+ /// true (1) if the cursor position was set successfully.
+ ///
+ int(CEF_CALLBACK* move_to_first_attribute)(struct _cef_xml_reader_t* self);
+
+ ///
+ /// Moves the cursor to the next attribute in the current element. Returns
+ /// true (1) if the cursor position was set successfully.
+ ///
+ int(CEF_CALLBACK* move_to_next_attribute)(struct _cef_xml_reader_t* self);
+
+ ///
+ /// Moves the cursor back to the carrying element. Returns true (1) if the
+ /// cursor position was set successfully.
+ ///
+ int(CEF_CALLBACK* move_to_carrying_element)(struct _cef_xml_reader_t* self);
+} cef_xml_reader_t;
+
+///
+/// Create a new cef_xml_reader_t object. The returned object's functions can
+/// only be called from the thread that created the object.
+///
+CEF_EXPORT cef_xml_reader_t* cef_xml_reader_create(
+ struct _cef_stream_reader_t* stream,
+ cef_xml_encoding_type_t encodingType,
+ const cef_string_t* URI);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_XML_READER_CAPI_H_
diff --git a/include/capi/cef_zip_reader_capi.h b/include/capi/cef_zip_reader_capi.h
new file mode 100644
index 00000000..05c9cd2e
--- /dev/null
+++ b/include/capi/cef_zip_reader_capi.h
@@ -0,0 +1,148 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=83debac545c04a630270665b391f52b15484b5d3$
+//
+
+#ifndef CEF_INCLUDE_CAPI_CEF_ZIP_READER_CAPI_H_
+#define CEF_INCLUDE_CAPI_CEF_ZIP_READER_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+#include "include/capi/cef_stream_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Structure that supports the reading of zip archives via the zlib unzip API.
+/// The functions of this structure should only be called on the thread that
+/// creates the object.
+///
+typedef struct _cef_zip_reader_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Moves the cursor to the first file in the archive. Returns true (1) if the
+ /// cursor position was set successfully.
+ ///
+ int(CEF_CALLBACK* move_to_first_file)(struct _cef_zip_reader_t* self);
+
+ ///
+ /// Moves the cursor to the next file in the archive. Returns true (1) if the
+ /// cursor position was set successfully.
+ ///
+ int(CEF_CALLBACK* move_to_next_file)(struct _cef_zip_reader_t* self);
+
+ ///
+ /// Moves the cursor to the specified file in the archive. If |caseSensitive|
+ /// is true (1) then the search will be case sensitive. Returns true (1) if
+ /// the cursor position was set successfully.
+ ///
+ int(CEF_CALLBACK* move_to_file)(struct _cef_zip_reader_t* self,
+ const cef_string_t* fileName,
+ int caseSensitive);
+
+ ///
+ /// Closes the archive. This should be called directly to ensure that cleanup
+ /// occurs on the correct thread.
+ ///
+ int(CEF_CALLBACK* close)(struct _cef_zip_reader_t* self);
+
+ ///
+ /// Returns the name of the file.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_file_name)(
+ struct _cef_zip_reader_t* self);
+
+ ///
+ /// Returns the uncompressed size of the file.
+ ///
+ int64(CEF_CALLBACK* get_file_size)(struct _cef_zip_reader_t* self);
+
+ ///
+ /// Returns the last modified timestamp for the file.
+ ///
+ cef_basetime_t(CEF_CALLBACK* get_file_last_modified)(
+ struct _cef_zip_reader_t* self);
+
+ ///
+ /// Opens the file for reading of uncompressed data. A read password may
+ /// optionally be specified.
+ ///
+ int(CEF_CALLBACK* open_file)(struct _cef_zip_reader_t* self,
+ const cef_string_t* password);
+
+ ///
+ /// Closes the file.
+ ///
+ int(CEF_CALLBACK* close_file)(struct _cef_zip_reader_t* self);
+
+ ///
+ /// Read uncompressed file contents into the specified buffer. Returns < 0 if
+ /// an error occurred, 0 if at the end of file, or the number of bytes read.
+ ///
+ int(CEF_CALLBACK* read_file)(struct _cef_zip_reader_t* self,
+ void* buffer,
+ size_t bufferSize);
+
+ ///
+ /// Returns the current offset in the uncompressed file contents.
+ ///
+ int64(CEF_CALLBACK* tell)(struct _cef_zip_reader_t* self);
+
+ ///
+ /// Returns true (1) if at end of the file contents.
+ ///
+ int(CEF_CALLBACK* eof)(struct _cef_zip_reader_t* self);
+} cef_zip_reader_t;
+
+///
+/// Create a new cef_zip_reader_t object. The returned object's functions can
+/// only be called from the thread that created the object.
+///
+CEF_EXPORT cef_zip_reader_t* cef_zip_reader_create(
+ struct _cef_stream_reader_t* stream);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_CEF_ZIP_READER_CAPI_H_
diff --git a/include/capi/test/cef_test_helpers_capi.h b/include/capi/test/cef_test_helpers_capi.h
new file mode 100644
index 00000000..c24bcf5a
--- /dev/null
+++ b/include/capi/test/cef_test_helpers_capi.h
@@ -0,0 +1,74 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=4d10dad2278e6d61367b3deaf501a0e7b4fd60e9$
+//
+
+#ifndef CEF_INCLUDE_CAPI_TEST_CEF_TEST_HELPERS_CAPI_H_
+#define CEF_INCLUDE_CAPI_TEST_CEF_TEST_HELPERS_CAPI_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED) && !defined(WRAPPING_CEF_SHARED) && \
+ !defined(UNIT_TEST)
+#error This file can be included for unit tests only
+#endif
+
+#include "include/capi/cef_base_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Execute JavaScript with a user gesture to trigger functionality like
+/// onbeforeunload handlers that will otherwise be blocked.
+///
+CEF_EXPORT void cef_execute_java_script_with_user_gesture_for_tests(
+ struct _cef_frame_t* frame,
+ const cef_string_t* javascript);
+
+///
+/// Set the DIR_SRC_TEST_DATA_ROOT directory used to load test data. Must be
+/// configured when running from a CEF binary distribution. Defaults to the
+/// "chromium/src" directory when running from a local CEF/Chromium build. |dir|
+/// must be an absolute path.
+///
+CEF_EXPORT void cef_set_data_directory_for_tests(const cef_string_t* dir);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_TEST_CEF_TEST_HELPERS_CAPI_H_
diff --git a/include/capi/test/cef_test_server_capi.h b/include/capi/test/cef_test_server_capi.h
new file mode 100644
index 00000000..ba30e684
--- /dev/null
+++ b/include/capi/test/cef_test_server_capi.h
@@ -0,0 +1,197 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=df532eb91caf9de44b077abdf00620dd2508402b$
+//
+
+#ifndef CEF_INCLUDE_CAPI_TEST_CEF_TEST_SERVER_CAPI_H_
+#define CEF_INCLUDE_CAPI_TEST_CEF_TEST_SERVER_CAPI_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED) && !defined(WRAPPING_CEF_SHARED) && \
+ !defined(UNIT_TEST)
+#error This file can be included for unit tests only
+#endif
+
+#include "include/capi/cef_base_capi.h"
+#include "include/capi/cef_request_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _cef_test_server_connection_t;
+struct _cef_test_server_handler_t;
+
+///
+/// Structure representing an embedded test server that supports HTTP/HTTPS
+/// requests. This is a basic server providing only an essential subset of the
+/// HTTP/1.1 protocol. Especially, it assumes that the request syntax is
+/// correct. It *does not* support a Chunked Transfer Encoding. Server capacity
+/// is limited and is intended to handle only a small number of simultaneous
+/// connections (e.g. for communicating between applications on localhost). The
+/// functions of this structure are safe to call from any thread in the brower
+/// process unless otherwise indicated.
+///
+typedef struct _cef_test_server_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Stop the server and shut down the dedicated server thread. This function
+ /// must be called on the same thread as CreateAndStart. It will block until
+ /// the dedicated server thread has shut down.
+ ///
+ void(CEF_CALLBACK* stop)(struct _cef_test_server_t* self);
+
+ ///
+ /// Returns the server origin including the port number (e.g.
+ /// "[http|https]://127.0.0.1:<port>".
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_origin)(
+ struct _cef_test_server_t* self);
+} cef_test_server_t;
+
+///
+/// Create and start a new test server that binds to |port|. If |port| is 0 an
+/// available port number will be selected. If |https_server| is true (1) the
+/// server will be HTTPS, otherwise it will be HTTP. When |https_server| is true
+/// (1) the |https_cert_type| value is used to configure the certificate type.
+/// Returns the newly created server object on success, or nullptr if the server
+/// cannot be started.
+///
+/// A new thread will be created for each CreateAndStart call (the "dedicated
+/// server thread"). It is therefore recommended to use a different
+/// cef_test_server_handler_t instance for each CreateAndStart call to avoid
+/// thread safety issues in the cef_test_server_handler_t implementation.
+///
+/// On success, this function will block until the dedicated server thread has
+/// started. The server will continue running until Stop is called.
+///
+CEF_EXPORT cef_test_server_t* cef_test_server_create_and_start(
+ uint16 port,
+ int https_server,
+ cef_test_cert_type_t https_cert_type,
+ struct _cef_test_server_handler_t* handler);
+
+///
+/// Implement this structure to handle test server requests. A new thread will
+/// be created for each cef_test_server_t::CreateAndStart call (the "dedicated
+/// server thread"), and the functions of this structure will be called on that
+/// thread. See related documentation on cef_test_server_t::CreateAndStart.
+///
+typedef struct _cef_test_server_handler_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Called when |server| receives a request. To handle the request return true
+ /// (1) and use |connection| to send the response either synchronously or
+ /// asynchronously. Otherwise, return false (0) if the request is unhandled.
+ /// When returning false (0) do not call any |connection| functions.
+ ///
+ int(CEF_CALLBACK* on_test_server_request)(
+ struct _cef_test_server_handler_t* self,
+ struct _cef_test_server_t* server,
+ struct _cef_request_t* request,
+ struct _cef_test_server_connection_t* connection);
+} cef_test_server_handler_t;
+
+///
+/// Structure representing a test server connection. The functions of this
+/// structure are safe to call from any thread in the brower process unless
+/// otherwise indicated.
+///
+typedef struct _cef_test_server_connection_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Send an HTTP 200 "OK" response. |content_type| is the response content
+ /// type (e.g. "text/html"). |data| is the response content and |data_size| is
+ /// the size of |data| in bytes. The contents of |data| will be copied. The
+ /// connection will be closed automatically after the response is sent.
+ ///
+ void(CEF_CALLBACK* send_http200response)(
+ struct _cef_test_server_connection_t* self,
+ const cef_string_t* content_type,
+ const void* data,
+ size_t data_size);
+
+ ///
+ /// Send an HTTP 404 "Not Found" response. The connection will be closed
+ /// automatically after the response is sent.
+ ///
+ void(CEF_CALLBACK* send_http404response)(
+ struct _cef_test_server_connection_t* self);
+
+ ///
+ /// Send an HTTP 500 "Internal Server Error" response. |error_message| is the
+ /// associated error message. The connection will be closed automatically
+ /// after the response is sent.
+ ///
+ void(CEF_CALLBACK* send_http500response)(
+ struct _cef_test_server_connection_t* self,
+ const cef_string_t* error_message);
+
+ ///
+ /// Send a custom HTTP response. |response_code| is the HTTP response code
+ /// sent in the status line (e.g. 200). |content_type| is the response content
+ /// type (e.g. "text/html"). |data| is the response content and |data_size| is
+ /// the size of |data| in bytes. The contents of |data| will be copied.
+ /// |extra_headers| is an optional map of additional header key/value pairs.
+ /// The connection will be closed automatically after the response is sent.
+ ///
+ void(CEF_CALLBACK* send_http_response)(
+ struct _cef_test_server_connection_t* self,
+ int response_code,
+ const cef_string_t* content_type,
+ const void* data,
+ size_t data_size,
+ cef_string_multimap_t extra_headers);
+} cef_test_server_connection_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_TEST_CEF_TEST_SERVER_CAPI_H_
diff --git a/include/capi/test/cef_translator_test_capi.h b/include/capi/test/cef_translator_test_capi.h
new file mode 100644
index 00000000..b1e87b05
--- /dev/null
+++ b/include/capi/test/cef_translator_test_capi.h
@@ -0,0 +1,763 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=58809bc0a16010773cf11b5165e65b32ec4b4793$
+//
+
+#ifndef CEF_INCLUDE_CAPI_TEST_CEF_TRANSLATOR_TEST_CAPI_H_
+#define CEF_INCLUDE_CAPI_TEST_CEF_TRANSLATOR_TEST_CAPI_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED) && !defined(WRAPPING_CEF_SHARED) && \
+ !defined(UNIT_TEST)
+#error This file can be included for unit tests only
+#endif
+
+#include "include/capi/cef_base_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _cef_translator_test_ref_ptr_client_child_t;
+struct _cef_translator_test_ref_ptr_client_t;
+struct _cef_translator_test_ref_ptr_library_child_t;
+struct _cef_translator_test_ref_ptr_library_t;
+struct _cef_translator_test_scoped_client_child_t;
+struct _cef_translator_test_scoped_client_t;
+struct _cef_translator_test_scoped_library_child_t;
+struct _cef_translator_test_scoped_library_t;
+
+///
+/// Structure for testing all of the possible data transfer types.
+///
+typedef struct _cef_translator_test_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Return a void value.
+ ///
+ void(CEF_CALLBACK* get_void)(struct _cef_translator_test_t* self);
+
+ ///
+ /// Return a bool value.
+ ///
+ int(CEF_CALLBACK* get_bool)(struct _cef_translator_test_t* self);
+
+ ///
+ /// Return an int value.
+ ///
+ int(CEF_CALLBACK* get_int)(struct _cef_translator_test_t* self);
+
+ ///
+ /// Return a double value.
+ ///
+ double(CEF_CALLBACK* get_double)(struct _cef_translator_test_t* self);
+
+ ///
+ /// Return a long value.
+ ///
+ long(CEF_CALLBACK* get_long)(struct _cef_translator_test_t* self);
+
+ ///
+ /// Return a size_t value.
+ ///
+ size_t(CEF_CALLBACK* get_sizet)(struct _cef_translator_test_t* self);
+
+ ///
+ /// Set a void value.
+ ///
+ int(CEF_CALLBACK* set_void)(struct _cef_translator_test_t* self);
+
+ ///
+ /// Set a bool value.
+ ///
+ int(CEF_CALLBACK* set_bool)(struct _cef_translator_test_t* self, int val);
+
+ ///
+ /// Set an int value.
+ ///
+ int(CEF_CALLBACK* set_int)(struct _cef_translator_test_t* self, int val);
+
+ ///
+ /// Set a double value.
+ ///
+ int(CEF_CALLBACK* set_double)(struct _cef_translator_test_t* self,
+ double val);
+
+ ///
+ /// Set a long value.
+ ///
+ int(CEF_CALLBACK* set_long)(struct _cef_translator_test_t* self, long val);
+
+ ///
+ /// Set a size_t value.
+ ///
+ int(CEF_CALLBACK* set_sizet)(struct _cef_translator_test_t* self, size_t val);
+
+ ///
+ /// Set a int list value.
+ ///
+ int(CEF_CALLBACK* set_int_list)(struct _cef_translator_test_t* self,
+ size_t valCount,
+ int const* val);
+
+ ///
+ /// Return an int list value by out-param.
+ ///
+ int(CEF_CALLBACK* get_int_list_by_ref)(struct _cef_translator_test_t* self,
+ size_t* valCount,
+ int* val);
+
+ ///
+ /// Return the number of points that will be output above.
+ ///
+ size_t(CEF_CALLBACK* get_int_list_size)(struct _cef_translator_test_t* self);
+
+ ///
+ /// Return a string value.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_string)(
+ struct _cef_translator_test_t* self);
+
+ ///
+ /// Set a string value.
+ ///
+ int(CEF_CALLBACK* set_string)(struct _cef_translator_test_t* self,
+ const cef_string_t* val);
+
+ ///
+ /// Return a string value by out-param.
+ ///
+ void(CEF_CALLBACK* get_string_by_ref)(struct _cef_translator_test_t* self,
+ cef_string_t* val);
+
+ ///
+ /// Set a string list value.
+ ///
+ int(CEF_CALLBACK* set_string_list)(struct _cef_translator_test_t* self,
+ cef_string_list_t val);
+
+ ///
+ /// Return a string list value by out-param.
+ ///
+ int(CEF_CALLBACK* get_string_list_by_ref)(struct _cef_translator_test_t* self,
+ cef_string_list_t val);
+
+ ///
+ /// Set a string map value.
+ ///
+ int(CEF_CALLBACK* set_string_map)(struct _cef_translator_test_t* self,
+ cef_string_map_t val);
+
+ ///
+ /// Return a string map value by out-param.
+ ///
+ int(CEF_CALLBACK* get_string_map_by_ref)(struct _cef_translator_test_t* self,
+ cef_string_map_t val);
+
+ ///
+ /// Set a string multimap value.
+ ///
+ int(CEF_CALLBACK* set_string_multimap)(struct _cef_translator_test_t* self,
+ cef_string_multimap_t val);
+
+ ///
+ /// Return a string multimap value by out-param.
+ ///
+ int(CEF_CALLBACK* get_string_multimap_by_ref)(
+ struct _cef_translator_test_t* self,
+ cef_string_multimap_t val);
+
+ ///
+ /// Return a point value.
+ ///
+ cef_point_t(CEF_CALLBACK* get_point)(struct _cef_translator_test_t* self);
+
+ ///
+ /// Set a point value.
+ ///
+ int(CEF_CALLBACK* set_point)(struct _cef_translator_test_t* self,
+ const cef_point_t* val);
+
+ ///
+ /// Return a point value by out-param.
+ ///
+ void(CEF_CALLBACK* get_point_by_ref)(struct _cef_translator_test_t* self,
+ cef_point_t* val);
+
+ ///
+ /// Set a point list vlaue.
+ ///
+ int(CEF_CALLBACK* set_point_list)(struct _cef_translator_test_t* self,
+ size_t valCount,
+ cef_point_t const* val);
+
+ ///
+ /// Return a point list value by out-param.
+ ///
+ int(CEF_CALLBACK* get_point_list_by_ref)(struct _cef_translator_test_t* self,
+ size_t* valCount,
+ cef_point_t* val);
+
+ ///
+ /// Return the number of points that will be output above.
+ ///
+ size_t(CEF_CALLBACK* get_point_list_size)(
+ struct _cef_translator_test_t* self);
+
+ ///
+ /// Return an new library-side object.
+ ///
+ struct _cef_translator_test_ref_ptr_library_t*(
+ CEF_CALLBACK* get_ref_ptr_library)(struct _cef_translator_test_t* self,
+ int val);
+
+ ///
+ /// Set an object. Returns the value from
+ /// cef_translator_test_ref_ptr_library_t::get_value(). This tests input and
+ /// execution of a library-side object type.
+ ///
+ int(CEF_CALLBACK* set_ref_ptr_library)(
+ struct _cef_translator_test_t* self,
+ struct _cef_translator_test_ref_ptr_library_t* val);
+
+ ///
+ /// Set an object. Returns the object passed in. This tests input and output
+ /// of a library-side object type.
+ ///
+ struct _cef_translator_test_ref_ptr_library_t*(
+ CEF_CALLBACK* set_ref_ptr_library_and_return)(
+ struct _cef_translator_test_t* self,
+ struct _cef_translator_test_ref_ptr_library_t* val);
+
+ ///
+ /// Set a child object. Returns the value from
+ /// cef_translator_test_ref_ptr_library_t::get_value(). This tests input of a
+ /// library- side child object type and execution as the parent type.
+ ///
+ int(CEF_CALLBACK* set_child_ref_ptr_library)(
+ struct _cef_translator_test_t* self,
+ struct _cef_translator_test_ref_ptr_library_child_t* val);
+
+ ///
+ /// Set a child object. Returns the object as the parent type. This tests
+ /// input of a library-side child object type and return as the parent type.
+ ///
+ struct _cef_translator_test_ref_ptr_library_t*(
+ CEF_CALLBACK* set_child_ref_ptr_library_and_return_parent)(
+ struct _cef_translator_test_t* self,
+ struct _cef_translator_test_ref_ptr_library_child_t* val);
+
+ ///
+ /// Set an object list vlaue.
+ ///
+ int(CEF_CALLBACK* set_ref_ptr_library_list)(
+ struct _cef_translator_test_t* self,
+ size_t valCount,
+ struct _cef_translator_test_ref_ptr_library_t* const* val,
+ int val1,
+ int val2);
+
+ ///
+ /// Return an object list value by out-param.
+ ///
+ int(CEF_CALLBACK* get_ref_ptr_library_list_by_ref)(
+ struct _cef_translator_test_t* self,
+ size_t* valCount,
+ struct _cef_translator_test_ref_ptr_library_t** val,
+ int val1,
+ int val2);
+
+ ///
+ /// Return the number of object that will be output above.
+ ///
+ size_t(CEF_CALLBACK* get_ref_ptr_library_list_size)(
+ struct _cef_translator_test_t* self);
+
+ ///
+ /// Set an object. Returns the value from
+ /// cef_translator_test_ref_ptr_client_t::get_value(). This tests input and
+ /// execution of a client-side object type.
+ ///
+ int(CEF_CALLBACK* set_ref_ptr_client)(
+ struct _cef_translator_test_t* self,
+ struct _cef_translator_test_ref_ptr_client_t* val);
+
+ ///
+ /// Set an object. Returns the handler passed in. This tests input and output
+ /// of a client-side object type.
+ ///
+ struct _cef_translator_test_ref_ptr_client_t*(
+ CEF_CALLBACK* set_ref_ptr_client_and_return)(
+ struct _cef_translator_test_t* self,
+ struct _cef_translator_test_ref_ptr_client_t* val);
+
+ ///
+ /// Set a child object. Returns the value from
+ /// cef_translator_test_ref_ptr_client_t::get_value(). This tests input of a
+ /// client- side child object type and execution as the parent type.
+ ///
+ int(CEF_CALLBACK* set_child_ref_ptr_client)(
+ struct _cef_translator_test_t* self,
+ struct _cef_translator_test_ref_ptr_client_child_t* val);
+
+ ///
+ /// Set a child object. Returns the object as the parent type. This tests
+ /// input of a client-side child object type and return as the parent type.
+ ///
+ struct _cef_translator_test_ref_ptr_client_t*(
+ CEF_CALLBACK* set_child_ref_ptr_client_and_return_parent)(
+ struct _cef_translator_test_t* self,
+ struct _cef_translator_test_ref_ptr_client_child_t* val);
+
+ ///
+ /// Set an object list vlaue.
+ ///
+ int(CEF_CALLBACK* set_ref_ptr_client_list)(
+ struct _cef_translator_test_t* self,
+ size_t valCount,
+ struct _cef_translator_test_ref_ptr_client_t* const* val,
+ int val1,
+ int val2);
+
+ ///
+ /// Return an object list value by out-param.
+ ///
+ int(CEF_CALLBACK* get_ref_ptr_client_list_by_ref)(
+ struct _cef_translator_test_t* self,
+ size_t* valCount,
+ struct _cef_translator_test_ref_ptr_client_t** val,
+ struct _cef_translator_test_ref_ptr_client_t* val1,
+ struct _cef_translator_test_ref_ptr_client_t* val2);
+
+ ///
+ /// Return the number of object that will be output above.
+ ///
+ size_t(CEF_CALLBACK* get_ref_ptr_client_list_size)(
+ struct _cef_translator_test_t* self);
+
+ ///
+ /// Return an new library-side object.
+ ///
+ struct _cef_translator_test_scoped_library_t*(
+ CEF_CALLBACK* get_own_ptr_library)(struct _cef_translator_test_t* self,
+ int val);
+
+ ///
+ /// Set an object. Returns the value from
+ /// cef_translator_test_scoped_library_t::get_value(). This tests input and
+ /// execution of a library-side object type.
+ ///
+ int(CEF_CALLBACK* set_own_ptr_library)(
+ struct _cef_translator_test_t* self,
+ struct _cef_translator_test_scoped_library_t* val);
+
+ ///
+ /// Set an object. Returns the object passed in. This tests input and output
+ /// of a library-side object type.
+ ///
+ struct _cef_translator_test_scoped_library_t*(
+ CEF_CALLBACK* set_own_ptr_library_and_return)(
+ struct _cef_translator_test_t* self,
+ struct _cef_translator_test_scoped_library_t* val);
+
+ ///
+ /// Set a child object. Returns the value from
+ /// cef_translator_test_scoped_library_t::get_value(). This tests input of a
+ /// library- side child object type and execution as the parent type.
+ ///
+ int(CEF_CALLBACK* set_child_own_ptr_library)(
+ struct _cef_translator_test_t* self,
+ struct _cef_translator_test_scoped_library_child_t* val);
+
+ ///
+ /// Set a child object. Returns the object as the parent type. This tests
+ /// input of a library-side child object type and return as the parent type.
+ ///
+ struct _cef_translator_test_scoped_library_t*(
+ CEF_CALLBACK* set_child_own_ptr_library_and_return_parent)(
+ struct _cef_translator_test_t* self,
+ struct _cef_translator_test_scoped_library_child_t* val);
+
+ ///
+ /// Set an object. Returns the value from
+ /// cef_translator_test_scoped_client_t::get_value(). This tests input and
+ /// execution of a client-side object type.
+ ///
+ int(CEF_CALLBACK* set_own_ptr_client)(
+ struct _cef_translator_test_t* self,
+ struct _cef_translator_test_scoped_client_t* val);
+
+ ///
+ /// Set an object. Returns the handler passed in. This tests input and output
+ /// of a client-side object type.
+ ///
+ struct _cef_translator_test_scoped_client_t*(
+ CEF_CALLBACK* set_own_ptr_client_and_return)(
+ struct _cef_translator_test_t* self,
+ struct _cef_translator_test_scoped_client_t* val);
+
+ ///
+ /// Set a child object. Returns the value from
+ /// cef_translator_test_scoped_client_t::get_value(). This tests input of a
+ /// client- side child object type and execution as the parent type.
+ ///
+ int(CEF_CALLBACK* set_child_own_ptr_client)(
+ struct _cef_translator_test_t* self,
+ struct _cef_translator_test_scoped_client_child_t* val);
+
+ ///
+ /// Set a child object. Returns the object as the parent type. This tests
+ /// input of a client-side child object type and return as the parent type.
+ ///
+ struct _cef_translator_test_scoped_client_t*(
+ CEF_CALLBACK* set_child_own_ptr_client_and_return_parent)(
+ struct _cef_translator_test_t* self,
+ struct _cef_translator_test_scoped_client_child_t* val);
+
+ ///
+ /// Set an object. Returns the value from
+ /// cef_translator_test_scoped_library_t::get_value(). This tests input and
+ /// execution of a library-side object type.
+ ///
+ int(CEF_CALLBACK* set_raw_ptr_library)(
+ struct _cef_translator_test_t* self,
+ struct _cef_translator_test_scoped_library_t* val);
+
+ ///
+ /// Set a child object. Returns the value from
+ /// cef_translator_test_scoped_library_t::get_value(). This tests input of a
+ /// library- side child object type and execution as the parent type.
+ ///
+ int(CEF_CALLBACK* set_child_raw_ptr_library)(
+ struct _cef_translator_test_t* self,
+ struct _cef_translator_test_scoped_library_child_t* val);
+
+ ///
+ /// Set an object list vlaue.
+ ///
+ int(CEF_CALLBACK* set_raw_ptr_library_list)(
+ struct _cef_translator_test_t* self,
+ size_t valCount,
+ struct _cef_translator_test_scoped_library_t* const* val,
+ int val1,
+ int val2);
+
+ ///
+ /// Set an object. Returns the value from
+ /// cef_translator_test_scoped_client_t::get_value(). This tests input and
+ /// execution of a client-side object type.
+ ///
+ int(CEF_CALLBACK* set_raw_ptr_client)(
+ struct _cef_translator_test_t* self,
+ struct _cef_translator_test_scoped_client_t* val);
+
+ ///
+ /// Set a child object. Returns the value from
+ /// cef_translator_test_scoped_client_t::get_value(). This tests input of a
+ /// client- side child object type and execution as the parent type.
+ ///
+ int(CEF_CALLBACK* set_child_raw_ptr_client)(
+ struct _cef_translator_test_t* self,
+ struct _cef_translator_test_scoped_client_child_t* val);
+
+ ///
+ /// Set an object list vlaue.
+ ///
+ int(CEF_CALLBACK* set_raw_ptr_client_list)(
+ struct _cef_translator_test_t* self,
+ size_t valCount,
+ struct _cef_translator_test_scoped_client_t* const* val,
+ int val1,
+ int val2);
+} cef_translator_test_t;
+
+///
+/// Create the test object.
+///
+CEF_EXPORT cef_translator_test_t* cef_translator_test_create(void);
+
+///
+/// Library-side test object for RefPtr.
+///
+typedef struct _cef_translator_test_ref_ptr_library_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Return a value.
+ ///
+ int(CEF_CALLBACK* get_value)(
+ struct _cef_translator_test_ref_ptr_library_t* self);
+
+ ///
+ /// Set a value.
+ ///
+ void(CEF_CALLBACK* set_value)(
+ struct _cef_translator_test_ref_ptr_library_t* self,
+ int value);
+} cef_translator_test_ref_ptr_library_t;
+
+///
+/// Create the test object.
+///
+CEF_EXPORT cef_translator_test_ref_ptr_library_t*
+cef_translator_test_ref_ptr_library_create(int value);
+
+///
+/// Library-side child test object for RefPtr.
+///
+typedef struct _cef_translator_test_ref_ptr_library_child_t {
+ ///
+ /// Base structure.
+ ///
+ cef_translator_test_ref_ptr_library_t base;
+
+ ///
+ /// Return a value.
+ ///
+ int(CEF_CALLBACK* get_other_value)(
+ struct _cef_translator_test_ref_ptr_library_child_t* self);
+
+ ///
+ /// Set a value.
+ ///
+ void(CEF_CALLBACK* set_other_value)(
+ struct _cef_translator_test_ref_ptr_library_child_t* self,
+ int value);
+} cef_translator_test_ref_ptr_library_child_t;
+
+///
+/// Create the test object.
+///
+CEF_EXPORT cef_translator_test_ref_ptr_library_child_t*
+cef_translator_test_ref_ptr_library_child_create(int value, int other_value);
+
+///
+/// Another library-side child test object for RefPtr.
+///
+typedef struct _cef_translator_test_ref_ptr_library_child_child_t {
+ ///
+ /// Base structure.
+ ///
+ cef_translator_test_ref_ptr_library_child_t base;
+
+ ///
+ /// Return a value.
+ ///
+ int(CEF_CALLBACK* get_other_other_value)(
+ struct _cef_translator_test_ref_ptr_library_child_child_t* self);
+
+ ///
+ /// Set a value.
+ ///
+ void(CEF_CALLBACK* set_other_other_value)(
+ struct _cef_translator_test_ref_ptr_library_child_child_t* self,
+ int value);
+} cef_translator_test_ref_ptr_library_child_child_t;
+
+///
+/// Create the test object.
+///
+CEF_EXPORT cef_translator_test_ref_ptr_library_child_child_t*
+cef_translator_test_ref_ptr_library_child_child_create(int value,
+ int other_value,
+ int other_other_value);
+
+///
+/// Client-side test object for RefPtr.
+///
+typedef struct _cef_translator_test_ref_ptr_client_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Return a value.
+ ///
+ int(CEF_CALLBACK* get_value)(
+ struct _cef_translator_test_ref_ptr_client_t* self);
+} cef_translator_test_ref_ptr_client_t;
+
+///
+/// Client-side child test object for RefPtr.
+///
+typedef struct _cef_translator_test_ref_ptr_client_child_t {
+ ///
+ /// Base structure.
+ ///
+ cef_translator_test_ref_ptr_client_t base;
+
+ ///
+ /// Return a value.
+ ///
+ int(CEF_CALLBACK* get_other_value)(
+ struct _cef_translator_test_ref_ptr_client_child_t* self);
+} cef_translator_test_ref_ptr_client_child_t;
+
+///
+/// Library-side test object for OwnPtr/RawPtr.
+///
+typedef struct _cef_translator_test_scoped_library_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_scoped_t base;
+
+ ///
+ /// Return a value.
+ ///
+ int(CEF_CALLBACK* get_value)(
+ struct _cef_translator_test_scoped_library_t* self);
+
+ ///
+ /// Set a value.
+ ///
+ void(CEF_CALLBACK* set_value)(
+ struct _cef_translator_test_scoped_library_t* self,
+ int value);
+} cef_translator_test_scoped_library_t;
+
+///
+/// Create the test object.
+///
+CEF_EXPORT cef_translator_test_scoped_library_t*
+cef_translator_test_scoped_library_create(int value);
+
+///
+/// Library-side child test object for OwnPtr/RawPtr.
+///
+typedef struct _cef_translator_test_scoped_library_child_t {
+ ///
+ /// Base structure.
+ ///
+ cef_translator_test_scoped_library_t base;
+
+ ///
+ /// Return a value.
+ ///
+ int(CEF_CALLBACK* get_other_value)(
+ struct _cef_translator_test_scoped_library_child_t* self);
+
+ ///
+ /// Set a value.
+ ///
+ void(CEF_CALLBACK* set_other_value)(
+ struct _cef_translator_test_scoped_library_child_t* self,
+ int value);
+} cef_translator_test_scoped_library_child_t;
+
+///
+/// Create the test object.
+///
+CEF_EXPORT cef_translator_test_scoped_library_child_t*
+cef_translator_test_scoped_library_child_create(int value, int other_value);
+
+///
+/// Another library-side child test object for OwnPtr/RawPtr.
+///
+typedef struct _cef_translator_test_scoped_library_child_child_t {
+ ///
+ /// Base structure.
+ ///
+ cef_translator_test_scoped_library_child_t base;
+
+ ///
+ /// Return a value.
+ ///
+ int(CEF_CALLBACK* get_other_other_value)(
+ struct _cef_translator_test_scoped_library_child_child_t* self);
+
+ ///
+ /// Set a value.
+ ///
+ void(CEF_CALLBACK* set_other_other_value)(
+ struct _cef_translator_test_scoped_library_child_child_t* self,
+ int value);
+} cef_translator_test_scoped_library_child_child_t;
+
+///
+/// Create the test object.
+///
+CEF_EXPORT cef_translator_test_scoped_library_child_child_t*
+cef_translator_test_scoped_library_child_child_create(int value,
+ int other_value,
+ int other_other_value);
+
+///
+/// Client-side test object for OwnPtr/RawPtr.
+///
+typedef struct _cef_translator_test_scoped_client_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_scoped_t base;
+
+ ///
+ /// Return a value.
+ ///
+ int(CEF_CALLBACK* get_value)(
+ struct _cef_translator_test_scoped_client_t* self);
+} cef_translator_test_scoped_client_t;
+
+///
+/// Client-side child test object for OwnPtr/RawPtr.
+///
+typedef struct _cef_translator_test_scoped_client_child_t {
+ ///
+ /// Base structure.
+ ///
+ cef_translator_test_scoped_client_t base;
+
+ ///
+ /// Return a value.
+ ///
+ int(CEF_CALLBACK* get_other_value)(
+ struct _cef_translator_test_scoped_client_child_t* self);
+} cef_translator_test_scoped_client_child_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_TEST_CEF_TRANSLATOR_TEST_CAPI_H_
diff --git a/include/capi/views/cef_box_layout_capi.h b/include/capi/views/cef_box_layout_capi.h
new file mode 100644
index 00000000..f053f017
--- /dev/null
+++ b/include/capi/views/cef_box_layout_capi.h
@@ -0,0 +1,88 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=31153d0702b646d310e74f04e256c0f5915b8caa$
+//
+
+#ifndef CEF_INCLUDE_CAPI_VIEWS_CEF_BOX_LAYOUT_CAPI_H_
+#define CEF_INCLUDE_CAPI_VIEWS_CEF_BOX_LAYOUT_CAPI_H_
+#pragma once
+
+#include "include/capi/views/cef_layout_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _cef_view_t;
+
+///
+/// A Layout manager that arranges child views vertically or horizontally in a
+/// side-by-side fashion with spacing around and between the child views. The
+/// child views are always sized according to their preferred size. If the
+/// host's bounds provide insufficient space, child views will be clamped.
+/// Excess space will not be distributed. Methods must be called on the browser
+/// process UI thread unless otherwise indicated.
+///
+typedef struct _cef_box_layout_t {
+ ///
+ /// Base structure.
+ ///
+ cef_layout_t base;
+
+ ///
+ /// Set the flex weight for the given |view|. Using the preferred size as the
+ /// basis, free space along the main axis is distributed to views in the ratio
+ /// of their flex weights. Similarly, if the views will overflow the parent,
+ /// space is subtracted in these ratios. A flex of 0 means this view is not
+ /// resized. Flex values must not be negative.
+ ///
+ void(CEF_CALLBACK* set_flex_for_view)(struct _cef_box_layout_t* self,
+ struct _cef_view_t* view,
+ int flex);
+
+ ///
+ /// Clears the flex for the given |view|, causing it to use the default flex
+ /// specified via cef_box_layout_tSettings.default_flex.
+ ///
+ void(CEF_CALLBACK* clear_flex_for_view)(struct _cef_box_layout_t* self,
+ struct _cef_view_t* view);
+} cef_box_layout_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_VIEWS_CEF_BOX_LAYOUT_CAPI_H_
diff --git a/include/capi/views/cef_browser_view_capi.h b/include/capi/views/cef_browser_view_capi.h
new file mode 100644
index 00000000..1e190bf7
--- /dev/null
+++ b/include/capi/views/cef_browser_view_capi.h
@@ -0,0 +1,117 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=f72e94f6bd63b6ea623c4d3170b5ad4333c136d6$
+//
+
+#ifndef CEF_INCLUDE_CAPI_VIEWS_CEF_BROWSER_VIEW_CAPI_H_
+#define CEF_INCLUDE_CAPI_VIEWS_CEF_BROWSER_VIEW_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_browser_capi.h"
+#include "include/capi/views/cef_browser_view_delegate_capi.h"
+#include "include/capi/views/cef_view_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// A View hosting a cef_browser_t instance. Methods must be called on the
+/// browser process UI thread unless otherwise indicated.
+///
+typedef struct _cef_browser_view_t {
+ ///
+ /// Base structure.
+ ///
+ cef_view_t base;
+
+ ///
+ /// Returns the cef_browser_t hosted by this BrowserView. Will return NULL if
+ /// the browser has not yet been created or has already been destroyed.
+ ///
+ struct _cef_browser_t*(CEF_CALLBACK* get_browser)(
+ struct _cef_browser_view_t* self);
+
+ ///
+ /// Returns the Chrome toolbar associated with this BrowserView. Only
+ /// supported when using the Chrome runtime. The cef_browser_view_delegate_t::
+ /// get_chrome_toolbar_type() function must return a value other than
+ /// CEF_CTT_NONE and the toolbar will not be available until after this
+ /// BrowserView is added to a cef_window_t and
+ /// cef_view_delegate_t::on_window_changed() has been called.
+ ///
+ struct _cef_view_t*(CEF_CALLBACK* get_chrome_toolbar)(
+ struct _cef_browser_view_t* self);
+
+ ///
+ /// Sets whether accelerators registered with cef_window_t::SetAccelerator are
+ /// triggered before or after the event is sent to the cef_browser_t. If
+ /// |prefer_accelerators| is true (1) then the matching accelerator will be
+ /// triggered immediately and the event will not be sent to the cef_browser_t.
+ /// If |prefer_accelerators| is false (0) then the matching accelerator will
+ /// only be triggered if the event is not handled by web content or by
+ /// cef_keyboard_handler_t. The default value is false (0).
+ ///
+ void(CEF_CALLBACK* set_prefer_accelerators)(struct _cef_browser_view_t* self,
+ int prefer_accelerators);
+} cef_browser_view_t;
+
+///
+/// Create a new BrowserView. The underlying cef_browser_t will not be created
+/// until this view is added to the views hierarchy. The optional |extra_info|
+/// parameter provides an opportunity to specify extra information specific to
+/// the created browser that will be passed to
+/// cef_render_process_handler_t::on_browser_created() in the render process.
+///
+CEF_EXPORT cef_browser_view_t* cef_browser_view_create(
+ struct _cef_client_t* client,
+ const cef_string_t* url,
+ const struct _cef_browser_settings_t* settings,
+ struct _cef_dictionary_value_t* extra_info,
+ struct _cef_request_context_t* request_context,
+ struct _cef_browser_view_delegate_t* delegate);
+
+///
+/// Returns the BrowserView associated with |browser|.
+///
+CEF_EXPORT cef_browser_view_t* cef_browser_view_get_for_browser(
+ struct _cef_browser_t* browser);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_VIEWS_CEF_BROWSER_VIEW_CAPI_H_
diff --git a/include/capi/views/cef_browser_view_delegate_capi.h b/include/capi/views/cef_browser_view_delegate_capi.h
new file mode 100644
index 00000000..25fc074f
--- /dev/null
+++ b/include/capi/views/cef_browser_view_delegate_capi.h
@@ -0,0 +1,129 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=e38c41a553d518abcd1b912d32281e99b93c4fd7$
+//
+
+#ifndef CEF_INCLUDE_CAPI_VIEWS_CEF_BROWSER_VIEW_DELEGATE_CAPI_H_
+#define CEF_INCLUDE_CAPI_VIEWS_CEF_BROWSER_VIEW_DELEGATE_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_client_capi.h"
+#include "include/capi/views/cef_view_delegate_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _cef_browser_t;
+struct _cef_browser_view_t;
+
+///
+/// Implement this structure to handle BrowserView events. The functions of this
+/// structure will be called on the browser process UI thread unless otherwise
+/// indicated.
+///
+typedef struct _cef_browser_view_delegate_t {
+ ///
+ /// Base structure.
+ ///
+ cef_view_delegate_t base;
+
+ ///
+ /// Called when |browser| associated with |browser_view| is created. This
+ /// function will be called after cef_life_span_handler_t::on_after_created()
+ /// is called for |browser| and before on_popup_browser_view_created() is
+ /// called for |browser|'s parent delegate if |browser| is a popup.
+ ///
+ void(CEF_CALLBACK* on_browser_created)(
+ struct _cef_browser_view_delegate_t* self,
+ struct _cef_browser_view_t* browser_view,
+ struct _cef_browser_t* browser);
+
+ ///
+ /// Called when |browser| associated with |browser_view| is destroyed. Release
+ /// all references to |browser| and do not attempt to execute any functions on
+ /// |browser| after this callback returns. This function will be called before
+ /// cef_life_span_handler_t::on_before_close() is called for |browser|.
+ ///
+ void(CEF_CALLBACK* on_browser_destroyed)(
+ struct _cef_browser_view_delegate_t* self,
+ struct _cef_browser_view_t* browser_view,
+ struct _cef_browser_t* browser);
+
+ ///
+ /// Called before a new popup BrowserView is created. The popup originated
+ /// from |browser_view|. |settings| and |client| are the values returned from
+ /// cef_life_span_handler_t::on_before_popup(). |is_devtools| will be true (1)
+ /// if the popup will be a DevTools browser. Return the delegate that will be
+ /// used for the new popup BrowserView.
+ ///
+ struct _cef_browser_view_delegate_t*(
+ CEF_CALLBACK* get_delegate_for_popup_browser_view)(
+ struct _cef_browser_view_delegate_t* self,
+ struct _cef_browser_view_t* browser_view,
+ const struct _cef_browser_settings_t* settings,
+ struct _cef_client_t* client,
+ int is_devtools);
+
+ ///
+ /// Called after |popup_browser_view| is created. This function will be called
+ /// after cef_life_span_handler_t::on_after_created() and on_browser_created()
+ /// are called for the new popup browser. The popup originated from
+ /// |browser_view|. |is_devtools| will be true (1) if the popup is a DevTools
+ /// browser. Optionally add |popup_browser_view| to the views hierarchy
+ /// yourself and return true (1). Otherwise return false (0) and a default
+ /// cef_window_t will be created for the popup.
+ ///
+ int(CEF_CALLBACK* on_popup_browser_view_created)(
+ struct _cef_browser_view_delegate_t* self,
+ struct _cef_browser_view_t* browser_view,
+ struct _cef_browser_view_t* popup_browser_view,
+ int is_devtools);
+
+ ///
+ /// Returns the Chrome toolbar type that will be available via
+ /// cef_browser_view_t::get_chrome_toolbar(). See that function for related
+ /// documentation.
+ ///
+ cef_chrome_toolbar_type_t(CEF_CALLBACK* get_chrome_toolbar_type)(
+ struct _cef_browser_view_delegate_t* self);
+} cef_browser_view_delegate_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_VIEWS_CEF_BROWSER_VIEW_DELEGATE_CAPI_H_
diff --git a/include/capi/views/cef_button_capi.h b/include/capi/views/cef_button_capi.h
new file mode 100644
index 00000000..e4fa6815
--- /dev/null
+++ b/include/capi/views/cef_button_capi.h
@@ -0,0 +1,104 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=6580dc6ef6c20d5d78dc0160982b9ef57c939f86$
+//
+
+#ifndef CEF_INCLUDE_CAPI_VIEWS_CEF_BUTTON_CAPI_H_
+#define CEF_INCLUDE_CAPI_VIEWS_CEF_BUTTON_CAPI_H_
+#pragma once
+
+#include "include/capi/views/cef_view_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _cef_label_button_t;
+
+///
+/// A View representing a button. Depending on the specific type, the button
+/// could be implemented by a native control or custom rendered. Methods must be
+/// called on the browser process UI thread unless otherwise indicated.
+///
+typedef struct _cef_button_t {
+ ///
+ /// Base structure.
+ ///
+ cef_view_t base;
+
+ ///
+ /// Returns this Button as a LabelButton or NULL if this is not a LabelButton.
+ ///
+ struct _cef_label_button_t*(CEF_CALLBACK* as_label_button)(
+ struct _cef_button_t* self);
+
+ ///
+ /// Sets the current display state of the Button.
+ ///
+ void(CEF_CALLBACK* set_state)(struct _cef_button_t* self,
+ cef_button_state_t state);
+
+ ///
+ /// Returns the current display state of the Button.
+ ///
+ cef_button_state_t(CEF_CALLBACK* get_state)(struct _cef_button_t* self);
+
+ ///
+ /// Sets the Button will use an ink drop effect for displaying state changes.
+ ///
+ void(CEF_CALLBACK* set_ink_drop_enabled)(struct _cef_button_t* self,
+ int enabled);
+
+ ///
+ /// Sets the tooltip text that will be displayed when the user hovers the
+ /// mouse cursor over the Button.
+ ///
+ void(CEF_CALLBACK* set_tooltip_text)(struct _cef_button_t* self,
+ const cef_string_t* tooltip_text);
+
+ ///
+ /// Sets the accessible name that will be exposed to assistive technology
+ /// (AT).
+ ///
+ void(CEF_CALLBACK* set_accessible_name)(struct _cef_button_t* self,
+ const cef_string_t* name);
+} cef_button_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_VIEWS_CEF_BUTTON_CAPI_H_
diff --git a/include/capi/views/cef_button_delegate_capi.h b/include/capi/views/cef_button_delegate_capi.h
new file mode 100644
index 00000000..caa27da2
--- /dev/null
+++ b/include/capi/views/cef_button_delegate_capi.h
@@ -0,0 +1,80 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=9843593667569cf8755386ab2d884620087a36b8$
+//
+
+#ifndef CEF_INCLUDE_CAPI_VIEWS_CEF_BUTTON_DELEGATE_CAPI_H_
+#define CEF_INCLUDE_CAPI_VIEWS_CEF_BUTTON_DELEGATE_CAPI_H_
+#pragma once
+
+#include "include/capi/views/cef_view_delegate_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _cef_button_t;
+
+///
+/// Implement this structure to handle Button events. The functions of this
+/// structure will be called on the browser process UI thread unless otherwise
+/// indicated.
+///
+typedef struct _cef_button_delegate_t {
+ ///
+ /// Base structure.
+ ///
+ cef_view_delegate_t base;
+
+ ///
+ /// Called when |button| is pressed.
+ ///
+ void(CEF_CALLBACK* on_button_pressed)(struct _cef_button_delegate_t* self,
+ struct _cef_button_t* button);
+
+ ///
+ /// Called when the state of |button| changes.
+ ///
+ void(CEF_CALLBACK* on_button_state_changed)(
+ struct _cef_button_delegate_t* self,
+ struct _cef_button_t* button);
+} cef_button_delegate_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_VIEWS_CEF_BUTTON_DELEGATE_CAPI_H_
diff --git a/include/capi/views/cef_display_capi.h b/include/capi/views/cef_display_capi.h
new file mode 100644
index 00000000..3c36324d
--- /dev/null
+++ b/include/capi/views/cef_display_capi.h
@@ -0,0 +1,175 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=7674d3af52dd4272b454b2028e7a4ee72fb3c9ff$
+//
+
+#ifndef CEF_INCLUDE_CAPI_VIEWS_CEF_DISPLAY_CAPI_H_
+#define CEF_INCLUDE_CAPI_VIEWS_CEF_DISPLAY_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// This structure typically, but not always, corresponds to a physical display
+/// connected to the system. A fake Display may exist on a headless system, or a
+/// Display may correspond to a remote, virtual display. All size and position
+/// values are in density independent pixel (DIP) coordinates unless otherwise
+/// indicated. Methods must be called on the browser process UI thread unless
+/// otherwise indicated.
+///
+typedef struct _cef_display_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Returns the unique identifier for this Display.
+ ///
+ int64(CEF_CALLBACK* get_id)(struct _cef_display_t* self);
+
+ ///
+ /// Returns this Display's device pixel scale factor. This specifies how much
+ /// the UI should be scaled when the actual output has more pixels than
+ /// standard displays (which is around 100~120dpi). The potential return
+ /// values differ by platform.
+ ///
+ float(CEF_CALLBACK* get_device_scale_factor)(struct _cef_display_t* self);
+
+ ///
+ /// Convert |point| from DIP coordinates to pixel coordinates using this
+ /// Display's device scale factor.
+ ///
+ void(CEF_CALLBACK* convert_point_to_pixels)(struct _cef_display_t* self,
+ cef_point_t* point);
+
+ ///
+ /// Convert |point| from pixel coordinates to DIP coordinates using this
+ /// Display's device scale factor.
+ ///
+ void(CEF_CALLBACK* convert_point_from_pixels)(struct _cef_display_t* self,
+ cef_point_t* point);
+
+ ///
+ /// Returns this Display's bounds in DIP screen coordinates. This is the full
+ /// size of the display.
+ ///
+ cef_rect_t(CEF_CALLBACK* get_bounds)(struct _cef_display_t* self);
+
+ ///
+ /// Returns this Display's work area in DIP screen coordinates. This excludes
+ /// areas of the display that are occupied with window manager toolbars, etc.
+ ///
+ cef_rect_t(CEF_CALLBACK* get_work_area)(struct _cef_display_t* self);
+
+ ///
+ /// Returns this Display's rotation in degrees.
+ ///
+ int(CEF_CALLBACK* get_rotation)(struct _cef_display_t* self);
+} cef_display_t;
+
+///
+/// Returns the primary Display.
+///
+CEF_EXPORT cef_display_t* cef_display_get_primary(void);
+
+///
+/// Returns the Display nearest |point|. Set |input_pixel_coords| to true (1) if
+/// |point| is in pixel screen coordinates instead of DIP screen coordinates.
+///
+CEF_EXPORT cef_display_t* cef_display_get_nearest_point(
+ const cef_point_t* point,
+ int input_pixel_coords);
+
+///
+/// Returns the Display that most closely intersects |bounds|. Set
+/// |input_pixel_coords| to true (1) if |bounds| is in pixel screen coordinates
+/// instead of DIP screen coordinates.
+///
+CEF_EXPORT cef_display_t* cef_display_get_matching_bounds(
+ const cef_rect_t* bounds,
+ int input_pixel_coords);
+
+///
+/// Returns the total number of Displays. Mirrored displays are excluded; this
+/// function is intended to return the number of distinct, usable displays.
+///
+CEF_EXPORT size_t cef_display_get_count(void);
+
+///
+/// Returns all Displays. Mirrored displays are excluded; this function is
+/// intended to return distinct, usable displays.
+///
+CEF_EXPORT void cef_display_get_alls(size_t* displaysCount,
+ cef_display_t** displays);
+
+///
+/// Convert |point| from DIP screen coordinates to pixel screen coordinates.
+/// This function is only used on Windows.
+///
+CEF_EXPORT cef_point_t
+cef_display_convert_screen_point_to_pixels(const cef_point_t* point);
+
+///
+/// Convert |point| from pixel screen coordinates to DIP screen coordinates.
+/// This function is only used on Windows.
+///
+CEF_EXPORT cef_point_t
+cef_display_convert_screen_point_from_pixels(const cef_point_t* point);
+
+///
+/// Convert |rect| from DIP screen coordinates to pixel screen coordinates. This
+/// function is only used on Windows.
+///
+CEF_EXPORT cef_rect_t
+cef_display_convert_screen_rect_to_pixels(const cef_rect_t* rect);
+
+///
+/// Convert |rect| from pixel screen coordinates to DIP screen coordinates. This
+/// function is only used on Windows.
+///
+CEF_EXPORT cef_rect_t
+cef_display_convert_screen_rect_from_pixels(const cef_rect_t* rect);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_VIEWS_CEF_DISPLAY_CAPI_H_
diff --git a/include/capi/views/cef_fill_layout_capi.h b/include/capi/views/cef_fill_layout_capi.h
new file mode 100644
index 00000000..c9ae6d9c
--- /dev/null
+++ b/include/capi/views/cef_fill_layout_capi.h
@@ -0,0 +1,65 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=fdb3457ac8b18ad3cf0144af5886586dd675c8f8$
+//
+
+#ifndef CEF_INCLUDE_CAPI_VIEWS_CEF_FILL_LAYOUT_CAPI_H_
+#define CEF_INCLUDE_CAPI_VIEWS_CEF_FILL_LAYOUT_CAPI_H_
+#pragma once
+
+#include "include/capi/views/cef_layout_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// A simple Layout that causes the associated Panel's one child to be sized to
+/// match the bounds of its parent. Methods must be called on the browser
+/// process UI thread unless otherwise indicated.
+///
+typedef struct _cef_fill_layout_t {
+ ///
+ /// Base structure.
+ ///
+ cef_layout_t base;
+} cef_fill_layout_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_VIEWS_CEF_FILL_LAYOUT_CAPI_H_
diff --git a/include/capi/views/cef_label_button_capi.h b/include/capi/views/cef_label_button_capi.h
new file mode 100644
index 00000000..07b38763
--- /dev/null
+++ b/include/capi/views/cef_label_button_capi.h
@@ -0,0 +1,162 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=eee5b9ebfa58617d5e6fa969e27cc9e378fddb22$
+//
+
+#ifndef CEF_INCLUDE_CAPI_VIEWS_CEF_LABEL_BUTTON_CAPI_H_
+#define CEF_INCLUDE_CAPI_VIEWS_CEF_LABEL_BUTTON_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_image_capi.h"
+#include "include/capi/views/cef_button_capi.h"
+#include "include/capi/views/cef_button_delegate_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _cef_menu_button_t;
+
+///
+/// LabelButton is a button with optional text and/or icon. Methods must be
+/// called on the browser process UI thread unless otherwise indicated.
+///
+typedef struct _cef_label_button_t {
+ ///
+ /// Base structure.
+ ///
+ cef_button_t base;
+
+ ///
+ /// Returns this LabelButton as a MenuButton or NULL if this is not a
+ /// MenuButton.
+ ///
+ struct _cef_menu_button_t*(CEF_CALLBACK* as_menu_button)(
+ struct _cef_label_button_t* self);
+
+ ///
+ /// Sets the text shown on the LabelButton. By default |text| will also be
+ /// used as the accessible name.
+ ///
+ void(CEF_CALLBACK* set_text)(struct _cef_label_button_t* self,
+ const cef_string_t* text);
+
+ ///
+ /// Returns the text shown on the LabelButton.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_text)(
+ struct _cef_label_button_t* self);
+
+ ///
+ /// Sets the image shown for |button_state|. When this Button is drawn if no
+ /// image exists for the current state then the image for
+ /// CEF_BUTTON_STATE_NORMAL, if any, will be shown.
+ ///
+ void(CEF_CALLBACK* set_image)(struct _cef_label_button_t* self,
+ cef_button_state_t button_state,
+ struct _cef_image_t* image);
+
+ ///
+ /// Returns the image shown for |button_state|. If no image exists for that
+ /// state then the image for CEF_BUTTON_STATE_NORMAL will be returned.
+ ///
+ struct _cef_image_t*(CEF_CALLBACK* get_image)(
+ struct _cef_label_button_t* self,
+ cef_button_state_t button_state);
+
+ ///
+ /// Sets the text color shown for the specified button |for_state| to |color|.
+ ///
+ void(CEF_CALLBACK* set_text_color)(struct _cef_label_button_t* self,
+ cef_button_state_t for_state,
+ cef_color_t color);
+
+ ///
+ /// Sets the text colors shown for the non-disabled states to |color|.
+ ///
+ void(CEF_CALLBACK* set_enabled_text_colors)(struct _cef_label_button_t* self,
+ cef_color_t color);
+
+ ///
+ /// Sets the font list. The format is "<FONT_FAMILY_LIST>,[STYLES] <SIZE>",
+ /// where: - FONT_FAMILY_LIST is a comma-separated list of font family names,
+ /// - STYLES is an optional space-separated list of style names (case-
+ /// sensitive
+ /// "Bold" and "Italic" are supported), and
+ /// - SIZE is an integer font size in pixels with the suffix "px".
+ ///
+ /// Here are examples of valid font description strings: - "Arial, Helvetica,
+ /// Bold Italic 14px" - "Arial, 14px"
+ ///
+ void(CEF_CALLBACK* set_font_list)(struct _cef_label_button_t* self,
+ const cef_string_t* font_list);
+
+ ///
+ /// Sets the horizontal alignment; reversed in RTL. Default is
+ /// CEF_HORIZONTAL_ALIGNMENT_CENTER.
+ ///
+ void(CEF_CALLBACK* set_horizontal_alignment)(
+ struct _cef_label_button_t* self,
+ cef_horizontal_alignment_t alignment);
+
+ ///
+ /// Reset the minimum size of this LabelButton to |size|.
+ ///
+ void(CEF_CALLBACK* set_minimum_size)(struct _cef_label_button_t* self,
+ const cef_size_t* size);
+
+ ///
+ /// Reset the maximum size of this LabelButton to |size|.
+ ///
+ void(CEF_CALLBACK* set_maximum_size)(struct _cef_label_button_t* self,
+ const cef_size_t* size);
+} cef_label_button_t;
+
+///
+/// Create a new LabelButton. A |delegate| must be provided to handle the button
+/// click. |text| will be shown on the LabelButton and used as the default
+/// accessible name.
+///
+CEF_EXPORT cef_label_button_t* cef_label_button_create(
+ struct _cef_button_delegate_t* delegate,
+ const cef_string_t* text);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_VIEWS_CEF_LABEL_BUTTON_CAPI_H_
diff --git a/include/capi/views/cef_layout_capi.h b/include/capi/views/cef_layout_capi.h
new file mode 100644
index 00000000..5430a459
--- /dev/null
+++ b/include/capi/views/cef_layout_capi.h
@@ -0,0 +1,85 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=c4a17c07bb2a3518fc5b7350efdc13ffeb803747$
+//
+
+#ifndef CEF_INCLUDE_CAPI_VIEWS_CEF_LAYOUT_CAPI_H_
+#define CEF_INCLUDE_CAPI_VIEWS_CEF_LAYOUT_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _cef_box_layout_t;
+struct _cef_fill_layout_t;
+
+///
+/// A Layout handles the sizing of the children of a Panel according to
+/// implementation-specific heuristics. Methods must be called on the browser
+/// process UI thread unless otherwise indicated.
+///
+typedef struct _cef_layout_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Returns this Layout as a BoxLayout or NULL if this is not a BoxLayout.
+ ///
+ struct _cef_box_layout_t*(CEF_CALLBACK* as_box_layout)(
+ struct _cef_layout_t* self);
+
+ ///
+ /// Returns this Layout as a FillLayout or NULL if this is not a FillLayout.
+ ///
+ struct _cef_fill_layout_t*(CEF_CALLBACK* as_fill_layout)(
+ struct _cef_layout_t* self);
+
+ ///
+ /// Returns true (1) if this Layout is valid.
+ ///
+ int(CEF_CALLBACK* is_valid)(struct _cef_layout_t* self);
+} cef_layout_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_VIEWS_CEF_LAYOUT_CAPI_H_
diff --git a/include/capi/views/cef_menu_button_capi.h b/include/capi/views/cef_menu_button_capi.h
new file mode 100644
index 00000000..85cec0fe
--- /dev/null
+++ b/include/capi/views/cef_menu_button_capi.h
@@ -0,0 +1,99 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=dcfa5d39d1355b2c675637a13378f43376a8053e$
+//
+
+#ifndef CEF_INCLUDE_CAPI_VIEWS_CEF_MENU_BUTTON_CAPI_H_
+#define CEF_INCLUDE_CAPI_VIEWS_CEF_MENU_BUTTON_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_menu_model_capi.h"
+#include "include/capi/views/cef_label_button_capi.h"
+#include "include/capi/views/cef_menu_button_delegate_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// MenuButton is a button with optional text, icon and/or menu marker that
+/// shows a menu when clicked with the left mouse button. All size and position
+/// values are in density independent pixels (DIP) unless otherwise indicated.
+/// Methods must be called on the browser process UI thread unless otherwise
+/// indicated.
+///
+typedef struct _cef_menu_button_t {
+ ///
+ /// Base structure.
+ ///
+ cef_label_button_t base;
+
+ ///
+ /// Show a menu with contents |menu_model|. |screen_point| specifies the menu
+ /// position in screen coordinates. |anchor_position| specifies how the menu
+ /// will be anchored relative to |screen_point|. This function should be
+ /// called from cef_menu_button_delegate_t::on_menu_button_pressed().
+ ///
+ void(CEF_CALLBACK* show_menu)(struct _cef_menu_button_t* self,
+ struct _cef_menu_model_t* menu_model,
+ const cef_point_t* screen_point,
+ cef_menu_anchor_position_t anchor_position);
+
+ ///
+ /// Show the menu for this button. Results in a call to
+ /// cef_menu_button_delegate_t::on_menu_button_pressed().
+ ///
+ void(CEF_CALLBACK* trigger_menu)(struct _cef_menu_button_t* self);
+} cef_menu_button_t;
+
+///
+/// Create a new MenuButton. A |delegate| must be provided to call show_menu()
+/// when the button is clicked. |text| will be shown on the MenuButton and used
+/// as the default accessible name. If |with_frame| is true (1) the button will
+/// have a visible frame at all times, center alignment, additional padding and
+/// a default minimum size of 70x33 DIP. If |with_frame| is false (0) the button
+/// will only have a visible frame on hover/press, left alignment, less padding
+/// and no default minimum size.
+///
+CEF_EXPORT cef_menu_button_t* cef_menu_button_create(
+ struct _cef_menu_button_delegate_t* delegate,
+ const cef_string_t* text);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_VIEWS_CEF_MENU_BUTTON_CAPI_H_
diff --git a/include/capi/views/cef_menu_button_delegate_capi.h b/include/capi/views/cef_menu_button_delegate_capi.h
new file mode 100644
index 00000000..5d938648
--- /dev/null
+++ b/include/capi/views/cef_menu_button_delegate_capi.h
@@ -0,0 +1,89 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=38177cad78713d382b81f8b8aa4372402c62fac7$
+//
+
+#ifndef CEF_INCLUDE_CAPI_VIEWS_CEF_MENU_BUTTON_DELEGATE_CAPI_H_
+#define CEF_INCLUDE_CAPI_VIEWS_CEF_MENU_BUTTON_DELEGATE_CAPI_H_
+#pragma once
+
+#include "include/capi/views/cef_button_delegate_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _cef_menu_button_t;
+
+///
+/// MenuButton pressed lock is released when this object is destroyed.
+///
+typedef struct _cef_menu_button_pressed_lock_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+} cef_menu_button_pressed_lock_t;
+
+///
+/// Implement this structure to handle MenuButton events. The functions of this
+/// structure will be called on the browser process UI thread unless otherwise
+/// indicated.
+///
+typedef struct _cef_menu_button_delegate_t {
+ ///
+ /// Base structure.
+ ///
+ cef_button_delegate_t base;
+
+ ///
+ /// Called when |button| is pressed. Call cef_menu_button_t::show_menu() to
+ /// show a popup menu at |screen_point|. When showing a custom popup such as a
+ /// window keep a reference to |button_pressed_lock| until the popup is hidden
+ /// to maintain the pressed button state.
+ ///
+ void(CEF_CALLBACK* on_menu_button_pressed)(
+ struct _cef_menu_button_delegate_t* self,
+ struct _cef_menu_button_t* menu_button,
+ const cef_point_t* screen_point,
+ struct _cef_menu_button_pressed_lock_t* button_pressed_lock);
+} cef_menu_button_delegate_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_VIEWS_CEF_MENU_BUTTON_DELEGATE_CAPI_H_
diff --git a/include/capi/views/cef_overlay_controller_capi.h b/include/capi/views/cef_overlay_controller_capi.h
new file mode 100644
index 00000000..8084bfd6
--- /dev/null
+++ b/include/capi/views/cef_overlay_controller_capi.h
@@ -0,0 +1,217 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=a5a2c7fe2c285b45268eee1710a8549ab12727f3$
+//
+
+#ifndef CEF_INCLUDE_CAPI_VIEWS_CEF_OVERLAY_CONTROLLER_CAPI_H_
+#define CEF_INCLUDE_CAPI_VIEWS_CEF_OVERLAY_CONTROLLER_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _cef_view_t;
+struct _cef_window_t;
+
+///
+/// Controller for an overlay that contains a contents View added via
+/// cef_window_t::AddOverlayView. Methods exposed by this controller should be
+/// called in preference to functions of the same name exposed by the contents
+/// View unless otherwise indicated. Methods must be called on the browser
+/// process UI thread unless otherwise indicated.
+///
+typedef struct _cef_overlay_controller_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Returns true (1) if this object is valid.
+ ///
+ int(CEF_CALLBACK* is_valid)(struct _cef_overlay_controller_t* self);
+
+ ///
+ /// Returns true (1) if this object is the same as |that| object.
+ ///
+ int(CEF_CALLBACK* is_same)(struct _cef_overlay_controller_t* self,
+ struct _cef_overlay_controller_t* that);
+
+ ///
+ /// Returns the contents View for this overlay.
+ ///
+ struct _cef_view_t*(CEF_CALLBACK* get_contents_view)(
+ struct _cef_overlay_controller_t* self);
+
+ ///
+ /// Returns the top-level Window hosting this overlay. Use this function
+ /// instead of calling get_window() on the contents View.
+ ///
+ struct _cef_window_t*(CEF_CALLBACK* get_window)(
+ struct _cef_overlay_controller_t* self);
+
+ ///
+ /// Returns the docking mode for this overlay.
+ ///
+ cef_docking_mode_t(CEF_CALLBACK* get_docking_mode)(
+ struct _cef_overlay_controller_t* self);
+
+ ///
+ /// Destroy this overlay.
+ ///
+ void(CEF_CALLBACK* destroy)(struct _cef_overlay_controller_t* self);
+
+ ///
+ /// Sets the bounds (size and position) of this overlay. This will set the
+ /// bounds of the contents View to match and trigger a re-layout if necessary.
+ /// |bounds| is in parent coordinates and any insets configured on this
+ /// overlay will be ignored. Use this function only for overlays created with
+ /// a docking mode value of CEF_DOCKING_MODE_CUSTOM. With other docking modes
+ /// modify the insets of this overlay and/or layout of the contents View and
+ /// call size_to_preferred_size() instead to calculate the new size and re-
+ /// position the overlay if necessary.
+ ///
+ void(CEF_CALLBACK* set_bounds)(struct _cef_overlay_controller_t* self,
+ const cef_rect_t* bounds);
+
+ ///
+ /// Returns the bounds (size and position) of this overlay in parent
+ /// coordinates.
+ ///
+ cef_rect_t(CEF_CALLBACK* get_bounds)(struct _cef_overlay_controller_t* self);
+
+ ///
+ /// Returns the bounds (size and position) of this overlay in DIP screen
+ /// coordinates.
+ ///
+ cef_rect_t(CEF_CALLBACK* get_bounds_in_screen)(
+ struct _cef_overlay_controller_t* self);
+
+ ///
+ /// Sets the size of this overlay without changing the position. This will set
+ /// the size of the contents View to match and trigger a re-layout if
+ /// necessary. |size| is in parent coordinates and any insets configured on
+ /// this overlay will be ignored. Use this function only for overlays created
+ /// with a docking mode value of CEF_DOCKING_MODE_CUSTOM. With other docking
+ /// modes modify the insets of this overlay and/or layout of the contents View
+ /// and call size_to_preferred_size() instead to calculate the new size and
+ /// re-position the overlay if necessary.
+ ///
+ void(CEF_CALLBACK* set_size)(struct _cef_overlay_controller_t* self,
+ const cef_size_t* size);
+
+ ///
+ /// Returns the size of this overlay in parent coordinates.
+ ///
+ cef_size_t(CEF_CALLBACK* get_size)(struct _cef_overlay_controller_t* self);
+
+ ///
+ /// Sets the position of this overlay without changing the size. |position| is
+ /// in parent coordinates and any insets configured on this overlay will be
+ /// ignored. Use this function only for overlays created with a docking mode
+ /// value of CEF_DOCKING_MODE_CUSTOM. With other docking modes modify the
+ /// insets of this overlay and/or layout of the contents View and call
+ /// size_to_preferred_size() instead to calculate the new size and re-position
+ /// the overlay if necessary.
+ ///
+ void(CEF_CALLBACK* set_position)(struct _cef_overlay_controller_t* self,
+ const cef_point_t* position);
+
+ ///
+ /// Returns the position of this overlay in parent coordinates.
+ ///
+ cef_point_t(CEF_CALLBACK* get_position)(
+ struct _cef_overlay_controller_t* self);
+
+ ///
+ /// Sets the insets for this overlay. |insets| is in parent coordinates. Use
+ /// this function only for overlays created with a docking mode value other
+ /// than CEF_DOCKING_MODE_CUSTOM.
+ ///
+ void(CEF_CALLBACK* set_insets)(struct _cef_overlay_controller_t* self,
+ const cef_insets_t* insets);
+
+ ///
+ /// Returns the insets for this overlay in parent coordinates.
+ ///
+ cef_insets_t(CEF_CALLBACK* get_insets)(
+ struct _cef_overlay_controller_t* self);
+
+ ///
+ /// Size this overlay to its preferred size and trigger a re-layout if
+ /// necessary. The position of overlays created with a docking mode value of
+ /// CEF_DOCKING_MODE_CUSTOM will not be modified by calling this function.
+ /// With other docking modes this function may re-position the overlay if
+ /// necessary to accommodate the new size and any insets configured on the
+ /// contents View.
+ ///
+ void(CEF_CALLBACK* size_to_preferred_size)(
+ struct _cef_overlay_controller_t* self);
+
+ ///
+ /// Sets whether this overlay is visible. Overlays are hidden by default. If
+ /// this overlay is hidden then it and any child Views will not be drawn and,
+ /// if any of those Views currently have focus, then focus will also be
+ /// cleared. Painting is scheduled as needed.
+ ///
+ void(CEF_CALLBACK* set_visible)(struct _cef_overlay_controller_t* self,
+ int visible);
+
+ ///
+ /// Returns whether this overlay is visible. A View may be visible but still
+ /// not drawn in a Window if any parent Views are hidden. Call is_drawn() to
+ /// determine whether this overlay and all parent Views are visible and will
+ /// be drawn.
+ ///
+ int(CEF_CALLBACK* is_visible)(struct _cef_overlay_controller_t* self);
+
+ ///
+ /// Returns whether this overlay is visible and drawn in a Window. A View is
+ /// drawn if it and all parent Views are visible. To determine if the
+ /// containing Window is visible to the user on-screen call is_visible() on
+ /// the Window.
+ ///
+ int(CEF_CALLBACK* is_drawn)(struct _cef_overlay_controller_t* self);
+} cef_overlay_controller_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_VIEWS_CEF_OVERLAY_CONTROLLER_CAPI_H_
diff --git a/include/capi/views/cef_panel_capi.h b/include/capi/views/cef_panel_capi.h
new file mode 100644
index 00000000..658b0050
--- /dev/null
+++ b/include/capi/views/cef_panel_capi.h
@@ -0,0 +1,151 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=40d350f75893a1e4307b282317d55f0fceae3baf$
+//
+
+#ifndef CEF_INCLUDE_CAPI_VIEWS_CEF_PANEL_CAPI_H_
+#define CEF_INCLUDE_CAPI_VIEWS_CEF_PANEL_CAPI_H_
+#pragma once
+
+#include "include/capi/views/cef_panel_delegate_capi.h"
+#include "include/capi/views/cef_view_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _cef_box_layout_t;
+struct _cef_fill_layout_t;
+struct _cef_layout_t;
+struct _cef_window_t;
+
+///
+/// A Panel is a container in the views hierarchy that can contain other Views
+/// as children. Methods must be called on the browser process UI thread unless
+/// otherwise indicated.
+///
+typedef struct _cef_panel_t {
+ ///
+ /// Base structure.
+ ///
+ cef_view_t base;
+
+ ///
+ /// Returns this Panel as a Window or NULL if this is not a Window.
+ ///
+ struct _cef_window_t*(CEF_CALLBACK* as_window)(struct _cef_panel_t* self);
+
+ ///
+ /// Set this Panel's Layout to FillLayout and return the FillLayout object.
+ ///
+ struct _cef_fill_layout_t*(CEF_CALLBACK* set_to_fill_layout)(
+ struct _cef_panel_t* self);
+
+ ///
+ /// Set this Panel's Layout to BoxLayout and return the BoxLayout object.
+ ///
+ struct _cef_box_layout_t*(CEF_CALLBACK* set_to_box_layout)(
+ struct _cef_panel_t* self,
+ const cef_box_layout_settings_t* settings);
+
+ ///
+ /// Get the Layout.
+ ///
+ struct _cef_layout_t*(CEF_CALLBACK* get_layout)(struct _cef_panel_t* self);
+
+ ///
+ /// Lay out the child Views (set their bounds based on sizing heuristics
+ /// specific to the current Layout).
+ ///
+ void(CEF_CALLBACK* layout)(struct _cef_panel_t* self);
+
+ ///
+ /// Add a child View.
+ ///
+ void(CEF_CALLBACK* add_child_view)(struct _cef_panel_t* self,
+ struct _cef_view_t* view);
+
+ ///
+ /// Add a child View at the specified |index|. If |index| matches the result
+ /// of GetChildCount() then the View will be added at the end.
+ ///
+ void(CEF_CALLBACK* add_child_view_at)(struct _cef_panel_t* self,
+ struct _cef_view_t* view,
+ int index);
+
+ ///
+ /// Move the child View to the specified |index|. A negative value for |index|
+ /// will move the View to the end.
+ ///
+ void(CEF_CALLBACK* reorder_child_view)(struct _cef_panel_t* self,
+ struct _cef_view_t* view,
+ int index);
+
+ ///
+ /// Remove a child View. The View can then be added to another Panel.
+ ///
+ void(CEF_CALLBACK* remove_child_view)(struct _cef_panel_t* self,
+ struct _cef_view_t* view);
+
+ ///
+ /// Remove all child Views. The removed Views will be deleted if the client
+ /// holds no references to them.
+ ///
+ void(CEF_CALLBACK* remove_all_child_views)(struct _cef_panel_t* self);
+
+ ///
+ /// Returns the number of child Views.
+ ///
+ size_t(CEF_CALLBACK* get_child_view_count)(struct _cef_panel_t* self);
+
+ ///
+ /// Returns the child View at the specified |index|.
+ ///
+ struct _cef_view_t*(
+ CEF_CALLBACK* get_child_view_at)(struct _cef_panel_t* self, int index);
+} cef_panel_t;
+
+///
+/// Create a new Panel.
+///
+CEF_EXPORT cef_panel_t* cef_panel_create(
+ struct _cef_panel_delegate_t* delegate);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_VIEWS_CEF_PANEL_CAPI_H_
diff --git a/include/capi/views/cef_panel_delegate_capi.h b/include/capi/views/cef_panel_delegate_capi.h
new file mode 100644
index 00000000..227762d5
--- /dev/null
+++ b/include/capi/views/cef_panel_delegate_capi.h
@@ -0,0 +1,65 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=e8bdae70e1f16fba3a5e01d9e215a02f13291ff5$
+//
+
+#ifndef CEF_INCLUDE_CAPI_VIEWS_CEF_PANEL_DELEGATE_CAPI_H_
+#define CEF_INCLUDE_CAPI_VIEWS_CEF_PANEL_DELEGATE_CAPI_H_
+#pragma once
+
+#include "include/capi/views/cef_view_delegate_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Implement this structure to handle Panel events. The functions of this
+/// structure will be called on the browser process UI thread unless otherwise
+/// indicated.
+///
+typedef struct _cef_panel_delegate_t {
+ ///
+ /// Base structure.
+ ///
+ cef_view_delegate_t base;
+} cef_panel_delegate_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_VIEWS_CEF_PANEL_DELEGATE_CAPI_H_
diff --git a/include/capi/views/cef_scroll_view_capi.h b/include/capi/views/cef_scroll_view_capi.h
new file mode 100644
index 00000000..dd503c28
--- /dev/null
+++ b/include/capi/views/cef_scroll_view_capi.h
@@ -0,0 +1,112 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=e3aa3fbb265a600d498884b0fbb852fc5bbf8856$
+//
+
+#ifndef CEF_INCLUDE_CAPI_VIEWS_CEF_SCROLL_VIEW_CAPI_H_
+#define CEF_INCLUDE_CAPI_VIEWS_CEF_SCROLL_VIEW_CAPI_H_
+#pragma once
+
+#include "include/capi/views/cef_view_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// A ScrollView will show horizontal and/or vertical scrollbars when necessary
+/// based on the size of the attached content view. Methods must be called on
+/// the browser process UI thread unless otherwise indicated.
+///
+typedef struct _cef_scroll_view_t {
+ ///
+ /// Base structure.
+ ///
+ cef_view_t base;
+
+ ///
+ /// Set the content View. The content View must have a specified size (e.g.
+ /// via cef_view_t::SetBounds or cef_view_delegate_t::GetPreferredSize).
+ ///
+ void(CEF_CALLBACK* set_content_view)(struct _cef_scroll_view_t* self,
+ struct _cef_view_t* view);
+
+ ///
+ /// Returns the content View.
+ ///
+ struct _cef_view_t*(CEF_CALLBACK* get_content_view)(
+ struct _cef_scroll_view_t* self);
+
+ ///
+ /// Returns the visible region of the content View.
+ ///
+ cef_rect_t(CEF_CALLBACK* get_visible_content_rect)(
+ struct _cef_scroll_view_t* self);
+
+ ///
+ /// Returns true (1) if the horizontal scrollbar is currently showing.
+ ///
+ int(CEF_CALLBACK* has_horizontal_scrollbar)(struct _cef_scroll_view_t* self);
+
+ ///
+ /// Returns the height of the horizontal scrollbar.
+ ///
+ int(CEF_CALLBACK* get_horizontal_scrollbar_height)(
+ struct _cef_scroll_view_t* self);
+
+ ///
+ /// Returns true (1) if the vertical scrollbar is currently showing.
+ ///
+ int(CEF_CALLBACK* has_vertical_scrollbar)(struct _cef_scroll_view_t* self);
+
+ ///
+ /// Returns the width of the vertical scrollbar.
+ ///
+ int(CEF_CALLBACK* get_vertical_scrollbar_width)(
+ struct _cef_scroll_view_t* self);
+} cef_scroll_view_t;
+
+///
+/// Create a new ScrollView.
+///
+CEF_EXPORT cef_scroll_view_t* cef_scroll_view_create(
+ struct _cef_view_delegate_t* delegate);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_VIEWS_CEF_SCROLL_VIEW_CAPI_H_
diff --git a/include/capi/views/cef_textfield_capi.h b/include/capi/views/cef_textfield_capi.h
new file mode 100644
index 00000000..c525f216
--- /dev/null
+++ b/include/capi/views/cef_textfield_capi.h
@@ -0,0 +1,274 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=7d5a43282c9847c5c842abd5de023f4c5c69a9f0$
+//
+
+#ifndef CEF_INCLUDE_CAPI_VIEWS_CEF_TEXTFIELD_CAPI_H_
+#define CEF_INCLUDE_CAPI_VIEWS_CEF_TEXTFIELD_CAPI_H_
+#pragma once
+
+#include "include/capi/views/cef_textfield_delegate_capi.h"
+#include "include/capi/views/cef_view_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// A Textfield supports editing of text. This control is custom rendered with
+/// no platform-specific code. Methods must be called on the browser process UI
+/// thread unless otherwise indicated.
+///
+typedef struct _cef_textfield_t {
+ ///
+ /// Base structure.
+ ///
+ cef_view_t base;
+
+ ///
+ /// Sets whether the text will be displayed as asterisks.
+ ///
+ void(CEF_CALLBACK* set_password_input)(struct _cef_textfield_t* self,
+ int password_input);
+
+ ///
+ /// Returns true (1) if the text will be displayed as asterisks.
+ ///
+ int(CEF_CALLBACK* is_password_input)(struct _cef_textfield_t* self);
+
+ ///
+ /// Sets whether the text will read-only.
+ ///
+ void(CEF_CALLBACK* set_read_only)(struct _cef_textfield_t* self,
+ int read_only);
+
+ ///
+ /// Returns true (1) if the text is read-only.
+ ///
+ int(CEF_CALLBACK* is_read_only)(struct _cef_textfield_t* self);
+
+ ///
+ /// Returns the currently displayed text.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_text)(struct _cef_textfield_t* self);
+
+ ///
+ /// Sets the contents to |text|. The cursor will be moved to end of the text
+ /// if the current position is outside of the text range.
+ ///
+ void(CEF_CALLBACK* set_text)(struct _cef_textfield_t* self,
+ const cef_string_t* text);
+
+ ///
+ /// Appends |text| to the previously-existing text.
+ ///
+ void(CEF_CALLBACK* append_text)(struct _cef_textfield_t* self,
+ const cef_string_t* text);
+
+ ///
+ /// Inserts |text| at the current cursor position replacing any selected text.
+ ///
+ void(CEF_CALLBACK* insert_or_replace_text)(struct _cef_textfield_t* self,
+ const cef_string_t* text);
+
+ ///
+ /// Returns true (1) if there is any selected text.
+ ///
+ int(CEF_CALLBACK* has_selection)(struct _cef_textfield_t* self);
+
+ ///
+ /// Returns the currently selected text.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_selected_text)(
+ struct _cef_textfield_t* self);
+
+ ///
+ /// Selects all text. If |reversed| is true (1) the range will end at the
+ /// logical beginning of the text; this generally shows the leading portion of
+ /// text that overflows its display area.
+ ///
+ void(CEF_CALLBACK* select_all)(struct _cef_textfield_t* self, int reversed);
+
+ ///
+ /// Clears the text selection and sets the caret to the end.
+ ///
+ void(CEF_CALLBACK* clear_selection)(struct _cef_textfield_t* self);
+
+ ///
+ /// Returns the selected logical text range.
+ ///
+ cef_range_t(CEF_CALLBACK* get_selected_range)(struct _cef_textfield_t* self);
+
+ ///
+ /// Selects the specified logical text range.
+ ///
+ void(CEF_CALLBACK* select_range)(struct _cef_textfield_t* self,
+ const cef_range_t* range);
+
+ ///
+ /// Returns the current cursor position.
+ ///
+ size_t(CEF_CALLBACK* get_cursor_position)(struct _cef_textfield_t* self);
+
+ ///
+ /// Sets the text color.
+ ///
+ void(CEF_CALLBACK* set_text_color)(struct _cef_textfield_t* self,
+ cef_color_t color);
+
+ ///
+ /// Returns the text color.
+ ///
+ cef_color_t(CEF_CALLBACK* get_text_color)(struct _cef_textfield_t* self);
+
+ ///
+ /// Sets the selection text color.
+ ///
+ void(CEF_CALLBACK* set_selection_text_color)(struct _cef_textfield_t* self,
+ cef_color_t color);
+
+ ///
+ /// Returns the selection text color.
+ ///
+ cef_color_t(CEF_CALLBACK* get_selection_text_color)(
+ struct _cef_textfield_t* self);
+
+ ///
+ /// Sets the selection background color.
+ ///
+ void(CEF_CALLBACK* set_selection_background_color)(
+ struct _cef_textfield_t* self,
+ cef_color_t color);
+
+ ///
+ /// Returns the selection background color.
+ ///
+ cef_color_t(CEF_CALLBACK* get_selection_background_color)(
+ struct _cef_textfield_t* self);
+
+ ///
+ /// Sets the font list. The format is "<FONT_FAMILY_LIST>,[STYLES] <SIZE>",
+ /// where: - FONT_FAMILY_LIST is a comma-separated list of font family names,
+ /// - STYLES is an optional space-separated list of style names (case-
+ /// sensitive
+ /// "Bold" and "Italic" are supported), and
+ /// - SIZE is an integer font size in pixels with the suffix "px".
+ ///
+ /// Here are examples of valid font description strings: - "Arial, Helvetica,
+ /// Bold Italic 14px" - "Arial, 14px"
+ ///
+ void(CEF_CALLBACK* set_font_list)(struct _cef_textfield_t* self,
+ const cef_string_t* font_list);
+
+ ///
+ /// Applies |color| to the specified |range| without changing the default
+ /// color. If |range| is NULL the color will be set on the complete text
+ /// contents.
+ ///
+ void(CEF_CALLBACK* apply_text_color)(struct _cef_textfield_t* self,
+ cef_color_t color,
+ const cef_range_t* range);
+
+ ///
+ /// Applies |style| to the specified |range| without changing the default
+ /// style. If |add| is true (1) the style will be added, otherwise the style
+ /// will be removed. If |range| is NULL the style will be set on the complete
+ /// text contents.
+ ///
+ void(CEF_CALLBACK* apply_text_style)(struct _cef_textfield_t* self,
+ cef_text_style_t style,
+ int add,
+ const cef_range_t* range);
+
+ ///
+ /// Returns true (1) if the action associated with the specified command id is
+ /// enabled. See additional comments on execute_command().
+ ///
+ int(CEF_CALLBACK* is_command_enabled)(struct _cef_textfield_t* self,
+ cef_text_field_commands_t command_id);
+
+ ///
+ /// Performs the action associated with the specified command id.
+ ///
+ void(CEF_CALLBACK* execute_command)(struct _cef_textfield_t* self,
+ cef_text_field_commands_t command_id);
+
+ ///
+ /// Clears Edit history.
+ ///
+ void(CEF_CALLBACK* clear_edit_history)(struct _cef_textfield_t* self);
+
+ ///
+ /// Sets the placeholder text that will be displayed when the Textfield is
+ /// NULL.
+ ///
+ void(CEF_CALLBACK* set_placeholder_text)(struct _cef_textfield_t* self,
+ const cef_string_t* text);
+
+ ///
+ /// Returns the placeholder text that will be displayed when the Textfield is
+ /// NULL.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_placeholder_text)(
+ struct _cef_textfield_t* self);
+
+ ///
+ /// Sets the placeholder text color.
+ ///
+ void(CEF_CALLBACK* set_placeholder_text_color)(struct _cef_textfield_t* self,
+ cef_color_t color);
+
+ ///
+ /// Set the accessible name that will be exposed to assistive technology (AT).
+ ///
+ void(CEF_CALLBACK* set_accessible_name)(struct _cef_textfield_t* self,
+ const cef_string_t* name);
+} cef_textfield_t;
+
+///
+/// Create a new Textfield.
+///
+CEF_EXPORT cef_textfield_t* cef_textfield_create(
+ struct _cef_textfield_delegate_t* delegate);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_VIEWS_CEF_TEXTFIELD_CAPI_H_
diff --git a/include/capi/views/cef_textfield_delegate_capi.h b/include/capi/views/cef_textfield_delegate_capi.h
new file mode 100644
index 00000000..a14c0bfe
--- /dev/null
+++ b/include/capi/views/cef_textfield_delegate_capi.h
@@ -0,0 +1,83 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=482b091326684014bd799fef864e3dfdfc8693a1$
+//
+
+#ifndef CEF_INCLUDE_CAPI_VIEWS_CEF_TEXTFIELD_DELEGATE_CAPI_H_
+#define CEF_INCLUDE_CAPI_VIEWS_CEF_TEXTFIELD_DELEGATE_CAPI_H_
+#pragma once
+
+#include "include/capi/views/cef_view_delegate_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _cef_textfield_t;
+
+///
+/// Implement this structure to handle Textfield events. The functions of this
+/// structure will be called on the browser process UI thread unless otherwise
+/// indicated.
+///
+typedef struct _cef_textfield_delegate_t {
+ ///
+ /// Base structure.
+ ///
+ cef_view_delegate_t base;
+
+ ///
+ /// Called when |textfield| recieves a keyboard event. |event| contains
+ /// information about the keyboard event. Return true (1) if the keyboard
+ /// event was handled or false (0) otherwise for default handling.
+ ///
+ int(CEF_CALLBACK* on_key_event)(struct _cef_textfield_delegate_t* self,
+ struct _cef_textfield_t* textfield,
+ const cef_key_event_t* event);
+
+ ///
+ /// Called after performing a user action that may change |textfield|.
+ ///
+ void(CEF_CALLBACK* on_after_user_action)(
+ struct _cef_textfield_delegate_t* self,
+ struct _cef_textfield_t* textfield);
+} cef_textfield_delegate_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_VIEWS_CEF_TEXTFIELD_DELEGATE_CAPI_H_
diff --git a/include/capi/views/cef_view_capi.h b/include/capi/views/cef_view_capi.h
new file mode 100644
index 00000000..5372f61f
--- /dev/null
+++ b/include/capi/views/cef_view_capi.h
@@ -0,0 +1,413 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=cb5950b283944d06312903eb554cc4c980713e98$
+//
+
+#ifndef CEF_INCLUDE_CAPI_VIEWS_CEF_VIEW_CAPI_H_
+#define CEF_INCLUDE_CAPI_VIEWS_CEF_VIEW_CAPI_H_
+#pragma once
+
+#include "include/capi/views/cef_view_delegate_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _cef_browser_view_t;
+struct _cef_button_t;
+struct _cef_panel_t;
+struct _cef_scroll_view_t;
+struct _cef_textfield_t;
+struct _cef_window_t;
+
+///
+/// A View is a rectangle within the views View hierarchy. It is the base
+/// structure for all Views. All size and position values are in density
+/// independent pixels (DIP) unless otherwise indicated. Methods must be called
+/// on the browser process UI thread unless otherwise indicated.
+///
+typedef struct _cef_view_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Returns this View as a BrowserView or NULL if this is not a BrowserView.
+ ///
+ struct _cef_browser_view_t*(CEF_CALLBACK* as_browser_view)(
+ struct _cef_view_t* self);
+
+ ///
+ /// Returns this View as a Button or NULL if this is not a Button.
+ ///
+ struct _cef_button_t*(CEF_CALLBACK* as_button)(struct _cef_view_t* self);
+
+ ///
+ /// Returns this View as a Panel or NULL if this is not a Panel.
+ ///
+ struct _cef_panel_t*(CEF_CALLBACK* as_panel)(struct _cef_view_t* self);
+
+ ///
+ /// Returns this View as a ScrollView or NULL if this is not a ScrollView.
+ ///
+ struct _cef_scroll_view_t*(CEF_CALLBACK* as_scroll_view)(
+ struct _cef_view_t* self);
+
+ ///
+ /// Returns this View as a Textfield or NULL if this is not a Textfield.
+ ///
+ struct _cef_textfield_t*(CEF_CALLBACK* as_textfield)(
+ struct _cef_view_t* self);
+
+ ///
+ /// Returns the type of this View as a string. Used primarily for testing
+ /// purposes.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_type_string)(
+ struct _cef_view_t* self);
+
+ ///
+ /// Returns a string representation of this View which includes the type and
+ /// various type-specific identifying attributes. If |include_children| is
+ /// true (1) any child Views will also be included. Used primarily for testing
+ /// purposes.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* to_string)(struct _cef_view_t* self,
+ int include_children);
+
+ ///
+ /// Returns true (1) if this View is valid.
+ ///
+ int(CEF_CALLBACK* is_valid)(struct _cef_view_t* self);
+
+ ///
+ /// Returns true (1) if this View is currently attached to another View. A
+ /// View can only be attached to one View at a time.
+ ///
+ int(CEF_CALLBACK* is_attached)(struct _cef_view_t* self);
+
+ ///
+ /// Returns true (1) if this View is the same as |that| View.
+ ///
+ int(CEF_CALLBACK* is_same)(struct _cef_view_t* self,
+ struct _cef_view_t* that);
+
+ ///
+ /// Returns the delegate associated with this View, if any.
+ ///
+ struct _cef_view_delegate_t*(CEF_CALLBACK* get_delegate)(
+ struct _cef_view_t* self);
+
+ ///
+ /// Returns the top-level Window hosting this View, if any.
+ ///
+ struct _cef_window_t*(CEF_CALLBACK* get_window)(struct _cef_view_t* self);
+
+ ///
+ /// Returns the ID for this View.
+ ///
+ int(CEF_CALLBACK* get_id)(struct _cef_view_t* self);
+
+ ///
+ /// Sets the ID for this View. ID should be unique within the subtree that you
+ /// intend to search for it. 0 is the default ID for views.
+ ///
+ void(CEF_CALLBACK* set_id)(struct _cef_view_t* self, int id);
+
+ ///
+ /// Returns the group id of this View, or -1 if not set.
+ ///
+ int(CEF_CALLBACK* get_group_id)(struct _cef_view_t* self);
+
+ ///
+ /// A group id is used to tag Views which are part of the same logical group.
+ /// Focus can be moved between views with the same group using the arrow keys.
+ /// The group id is immutable once it's set.
+ ///
+ void(CEF_CALLBACK* set_group_id)(struct _cef_view_t* self, int group_id);
+
+ ///
+ /// Returns the View that contains this View, if any.
+ ///
+ struct _cef_view_t*(CEF_CALLBACK* get_parent_view)(struct _cef_view_t* self);
+
+ ///
+ /// Recursively descends the view tree starting at this View, and returns the
+ /// first child that it encounters with the given ID. Returns NULL if no
+ /// matching child view is found.
+ ///
+ struct _cef_view_t*(CEF_CALLBACK* get_view_for_id)(struct _cef_view_t* self,
+ int id);
+
+ ///
+ /// Sets the bounds (size and position) of this View. |bounds| is in parent
+ /// coordinates, or DIP screen coordinates if there is no parent.
+ ///
+ void(CEF_CALLBACK* set_bounds)(struct _cef_view_t* self,
+ const cef_rect_t* bounds);
+
+ ///
+ /// Returns the bounds (size and position) of this View in parent coordinates,
+ /// or DIP screen coordinates if there is no parent.
+ ///
+ cef_rect_t(CEF_CALLBACK* get_bounds)(struct _cef_view_t* self);
+
+ ///
+ /// Returns the bounds (size and position) of this View in DIP screen
+ /// coordinates.
+ ///
+ cef_rect_t(CEF_CALLBACK* get_bounds_in_screen)(struct _cef_view_t* self);
+
+ ///
+ /// Sets the size of this View without changing the position. |size| in parent
+ /// coordinates, or DIP screen coordinates if there is no parent.
+ ///
+ void(CEF_CALLBACK* set_size)(struct _cef_view_t* self,
+ const cef_size_t* size);
+
+ ///
+ /// Returns the size of this View in parent coordinates, or DIP screen
+ /// coordinates if there is no parent.
+ ///
+ cef_size_t(CEF_CALLBACK* get_size)(struct _cef_view_t* self);
+
+ ///
+ /// Sets the position of this View without changing the size. |position| is in
+ /// parent coordinates, or DIP screen coordinates if there is no parent.
+ ///
+ void(CEF_CALLBACK* set_position)(struct _cef_view_t* self,
+ const cef_point_t* position);
+
+ ///
+ /// Returns the position of this View. Position is in parent coordinates, or
+ /// DIP screen coordinates if there is no parent.
+ ///
+ cef_point_t(CEF_CALLBACK* get_position)(struct _cef_view_t* self);
+
+ ///
+ /// Sets the insets for this View. |insets| is in parent coordinates, or DIP
+ /// screen coordinates if there is no parent.
+ ///
+ void(CEF_CALLBACK* set_insets)(struct _cef_view_t* self,
+ const cef_insets_t* insets);
+
+ ///
+ /// Returns the insets for this View in parent coordinates, or DIP screen
+ /// coordinates if there is no parent.
+ ///
+ cef_insets_t(CEF_CALLBACK* get_insets)(struct _cef_view_t* self);
+
+ ///
+ /// Returns the size this View would like to be if enough space is available.
+ /// Size is in parent coordinates, or DIP screen coordinates if there is no
+ /// parent.
+ ///
+ cef_size_t(CEF_CALLBACK* get_preferred_size)(struct _cef_view_t* self);
+
+ ///
+ /// Size this View to its preferred size. Size is in parent coordinates, or
+ /// DIP screen coordinates if there is no parent.
+ ///
+ void(CEF_CALLBACK* size_to_preferred_size)(struct _cef_view_t* self);
+
+ ///
+ /// Returns the minimum size for this View. Size is in parent coordinates, or
+ /// DIP screen coordinates if there is no parent.
+ ///
+ cef_size_t(CEF_CALLBACK* get_minimum_size)(struct _cef_view_t* self);
+
+ ///
+ /// Returns the maximum size for this View. Size is in parent coordinates, or
+ /// DIP screen coordinates if there is no parent.
+ ///
+ cef_size_t(CEF_CALLBACK* get_maximum_size)(struct _cef_view_t* self);
+
+ ///
+ /// Returns the height necessary to display this View with the provided width.
+ ///
+ int(CEF_CALLBACK* get_height_for_width)(struct _cef_view_t* self, int width);
+
+ ///
+ /// Indicate that this View and all parent Views require a re-layout. This
+ /// ensures the next call to layout() will propagate to this View even if the
+ /// bounds of parent Views do not change.
+ ///
+ void(CEF_CALLBACK* invalidate_layout)(struct _cef_view_t* self);
+
+ ///
+ /// Sets whether this View is visible. Windows are hidden by default and other
+ /// views are visible by default. This View and any parent views must be set
+ /// as visible for this View to be drawn in a Window. If this View is set as
+ /// hidden then it and any child views will not be drawn and, if any of those
+ /// views currently have focus, then focus will also be cleared. Painting is
+ /// scheduled as needed. If this View is a Window then calling this function
+ /// is equivalent to calling the Window show() and hide() functions.
+ ///
+ void(CEF_CALLBACK* set_visible)(struct _cef_view_t* self, int visible);
+
+ ///
+ /// Returns whether this View is visible. A view may be visible but still not
+ /// drawn in a Window if any parent views are hidden. If this View is a Window
+ /// then a return value of true (1) indicates that this Window is currently
+ /// visible to the user on-screen. If this View is not a Window then call
+ /// is_drawn() to determine whether this View and all parent views are visible
+ /// and will be drawn.
+ ///
+ int(CEF_CALLBACK* is_visible)(struct _cef_view_t* self);
+
+ ///
+ /// Returns whether this View is visible and drawn in a Window. A view is
+ /// drawn if it and all parent views are visible. If this View is a Window
+ /// then calling this function is equivalent to calling is_visible().
+ /// Otherwise, to determine if the containing Window is visible to the user
+ /// on-screen call is_visible() on the Window.
+ ///
+ int(CEF_CALLBACK* is_drawn)(struct _cef_view_t* self);
+
+ ///
+ /// Set whether this View is enabled. A disabled View does not receive
+ /// keyboard or mouse inputs. If |enabled| differs from the current value the
+ /// View will be repainted. Also, clears focus if the focused View is
+ /// disabled.
+ ///
+ void(CEF_CALLBACK* set_enabled)(struct _cef_view_t* self, int enabled);
+
+ ///
+ /// Returns whether this View is enabled.
+ ///
+ int(CEF_CALLBACK* is_enabled)(struct _cef_view_t* self);
+
+ ///
+ /// Sets whether this View is capable of taking focus. It will clear focus if
+ /// the focused View is set to be non-focusable. This is false (0) by default
+ /// so that a View used as a container does not get the focus.
+ ///
+ void(CEF_CALLBACK* set_focusable)(struct _cef_view_t* self, int focusable);
+
+ ///
+ /// Returns true (1) if this View is focusable, enabled and drawn.
+ ///
+ int(CEF_CALLBACK* is_focusable)(struct _cef_view_t* self);
+
+ ///
+ /// Return whether this View is focusable when the user requires full keyboard
+ /// access, even though it may not be normally focusable.
+ ///
+ int(CEF_CALLBACK* is_accessibility_focusable)(struct _cef_view_t* self);
+
+ ///
+ /// Request keyboard focus. If this View is focusable it will become the
+ /// focused View.
+ ///
+ void(CEF_CALLBACK* request_focus)(struct _cef_view_t* self);
+
+ ///
+ /// Sets the background color for this View.
+ ///
+ void(CEF_CALLBACK* set_background_color)(struct _cef_view_t* self,
+ cef_color_t color);
+
+ ///
+ /// Returns the background color for this View.
+ ///
+ cef_color_t(CEF_CALLBACK* get_background_color)(struct _cef_view_t* self);
+
+ ///
+ /// Convert |point| from this View's coordinate system to DIP screen
+ /// coordinates. This View must belong to a Window when calling this function.
+ /// Returns true (1) if the conversion is successful or false (0) otherwise.
+ /// Use cef_display_t::convert_point_to_pixels() after calling this function
+ /// if further conversion to display-specific pixel coordinates is desired.
+ ///
+ int(CEF_CALLBACK* convert_point_to_screen)(struct _cef_view_t* self,
+ cef_point_t* point);
+
+ ///
+ /// Convert |point| to this View's coordinate system from DIP screen
+ /// coordinates. This View must belong to a Window when calling this function.
+ /// Returns true (1) if the conversion is successful or false (0) otherwise.
+ /// Use cef_display_t::convert_point_from_pixels() before calling this
+ /// function if conversion from display-specific pixel coordinates is
+ /// necessary.
+ ///
+ int(CEF_CALLBACK* convert_point_from_screen)(struct _cef_view_t* self,
+ cef_point_t* point);
+
+ ///
+ /// Convert |point| from this View's coordinate system to that of the Window.
+ /// This View must belong to a Window when calling this function. Returns true
+ /// (1) if the conversion is successful or false (0) otherwise.
+ ///
+ int(CEF_CALLBACK* convert_point_to_window)(struct _cef_view_t* self,
+ cef_point_t* point);
+
+ ///
+ /// Convert |point| to this View's coordinate system from that of the Window.
+ /// This View must belong to a Window when calling this function. Returns true
+ /// (1) if the conversion is successful or false (0) otherwise.
+ ///
+ int(CEF_CALLBACK* convert_point_from_window)(struct _cef_view_t* self,
+ cef_point_t* point);
+
+ ///
+ /// Convert |point| from this View's coordinate system to that of |view|.
+ /// |view| needs to be in the same Window but not necessarily the same view
+ /// hierarchy. Returns true (1) if the conversion is successful or false (0)
+ /// otherwise.
+ ///
+ int(CEF_CALLBACK* convert_point_to_view)(struct _cef_view_t* self,
+ struct _cef_view_t* view,
+ cef_point_t* point);
+
+ ///
+ /// Convert |point| to this View's coordinate system from that |view|. |view|
+ /// needs to be in the same Window but not necessarily the same view
+ /// hierarchy. Returns true (1) if the conversion is successful or false (0)
+ /// otherwise.
+ ///
+ int(CEF_CALLBACK* convert_point_from_view)(struct _cef_view_t* self,
+ struct _cef_view_t* view,
+ cef_point_t* point);
+} cef_view_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_VIEWS_CEF_VIEW_CAPI_H_
diff --git a/include/capi/views/cef_view_delegate_capi.h b/include/capi/views/cef_view_delegate_capi.h
new file mode 100644
index 00000000..4f4b8f01
--- /dev/null
+++ b/include/capi/views/cef_view_delegate_capi.h
@@ -0,0 +1,149 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=70646cb55b5bf98ccfa2a93b2cf57bd5ba367268$
+//
+
+#ifndef CEF_INCLUDE_CAPI_VIEWS_CEF_VIEW_DELEGATE_CAPI_H_
+#define CEF_INCLUDE_CAPI_VIEWS_CEF_VIEW_DELEGATE_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _cef_view_t;
+
+///
+/// Implement this structure to handle view events. All size and position values
+/// are in density independent pixels (DIP) unless otherwise indicated. The
+/// functions of this structure will be called on the browser process UI thread
+/// unless otherwise indicated.
+///
+typedef struct _cef_view_delegate_t {
+ ///
+ /// Base structure.
+ ///
+ cef_base_ref_counted_t base;
+
+ ///
+ /// Return the preferred size for |view|. The Layout will use this information
+ /// to determine the display size.
+ ///
+ cef_size_t(CEF_CALLBACK* get_preferred_size)(
+ struct _cef_view_delegate_t* self,
+ struct _cef_view_t* view);
+
+ ///
+ /// Return the minimum size for |view|.
+ ///
+ cef_size_t(CEF_CALLBACK* get_minimum_size)(struct _cef_view_delegate_t* self,
+ struct _cef_view_t* view);
+
+ ///
+ /// Return the maximum size for |view|.
+ ///
+ cef_size_t(CEF_CALLBACK* get_maximum_size)(struct _cef_view_delegate_t* self,
+ struct _cef_view_t* view);
+
+ ///
+ /// Return the height necessary to display |view| with the provided |width|.
+ /// If not specified the result of get_preferred_size().height will be used by
+ /// default. Override if |view|'s preferred height depends upon the width (for
+ /// example, with Labels).
+ ///
+ int(CEF_CALLBACK* get_height_for_width)(struct _cef_view_delegate_t* self,
+ struct _cef_view_t* view,
+ int width);
+
+ ///
+ /// Called when the parent of |view| has changed. If |view| is being added to
+ /// |parent| then |added| will be true (1). If |view| is being removed from
+ /// |parent| then |added| will be false (0). If |view| is being reparented the
+ /// remove notification will be sent before the add notification. Do not
+ /// modify the view hierarchy in this callback.
+ ///
+ void(CEF_CALLBACK* on_parent_view_changed)(struct _cef_view_delegate_t* self,
+ struct _cef_view_t* view,
+ int added,
+ struct _cef_view_t* parent);
+
+ ///
+ /// Called when a child of |view| has changed. If |child| is being added to
+ /// |view| then |added| will be true (1). If |child| is being removed from
+ /// |view| then |added| will be false (0). If |child| is being reparented the
+ /// remove notification will be sent to the old parent before the add
+ /// notification is sent to the new parent. Do not modify the view hierarchy
+ /// in this callback.
+ ///
+ void(CEF_CALLBACK* on_child_view_changed)(struct _cef_view_delegate_t* self,
+ struct _cef_view_t* view,
+ int added,
+ struct _cef_view_t* child);
+
+ ///
+ /// Called when |view| is added or removed from the cef_window_t.
+ ///
+ void(CEF_CALLBACK* on_window_changed)(struct _cef_view_delegate_t* self,
+ struct _cef_view_t* view,
+ int added);
+
+ ///
+ /// Called when the layout of |view| has changed.
+ ///
+ void(CEF_CALLBACK* on_layout_changed)(struct _cef_view_delegate_t* self,
+ struct _cef_view_t* view,
+ const cef_rect_t* new_bounds);
+
+ ///
+ /// Called when |view| gains focus.
+ ///
+ void(CEF_CALLBACK* on_focus)(struct _cef_view_delegate_t* self,
+ struct _cef_view_t* view);
+
+ ///
+ /// Called when |view| loses focus.
+ ///
+ void(CEF_CALLBACK* on_blur)(struct _cef_view_delegate_t* self,
+ struct _cef_view_t* view);
+} cef_view_delegate_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_VIEWS_CEF_VIEW_DELEGATE_CAPI_H_
diff --git a/include/capi/views/cef_window_capi.h b/include/capi/views/cef_window_capi.h
new file mode 100644
index 00000000..912e4ba6
--- /dev/null
+++ b/include/capi/views/cef_window_capi.h
@@ -0,0 +1,349 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=04aa6e193cc5d5658c0ef28a42c0777c0a955409$
+//
+
+#ifndef CEF_INCLUDE_CAPI_VIEWS_CEF_WINDOW_CAPI_H_
+#define CEF_INCLUDE_CAPI_VIEWS_CEF_WINDOW_CAPI_H_
+#pragma once
+
+#include "include/capi/cef_image_capi.h"
+#include "include/capi/cef_menu_model_capi.h"
+#include "include/capi/views/cef_display_capi.h"
+#include "include/capi/views/cef_overlay_controller_capi.h"
+#include "include/capi/views/cef_panel_capi.h"
+#include "include/capi/views/cef_window_delegate_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// A Window is a top-level Window/widget in the Views hierarchy. By default it
+/// will have a non-client area with title bar, icon and buttons that supports
+/// moving and resizing. All size and position values are in density independent
+/// pixels (DIP) unless otherwise indicated. Methods must be called on the
+/// browser process UI thread unless otherwise indicated.
+///
+typedef struct _cef_window_t {
+ ///
+ /// Base structure.
+ ///
+ cef_panel_t base;
+
+ ///
+ /// Show the Window.
+ ///
+ void(CEF_CALLBACK* show)(struct _cef_window_t* self);
+
+ ///
+ /// Hide the Window.
+ ///
+ void(CEF_CALLBACK* hide)(struct _cef_window_t* self);
+
+ ///
+ /// Sizes the Window to |size| and centers it in the current display.
+ ///
+ void(CEF_CALLBACK* center_window)(struct _cef_window_t* self,
+ const cef_size_t* size);
+
+ ///
+ /// Close the Window.
+ ///
+ void(CEF_CALLBACK* close)(struct _cef_window_t* self);
+
+ ///
+ /// Returns true (1) if the Window has been closed.
+ ///
+ int(CEF_CALLBACK* is_closed)(struct _cef_window_t* self);
+
+ ///
+ /// Activate the Window, assuming it already exists and is visible.
+ ///
+ void(CEF_CALLBACK* activate)(struct _cef_window_t* self);
+
+ ///
+ /// Deactivate the Window, making the next Window in the Z order the active
+ /// Window.
+ ///
+ void(CEF_CALLBACK* deactivate)(struct _cef_window_t* self);
+
+ ///
+ /// Returns whether the Window is the currently active Window.
+ ///
+ int(CEF_CALLBACK* is_active)(struct _cef_window_t* self);
+
+ ///
+ /// Bring this Window to the top of other Windows in the Windowing system.
+ ///
+ void(CEF_CALLBACK* bring_to_top)(struct _cef_window_t* self);
+
+ ///
+ /// Set the Window to be on top of other Windows in the Windowing system.
+ ///
+ void(CEF_CALLBACK* set_always_on_top)(struct _cef_window_t* self, int on_top);
+
+ ///
+ /// Returns whether the Window has been set to be on top of other Windows in
+ /// the Windowing system.
+ ///
+ int(CEF_CALLBACK* is_always_on_top)(struct _cef_window_t* self);
+
+ ///
+ /// Maximize the Window.
+ ///
+ void(CEF_CALLBACK* maximize)(struct _cef_window_t* self);
+
+ ///
+ /// Minimize the Window.
+ ///
+ void(CEF_CALLBACK* minimize)(struct _cef_window_t* self);
+
+ ///
+ /// Restore the Window.
+ ///
+ void(CEF_CALLBACK* restore)(struct _cef_window_t* self);
+
+ ///
+ /// Set fullscreen Window state.
+ ///
+ void(CEF_CALLBACK* set_fullscreen)(struct _cef_window_t* self,
+ int fullscreen);
+
+ ///
+ /// Returns true (1) if the Window is maximized.
+ ///
+ int(CEF_CALLBACK* is_maximized)(struct _cef_window_t* self);
+
+ ///
+ /// Returns true (1) if the Window is minimized.
+ ///
+ int(CEF_CALLBACK* is_minimized)(struct _cef_window_t* self);
+
+ ///
+ /// Returns true (1) if the Window is fullscreen.
+ ///
+ int(CEF_CALLBACK* is_fullscreen)(struct _cef_window_t* self);
+
+ ///
+ /// Set the Window title.
+ ///
+ void(CEF_CALLBACK* set_title)(struct _cef_window_t* self,
+ const cef_string_t* title);
+
+ ///
+ /// Get the Window title.
+ ///
+ // The resulting string must be freed by calling cef_string_userfree_free().
+ cef_string_userfree_t(CEF_CALLBACK* get_title)(struct _cef_window_t* self);
+
+ ///
+ /// Set the Window icon. This should be a 16x16 icon suitable for use in the
+ /// Windows's title bar.
+ ///
+ void(CEF_CALLBACK* set_window_icon)(struct _cef_window_t* self,
+ struct _cef_image_t* image);
+
+ ///
+ /// Get the Window icon.
+ ///
+ struct _cef_image_t*(CEF_CALLBACK* get_window_icon)(
+ struct _cef_window_t* self);
+
+ ///
+ /// Set the Window App icon. This should be a larger icon for use in the host
+ /// environment app switching UI. On Windows, this is the ICON_BIG used in
+ /// Alt-Tab list and Windows taskbar. The Window icon will be used by default
+ /// if no Window App icon is specified.
+ ///
+ void(CEF_CALLBACK* set_window_app_icon)(struct _cef_window_t* self,
+ struct _cef_image_t* image);
+
+ ///
+ /// Get the Window App icon.
+ ///
+ struct _cef_image_t*(CEF_CALLBACK* get_window_app_icon)(
+ struct _cef_window_t* self);
+
+ ///
+ /// Add a View that will be overlayed on the Window contents with absolute
+ /// positioning and high z-order. Positioning is controlled by |docking_mode|
+ /// as described below. The returned cef_overlay_controller_t object is used
+ /// to control the overlay. Overlays are hidden by default.
+ ///
+ /// With CEF_DOCKING_MODE_CUSTOM:
+ /// 1. The overlay is initially hidden, sized to |view|'s preferred size,
+ /// and positioned in the top-left corner.
+ /// 2. Optionally change the overlay position and/or size by calling
+ /// CefOverlayController methods.
+ /// 3. Call CefOverlayController::SetVisible(true) to show the overlay.
+ /// 4. The overlay will be automatically re-sized if |view|'s layout
+ /// changes. Optionally change the overlay position and/or size when
+ /// OnLayoutChanged is called on the Window's delegate to indicate a
+ /// change in Window bounds.
+ ///
+ /// With other docking modes:
+ /// 1. The overlay is initially hidden, sized to |view|'s preferred size,
+ /// and positioned based on |docking_mode|.
+ /// 2. Call CefOverlayController::SetVisible(true) to show the overlay.
+ /// 3. The overlay will be automatically re-sized if |view|'s layout changes
+ /// and re-positioned as appropriate when the Window resizes.
+ ///
+ /// Overlays created by this function will receive a higher z-order then any
+ /// child Views added previously. It is therefore recommended to call this
+ /// function last after all other child Views have been added so that the
+ /// overlay displays as the top-most child of the Window.
+ ///
+ struct _cef_overlay_controller_t*(CEF_CALLBACK* add_overlay_view)(
+ struct _cef_window_t* self,
+ struct _cef_view_t* view,
+ cef_docking_mode_t docking_mode);
+
+ ///
+ /// Show a menu with contents |menu_model|. |screen_point| specifies the menu
+ /// position in screen coordinates. |anchor_position| specifies how the menu
+ /// will be anchored relative to |screen_point|.
+ ///
+ void(CEF_CALLBACK* show_menu)(struct _cef_window_t* self,
+ struct _cef_menu_model_t* menu_model,
+ const cef_point_t* screen_point,
+ cef_menu_anchor_position_t anchor_position);
+
+ ///
+ /// Cancel the menu that is currently showing, if any.
+ ///
+ void(CEF_CALLBACK* cancel_menu)(struct _cef_window_t* self);
+
+ ///
+ /// Returns the Display that most closely intersects the bounds of this
+ /// Window. May return NULL if this Window is not currently displayed.
+ ///
+ struct _cef_display_t*(CEF_CALLBACK* get_display)(struct _cef_window_t* self);
+
+ ///
+ /// Returns the bounds (size and position) of this Window's client area.
+ /// Position is in screen coordinates.
+ ///
+ cef_rect_t(CEF_CALLBACK* get_client_area_bounds_in_screen)(
+ struct _cef_window_t* self);
+
+ ///
+ /// Set the regions where mouse events will be intercepted by this Window to
+ /// support drag operations. Call this function with an NULL vector to clear
+ /// the draggable regions. The draggable region bounds should be in window
+ /// coordinates.
+ ///
+ void(CEF_CALLBACK* set_draggable_regions)(
+ struct _cef_window_t* self,
+ size_t regionsCount,
+ cef_draggable_region_t const* regions);
+
+ ///
+ /// Retrieve the platform window handle for this Window.
+ ///
+ cef_window_handle_t(CEF_CALLBACK* get_window_handle)(
+ struct _cef_window_t* self);
+
+ ///
+ /// Simulate a key press. |key_code| is the VKEY_* value from Chromium's
+ /// ui/events/keycodes/keyboard_codes.h header (VK_* values on Windows).
+ /// |event_flags| is some combination of EVENTFLAG_SHIFT_DOWN,
+ /// EVENTFLAG_CONTROL_DOWN and/or EVENTFLAG_ALT_DOWN. This function is exposed
+ /// primarily for testing purposes.
+ ///
+ void(CEF_CALLBACK* send_key_press)(struct _cef_window_t* self,
+ int key_code,
+ uint32 event_flags);
+
+ ///
+ /// Simulate a mouse move. The mouse cursor will be moved to the specified
+ /// (screen_x, screen_y) position. This function is exposed primarily for
+ /// testing purposes.
+ ///
+ void(CEF_CALLBACK* send_mouse_move)(struct _cef_window_t* self,
+ int screen_x,
+ int screen_y);
+
+ ///
+ /// Simulate mouse down and/or mouse up events. |button| is the mouse button
+ /// type. If |mouse_down| is true (1) a mouse down event will be sent. If
+ /// |mouse_up| is true (1) a mouse up event will be sent. If both are true (1)
+ /// a mouse down event will be sent followed by a mouse up event (equivalent
+ /// to clicking the mouse button). The events will be sent using the current
+ /// cursor position so make sure to call send_mouse_move() first to position
+ /// the mouse. This function is exposed primarily for testing purposes.
+ ///
+ void(CEF_CALLBACK* send_mouse_events)(struct _cef_window_t* self,
+ cef_mouse_button_type_t button,
+ int mouse_down,
+ int mouse_up);
+
+ ///
+ /// Set the keyboard accelerator for the specified |command_id|. |key_code|
+ /// can be any virtual key or character value.
+ /// cef_window_delegate_t::OnAccelerator will be called if the keyboard
+ /// combination is triggered while this window has focus.
+ ///
+ void(CEF_CALLBACK* set_accelerator)(struct _cef_window_t* self,
+ int command_id,
+ int key_code,
+ int shift_pressed,
+ int ctrl_pressed,
+ int alt_pressed);
+
+ ///
+ /// Remove the keyboard accelerator for the specified |command_id|.
+ ///
+ void(CEF_CALLBACK* remove_accelerator)(struct _cef_window_t* self,
+ int command_id);
+
+ ///
+ /// Remove all keyboard accelerators.
+ ///
+ void(CEF_CALLBACK* remove_all_accelerators)(struct _cef_window_t* self);
+} cef_window_t;
+
+///
+/// Create a new Window.
+///
+CEF_EXPORT cef_window_t* cef_window_create_top_level(
+ struct _cef_window_delegate_t* delegate);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_VIEWS_CEF_WINDOW_CAPI_H_
diff --git a/include/capi/views/cef_window_delegate_capi.h b/include/capi/views/cef_window_delegate_capi.h
new file mode 100644
index 00000000..ce63b865
--- /dev/null
+++ b/include/capi/views/cef_window_delegate_capi.h
@@ -0,0 +1,207 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=9f0389a439e6787282880d53375369829adb6a3d$
+//
+
+#ifndef CEF_INCLUDE_CAPI_VIEWS_CEF_WINDOW_DELEGATE_CAPI_H_
+#define CEF_INCLUDE_CAPI_VIEWS_CEF_WINDOW_DELEGATE_CAPI_H_
+#pragma once
+
+#include "include/capi/views/cef_panel_delegate_capi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _cef_window_t;
+
+///
+/// Implement this structure to handle window events. The functions of this
+/// structure will be called on the browser process UI thread unless otherwise
+/// indicated.
+///
+typedef struct _cef_window_delegate_t {
+ ///
+ /// Base structure.
+ ///
+ cef_panel_delegate_t base;
+
+ ///
+ /// Called when |window| is created.
+ ///
+ void(CEF_CALLBACK* on_window_created)(struct _cef_window_delegate_t* self,
+ struct _cef_window_t* window);
+
+ ///
+ /// Called when |window| is closing.
+ ///
+ void(CEF_CALLBACK* on_window_closing)(struct _cef_window_delegate_t* self,
+ struct _cef_window_t* window);
+
+ ///
+ /// Called when |window| is destroyed. Release all references to |window| and
+ /// do not attempt to execute any functions on |window| after this callback
+ /// returns.
+ ///
+ void(CEF_CALLBACK* on_window_destroyed)(struct _cef_window_delegate_t* self,
+ struct _cef_window_t* window);
+
+ ///
+ /// Called when |window| is activated or deactivated.
+ ///
+ void(CEF_CALLBACK* on_window_activation_changed)(
+ struct _cef_window_delegate_t* self,
+ struct _cef_window_t* window,
+ int active);
+
+ ///
+ /// Called when |window| bounds have changed. |new_bounds| will be in DIP
+ /// screen coordinates.
+ ///
+ void(CEF_CALLBACK* on_window_bounds_changed)(
+ struct _cef_window_delegate_t* self,
+ struct _cef_window_t* window,
+ const cef_rect_t* new_bounds);
+
+ ///
+ /// Return the parent for |window| or NULL if the |window| does not have a
+ /// parent. Windows with parents will not get a taskbar button. Set |is_menu|
+ /// to true (1) if |window| will be displayed as a menu, in which case it will
+ /// not be clipped to the parent window bounds. Set |can_activate_menu| to
+ /// false (0) if |is_menu| is true (1) and |window| should not be activated
+ /// (given keyboard focus) when displayed.
+ ///
+ struct _cef_window_t*(CEF_CALLBACK* get_parent_window)(
+ struct _cef_window_delegate_t* self,
+ struct _cef_window_t* window,
+ int* is_menu,
+ int* can_activate_menu);
+
+ ///
+ /// Return the initial bounds for |window| in density independent pixel (DIP)
+ /// coordinates. If this function returns an NULL CefRect then
+ /// get_preferred_size() will be called to retrieve the size, and the window
+ /// will be placed on the screen with origin (0,0). This function can be used
+ /// in combination with cef_view_t::get_bounds_in_screen() to restore the
+ /// previous window bounds.
+ ///
+ cef_rect_t(CEF_CALLBACK* get_initial_bounds)(
+ struct _cef_window_delegate_t* self,
+ struct _cef_window_t* window);
+
+ ///
+ /// Return the initial show state for |window|.
+ ///
+ cef_show_state_t(CEF_CALLBACK* get_initial_show_state)(
+ struct _cef_window_delegate_t* self,
+ struct _cef_window_t* window);
+
+ ///
+ /// Return true (1) if |window| should be created without a frame or title
+ /// bar. The window will be resizable if can_resize() returns true (1). Use
+ /// cef_window_t::set_draggable_regions() to specify draggable regions.
+ ///
+ int(CEF_CALLBACK* is_frameless)(struct _cef_window_delegate_t* self,
+ struct _cef_window_t* window);
+
+ ///
+ /// Return true (1) if |window| should be created with standard window buttons
+ /// like close, minimize and zoom.
+ ///
+ int(CEF_CALLBACK* with_standard_window_buttons)(
+ struct _cef_window_delegate_t* self,
+ struct _cef_window_t* window);
+
+ ///
+ /// Return whether the titlebar height should be overridden, and sets the
+ /// height of the titlebar in |titlebar_height|. On macOS, it can also be used
+ /// to adjust the vertical position of the traffic light buttons in frameless
+ /// windows. The buttons will be positioned halfway down the titlebar at a
+ /// height of |titlebar_height| / 2.
+ ///
+ int(CEF_CALLBACK* get_titlebar_height)(struct _cef_window_delegate_t* self,
+ struct _cef_window_t* window,
+ float* titlebar_height);
+
+ ///
+ /// Return true (1) if |window| can be resized.
+ ///
+ int(CEF_CALLBACK* can_resize)(struct _cef_window_delegate_t* self,
+ struct _cef_window_t* window);
+
+ ///
+ /// Return true (1) if |window| can be maximized.
+ ///
+ int(CEF_CALLBACK* can_maximize)(struct _cef_window_delegate_t* self,
+ struct _cef_window_t* window);
+
+ ///
+ /// Return true (1) if |window| can be minimized.
+ ///
+ int(CEF_CALLBACK* can_minimize)(struct _cef_window_delegate_t* self,
+ struct _cef_window_t* window);
+
+ ///
+ /// Return true (1) if |window| can be closed. This will be called for user-
+ /// initiated window close actions and when cef_window_t::close() is called.
+ ///
+ int(CEF_CALLBACK* can_close)(struct _cef_window_delegate_t* self,
+ struct _cef_window_t* window);
+
+ ///
+ /// Called when a keyboard accelerator registered with
+ /// cef_window_t::SetAccelerator is triggered. Return true (1) if the
+ /// accelerator was handled or false (0) otherwise.
+ ///
+ int(CEF_CALLBACK* on_accelerator)(struct _cef_window_delegate_t* self,
+ struct _cef_window_t* window,
+ int command_id);
+
+ ///
+ /// Called after all other controls in the window have had a chance to handle
+ /// the event. |event| contains information about the keyboard event. Return
+ /// true (1) if the keyboard event was handled or false (0) otherwise.
+ ///
+ int(CEF_CALLBACK* on_key_event)(struct _cef_window_delegate_t* self,
+ struct _cef_window_t* window,
+ const cef_key_event_t* event);
+} cef_window_delegate_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_CAPI_VIEWS_CEF_WINDOW_DELEGATE_CAPI_H_
diff --git a/include/cef_accessibility_handler.h b/include/cef_accessibility_handler.h
new file mode 100644
index 00000000..2b1719a5
--- /dev/null
+++ b/include/cef_accessibility_handler.h
@@ -0,0 +1,66 @@
+// Copyright (c) 2017 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_ACCESSIBILITY_HANDLER_H_
+#define CEF_INCLUDE_CEF_ACCESSIBILITY_HANDLER_H_
+#pragma once
+
+#include "include/cef_values.h"
+
+///
+/// Implement this interface to receive accessibility notification when
+/// accessibility events have been registered. The methods of this class will
+/// be called on the UI thread.
+///
+/*--cef(source=client)--*/
+class CefAccessibilityHandler : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Called after renderer process sends accessibility tree changes to the
+ /// browser process.
+ ///
+ /*--cef()--*/
+ virtual void OnAccessibilityTreeChange(CefRefPtr<CefValue> value) = 0;
+
+ ///
+ /// Called after renderer process sends accessibility location changes to the
+ /// browser process.
+ ///
+ /*--cef()--*/
+ virtual void OnAccessibilityLocationChange(CefRefPtr<CefValue> value) = 0;
+};
+
+#endif // CEF_INCLUDE_CEF_ACCESSIBILITY_HANDLER_H_
diff --git a/include/cef_api_hash.h b/include/cef_api_hash.h
new file mode 100644
index 00000000..92ac9163
--- /dev/null
+++ b/include/cef_api_hash.h
@@ -0,0 +1,71 @@
+// Copyright (c) 2023 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the make_api_hash_header.py tool.
+//
+
+#ifndef CEF_INCLUDE_API_HASH_H_
+#define CEF_INCLUDE_API_HASH_H_
+
+#include "include/internal/cef_export.h"
+
+// The API hash is created by analyzing CEF header files for C API type
+// definitions. The hash value will change when header files are modified in a
+// way that may cause binary incompatibility with other builds. The universal
+// hash value will change if any platform is affected whereas the platform hash
+// values will change only if that particular platform is affected.
+#define CEF_API_HASH_UNIVERSAL "1d8347d8e06dc0dd17f882ca253e1c7bf43d5863"
+#if defined(OS_WIN)
+#define CEF_API_HASH_PLATFORM "b6865f1992a10dcefc0bbc450cf296b648003271"
+#elif defined(OS_MAC)
+#define CEF_API_HASH_PLATFORM "d04c2a5ab471493c185eb7c7aa894bc4a79d5a7c"
+#elif defined(OS_LINUX)
+#define CEF_API_HASH_PLATFORM "d7d4cbffa4a798fea97e7b9f3610b5cb803d949e"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+// Returns CEF API hashes for the libcef library. The returned string is owned
+// by the library and should not be freed. The |entry| parameter describes which
+// hash value will be returned:
+// 0 - CEF_API_HASH_PLATFORM
+// 1 - CEF_API_HASH_UNIVERSAL
+// 2 - CEF_COMMIT_HASH (from cef_version.h)
+///
+CEF_EXPORT const char* cef_api_hash(int entry);
+
+#ifdef __cplusplus
+}
+#endif
+#endif // CEF_INCLUDE_API_HASH_H_
diff --git a/include/cef_app.h b/include/cef_app.h
new file mode 100644
index 00000000..3591297c
--- /dev/null
+++ b/include/cef_app.h
@@ -0,0 +1,190 @@
+// Copyright (c) 2012 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_APP_H_
+#define CEF_INCLUDE_CEF_APP_H_
+#pragma once
+
+#include "include/cef_base.h"
+#include "include/cef_browser_process_handler.h"
+#include "include/cef_command_line.h"
+#include "include/cef_render_process_handler.h"
+#include "include/cef_resource_bundle_handler.h"
+#include "include/cef_scheme.h"
+
+class CefApp;
+
+///
+/// This function should be called from the application entry point function to
+/// execute a secondary process. It can be used to run secondary processes from
+/// the browser client executable (default behavior) or from a separate
+/// executable specified by the cef_settings_t.browser_subprocess_path value. If
+/// called for the browser process (identified by no "type" command-line value)
+/// it will return immediately with a value of -1. If called for a recognized
+/// secondary process it will block until the process should exit and then
+/// return the process exit code. The |application| parameter may be empty. The
+/// |windows_sandbox_info| parameter is only used on Windows and may be NULL
+/// (see cef_sandbox_win.h for details).
+///
+/*--cef(api_hash_check,optional_param=application,
+ optional_param=windows_sandbox_info)--*/
+int CefExecuteProcess(const CefMainArgs& args,
+ CefRefPtr<CefApp> application,
+ void* windows_sandbox_info);
+
+///
+/// This function should be called on the main application thread to initialize
+/// the CEF browser process. The |application| parameter may be empty. A return
+/// value of true indicates that it succeeded and false indicates that it
+/// failed. The |windows_sandbox_info| parameter is only used on Windows and may
+/// be NULL (see cef_sandbox_win.h for details).
+///
+/*--cef(api_hash_check,optional_param=application,
+ optional_param=windows_sandbox_info)--*/
+bool CefInitialize(const CefMainArgs& args,
+ const CefSettings& settings,
+ CefRefPtr<CefApp> application,
+ void* windows_sandbox_info);
+
+///
+/// This function should be called on the main application thread to shut down
+/// the CEF browser process before the application exits.
+///
+/*--cef()--*/
+void CefShutdown();
+
+///
+/// Perform a single iteration of CEF message loop processing. This function is
+/// provided for cases where the CEF message loop must be integrated into an
+/// existing application message loop. Use of this function is not recommended
+/// for most users; use either the CefRunMessageLoop() function or
+/// cef_settings_t.multi_threaded_message_loop if possible. When using this
+/// function care must be taken to balance performance against excessive CPU
+/// usage. It is recommended to enable the cef_settings_t.external_message_pump
+/// option when using this function so that
+/// CefBrowserProcessHandler::OnScheduleMessagePumpWork() callbacks can
+/// facilitate the scheduling process. This function should only be called on
+/// the main application thread and only if CefInitialize() is called with a
+/// cef_settings_t.multi_threaded_message_loop value of false. This function
+/// will not block.
+///
+/*--cef()--*/
+void CefDoMessageLoopWork();
+
+///
+/// Run the CEF message loop. Use this function instead of an application-
+/// provided message loop to get the best balance between performance and CPU
+/// usage. This function should only be called on the main application thread
+/// and only if CefInitialize() is called with a
+/// cef_settings_t.multi_threaded_message_loop value of false. This function
+/// will block until a quit message is received by the system.
+///
+/*--cef()--*/
+void CefRunMessageLoop();
+
+///
+/// Quit the CEF message loop that was started by calling CefRunMessageLoop().
+/// This function should only be called on the main application thread and only
+/// if CefRunMessageLoop() was used.
+///
+/*--cef()--*/
+void CefQuitMessageLoop();
+
+///
+/// Implement this interface to provide handler implementations. Methods will be
+/// called by the process and/or thread indicated.
+///
+/*--cef(source=client,no_debugct_check)--*/
+class CefApp : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Provides an opportunity to view and/or modify command-line arguments
+ /// before processing by CEF and Chromium. The |process_type| value will be
+ /// empty for the browser process. Do not keep a reference to the
+ /// CefCommandLine object passed to this method. The
+ /// cef_settings_t.command_line_args_disabled value can be used to start with
+ /// an empty command-line object. Any values specified in CefSettings that
+ /// equate to command-line arguments will be set before this method is called.
+ /// Be cautious when using this method to modify command-line arguments for
+ /// non-browser processes as this may result in undefined behavior including
+ /// crashes.
+ ///
+ /*--cef(optional_param=process_type)--*/
+ virtual void OnBeforeCommandLineProcessing(
+ const CefString& process_type,
+ CefRefPtr<CefCommandLine> command_line) {}
+
+ ///
+ /// Provides an opportunity to register custom schemes. Do not keep a
+ /// reference to the |registrar| object. This method is called on the main
+ /// thread for each process and the registered schemes should be the same
+ /// across all processes.
+ ///
+ /*--cef()--*/
+ virtual void OnRegisterCustomSchemes(
+ CefRawPtr<CefSchemeRegistrar> registrar) {}
+
+ ///
+ /// Return the handler for resource bundle events. If
+ /// cef_settings_t.pack_loading_disabled is true a handler must be returned.
+ /// If no handler is returned resources will be loaded from pack files. This
+ /// method is called by the browser and render processes on multiple threads.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefResourceBundleHandler> GetResourceBundleHandler() {
+ return nullptr;
+ }
+
+ ///
+ /// Return the handler for functionality specific to the browser process. This
+ /// method is called on multiple threads in the browser process.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefBrowserProcessHandler> GetBrowserProcessHandler() {
+ return nullptr;
+ }
+
+ ///
+ /// Return the handler for functionality specific to the render process. This
+ /// method is called on the render process main thread.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefRenderProcessHandler> GetRenderProcessHandler() {
+ return nullptr;
+ }
+};
+
+#endif // CEF_INCLUDE_CEF_APP_H_
diff --git a/include/cef_application_mac.h b/include/cef_application_mac.h
new file mode 100644
index 00000000..d4d69e9e
--- /dev/null
+++ b/include/cef_application_mac.h
@@ -0,0 +1,110 @@
+// Copyright (c) 2011 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CEF_INCLUDE_CEF_APPLICATION_MAC_H_
+#define CEF_INCLUDE_CEF_APPLICATION_MAC_H_
+#pragma once
+
+#ifdef __cplusplus
+#include "include/cef_base.h"
+#endif // __cplusplus
+
+#if defined(OS_MAC) && defined(__OBJC__)
+
+#ifdef USING_CHROMIUM_INCLUDES
+
+// Use the existing CrAppControlProtocol definition.
+#import "base/mac/scoped_sending_event.h"
+
+// Use the existing CrAppProtocol definition.
+#import "base/message_loop/message_pump_mac.h"
+
+// Use the existing UnderlayableSurface definition.
+#import "ui/base/cocoa/underlay_opengl_hosting_window.h"
+
+// Use the existing empty protocol definitions.
+#import "base/mac/cocoa_protocols.h"
+
+// Use the existing empty protocol definitions.
+#import "base/mac/sdk_forward_declarations.h"
+
+#else // USING_CHROMIUM_INCLUDES
+
+#import <AppKit/AppKit.h>
+#import <Cocoa/Cocoa.h>
+
+// Copy of definition from base/message_loop/message_pump_mac.h.
+@protocol CrAppProtocol
+// Must return true if -[NSApplication sendEvent:] is currently on the stack.
+- (BOOL)isHandlingSendEvent;
+@end
+
+// Copy of definition from base/mac/scoped_sending_event.h.
+@protocol CrAppControlProtocol <CrAppProtocol>
+- (void)setHandlingSendEvent:(BOOL)handlingSendEvent;
+@end
+
+// Copy of definition from ui/base/cocoa/underlay_opengl_hosting_window.h.
+// Common base class for windows that host a OpenGL surface that renders under
+// the window. Contains methods relating to hole punching so that the OpenGL
+// surface is visible through the window.
+@interface UnderlayOpenGLHostingWindow : NSWindow
+@end
+
+#endif // USING_CHROMIUM_INCLUDES
+
+// All CEF client applications must subclass NSApplication and implement this
+// protocol.
+@protocol CefAppProtocol <CrAppControlProtocol>
+@end
+
+#ifdef __cplusplus
+
+// Controls the state of |isHandlingSendEvent| in the event loop so that it is
+// reset properly.
+class CefScopedSendingEvent {
+ public:
+ CefScopedSendingEvent()
+ : app_(static_cast<NSApplication<CefAppProtocol>*>(
+ [NSApplication sharedApplication])),
+ handling_([app_ isHandlingSendEvent]) {
+ [app_ setHandlingSendEvent:YES];
+ }
+ ~CefScopedSendingEvent() { [app_ setHandlingSendEvent:handling_]; }
+
+ private:
+ NSApplication<CefAppProtocol>* app_;
+ BOOL handling_;
+};
+
+#endif // __cplusplus
+
+#endif // defined(OS_MAC) && defined(__OBJC__)
+
+#endif // CEF_INCLUDE_CEF_APPLICATION_MAC_H_
diff --git a/include/cef_audio_handler.h b/include/cef_audio_handler.h
new file mode 100644
index 00000000..680db384
--- /dev/null
+++ b/include/cef_audio_handler.h
@@ -0,0 +1,111 @@
+// Copyright (c) 2019 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_AUDIO_HANDLER_H_
+#define CEF_INCLUDE_CEF_AUDIO_HANDLER_H_
+#pragma once
+
+#include "include/cef_base.h"
+#include "include/cef_browser.h"
+
+///
+/// Implement this interface to handle audio events.
+///
+/*--cef(source=client)--*/
+class CefAudioHandler : public virtual CefBaseRefCounted {
+ public:
+ typedef cef_channel_layout_t ChannelLayout;
+
+ ///
+ /// Called on the UI thread to allow configuration of audio stream parameters.
+ /// Return true to proceed with audio stream capture, or false to cancel it.
+ /// All members of |params| can optionally be configured here, but they are
+ /// also pre-filled with some sensible defaults.
+ ///
+ /*--cef()--*/
+ virtual bool GetAudioParameters(CefRefPtr<CefBrowser> browser,
+ CefAudioParameters& params) {
+ return true;
+ }
+
+ ///
+ /// Called on a browser audio capture thread when the browser starts
+ /// streaming audio. OnAudioStreamStopped will always be called after
+ /// OnAudioStreamStarted; both methods may be called multiple times
+ /// for the same browser. |params| contains the audio parameters like
+ /// sample rate and channel layout. |channels| is the number of channels.
+ ///
+ /*--cef()--*/
+ virtual void OnAudioStreamStarted(CefRefPtr<CefBrowser> browser,
+ const CefAudioParameters& params,
+ int channels) = 0;
+
+ ///
+ /// Called on the audio stream thread when a PCM packet is received for the
+ /// stream. |data| is an array representing the raw PCM data as a floating
+ /// point type, i.e. 4-byte value(s). |frames| is the number of frames in the
+ /// PCM packet. |pts| is the presentation timestamp (in milliseconds since the
+ /// Unix Epoch) and represents the time at which the decompressed packet
+ /// should be presented to the user. Based on |frames| and the
+ /// |channel_layout| value passed to OnAudioStreamStarted you can calculate
+ /// the size of the |data| array in bytes.
+ ///
+ /*--cef()--*/
+ virtual void OnAudioStreamPacket(CefRefPtr<CefBrowser> browser,
+ const float** data,
+ int frames,
+ int64 pts) = 0;
+
+ ///
+ /// Called on the UI thread when the stream has stopped. OnAudioSteamStopped
+ /// will always be called after OnAudioStreamStarted; both methods may be
+ /// called multiple times for the same stream.
+ ///
+ /*--cef()--*/
+ virtual void OnAudioStreamStopped(CefRefPtr<CefBrowser> browser) = 0;
+
+ ///
+ /// Called on the UI or audio stream thread when an error occurred. During the
+ /// stream creation phase this callback will be called on the UI thread while
+ /// in the capturing phase it will be called on the audio stream thread. The
+ /// stream will be stopped immediately.
+ ///
+ /*--cef()--*/
+ virtual void OnAudioStreamError(CefRefPtr<CefBrowser> browser,
+ const CefString& message) = 0;
+};
+
+#endif // CEF_INCLUDE_CEF_AUDIO_HANDLER_H_
diff --git a/include/cef_auth_callback.h b/include/cef_auth_callback.h
new file mode 100644
index 00000000..3372a726
--- /dev/null
+++ b/include/cef_auth_callback.h
@@ -0,0 +1,64 @@
+// Copyright (c) 2013 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_AUTH_CALLBACK_H_
+#define CEF_INCLUDE_CEF_AUTH_CALLBACK_H_
+#pragma once
+
+#include "include/cef_base.h"
+
+///
+/// Callback interface used for asynchronous continuation of authentication
+/// requests.
+///
+/*--cef(source=library)--*/
+class CefAuthCallback : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Continue the authentication request.
+ ///
+ /*--cef(capi_name=cont,optional_param=username,optional_param=password)--*/
+ virtual void Continue(const CefString& username,
+ const CefString& password) = 0;
+
+ ///
+ /// Cancel the authentication request.
+ ///
+ /*--cef()--*/
+ virtual void Cancel() = 0;
+};
+
+#endif // CEF_INCLUDE_CEF_AUTH_CALLBACK_H_
diff --git a/include/cef_base.h b/include/cef_base.h
new file mode 100644
index 00000000..bd8f11ed
--- /dev/null
+++ b/include/cef_base.h
@@ -0,0 +1,149 @@
+// Copyright (c) 2012 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CEF_INCLUDE_CEF_BASE_H_
+#define CEF_INCLUDE_CEF_BASE_H_
+#pragma once
+
+#include "include/base/cef_atomic_ref_count.h"
+#include "include/base/cef_build.h"
+#include "include/base/cef_macros.h"
+
+// Bring in common C++ type definitions used by CEF consumers.
+#include "include/internal/cef_ptr.h"
+#include "include/internal/cef_time_wrappers.h"
+#include "include/internal/cef_types_wrappers.h"
+#if defined(OS_WIN)
+#include "include/internal/cef_win.h"
+#elif defined(OS_MAC)
+#include "include/internal/cef_mac.h"
+#elif defined(OS_LINUX)
+#include "include/internal/cef_linux.h"
+#endif
+
+///
+/// All ref-counted framework classes must extend this class.
+///
+class CefBaseRefCounted {
+ public:
+ ///
+ /// Called to increment the reference count for the object. Should be called
+ /// for every new copy of a pointer to a given object.
+ ///
+ virtual void AddRef() const = 0;
+
+ ///
+ /// Called to decrement the reference count for the object. Returns true if
+ /// the reference count is 0, in which case the object should self-delete.
+ ///
+ virtual bool Release() const = 0;
+
+ ///
+ /// Returns true if the reference count is 1.
+ ///
+ virtual bool HasOneRef() const = 0;
+
+ ///
+ /// Returns true if the reference count is at least 1.
+ ///
+ virtual bool HasAtLeastOneRef() const = 0;
+
+ protected:
+ virtual ~CefBaseRefCounted() {}
+};
+
+///
+/// All scoped framework classes must extend this class.
+///
+class CefBaseScoped {
+ public:
+ virtual ~CefBaseScoped() {}
+};
+
+///
+/// Class that implements atomic reference counting.
+///
+class CefRefCount {
+ public:
+ CefRefCount() = default;
+
+ CefRefCount(const CefRefCount&) = delete;
+ CefRefCount& operator=(const CefRefCount&) = delete;
+
+ ///
+ /// Increment the reference count.
+ ///
+ void AddRef() const { ref_count_.Increment(); }
+
+ ///
+ /// Decrement the reference count. Returns true if the reference count is 0.
+ ///
+ bool Release() const { return !ref_count_.Decrement(); }
+
+ ///
+ /// Returns true if the reference count is 1.
+ ///
+ bool HasOneRef() const { return ref_count_.IsOne(); }
+
+ ///
+ /// Returns true if the reference count is at least 1.
+ ///
+ bool HasAtLeastOneRef() const { return !ref_count_.IsZero(); }
+
+ private:
+ mutable base::AtomicRefCount ref_count_{0};
+};
+
+///
+/// Macro that provides a reference counting implementation for classes
+/// extending CefBase.
+///
+#define IMPLEMENT_REFCOUNTING(ClassName) \
+ public: \
+ void AddRef() const override { \
+ ref_count_.AddRef(); \
+ } \
+ bool Release() const override { \
+ if (ref_count_.Release()) { \
+ delete static_cast<const ClassName*>(this); \
+ return true; \
+ } \
+ return false; \
+ } \
+ bool HasOneRef() const override { \
+ return ref_count_.HasOneRef(); \
+ } \
+ bool HasAtLeastOneRef() const override { \
+ return ref_count_.HasAtLeastOneRef(); \
+ } \
+ \
+ private: \
+ CefRefCount ref_count_
+
+#endif // CEF_INCLUDE_CEF_BASE_H_
diff --git a/include/cef_browser.h b/include/cef_browser.h
new file mode 100644
index 00000000..826c99dc
--- /dev/null
+++ b/include/cef_browser.h
@@ -0,0 +1,946 @@
+// Copyright (c) 2012 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_BROWSER_H_
+#define CEF_INCLUDE_CEF_BROWSER_H_
+#pragma once
+
+#include <vector>
+#include "include/cef_base.h"
+#include "include/cef_devtools_message_observer.h"
+#include "include/cef_drag_data.h"
+#include "include/cef_frame.h"
+#include "include/cef_image.h"
+#include "include/cef_navigation_entry.h"
+#include "include/cef_registration.h"
+#include "include/cef_request_context.h"
+
+class CefBrowserHost;
+class CefClient;
+
+///
+/// Class used to represent a browser. When used in the browser process the
+/// methods of this class may be called on any thread unless otherwise indicated
+/// in the comments. When used in the render process the methods of this class
+/// may only be called on the main thread.
+///
+/*--cef(source=library)--*/
+class CefBrowser : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// True if this object is currently valid. This will return false after
+ /// CefLifeSpanHandler::OnBeforeClose is called.
+ ///
+ /*--cef()--*/
+ virtual bool IsValid() = 0;
+
+ ///
+ /// Returns the browser host object. This method can only be called in the
+ /// browser process.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefBrowserHost> GetHost() = 0;
+
+ ///
+ /// Returns true if the browser can navigate backwards.
+ ///
+ /*--cef()--*/
+ virtual bool CanGoBack() = 0;
+
+ ///
+ /// Navigate backwards.
+ ///
+ /*--cef()--*/
+ virtual void GoBack() = 0;
+
+ ///
+ /// Returns true if the browser can navigate forwards.
+ ///
+ /*--cef()--*/
+ virtual bool CanGoForward() = 0;
+
+ ///
+ /// Navigate forwards.
+ ///
+ /*--cef()--*/
+ virtual void GoForward() = 0;
+
+ ///
+ /// Returns true if the browser is currently loading.
+ ///
+ /*--cef()--*/
+ virtual bool IsLoading() = 0;
+
+ ///
+ /// Reload the current page.
+ ///
+ /*--cef()--*/
+ virtual void Reload() = 0;
+
+ ///
+ /// Reload the current page ignoring any cached data.
+ ///
+ /*--cef()--*/
+ virtual void ReloadIgnoreCache() = 0;
+
+ ///
+ /// Stop loading the page.
+ ///
+ /*--cef()--*/
+ virtual void StopLoad() = 0;
+
+ ///
+ /// Returns the globally unique identifier for this browser. This value is
+ /// also used as the tabId for extension APIs.
+ ///
+ /*--cef()--*/
+ virtual int GetIdentifier() = 0;
+
+ ///
+ /// Returns true if this object is pointing to the same handle as |that|
+ /// object.
+ ///
+ /*--cef()--*/
+ virtual bool IsSame(CefRefPtr<CefBrowser> that) = 0;
+
+ ///
+ /// Returns true if the browser is a popup.
+ ///
+ /*--cef()--*/
+ virtual bool IsPopup() = 0;
+
+ ///
+ /// Returns true if a document has been loaded in the browser.
+ ///
+ /*--cef()--*/
+ virtual bool HasDocument() = 0;
+
+ ///
+ /// Returns the main (top-level) frame for the browser. In the browser process
+ /// this will return a valid object until after
+ /// CefLifeSpanHandler::OnBeforeClose is called. In the renderer process this
+ /// will return NULL if the main frame is hosted in a different renderer
+ /// process (e.g. for cross-origin sub-frames). The main frame object will
+ /// change during cross-origin navigation or re-navigation after renderer
+ /// process termination (due to crashes, etc).
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefFrame> GetMainFrame() = 0;
+
+ ///
+ /// Returns the focused frame for the browser.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefFrame> GetFocusedFrame() = 0;
+
+ ///
+ /// Returns the frame with the specified identifier, or NULL if not found.
+ ///
+ /*--cef(capi_name=get_frame_byident)--*/
+ virtual CefRefPtr<CefFrame> GetFrame(int64 identifier) = 0;
+
+ ///
+ /// Returns the frame with the specified name, or NULL if not found.
+ ///
+ /*--cef(optional_param=name)--*/
+ virtual CefRefPtr<CefFrame> GetFrame(const CefString& name) = 0;
+
+ ///
+ /// Returns the number of frames that currently exist.
+ ///
+ /*--cef()--*/
+ virtual size_t GetFrameCount() = 0;
+
+ ///
+ /// Returns the identifiers of all existing frames.
+ ///
+ /*--cef(count_func=identifiers:GetFrameCount)--*/
+ virtual void GetFrameIdentifiers(std::vector<int64>& identifiers) = 0;
+
+ ///
+ /// Returns the names of all existing frames.
+ ///
+ /*--cef()--*/
+ virtual void GetFrameNames(std::vector<CefString>& names) = 0;
+};
+
+///
+/// Callback interface for CefBrowserHost::RunFileDialog. The methods of this
+/// class will be called on the browser process UI thread.
+///
+/*--cef(source=client)--*/
+class CefRunFileDialogCallback : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Called asynchronously after the file dialog is dismissed.
+ /// |file_paths| will be a single value or a list of values depending on the
+ /// dialog mode. If the selection was cancelled |file_paths| will be empty.
+ ///
+ /*--cef(optional_param=file_paths)--*/
+ virtual void OnFileDialogDismissed(
+ const std::vector<CefString>& file_paths) = 0;
+};
+
+///
+/// Callback interface for CefBrowserHost::GetNavigationEntries. The methods of
+/// this class will be called on the browser process UI thread.
+///
+/*--cef(source=client)--*/
+class CefNavigationEntryVisitor : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Method that will be executed. Do not keep a reference to |entry| outside
+ /// of this callback. Return true to continue visiting entries or false to
+ /// stop. |current| is true if this entry is the currently loaded navigation
+ /// entry. |index| is the 0-based index of this entry and |total| is the total
+ /// number of entries.
+ ///
+ /*--cef()--*/
+ virtual bool Visit(CefRefPtr<CefNavigationEntry> entry,
+ bool current,
+ int index,
+ int total) = 0;
+};
+
+///
+/// Callback interface for CefBrowserHost::PrintToPDF. The methods of this class
+/// will be called on the browser process UI thread.
+///
+/*--cef(source=client)--*/
+class CefPdfPrintCallback : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Method that will be executed when the PDF printing has completed. |path|
+ /// is the output path. |ok| will be true if the printing completed
+ /// successfully or false otherwise.
+ ///
+ /*--cef()--*/
+ virtual void OnPdfPrintFinished(const CefString& path, bool ok) = 0;
+};
+
+///
+/// Callback interface for CefBrowserHost::DownloadImage. The methods of this
+/// class will be called on the browser process UI thread.
+///
+/*--cef(source=client)--*/
+class CefDownloadImageCallback : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Method that will be executed when the image download has completed.
+ /// |image_url| is the URL that was downloaded and |http_status_code| is the
+ /// resulting HTTP status code. |image| is the resulting image, possibly at
+ /// multiple scale factors, or empty if the download failed.
+ ///
+ /*--cef(optional_param=image)--*/
+ virtual void OnDownloadImageFinished(const CefString& image_url,
+ int http_status_code,
+ CefRefPtr<CefImage> image) = 0;
+};
+
+///
+/// Class used to represent the browser process aspects of a browser. The
+/// methods of this class can only be called in the browser process. They may be
+/// called on any thread in that process unless otherwise indicated in the
+/// comments.
+///
+/*--cef(source=library)--*/
+class CefBrowserHost : public virtual CefBaseRefCounted {
+ public:
+ typedef cef_drag_operations_mask_t DragOperationsMask;
+ typedef cef_file_dialog_mode_t FileDialogMode;
+ typedef cef_mouse_button_type_t MouseButtonType;
+ typedef cef_paint_element_type_t PaintElementType;
+
+ ///
+ /// Create a new browser using the window parameters specified by
+ /// |windowInfo|. All values will be copied internally and the actual window
+ /// (if any) will be created on the UI thread. If |request_context| is empty
+ /// the global request context will be used. This method can be called on any
+ /// browser process thread and will not block. The optional |extra_info|
+ /// parameter provides an opportunity to specify extra information specific to
+ /// the created browser that will be passed to
+ /// CefRenderProcessHandler::OnBrowserCreated() in the render process.
+ ///
+ /*--cef(optional_param=client,optional_param=url,
+ optional_param=request_context,optional_param=extra_info)--*/
+ static bool CreateBrowser(const CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient> client,
+ const CefString& url,
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefDictionaryValue> extra_info,
+ CefRefPtr<CefRequestContext> request_context);
+
+ ///
+ /// Create a new browser using the window parameters specified by
+ /// |windowInfo|. If |request_context| is empty the global request context
+ /// will be used. This method can only be called on the browser process UI
+ /// thread. The optional |extra_info| parameter provides an opportunity to
+ /// specify extra information specific to the created browser that will be
+ /// passed to CefRenderProcessHandler::OnBrowserCreated() in the render
+ /// process.
+ ///
+ /*--cef(optional_param=client,optional_param=url,
+ optional_param=request_context,optional_param=extra_info)--*/
+ static CefRefPtr<CefBrowser> CreateBrowserSync(
+ const CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient> client,
+ const CefString& url,
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefDictionaryValue> extra_info,
+ CefRefPtr<CefRequestContext> request_context);
+
+ ///
+ /// Returns the hosted browser object.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefBrowser> GetBrowser() = 0;
+
+ ///
+ /// Request that the browser close. The JavaScript 'onbeforeunload' event will
+ /// be fired. If |force_close| is false the event handler, if any, will be
+ /// allowed to prompt the user and the user can optionally cancel the close.
+ /// If |force_close| is true the prompt will not be displayed and the close
+ /// will proceed. Results in a call to CefLifeSpanHandler::DoClose() if the
+ /// event handler allows the close or if |force_close| is true. See
+ /// CefLifeSpanHandler::DoClose() documentation for additional usage
+ /// information.
+ ///
+ /*--cef()--*/
+ virtual void CloseBrowser(bool force_close) = 0;
+
+ ///
+ /// Helper for closing a browser. Call this method from the top-level window
+ /// close handler (if any). Internally this calls CloseBrowser(false) if the
+ /// close has not yet been initiated. This method returns false while the
+ /// close is pending and true after the close has completed. See
+ /// CloseBrowser() and CefLifeSpanHandler::DoClose() documentation for
+ /// additional usage information. This method must be called on the browser
+ /// process UI thread.
+ ///
+ /*--cef()--*/
+ virtual bool TryCloseBrowser() = 0;
+
+ ///
+ /// Set whether the browser is focused.
+ ///
+ /*--cef()--*/
+ virtual void SetFocus(bool focus) = 0;
+
+ ///
+ /// Retrieve the window handle (if any) for this browser. If this browser is
+ /// wrapped in a CefBrowserView this method should be called on the browser
+ /// process UI thread and it will return the handle for the top-level native
+ /// window.
+ ///
+ /*--cef()--*/
+ virtual CefWindowHandle GetWindowHandle() = 0;
+
+ ///
+ /// Retrieve the window handle (if any) of the browser that opened this
+ /// browser. Will return NULL for non-popup browsers or if this browser is
+ /// wrapped in a CefBrowserView. This method can be used in combination with
+ /// custom handling of modal windows.
+ ///
+ /*--cef()--*/
+ virtual CefWindowHandle GetOpenerWindowHandle() = 0;
+
+ ///
+ /// Returns true if this browser is wrapped in a CefBrowserView.
+ ///
+ /*--cef()--*/
+ virtual bool HasView() = 0;
+
+ ///
+ /// Returns the client for this browser.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefClient> GetClient() = 0;
+
+ ///
+ /// Returns the request context for this browser.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefRequestContext> GetRequestContext() = 0;
+
+ ///
+ /// Get the current zoom level. The default zoom level is 0.0. This method can
+ /// only be called on the UI thread.
+ ///
+ /*--cef()--*/
+ virtual double GetZoomLevel() = 0;
+
+ ///
+ /// Change the zoom level to the specified value. Specify 0.0 to reset the
+ /// zoom level. If called on the UI thread the change will be applied
+ /// immediately. Otherwise, the change will be applied asynchronously on the
+ /// UI thread.
+ ///
+ /*--cef()--*/
+ virtual void SetZoomLevel(double zoomLevel) = 0;
+
+ ///
+ /// Call to run a file chooser dialog. Only a single file chooser dialog may
+ /// be pending at any given time. |mode| represents the type of dialog to
+ /// display. |title| to the title to be used for the dialog and may be empty
+ /// to show the default title ("Open" or "Save" depending on the mode).
+ /// |default_file_path| is the path with optional directory and/or file name
+ /// component that will be initially selected in the dialog. |accept_filters|
+ /// are used to restrict the selectable file types and may any combination of
+ /// (a) valid lower-cased MIME types (e.g. "text/*" or "image/*"), (b)
+ /// individual file extensions (e.g.
+ /// ".txt" or ".png"), or (c) combined description and file extension
+ /// delimited using "|" and ";" (e.g. "Image Types|.png;.gif;.jpg").
+ /// |callback| will be executed after the dialog is dismissed or immediately
+ /// if another dialog is already pending. The dialog will be initiated
+ /// asynchronously on the UI thread.
+ ///
+ /*--cef(optional_param=title,optional_param=default_file_path,
+ optional_param=accept_filters)--*/
+ virtual void RunFileDialog(FileDialogMode mode,
+ const CefString& title,
+ const CefString& default_file_path,
+ const std::vector<CefString>& accept_filters,
+ CefRefPtr<CefRunFileDialogCallback> callback) = 0;
+
+ ///
+ /// Download the file at |url| using CefDownloadHandler.
+ ///
+ /*--cef()--*/
+ virtual void StartDownload(const CefString& url) = 0;
+
+ ///
+ /// Download |image_url| and execute |callback| on completion with the images
+ /// received from the renderer. If |is_favicon| is true then cookies are not
+ /// sent and not accepted during download. Images with density independent
+ /// pixel (DIP) sizes larger than |max_image_size| are filtered out from the
+ /// image results. Versions of the image at different scale factors may be
+ /// downloaded up to the maximum scale factor supported by the system. If
+ /// there are no image results <= |max_image_size| then the smallest image is
+ /// resized to |max_image_size| and is the only result. A |max_image_size| of
+ /// 0 means unlimited. If |bypass_cache| is true then |image_url| is requested
+ /// from the server even if it is present in the browser cache.
+ ///
+ /*--cef()--*/
+ virtual void DownloadImage(const CefString& image_url,
+ bool is_favicon,
+ uint32 max_image_size,
+ bool bypass_cache,
+ CefRefPtr<CefDownloadImageCallback> callback) = 0;
+
+ ///
+ /// Print the current browser contents.
+ ///
+ /*--cef()--*/
+ virtual void Print() = 0;
+
+ ///
+ /// Print the current browser contents to the PDF file specified by |path| and
+ /// execute |callback| on completion. The caller is responsible for deleting
+ /// |path| when done. For PDF printing to work on Linux you must implement the
+ /// CefPrintHandler::GetPdfPaperSize method.
+ ///
+ /*--cef(optional_param=callback)--*/
+ virtual void PrintToPDF(const CefString& path,
+ const CefPdfPrintSettings& settings,
+ CefRefPtr<CefPdfPrintCallback> callback) = 0;
+
+ ///
+ /// Search for |searchText|. |forward| indicates whether to search forward or
+ /// backward within the page. |matchCase| indicates whether the search should
+ /// be case-sensitive. |findNext| indicates whether this is the first request
+ /// or a follow-up. The search will be restarted if |searchText| or
+ /// |matchCase| change. The search will be stopped if |searchText| is empty.
+ /// The CefFindHandler instance, if any, returned via
+ /// CefClient::GetFindHandler will be called to report find results.
+ ///
+ /*--cef()--*/
+ virtual void Find(const CefString& searchText,
+ bool forward,
+ bool matchCase,
+ bool findNext) = 0;
+
+ ///
+ /// Cancel all searches that are currently going on.
+ ///
+ /*--cef()--*/
+ virtual void StopFinding(bool clearSelection) = 0;
+
+ ///
+ /// Open developer tools (DevTools) in its own browser. The DevTools browser
+ /// will remain associated with this browser. If the DevTools browser is
+ /// already open then it will be focused, in which case the |windowInfo|,
+ /// |client| and |settings| parameters will be ignored. If
+ /// |inspect_element_at| is non-empty then the element at the specified (x,y)
+ /// location will be inspected. The |windowInfo| parameter will be ignored if
+ /// this browser is wrapped in a CefBrowserView.
+ ///
+ /*--cef(optional_param=windowInfo,optional_param=client,
+ optional_param=settings,optional_param=inspect_element_at)--*/
+ virtual void ShowDevTools(const CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient> client,
+ const CefBrowserSettings& settings,
+ const CefPoint& inspect_element_at) = 0;
+
+ ///
+ /// Explicitly close the associated DevTools browser, if any.
+ ///
+ /*--cef()--*/
+ virtual void CloseDevTools() = 0;
+
+ ///
+ /// Returns true if this browser currently has an associated DevTools browser.
+ /// Must be called on the browser process UI thread.
+ ///
+ /*--cef()--*/
+ virtual bool HasDevTools() = 0;
+
+ ///
+ /// Send a method call message over the DevTools protocol. |message| must be a
+ /// UTF8-encoded JSON dictionary that contains "id" (int), "method" (string)
+ /// and "params" (dictionary, optional) values. See the DevTools protocol
+ /// documentation at https://chromedevtools.github.io/devtools-protocol/ for
+ /// details of supported methods and the expected "params" dictionary
+ /// contents. |message| will be copied if necessary. This method will return
+ /// true if called on the UI thread and the message was successfully submitted
+ /// for validation, otherwise false. Validation will be applied asynchronously
+ /// and any messages that fail due to formatting errors or missing parameters
+ /// may be discarded without notification. Prefer ExecuteDevToolsMethod if a
+ /// more structured approach to message formatting is desired.
+ ///
+ /// Every valid method call will result in an asynchronous method result or
+ /// error message that references the sent message "id". Event messages are
+ /// received while notifications are enabled (for example, between method
+ /// calls for "Page.enable" and "Page.disable"). All received messages will be
+ /// delivered to the observer(s) registered with AddDevToolsMessageObserver.
+ /// See CefDevToolsMessageObserver::OnDevToolsMessage documentation for
+ /// details of received message contents.
+ ///
+ /// Usage of the SendDevToolsMessage, ExecuteDevToolsMethod and
+ /// AddDevToolsMessageObserver methods does not require an active DevTools
+ /// front-end or remote-debugging session. Other active DevTools sessions will
+ /// continue to function independently. However, any modification of global
+ /// browser state by one session may not be reflected in the UI of other
+ /// sessions.
+ ///
+ /// Communication with the DevTools front-end (when displayed) can be logged
+ /// for development purposes by passing the
+ /// `--devtools-protocol-log-file=<path>` command-line flag.
+ ///
+ /*--cef()--*/
+ virtual bool SendDevToolsMessage(const void* message,
+ size_t message_size) = 0;
+
+ ///
+ /// Execute a method call over the DevTools protocol. This is a more
+ /// structured version of SendDevToolsMessage. |message_id| is an incremental
+ /// number that uniquely identifies the message (pass 0 to have the next
+ /// number assigned automatically based on previous values). |method| is the
+ /// method name. |params| are the method parameters, which may be empty. See
+ /// the DevTools protocol documentation (linked above) for details of
+ /// supported methods and the expected |params| dictionary contents. This
+ /// method will return the assigned message ID if called on the UI thread and
+ /// the message was successfully submitted for validation, otherwise 0. See
+ /// the SendDevToolsMessage documentation for additional usage information.
+ ///
+ /*--cef(optional_param=params)--*/
+ virtual int ExecuteDevToolsMethod(int message_id,
+ const CefString& method,
+ CefRefPtr<CefDictionaryValue> params) = 0;
+
+ ///
+ /// Add an observer for DevTools protocol messages (method results and
+ /// events). The observer will remain registered until the returned
+ /// Registration object is destroyed. See the SendDevToolsMessage
+ /// documentation for additional usage information.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefRegistration> AddDevToolsMessageObserver(
+ CefRefPtr<CefDevToolsMessageObserver> observer) = 0;
+
+ ///
+ /// Retrieve a snapshot of current navigation entries as values sent to the
+ /// specified visitor. If |current_only| is true only the current navigation
+ /// entry will be sent, otherwise all navigation entries will be sent.
+ ///
+ /*--cef()--*/
+ virtual void GetNavigationEntries(
+ CefRefPtr<CefNavigationEntryVisitor> visitor,
+ bool current_only) = 0;
+
+ ///
+ /// If a misspelled word is currently selected in an editable node calling
+ /// this method will replace it with the specified |word|.
+ ///
+ /*--cef()--*/
+ virtual void ReplaceMisspelling(const CefString& word) = 0;
+
+ ///
+ /// Add the specified |word| to the spelling dictionary.
+ ///
+ /*--cef()--*/
+ virtual void AddWordToDictionary(const CefString& word) = 0;
+
+ ///
+ /// Returns true if window rendering is disabled.
+ ///
+ /*--cef()--*/
+ virtual bool IsWindowRenderingDisabled() = 0;
+
+ ///
+ /// Notify the browser that the widget has been resized. The browser will
+ /// first call CefRenderHandler::GetViewRect to get the new size and then call
+ /// CefRenderHandler::OnPaint asynchronously with the updated regions. This
+ /// method is only used when window rendering is disabled.
+ ///
+ /*--cef()--*/
+ virtual void WasResized() = 0;
+
+ ///
+ /// Notify the browser that it has been hidden or shown. Layouting and
+ /// CefRenderHandler::OnPaint notification will stop when the browser is
+ /// hidden. This method is only used when window rendering is disabled.
+ ///
+ /*--cef()--*/
+ virtual void WasHidden(bool hidden) = 0;
+
+ ///
+ /// Send a notification to the browser that the screen info has changed. The
+ /// browser will then call CefRenderHandler::GetScreenInfo to update the
+ /// screen information with the new values. This simulates moving the webview
+ /// window from one display to another, or changing the properties of the
+ /// current display. This method is only used when window rendering is
+ /// disabled.
+ ///
+ /*--cef()--*/
+ virtual void NotifyScreenInfoChanged() = 0;
+
+ ///
+ /// Invalidate the view. The browser will call CefRenderHandler::OnPaint
+ /// asynchronously. This method is only used when window rendering is
+ /// disabled.
+ ///
+ /*--cef()--*/
+ virtual void Invalidate(PaintElementType type) = 0;
+
+ ///
+ /// Issue a BeginFrame request to Chromium. Only valid when
+ /// CefWindowInfo::external_begin_frame_enabled is set to true.
+ ///
+ /*--cef()--*/
+ virtual void SendExternalBeginFrame() = 0;
+
+ ///
+ /// Send a key event to the browser.
+ ///
+ /*--cef()--*/
+ virtual void SendKeyEvent(const CefKeyEvent& event) = 0;
+
+ ///
+ /// Send a mouse click event to the browser. The |x| and |y| coordinates are
+ /// relative to the upper-left corner of the view.
+ ///
+ /*--cef()--*/
+ virtual void SendMouseClickEvent(const CefMouseEvent& event,
+ MouseButtonType type,
+ bool mouseUp,
+ int clickCount) = 0;
+
+ ///
+ /// Send a mouse move event to the browser. The |x| and |y| coordinates are
+ /// relative to the upper-left corner of the view.
+ ///
+ /*--cef()--*/
+ virtual void SendMouseMoveEvent(const CefMouseEvent& event,
+ bool mouseLeave) = 0;
+
+ ///
+ /// Send a mouse wheel event to the browser. The |x| and |y| coordinates are
+ /// relative to the upper-left corner of the view. The |deltaX| and |deltaY|
+ /// values represent the movement delta in the X and Y directions
+ /// respectively. In order to scroll inside select popups with window
+ /// rendering disabled CefRenderHandler::GetScreenPoint should be implemented
+ /// properly.
+ ///
+ /*--cef()--*/
+ virtual void SendMouseWheelEvent(const CefMouseEvent& event,
+ int deltaX,
+ int deltaY) = 0;
+
+ ///
+ /// Send a touch event to the browser for a windowless browser.
+ ///
+ /*--cef()--*/
+ virtual void SendTouchEvent(const CefTouchEvent& event) = 0;
+
+ ///
+ /// Send a capture lost event to the browser.
+ ///
+ /*--cef()--*/
+ virtual void SendCaptureLostEvent() = 0;
+
+ ///
+ /// Notify the browser that the window hosting it is about to be moved or
+ /// resized. This method is only used on Windows and Linux.
+ ///
+ /*--cef()--*/
+ virtual void NotifyMoveOrResizeStarted() = 0;
+
+ ///
+ /// Returns the maximum rate in frames per second (fps) that
+ /// CefRenderHandler::OnPaint will be called for a windowless browser. The
+ /// actual fps may be lower if the browser cannot generate frames at the
+ /// requested rate. The minimum value is 1 and the maximum value is 60
+ /// (default 30). This method can only be called on the UI thread.
+ ///
+ /*--cef()--*/
+ virtual int GetWindowlessFrameRate() = 0;
+
+ ///
+ /// Set the maximum rate in frames per second (fps) that CefRenderHandler::
+ /// OnPaint will be called for a windowless browser. The actual fps may be
+ /// lower if the browser cannot generate frames at the requested rate. The
+ /// minimum value is 1 and the maximum value is 60 (default 30). Can also be
+ /// set at browser creation via CefBrowserSettings.windowless_frame_rate.
+ ///
+ /*--cef()--*/
+ virtual void SetWindowlessFrameRate(int frame_rate) = 0;
+
+ ///
+ /// Begins a new composition or updates the existing composition. Blink has a
+ /// special node (a composition node) that allows the input method to change
+ /// text without affecting other DOM nodes. |text| is the optional text that
+ /// will be inserted into the composition node. |underlines| is an optional
+ /// set of ranges that will be underlined in the resulting text.
+ /// |replacement_range| is an optional range of the existing text that will be
+ /// replaced. |selection_range| is an optional range of the resulting text
+ /// that will be selected after insertion or replacement. The
+ /// |replacement_range| value is only used on OS X.
+ ///
+ /// This method may be called multiple times as the composition changes. When
+ /// the client is done making changes the composition should either be
+ /// canceled or completed. To cancel the composition call
+ /// ImeCancelComposition. To complete the composition call either
+ /// ImeCommitText or ImeFinishComposingText. Completion is usually signaled
+ /// when:
+ ///
+ /// 1. The client receives a WM_IME_COMPOSITION message with a GCS_RESULTSTR
+ /// flag (on Windows), or;
+ /// 2. The client receives a "commit" signal of GtkIMContext (on Linux), or;
+ /// 3. insertText of NSTextInput is called (on Mac).
+ ///
+ /// This method is only used when window rendering is disabled.
+ ///
+ /*--cef(optional_param=text, optional_param=underlines)--*/
+ virtual void ImeSetComposition(
+ const CefString& text,
+ const std::vector<CefCompositionUnderline>& underlines,
+ const CefRange& replacement_range,
+ const CefRange& selection_range) = 0;
+
+ ///
+ /// Completes the existing composition by optionally inserting the specified
+ /// |text| into the composition node. |replacement_range| is an optional range
+ /// of the existing text that will be replaced. |relative_cursor_pos| is where
+ /// the cursor will be positioned relative to the current cursor position. See
+ /// comments on ImeSetComposition for usage. The |replacement_range| and
+ /// |relative_cursor_pos| values are only used on OS X.
+ /// This method is only used when window rendering is disabled.
+ ///
+ /*--cef(optional_param=text)--*/
+ virtual void ImeCommitText(const CefString& text,
+ const CefRange& replacement_range,
+ int relative_cursor_pos) = 0;
+
+ ///
+ /// Completes the existing composition by applying the current composition
+ /// node contents. If |keep_selection| is false the current selection, if any,
+ /// will be discarded. See comments on ImeSetComposition for usage. This
+ /// method is only used when window rendering is disabled.
+ ///
+ /*--cef()--*/
+ virtual void ImeFinishComposingText(bool keep_selection) = 0;
+
+ ///
+ /// Cancels the existing composition and discards the composition node
+ /// contents without applying them. See comments on ImeSetComposition for
+ /// usage.
+ /// This method is only used when window rendering is disabled.
+ ///
+ /*--cef()--*/
+ virtual void ImeCancelComposition() = 0;
+
+ ///
+ /// Call this method when the user drags the mouse into the web view (before
+ /// calling DragTargetDragOver/DragTargetLeave/DragTargetDrop).
+ /// |drag_data| should not contain file contents as this type of data is not
+ /// allowed to be dragged into the web view. File contents can be removed
+ /// using CefDragData::ResetFileContents (for example, if |drag_data| comes
+ /// from CefRenderHandler::StartDragging). This method is only used when
+ /// window rendering is disabled.
+ ///
+ /*--cef()--*/
+ virtual void DragTargetDragEnter(CefRefPtr<CefDragData> drag_data,
+ const CefMouseEvent& event,
+ DragOperationsMask allowed_ops) = 0;
+
+ ///
+ /// Call this method each time the mouse is moved across the web view during
+ /// a drag operation (after calling DragTargetDragEnter and before calling
+ /// DragTargetDragLeave/DragTargetDrop).
+ /// This method is only used when window rendering is disabled.
+ ///
+ /*--cef()--*/
+ virtual void DragTargetDragOver(const CefMouseEvent& event,
+ DragOperationsMask allowed_ops) = 0;
+
+ ///
+ /// Call this method when the user drags the mouse out of the web view (after
+ /// calling DragTargetDragEnter).
+ /// This method is only used when window rendering is disabled.
+ ///
+ /*--cef()--*/
+ virtual void DragTargetDragLeave() = 0;
+
+ ///
+ /// Call this method when the user completes the drag operation by dropping
+ /// the object onto the web view (after calling DragTargetDragEnter).
+ /// The object being dropped is |drag_data|, given as an argument to
+ /// the previous DragTargetDragEnter call.
+ /// This method is only used when window rendering is disabled.
+ ///
+ /*--cef()--*/
+ virtual void DragTargetDrop(const CefMouseEvent& event) = 0;
+
+ ///
+ /// Call this method when the drag operation started by a
+ /// CefRenderHandler::StartDragging call has ended either in a drop or
+ /// by being cancelled. |x| and |y| are mouse coordinates relative to the
+ /// upper-left corner of the view. If the web view is both the drag source
+ /// and the drag target then all DragTarget* methods should be called before
+ /// DragSource* mthods.
+ /// This method is only used when window rendering is disabled.
+ ///
+ /*--cef()--*/
+ virtual void DragSourceEndedAt(int x, int y, DragOperationsMask op) = 0;
+
+ ///
+ /// Call this method when the drag operation started by a
+ /// CefRenderHandler::StartDragging call has completed. This method may be
+ /// called immediately without first calling DragSourceEndedAt to cancel a
+ /// drag operation. If the web view is both the drag source and the drag
+ /// target then all DragTarget* methods should be called before DragSource*
+ /// mthods.
+ /// This method is only used when window rendering is disabled.
+ ///
+ /*--cef()--*/
+ virtual void DragSourceSystemDragEnded() = 0;
+
+ ///
+ /// Returns the current visible navigation entry for this browser. This method
+ /// can only be called on the UI thread.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefNavigationEntry> GetVisibleNavigationEntry() = 0;
+
+ ///
+ /// Set accessibility state for all frames. |accessibility_state| may be
+ /// default, enabled or disabled. If |accessibility_state| is STATE_DEFAULT
+ /// then accessibility will be disabled by default and the state may be
+ /// further controlled with the "force-renderer-accessibility" and
+ /// "disable-renderer-accessibility" command-line switches. If
+ /// |accessibility_state| is STATE_ENABLED then accessibility will be enabled.
+ /// If |accessibility_state| is STATE_DISABLED then accessibility will be
+ /// completely disabled.
+ ///
+ /// For windowed browsers accessibility will be enabled in Complete mode
+ /// (which corresponds to kAccessibilityModeComplete in Chromium). In this
+ /// mode all platform accessibility objects will be created and managed by
+ /// Chromium's internal implementation. The client needs only to detect the
+ /// screen reader and call this method appropriately. For example, on macOS
+ /// the client can handle the @"AXEnhancedUserInterface" accessibility
+ /// attribute to detect VoiceOver state changes and on Windows the client can
+ /// handle WM_GETOBJECT with OBJID_CLIENT to detect accessibility readers.
+ ///
+ /// For windowless browsers accessibility will be enabled in TreeOnly mode
+ /// (which corresponds to kAccessibilityModeWebContentsOnly in Chromium). In
+ /// this mode renderer accessibility is enabled, the full tree is computed,
+ /// and events are passed to CefAccessibiltyHandler, but platform
+ /// accessibility objects are not created. The client may implement platform
+ /// accessibility objects using CefAccessibiltyHandler callbacks if desired.
+ ///
+ /*--cef()--*/
+ virtual void SetAccessibilityState(cef_state_t accessibility_state) = 0;
+
+ ///
+ /// Enable notifications of auto resize via CefDisplayHandler::OnAutoResize.
+ /// Notifications are disabled by default. |min_size| and |max_size| define
+ /// the range of allowed sizes.
+ ///
+ /*--cef()--*/
+ virtual void SetAutoResizeEnabled(bool enabled,
+ const CefSize& min_size,
+ const CefSize& max_size) = 0;
+
+ ///
+ /// Returns the extension hosted in this browser or NULL if no extension is
+ /// hosted. See CefRequestContext::LoadExtension for details.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefExtension> GetExtension() = 0;
+
+ ///
+ /// Returns true if this browser is hosting an extension background script.
+ /// Background hosts do not have a window and are not displayable. See
+ /// CefRequestContext::LoadExtension for details.
+ ///
+ /*--cef()--*/
+ virtual bool IsBackgroundHost() = 0;
+
+ ///
+ /// Set whether the browser's audio is muted.
+ ///
+ /*--cef()--*/
+ virtual void SetAudioMuted(bool mute) = 0;
+
+ ///
+ /// Returns true if the browser's audio is muted. This method can only be
+ /// called on the UI thread.
+ ///
+ /*--cef()--*/
+ virtual bool IsAudioMuted() = 0;
+};
+
+#endif // CEF_INCLUDE_CEF_BROWSER_H_
diff --git a/include/cef_browser_process_handler.h b/include/cef_browser_process_handler.h
new file mode 100644
index 00000000..6579337a
--- /dev/null
+++ b/include/cef_browser_process_handler.h
@@ -0,0 +1,127 @@
+// Copyright (c) 2012 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_BROWSER_PROCESS_HANDLER_H_
+#define CEF_INCLUDE_CEF_BROWSER_PROCESS_HANDLER_H_
+#pragma once
+
+#include "include/cef_base.h"
+#include "include/cef_client.h"
+#include "include/cef_command_line.h"
+#include "include/cef_preference.h"
+#include "include/cef_values.h"
+
+///
+/// Class used to implement browser process callbacks. The methods of this class
+/// will be called on the browser process main thread unless otherwise
+/// indicated.
+///
+/*--cef(source=client,no_debugct_check)--*/
+class CefBrowserProcessHandler : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Provides an opportunity to register custom preferences prior to
+ /// global and request context initialization.
+ ///
+ /// If |type| is CEF_PREFERENCES_TYPE_GLOBAL the registered preferences can be
+ /// accessed via CefPreferenceManager::GetGlobalPreferences after
+ /// OnContextInitialized is called. Global preferences are registered a single
+ /// time at application startup. See related cef_settings_t.cache_path and
+ /// cef_settings_t.persist_user_preferences configuration.
+ ///
+ /// If |type| is CEF_PREFERENCES_TYPE_REQUEST_CONTEXT the preferences can be
+ /// accessed via the CefRequestContext after
+ /// CefRequestContextHandler::OnRequestContextInitialized is called. Request
+ /// context preferences are registered each time a new CefRequestContext is
+ /// created. It is intended but not required that all request contexts have
+ /// the same registered preferences. See related
+ /// cef_request_context_settings_t.cache_path and
+ /// cef_request_context_settings_t.persist_user_preferences configuration.
+ ///
+ /// Do not keep a reference to the |registrar| object. This method is called
+ /// on the browser process UI thread.
+ ///
+ /*--cef()--*/
+ virtual void OnRegisterCustomPreferences(
+ cef_preferences_type_t type,
+ CefRawPtr<CefPreferenceRegistrar> registrar) {}
+
+ ///
+ /// Called on the browser process UI thread immediately after the CEF context
+ /// has been initialized.
+ ///
+ /*--cef()--*/
+ virtual void OnContextInitialized() {}
+
+ ///
+ /// Called before a child process is launched. Will be called on the browser
+ /// process UI thread when launching a render process and on the browser
+ /// process IO thread when launching a GPU process. Provides an opportunity to
+ /// modify the child process command line. Do not keep a reference to
+ /// |command_line| outside of this method.
+ ///
+ /*--cef()--*/
+ virtual void OnBeforeChildProcessLaunch(
+ CefRefPtr<CefCommandLine> command_line) {}
+
+ ///
+ /// Called from any thread when work has been scheduled for the browser
+ /// process main (UI) thread. This callback is used in combination with
+ /// cef_settings_t.external_message_pump and CefDoMessageLoopWork() in cases
+ /// where the CEF message loop must be integrated into an existing application
+ /// message loop (see additional comments and warnings on
+ /// CefDoMessageLoopWork). This callback should schedule a
+ /// CefDoMessageLoopWork() call to happen on the main (UI) thread. |delay_ms|
+ /// is the requested delay in milliseconds. If |delay_ms| is <= 0 then the
+ /// call should happen reasonably soon. If |delay_ms| is > 0 then the call
+ /// should be scheduled to happen after the specified delay and any currently
+ /// pending scheduled call should be cancelled.
+ ///
+ /*--cef()--*/
+ virtual void OnScheduleMessagePumpWork(int64 delay_ms) {}
+
+ ///
+ /// Return the default client for use with a newly created browser window. If
+ /// null is returned the browser will be unmanaged (no callbacks will be
+ /// executed for that browser) and application shutdown will be blocked until
+ /// the browser window is closed manually. This method is currently only used
+ /// with the chrome runtime.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefClient> GetDefaultClient() { return nullptr; }
+};
+
+#endif // CEF_INCLUDE_CEF_BROWSER_PROCESS_HANDLER_H_
diff --git a/include/cef_callback.h b/include/cef_callback.h
new file mode 100644
index 00000000..b9e1111d
--- /dev/null
+++ b/include/cef_callback.h
@@ -0,0 +1,75 @@
+// Copyright (c) 2012 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_CALLBACK_H_
+#define CEF_INCLUDE_CEF_CALLBACK_H_
+#pragma once
+
+#include "include/cef_base.h"
+
+///
+/// Generic callback interface used for asynchronous continuation.
+///
+/*--cef(source=library)--*/
+class CefCallback : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Continue processing.
+ ///
+ /*--cef(capi_name=cont)--*/
+ virtual void Continue() = 0;
+
+ ///
+ /// Cancel processing.
+ ///
+ /*--cef()--*/
+ virtual void Cancel() = 0;
+};
+
+///
+/// Generic callback interface used for asynchronous completion.
+///
+/*--cef(source=client)--*/
+class CefCompletionCallback : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Method that will be called once the task is complete.
+ ///
+ /*--cef()--*/
+ virtual void OnComplete() = 0;
+};
+
+#endif // CEF_INCLUDE_CEF_CALLBACK_H_
diff --git a/include/cef_client.h b/include/cef_client.h
new file mode 100644
index 00000000..758c75f9
--- /dev/null
+++ b/include/cef_client.h
@@ -0,0 +1,202 @@
+// Copyright (c) 2012 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_CLIENT_H_
+#define CEF_INCLUDE_CEF_CLIENT_H_
+#pragma once
+
+#include "include/cef_audio_handler.h"
+#include "include/cef_base.h"
+#include "include/cef_command_handler.h"
+#include "include/cef_context_menu_handler.h"
+#include "include/cef_dialog_handler.h"
+#include "include/cef_display_handler.h"
+#include "include/cef_download_handler.h"
+#include "include/cef_drag_handler.h"
+#include "include/cef_find_handler.h"
+#include "include/cef_focus_handler.h"
+#include "include/cef_frame_handler.h"
+#include "include/cef_jsdialog_handler.h"
+#include "include/cef_keyboard_handler.h"
+#include "include/cef_life_span_handler.h"
+#include "include/cef_load_handler.h"
+#include "include/cef_permission_handler.h"
+#include "include/cef_print_handler.h"
+#include "include/cef_process_message.h"
+#include "include/cef_render_handler.h"
+#include "include/cef_request_handler.h"
+
+///
+/// Implement this interface to provide handler implementations.
+///
+/*--cef(source=client,no_debugct_check)--*/
+class CefClient : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Return the handler for audio rendering events.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefAudioHandler> GetAudioHandler() { return nullptr; }
+
+ ///
+ /// Return the handler for commands. If no handler is provided the default
+ /// implementation will be used.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefCommandHandler> GetCommandHandler() { return nullptr; }
+
+ ///
+ /// Return the handler for context menus. If no handler is provided the
+ /// default implementation will be used.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefContextMenuHandler> GetContextMenuHandler() {
+ return nullptr;
+ }
+
+ ///
+ /// Return the handler for dialogs. If no handler is provided the default
+ /// implementation will be used.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefDialogHandler> GetDialogHandler() { return nullptr; }
+
+ ///
+ /// Return the handler for browser display state events.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefDisplayHandler> GetDisplayHandler() { return nullptr; }
+
+ ///
+ /// Return the handler for download events. If no handler is returned
+ /// downloads will not be allowed.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefDownloadHandler> GetDownloadHandler() { return nullptr; }
+
+ ///
+ /// Return the handler for drag events.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefDragHandler> GetDragHandler() { return nullptr; }
+
+ ///
+ /// Return the handler for find result events.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefFindHandler> GetFindHandler() { return nullptr; }
+
+ ///
+ /// Return the handler for focus events.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefFocusHandler> GetFocusHandler() { return nullptr; }
+
+ ///
+ /// Return the handler for events related to CefFrame lifespan. This method
+ /// will be called once during CefBrowser creation and the result will be
+ /// cached for performance reasons.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefFrameHandler> GetFrameHandler() { return nullptr; }
+
+ ///
+ /// Return the handler for permission requests.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefPermissionHandler> GetPermissionHandler() {
+ return nullptr;
+ }
+
+ ///
+ /// Return the handler for JavaScript dialogs. If no handler is provided the
+ /// default implementation will be used.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefJSDialogHandler> GetJSDialogHandler() { return nullptr; }
+
+ ///
+ /// Return the handler for keyboard events.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefKeyboardHandler> GetKeyboardHandler() { return nullptr; }
+
+ ///
+ /// Return the handler for browser life span events.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() { return nullptr; }
+
+ ///
+ /// Return the handler for browser load status events.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefLoadHandler> GetLoadHandler() { return nullptr; }
+
+ ///
+ /// Return the handler for printing on Linux. If a print handler is not
+ /// provided then printing will not be supported on the Linux platform.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefPrintHandler> GetPrintHandler() { return nullptr; }
+
+ ///
+ /// Return the handler for off-screen rendering events.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefRenderHandler> GetRenderHandler() { return nullptr; }
+
+ ///
+ /// Return the handler for browser request events.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefRequestHandler> GetRequestHandler() { return nullptr; }
+
+ ///
+ /// Called when a new message is received from a different process. Return
+ /// true if the message was handled or false otherwise. It is safe to keep a
+ /// reference to |message| outside of this callback.
+ ///
+ /*--cef()--*/
+ virtual bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefProcessId source_process,
+ CefRefPtr<CefProcessMessage> message) {
+ return false;
+ }
+};
+
+#endif // CEF_INCLUDE_CEF_CLIENT_H_
diff --git a/include/cef_command_handler.h b/include/cef_command_handler.h
new file mode 100644
index 00000000..b8af5beb
--- /dev/null
+++ b/include/cef_command_handler.h
@@ -0,0 +1,68 @@
+// Copyright (c) 2022 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_COMMAND_HANDLER_H_
+#define CEF_INCLUDE_CEF_COMMAND_HANDLER_H_
+#pragma once
+
+#include "include/cef_base.h"
+#include "include/cef_browser.h"
+
+///
+/// Implement this interface to handle events related to commands. The methods
+/// of this class will be called on the UI thread.
+///
+/*--cef(source=client)--*/
+class CefCommandHandler : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Called to execute a Chrome command triggered via menu selection or
+ /// keyboard shortcut. Values for |command_id| can be found in the
+ /// cef_command_ids.h file. |disposition| provides information about the
+ /// intended command target. Return true if the command was handled or false
+ /// for the default implementation. For context menu commands this will be
+ /// called after CefContextMenuHandler::OnContextMenuCommand. Only used with
+ /// the Chrome runtime.
+ ///
+ /*--cef()--*/
+ virtual bool OnChromeCommand(CefRefPtr<CefBrowser> browser,
+ int command_id,
+ cef_window_open_disposition_t disposition) {
+ return false;
+ }
+};
+
+#endif // CEF_INCLUDE_CEF_COMMAND_HANDLER_H_
diff --git a/include/cef_command_line.h b/include/cef_command_line.h
new file mode 100644
index 00000000..9ae6ee64
--- /dev/null
+++ b/include/cef_command_line.h
@@ -0,0 +1,210 @@
+// Copyright (c) 2012 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_COMMAND_LINE_H_
+#define CEF_INCLUDE_CEF_COMMAND_LINE_H_
+#pragma once
+
+#include <map>
+#include <vector>
+#include "include/cef_base.h"
+
+///
+/// Class used to create and/or parse command line arguments. Arguments with
+/// "--", "-" and, on Windows, "/" prefixes are considered switches. Switches
+/// will always precede any arguments without switch prefixes. Switches can
+/// optionally have a value specified using the "=" delimiter (e.g.
+/// "-switch=value"). An argument of "--" will terminate switch parsing with all
+/// subsequent tokens, regardless of prefix, being interpreted as non-switch
+/// arguments. Switch names should be lowercase ASCII and will be converted to
+/// such if necessary. Switch values will retain the original case and UTF8
+/// encoding. This class can be used before CefInitialize() is called.
+///
+/*--cef(source=library,no_debugct_check)--*/
+class CefCommandLine : public virtual CefBaseRefCounted {
+ public:
+ typedef std::vector<CefString> ArgumentList;
+ typedef std::map<CefString, CefString> SwitchMap;
+
+ ///
+ /// Create a new CefCommandLine instance.
+ ///
+ /*--cef(api_hash_check)--*/
+ static CefRefPtr<CefCommandLine> CreateCommandLine();
+
+ ///
+ /// Returns the singleton global CefCommandLine object. The returned object
+ /// will be read-only.
+ ///
+ /*--cef(api_hash_check)--*/
+ static CefRefPtr<CefCommandLine> GetGlobalCommandLine();
+
+ ///
+ /// Returns true if this object is valid. Do not call any other methods if
+ /// this function returns false.
+ ///
+ /*--cef()--*/
+ virtual bool IsValid() = 0;
+
+ ///
+ /// Returns true if the values of this object are read-only. Some APIs may
+ /// expose read-only objects.
+ ///
+ /*--cef()--*/
+ virtual bool IsReadOnly() = 0;
+
+ ///
+ /// Returns a writable copy of this object.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefCommandLine> Copy() = 0;
+
+ ///
+ /// Initialize the command line with the specified |argc| and |argv| values.
+ /// The first argument must be the name of the program. This method is only
+ /// supported on non-Windows platforms.
+ ///
+ /*--cef()--*/
+ virtual void InitFromArgv(int argc, const char* const* argv) = 0;
+
+ ///
+ /// Initialize the command line with the string returned by calling
+ /// GetCommandLineW(). This method is only supported on Windows.
+ ///
+ /*--cef()--*/
+ virtual void InitFromString(const CefString& command_line) = 0;
+
+ ///
+ /// Reset the command-line switches and arguments but leave the program
+ /// component unchanged.
+ ///
+ /*--cef()--*/
+ virtual void Reset() = 0;
+
+ ///
+ /// Retrieve the original command line string as a vector of strings.
+ /// The argv array:
+ /// `{ program, [(--|-|/)switch[=value]]*, [--], [argument]* }`
+ ///
+ /*--cef()--*/
+ virtual void GetArgv(std::vector<CefString>& argv) = 0;
+
+ ///
+ /// Constructs and returns the represented command line string. Use this
+ /// method cautiously because quoting behavior is unclear.
+ ///
+ /*--cef()--*/
+ virtual CefString GetCommandLineString() = 0;
+
+ ///
+ /// Get the program part of the command line string (the first item).
+ ///
+ /*--cef()--*/
+ virtual CefString GetProgram() = 0;
+
+ ///
+ /// Set the program part of the command line string (the first item).
+ ///
+ /*--cef()--*/
+ virtual void SetProgram(const CefString& program) = 0;
+
+ ///
+ /// Returns true if the command line has switches.
+ ///
+ /*--cef()--*/
+ virtual bool HasSwitches() = 0;
+
+ ///
+ /// Returns true if the command line contains the given switch.
+ ///
+ /*--cef()--*/
+ virtual bool HasSwitch(const CefString& name) = 0;
+
+ ///
+ /// Returns the value associated with the given switch. If the switch has no
+ /// value or isn't present this method returns the empty string.
+ ///
+ /*--cef()--*/
+ virtual CefString GetSwitchValue(const CefString& name) = 0;
+
+ ///
+ /// Returns the map of switch names and values. If a switch has no value an
+ /// empty string is returned.
+ ///
+ /*--cef()--*/
+ virtual void GetSwitches(SwitchMap& switches) = 0;
+
+ ///
+ /// Add a switch to the end of the command line.
+ ///
+ /*--cef()--*/
+ virtual void AppendSwitch(const CefString& name) = 0;
+
+ ///
+ /// Add a switch with the specified value to the end of the command line. If
+ /// the switch has no value pass an empty value string.
+ ///
+ /*--cef()--*/
+ virtual void AppendSwitchWithValue(const CefString& name,
+ const CefString& value) = 0;
+
+ ///
+ /// True if there are remaining command line arguments.
+ ///
+ /*--cef()--*/
+ virtual bool HasArguments() = 0;
+
+ ///
+ /// Get the remaining command line arguments.
+ ///
+ /*--cef()--*/
+ virtual void GetArguments(ArgumentList& arguments) = 0;
+
+ ///
+ /// Add an argument to the end of the command line.
+ ///
+ /*--cef()--*/
+ virtual void AppendArgument(const CefString& argument) = 0;
+
+ ///
+ /// Insert a command before the current command.
+ /// Common for debuggers, like "valgrind" or "gdb --args".
+ ///
+ /*--cef()--*/
+ virtual void PrependWrapper(const CefString& wrapper) = 0;
+};
+
+#endif // CEF_INCLUDE_CEF_COMMAND_LINE_H_
diff --git a/include/cef_context_menu_handler.h b/include/cef_context_menu_handler.h
new file mode 100644
index 00000000..d499592a
--- /dev/null
+++ b/include/cef_context_menu_handler.h
@@ -0,0 +1,347 @@
+// Copyright (c) 2012 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_CONTEXT_MENU_HANDLER_H_
+#define CEF_INCLUDE_CEF_CONTEXT_MENU_HANDLER_H_
+#pragma once
+
+#include "include/cef_base.h"
+#include "include/cef_browser.h"
+#include "include/cef_frame.h"
+#include "include/cef_menu_model.h"
+
+class CefContextMenuParams;
+
+///
+/// Callback interface used for continuation of custom context menu display.
+///
+/*--cef(source=library)--*/
+class CefRunContextMenuCallback : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Complete context menu display by selecting the specified |command_id| and
+ /// |event_flags|.
+ ///
+ /*--cef(capi_name=cont)--*/
+ virtual void Continue(int command_id, cef_event_flags_t event_flags) = 0;
+
+ ///
+ /// Cancel context menu display.
+ ///
+ /*--cef()--*/
+ virtual void Cancel() = 0;
+};
+
+///
+/// Callback interface used for continuation of custom quick menu display.
+///
+/*--cef(source=library)--*/
+class CefRunQuickMenuCallback : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Complete quick menu display by selecting the specified |command_id| and
+ /// |event_flags|.
+ ///
+ /*--cef(capi_name=cont)--*/
+ virtual void Continue(int command_id, cef_event_flags_t event_flags) = 0;
+
+ ///
+ /// Cancel quick menu display.
+ ///
+ /*--cef()--*/
+ virtual void Cancel() = 0;
+};
+
+///
+/// Implement this interface to handle context menu events. The methods of this
+/// class will be called on the UI thread.
+///
+/*--cef(source=client)--*/
+class CefContextMenuHandler : public virtual CefBaseRefCounted {
+ public:
+ typedef cef_event_flags_t EventFlags;
+ typedef cef_quick_menu_edit_state_flags_t QuickMenuEditStateFlags;
+
+ ///
+ /// Called before a context menu is displayed. |params| provides information
+ /// about the context menu state. |model| initially contains the default
+ /// context menu. The |model| can be cleared to show no context menu or
+ /// modified to show a custom menu. Do not keep references to |params| or
+ /// |model| outside of this callback.
+ ///
+ /*--cef()--*/
+ virtual void OnBeforeContextMenu(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefContextMenuParams> params,
+ CefRefPtr<CefMenuModel> model) {}
+
+ ///
+ /// Called to allow custom display of the context menu. |params| provides
+ /// information about the context menu state. |model| contains the context
+ /// menu model resulting from OnBeforeContextMenu. For custom display return
+ /// true and execute |callback| either synchronously or asynchronously with
+ /// the selected command ID. For default display return false. Do not keep
+ /// references to |params| or |model| outside of this callback.
+ ///
+ /*--cef()--*/
+ virtual bool RunContextMenu(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefContextMenuParams> params,
+ CefRefPtr<CefMenuModel> model,
+ CefRefPtr<CefRunContextMenuCallback> callback) {
+ return false;
+ }
+
+ ///
+ /// Called to execute a command selected from the context menu. Return true if
+ /// the command was handled or false for the default implementation. See
+ /// cef_menu_id_t for the command ids that have default implementations. All
+ /// user-defined command ids should be between MENU_ID_USER_FIRST and
+ /// MENU_ID_USER_LAST. |params| will have the same values as what was passed
+ /// to OnBeforeContextMenu(). Do not keep a reference to |params| outside of
+ /// this callback.
+ ///
+ /*--cef()--*/
+ virtual bool OnContextMenuCommand(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefContextMenuParams> params,
+ int command_id,
+ EventFlags event_flags) {
+ return false;
+ }
+
+ ///
+ /// Called when the context menu is dismissed irregardless of whether the menu
+ /// was canceled or a command was selected.
+ ///
+ /*--cef()--*/
+ virtual void OnContextMenuDismissed(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) {}
+
+ ///
+ /// Called to allow custom display of the quick menu for a windowless browser.
+ /// |location| is the top left corner of the selected region. |size| is the
+ /// size of the selected region. |edit_state_flags| is a combination of flags
+ /// that represent the state of the quick menu. Return true if the menu will
+ /// be handled and execute |callback| either synchronously or asynchronously
+ /// with the selected command ID. Return false to cancel the menu.
+ ///
+ /*--cef()--*/
+ virtual bool RunQuickMenu(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const CefPoint& location,
+ const CefSize& size,
+ QuickMenuEditStateFlags edit_state_flags,
+ CefRefPtr<CefRunQuickMenuCallback> callback) {
+ return false;
+ }
+
+ ///
+ /// Called to execute a command selected from the quick menu for a windowless
+ /// browser. Return true if the command was handled or false for the default
+ /// implementation. See cef_menu_id_t for command IDs that have default
+ /// implementations.
+ ///
+ /*--cef()--*/
+ virtual bool OnQuickMenuCommand(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int command_id,
+ EventFlags event_flags) {
+ return false;
+ }
+
+ ///
+ /// Called when the quick menu for a windowless browser is dismissed
+ /// irregardless of whether the menu was canceled or a command was selected.
+ ///
+ /*--cef()--*/
+ virtual void OnQuickMenuDismissed(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) {}
+};
+
+///
+/// Provides information about the context menu state. The methods of this class
+/// can only be accessed on browser process the UI thread.
+///
+/*--cef(source=library)--*/
+class CefContextMenuParams : public virtual CefBaseRefCounted {
+ public:
+ typedef cef_context_menu_type_flags_t TypeFlags;
+ typedef cef_context_menu_media_type_t MediaType;
+ typedef cef_context_menu_media_state_flags_t MediaStateFlags;
+ typedef cef_context_menu_edit_state_flags_t EditStateFlags;
+
+ ///
+ /// Returns the X coordinate of the mouse where the context menu was invoked.
+ /// Coords are relative to the associated RenderView's origin.
+ ///
+ /*--cef()--*/
+ virtual int GetXCoord() = 0;
+
+ ///
+ /// Returns the Y coordinate of the mouse where the context menu was invoked.
+ /// Coords are relative to the associated RenderView's origin.
+ ///
+ /*--cef()--*/
+ virtual int GetYCoord() = 0;
+
+ ///
+ /// Returns flags representing the type of node that the context menu was
+ /// invoked on.
+ ///
+ /*--cef(default_retval=CM_TYPEFLAG_NONE)--*/
+ virtual TypeFlags GetTypeFlags() = 0;
+
+ ///
+ /// Returns the URL of the link, if any, that encloses the node that the
+ /// context menu was invoked on.
+ ///
+ /*--cef()--*/
+ virtual CefString GetLinkUrl() = 0;
+
+ ///
+ /// Returns the link URL, if any, to be used ONLY for "copy link address". We
+ /// don't validate this field in the frontend process.
+ ///
+ /*--cef()--*/
+ virtual CefString GetUnfilteredLinkUrl() = 0;
+
+ ///
+ /// Returns the source URL, if any, for the element that the context menu was
+ /// invoked on. Example of elements with source URLs are img, audio, and
+ /// video.
+ ///
+ /*--cef()--*/
+ virtual CefString GetSourceUrl() = 0;
+
+ ///
+ /// Returns true if the context menu was invoked on an image which has
+ /// non-empty contents.
+ ///
+ /*--cef()--*/
+ virtual bool HasImageContents() = 0;
+
+ ///
+ /// Returns the title text or the alt text if the context menu was invoked on
+ /// an image.
+ ///
+ /*--cef()--*/
+ virtual CefString GetTitleText() = 0;
+
+ ///
+ /// Returns the URL of the top level page that the context menu was invoked
+ /// on.
+ ///
+ /*--cef()--*/
+ virtual CefString GetPageUrl() = 0;
+
+ ///
+ /// Returns the URL of the subframe that the context menu was invoked on.
+ ///
+ /*--cef()--*/
+ virtual CefString GetFrameUrl() = 0;
+
+ ///
+ /// Returns the character encoding of the subframe that the context menu was
+ /// invoked on.
+ ///
+ /*--cef()--*/
+ virtual CefString GetFrameCharset() = 0;
+
+ ///
+ /// Returns the type of context node that the context menu was invoked on.
+ ///
+ /*--cef(default_retval=CM_MEDIATYPE_NONE)--*/
+ virtual MediaType GetMediaType() = 0;
+
+ ///
+ /// Returns flags representing the actions supported by the media element, if
+ /// any, that the context menu was invoked on.
+ ///
+ /*--cef(default_retval=CM_MEDIAFLAG_NONE)--*/
+ virtual MediaStateFlags GetMediaStateFlags() = 0;
+
+ ///
+ /// Returns the text of the selection, if any, that the context menu was
+ /// invoked on.
+ ///
+ /*--cef()--*/
+ virtual CefString GetSelectionText() = 0;
+
+ ///
+ /// Returns the text of the misspelled word, if any, that the context menu was
+ /// invoked on.
+ ///
+ /*--cef()--*/
+ virtual CefString GetMisspelledWord() = 0;
+
+ ///
+ /// Returns true if suggestions exist, false otherwise. Fills in |suggestions|
+ /// from the spell check service for the misspelled word if there is one.
+ ///
+ /*--cef()--*/
+ virtual bool GetDictionarySuggestions(
+ std::vector<CefString>& suggestions) = 0;
+
+ ///
+ /// Returns true if the context menu was invoked on an editable node.
+ ///
+ /*--cef()--*/
+ virtual bool IsEditable() = 0;
+
+ ///
+ /// Returns true if the context menu was invoked on an editable node where
+ /// spell-check is enabled.
+ ///
+ /*--cef()--*/
+ virtual bool IsSpellCheckEnabled() = 0;
+
+ ///
+ /// Returns flags representing the actions supported by the editable node, if
+ /// any, that the context menu was invoked on.
+ ///
+ /*--cef(default_retval=CM_EDITFLAG_NONE)--*/
+ virtual EditStateFlags GetEditStateFlags() = 0;
+
+ ///
+ /// Returns true if the context menu contains items specified by the renderer
+ /// process.
+ ///
+ /*--cef()--*/
+ virtual bool IsCustomMenu() = 0;
+};
+
+#endif // CEF_INCLUDE_CEF_CONTEXT_MENU_HANDLER_H_
diff --git a/include/cef_cookie.h b/include/cef_cookie.h
new file mode 100644
index 00000000..e3a68207
--- /dev/null
+++ b/include/cef_cookie.h
@@ -0,0 +1,179 @@
+// Copyright (c) 2012 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_COOKIE_H_
+#define CEF_INCLUDE_CEF_COOKIE_H_
+#pragma once
+
+#include <vector>
+#include "include/cef_base.h"
+#include "include/cef_callback.h"
+
+class CefCookieVisitor;
+class CefSetCookieCallback;
+class CefDeleteCookiesCallback;
+
+///
+/// Class used for managing cookies. The methods of this class may be called on
+/// any thread unless otherwise indicated.
+///
+/*--cef(source=library,no_debugct_check)--*/
+class CefCookieManager : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Returns the global cookie manager. By default data will be stored at
+ /// cef_settings_t.cache_path if specified or in memory otherwise. If
+ /// |callback| is non-NULL it will be executed asnychronously on the UI thread
+ /// after the manager's storage has been initialized. Using this method is
+ /// equivalent to calling
+ /// CefRequestContext::GetGlobalContext()->GetDefaultCookieManager().
+ ///
+ /*--cef(optional_param=callback)--*/
+ static CefRefPtr<CefCookieManager> GetGlobalManager(
+ CefRefPtr<CefCompletionCallback> callback);
+
+ ///
+ /// Visit all cookies on the UI thread. The returned cookies are ordered by
+ /// longest path, then by earliest creation date. Returns false if cookies
+ /// cannot be accessed.
+ ///
+ /*--cef()--*/
+ virtual bool VisitAllCookies(CefRefPtr<CefCookieVisitor> visitor) = 0;
+
+ ///
+ /// Visit a subset of cookies on the UI thread. The results are filtered by
+ /// the given url scheme, host, domain and path. If |includeHttpOnly| is true
+ /// HTTP-only cookies will also be included in the results. The returned
+ /// cookies are ordered by longest path, then by earliest creation date.
+ /// Returns false if cookies cannot be accessed.
+ ///
+ /*--cef()--*/
+ virtual bool VisitUrlCookies(const CefString& url,
+ bool includeHttpOnly,
+ CefRefPtr<CefCookieVisitor> visitor) = 0;
+
+ ///
+ /// Sets a cookie given a valid URL and explicit user-provided cookie
+ /// attributes. This function expects each attribute to be well-formed. It
+ /// will check for disallowed characters (e.g. the ';' character is disallowed
+ /// within the cookie value attribute) and fail without setting the cookie if
+ /// such characters are found. If |callback| is non-NULL it will be executed
+ /// asnychronously on the UI thread after the cookie has been set. Returns
+ /// false if an invalid URL is specified or if cookies cannot be accessed.
+ ///
+ /*--cef(optional_param=callback)--*/
+ virtual bool SetCookie(const CefString& url,
+ const CefCookie& cookie,
+ CefRefPtr<CefSetCookieCallback> callback) = 0;
+
+ ///
+ /// Delete all cookies that match the specified parameters. If both |url| and
+ /// |cookie_name| values are specified all host and domain cookies matching
+ /// both will be deleted. If only |url| is specified all host cookies (but not
+ /// domain cookies) irrespective of path will be deleted. If |url| is empty
+ /// all cookies for all hosts and domains will be deleted. If |callback| is
+ /// non-NULL it will be executed asnychronously on the UI thread after the
+ /// cookies have been deleted. Returns false if a non-empty invalid URL is
+ /// specified or if cookies cannot be accessed. Cookies can alternately be
+ /// deleted using the Visit*Cookies() methods.
+ ///
+ /*--cef(optional_param=url,optional_param=cookie_name,
+ optional_param=callback)--*/
+ virtual bool DeleteCookies(const CefString& url,
+ const CefString& cookie_name,
+ CefRefPtr<CefDeleteCookiesCallback> callback) = 0;
+
+ ///
+ /// Flush the backing store (if any) to disk. If |callback| is non-NULL it
+ /// will be executed asnychronously on the UI thread after the flush is
+ /// complete. Returns false if cookies cannot be accessed.
+ ///
+ /*--cef(optional_param=callback)--*/
+ virtual bool FlushStore(CefRefPtr<CefCompletionCallback> callback) = 0;
+};
+
+///
+/// Interface to implement for visiting cookie values. The methods of this class
+/// will always be called on the UI thread.
+///
+/*--cef(source=client)--*/
+class CefCookieVisitor : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Method that will be called once for each cookie. |count| is the 0-based
+ /// index for the current cookie. |total| is the total number of cookies.
+ /// Set |deleteCookie| to true to delete the cookie currently being visited.
+ /// Return false to stop visiting cookies. This method may never be called if
+ /// no cookies are found.
+ ///
+ /*--cef()--*/
+ virtual bool Visit(const CefCookie& cookie,
+ int count,
+ int total,
+ bool& deleteCookie) = 0;
+};
+
+///
+/// Interface to implement to be notified of asynchronous completion via
+/// CefCookieManager::SetCookie().
+///
+/*--cef(source=client)--*/
+class CefSetCookieCallback : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Method that will be called upon completion. |success| will be true if the
+ /// cookie was set successfully.
+ ///
+ /*--cef()--*/
+ virtual void OnComplete(bool success) = 0;
+};
+
+///
+/// Interface to implement to be notified of asynchronous completion via
+/// CefCookieManager::DeleteCookies().
+///
+/*--cef(source=client)--*/
+class CefDeleteCookiesCallback : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Method that will be called upon completion. |num_deleted| will be the
+ /// number of cookies that were deleted.
+ ///
+ /*--cef()--*/
+ virtual void OnComplete(int num_deleted) = 0;
+};
+
+#endif // CEF_INCLUDE_CEF_COOKIE_H_
diff --git a/include/cef_crash_util.h b/include/cef_crash_util.h
new file mode 100644
index 00000000..f9f87ee3
--- /dev/null
+++ b/include/cef_crash_util.h
@@ -0,0 +1,145 @@
+// Copyright (c) 2016 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_CRASH_UTIL_H_
+#define CEF_INCLUDE_CEF_CRASH_UTIL_H_
+#pragma once
+
+///
+/// Crash reporting is configured using an INI-style config file named
+/// "crash_reporter.cfg". On Windows and Linux this file must be placed next to
+/// the main application executable. On macOS this file must be placed in the
+/// top-level app bundle Resources directory (e.g.
+/// "<appname>.app/Contents/Resources"). File contents are as follows:
+///
+/// <pre>
+/// # Comments start with a hash character and must be on their own line.
+///
+/// [Config]
+/// ProductName=<Value of the "prod" crash key; defaults to "cef">
+/// ProductVersion=<Value of the "ver" crash key; defaults to the CEF version>
+/// AppName=<Windows only; App-specific folder name component for storing crash
+/// information; default to "CEF">
+/// ExternalHandler=<Windows only; Name of the external handler exe to use
+/// instead of re-launching the main exe; default to empty>
+/// BrowserCrashForwardingEnabled=<macOS only; True if browser process crashes
+/// should be forwarded to the system crash
+/// reporter; default to false>
+/// ServerURL=<crash server URL; default to empty>
+/// RateLimitEnabled=<True if uploads should be rate limited; default to true>
+/// MaxUploadsPerDay=<Max uploads per 24 hours, used if rate limit is enabled;
+/// default to 5>
+/// MaxDatabaseSizeInMb=<Total crash report disk usage greater than this value
+/// will cause older reports to be deleted; default to 20>
+/// MaxDatabaseAgeInDays=<Crash reports older than this value will be deleted;
+/// default to 5>
+///
+/// [CrashKeys]
+/// my_key1=<small|medium|large>
+/// my_key2=<small|medium|large>
+/// </pre>
+///
+/// <b>Config section:</b>
+///
+/// If "ProductName" and/or "ProductVersion" are set then the specified values
+/// will be included in the crash dump metadata. On macOS if these values are
+/// set to empty then they will be retrieved from the Info.plist file using the
+/// "CFBundleName" and "CFBundleShortVersionString" keys respectively.
+///
+/// If "AppName" is set on Windows then crash report information (metrics,
+/// database and dumps) will be stored locally on disk under the
+/// "C:\Users\[CurrentUser]\AppData\Local\[AppName]\User Data" folder. On other
+/// platforms the cef_settings_t.user_data_path value will be used.
+///
+/// If "ExternalHandler" is set on Windows then the specified exe will be
+/// launched as the crashpad-handler instead of re-launching the main process
+/// exe. The value can be an absolute path or a path relative to the main exe
+/// directory. On Linux the cef_settings_t.browser_subprocess_path value will be
+/// used. On macOS the existing subprocess app bundle will be used.
+///
+/// If "BrowserCrashForwardingEnabled" is set to true on macOS then browser
+/// process crashes will be forwarded to the system crash reporter. This results
+/// in the crash UI dialog being displayed to the user and crash reports being
+/// logged under "~/Library/Logs/DiagnosticReports". Forwarding of crash reports
+/// from non-browser processes and Debug builds is always disabled.
+///
+/// If "ServerURL" is set then crashes will be uploaded as a multi-part POST
+/// request to the specified URL. Otherwise, reports will only be stored locally
+/// on disk.
+///
+/// If "RateLimitEnabled" is set to true then crash report uploads will be rate
+/// limited as follows:
+/// 1. If "MaxUploadsPerDay" is set to a positive value then at most the
+/// specified number of crashes will be uploaded in each 24 hour period.
+/// 2. If crash upload fails due to a network or server error then an
+/// incremental backoff delay up to a maximum of 24 hours will be applied
+/// for retries.
+/// 3. If a backoff delay is applied and "MaxUploadsPerDay" is > 1 then the
+/// "MaxUploadsPerDay" value will be reduced to 1 until the client is
+/// restarted. This helps to avoid an upload flood when the network or
+/// server error is resolved.
+/// Rate limiting is not supported on Linux.
+///
+/// If "MaxDatabaseSizeInMb" is set to a positive value then crash report
+/// storage on disk will be limited to that size in megabytes. For example, on
+/// Windows each dump is about 600KB so a "MaxDatabaseSizeInMb" value of 20
+/// equates to about 34 crash reports stored on disk. Not supported on Linux.
+///
+/// If "MaxDatabaseAgeInDays" is set to a positive value then crash reports
+/// older than the specified age in days will be deleted. Not supported on
+/// Linux.
+///
+/// <b>CrashKeys section:</b>
+///
+/// A maximum of 26 crash keys of each size can be specified for use by the
+/// application. Crash key values will be truncated based on the specified size
+/// (small = 64 bytes, medium = 256 bytes, large = 1024 bytes). The value of
+/// crash keys can be set from any thread or process using the
+/// CefSetCrashKeyValue function. These key/value pairs will be sent to the
+/// crash server along with the crash dump file.
+///
+/*--cef()--*/
+bool CefCrashReportingEnabled();
+
+#include "include/cef_base.h"
+
+///
+/// Sets or clears a specific key-value pair from the crash metadata.
+///
+/*--cef(optional_param=value)--*/
+void CefSetCrashKeyValue(const CefString& key, const CefString& value);
+
+#endif // CEF_INCLUDE_CEF_CRASH_UTIL_H_
diff --git a/include/cef_devtools_message_observer.h b/include/cef_devtools_message_observer.h
new file mode 100644
index 00000000..757c607c
--- /dev/null
+++ b/include/cef_devtools_message_observer.h
@@ -0,0 +1,132 @@
+// Copyright (c) 2020 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_DEVTOOLS_MESSAGE_OBSERVER_H_
+#define CEF_INCLUDE_CEF_DEVTOOLS_MESSAGE_OBSERVER_H_
+#pragma once
+
+#include "include/cef_base.h"
+
+class CefBrowser;
+
+///
+/// Callback interface for CefBrowserHost::AddDevToolsMessageObserver. The
+/// methods of this class will be called on the browser process UI thread.
+///
+/*--cef(source=client)--*/
+class CefDevToolsMessageObserver : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Method that will be called on receipt of a DevTools protocol message.
+ /// |browser| is the originating browser instance. |message| is a UTF8-encoded
+ /// JSON dictionary representing either a method result or an event. |message|
+ /// is only valid for the scope of this callback and should be copied if
+ /// necessary. Return true if the message was handled or false if the message
+ /// should be further processed and passed to the OnDevToolsMethodResult or
+ /// OnDevToolsEvent methods as appropriate.
+ ///
+ /// Method result dictionaries include an "id" (int) value that identifies the
+ /// orginating method call sent from CefBrowserHost::SendDevToolsMessage, and
+ /// optionally either a "result" (dictionary) or "error" (dictionary) value.
+ /// The "error" dictionary will contain "code" (int) and "message" (string)
+ /// values. Event dictionaries include a "method" (string) value and
+ /// optionally a "params" (dictionary) value. See the DevTools protocol
+ /// documentation at https://chromedevtools.github.io/devtools-protocol/ for
+ /// details of supported method calls and the expected "result" or "params"
+ /// dictionary contents. JSON dictionaries can be parsed using the
+ /// CefParseJSON function if desired, however be aware of performance
+ /// considerations when parsing large messages (some of which may exceed 1MB
+ /// in size).
+ ///
+ /*--cef()--*/
+ virtual bool OnDevToolsMessage(CefRefPtr<CefBrowser> browser,
+ const void* message,
+ size_t message_size) {
+ return false;
+ }
+
+ ///
+ /// Method that will be called after attempted execution of a DevTools
+ /// protocol method. |browser| is the originating browser instance.
+ /// |message_id| is the "id" value that identifies the originating method call
+ /// message. If the method succeeded |success| will be true and |result| will
+ /// be the UTF8-encoded JSON "result" dictionary value (which may be empty).
+ /// If the method failed |success| will be false and |result| will be the
+ /// UTF8-encoded JSON "error" dictionary value. |result| is only valid for the
+ /// scope of this callback and should be copied if necessary. See the
+ /// OnDevToolsMessage documentation for additional details on |result|
+ /// contents.
+ ///
+ /*--cef(optional_param=result)--*/
+ virtual void OnDevToolsMethodResult(CefRefPtr<CefBrowser> browser,
+ int message_id,
+ bool success,
+ const void* result,
+ size_t result_size) {}
+
+ ///
+ /// Method that will be called on receipt of a DevTools protocol event.
+ /// |browser| is the originating browser instance. |method| is the "method"
+ /// value. |params| is the UTF8-encoded JSON "params" dictionary value (which
+ /// may be empty). |params| is only valid for the scope of this callback and
+ /// should be copied if necessary. See the OnDevToolsMessage documentation for
+ /// additional details on |params| contents.
+ ///
+ /*--cef(optional_param=params)--*/
+ virtual void OnDevToolsEvent(CefRefPtr<CefBrowser> browser,
+ const CefString& method,
+ const void* params,
+ size_t params_size) {}
+
+ ///
+ /// Method that will be called when the DevTools agent has attached. |browser|
+ /// is the originating browser instance. This will generally occur in response
+ /// to the first message sent while the agent is detached.
+ ///
+ /*--cef()--*/
+ virtual void OnDevToolsAgentAttached(CefRefPtr<CefBrowser> browser) {}
+
+ ///
+ /// Method that will be called when the DevTools agent has detached. |browser|
+ /// is the originating browser instance. Any method results that were pending
+ /// before the agent became detached will not be delivered, and any active
+ /// event subscriptions will be canceled.
+ ///
+ /*--cef()--*/
+ virtual void OnDevToolsAgentDetached(CefRefPtr<CefBrowser> browser) {}
+};
+
+#endif // CEF_INCLUDE_CEF_DEVTOOLS_MESSAGE_OBSERVER_H_
diff --git a/include/cef_dialog_handler.h b/include/cef_dialog_handler.h
new file mode 100644
index 00000000..30fd3a16
--- /dev/null
+++ b/include/cef_dialog_handler.h
@@ -0,0 +1,100 @@
+// Copyright (c) 2012 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_DIALOG_HANDLER_H_
+#define CEF_INCLUDE_CEF_DIALOG_HANDLER_H_
+#pragma once
+
+#include "include/cef_base.h"
+#include "include/cef_browser.h"
+
+///
+/// Callback interface for asynchronous continuation of file dialog requests.
+///
+/*--cef(source=library)--*/
+class CefFileDialogCallback : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Continue the file selection. |file_paths| should be a single value or a
+ /// list of values depending on the dialog mode. An empty |file_paths| value
+ /// is treated the same as calling Cancel().
+ ///
+ /*--cef(capi_name=cont,optional_param=file_paths)--*/
+ virtual void Continue(const std::vector<CefString>& file_paths) = 0;
+
+ ///
+ /// Cancel the file selection.
+ ///
+ /*--cef()--*/
+ virtual void Cancel() = 0;
+};
+
+///
+/// Implement this interface to handle dialog events. The methods of this class
+/// will be called on the browser process UI thread.
+///
+/*--cef(source=client)--*/
+class CefDialogHandler : public virtual CefBaseRefCounted {
+ public:
+ typedef cef_file_dialog_mode_t FileDialogMode;
+
+ ///
+ /// Called to run a file chooser dialog. |mode| represents the type of dialog
+ /// to display. |title| to the title to be used for the dialog and may be
+ /// empty to show the default title ("Open" or "Save" depending on the mode).
+ /// |default_file_path| is the path with optional directory and/or file name
+ /// component that should be initially selected in the dialog.
+ /// |accept_filters| are used to restrict the selectable file types and may
+ /// any combination of (a) valid lower-cased MIME types (e.g. "text/*" or
+ /// "image/*"), (b) individual file extensions (e.g. ".txt" or ".png"), or (c)
+ /// combined description and file extension delimited using "|" and ";" (e.g.
+ /// "Image Types|.png;.gif;.jpg"). To display a custom dialog return true and
+ /// execute |callback| either inline or at a later time. To display the
+ /// default dialog return false.
+ ///
+ /*--cef(optional_param=title,optional_param=default_file_path,
+ optional_param=accept_filters)--*/
+ virtual bool OnFileDialog(CefRefPtr<CefBrowser> browser,
+ FileDialogMode mode,
+ const CefString& title,
+ const CefString& default_file_path,
+ const std::vector<CefString>& accept_filters,
+ CefRefPtr<CefFileDialogCallback> callback) {
+ return false;
+ }
+};
+
+#endif // CEF_INCLUDE_CEF_DIALOG_HANDLER_H_
diff --git a/include/cef_display_handler.h b/include/cef_display_handler.h
new file mode 100644
index 00000000..0b698080
--- /dev/null
+++ b/include/cef_display_handler.h
@@ -0,0 +1,163 @@
+// Copyright (c) 2012 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_DISPLAY_HANDLER_H_
+#define CEF_INCLUDE_CEF_DISPLAY_HANDLER_H_
+#pragma once
+
+#include "include/cef_base.h"
+#include "include/cef_browser.h"
+#include "include/cef_frame.h"
+
+///
+/// Implement this interface to handle events related to browser display state.
+/// The methods of this class will be called on the UI thread.
+///
+/*--cef(source=client)--*/
+class CefDisplayHandler : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Called when a frame's address has changed.
+ ///
+ /*--cef()--*/
+ virtual void OnAddressChange(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const CefString& url) {}
+
+ ///
+ /// Called when the page title changes.
+ ///
+ /*--cef(optional_param=title)--*/
+ virtual void OnTitleChange(CefRefPtr<CefBrowser> browser,
+ const CefString& title) {}
+
+ ///
+ /// Called when the page icon changes.
+ ///
+ /*--cef(optional_param=icon_urls)--*/
+ virtual void OnFaviconURLChange(CefRefPtr<CefBrowser> browser,
+ const std::vector<CefString>& icon_urls) {}
+
+ ///
+ /// Called when web content in the page has toggled fullscreen mode. If
+ /// |fullscreen| is true the content will automatically be sized to fill the
+ /// browser content area. If |fullscreen| is false the content will
+ /// automatically return to its original size and position. The client is
+ /// responsible for resizing the browser if desired.
+ ///
+ /*--cef()--*/
+ virtual void OnFullscreenModeChange(CefRefPtr<CefBrowser> browser,
+ bool fullscreen) {}
+
+ ///
+ /// Called when the browser is about to display a tooltip. |text| contains the
+ /// text that will be displayed in the tooltip. To handle the display of the
+ /// tooltip yourself return true. Otherwise, you can optionally modify |text|
+ /// and then return false to allow the browser to display the tooltip.
+ /// When window rendering is disabled the application is responsible for
+ /// drawing tooltips and the return value is ignored.
+ ///
+ /*--cef(optional_param=text)--*/
+ virtual bool OnTooltip(CefRefPtr<CefBrowser> browser, CefString& text) {
+ return false;
+ }
+
+ ///
+ /// Called when the browser receives a status message. |value| contains the
+ /// text that will be displayed in the status message.
+ ///
+ /*--cef(optional_param=value)--*/
+ virtual void OnStatusMessage(CefRefPtr<CefBrowser> browser,
+ const CefString& value) {}
+
+ ///
+ /// Called to display a console message. Return true to stop the message from
+ /// being output to the console.
+ ///
+ /*--cef(optional_param=message,optional_param=source)--*/
+ virtual bool OnConsoleMessage(CefRefPtr<CefBrowser> browser,
+ cef_log_severity_t level,
+ const CefString& message,
+ const CefString& source,
+ int line) {
+ return false;
+ }
+
+ ///
+ /// Called when auto-resize is enabled via
+ /// CefBrowserHost::SetAutoResizeEnabled and the contents have auto-resized.
+ /// |new_size| will be the desired size in view coordinates. Return true if
+ /// the resize was handled or false for default handling.
+ ///
+ /*--cef()--*/
+ virtual bool OnAutoResize(CefRefPtr<CefBrowser> browser,
+ const CefSize& new_size) {
+ return false;
+ }
+
+ ///
+ /// Called when the overall page loading progress has changed. |progress|
+ /// ranges from 0.0 to 1.0.
+ ///
+ /*--cef()--*/
+ virtual void OnLoadingProgressChange(CefRefPtr<CefBrowser> browser,
+ double progress) {}
+
+ ///
+ /// Called when the browser's cursor has changed. If |type| is CT_CUSTOM then
+ /// |custom_cursor_info| will be populated with the custom cursor information.
+ /// Return true if the cursor change was handled or false for default
+ /// handling.
+ ///
+ /*--cef()--*/
+ virtual bool OnCursorChange(CefRefPtr<CefBrowser> browser,
+ CefCursorHandle cursor,
+ cef_cursor_type_t type,
+ const CefCursorInfo& custom_cursor_info) {
+ return false;
+ }
+
+ ///
+ /// Called when the browser's access to an audio and/or video source has
+ /// changed.
+ ///
+ /*--cef()--*/
+ virtual void OnMediaAccessChange(CefRefPtr<CefBrowser> browser,
+ bool has_video_access,
+ bool has_audio_access) {}
+};
+
+#endif // CEF_INCLUDE_CEF_DISPLAY_HANDLER_H_
diff --git a/include/cef_dom.h b/include/cef_dom.h
new file mode 100644
index 00000000..0f5b2989
--- /dev/null
+++ b/include/cef_dom.h
@@ -0,0 +1,333 @@
+// Copyright (c) 2012 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_DOM_H_
+#define CEF_INCLUDE_CEF_DOM_H_
+#pragma once
+
+#include <map>
+#include "include/cef_base.h"
+
+class CefDOMDocument;
+class CefDOMNode;
+
+///
+/// Interface to implement for visiting the DOM. The methods of this class will
+/// be called on the render process main thread.
+///
+/*--cef(source=client)--*/
+class CefDOMVisitor : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Method executed for visiting the DOM. The document object passed to this
+ /// method represents a snapshot of the DOM at the time this method is
+ /// executed. DOM objects are only valid for the scope of this method. Do not
+ /// keep references to or attempt to access any DOM objects outside the scope
+ /// of this method.
+ ///
+ /*--cef()--*/
+ virtual void Visit(CefRefPtr<CefDOMDocument> document) = 0;
+};
+
+///
+/// Class used to represent a DOM document. The methods of this class should
+/// only be called on the render process main thread thread.
+///
+/*--cef(source=library)--*/
+class CefDOMDocument : public virtual CefBaseRefCounted {
+ public:
+ typedef cef_dom_document_type_t Type;
+
+ ///
+ /// Returns the document type.
+ ///
+ /*--cef(default_retval=DOM_DOCUMENT_TYPE_UNKNOWN)--*/
+ virtual Type GetType() = 0;
+
+ ///
+ /// Returns the root document node.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefDOMNode> GetDocument() = 0;
+
+ ///
+ /// Returns the BODY node of an HTML document.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefDOMNode> GetBody() = 0;
+
+ ///
+ /// Returns the HEAD node of an HTML document.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefDOMNode> GetHead() = 0;
+
+ ///
+ /// Returns the title of an HTML document.
+ ///
+ /*--cef()--*/
+ virtual CefString GetTitle() = 0;
+
+ ///
+ /// Returns the document element with the specified ID value.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefDOMNode> GetElementById(const CefString& id) = 0;
+
+ ///
+ /// Returns the node that currently has keyboard focus.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefDOMNode> GetFocusedNode() = 0;
+
+ ///
+ /// Returns true if a portion of the document is selected.
+ ///
+ /*--cef()--*/
+ virtual bool HasSelection() = 0;
+
+ ///
+ /// Returns the selection offset within the start node.
+ ///
+ /*--cef()--*/
+ virtual int GetSelectionStartOffset() = 0;
+
+ ///
+ /// Returns the selection offset within the end node.
+ ///
+ /*--cef()--*/
+ virtual int GetSelectionEndOffset() = 0;
+
+ ///
+ /// Returns the contents of this selection as markup.
+ ///
+ /*--cef()--*/
+ virtual CefString GetSelectionAsMarkup() = 0;
+
+ ///
+ /// Returns the contents of this selection as text.
+ ///
+ /*--cef()--*/
+ virtual CefString GetSelectionAsText() = 0;
+
+ ///
+ /// Returns the base URL for the document.
+ ///
+ /*--cef()--*/
+ virtual CefString GetBaseURL() = 0;
+
+ ///
+ /// Returns a complete URL based on the document base URL and the specified
+ /// partial URL.
+ ///
+ /*--cef()--*/
+ virtual CefString GetCompleteURL(const CefString& partialURL) = 0;
+};
+
+///
+/// Class used to represent a DOM node. The methods of this class should only be
+/// called on the render process main thread.
+///
+/*--cef(source=library)--*/
+class CefDOMNode : public virtual CefBaseRefCounted {
+ public:
+ typedef std::map<CefString, CefString> AttributeMap;
+ typedef cef_dom_node_type_t Type;
+
+ ///
+ /// Returns the type for this node.
+ ///
+ /*--cef(default_retval=DOM_NODE_TYPE_UNSUPPORTED)--*/
+ virtual Type GetType() = 0;
+
+ ///
+ /// Returns true if this is a text node.
+ ///
+ /*--cef()--*/
+ virtual bool IsText() = 0;
+
+ ///
+ /// Returns true if this is an element node.
+ ///
+ /*--cef()--*/
+ virtual bool IsElement() = 0;
+
+ ///
+ /// Returns true if this is an editable node.
+ ///
+ /*--cef()--*/
+ virtual bool IsEditable() = 0;
+
+ ///
+ /// Returns true if this is a form control element node.
+ ///
+ /*--cef()--*/
+ virtual bool IsFormControlElement() = 0;
+
+ ///
+ /// Returns the type of this form control element node.
+ ///
+ /*--cef()--*/
+ virtual CefString GetFormControlElementType() = 0;
+
+ ///
+ /// Returns true if this object is pointing to the same handle as |that|
+ /// object.
+ ///
+ /*--cef()--*/
+ virtual bool IsSame(CefRefPtr<CefDOMNode> that) = 0;
+
+ ///
+ /// Returns the name of this node.
+ ///
+ /*--cef()--*/
+ virtual CefString GetName() = 0;
+
+ ///
+ /// Returns the value of this node.
+ ///
+ /*--cef()--*/
+ virtual CefString GetValue() = 0;
+
+ ///
+ /// Set the value of this node. Returns true on success.
+ ///
+ /*--cef()--*/
+ virtual bool SetValue(const CefString& value) = 0;
+
+ ///
+ /// Returns the contents of this node as markup.
+ ///
+ /*--cef()--*/
+ virtual CefString GetAsMarkup() = 0;
+
+ ///
+ /// Returns the document associated with this node.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefDOMDocument> GetDocument() = 0;
+
+ ///
+ /// Returns the parent node.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefDOMNode> GetParent() = 0;
+
+ ///
+ /// Returns the previous sibling node.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefDOMNode> GetPreviousSibling() = 0;
+
+ ///
+ /// Returns the next sibling node.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefDOMNode> GetNextSibling() = 0;
+
+ ///
+ /// Returns true if this node has child nodes.
+ ///
+ /*--cef()--*/
+ virtual bool HasChildren() = 0;
+
+ ///
+ /// Return the first child node.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefDOMNode> GetFirstChild() = 0;
+
+ ///
+ /// Returns the last child node.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefDOMNode> GetLastChild() = 0;
+
+ // The following methods are valid only for element nodes.
+
+ ///
+ /// Returns the tag name of this element.
+ ///
+ /*--cef()--*/
+ virtual CefString GetElementTagName() = 0;
+
+ ///
+ /// Returns true if this element has attributes.
+ ///
+ /*--cef()--*/
+ virtual bool HasElementAttributes() = 0;
+
+ ///
+ /// Returns true if this element has an attribute named |attrName|.
+ ///
+ /*--cef()--*/
+ virtual bool HasElementAttribute(const CefString& attrName) = 0;
+
+ ///
+ /// Returns the element attribute named |attrName|.
+ ///
+ /*--cef()--*/
+ virtual CefString GetElementAttribute(const CefString& attrName) = 0;
+
+ ///
+ /// Returns a map of all element attributes.
+ ///
+ /*--cef()--*/
+ virtual void GetElementAttributes(AttributeMap& attrMap) = 0;
+
+ ///
+ /// Set the value for the element attribute named |attrName|. Returns true on
+ /// success.
+ ///
+ /*--cef()--*/
+ virtual bool SetElementAttribute(const CefString& attrName,
+ const CefString& value) = 0;
+
+ ///
+ /// Returns the inner text of the element.
+ ///
+ /*--cef()--*/
+ virtual CefString GetElementInnerText() = 0;
+
+ ///
+ /// Returns the bounds of the element in device pixels. Use
+ /// "window.devicePixelRatio" to convert to/from CSS pixels.
+ ///
+ /*--cef()--*/
+ virtual CefRect GetElementBounds() = 0;
+};
+
+#endif // CEF_INCLUDE_CEF_DOM_H_
diff --git a/include/cef_download_handler.h b/include/cef_download_handler.h
new file mode 100644
index 00000000..de911b66
--- /dev/null
+++ b/include/cef_download_handler.h
@@ -0,0 +1,134 @@
+// Copyright (c) 2012 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_DOWNLOAD_HANDLER_H_
+#define CEF_INCLUDE_CEF_DOWNLOAD_HANDLER_H_
+#pragma once
+
+#include "include/cef_base.h"
+#include "include/cef_browser.h"
+#include "include/cef_download_item.h"
+
+///
+/// Callback interface used to asynchronously continue a download.
+///
+/*--cef(source=library)--*/
+class CefBeforeDownloadCallback : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Call to continue the download. Set |download_path| to the full file path
+ /// for the download including the file name or leave blank to use the
+ /// suggested name and the default temp directory. Set |show_dialog| to true
+ /// if you do wish to show the default "Save As" dialog.
+ ///
+ /*--cef(capi_name=cont,optional_param=download_path)--*/
+ virtual void Continue(const CefString& download_path, bool show_dialog) = 0;
+};
+
+///
+/// Callback interface used to asynchronously cancel a download.
+///
+/*--cef(source=library)--*/
+class CefDownloadItemCallback : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Call to cancel the download.
+ ///
+ /*--cef()--*/
+ virtual void Cancel() = 0;
+
+ ///
+ /// Call to pause the download.
+ ///
+ /*--cef()--*/
+ virtual void Pause() = 0;
+
+ ///
+ /// Call to resume the download.
+ ///
+ /*--cef()--*/
+ virtual void Resume() = 0;
+};
+
+///
+/// Class used to handle file downloads. The methods of this class will called
+/// on the browser process UI thread.
+///
+/*--cef(source=client)--*/
+class CefDownloadHandler : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Called before a download begins in response to a user-initiated action
+ /// (e.g. alt + link click or link click that returns a `Content-Disposition:
+ /// attachment` response from the server). |url| is the target download URL
+ /// and |request_method| is the target method (GET, POST, etc). Return true to
+ /// proceed with the download or false to cancel the download.
+ ///
+ /*--cef()--*/
+ virtual bool CanDownload(CefRefPtr<CefBrowser> browser,
+ const CefString& url,
+ const CefString& request_method) {
+ return true;
+ }
+
+ ///
+ /// Called before a download begins. |suggested_name| is the suggested name
+ /// for the download file. By default the download will be canceled. Execute
+ /// |callback| either asynchronously or in this method to continue the
+ /// download if desired. Do not keep a reference to |download_item| outside of
+ /// this method.
+ ///
+ /*--cef()--*/
+ virtual void OnBeforeDownload(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefDownloadItem> download_item,
+ const CefString& suggested_name,
+ CefRefPtr<CefBeforeDownloadCallback> callback) = 0;
+
+ ///
+ /// Called when a download's status or progress information has been updated.
+ /// This may be called multiple times before and after OnBeforeDownload().
+ /// Execute |callback| either asynchronously or in this method to cancel the
+ /// download if desired. Do not keep a reference to |download_item| outside of
+ /// this method.
+ ///
+ /*--cef()--*/
+ virtual void OnDownloadUpdated(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefDownloadItem> download_item,
+ CefRefPtr<CefDownloadItemCallback> callback) {}
+};
+
+#endif // CEF_INCLUDE_CEF_DOWNLOAD_HANDLER_H_
diff --git a/include/cef_download_item.h b/include/cef_download_item.h
new file mode 100644
index 00000000..bde3ac53
--- /dev/null
+++ b/include/cef_download_item.h
@@ -0,0 +1,154 @@
+// Copyright (c) 2012 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_DOWNLOAD_ITEM_H_
+#define CEF_INCLUDE_CEF_DOWNLOAD_ITEM_H_
+#pragma once
+
+#include "include/cef_base.h"
+
+///
+/// Class used to represent a download item.
+///
+/*--cef(source=library)--*/
+class CefDownloadItem : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Returns true if this object is valid. Do not call any other methods if
+ /// this function returns false.
+ ///
+ /*--cef()--*/
+ virtual bool IsValid() = 0;
+
+ ///
+ /// Returns true if the download is in progress.
+ ///
+ /*--cef()--*/
+ virtual bool IsInProgress() = 0;
+
+ ///
+ /// Returns true if the download is complete.
+ ///
+ /*--cef()--*/
+ virtual bool IsComplete() = 0;
+
+ ///
+ /// Returns true if the download has been canceled or interrupted.
+ ///
+ /*--cef()--*/
+ virtual bool IsCanceled() = 0;
+
+ ///
+ /// Returns a simple speed estimate in bytes/s.
+ ///
+ /*--cef()--*/
+ virtual int64 GetCurrentSpeed() = 0;
+
+ ///
+ /// Returns the rough percent complete or -1 if the receive total size is
+ /// unknown.
+ ///
+ /*--cef()--*/
+ virtual int GetPercentComplete() = 0;
+
+ ///
+ /// Returns the total number of bytes.
+ ///
+ /*--cef()--*/
+ virtual int64 GetTotalBytes() = 0;
+
+ ///
+ /// Returns the number of received bytes.
+ ///
+ /*--cef()--*/
+ virtual int64 GetReceivedBytes() = 0;
+
+ ///
+ /// Returns the time that the download started.
+ ///
+ /*--cef()--*/
+ virtual CefBaseTime GetStartTime() = 0;
+
+ ///
+ /// Returns the time that the download ended.
+ ///
+ /*--cef()--*/
+ virtual CefBaseTime GetEndTime() = 0;
+
+ ///
+ /// Returns the full path to the downloaded or downloading file.
+ ///
+ /*--cef()--*/
+ virtual CefString GetFullPath() = 0;
+
+ ///
+ /// Returns the unique identifier for this download.
+ ///
+ /*--cef()--*/
+ virtual uint32 GetId() = 0;
+
+ ///
+ /// Returns the URL.
+ ///
+ /*--cef()--*/
+ virtual CefString GetURL() = 0;
+
+ ///
+ /// Returns the original URL before any redirections.
+ ///
+ /*--cef()--*/
+ virtual CefString GetOriginalUrl() = 0;
+
+ ///
+ /// Returns the suggested file name.
+ ///
+ /*--cef()--*/
+ virtual CefString GetSuggestedFileName() = 0;
+
+ ///
+ /// Returns the content disposition.
+ ///
+ /*--cef()--*/
+ virtual CefString GetContentDisposition() = 0;
+
+ ///
+ /// Returns the mime type.
+ ///
+ /*--cef()--*/
+ virtual CefString GetMimeType() = 0;
+};
+
+#endif // CEF_INCLUDE_CEF_DOWNLOAD_ITEM_H_
diff --git a/include/cef_drag_data.h b/include/cef_drag_data.h
new file mode 100644
index 00000000..7a41a50c
--- /dev/null
+++ b/include/cef_drag_data.h
@@ -0,0 +1,225 @@
+// Copyright (c) 2013 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_DRAG_DATA_H_
+#define CEF_INCLUDE_CEF_DRAG_DATA_H_
+#pragma once
+
+#include <vector>
+#include "include/cef_base.h"
+#include "include/cef_image.h"
+#include "include/cef_stream.h"
+
+///
+/// Class used to represent drag data. The methods of this class may be called
+/// on any thread.
+///
+/*--cef(source=library)--*/
+class CefDragData : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Create a new CefDragData object.
+ ///
+ /*--cef()--*/
+ static CefRefPtr<CefDragData> Create();
+
+ ///
+ /// Returns a copy of the current object.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefDragData> Clone() = 0;
+
+ ///
+ /// Returns true if this object is read-only.
+ ///
+ /*--cef()--*/
+ virtual bool IsReadOnly() = 0;
+
+ ///
+ /// Returns true if the drag data is a link.
+ ///
+ /*--cef()--*/
+ virtual bool IsLink() = 0;
+
+ ///
+ /// Returns true if the drag data is a text or html fragment.
+ ///
+ /*--cef()--*/
+ virtual bool IsFragment() = 0;
+
+ ///
+ /// Returns true if the drag data is a file.
+ ///
+ /*--cef()--*/
+ virtual bool IsFile() = 0;
+
+ ///
+ /// Return the link URL that is being dragged.
+ ///
+ /*--cef()--*/
+ virtual CefString GetLinkURL() = 0;
+
+ ///
+ /// Return the title associated with the link being dragged.
+ ///
+ /*--cef()--*/
+ virtual CefString GetLinkTitle() = 0;
+
+ ///
+ /// Return the metadata, if any, associated with the link being dragged.
+ ///
+ /*--cef()--*/
+ virtual CefString GetLinkMetadata() = 0;
+
+ ///
+ /// Return the plain text fragment that is being dragged.
+ ///
+ /*--cef()--*/
+ virtual CefString GetFragmentText() = 0;
+
+ ///
+ /// Return the text/html fragment that is being dragged.
+ ///
+ /*--cef()--*/
+ virtual CefString GetFragmentHtml() = 0;
+
+ ///
+ /// Return the base URL that the fragment came from. This value is used for
+ /// resolving relative URLs and may be empty.
+ ///
+ /*--cef()--*/
+ virtual CefString GetFragmentBaseURL() = 0;
+
+ ///
+ /// Return the name of the file being dragged out of the browser window.
+ ///
+ /*--cef()--*/
+ virtual CefString GetFileName() = 0;
+
+ ///
+ /// Write the contents of the file being dragged out of the web view into
+ /// |writer|. Returns the number of bytes sent to |writer|. If |writer| is
+ /// NULL this method will return the size of the file contents in bytes.
+ /// Call GetFileName() to get a suggested name for the file.
+ ///
+ /*--cef(optional_param=writer)--*/
+ virtual size_t GetFileContents(CefRefPtr<CefStreamWriter> writer) = 0;
+
+ ///
+ /// Retrieve the list of file names that are being dragged into the browser
+ /// window.
+ ///
+ /*--cef()--*/
+ virtual bool GetFileNames(std::vector<CefString>& names) = 0;
+
+ ///
+ /// Set the link URL that is being dragged.
+ ///
+ /*--cef(optional_param=url)--*/
+ virtual void SetLinkURL(const CefString& url) = 0;
+
+ ///
+ /// Set the title associated with the link being dragged.
+ ///
+ /*--cef(optional_param=title)--*/
+ virtual void SetLinkTitle(const CefString& title) = 0;
+
+ ///
+ /// Set the metadata associated with the link being dragged.
+ ///
+ /*--cef(optional_param=data)--*/
+ virtual void SetLinkMetadata(const CefString& data) = 0;
+
+ ///
+ /// Set the plain text fragment that is being dragged.
+ ///
+ /*--cef(optional_param=text)--*/
+ virtual void SetFragmentText(const CefString& text) = 0;
+
+ ///
+ /// Set the text/html fragment that is being dragged.
+ ///
+ /*--cef(optional_param=html)--*/
+ virtual void SetFragmentHtml(const CefString& html) = 0;
+
+ ///
+ /// Set the base URL that the fragment came from.
+ ///
+ /*--cef(optional_param=base_url)--*/
+ virtual void SetFragmentBaseURL(const CefString& base_url) = 0;
+
+ ///
+ /// Reset the file contents. You should do this before calling
+ /// CefBrowserHost::DragTargetDragEnter as the web view does not allow us to
+ /// drag in this kind of data.
+ ///
+ /*--cef()--*/
+ virtual void ResetFileContents() = 0;
+
+ ///
+ /// Add a file that is being dragged into the webview.
+ ///
+ /*--cef(optional_param=display_name)--*/
+ virtual void AddFile(const CefString& path,
+ const CefString& display_name) = 0;
+
+ ///
+ /// Clear list of filenames.
+ ///
+ /*--cef()--*/
+ virtual void ClearFilenames() = 0;
+
+ ///
+ /// Get the image representation of drag data. May return NULL if no image
+ /// representation is available.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefImage> GetImage() = 0;
+
+ ///
+ /// Get the image hotspot (drag start location relative to image dimensions).
+ ///
+ /*--cef()--*/
+ virtual CefPoint GetImageHotspot() = 0;
+
+ ///
+ /// Returns true if an image representation of drag data is available.
+ ///
+ /*--cef()--*/
+ virtual bool HasImage() = 0;
+};
+
+#endif // CEF_INCLUDE_CEF_DRAG_DATA_H_
diff --git a/include/cef_drag_handler.h b/include/cef_drag_handler.h
new file mode 100644
index 00000000..cd354d78
--- /dev/null
+++ b/include/cef_drag_handler.h
@@ -0,0 +1,82 @@
+// Copyright (c) 2013 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_DRAG_HANDLER_H_
+#define CEF_INCLUDE_CEF_DRAG_HANDLER_H_
+#pragma once
+
+#include "include/cef_base.h"
+#include "include/cef_browser.h"
+#include "include/cef_drag_data.h"
+#include "include/cef_frame.h"
+
+///
+/// Implement this interface to handle events related to dragging. The methods
+/// of this class will be called on the UI thread.
+///
+/*--cef(source=client)--*/
+class CefDragHandler : public virtual CefBaseRefCounted {
+ public:
+ typedef cef_drag_operations_mask_t DragOperationsMask;
+
+ ///
+ /// Called when an external drag event enters the browser window. |dragData|
+ /// contains the drag event data and |mask| represents the type of drag
+ /// operation. Return false for default drag handling behavior or true to
+ /// cancel the drag event.
+ ///
+ /*--cef()--*/
+ virtual bool OnDragEnter(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefDragData> dragData,
+ DragOperationsMask mask) {
+ return false;
+ }
+
+ ///
+ /// Called whenever draggable regions for the browser window change. These can
+ /// be specified using the '-webkit-app-region: drag/no-drag' CSS-property. If
+ /// draggable regions are never defined in a document this method will also
+ /// never be called. If the last draggable region is removed from a document
+ /// this method will be called with an empty vector.
+ ///
+ /*--cef()--*/
+ virtual void OnDraggableRegionsChanged(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const std::vector<CefDraggableRegion>& regions) {}
+};
+
+#endif // CEF_INCLUDE_CEF_DRAG_HANDLER_H_
diff --git a/include/cef_extension.h b/include/cef_extension.h
new file mode 100644
index 00000000..5d94192f
--- /dev/null
+++ b/include/cef_extension.h
@@ -0,0 +1,118 @@
+// Copyright (c) 2017 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_EXTENSION_H_
+#define CEF_INCLUDE_CEF_EXTENSION_H_
+#pragma once
+
+#include "include/cef_base.h"
+#include "include/cef_values.h"
+
+class CefExtensionHandler;
+class CefRequestContext;
+
+///
+/// Object representing an extension. Methods may be called on any thread unless
+/// otherwise indicated.
+///
+/*--cef(source=library)--*/
+class CefExtension : public CefBaseRefCounted {
+ public:
+ ///
+ /// Returns the unique extension identifier. This is calculated based on the
+ /// extension public key, if available, or on the extension path. See
+ /// https://developer.chrome.com/extensions/manifest/key for details.
+ ///
+ /*--cef()--*/
+ virtual CefString GetIdentifier() = 0;
+
+ ///
+ /// Returns the absolute path to the extension directory on disk. This value
+ /// will be prefixed with PK_DIR_RESOURCES if a relative path was passed to
+ /// CefRequestContext::LoadExtension.
+ ///
+ /*--cef()--*/
+ virtual CefString GetPath() = 0;
+
+ ///
+ /// Returns the extension manifest contents as a CefDictionaryValue object.
+ /// See https://developer.chrome.com/extensions/manifest for details.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefDictionaryValue> GetManifest() = 0;
+
+ ///
+ /// Returns true if this object is the same extension as |that| object.
+ /// Extensions are considered the same if identifier, path and loader context
+ /// match.
+ ///
+ /*--cef()--*/
+ virtual bool IsSame(CefRefPtr<CefExtension> that) = 0;
+
+ ///
+ /// Returns the handler for this extension. Will return NULL for internal
+ /// extensions or if no handler was passed to
+ /// CefRequestContext::LoadExtension.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefExtensionHandler> GetHandler() = 0;
+
+ ///
+ /// Returns the request context that loaded this extension. Will return NULL
+ /// for internal extensions or if the extension has been unloaded. See the
+ /// CefRequestContext::LoadExtension documentation for more information about
+ /// loader contexts. Must be called on the browser process UI thread.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefRequestContext> GetLoaderContext() = 0;
+
+ ///
+ /// Returns true if this extension is currently loaded. Must be called on the
+ /// browser process UI thread.
+ ///
+ /*--cef()--*/
+ virtual bool IsLoaded() = 0;
+
+ ///
+ /// Unload this extension if it is not an internal extension and is currently
+ /// loaded. Will result in a call to CefExtensionHandler::OnExtensionUnloaded
+ /// on success.
+ ///
+ /*--cef()--*/
+ virtual void Unload() = 0;
+};
+
+#endif // CEF_INCLUDE_CEF_EXTENSION_H_
diff --git a/include/cef_extension_handler.h b/include/cef_extension_handler.h
new file mode 100644
index 00000000..4b34fbc0
--- /dev/null
+++ b/include/cef_extension_handler.h
@@ -0,0 +1,200 @@
+// Copyright (c) 2017 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_EXTENSION_HANDLER_H_
+#define CEF_INCLUDE_CEF_EXTENSION_HANDLER_H_
+#pragma once
+
+#include "include/cef_base.h"
+#include "include/cef_browser.h"
+#include "include/cef_extension.h"
+#include "include/cef_stream.h"
+
+class CefClient;
+
+///
+/// Callback interface used for asynchronous continuation of
+/// CefExtensionHandler::GetExtensionResource.
+///
+/*--cef(source=library)--*/
+class CefGetExtensionResourceCallback : public CefBaseRefCounted {
+ public:
+ ///
+ /// Continue the request. Read the resource contents from |stream|.
+ ///
+ /*--cef(capi_name=cont,optional_param=stream)--*/
+ virtual void Continue(CefRefPtr<CefStreamReader> stream) = 0;
+
+ ///
+ /// Cancel the request.
+ ///
+ /*--cef()--*/
+ virtual void Cancel() = 0;
+};
+
+///
+/// Implement this interface to handle events related to browser extensions.
+/// The methods of this class will be called on the UI thread. See
+/// CefRequestContext::LoadExtension for information about extension loading.
+///
+/*--cef(source=client)--*/
+class CefExtensionHandler : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Called if the CefRequestContext::LoadExtension request fails. |result|
+ /// will be the error code.
+ ///
+ /*--cef()--*/
+ virtual void OnExtensionLoadFailed(cef_errorcode_t result) {}
+
+ ///
+ /// Called if the CefRequestContext::LoadExtension request succeeds.
+ /// |extension| is the loaded extension.
+ ///
+ /*--cef()--*/
+ virtual void OnExtensionLoaded(CefRefPtr<CefExtension> extension) {}
+
+ ///
+ /// Called after the CefExtension::Unload request has completed.
+ ///
+ /*--cef()--*/
+ virtual void OnExtensionUnloaded(CefRefPtr<CefExtension> extension) {}
+
+ ///
+ /// Called when an extension needs a browser to host a background script
+ /// specified via the "background" manifest key. The browser will have no
+ /// visible window and cannot be displayed. |extension| is the extension that
+ /// is loading the background script. |url| is an internally generated
+ /// reference to an HTML page that will be used to load the background script
+ /// via a "<script>" src attribute. To allow creation of the browser
+ /// optionally modify |client| and |settings| and return false. To cancel
+ /// creation of the browser (and consequently cancel load of the background
+ /// script) return true. Successful creation will be indicated by a call to
+ /// CefLifeSpanHandler::OnAfterCreated, and CefBrowserHost::IsBackgroundHost
+ /// will return true for the resulting browser. See
+ /// https://developer.chrome.com/extensions/event_pages for more information
+ /// about extension background script usage.
+ ///
+ /*--cef()--*/
+ virtual bool OnBeforeBackgroundBrowser(CefRefPtr<CefExtension> extension,
+ const CefString& url,
+ CefRefPtr<CefClient>& client,
+ CefBrowserSettings& settings) {
+ return false;
+ }
+
+ ///
+ /// Called when an extension API (e.g. chrome.tabs.create) requests creation
+ /// of a new browser. |extension| and |browser| are the source of the API
+ /// call. |active_browser| may optionally be specified via the windowId
+ /// property or returned via the GetActiveBrowser() callback and provides the
+ /// default |client| and |settings| values for the new browser. |index| is the
+ /// position value optionally specified via the index property. |url| is the
+ /// URL that will be loaded in the browser. |active| is true if the new
+ /// browser should be active when opened. To allow creation of the browser
+ /// optionally modify |windowInfo|, |client| and |settings| and return false.
+ /// To cancel creation of the browser return true. Successful creation will be
+ /// indicated by a call to CefLifeSpanHandler::OnAfterCreated. Any
+ /// modifications to |windowInfo| will be ignored if |active_browser| is
+ /// wrapped in a CefBrowserView.
+ ///
+ /*--cef()--*/
+ virtual bool OnBeforeBrowser(CefRefPtr<CefExtension> extension,
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefBrowser> active_browser,
+ int index,
+ const CefString& url,
+ bool active,
+ CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient>& client,
+ CefBrowserSettings& settings) {
+ return false;
+ }
+
+ ///
+ /// Called when no tabId is specified to an extension API call that accepts a
+ /// tabId parameter (e.g. chrome.tabs.*). |extension| and |browser| are the
+ /// source of the API call. Return the browser that will be acted on by the
+ /// API call or return NULL to act on |browser|. The returned browser must
+ /// share the same CefRequestContext as |browser|. Incognito browsers should
+ /// not be considered unless the source extension has incognito access
+ /// enabled, in which case |include_incognito| will be true.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefBrowser> GetActiveBrowser(
+ CefRefPtr<CefExtension> extension,
+ CefRefPtr<CefBrowser> browser,
+ bool include_incognito) {
+ return nullptr;
+ }
+
+ ///
+ /// Called when the tabId associated with |target_browser| is specified to an
+ /// extension API call that accepts a tabId parameter (e.g. chrome.tabs.*).
+ /// |extension| and |browser| are the source of the API call. Return true
+ /// to allow access of false to deny access. Access to incognito browsers
+ /// should not be allowed unless the source extension has incognito access
+ /// enabled, in which case |include_incognito| will be true.
+ ///
+ /*--cef()--*/
+ virtual bool CanAccessBrowser(CefRefPtr<CefExtension> extension,
+ CefRefPtr<CefBrowser> browser,
+ bool include_incognito,
+ CefRefPtr<CefBrowser> target_browser) {
+ return true;
+ }
+
+ ///
+ /// Called to retrieve an extension resource that would normally be loaded
+ /// from disk (e.g. if a file parameter is specified to
+ /// chrome.tabs.executeScript). |extension| and |browser| are the source of
+ /// the resource request. |file| is the requested relative file path. To
+ /// handle the resource request return true and execute |callback| either
+ /// synchronously or asynchronously. For the default behavior which reads the
+ /// resource from the extension directory on disk return false. Localization
+ /// substitutions will not be applied to resources handled via this method.
+ ///
+ /*--cef()--*/
+ virtual bool GetExtensionResource(
+ CefRefPtr<CefExtension> extension,
+ CefRefPtr<CefBrowser> browser,
+ const CefString& file,
+ CefRefPtr<CefGetExtensionResourceCallback> callback) {
+ return false;
+ }
+};
+
+#endif // CEF_INCLUDE_CEF_EXTENSION_HANDLER_H_
diff --git a/include/cef_file_util.h b/include/cef_file_util.h
new file mode 100644
index 00000000..838bdc19
--- /dev/null
+++ b/include/cef_file_util.h
@@ -0,0 +1,130 @@
+// Copyright (c) 2016 Marshall A. Greenblatt. Portions copyright (c) 2012
+// Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_FILE_UTIL_H_
+#define CEF_INCLUDE_CEF_FILE_UTIL_H_
+#pragma once
+
+#include "include/cef_base.h"
+
+///
+/// Creates a directory and all parent directories if they don't already exist.
+/// Returns true on successful creation or if the directory already exists. The
+/// directory is only readable by the current user. Calling this function on the
+/// browser process UI or IO threads is not allowed.
+///
+/*--cef()--*/
+bool CefCreateDirectory(const CefString& full_path);
+
+///
+/// Get the temporary directory provided by the system.
+///
+/// WARNING: In general, you should use the temp directory variants below
+/// instead of this function. Those variants will ensure that the proper
+/// permissions are set so that other users on the system can't edit them while
+/// they're open (which could lead to security issues).
+///
+/*--cef()--*/
+bool CefGetTempDirectory(CefString& temp_dir);
+
+///
+/// Creates a new directory. On Windows if |prefix| is provided the new
+/// directory name is in the format of "prefixyyyy". Returns true on success and
+/// sets |new_temp_path| to the full path of the directory that was created. The
+/// directory is only readable by the current user. Calling this function on the
+/// browser process UI or IO threads is not allowed.
+///
+/*--cef(optional_param=prefix)--*/
+bool CefCreateNewTempDirectory(const CefString& prefix,
+ CefString& new_temp_path);
+
+///
+/// Creates a directory within another directory. Extra characters will be
+/// appended to |prefix| to ensure that the new directory does not have the same
+/// name as an existing directory. Returns true on success and sets |new_dir| to
+/// the full path of the directory that was created. The directory is only
+/// readable by the current user. Calling this function on the browser process
+/// UI or IO threads is not allowed.
+///
+/*--cef(optional_param=prefix)--*/
+bool CefCreateTempDirectoryInDirectory(const CefString& base_dir,
+ const CefString& prefix,
+ CefString& new_dir);
+
+///
+/// Returns true if the given path exists and is a directory. Calling this
+/// function on the browser process UI or IO threads is not allowed.
+///
+/*--cef()--*/
+bool CefDirectoryExists(const CefString& path);
+
+///
+/// Deletes the given path whether it's a file or a directory. If |path| is a
+/// directory all contents will be deleted. If |recursive| is true any sub-
+/// directories and their contents will also be deleted (equivalent to executing
+/// "rm -rf", so use with caution). On POSIX environments if |path| is a
+/// symbolic link then only the symlink will be deleted. Returns true on
+/// successful deletion or if |path| does not exist. Calling this function on
+/// the browser process UI or IO threads is not allowed.
+///
+/*--cef()--*/
+bool CefDeleteFile(const CefString& path, bool recursive);
+
+///
+/// Writes the contents of |src_dir| into a zip archive at |dest_file|. If
+/// |include_hidden_files| is true files starting with "." will be included.
+/// Returns true on success. Calling this function on the browser process UI or
+/// IO threads is not allowed.
+///
+/*--cef()--*/
+bool CefZipDirectory(const CefString& src_dir,
+ const CefString& dest_file,
+ bool include_hidden_files);
+
+///
+/// Loads the existing "Certificate Revocation Lists" file that is managed by
+/// Google Chrome. This file can generally be found in Chrome's User Data
+/// directory (e.g. "C:\Users\[User]\AppData\Local\Google\Chrome\User Data\" on
+/// Windows) and is updated periodically by Chrome's component updater service.
+/// Must be called in the browser process after the context has been
+/// initialized. See https://dev.chromium.org/Home/chromium-security/crlsets for
+/// background.
+///
+/*--cef()--*/
+void CefLoadCRLSetsFile(const CefString& path);
+
+#endif // CEF_INCLUDE_CEF_FILE_UTIL_H_
diff --git a/include/cef_find_handler.h b/include/cef_find_handler.h
new file mode 100644
index 00000000..bd3a700c
--- /dev/null
+++ b/include/cef_find_handler.h
@@ -0,0 +1,68 @@
+// Copyright (c) 2015 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_FIND_HANDLER_H_
+#define CEF_INCLUDE_CEF_FIND_HANDLER_H_
+#pragma once
+
+#include "include/cef_base.h"
+#include "include/cef_browser.h"
+
+///
+/// Implement this interface to handle events related to find results. The
+/// methods of this class will be called on the UI thread.
+///
+/*--cef(source=client)--*/
+class CefFindHandler : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Called to report find results returned by CefBrowserHost::Find().
+ /// |identifer| is a unique incremental identifier for the currently active
+ /// search, |count| is the number of matches currently identified,
+ /// |selectionRect| is the location of where the match was found (in window
+ /// coordinates), |activeMatchOrdinal| is the current position in the search
+ /// results, and |finalUpdate| is true if this is the last find notification.
+ ///
+ /*--cef()--*/
+ virtual void OnFindResult(CefRefPtr<CefBrowser> browser,
+ int identifier,
+ int count,
+ const CefRect& selectionRect,
+ int activeMatchOrdinal,
+ bool finalUpdate) {}
+};
+
+#endif // CEF_INCLUDE_CEF_FIND_HANDLER_H_
diff --git a/include/cef_focus_handler.h b/include/cef_focus_handler.h
new file mode 100644
index 00000000..5f05e504
--- /dev/null
+++ b/include/cef_focus_handler.h
@@ -0,0 +1,81 @@
+// Copyright (c) 2012 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_FOCUS_HANDLER_H_
+#define CEF_INCLUDE_CEF_FOCUS_HANDLER_H_
+#pragma once
+
+#include "include/cef_base.h"
+#include "include/cef_browser.h"
+#include "include/cef_dom.h"
+#include "include/cef_frame.h"
+
+///
+/// Implement this interface to handle events related to focus. The methods of
+/// this class will be called on the UI thread.
+///
+/*--cef(source=client)--*/
+class CefFocusHandler : public virtual CefBaseRefCounted {
+ public:
+ typedef cef_focus_source_t FocusSource;
+
+ ///
+ /// Called when the browser component is about to loose focus. For instance,
+ /// if focus was on the last HTML element and the user pressed the TAB key.
+ /// |next| will be true if the browser is giving focus to the next component
+ /// and false if the browser is giving focus to the previous component.
+ ///
+ /*--cef()--*/
+ virtual void OnTakeFocus(CefRefPtr<CefBrowser> browser, bool next) {}
+
+ ///
+ /// Called when the browser component is requesting focus. |source| indicates
+ /// where the focus request is originating from. Return false to allow the
+ /// focus to be set or true to cancel setting the focus.
+ ///
+ /*--cef()--*/
+ virtual bool OnSetFocus(CefRefPtr<CefBrowser> browser, FocusSource source) {
+ return false;
+ }
+
+ ///
+ /// Called when the browser component has received focus.
+ ///
+ /*--cef()--*/
+ virtual void OnGotFocus(CefRefPtr<CefBrowser> browser) {}
+};
+
+#endif // CEF_INCLUDE_CEF_FOCUS_HANDLER_H_
diff --git a/include/cef_frame.h b/include/cef_frame.h
new file mode 100644
index 00000000..a3c6eab6
--- /dev/null
+++ b/include/cef_frame.h
@@ -0,0 +1,263 @@
+// Copyright (c) 2012 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_FRAME_H_
+#define CEF_INCLUDE_CEF_FRAME_H_
+#pragma once
+
+#include "include/cef_base.h"
+#include "include/cef_dom.h"
+#include "include/cef_process_message.h"
+#include "include/cef_request.h"
+#include "include/cef_stream.h"
+#include "include/cef_string_visitor.h"
+
+class CefBrowser;
+class CefURLRequest;
+class CefURLRequestClient;
+class CefV8Context;
+
+///
+/// Class used to represent a frame in the browser window. When used in the
+/// browser process the methods of this class may be called on any thread unless
+/// otherwise indicated in the comments. When used in the render process the
+/// methods of this class may only be called on the main thread.
+///
+/*--cef(source=library)--*/
+class CefFrame : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// True if this object is currently attached to a valid frame.
+ ///
+ /*--cef()--*/
+ virtual bool IsValid() = 0;
+
+ ///
+ /// Execute undo in this frame.
+ ///
+ /*--cef()--*/
+ virtual void Undo() = 0;
+
+ ///
+ /// Execute redo in this frame.
+ ///
+ /*--cef()--*/
+ virtual void Redo() = 0;
+
+ ///
+ /// Execute cut in this frame.
+ ///
+ /*--cef()--*/
+ virtual void Cut() = 0;
+
+ ///
+ /// Execute copy in this frame.
+ ///
+ /*--cef()--*/
+ virtual void Copy() = 0;
+
+ ///
+ /// Execute paste in this frame.
+ ///
+ /*--cef()--*/
+ virtual void Paste() = 0;
+
+ ///
+ /// Execute delete in this frame.
+ ///
+ /*--cef(capi_name=del)--*/
+ virtual void Delete() = 0;
+
+ ///
+ /// Execute select all in this frame.
+ ///
+ /*--cef()--*/
+ virtual void SelectAll() = 0;
+
+ ///
+ /// Save this frame's HTML source to a temporary file and open it in the
+ /// default text viewing application. This method can only be called from the
+ /// browser process.
+ ///
+ /*--cef()--*/
+ virtual void ViewSource() = 0;
+
+ ///
+ /// Retrieve this frame's HTML source as a string sent to the specified
+ /// visitor.
+ ///
+ /*--cef()--*/
+ virtual void GetSource(CefRefPtr<CefStringVisitor> visitor) = 0;
+
+ ///
+ /// Retrieve this frame's display text as a string sent to the specified
+ /// visitor.
+ ///
+ /*--cef()--*/
+ virtual void GetText(CefRefPtr<CefStringVisitor> visitor) = 0;
+
+ ///
+ /// Load the request represented by the |request| object.
+ ///
+ /// WARNING: This method will fail with "bad IPC message" reason
+ /// INVALID_INITIATOR_ORIGIN (213) unless you first navigate to the
+ /// request origin using some other mechanism (LoadURL, link click, etc).
+ ///
+ /*--cef()--*/
+ virtual void LoadRequest(CefRefPtr<CefRequest> request) = 0;
+
+ ///
+ /// Load the specified |url|.
+ ///
+ /*--cef()--*/
+ virtual void LoadURL(const CefString& url) = 0;
+
+ ///
+ /// Execute a string of JavaScript code in this frame. The |script_url|
+ /// parameter is the URL where the script in question can be found, if any.
+ /// The renderer may request this URL to show the developer the source of the
+ /// error. The |start_line| parameter is the base line number to use for
+ /// error reporting.
+ ///
+ /*--cef(optional_param=script_url)--*/
+ virtual void ExecuteJavaScript(const CefString& code,
+ const CefString& script_url,
+ int start_line) = 0;
+
+ ///
+ /// Returns true if this is the main (top-level) frame.
+ ///
+ /*--cef()--*/
+ virtual bool IsMain() = 0;
+
+ ///
+ /// Returns true if this is the focused frame.
+ ///
+ /*--cef()--*/
+ virtual bool IsFocused() = 0;
+
+ ///
+ /// Returns the name for this frame. If the frame has an assigned name (for
+ /// example, set via the iframe "name" attribute) then that value will be
+ /// returned. Otherwise a unique name will be constructed based on the frame
+ /// parent hierarchy. The main (top-level) frame will always have an empty
+ /// name value.
+ ///
+ /*--cef()--*/
+ virtual CefString GetName() = 0;
+
+ ///
+ /// Returns the globally unique identifier for this frame or < 0 if the
+ /// underlying frame does not yet exist.
+ ///
+ /*--cef()--*/
+ virtual int64 GetIdentifier() = 0;
+
+ ///
+ /// Returns the parent of this frame or NULL if this is the main (top-level)
+ /// frame.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefFrame> GetParent() = 0;
+
+ ///
+ /// Returns the URL currently loaded in this frame.
+ ///
+ /*--cef()--*/
+ virtual CefString GetURL() = 0;
+
+ ///
+ /// Returns the browser that this frame belongs to.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefBrowser> GetBrowser() = 0;
+
+ ///
+ /// Get the V8 context associated with the frame. This method can only be
+ /// called from the render process.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefV8Context> GetV8Context() = 0;
+
+ ///
+ /// Visit the DOM document. This method can only be called from the render
+ /// process.
+ ///
+ /*--cef()--*/
+ virtual void VisitDOM(CefRefPtr<CefDOMVisitor> visitor) = 0;
+
+ ///
+ /// Create a new URL request that will be treated as originating from this
+ /// frame and the associated browser. This request may be intercepted by the
+ /// client via CefResourceRequestHandler or CefSchemeHandlerFactory. Use
+ /// CefURLRequest::Create instead if you do not want the request to have this
+ /// association, in which case it may be handled differently (see
+ /// documentation on that method). Requests may originate from both the
+ /// browser process and the render process.
+ ///
+ /// For requests originating from the browser process:
+ /// - POST data may only contain a single element of type PDE_TYPE_FILE or
+ /// PDE_TYPE_BYTES.
+ ///
+ /// For requests originating from the render process:
+ /// - POST data may only contain a single element of type PDE_TYPE_BYTES.
+ /// - If the response contains Content-Disposition or Mime-Type header
+ /// values that would not normally be rendered then the response may
+ /// receive special handling inside the browser (for example, via the
+ /// file download code path instead of the URL request code path).
+ ///
+ /// The |request| object will be marked as read-only after calling this
+ /// method.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefURLRequest> CreateURLRequest(
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefURLRequestClient> client) = 0;
+
+ ///
+ /// Send a message to the specified |target_process|. Ownership of the message
+ /// contents will be transferred and the |message| reference will be
+ /// invalidated. Message delivery is not guaranteed in all cases (for example,
+ /// if the browser is closing, navigating, or if the target process crashes).
+ /// Send an ACK message back from the target process if confirmation is
+ /// required.
+ ///
+ /*--cef()--*/
+ virtual void SendProcessMessage(CefProcessId target_process,
+ CefRefPtr<CefProcessMessage> message) = 0;
+};
+
+#endif // CEF_INCLUDE_CEF_FRAME_H_
diff --git a/include/cef_frame_handler.h b/include/cef_frame_handler.h
new file mode 100644
index 00000000..b742623f
--- /dev/null
+++ b/include/cef_frame_handler.h
@@ -0,0 +1,177 @@
+// Copyright (c) 2021 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_FRAME_HANDLER_H_
+#define CEF_INCLUDE_CEF_FRAME_HANDLER_H_
+#pragma once
+
+#include "include/cef_base.h"
+#include "include/cef_browser.h"
+#include "include/cef_frame.h"
+
+///
+/// Implement this interface to handle events related to CefFrame life span. The
+/// order of callbacks is:
+///
+/// (1) During initial CefBrowserHost creation and navigation of the main frame:
+/// - CefFrameHandler::OnFrameCreated => The initial main frame object has been
+/// created. Any commands will be queued until the frame is attached.
+/// - CefFrameHandler::OnMainFrameChanged => The initial main frame object has
+/// been assigned to the browser.
+/// - CefLifeSpanHandler::OnAfterCreated => The browser is now valid and can be
+/// used.
+/// - CefFrameHandler::OnFrameAttached => The initial main frame object is now
+/// connected to its peer in the renderer process. Commands can be routed.
+///
+/// (2) During further CefBrowserHost navigation/loading of the main frame
+/// and/or sub-frames:
+/// - CefFrameHandler::OnFrameCreated => A new main frame or sub-frame object
+/// has been created. Any commands will be queued until the frame is attached.
+/// - CefFrameHandler::OnFrameAttached => A new main frame or sub-frame object
+/// is now connected to its peer in the renderer process. Commands can be
+/// routed.
+/// - CefFrameHandler::OnFrameDetached => An existing main frame or sub-frame
+/// object has lost its connection to the renderer process. If multiple
+/// objects are detached at the same time then notifications will be sent for
+/// any sub-frame objects before the main frame object. Commands can no longer
+/// be routed and will be discarded.
+/// - CefFrameHandler::OnMainFrameChanged => A new main frame object has been
+/// assigned to the browser. This will only occur with cross-origin navigation
+/// or re-navigation after renderer process termination (due to crashes, etc).
+///
+/// (3) During final CefBrowserHost destruction of the main frame:
+/// - CefFrameHandler::OnFrameDetached => Any sub-frame objects have lost their
+/// connection to the renderer process. Commands can no longer be routed and
+/// will be discarded.
+/// - CefLifeSpanHandler::OnBeforeClose => The browser has been destroyed.
+/// - CefFrameHandler::OnFrameDetached => The main frame object have lost its
+/// connection to the renderer process. Notifications will be sent for any
+/// sub-frame objects before the main frame object. Commands can no longer be
+/// routed and will be discarded.
+/// - CefFrameHandler::OnMainFrameChanged => The final main frame object has
+/// been removed from the browser.
+///
+/// Cross-origin navigation and/or loading receives special handling.
+///
+/// When the main frame navigates to a different origin the OnMainFrameChanged
+/// callback (2) will be executed with the old and new main frame objects.
+///
+/// When a new sub-frame is loaded in, or an existing sub-frame is navigated to,
+/// a different origin from the parent frame, a temporary sub-frame object will
+/// first be created in the parent's renderer process. That temporary sub-frame
+/// will then be discarded after the real cross-origin sub-frame is created in
+/// the new/target renderer process. The client will receive cross-origin
+/// navigation callbacks (2) for the transition from the temporary sub-frame to
+/// the real sub-frame. The temporary sub-frame will not recieve or execute
+/// commands during this transitional period (any sent commands will be
+/// discarded).
+///
+/// When a new popup browser is created in a different origin from the parent
+/// browser, a temporary main frame object for the popup will first be created
+/// in the parent's renderer process. That temporary main frame will then be
+/// discarded after the real cross-origin main frame is created in the
+/// new/target renderer process. The client will recieve creation and initial
+/// navigation callbacks (1) for the temporary main frame, followed by
+/// cross-origin navigation callbacks (2) for the transition from the temporary
+/// main frame to the real main frame. The temporary main frame may receive and
+/// execute commands during this transitional period (any sent commands may be
+/// executed, but the behavior is potentially undesirable since they execute in
+/// the parent browser's renderer process and not the new/target renderer
+/// process).
+///
+/// Callbacks will not be executed for placeholders that may be created during
+/// pre-commit navigation for sub-frames that do not yet exist in the renderer
+/// process. Placeholders will have CefFrame::GetIdentifier() == -4.
+///
+/// The methods of this class will be called on the UI thread unless otherwise
+/// indicated.
+///
+/*--cef(source=client)--*/
+class CefFrameHandler : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Called when a new frame is created. This will be the first notification
+ /// that references |frame|. Any commands that require transport to the
+ /// associated renderer process (LoadRequest, SendProcessMessage, GetSource,
+ /// etc.) will be queued until OnFrameAttached is called for |frame|.
+ ///
+ /*--cef()--*/
+ virtual void OnFrameCreated(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) {}
+
+ ///
+ /// Called when a frame can begin routing commands to/from the associated
+ /// renderer process. |reattached| will be true if the frame was re-attached
+ /// after exiting the BackForwardCache. Any commands that were queued have now
+ /// been dispatched.
+ ///
+ /*--cef()--*/
+ virtual void OnFrameAttached(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ bool reattached) {}
+
+ ///
+ /// Called when a frame loses its connection to the renderer process and will
+ /// be destroyed. Any pending or future commands will be discarded and
+ /// CefFrame::IsValid() will now return false for |frame|. If called after
+ /// CefLifeSpanHandler::OnBeforeClose() during browser destruction then
+ /// CefBrowser::IsValid() will return false for |browser|.
+ ///
+ /*--cef()--*/
+ virtual void OnFrameDetached(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) {}
+
+ ///
+ /// Called when the main frame changes due to (a) initial browser creation,
+ /// (b) final browser destruction, (c) cross-origin navigation or (d)
+ /// re-navigation after renderer process termination (due to crashes, etc).
+ /// |old_frame| will be NULL and |new_frame| will be non-NULL when a main
+ /// frame is assigned to |browser| for the first time. |old_frame| will be
+ /// non-NULL and |new_frame| will be NULL and when a main frame is removed
+ /// from |browser| for the last time. Both |old_frame| and |new_frame| will be
+ /// non-NULL for cross-origin navigations or re-navigation after renderer
+ /// process termination. This method will be called after OnFrameCreated() for
+ /// |new_frame| and/or after OnFrameDetached() for |old_frame|. If called
+ /// after CefLifeSpanHandler::OnBeforeClose() during browser destruction then
+ /// CefBrowser::IsValid() will return false for |browser|.
+ ///
+ /*--cef(optional_param=old_frame,optional_param=new_frame)--*/
+ virtual void OnMainFrameChanged(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> old_frame,
+ CefRefPtr<CefFrame> new_frame) {}
+};
+
+#endif // CEF_INCLUDE_CEF_FRAME_HANDLER_H_
diff --git a/include/cef_i18n_util.h b/include/cef_i18n_util.h
new file mode 100644
index 00000000..5f9e1165
--- /dev/null
+++ b/include/cef_i18n_util.h
@@ -0,0 +1,49 @@
+// Copyright (c) 2021 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_I18N_UTIL_H_
+#define CEF_INCLUDE_CEF_I18N_UTIL_H_
+#pragma once
+
+#include "include/cef_base.h"
+
+///
+/// Returns true if the application text direction is right-to-left.
+///
+/*--cef()--*/
+bool CefIsRTL();
+
+#endif // CEF_INCLUDE_CEF_I18N_UTIL_H_
diff --git a/include/cef_image.h b/include/cef_image.h
new file mode 100644
index 00000000..cbea565b
--- /dev/null
+++ b/include/cef_image.h
@@ -0,0 +1,192 @@
+// Copyright (c) 2016 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_IMAGE_H_
+#define CEF_INCLUDE_CEF_IMAGE_H_
+#pragma once
+
+#include "include/cef_base.h"
+#include "include/cef_values.h"
+
+///
+/// Container for a single image represented at different scale factors. All
+/// image representations should be the same size in density independent pixel
+/// (DIP) units. For example, if the image at scale factor 1.0 is 100x100 pixels
+/// then the image at scale factor 2.0 should be 200x200 pixels -- both images
+/// will display with a DIP size of 100x100 units. The methods of this class can
+/// be called on any browser process thread.
+///
+/*--cef(source=library)--*/
+class CefImage : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Create a new CefImage. It will initially be empty. Use the Add*() methods
+ /// to add representations at different scale factors.
+ ///
+ /*--cef()--*/
+ static CefRefPtr<CefImage> CreateImage();
+
+ ///
+ /// Returns true if this Image is empty.
+ ///
+ /*--cef()--*/
+ virtual bool IsEmpty() = 0;
+
+ ///
+ /// Returns true if this Image and |that| Image share the same underlying
+ /// storage. Will also return true if both images are empty.
+ ///
+ /*--cef()--*/
+ virtual bool IsSame(CefRefPtr<CefImage> that) = 0;
+
+ ///
+ /// Add a bitmap image representation for |scale_factor|. Only 32-bit
+ /// RGBA/BGRA formats are supported. |pixel_width| and |pixel_height| are the
+ /// bitmap representation size in pixel coordinates. |pixel_data| is the array
+ /// of pixel data and should be |pixel_width| x |pixel_height| x 4 bytes in
+ /// size. |color_type| and |alpha_type| values specify the pixel format.
+ ///
+ /*--cef()--*/
+ virtual bool AddBitmap(float scale_factor,
+ int pixel_width,
+ int pixel_height,
+ cef_color_type_t color_type,
+ cef_alpha_type_t alpha_type,
+ const void* pixel_data,
+ size_t pixel_data_size) = 0;
+
+ ///
+ /// Add a PNG image representation for |scale_factor|. |png_data| is the image
+ /// data of size |png_data_size|. Any alpha transparency in the PNG data will
+ /// be maintained.
+ ///
+ /*--cef()--*/
+ virtual bool AddPNG(float scale_factor,
+ const void* png_data,
+ size_t png_data_size) = 0;
+
+ ///
+ /// Create a JPEG image representation for |scale_factor|. |jpeg_data| is the
+ /// image data of size |jpeg_data_size|. The JPEG format does not support
+ /// transparency so the alpha byte will be set to 0xFF for all pixels.
+ ///
+ /*--cef()--*/
+ virtual bool AddJPEG(float scale_factor,
+ const void* jpeg_data,
+ size_t jpeg_data_size) = 0;
+
+ ///
+ /// Returns the image width in density independent pixel (DIP) units.
+ ///
+ /*--cef()--*/
+ virtual size_t GetWidth() = 0;
+
+ ///
+ /// Returns the image height in density independent pixel (DIP) units.
+ ///
+ /*--cef()--*/
+ virtual size_t GetHeight() = 0;
+
+ ///
+ /// Returns true if this image contains a representation for |scale_factor|.
+ ///
+ /*--cef()--*/
+ virtual bool HasRepresentation(float scale_factor) = 0;
+
+ ///
+ /// Removes the representation for |scale_factor|. Returns true on success.
+ ///
+ /*--cef()--*/
+ virtual bool RemoveRepresentation(float scale_factor) = 0;
+
+ ///
+ /// Returns information for the representation that most closely matches
+ /// |scale_factor|. |actual_scale_factor| is the actual scale factor for the
+ /// representation. |pixel_width| and |pixel_height| are the representation
+ /// size in pixel coordinates. Returns true on success.
+ ///
+ /*--cef()--*/
+ virtual bool GetRepresentationInfo(float scale_factor,
+ float& actual_scale_factor,
+ int& pixel_width,
+ int& pixel_height) = 0;
+
+ ///
+ /// Returns the bitmap representation that most closely matches
+ /// |scale_factor|. Only 32-bit RGBA/BGRA formats are supported. |color_type|
+ /// and |alpha_type| values specify the desired output pixel format.
+ /// |pixel_width| and |pixel_height| are the output representation size in
+ /// pixel coordinates. Returns a CefBinaryValue containing the pixel data on
+ /// success or NULL on failure.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefBinaryValue> GetAsBitmap(float scale_factor,
+ cef_color_type_t color_type,
+ cef_alpha_type_t alpha_type,
+ int& pixel_width,
+ int& pixel_height) = 0;
+
+ ///
+ /// Returns the PNG representation that most closely matches |scale_factor|.
+ /// If |with_transparency| is true any alpha transparency in the image will be
+ /// represented in the resulting PNG data. |pixel_width| and |pixel_height|
+ /// are the output representation size in pixel coordinates. Returns a
+ /// CefBinaryValue containing the PNG image data on success or NULL on
+ /// failure.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefBinaryValue> GetAsPNG(float scale_factor,
+ bool with_transparency,
+ int& pixel_width,
+ int& pixel_height) = 0;
+
+ ///
+ /// Returns the JPEG representation that most closely matches |scale_factor|.
+ /// |quality| determines the compression level with 0 == lowest and 100 ==
+ /// highest. The JPEG format does not support alpha transparency and the alpha
+ /// channel, if any, will be discarded. |pixel_width| and |pixel_height| are
+ /// the output representation size in pixel coordinates. Returns a
+ /// CefBinaryValue containing the JPEG image data on success or NULL on
+ /// failure.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefBinaryValue> GetAsJPEG(float scale_factor,
+ int quality,
+ int& pixel_width,
+ int& pixel_height) = 0;
+};
+
+#endif // CEF_INCLUDE_CEF_IMAGE_H_
diff --git a/include/cef_jsdialog_handler.h b/include/cef_jsdialog_handler.h
new file mode 100644
index 00000000..9ad65276
--- /dev/null
+++ b/include/cef_jsdialog_handler.h
@@ -0,0 +1,127 @@
+// Copyright (c) 2012 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_JSDIALOG_HANDLER_H_
+#define CEF_INCLUDE_CEF_JSDIALOG_HANDLER_H_
+#pragma once
+
+#include "include/cef_base.h"
+#include "include/cef_browser.h"
+
+///
+/// Callback interface used for asynchronous continuation of JavaScript dialog
+/// requests.
+///
+/*--cef(source=library)--*/
+class CefJSDialogCallback : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Continue the JS dialog request. Set |success| to true if the OK button was
+ /// pressed. The |user_input| value should be specified for prompt dialogs.
+ ///
+ /*--cef(capi_name=cont,optional_param=user_input)--*/
+ virtual void Continue(bool success, const CefString& user_input) = 0;
+};
+
+///
+/// Implement this interface to handle events related to JavaScript dialogs. The
+/// methods of this class will be called on the UI thread.
+///
+/*--cef(source=client)--*/
+class CefJSDialogHandler : public virtual CefBaseRefCounted {
+ public:
+ typedef cef_jsdialog_type_t JSDialogType;
+
+ ///
+ /// Called to run a JavaScript dialog. If |origin_url| is non-empty it can be
+ /// passed to the CefFormatUrlForSecurityDisplay function to retrieve a secure
+ /// and user-friendly display string. The |default_prompt_text| value will be
+ /// specified for prompt dialogs only. Set |suppress_message| to true and
+ /// return false to suppress the message (suppressing messages is preferable
+ /// to immediately executing the callback as this is used to detect presumably
+ /// malicious behavior like spamming alert messages in onbeforeunload). Set
+ /// |suppress_message| to false and return false to use the default
+ /// implementation (the default implementation will show one modal dialog at a
+ /// time and suppress any additional dialog requests until the displayed
+ /// dialog is dismissed). Return true if the application will use a custom
+ /// dialog or if the callback has been executed immediately. Custom dialogs
+ /// may be either modal or modeless. If a custom dialog is used the
+ /// application must execute |callback| once the custom dialog is dismissed.
+ ///
+ /*--cef(optional_param=origin_url,optional_param=accept_lang,
+ optional_param=message_text,optional_param=default_prompt_text)--*/
+ virtual bool OnJSDialog(CefRefPtr<CefBrowser> browser,
+ const CefString& origin_url,
+ JSDialogType dialog_type,
+ const CefString& message_text,
+ const CefString& default_prompt_text,
+ CefRefPtr<CefJSDialogCallback> callback,
+ bool& suppress_message) {
+ return false;
+ }
+
+ ///
+ /// Called to run a dialog asking the user if they want to leave a page.
+ /// Return false to use the default dialog implementation. Return true if the
+ /// application will use a custom dialog or if the callback has been executed
+ /// immediately. Custom dialogs may be either modal or modeless. If a custom
+ /// dialog is used the application must execute |callback| once the custom
+ /// dialog is dismissed.
+ ///
+ /*--cef(optional_param=message_text)--*/
+ virtual bool OnBeforeUnloadDialog(CefRefPtr<CefBrowser> browser,
+ const CefString& message_text,
+ bool is_reload,
+ CefRefPtr<CefJSDialogCallback> callback) {
+ return false;
+ }
+
+ ///
+ /// Called to cancel any pending dialogs and reset any saved dialog state.
+ /// Will be called due to events like page navigation irregardless of whether
+ /// any dialogs are currently pending.
+ ///
+ /*--cef()--*/
+ virtual void OnResetDialogState(CefRefPtr<CefBrowser> browser) {}
+
+ ///
+ /// Called when the dialog is closed.
+ ///
+ /*--cef()--*/
+ virtual void OnDialogClosed(CefRefPtr<CefBrowser> browser) {}
+};
+
+#endif // CEF_INCLUDE_CEF_JSDIALOG_HANDLER_H_
diff --git a/include/cef_keyboard_handler.h b/include/cef_keyboard_handler.h
new file mode 100644
index 00000000..69838f98
--- /dev/null
+++ b/include/cef_keyboard_handler.h
@@ -0,0 +1,80 @@
+// Copyright (c) 2012 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_KEYBOARD_HANDLER_H_
+#define CEF_INCLUDE_CEF_KEYBOARD_HANDLER_H_
+#pragma once
+
+#include "include/cef_base.h"
+#include "include/cef_browser.h"
+
+///
+/// Implement this interface to handle events related to keyboard input. The
+/// methods of this class will be called on the UI thread.
+///
+/*--cef(source=client)--*/
+class CefKeyboardHandler : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Called before a keyboard event is sent to the renderer. |event| contains
+ /// information about the keyboard event. |os_event| is the operating system
+ /// event message, if any. Return true if the event was handled or false
+ /// otherwise. If the event will be handled in OnKeyEvent() as a keyboard
+ /// shortcut set |is_keyboard_shortcut| to true and return false.
+ ///
+ /*--cef()--*/
+ virtual bool OnPreKeyEvent(CefRefPtr<CefBrowser> browser,
+ const CefKeyEvent& event,
+ CefEventHandle os_event,
+ bool* is_keyboard_shortcut) {
+ return false;
+ }
+
+ ///
+ /// Called after the renderer and JavaScript in the page has had a chance to
+ /// handle the event. |event| contains information about the keyboard event.
+ /// |os_event| is the operating system event message, if any. Return true if
+ /// the keyboard event was handled or false otherwise.
+ ///
+ /*--cef()--*/
+ virtual bool OnKeyEvent(CefRefPtr<CefBrowser> browser,
+ const CefKeyEvent& event,
+ CefEventHandle os_event) {
+ return false;
+ }
+};
+
+#endif // CEF_INCLUDE_CEF_KEYBOARD_HANDLER_H_
diff --git a/include/cef_life_span_handler.h b/include/cef_life_span_handler.h
new file mode 100644
index 00000000..d779b075
--- /dev/null
+++ b/include/cef_life_span_handler.h
@@ -0,0 +1,214 @@
+// Copyright (c) 2012 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_LIFE_SPAN_HANDLER_H_
+#define CEF_INCLUDE_CEF_LIFE_SPAN_HANDLER_H_
+#pragma once
+
+#include "include/cef_base.h"
+#include "include/cef_browser.h"
+
+class CefClient;
+
+///
+/// Implement this interface to handle events related to browser life span. The
+/// methods of this class will be called on the UI thread unless otherwise
+/// indicated.
+///
+/*--cef(source=client)--*/
+class CefLifeSpanHandler : public virtual CefBaseRefCounted {
+ public:
+ typedef cef_window_open_disposition_t WindowOpenDisposition;
+
+ ///
+ /// Called on the UI thread before a new popup browser is created. The
+ /// |browser| and |frame| values represent the source of the popup request.
+ /// The |target_url| and |target_frame_name| values indicate where the popup
+ /// browser should navigate and may be empty if not specified with the
+ /// request. The |target_disposition| value indicates where the user intended
+ /// to open the popup (e.g. current tab, new tab, etc). The |user_gesture|
+ /// value will be true if the popup was opened via explicit user gesture (e.g.
+ /// clicking a link) or false if the popup opened automatically (e.g. via the
+ /// DomContentLoaded event). The |popupFeatures| structure contains additional
+ /// information about the requested popup window. To allow creation of the
+ /// popup browser optionally modify |windowInfo|, |client|, |settings| and
+ /// |no_javascript_access| and return false. To cancel creation of the popup
+ /// browser return true. The |client| and |settings| values will default to
+ /// the source browser's values. If the |no_javascript_access| value is set to
+ /// false the new browser will not be scriptable and may not be hosted in the
+ /// same renderer process as the source browser. Any modifications to
+ /// |windowInfo| will be ignored if the parent browser is wrapped in a
+ /// CefBrowserView. Popup browser creation will be canceled if the parent
+ /// browser is destroyed before the popup browser creation completes
+ /// (indicated by a call to OnAfterCreated for the popup browser). The
+ /// |extra_info| parameter provides an opportunity to specify extra
+ /// information specific to the created popup browser that will be passed to
+ /// CefRenderProcessHandler::OnBrowserCreated() in the render process.
+ ///
+ /*--cef(optional_param=target_url,optional_param=target_frame_name)--*/
+ virtual bool OnBeforePopup(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const CefString& target_url,
+ const CefString& target_frame_name,
+ WindowOpenDisposition target_disposition,
+ bool user_gesture,
+ const CefPopupFeatures& popupFeatures,
+ CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient>& client,
+ CefBrowserSettings& settings,
+ CefRefPtr<CefDictionaryValue>& extra_info,
+ bool* no_javascript_access) {
+ return false;
+ }
+
+ ///
+ /// Called after a new browser is created. It is now safe to begin performing
+ /// actions with |browser|. CefFrameHandler callbacks related to initial main
+ /// frame creation will arrive before this callback. See CefFrameHandler
+ /// documentation for additional usage information.
+ ///
+ /*--cef()--*/
+ virtual void OnAfterCreated(CefRefPtr<CefBrowser> browser) {}
+
+ ///
+ /// Called when a browser has recieved a request to close. This may result
+ /// directly from a call to CefBrowserHost::*CloseBrowser() or indirectly if
+ /// the browser is parented to a top-level window created by CEF and the user
+ /// attempts to close that window (by clicking the 'X', for example). The
+ /// DoClose() method will be called after the JavaScript 'onunload' event has
+ /// been fired.
+ ///
+ /// An application should handle top-level owner window close notifications by
+ /// calling CefBrowserHost::TryCloseBrowser() or
+ /// CefBrowserHost::CloseBrowser(false) instead of allowing the window to
+ /// close immediately (see the examples below). This gives CEF an opportunity
+ /// to process the 'onbeforeunload' event and optionally cancel the close
+ /// before DoClose() is called.
+ ///
+ /// When windowed rendering is enabled CEF will internally create a window or
+ /// view to host the browser. In that case returning false from DoClose() will
+ /// send the standard close notification to the browser's top-level owner
+ /// window (e.g. WM_CLOSE on Windows, performClose: on OS X, "delete_event" on
+ /// Linux or CefWindowDelegate::CanClose() callback from Views). If the
+ /// browser's host window/view has already been destroyed (via view hierarchy
+ /// tear-down, for example) then DoClose() will not be called for that browser
+ /// since is no longer possible to cancel the close.
+ ///
+ /// When windowed rendering is disabled returning false from DoClose() will
+ /// cause the browser object to be destroyed immediately.
+ ///
+ /// If the browser's top-level owner window requires a non-standard close
+ /// notification then send that notification from DoClose() and return true.
+ ///
+ /// The CefLifeSpanHandler::OnBeforeClose() method will be called after
+ /// DoClose() (if DoClose() is called) and immediately before the browser
+ /// object is destroyed. The application should only exit after
+ /// OnBeforeClose() has been called for all existing browsers.
+ ///
+ /// The below examples describe what should happen during window close when
+ /// the browser is parented to an application-provided top-level window.
+ ///
+ /// Example 1: Using CefBrowserHost::TryCloseBrowser(). This is recommended
+ /// for clients using standard close handling and windows created on the
+ /// browser process UI thread.
+ /// 1. User clicks the window close button which sends a close notification
+ /// to the application's top-level window.
+ /// 2. Application's top-level window receives the close notification and
+ /// calls TryCloseBrowser() (which internally calls CloseBrowser(false)).
+ /// TryCloseBrowser() returns false so the client cancels the window
+ /// close.
+ /// 3. JavaScript 'onbeforeunload' handler executes and shows the close
+ /// confirmation dialog (which can be overridden via
+ /// CefJSDialogHandler::OnBeforeUnloadDialog()).
+ /// 4. User approves the close.
+ /// 5. JavaScript 'onunload' handler executes.
+ /// 6. CEF sends a close notification to the application's top-level window
+ /// (because DoClose() returned false by default).
+ /// 7. Application's top-level window receives the close notification and
+ /// calls TryCloseBrowser(). TryCloseBrowser() returns true so the client
+ /// allows the window close.
+ /// 8. Application's top-level window is destroyed.
+ /// 9. Application's OnBeforeClose() handler is called and the browser object
+ /// is destroyed.
+ /// 10. Application exits by calling CefQuitMessageLoop() if no other browsers
+ /// exist.
+ ///
+ /// Example 2: Using CefBrowserHost::CloseBrowser(false) and implementing the
+ /// DoClose() callback. This is recommended for clients using non-standard
+ /// close handling or windows that were not created on the browser process UI
+ /// thread.
+ /// 1. User clicks the window close button which sends a close notification
+ /// to the application's top-level window.
+ /// 2. Application's top-level window receives the close notification and:
+ /// A. Calls CefBrowserHost::CloseBrowser(false).
+ /// B. Cancels the window close.
+ /// 3. JavaScript 'onbeforeunload' handler executes and shows the close
+ /// confirmation dialog (which can be overridden via
+ /// CefJSDialogHandler::OnBeforeUnloadDialog()).
+ /// 4. User approves the close.
+ /// 5. JavaScript 'onunload' handler executes.
+ /// 6. Application's DoClose() handler is called. Application will:
+ /// A. Set a flag to indicate that the next close attempt will be allowed.
+ /// B. Return false.
+ /// 7. CEF sends an close notification to the application's top-level window.
+ /// 8. Application's top-level window receives the close notification and
+ /// allows the window to close based on the flag from #6B.
+ /// 9. Application's top-level window is destroyed.
+ /// 10. Application's OnBeforeClose() handler is called and the browser object
+ /// is destroyed.
+ /// 11. Application exits by calling CefQuitMessageLoop() if no other browsers
+ /// exist.
+ ///
+ /*--cef()--*/
+ virtual bool DoClose(CefRefPtr<CefBrowser> browser) { return false; }
+
+ ///
+ /// Called just before a browser is destroyed. Release all references to the
+ /// browser object and do not attempt to execute any methods on the browser
+ /// object (other than IsValid, GetIdentifier or IsSame) after this callback
+ /// returns. CefFrameHandler callbacks related to final main frame destruction
+ /// will arrive after this callback and CefBrowser::IsValid will return false
+ /// at that time. Any in-progress network requests associated with |browser|
+ /// will be aborted when the browser is destroyed, and
+ /// CefResourceRequestHandler callbacks related to those requests may still
+ /// arrive on the IO thread after this callback. See CefFrameHandler and
+ /// DoClose() documentation for additional usage information.
+ ///
+ /*--cef()--*/
+ virtual void OnBeforeClose(CefRefPtr<CefBrowser> browser) {}
+};
+
+#endif // CEF_INCLUDE_CEF_LIFE_SPAN_HANDLER_H_
diff --git a/include/cef_load_handler.h b/include/cef_load_handler.h
new file mode 100644
index 00000000..a7381d82
--- /dev/null
+++ b/include/cef_load_handler.h
@@ -0,0 +1,117 @@
+// Copyright (c) 2012 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_LOAD_HANDLER_H_
+#define CEF_INCLUDE_CEF_LOAD_HANDLER_H_
+#pragma once
+
+#include "include/cef_base.h"
+#include "include/cef_browser.h"
+#include "include/cef_frame.h"
+
+///
+/// Implement this interface to handle events related to browser load status.
+/// The methods of this class will be called on the browser process UI thread or
+/// render process main thread (TID_RENDERER).
+///
+/*--cef(source=client)--*/
+class CefLoadHandler : public virtual CefBaseRefCounted {
+ public:
+ typedef cef_errorcode_t ErrorCode;
+ typedef cef_transition_type_t TransitionType;
+
+ ///
+ /// Called when the loading state has changed. This callback will be executed
+ /// twice -- once when loading is initiated either programmatically or by user
+ /// action, and once when loading is terminated due to completion,
+ /// cancellation of failure. It will be called before any calls to OnLoadStart
+ /// and after all calls to OnLoadError and/or OnLoadEnd.
+ ///
+ /*--cef()--*/
+ virtual void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
+ bool isLoading,
+ bool canGoBack,
+ bool canGoForward) {}
+
+ ///
+ /// Called after a navigation has been committed and before the browser begins
+ /// loading contents in the frame. The |frame| value will never be empty --
+ /// call the IsMain() method to check if this frame is the main frame.
+ /// |transition_type| provides information about the source of the navigation
+ /// and an accurate value is only available in the browser process. Multiple
+ /// frames may be loading at the same time. Sub-frames may start or continue
+ /// loading after the main frame load has ended. This method will not be
+ /// called for same page navigations (fragments, history state, etc.) or for
+ /// navigations that fail or are canceled before commit. For notification of
+ /// overall browser load status use OnLoadingStateChange instead.
+ ///
+ /*--cef()--*/
+ virtual void OnLoadStart(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ TransitionType transition_type) {}
+
+ ///
+ /// Called when the browser is done loading a frame. The |frame| value will
+ /// never be empty -- call the IsMain() method to check if this frame is the
+ /// main frame. Multiple frames may be loading at the same time. Sub-frames
+ /// may start or continue loading after the main frame load has ended. This
+ /// method will not be called for same page navigations (fragments, history
+ /// state, etc.) or for navigations that fail or are canceled before commit.
+ /// For notification of overall browser load status use OnLoadingStateChange
+ /// instead.
+ ///
+ /*--cef()--*/
+ virtual void OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int httpStatusCode) {}
+
+ ///
+ /// Called when a navigation fails or is canceled. This method may be called
+ /// by itself if before commit or in combination with OnLoadStart/OnLoadEnd if
+ /// after commit. |errorCode| is the error code number, |errorText| is the
+ /// error text and |failedUrl| is the URL that failed to load.
+ /// See net\base\net_error_list.h for complete descriptions of the error
+ /// codes.
+ ///
+ /*--cef(optional_param=errorText)--*/
+ virtual void OnLoadError(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ ErrorCode errorCode,
+ const CefString& errorText,
+ const CefString& failedUrl) {}
+};
+
+#endif // CEF_INCLUDE_CEF_LOAD_HANDLER_H_
diff --git a/include/cef_media_router.h b/include/cef_media_router.h
new file mode 100644
index 00000000..eb9ea3f8
--- /dev/null
+++ b/include/cef_media_router.h
@@ -0,0 +1,317 @@
+// Copyright (c) 2020 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_MEDIA_ROUTER_H_
+#define CEF_INCLUDE_CEF_MEDIA_ROUTER_H_
+#pragma once
+
+#include <vector>
+#include "include/cef_base.h"
+#include "include/cef_callback.h"
+#include "include/cef_registration.h"
+
+class CefMediaObserver;
+class CefMediaRoute;
+class CefMediaRouteCreateCallback;
+class CefMediaSink;
+class CefMediaSinkDeviceInfoCallback;
+class CefMediaSource;
+
+///
+/// Supports discovery of and communication with media devices on the local
+/// network via the Cast and DIAL protocols. The methods of this class may be
+/// called on any browser process thread unless otherwise indicated.
+///
+/*--cef(source=library)--*/
+class CefMediaRouter : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Returns the MediaRouter object associated with the global request context.
+ /// If |callback| is non-NULL it will be executed asnychronously on the UI
+ /// thread after the manager's storage has been initialized. Equivalent to
+ /// calling CefRequestContext::GetGlobalContext()->GetMediaRouter().
+ ///
+ /*--cef(optional_param=callback)--*/
+ static CefRefPtr<CefMediaRouter> GetGlobalMediaRouter(
+ CefRefPtr<CefCompletionCallback> callback);
+
+ ///
+ /// Add an observer for MediaRouter events. The observer will remain
+ /// registered until the returned Registration object is destroyed.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefRegistration> AddObserver(
+ CefRefPtr<CefMediaObserver> observer) = 0;
+
+ ///
+ /// Returns a MediaSource object for the specified media source URN. Supported
+ /// URN schemes include "cast:" and "dial:", and will be already known by the
+ /// client application (e.g. "cast:<appId>?clientId=<clientId>").
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefMediaSource> GetSource(const CefString& urn) = 0;
+
+ ///
+ /// Trigger an asynchronous call to CefMediaObserver::OnSinks on all
+ /// registered observers.
+ ///
+ /*--cef()--*/
+ virtual void NotifyCurrentSinks() = 0;
+
+ ///
+ /// Create a new route between |source| and |sink|. Source and sink must be
+ /// valid, compatible (as reported by CefMediaSink::IsCompatibleWith), and a
+ /// route between them must not already exist. |callback| will be executed
+ /// on success or failure. If route creation succeeds it will also trigger an
+ /// asynchronous call to CefMediaObserver::OnRoutes on all registered
+ /// observers.
+ ///
+ /*--cef()--*/
+ virtual void CreateRoute(CefRefPtr<CefMediaSource> source,
+ CefRefPtr<CefMediaSink> sink,
+ CefRefPtr<CefMediaRouteCreateCallback> callback) = 0;
+
+ ///
+ /// Trigger an asynchronous call to CefMediaObserver::OnRoutes on all
+ /// registered observers.
+ ///
+ /*--cef()--*/
+ virtual void NotifyCurrentRoutes() = 0;
+};
+
+///
+/// Implemented by the client to observe MediaRouter events and registered via
+/// CefMediaRouter::AddObserver. The methods of this class will be called on the
+/// browser process UI thread.
+///
+/*--cef(source=client)--*/
+class CefMediaObserver : public virtual CefBaseRefCounted {
+ public:
+ typedef cef_media_route_connection_state_t ConnectionState;
+
+ ///
+ /// The list of available media sinks has changed or
+ /// CefMediaRouter::NotifyCurrentSinks was called.
+ ///
+ /*--cef()--*/
+ virtual void OnSinks(const std::vector<CefRefPtr<CefMediaSink>>& sinks) = 0;
+
+ ///
+ /// The list of available media routes has changed or
+ /// CefMediaRouter::NotifyCurrentRoutes was called.
+ ///
+ /*--cef()--*/
+ virtual void OnRoutes(
+ const std::vector<CefRefPtr<CefMediaRoute>>& routes) = 0;
+
+ ///
+ /// The connection state of |route| has changed.
+ ///
+ /*--cef()--*/
+ virtual void OnRouteStateChanged(CefRefPtr<CefMediaRoute> route,
+ ConnectionState state) = 0;
+
+ ///
+ /// A message was recieved over |route|. |message| is only valid for
+ /// the scope of this callback and should be copied if necessary.
+ ///
+ /*--cef()--*/
+ virtual void OnRouteMessageReceived(CefRefPtr<CefMediaRoute> route,
+ const void* message,
+ size_t message_size) = 0;
+};
+
+///
+/// Represents the route between a media source and sink. Instances of this
+/// object are created via CefMediaRouter::CreateRoute and retrieved via
+/// CefMediaObserver::OnRoutes. Contains the status and metadata of a
+/// routing operation. The methods of this class may be called on any browser
+/// process thread unless otherwise indicated.
+///
+/*--cef(source=library)--*/
+class CefMediaRoute : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Returns the ID for this route.
+ ///
+ /*--cef()--*/
+ virtual CefString GetId() = 0;
+
+ ///
+ /// Returns the source associated with this route.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefMediaSource> GetSource() = 0;
+
+ ///
+ /// Returns the sink associated with this route.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefMediaSink> GetSink() = 0;
+
+ ///
+ /// Send a message over this route. |message| will be copied if necessary.
+ ///
+ /*--cef()--*/
+ virtual void SendRouteMessage(const void* message, size_t message_size) = 0;
+
+ ///
+ /// Terminate this route. Will result in an asynchronous call to
+ /// CefMediaObserver::OnRoutes on all registered observers.
+ ///
+ /*--cef()--*/
+ virtual void Terminate() = 0;
+};
+
+///
+/// Callback interface for CefMediaRouter::CreateRoute. The methods of this
+/// class will be called on the browser process UI thread.
+///
+/*--cef(source=client)--*/
+class CefMediaRouteCreateCallback : public virtual CefBaseRefCounted {
+ public:
+ typedef cef_media_route_create_result_t RouteCreateResult;
+
+ ///
+ /// Method that will be executed when the route creation has finished.
+ /// |result| will be CEF_MRCR_OK if the route creation succeeded. |error| will
+ /// be a description of the error if the route creation failed. |route| is the
+ /// resulting route, or empty if the route creation failed.
+ ///
+ /*--cef(optional_param=error,optional_param=route)--*/
+ virtual void OnMediaRouteCreateFinished(RouteCreateResult result,
+ const CefString& error,
+ CefRefPtr<CefMediaRoute> route) = 0;
+};
+
+///
+/// Represents a sink to which media can be routed. Instances of this object are
+/// retrieved via CefMediaObserver::OnSinks. The methods of this class may
+/// be called on any browser process thread unless otherwise indicated.
+///
+/*--cef(source=library)--*/
+class CefMediaSink : public virtual CefBaseRefCounted {
+ public:
+ typedef cef_media_sink_icon_type_t IconType;
+
+ ///
+ /// Returns the ID for this sink.
+ ///
+ /*--cef()--*/
+ virtual CefString GetId() = 0;
+
+ ///
+ /// Returns the name of this sink.
+ ///
+ /*--cef()--*/
+ virtual CefString GetName() = 0;
+
+ ///
+ /// Returns the icon type for this sink.
+ ///
+ /*--cef(default_retval=CEF_MSIT_GENERIC)--*/
+ virtual IconType GetIconType() = 0;
+
+ ///
+ /// Asynchronously retrieves device info.
+ ///
+ /*--cef()--*/
+ virtual void GetDeviceInfo(
+ CefRefPtr<CefMediaSinkDeviceInfoCallback> callback) = 0;
+
+ ///
+ /// Returns true if this sink accepts content via Cast.
+ ///
+ /*--cef()--*/
+ virtual bool IsCastSink() = 0;
+
+ ///
+ /// Returns true if this sink accepts content via DIAL.
+ ///
+ /*--cef()--*/
+ virtual bool IsDialSink() = 0;
+
+ ///
+ /// Returns true if this sink is compatible with |source|.
+ ///
+ /*--cef()--*/
+ virtual bool IsCompatibleWith(CefRefPtr<CefMediaSource> source) = 0;
+};
+
+///
+/// Callback interface for CefMediaSink::GetDeviceInfo. The methods of this
+/// class will be called on the browser process UI thread.
+///
+/*--cef(source=client)--*/
+class CefMediaSinkDeviceInfoCallback : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Method that will be executed asyncronously once device information has
+ /// been retrieved.
+ ///
+ /*--cef()--*/
+ virtual void OnMediaSinkDeviceInfo(
+ const CefMediaSinkDeviceInfo& device_info) = 0;
+};
+
+///
+/// Represents a source from which media can be routed. Instances of this object
+/// are retrieved via CefMediaRouter::GetSource. The methods of this class may
+/// be called on any browser process thread unless otherwise indicated.
+///
+/*--cef(source=library)--*/
+class CefMediaSource : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Returns the ID (media source URN or URL) for this source.
+ ///
+ /*--cef()--*/
+ virtual CefString GetId() = 0;
+
+ ///
+ /// Returns true if this source outputs its content via Cast.
+ ///
+ /*--cef()--*/
+ virtual bool IsCastSource() = 0;
+
+ ///
+ /// Returns true if this source outputs its content via DIAL.
+ ///
+ /*--cef()--*/
+ virtual bool IsDialSource() = 0;
+};
+
+#endif // CEF_INCLUDE_CEF_MEDIA_ROUTER_H_
diff --git a/include/cef_menu_model.h b/include/cef_menu_model.h
new file mode 100644
index 00000000..4ddc54a7
--- /dev/null
+++ b/include/cef_menu_model.h
@@ -0,0 +1,491 @@
+// Copyright (c) 2012 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_MENU_MODEL_H_
+#define CEF_INCLUDE_CEF_MENU_MODEL_H_
+#pragma once
+
+#include "include/cef_base.h"
+#include "include/cef_menu_model_delegate.h"
+
+///
+/// Supports creation and modification of menus. See cef_menu_id_t for the
+/// command ids that have default implementations. All user-defined command ids
+/// should be between MENU_ID_USER_FIRST and MENU_ID_USER_LAST. The methods of
+/// this class can only be accessed on the browser process the UI thread.
+///
+/*--cef(source=library)--*/
+class CefMenuModel : public virtual CefBaseRefCounted {
+ public:
+ typedef cef_menu_item_type_t MenuItemType;
+
+ ///
+ /// Create a new MenuModel with the specified |delegate|.
+ ///
+ /*--cef()--*/
+ static CefRefPtr<CefMenuModel> CreateMenuModel(
+ CefRefPtr<CefMenuModelDelegate> delegate);
+
+ ///
+ /// Returns true if this menu is a submenu.
+ ///
+ /*--cef()--*/
+ virtual bool IsSubMenu() = 0;
+
+ ///
+ /// Clears the menu. Returns true on success.
+ ///
+ /*--cef()--*/
+ virtual bool Clear() = 0;
+
+ ///
+ /// Returns the number of items in this menu.
+ ///
+ /*--cef()--*/
+ virtual size_t GetCount() = 0;
+
+ ///
+ /// Add a separator to the menu. Returns true on success.
+ ///
+ /*--cef()--*/
+ virtual bool AddSeparator() = 0;
+
+ ///
+ /// Add an item to the menu. Returns true on success.
+ ///
+ /*--cef()--*/
+ virtual bool AddItem(int command_id, const CefString& label) = 0;
+
+ ///
+ /// Add a check item to the menu. Returns true on success.
+ ///
+ /*--cef()--*/
+ virtual bool AddCheckItem(int command_id, const CefString& label) = 0;
+ ///
+ /// Add a radio item to the menu. Only a single item with the specified
+ /// |group_id| can be checked at a time. Returns true on success.
+ ///
+ /*--cef()--*/
+ virtual bool AddRadioItem(int command_id,
+ const CefString& label,
+ int group_id) = 0;
+
+ ///
+ /// Add a sub-menu to the menu. The new sub-menu is returned.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefMenuModel> AddSubMenu(int command_id,
+ const CefString& label) = 0;
+
+ ///
+ /// Insert a separator in the menu at the specified |index|. Returns true on
+ /// success.
+ ///
+ /*--cef()--*/
+ virtual bool InsertSeparatorAt(size_t index) = 0;
+
+ ///
+ /// Insert an item in the menu at the specified |index|. Returns true on
+ /// success.
+ ///
+ /*--cef()--*/
+ virtual bool InsertItemAt(size_t index,
+ int command_id,
+ const CefString& label) = 0;
+
+ ///
+ /// Insert a check item in the menu at the specified |index|. Returns true on
+ /// success.
+ ///
+ /*--cef()--*/
+ virtual bool InsertCheckItemAt(size_t index,
+ int command_id,
+ const CefString& label) = 0;
+
+ ///
+ /// Insert a radio item in the menu at the specified |index|. Only a single
+ /// item with the specified |group_id| can be checked at a time. Returns true
+ /// on success.
+ ///
+ /*--cef()--*/
+ virtual bool InsertRadioItemAt(size_t index,
+ int command_id,
+ const CefString& label,
+ int group_id) = 0;
+
+ ///
+ /// Insert a sub-menu in the menu at the specified |index|. The new sub-menu
+ /// is returned.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefMenuModel> InsertSubMenuAt(size_t index,
+ int command_id,
+ const CefString& label) = 0;
+
+ ///
+ /// Removes the item with the specified |command_id|. Returns true on success.
+ ///
+ /*--cef()--*/
+ virtual bool Remove(int command_id) = 0;
+
+ ///
+ /// Removes the item at the specified |index|. Returns true on success.
+ ///
+ /*--cef()--*/
+ virtual bool RemoveAt(size_t index) = 0;
+
+ ///
+ /// Returns the index associated with the specified |command_id| or -1 if not
+ /// found due to the command id not existing in the menu.
+ ///
+ /*--cef()--*/
+ virtual int GetIndexOf(int command_id) = 0;
+
+ ///
+ /// Returns the command id at the specified |index| or -1 if not found due to
+ /// invalid range or the index being a separator.
+ ///
+ /*--cef()--*/
+ virtual int GetCommandIdAt(size_t index) = 0;
+
+ ///
+ /// Sets the command id at the specified |index|. Returns true on success.
+ ///
+ /*--cef()--*/
+ virtual bool SetCommandIdAt(size_t index, int command_id) = 0;
+
+ ///
+ /// Returns the label for the specified |command_id| or empty if not found.
+ ///
+ /*--cef()--*/
+ virtual CefString GetLabel(int command_id) = 0;
+
+ ///
+ /// Returns the label at the specified |index| or empty if not found due to
+ /// invalid range or the index being a separator.
+ ///
+ /*--cef()--*/
+ virtual CefString GetLabelAt(size_t index) = 0;
+
+ ///
+ /// Sets the label for the specified |command_id|. Returns true on success.
+ ///
+ /*--cef()--*/
+ virtual bool SetLabel(int command_id, const CefString& label) = 0;
+
+ ///
+ /// Set the label at the specified |index|. Returns true on success.
+ ///
+ /*--cef()--*/
+ virtual bool SetLabelAt(size_t index, const CefString& label) = 0;
+
+ ///
+ /// Returns the item type for the specified |command_id|.
+ ///
+ /*--cef(default_retval=MENUITEMTYPE_NONE)--*/
+ virtual MenuItemType GetType(int command_id) = 0;
+
+ ///
+ /// Returns the item type at the specified |index|.
+ ///
+ /*--cef(default_retval=MENUITEMTYPE_NONE)--*/
+ virtual MenuItemType GetTypeAt(size_t index) = 0;
+
+ ///
+ /// Returns the group id for the specified |command_id| or -1 if invalid.
+ ///
+ /*--cef()--*/
+ virtual int GetGroupId(int command_id) = 0;
+
+ ///
+ /// Returns the group id at the specified |index| or -1 if invalid.
+ ///
+ /*--cef()--*/
+ virtual int GetGroupIdAt(size_t index) = 0;
+
+ ///
+ /// Sets the group id for the specified |command_id|. Returns true on success.
+ ///
+ /*--cef()--*/
+ virtual bool SetGroupId(int command_id, int group_id) = 0;
+
+ ///
+ /// Sets the group id at the specified |index|. Returns true on success.
+ ///
+ /*--cef()--*/
+ virtual bool SetGroupIdAt(size_t index, int group_id) = 0;
+
+ ///
+ /// Returns the submenu for the specified |command_id| or empty if invalid.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefMenuModel> GetSubMenu(int command_id) = 0;
+
+ ///
+ /// Returns the submenu at the specified |index| or empty if invalid.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefMenuModel> GetSubMenuAt(size_t index) = 0;
+
+ ///
+ /// Returns true if the specified |command_id| is visible.
+ ///
+ /*--cef()--*/
+ virtual bool IsVisible(int command_id) = 0;
+
+ ///
+ /// Returns true if the specified |index| is visible.
+ ///
+ /*--cef()--*/
+ virtual bool IsVisibleAt(size_t index) = 0;
+
+ ///
+ /// Change the visibility of the specified |command_id|. Returns true on
+ /// success.
+ ///
+ /*--cef()--*/
+ virtual bool SetVisible(int command_id, bool visible) = 0;
+
+ ///
+ /// Change the visibility at the specified |index|. Returns true on success.
+ ///
+ /*--cef()--*/
+ virtual bool SetVisibleAt(size_t index, bool visible) = 0;
+
+ ///
+ /// Returns true if the specified |command_id| is enabled.
+ ///
+ /*--cef()--*/
+ virtual bool IsEnabled(int command_id) = 0;
+
+ ///
+ /// Returns true if the specified |index| is enabled.
+ ///
+ /*--cef()--*/
+ virtual bool IsEnabledAt(size_t index) = 0;
+
+ ///
+ /// Change the enabled status of the specified |command_id|. Returns true on
+ /// success.
+ ///
+ /*--cef()--*/
+ virtual bool SetEnabled(int command_id, bool enabled) = 0;
+
+ ///
+ /// Change the enabled status at the specified |index|. Returns true on
+ /// success.
+ ///
+ /*--cef()--*/
+ virtual bool SetEnabledAt(size_t index, bool enabled) = 0;
+
+ ///
+ /// Returns true if the specified |command_id| is checked. Only applies to
+ /// check and radio items.
+ ///
+ /*--cef()--*/
+ virtual bool IsChecked(int command_id) = 0;
+
+ ///
+ /// Returns true if the specified |index| is checked. Only applies to check
+ /// and radio items.
+ ///
+ /*--cef()--*/
+ virtual bool IsCheckedAt(size_t index) = 0;
+
+ ///
+ /// Check the specified |command_id|. Only applies to check and radio items.
+ /// Returns true on success.
+ ///
+ /*--cef()--*/
+ virtual bool SetChecked(int command_id, bool checked) = 0;
+
+ ///
+ /// Check the specified |index|. Only applies to check and radio items.
+ /// Returns true on success.
+ ///
+ /*--cef()--*/
+ virtual bool SetCheckedAt(size_t index, bool checked) = 0;
+
+ ///
+ /// Returns true if the specified |command_id| has a keyboard accelerator
+ /// assigned.
+ ///
+ /*--cef()--*/
+ virtual bool HasAccelerator(int command_id) = 0;
+
+ ///
+ /// Returns true if the specified |index| has a keyboard accelerator assigned.
+ ///
+ /*--cef()--*/
+ virtual bool HasAcceleratorAt(size_t index) = 0;
+
+ ///
+ /// Set the keyboard accelerator for the specified |command_id|. |key_code|
+ /// can be any virtual key or character value. Returns true on success.
+ ///
+ /*--cef()--*/
+ virtual bool SetAccelerator(int command_id,
+ int key_code,
+ bool shift_pressed,
+ bool ctrl_pressed,
+ bool alt_pressed) = 0;
+
+ ///
+ /// Set the keyboard accelerator at the specified |index|. |key_code| can be
+ /// any virtual key or character value. Returns true on success.
+ ///
+ /*--cef()--*/
+ virtual bool SetAcceleratorAt(size_t index,
+ int key_code,
+ bool shift_pressed,
+ bool ctrl_pressed,
+ bool alt_pressed) = 0;
+
+ ///
+ /// Remove the keyboard accelerator for the specified |command_id|. Returns
+ /// true on success.
+ ///
+ /*--cef()--*/
+ virtual bool RemoveAccelerator(int command_id) = 0;
+
+ ///
+ /// Remove the keyboard accelerator at the specified |index|. Returns true on
+ /// success.
+ ///
+ /*--cef()--*/
+ virtual bool RemoveAcceleratorAt(size_t index) = 0;
+
+ ///
+ /// Retrieves the keyboard accelerator for the specified |command_id|. Returns
+ /// true on success.
+ ///
+ /*--cef()--*/
+ virtual bool GetAccelerator(int command_id,
+ int& key_code,
+ bool& shift_pressed,
+ bool& ctrl_pressed,
+ bool& alt_pressed) = 0;
+
+ ///
+ /// Retrieves the keyboard accelerator for the specified |index|. Returns true
+ /// on success.
+ ///
+ /*--cef()--*/
+ virtual bool GetAcceleratorAt(size_t index,
+ int& key_code,
+ bool& shift_pressed,
+ bool& ctrl_pressed,
+ bool& alt_pressed) = 0;
+
+ ///
+ /// Set the explicit color for |command_id| and |color_type| to |color|.
+ /// Specify a |color| value of 0 to remove the explicit color. If no explicit
+ /// color or default color is set for |color_type| then the system color will
+ /// be used. Returns true on success.
+ ///
+ /*--cef()--*/
+ virtual bool SetColor(int command_id,
+ cef_menu_color_type_t color_type,
+ cef_color_t color) = 0;
+
+ ///
+ /// Set the explicit color for |command_id| and |index| to |color|. Specify a
+ /// |color| value of 0 to remove the explicit color. Specify an |index| value
+ /// of -1 to set the default color for items that do not have an explicit
+ /// color set. If no explicit color or default color is set for |color_type|
+ /// then the system color will be used. Returns true on success.
+ ///
+ /*--cef()--*/
+ virtual bool SetColorAt(int index,
+ cef_menu_color_type_t color_type,
+ cef_color_t color) = 0;
+
+ ///
+ /// Returns in |color| the color that was explicitly set for |command_id| and
+ /// |color_type|. If a color was not set then 0 will be returned in |color|.
+ /// Returns true on success.
+ ///
+ /*--cef()--*/
+ virtual bool GetColor(int command_id,
+ cef_menu_color_type_t color_type,
+ cef_color_t& color) = 0;
+
+ ///
+ /// Returns in |color| the color that was explicitly set for |command_id| and
+ /// |color_type|. Specify an |index| value of -1 to return the default color
+ /// in |color|. If a color was not set then 0 will be returned in |color|.
+ /// Returns true on success.
+ ///
+ /*--cef()--*/
+ virtual bool GetColorAt(int index,
+ cef_menu_color_type_t color_type,
+ cef_color_t& color) = 0;
+
+ ///
+ /// Sets the font list for the specified |command_id|. If |font_list| is empty
+ /// the system font will be used. Returns true on success. The format is
+ /// "<FONT_FAMILY_LIST>,[STYLES] <SIZE>", where:
+ /// - FONT_FAMILY_LIST is a comma-separated list of font family names,
+ /// - STYLES is an optional space-separated list of style names
+ /// (case-sensitive "Bold" and "Italic" are supported), and
+ /// - SIZE is an integer font size in pixels with the suffix "px".
+ ///
+ /// Here are examples of valid font description strings:
+ /// - "Arial, Helvetica, Bold Italic 14px"
+ /// - "Arial, 14px"
+ ///
+ /*--cef(optional_param=font_list)--*/
+ virtual bool SetFontList(int command_id, const CefString& font_list) = 0;
+
+ ///
+ /// Sets the font list for the specified |index|. Specify an |index| value of
+ /// -1 to set the default font. If |font_list| is empty the system font will
+ /// be used. Returns true on success. The format is
+ /// "<FONT_FAMILY_LIST>,[STYLES] <SIZE>", where:
+ /// - FONT_FAMILY_LIST is a comma-separated list of font family names,
+ /// - STYLES is an optional space-separated list of style names
+ /// (case-sensitive "Bold" and "Italic" are supported), and
+ /// - SIZE is an integer font size in pixels with the suffix "px".
+ ///
+ /// Here are examples of valid font description strings:
+ /// - "Arial, Helvetica, Bold Italic 14px"
+ /// - "Arial, 14px"
+ ///
+ /*--cef(optional_param=font_list)--*/
+ virtual bool SetFontListAt(int index, const CefString& font_list) = 0;
+};
+
+#endif // CEF_INCLUDE_CEF_MENU_MODEL_H_
diff --git a/include/cef_menu_model_delegate.h b/include/cef_menu_model_delegate.h
new file mode 100644
index 00000000..c6482304
--- /dev/null
+++ b/include/cef_menu_model_delegate.h
@@ -0,0 +1,108 @@
+// Copyright (c) 2016 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_VIEWS_CEF_MENU_MODEL_DELEGATE_H_
+#define CEF_INCLUDE_VIEWS_CEF_MENU_MODEL_DELEGATE_H_
+#pragma once
+
+#include "include/cef_base.h"
+
+class CefMenuModel;
+
+///
+/// Implement this interface to handle menu model events. The methods of this
+/// class will be called on the browser process UI thread unless otherwise
+/// indicated.
+///
+/*--cef(source=client)--*/
+class CefMenuModelDelegate : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Perform the action associated with the specified |command_id| and
+ /// optional |event_flags|.
+ ///
+ /*--cef()--*/
+ virtual void ExecuteCommand(CefRefPtr<CefMenuModel> menu_model,
+ int command_id,
+ cef_event_flags_t event_flags) = 0;
+
+ ///
+ /// Called when the user moves the mouse outside the menu and over the owning
+ /// window.
+ ///
+ /*--cef()--*/
+ virtual void MouseOutsideMenu(CefRefPtr<CefMenuModel> menu_model,
+ const CefPoint& screen_point) {}
+
+ ///
+ /// Called on unhandled open submenu keyboard commands. |is_rtl| will be true
+ /// if the menu is displaying a right-to-left language.
+ ///
+ /*--cef()--*/
+ virtual void UnhandledOpenSubmenu(CefRefPtr<CefMenuModel> menu_model,
+ bool is_rtl) {}
+
+ ///
+ /// Called on unhandled close submenu keyboard commands. |is_rtl| will be true
+ /// if the menu is displaying a right-to-left language.
+ ///
+ /*--cef()--*/
+ virtual void UnhandledCloseSubmenu(CefRefPtr<CefMenuModel> menu_model,
+ bool is_rtl) {}
+
+ ///
+ /// The menu is about to show.
+ ///
+ /*--cef()--*/
+ virtual void MenuWillShow(CefRefPtr<CefMenuModel> menu_model) {}
+
+ ///
+ /// The menu has closed.
+ ///
+ /*--cef()--*/
+ virtual void MenuClosed(CefRefPtr<CefMenuModel> menu_model) {}
+
+ ///
+ /// Optionally modify a menu item label. Return true if |label| was modified.
+ ///
+ /*--cef()--*/
+ virtual bool FormatLabel(CefRefPtr<CefMenuModel> menu_model,
+ CefString& label) {
+ return false;
+ }
+};
+
+#endif // CEF_INCLUDE_VIEWS_CEF_MENU_MODEL_DELEGATE_H_
diff --git a/include/cef_navigation_entry.h b/include/cef_navigation_entry.h
new file mode 100644
index 00000000..a8e2f337
--- /dev/null
+++ b/include/cef_navigation_entry.h
@@ -0,0 +1,121 @@
+// Copyright (c) 2014 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_NAVIGATION_ENTRY_H_
+#define CEF_INCLUDE_CEF_NAVIGATION_ENTRY_H_
+#pragma once
+
+#include "include/cef_base.h"
+#include "include/cef_ssl_status.h"
+
+///
+/// Class used to represent an entry in navigation history.
+///
+/*--cef(source=library)--*/
+class CefNavigationEntry : public virtual CefBaseRefCounted {
+ public:
+ typedef cef_transition_type_t TransitionType;
+
+ ///
+ /// Returns true if this object is valid. Do not call any other methods if
+ /// this function returns false.
+ ///
+ /*--cef()--*/
+ virtual bool IsValid() = 0;
+
+ ///
+ /// Returns the actual URL of the page. For some pages this may be data: URL
+ /// or similar. Use GetDisplayURL() to return a display-friendly version.
+ ///
+ /*--cef()--*/
+ virtual CefString GetURL() = 0;
+
+ ///
+ /// Returns a display-friendly version of the URL.
+ ///
+ /*--cef()--*/
+ virtual CefString GetDisplayURL() = 0;
+
+ ///
+ /// Returns the original URL that was entered by the user before any
+ /// redirects.
+ ///
+ /*--cef()--*/
+ virtual CefString GetOriginalURL() = 0;
+
+ ///
+ /// Returns the title set by the page. This value may be empty.
+ ///
+ /*--cef()--*/
+ virtual CefString GetTitle() = 0;
+
+ ///
+ /// Returns the transition type which indicates what the user did to move to
+ /// this page from the previous page.
+ ///
+ /*--cef(default_retval=TT_EXPLICIT)--*/
+ virtual TransitionType GetTransitionType() = 0;
+
+ ///
+ /// Returns true if this navigation includes post data.
+ ///
+ /*--cef()--*/
+ virtual bool HasPostData() = 0;
+
+ ///
+ /// Returns the time for the last known successful navigation completion. A
+ /// navigation may be completed more than once if the page is reloaded. May be
+ /// 0 if the navigation has not yet completed.
+ ///
+ /*--cef()--*/
+ virtual CefBaseTime GetCompletionTime() = 0;
+
+ ///
+ /// Returns the HTTP status code for the last known successful navigation
+ /// response. May be 0 if the response has not yet been received or if the
+ /// navigation has not yet completed.
+ ///
+ /*--cef()--*/
+ virtual int GetHttpStatusCode() = 0;
+
+ ///
+ /// Returns the SSL information for this navigation entry.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefSSLStatus> GetSSLStatus() = 0;
+};
+
+#endif // CEF_INCLUDE_CEF_NAVIGATION_ENTRY_H_
diff --git a/include/cef_origin_whitelist.h b/include/cef_origin_whitelist.h
new file mode 100644
index 00000000..fa446fef
--- /dev/null
+++ b/include/cef_origin_whitelist.h
@@ -0,0 +1,103 @@
+// Copyright (c) 2012 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_ORIGIN_WHITELIST_H_
+#define CEF_INCLUDE_CEF_ORIGIN_WHITELIST_H_
+#pragma once
+
+#include "include/cef_base.h"
+
+///
+/// Add an entry to the cross-origin access whitelist.
+///
+/// The same-origin policy restricts how scripts hosted from different origins
+/// (scheme + domain + port) can communicate. By default, scripts can only
+/// access resources with the same origin. Scripts hosted on the HTTP and HTTPS
+/// schemes (but no other schemes) can use the "Access-Control-Allow-Origin"
+/// header to allow cross-origin requests. For example,
+/// https://source.example.com can make XMLHttpRequest requests on
+/// http://target.example.com if the http://target.example.com request returns
+/// an "Access-Control-Allow-Origin: https://source.example.com" response
+/// header.
+///
+/// Scripts in separate frames or iframes and hosted from the same protocol and
+/// domain suffix can execute cross-origin JavaScript if both pages set the
+/// document.domain value to the same domain suffix. For example,
+/// scheme://foo.example.com and scheme://bar.example.com can communicate using
+/// JavaScript if both domains set document.domain="example.com".
+///
+/// This method is used to allow access to origins that would otherwise violate
+/// the same-origin policy. Scripts hosted underneath the fully qualified
+/// |source_origin| URL (like http://www.example.com) will be allowed access to
+/// all resources hosted on the specified |target_protocol| and |target_domain|.
+/// If |target_domain| is non-empty and |allow_target_subdomains| if false only
+/// exact domain matches will be allowed. If |target_domain| contains a top-
+/// level domain component (like "example.com") and |allow_target_subdomains| is
+/// true sub-domain matches will be allowed. If |target_domain| is empty and
+/// |allow_target_subdomains| if true all domains and IP addresses will be
+/// allowed.
+///
+/// This method cannot be used to bypass the restrictions on local or display
+/// isolated schemes. See the comments on CefRegisterCustomScheme for more
+/// information.
+///
+/// This function may be called on any thread. Returns false if |source_origin|
+/// is invalid or the whitelist cannot be accessed.
+///
+/*--cef(optional_param=target_domain)--*/
+bool CefAddCrossOriginWhitelistEntry(const CefString& source_origin,
+ const CefString& target_protocol,
+ const CefString& target_domain,
+ bool allow_target_subdomains);
+
+///
+/// Remove an entry from the cross-origin access whitelist. Returns false if
+/// |source_origin| is invalid or the whitelist cannot be accessed.
+///
+/*--cef(optional_param=target_domain)--*/
+bool CefRemoveCrossOriginWhitelistEntry(const CefString& source_origin,
+ const CefString& target_protocol,
+ const CefString& target_domain,
+ bool allow_target_subdomains);
+
+///
+/// Remove all entries from the cross-origin access whitelist. Returns false if
+/// the whitelist cannot be accessed.
+///
+/*--cef()--*/
+bool CefClearCrossOriginWhitelist();
+
+#endif // CEF_INCLUDE_CEF_ORIGIN_WHITELIST_H_
diff --git a/include/cef_parser.h b/include/cef_parser.h
new file mode 100644
index 00000000..7482c7fe
--- /dev/null
+++ b/include/cef_parser.h
@@ -0,0 +1,175 @@
+// Copyright (c) 2012 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_PARSER_H_
+#define CEF_INCLUDE_CEF_PARSER_H_
+#pragma once
+
+#include <vector>
+
+#include "include/cef_base.h"
+#include "include/cef_values.h"
+
+///
+/// Combines specified |base_url| and |relative_url| into |resolved_url|.
+/// Returns false if one of the URLs is empty or invalid.
+///
+/*--cef()--*/
+bool CefResolveURL(const CefString& base_url,
+ const CefString& relative_url,
+ CefString& resolved_url);
+
+///
+/// Parse the specified |url| into its component parts.
+/// Returns false if the URL is empty or invalid.
+///
+/*--cef()--*/
+bool CefParseURL(const CefString& url, CefURLParts& parts);
+
+///
+/// Creates a URL from the specified |parts|, which must contain a non-empty
+/// spec or a non-empty host and path (at a minimum), but not both.
+/// Returns false if |parts| isn't initialized as described.
+///
+/*--cef()--*/
+bool CefCreateURL(const CefURLParts& parts, CefString& url);
+
+///
+/// This is a convenience function for formatting a URL in a concise and human-
+/// friendly way to help users make security-related decisions (or in other
+/// circumstances when people need to distinguish sites, origins, or otherwise-
+/// simplified URLs from each other). Internationalized domain names (IDN) may
+/// be presented in Unicode if the conversion is considered safe. The returned
+/// value will (a) omit the path for standard schemes, excepting file and
+/// filesystem, and (b) omit the port if it is the default for the scheme. Do
+/// not use this for URLs which will be parsed or sent to other applications.
+///
+/*--cef(optional_param=languages)--*/
+CefString CefFormatUrlForSecurityDisplay(const CefString& origin_url);
+
+///
+/// Returns the mime type for the specified file extension or an empty string if
+/// unknown.
+///
+/*--cef()--*/
+CefString CefGetMimeType(const CefString& extension);
+
+///
+/// Get the extensions associated with the given mime type. This should be
+/// passed in lower case. There could be multiple extensions for a given mime
+/// type, like "html,htm" for "text/html", or "txt,text,html,..." for "text/*".
+/// Any existing elements in the provided vector will not be erased.
+///
+/*--cef()--*/
+void CefGetExtensionsForMimeType(const CefString& mime_type,
+ std::vector<CefString>& extensions);
+
+///
+/// Encodes |data| as a base64 string.
+///
+/*--cef()--*/
+CefString CefBase64Encode(const void* data, size_t data_size);
+
+///
+/// Decodes the base64 encoded string |data|. The returned value will be NULL if
+/// the decoding fails.
+///
+/*--cef()--*/
+CefRefPtr<CefBinaryValue> CefBase64Decode(const CefString& data);
+
+///
+/// Escapes characters in |text| which are unsuitable for use as a query
+/// parameter value. Everything except alphanumerics and -_.!~*'() will be
+/// converted to "%XX". If |use_plus| is true spaces will change to "+". The
+/// result is basically the same as encodeURIComponent in Javacript.
+///
+/*--cef()--*/
+CefString CefURIEncode(const CefString& text, bool use_plus);
+
+///
+/// Unescapes |text| and returns the result. Unescaping consists of looking for
+/// the exact pattern "%XX" where each X is a hex digit and converting to the
+/// character with the numerical value of those digits (e.g. "i%20=%203%3b"
+/// unescapes to "i = 3;"). If |convert_to_utf8| is true this function will
+/// attempt to interpret the initial decoded result as UTF-8. If the result is
+/// convertable into UTF-8 it will be returned as converted. Otherwise the
+/// initial decoded result will be returned. The |unescape_rule| parameter
+/// supports further customization the decoding process.
+///
+/*--cef()--*/
+CefString CefURIDecode(const CefString& text,
+ bool convert_to_utf8,
+ cef_uri_unescape_rule_t unescape_rule);
+
+///
+/// Parses the specified |json_string| and returns a dictionary or list
+/// representation. If JSON parsing fails this method returns NULL.
+///
+/*--cef()--*/
+CefRefPtr<CefValue> CefParseJSON(const CefString& json_string,
+ cef_json_parser_options_t options);
+
+///
+/// Parses the specified UTF8-encoded |json| buffer of size |json_size| and
+/// returns a dictionary or list representation. If JSON parsing fails this
+/// method returns NULL.
+///
+/*--cef(capi_name=cef_parse_json_buffer)--*/
+CefRefPtr<CefValue> CefParseJSON(const void* json,
+ size_t json_size,
+ cef_json_parser_options_t options);
+
+///
+/// Parses the specified |json_string| and returns a dictionary or list
+/// representation. If JSON parsing fails this method returns NULL and populates
+/// |error_msg_out| with a formatted error message.
+///
+/*--cef()--*/
+CefRefPtr<CefValue> CefParseJSONAndReturnError(
+ const CefString& json_string,
+ cef_json_parser_options_t options,
+ CefString& error_msg_out);
+
+///
+/// Generates a JSON string from the specified root |node| which should be a
+/// dictionary or list value. Returns an empty string on failure. This method
+/// requires exclusive access to |node| including any underlying data.
+///
+/*--cef()--*/
+CefString CefWriteJSON(CefRefPtr<CefValue> node,
+ cef_json_writer_options_t options);
+
+#endif // CEF_INCLUDE_CEF_PARSER_H_
diff --git a/include/cef_path_util.h b/include/cef_path_util.h
new file mode 100644
index 00000000..d30dc6ce
--- /dev/null
+++ b/include/cef_path_util.h
@@ -0,0 +1,52 @@
+// Copyright (c) 2012 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_PATH_UTIL_H_
+#define CEF_INCLUDE_CEF_PATH_UTIL_H_
+#pragma once
+
+#include "include/cef_base.h"
+
+typedef cef_path_key_t PathKey;
+
+///
+/// Retrieve the path associated with the specified |key|. Returns true on
+/// success. Can be called on any thread in the browser process.
+///
+/*--cef()--*/
+bool CefGetPath(PathKey key, CefString& path);
+
+#endif // CEF_INCLUDE_CEF_PATH_UTIL_H_
diff --git a/include/cef_permission_handler.h b/include/cef_permission_handler.h
new file mode 100644
index 00000000..59f41473
--- /dev/null
+++ b/include/cef_permission_handler.h
@@ -0,0 +1,149 @@
+// Copyright (c) 2022 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_PERMISSION_HANDLER_H_
+#define CEF_INCLUDE_CEF_PERMISSION_HANDLER_H_
+#pragma once
+
+#include "include/cef_base.h"
+#include "include/cef_browser.h"
+
+///
+/// Callback interface used for asynchronous continuation of media access
+/// permission requests.
+///
+/*--cef(source=library)--*/
+class CefMediaAccessCallback : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Call to allow or deny media access. If this callback was initiated in
+ /// response to a getUserMedia (indicated by
+ /// CEF_MEDIA_PERMISSION_DEVICE_AUDIO_CAPTURE and/or
+ /// CEF_MEDIA_PERMISSION_DEVICE_VIDEO_CAPTURE being set) then
+ /// |allowed_permissions| must match |required_permissions| passed to
+ /// OnRequestMediaAccessPermission.
+ ///
+ /*--cef(capi_name=cont)--*/
+ virtual void Continue(uint32 allowed_permissions) = 0;
+
+ ///
+ /// Cancel the media access request.
+ ///
+ /*--cef()--*/
+ virtual void Cancel() = 0;
+};
+
+///
+/// Callback interface used for asynchronous continuation of permission prompts.
+///
+/*--cef(source=library)--*/
+class CefPermissionPromptCallback : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Complete the permissions request with the specified |result|.
+ ///
+ /*--cef(capi_name=cont)--*/
+ virtual void Continue(cef_permission_request_result_t result) = 0;
+};
+
+///
+/// Implement this interface to handle events related to permission requests.
+/// The methods of this class will be called on the browser process UI thread.
+///
+/*--cef(source=client)--*/
+class CefPermissionHandler : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Called when a page requests permission to access media.
+ /// |requesting_origin| is the URL origin requesting permission.
+ /// |requested_permissions| is a combination of values from
+ /// cef_media_access_permission_types_t that represent the requested
+ /// permissions. Return true and call CefMediaAccessCallback methods either in
+ /// this method or at a later time to continue or cancel the request. Return
+ /// false to proceed with default handling. With the Chrome runtime, default
+ /// handling will display the permission request UI. With the Alloy runtime,
+ /// default handling will deny the request. This method will not be called if
+ /// the "--enable-media-stream" command-line switch is used to grant all
+ /// permissions.
+ ///
+ /*--cef()--*/
+ virtual bool OnRequestMediaAccessPermission(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const CefString& requesting_origin,
+ uint32 requested_permissions,
+ CefRefPtr<CefMediaAccessCallback> callback) {
+ return false;
+ }
+
+ ///
+ /// Called when a page should show a permission prompt. |prompt_id| uniquely
+ /// identifies the prompt. |requesting_origin| is the URL origin requesting
+ /// permission. |requested_permissions| is a combination of values from
+ /// cef_permission_request_types_t that represent the requested permissions.
+ /// Return true and call CefPermissionPromptCallback::Continue either in this
+ /// method or at a later time to continue or cancel the request. Return false
+ /// to proceed with default handling. With the Chrome runtime, default
+ /// handling will display the permission prompt UI. With the Alloy runtime,
+ /// default handling is CEF_PERMISSION_RESULT_IGNORE.
+ ///
+ /*--cef()--*/
+ virtual bool OnShowPermissionPrompt(
+ CefRefPtr<CefBrowser> browser,
+ uint64 prompt_id,
+ const CefString& requesting_origin,
+ uint32 requested_permissions,
+ CefRefPtr<CefPermissionPromptCallback> callback) {
+ return false;
+ }
+
+ ///
+ /// Called when a permission prompt handled via OnShowPermissionPrompt is
+ /// dismissed. |prompt_id| will match the value that was passed to
+ /// OnShowPermissionPrompt. |result| will be the value passed to
+ /// CefPermissionPromptCallback::Continue or CEF_PERMISSION_RESULT_IGNORE if
+ /// the dialog was dismissed for other reasons such as navigation, browser
+ /// closure, etc. This method will not be called if OnShowPermissionPrompt
+ /// returned false for |prompt_id|.
+ ///
+ /*--cef()--*/
+ virtual void OnDismissPermissionPrompt(
+ CefRefPtr<CefBrowser> browser,
+ uint64 prompt_id,
+ cef_permission_request_result_t result) {}
+};
+
+#endif // CEF_INCLUDE_CEF_PERMISSION_HANDLER_H_
diff --git a/include/cef_preference.h b/include/cef_preference.h
new file mode 100644
index 00000000..8f3d61af
--- /dev/null
+++ b/include/cef_preference.h
@@ -0,0 +1,134 @@
+// Copyright (c) 2022 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_PREFERENCE_H_
+#define CEF_INCLUDE_CEF_PREFERENCE_H_
+#pragma once
+
+#include <vector>
+
+#include "include/cef_base.h"
+#include "include/cef_values.h"
+
+///
+/// Class that manages custom preference registrations.
+///
+/*--cef(source=library)--*/
+class CefPreferenceRegistrar : public CefBaseScoped {
+ public:
+ ///
+ /// Register a preference with the specified |name| and |default_value|. To
+ /// avoid conflicts with built-in preferences the |name| value should contain
+ /// an application-specific prefix followed by a period (e.g. "myapp.value").
+ /// The contents of |default_value| will be copied. The data type for the
+ /// preference will be inferred from |default_value|'s type and cannot be
+ /// changed after registration. Returns true on success. Returns false if
+ /// |name| is already registered or if |default_value| has an invalid type.
+ /// This method must be called from within the scope of the
+ /// CefBrowserProcessHandler::OnRegisterCustomPreferences callback.
+ ///
+ /*--cef()--*/
+ virtual bool AddPreference(const CefString& name,
+ CefRefPtr<CefValue> default_value) = 0;
+};
+
+///
+/// Manage access to preferences. Many built-in preferences are registered by
+/// Chromium. Custom preferences can be registered in
+/// CefBrowserProcessHandler::OnRegisterCustomPreferences.
+///
+/*--cef(source=library,no_debugct_check)--*/
+class CefPreferenceManager : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Returns the global preference manager object.
+ ///
+ /*--cef()--*/
+ static CefRefPtr<CefPreferenceManager> GetGlobalPreferenceManager();
+
+ ///
+ /// Returns true if a preference with the specified |name| exists. This method
+ /// must be called on the browser process UI thread.
+ ///
+ /*--cef()--*/
+ virtual bool HasPreference(const CefString& name) = 0;
+
+ ///
+ /// Returns the value for the preference with the specified |name|. Returns
+ /// NULL if the preference does not exist. The returned object contains a copy
+ /// of the underlying preference value and modifications to the returned
+ /// object will not modify the underlying preference value. This method must
+ /// be called on the browser process UI thread.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefValue> GetPreference(const CefString& name) = 0;
+
+ ///
+ /// Returns all preferences as a dictionary. If |include_defaults| is true
+ /// then preferences currently at their default value will be included. The
+ /// returned object contains a copy of the underlying preference values and
+ /// modifications to the returned object will not modify the underlying
+ /// preference values. This method must be called on the browser process UI
+ /// thread.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefDictionaryValue> GetAllPreferences(
+ bool include_defaults) = 0;
+
+ ///
+ /// Returns true if the preference with the specified |name| can be modified
+ /// using SetPreference. As one example preferences set via the command-line
+ /// usually cannot be modified. This method must be called on the browser
+ /// process UI thread.
+ ///
+ /*--cef()--*/
+ virtual bool CanSetPreference(const CefString& name) = 0;
+
+ ///
+ /// Set the |value| associated with preference |name|. Returns true if the
+ /// value is set successfully and false otherwise. If |value| is NULL the
+ /// preference will be restored to its default value. If setting the
+ /// preference fails then |error| will be populated with a detailed
+ /// description of the problem. This method must be called on the browser
+ /// process UI thread.
+ ///
+ /*--cef(optional_param=value)--*/
+ virtual bool SetPreference(const CefString& name,
+ CefRefPtr<CefValue> value,
+ CefString& error) = 0;
+};
+
+#endif // CEF_INCLUDE_CEF_PREFERENCE_H_
diff --git a/include/cef_print_handler.h b/include/cef_print_handler.h
new file mode 100644
index 00000000..8e4bcc64
--- /dev/null
+++ b/include/cef_print_handler.h
@@ -0,0 +1,142 @@
+// Copyright (c) 2014 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_PRINT_HANDLER_H_
+#define CEF_INCLUDE_CEF_PRINT_HANDLER_H_
+#pragma once
+
+#include "include/cef_base.h"
+#include "include/cef_browser.h"
+#include "include/cef_print_settings.h"
+
+///
+/// Callback interface for asynchronous continuation of print dialog requests.
+///
+/*--cef(source=library)--*/
+class CefPrintDialogCallback : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Continue printing with the specified |settings|.
+ ///
+ /*--cef(capi_name=cont)--*/
+ virtual void Continue(CefRefPtr<CefPrintSettings> settings) = 0;
+
+ ///
+ /// Cancel the printing.
+ ///
+ /*--cef()--*/
+ virtual void Cancel() = 0;
+};
+
+///
+/// Callback interface for asynchronous continuation of print job requests.
+///
+/*--cef(source=library)--*/
+class CefPrintJobCallback : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Indicate completion of the print job.
+ ///
+ /*--cef(capi_name=cont)--*/
+ virtual void Continue() = 0;
+};
+
+///
+/// Implement this interface to handle printing on Linux. Each browser will have
+/// only one print job in progress at a time. The methods of this class will be
+/// called on the browser process UI thread.
+///
+/*--cef(source=client)--*/
+class CefPrintHandler : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Called when printing has started for the specified |browser|. This method
+ /// will be called before the other OnPrint*() methods and irrespective of how
+ /// printing was initiated (e.g. CefBrowserHost::Print(), JavaScript
+ /// window.print() or PDF extension print button).
+ ///
+ /*--cef()--*/
+ virtual void OnPrintStart(CefRefPtr<CefBrowser> browser) = 0;
+
+ ///
+ /// Synchronize |settings| with client state. If |get_defaults| is true then
+ /// populate |settings| with the default print settings. Do not keep a
+ /// reference to |settings| outside of this callback.
+ ///
+ /*--cef()--*/
+ virtual void OnPrintSettings(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefPrintSettings> settings,
+ bool get_defaults) = 0;
+
+ ///
+ /// Show the print dialog. Execute |callback| once the dialog is dismissed.
+ /// Return true if the dialog will be displayed or false to cancel the
+ /// printing immediately.
+ ///
+ /*--cef()--*/
+ virtual bool OnPrintDialog(CefRefPtr<CefBrowser> browser,
+ bool has_selection,
+ CefRefPtr<CefPrintDialogCallback> callback) = 0;
+
+ ///
+ /// Send the print job to the printer. Execute |callback| once the job is
+ /// completed. Return true if the job will proceed or false to cancel the job
+ /// immediately.
+ ///
+ /*--cef()--*/
+ virtual bool OnPrintJob(CefRefPtr<CefBrowser> browser,
+ const CefString& document_name,
+ const CefString& pdf_file_path,
+ CefRefPtr<CefPrintJobCallback> callback) = 0;
+
+ ///
+ /// Reset client state related to printing.
+ ///
+ /*--cef()--*/
+ virtual void OnPrintReset(CefRefPtr<CefBrowser> browser) = 0;
+
+ ///
+ /// Return the PDF paper size in device units. Used in combination with
+ /// CefBrowserHost::PrintToPDF().
+ ///
+ /*--cef()--*/
+ virtual CefSize GetPdfPaperSize(CefRefPtr<CefBrowser> browser,
+ int device_units_per_inch) {
+ return CefSize();
+ }
+};
+
+#endif // CEF_INCLUDE_CEF_PRINT_HANDLER_H_
diff --git a/include/cef_print_settings.h b/include/cef_print_settings.h
new file mode 100644
index 00000000..df61a29f
--- /dev/null
+++ b/include/cef_print_settings.h
@@ -0,0 +1,201 @@
+// Copyright (c) 2014 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_PRINT_SETTINGS_H_
+#define CEF_INCLUDE_CEF_PRINT_SETTINGS_H_
+#pragma once
+
+#include <vector>
+
+#include "include/cef_base.h"
+
+///
+/// Class representing print settings.
+///
+/*--cef(source=library)--*/
+class CefPrintSettings : public virtual CefBaseRefCounted {
+ public:
+ typedef cef_color_model_t ColorModel;
+ typedef cef_duplex_mode_t DuplexMode;
+ typedef std::vector<CefRange> PageRangeList;
+
+ ///
+ /// Create a new CefPrintSettings object.
+ ///
+ /*--cef()--*/
+ static CefRefPtr<CefPrintSettings> Create();
+
+ ///
+ /// Returns true if this object is valid. Do not call any other methods if
+ /// this function returns false.
+ ///
+ /*--cef()--*/
+ virtual bool IsValid() = 0;
+
+ ///
+ /// Returns true if the values of this object are read-only. Some APIs may
+ /// expose read-only objects.
+ ///
+ /*--cef()--*/
+ virtual bool IsReadOnly() = 0;
+
+ ///
+ /// Set the page orientation.
+ ///
+ /*--cef()--*/
+ virtual void SetOrientation(bool landscape) = 0;
+
+ ///
+ /// Returns true if the orientation is landscape.
+ ///
+ /*--cef()--*/
+ virtual bool IsLandscape() = 0;
+
+ ///
+ /// Set the printer printable area in device units.
+ /// Some platforms already provide flipped area. Set |landscape_needs_flip|
+ /// to false on those platforms to avoid double flipping.
+ ///
+ /*--cef()--*/
+ virtual void SetPrinterPrintableArea(
+ const CefSize& physical_size_device_units,
+ const CefRect& printable_area_device_units,
+ bool landscape_needs_flip) = 0;
+
+ ///
+ /// Set the device name.
+ ///
+ /*--cef(optional_param=name)--*/
+ virtual void SetDeviceName(const CefString& name) = 0;
+
+ ///
+ /// Get the device name.
+ ///
+ /*--cef()--*/
+ virtual CefString GetDeviceName() = 0;
+
+ ///
+ /// Set the DPI (dots per inch).
+ ///
+ /*--cef()--*/
+ virtual void SetDPI(int dpi) = 0;
+
+ ///
+ /// Get the DPI (dots per inch).
+ ///
+ /*--cef()--*/
+ virtual int GetDPI() = 0;
+
+ ///
+ /// Set the page ranges.
+ ///
+ /*--cef()--*/
+ virtual void SetPageRanges(const PageRangeList& ranges) = 0;
+
+ ///
+ /// Returns the number of page ranges that currently exist.
+ ///
+ /*--cef()--*/
+ virtual size_t GetPageRangesCount() = 0;
+
+ ///
+ /// Retrieve the page ranges.
+ ///
+ /*--cef(count_func=ranges:GetPageRangesCount)--*/
+ virtual void GetPageRanges(PageRangeList& ranges) = 0;
+
+ ///
+ /// Set whether only the selection will be printed.
+ ///
+ /*--cef()--*/
+ virtual void SetSelectionOnly(bool selection_only) = 0;
+
+ ///
+ /// Returns true if only the selection will be printed.
+ ///
+ /*--cef()--*/
+ virtual bool IsSelectionOnly() = 0;
+
+ ///
+ /// Set whether pages will be collated.
+ ///
+ /*--cef()--*/
+ virtual void SetCollate(bool collate) = 0;
+
+ ///
+ /// Returns true if pages will be collated.
+ ///
+ /*--cef()--*/
+ virtual bool WillCollate() = 0;
+
+ ///
+ /// Set the color model.
+ ///
+ /*--cef()--*/
+ virtual void SetColorModel(ColorModel model) = 0;
+
+ ///
+ /// Get the color model.
+ ///
+ /*--cef(default_retval=COLOR_MODEL_UNKNOWN)--*/
+ virtual ColorModel GetColorModel() = 0;
+
+ ///
+ /// Set the number of copies.
+ ///
+ /*--cef()--*/
+ virtual void SetCopies(int copies) = 0;
+
+ ///
+ /// Get the number of copies.
+ ///
+ /*--cef()--*/
+ virtual int GetCopies() = 0;
+
+ ///
+ /// Set the duplex mode.
+ ///
+ /*--cef()--*/
+ virtual void SetDuplexMode(DuplexMode mode) = 0;
+
+ ///
+ /// Get the duplex mode.
+ ///
+ /*--cef(default_retval=DUPLEX_MODE_UNKNOWN)--*/
+ virtual DuplexMode GetDuplexMode() = 0;
+};
+
+#endif // CEF_INCLUDE_CEF_PRINT_SETTINGS_H_
diff --git a/include/cef_process_message.h b/include/cef_process_message.h
new file mode 100644
index 00000000..74f64810
--- /dev/null
+++ b/include/cef_process_message.h
@@ -0,0 +1,101 @@
+// Copyright (c) 2012 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_MESSAGE_H_
+#define CEF_INCLUDE_CEF_MESSAGE_H_
+#pragma once
+
+#include "include/cef_base.h"
+#include "include/cef_shared_memory_region.h"
+#include "include/cef_values.h"
+
+typedef cef_process_id_t CefProcessId;
+
+///
+/// Class representing a message. Can be used on any process and thread.
+///
+/*--cef(source=library)--*/
+class CefProcessMessage : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Create a new CefProcessMessage object with the specified name.
+ ///
+ /*--cef()--*/
+ static CefRefPtr<CefProcessMessage> Create(const CefString& name);
+
+ ///
+ /// Returns true if this object is valid. Do not call any other methods if
+ /// this function returns false.
+ ///
+ /*--cef()--*/
+ virtual bool IsValid() = 0;
+
+ ///
+ /// Returns true if the values of this object are read-only. Some APIs may
+ /// expose read-only objects.
+ ///
+ /*--cef()--*/
+ virtual bool IsReadOnly() = 0;
+
+ ///
+ /// Returns a writable copy of this object.
+ /// Returns nullptr when message contains a shared memory region.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefProcessMessage> Copy() = 0;
+
+ ///
+ /// Returns the message name.
+ ///
+ /*--cef()--*/
+ virtual CefString GetName() = 0;
+
+ ///
+ /// Returns the list of arguments.
+ /// Returns nullptr when message contains a shared memory region.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefListValue> GetArgumentList() = 0;
+
+ ///
+ /// Returns the shared memory region.
+ /// Returns nullptr when message contains an argument list.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefSharedMemoryRegion> GetSharedMemoryRegion() = 0;
+};
+
+#endif // CEF_INCLUDE_CEF_MESSAGE_H_
diff --git a/include/cef_process_util.h b/include/cef_process_util.h
new file mode 100644
index 00000000..c3e67312
--- /dev/null
+++ b/include/cef_process_util.h
@@ -0,0 +1,57 @@
+// Copyright (c) 2012 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_PROCESS_UTIL_H_
+#define CEF_INCLUDE_CEF_PROCESS_UTIL_H_
+#pragma once
+
+#include "include/cef_base.h"
+#include "include/cef_command_line.h"
+
+///
+/// Launches the process specified via |command_line|. Returns true upon
+/// success. Must be called on the browser process TID_PROCESS_LAUNCHER thread.
+///
+/// Unix-specific notes:
+/// - All file descriptors open in the parent process will be closed in the
+/// child process except for stdin, stdout, and stderr.
+/// - If the first argument on the command line does not contain a slash,
+/// PATH will be searched. (See man execvp.)
+///
+/*--cef()--*/
+bool CefLaunchProcess(CefRefPtr<CefCommandLine> command_line);
+
+#endif // CEF_INCLUDE_CEF_PROCESS_UTIL_H_
diff --git a/include/cef_registration.h b/include/cef_registration.h
new file mode 100644
index 00000000..87c9eee1
--- /dev/null
+++ b/include/cef_registration.h
@@ -0,0 +1,49 @@
+// Copyright (c) 2020 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_REGISTRATION_H_
+#define CEF_INCLUDE_CEF_REGISTRATION_H_
+#pragma once
+
+#include "include/cef_base.h"
+
+///
+/// Generic callback interface used for managing the lifespan of a registration.
+///
+/*--cef(source=library)--*/
+class CefRegistration : public virtual CefBaseRefCounted {};
+
+#endif // CEF_INCLUDE_CEF_REGISTRATION_H_
diff --git a/include/cef_render_handler.h b/include/cef_render_handler.h
new file mode 100644
index 00000000..b27403f9
--- /dev/null
+++ b/include/cef_render_handler.h
@@ -0,0 +1,255 @@
+// Copyright (c) 2012 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_RENDER_HANDLER_H_
+#define CEF_INCLUDE_CEF_RENDER_HANDLER_H_
+#pragma once
+
+#include <vector>
+
+#include "include/cef_accessibility_handler.h"
+#include "include/cef_base.h"
+#include "include/cef_browser.h"
+#include "include/cef_drag_data.h"
+
+///
+/// Implement this interface to handle events when window rendering is disabled.
+/// The methods of this class will be called on the UI thread.
+///
+/*--cef(source=client)--*/
+class CefRenderHandler : public virtual CefBaseRefCounted {
+ public:
+ typedef cef_drag_operations_mask_t DragOperation;
+ typedef cef_drag_operations_mask_t DragOperationsMask;
+ typedef cef_paint_element_type_t PaintElementType;
+ typedef std::vector<CefRect> RectList;
+ typedef cef_text_input_mode_t TextInputMode;
+
+ ///
+ /// Return the handler for accessibility notifications. If no handler is
+ /// provided the default implementation will be used.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefAccessibilityHandler> GetAccessibilityHandler() {
+ return nullptr;
+ }
+
+ ///
+ /// Called to retrieve the root window rectangle in screen DIP coordinates.
+ /// Return true if the rectangle was provided. If this method returns false
+ /// the rectangle from GetViewRect will be used.
+ ///
+ /*--cef()--*/
+ virtual bool GetRootScreenRect(CefRefPtr<CefBrowser> browser, CefRect& rect) {
+ return false;
+ }
+
+ ///
+ /// Called to retrieve the view rectangle in screen DIP coordinates. This
+ /// method must always provide a non-empty rectangle.
+ ///
+ /*--cef()--*/
+ virtual void GetViewRect(CefRefPtr<CefBrowser> browser, CefRect& rect) = 0;
+
+ ///
+ /// Called to retrieve the translation from view DIP coordinates to screen
+ /// coordinates. Windows/Linux should provide screen device (pixel)
+ /// coordinates and MacOS should provide screen DIP coordinates. Return true
+ /// if the requested coordinates were provided.
+ ///
+ /*--cef()--*/
+ virtual bool GetScreenPoint(CefRefPtr<CefBrowser> browser,
+ int viewX,
+ int viewY,
+ int& screenX,
+ int& screenY) {
+ return false;
+ }
+
+ ///
+ /// Called to allow the client to fill in the CefScreenInfo object with
+ /// appropriate values. Return true if the |screen_info| structure has been
+ /// modified.
+ ///
+ /// If the screen info rectangle is left empty the rectangle from GetViewRect
+ /// will be used. If the rectangle is still empty or invalid popups may not be
+ /// drawn correctly.
+ ///
+ /*--cef()--*/
+ virtual bool GetScreenInfo(CefRefPtr<CefBrowser> browser,
+ CefScreenInfo& screen_info) {
+ return false;
+ }
+
+ ///
+ /// Called when the browser wants to show or hide the popup widget. The popup
+ /// should be shown if |show| is true and hidden if |show| is false.
+ ///
+ /*--cef()--*/
+ virtual void OnPopupShow(CefRefPtr<CefBrowser> browser, bool show) {}
+
+ ///
+ /// Called when the browser wants to move or resize the popup widget. |rect|
+ /// contains the new location and size in view coordinates.
+ ///
+ /*--cef()--*/
+ virtual void OnPopupSize(CefRefPtr<CefBrowser> browser, const CefRect& rect) {
+ }
+
+ ///
+ /// Called when an element should be painted. Pixel values passed to this
+ /// method are scaled relative to view coordinates based on the value of
+ /// CefScreenInfo.device_scale_factor returned from GetScreenInfo. |type|
+ /// indicates whether the element is the view or the popup widget. |buffer|
+ /// contains the pixel data for the whole image. |dirtyRects| contains the set
+ /// of rectangles in pixel coordinates that need to be repainted. |buffer|
+ /// will be |width|*|height|*4 bytes in size and represents a BGRA image with
+ /// an upper-left origin. This method is only called when
+ /// CefWindowInfo::shared_texture_enabled is set to false.
+ ///
+ /*--cef()--*/
+ virtual void OnPaint(CefRefPtr<CefBrowser> browser,
+ PaintElementType type,
+ const RectList& dirtyRects,
+ const void* buffer,
+ int width,
+ int height) = 0;
+
+ ///
+ /// Called when an element has been rendered to the shared texture handle.
+ /// |type| indicates whether the element is the view or the popup widget.
+ /// |dirtyRects| contains the set of rectangles in pixel coordinates that need
+ /// to be repainted. |shared_handle| is the handle for a D3D11 Texture2D that
+ /// can be accessed via ID3D11Device using the OpenSharedResource method. This
+ /// method is only called when CefWindowInfo::shared_texture_enabled is set to
+ /// true, and is currently only supported on Windows.
+ ///
+ /*--cef()--*/
+ virtual void OnAcceleratedPaint(CefRefPtr<CefBrowser> browser,
+ PaintElementType type,
+ const RectList& dirtyRects,
+ void* shared_handle) {}
+
+ ///
+ /// Called to retrieve the size of the touch handle for the specified
+ /// |orientation|.
+ ///
+ /*--cef()--*/
+ virtual void GetTouchHandleSize(CefRefPtr<CefBrowser> browser,
+ cef_horizontal_alignment_t orientation,
+ CefSize& size) {}
+
+ ///
+ /// Called when touch handle state is updated. The client is responsible for
+ /// rendering the touch handles.
+ ///
+ /*--cef()--*/
+ virtual void OnTouchHandleStateChanged(CefRefPtr<CefBrowser> browser,
+ const CefTouchHandleState& state) {}
+
+ ///
+ /// Called when the user starts dragging content in the web view. Contextual
+ /// information about the dragged content is supplied by |drag_data|.
+ /// (|x|, |y|) is the drag start location in screen coordinates.
+ /// OS APIs that run a system message loop may be used within the
+ /// StartDragging call.
+ ///
+ /// Return false to abort the drag operation. Don't call any of
+ /// CefBrowserHost::DragSource*Ended* methods after returning false.
+ ///
+ /// Return true to handle the drag operation. Call
+ /// CefBrowserHost::DragSourceEndedAt and DragSourceSystemDragEnded either
+ /// synchronously or asynchronously to inform the web view that the drag
+ /// operation has ended.
+ ///
+ /*--cef()--*/
+ virtual bool StartDragging(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefDragData> drag_data,
+ DragOperationsMask allowed_ops,
+ int x,
+ int y) {
+ return false;
+ }
+
+ ///
+ /// Called when the web view wants to update the mouse cursor during a
+ /// drag & drop operation. |operation| describes the allowed operation
+ /// (none, move, copy, link).
+ ///
+ /*--cef()--*/
+ virtual void UpdateDragCursor(CefRefPtr<CefBrowser> browser,
+ DragOperation operation) {}
+
+ ///
+ /// Called when the scroll offset has changed.
+ ///
+ /*--cef()--*/
+ virtual void OnScrollOffsetChanged(CefRefPtr<CefBrowser> browser,
+ double x,
+ double y) {}
+
+ ///
+ /// Called when the IME composition range has changed. |selected_range| is the
+ /// range of characters that have been selected. |character_bounds| is the
+ /// bounds of each character in view coordinates.
+ ///
+ /*--cef()--*/
+ virtual void OnImeCompositionRangeChanged(CefRefPtr<CefBrowser> browser,
+ const CefRange& selected_range,
+ const RectList& character_bounds) {}
+
+ ///
+ /// Called when text selection has changed for the specified |browser|.
+ /// |selected_text| is the currently selected text and |selected_range| is
+ /// the character range.
+ ///
+ /*--cef(optional_param=selected_text,optional_param=selected_range)--*/
+ virtual void OnTextSelectionChanged(CefRefPtr<CefBrowser> browser,
+ const CefString& selected_text,
+ const CefRange& selected_range) {}
+
+ ///
+ /// Called when an on-screen keyboard should be shown or hidden for the
+ /// specified |browser|. |input_mode| specifies what kind of keyboard
+ /// should be opened. If |input_mode| is CEF_TEXT_INPUT_MODE_NONE, any
+ /// existing keyboard for this browser should be hidden.
+ ///
+ /*--cef()--*/
+ virtual void OnVirtualKeyboardRequested(CefRefPtr<CefBrowser> browser,
+ TextInputMode input_mode) {}
+};
+
+#endif // CEF_INCLUDE_CEF_RENDER_HANDLER_H_
diff --git a/include/cef_render_process_handler.h b/include/cef_render_process_handler.h
new file mode 100644
index 00000000..a9049ba2
--- /dev/null
+++ b/include/cef_render_process_handler.h
@@ -0,0 +1,150 @@
+// Copyright (c) 2013 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_RENDER_PROCESS_HANDLER_H_
+#define CEF_INCLUDE_CEF_RENDER_PROCESS_HANDLER_H_
+#pragma once
+
+#include "include/cef_base.h"
+#include "include/cef_browser.h"
+#include "include/cef_dom.h"
+#include "include/cef_frame.h"
+#include "include/cef_load_handler.h"
+#include "include/cef_process_message.h"
+#include "include/cef_v8.h"
+#include "include/cef_values.h"
+
+///
+/// Class used to implement render process callbacks. The methods of this class
+/// will be called on the render process main thread (TID_RENDERER) unless
+/// otherwise indicated.
+///
+/*--cef(source=client,no_debugct_check)--*/
+class CefRenderProcessHandler : public virtual CefBaseRefCounted {
+ public:
+ typedef cef_navigation_type_t NavigationType;
+
+ ///
+ /// Called after WebKit has been initialized.
+ ///
+ /*--cef()--*/
+ virtual void OnWebKitInitialized() {}
+
+ ///
+ /// Called after a browser has been created. When browsing cross-origin a new
+ /// browser will be created before the old browser with the same identifier is
+ /// destroyed. |extra_info| is an optional read-only value originating from
+ /// CefBrowserHost::CreateBrowser(), CefBrowserHost::CreateBrowserSync(),
+ /// CefLifeSpanHandler::OnBeforePopup() or
+ /// CefBrowserView::CreateBrowserView().
+ ///
+ /*--cef(optional_param=extra_info)--*/
+ virtual void OnBrowserCreated(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefDictionaryValue> extra_info) {}
+
+ ///
+ /// Called before a browser is destroyed.
+ ///
+ /*--cef()--*/
+ virtual void OnBrowserDestroyed(CefRefPtr<CefBrowser> browser) {}
+
+ ///
+ /// Return the handler for browser load status events.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefLoadHandler> GetLoadHandler() { return nullptr; }
+
+ ///
+ /// Called immediately after the V8 context for a frame has been created. To
+ /// retrieve the JavaScript 'window' object use the CefV8Context::GetGlobal()
+ /// method. V8 handles can only be accessed from the thread on which they are
+ /// created. A task runner for posting tasks on the associated thread can be
+ /// retrieved via the CefV8Context::GetTaskRunner() method.
+ ///
+ /*--cef()--*/
+ virtual void OnContextCreated(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefV8Context> context) {}
+
+ ///
+ /// Called immediately before the V8 context for a frame is released. No
+ /// references to the context should be kept after this method is called.
+ ///
+ /*--cef()--*/
+ virtual void OnContextReleased(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefV8Context> context) {}
+
+ ///
+ /// Called for global uncaught exceptions in a frame. Execution of this
+ /// callback is disabled by default. To enable set
+ /// cef_settings_t.uncaught_exception_stack_size > 0.
+ ///
+ /*--cef()--*/
+ virtual void OnUncaughtException(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefV8Context> context,
+ CefRefPtr<CefV8Exception> exception,
+ CefRefPtr<CefV8StackTrace> stackTrace) {}
+
+ ///
+ /// Called when a new node in the the browser gets focus. The |node| value may
+ /// be empty if no specific node has gained focus. The node object passed to
+ /// this method represents a snapshot of the DOM at the time this method is
+ /// executed. DOM objects are only valid for the scope of this method. Do not
+ /// keep references to or attempt to access any DOM objects outside the scope
+ /// of this method.
+ ///
+ /*--cef(optional_param=frame,optional_param=node)--*/
+ virtual void OnFocusedNodeChanged(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefDOMNode> node) {}
+
+ ///
+ /// Called when a new message is received from a different process. Return
+ /// true if the message was handled or false otherwise. It is safe to keep a
+ /// reference to |message| outside of this callback.
+ ///
+ /*--cef()--*/
+ virtual bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefProcessId source_process,
+ CefRefPtr<CefProcessMessage> message) {
+ return false;
+ }
+};
+
+#endif // CEF_INCLUDE_CEF_RENDER_PROCESS_HANDLER_H_
diff --git a/include/cef_request.h b/include/cef_request.h
new file mode 100644
index 00000000..138b4f1e
--- /dev/null
+++ b/include/cef_request.h
@@ -0,0 +1,354 @@
+// Copyright (c) 2012 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_REQUEST_H_
+#define CEF_INCLUDE_CEF_REQUEST_H_
+#pragma once
+
+#include <map>
+#include <vector>
+#include "include/cef_base.h"
+
+class CefPostData;
+class CefPostDataElement;
+
+///
+/// Class used to represent a web request. The methods of this class may be
+/// called on any thread.
+///
+/*--cef(source=library,no_debugct_check)--*/
+class CefRequest : public virtual CefBaseRefCounted {
+ public:
+ typedef std::multimap<CefString, CefString> HeaderMap;
+ typedef cef_referrer_policy_t ReferrerPolicy;
+ typedef cef_resource_type_t ResourceType;
+ typedef cef_transition_type_t TransitionType;
+
+ ///
+ /// Create a new CefRequest object.
+ ///
+ /*--cef()--*/
+ static CefRefPtr<CefRequest> Create();
+
+ ///
+ /// Returns true if this object is read-only.
+ ///
+ /*--cef()--*/
+ virtual bool IsReadOnly() = 0;
+
+ ///
+ /// Get the fully qualified URL.
+ ///
+ /*--cef()--*/
+ virtual CefString GetURL() = 0;
+
+ ///
+ /// Set the fully qualified URL.
+ ///
+ /*--cef()--*/
+ virtual void SetURL(const CefString& url) = 0;
+
+ ///
+ /// Get the request method type. The value will default to POST if post data
+ /// is provided and GET otherwise.
+ ///
+ /*--cef()--*/
+ virtual CefString GetMethod() = 0;
+
+ ///
+ /// Set the request method type.
+ ///
+ /*--cef()--*/
+ virtual void SetMethod(const CefString& method) = 0;
+
+ ///
+ /// Set the referrer URL and policy. If non-empty the referrer URL must be
+ /// fully qualified with an HTTP or HTTPS scheme component. Any username,
+ /// password or ref component will be removed.
+ ///
+ /*--cef(optional_param=referrer_url)--*/
+ virtual void SetReferrer(const CefString& referrer_url,
+ ReferrerPolicy policy) = 0;
+
+ ///
+ /// Get the referrer URL.
+ ///
+ /*--cef()--*/
+ virtual CefString GetReferrerURL() = 0;
+
+ ///
+ /// Get the referrer policy.
+ ///
+ /*--cef(default_retval=REFERRER_POLICY_DEFAULT)--*/
+ virtual ReferrerPolicy GetReferrerPolicy() = 0;
+
+ ///
+ /// Get the post data.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefPostData> GetPostData() = 0;
+
+ ///
+ /// Set the post data.
+ ///
+ /*--cef()--*/
+ virtual void SetPostData(CefRefPtr<CefPostData> postData) = 0;
+
+ ///
+ /// Get the header values. Will not include the Referer value if any.
+ ///
+ /*--cef()--*/
+ virtual void GetHeaderMap(HeaderMap& headerMap) = 0;
+
+ ///
+ /// Set the header values. If a Referer value exists in the header map it will
+ /// be removed and ignored.
+ ///
+ /*--cef()--*/
+ virtual void SetHeaderMap(const HeaderMap& headerMap) = 0;
+
+ ///
+ /// Returns the first header value for |name| or an empty string if not found.
+ /// Will not return the Referer value if any. Use GetHeaderMap instead if
+ /// |name| might have multiple values.
+ ///
+ /*--cef()--*/
+ virtual CefString GetHeaderByName(const CefString& name) = 0;
+
+ ///
+ /// Set the header |name| to |value|. If |overwrite| is true any existing
+ /// values will be replaced with the new value. If |overwrite| is false any
+ /// existing values will not be overwritten. The Referer value cannot be set
+ /// using this method.
+ ///
+ /*--cef(optional_param=value)--*/
+ virtual void SetHeaderByName(const CefString& name,
+ const CefString& value,
+ bool overwrite) = 0;
+
+ ///
+ /// Set all values at one time.
+ ///
+ /*--cef(optional_param=postData)--*/
+ virtual void Set(const CefString& url,
+ const CefString& method,
+ CefRefPtr<CefPostData> postData,
+ const HeaderMap& headerMap) = 0;
+
+ ///
+ /// Get the flags used in combination with CefURLRequest. See
+ /// cef_urlrequest_flags_t for supported values.
+ ///
+ /*--cef(default_retval=UR_FLAG_NONE)--*/
+ virtual int GetFlags() = 0;
+
+ ///
+ /// Set the flags used in combination with CefURLRequest. See
+ /// cef_urlrequest_flags_t for supported values.
+ ///
+ /*--cef()--*/
+ virtual void SetFlags(int flags) = 0;
+
+ ///
+ /// Get the URL to the first party for cookies used in combination with
+ /// CefURLRequest.
+ ///
+ /*--cef()--*/
+ virtual CefString GetFirstPartyForCookies() = 0;
+
+ ///
+ /// Set the URL to the first party for cookies used in combination with
+ /// CefURLRequest.
+ ///
+ /*--cef(optional_param=url)--*/
+ virtual void SetFirstPartyForCookies(const CefString& url) = 0;
+
+ ///
+ /// Get the resource type for this request. Only available in the browser
+ /// process.
+ ///
+ /*--cef(default_retval=RT_SUB_RESOURCE)--*/
+ virtual ResourceType GetResourceType() = 0;
+
+ ///
+ /// Get the transition type for this request. Only available in the browser
+ /// process and only applies to requests that represent a main frame or
+ /// sub-frame navigation.
+ ///
+ /*--cef(default_retval=TT_EXPLICIT)--*/
+ virtual TransitionType GetTransitionType() = 0;
+
+ ///
+ /// Returns the globally unique identifier for this request or 0 if not
+ /// specified. Can be used by CefResourceRequestHandler implementations in the
+ /// browser process to track a single request across multiple callbacks.
+ ///
+ /*--cef()--*/
+ virtual uint64 GetIdentifier() = 0;
+};
+
+///
+/// Class used to represent post data for a web request. The methods of this
+/// class may be called on any thread.
+///
+/*--cef(source=library,no_debugct_check)--*/
+class CefPostData : public virtual CefBaseRefCounted {
+ public:
+ typedef std::vector<CefRefPtr<CefPostDataElement>> ElementVector;
+
+ ///
+ /// Create a new CefPostData object.
+ ///
+ /*--cef()--*/
+ static CefRefPtr<CefPostData> Create();
+
+ ///
+ /// Returns true if this object is read-only.
+ ///
+ /*--cef()--*/
+ virtual bool IsReadOnly() = 0;
+
+ ///
+ /// Returns true if the underlying POST data includes elements that are not
+ /// represented by this CefPostData object (for example, multi-part file
+ /// upload data). Modifying CefPostData objects with excluded elements may
+ /// result in the request failing.
+ ///
+ /*--cef()--*/
+ virtual bool HasExcludedElements() = 0;
+
+ ///
+ /// Returns the number of existing post data elements.
+ ///
+ /*--cef()--*/
+ virtual size_t GetElementCount() = 0;
+
+ ///
+ /// Retrieve the post data elements.
+ ///
+ /*--cef(count_func=elements:GetElementCount)--*/
+ virtual void GetElements(ElementVector& elements) = 0;
+
+ ///
+ /// Remove the specified post data element. Returns true if the removal
+ /// succeeds.
+ ///
+ /*--cef()--*/
+ virtual bool RemoveElement(CefRefPtr<CefPostDataElement> element) = 0;
+
+ ///
+ /// Add the specified post data element. Returns true if the add succeeds.
+ ///
+ /*--cef()--*/
+ virtual bool AddElement(CefRefPtr<CefPostDataElement> element) = 0;
+
+ ///
+ /// Remove all existing post data elements.
+ ///
+ /*--cef()--*/
+ virtual void RemoveElements() = 0;
+};
+
+///
+/// Class used to represent a single element in the request post data. The
+/// methods of this class may be called on any thread.
+///
+/*--cef(source=library,no_debugct_check)--*/
+class CefPostDataElement : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Post data elements may represent either bytes or files.
+ ///
+ typedef cef_postdataelement_type_t Type;
+
+ ///
+ /// Create a new CefPostDataElement object.
+ ///
+ /*--cef()--*/
+ static CefRefPtr<CefPostDataElement> Create();
+
+ ///
+ /// Returns true if this object is read-only.
+ ///
+ /*--cef()--*/
+ virtual bool IsReadOnly() = 0;
+
+ ///
+ /// Remove all contents from the post data element.
+ ///
+ /*--cef()--*/
+ virtual void SetToEmpty() = 0;
+
+ ///
+ /// The post data element will represent a file.
+ ///
+ /*--cef()--*/
+ virtual void SetToFile(const CefString& fileName) = 0;
+
+ ///
+ /// The post data element will represent bytes. The bytes passed
+ /// in will be copied.
+ ///
+ /*--cef()--*/
+ virtual void SetToBytes(size_t size, const void* bytes) = 0;
+
+ ///
+ /// Return the type of this post data element.
+ ///
+ /*--cef(default_retval=PDE_TYPE_EMPTY)--*/
+ virtual Type GetType() = 0;
+
+ ///
+ /// Return the file name.
+ ///
+ /*--cef()--*/
+ virtual CefString GetFile() = 0;
+
+ ///
+ /// Return the number of bytes.
+ ///
+ /*--cef()--*/
+ virtual size_t GetBytesCount() = 0;
+
+ ///
+ /// Read up to |size| bytes into |bytes| and return the number of bytes
+ /// actually read.
+ ///
+ /*--cef()--*/
+ virtual size_t GetBytes(size_t size, void* bytes) = 0;
+};
+
+#endif // CEF_INCLUDE_CEF_REQUEST_H_
diff --git a/include/cef_request_context.h b/include/cef_request_context.h
new file mode 100644
index 00000000..f65fcd83
--- /dev/null
+++ b/include/cef_request_context.h
@@ -0,0 +1,319 @@
+// Copyright (c) 2013 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_REQUEST_CONTEXT_H_
+#define CEF_INCLUDE_CEF_REQUEST_CONTEXT_H_
+#pragma once
+
+#include <vector>
+
+#include "include/cef_callback.h"
+#include "include/cef_cookie.h"
+#include "include/cef_extension.h"
+#include "include/cef_extension_handler.h"
+#include "include/cef_media_router.h"
+#include "include/cef_preference.h"
+
+class CefRequestContextHandler;
+class CefSchemeHandlerFactory;
+
+///
+/// Callback interface for CefRequestContext::ResolveHost.
+///
+/*--cef(source=client)--*/
+class CefResolveCallback : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Called on the UI thread after the ResolveHost request has completed.
+ /// |result| will be the result code. |resolved_ips| will be the list of
+ /// resolved IP addresses or empty if the resolution failed.
+ ///
+ /*--cef(optional_param=resolved_ips)--*/
+ virtual void OnResolveCompleted(
+ cef_errorcode_t result,
+ const std::vector<CefString>& resolved_ips) = 0;
+};
+
+///
+/// A request context provides request handling for a set of related browser
+/// or URL request objects. A request context can be specified when creating a
+/// new browser via the CefBrowserHost static factory methods or when creating a
+/// new URL request via the CefURLRequest static factory methods. Browser
+/// objects with different request contexts will never be hosted in the same
+/// render process. Browser objects with the same request context may or may not
+/// be hosted in the same render process depending on the process model. Browser
+/// objects created indirectly via the JavaScript window.open function or
+/// targeted links will share the same render process and the same request
+/// context as the source browser. When running in single-process mode there is
+/// only a single render process (the main process) and so all browsers created
+/// in single-process mode will share the same request context. This will be the
+/// first request context passed into a CefBrowserHost static factory method and
+/// all other request context objects will be ignored.
+///
+/*--cef(source=library,no_debugct_check)--*/
+class CefRequestContext : public CefPreferenceManager {
+ public:
+ ///
+ /// Returns the global context object.
+ ///
+ /*--cef()--*/
+ static CefRefPtr<CefRequestContext> GetGlobalContext();
+
+ ///
+ /// Creates a new context object with the specified |settings| and optional
+ /// |handler|.
+ ///
+ /*--cef(optional_param=handler)--*/
+ static CefRefPtr<CefRequestContext> CreateContext(
+ const CefRequestContextSettings& settings,
+ CefRefPtr<CefRequestContextHandler> handler);
+
+ ///
+ /// Creates a new context object that shares storage with |other| and uses an
+ /// optional |handler|.
+ ///
+ /*--cef(capi_name=cef_create_context_shared,optional_param=handler)--*/
+ static CefRefPtr<CefRequestContext> CreateContext(
+ CefRefPtr<CefRequestContext> other,
+ CefRefPtr<CefRequestContextHandler> handler);
+
+ ///
+ /// Returns true if this object is pointing to the same context as |that|
+ /// object.
+ ///
+ /*--cef()--*/
+ virtual bool IsSame(CefRefPtr<CefRequestContext> other) = 0;
+
+ ///
+ /// Returns true if this object is sharing the same storage as |that| object.
+ ///
+ /*--cef()--*/
+ virtual bool IsSharingWith(CefRefPtr<CefRequestContext> other) = 0;
+
+ ///
+ /// Returns true if this object is the global context. The global context is
+ /// used by default when creating a browser or URL request with a NULL context
+ /// argument.
+ ///
+ /*--cef()--*/
+ virtual bool IsGlobal() = 0;
+
+ ///
+ /// Returns the handler for this context if any.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefRequestContextHandler> GetHandler() = 0;
+
+ ///
+ /// Returns the cache path for this object. If empty an "incognito mode"
+ /// in-memory cache is being used.
+ ///
+ /*--cef()--*/
+ virtual CefString GetCachePath() = 0;
+
+ ///
+ /// Returns the cookie manager for this object. If |callback| is non-NULL it
+ /// will be executed asnychronously on the UI thread after the manager's
+ /// storage has been initialized.
+ ///
+ /*--cef(optional_param=callback)--*/
+ virtual CefRefPtr<CefCookieManager> GetCookieManager(
+ CefRefPtr<CefCompletionCallback> callback) = 0;
+
+ ///
+ /// Register a scheme handler factory for the specified |scheme_name| and
+ /// optional |domain_name|. An empty |domain_name| value for a standard scheme
+ /// will cause the factory to match all domain names. The |domain_name| value
+ /// will be ignored for non-standard schemes. If |scheme_name| is a built-in
+ /// scheme and no handler is returned by |factory| then the built-in scheme
+ /// handler factory will be called. If |scheme_name| is a custom scheme then
+ /// you must also implement the CefApp::OnRegisterCustomSchemes() method in
+ /// all processes. This function may be called multiple times to change or
+ /// remove the factory that matches the specified |scheme_name| and optional
+ /// |domain_name|. Returns false if an error occurs. This function may be
+ /// called on any thread in the browser process.
+ ///
+ /*--cef(optional_param=domain_name,optional_param=factory)--*/
+ virtual bool RegisterSchemeHandlerFactory(
+ const CefString& scheme_name,
+ const CefString& domain_name,
+ CefRefPtr<CefSchemeHandlerFactory> factory) = 0;
+
+ ///
+ /// Clear all registered scheme handler factories. Returns false on error.
+ /// This function may be called on any thread in the browser process.
+ ///
+ /*--cef()--*/
+ virtual bool ClearSchemeHandlerFactories() = 0;
+
+ ///
+ /// Clears all certificate exceptions that were added as part of handling
+ /// CefRequestHandler::OnCertificateError(). If you call this it is
+ /// recommended that you also call CloseAllConnections() or you risk not
+ /// being prompted again for server certificates if you reconnect quickly.
+ /// If |callback| is non-NULL it will be executed on the UI thread after
+ /// completion.
+ ///
+ /*--cef(optional_param=callback)--*/
+ virtual void ClearCertificateExceptions(
+ CefRefPtr<CefCompletionCallback> callback) = 0;
+
+ ///
+ /// Clears all HTTP authentication credentials that were added as part of
+ /// handling GetAuthCredentials. If |callback| is non-NULL it will be executed
+ /// on the UI thread after completion.
+ ///
+ /*--cef(optional_param=callback)--*/
+ virtual void ClearHttpAuthCredentials(
+ CefRefPtr<CefCompletionCallback> callback) = 0;
+
+ ///
+ /// Clears all active and idle connections that Chromium currently has.
+ /// This is only recommended if you have released all other CEF objects but
+ /// don't yet want to call CefShutdown(). If |callback| is non-NULL it will be
+ /// executed on the UI thread after completion.
+ ///
+ /*--cef(optional_param=callback)--*/
+ virtual void CloseAllConnections(
+ CefRefPtr<CefCompletionCallback> callback) = 0;
+
+ ///
+ /// Attempts to resolve |origin| to a list of associated IP addresses.
+ /// |callback| will be executed on the UI thread after completion.
+ ///
+ /*--cef()--*/
+ virtual void ResolveHost(const CefString& origin,
+ CefRefPtr<CefResolveCallback> callback) = 0;
+
+ ///
+ /// Load an extension.
+ ///
+ /// If extension resources will be read from disk using the default load
+ /// implementation then |root_directory| should be the absolute path to the
+ /// extension resources directory and |manifest| should be NULL. If extension
+ /// resources will be provided by the client (e.g. via CefRequestHandler
+ /// and/or CefExtensionHandler) then |root_directory| should be a path
+ /// component unique to the extension (if not absolute this will be internally
+ /// prefixed with the PK_DIR_RESOURCES path) and |manifest| should contain the
+ /// contents that would otherwise be read from the "manifest.json" file on
+ /// disk.
+ ///
+ /// The loaded extension will be accessible in all contexts sharing the same
+ /// storage (HasExtension returns true). However, only the context on which
+ /// this method was called is considered the loader (DidLoadExtension returns
+ /// true) and only the loader will receive CefRequestContextHandler callbacks
+ /// for the extension.
+ ///
+ /// CefExtensionHandler::OnExtensionLoaded will be called on load success or
+ /// CefExtensionHandler::OnExtensionLoadFailed will be called on load failure.
+ ///
+ /// If the extension specifies a background script via the "background"
+ /// manifest key then CefExtensionHandler::OnBeforeBackgroundBrowser will be
+ /// called to create the background browser. See that method for additional
+ /// information about background scripts.
+ ///
+ /// For visible extension views the client application should evaluate the
+ /// manifest to determine the correct extension URL to load and then pass that
+ /// URL to the CefBrowserHost::CreateBrowser* function after the extension has
+ /// loaded. For example, the client can look for the "browser_action" manifest
+ /// key as documented at
+ /// https://developer.chrome.com/extensions/browserAction. Extension URLs take
+ /// the form "chrome-extension://<extension_id>/<path>".
+ ///
+ /// Browsers that host extensions differ from normal browsers as follows:
+ /// - Can access chrome.* JavaScript APIs if allowed by the manifest. Visit
+ /// chrome://extensions-support for the list of extension APIs currently
+ /// supported by CEF.
+ /// - Main frame navigation to non-extension content is blocked.
+ /// - Pinch-zooming is disabled.
+ /// - CefBrowserHost::GetExtension returns the hosted extension.
+ /// - CefBrowserHost::IsBackgroundHost returns true for background hosts.
+ ///
+ /// See https://developer.chrome.com/extensions for extension implementation
+ /// and usage documentation.
+ ///
+ /*--cef(optional_param=manifest,optional_param=handler)--*/
+ virtual void LoadExtension(const CefString& root_directory,
+ CefRefPtr<CefDictionaryValue> manifest,
+ CefRefPtr<CefExtensionHandler> handler) = 0;
+
+ ///
+ /// Returns true if this context was used to load the extension identified by
+ /// |extension_id|. Other contexts sharing the same storage will also have
+ /// access to the extension (see HasExtension). This method must be called on
+ /// the browser process UI thread.
+ ///
+ /*--cef()--*/
+ virtual bool DidLoadExtension(const CefString& extension_id) = 0;
+
+ ///
+ /// Returns true if this context has access to the extension identified by
+ /// |extension_id|. This may not be the context that was used to load the
+ /// extension (see DidLoadExtension). This method must be called on the
+ /// browser process UI thread.
+ ///
+ /*--cef()--*/
+ virtual bool HasExtension(const CefString& extension_id) = 0;
+
+ ///
+ /// Retrieve the list of all extensions that this context has access to (see
+ /// HasExtension). |extension_ids| will be populated with the list of
+ /// extension ID values. Returns true on success. This method must be called
+ /// on the browser process UI thread.
+ ///
+ /*--cef()--*/
+ virtual bool GetExtensions(std::vector<CefString>& extension_ids) = 0;
+
+ ///
+ /// Returns the extension matching |extension_id| or NULL if no matching
+ /// extension is accessible in this context (see HasExtension). This method
+ /// must be called on the browser process UI thread.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefExtension> GetExtension(
+ const CefString& extension_id) = 0;
+
+ ///
+ /// Returns the MediaRouter object associated with this context. If
+ /// |callback| is non-NULL it will be executed asnychronously on the UI thread
+ /// after the manager's context has been initialized.
+ ///
+ /*--cef(optional_param=callback)--*/
+ virtual CefRefPtr<CefMediaRouter> GetMediaRouter(
+ CefRefPtr<CefCompletionCallback> callback) = 0;
+};
+
+#endif // CEF_INCLUDE_CEF_REQUEST_CONTEXT_H_
diff --git a/include/cef_request_context_handler.h b/include/cef_request_context_handler.h
new file mode 100644
index 00000000..ac8c7710
--- /dev/null
+++ b/include/cef_request_context_handler.h
@@ -0,0 +1,96 @@
+// Copyright (c) 2013 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_REQUEST_CONTEXT_HANDLER_H_
+#define CEF_INCLUDE_CEF_REQUEST_CONTEXT_HANDLER_H_
+#pragma once
+
+#include "include/cef_base.h"
+#include "include/cef_browser.h"
+#include "include/cef_frame.h"
+#include "include/cef_preference.h"
+#include "include/cef_request.h"
+#include "include/cef_resource_request_handler.h"
+
+///
+/// Implement this interface to provide handler implementations. The handler
+/// instance will not be released until all objects related to the context have
+/// been destroyed.
+///
+/*--cef(source=client,no_debugct_check)--*/
+class CefRequestContextHandler : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Called on the browser process UI thread immediately after the request
+ /// context has been initialized.
+ ///
+ /*--cef()--*/
+ virtual void OnRequestContextInitialized(
+ CefRefPtr<CefRequestContext> request_context) {}
+
+ ///
+ /// Called on the browser process IO thread before a resource request is
+ /// initiated. The |browser| and |frame| values represent the source of the
+ /// request, and may be NULL for requests originating from service workers or
+ /// CefURLRequest. |request| represents the request contents and cannot be
+ /// modified in this callback. |is_navigation| will be true if the resource
+ /// request is a navigation. |is_download| will be true if the resource
+ /// request is a download. |request_initiator| is the origin (scheme + domain)
+ /// of the page that initiated the request. Set |disable_default_handling| to
+ /// true to disable default handling of the request, in which case it will
+ /// need to be handled via CefResourceRequestHandler::GetResourceHandler or it
+ /// will be canceled. To allow the resource load to proceed with default
+ /// handling return NULL. To specify a handler for the resource return a
+ /// CefResourceRequestHandler object. This method will not be called if the
+ /// client associated with |browser| returns a non-NULL value from
+ /// CefRequestHandler::GetResourceRequestHandler for the same request
+ /// (identified by CefRequest::GetIdentifier).
+ ///
+ /*--cef(optional_param=browser,optional_param=frame,
+ optional_param=request_initiator)--*/
+ virtual CefRefPtr<CefResourceRequestHandler> GetResourceRequestHandler(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ bool is_navigation,
+ bool is_download,
+ const CefString& request_initiator,
+ bool& disable_default_handling) {
+ return nullptr;
+ }
+};
+
+#endif // CEF_INCLUDE_CEF_REQUEST_CONTEXT_HANDLER_H_
diff --git a/include/cef_request_handler.h b/include/cef_request_handler.h
new file mode 100644
index 00000000..edeefbd1
--- /dev/null
+++ b/include/cef_request_handler.h
@@ -0,0 +1,241 @@
+// Copyright (c) 2011 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_REQUEST_HANDLER_H_
+#define CEF_INCLUDE_CEF_REQUEST_HANDLER_H_
+#pragma once
+
+#include <vector>
+
+#include "include/cef_auth_callback.h"
+#include "include/cef_base.h"
+#include "include/cef_browser.h"
+#include "include/cef_callback.h"
+#include "include/cef_frame.h"
+#include "include/cef_request.h"
+#include "include/cef_resource_request_handler.h"
+#include "include/cef_ssl_info.h"
+#include "include/cef_x509_certificate.h"
+
+///
+/// Callback interface used to select a client certificate for authentication.
+///
+/*--cef(source=library)--*/
+class CefSelectClientCertificateCallback : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Chooses the specified certificate for client certificate authentication.
+ /// NULL value means that no client certificate should be used.
+ ///
+ /*--cef(optional_param=cert)--*/
+ virtual void Select(CefRefPtr<CefX509Certificate> cert) = 0;
+};
+
+///
+/// Implement this interface to handle events related to browser requests. The
+/// methods of this class will be called on the thread indicated.
+///
+/*--cef(source=client)--*/
+class CefRequestHandler : public virtual CefBaseRefCounted {
+ public:
+ typedef cef_termination_status_t TerminationStatus;
+ typedef cef_window_open_disposition_t WindowOpenDisposition;
+ typedef std::vector<CefRefPtr<CefX509Certificate>> X509CertificateList;
+
+ ///
+ /// Called on the UI thread before browser navigation. Return true to cancel
+ /// the navigation or false to allow the navigation to proceed. The |request|
+ /// object cannot be modified in this callback.
+ /// CefLoadHandler::OnLoadingStateChange will be called twice in all cases.
+ /// If the navigation is allowed CefLoadHandler::OnLoadStart and
+ /// CefLoadHandler::OnLoadEnd will be called. If the navigation is canceled
+ /// CefLoadHandler::OnLoadError will be called with an |errorCode| value of
+ /// ERR_ABORTED. The |user_gesture| value will be true if the browser
+ /// navigated via explicit user gesture (e.g. clicking a link) or false if it
+ /// navigated automatically (e.g. via the DomContentLoaded event).
+ ///
+ /*--cef()--*/
+ virtual bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ bool user_gesture,
+ bool is_redirect) {
+ return false;
+ }
+
+ ///
+ /// Called on the UI thread before OnBeforeBrowse in certain limited cases
+ /// where navigating a new or different browser might be desirable. This
+ /// includes user-initiated navigation that might open in a special way (e.g.
+ /// links clicked via middle-click or ctrl + left-click) and certain types of
+ /// cross-origin navigation initiated from the renderer process (e.g.
+ /// navigating the top-level frame to/from a file URL). The |browser| and
+ /// |frame| values represent the source of the navigation. The
+ /// |target_disposition| value indicates where the user intended to navigate
+ /// the browser based on standard Chromium behaviors (e.g. current tab,
+ /// new tab, etc). The |user_gesture| value will be true if the browser
+ /// navigated via explicit user gesture (e.g. clicking a link) or false if it
+ /// navigated automatically (e.g. via the DomContentLoaded event). Return true
+ /// to cancel the navigation or false to allow the navigation to proceed in
+ /// the source browser's top-level frame.
+ ///
+ /*--cef()--*/
+ virtual bool OnOpenURLFromTab(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const CefString& target_url,
+ WindowOpenDisposition target_disposition,
+ bool user_gesture) {
+ return false;
+ }
+
+ ///
+ /// Called on the browser process IO thread before a resource request is
+ /// initiated. The |browser| and |frame| values represent the source of the
+ /// request. |request| represents the request contents and cannot be modified
+ /// in this callback. |is_navigation| will be true if the resource request is
+ /// a navigation. |is_download| will be true if the resource request is a
+ /// download. |request_initiator| is the origin (scheme + domain) of the page
+ /// that initiated the request. Set |disable_default_handling| to true to
+ /// disable default handling of the request, in which case it will need to be
+ /// handled via CefResourceRequestHandler::GetResourceHandler or it will be
+ /// canceled. To allow the resource load to proceed with default handling
+ /// return NULL. To specify a handler for the resource return a
+ /// CefResourceRequestHandler object. If this callback returns NULL the same
+ /// method will be called on the associated CefRequestContextHandler, if any.
+ ///
+ /*--cef(optional_param=request_initiator)--*/
+ virtual CefRefPtr<CefResourceRequestHandler> GetResourceRequestHandler(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ bool is_navigation,
+ bool is_download,
+ const CefString& request_initiator,
+ bool& disable_default_handling) {
+ return nullptr;
+ }
+
+ ///
+ /// Called on the IO thread when the browser needs credentials from the user.
+ /// |origin_url| is the origin making this authentication request. |isProxy|
+ /// indicates whether the host is a proxy server. |host| contains the hostname
+ /// and |port| contains the port number. |realm| is the realm of the challenge
+ /// and may be empty. |scheme| is the authentication scheme used, such as
+ /// "basic" or "digest", and will be empty if the source of the request is an
+ /// FTP server. Return true to continue the request and call
+ /// CefAuthCallback::Continue() either in this method or at a later time when
+ /// the authentication information is available. Return false to cancel the
+ /// request immediately.
+ ///
+ /*--cef(optional_param=realm,optional_param=scheme)--*/
+ virtual bool GetAuthCredentials(CefRefPtr<CefBrowser> browser,
+ const CefString& origin_url,
+ bool isProxy,
+ const CefString& host,
+ int port,
+ const CefString& realm,
+ const CefString& scheme,
+ CefRefPtr<CefAuthCallback> callback) {
+ return false;
+ }
+
+ ///
+ /// Called on the UI thread to handle requests for URLs with an invalid
+ /// SSL certificate. Return true and call CefCallback methods either in this
+ /// method or at a later time to continue or cancel the request. Return false
+ /// to cancel the request immediately. If
+ /// cef_settings_t.ignore_certificate_errors is set all invalid certificates
+ /// will be accepted without calling this method.
+ ///
+ /*--cef()--*/
+ virtual bool OnCertificateError(CefRefPtr<CefBrowser> browser,
+ cef_errorcode_t cert_error,
+ const CefString& request_url,
+ CefRefPtr<CefSSLInfo> ssl_info,
+ CefRefPtr<CefCallback> callback) {
+ return false;
+ }
+
+ ///
+ /// Called on the UI thread when a client certificate is being requested for
+ /// authentication. Return false to use the default behavior and automatically
+ /// select the first certificate available. Return true and call
+ /// CefSelectClientCertificateCallback::Select either in this method or at a
+ /// later time to select a certificate. Do not call Select or call it with
+ /// NULL to continue without using any certificate. |isProxy| indicates
+ /// whether the host is an HTTPS proxy or the origin server. |host| and |port|
+ /// contains the hostname and port of the SSL server. |certificates| is the
+ /// list of certificates to choose from; this list has already been pruned by
+ /// Chromium so that it only contains certificates from issuers that the
+ /// server trusts.
+ ///
+ /*--cef()--*/
+ virtual bool OnSelectClientCertificate(
+ CefRefPtr<CefBrowser> browser,
+ bool isProxy,
+ const CefString& host,
+ int port,
+ const X509CertificateList& certificates,
+ CefRefPtr<CefSelectClientCertificateCallback> callback) {
+ return false;
+ }
+
+ ///
+ /// Called on the browser process UI thread when the render view associated
+ /// with |browser| is ready to receive/handle IPC messages in the render
+ /// process.
+ ///
+ /*--cef()--*/
+ virtual void OnRenderViewReady(CefRefPtr<CefBrowser> browser) {}
+
+ ///
+ /// Called on the browser process UI thread when the render process
+ /// terminates unexpectedly. |status| indicates how the process
+ /// terminated.
+ ///
+ /*--cef()--*/
+ virtual void OnRenderProcessTerminated(CefRefPtr<CefBrowser> browser,
+ TerminationStatus status) {}
+
+ ///
+ /// Called on the browser process UI thread when the window.document object of
+ /// the main frame has been created.
+ ///
+ /*--cef()--*/
+ virtual void OnDocumentAvailableInMainFrame(CefRefPtr<CefBrowser> browser) {}
+};
+
+#endif // CEF_INCLUDE_CEF_REQUEST_HANDLER_H_
diff --git a/include/cef_resource_bundle.h b/include/cef_resource_bundle.h
new file mode 100644
index 00000000..d235e1c4
--- /dev/null
+++ b/include/cef_resource_bundle.h
@@ -0,0 +1,91 @@
+// Copyright (c) 2015 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_RESOURCE_BUNDLE_H_
+#define CEF_INCLUDE_CEF_RESOURCE_BUNDLE_H_
+#pragma once
+
+#include "include/cef_base.h"
+#include "include/cef_values.h"
+
+///
+/// Class used for retrieving resources from the resource bundle (*.pak) files
+/// loaded by CEF during startup or via the CefResourceBundleHandler returned
+/// from CefApp::GetResourceBundleHandler. See CefSettings for additional
+/// options related to resource bundle loading. The methods of this class may be
+/// called on any thread unless otherwise indicated.
+///
+/*--cef(source=library,no_debugct_check)--*/
+class CefResourceBundle : public virtual CefBaseRefCounted {
+ public:
+ typedef cef_scale_factor_t ScaleFactor;
+
+ ///
+ /// Returns the global resource bundle instance.
+ ///
+ /*--cef()--*/
+ static CefRefPtr<CefResourceBundle> GetGlobal();
+
+ ///
+ /// Returns the localized string for the specified |string_id| or an empty
+ /// string if the value is not found. Include cef_pack_strings.h for a listing
+ /// of valid string ID values.
+ ///
+ /*--cef()--*/
+ virtual CefString GetLocalizedString(int string_id) = 0;
+
+ ///
+ /// Returns a CefBinaryValue containing the decompressed contents of the
+ /// specified scale independent |resource_id| or NULL if not found. Include
+ /// cef_pack_resources.h for a listing of valid resource ID values.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefBinaryValue> GetDataResource(int resource_id) = 0;
+
+ ///
+ /// Returns a CefBinaryValue containing the decompressed contents of the
+ /// specified |resource_id| nearest the scale factor |scale_factor| or NULL if
+ /// not found. Use a |scale_factor| value of SCALE_FACTOR_NONE for scale
+ /// independent resources or call GetDataResource instead.Include
+ /// cef_pack_resources.h for a listing of valid resource ID values.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefBinaryValue> GetDataResourceForScale(
+ int resource_id,
+ ScaleFactor scale_factor) = 0;
+};
+
+#endif // CEF_INCLUDE_CEF_RESOURCE_BUNDLE_H_
diff --git a/include/cef_resource_bundle_handler.h b/include/cef_resource_bundle_handler.h
new file mode 100644
index 00000000..4743482c
--- /dev/null
+++ b/include/cef_resource_bundle_handler.h
@@ -0,0 +1,90 @@
+// Copyright (c) 2012 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_RESOURCE_BUNDLE_HANDLER_H_
+#define CEF_INCLUDE_CEF_RESOURCE_BUNDLE_HANDLER_H_
+#pragma once
+
+#include "include/cef_base.h"
+
+///
+/// Class used to implement a custom resource bundle interface. See CefSettings
+/// for additional options related to resource bundle loading. The methods of
+/// this class may be called on multiple threads.
+///
+/*--cef(source=client)--*/
+class CefResourceBundleHandler : public virtual CefBaseRefCounted {
+ public:
+ typedef cef_scale_factor_t ScaleFactor;
+
+ ///
+ /// Called to retrieve a localized translation for the specified |string_id|.
+ /// To provide the translation set |string| to the translation string and
+ /// return true. To use the default translation return false. Include
+ /// cef_pack_strings.h for a listing of valid string ID values.
+ ///
+ /*--cef()--*/
+ virtual bool GetLocalizedString(int string_id, CefString& string) = 0;
+
+ ///
+ /// Called to retrieve data for the specified scale independent |resource_id|.
+ /// To provide the resource data set |data| and |data_size| to the data
+ /// pointer and size respectively and return true. To use the default resource
+ /// data return false. The resource data will not be copied and must remain
+ /// resident in memory. Include cef_pack_resources.h for a listing of valid
+ /// resource ID values.
+ ///
+ /*--cef()--*/
+ virtual bool GetDataResource(int resource_id,
+ void*& data,
+ size_t& data_size) = 0;
+
+ ///
+ /// Called to retrieve data for the specified |resource_id| nearest the scale
+ /// factor |scale_factor|. To provide the resource data set |data| and
+ /// |data_size| to the data pointer and size respectively and return true. To
+ /// use the default resource data return false. The resource data will not be
+ /// copied and must remain resident in memory. Include cef_pack_resources.h
+ /// for a listing of valid resource ID values.
+ ///
+ /*--cef()--*/
+ virtual bool GetDataResourceForScale(int resource_id,
+ ScaleFactor scale_factor,
+ void*& data,
+ size_t& data_size) = 0;
+};
+
+#endif // CEF_INCLUDE_CEF_RESOURCE_BUNDLE_HANDLER_H_
diff --git a/include/cef_resource_handler.h b/include/cef_resource_handler.h
new file mode 100644
index 00000000..30dd76f7
--- /dev/null
+++ b/include/cef_resource_handler.h
@@ -0,0 +1,206 @@
+// Copyright (c) 2012 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_RESOURCE_HANDLER_H_
+#define CEF_INCLUDE_CEF_RESOURCE_HANDLER_H_
+#pragma once
+
+#include "include/cef_base.h"
+#include "include/cef_browser.h"
+#include "include/cef_callback.h"
+#include "include/cef_cookie.h"
+#include "include/cef_request.h"
+#include "include/cef_response.h"
+
+///
+/// Callback for asynchronous continuation of CefResourceHandler::Skip().
+///
+/*--cef(source=library)--*/
+class CefResourceSkipCallback : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Callback for asynchronous continuation of Skip(). If |bytes_skipped| > 0
+ /// then either Skip() will be called again until the requested number of
+ /// bytes have been skipped or the request will proceed. If |bytes_skipped|
+ /// <= 0 the request will fail with ERR_REQUEST_RANGE_NOT_SATISFIABLE.
+ ///
+ /*--cef(capi_name=cont)--*/
+ virtual void Continue(int64 bytes_skipped) = 0;
+};
+
+///
+/// Callback for asynchronous continuation of CefResourceHandler::Read().
+///
+/*--cef(source=library)--*/
+class CefResourceReadCallback : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Callback for asynchronous continuation of Read(). If |bytes_read| == 0
+ /// the response will be considered complete. If |bytes_read| > 0 then Read()
+ /// will be called again until the request is complete (based on either the
+ /// result or the expected content length). If |bytes_read| < 0 then the
+ /// request will fail and the |bytes_read| value will be treated as the error
+ /// code.
+ ///
+ /*--cef(capi_name=cont)--*/
+ virtual void Continue(int bytes_read) = 0;
+};
+
+///
+/// Class used to implement a custom request handler interface. The methods of
+/// this class will be called on the IO thread unless otherwise indicated.
+///
+/*--cef(source=client)--*/
+class CefResourceHandler : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Open the response stream. To handle the request immediately set
+ /// |handle_request| to true and return true. To decide at a later time set
+ /// |handle_request| to false, return true, and execute |callback| to continue
+ /// or cancel the request. To cancel the request immediately set
+ /// |handle_request| to true and return false. This method will be called in
+ /// sequence but not from a dedicated thread. For backwards compatibility set
+ /// |handle_request| to false and return false and the ProcessRequest method
+ /// will be called.
+ ///
+ /*--cef()--*/
+ virtual bool Open(CefRefPtr<CefRequest> request,
+ bool& handle_request,
+ CefRefPtr<CefCallback> callback) {
+ handle_request = false;
+ return false;
+ }
+
+ ///
+ /// Begin processing the request. To handle the request return true and call
+ /// CefCallback::Continue() once the response header information is available
+ /// (CefCallback::Continue() can also be called from inside this method if
+ /// header information is available immediately). To cancel the request return
+ /// false.
+ ///
+ /// WARNING: This method is deprecated. Use Open instead.
+ ///
+ /*--cef()--*/
+ virtual bool ProcessRequest(CefRefPtr<CefRequest> request,
+ CefRefPtr<CefCallback> callback) {
+ return false;
+ }
+
+ ///
+ /// Retrieve response header information. If the response length is not known
+ /// set |response_length| to -1 and ReadResponse() will be called until it
+ /// returns false. If the response length is known set |response_length|
+ /// to a positive value and ReadResponse() will be called until it returns
+ /// false or the specified number of bytes have been read. Use the |response|
+ /// object to set the mime type, http status code and other optional header
+ /// values. To redirect the request to a new URL set |redirectUrl| to the new
+ /// URL. |redirectUrl| can be either a relative or fully qualified URL.
+ /// It is also possible to set |response| to a redirect http status code
+ /// and pass the new URL via a Location header. Likewise with |redirectUrl| it
+ /// is valid to set a relative or fully qualified URL as the Location header
+ /// value. If an error occured while setting up the request you can call
+ /// SetError() on |response| to indicate the error condition.
+ ///
+ /*--cef()--*/
+ virtual void GetResponseHeaders(CefRefPtr<CefResponse> response,
+ int64& response_length,
+ CefString& redirectUrl) = 0;
+
+ ///
+ /// Skip response data when requested by a Range header. Skip over and discard
+ /// |bytes_to_skip| bytes of response data. If data is available immediately
+ /// set |bytes_skipped| to the number of bytes skipped and return true. To
+ /// read the data at a later time set |bytes_skipped| to 0, return true and
+ /// execute |callback| when the data is available. To indicate failure set
+ /// |bytes_skipped| to < 0 (e.g. -2 for ERR_FAILED) and return false. This
+ /// method will be called in sequence but not from a dedicated thread.
+ ///
+ /*--cef()--*/
+ virtual bool Skip(int64 bytes_to_skip,
+ int64& bytes_skipped,
+ CefRefPtr<CefResourceSkipCallback> callback) {
+ bytes_skipped = -2;
+ return false;
+ }
+
+ ///
+ /// Read response data. If data is available immediately copy up to
+ /// |bytes_to_read| bytes into |data_out|, set |bytes_read| to the number of
+ /// bytes copied, and return true. To read the data at a later time keep a
+ /// pointer to |data_out|, set |bytes_read| to 0, return true and execute
+ /// |callback| when the data is available (|data_out| will remain valid until
+ /// the callback is executed). To indicate response completion set
+ /// |bytes_read| to 0 and return false. To indicate failure set |bytes_read|
+ /// to < 0 (e.g. -2 for ERR_FAILED) and return false. This method will be
+ /// called in sequence but not from a dedicated thread. For backwards
+ /// compatibility set |bytes_read| to -1 and return false and the ReadResponse
+ /// method will be called.
+ ///
+ /*--cef()--*/
+ virtual bool Read(void* data_out,
+ int bytes_to_read,
+ int& bytes_read,
+ CefRefPtr<CefResourceReadCallback> callback) {
+ bytes_read = -1;
+ return false;
+ }
+
+ ///
+ /// Read response data. If data is available immediately copy up to
+ /// |bytes_to_read| bytes into |data_out|, set |bytes_read| to the number of
+ /// bytes copied, and return true. To read the data at a later time set
+ /// |bytes_read| to 0, return true and call CefCallback::Continue() when the
+ /// data is available. To indicate response completion return false.
+ ///
+ /// WARNING: This method is deprecated. Use Skip and Read instead.
+ ///
+ /*--cef()--*/
+ virtual bool ReadResponse(void* data_out,
+ int bytes_to_read,
+ int& bytes_read,
+ CefRefPtr<CefCallback> callback) {
+ bytes_read = -2;
+ return false;
+ }
+
+ ///
+ /// Request processing has been canceled.
+ ///
+ /*--cef()--*/
+ virtual void Cancel() = 0;
+};
+
+#endif // CEF_INCLUDE_CEF_RESOURCE_HANDLER_H_
diff --git a/include/cef_resource_request_handler.h b/include/cef_resource_request_handler.h
new file mode 100644
index 00000000..01d66781
--- /dev/null
+++ b/include/cef_resource_request_handler.h
@@ -0,0 +1,250 @@
+// Copyright (c) 2011 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_RESOURCE_REQUEST_HANDLER_H_
+#define CEF_INCLUDE_CEF_RESOURCE_REQUEST_HANDLER_H_
+#pragma once
+
+#include "include/cef_base.h"
+#include "include/cef_browser.h"
+#include "include/cef_callback.h"
+#include "include/cef_frame.h"
+#include "include/cef_request.h"
+#include "include/cef_resource_handler.h"
+#include "include/cef_response.h"
+#include "include/cef_response_filter.h"
+
+class CefCookieAccessFilter;
+
+///
+/// Implement this interface to handle events related to browser requests. The
+/// methods of this class will be called on the IO thread unless otherwise
+/// indicated.
+///
+/*--cef(source=client,no_debugct_check)--*/
+class CefResourceRequestHandler : public virtual CefBaseRefCounted {
+ public:
+ typedef cef_return_value_t ReturnValue;
+ typedef cef_urlrequest_status_t URLRequestStatus;
+
+ ///
+ /// Called on the IO thread before a resource request is loaded. The |browser|
+ /// and |frame| values represent the source of the request, and may be NULL
+ /// for requests originating from service workers or CefURLRequest. To
+ /// optionally filter cookies for the request return a CefCookieAccessFilter
+ /// object. The |request| object cannot not be modified in this callback.
+ ///
+ /*--cef(optional_param=browser,optional_param=frame)--*/
+ virtual CefRefPtr<CefCookieAccessFilter> GetCookieAccessFilter(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request) {
+ return nullptr;
+ }
+
+ ///
+ /// Called on the IO thread before a resource request is loaded. The |browser|
+ /// and |frame| values represent the source of the request, and may be NULL
+ /// for requests originating from service workers or CefURLRequest. To
+ /// redirect or change the resource load optionally modify |request|.
+ /// Modification of the request URL will be treated as a redirect. Return
+ /// RV_CONTINUE to continue the request immediately. Return RV_CONTINUE_ASYNC
+ /// and call CefCallback methods at a later time to continue or cancel the
+ /// request asynchronously. Return RV_CANCEL to cancel the request
+ /// immediately.
+ ///
+ /*--cef(optional_param=browser,optional_param=frame,
+ default_retval=RV_CONTINUE)--*/
+ virtual ReturnValue OnBeforeResourceLoad(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefCallback> callback) {
+ return RV_CONTINUE;
+ }
+
+ ///
+ /// Called on the IO thread before a resource is loaded. The |browser| and
+ /// |frame| values represent the source of the request, and may be NULL for
+ /// requests originating from service workers or CefURLRequest. To allow the
+ /// resource to load using the default network loader return NULL. To specify
+ /// a handler for the resource return a CefResourceHandler object. The
+ /// |request| object cannot not be modified in this callback.
+ ///
+ /*--cef(optional_param=browser,optional_param=frame)--*/
+ virtual CefRefPtr<CefResourceHandler> GetResourceHandler(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request) {
+ return nullptr;
+ }
+
+ ///
+ /// Called on the IO thread when a resource load is redirected. The |browser|
+ /// and |frame| values represent the source of the request, and may be NULL
+ /// for requests originating from service workers or CefURLRequest. The
+ /// |request| parameter will contain the old URL and other request-related
+ /// information. The |response| parameter will contain the response that
+ /// resulted in the redirect. The |new_url| parameter will contain the new URL
+ /// and can be changed if desired. The |request| and |response| objects cannot
+ /// be modified in this callback.
+ ///
+ /*--cef(optional_param=browser,optional_param=frame)--*/
+ virtual void OnResourceRedirect(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response,
+ CefString& new_url) {}
+
+ ///
+ /// Called on the IO thread when a resource response is received. The
+ /// |browser| and |frame| values represent the source of the request, and may
+ /// be NULL for requests originating from service workers or CefURLRequest. To
+ /// allow the resource load to proceed without modification return false. To
+ /// redirect or retry the resource load optionally modify |request| and return
+ /// true. Modification of the request URL will be treated as a redirect.
+ /// Requests handled using the default network loader cannot be redirected in
+ /// this callback. The |response| object cannot be modified in this callback.
+ ///
+ /// WARNING: Redirecting using this method is deprecated. Use
+ /// OnBeforeResourceLoad or GetResourceHandler to perform redirects.
+ ///
+ /*--cef(optional_param=browser,optional_param=frame)--*/
+ virtual bool OnResourceResponse(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response) {
+ return false;
+ }
+
+ ///
+ /// Called on the IO thread to optionally filter resource response content.
+ /// The |browser| and |frame| values represent the source of the request, and
+ /// may be NULL for requests originating from service workers or
+ /// CefURLRequest. |request| and |response| represent the request and response
+ /// respectively and cannot be modified in this callback.
+ ///
+ /*--cef(optional_param=browser,optional_param=frame)--*/
+ virtual CefRefPtr<CefResponseFilter> GetResourceResponseFilter(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response) {
+ return nullptr;
+ }
+
+ ///
+ /// Called on the IO thread when a resource load has completed. The |browser|
+ /// and |frame| values represent the source of the request, and may be NULL
+ /// for requests originating from service workers or CefURLRequest. |request|
+ /// and |response| represent the request and response respectively and cannot
+ /// be modified in this callback. |status| indicates the load completion
+ /// status. |received_content_length| is the number of response bytes actually
+ /// read. This method will be called for all requests, including requests that
+ /// are aborted due to CEF shutdown or destruction of the associated browser.
+ /// In cases where the associated browser is destroyed this callback may
+ /// arrive after the CefLifeSpanHandler::OnBeforeClose callback for that
+ /// browser. The CefFrame::IsValid method can be used to test for this
+ /// situation, and care should be taken not to call |browser| or |frame|
+ /// methods that modify state (like LoadURL, SendProcessMessage, etc.) if the
+ /// frame is invalid.
+ ///
+ /*--cef(optional_param=browser,optional_param=frame)--*/
+ virtual void OnResourceLoadComplete(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response,
+ URLRequestStatus status,
+ int64 received_content_length) {}
+
+ ///
+ /// Called on the IO thread to handle requests for URLs with an unknown
+ /// protocol component. The |browser| and |frame| values represent the source
+ /// of the request, and may be NULL for requests originating from service
+ /// workers or CefURLRequest. |request| cannot be modified in this callback.
+ /// Set |allow_os_execution| to true to attempt execution via the registered
+ /// OS protocol handler, if any. SECURITY WARNING: YOU SHOULD USE THIS METHOD
+ /// TO ENFORCE RESTRICTIONS BASED ON SCHEME, HOST OR OTHER URL ANALYSIS BEFORE
+ /// ALLOWING OS EXECUTION.
+ ///
+ /*--cef(optional_param=browser,optional_param=frame)--*/
+ virtual void OnProtocolExecution(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ bool& allow_os_execution) {}
+};
+
+///
+/// Implement this interface to filter cookies that may be sent or received from
+/// resource requests. The methods of this class will be called on the IO thread
+/// unless otherwise indicated.
+///
+/*--cef(source=client,no_debugct_check)--*/
+class CefCookieAccessFilter : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Called on the IO thread before a resource request is sent. The |browser|
+ /// and |frame| values represent the source of the request, and may be NULL
+ /// for requests originating from service workers or CefURLRequest. |request|
+ /// cannot be modified in this callback. Return true if the specified cookie
+ /// can be sent with the request or false otherwise.
+ ///
+ /*--cef(optional_param=browser,optional_param=frame)--*/
+ virtual bool CanSendCookie(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ const CefCookie& cookie) {
+ return true;
+ }
+
+ ///
+ /// Called on the IO thread after a resource response is received. The
+ /// |browser| and |frame| values represent the source of the request, and may
+ /// be NULL for requests originating from service workers or CefURLRequest.
+ /// |request| cannot be modified in this callback. Return true if the
+ /// specified cookie returned with the response can be saved or false
+ /// otherwise.
+ ///
+ /*--cef(optional_param=browser,optional_param=frame)--*/
+ virtual bool CanSaveCookie(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response,
+ const CefCookie& cookie) {
+ return true;
+ }
+};
+
+#endif // CEF_INCLUDE_CEF_RESOURCE_REQUEST_HANDLER_H_
diff --git a/include/cef_response.h b/include/cef_response.h
new file mode 100644
index 00000000..571998a4
--- /dev/null
+++ b/include/cef_response.h
@@ -0,0 +1,167 @@
+// Copyright (c) 2012 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_RESPONSE_H_
+#define CEF_INCLUDE_CEF_RESPONSE_H_
+#pragma once
+
+#include <map>
+#include "include/cef_base.h"
+
+///
+/// Class used to represent a web response. The methods of this class may be
+/// called on any thread.
+///
+/*--cef(source=library,no_debugct_check)--*/
+class CefResponse : public virtual CefBaseRefCounted {
+ public:
+ typedef std::multimap<CefString, CefString> HeaderMap;
+
+ ///
+ /// Create a new CefResponse object.
+ ///
+ /*--cef()--*/
+ static CefRefPtr<CefResponse> Create();
+
+ ///
+ /// Returns true if this object is read-only.
+ ///
+ /*--cef()--*/
+ virtual bool IsReadOnly() = 0;
+
+ ///
+ /// Get the response error code. Returns ERR_NONE if there was no error.
+ ///
+ /*--cef(default_retval=ERR_NONE)--*/
+ virtual cef_errorcode_t GetError() = 0;
+
+ ///
+ /// Set the response error code. This can be used by custom scheme handlers
+ /// to return errors during initial request processing.
+ ///
+ /*--cef()--*/
+ virtual void SetError(cef_errorcode_t error) = 0;
+
+ ///
+ /// Get the response status code.
+ ///
+ /*--cef()--*/
+ virtual int GetStatus() = 0;
+
+ ///
+ /// Set the response status code.
+ ///
+ /*--cef()--*/
+ virtual void SetStatus(int status) = 0;
+
+ ///
+ /// Get the response status text.
+ ///
+ /*--cef()--*/
+ virtual CefString GetStatusText() = 0;
+
+ ///
+ /// Set the response status text.
+ ///
+ /*--cef(optional_param=statusText)--*/
+ virtual void SetStatusText(const CefString& statusText) = 0;
+
+ ///
+ /// Get the response mime type.
+ ///
+ /*--cef()--*/
+ virtual CefString GetMimeType() = 0;
+
+ ///
+ /// Set the response mime type.
+ ///
+ /*--cef(optional_param=mimeType)--*/
+ virtual void SetMimeType(const CefString& mimeType) = 0;
+
+ ///
+ /// Get the response charset.
+ ///
+ /*--cef()--*/
+ virtual CefString GetCharset() = 0;
+
+ ///
+ /// Set the response charset.
+ ///
+ /*--cef(optional_param=charset)--*/
+ virtual void SetCharset(const CefString& charset) = 0;
+
+ ///
+ /// Get the value for the specified response header field.
+ ///
+ /*--cef()--*/
+ virtual CefString GetHeaderByName(const CefString& name) = 0;
+
+ ///
+ /// Set the header |name| to |value|. If |overwrite| is true any existing
+ /// values will be replaced with the new value. If |overwrite| is false any
+ /// existing values will not be overwritten.
+ ///
+ /*--cef(optional_param=value)--*/
+ virtual void SetHeaderByName(const CefString& name,
+ const CefString& value,
+ bool overwrite) = 0;
+
+ ///
+ /// Get all response header fields.
+ ///
+ /*--cef()--*/
+ virtual void GetHeaderMap(HeaderMap& headerMap) = 0;
+
+ ///
+ /// Set all response header fields.
+ ///
+ /*--cef()--*/
+ virtual void SetHeaderMap(const HeaderMap& headerMap) = 0;
+
+ ///
+ /// Get the resolved URL after redirects or changed as a result of HSTS.
+ ///
+ /*--cef()--*/
+ virtual CefString GetURL() = 0;
+
+ ///
+ /// Set the resolved URL after redirects or changed as a result of HSTS.
+ ///
+ /*--cef(optional_param=url)--*/
+ virtual void SetURL(const CefString& url) = 0;
+};
+
+#endif // CEF_INCLUDE_CEF_RESPONSE_H_
diff --git a/include/cef_response_filter.h b/include/cef_response_filter.h
new file mode 100644
index 00000000..37d70649
--- /dev/null
+++ b/include/cef_response_filter.h
@@ -0,0 +1,99 @@
+// Copyright (c) 2015 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_RESPONSE_FILTER_H_
+#define CEF_INCLUDE_CEF_RESPONSE_FILTER_H_
+#pragma once
+
+#include "include/cef_base.h"
+
+///
+/// Implement this interface to filter resource response content. The methods of
+/// this class will be called on the browser process IO thread.
+///
+/*--cef(source=client)--*/
+class CefResponseFilter : public virtual CefBaseRefCounted {
+ public:
+ typedef cef_response_filter_status_t FilterStatus;
+
+ ///
+ /// Initialize the response filter. Will only be called a single time. The
+ /// filter will not be installed if this method returns false.
+ ///
+ /*--cef()--*/
+ virtual bool InitFilter() = 0;
+
+ ///
+ /// Called to filter a chunk of data. Expected usage is as follows:
+ ///
+ /// 1. Read input data from |data_in| and set |data_in_read| to the number of
+ /// bytes that were read up to a maximum of |data_in_size|. |data_in| will
+ /// be NULL if |data_in_size| is zero.
+ /// 2. Write filtered output data to |data_out| and set |data_out_written| to
+ /// the number of bytes that were written up to a maximum of
+ /// |data_out_size|. If no output data was written then all data must be
+ /// read from |data_in| (user must set |data_in_read| = |data_in_size|).
+ /// 3. Return RESPONSE_FILTER_DONE if all output data was written or
+ /// RESPONSE_FILTER_NEED_MORE_DATA if output data is still pending.
+ ///
+ /// This method will be called repeatedly until the input buffer has been
+ /// fully read (user sets |data_in_read| = |data_in_size|) and there is no
+ /// more input data to filter (the resource response is complete). This method
+ /// may then be called an additional time with an empty input buffer if the
+ /// user filled the output buffer (set |data_out_written| = |data_out_size|)
+ /// and returned RESPONSE_FILTER_NEED_MORE_DATA to indicate that output data
+ /// is still pending.
+ ///
+ /// Calls to this method will stop when one of the following conditions is
+ /// met:
+ ///
+ /// 1. There is no more input data to filter (the resource response is
+ /// complete) and the user sets |data_out_written| = 0 or returns
+ /// RESPONSE_FILTER_DONE to indicate that all data has been written, or;
+ /// 2. The user returns RESPONSE_FILTER_ERROR to indicate an error.
+ ///
+ /// Do not keep a reference to the buffers passed to this method.
+ ///
+ /*--cef(optional_param=data_in,default_retval=RESPONSE_FILTER_ERROR)--*/
+ virtual FilterStatus Filter(void* data_in,
+ size_t data_in_size,
+ size_t& data_in_read,
+ void* data_out,
+ size_t data_out_size,
+ size_t& data_out_written) = 0;
+};
+
+#endif // CEF_INCLUDE_CEF_RESPONSE_FILTER_H_
diff --git a/include/cef_sandbox_mac.h b/include/cef_sandbox_mac.h
new file mode 100644
index 00000000..cec624ee
--- /dev/null
+++ b/include/cef_sandbox_mac.h
@@ -0,0 +1,93 @@
+// Copyright (c) 2018 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CEF_INCLUDE_CEF_SANDBOX_MAC_H_
+#define CEF_INCLUDE_CEF_SANDBOX_MAC_H_
+#pragma once
+
+#include "include/base/cef_build.h"
+#include "include/internal/cef_export.h"
+
+#if defined(OS_MAC)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// \file
+/// The sandbox is used to restrict sub-processes (renderer, GPU, etc) from
+/// directly accessing system resources. This helps to protect the user from
+/// untrusted and potentially malicious Web content. See
+/// http://www.chromium.org/developers/design-documents/sandbox for complete
+/// details.
+///
+/// To enable the sandbox on macOS the following requirements must be met:
+/// 1. Link the helper process executable with the cef_sandbox static library.
+/// 2. Call the cef_sandbox_initialize() function at the beginning of the
+/// helper executable main() function and before loading the CEF framework
+/// library. See include/wrapper/cef_library_loader.h for example usage.
+///
+
+///
+/// Initialize the sandbox for this process. Returns the sandbox context
+/// handle on success or NULL on failure. The returned handle should be
+/// passed to cef_sandbox_destroy() immediately before process termination.
+///
+CEF_EXPORT void* cef_sandbox_initialize(int argc, char** argv);
+
+///
+/// Destroy the specified sandbox context handle.
+///
+CEF_EXPORT void cef_sandbox_destroy(void* sandbox_context);
+
+#ifdef __cplusplus
+}
+
+///
+/// Scoped helper for managing the life span of a sandbox context handle.
+///
+class CEF_EXPORT CefScopedSandboxContext {
+ public:
+ CefScopedSandboxContext();
+ ~CefScopedSandboxContext();
+
+ ///
+ /// Load the sandbox for this process. Returns true on success.
+ ///
+ bool Initialize(int argc, char** argv);
+
+ private:
+ void* sandbox_context_;
+};
+#endif // __cplusplus
+
+#endif // defined(OS_MAC)
+
+#endif // CEF_INCLUDE_CEF_SANDBOX_MAC_H_
diff --git a/include/cef_sandbox_win.h b/include/cef_sandbox_win.h
new file mode 100644
index 00000000..a98d64c6
--- /dev/null
+++ b/include/cef_sandbox_win.h
@@ -0,0 +1,91 @@
+// Copyright (c) 2013 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CEF_INCLUDE_CEF_SANDBOX_WIN_H_
+#define CEF_INCLUDE_CEF_SANDBOX_WIN_H_
+#pragma once
+
+#include "include/base/cef_build.h"
+
+#if defined(OS_WIN)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// \file
+/// The sandbox is used to restrict sub-processes (renderer, GPU, etc) from
+/// directly accessing system resources. This helps to protect the user from
+/// untrusted and potentially malicious Web content. See
+/// http://www.chromium.org/developers/design-documents/sandbox for complete
+/// details.
+///
+/// To enable the sandbox on Windows the following requirements must be met:
+/// 1. Use the same executable for the browser process and all sub-processes.
+/// 2. Link the executable with the cef_sandbox static library.
+/// 3. Call the cef_sandbox_info_create() function from within the executable
+/// (not from a separate DLL) and pass the resulting pointer into both the
+/// CefExecuteProcess() and CefInitialize() functions via the
+/// |windows_sandbox_info| parameter.
+///
+
+///
+/// Create the sandbox information object for this process. It is safe to create
+/// multiple of this object and to destroy the object immediately after passing
+/// into the CefExecuteProcess() and/or CefInitialize() functions.
+///
+void* cef_sandbox_info_create(void);
+
+///
+/// Destroy the specified sandbox information object.
+///
+void cef_sandbox_info_destroy(void* sandbox_info);
+
+#ifdef __cplusplus
+}
+
+///
+/// Manages the life span of a sandbox information object.
+///
+class CefScopedSandboxInfo {
+ public:
+ CefScopedSandboxInfo() { sandbox_info_ = cef_sandbox_info_create(); }
+ ~CefScopedSandboxInfo() { cef_sandbox_info_destroy(sandbox_info_); }
+
+ void* sandbox_info() const { return sandbox_info_; }
+
+ private:
+ void* sandbox_info_;
+};
+#endif // __cplusplus
+
+#endif // defined(OS_WIN)
+
+#endif // CEF_INCLUDE_CEF_SANDBOX_WIN_H_
diff --git a/include/cef_scheme.h b/include/cef_scheme.h
new file mode 100644
index 00000000..97f4c155
--- /dev/null
+++ b/include/cef_scheme.h
@@ -0,0 +1,122 @@
+// Copyright (c) 2012 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_SCHEME_H_
+#define CEF_INCLUDE_CEF_SCHEME_H_
+#pragma once
+
+#include "include/cef_base.h"
+#include "include/cef_browser.h"
+#include "include/cef_frame.h"
+#include "include/cef_request.h"
+#include "include/cef_resource_handler.h"
+#include "include/cef_response.h"
+
+class CefSchemeHandlerFactory;
+
+///
+/// Register a scheme handler factory with the global request context. An empty
+/// |domain_name| value for a standard scheme will cause the factory to match
+/// all domain names. The |domain_name| value will be ignored for non-standard
+/// schemes. If |scheme_name| is a built-in scheme and no handler is returned by
+/// |factory| then the built-in scheme handler factory will be called. If
+/// |scheme_name| is a custom scheme then you must also implement the
+/// CefApp::OnRegisterCustomSchemes() method in all processes. This function may
+/// be called multiple times to change or remove the factory that matches the
+/// specified |scheme_name| and optional |domain_name|. Returns false if an
+/// error occurs. This function may be called on any thread in the browser
+/// process. Using this function is equivalent to calling
+/// CefRequestContext::GetGlobalContext()->RegisterSchemeHandlerFactory().
+///
+/*--cef(optional_param=domain_name,optional_param=factory)--*/
+bool CefRegisterSchemeHandlerFactory(
+ const CefString& scheme_name,
+ const CefString& domain_name,
+ CefRefPtr<CefSchemeHandlerFactory> factory);
+
+///
+/// Clear all scheme handler factories registered with the global request
+/// context. Returns false on error. This function may be called on any thread
+/// in the browser process. Using this function is equivalent to calling
+/// CefRequestContext::GetGlobalContext()->ClearSchemeHandlerFactories().
+///
+/*--cef()--*/
+bool CefClearSchemeHandlerFactories();
+
+///
+/// Class that manages custom scheme registrations.
+///
+/*--cef(source=library)--*/
+class CefSchemeRegistrar : public CefBaseScoped {
+ public:
+ ///
+ /// Register a custom scheme. This method should not be called for the
+ /// built-in HTTP, HTTPS, FILE, FTP, ABOUT and DATA schemes.
+ ///
+ /// See cef_scheme_options_t for possible values for |options|.
+ ///
+ /// This function may be called on any thread. It should only be called once
+ /// per unique |scheme_name| value. If |scheme_name| is already registered or
+ /// if an error occurs this method will return false.
+ ///
+ /*--cef()--*/
+ virtual bool AddCustomScheme(const CefString& scheme_name, int options) = 0;
+};
+
+///
+/// Class that creates CefResourceHandler instances for handling scheme
+/// requests. The methods of this class will always be called on the IO thread.
+///
+/*--cef(source=client,no_debugct_check)--*/
+class CefSchemeHandlerFactory : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Return a new resource handler instance to handle the request or an empty
+ /// reference to allow default handling of the request. |browser| and |frame|
+ /// will be the browser window and frame respectively that originated the
+ /// request or NULL if the request did not originate from a browser window
+ /// (for example, if the request came from CefURLRequest). The |request|
+ /// object passed to this method cannot be modified.
+ ///
+ /*--cef(optional_param=browser,optional_param=frame)--*/
+ virtual CefRefPtr<CefResourceHandler> Create(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const CefString& scheme_name,
+ CefRefPtr<CefRequest> request) = 0;
+};
+
+#endif // CEF_INCLUDE_CEF_SCHEME_H_
diff --git a/include/cef_server.h b/include/cef_server.h
new file mode 100644
index 00000000..7a3b6e6d
--- /dev/null
+++ b/include/cef_server.h
@@ -0,0 +1,316 @@
+// Copyright (c) 2017 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_SERVER_H_
+#define CEF_INCLUDE_CEF_SERVER_H_
+#pragma once
+
+#include <map>
+#include "include/cef_base.h"
+#include "include/cef_callback.h"
+#include "include/cef_request.h"
+#include "include/cef_task.h"
+
+class CefServerHandler;
+
+///
+/// Class representing a server that supports HTTP and WebSocket requests.
+/// Server capacity is limited and is intended to handle only a small number of
+/// simultaneous connections (e.g. for communicating between applications on
+/// localhost). The methods of this class are safe to call from any thread in
+/// the brower process unless otherwise indicated.
+///
+/*--cef(source=library)--*/
+class CefServer : public CefBaseRefCounted {
+ public:
+ typedef std::multimap<CefString, CefString> HeaderMap;
+
+ ///
+ /// Create a new server that binds to |address| and |port|. |address| must be
+ /// a valid IPv4 or IPv6 address (e.g. 127.0.0.1 or ::1) and |port| must be a
+ /// port number outside of the reserved range (e.g. between 1025 and 65535 on
+ /// most platforms). |backlog| is the maximum number of pending connections.
+ /// A new thread will be created for each CreateServer call (the "dedicated
+ /// server thread"). It is therefore recommended to use a different
+ /// CefServerHandler instance for each CreateServer call to avoid thread
+ /// safety issues in the CefServerHandler implementation. The
+ /// CefServerHandler::OnServerCreated method will be called on the dedicated
+ /// server thread to report success or failure. See
+ /// CefServerHandler::OnServerCreated documentation for a description of
+ /// server lifespan.
+ ///
+ /*--cef()--*/
+ static void CreateServer(const CefString& address,
+ uint16 port,
+ int backlog,
+ CefRefPtr<CefServerHandler> handler);
+
+ ///
+ /// Returns the task runner for the dedicated server thread.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefTaskRunner> GetTaskRunner() = 0;
+
+ ///
+ /// Stop the server and shut down the dedicated server thread. See
+ /// CefServerHandler::OnServerCreated documentation for a description of
+ /// server lifespan.
+ ///
+ /*--cef()--*/
+ virtual void Shutdown() = 0;
+
+ ///
+ /// Returns true if the server is currently running and accepting incoming
+ /// connections. See CefServerHandler::OnServerCreated documentation for a
+ /// description of server lifespan. This method must be called on the
+ /// dedicated server thread.
+ ///
+ /*--cef()--*/
+ virtual bool IsRunning() = 0;
+
+ ///
+ /// Returns the server address including the port number.
+ ///
+ /*--cef()--*/
+ virtual CefString GetAddress() = 0;
+
+ ///
+ /// Returns true if the server currently has a connection. This method must be
+ /// called on the dedicated server thread.
+ ///
+ /*--cef()--*/
+ virtual bool HasConnection() = 0;
+
+ ///
+ /// Returns true if |connection_id| represents a valid connection. This method
+ /// must be called on the dedicated server thread.
+ ///
+ /*--cef()--*/
+ virtual bool IsValidConnection(int connection_id) = 0;
+
+ ///
+ /// Send an HTTP 200 "OK" response to the connection identified by
+ /// |connection_id|. |content_type| is the response content type (e.g.
+ /// "text/html"), |data| is the response content, and |data_size| is the size
+ /// of |data| in bytes. The contents of |data| will be copied. The connection
+ /// will be closed automatically after the response is sent.
+ ///
+ /*--cef()--*/
+ virtual void SendHttp200Response(int connection_id,
+ const CefString& content_type,
+ const void* data,
+ size_t data_size) = 0;
+
+ ///
+ /// Send an HTTP 404 "Not Found" response to the connection identified by
+ /// |connection_id|. The connection will be closed automatically after the
+ /// response is sent.
+ ///
+ /*--cef()--*/
+ virtual void SendHttp404Response(int connection_id) = 0;
+
+ ///
+ /// Send an HTTP 500 "Internal Server Error" response to the connection
+ /// identified by |connection_id|. |error_message| is the associated error
+ /// message. The connection will be closed automatically after the response is
+ /// sent.
+ ///
+ /*--cef()--*/
+ virtual void SendHttp500Response(int connection_id,
+ const CefString& error_message) = 0;
+
+ ///
+ /// Send a custom HTTP response to the connection identified by
+ /// |connection_id|. |response_code| is the HTTP response code sent in the
+ /// status line (e.g. 200), |content_type| is the response content type sent
+ /// as the "Content-Type" header (e.g. "text/html"), |content_length| is the
+ /// expected content length, and |extra_headers| is the map of extra response
+ /// headers. If |content_length| is >= 0 then the "Content-Length" header will
+ /// be sent. If |content_length| is 0 then no content is expected and the
+ /// connection will be closed automatically after the response is sent. If
+ /// |content_length| is < 0 then no "Content-Length" header will be sent and
+ /// the client will continue reading until the connection is closed. Use the
+ /// SendRawData method to send the content, if applicable, and call
+ /// CloseConnection after all content has been sent.
+ ///
+ /*--cef(optional_param=extra_headers)--*/
+ virtual void SendHttpResponse(int connection_id,
+ int response_code,
+ const CefString& content_type,
+ int64 content_length,
+ const HeaderMap& extra_headers) = 0;
+
+ ///
+ /// Send raw data directly to the connection identified by |connection_id|.
+ /// |data| is the raw data and |data_size| is the size of |data| in bytes.
+ /// The contents of |data| will be copied. No validation of |data| is
+ /// performed internally so the client should be careful to send the amount
+ /// indicated by the "Content-Length" header, if specified. See
+ /// SendHttpResponse documentation for intended usage.
+ ///
+ /*--cef()--*/
+ virtual void SendRawData(int connection_id,
+ const void* data,
+ size_t data_size) = 0;
+
+ ///
+ /// Close the connection identified by |connection_id|. See SendHttpResponse
+ /// documentation for intended usage.
+ ///
+ /*--cef()--*/
+ virtual void CloseConnection(int connection_id) = 0;
+
+ ///
+ /// Send a WebSocket message to the connection identified by |connection_id|.
+ /// |data| is the response content and |data_size| is the size of |data| in
+ /// bytes. The contents of |data| will be copied. See
+ /// CefServerHandler::OnWebSocketRequest documentation for intended usage.
+ ///
+ /*--cef()--*/
+ virtual void SendWebSocketMessage(int connection_id,
+ const void* data,
+ size_t data_size) = 0;
+};
+
+///
+/// Implement this interface to handle HTTP server requests. A new thread will
+/// be created for each CefServer::CreateServer call (the "dedicated server
+/// thread"), and the methods of this class will be called on that thread. It is
+/// therefore recommended to use a different CefServerHandler instance for each
+/// CefServer::CreateServer call to avoid thread safety issues in the
+/// CefServerHandler implementation.
+///
+/*--cef(source=client)--*/
+class CefServerHandler : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Called when |server| is created. If the server was started successfully
+ /// then CefServer::IsRunning will return true. The server will continue
+ /// running until CefServer::Shutdown is called, after which time
+ /// OnServerDestroyed will be called. If the server failed to start then
+ /// OnServerDestroyed will be called immediately after this method returns.
+ ///
+ /*--cef()--*/
+ virtual void OnServerCreated(CefRefPtr<CefServer> server) = 0;
+
+ ///
+ /// Called when |server| is destroyed. The server thread will be stopped after
+ /// this method returns. The client should release any references to |server|
+ /// when this method is called. See OnServerCreated documentation for a
+ /// description of server lifespan.
+ ///
+ /*--cef()--*/
+ virtual void OnServerDestroyed(CefRefPtr<CefServer> server) = 0;
+
+ ///
+ /// Called when a client connects to |server|. |connection_id| uniquely
+ /// identifies the connection. Each call to this method will have a matching
+ /// call to OnClientDisconnected.
+ ///
+ /*--cef()--*/
+ virtual void OnClientConnected(CefRefPtr<CefServer> server,
+ int connection_id) = 0;
+
+ ///
+ /// Called when a client disconnects from |server|. |connection_id| uniquely
+ /// identifies the connection. The client should release any data associated
+ /// with |connection_id| when this method is called and |connection_id| should
+ /// no longer be passed to CefServer methods. Disconnects can originate from
+ /// either the client or the server. For example, the server will disconnect
+ /// automatically after a CefServer::SendHttpXXXResponse method is called.
+ ///
+ /*--cef()--*/
+ virtual void OnClientDisconnected(CefRefPtr<CefServer> server,
+ int connection_id) = 0;
+
+ ///
+ /// Called when |server| receives an HTTP request. |connection_id| uniquely
+ /// identifies the connection, |client_address| is the requesting IPv4 or IPv6
+ /// client address including port number, and |request| contains the request
+ /// contents (URL, method, headers and optional POST data). Call CefServer
+ /// methods either synchronously or asynchronusly to send a response.
+ ///
+ /*--cef()--*/
+ virtual void OnHttpRequest(CefRefPtr<CefServer> server,
+ int connection_id,
+ const CefString& client_address,
+ CefRefPtr<CefRequest> request) = 0;
+
+ ///
+ /// Called when |server| receives a WebSocket request. |connection_id|
+ /// uniquely identifies the connection, |client_address| is the requesting
+ /// IPv4 or IPv6 client address including port number, and |request| contains
+ /// the request contents (URL, method, headers and optional POST data).
+ /// Execute |callback| either synchronously or asynchronously to accept or
+ /// decline the WebSocket connection. If the request is accepted then
+ /// OnWebSocketConnected will be called after the WebSocket has connected and
+ /// incoming messages will be delivered to the OnWebSocketMessage callback. If
+ /// the request is declined then the client will be disconnected and
+ /// OnClientDisconnected will be called. Call the
+ /// CefServer::SendWebSocketMessage method after receiving the
+ /// OnWebSocketConnected callback to respond with WebSocket messages.
+ ///
+ /*--cef()--*/
+ virtual void OnWebSocketRequest(CefRefPtr<CefServer> server,
+ int connection_id,
+ const CefString& client_address,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefCallback> callback) = 0;
+
+ ///
+ /// Called after the client has accepted the WebSocket connection for |server|
+ /// and |connection_id| via the OnWebSocketRequest callback. See
+ /// OnWebSocketRequest documentation for intended usage.
+ ///
+ /*--cef()--*/
+ virtual void OnWebSocketConnected(CefRefPtr<CefServer> server,
+ int connection_id) = 0;
+
+ ///
+ /// Called when |server| receives an WebSocket message. |connection_id|
+ /// uniquely identifies the connection, |data| is the message content and
+ /// |data_size| is the size of |data| in bytes. Do not keep a reference to
+ /// |data| outside of this method. See OnWebSocketRequest documentation for
+ /// intended usage.
+ ///
+ /*--cef()--*/
+ virtual void OnWebSocketMessage(CefRefPtr<CefServer> server,
+ int connection_id,
+ const void* data,
+ size_t data_size) = 0;
+};
+
+#endif // CEF_INCLUDE_CEF_SERVER_H_
diff --git a/include/cef_shared_memory_region.h b/include/cef_shared_memory_region.h
new file mode 100644
index 00000000..ba708002
--- /dev/null
+++ b/include/cef_shared_memory_region.h
@@ -0,0 +1,69 @@
+// Copyright (c) 2022 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_SHARED_MEMORY_REGION_H_
+#define CEF_INCLUDE_CEF_SHARED_MEMORY_REGION_H_
+#pragma once
+
+#include "include/cef_base.h"
+
+///
+/// Class that wraps platform-dependent share memory region mapping.
+///
+/*--cef(source=library)--*/
+class CefSharedMemoryRegion : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Returns true if the mapping is valid.
+ ///
+ /*--cef()--*/
+ virtual bool IsValid() = 0;
+
+ ///
+ /// Returns the size of the mapping in bytes. Returns 0 for invalid instances.
+ ///
+ /*--cef()--*/
+ virtual size_t Size() = 0;
+
+ ///
+ /// Returns the pointer to the memory. Returns nullptr for invalid instances.
+ /// The returned pointer is only valid for the life span of this object.
+ ///
+ /*--cef()--*/
+ virtual const void* Memory() = 0;
+};
+
+#endif // CEF_INCLUDE_CEF_SHARED_MEMORY_REGION_H_
diff --git a/include/cef_shared_process_message_builder.h b/include/cef_shared_process_message_builder.h
new file mode 100644
index 00000000..f67e58fd
--- /dev/null
+++ b/include/cef_shared_process_message_builder.h
@@ -0,0 +1,87 @@
+// Copyright (c) 2022 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_SHARED_PROCESS_MESSAGE_BUILDER_H_
+#define CEF_INCLUDE_CEF_SHARED_PROCESS_MESSAGE_BUILDER_H_
+#pragma once
+
+#include "include/cef_process_message.h"
+
+///
+/// Class that builds a CefProcessMessage containing a shared memory region.
+/// This class is not thread-safe but may be used exclusively on a different
+/// thread from the one which constructed it.
+///
+/*--cef(source=library)--*/
+class CefSharedProcessMessageBuilder : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Creates a new CefSharedProcessMessageBuilder with the specified |name| and
+ /// shared memory region of specified |byte_size|.
+ ///
+ /*--cef()--*/
+ static CefRefPtr<CefSharedProcessMessageBuilder> Create(const CefString& name,
+ size_t byte_size);
+ ///
+ /// Returns true if the builder is valid.
+ ///
+ /*--cef()--*/
+ virtual bool IsValid() = 0;
+
+ ///
+ /// Returns the size of the shared memory region in bytes. Returns 0 for
+ /// invalid instances.
+ ///
+ /*--cef()--*/
+ virtual size_t Size() = 0;
+
+ ///
+ /// Returns the pointer to the writable memory. Returns nullptr for invalid
+ /// instances. The returned pointer is only valid for the life span of this
+ /// object.
+ ///
+ /*--cef()--*/
+ virtual void* Memory() = 0;
+
+ ///
+ /// Creates a new CefProcessMessage from the data provided to the builder.
+ /// Returns nullptr for invalid instances. Invalidates the builder instance.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefProcessMessage> Build() = 0;
+};
+
+#endif // CEF_INCLUDE_CEF_SHARED_PROCESS_MESSAGE_BUILDER_H_
diff --git a/include/cef_ssl_info.h b/include/cef_ssl_info.h
new file mode 100644
index 00000000..67b9cdfd
--- /dev/null
+++ b/include/cef_ssl_info.h
@@ -0,0 +1,72 @@
+// Copyright (c) 2015 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_SSL_INFO_H_
+#define CEF_INCLUDE_CEF_SSL_INFO_H_
+#pragma once
+
+#include "include/cef_base.h"
+#include "include/cef_values.h"
+
+#include "include/cef_x509_certificate.h"
+
+///
+/// Class representing SSL information.
+///
+/*--cef(source=library)--*/
+class CefSSLInfo : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Returns a bitmask containing any and all problems verifying the server
+ /// certificate.
+ ///
+ /*--cef(default_retval=CERT_STATUS_NONE)--*/
+ virtual cef_cert_status_t GetCertStatus() = 0;
+
+ ///
+ /// Returns the X.509 certificate.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefX509Certificate> GetX509Certificate() = 0;
+};
+
+///
+/// Returns true if the certificate status represents an error.
+///
+/*--cef()--*/
+bool CefIsCertStatusError(cef_cert_status_t status);
+
+#endif // CEF_INCLUDE_CEF_SSL_INFO_H_
diff --git a/include/cef_ssl_status.h b/include/cef_ssl_status.h
new file mode 100644
index 00000000..fe108dff
--- /dev/null
+++ b/include/cef_ssl_status.h
@@ -0,0 +1,83 @@
+// Copyright (c) 2016 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_SSL_STATUS_H_
+#define CEF_INCLUDE_CEF_SSL_STATUS_H_
+#pragma once
+
+#include "include/cef_base.h"
+#include "include/cef_values.h"
+#include "include/cef_x509_certificate.h"
+
+///
+/// Class representing the SSL information for a navigation entry.
+///
+/*--cef(source=library)--*/
+class CefSSLStatus : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Returns true if the status is related to a secure SSL/TLS connection.
+ ///
+ /*--cef()--*/
+ virtual bool IsSecureConnection() = 0;
+
+ ///
+ /// Returns a bitmask containing any and all problems verifying the server
+ /// certificate.
+ ///
+ /*--cef(default_retval=CERT_STATUS_NONE)--*/
+ virtual cef_cert_status_t GetCertStatus() = 0;
+
+ ///
+ /// Returns the SSL version used for the SSL connection.
+ ///
+ /*--cef(default_retval=SSL_CONNECTION_VERSION_UNKNOWN)--*/
+ virtual cef_ssl_version_t GetSSLVersion() = 0;
+
+ ///
+ /// Returns a bitmask containing the page security content status.
+ ///
+ /*--cef(default_retval=SSL_CONTENT_NORMAL_CONTENT)--*/
+ virtual cef_ssl_content_status_t GetContentStatus() = 0;
+
+ ///
+ /// Returns the X.509 certificate.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefX509Certificate> GetX509Certificate() = 0;
+};
+
+#endif // CEF_INCLUDE_CEF_SSL_STATUS_H_
diff --git a/include/cef_stream.h b/include/cef_stream.h
new file mode 100644
index 00000000..a7279395
--- /dev/null
+++ b/include/cef_stream.h
@@ -0,0 +1,241 @@
+// Copyright (c) 2012 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_STREAM_H_
+#define CEF_INCLUDE_CEF_STREAM_H_
+
+#include "include/cef_base.h"
+
+///
+/// Interface the client can implement to provide a custom stream reader. The
+/// methods of this class may be called on any thread.
+///
+/*--cef(source=client)--*/
+class CefReadHandler : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Read raw binary data.
+ ///
+ /*--cef()--*/
+ virtual size_t Read(void* ptr, size_t size, size_t n) = 0;
+
+ ///
+ /// Seek to the specified offset position. |whence| may be any one of
+ /// SEEK_CUR, SEEK_END or SEEK_SET. Return zero on success and non-zero on
+ /// failure.
+ ///
+ /*--cef()--*/
+ virtual int Seek(int64 offset, int whence) = 0;
+
+ ///
+ /// Return the current offset position.
+ ///
+ /*--cef()--*/
+ virtual int64 Tell() = 0;
+
+ ///
+ /// Return non-zero if at end of file.
+ ///
+ /*--cef()--*/
+ virtual int Eof() = 0;
+
+ ///
+ /// Return true if this handler performs work like accessing the file system
+ /// which may block. Used as a hint for determining the thread to access the
+ /// handler from.
+ ///
+ /*--cef()--*/
+ virtual bool MayBlock() = 0;
+};
+
+///
+/// Class used to read data from a stream. The methods of this class may be
+/// called on any thread.
+///
+/*--cef(source=library)--*/
+class CefStreamReader : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Create a new CefStreamReader object from a file.
+ ///
+ /*--cef()--*/
+ static CefRefPtr<CefStreamReader> CreateForFile(const CefString& fileName);
+
+ ///
+ /// Create a new CefStreamReader object from data.
+ ///
+ /*--cef()--*/
+ static CefRefPtr<CefStreamReader> CreateForData(void* data, size_t size);
+
+ ///
+ /// Create a new CefStreamReader object from a custom handler.
+ ///
+ /*--cef()--*/
+ static CefRefPtr<CefStreamReader> CreateForHandler(
+ CefRefPtr<CefReadHandler> handler);
+
+ ///
+ /// Read raw binary data.
+ ///
+ /*--cef()--*/
+ virtual size_t Read(void* ptr, size_t size, size_t n) = 0;
+
+ ///
+ /// Seek to the specified offset position. |whence| may be any one of
+ /// SEEK_CUR, SEEK_END or SEEK_SET. Returns zero on success and non-zero on
+ /// failure.
+ ///
+ /*--cef()--*/
+ virtual int Seek(int64 offset, int whence) = 0;
+
+ ///
+ /// Return the current offset position.
+ ///
+ /*--cef()--*/
+ virtual int64 Tell() = 0;
+
+ ///
+ /// Return non-zero if at end of file.
+ ///
+ /*--cef()--*/
+ virtual int Eof() = 0;
+
+ ///
+ /// Returns true if this reader performs work like accessing the file system
+ /// which may block. Used as a hint for determining the thread to access the
+ /// reader from.
+ ///
+ /*--cef()--*/
+ virtual bool MayBlock() = 0;
+};
+
+///
+/// Interface the client can implement to provide a custom stream writer. The
+/// methods of this class may be called on any thread.
+///
+/*--cef(source=client)--*/
+class CefWriteHandler : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Write raw binary data.
+ ///
+ /*--cef()--*/
+ virtual size_t Write(const void* ptr, size_t size, size_t n) = 0;
+
+ ///
+ /// Seek to the specified offset position. |whence| may be any one of
+ /// SEEK_CUR, SEEK_END or SEEK_SET. Return zero on success and non-zero on
+ /// failure.
+ ///
+ /*--cef()--*/
+ virtual int Seek(int64 offset, int whence) = 0;
+
+ ///
+ /// Return the current offset position.
+ ///
+ /*--cef()--*/
+ virtual int64 Tell() = 0;
+
+ ///
+ /// Flush the stream.
+ ///
+ /*--cef()--*/
+ virtual int Flush() = 0;
+
+ ///
+ /// Return true if this handler performs work like accessing the file system
+ /// which may block. Used as a hint for determining the thread to access the
+ /// handler from.
+ ///
+ /*--cef()--*/
+ virtual bool MayBlock() = 0;
+};
+
+///
+/// Class used to write data to a stream. The methods of this class may be
+/// called on any thread.
+///
+/*--cef(source=library)--*/
+class CefStreamWriter : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Create a new CefStreamWriter object for a file.
+ ///
+ /*--cef()--*/
+ static CefRefPtr<CefStreamWriter> CreateForFile(const CefString& fileName);
+ ///
+ /// Create a new CefStreamWriter object for a custom handler.
+ ///
+ /*--cef()--*/
+ static CefRefPtr<CefStreamWriter> CreateForHandler(
+ CefRefPtr<CefWriteHandler> handler);
+
+ ///
+ /// Write raw binary data.
+ ///
+ /*--cef()--*/
+ virtual size_t Write(const void* ptr, size_t size, size_t n) = 0;
+
+ ///
+ /// Seek to the specified offset position. |whence| may be any one of
+ /// SEEK_CUR, SEEK_END or SEEK_SET. Returns zero on success and non-zero on
+ /// failure.
+ ///
+ /*--cef()--*/
+ virtual int Seek(int64 offset, int whence) = 0;
+
+ ///
+ /// Return the current offset position.
+ ///
+ /*--cef()--*/
+ virtual int64 Tell() = 0;
+
+ ///
+ /// Flush the stream.
+ ///
+ /*--cef()--*/
+ virtual int Flush() = 0;
+
+ ///
+ /// Returns true if this writer performs work like accessing the file system
+ /// which may block. Used as a hint for determining the thread to access the
+ /// writer from.
+ ///
+ /*--cef()--*/
+ virtual bool MayBlock() = 0;
+};
+
+#endif // CEF_INCLUDE_CEF_STREAM_H_
diff --git a/include/cef_string_visitor.h b/include/cef_string_visitor.h
new file mode 100644
index 00000000..c77e59c0
--- /dev/null
+++ b/include/cef_string_visitor.h
@@ -0,0 +1,55 @@
+// Copyright (c) 2012 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_STRING_VISITOR_H_
+#define CEF_INCLUDE_CEF_STRING_VISITOR_H_
+
+#include "include/cef_base.h"
+
+///
+/// Implement this interface to receive string values asynchronously.
+///
+/*--cef(source=client)--*/
+class CefStringVisitor : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Method that will be executed.
+ ///
+ /*--cef(optional_param=string)--*/
+ virtual void Visit(const CefString& string) = 0;
+};
+
+#endif // CEF_INCLUDE_CEF_STRING_VISITOR_H_
diff --git a/include/cef_task.h b/include/cef_task.h
new file mode 100644
index 00000000..f7e414d8
--- /dev/null
+++ b/include/cef_task.h
@@ -0,0 +1,148 @@
+// Copyright (c) 2013 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_TASK_H_
+#define CEF_INCLUDE_CEF_TASK_H_
+
+#include "include/cef_base.h"
+
+typedef cef_thread_id_t CefThreadId;
+
+///
+/// Implement this interface for asynchronous task execution. If the task is
+/// posted successfully and if the associated message loop is still running then
+/// the Execute() method will be called on the target thread. If the task fails
+/// to post then the task object may be destroyed on the source thread instead
+/// of the target thread. For this reason be cautious when performing work in
+/// the task object destructor.
+///
+/*--cef(source=client,no_debugct_check)--*/
+class CefTask : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Method that will be executed on the target thread.
+ ///
+ /*--cef()--*/
+ virtual void Execute() = 0;
+};
+
+///
+/// Class that asynchronously executes tasks on the associated thread. It is
+/// safe to call the methods of this class on any thread.
+///
+/// CEF maintains multiple internal threads that are used for handling different
+/// types of tasks in different processes. The cef_thread_id_t definitions in
+/// cef_types.h list the common CEF threads. Task runners are also available for
+/// other CEF threads as appropriate (for example, V8 WebWorker threads).
+///
+/*--cef(source=library)--*/
+class CefTaskRunner : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Returns the task runner for the current thread. Only CEF threads will have
+ /// task runners. An empty reference will be returned if this method is called
+ /// on an invalid thread.
+ ///
+ /*--cef()--*/
+ static CefRefPtr<CefTaskRunner> GetForCurrentThread();
+
+ ///
+ /// Returns the task runner for the specified CEF thread.
+ ///
+ /*--cef()--*/
+ static CefRefPtr<CefTaskRunner> GetForThread(CefThreadId threadId);
+
+ ///
+ /// Returns true if this object is pointing to the same task runner as |that|
+ /// object.
+ ///
+ /*--cef()--*/
+ virtual bool IsSame(CefRefPtr<CefTaskRunner> that) = 0;
+
+ ///
+ /// Returns true if this task runner belongs to the current thread.
+ ///
+ /*--cef()--*/
+ virtual bool BelongsToCurrentThread() = 0;
+
+ ///
+ /// Returns true if this task runner is for the specified CEF thread.
+ ///
+ /*--cef()--*/
+ virtual bool BelongsToThread(CefThreadId threadId) = 0;
+
+ ///
+ /// Post a task for execution on the thread associated with this task runner.
+ /// Execution will occur asynchronously.
+ ///
+ /*--cef()--*/
+ virtual bool PostTask(CefRefPtr<CefTask> task) = 0;
+
+ ///
+ /// Post a task for delayed execution on the thread associated with this task
+ /// runner. Execution will occur asynchronously. Delayed tasks are not
+ /// supported on V8 WebWorker threads and will be executed without the
+ /// specified delay.
+ ///
+ /*--cef()--*/
+ virtual bool PostDelayedTask(CefRefPtr<CefTask> task, int64 delay_ms) = 0;
+};
+
+///
+/// Returns true if called on the specified thread. Equivalent to using
+/// CefTaskRunner::GetForThread(threadId)->BelongsToCurrentThread().
+///
+/*--cef()--*/
+bool CefCurrentlyOn(CefThreadId threadId);
+
+///
+/// Post a task for execution on the specified thread. Equivalent to
+/// using CefTaskRunner::GetForThread(threadId)->PostTask(task).
+///
+/*--cef()--*/
+bool CefPostTask(CefThreadId threadId, CefRefPtr<CefTask> task);
+
+///
+/// Post a task for delayed execution on the specified thread. Equivalent to
+/// using CefTaskRunner::GetForThread(threadId)->PostDelayedTask(task,
+/// delay_ms).
+///
+/*--cef()--*/
+bool CefPostDelayedTask(CefThreadId threadId,
+ CefRefPtr<CefTask> task,
+ int64 delay_ms);
+
+#endif // CEF_INCLUDE_CEF_TASK_H_
diff --git a/include/cef_thread.h b/include/cef_thread.h
new file mode 100644
index 00000000..da00c1e0
--- /dev/null
+++ b/include/cef_thread.h
@@ -0,0 +1,117 @@
+// Copyright (c) 2016 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_THREAD_H_
+#define CEF_INCLUDE_CEF_THREAD_H_
+#pragma once
+
+#include "include/cef_task.h"
+#include "include/internal/cef_thread_internal.h"
+
+///
+/// A simple thread abstraction that establishes a message loop on a new thread.
+/// The consumer uses CefTaskRunner to execute code on the thread's message
+/// loop. The thread is terminated when the CefThread object is destroyed or
+/// Stop() is called. All pending tasks queued on the thread's message loop will
+/// run to completion before the thread is terminated. CreateThread() can be
+/// called on any valid CEF thread in either the browser or render process. This
+/// class should only be used for tasks that require a dedicated thread. In most
+/// cases you can post tasks to an existing CEF thread instead of creating a new
+/// one; see cef_task.h for details.
+///
+/*--cef(source=library)--*/
+class CefThread : public CefBaseRefCounted {
+ public:
+ ///
+ /// Create and start a new thread. This method does not block waiting for the
+ /// thread to run initialization. |display_name| is the name that will be used
+ /// to identify the thread. |priority| is the thread execution priority.
+ /// |message_loop_type| indicates the set of asynchronous events that the
+ /// thread can process. If |stoppable| is true the thread will stopped and
+ /// joined on destruction or when Stop() is called; otherwise, the thread
+ /// cannot be stopped and will be leaked on shutdown. On Windows the
+ /// |com_init_mode| value specifies how COM will be initialized for the
+ /// thread. If |com_init_mode| is set to COM_INIT_MODE_STA then
+ /// |message_loop_type| must be set to ML_TYPE_UI.
+ ///
+ /*--cef(optional_param=display_name)--*/
+ static CefRefPtr<CefThread> CreateThread(
+ const CefString& display_name,
+ cef_thread_priority_t priority,
+ cef_message_loop_type_t message_loop_type,
+ bool stoppable,
+ cef_com_init_mode_t com_init_mode);
+
+ ///
+ /// Create and start a new thread with default/recommended values.
+ /// |display_name| is the name that will be used to identify the thread.
+ ///
+ static CefRefPtr<CefThread> CreateThread(const CefString& display_name) {
+ return CreateThread(display_name, TP_NORMAL, ML_TYPE_DEFAULT, true,
+ COM_INIT_MODE_NONE);
+ }
+
+ ///
+ /// Returns the CefTaskRunner that will execute code on this thread's message
+ /// loop. This method is safe to call from any thread.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefTaskRunner> GetTaskRunner() = 0;
+
+ ///
+ /// Returns the platform thread ID. It will return the same value after Stop()
+ /// is called. This method is safe to call from any thread.
+ ///
+ /*--cef(default_retval=kInvalidPlatformThreadId)--*/
+ virtual cef_platform_thread_id_t GetPlatformThreadId() = 0;
+
+ ///
+ /// Stop and join the thread. This method must be called from the same thread
+ /// that called CreateThread(). Do not call this method if CreateThread() was
+ /// called with a |stoppable| value of false.
+ ///
+ /*--cef()--*/
+ virtual void Stop() = 0;
+
+ ///
+ /// Returns true if the thread is currently running. This method must be
+ /// called from the same thread that called CreateThread().
+ ///
+ /*--cef()--*/
+ virtual bool IsRunning() = 0;
+};
+
+#endif // CEF_INCLUDE_CEF_THREAD_H_
diff --git a/include/cef_trace.h b/include/cef_trace.h
new file mode 100644
index 00000000..20d1c2cf
--- /dev/null
+++ b/include/cef_trace.h
@@ -0,0 +1,111 @@
+// Copyright (c) 2012 Marshall A. Greenblatt. Portons copyright (c) 2012
+// Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+// See cef_trace_event.h for trace macros and additonal documentation.
+
+#ifndef CEF_INCLUDE_CEF_TRACE_H_
+#define CEF_INCLUDE_CEF_TRACE_H_
+#pragma once
+
+#include "include/cef_base.h"
+#include "include/cef_callback.h"
+
+///
+/// Implement this interface to receive notification when tracing has completed.
+/// The methods of this class will be called on the browser process UI thread.
+///
+/*--cef(source=client)--*/
+class CefEndTracingCallback : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Called after all processes have sent their trace data. |tracing_file| is
+ /// the path at which tracing data was written. The client is responsible for
+ /// deleting |tracing_file|.
+ ///
+ /*--cef()--*/
+ virtual void OnEndTracingComplete(const CefString& tracing_file) = 0;
+};
+
+///
+/// Start tracing events on all processes. Tracing is initialized asynchronously
+/// and |callback| will be executed on the UI thread after initialization is
+/// complete.
+///
+/// If CefBeginTracing was called previously, or if a CefEndTracingAsync call is
+/// pending, CefBeginTracing will fail and return false.
+///
+/// |categories| is a comma-delimited list of category wildcards. A category can
+/// have an optional '-' prefix to make it an excluded category. Having both
+/// included and excluded categories in the same list is not supported.
+///
+/// Examples:
+/// - "test_MyTest*"
+/// - "test_MyTest*,test_OtherStuff"
+/// - "-excluded_category1,-excluded_category2"
+///
+/// This function must be called on the browser process UI thread.
+///
+/*--cef(optional_param=categories,optional_param=callback)--*/
+bool CefBeginTracing(const CefString& categories,
+ CefRefPtr<CefCompletionCallback> callback);
+
+///
+/// Stop tracing events on all processes.
+///
+/// This function will fail and return false if a previous call to
+/// CefEndTracingAsync is already pending or if CefBeginTracing was not called.
+///
+/// |tracing_file| is the path at which tracing data will be written and
+/// |callback| is the callback that will be executed once all processes have
+/// sent their trace data. If |tracing_file| is empty a new temporary file path
+/// will be used. If |callback| is empty no trace data will be written.
+///
+/// This function must be called on the browser process UI thread.
+///
+/*--cef(optional_param=tracing_file,optional_param=callback)--*/
+bool CefEndTracing(const CefString& tracing_file,
+ CefRefPtr<CefEndTracingCallback> callback);
+
+///
+/// Returns the current system trace time or, if none is defined, the current
+/// high-res time. Can be used by clients to synchronize with the time
+/// information in trace events.
+///
+/*--cef()--*/
+int64 CefNowFromSystemTraceTime();
+
+#endif // CEF_INCLUDE_CEF_TRACE_H_
diff --git a/include/cef_urlrequest.h b/include/cef_urlrequest.h
new file mode 100644
index 00000000..faebfe76
--- /dev/null
+++ b/include/cef_urlrequest.h
@@ -0,0 +1,198 @@
+// Copyright (c) 2012 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_URLREQUEST_H_
+#define CEF_INCLUDE_CEF_URLREQUEST_H_
+#pragma once
+
+#include "include/cef_auth_callback.h"
+#include "include/cef_base.h"
+#include "include/cef_request.h"
+#include "include/cef_request_context.h"
+#include "include/cef_response.h"
+
+class CefURLRequestClient;
+
+///
+/// Class used to make a URL request. URL requests are not associated with a
+/// browser instance so no CefClient callbacks will be executed. URL requests
+/// can be created on any valid CEF thread in either the browser or render
+/// process. Once created the methods of the URL request object must be accessed
+/// on the same thread that created it.
+///
+/*--cef(source=library)--*/
+class CefURLRequest : public virtual CefBaseRefCounted {
+ public:
+ typedef cef_urlrequest_status_t Status;
+ typedef cef_errorcode_t ErrorCode;
+
+ ///
+ /// Create a new URL request that is not associated with a specific browser or
+ /// frame. Use CefFrame::CreateURLRequest instead if you want the request to
+ /// have this association, in which case it may be handled differently (see
+ /// documentation on that method). A request created with this method may only
+ /// originate from the browser process, and will behave as follows:
+ /// - It may be intercepted by the client via CefResourceRequestHandler or
+ /// CefSchemeHandlerFactory.
+ /// - POST data may only contain only a single element of type PDE_TYPE_FILE
+ /// or PDE_TYPE_BYTES.
+ /// - If |request_context| is empty the global request context will be used.
+ ///
+ /// The |request| object will be marked as read-only after calling this
+ /// method.
+ ///
+ /*--cef(optional_param=request_context)--*/
+ static CefRefPtr<CefURLRequest> Create(
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefURLRequestClient> client,
+ CefRefPtr<CefRequestContext> request_context);
+
+ ///
+ /// Returns the request object used to create this URL request. The returned
+ /// object is read-only and should not be modified.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefRequest> GetRequest() = 0;
+
+ ///
+ /// Returns the client.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefURLRequestClient> GetClient() = 0;
+
+ ///
+ /// Returns the request status.
+ ///
+ /*--cef(default_retval=UR_UNKNOWN)--*/
+ virtual Status GetRequestStatus() = 0;
+
+ ///
+ /// Returns the request error if status is UR_CANCELED or UR_FAILED, or 0
+ /// otherwise.
+ ///
+ /*--cef(default_retval=ERR_NONE)--*/
+ virtual ErrorCode GetRequestError() = 0;
+
+ ///
+ /// Returns the response, or NULL if no response information is available.
+ /// Response information will only be available after the upload has
+ /// completed. The returned object is read-only and should not be modified.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefResponse> GetResponse() = 0;
+
+ ///
+ /// Returns true if the response body was served from the cache. This includes
+ /// responses for which revalidation was required.
+ ///
+ /*--cef()--*/
+ virtual bool ResponseWasCached() = 0;
+
+ ///
+ /// Cancel the request.
+ ///
+ /*--cef()--*/
+ virtual void Cancel() = 0;
+};
+
+///
+/// Interface that should be implemented by the CefURLRequest client. The
+/// methods of this class will be called on the same thread that created the
+/// request unless otherwise documented.
+///
+/*--cef(source=client)--*/
+class CefURLRequestClient : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Notifies the client that the request has completed. Use the
+ /// CefURLRequest::GetRequestStatus method to determine if the request was
+ /// successful or not.
+ ///
+ /*--cef()--*/
+ virtual void OnRequestComplete(CefRefPtr<CefURLRequest> request) = 0;
+
+ ///
+ /// Notifies the client of upload progress. |current| denotes the number of
+ /// bytes sent so far and |total| is the total size of uploading data (or -1
+ /// if chunked upload is enabled). This method will only be called if the
+ /// UR_FLAG_REPORT_UPLOAD_PROGRESS flag is set on the request.
+ ///
+ /*--cef()--*/
+ virtual void OnUploadProgress(CefRefPtr<CefURLRequest> request,
+ int64 current,
+ int64 total) = 0;
+
+ ///
+ /// Notifies the client of download progress. |current| denotes the number of
+ /// bytes received up to the call and |total| is the expected total size of
+ /// the response (or -1 if not determined).
+ ///
+ /*--cef()--*/
+ virtual void OnDownloadProgress(CefRefPtr<CefURLRequest> request,
+ int64 current,
+ int64 total) = 0;
+
+ ///
+ /// Called when some part of the response is read. |data| contains the current
+ /// bytes received since the last call. This method will not be called if the
+ /// UR_FLAG_NO_DOWNLOAD_DATA flag is set on the request.
+ ///
+ /*--cef()--*/
+ virtual void OnDownloadData(CefRefPtr<CefURLRequest> request,
+ const void* data,
+ size_t data_length) = 0;
+
+ ///
+ /// Called on the IO thread when the browser needs credentials from the user.
+ /// |isProxy| indicates whether the host is a proxy server. |host| contains
+ /// the hostname and |port| contains the port number. Return true to continue
+ /// the request and call CefAuthCallback::Continue() when the authentication
+ /// information is available. If the request has an associated browser/frame
+ /// then returning false will result in a call to GetAuthCredentials on the
+ /// CefRequestHandler associated with that browser, if any. Otherwise,
+ /// returning false will cancel the request immediately. This method will only
+ /// be called for requests initiated from the browser process.
+ ///
+ /*--cef(optional_param=realm)--*/
+ virtual bool GetAuthCredentials(bool isProxy,
+ const CefString& host,
+ int port,
+ const CefString& realm,
+ const CefString& scheme,
+ CefRefPtr<CefAuthCallback> callback) = 0;
+};
+
+#endif // CEF_INCLUDE_CEF_URLREQUEST_H_
diff --git a/include/cef_v8.h b/include/cef_v8.h
new file mode 100644
index 00000000..a8534da2
--- /dev/null
+++ b/include/cef_v8.h
@@ -0,0 +1,1038 @@
+// Copyright (c) 2013 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_V8_H_
+#define CEF_INCLUDE_CEF_V8_H_
+#pragma once
+
+#include <vector>
+#include "include/cef_base.h"
+#include "include/cef_browser.h"
+#include "include/cef_frame.h"
+#include "include/cef_task.h"
+
+class CefV8Exception;
+class CefV8Handler;
+class CefV8StackFrame;
+class CefV8Value;
+
+///
+/// Register a new V8 extension with the specified JavaScript extension code and
+/// handler. Functions implemented by the handler are prototyped using the
+/// keyword 'native'. The calling of a native function is restricted to the
+/// scope in which the prototype of the native function is defined. This
+/// function may only be called on the render process main thread.
+///
+/// Example JavaScript extension code:
+/// <pre>
+/// // create the 'example' global object if it doesn't already exist.
+/// if (!example)
+/// example = {};
+/// // create the 'example.test' global object if it doesn't already exist.
+/// if (!example.test)
+/// example.test = {};
+/// (function() {
+/// // Define the function 'example.test.myfunction'.
+/// example.test.myfunction = function() {
+/// // Call CefV8Handler::Execute() with the function name 'MyFunction'
+/// // and no arguments.
+/// native function MyFunction();
+/// return MyFunction();
+/// };
+/// // Define the getter function for parameter 'example.test.myparam'.
+/// example.test.__defineGetter__('myparam', function() {
+/// // Call CefV8Handler::Execute() with the function name 'GetMyParam'
+/// // and no arguments.
+/// native function GetMyParam();
+/// return GetMyParam();
+/// });
+/// // Define the setter function for parameter 'example.test.myparam'.
+/// example.test.__defineSetter__('myparam', function(b) {
+/// // Call CefV8Handler::Execute() with the function name 'SetMyParam'
+/// // and a single argument.
+/// native function SetMyParam();
+/// if(b) SetMyParam(b);
+/// });
+///
+/// // Extension definitions can also contain normal JavaScript variables
+/// // and functions.
+/// var myint = 0;
+/// example.test.increment = function() {
+/// myint += 1;
+/// return myint;
+/// };
+/// })();
+/// </pre>
+///
+/// Example usage in the page:
+/// <pre>
+/// // Call the function.
+/// example.test.myfunction();
+/// // Set the parameter.
+/// example.test.myparam = value;
+/// // Get the parameter.
+/// value = example.test.myparam;
+/// // Call another function.
+/// example.test.increment();
+/// </pre>
+///
+/*--cef(optional_param=handler)--*/
+bool CefRegisterExtension(const CefString& extension_name,
+ const CefString& javascript_code,
+ CefRefPtr<CefV8Handler> handler);
+
+///
+/// Class representing a V8 context handle. V8 handles can only be accessed from
+/// the thread on which they are created. Valid threads for creating a V8 handle
+/// include the render process main thread (TID_RENDERER) and WebWorker threads.
+/// A task runner for posting tasks on the associated thread can be retrieved
+/// via the CefV8Context::GetTaskRunner() method.
+///
+/*--cef(source=library,no_debugct_check)--*/
+class CefV8Context : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Returns the current (top) context object in the V8 context stack.
+ ///
+ /*--cef()--*/
+ static CefRefPtr<CefV8Context> GetCurrentContext();
+
+ ///
+ /// Returns the entered (bottom) context object in the V8 context stack.
+ ///
+ /*--cef()--*/
+ static CefRefPtr<CefV8Context> GetEnteredContext();
+
+ ///
+ /// Returns true if V8 is currently inside a context.
+ ///
+ /*--cef()--*/
+ static bool InContext();
+
+ ///
+ /// Returns the task runner associated with this context. V8 handles can only
+ /// be accessed from the thread on which they are created. This method can be
+ /// called on any render process thread.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefTaskRunner> GetTaskRunner() = 0;
+
+ ///
+ /// Returns true if the underlying handle is valid and it can be accessed on
+ /// the current thread. Do not call any other methods if this method returns
+ /// false.
+ ///
+ /*--cef()--*/
+ virtual bool IsValid() = 0;
+
+ ///
+ /// Returns the browser for this context. This method will return an empty
+ /// reference for WebWorker contexts.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefBrowser> GetBrowser() = 0;
+
+ ///
+ /// Returns the frame for this context. This method will return an empty
+ /// reference for WebWorker contexts.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefFrame> GetFrame() = 0;
+
+ ///
+ /// Returns the global object for this context. The context must be entered
+ /// before calling this method.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefV8Value> GetGlobal() = 0;
+
+ ///
+ /// Enter this context. A context must be explicitly entered before creating a
+ /// V8 Object, Array, Function or Date asynchronously. Exit() must be called
+ /// the same number of times as Enter() before releasing this context. V8
+ /// objects belong to the context in which they are created. Returns true if
+ /// the scope was entered successfully.
+ ///
+ /*--cef()--*/
+ virtual bool Enter() = 0;
+
+ ///
+ /// Exit this context. Call this method only after calling Enter(). Returns
+ /// true if the scope was exited successfully.
+ ///
+ /*--cef()--*/
+ virtual bool Exit() = 0;
+
+ ///
+ /// Returns true if this object is pointing to the same handle as |that|
+ /// object.
+ ///
+ /*--cef()--*/
+ virtual bool IsSame(CefRefPtr<CefV8Context> that) = 0;
+
+ ///
+ /// Execute a string of JavaScript code in this V8 context. The |script_url|
+ /// parameter is the URL where the script in question can be found, if any.
+ /// The |start_line| parameter is the base line number to use for error
+ /// reporting. On success |retval| will be set to the return value, if any,
+ /// and the function will return true. On failure |exception| will be set to
+ /// the exception, if any, and the function will return false.
+ ///
+ /*--cef(optional_param=script_url)--*/
+ virtual bool Eval(const CefString& code,
+ const CefString& script_url,
+ int start_line,
+ CefRefPtr<CefV8Value>& retval,
+ CefRefPtr<CefV8Exception>& exception) = 0;
+};
+
+typedef std::vector<CefRefPtr<CefV8Value>> CefV8ValueList;
+
+///
+/// Interface that should be implemented to handle V8 function calls. The
+/// methods of this class will be called on the thread associated with the V8
+/// function.
+///
+/*--cef(source=client,no_debugct_check)--*/
+class CefV8Handler : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Handle execution of the function identified by |name|. |object| is the
+ /// receiver ('this' object) of the function. |arguments| is the list of
+ /// arguments passed to the function. If execution succeeds set |retval| to
+ /// the function return value. If execution fails set |exception| to the
+ /// exception that will be thrown. Return true if execution was handled.
+ ///
+ /*--cef()--*/
+ virtual bool Execute(const CefString& name,
+ CefRefPtr<CefV8Value> object,
+ const CefV8ValueList& arguments,
+ CefRefPtr<CefV8Value>& retval,
+ CefString& exception) = 0;
+};
+
+///
+/// Interface that should be implemented to handle V8 accessor calls. Accessor
+/// identifiers are registered by calling CefV8Value::SetValue(). The methods
+/// of this class will be called on the thread associated with the V8 accessor.
+///
+/*--cef(source=client,no_debugct_check)--*/
+class CefV8Accessor : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Handle retrieval the accessor value identified by |name|. |object| is the
+ /// receiver ('this' object) of the accessor. If retrieval succeeds set
+ /// |retval| to the return value. If retrieval fails set |exception| to the
+ /// exception that will be thrown. Return true if accessor retrieval was
+ /// handled.
+ ///
+ /*--cef()--*/
+ virtual bool Get(const CefString& name,
+ const CefRefPtr<CefV8Value> object,
+ CefRefPtr<CefV8Value>& retval,
+ CefString& exception) = 0;
+
+ ///
+ /// Handle assignment of the accessor value identified by |name|. |object| is
+ /// the receiver ('this' object) of the accessor. |value| is the new value
+ /// being assigned to the accessor. If assignment fails set |exception| to the
+ /// exception that will be thrown. Return true if accessor assignment was
+ /// handled.
+ ///
+ /*--cef()--*/
+ virtual bool Set(const CefString& name,
+ const CefRefPtr<CefV8Value> object,
+ const CefRefPtr<CefV8Value> value,
+ CefString& exception) = 0;
+};
+
+///
+/// Interface that should be implemented to handle V8 interceptor calls. The
+/// methods of this class will be called on the thread associated with the V8
+/// interceptor. Interceptor's named property handlers (with first argument of
+/// type CefString) are called when object is indexed by string. Indexed
+/// property handlers (with first argument of type int) are called when object
+/// is indexed by integer.
+///
+/*--cef(source=client,no_debugct_check)--*/
+class CefV8Interceptor : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Handle retrieval of the interceptor value identified by |name|. |object|
+ /// is the receiver ('this' object) of the interceptor. If retrieval succeeds,
+ /// set |retval| to the return value. If the requested value does not exist,
+ /// don't set either |retval| or |exception|. If retrieval fails, set
+ /// |exception| to the exception that will be thrown. If the property has an
+ /// associated accessor, it will be called only if you don't set |retval|.
+ /// Return true if interceptor retrieval was handled, false otherwise.
+ ///
+ /*--cef(capi_name=get_byname)--*/
+ virtual bool Get(const CefString& name,
+ const CefRefPtr<CefV8Value> object,
+ CefRefPtr<CefV8Value>& retval,
+ CefString& exception) = 0;
+
+ ///
+ /// Handle retrieval of the interceptor value identified by |index|. |object|
+ /// is the receiver ('this' object) of the interceptor. If retrieval succeeds,
+ /// set |retval| to the return value. If the requested value does not exist,
+ /// don't set either |retval| or |exception|. If retrieval fails, set
+ /// |exception| to the exception that will be thrown.
+ /// Return true if interceptor retrieval was handled, false otherwise.
+ ///
+ /*--cef(capi_name=get_byindex,index_param=index)--*/
+ virtual bool Get(int index,
+ const CefRefPtr<CefV8Value> object,
+ CefRefPtr<CefV8Value>& retval,
+ CefString& exception) = 0;
+
+ ///
+ /// Handle assignment of the interceptor value identified by |name|. |object|
+ /// is the receiver ('this' object) of the interceptor. |value| is the new
+ /// value being assigned to the interceptor. If assignment fails, set
+ /// |exception| to the exception that will be thrown. This setter will always
+ /// be called, even when the property has an associated accessor.
+ /// Return true if interceptor assignment was handled, false otherwise.
+ ///
+ /*--cef(capi_name=set_byname)--*/
+ virtual bool Set(const CefString& name,
+ const CefRefPtr<CefV8Value> object,
+ const CefRefPtr<CefV8Value> value,
+ CefString& exception) = 0;
+
+ ///
+ /// Handle assignment of the interceptor value identified by |index|. |object|
+ /// is the receiver ('this' object) of the interceptor. |value| is the new
+ /// value being assigned to the interceptor. If assignment fails, set
+ /// |exception| to the exception that will be thrown.
+ /// Return true if interceptor assignment was handled, false otherwise.
+ ///
+ /*--cef(capi_name=set_byindex,index_param=index)--*/
+ virtual bool Set(int index,
+ const CefRefPtr<CefV8Value> object,
+ const CefRefPtr<CefV8Value> value,
+ CefString& exception) = 0;
+};
+
+///
+/// Class representing a V8 exception. The methods of this class may be called
+/// on any render process thread.
+///
+/*--cef(source=library,no_debugct_check)--*/
+class CefV8Exception : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Returns the exception message.
+ ///
+ /*--cef()--*/
+ virtual CefString GetMessage() = 0;
+
+ ///
+ /// Returns the line of source code that the exception occurred within.
+ ///
+ /*--cef()--*/
+ virtual CefString GetSourceLine() = 0;
+
+ ///
+ /// Returns the resource name for the script from where the function causing
+ /// the error originates.
+ ///
+ /*--cef()--*/
+ virtual CefString GetScriptResourceName() = 0;
+
+ ///
+ /// Returns the 1-based number of the line where the error occurred or 0 if
+ /// the line number is unknown.
+ ///
+ /*--cef()--*/
+ virtual int GetLineNumber() = 0;
+
+ ///
+ /// Returns the index within the script of the first character where the error
+ /// occurred.
+ ///
+ /*--cef()--*/
+ virtual int GetStartPosition() = 0;
+
+ ///
+ /// Returns the index within the script of the last character where the error
+ /// occurred.
+ ///
+ /*--cef()--*/
+ virtual int GetEndPosition() = 0;
+
+ ///
+ /// Returns the index within the line of the first character where the error
+ /// occurred.
+ ///
+ /*--cef()--*/
+ virtual int GetStartColumn() = 0;
+
+ ///
+ /// Returns the index within the line of the last character where the error
+ /// occurred.
+ ///
+ /*--cef()--*/
+ virtual int GetEndColumn() = 0;
+};
+
+///
+/// Callback interface that is passed to CefV8Value::CreateArrayBuffer.
+///
+/*--cef(source=client,no_debugct_check)--*/
+class CefV8ArrayBufferReleaseCallback : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Called to release |buffer| when the ArrayBuffer JS object is garbage
+ /// collected. |buffer| is the value that was passed to CreateArrayBuffer
+ /// along with this object.
+ ///
+ /*--cef()--*/
+ virtual void ReleaseBuffer(void* buffer) = 0;
+};
+
+///
+/// Class representing a V8 value handle. V8 handles can only be accessed from
+/// the thread on which they are created. Valid threads for creating a V8 handle
+/// include the render process main thread (TID_RENDERER) and WebWorker threads.
+/// A task runner for posting tasks on the associated thread can be retrieved
+/// via the CefV8Context::GetTaskRunner() method.
+///
+/*--cef(source=library,no_debugct_check)--*/
+class CefV8Value : public virtual CefBaseRefCounted {
+ public:
+ typedef cef_v8_accesscontrol_t AccessControl;
+ typedef cef_v8_propertyattribute_t PropertyAttribute;
+
+ ///
+ /// Create a new CefV8Value object of type undefined.
+ ///
+ /*--cef()--*/
+ static CefRefPtr<CefV8Value> CreateUndefined();
+
+ ///
+ /// Create a new CefV8Value object of type null.
+ ///
+ /*--cef()--*/
+ static CefRefPtr<CefV8Value> CreateNull();
+
+ ///
+ /// Create a new CefV8Value object of type bool.
+ ///
+ /*--cef()--*/
+ static CefRefPtr<CefV8Value> CreateBool(bool value);
+
+ ///
+ /// Create a new CefV8Value object of type int.
+ ///
+ /*--cef()--*/
+ static CefRefPtr<CefV8Value> CreateInt(int32 value);
+
+ ///
+ /// Create a new CefV8Value object of type unsigned int.
+ ///
+ /*--cef()--*/
+ static CefRefPtr<CefV8Value> CreateUInt(uint32 value);
+
+ ///
+ /// Create a new CefV8Value object of type double.
+ ///
+ /*--cef()--*/
+ static CefRefPtr<CefV8Value> CreateDouble(double value);
+
+ ///
+ /// Create a new CefV8Value object of type Date. This method should only be
+ /// called from within the scope of a CefRenderProcessHandler, CefV8Handler or
+ /// CefV8Accessor callback, or in combination with calling Enter() and Exit()
+ /// on a stored CefV8Context reference.
+ ///
+ /*--cef()--*/
+ static CefRefPtr<CefV8Value> CreateDate(CefBaseTime date);
+
+ ///
+ /// Create a new CefV8Value object of type string.
+ ///
+ /*--cef(optional_param=value)--*/
+ static CefRefPtr<CefV8Value> CreateString(const CefString& value);
+
+ ///
+ /// Create a new CefV8Value object of type object with optional accessor
+ /// and/or interceptor. This method should only be called from within the
+ /// scope of a CefRenderProcessHandler, CefV8Handler or CefV8Accessor
+ /// callback, or in combination with calling Enter() and Exit() on a stored
+ /// CefV8Context reference.
+ ///
+ /*--cef(optional_param=accessor, optional_param=interceptor)--*/
+ static CefRefPtr<CefV8Value> CreateObject(
+ CefRefPtr<CefV8Accessor> accessor,
+ CefRefPtr<CefV8Interceptor> interceptor);
+
+ ///
+ /// Create a new CefV8Value object of type array with the specified |length|.
+ /// If |length| is negative the returned array will have length 0. This method
+ /// should only be called from within the scope of a CefRenderProcessHandler,
+ /// CefV8Handler or CefV8Accessor callback, or in combination with calling
+ /// Enter() and Exit() on a stored CefV8Context reference.
+ ///
+ /*--cef()--*/
+ static CefRefPtr<CefV8Value> CreateArray(int length);
+
+ ///
+ /// Create a new CefV8Value object of type ArrayBuffer which wraps the
+ /// provided |buffer| of size |length| bytes. The ArrayBuffer is externalized,
+ /// meaning that it does not own |buffer|. The caller is responsible for
+ /// freeing |buffer| when requested via a call to
+ /// CefV8ArrayBufferReleaseCallback::ReleaseBuffer. This method should only
+ /// be called from within the scope of a CefRenderProcessHandler, CefV8Handler
+ /// or CefV8Accessor callback, or in combination with calling Enter() and
+ /// Exit() on a stored CefV8Context reference.
+ ///
+ /*--cef()--*/
+ static CefRefPtr<CefV8Value> CreateArrayBuffer(
+ void* buffer,
+ size_t length,
+ CefRefPtr<CefV8ArrayBufferReleaseCallback> release_callback);
+
+ ///
+ /// Create a new CefV8Value object of type function. This method should only
+ /// be called from within the scope of a CefRenderProcessHandler, CefV8Handler
+ /// or CefV8Accessor callback, or in combination with calling Enter() and
+ /// Exit() on a stored CefV8Context reference.
+ ///
+ /*--cef()--*/
+ static CefRefPtr<CefV8Value> CreateFunction(const CefString& name,
+ CefRefPtr<CefV8Handler> handler);
+
+ ///
+ /// Create a new CefV8Value object of type Promise. This method should only be
+ /// called from within the scope of a CefRenderProcessHandler, CefV8Handler or
+ /// CefV8Accessor callback, or in combination with calling Enter() and Exit()
+ /// on a stored CefV8Context reference.
+ ///
+ /*--cef()--*/
+ static CefRefPtr<CefV8Value> CreatePromise();
+
+ ///
+ /// Returns true if the underlying handle is valid and it can be accessed on
+ /// the current thread. Do not call any other methods if this method returns
+ /// false.
+ ///
+ /*--cef()--*/
+ virtual bool IsValid() = 0;
+
+ ///
+ /// True if the value type is undefined.
+ ///
+ /*--cef()--*/
+ virtual bool IsUndefined() = 0;
+
+ ///
+ /// True if the value type is null.
+ ///
+ /*--cef()--*/
+ virtual bool IsNull() = 0;
+
+ ///
+ /// True if the value type is bool.
+ ///
+ /*--cef()--*/
+ virtual bool IsBool() = 0;
+
+ ///
+ /// True if the value type is int.
+ ///
+ /*--cef()--*/
+ virtual bool IsInt() = 0;
+
+ ///
+ /// True if the value type is unsigned int.
+ ///
+ /*--cef()--*/
+ virtual bool IsUInt() = 0;
+
+ ///
+ /// True if the value type is double.
+ ///
+ /*--cef()--*/
+ virtual bool IsDouble() = 0;
+
+ ///
+ /// True if the value type is Date.
+ ///
+ /*--cef()--*/
+ virtual bool IsDate() = 0;
+
+ ///
+ /// True if the value type is string.
+ ///
+ /*--cef()--*/
+ virtual bool IsString() = 0;
+
+ ///
+ /// True if the value type is object.
+ ///
+ /*--cef()--*/
+ virtual bool IsObject() = 0;
+
+ ///
+ /// True if the value type is array.
+ ///
+ /*--cef()--*/
+ virtual bool IsArray() = 0;
+
+ ///
+ /// True if the value type is an ArrayBuffer.
+ ///
+ /*--cef()--*/
+ virtual bool IsArrayBuffer() = 0;
+
+ ///
+ /// True if the value type is function.
+ ///
+ /*--cef()--*/
+ virtual bool IsFunction() = 0;
+
+ ///
+ /// True if the value type is a Promise.
+ ///
+ /*--cef()--*/
+ virtual bool IsPromise() = 0;
+
+ ///
+ /// Returns true if this object is pointing to the same handle as |that|
+ /// object.
+ ///
+ /*--cef()--*/
+ virtual bool IsSame(CefRefPtr<CefV8Value> that) = 0;
+
+ ///
+ /// Return a bool value.
+ ///
+ /*--cef()--*/
+ virtual bool GetBoolValue() = 0;
+
+ ///
+ /// Return an int value.
+ ///
+ /*--cef()--*/
+ virtual int32 GetIntValue() = 0;
+
+ ///
+ /// Return an unsigned int value.
+ ///
+ /*--cef()--*/
+ virtual uint32 GetUIntValue() = 0;
+
+ ///
+ /// Return a double value.
+ ///
+ /*--cef()--*/
+ virtual double GetDoubleValue() = 0;
+
+ ///
+ /// Return a Date value.
+ ///
+ /*--cef()--*/
+ virtual CefBaseTime GetDateValue() = 0;
+
+ ///
+ /// Return a string value.
+ ///
+ /*--cef()--*/
+ virtual CefString GetStringValue() = 0;
+
+ /// OBJECT METHODS - These methods are only available on objects. Arrays and
+ /// functions are also objects. String- and integer-based keys can be used
+ /// interchangably with the framework converting between them as necessary.
+
+ ///
+ /// Returns true if this is a user created object.
+ ///
+ /*--cef()--*/
+ virtual bool IsUserCreated() = 0;
+
+ ///
+ /// Returns true if the last method call resulted in an exception. This
+ /// attribute exists only in the scope of the current CEF value object.
+ ///
+ /*--cef()--*/
+ virtual bool HasException() = 0;
+
+ ///
+ /// Returns the exception resulting from the last method call. This attribute
+ /// exists only in the scope of the current CEF value object.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefV8Exception> GetException() = 0;
+
+ ///
+ /// Clears the last exception and returns true on success.
+ ///
+ /*--cef()--*/
+ virtual bool ClearException() = 0;
+
+ ///
+ /// Returns true if this object will re-throw future exceptions. This
+ /// attribute exists only in the scope of the current CEF value object.
+ ///
+ /*--cef()--*/
+ virtual bool WillRethrowExceptions() = 0;
+
+ ///
+ /// Set whether this object will re-throw future exceptions. By default
+ /// exceptions are not re-thrown. If a exception is re-thrown the current
+ /// context should not be accessed again until after the exception has been
+ /// caught and not re-thrown. Returns true on success. This attribute exists
+ /// only in the scope of the current CEF value object.
+ ///
+ /*--cef()--*/
+ virtual bool SetRethrowExceptions(bool rethrow) = 0;
+
+ ///
+ /// Returns true if the object has a value with the specified identifier.
+ ///
+ /*--cef(capi_name=has_value_bykey,optional_param=key)--*/
+ virtual bool HasValue(const CefString& key) = 0;
+
+ ///
+ /// Returns true if the object has a value with the specified identifier.
+ ///
+ /*--cef(capi_name=has_value_byindex,index_param=index)--*/
+ virtual bool HasValue(int index) = 0;
+
+ ///
+ /// Deletes the value with the specified identifier and returns true on
+ /// success. Returns false if this method is called incorrectly or an
+ /// exception is thrown. For read-only and don't-delete values this method
+ /// will return true even though deletion failed.
+ ///
+ /*--cef(capi_name=delete_value_bykey,optional_param=key)--*/
+ virtual bool DeleteValue(const CefString& key) = 0;
+
+ ///
+ /// Deletes the value with the specified identifier and returns true on
+ /// success. Returns false if this method is called incorrectly, deletion
+ /// fails or an exception is thrown. For read-only and don't-delete values
+ /// this method will return true even though deletion failed.
+ ///
+ /*--cef(capi_name=delete_value_byindex,index_param=index)--*/
+ virtual bool DeleteValue(int index) = 0;
+
+ ///
+ /// Returns the value with the specified identifier on success. Returns NULL
+ /// if this method is called incorrectly or an exception is thrown.
+ ///
+ /*--cef(capi_name=get_value_bykey,optional_param=key)--*/
+ virtual CefRefPtr<CefV8Value> GetValue(const CefString& key) = 0;
+
+ ///
+ /// Returns the value with the specified identifier on success. Returns NULL
+ /// if this method is called incorrectly or an exception is thrown.
+ ///
+ /*--cef(capi_name=get_value_byindex,index_param=index)--*/
+ virtual CefRefPtr<CefV8Value> GetValue(int index) = 0;
+
+ ///
+ /// Associates a value with the specified identifier and returns true on
+ /// success. Returns false if this method is called incorrectly or an
+ /// exception is thrown. For read-only values this method will return true
+ /// even though assignment failed.
+ ///
+ /*--cef(capi_name=set_value_bykey,optional_param=key)--*/
+ virtual bool SetValue(const CefString& key,
+ CefRefPtr<CefV8Value> value,
+ PropertyAttribute attribute) = 0;
+
+ ///
+ /// Associates a value with the specified identifier and returns true on
+ /// success. Returns false if this method is called incorrectly or an
+ /// exception is thrown. For read-only values this method will return true
+ /// even though assignment failed.
+ ///
+ /*--cef(capi_name=set_value_byindex,index_param=index)--*/
+ virtual bool SetValue(int index, CefRefPtr<CefV8Value> value) = 0;
+
+ ///
+ /// Registers an identifier and returns true on success. Access to the
+ /// identifier will be forwarded to the CefV8Accessor instance passed to
+ /// CefV8Value::CreateObject(). Returns false if this method is called
+ /// incorrectly or an exception is thrown. For read-only values this method
+ /// will return true even though assignment failed.
+ ///
+ /*--cef(capi_name=set_value_byaccessor,optional_param=key)--*/
+ virtual bool SetValue(const CefString& key,
+ AccessControl settings,
+ PropertyAttribute attribute) = 0;
+
+ ///
+ /// Read the keys for the object's values into the specified vector. Integer-
+ /// based keys will also be returned as strings.
+ ///
+ /*--cef()--*/
+ virtual bool GetKeys(std::vector<CefString>& keys) = 0;
+
+ ///
+ /// Sets the user data for this object and returns true on success. Returns
+ /// false if this method is called incorrectly. This method can only be called
+ /// on user created objects.
+ ///
+ /*--cef(optional_param=user_data)--*/
+ virtual bool SetUserData(CefRefPtr<CefBaseRefCounted> user_data) = 0;
+
+ ///
+ /// Returns the user data, if any, assigned to this object.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefBaseRefCounted> GetUserData() = 0;
+
+ ///
+ /// Returns the amount of externally allocated memory registered for the
+ /// object.
+ ///
+ /*--cef()--*/
+ virtual int GetExternallyAllocatedMemory() = 0;
+
+ ///
+ /// Adjusts the amount of registered external memory for the object. Used to
+ /// give V8 an indication of the amount of externally allocated memory that is
+ /// kept alive by JavaScript objects. V8 uses this information to decide when
+ /// to perform global garbage collection. Each CefV8Value tracks the amount of
+ /// external memory associated with it and automatically decreases the global
+ /// total by the appropriate amount on its destruction. |change_in_bytes|
+ /// specifies the number of bytes to adjust by. This method returns the number
+ /// of bytes associated with the object after the adjustment. This method can
+ /// only be called on user created objects.
+ ///
+ /*--cef()--*/
+ virtual int AdjustExternallyAllocatedMemory(int change_in_bytes) = 0;
+
+ // ARRAY METHODS - These methods are only available on arrays.
+
+ ///
+ /// Returns the number of elements in the array.
+ ///
+ /*--cef()--*/
+ virtual int GetArrayLength() = 0;
+
+ // ARRAY BUFFER METHODS - These methods are only available on ArrayBuffers.
+
+ ///
+ /// Returns the ReleaseCallback object associated with the ArrayBuffer or NULL
+ /// if the ArrayBuffer was not created with CreateArrayBuffer.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefV8ArrayBufferReleaseCallback>
+ GetArrayBufferReleaseCallback() = 0;
+
+ ///
+ /// Prevent the ArrayBuffer from using it's memory block by setting the length
+ /// to zero. This operation cannot be undone. If the ArrayBuffer was created
+ /// with CreateArrayBuffer then CefV8ArrayBufferReleaseCallback::ReleaseBuffer
+ /// will be called to release the underlying buffer.
+ ///
+ /*--cef()--*/
+ virtual bool NeuterArrayBuffer() = 0;
+
+ // FUNCTION METHODS - These methods are only available on functions.
+
+ ///
+ /// Returns the function name.
+ ///
+ /*--cef()--*/
+ virtual CefString GetFunctionName() = 0;
+
+ ///
+ /// Returns the function handler or NULL if not a CEF-created function.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefV8Handler> GetFunctionHandler() = 0;
+
+ ///
+ /// Execute the function using the current V8 context. This method should only
+ /// be called from within the scope of a CefV8Handler or CefV8Accessor
+ /// callback, or in combination with calling Enter() and Exit() on a stored
+ /// CefV8Context reference. |object| is the receiver ('this' object) of the
+ /// function. If |object| is empty the current context's global object will be
+ /// used. |arguments| is the list of arguments that will be passed to the
+ /// function. Returns the function return value on success. Returns NULL if
+ /// this method is called incorrectly or an exception is thrown.
+ ///
+ /*--cef(optional_param=object)--*/
+ virtual CefRefPtr<CefV8Value> ExecuteFunction(
+ CefRefPtr<CefV8Value> object,
+ const CefV8ValueList& arguments) = 0;
+
+ ///
+ /// Execute the function using the specified V8 context. |object| is the
+ /// receiver ('this' object) of the function. If |object| is empty the
+ /// specified context's global object will be used. |arguments| is the list of
+ /// arguments that will be passed to the function. Returns the function return
+ /// value on success. Returns NULL if this method is called incorrectly or an
+ /// exception is thrown.
+ ///
+ /*--cef(optional_param=object)--*/
+ virtual CefRefPtr<CefV8Value> ExecuteFunctionWithContext(
+ CefRefPtr<CefV8Context> context,
+ CefRefPtr<CefV8Value> object,
+ const CefV8ValueList& arguments) = 0;
+
+ // PROMISE METHODS - These methods are only available on Promises.
+
+ ///
+ /// Resolve the Promise using the current V8 context. This method should only
+ /// be called from within the scope of a CefV8Handler or CefV8Accessor
+ /// callback, or in combination with calling Enter() and Exit() on a stored
+ /// CefV8Context reference. |arg| is the argument passed to the resolved
+ /// promise. Returns true on success. Returns false if this method is called
+ /// incorrectly or an exception is thrown.
+ ///
+ /*--cef(optional_param=arg)--*/
+ virtual bool ResolvePromise(CefRefPtr<CefV8Value> arg) = 0;
+
+ ///
+ /// Reject the Promise using the current V8 context. This method should only
+ /// be called from within the scope of a CefV8Handler or CefV8Accessor
+ /// callback, or in combination with calling Enter() and Exit() on a stored
+ /// CefV8Context reference. Returns true on success. Returns false if this
+ /// method is called incorrectly or an exception is thrown.
+ ///
+ /*--cef()--*/
+ virtual bool RejectPromise(const CefString& errorMsg) = 0;
+};
+
+///
+/// Class representing a V8 stack trace handle. V8 handles can only be accessed
+/// from the thread on which they are created. Valid threads for creating a V8
+/// handle include the render process main thread (TID_RENDERER) and WebWorker
+/// threads. A task runner for posting tasks on the associated thread can be
+/// retrieved via the CefV8Context::GetTaskRunner() method.
+///
+/*--cef(source=library)--*/
+class CefV8StackTrace : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Returns the stack trace for the currently active context. |frame_limit| is
+ /// the maximum number of frames that will be captured.
+ ///
+ /*--cef()--*/
+ static CefRefPtr<CefV8StackTrace> GetCurrent(int frame_limit);
+
+ ///
+ /// Returns true if the underlying handle is valid and it can be accessed on
+ /// the current thread. Do not call any other methods if this method returns
+ /// false.
+ ///
+ /*--cef()--*/
+ virtual bool IsValid() = 0;
+
+ ///
+ /// Returns the number of stack frames.
+ ///
+ /*--cef()--*/
+ virtual int GetFrameCount() = 0;
+
+ ///
+ /// Returns the stack frame at the specified 0-based index.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefV8StackFrame> GetFrame(int index) = 0;
+};
+
+///
+/// Class representing a V8 stack frame handle. V8 handles can only be accessed
+/// from the thread on which they are created. Valid threads for creating a V8
+/// handle include the render process main thread (TID_RENDERER) and WebWorker
+/// threads. A task runner for posting tasks on the associated thread can be
+/// retrieved via the CefV8Context::GetTaskRunner() method.
+///
+/*--cef(source=library,no_debugct_check)--*/
+class CefV8StackFrame : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Returns true if the underlying handle is valid and it can be accessed on
+ /// the current thread. Do not call any other methods if this method returns
+ /// false.
+ ///
+ /*--cef()--*/
+ virtual bool IsValid() = 0;
+
+ ///
+ /// Returns the name of the resource script that contains the function.
+ ///
+ /*--cef()--*/
+ virtual CefString GetScriptName() = 0;
+
+ ///
+ /// Returns the name of the resource script that contains the function or the
+ /// sourceURL value if the script name is undefined and its source ends with
+ /// a "//@ sourceURL=..." string.
+ ///
+ /*--cef()--*/
+ virtual CefString GetScriptNameOrSourceURL() = 0;
+
+ ///
+ /// Returns the name of the function.
+ ///
+ /*--cef()--*/
+ virtual CefString GetFunctionName() = 0;
+
+ ///
+ /// Returns the 1-based line number for the function call or 0 if unknown.
+ ///
+ /*--cef()--*/
+ virtual int GetLineNumber() = 0;
+
+ ///
+ /// Returns the 1-based column offset on the line for the function call or 0
+ /// if unknown.
+ ///
+ /*--cef()--*/
+ virtual int GetColumn() = 0;
+
+ ///
+ /// Returns true if the function was compiled using eval().
+ ///
+ /*--cef()--*/
+ virtual bool IsEval() = 0;
+
+ ///
+ /// Returns true if the function was called as a constructor via "new".
+ ///
+ /*--cef()--*/
+ virtual bool IsConstructor() = 0;
+};
+
+#endif // CEF_INCLUDE_CEF_V8_H_
diff --git a/include/cef_values.h b/include/cef_values.h
new file mode 100644
index 00000000..7e57113f
--- /dev/null
+++ b/include/cef_values.h
@@ -0,0 +1,750 @@
+// Copyright (c) 2012 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_VALUES_H_
+#define CEF_INCLUDE_CEF_VALUES_H_
+#pragma once
+
+#include <vector>
+#include "include/cef_base.h"
+
+class CefBinaryValue;
+class CefDictionaryValue;
+class CefListValue;
+
+typedef cef_value_type_t CefValueType;
+
+///
+/// Class that wraps other data value types. Complex types (binary, dictionary
+/// and list) will be referenced but not owned by this object. Can be used on
+/// any process and thread.
+///
+/*--cef(source=library)--*/
+class CefValue : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Creates a new object.
+ ///
+ /*--cef()--*/
+ static CefRefPtr<CefValue> Create();
+
+ ///
+ /// Returns true if the underlying data is valid. This will always be true for
+ /// simple types. For complex types (binary, dictionary and list) the
+ /// underlying data may become invalid if owned by another object (e.g. list
+ /// or dictionary) and that other object is then modified or destroyed. This
+ /// value object can be re-used by calling Set*() even if the underlying data
+ /// is invalid.
+ ///
+ /*--cef()--*/
+ virtual bool IsValid() = 0;
+
+ ///
+ /// Returns true if the underlying data is owned by another object.
+ ///
+ /*--cef()--*/
+ virtual bool IsOwned() = 0;
+
+ ///
+ /// Returns true if the underlying data is read-only. Some APIs may expose
+ /// read-only objects.
+ ///
+ /*--cef()--*/
+ virtual bool IsReadOnly() = 0;
+
+ ///
+ /// Returns true if this object and |that| object have the same underlying
+ /// data. If true modifications to this object will also affect |that| object
+ /// and vice-versa.
+ ///
+ /*--cef()--*/
+ virtual bool IsSame(CefRefPtr<CefValue> that) = 0;
+
+ ///
+ /// Returns true if this object and |that| object have an equivalent
+ /// underlying value but are not necessarily the same object.
+ ///
+ /*--cef()--*/
+ virtual bool IsEqual(CefRefPtr<CefValue> that) = 0;
+
+ ///
+ /// Returns a copy of this object. The underlying data will also be copied.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefValue> Copy() = 0;
+
+ ///
+ /// Returns the underlying value type.
+ ///
+ /*--cef(default_retval=VTYPE_INVALID)--*/
+ virtual CefValueType GetType() = 0;
+
+ ///
+ /// Returns the underlying value as type bool.
+ ///
+ /*--cef()--*/
+ virtual bool GetBool() = 0;
+
+ ///
+ /// Returns the underlying value as type int.
+ ///
+ /*--cef()--*/
+ virtual int GetInt() = 0;
+
+ ///
+ /// Returns the underlying value as type double.
+ ///
+ /*--cef()--*/
+ virtual double GetDouble() = 0;
+
+ ///
+ /// Returns the underlying value as type string.
+ ///
+ /*--cef()--*/
+ virtual CefString GetString() = 0;
+
+ ///
+ /// Returns the underlying value as type binary. The returned reference may
+ /// become invalid if the value is owned by another object or if ownership is
+ /// transferred to another object in the future. To maintain a reference to
+ /// the value after assigning ownership to a dictionary or list pass this
+ /// object to the SetValue() method instead of passing the returned reference
+ /// to SetBinary().
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefBinaryValue> GetBinary() = 0;
+
+ ///
+ /// Returns the underlying value as type dictionary. The returned reference
+ /// may become invalid if the value is owned by another object or if ownership
+ /// is transferred to another object in the future. To maintain a reference to
+ /// the value after assigning ownership to a dictionary or list pass this
+ /// object to the SetValue() method instead of passing the returned reference
+ /// to SetDictionary().
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefDictionaryValue> GetDictionary() = 0;
+
+ ///
+ /// Returns the underlying value as type list. The returned reference may
+ /// become invalid if the value is owned by another object or if ownership is
+ /// transferred to another object in the future. To maintain a reference to
+ /// the value after assigning ownership to a dictionary or list pass this
+ /// object to the SetValue() method instead of passing the returned reference
+ /// to SetList().
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefListValue> GetList() = 0;
+
+ ///
+ /// Sets the underlying value as type null. Returns true if the value was set
+ /// successfully.
+ ///
+ /*--cef()--*/
+ virtual bool SetNull() = 0;
+
+ ///
+ /// Sets the underlying value as type bool. Returns true if the value was set
+ /// successfully.
+ ///
+ /*--cef()--*/
+ virtual bool SetBool(bool value) = 0;
+
+ ///
+ /// Sets the underlying value as type int. Returns true if the value was set
+ /// successfully.
+ ///
+ /*--cef()--*/
+ virtual bool SetInt(int value) = 0;
+
+ ///
+ /// Sets the underlying value as type double. Returns true if the value was
+ /// set successfully.
+ ///
+ /*--cef()--*/
+ virtual bool SetDouble(double value) = 0;
+
+ ///
+ /// Sets the underlying value as type string. Returns true if the value was
+ /// set successfully.
+ ///
+ /*--cef(optional_param=value)--*/
+ virtual bool SetString(const CefString& value) = 0;
+
+ ///
+ /// Sets the underlying value as type binary. Returns true if the value was
+ /// set successfully. This object keeps a reference to |value| and ownership
+ /// of the underlying data remains unchanged.
+ ///
+ /*--cef()--*/
+ virtual bool SetBinary(CefRefPtr<CefBinaryValue> value) = 0;
+
+ ///
+ /// Sets the underlying value as type dict. Returns true if the value was set
+ /// successfully. This object keeps a reference to |value| and ownership of
+ /// the underlying data remains unchanged.
+ ///
+ /*--cef()--*/
+ virtual bool SetDictionary(CefRefPtr<CefDictionaryValue> value) = 0;
+
+ ///
+ /// Sets the underlying value as type list. Returns true if the value was set
+ /// successfully. This object keeps a reference to |value| and ownership of
+ /// the underlying data remains unchanged.
+ ///
+ /*--cef()--*/
+ virtual bool SetList(CefRefPtr<CefListValue> value) = 0;
+};
+
+///
+/// Class representing a binary value. Can be used on any process and thread.
+///
+/*--cef(source=library)--*/
+class CefBinaryValue : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Creates a new object that is not owned by any other object. The specified
+ /// |data| will be copied.
+ ///
+ /*--cef()--*/
+ static CefRefPtr<CefBinaryValue> Create(const void* data, size_t data_size);
+
+ ///
+ /// Returns true if this object is valid. This object may become invalid if
+ /// the underlying data is owned by another object (e.g. list or dictionary)
+ /// and that other object is then modified or destroyed. Do not call any other
+ /// methods if this method returns false.
+ ///
+ /*--cef()--*/
+ virtual bool IsValid() = 0;
+
+ ///
+ /// Returns true if this object is currently owned by another object.
+ ///
+ /*--cef()--*/
+ virtual bool IsOwned() = 0;
+
+ ///
+ /// Returns true if this object and |that| object have the same underlying
+ /// data.
+ ///
+ /*--cef()--*/
+ virtual bool IsSame(CefRefPtr<CefBinaryValue> that) = 0;
+
+ ///
+ /// Returns true if this object and |that| object have an equivalent
+ /// underlying value but are not necessarily the same object.
+ ///
+ /*--cef()--*/
+ virtual bool IsEqual(CefRefPtr<CefBinaryValue> that) = 0;
+
+ ///
+ /// Returns a copy of this object. The data in this object will also be
+ /// copied.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefBinaryValue> Copy() = 0;
+
+ ///
+ /// Returns the data size.
+ ///
+ /*--cef()--*/
+ virtual size_t GetSize() = 0;
+
+ ///
+ /// Read up to |buffer_size| number of bytes into |buffer|. Reading begins at
+ /// the specified byte |data_offset|. Returns the number of bytes read.
+ ///
+ /*--cef()--*/
+ virtual size_t GetData(void* buffer,
+ size_t buffer_size,
+ size_t data_offset) = 0;
+};
+
+///
+/// Class representing a dictionary value. Can be used on any process and
+/// thread.
+///
+/*--cef(source=library)--*/
+class CefDictionaryValue : public virtual CefBaseRefCounted {
+ public:
+ typedef std::vector<CefString> KeyList;
+
+ ///
+ /// Creates a new object that is not owned by any other object.
+ ///
+ /*--cef()--*/
+ static CefRefPtr<CefDictionaryValue> Create();
+
+ ///
+ /// Returns true if this object is valid. This object may become invalid if
+ /// the underlying data is owned by another object (e.g. list or dictionary)
+ /// and that other object is then modified or destroyed. Do not call any other
+ /// methods if this method returns false.
+ ///
+ /*--cef()--*/
+ virtual bool IsValid() = 0;
+
+ ///
+ /// Returns true if this object is currently owned by another object.
+ ///
+ /*--cef()--*/
+ virtual bool IsOwned() = 0;
+
+ ///
+ /// Returns true if the values of this object are read-only. Some APIs may
+ /// expose read-only objects.
+ ///
+ /*--cef()--*/
+ virtual bool IsReadOnly() = 0;
+
+ ///
+ /// Returns true if this object and |that| object have the same underlying
+ /// data. If true modifications to this object will also affect |that| object
+ /// and vice-versa.
+ ///
+ /*--cef()--*/
+ virtual bool IsSame(CefRefPtr<CefDictionaryValue> that) = 0;
+
+ ///
+ /// Returns true if this object and |that| object have an equivalent
+ /// underlying value but are not necessarily the same object.
+ ///
+ /*--cef()--*/
+ virtual bool IsEqual(CefRefPtr<CefDictionaryValue> that) = 0;
+
+ ///
+ /// Returns a writable copy of this object. If |exclude_empty_children| is
+ /// true any empty dictionaries or lists will be excluded from the copy.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefDictionaryValue> Copy(bool exclude_empty_children) = 0;
+
+ ///
+ /// Returns the number of values.
+ ///
+ /*--cef()--*/
+ virtual size_t GetSize() = 0;
+
+ ///
+ /// Removes all values. Returns true on success.
+ ///
+ /*--cef()--*/
+ virtual bool Clear() = 0;
+
+ ///
+ /// Returns true if the current dictionary has a value for the given key.
+ ///
+ /*--cef()--*/
+ virtual bool HasKey(const CefString& key) = 0;
+
+ ///
+ /// Reads all keys for this dictionary into the specified vector.
+ ///
+ /*--cef()--*/
+ virtual bool GetKeys(KeyList& keys) = 0;
+
+ ///
+ /// Removes the value at the specified key. Returns true is the value was
+ /// removed successfully.
+ ///
+ /*--cef()--*/
+ virtual bool Remove(const CefString& key) = 0;
+
+ ///
+ /// Returns the value type for the specified key.
+ ///
+ /*--cef(default_retval=VTYPE_INVALID)--*/
+ virtual CefValueType GetType(const CefString& key) = 0;
+
+ ///
+ /// Returns the value at the specified key. For simple types the returned
+ /// value will copy existing data and modifications to the value will not
+ /// modify this object. For complex types (binary, dictionary and list) the
+ /// returned value will reference existing data and modifications to the value
+ /// will modify this object.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefValue> GetValue(const CefString& key) = 0;
+
+ ///
+ /// Returns the value at the specified key as type bool.
+ ///
+ /*--cef()--*/
+ virtual bool GetBool(const CefString& key) = 0;
+
+ ///
+ /// Returns the value at the specified key as type int.
+ ///
+ /*--cef()--*/
+ virtual int GetInt(const CefString& key) = 0;
+
+ ///
+ /// Returns the value at the specified key as type double.
+ ///
+ /*--cef()--*/
+ virtual double GetDouble(const CefString& key) = 0;
+
+ ///
+ /// Returns the value at the specified key as type string.
+ ///
+ /*--cef()--*/
+ virtual CefString GetString(const CefString& key) = 0;
+
+ ///
+ /// Returns the value at the specified key as type binary. The returned
+ /// value will reference existing data.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefBinaryValue> GetBinary(const CefString& key) = 0;
+
+ ///
+ /// Returns the value at the specified key as type dictionary. The returned
+ /// value will reference existing data and modifications to the value will
+ /// modify this object.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefDictionaryValue> GetDictionary(const CefString& key) = 0;
+
+ ///
+ /// Returns the value at the specified key as type list. The returned value
+ /// will reference existing data and modifications to the value will modify
+ /// this object.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefListValue> GetList(const CefString& key) = 0;
+
+ ///
+ /// Sets the value at the specified key. Returns true if the value was set
+ /// successfully. If |value| represents simple data then the underlying data
+ /// will be copied and modifications to |value| will not modify this object.
+ /// If |value| represents complex data (binary, dictionary or list) then the
+ /// underlying data will be referenced and modifications to |value| will
+ /// modify this object.
+ ///
+ /*--cef()--*/
+ virtual bool SetValue(const CefString& key, CefRefPtr<CefValue> value) = 0;
+
+ ///
+ /// Sets the value at the specified key as type null. Returns true if the
+ /// value was set successfully.
+ ///
+ /*--cef()--*/
+ virtual bool SetNull(const CefString& key) = 0;
+
+ ///
+ /// Sets the value at the specified key as type bool. Returns true if the
+ /// value was set successfully.
+ ///
+ /*--cef()--*/
+ virtual bool SetBool(const CefString& key, bool value) = 0;
+
+ ///
+ /// Sets the value at the specified key as type int. Returns true if the
+ /// value was set successfully.
+ ///
+ /*--cef()--*/
+ virtual bool SetInt(const CefString& key, int value) = 0;
+
+ ///
+ /// Sets the value at the specified key as type double. Returns true if the
+ /// value was set successfully.
+ ///
+ /*--cef()--*/
+ virtual bool SetDouble(const CefString& key, double value) = 0;
+
+ ///
+ /// Sets the value at the specified key as type string. Returns true if the
+ /// value was set successfully.
+ ///
+ /*--cef(optional_param=value)--*/
+ virtual bool SetString(const CefString& key, const CefString& value) = 0;
+
+ ///
+ /// Sets the value at the specified key as type binary. Returns true if the
+ /// value was set successfully. If |value| is currently owned by another
+ /// object then the value will be copied and the |value| reference will not
+ /// change. Otherwise, ownership will be transferred to this object and the
+ /// |value| reference will be invalidated.
+ ///
+ /*--cef()--*/
+ virtual bool SetBinary(const CefString& key,
+ CefRefPtr<CefBinaryValue> value) = 0;
+
+ ///
+ /// Sets the value at the specified key as type dict. Returns true if the
+ /// value was set successfully. If |value| is currently owned by another
+ /// object then the value will be copied and the |value| reference will not
+ /// change. Otherwise, ownership will be transferred to this object and the
+ /// |value| reference will be invalidated.
+ ///
+ /*--cef()--*/
+ virtual bool SetDictionary(const CefString& key,
+ CefRefPtr<CefDictionaryValue> value) = 0;
+
+ ///
+ /// Sets the value at the specified key as type list. Returns true if the
+ /// value was set successfully. If |value| is currently owned by another
+ /// object then the value will be copied and the |value| reference will not
+ /// change. Otherwise, ownership will be transferred to this object and the
+ /// |value| reference will be invalidated.
+ ///
+ /*--cef()--*/
+ virtual bool SetList(const CefString& key, CefRefPtr<CefListValue> value) = 0;
+};
+
+///
+/// Class representing a list value. Can be used on any process and thread.
+///
+/*--cef(source=library)--*/
+class CefListValue : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Creates a new object that is not owned by any other object.
+ ///
+ /*--cef()--*/
+ static CefRefPtr<CefListValue> Create();
+
+ ///
+ /// Returns true if this object is valid. This object may become invalid if
+ /// the underlying data is owned by another object (e.g. list or dictionary)
+ /// and that other object is then modified or destroyed. Do not call any other
+ /// methods if this method returns false.
+ ///
+ /*--cef()--*/
+ virtual bool IsValid() = 0;
+
+ ///
+ /// Returns true if this object is currently owned by another object.
+ ///
+ /*--cef()--*/
+ virtual bool IsOwned() = 0;
+
+ ///
+ /// Returns true if the values of this object are read-only. Some APIs may
+ /// expose read-only objects.
+ ///
+ /*--cef()--*/
+ virtual bool IsReadOnly() = 0;
+
+ ///
+ /// Returns true if this object and |that| object have the same underlying
+ /// data. If true modifications to this object will also affect |that| object
+ /// and vice-versa.
+ ///
+ /*--cef()--*/
+ virtual bool IsSame(CefRefPtr<CefListValue> that) = 0;
+
+ ///
+ /// Returns true if this object and |that| object have an equivalent
+ /// underlying value but are not necessarily the same object.
+ ///
+ /*--cef()--*/
+ virtual bool IsEqual(CefRefPtr<CefListValue> that) = 0;
+
+ ///
+ /// Returns a writable copy of this object.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefListValue> Copy() = 0;
+
+ ///
+ /// Sets the number of values. If the number of values is expanded all
+ /// new value slots will default to type null. Returns true on success.
+ ///
+ /*--cef()--*/
+ virtual bool SetSize(size_t size) = 0;
+
+ ///
+ /// Returns the number of values.
+ ///
+ /*--cef()--*/
+ virtual size_t GetSize() = 0;
+
+ ///
+ /// Removes all values. Returns true on success.
+ ///
+ /*--cef()--*/
+ virtual bool Clear() = 0;
+
+ ///
+ /// Removes the value at the specified index.
+ ///
+ /*--cef()--*/
+ virtual bool Remove(size_t index) = 0;
+
+ ///
+ /// Returns the value type at the specified index.
+ ///
+ /*--cef(default_retval=VTYPE_INVALID)--*/
+ virtual CefValueType GetType(size_t index) = 0;
+
+ ///
+ /// Returns the value at the specified index. For simple types the returned
+ /// value will copy existing data and modifications to the value will not
+ /// modify this object. For complex types (binary, dictionary and list) the
+ /// returned value will reference existing data and modifications to the value
+ /// will modify this object.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefValue> GetValue(size_t index) = 0;
+
+ ///
+ /// Returns the value at the specified index as type bool.
+ ///
+ /*--cef()--*/
+ virtual bool GetBool(size_t index) = 0;
+
+ ///
+ /// Returns the value at the specified index as type int.
+ ///
+ /*--cef()--*/
+ virtual int GetInt(size_t index) = 0;
+
+ ///
+ /// Returns the value at the specified index as type double.
+ ///
+ /*--cef()--*/
+ virtual double GetDouble(size_t index) = 0;
+
+ ///
+ /// Returns the value at the specified index as type string.
+ ///
+ /*--cef()--*/
+ virtual CefString GetString(size_t index) = 0;
+
+ ///
+ /// Returns the value at the specified index as type binary. The returned
+ /// value will reference existing data.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefBinaryValue> GetBinary(size_t index) = 0;
+
+ ///
+ /// Returns the value at the specified index as type dictionary. The returned
+ /// value will reference existing data and modifications to the value will
+ /// modify this object.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefDictionaryValue> GetDictionary(size_t index) = 0;
+
+ ///
+ /// Returns the value at the specified index as type list. The returned
+ /// value will reference existing data and modifications to the value will
+ /// modify this object.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefListValue> GetList(size_t index) = 0;
+
+ ///
+ /// Sets the value at the specified index. Returns true if the value was set
+ /// successfully. If |value| represents simple data then the underlying data
+ /// will be copied and modifications to |value| will not modify this object.
+ /// If |value| represents complex data (binary, dictionary or list) then the
+ /// underlying data will be referenced and modifications to |value| will
+ /// modify this object.
+ ///
+ /*--cef()--*/
+ virtual bool SetValue(size_t index, CefRefPtr<CefValue> value) = 0;
+
+ ///
+ /// Sets the value at the specified index as type null. Returns true if the
+ /// value was set successfully.
+ ///
+ /*--cef()--*/
+ virtual bool SetNull(size_t index) = 0;
+
+ ///
+ /// Sets the value at the specified index as type bool. Returns true if the
+ /// value was set successfully.
+ ///
+ /*--cef()--*/
+ virtual bool SetBool(size_t index, bool value) = 0;
+
+ ///
+ /// Sets the value at the specified index as type int. Returns true if the
+ /// value was set successfully.
+ ///
+ /*--cef()--*/
+ virtual bool SetInt(size_t index, int value) = 0;
+
+ ///
+ /// Sets the value at the specified index as type double. Returns true if the
+ /// value was set successfully.
+ ///
+ /*--cef()--*/
+ virtual bool SetDouble(size_t index, double value) = 0;
+
+ ///
+ /// Sets the value at the specified index as type string. Returns true if the
+ /// value was set successfully.
+ ///
+ /*--cef(optional_param=value)--*/
+ virtual bool SetString(size_t index, const CefString& value) = 0;
+
+ ///
+ /// Sets the value at the specified index as type binary. Returns true if the
+ /// value was set successfully. If |value| is currently owned by another
+ /// object then the value will be copied and the |value| reference will not
+ /// change. Otherwise, ownership will be transferred to this object and the
+ /// |value| reference will be invalidated.
+ ///
+ /*--cef()--*/
+ virtual bool SetBinary(size_t index, CefRefPtr<CefBinaryValue> value) = 0;
+
+ ///
+ /// Sets the value at the specified index as type dict. Returns true if the
+ /// value was set successfully. If |value| is currently owned by another
+ /// object then the value will be copied and the |value| reference will not
+ /// change. Otherwise, ownership will be transferred to this object and the
+ /// |value| reference will be invalidated.
+ ///
+ /*--cef()--*/
+ virtual bool SetDictionary(size_t index,
+ CefRefPtr<CefDictionaryValue> value) = 0;
+
+ ///
+ /// Sets the value at the specified index as type list. Returns true if the
+ /// value was set successfully. If |value| is currently owned by another
+ /// object then the value will be copied and the |value| reference will not
+ /// change. Otherwise, ownership will be transferred to this object and the
+ /// |value| reference will be invalidated.
+ ///
+ /*--cef()--*/
+ virtual bool SetList(size_t index, CefRefPtr<CefListValue> value) = 0;
+};
+
+#endif // CEF_INCLUDE_CEF_VALUES_H_
diff --git a/include/cef_waitable_event.h b/include/cef_waitable_event.h
new file mode 100644
index 00000000..96b46955
--- /dev/null
+++ b/include/cef_waitable_event.h
@@ -0,0 +1,109 @@
+// Copyright (c) 2016 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_WAITABLE_EVENT_H_
+#define CEF_INCLUDE_CEF_WAITABLE_EVENT_H_
+#pragma once
+
+#include "include/cef_base.h"
+
+///
+/// WaitableEvent is a thread synchronization tool that allows one thread to
+/// wait for another thread to finish some work. This is equivalent to using a
+/// Lock+ConditionVariable to protect a simple boolean value. However, using
+/// WaitableEvent in conjunction with a Lock to wait for a more complex state
+/// change (e.g., for an item to be added to a queue) is not recommended. In
+/// that case consider using a ConditionVariable instead of a WaitableEvent. It
+/// is safe to create and/or signal a WaitableEvent from any thread. Blocking on
+/// a WaitableEvent by calling the *Wait() methods is not allowed on the browser
+/// process UI or IO threads.
+///
+/*--cef(source=library)--*/
+class CefWaitableEvent : public CefBaseRefCounted {
+ public:
+ ///
+ /// Create a new waitable event. If |automatic_reset| is true then the event
+ /// state is automatically reset to un-signaled after a single waiting thread
+ /// has been released; otherwise, the state remains signaled until Reset() is
+ /// called manually. If |initially_signaled| is true then the event will start
+ /// in the signaled state.
+ ///
+ /*--cef()--*/
+ static CefRefPtr<CefWaitableEvent> CreateWaitableEvent(
+ bool automatic_reset,
+ bool initially_signaled);
+
+ ///
+ /// Put the event in the un-signaled state.
+ ///
+ /*--cef()--*/
+ virtual void Reset() = 0;
+
+ ///
+ /// Put the event in the signaled state. This causes any thread blocked on
+ /// Wait to be woken up.
+ ///
+ /*--cef()--*/
+ virtual void Signal() = 0;
+
+ ///
+ /// Returns true if the event is in the signaled state, else false. If the
+ /// event was created with |automatic_reset| set to true then calling this
+ /// method will also cause a reset.
+ ///
+ /*--cef()--*/
+ virtual bool IsSignaled() = 0;
+
+ ///
+ /// Wait indefinitely for the event to be signaled. This method will not
+ /// return until after the call to Signal() has completed. This method cannot
+ /// be called on the browser process UI or IO threads.
+ ///
+ /*--cef()--*/
+ virtual void Wait() = 0;
+
+ ///
+ /// Wait up to |max_ms| milliseconds for the event to be signaled. Returns
+ /// true if the event was signaled. A return value of false does not
+ /// necessarily mean that |max_ms| was exceeded. This method will not return
+ /// until after the call to Signal() has completed. This method cannot be
+ /// called on the browser process UI or IO threads.
+ ///
+ /*--cef()--*/
+ virtual bool TimedWait(int64 max_ms) = 0;
+};
+
+#endif // CEF_INCLUDE_CEF_WAITABLE_EVENT_H_
diff --git a/include/cef_x509_certificate.h b/include/cef_x509_certificate.h
new file mode 100644
index 00000000..45432ffd
--- /dev/null
+++ b/include/cef_x509_certificate.h
@@ -0,0 +1,188 @@
+// Copyright (c) 2016 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_X509_CERTIFICATE_H_
+#define CEF_INCLUDE_CEF_X509_CERTIFICATE_H_
+#pragma once
+
+#include <vector>
+
+#include "include/cef_base.h"
+#include "include/cef_values.h"
+
+///
+/// Class representing the issuer or subject field of an X.509 certificate.
+///
+/*--cef(source=library)--*/
+class CefX509CertPrincipal : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Returns a name that can be used to represent the issuer. It tries in this
+ /// order: Common Name (CN), Organization Name (O) and Organizational Unit
+ /// Name (OU) and returns the first non-empty one found.
+ ///
+ /*--cef()--*/
+ virtual CefString GetDisplayName() = 0;
+
+ ///
+ /// Returns the common name.
+ ///
+ /*--cef()--*/
+ virtual CefString GetCommonName() = 0;
+
+ ///
+ /// Returns the locality name.
+ ///
+ /*--cef()--*/
+ virtual CefString GetLocalityName() = 0;
+
+ ///
+ /// Returns the state or province name.
+ ///
+ /*--cef()--*/
+ virtual CefString GetStateOrProvinceName() = 0;
+
+ ///
+ /// Returns the country name.
+ ///
+ /*--cef()--*/
+ virtual CefString GetCountryName() = 0;
+
+ ///
+ /// Retrieve the list of street addresses.
+ ///
+ /*--cef()--*/
+ virtual void GetStreetAddresses(std::vector<CefString>& addresses) = 0;
+
+ ///
+ /// Retrieve the list of organization names.
+ ///
+ /*--cef()--*/
+ virtual void GetOrganizationNames(std::vector<CefString>& names) = 0;
+
+ ///
+ /// Retrieve the list of organization unit names.
+ ///
+ /*--cef()--*/
+ virtual void GetOrganizationUnitNames(std::vector<CefString>& names) = 0;
+
+ ///
+ /// Retrieve the list of domain components.
+ ///
+ /*--cef()--*/
+ virtual void GetDomainComponents(std::vector<CefString>& components) = 0;
+};
+
+///
+/// Class representing a X.509 certificate.
+///
+/*--cef(source=library)--*/
+class CefX509Certificate : public virtual CefBaseRefCounted {
+ public:
+ typedef std::vector<CefRefPtr<CefBinaryValue>> IssuerChainBinaryList;
+
+ ///
+ /// Returns the subject of the X.509 certificate. For HTTPS server
+ /// certificates this represents the web server. The common name of the
+ /// subject should match the host name of the web server.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefX509CertPrincipal> GetSubject() = 0;
+
+ ///
+ /// Returns the issuer of the X.509 certificate.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefX509CertPrincipal> GetIssuer() = 0;
+
+ ///
+ /// Returns the DER encoded serial number for the X.509 certificate. The value
+ /// possibly includes a leading 00 byte.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefBinaryValue> GetSerialNumber() = 0;
+
+ ///
+ /// Returns the date before which the X.509 certificate is invalid.
+ /// CefBaseTime.GetTimeT() will return 0 if no date was specified.
+ ///
+ /*--cef()--*/
+ virtual CefBaseTime GetValidStart() = 0;
+
+ ///
+ /// Returns the date after which the X.509 certificate is invalid.
+ /// CefBaseTime.GetTimeT() will return 0 if no date was specified.
+ ///
+ /*--cef()--*/
+ virtual CefBaseTime GetValidExpiry() = 0;
+
+ ///
+ /// Returns the DER encoded data for the X.509 certificate.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefBinaryValue> GetDEREncoded() = 0;
+
+ ///
+ /// Returns the PEM encoded data for the X.509 certificate.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefBinaryValue> GetPEMEncoded() = 0;
+
+ ///
+ /// Returns the number of certificates in the issuer chain.
+ /// If 0, the certificate is self-signed.
+ ///
+ /*--cef()--*/
+ virtual size_t GetIssuerChainSize() = 0;
+
+ ///
+ /// Returns the DER encoded data for the certificate issuer chain.
+ /// If we failed to encode a certificate in the chain it is still
+ /// present in the array but is an empty string.
+ ///
+ /*--cef(count_func=chain:GetIssuerChainSize)--*/
+ virtual void GetDEREncodedIssuerChain(IssuerChainBinaryList& chain) = 0;
+
+ ///
+ /// Returns the PEM encoded data for the certificate issuer chain.
+ /// If we failed to encode a certificate in the chain it is still
+ /// present in the array but is an empty string.
+ ///
+ /*--cef(count_func=chain:GetIssuerChainSize)--*/
+ virtual void GetPEMEncodedIssuerChain(IssuerChainBinaryList& chain) = 0;
+};
+
+#endif // CEF_INCLUDE_CEF_X509_CERTIFICATE_H_
diff --git a/include/cef_xml_reader.h b/include/cef_xml_reader.h
new file mode 100644
index 00000000..055d522d
--- /dev/null
+++ b/include/cef_xml_reader.h
@@ -0,0 +1,266 @@
+// Copyright (c) 2012 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_XML_READER_H_
+#define CEF_INCLUDE_CEF_XML_READER_H_
+#pragma once
+
+#include "include/cef_base.h"
+#include "include/cef_stream.h"
+
+///
+/// Class that supports the reading of XML data via the libxml streaming API.
+/// The methods of this class should only be called on the thread that creates
+/// the object.
+///
+/*--cef(source=library)--*/
+class CefXmlReader : public virtual CefBaseRefCounted {
+ public:
+ typedef cef_xml_encoding_type_t EncodingType;
+ typedef cef_xml_node_type_t NodeType;
+
+ ///
+ /// Create a new CefXmlReader object. The returned object's methods can only
+ /// be called from the thread that created the object.
+ ///
+ /*--cef()--*/
+ static CefRefPtr<CefXmlReader> Create(CefRefPtr<CefStreamReader> stream,
+ EncodingType encodingType,
+ const CefString& URI);
+
+ ///
+ /// Moves the cursor to the next node in the document. This method must be
+ /// called at least once to set the current cursor position. Returns true if
+ /// the cursor position was set successfully.
+ ///
+ /*--cef()--*/
+ virtual bool MoveToNextNode() = 0;
+
+ ///
+ /// Close the document. This should be called directly to ensure that cleanup
+ /// occurs on the correct thread.
+ ///
+ /*--cef()--*/
+ virtual bool Close() = 0;
+
+ ///
+ /// Returns true if an error has been reported by the XML parser.
+ ///
+ /*--cef()--*/
+ virtual bool HasError() = 0;
+
+ ///
+ /// Returns the error string.
+ ///
+ /*--cef()--*/
+ virtual CefString GetError() = 0;
+
+ /// The below methods retrieve data for the node at the current cursor
+ /// position.
+
+ ///
+ /// Returns the node type.
+ ///
+ /*--cef(default_retval=XML_NODE_UNSUPPORTED)--*/
+ virtual NodeType GetType() = 0;
+
+ ///
+ /// Returns the node depth. Depth starts at 0 for the root node.
+ ///
+ /*--cef()--*/
+ virtual int GetDepth() = 0;
+
+ ///
+ /// Returns the local name. See
+ /// http://www.w3.org/TR/REC-xml-names/#NT-LocalPart for additional details.
+ ///
+ /*--cef()--*/
+ virtual CefString GetLocalName() = 0;
+
+ ///
+ /// Returns the namespace prefix. See http://www.w3.org/TR/REC-xml-names/ for
+ /// additional details.
+ ///
+ /*--cef()--*/
+ virtual CefString GetPrefix() = 0;
+
+ ///
+ /// Returns the qualified name, equal to (Prefix:)LocalName. See
+ /// http://www.w3.org/TR/REC-xml-names/#ns-qualnames for additional details.
+ ///
+ /*--cef()--*/
+ virtual CefString GetQualifiedName() = 0;
+
+ ///
+ /// Returns the URI defining the namespace associated with the node. See
+ /// http://www.w3.org/TR/REC-xml-names/ for additional details.
+ ///
+ /*--cef()--*/
+ virtual CefString GetNamespaceURI() = 0;
+
+ ///
+ /// Returns the base URI of the node. See http://www.w3.org/TR/xmlbase/ for
+ /// additional details.
+ ///
+ /*--cef()--*/
+ virtual CefString GetBaseURI() = 0;
+
+ ///
+ /// Returns the xml:lang scope within which the node resides. See
+ /// http://www.w3.org/TR/REC-xml/#sec-lang-tag for additional details.
+ ///
+ /*--cef()--*/
+ virtual CefString GetXmlLang() = 0;
+
+ ///
+ /// Returns true if the node represents an empty element. "<a/>" is considered
+ /// empty but "<a></a>" is not.
+ ///
+ /*--cef()--*/
+ virtual bool IsEmptyElement() = 0;
+
+ ///
+ /// Returns true if the node has a text value.
+ ///
+ /*--cef()--*/
+ virtual bool HasValue() = 0;
+
+ ///
+ /// Returns the text value.
+ ///
+ /*--cef()--*/
+ virtual CefString GetValue() = 0;
+
+ ///
+ /// Returns true if the node has attributes.
+ ///
+ /*--cef()--*/
+ virtual bool HasAttributes() = 0;
+
+ ///
+ /// Returns the number of attributes.
+ ///
+ /*--cef()--*/
+ virtual size_t GetAttributeCount() = 0;
+
+ ///
+ /// Returns the value of the attribute at the specified 0-based index.
+ ///
+ /*--cef(capi_name=get_attribute_byindex,index_param=index)--*/
+ virtual CefString GetAttribute(int index) = 0;
+
+ ///
+ /// Returns the value of the attribute with the specified qualified name.
+ ///
+ /*--cef(capi_name=get_attribute_byqname)--*/
+ virtual CefString GetAttribute(const CefString& qualifiedName) = 0;
+
+ ///
+ /// Returns the value of the attribute with the specified local name and
+ /// namespace URI.
+ ///
+ /*--cef(capi_name=get_attribute_bylname)--*/
+ virtual CefString GetAttribute(const CefString& localName,
+ const CefString& namespaceURI) = 0;
+
+ ///
+ /// Returns an XML representation of the current node's children.
+ ///
+ /*--cef()--*/
+ virtual CefString GetInnerXml() = 0;
+
+ ///
+ /// Returns an XML representation of the current node including its children.
+ ///
+ /*--cef()--*/
+ virtual CefString GetOuterXml() = 0;
+
+ ///
+ /// Returns the line number for the current node.
+ ///
+ /*--cef()--*/
+ virtual int GetLineNumber() = 0;
+
+ /// Attribute nodes are not traversed by default. The below methods can be
+ /// used to move the cursor to an attribute node. MoveToCarryingElement() can
+ /// be called afterwards to return the cursor to the carrying element. The
+ /// depth of an attribute node will be 1 + the depth of the carrying element.
+
+ ///
+ /// Moves the cursor to the attribute at the specified 0-based index. Returns
+ /// true if the cursor position was set successfully.
+ ///
+ /*--cef(capi_name=move_to_attribute_byindex,index_param=index)--*/
+ virtual bool MoveToAttribute(int index) = 0;
+
+ ///
+ /// Moves the cursor to the attribute with the specified qualified name.
+ /// Returns true if the cursor position was set successfully.
+ ///
+ /*--cef(capi_name=move_to_attribute_byqname)--*/
+ virtual bool MoveToAttribute(const CefString& qualifiedName) = 0;
+
+ ///
+ /// Moves the cursor to the attribute with the specified local name and
+ /// namespace URI. Returns true if the cursor position was set successfully.
+ ///
+ /*--cef(capi_name=move_to_attribute_bylname)--*/
+ virtual bool MoveToAttribute(const CefString& localName,
+ const CefString& namespaceURI) = 0;
+
+ ///
+ /// Moves the cursor to the first attribute in the current element. Returns
+ /// true if the cursor position was set successfully.
+ ///
+ /*--cef()--*/
+ virtual bool MoveToFirstAttribute() = 0;
+
+ ///
+ /// Moves the cursor to the next attribute in the current element. Returns
+ /// true if the cursor position was set successfully.
+ ///
+ /*--cef()--*/
+ virtual bool MoveToNextAttribute() = 0;
+
+ ///
+ /// Moves the cursor back to the carrying element. Returns true if the cursor
+ /// position was set successfully.
+ ///
+ /*--cef()--*/
+ virtual bool MoveToCarryingElement() = 0;
+};
+
+#endif // CEF_INCLUDE_CEF_XML_READER_H_
diff --git a/include/cef_zip_reader.h b/include/cef_zip_reader.h
new file mode 100644
index 00000000..79bc82e9
--- /dev/null
+++ b/include/cef_zip_reader.h
@@ -0,0 +1,140 @@
+// Copyright (c) 2012 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_CEF_ZIP_READER_H_
+#define CEF_INCLUDE_CEF_ZIP_READER_H_
+
+#include "include/cef_base.h"
+#include "include/cef_stream.h"
+
+///
+/// Class that supports the reading of zip archives via the zlib unzip API.
+/// The methods of this class should only be called on the thread that creates
+/// the object.
+///
+/*--cef(source=library)--*/
+class CefZipReader : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Create a new CefZipReader object. The returned object's methods can only
+ /// be called from the thread that created the object.
+ ///
+ /*--cef()--*/
+ static CefRefPtr<CefZipReader> Create(CefRefPtr<CefStreamReader> stream);
+
+ ///
+ /// Moves the cursor to the first file in the archive. Returns true if the
+ /// cursor position was set successfully.
+ ///
+ /*--cef()--*/
+ virtual bool MoveToFirstFile() = 0;
+
+ ///
+ /// Moves the cursor to the next file in the archive. Returns true if the
+ /// cursor position was set successfully.
+ ///
+ /*--cef()--*/
+ virtual bool MoveToNextFile() = 0;
+
+ ///
+ /// Moves the cursor to the specified file in the archive. If |caseSensitive|
+ /// is true then the search will be case sensitive. Returns true if the cursor
+ /// position was set successfully.
+ ///
+ /*--cef()--*/
+ virtual bool MoveToFile(const CefString& fileName, bool caseSensitive) = 0;
+
+ ///
+ /// Closes the archive. This should be called directly to ensure that cleanup
+ /// occurs on the correct thread.
+ ///
+ /*--cef()--*/
+ virtual bool Close() = 0;
+
+ /// The below methods act on the file at the current cursor position.
+
+ ///
+ /// Returns the name of the file.
+ ///
+ /*--cef()--*/
+ virtual CefString GetFileName() = 0;
+
+ ///
+ /// Returns the uncompressed size of the file.
+ ///
+ /*--cef()--*/
+ virtual int64 GetFileSize() = 0;
+
+ ///
+ /// Returns the last modified timestamp for the file.
+ ///
+ /*--cef()--*/
+ virtual CefBaseTime GetFileLastModified() = 0;
+
+ ///
+ /// Opens the file for reading of uncompressed data. A read password may
+ /// optionally be specified.
+ ///
+ /*--cef(optional_param=password)--*/
+ virtual bool OpenFile(const CefString& password) = 0;
+
+ ///
+ /// Closes the file.
+ ///
+ /*--cef()--*/
+ virtual bool CloseFile() = 0;
+
+ ///
+ /// Read uncompressed file contents into the specified buffer. Returns < 0 if
+ /// an error occurred, 0 if at the end of file, or the number of bytes read.
+ ///
+ /*--cef()--*/
+ virtual int ReadFile(void* buffer, size_t bufferSize) = 0;
+
+ ///
+ /// Returns the current offset in the uncompressed file contents.
+ ///
+ /*--cef()--*/
+ virtual int64 Tell() = 0;
+
+ ///
+ /// Returns true if at end of the file contents.
+ ///
+ /*--cef()--*/
+ virtual bool Eof() = 0;
+};
+
+#endif // CEF_INCLUDE_CEF_ZIP_READER_H_
diff --git a/include/internal/cef_app_win.h b/include/internal/cef_app_win.h
new file mode 100644
index 00000000..3e8a3eeb
--- /dev/null
+++ b/include/internal/cef_app_win.h
@@ -0,0 +1,107 @@
+// Copyright (c) 2022 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CEF_INCLUDE_INTERNAL_CEF_APP_WIN_H_
+#define CEF_INCLUDE_INTERNAL_CEF_APP_WIN_H_
+#pragma once
+
+#include "include/base/cef_build.h"
+
+#if defined(OS_WIN)
+
+#if defined(ARCH_CPU_32_BITS)
+#include <windows.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(ARCH_CPU_32_BITS)
+typedef int(APIENTRY* wWinMainPtr)(HINSTANCE hInstance,
+ HINSTANCE hPrevInstance,
+ LPWSTR lpCmdLine,
+ int nCmdShow);
+typedef int (*mainPtr)(int argc, char* argv[]);
+
+///
+/// Run the main thread on 32-bit Windows using a fiber with the preferred 4MiB
+/// stack size. This function must be called at the top of the executable entry
+/// point function (`main()` or `wWinMain()`). It is used in combination with
+/// the initial stack size of 0.5MiB configured via the `/STACK:0x80000` linker
+/// flag on executable targets. This saves significant memory on threads (like
+/// those in the Windows thread pool, and others) whose stack size can only be
+/// controlled via the linker flag.
+///
+/// CEF's main thread needs at least a 1.5 MiB stack size in order to avoid
+/// stack overflow crashes. However, if this is set in the PE file then other
+/// threads get this size as well, leading to address-space exhaustion in 32-bit
+/// CEF. This function uses fibers to switch the main thread to a 4 MiB stack
+/// (roughly the same effective size as the 64-bit build's 8 MiB stack) before
+/// running any other code.
+///
+/// Choose the function variant that matches the entry point function type used
+/// by the executable. Reusing the entry point minimizes confusion when
+/// examining call stacks in crash reports.
+///
+/// If this function is already running on the fiber it will return -1
+/// immediately, meaning that execution should proceed with the remainder of the
+/// entry point function. Otherwise, this function will block until the entry
+/// point function has completed execution on the fiber and then return a result
+/// >= 0, meaning that the entry point function should return the result
+/// immediately without proceeding with execution.
+///
+CEF_EXPORT int cef_run_winmain_with_preferred_stack_size(wWinMainPtr wWinMain,
+ HINSTANCE hInstance,
+ LPWSTR lpCmdLine,
+ int nCmdShow);
+CEF_EXPORT int cef_run_main_with_preferred_stack_size(mainPtr main,
+ int argc,
+ char* argv[]);
+#endif // defined(ARCH_CPU_32_BITS)
+
+///
+/// Call during process startup to enable High-DPI support on Windows 7 or
+/// newer. Older versions of Windows should be left DPI-unaware because they do
+/// not support DirectWrite and GDI fonts are kerned very badly.
+///
+CEF_EXPORT void cef_enable_highdpi_support(void);
+
+///
+/// Set to true (1) before calling Windows APIs like TrackPopupMenu that enter a
+/// modal message loop. Set to false (0) after exiting the modal message loop.
+///
+CEF_EXPORT void cef_set_osmodal_loop(int osModalLoop);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // defined(OS_WIN)
+#endif // CEF_INCLUDE_INTERNAL_CEF_APP_WIN_H_
diff --git a/include/internal/cef_export.h b/include/internal/cef_export.h
new file mode 100644
index 00000000..1915f5e5
--- /dev/null
+++ b/include/internal/cef_export.h
@@ -0,0 +1,59 @@
+// Copyright (c) 2009 The Chromium Embedded Framework Authors. All rights
+// reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CEF_INCLUDE_INTERNAL_CEF_EXPORT_H_
+#define CEF_INCLUDE_INTERNAL_CEF_EXPORT_H_
+#pragma once
+
+#include "include/base/cef_build.h"
+
+#if defined(COMPILER_MSVC)
+
+#ifdef BUILDING_CEF_SHARED
+#define CEF_EXPORT __declspec(dllexport)
+#elif USING_CEF_SHARED
+#define CEF_EXPORT __declspec(dllimport)
+#else
+#define CEF_EXPORT
+#endif
+
+#elif defined(COMPILER_GCC)
+
+#define CEF_EXPORT __attribute__((visibility("default")))
+
+#endif // COMPILER_GCC
+
+#if defined(OS_WIN)
+#define CEF_CALLBACK __stdcall
+#else
+#define CEF_CALLBACK
+#endif
+
+#endif // CEF_INCLUDE_INTERNAL_CEF_EXPORT_H_
diff --git a/include/internal/cef_linux.h b/include/internal/cef_linux.h
new file mode 100644
index 00000000..cebd7f6c
--- /dev/null
+++ b/include/internal/cef_linux.h
@@ -0,0 +1,116 @@
+// Copyright (c) 2010 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CEF_INCLUDE_INTERNAL_CEF_LINUX_H_
+#define CEF_INCLUDE_INTERNAL_CEF_LINUX_H_
+#pragma once
+
+#include "include/internal/cef_types_linux.h"
+#include "include/internal/cef_types_wrappers.h"
+
+// Handle types.
+#define CefCursorHandle cef_cursor_handle_t
+#define CefEventHandle cef_event_handle_t
+#define CefWindowHandle cef_window_handle_t
+
+///
+/// Class representing CefExecuteProcess arguments.
+///
+class CefMainArgs : public cef_main_args_t {
+ public:
+ CefMainArgs() : cef_main_args_t{} {}
+ CefMainArgs(const cef_main_args_t& r) : cef_main_args_t(r) {}
+ CefMainArgs(int argc_arg, char** argv_arg)
+ : cef_main_args_t{argc_arg, argv_arg} {}
+};
+
+struct CefWindowInfoTraits {
+ typedef cef_window_info_t struct_type;
+
+ static inline void init(struct_type* s) {}
+
+ static inline void clear(struct_type* s) {
+ cef_string_clear(&s->window_name);
+ }
+
+ static inline void set(const struct_type* src,
+ struct_type* target,
+ bool copy) {
+ cef_string_set(src->window_name.str, src->window_name.length,
+ &target->window_name, copy);
+ target->bounds = src->bounds;
+ target->parent_window = src->parent_window;
+ target->windowless_rendering_enabled = src->windowless_rendering_enabled;
+ target->shared_texture_enabled = src->shared_texture_enabled;
+ target->external_begin_frame_enabled = src->external_begin_frame_enabled;
+ target->window = src->window;
+ }
+};
+
+///
+/// Class representing window information.
+///
+class CefWindowInfo : public CefStructBase<CefWindowInfoTraits> {
+ public:
+ typedef CefStructBase<CefWindowInfoTraits> parent;
+
+ CefWindowInfo() : parent() {}
+ explicit CefWindowInfo(const cef_window_info_t& r) : parent(r) {}
+ explicit CefWindowInfo(const CefWindowInfo& r) : parent(r) {}
+
+ CefWindowInfo& operator=(const CefWindowInfo&) = default;
+ CefWindowInfo& operator=(CefWindowInfo&&) = default;
+
+ ///
+ /// Create the browser as a child window.
+ ///
+ void SetAsChild(CefWindowHandle parent, const CefRect& bounds) {
+ parent_window = parent;
+ this->bounds = bounds;
+ }
+
+ ///
+ /// Create the browser using windowless (off-screen) rendering. No window
+ /// will be created for the browser and all rendering will occur via the
+ /// CefRenderHandler interface. The |parent| value will be used to identify
+ /// monitor info and to act as the parent window for dialogs, context menus,
+ /// etc. If |parent| is not provided then the main screen monitor will be used
+ /// and some functionality that requires a parent window may not function
+ /// correctly. In order to create windowless browsers the
+ /// CefSettings.windowless_rendering_enabled value must be set to true.
+ /// Transparent painting is enabled by default but can be disabled by setting
+ /// CefBrowserSettings.background_color to an opaque value.
+ ///
+ void SetAsWindowless(CefWindowHandle parent) {
+ windowless_rendering_enabled = true;
+ parent_window = parent;
+ }
+};
+
+#endif // CEF_INCLUDE_INTERNAL_CEF_LINUX_H_
diff --git a/include/internal/cef_logging_internal.h b/include/internal/cef_logging_internal.h
new file mode 100644
index 00000000..d29cfc86
--- /dev/null
+++ b/include/internal/cef_logging_internal.h
@@ -0,0 +1,68 @@
+// Copyright (c) 2014 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CEF_INCLUDE_INTERNAL_CEF_LOGGING_INTERNAL_H_
+#define CEF_INCLUDE_INTERNAL_CEF_LOGGING_INTERNAL_H_
+#pragma once
+
+#include <stddef.h>
+
+#include "include/internal/cef_export.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// See include/base/cef_logging.h for macros and intended usage.
+
+///
+/// Gets the current log level.
+///
+CEF_EXPORT int cef_get_min_log_level(void);
+
+///
+/// Gets the current vlog level for the given file (usually taken from
+/// __FILE__). Note that |N| is the size *with* the null terminator.
+///
+CEF_EXPORT int cef_get_vlog_level(const char* file_start, size_t N);
+
+///
+/// Add a log message. See the LogSeverity defines for supported |severity|
+/// values.
+///
+CEF_EXPORT void cef_log(const char* file,
+ int line,
+ int severity,
+ const char* message);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // CEF_INCLUDE_INTERNAL_CEF_LOGGING_INTERNAL_H_
diff --git a/include/internal/cef_mac.h b/include/internal/cef_mac.h
new file mode 100644
index 00000000..983eda8c
--- /dev/null
+++ b/include/internal/cef_mac.h
@@ -0,0 +1,118 @@
+// Copyright (c) 2010 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CEF_INCLUDE_INTERNAL_CEF_MAC_H_
+#define CEF_INCLUDE_INTERNAL_CEF_MAC_H_
+#pragma once
+
+#include "include/internal/cef_types_mac.h"
+#include "include/internal/cef_types_wrappers.h"
+
+// Handle types.
+#define CefCursorHandle cef_cursor_handle_t
+#define CefEventHandle cef_event_handle_t
+#define CefWindowHandle cef_window_handle_t
+
+///
+/// Class representing CefExecuteProcess arguments.
+///
+class CefMainArgs : public cef_main_args_t {
+ public:
+ CefMainArgs() : cef_main_args_t{} {}
+ CefMainArgs(const cef_main_args_t& r) : cef_main_args_t(r) {}
+ CefMainArgs(int argc_arg, char** argv_arg)
+ : cef_main_args_t{argc_arg, argv_arg} {}
+};
+
+struct CefWindowInfoTraits {
+ typedef cef_window_info_t struct_type;
+
+ static inline void init(struct_type* s) {}
+
+ static inline void clear(struct_type* s) {
+ cef_string_clear(&s->window_name);
+ }
+
+ static inline void set(const struct_type* src,
+ struct_type* target,
+ bool copy) {
+ cef_string_set(src->window_name.str, src->window_name.length,
+ &target->window_name, copy);
+ target->bounds = src->bounds;
+ target->hidden = src->hidden;
+ target->parent_view = src->parent_view;
+ target->windowless_rendering_enabled = src->windowless_rendering_enabled;
+ target->shared_texture_enabled = src->shared_texture_enabled;
+ target->external_begin_frame_enabled = src->external_begin_frame_enabled;
+ target->view = src->view;
+ }
+};
+
+///
+/// Class representing window information.
+///
+class CefWindowInfo : public CefStructBase<CefWindowInfoTraits> {
+ public:
+ typedef CefStructBase<CefWindowInfoTraits> parent;
+
+ CefWindowInfo() : parent() {}
+ explicit CefWindowInfo(const cef_window_info_t& r) : parent(r) {}
+ explicit CefWindowInfo(const CefWindowInfo& r) : parent(r) {}
+
+ CefWindowInfo& operator=(const CefWindowInfo&) = default;
+ CefWindowInfo& operator=(CefWindowInfo&&) = default;
+
+ ///
+ /// Create the browser as a child view.
+ ///
+ void SetAsChild(CefWindowHandle parent, const CefRect& bounds) {
+ parent_view = parent;
+ this->bounds = bounds;
+ hidden = false;
+ }
+
+ ///
+ /// Create the browser using windowless (off-screen) rendering. No view
+ /// will be created for the browser and all rendering will occur via the
+ /// CefRenderHandler interface. The |parent| value will be used to identify
+ /// monitor info and to act as the parent view for dialogs, context menus,
+ /// etc. If |parent| is not provided then the main screen monitor will be used
+ /// and some functionality that requires a parent view may not function
+ /// correctly. In order to create windowless browsers the
+ /// CefSettings.windowless_rendering_enabled value must be set to true.
+ /// Transparent painting is enabled by default but can be disabled by setting
+ /// CefBrowserSettings.background_color to an opaque value.
+ ///
+ void SetAsWindowless(CefWindowHandle parent) {
+ windowless_rendering_enabled = true;
+ parent_view = parent;
+ }
+};
+
+#endif // CEF_INCLUDE_INTERNAL_CEF_MAC_H_
diff --git a/include/internal/cef_ptr.h b/include/internal/cef_ptr.h
new file mode 100644
index 00000000..855ade53
--- /dev/null
+++ b/include/internal/cef_ptr.h
@@ -0,0 +1,176 @@
+// Copyright (c) 2014 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CEF_INCLUDE_INTERNAL_CEF_PTR_H_
+#define CEF_INCLUDE_INTERNAL_CEF_PTR_H_
+#pragma once
+
+#include <memory>
+
+#include "include/base/cef_build.h"
+#include "include/base/cef_ref_counted.h"
+
+///
+/// Smart pointer implementation that is an alias of scoped_refptr from
+/// include/base/cef_ref_counted.h.
+///
+/// A smart pointer class for reference counted objects. Use this class instead
+/// of calling AddRef and Release manually on a reference counted object to
+/// avoid common memory leaks caused by forgetting to Release an object
+/// reference. Sample usage:
+///
+/// <pre>
+/// class MyFoo : public CefBaseRefCounted {
+/// ...
+/// };
+///
+/// void some_function() {
+/// // The MyFoo object that |foo| represents starts with a single
+/// // reference.
+/// CefRefPtr&lt;MyFoo&gt; foo = new MyFoo();
+/// foo-&gt;Method(param);
+/// // |foo| is released when this function returns
+/// }
+///
+/// void some_other_function() {
+/// CefRefPtr&lt;MyFoo&gt; foo = new MyFoo();
+/// ...
+/// foo = NULL; /// explicitly releases |foo|
+/// ...
+/// if (foo)
+/// foo-&gt;Method(param);
+/// }
+/// </pre>
+///
+/// The above examples show how CefRefPtr&lt;T&gt; acts like a pointer to T.
+/// Given two CefRefPtr&lt;T&gt; classes, it is also possible to exchange
+/// references between the two objects, like so:
+///
+/// <pre>
+/// {
+/// CefRefPtr&lt;MyFoo&gt; a = new MyFoo();
+/// CefRefPtr&lt;MyFoo&gt; b;
+///
+/// b.swap(a);
+/// // now, |b| references the MyFoo object, and |a| references NULL.
+/// }
+/// </pre>
+///
+/// To make both |a| and |b| in the above example reference the same MyFoo
+/// object, simply use the assignment operator:
+///
+/// <pre>
+/// {
+/// CefRefPtr&lt;MyFoo&gt; a = new MyFoo();
+/// CefRefPtr&lt;MyFoo&gt; b;
+///
+/// b = a;
+/// // now, |a| and |b| each own a reference to the same MyFoo object.
+/// // the reference count of the underlying MyFoo object will be 2.
+/// }
+/// </pre>
+///
+/// Reference counted objects can also be passed as function parameters and
+/// used as function return values:
+///
+/// <pre>
+/// void some_func_with_param(CefRefPtr&lt;MyFoo&gt; param) {
+/// // A reference is added to the MyFoo object that |param| represents
+/// // during the scope of some_func_with_param() and released when
+/// // some_func_with_param() goes out of scope.
+/// }
+///
+/// CefRefPtr&lt;MyFoo&gt; some_func_with_retval() {
+/// // The MyFoo object that |foox| represents starts with a single
+/// // reference.
+/// CefRefPtr&lt;MyFoo&gt; foox = new MyFoo();
+///
+/// // Creating the return value adds an additional reference.
+/// return foox;
+///
+/// // When some_func_with_retval() goes out of scope the original |foox|
+/// // reference is released.
+/// }
+///
+/// void and_another_function() {
+/// CefRefPtr&lt;MyFoo&gt; foo = new MyFoo();
+///
+/// // pass |foo| as a parameter.
+/// some_function(foo);
+///
+/// CefRefPtr&lt;MyFoo&gt; foo2 = some_func_with_retval();
+/// // Now, since we kept a reference to the some_func_with_retval() return
+/// // value, |foo2| is the only class pointing to the MyFoo object created
+/// in some_func_with_retval(), and it has a reference count of 1.
+///
+/// some_func_with_retval();
+/// // Now, since we didn't keep a reference to the some_func_with_retval()
+/// // return value, the MyFoo object created in some_func_with_retval()
+/// // will automatically be released.
+/// }
+/// </pre>
+///
+/// And in standard containers:
+///
+/// <pre>
+/// {
+/// // Create a vector that holds MyFoo objects.
+/// std::vector&lt;CefRefPtr&lt;MyFoo&gt; &gt; MyFooVec;
+///
+/// // The MyFoo object that |foo| represents starts with a single
+/// // reference.
+/// CefRefPtr&lt;MyFoo&gt; foo = new MyFoo();
+///
+/// // When the MyFoo object is added to |MyFooVec| the reference count
+/// // is increased to 2.
+/// MyFooVec.push_back(foo);
+/// }
+/// </pre>
+///
+template <class T>
+using CefRefPtr = scoped_refptr<T>;
+
+///
+/// A CefOwnPtr<T> is like a T*, except that the destructor of CefOwnPtr<T>
+/// automatically deletes the pointer it holds (if any). That is, CefOwnPtr<T>
+/// owns the T object that it points to. Like a T*, a CefOwnPtr<T> may hold
+/// either NULL or a pointer to a T object. Also like T*, CefOwnPtr<T> is
+/// thread-compatible, and once you dereference it, you get the thread safety
+/// guarantees of T.
+///
+template <class T, class D = std::default_delete<T>>
+using CefOwnPtr = std::unique_ptr<T, D>;
+
+///
+/// A CefRawPtr<T> is the same as T*
+///
+template <class T>
+using CefRawPtr = T*;
+
+#endif // CEF_INCLUDE_INTERNAL_CEF_PTR_H_
diff --git a/include/internal/cef_string.h b/include/internal/cef_string.h
new file mode 100644
index 00000000..77c8ca3d
--- /dev/null
+++ b/include/internal/cef_string.h
@@ -0,0 +1,112 @@
+// Copyright (c) 2010 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CEF_INCLUDE_INTERNAL_CEF_STRING_H_
+#define CEF_INCLUDE_INTERNAL_CEF_STRING_H_
+#pragma once
+
+// The CEF interface is built with one string type as the default. Comment out
+// all but one of the CEF_STRING_TYPE_* defines below to specify the default.
+// If you change the default you MUST recompile all of CEF.
+
+// Build with the UTF8 string type as default.
+// #define CEF_STRING_TYPE_UTF8 1
+
+// Build with the UTF16 string type as default.
+#define CEF_STRING_TYPE_UTF16 1
+
+// Build with the wide string type as default.
+// #define CEF_STRING_TYPE_WIDE 1
+
+#include "include/internal/cef_string_types.h"
+
+#ifdef __cplusplus
+#include "include/internal/cef_string_wrappers.h"
+#if defined(CEF_STRING_TYPE_UTF16)
+typedef CefStringUTF16 CefString;
+#elif defined(CEF_STRING_TYPE_UTF8)
+typedef CefStringUTF8 CefString;
+#elif defined(CEF_STRING_TYPE_WIDE)
+typedef CefStringWide CefString;
+#endif
+#endif // __cplusplus
+
+#if defined(CEF_STRING_TYPE_UTF8)
+typedef char cef_char_t;
+typedef cef_string_utf8_t cef_string_t;
+typedef cef_string_userfree_utf8_t cef_string_userfree_t;
+#define cef_string_set cef_string_utf8_set
+#define cef_string_copy cef_string_utf8_copy
+#define cef_string_clear cef_string_utf8_clear
+#define cef_string_userfree_alloc cef_string_userfree_utf8_alloc
+#define cef_string_userfree_free cef_string_userfree_utf8_free
+#define cef_string_from_ascii cef_string_utf8_copy
+#define cef_string_to_utf8 cef_string_utf8_copy
+#define cef_string_from_utf8 cef_string_utf8_copy
+#define cef_string_to_utf16 cef_string_utf8_to_utf16
+#define cef_string_from_utf16 cef_string_utf16_to_utf8
+#define cef_string_to_wide cef_string_utf8_to_wide
+#define cef_string_from_wide cef_string_wide_to_utf8
+#elif defined(CEF_STRING_TYPE_UTF16)
+typedef char16 cef_char_t;
+typedef cef_string_userfree_utf16_t cef_string_userfree_t;
+typedef cef_string_utf16_t cef_string_t;
+#define cef_string_set cef_string_utf16_set
+#define cef_string_copy cef_string_utf16_copy
+#define cef_string_clear cef_string_utf16_clear
+#define cef_string_userfree_alloc cef_string_userfree_utf16_alloc
+#define cef_string_userfree_free cef_string_userfree_utf16_free
+#define cef_string_from_ascii cef_string_ascii_to_utf16
+#define cef_string_to_utf8 cef_string_utf16_to_utf8
+#define cef_string_from_utf8 cef_string_utf8_to_utf16
+#define cef_string_to_utf16 cef_string_utf16_copy
+#define cef_string_from_utf16 cef_string_utf16_copy
+#define cef_string_to_wide cef_string_utf16_to_wide
+#define cef_string_from_wide cef_string_wide_to_utf16
+#elif defined(CEF_STRING_TYPE_WIDE)
+typedef wchar_t cef_char_t;
+typedef cef_string_wide_t cef_string_t;
+typedef cef_string_userfree_wide_t cef_string_userfree_t;
+#define cef_string_set cef_string_wide_set
+#define cef_string_copy cef_string_wide_copy
+#define cef_string_clear cef_string_wide_clear
+#define cef_string_userfree_alloc cef_string_userfree_wide_alloc
+#define cef_string_userfree_free cef_string_userfree_wide_free
+#define cef_string_from_ascii cef_string_ascii_to_wide
+#define cef_string_to_utf8 cef_string_wide_to_utf8
+#define cef_string_from_utf8 cef_string_utf8_to_wide
+#define cef_string_to_utf16 cef_string_wide_to_utf16
+#define cef_string_from_utf16 cef_string_utf16_to_wide
+#define cef_string_to_wide cef_string_wide_copy
+#define cef_string_from_wide cef_string_wide_copy
+#else
+#error Please choose a string type.
+#endif
+
+#endif // CEF_INCLUDE_INTERNAL_CEF_STRING_H_
diff --git a/include/internal/cef_string_list.h b/include/internal/cef_string_list.h
new file mode 100644
index 00000000..0b6226bc
--- /dev/null
+++ b/include/internal/cef_string_list.h
@@ -0,0 +1,89 @@
+// Copyright (c) 2009 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CEF_INCLUDE_INTERNAL_CEF_STRING_LIST_H_
+#define CEF_INCLUDE_INTERNAL_CEF_STRING_LIST_H_
+#pragma once
+
+#include "include/internal/cef_export.h"
+#include "include/internal/cef_string.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// CEF string maps are a set of key/value string pairs.
+///
+typedef void* cef_string_list_t;
+
+///
+/// Allocate a new string map.
+///
+CEF_EXPORT cef_string_list_t cef_string_list_alloc(void);
+
+///
+/// Return the number of elements in the string list.
+///
+CEF_EXPORT size_t cef_string_list_size(cef_string_list_t list);
+
+///
+/// Retrieve the value at the specified zero-based string list index. Returns
+/// true (1) if the value was successfully retrieved.
+///
+CEF_EXPORT int cef_string_list_value(cef_string_list_t list,
+ size_t index,
+ cef_string_t* value);
+
+///
+/// Append a new value at the end of the string list.
+///
+CEF_EXPORT void cef_string_list_append(cef_string_list_t list,
+ const cef_string_t* value);
+
+///
+/// Clear the string list.
+///
+CEF_EXPORT void cef_string_list_clear(cef_string_list_t list);
+
+///
+/// Free the string list.
+///
+CEF_EXPORT void cef_string_list_free(cef_string_list_t list);
+
+///
+/// Creates a copy of an existing string list.
+///
+CEF_EXPORT cef_string_list_t cef_string_list_copy(cef_string_list_t list);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_INTERNAL_CEF_STRING_LIST_H_
diff --git a/include/internal/cef_string_map.h b/include/internal/cef_string_map.h
new file mode 100644
index 00000000..f3a80835
--- /dev/null
+++ b/include/internal/cef_string_map.h
@@ -0,0 +1,98 @@
+// Copyright (c) 2009 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CEF_INCLUDE_INTERNAL_CEF_STRING_MAP_H_
+#define CEF_INCLUDE_INTERNAL_CEF_STRING_MAP_H_
+#pragma once
+
+#include "include/internal/cef_export.h"
+#include "include/internal/cef_string.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// CEF string maps are a set of key/value string pairs.
+///
+typedef void* cef_string_map_t;
+
+///
+/// Allocate a new string map.
+///
+CEF_EXPORT cef_string_map_t cef_string_map_alloc(void);
+
+///
+/// Return the number of elements in the string map.
+///
+CEF_EXPORT size_t cef_string_map_size(cef_string_map_t map);
+
+///
+/// Return the value assigned to the specified key.
+///
+CEF_EXPORT int cef_string_map_find(cef_string_map_t map,
+ const cef_string_t* key,
+ cef_string_t* value);
+
+///
+/// Return the key at the specified zero-based string map index.
+///
+CEF_EXPORT int cef_string_map_key(cef_string_map_t map,
+ size_t index,
+ cef_string_t* key);
+
+///
+/// Return the value at the specified zero-based string map index.
+///
+CEF_EXPORT int cef_string_map_value(cef_string_map_t map,
+ size_t index,
+ cef_string_t* value);
+
+///
+/// Append a new key/value pair at the end of the string map.
+///
+CEF_EXPORT int cef_string_map_append(cef_string_map_t map,
+ const cef_string_t* key,
+ const cef_string_t* value);
+
+///
+/// Clear the string map.
+///
+CEF_EXPORT void cef_string_map_clear(cef_string_map_t map);
+
+///
+/// Free the string map.
+///
+CEF_EXPORT void cef_string_map_free(cef_string_map_t map);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_INTERNAL_CEF_STRING_MAP_H_
diff --git a/include/internal/cef_string_multimap.h b/include/internal/cef_string_multimap.h
new file mode 100644
index 00000000..313bd9dc
--- /dev/null
+++ b/include/internal/cef_string_multimap.h
@@ -0,0 +1,106 @@
+// Copyright (c) 2011 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CEF_INCLUDE_INTERNAL_CEF_STRING_MULTIMAP_H_
+#define CEF_INCLUDE_INTERNAL_CEF_STRING_MULTIMAP_H_
+#pragma once
+
+#include "include/internal/cef_export.h"
+#include "include/internal/cef_string.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// CEF string multimaps are a set of key/value string pairs.
+/// More than one value can be assigned to a single key.
+///
+typedef void* cef_string_multimap_t;
+
+///
+/// Allocate a new string multimap.
+///
+CEF_EXPORT cef_string_multimap_t cef_string_multimap_alloc(void);
+
+///
+/// Return the number of elements in the string multimap.
+///
+CEF_EXPORT size_t cef_string_multimap_size(cef_string_multimap_t map);
+
+///
+/// Return the number of values with the specified key.
+///
+CEF_EXPORT size_t cef_string_multimap_find_count(cef_string_multimap_t map,
+ const cef_string_t* key);
+
+///
+/// Return the value_index-th value with the specified key.
+///
+CEF_EXPORT int cef_string_multimap_enumerate(cef_string_multimap_t map,
+ const cef_string_t* key,
+ size_t value_index,
+ cef_string_t* value);
+
+///
+/// Return the key at the specified zero-based string multimap index.
+///
+CEF_EXPORT int cef_string_multimap_key(cef_string_multimap_t map,
+ size_t index,
+ cef_string_t* key);
+
+///
+/// Return the value at the specified zero-based string multimap index.
+///
+CEF_EXPORT int cef_string_multimap_value(cef_string_multimap_t map,
+ size_t index,
+ cef_string_t* value);
+
+///
+/// Append a new key/value pair at the end of the string multimap.
+///
+CEF_EXPORT int cef_string_multimap_append(cef_string_multimap_t map,
+ const cef_string_t* key,
+ const cef_string_t* value);
+
+///
+/// Clear the string multimap.
+///
+CEF_EXPORT void cef_string_multimap_clear(cef_string_multimap_t map);
+
+///
+/// Free the string multimap.
+///
+CEF_EXPORT void cef_string_multimap_free(cef_string_multimap_t map);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_INTERNAL_CEF_STRING_MULTIMAP_H_
diff --git a/include/internal/cef_string_types.h b/include/internal/cef_string_types.h
new file mode 100644
index 00000000..00a16c70
--- /dev/null
+++ b/include/internal/cef_string_types.h
@@ -0,0 +1,212 @@
+// Copyright (c) 2010 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CEF_INCLUDE_INTERNAL_CEF_STRING_TYPES_H_
+#define CEF_INCLUDE_INTERNAL_CEF_STRING_TYPES_H_
+#pragma once
+
+#include <stddef.h>
+
+#include "include/base/cef_basictypes.h"
+#include "include/internal/cef_export.h"
+
+///
+/// \file
+/// CEF provides functions for converting between UTF-8, -16 and -32 strings.
+/// CEF string types are safe for reading from multiple threads but not for
+/// modification. It is the user's responsibility to provide synchronization if
+/// modifying CEF strings from multiple threads.
+///
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// CEF string type definitions. Whomever allocates |str| is responsible for
+/// providing an appropriate |dtor| implementation that will free the string in
+/// the same memory space. When reusing an existing string structure make sure
+/// to call |dtor| for the old value before assigning new |str| and |dtor|
+/// values. Static strings will have a NULL |dtor| value. Using the below
+/// functions if you want this managed for you.
+///
+
+typedef struct _cef_string_wide_t {
+ wchar_t* str;
+ size_t length;
+ void (*dtor)(wchar_t* str);
+} cef_string_wide_t;
+
+typedef struct _cef_string_utf8_t {
+ char* str;
+ size_t length;
+ void (*dtor)(char* str);
+} cef_string_utf8_t;
+
+typedef struct _cef_string_utf16_t {
+ char16* str;
+ size_t length;
+ void (*dtor)(char16* str);
+} cef_string_utf16_t;
+
+///
+/// These functions set string values. If |copy| is true (1) the value will be
+/// copied instead of referenced. It is up to the user to properly manage
+/// the lifespan of references.
+///
+
+CEF_EXPORT int cef_string_wide_set(const wchar_t* src,
+ size_t src_len,
+ cef_string_wide_t* output,
+ int copy);
+CEF_EXPORT int cef_string_utf8_set(const char* src,
+ size_t src_len,
+ cef_string_utf8_t* output,
+ int copy);
+CEF_EXPORT int cef_string_utf16_set(const char16* src,
+ size_t src_len,
+ cef_string_utf16_t* output,
+ int copy);
+
+///
+/// Convenience macros for copying values.
+///
+
+#define cef_string_wide_copy(src, src_len, output) \
+ cef_string_wide_set(src, src_len, output, true)
+#define cef_string_utf8_copy(src, src_len, output) \
+ cef_string_utf8_set(src, src_len, output, true)
+#define cef_string_utf16_copy(src, src_len, output) \
+ cef_string_utf16_set(src, src_len, output, true)
+
+///
+/// These functions clear string values. The structure itself is not freed.
+///
+
+CEF_EXPORT void cef_string_wide_clear(cef_string_wide_t* str);
+CEF_EXPORT void cef_string_utf8_clear(cef_string_utf8_t* str);
+CEF_EXPORT void cef_string_utf16_clear(cef_string_utf16_t* str);
+
+///
+/// These functions compare two string values with the same results as strcmp().
+///
+
+CEF_EXPORT int cef_string_wide_cmp(const cef_string_wide_t* str1,
+ const cef_string_wide_t* str2);
+CEF_EXPORT int cef_string_utf8_cmp(const cef_string_utf8_t* str1,
+ const cef_string_utf8_t* str2);
+CEF_EXPORT int cef_string_utf16_cmp(const cef_string_utf16_t* str1,
+ const cef_string_utf16_t* str2);
+
+///
+/// These functions convert between UTF-8, -16, and -32 strings. They are
+/// potentially slow so unnecessary conversions should be avoided. The best
+/// possible result will always be written to |output| with the boolean return
+/// value indicating whether the conversion is 100% valid.
+///
+
+CEF_EXPORT int cef_string_wide_to_utf8(const wchar_t* src,
+ size_t src_len,
+ cef_string_utf8_t* output);
+CEF_EXPORT int cef_string_utf8_to_wide(const char* src,
+ size_t src_len,
+ cef_string_wide_t* output);
+
+CEF_EXPORT int cef_string_wide_to_utf16(const wchar_t* src,
+ size_t src_len,
+ cef_string_utf16_t* output);
+CEF_EXPORT int cef_string_utf16_to_wide(const char16* src,
+ size_t src_len,
+ cef_string_wide_t* output);
+
+CEF_EXPORT int cef_string_utf8_to_utf16(const char* src,
+ size_t src_len,
+ cef_string_utf16_t* output);
+CEF_EXPORT int cef_string_utf16_to_utf8(const char16* src,
+ size_t src_len,
+ cef_string_utf8_t* output);
+
+///
+/// These functions convert an ASCII string, typically a hardcoded constant, to
+/// a Wide/UTF16 string. Use instead of the UTF8 conversion routines if you know
+/// the string is ASCII.
+///
+
+CEF_EXPORT int cef_string_ascii_to_wide(const char* src,
+ size_t src_len,
+ cef_string_wide_t* output);
+CEF_EXPORT int cef_string_ascii_to_utf16(const char* src,
+ size_t src_len,
+ cef_string_utf16_t* output);
+
+///
+/// It is sometimes necessary for the system to allocate string structures with
+/// the expectation that the user will free them. The userfree types act as a
+/// hint that the user is responsible for freeing the structure.
+///
+
+typedef cef_string_wide_t* cef_string_userfree_wide_t;
+typedef cef_string_utf8_t* cef_string_userfree_utf8_t;
+typedef cef_string_utf16_t* cef_string_userfree_utf16_t;
+
+///
+/// These functions allocate a new string structure. They must be freed by
+/// calling the associated free function.
+///
+
+CEF_EXPORT cef_string_userfree_wide_t cef_string_userfree_wide_alloc(void);
+CEF_EXPORT cef_string_userfree_utf8_t cef_string_userfree_utf8_alloc(void);
+CEF_EXPORT cef_string_userfree_utf16_t cef_string_userfree_utf16_alloc(void);
+
+///
+/// These functions free the string structure allocated by the associated
+/// alloc function. Any string contents will first be cleared.
+///
+
+CEF_EXPORT void cef_string_userfree_wide_free(cef_string_userfree_wide_t str);
+CEF_EXPORT void cef_string_userfree_utf8_free(cef_string_userfree_utf8_t str);
+CEF_EXPORT void cef_string_userfree_utf16_free(cef_string_userfree_utf16_t str);
+
+///
+/// These functions convert utf16 string case using the current ICU locale. This
+/// may change the length of the string in some cases.
+///
+
+CEF_EXPORT int cef_string_utf16_to_lower(const char16* src,
+ size_t src_len,
+ cef_string_utf16_t* output);
+CEF_EXPORT int cef_string_utf16_to_upper(const char16* src,
+ size_t src_len,
+ cef_string_utf16_t* output);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_INTERNAL_CEF_STRING_TYPES_H_
diff --git a/include/internal/cef_string_wrappers.h b/include/internal/cef_string_wrappers.h
new file mode 100644
index 00000000..44e453f6
--- /dev/null
+++ b/include/internal/cef_string_wrappers.h
@@ -0,0 +1,865 @@
+// Copyright (c) 2010 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CEF_INCLUDE_INTERNAL_CEF_STRING_WRAPPERS_H_
+#define CEF_INCLUDE_INTERNAL_CEF_STRING_WRAPPERS_H_
+#pragma once
+
+#include <memory.h>
+#include <string>
+
+#include "include/internal/cef_string_types.h"
+
+#if defined(USING_CHROMIUM_INCLUDES)
+#include "base/files/file_path.h"
+#endif
+
+///
+/// Traits implementation for wide character strings.
+///
+struct CefStringTraitsWide {
+ typedef wchar_t char_type;
+ typedef cef_string_wide_t struct_type;
+ typedef cef_string_userfree_wide_t userfree_struct_type;
+
+ static inline void clear(struct_type* s) { cef_string_wide_clear(s); }
+ static inline int set(const char_type* src,
+ size_t src_size,
+ struct_type* output,
+ int copy) {
+ return cef_string_wide_set(src, src_size, output, copy);
+ }
+ static inline int compare(const struct_type* s1, const struct_type* s2) {
+ return cef_string_wide_cmp(s1, s2);
+ }
+ static inline userfree_struct_type userfree_alloc() {
+ return cef_string_userfree_wide_alloc();
+ }
+ static inline void userfree_free(userfree_struct_type ufs) {
+ return cef_string_userfree_wide_free(ufs);
+ }
+
+ // Conversion methods.
+ static inline bool from_ascii(const char* str, size_t len, struct_type* s) {
+ return cef_string_ascii_to_wide(str, len, s) ? true : false;
+ }
+ static inline std::string to_string(const struct_type* s) {
+ cef_string_utf8_t cstr;
+ memset(&cstr, 0, sizeof(cstr));
+ cef_string_wide_to_utf8(s->str, s->length, &cstr);
+ std::string str;
+ if (cstr.length > 0) {
+ str = std::string(cstr.str, cstr.length);
+ }
+ cef_string_utf8_clear(&cstr);
+ return str;
+ }
+ static inline bool from_string(const std::string::value_type* data,
+ size_t length,
+ struct_type* s) {
+ return cef_string_utf8_to_wide(data, length, s) ? true : false;
+ }
+ static inline bool from_string(const std::string& str, struct_type* s) {
+ return from_string(str.data(), str.length(), s);
+ }
+ static inline std::wstring to_wstring(const struct_type* s) {
+ return std::wstring(s->str, s->length);
+ }
+ static inline bool from_wstring(const std::wstring::value_type* data,
+ size_t length,
+ struct_type* s) {
+ return cef_string_wide_set(data, length, s, true) ? true : false;
+ }
+ static inline bool from_wstring(const std::wstring& str, struct_type* s) {
+ return from_wstring(str.data(), str.length(), s);
+ }
+#if defined(WCHAR_T_IS_UTF32)
+ static inline std::u16string to_string16(const struct_type* s) {
+ cef_string_utf16_t cstr;
+ memset(&cstr, 0, sizeof(cstr));
+ cef_string_wide_to_utf16(s->str, s->length, &cstr);
+ std::u16string str;
+ if (cstr.length > 0) {
+ str = std::u16string(
+ reinterpret_cast<std::u16string::value_type*>(cstr.str), cstr.length);
+ }
+ cef_string_utf16_clear(&cstr);
+ return str;
+ }
+ static inline bool from_string16(const std::u16string::value_type* data,
+ size_t length,
+ struct_type* s) {
+ return cef_string_utf16_to_wide(reinterpret_cast<const char16*>(data),
+ length, s)
+ ? true
+ : false;
+ }
+#else // WCHAR_T_IS_UTF32
+ static inline std::u16string to_string16(const struct_type* s) {
+ return std::u16string(
+ reinterpret_cast<const std::u16string::value_type*>(s->str), s->length);
+ }
+ static inline bool from_string16(const std::u16string::value_type* data,
+ size_t length,
+ struct_type* s) {
+ return cef_string_wide_set(reinterpret_cast<const wchar_t*>(data), length,
+ s, true)
+ ? true
+ : false;
+ }
+#endif // WCHAR_T_IS_UTF32
+ static inline bool from_string16(const std::u16string& str, struct_type* s) {
+ return from_string16(str.data(), str.length(), s);
+ }
+};
+
+///
+/// Traits implementation for utf8 character strings.
+///
+struct CefStringTraitsUTF8 {
+ typedef char char_type;
+ typedef cef_string_utf8_t struct_type;
+ typedef cef_string_userfree_utf8_t userfree_struct_type;
+
+ static inline void clear(struct_type* s) { cef_string_utf8_clear(s); }
+ static inline int set(const char_type* src,
+ size_t src_size,
+ struct_type* output,
+ int copy) {
+ return cef_string_utf8_set(src, src_size, output, copy);
+ }
+ static inline int compare(const struct_type* s1, const struct_type* s2) {
+ return cef_string_utf8_cmp(s1, s2);
+ }
+ static inline userfree_struct_type userfree_alloc() {
+ return cef_string_userfree_utf8_alloc();
+ }
+ static inline void userfree_free(userfree_struct_type ufs) {
+ return cef_string_userfree_utf8_free(ufs);
+ }
+
+ // Conversion methods.
+ static inline bool from_ascii(const char* str, size_t len, struct_type* s) {
+ return cef_string_utf8_copy(str, len, s) ? true : false;
+ }
+ static inline std::string to_string(const struct_type* s) {
+ return std::string(s->str, s->length);
+ }
+ static inline bool from_string(const std::string::value_type* data,
+ size_t length,
+ struct_type* s) {
+ return cef_string_utf8_copy(data, length, s) ? true : false;
+ }
+ static inline bool from_string(const std::string& str, struct_type* s) {
+ return from_string(str.c_str(), str.length(), s);
+ }
+ static inline std::wstring to_wstring(const struct_type* s) {
+ cef_string_wide_t cstr;
+ memset(&cstr, 0, sizeof(cstr));
+ cef_string_utf8_to_wide(s->str, s->length, &cstr);
+ std::wstring str;
+ if (cstr.length > 0) {
+ str = std::wstring(cstr.str, cstr.length);
+ }
+ cef_string_wide_clear(&cstr);
+ return str;
+ }
+ static inline bool from_wstring(const std::wstring::value_type* data,
+ size_t length,
+ struct_type* s) {
+ return cef_string_wide_to_utf8(data, length, s) ? true : false;
+ }
+ static inline bool from_wstring(const std::wstring& str, struct_type* s) {
+ return from_wstring(str.data(), str.length(), s);
+ }
+ static inline std::u16string to_string16(const struct_type* s) {
+ cef_string_utf16_t cstr;
+ memset(&cstr, 0, sizeof(cstr));
+ cef_string_utf8_to_utf16(s->str, s->length, &cstr);
+ std::u16string str;
+ if (cstr.length > 0) {
+ str = std::u16string(
+ reinterpret_cast<std::u16string::value_type*>(cstr.str), cstr.length);
+ }
+ cef_string_utf16_clear(&cstr);
+ return str;
+ }
+ static inline bool from_string16(const std::u16string::value_type* data,
+ size_t length,
+ struct_type* s) {
+ return cef_string_utf16_to_utf8(reinterpret_cast<const char16*>(data),
+ length, s)
+ ? true
+ : false;
+ }
+ static inline bool from_string16(const std::u16string& str, struct_type* s) {
+ return from_string16(str.data(), str.length(), s);
+ }
+};
+
+///
+/// Traits implementation for utf16 character strings.
+///
+struct CefStringTraitsUTF16 {
+ typedef char16 char_type;
+ typedef cef_string_utf16_t struct_type;
+ typedef cef_string_userfree_utf16_t userfree_struct_type;
+
+ static inline void clear(struct_type* s) { cef_string_utf16_clear(s); }
+ static inline int set(const char_type* src,
+ size_t src_size,
+ struct_type* output,
+ int copy) {
+ return cef_string_utf16_set(src, src_size, output, copy);
+ }
+ static inline int compare(const struct_type* s1, const struct_type* s2) {
+ return cef_string_utf16_cmp(s1, s2);
+ }
+ static inline userfree_struct_type userfree_alloc() {
+ return cef_string_userfree_utf16_alloc();
+ }
+ static inline void userfree_free(userfree_struct_type ufs) {
+ return cef_string_userfree_utf16_free(ufs);
+ }
+
+ // Conversion methods.
+ static inline bool from_ascii(const char* str, size_t len, struct_type* s) {
+ return cef_string_ascii_to_utf16(str, len, s) ? true : false;
+ }
+ static inline std::string to_string(const struct_type* s) {
+ cef_string_utf8_t cstr;
+ memset(&cstr, 0, sizeof(cstr));
+ cef_string_utf16_to_utf8(s->str, s->length, &cstr);
+ std::string str;
+ if (cstr.length > 0) {
+ str = std::string(cstr.str, cstr.length);
+ }
+ cef_string_utf8_clear(&cstr);
+ return str;
+ }
+ static inline bool from_string(const std::string::value_type* data,
+ size_t length,
+ struct_type* s) {
+ return cef_string_utf8_to_utf16(data, length, s) ? true : false;
+ }
+ static inline bool from_string(const std::string& str, struct_type* s) {
+ return from_string(str.data(), str.length(), s);
+ }
+#if defined(WCHAR_T_IS_UTF32)
+ static inline std::wstring to_wstring(const struct_type* s) {
+ cef_string_wide_t cstr;
+ memset(&cstr, 0, sizeof(cstr));
+ cef_string_utf16_to_wide(s->str, s->length, &cstr);
+ std::wstring str;
+ if (cstr.length > 0) {
+ str = std::wstring(cstr.str, cstr.length);
+ }
+ cef_string_wide_clear(&cstr);
+ return str;
+ }
+ static inline bool from_wstring(const std::wstring::value_type* data,
+ size_t length,
+ struct_type* s) {
+ return cef_string_wide_to_utf16(data, length, s) ? true : false;
+ }
+#else // WCHAR_T_IS_UTF32
+ static inline std::wstring to_wstring(const struct_type* s) {
+ return std::wstring(s->str, s->length);
+ }
+ static inline bool from_wstring(const std::wstring::value_type* data,
+ size_t length,
+ struct_type* s) {
+ return cef_string_utf16_set(data, length, s, true) ? true : false;
+ }
+#endif // WCHAR_T_IS_UTF32
+ static inline bool from_wstring(const std::wstring& str, struct_type* s) {
+ return from_wstring(str.data(), str.length(), s);
+ }
+ static inline std::u16string to_string16(const struct_type* s) {
+ return std::u16string(
+ reinterpret_cast<const std::u16string::value_type*>(s->str), s->length);
+ }
+ static inline bool from_string16(const std::u16string::value_type* data,
+ size_t length,
+ struct_type* s) {
+ return cef_string_utf16_set(reinterpret_cast<const char16*>(data), length,
+ s, true)
+ ? true
+ : false;
+ }
+ static inline bool from_string16(const std::u16string& str, struct_type* s) {
+ return from_string16(str.data(), str.length(), s);
+ }
+};
+
+///
+/// CEF string classes can convert between all supported string types. For
+/// example, the CefStringWide class uses wchar_t as the underlying character
+/// type and provides two approaches for converting data to/from a UTF8 string
+/// (std::string).
+///
+/// 1. Implicit conversion using the assignment operator overload.
+/// <pre>
+/// CefStringWide aCefString;
+/// std::string aUTF8String;
+/// aCefString = aUTF8String; // Assign std::string to CefStringWide
+/// aUTF8String = aCefString; // Assign CefStringWide to std::string
+/// </pre>
+///
+/// 2. Explicit conversion using the FromString/ToString methods.
+/// <pre>
+/// CefStringWide aCefString;
+/// std::string aUTF8String;
+/// aCefString.FromString(aUTF8String); // Assign std::string to CefStringWide
+/// aUTF8String = aCefString.ToString(); // Assign CefStringWide to
+/// std::string
+/// </pre>
+///
+/// Conversion will only occur if the assigned value is a different string type.
+/// Assigning a std::string to a CefStringUTF8, for example, will copy the data
+/// without performing a conversion.
+///
+/// CEF string classes are safe for reading from multiple threads but not for
+/// modification. It is the user's responsibility to provide synchronization if
+/// modifying CEF strings from multiple threads.
+///
+template <class traits>
+class CefStringBase {
+ public:
+ typedef typename traits::char_type char_type;
+ typedef typename traits::struct_type struct_type;
+ typedef typename traits::userfree_struct_type userfree_struct_type;
+
+ ///
+ /// Default constructor.
+ ///
+ CefStringBase() : string_(NULL), owner_(false) {}
+
+ ///
+ /// Create a new string from an existing string. Data will always be copied.
+ ///
+ CefStringBase(const CefStringBase& str) : string_(NULL), owner_(false) {
+ FromString(str.c_str(), str.length(), true);
+ }
+
+ ///
+ /// Create a new string from an existing std::string. Data will be always
+ /// copied. Translation will occur if necessary based on the underlying string
+ /// type.
+ ///
+ CefStringBase(const std::string& src) : string_(NULL), owner_(false) {
+ FromString(src);
+ }
+ CefStringBase(const char* src, size_t length = 0)
+ : string_(NULL), owner_(false) {
+ if (src) {
+ FromString(src, length);
+ }
+ }
+
+ ///
+ /// Create a new string from an existing std::wstring. Data will be always
+ /// copied. Translation will occur if necessary based on the underlying string
+ /// type.
+ ///
+ CefStringBase(const std::wstring& src) : string_(NULL), owner_(false) {
+ FromWString(src);
+ }
+ CefStringBase(const wchar_t* src, size_t length = 0)
+ : string_(NULL), owner_(false) {
+ if (src) {
+ FromWString(src, length);
+ }
+ }
+
+ ///
+ /// Create a new string from an existing string16. Data will be always
+ /// copied. Translation will occur if necessary based on the underlying string
+ /// type.
+ ///
+ CefStringBase(const std::u16string& src) : string_(NULL), owner_(false) {
+ FromString16(src);
+ }
+ CefStringBase(const std::u16string::value_type* src, size_t length = 0)
+ : string_(NULL), owner_(false) {
+ if (src) {
+ FromString16(src, length);
+ }
+ }
+#if defined(WCHAR_T_IS_UTF32)
+ CefStringBase(const char16* src, size_t length = 0)
+ : string_(NULL), owner_(false) {
+ if (src) {
+ FromString16(reinterpret_cast<const std::u16string::value_type*>(src),
+ length);
+ }
+ }
+#endif // WCHAR_T_IS_UTF32
+
+ ///
+ /// Create a new string from an existing character array. If |copy| is true
+ /// this class will copy the data. Otherwise, this class will reference the
+ /// existing data. Referenced data must exist for the lifetime of this class
+ /// and will not be freed by this class.
+ ///
+ CefStringBase(const char_type* src, size_t src_len, bool copy)
+ : string_(NULL), owner_(false) {
+ if (src && src_len > 0) {
+ FromString(src, src_len, copy);
+ }
+ }
+
+ ///
+ /// Create a new string referencing an existing string structure without
+ /// taking ownership. Referenced structures must exist for the lifetime of
+ /// this class and will not be freed by this class.
+ ///
+ CefStringBase(const struct_type* src) : string_(NULL), owner_(false) {
+ if (!src) {
+ return;
+ }
+ // Reference the existing structure without taking ownership.
+ Attach(const_cast<struct_type*>(src), false);
+ }
+
+ virtual ~CefStringBase() { ClearAndFree(); }
+
+ /// The following methods are named for compatibility with the standard
+ /// library string template types.
+
+ ///
+ /// Return a read-only pointer to the string data.
+ ///
+ const char_type* c_str() const { return (string_ ? string_->str : NULL); }
+
+ ///
+ /// Return the length of the string data.
+ ///
+ size_t length() const { return (string_ ? string_->length : 0); }
+
+ ///
+ /// Return the length of the string data.
+ ///
+ inline size_t size() const { return length(); }
+
+ ///
+ /// Returns true if the string is empty.
+ ///
+ bool empty() const { return (string_ == NULL || string_->length == 0); }
+
+ ///
+ /// Compare this string to the specified string.
+ ///
+ int compare(const CefStringBase& str) const {
+ if (empty() && str.empty()) {
+ return 0;
+ }
+ if (empty()) {
+ return -1;
+ }
+ if (str.empty()) {
+ return 1;
+ }
+ return traits::compare(string_, str.GetStruct());
+ }
+
+ ///
+ /// Clear the string data.
+ ///
+ void clear() {
+ if (string_) {
+ traits::clear(string_);
+ }
+ }
+
+ ///
+ /// Swap this string's contents with the specified string.
+ ///
+ void swap(CefStringBase& str) {
+ struct_type* tmp_string = string_;
+ bool tmp_owner = owner_;
+ string_ = str.string_;
+ owner_ = str.owner_;
+ str.string_ = tmp_string;
+ str.owner_ = tmp_owner;
+ }
+
+ // The following methods are unique to CEF string template types.
+
+ ///
+ /// Returns true if this class owns the underlying string structure.
+ ///
+ bool IsOwner() const { return owner_; }
+
+ ///
+ /// Returns a read-only pointer to the underlying string structure. May return
+ /// NULL if no structure is currently allocated.
+ ///
+ const struct_type* GetStruct() const { return string_; }
+
+ ///
+ /// Returns a writable pointer to the underlying string structure. Will never
+ /// return NULL.
+ ///
+ struct_type* GetWritableStruct() {
+ AllocIfNeeded();
+ return string_;
+ }
+
+ ///
+ /// Clear the state of this class. The underlying string structure and data
+ /// will be freed if this class owns the structure.
+ ///
+ void ClearAndFree() {
+ if (!string_) {
+ return;
+ }
+ if (owner_) {
+ clear();
+ delete string_;
+ }
+ string_ = NULL;
+ owner_ = false;
+ }
+
+ ///
+ /// Attach to the specified string structure. If |owner| is true this class
+ /// will take ownership of the structure.
+ ///
+ void Attach(struct_type* str, bool owner) {
+ // Free the previous structure and data, if any.
+ ClearAndFree();
+
+ string_ = str;
+ owner_ = owner;
+ }
+
+ ///
+ /// Take ownership of the specified userfree structure's string data. The
+ /// userfree structure itself will be freed. Only use this method with
+ /// userfree structures.
+ ///
+ void AttachToUserFree(userfree_struct_type str) {
+ // Free the previous structure and data, if any.
+ ClearAndFree();
+
+ if (!str) {
+ return;
+ }
+
+ AllocIfNeeded();
+ owner_ = true;
+ memcpy(string_, str, sizeof(struct_type));
+
+ /// Free the |str| structure but not the data.
+ memset(str, 0, sizeof(struct_type));
+ traits::userfree_free(str);
+ }
+
+ ///
+ /// Detach from the underlying string structure. To avoid memory leaks only
+ /// use this method if you already hold a pointer to the underlying string
+ /// structure.
+ ///
+ void Detach() {
+ string_ = NULL;
+ owner_ = false;
+ }
+
+ ///
+ /// Create a userfree structure and give it ownership of this class' string
+ /// data. This class will be disassociated from the data. May return NULL if
+ /// this string class currently contains no data.
+ ///
+ userfree_struct_type DetachToUserFree() {
+ if (empty()) {
+ return NULL;
+ }
+
+ userfree_struct_type str = traits::userfree_alloc();
+ if (owner_) {
+ // Transfer ownership of the data to |str|.
+ memcpy(str, string_, sizeof(struct_type));
+ // Free this class' structure but not the data.
+ memset(string_, 0, sizeof(struct_type));
+ } else {
+ // Copy the data to |str|.
+ traits::set(string_->str, string_->length, str, /*copy=*/true);
+ }
+
+ ClearAndFree();
+
+ return str;
+ }
+
+ ///
+ /// Set this string's data to the specified character array. If |copy| is true
+ /// this class will copy the data. Otherwise, this class will reference the
+ /// existing data. Referenced data must exist for the lifetime of this class
+ /// and will not be freed by this class.
+ ///
+ bool FromString(const char_type* src, size_t src_len, bool copy) {
+ if (src == NULL || src_len == 0) {
+ clear();
+ return true;
+ }
+ AllocIfNeeded();
+ return traits::set(src, src_len, string_, copy) ? true : false;
+ }
+
+ ///
+ /// Set this string's data from an existing ASCII string. Data will be always
+ /// copied. Translation will occur if necessary based on the underlying string
+ /// type.
+ ///
+ bool FromASCII(const char* str) {
+ size_t len = str ? strlen(str) : 0;
+ if (len == 0) {
+ clear();
+ return true;
+ }
+ AllocIfNeeded();
+ return traits::from_ascii(str, len, string_);
+ }
+
+ ///
+ /// Return this string's data as a std::string. Translation will occur if
+ /// necessary based on the underlying string type.
+ ///
+ std::string ToString() const {
+ if (empty()) {
+ return std::string();
+ }
+ return traits::to_string(string_);
+ }
+
+ ///
+ /// Set this string's data from an existing std::string. Data will be always
+ /// copied. Translation will occur if necessary based on the underlying string
+ /// type.
+ ///
+ bool FromString(const std::string& str) {
+ if (str.empty()) {
+ clear();
+ return true;
+ }
+ AllocIfNeeded();
+ return traits::from_string(str, string_);
+ }
+
+ ///
+ /// Set this string's data from existing |data| and optional |length|. Data
+ /// will be always copied. Translation will occur if necessary based on the
+ /// underlying string type.
+ ///
+ bool FromString(const std::string::value_type* data, size_t length = 0) {
+ if (data && length == 0) {
+ length = std::char_traits<std::string::value_type>::length(data);
+ }
+ if (!data || length == 0) {
+ clear();
+ return true;
+ }
+ AllocIfNeeded();
+ return traits::from_string(data, length, string_);
+ }
+
+ ///
+ /// Return this string's data as a std::wstring. Translation will occur if
+ /// necessary based on the underlying string type.
+ ///
+ std::wstring ToWString() const {
+ if (empty()) {
+ return std::wstring();
+ }
+ return traits::to_wstring(string_);
+ }
+
+ ///
+ /// Set this string's data from an existing std::wstring. Data will be always
+ /// copied. Translation will occur if necessary based on the underlying string
+ /// type.
+ ///
+ bool FromWString(const std::wstring& str) {
+ if (str.empty()) {
+ clear();
+ return true;
+ }
+ AllocIfNeeded();
+ return traits::from_wstring(str, string_);
+ }
+
+ ///
+ /// Set this string's data from existing |data| and optional |length|. Data
+ /// will be always copied. Translation will occur if necessary based on the
+ /// underlying string type.
+ ///
+ bool FromWString(const std::wstring::value_type* data, size_t length = 0) {
+ if (data && length == 0) {
+ length = std::char_traits<std::wstring::value_type>::length(data);
+ }
+ if (!data || length == 0) {
+ clear();
+ return true;
+ }
+ AllocIfNeeded();
+ return traits::from_wstring(data, length, string_);
+ }
+
+ ///
+ /// Return this string's data as a string16. Translation will occur if
+ /// necessary based on the underlying string type.
+ ///
+ std::u16string ToString16() const {
+ if (empty()) {
+ return std::u16string();
+ }
+ return traits::to_string16(string_);
+ }
+
+ ///
+ /// Set this string's data from an existing string16. Data will be always
+ /// copied. Translation will occur if necessary based on the underlying string
+ /// type.
+ ///
+ bool FromString16(const std::u16string& str) {
+ if (str.empty()) {
+ clear();
+ return true;
+ }
+ AllocIfNeeded();
+ return traits::from_string16(str, string_);
+ }
+
+ ///
+ /// Set this string's data from existing |data| and optional |length|. Data
+ /// will be always copied. Translation will occur if necessary based on the
+ /// underlying string type.
+ ///
+ bool FromString16(const std::u16string::value_type* data, size_t length = 0) {
+ if (data && length == 0) {
+ length = std::char_traits<std::u16string::value_type>::length(data);
+ }
+ if (!data || length == 0) {
+ clear();
+ return true;
+ }
+ AllocIfNeeded();
+ return traits::from_string16(data, length, string_);
+ }
+
+ ///
+ /// Comparison operator overloads.
+ ///
+ bool operator<(const CefStringBase& str) const { return (compare(str) < 0); }
+ bool operator<=(const CefStringBase& str) const {
+ return (compare(str) <= 0);
+ }
+ bool operator>(const CefStringBase& str) const { return (compare(str) > 0); }
+ bool operator>=(const CefStringBase& str) const {
+ return (compare(str) >= 0);
+ }
+ bool operator==(const CefStringBase& str) const {
+ return (compare(str) == 0);
+ }
+ bool operator!=(const CefStringBase& str) const {
+ return (compare(str) != 0);
+ }
+
+ ///
+ /// Assignment operator overloads.
+ ///
+ CefStringBase& operator=(const CefStringBase& str) {
+ FromString(str.c_str(), str.length(), true);
+ return *this;
+ }
+ operator std::string() const { return ToString(); }
+ CefStringBase& operator=(const std::string& str) {
+ FromString(str);
+ return *this;
+ }
+ CefStringBase& operator=(const std::string::value_type* str) {
+ FromString(str);
+ return *this;
+ }
+ operator std::wstring() const { return ToWString(); }
+ CefStringBase& operator=(const std::wstring& str) {
+ FromWString(str);
+ return *this;
+ }
+ CefStringBase& operator=(const std::wstring::value_type* str) {
+ FromWString(str);
+ return *this;
+ }
+ operator std::u16string() const { return ToString16(); }
+ CefStringBase& operator=(const std::u16string& str) {
+ FromString16(str);
+ return *this;
+ }
+ CefStringBase& operator=(const std::u16string::value_type* str) {
+ FromString16(str);
+ return *this;
+ }
+#if defined(WCHAR_T_IS_UTF32)
+ CefStringBase& operator=(const char16* str) {
+ FromString16(reinterpret_cast<const std::u16string::value_type*>(str));
+ return *this;
+ }
+#endif // WCHAR_T_IS_UTF32
+#if defined(USING_CHROMIUM_INCLUDES)
+ // The base::FilePath constructor is marked as explicit so provide the
+ // conversion here for convenience.
+ operator base::FilePath() const {
+#if defined(OS_WIN)
+ return base::FilePath(ToWString());
+#else
+ return base::FilePath(ToString());
+#endif
+ }
+#endif // USING_CHROMIUM_INCLUDES
+
+ private:
+ /// Allocate the string structure if it doesn't already exist.
+ void AllocIfNeeded() {
+ if (string_ == NULL) {
+ string_ = new struct_type;
+ memset(string_, 0, sizeof(struct_type));
+ owner_ = true;
+ }
+ }
+
+ struct_type* string_;
+ bool owner_;
+};
+
+typedef CefStringBase<CefStringTraitsWide> CefStringWide;
+typedef CefStringBase<CefStringTraitsUTF8> CefStringUTF8;
+typedef CefStringBase<CefStringTraitsUTF16> CefStringUTF16;
+
+#endif // CEF_INCLUDE_INTERNAL_CEF_STRING_WRAPPERS_H_
diff --git a/include/internal/cef_thread_internal.h b/include/internal/cef_thread_internal.h
new file mode 100644
index 00000000..7df3be86
--- /dev/null
+++ b/include/internal/cef_thread_internal.h
@@ -0,0 +1,78 @@
+// Copyright (c) 2014 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CEF_INCLUDE_INTERNAL_CEF_THREAD_INTERNAL_H_
+#define CEF_INCLUDE_INTERNAL_CEF_THREAD_INTERNAL_H_
+#pragma once
+
+#if defined(OS_WIN)
+#include <windows.h>
+#elif defined(OS_POSIX)
+#include <pthread.h>
+#include <unistd.h>
+#endif
+
+#include "include/internal/cef_export.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(OS_WIN)
+typedef DWORD cef_platform_thread_id_t;
+#define kInvalidPlatformThreadId 0U
+#elif defined(OS_POSIX)
+typedef pid_t cef_platform_thread_id_t;
+#define kInvalidPlatformThreadId 0
+#endif
+
+///
+/// Returns the current platform thread ID.
+///
+CEF_EXPORT cef_platform_thread_id_t cef_get_current_platform_thread_id(void);
+
+#if defined(OS_WIN)
+typedef DWORD cef_platform_thread_handle_t;
+#define kInvalidPlatformThreadHandle 0U
+#elif defined(OS_POSIX)
+typedef pthread_t cef_platform_thread_handle_t;
+#define kInvalidPlatformThreadHandle 0
+#endif
+
+///
+/// Returns the current platform thread handle.
+///
+CEF_EXPORT cef_platform_thread_handle_t
+cef_get_current_platform_thread_handle(void);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // CEF_INCLUDE_INTERNAL_CEF_THREAD_INTERNAL_H_
diff --git a/include/internal/cef_time.h b/include/internal/cef_time.h
new file mode 100644
index 00000000..7d0b4cc7
--- /dev/null
+++ b/include/internal/cef_time.h
@@ -0,0 +1,152 @@
+// Copyright (c) 2011 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CEF_INCLUDE_INTERNAL_CEF_TIME_H_
+#define CEF_INCLUDE_INTERNAL_CEF_TIME_H_
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <time.h>
+#include "include/base/cef_basictypes.h"
+#include "include/internal/cef_export.h"
+
+///
+/// Represents a wall clock time in UTC. Values are not guaranteed to be
+/// monotonically non-decreasing and are subject to large amounts of skew.
+/// Time is stored internally as microseconds since the Windows epoch (1601).
+///
+/// This is equivalent of Chromium `base::Time` (see base/time/time.h).
+///
+typedef struct _cef_basetime_t {
+ int64 val;
+} cef_basetime_t;
+
+///
+/// Time information. Values should always be in UTC.
+///
+typedef struct _cef_time_t {
+ ///
+ /// Four or five digit year "2007" (1601 to 30827 on Windows, 1970 to 2038 on
+ /// 32-bit POSIX)
+ ///
+ int year;
+
+ ///
+ /// 1-based month (values 1 = January, etc.)
+ ///
+ int month;
+
+ ///
+ /// 0-based day of week (0 = Sunday, etc.)
+ ///
+ int day_of_week;
+
+ ///
+ /// 1-based day of month (1-31)
+ ///
+ int day_of_month;
+
+ ///
+ /// Hour within the current day (0-23)
+ ///
+ int hour;
+
+ ///
+ /// Minute within the current hour (0-59)
+ ///
+ int minute;
+
+ ///
+ /// Second within the current minute (0-59 plus leap seconds which may take
+ /// it up to 60).
+ ///
+ int second;
+
+ ///
+ /// Milliseconds within the current second (0-999)
+ ///
+ int millisecond;
+} cef_time_t;
+
+///
+/// Converts cef_time_t to/from time_t. Returns true (1) on success and false
+/// (0) on failure.
+///
+CEF_EXPORT int cef_time_to_timet(const cef_time_t* cef_time, time_t* time);
+CEF_EXPORT int cef_time_from_timet(time_t time, cef_time_t* cef_time);
+
+///
+/// Converts cef_time_t to/from a double which is the number of seconds since
+/// epoch (Jan 1, 1970). Webkit uses this format to represent time. A value of 0
+/// means "not initialized". Returns true (1) on success and false (0) on
+/// failure.
+///
+CEF_EXPORT int cef_time_to_doublet(const cef_time_t* cef_time, double* time);
+CEF_EXPORT int cef_time_from_doublet(double time, cef_time_t* cef_time);
+
+///
+/// Retrieve the current system time. Returns true (1) on success and false (0)
+/// on failure.
+///
+CEF_EXPORT int cef_time_now(cef_time_t* cef_time);
+
+///
+/// Retrieve the current system time.
+///
+CEF_EXPORT cef_basetime_t cef_basetime_now(void);
+
+///
+/// Retrieve the delta in milliseconds between two time values. Returns true (1)
+/// on success and false (0) on failure.
+//
+CEF_EXPORT int cef_time_delta(const cef_time_t* cef_time1,
+ const cef_time_t* cef_time2,
+ long long* delta);
+
+///
+/// Converts cef_time_t to cef_basetime_t. Returns true (1) on success and
+/// false (0) on failure.
+///
+CEF_EXPORT int cef_time_to_basetime(const cef_time_t* from, cef_basetime_t* to);
+
+///
+/// Converts cef_basetime_t to cef_time_t. Returns true (1) on success and
+/// false (0) on failure.
+///
+CEF_EXPORT int cef_time_from_basetime(const cef_basetime_t from,
+ cef_time_t* to);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_INTERNAL_CEF_TIME_H_
diff --git a/include/internal/cef_time_wrappers.h b/include/internal/cef_time_wrappers.h
new file mode 100644
index 00000000..7b5cbfb8
--- /dev/null
+++ b/include/internal/cef_time_wrappers.h
@@ -0,0 +1,111 @@
+// Copyright (c) 2022 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CEF_INCLUDE_INTERNAL_CEF_TIME_WRAPPERS_H_
+#define CEF_INCLUDE_INTERNAL_CEF_TIME_WRAPPERS_H_
+#pragma once
+
+#include "include/internal/cef_time.h"
+
+#if defined(USING_CHROMIUM_INCLUDES)
+#include "base/time/time.h"
+#endif
+
+///
+/// Represents a wall clock time in UTC. Values are not guaranteed to be
+/// monotonically non-decreasing and are subject to large amounts of skew.
+/// Time is stored internally as microseconds since the Windows epoch (1601).
+///
+/// This is equivalent of Chromium `base::Time` (see base/time/time.h).
+///
+class CefBaseTime : public cef_basetime_t {
+ public:
+ CefBaseTime() : cef_basetime_t{} {}
+ CefBaseTime(const cef_basetime_t& value) : cef_basetime_t(value) {}
+
+#if defined(USING_CHROMIUM_INCLUDES)
+ CefBaseTime(const base::Time& value)
+ : cef_basetime_t{value.ToDeltaSinceWindowsEpoch().InMicroseconds()} {}
+
+ operator base::Time() const {
+ return base::Time::FromDeltaSinceWindowsEpoch(base::Microseconds(val));
+ }
+#endif
+
+ static CefBaseTime Now() { return cef_basetime_now(); }
+};
+
+///
+/// Class representing a time.
+///
+class CefTime : public cef_time_t {
+ public:
+ CefTime() : cef_time_t{} {}
+ CefTime(const cef_time_t& r) : cef_time_t(r) {}
+ explicit CefTime(time_t r) { SetTimeT(r); }
+ explicit CefTime(double r) { SetDoubleT(r); }
+
+ ///
+ /// Converts to/from time_t.
+ ///
+ void SetTimeT(time_t r) { cef_time_from_timet(r, this); }
+ time_t GetTimeT() const {
+ time_t time = 0;
+ cef_time_to_timet(this, &time);
+ return time;
+ }
+
+ ///
+ /// Converts to/from a double which is the number of seconds since epoch
+ /// (Jan 1, 1970). Webkit uses this format to represent time. A value of 0
+ /// means "not initialized".
+ ///
+ void SetDoubleT(double r) { cef_time_from_doublet(r, this); }
+ double GetDoubleT() const {
+ double time = 0;
+ cef_time_to_doublet(this, &time);
+ return time;
+ }
+
+ ///
+ /// Set this object to now.
+ ///
+ void Now() { cef_time_now(this); }
+
+ ///
+ /// Return the delta between this object and |other| in milliseconds.
+ ///
+ long long Delta(const CefTime& other) {
+ long long delta = 0;
+ cef_time_delta(this, &other, &delta);
+ return delta;
+ }
+};
+
+#endif // CEF_INCLUDE_INTERNAL_CEF_TIME_WRAPPERS_H_
diff --git a/include/internal/cef_trace_event_internal.h b/include/internal/cef_trace_event_internal.h
new file mode 100644
index 00000000..6df87071
--- /dev/null
+++ b/include/internal/cef_trace_event_internal.h
@@ -0,0 +1,124 @@
+// Copyright (c) 2014 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CEF_INCLUDE_INTERNAL_CEF_TRACE_EVENT_INTERNAL_H_
+#define CEF_INCLUDE_INTERNAL_CEF_TRACE_EVENT_INTERNAL_H_
+#pragma once
+
+#include "include/internal/cef_export.h"
+#include "include/internal/cef_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// See include/base/cef_trace_event.h for macros and intended usage.
+
+// Functions for tracing counters and functions; called from macros.
+// - |category| string must have application lifetime (static or literal). They
+// may not include "(quotes) chars.
+// - |argX_name|, |argX_val|, |valueX_name|, |valeX_val| are optional parameters
+// and represent pairs of name and values of arguments
+// - |copy| is used to avoid memory scoping issues with the |name| and
+// |arg_name| parameters by copying them
+// - |id| is used to disambiguate counters with the same name, or match async
+// trace events
+
+CEF_EXPORT void cef_trace_event_instant(const char* category,
+ const char* name,
+ const char* arg1_name,
+ uint64 arg1_val,
+ const char* arg2_name,
+ uint64 arg2_val,
+ int copy);
+CEF_EXPORT void cef_trace_event_begin(const char* category,
+ const char* name,
+ const char* arg1_name,
+ uint64 arg1_val,
+ const char* arg2_name,
+ uint64 arg2_val,
+ int copy);
+CEF_EXPORT void cef_trace_event_end(const char* category,
+ const char* name,
+ const char* arg1_name,
+ uint64 arg1_val,
+ const char* arg2_name,
+ uint64 arg2_val,
+ int copy);
+CEF_EXPORT void cef_trace_counter(const char* category,
+ const char* name,
+ const char* value1_name,
+ uint64 value1_val,
+ const char* value2_name,
+ uint64 value2_val,
+ int copy);
+CEF_EXPORT void cef_trace_counter_id(const char* category,
+ const char* name,
+ uint64 id,
+ const char* value1_name,
+ uint64 value1_val,
+ const char* value2_name,
+ uint64 value2_val,
+ int copy);
+CEF_EXPORT void cef_trace_event_async_begin(const char* category,
+ const char* name,
+ uint64 id,
+ const char* arg1_name,
+ uint64 arg1_val,
+ const char* arg2_name,
+ uint64 arg2_val,
+ int copy);
+CEF_EXPORT void cef_trace_event_async_step_into(const char* category,
+ const char* name,
+ uint64 id,
+ uint64 step,
+ const char* arg1_name,
+ uint64 arg1_val,
+ int copy);
+CEF_EXPORT void cef_trace_event_async_step_past(const char* category,
+ const char* name,
+ uint64 id,
+ uint64 step,
+ const char* arg1_name,
+ uint64 arg1_val,
+ int copy);
+CEF_EXPORT void cef_trace_event_async_end(const char* category,
+ const char* name,
+ uint64 id,
+ const char* arg1_name,
+ uint64 arg1_val,
+ const char* arg2_name,
+ uint64 arg2_val,
+ int copy);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // CEF_INCLUDE_INTERNAL_CEF_TRACE_EVENT_INTERNAL_H_
diff --git a/include/internal/cef_types.h b/include/internal/cef_types.h
new file mode 100644
index 00000000..810dc524
--- /dev/null
+++ b/include/internal/cef_types.h
@@ -0,0 +1,3450 @@
+// Copyright (c) 2014 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CEF_INCLUDE_INTERNAL_CEF_TYPES_H_
+#define CEF_INCLUDE_INTERNAL_CEF_TYPES_H_
+#pragma once
+
+#include "include/base/cef_basictypes.h"
+#include "include/internal/cef_string.h"
+#include "include/internal/cef_string_list.h"
+#include "include/internal/cef_time.h"
+#include "include/internal/cef_types_geometry.h"
+
+// Bring in platform-specific definitions.
+#if defined(OS_WIN)
+#include "include/internal/cef_types_win.h"
+#elif defined(OS_MAC)
+#include "include/internal/cef_types_mac.h"
+#elif defined(OS_LINUX)
+#include "include/internal/cef_types_linux.h"
+#endif
+
+// 32-bit ARGB color value, not premultiplied. The color components are always
+// in a known order. Equivalent to the SkColor type.
+typedef uint32 cef_color_t;
+
+// Return the alpha byte from a cef_color_t value.
+#define CefColorGetA(color) (((color) >> 24) & 0xFF)
+// Return the red byte from a cef_color_t value.
+#define CefColorGetR(color) (((color) >> 16) & 0xFF)
+// Return the green byte from a cef_color_t value.
+#define CefColorGetG(color) (((color) >> 8) & 0xFF)
+// Return the blue byte from a cef_color_t value.
+#define CefColorGetB(color) (((color) >> 0) & 0xFF)
+
+// Return an cef_color_t value with the specified byte component values.
+#define CefColorSetARGB(a, r, g, b) \
+ static_cast<cef_color_t>( \
+ (static_cast<unsigned>(a) << 24) | (static_cast<unsigned>(r) << 16) | \
+ (static_cast<unsigned>(g) << 8) | (static_cast<unsigned>(b) << 0))
+
+// Return an int64 value with the specified low and high int32 component values.
+#define CefInt64Set(int32_low, int32_high) \
+ static_cast<int64>((static_cast<uint32>(int32_low)) | \
+ (static_cast<int64>(static_cast<int32>(int32_high))) \
+ << 32)
+
+// Return the low int32 value from an int64 value.
+#define CefInt64GetLow(int64_val) static_cast<int32>(int64_val)
+// Return the high int32 value from an int64 value.
+#define CefInt64GetHigh(int64_val) \
+ static_cast<int32>((static_cast<int64>(int64_val) >> 32) & 0xFFFFFFFFL)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Log severity levels.
+///
+typedef enum {
+ ///
+ /// Default logging (currently INFO logging).
+ ///
+ LOGSEVERITY_DEFAULT,
+
+ ///
+ /// Verbose logging.
+ ///
+ LOGSEVERITY_VERBOSE,
+
+ ///
+ /// DEBUG logging.
+ ///
+ LOGSEVERITY_DEBUG = LOGSEVERITY_VERBOSE,
+
+ ///
+ /// INFO logging.
+ ///
+ LOGSEVERITY_INFO,
+
+ ///
+ /// WARNING logging.
+ ///
+ LOGSEVERITY_WARNING,
+
+ ///
+ /// ERROR logging.
+ ///
+ LOGSEVERITY_ERROR,
+
+ ///
+ /// FATAL logging.
+ ///
+ LOGSEVERITY_FATAL,
+
+ ///
+ /// Disable logging to file for all messages, and to stderr for messages with
+ /// severity less than FATAL.
+ ///
+ LOGSEVERITY_DISABLE = 99
+} cef_log_severity_t;
+
+///
+/// Represents the state of a setting.
+///
+typedef enum {
+ ///
+ /// Use the default state for the setting.
+ ///
+ STATE_DEFAULT = 0,
+
+ ///
+ /// Enable or allow the setting.
+ ///
+ STATE_ENABLED,
+
+ ///
+ /// Disable or disallow the setting.
+ ///
+ STATE_DISABLED,
+} cef_state_t;
+
+///
+/// Initialization settings. Specify NULL or 0 to get the recommended default
+/// values. Many of these and other settings can also configured using command-
+/// line switches.
+///
+typedef struct _cef_settings_t {
+ ///
+ /// Size of this structure.
+ ///
+ size_t size;
+
+ ///
+ /// Set to true (1) to disable the sandbox for sub-processes. See
+ /// cef_sandbox_win.h for requirements to enable the sandbox on Windows. Also
+ /// configurable using the "no-sandbox" command-line switch.
+ ///
+ int no_sandbox;
+
+ ///
+ /// The path to a separate executable that will be launched for sub-processes.
+ /// If this value is empty on Windows or Linux then the main process
+ /// executable will be used. If this value is empty on macOS then a helper
+ /// executable must exist at "Contents/Frameworks/<app>
+ /// Helper.app/Contents/MacOS/<app> Helper" in the top-level app bundle. See
+ /// the comments on CefExecuteProcess() for details. If this value is
+ /// non-empty then it must be an absolute path. Also configurable using the
+ /// "browser-subprocess-path" command-line switch.
+ ///
+ cef_string_t browser_subprocess_path;
+
+ ///
+ /// The path to the CEF framework directory on macOS. If this value is empty
+ /// then the framework must exist at "Contents/Frameworks/Chromium Embedded
+ /// Framework.framework" in the top-level app bundle. If this value is
+ /// non-empty then it must be an absolute path. Also configurable using the
+ /// "framework-dir-path" command-line switch.
+ ///
+ cef_string_t framework_dir_path;
+
+ ///
+ /// The path to the main bundle on macOS. If this value is empty then it
+ /// defaults to the top-level app bundle. If this value is non-empty then it
+ /// must be an absolute path. Also configurable using the "main-bundle-path"
+ /// command-line switch.
+ ///
+ cef_string_t main_bundle_path;
+
+ ///
+ /// Set to true (1) to enable use of the Chrome runtime in CEF. This feature
+ /// is considered experimental and is not recommended for most users at this
+ /// time. See issue #2969 for details.
+ ///
+ int chrome_runtime;
+
+ ///
+ /// Set to true (1) to have the browser process message loop run in a separate
+ /// thread. If false (0) then the CefDoMessageLoopWork() function must be
+ /// called from your application message loop. This option is only supported
+ /// on Windows and Linux.
+ ///
+ int multi_threaded_message_loop;
+
+ ///
+ /// Set to true (1) to control browser process main (UI) thread message pump
+ /// scheduling via the CefBrowserProcessHandler::OnScheduleMessagePumpWork()
+ /// callback. This option is recommended for use in combination with the
+ /// CefDoMessageLoopWork() function in cases where the CEF message loop must
+ /// be integrated into an existing application message loop (see additional
+ /// comments and warnings on CefDoMessageLoopWork). Enabling this option is
+ /// not recommended for most users; leave this option disabled and use either
+ /// the CefRunMessageLoop() function or multi_threaded_message_loop if
+ /// possible.
+ ///
+ int external_message_pump;
+
+ ///
+ /// Set to true (1) to enable windowless (off-screen) rendering support. Do
+ /// not enable this value if the application does not use windowless rendering
+ /// as it may reduce rendering performance on some systems.
+ ///
+ int windowless_rendering_enabled;
+
+ ///
+ /// Set to true (1) to disable configuration of browser process features using
+ /// standard CEF and Chromium command-line arguments. Configuration can still
+ /// be specified using CEF data structures or via the
+ /// CefApp::OnBeforeCommandLineProcessing() method.
+ ///
+ int command_line_args_disabled;
+
+ ///
+ /// The location where data for the global browser cache will be stored on
+ /// disk. If this value is non-empty then it must be an absolute path that is
+ /// either equal to or a child directory of CefSettings.root_cache_path. If
+ /// this value is empty then browsers will be created in "incognito mode"
+ /// where in-memory caches are used for storage and no data is persisted to
+ /// disk. HTML5 databases such as localStorage will only persist across
+ /// sessions if a cache path is specified. Can be overridden for individual
+ /// CefRequestContext instances via the CefRequestContextSettings.cache_path
+ /// value. When using the Chrome runtime the "default" profile will be used if
+ /// |cache_path| and |root_cache_path| have the same value.
+ ///
+ cef_string_t cache_path;
+
+ ///
+ /// The root directory that all CefSettings.cache_path and
+ /// CefRequestContextSettings.cache_path values must have in common. If this
+ /// value is empty and CefSettings.cache_path is non-empty then it will
+ /// default to the CefSettings.cache_path value. If this value is non-empty
+ /// then it must be an absolute path. Failure to set this value correctly may
+ /// result in the sandbox blocking read/write access to the cache_path
+ /// directory.
+ ///
+ cef_string_t root_cache_path;
+
+ ///
+ /// The location where user data such as the Widevine CDM module and spell
+ /// checking dictionary files will be stored on disk. If this value is empty
+ /// then the default platform-specific user data directory will be used
+ /// ("~/.config/cef_user_data" directory on Linux, "~/Library/Application
+ /// Support/CEF/User Data" directory on MacOS, "AppData\Local\CEF\User Data"
+ /// directory under the user profile directory on Windows). If this value is
+ /// non-empty then it must be an absolute path. When using the Chrome runtime
+ /// this value will be ignored in favor of the |root_cache_path| value.
+ ///
+ cef_string_t user_data_path;
+
+ ///
+ /// To persist session cookies (cookies without an expiry date or validity
+ /// interval) by default when using the global cookie manager set this value
+ /// to true (1). Session cookies are generally intended to be transient and
+ /// most Web browsers do not persist them. A |cache_path| value must also be
+ /// specified to enable this feature. Also configurable using the
+ /// "persist-session-cookies" command-line switch. Can be overridden for
+ /// individual CefRequestContext instances via the
+ /// CefRequestContextSettings.persist_session_cookies value.
+ ///
+ int persist_session_cookies;
+
+ ///
+ /// To persist user preferences as a JSON file in the cache path directory set
+ /// this value to true (1). A |cache_path| value must also be specified
+ /// to enable this feature. Also configurable using the
+ /// "persist-user-preferences" command-line switch. Can be overridden for
+ /// individual CefRequestContext instances via the
+ /// CefRequestContextSettings.persist_user_preferences value.
+ ///
+ int persist_user_preferences;
+
+ ///
+ /// Value that will be returned as the User-Agent HTTP header. If empty the
+ /// default User-Agent string will be used. Also configurable using the
+ /// "user-agent" command-line switch.
+ ///
+ cef_string_t user_agent;
+
+ ///
+ /// Value that will be inserted as the product portion of the default
+ /// User-Agent string. If empty the Chromium product version will be used. If
+ /// |userAgent| is specified this value will be ignored. Also configurable
+ /// using the "user-agent-product" command-line switch.
+ ///
+ cef_string_t user_agent_product;
+
+ ///
+ /// The locale string that will be passed to WebKit. If empty the default
+ /// locale of "en-US" will be used. This value is ignored on Linux where
+ /// locale is determined using environment variable parsing with the
+ /// precedence order: LANGUAGE, LC_ALL, LC_MESSAGES and LANG. Also
+ /// configurable using the "lang" command-line switch.
+ ///
+ cef_string_t locale;
+
+ ///
+ /// The directory and file name to use for the debug log. If empty a default
+ /// log file name and location will be used. On Windows and Linux a
+ /// "debug.log" file will be written in the main executable directory. On
+ /// MacOS a "~/Library/Logs/[app name]_debug.log" file will be written where
+ /// [app name] is the name of the main app executable. Also configurable using
+ /// the "log-file" command-line switch.
+ ///
+ cef_string_t log_file;
+
+ ///
+ /// The log severity. Only messages of this severity level or higher will be
+ /// logged. When set to DISABLE no messages will be written to the log file,
+ /// but FATAL messages will still be output to stderr. Also configurable using
+ /// the "log-severity" command-line switch with a value of "verbose", "info",
+ /// "warning", "error", "fatal" or "disable".
+ ///
+ cef_log_severity_t log_severity;
+
+ ///
+ /// Custom flags that will be used when initializing the V8 JavaScript engine.
+ /// The consequences of using custom flags may not be well tested. Also
+ /// configurable using the "js-flags" command-line switch.
+ ///
+ cef_string_t javascript_flags;
+
+ ///
+ /// The fully qualified path for the resources directory. If this value is
+ /// empty the *.pak files must be located in the module directory on
+ /// Windows/Linux or the app bundle Resources directory on MacOS. If this
+ /// value is non-empty then it must be an absolute path. Also configurable
+ /// using the "resources-dir-path" command-line switch.
+ ///
+ cef_string_t resources_dir_path;
+
+ ///
+ /// The fully qualified path for the locales directory. If this value is empty
+ /// the locales directory must be located in the module directory. If this
+ /// value is non-empty then it must be an absolute path. This value is ignored
+ /// on MacOS where pack files are always loaded from the app bundle Resources
+ /// directory. Also configurable using the "locales-dir-path" command-line
+ /// switch.
+ ///
+ cef_string_t locales_dir_path;
+
+ ///
+ /// Set to true (1) to disable loading of pack files for resources and
+ /// locales. A resource bundle handler must be provided for the browser and
+ /// render processes via CefApp::GetResourceBundleHandler() if loading of pack
+ /// files is disabled. Also configurable using the "disable-pack-loading"
+ /// command- line switch.
+ ///
+ int pack_loading_disabled;
+
+ ///
+ /// Set to a value between 1024 and 65535 to enable remote debugging on the
+ /// specified port. Also configurable using the "remote-debugging-port"
+ /// command-line switch. Remote debugging can be accessed by loading the
+ /// chrome://inspect page in Google Chrome. Port numbers 9222 and 9229 are
+ /// discoverable by default. Other port numbers may need to be configured via
+ /// "Discover network targets" on the Devices tab.
+ ///
+ int remote_debugging_port;
+
+ ///
+ /// The number of stack trace frames to capture for uncaught exceptions.
+ /// Specify a positive value to enable the
+ /// CefRenderProcessHandler::OnUncaughtException() callback. Specify 0
+ /// (default value) and OnUncaughtException() will not be called. Also
+ /// configurable using the "uncaught-exception-stack-size" command-line
+ /// switch.
+ ///
+ int uncaught_exception_stack_size;
+
+ ///
+ /// Background color used for the browser before a document is loaded and when
+ /// no document color is specified. The alpha component must be either fully
+ /// opaque (0xFF) or fully transparent (0x00). If the alpha component is fully
+ /// opaque then the RGB components will be used as the background color. If
+ /// the alpha component is fully transparent for a windowed browser then the
+ /// default value of opaque white be used. If the alpha component is fully
+ /// transparent for a windowless (off-screen) browser then transparent
+ /// painting will be enabled.
+ ///
+ cef_color_t background_color;
+
+ ///
+ /// Comma delimited ordered list of language codes without any whitespace that
+ /// will be used in the "Accept-Language" HTTP header. May be overridden on a
+ /// per-browser basis using the CefBrowserSettings.accept_language_list value.
+ /// If both values are empty then "en-US,en" will be used. Can be overridden
+ /// for individual CefRequestContext instances via the
+ /// CefRequestContextSettings.accept_language_list value.
+ ///
+ cef_string_t accept_language_list;
+
+ ///
+ /// Comma delimited list of schemes supported by the associated
+ /// CefCookieManager. If |cookieable_schemes_exclude_defaults| is false (0)
+ /// the default schemes ("http", "https", "ws" and "wss") will also be
+ /// supported. Not specifying a |cookieable_schemes_list| value and setting
+ /// |cookieable_schemes_exclude_defaults| to true (1) will disable all loading
+ /// and saving of cookies. These settings will only impact the global
+ /// CefRequestContext. Individual CefRequestContext instances can be
+ /// configured via the CefRequestContextSettings.cookieable_schemes_list and
+ /// CefRequestContextSettings.cookieable_schemes_exclude_defaults values.
+ ///
+ cef_string_t cookieable_schemes_list;
+ int cookieable_schemes_exclude_defaults;
+} cef_settings_t;
+
+///
+/// Request context initialization settings. Specify NULL or 0 to get the
+/// recommended default values.
+///
+typedef struct _cef_request_context_settings_t {
+ ///
+ /// Size of this structure.
+ ///
+ size_t size;
+
+ ///
+ /// The location where cache data for this request context will be stored on
+ /// disk. If this value is non-empty then it must be an absolute path that is
+ /// either equal to or a child directory of CefSettings.root_cache_path. If
+ /// this value is empty then browsers will be created in "incognito mode"
+ /// where in-memory caches are used for storage and no data is persisted to
+ /// disk. HTML5 databases such as localStorage will only persist across
+ /// sessions if a cache path is specified. To share the global browser cache
+ /// and related configuration set this value to match the
+ /// CefSettings.cache_path value.
+ ///
+ cef_string_t cache_path;
+
+ ///
+ /// To persist session cookies (cookies without an expiry date or validity
+ /// interval) by default when using the global cookie manager set this value
+ /// to true (1). Session cookies are generally intended to be transient and
+ /// most Web browsers do not persist them. Can be set globally using the
+ /// CefSettings.persist_session_cookies value. This value will be ignored if
+ /// |cache_path| is empty or if it matches the CefSettings.cache_path value.
+ ///
+ int persist_session_cookies;
+
+ ///
+ /// To persist user preferences as a JSON file in the cache path directory set
+ /// this value to true (1). Can be set globally using the
+ /// CefSettings.persist_user_preferences value. This value will be ignored if
+ /// |cache_path| is empty or if it matches the CefSettings.cache_path value.
+ ///
+ int persist_user_preferences;
+
+ ///
+ /// Comma delimited ordered list of language codes without any whitespace that
+ /// will be used in the "Accept-Language" HTTP header. Can be set globally
+ /// using the CefSettings.accept_language_list value or overridden on a per-
+ /// browser basis using the CefBrowserSettings.accept_language_list value. If
+ /// all values are empty then "en-US,en" will be used. This value will be
+ /// ignored if |cache_path| matches the CefSettings.cache_path value.
+ ///
+ cef_string_t accept_language_list;
+
+ ///
+ /// Comma delimited list of schemes supported by the associated
+ /// CefCookieManager. If |cookieable_schemes_exclude_defaults| is false (0)
+ /// the default schemes ("http", "https", "ws" and "wss") will also be
+ /// supported. Not specifying a |cookieable_schemes_list| value and setting
+ /// |cookieable_schemes_exclude_defaults| to true (1) will disable all loading
+ /// and saving of cookies. These values will be ignored if |cache_path|
+ /// matches the CefSettings.cache_path value.
+ ///
+ cef_string_t cookieable_schemes_list;
+ int cookieable_schemes_exclude_defaults;
+} cef_request_context_settings_t;
+
+///
+/// Browser initialization settings. Specify NULL or 0 to get the recommended
+/// default values. The consequences of using custom values may not be well
+/// tested. Many of these and other settings can also configured using command-
+/// line switches.
+///
+typedef struct _cef_browser_settings_t {
+ ///
+ /// Size of this structure.
+ ///
+ size_t size;
+
+ ///
+ /// The maximum rate in frames per second (fps) that CefRenderHandler::OnPaint
+ /// will be called for a windowless browser. The actual fps may be lower if
+ /// the browser cannot generate frames at the requested rate. The minimum
+ /// value is 1 and the maximum value is 60 (default 30). This value can also
+ /// be changed dynamically via CefBrowserHost::SetWindowlessFrameRate.
+ ///
+ int windowless_frame_rate;
+
+ /// BEGIN values that map to WebPreferences settings.
+
+ ///
+ /// Font settings.
+ ///
+ cef_string_t standard_font_family;
+ cef_string_t fixed_font_family;
+ cef_string_t serif_font_family;
+ cef_string_t sans_serif_font_family;
+ cef_string_t cursive_font_family;
+ cef_string_t fantasy_font_family;
+ int default_font_size;
+ int default_fixed_font_size;
+ int minimum_font_size;
+ int minimum_logical_font_size;
+
+ ///
+ /// Default encoding for Web content. If empty "ISO-8859-1" will be used. Also
+ /// configurable using the "default-encoding" command-line switch.
+ ///
+ cef_string_t default_encoding;
+
+ ///
+ /// Controls the loading of fonts from remote sources. Also configurable using
+ /// the "disable-remote-fonts" command-line switch.
+ ///
+ cef_state_t remote_fonts;
+
+ ///
+ /// Controls whether JavaScript can be executed. Also configurable using the
+ /// "disable-javascript" command-line switch.
+ ///
+ cef_state_t javascript;
+
+ ///
+ /// Controls whether JavaScript can be used to close windows that were not
+ /// opened via JavaScript. JavaScript can still be used to close windows that
+ /// were opened via JavaScript or that have no back/forward history. Also
+ /// configurable using the "disable-javascript-close-windows" command-line
+ /// switch.
+ ///
+ cef_state_t javascript_close_windows;
+
+ ///
+ /// Controls whether JavaScript can access the clipboard. Also configurable
+ /// using the "disable-javascript-access-clipboard" command-line switch.
+ ///
+ cef_state_t javascript_access_clipboard;
+
+ ///
+ /// Controls whether DOM pasting is supported in the editor via
+ /// execCommand("paste"). The |javascript_access_clipboard| setting must also
+ /// be enabled. Also configurable using the "disable-javascript-dom-paste"
+ /// command-line switch.
+ ///
+ cef_state_t javascript_dom_paste;
+
+ ///
+ /// Controls whether image URLs will be loaded from the network. A cached
+ /// image will still be rendered if requested. Also configurable using the
+ /// "disable-image-loading" command-line switch.
+ ///
+ cef_state_t image_loading;
+
+ ///
+ /// Controls whether standalone images will be shrunk to fit the page. Also
+ /// configurable using the "image-shrink-standalone-to-fit" command-line
+ /// switch.
+ ///
+ cef_state_t image_shrink_standalone_to_fit;
+
+ ///
+ /// Controls whether text areas can be resized. Also configurable using the
+ /// "disable-text-area-resize" command-line switch.
+ ///
+ cef_state_t text_area_resize;
+
+ ///
+ /// Controls whether the tab key can advance focus to links. Also configurable
+ /// using the "disable-tab-to-links" command-line switch.
+ ///
+ cef_state_t tab_to_links;
+
+ ///
+ /// Controls whether local storage can be used. Also configurable using the
+ /// "disable-local-storage" command-line switch.
+ ///
+ cef_state_t local_storage;
+
+ ///
+ /// Controls whether databases can be used. Also configurable using the
+ /// "disable-databases" command-line switch.
+ ///
+ cef_state_t databases;
+
+ ///
+ /// Controls whether WebGL can be used. Note that WebGL requires hardware
+ /// support and may not work on all systems even when enabled. Also
+ /// configurable using the "disable-webgl" command-line switch.
+ ///
+ cef_state_t webgl;
+
+ /// END values that map to WebPreferences settings.
+
+ ///
+ /// Background color used for the browser before a document is loaded and when
+ /// no document color is specified. The alpha component must be either fully
+ /// opaque (0xFF) or fully transparent (0x00). If the alpha component is fully
+ /// opaque then the RGB components will be used as the background color. If
+ /// the alpha component is fully transparent for a windowed browser then the
+ /// CefSettings.background_color value will be used. If the alpha component is
+ /// fully transparent for a windowless (off-screen) browser then transparent
+ /// painting will be enabled.
+ ///
+ cef_color_t background_color;
+
+ ///
+ /// Comma delimited ordered list of language codes without any whitespace that
+ /// will be used in the "Accept-Language" HTTP header. May be set globally
+ /// using the CefSettings.accept_language_list value. If both values are
+ /// empty then "en-US,en" will be used.
+ ///
+ cef_string_t accept_language_list;
+
+ ///
+ /// Controls whether the Chrome status bubble will be used. Only supported
+ /// with the Chrome runtime. For details about the status bubble see
+ /// https://www.chromium.org/user-experience/status-bubble/
+ ///
+ cef_state_t chrome_status_bubble;
+} cef_browser_settings_t;
+
+///
+/// Return value types.
+///
+typedef enum {
+ ///
+ /// Cancel immediately.
+ ///
+ RV_CANCEL = 0,
+
+ ///
+ /// Continue immediately.
+ ///
+ RV_CONTINUE,
+
+ ///
+ /// Continue asynchronously (usually via a callback).
+ ///
+ RV_CONTINUE_ASYNC,
+} cef_return_value_t;
+
+///
+/// URL component parts.
+///
+typedef struct _cef_urlparts_t {
+ ///
+ /// The complete URL specification.
+ ///
+ cef_string_t spec;
+
+ ///
+ /// Scheme component not including the colon (e.g., "http").
+ ///
+ cef_string_t scheme;
+
+ ///
+ /// User name component.
+ ///
+ cef_string_t username;
+
+ ///
+ /// Password component.
+ ///
+ cef_string_t password;
+
+ ///
+ /// Host component. This may be a hostname, an IPv4 address or an IPv6 literal
+ /// surrounded by square brackets (e.g., "[2001:db8::1]").
+ ///
+ cef_string_t host;
+
+ ///
+ /// Port number component.
+ ///
+ cef_string_t port;
+
+ ///
+ /// Origin contains just the scheme, host, and port from a URL. Equivalent to
+ /// clearing any username and password, replacing the path with a slash, and
+ /// clearing everything after that. This value will be empty for non-standard
+ /// URLs.
+ ///
+ cef_string_t origin;
+
+ ///
+ /// Path component including the first slash following the host.
+ ///
+ cef_string_t path;
+
+ ///
+ /// Query string component (i.e., everything following the '?').
+ ///
+ cef_string_t query;
+
+ ///
+ /// Fragment (hash) identifier component (i.e., the string following the '#').
+ ///
+ cef_string_t fragment;
+} cef_urlparts_t;
+
+///
+/// Cookie priority values.
+///
+typedef enum {
+ CEF_COOKIE_PRIORITY_LOW = -1,
+ CEF_COOKIE_PRIORITY_MEDIUM = 0,
+ CEF_COOKIE_PRIORITY_HIGH = 1,
+} cef_cookie_priority_t;
+
+///
+/// Cookie same site values.
+///
+typedef enum {
+ CEF_COOKIE_SAME_SITE_UNSPECIFIED,
+ CEF_COOKIE_SAME_SITE_NO_RESTRICTION,
+ CEF_COOKIE_SAME_SITE_LAX_MODE,
+ CEF_COOKIE_SAME_SITE_STRICT_MODE,
+} cef_cookie_same_site_t;
+
+///
+/// Cookie information.
+///
+typedef struct _cef_cookie_t {
+ ///
+ /// The cookie name.
+ ///
+ cef_string_t name;
+
+ ///
+ /// The cookie value.
+ ///
+ cef_string_t value;
+
+ ///
+ /// If |domain| is empty a host cookie will be created instead of a domain
+ /// cookie. Domain cookies are stored with a leading "." and are visible to
+ /// sub-domains whereas host cookies are not.
+ ///
+ cef_string_t domain;
+
+ ///
+ /// If |path| is non-empty only URLs at or below the path will get the cookie
+ /// value.
+ ///
+ cef_string_t path;
+
+ ///
+ /// If |secure| is true the cookie will only be sent for HTTPS requests.
+ ///
+ int secure;
+
+ ///
+ /// If |httponly| is true the cookie will only be sent for HTTP requests.
+ ///
+ int httponly;
+
+ ///
+ /// The cookie creation date. This is automatically populated by the system on
+ /// cookie creation.
+ ///
+ cef_basetime_t creation;
+
+ ///
+ /// The cookie last access date. This is automatically populated by the system
+ /// on access.
+ ///
+ cef_basetime_t last_access;
+
+ ///
+ /// The cookie expiration date is only valid if |has_expires| is true.
+ ///
+ int has_expires;
+ cef_basetime_t expires;
+
+ ///
+ /// Same site.
+ ///
+ cef_cookie_same_site_t same_site;
+
+ ///
+ /// Priority.
+ ///
+ cef_cookie_priority_t priority;
+} cef_cookie_t;
+
+///
+/// Process termination status values.
+///
+typedef enum {
+ ///
+ /// Non-zero exit status.
+ ///
+ TS_ABNORMAL_TERMINATION,
+
+ ///
+ /// SIGKILL or task manager kill.
+ ///
+ TS_PROCESS_WAS_KILLED,
+
+ ///
+ /// Segmentation fault.
+ ///
+ TS_PROCESS_CRASHED,
+
+ ///
+ /// Out of memory. Some platforms may use TS_PROCESS_CRASHED instead.
+ ///
+ TS_PROCESS_OOM,
+} cef_termination_status_t;
+
+///
+/// Path key values.
+///
+typedef enum {
+ ///
+ /// Current directory.
+ ///
+ PK_DIR_CURRENT,
+
+ ///
+ /// Directory containing PK_FILE_EXE.
+ ///
+ PK_DIR_EXE,
+
+ ///
+ /// Directory containing PK_FILE_MODULE.
+ ///
+ PK_DIR_MODULE,
+
+ ///
+ /// Temporary directory.
+ ///
+ PK_DIR_TEMP,
+
+ ///
+ /// Path and filename of the current executable.
+ ///
+ PK_FILE_EXE,
+
+ ///
+ /// Path and filename of the module containing the CEF code (usually the
+ /// libcef module).
+ ///
+ PK_FILE_MODULE,
+
+ ///
+ /// "Local Settings\Application Data" directory under the user profile
+ /// directory on Windows.
+ ///
+ PK_LOCAL_APP_DATA,
+
+ ///
+ /// "Application Data" directory under the user profile directory on Windows
+ /// and "~/Library/Application Support" directory on MacOS.
+ ///
+ PK_USER_DATA,
+
+ ///
+ /// Directory containing application resources. Can be configured via
+ /// CefSettings.resources_dir_path.
+ ///
+ PK_DIR_RESOURCES,
+} cef_path_key_t;
+
+///
+/// Storage types.
+///
+typedef enum {
+ ST_LOCALSTORAGE = 0,
+ ST_SESSIONSTORAGE,
+} cef_storage_type_t;
+
+///
+/// Supported error code values. For the complete list of error values see
+/// "include/base/internal/cef_net_error_list.h".
+///
+typedef enum {
+ // No error.
+ ERR_NONE = 0,
+
+#define NET_ERROR(label, value) ERR_##label = value,
+#include "include/base/internal/cef_net_error_list.h"
+#undef NET_ERROR
+
+} cef_errorcode_t;
+
+///
+/// Supported certificate status code values. See net\cert\cert_status_flags.h
+/// for more information. CERT_STATUS_NONE is new in CEF because we use an
+/// enum while cert_status_flags.h uses a typedef and static const variables.
+///
+typedef enum {
+ CERT_STATUS_NONE = 0,
+ CERT_STATUS_COMMON_NAME_INVALID = 1 << 0,
+ CERT_STATUS_DATE_INVALID = 1 << 1,
+ CERT_STATUS_AUTHORITY_INVALID = 1 << 2,
+ // 1 << 3 is reserved for ERR_CERT_CONTAINS_ERRORS (not useful with WinHTTP).
+ CERT_STATUS_NO_REVOCATION_MECHANISM = 1 << 4,
+ CERT_STATUS_UNABLE_TO_CHECK_REVOCATION = 1 << 5,
+ CERT_STATUS_REVOKED = 1 << 6,
+ CERT_STATUS_INVALID = 1 << 7,
+ CERT_STATUS_WEAK_SIGNATURE_ALGORITHM = 1 << 8,
+ // 1 << 9 was used for CERT_STATUS_NOT_IN_DNS
+ CERT_STATUS_NON_UNIQUE_NAME = 1 << 10,
+ CERT_STATUS_WEAK_KEY = 1 << 11,
+ // 1 << 12 was used for CERT_STATUS_WEAK_DH_KEY
+ CERT_STATUS_PINNED_KEY_MISSING = 1 << 13,
+ CERT_STATUS_NAME_CONSTRAINT_VIOLATION = 1 << 14,
+ CERT_STATUS_VALIDITY_TOO_LONG = 1 << 15,
+
+ // Bits 16 to 31 are for non-error statuses.
+ CERT_STATUS_IS_EV = 1 << 16,
+ CERT_STATUS_REV_CHECKING_ENABLED = 1 << 17,
+ // Bit 18 was CERT_STATUS_IS_DNSSEC
+ CERT_STATUS_SHA1_SIGNATURE_PRESENT = 1 << 19,
+ CERT_STATUS_CT_COMPLIANCE_FAILED = 1 << 20,
+} cef_cert_status_t;
+
+///
+/// The manner in which a link click should be opened. These constants match
+/// their equivalents in Chromium's window_open_disposition.h and should not be
+/// renumbered.
+///
+typedef enum {
+ WOD_UNKNOWN,
+
+ ///
+ /// Current tab. This is the default in most cases.
+ ///
+ WOD_CURRENT_TAB,
+
+ ///
+ /// Indicates that only one tab with the url should exist in the same window.
+ ///
+ WOD_SINGLETON_TAB,
+
+ ///
+ /// Shift key + Middle mouse button or meta/ctrl key while clicking.
+ ///
+ WOD_NEW_FOREGROUND_TAB,
+
+ ///
+ /// Middle mouse button or meta/ctrl key while clicking.
+ ///
+ WOD_NEW_BACKGROUND_TAB,
+
+ ///
+ /// New popup window.
+ ///
+ WOD_NEW_POPUP,
+
+ ///
+ /// Shift key while clicking.
+ ///
+ WOD_NEW_WINDOW,
+
+ ///
+ /// Alt key while clicking.
+ ///
+ WOD_SAVE_TO_DISK,
+
+ ///
+ /// New off-the-record (incognito) window.
+ ///
+ WOD_OFF_THE_RECORD,
+
+ ///
+ /// Special case error condition from the renderer.
+ ///
+ WOD_IGNORE_ACTION,
+
+ ///
+ /// Activates an existing tab containing the url, rather than navigating.
+ /// This is similar to SINGLETON_TAB, but searches across all windows from
+ /// the current profile and anonymity (instead of just the current one);
+ /// closes the current tab on switching if the current tab was the NTP with
+ /// no session history; and behaves like CURRENT_TAB instead of
+ /// NEW_FOREGROUND_TAB when no existing tab is found.
+ ///
+ WOD_SWITCH_TO_TAB,
+
+ ///
+ /// Creates a new document picture-in-picture window showing a child WebView.
+ ///
+ WOD_NEW_PICTURE_IN_PICTURE,
+} cef_window_open_disposition_t;
+
+///
+/// "Verb" of a drag-and-drop operation as negotiated between the source and
+/// destination. These constants match their equivalents in WebCore's
+/// DragActions.h and should not be renumbered.
+///
+typedef enum {
+ DRAG_OPERATION_NONE = 0,
+ DRAG_OPERATION_COPY = 1,
+ DRAG_OPERATION_LINK = 2,
+ DRAG_OPERATION_GENERIC = 4,
+ DRAG_OPERATION_PRIVATE = 8,
+ DRAG_OPERATION_MOVE = 16,
+ DRAG_OPERATION_DELETE = 32,
+ DRAG_OPERATION_EVERY = UINT_MAX
+} cef_drag_operations_mask_t;
+
+///
+/// Input mode of a virtual keyboard. These constants match their equivalents
+/// in Chromium's text_input_mode.h and should not be renumbered.
+/// See https://html.spec.whatwg.org/#input-modalities:-the-inputmode-attribute
+///
+typedef enum {
+ CEF_TEXT_INPUT_MODE_DEFAULT,
+ CEF_TEXT_INPUT_MODE_NONE,
+ CEF_TEXT_INPUT_MODE_TEXT,
+ CEF_TEXT_INPUT_MODE_TEL,
+ CEF_TEXT_INPUT_MODE_URL,
+ CEF_TEXT_INPUT_MODE_EMAIL,
+ CEF_TEXT_INPUT_MODE_NUMERIC,
+ CEF_TEXT_INPUT_MODE_DECIMAL,
+ CEF_TEXT_INPUT_MODE_SEARCH,
+
+ CEF_TEXT_INPUT_MODE_MAX = CEF_TEXT_INPUT_MODE_SEARCH,
+} cef_text_input_mode_t;
+
+///
+/// V8 access control values.
+///
+typedef enum {
+ V8_ACCESS_CONTROL_DEFAULT = 0,
+ V8_ACCESS_CONTROL_ALL_CAN_READ = 1,
+ V8_ACCESS_CONTROL_ALL_CAN_WRITE = 1 << 1,
+ V8_ACCESS_CONTROL_PROHIBITS_OVERWRITING = 1 << 2
+} cef_v8_accesscontrol_t;
+
+///
+/// V8 property attribute values.
+///
+typedef enum {
+ ///
+ /// Writeable, Enumerable, Configurable
+ ///
+ V8_PROPERTY_ATTRIBUTE_NONE = 0,
+
+ ///
+ /// Not writeable
+ ///
+ V8_PROPERTY_ATTRIBUTE_READONLY = 1 << 0,
+
+ ///
+ /// Not enumerable
+ ///
+ V8_PROPERTY_ATTRIBUTE_DONTENUM = 1 << 1,
+
+ ///
+ /// Not configurable
+ ///
+ V8_PROPERTY_ATTRIBUTE_DONTDELETE = 1 << 2
+} cef_v8_propertyattribute_t;
+
+///
+/// Post data elements may represent either bytes or files.
+///
+typedef enum {
+ PDE_TYPE_EMPTY = 0,
+ PDE_TYPE_BYTES,
+ PDE_TYPE_FILE,
+} cef_postdataelement_type_t;
+
+///
+/// Resource type for a request. These constants match their equivalents in
+/// Chromium's ResourceType and should not be renumbered.
+///
+typedef enum {
+ ///
+ /// Top level page.
+ ///
+ RT_MAIN_FRAME = 0,
+
+ ///
+ /// Frame or iframe.
+ ///
+ RT_SUB_FRAME,
+
+ ///
+ /// CSS stylesheet.
+ ///
+ RT_STYLESHEET,
+
+ ///
+ /// External script.
+ ///
+ RT_SCRIPT,
+
+ ///
+ /// Image (jpg/gif/png/etc).
+ ///
+ RT_IMAGE,
+
+ ///
+ /// Font.
+ ///
+ RT_FONT_RESOURCE,
+
+ ///
+ /// Some other subresource. This is the default type if the actual type is
+ /// unknown.
+ ///
+ RT_SUB_RESOURCE,
+
+ ///
+ /// Object (or embed) tag for a plugin, or a resource that a plugin requested.
+ ///
+ RT_OBJECT,
+
+ ///
+ /// Media resource.
+ ///
+ RT_MEDIA,
+
+ ///
+ /// Main resource of a dedicated worker.
+ ///
+ RT_WORKER,
+
+ ///
+ /// Main resource of a shared worker.
+ ///
+ RT_SHARED_WORKER,
+
+ ///
+ /// Explicitly requested prefetch.
+ ///
+ RT_PREFETCH,
+
+ ///
+ /// Favicon.
+ ///
+ RT_FAVICON,
+
+ ///
+ /// XMLHttpRequest.
+ ///
+ RT_XHR,
+
+ ///
+ /// A request for a "<ping>".
+ ///
+ RT_PING,
+
+ ///
+ /// Main resource of a service worker.
+ ///
+ RT_SERVICE_WORKER,
+
+ ///
+ /// A report of Content Security Policy violations.
+ ///
+ RT_CSP_REPORT,
+
+ ///
+ /// A resource that a plugin requested.
+ ///
+ RT_PLUGIN_RESOURCE,
+
+ ///
+ /// A main-frame service worker navigation preload request.
+ ///
+ RT_NAVIGATION_PRELOAD_MAIN_FRAME = 19,
+
+ ///
+ /// A sub-frame service worker navigation preload request.
+ ///
+ RT_NAVIGATION_PRELOAD_SUB_FRAME,
+} cef_resource_type_t;
+
+///
+/// Transition type for a request. Made up of one source value and 0 or more
+/// qualifiers.
+///
+typedef enum {
+ ///
+ /// Source is a link click or the JavaScript window.open function. This is
+ /// also the default value for requests like sub-resource loads that are not
+ /// navigations.
+ ///
+ TT_LINK = 0,
+
+ ///
+ /// Source is some other "explicit" navigation. This is the default value for
+ /// navigations where the actual type is unknown. See also
+ /// TT_DIRECT_LOAD_FLAG.
+ ///
+ TT_EXPLICIT = 1,
+
+ ///
+ /// User got to this page through a suggestion in the UI (for example, via the
+ /// destinations page). Chrome runtime only.
+ ///
+ TT_AUTO_BOOKMARK = 2,
+
+ ///
+ /// Source is a subframe navigation. This is any content that is automatically
+ /// loaded in a non-toplevel frame. For example, if a page consists of several
+ /// frames containing ads, those ad URLs will have this transition type.
+ /// The user may not even realize the content in these pages is a separate
+ /// frame, so may not care about the URL.
+ ///
+ TT_AUTO_SUBFRAME = 3,
+
+ ///
+ /// Source is a subframe navigation explicitly requested by the user that will
+ /// generate new navigation entries in the back/forward list. These are
+ /// probably more important than frames that were automatically loaded in
+ /// the background because the user probably cares about the fact that this
+ /// link was loaded.
+ ///
+ TT_MANUAL_SUBFRAME = 4,
+
+ ///
+ /// User got to this page by typing in the URL bar and selecting an entry
+ /// that did not look like a URL. For example, a match might have the URL
+ /// of a Google search result page, but appear like "Search Google for ...".
+ /// These are not quite the same as EXPLICIT navigations because the user
+ /// didn't type or see the destination URL. Chrome runtime only.
+ /// See also TT_KEYWORD.
+ ///
+ TT_GENERATED = 5,
+
+ ///
+ /// This is a toplevel navigation. This is any content that is automatically
+ /// loaded in a toplevel frame. For example, opening a tab to show the ASH
+ /// screen saver, opening the devtools window, opening the NTP after the safe
+ /// browsing warning, opening web-based dialog boxes are examples of
+ /// AUTO_TOPLEVEL navigations. Chrome runtime only.
+ ///
+ TT_AUTO_TOPLEVEL = 6,
+
+ ///
+ /// Source is a form submission by the user. NOTE: In some situations
+ /// submitting a form does not result in this transition type. This can happen
+ /// if the form uses a script to submit the contents.
+ ///
+ TT_FORM_SUBMIT = 7,
+
+ ///
+ /// Source is a "reload" of the page via the Reload function or by re-visiting
+ /// the same URL. NOTE: This is distinct from the concept of whether a
+ /// particular load uses "reload semantics" (i.e. bypasses cached data).
+ ///
+ TT_RELOAD = 8,
+
+ ///
+ /// The url was generated from a replaceable keyword other than the default
+ /// search provider. If the user types a keyword (which also applies to
+ /// tab-to-search) in the omnibox this qualifier is applied to the transition
+ /// type of the generated url. TemplateURLModel then may generate an
+ /// additional visit with a transition type of TT_KEYWORD_GENERATED against
+ /// the url 'http://' + keyword. For example, if you do a tab-to-search
+ /// against wikipedia the generated url has a transition qualifer of
+ /// TT_KEYWORD, and TemplateURLModel generates a visit for 'wikipedia.org'
+ /// with a transition type of TT_KEYWORD_GENERATED. Chrome runtime only.
+ ///
+ TT_KEYWORD = 9,
+
+ ///
+ /// Corresponds to a visit generated for a keyword. See description of
+ /// TT_KEYWORD for more details. Chrome runtime only.
+ ///
+ TT_KEYWORD_GENERATED = 10,
+
+ ///
+ /// General mask defining the bits used for the source values.
+ ///
+ TT_SOURCE_MASK = 0xFF,
+
+ /// Qualifiers.
+ /// Any of the core values above can be augmented by one or more qualifiers.
+ /// These qualifiers further define the transition.
+
+ ///
+ /// Attempted to visit a URL but was blocked.
+ ///
+ TT_BLOCKED_FLAG = 0x00800000,
+
+ ///
+ /// Used the Forward or Back function to navigate among browsing history.
+ /// Will be ORed to the transition type for the original load.
+ ///
+ TT_FORWARD_BACK_FLAG = 0x01000000,
+
+ ///
+ /// Loaded a URL directly via CreateBrowser, LoadURL or LoadRequest.
+ ///
+ TT_DIRECT_LOAD_FLAG = 0x02000000,
+
+ ///
+ /// User is navigating to the home page. Chrome runtime only.
+ ///
+ TT_HOME_PAGE_FLAG = 0x04000000,
+
+ ///
+ /// The transition originated from an external application; the exact
+ /// definition of this is embedder dependent. Chrome runtime and
+ /// extension system only.
+ ///
+ TT_FROM_API_FLAG = 0x08000000,
+
+ ///
+ /// The beginning of a navigation chain.
+ ///
+ TT_CHAIN_START_FLAG = 0x10000000,
+
+ ///
+ /// The last transition in a redirect chain.
+ ///
+ TT_CHAIN_END_FLAG = 0x20000000,
+
+ ///
+ /// Redirects caused by JavaScript or a meta refresh tag on the page.
+ ///
+ TT_CLIENT_REDIRECT_FLAG = 0x40000000,
+
+ ///
+ /// Redirects sent from the server by HTTP headers.
+ ///
+ TT_SERVER_REDIRECT_FLAG = 0x80000000,
+
+ ///
+ /// Used to test whether a transition involves a redirect.
+ ///
+ TT_IS_REDIRECT_MASK = 0xC0000000,
+
+ ///
+ /// General mask defining the bits used for the qualifiers.
+ ///
+ TT_QUALIFIER_MASK = 0xFFFFFF00,
+} cef_transition_type_t;
+
+///
+/// Flags used to customize the behavior of CefURLRequest.
+///
+typedef enum {
+ ///
+ /// Default behavior.
+ ///
+ UR_FLAG_NONE = 0,
+
+ ///
+ /// If set the cache will be skipped when handling the request. Setting this
+ /// value is equivalent to specifying the "Cache-Control: no-cache" request
+ /// header. Setting this value in combination with UR_FLAG_ONLY_FROM_CACHE
+ /// will cause the request to fail.
+ ///
+ UR_FLAG_SKIP_CACHE = 1 << 0,
+
+ ///
+ /// If set the request will fail if it cannot be served from the cache (or
+ /// some equivalent local store). Setting this value is equivalent to
+ /// specifying the "Cache-Control: only-if-cached" request header. Setting
+ /// this value in combination with UR_FLAG_SKIP_CACHE or UR_FLAG_DISABLE_CACHE
+ /// will cause the request to fail.
+ ///
+ UR_FLAG_ONLY_FROM_CACHE = 1 << 1,
+
+ ///
+ /// If set the cache will not be used at all. Setting this value is equivalent
+ /// to specifying the "Cache-Control: no-store" request header. Setting this
+ /// value in combination with UR_FLAG_ONLY_FROM_CACHE will cause the request
+ /// to fail.
+ ///
+ UR_FLAG_DISABLE_CACHE = 1 << 2,
+
+ ///
+ /// If set user name, password, and cookies may be sent with the request, and
+ /// cookies may be saved from the response.
+ ///
+ UR_FLAG_ALLOW_STORED_CREDENTIALS = 1 << 3,
+
+ ///
+ /// If set upload progress events will be generated when a request has a body.
+ ///
+ UR_FLAG_REPORT_UPLOAD_PROGRESS = 1 << 4,
+
+ ///
+ /// If set the CefURLRequestClient::OnDownloadData method will not be called.
+ ///
+ UR_FLAG_NO_DOWNLOAD_DATA = 1 << 5,
+
+ ///
+ /// If set 5XX redirect errors will be propagated to the observer instead of
+ /// automatically re-tried. This currently only applies for requests
+ /// originated in the browser process.
+ ///
+ UR_FLAG_NO_RETRY_ON_5XX = 1 << 6,
+
+ ///
+ /// If set 3XX responses will cause the fetch to halt immediately rather than
+ /// continue through the redirect.
+ ///
+ UR_FLAG_STOP_ON_REDIRECT = 1 << 7,
+} cef_urlrequest_flags_t;
+
+///
+/// Flags that represent CefURLRequest status.
+///
+typedef enum {
+ ///
+ /// Unknown status.
+ ///
+ UR_UNKNOWN = 0,
+
+ ///
+ /// Request succeeded.
+ ///
+ UR_SUCCESS,
+
+ ///
+ /// An IO request is pending, and the caller will be informed when it is
+ /// completed.
+ ///
+ UR_IO_PENDING,
+
+ ///
+ /// Request was canceled programatically.
+ ///
+ UR_CANCELED,
+
+ ///
+ /// Request failed for some reason.
+ ///
+ UR_FAILED,
+} cef_urlrequest_status_t;
+
+/// Structure representing a draggable region.
+///
+typedef struct _cef_draggable_region_t {
+ ///
+ /// Bounds of the region.
+ ///
+ cef_rect_t bounds;
+
+ ///
+ /// True (1) this this region is draggable and false (0) otherwise.
+ ///
+ int draggable;
+} cef_draggable_region_t;
+
+///
+/// Existing process IDs.
+///
+typedef enum {
+ ///
+ /// Browser process.
+ ///
+ PID_BROWSER,
+ ///
+ /// Renderer process.
+ ///
+ PID_RENDERER,
+} cef_process_id_t;
+
+///
+/// Existing thread IDs.
+///
+typedef enum {
+ // BROWSER PROCESS THREADS -- Only available in the browser process.
+
+ ///
+ /// The main thread in the browser. This will be the same as the main
+ /// application thread if CefInitialize() is called with a
+ /// CefSettings.multi_threaded_message_loop value of false. Do not perform
+ /// blocking tasks on this thread. All tasks posted after
+ /// CefBrowserProcessHandler::OnContextInitialized() and before CefShutdown()
+ /// are guaranteed to run. This thread will outlive all other CEF threads.
+ ///
+ TID_UI,
+
+ ///
+ /// Used for blocking tasks like file system access where the user won't
+ /// notice if the task takes an arbitrarily long time to complete. All tasks
+ /// posted after CefBrowserProcessHandler::OnContextInitialized() and before
+ /// CefShutdown() are guaranteed to run.
+ ///
+ TID_FILE_BACKGROUND,
+
+ ///
+ /// Used for blocking tasks like file system access that affect UI or
+ /// responsiveness of future user interactions. Do not use if an immediate
+ /// response to a user interaction is expected. All tasks posted after
+ /// CefBrowserProcessHandler::OnContextInitialized() and before CefShutdown()
+ /// are guaranteed to run.
+ /// Examples:
+ /// - Updating the UI to reflect progress on a long task.
+ /// - Loading data that might be shown in the UI after a future user
+ /// interaction.
+ ///
+ TID_FILE_USER_VISIBLE,
+
+ ///
+ /// Used for blocking tasks like file system access that affect UI
+ /// immediately after a user interaction. All tasks posted after
+ /// CefBrowserProcessHandler::OnContextInitialized() and before CefShutdown()
+ /// are guaranteed to run.
+ /// Example: Generating data shown in the UI immediately after a click.
+ ///
+ TID_FILE_USER_BLOCKING,
+
+ ///
+ /// Used to launch and terminate browser processes.
+ ///
+ TID_PROCESS_LAUNCHER,
+
+ ///
+ /// Used to process IPC and network messages. Do not perform blocking tasks on
+ /// this thread. All tasks posted after
+ /// CefBrowserProcessHandler::OnContextInitialized() and before CefShutdown()
+ /// are guaranteed to run.
+ ///
+ TID_IO,
+
+ // RENDER PROCESS THREADS -- Only available in the render process.
+
+ ///
+ /// The main thread in the renderer. Used for all WebKit and V8 interaction.
+ /// Tasks may be posted to this thread after
+ /// CefRenderProcessHandler::OnWebKitInitialized but are not guaranteed to
+ /// run before sub-process termination (sub-processes may be killed at any
+ /// time without warning).
+ ///
+ TID_RENDERER,
+} cef_thread_id_t;
+
+///
+/// Thread priority values listed in increasing order of importance.
+///
+typedef enum {
+ ///
+ /// Suitable for threads that shouldn't disrupt high priority work.
+ ///
+ TP_BACKGROUND,
+
+ ///
+ /// Default priority level.
+ ///
+ TP_NORMAL,
+
+ ///
+ /// Suitable for threads which generate data for the display (at ~60Hz).
+ ///
+ TP_DISPLAY,
+
+ ///
+ /// Suitable for low-latency, glitch-resistant audio.
+ ///
+ TP_REALTIME_AUDIO,
+} cef_thread_priority_t;
+
+///
+/// Message loop types. Indicates the set of asynchronous events that a message
+/// loop can process.
+///
+typedef enum {
+ ///
+ /// Supports tasks and timers.
+ ///
+ ML_TYPE_DEFAULT,
+
+ ///
+ /// Supports tasks, timers and native UI events (e.g. Windows messages).
+ ///
+ ML_TYPE_UI,
+
+ ///
+ /// Supports tasks, timers and asynchronous IO events.
+ ///
+ ML_TYPE_IO,
+} cef_message_loop_type_t;
+
+///
+/// Windows COM initialization mode. Specifies how COM will be initialized for a
+/// new thread.
+///
+typedef enum {
+ ///
+ /// No COM initialization.
+ ///
+ COM_INIT_MODE_NONE,
+
+ ///
+ /// Initialize COM using single-threaded apartments.
+ ///
+ COM_INIT_MODE_STA,
+
+ ///
+ /// Initialize COM using multi-threaded apartments.
+ ///
+ COM_INIT_MODE_MTA,
+} cef_com_init_mode_t;
+
+///
+/// Supported value types.
+///
+typedef enum {
+ VTYPE_INVALID = 0,
+ VTYPE_NULL,
+ VTYPE_BOOL,
+ VTYPE_INT,
+ VTYPE_DOUBLE,
+ VTYPE_STRING,
+ VTYPE_BINARY,
+ VTYPE_DICTIONARY,
+ VTYPE_LIST,
+} cef_value_type_t;
+
+///
+/// Supported JavaScript dialog types.
+///
+typedef enum {
+ JSDIALOGTYPE_ALERT = 0,
+ JSDIALOGTYPE_CONFIRM,
+ JSDIALOGTYPE_PROMPT,
+} cef_jsdialog_type_t;
+
+///
+/// Screen information used when window rendering is disabled. This structure is
+/// passed as a parameter to CefRenderHandler::GetScreenInfo and should be
+/// filled in by the client.
+///
+typedef struct _cef_screen_info_t {
+ ///
+ /// Device scale factor. Specifies the ratio between physical and logical
+ /// pixels.
+ ///
+ float device_scale_factor;
+
+ ///
+ /// The screen depth in bits per pixel.
+ ///
+ int depth;
+
+ ///
+ /// The bits per color component. This assumes that the colors are balanced
+ /// equally.
+ ///
+ int depth_per_component;
+
+ ///
+ /// This can be true for black and white printers.
+ ///
+ int is_monochrome;
+
+ ///
+ /// This is set from the rcMonitor member of MONITORINFOEX, to whit:
+ /// "A RECT structure that specifies the display monitor rectangle,
+ /// expressed in virtual-screen coordinates. Note that if the monitor
+ /// is not the primary display monitor, some of the rectangle's
+ /// coordinates may be negative values."
+ //
+ /// The |rect| and |available_rect| properties are used to determine the
+ /// available surface for rendering popup views.
+ ///
+ cef_rect_t rect;
+
+ ///
+ /// This is set from the rcWork member of MONITORINFOEX, to whit:
+ /// "A RECT structure that specifies the work area rectangle of the
+ /// display monitor that can be used by applications, expressed in
+ /// virtual-screen coordinates. Windows uses this rectangle to
+ /// maximize an application on the monitor. The rest of the area in
+ /// rcMonitor contains system windows such as the task bar and side
+ /// bars. Note that if the monitor is not the primary display monitor,
+ /// some of the rectangle's coordinates may be negative values".
+ //
+ /// The |rect| and |available_rect| properties are used to determine the
+ /// available surface for rendering popup views.
+ ///
+ cef_rect_t available_rect;
+} cef_screen_info_t;
+
+///
+/// Supported menu IDs. Non-English translations can be provided for the
+/// IDS_MENU_* strings in CefResourceBundleHandler::GetLocalizedString().
+///
+typedef enum {
+ // Navigation.
+ MENU_ID_BACK = 100,
+ MENU_ID_FORWARD = 101,
+ MENU_ID_RELOAD = 102,
+ MENU_ID_RELOAD_NOCACHE = 103,
+ MENU_ID_STOPLOAD = 104,
+
+ // Editing.
+ MENU_ID_UNDO = 110,
+ MENU_ID_REDO = 111,
+ MENU_ID_CUT = 112,
+ MENU_ID_COPY = 113,
+ MENU_ID_PASTE = 114,
+ MENU_ID_DELETE = 115,
+ MENU_ID_SELECT_ALL = 116,
+
+ // Miscellaneous.
+ MENU_ID_FIND = 130,
+ MENU_ID_PRINT = 131,
+ MENU_ID_VIEW_SOURCE = 132,
+
+ // Spell checking word correction suggestions.
+ MENU_ID_SPELLCHECK_SUGGESTION_0 = 200,
+ MENU_ID_SPELLCHECK_SUGGESTION_1 = 201,
+ MENU_ID_SPELLCHECK_SUGGESTION_2 = 202,
+ MENU_ID_SPELLCHECK_SUGGESTION_3 = 203,
+ MENU_ID_SPELLCHECK_SUGGESTION_4 = 204,
+ MENU_ID_SPELLCHECK_SUGGESTION_LAST = 204,
+ MENU_ID_NO_SPELLING_SUGGESTIONS = 205,
+ MENU_ID_ADD_TO_DICTIONARY = 206,
+
+ // Custom menu items originating from the renderer process.
+ MENU_ID_CUSTOM_FIRST = 220,
+ MENU_ID_CUSTOM_LAST = 250,
+
+ // All user-defined menu IDs should come between MENU_ID_USER_FIRST and
+ // MENU_ID_USER_LAST to avoid overlapping the Chromium and CEF ID ranges
+ // defined in the tools/gritsettings/resource_ids file.
+ MENU_ID_USER_FIRST = 26500,
+ MENU_ID_USER_LAST = 28500,
+} cef_menu_id_t;
+
+///
+/// Mouse button types.
+///
+typedef enum {
+ MBT_LEFT = 0,
+ MBT_MIDDLE,
+ MBT_RIGHT,
+} cef_mouse_button_type_t;
+
+///
+/// Structure representing mouse event information.
+///
+typedef struct _cef_mouse_event_t {
+ ///
+ /// X coordinate relative to the left side of the view.
+ ///
+ int x;
+
+ ///
+ /// Y coordinate relative to the top side of the view.
+ ///
+ int y;
+
+ ///
+ /// Bit flags describing any pressed modifier keys. See
+ /// cef_event_flags_t for values.
+ ///
+ uint32 modifiers;
+} cef_mouse_event_t;
+
+///
+/// Touch points states types.
+///
+typedef enum {
+ CEF_TET_RELEASED = 0,
+ CEF_TET_PRESSED,
+ CEF_TET_MOVED,
+ CEF_TET_CANCELLED
+} cef_touch_event_type_t;
+
+///
+/// The device type that caused the event.
+///
+typedef enum {
+ CEF_POINTER_TYPE_TOUCH = 0,
+ CEF_POINTER_TYPE_MOUSE,
+ CEF_POINTER_TYPE_PEN,
+ CEF_POINTER_TYPE_ERASER,
+ CEF_POINTER_TYPE_UNKNOWN
+} cef_pointer_type_t;
+
+///
+/// Structure representing touch event information.
+///
+typedef struct _cef_touch_event_t {
+ ///
+ /// Id of a touch point. Must be unique per touch, can be any number except
+ /// -1. Note that a maximum of 16 concurrent touches will be tracked; touches
+ /// beyond that will be ignored.
+ ///
+ int id;
+
+ ///
+ /// X coordinate relative to the left side of the view.
+ ///
+ float x;
+
+ ///
+ /// Y coordinate relative to the top side of the view.
+ ///
+ float y;
+
+ ///
+ /// X radius in pixels. Set to 0 if not applicable.
+ ///
+ float radius_x;
+
+ ///
+ /// Y radius in pixels. Set to 0 if not applicable.
+ ///
+ float radius_y;
+
+ ///
+ /// Rotation angle in radians. Set to 0 if not applicable.
+ ///
+ float rotation_angle;
+
+ ///
+ /// The normalized pressure of the pointer input in the range of [0,1].
+ /// Set to 0 if not applicable.
+ ///
+ float pressure;
+
+ ///
+ /// The state of the touch point. Touches begin with one CEF_TET_PRESSED event
+ /// followed by zero or more CEF_TET_MOVED events and finally one
+ /// CEF_TET_RELEASED or CEF_TET_CANCELLED event. Events not respecting this
+ /// order will be ignored.
+ ///
+ cef_touch_event_type_t type;
+
+ ///
+ /// Bit flags describing any pressed modifier keys. See
+ /// cef_event_flags_t for values.
+ ///
+ uint32 modifiers;
+
+ ///
+ /// The device type that caused the event.
+ ///
+ cef_pointer_type_t pointer_type;
+
+} cef_touch_event_t;
+
+///
+/// Paint element types.
+///
+typedef enum {
+ PET_VIEW = 0,
+ PET_POPUP,
+} cef_paint_element_type_t;
+
+///
+/// Supported event bit flags.
+///
+typedef enum {
+ EVENTFLAG_NONE = 0,
+ EVENTFLAG_CAPS_LOCK_ON = 1 << 0,
+ EVENTFLAG_SHIFT_DOWN = 1 << 1,
+ EVENTFLAG_CONTROL_DOWN = 1 << 2,
+ EVENTFLAG_ALT_DOWN = 1 << 3,
+ EVENTFLAG_LEFT_MOUSE_BUTTON = 1 << 4,
+ EVENTFLAG_MIDDLE_MOUSE_BUTTON = 1 << 5,
+ EVENTFLAG_RIGHT_MOUSE_BUTTON = 1 << 6,
+ /// Mac OS-X command key.
+ EVENTFLAG_COMMAND_DOWN = 1 << 7,
+ EVENTFLAG_NUM_LOCK_ON = 1 << 8,
+ EVENTFLAG_IS_KEY_PAD = 1 << 9,
+ EVENTFLAG_IS_LEFT = 1 << 10,
+ EVENTFLAG_IS_RIGHT = 1 << 11,
+ EVENTFLAG_ALTGR_DOWN = 1 << 12,
+ EVENTFLAG_IS_REPEAT = 1 << 13,
+} cef_event_flags_t;
+
+///
+/// Supported menu item types.
+///
+typedef enum {
+ MENUITEMTYPE_NONE,
+ MENUITEMTYPE_COMMAND,
+ MENUITEMTYPE_CHECK,
+ MENUITEMTYPE_RADIO,
+ MENUITEMTYPE_SEPARATOR,
+ MENUITEMTYPE_SUBMENU,
+} cef_menu_item_type_t;
+
+///
+/// Supported context menu type flags.
+///
+typedef enum {
+ ///
+ /// No node is selected.
+ ///
+ CM_TYPEFLAG_NONE = 0,
+ ///
+ /// The top page is selected.
+ ///
+ CM_TYPEFLAG_PAGE = 1 << 0,
+ ///
+ /// A subframe page is selected.
+ ///
+ CM_TYPEFLAG_FRAME = 1 << 1,
+ ///
+ /// A link is selected.
+ ///
+ CM_TYPEFLAG_LINK = 1 << 2,
+ ///
+ /// A media node is selected.
+ ///
+ CM_TYPEFLAG_MEDIA = 1 << 3,
+ ///
+ /// There is a textual or mixed selection that is selected.
+ ///
+ CM_TYPEFLAG_SELECTION = 1 << 4,
+ ///
+ /// An editable element is selected.
+ ///
+ CM_TYPEFLAG_EDITABLE = 1 << 5,
+} cef_context_menu_type_flags_t;
+
+///
+/// Supported context menu media types. These constants match their equivalents
+/// in Chromium's ContextMenuDataMediaType and should not be renumbered.
+///
+typedef enum {
+ ///
+ /// No special node is in context.
+ ///
+ CM_MEDIATYPE_NONE,
+ ///
+ /// An image node is selected.
+ ///
+ CM_MEDIATYPE_IMAGE,
+ ///
+ /// A video node is selected.
+ ///
+ CM_MEDIATYPE_VIDEO,
+ ///
+ /// An audio node is selected.
+ ///
+ CM_MEDIATYPE_AUDIO,
+ ///
+ /// An canvas node is selected.
+ ///
+ CM_MEDIATYPE_CANVAS,
+ ///
+ /// A file node is selected.
+ ///
+ CM_MEDIATYPE_FILE,
+ ///
+ /// A plugin node is selected.
+ ///
+ CM_MEDIATYPE_PLUGIN,
+} cef_context_menu_media_type_t;
+
+///
+/// Supported context menu media state bit flags. These constants match their
+/// equivalents in Chromium's ContextMenuData::MediaFlags and should not be
+/// renumbered.
+///
+typedef enum {
+ CM_MEDIAFLAG_NONE = 0,
+ CM_MEDIAFLAG_IN_ERROR = 1 << 0,
+ CM_MEDIAFLAG_PAUSED = 1 << 1,
+ CM_MEDIAFLAG_MUTED = 1 << 2,
+ CM_MEDIAFLAG_LOOP = 1 << 3,
+ CM_MEDIAFLAG_CAN_SAVE = 1 << 4,
+ CM_MEDIAFLAG_HAS_AUDIO = 1 << 5,
+ CM_MEDIAFLAG_CAN_TOGGLE_CONTROLS = 1 << 6,
+ CM_MEDIAFLAG_CONTROLS = 1 << 7,
+ CM_MEDIAFLAG_CAN_PRINT = 1 << 8,
+ CM_MEDIAFLAG_CAN_ROTATE = 1 << 9,
+ CM_MEDIAFLAG_CAN_PICTURE_IN_PICTURE = 1 << 10,
+ CM_MEDIAFLAG_PICTURE_IN_PICTURE = 1 << 11,
+ CM_MEDIAFLAG_CAN_LOOP = 1 << 12,
+} cef_context_menu_media_state_flags_t;
+
+///
+/// Supported context menu edit state bit flags. These constants match their
+/// equivalents in Chromium's ContextMenuDataEditFlags and should not be
+/// renumbered.
+///
+typedef enum {
+ CM_EDITFLAG_NONE = 0,
+ CM_EDITFLAG_CAN_UNDO = 1 << 0,
+ CM_EDITFLAG_CAN_REDO = 1 << 1,
+ CM_EDITFLAG_CAN_CUT = 1 << 2,
+ CM_EDITFLAG_CAN_COPY = 1 << 3,
+ CM_EDITFLAG_CAN_PASTE = 1 << 4,
+ CM_EDITFLAG_CAN_DELETE = 1 << 5,
+ CM_EDITFLAG_CAN_SELECT_ALL = 1 << 6,
+ CM_EDITFLAG_CAN_TRANSLATE = 1 << 7,
+ CM_EDITFLAG_CAN_EDIT_RICHLY = 1 << 8,
+} cef_context_menu_edit_state_flags_t;
+
+///
+/// Supported quick menu state bit flags.
+///
+typedef enum {
+ QM_EDITFLAG_NONE = 0,
+ QM_EDITFLAG_CAN_ELLIPSIS = 1 << 0,
+ QM_EDITFLAG_CAN_CUT = 1 << 1,
+ QM_EDITFLAG_CAN_COPY = 1 << 2,
+ QM_EDITFLAG_CAN_PASTE = 1 << 3,
+} cef_quick_menu_edit_state_flags_t;
+
+///
+/// Key event types.
+///
+typedef enum {
+ ///
+ /// Notification that a key transitioned from "up" to "down".
+ ///
+ KEYEVENT_RAWKEYDOWN = 0,
+
+ ///
+ /// Notification that a key was pressed. This does not necessarily correspond
+ /// to a character depending on the key and language. Use KEYEVENT_CHAR for
+ /// character input.
+ ///
+ KEYEVENT_KEYDOWN,
+
+ ///
+ /// Notification that a key was released.
+ ///
+ KEYEVENT_KEYUP,
+
+ ///
+ /// Notification that a character was typed. Use this for text input. Key
+ /// down events may generate 0, 1, or more than one character event depending
+ /// on the key, locale, and operating system.
+ ///
+ KEYEVENT_CHAR
+} cef_key_event_type_t;
+
+///
+/// Structure representing keyboard event information.
+///
+typedef struct _cef_key_event_t {
+ ///
+ /// The type of keyboard event.
+ ///
+ cef_key_event_type_t type;
+
+ ///
+ /// Bit flags describing any pressed modifier keys. See
+ /// cef_event_flags_t for values.
+ ///
+ uint32 modifiers;
+
+ ///
+ /// The Windows key code for the key event. This value is used by the DOM
+ /// specification. Sometimes it comes directly from the event (i.e. on
+ /// Windows) and sometimes it's determined using a mapping function. See
+ /// WebCore/platform/chromium/KeyboardCodes.h for the list of values.
+ ///
+ int windows_key_code;
+
+ ///
+ /// The actual key code genenerated by the platform.
+ ///
+ int native_key_code;
+
+ ///
+ /// Indicates whether the event is considered a "system key" event (see
+ /// http://msdn.microsoft.com/en-us/library/ms646286(VS.85).aspx for details).
+ /// This value will always be false on non-Windows platforms.
+ ///
+ int is_system_key;
+
+ ///
+ /// The character generated by the keystroke.
+ ///
+ char16 character;
+
+ ///
+ /// Same as |character| but unmodified by any concurrently-held modifiers
+ /// (except shift). This is useful for working out shortcut keys.
+ ///
+ char16 unmodified_character;
+
+ ///
+ /// True if the focus is currently on an editable field on the page. This is
+ /// useful for determining if standard key events should be intercepted.
+ ///
+ int focus_on_editable_field;
+} cef_key_event_t;
+
+///
+/// Focus sources.
+///
+typedef enum {
+ ///
+ /// The source is explicit navigation via the API (LoadURL(), etc).
+ ///
+ FOCUS_SOURCE_NAVIGATION = 0,
+ ///
+ /// The source is a system-generated focus event.
+ ///
+ FOCUS_SOURCE_SYSTEM,
+} cef_focus_source_t;
+
+///
+/// Navigation types.
+///
+typedef enum {
+ NAVIGATION_LINK_CLICKED = 0,
+ NAVIGATION_FORM_SUBMITTED,
+ NAVIGATION_BACK_FORWARD,
+ NAVIGATION_RELOAD,
+ NAVIGATION_FORM_RESUBMITTED,
+ NAVIGATION_OTHER,
+} cef_navigation_type_t;
+
+///
+/// Supported XML encoding types. The parser supports ASCII, ISO-8859-1, and
+/// UTF16 (LE and BE) by default. All other types must be translated to UTF8
+/// before being passed to the parser. If a BOM is detected and the correct
+/// decoder is available then that decoder will be used automatically.
+///
+typedef enum {
+ XML_ENCODING_NONE = 0,
+ XML_ENCODING_UTF8,
+ XML_ENCODING_UTF16LE,
+ XML_ENCODING_UTF16BE,
+ XML_ENCODING_ASCII,
+} cef_xml_encoding_type_t;
+
+///
+/// XML node types.
+///
+typedef enum {
+ XML_NODE_UNSUPPORTED = 0,
+ XML_NODE_PROCESSING_INSTRUCTION,
+ XML_NODE_DOCUMENT_TYPE,
+ XML_NODE_ELEMENT_START,
+ XML_NODE_ELEMENT_END,
+ XML_NODE_ATTRIBUTE,
+ XML_NODE_TEXT,
+ XML_NODE_CDATA,
+ XML_NODE_ENTITY_REFERENCE,
+ XML_NODE_WHITESPACE,
+ XML_NODE_COMMENT,
+} cef_xml_node_type_t;
+
+///
+/// Popup window features.
+///
+typedef struct _cef_popup_features_t {
+ int x;
+ int xSet;
+ int y;
+ int ySet;
+ int width;
+ int widthSet;
+ int height;
+ int heightSet;
+
+ /// True (1) if browser interface elements should be hidden.
+ int isPopup;
+} cef_popup_features_t;
+
+///
+/// DOM document types.
+///
+typedef enum {
+ DOM_DOCUMENT_TYPE_UNKNOWN = 0,
+ DOM_DOCUMENT_TYPE_HTML,
+ DOM_DOCUMENT_TYPE_XHTML,
+ DOM_DOCUMENT_TYPE_PLUGIN,
+} cef_dom_document_type_t;
+
+///
+/// DOM event category flags.
+///
+typedef enum {
+ DOM_EVENT_CATEGORY_UNKNOWN = 0x0,
+ DOM_EVENT_CATEGORY_UI = 0x1,
+ DOM_EVENT_CATEGORY_MOUSE = 0x2,
+ DOM_EVENT_CATEGORY_MUTATION = 0x4,
+ DOM_EVENT_CATEGORY_KEYBOARD = 0x8,
+ DOM_EVENT_CATEGORY_TEXT = 0x10,
+ DOM_EVENT_CATEGORY_COMPOSITION = 0x20,
+ DOM_EVENT_CATEGORY_DRAG = 0x40,
+ DOM_EVENT_CATEGORY_CLIPBOARD = 0x80,
+ DOM_EVENT_CATEGORY_MESSAGE = 0x100,
+ DOM_EVENT_CATEGORY_WHEEL = 0x200,
+ DOM_EVENT_CATEGORY_BEFORE_TEXT_INSERTED = 0x400,
+ DOM_EVENT_CATEGORY_OVERFLOW = 0x800,
+ DOM_EVENT_CATEGORY_PAGE_TRANSITION = 0x1000,
+ DOM_EVENT_CATEGORY_POPSTATE = 0x2000,
+ DOM_EVENT_CATEGORY_PROGRESS = 0x4000,
+ DOM_EVENT_CATEGORY_XMLHTTPREQUEST_PROGRESS = 0x8000,
+} cef_dom_event_category_t;
+
+///
+/// DOM event processing phases.
+///
+typedef enum {
+ DOM_EVENT_PHASE_UNKNOWN = 0,
+ DOM_EVENT_PHASE_CAPTURING,
+ DOM_EVENT_PHASE_AT_TARGET,
+ DOM_EVENT_PHASE_BUBBLING,
+} cef_dom_event_phase_t;
+
+///
+/// DOM node types.
+///
+typedef enum {
+ DOM_NODE_TYPE_UNSUPPORTED = 0,
+ DOM_NODE_TYPE_ELEMENT,
+ DOM_NODE_TYPE_ATTRIBUTE,
+ DOM_NODE_TYPE_TEXT,
+ DOM_NODE_TYPE_CDATA_SECTION,
+ DOM_NODE_TYPE_PROCESSING_INSTRUCTIONS,
+ DOM_NODE_TYPE_COMMENT,
+ DOM_NODE_TYPE_DOCUMENT,
+ DOM_NODE_TYPE_DOCUMENT_TYPE,
+ DOM_NODE_TYPE_DOCUMENT_FRAGMENT,
+} cef_dom_node_type_t;
+
+///
+/// Supported file dialog modes.
+///
+typedef enum {
+ ///
+ /// Requires that the file exists before allowing the user to pick it.
+ ///
+ FILE_DIALOG_OPEN = 0,
+
+ ///
+ /// Like Open, but allows picking multiple files to open.
+ ///
+ FILE_DIALOG_OPEN_MULTIPLE,
+
+ ///
+ /// Like Open, but selects a folder to open.
+ ///
+ FILE_DIALOG_OPEN_FOLDER,
+
+ ///
+ /// Allows picking a nonexistent file, and prompts to overwrite if the file
+ /// already exists.
+ ///
+ FILE_DIALOG_SAVE,
+} cef_file_dialog_mode_t;
+
+///
+/// Print job color mode values.
+///
+typedef enum {
+ COLOR_MODEL_UNKNOWN,
+ COLOR_MODEL_GRAY,
+ COLOR_MODEL_COLOR,
+ COLOR_MODEL_CMYK,
+ COLOR_MODEL_CMY,
+ COLOR_MODEL_KCMY,
+ COLOR_MODEL_CMY_K, // CMY_K represents CMY+K.
+ COLOR_MODEL_BLACK,
+ COLOR_MODEL_GRAYSCALE,
+ COLOR_MODEL_RGB,
+ COLOR_MODEL_RGB16,
+ COLOR_MODEL_RGBA,
+ COLOR_MODEL_COLORMODE_COLOR, // Used in samsung printer ppds.
+ COLOR_MODEL_COLORMODE_MONOCHROME, // Used in samsung printer ppds.
+ COLOR_MODEL_HP_COLOR_COLOR, // Used in HP color printer ppds.
+ COLOR_MODEL_HP_COLOR_BLACK, // Used in HP color printer ppds.
+ COLOR_MODEL_PRINTOUTMODE_NORMAL, // Used in foomatic ppds.
+ COLOR_MODEL_PRINTOUTMODE_NORMAL_GRAY, // Used in foomatic ppds.
+ COLOR_MODEL_PROCESSCOLORMODEL_CMYK, // Used in canon printer ppds.
+ COLOR_MODEL_PROCESSCOLORMODEL_GREYSCALE, // Used in canon printer ppds.
+ COLOR_MODEL_PROCESSCOLORMODEL_RGB, // Used in canon printer ppds
+} cef_color_model_t;
+
+///
+/// Print job duplex mode values.
+///
+typedef enum {
+ DUPLEX_MODE_UNKNOWN = -1,
+ DUPLEX_MODE_SIMPLEX,
+ DUPLEX_MODE_LONG_EDGE,
+ DUPLEX_MODE_SHORT_EDGE,
+} cef_duplex_mode_t;
+
+///
+/// Cursor type values.
+///
+typedef enum {
+ CT_POINTER = 0,
+ CT_CROSS,
+ CT_HAND,
+ CT_IBEAM,
+ CT_WAIT,
+ CT_HELP,
+ CT_EASTRESIZE,
+ CT_NORTHRESIZE,
+ CT_NORTHEASTRESIZE,
+ CT_NORTHWESTRESIZE,
+ CT_SOUTHRESIZE,
+ CT_SOUTHEASTRESIZE,
+ CT_SOUTHWESTRESIZE,
+ CT_WESTRESIZE,
+ CT_NORTHSOUTHRESIZE,
+ CT_EASTWESTRESIZE,
+ CT_NORTHEASTSOUTHWESTRESIZE,
+ CT_NORTHWESTSOUTHEASTRESIZE,
+ CT_COLUMNRESIZE,
+ CT_ROWRESIZE,
+ CT_MIDDLEPANNING,
+ CT_EASTPANNING,
+ CT_NORTHPANNING,
+ CT_NORTHEASTPANNING,
+ CT_NORTHWESTPANNING,
+ CT_SOUTHPANNING,
+ CT_SOUTHEASTPANNING,
+ CT_SOUTHWESTPANNING,
+ CT_WESTPANNING,
+ CT_MOVE,
+ CT_VERTICALTEXT,
+ CT_CELL,
+ CT_CONTEXTMENU,
+ CT_ALIAS,
+ CT_PROGRESS,
+ CT_NODROP,
+ CT_COPY,
+ CT_NONE,
+ CT_NOTALLOWED,
+ CT_ZOOMIN,
+ CT_ZOOMOUT,
+ CT_GRAB,
+ CT_GRABBING,
+ CT_MIDDLE_PANNING_VERTICAL,
+ CT_MIDDLE_PANNING_HORIZONTAL,
+ CT_CUSTOM,
+ CT_DND_NONE,
+ CT_DND_MOVE,
+ CT_DND_COPY,
+ CT_DND_LINK,
+} cef_cursor_type_t;
+
+///
+/// Structure representing cursor information. |buffer| will be
+/// |size.width|*|size.height|*4 bytes in size and represents a BGRA image with
+/// an upper-left origin.
+///
+typedef struct _cef_cursor_info_t {
+ cef_point_t hotspot;
+ float image_scale_factor;
+ void* buffer;
+ cef_size_t size;
+} cef_cursor_info_t;
+
+///
+/// URI unescape rules passed to CefURIDecode().
+///
+typedef enum {
+ ///
+ /// Don't unescape anything at all.
+ ///
+ UU_NONE = 0,
+
+ ///
+ /// Don't unescape anything special, but all normal unescaping will happen.
+ /// This is a placeholder and can't be combined with other flags (since it's
+ /// just the absence of them). All other unescape rules imply "normal" in
+ /// addition to their special meaning. Things like escaped letters, digits,
+ /// and most symbols will get unescaped with this mode.
+ ///
+ UU_NORMAL = 1 << 0,
+
+ ///
+ /// Convert %20 to spaces. In some places where we're showing URLs, we may
+ /// want this. In places where the URL may be copied and pasted out, then
+ /// you wouldn't want this since it might not be interpreted in one piece
+ /// by other applications.
+ ///
+ UU_SPACES = 1 << 1,
+
+ ///
+ /// Unescapes '/' and '\\'. If these characters were unescaped, the resulting
+ /// URL won't be the same as the source one. Moreover, they are dangerous to
+ /// unescape in strings that will be used as file paths or names. This value
+ /// should only be used when slashes don't have special meaning, like data
+ /// URLs.
+ ///
+ UU_PATH_SEPARATORS = 1 << 2,
+
+ ///
+ /// Unescapes various characters that will change the meaning of URLs,
+ /// including '%', '+', '&', '#'. Does not unescape path separators.
+ /// If these characters were unescaped, the resulting URL won't be the same
+ /// as the source one. This flag is used when generating final output like
+ /// filenames for URLs where we won't be interpreting as a URL and want to do
+ /// as much unescaping as possible.
+ ///
+ UU_URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS = 1 << 3,
+
+ ///
+ /// URL queries use "+" for space. This flag controls that replacement.
+ ///
+ UU_REPLACE_PLUS_WITH_SPACE = 1 << 4,
+} cef_uri_unescape_rule_t;
+
+///
+/// Options that can be passed to CefParseJSON.
+///
+typedef enum {
+ ///
+ /// Parses the input strictly according to RFC 4627. See comments in
+ /// Chromium's base/json/json_reader.h file for known limitations/
+ /// deviations from the RFC.
+ ///
+ JSON_PARSER_RFC = 0,
+
+ ///
+ /// Allows commas to exist after the last element in structures.
+ ///
+ JSON_PARSER_ALLOW_TRAILING_COMMAS = 1 << 0,
+} cef_json_parser_options_t;
+
+///
+/// Options that can be passed to CefWriteJSON.
+///
+typedef enum {
+ ///
+ /// Default behavior.
+ ///
+ JSON_WRITER_DEFAULT = 0,
+
+ ///
+ /// This option instructs the writer that if a Binary value is encountered,
+ /// the value (and key if within a dictionary) will be omitted from the
+ /// output, and success will be returned. Otherwise, if a binary value is
+ /// encountered, failure will be returned.
+ ///
+ JSON_WRITER_OMIT_BINARY_VALUES = 1 << 0,
+
+ ///
+ /// This option instructs the writer to write doubles that have no fractional
+ /// part as a normal integer (i.e., without using exponential notation
+ /// or appending a '.0') as long as the value is within the range of a
+ /// 64-bit int.
+ ///
+ JSON_WRITER_OMIT_DOUBLE_TYPE_PRESERVATION = 1 << 1,
+
+ ///
+ /// Return a slightly nicer formatted json string (pads with whitespace to
+ /// help with readability).
+ ///
+ JSON_WRITER_PRETTY_PRINT = 1 << 2,
+} cef_json_writer_options_t;
+
+///
+/// Margin type for PDF printing.
+///
+typedef enum {
+ ///
+ /// Default margins of 1cm (~0.4 inches).
+ ///
+ PDF_PRINT_MARGIN_DEFAULT,
+
+ ///
+ /// No margins.
+ ///
+ PDF_PRINT_MARGIN_NONE,
+
+ ///
+ /// Custom margins using the |margin_*| values from cef_pdf_print_settings_t.
+ ///
+ PDF_PRINT_MARGIN_CUSTOM,
+} cef_pdf_print_margin_type_t;
+
+///
+/// Structure representing PDF print settings. These values match the parameters
+/// supported by the DevTools Page.printToPDF function. See
+/// https://chromedevtools.github.io/devtools-protocol/tot/Page/#method-printToPDF
+///
+typedef struct _cef_pdf_print_settings_t {
+ ///
+ /// Set to true (1) for landscape mode or false (0) for portrait mode.
+ ///
+ int landscape;
+
+ ///
+ /// Set to true (1) to print background graphics.
+ ///
+ int print_background;
+
+ ///
+ /// The percentage to scale the PDF by before printing (e.g. .5 is 50%).
+ /// If this value is less than or equal to zero the default value of 1.0
+ /// will be used.
+ ///
+ double scale;
+
+ ///
+ /// Output paper size in inches. If either of these values is less than or
+ /// equal to zero then the default paper size (letter, 8.5 x 11 inches) will
+ /// be used.
+ ///
+ double paper_width;
+ double paper_height;
+
+ ///
+ /// Set to true (1) to prefer page size as defined by css. Defaults to false
+ /// (0), in which case the content will be scaled to fit the paper size.
+ ///
+ int prefer_css_page_size;
+
+ ///
+ /// Margin type.
+ ///
+ cef_pdf_print_margin_type_t margin_type;
+
+ ///
+ /// Margins in inches. Only used if |margin_type| is set to
+ /// PDF_PRINT_MARGIN_CUSTOM.
+ ///
+ double margin_top;
+ double margin_right;
+ double margin_bottom;
+ double margin_left;
+
+ ///
+ /// Paper ranges to print, one based, e.g., '1-5, 8, 11-13'. Pages are printed
+ /// in the document order, not in the order specified, and no more than once.
+ /// Defaults to empty string, which implies the entire document is printed.
+ /// The page numbers are quietly capped to actual page count of the document,
+ /// and ranges beyond the end of the document are ignored. If this results in
+ /// no pages to print, an error is reported. It is an error to specify a range
+ /// with start greater than end.
+ ///
+ cef_string_t page_ranges;
+
+ ///
+ /// Set to true (1) to display the header and/or footer. Modify
+ /// |header_template| and/or |footer_template| to customize the display.
+ ///
+ int display_header_footer;
+
+ ///
+ /// HTML template for the print header. Only displayed if
+ /// |display_header_footer| is true (1). Should be valid HTML markup with
+ /// the following classes used to inject printing values into them:
+ ///
+ /// - date: formatted print date
+ /// - title: document title
+ /// - url: document location
+ /// - pageNumber: current page number
+ /// - totalPages: total pages in the document
+ ///
+ /// For example, "<span class=title></span>" would generate a span containing
+ /// the title.
+ ///
+ cef_string_t header_template;
+
+ ///
+ /// HTML template for the print footer. Only displayed if
+ /// |display_header_footer| is true (1). Uses the same format as
+ /// |header_template|.
+ ///
+ cef_string_t footer_template;
+} cef_pdf_print_settings_t;
+
+///
+/// Supported UI scale factors for the platform. SCALE_FACTOR_NONE is used for
+/// density independent resources such as string, html/js files or an image that
+/// can be used for any scale factors (such as wallpapers).
+///
+typedef enum {
+ SCALE_FACTOR_NONE = 0,
+ SCALE_FACTOR_100P,
+ SCALE_FACTOR_125P,
+ SCALE_FACTOR_133P,
+ SCALE_FACTOR_140P,
+ SCALE_FACTOR_150P,
+ SCALE_FACTOR_180P,
+ SCALE_FACTOR_200P,
+ SCALE_FACTOR_250P,
+ SCALE_FACTOR_300P,
+} cef_scale_factor_t;
+
+///
+/// Policy for how the Referrer HTTP header value will be sent during
+/// navigation. If the `--no-referrers` command-line flag is specified then the
+/// policy value will be ignored and the Referrer value will never be sent. Must
+/// be kept synchronized with net::URLRequest::ReferrerPolicy from Chromium.
+///
+typedef enum {
+ ///
+ /// Clear the referrer header if the header value is HTTPS but the request
+ /// destination is HTTP. This is the default behavior.
+ ///
+ REFERRER_POLICY_CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE,
+ REFERRER_POLICY_DEFAULT =
+ REFERRER_POLICY_CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE,
+
+ ///
+ /// A slight variant on CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE:
+ /// If the request destination is HTTP, an HTTPS referrer will be cleared. If
+ /// the request's destination is cross-origin with the referrer (but does not
+ /// downgrade), the referrer's granularity will be stripped down to an origin
+ /// rather than a full URL. Same-origin requests will send the full referrer.
+ ///
+ REFERRER_POLICY_REDUCE_REFERRER_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN,
+
+ ///
+ /// Strip the referrer down to an origin when the origin of the referrer is
+ /// different from the destination's origin.
+ ///
+ REFERRER_POLICY_ORIGIN_ONLY_ON_TRANSITION_CROSS_ORIGIN,
+
+ ///
+ /// Never change the referrer.
+ ///
+ REFERRER_POLICY_NEVER_CLEAR_REFERRER,
+
+ ///
+ /// Strip the referrer down to the origin regardless of the redirect location.
+ ///
+ REFERRER_POLICY_ORIGIN,
+
+ ///
+ /// Clear the referrer when the request's referrer is cross-origin with the
+ /// request's destination.
+ ///
+ REFERRER_POLICY_CLEAR_REFERRER_ON_TRANSITION_CROSS_ORIGIN,
+
+ ///
+ /// Strip the referrer down to the origin, but clear it entirely if the
+ /// referrer value is HTTPS and the destination is HTTP.
+ ///
+ REFERRER_POLICY_ORIGIN_CLEAR_ON_TRANSITION_FROM_SECURE_TO_INSECURE,
+
+ ///
+ /// Always clear the referrer regardless of the request destination.
+ ///
+ REFERRER_POLICY_NO_REFERRER,
+
+ /// Always the last value in this enumeration.
+ REFERRER_POLICY_LAST_VALUE = REFERRER_POLICY_NO_REFERRER,
+} cef_referrer_policy_t;
+
+///
+/// Return values for CefResponseFilter::Filter().
+///
+typedef enum {
+ ///
+ /// Some or all of the pre-filter data was read successfully but more data is
+ /// needed in order to continue filtering (filtered output is pending).
+ ///
+ RESPONSE_FILTER_NEED_MORE_DATA,
+
+ ///
+ /// Some or all of the pre-filter data was read successfully and all available
+ /// filtered output has been written.
+ ///
+ RESPONSE_FILTER_DONE,
+
+ ///
+ /// An error occurred during filtering.
+ ///
+ RESPONSE_FILTER_ERROR
+} cef_response_filter_status_t;
+
+///
+/// Describes how to interpret the components of a pixel.
+///
+typedef enum {
+ ///
+ /// RGBA with 8 bits per pixel (32bits total).
+ ///
+ CEF_COLOR_TYPE_RGBA_8888,
+
+ ///
+ /// BGRA with 8 bits per pixel (32bits total).
+ ///
+ CEF_COLOR_TYPE_BGRA_8888,
+} cef_color_type_t;
+
+///
+/// Describes how to interpret the alpha component of a pixel.
+///
+typedef enum {
+ ///
+ /// No transparency. The alpha component is ignored.
+ ///
+ CEF_ALPHA_TYPE_OPAQUE,
+
+ ///
+ /// Transparency with pre-multiplied alpha component.
+ ///
+ CEF_ALPHA_TYPE_PREMULTIPLIED,
+
+ ///
+ /// Transparency with post-multiplied alpha component.
+ ///
+ CEF_ALPHA_TYPE_POSTMULTIPLIED,
+} cef_alpha_type_t;
+
+///
+/// Text style types. Should be kepy in sync with gfx::TextStyle.
+///
+typedef enum {
+ CEF_TEXT_STYLE_BOLD,
+ CEF_TEXT_STYLE_ITALIC,
+ CEF_TEXT_STYLE_STRIKE,
+ CEF_TEXT_STYLE_DIAGONAL_STRIKE,
+ CEF_TEXT_STYLE_UNDERLINE,
+} cef_text_style_t;
+
+///
+/// Specifies where along the main axis the CefBoxLayout child views should be
+/// laid out.
+///
+typedef enum {
+ ///
+ /// Child views will be left-aligned.
+ ///
+ CEF_MAIN_AXIS_ALIGNMENT_START,
+
+ ///
+ /// Child views will be center-aligned.
+ ///
+ CEF_MAIN_AXIS_ALIGNMENT_CENTER,
+
+ ///
+ /// Child views will be right-aligned.
+ ///
+ CEF_MAIN_AXIS_ALIGNMENT_END,
+} cef_main_axis_alignment_t;
+
+///
+/// Specifies where along the cross axis the CefBoxLayout child views should be
+/// laid out.
+///
+typedef enum {
+ ///
+ /// Child views will be stretched to fit.
+ ///
+ CEF_CROSS_AXIS_ALIGNMENT_STRETCH,
+
+ ///
+ /// Child views will be left-aligned.
+ ///
+ CEF_CROSS_AXIS_ALIGNMENT_START,
+
+ ///
+ /// Child views will be center-aligned.
+ ///
+ CEF_CROSS_AXIS_ALIGNMENT_CENTER,
+
+ ///
+ /// Child views will be right-aligned.
+ ///
+ CEF_CROSS_AXIS_ALIGNMENT_END,
+} cef_cross_axis_alignment_t;
+
+///
+/// Settings used when initializing a CefBoxLayout.
+///
+typedef struct _cef_box_layout_settings_t {
+ ///
+ /// If true (1) the layout will be horizontal, otherwise the layout will be
+ /// vertical.
+ ///
+ int horizontal;
+
+ ///
+ /// Adds additional horizontal space between the child view area and the host
+ /// view border.
+ ///
+ int inside_border_horizontal_spacing;
+
+ ///
+ /// Adds additional vertical space between the child view area and the host
+ /// view border.
+ ///
+ int inside_border_vertical_spacing;
+
+ ///
+ /// Adds additional space around the child view area.
+ ///
+ cef_insets_t inside_border_insets;
+
+ ///
+ /// Adds additional space between child views.
+ ///
+ int between_child_spacing;
+
+ ///
+ /// Specifies where along the main axis the child views should be laid out.
+ ///
+ cef_main_axis_alignment_t main_axis_alignment;
+
+ ///
+ /// Specifies where along the cross axis the child views should be laid out.
+ ///
+ cef_cross_axis_alignment_t cross_axis_alignment;
+
+ ///
+ /// Minimum cross axis size.
+ ///
+ int minimum_cross_axis_size;
+
+ ///
+ /// Default flex for views when none is specified via CefBoxLayout methods.
+ /// Using the preferred size as the basis, free space along the main axis is
+ /// distributed to views in the ratio of their flex weights. Similarly, if the
+ /// views will overflow the parent, space is subtracted in these ratios. A
+ /// flex of 0 means this view is not resized. Flex values must not be
+ /// negative.
+ ///
+ int default_flex;
+} cef_box_layout_settings_t;
+
+///
+/// Specifies the button display state.
+///
+typedef enum {
+ CEF_BUTTON_STATE_NORMAL,
+ CEF_BUTTON_STATE_HOVERED,
+ CEF_BUTTON_STATE_PRESSED,
+ CEF_BUTTON_STATE_DISABLED,
+} cef_button_state_t;
+
+///
+/// Specifies the horizontal text alignment mode.
+///
+typedef enum {
+ ///
+ /// Align the text's left edge with that of its display area.
+ ///
+ CEF_HORIZONTAL_ALIGNMENT_LEFT,
+
+ ///
+ /// Align the text's center with that of its display area.
+ ///
+ CEF_HORIZONTAL_ALIGNMENT_CENTER,
+
+ ///
+ /// Align the text's right edge with that of its display area.
+ ///
+ CEF_HORIZONTAL_ALIGNMENT_RIGHT,
+} cef_horizontal_alignment_t;
+
+///
+/// Specifies how a menu will be anchored for non-RTL languages. The opposite
+/// position will be used for RTL languages.
+///
+typedef enum {
+ CEF_MENU_ANCHOR_TOPLEFT,
+ CEF_MENU_ANCHOR_TOPRIGHT,
+ CEF_MENU_ANCHOR_BOTTOMCENTER,
+} cef_menu_anchor_position_t;
+
+///
+/// Supported color types for menu items.
+///
+typedef enum {
+ CEF_MENU_COLOR_TEXT,
+ CEF_MENU_COLOR_TEXT_HOVERED,
+ CEF_MENU_COLOR_TEXT_ACCELERATOR,
+ CEF_MENU_COLOR_TEXT_ACCELERATOR_HOVERED,
+ CEF_MENU_COLOR_BACKGROUND,
+ CEF_MENU_COLOR_BACKGROUND_HOVERED,
+ CEF_MENU_COLOR_COUNT,
+} cef_menu_color_type_t;
+
+/// Supported SSL version values. See net/ssl/ssl_connection_status_flags.h
+/// for more information.
+typedef enum {
+ SSL_CONNECTION_VERSION_UNKNOWN = 0, // Unknown SSL version.
+ SSL_CONNECTION_VERSION_SSL2 = 1,
+ SSL_CONNECTION_VERSION_SSL3 = 2,
+ SSL_CONNECTION_VERSION_TLS1 = 3,
+ SSL_CONNECTION_VERSION_TLS1_1 = 4,
+ SSL_CONNECTION_VERSION_TLS1_2 = 5,
+ SSL_CONNECTION_VERSION_TLS1_3 = 6,
+ SSL_CONNECTION_VERSION_QUIC = 7,
+} cef_ssl_version_t;
+
+/// Supported SSL content status flags. See content/public/common/ssl_status.h
+/// for more information.
+typedef enum {
+ SSL_CONTENT_NORMAL_CONTENT = 0,
+ SSL_CONTENT_DISPLAYED_INSECURE_CONTENT = 1 << 0,
+ SSL_CONTENT_RAN_INSECURE_CONTENT = 1 << 1,
+} cef_ssl_content_status_t;
+
+//
+/// Configuration options for registering a custom scheme.
+/// These values are used when calling AddCustomScheme.
+//
+typedef enum {
+ CEF_SCHEME_OPTION_NONE = 0,
+
+ ///
+ /// If CEF_SCHEME_OPTION_STANDARD is set the scheme will be treated as a
+ /// standard scheme. Standard schemes are subject to URL canonicalization and
+ /// parsing rules as defined in the Common Internet Scheme Syntax RFC 1738
+ /// Section 3.1 available at http://www.ietf.org/rfc/rfc1738.txt
+ //
+ /// In particular, the syntax for standard scheme URLs must be of the form:
+ /// <pre>
+ /// [scheme]://[username]:[password]@[host]:[port]/[url-path]
+ /// </pre> Standard scheme URLs must have a host component that is a fully
+ /// qualified domain name as defined in Section 3.5 of RFC 1034 [13] and
+ /// Section 2.1 of RFC 1123. These URLs will be canonicalized to
+ /// "scheme://host/path" in the simplest case and
+ /// "scheme://username:password@host:port/path" in the most explicit case. For
+ /// example, "scheme:host/path" and "scheme:///host/path" will both be
+ /// canonicalized to "scheme://host/path". The origin of a standard scheme URL
+ /// is the combination of scheme, host and port (i.e., "scheme://host:port" in
+ /// the most explicit case).
+ //
+ /// For non-standard scheme URLs only the "scheme:" component is parsed and
+ /// canonicalized. The remainder of the URL will be passed to the handler as-
+ /// is. For example, "scheme:///some%20text" will remain the same.
+ /// Non-standard scheme URLs cannot be used as a target for form submission.
+ ///
+ CEF_SCHEME_OPTION_STANDARD = 1 << 0,
+
+ ///
+ /// If CEF_SCHEME_OPTION_LOCAL is set the scheme will be treated with the same
+ /// security rules as those applied to "file" URLs. Normal pages cannot link
+ /// to or access local URLs. Also, by default, local URLs can only perform
+ /// XMLHttpRequest calls to the same URL (origin + path) that originated the
+ /// request. To allow XMLHttpRequest calls from a local URL to other URLs with
+ /// the same origin set the CefSettings.file_access_from_file_urls_allowed
+ /// value to true (1). To allow XMLHttpRequest calls from a local URL to all
+ /// origins set the CefSettings.universal_access_from_file_urls_allowed value
+ /// to true (1).
+ ///
+ CEF_SCHEME_OPTION_LOCAL = 1 << 1,
+
+ ///
+ /// If CEF_SCHEME_OPTION_DISPLAY_ISOLATED is set the scheme can only be
+ /// displayed from other content hosted with the same scheme. For example,
+ /// pages in other origins cannot create iframes or hyperlinks to URLs with
+ /// the scheme. For schemes that must be accessible from other schemes don't
+ /// set this, set CEF_SCHEME_OPTION_CORS_ENABLED, and use CORS
+ /// "Access-Control-Allow-Origin" headers to further restrict access.
+ ///
+ CEF_SCHEME_OPTION_DISPLAY_ISOLATED = 1 << 2,
+
+ ///
+ /// If CEF_SCHEME_OPTION_SECURE is set the scheme will be treated with the
+ /// same security rules as those applied to "https" URLs. For example, loading
+ /// this scheme from other secure schemes will not trigger mixed content
+ /// warnings.
+ ///
+ CEF_SCHEME_OPTION_SECURE = 1 << 3,
+
+ ///
+ /// If CEF_SCHEME_OPTION_CORS_ENABLED is set the scheme can be sent CORS
+ /// requests. This value should be set in most cases where
+ /// CEF_SCHEME_OPTION_STANDARD is set.
+ ///
+ CEF_SCHEME_OPTION_CORS_ENABLED = 1 << 4,
+
+ ///
+ /// If CEF_SCHEME_OPTION_CSP_BYPASSING is set the scheme can bypass Content-
+ /// Security-Policy (CSP) checks. This value should not be set in most cases
+ /// where CEF_SCHEME_OPTION_STANDARD is set.
+ ///
+ CEF_SCHEME_OPTION_CSP_BYPASSING = 1 << 5,
+
+ ///
+ /// If CEF_SCHEME_OPTION_FETCH_ENABLED is set the scheme can perform Fetch API
+ /// requests.
+ ///
+ CEF_SCHEME_OPTION_FETCH_ENABLED = 1 << 6,
+} cef_scheme_options_t;
+
+///
+/// Structure representing a range.
+///
+typedef struct _cef_range_t {
+ int from;
+ int to;
+} cef_range_t;
+
+///
+/// Composition underline style.
+///
+typedef enum {
+ CEF_CUS_SOLID,
+ CEF_CUS_DOT,
+ CEF_CUS_DASH,
+ CEF_CUS_NONE,
+} cef_composition_underline_style_t;
+
+///
+/// Structure representing IME composition underline information. This is a thin
+/// wrapper around Blink's WebCompositionUnderline class and should be kept in
+/// sync with that.
+///
+typedef struct _cef_composition_underline_t {
+ ///
+ /// Underline character range.
+ ///
+ cef_range_t range;
+
+ ///
+ /// Text color.
+ ///
+ cef_color_t color;
+
+ ///
+ /// Background color.
+ ///
+ cef_color_t background_color;
+
+ ///
+ /// Set to true (1) for thick underline.
+ ///
+ int thick;
+
+ ///
+ /// Style.
+ ///
+ cef_composition_underline_style_t style;
+} cef_composition_underline_t;
+
+///
+/// Enumerates the various representations of the ordering of audio channels.
+/// Must be kept synchronized with media::ChannelLayout from Chromium.
+/// See media\base\channel_layout.h
+///
+typedef enum {
+ CEF_CHANNEL_LAYOUT_NONE = 0,
+ CEF_CHANNEL_LAYOUT_UNSUPPORTED = 1,
+
+ /// Front C
+ CEF_CHANNEL_LAYOUT_MONO = 2,
+
+ /// Front L, Front R
+ CEF_CHANNEL_LAYOUT_STEREO = 3,
+
+ /// Front L, Front R, Back C
+ CEF_CHANNEL_LAYOUT_2_1 = 4,
+
+ /// Front L, Front R, Front C
+ CEF_CHANNEL_LAYOUT_SURROUND = 5,
+
+ /// Front L, Front R, Front C, Back C
+ CEF_CHANNEL_LAYOUT_4_0 = 6,
+
+ /// Front L, Front R, Side L, Side R
+ CEF_CHANNEL_LAYOUT_2_2 = 7,
+
+ /// Front L, Front R, Back L, Back R
+ CEF_CHANNEL_LAYOUT_QUAD = 8,
+
+ /// Front L, Front R, Front C, Side L, Side R
+ CEF_CHANNEL_LAYOUT_5_0 = 9,
+
+ /// Front L, Front R, Front C, LFE, Side L, Side R
+ CEF_CHANNEL_LAYOUT_5_1 = 10,
+
+ /// Front L, Front R, Front C, Back L, Back R
+ CEF_CHANNEL_LAYOUT_5_0_BACK = 11,
+
+ /// Front L, Front R, Front C, LFE, Back L, Back R
+ CEF_CHANNEL_LAYOUT_5_1_BACK = 12,
+
+ /// Front L, Front R, Front C, Side L, Side R, Back L, Back R
+ CEF_CHANNEL_LAYOUT_7_0 = 13,
+
+ /// Front L, Front R, Front C, LFE, Side L, Side R, Back L, Back R
+ CEF_CHANNEL_LAYOUT_7_1 = 14,
+
+ /// Front L, Front R, Front C, LFE, Side L, Side R, Front LofC, Front RofC
+ CEF_CHANNEL_LAYOUT_7_1_WIDE = 15,
+
+ /// Stereo L, Stereo R
+ CEF_CHANNEL_LAYOUT_STEREO_DOWNMIX = 16,
+
+ /// Stereo L, Stereo R, LFE
+ CEF_CHANNEL_LAYOUT_2POINT1 = 17,
+
+ /// Stereo L, Stereo R, Front C, LFE
+ CEF_CHANNEL_LAYOUT_3_1 = 18,
+
+ /// Stereo L, Stereo R, Front C, Rear C, LFE
+ CEF_CHANNEL_LAYOUT_4_1 = 19,
+
+ /// Stereo L, Stereo R, Front C, Side L, Side R, Back C
+ CEF_CHANNEL_LAYOUT_6_0 = 20,
+
+ /// Stereo L, Stereo R, Side L, Side R, Front LofC, Front RofC
+ CEF_CHANNEL_LAYOUT_6_0_FRONT = 21,
+
+ /// Stereo L, Stereo R, Front C, Rear L, Rear R, Rear C
+ CEF_CHANNEL_LAYOUT_HEXAGONAL = 22,
+
+ /// Stereo L, Stereo R, Front C, LFE, Side L, Side R, Rear Center
+ CEF_CHANNEL_LAYOUT_6_1 = 23,
+
+ /// Stereo L, Stereo R, Front C, LFE, Back L, Back R, Rear Center
+ CEF_CHANNEL_LAYOUT_6_1_BACK = 24,
+
+ /// Stereo L, Stereo R, Side L, Side R, Front LofC, Front RofC, LFE
+ CEF_CHANNEL_LAYOUT_6_1_FRONT = 25,
+
+ /// Front L, Front R, Front C, Side L, Side R, Front LofC, Front RofC
+ CEF_CHANNEL_LAYOUT_7_0_FRONT = 26,
+
+ /// Front L, Front R, Front C, LFE, Back L, Back R, Front LofC, Front RofC
+ CEF_CHANNEL_LAYOUT_7_1_WIDE_BACK = 27,
+
+ /// Front L, Front R, Front C, Side L, Side R, Rear L, Back R, Back C.
+ CEF_CHANNEL_LAYOUT_OCTAGONAL = 28,
+
+ /// Channels are not explicitly mapped to speakers.
+ CEF_CHANNEL_LAYOUT_DISCRETE = 29,
+
+ /// Front L, Front R, Front C. Front C contains the keyboard mic audio. This
+ /// layout is only intended for input for WebRTC. The Front C channel
+ /// is stripped away in the WebRTC audio input pipeline and never seen outside
+ /// of that.
+ CEF_CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC = 30,
+
+ /// Front L, Front R, Side L, Side R, LFE
+ CEF_CHANNEL_LAYOUT_4_1_QUAD_SIDE = 31,
+
+ /// Actual channel layout is specified in the bitstream and the actual channel
+ /// count is unknown at Chromium media pipeline level (useful for audio
+ /// pass-through mode).
+ CEF_CHANNEL_LAYOUT_BITSTREAM = 32,
+
+ /// Front L, Front R, Front C, LFE, Side L, Side R,
+ /// Front Height L, Front Height R, Rear Height L, Rear Height R
+ /// Will be represented as six channels (5.1) due to eight channel limit
+ /// kMaxConcurrentChannels
+ CEF_CHANNEL_LAYOUT_5_1_4_DOWNMIX = 33,
+
+ /// Max value, must always equal the largest entry ever logged.
+ CEF_CHANNEL_LAYOUT_MAX = CEF_CHANNEL_LAYOUT_5_1_4_DOWNMIX
+} cef_channel_layout_t;
+
+///
+/// Structure representing the audio parameters for setting up the audio
+/// handler.
+///
+typedef struct _cef_audio_parameters_t {
+ ///
+ /// Layout of the audio channels
+ ///
+ cef_channel_layout_t channel_layout;
+
+ ///
+ /// Sample rate
+ //
+ int sample_rate;
+
+ ///
+ /// Number of frames per buffer
+ ///
+ int frames_per_buffer;
+} cef_audio_parameters_t;
+
+///
+/// Result codes for CefMediaRouter::CreateRoute. Should be kept in sync with
+/// Chromium's media_router::mojom::RouteRequestResultCode type.
+///
+typedef enum {
+ CEF_MRCR_UNKNOWN_ERROR = 0,
+ CEF_MRCR_OK = 1,
+ CEF_MRCR_TIMED_OUT = 2,
+ CEF_MRCR_ROUTE_NOT_FOUND = 3,
+ CEF_MRCR_SINK_NOT_FOUND = 4,
+ CEF_MRCR_INVALID_ORIGIN = 5,
+ CEF_MRCR_NO_SUPPORTED_PROVIDER = 7,
+ CEF_MRCR_CANCELLED = 8,
+ CEF_MRCR_ROUTE_ALREADY_EXISTS = 9,
+ CEF_MRCR_ROUTE_ALREADY_TERMINATED = 11,
+} cef_media_route_create_result_t;
+
+///
+/// Connection state for a MediaRoute object.
+///
+typedef enum {
+ CEF_MRCS_UNKNOWN,
+ CEF_MRCS_CONNECTING,
+ CEF_MRCS_CONNECTED,
+ CEF_MRCS_CLOSED,
+ CEF_MRCS_TERMINATED,
+} cef_media_route_connection_state_t;
+
+///
+/// Icon types for a MediaSink object. Should be kept in sync with Chromium's
+/// media_router::SinkIconType type.
+///
+typedef enum {
+ CEF_MSIT_CAST,
+ CEF_MSIT_CAST_AUDIO_GROUP,
+ CEF_MSIT_CAST_AUDIO,
+ CEF_MSIT_MEETING,
+ CEF_MSIT_HANGOUT,
+ CEF_MSIT_EDUCATION,
+ CEF_MSIT_WIRED_DISPLAY,
+ CEF_MSIT_GENERIC,
+
+ CEF_MSIT_TOTAL_COUNT, // The total number of values.
+} cef_media_sink_icon_type_t;
+
+///
+/// Device information for a MediaSink object.
+///
+typedef struct _cef_media_sink_device_info_t {
+ cef_string_t ip_address;
+ int port;
+ cef_string_t model_name;
+} cef_media_sink_device_info_t;
+
+///
+/// Represents commands available to TextField.
+///
+typedef enum {
+ CEF_TFC_CUT = 1,
+ CEF_TFC_COPY,
+ CEF_TFC_PASTE,
+ CEF_TFC_UNDO,
+ CEF_TFC_DELETE,
+ CEF_TFC_SELECT_ALL,
+} cef_text_field_commands_t;
+
+///
+/// Supported Chrome toolbar types.
+///
+typedef enum {
+ CEF_CTT_NONE = 1,
+ CEF_CTT_NORMAL,
+ CEF_CTT_LOCATION,
+} cef_chrome_toolbar_type_t;
+
+///
+/// Docking modes supported by CefWindow::AddOverlay.
+///
+typedef enum {
+ CEF_DOCKING_MODE_TOP_LEFT = 1,
+ CEF_DOCKING_MODE_TOP_RIGHT,
+ CEF_DOCKING_MODE_BOTTOM_LEFT,
+ CEF_DOCKING_MODE_BOTTOM_RIGHT,
+ CEF_DOCKING_MODE_CUSTOM,
+} cef_docking_mode_t;
+
+///
+/// Show states supported by CefWindowDelegate::GetInitialShowState.
+///
+typedef enum {
+ CEF_SHOW_STATE_NORMAL = 1,
+ CEF_SHOW_STATE_MINIMIZED,
+ CEF_SHOW_STATE_MAXIMIZED,
+ CEF_SHOW_STATE_FULLSCREEN,
+} cef_show_state_t;
+
+///
+/// Values indicating what state of the touch handle is set.
+///
+typedef enum {
+ CEF_THS_FLAG_NONE = 0,
+ CEF_THS_FLAG_ENABLED = 1 << 0,
+ CEF_THS_FLAG_ORIENTATION = 1 << 1,
+ CEF_THS_FLAG_ORIGIN = 1 << 2,
+ CEF_THS_FLAG_ALPHA = 1 << 3,
+} cef_touch_handle_state_flags_t;
+
+typedef struct _cef_touch_handle_state_t {
+ ///
+ /// Touch handle id. Increments for each new touch handle.
+ ///
+ int touch_handle_id;
+
+ ///
+ /// Combination of cef_touch_handle_state_flags_t values indicating what state
+ /// is set.
+ ///
+ uint32 flags;
+
+ ///
+ /// Enabled state. Only set if |flags| contains CEF_THS_FLAG_ENABLED.
+ ///
+ int enabled;
+
+ ///
+ /// Orientation state. Only set if |flags| contains CEF_THS_FLAG_ORIENTATION.
+ ///
+ cef_horizontal_alignment_t orientation;
+ int mirror_vertical;
+ int mirror_horizontal;
+
+ ///
+ /// Origin state. Only set if |flags| contains CEF_THS_FLAG_ORIGIN.
+ ///
+ cef_point_t origin;
+
+ ///
+ /// Alpha state. Only set if |flags| contains CEF_THS_FLAG_ALPHA.
+ ///
+ float alpha;
+} cef_touch_handle_state_t;
+
+///
+/// Media access permissions used by OnRequestMediaAccessPermission.
+///
+typedef enum {
+ ///
+ /// No permission.
+ ///
+ CEF_MEDIA_PERMISSION_NONE = 0,
+
+ ///
+ /// Device audio capture permission.
+ ///
+ CEF_MEDIA_PERMISSION_DEVICE_AUDIO_CAPTURE = 1 << 0,
+
+ ///
+ /// Device video capture permission.
+ ///
+ CEF_MEDIA_PERMISSION_DEVICE_VIDEO_CAPTURE = 1 << 1,
+
+ ///
+ /// Desktop audio capture permission.
+ ///
+ CEF_MEDIA_PERMISSION_DESKTOP_AUDIO_CAPTURE = 1 << 2,
+
+ ///
+ /// Desktop video capture permission.
+ ///
+ CEF_MEDIA_PERMISSION_DESKTOP_VIDEO_CAPTURE = 1 << 3,
+} cef_media_access_permission_types_t;
+
+///
+/// Permission types used with OnShowPermissionPrompt. Some types are
+/// platform-specific or only supported with the Chrome runtime. Should be kept
+/// in sync with Chromium's permissions::RequestType type.
+///
+typedef enum {
+ CEF_PERMISSION_TYPE_NONE = 0,
+ CEF_PERMISSION_TYPE_ACCESSIBILITY_EVENTS = 1 << 0,
+ CEF_PERMISSION_TYPE_AR_SESSION = 1 << 1,
+ CEF_PERMISSION_TYPE_CAMERA_PAN_TILT_ZOOM = 1 << 2,
+ CEF_PERMISSION_TYPE_CAMERA_STREAM = 1 << 3,
+ CEF_PERMISSION_TYPE_CLIPBOARD = 1 << 4,
+ CEF_PERMISSION_TYPE_TOP_LEVEL_STORAGE_ACCESS = 1 << 5,
+ CEF_PERMISSION_TYPE_DISK_QUOTA = 1 << 6,
+ CEF_PERMISSION_TYPE_LOCAL_FONTS = 1 << 7,
+ CEF_PERMISSION_TYPE_GEOLOCATION = 1 << 8,
+ CEF_PERMISSION_TYPE_IDLE_DETECTION = 1 << 9,
+ CEF_PERMISSION_TYPE_MIC_STREAM = 1 << 10,
+ CEF_PERMISSION_TYPE_MIDI_SYSEX = 1 << 11,
+ CEF_PERMISSION_TYPE_MULTIPLE_DOWNLOADS = 1 << 12,
+ CEF_PERMISSION_TYPE_NOTIFICATIONS = 1 << 13,
+ CEF_PERMISSION_TYPE_PROTECTED_MEDIA_IDENTIFIER = 1 << 14,
+ CEF_PERMISSION_TYPE_REGISTER_PROTOCOL_HANDLER = 1 << 15,
+ CEF_PERMISSION_TYPE_SECURITY_ATTESTATION = 1 << 16,
+ CEF_PERMISSION_TYPE_STORAGE_ACCESS = 1 << 17,
+ CEF_PERMISSION_TYPE_U2F_API_REQUEST = 1 << 18,
+ CEF_PERMISSION_TYPE_VR_SESSION = 1 << 19,
+ CEF_PERMISSION_TYPE_WINDOW_MANAGEMENT = 1 << 20,
+} cef_permission_request_types_t;
+
+///
+/// Permission request results.
+///
+typedef enum {
+ ///
+ /// Accept the permission request as an explicit user action.
+ ///
+ CEF_PERMISSION_RESULT_ACCEPT,
+
+ ///
+ /// Deny the permission request as an explicit user action.
+ ///
+ CEF_PERMISSION_RESULT_DENY,
+
+ ///
+ /// Dismiss the permission request as an explicit user action.
+ ///
+ CEF_PERMISSION_RESULT_DISMISS,
+
+ ///
+ /// Ignore the permission request. If the prompt remains unhandled (e.g.
+ /// OnShowPermissionPrompt returns false and there is no default permissions
+ /// UI) then any related promises may remain unresolved.
+ ///
+ CEF_PERMISSION_RESULT_IGNORE,
+} cef_permission_request_result_t;
+
+///
+/// Certificate types supported by CefTestServer::CreateAndStart. The matching
+/// certificate file must exist in the "net/data/ssl/certificates" directory.
+/// See CefSetDataDirectoryForTests() for related configuration.
+///
+typedef enum {
+ /// Valid certificate using the IP (127.0.0.1). Loads the "ok_cert.pem" file.
+ CEF_TEST_CERT_OK_IP,
+
+ /// Valid certificate using the domain ("localhost"). Loads the
+ /// "localhost_cert.pem" file.
+ CEF_TEST_CERT_OK_DOMAIN,
+
+ /// Expired certificate. Loads the "expired_cert.pem" file.
+ CEF_TEST_CERT_EXPIRED,
+} cef_test_cert_type_t;
+
+///
+/// Preferences type passed to
+/// CefBrowserProcessHandler::OnRegisterCustomPreferences.
+///
+typedef enum {
+ /// Global preferences registered a single time at application startup.
+ CEF_PREFERENCES_TYPE_GLOBAL,
+
+ /// Request context preferences registered each time a new CefRequestContext
+ /// is created.
+ CEF_PREFERENCES_TYPE_REQUEST_CONTEXT,
+} cef_preferences_type_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_INTERNAL_CEF_TYPES_H_
diff --git a/include/internal/cef_types_geometry.h b/include/internal/cef_types_geometry.h
new file mode 100644
index 00000000..7410f15d
--- /dev/null
+++ b/include/internal/cef_types_geometry.h
@@ -0,0 +1,78 @@
+// Copyright (c) 2014 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CEF_INCLUDE_INTERNAL_CEF_TYPES_GEOMETRY_H_
+#define CEF_INCLUDE_INTERNAL_CEF_TYPES_GEOMETRY_H_
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Structure representing a point.
+///
+typedef struct _cef_point_t {
+ int x;
+ int y;
+} cef_point_t;
+
+///
+/// Structure representing a rectangle.
+///
+typedef struct _cef_rect_t {
+ int x;
+ int y;
+ int width;
+ int height;
+} cef_rect_t;
+
+///
+/// Structure representing a size.
+///
+typedef struct _cef_size_t {
+ int width;
+ int height;
+} cef_size_t;
+
+///
+/// Structure representing insets.
+///
+typedef struct _cef_insets_t {
+ int top;
+ int left;
+ int bottom;
+ int right;
+} cef_insets_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CEF_INCLUDE_INTERNAL_CEF_TYPES_GEOMETRY_H_
diff --git a/include/internal/cef_types_linux.h b/include/internal/cef_types_linux.h
new file mode 100644
index 00000000..171cda32
--- /dev/null
+++ b/include/internal/cef_types_linux.h
@@ -0,0 +1,146 @@
+// Copyright (c) 2014 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CEF_INCLUDE_INTERNAL_CEF_TYPES_LINUX_H_
+#define CEF_INCLUDE_INTERNAL_CEF_TYPES_LINUX_H_
+#pragma once
+
+#include "include/base/cef_build.h"
+#include "include/cef_config.h"
+
+#if defined(OS_LINUX)
+
+#if defined(CEF_X11)
+typedef union _XEvent XEvent;
+typedef struct _XDisplay XDisplay;
+#endif
+
+#include "include/internal/cef_export.h"
+#include "include/internal/cef_string.h"
+#include "include/internal/cef_types_geometry.h"
+
+// Handle types.
+#if defined(CEF_X11)
+#define cef_cursor_handle_t unsigned long
+#define cef_event_handle_t XEvent*
+#else
+#define cef_cursor_handle_t void*
+#define cef_event_handle_t void*
+#endif
+
+#define cef_window_handle_t unsigned long
+
+#define kNullCursorHandle 0
+#define kNullEventHandle NULL
+#define kNullWindowHandle 0
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Return the singleton X11 display shared with Chromium. The display is not
+/// thread-safe and must only be accessed on the browser process UI thread.
+///
+#if defined(CEF_X11)
+CEF_EXPORT XDisplay* cef_get_xdisplay(void);
+#endif
+
+///
+/// Structure representing CefExecuteProcess arguments.
+///
+typedef struct _cef_main_args_t {
+ int argc;
+ char** argv;
+} cef_main_args_t;
+
+///
+/// Class representing window information.
+///
+typedef struct _cef_window_info_t {
+ ///
+ /// The initial title of the window, to be set when the window is created.
+ /// Some layout managers (e.g., Compiz) can look at the window title
+ /// in order to decide where to place the window when it is
+ /// created. When this attribute is not empty, the window title will
+ /// be set before the window is mapped to the dispay. Otherwise the
+ /// title will be initially empty.
+ ///
+ cef_string_t window_name;
+
+ ///
+ /// Initial window bounds.
+ ///
+ cef_rect_t bounds;
+
+ ///
+ /// Pointer for the parent window.
+ ///
+ cef_window_handle_t parent_window;
+
+ ///
+ /// Set to true (1) to create the browser using windowless (off-screen)
+ /// rendering. No window will be created for the browser and all rendering
+ /// will occur via the CefRenderHandler interface. The |parent_window| value
+ /// will be used to identify monitor info and to act as the parent window for
+ /// dialogs, context menus, etc. If |parent_window| is not provided then the
+ /// main screen monitor will be used and some functionality that requires a
+ /// parent window may not function correctly. In order to create windowless
+ /// browsers the CefSettings.windowless_rendering_enabled value must be set to
+ /// true. Transparent painting is enabled by default but can be disabled by
+ /// setting CefBrowserSettings.background_color to an opaque value.
+ ///
+ int windowless_rendering_enabled;
+
+ ///
+ /// Set to true (1) to enable shared textures for windowless rendering. Only
+ /// valid if windowless_rendering_enabled above is also set to true. Currently
+ /// only supported on Windows (D3D11).
+ ///
+ int shared_texture_enabled;
+
+ ///
+ /// Set to true (1) to enable the ability to issue BeginFrame requests from
+ /// the client application by calling CefBrowserHost::SendExternalBeginFrame.
+ ///
+ int external_begin_frame_enabled;
+
+ ///
+ /// Pointer for the new browser window. Only used with windowed rendering.
+ ///
+ cef_window_handle_t window;
+} cef_window_info_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // OS_LINUX
+
+#endif // CEF_INCLUDE_INTERNAL_CEF_TYPES_LINUX_H_
diff --git a/include/internal/cef_types_mac.h b/include/internal/cef_types_mac.h
new file mode 100644
index 00000000..8ee619e6
--- /dev/null
+++ b/include/internal/cef_types_mac.h
@@ -0,0 +1,145 @@
+// Copyright (c) 2014 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CEF_INCLUDE_INTERNAL_CEF_TYPES_MAC_H_
+#define CEF_INCLUDE_INTERNAL_CEF_TYPES_MAC_H_
+#pragma once
+
+#include "include/base/cef_build.h"
+
+#if defined(OS_MAC)
+#include "include/internal/cef_string.h"
+#include "include/internal/cef_types_geometry.h"
+
+// Handle types.
+// Actually NSCursor*
+#define cef_cursor_handle_t void*
+// Acutally NSEvent*
+#define cef_event_handle_t void*
+// Actually NSView*
+#define cef_window_handle_t void*
+
+#define kNullCursorHandle NULL
+#define kNullEventHandle NULL
+#define kNullWindowHandle NULL
+
+#ifdef __OBJC__
+#if __has_feature(objc_arc)
+#define CAST_CEF_CURSOR_HANDLE_TO_NSCURSOR(handle) ((__bridge NSCursor*)handle)
+#define CAST_CEF_EVENT_HANDLE_TO_NSEVENT(handle) ((__bridge NSEvent*)handle)
+#define CAST_CEF_WINDOW_HANDLE_TO_NSVIEW(handle) ((__bridge NSView*)handle)
+
+#define CAST_NSCURSOR_TO_CEF_CURSOR_HANDLE(cursor) ((__bridge void*)cursor)
+#define CAST_NSEVENT_TO_CEF_EVENT_HANDLE(event) ((__bridge void*)event)
+#define CAST_NSVIEW_TO_CEF_WINDOW_HANDLE(view) ((__bridge void*)view)
+#else // __has_feature(objc_arc)
+#define CAST_CEF_CURSOR_HANDLE_TO_NSCURSOR(handle) ((NSCursor*)handle)
+#define CAST_CEF_EVENT_HANDLE_TO_NSEVENT(handle) ((NSEvent*)handle)
+#define CAST_CEF_WINDOW_HANDLE_TO_NSVIEW(handle) ((NSView*)handle)
+
+#define CAST_NSCURSOR_TO_CEF_CURSOR_HANDLE(cursor) ((void*)cursor)
+#define CAST_NSEVENT_TO_CEF_EVENT_HANDLE(event) ((void*)event)
+#define CAST_NSVIEW_TO_CEF_WINDOW_HANDLE(view) ((void*)view)
+#endif // __has_feature(objc_arc)
+#endif // __OBJC__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Structure representing CefExecuteProcess arguments.
+///
+typedef struct _cef_main_args_t {
+ int argc;
+ char** argv;
+} cef_main_args_t;
+
+///
+/// Class representing window information.
+///
+typedef struct _cef_window_info_t {
+ cef_string_t window_name;
+
+ ///
+ /// Initial window bounds.
+ ///
+ cef_rect_t bounds;
+
+ ///
+ /// Set to true (1) to create the view initially hidden.
+ ///
+ int hidden;
+
+ ///
+ /// NSView pointer for the parent view.
+ ///
+ cef_window_handle_t parent_view;
+
+ ///
+ /// Set to true (1) to create the browser using windowless (off-screen)
+ /// rendering. No view will be created for the browser and all rendering will
+ /// occur via the CefRenderHandler interface. The |parent_view| value will be
+ /// used to identify monitor info and to act as the parent view for dialogs,
+ /// context menus, etc. If |parent_view| is not provided then the main screen
+ /// monitor will be used and some functionality that requires a parent view
+ /// may not function correctly. In order to create windowless browsers the
+ /// CefSettings.windowless_rendering_enabled value must be set to true.
+ /// Transparent painting is enabled by default but can be disabled by setting
+ /// CefBrowserSettings.background_color to an opaque value.
+ ///
+ int windowless_rendering_enabled;
+
+ ///
+ /// Set to true (1) to enable shared textures for windowless rendering. Only
+ /// valid if windowless_rendering_enabled above is also set to true. Currently
+ /// only supported on Windows (D3D11).
+ ///
+ int shared_texture_enabled;
+
+ ///
+ /// Set to true (1) to enable the ability to issue BeginFrame from the client
+ /// application.
+ ///
+ int external_begin_frame_enabled;
+
+ ///
+ /// NSView pointer for the new browser view. Only used with windowed
+ /// rendering.
+ ///
+ cef_window_handle_t view;
+} cef_window_info_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // OS_MAC
+
+#endif // CEF_INCLUDE_INTERNAL_CEF_TYPES_MAC_H_
diff --git a/include/internal/cef_types_win.h b/include/internal/cef_types_win.h
new file mode 100644
index 00000000..abf80c7d
--- /dev/null
+++ b/include/internal/cef_types_win.h
@@ -0,0 +1,113 @@
+// Copyright (c) 2009 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CEF_INCLUDE_INTERNAL_CEF_TYPES_WIN_H_
+#define CEF_INCLUDE_INTERNAL_CEF_TYPES_WIN_H_
+#pragma once
+
+#include "include/base/cef_build.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+
+#include "include/internal/cef_string.h"
+#include "include/internal/cef_types_geometry.h"
+
+// Handle types.
+#define cef_cursor_handle_t HCURSOR
+#define cef_event_handle_t MSG*
+#define cef_window_handle_t HWND
+
+#define kNullCursorHandle NULL
+#define kNullEventHandle NULL
+#define kNullWindowHandle NULL
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+/// Structure representing CefExecuteProcess arguments.
+///
+typedef struct _cef_main_args_t {
+ HINSTANCE instance;
+} cef_main_args_t;
+
+///
+/// Structure representing window information.
+///
+typedef struct _cef_window_info_t {
+ // Standard parameters required by CreateWindowEx()
+ DWORD ex_style;
+ cef_string_t window_name;
+ DWORD style;
+ cef_rect_t bounds;
+ cef_window_handle_t parent_window;
+ HMENU menu;
+
+ ///
+ /// Set to true (1) to create the browser using windowless (off-screen)
+ /// rendering. No window will be created for the browser and all rendering
+ /// will occur via the CefRenderHandler interface. The |parent_window| value
+ /// will be used to identify monitor info and to act as the parent window for
+ /// dialogs, context menus, etc. If |parent_window| is not provided then the
+ /// main screen monitor will be used and some functionality that requires a
+ /// parent window may not function correctly. In order to create windowless
+ /// browsers the CefSettings.windowless_rendering_enabled value must be set to
+ /// true. Transparent painting is enabled by default but can be disabled by
+ /// setting CefBrowserSettings.background_color to an opaque value.
+ ///
+ int windowless_rendering_enabled;
+
+ ///
+ /// Set to true (1) to enable shared textures for windowless rendering. Only
+ /// valid if windowless_rendering_enabled above is also set to true. Currently
+ /// only supported on Windows (D3D11).
+ ///
+ int shared_texture_enabled;
+
+ ///
+ /// Set to true (1) to enable the ability to issue BeginFrame requests from
+ /// the client application by calling CefBrowserHost::SendExternalBeginFrame.
+ ///
+ int external_begin_frame_enabled;
+
+ ///
+ /// Handle for the new browser window. Only used with windowed rendering.
+ ///
+ cef_window_handle_t window;
+} cef_window_info_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // OS_WIN
+
+#endif // CEF_INCLUDE_INTERNAL_CEF_TYPES_WIN_H_
diff --git a/include/internal/cef_types_wrappers.h b/include/internal/cef_types_wrappers.h
new file mode 100644
index 00000000..c1153275
--- /dev/null
+++ b/include/internal/cef_types_wrappers.h
@@ -0,0 +1,742 @@
+// Copyright (c) 2013 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CEF_INCLUDE_INTERNAL_CEF_TYPES_WRAPPERS_H_
+#define CEF_INCLUDE_INTERNAL_CEF_TYPES_WRAPPERS_H_
+#pragma once
+
+#include "include/internal/cef_string.h"
+#include "include/internal/cef_string_list.h"
+#include "include/internal/cef_types.h"
+
+///
+/// Template class that provides common functionality for CEF structure
+/// wrapping. Use only with non-POD types that benefit from referencing unowned
+/// members.
+///
+template <class traits>
+class CefStructBase : public traits::struct_type {
+ public:
+ using struct_type = typename traits::struct_type;
+
+ CefStructBase() : attached_to_(NULL) { Init(); }
+ virtual ~CefStructBase() {
+ // Only clear this object's data if it isn't currently attached to a
+ // structure.
+ if (!attached_to_) {
+ Clear(this);
+ }
+ }
+
+ CefStructBase(const CefStructBase& r) {
+ Init();
+ *this = r;
+ }
+ CefStructBase(const struct_type& r) {
+ Init();
+ *this = r;
+ }
+
+ ///
+ /// Attach to the source structure's existing values. DetachTo() can be called
+ /// to insert the values back into the existing structure.
+ ///
+ void AttachTo(struct_type& source) {
+ // Only clear this object's data if it isn't currently attached to a
+ // structure.
+ if (!attached_to_) {
+ Clear(this);
+ }
+
+ // This object is now attached to the new structure.
+ attached_to_ = &source;
+
+ // Transfer ownership of the values from the source structure.
+ memcpy(static_cast<struct_type*>(this), &source, sizeof(struct_type));
+ }
+
+ ///
+ /// Relinquish ownership of values to the target structure.
+ ///
+ void DetachTo(struct_type& target) {
+ if (attached_to_ != &target) {
+ // Clear the target structure's values only if we are not currently
+ // attached to that structure.
+ Clear(&target);
+ }
+
+ // Transfer ownership of the values to the target structure.
+ memcpy(&target, static_cast<struct_type*>(this), sizeof(struct_type));
+
+ // Remove the references from this object.
+ Init();
+ }
+
+ ///
+ /// Set this object's values. If |copy| is true the source structure's values
+ /// will be copied instead of referenced.
+ ///
+ void Set(const struct_type& source, bool copy) {
+ traits::set(&source, this, copy);
+ }
+
+ CefStructBase& operator=(const CefStructBase& s) {
+ return operator=(static_cast<const struct_type&>(s));
+ }
+
+ CefStructBase& operator=(const struct_type& s) {
+ Set(s, true);
+ return *this;
+ }
+
+ protected:
+ void Init() {
+ memset(static_cast<struct_type*>(this), 0, sizeof(struct_type));
+ attached_to_ = NULL;
+ traits::init(this);
+ }
+
+ static void Clear(struct_type* s) { traits::clear(s); }
+
+ struct_type* attached_to_;
+};
+
+///
+/// Class representing a point.
+///
+class CefPoint : public cef_point_t {
+ public:
+ CefPoint() : cef_point_t{} {}
+ CefPoint(const cef_point_t& r) : cef_point_t(r) {}
+ CefPoint(int x, int y) : cef_point_t{x, y} {}
+
+ bool IsEmpty() const { return x <= 0 && y <= 0; }
+ void Set(int x_val, int y_val) { x = x_val, y = y_val; }
+};
+
+inline bool operator==(const CefPoint& a, const CefPoint& b) {
+ return a.x == b.x && a.y == b.y;
+}
+
+inline bool operator!=(const CefPoint& a, const CefPoint& b) {
+ return !(a == b);
+}
+
+///
+/// Class representing a rectangle.
+///
+class CefRect : public cef_rect_t {
+ public:
+ CefRect() : cef_rect_t{} {}
+ CefRect(const cef_rect_t& r) : cef_rect_t(r) {}
+ CefRect(int x, int y, int width, int height)
+ : cef_rect_t{x, y, width, height} {}
+
+ bool IsEmpty() const { return width <= 0 || height <= 0; }
+ void Set(int x_val, int y_val, int width_val, int height_val) {
+ x = x_val, y = y_val, width = width_val, height = height_val;
+ }
+
+ ///
+ /// Returns true if the point identified by point_x and point_y falls inside
+ /// this rectangle. The point (x, y) is inside the rectangle, but the
+ /// point (x + width, y + height) is not.
+ ///
+ bool Contains(int point_x, int point_y) const {
+ return (point_x >= x) && (point_x < x + width) && (point_y >= y) &&
+ (point_y < y + height);
+ }
+ bool Contains(const CefPoint& point) const {
+ return Contains(point.x, point.y);
+ }
+};
+
+inline bool operator==(const CefRect& a, const CefRect& b) {
+ return a.x == b.x && a.y == b.y && a.width == b.width && a.height == b.height;
+}
+
+inline bool operator!=(const CefRect& a, const CefRect& b) {
+ return !(a == b);
+}
+
+///
+/// Class representing a size.
+///
+class CefSize : public cef_size_t {
+ public:
+ CefSize() : cef_size_t{} {}
+ CefSize(const cef_size_t& r) : cef_size_t(r) {}
+ CefSize(int width, int height) : cef_size_t{width, height} {}
+
+ bool IsEmpty() const { return width <= 0 || height <= 0; }
+ void Set(int width_val, int height_val) {
+ width = width_val, height = height_val;
+ }
+};
+
+inline bool operator==(const CefSize& a, const CefSize& b) {
+ return a.width == b.width && a.height == b.height;
+}
+
+inline bool operator!=(const CefSize& a, const CefSize& b) {
+ return !(a == b);
+}
+
+///
+/// Class representing a range.
+///
+class CefRange : public cef_range_t {
+ public:
+ CefRange() : cef_range_t{} {}
+ CefRange(const cef_range_t& r) : cef_range_t(r) {}
+ CefRange(int from, int to) : cef_range_t{from, to} {}
+
+ void Set(int from_val, int to_val) { from = from_val, to = to_val; }
+};
+
+inline bool operator==(const CefRange& a, const CefRange& b) {
+ return a.from == b.from && a.to == b.to;
+}
+
+inline bool operator!=(const CefRange& a, const CefRange& b) {
+ return !(a == b);
+}
+
+///
+/// Class representing insets.
+///
+class CefInsets : public cef_insets_t {
+ public:
+ CefInsets() : cef_insets_t{} {}
+ CefInsets(const cef_insets_t& r) : cef_insets_t(r) {}
+ CefInsets(int top, int left, int bottom, int right)
+ : cef_insets_t{top, left, bottom, right} {}
+
+ void Set(int top_val, int left_val, int bottom_val, int right_val) {
+ top = top_val, left = left_val, bottom = bottom_val, right = right_val;
+ }
+};
+
+inline bool operator==(const CefInsets& a, const CefInsets& b) {
+ return a.top == b.top && a.left == b.left && a.bottom == b.bottom &&
+ a.right == b.right;
+}
+
+inline bool operator!=(const CefInsets& a, const CefInsets& b) {
+ return !(a == b);
+}
+
+///
+/// Class representing a draggable region.
+///
+class CefDraggableRegion : public cef_draggable_region_t {
+ public:
+ CefDraggableRegion() : cef_draggable_region_t{} {}
+ CefDraggableRegion(const cef_draggable_region_t& r)
+ : cef_draggable_region_t(r) {}
+ CefDraggableRegion(const cef_rect_t& bounds, bool draggable)
+ : cef_draggable_region_t{bounds, draggable} {}
+
+ void Set(const CefRect& bounds_val, bool draggable_val) {
+ bounds = bounds_val, draggable = draggable_val;
+ }
+};
+
+inline bool operator==(const CefDraggableRegion& a,
+ const CefDraggableRegion& b) {
+ return a.bounds == b.bounds && a.draggable == b.draggable;
+}
+
+inline bool operator!=(const CefDraggableRegion& a,
+ const CefDraggableRegion& b) {
+ return !(a == b);
+}
+
+///
+/// Class representing the virtual screen information for use when window
+/// rendering is disabled.
+///
+class CefScreenInfo : public cef_screen_info_t {
+ public:
+ CefScreenInfo() : cef_screen_info_t{} {}
+ CefScreenInfo(const cef_screen_info_t& r) : cef_screen_info_t(r) {}
+ CefScreenInfo(float device_scale_factor,
+ int depth,
+ int depth_per_component,
+ bool is_monochrome,
+ const cef_rect_t& rect,
+ const cef_rect_t& available_rect)
+ : cef_screen_info_t{device_scale_factor, depth, depth_per_component,
+ is_monochrome, rect, available_rect} {}
+
+ void Set(float device_scale_factor_val,
+ int depth_val,
+ int depth_per_component_val,
+ bool is_monochrome_val,
+ const CefRect& rect_val,
+ const CefRect& available_rect_val) {
+ device_scale_factor = device_scale_factor_val;
+ depth = depth_val;
+ depth_per_component = depth_per_component_val;
+ is_monochrome = is_monochrome_val;
+ rect = rect_val;
+ available_rect = available_rect_val;
+ }
+};
+
+///
+/// Class representing a a keyboard event.
+///
+class CefKeyEvent : public cef_key_event_t {
+ public:
+ CefKeyEvent() : cef_key_event_t{} {}
+ CefKeyEvent(const cef_key_event_t& r) : cef_key_event_t(r) {}
+};
+
+///
+/// Class representing a mouse event.
+///
+class CefMouseEvent : public cef_mouse_event_t {
+ public:
+ CefMouseEvent() : cef_mouse_event_t{} {}
+ CefMouseEvent(const cef_mouse_event_t& r) : cef_mouse_event_t(r) {}
+};
+
+///
+/// Class representing a touch event.
+///
+class CefTouchEvent : public cef_touch_event_t {
+ public:
+ CefTouchEvent() : cef_touch_event_t{} {}
+ CefTouchEvent(const cef_touch_event_t& r) : cef_touch_event_t(r) {}
+};
+
+///
+/// Class representing popup window features.
+///
+class CefPopupFeatures : public cef_popup_features_t {
+ public:
+ CefPopupFeatures() : cef_popup_features_t{} {}
+ CefPopupFeatures(const cef_popup_features_t& r) : cef_popup_features_t(r) {}
+};
+
+struct CefSettingsTraits {
+ using struct_type = cef_settings_t;
+
+ static inline void init(struct_type* s) { s->size = sizeof(struct_type); }
+
+ static inline void clear(struct_type* s) {
+ cef_string_clear(&s->browser_subprocess_path);
+ cef_string_clear(&s->framework_dir_path);
+ cef_string_clear(&s->main_bundle_path);
+ cef_string_clear(&s->cache_path);
+ cef_string_clear(&s->root_cache_path);
+ cef_string_clear(&s->user_data_path);
+ cef_string_clear(&s->user_agent);
+ cef_string_clear(&s->user_agent_product);
+ cef_string_clear(&s->locale);
+ cef_string_clear(&s->log_file);
+ cef_string_clear(&s->javascript_flags);
+ cef_string_clear(&s->resources_dir_path);
+ cef_string_clear(&s->locales_dir_path);
+ cef_string_clear(&s->accept_language_list);
+ cef_string_clear(&s->cookieable_schemes_list);
+ }
+
+ static inline void set(const struct_type* src,
+ struct_type* target,
+ bool copy) {
+ target->no_sandbox = src->no_sandbox;
+ cef_string_set(src->browser_subprocess_path.str,
+ src->browser_subprocess_path.length,
+ &target->browser_subprocess_path, copy);
+ cef_string_set(src->framework_dir_path.str, src->framework_dir_path.length,
+ &target->framework_dir_path, copy);
+ cef_string_set(src->main_bundle_path.str, src->main_bundle_path.length,
+ &target->main_bundle_path, copy);
+ target->chrome_runtime = src->chrome_runtime;
+ target->multi_threaded_message_loop = src->multi_threaded_message_loop;
+ target->external_message_pump = src->external_message_pump;
+ target->windowless_rendering_enabled = src->windowless_rendering_enabled;
+ target->command_line_args_disabled = src->command_line_args_disabled;
+
+ cef_string_set(src->cache_path.str, src->cache_path.length,
+ &target->cache_path, copy);
+ cef_string_set(src->root_cache_path.str, src->root_cache_path.length,
+ &target->root_cache_path, copy);
+ cef_string_set(src->user_data_path.str, src->user_data_path.length,
+ &target->user_data_path, copy);
+ target->persist_session_cookies = src->persist_session_cookies;
+ target->persist_user_preferences = src->persist_user_preferences;
+
+ cef_string_set(src->user_agent.str, src->user_agent.length,
+ &target->user_agent, copy);
+ cef_string_set(src->user_agent_product.str, src->user_agent_product.length,
+ &target->user_agent_product, copy);
+ cef_string_set(src->locale.str, src->locale.length, &target->locale, copy);
+
+ cef_string_set(src->log_file.str, src->log_file.length, &target->log_file,
+ copy);
+ target->log_severity = src->log_severity;
+ cef_string_set(src->javascript_flags.str, src->javascript_flags.length,
+ &target->javascript_flags, copy);
+
+ cef_string_set(src->resources_dir_path.str, src->resources_dir_path.length,
+ &target->resources_dir_path, copy);
+ cef_string_set(src->locales_dir_path.str, src->locales_dir_path.length,
+ &target->locales_dir_path, copy);
+ target->pack_loading_disabled = src->pack_loading_disabled;
+ target->remote_debugging_port = src->remote_debugging_port;
+ target->uncaught_exception_stack_size = src->uncaught_exception_stack_size;
+ target->background_color = src->background_color;
+
+ cef_string_set(src->accept_language_list.str,
+ src->accept_language_list.length,
+ &target->accept_language_list, copy);
+
+ cef_string_set(src->cookieable_schemes_list.str,
+ src->cookieable_schemes_list.length,
+ &target->cookieable_schemes_list, copy);
+ target->cookieable_schemes_exclude_defaults =
+ src->cookieable_schemes_exclude_defaults;
+ }
+};
+
+///
+/// Class representing initialization settings.
+///
+using CefSettings = CefStructBase<CefSettingsTraits>;
+
+struct CefRequestContextSettingsTraits {
+ using struct_type = cef_request_context_settings_t;
+
+ static inline void init(struct_type* s) { s->size = sizeof(struct_type); }
+
+ static inline void clear(struct_type* s) {
+ cef_string_clear(&s->cache_path);
+ cef_string_clear(&s->accept_language_list);
+ cef_string_clear(&s->cookieable_schemes_list);
+ }
+
+ static inline void set(const struct_type* src,
+ struct_type* target,
+ bool copy) {
+ cef_string_set(src->cache_path.str, src->cache_path.length,
+ &target->cache_path, copy);
+ target->persist_session_cookies = src->persist_session_cookies;
+ target->persist_user_preferences = src->persist_user_preferences;
+ cef_string_set(src->accept_language_list.str,
+ src->accept_language_list.length,
+ &target->accept_language_list, copy);
+
+ cef_string_set(src->cookieable_schemes_list.str,
+ src->cookieable_schemes_list.length,
+ &target->cookieable_schemes_list, copy);
+ target->cookieable_schemes_exclude_defaults =
+ src->cookieable_schemes_exclude_defaults;
+ }
+};
+
+///
+/// Class representing request context initialization settings.
+///
+using CefRequestContextSettings =
+ CefStructBase<CefRequestContextSettingsTraits>;
+
+struct CefBrowserSettingsTraits {
+ using struct_type = cef_browser_settings_t;
+
+ static inline void init(struct_type* s) { s->size = sizeof(struct_type); }
+
+ static inline void clear(struct_type* s) {
+ cef_string_clear(&s->standard_font_family);
+ cef_string_clear(&s->fixed_font_family);
+ cef_string_clear(&s->serif_font_family);
+ cef_string_clear(&s->sans_serif_font_family);
+ cef_string_clear(&s->cursive_font_family);
+ cef_string_clear(&s->fantasy_font_family);
+ cef_string_clear(&s->default_encoding);
+ cef_string_clear(&s->accept_language_list);
+ }
+
+ static inline void set(const struct_type* src,
+ struct_type* target,
+ bool copy) {
+ target->windowless_frame_rate = src->windowless_frame_rate;
+
+ cef_string_set(src->standard_font_family.str,
+ src->standard_font_family.length,
+ &target->standard_font_family, copy);
+ cef_string_set(src->fixed_font_family.str, src->fixed_font_family.length,
+ &target->fixed_font_family, copy);
+ cef_string_set(src->serif_font_family.str, src->serif_font_family.length,
+ &target->serif_font_family, copy);
+ cef_string_set(src->sans_serif_font_family.str,
+ src->sans_serif_font_family.length,
+ &target->sans_serif_font_family, copy);
+ cef_string_set(src->cursive_font_family.str,
+ src->cursive_font_family.length,
+ &target->cursive_font_family, copy);
+ cef_string_set(src->fantasy_font_family.str,
+ src->fantasy_font_family.length,
+ &target->fantasy_font_family, copy);
+
+ target->default_font_size = src->default_font_size;
+ target->default_fixed_font_size = src->default_fixed_font_size;
+ target->minimum_font_size = src->minimum_font_size;
+ target->minimum_logical_font_size = src->minimum_logical_font_size;
+
+ cef_string_set(src->default_encoding.str, src->default_encoding.length,
+ &target->default_encoding, copy);
+
+ target->remote_fonts = src->remote_fonts;
+ target->javascript = src->javascript;
+ target->javascript_close_windows = src->javascript_close_windows;
+ target->javascript_access_clipboard = src->javascript_access_clipboard;
+ target->javascript_dom_paste = src->javascript_dom_paste;
+ target->image_loading = src->image_loading;
+ target->image_shrink_standalone_to_fit =
+ src->image_shrink_standalone_to_fit;
+ target->text_area_resize = src->text_area_resize;
+ target->tab_to_links = src->tab_to_links;
+ target->local_storage = src->local_storage;
+ target->databases = src->databases;
+ target->webgl = src->webgl;
+
+ target->background_color = src->background_color;
+
+ cef_string_set(src->accept_language_list.str,
+ src->accept_language_list.length,
+ &target->accept_language_list, copy);
+
+ target->chrome_status_bubble = src->chrome_status_bubble;
+ }
+};
+
+///
+/// Class representing browser initialization settings.
+///
+using CefBrowserSettings = CefStructBase<CefBrowserSettingsTraits>;
+
+struct CefURLPartsTraits {
+ using struct_type = cef_urlparts_t;
+
+ static inline void init(struct_type* s) {}
+
+ static inline void clear(struct_type* s) {
+ cef_string_clear(&s->spec);
+ cef_string_clear(&s->scheme);
+ cef_string_clear(&s->username);
+ cef_string_clear(&s->password);
+ cef_string_clear(&s->host);
+ cef_string_clear(&s->port);
+ cef_string_clear(&s->origin);
+ cef_string_clear(&s->path);
+ cef_string_clear(&s->query);
+ cef_string_clear(&s->fragment);
+ }
+
+ static inline void set(const struct_type* src,
+ struct_type* target,
+ bool copy) {
+ cef_string_set(src->spec.str, src->spec.length, &target->spec, copy);
+ cef_string_set(src->scheme.str, src->scheme.length, &target->scheme, copy);
+ cef_string_set(src->username.str, src->username.length, &target->username,
+ copy);
+ cef_string_set(src->password.str, src->password.length, &target->password,
+ copy);
+ cef_string_set(src->host.str, src->host.length, &target->host, copy);
+ cef_string_set(src->port.str, src->port.length, &target->port, copy);
+ cef_string_set(src->origin.str, src->origin.length, &target->origin, copy);
+ cef_string_set(src->path.str, src->path.length, &target->path, copy);
+ cef_string_set(src->query.str, src->query.length, &target->query, copy);
+ cef_string_set(src->fragment.str, src->fragment.length, &target->fragment,
+ copy);
+ }
+};
+
+///
+/// Class representing a URL's component parts.
+///
+using CefURLParts = CefStructBase<CefURLPartsTraits>;
+
+///
+/// Class representing the state of a touch handle.
+///
+class CefTouchHandleState : public cef_touch_handle_state_t {
+ public:
+ CefTouchHandleState() : cef_touch_handle_state_t{} {}
+ CefTouchHandleState(const cef_touch_handle_state_t& r)
+ : cef_touch_handle_state_t(r) {}
+};
+
+struct CefCookieTraits {
+ using struct_type = cef_cookie_t;
+
+ static inline void init(struct_type* s) {}
+
+ static inline void clear(struct_type* s) {
+ cef_string_clear(&s->name);
+ cef_string_clear(&s->value);
+ cef_string_clear(&s->domain);
+ cef_string_clear(&s->path);
+ }
+
+ static inline void set(const struct_type* src,
+ struct_type* target,
+ bool copy) {
+ cef_string_set(src->name.str, src->name.length, &target->name, copy);
+ cef_string_set(src->value.str, src->value.length, &target->value, copy);
+ cef_string_set(src->domain.str, src->domain.length, &target->domain, copy);
+ cef_string_set(src->path.str, src->path.length, &target->path, copy);
+ target->secure = src->secure;
+ target->httponly = src->httponly;
+ target->creation = src->creation;
+ target->last_access = src->last_access;
+ target->has_expires = src->has_expires;
+ target->expires = src->expires;
+ target->same_site = src->same_site;
+ target->priority = src->priority;
+ }
+};
+
+///
+/// Class representing a cookie.
+///
+using CefCookie = CefStructBase<CefCookieTraits>;
+
+///
+/// Class representing cursor information.
+///
+class CefCursorInfo : public cef_cursor_info_t {
+ public:
+ CefCursorInfo() : cef_cursor_info_t{} {}
+ CefCursorInfo(const cef_cursor_info_t& r) : cef_cursor_info_t(r) {}
+};
+
+struct CefPdfPrintSettingsTraits {
+ using struct_type = cef_pdf_print_settings_t;
+
+ static inline void init(struct_type* s) {}
+
+ static inline void clear(struct_type* s) {
+ cef_string_clear(&s->page_ranges);
+ cef_string_clear(&s->header_template);
+ cef_string_clear(&s->footer_template);
+ }
+
+ static inline void set(const struct_type* src,
+ struct_type* target,
+ bool copy) {
+ target->landscape = src->landscape;
+ target->print_background = src->print_background;
+ target->scale = src->scale;
+ target->paper_width = src->paper_width;
+ target->paper_height = src->paper_height;
+ target->prefer_css_page_size = src->prefer_css_page_size;
+
+ target->margin_type = src->margin_type;
+ target->margin_top = src->margin_top;
+ target->margin_right = src->margin_right;
+ target->margin_bottom = src->margin_bottom;
+ target->margin_left = src->margin_left;
+
+ cef_string_set(src->page_ranges.str, src->page_ranges.length,
+ &target->page_ranges, copy);
+
+ target->display_header_footer = src->display_header_footer;
+ cef_string_set(src->header_template.str, src->header_template.length,
+ &target->header_template, copy);
+ cef_string_set(src->footer_template.str, src->footer_template.length,
+ &target->footer_template, copy);
+ }
+};
+
+///
+/// Class representing PDF print settings
+///
+using CefPdfPrintSettings = CefStructBase<CefPdfPrintSettingsTraits>;
+
+///
+/// Class representing CefBoxLayout settings.
+///
+class CefBoxLayoutSettings : public cef_box_layout_settings_t {
+ public:
+ CefBoxLayoutSettings() : cef_box_layout_settings_t{} {}
+ CefBoxLayoutSettings(const cef_box_layout_settings_t& r)
+ : cef_box_layout_settings_t(r) {}
+};
+
+///
+/// Class representing IME composition underline.
+///
+class CefCompositionUnderline : public cef_composition_underline_t {
+ public:
+ CefCompositionUnderline() : cef_composition_underline_t{} {}
+ CefCompositionUnderline(const cef_composition_underline_t& r)
+ : cef_composition_underline_t(r) {}
+};
+
+///
+/// Class representing CefAudioParameters settings
+///
+class CefAudioParameters : public cef_audio_parameters_t {
+ public:
+ CefAudioParameters() : cef_audio_parameters_t{} {}
+ CefAudioParameters(const cef_audio_parameters_t& r)
+ : cef_audio_parameters_t(r) {}
+};
+
+struct CefMediaSinkDeviceInfoTraits {
+ using struct_type = cef_media_sink_device_info_t;
+
+ static inline void init(struct_type* s) {}
+
+ static inline void clear(struct_type* s) {
+ cef_string_clear(&s->ip_address);
+ cef_string_clear(&s->model_name);
+ }
+
+ static inline void set(const struct_type* src,
+ struct_type* target,
+ bool copy) {
+ cef_string_set(src->ip_address.str, src->ip_address.length,
+ &target->ip_address, copy);
+ target->port = src->port;
+ cef_string_set(src->model_name.str, src->model_name.length,
+ &target->model_name, copy);
+ }
+};
+
+///
+/// Class representing MediaSink device info.
+///
+using CefMediaSinkDeviceInfo = CefStructBase<CefMediaSinkDeviceInfoTraits>;
+
+#endif // CEF_INCLUDE_INTERNAL_CEF_TYPES_WRAPPERS_H_
diff --git a/include/internal/cef_win.h b/include/internal/cef_win.h
new file mode 100644
index 00000000..cccc6d52
--- /dev/null
+++ b/include/internal/cef_win.h
@@ -0,0 +1,184 @@
+// Copyright (c) 2008 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CEF_INCLUDE_INTERNAL_CEF_WIN_H_
+#define CEF_INCLUDE_INTERNAL_CEF_WIN_H_
+#pragma once
+
+#include "include/internal/cef_app_win.h"
+#include "include/internal/cef_types_win.h"
+#include "include/internal/cef_types_wrappers.h"
+
+// Handle types.
+#define CefCursorHandle cef_cursor_handle_t
+#define CefEventHandle cef_event_handle_t
+#define CefWindowHandle cef_window_handle_t
+
+///
+/// Class representing CefExecuteProcess arguments.
+///
+class CefMainArgs : public cef_main_args_t {
+ public:
+ CefMainArgs() : cef_main_args_t{} {}
+ CefMainArgs(const cef_main_args_t& r) : cef_main_args_t(r) {}
+ explicit CefMainArgs(HINSTANCE hInstance) : cef_main_args_t{hInstance} {}
+};
+
+struct CefWindowInfoTraits {
+ typedef cef_window_info_t struct_type;
+
+ static inline void init(struct_type* s) {}
+
+ static inline void clear(struct_type* s) {
+ cef_string_clear(&s->window_name);
+ }
+
+ static inline void set(const struct_type* src,
+ struct_type* target,
+ bool copy) {
+ target->ex_style = src->ex_style;
+ cef_string_set(src->window_name.str, src->window_name.length,
+ &target->window_name, copy);
+ target->style = src->style;
+ target->bounds = src->bounds;
+ target->parent_window = src->parent_window;
+ target->menu = src->menu;
+ target->windowless_rendering_enabled = src->windowless_rendering_enabled;
+ target->shared_texture_enabled = src->shared_texture_enabled;
+ target->external_begin_frame_enabled = src->external_begin_frame_enabled;
+ target->window = src->window;
+ }
+};
+
+///
+/// Class representing window information.
+///
+class CefWindowInfo : public CefStructBase<CefWindowInfoTraits> {
+ public:
+ typedef CefStructBase<CefWindowInfoTraits> parent;
+
+ CefWindowInfo() : parent() {}
+ explicit CefWindowInfo(const cef_window_info_t& r) : parent(r) {}
+ explicit CefWindowInfo(const CefWindowInfo& r) : parent(r) {}
+
+ CefWindowInfo& operator=(const CefWindowInfo&) = default;
+ CefWindowInfo& operator=(CefWindowInfo&&) = default;
+
+ ///
+ /// Create the browser as a child window.
+ ///
+ void SetAsChild(CefWindowHandle parent, const CefRect& windowBounds) {
+ style =
+ WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_TABSTOP | WS_VISIBLE;
+ parent_window = parent;
+ bounds = windowBounds;
+ }
+
+ ///
+ /// Create the browser as a popup window.
+ ///
+ void SetAsPopup(CefWindowHandle parent, const CefString& windowName) {
+ style =
+ WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE;
+ parent_window = parent;
+ bounds.x = CW_USEDEFAULT;
+ bounds.y = CW_USEDEFAULT;
+ bounds.width = CW_USEDEFAULT;
+ bounds.height = CW_USEDEFAULT;
+
+ cef_string_copy(windowName.c_str(), windowName.length(), &window_name);
+ }
+
+ ///
+ /// Create the browser using windowless (off-screen) rendering. No window
+ /// will be created for the browser and all rendering will occur via the
+ /// CefRenderHandler interface. The |parent| value will be used to identify
+ /// monitor info and to act as the parent window for dialogs, context menus,
+ /// etc. If |parent| is not provided then the main screen monitor will be used
+ /// and some functionality that requires a parent window may not function
+ /// correctly. In order to create windowless browsers the
+ /// CefSettings.windowless_rendering_enabled value must be set to true.
+ /// Transparent painting is enabled by default but can be disabled by setting
+ /// CefBrowserSettings.background_color to an opaque value.
+ ///
+ void SetAsWindowless(CefWindowHandle parent) {
+ windowless_rendering_enabled = TRUE;
+ parent_window = parent;
+ }
+};
+
+#if defined(ARCH_CPU_32_BITS)
+///
+/// Run the main thread on 32-bit Windows using a fiber with the preferred 4MiB
+/// stack size. This function must be called at the top of the executable entry
+/// point function (`main()` or `wWinMain()`). It is used in combination with
+/// the initial stack size of 0.5MiB configured via the `/STACK:0x80000` linker
+/// flag on executable targets. This saves significant memory on threads (like
+/// those in the Windows thread pool, and others) whose stack size can only be
+/// controlled via the linker flag.
+///
+/// CEF's main thread needs at least a 1.5 MiB stack size in order to avoid
+/// stack overflow crashes. However, if this is set in the PE file then other
+/// threads get this size as well, leading to address-space exhaustion in 32-bit
+/// CEF. This function uses fibers to switch the main thread to a 4 MiB stack
+/// (roughly the same effective size as the 64-bit build's 8 MiB stack) before
+/// running any other code.
+///
+/// Choose the function variant that matches the entry point function type used
+/// by the executable. Reusing the entry point minimizes confusion when
+/// examining call stacks in crash reports.
+///
+/// If this function is already running on the fiber it will return -1
+/// immediately, meaning that execution should proceed with the remainder of the
+/// entry point function. Otherwise, this function will block until the entry
+/// point function has completed execution on the fiber and then return a result
+/// >= 0, meaning that the entry point function should return the result
+/// immediately without proceeding with execution.
+///
+int CefRunWinMainWithPreferredStackSize(wWinMainPtr wWinMain,
+ HINSTANCE hInstance,
+ LPWSTR lpCmdLine,
+ int nCmdShow);
+int CefRunMainWithPreferredStackSize(mainPtr main, int argc, char* argv[]);
+#endif // defined(ARCH_CPU_32_BITS)
+
+///
+/// Call during process startup to enable High-DPI support on Windows 7 or
+/// newer. Older versions of Windows should be left DPI-unaware because they do
+/// not support DirectWrite and GDI fonts are kerned very badly.
+///
+void CefEnableHighDPISupport();
+
+///
+/// Set to true before calling Windows APIs like TrackPopupMenu that enter a
+/// modal message loop. Set to false after exiting the modal message loop.
+///
+void CefSetOSModalLoop(bool osModalLoop);
+
+#endif // CEF_INCLUDE_INTERNAL_CEF_WIN_H_
diff --git a/include/test/cef_test_helpers.h b/include/test/cef_test_helpers.h
new file mode 100644
index 00000000..7f7c3741
--- /dev/null
+++ b/include/test/cef_test_helpers.h
@@ -0,0 +1,70 @@
+// Copyright (c) 2017 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+// THIS FILE IS FOR TESTING PURPOSES ONLY.
+//
+// The APIs defined in this file are for testing purposes only. They should only
+// be included from unit test targets.
+//
+
+#ifndef CEF_INCLUDE_TEST_CEF_TEST_HELPERS_H_
+#define CEF_INCLUDE_TEST_CEF_TEST_HELPERS_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED) && !defined(WRAPPING_CEF_SHARED) && \
+ !defined(UNIT_TEST)
+#error This file can be included for unit tests only
+#endif
+
+#include "include/cef_frame.h"
+
+///
+/// Execute JavaScript with a user gesture to trigger functionality like
+/// onbeforeunload handlers that will otherwise be blocked.
+///
+/*--cef(optional_param=javascript)--*/
+void CefExecuteJavaScriptWithUserGestureForTests(CefRefPtr<CefFrame> frame,
+ const CefString& javascript);
+
+///
+/// Set the DIR_SRC_TEST_DATA_ROOT directory used to load test data. Must be
+/// configured when running from a CEF binary distribution. Defaults to the
+/// "chromium/src" directory when running from a local CEF/Chromium build. |dir|
+/// must be an absolute path.
+///
+/*--cef()--*/
+void CefSetDataDirectoryForTests(const CefString& dir);
+
+#endif // CEF_INCLUDE_TEST_CEF_TEST_HELPERS_H_
diff --git a/include/test/cef_test_server.h b/include/test/cef_test_server.h
new file mode 100644
index 00000000..37f7a739
--- /dev/null
+++ b/include/test/cef_test_server.h
@@ -0,0 +1,184 @@
+// Copyright (c) 2022 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+// THIS FILE IS FOR TESTING PURPOSES ONLY.
+//
+// The APIs defined in this file are for testing purposes only. They should only
+// be included from unit test targets.
+//
+
+#ifndef CEF_INCLUDE_TEST_CEF_TEST_SERVER_H_
+#define CEF_INCLUDE_TEST_CEF_TEST_SERVER_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED) && !defined(WRAPPING_CEF_SHARED) && \
+ !defined(UNIT_TEST)
+#error This file can be included for unit tests only
+#endif
+
+#include <map>
+#include "include/cef_base.h"
+#include "include/cef_request.h"
+
+class CefTestServerConnection;
+class CefTestServerHandler;
+
+///
+/// Class representing an embedded test server that supports HTTP/HTTPS
+/// requests. This is a basic server providing only an essential subset of the
+/// HTTP/1.1 protocol. Especially, it assumes that the request syntax is
+/// correct. It *does not* support a Chunked Transfer Encoding. Server capacity
+/// is limited and is intended to handle only a small number of simultaneous
+/// connections (e.g. for communicating between applications on localhost). The
+/// methods of this class are safe to call from any thread in the brower process
+/// unless otherwise indicated.
+///
+/*--cef(source=library)--*/
+class CefTestServer : public CefBaseRefCounted {
+ public:
+ ///
+ /// Create and start a new test server that binds to |port|. If |port| is 0 an
+ /// available port number will be selected. If |https_server| is true the
+ /// server will be HTTPS, otherwise it will be HTTP. When |https_server| is
+ /// true the |https_cert_type| value is used to configure the certificate
+ /// type. Returns the newly created server object on success, or nullptr if
+ /// the server cannot be started.
+ ///
+ /// A new thread will be created for each CreateAndStart call (the "dedicated
+ /// server thread"). It is therefore recommended to use a different
+ /// CefTestServerHandler instance for each CreateAndStart call to avoid thread
+ /// safety issues in the CefTestServerHandler implementation.
+ ///
+ /// On success, this method will block until the dedicated server thread has
+ /// started. The server will continue running until Stop is called.
+ ///
+ /*--cef()--*/
+ static CefRefPtr<CefTestServer> CreateAndStart(
+ uint16 port,
+ bool https_server,
+ cef_test_cert_type_t https_cert_type,
+ CefRefPtr<CefTestServerHandler> handler);
+
+ ///
+ /// Stop the server and shut down the dedicated server thread. This method
+ /// must be called on the same thread as CreateAndStart. It will block until
+ /// the dedicated server thread has shut down.
+ ///
+ /*--cef()--*/
+ virtual void Stop() = 0;
+
+ ///
+ /// Returns the server origin including the port number (e.g.
+ /// "[http|https]://127.0.0.1:<port>".
+ ///
+ /*--cef()--*/
+ virtual CefString GetOrigin() = 0;
+};
+
+///
+/// Implement this interface to handle test server requests. A new thread will
+/// be created for each CefTestServer::CreateAndStart call (the "dedicated
+/// server thread"), and the methods of this class will be called on that
+/// thread. See related documentation on CefTestServer::CreateAndStart.
+///
+/*--cef(source=client)--*/
+class CefTestServerHandler : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Called when |server| receives a request. To handle the request return true
+ /// and use |connection| to send the response either synchronously or
+ /// asynchronously. Otherwise, return false if the request is unhandled. When
+ /// returning false do not call any |connection| methods.
+ ///
+ /*--cef()--*/
+ virtual bool OnTestServerRequest(
+ CefRefPtr<CefTestServer> server,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefTestServerConnection> connection) = 0;
+};
+
+///
+/// Class representing a test server connection. The methods of this class are
+/// safe to call from any thread in the brower process unless otherwise
+/// indicated.
+///
+/*--cef(source=library)--*/
+class CefTestServerConnection : public CefBaseRefCounted {
+ public:
+ typedef std::multimap<CefString, CefString> HeaderMap;
+
+ ///
+ /// Send an HTTP 200 "OK" response. |content_type| is the response content
+ /// type (e.g. "text/html"). |data| is the response content and |data_size| is
+ /// the size of |data| in bytes. The contents of |data| will be copied. The
+ /// connection will be closed automatically after the response is sent.
+ ///
+ /*--cef()--*/
+ virtual void SendHttp200Response(const CefString& content_type,
+ const void* data,
+ size_t data_size) = 0;
+
+ ///
+ /// Send an HTTP 404 "Not Found" response. The connection will be closed
+ /// automatically after the response is sent.
+ ///
+ /*--cef()--*/
+ virtual void SendHttp404Response() = 0;
+
+ ///
+ /// Send an HTTP 500 "Internal Server Error" response. |error_message| is the
+ /// associated error message. The connection will be closed automatically
+ /// after the response is sent.
+ ///
+ /*--cef()--*/
+ virtual void SendHttp500Response(const CefString& error_message) = 0;
+
+ ///
+ /// Send a custom HTTP response. |response_code| is the HTTP response code
+ /// sent in the status line (e.g. 200). |content_type| is the response content
+ /// type (e.g. "text/html"). |data| is the response content and |data_size| is
+ /// the size of |data| in bytes. The contents of |data| will be copied.
+ /// |extra_headers| is an optional map of additional header key/value pairs.
+ /// The connection will be closed automatically after the response is sent.
+ ///
+ /*--cef(optional_param=extra_headers)--*/
+ virtual void SendHttpResponse(int response_code,
+ const CefString& content_type,
+ const void* data,
+ size_t data_size,
+ const HeaderMap& extra_headers) = 0;
+};
+
+#endif // CEF_INCLUDE_TEST_CEF_TEST_SERVER_H_
diff --git a/include/test/cef_translator_test.h b/include/test/cef_translator_test.h
new file mode 100644
index 00000000..8ac49343
--- /dev/null
+++ b/include/test/cef_translator_test.h
@@ -0,0 +1,808 @@
+// Copyright (c) 2015 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+// THIS FILE IS FOR TESTING PURPOSES ONLY.
+//
+// The APIs defined in this file are for testing purposes only. They should only
+// be included from unit test targets.
+//
+
+#ifndef CEF_INCLUDE_TEST_CEF_TEST_H_
+#define CEF_INCLUDE_TEST_CEF_TEST_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED) && !defined(WRAPPING_CEF_SHARED) && \
+ !defined(UNIT_TEST)
+#error This file can be included for unit tests only
+#endif
+
+#include <map>
+#include <vector>
+
+#include "include/cef_base.h"
+
+class CefTranslatorTestRefPtrClient;
+class CefTranslatorTestRefPtrClientChild;
+class CefTranslatorTestRefPtrLibrary;
+class CefTranslatorTestRefPtrLibraryChild;
+class CefTranslatorTestScopedClient;
+class CefTranslatorTestScopedClientChild;
+class CefTranslatorTestScopedLibrary;
+class CefTranslatorTestScopedLibraryChild;
+
+// Test values.
+#define TEST_INT_VAL 5
+#define TEST_INT_VAL2 60
+#define TEST_BOOL_VAL true
+#define TEST_DOUBLE_VAL 4.543
+#define TEST_LONG_VAL -65
+#define TEST_SIZET_VAL 3U
+#define TEST_STRING_VAL "My test string"
+#define TEST_STRING_VAL2 "My 2nd test string"
+#define TEST_STRING_VAL3 "My 3rd test string"
+#define TEST_STRING_KEY "key0"
+#define TEST_STRING_KEY2 "key1"
+#define TEST_STRING_KEY3 "key2"
+#define TEST_X_VAL 44
+#define TEST_Y_VAL 754
+#define TEST_X_VAL2 900
+#define TEST_Y_VAL2 300
+
+///
+/// Class for testing all of the possible data transfer types.
+///
+/*--cef(source=library)--*/
+class CefTranslatorTest : public CefBaseRefCounted {
+ public:
+ ///
+ /// Create the test object.
+ ///
+ /*--cef()--*/
+ static CefRefPtr<CefTranslatorTest> Create();
+
+ // PRIMITIVE VALUES
+
+ ///
+ /// Return a void value.
+ ///
+ /*--cef()--*/
+ virtual void GetVoid() = 0;
+
+ ///
+ /// Return a bool value.
+ ///
+ /*--cef()--*/
+ virtual bool GetBool() = 0;
+
+ ///
+ /// Return an int value.
+ ///
+ /*--cef()--*/
+ virtual int GetInt() = 0;
+
+ ///
+ /// Return a double value.
+ ///
+ /*--cef()--*/
+ virtual double GetDouble() = 0;
+
+ ///
+ /// Return a long value.
+ ///
+ /*--cef()--*/
+ virtual long GetLong() = 0;
+
+ ///
+ /// Return a size_t value.
+ ///
+ /*--cef()--*/
+ virtual size_t GetSizet() = 0;
+
+ ///
+ /// Set a void value.
+ ///
+ /*--cef()--*/
+ virtual bool SetVoid() = 0;
+
+ ///
+ /// Set a bool value.
+ ///
+ /*--cef()--*/
+ virtual bool SetBool(bool val) = 0;
+
+ ///
+ /// Set an int value.
+ ///
+ /*--cef()--*/
+ virtual bool SetInt(int val) = 0;
+
+ ///
+ /// Set a double value.
+ ///
+ /*--cef()--*/
+ virtual bool SetDouble(double val) = 0;
+
+ ///
+ /// Set a long value.
+ ///
+ /*--cef()--*/
+ virtual bool SetLong(long val) = 0;
+
+ ///
+ /// Set a size_t value.
+ ///
+ /*--cef()--*/
+ virtual bool SetSizet(size_t val) = 0;
+
+ // PRIMITIVE LIST VALUES
+
+ // Test both with and without a typedef.
+ typedef std::vector<int> IntList;
+
+ ///
+ /// Set a int list value.
+ ///
+ /*--cef()--*/
+ virtual bool SetIntList(const std::vector<int>& val) = 0;
+
+ ///
+ /// Return an int list value by out-param.
+ ///
+ /*--cef(count_func=val:GetIntListSize)--*/
+ virtual bool GetIntListByRef(IntList& val) = 0;
+
+ ///
+ /// Return the number of points that will be output above.
+ ///
+ /*--cef()--*/
+ virtual size_t GetIntListSize() = 0;
+
+ // STRING VALUES
+
+ ///
+ /// Return a string value.
+ ///
+ /*--cef()--*/
+ virtual CefString GetString() = 0;
+
+ ///
+ /// Set a string value.
+ ///
+ /*--cef()--*/
+ virtual bool SetString(const CefString& val) = 0;
+
+ ///
+ /// Return a string value by out-param.
+ ///
+ /*--cef()--*/
+ virtual void GetStringByRef(CefString& val) = 0;
+
+ // STRING LIST VALUES
+
+ // Test both with and without a typedef.
+ typedef std::vector<CefString> StringList;
+
+ ///
+ /// Set a string list value.
+ ///
+ /*--cef()--*/
+ virtual bool SetStringList(const std::vector<CefString>& val) = 0;
+
+ ///
+ /// Return a string list value by out-param.
+ ///
+ /*--cef()--*/
+ virtual bool GetStringListByRef(StringList& val) = 0;
+
+ // STRING MAP VALUES
+
+ // Test both with and without a typedef.
+ typedef std::map<CefString, CefString> StringMap;
+
+ ///
+ /// Set a string map value.
+ ///
+ /*--cef()--*/
+ virtual bool SetStringMap(const StringMap& val) = 0;
+
+ ///
+ /// Return a string map value by out-param.
+ ///
+ /*--cef()--*/
+ virtual bool GetStringMapByRef(std::map<CefString, CefString>& val) = 0;
+
+ // STRING MULTIMAP VALUES
+
+ // Test both with and without a typedef.
+ typedef std::multimap<CefString, CefString> StringMultimap;
+
+ ///
+ /// Set a string multimap value.
+ ///
+ /*--cef()--*/
+ virtual bool SetStringMultimap(
+ const std::multimap<CefString, CefString>& val) = 0;
+
+ ///
+ /// Return a string multimap value by out-param.
+ ///
+ /*--cef()--*/
+ virtual bool GetStringMultimapByRef(StringMultimap& val) = 0;
+
+ // STRUCT VALUES
+
+ ///
+ /// Return a point value.
+ ///
+ /*--cef()--*/
+ virtual CefPoint GetPoint() = 0;
+
+ ///
+ /// Set a point value.
+ ///
+ /*--cef()--*/
+ virtual bool SetPoint(const CefPoint& val) = 0;
+
+ ///
+ /// Return a point value by out-param.
+ ///
+ /*--cef()--*/
+ virtual void GetPointByRef(CefPoint& val) = 0;
+
+ // STRUCT LIST VALUES
+
+ // Test both with and without a typedef.
+ typedef std::vector<CefPoint> PointList;
+
+ ///
+ /// Set a point list vlaue.
+ ///
+ /*--cef()--*/
+ virtual bool SetPointList(const std::vector<CefPoint>& val) = 0;
+
+ ///
+ /// Return a point list value by out-param.
+ ///
+ /*--cef(count_func=val:GetPointListSize)--*/
+ virtual bool GetPointListByRef(PointList& val) = 0;
+
+ ///
+ /// Return the number of points that will be output above.
+ ///
+ /*--cef()--*/
+ virtual size_t GetPointListSize() = 0;
+
+ // LIBRARY-SIDE REFPTR VALUES
+
+ ///
+ /// Return an new library-side object.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefTranslatorTestRefPtrLibrary> GetRefPtrLibrary(
+ int val) = 0;
+
+ ///
+ /// Set an object. Returns the value from
+ /// CefTranslatorTestRefPtrLibrary::GetValue().
+ /// This tests input and execution of a library-side object type.
+ ///
+ /*--cef()--*/
+ virtual int SetRefPtrLibrary(
+ CefRefPtr<CefTranslatorTestRefPtrLibrary> val) = 0;
+
+ ///
+ /// Set an object. Returns the object passed in. This tests input and output
+ /// of a library-side object type.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefTranslatorTestRefPtrLibrary> SetRefPtrLibraryAndReturn(
+ CefRefPtr<CefTranslatorTestRefPtrLibrary> val) = 0;
+
+ ///
+ /// Set a child object. Returns the value from
+ /// CefTranslatorTestRefPtrLibrary::GetValue(). This tests input of a library-
+ /// side child object type and execution as the parent type.
+ ///
+ /*--cef()--*/
+ virtual int SetChildRefPtrLibrary(
+ CefRefPtr<CefTranslatorTestRefPtrLibraryChild> val) = 0;
+
+ ///
+ /// Set a child object. Returns the object as the parent type. This tests
+ /// input of a library-side child object type and return as the parent type.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefTranslatorTestRefPtrLibrary>
+ SetChildRefPtrLibraryAndReturnParent(
+ CefRefPtr<CefTranslatorTestRefPtrLibraryChild> val) = 0;
+
+ // LIBRARY-SIDE REFPTR LIST VALUES
+
+ // Test both with and without a typedef.
+ typedef std::vector<CefRefPtr<CefTranslatorTestRefPtrLibrary>>
+ RefPtrLibraryList;
+
+ ///
+ /// Set an object list vlaue.
+ ///
+ /*--cef()--*/
+ virtual bool SetRefPtrLibraryList(
+ const std::vector<CefRefPtr<CefTranslatorTestRefPtrLibrary>>& val,
+ int val1,
+ int val2) = 0;
+
+ ///
+ /// Return an object list value by out-param.
+ ///
+ /*--cef(count_func=val:GetRefPtrLibraryListSize)--*/
+ virtual bool GetRefPtrLibraryListByRef(RefPtrLibraryList& val,
+ int val1,
+ int val2) = 0;
+
+ ///
+ /// Return the number of object that will be output above.
+ ///
+ /*--cef()--*/
+ virtual size_t GetRefPtrLibraryListSize() = 0;
+
+ // CLIENT-SIDE REFPTR VALUES
+
+ ///
+ /// Set an object. Returns the value from
+ /// CefTranslatorTestRefPtrClient::GetValue().
+ /// This tests input and execution of a client-side object type.
+ ///
+ /*--cef()--*/
+ virtual int SetRefPtrClient(CefRefPtr<CefTranslatorTestRefPtrClient> val) = 0;
+
+ ///
+ /// Set an object. Returns the handler passed in. This tests input and output
+ /// of a client-side object type.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefTranslatorTestRefPtrClient> SetRefPtrClientAndReturn(
+ CefRefPtr<CefTranslatorTestRefPtrClient> val) = 0;
+
+ ///
+ /// Set a child object. Returns the value from
+ /// CefTranslatorTestRefPtrClient::GetValue(). This tests input of a client-
+ /// side child object type and execution as the parent type.
+ ///
+ /*--cef()--*/
+ virtual int SetChildRefPtrClient(
+ CefRefPtr<CefTranslatorTestRefPtrClientChild> val) = 0;
+
+ ///
+ /// Set a child object. Returns the object as the parent type. This tests
+ /// input of a client-side child object type and return as the parent type.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefTranslatorTestRefPtrClient>
+ SetChildRefPtrClientAndReturnParent(
+ CefRefPtr<CefTranslatorTestRefPtrClientChild> val) = 0;
+
+ // CLIENT-SIDE REFPTR LIST VALUES
+
+ // Test both with and without a typedef.
+ typedef std::vector<CefRefPtr<CefTranslatorTestRefPtrClient>>
+ RefPtrClientList;
+
+ ///
+ /// Set an object list vlaue.
+ ///
+ /*--cef()--*/
+ virtual bool SetRefPtrClientList(
+ const std::vector<CefRefPtr<CefTranslatorTestRefPtrClient>>& val,
+ int val1,
+ int val2) = 0;
+
+ ///
+ /// Return an object list value by out-param.
+ ///
+ /*--cef(count_func=val:GetRefPtrLibraryListSize)--*/
+ virtual bool GetRefPtrClientListByRef(
+ RefPtrClientList& val,
+ CefRefPtr<CefTranslatorTestRefPtrClient> val1,
+ CefRefPtr<CefTranslatorTestRefPtrClient> val2) = 0;
+
+ ///
+ /// Return the number of object that will be output above.
+ ///
+ /*--cef()--*/
+ virtual size_t GetRefPtrClientListSize() = 0;
+
+ // LIBRARY-SIDE OWNPTR VALUES
+
+ ///
+ /// Return an new library-side object.
+ ///
+ /*--cef()--*/
+ virtual CefOwnPtr<CefTranslatorTestScopedLibrary> GetOwnPtrLibrary(
+ int val) = 0;
+
+ ///
+ /// Set an object. Returns the value from
+ /// CefTranslatorTestScopedLibrary::GetValue().
+ /// This tests input and execution of a library-side object type.
+ ///
+ /*--cef()--*/
+ virtual int SetOwnPtrLibrary(
+ CefOwnPtr<CefTranslatorTestScopedLibrary> val) = 0;
+
+ ///
+ /// Set an object. Returns the object passed in. This tests input and output
+ /// of a library-side object type.
+ ///
+ /*--cef()--*/
+ virtual CefOwnPtr<CefTranslatorTestScopedLibrary> SetOwnPtrLibraryAndReturn(
+ CefOwnPtr<CefTranslatorTestScopedLibrary> val) = 0;
+
+ ///
+ /// Set a child object. Returns the value from
+ /// CefTranslatorTestScopedLibrary::GetValue(). This tests input of a library-
+ /// side child object type and execution as the parent type.
+ ///
+ /*--cef()--*/
+ virtual int SetChildOwnPtrLibrary(
+ CefOwnPtr<CefTranslatorTestScopedLibraryChild> val) = 0;
+
+ ///
+ /// Set a child object. Returns the object as the parent type. This tests
+ /// input of a library-side child object type and return as the parent type.
+ ///
+ /*--cef()--*/
+ virtual CefOwnPtr<CefTranslatorTestScopedLibrary>
+ SetChildOwnPtrLibraryAndReturnParent(
+ CefOwnPtr<CefTranslatorTestScopedLibraryChild> val) = 0;
+
+ // CLIENT-SIDE OWNPTR VALUES
+
+ ///
+ /// Set an object. Returns the value from
+ /// CefTranslatorTestScopedClient::GetValue().
+ /// This tests input and execution of a client-side object type.
+ ///
+ /*--cef()--*/
+ virtual int SetOwnPtrClient(CefOwnPtr<CefTranslatorTestScopedClient> val) = 0;
+
+ ///
+ /// Set an object. Returns the handler passed in. This tests input and output
+ /// of a client-side object type.
+ ///
+ /*--cef()--*/
+ virtual CefOwnPtr<CefTranslatorTestScopedClient> SetOwnPtrClientAndReturn(
+ CefOwnPtr<CefTranslatorTestScopedClient> val) = 0;
+
+ ///
+ /// Set a child object. Returns the value from
+ /// CefTranslatorTestScopedClient::GetValue(). This tests input of a client-
+ /// side child object type and execution as the parent type.
+ ///
+ /*--cef()--*/
+ virtual int SetChildOwnPtrClient(
+ CefOwnPtr<CefTranslatorTestScopedClientChild> val) = 0;
+
+ ///
+ /// Set a child object. Returns the object as the parent type. This tests
+ /// input of a client-side child object type and return as the parent type.
+ ///
+ /*--cef()--*/
+ virtual CefOwnPtr<CefTranslatorTestScopedClient>
+ SetChildOwnPtrClientAndReturnParent(
+ CefOwnPtr<CefTranslatorTestScopedClientChild> val) = 0;
+
+ // LIBRARY-SIDE RAWPTR VALUES
+
+ ///
+ /// Set an object. Returns the value from
+ /// CefTranslatorTestScopedLibrary::GetValue().
+ /// This tests input and execution of a library-side object type.
+ ///
+ /*--cef()--*/
+ virtual int SetRawPtrLibrary(
+ CefRawPtr<CefTranslatorTestScopedLibrary> val) = 0;
+
+ ///
+ /// Set a child object. Returns the value from
+ /// CefTranslatorTestScopedLibrary::GetValue(). This tests input of a library-
+ /// side child object type and execution as the parent type.
+ ///
+ /*--cef()--*/
+ virtual int SetChildRawPtrLibrary(
+ CefRawPtr<CefTranslatorTestScopedLibraryChild> val) = 0;
+
+ // LIBRARY-SIDE RAWPTR LIST VALUES
+
+ // Test both with and without a typedef.
+ typedef std::vector<CefRawPtr<CefTranslatorTestScopedLibrary>>
+ RawPtrLibraryList;
+
+ ///
+ /// Set an object list vlaue.
+ ///
+ /*--cef()--*/
+ virtual bool SetRawPtrLibraryList(
+ const std::vector<CefRawPtr<CefTranslatorTestScopedLibrary>>& val,
+ int val1,
+ int val2) = 0;
+
+ // CLIENT-SIDE RAWPTR VALUES
+
+ ///
+ /// Set an object. Returns the value from
+ /// CefTranslatorTestScopedClient::GetValue().
+ /// This tests input and execution of a client-side object type.
+ ///
+ /*--cef()--*/
+ virtual int SetRawPtrClient(CefRawPtr<CefTranslatorTestScopedClient> val) = 0;
+
+ ///
+ /// Set a child object. Returns the value from
+ /// CefTranslatorTestScopedClient::GetValue(). This tests input of a client-
+ /// side child object type and execution as the parent type.
+ ///
+ /*--cef()--*/
+ virtual int SetChildRawPtrClient(
+ CefRawPtr<CefTranslatorTestScopedClientChild> val) = 0;
+
+ // CLIENT-SIDE RAWPTR LIST VALUES
+
+ // Test both with and without a typedef.
+ typedef std::vector<CefRawPtr<CefTranslatorTestScopedClient>>
+ RawPtrClientList;
+
+ ///
+ /// Set an object list vlaue.
+ ///
+ /*--cef()--*/
+ virtual bool SetRawPtrClientList(
+ const std::vector<CefRawPtr<CefTranslatorTestScopedClient>>& val,
+ int val1,
+ int val2) = 0;
+};
+
+///
+/// Library-side test object for RefPtr.
+///
+/*--cef(source=library)--*/
+class CefTranslatorTestRefPtrLibrary : public CefBaseRefCounted {
+ public:
+ ///
+ /// Create the test object.
+ ///
+ /*--cef()--*/
+ static CefRefPtr<CefTranslatorTestRefPtrLibrary> Create(int value);
+
+ ///
+ /// Return a value.
+ ///
+ /*--cef()--*/
+ virtual int GetValue() = 0;
+
+ ///
+ /// Set a value.
+ ///
+ /*--cef()--*/
+ virtual void SetValue(int value) = 0;
+};
+
+///
+/// Library-side child test object for RefPtr.
+///
+/*--cef(source=library)--*/
+class CefTranslatorTestRefPtrLibraryChild
+ : public CefTranslatorTestRefPtrLibrary {
+ public:
+ ///
+ /// Create the test object.
+ ///
+ /*--cef()--*/
+ static CefRefPtr<CefTranslatorTestRefPtrLibraryChild> Create(int value,
+ int other_value);
+
+ ///
+ /// Return a value.
+ ///
+ /*--cef()--*/
+ virtual int GetOtherValue() = 0;
+
+ ///
+ /// Set a value.
+ ///
+ /*--cef()--*/
+ virtual void SetOtherValue(int value) = 0;
+};
+
+///
+/// Another library-side child test object for RefPtr.
+///
+/*--cef(source=library)--*/
+class CefTranslatorTestRefPtrLibraryChildChild
+ : public CefTranslatorTestRefPtrLibraryChild {
+ public:
+ ///
+ /// Create the test object.
+ ///
+ /*--cef()--*/
+ static CefRefPtr<CefTranslatorTestRefPtrLibraryChildChild>
+ Create(int value, int other_value, int other_other_value);
+
+ ///
+ /// Return a value.
+ ///
+ /*--cef()--*/
+ virtual int GetOtherOtherValue() = 0;
+
+ ///
+ /// Set a value.
+ ///
+ /*--cef()--*/
+ virtual void SetOtherOtherValue(int value) = 0;
+};
+
+///
+/// Client-side test object for RefPtr.
+///
+/*--cef(source=client)--*/
+class CefTranslatorTestRefPtrClient : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Return a value.
+ ///
+ /*--cef()--*/
+ virtual int GetValue() = 0;
+};
+
+///
+/// Client-side child test object for RefPtr.
+///
+/*--cef(source=client)--*/
+class CefTranslatorTestRefPtrClientChild
+ : public CefTranslatorTestRefPtrClient {
+ public:
+ ///
+ /// Return a value.
+ ///
+ /*--cef()--*/
+ virtual int GetOtherValue() = 0;
+};
+
+///
+/// Library-side test object for OwnPtr/RawPtr.
+///
+/*--cef(source=library)--*/
+class CefTranslatorTestScopedLibrary : public CefBaseScoped {
+ public:
+ ///
+ /// Create the test object.
+ ///
+ /*--cef()--*/
+ static CefOwnPtr<CefTranslatorTestScopedLibrary> Create(int value);
+
+ ///
+ /// Return a value.
+ ///
+ /*--cef()--*/
+ virtual int GetValue() = 0;
+
+ ///
+ /// Set a value.
+ ///
+ /*--cef()--*/
+ virtual void SetValue(int value) = 0;
+};
+
+///
+/// Library-side child test object for OwnPtr/RawPtr.
+///
+/*--cef(source=library)--*/
+class CefTranslatorTestScopedLibraryChild
+ : public CefTranslatorTestScopedLibrary {
+ public:
+ ///
+ /// Create the test object.
+ ///
+ /*--cef()--*/
+ static CefOwnPtr<CefTranslatorTestScopedLibraryChild> Create(int value,
+ int other_value);
+
+ ///
+ /// Return a value.
+ ///
+ /*--cef()--*/
+ virtual int GetOtherValue() = 0;
+
+ ///
+ /// Set a value.
+ ///
+ /*--cef()--*/
+ virtual void SetOtherValue(int value) = 0;
+};
+
+///
+/// Another library-side child test object for OwnPtr/RawPtr.
+///
+/*--cef(source=library)--*/
+class CefTranslatorTestScopedLibraryChildChild
+ : public CefTranslatorTestScopedLibraryChild {
+ public:
+ ///
+ /// Create the test object.
+ ///
+ /*--cef()--*/
+ static CefOwnPtr<CefTranslatorTestScopedLibraryChildChild>
+ Create(int value, int other_value, int other_other_value);
+
+ ///
+ /// Return a value.
+ ///
+ /*--cef()--*/
+ virtual int GetOtherOtherValue() = 0;
+
+ ///
+ /// Set a value.
+ ///
+ /*--cef()--*/
+ virtual void SetOtherOtherValue(int value) = 0;
+};
+
+///
+/// Client-side test object for OwnPtr/RawPtr.
+///
+/*--cef(source=client)--*/
+class CefTranslatorTestScopedClient : public virtual CefBaseScoped {
+ public:
+ ///
+ /// Return a value.
+ ///
+ /*--cef()--*/
+ virtual int GetValue() = 0;
+};
+
+///
+/// Client-side child test object for OwnPtr/RawPtr.
+///
+/*--cef(source=client)--*/
+class CefTranslatorTestScopedClientChild
+ : public CefTranslatorTestScopedClient {
+ public:
+ ///
+ /// Return a value.
+ ///
+ /*--cef()--*/
+ virtual int GetOtherValue() = 0;
+};
+
+#endif // CEF_INCLUDE_TEST_CEF_TEST_H_
diff --git a/include/views/cef_box_layout.h b/include/views/cef_box_layout.h
new file mode 100644
index 00000000..14bb8d2f
--- /dev/null
+++ b/include/views/cef_box_layout.h
@@ -0,0 +1,74 @@
+// Copyright (c) 2016 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_VIEWS_CEF_BOX_LAYOUT_H_
+#define CEF_INCLUDE_VIEWS_CEF_BOX_LAYOUT_H_
+#pragma once
+
+#include "include/views/cef_layout.h"
+
+class CefView;
+
+///
+/// A Layout manager that arranges child views vertically or horizontally in a
+/// side-by-side fashion with spacing around and between the child views. The
+/// child views are always sized according to their preferred size. If the
+/// host's bounds provide insufficient space, child views will be clamped.
+/// Excess space will not be distributed. Methods must be called on the browser
+/// process UI thread unless otherwise indicated.
+///
+/*--cef(source=library)--*/
+class CefBoxLayout : public CefLayout {
+ public:
+ ///
+ /// Set the flex weight for the given |view|. Using the preferred size as
+ /// the basis, free space along the main axis is distributed to views in the
+ /// ratio of their flex weights. Similarly, if the views will overflow the
+ /// parent, space is subtracted in these ratios. A flex of 0 means this view
+ /// is not resized. Flex values must not be negative.
+ ///
+ /*--cef()--*/
+ virtual void SetFlexForView(CefRefPtr<CefView> view, int flex) = 0;
+
+ ///
+ /// Clears the flex for the given |view|, causing it to use the default flex
+ /// specified via CefBoxLayoutSettings.default_flex.
+ ///
+ /*--cef()--*/
+ virtual void ClearFlexForView(CefRefPtr<CefView> view) = 0;
+};
+
+#endif // CEF_INCLUDE_VIEWS_CEF_BOX_LAYOUT_H_
diff --git a/include/views/cef_browser_view.h b/include/views/cef_browser_view.h
new file mode 100644
index 00000000..e8b4218f
--- /dev/null
+++ b/include/views/cef_browser_view.h
@@ -0,0 +1,107 @@
+// Copyright (c) 2016 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_VIEWS_CEF_BROWSER_VIEW_H_
+#define CEF_INCLUDE_VIEWS_CEF_BROWSER_VIEW_H_
+#pragma once
+
+#include "include/cef_browser.h"
+#include "include/views/cef_browser_view_delegate.h"
+#include "include/views/cef_view.h"
+
+///
+/// A View hosting a CefBrowser instance. Methods must be called on the browser
+/// process UI thread unless otherwise indicated.
+///
+/*--cef(source=library)--*/
+class CefBrowserView : public CefView {
+ public:
+ ///
+ /// Create a new BrowserView. The underlying CefBrowser will not be created
+ /// until this view is added to the views hierarchy. The optional |extra_info|
+ /// parameter provides an opportunity to specify extra information specific
+ /// to the created browser that will be passed to
+ /// CefRenderProcessHandler::OnBrowserCreated() in the render process.
+ ///
+ /*--cef(optional_param=client,optional_param=url,
+ optional_param=request_context,optional_param=delegate,
+ optional_param=extra_info)--*/
+ static CefRefPtr<CefBrowserView> CreateBrowserView(
+ CefRefPtr<CefClient> client,
+ const CefString& url,
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefDictionaryValue> extra_info,
+ CefRefPtr<CefRequestContext> request_context,
+ CefRefPtr<CefBrowserViewDelegate> delegate);
+
+ ///
+ /// Returns the BrowserView associated with |browser|.
+ ///
+ /*--cef()--*/
+ static CefRefPtr<CefBrowserView> GetForBrowser(CefRefPtr<CefBrowser> browser);
+
+ ///
+ /// Returns the CefBrowser hosted by this BrowserView. Will return NULL if the
+ /// browser has not yet been created or has already been destroyed.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefBrowser> GetBrowser() = 0;
+
+ ///
+ /// Returns the Chrome toolbar associated with this BrowserView. Only
+ /// supported when using the Chrome runtime. The CefBrowserViewDelegate::
+ /// GetChromeToolbarType() method must return a value other than
+ /// CEF_CTT_NONE and the toolbar will not be available until after this
+ /// BrowserView is added to a CefWindow and CefViewDelegate::OnWindowChanged()
+ /// has been called.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefView> GetChromeToolbar() = 0;
+
+ ///
+ /// Sets whether accelerators registered with CefWindow::SetAccelerator are
+ /// triggered before or after the event is sent to the CefBrowser. If
+ /// |prefer_accelerators| is true then the matching accelerator will be
+ /// triggered immediately and the event will not be sent to the CefBrowser. If
+ /// |prefer_accelerators| is false then the matching accelerator will only be
+ /// triggered if the event is not handled by web content or by
+ /// CefKeyboardHandler. The default value is false.
+ ///
+ /*--cef()--*/
+ virtual void SetPreferAccelerators(bool prefer_accelerators) = 0;
+};
+
+#endif // CEF_INCLUDE_VIEWS_CEF_BROWSER_VIEW_H_
diff --git a/include/views/cef_browser_view_delegate.h b/include/views/cef_browser_view_delegate.h
new file mode 100644
index 00000000..262c1452
--- /dev/null
+++ b/include/views/cef_browser_view_delegate.h
@@ -0,0 +1,119 @@
+// Copyright (c) 2016 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_VIEWS_CEF_BROWSER_VIEW_DELEGATE_H_
+#define CEF_INCLUDE_VIEWS_CEF_BROWSER_VIEW_DELEGATE_H_
+#pragma once
+
+#include "include/cef_client.h"
+#include "include/views/cef_view_delegate.h"
+
+class CefBrowser;
+class CefBrowserView;
+
+///
+/// Implement this interface to handle BrowserView events. The methods of this
+/// class will be called on the browser process UI thread unless otherwise
+/// indicated.
+///
+/*--cef(source=client)--*/
+class CefBrowserViewDelegate : public CefViewDelegate {
+ public:
+ typedef cef_chrome_toolbar_type_t ChromeToolbarType;
+
+ ///
+ /// Called when |browser| associated with |browser_view| is created. This
+ /// method will be called after CefLifeSpanHandler::OnAfterCreated() is called
+ /// for |browser| and before OnPopupBrowserViewCreated() is called for
+ /// |browser|'s parent delegate if |browser| is a popup.
+ ///
+ /*--cef()--*/
+ virtual void OnBrowserCreated(CefRefPtr<CefBrowserView> browser_view,
+ CefRefPtr<CefBrowser> browser) {}
+
+ ///
+ /// Called when |browser| associated with |browser_view| is destroyed. Release
+ /// all references to |browser| and do not attempt to execute any methods on
+ /// |browser| after this callback returns. This method will be called before
+ /// CefLifeSpanHandler::OnBeforeClose() is called for |browser|.
+ ///
+ /*--cef()--*/
+ virtual void OnBrowserDestroyed(CefRefPtr<CefBrowserView> browser_view,
+ CefRefPtr<CefBrowser> browser) {}
+
+ ///
+ /// Called before a new popup BrowserView is created. The popup originated
+ /// from |browser_view|. |settings| and |client| are the values returned from
+ /// CefLifeSpanHandler::OnBeforePopup(). |is_devtools| will be true if the
+ /// popup will be a DevTools browser. Return the delegate that will be used
+ /// for the new popup BrowserView.
+ ///
+ /*--cef(optional_param=client)--*/
+ virtual CefRefPtr<CefBrowserViewDelegate> GetDelegateForPopupBrowserView(
+ CefRefPtr<CefBrowserView> browser_view,
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefClient> client,
+ bool is_devtools) {
+ return this;
+ }
+
+ ///
+ /// Called after |popup_browser_view| is created. This method will be called
+ /// after CefLifeSpanHandler::OnAfterCreated() and OnBrowserCreated() are
+ /// called for the new popup browser. The popup originated from
+ /// |browser_view|. |is_devtools| will be true if the popup is a DevTools
+ /// browser. Optionally add |popup_browser_view| to the views hierarchy
+ /// yourself and return true. Otherwise return false and a default CefWindow
+ /// will be created for the popup.
+ ///
+ /*--cef()--*/
+ virtual bool OnPopupBrowserViewCreated(
+ CefRefPtr<CefBrowserView> browser_view,
+ CefRefPtr<CefBrowserView> popup_browser_view,
+ bool is_devtools) {
+ return false;
+ }
+
+ ///
+ /// Returns the Chrome toolbar type that will be available via
+ /// CefBrowserView::GetChromeToolbar(). See that method for related
+ /// documentation.
+ ///
+ /*--cef(default_retval=CEF_CTT_NONE)--*/
+ virtual ChromeToolbarType GetChromeToolbarType() { return CEF_CTT_NONE; }
+};
+
+#endif // CEF_INCLUDE_VIEWS_CEF_BROWSER_VIEW_DELEGATE_H_
diff --git a/include/views/cef_button.h b/include/views/cef_button.h
new file mode 100644
index 00000000..944a7bb2
--- /dev/null
+++ b/include/views/cef_button.h
@@ -0,0 +1,92 @@
+// Copyright (c) 2016 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_VIEWS_CEF_BUTTON_H_
+#define CEF_INCLUDE_VIEWS_CEF_BUTTON_H_
+#pragma once
+
+#include "include/views/cef_view.h"
+
+class CefLabelButton;
+
+///
+/// A View representing a button. Depending on the specific type, the button
+/// could be implemented by a native control or custom rendered. Methods must be
+/// called on the browser process UI thread unless otherwise indicated.
+///
+/*--cef(source=library)--*/
+class CefButton : public CefView {
+ public:
+ ///
+ /// Returns this Button as a LabelButton or NULL if this is not a LabelButton.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefLabelButton> AsLabelButton() = 0;
+
+ ///
+ /// Sets the current display state of the Button.
+ ///
+ /*--cef()--*/
+ virtual void SetState(cef_button_state_t state) = 0;
+
+ ///
+ /// Returns the current display state of the Button.
+ ///
+ /*--cef(default_retval=CEF_BUTTON_STATE_NORMAL)--*/
+ virtual cef_button_state_t GetState() = 0;
+
+ ///
+ /// Sets the Button will use an ink drop effect for displaying state changes.
+ ///
+ /*--cef()--*/
+ virtual void SetInkDropEnabled(bool enabled) = 0;
+
+ ///
+ /// Sets the tooltip text that will be displayed when the user hovers the
+ /// mouse cursor over the Button.
+ ///
+ /*--cef()--*/
+ virtual void SetTooltipText(const CefString& tooltip_text) = 0;
+
+ ///
+ /// Sets the accessible name that will be exposed to assistive technology
+ /// (AT).
+ ///
+ /*--cef()--*/
+ virtual void SetAccessibleName(const CefString& name) = 0;
+};
+
+#endif // CEF_INCLUDE_VIEWS_CEF_BUTTON_H_
diff --git a/include/views/cef_button_delegate.h b/include/views/cef_button_delegate.h
new file mode 100644
index 00000000..3d6ee227
--- /dev/null
+++ b/include/views/cef_button_delegate.h
@@ -0,0 +1,65 @@
+// Copyright (c) 2016 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_VIEWS_CEF_BUTTON_DELEGATE_H_
+#define CEF_INCLUDE_VIEWS_CEF_BUTTON_DELEGATE_H_
+#pragma once
+
+#include "include/views/cef_view_delegate.h"
+
+class CefButton;
+
+///
+/// Implement this interface to handle Button events. The methods of this class
+/// will be called on the browser process UI thread unless otherwise indicated.
+///
+/*--cef(source=client)--*/
+class CefButtonDelegate : public CefViewDelegate {
+ public:
+ ///
+ /// Called when |button| is pressed.
+ ///
+ /*--cef()--*/
+ virtual void OnButtonPressed(CefRefPtr<CefButton> button) = 0;
+
+ ///
+ /// Called when the state of |button| changes.
+ ///
+ /*--cef()--*/
+ virtual void OnButtonStateChanged(CefRefPtr<CefButton> button) {}
+};
+
+#endif // CEF_INCLUDE_VIEWS_CEF_BUTTON_DELEGATE_H_
diff --git a/include/views/cef_display.h b/include/views/cef_display.h
new file mode 100644
index 00000000..574410ef
--- /dev/null
+++ b/include/views/cef_display.h
@@ -0,0 +1,172 @@
+// Copyright (c) 2016 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_VIEWS_CEF_DISPLAY_H_
+#define CEF_INCLUDE_VIEWS_CEF_DISPLAY_H_
+#pragma once
+
+#include <vector>
+
+#include "include/cef_base.h"
+
+///
+/// This class typically, but not always, corresponds to a physical display
+/// connected to the system. A fake Display may exist on a headless system, or a
+/// Display may correspond to a remote, virtual display. All size and position
+/// values are in density independent pixel (DIP) coordinates unless otherwise
+/// indicated. Methods must be called on the browser process UI thread unless
+/// otherwise indicated.
+///
+/*--cef(source=library)--*/
+class CefDisplay : public CefBaseRefCounted {
+ public:
+ ///
+ /// Returns the primary Display.
+ ///
+ /*--cef()--*/
+ static CefRefPtr<CefDisplay> GetPrimaryDisplay();
+
+ ///
+ /// Returns the Display nearest |point|. Set |input_pixel_coords| to true if
+ /// |point| is in pixel screen coordinates instead of DIP screen coordinates.
+ ///
+ /*--cef()--*/
+ static CefRefPtr<CefDisplay> GetDisplayNearestPoint(const CefPoint& point,
+ bool input_pixel_coords);
+
+ ///
+ /// Returns the Display that most closely intersects |bounds|. Set
+ /// |input_pixel_coords| to true if |bounds| is in pixel screen coordinates
+ /// instead of DIP screen coordinates.
+ ///
+ /*--cef()--*/
+ static CefRefPtr<CefDisplay> GetDisplayMatchingBounds(
+ const CefRect& bounds,
+ bool input_pixel_coords);
+
+ ///
+ /// Returns the total number of Displays. Mirrored displays are excluded; this
+ /// method is intended to return the number of distinct, usable displays.
+ ///
+ /*--cef()--*/
+ static size_t GetDisplayCount();
+
+ ///
+ /// Returns all Displays. Mirrored displays are excluded; this method is
+ /// intended to return distinct, usable displays.
+ ///
+ /*--cef(count_func=displays:GetDisplayCount)--*/
+ static void GetAllDisplays(std::vector<CefRefPtr<CefDisplay>>& displays);
+
+ ///
+ /// Convert |point| from DIP screen coordinates to pixel screen coordinates.
+ /// This method is only used on Windows.
+ ///
+ /*--cef()--*/
+ static CefPoint ConvertScreenPointToPixels(const CefPoint& point);
+
+ ///
+ /// Convert |point| from pixel screen coordinates to DIP screen coordinates.
+ /// This method is only used on Windows.
+ ///
+ /*--cef()--*/
+ static CefPoint ConvertScreenPointFromPixels(const CefPoint& point);
+
+ ///
+ /// Convert |rect| from DIP screen coordinates to pixel screen coordinates.
+ /// This method is only used on Windows.
+ ///
+ /*--cef()--*/
+ static CefRect ConvertScreenRectToPixels(const CefRect& rect);
+
+ ///
+ /// Convert |rect| from pixel screen coordinates to DIP screen coordinates.
+ /// This method is only used on Windows.
+ ///
+ /*--cef()--*/
+ static CefRect ConvertScreenRectFromPixels(const CefRect& rect);
+
+ ///
+ /// Returns the unique identifier for this Display.
+ ///
+ /*--cef()--*/
+ virtual int64 GetID() = 0;
+
+ ///
+ /// Returns this Display's device pixel scale factor. This specifies how much
+ /// the UI should be scaled when the actual output has more pixels than
+ /// standard displays (which is around 100~120dpi). The potential return
+ /// values differ by platform.
+ ///
+ /*--cef()--*/
+ virtual float GetDeviceScaleFactor() = 0;
+
+ ///
+ /// Convert |point| from DIP coordinates to pixel coordinates using this
+ /// Display's device scale factor.
+ ///
+ /*--cef()--*/
+ virtual void ConvertPointToPixels(CefPoint& point) = 0;
+
+ ///
+ /// Convert |point| from pixel coordinates to DIP coordinates using this
+ /// Display's device scale factor.
+ ///
+ /*--cef()--*/
+ virtual void ConvertPointFromPixels(CefPoint& point) = 0;
+
+ ///
+ /// Returns this Display's bounds in DIP screen coordinates. This is the full
+ /// size of the display.
+ ///
+ /*--cef()--*/
+ virtual CefRect GetBounds() = 0;
+
+ ///
+ /// Returns this Display's work area in DIP screen coordinates. This excludes
+ /// areas of the display that are occupied with window manager toolbars, etc.
+ ///
+ /*--cef()--*/
+ virtual CefRect GetWorkArea() = 0;
+
+ ///
+ /// Returns this Display's rotation in degrees.
+ ///
+ /*--cef()--*/
+ virtual int GetRotation() = 0;
+};
+
+#endif // CEF_INCLUDE_VIEWS_CEF_DISPLAY_H_
diff --git a/include/views/cef_fill_layout.h b/include/views/cef_fill_layout.h
new file mode 100644
index 00000000..eedbc94e
--- /dev/null
+++ b/include/views/cef_fill_layout.h
@@ -0,0 +1,51 @@
+// Copyright (c) 2016 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_VIEWS_CEF_FILL_LAYOUT_H_
+#define CEF_INCLUDE_VIEWS_CEF_FILL_LAYOUT_H_
+#pragma once
+
+#include "include/views/cef_layout.h"
+
+///
+/// A simple Layout that causes the associated Panel's one child to be sized to
+/// match the bounds of its parent. Methods must be called on the browser
+/// process UI thread unless otherwise indicated.
+///
+/*--cef(source=library)--*/
+class CefFillLayout : public CefLayout {};
+
+#endif // CEF_INCLUDE_VIEWS_CEF_FILL_LAYOUT_H_
diff --git a/include/views/cef_label_button.h b/include/views/cef_label_button.h
new file mode 100644
index 00000000..c099d437
--- /dev/null
+++ b/include/views/cef_label_button.h
@@ -0,0 +1,149 @@
+// Copyright (c) 2016 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_VIEWS_CEF_LABEL_BUTTON_H_
+#define CEF_INCLUDE_VIEWS_CEF_LABEL_BUTTON_H_
+#pragma once
+
+#include "include/cef_image.h"
+#include "include/views/cef_button.h"
+#include "include/views/cef_button_delegate.h"
+
+class CefMenuButton;
+
+///
+/// LabelButton is a button with optional text and/or icon. Methods must be
+/// called on the browser process UI thread unless otherwise indicated.
+///
+/*--cef(source=library)--*/
+class CefLabelButton : public CefButton {
+ public:
+ ///
+ /// Create a new LabelButton. A |delegate| must be provided to handle the
+ /// button click. |text| will be shown on the LabelButton and used as the
+ /// default accessible name.
+ ///
+ /*--cef(optional_param=text)--*/
+ static CefRefPtr<CefLabelButton> CreateLabelButton(
+ CefRefPtr<CefButtonDelegate> delegate,
+ const CefString& text);
+
+ ///
+ /// Returns this LabelButton as a MenuButton or NULL if this is not a
+ /// MenuButton.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefMenuButton> AsMenuButton() = 0;
+
+ ///
+ /// Sets the text shown on the LabelButton. By default |text| will also be
+ /// used as the accessible name.
+ ///
+ /*--cef()--*/
+ virtual void SetText(const CefString& text) = 0;
+
+ ///
+ /// Returns the text shown on the LabelButton.
+ ///
+ /*--cef()--*/
+ virtual CefString GetText() = 0;
+
+ ///
+ /// Sets the image shown for |button_state|. When this Button is drawn if no
+ /// image exists for the current state then the image for
+ /// CEF_BUTTON_STATE_NORMAL, if any, will be shown.
+ ///
+ /*--cef(optional_param=image)--*/
+ virtual void SetImage(cef_button_state_t button_state,
+ CefRefPtr<CefImage> image) = 0;
+
+ ///
+ /// Returns the image shown for |button_state|. If no image exists for that
+ /// state then the image for CEF_BUTTON_STATE_NORMAL will be returned.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefImage> GetImage(cef_button_state_t button_state) = 0;
+
+ ///
+ /// Sets the text color shown for the specified button |for_state| to |color|.
+ ///
+ /*--cef()--*/
+ virtual void SetTextColor(cef_button_state_t for_state,
+ cef_color_t color) = 0;
+
+ ///
+ /// Sets the text colors shown for the non-disabled states to |color|.
+ ///
+ /*--cef()--*/
+ virtual void SetEnabledTextColors(cef_color_t color) = 0;
+
+ ///
+ /// Sets the font list. The format is "<FONT_FAMILY_LIST>,[STYLES] <SIZE>",
+ /// where:
+ /// - FONT_FAMILY_LIST is a comma-separated list of font family names,
+ /// - STYLES is an optional space-separated list of style names
+ /// (case-sensitive
+ /// "Bold" and "Italic" are supported), and
+ /// - SIZE is an integer font size in pixels with the suffix "px".
+ ///
+ /// Here are examples of valid font description strings:
+ /// - "Arial, Helvetica, Bold Italic 14px"
+ /// - "Arial, 14px"
+ ///
+ /*--cef()--*/
+ virtual void SetFontList(const CefString& font_list) = 0;
+
+ ///
+ /// Sets the horizontal alignment; reversed in RTL. Default is
+ /// CEF_HORIZONTAL_ALIGNMENT_CENTER.
+ ///
+ /*--cef()--*/
+ virtual void SetHorizontalAlignment(cef_horizontal_alignment_t alignment) = 0;
+
+ ///
+ /// Reset the minimum size of this LabelButton to |size|.
+ ///
+ /*--cef()--*/
+ virtual void SetMinimumSize(const CefSize& size) = 0;
+
+ ///
+ /// Reset the maximum size of this LabelButton to |size|.
+ ///
+ /*--cef()--*/
+ virtual void SetMaximumSize(const CefSize& size) = 0;
+};
+
+#endif // CEF_INCLUDE_VIEWS_CEF_LABEL_BUTTON_H_
diff --git a/include/views/cef_layout.h b/include/views/cef_layout.h
new file mode 100644
index 00000000..61687dab
--- /dev/null
+++ b/include/views/cef_layout.h
@@ -0,0 +1,73 @@
+// Copyright (c) 2016 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_VIEWS_CEF_LAYOUT_H_
+#define CEF_INCLUDE_VIEWS_CEF_LAYOUT_H_
+#pragma once
+
+#include "include/cef_base.h"
+
+class CefBoxLayout;
+class CefFillLayout;
+
+///
+/// A Layout handles the sizing of the children of a Panel according to
+/// implementation-specific heuristics. Methods must be called on the browser
+/// process UI thread unless otherwise indicated.
+///
+/*--cef(source=library)--*/
+class CefLayout : public CefBaseRefCounted {
+ public:
+ ///
+ /// Returns this Layout as a BoxLayout or NULL if this is not a BoxLayout.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefBoxLayout> AsBoxLayout() = 0;
+
+ ///
+ /// Returns this Layout as a FillLayout or NULL if this is not a FillLayout.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefFillLayout> AsFillLayout() = 0;
+
+ ///
+ /// Returns true if this Layout is valid.
+ ///
+ /*--cef()--*/
+ virtual bool IsValid() = 0;
+};
+
+#endif // CEF_INCLUDE_VIEWS_CEF_LAYOUT_H_
diff --git a/include/views/cef_menu_button.h b/include/views/cef_menu_button.h
new file mode 100644
index 00000000..11f1bf45
--- /dev/null
+++ b/include/views/cef_menu_button.h
@@ -0,0 +1,88 @@
+// Copyright (c) 2016 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_VIEWS_CEF_MENU_BUTTON_H_
+#define CEF_INCLUDE_VIEWS_CEF_MENU_BUTTON_H_
+#pragma once
+
+#include "include/cef_menu_model.h"
+#include "include/views/cef_label_button.h"
+#include "include/views/cef_menu_button_delegate.h"
+
+///
+/// MenuButton is a button with optional text, icon and/or menu marker that
+/// shows a menu when clicked with the left mouse button. All size and position
+/// values are in density independent pixels (DIP) unless otherwise indicated.
+/// Methods must be called on the browser process UI thread unless otherwise
+/// indicated.
+///
+/*--cef(source=library)--*/
+class CefMenuButton : public CefLabelButton {
+ public:
+ ///
+ /// Create a new MenuButton. A |delegate| must be provided to call ShowMenu()
+ /// when the button is clicked. |text| will be shown on the MenuButton and
+ /// used as the default accessible name. If |with_frame| is true the button
+ /// will have a visible frame at all times, center alignment, additional
+ /// padding and a default minimum size of 70x33 DIP. If |with_frame| is false
+ /// the button will only have a visible frame on hover/press, left alignment,
+ /// less padding and no default minimum size.
+ ///
+ /*--cef(optional_param=text)--*/
+ static CefRefPtr<CefMenuButton> CreateMenuButton(
+ CefRefPtr<CefMenuButtonDelegate> delegate,
+ const CefString& text);
+
+ ///
+ /// Show a menu with contents |menu_model|. |screen_point| specifies the menu
+ /// position in screen coordinates. |anchor_position| specifies how the menu
+ /// will be anchored relative to |screen_point|. This method should be called
+ /// from CefMenuButtonDelegate::OnMenuButtonPressed().
+ ///
+ /*--cef()--*/
+ virtual void ShowMenu(CefRefPtr<CefMenuModel> menu_model,
+ const CefPoint& screen_point,
+ cef_menu_anchor_position_t anchor_position) = 0;
+
+ ///
+ /// Show the menu for this button. Results in a call to
+ /// CefMenuButtonDelegate::OnMenuButtonPressed().
+ ///
+ /*--cef()--*/
+ virtual void TriggerMenu() = 0;
+};
+
+#endif // CEF_INCLUDE_VIEWS_CEF_MENU_BUTTON_H_
diff --git a/include/views/cef_menu_button_delegate.h b/include/views/cef_menu_button_delegate.h
new file mode 100644
index 00000000..333e80e1
--- /dev/null
+++ b/include/views/cef_menu_button_delegate.h
@@ -0,0 +1,72 @@
+// Copyright (c) 2016 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_VIEWS_CEF_MENU_BUTTON_DELEGATE_H_
+#define CEF_INCLUDE_VIEWS_CEF_MENU_BUTTON_DELEGATE_H_
+#pragma once
+
+#include "include/views/cef_button_delegate.h"
+
+class CefMenuButton;
+
+///
+/// MenuButton pressed lock is released when this object is destroyed.
+///
+/*--cef(source=library)--*/
+class CefMenuButtonPressedLock : public CefBaseRefCounted {};
+
+///
+/// Implement this interface to handle MenuButton events. The methods of this
+/// class will be called on the browser process UI thread unless otherwise
+/// indicated.
+///
+/*--cef(source=client)--*/
+class CefMenuButtonDelegate : public CefButtonDelegate {
+ public:
+ ///
+ /// Called when |button| is pressed. Call CefMenuButton::ShowMenu() to show a
+ /// popup menu at |screen_point|. When showing a custom popup such as a window
+ /// keep a reference to |button_pressed_lock| until the popup is hidden to
+ /// maintain the pressed button state.
+ ///
+ /*--cef()--*/
+ virtual void OnMenuButtonPressed(
+ CefRefPtr<CefMenuButton> menu_button,
+ const CefPoint& screen_point,
+ CefRefPtr<CefMenuButtonPressedLock> button_pressed_lock) = 0;
+};
+
+#endif // CEF_INCLUDE_VIEWS_CEF_MENU_BUTTON_DELEGATE_H_
diff --git a/include/views/cef_overlay_controller.h b/include/views/cef_overlay_controller.h
new file mode 100644
index 00000000..038c26d5
--- /dev/null
+++ b/include/views/cef_overlay_controller.h
@@ -0,0 +1,210 @@
+// Copyright (c) 2021 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_VIEWS_CEF_OVERLAY_CONTROLLER_H_
+#define CEF_INCLUDE_VIEWS_CEF_OVERLAY_CONTROLLER_H_
+#pragma once
+
+#include "include/cef_base.h"
+
+class CefView;
+class CefWindow;
+
+///
+/// Controller for an overlay that contains a contents View added via
+/// CefWindow::AddOverlayView. Methods exposed by this controller should be
+/// called in preference to methods of the same name exposed by the contents
+/// View unless otherwise indicated. Methods must be called on the browser
+/// process UI thread unless otherwise indicated.
+///
+/*--cef(source=library)--*/
+class CefOverlayController : public CefBaseRefCounted {
+ public:
+ ///
+ /// Returns true if this object is valid.
+ ///
+ /*--cef()--*/
+ virtual bool IsValid() = 0;
+
+ ///
+ /// Returns true if this object is the same as |that| object.
+ ///
+ /*--cef()--*/
+ virtual bool IsSame(CefRefPtr<CefOverlayController> that) = 0;
+
+ ///
+ /// Returns the contents View for this overlay.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefView> GetContentsView() = 0;
+
+ ///
+ /// Returns the top-level Window hosting this overlay. Use this method instead
+ /// of calling GetWindow() on the contents View.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefWindow> GetWindow() = 0;
+
+ ///
+ /// Returns the docking mode for this overlay.
+ ///
+ /*--cef(default_retval=CEF_DOCKING_MODE_TOP_LEFT)--*/
+ virtual cef_docking_mode_t GetDockingMode() = 0;
+
+ ///
+ /// Destroy this overlay.
+ ///
+ /*--cef()--*/
+ virtual void Destroy() = 0;
+
+ ///
+ /// Sets the bounds (size and position) of this overlay. This will set the
+ /// bounds of the contents View to match and trigger a re-layout if necessary.
+ /// |bounds| is in parent coordinates and any insets configured on this
+ /// overlay will be ignored. Use this method only for overlays created with a
+ /// docking mode value of CEF_DOCKING_MODE_CUSTOM. With other docking modes
+ /// modify the insets of this overlay and/or layout of the contents View and
+ /// call SizeToPreferredSize() instead to calculate the new size and
+ /// re-position the overlay if necessary.
+ ///
+ /*--cef()--*/
+ virtual void SetBounds(const CefRect& bounds) = 0;
+
+ ///
+ /// Returns the bounds (size and position) of this overlay in parent
+ /// coordinates.
+ ///
+ /*--cef()--*/
+ virtual CefRect GetBounds() = 0;
+
+ ///
+ /// Returns the bounds (size and position) of this overlay in DIP screen
+ /// coordinates.
+ ///
+ /*--cef()--*/
+ virtual CefRect GetBoundsInScreen() = 0;
+
+ ///
+ /// Sets the size of this overlay without changing the position. This will set
+ /// the size of the contents View to match and trigger a re-layout if
+ /// necessary. |size| is in parent coordinates and any insets configured on
+ /// this overlay will be ignored. Use this method only for overlays created
+ /// with a docking mode value of CEF_DOCKING_MODE_CUSTOM. With other docking
+ /// modes modify the insets of this overlay and/or layout of the contents View
+ /// and call SizeToPreferredSize() instead to calculate the new size and
+ /// re-position the overlay if necessary.
+ ///
+ /*--cef()--*/
+ virtual void SetSize(const CefSize& size) = 0;
+
+ ///
+ /// Returns the size of this overlay in parent coordinates.
+ ///
+ /*--cef()--*/
+ virtual CefSize GetSize() = 0;
+
+ ///
+ /// Sets the position of this overlay without changing the size. |position| is
+ /// in parent coordinates and any insets configured on this overlay will
+ /// be ignored. Use this method only for overlays created with a docking mode
+ /// value of CEF_DOCKING_MODE_CUSTOM. With other docking modes modify the
+ /// insets of this overlay and/or layout of the contents View and call
+ /// SizeToPreferredSize() instead to calculate the new size and re-position
+ /// the overlay if necessary.
+ ///
+ /*--cef()--*/
+ virtual void SetPosition(const CefPoint& position) = 0;
+
+ ///
+ /// Returns the position of this overlay in parent coordinates.
+ ///
+ /*--cef()--*/
+ virtual CefPoint GetPosition() = 0;
+
+ ///
+ /// Sets the insets for this overlay. |insets| is in parent coordinates. Use
+ /// this method only for overlays created with a docking mode value other than
+ /// CEF_DOCKING_MODE_CUSTOM.
+ ///
+ /*--cef()--*/
+ virtual void SetInsets(const CefInsets& insets) = 0;
+
+ ///
+ /// Returns the insets for this overlay in parent coordinates.
+ ///
+ /*--cef()--*/
+ virtual CefInsets GetInsets() = 0;
+
+ ///
+ /// Size this overlay to its preferred size and trigger a re-layout if
+ /// necessary. The position of overlays created with a docking mode value of
+ /// CEF_DOCKING_MODE_CUSTOM will not be modified by calling this method. With
+ /// other docking modes this method may re-position the overlay if necessary
+ /// to accommodate the new size and any insets configured on the contents
+ /// View.
+ ///
+ /*--cef()--*/
+ virtual void SizeToPreferredSize() = 0;
+
+ ///
+ /// Sets whether this overlay is visible. Overlays are hidden by default. If
+ /// this overlay is hidden then it and any child Views will not be drawn and,
+ /// if any of those Views currently have focus, then focus will also be
+ /// cleared. Painting is scheduled as needed.
+ ///
+ /*--cef()--*/
+ virtual void SetVisible(bool visible) = 0;
+
+ ///
+ /// Returns whether this overlay is visible. A View may be visible but still
+ /// not drawn in a Window if any parent Views are hidden. Call IsDrawn() to
+ /// determine whether this overlay and all parent Views are visible and will
+ /// be drawn.
+ ///
+ /*--cef()--*/
+ virtual bool IsVisible() = 0;
+
+ ///
+ /// Returns whether this overlay is visible and drawn in a Window. A View is
+ /// drawn if it and all parent Views are visible. To determine if the
+ /// containing Window is visible to the user on-screen call IsVisible() on the
+ /// Window.
+ ///
+ /*--cef()--*/
+ virtual bool IsDrawn() = 0;
+};
+
+#endif // CEF_INCLUDE_VIEWS_CEF_OVERLAY_CONTROLLER_H_
diff --git a/include/views/cef_panel.h b/include/views/cef_panel.h
new file mode 100644
index 00000000..f74c2281
--- /dev/null
+++ b/include/views/cef_panel.h
@@ -0,0 +1,141 @@
+// Copyright (c) 2016 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_VIEWS_CEF_PANEL_H_
+#define CEF_INCLUDE_VIEWS_CEF_PANEL_H_
+#pragma once
+
+#include "include/views/cef_panel_delegate.h"
+#include "include/views/cef_view.h"
+
+class CefBoxLayout;
+class CefFillLayout;
+class CefLayout;
+class CefWindow;
+
+///
+/// A Panel is a container in the views hierarchy that can contain other Views
+/// as children. Methods must be called on the browser process UI thread unless
+/// otherwise indicated.
+///
+/*--cef(source=library)--*/
+class CefPanel : public CefView {
+ public:
+ ///
+ /// Create a new Panel.
+ ///
+ /*--cef(optional_param=delegate)--*/
+ static CefRefPtr<CefPanel> CreatePanel(CefRefPtr<CefPanelDelegate> delegate);
+
+ ///
+ /// Returns this Panel as a Window or NULL if this is not a Window.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefWindow> AsWindow() = 0;
+
+ ///
+ /// Set this Panel's Layout to FillLayout and return the FillLayout object.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefFillLayout> SetToFillLayout() = 0;
+
+ ///
+ /// Set this Panel's Layout to BoxLayout and return the BoxLayout object.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefBoxLayout> SetToBoxLayout(
+ const CefBoxLayoutSettings& settings) = 0;
+
+ ///
+ /// Get the Layout.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefLayout> GetLayout() = 0;
+
+ ///
+ /// Lay out the child Views (set their bounds based on sizing heuristics
+ /// specific to the current Layout).
+ ///
+ /*--cef()--*/
+ virtual void Layout() = 0;
+
+ ///
+ /// Add a child View.
+ ///
+ /*--cef()--*/
+ virtual void AddChildView(CefRefPtr<CefView> view) = 0;
+
+ ///
+ /// Add a child View at the specified |index|. If |index| matches the result
+ /// of GetChildCount() then the View will be added at the end.
+ ///
+ /*--cef(index_param=index)--*/
+ virtual void AddChildViewAt(CefRefPtr<CefView> view, int index) = 0;
+
+ ///
+ /// Move the child View to the specified |index|. A negative value for |index|
+ /// will move the View to the end.
+ ///
+ /*--cef()--*/
+ virtual void ReorderChildView(CefRefPtr<CefView> view, int index) = 0;
+
+ ///
+ /// Remove a child View. The View can then be added to another Panel.
+ ///
+ /*--cef()--*/
+ virtual void RemoveChildView(CefRefPtr<CefView> view) = 0;
+
+ ///
+ /// Remove all child Views. The removed Views will be deleted if the client
+ /// holds no references to them.
+ ///
+ /*--cef()--*/
+ virtual void RemoveAllChildViews() = 0;
+
+ ///
+ /// Returns the number of child Views.
+ ///
+ /*--cef()--*/
+ virtual size_t GetChildViewCount() = 0;
+
+ ///
+ /// Returns the child View at the specified |index|.
+ ///
+ /*--cef(index_param=index)--*/
+ virtual CefRefPtr<CefView> GetChildViewAt(int index) = 0;
+};
+
+#endif // CEF_INCLUDE_VIEWS_CEF_PANEL_H_
diff --git a/include/views/cef_panel_delegate.h b/include/views/cef_panel_delegate.h
new file mode 100644
index 00000000..10768386
--- /dev/null
+++ b/include/views/cef_panel_delegate.h
@@ -0,0 +1,50 @@
+// Copyright (c) 2016 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_VIEWS_CEF_PANEL_DELEGATE_H_
+#define CEF_INCLUDE_VIEWS_CEF_PANEL_DELEGATE_H_
+#pragma once
+
+#include "include/views/cef_view_delegate.h"
+
+///
+/// Implement this interface to handle Panel events. The methods of this class
+/// will be called on the browser process UI thread unless otherwise indicated.
+///
+/*--cef(source=client)--*/
+class CefPanelDelegate : public CefViewDelegate {};
+
+#endif // CEF_INCLUDE_VIEWS_CEF_PANEL_DELEGATE_H_
diff --git a/include/views/cef_scroll_view.h b/include/views/cef_scroll_view.h
new file mode 100644
index 00000000..fb624590
--- /dev/null
+++ b/include/views/cef_scroll_view.h
@@ -0,0 +1,102 @@
+// Copyright (c) 2016 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_VIEWS_CEF_SCROLL_VIEW_H_
+#define CEF_INCLUDE_VIEWS_CEF_SCROLL_VIEW_H_
+#pragma once
+
+#include "include/views/cef_view.h"
+
+///
+/// A ScrollView will show horizontal and/or vertical scrollbars when necessary
+/// based on the size of the attached content view. Methods must be called on
+/// the browser process UI thread unless otherwise indicated.
+///
+/*--cef(source=library)--*/
+class CefScrollView : public CefView {
+ public:
+ ///
+ /// Create a new ScrollView.
+ ///
+ /*--cef(optional_param=delegate)--*/
+ static CefRefPtr<CefScrollView> CreateScrollView(
+ CefRefPtr<CefViewDelegate> delegate);
+
+ ///
+ /// Set the content View. The content View must have a specified size (e.g.
+ /// via CefView::SetBounds or CefViewDelegate::GetPreferredSize).
+ ///
+ /*--cef()--*/
+ virtual void SetContentView(CefRefPtr<CefView> view) = 0;
+
+ ///
+ /// Returns the content View.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefView> GetContentView() = 0;
+
+ ///
+ /// Returns the visible region of the content View.
+ ///
+ /*--cef()--*/
+ virtual CefRect GetVisibleContentRect() = 0;
+
+ ///
+ /// Returns true if the horizontal scrollbar is currently showing.
+ ///
+ /*--cef()--*/
+ virtual bool HasHorizontalScrollbar() = 0;
+
+ ///
+ /// Returns the height of the horizontal scrollbar.
+ ///
+ /*--cef()--*/
+ virtual int GetHorizontalScrollbarHeight() = 0;
+
+ ///
+ /// Returns true if the vertical scrollbar is currently showing.
+ ///
+ /*--cef()--*/
+ virtual bool HasVerticalScrollbar() = 0;
+
+ ///
+ /// Returns the width of the vertical scrollbar.
+ ///
+ /*--cef()--*/
+ virtual int GetVerticalScrollbarWidth() = 0;
+};
+
+#endif // CEF_INCLUDE_VIEWS_CEF_SCROLL_VIEW_H_
diff --git a/include/views/cef_textfield.h b/include/views/cef_textfield.h
new file mode 100644
index 00000000..e6f8edb1
--- /dev/null
+++ b/include/views/cef_textfield.h
@@ -0,0 +1,269 @@
+// Copyright (c) 2016 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_VIEWS_CEF_TEXTFIELD_H_
+#define CEF_INCLUDE_VIEWS_CEF_TEXTFIELD_H_
+#pragma once
+
+#include "include/views/cef_textfield_delegate.h"
+#include "include/views/cef_view.h"
+
+///
+/// A Textfield supports editing of text. This control is custom rendered with
+/// no platform-specific code. Methods must be called on the browser process UI
+/// thread unless otherwise indicated.
+///
+/*--cef(source=library)--*/
+class CefTextfield : public CefView {
+ public:
+ ///
+ /// Create a new Textfield.
+ ///
+ /*--cef(optional_param=delegate)--*/
+ static CefRefPtr<CefTextfield> CreateTextfield(
+ CefRefPtr<CefTextfieldDelegate> delegate);
+
+ ///
+ /// Sets whether the text will be displayed as asterisks.
+ ///
+ /*--cef()--*/
+ virtual void SetPasswordInput(bool password_input) = 0;
+
+ ///
+ /// Returns true if the text will be displayed as asterisks.
+ ///
+ /*--cef()--*/
+ virtual bool IsPasswordInput() = 0;
+
+ ///
+ /// Sets whether the text will read-only.
+ ///
+ /*--cef()--*/
+ virtual void SetReadOnly(bool read_only) = 0;
+
+ ///
+ /// Returns true if the text is read-only.
+ ///
+ /*--cef()--*/
+ virtual bool IsReadOnly() = 0;
+
+ ///
+ /// Returns the currently displayed text.
+ ///
+ /*--cef()--*/
+ virtual CefString GetText() = 0;
+
+ ///
+ /// Sets the contents to |text|. The cursor will be moved to end of the text
+ /// if the current position is outside of the text range.
+ ///
+ /*--cef()--*/
+ virtual void SetText(const CefString& text) = 0;
+
+ ///
+ /// Appends |text| to the previously-existing text.
+ ///
+ /*--cef()--*/
+ virtual void AppendText(const CefString& text) = 0;
+
+ ///
+ /// Inserts |text| at the current cursor position replacing any selected text.
+ ///
+ /*--cef()--*/
+ virtual void InsertOrReplaceText(const CefString& text) = 0;
+
+ ///
+ /// Returns true if there is any selected text.
+ ///
+ /*--cef()--*/
+ virtual bool HasSelection() = 0;
+
+ ///
+ /// Returns the currently selected text.
+ ///
+ /*--cef()--*/
+ virtual CefString GetSelectedText() = 0;
+
+ ///
+ /// Selects all text. If |reversed| is true the range will end at the logical
+ /// beginning of the text; this generally shows the leading portion of text
+ /// that overflows its display area.
+ ///
+ /*--cef()--*/
+ virtual void SelectAll(bool reversed) = 0;
+
+ ///
+ /// Clears the text selection and sets the caret to the end.
+ ///
+ /*--cef()--*/
+ virtual void ClearSelection() = 0;
+
+ ///
+ /// Returns the selected logical text range.
+ ///
+ /*--cef()--*/
+ virtual CefRange GetSelectedRange() = 0;
+
+ ///
+ /// Selects the specified logical text range.
+ ///
+ /*--cef()--*/
+ virtual void SelectRange(const CefRange& range) = 0;
+
+ ///
+ /// Returns the current cursor position.
+ ///
+ /*--cef()--*/
+ virtual size_t GetCursorPosition() = 0;
+
+ ///
+ /// Sets the text color.
+ ///
+ /*--cef()--*/
+ virtual void SetTextColor(cef_color_t color) = 0;
+
+ ///
+ /// Returns the text color.
+ ///
+ /*--cef()--*/
+ virtual cef_color_t GetTextColor() = 0;
+
+ ///
+ /// Sets the selection text color.
+ ///
+ /*--cef()--*/
+ virtual void SetSelectionTextColor(cef_color_t color) = 0;
+
+ ///
+ /// Returns the selection text color.
+ ///
+ /*--cef()--*/
+ virtual cef_color_t GetSelectionTextColor() = 0;
+
+ ///
+ /// Sets the selection background color.
+ ///
+ /*--cef()--*/
+ virtual void SetSelectionBackgroundColor(cef_color_t color) = 0;
+
+ ///
+ /// Returns the selection background color.
+ ///
+ /*--cef()--*/
+ virtual cef_color_t GetSelectionBackgroundColor() = 0;
+
+ ///
+ /// Sets the font list. The format is "<FONT_FAMILY_LIST>,[STYLES] <SIZE>",
+ /// where:
+ /// - FONT_FAMILY_LIST is a comma-separated list of font family names,
+ /// - STYLES is an optional space-separated list of style names
+ /// (case-sensitive
+ /// "Bold" and "Italic" are supported), and
+ /// - SIZE is an integer font size in pixels with the suffix "px".
+ ///
+ /// Here are examples of valid font description strings:
+ /// - "Arial, Helvetica, Bold Italic 14px"
+ /// - "Arial, 14px"
+ ///
+ /*--cef()--*/
+ virtual void SetFontList(const CefString& font_list) = 0;
+
+ ///
+ /// Applies |color| to the specified |range| without changing the default
+ /// color. If |range| is empty the color will be set on the complete text
+ /// contents.
+ ///
+ /*--cef()--*/
+ virtual void ApplyTextColor(cef_color_t color, const CefRange& range) = 0;
+
+ ///
+ /// Applies |style| to the specified |range| without changing the default
+ /// style. If |add| is true the style will be added, otherwise the style will
+ /// be removed. If |range| is empty the style will be set on the complete text
+ /// contents.
+ ///
+ /*--cef()--*/
+ virtual void ApplyTextStyle(cef_text_style_t style,
+ bool add,
+ const CefRange& range) = 0;
+
+ ///
+ /// Returns true if the action associated with the specified command id is
+ /// enabled. See additional comments on ExecuteCommand().
+ ///
+ /*--cef()--*/
+ virtual bool IsCommandEnabled(cef_text_field_commands_t command_id) = 0;
+
+ ///
+ /// Performs the action associated with the specified command id.
+ ///
+ /*--cef()--*/
+ virtual void ExecuteCommand(cef_text_field_commands_t command_id) = 0;
+
+ ///
+ /// Clears Edit history.
+ ///
+ /*--cef()--*/
+ virtual void ClearEditHistory() = 0;
+
+ ///
+ /// Sets the placeholder text that will be displayed when the Textfield is
+ /// empty.
+ ///
+ /*--cef()--*/
+ virtual void SetPlaceholderText(const CefString& text) = 0;
+
+ ///
+ /// Returns the placeholder text that will be displayed when the Textfield is
+ /// empty.
+ ///
+ /*--cef()--*/
+ virtual CefString GetPlaceholderText() = 0;
+
+ ///
+ /// Sets the placeholder text color.
+ ///
+ /*--cef()--*/
+ virtual void SetPlaceholderTextColor(cef_color_t color) = 0;
+
+ ///
+ /// Set the accessible name that will be exposed to assistive technology (AT).
+ ///
+ /*--cef()--*/
+ virtual void SetAccessibleName(const CefString& name) = 0;
+};
+
+#endif // CEF_INCLUDE_VIEWS_CEF_TEXTFIELD_H_
diff --git a/include/views/cef_textfield_delegate.h b/include/views/cef_textfield_delegate.h
new file mode 100644
index 00000000..aa3660ef
--- /dev/null
+++ b/include/views/cef_textfield_delegate.h
@@ -0,0 +1,71 @@
+// Copyright (c) 2016 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_VIEWS_CEF_TEXTFIELD_DELEGATE_H_
+#define CEF_INCLUDE_VIEWS_CEF_TEXTFIELD_DELEGATE_H_
+#pragma once
+
+#include "include/views/cef_view_delegate.h"
+
+class CefTextfield;
+
+///
+/// Implement this interface to handle Textfield events. The methods of this
+/// class will be called on the browser process UI thread unless otherwise
+/// indicated.
+///
+/*--cef(source=client)--*/
+class CefTextfieldDelegate : public CefViewDelegate {
+ public:
+ ///
+ /// Called when |textfield| recieves a keyboard event. |event| contains
+ /// information about the keyboard event. Return true if the keyboard event
+ /// was handled or false otherwise for default handling.
+ ///
+ /*--cef()--*/
+ virtual bool OnKeyEvent(CefRefPtr<CefTextfield> textfield,
+ const CefKeyEvent& event) {
+ return false;
+ }
+
+ ///
+ /// Called after performing a user action that may change |textfield|.
+ ///
+ /*--cef()--*/
+ virtual void OnAfterUserAction(CefRefPtr<CefTextfield> textfield) {}
+};
+
+#endif // CEF_INCLUDE_VIEWS_CEF_TEXTFIELD_DELEGATE_H_
diff --git a/include/views/cef_view.h b/include/views/cef_view.h
new file mode 100644
index 00000000..9bfd1f47
--- /dev/null
+++ b/include/views/cef_view.h
@@ -0,0 +1,427 @@
+// Copyright (c) 2016 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_VIEWS_CEF_VIEW_H_
+#define CEF_INCLUDE_VIEWS_CEF_VIEW_H_
+#pragma once
+
+#include "include/views/cef_view_delegate.h"
+
+class CefBrowserView;
+class CefButton;
+class CefPanel;
+class CefScrollView;
+class CefTextfield;
+class CefWindow;
+
+///
+/// A View is a rectangle within the views View hierarchy. It is the base class
+/// for all Views. All size and position values are in density independent
+/// pixels (DIP) unless otherwise indicated. Methods must be called on the
+/// browser process UI thread unless otherwise indicated.
+///
+/*--cef(source=library)--*/
+class CefView : public CefBaseRefCounted {
+ public:
+ ///
+ /// Returns this View as a BrowserView or NULL if this is not a BrowserView.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefBrowserView> AsBrowserView() = 0;
+
+ ///
+ /// Returns this View as a Button or NULL if this is not a Button.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefButton> AsButton() = 0;
+
+ ///
+ /// Returns this View as a Panel or NULL if this is not a Panel.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefPanel> AsPanel() = 0;
+
+ ///
+ /// Returns this View as a ScrollView or NULL if this is not a ScrollView.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefScrollView> AsScrollView() = 0;
+
+ ///
+ /// Returns this View as a Textfield or NULL if this is not a Textfield.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefTextfield> AsTextfield() = 0;
+
+ ///
+ /// Returns the type of this View as a string. Used primarily for testing
+ /// purposes.
+ ///
+ /*--cef()--*/
+ virtual CefString GetTypeString() = 0;
+
+ ///
+ /// Returns a string representation of this View which includes the type and
+ /// various type-specific identifying attributes. If |include_children| is
+ /// true any child Views will also be included. Used primarily for testing
+ /// purposes.
+ ///
+ /*--cef()--*/
+ virtual CefString ToString(bool include_children) = 0;
+
+ ///
+ /// Returns true if this View is valid.
+ ///
+ /*--cef()--*/
+ virtual bool IsValid() = 0;
+
+ ///
+ /// Returns true if this View is currently attached to another View. A View
+ /// can only be attached to one View at a time.
+ ///
+ /*--cef()--*/
+ virtual bool IsAttached() = 0;
+
+ ///
+ /// Returns true if this View is the same as |that| View.
+ ///
+ /*--cef()--*/
+ virtual bool IsSame(CefRefPtr<CefView> that) = 0;
+
+ ///
+ /// Returns the delegate associated with this View, if any.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefViewDelegate> GetDelegate() = 0;
+
+ ///
+ /// Returns the top-level Window hosting this View, if any.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefWindow> GetWindow() = 0;
+
+ ///
+ /// Returns the ID for this View.
+ ///
+ /*--cef()--*/
+ virtual int GetID() = 0;
+
+ ///
+ /// Sets the ID for this View. ID should be unique within the subtree that you
+ /// intend to search for it. 0 is the default ID for views.
+ ///
+ /*--cef()--*/
+ virtual void SetID(int id) = 0;
+
+ ///
+ /// Returns the group id of this View, or -1 if not set.
+ ///
+ /*--cef()--*/
+ virtual int GetGroupID() = 0;
+
+ ///
+ /// A group id is used to tag Views which are part of the same logical group.
+ /// Focus can be moved between views with the same group using the arrow keys.
+ /// The group id is immutable once it's set.
+ ///
+ /*--cef()--*/
+ virtual void SetGroupID(int group_id) = 0;
+
+ ///
+ /// Returns the View that contains this View, if any.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefView> GetParentView() = 0;
+
+ ///
+ /// Recursively descends the view tree starting at this View, and returns the
+ /// first child that it encounters with the given ID. Returns NULL if no
+ /// matching child view is found.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefView> GetViewForID(int id) = 0;
+
+ ///
+ /// Sets the bounds (size and position) of this View. |bounds| is in parent
+ /// coordinates, or DIP screen coordinates if there is no parent.
+ ///
+ /*--cef()--*/
+ virtual void SetBounds(const CefRect& bounds) = 0;
+
+ ///
+ /// Returns the bounds (size and position) of this View in parent coordinates,
+ /// or DIP screen coordinates if there is no parent.
+ ///
+ /*--cef()--*/
+ virtual CefRect GetBounds() = 0;
+
+ ///
+ /// Returns the bounds (size and position) of this View in DIP screen
+ /// coordinates.
+ ///
+ /*--cef()--*/
+ virtual CefRect GetBoundsInScreen() = 0;
+
+ ///
+ /// Sets the size of this View without changing the position. |size| in
+ /// parent coordinates, or DIP screen coordinates if there is no parent.
+ ///
+ /*--cef()--*/
+ virtual void SetSize(const CefSize& size) = 0;
+
+ ///
+ /// Returns the size of this View in parent coordinates, or DIP screen
+ /// coordinates if there is no parent.
+ ///
+ /*--cef()--*/
+ virtual CefSize GetSize() = 0;
+
+ ///
+ /// Sets the position of this View without changing the size. |position| is in
+ /// parent coordinates, or DIP screen coordinates if there is no parent.
+ ///
+ /*--cef()--*/
+ virtual void SetPosition(const CefPoint& position) = 0;
+
+ ///
+ /// Returns the position of this View. Position is in parent coordinates, or
+ /// DIP screen coordinates if there is no parent.
+ ///
+ /*--cef()--*/
+ virtual CefPoint GetPosition() = 0;
+
+ ///
+ /// Sets the insets for this View. |insets| is in parent coordinates, or DIP
+ /// screen coordinates if there is no parent.
+ ///
+ /*--cef()--*/
+ virtual void SetInsets(const CefInsets& insets) = 0;
+
+ ///
+ /// Returns the insets for this View in parent coordinates, or DIP screen
+ /// coordinates if there is no parent.
+ ///
+ /*--cef()--*/
+ virtual CefInsets GetInsets() = 0;
+
+ ///
+ /// Returns the size this View would like to be if enough space is available.
+ /// Size is in parent coordinates, or DIP screen coordinates if there is no
+ /// parent.
+ ///
+ /*--cef()--*/
+ virtual CefSize GetPreferredSize() = 0;
+
+ ///
+ /// Size this View to its preferred size. Size is in parent coordinates, or
+ /// DIP screen coordinates if there is no parent.
+ ///
+ /*--cef()--*/
+ virtual void SizeToPreferredSize() = 0;
+
+ ///
+ /// Returns the minimum size for this View. Size is in parent coordinates, or
+ /// DIP screen coordinates if there is no parent.
+ ///
+ /*--cef()--*/
+ virtual CefSize GetMinimumSize() = 0;
+
+ ///
+ /// Returns the maximum size for this View. Size is in parent coordinates, or
+ /// DIP screen coordinates if there is no parent.
+ ///
+ /*--cef()--*/
+ virtual CefSize GetMaximumSize() = 0;
+
+ ///
+ /// Returns the height necessary to display this View with the provided width.
+ ///
+ /*--cef()--*/
+ virtual int GetHeightForWidth(int width) = 0;
+
+ ///
+ /// Indicate that this View and all parent Views require a re-layout. This
+ /// ensures the next call to Layout() will propagate to this View even if the
+ /// bounds of parent Views do not change.
+ ///
+ /*--cef()--*/
+ virtual void InvalidateLayout() = 0;
+
+ ///
+ /// Sets whether this View is visible. Windows are hidden by default and other
+ /// views are visible by default. This View and any parent views must be set
+ /// as visible for this View to be drawn in a Window. If this View is set as
+ /// hidden then it and any child views will not be drawn and, if any of those
+ /// views currently have focus, then focus will also be cleared. Painting is
+ /// scheduled as needed. If this View is a Window then calling this method is
+ /// equivalent to calling the Window Show() and Hide() methods.
+ ///
+ /*--cef()--*/
+ virtual void SetVisible(bool visible) = 0;
+
+ ///
+ /// Returns whether this View is visible. A view may be visible but still not
+ /// drawn in a Window if any parent views are hidden. If this View is a Window
+ /// then a return value of true indicates that this Window is currently
+ /// visible to the user on-screen. If this View is not a Window then call
+ /// IsDrawn() to determine whether this View and all parent views are visible
+ /// and will be drawn.
+ ///
+ /*--cef()--*/
+ virtual bool IsVisible() = 0;
+
+ ///
+ /// Returns whether this View is visible and drawn in a Window. A view is
+ /// drawn if it and all parent views are visible. If this View is a Window
+ /// then calling this method is equivalent to calling IsVisible(). Otherwise,
+ /// to determine if the containing Window is visible to the user on-screen
+ /// call IsVisible() on the Window.
+ ///
+ /*--cef()--*/
+ virtual bool IsDrawn() = 0;
+
+ ///
+ /// Set whether this View is enabled. A disabled View does not receive
+ /// keyboard or mouse inputs. If |enabled| differs from the current value the
+ /// View will be repainted. Also, clears focus if the focused View is
+ /// disabled.
+ ///
+ /*--cef()--*/
+ virtual void SetEnabled(bool enabled) = 0;
+
+ ///
+ /// Returns whether this View is enabled.
+ ///
+ /*--cef()--*/
+ virtual bool IsEnabled() = 0;
+
+ ///
+ /// Sets whether this View is capable of taking focus. It will clear focus if
+ /// the focused View is set to be non-focusable. This is false by default so
+ /// that a View used as a container does not get the focus.
+ ///
+ /*--cef()--*/
+ virtual void SetFocusable(bool focusable) = 0;
+
+ ///
+ /// Returns true if this View is focusable, enabled and drawn.
+ ///
+ /*--cef()--*/
+ virtual bool IsFocusable() = 0;
+
+ ///
+ /// Return whether this View is focusable when the user requires full keyboard
+ /// access, even though it may not be normally focusable.
+ ///
+ /*--cef()--*/
+ virtual bool IsAccessibilityFocusable() = 0;
+
+ ///
+ /// Request keyboard focus. If this View is focusable it will become the
+ /// focused View.
+ ///
+ /*--cef()--*/
+ virtual void RequestFocus() = 0;
+
+ ///
+ /// Sets the background color for this View.
+ ///
+ /*--cef()--*/
+ virtual void SetBackgroundColor(cef_color_t color) = 0;
+
+ ///
+ /// Returns the background color for this View.
+ ///
+ /*--cef()--*/
+ virtual cef_color_t GetBackgroundColor() = 0;
+
+ ///
+ /// Convert |point| from this View's coordinate system to DIP screen
+ /// coordinates. This View must belong to a Window when calling this method.
+ /// Returns true if the conversion is successful or false otherwise. Use
+ /// CefDisplay::ConvertPointToPixels() after calling this method if further
+ /// conversion to display-specific pixel coordinates is desired.
+ ///
+ /*--cef()--*/
+ virtual bool ConvertPointToScreen(CefPoint& point) = 0;
+
+ ///
+ /// Convert |point| to this View's coordinate system from DIP screen
+ /// coordinates. This View must belong to a Window when calling this method.
+ /// Returns true if the conversion is successful or false otherwise. Use
+ /// CefDisplay::ConvertPointFromPixels() before calling this method if
+ /// conversion from display-specific pixel coordinates is necessary.
+ ///
+ /*--cef()--*/
+ virtual bool ConvertPointFromScreen(CefPoint& point) = 0;
+
+ ///
+ /// Convert |point| from this View's coordinate system to that of the Window.
+ /// This View must belong to a Window when calling this method. Returns true
+ /// if the conversion is successful or false otherwise.
+ ///
+ /*--cef()--*/
+ virtual bool ConvertPointToWindow(CefPoint& point) = 0;
+
+ ///
+ /// Convert |point| to this View's coordinate system from that of the Window.
+ /// This View must belong to a Window when calling this method. Returns true
+ /// if the conversion is successful or false otherwise.
+ ///
+ /*--cef()--*/
+ virtual bool ConvertPointFromWindow(CefPoint& point) = 0;
+
+ ///
+ /// Convert |point| from this View's coordinate system to that of |view|.
+ /// |view| needs to be in the same Window but not necessarily the same view
+ /// hierarchy. Returns true if the conversion is successful or false
+ /// otherwise.
+ ///
+ /*--cef()--*/
+ virtual bool ConvertPointToView(CefRefPtr<CefView> view, CefPoint& point) = 0;
+
+ ///
+ /// Convert |point| to this View's coordinate system from that |view|. |view|
+ /// needs to be in the same Window but not necessarily the same view
+ /// hierarchy. Returns true if the conversion is successful or false
+ /// otherwise.
+ ///
+ /*--cef()--*/
+ virtual bool ConvertPointFromView(CefRefPtr<CefView> view,
+ CefPoint& point) = 0;
+};
+
+#endif // CEF_INCLUDE_VIEWS_CEF_VIEW_H_
diff --git a/include/views/cef_view_delegate.h b/include/views/cef_view_delegate.h
new file mode 100644
index 00000000..23878323
--- /dev/null
+++ b/include/views/cef_view_delegate.h
@@ -0,0 +1,136 @@
+// Copyright (c) 2016 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_VIEWS_CEF_VIEW_DELEGATE_H_
+#define CEF_INCLUDE_VIEWS_CEF_VIEW_DELEGATE_H_
+#pragma once
+
+#include "include/cef_base.h"
+
+class CefView;
+
+///
+/// Implement this interface to handle view events. All size and position values
+/// are in density independent pixels (DIP) unless otherwise indicated. The
+/// methods of this class will be called on the browser process UI thread unless
+/// otherwise indicated.
+///
+/*--cef(source=client)--*/
+class CefViewDelegate : public virtual CefBaseRefCounted {
+ public:
+ ///
+ /// Return the preferred size for |view|. The Layout will use this information
+ /// to determine the display size.
+ ///
+ /*--cef()--*/
+ virtual CefSize GetPreferredSize(CefRefPtr<CefView> view) {
+ return CefSize();
+ }
+
+ ///
+ /// Return the minimum size for |view|.
+ ///
+ /*--cef()--*/
+ virtual CefSize GetMinimumSize(CefRefPtr<CefView> view) { return CefSize(); }
+
+ ///
+ /// Return the maximum size for |view|.
+ ///
+ /*--cef()--*/
+ virtual CefSize GetMaximumSize(CefRefPtr<CefView> view) { return CefSize(); }
+
+ ///
+ /// Return the height necessary to display |view| with the provided |width|.
+ /// If not specified the result of GetPreferredSize().height will be used by
+ /// default. Override if |view|'s preferred height depends upon the width
+ /// (for example, with Labels).
+ ///
+ /*--cef()--*/
+ virtual int GetHeightForWidth(CefRefPtr<CefView> view, int width) {
+ return 0;
+ }
+
+ ///
+ /// Called when the parent of |view| has changed. If |view| is being added to
+ /// |parent| then |added| will be true. If |view| is being removed from
+ /// |parent| then |added| will be false. If |view| is being reparented the
+ /// remove notification will be sent before the add notification. Do not
+ /// modify the view hierarchy in this callback.
+ ///
+ /*--cef()--*/
+ virtual void OnParentViewChanged(CefRefPtr<CefView> view,
+ bool added,
+ CefRefPtr<CefView> parent) {}
+
+ ///
+ /// Called when a child of |view| has changed. If |child| is being added to
+ /// |view| then |added| will be true. If |child| is being removed from |view|
+ /// then |added| will be false. If |child| is being reparented the remove
+ /// notification will be sent to the old parent before the add notification is
+ /// sent to the new parent. Do not modify the view hierarchy in this callback.
+ ///
+ /*--cef()--*/
+ virtual void OnChildViewChanged(CefRefPtr<CefView> view,
+ bool added,
+ CefRefPtr<CefView> child) {}
+
+ ///
+ /// Called when |view| is added or removed from the CefWindow.
+ ///
+ /*--cef()--*/
+ virtual void OnWindowChanged(CefRefPtr<CefView> view, bool added) {}
+
+ ///
+ /// Called when the layout of |view| has changed.
+ ///
+ /*--cef()--*/
+ virtual void OnLayoutChanged(CefRefPtr<CefView> view,
+ const CefRect& new_bounds) {}
+
+ ///
+ /// Called when |view| gains focus.
+ ///
+ /*--cef()--*/
+ virtual void OnFocus(CefRefPtr<CefView> view) {}
+
+ ///
+ /// Called when |view| loses focus.
+ ///
+ /*--cef()--*/
+ virtual void OnBlur(CefRefPtr<CefView> view) {}
+};
+
+#endif // CEF_INCLUDE_VIEWS_CEF_WINDOW_DELEGATE_H_
diff --git a/include/views/cef_window.h b/include/views/cef_window.h
new file mode 100644
index 00000000..e34e446b
--- /dev/null
+++ b/include/views/cef_window.h
@@ -0,0 +1,353 @@
+// Copyright (c) 2016 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_VIEWS_CEF_WINDOW_H_
+#define CEF_INCLUDE_VIEWS_CEF_WINDOW_H_
+#pragma once
+
+#include "include/cef_image.h"
+#include "include/cef_menu_model.h"
+#include "include/views/cef_display.h"
+#include "include/views/cef_overlay_controller.h"
+#include "include/views/cef_panel.h"
+#include "include/views/cef_window_delegate.h"
+
+///
+/// A Window is a top-level Window/widget in the Views hierarchy. By default it
+/// will have a non-client area with title bar, icon and buttons that supports
+/// moving and resizing. All size and position values are in density independent
+/// pixels (DIP) unless otherwise indicated. Methods must be called on the
+/// browser process UI thread unless otherwise indicated.
+///
+/*--cef(source=library)--*/
+class CefWindow : public CefPanel {
+ public:
+ ///
+ /// Create a new Window.
+ ///
+ /*--cef(optional_param=delegate)--*/
+ static CefRefPtr<CefWindow> CreateTopLevelWindow(
+ CefRefPtr<CefWindowDelegate> delegate);
+
+ ///
+ /// Show the Window.
+ ///
+ /*--cef()--*/
+ virtual void Show() = 0;
+
+ ///
+ /// Hide the Window.
+ ///
+ /*--cef()--*/
+ virtual void Hide() = 0;
+
+ ///
+ /// Sizes the Window to |size| and centers it in the current display.
+ ///
+ /*--cef()--*/
+ virtual void CenterWindow(const CefSize& size) = 0;
+
+ ///
+ /// Close the Window.
+ ///
+ /*--cef()--*/
+ virtual void Close() = 0;
+
+ ///
+ /// Returns true if the Window has been closed.
+ ///
+ /*--cef()--*/
+ virtual bool IsClosed() = 0;
+
+ ///
+ /// Activate the Window, assuming it already exists and is visible.
+ ///
+ /*--cef()--*/
+ virtual void Activate() = 0;
+
+ ///
+ /// Deactivate the Window, making the next Window in the Z order the active
+ /// Window.
+ ///
+ /*--cef()--*/
+ virtual void Deactivate() = 0;
+
+ ///
+ /// Returns whether the Window is the currently active Window.
+ ///
+ /*--cef()--*/
+ virtual bool IsActive() = 0;
+
+ ///
+ /// Bring this Window to the top of other Windows in the Windowing system.
+ ///
+ /*--cef()--*/
+ virtual void BringToTop() = 0;
+
+ ///
+ /// Set the Window to be on top of other Windows in the Windowing system.
+ ///
+ /*--cef()--*/
+ virtual void SetAlwaysOnTop(bool on_top) = 0;
+
+ ///
+ /// Returns whether the Window has been set to be on top of other Windows in
+ /// the Windowing system.
+ ///
+ /*--cef()--*/
+ virtual bool IsAlwaysOnTop() = 0;
+
+ ///
+ /// Maximize the Window.
+ ///
+ /*--cef()--*/
+ virtual void Maximize() = 0;
+
+ ///
+ /// Minimize the Window.
+ ///
+ /*--cef()--*/
+ virtual void Minimize() = 0;
+
+ ///
+ /// Restore the Window.
+ ///
+ /*--cef()--*/
+ virtual void Restore() = 0;
+
+ ///
+ /// Set fullscreen Window state.
+ ///
+ /*--cef()--*/
+ virtual void SetFullscreen(bool fullscreen) = 0;
+
+ ///
+ /// Returns true if the Window is maximized.
+ ///
+ /*--cef()--*/
+ virtual bool IsMaximized() = 0;
+
+ ///
+ /// Returns true if the Window is minimized.
+ ///
+ /*--cef()--*/
+ virtual bool IsMinimized() = 0;
+
+ ///
+ /// Returns true if the Window is fullscreen.
+ ///
+ /*--cef()--*/
+ virtual bool IsFullscreen() = 0;
+
+ ///
+ /// Set the Window title.
+ ///
+ /*--cef(optional_param=title)--*/
+ virtual void SetTitle(const CefString& title) = 0;
+
+ ///
+ /// Get the Window title.
+ ///
+ /*--cef()--*/
+ virtual CefString GetTitle() = 0;
+
+ ///
+ /// Set the Window icon. This should be a 16x16 icon suitable for use in the
+ /// Windows's title bar.
+ ///
+ /*--cef()--*/
+ virtual void SetWindowIcon(CefRefPtr<CefImage> image) = 0;
+
+ ///
+ /// Get the Window icon.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefImage> GetWindowIcon() = 0;
+
+ ///
+ /// Set the Window App icon. This should be a larger icon for use in the host
+ /// environment app switching UI. On Windows, this is the ICON_BIG used in
+ /// Alt-Tab list and Windows taskbar. The Window icon will be used by default
+ /// if no Window App icon is specified.
+ ///
+ /*--cef()--*/
+ virtual void SetWindowAppIcon(CefRefPtr<CefImage> image) = 0;
+
+ ///
+ /// Get the Window App icon.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefImage> GetWindowAppIcon() = 0;
+
+ ///
+ /// Add a View that will be overlayed on the Window contents with absolute
+ /// positioning and high z-order. Positioning is controlled by |docking_mode|
+ /// as described below. The returned CefOverlayController object is used to
+ /// control the overlay. Overlays are hidden by default.
+ ///
+ /// With CEF_DOCKING_MODE_CUSTOM:
+ /// 1. The overlay is initially hidden, sized to |view|'s preferred size,
+ /// and positioned in the top-left corner.
+ /// 2. Optionally change the overlay position and/or size by calling
+ /// CefOverlayController methods.
+ /// 3. Call CefOverlayController::SetVisible(true) to show the overlay.
+ /// 4. The overlay will be automatically re-sized if |view|'s layout
+ /// changes. Optionally change the overlay position and/or size when
+ /// OnLayoutChanged is called on the Window's delegate to indicate a
+ /// change in Window bounds.
+ ///
+ /// With other docking modes:
+ /// 1. The overlay is initially hidden, sized to |view|'s preferred size,
+ /// and positioned based on |docking_mode|.
+ /// 2. Call CefOverlayController::SetVisible(true) to show the overlay.
+ /// 3. The overlay will be automatically re-sized if |view|'s layout changes
+ /// and re-positioned as appropriate when the Window resizes.
+ ///
+ /// Overlays created by this method will receive a higher z-order then any
+ /// child Views added previously. It is therefore recommended to call this
+ /// method last after all other child Views have been added so that the
+ /// overlay displays as the top-most child of the Window.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefOverlayController> AddOverlayView(
+ CefRefPtr<CefView> view,
+ cef_docking_mode_t docking_mode) = 0;
+
+ ///
+ /// Show a menu with contents |menu_model|. |screen_point| specifies the menu
+ /// position in screen coordinates. |anchor_position| specifies how the menu
+ /// will be anchored relative to |screen_point|.
+ ///
+ /*--cef()--*/
+ virtual void ShowMenu(CefRefPtr<CefMenuModel> menu_model,
+ const CefPoint& screen_point,
+ cef_menu_anchor_position_t anchor_position) = 0;
+
+ ///
+ /// Cancel the menu that is currently showing, if any.
+ ///
+ /*--cef()--*/
+ virtual void CancelMenu() = 0;
+
+ ///
+ /// Returns the Display that most closely intersects the bounds of this
+ /// Window. May return NULL if this Window is not currently displayed.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefDisplay> GetDisplay() = 0;
+
+ ///
+ /// Returns the bounds (size and position) of this Window's client area.
+ /// Position is in screen coordinates.
+ ///
+ /*--cef()--*/
+ virtual CefRect GetClientAreaBoundsInScreen() = 0;
+
+ ///
+ /// Set the regions where mouse events will be intercepted by this Window to
+ /// support drag operations. Call this method with an empty vector to clear
+ /// the draggable regions. The draggable region bounds should be in window
+ /// coordinates.
+ ///
+ /*--cef(optional_param=regions)--*/
+ virtual void SetDraggableRegions(
+ const std::vector<CefDraggableRegion>& regions) = 0;
+
+ ///
+ /// Retrieve the platform window handle for this Window.
+ ///
+ /*--cef()--*/
+ virtual CefWindowHandle GetWindowHandle() = 0;
+
+ ///
+ /// Simulate a key press. |key_code| is the VKEY_* value from Chromium's
+ /// ui/events/keycodes/keyboard_codes.h header (VK_* values on Windows).
+ /// |event_flags| is some combination of EVENTFLAG_SHIFT_DOWN,
+ /// EVENTFLAG_CONTROL_DOWN and/or EVENTFLAG_ALT_DOWN. This method is exposed
+ /// primarily for testing purposes.
+ ///
+ /*--cef()--*/
+ virtual void SendKeyPress(int key_code, uint32 event_flags) = 0;
+
+ ///
+ /// Simulate a mouse move. The mouse cursor will be moved to the specified
+ /// (screen_x, screen_y) position. This method is exposed primarily for
+ /// testing purposes.
+ ///
+ /*--cef()--*/
+ virtual void SendMouseMove(int screen_x, int screen_y) = 0;
+
+ ///
+ /// Simulate mouse down and/or mouse up events. |button| is the mouse button
+ /// type. If |mouse_down| is true a mouse down event will be sent. If
+ /// |mouse_up| is true a mouse up event will be sent. If both are true a mouse
+ /// down event will be sent followed by a mouse up event (equivalent to
+ /// clicking the mouse button). The events will be sent using the current
+ /// cursor position so make sure to call SendMouseMove() first to position the
+ /// mouse. This method is exposed primarily for testing purposes.
+ ///
+ /*--cef()--*/
+ virtual void SendMouseEvents(cef_mouse_button_type_t button,
+ bool mouse_down,
+ bool mouse_up) = 0;
+
+ ///
+ /// Set the keyboard accelerator for the specified |command_id|. |key_code|
+ /// can be any virtual key or character value.
+ /// CefWindowDelegate::OnAccelerator will be called if the keyboard
+ /// combination is triggered while this window has focus.
+ ///
+ /*--cef()--*/
+ virtual void SetAccelerator(int command_id,
+ int key_code,
+ bool shift_pressed,
+ bool ctrl_pressed,
+ bool alt_pressed) = 0;
+
+ ///
+ /// Remove the keyboard accelerator for the specified |command_id|.
+ ///
+ /*--cef()--*/
+ virtual void RemoveAccelerator(int command_id) = 0;
+
+ ///
+ /// Remove all keyboard accelerators.
+ ///
+ /*--cef()--*/
+ virtual void RemoveAllAccelerators() = 0;
+};
+
+#endif // CEF_INCLUDE_VIEWS_CEF_WINDOW_H_
diff --git a/include/views/cef_window_delegate.h b/include/views/cef_window_delegate.h
new file mode 100644
index 00000000..90bc7dfb
--- /dev/null
+++ b/include/views/cef_window_delegate.h
@@ -0,0 +1,201 @@
+// Copyright (c) 2016 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file must follow a specific format in order to
+// support the CEF translator tool. See the translator.README.txt file in the
+// tools directory for more information.
+//
+
+#ifndef CEF_INCLUDE_VIEWS_CEF_WINDOW_DELEGATE_H_
+#define CEF_INCLUDE_VIEWS_CEF_WINDOW_DELEGATE_H_
+#pragma once
+
+#include "include/views/cef_panel_delegate.h"
+
+class CefWindow;
+
+///
+/// Implement this interface to handle window events. The methods of this class
+/// will be called on the browser process UI thread unless otherwise indicated.
+///
+/*--cef(source=client)--*/
+class CefWindowDelegate : public CefPanelDelegate {
+ public:
+ ///
+ /// Called when |window| is created.
+ ///
+ /*--cef()--*/
+ virtual void OnWindowCreated(CefRefPtr<CefWindow> window) {}
+
+ ///
+ /// Called when |window| is closing.
+ ///
+ /*--cef()--*/
+ virtual void OnWindowClosing(CefRefPtr<CefWindow> window) {}
+
+ ///
+ /// Called when |window| is destroyed. Release all references to |window| and
+ /// do not attempt to execute any methods on |window| after this callback
+ /// returns.
+ ///
+ /*--cef()--*/
+ virtual void OnWindowDestroyed(CefRefPtr<CefWindow> window) {}
+
+ ///
+ /// Called when |window| is activated or deactivated.
+ ///
+ /*--cef()--*/
+ virtual void OnWindowActivationChanged(CefRefPtr<CefWindow> window,
+ bool active) {}
+
+ ///
+ /// Called when |window| bounds have changed. |new_bounds| will be in DIP
+ /// screen coordinates.
+ ///
+ /*--cef()--*/
+ virtual void OnWindowBoundsChanged(CefRefPtr<CefWindow> window,
+ const CefRect& new_bounds) {}
+
+ ///
+ /// Return the parent for |window| or NULL if the |window| does not have a
+ /// parent. Windows with parents will not get a taskbar button. Set |is_menu|
+ /// to true if |window| will be displayed as a menu, in which case it will not
+ /// be clipped to the parent window bounds. Set |can_activate_menu| to false
+ /// if |is_menu| is true and |window| should not be activated (given keyboard
+ /// focus) when displayed.
+ ///
+ /*--cef()--*/
+ virtual CefRefPtr<CefWindow> GetParentWindow(CefRefPtr<CefWindow> window,
+ bool* is_menu,
+ bool* can_activate_menu) {
+ return nullptr;
+ }
+
+ ///
+ /// Return the initial bounds for |window| in density independent pixel (DIP)
+ /// coordinates. If this method returns an empty CefRect then
+ /// GetPreferredSize() will be called to retrieve the size, and the window
+ /// will be placed on the screen with origin (0,0). This method can be used in
+ /// combination with CefView::GetBoundsInScreen() to restore the previous
+ /// window bounds.
+ ///
+ /*--cef()--*/
+ virtual CefRect GetInitialBounds(CefRefPtr<CefWindow> window) {
+ return CefRect();
+ }
+
+ ///
+ /// Return the initial show state for |window|.
+ ///
+ /*--cef(default_retval=CEF_SHOW_STATE_NORMAL)--*/
+ virtual cef_show_state_t GetInitialShowState(CefRefPtr<CefWindow> window) {
+ return CEF_SHOW_STATE_NORMAL;
+ }
+
+ ///
+ /// Return true if |window| should be created without a frame or title bar.
+ /// The window will be resizable if CanResize() returns true. Use
+ /// CefWindow::SetDraggableRegions() to specify draggable regions.
+ ///
+ /*--cef()--*/
+ virtual bool IsFrameless(CefRefPtr<CefWindow> window) { return false; }
+
+ ///
+ /// Return true if |window| should be created with standard window buttons
+ /// like close, minimize and zoom.
+ ///
+ /*--cef()--*/
+ virtual bool WithStandardWindowButtons(CefRefPtr<CefWindow> window) {
+ return !IsFrameless(window);
+ }
+
+ ///
+ /// Return whether the titlebar height should be overridden,
+ /// and sets the height of the titlebar in |titlebar_height|.
+ /// On macOS, it can also be used to adjust the vertical position
+ /// of the traffic light buttons in frameless windows.
+ /// The buttons will be positioned halfway down the titlebar
+ /// at a height of |titlebar_height| / 2.
+ ///
+ /*--cef()--*/
+ virtual bool GetTitlebarHeight(CefRefPtr<CefWindow> window,
+ float* titlebar_height) {
+ return false;
+ }
+
+ ///
+ /// Return true if |window| can be resized.
+ ///
+ /*--cef()--*/
+ virtual bool CanResize(CefRefPtr<CefWindow> window) { return true; }
+
+ ///
+ /// Return true if |window| can be maximized.
+ ///
+ /*--cef()--*/
+ virtual bool CanMaximize(CefRefPtr<CefWindow> window) { return true; }
+
+ ///
+ /// Return true if |window| can be minimized.
+ ///
+ /*--cef()--*/
+ virtual bool CanMinimize(CefRefPtr<CefWindow> window) { return true; }
+
+ ///
+ /// Return true if |window| can be closed. This will be called for user-
+ /// initiated window close actions and when CefWindow::Close() is called.
+ ///
+ /*--cef()--*/
+ virtual bool CanClose(CefRefPtr<CefWindow> window) { return true; }
+
+ ///
+ /// Called when a keyboard accelerator registered with
+ /// CefWindow::SetAccelerator is triggered. Return true if the accelerator was
+ /// handled or false otherwise.
+ ///
+ /*--cef()--*/
+ virtual bool OnAccelerator(CefRefPtr<CefWindow> window, int command_id) {
+ return false;
+ }
+
+ ///
+ /// Called after all other controls in the window have had a chance to
+ /// handle the event. |event| contains information about the keyboard event.
+ /// Return true if the keyboard event was handled or false otherwise.
+ ///
+ /*--cef()--*/
+ virtual bool OnKeyEvent(CefRefPtr<CefWindow> window,
+ const CefKeyEvent& event) {
+ return false;
+ }
+};
+
+#endif // CEF_INCLUDE_VIEWS_CEF_WINDOW_DELEGATE_H_
diff --git a/include/wrapper/cef_byte_read_handler.h b/include/wrapper/cef_byte_read_handler.h
new file mode 100644
index 00000000..4a1ba0b1
--- /dev/null
+++ b/include/wrapper/cef_byte_read_handler.h
@@ -0,0 +1,80 @@
+// Copyright (c) 2012 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file are only available to applications that link
+// against the libcef_dll_wrapper target.
+//
+
+#ifndef CEF_INCLUDE_WRAPPER_CEF_BYTE_READ_HANDLER_H_
+#define CEF_INCLUDE_WRAPPER_CEF_BYTE_READ_HANDLER_H_
+#pragma once
+
+#include "include/base/cef_lock.h"
+#include "include/cef_base.h"
+#include "include/cef_stream.h"
+
+///
+/// Thread safe implementation of the CefReadHandler class for reading an
+/// in-memory array of bytes.
+///
+class CefByteReadHandler : public CefReadHandler {
+ public:
+ ///
+ /// Create a new object for reading an array of bytes. An optional |source|
+ /// reference can be kept to keep the underlying data source from being
+ /// released while the reader exists.
+ ///
+ CefByteReadHandler(const unsigned char* bytes,
+ size_t size,
+ CefRefPtr<CefBaseRefCounted> source);
+
+ CefByteReadHandler(const CefByteReadHandler&) = delete;
+ CefByteReadHandler& operator=(const CefByteReadHandler&) = delete;
+
+ // CefReadHandler methods.
+ virtual size_t Read(void* ptr, size_t size, size_t n) override;
+ virtual int Seek(int64 offset, int whence) override;
+ virtual int64 Tell() override;
+ virtual int Eof() override;
+ virtual bool MayBlock() override { return false; }
+
+ private:
+ const unsigned char* bytes_;
+ int64 size_;
+ int64 offset_;
+ CefRefPtr<CefBaseRefCounted> source_;
+
+ base::Lock lock_;
+
+ IMPLEMENT_REFCOUNTING(CefByteReadHandler);
+};
+
+#endif // CEF_INCLUDE_WRAPPER_CEF_BYTE_READ_HANDLER_H_
diff --git a/include/wrapper/cef_closure_task.h b/include/wrapper/cef_closure_task.h
new file mode 100644
index 00000000..51f12aff
--- /dev/null
+++ b/include/wrapper/cef_closure_task.h
@@ -0,0 +1,117 @@
+// Copyright (c) 2014 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file are only available to applications that link
+// against the libcef_dll_wrapper target.
+//
+
+#ifndef CEF_INCLUDE_WRAPPER_CEF_CLOSURE_TASK_H_
+#define CEF_INCLUDE_WRAPPER_CEF_CLOSURE_TASK_H_
+#pragma once
+
+#include "include/base/cef_callback_forward.h"
+#include "include/cef_task.h"
+
+///
+/// \file
+/// Helpers for asynchronously executing a base::[Once|Repeating]Closure (bound
+/// function or method) on a CEF thread. Creation of a
+/// base::[Once|Repeating]Closure can be facilitated using
+/// base::Bind[Once|Repeating]. See include/base/cef_callback.h for complete
+/// usage instructions.
+///
+/// To use these helpers you should include this header and the header that
+/// defines base::Bind[Once|Repeating].
+///
+/// <pre>
+/// #include "include/base/cef_callback.h"
+/// #include "include/wrapper/cef_closure_task.h"
+/// </pre>
+///
+/// Example of executing a bound function:
+///
+/// <pre>
+/// // Define a function.
+/// void MyFunc(int arg) { /* do something with |arg| on the UI thread */ }
+///
+/// // Post a task that will execute MyFunc on the UI thread and pass an |arg|
+/// // value of 5.
+/// CefPostTask(TID_UI, base::BindOnce(&MyFunc, 5));
+/// </pre>
+///
+/// Example of executing a bound method:
+///
+/// <pre>
+/// // Define a class.
+/// class MyClass : public CefBaseRefCounted {
+/// public:
+/// MyClass() {}
+/// void MyMethod(int arg) { /* do something with |arg| on the UI thread */
+/// }
+/// private:
+/// IMPLEMENT_REFCOUNTING(MyClass);
+/// };
+///
+/// // Create an instance of MyClass.
+/// CefRefPtr<MyClass> instance = new MyClass();
+///
+/// // Post a task that will execute MyClass::MyMethod on the UI thread and
+/// // pass an |arg| value of 5. |instance| will be kept alive until after the
+/// // task completes.
+/// CefPostTask(TID_UI, base::BindOnce(&MyClass::MyMethod, instance, 5));
+/// </pre>
+///
+
+///
+/// Create a CefTask that wraps a base::[Once|Repeating]Closure. Can be used in
+/// combination with CefTaskRunner.
+///
+CefRefPtr<CefTask> CefCreateClosureTask(base::OnceClosure closure);
+CefRefPtr<CefTask> CefCreateClosureTask(const base::RepeatingClosure& closure);
+
+///
+/// Post a base::[Once|Repeating]Closure for execution on the specified thread.
+///
+bool CefPostTask(CefThreadId threadId, base::OnceClosure closure);
+bool CefPostTask(CefThreadId threadId, const base::RepeatingClosure& closure);
+
+///
+/// Post a base::[Once|Repeating]Closure for delayed execution on the specified
+/// thread.
+///
+bool CefPostDelayedTask(CefThreadId threadId,
+ base::OnceClosure closure,
+ int64 delay_ms);
+bool CefPostDelayedTask(CefThreadId threadId,
+ const base::RepeatingClosure& closure,
+ int64 delay_ms);
+
+#endif // CEF_INCLUDE_WRAPPER_CEF_CLOSURE_TASK_H_
diff --git a/include/wrapper/cef_helpers.h b/include/wrapper/cef_helpers.h
new file mode 100644
index 00000000..4917c88a
--- /dev/null
+++ b/include/wrapper/cef_helpers.h
@@ -0,0 +1,165 @@
+// Copyright (c) 2014 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file are only available to applications that link
+// against the libcef_dll_wrapper target.
+//
+
+#ifndef CEF_INCLUDE_WRAPPER_CEF_HELPERS_H_
+#define CEF_INCLUDE_WRAPPER_CEF_HELPERS_H_
+#pragma once
+
+#include <cstring>
+#include <string>
+#include <vector>
+
+#include "include/base/cef_bind.h"
+#include "include/base/cef_logging.h"
+#include "include/cef_task.h"
+
+#define CEF_REQUIRE_UI_THREAD() DCHECK(CefCurrentlyOn(TID_UI));
+#define CEF_REQUIRE_IO_THREAD() DCHECK(CefCurrentlyOn(TID_IO));
+#define CEF_REQUIRE_FILE_BACKGROUND_THREAD() \
+ DCHECK(CefCurrentlyOn(TID_FILE_BACKGROUND));
+#define CEF_REQUIRE_FILE_USER_VISIBLE_THREAD() \
+ DCHECK(CefCurrentlyOn(TID_FILE_USER_VISIBLE));
+#define CEF_REQUIRE_FILE_USER_BLOCKING_THREAD() \
+ DCHECK(CefCurrentlyOn(TID_FILE_USER_BLOCKING));
+#define CEF_REQUIRE_RENDERER_THREAD() DCHECK(CefCurrentlyOn(TID_RENDERER));
+
+///
+/// Use this struct in conjuction with refcounted types to ensure that an
+/// object is deleted on the specified thread. For example:
+///
+/// <pre>
+/// class Foo : public base::RefCountedThreadSafe<Foo, CefDeleteOnUIThread> {
+/// public:
+/// Foo();
+/// void DoSomething();
+///
+/// private:
+/// // Allow deletion via scoped_refptr only.
+/// friend struct CefDeleteOnThread<TID_UI>;
+/// friend class base::RefCountedThreadSafe<Foo, CefDeleteOnUIThread>;
+///
+/// virtual ~Foo() {}
+/// };
+///
+/// base::scoped_refptr<Foo> foo = new Foo();
+/// foo->DoSomething();
+/// foo = NULL; /// Deletion of |foo| will occur on the UI thread.
+/// </pre>
+///
+template <CefThreadId thread>
+struct CefDeleteOnThread {
+ template <typename T>
+ static void Destruct(const T* x) {
+ if (CefCurrentlyOn(thread)) {
+ delete x;
+ } else {
+ CefPostTask(thread,
+ base::BindOnce(&CefDeleteOnThread<thread>::Destruct<T>,
+ base::Unretained(x)));
+ }
+ }
+};
+
+struct CefDeleteOnUIThread : public CefDeleteOnThread<TID_UI> {};
+struct CefDeleteOnIOThread : public CefDeleteOnThread<TID_IO> {};
+struct CefDeleteOnFileBackgroundThread
+ : public CefDeleteOnThread<TID_FILE_BACKGROUND> {};
+struct CefDeleteOnFileUserVisibleThread
+ : public CefDeleteOnThread<TID_FILE_USER_VISIBLE> {};
+struct CefDeleteOnFileUserBlockingThread
+ : public CefDeleteOnThread<TID_FILE_USER_BLOCKING> {};
+struct CefDeleteOnRendererThread : public CefDeleteOnThread<TID_RENDERER> {};
+
+// Same as IMPLEMENT_REFCOUNTING() but using the specified Destructor.
+#define IMPLEMENT_REFCOUNTING_EX(ClassName, Destructor) \
+ public: \
+ void AddRef() const override { \
+ ref_count_.AddRef(); \
+ } \
+ bool Release() const override { \
+ if (ref_count_.Release()) { \
+ Destructor::Destruct(this); \
+ return true; \
+ } \
+ return false; \
+ } \
+ bool HasOneRef() const override { \
+ return ref_count_.HasOneRef(); \
+ } \
+ bool HasAtLeastOneRef() const override { \
+ return ref_count_.HasAtLeastOneRef(); \
+ } \
+ \
+ private: \
+ CefRefCount ref_count_
+
+#define IMPLEMENT_REFCOUNTING_DELETE_ON_UIT(ClassName) \
+ IMPLEMENT_REFCOUNTING_EX(ClassName, CefDeleteOnUIThread)
+
+#define IMPLEMENT_REFCOUNTING_DELETE_ON_IOT(ClassName) \
+ IMPLEMENT_REFCOUNTING_EX(ClassName, CefDeleteOnIOThread)
+
+///
+/// Helper class to manage a scoped copy of |argv|.
+///
+class CefScopedArgArray {
+ public:
+ CefScopedArgArray(int argc, char* argv[]) {
+ // argv should have (argc + 1) elements, the last one always being NULL.
+ array_ = new char*[argc + 1];
+ values_.resize(argc);
+ for (int i = 0; i < argc; ++i) {
+ values_[i] = argv[i];
+ array_[i] = const_cast<char*>(values_[i].c_str());
+ }
+ array_[argc] = NULL;
+ }
+
+ CefScopedArgArray(const CefScopedArgArray&) = delete;
+ CefScopedArgArray& operator=(const CefScopedArgArray&) = delete;
+
+ ~CefScopedArgArray() { delete[] array_; }
+
+ char** array() const { return array_; }
+
+ private:
+ char** array_;
+
+ // Keep values in a vector separate from |array_| because various users may
+ // modify |array_| and we still want to clean up memory properly.
+ std::vector<std::string> values_;
+};
+
+#endif // CEF_INCLUDE_WRAPPER_CEF_HELPERS_H_
diff --git a/include/wrapper/cef_library_loader.h b/include/wrapper/cef_library_loader.h
new file mode 100644
index 00000000..4fa8343f
--- /dev/null
+++ b/include/wrapper/cef_library_loader.h
@@ -0,0 +1,133 @@
+// Copyright (c) 2018 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CEF_INCLUDE_WRAPPER_CEF_LIBRARY_LOADER_H_
+#define CEF_INCLUDE_WRAPPER_CEF_LIBRARY_LOADER_H_
+#pragma once
+
+#include "include/base/cef_build.h"
+
+#ifdef __cplusplus
+#include <string>
+
+extern "C" {
+#endif // __cplusplus
+
+///
+/// Load the CEF library at the specified |path|. Returns true (1) on
+/// success and false (0) on failure.
+///
+int cef_load_library(const char* path);
+
+///
+/// Unload the CEF library that was previously loaded. Returns true (1)
+/// on success and false (0) on failure.
+///
+int cef_unload_library(void);
+
+#ifdef __cplusplus
+}
+
+#if defined(OS_MAC)
+
+///
+/// Scoped helper for loading and unloading the CEF framework library at
+/// runtime from the expected location in the app bundle. Loading at runtime
+/// instead of linking directly is a requirement of the macOS sandbox
+/// implementation.
+///
+/// Example usage in the main process:
+///
+/// <pre>
+/// #include "include/wrapper/cef_library_loader.h"
+///
+/// int main(int argc, char* argv[]) {
+/// // Dynamically load the CEF framework library.
+/// CefScopedLibraryLoader library_loader;
+/// if (!library_loader.LoadInMain())
+/// return 1;
+///
+/// // Continue with CEF initialization...
+/// }
+/// </pre>
+///
+/// Example usage in the helper process:
+///
+/// <pre>
+/// #include "include/cef_sandbox_mac.h"
+/// #include "include/wrapper/cef_library_loader.h"
+///
+/// int main(int argc, char* argv[]) {
+/// // Initialize the macOS sandbox for this helper process.
+/// CefScopedSandboxContext sandbox_context;
+/// if (!sandbox_context.Initialize(argc, argv))
+/// return 1;
+///
+/// // Dynamically load the CEF framework library.
+/// CefScopedLibraryLoader library_loader;
+/// if (!library_loader.LoadInHelper())
+/// return 1;
+///
+/// // Continue with CEF initialization...
+/// }
+/// </pre>
+///
+class CefScopedLibraryLoader {
+ public:
+ CefScopedLibraryLoader();
+
+ CefScopedLibraryLoader(const CefScopedLibraryLoader&) = delete;
+ CefScopedLibraryLoader& operator=(const CefScopedLibraryLoader&) = delete;
+
+ ~CefScopedLibraryLoader();
+
+ ///
+ /// Load the CEF framework in the main process from the expected app
+ /// bundle location relative to the executable. Returns true if the
+ /// load succeeds.
+ ///
+ bool LoadInMain() { return Load(false); }
+
+ ///
+ /// Load the CEF framework in the helper process from the expected app
+ /// bundle location relative to the executable. Returns true if the
+ /// load succeeds.
+ ///
+ bool LoadInHelper() { return Load(true); }
+
+ private:
+ bool Load(bool helper);
+
+ bool loaded_;
+};
+
+#endif // defined(OS_MAC)
+#endif // __cplusplus
+
+#endif // CEF_INCLUDE_WRAPPER_CEF_LIBRARY_LOADER_H_
diff --git a/include/wrapper/cef_message_router.h b/include/wrapper/cef_message_router.h
new file mode 100644
index 00000000..7ce06e41
--- /dev/null
+++ b/include/wrapper/cef_message_router.h
@@ -0,0 +1,439 @@
+// Copyright (c) 2014 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file are only available to applications that link
+// against the libcef_dll_wrapper target.
+//
+
+#ifndef CEF_INCLUDE_WRAPPER_CEF_MESSAGE_ROUTER_H_
+#define CEF_INCLUDE_WRAPPER_CEF_MESSAGE_ROUTER_H_
+#pragma once
+
+#include "include/base/cef_ref_counted.h"
+#include "include/cef_base.h"
+#include "include/cef_browser.h"
+#include "include/cef_process_message.h"
+#include "include/cef_v8.h"
+
+// The below classes implement support for routing aynchronous messages between
+// JavaScript running in the renderer process and C++ running in the browser
+// process. An application interacts with the router by passing it data from
+// standard CEF C++ callbacks (OnBeforeBrowse, OnProcessMessageReceived,
+// OnContextCreated, etc). The renderer-side router supports generic JavaScript
+// callback registration and execution while the browser-side router supports
+// application-specific logic via one or more application-provided Handler
+// instances.
+//
+// The renderer-side router implementation exposes a query function and a cancel
+// function via the JavaScript 'window' object:
+//
+// // Create and send a new query.
+// var request_id = window.cefQuery({
+// request: 'my_request',
+// persistent: false,
+// onSuccess: function(response) {},
+// onFailure: function(error_code, error_message) {}
+// });
+//
+// // Optionally cancel the query.
+// window.cefQueryCancel(request_id);
+//
+// When |window.cefQuery| is executed the request is sent asynchronously to one
+// or more C++ Handler objects registered in the browser process. Each C++
+// Handler can choose to either handle or ignore the query in the
+// Handler::OnQuery callback. If a Handler chooses to handle the query then it
+// should execute Callback::Success when a response is available or
+// Callback::Failure if an error occurs. This will result in asynchronous
+// execution of the associated JavaScript callback in the renderer process. Any
+// queries unhandled by C++ code in the browser process will be automatically
+// canceled and the associated JavaScript onFailure callback will be executed
+// with an error code of -1.
+//
+// Queries can be either persistent or non-persistent. If the query is
+// persistent then the callbacks will remain registered until one of the
+// following conditions are met:
+//
+// A. The query is canceled in JavaScript using the |window.cefQueryCancel|
+// function.
+// B. The query is canceled in C++ code using the Callback::Failure function.
+// C. The context associated with the query is released due to browser
+// destruction, navigation or renderer process termination.
+//
+// If the query is non-persistent then the registration will be removed after
+// the JavaScript callback is executed a single time. If a query is canceled for
+// a reason other than Callback::Failure being executed then the associated
+// Handler's OnQueryCanceled method will be called.
+//
+// Some possible usage patterns include:
+//
+// One-time Request. Use a non-persistent query to send a JavaScript request.
+// The Handler evaluates the request and returns the response. The query is
+// then discarded.
+//
+// Broadcast. Use a persistent query to register as a JavaScript broadcast
+// receiver. The Handler keeps track of all registered Callbacks and executes
+// them sequentially to deliver the broadcast message.
+//
+// Subscription. Use a persistent query to register as a JavaScript subscription
+// receiver. The Handler initiates the subscription feed on the first request
+// and delivers responses to all registered subscribers as they become
+// available. The Handler cancels the subscription feed when there are no
+// longer any registered JavaScript receivers.
+//
+// Message routing occurs on a per-browser and per-context basis. Consequently,
+// additional application logic can be applied by restricting which browser or
+// context instances are passed into the router. If you choose to use this
+// approach do so cautiously. In order for the router to function correctly any
+// browser or context instance passed into a single router callback must then
+// be passed into all router callbacks.
+//
+// There is generally no need to have multiple renderer-side routers unless you
+// wish to have multiple bindings with different JavaScript function names. It
+// can be useful to have multiple browser-side routers with different client-
+// provided Handler instances when implementing different behaviors on a per-
+// browser basis.
+//
+// This implementation places no formatting restrictions on payload content.
+// An application may choose to exchange anything from simple formatted
+// strings to serialized XML or JSON data.
+//
+//
+// EXAMPLE USAGE
+//
+// 1. Define the router configuration. You can optionally specify settings
+// like the JavaScript function names. The configuration must be the same in
+// both the browser and renderer processes. If using multiple routers in the
+// same application make sure to specify unique function names for each
+// router configuration.
+//
+// // Example config object showing the default values.
+// CefMessageRouterConfig config;
+// config.js_query_function = "cefQuery";
+// config.js_cancel_function = "cefQueryCancel";
+//
+// 2. Create an instance of CefMessageRouterBrowserSide in the browser process.
+// You might choose to make it a member of your CefClient implementation,
+// for example.
+//
+// browser_side_router_ = CefMessageRouterBrowserSide::Create(config);
+//
+// 3. Register one or more Handlers. The Handler instances must either outlive
+// the router or be removed from the router before they're deleted.
+//
+// browser_side_router_->AddHandler(my_handler);
+//
+// 4. Call all required CefMessageRouterBrowserSide methods from other callbacks
+// in your CefClient implementation (OnBeforeClose, etc). See the
+// CefMessageRouterBrowserSide class documentation for the complete list of
+// methods.
+//
+// 5. Create an instance of CefMessageRouterRendererSide in the renderer
+// process.
+// You might choose to make it a member of your CefApp implementation, for
+// example.
+//
+// renderer_side_router_ = CefMessageRouterRendererSide::Create(config);
+//
+// 6. Call all required CefMessageRouterRendererSide methods from other
+// callbacks in your CefRenderProcessHandler implementation
+// (OnContextCreated, etc). See the CefMessageRouterRendererSide class
+// documentation for the complete list of methods.
+//
+// 7. Execute the query function from JavaScript code.
+//
+// window.cefQuery({request: 'my_request',
+// persistent: false,
+// onSuccess: function(response) { print(response); },
+// onFailure: function(error_code, error_message) {} });
+//
+// 8. Handle the query in your Handler::OnQuery implementation and execute the
+// appropriate callback either immediately or asynchronously.
+//
+// void MyHandler::OnQuery(int64 query_id,
+// CefRefPtr<CefBrowser> browser,
+// CefRefPtr<CefFrame> frame,
+// const CefString& request,
+// bool persistent,
+// CefRefPtr<Callback> callback) {
+// if (request == "my_request") {
+// callback->Continue("my_response");
+// return true;
+// }
+// return false; // Not handled.
+// }
+//
+// 9. Notice that the onSuccess callback is executed in JavaScript.
+
+///
+/// Used to configure the query router. The same values must be passed to both
+/// CefMessageRouterBrowserSide and CefMessageRouterRendererSide. If using
+/// multiple router pairs make sure to choose values that do not conflict.
+///
+struct CefMessageRouterConfig {
+ CefMessageRouterConfig();
+
+ ///
+ /// Name of the JavaScript function that will be added to the 'window' object
+ /// for sending a query. The default value is "cefQuery".
+ ///
+ CefString js_query_function;
+
+ ///
+ /// Name of the JavaScript function that will be added to the 'window' object
+ /// for canceling a pending query. The default value is "cefQueryCancel".
+ ///
+ CefString js_cancel_function;
+
+ ///
+ /// Messages of size (in bytes) larger than this threshold will be sent via
+ /// shared memory region.
+ ///
+ size_t message_size_threshold;
+};
+
+///
+/// Implements the browser side of query routing. The methods of this class may
+/// be called on any browser process thread unless otherwise indicated.
+///
+class CefMessageRouterBrowserSide
+ : public base::RefCountedThreadSafe<CefMessageRouterBrowserSide> {
+ public:
+ ///
+ /// Callback associated with a single pending asynchronous query. Execute the
+ /// Success or Failure method to send an asynchronous response to the
+ /// associated JavaScript handler. It is a runtime error to destroy a Callback
+ /// object associated with an uncanceled query without first executing one of
+ /// the callback methods. The methods of this class may be called on any
+ /// browser process thread.
+ ///
+ class Callback : public CefBaseRefCounted {
+ public:
+ ///
+ /// Notify the associated JavaScript onSuccess callback that the query has
+ /// completed successfully with the specified |response|.
+ ///
+ virtual void Success(const CefString& response) = 0;
+
+ ///
+ /// Notify the associated JavaScript onFailure callback that the query has
+ /// failed with the specified |error_code| and |error_message|.
+ ///
+ virtual void Failure(int error_code, const CefString& error_message) = 0;
+ };
+
+ ///
+ /// Implement this interface to handle queries. All methods will be executed
+ /// on the browser process UI thread.
+ ///
+ class Handler {
+ public:
+ using Callback = CefMessageRouterBrowserSide::Callback;
+
+ ///
+ /// Executed when a new query is received. |query_id| uniquely identifies
+ /// the query for the life span of the router. Return true to handle the
+ /// query or false to propagate the query to other registered handlers, if
+ /// any. If no handlers return true from this method then the query will be
+ /// automatically canceled with an error code of -1 delivered to the
+ /// JavaScript onFailure callback. If this method returns true then a
+ /// Callback method must be executed either in this method or asynchronously
+ /// to complete the query.
+ ///
+ virtual bool OnQuery(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int64 query_id,
+ const CefString& request,
+ bool persistent,
+ CefRefPtr<Callback> callback) {
+ return false;
+ }
+
+ ///
+ /// Executed when a query has been canceled either explicitly using the
+ /// JavaScript cancel function or implicitly due to browser destruction,
+ /// navigation or renderer process termination. It will only be called for
+ /// the single handler that returned true from OnQuery for the same
+ /// |query_id|. No references to the associated Callback object should be
+ /// kept after this method is called, nor should any Callback methods be
+ /// executed.
+ ///
+ virtual void OnQueryCanceled(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int64 query_id) {}
+
+ virtual ~Handler() {}
+ };
+
+ ///
+ /// Create a new router with the specified configuration.
+ ///
+ static CefRefPtr<CefMessageRouterBrowserSide> Create(
+ const CefMessageRouterConfig& config);
+
+ ///
+ /// Add a new query handler. If |first| is true it will be added as the first
+ /// handler, otherwise it will be added as the last handler. Returns true if
+ /// the handler is added successfully or false if the handler has already been
+ /// added. Must be called on the browser process UI thread. The Handler object
+ /// must either outlive the router or be removed before deletion.
+ ///
+ virtual bool AddHandler(Handler* handler, bool first) = 0;
+
+ ///
+ /// Remove an existing query handler. Any pending queries associated with the
+ /// handler will be canceled. Handler::OnQueryCanceled will be called and the
+ /// associated JavaScript onFailure callback will be executed with an error
+ /// code of -1. Returns true if the handler is removed successfully or false
+ /// if the handler is not found. Must be called on the browser process UI
+ /// thread.
+ ///
+ virtual bool RemoveHandler(Handler* handler) = 0;
+
+ ///
+ /// Cancel all pending queries associated with either |browser| or |handler|.
+ /// If both |browser| and |handler| are NULL all pending queries will be
+ /// canceled. Handler::OnQueryCanceled will be called and the associated
+ /// JavaScript onFailure callback will be executed in all cases with an error
+ /// code of -1.
+ ///
+ virtual void CancelPending(CefRefPtr<CefBrowser> browser,
+ Handler* handler) = 0;
+
+ ///
+ /// Returns the number of queries currently pending for the specified
+ /// |browser| and/or |handler|. Either or both values may be empty. Must be
+ /// called on the browser process UI thread.
+ ///
+ virtual int GetPendingCount(CefRefPtr<CefBrowser> browser,
+ Handler* handler) = 0;
+
+ /// The below methods should be called from other CEF handlers. They must be
+ /// called exactly as documented for the router to function correctly.
+
+ ///
+ /// Call from CefLifeSpanHandler::OnBeforeClose. Any pending queries
+ /// associated with |browser| will be canceled and Handler::OnQueryCanceled
+ /// will be called. No JavaScript callbacks will be executed since this
+ /// indicates destruction of the browser.
+ ///
+ virtual void OnBeforeClose(CefRefPtr<CefBrowser> browser) = 0;
+
+ ///
+ /// Call from CefRequestHandler::OnRenderProcessTerminated. Any pending
+ /// queries associated with |browser| will be canceled and
+ /// Handler::OnQueryCanceled will be called. No JavaScript callbacks will be
+ /// executed since this indicates destruction of the context.
+ ///
+ virtual void OnRenderProcessTerminated(CefRefPtr<CefBrowser> browser) = 0;
+
+ ///
+ /// Call from CefRequestHandler::OnBeforeBrowse only if the navigation is
+ /// allowed to proceed. If |frame| is the main frame then any pending queries
+ /// associated with |browser| will be canceled and Handler::OnQueryCanceled
+ /// will be called. No JavaScript callbacks will be executed since this
+ /// indicates destruction of the context.
+ ///
+ virtual void OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) = 0;
+
+ ///
+ /// Call from CefClient::OnProcessMessageReceived. Returns true if the message
+ /// is handled by this router or false otherwise.
+ ///
+ virtual bool OnProcessMessageReceived(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefProcessId source_process,
+ CefRefPtr<CefProcessMessage> message) = 0;
+
+ protected:
+ // Protect against accidental deletion of this object.
+ friend class base::RefCountedThreadSafe<CefMessageRouterBrowserSide>;
+ virtual ~CefMessageRouterBrowserSide() {}
+};
+
+///
+/// Implements the renderer side of query routing. The methods of this class
+/// must be called on the render process main thread.
+///
+class CefMessageRouterRendererSide
+ : public base::RefCountedThreadSafe<CefMessageRouterRendererSide> {
+ public:
+ ///
+ /// Create a new router with the specified configuration.
+ ///
+ static CefRefPtr<CefMessageRouterRendererSide> Create(
+ const CefMessageRouterConfig& config);
+
+ ///
+ /// Returns the number of queries currently pending for the specified
+ /// |browser| and/or |context|. Either or both values may be empty.
+ ///
+ virtual int GetPendingCount(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefV8Context> context) = 0;
+
+ // The below methods should be called from other CEF handlers. They must be
+ // called exactly as documented for the router to function correctly.
+
+ ///
+ /// Call from CefRenderProcessHandler::OnContextCreated. Registers the
+ /// JavaScripts functions with the new context.
+ ///
+ virtual void OnContextCreated(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefV8Context> context) = 0;
+
+ ///
+ /// Call from CefRenderProcessHandler::OnContextReleased. Any pending queries
+ /// associated with the released context will be canceled and
+ /// Handler::OnQueryCanceled will be called in the browser process.
+ ///
+ virtual void OnContextReleased(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefV8Context> context) = 0;
+
+ ///
+ /// Call from CefRenderProcessHandler::OnProcessMessageReceived. Returns true
+ /// if the message is handled by this router or false otherwise.
+ ///
+ virtual bool OnProcessMessageReceived(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefProcessId source_process,
+ CefRefPtr<CefProcessMessage> message) = 0;
+
+ protected:
+ // Protect against accidental deletion of this object.
+ friend class base::RefCountedThreadSafe<CefMessageRouterRendererSide>;
+ virtual ~CefMessageRouterRendererSide() {}
+};
+
+#endif // CEF_INCLUDE_WRAPPER_CEF_MESSAGE_ROUTER_H_
diff --git a/include/wrapper/cef_resource_manager.h b/include/wrapper/cef_resource_manager.h
new file mode 100644
index 00000000..0ff51fc0
--- /dev/null
+++ b/include/wrapper/cef_resource_manager.h
@@ -0,0 +1,374 @@
+// Copyright (c) 2015 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file are only available to applications that link
+// against the libcef_dll_wrapper target.
+//
+
+#ifndef CEF_INCLUDE_WRAPPER_CEF_RESOURCE_MANAGER_H_
+#define CEF_INCLUDE_WRAPPER_CEF_RESOURCE_MANAGER_H_
+#pragma once
+
+#include <list>
+#include <memory>
+
+#include "include/base/cef_callback.h"
+#include "include/base/cef_ref_counted.h"
+#include "include/base/cef_weak_ptr.h"
+#include "include/cef_request_handler.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "include/wrapper/cef_helpers.h"
+
+///
+/// Class for managing multiple resource providers. For each resource request
+/// providers will be called in order and have the option to (a) handle the
+/// request by returning a CefResourceHandler, (b) pass the request to the next
+/// provider in order, or (c) stop handling the request. See comments on the
+/// Request object for additional usage information. The methods of this class
+/// may be called on any browser process thread unless otherwise indicated.
+///
+class CefResourceManager
+ : public base::RefCountedThreadSafe<CefResourceManager,
+ CefDeleteOnIOThread> {
+ public:
+ ///
+ /// Provides an opportunity to modify |url| before it is passed to a provider.
+ /// For example, the implementation could rewrite |url| to include a default
+ /// file extension. |url| will be fully qualified and may contain query or
+ /// fragment components.
+ ///
+ using UrlFilter =
+ base::RepeatingCallback<std::string(const std::string& /*url*/)>;
+
+ ///
+ /// Used to resolve mime types for URLs, usually based on the file extension.
+ /// |url| will be fully qualified and may contain query or fragment
+ /// components.
+ ///
+ using MimeTypeResolver =
+ base::RepeatingCallback<std::string(const std::string& /*url*/)>;
+
+ private:
+ // Values that stay with a request as it moves between providers.
+ struct RequestParams {
+ std::string url_;
+ CefRefPtr<CefBrowser> browser_;
+ CefRefPtr<CefFrame> frame_;
+ CefRefPtr<CefRequest> request_;
+ UrlFilter url_filter_;
+ MimeTypeResolver mime_type_resolver_;
+ };
+
+ // Values that are associated with the pending request only.
+ struct RequestState;
+
+ public:
+ ///
+ /// Object representing a request. Each request object is used for a single
+ /// call to Provider::OnRequest and will become detached (meaning the
+ /// callbacks will no longer trigger) after Request::Continue or Request::Stop
+ /// is called. A request passed to Provider::OnRequestCanceled will already
+ /// have been detached. The methods of this class may be called on any browser
+ /// process thread.
+ ///
+ class Request : public base::RefCountedThreadSafe<Request> {
+ public:
+ Request(const Request&) = delete;
+ Request& operator=(const Request&) = delete;
+
+ ///
+ /// Returns the URL associated with this request. The returned value will be
+ /// fully qualified but will not contain query or fragment components. It
+ /// will already have been passed through the URL filter.
+ ///
+ std::string url() const { return params_.url_; }
+
+ ///
+ /// Returns the CefBrowser associated with this request.
+ ///
+ CefRefPtr<CefBrowser> browser() const { return params_.browser_; }
+
+ ///
+ /// Returns the CefFrame associated with this request.
+ ///
+ CefRefPtr<CefFrame> frame() const { return params_.frame_; }
+
+ ///
+ /// Returns the CefRequest associated with this request.
+ ///
+ CefRefPtr<CefRequest> request() const { return params_.request_; }
+
+ ///
+ /// Returns the current URL filter.
+ ///
+ const CefResourceManager::UrlFilter& url_filter() const {
+ return params_.url_filter_;
+ }
+
+ ///
+ /// Returns the current mime type resolver.
+ ///
+ const CefResourceManager::MimeTypeResolver& mime_type_resolver() const {
+ return params_.mime_type_resolver_;
+ }
+
+ ///
+ /// Continue handling the request. If |handler| is non-NULL then no
+ /// additional providers will be called and the |handler| value will be
+ /// returned via CefResourceManager::GetResourceHandler. If |handler| is
+ /// NULL then the next provider in order, if any, will be called. If there
+ /// are no additional providers then NULL will be returned via
+ /// CefResourceManager:: GetResourceHandler.
+ ///
+ void Continue(CefRefPtr<CefResourceHandler> handler);
+
+ ///
+ /// Stop handling the request. No additional providers will be called and
+ /// NULL will be returned via CefResourceManager::GetResourceHandler.
+ ///
+ void Stop();
+
+ private:
+ // Only allow deletion via scoped_refptr.
+ friend class base::RefCountedThreadSafe<Request>;
+
+ friend class CefResourceManager;
+
+ // The below methods are called on the browser process IO thread.
+
+ explicit Request(std::unique_ptr<RequestState> state);
+
+ std::unique_ptr<RequestState> SendRequest();
+ bool HasState();
+
+ static void ContinueOnIOThread(std::unique_ptr<RequestState> state,
+ CefRefPtr<CefResourceHandler> handler);
+ static void StopOnIOThread(std::unique_ptr<RequestState> state);
+
+ // Will be non-NULL while the request is pending. Only accessed on the
+ // browser process IO thread.
+ std::unique_ptr<RequestState> state_;
+
+ // Params that stay with this request object. Safe to access on any thread.
+ RequestParams params_;
+ };
+
+ using RequestList = std::list<scoped_refptr<Request>>;
+
+ ///
+ /// Interface implemented by resource providers. A provider may be created on
+ /// any thread but the methods will be called on, and the object will be
+ /// destroyed on, the browser process IO thread.
+ ///
+ class Provider {
+ public:
+ ///
+ /// Called to handle a request. If the provider knows immediately that it
+ /// will not handle the request return false. Otherwise, return true and
+ /// call Request::Continue or Request::Stop either in this method or
+ /// asynchronously to indicate completion. See comments on Request for
+ /// additional usage information.
+ ///
+ virtual bool OnRequest(scoped_refptr<Request> request) = 0;
+
+ ///
+ /// Called when a request has been canceled. It is still safe to dereference
+ /// |request| but any calls to Request::Continue or Request::Stop will be
+ /// ignored.
+ ///
+ virtual void OnRequestCanceled(scoped_refptr<Request> request) {}
+
+ virtual ~Provider() {}
+ };
+
+ CefResourceManager();
+
+ CefResourceManager(const CefResourceManager&) = delete;
+ CefResourceManager& operator=(const CefResourceManager&) = delete;
+
+ ///
+ /// Add a provider that maps requests for |url| to |content|. |url| should be
+ /// fully qualified but not include a query or fragment component. If
+ /// |mime_type| is empty the MimeTypeResolver will be used. See comments on
+ /// AddProvider for usage of the |order| and |identifier| parameters.
+ ///
+ void AddContentProvider(const std::string& url,
+ const std::string& content,
+ const std::string& mime_type,
+ int order,
+ const std::string& identifier);
+
+ ///
+ /// Add a provider that maps requests that start with |url_path| to files
+ /// under |directory_path|. |url_path| should include an origin and optional
+ /// path component only. Files will be loaded when a matching URL is
+ /// requested. See comments on AddProvider for usage of the |order| and
+ /// |identifier| parameters.
+ ///
+ void AddDirectoryProvider(const std::string& url_path,
+ const std::string& directory_path,
+ int order,
+ const std::string& identifier);
+
+ ///
+ /// Add a provider that maps requests that start with |url_path| to files
+ /// stored in the archive file at |archive_path|. |url_path| should include an
+ /// origin and optional path component only. The archive file will be loaded
+ /// when a matching URL is requested for the first time. See comments on
+ /// AddProvider for usage of the |order| and |identifier| parameters.
+ ///
+ void AddArchiveProvider(const std::string& url_path,
+ const std::string& archive_path,
+ const std::string& password,
+ int order,
+ const std::string& identifier);
+
+ ///
+ /// Add a provider. This object takes ownership of |provider|. Providers will
+ /// be called in ascending order based on the |order| value. Multiple
+ /// providers sharing the same |order| value will be called in the order that
+ /// they were added. The |identifier| value, which does not need to be unique,
+ /// can be used to remove the provider at a later time.
+ ///
+ void AddProvider(Provider* provider,
+ int order,
+ const std::string& identifier);
+
+ ///
+ /// Remove all providers with the specified |identifier| value. If any removed
+ /// providers have pending requests the Provider::OnRequestCancel method will
+ /// be called. The removed providers may be deleted immediately or at a later
+ /// time.
+ ///
+ void RemoveProviders(const std::string& identifier);
+
+ ///
+ /// Remove all providers. If any removed providers have pending requests the
+ /// Provider::OnRequestCancel method will be called. The removed providers may
+ /// be deleted immediately or at a later time.
+ ///
+ void RemoveAllProviders();
+
+ ///
+ /// Set the url filter. If not set the default no-op filter will be used.
+ /// Changes to this value will not affect currently pending requests.
+ ///
+ void SetUrlFilter(const UrlFilter& filter);
+
+ ///
+ /// Set the mime type resolver. If not set the default resolver will be used.
+ /// Changes to this value will not affect currently pending requests.
+ ///
+ void SetMimeTypeResolver(const MimeTypeResolver& resolver);
+
+ /// The below methods should be called from other CEF handlers. They must be
+ /// called exactly as documented for the manager to function correctly.
+
+ ///
+ /// Called from CefRequestHandler::OnBeforeResourceLoad on the browser process
+ /// IO thread.
+ ///
+ cef_return_value_t OnBeforeResourceLoad(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefCallback> callback);
+
+ ///
+ /// Called from CefRequestHandler::GetResourceHandler on the browser process
+ /// IO thread.
+ ///
+ CefRefPtr<CefResourceHandler> GetResourceHandler(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request);
+
+ private:
+ // Only allow deletion via scoped_refptr.
+ friend struct CefDeleteOnThread<TID_IO>;
+ friend class base::RefCountedThreadSafe<CefResourceManager,
+ CefDeleteOnIOThread>;
+
+ ~CefResourceManager();
+
+ // Provider and associated information.
+ struct ProviderEntry;
+ using ProviderEntryList = std::list<ProviderEntry*>;
+
+ // Values associated with the pending request only. Ownership will be passed
+ // between requests and the resource manager as request handling proceeds.
+ struct RequestState {
+ ~RequestState();
+
+ base::WeakPtr<CefResourceManager> manager_;
+
+ // Callback to execute once request handling is complete.
+ CefRefPtr<CefCallback> callback_;
+
+ // Position of the currently associated ProviderEntry in the |providers_|
+ // list.
+ ProviderEntryList::iterator current_entry_pos_;
+
+ // Position of this request object in the currently associated
+ // ProviderEntry's |pending_requests_| list.
+ RequestList::iterator current_request_pos_;
+
+ // Params that will be copied to each request object.
+ RequestParams params_;
+ };
+
+ // Methods that manage request state between requests. Called on the browser
+ // process IO thread.
+ bool SendRequest(std::unique_ptr<RequestState> state);
+ void ContinueRequest(std::unique_ptr<RequestState> state,
+ CefRefPtr<CefResourceHandler> handler);
+ void StopRequest(std::unique_ptr<RequestState> state);
+ bool IncrementProvider(RequestState* state);
+ void DetachRequestFromProvider(RequestState* state);
+ void GetNextValidProvider(ProviderEntryList::iterator& iterator);
+ void DeleteProvider(ProviderEntryList::iterator& iterator, bool stop);
+
+ // The below members are only accessed on the browser process IO thread.
+
+ // List of providers including additional associated information.
+ ProviderEntryList providers_;
+
+ // Map of response ID to pending CefResourceHandler object.
+ using PendingHandlersMap = std::map<uint64, CefRefPtr<CefResourceHandler>>;
+ PendingHandlersMap pending_handlers_;
+
+ UrlFilter url_filter_;
+ MimeTypeResolver mime_type_resolver_;
+
+ // Must be the last member. Created and accessed on the IO thread.
+ std::unique_ptr<base::WeakPtrFactory<CefResourceManager>> weak_ptr_factory_;
+};
+
+#endif // CEF_INCLUDE_WRAPPER_CEF_RESOURCE_MANAGER_H_
diff --git a/include/wrapper/cef_scoped_temp_dir.h b/include/wrapper/cef_scoped_temp_dir.h
new file mode 100644
index 00000000..6bd8cea0
--- /dev/null
+++ b/include/wrapper/cef_scoped_temp_dir.h
@@ -0,0 +1,118 @@
+// Copyright (c) 2016 Marshall A. Greenblatt. Portions copyright (c) 2011
+// Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file are only available to applications that link
+// against the libcef_dll_wrapper target.
+//
+
+#ifndef CEF_INCLUDE_SCOPED_TEMP_DIR_H_
+#define CEF_INCLUDE_SCOPED_TEMP_DIR_H_
+#pragma once
+
+#include "include/base/cef_build.h"
+#include "include/cef_base.h"
+
+///
+/// An object representing a temporary / scratch directory that should be
+/// cleaned up (recursively) when this object goes out of scope. Note that
+/// since deletion occurs during the destructor, no further error handling is
+/// possible if the directory fails to be deleted. As a result, deletion is not
+/// guaranteed by this class.
+///
+/// Multiple calls to the methods which establish a temporary directory
+/// (CreateUniqueTempDir, CreateUniqueTempDirUnderPath, and Set) must have
+/// intervening calls to Delete or Take, or the calls will fail.
+///
+class CefScopedTempDir {
+ public:
+ ///
+ /// No directory is owned/created initially.
+ ///
+ CefScopedTempDir();
+
+ CefScopedTempDir(const CefScopedTempDir&) = delete;
+ CefScopedTempDir& operator=(const CefScopedTempDir&) = delete;
+
+ ///
+ /// Recursively delete path.
+ ///
+ ~CefScopedTempDir();
+
+ ///
+ /// Creates a unique directory in TempPath, and takes ownership of it.
+ /// See file_util::CreateNewTemporaryDirectory.
+ ///
+ [[nodiscard]] bool CreateUniqueTempDir();
+
+ ///
+ /// Creates a unique directory under a given path, and takes ownership of it.
+ ///
+ [[nodiscard]] bool CreateUniqueTempDirUnderPath(const CefString& path);
+
+ ///
+ /// Takes ownership of directory at |path|, creating it if necessary.
+ /// Don't call multiple times unless Take() has been called first.
+ ///
+ [[nodiscard]] bool Set(const CefString& path);
+
+ ///
+ /// Deletes the temporary directory wrapped by this object.
+ ///
+ [[nodiscard]] bool Delete();
+
+ ///
+ /// Caller takes ownership of the temporary directory so it won't be destroyed
+ /// when this object goes out of scope.
+ ///
+ CefString Take();
+
+ ///
+ /// Returns the path to the created directory. Call one of the
+ /// CreateUniqueTempDir* methods before getting the path.
+ ///
+ const CefString& GetPath() const;
+
+ ///
+ /// Returns true if path_ is empty.
+ ///
+ bool IsEmpty() const;
+
+ ///
+ /// Returns true if path_ is non-empty and exists.
+ ///
+ bool IsValid() const;
+
+ private:
+ CefString path_;
+};
+
+#endif // CEF_INCLUDE_SCOPED_TEMP_DIR_H_
diff --git a/include/wrapper/cef_stream_resource_handler.h b/include/wrapper/cef_stream_resource_handler.h
new file mode 100644
index 00000000..20246d13
--- /dev/null
+++ b/include/wrapper/cef_stream_resource_handler.h
@@ -0,0 +1,89 @@
+// Copyright (c) 2012 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file are only available to applications that link
+// against the libcef_dll_wrapper target.
+//
+
+#ifndef CEF_INCLUDE_WRAPPER_CEF_STREAM_RESOURCE_HANDLER_H_
+#define CEF_INCLUDE_WRAPPER_CEF_STREAM_RESOURCE_HANDLER_H_
+#pragma once
+
+#include "include/cef_resource_handler.h"
+#include "include/cef_response.h"
+#include "include/cef_stream.h"
+
+///
+/// Implementation of the CefResourceHandler class for reading from a CefStream.
+///
+class CefStreamResourceHandler : public CefResourceHandler {
+ public:
+ ///
+ /// Create a new object with default response values.
+ ///
+ CefStreamResourceHandler(const CefString& mime_type,
+ CefRefPtr<CefStreamReader> stream);
+ ///
+ /// Create a new object with explicit response values.
+ ///
+ CefStreamResourceHandler(int status_code,
+ const CefString& status_text,
+ const CefString& mime_type,
+ CefResponse::HeaderMap header_map,
+ CefRefPtr<CefStreamReader> stream);
+
+ CefStreamResourceHandler(const CefStreamResourceHandler&) = delete;
+ CefStreamResourceHandler& operator=(const CefStreamResourceHandler&) = delete;
+
+ // CefResourceHandler methods.
+ bool Open(CefRefPtr<CefRequest> request,
+ bool& handle_request,
+ CefRefPtr<CefCallback> callback) override;
+ void GetResponseHeaders(CefRefPtr<CefResponse> response,
+ int64& response_length,
+ CefString& redirectUrl) override;
+ bool Read(void* data_out,
+ int bytes_to_read,
+ int& bytes_read,
+ CefRefPtr<CefResourceReadCallback> callback) override;
+ void Cancel() override;
+
+ private:
+ const int status_code_;
+ const CefString status_text_;
+ const CefString mime_type_;
+ const CefResponse::HeaderMap header_map_;
+ const CefRefPtr<CefStreamReader> stream_;
+
+ IMPLEMENT_REFCOUNTING(CefStreamResourceHandler);
+};
+
+#endif // CEF_INCLUDE_WRAPPER_CEF_STREAM_RESOURCE_HANDLER_H_
diff --git a/include/wrapper/cef_xml_object.h b/include/wrapper/cef_xml_object.h
new file mode 100644
index 00000000..36130984
--- /dev/null
+++ b/include/wrapper/cef_xml_object.h
@@ -0,0 +1,195 @@
+// Copyright (c) 2011 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file are only available to applications that link
+// against the libcef_dll_wrapper target.
+//
+
+#ifndef CEF_INCLUDE_WRAPPER_CEF_XML_OBJECT_H_
+#define CEF_INCLUDE_WRAPPER_CEF_XML_OBJECT_H_
+#pragma once
+
+#include <map>
+#include <vector>
+
+#include "include/base/cef_lock.h"
+#include "include/base/cef_ref_counted.h"
+#include "include/cef_base.h"
+#include "include/cef_xml_reader.h"
+
+class CefStreamReader;
+
+///
+/// Thread safe class for representing XML data as a structured object. This
+/// class should not be used with large XML documents because all data will be
+/// resident in memory at the same time. This implementation supports a
+/// restricted set of XML features:
+///
+/// 1. Processing instructions, whitespace and comments are ignored.
+/// 2. Elements and attributes must always be referenced using the fully
+/// qualified name (ie, namespace:localname).
+/// 3. Empty elements ("<a/>") and elements with zero-length values ("<a></a>")
+/// are considered the same.
+/// 4. Element nodes are considered part of a value if:
+/// 1. The element node follows a non-element node at the same depth
+/// (see 5), or
+/// 2. The element node does not have a namespace and the parent node does.
+/// 5. Mixed node types at the same depth are combined into a single element
+/// value as follows:
+/// 1. All node values are concatenated to form a single string value.
+/// 2. Entity reference nodes are resolved to the corresponding entity value.
+/// 3. Element nodes are represented by their outer XML string.
+///
+class CefXmlObject : public base::RefCountedThreadSafe<CefXmlObject> {
+ public:
+ using ObjectVector = std::vector<CefRefPtr<CefXmlObject>>;
+ using AttributeMap = std::map<CefString, CefString>;
+
+ ///
+ /// Create a new object with the specified name. An object name must always be
+ /// at least one character long.
+ ///
+ explicit CefXmlObject(const CefString& name);
+
+ CefXmlObject(const CefXmlObject&) = delete;
+ CefXmlObject& operator=(const CefXmlObject&) = delete;
+
+ ///
+ /// Load the contents of the specified XML stream into this object. The
+ /// existing children and attributes, if any, will first be cleared.
+ ///
+ bool Load(CefRefPtr<CefStreamReader> stream,
+ CefXmlReader::EncodingType encodingType,
+ const CefString& URI,
+ CefString* loadError);
+
+ ///
+ /// Set the name, children and attributes of this object to a duplicate of the
+ /// specified object's contents. The existing children and attributes, if any,
+ /// will first be cleared.
+ ///
+ void Set(CefRefPtr<CefXmlObject> object);
+
+ ///
+ /// Append a duplicate of the children and attributes of the specified object
+ /// to this object. If |overwriteAttributes| is true then any attributes in
+ /// this object that also exist in the specified object will be overwritten
+ /// with the new values. The name of this object is not changed.
+ ///
+ void Append(CefRefPtr<CefXmlObject> object, bool overwriteAttributes);
+
+ ///
+ /// Return a new object with the same name, children and attributes as this
+ /// object. The parent of the new object will be NULL.
+ ///
+ CefRefPtr<CefXmlObject> Duplicate();
+
+ ///
+ /// Clears this object's children and attributes. The name and parenting of
+ /// this object are not changed.
+ ///
+ void Clear();
+
+ ///
+ /// Access the object's name. An object name must always be at least one
+ /// character long.
+ ///
+ CefString GetName();
+ bool SetName(const CefString& name);
+
+ ///
+ /// Access the object's parent. The parent can be NULL if this object has not
+ /// been added as the child on another object.
+ ///
+ bool HasParent();
+ CefRefPtr<CefXmlObject> GetParent();
+
+ ///
+ /// Access the object's value. An object cannot have a value if it also has
+ /// children. Attempting to set the value while children exist will fail.
+ ///
+ bool HasValue();
+ CefString GetValue();
+ bool SetValue(const CefString& value);
+
+ ///
+ /// Access the object's attributes. Attributes must have unique names.
+ ///
+ bool HasAttributes();
+ size_t GetAttributeCount();
+ bool HasAttribute(const CefString& name);
+ CefString GetAttributeValue(const CefString& name);
+ bool SetAttributeValue(const CefString& name, const CefString& value);
+ size_t GetAttributes(AttributeMap& attributes);
+ void ClearAttributes();
+
+ ///
+ /// Access the object's children. Each object can only have one parent so
+ /// attempting to add an object that already has a parent will fail. Removing
+ /// a child will set the child's parent to NULL. Adding a child will set the
+ /// child's parent to this object. This object's value, if any, will be
+ /// cleared if a child is added.
+ ///
+ bool HasChildren();
+ size_t GetChildCount();
+ bool HasChild(CefRefPtr<CefXmlObject> child);
+ bool AddChild(CefRefPtr<CefXmlObject> child);
+ bool RemoveChild(CefRefPtr<CefXmlObject> child);
+ size_t GetChildren(ObjectVector& children);
+ void ClearChildren();
+
+ ///
+ /// Find the first child with the specified name.
+ ///
+ CefRefPtr<CefXmlObject> FindChild(const CefString& name);
+
+ ///
+ /// Find all children with the specified name.
+ ///
+ size_t FindChildren(const CefString& name, ObjectVector& children);
+
+ private:
+ // Protect against accidental deletion of this object.
+ friend class base::RefCountedThreadSafe<CefXmlObject>;
+ ~CefXmlObject();
+
+ void SetParent(CefXmlObject* parent);
+
+ CefString name_;
+ CefXmlObject* parent_;
+ CefString value_;
+ AttributeMap attributes_;
+ ObjectVector children_;
+
+ base::Lock lock_;
+};
+
+#endif // CEF_INCLUDE_WRAPPER_CEF_XML_OBJECT_H_
diff --git a/include/wrapper/cef_zip_archive.h b/include/wrapper/cef_zip_archive.h
new file mode 100644
index 00000000..4f8d351d
--- /dev/null
+++ b/include/wrapper/cef_zip_archive.h
@@ -0,0 +1,143 @@
+// Copyright (c) 2011 Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// The contents of this file are only available to applications that link
+// against the libcef_dll_wrapper target.
+//
+
+#ifndef CEF_INCLUDE_WRAPPER_CEF_ZIP_ARCHIVE_H_
+#define CEF_INCLUDE_WRAPPER_CEF_ZIP_ARCHIVE_H_
+#pragma once
+
+#include <map>
+
+#include "include/base/cef_lock.h"
+#include "include/base/cef_ref_counted.h"
+#include "include/cef_base.h"
+
+class CefStreamReader;
+
+///
+/// Thread-safe class for accessing zip archive file contents. This class should
+/// not be used with large archive files because all data will be resident in
+/// memory at the same time. This implementation supports a restricted set of
+/// zip archive features:
+/// 1. All file names are stored and compared in lower case.
+/// 2. File ordering from the original zip archive is not maintained. This means
+/// that files from the same folder may not be located together in the file
+/// content map.
+///
+class CefZipArchive : public base::RefCountedThreadSafe<CefZipArchive> {
+ public:
+ ///
+ /// Class representing a file in the archive. Accessing the file data from
+ /// multiple threads is safe provided a reference to the File object is kept.
+ ///
+ class File : public CefBaseRefCounted {
+ public:
+ ///
+ /// Returns the read-only data contained in the file.
+ ///
+ virtual const unsigned char* GetData() const = 0;
+
+ ///
+ /// Returns the size of the data in the file.
+ ///
+ virtual size_t GetDataSize() const = 0;
+
+ ///
+ /// Returns a CefStreamReader object for streaming the contents of the file.
+ ///
+ virtual CefRefPtr<CefStreamReader> GetStreamReader() const = 0;
+ };
+
+ using FileMap = std::map<CefString, CefRefPtr<File>>;
+
+ ///
+ /// Create a new object.
+ ///
+ CefZipArchive();
+
+ CefZipArchive(const CefZipArchive&) = delete;
+ CefZipArchive& operator=(const CefZipArchive&) = delete;
+
+ ///
+ /// Load the contents of the specified zip archive stream into this object.
+ /// If the zip archive requires a password then provide it via |password|.
+ /// If |overwriteExisting| is true then any files in this object that also
+ /// exist in the specified archive will be replaced with the new files.
+ /// Returns the number of files successfully loaded.
+ ///
+ size_t Load(CefRefPtr<CefStreamReader> stream,
+ const CefString& password,
+ bool overwriteExisting);
+
+ ///
+ /// Clears the contents of this object.
+ ///
+ void Clear();
+
+ ///
+ /// Returns the number of files in the archive.
+ ///
+ size_t GetFileCount() const;
+
+ ///
+ /// Returns true if the specified file exists and has contents.
+ ///
+ bool HasFile(const CefString& fileName) const;
+
+ ///
+ /// Returns the specified file.
+ ///
+ CefRefPtr<File> GetFile(const CefString& fileName) const;
+
+ ///
+ /// Removes the specified file.
+ ///
+ bool RemoveFile(const CefString& fileName);
+
+ ///
+ /// Returns the map of all files.
+ ///
+ size_t GetFiles(FileMap& map) const;
+
+ private:
+ // Protect against accidental deletion of this object.
+ friend class base::RefCountedThreadSafe<CefZipArchive>;
+ ~CefZipArchive();
+
+ FileMap contents_;
+
+ mutable base::Lock lock_;
+};
+
+#endif // CEF_INCLUDE_WRAPPER_CEF_ZIP_ARCHIVE_H_
diff --git a/libcef/browser/alloy/alloy_browser_context.cc b/libcef/browser/alloy/alloy_browser_context.cc
new file mode 100644
index 00000000..ca4ccd05
--- /dev/null
+++ b/libcef/browser/alloy/alloy_browser_context.cc
@@ -0,0 +1,486 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/alloy/alloy_browser_context.h"
+
+#include <map>
+#include <utility>
+
+#include "libcef/browser/download_manager_delegate.h"
+#include "libcef/browser/extensions/extension_system.h"
+#include "libcef/browser/prefs/browser_prefs.h"
+#include "libcef/browser/ssl_host_state_delegate.h"
+#include "libcef/browser/thread_util.h"
+#include "libcef/common/cef_switches.h"
+#include "libcef/common/extensions/extensions_util.h"
+
+#include "base/command_line.h"
+#include "base/files/file_util.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+#include "chrome/browser/font_family_cache.h"
+#include "chrome/browser/media/media_device_id_salt.h"
+#include "chrome/browser/permissions/permission_manager_factory.h"
+#include "chrome/browser/plugins/chrome_plugin_service_filter.h"
+#include "chrome/browser/profiles/profile_key.h"
+#include "chrome/browser/reduce_accept_language/reduce_accept_language_factory.h"
+#include "chrome/browser/ui/zoom/chrome_zoom_level_prefs.h"
+#include "chrome/common/pref_names.h"
+#include "components/guest_view/browser/guest_view_manager.h"
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "components/keyed_service/core/simple_dependency_manager.h"
+#include "components/keyed_service/core/simple_key_map.h"
+#include "components/permissions/permission_manager.h"
+#include "components/prefs/pref_service.h"
+#include "components/proxy_config/pref_proxy_config_tracker_impl.h"
+#include "components/user_prefs/user_prefs.h"
+#include "components/visitedlink/browser/visitedlink_event_listener.h"
+#include "components/visitedlink/browser/visitedlink_writer.h"
+#include "components/zoom/zoom_event_manager.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/download_manager.h"
+#include "content/public/browser/resource_context.h"
+#include "content/public/browser/storage_partition.h"
+#include "extensions/browser/extension_protocols.h"
+#include "extensions/browser/process_manager.h"
+#include "extensions/common/constants.h"
+#include "net/proxy_resolution/proxy_config_service.h"
+#include "services/network/public/mojom/cors_origin_pattern.mojom.h"
+
+using content::BrowserThread;
+
+// Creates and manages VisitedLinkEventListener objects for each
+// AlloyBrowserContext sharing the same VisitedLinkWriter.
+class CefVisitedLinkListener : public visitedlink::VisitedLinkWriter::Listener {
+ public:
+ CefVisitedLinkListener() { DCHECK(listener_map_.empty()); }
+
+ CefVisitedLinkListener(const CefVisitedLinkListener&) = delete;
+ CefVisitedLinkListener& operator=(const CefVisitedLinkListener&) = delete;
+
+ void CreateListenerForContext(content::BrowserContext* context) {
+ CEF_REQUIRE_UIT();
+ auto listener =
+ std::make_unique<visitedlink::VisitedLinkEventListener>(context);
+ listener_map_.insert(std::make_pair(context, std::move(listener)));
+ }
+
+ void RemoveListenerForContext(content::BrowserContext* context) {
+ CEF_REQUIRE_UIT();
+ ListenerMap::iterator it = listener_map_.find(context);
+ DCHECK(it != listener_map_.end());
+ listener_map_.erase(it);
+ }
+
+ // visitedlink::VisitedLinkWriter::Listener methods.
+
+ void NewTable(base::ReadOnlySharedMemoryRegion* table_region) override {
+ CEF_REQUIRE_UIT();
+ ListenerMap::iterator it = listener_map_.begin();
+ for (; it != listener_map_.end(); ++it) {
+ it->second->NewTable(table_region);
+ }
+ }
+
+ void Add(visitedlink::VisitedLinkCommon::Fingerprint fingerprint) override {
+ CEF_REQUIRE_UIT();
+ ListenerMap::iterator it = listener_map_.begin();
+ for (; it != listener_map_.end(); ++it) {
+ it->second->Add(fingerprint);
+ }
+ }
+
+ void Reset(bool invalidate_hashes) override {
+ CEF_REQUIRE_UIT();
+ ListenerMap::iterator it = listener_map_.begin();
+ for (; it != listener_map_.end(); ++it) {
+ it->second->Reset(invalidate_hashes);
+ }
+ }
+
+ private:
+ // Map of AlloyBrowserContext to the associated VisitedLinkEventListener.
+ using ListenerMap =
+ std::map<const content::BrowserContext*,
+ std::unique_ptr<visitedlink::VisitedLinkEventListener>>;
+ ListenerMap listener_map_;
+};
+
+AlloyBrowserContext::AlloyBrowserContext(
+ const CefRequestContextSettings& settings)
+ : CefBrowserContext(settings) {}
+
+AlloyBrowserContext::~AlloyBrowserContext() {
+ if (resource_context_) {
+ content::BrowserThread::DeleteSoon(content::BrowserThread::IO, FROM_HERE,
+ resource_context_.release());
+ }
+}
+
+bool AlloyBrowserContext::IsInitialized() const {
+ CEF_REQUIRE_UIT();
+ return !!key_;
+}
+
+void AlloyBrowserContext::StoreOrTriggerInitCallback(
+ base::OnceClosure callback) {
+ CEF_REQUIRE_UIT();
+ // Initialization is always synchronous.
+ std::move(callback).Run();
+}
+
+void AlloyBrowserContext::Initialize() {
+ CefBrowserContext::Initialize();
+
+ key_ = std::make_unique<ProfileKey>(cache_path_);
+ SimpleKeyMap::GetInstance()->Associate(this, key_.get());
+
+ // Initialize the PrefService object.
+ pref_service_ = browser_prefs::CreatePrefService(
+ this, cache_path_, !!settings_.persist_user_preferences);
+
+ // This must be called before creating any services to avoid hitting
+ // DependencyManager::AssertContextWasntDestroyed when creating/destroying
+ // multiple browser contexts (due to pointer address reuse).
+ BrowserContextDependencyManager::GetInstance()->CreateBrowserContextServices(
+ this);
+
+ const bool extensions_enabled = extensions::ExtensionsEnabled();
+ if (extensions_enabled) {
+ // Create the custom ExtensionSystem first because other KeyedServices
+ // depend on it.
+ extension_system_ = static_cast<extensions::CefExtensionSystem*>(
+ extensions::ExtensionSystem::Get(this));
+ extension_system_->InitForRegularProfile(true);
+
+ // Make sure the ProcessManager is created so that it receives extension
+ // load notifications. This is necessary for the proper initialization of
+ // background/event pages.
+ extensions::ProcessManager::Get(this);
+ }
+
+ // Initialize visited links management.
+ base::FilePath visited_link_path;
+ if (!cache_path_.empty()) {
+ visited_link_path = cache_path_.Append(FILE_PATH_LITERAL("Visited Links"));
+ }
+ visitedlink_listener_ = new CefVisitedLinkListener;
+ visitedlink_master_.reset(new visitedlink::VisitedLinkWriter(
+ visitedlink_listener_, this, !visited_link_path.empty(), false,
+ visited_link_path, 0));
+ visitedlink_listener_->CreateListenerForContext(this);
+ visitedlink_master_->Init();
+
+ // Initialize proxy configuration tracker.
+ pref_proxy_config_tracker_.reset(new PrefProxyConfigTrackerImpl(
+ GetPrefs(), content::GetIOThreadTaskRunner({})));
+
+ // Spell checking support and possibly other subsystems retrieve the
+ // PrefService associated with a BrowserContext via UserPrefs::Get().
+ PrefService* pref_service = GetPrefs();
+ DCHECK(pref_service);
+ user_prefs::UserPrefs::Set(this, pref_service);
+ key_->SetPrefs(pref_service);
+
+ if (extensions_enabled) {
+ extension_system_->Init();
+ }
+
+ ChromePluginServiceFilter::GetInstance()->RegisterProfile(this);
+
+ media_device_id_salt_ = new MediaDeviceIDSalt(pref_service);
+}
+
+void AlloyBrowserContext::Shutdown() {
+ CefBrowserContext::Shutdown();
+
+ // Send notifications to clean up objects associated with this Profile.
+ MaybeSendDestroyedNotification();
+
+ ChromePluginServiceFilter::GetInstance()->UnregisterProfile(this);
+
+ // Remove any BrowserContextKeyedServiceFactory associations. This must be
+ // called before the ProxyService owned by AlloyBrowserContext is destroyed.
+ // The SimpleDependencyManager should always be passed after the
+ // BrowserContextDependencyManager. This is because the KeyedService instances
+ // in the BrowserContextDependencyManager's dependency graph can depend on the
+ // ones in the SimpleDependencyManager's graph.
+ DependencyManager::PerformInterlockedTwoPhaseShutdown(
+ BrowserContextDependencyManager::GetInstance(), this,
+ SimpleDependencyManager::GetInstance(), key_.get());
+
+ key_.reset();
+ SimpleKeyMap::GetInstance()->Dissociate(this);
+
+ // Shuts down the storage partitions associated with this browser context.
+ // This must be called before the browser context is actually destroyed
+ // and before a clean-up task for its corresponding IO thread residents
+ // (e.g. ResourceContext) is posted, so that the classes that hung on
+ // StoragePartition can have time to do necessary cleanups on IO thread.
+ ShutdownStoragePartitions();
+
+ visitedlink_listener_->RemoveListenerForContext(this);
+
+ // The FontFamilyCache references the ProxyService so delete it before the
+ // ProxyService is deleted.
+ SetUserData(&kFontFamilyCacheKey, nullptr);
+
+ pref_proxy_config_tracker_->DetachFromPrefService();
+
+ // Delete the download manager delegate here because otherwise we'll crash
+ // when it's accessed from the content::BrowserContext destructor.
+ if (download_manager_delegate_) {
+ download_manager_delegate_.reset(nullptr);
+ }
+}
+
+void AlloyBrowserContext::RemoveCefRequestContext(
+ CefRequestContextImpl* context) {
+ CEF_REQUIRE_UIT();
+
+ if (extensions::ExtensionsEnabled()) {
+ extension_system()->OnRequestContextDeleted(context);
+ }
+
+ // May result in |this| being deleted.
+ CefBrowserContext::RemoveCefRequestContext(context);
+}
+
+void AlloyBrowserContext::LoadExtension(
+ const CefString& root_directory,
+ CefRefPtr<CefDictionaryValue> manifest,
+ CefRefPtr<CefExtensionHandler> handler,
+ CefRefPtr<CefRequestContext> loader_context) {
+ if (!extensions::ExtensionsEnabled()) {
+ if (handler) {
+ handler->OnExtensionLoadFailed(ERR_ABORTED);
+ }
+ return;
+ }
+
+ if (manifest && manifest->GetSize() > 0) {
+ CefDictionaryValueImpl* value_impl =
+ static_cast<CefDictionaryValueImpl*>(manifest.get());
+ auto value = value_impl->CopyValue();
+ extension_system()->LoadExtension(std::move(value.GetDict()),
+ root_directory, false /* builtin */,
+ loader_context, handler);
+ } else {
+ extension_system()->LoadExtension(root_directory, false /* builtin */,
+ loader_context, handler);
+ }
+}
+
+bool AlloyBrowserContext::GetExtensions(std::vector<CefString>& extension_ids) {
+ if (!extensions::ExtensionsEnabled()) {
+ return false;
+ }
+
+ extensions::CefExtensionSystem::ExtensionMap extension_map =
+ extension_system()->GetExtensions();
+ extensions::CefExtensionSystem::ExtensionMap::const_iterator it =
+ extension_map.begin();
+ for (; it != extension_map.end(); ++it) {
+ extension_ids.push_back(it->second->GetIdentifier());
+ }
+
+ return true;
+}
+
+CefRefPtr<CefExtension> AlloyBrowserContext::GetExtension(
+ const CefString& extension_id) {
+ if (!extensions::ExtensionsEnabled()) {
+ return nullptr;
+ }
+
+ return extension_system()->GetExtension(extension_id);
+}
+
+bool AlloyBrowserContext::UnloadExtension(const CefString& extension_id) {
+ DCHECK(extensions::ExtensionsEnabled());
+ return extension_system()->UnloadExtension(extension_id);
+}
+
+bool AlloyBrowserContext::IsPrintPreviewSupported() const {
+ CEF_REQUIRE_UIT();
+ if (!extensions::PrintPreviewEnabled()) {
+ return false;
+ }
+
+ return !GetPrefs()->GetBoolean(prefs::kPrintPreviewDisabled);
+}
+
+content::ResourceContext* AlloyBrowserContext::GetResourceContext() {
+ if (!resource_context_) {
+ resource_context_ = std::make_unique<content::ResourceContext>();
+ }
+ return resource_context_.get();
+}
+
+content::ClientHintsControllerDelegate*
+AlloyBrowserContext::GetClientHintsControllerDelegate() {
+ return nullptr;
+}
+
+ChromeZoomLevelPrefs* AlloyBrowserContext::GetZoomLevelPrefs() {
+ return static_cast<ChromeZoomLevelPrefs*>(
+ GetStoragePartition(nullptr)->GetZoomLevelDelegate());
+}
+
+scoped_refptr<network::SharedURLLoaderFactory>
+AlloyBrowserContext::GetURLLoaderFactory() {
+ return GetDefaultStoragePartition()->GetURLLoaderFactoryForBrowserProcess();
+}
+
+base::FilePath AlloyBrowserContext::GetPath() {
+ return cache_path_;
+}
+
+base::FilePath AlloyBrowserContext::GetPath() const {
+ return cache_path_;
+}
+
+std::unique_ptr<content::ZoomLevelDelegate>
+AlloyBrowserContext::CreateZoomLevelDelegate(
+ const base::FilePath& partition_path) {
+ if (cache_path_.empty()) {
+ return std::unique_ptr<content::ZoomLevelDelegate>();
+ }
+
+ return base::WrapUnique(new ChromeZoomLevelPrefs(
+ GetPrefs(), cache_path_, partition_path,
+ zoom::ZoomEventManager::GetForBrowserContext(this)->GetWeakPtr()));
+}
+
+content::DownloadManagerDelegate*
+AlloyBrowserContext::GetDownloadManagerDelegate() {
+ if (!download_manager_delegate_) {
+ download_manager_delegate_.reset(
+ new CefDownloadManagerDelegate(GetDownloadManager()));
+ }
+ return download_manager_delegate_.get();
+}
+
+content::BrowserPluginGuestManager* AlloyBrowserContext::GetGuestManager() {
+ if (!extensions::ExtensionsEnabled()) {
+ return nullptr;
+ }
+ return guest_view::GuestViewManager::FromBrowserContext(this);
+}
+
+storage::SpecialStoragePolicy* AlloyBrowserContext::GetSpecialStoragePolicy() {
+ return nullptr;
+}
+
+content::PlatformNotificationService*
+AlloyBrowserContext::GetPlatformNotificationService() {
+ return nullptr;
+}
+
+content::PushMessagingService* AlloyBrowserContext::GetPushMessagingService() {
+ return nullptr;
+}
+
+content::StorageNotificationService*
+AlloyBrowserContext::GetStorageNotificationService() {
+ return nullptr;
+}
+
+content::SSLHostStateDelegate* AlloyBrowserContext::GetSSLHostStateDelegate() {
+ if (!ssl_host_state_delegate_) {
+ ssl_host_state_delegate_.reset(new CefSSLHostStateDelegate());
+ }
+ return ssl_host_state_delegate_.get();
+}
+
+content::PermissionControllerDelegate*
+AlloyBrowserContext::GetPermissionControllerDelegate() {
+ return PermissionManagerFactory::GetForProfile(this);
+}
+
+content::BackgroundFetchDelegate*
+AlloyBrowserContext::GetBackgroundFetchDelegate() {
+ return nullptr;
+}
+
+content::BackgroundSyncController*
+AlloyBrowserContext::GetBackgroundSyncController() {
+ return nullptr;
+}
+
+content::BrowsingDataRemoverDelegate*
+AlloyBrowserContext::GetBrowsingDataRemoverDelegate() {
+ return nullptr;
+}
+
+content::ReduceAcceptLanguageControllerDelegate*
+AlloyBrowserContext::GetReduceAcceptLanguageControllerDelegate() {
+ return ReduceAcceptLanguageFactory::GetForProfile(this);
+}
+
+std::string AlloyBrowserContext::GetMediaDeviceIDSalt() {
+ return media_device_id_salt_->GetSalt();
+}
+
+PrefService* AlloyBrowserContext::GetPrefs() {
+ return pref_service_.get();
+}
+
+const PrefService* AlloyBrowserContext::GetPrefs() const {
+ return pref_service_.get();
+}
+
+ProfileKey* AlloyBrowserContext::GetProfileKey() const {
+ DCHECK(key_);
+ return key_.get();
+}
+
+policy::SchemaRegistryService*
+AlloyBrowserContext::GetPolicySchemaRegistryService() {
+ NOTREACHED();
+ return nullptr;
+}
+
+policy::UserCloudPolicyManager*
+AlloyBrowserContext::GetUserCloudPolicyManager() {
+ NOTREACHED();
+ return nullptr;
+}
+
+policy::ProfilePolicyConnector*
+AlloyBrowserContext::GetProfilePolicyConnector() {
+ NOTREACHED();
+ return nullptr;
+}
+
+const policy::ProfilePolicyConnector*
+AlloyBrowserContext::GetProfilePolicyConnector() const {
+ NOTREACHED();
+ return nullptr;
+}
+
+bool AlloyBrowserContext::IsNewProfile() const {
+ NOTREACHED();
+ return false;
+}
+
+void AlloyBrowserContext::RebuildTable(
+ const scoped_refptr<URLEnumerator>& enumerator) {
+ // Called when visited links will not or cannot be loaded from disk.
+ enumerator->OnComplete(true);
+}
+
+DownloadPrefs* AlloyBrowserContext::GetDownloadPrefs() {
+ CEF_REQUIRE_UIT();
+ if (!download_prefs_) {
+ download_prefs_.reset(new DownloadPrefs(this));
+ }
+ return download_prefs_.get();
+}
+
+void AlloyBrowserContext::AddVisitedURLs(const std::vector<GURL>& urls) {
+ visitedlink_master_->AddURLs(urls);
+}
diff --git a/libcef/browser/alloy/alloy_browser_context.h b/libcef/browser/alloy/alloy_browser_context.h
new file mode 100644
index 00000000..f3d679da
--- /dev/null
+++ b/libcef/browser/alloy/alloy_browser_context.h
@@ -0,0 +1,152 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_ALLOY_ALLOY_BROWSER_CONTEXT_H_
+#define CEF_LIBCEF_BROWSER_ALLOY_ALLOY_BROWSER_CONTEXT_H_
+#pragma once
+
+#include "include/cef_request_context_handler.h"
+#include "libcef/browser/alloy/chrome_profile_alloy.h"
+#include "libcef/browser/browser_context.h"
+#include "libcef/browser/request_context_handler_map.h"
+
+#include "chrome/browser/download/download_prefs.h"
+#include "components/proxy_config/pref_proxy_config_tracker.h"
+#include "components/visitedlink/browser/visitedlink_delegate.h"
+
+class CefDownloadManagerDelegate;
+class CefSSLHostStateDelegate;
+class CefVisitedLinkListener;
+class MediaDeviceIDSalt;
+class PrefService;
+
+namespace extensions {
+class CefExtensionSystem;
+}
+
+namespace visitedlink {
+class VisitedLinkWriter;
+}
+
+// See CefBrowserContext documentation for usage. Only accessed on the UI thread
+// unless otherwise indicated. ChromeProfileAlloy must be the first listed base
+// class to avoid issues when casting between void* and content::BrowserContext*
+// in Chromium code.
+class AlloyBrowserContext : public ChromeProfileAlloy,
+ public CefBrowserContext,
+ public visitedlink::VisitedLinkDelegate {
+ public:
+ explicit AlloyBrowserContext(const CefRequestContextSettings& settings);
+
+ AlloyBrowserContext(const AlloyBrowserContext&) = delete;
+ AlloyBrowserContext& operator=(const AlloyBrowserContext&) = delete;
+
+ // CefBrowserContext overrides.
+ content::BrowserContext* AsBrowserContext() override { return this; }
+ Profile* AsProfile() override { return this; }
+ bool IsInitialized() const override;
+ void StoreOrTriggerInitCallback(base::OnceClosure callback) override;
+ void Initialize() override;
+ void Shutdown() override;
+ void RemoveCefRequestContext(CefRequestContextImpl* context) override;
+ void LoadExtension(const CefString& root_directory,
+ CefRefPtr<CefDictionaryValue> manifest,
+ CefRefPtr<CefExtensionHandler> handler,
+ CefRefPtr<CefRequestContext> loader_context) override;
+ bool GetExtensions(std::vector<CefString>& extension_ids) override;
+ CefRefPtr<CefExtension> GetExtension(const CefString& extension_id) override;
+ bool UnloadExtension(const CefString& extension_id) override;
+ bool IsPrintPreviewSupported() const override;
+
+ // content::BrowserContext overrides.
+ content::ResourceContext* GetResourceContext() override;
+ content::ClientHintsControllerDelegate* GetClientHintsControllerDelegate()
+ override;
+ base::FilePath GetPath() override;
+ base::FilePath GetPath() const override;
+ std::unique_ptr<content::ZoomLevelDelegate> CreateZoomLevelDelegate(
+ const base::FilePath& partition_path) override;
+ content::DownloadManagerDelegate* GetDownloadManagerDelegate() override;
+ content::BrowserPluginGuestManager* GetGuestManager() override;
+ storage::SpecialStoragePolicy* GetSpecialStoragePolicy() override;
+ content::PlatformNotificationService* GetPlatformNotificationService()
+ override;
+ content::PushMessagingService* GetPushMessagingService() override;
+ content::StorageNotificationService* GetStorageNotificationService() override;
+ content::SSLHostStateDelegate* GetSSLHostStateDelegate() override;
+ content::PermissionControllerDelegate* GetPermissionControllerDelegate()
+ override;
+ content::BackgroundFetchDelegate* GetBackgroundFetchDelegate() override;
+ content::BackgroundSyncController* GetBackgroundSyncController() override;
+ content::BrowsingDataRemoverDelegate* GetBrowsingDataRemoverDelegate()
+ override;
+ content::ReduceAcceptLanguageControllerDelegate*
+ GetReduceAcceptLanguageControllerDelegate() override;
+ std::string GetMediaDeviceIDSalt() override;
+
+ // Profile overrides.
+ ChromeZoomLevelPrefs* GetZoomLevelPrefs() override;
+ scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory() override;
+ PrefService* GetPrefs() override;
+ bool AllowsBrowserWindows() const override { return false; }
+ const PrefService* GetPrefs() const override;
+ ProfileKey* GetProfileKey() const override;
+ policy::SchemaRegistryService* GetPolicySchemaRegistryService() override;
+ policy::UserCloudPolicyManager* GetUserCloudPolicyManager() override;
+ policy::ProfilePolicyConnector* GetProfilePolicyConnector() override;
+ const policy::ProfilePolicyConnector* GetProfilePolicyConnector()
+ const override;
+ bool IsNewProfile() const override;
+
+ // Values checked in ProfileNetworkContextService::CreateNetworkContextParams
+ // when creating the NetworkContext.
+ bool ShouldRestoreOldSessionCookies() override {
+ return ShouldPersistSessionCookies();
+ }
+ bool ShouldPersistSessionCookies() const override {
+ return !!settings_.persist_session_cookies;
+ }
+
+ // visitedlink::VisitedLinkDelegate methods.
+ void RebuildTable(const scoped_refptr<URLEnumerator>& enumerator) override;
+
+ // Manages extensions.
+ extensions::CefExtensionSystem* extension_system() const {
+ return extension_system_;
+ }
+
+ // Called from AlloyBrowserHostImpl::DidFinishNavigation to update the table
+ // of visited links.
+ void AddVisitedURLs(const std::vector<GURL>& urls);
+
+ // Called from DownloadPrefs::FromBrowserContext.
+ DownloadPrefs* GetDownloadPrefs();
+
+ private:
+ ~AlloyBrowserContext() override;
+
+ std::unique_ptr<PrefService> pref_service_;
+ std::unique_ptr<PrefProxyConfigTracker> pref_proxy_config_tracker_;
+
+ std::unique_ptr<CefDownloadManagerDelegate> download_manager_delegate_;
+ std::unique_ptr<CefSSLHostStateDelegate> ssl_host_state_delegate_;
+ std::unique_ptr<visitedlink::VisitedLinkWriter> visitedlink_master_;
+ // |visitedlink_listener_| is owned by visitedlink_master_.
+ CefVisitedLinkListener* visitedlink_listener_ = nullptr;
+
+ // Owned by the KeyedService system.
+ extensions::CefExtensionSystem* extension_system_ = nullptr;
+
+ // The key to index KeyedService instances created by
+ // SimpleKeyedServiceFactory.
+ std::unique_ptr<ProfileKey> key_;
+
+ std::unique_ptr<DownloadPrefs> download_prefs_;
+
+ std::unique_ptr<content::ResourceContext> resource_context_;
+
+ scoped_refptr<MediaDeviceIDSalt> media_device_id_salt_;
+};
+
+#endif // CEF_LIBCEF_BROWSER_ALLOY_ALLOY_BROWSER_CONTEXT_H_
diff --git a/libcef/browser/alloy/alloy_browser_host_impl.cc b/libcef/browser/alloy/alloy_browser_host_impl.cc
new file mode 100644
index 00000000..a6720dee
--- /dev/null
+++ b/libcef/browser/alloy/alloy_browser_host_impl.cc
@@ -0,0 +1,1528 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors.
+// Portions copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/alloy/alloy_browser_host_impl.h"
+
+#include <string>
+#include <utility>
+
+#include "libcef/browser/alloy/alloy_browser_context.h"
+#include "libcef/browser/alloy/browser_platform_delegate_alloy.h"
+#include "libcef/browser/audio_capturer.h"
+#include "libcef/browser/browser_context.h"
+#include "libcef/browser/browser_info.h"
+#include "libcef/browser/browser_info_manager.h"
+#include "libcef/browser/browser_platform_delegate.h"
+#include "libcef/browser/context.h"
+#include "libcef/browser/devtools/devtools_manager.h"
+#include "libcef/browser/media_access_query.h"
+#include "libcef/browser/osr/osr_util.h"
+#include "libcef/browser/request_context_impl.h"
+#include "libcef/browser/thread_util.h"
+#include "libcef/common/cef_switches.h"
+#include "libcef/common/drag_data_impl.h"
+#include "libcef/common/frame_util.h"
+#include "libcef/common/net/url_util.h"
+#include "libcef/common/request_impl.h"
+#include "libcef/common/values_impl.h"
+#include "libcef/features/runtime_checks.h"
+
+#include "base/command_line.h"
+#include "base/functional/bind.h"
+#include "base/functional/callback_helpers.h"
+#include "chrome/browser/file_select_helper.h"
+#include "chrome/browser/picture_in_picture/picture_in_picture_window_manager.h"
+#include "content/browser/gpu/compositor_util.h"
+#include "content/public/browser/desktop_media_id.h"
+#include "content/public/browser/file_select_listener.h"
+#include "content/public/browser/host_zoom_map.h"
+#include "content/public/browser/keyboard_event_processing_result.h"
+#include "content/public/browser/native_web_keyboard_event.h"
+#include "content/public/browser/navigation_controller.h"
+#include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/common/url_constants.h"
+#include "extensions/common/constants.h"
+#include "extensions/common/extension.h"
+#include "net/base/net_errors.h"
+#include "ui/events/base_event_utils.h"
+
+using content::KeyboardEventProcessingResult;
+
+namespace {
+
+class ShowDevToolsHelper {
+ public:
+ ShowDevToolsHelper(CefRefPtr<AlloyBrowserHostImpl> browser,
+ const CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient> client,
+ const CefBrowserSettings& settings,
+ const CefPoint& inspect_element_at)
+ : browser_(browser),
+ window_info_(windowInfo),
+ client_(client),
+ settings_(settings),
+ inspect_element_at_(inspect_element_at) {}
+
+ CefRefPtr<AlloyBrowserHostImpl> browser_;
+ CefWindowInfo window_info_;
+ CefRefPtr<CefClient> client_;
+ CefBrowserSettings settings_;
+ CefPoint inspect_element_at_;
+};
+
+void ShowDevToolsWithHelper(ShowDevToolsHelper* helper) {
+ helper->browser_->ShowDevTools(helper->window_info_, helper->client_,
+ helper->settings_,
+ helper->inspect_element_at_);
+ delete helper;
+}
+
+static constexpr base::TimeDelta kRecentlyAudibleTimeout = base::Seconds(2);
+
+} // namespace
+
+// AlloyBrowserHostImpl static methods.
+// -----------------------------------------------------------------------------
+
+// static
+CefRefPtr<AlloyBrowserHostImpl> AlloyBrowserHostImpl::Create(
+ CefBrowserCreateParams& create_params) {
+ std::unique_ptr<CefBrowserPlatformDelegate> platform_delegate =
+ CefBrowserPlatformDelegate::Create(create_params);
+ CHECK(platform_delegate);
+
+ const bool is_devtools_popup = !!create_params.devtools_opener;
+
+ scoped_refptr<CefBrowserInfo> info =
+ CefBrowserInfoManager::GetInstance()->CreateBrowserInfo(
+ is_devtools_popup, platform_delegate->IsWindowless(),
+ create_params.extra_info);
+
+ bool own_web_contents = false;
+
+ // This call may modify |create_params|.
+ auto web_contents =
+ platform_delegate->CreateWebContents(create_params, own_web_contents);
+
+ auto request_context_impl =
+ static_cast<CefRequestContextImpl*>(create_params.request_context.get());
+
+ CefRefPtr<CefExtension> cef_extension;
+ if (create_params.extension) {
+ auto cef_browser_context = request_context_impl->GetBrowserContext();
+ cef_extension =
+ cef_browser_context->GetExtension(create_params.extension->id());
+ CHECK(cef_extension);
+ }
+
+ auto platform_delegate_ptr = platform_delegate.get();
+
+ CefRefPtr<AlloyBrowserHostImpl> browser = CreateInternal(
+ create_params.settings, create_params.client, web_contents,
+ own_web_contents, info,
+ static_cast<AlloyBrowserHostImpl*>(create_params.devtools_opener.get()),
+ is_devtools_popup, request_context_impl, std::move(platform_delegate),
+ cef_extension);
+ if (!browser) {
+ return nullptr;
+ }
+
+ GURL url = url_util::MakeGURL(create_params.url, /*fixup=*/true);
+
+ if (create_params.extension) {
+ platform_delegate_ptr->CreateExtensionHost(
+ create_params.extension, url, create_params.extension_host_type);
+ } else if (!url.is_empty()) {
+ content::OpenURLParams params(url, content::Referrer(),
+ WindowOpenDisposition::CURRENT_TAB,
+ CefFrameHostImpl::kPageTransitionExplicit,
+ /*is_renderer_initiated=*/false);
+ browser->LoadMainFrameURL(params);
+ }
+
+ return browser.get();
+}
+
+// static
+CefRefPtr<AlloyBrowserHostImpl> AlloyBrowserHostImpl::CreateInternal(
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefClient> client,
+ content::WebContents* web_contents,
+ bool own_web_contents,
+ scoped_refptr<CefBrowserInfo> browser_info,
+ CefRefPtr<AlloyBrowserHostImpl> opener,
+ bool is_devtools_popup,
+ CefRefPtr<CefRequestContextImpl> request_context,
+ std::unique_ptr<CefBrowserPlatformDelegate> platform_delegate,
+ CefRefPtr<CefExtension> extension) {
+ CEF_REQUIRE_UIT();
+ DCHECK(web_contents);
+ DCHECK(browser_info);
+ DCHECK(request_context);
+ DCHECK(platform_delegate);
+
+ // If |opener| is non-NULL it must be a popup window.
+ DCHECK(!opener.get() || browser_info->is_popup());
+
+ if (opener) {
+ if (!opener->platform_delegate_) {
+ // The opener window is being destroyed. Cancel the popup.
+ if (own_web_contents) {
+ delete web_contents;
+ }
+ return nullptr;
+ }
+
+ // Give the opener browser's platform delegate an opportunity to modify the
+ // new browser's platform delegate.
+ opener->platform_delegate_->PopupWebContentsCreated(
+ settings, client, web_contents, platform_delegate.get(),
+ is_devtools_popup);
+ }
+
+ // Take ownership of |web_contents| if |own_web_contents| is true.
+ platform_delegate->WebContentsCreated(web_contents, own_web_contents);
+
+ CefRefPtr<AlloyBrowserHostImpl> browser = new AlloyBrowserHostImpl(
+ settings, client, web_contents, browser_info, opener, request_context,
+ std::move(platform_delegate), extension);
+ browser->InitializeBrowser();
+
+ if (!browser->CreateHostWindow()) {
+ return nullptr;
+ }
+
+ // Notify that the browser has been created. These must be delivered in the
+ // expected order.
+
+ if (opener && opener->platform_delegate_) {
+ // 1. Notify the opener browser's platform delegate. With Views this will
+ // result in a call to CefBrowserViewDelegate::OnPopupBrowserViewCreated().
+ // Do this first for consistency with the Chrome runtime.
+ opener->platform_delegate_->PopupBrowserCreated(browser.get(),
+ is_devtools_popup);
+ }
+
+ // 2. Notify the browser's LifeSpanHandler. This must always be the first
+ // notification for the browser. Block navigation to avoid issues with focus
+ // changes being sent to an unbound interface.
+ {
+ auto navigation_lock = browser_info->CreateNavigationLock();
+ browser->OnAfterCreated();
+ }
+
+ // 3. Notify the platform delegate. With Views this will result in a call to
+ // CefBrowserViewDelegate::OnBrowserCreated().
+ browser->platform_delegate_->NotifyBrowserCreated();
+
+ return browser;
+}
+
+// static
+CefRefPtr<AlloyBrowserHostImpl> AlloyBrowserHostImpl::GetBrowserForHost(
+ const content::RenderViewHost* host) {
+ REQUIRE_ALLOY_RUNTIME();
+ auto browser = CefBrowserHostBase::GetBrowserForHost(host);
+ return static_cast<AlloyBrowserHostImpl*>(browser.get());
+}
+
+// static
+CefRefPtr<AlloyBrowserHostImpl> AlloyBrowserHostImpl::GetBrowserForHost(
+ const content::RenderFrameHost* host) {
+ REQUIRE_ALLOY_RUNTIME();
+ auto browser = CefBrowserHostBase::GetBrowserForHost(host);
+ return static_cast<AlloyBrowserHostImpl*>(browser.get());
+}
+
+// static
+CefRefPtr<AlloyBrowserHostImpl> AlloyBrowserHostImpl::GetBrowserForContents(
+ const content::WebContents* contents) {
+ REQUIRE_ALLOY_RUNTIME();
+ auto browser = CefBrowserHostBase::GetBrowserForContents(contents);
+ return static_cast<AlloyBrowserHostImpl*>(browser.get());
+}
+
+// static
+CefRefPtr<AlloyBrowserHostImpl> AlloyBrowserHostImpl::GetBrowserForGlobalId(
+ const content::GlobalRenderFrameHostId& global_id) {
+ REQUIRE_ALLOY_RUNTIME();
+ auto browser = CefBrowserHostBase::GetBrowserForGlobalId(global_id);
+ return static_cast<AlloyBrowserHostImpl*>(browser.get());
+}
+
+// AlloyBrowserHostImpl methods.
+// -----------------------------------------------------------------------------
+
+AlloyBrowserHostImpl::~AlloyBrowserHostImpl() {}
+
+void AlloyBrowserHostImpl::CloseBrowser(bool force_close) {
+ if (CEF_CURRENTLY_ON_UIT()) {
+ // Exit early if a close attempt is already pending and this method is
+ // called again from somewhere other than WindowDestroyed().
+ if (destruction_state_ >= DESTRUCTION_STATE_PENDING &&
+ (IsWindowless() || !window_destroyed_)) {
+ if (force_close && destruction_state_ == DESTRUCTION_STATE_PENDING) {
+ // Upgrade the destruction state.
+ destruction_state_ = DESTRUCTION_STATE_ACCEPTED;
+ }
+ return;
+ }
+
+ if (destruction_state_ < DESTRUCTION_STATE_ACCEPTED) {
+ destruction_state_ = (force_close ? DESTRUCTION_STATE_ACCEPTED
+ : DESTRUCTION_STATE_PENDING);
+ }
+
+ content::WebContents* contents = web_contents();
+ if (contents && contents->NeedToFireBeforeUnloadOrUnloadEvents()) {
+ // Will result in a call to BeforeUnloadFired() and, if the close isn't
+ // canceled, CloseContents().
+ contents->DispatchBeforeUnload(false /* auto_cancel */);
+ } else {
+ CloseContents(contents);
+ }
+ } else {
+ CEF_POST_TASK(CEF_UIT, base::BindOnce(&AlloyBrowserHostImpl::CloseBrowser,
+ this, force_close));
+ }
+}
+
+bool AlloyBrowserHostImpl::TryCloseBrowser() {
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ NOTREACHED() << "called on invalid thread";
+ return false;
+ }
+
+ // Protect against multiple requests to close while the close is pending.
+ if (destruction_state_ <= DESTRUCTION_STATE_PENDING) {
+ if (destruction_state_ == DESTRUCTION_STATE_NONE) {
+ // Request that the browser close.
+ CloseBrowser(false);
+ }
+
+ // Cancel the close.
+ return false;
+ }
+
+ // Allow the close.
+ return true;
+}
+
+CefWindowHandle AlloyBrowserHostImpl::GetWindowHandle() {
+ if (is_views_hosted_ && CEF_CURRENTLY_ON_UIT()) {
+ // Always return the most up-to-date window handle for a views-hosted
+ // browser since it may change if the view is re-parented.
+ if (platform_delegate_) {
+ return platform_delegate_->GetHostWindowHandle();
+ }
+ }
+ return host_window_handle_;
+}
+
+CefWindowHandle AlloyBrowserHostImpl::GetOpenerWindowHandle() {
+ return opener_;
+}
+
+double AlloyBrowserHostImpl::GetZoomLevel() {
+ // Verify that this method is being called on the UI thread.
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ NOTREACHED() << "called on invalid thread";
+ return 0;
+ }
+
+ if (web_contents()) {
+ return content::HostZoomMap::GetZoomLevel(web_contents());
+ }
+
+ return 0;
+}
+
+void AlloyBrowserHostImpl::SetZoomLevel(double zoomLevel) {
+ if (CEF_CURRENTLY_ON_UIT()) {
+ if (web_contents()) {
+ content::HostZoomMap::SetZoomLevel(web_contents(), zoomLevel);
+ }
+ } else {
+ CEF_POST_TASK(CEF_UIT, base::BindOnce(&AlloyBrowserHostImpl::SetZoomLevel,
+ this, zoomLevel));
+ }
+}
+
+void AlloyBrowserHostImpl::Find(const CefString& searchText,
+ bool forward,
+ bool matchCase,
+ bool findNext) {
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(CEF_UIT,
+ base::BindOnce(&AlloyBrowserHostImpl::Find, this, searchText,
+ forward, matchCase, findNext));
+ return;
+ }
+
+ if (platform_delegate_) {
+ platform_delegate_->Find(searchText, forward, matchCase, findNext);
+ }
+}
+
+void AlloyBrowserHostImpl::StopFinding(bool clearSelection) {
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(CEF_UIT, base::BindOnce(&AlloyBrowserHostImpl::StopFinding,
+ this, clearSelection));
+ return;
+ }
+
+ if (platform_delegate_) {
+ platform_delegate_->StopFinding(clearSelection);
+ }
+}
+
+void AlloyBrowserHostImpl::ShowDevTools(const CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient> client,
+ const CefBrowserSettings& settings,
+ const CefPoint& inspect_element_at) {
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ ShowDevToolsHelper* helper = new ShowDevToolsHelper(
+ this, windowInfo, client, settings, inspect_element_at);
+ CEF_POST_TASK(CEF_UIT, base::BindOnce(ShowDevToolsWithHelper, helper));
+ return;
+ }
+
+ if (!EnsureDevToolsManager()) {
+ return;
+ }
+ devtools_manager_->ShowDevTools(windowInfo, client, settings,
+ inspect_element_at);
+}
+
+void AlloyBrowserHostImpl::CloseDevTools() {
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(CEF_UIT,
+ base::BindOnce(&AlloyBrowserHostImpl::CloseDevTools, this));
+ return;
+ }
+
+ if (!devtools_manager_) {
+ return;
+ }
+ devtools_manager_->CloseDevTools();
+}
+
+bool AlloyBrowserHostImpl::HasDevTools() {
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ NOTREACHED() << "called on invalid thread";
+ return false;
+ }
+
+ if (!devtools_manager_) {
+ return false;
+ }
+ return devtools_manager_->HasDevTools();
+}
+
+void AlloyBrowserHostImpl::SetAccessibilityState(
+ cef_state_t accessibility_state) {
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(CEF_UIT,
+ base::BindOnce(&AlloyBrowserHostImpl::SetAccessibilityState,
+ this, accessibility_state));
+ return;
+ }
+
+ if (platform_delegate_) {
+ platform_delegate_->SetAccessibilityState(accessibility_state);
+ }
+}
+
+void AlloyBrowserHostImpl::SetAutoResizeEnabled(bool enabled,
+ const CefSize& min_size,
+ const CefSize& max_size) {
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(CEF_UIT,
+ base::BindOnce(&AlloyBrowserHostImpl::SetAutoResizeEnabled,
+ this, enabled, min_size, max_size));
+ return;
+ }
+
+ if (platform_delegate_) {
+ platform_delegate_->SetAutoResizeEnabled(enabled, min_size, max_size);
+ }
+}
+
+CefRefPtr<CefExtension> AlloyBrowserHostImpl::GetExtension() {
+ return extension_;
+}
+
+bool AlloyBrowserHostImpl::IsBackgroundHost() {
+ return is_background_host_;
+}
+
+bool AlloyBrowserHostImpl::IsWindowRenderingDisabled() {
+ return IsWindowless();
+}
+
+void AlloyBrowserHostImpl::WasResized() {
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(CEF_UIT,
+ base::BindOnce(&AlloyBrowserHostImpl::WasResized, this));
+ return;
+ }
+
+ if (platform_delegate_) {
+ platform_delegate_->WasResized();
+ }
+}
+
+void AlloyBrowserHostImpl::WasHidden(bool hidden) {
+ if (!IsWindowless()) {
+ NOTREACHED() << "Window rendering is not disabled";
+ return;
+ }
+
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(CEF_UIT,
+ base::BindOnce(&CefBrowserHost::WasHidden, this, hidden));
+ return;
+ }
+
+ if (platform_delegate_) {
+ platform_delegate_->WasHidden(hidden);
+ }
+}
+
+void AlloyBrowserHostImpl::NotifyScreenInfoChanged() {
+ if (!IsWindowless()) {
+ NOTREACHED() << "Window rendering is not disabled";
+ return;
+ }
+
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(
+ CEF_UIT,
+ base::BindOnce(&AlloyBrowserHostImpl::NotifyScreenInfoChanged, this));
+ return;
+ }
+
+ if (platform_delegate_) {
+ platform_delegate_->NotifyScreenInfoChanged();
+ }
+}
+
+void AlloyBrowserHostImpl::Invalidate(PaintElementType type) {
+ if (!IsWindowless()) {
+ NOTREACHED() << "Window rendering is not disabled";
+ return;
+ }
+
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(
+ CEF_UIT, base::BindOnce(&AlloyBrowserHostImpl::Invalidate, this, type));
+ return;
+ }
+
+ if (platform_delegate_) {
+ platform_delegate_->Invalidate(type);
+ }
+}
+
+void AlloyBrowserHostImpl::SendExternalBeginFrame() {
+ if (!IsWindowless()) {
+ NOTREACHED() << "Window rendering is not disabled";
+ return;
+ }
+
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(
+ CEF_UIT,
+ base::BindOnce(&AlloyBrowserHostImpl::SendExternalBeginFrame, this));
+ return;
+ }
+
+ if (platform_delegate_) {
+ platform_delegate_->SendExternalBeginFrame();
+ }
+}
+
+void AlloyBrowserHostImpl::SendTouchEvent(const CefTouchEvent& event) {
+ if (!IsWindowless()) {
+ NOTREACHED() << "Window rendering is not disabled";
+ return;
+ }
+
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(CEF_UIT, base::BindOnce(&AlloyBrowserHostImpl::SendTouchEvent,
+ this, event));
+ return;
+ }
+
+ if (platform_delegate_) {
+ platform_delegate_->SendTouchEvent(event);
+ }
+}
+
+void AlloyBrowserHostImpl::SendCaptureLostEvent() {
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(
+ CEF_UIT,
+ base::BindOnce(&AlloyBrowserHostImpl::SendCaptureLostEvent, this));
+ return;
+ }
+
+ if (platform_delegate_) {
+ platform_delegate_->SendCaptureLostEvent();
+ }
+}
+
+int AlloyBrowserHostImpl::GetWindowlessFrameRate() {
+ // Verify that this method is being called on the UI thread.
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ NOTREACHED() << "called on invalid thread";
+ return 0;
+ }
+
+ return osr_util::ClampFrameRate(settings_.windowless_frame_rate);
+}
+
+void AlloyBrowserHostImpl::SetWindowlessFrameRate(int frame_rate) {
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(CEF_UIT,
+ base::BindOnce(&AlloyBrowserHostImpl::SetWindowlessFrameRate,
+ this, frame_rate));
+ return;
+ }
+
+ settings_.windowless_frame_rate = frame_rate;
+
+ if (platform_delegate_) {
+ platform_delegate_->SetWindowlessFrameRate(frame_rate);
+ }
+}
+
+// AlloyBrowserHostImpl public methods.
+// -----------------------------------------------------------------------------
+
+bool AlloyBrowserHostImpl::IsWindowless() const {
+ return is_windowless_;
+}
+
+bool AlloyBrowserHostImpl::IsVisible() const {
+ CEF_REQUIRE_UIT();
+ if (IsWindowless() && platform_delegate_) {
+ return !platform_delegate_->IsHidden();
+ }
+ return CefBrowserHostBase::IsVisible();
+}
+
+bool AlloyBrowserHostImpl::IsPictureInPictureSupported() const {
+ // Not currently supported with OSR.
+ return !IsWindowless();
+}
+
+void AlloyBrowserHostImpl::WindowDestroyed() {
+ CEF_REQUIRE_UIT();
+ DCHECK(!window_destroyed_);
+ window_destroyed_ = true;
+ CloseBrowser(true);
+}
+
+bool AlloyBrowserHostImpl::WillBeDestroyed() const {
+ CEF_REQUIRE_UIT();
+ return destruction_state_ >= DESTRUCTION_STATE_ACCEPTED;
+}
+
+void AlloyBrowserHostImpl::DestroyBrowser() {
+ CEF_REQUIRE_UIT();
+
+ destruction_state_ = DESTRUCTION_STATE_COMPLETED;
+
+ // Notify that this browser has been destroyed. These must be delivered in
+ // the expected order.
+
+ // 1. Notify the platform delegate. With Views this will result in a call to
+ // CefBrowserViewDelegate::OnBrowserDestroyed().
+ platform_delegate_->NotifyBrowserDestroyed();
+
+ // 2. Notify the browser's LifeSpanHandler. This must always be the last
+ // notification for this browser.
+ OnBeforeClose();
+
+ // Destroy any platform constructs first.
+ if (javascript_dialog_manager_.get()) {
+ javascript_dialog_manager_->Destroy();
+ }
+ if (menu_manager_.get()) {
+ menu_manager_->Destroy();
+ }
+
+ // Notify any observers that may have state associated with this browser.
+ OnBrowserDestroyed();
+
+ // If the WebContents still exists at this point, signal destruction before
+ // browser destruction.
+ if (web_contents()) {
+ WebContentsDestroyed();
+ }
+
+ // Disassociate the platform delegate from this browser.
+ platform_delegate_->BrowserDestroyed(this);
+
+ // Delete objects created by the platform delegate that may be referenced by
+ // the WebContents.
+ file_dialog_manager_.reset(nullptr);
+ javascript_dialog_manager_.reset(nullptr);
+ menu_manager_.reset(nullptr);
+
+ // Delete the audio capturer
+ if (recently_audible_timer_) {
+ recently_audible_timer_->Stop();
+ recently_audible_timer_.reset();
+ }
+ audio_capturer_.reset(nullptr);
+
+ CefBrowserHostBase::DestroyBrowser();
+}
+
+void AlloyBrowserHostImpl::CancelContextMenu() {
+ CEF_REQUIRE_UIT();
+ if (menu_manager_) {
+ menu_manager_->CancelContextMenu();
+ }
+}
+
+bool AlloyBrowserHostImpl::MaybeAllowNavigation(
+ content::RenderFrameHost* opener,
+ bool is_guest_view,
+ const content::OpenURLParams& params) {
+ if (is_guest_view && !params.is_pdf &&
+ !params.url.SchemeIs(extensions::kExtensionScheme) &&
+ !params.url.SchemeIs(content::kChromeUIScheme)) {
+ // The PDF viewer will load the PDF extension in the guest view, and print
+ // preview will load chrome://print in the guest view. The PDF renderer
+ // used with PdfUnseasoned will set |params.is_pdf| when loading the PDF
+ // stream (see PdfNavigationThrottle::WillStartRequest). All other
+ // navigations are passed to the owner browser.
+ CEF_POST_TASK(CEF_UIT,
+ base::BindOnce(
+ base::IgnoreResult(&AlloyBrowserHostImpl::OpenURLFromTab),
+ this, nullptr, params));
+
+ return false;
+ }
+
+ return true;
+}
+
+extensions::ExtensionHost* AlloyBrowserHostImpl::GetExtensionHost() const {
+ CEF_REQUIRE_UIT();
+ DCHECK(platform_delegate_);
+ return platform_delegate_->GetExtensionHost();
+}
+
+void AlloyBrowserHostImpl::OnSetFocus(cef_focus_source_t source) {
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(CEF_UIT, base::BindOnce(&AlloyBrowserHostImpl::OnSetFocus,
+ this, source));
+ return;
+ }
+
+ if (contents_delegate_->OnSetFocus(source)) {
+ return;
+ }
+
+ if (platform_delegate_) {
+ platform_delegate_->SetFocus(true);
+ }
+}
+
+void AlloyBrowserHostImpl::EnterFullscreenModeForTab(
+ content::RenderFrameHost* requesting_frame,
+ const blink::mojom::FullscreenOptions& options) {
+ contents_delegate_->EnterFullscreenModeForTab(requesting_frame, options);
+ WasResized();
+}
+
+void AlloyBrowserHostImpl::ExitFullscreenModeForTab(
+ content::WebContents* web_contents) {
+ contents_delegate_->ExitFullscreenModeForTab(web_contents);
+ WasResized();
+}
+
+bool AlloyBrowserHostImpl::IsFullscreenForTabOrPending(
+ const content::WebContents* web_contents) {
+ return is_fullscreen_;
+}
+
+blink::mojom::DisplayMode AlloyBrowserHostImpl::GetDisplayMode(
+ const content::WebContents* web_contents) {
+ return is_fullscreen_ ? blink::mojom::DisplayMode::kFullscreen
+ : blink::mojom::DisplayMode::kBrowser;
+}
+
+void AlloyBrowserHostImpl::FindReply(content::WebContents* web_contents,
+ int request_id,
+ int number_of_matches,
+ const gfx::Rect& selection_rect,
+ int active_match_ordinal,
+ bool final_update) {
+ auto alloy_delegate =
+ static_cast<CefBrowserPlatformDelegateAlloy*>(platform_delegate());
+ if (alloy_delegate->HandleFindReply(request_id, number_of_matches,
+ selection_rect, active_match_ordinal,
+ final_update)) {
+ if (client_) {
+ if (auto handler = client_->GetFindHandler()) {
+ const auto& details = alloy_delegate->last_search_result();
+ CefRect rect(details.selection_rect().x(), details.selection_rect().y(),
+ details.selection_rect().width(),
+ details.selection_rect().height());
+ handler->OnFindResult(
+ this, details.request_id(), details.number_of_matches(), rect,
+ details.active_match_ordinal(), details.final_update());
+ }
+ }
+ }
+}
+
+void AlloyBrowserHostImpl::ImeSetComposition(
+ const CefString& text,
+ const std::vector<CefCompositionUnderline>& underlines,
+ const CefRange& replacement_range,
+ const CefRange& selection_range) {
+ if (!IsWindowless()) {
+ NOTREACHED() << "Window rendering is not disabled";
+ return;
+ }
+
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(
+ CEF_UIT,
+ base::BindOnce(&AlloyBrowserHostImpl::ImeSetComposition, this, text,
+ underlines, replacement_range, selection_range));
+ return;
+ }
+
+ if (platform_delegate_) {
+ platform_delegate_->ImeSetComposition(text, underlines, replacement_range,
+ selection_range);
+ }
+}
+
+void AlloyBrowserHostImpl::ImeCommitText(const CefString& text,
+ const CefRange& replacement_range,
+ int relative_cursor_pos) {
+ if (!IsWindowless()) {
+ NOTREACHED() << "Window rendering is not disabled";
+ return;
+ }
+
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(CEF_UIT,
+ base::BindOnce(&AlloyBrowserHostImpl::ImeCommitText, this,
+ text, replacement_range, relative_cursor_pos));
+ return;
+ }
+
+ if (platform_delegate_) {
+ platform_delegate_->ImeCommitText(text, replacement_range,
+ relative_cursor_pos);
+ }
+}
+
+void AlloyBrowserHostImpl::ImeFinishComposingText(bool keep_selection) {
+ if (!IsWindowless()) {
+ NOTREACHED() << "Window rendering is not disabled";
+ return;
+ }
+
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(CEF_UIT,
+ base::BindOnce(&AlloyBrowserHostImpl::ImeFinishComposingText,
+ this, keep_selection));
+ return;
+ }
+
+ if (platform_delegate_) {
+ platform_delegate_->ImeFinishComposingText(keep_selection);
+ }
+}
+
+void AlloyBrowserHostImpl::ImeCancelComposition() {
+ if (!IsWindowless()) {
+ NOTREACHED() << "Window rendering is not disabled";
+ return;
+ }
+
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(
+ CEF_UIT,
+ base::BindOnce(&AlloyBrowserHostImpl::ImeCancelComposition, this));
+ return;
+ }
+
+ if (platform_delegate_) {
+ platform_delegate_->ImeCancelComposition();
+ }
+}
+
+void AlloyBrowserHostImpl::DragTargetDragEnter(
+ CefRefPtr<CefDragData> drag_data,
+ const CefMouseEvent& event,
+ CefBrowserHost::DragOperationsMask allowed_ops) {
+ if (!IsWindowless()) {
+ NOTREACHED() << "Window rendering is not disabled";
+ return;
+ }
+
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(CEF_UIT,
+ base::BindOnce(&AlloyBrowserHostImpl::DragTargetDragEnter,
+ this, drag_data, event, allowed_ops));
+ return;
+ }
+
+ if (!drag_data.get()) {
+ NOTREACHED();
+ return;
+ }
+
+ if (platform_delegate_) {
+ platform_delegate_->DragTargetDragEnter(drag_data, event, allowed_ops);
+ }
+}
+
+void AlloyBrowserHostImpl::DragTargetDragOver(
+ const CefMouseEvent& event,
+ CefBrowserHost::DragOperationsMask allowed_ops) {
+ if (!IsWindowless()) {
+ NOTREACHED() << "Window rendering is not disabled";
+ return;
+ }
+
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(
+ CEF_UIT, base::BindOnce(&AlloyBrowserHostImpl::DragTargetDragOver, this,
+ event, allowed_ops));
+ return;
+ }
+
+ if (platform_delegate_) {
+ platform_delegate_->DragTargetDragOver(event, allowed_ops);
+ }
+}
+
+void AlloyBrowserHostImpl::DragTargetDragLeave() {
+ if (!IsWindowless()) {
+ NOTREACHED() << "Window rendering is not disabled";
+ return;
+ }
+
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(
+ CEF_UIT,
+ base::BindOnce(&AlloyBrowserHostImpl::DragTargetDragLeave, this));
+ return;
+ }
+
+ if (platform_delegate_) {
+ platform_delegate_->DragTargetDragLeave();
+ }
+}
+
+void AlloyBrowserHostImpl::DragTargetDrop(const CefMouseEvent& event) {
+ if (!IsWindowless()) {
+ NOTREACHED() << "Window rendering is not disabled";
+ return;
+ }
+
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(CEF_UIT, base::BindOnce(&AlloyBrowserHostImpl::DragTargetDrop,
+ this, event));
+ return;
+ }
+
+ if (platform_delegate_) {
+ platform_delegate_->DragTargetDrop(event);
+ }
+}
+
+void AlloyBrowserHostImpl::DragSourceSystemDragEnded() {
+ if (!IsWindowless()) {
+ NOTREACHED() << "Window rendering is not disabled";
+ return;
+ }
+
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(
+ CEF_UIT,
+ base::BindOnce(&AlloyBrowserHostImpl::DragSourceSystemDragEnded, this));
+ return;
+ }
+
+ if (platform_delegate_) {
+ platform_delegate_->DragSourceSystemDragEnded();
+ }
+}
+
+void AlloyBrowserHostImpl::DragSourceEndedAt(
+ int x,
+ int y,
+ CefBrowserHost::DragOperationsMask op) {
+ if (!IsWindowless()) {
+ NOTREACHED() << "Window rendering is not disabled";
+ return;
+ }
+
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(CEF_UIT,
+ base::BindOnce(&AlloyBrowserHostImpl::DragSourceEndedAt, this,
+ x, y, op));
+ return;
+ }
+
+ if (platform_delegate_) {
+ platform_delegate_->DragSourceEndedAt(x, y, op);
+ }
+}
+
+void AlloyBrowserHostImpl::SetAudioMuted(bool mute) {
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(CEF_UIT, base::BindOnce(&AlloyBrowserHostImpl::SetAudioMuted,
+ this, mute));
+ return;
+ }
+ if (!web_contents()) {
+ return;
+ }
+ web_contents()->SetAudioMuted(mute);
+}
+
+bool AlloyBrowserHostImpl::IsAudioMuted() {
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ NOTREACHED() << "called on invalid thread";
+ return false;
+ }
+ if (!web_contents()) {
+ return false;
+ }
+ return web_contents()->IsAudioMuted();
+}
+
+// content::WebContentsDelegate methods.
+// -----------------------------------------------------------------------------
+
+content::WebContents* AlloyBrowserHostImpl::OpenURLFromTab(
+ content::WebContents* source,
+ const content::OpenURLParams& params) {
+ auto target_contents = contents_delegate_->OpenURLFromTab(source, params);
+ if (target_contents) {
+ // Start a navigation in the current browser that will result in the
+ // creation of a new render process.
+ LoadMainFrameURL(params);
+ return target_contents;
+ }
+
+ // Cancel the navigation.
+ return nullptr;
+}
+
+bool AlloyBrowserHostImpl::ShouldAllowRendererInitiatedCrossProcessNavigation(
+ bool is_main_frame_navigation) {
+ return platform_delegate_->ShouldAllowRendererInitiatedCrossProcessNavigation(
+ is_main_frame_navigation);
+}
+
+void AlloyBrowserHostImpl::AddNewContents(
+ content::WebContents* source,
+ std::unique_ptr<content::WebContents> new_contents,
+ const GURL& target_url,
+ WindowOpenDisposition disposition,
+ const blink::mojom::WindowFeatures& window_features,
+ bool user_gesture,
+ bool* was_blocked) {
+ platform_delegate_->AddNewContents(source, std::move(new_contents),
+ target_url, disposition, window_features,
+ user_gesture, was_blocked);
+}
+
+void AlloyBrowserHostImpl::LoadingStateChanged(content::WebContents* source,
+ bool should_show_loading_ui) {
+ contents_delegate_->LoadingStateChanged(source, should_show_loading_ui);
+}
+
+void AlloyBrowserHostImpl::CloseContents(content::WebContents* source) {
+ CEF_REQUIRE_UIT();
+
+ if (destruction_state_ == DESTRUCTION_STATE_COMPLETED) {
+ return;
+ }
+
+ bool close_browser = true;
+
+ // If this method is called in response to something other than
+ // WindowDestroyed() ask the user if the browser should close.
+ if (client_.get() && (IsWindowless() || !window_destroyed_)) {
+ CefRefPtr<CefLifeSpanHandler> handler = client_->GetLifeSpanHandler();
+ if (handler.get()) {
+ close_browser = !handler->DoClose(this);
+ }
+ }
+
+ if (close_browser) {
+ if (destruction_state_ != DESTRUCTION_STATE_ACCEPTED) {
+ destruction_state_ = DESTRUCTION_STATE_ACCEPTED;
+ }
+
+ if (!IsWindowless() && !window_destroyed_) {
+ // A window exists so try to close it using the platform method. Will
+ // result in a call to WindowDestroyed() if/when the window is destroyed
+ // via the platform window destruction mechanism.
+ platform_delegate_->CloseHostWindow();
+ } else {
+ // Keep a reference to the browser while it's in the process of being
+ // destroyed.
+ CefRefPtr<AlloyBrowserHostImpl> browser(this);
+
+ if (source) {
+ // Try to fast shutdown the associated process.
+ source->GetPrimaryMainFrame()->GetProcess()->FastShutdownIfPossible(
+ 1, false);
+ }
+
+ // No window exists. Destroy the browser immediately. Don't call other
+ // browser methods after calling DestroyBrowser().
+ DestroyBrowser();
+ }
+ } else if (destruction_state_ != DESTRUCTION_STATE_NONE) {
+ destruction_state_ = DESTRUCTION_STATE_NONE;
+ }
+}
+
+void AlloyBrowserHostImpl::UpdateTargetURL(content::WebContents* source,
+ const GURL& url) {
+ contents_delegate_->UpdateTargetURL(source, url);
+}
+
+bool AlloyBrowserHostImpl::DidAddMessageToConsole(
+ content::WebContents* source,
+ blink::mojom::ConsoleMessageLevel level,
+ const std::u16string& message,
+ int32_t line_no,
+ const std::u16string& source_id) {
+ return contents_delegate_->DidAddMessageToConsole(source, level, message,
+ line_no, source_id);
+}
+
+void AlloyBrowserHostImpl::BeforeUnloadFired(content::WebContents* source,
+ bool proceed,
+ bool* proceed_to_fire_unload) {
+ if (destruction_state_ == DESTRUCTION_STATE_ACCEPTED || proceed) {
+ *proceed_to_fire_unload = true;
+ } else if (!proceed) {
+ *proceed_to_fire_unload = false;
+ destruction_state_ = DESTRUCTION_STATE_NONE;
+ }
+}
+
+bool AlloyBrowserHostImpl::TakeFocus(content::WebContents* source,
+ bool reverse) {
+ if (client_.get()) {
+ CefRefPtr<CefFocusHandler> handler = client_->GetFocusHandler();
+ if (handler.get()) {
+ handler->OnTakeFocus(this, !reverse);
+ }
+ }
+
+ return false;
+}
+
+void AlloyBrowserHostImpl::CanDownload(
+ const GURL& url,
+ const std::string& request_method,
+ base::OnceCallback<void(bool)> callback) {
+ contents_delegate_->CanDownload(url, request_method, std::move(callback));
+}
+
+KeyboardEventProcessingResult AlloyBrowserHostImpl::PreHandleKeyboardEvent(
+ content::WebContents* source,
+ const content::NativeWebKeyboardEvent& event) {
+ return contents_delegate_->PreHandleKeyboardEvent(source, event);
+}
+
+bool AlloyBrowserHostImpl::HandleKeyboardEvent(
+ content::WebContents* source,
+ const content::NativeWebKeyboardEvent& event) {
+ // Check to see if event should be ignored.
+ if (event.skip_in_browser) {
+ return false;
+ }
+
+ if (contents_delegate_->HandleKeyboardEvent(source, event)) {
+ return true;
+ }
+
+ if (platform_delegate_) {
+ return platform_delegate_->HandleKeyboardEvent(event);
+ }
+ return false;
+}
+
+bool AlloyBrowserHostImpl::PreHandleGestureEvent(
+ content::WebContents* source,
+ const blink::WebGestureEvent& event) {
+ return platform_delegate_->PreHandleGestureEvent(source, event);
+}
+
+bool AlloyBrowserHostImpl::CanDragEnter(content::WebContents* source,
+ const content::DropData& data,
+ blink::DragOperationsMask mask) {
+ CefRefPtr<CefDragHandler> handler;
+ if (client_) {
+ handler = client_->GetDragHandler();
+ }
+ if (handler) {
+ CefRefPtr<CefDragDataImpl> drag_data(new CefDragDataImpl(data));
+ drag_data->SetReadOnly(true);
+ if (handler->OnDragEnter(
+ this, drag_data.get(),
+ static_cast<CefDragHandler::DragOperationsMask>(mask))) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void AlloyBrowserHostImpl::GetCustomWebContentsView(
+ content::WebContents* web_contents,
+ const GURL& target_url,
+ int opener_render_process_id,
+ int opener_render_frame_id,
+ content::WebContentsView** view,
+ content::RenderViewHostDelegateView** delegate_view) {
+ CefBrowserInfoManager::GetInstance()->GetCustomWebContentsView(
+ target_url,
+ frame_util::MakeGlobalId(opener_render_process_id,
+ opener_render_frame_id),
+ view, delegate_view);
+}
+
+void AlloyBrowserHostImpl::WebContentsCreated(
+ content::WebContents* source_contents,
+ int opener_render_process_id,
+ int opener_render_frame_id,
+ const std::string& frame_name,
+ const GURL& target_url,
+ content::WebContents* new_contents) {
+ CefBrowserSettings settings;
+ CefRefPtr<CefClient> client;
+ std::unique_ptr<CefBrowserPlatformDelegate> platform_delegate;
+ CefRefPtr<CefDictionaryValue> extra_info;
+
+ CefBrowserInfoManager::GetInstance()->WebContentsCreated(
+ target_url,
+ frame_util::MakeGlobalId(opener_render_process_id,
+ opener_render_frame_id),
+ settings, client, platform_delegate, extra_info, new_contents);
+
+ scoped_refptr<CefBrowserInfo> info =
+ CefBrowserInfoManager::GetInstance()->CreatePopupBrowserInfo(
+ new_contents, platform_delegate->IsWindowless(), extra_info);
+ CHECK(info.get());
+ CHECK(info->is_popup());
+
+ CefRefPtr<AlloyBrowserHostImpl> opener =
+ GetBrowserForContents(source_contents);
+ if (!opener) {
+ return;
+ }
+
+ // Popups must share the same RequestContext as the parent.
+ CefRefPtr<CefRequestContextImpl> request_context = opener->request_context();
+ CHECK(request_context);
+
+ // We don't officially own |new_contents| until AddNewContents() is called.
+ // However, we need to install observers/delegates here.
+ CefRefPtr<AlloyBrowserHostImpl> browser =
+ CreateInternal(settings, client, new_contents, /*own_web_contents=*/false,
+ info, opener, /*is_devtools_popup=*/false, request_context,
+ std::move(platform_delegate), /*cef_extension=*/nullptr);
+}
+
+content::JavaScriptDialogManager*
+AlloyBrowserHostImpl::GetJavaScriptDialogManager(content::WebContents* source) {
+ if (!javascript_dialog_manager_) {
+ javascript_dialog_manager_.reset(new CefJavaScriptDialogManager(this));
+ }
+ return javascript_dialog_manager_.get();
+}
+
+void AlloyBrowserHostImpl::RunFileChooser(
+ content::RenderFrameHost* render_frame_host,
+ scoped_refptr<content::FileSelectListener> listener,
+ const blink::mojom::FileChooserParams& params) {
+ // This will eventually call into CefFileDialogManager.
+ FileSelectHelper::RunFileChooser(render_frame_host, std::move(listener),
+ params);
+}
+
+bool AlloyBrowserHostImpl::ShowContextMenu(
+ const content::ContextMenuParams& params) {
+ CEF_REQUIRE_UIT();
+ if (!menu_manager_.get() && platform_delegate_) {
+ menu_manager_.reset(
+ new CefMenuManager(this, platform_delegate_->CreateMenuRunner()));
+ }
+ return menu_manager_->CreateContextMenu(params);
+}
+
+void AlloyBrowserHostImpl::UpdatePreferredSize(content::WebContents* source,
+ const gfx::Size& pref_size) {
+#if BUILDFLAG(IS_WIN) || (BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC))
+ CEF_REQUIRE_UIT();
+ if (platform_delegate_) {
+ platform_delegate_->SizeTo(pref_size.width(), pref_size.height());
+ }
+#endif
+}
+
+void AlloyBrowserHostImpl::ResizeDueToAutoResize(content::WebContents* source,
+ const gfx::Size& new_size) {
+ CEF_REQUIRE_UIT();
+
+ if (client_) {
+ CefRefPtr<CefDisplayHandler> handler = client_->GetDisplayHandler();
+ if (handler && handler->OnAutoResize(
+ this, CefSize(new_size.width(), new_size.height()))) {
+ return;
+ }
+ }
+
+ UpdatePreferredSize(source, new_size);
+}
+
+void AlloyBrowserHostImpl::RequestMediaAccessPermission(
+ content::WebContents* web_contents,
+ const content::MediaStreamRequest& request,
+ content::MediaResponseCallback callback) {
+ auto returned_callback = media_access_query::RequestMediaAccessPermission(
+ this, request, std::move(callback), /*default_disallow=*/true);
+ // Callback should not be returned.
+ DCHECK(returned_callback.is_null());
+}
+
+bool AlloyBrowserHostImpl::CheckMediaAccessPermission(
+ content::RenderFrameHost* render_frame_host,
+ const GURL& security_origin,
+ blink::mojom::MediaStreamType type) {
+ return media_access_query::CheckMediaAccessPermission(this, render_frame_host,
+ security_origin, type);
+}
+
+bool AlloyBrowserHostImpl::IsNeverComposited(
+ content::WebContents* web_contents) {
+ return platform_delegate_->IsNeverComposited(web_contents);
+}
+
+content::PictureInPictureResult AlloyBrowserHostImpl::EnterPictureInPicture(
+ content::WebContents* web_contents) {
+ if (!IsPictureInPictureSupported()) {
+ return content::PictureInPictureResult::kNotSupported;
+ }
+
+ return PictureInPictureWindowManager::GetInstance()
+ ->EnterVideoPictureInPicture(web_contents);
+}
+
+void AlloyBrowserHostImpl::ExitPictureInPicture() {
+ DCHECK(IsPictureInPictureSupported());
+ PictureInPictureWindowManager::GetInstance()->ExitPictureInPicture();
+}
+
+bool AlloyBrowserHostImpl::IsBackForwardCacheSupported() {
+ // Disabled due to issue #3237.
+ return false;
+}
+
+content::PreloadingEligibility AlloyBrowserHostImpl::IsPrerender2Supported(
+ content::WebContents& web_contents) {
+ return content::PreloadingEligibility::kEligible;
+}
+
+// content::WebContentsObserver methods.
+// -----------------------------------------------------------------------------
+
+void AlloyBrowserHostImpl::DidFinishNavigation(
+ content::NavigationHandle* navigation_handle) {
+ if (web_contents()) {
+ auto cef_browser_context =
+ static_cast<AlloyBrowserContext*>(web_contents()->GetBrowserContext());
+ if (cef_browser_context) {
+ cef_browser_context->AddVisitedURLs(
+ navigation_handle->GetRedirectChain());
+ }
+ }
+}
+
+void AlloyBrowserHostImpl::OnAudioStateChanged(bool audible) {
+ if (audible) {
+ if (recently_audible_timer_) {
+ recently_audible_timer_->Stop();
+ }
+
+ StartAudioCapturer();
+ } else if (audio_capturer_) {
+ if (!recently_audible_timer_) {
+ recently_audible_timer_ = std::make_unique<base::OneShotTimer>();
+ }
+
+ // If you have a media playing that has a short quiet moment, web_contents
+ // will immediately switch to non-audible state. We don't want to stop
+ // audio stream so quickly, let's give the stream some time to resume
+ // playing.
+ recently_audible_timer_->Start(
+ FROM_HERE, kRecentlyAudibleTimeout,
+ base::BindOnce(&AlloyBrowserHostImpl::OnRecentlyAudibleTimerFired,
+ this));
+ }
+}
+
+void AlloyBrowserHostImpl::OnRecentlyAudibleTimerFired() {
+ audio_capturer_.reset();
+}
+
+void AlloyBrowserHostImpl::AccessibilityEventReceived(
+ const content::AXEventNotificationDetails& content_event_bundle) {
+ // Only needed in windowless mode.
+ if (IsWindowless()) {
+ if (!web_contents() || !platform_delegate_) {
+ return;
+ }
+
+ platform_delegate_->AccessibilityEventReceived(content_event_bundle);
+ }
+}
+
+void AlloyBrowserHostImpl::AccessibilityLocationChangesReceived(
+ const std::vector<content::AXLocationChangeNotificationDetails>& locData) {
+ // Only needed in windowless mode.
+ if (IsWindowless()) {
+ if (!web_contents() || !platform_delegate_) {
+ return;
+ }
+
+ platform_delegate_->AccessibilityLocationChangesReceived(locData);
+ }
+}
+
+void AlloyBrowserHostImpl::WebContentsDestroyed() {
+ auto wc = web_contents();
+ content::WebContentsObserver::Observe(nullptr);
+ if (platform_delegate_) {
+ platform_delegate_->WebContentsDestroyed(wc);
+ }
+}
+
+void AlloyBrowserHostImpl::StartAudioCapturer() {
+ if (!client_.get() || audio_capturer_) {
+ return;
+ }
+
+ CefRefPtr<CefAudioHandler> audio_handler = client_->GetAudioHandler();
+ if (!audio_handler.get()) {
+ return;
+ }
+
+ CefAudioParameters params;
+ params.channel_layout = CEF_CHANNEL_LAYOUT_STEREO;
+ params.sample_rate = media::AudioParameters::kAudioCDSampleRate;
+ params.frames_per_buffer = 1024;
+
+ if (!audio_handler->GetAudioParameters(this, params)) {
+ return;
+ }
+
+ audio_capturer_.reset(new CefAudioCapturer(params, this, audio_handler));
+}
+
+// AlloyBrowserHostImpl private methods.
+// -----------------------------------------------------------------------------
+
+AlloyBrowserHostImpl::AlloyBrowserHostImpl(
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefClient> client,
+ content::WebContents* web_contents,
+ scoped_refptr<CefBrowserInfo> browser_info,
+ CefRefPtr<AlloyBrowserHostImpl> opener,
+ CefRefPtr<CefRequestContextImpl> request_context,
+ std::unique_ptr<CefBrowserPlatformDelegate> platform_delegate,
+ CefRefPtr<CefExtension> extension)
+ : CefBrowserHostBase(settings,
+ client,
+ std::move(platform_delegate),
+ browser_info,
+ request_context),
+ content::WebContentsObserver(web_contents),
+ opener_(kNullWindowHandle),
+ is_windowless_(platform_delegate_->IsWindowless()),
+ extension_(extension) {
+ contents_delegate_->ObserveWebContents(web_contents);
+
+ if (opener.get() && !is_views_hosted_) {
+ // GetOpenerWindowHandle() only returns a value for non-views-hosted
+ // popup browsers.
+ opener_ = opener->GetWindowHandle();
+ }
+
+ // Associate the platform delegate with this browser.
+ platform_delegate_->BrowserCreated(this);
+
+ // Make sure RenderFrameCreated is called at least one time.
+ RenderFrameCreated(web_contents->GetPrimaryMainFrame());
+}
+
+bool AlloyBrowserHostImpl::CreateHostWindow() {
+ // |host_window_handle_| will not change after initial host creation for
+ // non-views-hosted browsers.
+ bool success = true;
+ if (!IsWindowless()) {
+ success = platform_delegate_->CreateHostWindow();
+ }
+ if (success && !is_views_hosted_) {
+ host_window_handle_ = platform_delegate_->GetHostWindowHandle();
+ }
+ return success;
+}
+
+gfx::Point AlloyBrowserHostImpl::GetScreenPoint(const gfx::Point& view,
+ bool want_dip_coords) const {
+ CEF_REQUIRE_UIT();
+ if (platform_delegate_) {
+ return platform_delegate_->GetScreenPoint(view, want_dip_coords);
+ }
+ return gfx::Point();
+}
+
+void AlloyBrowserHostImpl::StartDragging(
+ const content::DropData& drop_data,
+ blink::DragOperationsMask allowed_ops,
+ const gfx::ImageSkia& image,
+ const gfx::Vector2d& image_offset,
+ const blink::mojom::DragEventSourceInfo& event_info,
+ content::RenderWidgetHostImpl* source_rwh) {
+ if (platform_delegate_) {
+ platform_delegate_->StartDragging(drop_data, allowed_ops, image,
+ image_offset, event_info, source_rwh);
+ }
+}
+
+void AlloyBrowserHostImpl::UpdateDragCursor(
+ ui::mojom::DragOperation operation) {
+ if (platform_delegate_) {
+ platform_delegate_->UpdateDragCursor(operation);
+ }
+}
diff --git a/libcef/browser/alloy/alloy_browser_host_impl.h b/libcef/browser/alloy/alloy_browser_host_impl.h
new file mode 100644
index 00000000..6aa3bfba
--- /dev/null
+++ b/libcef/browser/alloy/alloy_browser_host_impl.h
@@ -0,0 +1,348 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors.
+// Portions copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_ALLOY_ALLOY_BROWSER_HOST_IMPL_H_
+#define CEF_LIBCEF_BROWSER_ALLOY_ALLOY_BROWSER_HOST_IMPL_H_
+#pragma once
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "include/cef_browser.h"
+#include "include/cef_client.h"
+#include "include/cef_frame.h"
+#include "libcef/browser/browser_host_base.h"
+#include "libcef/browser/browser_info.h"
+#include "libcef/browser/frame_host_impl.h"
+#include "libcef/browser/javascript_dialog_manager.h"
+#include "libcef/browser/menu_manager.h"
+#include "libcef/browser/request_context_impl.h"
+
+#include "base/synchronization/lock.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_delegate.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "extensions/common/mojom/view_type.mojom-forward.h"
+
+class CefAudioCapturer;
+class CefBrowserInfo;
+class SiteInstance;
+
+// CefBrowser implementation for the alloy runtime. Method calls are delegated
+// to the CefPlatformDelegate or the WebContents as appropriate. All methods are
+// thread-safe unless otherwise indicated.
+//
+// WebContentsDelegate: Interface for handling WebContents delegations. There is
+// a one-to-one relationship between AlloyBrowserHostImpl and WebContents
+// instances.
+//
+// WebContentsObserver: Interface for observing WebContents notifications and
+// IPC messages. There is a one-to-one relationship between WebContents and
+// RenderViewHost instances. IPC messages received by the RenderViewHost will be
+// forwarded to this WebContentsObserver implementation via WebContents. IPC
+// messages sent using AlloyBrowserHostImpl::Send() will be forwarded to the
+// RenderViewHost (after posting to the UI thread if necessary). Use
+// WebContentsObserver::routing_id() when sending IPC messages.
+class AlloyBrowserHostImpl : public CefBrowserHostBase,
+ public content::WebContentsDelegate,
+ public content::WebContentsObserver {
+ public:
+ // Used for handling the response to command messages.
+ class CommandResponseHandler : public virtual CefBaseRefCounted {
+ public:
+ virtual void OnResponse(const std::string& response) = 0;
+ };
+
+ ~AlloyBrowserHostImpl() override;
+
+ // Create a new AlloyBrowserHostImpl instance with owned WebContents.
+ static CefRefPtr<AlloyBrowserHostImpl> Create(
+ CefBrowserCreateParams& create_params);
+
+ // Returns the browser associated with the specified RenderViewHost.
+ static CefRefPtr<AlloyBrowserHostImpl> GetBrowserForHost(
+ const content::RenderViewHost* host);
+ // Returns the browser associated with the specified RenderFrameHost.
+ static CefRefPtr<AlloyBrowserHostImpl> GetBrowserForHost(
+ const content::RenderFrameHost* host);
+ // Returns the browser associated with the specified WebContents.
+ static CefRefPtr<AlloyBrowserHostImpl> GetBrowserForContents(
+ const content::WebContents* contents);
+ // Returns the browser associated with the specified global ID.
+ static CefRefPtr<AlloyBrowserHostImpl> GetBrowserForGlobalId(
+ const content::GlobalRenderFrameHostId& global_id);
+
+ // CefBrowserHost methods.
+ void CloseBrowser(bool force_close) override;
+ bool TryCloseBrowser() override;
+ CefWindowHandle GetWindowHandle() override;
+ CefWindowHandle GetOpenerWindowHandle() override;
+ double GetZoomLevel() override;
+ void SetZoomLevel(double zoomLevel) override;
+ void Find(const CefString& searchText,
+ bool forward,
+ bool matchCase,
+ bool findNext) override;
+ void StopFinding(bool clearSelection) override;
+ void ShowDevTools(const CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient> client,
+ const CefBrowserSettings& settings,
+ const CefPoint& inspect_element_at) override;
+ void CloseDevTools() override;
+ bool HasDevTools() override;
+ bool IsWindowRenderingDisabled() override;
+ void WasResized() override;
+ void WasHidden(bool hidden) override;
+ void NotifyScreenInfoChanged() override;
+ void Invalidate(PaintElementType type) override;
+ void SendExternalBeginFrame() override;
+ void SendTouchEvent(const CefTouchEvent& event) override;
+ void SendCaptureLostEvent() override;
+ int GetWindowlessFrameRate() override;
+ void SetWindowlessFrameRate(int frame_rate) override;
+ void ImeSetComposition(const CefString& text,
+ const std::vector<CefCompositionUnderline>& underlines,
+ const CefRange& replacement_range,
+ const CefRange& selection_range) override;
+ void ImeCommitText(const CefString& text,
+ const CefRange& replacement_range,
+ int relative_cursor_pos) override;
+ void ImeFinishComposingText(bool keep_selection) override;
+ void ImeCancelComposition() override;
+ void DragTargetDragEnter(CefRefPtr<CefDragData> drag_data,
+ const CefMouseEvent& event,
+ DragOperationsMask allowed_ops) override;
+ void DragTargetDragOver(const CefMouseEvent& event,
+ DragOperationsMask allowed_ops) override;
+ void DragTargetDragLeave() override;
+ void DragTargetDrop(const CefMouseEvent& event) override;
+ void DragSourceSystemDragEnded() override;
+ void DragSourceEndedAt(int x, int y, DragOperationsMask op) override;
+ void SetAudioMuted(bool mute) override;
+ bool IsAudioMuted() override;
+ void SetAccessibilityState(cef_state_t accessibility_state) override;
+ void SetAutoResizeEnabled(bool enabled,
+ const CefSize& min_size,
+ const CefSize& max_size) override;
+ CefRefPtr<CefExtension> GetExtension() override;
+ bool IsBackgroundHost() override;
+
+ // Returns true if windowless rendering is enabled.
+ bool IsWindowless() const override;
+
+ bool IsVisible() const override;
+
+ // Returns true if this browser supports picture-in-picture.
+ bool IsPictureInPictureSupported() const;
+
+ // Called when the OS window hosting the browser is destroyed.
+ void WindowDestroyed() override;
+
+ bool WillBeDestroyed() const override;
+
+ // Destroy the browser members. This method should only be called after the
+ // native browser window is not longer processing messages.
+ void DestroyBrowser() override;
+
+ // Cancel display of the context menu, if any.
+ void CancelContextMenu();
+
+ bool MaybeAllowNavigation(content::RenderFrameHost* opener,
+ bool is_guest_view,
+ const content::OpenURLParams& params) override;
+
+ // Convert from view DIP coordinates to screen coordinates. If
+ // |want_dip_coords| is true return DIP instead of device (pixel) coordinates
+ // on Windows/Linux.
+ gfx::Point GetScreenPoint(const gfx::Point& view, bool want_dip_coords) const;
+
+ void StartDragging(const content::DropData& drop_data,
+ blink::DragOperationsMask allowed_ops,
+ const gfx::ImageSkia& image,
+ const gfx::Vector2d& image_offset,
+ const blink::mojom::DragEventSourceInfo& event_info,
+ content::RenderWidgetHostImpl* source_rwh);
+ void UpdateDragCursor(ui::mojom::DragOperation operation);
+
+ // Accessors that must be called on the UI thread.
+ extensions::ExtensionHost* GetExtensionHost() const;
+
+ void OnSetFocus(cef_focus_source_t source) override;
+
+ bool ShowContextMenu(const content::ContextMenuParams& params);
+
+ enum DestructionState {
+ DESTRUCTION_STATE_NONE = 0,
+ DESTRUCTION_STATE_PENDING,
+ DESTRUCTION_STATE_ACCEPTED,
+ DESTRUCTION_STATE_COMPLETED
+ };
+ DestructionState destruction_state() const { return destruction_state_; }
+
+ // content::WebContentsDelegate methods.
+ content::WebContents* OpenURLFromTab(
+ content::WebContents* source,
+ const content::OpenURLParams& params) override;
+ bool ShouldAllowRendererInitiatedCrossProcessNavigation(
+ bool is_main_frame_navigation) override;
+ void AddNewContents(content::WebContents* source,
+ std::unique_ptr<content::WebContents> new_contents,
+ const GURL& target_url,
+ WindowOpenDisposition disposition,
+ const blink::mojom::WindowFeatures& window_features,
+ bool user_gesture,
+ bool* was_blocked) override;
+ void LoadingStateChanged(content::WebContents* source,
+ bool should_show_loading_ui) override;
+ void CloseContents(content::WebContents* source) override;
+ void UpdateTargetURL(content::WebContents* source, const GURL& url) override;
+ bool DidAddMessageToConsole(content::WebContents* source,
+ blink::mojom::ConsoleMessageLevel log_level,
+ const std::u16string& message,
+ int32_t line_no,
+ const std::u16string& source_id) override;
+ void BeforeUnloadFired(content::WebContents* source,
+ bool proceed,
+ bool* proceed_to_fire_unload) override;
+ bool TakeFocus(content::WebContents* source, bool reverse) override;
+ void CanDownload(const GURL& url,
+ const std::string& request_method,
+ base::OnceCallback<void(bool)> callback) override;
+ content::KeyboardEventProcessingResult PreHandleKeyboardEvent(
+ content::WebContents* source,
+ const content::NativeWebKeyboardEvent& event) override;
+ bool HandleKeyboardEvent(
+ content::WebContents* source,
+ const content::NativeWebKeyboardEvent& event) override;
+ bool PreHandleGestureEvent(content::WebContents* source,
+ const blink::WebGestureEvent& event) override;
+ bool CanDragEnter(content::WebContents* source,
+ const content::DropData& data,
+ blink::DragOperationsMask operations_allowed) override;
+ void GetCustomWebContentsView(
+ content::WebContents* web_contents,
+ const GURL& target_url,
+ int opener_render_process_id,
+ int opener_render_frame_id,
+ content::WebContentsView** view,
+ content::RenderViewHostDelegateView** delegate_view) override;
+ void WebContentsCreated(content::WebContents* source_contents,
+ int opener_render_process_id,
+ int opener_render_frame_id,
+ const std::string& frame_name,
+ const GURL& target_url,
+ content::WebContents* new_contents) override;
+ content::JavaScriptDialogManager* GetJavaScriptDialogManager(
+ content::WebContents* source) override;
+ void RunFileChooser(content::RenderFrameHost* render_frame_host,
+ scoped_refptr<content::FileSelectListener> listener,
+ const blink::mojom::FileChooserParams& params) override;
+ void EnterFullscreenModeForTab(
+ content::RenderFrameHost* requesting_frame,
+ const blink::mojom::FullscreenOptions& options) override;
+ void ExitFullscreenModeForTab(content::WebContents* web_contents) override;
+ bool IsFullscreenForTabOrPending(
+ const content::WebContents* web_contents) override;
+ blink::mojom::DisplayMode GetDisplayMode(
+ const content::WebContents* web_contents) override;
+ void FindReply(content::WebContents* web_contents,
+ int request_id,
+ int number_of_matches,
+ const gfx::Rect& selection_rect,
+ int active_match_ordinal,
+ bool final_update) override;
+ void UpdatePreferredSize(content::WebContents* source,
+ const gfx::Size& pref_size) override;
+ void ResizeDueToAutoResize(content::WebContents* source,
+ const gfx::Size& new_size) override;
+ void RequestMediaAccessPermission(
+ content::WebContents* web_contents,
+ const content::MediaStreamRequest& request,
+ content::MediaResponseCallback callback) override;
+ bool CheckMediaAccessPermission(content::RenderFrameHost* render_frame_host,
+ const GURL& security_origin,
+ blink::mojom::MediaStreamType type) override;
+ bool IsNeverComposited(content::WebContents* web_contents) override;
+ content::PictureInPictureResult EnterPictureInPicture(
+ content::WebContents* web_contents) override;
+ void ExitPictureInPicture() override;
+ bool IsBackForwardCacheSupported() override;
+ content::PreloadingEligibility IsPrerender2Supported(
+ content::WebContents& web_contents) override;
+
+ // content::WebContentsObserver methods.
+ using content::WebContentsObserver::BeforeUnloadFired;
+ void DidFinishNavigation(
+ content::NavigationHandle* navigation_handle) override;
+ void OnAudioStateChanged(bool audible) override;
+ void AccessibilityEventReceived(
+ const content::AXEventNotificationDetails& content_event_bundle) override;
+ void AccessibilityLocationChangesReceived(
+ const std::vector<content::AXLocationChangeNotificationDetails>& locData)
+ override;
+ void WebContentsDestroyed() override;
+
+ private:
+ friend class CefBrowserPlatformDelegateAlloy;
+
+ static CefRefPtr<AlloyBrowserHostImpl> CreateInternal(
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefClient> client,
+ content::WebContents* web_contents,
+ bool own_web_contents,
+ scoped_refptr<CefBrowserInfo> browser_info,
+ CefRefPtr<AlloyBrowserHostImpl> opener,
+ bool is_devtools_popup,
+ CefRefPtr<CefRequestContextImpl> request_context,
+ std::unique_ptr<CefBrowserPlatformDelegate> platform_delegate,
+ CefRefPtr<CefExtension> extension);
+
+ AlloyBrowserHostImpl(
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefClient> client,
+ content::WebContents* web_contents,
+ scoped_refptr<CefBrowserInfo> browser_info,
+ CefRefPtr<AlloyBrowserHostImpl> opener,
+ CefRefPtr<CefRequestContextImpl> request_context,
+ std::unique_ptr<CefBrowserPlatformDelegate> platform_delegate,
+ CefRefPtr<CefExtension> extension);
+
+ // Give the platform delegate an opportunity to create the host window.
+ bool CreateHostWindow();
+
+ void StartAudioCapturer();
+ void OnRecentlyAudibleTimerFired();
+
+ CefWindowHandle opener_;
+ const bool is_windowless_;
+ CefWindowHandle host_window_handle_ = kNullWindowHandle;
+ CefRefPtr<CefExtension> extension_;
+ bool is_background_host_ = false;
+
+ // Represents the current browser destruction state. Only accessed on the UI
+ // thread.
+ DestructionState destruction_state_ = DESTRUCTION_STATE_NONE;
+
+ // True if the OS window hosting the browser has been destroyed. Only accessed
+ // on the UI thread.
+ bool window_destroyed_ = false;
+
+ // Used for creating and managing JavaScript dialogs.
+ std::unique_ptr<CefJavaScriptDialogManager> javascript_dialog_manager_;
+
+ // Used for creating and managing context menus.
+ std::unique_ptr<CefMenuManager> menu_manager_;
+
+ // Used for capturing audio for CefAudioHandler.
+ std::unique_ptr<CefAudioCapturer> audio_capturer_;
+
+ // Timer for determining when "recently audible" transitions to false. This
+ // starts running when a tab stops being audible, and is canceled if it starts
+ // being audible again before it fires.
+ std::unique_ptr<base::OneShotTimer> recently_audible_timer_;
+};
+
+#endif // CEF_LIBCEF_BROWSER_ALLOY_ALLOY_BROWSER_HOST_IMPL_H_
diff --git a/libcef/browser/alloy/alloy_browser_main.cc b/libcef/browser/alloy/alloy_browser_main.cc
new file mode 100644
index 00000000..ea51ed45
--- /dev/null
+++ b/libcef/browser/alloy/alloy_browser_main.cc
@@ -0,0 +1,350 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/alloy/alloy_browser_main.h"
+
+#include <stdint.h>
+
+#include <string>
+
+#include "libcef/browser/alloy/dialogs/alloy_constrained_window_views_client.h"
+#include "libcef/browser/browser_context.h"
+#include "libcef/browser/browser_context_keyed_service_factories.h"
+#include "libcef/browser/context.h"
+#include "libcef/browser/devtools/devtools_manager_delegate.h"
+#include "libcef/browser/extensions/extension_system_factory.h"
+#include "libcef/browser/file_dialog_runner.h"
+#include "libcef/browser/net/chrome_scheme_handler.h"
+#include "libcef/browser/permission_prompt.h"
+#include "libcef/browser/thread_util.h"
+#include "libcef/common/app_manager.h"
+#include "libcef/common/extensions/extensions_util.h"
+#include "libcef/common/net/net_resource_provider.h"
+
+#include "base/feature_list.h"
+#include "base/functional/bind.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/task/thread_pool.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/media/router/chrome_media_router_factory.h"
+#include "chrome/browser/net/system_network_context_manager.h"
+#include "chrome/browser/ui/javascript_dialogs/chrome_javascript_app_modal_dialog_view_factory.h"
+#include "chrome/browser/ui/ui_features.h"
+#include "chrome/common/chrome_switches.h"
+#include "components/constrained_window/constrained_window_views.h"
+#include "content/public/browser/gpu_data_manager.h"
+#include "content/public/browser/network_service_instance.h"
+#include "content/public/common/result_codes.h"
+#include "extensions/browser/extensions_browser_client.h"
+#include "extensions/common/constants.h"
+#include "net/base/net_module.h"
+#include "third_party/widevine/cdm/buildflags.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/native_theme/native_theme.h"
+
+#if BUILDFLAG(IS_LINUX)
+#include "ui/ozone/buildflags.h"
+#if defined(USE_AURA) && BUILDFLAG(OZONE_PLATFORM_X11)
+#include "ui/events/devices/x11/touch_factory_x11.h"
+#endif
+#endif
+
+#if defined(USE_AURA)
+#include "ui/aura/env.h"
+#include "ui/views/widget/desktop_aura/desktop_screen.h"
+#include "ui/wm/core/wm_state.h"
+
+#if BUILDFLAG(IS_WIN)
+#include "base/enterprise_util.h"
+#include "chrome/browser/chrome_browser_main_win.h"
+#include "chrome/browser/win/parental_controls.h"
+#endif
+#endif // defined(USE_AURA)
+
+#if BUILDFLAG(IS_MAC)
+#include "chrome/browser/ui/views/chrome_layout_provider.h"
+#include "chrome/browser/ui/views/chrome_views_delegate.h"
+#else
+#include "ui/views/test/desktop_test_views_delegate.h"
+#endif
+
+#if defined(USE_AURA) && BUILDFLAG(IS_LINUX)
+#include "ui/base/ime/init/input_method_initializer.h"
+#endif
+
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX)
+#include "components/os_crypt/os_crypt.h"
+#endif
+
+#if BUILDFLAG(IS_LINUX)
+#include "base/path_service.h"
+#include "chrome/browser/themes/theme_service_aura_linux.h"
+#include "chrome/browser/ui/views/theme_profile_key.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/grit/chromium_strings.h"
+#include "components/os_crypt/key_storage_config_linux.h"
+#include "libcef/browser/printing/print_dialog_linux.h"
+#include "ui/base/cursor/cursor_factory.h"
+#include "ui/base/ime/input_method.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/linux/linux_ui.h"
+#include "ui/linux/linux_ui_delegate.h"
+#include "ui/linux/linux_ui_factory.h"
+#include "ui/linux/linux_ui_getter.h"
+#include "ui/ozone/public/ozone_platform.h"
+#endif // BUILDFLAG(IS_LINUX)
+
+#if BUILDFLAG(ENABLE_MEDIA_FOUNDATION_WIDEVINE_CDM)
+#include "chrome/browser/component_updater/media_foundation_widevine_cdm_component_installer.h"
+#endif
+
+#if BUILDFLAG(ENABLE_WIDEVINE_CDM_COMPONENT)
+#include "chrome/browser/component_updater/widevine_cdm_component_installer.h"
+#endif
+
+namespace {
+
+#if BUILDFLAG(IS_LINUX)
+
+class LinuxUiGetterImpl : public ui::LinuxUiGetter {
+ public:
+ LinuxUiGetterImpl() = default;
+ ~LinuxUiGetterImpl() override = default;
+ ui::LinuxUiTheme* GetForWindow(aura::Window* window) override {
+ return window ? GetForProfile(GetThemeProfileForWindow(window)) : nullptr;
+ }
+ ui::LinuxUiTheme* GetForProfile(Profile* profile) override {
+ return ui::GetLinuxUiTheme(
+ ThemeServiceAuraLinux::GetSystemThemeForProfile(profile));
+ }
+};
+
+ui::LinuxUi* GetLinuxUI() {
+ // We can't use GtkUi in combination with multi-threaded-message-loop because
+ // Chromium's GTK implementation doesn't use GDK threads.
+ if (!!CefContext::Get()->settings().multi_threaded_message_loop) {
+ return nullptr;
+ }
+
+ // If the ozone backend hasn't provided a LinuxUiDelegate, don't try to create
+ // a LinuxUi instance as this may result in a crash in toolkit initialization.
+ if (!ui::LinuxUiDelegate::GetInstance()) {
+ return nullptr;
+ }
+
+ return ui::GetDefaultLinuxUi();
+}
+
+#endif // BUILDFLAG(IS_LINUX)
+
+} // namespace
+
+AlloyBrowserMainParts::AlloyBrowserMainParts() = default;
+
+AlloyBrowserMainParts::~AlloyBrowserMainParts() {
+ constrained_window::SetConstrainedWindowViewsClient(nullptr);
+}
+
+void AlloyBrowserMainParts::ToolkitInitialized() {
+ SetConstrainedWindowViewsClient(CreateAlloyConstrainedWindowViewsClient());
+#if defined(USE_AURA)
+ CHECK(aura::Env::GetInstance());
+
+ wm_state_.reset(new wm::WMState);
+#endif // defined(USE_AURA)
+
+#if BUILDFLAG(IS_MAC)
+ views_delegate_ = std::make_unique<ChromeViewsDelegate>();
+ layout_provider_ = ChromeLayoutProvider::CreateLayoutProvider();
+#else
+ views_delegate_ = std::make_unique<views::DesktopTestViewsDelegate>();
+#endif
+
+#if BUILDFLAG(IS_LINUX)
+ // Based on chrome_browser_main_extra_parts_views_linux.cc
+ if (auto linux_ui = GetLinuxUI()) {
+ linux_ui_getter_ = std::make_unique<LinuxUiGetterImpl>();
+ ui::LinuxUi::SetInstance(linux_ui);
+
+ // Cursor theme changes are tracked by LinuxUI (via a CursorThemeManager
+ // implementation). Start observing them once it's initialized.
+ ui::CursorFactory::GetInstance()->ObserveThemeChanges();
+ }
+
+ auto printing_delegate = new CefPrintingContextLinuxDelegate();
+ auto default_delegate =
+ ui::PrintingContextLinuxDelegate::SetInstance(printing_delegate);
+ printing_delegate->SetDefaultDelegate(default_delegate);
+#endif // BUILDFLAG(IS_LINUX)
+
+#if BUILDFLAG(IS_MAC)
+ if (base::FeatureList::IsEnabled(features::kViewsJSAppModalDialog)) {
+ InstallChromeJavaScriptAppModalDialogViewFactory();
+ } else {
+ InstallChromeJavaScriptAppModalDialogViewCocoaFactory();
+ }
+#else
+ InstallChromeJavaScriptAppModalDialogViewFactory();
+#endif
+}
+
+void AlloyBrowserMainParts::PreCreateMainMessageLoop() {
+#if BUILDFLAG(IS_LINUX)
+#if defined(USE_AURA) && BUILDFLAG(OZONE_PLATFORM_X11)
+ ui::TouchFactory::SetTouchDeviceListFromCommandLine();
+#endif
+#endif
+
+#if BUILDFLAG(IS_WIN)
+ // Initialize the OSCrypt.
+ PrefService* local_state = g_browser_process->local_state();
+ DCHECK(local_state);
+ bool os_crypt_init = OSCrypt::Init(local_state);
+ DCHECK(os_crypt_init);
+
+ // installer_util references strings that are normally compiled into
+ // setup.exe. In Chrome, these strings are in the locale files.
+ ChromeBrowserMainPartsWin::SetupInstallerUtilStrings();
+#endif // BUILDFLAG(IS_WIN)
+
+ media_router::ChromeMediaRouterFactory::DoPlatformInit();
+}
+
+void AlloyBrowserMainParts::PostCreateMainMessageLoop() {
+#if BUILDFLAG(IS_LINUX)
+ const base::CommandLine* command_line =
+ base::CommandLine::ForCurrentProcess();
+
+ // Set up crypt config. This needs to be done before anything starts the
+ // network service, as the raw encryption key needs to be shared with the
+ // network service for encrypted cookie storage.
+ // Based on ChromeBrowserMainPartsLinux::PostCreateMainMessageLoop.
+ std::unique_ptr<os_crypt::Config> config =
+ std::make_unique<os_crypt::Config>();
+ // Forward to os_crypt the flag to use a specific password store.
+ config->store = command_line->GetSwitchValueASCII(switches::kPasswordStore);
+ // Forward the product name (defaults to "Chromium").
+ config->product_name = l10n_util::GetStringUTF8(IDS_PRODUCT_NAME);
+ // OSCrypt may target keyring, which requires calls from the main thread.
+ config->main_thread_runner = content::GetUIThreadTaskRunner({});
+ // OSCrypt can be disabled in a special settings file.
+ config->should_use_preference =
+ command_line->HasSwitch(switches::kEnableEncryptionSelection);
+ base::PathService::Get(chrome::DIR_USER_DATA, &config->user_data_path);
+ DCHECK(!config->user_data_path.empty());
+ OSCrypt::SetConfig(std::move(config));
+#endif // BUILDFLAG(IS_LINUX)
+}
+
+int AlloyBrowserMainParts::PreCreateThreads() {
+#if BUILDFLAG(IS_WIN)
+ PlatformInitialize();
+#endif
+
+ net::NetModule::SetResourceProvider(&NetResourceProvider);
+
+ // Initialize these objects before IO access restrictions are applied and
+ // before the IO thread is started.
+ content::GpuDataManager::GetInstance();
+ SystemNetworkContextManager::CreateInstance(g_browser_process->local_state());
+
+ return 0;
+}
+
+int AlloyBrowserMainParts::PreMainMessageLoopRun() {
+#if defined(USE_AURA)
+ screen_ = views::CreateDesktopScreen();
+#endif
+#if BUILDFLAG(IS_MAC)
+ screen_ = std::make_unique<display::ScopedNativeScreen>();
+#endif
+
+ if (extensions::ExtensionsEnabled()) {
+ // This should be set in ChromeBrowserProcessAlloy::Initialize.
+ DCHECK(extensions::ExtensionsBrowserClient::Get());
+ // Initialize extension global objects before creating the global
+ // BrowserContext.
+ extensions::CefExtensionSystemFactory::GetInstance();
+ }
+
+ // Register additional KeyedService factories here. See
+ // ChromeBrowserMainExtraPartsProfiles for details.
+ cef::EnsureBrowserContextKeyedServiceFactoriesBuilt();
+
+ background_task_runner_ = base::ThreadPool::CreateSingleThreadTaskRunner(
+ {base::TaskPriority::BEST_EFFORT,
+ base::TaskShutdownBehavior::BLOCK_SHUTDOWN, base::MayBlock()});
+ user_visible_task_runner_ = base::ThreadPool::CreateSingleThreadTaskRunner(
+ {base::TaskPriority::USER_VISIBLE,
+ base::TaskShutdownBehavior::BLOCK_SHUTDOWN, base::MayBlock()});
+ user_blocking_task_runner_ = base::ThreadPool::CreateSingleThreadTaskRunner(
+ {base::TaskPriority::USER_BLOCKING,
+ base::TaskShutdownBehavior::BLOCK_SHUTDOWN, base::MayBlock()});
+
+ CefRequestContextSettings settings;
+ CefContext::Get()->PopulateGlobalRequestContextSettings(&settings);
+
+ // Create the global RequestContext.
+ global_request_context_ =
+ CefRequestContextImpl::CreateGlobalRequestContext(settings);
+ auto browser_context =
+ global_request_context_->GetBrowserContext()->AsBrowserContext();
+
+ CefDevToolsManagerDelegate::StartHttpHandler(browser_context);
+
+#if BUILDFLAG(IS_WIN)
+ // Windows parental controls calls can be slow, so we do an early init here
+ // that calculates this value off of the UI thread.
+ InitializeWinParentalControls();
+
+ // These methods may call LoadLibrary and could trigger
+ // AssertBlockingAllowed() failures if executed at a later time on the UI
+ // thread.
+ base::IsManagedDevice();
+ base::IsEnterpriseDevice();
+#endif // BUILDFLAG(IS_WIN)
+
+ scheme::RegisterWebUIControllerFactory();
+ file_dialog_runner::RegisterFactory();
+ permission_prompt::RegisterCreateCallback();
+
+ // Initialize theme configuration (high contrast, dark mode, etc).
+ ui::NativeTheme::GetInstanceForNativeUi();
+
+#if BUILDFLAG(ENABLE_MEDIA_FOUNDATION_WIDEVINE_CDM) || \
+ BUILDFLAG(ENABLE_WIDEVINE_CDM_COMPONENT)
+ const base::CommandLine* command_line =
+ base::CommandLine::ForCurrentProcess();
+ if (!command_line->HasSwitch(switches::kDisableComponentUpdate)) {
+ auto* const cus = g_browser_process->component_updater();
+
+#if BUILDFLAG(ENABLE_MEDIA_FOUNDATION_WIDEVINE_CDM)
+ RegisterMediaFoundationWidevineCdmComponent(cus);
+#endif
+
+#if BUILDFLAG(ENABLE_WIDEVINE_CDM_COMPONENT)
+ RegisterWidevineCdmComponent(cus);
+#endif
+ }
+#endif
+
+ return content::RESULT_CODE_NORMAL_EXIT;
+}
+
+void AlloyBrowserMainParts::PostMainMessageLoopRun() {
+ // NOTE: Destroy objects in reverse order of creation.
+ CefDevToolsManagerDelegate::StopHttpHandler();
+
+ // There should be no additional references to the global CefRequestContext
+ // during shutdown. Did you forget to release a CefBrowser reference?
+ DCHECK(global_request_context_->HasOneRef());
+ global_request_context_ = nullptr;
+}
+
+void AlloyBrowserMainParts::PostDestroyThreads() {
+ views_delegate_.reset();
+#if BUILDFLAG(IS_MAC)
+ layout_provider_.reset();
+#endif
+}
diff --git a/libcef/browser/alloy/alloy_browser_main.h b/libcef/browser/alloy/alloy_browser_main.h
new file mode 100644
index 00000000..856d19f5
--- /dev/null
+++ b/libcef/browser/alloy/alloy_browser_main.h
@@ -0,0 +1,104 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_ALLOY_ALLOY_BROWSER_MAIN_H_
+#define CEF_LIBCEF_BROWSER_ALLOY_ALLOY_BROWSER_MAIN_H_
+#pragma once
+
+#include "libcef/browser/request_context_impl.h"
+
+#include "base/command_line.h"
+#include "base/strings/string_piece.h"
+#include "build/build_config.h"
+#include "components/prefs/pref_service.h"
+#include "content/public/browser/browser_main_parts.h"
+#include "ui/display/screen.h"
+
+#if defined(USE_AURA)
+namespace wm {
+class WMState;
+}
+#endif
+
+namespace views {
+class ViewsDelegate;
+#if BUILDFLAG(IS_MAC)
+class LayoutProvider;
+#endif
+} // namespace views
+
+#if BUILDFLAG(IS_LINUX)
+namespace ui {
+class LinuxUiGetter;
+}
+#endif
+
+class CefDevToolsDelegate;
+
+class AlloyBrowserMainParts : public content::BrowserMainParts {
+ public:
+ AlloyBrowserMainParts();
+
+ AlloyBrowserMainParts(const AlloyBrowserMainParts&) = delete;
+ AlloyBrowserMainParts& operator=(const AlloyBrowserMainParts&) = delete;
+
+ ~AlloyBrowserMainParts() override;
+
+ void ToolkitInitialized() override;
+ void PreCreateMainMessageLoop() override;
+ void PostCreateMainMessageLoop() override;
+ int PreCreateThreads() override;
+ int PreMainMessageLoopRun() override;
+ void PostMainMessageLoopRun() override;
+ void PostDestroyThreads() override;
+
+ CefRefPtr<CefRequestContextImpl> request_context() const {
+ return global_request_context_;
+ }
+ CefDevToolsDelegate* devtools_delegate() const { return devtools_delegate_; }
+
+ scoped_refptr<base::SingleThreadTaskRunner> background_task_runner() const {
+ return background_task_runner_;
+ }
+ scoped_refptr<base::SingleThreadTaskRunner> user_visible_task_runner() const {
+ return user_visible_task_runner_;
+ }
+ scoped_refptr<base::SingleThreadTaskRunner> user_blocking_task_runner()
+ const {
+ return user_blocking_task_runner_;
+ }
+
+ private:
+#if BUILDFLAG(IS_WIN)
+ void PlatformInitialize();
+#endif // BUILDFLAG(IS_WIN)
+
+ CefRefPtr<CefRequestContextImpl> global_request_context_;
+ CefDevToolsDelegate* devtools_delegate_ = nullptr; // Deletes itself.
+
+ // Blocking task runners exposed via CefTaskRunner. For consistency with
+ // previous named thread behavior always execute all pending tasks before
+ // shutdown (e.g. to make sure critical data is saved to disk).
+ // |background_task_runner_| is also passed to SQLitePersistentCookieStore.
+ scoped_refptr<base::SingleThreadTaskRunner> background_task_runner_;
+ scoped_refptr<base::SingleThreadTaskRunner> user_visible_task_runner_;
+ scoped_refptr<base::SingleThreadTaskRunner> user_blocking_task_runner_;
+
+#if defined(USE_AURA)
+ std::unique_ptr<display::Screen> screen_;
+ std::unique_ptr<wm::WMState> wm_state_;
+#endif
+
+ std::unique_ptr<views::ViewsDelegate> views_delegate_;
+#if BUILDFLAG(IS_MAC)
+ std::unique_ptr<display::ScopedNativeScreen> screen_;
+ std::unique_ptr<views::LayoutProvider> layout_provider_;
+#endif
+
+#if BUILDFLAG(IS_LINUX)
+ std::unique_ptr<ui::LinuxUiGetter> linux_ui_getter_;
+#endif
+};
+
+#endif // CEF_LIBCEF_BROWSER_ALLOY_ALLOY_BROWSER_MAIN_H_
diff --git a/libcef/browser/alloy/alloy_browser_main_win.cc b/libcef/browser/alloy/alloy_browser_main_win.cc
new file mode 100644
index 00000000..ac3cbc14
--- /dev/null
+++ b/libcef/browser/alloy/alloy_browser_main_win.cc
@@ -0,0 +1,27 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <Objbase.h>
+#include <commctrl.h>
+#include <windows.h>
+
+#include "libcef/browser/alloy/alloy_browser_main.h"
+
+#include "base/logging.h"
+
+void AlloyBrowserMainParts::PlatformInitialize() {
+ HRESULT res;
+
+ // Initialize common controls.
+ res = CoInitialize(nullptr);
+ DCHECK(SUCCEEDED(res));
+ INITCOMMONCONTROLSEX InitCtrlEx;
+ InitCtrlEx.dwSize = sizeof(INITCOMMONCONTROLSEX);
+ InitCtrlEx.dwICC = ICC_STANDARD_CLASSES;
+ InitCommonControlsEx(&InitCtrlEx);
+
+ // Start COM stuff.
+ res = OleInitialize(nullptr);
+ DCHECK(SUCCEEDED(res));
+}
diff --git a/libcef/browser/alloy/alloy_content_browser_client.cc b/libcef/browser/alloy/alloy_content_browser_client.cc
new file mode 100644
index 00000000..55711ca3
--- /dev/null
+++ b/libcef/browser/alloy/alloy_content_browser_client.cc
@@ -0,0 +1,1419 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/alloy/alloy_content_browser_client.h"
+
+#include <algorithm>
+#include <tuple>
+#include <utility>
+
+#include "include/cef_version.h"
+#include "libcef/browser/alloy/alloy_browser_context.h"
+#include "libcef/browser/alloy/alloy_browser_host_impl.h"
+#include "libcef/browser/alloy/alloy_browser_main.h"
+#include "libcef/browser/alloy/alloy_web_contents_view_delegate.h"
+#include "libcef/browser/browser_context.h"
+#include "libcef/browser/browser_frame.h"
+#include "libcef/browser/browser_info.h"
+#include "libcef/browser/browser_info_manager.h"
+#include "libcef/browser/browser_manager.h"
+#include "libcef/browser/browser_platform_delegate.h"
+#include "libcef/browser/certificate_query.h"
+#include "libcef/browser/context.h"
+#include "libcef/browser/devtools/devtools_manager_delegate.h"
+#include "libcef/browser/extensions/extension_system.h"
+#include "libcef/browser/extensions/extension_web_contents_observer.h"
+#include "libcef/browser/media_capture_devices_dispatcher.h"
+#include "libcef/browser/net/chrome_scheme_handler.h"
+#include "libcef/browser/net/throttle_handler.h"
+#include "libcef/browser/net_service/cookie_manager_impl.h"
+#include "libcef/browser/net_service/login_delegate.h"
+#include "libcef/browser/net_service/proxy_url_loader_factory.h"
+#include "libcef/browser/net_service/resource_request_handler_wrapper.h"
+#include "libcef/browser/prefs/renderer_prefs.h"
+#include "libcef/browser/speech_recognition_manager_delegate.h"
+#include "libcef/browser/thread_util.h"
+#include "libcef/browser/x509_certificate_impl.h"
+#include "libcef/common/alloy/alloy_content_client.h"
+#include "libcef/common/app_manager.h"
+#include "libcef/common/cef_switches.h"
+#include "libcef/common/command_line_impl.h"
+#include "libcef/common/extensions/extensions_util.h"
+#include "libcef/common/frame_util.h"
+#include "libcef/common/net/scheme_registration.h"
+#include "libcef/common/request_impl.h"
+
+#include "base/base_switches.h"
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/json/json_reader.h"
+#include "base/path_service.h"
+#include "base/stl_util.h"
+#include "base/threading/thread_restrictions.h"
+#include "cef/grit/cef_resources.h"
+#include "chrome/browser/accessibility/live_caption_unavailability_notifier.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/content_settings/cookie_settings_factory.h"
+#include "chrome/browser/extensions/chrome_content_browser_client_extensions_part.h"
+#include "chrome/browser/net/profile_network_context_service.h"
+#include "chrome/browser/net/profile_network_context_service_factory.h"
+#include "chrome/browser/net/system_network_context_manager.h"
+#include "chrome/browser/pdf/chrome_pdf_stream_delegate.h"
+#include "chrome/browser/plugins/pdf_iframe_navigation_throttle.h"
+#include "chrome/browser/plugins/plugin_info_host_impl.h"
+#include "chrome/browser/plugins/plugin_response_interceptor_url_loader_throttle.h"
+#include "chrome/browser/plugins/plugin_utils.h"
+#include "chrome/browser/predictors/network_hints_handler_impl.h"
+#include "chrome/browser/printing/print_view_manager.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/renderer_updater.h"
+#include "chrome/browser/profiles/renderer_updater_factory.h"
+#include "chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.h"
+#include "chrome/browser/spellchecker/spell_check_host_chrome_impl.h"
+#include "chrome/browser/ui/chrome_select_file_policy.h"
+#include "chrome/common/chrome_content_client.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/google_url_loader_throttle.h"
+#include "chrome/common/pdf_util.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/common/webui_url_constants.h"
+#include "chrome/grit/browser_resources.h"
+#include "chrome/grit/generated_resources.h"
+#include "chrome/services/printing/printing_service.h"
+#include "components/content_settings/core/browser/cookie_settings.h"
+#include "components/embedder_support/switches.h"
+#include "components/embedder_support/user_agent_utils.h"
+#include "components/pdf/browser/pdf_navigation_throttle.h"
+#include "components/pdf/browser/pdf_url_loader_request_interceptor.h"
+#include "components/pdf/browser/pdf_web_contents_helper.h"
+#include "components/pdf/common/internal_plugin_helpers.h"
+#include "components/spellcheck/common/spellcheck.mojom.h"
+#include "components/version_info/version_info.h"
+#include "content/browser/plugin_service_impl.h"
+#include "content/browser/renderer_host/render_frame_host_impl.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/browser_ppapi_host.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/client_certificate_delegate.h"
+#include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/overlay_window.h"
+#include "content/public/browser/page_navigator.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
+#include "content/public/browser/render_widget_host_view.h"
+#include "content/public/browser/storage_partition.h"
+#include "content/public/browser/web_ui_url_loader_factory.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/common/url_constants.h"
+#include "content/public/common/user_agent.h"
+#include "crypto/crypto_buildflags.h"
+#include "extensions/browser/event_router.h"
+#include "extensions/browser/extension_message_filter.h"
+#include "extensions/browser/extension_protocols.h"
+#include "extensions/browser/extension_registry.h"
+#include "extensions/browser/extension_web_contents_observer.h"
+#include "extensions/browser/extensions_browser_client.h"
+#include "extensions/browser/guest_view/extensions_guest_view.h"
+#include "extensions/browser/guest_view/web_view/web_view_guest.h"
+#include "extensions/browser/info_map.h"
+#include "extensions/browser/process_map.h"
+#include "extensions/browser/renderer_startup_helper.h"
+#include "extensions/browser/url_loader_factory_manager.h"
+#include "extensions/common/constants.h"
+#include "extensions/common/switches.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "mojo/public/cpp/bindings/self_owned_associated_receiver.h"
+#include "net/base/auth.h"
+#include "net/ssl/ssl_cert_request_info.h"
+#include "net/ssl/ssl_private_key.h"
+#include "pdf/pdf_features.h"
+#include "ppapi/host/ppapi_host.h"
+#include "sandbox/policy/switches.h"
+#include "services/network/public/cpp/network_switches.h"
+#include "services/proxy_resolver/public/mojom/proxy_resolver.mojom.h"
+#include "services/service_manager/public/mojom/connector.mojom.h"
+#include "third_party/blink/public/common/associated_interfaces/associated_interface_registry.h"
+#include "third_party/blink/public/common/web_preferences/web_preferences.h"
+#include "third_party/blink/public/mojom/badging/badging.mojom.h"
+#include "third_party/blink/public/mojom/prerender/prerender.mojom.h"
+#include "third_party/blink/public/web/web_window_features.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/base/ui_base_switches.h"
+#include "url/gurl.h"
+
+#if BUILDFLAG(IS_MAC)
+#include "net/ssl/client_cert_store_mac.h"
+#include "services/video_capture/public/mojom/constants.mojom.h"
+#elif BUILDFLAG(IS_POSIX)
+#include "components/crash/core/app/crash_switches.h"
+#include "components/crash/core/app/crashpad.h"
+#include "content/public/common/content_descriptors.h"
+#include "libcef/common/crash_reporting.h"
+#endif
+
+#if BUILDFLAG(IS_WIN)
+#include "net/ssl/client_cert_store_win.h"
+#include "sandbox/win/src/sandbox_policy.h"
+#endif
+
+#if BUILDFLAG(USE_NSS_CERTS)
+#include "net/ssl/client_cert_store_nss.h"
+#endif
+
+#if BUILDFLAG(HAS_SPELLCHECK_PANEL)
+#include "chrome/browser/spellchecker/spell_check_panel_host_impl.h"
+#endif
+
+namespace {
+
+class CefSelectClientCertificateCallbackImpl
+ : public CefSelectClientCertificateCallback {
+ public:
+ explicit CefSelectClientCertificateCallbackImpl(
+ std::unique_ptr<content::ClientCertificateDelegate> delegate)
+ : delegate_(std::move(delegate)) {}
+
+ CefSelectClientCertificateCallbackImpl(
+ const CefSelectClientCertificateCallbackImpl&) = delete;
+ CefSelectClientCertificateCallbackImpl& operator=(
+ const CefSelectClientCertificateCallbackImpl&) = delete;
+
+ ~CefSelectClientCertificateCallbackImpl() {
+ // If Select has not been called, call it with NULL to continue without any
+ // client certificate.
+ if (delegate_) {
+ DoSelect(nullptr);
+ }
+ }
+
+ void Select(CefRefPtr<CefX509Certificate> cert) override {
+ if (delegate_) {
+ DoSelect(cert);
+ }
+ }
+
+ private:
+ void DoSelect(CefRefPtr<CefX509Certificate> cert) {
+ if (CEF_CURRENTLY_ON_UIT()) {
+ RunNow(std::move(delegate_), cert);
+ } else {
+ CEF_POST_TASK(
+ CEF_UIT,
+ base::BindOnce(&CefSelectClientCertificateCallbackImpl::RunNow,
+ std::move(delegate_), cert));
+ }
+ }
+
+ static void RunNow(
+ std::unique_ptr<content::ClientCertificateDelegate> delegate,
+ CefRefPtr<CefX509Certificate> cert) {
+ CEF_REQUIRE_UIT();
+
+ if (cert) {
+ CefX509CertificateImpl* certImpl =
+ static_cast<CefX509CertificateImpl*>(cert.get());
+ certImpl->AcquirePrivateKey(base::BindOnce(
+ &CefSelectClientCertificateCallbackImpl::RunWithPrivateKey,
+ std::move(delegate), cert));
+ return;
+ }
+
+ delegate->ContinueWithCertificate(nullptr, nullptr);
+ }
+
+ static void RunWithPrivateKey(
+ std::unique_ptr<content::ClientCertificateDelegate> delegate,
+ CefRefPtr<CefX509Certificate> cert,
+ scoped_refptr<net::SSLPrivateKey> key) {
+ CEF_REQUIRE_UIT();
+ DCHECK(cert);
+
+ if (key) {
+ CefX509CertificateImpl* certImpl =
+ static_cast<CefX509CertificateImpl*>(cert.get());
+ delegate->ContinueWithCertificate(certImpl->GetInternalCertObject(), key);
+ } else {
+ delegate->ContinueWithCertificate(nullptr, nullptr);
+ }
+ }
+
+ std::unique_ptr<content::ClientCertificateDelegate> delegate_;
+
+ IMPLEMENT_REFCOUNTING(CefSelectClientCertificateCallbackImpl);
+};
+
+#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC)
+int GetCrashSignalFD() {
+ if (!crash_reporting::Enabled()) {
+ return -1;
+ }
+
+ int fd;
+ pid_t pid;
+ return crash_reporter::GetHandlerSocket(&fd, &pid) ? fd : -1;
+}
+#endif // BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC)
+
+// From chrome/browser/plugins/chrome_content_browser_client_plugins_part.cc.
+void BindPluginInfoHost(
+ int render_process_id,
+ mojo::PendingAssociatedReceiver<chrome::mojom::PluginInfoHost> receiver) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ content::RenderProcessHost* host =
+ content::RenderProcessHost::FromID(render_process_id);
+ if (!host) {
+ return;
+ }
+
+ Profile* profile = Profile::FromBrowserContext(host->GetBrowserContext());
+ mojo::MakeSelfOwnedAssociatedReceiver(
+ std::make_unique<PluginInfoHostImpl>(render_process_id, profile),
+ std::move(receiver));
+}
+
+void BindBadgeService(
+ content::RenderFrameHost* frame_host,
+ mojo::PendingReceiver<blink::mojom::BadgeService> receiver) {}
+
+void BindBadgeServiceForServiceWorker(
+ const content::ServiceWorkerVersionBaseInfo& info,
+ mojo::PendingReceiver<blink::mojom::BadgeService> receiver) {}
+
+void BindMediaFoundationRendererNotifierHandler(
+ content::RenderFrameHost* frame_host,
+ mojo::PendingReceiver<media::mojom::MediaFoundationRendererNotifier>
+ receiver) {}
+
+void BindNetworkHintsHandler(
+ content::RenderFrameHost* frame_host,
+ mojo::PendingReceiver<network_hints::mojom::NetworkHintsHandler> receiver) {
+ predictors::NetworkHintsHandlerImpl::Create(frame_host, std::move(receiver));
+}
+
+base::FilePath GetRootCachePath() {
+ // The CefContext::ValidateCachePath method enforces the requirement that all
+ // cache_path values be either equal to or a child of root_cache_path.
+ return base::FilePath(
+ CefString(&CefContext::Get()->settings().root_cache_path));
+}
+
+const extensions::Extension* GetEnabledExtensionFromSiteURL(
+ content::BrowserContext* context,
+ const GURL& site_url) {
+ if (!site_url.SchemeIs(extensions::kExtensionScheme)) {
+ return nullptr;
+ }
+
+ auto registry = extensions::ExtensionRegistry::Get(context);
+ if (!registry) {
+ return nullptr;
+ }
+
+ return registry->enabled_extensions().GetByID(site_url.host());
+}
+
+} // namespace
+
+AlloyContentBrowserClient::AlloyContentBrowserClient() = default;
+
+AlloyContentBrowserClient::~AlloyContentBrowserClient() = default;
+
+std::unique_ptr<content::BrowserMainParts>
+AlloyContentBrowserClient::CreateBrowserMainParts(
+ bool /* is_integration_test */) {
+ auto browser_main_parts = std::make_unique<AlloyBrowserMainParts>();
+ browser_main_parts_ = browser_main_parts.get();
+ return browser_main_parts;
+}
+
+void AlloyContentBrowserClient::RenderProcessWillLaunch(
+ content::RenderProcessHost* host) {
+ const int id = host->GetID();
+ Profile* profile = Profile::FromBrowserContext(host->GetBrowserContext());
+
+ if (extensions::ExtensionsEnabled()) {
+ host->AddFilter(new extensions::ExtensionMessageFilter(id, profile));
+ }
+
+ // If the renderer process crashes then the host may already have
+ // CefBrowserInfoManager as an observer. Try to remove it first before adding
+ // to avoid DCHECKs.
+ host->RemoveObserver(CefBrowserInfoManager::GetInstance());
+ host->AddObserver(CefBrowserInfoManager::GetInstance());
+
+ // Forwards dynamic parameters to CefRenderThreadObserver.
+ Profile* original_profile = profile->GetOriginalProfile();
+ RendererUpdaterFactory::GetForProfile(original_profile)
+ ->InitializeRenderer(host);
+}
+
+bool AlloyContentBrowserClient::ShouldUseProcessPerSite(
+ content::BrowserContext* browser_context,
+ const GURL& site_url) {
+ if (extensions::ExtensionsEnabled()) {
+ if (auto profile = Profile::FromBrowserContext(browser_context)) {
+ return extensions::ChromeContentBrowserClientExtensionsPart::
+ ShouldUseProcessPerSite(profile, site_url);
+ }
+ }
+
+ return content::ContentBrowserClient::ShouldUseProcessPerSite(browser_context,
+ site_url);
+}
+
+bool AlloyContentBrowserClient::ShouldUseSpareRenderProcessHost(
+ content::BrowserContext* browser_context,
+ const GURL& site_url) {
+ if (extensions::ExtensionsEnabled()) {
+ if (auto profile = Profile::FromBrowserContext(browser_context)) {
+ return extensions::ChromeContentBrowserClientExtensionsPart::
+ ShouldUseSpareRenderProcessHost(profile, site_url);
+ }
+ }
+
+ return content::ContentBrowserClient::ShouldUseSpareRenderProcessHost(
+ browser_context, site_url);
+}
+
+bool AlloyContentBrowserClient::DoesSiteRequireDedicatedProcess(
+ content::BrowserContext* browser_context,
+ const GURL& effective_site_url) {
+ if (extensions::ExtensionsEnabled()) {
+ return extensions::ChromeContentBrowserClientExtensionsPart::
+ DoesSiteRequireDedicatedProcess(browser_context, effective_site_url);
+ }
+
+ return content::ContentBrowserClient::DoesSiteRequireDedicatedProcess(
+ browser_context, effective_site_url);
+}
+
+bool AlloyContentBrowserClient::ShouldTreatURLSchemeAsFirstPartyWhenTopLevel(
+ base::StringPiece scheme,
+ bool is_embedded_origin_secure) {
+ // This is needed to bypass the normal SameSite rules for any chrome:// page
+ // embedding a secure origin, regardless of the registrable domains of any
+ // intervening frames. For example, this is needed for browser UI to interact
+ // with SameSite cookies on accounts.google.com, which are used for logging
+ // into Cloud Print from chrome://print, for displaying a list of available
+ // accounts on the NTP (chrome://new-tab-page), etc.
+ if (is_embedded_origin_secure && scheme == content::kChromeUIScheme) {
+ return true;
+ }
+
+ if (extensions::ExtensionsEnabled()) {
+ return scheme == extensions::kExtensionScheme;
+ }
+
+ return false;
+}
+
+bool AlloyContentBrowserClient::
+ ShouldIgnoreSameSiteCookieRestrictionsWhenTopLevel(
+ base::StringPiece scheme,
+ bool is_embedded_origin_secure) {
+ return is_embedded_origin_secure && scheme == content::kChromeUIScheme;
+}
+
+void AlloyContentBrowserClient::OverrideURLLoaderFactoryParams(
+ content::BrowserContext* browser_context,
+ const url::Origin& origin,
+ bool is_for_isolated_world,
+ network::mojom::URLLoaderFactoryParams* factory_params) {
+ if (extensions::ExtensionsEnabled()) {
+ extensions::URLLoaderFactoryManager::OverrideURLLoaderFactoryParams(
+ browser_context, origin, is_for_isolated_world, factory_params);
+ }
+}
+
+void AlloyContentBrowserClient::GetAdditionalWebUISchemes(
+ std::vector<std::string>* additional_schemes) {
+ // Any schemes listed here are treated as WebUI schemes but do not get WebUI
+ // bindings. Also, view-source is allowed for these schemes. WebUI schemes
+ // will not be passed to HandleExternalProtocol.
+}
+
+void AlloyContentBrowserClient::GetAdditionalViewSourceSchemes(
+ std::vector<std::string>* additional_schemes) {
+ GetAdditionalWebUISchemes(additional_schemes);
+
+ additional_schemes->push_back(extensions::kExtensionScheme);
+}
+
+std::unique_ptr<ui::SelectFilePolicy>
+AlloyContentBrowserClient::CreateSelectFilePolicy(
+ content::WebContents* web_contents) {
+ return std::make_unique<ChromeSelectFilePolicy>(web_contents);
+}
+
+void AlloyContentBrowserClient::GetAdditionalAllowedSchemesForFileSystem(
+ std::vector<std::string>* additional_allowed_schemes) {
+ ContentBrowserClient::GetAdditionalAllowedSchemesForFileSystem(
+ additional_allowed_schemes);
+ additional_allowed_schemes->push_back(content::kChromeDevToolsScheme);
+ additional_allowed_schemes->push_back(content::kChromeUIScheme);
+ additional_allowed_schemes->push_back(content::kChromeUIUntrustedScheme);
+}
+
+bool AlloyContentBrowserClient::IsWebUIAllowedToMakeNetworkRequests(
+ const url::Origin& origin) {
+ return scheme::IsWebUIAllowedToMakeNetworkRequests(origin);
+}
+
+bool AlloyContentBrowserClient::IsHandledURL(const GURL& url) {
+ if (!url.is_valid()) {
+ return false;
+ }
+ const std::string& scheme = url.scheme();
+ DCHECK_EQ(scheme, base::ToLowerASCII(scheme));
+
+ if (scheme::IsInternalHandledScheme(scheme)) {
+ return true;
+ }
+
+ return CefAppManager::Get()->HasCustomScheme(scheme);
+}
+
+void AlloyContentBrowserClient::SiteInstanceGotProcess(
+ content::SiteInstance* site_instance) {
+ if (!extensions::ExtensionsEnabled()) {
+ return;
+ }
+
+ CHECK(site_instance->HasProcess());
+
+ auto context = site_instance->GetBrowserContext();
+
+ // Only add the process to the map if the SiteInstance's site URL is already
+ // a chrome-extension:// URL. This includes hosted apps, except in rare cases
+ // that a URL in the hosted app's extent is not treated as a hosted app (e.g.,
+ // for isolated origins or cross-site iframes). For that case, don't look up
+ // the hosted app's Extension from the site URL using GetExtensionOrAppByURL,
+ // since it isn't treated as a hosted app.
+ const auto extension =
+ GetEnabledExtensionFromSiteURL(context, site_instance->GetSiteURL());
+ if (!extension) {
+ return;
+ }
+
+ extensions::ProcessMap::Get(context)->Insert(
+ extension->id(), site_instance->GetProcess()->GetID(),
+ site_instance->GetId());
+}
+
+void AlloyContentBrowserClient::SiteInstanceDeleting(
+ content::SiteInstance* site_instance) {
+ if (!extensions::ExtensionsEnabled()) {
+ return;
+ }
+
+ if (!site_instance->HasProcess()) {
+ return;
+ }
+
+ auto context = site_instance->GetBrowserContext();
+ auto registry = extensions::ExtensionRegistry::Get(context);
+ if (!registry) {
+ return;
+ }
+
+ auto extension = registry->enabled_extensions().GetExtensionOrAppByURL(
+ site_instance->GetSiteURL());
+ if (!extension) {
+ return;
+ }
+
+ extensions::ProcessMap::Get(context)->Remove(
+ extension->id(), site_instance->GetProcess()->GetID(),
+ site_instance->GetId());
+}
+
+void AlloyContentBrowserClient::BindHostReceiverForRenderer(
+ content::RenderProcessHost* render_process_host,
+ mojo::GenericPendingReceiver receiver) {
+ if (auto host_receiver = receiver.As<spellcheck::mojom::SpellCheckHost>()) {
+ SpellCheckHostChromeImpl::Create(render_process_host->GetID(),
+ std::move(host_receiver));
+ return;
+ }
+
+#if BUILDFLAG(HAS_SPELLCHECK_PANEL)
+ if (auto panel_host_receiver =
+ receiver.As<spellcheck::mojom::SpellCheckPanelHost>()) {
+ SpellCheckPanelHostImpl::Create(render_process_host->GetID(),
+ std::move(panel_host_receiver));
+ return;
+ }
+#endif // BUILDFLAG(HAS_SPELLCHECK_PANEL)
+}
+
+void AlloyContentBrowserClient::AppendExtraCommandLineSwitches(
+ base::CommandLine* command_line,
+ int child_process_id) {
+ const base::CommandLine* browser_cmd = base::CommandLine::ForCurrentProcess();
+
+ {
+ // Propagate the following switches to all command lines (along with any
+ // associated values) if present in the browser command line.
+ static const char* const kSwitchNames[] = {
+ switches::kDisablePackLoading,
+#if BUILDFLAG(IS_MAC)
+ switches::kFrameworkDirPath,
+ switches::kMainBundlePath,
+#endif
+ switches::kLocalesDirPath,
+ switches::kLogSeverity,
+ switches::kResourcesDirPath,
+ embedder_support::kUserAgent,
+ switches::kUserAgentProductAndVersion,
+ };
+ command_line->CopySwitchesFrom(*browser_cmd, kSwitchNames,
+ std::size(kSwitchNames));
+ }
+
+ const std::string& process_type =
+ command_line->GetSwitchValueASCII(switches::kProcessType);
+ if (process_type == switches::kRendererProcess) {
+ // Propagate the following switches to the renderer command line (along with
+ // any associated values) if present in the browser command line.
+ static const char* const kSwitchNames[] = {
+ switches::kDisableExtensions,
+ switches::kDisablePdfExtension,
+ switches::kDisablePrintPreview,
+ switches::kDisableScrollBounce,
+ switches::kDisableSpellChecking,
+ switches::kEnableSpeechInput,
+ switches::kUncaughtExceptionStackSize,
+ network::switches::kUnsafelyTreatInsecureOriginAsSecure,
+ };
+ command_line->CopySwitchesFrom(*browser_cmd, kSwitchNames,
+ std::size(kSwitchNames));
+
+ if (extensions::ExtensionsEnabled()) {
+ content::RenderProcessHost* process =
+ content::RenderProcessHost::FromID(child_process_id);
+ auto browser_context = process->GetBrowserContext();
+ CefBrowserContext* cef_browser_context =
+ process ? CefBrowserContext::FromBrowserContext(browser_context)
+ : nullptr;
+ if (cef_browser_context) {
+ if (cef_browser_context->IsPrintPreviewSupported()) {
+ command_line->AppendSwitch(switches::kEnablePrintPreview);
+ }
+
+ // Based on ChromeContentBrowserClientExtensionsPart::
+ // AppendExtraRendererCommandLineSwitches
+ if (extensions::ProcessMap::Get(browser_context)
+ ->Contains(process->GetID())) {
+ command_line->AppendSwitch(extensions::switches::kExtensionProcess);
+ }
+ }
+ }
+ } else {
+ // Propagate the following switches to non-renderer command line (along with
+ // any associated values) if present in the browser command line.
+ static const char* const kSwitchNames[] = {
+ switches::kLang,
+ };
+ command_line->CopySwitchesFrom(*browser_cmd, kSwitchNames,
+ std::size(kSwitchNames));
+ }
+
+ // Necessary to populate DIR_USER_DATA in sub-processes.
+ // See resource_util.cc GetUserDataPath.
+ base::FilePath user_data_dir;
+ if (base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir)) {
+ command_line->AppendSwitchPath(switches::kUserDataDir, user_data_dir);
+ }
+
+#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC)
+ if (process_type == switches::kZygoteProcess) {
+ if (browser_cmd->HasSwitch(switches::kBrowserSubprocessPath)) {
+ // Force use of the sub-process executable path for the zygote process.
+ const base::FilePath& subprocess_path =
+ browser_cmd->GetSwitchValuePath(switches::kBrowserSubprocessPath);
+ if (!subprocess_path.empty()) {
+ command_line->SetProgram(subprocess_path);
+ }
+ }
+
+ // Propagate the following switches to the zygote command line (along with
+ // any associated values) if present in the browser command line.
+ static const char* const kSwitchNames[] = {
+ switches::kLogFile,
+ };
+ command_line->CopySwitchesFrom(*browser_cmd, kSwitchNames,
+ std::size(kSwitchNames));
+ }
+
+ if (crash_reporting::Enabled()) {
+ int fd;
+ pid_t pid;
+ if (crash_reporter::GetHandlerSocket(&fd, &pid)) {
+ command_line->AppendSwitchASCII(
+ crash_reporter::switches::kCrashpadHandlerPid,
+ base::NumberToString(pid));
+ }
+ }
+#endif // BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC)
+
+ CefRefPtr<CefApp> app = CefAppManager::Get()->GetApplication();
+ if (app.get()) {
+ CefRefPtr<CefBrowserProcessHandler> handler =
+ app->GetBrowserProcessHandler();
+ if (handler.get()) {
+ CefRefPtr<CefCommandLineImpl> commandLinePtr(
+ new CefCommandLineImpl(command_line, false, false));
+ handler->OnBeforeChildProcessLaunch(commandLinePtr.get());
+ std::ignore = commandLinePtr->Detach(nullptr);
+ }
+ }
+}
+
+std::string AlloyContentBrowserClient::GetApplicationLocale() {
+ return g_browser_process->GetApplicationLocale();
+}
+
+scoped_refptr<network::SharedURLLoaderFactory>
+AlloyContentBrowserClient::GetSystemSharedURLLoaderFactory() {
+ DCHECK(
+ content::BrowserThread::CurrentlyOn(content::BrowserThread::UI) ||
+ !content::BrowserThread::IsThreadInitialized(content::BrowserThread::UI));
+
+ if (!SystemNetworkContextManager::GetInstance()) {
+ return nullptr;
+ }
+
+ return SystemNetworkContextManager::GetInstance()
+ ->GetSharedURLLoaderFactory();
+}
+
+network::mojom::NetworkContext*
+AlloyContentBrowserClient::GetSystemNetworkContext() {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ DCHECK(SystemNetworkContextManager::GetInstance());
+ return SystemNetworkContextManager::GetInstance()->GetContext();
+}
+
+content::MediaObserver* AlloyContentBrowserClient::GetMediaObserver() {
+ return CefMediaCaptureDevicesDispatcher::GetInstance();
+}
+
+content::SpeechRecognitionManagerDelegate*
+AlloyContentBrowserClient::CreateSpeechRecognitionManagerDelegate() {
+ const base::CommandLine* command_line =
+ base::CommandLine::ForCurrentProcess();
+ if (command_line->HasSwitch(switches::kEnableSpeechInput)) {
+ return new CefSpeechRecognitionManagerDelegate();
+ }
+
+ return nullptr;
+}
+
+content::GeneratedCodeCacheSettings
+AlloyContentBrowserClient::GetGeneratedCodeCacheSettings(
+ content::BrowserContext* context) {
+ // If we pass 0 for size, disk_cache will pick a default size using the
+ // heuristics based on available disk size. These are implemented in
+ // disk_cache::PreferredCacheSize in net/disk_cache/cache_util.cc.
+ const base::FilePath& cache_path = context->GetPath();
+ return content::GeneratedCodeCacheSettings(!cache_path.empty() /* enabled */,
+ 0 /* size */, cache_path);
+}
+
+void AlloyContentBrowserClient::AllowCertificateError(
+ content::WebContents* web_contents,
+ int cert_error,
+ const net::SSLInfo& ssl_info,
+ const GURL& request_url,
+ bool is_main_frame_request,
+ bool strict_enforcement,
+ base::OnceCallback<void(content::CertificateRequestResultType)> callback) {
+ auto returned_callback = certificate_query::AllowCertificateError(
+ web_contents, cert_error, ssl_info, request_url, is_main_frame_request,
+ strict_enforcement, std::move(callback), /*default_disallow=*/true);
+ // Callback should not be returned.
+ DCHECK(returned_callback.is_null());
+}
+
+base::OnceClosure AlloyContentBrowserClient::SelectClientCertificate(
+ content::WebContents* web_contents,
+ net::SSLCertRequestInfo* cert_request_info,
+ net::ClientCertIdentityList client_certs,
+ std::unique_ptr<content::ClientCertificateDelegate> delegate) {
+ CEF_REQUIRE_UIT();
+
+ CefRefPtr<CefRequestHandler> handler;
+ CefRefPtr<AlloyBrowserHostImpl> browser =
+ AlloyBrowserHostImpl::GetBrowserForContents(web_contents);
+ if (browser.get()) {
+ CefRefPtr<CefClient> client = browser->GetClient();
+ if (client.get()) {
+ handler = client->GetRequestHandler();
+ }
+ }
+
+ if (!handler.get()) {
+ delegate->ContinueWithCertificate(nullptr, nullptr);
+ return base::OnceClosure();
+ }
+
+ CefRequestHandler::X509CertificateList certs;
+ for (net::ClientCertIdentityList::iterator iter = client_certs.begin();
+ iter != client_certs.end(); iter++) {
+ certs.push_back(new CefX509CertificateImpl(std::move(*iter)));
+ }
+
+ CefRefPtr<CefSelectClientCertificateCallbackImpl> callbackImpl(
+ new CefSelectClientCertificateCallbackImpl(std::move(delegate)));
+
+ bool proceed = handler->OnSelectClientCertificate(
+ browser.get(), cert_request_info->is_proxy,
+ cert_request_info->host_and_port.host(),
+ cert_request_info->host_and_port.port(), certs, callbackImpl.get());
+
+ if (!proceed && !certs.empty()) {
+ callbackImpl->Select(certs[0]);
+ }
+ return base::OnceClosure();
+}
+
+bool AlloyContentBrowserClient::CanCreateWindow(
+ content::RenderFrameHost* opener,
+ const GURL& opener_url,
+ const GURL& opener_top_level_frame_url,
+ const url::Origin& source_origin,
+ content::mojom::WindowContainerType container_type,
+ const GURL& target_url,
+ const content::Referrer& referrer,
+ const std::string& frame_name,
+ WindowOpenDisposition disposition,
+ const blink::mojom::WindowFeatures& features,
+ bool user_gesture,
+ bool opener_suppressed,
+ bool* no_javascript_access) {
+ CEF_REQUIRE_UIT();
+ *no_javascript_access = false;
+
+ return CefBrowserInfoManager::GetInstance()->CanCreateWindow(
+ opener, target_url, referrer, frame_name, disposition, features,
+ user_gesture, opener_suppressed, no_javascript_access);
+}
+
+void AlloyContentBrowserClient::OverrideWebkitPrefs(
+ content::WebContents* web_contents,
+ blink::web_pref::WebPreferences* prefs) {
+ auto rvh = web_contents->GetRenderViewHost();
+
+ // Using RVH instead of RFH here because rvh->GetMainFrame() may be nullptr
+ // when this method is called.
+ SkColor base_background_color;
+ renderer_prefs::PopulateWebPreferences(rvh, *prefs, base_background_color);
+
+ web_contents->SetPageBaseBackgroundColor(base_background_color);
+}
+
+bool AlloyContentBrowserClient::OverrideWebPreferencesAfterNavigation(
+ content::WebContents* web_contents,
+ blink::web_pref::WebPreferences* prefs) {
+ return renderer_prefs::PopulateWebPreferencesAfterNavigation(web_contents,
+ *prefs);
+}
+
+void AlloyContentBrowserClient::BrowserURLHandlerCreated(
+ content::BrowserURLHandler* handler) {
+ scheme::BrowserURLHandlerCreated(handler);
+}
+
+std::string AlloyContentBrowserClient::GetDefaultDownloadName() {
+ return "download";
+}
+
+void AlloyContentBrowserClient::DidCreatePpapiPlugin(
+ content::BrowserPpapiHost* browser_host) {
+ browser_host->GetPpapiHost()->AddHostFactoryFilter(
+ std::unique_ptr<ppapi::host::HostFactory>(
+ new ChromeBrowserPepperHostFactory(browser_host)));
+}
+
+std::unique_ptr<content::DevToolsManagerDelegate>
+AlloyContentBrowserClient::CreateDevToolsManagerDelegate() {
+ return std::make_unique<CefDevToolsManagerDelegate>();
+}
+
+void AlloyContentBrowserClient::
+ RegisterAssociatedInterfaceBindersForRenderFrameHost(
+ content::RenderFrameHost& render_frame_host,
+ blink::AssociatedInterfaceRegistry& associated_registry) {
+ associated_registry.AddInterface<extensions::mojom::LocalFrameHost>(
+ base::BindRepeating(
+ [](content::RenderFrameHost* render_frame_host,
+ mojo::PendingAssociatedReceiver<extensions::mojom::LocalFrameHost>
+ receiver) {
+ extensions::ExtensionWebContentsObserver::BindLocalFrameHost(
+ std::move(receiver), render_frame_host);
+ },
+ &render_frame_host));
+
+ associated_registry.AddInterface<printing::mojom::PrintManagerHost>(
+ base::BindRepeating(
+ [](content::RenderFrameHost* render_frame_host,
+ mojo::PendingAssociatedReceiver<printing::mojom::PrintManagerHost>
+ receiver) {
+ printing::PrintViewManager::BindPrintManagerHost(
+ std::move(receiver), render_frame_host);
+ },
+ &render_frame_host));
+
+ associated_registry.AddInterface<pdf::mojom::PdfService>(base::BindRepeating(
+ [](content::RenderFrameHost* render_frame_host,
+ mojo::PendingAssociatedReceiver<pdf::mojom::PdfService> receiver) {
+ pdf::PDFWebContentsHelper::BindPdfService(std::move(receiver),
+ render_frame_host);
+ },
+ &render_frame_host));
+}
+
+std::vector<std::unique_ptr<content::NavigationThrottle>>
+AlloyContentBrowserClient::CreateThrottlesForNavigation(
+ content::NavigationHandle* navigation_handle) {
+ throttle::NavigationThrottleList throttles;
+
+ if (extensions::ExtensionsEnabled()) {
+ auto pdf_iframe_throttle =
+ PDFIFrameNavigationThrottle::MaybeCreateThrottleFor(navigation_handle);
+ if (pdf_iframe_throttle) {
+ throttles.push_back(std::move(pdf_iframe_throttle));
+ }
+
+ auto pdf_throttle = pdf::PdfNavigationThrottle::MaybeCreateThrottleFor(
+ navigation_handle, std::make_unique<ChromePdfStreamDelegate>());
+ if (pdf_throttle) {
+ throttles.push_back(std::move(pdf_throttle));
+ }
+ }
+
+ throttle::CreateThrottlesForNavigation(navigation_handle, throttles);
+
+ return throttles;
+}
+
+std::vector<std::unique_ptr<blink::URLLoaderThrottle>>
+AlloyContentBrowserClient::CreateURLLoaderThrottles(
+ const network::ResourceRequest& request,
+ content::BrowserContext* browser_context,
+ const base::RepeatingCallback<content::WebContents*()>& wc_getter,
+ content::NavigationUIData* navigation_ui_data,
+ int frame_tree_node_id) {
+ std::vector<std::unique_ptr<blink::URLLoaderThrottle>> result;
+
+ // Used to substitute View ID for PDF contents when using the PDF plugin.
+ result.push_back(std::make_unique<PluginResponseInterceptorURLLoaderThrottle>(
+ request.destination, frame_tree_node_id));
+
+ Profile* profile = Profile::FromBrowserContext(browser_context);
+
+ chrome::mojom::DynamicParams dynamic_params = {
+ profile->GetPrefs()->GetBoolean(prefs::kForceGoogleSafeSearch),
+ profile->GetPrefs()->GetInteger(prefs::kForceYouTubeRestrict),
+ profile->GetPrefs()->GetString(prefs::kAllowedDomainsForApps)};
+ result.push_back(
+ std::make_unique<GoogleURLLoaderThrottle>(std::move(dynamic_params)));
+
+ return result;
+}
+
+std::vector<std::unique_ptr<content::URLLoaderRequestInterceptor>>
+AlloyContentBrowserClient::WillCreateURLLoaderRequestInterceptors(
+ content::NavigationUIData* navigation_ui_data,
+ int frame_tree_node_id) {
+ std::vector<std::unique_ptr<content::URLLoaderRequestInterceptor>>
+ interceptors;
+
+ if (extensions::ExtensionsEnabled()) {
+ auto pdf_interceptor =
+ pdf::PdfURLLoaderRequestInterceptor::MaybeCreateInterceptor(
+ frame_tree_node_id, std::make_unique<ChromePdfStreamDelegate>());
+ if (pdf_interceptor) {
+ interceptors.push_back(std::move(pdf_interceptor));
+ }
+ }
+
+ return interceptors;
+}
+
+#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC)
+void AlloyContentBrowserClient::GetAdditionalMappedFilesForChildProcess(
+ const base::CommandLine& command_line,
+ int child_process_id,
+ content::PosixFileDescriptorInfo* mappings) {
+ int crash_signal_fd = GetCrashSignalFD();
+ if (crash_signal_fd >= 0) {
+ mappings->Share(kCrashDumpSignal, crash_signal_fd);
+ }
+}
+#endif // BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC)
+
+void AlloyContentBrowserClient::ExposeInterfacesToRenderer(
+ service_manager::BinderRegistry* registry,
+ blink::AssociatedInterfaceRegistry* associated_registry,
+ content::RenderProcessHost* host) {
+ associated_registry->AddInterface<chrome::mojom::PluginInfoHost>(
+ base::BindRepeating(&BindPluginInfoHost, host->GetID()));
+
+ if (extensions::ExtensionsEnabled()) {
+ associated_registry->AddInterface<extensions::mojom::EventRouter>(
+ base::BindRepeating(&extensions::EventRouter::BindForRenderer,
+ host->GetID()));
+ associated_registry->AddInterface<guest_view::mojom::GuestViewHost>(
+ base::BindRepeating(
+ &extensions::ExtensionsGuestView::CreateForComponents,
+ host->GetID()));
+ associated_registry->AddInterface<extensions::mojom::GuestView>(
+ base::BindRepeating(
+ &extensions::ExtensionsGuestView::CreateForExtensions,
+ host->GetID()));
+ associated_registry->AddInterface<extensions::mojom::RendererHost>(
+ base::BindRepeating(&extensions::RendererStartupHelper::BindForRenderer,
+ host->GetID()));
+ }
+
+ CefBrowserManager::ExposeInterfacesToRenderer(registry, associated_registry,
+ host);
+}
+
+std::unique_ptr<net::ClientCertStore>
+AlloyContentBrowserClient::CreateClientCertStore(
+ content::BrowserContext* browser_context) {
+ // Match the logic in ProfileNetworkContextService::CreateClientCertStore.
+#if BUILDFLAG(USE_NSS_CERTS)
+ // TODO: Add support for client implementation of crypto password dialog.
+ return std::unique_ptr<net::ClientCertStore>(new net::ClientCertStoreNSS(
+ net::ClientCertStoreNSS::PasswordDelegateFactory()));
+#elif BUILDFLAG(IS_WIN)
+ return std::unique_ptr<net::ClientCertStore>(new net::ClientCertStoreWin());
+#elif BUILDFLAG(IS_MAC)
+ return std::unique_ptr<net::ClientCertStore>(new net::ClientCertStoreMac());
+#else
+#error Unknown platform.
+#endif
+}
+
+std::unique_ptr<content::LoginDelegate>
+AlloyContentBrowserClient::CreateLoginDelegate(
+ const net::AuthChallengeInfo& auth_info,
+ content::WebContents* web_contents,
+ const content::GlobalRequestID& request_id,
+ bool is_request_for_main_frame,
+ const GURL& url,
+ scoped_refptr<net::HttpResponseHeaders> response_headers,
+ bool first_auth_attempt,
+ LoginAuthRequiredCallback auth_required_callback) {
+ return std::make_unique<net_service::LoginDelegate>(
+ auth_info, web_contents, request_id, url,
+ std::move(auth_required_callback));
+}
+
+void AlloyContentBrowserClient::RegisterNonNetworkNavigationURLLoaderFactories(
+ int frame_tree_node_id,
+ ukm::SourceIdObj ukm_source_id,
+ NonNetworkURLLoaderFactoryMap* factories) {
+ if (!extensions::ExtensionsEnabled()) {
+ return;
+ }
+
+ content::WebContents* web_contents =
+ content::WebContents::FromFrameTreeNodeId(frame_tree_node_id);
+ factories->emplace(
+ extensions::kExtensionScheme,
+ extensions::CreateExtensionNavigationURLLoaderFactory(
+ web_contents->GetBrowserContext(), ukm_source_id,
+ !!extensions::WebViewGuest::FromWebContents(web_contents)));
+}
+
+void AlloyContentBrowserClient::RegisterNonNetworkSubresourceURLLoaderFactories(
+ int render_process_id,
+ int render_frame_id,
+ const absl::optional<url::Origin>& request_initiator_origin,
+ NonNetworkURLLoaderFactoryMap* factories) {
+ if (!extensions::ExtensionsEnabled()) {
+ return;
+ }
+
+ auto factory = extensions::CreateExtensionURLLoaderFactory(render_process_id,
+ render_frame_id);
+ if (factory) {
+ factories->emplace(extensions::kExtensionScheme, std::move(factory));
+ }
+
+ content::RenderFrameHost* frame_host =
+ content::RenderFrameHost::FromID(render_process_id, render_frame_id);
+ content::WebContents* web_contents =
+ content::WebContents::FromRenderFrameHost(frame_host);
+ if (!web_contents) {
+ return;
+ }
+
+ extensions::CefExtensionWebContentsObserver* web_observer =
+ extensions::CefExtensionWebContentsObserver::FromWebContents(
+ web_contents);
+
+ // There is nothing to do if no CefExtensionWebContentsObserver is attached
+ // to the |web_contents|.
+ if (!web_observer) {
+ return;
+ }
+
+ const extensions::Extension* extension =
+ web_observer->GetExtensionFromFrame(frame_host, false);
+ if (!extension) {
+ return;
+ }
+
+ std::vector<std::string> allowed_webui_hosts;
+ // Support for chrome:// scheme if appropriate.
+ if ((extension->is_extension() || extension->is_platform_app()) &&
+ extensions::Manifest::IsComponentLocation(extension->location())) {
+ // Components of chrome that are implemented as extensions or platform apps
+ // are allowed to use chrome://resources/ and chrome://theme/ URLs.
+ // See also HasCrossOriginWhitelistEntry.
+ allowed_webui_hosts.emplace_back(content::kChromeUIResourcesHost);
+ allowed_webui_hosts.emplace_back(chrome::kChromeUIThemeHost);
+ }
+ if (!allowed_webui_hosts.empty()) {
+ factories->emplace(content::kChromeUIScheme,
+ content::CreateWebUIURLLoaderFactory(
+ frame_host, content::kChromeUIScheme,
+ std::move(allowed_webui_hosts)));
+ }
+}
+
+bool AlloyContentBrowserClient::WillCreateURLLoaderFactory(
+ content::BrowserContext* browser_context,
+ content::RenderFrameHost* frame,
+ int render_process_id,
+ URLLoaderFactoryType type,
+ const url::Origin& request_initiator,
+ absl::optional<int64_t> navigation_id,
+ ukm::SourceIdObj ukm_source_id,
+ mojo::PendingReceiver<network::mojom::URLLoaderFactory>* factory_receiver,
+ mojo::PendingRemote<network::mojom::TrustedURLLoaderHeaderClient>*
+ header_client,
+ bool* bypass_redirect_checks,
+ bool* disable_secure_dns,
+ network::mojom::URLLoaderFactoryOverridePtr* factory_override) {
+ auto request_handler = net_service::CreateInterceptedRequestHandler(
+ browser_context, frame, render_process_id,
+ type == URLLoaderFactoryType::kNavigation,
+ type == URLLoaderFactoryType::kDownload, request_initiator);
+
+ net_service::ProxyURLLoaderFactory::CreateProxy(
+ browser_context, factory_receiver, header_client,
+ std::move(request_handler));
+ return true;
+}
+
+void AlloyContentBrowserClient::OnNetworkServiceCreated(
+ network::mojom::NetworkService* network_service) {
+ DCHECK(g_browser_process);
+ PrefService* local_state = g_browser_process->local_state();
+ DCHECK(local_state);
+
+ // Need to set up global NetworkService state before anything else uses it.
+ DCHECK(SystemNetworkContextManager::GetInstance());
+ SystemNetworkContextManager::GetInstance()->OnNetworkServiceCreated(
+ network_service);
+}
+
+bool AlloyContentBrowserClient::ConfigureNetworkContextParams(
+ content::BrowserContext* context,
+ bool in_memory,
+ const base::FilePath& relative_partition_path,
+ network::mojom::NetworkContextParams* network_context_params,
+ cert_verifier::mojom::CertVerifierCreationParams*
+ cert_verifier_creation_params) {
+ // This method may be called during shutdown when using multi-threaded
+ // message loop mode. In that case exit early to avoid crashes.
+ if (!SystemNetworkContextManager::GetInstance()) {
+ // Cancel NetworkContext creation in
+ // StoragePartitionImpl::InitNetworkContext.
+ return false;
+ }
+
+ auto cef_context = CefBrowserContext::FromBrowserContext(context);
+
+ Profile* profile = cef_context->AsProfile();
+ ProfileNetworkContextService* service =
+ ProfileNetworkContextServiceFactory::GetForContext(profile);
+ if (service) {
+ service->ConfigureNetworkContextParams(in_memory, relative_partition_path,
+ network_context_params,
+ cert_verifier_creation_params);
+ } else {
+ // Set default params.
+ network_context_params->user_agent = GetUserAgent();
+ network_context_params->accept_language = GetApplicationLocale();
+ }
+
+ network_context_params->cookieable_schemes =
+ cef_context->GetCookieableSchemes();
+
+ // TODO(cef): Remove this and add required NetworkIsolationKeys,
+ // this is currently not the case and this was not required pre M84.
+ network_context_params->require_network_isolation_key = false;
+
+ return true;
+}
+
+// The sandbox may block read/write access from the NetworkService to
+// directories that are not returned by this method.
+std::vector<base::FilePath>
+AlloyContentBrowserClient::GetNetworkContextsParentDirectory() {
+ base::FilePath user_data_path;
+ base::PathService::Get(chrome::DIR_USER_DATA, &user_data_path);
+ DCHECK(!user_data_path.empty());
+
+ const auto& root_cache_path = GetRootCachePath();
+
+ // root_cache_path may sometimes be empty or a child of user_data_path, so
+ // only return the one path in that case.
+ if (root_cache_path.empty() || user_data_path.IsParent(root_cache_path)) {
+ return {user_data_path};
+ }
+
+ return {user_data_path, root_cache_path};
+}
+
+bool AlloyContentBrowserClient::HandleExternalProtocol(
+ const GURL& url,
+ content::WebContents::Getter web_contents_getter,
+ int frame_tree_node_id,
+ content::NavigationUIData* navigation_data,
+ bool is_primary_main_frame,
+ bool is_in_fenced_frame_tree,
+ network::mojom::WebSandboxFlags sandbox_flags,
+ ui::PageTransition page_transition,
+ bool has_user_gesture,
+ const absl::optional<url::Origin>& initiating_origin,
+ content::RenderFrameHost* initiator_document,
+ mojo::PendingRemote<network::mojom::URLLoaderFactory>* out_factory) {
+ // Call the other HandleExternalProtocol variant.
+ return false;
+}
+
+bool AlloyContentBrowserClient::HandleExternalProtocol(
+ content::WebContents::Getter web_contents_getter,
+ int frame_tree_node_id,
+ content::NavigationUIData* navigation_data,
+ bool is_primary_main_frame,
+ bool is_in_fenced_frame_tree,
+ network::mojom::WebSandboxFlags sandbox_flags,
+ const network::ResourceRequest& resource_request,
+ const absl::optional<url::Origin>& initiating_origin,
+ content::RenderFrameHost* initiator_document,
+ mojo::PendingRemote<network::mojom::URLLoaderFactory>* out_factory) {
+ mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver =
+ out_factory->InitWithNewPipeAndPassReceiver();
+
+ // CefBrowserPlatformDelegate::HandleExternalProtocol may be called if
+ // nothing handles the request.
+ auto request_handler = net_service::CreateInterceptedRequestHandler(
+ web_contents_getter, frame_tree_node_id, resource_request,
+ base::BindRepeating(CefBrowserPlatformDelegate::HandleExternalProtocol,
+ resource_request.url));
+
+ net_service::ProxyURLLoaderFactory::CreateProxy(
+ web_contents_getter, std::move(receiver), std::move(request_handler));
+ return true;
+}
+
+std::unique_ptr<content::VideoOverlayWindow>
+AlloyContentBrowserClient::CreateWindowForVideoPictureInPicture(
+ content::VideoPictureInPictureWindowController* controller) {
+ // Note: content::VideoOverlayWindow::Create() is defined by platform-specific
+ // implementation in chrome/browser/ui/views. This layering hack, which goes
+ // through //content and ContentBrowserClient, allows us to work around the
+ // dependency constraints that disallow directly calling
+ // chrome/browser/ui/views code either from here or from other code in
+ // chrome/browser.
+ return content::VideoOverlayWindow::Create(controller);
+}
+
+void AlloyContentBrowserClient::RegisterBrowserInterfaceBindersForFrame(
+ content::RenderFrameHost* render_frame_host,
+ mojo::BinderMapWithContext<content::RenderFrameHost*>* map) {
+ CefBrowserFrame::RegisterBrowserInterfaceBindersForFrame(render_frame_host,
+ map);
+
+ map->Add<blink::mojom::BadgeService>(base::BindRepeating(&BindBadgeService));
+ map->Add<media::mojom::MediaFoundationRendererNotifier>(
+ base::BindRepeating(&BindMediaFoundationRendererNotifierHandler));
+ map->Add<network_hints::mojom::NetworkHintsHandler>(
+ base::BindRepeating(&BindNetworkHintsHandler));
+
+ if (!extensions::ExtensionsEnabled()) {
+ return;
+ }
+
+ content::WebContents* web_contents =
+ content::WebContents::FromRenderFrameHost(render_frame_host);
+ if (!web_contents) {
+ return;
+ }
+
+ const GURL& site = render_frame_host->GetSiteInstance()->GetSiteURL();
+ if (!site.SchemeIs(extensions::kExtensionScheme)) {
+ return;
+ }
+
+ content::BrowserContext* browser_context =
+ render_frame_host->GetProcess()->GetBrowserContext();
+ auto* extension = extensions::ExtensionRegistry::Get(browser_context)
+ ->enabled_extensions()
+ .GetByID(site.host());
+ if (!extension) {
+ return;
+ }
+ extensions::ExtensionsBrowserClient::Get()
+ ->RegisterBrowserInterfaceBindersForFrame(map, render_frame_host,
+ extension);
+}
+
+void AlloyContentBrowserClient::RegisterBrowserInterfaceBindersForServiceWorker(
+ content::BrowserContext* browser_context,
+ const content::ServiceWorkerVersionBaseInfo& service_worker_version_info,
+ mojo::BinderMapWithContext<const content::ServiceWorkerVersionBaseInfo&>*
+ map) {
+ map->Add<blink::mojom::BadgeService>(
+ base::BindRepeating(&BindBadgeServiceForServiceWorker));
+}
+
+base::FilePath
+AlloyContentBrowserClient::GetSandboxedStorageServiceDataDirectory() {
+ return GetRootCachePath();
+}
+
+std::string AlloyContentBrowserClient::GetProduct() {
+ return GetChromeProduct();
+}
+
+std::string AlloyContentBrowserClient::GetChromeProduct() {
+ return version_info::GetProductNameAndVersionForUserAgent();
+}
+
+std::string AlloyContentBrowserClient::GetUserAgent() {
+ return embedder_support::GetUserAgent();
+}
+
+std::string AlloyContentBrowserClient::GetFullUserAgent() {
+ return embedder_support::GetFullUserAgent();
+}
+
+std::string AlloyContentBrowserClient::GetReducedUserAgent() {
+ return embedder_support::GetReducedUserAgent();
+}
+
+std::unique_ptr<content::WebContentsViewDelegate>
+AlloyContentBrowserClient::GetWebContentsViewDelegate(
+ content::WebContents* web_contents) {
+ return std::make_unique<AlloyWebContentsViewDelegate>(web_contents);
+}
+
+blink::UserAgentMetadata AlloyContentBrowserClient::GetUserAgentMetadata() {
+ blink::UserAgentMetadata metadata;
+
+ metadata.brand_version_list = {blink::UserAgentBrandVersion{
+ version_info::GetProductName(), version_info::GetMajorVersionNumber()}};
+ metadata.full_version = version_info::GetVersionNumber();
+ metadata.platform = version_info::GetOSType();
+
+ // TODO(mkwst): Poke at BuildUserAgentFromProduct to split out these pieces.
+ metadata.architecture = "";
+ metadata.model = "";
+
+ return metadata;
+}
+
+base::flat_set<std::string>
+AlloyContentBrowserClient::GetPluginMimeTypesWithExternalHandlers(
+ content::BrowserContext* browser_context) {
+ base::flat_set<std::string> mime_types;
+ auto map = PluginUtils::GetMimeTypeToExtensionIdMap(browser_context);
+ for (const auto& pair : map) {
+ mime_types.insert(pair.first);
+ }
+ mime_types.insert(pdf::kInternalPluginMimeType);
+ return mime_types;
+}
+
+bool AlloyContentBrowserClient::ArePersistentMediaDeviceIDsAllowed(
+ content::BrowserContext* browser_context,
+ const GURL& url,
+ const net::SiteForCookies& site_for_cookies,
+ const absl::optional<url::Origin>& top_frame_origin) {
+ // Persistent MediaDevice IDs are allowed if cookies are allowed.
+ return CookieSettingsFactory::GetForProfile(
+ Profile::FromBrowserContext(browser_context))
+ ->IsFullCookieAccessAllowed(
+ url, site_for_cookies, top_frame_origin,
+ net::CookieSettingOverrides(),
+ content_settings::CookieSettings::QueryReason::kSiteStorage);
+}
+
+void AlloyContentBrowserClient::OnWebContentsCreated(
+ content::WebContents* web_contents) {
+ // Attach universal WebContentsObservers. These are quite rare, and in most
+ // cases CefBrowserPlatformDelegateAlloy::BrowserCreated and/or
+ // CefExtensionsAPIClient::AttachWebContentsHelpers should be used instead.
+
+ if (extensions::ExtensionsEnabled()) {
+ extensions::CefExtensionWebContentsObserver::CreateForWebContents(
+ web_contents);
+ }
+}
+
+bool AlloyContentBrowserClient::IsFindInPageDisabledForOrigin(
+ const url::Origin& origin) {
+ // For PDF viewing with the PPAPI-free PDF Viewer, find-in-page should only
+ // display results from the PDF content, and not from the UI.
+ return IsPdfExtensionOrigin(origin);
+}
+
+CefRefPtr<CefRequestContextImpl> AlloyContentBrowserClient::request_context()
+ const {
+ return browser_main_parts_->request_context();
+}
+
+CefDevToolsDelegate* AlloyContentBrowserClient::devtools_delegate() const {
+ return browser_main_parts_->devtools_delegate();
+}
+
+scoped_refptr<base::SingleThreadTaskRunner>
+AlloyContentBrowserClient::background_task_runner() const {
+ return browser_main_parts_->background_task_runner();
+}
+
+scoped_refptr<base::SingleThreadTaskRunner>
+AlloyContentBrowserClient::user_visible_task_runner() const {
+ return browser_main_parts_->user_visible_task_runner();
+}
+
+scoped_refptr<base::SingleThreadTaskRunner>
+AlloyContentBrowserClient::user_blocking_task_runner() const {
+ return browser_main_parts_->user_blocking_task_runner();
+}
+
+const extensions::Extension* AlloyContentBrowserClient::GetExtension(
+ content::SiteInstance* site_instance) {
+ extensions::ExtensionRegistry* registry =
+ extensions::ExtensionRegistry::Get(site_instance->GetBrowserContext());
+ if (!registry) {
+ return nullptr;
+ }
+ return registry->enabled_extensions().GetExtensionOrAppByURL(
+ site_instance->GetSiteURL());
+}
diff --git a/libcef/browser/alloy/alloy_content_browser_client.h b/libcef/browser/alloy/alloy_content_browser_client.h
new file mode 100644
index 00000000..21250725
--- /dev/null
+++ b/libcef/browser/alloy/alloy_content_browser_client.h
@@ -0,0 +1,264 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_ALLOY_ALLOY_CONTENT_BROWSER_CLIENT_H_
+#define CEF_LIBCEF_BROWSER_ALLOY_ALLOY_CONTENT_BROWSER_CLIENT_H_
+#pragma once
+
+#include <string>
+#include <utility>
+
+#include "include/cef_request_context_handler.h"
+#include "libcef/browser/request_context_impl.h"
+
+#include "base/memory/ref_counted.h"
+#include "build/build_config.h"
+#include "content/public/browser/content_browser_client.h"
+#include "third_party/skia/include/core/SkColor.h"
+
+class AlloyBrowserMainParts;
+class CefDevToolsDelegate;
+
+namespace content {
+class SiteInstance;
+} // namespace content
+
+namespace extensions {
+class Extension;
+}
+
+class AlloyContentBrowserClient : public content::ContentBrowserClient {
+ public:
+ AlloyContentBrowserClient();
+ ~AlloyContentBrowserClient() override;
+
+ // ContentBrowserClient implementation.
+ std::unique_ptr<content::BrowserMainParts> CreateBrowserMainParts(
+ bool is_integration_test) override;
+ void RenderProcessWillLaunch(content::RenderProcessHost* host) override;
+ bool ShouldUseProcessPerSite(content::BrowserContext* browser_context,
+ const GURL& site_url) override;
+ bool ShouldUseSpareRenderProcessHost(content::BrowserContext* browser_context,
+ const GURL& site_url) override;
+ bool DoesSiteRequireDedicatedProcess(content::BrowserContext* browser_context,
+ const GURL& effective_site_url) override;
+ bool ShouldTreatURLSchemeAsFirstPartyWhenTopLevel(
+ base::StringPiece scheme,
+ bool is_embedded_origin_secure) override;
+ bool ShouldIgnoreSameSiteCookieRestrictionsWhenTopLevel(
+ base::StringPiece scheme,
+ bool is_embedded_origin_secure) override;
+ void OverrideURLLoaderFactoryParams(
+ content::BrowserContext* browser_context,
+ const url::Origin& origin,
+ bool is_for_isolated_world,
+ network::mojom::URLLoaderFactoryParams* factory_params) override;
+ void GetAdditionalWebUISchemes(
+ std::vector<std::string>* additional_schemes) override;
+ void GetAdditionalViewSourceSchemes(
+ std::vector<std::string>* additional_schemes) override;
+ std::unique_ptr<ui::SelectFilePolicy> CreateSelectFilePolicy(
+ content::WebContents* web_contents) override;
+ void GetAdditionalAllowedSchemesForFileSystem(
+ std::vector<std::string>* additional_allowed_schemes) override;
+ bool IsWebUIAllowedToMakeNetworkRequests(const url::Origin& origin) override;
+ bool IsHandledURL(const GURL& url) override;
+ void SiteInstanceGotProcess(content::SiteInstance* site_instance) override;
+ void SiteInstanceDeleting(content::SiteInstance* site_instance) override;
+ void BindHostReceiverForRenderer(
+ content::RenderProcessHost* render_process_host,
+ mojo::GenericPendingReceiver receiver) override;
+ void AppendExtraCommandLineSwitches(base::CommandLine* command_line,
+ int child_process_id) override;
+ std::string GetApplicationLocale() override;
+ scoped_refptr<network::SharedURLLoaderFactory>
+ GetSystemSharedURLLoaderFactory() override;
+ network::mojom::NetworkContext* GetSystemNetworkContext() override;
+ content::MediaObserver* GetMediaObserver() override;
+ content::SpeechRecognitionManagerDelegate*
+ CreateSpeechRecognitionManagerDelegate() override;
+ content::GeneratedCodeCacheSettings GetGeneratedCodeCacheSettings(
+ content::BrowserContext* context) override;
+ void AllowCertificateError(
+ content::WebContents* web_contents,
+ int cert_error,
+ const net::SSLInfo& ssl_info,
+ const GURL& request_url,
+ bool is_main_frame_request,
+ bool strict_enforcement,
+ base::OnceCallback<void(content::CertificateRequestResultType)> callback)
+ override;
+ base::OnceClosure SelectClientCertificate(
+ content::WebContents* web_contents,
+ net::SSLCertRequestInfo* cert_request_info,
+ net::ClientCertIdentityList client_certs,
+ std::unique_ptr<content::ClientCertificateDelegate> delegate) override;
+ bool CanCreateWindow(content::RenderFrameHost* opener,
+ const GURL& opener_url,
+ const GURL& opener_top_level_frame_url,
+ const url::Origin& source_origin,
+ content::mojom::WindowContainerType container_type,
+ const GURL& target_url,
+ const content::Referrer& referrer,
+ const std::string& frame_name,
+ WindowOpenDisposition disposition,
+ const blink::mojom::WindowFeatures& features,
+ bool user_gesture,
+ bool opener_suppressed,
+ bool* no_javascript_access) override;
+ void OverrideWebkitPrefs(content::WebContents* web_contents,
+ blink::web_pref::WebPreferences* prefs) override;
+ bool OverrideWebPreferencesAfterNavigation(
+ content::WebContents* web_contents,
+ blink::web_pref::WebPreferences* prefs) override;
+ void BrowserURLHandlerCreated(content::BrowserURLHandler* handler) override;
+ std::string GetDefaultDownloadName() override;
+ void DidCreatePpapiPlugin(content::BrowserPpapiHost* browser_host) override;
+ std::unique_ptr<content::DevToolsManagerDelegate>
+ CreateDevToolsManagerDelegate() override;
+ void RegisterAssociatedInterfaceBindersForRenderFrameHost(
+ content::RenderFrameHost& render_frame_host,
+ blink::AssociatedInterfaceRegistry& associated_registry) override;
+ std::vector<std::unique_ptr<content::NavigationThrottle>>
+ CreateThrottlesForNavigation(
+ content::NavigationHandle* navigation_handle) override;
+ std::vector<std::unique_ptr<blink::URLLoaderThrottle>>
+ CreateURLLoaderThrottles(
+ const network::ResourceRequest& request,
+ content::BrowserContext* browser_context,
+ const base::RepeatingCallback<content::WebContents*()>& wc_getter,
+ content::NavigationUIData* navigation_ui_data,
+ int frame_tree_node_id) override;
+ std::vector<std::unique_ptr<content::URLLoaderRequestInterceptor>>
+ WillCreateURLLoaderRequestInterceptors(
+ content::NavigationUIData* navigation_ui_data,
+ int frame_tree_node_id) override;
+
+#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC)
+ void GetAdditionalMappedFilesForChildProcess(
+ const base::CommandLine& command_line,
+ int child_process_id,
+ content::PosixFileDescriptorInfo* mappings) override;
+#endif
+
+ void ExposeInterfacesToRenderer(
+ service_manager::BinderRegistry* registry,
+ blink::AssociatedInterfaceRegistry* associated_registry,
+ content::RenderProcessHost* render_process_host) override;
+ std::unique_ptr<net::ClientCertStore> CreateClientCertStore(
+ content::BrowserContext* browser_context) override;
+ std::unique_ptr<content::LoginDelegate> CreateLoginDelegate(
+ const net::AuthChallengeInfo& auth_info,
+ content::WebContents* web_contents,
+ const content::GlobalRequestID& request_id,
+ bool is_request_for_main_frame,
+ const GURL& url,
+ scoped_refptr<net::HttpResponseHeaders> response_headers,
+ bool first_auth_attempt,
+ LoginAuthRequiredCallback auth_required_callback) override;
+ void RegisterNonNetworkNavigationURLLoaderFactories(
+ int frame_tree_node_id,
+ ukm::SourceIdObj ukm_source_id,
+ NonNetworkURLLoaderFactoryMap* factories) override;
+ void RegisterNonNetworkSubresourceURLLoaderFactories(
+ int render_process_id,
+ int render_frame_id,
+ const absl::optional<url::Origin>& request_initiator_origin,
+ NonNetworkURLLoaderFactoryMap* factories) override;
+ bool WillCreateURLLoaderFactory(
+ content::BrowserContext* browser_context,
+ content::RenderFrameHost* frame,
+ int render_process_id,
+ URLLoaderFactoryType type,
+ const url::Origin& request_initiator,
+ absl::optional<int64_t> navigation_id,
+ ukm::SourceIdObj ukm_source_id,
+ mojo::PendingReceiver<network::mojom::URLLoaderFactory>* factory_receiver,
+ mojo::PendingRemote<network::mojom::TrustedURLLoaderHeaderClient>*
+ header_client,
+ bool* bypass_redirect_checks,
+ bool* disable_secure_dns,
+ network::mojom::URLLoaderFactoryOverridePtr* factory_override) override;
+ void OnNetworkServiceCreated(
+ network::mojom::NetworkService* network_service) override;
+ bool ConfigureNetworkContextParams(
+ content::BrowserContext* context,
+ bool in_memory,
+ const base::FilePath& relative_partition_path,
+ network::mojom::NetworkContextParams* network_context_params,
+ cert_verifier::mojom::CertVerifierCreationParams*
+ cert_verifier_creation_params) override;
+ std::vector<base::FilePath> GetNetworkContextsParentDirectory() override;
+ bool HandleExternalProtocol(
+ const GURL& url,
+ content::WebContents::Getter web_contents_getter,
+ int frame_tree_node_id,
+ content::NavigationUIData* navigation_data,
+ bool is_primary_main_frame,
+ bool is_in_fenced_frame_tree,
+ network::mojom::WebSandboxFlags sandbox_flags,
+ ui::PageTransition page_transition,
+ bool has_user_gesture,
+ const absl::optional<url::Origin>& initiating_origin,
+ content::RenderFrameHost* initiator_document,
+ mojo::PendingRemote<network::mojom::URLLoaderFactory>* out_factory)
+ override;
+ bool HandleExternalProtocol(
+ content::WebContents::Getter web_contents_getter,
+ int frame_tree_node_id,
+ content::NavigationUIData* navigation_data,
+ bool is_primary_main_frame,
+ bool is_in_fenced_frame_tree,
+ network::mojom::WebSandboxFlags sandbox_flags,
+ const network::ResourceRequest& request,
+ const absl::optional<url::Origin>& initiating_origin,
+ content::RenderFrameHost* initiator_document,
+ mojo::PendingRemote<network::mojom::URLLoaderFactory>* out_factory)
+ override;
+ std::unique_ptr<content::VideoOverlayWindow>
+ CreateWindowForVideoPictureInPicture(
+ content::VideoPictureInPictureWindowController* controller) override;
+ void RegisterBrowserInterfaceBindersForFrame(
+ content::RenderFrameHost* render_frame_host,
+ mojo::BinderMapWithContext<content::RenderFrameHost*>* map) override;
+ void RegisterBrowserInterfaceBindersForServiceWorker(
+ content::BrowserContext* browser_context,
+ const content::ServiceWorkerVersionBaseInfo& service_worker_version_info,
+ mojo::BinderMapWithContext<const content::ServiceWorkerVersionBaseInfo&>*
+ map) override;
+ base::FilePath GetSandboxedStorageServiceDataDirectory() override;
+ std::string GetProduct() override;
+ std::string GetChromeProduct() override;
+ std::string GetUserAgent() override;
+ std::string GetFullUserAgent() override;
+ std::string GetReducedUserAgent() override;
+ std::unique_ptr<content::WebContentsViewDelegate> GetWebContentsViewDelegate(
+ content::WebContents* web_contents) override;
+ blink::UserAgentMetadata GetUserAgentMetadata() override;
+ base::flat_set<std::string> GetPluginMimeTypesWithExternalHandlers(
+ content::BrowserContext* browser_context) override;
+ bool ArePersistentMediaDeviceIDsAllowed(
+ content::BrowserContext* browser_context,
+ const GURL& scope,
+ const net::SiteForCookies& site_for_cookies,
+ const absl::optional<url::Origin>& top_frame_origin) override;
+ void OnWebContentsCreated(content::WebContents* web_contents) override;
+ bool IsFindInPageDisabledForOrigin(const url::Origin& origin) override;
+
+ CefRefPtr<CefRequestContextImpl> request_context() const;
+ CefDevToolsDelegate* devtools_delegate() const;
+
+ scoped_refptr<base::SingleThreadTaskRunner> background_task_runner() const;
+ scoped_refptr<base::SingleThreadTaskRunner> user_visible_task_runner() const;
+ scoped_refptr<base::SingleThreadTaskRunner> user_blocking_task_runner() const;
+
+ private:
+ // Returns the extension or app associated with |site_instance| or NULL.
+ const extensions::Extension* GetExtension(
+ content::SiteInstance* site_instance);
+
+ AlloyBrowserMainParts* browser_main_parts_ = nullptr;
+};
+
+#endif // CEF_LIBCEF_BROWSER_ALLOY_ALLOY_CONTENT_BROWSER_CLIENT_H_
diff --git a/libcef/browser/alloy/alloy_download_util.cc b/libcef/browser/alloy/alloy_download_util.cc
new file mode 100644
index 00000000..92e52b6a
--- /dev/null
+++ b/libcef/browser/alloy/alloy_download_util.cc
@@ -0,0 +1,16 @@
+// Copyright 2021 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#include "libcef/browser/alloy/alloy_download_util.h"
+
+#include "libcef/browser/alloy/alloy_browser_context.h"
+
+namespace alloy {
+
+DownloadPrefs* GetDownloadPrefsFromBrowserContext(
+ content::BrowserContext* context) {
+ return static_cast<AlloyBrowserContext*>(context)->GetDownloadPrefs();
+}
+
+} // namespace alloy
diff --git a/libcef/browser/alloy/alloy_download_util.h b/libcef/browser/alloy/alloy_download_util.h
new file mode 100644
index 00000000..51c2e285
--- /dev/null
+++ b/libcef/browser/alloy/alloy_download_util.h
@@ -0,0 +1,23 @@
+// Copyright 2021 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_ALLOY_ALLOY_DOWNLOAD_UTIL_H_
+#define CEF_LIBCEF_BROWSER_ALLOY_ALLOY_DOWNLOAD_UTIL_H_
+#pragma once
+
+class DownloadPrefs;
+
+namespace content {
+class BrowserContext;
+} // namespace content
+
+namespace alloy {
+
+// Called from DownloadPrefs::FromBrowserContext.
+DownloadPrefs* GetDownloadPrefsFromBrowserContext(
+ content::BrowserContext* context);
+
+} // namespace alloy
+
+#endif // CEF_LIBCEF_BROWSER_ALLOY_ALLOY_DOWNLOAD_UTIL_H_
diff --git a/libcef/browser/alloy/alloy_web_contents_view_delegate.cc b/libcef/browser/alloy/alloy_web_contents_view_delegate.cc
new file mode 100644
index 00000000..39a65dc5
--- /dev/null
+++ b/libcef/browser/alloy/alloy_web_contents_view_delegate.cc
@@ -0,0 +1,22 @@
+// Copyright 2022 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/alloy/alloy_web_contents_view_delegate.h"
+
+#include "content/public/browser/web_contents.h"
+
+#include "libcef/browser/alloy/alloy_browser_host_impl.h"
+
+AlloyWebContentsViewDelegate::AlloyWebContentsViewDelegate(
+ content::WebContents* web_contents)
+ : web_contents_(web_contents) {}
+
+void AlloyWebContentsViewDelegate::ShowContextMenu(
+ content::RenderFrameHost& render_frame_host,
+ const content::ContextMenuParams& params) {
+ if (auto browser =
+ AlloyBrowserHostImpl::GetBrowserForContents(web_contents_)) {
+ browser->ShowContextMenu(params);
+ }
+}
diff --git a/libcef/browser/alloy/alloy_web_contents_view_delegate.h b/libcef/browser/alloy/alloy_web_contents_view_delegate.h
new file mode 100644
index 00000000..17992dfe
--- /dev/null
+++ b/libcef/browser/alloy/alloy_web_contents_view_delegate.h
@@ -0,0 +1,33 @@
+// Copyright 2022 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_ALLOY_ALLOY_WEB_CONTENTS_VIEW_DELEGATE_H_
+#define CEF_LIBCEF_BROWSER_ALLOY_ALLOY_WEB_CONTENTS_VIEW_DELEGATE_H_
+#pragma once
+
+#include "include/internal/cef_ptr.h"
+
+#include "content/public/browser/web_contents_view_delegate.h"
+
+namespace content {
+class WebContents;
+}
+
+class AlloyWebContentsViewDelegate : public content::WebContentsViewDelegate {
+ public:
+ explicit AlloyWebContentsViewDelegate(content::WebContents* web_contents);
+
+ AlloyWebContentsViewDelegate(const AlloyWebContentsViewDelegate&) = delete;
+ AlloyWebContentsViewDelegate& operator=(const AlloyWebContentsViewDelegate&) =
+ delete;
+
+ // WebContentsViewDelegate methods:
+ void ShowContextMenu(content::RenderFrameHost& render_frame_host,
+ const content::ContextMenuParams& params) override;
+
+ private:
+ content::WebContents* const web_contents_;
+};
+
+#endif // CEF_LIBCEF_BROWSER_ALLOY_ALLOY_WEB_CONTENTS_VIEW_DELEGATE_H_
diff --git a/libcef/browser/alloy/browser_platform_delegate_alloy.cc b/libcef/browser/alloy/browser_platform_delegate_alloy.cc
new file mode 100644
index 00000000..2a8b43b1
--- /dev/null
+++ b/libcef/browser/alloy/browser_platform_delegate_alloy.cc
@@ -0,0 +1,450 @@
+// Copyright 2015 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/alloy/browser_platform_delegate_alloy.h"
+
+#include "libcef/browser/alloy/alloy_browser_host_impl.h"
+#include "libcef/browser/alloy/dialogs/alloy_javascript_dialog_manager_delegate.h"
+#include "libcef/browser/extensions/browser_extensions_util.h"
+#include "libcef/browser/extensions/extension_background_host.h"
+#include "libcef/browser/extensions/extension_system.h"
+#include "libcef/browser/extensions/extension_view_host.h"
+#include "libcef/browser/extensions/extension_web_contents_observer.h"
+#include "libcef/common/extensions/extensions_util.h"
+#include "libcef/common/net/url_util.h"
+#include "libcef/features/runtime_checks.h"
+
+#include "base/logging.h"
+#include "chrome/browser/printing/print_view_manager.h"
+#include "chrome/browser/ui/prefs/prefs_tab_helper.h"
+#include "components/find_in_page/find_tab_helper.h"
+#include "components/find_in_page/find_types.h"
+#include "components/javascript_dialogs/tab_modal_dialog_manager.h"
+#include "components/permissions/permission_request_manager.h"
+#include "components/zoom/zoom_controller.h"
+#include "content/browser/renderer_host/render_widget_host_impl.h"
+#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/public/browser/render_view_host.h"
+#include "extensions/browser/process_manager.h"
+#include "pdf/pdf_features.h"
+#include "third_party/blink/public/mojom/frame/find_in_page.mojom.h"
+
+CefBrowserPlatformDelegateAlloy::CefBrowserPlatformDelegateAlloy()
+ : weak_ptr_factory_(this) {}
+
+content::WebContents* CefBrowserPlatformDelegateAlloy::CreateWebContents(
+ CefBrowserCreateParams& create_params,
+ bool& own_web_contents) {
+ REQUIRE_ALLOY_RUNTIME();
+ DCHECK(primary_);
+
+ // Get or create the request context and browser context.
+ CefRefPtr<CefRequestContextImpl> request_context_impl =
+ CefRequestContextImpl::GetOrCreateForRequestContext(
+ create_params.request_context);
+ CHECK(request_context_impl);
+ auto cef_browser_context = request_context_impl->GetBrowserContext();
+ CHECK(cef_browser_context);
+ auto browser_context = cef_browser_context->AsBrowserContext();
+
+ if (!create_params.request_context) {
+ // Using the global request context.
+ create_params.request_context = request_context_impl.get();
+ }
+
+ scoped_refptr<content::SiteInstance> site_instance;
+ if (extensions::ExtensionsEnabled() && !create_params.url.empty()) {
+ GURL gurl = url_util::MakeGURL(create_params.url, /*fixup=*/true);
+ if (!create_params.extension) {
+ // We might be loading an extension app view where the extension URL is
+ // provided by the client.
+ create_params.extension =
+ extensions::GetExtensionForUrl(browser_context, gurl);
+ }
+ if (create_params.extension) {
+ if (create_params.extension_host_type ==
+ extensions::mojom::ViewType::kInvalid) {
+ // Default to dialog behavior.
+ create_params.extension_host_type =
+ extensions::mojom::ViewType::kExtensionDialog;
+ }
+
+ // Extension resources will fail to load if we don't use a SiteInstance
+ // associated with the extension.
+ // (AlloyContentBrowserClient::SiteInstanceGotProcess won't find the
+ // extension to register with InfoMap, and AllowExtensionResourceLoad in
+ // ExtensionProtocolHandler::MaybeCreateJob will return false resulting in
+ // ERR_BLOCKED_BY_CLIENT).
+ site_instance = extensions::ProcessManager::Get(browser_context)
+ ->GetSiteInstanceForURL(gurl);
+ DCHECK(site_instance);
+ }
+ }
+
+ content::WebContents::CreateParams wc_create_params(browser_context,
+ site_instance);
+
+ if (IsWindowless()) {
+ // Create the OSR view for the WebContents.
+ CreateViewForWebContents(&wc_create_params.view,
+ &wc_create_params.delegate_view);
+ }
+
+ auto web_contents = content::WebContents::Create(wc_create_params);
+ CHECK(web_contents);
+
+ own_web_contents = true;
+ return web_contents.release();
+}
+
+void CefBrowserPlatformDelegateAlloy::WebContentsCreated(
+ content::WebContents* web_contents,
+ bool owned) {
+ CefBrowserPlatformDelegate::WebContentsCreated(web_contents, owned);
+
+ if (primary_) {
+ find_in_page::FindTabHelper::CreateForWebContents(web_contents);
+
+ if (owned) {
+ SetOwnedWebContents(web_contents);
+ }
+ } else {
+ DCHECK(!owned);
+ }
+}
+
+void CefBrowserPlatformDelegateAlloy::AddNewContents(
+ content::WebContents* source,
+ std::unique_ptr<content::WebContents> new_contents,
+ const GURL& target_url,
+ WindowOpenDisposition disposition,
+ const blink::mojom::WindowFeatures& window_features,
+ bool user_gesture,
+ bool* was_blocked) {
+ REQUIRE_ALLOY_RUNTIME();
+ DCHECK(primary_);
+
+ CefRefPtr<AlloyBrowserHostImpl> owner =
+ AlloyBrowserHostImpl::GetBrowserForContents(new_contents.get());
+ if (owner) {
+ // Taking ownership of |new_contents|.
+ static_cast<CefBrowserPlatformDelegateAlloy*>(
+ owner->platform_delegate_.get())
+ ->SetOwnedWebContents(new_contents.release());
+ return;
+ }
+
+ if (extension_host_) {
+ extension_host_->AddNewContents(source, std::move(new_contents), target_url,
+ disposition, window_features, user_gesture,
+ was_blocked);
+ }
+}
+
+bool CefBrowserPlatformDelegateAlloy::
+ ShouldAllowRendererInitiatedCrossProcessNavigation(
+ bool is_main_frame_navigation) {
+ if (extension_host_) {
+ return extension_host_->ShouldAllowRendererInitiatedCrossProcessNavigation(
+ is_main_frame_navigation);
+ }
+ return true;
+}
+
+void CefBrowserPlatformDelegateAlloy::RenderViewReady() {
+ ConfigureAutoResize();
+}
+
+void CefBrowserPlatformDelegateAlloy::BrowserCreated(
+ CefBrowserHostBase* browser) {
+ CefBrowserPlatformDelegate::BrowserCreated(browser);
+
+ // Only register WebContents delegate/observers if we're the primary delegate.
+ if (!primary_) {
+ return;
+ }
+
+ DCHECK(!web_contents_->GetDelegate());
+ web_contents_->SetDelegate(static_cast<AlloyBrowserHostImpl*>(browser));
+
+ permissions::PermissionRequestManager::CreateForWebContents(web_contents_);
+ PrefsTabHelper::CreateForWebContents(web_contents_);
+ printing::PrintViewManager::CreateForWebContents(web_contents_);
+
+ if (extensions::ExtensionsEnabled()) {
+ // Used by the tabs extension API.
+ zoom::ZoomController::CreateForWebContents(web_contents_);
+ }
+
+ javascript_dialogs::TabModalDialogManager::CreateForWebContents(
+ web_contents_,
+ CreateAlloyJavaScriptTabModalDialogManagerDelegateDesktop(web_contents_));
+
+ // Used for print preview and JavaScript dialogs.
+ web_contents_dialog_helper_.reset(
+ new AlloyWebContentsDialogHelper(web_contents_, this));
+}
+
+void CefBrowserPlatformDelegateAlloy::CreateExtensionHost(
+ const extensions::Extension* extension,
+ const GURL& url,
+ extensions::mojom::ViewType host_type) {
+ REQUIRE_ALLOY_RUNTIME();
+ DCHECK(primary_);
+
+ // Should get WebContentsCreated and BrowserCreated calls first.
+ DCHECK(web_contents_);
+ DCHECK(browser_);
+ DCHECK(!extension_host_);
+
+ auto alloy_browser = static_cast<AlloyBrowserHostImpl*>(browser_);
+
+ if (host_type == extensions::mojom::ViewType::kExtensionDialog ||
+ host_type == extensions::mojom::ViewType::kExtensionPopup) {
+ // Create an extension host that we own.
+ extension_host_ = new extensions::CefExtensionViewHost(
+ alloy_browser, extension, web_contents_, url, host_type);
+ // Trigger load of the extension URL.
+ extension_host_->CreateRendererSoon();
+ } else if (host_type ==
+ extensions::mojom::ViewType::kExtensionBackgroundPage) {
+ is_background_host_ = true;
+ alloy_browser->is_background_host_ = true;
+ // Create an extension host that will be owned by ProcessManager.
+ extension_host_ = new extensions::CefExtensionBackgroundHost(
+ alloy_browser,
+ base::BindOnce(&CefBrowserPlatformDelegateAlloy::OnExtensionHostDeleted,
+ weak_ptr_factory_.GetWeakPtr()),
+ extension, web_contents_, url, host_type);
+ // Load will be triggered by ProcessManager::CreateBackgroundHost.
+ } else {
+ NOTREACHED() << " Unsupported extension host type: " << host_type;
+ }
+}
+
+extensions::ExtensionHost* CefBrowserPlatformDelegateAlloy::GetExtensionHost()
+ const {
+ return extension_host_;
+}
+
+void CefBrowserPlatformDelegateAlloy::BrowserDestroyed(
+ CefBrowserHostBase* browser) {
+ if (primary_) {
+ DestroyExtensionHost();
+ owned_web_contents_.reset();
+ }
+
+ CefBrowserPlatformDelegate::BrowserDestroyed(browser);
+}
+
+web_modal::WebContentsModalDialogHost*
+CefBrowserPlatformDelegateAlloy::GetWebContentsModalDialogHost() const {
+ return web_contents_dialog_helper_.get();
+}
+
+void CefBrowserPlatformDelegateAlloy::SendCaptureLostEvent() {
+ if (!web_contents_) {
+ return;
+ }
+ content::RenderViewHost* host = web_contents_->GetRenderViewHost();
+ if (!host) {
+ return;
+ }
+
+ content::RenderWidgetHostImpl* widget =
+ content::RenderWidgetHostImpl::From(host->GetWidget());
+ if (widget) {
+ widget->LostCapture();
+ }
+}
+
+#if BUILDFLAG(IS_WIN) || (BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC))
+void CefBrowserPlatformDelegateAlloy::NotifyMoveOrResizeStarted() {
+ if (!browser_) {
+ return;
+ }
+
+ // Dismiss any existing popups.
+ auto frame = browser_->GetMainFrame();
+ if (frame && frame->IsValid()) {
+ static_cast<CefFrameHostImpl*>(frame.get())->NotifyMoveOrResizeStarted();
+ }
+}
+#endif
+
+bool CefBrowserPlatformDelegateAlloy::PreHandleGestureEvent(
+ content::WebContents* source,
+ const blink::WebGestureEvent& event) {
+ if (extension_host_) {
+ return extension_host_->PreHandleGestureEvent(source, event);
+ }
+ return false;
+}
+
+bool CefBrowserPlatformDelegateAlloy::IsNeverComposited(
+ content::WebContents* web_contents) {
+ if (extension_host_) {
+ return extension_host_->IsNeverComposited(web_contents);
+ }
+ return false;
+}
+
+void CefBrowserPlatformDelegateAlloy::SetAutoResizeEnabled(
+ bool enabled,
+ const CefSize& min_size,
+ const CefSize& max_size) {
+ if (enabled == auto_resize_enabled_) {
+ return;
+ }
+
+ auto_resize_enabled_ = enabled;
+ if (enabled) {
+ auto_resize_min_ = gfx::Size(min_size.width, min_size.height);
+ auto_resize_max_ = gfx::Size(max_size.width, max_size.height);
+ } else {
+ auto_resize_min_ = auto_resize_max_ = gfx::Size();
+ }
+ ConfigureAutoResize();
+}
+
+void CefBrowserPlatformDelegateAlloy::ConfigureAutoResize() {
+ if (!web_contents_ || !web_contents_->GetRenderWidgetHostView()) {
+ return;
+ }
+
+ if (auto_resize_enabled_) {
+ web_contents_->GetRenderWidgetHostView()->EnableAutoResize(
+ auto_resize_min_, auto_resize_max_);
+ } else {
+ web_contents_->GetRenderWidgetHostView()->DisableAutoResize(gfx::Size());
+ }
+}
+
+void CefBrowserPlatformDelegateAlloy::SetAccessibilityState(
+ cef_state_t accessibility_state) {
+ // Do nothing if state is set to default. It'll be disabled by default and
+ // controlled by the commmand-line flags "force-renderer-accessibility" and
+ // "disable-renderer-accessibility".
+ if (accessibility_state == STATE_DEFAULT) {
+ return;
+ }
+
+ content::WebContentsImpl* web_contents_impl =
+ static_cast<content::WebContentsImpl*>(web_contents_);
+
+ if (!web_contents_impl) {
+ return;
+ }
+
+ ui::AXMode accMode;
+ // In windowless mode set accessibility to TreeOnly mode. Else native
+ // accessibility APIs, specific to each platform, are also created.
+ if (accessibility_state == STATE_ENABLED) {
+ accMode = IsWindowless() ? ui::kAXModeWebContentsOnly : ui::kAXModeComplete;
+ }
+ web_contents_impl->SetAccessibilityMode(accMode);
+}
+
+bool CefBrowserPlatformDelegateAlloy::IsPrintPreviewSupported() const {
+ REQUIRE_ALLOY_RUNTIME();
+
+ // Print preview is not currently supported with OSR.
+ if (IsWindowless()) {
+ return false;
+ }
+
+ auto cef_browser_context =
+ CefBrowserContext::FromBrowserContext(web_contents_->GetBrowserContext());
+ return cef_browser_context->IsPrintPreviewSupported();
+}
+
+void CefBrowserPlatformDelegateAlloy::Find(const CefString& searchText,
+ bool forward,
+ bool matchCase,
+ bool findNext) {
+ if (!web_contents_) {
+ return;
+ }
+
+ find_in_page::FindTabHelper::FromWebContents(web_contents_)
+ ->StartFinding(searchText.ToString16(), forward, matchCase, findNext,
+ /*run_synchronously_for_testing=*/false);
+}
+
+void CefBrowserPlatformDelegateAlloy::StopFinding(bool clearSelection) {
+ if (!web_contents_) {
+ return;
+ }
+
+ last_search_result_ = find_in_page::FindNotificationDetails();
+ find_in_page::FindTabHelper::FromWebContents(web_contents_)
+ ->StopFinding(clearSelection ? find_in_page::SelectionAction::kClear
+ : find_in_page::SelectionAction::kKeep);
+}
+
+bool CefBrowserPlatformDelegateAlloy::HandleFindReply(
+ int request_id,
+ int number_of_matches,
+ const gfx::Rect& selection_rect,
+ int active_match_ordinal,
+ bool final_update) {
+ if (!web_contents_) {
+ return false;
+ }
+
+ auto find_in_page =
+ find_in_page::FindTabHelper::FromWebContents(web_contents_);
+
+ find_in_page->HandleFindReply(request_id, number_of_matches, selection_rect,
+ active_match_ordinal, final_update);
+ if (!(find_in_page->find_result() == last_search_result_)) {
+ last_search_result_ = find_in_page->find_result();
+ return true;
+ }
+ return false;
+}
+
+base::RepeatingClosure
+CefBrowserPlatformDelegateAlloy::GetBoundsChangedCallback() {
+ if (web_contents_dialog_helper_) {
+ return web_contents_dialog_helper_->GetBoundsChangedCallback();
+ }
+
+ return base::RepeatingClosure();
+}
+
+void CefBrowserPlatformDelegateAlloy::SetOwnedWebContents(
+ content::WebContents* owned_contents) {
+ DCHECK(primary_);
+
+ // Should not currently own a WebContents.
+ CHECK(!owned_web_contents_);
+ owned_web_contents_.reset(owned_contents);
+}
+
+void CefBrowserPlatformDelegateAlloy::DestroyExtensionHost() {
+ if (!extension_host_) {
+ return;
+ }
+ if (extension_host_->extension_host_type() ==
+ extensions::mojom::ViewType::kExtensionBackgroundPage) {
+ DCHECK(is_background_host_);
+ // Close notification for background pages arrives via CloseContents.
+ // The extension host will be deleted by
+ // ProcessManager::CloseBackgroundHost and OnExtensionHostDeleted will be
+ // called to notify us.
+ extension_host_->Close();
+ } else {
+ DCHECK(!is_background_host_);
+ // We own the extension host and must delete it.
+ delete extension_host_;
+ extension_host_ = nullptr;
+ }
+}
+
+void CefBrowserPlatformDelegateAlloy::OnExtensionHostDeleted() {
+ DCHECK(is_background_host_);
+ DCHECK(extension_host_);
+ extension_host_ = nullptr;
+}
diff --git a/libcef/browser/alloy/browser_platform_delegate_alloy.h b/libcef/browser/alloy/browser_platform_delegate_alloy.h
new file mode 100644
index 00000000..dbd9e5c0
--- /dev/null
+++ b/libcef/browser/alloy/browser_platform_delegate_alloy.h
@@ -0,0 +1,121 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors.
+// Portions copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_ALLOY_BROWSER_PLATFORM_DELEGATE_ALLOY_H_
+#define CEF_LIBCEF_BROWSER_ALLOY_BROWSER_PLATFORM_DELEGATE_ALLOY_H_
+
+#include "libcef/browser/alloy/dialogs/alloy_web_contents_dialog_helper.h"
+#include "libcef/browser/browser_platform_delegate.h"
+
+#include "base/memory/weak_ptr.h"
+#include "components/find_in_page/find_notification_details.h"
+#include "content/public/browser/web_contents.h"
+#include "ui/gfx/geometry/size.h"
+
+// Implementation of Alloy-based browser functionality.
+class CefBrowserPlatformDelegateAlloy : public CefBrowserPlatformDelegate {
+ public:
+ CefBrowserPlatformDelegateAlloy(const CefBrowserPlatformDelegateAlloy&) =
+ delete;
+ CefBrowserPlatformDelegateAlloy& operator=(
+ const CefBrowserPlatformDelegateAlloy&) = delete;
+
+ content::WebContents* CreateWebContents(CefBrowserCreateParams& create_params,
+ bool& own_web_contents) override;
+ void WebContentsCreated(content::WebContents* web_contents,
+ bool owned) override;
+ void AddNewContents(content::WebContents* source,
+ std::unique_ptr<content::WebContents> new_contents,
+ const GURL& target_url,
+ WindowOpenDisposition disposition,
+ const blink::mojom::WindowFeatures& window_features,
+ bool user_gesture,
+ bool* was_blocked) override;
+ bool ShouldAllowRendererInitiatedCrossProcessNavigation(
+ bool is_main_frame_navigation) override;
+ void RenderViewReady() override;
+ void BrowserCreated(CefBrowserHostBase* browser) override;
+ void CreateExtensionHost(const extensions::Extension* extension,
+ const GURL& url,
+ extensions::mojom::ViewType host_type) override;
+ extensions::ExtensionHost* GetExtensionHost() const override;
+ void BrowserDestroyed(CefBrowserHostBase* browser) override;
+ web_modal::WebContentsModalDialogHost* GetWebContentsModalDialogHost()
+ const override;
+ void SendCaptureLostEvent() override;
+#if BUILDFLAG(IS_WIN) || (BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC))
+ void NotifyMoveOrResizeStarted() override;
+#endif
+ bool PreHandleGestureEvent(content::WebContents* source,
+ const blink::WebGestureEvent& event) override;
+ bool IsNeverComposited(content::WebContents* web_contents) override;
+ void SetAutoResizeEnabled(bool enabled,
+ const CefSize& min_size,
+ const CefSize& max_size) override;
+ void SetAccessibilityState(cef_state_t accessibility_state) override;
+ bool IsPrintPreviewSupported() const override;
+ void Find(const CefString& searchText,
+ bool forward,
+ bool matchCase,
+ bool findNext) override;
+ void StopFinding(bool clearSelection) override;
+
+ // Called from AlloyBrowserHostImpl::FindReply().
+ bool HandleFindReply(int request_id,
+ int number_of_matches,
+ const gfx::Rect& selection_rect,
+ int active_match_ordinal,
+ bool final_update);
+
+ const find_in_page::FindNotificationDetails& last_search_result() const {
+ return last_search_result_;
+ }
+
+ protected:
+ CefBrowserPlatformDelegateAlloy();
+
+ base::RepeatingClosure GetBoundsChangedCallback();
+
+ // Called from BrowserPlatformDelegateNative::set_windowless_handler().
+ void set_as_secondary() { primary_ = false; }
+
+ private:
+ void SetOwnedWebContents(content::WebContents* owned_contents);
+
+ void DestroyExtensionHost();
+ void OnExtensionHostDeleted();
+
+ void ConfigureAutoResize();
+
+ // Non-nullptr if this object owns the WebContents. Will be nullptr for popup
+ // browsers between the calls to WebContentsCreated() and AddNewContents(),
+ // and may never be set if the parent browser is destroyed during popup
+ // creation.
+ std::unique_ptr<content::WebContents> owned_web_contents_;
+
+ // Used for the print preview dialog.
+ std::unique_ptr<AlloyWebContentsDialogHelper> web_contents_dialog_helper_;
+
+ // The last find result. This object contains details about the number of
+ // matches, the find selection rectangle, etc.
+ find_in_page::FindNotificationDetails last_search_result_;
+
+ // Used when the browser is hosting an extension.
+ extensions::ExtensionHost* extension_host_ = nullptr;
+ bool is_background_host_ = false;
+
+ // Used with auto-resize.
+ bool auto_resize_enabled_ = false;
+ gfx::Size auto_resize_min_;
+ gfx::Size auto_resize_max_;
+
+ // True if this is the primary platform delegate, in which case it will
+ // register WebContents delegate/observers.
+ bool primary_ = true;
+
+ base::WeakPtrFactory<CefBrowserPlatformDelegateAlloy> weak_ptr_factory_;
+};
+
+#endif // CEF_LIBCEF_BROWSER_ALLOY_BROWSER_PLATFORM_DELEGATE_ALLOY_H_
diff --git a/libcef/browser/alloy/chrome_browser_process_alloy.cc b/libcef/browser/alloy/chrome_browser_process_alloy.cc
new file mode 100644
index 00000000..ef9d0626
--- /dev/null
+++ b/libcef/browser/alloy/chrome_browser_process_alloy.cc
@@ -0,0 +1,428 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors.
+// Portions (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/alloy/chrome_browser_process_alloy.h"
+
+#include "libcef/browser/alloy/chrome_profile_manager_alloy.h"
+#include "libcef/browser/browser_context.h"
+#include "libcef/browser/context.h"
+#include "libcef/browser/extensions/extensions_browser_client.h"
+#include "libcef/browser/prefs/browser_prefs.h"
+#include "libcef/browser/thread_util.h"
+#include "libcef/common/cef_switches.h"
+#include "libcef/common/extensions/extensions_client.h"
+#include "libcef/common/extensions/extensions_util.h"
+
+#include "base/command_line.h"
+#include "chrome/browser/component_updater/chrome_component_updater_configurator.h"
+#include "chrome/browser/net/system_network_context_manager.h"
+#include "chrome/browser/permissions/chrome_permissions_client.h"
+#include "chrome/browser/policy/chrome_browser_policy_connector.h"
+#include "chrome/browser/printing/background_printing_manager.h"
+#include "chrome/browser/printing/print_job_manager.h"
+#include "chrome/browser/printing/print_preview_dialog_controller.h"
+#include "chrome/browser/ui/prefs/pref_watcher.h"
+#include "components/component_updater/component_updater_service.h"
+#include "components/component_updater/timer_update_scheduler.h"
+#include "components/net_log/chrome_net_log.h"
+#include "components/prefs/pref_service.h"
+#include "content/browser/startup_helper.h"
+#include "content/public/browser/network_service_instance.h"
+#include "content/public/common/content_switches.h"
+#include "net/log/net_log_capture_mode.h"
+#include "services/network/public/cpp/network_switches.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+
+ChromeBrowserProcessAlloy::ChromeBrowserProcessAlloy()
+ : initialized_(false),
+ context_initialized_(false),
+ shutdown_(false),
+ locale_("en-US") {}
+
+ChromeBrowserProcessAlloy::~ChromeBrowserProcessAlloy() {
+ DCHECK((!initialized_ && !context_initialized_) || shutdown_);
+
+ if (extensions::ExtensionsEnabled()) {
+ extensions::ExtensionsBrowserClient::Set(nullptr);
+ extensions_browser_client_.reset();
+ }
+}
+
+void ChromeBrowserProcessAlloy::Initialize() {
+ DCHECK(!initialized_);
+ DCHECK(!context_initialized_);
+ DCHECK(!shutdown_);
+ DCHECK(!field_trial_list_);
+
+ // Initialize this early before any code tries to check feature flags.
+ field_trial_list_ = content::SetUpFieldTrialsAndFeatureList();
+
+ if (extensions::ExtensionsEnabled()) {
+ // Initialize extension global objects before creating the global
+ // BrowserContext.
+ extensions_client_.reset(new extensions::CefExtensionsClient());
+ extensions::ExtensionsClient::Set(extensions_client_.get());
+ extensions_browser_client_.reset(
+ new extensions::CefExtensionsBrowserClient);
+ extensions::ExtensionsBrowserClient::Set(extensions_browser_client_.get());
+ }
+
+ // Make sure permissions client has been set.
+ ChromePermissionsClient::GetInstance();
+
+ initialized_ = true;
+}
+
+void ChromeBrowserProcessAlloy::OnContextInitialized() {
+ CEF_REQUIRE_UIT();
+ DCHECK(initialized_);
+ DCHECK(!context_initialized_);
+ DCHECK(!shutdown_);
+
+ // Must be created after the NotificationService.
+ print_job_manager_.reset(new printing::PrintJobManager());
+ profile_manager_.reset(new ChromeProfileManagerAlloy());
+ event_router_forwarder_ = new extensions::EventRouterForwarder();
+ context_initialized_ = true;
+}
+
+void ChromeBrowserProcessAlloy::CleanupOnUIThread() {
+ CEF_REQUIRE_UIT();
+ DCHECK(initialized_);
+ DCHECK(context_initialized_);
+ DCHECK(!shutdown_);
+
+ // Wait for the pending print jobs to finish. Don't do this later, since
+ // this might cause a nested message loop to run, and we don't want pending
+ // tasks to run once teardown has started.
+ print_job_manager_->Shutdown();
+ print_job_manager_.reset(nullptr);
+ print_preview_dialog_controller_ = nullptr;
+
+ profile_manager_.reset();
+ event_router_forwarder_ = nullptr;
+
+ if (SystemNetworkContextManager::GetInstance()) {
+ SystemNetworkContextManager::DeleteInstance();
+ }
+
+ // Release any references held by objects associated with a Profile. The
+ // Profile will be deleted later.
+ for (const auto& browser_context : CefBrowserContext::GetAll()) {
+ // Release any references to |local_state_|.
+ auto profile = browser_context->AsProfile();
+ PrefWatcher* pref_watcher = PrefWatcher::Get(profile);
+ if (pref_watcher) {
+ pref_watcher->Shutdown();
+ }
+
+ // Unregister observers for |background_printing_manager_|.
+ if (background_printing_manager_) {
+ background_printing_manager_->DeletePreviewContentsForBrowserContext(
+ profile);
+ }
+ }
+
+ local_state_.reset();
+ browser_policy_connector_.reset();
+ background_printing_manager_.reset();
+ field_trial_list_.reset();
+ component_updater_.reset();
+
+ shutdown_ = true;
+}
+
+void ChromeBrowserProcessAlloy::EndSession() {
+ NOTREACHED();
+}
+
+void ChromeBrowserProcessAlloy::FlushLocalStateAndReply(
+ base::OnceClosure reply) {
+ NOTREACHED();
+}
+
+metrics_services_manager::MetricsServicesManager*
+ChromeBrowserProcessAlloy::GetMetricsServicesManager() {
+ NOTREACHED();
+ return nullptr;
+}
+
+metrics::MetricsService* ChromeBrowserProcessAlloy::metrics_service() {
+ NOTREACHED();
+ return nullptr;
+}
+
+SystemNetworkContextManager*
+ChromeBrowserProcessAlloy::system_network_context_manager() {
+ DCHECK(SystemNetworkContextManager::GetInstance());
+ return SystemNetworkContextManager::GetInstance();
+}
+
+network::NetworkQualityTracker*
+ChromeBrowserProcessAlloy::network_quality_tracker() {
+ NOTREACHED();
+ return nullptr;
+}
+
+ProfileManager* ChromeBrowserProcessAlloy::profile_manager() {
+ DCHECK(context_initialized_);
+ return profile_manager_.get();
+}
+
+PrefService* ChromeBrowserProcessAlloy::local_state() {
+ DCHECK(initialized_);
+ if (!local_state_) {
+ // Use a location that is shared by all request contexts.
+ const CefSettings& settings = CefContext::Get()->settings();
+ const base::FilePath& root_cache_path =
+ base::FilePath(CefString(&settings.root_cache_path));
+
+ // Used for very early NetworkService initialization.
+ // Always persist preferences for this PrefService if possible because it
+ // contains the cookie encryption key on Windows.
+ local_state_ =
+ browser_prefs::CreatePrefService(nullptr /* profile */, root_cache_path,
+ true /* persist_user_preferences */);
+ }
+ return local_state_.get();
+}
+
+scoped_refptr<network::SharedURLLoaderFactory>
+ChromeBrowserProcessAlloy::shared_url_loader_factory() {
+ NOTREACHED();
+ return nullptr;
+}
+
+variations::VariationsService* ChromeBrowserProcessAlloy::variations_service() {
+ NOTREACHED();
+ return nullptr;
+}
+
+BrowserProcessPlatformPart* ChromeBrowserProcessAlloy::platform_part() {
+ NOTREACHED();
+ return nullptr;
+}
+
+extensions::EventRouterForwarder*
+ChromeBrowserProcessAlloy::extension_event_router_forwarder() {
+ DCHECK(context_initialized_);
+ return event_router_forwarder_.get();
+}
+
+NotificationUIManager* ChromeBrowserProcessAlloy::notification_ui_manager() {
+ NOTREACHED();
+ return nullptr;
+}
+
+NotificationPlatformBridge*
+ChromeBrowserProcessAlloy::notification_platform_bridge() {
+ NOTREACHED();
+ return nullptr;
+}
+
+policy::ChromeBrowserPolicyConnector*
+ChromeBrowserProcessAlloy::browser_policy_connector() {
+ if (!browser_policy_connector_) {
+ browser_policy_connector_ =
+ std::make_unique<policy::ChromeBrowserPolicyConnector>();
+ }
+ return browser_policy_connector_.get();
+}
+
+policy::PolicyService* ChromeBrowserProcessAlloy::policy_service() {
+ return browser_policy_connector()->GetPolicyService();
+}
+
+IconManager* ChromeBrowserProcessAlloy::icon_manager() {
+ NOTREACHED();
+ return nullptr;
+}
+
+GpuModeManager* ChromeBrowserProcessAlloy::gpu_mode_manager() {
+ NOTREACHED();
+ return nullptr;
+}
+
+void ChromeBrowserProcessAlloy::CreateDevToolsProtocolHandler() {
+ NOTREACHED();
+}
+
+void ChromeBrowserProcessAlloy::CreateDevToolsAutoOpener() {
+ NOTREACHED();
+}
+
+bool ChromeBrowserProcessAlloy::IsShuttingDown() {
+ NOTREACHED();
+ return false;
+}
+
+printing::PrintJobManager* ChromeBrowserProcessAlloy::print_job_manager() {
+ DCHECK(context_initialized_);
+ return print_job_manager_.get();
+}
+
+printing::PrintPreviewDialogController*
+ChromeBrowserProcessAlloy::print_preview_dialog_controller() {
+ if (!print_preview_dialog_controller_.get()) {
+ print_preview_dialog_controller_ =
+ new printing::PrintPreviewDialogController();
+ }
+ return print_preview_dialog_controller_.get();
+}
+
+printing::BackgroundPrintingManager*
+ChromeBrowserProcessAlloy::background_printing_manager() {
+ if (!background_printing_manager_.get()) {
+ background_printing_manager_.reset(
+ new printing::BackgroundPrintingManager());
+ }
+ return background_printing_manager_.get();
+}
+
+IntranetRedirectDetector*
+ChromeBrowserProcessAlloy::intranet_redirect_detector() {
+ NOTREACHED();
+ return nullptr;
+}
+
+const std::string& ChromeBrowserProcessAlloy::GetApplicationLocale() {
+ DCHECK(!locale_.empty());
+ return locale_;
+}
+
+void ChromeBrowserProcessAlloy::SetApplicationLocale(
+ const std::string& locale) {
+ locale_ = locale;
+}
+
+DownloadStatusUpdater* ChromeBrowserProcessAlloy::download_status_updater() {
+ NOTREACHED();
+ return nullptr;
+}
+
+DownloadRequestLimiter* ChromeBrowserProcessAlloy::download_request_limiter() {
+ NOTREACHED();
+ return nullptr;
+}
+
+#if BUILDFLAG(ENABLE_BACKGROUND_MODE)
+BackgroundModeManager* ChromeBrowserProcessAlloy::background_mode_manager() {
+ NOTREACHED();
+ return nullptr;
+}
+
+void ChromeBrowserProcessAlloy::set_background_mode_manager_for_test(
+ std::unique_ptr<BackgroundModeManager> manager) {
+ NOTREACHED();
+}
+#endif
+
+StatusTray* ChromeBrowserProcessAlloy::status_tray() {
+ NOTREACHED();
+ return nullptr;
+}
+
+safe_browsing::SafeBrowsingService*
+ChromeBrowserProcessAlloy::safe_browsing_service() {
+ return nullptr;
+}
+
+subresource_filter::RulesetService*
+ChromeBrowserProcessAlloy::subresource_filter_ruleset_service() {
+ NOTREACHED();
+ return nullptr;
+}
+
+StartupData* ChromeBrowserProcessAlloy::startup_data() {
+ NOTREACHED();
+ return nullptr;
+}
+
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX)
+void ChromeBrowserProcessAlloy::StartAutoupdateTimer() {}
+#endif
+
+component_updater::ComponentUpdateService*
+ChromeBrowserProcessAlloy::component_updater() {
+ if (component_updater_) {
+ return component_updater_.get();
+ }
+
+ if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) {
+ return nullptr;
+ }
+
+ std::unique_ptr<component_updater::UpdateScheduler> scheduler =
+ std::make_unique<component_updater::TimerUpdateScheduler>();
+
+ component_updater_ = component_updater::ComponentUpdateServiceFactory(
+ component_updater::MakeChromeComponentUpdaterConfigurator(
+ base::CommandLine::ForCurrentProcess(),
+ g_browser_process->local_state()),
+ std::move(scheduler), /*brand=*/std::string());
+
+ return component_updater_.get();
+}
+
+MediaFileSystemRegistry*
+ChromeBrowserProcessAlloy::media_file_system_registry() {
+ NOTREACHED();
+ return nullptr;
+}
+
+WebRtcLogUploader* ChromeBrowserProcessAlloy::webrtc_log_uploader() {
+ NOTREACHED();
+ return nullptr;
+}
+
+network_time::NetworkTimeTracker*
+ChromeBrowserProcessAlloy::network_time_tracker() {
+ NOTREACHED();
+ return nullptr;
+}
+
+gcm::GCMDriver* ChromeBrowserProcessAlloy::gcm_driver() {
+ NOTREACHED();
+ return nullptr;
+}
+
+resource_coordinator::TabManager* ChromeBrowserProcessAlloy::GetTabManager() {
+ NOTREACHED();
+ return nullptr;
+}
+
+resource_coordinator::ResourceCoordinatorParts*
+ChromeBrowserProcessAlloy::resource_coordinator_parts() {
+ NOTREACHED();
+ return nullptr;
+}
+
+BuildState* ChromeBrowserProcessAlloy::GetBuildState() {
+ NOTREACHED();
+ return nullptr;
+}
+
+SerialPolicyAllowedPorts*
+ChromeBrowserProcessAlloy::serial_policy_allowed_ports() {
+ NOTREACHED();
+ return nullptr;
+}
+
+HidPolicyAllowedDevices*
+ChromeBrowserProcessAlloy::hid_policy_allowed_devices() {
+ NOTREACHED();
+ return nullptr;
+}
+
+breadcrumbs::BreadcrumbPersistentStorageManager*
+ChromeBrowserProcessAlloy::GetBreadcrumbPersistentStorageManager() {
+ NOTREACHED();
+ return nullptr;
+}
+
+HidSystemTrayIcon* ChromeBrowserProcessAlloy::hid_system_tray_icon() {
+ NOTREACHED();
+ return nullptr;
+}
diff --git a/libcef/browser/alloy/chrome_browser_process_alloy.h b/libcef/browser/alloy/chrome_browser_process_alloy.h
new file mode 100644
index 00000000..80b3d106
--- /dev/null
+++ b/libcef/browser/alloy/chrome_browser_process_alloy.h
@@ -0,0 +1,141 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors.
+// Portions (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file provides a stub implementation of Chrome's BrowserProcess object
+// for use as an interop layer between CEF and files that live in chrome/.
+
+#ifndef CEF_LIBCEF_BROWSER_ALLOY_CHROME_BROWSER_PROCESS_ALLOY_H_
+#define CEF_LIBCEF_BROWSER_ALLOY_CHROME_BROWSER_PROCESS_ALLOY_H_
+
+#include <memory>
+#include <string>
+
+#include "base/metrics/field_trial.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/extensions/event_router_forwarder.h"
+#include "media/media_buildflags.h"
+
+namespace extensions {
+class ExtensionsBrowserClient;
+class ExtensionsClient;
+} // namespace extensions
+
+class ChromeProfileManagerAlloy;
+
+class BackgroundModeManager {
+ public:
+ BackgroundModeManager();
+
+ BackgroundModeManager(const BackgroundModeManager&) = delete;
+ BackgroundModeManager& operator=(const BackgroundModeManager&) = delete;
+
+ virtual ~BackgroundModeManager();
+};
+
+class ChromeBrowserProcessAlloy : public BrowserProcess {
+ public:
+ ChromeBrowserProcessAlloy();
+
+ ChromeBrowserProcessAlloy(const ChromeBrowserProcessAlloy&) = delete;
+ ChromeBrowserProcessAlloy& operator=(const ChromeBrowserProcessAlloy&) =
+ delete;
+
+ ~ChromeBrowserProcessAlloy() override;
+
+ void Initialize();
+ void OnContextInitialized();
+ void CleanupOnUIThread();
+
+ // BrowserProcess implementation.
+ void EndSession() override;
+ void FlushLocalStateAndReply(base::OnceClosure reply) override;
+ metrics_services_manager::MetricsServicesManager* GetMetricsServicesManager()
+ override;
+ metrics::MetricsService* metrics_service() override;
+ SystemNetworkContextManager* system_network_context_manager() override;
+ network::NetworkQualityTracker* network_quality_tracker() override;
+ ProfileManager* profile_manager() override;
+ PrefService* local_state() override;
+ scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory()
+ override;
+ variations::VariationsService* variations_service() override;
+ BrowserProcessPlatformPart* platform_part() override;
+ extensions::EventRouterForwarder* extension_event_router_forwarder() override;
+ NotificationUIManager* notification_ui_manager() override;
+ NotificationPlatformBridge* notification_platform_bridge() override;
+ policy::ChromeBrowserPolicyConnector* browser_policy_connector() override;
+ policy::PolicyService* policy_service() override;
+ IconManager* icon_manager() override;
+ GpuModeManager* gpu_mode_manager() override;
+ void CreateDevToolsProtocolHandler() override;
+ void CreateDevToolsAutoOpener() override;
+ bool IsShuttingDown() override;
+ printing::PrintJobManager* print_job_manager() override;
+ printing::PrintPreviewDialogController* print_preview_dialog_controller()
+ override;
+ printing::BackgroundPrintingManager* background_printing_manager() override;
+ IntranetRedirectDetector* intranet_redirect_detector() override;
+ const std::string& GetApplicationLocale() override;
+ void SetApplicationLocale(const std::string& locale) override;
+ DownloadStatusUpdater* download_status_updater() override;
+ DownloadRequestLimiter* download_request_limiter() override;
+#if BUILDFLAG(ENABLE_BACKGROUND_MODE)
+ BackgroundModeManager* background_mode_manager() override;
+ void set_background_mode_manager_for_test(
+ std::unique_ptr<BackgroundModeManager> manager) override;
+#endif
+ StatusTray* status_tray() override;
+ safe_browsing::SafeBrowsingService* safe_browsing_service() override;
+ subresource_filter::RulesetService* subresource_filter_ruleset_service()
+ override;
+ StartupData* startup_data() override;
+
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX)
+ void StartAutoupdateTimer() override;
+#endif
+
+ component_updater::ComponentUpdateService* component_updater() override;
+ MediaFileSystemRegistry* media_file_system_registry() override;
+ WebRtcLogUploader* webrtc_log_uploader() override;
+ network_time::NetworkTimeTracker* network_time_tracker() override;
+ gcm::GCMDriver* gcm_driver() override;
+ resource_coordinator::TabManager* GetTabManager() override;
+ resource_coordinator::ResourceCoordinatorParts* resource_coordinator_parts()
+ override;
+ BuildState* GetBuildState() override;
+ SerialPolicyAllowedPorts* serial_policy_allowed_ports() override;
+ HidPolicyAllowedDevices* hid_policy_allowed_devices() override;
+ breadcrumbs::BreadcrumbPersistentStorageManager*
+ GetBreadcrumbPersistentStorageManager() override;
+ HidSystemTrayIcon* hid_system_tray_icon() override;
+
+ private:
+ bool initialized_;
+ bool context_initialized_;
+ bool shutdown_;
+
+ std::unique_ptr<extensions::ExtensionsClient> extensions_client_;
+ std::unique_ptr<extensions::ExtensionsBrowserClient>
+ extensions_browser_client_;
+
+ std::string locale_;
+ std::unique_ptr<printing::PrintJobManager> print_job_manager_;
+ std::unique_ptr<ChromeProfileManagerAlloy> profile_manager_;
+ scoped_refptr<extensions::EventRouterForwarder> event_router_forwarder_;
+ scoped_refptr<printing::PrintPreviewDialogController>
+ print_preview_dialog_controller_;
+ std::unique_ptr<printing::BackgroundPrintingManager>
+ background_printing_manager_;
+ std::unique_ptr<PrefService> local_state_;
+
+ // Must be destroyed after |local_state_|.
+ std::unique_ptr<policy::ChromeBrowserPolicyConnector>
+ browser_policy_connector_;
+ std::unique_ptr<base::FieldTrialList> field_trial_list_;
+
+ std::unique_ptr<component_updater::ComponentUpdateService> component_updater_;
+};
+
+#endif // CEF_LIBCEF_BROWSER_ALLOY_CHROME_BROWSER_PROCESS_ALLOY_H_
diff --git a/libcef/browser/alloy/chrome_profile_alloy.cc b/libcef/browser/alloy/chrome_profile_alloy.cc
new file mode 100644
index 00000000..7e5b3c0d
--- /dev/null
+++ b/libcef/browser/alloy/chrome_profile_alloy.cc
@@ -0,0 +1,168 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors.
+// Portions copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/alloy/chrome_profile_alloy.h"
+
+#include "base/no_destructor.h"
+#include "components/profile_metrics/browser_profile_type.h"
+#include "components/variations/variations_client.h"
+#include "components/variations/variations_ids_provider.h"
+#include "net/url_request/url_request_context.h"
+
+namespace {
+
+class CefVariationsClient : public variations::VariationsClient {
+ public:
+ explicit CefVariationsClient(content::BrowserContext* browser_context)
+ : browser_context_(browser_context) {}
+
+ ~CefVariationsClient() override = default;
+
+ bool IsOffTheRecord() const override {
+ return browser_context_->IsOffTheRecord();
+ }
+
+ variations::mojom::VariationsHeadersPtr GetVariationsHeaders()
+ const override {
+ return variations::VariationsIdsProvider::GetInstance()
+ ->GetClientDataHeaders(false /* is_signed_in */);
+ }
+
+ private:
+ content::BrowserContext* browser_context_;
+};
+
+} // namespace
+
+ChromeProfileAlloy::ChromeProfileAlloy() {
+ profile_metrics::SetBrowserProfileType(
+ this, profile_metrics::BrowserProfileType::kRegular);
+}
+
+ChromeProfileAlloy::~ChromeProfileAlloy() {}
+
+bool ChromeProfileAlloy::IsOffTheRecord() {
+ return false;
+}
+
+bool ChromeProfileAlloy::IsOffTheRecord() const {
+ // Alloy contexts are never flagged as off-the-record. It causes problems
+ // for the extension system.
+ return false;
+}
+
+const Profile::OTRProfileID& ChromeProfileAlloy::GetOTRProfileID() const {
+ NOTREACHED();
+ static base::NoDestructor<Profile::OTRProfileID> otr_profile_id(
+ Profile::OTRProfileID::PrimaryID());
+ return *otr_profile_id;
+}
+
+variations::VariationsClient* ChromeProfileAlloy::GetVariationsClient() {
+ if (!variations_client_) {
+ variations_client_ = std::make_unique<CefVariationsClient>(this);
+ }
+ return variations_client_.get();
+}
+
+scoped_refptr<base::SequencedTaskRunner> ChromeProfileAlloy::GetIOTaskRunner() {
+ NOTREACHED();
+ return scoped_refptr<base::SequencedTaskRunner>();
+}
+
+std::string ChromeProfileAlloy::GetProfileUserName() const {
+ NOTREACHED();
+ return std::string();
+}
+
+Profile* ChromeProfileAlloy::GetOffTheRecordProfile(
+ const Profile::OTRProfileID& otr_profile_id,
+ bool create_if_needed) {
+ NOTREACHED();
+ return nullptr;
+}
+
+std::vector<Profile*> ChromeProfileAlloy::GetAllOffTheRecordProfiles() {
+ return {};
+}
+
+void ChromeProfileAlloy::DestroyOffTheRecordProfile(Profile* otr_profile) {
+ NOTREACHED();
+}
+
+bool ChromeProfileAlloy::HasOffTheRecordProfile(
+ const Profile::OTRProfileID& otr_profile_id) {
+ return false;
+}
+
+bool ChromeProfileAlloy::HasAnyOffTheRecordProfile() {
+ return false;
+}
+
+Profile* ChromeProfileAlloy::GetOriginalProfile() {
+ return this;
+}
+
+const Profile* ChromeProfileAlloy::GetOriginalProfile() const {
+ return this;
+}
+
+bool ChromeProfileAlloy::IsChild() const {
+ return false;
+}
+
+ExtensionSpecialStoragePolicy*
+ChromeProfileAlloy::GetExtensionSpecialStoragePolicy() {
+ NOTREACHED();
+ return nullptr;
+}
+
+bool ChromeProfileAlloy::IsSameOrParent(Profile* profile) {
+ NOTREACHED();
+ return false;
+}
+
+base::Time ChromeProfileAlloy::GetStartTime() const {
+ NOTREACHED();
+ return base::Time();
+}
+
+base::FilePath ChromeProfileAlloy::last_selected_directory() {
+ return last_selected_directory_;
+}
+
+void ChromeProfileAlloy::set_last_selected_directory(
+ const base::FilePath& path) {
+ last_selected_directory_ = path;
+}
+
+GURL ChromeProfileAlloy::GetHomePage() {
+ NOTREACHED();
+ return GURL();
+}
+
+bool ChromeProfileAlloy::WasCreatedByVersionOrLater(
+ const std::string& version) {
+ NOTREACHED();
+ return false;
+}
+
+base::Time ChromeProfileAlloy::GetCreationTime() const {
+ NOTREACHED();
+ return base::Time();
+}
+
+void ChromeProfileAlloy::SetCreationTimeForTesting(base::Time creation_time) {
+ NOTREACHED();
+}
+
+void ChromeProfileAlloy::RecordPrimaryMainFrameNavigation() {
+ NOTREACHED();
+}
+
+bool ChromeProfileAlloy::IsSignedIn() {
+ NOTREACHED();
+ return false;
+}
diff --git a/libcef/browser/alloy/chrome_profile_alloy.h b/libcef/browser/alloy/chrome_profile_alloy.h
new file mode 100644
index 00000000..95c6ca91
--- /dev/null
+++ b/libcef/browser/alloy/chrome_profile_alloy.h
@@ -0,0 +1,61 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors.
+// Portions copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This class gathers state related to a single user profile.
+
+#ifndef CEF_LIBCEF_BROWSER_ALLOY_CHROME_PROFILE_ALLOY_H_
+#define CEF_LIBCEF_BROWSER_ALLOY_CHROME_PROFILE_ALLOY_H_
+
+#include "base/files/file_path.h"
+#include "chrome/browser/profiles/profile.h"
+
+// This file provides a stub implementation of Chrome's Profile object for use
+// as an interop layer between CEF and files that live in chrome/.
+
+class ChromeProfileAlloy : public Profile {
+ public:
+ ChromeProfileAlloy();
+
+ ChromeProfileAlloy(const ChromeProfileAlloy&) = delete;
+ ChromeProfileAlloy& operator=(const ChromeProfileAlloy&) = delete;
+
+ ~ChromeProfileAlloy() override;
+
+ protected:
+ // Profile methods.
+ bool IsOffTheRecord() override;
+ bool IsOffTheRecord() const override;
+ const OTRProfileID& GetOTRProfileID() const override;
+ variations::VariationsClient* GetVariationsClient() override;
+ scoped_refptr<base::SequencedTaskRunner> GetIOTaskRunner() override;
+ std::string GetProfileUserName() const override;
+ Profile* GetOffTheRecordProfile(const Profile::OTRProfileID& otr_profile_id,
+ bool create_if_needed) override;
+ std::vector<Profile*> GetAllOffTheRecordProfiles() override;
+ void DestroyOffTheRecordProfile(Profile* otr_profile) override;
+ bool HasOffTheRecordProfile(
+ const Profile::OTRProfileID& otr_profile_id) override;
+ bool HasAnyOffTheRecordProfile() override;
+ Profile* GetOriginalProfile() override;
+ const Profile* GetOriginalProfile() const override;
+ bool IsChild() const override;
+ ExtensionSpecialStoragePolicy* GetExtensionSpecialStoragePolicy() override;
+ bool IsSameOrParent(Profile* profile) override;
+ base::Time GetStartTime() const override;
+ base::FilePath last_selected_directory() override;
+ void set_last_selected_directory(const base::FilePath& path) override;
+ GURL GetHomePage() override;
+ bool WasCreatedByVersionOrLater(const std::string& version) override;
+ base::Time GetCreationTime() const override;
+ void SetCreationTimeForTesting(base::Time creation_time) override;
+ void RecordPrimaryMainFrameNavigation() override;
+ bool IsSignedIn() override;
+
+ private:
+ std::unique_ptr<variations::VariationsClient> variations_client_;
+ base::FilePath last_selected_directory_;
+};
+
+#endif // CEF_LIBCEF_BROWSER_ALLOY_CHROME_PROFILE_ALLOY_H_
diff --git a/libcef/browser/alloy/chrome_profile_manager_alloy.cc b/libcef/browser/alloy/chrome_profile_manager_alloy.cc
new file mode 100644
index 00000000..8a577f5c
--- /dev/null
+++ b/libcef/browser/alloy/chrome_profile_manager_alloy.cc
@@ -0,0 +1,59 @@
+// Copyright (c) 2016 The Chromium Embedded Framework Authors.
+// Portions copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/alloy/chrome_profile_manager_alloy.h"
+
+#include "libcef/browser/browser_context.h"
+#include "libcef/browser/request_context_impl.h"
+#include "libcef/common/app_manager.h"
+
+namespace {
+
+// Return the active browser context. This is primarily called from Chrome code
+// that handles WebUI views and wishes to associate the view's data with a
+// particular context (profile). Chrome stores multiple profiles in sub-
+// directories of |user_data_dir| and then uses ProfileManager to track which
+// profile (sub-directory name) was last active.
+//
+// TODO(cef): To most closely match Chrome behavior this should return the
+// context for the currently active browser (e.g. the browser with input focus).
+// Return the main context for now since we don't currently have a good way to
+// determine that.
+CefBrowserContext* GetActiveBrowserContext() {
+ auto request_context = static_cast<CefRequestContextImpl*>(
+ CefAppManager::Get()->GetGlobalRequestContext().get());
+ return request_context->GetBrowserContext();
+}
+
+} // namespace
+
+ChromeProfileManagerAlloy::ChromeProfileManagerAlloy()
+ : ProfileManager(base::FilePath()) {}
+
+ChromeProfileManagerAlloy::~ChromeProfileManagerAlloy() {}
+
+Profile* ChromeProfileManagerAlloy::GetProfile(
+ const base::FilePath& profile_dir) {
+ CefBrowserContext* browser_context =
+ CefBrowserContext::FromCachePath(profile_dir);
+ if (!browser_context) {
+ // ProfileManager makes assumptions about profile directory paths that do
+ // not match CEF usage. For example, the default Chrome profile name is
+ // "Default" so it will append that sub-directory name to an empty
+ // |user_data_dir| value and then call this method. Use the active context
+ // in cases such as this where we don't understand what ProfileManager is
+ // asking for.
+ browser_context = GetActiveBrowserContext();
+ }
+ return browser_context->AsProfile();
+}
+
+bool ChromeProfileManagerAlloy::IsValidProfile(const void* profile) {
+ if (!profile) {
+ return false;
+ }
+ return !!CefBrowserContext::FromBrowserContext(
+ static_cast<const content::BrowserContext*>(profile));
+}
diff --git a/libcef/browser/alloy/chrome_profile_manager_alloy.h b/libcef/browser/alloy/chrome_profile_manager_alloy.h
new file mode 100644
index 00000000..5473d2e7
--- /dev/null
+++ b/libcef/browser/alloy/chrome_profile_manager_alloy.h
@@ -0,0 +1,28 @@
+// Copyright (c) 2016 The Chromium Embedded Framework Authors.
+// Portions copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file provides a stub implementation of Chrome's ProfileManager object
+// for use as an interop layer between CEF and files that live in chrome/.
+
+#ifndef CEF_LIBCEF_BROWSER_ALLOY_CHROME_PROFILE_MANAGER_ALLOY_H_
+#define CEF_LIBCEF_BROWSER_ALLOY_CHROME_PROFILE_MANAGER_ALLOY_H_
+
+#include "chrome/browser/profiles/profile_manager.h"
+
+class ChromeProfileManagerAlloy : public ProfileManager {
+ public:
+ ChromeProfileManagerAlloy();
+
+ ChromeProfileManagerAlloy(const ChromeProfileManagerAlloy&) = delete;
+ ChromeProfileManagerAlloy& operator=(const ChromeProfileManagerAlloy&) =
+ delete;
+
+ ~ChromeProfileManagerAlloy() override;
+
+ Profile* GetProfile(const base::FilePath& profile_dir) override;
+ bool IsValidProfile(const void* profile) override;
+};
+
+#endif // CEF_LIBCEF_BROWSER_ALLOY_CHROME_PROFILE_MANAGER_ALLOY_H_
diff --git a/libcef/browser/alloy/dialogs/alloy_constrained_window_views_client.cc b/libcef/browser/alloy/dialogs/alloy_constrained_window_views_client.cc
new file mode 100644
index 00000000..0b0d371c
--- /dev/null
+++ b/libcef/browser/alloy/dialogs/alloy_constrained_window_views_client.cc
@@ -0,0 +1,76 @@
+// Copyright 2022 The Chromium Embedded Framework Authors.
+// Portions copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/alloy/dialogs/alloy_constrained_window_views_client.h"
+
+#include "libcef/browser/browser_host_base.h"
+
+#include "base/notreached.h"
+#include "components/web_modal/web_contents_modal_dialog_host.h"
+
+namespace {
+
+class AlloyConstrainedWindowViewsClient
+ : public constrained_window::ConstrainedWindowViewsClient {
+ public:
+ AlloyConstrainedWindowViewsClient() = default;
+
+ AlloyConstrainedWindowViewsClient(const AlloyConstrainedWindowViewsClient&) =
+ delete;
+ AlloyConstrainedWindowViewsClient& operator=(
+ const AlloyConstrainedWindowViewsClient&) = delete;
+
+ private:
+ // ConstrainedWindowViewsClient methods:
+ web_modal::ModalDialogHost* GetModalDialogHost(
+ gfx::NativeWindow parent) override {
+ if (auto browser = GetPreferredBrowser(parent)) {
+ return browser->platform_delegate()->GetWebContentsModalDialogHost();
+ }
+ NOTREACHED();
+ return nullptr;
+ }
+
+ gfx::NativeView GetDialogHostView(gfx::NativeWindow parent) override {
+ if (auto dialog_host = GetModalDialogHost(parent)) {
+ return dialog_host->GetHostView();
+ }
+ return gfx::NativeView();
+ }
+
+ static CefRefPtr<CefBrowserHostBase> GetPreferredBrowser(
+ gfx::NativeWindow parent) {
+ CefRefPtr<CefBrowserHostBase> browser;
+
+ // 1. Browser associated with the top-level native window (owning_window).
+ // This should be reliable with windowed browsers. However, |parent| will
+ // always be nullptr with windowless browsers.
+ if (parent) {
+ browser = CefBrowserHostBase::GetBrowserForTopLevelNativeWindow(parent);
+ if (!browser) {
+ LOG(WARNING) << "No browser associated with top-level native window";
+ }
+ }
+
+ // 2. Browser most likely to be focused. This may be somewhat iffy with
+ // windowless browsers as there is no guarantee that the client has only
+ // one browser focused at a time.
+ if (!browser) {
+ browser = CefBrowserHostBase::GetLikelyFocusedBrowser();
+ if (!browser) {
+ LOG(WARNING) << "No likely focused browser";
+ }
+ }
+
+ return browser;
+ }
+};
+
+} // namespace
+
+std::unique_ptr<constrained_window::ConstrainedWindowViewsClient>
+CreateAlloyConstrainedWindowViewsClient() {
+ return std::make_unique<AlloyConstrainedWindowViewsClient>();
+} \ No newline at end of file
diff --git a/libcef/browser/alloy/dialogs/alloy_constrained_window_views_client.h b/libcef/browser/alloy/dialogs/alloy_constrained_window_views_client.h
new file mode 100644
index 00000000..c33a38cc
--- /dev/null
+++ b/libcef/browser/alloy/dialogs/alloy_constrained_window_views_client.h
@@ -0,0 +1,17 @@
+// Copyright 2022 The Chromium Embedded Framework Authors.
+// Portions copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_ALLOY_DIALOGS_ALLOY_CONSTRAINED_WINDOW_VIEWS_CLIENT_H_
+#define CEF_LIBCEF_BROWSER_ALLOY_DIALOGS_ALLOY_CONSTRAINED_WINDOW_VIEWS_CLIENT_H_
+
+#include <memory>
+
+#include "components/constrained_window/constrained_window_views_client.h"
+
+// Creates a ConstrainedWindowViewsClient for the Chrome environment.
+std::unique_ptr<constrained_window::ConstrainedWindowViewsClient>
+CreateAlloyConstrainedWindowViewsClient();
+
+#endif // CEF_LIBCEF_BROWSER_ALLOY_DIALOGS_ALLOY_CONSTRAINED_WINDOW_VIEWS_CLIENT_H_ \ No newline at end of file
diff --git a/libcef/browser/alloy/dialogs/alloy_javascript_dialog_manager_delegate.cc b/libcef/browser/alloy/dialogs/alloy_javascript_dialog_manager_delegate.cc
new file mode 100644
index 00000000..bb7647bb
--- /dev/null
+++ b/libcef/browser/alloy/dialogs/alloy_javascript_dialog_manager_delegate.cc
@@ -0,0 +1,58 @@
+// Copyright 2022 The Chromium Embedded Framework Authors.
+// Portions copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/alloy/dialogs/alloy_javascript_dialog_manager_delegate.h"
+
+#include "libcef/browser/browser_host_base.h"
+
+#include "base/logging.h"
+
+namespace {
+
+class AlloyJavaScriptTabModalDialogManagerDelegateDesktop
+ : public JavaScriptTabModalDialogManagerDelegateDesktop {
+ public:
+ explicit AlloyJavaScriptTabModalDialogManagerDelegateDesktop(
+ content::WebContents* web_contents)
+ : JavaScriptTabModalDialogManagerDelegateDesktop(web_contents),
+ web_contents_(web_contents) {}
+
+ AlloyJavaScriptTabModalDialogManagerDelegateDesktop(
+ const AlloyJavaScriptTabModalDialogManagerDelegateDesktop&) = delete;
+ AlloyJavaScriptTabModalDialogManagerDelegateDesktop& operator=(
+ const AlloyJavaScriptTabModalDialogManagerDelegateDesktop&) = delete;
+
+ // javascript_dialogs::TabModalDialogManagerDelegate methods:
+ void WillRunDialog() override {}
+
+ void DidCloseDialog() override {}
+
+ void SetTabNeedsAttention(bool attention) override {}
+
+ bool IsWebContentsForemost() override {
+ if (auto browser =
+ CefBrowserHostBase::GetBrowserForContents(web_contents_)) {
+ return browser->IsVisible();
+ }
+ return false;
+ }
+
+ bool IsApp() override { return false; }
+
+ private:
+ // The WebContents for the tab over which the dialog will be modal. This may
+ // be different from the WebContents that requested the dialog, such as with
+ // Chrome app <webview>s.
+ raw_ptr<content::WebContents> web_contents_;
+};
+
+} // namespace
+
+std::unique_ptr<JavaScriptTabModalDialogManagerDelegateDesktop>
+CreateAlloyJavaScriptTabModalDialogManagerDelegateDesktop(
+ content::WebContents* web_contents) {
+ return std::make_unique<AlloyJavaScriptTabModalDialogManagerDelegateDesktop>(
+ web_contents);
+}
diff --git a/libcef/browser/alloy/dialogs/alloy_javascript_dialog_manager_delegate.h b/libcef/browser/alloy/dialogs/alloy_javascript_dialog_manager_delegate.h
new file mode 100644
index 00000000..4d3df0da
--- /dev/null
+++ b/libcef/browser/alloy/dialogs/alloy_javascript_dialog_manager_delegate.h
@@ -0,0 +1,18 @@
+// Copyright 2022 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_ALLOY_DIALOGS_ALLOY_JAVASCRIPT_DIALOG_MANAGER_DELEGATE_H_
+#define CEF_LIBCEF_BROWSER_ALLOY_DIALOGS_ALLOY_JAVASCRIPT_DIALOG_MANAGER_DELEGATE_H_
+
+#include <memory>
+
+#include "chrome/browser/ui/javascript_dialogs/javascript_tab_modal_dialog_manager_delegate_desktop.h"
+
+// Creates a JavaScriptTabModalDialogManagerDelegateDesktop for the Chrome
+// environment.
+std::unique_ptr<JavaScriptTabModalDialogManagerDelegateDesktop>
+CreateAlloyJavaScriptTabModalDialogManagerDelegateDesktop(
+ content::WebContents* web_contents);
+
+#endif // CEF_LIBCEF_BROWSER_ALLOY_DIALOGS_ALLOY_JAVASCRIPT_DIALOG_MANAGER_DELEGATE_H_ \ No newline at end of file
diff --git a/libcef/browser/alloy/dialogs/alloy_web_contents_dialog_helper.cc b/libcef/browser/alloy/dialogs/alloy_web_contents_dialog_helper.cc
new file mode 100644
index 00000000..402ce172
--- /dev/null
+++ b/libcef/browser/alloy/dialogs/alloy_web_contents_dialog_helper.cc
@@ -0,0 +1,98 @@
+// Copyright (c) 2019 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "libcef/browser/alloy/dialogs/alloy_web_contents_dialog_helper.h"
+
+#include "libcef/browser/browser_platform_delegate.h"
+
+#include "base/notreached.h"
+#include "chrome/browser/platform_util.h"
+#include "components/web_modal/web_contents_modal_dialog_manager.h"
+#include "ui/views/widget/widget.h"
+
+AlloyWebContentsDialogHelper::AlloyWebContentsDialogHelper(
+ content::WebContents* web_contents,
+ CefBrowserPlatformDelegate* browser_delegate)
+ : browser_delegate_(browser_delegate), weak_factory_(this) {
+ web_modal::WebContentsModalDialogManager::CreateForWebContents(web_contents);
+ web_modal::WebContentsModalDialogManager::FromWebContents(web_contents)
+ ->SetDelegate(this);
+}
+
+base::RepeatingClosure
+AlloyWebContentsDialogHelper::GetBoundsChangedCallback() {
+ return base::BindRepeating(&AlloyWebContentsDialogHelper::OnBoundsChanged,
+ weak_factory_.GetWeakPtr());
+}
+
+bool AlloyWebContentsDialogHelper::IsWebContentsVisible(
+ content::WebContents* web_contents) {
+ if (browser_delegate_->IsWindowless()) {
+ return !browser_delegate_->IsHidden();
+ } else if (auto native_view = web_contents->GetNativeView()) {
+ return platform_util::IsVisible(native_view);
+ }
+ NOTREACHED();
+ return false;
+}
+
+web_modal::WebContentsModalDialogHost*
+AlloyWebContentsDialogHelper::GetWebContentsModalDialogHost() {
+ return this;
+}
+
+gfx::NativeView AlloyWebContentsDialogHelper::GetHostView() const {
+ // Windowless rendering uses GetHostWidget() instead.
+ if (browser_delegate_->IsWindowless()) {
+ return gfx::NativeView();
+ }
+
+ if (auto widget = browser_delegate_->GetWindowWidget()) {
+ return widget->GetNativeView();
+ }
+ NOTREACHED();
+ return gfx::NativeView();
+}
+
+gfx::AcceleratedWidget AlloyWebContentsDialogHelper::GetHostWidget() const {
+#if defined(USE_AURA)
+ // Windowed rendering uses GetHostView() instead.
+ if (!browser_delegate_->IsWindowless()) {
+ return gfx::kNullAcceleratedWidget;
+ }
+
+ if (auto parent_widget = browser_delegate_->GetHostWindowHandle()) {
+ return parent_widget;
+ }
+#endif // defined(USE_AURA)
+ NOTREACHED();
+ return gfx::kNullAcceleratedWidget;
+}
+
+gfx::Point AlloyWebContentsDialogHelper::GetDialogPosition(
+ const gfx::Size& size) {
+ return browser_delegate_->GetDialogPosition(size);
+}
+
+gfx::Size AlloyWebContentsDialogHelper::GetMaximumDialogSize() {
+ return browser_delegate_->GetMaximumDialogSize();
+}
+
+void AlloyWebContentsDialogHelper::AddObserver(
+ web_modal::ModalDialogHostObserver* observer) {
+ if (observer && !observer_list_.HasObserver(observer)) {
+ observer_list_.AddObserver(observer);
+ }
+}
+
+void AlloyWebContentsDialogHelper::RemoveObserver(
+ web_modal::ModalDialogHostObserver* observer) {
+ observer_list_.RemoveObserver(observer);
+}
+
+void AlloyWebContentsDialogHelper::OnBoundsChanged() {
+ for (auto& observer : observer_list_) {
+ observer.OnPositionRequiresUpdate();
+ }
+}
diff --git a/libcef/browser/alloy/dialogs/alloy_web_contents_dialog_helper.h b/libcef/browser/alloy/dialogs/alloy_web_contents_dialog_helper.h
new file mode 100644
index 00000000..e5630501
--- /dev/null
+++ b/libcef/browser/alloy/dialogs/alloy_web_contents_dialog_helper.h
@@ -0,0 +1,52 @@
+// Copyright (c) 2019 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_ALLOY_DIALOGS_ALLOY_WEB_CONTENTS_DIALOG_HELPER_H_
+#define CEF_LIBCEF_BROWSER_ALLOY_DIALOGS_ALLOY_WEB_CONTENTS_DIALOG_HELPER_H_
+#pragma once
+
+#include "base/functional/callback_forward.h"
+#include "base/memory/weak_ptr.h"
+#include "base/observer_list.h"
+#include "components/web_modal/modal_dialog_host.h"
+#include "components/web_modal/web_contents_modal_dialog_host.h"
+#include "components/web_modal/web_contents_modal_dialog_manager_delegate.h"
+
+class CefBrowserPlatformDelegate;
+
+class AlloyWebContentsDialogHelper
+ : public web_modal::WebContentsModalDialogManagerDelegate,
+ public web_modal::WebContentsModalDialogHost {
+ public:
+ AlloyWebContentsDialogHelper(content::WebContents* web_contents,
+ CefBrowserPlatformDelegate* browser_delegate);
+
+ base::RepeatingClosure GetBoundsChangedCallback();
+
+ // web_modal::WebContentsModalDialogManagerDelegate methods:
+ bool IsWebContentsVisible(content::WebContents* web_contents) override;
+ web_modal::WebContentsModalDialogHost* GetWebContentsModalDialogHost()
+ override;
+
+ // web_modal::WebContentsModalDialogHost methods:
+ gfx::NativeView GetHostView() const override;
+ gfx::AcceleratedWidget GetHostWidget() const override;
+ gfx::Point GetDialogPosition(const gfx::Size& size) override;
+ gfx::Size GetMaximumDialogSize() override;
+ void AddObserver(web_modal::ModalDialogHostObserver* observer) override;
+ void RemoveObserver(web_modal::ModalDialogHostObserver* observer) override;
+
+ private:
+ void OnBoundsChanged();
+
+ CefBrowserPlatformDelegate* const browser_delegate_;
+
+ // Used to notify WebContentsModalDialog.
+ base::ObserverList<web_modal::ModalDialogHostObserver>::Unchecked
+ observer_list_;
+
+ base::WeakPtrFactory<AlloyWebContentsDialogHelper> weak_factory_;
+};
+
+#endif // CEF_LIBCEF_BROWSER_ALLOY_DIALOGS_ALLOY_WEB_CONTENTS_DIALOG_HELPER_H_
diff --git a/libcef/browser/audio_capturer.cc b/libcef/browser/audio_capturer.cc
new file mode 100644
index 00000000..ce762508
--- /dev/null
+++ b/libcef/browser/audio_capturer.cc
@@ -0,0 +1,132 @@
+// Copyright (c) 2019 The Chromium Embedded Framework Authors.
+// Portions copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/audio_capturer.h"
+
+#include "libcef/browser/alloy/alloy_browser_host_impl.h"
+#include "libcef/browser/audio_loopback_stream_creator.h"
+
+#include "components/mirroring/service/captured_audio_input.h"
+#include "media/audio/audio_input_device.h"
+
+namespace {
+
+media::ChannelLayoutConfig TranslateChannelLayout(
+ cef_channel_layout_t channel_layout) {
+ // Verify that our enum matches Chromium's values. The enum values match
+ // between those enums and existing values don't ever change, so it's enough
+ // to check that there are no new ones added.
+ static_assert(
+ static_cast<int>(CEF_CHANNEL_LAYOUT_MAX) ==
+ static_cast<int>(media::CHANNEL_LAYOUT_MAX),
+ "cef_channel_layout_t must match the ChannelLayout enum in Chromium");
+
+ const auto layout = static_cast<media::ChannelLayout>(channel_layout);
+ return {layout, media::ChannelLayoutToChannelCount(layout)};
+}
+
+void StreamCreatorHelper(
+ content::WebContents* source_web_contents,
+ CefAudioLoopbackStreamCreator* audio_stream_creator,
+ mojo::PendingRemote<mirroring::mojom::AudioStreamCreatorClient> client,
+ const media::AudioParameters& params,
+ uint32_t total_segments) {
+ audio_stream_creator->CreateLoopbackStream(
+ source_web_contents, params, total_segments,
+ base::BindRepeating(
+ [](mojo::PendingRemote<mirroring::mojom::AudioStreamCreatorClient>
+ client,
+ mojo::PendingRemote<media::mojom::AudioInputStream> stream,
+ mojo::PendingReceiver<media::mojom::AudioInputStreamClient>
+ client_receiver,
+ media::mojom::ReadOnlyAudioDataPipePtr data_pipe) {
+ mojo::Remote<mirroring::mojom::AudioStreamCreatorClient>
+ audio_client(std::move(client));
+ audio_client->StreamCreated(std::move(stream),
+ std::move(client_receiver),
+ std::move(data_pipe));
+ },
+ base::Passed(&client)));
+}
+
+} // namespace
+
+CefAudioCapturer::CefAudioCapturer(const CefAudioParameters& params,
+ CefRefPtr<AlloyBrowserHostImpl> browser,
+ CefRefPtr<CefAudioHandler> audio_handler)
+ : params_(params),
+ browser_(browser),
+ audio_handler_(audio_handler),
+ audio_stream_creator_(std::make_unique<CefAudioLoopbackStreamCreator>()) {
+ media::AudioParameters audio_params(
+ media::AudioParameters::AUDIO_PCM_LINEAR,
+ TranslateChannelLayout(params.channel_layout), params.sample_rate,
+ params.frames_per_buffer);
+
+ if (!audio_params.IsValid()) {
+ LOG(ERROR) << "Invalid audio parameters";
+ return;
+ }
+
+ DCHECK(browser_);
+ DCHECK(audio_handler_);
+ DCHECK(browser_->web_contents());
+
+ channels_ = audio_params.channels();
+ audio_input_device_ = new media::AudioInputDevice(
+ std::make_unique<mirroring::CapturedAudioInput>(base::BindRepeating(
+ &StreamCreatorHelper, base::Unretained(browser_->web_contents()),
+ base::Unretained(audio_stream_creator_.get()))),
+ media::AudioInputDevice::kLoopback,
+ media::AudioInputDevice::DeadStreamDetection::kEnabled);
+
+ audio_input_device_->Initialize(audio_params, this);
+ audio_input_device_->Start();
+}
+
+CefAudioCapturer::~CefAudioCapturer() {
+ StopStream();
+}
+
+void CefAudioCapturer::OnCaptureStarted() {
+ audio_handler_->OnAudioStreamStarted(browser_, params_, channels_);
+ DCHECK(!capturing_);
+ capturing_ = true;
+}
+
+void CefAudioCapturer::Capture(const media::AudioBus* source,
+ base::TimeTicks audio_capture_time,
+ double /*volume*/,
+ bool /*key_pressed*/) {
+ const int channels = source->channels();
+ std::array<const float*, media::CHANNELS_MAX> data;
+ DCHECK(channels == channels_);
+ DCHECK(channels <= static_cast<int>(data.size()));
+ for (int c = 0; c < channels; ++c) {
+ data[c] = source->channel(c);
+ }
+ base::TimeDelta pts = audio_capture_time - base::TimeTicks::UnixEpoch();
+ audio_handler_->OnAudioStreamPacket(browser_, data.data(), source->frames(),
+ pts.InMilliseconds());
+}
+
+void CefAudioCapturer::OnCaptureError(
+ media::AudioCapturerSource::ErrorCode code,
+ const std::string& message) {
+ audio_handler_->OnAudioStreamError(browser_, message);
+ StopStream();
+}
+
+void CefAudioCapturer::StopStream() {
+ if (audio_input_device_) {
+ audio_input_device_->Stop();
+ }
+ if (capturing_) {
+ audio_handler_->OnAudioStreamStopped(browser_);
+ }
+
+ audio_input_device_ = nullptr;
+ capturing_ = false;
+} \ No newline at end of file
diff --git a/libcef/browser/audio_capturer.h b/libcef/browser/audio_capturer.h
new file mode 100644
index 00000000..c38e01dd
--- /dev/null
+++ b/libcef/browser/audio_capturer.h
@@ -0,0 +1,51 @@
+// Copyright (c) 2019 The Chromium Embedded Framework Authors.
+// Portions copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_AUDIO_CAPTURER_H_
+#define CEF_LIBCEF_BROWSER_AUDIO_CAPTURER_H_
+#pragma once
+
+#include "include/internal/cef_ptr.h"
+#include "include/internal/cef_types_wrappers.h"
+
+#include "media/base/audio_capturer_source.h"
+
+namespace media {
+class AudioInputDevice;
+} // namespace media
+
+class CefAudioHandler;
+class CefAudioLoopbackStreamCreator;
+class AlloyBrowserHostImpl;
+
+class CefAudioCapturer : public media::AudioCapturerSource::CaptureCallback {
+ public:
+ CefAudioCapturer(const CefAudioParameters& params,
+ CefRefPtr<AlloyBrowserHostImpl> browser,
+ CefRefPtr<CefAudioHandler> audio_handler);
+ ~CefAudioCapturer() override;
+
+ private:
+ void OnCaptureStarted() override;
+ void Capture(const media::AudioBus* audio_source,
+ base::TimeTicks audio_capture_time,
+ double volume,
+ bool key_pressed) override;
+ void OnCaptureError(media::AudioCapturerSource::ErrorCode code,
+ const std::string& message) override;
+ void OnCaptureMuted(bool is_muted) override {}
+
+ void StopStream();
+
+ CefAudioParameters params_;
+ CefRefPtr<AlloyBrowserHostImpl> browser_;
+ CefRefPtr<CefAudioHandler> audio_handler_;
+ std::unique_ptr<CefAudioLoopbackStreamCreator> audio_stream_creator_;
+ scoped_refptr<media::AudioInputDevice> audio_input_device_;
+ bool capturing_ = false;
+ int channels_ = 0;
+};
+
+#endif // CEF_LIBCEF_BROWSER_AUDIO_CAPTURER_H_ \ No newline at end of file
diff --git a/libcef/browser/audio_loopback_stream_creator.cc b/libcef/browser/audio_loopback_stream_creator.cc
new file mode 100644
index 00000000..48aea22d
--- /dev/null
+++ b/libcef/browser/audio_loopback_stream_creator.cc
@@ -0,0 +1,135 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/audio_loopback_stream_creator.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/check_op.h"
+#include "base/functional/bind.h"
+#include "base/location.h"
+#include "content/browser/browser_main_loop.h"
+#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_frame_host.h"
+#include "media/audio/audio_device_description.h"
+#include "media/base/user_input_monitor.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/self_owned_receiver.h"
+#include "third_party/blink/public/mojom/media/renderer_audio_input_stream_factory.mojom.h"
+
+namespace {
+
+// A blink::mojom::RendererAudioInputStreamFactoryClient that holds a
+// CefAudioLoopbackStreamCreator::StreamCreatedCallback. The callback runs when
+// the requested audio stream is created.
+class StreamCreatedCallbackAdapter final
+ : public blink::mojom::RendererAudioInputStreamFactoryClient {
+ public:
+ explicit StreamCreatedCallbackAdapter(
+ const CefAudioLoopbackStreamCreator::StreamCreatedCallback& callback)
+ : callback_(callback) {
+ DCHECK(callback_);
+ }
+
+ StreamCreatedCallbackAdapter(const StreamCreatedCallbackAdapter&) = delete;
+ StreamCreatedCallbackAdapter& operator=(const StreamCreatedCallbackAdapter&) =
+ delete;
+
+ ~StreamCreatedCallbackAdapter() override {}
+
+ // blink::mojom::RendererAudioInputStreamFactoryClient implementation.
+ void StreamCreated(
+ mojo::PendingRemote<media::mojom::AudioInputStream> stream,
+ mojo::PendingReceiver<media::mojom::AudioInputStreamClient>
+ client_receiver,
+ media::mojom::ReadOnlyAudioDataPipePtr data_pipe,
+ bool initially_muted,
+ const absl::optional<base::UnguessableToken>& stream_id) override {
+ DCHECK(!initially_muted); // Loopback streams shouldn't be started muted.
+ callback_.Run(std::move(stream), std::move(client_receiver),
+ std::move(data_pipe));
+ }
+
+ private:
+ const CefAudioLoopbackStreamCreator::StreamCreatedCallback callback_;
+};
+
+void CreateLoopbackStreamHelper(
+ content::ForwardingAudioStreamFactory::Core* factory,
+ content::AudioStreamBroker::LoopbackSource* loopback_source,
+ const media::AudioParameters& params,
+ uint32_t total_segments,
+ mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient>
+ client_remote) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+
+ const bool mute_source = true;
+ factory->CreateLoopbackStream(-1, -1, loopback_source, params, total_segments,
+ mute_source, std::move(client_remote));
+}
+
+void CreateSystemWideLoopbackStreamHelper(
+ content::ForwardingAudioStreamFactory::Core* factory,
+ const media::AudioParameters& params,
+ uint32_t total_segments,
+ mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient>
+ client_remote) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+
+ const bool enable_agc = false;
+ factory->CreateInputStream(
+ -1, -1, media::AudioDeviceDescription::kLoopbackWithMuteDeviceId, params,
+ total_segments, enable_agc, media::mojom::AudioProcessingConfigPtr(),
+ std::move(client_remote));
+}
+
+} // namespace
+
+CefAudioLoopbackStreamCreator::CefAudioLoopbackStreamCreator()
+ : factory_(nullptr,
+ content::BrowserMainLoop::GetInstance()
+ ? static_cast<media::UserInputMonitorBase*>(
+ content::BrowserMainLoop::GetInstance()
+ ->user_input_monitor())
+ : nullptr,
+ content::AudioStreamBrokerFactory::CreateImpl()) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+}
+
+CefAudioLoopbackStreamCreator::~CefAudioLoopbackStreamCreator() {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+}
+
+void CefAudioLoopbackStreamCreator::CreateLoopbackStream(
+ content::WebContents* loopback_source,
+ const media::AudioParameters& params,
+ uint32_t total_segments,
+ const StreamCreatedCallback& callback) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ mojo::PendingRemote<blink::mojom::RendererAudioInputStreamFactoryClient>
+ client;
+ mojo::MakeSelfOwnedReceiver(
+ std::make_unique<StreamCreatedCallbackAdapter>(callback),
+ client.InitWithNewPipeAndPassReceiver());
+ // Deletion of factory_.core() is posted to the IO thread when |factory_| is
+ // destroyed, so Unretained is safe below.
+ if (loopback_source) {
+ content::GetIOThreadTaskRunner({})->PostTask(
+ FROM_HERE,
+ base::BindOnce(&CreateLoopbackStreamHelper, factory_.core(),
+ static_cast<content::WebContentsImpl*>(loopback_source)
+ ->GetAudioStreamFactory()
+ ->core(),
+ params, total_segments, std::move(client)));
+ return;
+ }
+ // A null |frame_of_source_web_contents| requests system-wide loopback.
+ content::GetIOThreadTaskRunner({})->PostTask(
+ FROM_HERE,
+ base::BindOnce(&CreateSystemWideLoopbackStreamHelper, factory_.core(),
+ params, total_segments, std::move(client)));
+}
diff --git a/libcef/browser/audio_loopback_stream_creator.h b/libcef/browser/audio_loopback_stream_creator.h
new file mode 100644
index 00000000..1887832a
--- /dev/null
+++ b/libcef/browser/audio_loopback_stream_creator.h
@@ -0,0 +1,53 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_AUDIO_LOOPBACK_STREAM_CREATOR_H_
+#define CEF_LIBCEF_BROWSER_AUDIO_LOOPBACK_STREAM_CREATOR_H_
+
+#include "base/functional/callback.h"
+#include "content/browser/media/forwarding_audio_stream_factory.h"
+#include "content/common/content_export.h"
+#include "media/mojo/mojom/audio_data_pipe.mojom.h"
+#include "media/mojo/mojom/audio_input_stream.mojom.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+
+namespace media {
+class AudioParameters;
+}
+
+// This class handles creating a loopback stream that either captures audio from
+// a WebContents or the system-wide loopback through the Audio Service.
+// This class is operated on the UI thread.
+// Based on InProcessAudioLoopbackStreamCreator which was deleted in
+// https://crrev.com/a5af2468cf.
+class CefAudioLoopbackStreamCreator final {
+ public:
+ CefAudioLoopbackStreamCreator();
+
+ CefAudioLoopbackStreamCreator(const CefAudioLoopbackStreamCreator&) = delete;
+ CefAudioLoopbackStreamCreator& operator=(
+ const CefAudioLoopbackStreamCreator&) = delete;
+
+ ~CefAudioLoopbackStreamCreator();
+
+ // The callback that is called when the requested stream is created.
+ using StreamCreatedCallback = base::RepeatingCallback<void(
+ mojo::PendingRemote<media::mojom::AudioInputStream> stream,
+ mojo::PendingReceiver<media::mojom::AudioInputStreamClient>
+ client_receiver,
+ media::mojom::ReadOnlyAudioDataPipePtr data_pipe)>;
+
+ // Creates a loopback stream that captures the audio from |loopback_source|,
+ // or the default system playback if |loopback_source| is null. Local output
+ // of the source/system audio is muted during capturing.
+ void CreateLoopbackStream(content::WebContents* loopback_source,
+ const media::AudioParameters& params,
+ uint32_t total_segments,
+ const StreamCreatedCallback& callback);
+
+ private:
+ content::ForwardingAudioStreamFactory factory_;
+};
+
+#endif // CEF_LIBCEF_BROWSER_AUDIO_LOOPBACK_STREAM_CREATOR_H_
diff --git a/libcef/browser/browser_contents_delegate.cc b/libcef/browser/browser_contents_delegate.cc
new file mode 100644
index 00000000..a6fc972d
--- /dev/null
+++ b/libcef/browser/browser_contents_delegate.cc
@@ -0,0 +1,720 @@
+// Copyright 2020 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/browser_contents_delegate.h"
+
+#include "libcef/browser/browser_host_base.h"
+#include "libcef/browser/browser_platform_delegate.h"
+#include "libcef/browser/browser_util.h"
+#include "libcef/browser/native/cursor_util.h"
+#include "libcef/common/frame_util.h"
+
+#include "content/browser/renderer_host/render_widget_host_impl.h"
+#include "content/public/browser/focused_node_details.h"
+#include "content/public/browser/keyboard_event_processing_result.h"
+#include "content/public/browser/native_web_keyboard_event.h"
+#include "content/public/browser/navigation_entry.h"
+#include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/notification_details.h"
+#include "content/public/browser/notification_source.h"
+#include "content/public/browser/notification_types.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
+#include "content/public/browser/render_widget_host_observer.h"
+#include "content/public/browser/render_widget_host_view.h"
+#include "third_party/blink/public/mojom/favicon/favicon_url.mojom.h"
+#include "third_party/blink/public/mojom/input/focus_type.mojom-blink.h"
+#include "third_party/blink/public/mojom/widget/platform_widget.mojom-test-utils.h"
+
+using content::KeyboardEventProcessingResult;
+
+namespace {
+
+class CefWidgetHostInterceptor
+ : public blink::mojom::WidgetHostInterceptorForTesting,
+ public content::RenderWidgetHostObserver {
+ public:
+ CefWidgetHostInterceptor(CefRefPtr<CefBrowser> browser,
+ content::RenderWidgetHost* render_widget_host)
+ : browser_(browser),
+ render_widget_host_(render_widget_host),
+ impl_(static_cast<content::RenderWidgetHostImpl*>(render_widget_host)
+ ->widget_host_receiver_for_testing()
+ .SwapImplForTesting(this)) {
+ render_widget_host_->AddObserver(this);
+ }
+
+ CefWidgetHostInterceptor(const CefWidgetHostInterceptor&) = delete;
+ CefWidgetHostInterceptor& operator=(const CefWidgetHostInterceptor&) = delete;
+
+ blink::mojom::WidgetHost* GetForwardingInterface() override { return impl_; }
+
+ // WidgetHostInterceptorForTesting method:
+ void SetCursor(const ui::Cursor& cursor) override {
+ if (cursor_util::OnCursorChange(browser_, cursor)) {
+ // Don't change the cursor.
+ return;
+ }
+
+ GetForwardingInterface()->SetCursor(cursor);
+ }
+
+ // RenderWidgetHostObserver method:
+ void RenderWidgetHostDestroyed(
+ content::RenderWidgetHost* widget_host) override {
+ widget_host->RemoveObserver(this);
+ delete this;
+ }
+
+ private:
+ CefRefPtr<CefBrowser> const browser_;
+ content::RenderWidgetHost* const render_widget_host_;
+ blink::mojom::WidgetHost* const impl_;
+};
+
+} // namespace
+
+CefBrowserContentsDelegate::CefBrowserContentsDelegate(
+ scoped_refptr<CefBrowserInfo> browser_info)
+ : browser_info_(browser_info) {
+ DCHECK(browser_info_->browser());
+}
+
+void CefBrowserContentsDelegate::ObserveWebContents(
+ content::WebContents* new_contents) {
+ WebContentsObserver::Observe(new_contents);
+
+ if (new_contents) {
+ registrar_.reset(new content::NotificationRegistrar);
+
+ // When navigating through the history, the restored NavigationEntry's title
+ // will be used. If the entry ends up having the same title after we return
+ // to it, as will usually be the case, the
+ // NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED will then be suppressed, since
+ // the NavigationEntry's title hasn't changed.
+ registrar_->Add(this, content::NOTIFICATION_LOAD_STOP,
+ content::Source<content::NavigationController>(
+ &new_contents->GetController()));
+
+ // Make sure MaybeCreateFrame is called at least one time.
+ // Create the frame representation before OnAfterCreated is called for a new
+ // browser.
+ browser_info_->MaybeCreateFrame(new_contents->GetPrimaryMainFrame(),
+ false /* is_guest_view */);
+
+ // Make sure RenderWidgetCreated is called at least one time. This Observer
+ // is registered too late to catch the initial creation.
+ RenderWidgetCreated(new_contents->GetRenderViewHost()->GetWidget());
+ } else {
+ registrar_.reset();
+ }
+}
+
+void CefBrowserContentsDelegate::AddObserver(Observer* observer) {
+ observers_.AddObserver(observer);
+}
+
+void CefBrowserContentsDelegate::RemoveObserver(Observer* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+// |source| may be NULL for navigations in the current tab, or if the
+// navigation originates from a guest view via MaybeAllowNavigation.
+content::WebContents* CefBrowserContentsDelegate::OpenURLFromTab(
+ content::WebContents* source,
+ const content::OpenURLParams& params) {
+ bool cancel = false;
+
+ if (auto c = client()) {
+ if (auto handler = c->GetRequestHandler()) {
+ // May return nullptr for omnibox navigations.
+ auto frame = browser()->GetFrame(params.frame_tree_node_id);
+ if (!frame) {
+ frame = browser()->GetMainFrame();
+ }
+ cancel = handler->OnOpenURLFromTab(
+ browser(), frame, params.url.spec(),
+ static_cast<cef_window_open_disposition_t>(params.disposition),
+ params.user_gesture);
+ }
+ }
+
+ // Returning nullptr will cancel the navigation.
+ return cancel ? nullptr : web_contents();
+}
+
+void CefBrowserContentsDelegate::LoadingStateChanged(
+ content::WebContents* source,
+ bool should_show_loading_ui) {
+ const int current_index =
+ source->GetController().GetLastCommittedEntryIndex();
+ const int max_index = source->GetController().GetEntryCount() - 1;
+
+ const bool is_loading = source->IsLoading();
+ const bool can_go_back = (current_index > 0);
+ const bool can_go_forward = (current_index < max_index);
+
+ // This method may be called multiple times in a row with |is_loading|
+ // true as a result of https://crrev.com/5e750ad0. Ignore the 2nd+ times.
+ if (is_loading_ == is_loading && can_go_back_ == can_go_back &&
+ can_go_forward_ == can_go_forward) {
+ return;
+ }
+
+ is_loading_ = is_loading;
+ can_go_back_ = can_go_back;
+ can_go_forward_ = can_go_forward;
+ OnStateChanged(State::kNavigation);
+
+ if (auto c = client()) {
+ if (auto handler = c->GetLoadHandler()) {
+ auto navigation_lock = browser_info_->CreateNavigationLock();
+ handler->OnLoadingStateChange(browser(), is_loading, can_go_back,
+ can_go_forward);
+ }
+ }
+}
+
+void CefBrowserContentsDelegate::UpdateTargetURL(content::WebContents* source,
+ const GURL& url) {
+ if (auto c = client()) {
+ if (auto handler = c->GetDisplayHandler()) {
+ handler->OnStatusMessage(browser(), url.spec());
+ }
+ }
+}
+
+bool CefBrowserContentsDelegate::DidAddMessageToConsole(
+ content::WebContents* source,
+ blink::mojom::ConsoleMessageLevel log_level,
+ const std::u16string& message,
+ int32_t line_no,
+ const std::u16string& source_id) {
+ if (auto c = client()) {
+ if (auto handler = c->GetDisplayHandler()) {
+ // Use LOGSEVERITY_DEBUG for unrecognized |level| values.
+ cef_log_severity_t cef_level = LOGSEVERITY_DEBUG;
+ switch (log_level) {
+ case blink::mojom::ConsoleMessageLevel::kVerbose:
+ cef_level = LOGSEVERITY_DEBUG;
+ break;
+ case blink::mojom::ConsoleMessageLevel::kInfo:
+ cef_level = LOGSEVERITY_INFO;
+ break;
+ case blink::mojom::ConsoleMessageLevel::kWarning:
+ cef_level = LOGSEVERITY_WARNING;
+ break;
+ case blink::mojom::ConsoleMessageLevel::kError:
+ cef_level = LOGSEVERITY_ERROR;
+ break;
+ }
+
+ return handler->OnConsoleMessage(browser(), cef_level, message, source_id,
+ line_no);
+ }
+ }
+
+ return false;
+}
+
+void CefBrowserContentsDelegate::EnterFullscreenModeForTab(
+ content::RenderFrameHost* requesting_frame,
+ const blink::mojom::FullscreenOptions& options) {
+ OnFullscreenModeChange(/*fullscreen=*/true);
+}
+
+void CefBrowserContentsDelegate::ExitFullscreenModeForTab(
+ content::WebContents* web_contents) {
+ OnFullscreenModeChange(/*fullscreen=*/false);
+}
+
+void CefBrowserContentsDelegate::CanDownload(
+ const GURL& url,
+ const std::string& request_method,
+ base::OnceCallback<void(bool)> callback) {
+ bool allow = true;
+
+ if (auto delegate = platform_delegate()) {
+ if (auto c = client()) {
+ if (auto handler = c->GetDownloadHandler()) {
+ allow = handler->CanDownload(browser(), url.spec(), request_method);
+ }
+ }
+ }
+
+ std::move(callback).Run(allow);
+}
+
+KeyboardEventProcessingResult
+CefBrowserContentsDelegate::PreHandleKeyboardEvent(
+ content::WebContents* source,
+ const content::NativeWebKeyboardEvent& event) {
+ if (auto delegate = platform_delegate()) {
+ if (auto c = client()) {
+ if (auto handler = c->GetKeyboardHandler()) {
+ CefKeyEvent cef_event;
+ if (browser_util::GetCefKeyEvent(event, cef_event)) {
+ cef_event.focus_on_editable_field = focus_on_editable_field_;
+
+ auto event_handle = delegate->GetEventHandle(event);
+ bool is_keyboard_shortcut = false;
+ bool result = handler->OnPreKeyEvent(
+ browser(), cef_event, event_handle, &is_keyboard_shortcut);
+ if (result) {
+ return KeyboardEventProcessingResult::HANDLED;
+ } else if (is_keyboard_shortcut) {
+ return KeyboardEventProcessingResult::NOT_HANDLED_IS_SHORTCUT;
+ }
+ }
+ }
+ }
+ }
+
+ return KeyboardEventProcessingResult::NOT_HANDLED;
+}
+
+bool CefBrowserContentsDelegate::HandleKeyboardEvent(
+ content::WebContents* source,
+ const content::NativeWebKeyboardEvent& event) {
+ // Check to see if event should be ignored.
+ if (event.skip_in_browser) {
+ return false;
+ }
+
+ if (auto delegate = platform_delegate()) {
+ if (auto c = client()) {
+ if (auto handler = c->GetKeyboardHandler()) {
+ CefKeyEvent cef_event;
+ if (browser_util::GetCefKeyEvent(event, cef_event)) {
+ cef_event.focus_on_editable_field = focus_on_editable_field_;
+
+ auto event_handle = delegate->GetEventHandle(event);
+ if (handler->OnKeyEvent(browser(), cef_event, event_handle)) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+void CefBrowserContentsDelegate::RenderFrameCreated(
+ content::RenderFrameHost* render_frame_host) {
+ browser_info_->MaybeCreateFrame(render_frame_host, false /* is_guest_view */);
+ if (render_frame_host->GetParent() == nullptr) {
+ auto render_view_host = render_frame_host->GetRenderViewHost();
+ auto base_background_color = platform_delegate()->GetBackgroundColor();
+ if (browser_info_ && browser_info_->is_popup()) {
+ // force reset page base background color because popup window won't get
+ // the page base background from web_contents at the creation time
+ web_contents()->SetPageBaseBackgroundColor(SkColor());
+ web_contents()->SetPageBaseBackgroundColor(base_background_color);
+ }
+ if (render_view_host->GetWidget() &&
+ render_view_host->GetWidget()->GetView()) {
+ render_view_host->GetWidget()->GetView()->SetBackgroundColor(
+ base_background_color);
+ }
+
+ platform_delegate()->RenderViewCreated(render_view_host);
+ }
+}
+
+void CefBrowserContentsDelegate::RenderFrameHostChanged(
+ content::RenderFrameHost* old_host,
+ content::RenderFrameHost* new_host) {
+ // Just in case RenderFrameCreated wasn't called for some reason.
+ RenderFrameCreated(new_host);
+}
+
+void CefBrowserContentsDelegate::RenderFrameHostStateChanged(
+ content::RenderFrameHost* host,
+ content::RenderFrameHost::LifecycleState old_state,
+ content::RenderFrameHost::LifecycleState new_state) {
+ browser_info_->FrameHostStateChanged(host, old_state, new_state);
+}
+
+void CefBrowserContentsDelegate::RenderFrameDeleted(
+ content::RenderFrameHost* render_frame_host) {
+ const auto frame_id =
+ frame_util::MakeFrameId(render_frame_host->GetGlobalId());
+ browser_info_->RemoveFrame(render_frame_host);
+
+ if (focused_frame_ && focused_frame_->GetIdentifier() == frame_id) {
+ focused_frame_ = nullptr;
+ OnStateChanged(State::kFocusedFrame);
+ }
+}
+
+void CefBrowserContentsDelegate::RenderWidgetCreated(
+ content::RenderWidgetHost* render_widget_host) {
+ new CefWidgetHostInterceptor(browser(), render_widget_host);
+}
+
+void CefBrowserContentsDelegate::RenderViewReady() {
+ platform_delegate()->RenderViewReady();
+
+ if (auto c = client()) {
+ if (auto handler = c->GetRequestHandler()) {
+ handler->OnRenderViewReady(browser());
+ }
+ }
+}
+
+void CefBrowserContentsDelegate::PrimaryMainFrameRenderProcessGone(
+ base::TerminationStatus status) {
+ cef_termination_status_t ts = TS_ABNORMAL_TERMINATION;
+ if (status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED) {
+ ts = TS_PROCESS_WAS_KILLED;
+ } else if (status == base::TERMINATION_STATUS_PROCESS_CRASHED) {
+ ts = TS_PROCESS_CRASHED;
+ } else if (status == base::TERMINATION_STATUS_OOM) {
+ ts = TS_PROCESS_OOM;
+ } else if (status != base::TERMINATION_STATUS_ABNORMAL_TERMINATION) {
+ return;
+ }
+
+ if (auto c = client()) {
+ if (auto handler = c->GetRequestHandler()) {
+ auto navigation_lock = browser_info_->CreateNavigationLock();
+ handler->OnRenderProcessTerminated(browser(), ts);
+ }
+ }
+}
+
+void CefBrowserContentsDelegate::OnFrameFocused(
+ content::RenderFrameHost* render_frame_host) {
+ CefRefPtr<CefFrameHostImpl> frame = static_cast<CefFrameHostImpl*>(
+ browser_info_->GetFrameForHost(render_frame_host).get());
+ if (!frame || frame->IsFocused()) {
+ return;
+ }
+
+ CefRefPtr<CefFrameHostImpl> previous_frame = focused_frame_;
+ if (frame->IsMain()) {
+ focused_frame_ = nullptr;
+ } else {
+ focused_frame_ = frame;
+ }
+
+ if (!previous_frame) {
+ // The main frame is focused by default.
+ previous_frame = browser_info_->GetMainFrame();
+ }
+
+ if (previous_frame->GetIdentifier() != frame->GetIdentifier()) {
+ previous_frame->SetFocused(false);
+ frame->SetFocused(true);
+ }
+
+ OnStateChanged(State::kFocusedFrame);
+}
+
+void CefBrowserContentsDelegate::PrimaryMainDocumentElementAvailable() {
+ has_document_ = true;
+ OnStateChanged(State::kDocument);
+
+ if (auto c = client()) {
+ if (auto handler = c->GetRequestHandler()) {
+ handler->OnDocumentAvailableInMainFrame(browser());
+ }
+ }
+}
+
+void CefBrowserContentsDelegate::LoadProgressChanged(double progress) {
+ if (auto c = client()) {
+ if (auto handler = c->GetDisplayHandler()) {
+ handler->OnLoadingProgressChange(browser(), progress);
+ }
+ }
+}
+
+void CefBrowserContentsDelegate::DidStopLoading() {
+ // Notify all renderers that loading has stopped. We used to use
+ // RenderFrameObserver::DidStopLoading in the renderer process but that was
+ // removed in https://crrev.com/3e37dd0ead. However, that callback wasn't
+ // necessarily accurate because it wasn't called in all of the cases where
+ // RenderFrameImpl sends the FrameHostMsg_DidStopLoading message. This adds
+ // an additional round trip but should provide the same or improved
+ // functionality.
+ for (const auto& frame : browser_info_->GetAllFrames()) {
+ frame->MaybeSendDidStopLoading();
+ }
+}
+
+void CefBrowserContentsDelegate::DidFinishNavigation(
+ content::NavigationHandle* navigation_handle) {
+ const net::Error error_code = navigation_handle->GetNetErrorCode();
+
+ // Skip calls where the navigation has not yet committed and there is no
+ // error code. For example, when creating a browser without loading a URL.
+ if (!navigation_handle->HasCommitted() && error_code == net::OK) {
+ return;
+ }
+
+ if (navigation_handle->IsInPrimaryMainFrame() &&
+ navigation_handle->HasCommitted()) {
+ // A primary main frame navigation has occured.
+ has_document_ = false;
+ OnStateChanged(State::kDocument);
+ }
+
+ const bool is_main_frame = navigation_handle->IsInMainFrame();
+ const auto global_id = frame_util::GetGlobalId(navigation_handle);
+ const GURL& url =
+ (error_code == net::OK ? navigation_handle->GetURL() : GURL());
+
+ auto browser_info = browser_info_;
+ if (!browser_info->browser()) {
+ // Ignore notifications when the browser is closing.
+ return;
+ }
+
+ // May return NULL when starting a new navigation if the previous navigation
+ // caused the renderer process to crash during load.
+ CefRefPtr<CefFrameHostImpl> frame =
+ browser_info->GetFrameForGlobalId(global_id);
+ if (!frame) {
+ if (is_main_frame) {
+ frame = browser_info->GetMainFrame();
+ } else {
+ frame = browser_info->CreateTempSubFrame(frame_util::InvalidGlobalId());
+ }
+ }
+ frame->RefreshAttributes();
+
+ if (error_code == net::OK) {
+ // The navigation has been committed and there is no error.
+ DCHECK(navigation_handle->HasCommitted());
+
+ // Don't call OnLoadStart for same page navigations (fragments,
+ // history state).
+ if (!navigation_handle->IsSameDocument()) {
+ OnLoadStart(frame.get(), navigation_handle->GetPageTransition());
+ if (navigation_handle->IsServedFromBackForwardCache()) {
+ // We won't get an OnLoadEnd notification from anywhere else.
+ OnLoadEnd(frame.get(), navigation_handle->GetURL(), 0);
+ }
+ }
+
+ if (is_main_frame) {
+ OnAddressChange(url);
+ }
+ } else {
+ // The navigation failed with an error. This may happen before commit
+ // (e.g. network error) or after commit (e.g. response filter error).
+ // If the error happened before commit then this call will originate from
+ // RenderFrameHostImpl::OnDidFailProvisionalLoadWithError.
+ // OnLoadStart/OnLoadEnd will not be called.
+ OnLoadError(frame.get(), navigation_handle->GetURL(), error_code);
+ }
+}
+
+void CefBrowserContentsDelegate::DidFailLoad(
+ content::RenderFrameHost* render_frame_host,
+ const GURL& validated_url,
+ int error_code) {
+ // The navigation failed after commit. OnLoadStart was called so we also
+ // call OnLoadEnd.
+ auto frame = browser_info_->GetFrameForHost(render_frame_host);
+ frame->RefreshAttributes();
+ OnLoadError(frame, validated_url, error_code);
+ OnLoadEnd(frame, validated_url, error_code);
+}
+
+void CefBrowserContentsDelegate::DidFinishLoad(
+ content::RenderFrameHost* render_frame_host,
+ const GURL& validated_url) {
+ auto frame = browser_info_->GetFrameForHost(render_frame_host);
+ frame->RefreshAttributes();
+
+ int http_status_code = 0;
+ if (auto response_headers = render_frame_host->GetLastResponseHeaders()) {
+ http_status_code = response_headers->response_code();
+ }
+
+ OnLoadEnd(frame, validated_url, http_status_code);
+}
+
+void CefBrowserContentsDelegate::TitleWasSet(content::NavigationEntry* entry) {
+ // |entry| may be NULL if a popup is created via window.open and never
+ // navigated.
+ if (entry) {
+ OnTitleChange(entry->GetTitle());
+ } else if (web_contents()) {
+ OnTitleChange(web_contents()->GetTitle());
+ }
+}
+
+void CefBrowserContentsDelegate::DidUpdateFaviconURL(
+ content::RenderFrameHost* render_frame_host,
+ const std::vector<blink::mojom::FaviconURLPtr>& candidates) {
+ if (auto c = client()) {
+ if (auto handler = c->GetDisplayHandler()) {
+ std::vector<CefString> icon_urls;
+ for (const auto& icon : candidates) {
+ if (icon->icon_type == blink::mojom::FaviconIconType::kFavicon) {
+ icon_urls.push_back(icon->icon_url.spec());
+ }
+ }
+ if (!icon_urls.empty()) {
+ handler->OnFaviconURLChange(browser(), icon_urls);
+ }
+ }
+ }
+}
+
+void CefBrowserContentsDelegate::OnWebContentsFocused(
+ content::RenderWidgetHost* render_widget_host) {
+ if (auto c = client()) {
+ if (auto handler = c->GetFocusHandler()) {
+ handler->OnGotFocus(browser());
+ }
+ }
+}
+
+void CefBrowserContentsDelegate::OnFocusChangedInPage(
+ content::FocusedNodeDetails* details) {
+ focus_on_editable_field_ =
+ details->focus_type != blink::mojom::blink::FocusType::kNone &&
+ details->is_editable_node;
+}
+
+void CefBrowserContentsDelegate::WebContentsDestroyed() {
+ auto wc = web_contents();
+ ObserveWebContents(nullptr);
+ for (auto& observer : observers_) {
+ observer.OnWebContentsDestroyed(wc);
+ }
+}
+
+void CefBrowserContentsDelegate::Observe(
+ int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) {
+ DCHECK_EQ(type, content::NOTIFICATION_LOAD_STOP);
+
+ if (type == content::NOTIFICATION_LOAD_STOP) {
+ OnTitleChange(web_contents()->GetTitle());
+ }
+}
+
+bool CefBrowserContentsDelegate::OnSetFocus(cef_focus_source_t source) {
+ // SetFocus() might be called while inside the OnSetFocus() callback. If
+ // so, don't re-enter the callback.
+ if (is_in_onsetfocus_) {
+ return true;
+ }
+
+ if (auto c = client()) {
+ if (auto handler = c->GetFocusHandler()) {
+ is_in_onsetfocus_ = true;
+ bool handled = handler->OnSetFocus(browser(), source);
+ is_in_onsetfocus_ = false;
+
+ return handled;
+ }
+ }
+
+ return false;
+}
+
+CefRefPtr<CefClient> CefBrowserContentsDelegate::client() const {
+ if (auto b = browser()) {
+ return b->GetHost()->GetClient();
+ }
+ return nullptr;
+}
+
+CefRefPtr<CefBrowser> CefBrowserContentsDelegate::browser() const {
+ return browser_info_->browser();
+}
+
+CefBrowserPlatformDelegate* CefBrowserContentsDelegate::platform_delegate()
+ const {
+ auto browser = browser_info_->browser();
+ if (browser) {
+ return browser->platform_delegate();
+ }
+ return nullptr;
+}
+
+void CefBrowserContentsDelegate::OnAddressChange(const GURL& url) {
+ if (auto c = client()) {
+ if (auto handler = c->GetDisplayHandler()) {
+ // On the handler of an address change.
+ handler->OnAddressChange(browser(), browser_info_->GetMainFrame(),
+ url.spec());
+ }
+ }
+}
+
+void CefBrowserContentsDelegate::OnLoadStart(
+ CefRefPtr<CefFrame> frame,
+ ui::PageTransition transition_type) {
+ if (auto c = client()) {
+ if (auto handler = c->GetLoadHandler()) {
+ auto navigation_lock = browser_info_->CreateNavigationLock();
+ // On the handler that loading has started.
+ handler->OnLoadStart(browser(), frame,
+ static_cast<cef_transition_type_t>(transition_type));
+ }
+ }
+}
+
+void CefBrowserContentsDelegate::OnLoadEnd(CefRefPtr<CefFrame> frame,
+ const GURL& url,
+ int http_status_code) {
+ if (auto c = client()) {
+ if (auto handler = c->GetLoadHandler()) {
+ auto navigation_lock = browser_info_->CreateNavigationLock();
+ handler->OnLoadEnd(browser(), frame, http_status_code);
+ }
+ }
+}
+
+void CefBrowserContentsDelegate::OnLoadError(CefRefPtr<CefFrame> frame,
+ const GURL& url,
+ int error_code) {
+ if (auto c = client()) {
+ if (auto handler = c->GetLoadHandler()) {
+ auto navigation_lock = browser_info_->CreateNavigationLock();
+ // On the handler that loading has failed.
+ handler->OnLoadError(browser(), frame,
+ static_cast<cef_errorcode_t>(error_code),
+ net::ErrorToShortString(error_code), url.spec());
+ }
+ }
+}
+
+void CefBrowserContentsDelegate::OnTitleChange(const std::u16string& title) {
+ if (auto c = client()) {
+ if (auto handler = c->GetDisplayHandler()) {
+ handler->OnTitleChange(browser(), title);
+ }
+ }
+}
+
+void CefBrowserContentsDelegate::OnFullscreenModeChange(bool fullscreen) {
+ if (fullscreen == is_fullscreen_) {
+ return;
+ }
+
+ is_fullscreen_ = fullscreen;
+ OnStateChanged(State::kFullscreen);
+
+ if (auto c = client()) {
+ if (auto handler = c->GetDisplayHandler()) {
+ handler->OnFullscreenModeChange(browser(), fullscreen);
+ }
+ }
+}
+
+void CefBrowserContentsDelegate::OnStateChanged(State state_changed) {
+ for (auto& observer : observers_) {
+ observer.OnStateChanged(state_changed);
+ }
+}
diff --git a/libcef/browser/browser_contents_delegate.h b/libcef/browser/browser_contents_delegate.h
new file mode 100644
index 00000000..87c931eb
--- /dev/null
+++ b/libcef/browser/browser_contents_delegate.h
@@ -0,0 +1,206 @@
+// Copyright 2020 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_BROWSER_CONTENTS_DELEGATE_H_
+#define CEF_LIBCEF_BROWSER_BROWSER_CONTENTS_DELEGATE_H_
+#pragma once
+
+#include <memory>
+
+#include "libcef/browser/frame_host_impl.h"
+
+#include "base/callback_list.h"
+#include "base/observer_list.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
+#include "content/public/browser/web_contents_delegate.h"
+#include "content/public/browser/web_contents_observer.h"
+
+class CefBrowser;
+class CefBrowserInfo;
+class CefBrowserPlatformDelegate;
+class CefClient;
+
+// Flags that represent which states have changed.
+enum class CefBrowserContentsState : uint8_t {
+ kNone = 0,
+ kNavigation = (1 << 0),
+ kDocument = (1 << 1),
+ kFullscreen = (1 << 2),
+ kFocusedFrame = (1 << 3),
+};
+
+constexpr inline CefBrowserContentsState operator&(
+ CefBrowserContentsState lhs,
+ CefBrowserContentsState rhs) {
+ return static_cast<CefBrowserContentsState>(static_cast<int>(lhs) &
+ static_cast<int>(rhs));
+}
+
+constexpr inline CefBrowserContentsState operator|(
+ CefBrowserContentsState lhs,
+ CefBrowserContentsState rhs) {
+ return static_cast<CefBrowserContentsState>(static_cast<int>(lhs) |
+ static_cast<int>(rhs));
+}
+
+// Tracks state and executes client callbacks based on WebContents callbacks.
+// Includes functionality that is shared by the alloy and chrome runtimes.
+// Only accessed on the UI thread.
+class CefBrowserContentsDelegate : public content::WebContentsDelegate,
+ public content::WebContentsObserver,
+ public content::NotificationObserver {
+ public:
+ using State = CefBrowserContentsState;
+
+ // Interface to implement for observers that wish to be informed of changes
+ // to the delegate. All methods will be called on the UI thread.
+ class Observer : public base::CheckedObserver {
+ public:
+ // Called after state has changed and before the associated CefClient
+ // callback is executed.
+ virtual void OnStateChanged(State state_changed) = 0;
+
+ // Called when the associated WebContents is destroyed.
+ virtual void OnWebContentsDestroyed(content::WebContents* web_contents) = 0;
+
+ protected:
+ ~Observer() override {}
+ };
+
+ explicit CefBrowserContentsDelegate(
+ scoped_refptr<CefBrowserInfo> browser_info);
+
+ CefBrowserContentsDelegate(const CefBrowserContentsDelegate&) = delete;
+ CefBrowserContentsDelegate& operator=(const CefBrowserContentsDelegate&) =
+ delete;
+
+ void ObserveWebContents(content::WebContents* new_contents);
+
+ // Manage observer objects. The observer must either outlive this object or
+ // be removed before destruction.
+ void AddObserver(Observer* observer);
+ void RemoveObserver(Observer* observer);
+
+ // WebContentsDelegate methods:
+ content::WebContents* OpenURLFromTab(
+ content::WebContents* source,
+ const content::OpenURLParams& params) override;
+ void LoadingStateChanged(content::WebContents* source,
+ bool should_show_loading_ui) override;
+ void UpdateTargetURL(content::WebContents* source, const GURL& url) override;
+ bool DidAddMessageToConsole(content::WebContents* source,
+ blink::mojom::ConsoleMessageLevel log_level,
+ const std::u16string& message,
+ int32_t line_no,
+ const std::u16string& source_id) override;
+ void EnterFullscreenModeForTab(
+ content::RenderFrameHost* requesting_frame,
+ const blink::mojom::FullscreenOptions& options) override;
+ void ExitFullscreenModeForTab(content::WebContents* web_contents) override;
+ void CanDownload(const GURL& url,
+ const std::string& request_method,
+ base::OnceCallback<void(bool)> callback) override;
+ content::KeyboardEventProcessingResult PreHandleKeyboardEvent(
+ content::WebContents* source,
+ const content::NativeWebKeyboardEvent& event) override;
+ bool HandleKeyboardEvent(
+ content::WebContents* source,
+ const content::NativeWebKeyboardEvent& event) override;
+
+ // WebContentsObserver methods:
+ void RenderFrameCreated(content::RenderFrameHost* render_frame_host) override;
+ void RenderFrameHostChanged(content::RenderFrameHost* old_host,
+ content::RenderFrameHost* new_host) override;
+ void RenderFrameHostStateChanged(
+ content::RenderFrameHost* host,
+ content::RenderFrameHost::LifecycleState old_state,
+ content::RenderFrameHost::LifecycleState new_state) override;
+ void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) override;
+ void RenderWidgetCreated(
+ content::RenderWidgetHost* render_widget_host) override;
+ void RenderViewReady() override;
+ void PrimaryMainFrameRenderProcessGone(
+ base::TerminationStatus status) override;
+ void OnFrameFocused(content::RenderFrameHost* render_frame_host) override;
+ void PrimaryMainDocumentElementAvailable() override;
+ void LoadProgressChanged(double progress) override;
+ void DidStopLoading() override;
+ void DidFinishNavigation(
+ content::NavigationHandle* navigation_handle) override;
+ void DidFailLoad(content::RenderFrameHost* render_frame_host,
+ const GURL& validated_url,
+ int error_code) override;
+ void DidFinishLoad(content::RenderFrameHost* render_frame_host,
+ const GURL& validated_url) override;
+ void TitleWasSet(content::NavigationEntry* entry) override;
+ void DidUpdateFaviconURL(
+ content::RenderFrameHost* render_frame_host,
+ const std::vector<blink::mojom::FaviconURLPtr>& candidates) override;
+ void OnWebContentsFocused(
+ content::RenderWidgetHost* render_widget_host) override;
+ void OnFocusChangedInPage(content::FocusedNodeDetails* details) override;
+ void WebContentsDestroyed() override;
+
+ // NotificationObserver methods.
+ void Observe(int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) override;
+
+ // Accessors for state information. Changes will be signaled to
+ // Observer::OnStateChanged.
+ bool is_loading() const { return is_loading_; }
+ bool can_go_back() const { return can_go_back_; }
+ bool can_go_forward() const { return can_go_forward_; }
+ bool has_document() const { return has_document_; }
+ bool is_fullscreen() const { return is_fullscreen_; }
+ CefRefPtr<CefFrameHostImpl> focused_frame() const { return focused_frame_; }
+
+ // Helpers for executing client callbacks.
+ // TODO(cef): Make this private if/when possible.
+ bool OnSetFocus(cef_focus_source_t source);
+
+ private:
+ CefRefPtr<CefClient> client() const;
+ CefRefPtr<CefBrowser> browser() const;
+ CefBrowserPlatformDelegate* platform_delegate() const;
+
+ // Helpers for executing client callbacks.
+ void OnAddressChange(const GURL& url);
+ void OnLoadStart(CefRefPtr<CefFrame> frame,
+ ui::PageTransition transition_type);
+ void OnLoadEnd(CefRefPtr<CefFrame> frame,
+ const GURL& url,
+ int http_status_code);
+ void OnLoadError(CefRefPtr<CefFrame> frame, const GURL& url, int error_code);
+ void OnTitleChange(const std::u16string& title);
+ void OnFullscreenModeChange(bool fullscreen);
+
+ void OnStateChanged(State state_changed);
+
+ scoped_refptr<CefBrowserInfo> browser_info_;
+
+ bool is_loading_ = false;
+ bool can_go_back_ = false;
+ bool can_go_forward_ = false;
+ bool has_document_ = false;
+ bool is_fullscreen_ = false;
+
+ // The currently focused frame, or nullptr if the main frame is focused.
+ CefRefPtr<CefFrameHostImpl> focused_frame_;
+
+ // True if currently in the OnSetFocus callback.
+ bool is_in_onsetfocus_ = false;
+
+ // Observers that want to be notified of changes to this object.
+ base::ObserverList<Observer> observers_;
+
+ // Used for managing notification subscriptions.
+ std::unique_ptr<content::NotificationRegistrar> registrar_;
+
+ // True if the focus is currently on an editable field on the page.
+ bool focus_on_editable_field_ = false;
+};
+
+#endif // CEF_LIBCEF_BROWSER_BROWSER_CONTENTS_DELEGATE_H_
diff --git a/libcef/browser/browser_context.cc b/libcef/browser/browser_context.cc
new file mode 100644
index 00000000..eddb623c
--- /dev/null
+++ b/libcef/browser/browser_context.cc
@@ -0,0 +1,445 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/browser_context.h"
+
+#include <map>
+#include <utility>
+
+#include "libcef/browser/context.h"
+#include "libcef/browser/media_router/media_router_manager.h"
+#include "libcef/browser/request_context_impl.h"
+#include "libcef/browser/thread_util.h"
+#include "libcef/common/cef_switches.h"
+#include "libcef/common/frame_util.h"
+#include "libcef/features/runtime.h"
+
+#include "base/files/file_util.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/no_destructor.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "chrome/browser/profiles/profile.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/storage_partition.h"
+
+using content::BrowserThread;
+
+namespace {
+
+// Manages the global list of Impl instances.
+class ImplManager {
+ public:
+ using Vector = std::vector<CefBrowserContext*>;
+
+ ImplManager() {}
+
+ ImplManager(const ImplManager&) = delete;
+ ImplManager& operator=(const ImplManager&) = delete;
+
+ ~ImplManager() {
+ DCHECK(all_.empty());
+ DCHECK(map_.empty());
+ }
+
+ void AddImpl(CefBrowserContext* impl) {
+ CEF_REQUIRE_UIT();
+ DCHECK(!IsValidImpl(impl));
+ all_.push_back(impl);
+ }
+
+ void RemoveImpl(CefBrowserContext* impl, const base::FilePath& path) {
+ CEF_REQUIRE_UIT();
+
+ {
+ Vector::iterator it = GetImplPos(impl);
+ DCHECK(it != all_.end());
+ all_.erase(it);
+ }
+
+ if (!path.empty()) {
+ PathMap::iterator it = map_.find(path);
+ DCHECK(it != map_.end());
+ if (it != map_.end()) {
+ map_.erase(it);
+ }
+ }
+ }
+
+ bool IsValidImpl(const CefBrowserContext* impl) {
+ CEF_REQUIRE_UIT();
+ return GetImplPos(impl) != all_.end();
+ }
+
+ CefBrowserContext* GetImplFromGlobalId(
+ const content::GlobalRenderFrameHostId& global_id,
+ bool require_frame_match) {
+ CEF_REQUIRE_UIT();
+ for (const auto& context : all_) {
+ if (context->IsAssociatedContext(global_id, require_frame_match)) {
+ return context;
+ }
+ }
+ return nullptr;
+ }
+
+ CefBrowserContext* GetImplFromBrowserContext(
+ const content::BrowserContext* context) {
+ CEF_REQUIRE_UIT();
+ if (!context) {
+ return nullptr;
+ }
+
+ for (const auto& bc : all_) {
+ if (bc->AsBrowserContext() == context) {
+ return bc;
+ }
+ }
+ return nullptr;
+ }
+
+ void SetImplPath(CefBrowserContext* impl, const base::FilePath& path) {
+ CEF_REQUIRE_UIT();
+ DCHECK(!path.empty());
+ DCHECK(IsValidImpl(impl));
+ DCHECK(GetImplFromPath(path) == nullptr);
+ map_.insert(std::make_pair(path, impl));
+ }
+
+ CefBrowserContext* GetImplFromPath(const base::FilePath& path) {
+ CEF_REQUIRE_UIT();
+ DCHECK(!path.empty());
+ PathMap::const_iterator it = map_.find(path);
+ if (it != map_.end()) {
+ return it->second;
+ }
+ return nullptr;
+ }
+
+ const Vector GetAllImpl() const { return all_; }
+
+ private:
+ Vector::iterator GetImplPos(const CefBrowserContext* impl) {
+ Vector::iterator it = all_.begin();
+ for (; it != all_.end(); ++it) {
+ if (*it == impl) {
+ return it;
+ }
+ }
+ return all_.end();
+ }
+
+ using PathMap = std::map<base::FilePath, CefBrowserContext*>;
+ PathMap map_;
+
+ Vector all_;
+};
+
+#if DCHECK_IS_ON()
+// Because of DCHECK()s in the object destructor.
+base::LazyInstance<ImplManager>::DestructorAtExit g_manager =
+ LAZY_INSTANCE_INITIALIZER;
+#else
+base::LazyInstance<ImplManager>::Leaky g_manager = LAZY_INSTANCE_INITIALIZER;
+#endif
+
+CefBrowserContext* GetSelf(base::WeakPtr<CefBrowserContext> self) {
+ CEF_REQUIRE_UIT();
+ return self.get();
+}
+
+CefBrowserContext::CookieableSchemes MakeSupportedSchemes(
+ const CefString& schemes_list,
+ bool include_defaults) {
+ if (schemes_list.empty() && include_defaults) {
+ // No explicit registration of schemes.
+ return absl::nullopt;
+ }
+
+ std::vector<std::string> all_schemes;
+ if (!schemes_list.empty()) {
+ all_schemes =
+ base::SplitString(schemes_list.ToString(), std::string(","),
+ base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+ }
+
+ if (include_defaults) {
+ // Add default schemes that should always support cookies.
+ // This list should match CookieMonster::kDefaultCookieableSchemes.
+ all_schemes.push_back("http");
+ all_schemes.push_back("https");
+ all_schemes.push_back("ws");
+ all_schemes.push_back("wss");
+ }
+
+ return absl::make_optional(all_schemes);
+}
+
+template <typename T>
+CefBrowserContext::CookieableSchemes MakeSupportedSchemes(const T& settings) {
+ return MakeSupportedSchemes(CefString(&settings.cookieable_schemes_list),
+ !settings.cookieable_schemes_exclude_defaults);
+}
+
+} // namespace
+
+CefBrowserContext::CefBrowserContext(const CefRequestContextSettings& settings)
+ : settings_(settings), weak_ptr_factory_(this) {
+ g_manager.Get().AddImpl(this);
+ getter_ = base::BindRepeating(GetSelf, weak_ptr_factory_.GetWeakPtr());
+}
+
+CefBrowserContext::~CefBrowserContext() {
+ CEF_REQUIRE_UIT();
+#if DCHECK_IS_ON()
+ DCHECK(is_shutdown_);
+#endif
+}
+
+void CefBrowserContext::Initialize() {
+ cache_path_ = base::FilePath(CefString(&settings_.cache_path));
+
+ if (!cache_path_.empty()) {
+ g_manager.Get().SetImplPath(this, cache_path_);
+ }
+
+ iothread_state_ = base::MakeRefCounted<CefIOThreadState>();
+ cookieable_schemes_ = MakeSupportedSchemes(settings_);
+}
+
+void CefBrowserContext::Shutdown() {
+ CEF_REQUIRE_UIT();
+
+#if DCHECK_IS_ON()
+ is_shutdown_ = true;
+#endif
+
+ // No CefRequestContext should be referencing this object any longer.
+ DCHECK(request_context_set_.empty());
+
+ // Unregister the context first to avoid re-entrancy during shutdown.
+ g_manager.Get().RemoveImpl(this, cache_path_);
+
+ // Destroy objects that may hold references to the MediaRouter.
+ media_router_manager_.reset();
+
+ // Invalidate any Getter references to this object.
+ weak_ptr_factory_.InvalidateWeakPtrs();
+}
+
+void CefBrowserContext::AddCefRequestContext(CefRequestContextImpl* context) {
+ CEF_REQUIRE_UIT();
+ request_context_set_.insert(context);
+}
+
+void CefBrowserContext::RemoveCefRequestContext(
+ CefRequestContextImpl* context) {
+ CEF_REQUIRE_UIT();
+
+ request_context_set_.erase(context);
+
+ // Delete ourselves when the reference count reaches zero.
+ if (request_context_set_.empty()) {
+ Shutdown();
+
+ // Allow the current call stack to unwind before deleting |this|.
+ content::BrowserThread::DeleteSoon(CEF_UIT, FROM_HERE, this);
+ }
+}
+
+// static
+CefBrowserContext* CefBrowserContext::FromCachePath(
+ const base::FilePath& cache_path) {
+ return g_manager.Get().GetImplFromPath(cache_path);
+}
+
+// static
+CefBrowserContext* CefBrowserContext::FromGlobalId(
+ const content::GlobalRenderFrameHostId& global_id,
+ bool require_frame_match) {
+ return g_manager.Get().GetImplFromGlobalId(global_id, require_frame_match);
+}
+
+// static
+CefBrowserContext* CefBrowserContext::FromBrowserContext(
+ const content::BrowserContext* context) {
+ return g_manager.Get().GetImplFromBrowserContext(context);
+}
+
+// static
+CefBrowserContext* CefBrowserContext::FromProfile(const Profile* profile) {
+ auto* cef_context = FromBrowserContext(profile);
+ if (cef_context) {
+ return cef_context;
+ }
+
+ if (cef::IsChromeRuntimeEnabled()) {
+ auto* original_profile = profile->GetOriginalProfile();
+ if (original_profile != profile) {
+ // With the Chrome runtime if the user launches an incognito window via
+ // the UI we might be associated with the original Profile instead of the
+ // (current) incognito profile.
+ return FromBrowserContext(original_profile);
+ }
+ }
+
+ return nullptr;
+}
+
+// static
+std::vector<CefBrowserContext*> CefBrowserContext::GetAll() {
+ return g_manager.Get().GetAllImpl();
+}
+
+void CefBrowserContext::OnRenderFrameCreated(
+ CefRequestContextImpl* request_context,
+ const content::GlobalRenderFrameHostId& global_id,
+ bool is_main_frame,
+ bool is_guest_view) {
+ CEF_REQUIRE_UIT();
+ DCHECK(frame_util::IsValidGlobalId(global_id));
+
+ render_id_set_.insert(global_id);
+
+ CefRefPtr<CefRequestContextHandler> handler = request_context->GetHandler();
+ if (handler) {
+ handler_map_.AddHandler(global_id, handler);
+
+ CEF_POST_TASK(CEF_IOT, base::BindOnce(&CefIOThreadState::AddHandler,
+ iothread_state_, global_id, handler));
+ }
+}
+
+void CefBrowserContext::OnRenderFrameDeleted(
+ CefRequestContextImpl* request_context,
+ const content::GlobalRenderFrameHostId& global_id,
+ bool is_main_frame,
+ bool is_guest_view) {
+ CEF_REQUIRE_UIT();
+ DCHECK(frame_util::IsValidGlobalId(global_id));
+
+ auto it1 = render_id_set_.find(global_id);
+ if (it1 != render_id_set_.end()) {
+ render_id_set_.erase(it1);
+ }
+
+ CefRefPtr<CefRequestContextHandler> handler = request_context->GetHandler();
+ if (handler) {
+ handler_map_.RemoveHandler(global_id);
+
+ CEF_POST_TASK(CEF_IOT, base::BindOnce(&CefIOThreadState::RemoveHandler,
+ iothread_state_, global_id));
+ }
+}
+
+CefRefPtr<CefRequestContextHandler> CefBrowserContext::GetHandler(
+ const content::GlobalRenderFrameHostId& global_id,
+ bool require_frame_match) const {
+ CEF_REQUIRE_UIT();
+ return handler_map_.GetHandler(global_id, require_frame_match);
+}
+
+bool CefBrowserContext::IsAssociatedContext(
+ const content::GlobalRenderFrameHostId& global_id,
+ bool require_frame_match) const {
+ CEF_REQUIRE_UIT();
+
+ if (frame_util::IsValidGlobalId(global_id)) {
+ const auto it1 = render_id_set_.find(global_id);
+ if (it1 != render_id_set_.end()) {
+ return true;
+ }
+ }
+
+ if (frame_util::IsValidChildId(global_id.child_id) && !require_frame_match) {
+ // Choose an arbitrary handler for the same process.
+ for (const auto& render_ids : render_id_set_) {
+ if (render_ids.child_id == global_id.child_id) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+void CefBrowserContext::RegisterSchemeHandlerFactory(
+ const CefString& scheme_name,
+ const CefString& domain_name,
+ CefRefPtr<CefSchemeHandlerFactory> factory) {
+ CEF_POST_TASK(
+ CEF_IOT,
+ base::BindOnce(&CefIOThreadState::RegisterSchemeHandlerFactory,
+ iothread_state_, scheme_name, domain_name, factory));
+}
+
+void CefBrowserContext::ClearSchemeHandlerFactories() {
+ CEF_POST_TASK(CEF_IOT,
+ base::BindOnce(&CefIOThreadState::ClearSchemeHandlerFactories,
+ iothread_state_));
+}
+
+void CefBrowserContext::LoadExtension(
+ const CefString& root_directory,
+ CefRefPtr<CefDictionaryValue> manifest,
+ CefRefPtr<CefExtensionHandler> handler,
+ CefRefPtr<CefRequestContext> loader_context) {
+ NOTIMPLEMENTED();
+ if (handler) {
+ handler->OnExtensionLoadFailed(ERR_ABORTED);
+ }
+}
+
+bool CefBrowserContext::GetExtensions(std::vector<CefString>& extension_ids) {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+CefRefPtr<CefExtension> CefBrowserContext::GetExtension(
+ const CefString& extension_id) {
+ NOTIMPLEMENTED();
+ return nullptr;
+}
+
+bool CefBrowserContext::UnloadExtension(const CefString& extension_id) {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+bool CefBrowserContext::IsPrintPreviewSupported() const {
+ return true;
+}
+
+network::mojom::NetworkContext* CefBrowserContext::GetNetworkContext() {
+ CEF_REQUIRE_UIT();
+ auto browser_context = AsBrowserContext();
+ return browser_context->GetDefaultStoragePartition()->GetNetworkContext();
+}
+
+CefMediaRouterManager* CefBrowserContext::GetMediaRouterManager() {
+ CEF_REQUIRE_UIT();
+ if (!media_router_manager_) {
+ media_router_manager_.reset(new CefMediaRouterManager(AsBrowserContext()));
+ }
+ return media_router_manager_.get();
+}
+
+CefBrowserContext::CookieableSchemes CefBrowserContext::GetCookieableSchemes()
+ const {
+ CEF_REQUIRE_UIT();
+ return cookieable_schemes_;
+}
+
+// static
+CefBrowserContext::CookieableSchemes
+CefBrowserContext::GetGlobalCookieableSchemes() {
+ CEF_REQUIRE_UIT();
+
+ static base::NoDestructor<CookieableSchemes> schemes(
+ []() { return MakeSupportedSchemes(CefContext::Get()->settings()); }());
+ return *schemes;
+}
diff --git a/libcef/browser/browser_context.h b/libcef/browser/browser_context.h
new file mode 100644
index 00000000..8da79950
--- /dev/null
+++ b/libcef/browser/browser_context.h
@@ -0,0 +1,243 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_BROWSER_CONTEXT_IMPL_H_
+#define CEF_LIBCEF_BROWSER_BROWSER_CONTEXT_IMPL_H_
+#pragma once
+
+#include <set>
+#include <vector>
+
+#include "include/cef_request_context_handler.h"
+#include "libcef/browser/iothread_state.h"
+#include "libcef/browser/request_context_handler_map.h"
+
+#include "base/files/file_path.h"
+#include "base/functional/callback.h"
+#include "base/memory/weak_ptr.h"
+#include "base/task/sequenced_task_runner_helpers.h"
+#include "chrome/common/plugin.mojom.h"
+#include "services/network/public/mojom/network_context.mojom.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "url/origin.h"
+
+/*
+// Classes used in request processing (network, storage, service, etc.):
+//
+// WC = WebContents
+// Content API representation of a browser. Created by BHI or the system (for
+// popups) and owned by BHI. Keeps a pointer to the content::BrowserContext.
+//
+// BHI = AlloyBrowserHostImpl
+// Implements the CefBrowser and CefBrowserHost interfaces which are exposed
+// to clients. References an RCI instance. Owns a WC. Lifespan is controlled
+// by client references and CefBrowserInfoManager (until the browser has
+// closed).
+//
+// RCI = CefRequestContextImpl
+// Implements the CefRequestContext interface which is exposed to clients.
+// Creates or references a BC. Lifespan is controlled by client references and
+// BrowserMainParts (for the global RCI).
+//
+// BC = CefBrowserContext
+// Is/owns the content::BrowserContext which is the entry point from WC.
+// Owns the IOTS and creates the SPI indirectly. Potentially shared by
+// multiple RCI. Deletes itself when no longer needed by RCI.
+//
+// SPI = content::StoragePartitionImpl
+// Owns storage-related objects like Quota, IndexedDB, Cache, etc. Created by
+// StoragePartitionImplMap::Get(). Life span is controlled indirectly by BC.
+//
+// IOTS = CefIOThreadState
+// Stores state for access on the IO thread. Life span is controlled by BC.
+//
+//
+// Relationship diagram:
+// ref = reference (CefRefPtr/scoped_refptr)
+// own = ownership (std::unique_ptr)
+// ptr = raw pointer
+//
+// BHI -ref-> RCI -ptr-> BC -own-> SPI, IOTS
+// ^
+// BHI -own-> WC -ptr--/
+//
+//
+// How shutdown works:
+// 1. AlloyBrowserHostImpl::DestroyBrowser is called on the UI thread after the
+// browser is closed and deletes the WebContents.
+// 1. AlloyBrowserHostImpl is destroyed on any thread when the last reference
+// is released.
+// 2. CefRequestContextImpl is destroyed (possibly asynchronously) on the UI
+// thread when the last reference is released.
+// 3. CefBrowserContext is destroyed on the UI thread when no longer needed
+// by any CefRequestContextImpl (via RemoveCefRequestContext).
+// 4. CefIOThreadState is destroyed asynchronously on the IO thread after
+// the owning CefBrowserContext is destroyed.
+*/
+
+namespace content {
+class BrowserContext;
+struct GlobalRenderFrameHostId;
+} // namespace content
+
+class CefMediaRouterManager;
+class CefRequestContextImpl;
+class Profile;
+
+// Main entry point for configuring behavior on a per-RequestContext basis. The
+// content::BrowserContext represented by this class is passed to
+// WebContents::Create in AlloyBrowserHostImpl::CreateInternal. Only accessed on
+// the UI thread unless otherwise indicated.
+class CefBrowserContext {
+ public:
+ CefBrowserContext(const CefBrowserContext&) = delete;
+ CefBrowserContext& operator=(const CefBrowserContext&) = delete;
+
+ // Returns the existing instance, if any, associated with the specified
+ // |cache_path|.
+ static CefBrowserContext* FromCachePath(const base::FilePath& cache_path);
+
+ // Returns the existing instance, if any, associated with the specified IDs.
+ // See comments on IsAssociatedContext() for usage.
+ static CefBrowserContext* FromGlobalId(
+ const content::GlobalRenderFrameHostId& global_id,
+ bool require_frame_match);
+
+ // Returns the underlying CefBrowserContext if any.
+ static CefBrowserContext* FromBrowserContext(
+ const content::BrowserContext* context);
+ static CefBrowserContext* FromProfile(const Profile* profile);
+
+ // Returns all existing CefBrowserContext.
+ static std::vector<CefBrowserContext*> GetAll();
+
+ // Returns the content and chrome layer representations of the context.
+ virtual content::BrowserContext* AsBrowserContext() = 0;
+ virtual Profile* AsProfile() = 0;
+
+ // Returns true if the context is fully initialized.
+ virtual bool IsInitialized() const = 0;
+
+ // If the context is fully initialized execute |callback|, otherwise
+ // store it until the context is fully initialized.
+ virtual void StoreOrTriggerInitCallback(base::OnceClosure callback) = 0;
+
+ // Called from CefRequestContextImpl to track associated objects. This
+ // object will delete itself when the count reaches zero.
+ void AddCefRequestContext(CefRequestContextImpl* context);
+ virtual void RemoveCefRequestContext(CefRequestContextImpl* context);
+
+ // Called from CefRequestContextImpl::OnRenderFrameCreated.
+ void OnRenderFrameCreated(CefRequestContextImpl* request_context,
+ const content::GlobalRenderFrameHostId& global_id,
+ bool is_main_frame,
+ bool is_guest_view);
+
+ // Called from CefRequestContextImpl::OnRenderFrameDeleted.
+ void OnRenderFrameDeleted(CefRequestContextImpl* request_context,
+ const content::GlobalRenderFrameHostId& global_id,
+ bool is_main_frame,
+ bool is_guest_view);
+
+ // Returns the handler that matches the specified IDs. Pass -1 for unknown
+ // values. If |require_frame_match| is true only exact matches will be
+ // returned. If |require_frame_match| is false, and there is not an exact
+ // match, then the first handler for the same |render_process_id| will be
+ // returned.
+ CefRefPtr<CefRequestContextHandler> GetHandler(
+ const content::GlobalRenderFrameHostId& global_id,
+ bool require_frame_match) const;
+
+ // Returns true if this context is associated with the specified IDs. Pass -1
+ // for unknown values. If |require_frame_match| is true only exact matches
+ // will qualify. If |require_frame_match| is false, and there is not an exact
+ // match, then any match for |render_process_id| will qualify.
+ bool IsAssociatedContext(const content::GlobalRenderFrameHostId& global_id,
+ bool require_frame_match) const;
+
+ // Called from CefRequestContextImpl methods of the same name.
+ void RegisterSchemeHandlerFactory(const CefString& scheme_name,
+ const CefString& domain_name,
+ CefRefPtr<CefSchemeHandlerFactory> factory);
+ void ClearSchemeHandlerFactories();
+ // TODO(chrome-runtime): Make these extension methods pure virtual.
+ virtual void LoadExtension(const CefString& root_directory,
+ CefRefPtr<CefDictionaryValue> manifest,
+ CefRefPtr<CefExtensionHandler> handler,
+ CefRefPtr<CefRequestContext> loader_context);
+ virtual bool GetExtensions(std::vector<CefString>& extension_ids);
+ virtual CefRefPtr<CefExtension> GetExtension(const CefString& extension_id);
+
+ // Called from CefExtensionImpl::Unload().
+ virtual bool UnloadExtension(const CefString& extension_id);
+
+ // Returns true if this context supports print preview.
+ virtual bool IsPrintPreviewSupported() const;
+
+ network::mojom::NetworkContext* GetNetworkContext();
+
+ CefMediaRouterManager* GetMediaRouterManager();
+
+ using CookieableSchemes = absl::optional<std::vector<std::string>>;
+
+ // Returns the schemes associated with this context specifically, or the
+ // global configuration if unset.
+ CookieableSchemes GetCookieableSchemes() const;
+ static CookieableSchemes GetGlobalCookieableSchemes();
+
+ // These accessors are safe to call from any thread because the values don't
+ // change during this object's lifespan.
+ const CefRequestContextSettings& settings() const { return settings_; }
+ base::FilePath cache_path() const { return cache_path_; }
+ scoped_refptr<CefIOThreadState> iothread_state() const {
+ return iothread_state_;
+ }
+
+ // Used to hold a WeakPtr reference to this this object. The Getter returns
+ // nullptr if this object has already been destroyed.
+ using Getter = base::RepeatingCallback<CefBrowserContext*()>;
+ Getter getter() const { return getter_; }
+
+ protected:
+ explicit CefBrowserContext(const CefRequestContextSettings& settings);
+ virtual ~CefBrowserContext();
+
+ // Will be called immediately after this object is created.
+ virtual void Initialize();
+
+ // Will be called immediately before this object is deleted.
+ virtual void Shutdown();
+
+ // Members initialized during construction or Initialize() are safe to access
+ // from any thread.
+ const CefRequestContextSettings settings_;
+ base::FilePath cache_path_;
+
+ private:
+ // For DeleteSoon().
+ friend class base::DeleteHelper<CefBrowserContext>;
+
+ scoped_refptr<CefIOThreadState> iothread_state_;
+ CookieableSchemes cookieable_schemes_;
+ std::unique_ptr<CefMediaRouterManager> media_router_manager_;
+
+ // CefRequestContextImpl objects referencing this object.
+ std::set<CefRequestContextImpl*> request_context_set_;
+
+ // Map IDs to CefRequestContextHandler objects.
+ CefRequestContextHandlerMap handler_map_;
+
+ // Set of global IDs associated with this context.
+ using RenderIdSet = std::set<content::GlobalRenderFrameHostId>;
+ RenderIdSet render_id_set_;
+
+#if DCHECK_IS_ON()
+ bool is_shutdown_ = false;
+#endif
+
+ Getter getter_;
+ base::WeakPtrFactory<CefBrowserContext> weak_ptr_factory_;
+};
+
+#endif // CEF_LIBCEF_BROWSER_BROWSER_CONTEXT_IMPL_H_
diff --git a/libcef/browser/browser_context_keyed_service_factories.cc b/libcef/browser/browser_context_keyed_service_factories.cc
new file mode 100644
index 00000000..1c4e1400
--- /dev/null
+++ b/libcef/browser/browser_context_keyed_service_factories.cc
@@ -0,0 +1,45 @@
+// Copyright 2015 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#include "libcef/browser/browser_context_keyed_service_factories.h"
+#include "libcef/common/extensions/extensions_util.h"
+
+#include "base/feature_list.h"
+#include "chrome/browser/content_settings/cookie_settings_factory.h"
+#include "chrome/browser/media/router/chrome_media_router_factory.h"
+#include "chrome/browser/plugins/plugin_prefs_factory.h"
+#include "chrome/browser/profiles/renderer_updater_factory.h"
+#include "chrome/browser/reduce_accept_language/reduce_accept_language_factory.h"
+#include "chrome/browser/spellchecker/spellcheck_factory.h"
+#include "chrome/browser/themes/theme_service_factory.h"
+#include "chrome/browser/ui/prefs/prefs_tab_helper.h"
+#include "components/permissions/features.h"
+#include "extensions/browser/api/alarms/alarm_manager.h"
+#include "extensions/browser/api/storage/storage_frontend.h"
+#include "extensions/browser/renderer_startup_helper.h"
+#include "services/network/public/cpp/features.h"
+
+namespace cef {
+
+void EnsureBrowserContextKeyedServiceFactoriesBuilt() {
+ CookieSettingsFactory::GetInstance();
+ media_router::ChromeMediaRouterFactory::GetInstance();
+ PluginPrefsFactory::GetInstance();
+ PrefsTabHelper::GetServiceInstance();
+ RendererUpdaterFactory::GetInstance();
+ SpellcheckServiceFactory::GetInstance();
+ ThemeServiceFactory::GetInstance();
+
+ if (extensions::ExtensionsEnabled()) {
+ extensions::AlarmManager::GetFactoryInstance();
+ extensions::RendererStartupHelperFactory::GetInstance();
+ extensions::StorageFrontend::GetFactoryInstance();
+ }
+
+ if (base::FeatureList::IsEnabled(network::features::kReduceAcceptLanguage)) {
+ ReduceAcceptLanguageFactory::GetInstance();
+ }
+}
+
+} // namespace cef
diff --git a/libcef/browser/browser_context_keyed_service_factories.h b/libcef/browser/browser_context_keyed_service_factories.h
new file mode 100644
index 00000000..ba194922
--- /dev/null
+++ b/libcef/browser/browser_context_keyed_service_factories.h
@@ -0,0 +1,17 @@
+// Copyright 2015 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_BROWSER_CONTEXT_KEYED_SERVICE_FACTORIES_H_
+#define CEF_LIBCEF_BROWSER_BROWSER_CONTEXT_KEYED_SERVICE_FACTORIES_H_
+
+namespace cef {
+
+// Ensures the existence of any BrowserContextKeyedServiceFactory provided by
+// the CEF extensions code or otherwise required by CEF. See
+// libcef/common/extensions/api/README.txt for additional details.
+void EnsureBrowserContextKeyedServiceFactoriesBuilt();
+
+} // namespace cef
+
+#endif // CEF_LIBCEF_BROWSER_BROWSER_CONTEXT_KEYED_SERVICE_FACTORIES_H_
diff --git a/libcef/browser/browser_frame.cc b/libcef/browser/browser_frame.cc
new file mode 100644
index 00000000..91897f65
--- /dev/null
+++ b/libcef/browser/browser_frame.cc
@@ -0,0 +1,82 @@
+// Copyright 2021 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/browser_frame.h"
+
+#include "libcef/browser/browser_host_base.h"
+#include "libcef/browser/thread_util.h"
+
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "mojo/public/cpp/bindings/self_owned_receiver.h"
+
+CefBrowserFrame::CefBrowserFrame(
+ content::RenderFrameHost* render_frame_host,
+ mojo::PendingReceiver<cef::mojom::BrowserFrame> receiver)
+ : FrameServiceBase(render_frame_host, std::move(receiver)) {}
+
+CefBrowserFrame::~CefBrowserFrame() = default;
+
+// static
+void CefBrowserFrame::RegisterBrowserInterfaceBindersForFrame(
+ content::RenderFrameHost* render_frame_host,
+ mojo::BinderMapWithContext<content::RenderFrameHost*>* map) {
+ map->Add<cef::mojom::BrowserFrame>(base::BindRepeating(
+ [](content::RenderFrameHost* frame_host,
+ mojo::PendingReceiver<cef::mojom::BrowserFrame> receiver) {
+ // This object is bound to the lifetime of |frame_host| and the mojo
+ // connection. See DocumentServiceBase for details.
+ new CefBrowserFrame(frame_host, std::move(receiver));
+ }));
+}
+
+void CefBrowserFrame::SendMessage(const std::string& name,
+ base::Value::List arguments) {
+ // Always send to the newly created RFH, which may be speculative when
+ // navigating cross-origin.
+ if (auto host = GetFrameHost(/*prefer_speculative=*/true)) {
+ host->SendMessage(name, std::move(arguments));
+ }
+}
+
+void CefBrowserFrame::SendSharedMemoryRegion(
+ const std::string& name,
+ base::ReadOnlySharedMemoryRegion region) {
+ // Always send to the newly created RFH, which may be speculative when
+ // navigating cross-origin.
+ if (auto host = GetFrameHost(/*prefer_speculative=*/true)) {
+ host->SendSharedMemoryRegion(name, std::move(region));
+ }
+}
+
+void CefBrowserFrame::FrameAttached(
+ mojo::PendingRemote<cef::mojom::RenderFrame> render_frame,
+ bool reattached) {
+ // Always send to the newly created RFH, which may be speculative when
+ // navigating cross-origin.
+ if (auto host = GetFrameHost(/*prefer_speculative=*/true)) {
+ host->FrameAttached(std::move(render_frame), reattached);
+ }
+}
+
+void CefBrowserFrame::UpdateDraggableRegions(
+ absl::optional<std::vector<cef::mojom::DraggableRegionEntryPtr>> regions) {
+ if (auto host = GetFrameHost()) {
+ host->UpdateDraggableRegions(std::move(regions));
+ }
+}
+
+CefRefPtr<CefFrameHostImpl> CefBrowserFrame::GetFrameHost(
+ bool prefer_speculative) const {
+ CEF_REQUIRE_UIT();
+ auto rfh = render_frame_host();
+ if (auto browser = CefBrowserHostBase::GetBrowserForHost(rfh)) {
+ return browser->browser_info()->GetFrameForHost(rfh, nullptr,
+ prefer_speculative);
+ }
+ NOTREACHED();
+ return nullptr;
+}
diff --git a/libcef/browser/browser_frame.h b/libcef/browser/browser_frame.h
new file mode 100644
index 00000000..41576a09
--- /dev/null
+++ b/libcef/browser/browser_frame.h
@@ -0,0 +1,55 @@
+// Copyright 2021 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_BROWSER_FRAME_H_
+#define CEF_LIBCEF_BROWSER_BROWSER_FRAME_H_
+#pragma once
+
+#include "libcef/browser/frame_host_impl.h"
+#include "libcef/browser/frame_service_base.h"
+
+#include "cef/libcef/common/mojom/cef.mojom.h"
+#include "mojo/public/cpp/bindings/binder_map.h"
+
+// Implementation of the BrowserFrame mojo interface.
+// This is implemented separately from CefFrameHostImpl to better manage the
+// association with the RenderFrameHost (which may be speculative, etc.), and so
+// that messages are always routed to the most appropriate CefFrameHostImpl
+// instance. Lifespan is tied to the RFH via FrameServiceBase.
+class CefBrowserFrame
+ : public content::FrameServiceBase<cef::mojom::BrowserFrame> {
+ public:
+ CefBrowserFrame(content::RenderFrameHost* render_frame_host,
+ mojo::PendingReceiver<cef::mojom::BrowserFrame> receiver);
+
+ CefBrowserFrame(const CefBrowserFrame&) = delete;
+ CefBrowserFrame& operator=(const CefBrowserFrame&) = delete;
+
+ ~CefBrowserFrame() override;
+
+ // Called from the ContentBrowserClient method of the same name.
+ static void RegisterBrowserInterfaceBindersForFrame(
+ content::RenderFrameHost* render_frame_host,
+ mojo::BinderMapWithContext<content::RenderFrameHost*>* map);
+
+ private:
+ // cef::mojom::BrowserFrame methods:
+ void SendMessage(const std::string& name,
+ base::Value::List arguments) override;
+ void SendSharedMemoryRegion(const std::string& name,
+ base::ReadOnlySharedMemoryRegion region) override;
+ void FrameAttached(mojo::PendingRemote<cef::mojom::RenderFrame> render_frame,
+ bool reattached) override;
+ void UpdateDraggableRegions(
+ absl::optional<std::vector<cef::mojom::DraggableRegionEntryPtr>> regions)
+ override;
+
+ // FrameServiceBase methods:
+ bool ShouldCloseOnFinishNavigation() const override { return false; }
+
+ CefRefPtr<CefFrameHostImpl> GetFrameHost(
+ bool prefer_speculative = false) const;
+};
+
+#endif // CEF_LIBCEF_BROWSER_BROWSER_FRAME_H_
diff --git a/libcef/browser/browser_host_base.cc b/libcef/browser/browser_host_base.cc
new file mode 100644
index 00000000..990be972
--- /dev/null
+++ b/libcef/browser/browser_host_base.cc
@@ -0,0 +1,1137 @@
+// Copyright 2020 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/browser_host_base.h"
+
+#include <tuple>
+
+#include "libcef/browser/browser_info_manager.h"
+#include "libcef/browser/browser_platform_delegate.h"
+#include "libcef/browser/context.h"
+#include "libcef/browser/image_impl.h"
+#include "libcef/browser/navigation_entry_impl.h"
+#include "libcef/browser/printing/print_util.h"
+#include "libcef/browser/thread_util.h"
+#include "libcef/common/frame_util.h"
+#include "libcef/common/net/url_util.h"
+
+#include "base/logging.h"
+#include "chrome/browser/platform_util.h"
+#include "chrome/browser/spellchecker/spellcheck_factory.h"
+#include "chrome/browser/spellchecker/spellcheck_service.h"
+#include "components/favicon/core/favicon_url.h"
+#include "components/spellcheck/common/spellcheck_features.h"
+#include "content/browser/renderer_host/render_frame_host_impl.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/download_manager.h"
+#include "content/public/browser/download_request_utils.h"
+#include "content/public/browser/file_select_listener.h"
+#include "content/public/browser/navigation_entry.h"
+#include "ui/gfx/image/image_skia.h"
+#include "ui/shell_dialogs/select_file_policy.h"
+
+#if BUILDFLAG(IS_MAC)
+#include "components/spellcheck/browser/spellcheck_platform.h"
+#endif
+
+namespace {
+
+// Associates a CefBrowserHostBase instance with a WebContents. This object will
+// be deleted automatically when the WebContents is destroyed.
+class WebContentsUserDataAdapter : public base::SupportsUserData::Data {
+ public:
+ static void Register(CefRefPtr<CefBrowserHostBase> browser) {
+ new WebContentsUserDataAdapter(browser);
+ }
+
+ static CefRefPtr<CefBrowserHostBase> Get(
+ const content::WebContents* web_contents) {
+ WebContentsUserDataAdapter* adapter =
+ static_cast<WebContentsUserDataAdapter*>(
+ web_contents->GetUserData(UserDataKey()));
+ if (adapter) {
+ return adapter->browser_;
+ }
+ return nullptr;
+ }
+
+ private:
+ WebContentsUserDataAdapter(CefRefPtr<CefBrowserHostBase> browser)
+ : browser_(browser) {
+ auto web_contents = browser->GetWebContents();
+ DCHECK(web_contents);
+ web_contents->SetUserData(UserDataKey(), base::WrapUnique(this));
+ }
+
+ static void* UserDataKey() {
+ // We just need a unique constant. Use the address of a static that
+ // COMDAT folding won't touch in an optimizing linker.
+ static int data_key = 0;
+ return reinterpret_cast<void*>(&data_key);
+ }
+
+ CefRefPtr<CefBrowserHostBase> browser_;
+};
+
+} // namespace
+
+// static
+CefRefPtr<CefBrowserHostBase> CefBrowserHostBase::GetBrowserForHost(
+ const content::RenderViewHost* host) {
+ DCHECK(host);
+ CEF_REQUIRE_UIT();
+ content::WebContents* web_contents = content::WebContents::FromRenderViewHost(
+ const_cast<content::RenderViewHost*>(host));
+ if (web_contents) {
+ return GetBrowserForContents(web_contents);
+ }
+ return nullptr;
+}
+
+// static
+CefRefPtr<CefBrowserHostBase> CefBrowserHostBase::GetBrowserForHost(
+ const content::RenderFrameHost* host) {
+ DCHECK(host);
+ CEF_REQUIRE_UIT();
+ content::WebContents* web_contents =
+ content::WebContents::FromRenderFrameHost(
+ const_cast<content::RenderFrameHost*>(host));
+ if (web_contents) {
+ return GetBrowserForContents(web_contents);
+ }
+ return nullptr;
+}
+
+// static
+CefRefPtr<CefBrowserHostBase> CefBrowserHostBase::GetBrowserForContents(
+ const content::WebContents* contents) {
+ DCHECK(contents);
+ CEF_REQUIRE_UIT();
+ return WebContentsUserDataAdapter::Get(contents);
+}
+
+// static
+CefRefPtr<CefBrowserHostBase> CefBrowserHostBase::GetBrowserForGlobalId(
+ const content::GlobalRenderFrameHostId& global_id) {
+ if (!frame_util::IsValidGlobalId(global_id)) {
+ return nullptr;
+ }
+
+ if (CEF_CURRENTLY_ON_UIT()) {
+ // Use the non-thread-safe but potentially faster approach.
+ content::RenderFrameHost* render_frame_host =
+ content::RenderFrameHost::FromID(global_id);
+ if (!render_frame_host) {
+ return nullptr;
+ }
+ return GetBrowserForHost(render_frame_host);
+ } else {
+ // Use the thread-safe approach.
+ bool is_guest_view = false;
+ auto info = CefBrowserInfoManager::GetInstance()->GetBrowserInfo(
+ global_id, &is_guest_view);
+ if (info && !is_guest_view) {
+ auto browser = info->browser();
+ if (!browser) {
+ LOG(WARNING) << "Found browser id " << info->browser_id()
+ << " but no browser object matching frame "
+ << frame_util::GetFrameDebugString(global_id);
+ }
+ return browser;
+ }
+ return nullptr;
+ }
+}
+
+// static
+CefRefPtr<CefBrowserHostBase>
+CefBrowserHostBase::GetBrowserForTopLevelNativeWindow(
+ gfx::NativeWindow owning_window) {
+ DCHECK(owning_window);
+ CEF_REQUIRE_UIT();
+
+ for (const auto& browser_info :
+ CefBrowserInfoManager::GetInstance()->GetBrowserInfoList()) {
+ if (auto browser = browser_info->browser()) {
+ if (browser->GetTopLevelNativeWindow() == owning_window) {
+ return browser;
+ }
+ }
+ }
+
+ return nullptr;
+}
+
+// static
+CefRefPtr<CefBrowserHostBase> CefBrowserHostBase::GetLikelyFocusedBrowser() {
+ CEF_REQUIRE_UIT();
+
+ for (const auto& browser_info :
+ CefBrowserInfoManager::GetInstance()->GetBrowserInfoList()) {
+ if (auto browser = browser_info->browser()) {
+ if (browser->IsFocused()) {
+ return browser;
+ }
+ }
+ }
+
+ return nullptr;
+}
+
+CefBrowserHostBase::CefBrowserHostBase(
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefClient> client,
+ std::unique_ptr<CefBrowserPlatformDelegate> platform_delegate,
+ scoped_refptr<CefBrowserInfo> browser_info,
+ CefRefPtr<CefRequestContextImpl> request_context)
+ : settings_(settings),
+ client_(client),
+ platform_delegate_(std::move(platform_delegate)),
+ browser_info_(browser_info),
+ request_context_(request_context),
+ is_views_hosted_(platform_delegate_->IsViewsHosted()) {
+ CEF_REQUIRE_UIT();
+ DCHECK(!browser_info_->browser().get());
+ browser_info_->SetBrowser(this);
+
+ contents_delegate_ =
+ std::make_unique<CefBrowserContentsDelegate>(browser_info_);
+ contents_delegate_->AddObserver(this);
+}
+
+void CefBrowserHostBase::InitializeBrowser() {
+ CEF_REQUIRE_UIT();
+
+ // Associate the WebContents with this browser object.
+ DCHECK(GetWebContents());
+ WebContentsUserDataAdapter::Register(this);
+}
+
+void CefBrowserHostBase::DestroyBrowser() {
+ CEF_REQUIRE_UIT();
+
+ devtools_manager_.reset();
+ media_stream_registrar_.reset();
+
+ platform_delegate_.reset();
+
+ contents_delegate_->RemoveObserver(this);
+ contents_delegate_->ObserveWebContents(nullptr);
+
+ CefBrowserInfoManager::GetInstance()->RemoveBrowserInfo(browser_info_);
+ browser_info_->SetBrowser(nullptr);
+}
+
+CefRefPtr<CefBrowser> CefBrowserHostBase::GetBrowser() {
+ return this;
+}
+
+CefRefPtr<CefClient> CefBrowserHostBase::GetClient() {
+ return client_;
+}
+
+CefRefPtr<CefRequestContext> CefBrowserHostBase::GetRequestContext() {
+ return request_context_;
+}
+
+bool CefBrowserHostBase::HasView() {
+ return is_views_hosted_;
+}
+
+void CefBrowserHostBase::SetFocus(bool focus) {
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(CEF_UIT,
+ base::BindOnce(&CefBrowserHostBase::SetFocus, this, focus));
+ return;
+ }
+
+ if (focus) {
+ OnSetFocus(FOCUS_SOURCE_SYSTEM);
+ } else if (platform_delegate_) {
+ platform_delegate_->SetFocus(false);
+ }
+}
+
+void CefBrowserHostBase::RunFileDialog(
+ FileDialogMode mode,
+ const CefString& title,
+ const CefString& default_file_path,
+ const std::vector<CefString>& accept_filters,
+ CefRefPtr<CefRunFileDialogCallback> callback) {
+ DCHECK(callback);
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(CEF_UIT, base::BindOnce(&CefBrowserHostBase::RunFileDialog,
+ this, mode, title, default_file_path,
+ accept_filters, callback));
+ return;
+ }
+
+ if (!callback || !EnsureFileDialogManager()) {
+ LOG(ERROR) << "File dialog canceled due to invalid state.";
+ if (callback) {
+ callback->OnFileDialogDismissed({});
+ }
+ return;
+ }
+
+ file_dialog_manager_->RunFileDialog(mode, title, default_file_path,
+ accept_filters, callback);
+}
+
+void CefBrowserHostBase::StartDownload(const CefString& url) {
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(
+ CEF_UIT, base::BindOnce(&CefBrowserHostBase::StartDownload, this, url));
+ return;
+ }
+
+ GURL gurl = GURL(url.ToString());
+ if (gurl.is_empty() || !gurl.is_valid()) {
+ return;
+ }
+
+ auto web_contents = GetWebContents();
+ if (!web_contents) {
+ return;
+ }
+
+ auto browser_context = web_contents->GetBrowserContext();
+ if (!browser_context) {
+ return;
+ }
+
+ content::DownloadManager* manager = browser_context->GetDownloadManager();
+ if (!manager) {
+ return;
+ }
+
+ std::unique_ptr<download::DownloadUrlParameters> params(
+ content::DownloadRequestUtils::CreateDownloadForWebContentsMainFrame(
+ web_contents, gurl, MISSING_TRAFFIC_ANNOTATION));
+ manager->DownloadUrl(std::move(params));
+}
+
+void CefBrowserHostBase::DownloadImage(
+ const CefString& image_url,
+ bool is_favicon,
+ uint32 max_image_size,
+ bool bypass_cache,
+ CefRefPtr<CefDownloadImageCallback> callback) {
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(
+ CEF_UIT,
+ base::BindOnce(&CefBrowserHostBase::DownloadImage, this, image_url,
+ is_favicon, max_image_size, bypass_cache, callback));
+ return;
+ }
+
+ if (!callback) {
+ return;
+ }
+
+ GURL gurl = GURL(image_url.ToString());
+ if (gurl.is_empty() || !gurl.is_valid()) {
+ return;
+ }
+
+ auto web_contents = GetWebContents();
+ if (!web_contents) {
+ return;
+ }
+
+ web_contents->DownloadImage(
+ gurl, is_favicon, gfx::Size(max_image_size, max_image_size),
+ max_image_size * gfx::ImageSkia::GetMaxSupportedScale(), bypass_cache,
+ base::BindOnce(
+ [](uint32 max_image_size,
+ CefRefPtr<CefDownloadImageCallback> callback, int id,
+ int http_status_code, const GURL& image_url,
+ const std::vector<SkBitmap>& bitmaps,
+ const std::vector<gfx::Size>& sizes) {
+ CEF_REQUIRE_UIT();
+
+ CefRefPtr<CefImageImpl> image_impl;
+
+ if (!bitmaps.empty()) {
+ image_impl = new CefImageImpl();
+ image_impl->AddBitmaps(max_image_size, bitmaps);
+ }
+
+ callback->OnDownloadImageFinished(
+ image_url.spec(), http_status_code, image_impl.get());
+ },
+ max_image_size, callback));
+}
+
+void CefBrowserHostBase::Print() {
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(CEF_UIT, base::BindOnce(&CefBrowserHostBase::Print, this));
+ return;
+ }
+
+ auto web_contents = GetWebContents();
+ if (!web_contents) {
+ return;
+ }
+
+ const bool print_preview_disabled =
+ !platform_delegate_ || !platform_delegate_->IsPrintPreviewSupported();
+ print_util::Print(web_contents, print_preview_disabled);
+}
+
+void CefBrowserHostBase::PrintToPDF(const CefString& path,
+ const CefPdfPrintSettings& settings,
+ CefRefPtr<CefPdfPrintCallback> callback) {
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(CEF_UIT, base::BindOnce(&CefBrowserHostBase::PrintToPDF, this,
+ path, settings, callback));
+ return;
+ }
+
+ auto web_contents = GetWebContents();
+ if (!web_contents) {
+ return;
+ }
+
+ print_util::PrintToPDF(web_contents, path, settings, callback);
+}
+
+bool CefBrowserHostBase::SendDevToolsMessage(const void* message,
+ size_t message_size) {
+ if (!message || message_size == 0) {
+ return false;
+ }
+
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ std::string message_str(static_cast<const char*>(message), message_size);
+ CEF_POST_TASK(
+ CEF_UIT,
+ base::BindOnce(
+ [](CefRefPtr<CefBrowserHostBase> self, std::string message_str) {
+ self->SendDevToolsMessage(message_str.data(), message_str.size());
+ },
+ CefRefPtr<CefBrowserHostBase>(this), std::move(message_str)));
+ return false;
+ }
+
+ if (!EnsureDevToolsManager()) {
+ return false;
+ }
+ return devtools_manager_->SendDevToolsMessage(message, message_size);
+}
+
+int CefBrowserHostBase::ExecuteDevToolsMethod(
+ int message_id,
+ const CefString& method,
+ CefRefPtr<CefDictionaryValue> params) {
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(
+ CEF_UIT, base::BindOnce(base::IgnoreResult(
+ &CefBrowserHostBase::ExecuteDevToolsMethod),
+ this, message_id, method, params));
+ return 0;
+ }
+
+ if (!EnsureDevToolsManager()) {
+ return 0;
+ }
+ return devtools_manager_->ExecuteDevToolsMethod(message_id, method, params);
+}
+
+CefRefPtr<CefRegistration> CefBrowserHostBase::AddDevToolsMessageObserver(
+ CefRefPtr<CefDevToolsMessageObserver> observer) {
+ if (!observer) {
+ return nullptr;
+ }
+ auto registration = CefDevToolsManager::CreateRegistration(observer);
+ InitializeDevToolsRegistrationOnUIThread(registration);
+ return registration.get();
+}
+
+void CefBrowserHostBase::GetNavigationEntries(
+ CefRefPtr<CefNavigationEntryVisitor> visitor,
+ bool current_only) {
+ DCHECK(visitor.get());
+ if (!visitor.get()) {
+ return;
+ }
+
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(
+ CEF_UIT, base::BindOnce(&CefBrowserHostBase::GetNavigationEntries, this,
+ visitor, current_only));
+ return;
+ }
+
+ auto web_contents = GetWebContents();
+ if (!web_contents) {
+ return;
+ }
+
+ content::NavigationController& controller = web_contents->GetController();
+ const int total = controller.GetEntryCount();
+ const int current = controller.GetCurrentEntryIndex();
+
+ if (current_only) {
+ // Visit only the current entry.
+ CefRefPtr<CefNavigationEntryImpl> entry =
+ new CefNavigationEntryImpl(controller.GetEntryAtIndex(current));
+ visitor->Visit(entry.get(), true, current, total);
+ std::ignore = entry->Detach(nullptr);
+ } else {
+ // Visit all entries.
+ bool cont = true;
+ for (int i = 0; i < total && cont; ++i) {
+ CefRefPtr<CefNavigationEntryImpl> entry =
+ new CefNavigationEntryImpl(controller.GetEntryAtIndex(i));
+ cont = visitor->Visit(entry.get(), (i == current), i, total);
+ std::ignore = entry->Detach(nullptr);
+ }
+ }
+}
+
+CefRefPtr<CefNavigationEntry> CefBrowserHostBase::GetVisibleNavigationEntry() {
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ NOTREACHED() << "called on invalid thread";
+ return nullptr;
+ }
+
+ content::NavigationEntry* entry = nullptr;
+ auto web_contents = GetWebContents();
+ if (web_contents) {
+ entry = web_contents->GetController().GetVisibleEntry();
+ }
+
+ if (!entry) {
+ return nullptr;
+ }
+
+ return new CefNavigationEntryImpl(entry);
+}
+
+void CefBrowserHostBase::NotifyMoveOrResizeStarted() {
+#if BUILDFLAG(IS_WIN) || (BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC))
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(
+ CEF_UIT,
+ base::BindOnce(&CefBrowserHostBase::NotifyMoveOrResizeStarted, this));
+ return;
+ }
+
+ if (platform_delegate_) {
+ platform_delegate_->NotifyMoveOrResizeStarted();
+ }
+#endif
+}
+
+void CefBrowserHostBase::ReplaceMisspelling(const CefString& word) {
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(
+ CEF_UIT,
+ base::BindOnce(&CefBrowserHostBase::ReplaceMisspelling, this, word));
+ return;
+ }
+
+ auto web_contents = GetWebContents();
+ if (web_contents) {
+ web_contents->ReplaceMisspelling(word);
+ }
+}
+
+void CefBrowserHostBase::AddWordToDictionary(const CefString& word) {
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(
+ CEF_UIT,
+ base::BindOnce(&CefBrowserHostBase::AddWordToDictionary, this, word));
+ return;
+ }
+
+ auto web_contents = GetWebContents();
+ if (!web_contents) {
+ return;
+ }
+
+ SpellcheckService* spellcheck = nullptr;
+ content::BrowserContext* browser_context = web_contents->GetBrowserContext();
+ if (browser_context) {
+ spellcheck = SpellcheckServiceFactory::GetForContext(browser_context);
+ if (spellcheck) {
+ spellcheck->GetCustomDictionary()->AddWord(word);
+ }
+ }
+#if BUILDFLAG(IS_MAC)
+ if (spellcheck && spellcheck::UseBrowserSpellChecker()) {
+ spellcheck_platform::AddWord(spellcheck->platform_spell_checker(), word);
+ }
+#endif
+}
+
+void CefBrowserHostBase::SendKeyEvent(const CefKeyEvent& event) {
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(CEF_UIT, base::BindOnce(&CefBrowserHostBase::SendKeyEvent,
+ this, event));
+ return;
+ }
+
+ if (platform_delegate_) {
+ platform_delegate_->SendKeyEvent(event);
+ }
+}
+
+void CefBrowserHostBase::SendMouseClickEvent(const CefMouseEvent& event,
+ MouseButtonType type,
+ bool mouseUp,
+ int clickCount) {
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(CEF_UIT,
+ base::BindOnce(&CefBrowserHostBase::SendMouseClickEvent, this,
+ event, type, mouseUp, clickCount));
+ return;
+ }
+
+ if (platform_delegate_) {
+ platform_delegate_->SendMouseClickEvent(event, type, mouseUp, clickCount);
+ }
+}
+
+void CefBrowserHostBase::SendMouseMoveEvent(const CefMouseEvent& event,
+ bool mouseLeave) {
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(CEF_UIT,
+ base::BindOnce(&CefBrowserHostBase::SendMouseMoveEvent, this,
+ event, mouseLeave));
+ return;
+ }
+
+ if (platform_delegate_) {
+ platform_delegate_->SendMouseMoveEvent(event, mouseLeave);
+ }
+}
+
+void CefBrowserHostBase::SendMouseWheelEvent(const CefMouseEvent& event,
+ int deltaX,
+ int deltaY) {
+ if (deltaX == 0 && deltaY == 0) {
+ // Nothing to do.
+ return;
+ }
+
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(CEF_UIT,
+ base::BindOnce(&CefBrowserHostBase::SendMouseWheelEvent, this,
+ event, deltaX, deltaY));
+ return;
+ }
+
+ if (platform_delegate_) {
+ platform_delegate_->SendMouseWheelEvent(event, deltaX, deltaY);
+ }
+}
+
+bool CefBrowserHostBase::IsValid() {
+ return browser_info_->browser() == this;
+}
+
+CefRefPtr<CefBrowserHost> CefBrowserHostBase::GetHost() {
+ return this;
+}
+
+bool CefBrowserHostBase::CanGoBack() {
+ base::AutoLock lock_scope(state_lock_);
+ return can_go_back_;
+}
+
+void CefBrowserHostBase::GoBack() {
+ auto callback = base::BindOnce(&CefBrowserHostBase::GoBack, this);
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(CEF_UIT, std::move(callback));
+ return;
+ }
+
+ if (browser_info_->IsNavigationLocked(std::move(callback))) {
+ return;
+ }
+
+ auto wc = GetWebContents();
+ if (wc && wc->GetController().CanGoBack()) {
+ wc->GetController().GoBack();
+ }
+}
+
+bool CefBrowserHostBase::CanGoForward() {
+ base::AutoLock lock_scope(state_lock_);
+ return can_go_forward_;
+}
+
+void CefBrowserHostBase::GoForward() {
+ auto callback = base::BindOnce(&CefBrowserHostBase::GoForward, this);
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(CEF_UIT, std::move(callback));
+ return;
+ }
+
+ if (browser_info_->IsNavigationLocked(std::move(callback))) {
+ return;
+ }
+
+ auto wc = GetWebContents();
+ if (wc && wc->GetController().CanGoForward()) {
+ wc->GetController().GoForward();
+ }
+}
+
+bool CefBrowserHostBase::IsLoading() {
+ base::AutoLock lock_scope(state_lock_);
+ return is_loading_;
+}
+
+void CefBrowserHostBase::Reload() {
+ auto callback = base::BindOnce(&CefBrowserHostBase::Reload, this);
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(CEF_UIT, std::move(callback));
+ return;
+ }
+
+ if (browser_info_->IsNavigationLocked(std::move(callback))) {
+ return;
+ }
+
+ auto wc = GetWebContents();
+ if (wc) {
+ wc->GetController().Reload(content::ReloadType::NORMAL, true);
+ }
+}
+
+void CefBrowserHostBase::ReloadIgnoreCache() {
+ auto callback = base::BindOnce(&CefBrowserHostBase::ReloadIgnoreCache, this);
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(CEF_UIT, std::move(callback));
+ return;
+ }
+
+ if (browser_info_->IsNavigationLocked(std::move(callback))) {
+ return;
+ }
+
+ auto wc = GetWebContents();
+ if (wc) {
+ wc->GetController().Reload(content::ReloadType::BYPASSING_CACHE, true);
+ }
+}
+
+void CefBrowserHostBase::StopLoad() {
+ auto callback = base::BindOnce(&CefBrowserHostBase::StopLoad, this);
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(CEF_UIT, std::move(callback));
+ return;
+ }
+
+ if (browser_info_->IsNavigationLocked(std::move(callback))) {
+ return;
+ }
+
+ auto wc = GetWebContents();
+ if (wc) {
+ wc->Stop();
+ }
+}
+
+int CefBrowserHostBase::GetIdentifier() {
+ return browser_id();
+}
+
+bool CefBrowserHostBase::IsSame(CefRefPtr<CefBrowser> that) {
+ auto impl = static_cast<CefBrowserHostBase*>(that.get());
+ return (impl == this);
+}
+
+bool CefBrowserHostBase::HasDocument() {
+ base::AutoLock lock_scope(state_lock_);
+ return has_document_;
+}
+
+bool CefBrowserHostBase::IsPopup() {
+ return browser_info_->is_popup();
+}
+
+CefRefPtr<CefFrame> CefBrowserHostBase::GetMainFrame() {
+ return GetFrame(CefFrameHostImpl::kMainFrameId);
+}
+
+CefRefPtr<CefFrame> CefBrowserHostBase::GetFocusedFrame() {
+ return GetFrame(CefFrameHostImpl::kFocusedFrameId);
+}
+
+CefRefPtr<CefFrame> CefBrowserHostBase::GetFrame(int64 identifier) {
+ if (identifier == CefFrameHostImpl::kInvalidFrameId) {
+ return nullptr;
+ } else if (identifier == CefFrameHostImpl::kMainFrameId) {
+ return browser_info_->GetMainFrame();
+ } else if (identifier == CefFrameHostImpl::kFocusedFrameId) {
+ base::AutoLock lock_scope(state_lock_);
+ if (!focused_frame_) {
+ // The main frame is focused by default.
+ return browser_info_->GetMainFrame();
+ }
+ return focused_frame_;
+ }
+
+ return browser_info_->GetFrameForGlobalId(
+ frame_util::MakeGlobalId(identifier));
+}
+
+CefRefPtr<CefFrame> CefBrowserHostBase::GetFrame(const CefString& name) {
+ for (const auto& frame : browser_info_->GetAllFrames()) {
+ if (frame->GetName() == name) {
+ return frame;
+ }
+ }
+ return nullptr;
+}
+
+size_t CefBrowserHostBase::GetFrameCount() {
+ return browser_info_->GetAllFrames().size();
+}
+
+void CefBrowserHostBase::GetFrameIdentifiers(std::vector<int64>& identifiers) {
+ if (identifiers.size() > 0) {
+ identifiers.clear();
+ }
+
+ const auto frames = browser_info_->GetAllFrames();
+ if (frames.empty()) {
+ return;
+ }
+
+ identifiers.reserve(frames.size());
+ for (const auto& frame : frames) {
+ identifiers.push_back(frame->GetIdentifier());
+ }
+}
+
+void CefBrowserHostBase::GetFrameNames(std::vector<CefString>& names) {
+ if (names.size() > 0) {
+ names.clear();
+ }
+
+ const auto frames = browser_info_->GetAllFrames();
+ if (frames.empty()) {
+ return;
+ }
+
+ names.reserve(frames.size());
+ for (const auto& frame : frames) {
+ names.push_back(frame->GetName());
+ }
+}
+
+void CefBrowserHostBase::OnStateChanged(CefBrowserContentsState state_changed) {
+ // Make sure that CefBrowser state is consistent before the associated
+ // CefClient callback is executed.
+ base::AutoLock lock_scope(state_lock_);
+ if ((state_changed & CefBrowserContentsState::kNavigation) ==
+ CefBrowserContentsState::kNavigation) {
+ is_loading_ = contents_delegate_->is_loading();
+ can_go_back_ = contents_delegate_->can_go_back();
+ can_go_forward_ = contents_delegate_->can_go_forward();
+ }
+ if ((state_changed & CefBrowserContentsState::kDocument) ==
+ CefBrowserContentsState::kDocument) {
+ has_document_ = contents_delegate_->has_document();
+ }
+ if ((state_changed & CefBrowserContentsState::kFullscreen) ==
+ CefBrowserContentsState::kFullscreen) {
+ is_fullscreen_ = contents_delegate_->is_fullscreen();
+ }
+ if ((state_changed & CefBrowserContentsState::kFocusedFrame) ==
+ CefBrowserContentsState::kFocusedFrame) {
+ focused_frame_ = contents_delegate_->focused_frame();
+ }
+}
+
+void CefBrowserHostBase::OnWebContentsDestroyed(
+ content::WebContents* web_contents) {}
+
+CefRefPtr<CefFrame> CefBrowserHostBase::GetFrameForHost(
+ const content::RenderFrameHost* host) {
+ CEF_REQUIRE_UIT();
+ if (!host) {
+ return nullptr;
+ }
+
+ return browser_info_->GetFrameForHost(host);
+}
+
+CefRefPtr<CefFrame> CefBrowserHostBase::GetFrameForGlobalId(
+ const content::GlobalRenderFrameHostId& global_id) {
+ return browser_info_->GetFrameForGlobalId(global_id, nullptr);
+}
+
+void CefBrowserHostBase::AddObserver(Observer* observer) {
+ CEF_REQUIRE_UIT();
+ observers_.AddObserver(observer);
+}
+
+void CefBrowserHostBase::RemoveObserver(Observer* observer) {
+ CEF_REQUIRE_UIT();
+ observers_.RemoveObserver(observer);
+}
+
+bool CefBrowserHostBase::HasObserver(Observer* observer) const {
+ CEF_REQUIRE_UIT();
+ return observers_.HasObserver(observer);
+}
+
+void CefBrowserHostBase::LoadMainFrameURL(
+ const content::OpenURLParams& params) {
+ auto callback =
+ base::BindOnce(&CefBrowserHostBase::LoadMainFrameURL, this, params);
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(CEF_UIT, std::move(callback));
+ return;
+ }
+
+ if (browser_info_->IsNavigationLocked(std::move(callback))) {
+ return;
+ }
+
+ if (Navigate(params)) {
+ OnSetFocus(FOCUS_SOURCE_NAVIGATION);
+ }
+}
+
+bool CefBrowserHostBase::Navigate(const content::OpenURLParams& params) {
+ CEF_REQUIRE_UIT();
+ auto web_contents = GetWebContents();
+ if (web_contents) {
+ GURL gurl = params.url;
+ if (!url_util::FixupGURL(gurl)) {
+ return false;
+ }
+
+ web_contents->GetController().LoadURL(
+ gurl, params.referrer, params.transition, params.extra_headers);
+ return true;
+ }
+ return false;
+}
+
+void CefBrowserHostBase::ViewText(const std::string& text) {
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(CEF_UIT,
+ base::BindOnce(&CefBrowserHostBase::ViewText, this, text));
+ return;
+ }
+
+ if (platform_delegate_) {
+ platform_delegate_->ViewText(text);
+ }
+}
+
+void CefBrowserHostBase::RunFileChooserForBrowser(
+ const blink::mojom::FileChooserParams& params,
+ CefFileDialogManager::RunFileChooserCallback callback) {
+ if (!EnsureFileDialogManager()) {
+ LOG(ERROR) << "File dialog canceled due to invalid state.";
+ std::move(callback).Run({});
+ return;
+ }
+ file_dialog_manager_->RunFileChooser(params, std::move(callback));
+}
+
+void CefBrowserHostBase::RunSelectFile(
+ ui::SelectFileDialog::Listener* listener,
+ std::unique_ptr<ui::SelectFilePolicy> policy,
+ ui::SelectFileDialog::Type type,
+ const std::u16string& title,
+ const base::FilePath& default_path,
+ const ui::SelectFileDialog::FileTypeInfo* file_types,
+ int file_type_index,
+ const base::FilePath::StringType& default_extension,
+ gfx::NativeWindow owning_window,
+ void* params) {
+ if (!EnsureFileDialogManager()) {
+ LOG(ERROR) << "File dialog canceled due to invalid state.";
+ listener->FileSelectionCanceled(params);
+ return;
+ }
+ file_dialog_manager_->RunSelectFile(listener, std::move(policy), type, title,
+ default_path, file_types, file_type_index,
+ default_extension, owning_window, params);
+}
+
+void CefBrowserHostBase::SelectFileListenerDestroyed(
+ ui::SelectFileDialog::Listener* listener) {
+ if (file_dialog_manager_) {
+ file_dialog_manager_->SelectFileListenerDestroyed(listener);
+ }
+}
+
+bool CefBrowserHostBase::MaybeAllowNavigation(
+ content::RenderFrameHost* opener,
+ bool is_guest_view,
+ const content::OpenURLParams& params) {
+ return true;
+}
+
+void CefBrowserHostBase::OnAfterCreated() {
+ CEF_REQUIRE_UIT();
+ if (client_) {
+ if (auto handler = client_->GetLifeSpanHandler()) {
+ handler->OnAfterCreated(this);
+ }
+ }
+}
+
+void CefBrowserHostBase::OnBeforeClose() {
+ CEF_REQUIRE_UIT();
+ if (client_) {
+ if (auto handler = client_->GetLifeSpanHandler()) {
+ handler->OnBeforeClose(this);
+ }
+ }
+ browser_info_->SetClosing();
+}
+
+void CefBrowserHostBase::OnBrowserDestroyed() {
+ CEF_REQUIRE_UIT();
+
+ // Destroy any platform constructs.
+ if (file_dialog_manager_) {
+ file_dialog_manager_->Destroy();
+ file_dialog_manager_.reset();
+ }
+
+ for (auto& observer : observers_) {
+ observer.OnBrowserDestroyed(this);
+ }
+}
+
+int CefBrowserHostBase::browser_id() const {
+ return browser_info_->browser_id();
+}
+
+SkColor CefBrowserHostBase::GetBackgroundColor() const {
+ // Don't use |platform_delegate_| because it's not thread-safe.
+ return CefContext::Get()->GetBackgroundColor(
+ &settings_, IsWindowless() ? STATE_ENABLED : STATE_DISABLED);
+}
+
+bool CefBrowserHostBase::IsWindowless() const {
+ return false;
+}
+
+content::WebContents* CefBrowserHostBase::GetWebContents() const {
+ CEF_REQUIRE_UIT();
+ return contents_delegate_->web_contents();
+}
+
+content::BrowserContext* CefBrowserHostBase::GetBrowserContext() const {
+ CEF_REQUIRE_UIT();
+ auto web_contents = GetWebContents();
+ if (web_contents) {
+ return web_contents->GetBrowserContext();
+ }
+ return nullptr;
+}
+
+CefMediaStreamRegistrar* CefBrowserHostBase::GetMediaStreamRegistrar() {
+ CEF_REQUIRE_UIT();
+ if (!media_stream_registrar_) {
+ media_stream_registrar_ = std::make_unique<CefMediaStreamRegistrar>(this);
+ }
+ return media_stream_registrar_.get();
+}
+
+views::Widget* CefBrowserHostBase::GetWindowWidget() const {
+ CEF_REQUIRE_UIT();
+ if (!platform_delegate_) {
+ return nullptr;
+ }
+ return platform_delegate_->GetWindowWidget();
+}
+
+CefRefPtr<CefBrowserView> CefBrowserHostBase::GetBrowserView() const {
+ CEF_REQUIRE_UIT();
+ if (is_views_hosted_ && platform_delegate_) {
+ return platform_delegate_->GetBrowserView();
+ }
+ return nullptr;
+}
+
+gfx::NativeWindow CefBrowserHostBase::GetTopLevelNativeWindow() const {
+ CEF_REQUIRE_UIT();
+ // Windowless browsers always return nullptr from GetTopLevelNativeWindow().
+ if (!IsWindowless()) {
+ auto web_contents = GetWebContents();
+ if (web_contents) {
+ return web_contents->GetTopLevelNativeWindow();
+ }
+ }
+ return gfx::NativeWindow();
+}
+
+bool CefBrowserHostBase::IsFocused() const {
+ CEF_REQUIRE_UIT();
+ auto web_contents = GetWebContents();
+ if (web_contents) {
+ return static_cast<content::RenderFrameHostImpl*>(
+ web_contents->GetPrimaryMainFrame())
+ ->IsFocused();
+ }
+ return false;
+}
+
+bool CefBrowserHostBase::IsVisible() const {
+ CEF_REQUIRE_UIT();
+ // Windowless browsers always return nullptr from GetNativeView().
+ if (!IsWindowless()) {
+ auto web_contents = GetWebContents();
+ if (web_contents) {
+ return platform_util::IsVisible(web_contents->GetNativeView());
+ }
+ }
+ return false;
+}
+
+bool CefBrowserHostBase::EnsureDevToolsManager() {
+ CEF_REQUIRE_UIT();
+ if (!contents_delegate_->web_contents()) {
+ return false;
+ }
+
+ if (!devtools_manager_) {
+ devtools_manager_ = std::make_unique<CefDevToolsManager>(this);
+ }
+ return true;
+}
+
+void CefBrowserHostBase::InitializeDevToolsRegistrationOnUIThread(
+ CefRefPtr<CefRegistration> registration) {
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(
+ CEF_UIT,
+ base::BindOnce(
+ &CefBrowserHostBase::InitializeDevToolsRegistrationOnUIThread, this,
+ registration));
+ return;
+ }
+
+ if (!EnsureDevToolsManager()) {
+ return;
+ }
+ devtools_manager_->InitializeRegistrationOnUIThread(registration);
+}
+
+bool CefBrowserHostBase::EnsureFileDialogManager() {
+ CEF_REQUIRE_UIT();
+ if (!contents_delegate_->web_contents()) {
+ return false;
+ }
+
+ if (!file_dialog_manager_) {
+ file_dialog_manager_ = std::make_unique<CefFileDialogManager>(this);
+ }
+ return true;
+}
diff --git a/libcef/browser/browser_host_base.h b/libcef/browser/browser_host_base.h
new file mode 100644
index 00000000..98281293
--- /dev/null
+++ b/libcef/browser/browser_host_base.h
@@ -0,0 +1,382 @@
+// Copyright 2020 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_BROWSER_HOST_BASE_H_
+#define CEF_LIBCEF_BROWSER_BROWSER_HOST_BASE_H_
+#pragma once
+
+#include "include/cef_browser.h"
+#include "include/cef_client.h"
+#include "include/views/cef_browser_view.h"
+#include "libcef/browser/browser_contents_delegate.h"
+#include "libcef/browser/browser_info.h"
+#include "libcef/browser/browser_platform_delegate.h"
+#include "libcef/browser/devtools/devtools_manager.h"
+#include "libcef/browser/file_dialog_manager.h"
+#include "libcef/browser/frame_host_impl.h"
+#include "libcef/browser/media_stream_registrar.h"
+#include "libcef/browser/request_context_impl.h"
+
+#include "base/observer_list.h"
+#include "base/synchronization/lock.h"
+#include "extensions/common/mojom/view_type.mojom.h"
+
+namespace extensions {
+class Extension;
+}
+
+// Parameters that are passed to the runtime-specific Create methods.
+struct CefBrowserCreateParams {
+ CefBrowserCreateParams() {}
+
+ // Copy constructor used with the chrome runtime only.
+ CefBrowserCreateParams(const CefBrowserCreateParams& that) {
+ operator=(that);
+ }
+ CefBrowserCreateParams& operator=(const CefBrowserCreateParams& that) {
+ // Not all parameters can be copied.
+ client = that.client;
+ url = that.url;
+ settings = that.settings;
+ request_context = that.request_context;
+ extra_info = that.extra_info;
+ if (that.window_info) {
+ MaybeSetWindowInfo(*that.window_info);
+ }
+ browser_view = that.browser_view;
+ return *this;
+ }
+
+ // Set |window_info| if appropriate (see below).
+ void MaybeSetWindowInfo(const CefWindowInfo& window_info);
+
+ // Platform-specific window creation info. Will be nullptr for Views-hosted
+ // browsers except when using the Chrome runtime with a native parent handle.
+ std::unique_ptr<CefWindowInfo> window_info;
+
+ // The BrowserView that will own a Views-hosted browser. Will be nullptr for
+ // popup browsers.
+ CefRefPtr<CefBrowserView> browser_view;
+
+ // True if this browser is a popup and has a Views-hosted opener, in which
+ // case the BrowserView for this browser will be created later (from
+ // PopupWebContentsCreated).
+ bool popup_with_views_hosted_opener = false;
+
+ // Client implementation. May be nullptr.
+ CefRefPtr<CefClient> client;
+
+ // Initial URL to load. May be empty. If this is a valid extension URL then
+ // the browser will be created as an app view extension host.
+ CefString url;
+
+ // Browser settings.
+ CefBrowserSettings settings;
+
+ // Other browser that opened this DevTools browser. Will be nullptr for non-
+ // DevTools browsers. Currently used with the alloy runtime only.
+ CefRefPtr<CefBrowserHostBase> devtools_opener;
+
+ // Request context to use when creating the browser. If nullptr the global
+ // request context will be used.
+ CefRefPtr<CefRequestContext> request_context;
+
+ // Extra information that will be passed to
+ // CefRenderProcessHandler::OnBrowserCreated.
+ CefRefPtr<CefDictionaryValue> extra_info;
+
+ // Used when explicitly creating the browser as an extension host via
+ // ProcessManager::CreateBackgroundHost. Currently used with the alloy
+ // runtime only.
+ const extensions::Extension* extension = nullptr;
+ extensions::mojom::ViewType extension_host_type =
+ extensions::mojom::ViewType::kInvalid;
+};
+
+// Base class for CefBrowserHost implementations. Includes functionality that is
+// shared by the alloy and chrome runtimes. All methods are thread-safe unless
+// otherwise indicated.
+class CefBrowserHostBase : public CefBrowserHost,
+ public CefBrowser,
+ public CefBrowserContentsDelegate::Observer {
+ public:
+ // Interface to implement for observers that wish to be informed of changes
+ // to the CefBrowserHostBase. All methods will be called on the UI thread.
+ class Observer : public base::CheckedObserver {
+ public:
+ // Called before |browser| is destroyed. Any references to |browser| should
+ // be cleared when this method is called.
+ virtual void OnBrowserDestroyed(CefBrowserHostBase* browser) = 0;
+
+ protected:
+ virtual ~Observer() {}
+ };
+
+ // Create a new CefBrowserHost instance of the current runtime type with
+ // owned WebContents.
+ static CefRefPtr<CefBrowserHostBase> Create(
+ CefBrowserCreateParams& create_params);
+
+ // Returns the browser associated with the specified RenderViewHost.
+ static CefRefPtr<CefBrowserHostBase> GetBrowserForHost(
+ const content::RenderViewHost* host);
+ // Returns the browser associated with the specified RenderFrameHost.
+ static CefRefPtr<CefBrowserHostBase> GetBrowserForHost(
+ const content::RenderFrameHost* host);
+ // Returns the browser associated with the specified WebContents.
+ static CefRefPtr<CefBrowserHostBase> GetBrowserForContents(
+ const content::WebContents* contents);
+ // Returns the browser associated with the specified global ID.
+ static CefRefPtr<CefBrowserHostBase> GetBrowserForGlobalId(
+ const content::GlobalRenderFrameHostId& global_id);
+ // Returns the browser associated with the specified top-level window.
+ static CefRefPtr<CefBrowserHostBase> GetBrowserForTopLevelNativeWindow(
+ gfx::NativeWindow owning_window);
+
+ // Returns the browser most likely to be focused. This may be somewhat iffy
+ // with windowless browsers as there is no guarantee that the client has only
+ // one browser focused at a time.
+ static CefRefPtr<CefBrowserHostBase> GetLikelyFocusedBrowser();
+
+ CefBrowserHostBase(
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefClient> client,
+ std::unique_ptr<CefBrowserPlatformDelegate> platform_delegate,
+ scoped_refptr<CefBrowserInfo> browser_info,
+ CefRefPtr<CefRequestContextImpl> request_context);
+
+ CefBrowserHostBase(const CefBrowserHostBase&) = delete;
+ CefBrowserHostBase& operator=(const CefBrowserHostBase&) = delete;
+
+ // Called on the UI thread after the associated WebContents is created.
+ virtual void InitializeBrowser();
+
+ // Called on the UI thread when the OS window hosting the browser is
+ // destroyed.
+ virtual void WindowDestroyed() = 0;
+
+ // Returns true if the browser is in the process of being destroyed. Called on
+ // the UI thread only.
+ virtual bool WillBeDestroyed() const = 0;
+
+ // Called on the UI thread after the associated WebContents is destroyed.
+ // Also called from CefBrowserInfoManager::DestroyAllBrowsers if the browser
+ // was not properly shut down.
+ virtual void DestroyBrowser();
+
+ // CefBrowserHost methods:
+ CefRefPtr<CefBrowser> GetBrowser() override;
+ CefRefPtr<CefClient> GetClient() override;
+ CefRefPtr<CefRequestContext> GetRequestContext() override;
+ bool HasView() override;
+ void SetFocus(bool focus) override;
+ void RunFileDialog(FileDialogMode mode,
+ const CefString& title,
+ const CefString& default_file_path,
+ const std::vector<CefString>& accept_filters,
+ CefRefPtr<CefRunFileDialogCallback> callback) override;
+ void StartDownload(const CefString& url) override;
+ void DownloadImage(const CefString& image_url,
+ bool is_favicon,
+ uint32 max_image_size,
+ bool bypass_cache,
+ CefRefPtr<CefDownloadImageCallback> callback) override;
+ void Print() override;
+ void PrintToPDF(const CefString& path,
+ const CefPdfPrintSettings& settings,
+ CefRefPtr<CefPdfPrintCallback> callback) override;
+ void ReplaceMisspelling(const CefString& word) override;
+ void AddWordToDictionary(const CefString& word) override;
+ void SendKeyEvent(const CefKeyEvent& event) override;
+ void SendMouseClickEvent(const CefMouseEvent& event,
+ MouseButtonType type,
+ bool mouseUp,
+ int clickCount) override;
+ void SendMouseMoveEvent(const CefMouseEvent& event, bool mouseLeave) override;
+ void SendMouseWheelEvent(const CefMouseEvent& event,
+ int deltaX,
+ int deltaY) override;
+ bool SendDevToolsMessage(const void* message, size_t message_size) override;
+ int ExecuteDevToolsMethod(int message_id,
+ const CefString& method,
+ CefRefPtr<CefDictionaryValue> params) override;
+ CefRefPtr<CefRegistration> AddDevToolsMessageObserver(
+ CefRefPtr<CefDevToolsMessageObserver> observer) override;
+ void GetNavigationEntries(CefRefPtr<CefNavigationEntryVisitor> visitor,
+ bool current_only) override;
+ CefRefPtr<CefNavigationEntry> GetVisibleNavigationEntry() override;
+ void NotifyMoveOrResizeStarted() override;
+
+ // CefBrowser methods:
+ bool IsValid() override;
+ CefRefPtr<CefBrowserHost> GetHost() override;
+ bool CanGoBack() override;
+ void GoBack() override;
+ bool CanGoForward() override;
+ void GoForward() override;
+ bool IsLoading() override;
+ void Reload() override;
+ void ReloadIgnoreCache() override;
+ void StopLoad() override;
+ int GetIdentifier() override;
+ bool IsSame(CefRefPtr<CefBrowser> that) override;
+ bool HasDocument() override;
+ bool IsPopup() override;
+ CefRefPtr<CefFrame> GetMainFrame() override;
+ CefRefPtr<CefFrame> GetFocusedFrame() override;
+ CefRefPtr<CefFrame> GetFrame(int64 identifier) override;
+ CefRefPtr<CefFrame> GetFrame(const CefString& name) override;
+ size_t GetFrameCount() override;
+ void GetFrameIdentifiers(std::vector<int64>& identifiers) override;
+ void GetFrameNames(std::vector<CefString>& names) override;
+
+ // CefBrowserContentsDelegate::Observer methods:
+ void OnStateChanged(CefBrowserContentsState state_changed) override;
+ void OnWebContentsDestroyed(content::WebContents* web_contents) override;
+
+ // Returns the frame associated with the specified RenderFrameHost.
+ CefRefPtr<CefFrame> GetFrameForHost(const content::RenderFrameHost* host);
+
+ // Returns the frame associated with the specified global ID. See
+ // documentation on RenderFrameHost::GetFrameTreeNodeId() for why the global
+ // ID is preferred.
+ CefRefPtr<CefFrame> GetFrameForGlobalId(
+ const content::GlobalRenderFrameHostId& global_id);
+
+ // Manage observer objects. The observer must either outlive this object or
+ // be removed before destruction. Must be called on the UI thread.
+ void AddObserver(Observer* observer);
+ void RemoveObserver(Observer* observer);
+ bool HasObserver(Observer* observer) const;
+
+ // Methods called from CefFrameHostImpl.
+ void LoadMainFrameURL(const content::OpenURLParams& params);
+ virtual void OnSetFocus(cef_focus_source_t source) = 0;
+ void ViewText(const std::string& text);
+
+ // Calls CefFileDialogManager methods.
+ void RunFileChooserForBrowser(
+ const blink::mojom::FileChooserParams& params,
+ CefFileDialogManager::RunFileChooserCallback callback);
+ void RunSelectFile(ui::SelectFileDialog::Listener* listener,
+ std::unique_ptr<ui::SelectFilePolicy> policy,
+ ui::SelectFileDialog::Type type,
+ const std::u16string& title,
+ const base::FilePath& default_path,
+ const ui::SelectFileDialog::FileTypeInfo* file_types,
+ int file_type_index,
+ const base::FilePath::StringType& default_extension,
+ gfx::NativeWindow owning_window,
+ void* params);
+ void SelectFileListenerDestroyed(ui::SelectFileDialog::Listener* listener);
+
+ // Called from CefBrowserInfoManager::MaybeAllowNavigation.
+ virtual bool MaybeAllowNavigation(content::RenderFrameHost* opener,
+ bool is_guest_view,
+ const content::OpenURLParams& params);
+
+ // Helpers for executing client callbacks. Must be called on the UI thread.
+ void OnAfterCreated();
+ void OnBeforeClose();
+ void OnBrowserDestroyed();
+
+ // Thread-safe accessors.
+ const CefBrowserSettings& settings() const { return settings_; }
+ CefRefPtr<CefClient> client() const { return client_; }
+ scoped_refptr<CefBrowserInfo> browser_info() const { return browser_info_; }
+ int browser_id() const;
+ CefRefPtr<CefRequestContextImpl> request_context() const {
+ return request_context_;
+ }
+ bool is_views_hosted() const { return is_views_hosted_; }
+ SkColor GetBackgroundColor() const;
+
+ // Returns true if windowless rendering is enabled.
+ virtual bool IsWindowless() const;
+
+ // Accessors that must be called on the UI thread.
+ content::WebContents* GetWebContents() const;
+ content::BrowserContext* GetBrowserContext() const;
+ CefBrowserPlatformDelegate* platform_delegate() const {
+ return platform_delegate_.get();
+ }
+ CefBrowserContentsDelegate* contents_delegate() const {
+ return contents_delegate_.get();
+ }
+ CefMediaStreamRegistrar* GetMediaStreamRegistrar();
+
+ // Returns the Widget owner for the browser window. Only used with windowed
+ // browsers.
+ views::Widget* GetWindowWidget() const;
+
+ // Returns the BrowserView associated with this browser. Only used with Views-
+ // based browsers.
+ CefRefPtr<CefBrowserView> GetBrowserView() const;
+
+ // Returns the top-level native window for this browser. With windowed
+ // browsers this will be an aura::Window* on Aura platforms (Windows/Linux)
+ // and an NSWindow wrapper object from native_widget_types.h on MacOS. With
+ // windowless browsers this method will always return an empty value.
+ gfx::NativeWindow GetTopLevelNativeWindow() const;
+
+ // Returns true if this browser is currently focused. A browser is considered
+ // focused when the top-level RenderFrameHost is in the parent chain of the
+ // currently focused RFH within the frame tree. In addition, its associated
+ // RenderWidgetHost must also be focused. With windowed browsers only one
+ // browser should be focused at a time. With windowless browsers this relies
+ // on the client to properly configure focus state.
+ bool IsFocused() const;
+
+ // Returns true if this browser is currently visible.
+ virtual bool IsVisible() const;
+
+ protected:
+ bool EnsureDevToolsManager();
+ void InitializeDevToolsRegistrationOnUIThread(
+ CefRefPtr<CefRegistration> registration);
+
+ // Called from LoadMainFrameURL to perform the actual navigation.
+ virtual bool Navigate(const content::OpenURLParams& params);
+
+ // Create the CefFileDialogManager if it doesn't already exist.
+ bool EnsureFileDialogManager();
+
+ // Thread-safe members.
+ CefBrowserSettings settings_;
+ CefRefPtr<CefClient> client_;
+ std::unique_ptr<CefBrowserPlatformDelegate> platform_delegate_;
+ scoped_refptr<CefBrowserInfo> browser_info_;
+ CefRefPtr<CefRequestContextImpl> request_context_;
+ const bool is_views_hosted_;
+
+ // Only accessed on the UI thread.
+ std::unique_ptr<CefBrowserContentsDelegate> contents_delegate_;
+
+ // Observers that want to be notified of changes to this object.
+ // Only accessed on the UI thread.
+ base::ObserverList<Observer> observers_;
+
+ // Used for creating and managing file dialogs.
+ std::unique_ptr<CefFileDialogManager> file_dialog_manager_;
+
+ // Volatile state accessed from multiple threads. All access must be protected
+ // by |state_lock_|.
+ base::Lock state_lock_;
+ bool is_loading_ = false;
+ bool can_go_back_ = false;
+ bool can_go_forward_ = false;
+ bool has_document_ = false;
+ bool is_fullscreen_ = false;
+ CefRefPtr<CefFrameHostImpl> focused_frame_;
+
+ // Used for creating and managing DevTools instances.
+ std::unique_ptr<CefDevToolsManager> devtools_manager_;
+
+ std::unique_ptr<CefMediaStreamRegistrar> media_stream_registrar_;
+
+ private:
+ IMPLEMENT_REFCOUNTING(CefBrowserHostBase);
+};
+
+#endif // CEF_LIBCEF_BROWSER_BROWSER_HOST_BASE_H_
diff --git a/libcef/browser/browser_host_create.cc b/libcef/browser/browser_host_create.cc
new file mode 100644
index 00000000..ac09edfa
--- /dev/null
+++ b/libcef/browser/browser_host_create.cc
@@ -0,0 +1,174 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors.
+// Portions copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "include/cef_browser.h"
+#include "libcef/browser/alloy/alloy_browser_host_impl.h"
+#include "libcef/browser/chrome/chrome_browser_host_impl.h"
+#include "libcef/browser/chrome/views/chrome_child_window.h"
+#include "libcef/browser/context.h"
+#include "libcef/browser/thread_util.h"
+#include "libcef/features/runtime.h"
+
+namespace {
+
+class CreateBrowserHelper {
+ public:
+ CreateBrowserHelper(const CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient> client,
+ const CefString& url,
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefDictionaryValue> extra_info,
+ CefRefPtr<CefRequestContext> request_context)
+ : window_info_(windowInfo),
+ client_(client),
+ url_(url),
+ settings_(settings),
+ extra_info_(extra_info),
+ request_context_(request_context) {}
+
+ void Run() {
+ CefBrowserHost::CreateBrowserSync(window_info_, client_, url_, settings_,
+ extra_info_, request_context_);
+ }
+
+ CefWindowInfo window_info_;
+ CefRefPtr<CefClient> client_;
+ CefString url_;
+ CefBrowserSettings settings_;
+ CefRefPtr<CefDictionaryValue> extra_info_;
+ CefRefPtr<CefRequestContext> request_context_;
+};
+
+} // namespace
+
+// static
+bool CefBrowserHost::CreateBrowser(
+ const CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient> client,
+ const CefString& url,
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefDictionaryValue> extra_info,
+ CefRefPtr<CefRequestContext> request_context) {
+ // Verify that the context is in a valid state.
+ if (!CONTEXT_STATE_VALID()) {
+ NOTREACHED() << "context not valid";
+ return false;
+ }
+
+ // Verify that the settings structure is a valid size.
+ if (settings.size != sizeof(cef_browser_settings_t)) {
+ NOTREACHED() << "invalid CefBrowserSettings structure size";
+ return false;
+ }
+
+ // Verify windowless rendering requirements.
+ if (windowInfo.windowless_rendering_enabled &&
+ !client->GetRenderHandler().get()) {
+ NOTREACHED() << "CefRenderHandler implementation is required";
+ return false;
+ }
+
+ if (windowInfo.windowless_rendering_enabled &&
+ !CefContext::Get()->settings().windowless_rendering_enabled) {
+ LOG(ERROR) << "Creating a windowless browser without setting "
+ "CefSettings.windowless_rendering_enabled may result in "
+ "reduced performance or runtime errors.";
+ }
+
+ if (!request_context) {
+ request_context = CefRequestContext::GetGlobalContext();
+ }
+
+ auto helper = std::make_unique<CreateBrowserHelper>(
+ windowInfo, client, url, settings, extra_info, request_context);
+
+ auto request_context_impl =
+ static_cast<CefRequestContextImpl*>(request_context.get());
+
+ // Wait for the browser context to be initialized before creating the browser.
+ request_context_impl->ExecuteWhenBrowserContextInitialized(base::BindOnce(
+ [](std::unique_ptr<CreateBrowserHelper> helper) {
+ // Always execute asynchronously to avoid potential issues if we're
+ // being called synchronously during app initialization.
+ CEF_POST_TASK(CEF_UIT, base::BindOnce(&CreateBrowserHelper::Run,
+ std::move(helper)));
+ },
+ std::move(helper)));
+
+ return true;
+}
+
+// static
+CefRefPtr<CefBrowser> CefBrowserHost::CreateBrowserSync(
+ const CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient> client,
+ const CefString& url,
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefDictionaryValue> extra_info,
+ CefRefPtr<CefRequestContext> request_context) {
+ // Verify that the context is in a valid state.
+ if (!CONTEXT_STATE_VALID()) {
+ NOTREACHED() << "context not valid";
+ return nullptr;
+ }
+
+ // Verify that the settings structure is a valid size.
+ if (settings.size != sizeof(cef_browser_settings_t)) {
+ NOTREACHED() << "invalid CefBrowserSettings structure size";
+ return nullptr;
+ }
+
+ if (!request_context) {
+ request_context = CefRequestContext::GetGlobalContext();
+ }
+
+ // Verify that the browser context is valid.
+ auto request_context_impl =
+ static_cast<CefRequestContextImpl*>(request_context.get());
+ if (!request_context_impl->VerifyBrowserContext()) {
+ return nullptr;
+ }
+
+ // Verify windowless rendering requirements.
+ if (windowInfo.windowless_rendering_enabled &&
+ !client->GetRenderHandler().get()) {
+ NOTREACHED() << "CefRenderHandler implementation is required";
+ return nullptr;
+ }
+
+ CefBrowserCreateParams create_params;
+ create_params.MaybeSetWindowInfo(windowInfo);
+ create_params.client = client;
+ create_params.url = url;
+ create_params.settings = settings;
+ create_params.extra_info = extra_info;
+ create_params.request_context = request_context;
+
+ return CefBrowserHostBase::Create(create_params);
+}
+
+void CefBrowserCreateParams::MaybeSetWindowInfo(
+ const CefWindowInfo& new_window_info) {
+ if (!cef::IsChromeRuntimeEnabled() ||
+ chrome_child_window::HasParentHandle(new_window_info)) {
+ window_info = std::make_unique<CefWindowInfo>(new_window_info);
+ }
+}
+
+// static
+CefRefPtr<CefBrowserHostBase> CefBrowserHostBase::Create(
+ CefBrowserCreateParams& create_params) {
+ if (cef::IsChromeRuntimeEnabled()) {
+ if (auto browser =
+ chrome_child_window::MaybeCreateChildBrowser(create_params)) {
+ return browser.get();
+ }
+ auto browser = ChromeBrowserHostImpl::Create(create_params);
+ return browser.get();
+ }
+
+ auto browser = AlloyBrowserHostImpl::Create(create_params);
+ return browser.get();
+}
diff --git a/libcef/browser/browser_info.cc b/libcef/browser/browser_info.cc
new file mode 100644
index 00000000..1b6f5ffb
--- /dev/null
+++ b/libcef/browser/browser_info.cc
@@ -0,0 +1,563 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#include "libcef/browser/browser_info.h"
+
+#include "libcef/browser/browser_host_base.h"
+#include "libcef/browser/thread_util.h"
+#include "libcef/common/frame_util.h"
+#include "libcef/common/values_impl.h"
+
+#include "base/logging.h"
+#include "content/browser/renderer_host/frame_tree_node.h"
+#include "content/browser/renderer_host/render_frame_host_impl.h"
+#include "content/public/browser/render_process_host.h"
+#include "ipc/ipc_message.h"
+
+CefBrowserInfo::FrameInfo::~FrameInfo() {
+#if DCHECK_IS_ON()
+ if (frame_ && !IsCurrentMainFrame()) {
+ // Should already be Detached.
+ DCHECK(!frame_->GetRenderFrameHost());
+ }
+#endif
+}
+
+CefBrowserInfo::CefBrowserInfo(int browser_id,
+ bool is_popup,
+ bool is_windowless,
+ CefRefPtr<CefDictionaryValue> extra_info)
+ : browser_id_(browser_id),
+ is_popup_(is_popup),
+ is_windowless_(is_windowless),
+ extra_info_(extra_info) {
+ DCHECK_GT(browser_id, 0);
+}
+
+CefBrowserInfo::~CefBrowserInfo() {
+ DCHECK(frame_info_set_.empty());
+}
+
+CefRefPtr<CefBrowserHostBase> CefBrowserInfo::browser() const {
+ base::AutoLock lock_scope(lock_);
+ if (!is_closing_) {
+ return browser_;
+ }
+ return nullptr;
+}
+
+void CefBrowserInfo::SetBrowser(CefRefPtr<CefBrowserHostBase> browser) {
+ NotificationStateLock lock_scope(this);
+
+ if (browser) {
+ DCHECK(!browser_);
+
+ // Cache the associated frame handler.
+ if (auto client = browser->GetClient()) {
+ frame_handler_ = client->GetFrameHandler();
+ }
+ } else {
+ DCHECK(browser_);
+ }
+
+ auto old_browser = browser_;
+ browser_ = browser;
+
+ if (!browser_) {
+ RemoveAllFrames(old_browser);
+
+ // Any future calls to MaybeExecuteFrameNotification will now fail.
+ // NotificationStateLock already took a reference for the delivery of any
+ // notifications that are currently queued due to RemoveAllFrames.
+ frame_handler_ = nullptr;
+ }
+}
+
+void CefBrowserInfo::SetClosing() {
+ base::AutoLock lock_scope(lock_);
+ DCHECK(!is_closing_);
+ is_closing_ = true;
+}
+
+void CefBrowserInfo::MaybeCreateFrame(content::RenderFrameHost* host,
+ bool is_guest_view) {
+ CEF_REQUIRE_UIT();
+
+ const auto global_id = host->GetGlobalId();
+ const bool is_main_frame = (host->GetParent() == nullptr);
+
+ // A speculative RFH will be created in response to a browser-initiated
+ // cross-origin navigation (e.g. via LoadURL) and eventually either discarded
+ // or swapped in based on whether the navigation is committed. We'll create a
+ // frame object for the speculative RFH so that it can be found by
+ // frame/routing ID. However, we won't replace the main frame with a
+ // speculative RFH until after it's swapped in, and we'll generally prefer to
+ // return a non-speculative RFH for the same node ID if one exists.
+ const bool is_speculative = (static_cast<content::RenderFrameHostImpl*>(host)
+ ->frame_tree_node()
+ ->render_manager()
+ ->current_frame_host() != host);
+
+ NotificationStateLock lock_scope(this);
+ DCHECK(browser_);
+
+ const auto it = frame_id_map_.find(global_id);
+ if (it != frame_id_map_.end()) {
+ auto info = it->second;
+
+#if DCHECK_IS_ON()
+ // Check that the frame info hasn't changed unexpectedly.
+ DCHECK_EQ(info->global_id_, global_id);
+ DCHECK_EQ(info->is_guest_view_, is_guest_view);
+ DCHECK_EQ(info->is_main_frame_, is_main_frame);
+#endif
+
+ if (!info->is_guest_view_ && info->is_speculative_ && !is_speculative) {
+ // Upgrade the frame info from speculative to non-speculative.
+ if (info->is_main_frame_) {
+ // Set the main frame object.
+ SetMainFrame(browser_, info->frame_);
+ }
+ info->is_speculative_ = false;
+ }
+ return;
+ }
+
+ auto frame_info = new FrameInfo;
+ frame_info->host_ = host;
+ frame_info->global_id_ = global_id;
+ frame_info->is_guest_view_ = is_guest_view;
+ frame_info->is_main_frame_ = is_main_frame;
+ frame_info->is_speculative_ = is_speculative;
+
+ // Guest views don't get their own CefBrowser or CefFrame objects.
+ if (!is_guest_view) {
+ // Create a new frame object.
+ frame_info->frame_ = new CefFrameHostImpl(this, host);
+ MaybeNotifyFrameCreated(frame_info->frame_);
+ if (is_main_frame && !is_speculative) {
+ SetMainFrame(browser_, frame_info->frame_);
+ }
+
+#if DCHECK_IS_ON()
+ // Check that the frame info hasn't changed unexpectedly.
+ DCHECK_EQ(frame_util::MakeFrameId(global_id),
+ frame_info->frame_->GetIdentifier());
+ DCHECK_EQ(frame_info->is_main_frame_, frame_info->frame_->IsMain());
+#endif
+ }
+
+ browser_->request_context()->OnRenderFrameCreated(global_id, is_main_frame,
+ is_guest_view);
+
+ // Populate the lookup maps.
+ frame_id_map_.insert(std::make_pair(global_id, frame_info));
+
+ // And finally set the ownership.
+ frame_info_set_.insert(base::WrapUnique(frame_info));
+}
+
+void CefBrowserInfo::FrameHostStateChanged(
+ content::RenderFrameHost* host,
+ content::RenderFrameHost::LifecycleState old_state,
+ content::RenderFrameHost::LifecycleState new_state) {
+ CEF_REQUIRE_UIT();
+
+ if ((old_state == content::RenderFrameHost::LifecycleState::kPrerendering ||
+ old_state ==
+ content::RenderFrameHost::LifecycleState::kInBackForwardCache) &&
+ new_state == content::RenderFrameHost::LifecycleState::kActive) {
+ if (auto frame = GetFrameForHost(host)) {
+ // Update the associated RFH, which may have changed.
+ frame->MaybeReAttach(this, host);
+
+ if (frame->IsMain()) {
+ // Update the main frame object.
+ NotificationStateLock lock_scope(this);
+ SetMainFrame(browser_, frame);
+ }
+
+ // Update draggable regions.
+ frame->MaybeSendDidStopLoading();
+ }
+ }
+
+ // Update BackForwardCache state.
+ bool added_to_bfcache =
+ new_state ==
+ content::RenderFrameHost::LifecycleState::kInBackForwardCache;
+ bool removed_from_bfcache =
+ old_state ==
+ content::RenderFrameHost::LifecycleState::kInBackForwardCache;
+ if (!added_to_bfcache && !removed_from_bfcache) {
+ return;
+ }
+
+ base::AutoLock lock_scope(lock_);
+
+ auto it = frame_id_map_.find(host->GetGlobalId());
+ DCHECK(it != frame_id_map_.end());
+ DCHECK((!it->second->is_in_bfcache_ && added_to_bfcache) ||
+ (it->second->is_in_bfcache_ && removed_from_bfcache));
+ it->second->is_in_bfcache_ = added_to_bfcache;
+}
+
+void CefBrowserInfo::RemoveFrame(content::RenderFrameHost* host) {
+ CEF_REQUIRE_UIT();
+
+ NotificationStateLock lock_scope(this);
+
+ const auto global_id = host->GetGlobalId();
+ auto it = frame_id_map_.find(global_id);
+ DCHECK(it != frame_id_map_.end());
+
+ auto frame_info = it->second;
+
+ browser_->request_context()->OnRenderFrameDeleted(
+ global_id, frame_info->is_main_frame_, frame_info->is_guest_view_);
+
+ // Remove from the lookup maps.
+ frame_id_map_.erase(it);
+
+ // And finally delete the frame info.
+ {
+ auto it2 = frame_info_set_.find(frame_info);
+
+ // Explicitly Detach everything but the current main frame.
+ const auto& other_frame_info = *it2;
+ if (other_frame_info->frame_ && !other_frame_info->IsCurrentMainFrame()) {
+ if (other_frame_info->frame_->Detach(
+ CefFrameHostImpl::DetachReason::RENDER_FRAME_DELETED)) {
+ MaybeNotifyFrameDetached(browser_, other_frame_info->frame_);
+ }
+ }
+
+ frame_info_set_.erase(it2);
+ }
+}
+
+CefRefPtr<CefFrameHostImpl> CefBrowserInfo::GetMainFrame() {
+ base::AutoLock lock_scope(lock_);
+ // Early exit if called post-destruction.
+ if (!browser_ || is_closing_) {
+ return nullptr;
+ }
+
+ CHECK(main_frame_);
+ return main_frame_;
+}
+
+CefRefPtr<CefFrameHostImpl> CefBrowserInfo::CreateTempSubFrame(
+ const content::GlobalRenderFrameHostId& parent_global_id) {
+ CefRefPtr<CefFrameHostImpl> parent = GetFrameForGlobalId(parent_global_id);
+ if (!parent) {
+ parent = GetMainFrame();
+ }
+ // Intentionally not notifying for temporary frames.
+ return new CefFrameHostImpl(this, parent->GetIdentifier());
+}
+
+CefRefPtr<CefFrameHostImpl> CefBrowserInfo::GetFrameForHost(
+ const content::RenderFrameHost* host,
+ bool* is_guest_view,
+ bool prefer_speculative) const {
+ if (is_guest_view) {
+ *is_guest_view = false;
+ }
+
+ if (!host) {
+ return nullptr;
+ }
+
+ return GetFrameForGlobalId(
+ const_cast<content::RenderFrameHost*>(host)->GetGlobalId(), is_guest_view,
+ prefer_speculative);
+}
+
+CefRefPtr<CefFrameHostImpl> CefBrowserInfo::GetFrameForGlobalId(
+ const content::GlobalRenderFrameHostId& global_id,
+ bool* is_guest_view,
+ bool prefer_speculative) const {
+ if (is_guest_view) {
+ *is_guest_view = false;
+ }
+
+ if (!frame_util::IsValidGlobalId(global_id)) {
+ return nullptr;
+ }
+
+ base::AutoLock lock_scope(lock_);
+
+ const auto it = frame_id_map_.find(global_id);
+ if (it != frame_id_map_.end()) {
+ const auto info = it->second;
+
+ if (info->is_guest_view_) {
+ if (is_guest_view) {
+ *is_guest_view = true;
+ }
+ return nullptr;
+ }
+
+ if (info->is_speculative_ && !prefer_speculative) {
+ if (info->is_main_frame_ && main_frame_) {
+ // Always prefer the non-speculative main frame.
+ return main_frame_;
+ }
+
+ LOG(WARNING) << "Returning a speculative frame for "
+ << frame_util::GetFrameDebugString(global_id);
+ }
+
+ DCHECK(info->frame_);
+ return info->frame_;
+ }
+
+ return nullptr;
+}
+
+CefBrowserInfo::FrameHostList CefBrowserInfo::GetAllFrames() const {
+ base::AutoLock lock_scope(lock_);
+ FrameHostList frames;
+ for (const auto& info : frame_info_set_) {
+ if (info->frame_ && !info->is_speculative_ && !info->is_in_bfcache_) {
+ frames.insert(info->frame_);
+ }
+ }
+ return frames;
+}
+
+CefBrowserInfo::NavigationLock::NavigationLock() : weak_ptr_factory_(this) {}
+
+CefBrowserInfo::NavigationLock::~NavigationLock() {
+ CEF_REQUIRE_UIT();
+ if (pending_action_) {
+ CEF_POST_TASK(CEF_UIT, std::move(pending_action_));
+ }
+}
+
+scoped_refptr<CefBrowserInfo::NavigationLock>
+CefBrowserInfo::CreateNavigationLock() {
+ CEF_REQUIRE_UIT();
+ scoped_refptr<NavigationLock> lock;
+ if (!navigation_lock_) {
+ lock = new NavigationLock();
+ navigation_lock_ = lock->weak_ptr_factory_.GetWeakPtr();
+ } else {
+ lock = navigation_lock_.get();
+ }
+ return lock;
+}
+
+bool CefBrowserInfo::IsNavigationLocked(base::OnceClosure pending_action) {
+ CEF_REQUIRE_UIT();
+ if (navigation_lock_) {
+ navigation_lock_->pending_action_ = std::move(pending_action);
+ return true;
+ }
+ return false;
+}
+
+void CefBrowserInfo::MaybeExecuteFrameNotification(
+ FrameNotifyOnceAction pending_action) {
+ CefRefPtr<CefFrameHandler> frame_handler;
+
+ {
+ base::AutoLock lock_scope_(notification_lock_);
+ if (!frame_handler_) {
+ // No notifications will be executed.
+ return;
+ }
+
+ if (notification_state_lock_) {
+ // Queue the notification until the lock is released.
+ notification_state_lock_->queue_.push(std::move(pending_action));
+ return;
+ }
+
+ frame_handler = frame_handler_;
+ }
+
+ // Execute immediately if not locked.
+ std::move(pending_action).Run(frame_handler);
+}
+
+void CefBrowserInfo::MaybeNotifyDraggableRegionsChanged(
+ CefRefPtr<CefBrowserHostBase> browser,
+ CefRefPtr<CefFrameHostImpl> frame,
+ std::vector<CefDraggableRegion> draggable_regions) {
+ CEF_REQUIRE_UIT();
+ DCHECK(frame->IsMain());
+
+ if (draggable_regions == draggable_regions_) {
+ return;
+ }
+
+ draggable_regions_ = std::move(draggable_regions);
+
+ if (auto client = browser->GetClient()) {
+ if (auto handler = client->GetDragHandler()) {
+ handler->OnDraggableRegionsChanged(browser.get(), frame,
+ draggable_regions_);
+ }
+ }
+}
+
+// Passing in |browser| here because |browser_| may already be cleared.
+void CefBrowserInfo::SetMainFrame(CefRefPtr<CefBrowserHostBase> browser,
+ CefRefPtr<CefFrameHostImpl> frame) {
+ lock_.AssertAcquired();
+ DCHECK(browser);
+ DCHECK(!frame || frame->IsMain());
+
+ if (frame && main_frame_ &&
+ frame->GetIdentifier() == main_frame_->GetIdentifier()) {
+ // Nothing to do.
+ return;
+ }
+
+ CefRefPtr<CefFrameHostImpl> old_frame;
+ if (main_frame_) {
+ old_frame = main_frame_;
+ if (old_frame->Detach(CefFrameHostImpl::DetachReason::NEW_MAIN_FRAME)) {
+ MaybeNotifyFrameDetached(browser, old_frame);
+ }
+ }
+
+ main_frame_ = frame;
+
+ MaybeNotifyMainFrameChanged(browser, old_frame, main_frame_);
+}
+
+void CefBrowserInfo::MaybeNotifyFrameCreated(
+ CefRefPtr<CefFrameHostImpl> frame) {
+ CEF_REQUIRE_UIT();
+
+ // Never notify for temporary objects.
+ DCHECK(!frame->is_temporary());
+
+ MaybeExecuteFrameNotification(base::BindOnce(
+ [](scoped_refptr<CefBrowserInfo> self, CefRefPtr<CefFrameHostImpl> frame,
+ CefRefPtr<CefFrameHandler> handler) {
+ if (auto browser = self->browser()) {
+ handler->OnFrameCreated(browser, frame);
+ }
+ },
+ scoped_refptr<CefBrowserInfo>(this), frame));
+}
+
+// Passing in |browser| here because |browser_| may already be cleared.
+void CefBrowserInfo::MaybeNotifyFrameDetached(
+ CefRefPtr<CefBrowserHostBase> browser,
+ CefRefPtr<CefFrameHostImpl> frame) {
+ CEF_REQUIRE_UIT();
+
+ // Never notify for temporary objects.
+ DCHECK(!frame->is_temporary());
+
+ MaybeExecuteFrameNotification(base::BindOnce(
+ [](CefRefPtr<CefBrowserHostBase> browser,
+ CefRefPtr<CefFrameHostImpl> frame,
+ CefRefPtr<CefFrameHandler> handler) {
+ handler->OnFrameDetached(browser, frame);
+ },
+ browser, frame));
+}
+
+// Passing in |browser| here because |browser_| may already be cleared.
+void CefBrowserInfo::MaybeNotifyMainFrameChanged(
+ CefRefPtr<CefBrowserHostBase> browser,
+ CefRefPtr<CefFrameHostImpl> old_frame,
+ CefRefPtr<CefFrameHostImpl> new_frame) {
+ CEF_REQUIRE_UIT();
+
+ // Never notify for temporary objects.
+ DCHECK(!old_frame || !old_frame->is_temporary());
+ DCHECK(!new_frame || !new_frame->is_temporary());
+
+ MaybeExecuteFrameNotification(base::BindOnce(
+ [](CefRefPtr<CefBrowserHostBase> browser,
+ CefRefPtr<CefFrameHostImpl> old_frame,
+ CefRefPtr<CefFrameHostImpl> new_frame,
+ CefRefPtr<CefFrameHandler> handler) {
+ handler->OnMainFrameChanged(browser, old_frame, new_frame);
+ },
+ browser, old_frame, new_frame));
+}
+
+void CefBrowserInfo::RemoveAllFrames(
+ CefRefPtr<CefBrowserHostBase> old_browser) {
+ lock_.AssertAcquired();
+
+ // Make sure any callbacks will see the correct state (e.g. like
+ // CefBrowser::GetMainFrame returning nullptr and CefBrowser::IsValid
+ // returning false).
+ DCHECK(!browser_);
+ DCHECK(old_browser);
+
+ // Clear the lookup maps.
+ frame_id_map_.clear();
+
+ // Explicitly Detach everything but the current main frame.
+ for (auto& info : frame_info_set_) {
+ if (info->frame_ && !info->IsCurrentMainFrame()) {
+ if (info->frame_->Detach(
+ CefFrameHostImpl::DetachReason::BROWSER_DESTROYED)) {
+ MaybeNotifyFrameDetached(old_browser, info->frame_);
+ }
+ }
+ }
+
+ if (main_frame_) {
+ SetMainFrame(old_browser, nullptr);
+ }
+
+ // And finally delete the frame info.
+ frame_info_set_.clear();
+}
+
+CefBrowserInfo::NotificationStateLock::NotificationStateLock(
+ CefBrowserInfo* browser_info)
+ : browser_info_(browser_info) {
+ CEF_REQUIRE_UIT();
+
+ // Take the navigation state lock.
+ {
+ base::AutoLock lock_scope_(browser_info_->notification_lock_);
+ CHECK(!browser_info_->notification_state_lock_);
+ browser_info_->notification_state_lock_ = this;
+ // We may need this on destruction, and the original might be cleared.
+ frame_handler_ = browser_info_->frame_handler_;
+ }
+
+ // Take the browser info state lock.
+ browser_info_lock_scope_.reset(new base::AutoLock(browser_info_->lock_));
+}
+
+CefBrowserInfo::NotificationStateLock::~NotificationStateLock() {
+ CEF_REQUIRE_UIT();
+
+ // Unlock in reverse order.
+ browser_info_lock_scope_.reset();
+
+ {
+ base::AutoLock lock_scope_(browser_info_->notification_lock_);
+ CHECK_EQ(this, browser_info_->notification_state_lock_);
+ browser_info_->notification_state_lock_ = nullptr;
+ }
+
+ if (!queue_.empty()) {
+ DCHECK(frame_handler_);
+
+ // Don't navigate while inside callbacks.
+ auto nav_lock = browser_info_->CreateNavigationLock();
+
+ // Empty the queue of pending actions. Any of these actions might result in
+ // the acquisition of a new NotificationStateLock.
+ while (!queue_.empty()) {
+ std::move(queue_.front()).Run(frame_handler_);
+ queue_.pop();
+ }
+ }
+}
diff --git a/libcef/browser/browser_info.h b/libcef/browser/browser_info.h
new file mode 100644
index 00000000..d53d77ab
--- /dev/null
+++ b/libcef/browser/browser_info.h
@@ -0,0 +1,259 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_BROWSER_INFO_H_
+#define CEF_LIBCEF_BROWSER_BROWSER_INFO_H_
+#pragma once
+
+#include <queue>
+#include <set>
+#include <unordered_map>
+
+#include "include/internal/cef_ptr.h"
+#include "libcef/common/values_impl.h"
+
+#include "base/containers/unique_ptr_adapters.h"
+#include "base/functional/callback.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "base/synchronization/lock.h"
+#include "base/values.h"
+#include "content/public/browser/global_routing_id.h"
+#include "content/public/browser/render_frame_host.h"
+
+class CefBrowserHostBase;
+class CefFrameHandler;
+class CefFrameHostImpl;
+
+// CefBrowserInfo is used to associate a browser ID and render view/process
+// IDs with a particular CefBrowserHostBase. Render view/process IDs may change
+// during the lifetime of a single CefBrowserHostBase.
+//
+// CefBrowserInfo objects are managed by CefBrowserInfoManager and should not be
+// created directly.
+class CefBrowserInfo : public base::RefCountedThreadSafe<CefBrowserInfo> {
+ public:
+ CefBrowserInfo(int browser_id,
+ bool is_popup,
+ bool is_windowless,
+ CefRefPtr<CefDictionaryValue> extra_info);
+
+ CefBrowserInfo(const CefBrowserInfo&) = delete;
+ CefBrowserInfo& operator=(const CefBrowserInfo&) = delete;
+
+ int browser_id() const { return browser_id_; }
+ bool is_popup() const { return is_popup_; }
+ bool is_windowless() const { return is_windowless_; }
+ CefRefPtr<CefDictionaryValue> extra_info() const { return extra_info_; }
+
+ // May return NULL if the browser has not yet been created or if the browser
+ // has been destroyed.
+ CefRefPtr<CefBrowserHostBase> browser() const;
+
+ // Set or clear the browser. Called from CefBrowserHostBase InitializeBrowser
+ // (to set) and DestroyBrowser (to clear).
+ void SetBrowser(CefRefPtr<CefBrowserHostBase> browser);
+
+ // Called after OnBeforeClose and before SetBrowser(nullptr). This will cause
+ // browser() and GetMainFrame() to return nullptr as expected by
+ // CefFrameHandler callbacks. Note that this differs from calling
+ // SetBrowser(nullptr) because the WebContents has not yet been destroyed and
+ // further frame-related callbacks are expected.
+ void SetClosing();
+
+ // Ensure that a frame record exists for |host|. Called for the main frame
+ // when the RenderView is created, or for a sub-frame when the associated
+ // RenderFrame is created in the renderer process.
+ // Called from CefBrowserContentsDelegate::RenderFrameCreated (is_guest_view =
+ // false) or CefMimeHandlerViewGuestDelegate::OnGuestAttached (is_guest_view =
+ // true).
+ void MaybeCreateFrame(content::RenderFrameHost* host, bool is_guest_view);
+
+ // Used to track state changes such as entering/exiting the BackForwardCache.
+ // Called from CefBrowserContentsDelegate::RenderFrameHostStateChanged.
+ void FrameHostStateChanged(
+ content::RenderFrameHost* host,
+ content::RenderFrameHost::LifecycleState old_state,
+ content::RenderFrameHost::LifecycleState new_state);
+
+ // Remove the frame record for |host|. Called for the main frame when the
+ // RenderView is destroyed, or for a sub-frame when the associated RenderFrame
+ // is destroyed in the renderer process.
+ // Called from CefBrowserContentsDelegate::RenderFrameDeleted or
+ // CefMimeHandlerViewGuestDelegate::OnGuestDetached.
+ void RemoveFrame(content::RenderFrameHost* host);
+
+ // Returns the main frame object. This object will remain valid until the
+ // browser is destroyed even though the indentifier may change with cross-
+ // origin navigations. Furthermore, calling LoadURL on this object will always
+ // behave as expected because the call is routed through the browser's
+ // NavigationController.
+ CefRefPtr<CefFrameHostImpl> GetMainFrame();
+
+ // Creates a temporary sub-frame object for situations during navigation or
+ // resource loading where a RFH does not yet exist. If |parent_frame_id|
+ // is invalid the current main frame will be specified as the parent.
+ // Temporary frame objects are not tracked but will be implicitly detached
+ // on browser destruction.
+ CefRefPtr<CefFrameHostImpl> CreateTempSubFrame(
+ const content::GlobalRenderFrameHostId& parent_global_id);
+
+ // Returns the frame object matching the specified host or nullptr if no match
+ // is found. Nullptr will also be returned if a guest view match is found
+ // because we don't create frame objects for guest views. If |is_guest_view|
+ // is non-nullptr it will be set to true in this case. Must be called on the
+ // UI thread.
+ CefRefPtr<CefFrameHostImpl> GetFrameForHost(
+ const content::RenderFrameHost* host,
+ bool* is_guest_view = nullptr,
+ bool prefer_speculative = false) const;
+
+ // Returns the frame object matching the specified ID or nullptr if no match
+ // is found. Nullptr will also be returned if a guest view match is found
+ // because we don't create frame objects for guest views. If |is_guest_view|
+ // is non-nullptr it will be set to true in this case. Safe to call from any
+ // thread.
+ CefRefPtr<CefFrameHostImpl> GetFrameForGlobalId(
+ const content::GlobalRenderFrameHostId& global_id,
+ bool* is_guest_view = nullptr,
+ bool prefer_speculative = false) const;
+
+ // Returns all non-speculative frame objects that currently exist. Guest views
+ // will be excluded because they don't have a frame object. Safe to call from
+ // any thread.
+ using FrameHostList = std::set<CefRefPtr<CefFrameHostImpl>>;
+ FrameHostList GetAllFrames() const;
+
+ class NavigationLock final : public base::RefCounted<NavigationLock> {
+ private:
+ friend class CefBrowserInfo;
+ friend class base::RefCounted<NavigationLock>;
+
+ NavigationLock();
+ ~NavigationLock();
+
+ base::OnceClosure pending_action_;
+ base::WeakPtrFactory<NavigationLock> weak_ptr_factory_;
+ };
+
+ // Block navigation actions on NavigationLock life span. Must be called on the
+ // UI thread.
+ scoped_refptr<NavigationLock> CreateNavigationLock();
+
+ // Returns true if navigation actions are currently blocked. If this method
+ // returns true the most recent |pending_action| will be executed on the UI
+ // thread once the navigation lock is released. Must be called on the UI
+ // thread.
+ bool IsNavigationLocked(base::OnceClosure pending_action);
+
+ using FrameNotifyOnceAction =
+ base::OnceCallback<void(CefRefPtr<CefFrameHandler>)>;
+
+ // Specifies a CefFrameHandler notification action whose execution may need
+ // to be blocked on release of a potentially held NotificationStateLock. If no
+ // CefFrameHandler exists then the action will be discarded without executing.
+ // If the NotificationStateLock is not currently held then the action will be
+ // executed immediately.
+ void MaybeExecuteFrameNotification(FrameNotifyOnceAction pending_action);
+
+ void MaybeNotifyDraggableRegionsChanged(
+ CefRefPtr<CefBrowserHostBase> browser,
+ CefRefPtr<CefFrameHostImpl> frame,
+ std::vector<CefDraggableRegion> draggable_regions);
+
+ private:
+ friend class base::RefCountedThreadSafe<CefBrowserInfo>;
+
+ virtual ~CefBrowserInfo();
+
+ struct FrameInfo {
+ ~FrameInfo();
+
+ inline bool IsCurrentMainFrame() const {
+ return frame_ && is_main_frame_ && !is_speculative_ && !is_in_bfcache_;
+ }
+
+ content::RenderFrameHost* host_;
+ content::GlobalRenderFrameHostId global_id_;
+ bool is_guest_view_;
+ bool is_main_frame_;
+ bool is_speculative_;
+ bool is_in_bfcache_ = false;
+ CefRefPtr<CefFrameHostImpl> frame_;
+ };
+
+ void SetMainFrame(CefRefPtr<CefBrowserHostBase> browser,
+ CefRefPtr<CefFrameHostImpl> frame);
+
+ void MaybeNotifyFrameCreated(CefRefPtr<CefFrameHostImpl> frame);
+ void MaybeNotifyFrameDetached(CefRefPtr<CefBrowserHostBase> browser,
+ CefRefPtr<CefFrameHostImpl> frame);
+ void MaybeNotifyMainFrameChanged(CefRefPtr<CefBrowserHostBase> browser,
+ CefRefPtr<CefFrameHostImpl> old_frame,
+ CefRefPtr<CefFrameHostImpl> new_frame);
+
+ void RemoveAllFrames(CefRefPtr<CefBrowserHostBase> old_browser);
+
+ int browser_id_;
+ bool is_popup_;
+ bool is_windowless_;
+ CefRefPtr<CefDictionaryValue> extra_info_;
+
+ // Navigation will be blocked while |navigation_lock_| exists.
+ // Only accessed on the UI thread.
+ base::WeakPtr<NavigationLock> navigation_lock_;
+
+ // Used instead of |base::AutoLock(lock_)| in situations that might generate
+ // CefFrameHandler notifications. Any notifications passed to
+ // MaybeExecuteFrameNotification() will be queued until the lock is released,
+ // and then executed in order. Only accessed on the UI thread.
+ class NotificationStateLock final {
+ public:
+ explicit NotificationStateLock(CefBrowserInfo* browser_info);
+ ~NotificationStateLock();
+
+ protected:
+ friend class CefBrowserInfo;
+ CefBrowserInfo* const browser_info_;
+ CefRefPtr<CefFrameHandler> frame_handler_;
+ std::unique_ptr<base::AutoLock> browser_info_lock_scope_;
+ std::queue<FrameNotifyOnceAction> queue_;
+ };
+
+ mutable base::Lock notification_lock_;
+
+ // These members must be protected by |notification_lock_|.
+ NotificationStateLock* notification_state_lock_ = nullptr;
+ CefRefPtr<CefFrameHandler> frame_handler_;
+
+ mutable base::Lock lock_;
+
+ // The below members must be protected by |lock_|.
+
+ CefRefPtr<CefBrowserHostBase> browser_;
+
+ // Owner of FrameInfo structs.
+ using FrameInfoSet =
+ std::set<std::unique_ptr<FrameInfo>, base::UniquePtrComparator>;
+ FrameInfoSet frame_info_set_;
+
+ // Map a global ID to one frame. These IDs are guaranteed to uniquely
+ // identify a RFH for its complete lifespan. See documentation on
+ // RenderFrameHost::GetFrameTreeNodeId() for background.
+ using FrameIDMap = std::unordered_map<content::GlobalRenderFrameHostId,
+ FrameInfo*,
+ content::GlobalRenderFrameHostIdHasher>;
+ FrameIDMap frame_id_map_;
+
+ // The current main frame.
+ CefRefPtr<CefFrameHostImpl> main_frame_;
+
+ // True if the browser is currently closing.
+ bool is_closing_ = false;
+
+ // Only accessed on the UI thread.
+ std::vector<CefDraggableRegion> draggable_regions_;
+};
+
+#endif // CEF_LIBCEF_BROWSER_BROWSER_INFO_H_
diff --git a/libcef/browser/browser_info_manager.cc b/libcef/browser/browser_info_manager.cc
new file mode 100644
index 00000000..c832288c
--- /dev/null
+++ b/libcef/browser/browser_info_manager.cc
@@ -0,0 +1,629 @@
+// Copyright 2015 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#include "libcef/browser/browser_info_manager.h"
+
+#include <utility>
+
+#include "libcef/browser/browser_host_base.h"
+#include "libcef/browser/browser_platform_delegate.h"
+#include "libcef/browser/extensions/browser_extensions_util.h"
+#include "libcef/browser/thread_util.h"
+#include "libcef/common/cef_switches.h"
+#include "libcef/common/extensions/extensions_util.h"
+#include "libcef/common/frame_util.h"
+#include "libcef/common/values_impl.h"
+#include "libcef/features/runtime_checks.h"
+
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/task/sequenced_task_runner.h"
+#include "content/public/browser/child_process_host.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/common/url_constants.h"
+
+namespace {
+
+// Timeout delay for new browser info responses.
+const int64_t kNewBrowserInfoResponseTimeoutMs = 2000;
+
+void TranslatePopupFeatures(const blink::mojom::WindowFeatures& webKitFeatures,
+ CefPopupFeatures& features) {
+ features.x = static_cast<int>(webKitFeatures.bounds.x());
+ features.xSet = webKitFeatures.has_x;
+ features.y = static_cast<int>(webKitFeatures.bounds.y());
+ features.ySet = webKitFeatures.has_y;
+ features.width = static_cast<int>(webKitFeatures.bounds.width());
+ features.widthSet = webKitFeatures.has_width;
+ features.height = static_cast<int>(webKitFeatures.bounds.height());
+ features.heightSet = webKitFeatures.has_height;
+
+ features.isPopup = webKitFeatures.is_popup;
+}
+
+CefBrowserInfoManager* g_info_manager = nullptr;
+
+} // namespace
+
+CefBrowserInfoManager::CefBrowserInfoManager() {
+ DCHECK(!g_info_manager);
+ g_info_manager = this;
+}
+
+CefBrowserInfoManager::~CefBrowserInfoManager() {
+ DCHECK(browser_info_list_.empty());
+ g_info_manager = nullptr;
+}
+
+// static
+CefBrowserInfoManager* CefBrowserInfoManager::GetInstance() {
+ return g_info_manager;
+}
+
+scoped_refptr<CefBrowserInfo> CefBrowserInfoManager::CreateBrowserInfo(
+ bool is_popup,
+ bool is_windowless,
+ CefRefPtr<CefDictionaryValue> extra_info) {
+ base::AutoLock lock_scope(browser_info_lock_);
+
+ scoped_refptr<CefBrowserInfo> browser_info = new CefBrowserInfo(
+ ++next_browser_id_, is_popup, is_windowless, extra_info);
+ browser_info_list_.push_back(browser_info);
+
+ return browser_info;
+}
+
+scoped_refptr<CefBrowserInfo> CefBrowserInfoManager::CreatePopupBrowserInfo(
+ content::WebContents* new_contents,
+ bool is_windowless,
+ CefRefPtr<CefDictionaryValue> extra_info) {
+ base::AutoLock lock_scope(browser_info_lock_);
+
+ auto frame_host = new_contents->GetPrimaryMainFrame();
+
+ scoped_refptr<CefBrowserInfo> browser_info =
+ new CefBrowserInfo(++next_browser_id_, true, is_windowless, extra_info);
+ browser_info_list_.push_back(browser_info);
+
+ // Continue any pending NewBrowserInfo request.
+ auto it = pending_new_browser_info_map_.find(frame_host->GetGlobalId());
+ if (it != pending_new_browser_info_map_.end()) {
+ SendNewBrowserInfoResponse(browser_info, /*is_guest_view=*/false,
+ std::move(it->second->callback),
+ it->second->callback_runner);
+ pending_new_browser_info_map_.erase(it);
+ }
+
+ return browser_info;
+}
+
+bool CefBrowserInfoManager::CanCreateWindow(
+ content::RenderFrameHost* opener,
+ const GURL& target_url,
+ const content::Referrer& referrer,
+ const std::string& frame_name,
+ WindowOpenDisposition disposition,
+ const blink::mojom::WindowFeatures& features,
+ bool user_gesture,
+ bool opener_suppressed,
+ bool* no_javascript_access) {
+ CEF_REQUIRE_UIT();
+
+ content::OpenURLParams params(target_url, referrer, disposition,
+ ui::PAGE_TRANSITION_LINK,
+ /*is_renderer_initiated=*/true);
+ params.user_gesture = user_gesture;
+
+ CefRefPtr<CefBrowserHostBase> browser;
+ if (!MaybeAllowNavigation(opener, params, browser) || !browser) {
+ // Cancel the popup.
+ return false;
+ }
+
+ CefRefPtr<CefClient> client = browser->GetClient();
+ bool allow = true;
+ bool handled = false;
+
+ CefWindowInfo window_info;
+
+#if BUILDFLAG(IS_WIN)
+ window_info.SetAsPopup(nullptr, CefString());
+#endif
+
+ auto pending_popup = std::make_unique<CefBrowserInfoManager::PendingPopup>();
+ pending_popup->step = PendingPopup::CAN_CREATE_WINDOW;
+ pending_popup->opener_global_id = opener->GetGlobalId();
+ pending_popup->target_url = target_url;
+ pending_popup->target_frame_name = frame_name;
+
+ // Start with the current browser's settings.
+ pending_popup->client = client;
+ pending_popup->settings = browser->settings();
+
+ // With the Chrome runtime, we want to use default popup Browser creation
+ // for document picture-in-picture.
+ pending_popup->use_default_browser_creation =
+ disposition == WindowOpenDisposition::NEW_PICTURE_IN_PICTURE;
+
+ if (client.get()) {
+ CefRefPtr<CefLifeSpanHandler> handler = client->GetLifeSpanHandler();
+ if (handler.get()) {
+ CefRefPtr<CefFrame> opener_frame = browser->GetFrameForHost(opener);
+ DCHECK(opener_frame);
+
+ CefPopupFeatures cef_features;
+ TranslatePopupFeatures(features, cef_features);
+
+ // Default to the size from the popup features.
+ if (cef_features.xSet) {
+ window_info.bounds.x = cef_features.x;
+ }
+ if (cef_features.ySet) {
+ window_info.bounds.y = cef_features.y;
+ }
+ if (cef_features.widthSet) {
+ window_info.bounds.width = cef_features.width;
+ }
+ if (cef_features.heightSet) {
+ window_info.bounds.height = cef_features.height;
+ }
+
+ allow = !handler->OnBeforePopup(
+ browser.get(), opener_frame, pending_popup->target_url.spec(),
+ pending_popup->target_frame_name,
+ static_cast<cef_window_open_disposition_t>(disposition), user_gesture,
+ cef_features, window_info, pending_popup->client,
+ pending_popup->settings, pending_popup->extra_info,
+ no_javascript_access);
+ handled = true;
+ }
+ }
+
+ if (allow) {
+ CefBrowserCreateParams create_params;
+ create_params.MaybeSetWindowInfo(window_info);
+
+ if (!handled) {
+ // Use default Browser creation if OnBeforePopup was unhandled.
+ // TODO(chrome): Expose a mechanism for the client to choose default
+ // creation.
+ pending_popup->use_default_browser_creation = true;
+ }
+
+ // In most cases, Views-hosted browsers should create Views-hosted popups
+ // and native browsers should use default popup handling. With the Chrome
+ // runtime, we should additionally use default handling (a) when using an
+ // external parent and (b) when using default Browser creation.
+ create_params.popup_with_views_hosted_opener =
+ browser->HasView() &&
+ !browser->platform_delegate()->HasExternalParent() &&
+ !pending_popup->use_default_browser_creation;
+
+ create_params.settings = pending_popup->settings;
+ create_params.client = pending_popup->client;
+ create_params.extra_info = pending_popup->extra_info;
+
+ pending_popup->platform_delegate =
+ CefBrowserPlatformDelegate::Create(create_params);
+ CHECK(pending_popup->platform_delegate.get());
+
+ // Between the calls to CanCreateWindow and GetCustomWebContentsView
+ // RenderViewHostImpl::CreateNewWindow() will call
+ // RenderProcessHostImpl::FilterURL() which, in the case of "javascript:"
+ // URIs, rewrites the URL to "about:blank". We need to apply the same filter
+ // otherwise GetCustomWebContentsView will fail to retrieve the PopupInfo.
+ opener->GetProcess()->FilterURL(false, &pending_popup->target_url);
+
+ PushPendingPopup(std::move(pending_popup));
+ }
+
+ return allow;
+}
+
+void CefBrowserInfoManager::GetCustomWebContentsView(
+ const GURL& target_url,
+ const content::GlobalRenderFrameHostId& opener_global_id,
+ content::WebContentsView** view,
+ content::RenderViewHostDelegateView** delegate_view) {
+ CEF_REQUIRE_UIT();
+ REQUIRE_ALLOY_RUNTIME();
+
+ auto pending_popup = PopPendingPopup(PendingPopup::CAN_CREATE_WINDOW,
+ opener_global_id, target_url);
+ DCHECK(pending_popup.get());
+ DCHECK(pending_popup->platform_delegate.get());
+
+ if (pending_popup->platform_delegate->IsWindowless()) {
+ pending_popup->platform_delegate->CreateViewForWebContents(view,
+ delegate_view);
+ }
+
+ pending_popup->step = PendingPopup::GET_CUSTOM_WEB_CONTENTS_VIEW;
+ PushPendingPopup(std::move(pending_popup));
+}
+
+void CefBrowserInfoManager::WebContentsCreated(
+ const GURL& target_url,
+ const content::GlobalRenderFrameHostId& opener_global_id,
+ CefBrowserSettings& settings,
+ CefRefPtr<CefClient>& client,
+ std::unique_ptr<CefBrowserPlatformDelegate>& platform_delegate,
+ CefRefPtr<CefDictionaryValue>& extra_info,
+ content::WebContents* new_contents) {
+ CEF_REQUIRE_UIT();
+
+ // GET_CUSTOM_WEB_CONTENTS_VIEW is only used with the alloy runtime.
+ const auto previous_step = cef::IsAlloyRuntimeEnabled()
+ ? PendingPopup::GET_CUSTOM_WEB_CONTENTS_VIEW
+ : PendingPopup::CAN_CREATE_WINDOW;
+
+ auto pending_popup =
+ PopPendingPopup(previous_step, opener_global_id, target_url);
+ DCHECK(pending_popup.get());
+ DCHECK(pending_popup->platform_delegate.get());
+
+ settings = pending_popup->settings;
+ client = pending_popup->client;
+ platform_delegate = std::move(pending_popup->platform_delegate);
+ extra_info = pending_popup->extra_info;
+
+ // AddWebContents (the next step) is only used with the Chrome runtime.
+ if (cef::IsChromeRuntimeEnabled()) {
+ pending_popup->step = PendingPopup::WEB_CONTENTS_CREATED;
+ pending_popup->new_contents = new_contents;
+ PushPendingPopup(std::move(pending_popup));
+ }
+}
+
+bool CefBrowserInfoManager::AddWebContents(content::WebContents* new_contents) {
+ CEF_REQUIRE_UIT();
+ DCHECK(cef::IsChromeRuntimeEnabled());
+
+ // Pending popup information may be missing in cases where
+ // chrome::AddWebContents is called directly from the Chrome UI (profile
+ // settings, etc).
+ auto pending_popup =
+ PopPendingPopup(PendingPopup::WEB_CONTENTS_CREATED, new_contents);
+ if (pending_popup) {
+ return !pending_popup->use_default_browser_creation;
+ }
+
+ // Proceed with default handling.
+ return false;
+}
+
+void CefBrowserInfoManager::OnGetNewBrowserInfo(
+ const content::GlobalRenderFrameHostId& global_id,
+ cef::mojom::BrowserManager::GetNewBrowserInfoCallback callback) {
+ DCHECK(frame_util::IsValidGlobalId(global_id));
+ DCHECK(callback);
+
+ auto callback_runner = base::SequencedTaskRunner::GetCurrentDefault();
+
+ base::AutoLock lock_scope(browser_info_lock_);
+
+ bool is_guest_view = false;
+
+ scoped_refptr<CefBrowserInfo> browser_info =
+ GetBrowserInfoInternal(global_id, &is_guest_view);
+
+ if (browser_info) {
+ // Send the response immediately.
+ SendNewBrowserInfoResponse(browser_info, is_guest_view, std::move(callback),
+ callback_runner);
+ return;
+ }
+
+ // Verify that no request for the same route is currently queued.
+ DCHECK(pending_new_browser_info_map_.find(global_id) ==
+ pending_new_browser_info_map_.end());
+
+ const int timeout_id = ++next_timeout_id_;
+
+ // Queue the request.
+ std::unique_ptr<PendingNewBrowserInfo> pending(new PendingNewBrowserInfo());
+ pending->global_id = global_id;
+ pending->timeout_id = timeout_id;
+ pending->callback = std::move(callback);
+ pending->callback_runner = callback_runner;
+ pending_new_browser_info_map_.insert(
+ std::make_pair(global_id, std::move(pending)));
+
+ // Register a timeout for the pending response so that the renderer process
+ // doesn't hang forever. With the Chrome runtime, timeouts may occur in cases
+ // where chrome::AddWebContents or WebContents::Create are called directly
+ // from the Chrome UI (profile settings, etc).
+ if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableNewBrowserInfoTimeout)) {
+ CEF_POST_DELAYED_TASK(
+ CEF_UIT,
+ base::BindOnce(&CefBrowserInfoManager::TimeoutNewBrowserInfoResponse,
+ global_id, timeout_id),
+ kNewBrowserInfoResponseTimeoutMs);
+ }
+}
+
+void CefBrowserInfoManager::RemoveBrowserInfo(
+ scoped_refptr<CefBrowserInfo> browser_info) {
+ base::AutoLock lock_scope(browser_info_lock_);
+
+ BrowserInfoList::iterator it = browser_info_list_.begin();
+ for (; it != browser_info_list_.end(); ++it) {
+ if (*it == browser_info) {
+ browser_info_list_.erase(it);
+ return;
+ }
+ }
+
+ NOTREACHED();
+}
+
+void CefBrowserInfoManager::DestroyAllBrowsers() {
+ BrowserInfoList list;
+
+ {
+ base::AutoLock lock_scope(browser_info_lock_);
+ list = browser_info_list_;
+ }
+
+ // Destroy any remaining browser windows.
+ if (!list.empty()) {
+ BrowserInfoList::iterator it = list.begin();
+ for (; it != list.end(); ++it) {
+ CefRefPtr<CefBrowserHostBase> browser = (*it)->browser();
+ DCHECK(browser.get());
+ if (browser.get()) {
+ // DestroyBrowser will call RemoveBrowserInfo.
+ browser->DestroyBrowser();
+ }
+ }
+ }
+
+#if DCHECK_IS_ON()
+ {
+ // Verify that all browser windows have been destroyed.
+ base::AutoLock lock_scope(browser_info_lock_);
+ DCHECK(browser_info_list_.empty());
+ }
+#endif
+}
+
+scoped_refptr<CefBrowserInfo> CefBrowserInfoManager::GetBrowserInfo(
+ const content::GlobalRenderFrameHostId& global_id,
+ bool* is_guest_view) {
+ base::AutoLock lock_scope(browser_info_lock_);
+ return GetBrowserInfoInternal(global_id, is_guest_view);
+}
+
+bool CefBrowserInfoManager::MaybeAllowNavigation(
+ content::RenderFrameHost* opener,
+ const content::OpenURLParams& params,
+ CefRefPtr<CefBrowserHostBase>& browser_out) const {
+ CEF_REQUIRE_UIT();
+
+ bool is_guest_view = false;
+ auto browser = extensions::GetOwnerBrowserForHost(opener, &is_guest_view);
+ if (!browser) {
+ // Print preview uses a modal dialog where we don't own the WebContents.
+ // Allow that navigation to proceed.
+ return true;
+ }
+
+ if (!browser->MaybeAllowNavigation(opener, is_guest_view, params)) {
+ return false;
+ }
+
+ browser_out = browser;
+ return true;
+}
+
+CefBrowserInfoManager::BrowserInfoList
+CefBrowserInfoManager::GetBrowserInfoList() {
+ base::AutoLock lock_scope(browser_info_lock_);
+ BrowserInfoList copy;
+ copy.assign(browser_info_list_.begin(), browser_info_list_.end());
+ return copy;
+}
+
+void CefBrowserInfoManager::RenderProcessHostDestroyed(
+ content::RenderProcessHost* host) {
+ CEF_REQUIRE_UIT();
+
+ host->RemoveObserver(this);
+
+ const int render_process_id = host->GetID();
+ DCHECK_GT(render_process_id, 0);
+
+ // Remove all pending requests that reference the destroyed host.
+ {
+ base::AutoLock lock_scope(browser_info_lock_);
+
+ PendingNewBrowserInfoMap::iterator it =
+ pending_new_browser_info_map_.begin();
+ while (it != pending_new_browser_info_map_.end()) {
+ const auto& info = it->second;
+ if (info->global_id.child_id == render_process_id) {
+ CancelNewBrowserInfoResponse(info.get());
+ it = pending_new_browser_info_map_.erase(it);
+ } else {
+ ++it;
+ }
+ }
+ }
+
+ // Remove all pending popups that reference the destroyed host as the opener.
+ {
+ PendingPopupList::iterator it = pending_popup_list_.begin();
+ while (it != pending_popup_list_.end()) {
+ PendingPopup* popup = it->get();
+ if (popup->opener_global_id.child_id == render_process_id) {
+ it = pending_popup_list_.erase(it);
+ } else {
+ ++it;
+ }
+ }
+ }
+}
+
+void CefBrowserInfoManager::PushPendingPopup(
+ std::unique_ptr<PendingPopup> popup) {
+ CEF_REQUIRE_UIT();
+ pending_popup_list_.push_back(std::move(popup));
+}
+
+std::unique_ptr<CefBrowserInfoManager::PendingPopup>
+CefBrowserInfoManager::PopPendingPopup(
+ PendingPopup::Step previous_step,
+ const content::GlobalRenderFrameHostId& opener_global_id,
+ const GURL& target_url) {
+ CEF_REQUIRE_UIT();
+ DCHECK(frame_util::IsValidGlobalId(opener_global_id));
+ DCHECK_LE(previous_step, PendingPopup::GET_CUSTOM_WEB_CONTENTS_VIEW);
+
+ PendingPopupList::iterator it = pending_popup_list_.begin();
+ for (; it != pending_popup_list_.end(); ++it) {
+ PendingPopup* popup = it->get();
+ if (popup->step == previous_step &&
+ popup->opener_global_id == opener_global_id &&
+ popup->target_url == target_url) {
+ // Transfer ownership of the pointer.
+ it->release();
+ pending_popup_list_.erase(it);
+ return base::WrapUnique(popup);
+ }
+ }
+
+ return nullptr;
+}
+
+std::unique_ptr<CefBrowserInfoManager::PendingPopup>
+CefBrowserInfoManager::PopPendingPopup(PendingPopup::Step previous_step,
+ content::WebContents* new_contents) {
+ CEF_REQUIRE_UIT();
+ DCHECK_GE(previous_step, PendingPopup::WEB_CONTENTS_CREATED);
+
+ PendingPopupList::iterator it = pending_popup_list_.begin();
+ for (; it != pending_popup_list_.end(); ++it) {
+ PendingPopup* popup = it->get();
+ if (popup->step == previous_step && popup->new_contents == new_contents) {
+ // Transfer ownership of the pointer.
+ it->release();
+ pending_popup_list_.erase(it);
+ return base::WrapUnique(popup);
+ }
+ }
+
+ return nullptr;
+}
+
+scoped_refptr<CefBrowserInfo> CefBrowserInfoManager::GetBrowserInfoInternal(
+ const content::GlobalRenderFrameHostId& global_id,
+ bool* is_guest_view) {
+ browser_info_lock_.AssertAcquired();
+
+ if (is_guest_view) {
+ *is_guest_view = false;
+ }
+
+ if (!frame_util::IsValidGlobalId(global_id)) {
+ return nullptr;
+ }
+
+ for (const auto& browser_info : browser_info_list_) {
+ bool is_guest_view_tmp;
+ auto frame =
+ browser_info->GetFrameForGlobalId(global_id, &is_guest_view_tmp);
+ if (frame || is_guest_view_tmp) {
+ if (is_guest_view) {
+ *is_guest_view = is_guest_view_tmp;
+ }
+ return browser_info;
+ }
+ }
+
+ return nullptr;
+}
+
+// static
+void CefBrowserInfoManager::SendNewBrowserInfoResponse(
+ scoped_refptr<CefBrowserInfo> browser_info,
+ bool is_guest_view,
+ cef::mojom::BrowserManager::GetNewBrowserInfoCallback callback,
+ scoped_refptr<base::SequencedTaskRunner> callback_runner) {
+ if (!callback_runner->RunsTasksInCurrentSequence()) {
+ callback_runner->PostTask(
+ FROM_HERE,
+ base::BindOnce(&CefBrowserInfoManager::SendNewBrowserInfoResponse,
+ browser_info, is_guest_view, std::move(callback),
+ callback_runner));
+ return;
+ }
+
+ auto params = cef::mojom::NewBrowserInfo::New();
+ params->is_guest_view = is_guest_view;
+
+ if (browser_info) {
+ params->browser_id = browser_info->browser_id();
+ params->is_windowless = browser_info->is_windowless();
+ params->is_popup = browser_info->is_popup();
+
+ auto extra_info = browser_info->extra_info();
+ if (extra_info) {
+ auto extra_info_impl =
+ static_cast<CefDictionaryValueImpl*>(extra_info.get());
+ auto extra_info_value = extra_info_impl->CopyValue();
+ params->extra_info = std::move(extra_info_value.GetDict());
+ }
+ } else {
+ // The new browser info response has timed out.
+ params->browser_id = -1;
+ }
+
+ std::move(callback).Run(std::move(params));
+}
+
+// static
+void CefBrowserInfoManager::CancelNewBrowserInfoResponse(
+ PendingNewBrowserInfo* pending_info) {
+ SendNewBrowserInfoResponse(/*browser_info=*/nullptr, /*is_guest_view=*/false,
+ std::move(pending_info->callback),
+ pending_info->callback_runner);
+}
+
+// static
+void CefBrowserInfoManager::TimeoutNewBrowserInfoResponse(
+ const content::GlobalRenderFrameHostId& global_id,
+ int timeout_id) {
+ CEF_REQUIRE_UIT();
+ if (!g_info_manager) {
+ return;
+ }
+
+ base::AutoLock lock_scope(g_info_manager->browser_info_lock_);
+
+ // Continue the NewBrowserInfo request if it's still pending.
+ auto it = g_info_manager->pending_new_browser_info_map_.find(global_id);
+ if (it != g_info_manager->pending_new_browser_info_map_.end()) {
+ const auto& pending_info = it->second;
+ // Don't accidentally timeout a new request for the same frame.
+ if (pending_info->timeout_id != timeout_id) {
+ return;
+ }
+
+#if DCHECK_IS_ON()
+ // This method should never be called for a PDF renderer.
+ content::RenderProcessHost* process =
+ content::RenderProcessHost::FromID(global_id.child_id);
+ DCHECK(!process || !process->IsPdf());
+#endif
+
+ LOG(ERROR) << "Timeout of new browser info response for frame "
+ << frame_util::GetFrameDebugString(global_id);
+
+ CancelNewBrowserInfoResponse(pending_info.get());
+ g_info_manager->pending_new_browser_info_map_.erase(it);
+ }
+}
diff --git a/libcef/browser/browser_info_manager.h b/libcef/browser/browser_info_manager.h
new file mode 100644
index 00000000..bbe1f6a5
--- /dev/null
+++ b/libcef/browser/browser_info_manager.h
@@ -0,0 +1,263 @@
+// Copyright 2015 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_BROWSER_INFO_MANAGER_H_
+#define CEF_LIBCEF_BROWSER_BROWSER_INFO_MANAGER_H_
+#pragma once
+
+#include "include/cef_client.h"
+
+#include <list>
+#include <map>
+#include <memory>
+#include <vector>
+
+#include "libcef/browser/browser_info.h"
+
+#include "base/synchronization/lock.h"
+#include "base/task/sequenced_task_runner.h"
+#include "cef/libcef/common/mojom/cef.mojom.h"
+#include "content/public/browser/global_routing_id.h"
+#include "content/public/browser/render_process_host_observer.h"
+#include "third_party/blink/public/mojom/window_features/window_features.mojom.h"
+#include "ui/base/window_open_disposition.h"
+#include "url/gurl.h"
+
+namespace blink {
+struct WebWindowFeatures;
+}
+
+namespace content {
+struct OpenURLParams;
+struct Referrer;
+class RenderFrameHost;
+class RenderViewHostDelegateView;
+class WebContents;
+class WebContentsView;
+} // namespace content
+
+class CefBrowserHostBase;
+class CefBrowserPlatformDelegate;
+
+// Singleton object for managing BrowserInfo instances.
+class CefBrowserInfoManager : public content::RenderProcessHostObserver {
+ public:
+ CefBrowserInfoManager();
+
+ CefBrowserInfoManager(const CefBrowserInfoManager&) = delete;
+ CefBrowserInfoManager& operator=(const CefBrowserInfoManager&) = delete;
+
+ ~CefBrowserInfoManager() override;
+
+ // Returns this singleton instance of this class.
+ static CefBrowserInfoManager* GetInstance();
+
+ // Called immediately before a new CefBrowserHost implementation is created
+ // directly. In this case |is_popup| will be true only for DevTools browsers.
+ scoped_refptr<CefBrowserInfo> CreateBrowserInfo(
+ bool is_popup,
+ bool is_windowless,
+ CefRefPtr<CefDictionaryValue> extra_info);
+
+ // Called from WebContentsDelegate::WebContentsCreated when a new browser is
+ // being created for a traditional popup (e.g. window.open() or targeted
+ // link). If any OnGetNewBrowserInfo requests are pending for the popup the
+ // response will be sent when this method is called.
+ scoped_refptr<CefBrowserInfo> CreatePopupBrowserInfo(
+ content::WebContents* new_contents,
+ bool is_windowless,
+ CefRefPtr<CefDictionaryValue> extra_info);
+
+ // Called from ContentBrowserClient::CanCreateWindow. See comments on
+ // PendingPopup for more information.
+ bool CanCreateWindow(content::RenderFrameHost* opener,
+ const GURL& target_url,
+ const content::Referrer& referrer,
+ const std::string& frame_name,
+ WindowOpenDisposition disposition,
+ const blink::mojom::WindowFeatures& features,
+ bool user_gesture,
+ bool opener_suppressed,
+ bool* no_javascript_access);
+
+ // Called from WebContentsDelegate::GetCustomWebContentsView (alloy runtime
+ // only). See comments on PendingPopup for more information.
+ void GetCustomWebContentsView(
+ const GURL& target_url,
+ const content::GlobalRenderFrameHostId& opener_global_id,
+ content::WebContentsView** view,
+ content::RenderViewHostDelegateView** delegate_view);
+
+ // Called from WebContentsDelegate::WebContentsCreated. See comments on
+ // PendingPopup for more information.
+ void WebContentsCreated(
+ const GURL& target_url,
+ const content::GlobalRenderFrameHostId& opener_global_id,
+ CefBrowserSettings& settings,
+ CefRefPtr<CefClient>& client,
+ std::unique_ptr<CefBrowserPlatformDelegate>& platform_delegate,
+ CefRefPtr<CefDictionaryValue>& extra_info,
+ content::WebContents* new_contents);
+
+ // Called from ChromeBrowserDelegate::AddWebContents. See comments on
+ // PendingPopup for more information. Returns true for custom handling.
+ bool AddWebContents(content::WebContents* source_contents);
+
+ // Called from CefBrowserManager::GetNewBrowserInfo for delivering
+ // browser info to the renderer process. If the browser info already exists
+ // the response will be sent immediately. Otherwise, the response will be sent
+ // when CreatePopupBrowserInfo creates the browser info. The info will already
+ // exist for explicitly created browsers and guest views. It may sometimes
+ // already exist for traditional popup browsers depending on timing. See
+ // comments on PendingPopup for more information.
+ void OnGetNewBrowserInfo(
+ const content::GlobalRenderFrameHostId& global_id,
+ cef::mojom::BrowserManager::GetNewBrowserInfoCallback callback);
+
+ // Called from CefBrowserHostBase::DestroyBrowser() when a browser is
+ // destroyed.
+ void RemoveBrowserInfo(scoped_refptr<CefBrowserInfo> browser_info);
+
+ // Called from CefContext::FinishShutdownOnUIThread() to destroy all browsers.
+ void DestroyAllBrowsers();
+
+ // Returns the CefBrowserInfo matching the specified ID or nullptr if no
+ // match is found. It is allowed to add new callers of this method but
+ // consider using CefBrowserHostBase::GetBrowserForGlobalId() or
+ // extensions::GetOwnerBrowserForGlobalId() instead. If |is_guest_view| is
+ // non-nullptr it will be set to true if the ID matches a guest view
+ // associated with the returned browser info instead of the browser itself.
+ scoped_refptr<CefBrowserInfo> GetBrowserInfo(
+ const content::GlobalRenderFrameHostId& global_id,
+ bool* is_guest_view = nullptr);
+
+ // Returns all existing CefBrowserInfo objects.
+ using BrowserInfoList = std::list<scoped_refptr<CefBrowserInfo>>;
+ BrowserInfoList GetBrowserInfoList();
+
+ // Returns true if the navigation should be allowed to proceed, or false if
+ // the navigation will instead be sent via OpenURLFromTab. If allowed,
+ // |browser| will be set to the target browser if any.
+ bool MaybeAllowNavigation(content::RenderFrameHost* opener,
+ const content::OpenURLParams& params,
+ CefRefPtr<CefBrowserHostBase>& browser) const;
+
+ private:
+ // RenderProcessHostObserver methods:
+ void RenderProcessHostDestroyed(content::RenderProcessHost* host) override;
+
+ // Store state information about pending popups. Call order is:
+ // - CanCreateWindow (UIT):
+ // Provides an opportunity to cancel the popup (calls OnBeforePopup) and
+ // creates the new platform delegate for the popup. If the popup owner is
+ // an extension guest view then the popup is canceled and
+ // WebContentsDelegate::OpenURLFromTab is called via the
+ // CefBrowserHostBase::MaybeAllowNavigation implementation.
+ // And then the following calls may occur at the same time:
+ // - GetCustomWebContentsView (UIT) (alloy runtime only):
+ // Creates the OSR views for windowless popups.
+ // - WebContentsCreated (UIT):
+ // Creates the CefBrowserHost representation for the popup.
+ // - AddWebContents (UIT) (chrome runtime only):
+ // Creates the Browser or tab representation for the popup.
+ // - CefBrowserManager::GetNewBrowserInfo (IOT)
+ // Passes information about the popup to the renderer process.
+ struct PendingPopup {
+ // Track the last method that modified this PendingPopup instance. There may
+ // be multiple pending popups with the same identifiers and this allows us
+ // to differentiate between them at different processing steps.
+ enum Step {
+ CAN_CREATE_WINDOW,
+ GET_CUSTOM_WEB_CONTENTS_VIEW,
+ WEB_CONTENTS_CREATED,
+ } step;
+
+ // Initial state from ViewHostMsg_CreateWindow.
+ // |target_url| will be empty if a popup is created via window.open() and
+ // never navigated. For example: javascript:window.open();
+ content::GlobalRenderFrameHostId opener_global_id;
+ GURL target_url;
+ std::string target_frame_name;
+
+ // Values specified by OnBeforePopup.
+ CefBrowserSettings settings;
+ CefRefPtr<CefClient> client;
+ CefRefPtr<CefDictionaryValue> extra_info;
+
+ // Platform delegate specific to the new popup.
+ std::unique_ptr<CefBrowserPlatformDelegate> platform_delegate;
+
+ // True if default Browser or tab creation should proceed from
+ // AddWebContents (chrome runtime only).
+ bool use_default_browser_creation = false;
+
+ // The newly created WebContents (set in WebContentsCreated).
+ content::WebContents* new_contents = nullptr;
+ };
+
+ // Manage pending popups. Only called on the UI thread.
+ void PushPendingPopup(std::unique_ptr<PendingPopup> popup);
+
+ // Used after CanCreateWindow is called.
+ std::unique_ptr<PendingPopup> PopPendingPopup(
+ PendingPopup::Step previous_step,
+ const content::GlobalRenderFrameHostId& opener_global_id,
+ const GURL& target_url);
+
+ // Used after WebContentsCreated is called.
+ std::unique_ptr<PendingPopup> PopPendingPopup(
+ PendingPopup::Step previous_step,
+ content::WebContents* new_contents);
+
+ // Retrieves the BrowserInfo matching the specified ID.
+ scoped_refptr<CefBrowserInfo> GetBrowserInfoInternal(
+ const content::GlobalRenderFrameHostId& global_id,
+ bool* is_guest_view);
+
+ // Send the response for a pending OnGetNewBrowserInfo request.
+ static void SendNewBrowserInfoResponse(
+ scoped_refptr<CefBrowserInfo> browser_info,
+ bool is_guest_view,
+ cef::mojom::BrowserManager::GetNewBrowserInfoCallback callback,
+ scoped_refptr<base::SequencedTaskRunner> callback_runner);
+
+ // Pending request for OnGetNewBrowserInfo.
+ struct PendingNewBrowserInfo {
+ content::GlobalRenderFrameHostId global_id;
+ int timeout_id;
+ cef::mojom::BrowserManager::GetNewBrowserInfoCallback callback;
+ scoped_refptr<base::SequencedTaskRunner> callback_runner;
+ };
+
+ // Cancel a response that is still pending.
+ static void CancelNewBrowserInfoResponse(PendingNewBrowserInfo* pending_info);
+
+ // Time out a response if it's still pending.
+ static void TimeoutNewBrowserInfoResponse(
+ const content::GlobalRenderFrameHostId& global_id,
+ int timeout_id);
+
+ mutable base::Lock browser_info_lock_;
+
+ // Access to the below members must be protected by |browser_info_lock_|.
+
+ BrowserInfoList browser_info_list_;
+ int next_browser_id_ = 0;
+
+ // Map of global ID to info. These IDs are guaranteed to uniquely
+ // identify a RFH for its complete lifespan. See documentation on
+ // RenderFrameHost::GetFrameTreeNodeId() for background.
+ using PendingNewBrowserInfoMap =
+ std::map<content::GlobalRenderFrameHostId,
+ std::unique_ptr<PendingNewBrowserInfo>>;
+ PendingNewBrowserInfoMap pending_new_browser_info_map_;
+
+ // Only accessed on the UI thread.
+ using PendingPopupList = std::vector<std::unique_ptr<PendingPopup>>;
+ PendingPopupList pending_popup_list_;
+
+ int next_timeout_id_ = 0;
+};
+
+#endif // CEF_LIBCEF_BROWSER_BROWSER_INFO_H_
diff --git a/libcef/browser/browser_manager.cc b/libcef/browser/browser_manager.cc
new file mode 100644
index 00000000..8022e26b
--- /dev/null
+++ b/libcef/browser/browser_manager.cc
@@ -0,0 +1,58 @@
+// Copyright 2021 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/browser_manager.h"
+
+#include "libcef/browser/browser_info_manager.h"
+#include "libcef/browser/origin_whitelist_impl.h"
+#include "libcef/common/frame_util.h"
+
+#include "content/public/browser/render_process_host.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/self_owned_receiver.h"
+#include "services/service_manager/public/cpp/binder_registry.h"
+
+CefBrowserManager::CefBrowserManager(int render_process_id)
+ : render_process_id_(render_process_id) {}
+
+CefBrowserManager::~CefBrowserManager() = default;
+
+// static
+void CefBrowserManager::ExposeInterfacesToRenderer(
+ service_manager::BinderRegistry* registry,
+ blink::AssociatedInterfaceRegistry* associated_registry,
+ content::RenderProcessHost* host) {
+ registry->AddInterface<cef::mojom::BrowserManager>(base::BindRepeating(
+ [](int render_process_id,
+ mojo::PendingReceiver<cef::mojom::BrowserManager> receiver) {
+ mojo::MakeSelfOwnedReceiver(
+ std::make_unique<CefBrowserManager>(render_process_id),
+ std::move(receiver));
+ },
+ host->GetID()));
+}
+
+// static
+mojo::Remote<cef::mojom::RenderManager>
+CefBrowserManager::GetRenderManagerForProcess(
+ content::RenderProcessHost* host) {
+ mojo::Remote<cef::mojom::RenderManager> client;
+ host->BindReceiver(client.BindNewPipeAndPassReceiver());
+ return client;
+}
+
+void CefBrowserManager::GetNewRenderThreadInfo(
+ cef::mojom::BrowserManager::GetNewRenderThreadInfoCallback callback) {
+ auto info = cef::mojom::NewRenderThreadInfo::New();
+ GetCrossOriginWhitelistEntries(&info->cross_origin_whitelist_entries);
+ std::move(callback).Run(std::move(info));
+}
+
+void CefBrowserManager::GetNewBrowserInfo(
+ int32_t render_frame_routing_id,
+ cef::mojom::BrowserManager::GetNewBrowserInfoCallback callback) {
+ CefBrowserInfoManager::GetInstance()->OnGetNewBrowserInfo(
+ frame_util::MakeGlobalId(render_process_id_, render_frame_routing_id),
+ std::move(callback));
+}
diff --git a/libcef/browser/browser_manager.h b/libcef/browser/browser_manager.h
new file mode 100644
index 00000000..3087050e
--- /dev/null
+++ b/libcef/browser/browser_manager.h
@@ -0,0 +1,56 @@
+// Copyright 2021 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_BROWSER_MANAGER_H_
+#define CEF_LIBCEF_BROWSER_BROWSER_MANAGER_H_
+
+#include "cef/libcef/common/mojom/cef.mojom.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "services/service_manager/public/cpp/binder_registry.h"
+
+namespace blink {
+class AssociatedInterfaceRegistry;
+}
+
+namespace content {
+class RenderProcessHost;
+}
+
+class CefBrowserManager : public cef::mojom::BrowserManager {
+ public:
+ explicit CefBrowserManager(int render_process_id);
+
+ CefBrowserManager(const CefBrowserManager&) = delete;
+ CefBrowserManager& operator=(const CefBrowserManager&) = delete;
+
+ ~CefBrowserManager() override;
+
+ // Called from the ContentBrowserClient method of the same name.
+ // |associated_registry| is used for interfaces which must be associated with
+ // some IPC::ChannelProxy, meaning that messages on the interface retain FIFO
+ // with respect to legacy Chrome IPC messages sent or dispatched on the
+ // channel.
+ static void ExposeInterfacesToRenderer(
+ service_manager::BinderRegistry* registry,
+ blink::AssociatedInterfaceRegistry* associated_registry,
+ content::RenderProcessHost* host);
+
+ // Connects to CefRenderManager in the render process.
+ static mojo::Remote<cef::mojom::RenderManager> GetRenderManagerForProcess(
+ content::RenderProcessHost* host);
+
+ private:
+ // cef::mojom::BrowserManager methods:
+ void GetNewRenderThreadInfo(
+ cef::mojom::BrowserManager::GetNewRenderThreadInfoCallback callback)
+ override;
+ void GetNewBrowserInfo(
+ int32_t render_frame_routing_id,
+ cef::mojom::BrowserManager::GetNewBrowserInfoCallback callback) override;
+
+ // The process ID of the renderer.
+ const int render_process_id_;
+};
+
+#endif // CEF_LIBCEF_BROWSER_BROWSER_MANAGER_H_
diff --git a/libcef/browser/browser_message_loop.cc b/libcef/browser/browser_message_loop.cc
new file mode 100644
index 00000000..92d92487
--- /dev/null
+++ b/libcef/browser/browser_message_loop.cc
@@ -0,0 +1,128 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#include "libcef/browser/browser_message_loop.h"
+#include "libcef/common/app_manager.h"
+
+#include "base/memory/ptr_util.h"
+#include "base/message_loop/message_pump.h"
+#include "base/message_loop/message_pump_for_ui.h"
+
+#if BUILDFLAG(IS_MAC)
+#include "base/mac/scoped_nsautorelease_pool.h"
+#include "base/message_loop/message_pump_mac.h"
+#endif
+
+#include "content/public/browser/browser_thread.h"
+
+namespace {
+
+// MessagePump implementation that delegates to OnScheduleMessagePumpWork() for
+// scheduling.
+class MessagePumpExternal : public base::MessagePumpForUI {
+ public:
+ MessagePumpExternal(float max_time_slice,
+ CefRefPtr<CefBrowserProcessHandler> handler)
+ : max_time_slice_(max_time_slice), handler_(handler) {}
+
+ void Run(Delegate* delegate) override {
+ base::TimeTicks start = base::TimeTicks::Now();
+ while (true) {
+#if BUILDFLAG(IS_MAC)
+ base::mac::ScopedNSAutoreleasePool autorelease_pool;
+#endif
+
+ base::TimeTicks next_run_time; // is_null()
+ const bool has_more_work = DirectRunWork(delegate, &next_run_time);
+ if (!has_more_work) {
+ break;
+ }
+
+ if (next_run_time.is_null()) {
+ // We have more work that should run immediately.
+ next_run_time = base::TimeTicks::Now();
+ }
+
+ const base::TimeDelta& delta = next_run_time - start;
+ if (delta.InSecondsF() > max_time_slice_) {
+ break;
+ }
+ }
+ }
+
+ void Quit() override {}
+
+ void ScheduleWork() override { handler_->OnScheduleMessagePumpWork(0); }
+
+ void ScheduleDelayedWork(
+ const Delegate::NextWorkInfo& next_work_info) override {
+ const base::TimeDelta& delta =
+ next_work_info.delayed_run_time - next_work_info.recent_now;
+ handler_->OnScheduleMessagePumpWork(delta.InMilliseconds());
+ }
+
+ private:
+ static bool DirectRunWork(Delegate* delegate,
+ base::TimeTicks* next_run_time) {
+ bool more_immediate_work = false;
+ bool more_idle_work = false;
+ bool more_delayed_work = false;
+
+ Delegate::NextWorkInfo next_work_info = delegate->DoWork();
+
+ // is_immediate() returns true if the next task is ready right away.
+ more_immediate_work = next_work_info.is_immediate();
+ if (!more_immediate_work) {
+ // Check the next PendingTask's |delayed_run_time|.
+ // is_max() returns true if there are no more immediate nor delayed tasks.
+ more_delayed_work = !next_work_info.delayed_run_time.is_max();
+ if (more_delayed_work) {
+ // The only remaining work that we know about is the PendingTask.
+ // Consider the run time for that task in the time slice calculation.
+ *next_run_time = next_work_info.delayed_run_time;
+ }
+ }
+
+ if (!more_immediate_work && !more_delayed_work) {
+ // DoIdleWork() returns true if idle work was all done.
+ more_idle_work = !delegate->DoIdleWork();
+ }
+
+ return more_immediate_work || more_idle_work || more_delayed_work;
+ }
+
+ const float max_time_slice_;
+ CefRefPtr<CefBrowserProcessHandler> handler_;
+};
+
+CefRefPtr<CefBrowserProcessHandler> GetBrowserProcessHandler() {
+ CefRefPtr<CefApp> app = CefAppManager::Get()->GetApplication();
+ if (app) {
+ return app->GetBrowserProcessHandler();
+ }
+ return nullptr;
+}
+
+std::unique_ptr<base::MessagePump> MessagePumpFactoryForUI() {
+ if (!content::BrowserThread::IsThreadInitialized(
+ content::BrowserThread::UI) ||
+ content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) {
+ CefRefPtr<CefBrowserProcessHandler> handler = GetBrowserProcessHandler();
+ if (handler) {
+ return std::make_unique<MessagePumpExternal>(0.01f, handler);
+ }
+ }
+
+#if BUILDFLAG(IS_MAC)
+ return base::MessagePumpMac::Create();
+#else
+ return std::make_unique<base::MessagePumpForUI>();
+#endif
+}
+
+} // namespace
+
+void InitExternalMessagePumpFactoryForUI() {
+ base::MessagePump::OverrideMessagePumpForUIFactory(MessagePumpFactoryForUI);
+}
diff --git a/libcef/browser/browser_message_loop.h b/libcef/browser/browser_message_loop.h
new file mode 100644
index 00000000..38f2b025
--- /dev/null
+++ b/libcef/browser/browser_message_loop.h
@@ -0,0 +1,10 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_BROWSER_MESSAGE_LOOP_H_
+#define CEF_LIBCEF_BROWSER_BROWSER_MESSAGE_LOOP_H_
+
+void InitExternalMessagePumpFactoryForUI();
+
+#endif // CEF_LIBCEF_BROWSER_BROWSER_MESSAGE_LOOP_H_
diff --git a/libcef/browser/browser_platform_delegate.cc b/libcef/browser/browser_platform_delegate.cc
new file mode 100644
index 00000000..e503ef7b
--- /dev/null
+++ b/libcef/browser/browser_platform_delegate.cc
@@ -0,0 +1,454 @@
+// Copyright 2015 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/browser_platform_delegate.h"
+
+#include "libcef/browser/alloy/alloy_browser_host_impl.h"
+
+#include "base/logging.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
+#include "content/public/browser/render_widget_host_view.h"
+
+CefBrowserPlatformDelegate::CefBrowserPlatformDelegate() = default;
+
+CefBrowserPlatformDelegate::~CefBrowserPlatformDelegate() {
+ DCHECK(!browser_);
+}
+
+content::WebContents* CefBrowserPlatformDelegate::CreateWebContents(
+ CefBrowserCreateParams& create_params,
+ bool& own_web_contents) {
+ NOTREACHED();
+ return nullptr;
+}
+
+void CefBrowserPlatformDelegate::CreateViewForWebContents(
+ content::WebContentsView** view,
+ content::RenderViewHostDelegateView** delegate_view) {
+ NOTREACHED();
+}
+
+void CefBrowserPlatformDelegate::WebContentsCreated(
+ content::WebContents* web_contents,
+ bool owned) {
+ // We should not have a browser at this point.
+ DCHECK(!browser_);
+
+ DCHECK(!web_contents_);
+ web_contents_ = web_contents;
+}
+
+void CefBrowserPlatformDelegate::AddNewContents(
+ content::WebContents* source,
+ std::unique_ptr<content::WebContents> new_contents,
+ const GURL& target_url,
+ WindowOpenDisposition disposition,
+ const blink::mojom::WindowFeatures& window_features,
+ bool user_gesture,
+ bool* was_blocked) {
+ NOTREACHED();
+}
+
+void CefBrowserPlatformDelegate::WebContentsDestroyed(
+ content::WebContents* web_contents) {
+ DCHECK(web_contents_ && web_contents_ == web_contents);
+ web_contents_ = nullptr;
+}
+
+bool CefBrowserPlatformDelegate::
+ ShouldAllowRendererInitiatedCrossProcessNavigation(
+ bool is_main_frame_navigation) {
+ return true;
+}
+
+void CefBrowserPlatformDelegate::RenderViewCreated(
+ content::RenderViewHost* render_view_host) {
+ // Indicate that the view has an external parent (namely us). This setting is
+ // required for proper focus handling on Windows and Linux.
+ if (HasExternalParent() && render_view_host->GetWidget()->GetView()) {
+ render_view_host->GetWidget()->GetView()->SetHasExternalParent(true);
+ }
+}
+
+void CefBrowserPlatformDelegate::RenderViewReady() {}
+
+void CefBrowserPlatformDelegate::BrowserCreated(CefBrowserHostBase* browser) {
+ // We should have an associated WebContents at this point.
+ DCHECK(web_contents_);
+
+ DCHECK(!browser_);
+ DCHECK(browser);
+ browser_ = browser;
+}
+
+void CefBrowserPlatformDelegate::CreateExtensionHost(
+ const extensions::Extension* extension,
+ const GURL& url,
+ extensions::mojom::ViewType host_type) {
+ NOTREACHED();
+}
+
+extensions::ExtensionHost* CefBrowserPlatformDelegate::GetExtensionHost()
+ const {
+ NOTREACHED();
+ return nullptr;
+}
+
+void CefBrowserPlatformDelegate::NotifyBrowserCreated() {}
+
+void CefBrowserPlatformDelegate::NotifyBrowserDestroyed() {}
+
+void CefBrowserPlatformDelegate::BrowserDestroyed(CefBrowserHostBase* browser) {
+ // WebContentsDestroyed should already be called.
+ DCHECK(!web_contents_);
+
+ DCHECK(browser_ && browser_ == browser);
+ browser_ = nullptr;
+}
+
+bool CefBrowserPlatformDelegate::CreateHostWindow() {
+ NOTREACHED();
+ return true;
+}
+
+void CefBrowserPlatformDelegate::CloseHostWindow() {
+ NOTREACHED();
+}
+
+CefWindowHandle CefBrowserPlatformDelegate::GetHostWindowHandle() const {
+ NOTREACHED();
+ return kNullWindowHandle;
+}
+
+views::Widget* CefBrowserPlatformDelegate::GetWindowWidget() const {
+ NOTREACHED();
+ return nullptr;
+}
+
+CefRefPtr<CefBrowserView> CefBrowserPlatformDelegate::GetBrowserView() const {
+ NOTREACHED();
+ return nullptr;
+}
+
+web_modal::WebContentsModalDialogHost*
+CefBrowserPlatformDelegate::GetWebContentsModalDialogHost() const {
+ NOTREACHED();
+ return nullptr;
+}
+
+void CefBrowserPlatformDelegate::PopupWebContentsCreated(
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefClient> client,
+ content::WebContents* new_web_contents,
+ CefBrowserPlatformDelegate* new_platform_delegate,
+ bool is_devtools) {}
+
+void CefBrowserPlatformDelegate::PopupBrowserCreated(
+ CefBrowserHostBase* new_browser,
+ bool is_devtools) {}
+
+SkColor CefBrowserPlatformDelegate::GetBackgroundColor() const {
+ NOTREACHED();
+ return SkColor();
+}
+
+void CefBrowserPlatformDelegate::WasResized() {
+ NOTREACHED();
+}
+
+void CefBrowserPlatformDelegate::SendKeyEvent(const CefKeyEvent& event) {
+ NOTIMPLEMENTED();
+}
+
+void CefBrowserPlatformDelegate::SendMouseClickEvent(
+ const CefMouseEvent& event,
+ CefBrowserHost::MouseButtonType type,
+ bool mouseUp,
+ int clickCount) {
+ NOTIMPLEMENTED();
+}
+
+void CefBrowserPlatformDelegate::SendMouseMoveEvent(const CefMouseEvent& event,
+ bool mouseLeave) {
+ NOTIMPLEMENTED();
+}
+
+void CefBrowserPlatformDelegate::SendMouseWheelEvent(const CefMouseEvent& event,
+ int deltaX,
+ int deltaY) {
+ NOTIMPLEMENTED();
+}
+
+void CefBrowserPlatformDelegate::SendTouchEvent(const CefTouchEvent& event) {
+ NOTIMPLEMENTED();
+}
+
+void CefBrowserPlatformDelegate::SetFocus(bool setFocus) {}
+
+void CefBrowserPlatformDelegate::SendCaptureLostEvent() {
+ NOTIMPLEMENTED();
+}
+
+#if BUILDFLAG(IS_WIN) || (BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC))
+void CefBrowserPlatformDelegate::NotifyMoveOrResizeStarted() {}
+
+void CefBrowserPlatformDelegate::SizeTo(int width, int height) {}
+#endif
+
+gfx::Point CefBrowserPlatformDelegate::GetScreenPoint(
+ const gfx::Point& view,
+ bool want_dip_coords) const {
+ NOTREACHED();
+ return gfx::Point();
+}
+
+void CefBrowserPlatformDelegate::ViewText(const std::string& text) {
+ NOTIMPLEMENTED();
+}
+
+bool CefBrowserPlatformDelegate::HandleKeyboardEvent(
+ const content::NativeWebKeyboardEvent& event) {
+ NOTREACHED();
+ return false;
+}
+
+bool CefBrowserPlatformDelegate::PreHandleGestureEvent(
+ content::WebContents* source,
+ const blink::WebGestureEvent& event) {
+ return false;
+}
+
+bool CefBrowserPlatformDelegate::IsNeverComposited(
+ content::WebContents* web_contents) {
+ return false;
+}
+
+CefEventHandle CefBrowserPlatformDelegate::GetEventHandle(
+ const content::NativeWebKeyboardEvent& event) const {
+ NOTREACHED();
+ return kNullEventHandle;
+}
+
+std::unique_ptr<CefJavaScriptDialogRunner>
+CefBrowserPlatformDelegate::CreateJavaScriptDialogRunner() {
+ return nullptr;
+}
+
+std::unique_ptr<CefMenuRunner> CefBrowserPlatformDelegate::CreateMenuRunner() {
+ NOTIMPLEMENTED();
+ return nullptr;
+}
+
+bool CefBrowserPlatformDelegate::IsWindowless() const {
+ return false;
+}
+
+bool CefBrowserPlatformDelegate::IsViewsHosted() const {
+ return false;
+}
+
+bool CefBrowserPlatformDelegate::HasExternalParent() const {
+ // In the majority of cases a Views-hosted browser will not have an external
+ // parent, and visa-versa.
+ return !IsViewsHosted();
+}
+
+void CefBrowserPlatformDelegate::WasHidden(bool hidden) {
+ NOTREACHED();
+}
+
+bool CefBrowserPlatformDelegate::IsHidden() const {
+ NOTREACHED();
+ return false;
+}
+
+void CefBrowserPlatformDelegate::NotifyScreenInfoChanged() {
+ NOTREACHED();
+}
+
+void CefBrowserPlatformDelegate::Invalidate(cef_paint_element_type_t type) {
+ NOTREACHED();
+}
+
+void CefBrowserPlatformDelegate::SendExternalBeginFrame() {
+ NOTREACHED();
+}
+
+void CefBrowserPlatformDelegate::SetWindowlessFrameRate(int frame_rate) {
+ NOTREACHED();
+}
+
+void CefBrowserPlatformDelegate::ImeSetComposition(
+ const CefString& text,
+ const std::vector<CefCompositionUnderline>& underlines,
+ const CefRange& replacement_range,
+ const CefRange& selection_range) {
+ NOTREACHED();
+}
+
+void CefBrowserPlatformDelegate::ImeCommitText(
+ const CefString& text,
+ const CefRange& replacement_range,
+ int relative_cursor_pos) {
+ NOTREACHED();
+}
+
+void CefBrowserPlatformDelegate::ImeFinishComposingText(bool keep_selection) {
+ NOTREACHED();
+}
+
+void CefBrowserPlatformDelegate::ImeCancelComposition() {
+ NOTREACHED();
+}
+
+void CefBrowserPlatformDelegate::DragTargetDragEnter(
+ CefRefPtr<CefDragData> drag_data,
+ const CefMouseEvent& event,
+ cef_drag_operations_mask_t allowed_ops) {
+ NOTREACHED();
+}
+
+void CefBrowserPlatformDelegate::DragTargetDragOver(
+ const CefMouseEvent& event,
+ cef_drag_operations_mask_t allowed_ops) {
+ NOTREACHED();
+}
+
+void CefBrowserPlatformDelegate::DragTargetDragLeave() {
+ NOTREACHED();
+}
+
+void CefBrowserPlatformDelegate::DragTargetDrop(const CefMouseEvent& event) {
+ NOTREACHED();
+}
+
+void CefBrowserPlatformDelegate::StartDragging(
+ const content::DropData& drop_data,
+ blink::DragOperationsMask allowed_ops,
+ const gfx::ImageSkia& image,
+ const gfx::Vector2d& image_offset,
+ const blink::mojom::DragEventSourceInfo& event_info,
+ content::RenderWidgetHostImpl* source_rwh) {
+ NOTREACHED();
+}
+
+void CefBrowserPlatformDelegate::UpdateDragCursor(
+ ui::mojom::DragOperation operation) {
+ NOTREACHED();
+}
+
+void CefBrowserPlatformDelegate::DragSourceEndedAt(
+ int x,
+ int y,
+ cef_drag_operations_mask_t op) {
+ NOTREACHED();
+}
+
+void CefBrowserPlatformDelegate::DragSourceSystemDragEnded() {
+ NOTREACHED();
+}
+
+void CefBrowserPlatformDelegate::AccessibilityEventReceived(
+ const content::AXEventNotificationDetails& eventData) {
+ NOTREACHED();
+}
+
+void CefBrowserPlatformDelegate::AccessibilityLocationChangesReceived(
+ const std::vector<content::AXLocationChangeNotificationDetails>& locData) {
+ NOTREACHED();
+}
+
+gfx::Point CefBrowserPlatformDelegate::GetDialogPosition(
+ const gfx::Size& size) {
+ const gfx::Size& max_size = GetMaximumDialogSize();
+ return gfx::Point((max_size.width() - size.width()) / 2,
+ (max_size.height() - size.height()) / 2);
+}
+
+gfx::Size CefBrowserPlatformDelegate::GetMaximumDialogSize() {
+ if (!web_contents_) {
+ return gfx::Size();
+ }
+
+ // The dialog should try to fit within the overlay for the web contents.
+ // Note that, for things like print preview, this is just a suggested maximum.
+ return web_contents_->GetContainerBounds().size();
+}
+
+void CefBrowserPlatformDelegate::SetAutoResizeEnabled(bool enabled,
+ const CefSize& min_size,
+ const CefSize& max_size) {
+ NOTIMPLEMENTED();
+}
+
+void CefBrowserPlatformDelegate::SetAccessibilityState(
+ cef_state_t accessibility_state) {
+ NOTIMPLEMENTED();
+}
+
+bool CefBrowserPlatformDelegate::IsPrintPreviewSupported() const {
+ return true;
+}
+
+void CefBrowserPlatformDelegate::Find(const CefString& searchText,
+ bool forward,
+ bool matchCase,
+ bool findNext) {
+ NOTIMPLEMENTED();
+}
+
+void CefBrowserPlatformDelegate::StopFinding(bool clearSelection) {
+ NOTIMPLEMENTED();
+}
+
+// static
+int CefBrowserPlatformDelegate::TranslateWebEventModifiers(
+ uint32 cef_modifiers) {
+ int result = 0;
+ // Set modifiers based on key state.
+ if (cef_modifiers & EVENTFLAG_CAPS_LOCK_ON) {
+ result |= blink::WebInputEvent::kCapsLockOn;
+ }
+ if (cef_modifiers & EVENTFLAG_SHIFT_DOWN) {
+ result |= blink::WebInputEvent::kShiftKey;
+ }
+ if (cef_modifiers & EVENTFLAG_CONTROL_DOWN) {
+ result |= blink::WebInputEvent::kControlKey;
+ }
+ if (cef_modifiers & EVENTFLAG_ALT_DOWN) {
+ result |= blink::WebInputEvent::kAltKey;
+ }
+ if (cef_modifiers & EVENTFLAG_LEFT_MOUSE_BUTTON) {
+ result |= blink::WebInputEvent::kLeftButtonDown;
+ }
+ if (cef_modifiers & EVENTFLAG_MIDDLE_MOUSE_BUTTON) {
+ result |= blink::WebInputEvent::kMiddleButtonDown;
+ }
+ if (cef_modifiers & EVENTFLAG_RIGHT_MOUSE_BUTTON) {
+ result |= blink::WebInputEvent::kRightButtonDown;
+ }
+ if (cef_modifiers & EVENTFLAG_COMMAND_DOWN) {
+ result |= blink::WebInputEvent::kMetaKey;
+ }
+ if (cef_modifiers & EVENTFLAG_NUM_LOCK_ON) {
+ result |= blink::WebInputEvent::kNumLockOn;
+ }
+ if (cef_modifiers & EVENTFLAG_IS_KEY_PAD) {
+ result |= blink::WebInputEvent::kIsKeyPad;
+ }
+ if (cef_modifiers & EVENTFLAG_IS_LEFT) {
+ result |= blink::WebInputEvent::kIsLeft;
+ }
+ if (cef_modifiers & EVENTFLAG_IS_RIGHT) {
+ result |= blink::WebInputEvent::kIsRight;
+ }
+ if (cef_modifiers & EVENTFLAG_ALTGR_DOWN) {
+ result |= blink::WebInputEvent::kAltGrKey;
+ }
+ if (cef_modifiers & EVENTFLAG_IS_REPEAT) {
+ result |= blink::WebInputEvent::kIsAutoRepeat;
+ }
+ return result;
+}
diff --git a/libcef/browser/browser_platform_delegate.h b/libcef/browser/browser_platform_delegate.h
new file mode 100644
index 00000000..af271a4a
--- /dev/null
+++ b/libcef/browser/browser_platform_delegate.h
@@ -0,0 +1,386 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors.
+// Portions copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_BROWSER_PLATFORM_DELEGATE_H_
+#define CEF_LIBCEF_BROWSER_BROWSER_PLATFORM_DELEGATE_H_
+
+#include <string>
+#include <vector>
+
+#include "include/cef_client.h"
+#include "include/cef_drag_data.h"
+#include "include/internal/cef_types.h"
+#include "include/views/cef_browser_view.h"
+
+#include "base/functional/callback_forward.h"
+#include "extensions/common/mojom/view_type.mojom-forward.h"
+#include "third_party/blink/public/common/page/drag_operation.h"
+#include "third_party/blink/public/mojom/drag/drag.mojom-forward.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "ui/base/dragdrop/mojom/drag_drop_types.mojom-forward.h"
+#include "ui/base/window_open_disposition.h"
+
+class GURL;
+
+namespace blink {
+class WebGestureEvent;
+class WebMouseEvent;
+class WebMouseWheelEvent;
+class WebInputEvent;
+class WebTouchEvent;
+
+namespace mojom {
+class WindowFeatures;
+}
+} // namespace blink
+
+namespace content {
+struct AXEventNotificationDetails;
+struct AXLocationChangeNotificationDetails;
+struct DropData;
+struct NativeWebKeyboardEvent;
+class RenderViewHost;
+class RenderViewHostDelegateView;
+class RenderWidgetHostImpl;
+class WebContents;
+class WebContentsView;
+} // namespace content
+
+namespace extensions {
+class Extension;
+class ExtensionHost;
+} // namespace extensions
+
+namespace gfx {
+class ImageSkia;
+class Point;
+class Rect;
+class Size;
+class Vector2d;
+} // namespace gfx
+
+namespace views {
+class Widget;
+}
+
+namespace web_modal {
+class WebContentsModalDialogHost;
+}
+
+struct CefBrowserCreateParams;
+class CefBrowserHostBase;
+class CefJavaScriptDialogRunner;
+class CefMenuRunner;
+
+// Provides platform-specific implementations of browser functionality. All
+// methods are called on the browser process UI thread unless otherwise
+// indicated.
+class CefBrowserPlatformDelegate {
+ public:
+ CefBrowserPlatformDelegate(const CefBrowserPlatformDelegate&) = delete;
+ CefBrowserPlatformDelegate& operator=(const CefBrowserPlatformDelegate&) =
+ delete;
+
+ // Create a new CefBrowserPlatformDelegate instance. May be called on multiple
+ // threads.
+ static std::unique_ptr<CefBrowserPlatformDelegate> Create(
+ const CefBrowserCreateParams& create_params);
+
+ // Called from AlloyBrowserHostImpl::Create.
+ // Wait for the call to WebContentsCreated(owned=true) before taking ownership
+ // of the resulting WebContents object.
+ virtual content::WebContents* CreateWebContents(
+ CefBrowserCreateParams& create_params,
+ bool& own_web_contents);
+
+ // Called to create the view objects for a new WebContents. Will only be
+ // called a single time per instance. May be called on multiple threads. Only
+ // used with windowless rendering.
+ virtual void CreateViewForWebContents(
+ content::WebContentsView** view,
+ content::RenderViewHostDelegateView** delegate_view);
+
+ // Called after the WebContents for a browser has been created. |owned| will
+ // be true if |web_contents| was created via CreateWebContents() and we should
+ // take ownership. This will also be called for popup WebContents created
+ // indirectly by Chromium. Will only be called a single time per instance.
+ virtual void WebContentsCreated(content::WebContents* web_contents,
+ bool owned);
+
+ // Called when Chromium is ready to hand over ownership of a popup
+ // WebContents. WebContentsCreated(owned=false) will be called first for
+ // |new_contents|. Will only be called a single time per instance. See also
+ // the WebContentsDelegate documentation.
+ virtual void AddNewContents(
+ content::WebContents* source,
+ std::unique_ptr<content::WebContents> new_contents,
+ const GURL& target_url,
+ WindowOpenDisposition disposition,
+ const blink::mojom::WindowFeatures& window_features,
+ bool user_gesture,
+ bool* was_blocked);
+
+ // Called when the WebContents is destroyed. This will be called before
+ // BrowserDestroyed(). Will only be called a single time per instance.
+ virtual void WebContentsDestroyed(content::WebContents* web_contents);
+
+ // See WebContentsDelegate documentation.
+ virtual bool ShouldAllowRendererInitiatedCrossProcessNavigation(
+ bool is_main_frame_navigation);
+
+ // Called after the RenderViewHost is created.
+ virtual void RenderViewCreated(content::RenderViewHost* render_view_host);
+
+ // See WebContentsObserver documentation.
+ virtual void RenderViewReady();
+
+ // Called after the owning AlloyBrowserHostImpl is created. Will only be
+ // called a single time per instance. Do not send any client notifications
+ // from this method.
+ virtual void BrowserCreated(CefBrowserHostBase* browser);
+
+ // Called from AlloyBrowserHostImpl::Create.
+ virtual void CreateExtensionHost(const extensions::Extension* extension,
+ const GURL& url,
+ extensions::mojom::ViewType host_type);
+
+ // Returns the current extension host.
+ virtual extensions::ExtensionHost* GetExtensionHost() const;
+
+ // Send any notifications related to browser creation. Called after
+ // BrowserCreated().
+ virtual void NotifyBrowserCreated();
+
+ // Send any notifications related to browser destruction. Called before
+ // BrowserDestroyed().
+ virtual void NotifyBrowserDestroyed();
+
+ // Called before the owning AlloyBrowserHostImpl is destroyed. Will only be
+ // called a single time per instance. All references to the
+ // AlloyBrowserHostImpl and WebContents should be cleared when this method is
+ // called. Do not send any client notifications from this method.
+ virtual void BrowserDestroyed(CefBrowserHostBase* browser);
+
+ // Create the window that hosts the browser. Will only be called a single time
+ // per instance. Only used with windowed rendering.
+ virtual bool CreateHostWindow();
+
+ // Sends a message to close the window that hosts the browser. On native
+ // platforms this will be done via the OS. DestroyBrowser will be called after
+ // the native window has closed. Only used with windowed rendering.
+ virtual void CloseHostWindow();
+
+ // Return the OS handle for the window that hosts the browser. For windowed
+ // rendering this will return the most immediate parent window handle. For
+ // windowless rendering this will return the parent window handle specified by
+ // the client, which may be NULL. May be called on multiple threads.
+ virtual CefWindowHandle GetHostWindowHandle() const;
+
+ // Returns the Widget owner for the browser window. Only used with windowed
+ // rendering.
+ virtual views::Widget* GetWindowWidget() const;
+
+ // Returns the BrowserView associated with this browser. Only used with views-
+ // based browsers.
+ virtual CefRefPtr<CefBrowserView> GetBrowserView() const;
+
+ // Returns the WebContentsModalDialogHost associated with this browser.
+ virtual web_modal::WebContentsModalDialogHost* GetWebContentsModalDialogHost()
+ const;
+
+ // Called after the WebContents have been created for a new popup browser
+ // parented to this browser but before the AlloyBrowserHostImpl is created for
+ // the popup. |is_devtools| will be true if the popup will host DevTools. This
+ // method will be called before WebContentsCreated() is called on
+ // |new_platform_delegate|. Do not make the new browser visible in this
+ // callback.
+ virtual void PopupWebContentsCreated(
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefClient> client,
+ content::WebContents* new_web_contents,
+ CefBrowserPlatformDelegate* new_platform_delegate,
+ bool is_devtools);
+
+ // Called after the AlloyBrowserHostImpl is created for a new popup browser
+ // parented to this browser. |is_devtools| will be true if the popup will host
+ // DevTools. This method will be called immediately after
+ // CefLifeSpanHandler::OnAfterCreated() for the popup browser. It is safe to
+ // make the new browser visible in this callback (for example, add the browser
+ // to a window and show it).
+ virtual void PopupBrowserCreated(CefBrowserHostBase* new_browser,
+ bool is_devtools);
+
+ // Returns the background color for the browser. The alpha component will be
+ // either SK_AlphaTRANSPARENT or SK_AlphaOPAQUE (e.g. fully transparent or
+ // fully opaque). SK_AlphaOPAQUE will always be returned for windowed
+ // browsers. SK_ColorTRANSPARENT may be returned for windowless browsers to
+ // enable transparency.
+ virtual SkColor GetBackgroundColor() const;
+
+ // Notify the window that it was resized.
+ virtual void WasResized();
+
+ // Send input events.
+ virtual void SendKeyEvent(const CefKeyEvent& event);
+ virtual void SendMouseClickEvent(const CefMouseEvent& event,
+ CefBrowserHost::MouseButtonType type,
+ bool mouseUp,
+ int clickCount);
+ virtual void SendMouseMoveEvent(const CefMouseEvent& event, bool mouseLeave);
+ virtual void SendMouseWheelEvent(const CefMouseEvent& event,
+ int deltaX,
+ int deltaY);
+ virtual void SendTouchEvent(const CefTouchEvent& event);
+
+ // Send focus event. The browser's WebContents may be NULL when this method is
+ // called.
+ virtual void SetFocus(bool setFocus);
+
+ // Send capture lost event.
+ virtual void SendCaptureLostEvent();
+
+#if BUILDFLAG(IS_WIN) || (BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC))
+ // The window hosting the browser is about to be moved or resized. Only used
+ // on Windows and Linux.
+ virtual void NotifyMoveOrResizeStarted();
+
+ // Resize the host window to the given dimensions. Only used with windowed
+ // rendering on Windows and Linux.
+ virtual void SizeTo(int width, int height);
+#endif
+
+ // Convert from view DIP coordinates to screen coordinates. If
+ // |want_dip_coords| is true return DIP instead of device (pixel) coordinates
+ // on Windows/Linux.
+ virtual gfx::Point GetScreenPoint(const gfx::Point& view,
+ bool want_dip_coords) const;
+
+ // Open the specified text in the default text editor.
+ virtual void ViewText(const std::string& text);
+
+ // Forward the keyboard event to the application or frame window to allow
+ // processing of shortcut keys.
+ virtual bool HandleKeyboardEvent(
+ const content::NativeWebKeyboardEvent& event);
+
+ // See WebContentsDelegate documentation.
+ virtual bool PreHandleGestureEvent(content::WebContents* source,
+ const blink::WebGestureEvent& event);
+
+ // See WebContentsDelegate documentation.
+ virtual bool IsNeverComposited(content::WebContents* web_contents);
+
+ // Invoke platform specific handling for the external protocol.
+ static void HandleExternalProtocol(const GURL& url);
+
+ // Returns the OS event handle, if any, associated with |event|.
+ virtual CefEventHandle GetEventHandle(
+ const content::NativeWebKeyboardEvent& event) const;
+
+ // Create the platform-specific JavaScript dialog runner.
+ virtual std::unique_ptr<CefJavaScriptDialogRunner>
+ CreateJavaScriptDialogRunner();
+
+ // Create the platform-specific menu runner.
+ virtual std::unique_ptr<CefMenuRunner> CreateMenuRunner();
+
+ // Returns true if this delegate implements windowless rendering. May be
+ // called on multiple threads.
+ virtual bool IsWindowless() const;
+
+ // Returns true if this delegate implements views-hosted browser handling. May
+ // be called on multiple threads.
+ virtual bool IsViewsHosted() const;
+
+ // Returns true if this delegate implements a browser with external
+ // (client-provided) parent window. May be called on multiple threads.
+ virtual bool HasExternalParent() const;
+
+ // Notify the browser that it was hidden. Only used with windowless rendering.
+ virtual void WasHidden(bool hidden);
+
+ // Returns true if the browser is currently hidden. Only used with windowless
+ // rendering.
+ virtual bool IsHidden() const;
+
+ // Notify the browser that screen information has changed. Only used with
+ // windowless rendering.
+ virtual void NotifyScreenInfoChanged();
+
+ // Invalidate the view. Only used with windowless rendering.
+ virtual void Invalidate(cef_paint_element_type_t type);
+
+ // Send the external begin frame message. Only used with windowless rendering.
+ virtual void SendExternalBeginFrame();
+
+ // Set the windowless frame rate. Only used with windowless rendering.
+ virtual void SetWindowlessFrameRate(int frame_rate);
+
+ // IME-related callbacks. See documentation in CefBrowser and
+ // CefRenderHandler. Only used with windowless rendering.
+ virtual void ImeSetComposition(
+ const CefString& text,
+ const std::vector<CefCompositionUnderline>& underlines,
+ const CefRange& replacement_range,
+ const CefRange& selection_range);
+ virtual void ImeCommitText(const CefString& text,
+ const CefRange& replacement_range,
+ int relative_cursor_pos);
+ virtual void ImeFinishComposingText(bool keep_selection);
+ virtual void ImeCancelComposition();
+
+ // Drag/drop-related callbacks. See documentation in CefRenderHandler. Only
+ // used with windowless rendering.
+ virtual void DragTargetDragEnter(CefRefPtr<CefDragData> drag_data,
+ const CefMouseEvent& event,
+ cef_drag_operations_mask_t allowed_ops);
+ virtual void DragTargetDragOver(const CefMouseEvent& event,
+ cef_drag_operations_mask_t allowed_ops);
+ virtual void DragTargetDragLeave();
+ virtual void DragTargetDrop(const CefMouseEvent& event);
+ virtual void StartDragging(
+ const content::DropData& drop_data,
+ blink::DragOperationsMask allowed_ops,
+ const gfx::ImageSkia& image,
+ const gfx::Vector2d& image_offset,
+ const blink::mojom::DragEventSourceInfo& event_info,
+ content::RenderWidgetHostImpl* source_rwh);
+ virtual void UpdateDragCursor(ui::mojom::DragOperation operation);
+ virtual void DragSourceEndedAt(int x, int y, cef_drag_operations_mask_t op);
+ virtual void DragSourceSystemDragEnded();
+ virtual void AccessibilityEventReceived(
+ const content::AXEventNotificationDetails& eventData);
+ virtual void AccessibilityLocationChangesReceived(
+ const std::vector<content::AXLocationChangeNotificationDetails>& locData);
+ virtual gfx::Point GetDialogPosition(const gfx::Size& size);
+ virtual gfx::Size GetMaximumDialogSize();
+
+ // See CefBrowserHost documentation.
+ virtual void SetAutoResizeEnabled(bool enabled,
+ const CefSize& min_size,
+ const CefSize& max_size);
+ virtual void SetAccessibilityState(cef_state_t accessibility_state);
+ virtual bool IsPrintPreviewSupported() const;
+ virtual void Find(const CefString& searchText,
+ bool forward,
+ bool matchCase,
+ bool findNext);
+ virtual void StopFinding(bool clearSelection);
+
+ protected:
+ // Allow deletion via std::unique_ptr only.
+ friend std::default_delete<CefBrowserPlatformDelegate>;
+
+ CefBrowserPlatformDelegate();
+ virtual ~CefBrowserPlatformDelegate();
+
+ static int TranslateWebEventModifiers(uint32 cef_modifiers);
+
+ // Not owned by this object.
+ content::WebContents* web_contents_ = nullptr;
+ CefBrowserHostBase* browser_ = nullptr;
+};
+
+#endif // CEF_LIBCEF_BROWSER_BROWSER_PLATFORM_DELEGATE_H_
diff --git a/libcef/browser/browser_platform_delegate_create.cc b/libcef/browser/browser_platform_delegate_create.cc
new file mode 100644
index 00000000..291b1563
--- /dev/null
+++ b/libcef/browser/browser_platform_delegate_create.cc
@@ -0,0 +1,143 @@
+// Copyright 2015 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/browser_platform_delegate.h"
+
+#include <utility>
+
+#include "libcef/browser/context.h"
+
+#include "base/memory/ptr_util.h"
+#include "build/build_config.h"
+
+#include "libcef/browser/browser_host_base.h"
+#include "libcef/browser/chrome/browser_platform_delegate_chrome.h"
+#include "libcef/browser/chrome/views/browser_platform_delegate_chrome_child_window.h"
+#include "libcef/browser/chrome/views/browser_platform_delegate_chrome_views.h"
+#include "libcef/browser/chrome/views/chrome_child_window.h"
+#include "libcef/browser/extensions/browser_platform_delegate_background.h"
+#include "libcef/browser/views/browser_platform_delegate_views.h"
+#include "libcef/features/runtime_checks.h"
+
+#if BUILDFLAG(IS_WIN)
+#include "libcef/browser/native/browser_platform_delegate_native_win.h"
+#include "libcef/browser/osr/browser_platform_delegate_osr_win.h"
+#elif BUILDFLAG(IS_MAC)
+#include "libcef/browser/native/browser_platform_delegate_native_mac.h"
+#include "libcef/browser/osr/browser_platform_delegate_osr_mac.h"
+#elif BUILDFLAG(IS_LINUX)
+#include "libcef/browser/native/browser_platform_delegate_native_linux.h"
+#include "libcef/browser/osr/browser_platform_delegate_osr_linux.h"
+#else
+#error A delegate implementation is not available for your platform.
+#endif
+
+namespace {
+
+std::unique_ptr<CefBrowserPlatformDelegateNative> CreateNativeDelegate(
+ const CefWindowInfo& window_info,
+ SkColor background_color) {
+#if BUILDFLAG(IS_WIN)
+ return std::make_unique<CefBrowserPlatformDelegateNativeWin>(
+ window_info, background_color);
+#elif BUILDFLAG(IS_MAC)
+ return std::make_unique<CefBrowserPlatformDelegateNativeMac>(
+ window_info, background_color);
+#elif BUILDFLAG(IS_LINUX)
+ return std::make_unique<CefBrowserPlatformDelegateNativeLinux>(
+ window_info, background_color);
+#endif
+}
+
+std::unique_ptr<CefBrowserPlatformDelegateOsr> CreateOSRDelegate(
+ std::unique_ptr<CefBrowserPlatformDelegateNative> native_delegate,
+ bool use_shared_texture,
+ bool use_external_begin_frame) {
+#if BUILDFLAG(IS_WIN)
+ return std::make_unique<CefBrowserPlatformDelegateOsrWin>(
+ std::move(native_delegate), use_shared_texture, use_external_begin_frame);
+#elif BUILDFLAG(IS_MAC)
+ return std::make_unique<CefBrowserPlatformDelegateOsrMac>(
+ std::move(native_delegate));
+#elif BUILDFLAG(IS_LINUX)
+ return std::make_unique<CefBrowserPlatformDelegateOsrLinux>(
+ std::move(native_delegate), use_external_begin_frame);
+#endif
+}
+
+} // namespace
+
+// static
+std::unique_ptr<CefBrowserPlatformDelegate> CefBrowserPlatformDelegate::Create(
+ const CefBrowserCreateParams& create_params) {
+ const bool is_windowless =
+ create_params.window_info &&
+ create_params.window_info->windowless_rendering_enabled &&
+ create_params.client && create_params.client->GetRenderHandler().get();
+ const SkColor background_color = CefContext::Get()->GetBackgroundColor(
+ &create_params.settings, is_windowless ? STATE_ENABLED : STATE_DISABLED);
+
+ if (cef::IsChromeRuntimeEnabled()) {
+ CefWindowInfo window_info;
+ if (create_params.window_info) {
+ window_info = *create_params.window_info;
+ }
+
+ std::unique_ptr<CefBrowserPlatformDelegateNative> native_delegate =
+ CreateNativeDelegate(window_info, background_color);
+
+ if (create_params.window_info) {
+ // CefWindowInfo should only be set if a parent handle was specified.
+ DCHECK(chrome_child_window::HasParentHandle(window_info));
+ return std::make_unique<CefBrowserPlatformDelegateChromeChildWindow>(
+ std::move(native_delegate),
+ static_cast<CefBrowserViewImpl*>(create_params.browser_view.get()));
+ } else if (create_params.browser_view ||
+ create_params.popup_with_views_hosted_opener) {
+ // CefWindowInfo is not used in this case.
+ return std::make_unique<CefBrowserPlatformDelegateChromeViews>(
+ std::move(native_delegate),
+ static_cast<CefBrowserViewImpl*>(create_params.browser_view.get()));
+ }
+
+ return std::make_unique<CefBrowserPlatformDelegateChrome>(
+ std::move(native_delegate));
+ }
+
+ if (create_params.browser_view ||
+ create_params.popup_with_views_hosted_opener) {
+ // CefWindowInfo is not used in this case.
+ std::unique_ptr<CefBrowserPlatformDelegateNative> native_delegate =
+ CreateNativeDelegate(CefWindowInfo(), background_color);
+ return std::make_unique<CefBrowserPlatformDelegateViews>(
+ std::move(native_delegate),
+ static_cast<CefBrowserViewImpl*>(create_params.browser_view.get()));
+ } else if (create_params.extension_host_type ==
+ extensions::mojom::ViewType::kExtensionBackgroundPage) {
+ // Creating a background extension host without a window.
+ std::unique_ptr<CefBrowserPlatformDelegateNative> native_delegate =
+ CreateNativeDelegate(CefWindowInfo(), background_color);
+ return std::make_unique<CefBrowserPlatformDelegateBackground>(
+ std::move(native_delegate));
+ } else if (create_params.window_info) {
+ std::unique_ptr<CefBrowserPlatformDelegateNative> native_delegate =
+ CreateNativeDelegate(*create_params.window_info, background_color);
+ if (is_windowless) {
+ REQUIRE_ALLOY_RUNTIME();
+
+ const bool use_shared_texture =
+ create_params.window_info->shared_texture_enabled;
+
+ const bool use_external_begin_frame =
+ create_params.window_info->external_begin_frame_enabled;
+
+ return CreateOSRDelegate(std::move(native_delegate), use_shared_texture,
+ use_external_begin_frame);
+ }
+ return std::move(native_delegate);
+ }
+
+ NOTREACHED();
+ return nullptr;
+}
diff --git a/libcef/browser/browser_util.cc b/libcef/browser/browser_util.cc
new file mode 100644
index 00000000..e7bddaf6
--- /dev/null
+++ b/libcef/browser/browser_util.cc
@@ -0,0 +1,73 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#include "libcef/browser/browser_util.h"
+
+#include "content/public/browser/native_web_keyboard_event.h"
+
+namespace browser_util {
+
+bool GetCefKeyEvent(const content::NativeWebKeyboardEvent& event,
+ CefKeyEvent& cef_event) {
+ switch (event.GetType()) {
+ case blink::WebKeyboardEvent::Type::kRawKeyDown:
+ cef_event.type = KEYEVENT_RAWKEYDOWN;
+ break;
+ case blink::WebKeyboardEvent::Type::kKeyDown:
+ cef_event.type = KEYEVENT_KEYDOWN;
+ break;
+ case blink::WebKeyboardEvent::Type::kKeyUp:
+ cef_event.type = KEYEVENT_KEYUP;
+ break;
+ case blink::WebKeyboardEvent::Type::kChar:
+ cef_event.type = KEYEVENT_CHAR;
+ break;
+ default:
+ return false;
+ }
+
+ cef_event.modifiers = 0;
+ if (event.GetModifiers() & blink::WebKeyboardEvent::kShiftKey) {
+ cef_event.modifiers |= EVENTFLAG_SHIFT_DOWN;
+ }
+ if (event.GetModifiers() & blink::WebKeyboardEvent::kControlKey) {
+ cef_event.modifiers |= EVENTFLAG_CONTROL_DOWN;
+ }
+ if (event.GetModifiers() & blink::WebKeyboardEvent::kAltKey) {
+ cef_event.modifiers |= EVENTFLAG_ALT_DOWN;
+ }
+ if (event.GetModifiers() & blink::WebKeyboardEvent::kMetaKey) {
+ cef_event.modifiers |= EVENTFLAG_COMMAND_DOWN;
+ }
+ if (event.GetModifiers() & blink::WebKeyboardEvent::kIsKeyPad) {
+ cef_event.modifiers |= EVENTFLAG_IS_KEY_PAD;
+ }
+ if (event.GetModifiers() & blink::WebKeyboardEvent::kIsLeft) {
+ cef_event.modifiers |= EVENTFLAG_IS_LEFT;
+ }
+ if (event.GetModifiers() & blink::WebKeyboardEvent::kIsRight) {
+ cef_event.modifiers |= EVENTFLAG_IS_RIGHT;
+ }
+ if (event.GetModifiers() & blink::WebKeyboardEvent::kAltGrKey) {
+ cef_event.modifiers |= EVENTFLAG_ALTGR_DOWN;
+ }
+ if (event.GetModifiers() & blink::WebKeyboardEvent::kIsAutoRepeat) {
+ cef_event.modifiers |= EVENTFLAG_IS_REPEAT;
+ }
+
+ cef_event.windows_key_code = event.windows_key_code;
+ cef_event.native_key_code = event.native_key_code;
+ cef_event.is_system_key = event.is_system_key;
+ cef_event.character = event.text[0];
+ cef_event.unmodified_character = event.unmodified_text[0];
+
+ return true;
+}
+
+bool GetCefKeyEvent(const ui::KeyEvent& event, CefKeyEvent& cef_event) {
+ content::NativeWebKeyboardEvent native_event(event);
+ return GetCefKeyEvent(native_event, cef_event);
+}
+
+} // namespace browser_util
diff --git a/libcef/browser/browser_util.h b/libcef/browser/browser_util.h
new file mode 100644
index 00000000..74c36f14
--- /dev/null
+++ b/libcef/browser/browser_util.h
@@ -0,0 +1,30 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_BROWSER_UTIL_H_
+#define CEF_LIBCEF_BROWSER_BROWSER_UTIL_H_
+#pragma once
+
+#include "include/internal/cef_types_wrappers.h"
+
+namespace content {
+struct NativeWebKeyboardEvent;
+}
+
+namespace ui {
+class KeyEvent;
+}
+
+namespace browser_util {
+
+// Convert a content::NativeWebKeyboardEvent to a CefKeyEvent.
+bool GetCefKeyEvent(const content::NativeWebKeyboardEvent& event,
+ CefKeyEvent& cef_event);
+
+// Convert a ui::KeyEvent to a CefKeyEvent.
+bool GetCefKeyEvent(const ui::KeyEvent& event, CefKeyEvent& cef_event);
+
+} // namespace browser_util
+
+#endif // CEF_LIBCEF_BROWSER_BROWSER_UTIL_H_
diff --git a/libcef/browser/certificate_query.cc b/libcef/browser/certificate_query.cc
new file mode 100644
index 00000000..ca787984
--- /dev/null
+++ b/libcef/browser/certificate_query.cc
@@ -0,0 +1,130 @@
+// Copyright 2022 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#include "libcef/browser/certificate_query.h"
+
+#include "include/cef_request_handler.h"
+#include "libcef/browser/browser_host_base.h"
+#include "libcef/browser/ssl_info_impl.h"
+#include "libcef/browser/thread_util.h"
+
+#include "base/functional/callback.h"
+#include "base/functional/callback_helpers.h"
+#include "base/logging.h"
+#include "content/public/browser/web_contents.h"
+#include "net/ssl/ssl_info.h"
+#include "url/gurl.h"
+
+namespace certificate_query {
+
+namespace {
+
+class CefAllowCertificateErrorCallbackImpl : public CefCallback {
+ public:
+ using CallbackType = CertificateErrorCallback;
+
+ explicit CefAllowCertificateErrorCallbackImpl(CallbackType callback)
+ : callback_(std::move(callback)) {}
+
+ CefAllowCertificateErrorCallbackImpl(
+ const CefAllowCertificateErrorCallbackImpl&) = delete;
+ CefAllowCertificateErrorCallbackImpl& operator=(
+ const CefAllowCertificateErrorCallbackImpl&) = delete;
+
+ ~CefAllowCertificateErrorCallbackImpl() {
+ if (!callback_.is_null()) {
+ // The callback is still pending. Cancel it now.
+ if (CEF_CURRENTLY_ON_UIT()) {
+ RunNow(std::move(callback_), false);
+ } else {
+ CEF_POST_TASK(
+ CEF_UIT,
+ base::BindOnce(&CefAllowCertificateErrorCallbackImpl::RunNow,
+ std::move(callback_), false));
+ }
+ }
+ }
+
+ void Continue() override { ContinueNow(true); }
+
+ void Cancel() override { ContinueNow(false); }
+
+ [[nodiscard]] CallbackType Disconnect() { return std::move(callback_); }
+
+ private:
+ void ContinueNow(bool allow) {
+ if (CEF_CURRENTLY_ON_UIT()) {
+ if (!callback_.is_null()) {
+ RunNow(std::move(callback_), allow);
+ }
+ } else {
+ CEF_POST_TASK(
+ CEF_UIT,
+ base::BindOnce(&CefAllowCertificateErrorCallbackImpl::ContinueNow,
+ this, allow));
+ }
+ }
+
+ static void RunNow(CallbackType callback, bool allow) {
+ CEF_REQUIRE_UIT();
+ std::move(callback).Run(
+ allow ? content::CERTIFICATE_REQUEST_RESULT_TYPE_CONTINUE
+ : content::CERTIFICATE_REQUEST_RESULT_TYPE_DENY);
+ }
+
+ CallbackType callback_;
+
+ IMPLEMENT_REFCOUNTING(CefAllowCertificateErrorCallbackImpl);
+};
+
+} // namespace
+
+CertificateErrorCallback AllowCertificateError(
+ content::WebContents* web_contents,
+ int cert_error,
+ const net::SSLInfo& ssl_info,
+ const GURL& request_url,
+ bool is_main_frame_request,
+ bool strict_enforcement,
+ CertificateErrorCallback callback,
+ bool default_disallow) {
+ CEF_REQUIRE_UIT();
+
+ if (!is_main_frame_request) {
+ // A sub-resource has a certificate error. The user doesn't really
+ // have a context for making the right decision, so block the request
+ // hard.
+ std::move(callback).Run(content::CERTIFICATE_REQUEST_RESULT_TYPE_DENY);
+ return base::NullCallback();
+ }
+
+ if (auto browser = CefBrowserHostBase::GetBrowserForContents(web_contents)) {
+ if (auto client = browser->GetClient()) {
+ if (auto handler = client->GetRequestHandler()) {
+ CefRefPtr<CefSSLInfo> sslInfo(new CefSSLInfoImpl(ssl_info));
+ CefRefPtr<CefAllowCertificateErrorCallbackImpl> callbackImpl(
+ new CefAllowCertificateErrorCallbackImpl(std::move(callback)));
+
+ bool proceed = handler->OnCertificateError(
+ browser.get(), static_cast<cef_errorcode_t>(cert_error),
+ request_url.spec(), sslInfo, callbackImpl.get());
+ if (!proceed) {
+ callback = callbackImpl->Disconnect();
+ LOG_IF(ERROR, callback.is_null())
+ << "Should return true from OnCertificateError when executing "
+ "the callback";
+ }
+ }
+ }
+ }
+
+ if (!callback.is_null() && default_disallow) {
+ std::move(callback).Run(content::CERTIFICATE_REQUEST_RESULT_TYPE_DENY);
+ return base::NullCallback();
+ }
+
+ return callback;
+}
+
+} // namespace certificate_query
diff --git a/libcef/browser/certificate_query.h b/libcef/browser/certificate_query.h
new file mode 100644
index 00000000..f2e6b531
--- /dev/null
+++ b/libcef/browser/certificate_query.h
@@ -0,0 +1,42 @@
+// Copyright 2022 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_CERTIFICATE_QUERY_H_
+#define CEF_LIBCEF_BROWSER_CERTIFICATE_QUERY_H_
+#pragma once
+
+#include "base/functional/callback_forward.h"
+#include "content/public/browser/certificate_request_result_type.h"
+
+namespace content {
+class WebContents;
+}
+
+namespace net {
+class SSLInfo;
+}
+
+class GURL;
+
+namespace certificate_query {
+
+using CertificateErrorCallback =
+ base::OnceCallback<void(content::CertificateRequestResultType)>;
+
+// Called from ContentBrowserClient::AllowCertificateError.
+// |callback| will be returned if the request is unhandled and
+// |default_disallow| is false.
+[[nodiscard]] CertificateErrorCallback AllowCertificateError(
+ content::WebContents* web_contents,
+ int cert_error,
+ const net::SSLInfo& ssl_info,
+ const GURL& request_url,
+ bool is_main_frame_request,
+ bool strict_enforcement,
+ CertificateErrorCallback callback,
+ bool default_disallow);
+
+} // namespace certificate_query
+
+#endif // CEF_LIBCEF_BROWSER_CERTIFICATE_QUERY_H_
diff --git a/libcef/browser/chrome/browser_delegate.h b/libcef/browser/chrome/browser_delegate.h
new file mode 100644
index 00000000..0a1df458
--- /dev/null
+++ b/libcef/browser/chrome/browser_delegate.h
@@ -0,0 +1,80 @@
+// Copyright 2020 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_CHROME_BROWSER_DELEGATE_H_
+#define CEF_LIBCEF_BROWSER_CHROME_BROWSER_DELEGATE_H_
+#pragma once
+
+#include <memory>
+
+#include "base/memory/scoped_refptr.h"
+#include "content/public/browser/web_contents_delegate.h"
+#include "ui/base/window_open_disposition.h"
+
+class Browser;
+
+namespace cef {
+
+// Delegate for the chrome Browser object. Lifespan is controlled by the Browser
+// object. See the ChromeBrowserDelegate documentation for additional details.
+// Only accessed on the UI thread.
+class BrowserDelegate : public content::WebContentsDelegate {
+ public:
+ // Opaque ref-counted base class for CEF-specific parameters passed via
+ // Browser::CreateParams::cef_params and possibly shared by multiple Browser
+ // instances.
+ class CreateParams : public base::RefCounted<CreateParams> {
+ public:
+ virtual ~CreateParams() {}
+ };
+
+ // Called from the Browser constructor to create a new delegate.
+ static std::unique_ptr<BrowserDelegate> Create(
+ Browser* browser,
+ scoped_refptr<CreateParams> cef_params);
+
+ ~BrowserDelegate() override {}
+
+ // Optionally override chrome::AddWebContents behavior. This is most often
+ // called via Browser::AddNewContents for new popup browsers and provides an
+ // opportunity for CEF to create a new Browser instead of proceeding with
+ // default Browser or tab creation.
+ virtual std::unique_ptr<content::WebContents> AddWebContents(
+ std::unique_ptr<content::WebContents> new_contents) = 0;
+
+ // Called immediately after |new_contents| is created via chrome::Navigate.
+ // This is most often called for navigations targeting a new tab without a
+ // pre-existing WebContents.
+ virtual void OnWebContentsCreated(content::WebContents* new_contents) = 0;
+
+ // Add or remove ownership of the WebContents.
+ virtual void SetAsDelegate(content::WebContents* web_contents,
+ bool set_delegate) = 0;
+
+ // Return true to show the status bubble. This should consistently return the
+ // same value for the lifespan of a Browser.
+ virtual bool ShowStatusBubble(bool show_by_default) {
+ return show_by_default;
+ }
+
+ // Return true to handle (or disable) a command. ID values come from
+ // chrome/app/chrome_command_ids.h.
+ virtual bool HandleCommand(int command_id,
+ WindowOpenDisposition disposition) {
+ return false;
+ }
+
+ // Same as RequestMediaAccessPermission but returning |callback| if the
+ // request is unhandled.
+ [[nodiscard]] virtual content::MediaResponseCallback
+ RequestMediaAccessPermissionEx(content::WebContents* web_contents,
+ const content::MediaStreamRequest& request,
+ content::MediaResponseCallback callback) {
+ return callback;
+ }
+};
+
+} // namespace cef
+
+#endif // CEF_LIBCEF_BROWSER_CHROME_BROWSER_DELEGATE_H_
diff --git a/libcef/browser/chrome/browser_platform_delegate_chrome.cc b/libcef/browser/chrome/browser_platform_delegate_chrome.cc
new file mode 100644
index 00000000..e53eb4ee
--- /dev/null
+++ b/libcef/browser/chrome/browser_platform_delegate_chrome.cc
@@ -0,0 +1,148 @@
+// Copyright 2020 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/chrome/browser_platform_delegate_chrome.h"
+
+#include "libcef/browser/views/view_util.h"
+
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/chrome_web_modal_dialog_manager_delegate.h"
+#include "chrome/common/pref_names.h"
+#include "ui/display/display.h"
+#include "ui/display/screen.h"
+#include "ui/gfx/geometry/point.h"
+
+CefBrowserPlatformDelegateChrome::CefBrowserPlatformDelegateChrome(
+ std::unique_ptr<CefBrowserPlatformDelegateNative> native_delegate)
+ : native_delegate_(std::move(native_delegate)) {
+ native_delegate_->set_windowless_handler(this);
+}
+
+void CefBrowserPlatformDelegateChrome::WebContentsCreated(
+ content::WebContents* web_contents,
+ bool owned) {
+ CefBrowserPlatformDelegate::WebContentsCreated(web_contents, owned);
+ native_delegate_->WebContentsCreated(web_contents, /*owned=*/false);
+}
+
+void CefBrowserPlatformDelegateChrome::WebContentsDestroyed(
+ content::WebContents* web_contents) {
+ CefBrowserPlatformDelegate::WebContentsDestroyed(web_contents);
+ native_delegate_->WebContentsDestroyed(web_contents);
+}
+
+void CefBrowserPlatformDelegateChrome::BrowserCreated(
+ CefBrowserHostBase* browser) {
+ CefBrowserPlatformDelegate::BrowserCreated(browser);
+ native_delegate_->BrowserCreated(browser);
+}
+
+void CefBrowserPlatformDelegateChrome::BrowserDestroyed(
+ CefBrowserHostBase* browser) {
+ CefBrowserPlatformDelegate::BrowserDestroyed(browser);
+ native_delegate_->BrowserDestroyed(browser);
+}
+
+CefWindowHandle CefBrowserPlatformDelegateChrome::GetHostWindowHandle() const {
+ return view_util::GetWindowHandle(GetNativeWindow());
+}
+
+web_modal::WebContentsModalDialogHost*
+CefBrowserPlatformDelegateChrome::GetWebContentsModalDialogHost() const {
+ if (chrome_browser_) {
+ ChromeWebModalDialogManagerDelegate* manager = chrome_browser_;
+ return manager->GetWebContentsModalDialogHost();
+ }
+ NOTREACHED();
+ return nullptr;
+}
+
+SkColor CefBrowserPlatformDelegateChrome::GetBackgroundColor() const {
+ return native_delegate_->GetBackgroundColor();
+}
+
+void CefBrowserPlatformDelegateChrome::SendKeyEvent(const CefKeyEvent& event) {
+ native_delegate_->SendKeyEvent(event);
+}
+
+void CefBrowserPlatformDelegateChrome::SendMouseClickEvent(
+ const CefMouseEvent& event,
+ CefBrowserHost::MouseButtonType type,
+ bool mouseUp,
+ int clickCount) {
+ native_delegate_->SendMouseClickEvent(event, type, mouseUp, clickCount);
+}
+
+void CefBrowserPlatformDelegateChrome::SendMouseMoveEvent(
+ const CefMouseEvent& event,
+ bool mouseLeave) {
+ native_delegate_->SendMouseMoveEvent(event, mouseLeave);
+}
+
+void CefBrowserPlatformDelegateChrome::SendMouseWheelEvent(
+ const CefMouseEvent& event,
+ int deltaX,
+ int deltaY) {
+ native_delegate_->SendMouseWheelEvent(event, deltaX, deltaY);
+}
+
+gfx::Point CefBrowserPlatformDelegateChrome::GetScreenPoint(
+ const gfx::Point& view,
+ bool want_dip_coords) const {
+ auto screen = display::Screen::GetScreen();
+
+ // Get device (pixel) coordinates.
+ auto screen_rect = screen->DIPToScreenRectInWindow(
+ GetNativeWindow(), gfx::Rect(view, gfx::Size(0, 0)));
+ auto screen_point = screen_rect.origin();
+
+ if (want_dip_coords) {
+ // Convert to DIP coordinates.
+ const auto& display = view_util::GetDisplayNearestPoint(
+ screen_point, /*input_pixel_coords=*/true);
+ view_util::ConvertPointFromPixels(&screen_point,
+ display.device_scale_factor());
+ }
+
+ return screen_point;
+}
+
+void CefBrowserPlatformDelegateChrome::ViewText(const std::string& text) {
+ native_delegate_->ViewText(text);
+}
+
+CefEventHandle CefBrowserPlatformDelegateChrome::GetEventHandle(
+ const content::NativeWebKeyboardEvent& event) const {
+ return native_delegate_->GetEventHandle(event);
+}
+
+bool CefBrowserPlatformDelegateChrome::IsPrintPreviewSupported() const {
+ return chrome_browser_ && !chrome_browser_->profile()->GetPrefs()->GetBoolean(
+ prefs::kPrintPreviewDisabled);
+}
+
+CefWindowHandle CefBrowserPlatformDelegateChrome::GetParentWindowHandle()
+ const {
+ return GetHostWindowHandle();
+}
+
+gfx::Point CefBrowserPlatformDelegateChrome::GetParentScreenPoint(
+ const gfx::Point& view,
+ bool want_dip_coords) const {
+ return GetScreenPoint(view, want_dip_coords);
+}
+
+void CefBrowserPlatformDelegateChrome::set_chrome_browser(Browser* browser) {
+ chrome_browser_ = browser;
+}
+
+gfx::NativeWindow CefBrowserPlatformDelegateChrome::GetNativeWindow() const {
+ if (chrome_browser_ && chrome_browser_->window()) {
+ return chrome_browser_->window()->GetNativeWindow();
+ }
+ NOTREACHED();
+ return gfx::NativeWindow();
+}
diff --git a/libcef/browser/chrome/browser_platform_delegate_chrome.h b/libcef/browser/chrome/browser_platform_delegate_chrome.h
new file mode 100644
index 00000000..4f13aced
--- /dev/null
+++ b/libcef/browser/chrome/browser_platform_delegate_chrome.h
@@ -0,0 +1,66 @@
+// Copyright 2020 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_CHROME_BROWSER_PLATFORM_DELEGATE_CHROME_H_
+#define CEF_LIBCEF_BROWSER_CHROME_BROWSER_PLATFORM_DELEGATE_CHROME_H_
+
+#include "libcef/browser/browser_platform_delegate.h"
+#include "libcef/browser/native/browser_platform_delegate_native.h"
+
+class Browser;
+
+// Implementation of Chrome-based browser functionality.
+class CefBrowserPlatformDelegateChrome
+ : public CefBrowserPlatformDelegate,
+ public CefBrowserPlatformDelegateNative::WindowlessHandler {
+ public:
+ explicit CefBrowserPlatformDelegateChrome(
+ std::unique_ptr<CefBrowserPlatformDelegateNative> native_delegate);
+
+ // CefBrowserPlatformDelegate overrides.
+ void WebContentsCreated(content::WebContents* web_contents,
+ bool owned) override;
+ void WebContentsDestroyed(content::WebContents* web_contents) override;
+ void BrowserCreated(CefBrowserHostBase* browser) override;
+ void BrowserDestroyed(CefBrowserHostBase* browser) override;
+ CefWindowHandle GetHostWindowHandle() const override;
+ web_modal::WebContentsModalDialogHost* GetWebContentsModalDialogHost()
+ const override;
+ SkColor GetBackgroundColor() const override;
+ void SendKeyEvent(const CefKeyEvent& event) override;
+ void SendMouseClickEvent(const CefMouseEvent& event,
+ CefBrowserHost::MouseButtonType type,
+ bool mouseUp,
+ int clickCount) override;
+ void SendMouseMoveEvent(const CefMouseEvent& event, bool mouseLeave) override;
+ void SendMouseWheelEvent(const CefMouseEvent& event,
+ int deltaX,
+ int deltaY) override;
+ gfx::Point GetScreenPoint(const gfx::Point& view,
+ bool want_dip_coords) const override;
+ void ViewText(const std::string& text) override;
+ CefEventHandle GetEventHandle(
+ const content::NativeWebKeyboardEvent& event) const override;
+ bool IsPrintPreviewSupported() const override;
+
+ // CefBrowserPlatformDelegateNative::WindowlessHandler methods:
+ CefWindowHandle GetParentWindowHandle() const override;
+ gfx::Point GetParentScreenPoint(const gfx::Point& view,
+ bool want_dip_coords) const override;
+
+ void set_chrome_browser(Browser* browser);
+
+ CefBrowserPlatformDelegateNative* native_delegate() const {
+ return native_delegate_.get();
+ }
+
+ protected:
+ gfx::NativeWindow GetNativeWindow() const;
+
+ std::unique_ptr<CefBrowserPlatformDelegateNative> native_delegate_;
+
+ Browser* chrome_browser_ = nullptr;
+};
+
+#endif // CEF_LIBCEF_BROWSER_CHROME_BROWSER_PLATFORM_DELEGATE_CHROME_H_
diff --git a/libcef/browser/chrome/chrome_browser_context.cc b/libcef/browser/chrome/chrome_browser_context.cc
new file mode 100644
index 00000000..7528a670
--- /dev/null
+++ b/libcef/browser/chrome/chrome_browser_context.cc
@@ -0,0 +1,184 @@
+// Copyright 2020 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/chrome/chrome_browser_context.h"
+
+#include "libcef/browser/thread_util.h"
+
+#include "base/threading/thread_restrictions.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/prefs/session_startup_pref.h"
+#include "chrome/browser/profiles/keep_alive/profile_keep_alive_types.h"
+#include "chrome/browser/profiles/keep_alive/scoped_profile_keep_alive.h"
+#include "chrome/browser/profiles/off_the_record_profile_impl.h"
+#include "chrome/common/pref_names.h"
+
+namespace {
+
+// Match the default logic from ProfileManager::GetPrimaryUserProfile which was
+// restricted in https://crbug.com/1264436.
+Profile* GetPrimaryUserProfile() {
+ ProfileManager* profile_manager = g_browser_process->profile_manager();
+
+ // From ProfileManager::GetActiveUserOrOffTheRecordProfile.
+ base::FilePath default_profile_dir = profile_manager->user_data_dir().Append(
+ profile_manager->GetInitialProfileDir());
+ return profile_manager->GetProfile(default_profile_dir);
+}
+
+} // namespace
+
+ChromeBrowserContext::ChromeBrowserContext(
+ const CefRequestContextSettings& settings)
+ : CefBrowserContext(settings), weak_ptr_factory_(this) {}
+
+ChromeBrowserContext::~ChromeBrowserContext() = default;
+
+content::BrowserContext* ChromeBrowserContext::AsBrowserContext() {
+ CHECK(!destroyed_);
+ return profile_;
+}
+
+Profile* ChromeBrowserContext::AsProfile() {
+ CHECK(!destroyed_);
+ return profile_;
+}
+
+bool ChromeBrowserContext::IsInitialized() const {
+ CEF_REQUIRE_UIT();
+ CHECK(!destroyed_);
+ return !!profile_;
+}
+
+void ChromeBrowserContext::StoreOrTriggerInitCallback(
+ base::OnceClosure callback) {
+ CEF_REQUIRE_UIT();
+ if (IsInitialized()) {
+ std::move(callback).Run();
+ } else {
+ init_callbacks_.emplace_back(std::move(callback));
+ }
+}
+
+void ChromeBrowserContext::InitializeAsync(base::OnceClosure initialized_cb) {
+ init_callbacks_.emplace_back(std::move(initialized_cb));
+
+ CefBrowserContext::Initialize();
+
+ if (!cache_path_.empty()) {
+ auto* profile_manager = g_browser_process->profile_manager();
+ const auto& user_data_dir = profile_manager->user_data_dir();
+
+ if (cache_path_ == user_data_dir) {
+ // Use the default disk-based profile.
+ auto profile = GetPrimaryUserProfile();
+ ProfileCreated(Profile::CreateStatus::CREATE_STATUS_INITIALIZED, profile);
+ return;
+ } else if (cache_path_.DirName() == user_data_dir) {
+ // Create or load a specific disk-based profile. May continue
+ // synchronously or asynchronously.
+ profile_manager->CreateProfileAsync(
+ cache_path_,
+ base::BindOnce(&ChromeBrowserContext::ProfileCreated,
+ weak_ptr_factory_.GetWeakPtr(),
+ Profile::CreateStatus::CREATE_STATUS_INITIALIZED),
+ base::BindOnce(&ChromeBrowserContext::ProfileCreated,
+ weak_ptr_factory_.GetWeakPtr(),
+ Profile::CreateStatus::CREATE_STATUS_CREATED));
+ return;
+ } else {
+ // All profile directories must be relative to |user_data_dir|.
+ LOG(ERROR) << "Cannot create profile at path "
+ << cache_path_.AsUTF8Unsafe();
+ }
+ }
+
+ // Default to creating a new/unique OffTheRecord profile.
+ ProfileCreated(Profile::CreateStatus::CREATE_STATUS_LOCAL_FAIL, nullptr);
+}
+
+void ChromeBrowserContext::Shutdown() {
+ CefBrowserContext::Shutdown();
+
+ // Allow potential deletion of the Profile at some future point (controlled
+ // by ProfileManager).
+ profile_keep_alive_.reset();
+
+ // |g_browser_process| may be nullptr during shutdown.
+ if (g_browser_process) {
+ if (should_destroy_) {
+ GetPrimaryUserProfile()->DestroyOffTheRecordProfile(profile_);
+ } else if (profile_) {
+ OnProfileWillBeDestroyed(profile_);
+ }
+ }
+}
+
+void ChromeBrowserContext::ProfileCreated(Profile::CreateStatus status,
+ Profile* profile) {
+ Profile* parent_profile = nullptr;
+ OffTheRecordProfileImpl* otr_profile = nullptr;
+
+ if (status != Profile::CreateStatus::CREATE_STATUS_CREATED &&
+ status != Profile::CreateStatus::CREATE_STATUS_INITIALIZED) {
+ CHECK(!profile);
+ CHECK(!profile_);
+
+ // Profile creation may access the filesystem.
+ base::ScopedAllowBlockingForTesting allow_blocking;
+
+ // Creation of a disk-based profile failed for some reason. Create a
+ // new/unique OffTheRecord profile instead.
+ const auto& profile_id = Profile::OTRProfileID::CreateUniqueForCEF();
+ parent_profile = GetPrimaryUserProfile();
+ profile_ = parent_profile->GetOffTheRecordProfile(
+ profile_id, /*create_if_needed=*/true);
+ otr_profile = static_cast<OffTheRecordProfileImpl*>(profile_);
+ status = Profile::CreateStatus::CREATE_STATUS_INITIALIZED;
+ should_destroy_ = true;
+ } else if (profile && !profile_) {
+ // May be CREATE_STATUS_CREATED or CREATE_STATUS_INITIALIZED since
+ // *CREATED isn't always sent for a disk-based profile that already
+ // exists.
+ profile_ = profile;
+ profile_->AddObserver(this);
+ profile_keep_alive_.reset(new ScopedProfileKeepAlive(
+ profile_, ProfileKeepAliveOrigin::kAppWindow));
+ }
+
+ if (status == Profile::CreateStatus::CREATE_STATUS_INITIALIZED) {
+ CHECK(profile_);
+
+ // Must set |profile_| before Init() calls
+ // ChromeContentBrowserClientCef::ConfigureNetworkContextParams so that
+ // CefBrowserContext::FromBrowserContext can find us.
+ if (otr_profile) {
+ otr_profile->Init();
+ parent_profile->NotifyOffTheRecordProfileCreated(otr_profile);
+ }
+
+ if (!profile_->IsOffTheRecord()) {
+ // Configure the desired profile restore behavior for the next application
+ // restart (checked via ProfileImpl::ShouldRestoreOldSessionCookies).
+ profile_->GetPrefs()->SetInteger(
+ prefs::kRestoreOnStartup, !!settings_.persist_session_cookies
+ ? SessionStartupPref::kPrefValueLast
+ : SessionStartupPref::kPrefValueNewTab);
+ }
+
+ if (!init_callbacks_.empty()) {
+ for (auto& callback : init_callbacks_) {
+ std::move(callback).Run();
+ }
+ init_callbacks_.clear();
+ }
+ }
+}
+
+void ChromeBrowserContext::OnProfileWillBeDestroyed(Profile* profile) {
+ CHECK_EQ(profile_, profile);
+ profile_->RemoveObserver(this);
+ profile_ = nullptr;
+ destroyed_ = true;
+}
diff --git a/libcef/browser/chrome/chrome_browser_context.h b/libcef/browser/chrome/chrome_browser_context.h
new file mode 100644
index 00000000..0bac7fde
--- /dev/null
+++ b/libcef/browser/chrome/chrome_browser_context.h
@@ -0,0 +1,55 @@
+// Copyright 2020 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_CHROME_CHROME_BROWSER_CONTEXT_H_
+#define CEF_LIBCEF_BROWSER_CHROME_CHROME_BROWSER_CONTEXT_H_
+#pragma once
+
+#include "libcef/browser/browser_context.h"
+
+#include "base/memory/weak_ptr.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/profiles/profile_observer.h"
+
+class ScopedProfileKeepAlive;
+
+// See CefBrowserContext documentation for usage. Only accessed on the UI thread
+// unless otherwise indicated.
+class ChromeBrowserContext : public CefBrowserContext, public ProfileObserver {
+ public:
+ explicit ChromeBrowserContext(const CefRequestContextSettings& settings);
+
+ ChromeBrowserContext(const ChromeBrowserContext&) = delete;
+ ChromeBrowserContext& operator=(const ChromeBrowserContext&) = delete;
+
+ void InitializeAsync(base::OnceClosure initialized_cb);
+
+ // CefBrowserContext overrides.
+ content::BrowserContext* AsBrowserContext() override;
+ Profile* AsProfile() override;
+ bool IsInitialized() const override;
+ void StoreOrTriggerInitCallback(base::OnceClosure callback) override;
+ void Shutdown() override;
+
+ // ProfileObserver overrides.
+ void OnProfileWillBeDestroyed(Profile* profile) override;
+
+ private:
+ ~ChromeBrowserContext() override;
+
+ void ProfileCreated(Profile::CreateStatus status, Profile* profile);
+
+ base::OnceClosure initialized_cb_;
+ Profile* profile_ = nullptr;
+ bool should_destroy_ = false;
+
+ bool destroyed_ = false;
+ std::unique_ptr<ScopedProfileKeepAlive> profile_keep_alive_;
+
+ std::vector<base::OnceClosure> init_callbacks_;
+
+ base::WeakPtrFactory<ChromeBrowserContext> weak_ptr_factory_;
+};
+
+#endif // CEF_LIBCEF_BROWSER_CHROME_CHROME_BROWSER_CONTEXT_H_
diff --git a/libcef/browser/chrome/chrome_browser_delegate.cc b/libcef/browser/chrome/chrome_browser_delegate.cc
new file mode 100644
index 00000000..a1f6a97e
--- /dev/null
+++ b/libcef/browser/chrome/chrome_browser_delegate.cc
@@ -0,0 +1,358 @@
+// Copyright 2020 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <memory>
+
+#include "libcef/browser/chrome/chrome_browser_delegate.h"
+
+#include "libcef/browser/browser_contents_delegate.h"
+#include "libcef/browser/browser_host_base.h"
+#include "libcef/browser/browser_info_manager.h"
+#include "libcef/browser/browser_platform_delegate.h"
+#include "libcef/browser/chrome/chrome_browser_host_impl.h"
+#include "libcef/browser/media_access_query.h"
+#include "libcef/browser/request_context_impl.h"
+#include "libcef/common/app_manager.h"
+#include "libcef/common/frame_util.h"
+
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_tabstrip.h"
+#include "content/public/browser/global_routing_id.h"
+#include "content/public/browser/keyboard_event_processing_result.h"
+#include "content/public/browser/native_web_keyboard_event.h"
+
+using content::KeyboardEventProcessingResult;
+
+ChromeBrowserDelegate::ChromeBrowserDelegate(
+ Browser* browser,
+ const CefBrowserCreateParams& create_params)
+ : browser_(browser), create_params_(create_params) {
+ DCHECK(browser_);
+}
+
+ChromeBrowserDelegate::~ChromeBrowserDelegate() = default;
+
+std::unique_ptr<content::WebContents> ChromeBrowserDelegate::AddWebContents(
+ std::unique_ptr<content::WebContents> new_contents) {
+ if (CefBrowserInfoManager::GetInstance()->AddWebContents(
+ new_contents.get())) {
+ // The browser host should have been created in WebContentsCreated().
+ auto new_browser =
+ ChromeBrowserHostImpl::GetBrowserForContents(new_contents.get());
+ if (new_browser) {
+ // Create a new Browser and give it ownership of the new WebContents.
+ new_browser->AddNewContents(std::move(new_contents));
+ } else {
+ LOG(ERROR) << "No host found for chrome popup browser";
+ }
+ }
+
+ // Proceed with default chrome::AddWebContents behavior.
+ return new_contents;
+}
+
+void ChromeBrowserDelegate::OnWebContentsCreated(
+ content::WebContents* new_contents) {
+ // Necessary to receive LoadingStateChanged calls during initial navigation.
+ // This will be called again in Browser::SetAsDelegate, which should be fine.
+ new_contents->SetDelegate(browser_);
+
+ SetAsDelegate(new_contents, /*set_delegate=*/true);
+}
+
+void ChromeBrowserDelegate::SetAsDelegate(content::WebContents* web_contents,
+ bool set_delegate) {
+ DCHECK(web_contents);
+ auto browser_host =
+ ChromeBrowserHostImpl::GetBrowserForContents(web_contents);
+
+ // |set_delegate=false| only makes sense if we already have a browser host.
+ DCHECK(browser_host || set_delegate);
+
+ if (browser_host) {
+ // We already have a browser host, so just change the associated Browser.
+ browser_host->SetBrowser(set_delegate ? browser_ : nullptr);
+ return;
+ }
+
+ auto platform_delegate = CefBrowserPlatformDelegate::Create(create_params_);
+ CHECK(platform_delegate);
+
+ auto browser_info = CefBrowserInfoManager::GetInstance()->CreateBrowserInfo(
+ /*is_popup=*/false, /*is_windowless=*/false, create_params_.extra_info);
+
+ auto request_context_impl =
+ CefRequestContextImpl::GetOrCreateForRequestContext(
+ create_params_.request_context);
+
+ CreateBrowser(web_contents, create_params_.settings, create_params_.client,
+ std::move(platform_delegate), browser_info, /*opener=*/nullptr,
+ request_context_impl);
+}
+
+bool ChromeBrowserDelegate::ShowStatusBubble(bool show_by_default) {
+ if (!show_status_bubble_.has_value()) {
+ show_status_bubble_ = show_by_default;
+ if (auto browser = ChromeBrowserHostImpl::GetBrowserForBrowser(browser_)) {
+ const auto& state = browser->settings().chrome_status_bubble;
+ if (show_by_default && state == STATE_DISABLED) {
+ show_status_bubble_ = false;
+ } else if (!show_by_default && state == STATE_ENABLED) {
+ show_status_bubble_ = true;
+ }
+ }
+ }
+
+ return *show_status_bubble_;
+}
+
+bool ChromeBrowserDelegate::HandleCommand(int command_id,
+ WindowOpenDisposition disposition) {
+ if (auto browser = ChromeBrowserHostImpl::GetBrowserForBrowser(browser_)) {
+ if (auto client = browser->GetClient()) {
+ if (auto handler = client->GetCommandHandler()) {
+ return handler->OnChromeCommand(
+ browser.get(), command_id,
+ static_cast<cef_window_open_disposition_t>(disposition));
+ }
+ }
+ }
+ return false;
+}
+
+content::MediaResponseCallback
+ChromeBrowserDelegate::RequestMediaAccessPermissionEx(
+ content::WebContents* web_contents,
+ const content::MediaStreamRequest& request,
+ content::MediaResponseCallback callback) {
+ if (auto browser = ChromeBrowserHostImpl::GetBrowserForBrowser(browser_)) {
+ return media_access_query::RequestMediaAccessPermission(
+ browser.get(), request, std::move(callback),
+ /*default_disallow=*/false);
+ }
+ return callback;
+}
+
+void ChromeBrowserDelegate::WebContentsCreated(
+ content::WebContents* source_contents,
+ int opener_render_process_id,
+ int opener_render_frame_id,
+ const std::string& frame_name,
+ const GURL& target_url,
+ content::WebContents* new_contents) {
+ CefBrowserSettings settings;
+ CefRefPtr<CefClient> client;
+ std::unique_ptr<CefBrowserPlatformDelegate> platform_delegate;
+ CefRefPtr<CefDictionaryValue> extra_info;
+
+ CefBrowserInfoManager::GetInstance()->WebContentsCreated(
+ target_url,
+ frame_util::MakeGlobalId(opener_render_process_id,
+ opener_render_frame_id),
+ settings, client, platform_delegate, extra_info, new_contents);
+
+ auto opener = ChromeBrowserHostImpl::GetBrowserForContents(source_contents);
+ if (!opener) {
+ LOG(ERROR) << "No opener found for chrome popup browser";
+ return;
+ }
+
+ auto browser_info =
+ CefBrowserInfoManager::GetInstance()->CreatePopupBrowserInfo(
+ new_contents, /*is_windowless=*/false, extra_info);
+ CHECK(browser_info->is_popup());
+
+ // Popups must share the same RequestContext as the parent.
+ auto request_context_impl = opener->request_context();
+ CHECK(request_context_impl);
+
+ // We don't officially own |new_contents| until AddNewContents() is called.
+ // However, we need to install observers/delegates here.
+ CreateBrowser(new_contents, settings, client, std::move(platform_delegate),
+ browser_info, opener, request_context_impl);
+}
+
+content::WebContents* ChromeBrowserDelegate::OpenURLFromTab(
+ content::WebContents* source,
+ const content::OpenURLParams& params) {
+ // |source| may be nullptr when opening a link from chrome UI such as the
+ // Reading List sidebar. In that case we default to using the Browser's
+ // currently active WebContents.
+ if (!source) {
+ source = browser_->tab_strip_model()->GetActiveWebContents();
+ DCHECK(source);
+ }
+
+ // Return nullptr to cancel the navigation. Otherwise, proceed with default
+ // chrome handling.
+ if (auto delegate = GetDelegateForWebContents(source)) {
+ return delegate->OpenURLFromTab(source, params);
+ }
+ return nullptr;
+}
+
+void ChromeBrowserDelegate::LoadingStateChanged(content::WebContents* source,
+ bool should_show_loading_ui) {
+ if (auto delegate = GetDelegateForWebContents(source)) {
+ delegate->LoadingStateChanged(source, should_show_loading_ui);
+ }
+}
+
+void ChromeBrowserDelegate::UpdateTargetURL(content::WebContents* source,
+ const GURL& url) {
+ if (auto delegate = GetDelegateForWebContents(source)) {
+ delegate->UpdateTargetURL(source, url);
+ }
+}
+
+bool ChromeBrowserDelegate::DidAddMessageToConsole(
+ content::WebContents* source,
+ blink::mojom::ConsoleMessageLevel log_level,
+ const std::u16string& message,
+ int32_t line_no,
+ const std::u16string& source_id) {
+ if (auto delegate = GetDelegateForWebContents(source)) {
+ return delegate->DidAddMessageToConsole(source, log_level, message, line_no,
+ source_id);
+ }
+ return false;
+}
+
+void ChromeBrowserDelegate::EnterFullscreenModeForTab(
+ content::RenderFrameHost* requesting_frame,
+ const blink::mojom::FullscreenOptions& options) {
+ auto web_contents =
+ content::WebContents::FromRenderFrameHost(requesting_frame);
+ if (!web_contents) {
+ return;
+ }
+
+ if (auto delegate = GetDelegateForWebContents(web_contents)) {
+ delegate->EnterFullscreenModeForTab(requesting_frame, options);
+ }
+}
+
+void ChromeBrowserDelegate::ExitFullscreenModeForTab(
+ content::WebContents* web_contents) {
+ if (auto delegate = GetDelegateForWebContents(web_contents)) {
+ delegate->ExitFullscreenModeForTab(web_contents);
+ }
+}
+
+void ChromeBrowserDelegate::CanDownload(
+ const GURL& url,
+ const std::string& request_method,
+ base::OnceCallback<void(bool)> callback) {
+ auto source = browser_->tab_strip_model()->GetActiveWebContents();
+ DCHECK(source);
+
+ if (auto delegate = GetDelegateForWebContents(source)) {
+ delegate->CanDownload(url, request_method, std::move(callback));
+ return;
+ }
+ std::move(callback).Run(true);
+}
+
+KeyboardEventProcessingResult ChromeBrowserDelegate::PreHandleKeyboardEvent(
+ content::WebContents* source,
+ const content::NativeWebKeyboardEvent& event) {
+ if (auto delegate = GetDelegateForWebContents(source)) {
+ return delegate->PreHandleKeyboardEvent(source, event);
+ }
+ return KeyboardEventProcessingResult::NOT_HANDLED;
+}
+
+bool ChromeBrowserDelegate::HandleKeyboardEvent(
+ content::WebContents* source,
+ const content::NativeWebKeyboardEvent& event) {
+ if (auto delegate = GetDelegateForWebContents(source)) {
+ return delegate->HandleKeyboardEvent(source, event);
+ }
+ return false;
+}
+
+void ChromeBrowserDelegate::CreateBrowser(
+ content::WebContents* web_contents,
+ CefBrowserSettings settings,
+ CefRefPtr<CefClient> client,
+ std::unique_ptr<CefBrowserPlatformDelegate> platform_delegate,
+ scoped_refptr<CefBrowserInfo> browser_info,
+ CefRefPtr<ChromeBrowserHostImpl> opener,
+ CefRefPtr<CefRequestContextImpl> request_context_impl) {
+ CEF_REQUIRE_UIT();
+ DCHECK(web_contents);
+ DCHECK(platform_delegate);
+ DCHECK(browser_info);
+ DCHECK(request_context_impl);
+
+ // If |opener| is non-nullptr it must be a popup window.
+ DCHECK(!opener.get() || browser_info->is_popup());
+
+ if (!client) {
+ if (auto app = CefAppManager::Get()->GetApplication()) {
+ if (auto bph = app->GetBrowserProcessHandler()) {
+ client = bph->GetDefaultClient();
+ }
+ }
+ }
+
+ if (!client) {
+ LOG(WARNING) << "Creating a chrome browser without a client";
+ }
+
+ // Check if chrome and CEF are using the same browser context.
+ // TODO(chrome-runtime): Verify if/when this might occur.
+ auto chrome_browser_context =
+ CefBrowserContext::FromBrowserContext(browser_->create_params().profile);
+ if (chrome_browser_context != request_context_impl->GetBrowserContext()) {
+ LOG(WARNING) << "Creating a chrome browser with mismatched context";
+ }
+
+ // Remains alive until the associated WebContents is destroyed.
+ CefRefPtr<ChromeBrowserHostImpl> browser_host =
+ new ChromeBrowserHostImpl(settings, client, std::move(platform_delegate),
+ browser_info, request_context_impl);
+ browser_host->Attach(web_contents, opener);
+
+ // The Chrome browser for a popup won't be created until AddNewContents().
+ if (!opener) {
+ browser_host->SetBrowser(browser_);
+ }
+}
+
+CefBrowserContentsDelegate* ChromeBrowserDelegate::GetDelegateForWebContents(
+ content::WebContents* web_contents) {
+ auto browser_host =
+ ChromeBrowserHostImpl::GetBrowserForContents(web_contents);
+ if (browser_host) {
+ return browser_host->contents_delegate();
+ }
+ return nullptr;
+}
+
+namespace cef {
+
+// static
+std::unique_ptr<BrowserDelegate> BrowserDelegate::Create(
+ Browser* browser,
+ scoped_refptr<CreateParams> cef_params) {
+ CefBrowserCreateParams create_params;
+
+ // Parameters from ChromeBrowserHostImpl::Create, or nullptr if the Browser
+ // was created from somewhere else.
+ auto params = static_cast<ChromeBrowserHostImpl::DelegateCreateParams*>(
+ cef_params.get());
+ if (params) {
+ create_params = params->create_params_;
+
+ // Clear these values so they're not persisted to additional Browsers.
+ params->create_params_.window_info.reset();
+ params->create_params_.browser_view = nullptr;
+ }
+
+ return std::make_unique<ChromeBrowserDelegate>(browser, create_params);
+}
+
+} // namespace cef
diff --git a/libcef/browser/chrome/chrome_browser_delegate.h b/libcef/browser/chrome/chrome_browser_delegate.h
new file mode 100644
index 00000000..3f7a8a1b
--- /dev/null
+++ b/libcef/browser/chrome/chrome_browser_delegate.h
@@ -0,0 +1,119 @@
+// Copyright 2020 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_CHROME_CHROME_BROWSER_DELEGATE_H_
+#define CEF_LIBCEF_BROWSER_CHROME_CHROME_BROWSER_DELEGATE_H_
+#pragma once
+
+#include <memory>
+
+#include "libcef/browser/browser_host_base.h"
+#include "libcef/browser/browser_info.h"
+#include "libcef/browser/chrome/browser_delegate.h"
+
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+class CefBrowserContentsDelegate;
+class CefRequestContextImpl;
+class ChromeBrowserHostImpl;
+
+// Implementation of the cef::BrowserDelegate interface. Lifespan is controlled
+// by the Browser object. Only accessed on the UI thread.
+//
+// The Browser object represents the top-level Chrome browser window. One or
+// more tabs (WebContents) are then owned by the Browser object via
+// TabStripModel. A new Browser object can be created programmatically using
+// "new Browser" or Browser::Create, or as a result of user action such as
+// dragging a tab out of an existing window. New or existing tabs can also be
+// added to an already existing Browser object.
+//
+// The Browser object acts as the WebContentsDelegate for all attached tabs. CEF
+// integration requires WebContentsDelegate callbacks and notification of tab
+// attach/detach. To support this integration a cef::BrowserDelegate
+// (ChromeBrowserDelegate) member is created in the Browser constructor and
+// receives delegation for the Browser callbacks. ChromeBrowserDelegate creates
+// a new ChromeBrowserHostImpl when a tab is added to a Browser for the first
+// time, and that ChromeBrowserHostImpl continues to exist until the tab's
+// WebContents is destroyed. The associated WebContents object does not change,
+// but the Browser object will change when the tab is dragged between windows.
+class ChromeBrowserDelegate : public cef::BrowserDelegate {
+ public:
+ ChromeBrowserDelegate(Browser* browser,
+ const CefBrowserCreateParams& create_params);
+
+ ChromeBrowserDelegate(const ChromeBrowserDelegate&) = delete;
+ ChromeBrowserDelegate& operator=(const ChromeBrowserDelegate&) = delete;
+
+ ~ChromeBrowserDelegate() override;
+
+ // cef::BrowserDelegate methods:
+ std::unique_ptr<content::WebContents> AddWebContents(
+ std::unique_ptr<content::WebContents> new_contents) override;
+ void OnWebContentsCreated(content::WebContents* new_contents) override;
+ void SetAsDelegate(content::WebContents* web_contents,
+ bool set_delegate) override;
+ bool ShowStatusBubble(bool show_by_default) override;
+ bool HandleCommand(int command_id,
+ WindowOpenDisposition disposition) override;
+ [[nodiscard]] content::MediaResponseCallback RequestMediaAccessPermissionEx(
+ content::WebContents* web_contents,
+ const content::MediaStreamRequest& request,
+ content::MediaResponseCallback callback) override;
+
+ // WebContentsDelegate methods:
+ void WebContentsCreated(content::WebContents* source_contents,
+ int opener_render_process_id,
+ int opener_render_frame_id,
+ const std::string& frame_name,
+ const GURL& target_url,
+ content::WebContents* new_contents) override;
+ content::WebContents* OpenURLFromTab(
+ content::WebContents* source,
+ const content::OpenURLParams& params) override;
+ void LoadingStateChanged(content::WebContents* source,
+ bool should_show_loading_ui) override;
+ void UpdateTargetURL(content::WebContents* source, const GURL& url) override;
+ bool DidAddMessageToConsole(content::WebContents* source,
+ blink::mojom::ConsoleMessageLevel log_level,
+ const std::u16string& message,
+ int32_t line_no,
+ const std::u16string& source_id) override;
+ void EnterFullscreenModeForTab(
+ content::RenderFrameHost* requesting_frame,
+ const blink::mojom::FullscreenOptions& options) override;
+ void ExitFullscreenModeForTab(content::WebContents* web_contents) override;
+ void CanDownload(const GURL& url,
+ const std::string& request_method,
+ base::OnceCallback<void(bool)> callback) override;
+ content::KeyboardEventProcessingResult PreHandleKeyboardEvent(
+ content::WebContents* source,
+ const content::NativeWebKeyboardEvent& event) override;
+ bool HandleKeyboardEvent(
+ content::WebContents* source,
+ const content::NativeWebKeyboardEvent& event) override;
+
+ Browser* browser() const { return browser_; }
+
+ private:
+ void CreateBrowser(
+ content::WebContents* web_contents,
+ CefBrowserSettings settings,
+ CefRefPtr<CefClient> client,
+ std::unique_ptr<CefBrowserPlatformDelegate> platform_delegate,
+ scoped_refptr<CefBrowserInfo> browser_info,
+ CefRefPtr<ChromeBrowserHostImpl> opener,
+ CefRefPtr<CefRequestContextImpl> request_context_impl);
+
+ CefBrowserContentsDelegate* GetDelegateForWebContents(
+ content::WebContents* web_contents);
+
+ Browser* const browser_;
+
+ // Used when creating a new browser host.
+ const CefBrowserCreateParams create_params_;
+
+ absl::optional<bool> show_status_bubble_;
+};
+
+#endif // CEF_LIBCEF_BROWSER_CHROME_CHROME_BROWSER_DELEGATE_H_
diff --git a/libcef/browser/chrome/chrome_browser_host_impl.cc b/libcef/browser/chrome/chrome_browser_host_impl.cc
new file mode 100644
index 00000000..c62776bf
--- /dev/null
+++ b/libcef/browser/chrome/chrome_browser_host_impl.cc
@@ -0,0 +1,566 @@
+// Copyright 2020 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/chrome/chrome_browser_host_impl.h"
+
+#include "libcef/browser/browser_platform_delegate.h"
+#include "libcef/browser/chrome/browser_platform_delegate_chrome.h"
+#include "libcef/browser/thread_util.h"
+#include "libcef/browser/views/browser_view_impl.h"
+#include "libcef/common/net/url_util.h"
+#include "libcef/features/runtime_checks.h"
+
+#include "base/logging.h"
+#include "base/notreached.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_commands.h"
+#include "chrome/browser/ui/browser_navigator.h"
+#include "chrome/browser/ui/browser_tabstrip.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/views/frame/contents_web_view.h"
+#include "chrome/common/pref_names.h"
+#include "libcef/browser/chrome/views/chrome_browser_frame.h"
+#include "libcef/browser/chrome/views/chrome_browser_view.h"
+
+// static
+CefRefPtr<ChromeBrowserHostImpl> ChromeBrowserHostImpl::Create(
+ const CefBrowserCreateParams& params) {
+ auto browser = CreateBrowser(params);
+
+ GURL url = url_util::MakeGURL(params.url, /*fixup=*/true);
+ if (url.is_empty()) {
+ // Chrome will navigate to kChromeUINewTabURL by default. We want to keep
+ // the current CEF behavior of not navigating at all. Use a special URL that
+ // will be recognized in HandleNonNavigationAboutURL.
+ url = GURL("chrome://ignore/");
+ }
+
+ // Add a new tab. This will indirectly create a new tab WebContents and
+ // call ChromeBrowserDelegate::OnWebContentsCreated to create the associated
+ // ChromeBrowserHostImpl.
+ chrome::AddTabAt(browser, url, /*index=*/TabStripModel::kNoTab,
+ /*foreground=*/true);
+
+ // The new tab WebContents.
+ auto web_contents = browser->tab_strip_model()->GetActiveWebContents();
+ CHECK(web_contents);
+
+ // The associated ChromeBrowserHostImpl.
+ auto browser_host =
+ ChromeBrowserHostImpl::GetBrowserForContents(web_contents);
+ CHECK(browser_host);
+
+ return browser_host;
+}
+
+// static
+CefRefPtr<ChromeBrowserHostImpl> ChromeBrowserHostImpl::GetBrowserForHost(
+ const content::RenderViewHost* host) {
+ REQUIRE_CHROME_RUNTIME();
+ auto browser = CefBrowserHostBase::GetBrowserForHost(host);
+ return static_cast<ChromeBrowserHostImpl*>(browser.get());
+}
+
+// static
+CefRefPtr<ChromeBrowserHostImpl> ChromeBrowserHostImpl::GetBrowserForHost(
+ const content::RenderFrameHost* host) {
+ REQUIRE_CHROME_RUNTIME();
+ auto browser = CefBrowserHostBase::GetBrowserForHost(host);
+ return static_cast<ChromeBrowserHostImpl*>(browser.get());
+}
+
+// static
+CefRefPtr<ChromeBrowserHostImpl> ChromeBrowserHostImpl::GetBrowserForContents(
+ const content::WebContents* contents) {
+ REQUIRE_CHROME_RUNTIME();
+ auto browser = CefBrowserHostBase::GetBrowserForContents(contents);
+ return static_cast<ChromeBrowserHostImpl*>(browser.get());
+}
+
+// static
+CefRefPtr<ChromeBrowserHostImpl> ChromeBrowserHostImpl::GetBrowserForGlobalId(
+ const content::GlobalRenderFrameHostId& global_id) {
+ REQUIRE_CHROME_RUNTIME();
+ auto browser = CefBrowserHostBase::GetBrowserForGlobalId(global_id);
+ return static_cast<ChromeBrowserHostImpl*>(browser.get());
+}
+
+// static
+CefRefPtr<ChromeBrowserHostImpl> ChromeBrowserHostImpl::GetBrowserForBrowser(
+ const Browser* browser) {
+ REQUIRE_CHROME_RUNTIME();
+ return GetBrowserForContents(
+ browser->tab_strip_model()->GetActiveWebContents());
+}
+
+ChromeBrowserHostImpl::~ChromeBrowserHostImpl() = default;
+
+void ChromeBrowserHostImpl::AddNewContents(
+ std::unique_ptr<content::WebContents> contents) {
+ DCHECK(contents);
+ DCHECK(!browser_);
+
+ // We should already be associated with the WebContents.
+ DCHECK_EQ(GetWebContents(), contents.get());
+
+ CefBrowserCreateParams params;
+ params.request_context = request_context();
+ params.browser_view = GetBrowserView();
+
+ // Create the new Browser representation.
+ auto browser = CreateBrowser(params);
+
+ // Add the WebContents to the Browser.
+ browser->tab_strip_model()->AddWebContents(
+ std::move(contents), /*index=*/TabStripModel::kNoTab,
+ ui::PageTransition::PAGE_TRANSITION_AUTO_TOPLEVEL,
+ AddTabTypes::ADD_ACTIVE);
+
+ SetBrowser(browser);
+}
+
+void ChromeBrowserHostImpl::OnWebContentsDestroyed(
+ content::WebContents* web_contents) {
+ platform_delegate_->WebContentsDestroyed(web_contents);
+ DestroyBrowser();
+}
+
+void ChromeBrowserHostImpl::OnSetFocus(cef_focus_source_t source) {
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(CEF_UIT, base::BindOnce(&ChromeBrowserHostImpl::OnSetFocus,
+ this, source));
+ return;
+ }
+
+ if (contents_delegate_->OnSetFocus(source)) {
+ return;
+ }
+
+ if (platform_delegate_) {
+ platform_delegate_->SetFocus(true);
+ }
+
+ if (browser_) {
+ const int tab_index = GetCurrentTabIndex();
+ if (tab_index != TabStripModel::kNoTab) {
+ chrome::SelectNumberedTab(browser_, tab_index);
+ }
+ }
+}
+
+void ChromeBrowserHostImpl::CloseBrowser(bool force_close) {
+ // Always do this asynchronously because TabStripModel is not re-entrant.
+ CEF_POST_TASK(CEF_UIT, base::BindOnce(&ChromeBrowserHostImpl::DoCloseBrowser,
+ this, force_close));
+}
+
+bool ChromeBrowserHostImpl::TryCloseBrowser() {
+ // TODO(chrome): Handle the case where the browser may not close immediately.
+ CloseBrowser(true);
+ return true;
+}
+
+CefWindowHandle ChromeBrowserHostImpl::GetWindowHandle() {
+ if (CEF_CURRENTLY_ON_UIT()) {
+ // Always return the most up-to-date window handle for a views-hosted
+ // browser since it may change if the view is re-parented.
+ if (platform_delegate_) {
+ return platform_delegate_->GetHostWindowHandle();
+ }
+ }
+ return host_window_handle_;
+}
+
+CefWindowHandle ChromeBrowserHostImpl::GetOpenerWindowHandle() {
+ NOTIMPLEMENTED();
+ return kNullWindowHandle;
+}
+
+double ChromeBrowserHostImpl::GetZoomLevel() {
+ NOTIMPLEMENTED();
+ return 0.0;
+}
+
+void ChromeBrowserHostImpl::SetZoomLevel(double zoomLevel) {
+ NOTIMPLEMENTED();
+}
+
+void ChromeBrowserHostImpl::Find(const CefString& searchText,
+ bool forward,
+ bool matchCase,
+ bool findNext) {
+ NOTIMPLEMENTED();
+}
+
+void ChromeBrowserHostImpl::StopFinding(bool clearSelection) {
+ NOTIMPLEMENTED();
+}
+
+void ChromeBrowserHostImpl::ShowDevTools(const CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient> client,
+ const CefBrowserSettings& settings,
+ const CefPoint& inspect_element_at) {
+ NOTIMPLEMENTED();
+}
+
+void ChromeBrowserHostImpl::CloseDevTools() {
+ NOTIMPLEMENTED();
+}
+
+bool ChromeBrowserHostImpl::HasDevTools() {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+bool ChromeBrowserHostImpl::IsWindowRenderingDisabled() {
+ return false;
+}
+
+void ChromeBrowserHostImpl::WasResized() {
+ NOTIMPLEMENTED();
+}
+
+void ChromeBrowserHostImpl::WasHidden(bool hidden) {
+ NOTIMPLEMENTED();
+}
+
+void ChromeBrowserHostImpl::NotifyScreenInfoChanged() {
+ NOTIMPLEMENTED();
+}
+
+void ChromeBrowserHostImpl::Invalidate(PaintElementType type) {
+ NOTIMPLEMENTED();
+}
+
+void ChromeBrowserHostImpl::SendExternalBeginFrame() {
+ NOTIMPLEMENTED();
+}
+
+void ChromeBrowserHostImpl::SendTouchEvent(const CefTouchEvent& event) {
+ NOTIMPLEMENTED();
+}
+
+void ChromeBrowserHostImpl::SendCaptureLostEvent() {
+ NOTIMPLEMENTED();
+}
+
+int ChromeBrowserHostImpl::GetWindowlessFrameRate() {
+ return 0;
+}
+
+void ChromeBrowserHostImpl::SetWindowlessFrameRate(int frame_rate) {}
+
+void ChromeBrowserHostImpl::ImeSetComposition(
+ const CefString& text,
+ const std::vector<CefCompositionUnderline>& underlines,
+ const CefRange& replacement_range,
+ const CefRange& selection_range) {
+ NOTIMPLEMENTED();
+}
+
+void ChromeBrowserHostImpl::ImeCommitText(const CefString& text,
+ const CefRange& replacement_range,
+ int relative_cursor_pos) {
+ NOTIMPLEMENTED();
+}
+void ChromeBrowserHostImpl::ImeFinishComposingText(bool keep_selection) {
+ NOTIMPLEMENTED();
+}
+
+void ChromeBrowserHostImpl::ImeCancelComposition() {
+ NOTIMPLEMENTED();
+}
+
+void ChromeBrowserHostImpl::DragTargetDragEnter(
+ CefRefPtr<CefDragData> drag_data,
+ const CefMouseEvent& event,
+ DragOperationsMask allowed_ops) {
+ NOTIMPLEMENTED();
+}
+
+void ChromeBrowserHostImpl::DragTargetDragOver(const CefMouseEvent& event,
+ DragOperationsMask allowed_ops) {
+ NOTIMPLEMENTED();
+}
+
+void ChromeBrowserHostImpl::DragTargetDragLeave() {
+ NOTIMPLEMENTED();
+}
+
+void ChromeBrowserHostImpl::DragTargetDrop(const CefMouseEvent& event) {
+ NOTIMPLEMENTED();
+}
+
+void ChromeBrowserHostImpl::DragSourceSystemDragEnded() {
+ NOTIMPLEMENTED();
+}
+
+void ChromeBrowserHostImpl::DragSourceEndedAt(int x,
+ int y,
+ DragOperationsMask op) {
+ NOTIMPLEMENTED();
+}
+
+void ChromeBrowserHostImpl::SetAudioMuted(bool mute) {
+ NOTIMPLEMENTED();
+}
+
+bool ChromeBrowserHostImpl::IsAudioMuted() {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+void ChromeBrowserHostImpl::SetAccessibilityState(
+ cef_state_t accessibility_state) {
+ NOTIMPLEMENTED();
+}
+
+void ChromeBrowserHostImpl::SetAutoResizeEnabled(bool enabled,
+ const CefSize& min_size,
+ const CefSize& max_size) {
+ NOTIMPLEMENTED();
+}
+
+CefRefPtr<CefExtension> ChromeBrowserHostImpl::GetExtension() {
+ return nullptr;
+}
+
+bool ChromeBrowserHostImpl::IsBackgroundHost() {
+ return false;
+}
+
+bool ChromeBrowserHostImpl::Navigate(const content::OpenURLParams& params) {
+ CEF_REQUIRE_UIT();
+ if (GetCurrentTabIndex() == TabStripModel::kNoTab) {
+ // We can't navigate via the Browser because we don't have a current tab.
+ return CefBrowserHostBase::Navigate(params);
+ }
+
+ if (browser_) {
+ GURL gurl = params.url;
+ if (!url_util::FixupGURL(gurl)) {
+ return false;
+ }
+
+ // This is generally equivalent to calling Browser::OpenURL, except:
+ // 1. It doesn't trigger a call to CefRequestHandler::OnOpenURLFromTab, and
+ // 2. It navigates in this CefBrowserHost's WebContents instead of
+ // (a) creating a new WebContents, or (b) using the Browser's active
+ // WebContents (which may not be the same), and
+ // 3. There is no risk of triggering chrome's popup blocker.
+ NavigateParams nav_params(browser_, gurl, params.transition);
+ nav_params.FillNavigateParamsFromOpenURLParams(params);
+
+ // Always navigate in the current tab.
+ nav_params.disposition = WindowOpenDisposition::CURRENT_TAB;
+ nav_params.source_contents = GetWebContents();
+
+ nav_params.tabstrip_add_types = AddTabTypes::ADD_NONE;
+ if (params.user_gesture) {
+ nav_params.window_action = NavigateParams::SHOW_WINDOW;
+ }
+ ::Navigate(&nav_params);
+ return true;
+ }
+ return false;
+}
+
+ChromeBrowserHostImpl::ChromeBrowserHostImpl(
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefClient> client,
+ std::unique_ptr<CefBrowserPlatformDelegate> platform_delegate,
+ scoped_refptr<CefBrowserInfo> browser_info,
+ CefRefPtr<CefRequestContextImpl> request_context)
+ : CefBrowserHostBase(settings,
+ client,
+ std::move(platform_delegate),
+ browser_info,
+ request_context) {}
+
+// static
+Browser* ChromeBrowserHostImpl::CreateBrowser(
+ const CefBrowserCreateParams& params) {
+ // Get or create the request context and profile.
+ CefRefPtr<CefRequestContextImpl> request_context_impl =
+ CefRequestContextImpl::GetOrCreateForRequestContext(
+ params.request_context);
+ CHECK(request_context_impl);
+ auto cef_browser_context = request_context_impl->GetBrowserContext();
+ CHECK(cef_browser_context);
+ auto profile = cef_browser_context->AsProfile();
+ CHECK(profile);
+
+ Browser::CreateParams chrome_params =
+ Browser::CreateParams(profile, /*user_gesture=*/false);
+
+ // Pass |params| to cef::BrowserDelegate::Create from the Browser constructor.
+ chrome_params.cef_params = base::MakeRefCounted<DelegateCreateParams>(params);
+
+ // Configure Browser creation to use the existing Views-based
+ // Widget/BrowserFrame (ChromeBrowserFrame) and BrowserView/BrowserWindow
+ // (ChromeBrowserView). See views/chrome_browser_frame.h for related
+ // documentation.
+ ChromeBrowserView* chrome_browser_view = nullptr;
+ if (params.browser_view) {
+ // Don't show most controls.
+ chrome_params.type = Browser::TYPE_POPUP;
+ // Don't show title bar or address.
+ chrome_params.trusted_source = true;
+
+ auto view_impl =
+ static_cast<CefBrowserViewImpl*>(params.browser_view.get());
+
+ chrome_browser_view =
+ static_cast<ChromeBrowserView*>(view_impl->root_view());
+ chrome_params.window = chrome_browser_view;
+
+ auto chrome_widget =
+ static_cast<ChromeBrowserFrame*>(chrome_browser_view->GetWidget());
+ chrome_browser_view->set_frame(chrome_widget);
+ }
+
+ // Create the Browser. This will indirectly create the ChomeBrowserDelegate.
+ // The same params will be used to create a new Browser if the tab is dragged
+ // out of the existing Browser. The returned Browser is owned by the
+ // associated BrowserView.
+ auto browser = Browser::Create(chrome_params);
+
+ bool show_browser = true;
+
+ if (chrome_browser_view) {
+ // Initialize the BrowserFrame and BrowserView and create the controls that
+ // require access to the Browser.
+ chrome_browser_view->InitBrowser(base::WrapUnique(browser),
+ params.browser_view);
+
+ // Don't set theme colors in ContentsWebView::UpdateBackgroundColor.
+ chrome_browser_view->contents_web_view()->SetBackgroundVisible(false);
+
+ // Don't show the browser by default.
+ show_browser = false;
+ }
+
+ if (show_browser) {
+ browser->window()->Show();
+ }
+
+ return browser;
+}
+
+void ChromeBrowserHostImpl::Attach(content::WebContents* web_contents,
+ CefRefPtr<ChromeBrowserHostImpl> opener) {
+ DCHECK(web_contents);
+
+ if (opener) {
+ // Give the opener browser's platform delegate an opportunity to modify the
+ // new browser's platform delegate.
+ opener->platform_delegate_->PopupWebContentsCreated(
+ settings_, client_, web_contents, platform_delegate_.get(),
+ /*is_devtools_popup=*/false);
+ }
+
+ platform_delegate_->WebContentsCreated(web_contents,
+ /*own_web_contents=*/false);
+ contents_delegate_->ObserveWebContents(web_contents);
+
+ // Associate the platform delegate with this browser.
+ platform_delegate_->BrowserCreated(this);
+
+ // Associate the base class with the WebContents.
+ InitializeBrowser();
+
+ // Notify that the browser has been created. These must be delivered in the
+ // expected order.
+
+ if (opener && opener->platform_delegate_) {
+ // 1. Notify the opener browser's platform delegate. With Views this will
+ // result in a call to CefBrowserViewDelegate::OnPopupBrowserViewCreated().
+ // We want to call this method first because the implementation will often
+ // create the Widget for the new popup browser. Without that Widget
+ // CefBrowserHost::GetWindowHandle() will return kNullWindowHandle in
+ // OnAfterCreated(), which breaks client expectations (e.g. clients expect
+ // everything about the browser to be valid at that time).
+ opener->platform_delegate_->PopupBrowserCreated(
+ this,
+ /*is_devtools_popup=*/false);
+ }
+
+ // 2. Notify the browser's LifeSpanHandler. This must always be the first
+ // notification for the browser.
+ {
+ // The WebContents won't be added to the Browser's TabStripModel until later
+ // in the current call stack. Block navigation until that time.
+ auto navigation_lock = browser_info_->CreateNavigationLock();
+ OnAfterCreated();
+ }
+
+ // 3. Notify the platform delegate. With Views this will result in a call to
+ // CefBrowserViewDelegate::OnBrowserCreated().
+ platform_delegate_->NotifyBrowserCreated();
+}
+
+void ChromeBrowserHostImpl::SetBrowser(Browser* browser) {
+ CEF_REQUIRE_UIT();
+ browser_ = browser;
+ static_cast<CefBrowserPlatformDelegateChrome*>(platform_delegate_.get())
+ ->set_chrome_browser(browser);
+ if (browser_) {
+ host_window_handle_ = platform_delegate_->GetHostWindowHandle();
+ }
+}
+
+void ChromeBrowserHostImpl::WindowDestroyed() {
+ CEF_REQUIRE_UIT();
+ if (browser_ && is_views_hosted_) {
+ auto chrome_browser_view =
+ static_cast<ChromeBrowserView*>(browser_->window());
+ chrome_browser_view->Destroyed();
+ }
+
+ platform_delegate_->CloseHostWindow();
+}
+
+bool ChromeBrowserHostImpl::WillBeDestroyed() const {
+ CEF_REQUIRE_UIT();
+ // TODO(chrome): Modify this to support DoClose(), see issue #3294.
+ return !!browser_;
+}
+
+void ChromeBrowserHostImpl::DestroyBrowser() {
+ CEF_REQUIRE_UIT();
+ browser_ = nullptr;
+
+ OnBeforeClose();
+ OnBrowserDestroyed();
+
+ // Disassociate the platform delegate from this browser.
+ platform_delegate_->BrowserDestroyed(this);
+
+ CefBrowserHostBase::DestroyBrowser();
+}
+
+void ChromeBrowserHostImpl::DoCloseBrowser(bool force_close) {
+ CEF_REQUIRE_UIT();
+ if (browser_) {
+ // Like chrome::CloseTab() but specifying the WebContents.
+ const int tab_index = GetCurrentTabIndex();
+ if (tab_index != TabStripModel::kNoTab) {
+ // TODO(chrome): Handle the case where this method returns false,
+ // indicating that the contents were not closed immediately.
+ browser_->tab_strip_model()->CloseWebContentsAt(
+ tab_index, TabCloseTypes::CLOSE_CREATE_HISTORICAL_TAB |
+ TabCloseTypes::CLOSE_USER_GESTURE);
+ }
+ }
+}
+
+int ChromeBrowserHostImpl::GetCurrentTabIndex() const {
+ CEF_REQUIRE_UIT();
+ if (browser_) {
+ return browser_->tab_strip_model()->GetIndexOfWebContents(GetWebContents());
+ }
+ return TabStripModel::kNoTab;
+}
diff --git a/libcef/browser/chrome/chrome_browser_host_impl.h b/libcef/browser/chrome/chrome_browser_host_impl.h
new file mode 100644
index 00000000..effb5205
--- /dev/null
+++ b/libcef/browser/chrome/chrome_browser_host_impl.h
@@ -0,0 +1,162 @@
+// Copyright 2020 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_CHROME_CHROME_BROWSER_HOST_IMPL_H_
+#define CEF_LIBCEF_BROWSER_CHROME_CHROME_BROWSER_HOST_IMPL_H_
+#pragma once
+
+#include <memory>
+
+#include "libcef/browser/browser_host_base.h"
+#include "libcef/browser/chrome/browser_delegate.h"
+
+class Browser;
+class ChromeBrowserDelegate;
+
+// CefBrowser implementation for the chrome runtime. Method calls are delegated
+// to the chrome Browser object or the WebContents as appropriate. See the
+// ChromeBrowserDelegate documentation for additional details. All methods are
+// thread-safe unless otherwise indicated.
+class ChromeBrowserHostImpl : public CefBrowserHostBase {
+ public:
+ // CEF-specific parameters passed via Browser::CreateParams::cef_params and
+ // possibly shared by multiple Browser instances.
+ class DelegateCreateParams : public cef::BrowserDelegate::CreateParams {
+ public:
+ DelegateCreateParams(const CefBrowserCreateParams& create_params)
+ : create_params_(create_params) {}
+
+ CefBrowserCreateParams create_params_;
+ };
+
+ // Create a new Browser with a single tab (WebContents) and associated
+ // ChromeBrowserHostImpl instance.
+ static CefRefPtr<ChromeBrowserHostImpl> Create(
+ const CefBrowserCreateParams& params);
+
+ // Returns the browser associated with the specified RenderViewHost.
+ static CefRefPtr<ChromeBrowserHostImpl> GetBrowserForHost(
+ const content::RenderViewHost* host);
+ // Returns the browser associated with the specified RenderFrameHost.
+ static CefRefPtr<ChromeBrowserHostImpl> GetBrowserForHost(
+ const content::RenderFrameHost* host);
+ // Returns the browser associated with the specified WebContents.
+ static CefRefPtr<ChromeBrowserHostImpl> GetBrowserForContents(
+ const content::WebContents* contents);
+ // Returns the browser associated with the specified global ID.
+ static CefRefPtr<ChromeBrowserHostImpl> GetBrowserForGlobalId(
+ const content::GlobalRenderFrameHostId& global_id);
+ // Returns the browser associated with the specified Browser.
+ static CefRefPtr<ChromeBrowserHostImpl> GetBrowserForBrowser(
+ const Browser* browser);
+
+ ~ChromeBrowserHostImpl() override;
+
+ // CefBrowserContentsDelegate::Observer methods:
+ void OnWebContentsDestroyed(content::WebContents* web_contents) override;
+
+ // CefBrowserHostBase methods called from CefFrameHostImpl:
+ void OnSetFocus(cef_focus_source_t source) override;
+
+ // CefBrowserHost methods:
+ void CloseBrowser(bool force_close) override;
+ bool TryCloseBrowser() override;
+ CefWindowHandle GetWindowHandle() override;
+ CefWindowHandle GetOpenerWindowHandle() override;
+ double GetZoomLevel() override;
+ void SetZoomLevel(double zoomLevel) override;
+ void Find(const CefString& searchText,
+ bool forward,
+ bool matchCase,
+ bool findNext) override;
+ void StopFinding(bool clearSelection) override;
+ void ShowDevTools(const CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient> client,
+ const CefBrowserSettings& settings,
+ const CefPoint& inspect_element_at) override;
+ void CloseDevTools() override;
+ bool HasDevTools() override;
+ bool IsWindowRenderingDisabled() override;
+ void WasResized() override;
+ void WasHidden(bool hidden) override;
+ void NotifyScreenInfoChanged() override;
+ void Invalidate(PaintElementType type) override;
+ void SendExternalBeginFrame() override;
+ void SendTouchEvent(const CefTouchEvent& event) override;
+ void SendCaptureLostEvent() override;
+ int GetWindowlessFrameRate() override;
+ void SetWindowlessFrameRate(int frame_rate) override;
+ void ImeSetComposition(const CefString& text,
+ const std::vector<CefCompositionUnderline>& underlines,
+ const CefRange& replacement_range,
+ const CefRange& selection_range) override;
+ void ImeCommitText(const CefString& text,
+ const CefRange& replacement_range,
+ int relative_cursor_pos) override;
+ void ImeFinishComposingText(bool keep_selection) override;
+ void ImeCancelComposition() override;
+ void DragTargetDragEnter(CefRefPtr<CefDragData> drag_data,
+ const CefMouseEvent& event,
+ DragOperationsMask allowed_ops) override;
+ void DragTargetDragOver(const CefMouseEvent& event,
+ DragOperationsMask allowed_ops) override;
+ void DragTargetDragLeave() override;
+ void DragTargetDrop(const CefMouseEvent& event) override;
+ void DragSourceSystemDragEnded() override;
+ void DragSourceEndedAt(int x, int y, DragOperationsMask op) override;
+ void SetAudioMuted(bool mute) override;
+ bool IsAudioMuted() override;
+ void SetAccessibilityState(cef_state_t accessibility_state) override;
+ void SetAutoResizeEnabled(bool enabled,
+ const CefSize& min_size,
+ const CefSize& max_size) override;
+ CefRefPtr<CefExtension> GetExtension() override;
+ bool IsBackgroundHost() override;
+
+ protected:
+ bool Navigate(const content::OpenURLParams& params) override;
+
+ private:
+ friend class ChromeBrowserDelegate;
+
+ ChromeBrowserHostImpl(
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefClient> client,
+ std::unique_ptr<CefBrowserPlatformDelegate> platform_delegate,
+ scoped_refptr<CefBrowserInfo> browser_info,
+ CefRefPtr<CefRequestContextImpl> request_context);
+
+ // Create a new Browser without initializing the WebContents.
+ static Browser* CreateBrowser(const CefBrowserCreateParams& params);
+
+ // Called from ChromeBrowserDelegate::CreateBrowser when this object is first
+ // created. Must be called on the UI thread.
+ void Attach(content::WebContents* web_contents,
+ CefRefPtr<ChromeBrowserHostImpl> opener);
+
+ // Called from ChromeBrowserDelegate::AddNewContents to take ownership of a
+ // popup WebContents.
+ void AddNewContents(std::unique_ptr<content::WebContents> contents);
+
+ // Called when this object changes Browser ownership (e.g. initially created,
+ // dragging between windows, etc). The old Browser, if any, will be cleared
+ // before the new Browser is added. Must be called on the UI thread.
+ void SetBrowser(Browser* browser);
+
+ // CefBrowserHostBase methods:
+ void WindowDestroyed() override;
+ bool WillBeDestroyed() const override;
+ void DestroyBrowser() override;
+
+ void DoCloseBrowser(bool force_close);
+
+ // Returns the current tab index for the associated WebContents, or
+ // TabStripModel::kNoTab if not found.
+ int GetCurrentTabIndex() const;
+
+ Browser* browser_ = nullptr;
+ CefWindowHandle host_window_handle_ = kNullWindowHandle;
+};
+
+#endif // CEF_LIBCEF_BROWSER_CHROME_CHROME_BROWSER_HOST_IMPL_H_
diff --git a/libcef/browser/chrome/chrome_browser_main_extra_parts_cef.cc b/libcef/browser/chrome/chrome_browser_main_extra_parts_cef.cc
new file mode 100644
index 00000000..87aa49fa
--- /dev/null
+++ b/libcef/browser/chrome/chrome_browser_main_extra_parts_cef.cc
@@ -0,0 +1,52 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/chrome/chrome_browser_main_extra_parts_cef.h"
+
+#include "libcef/browser/chrome/chrome_context_menu_handler.h"
+#include "libcef/browser/context.h"
+#include "libcef/browser/file_dialog_runner.h"
+#include "libcef/browser/net/chrome_scheme_handler.h"
+#include "libcef/browser/permission_prompt.h"
+
+#include "base/task/thread_pool.h"
+#include "chrome/browser/profiles/profile.h"
+
+ChromeBrowserMainExtraPartsCef::ChromeBrowserMainExtraPartsCef() = default;
+
+ChromeBrowserMainExtraPartsCef::~ChromeBrowserMainExtraPartsCef() = default;
+
+void ChromeBrowserMainExtraPartsCef::PostProfileInit(Profile* profile,
+ bool is_initial_profile) {
+ if (!is_initial_profile) {
+ return;
+ }
+
+ CefRequestContextSettings settings;
+ CefContext::Get()->PopulateGlobalRequestContextSettings(&settings);
+
+ // Use the existing path for the initial profile.
+ CefString(&settings.cache_path) = profile->GetPath().value();
+
+ // Create the global RequestContext.
+ global_request_context_ =
+ CefRequestContextImpl::CreateGlobalRequestContext(settings);
+}
+
+void ChromeBrowserMainExtraPartsCef::PreMainMessageLoopRun() {
+ background_task_runner_ = base::ThreadPool::CreateSingleThreadTaskRunner(
+ {base::TaskPriority::BEST_EFFORT,
+ base::TaskShutdownBehavior::BLOCK_SHUTDOWN, base::MayBlock()});
+ user_visible_task_runner_ = base::ThreadPool::CreateSingleThreadTaskRunner(
+ {base::TaskPriority::USER_VISIBLE,
+ base::TaskShutdownBehavior::BLOCK_SHUTDOWN, base::MayBlock()});
+ user_blocking_task_runner_ = base::ThreadPool::CreateSingleThreadTaskRunner(
+ {base::TaskPriority::USER_BLOCKING,
+ base::TaskShutdownBehavior::BLOCK_SHUTDOWN, base::MayBlock()});
+
+ scheme::RegisterWebUIControllerFactory();
+ context_menu::RegisterMenuCreatedCallback();
+ file_dialog_runner::RegisterFactory();
+ permission_prompt::RegisterCreateCallback();
+}
diff --git a/libcef/browser/chrome/chrome_browser_main_extra_parts_cef.h b/libcef/browser/chrome/chrome_browser_main_extra_parts_cef.h
new file mode 100644
index 00000000..74a6c327
--- /dev/null
+++ b/libcef/browser/chrome/chrome_browser_main_extra_parts_cef.h
@@ -0,0 +1,57 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_CHROME_CHROME_BROWSER_MAIN_EXTRA_PARTS_CEF_H_
+#define CEF_LIBCEF_BROWSER_CHROME_CHROME_BROWSER_MAIN_EXTRA_PARTS_CEF_H_
+
+#include <memory>
+
+#include "libcef/browser/request_context_impl.h"
+
+#include "base/task/single_thread_task_runner.h"
+#include "chrome/browser/chrome_browser_main_extra_parts.h"
+
+// Wrapper that owns and initialize the browser memory-related extra parts.
+class ChromeBrowserMainExtraPartsCef : public ChromeBrowserMainExtraParts {
+ public:
+ ChromeBrowserMainExtraPartsCef();
+
+ ChromeBrowserMainExtraPartsCef(const ChromeBrowserMainExtraPartsCef&) =
+ delete;
+ ChromeBrowserMainExtraPartsCef& operator=(
+ const ChromeBrowserMainExtraPartsCef&) = delete;
+
+ ~ChromeBrowserMainExtraPartsCef() override;
+
+ CefRefPtr<CefRequestContextImpl> request_context() const {
+ return global_request_context_;
+ }
+
+ scoped_refptr<base::SingleThreadTaskRunner> background_task_runner() const {
+ return background_task_runner_;
+ }
+ scoped_refptr<base::SingleThreadTaskRunner> user_visible_task_runner() const {
+ return user_visible_task_runner_;
+ }
+ scoped_refptr<base::SingleThreadTaskRunner> user_blocking_task_runner()
+ const {
+ return user_blocking_task_runner_;
+ }
+
+ private:
+ // ChromeBrowserMainExtraParts overrides.
+ void PostProfileInit(Profile* profile, bool is_initial_profile) override;
+ void PreMainMessageLoopRun() override;
+
+ CefRefPtr<CefRequestContextImpl> global_request_context_;
+
+ // Blocking task runners exposed via CefTaskRunner. For consistency with
+ // previous named thread behavior always execute all pending tasks before
+ // shutdown (e.g. to make sure critical data is saved to disk).
+ scoped_refptr<base::SingleThreadTaskRunner> background_task_runner_;
+ scoped_refptr<base::SingleThreadTaskRunner> user_visible_task_runner_;
+ scoped_refptr<base::SingleThreadTaskRunner> user_blocking_task_runner_;
+};
+
+#endif // CEF_LIBCEF_BROWSER_CHROME_CHROME_BROWSER_MAIN_EXTRA_PARTS_CEF_H_
diff --git a/libcef/browser/chrome/chrome_content_browser_client_cef.cc b/libcef/browser/chrome/chrome_content_browser_client_cef.cc
new file mode 100644
index 00000000..c28d097a
--- /dev/null
+++ b/libcef/browser/chrome/chrome_content_browser_client_cef.cc
@@ -0,0 +1,502 @@
+// Copyright 2020 The Chromium Embedded Framework Authors.
+// Portions copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/chrome/chrome_content_browser_client_cef.h"
+
+#include <tuple>
+
+#include "libcef/browser/browser_frame.h"
+#include "libcef/browser/browser_info_manager.h"
+#include "libcef/browser/browser_manager.h"
+#include "libcef/browser/certificate_query.h"
+#include "libcef/browser/chrome/chrome_browser_host_impl.h"
+#include "libcef/browser/chrome/chrome_browser_main_extra_parts_cef.h"
+#include "libcef/browser/context.h"
+#include "libcef/browser/net/chrome_scheme_handler.h"
+#include "libcef/browser/net/throttle_handler.h"
+#include "libcef/browser/net_service/cookie_manager_impl.h"
+#include "libcef/browser/net_service/login_delegate.h"
+#include "libcef/browser/net_service/proxy_url_loader_factory.h"
+#include "libcef/browser/net_service/resource_request_handler_wrapper.h"
+#include "libcef/browser/prefs/browser_prefs.h"
+#include "libcef/browser/prefs/renderer_prefs.h"
+#include "libcef/common/app_manager.h"
+#include "libcef/common/cef_switches.h"
+#include "libcef/common/command_line_impl.h"
+
+#include "base/command_line.h"
+#include "base/path_service.h"
+#include "chrome/browser/chrome_browser_main.h"
+#include "chrome/browser/net/system_network_context_manager.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/chrome_switches.h"
+#include "content/public/browser/navigation_throttle.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
+#include "content/public/browser/render_widget_host_view.h"
+#include "content/public/browser/weak_document_ptr.h"
+#include "content/public/common/content_switches.h"
+#include "third_party/blink/public/common/web_preferences/web_preferences.h"
+#include "third_party/blink/public/mojom/loader/resource_load_info.mojom-shared.h"
+
+namespace {
+
+void HandleExternalProtocolHelper(
+ ChromeContentBrowserClientCef* self,
+ content::WebContents::Getter web_contents_getter,
+ int frame_tree_node_id,
+ content::NavigationUIData* navigation_data,
+ bool is_primary_main_frame,
+ bool is_in_fenced_frame_tree,
+ network::mojom::WebSandboxFlags sandbox_flags,
+ const network::ResourceRequest& resource_request,
+ const absl::optional<url::Origin>& initiating_origin,
+ content::WeakDocumentPtr initiator_document) {
+ // May return nullptr if frame has been deleted or a cross-document navigation
+ // has committed in the same RenderFrameHost.
+ auto initiator_rfh = initiator_document.AsRenderFrameHostIfValid();
+ if (!initiator_rfh) {
+ return;
+ }
+
+ // Match the logic of the original call in
+ // NavigationURLLoaderImpl::PrepareForNonInterceptedRequest.
+ self->HandleExternalProtocol(
+ resource_request.url, web_contents_getter, frame_tree_node_id,
+ navigation_data, is_primary_main_frame, is_in_fenced_frame_tree,
+ sandbox_flags,
+ static_cast<ui::PageTransition>(resource_request.transition_type),
+ resource_request.has_user_gesture, initiating_origin, initiator_rfh,
+ nullptr);
+}
+
+} // namespace
+
+ChromeContentBrowserClientCef::ChromeContentBrowserClientCef() = default;
+ChromeContentBrowserClientCef::~ChromeContentBrowserClientCef() = default;
+
+std::unique_ptr<content::BrowserMainParts>
+ChromeContentBrowserClientCef::CreateBrowserMainParts(
+ bool is_integration_test) {
+ auto main_parts =
+ ChromeContentBrowserClient::CreateBrowserMainParts(is_integration_test);
+ auto browser_main_parts = std::make_unique<ChromeBrowserMainExtraPartsCef>();
+ browser_main_parts_ = browser_main_parts.get();
+ static_cast<ChromeBrowserMainParts*>(main_parts.get())
+ ->AddParts(std::move(browser_main_parts));
+ return main_parts;
+}
+
+void ChromeContentBrowserClientCef::AppendExtraCommandLineSwitches(
+ base::CommandLine* command_line,
+ int child_process_id) {
+ ChromeContentBrowserClient::AppendExtraCommandLineSwitches(command_line,
+ child_process_id);
+
+ // Necessary to launch sub-processes in the correct mode.
+ command_line->AppendSwitch(switches::kEnableChromeRuntime);
+
+ // Necessary to populate DIR_USER_DATA in sub-processes.
+ // See resource_util.cc GetUserDataPath.
+ base::FilePath user_data_dir;
+ if (base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir)) {
+ command_line->AppendSwitchPath(switches::kUserDataDir, user_data_dir);
+ }
+
+ const base::CommandLine* browser_cmd = base::CommandLine::ForCurrentProcess();
+
+ {
+ // Propagate the following switches to all command lines (along with any
+ // associated values) if present in the browser command line.
+ static const char* const kSwitchNames[] = {
+ switches::kUserAgentProductAndVersion,
+ };
+ command_line->CopySwitchesFrom(*browser_cmd, kSwitchNames,
+ std::size(kSwitchNames));
+ }
+
+ const std::string& process_type =
+ command_line->GetSwitchValueASCII(switches::kProcessType);
+ if (process_type == switches::kRendererProcess) {
+ // Propagate the following switches to the renderer command line (along with
+ // any associated values) if present in the browser command line.
+ static const char* const kSwitchNames[] = {
+ switches::kUncaughtExceptionStackSize,
+ };
+ command_line->CopySwitchesFrom(*browser_cmd, kSwitchNames,
+ std::size(kSwitchNames));
+ }
+
+ CefRefPtr<CefApp> app = CefAppManager::Get()->GetApplication();
+ if (app.get()) {
+ CefRefPtr<CefBrowserProcessHandler> handler =
+ app->GetBrowserProcessHandler();
+ if (handler.get()) {
+ CefRefPtr<CefCommandLineImpl> commandLinePtr(
+ new CefCommandLineImpl(command_line, false, false));
+ handler->OnBeforeChildProcessLaunch(commandLinePtr.get());
+ std::ignore = commandLinePtr->Detach(nullptr);
+ }
+ }
+}
+
+void ChromeContentBrowserClientCef::RenderProcessWillLaunch(
+ content::RenderProcessHost* host) {
+ ChromeContentBrowserClient::RenderProcessWillLaunch(host);
+
+ // If the renderer process crashes then the host may already have
+ // CefBrowserInfoManager as an observer. Try to remove it first before adding
+ // to avoid DCHECKs.
+ host->RemoveObserver(CefBrowserInfoManager::GetInstance());
+ host->AddObserver(CefBrowserInfoManager::GetInstance());
+}
+
+void ChromeContentBrowserClientCef::AllowCertificateError(
+ content::WebContents* web_contents,
+ int cert_error,
+ const net::SSLInfo& ssl_info,
+ const GURL& request_url,
+ bool is_main_frame_request,
+ bool strict_enforcement,
+ base::OnceCallback<void(content::CertificateRequestResultType)> callback) {
+ auto returned_callback = certificate_query::AllowCertificateError(
+ web_contents, cert_error, ssl_info, request_url, is_main_frame_request,
+ strict_enforcement, std::move(callback), /*default_disallow=*/false);
+ if (returned_callback.is_null()) {
+ // The error was handled.
+ return;
+ }
+
+ // Proceed with default handling.
+ ChromeContentBrowserClient::AllowCertificateError(
+ web_contents, cert_error, ssl_info, request_url, is_main_frame_request,
+ strict_enforcement, std::move(returned_callback));
+}
+
+bool ChromeContentBrowserClientCef::CanCreateWindow(
+ content::RenderFrameHost* opener,
+ const GURL& opener_url,
+ const GURL& opener_top_level_frame_url,
+ const url::Origin& source_origin,
+ content::mojom::WindowContainerType container_type,
+ const GURL& target_url,
+ const content::Referrer& referrer,
+ const std::string& frame_name,
+ WindowOpenDisposition disposition,
+ const blink::mojom::WindowFeatures& features,
+ bool user_gesture,
+ bool opener_suppressed,
+ bool* no_javascript_access) {
+ // The chrome layer has popup blocker, extensions, etc.
+ if (!ChromeContentBrowserClient::CanCreateWindow(
+ opener, opener_url, opener_top_level_frame_url, source_origin,
+ container_type, target_url, referrer, frame_name, disposition,
+ features, user_gesture, opener_suppressed, no_javascript_access)) {
+ return false;
+ }
+
+ return CefBrowserInfoManager::GetInstance()->CanCreateWindow(
+ opener, target_url, referrer, frame_name, disposition, features,
+ user_gesture, opener_suppressed, no_javascript_access);
+}
+
+void ChromeContentBrowserClientCef::OverrideWebkitPrefs(
+ content::WebContents* web_contents,
+ blink::web_pref::WebPreferences* prefs) {
+ renderer_prefs::SetDefaultPrefs(*prefs);
+
+ ChromeContentBrowserClient::OverrideWebkitPrefs(web_contents, prefs);
+
+ SkColor base_background_color;
+ auto browser = ChromeBrowserHostImpl::GetBrowserForContents(web_contents);
+ if (browser) {
+ renderer_prefs::SetCefPrefs(browser->settings(), *prefs);
+
+ // Set the background color for the WebView.
+ base_background_color = browser->GetBackgroundColor();
+ } else {
+ // We don't know for sure that the browser will be windowless but assume
+ // that the global windowless state is likely to be accurate.
+ base_background_color =
+ CefContext::Get()->GetBackgroundColor(nullptr, STATE_DEFAULT);
+ }
+
+ web_contents->SetPageBaseBackgroundColor(base_background_color);
+}
+
+bool ChromeContentBrowserClientCef::WillCreateURLLoaderFactory(
+ content::BrowserContext* browser_context,
+ content::RenderFrameHost* frame,
+ int render_process_id,
+ URLLoaderFactoryType type,
+ const url::Origin& request_initiator,
+ absl::optional<int64_t> navigation_id,
+ ukm::SourceIdObj ukm_source_id,
+ mojo::PendingReceiver<network::mojom::URLLoaderFactory>* factory_receiver,
+ mojo::PendingRemote<network::mojom::TrustedURLLoaderHeaderClient>*
+ header_client,
+ bool* bypass_redirect_checks,
+ bool* disable_secure_dns,
+ network::mojom::URLLoaderFactoryOverridePtr* factory_override) {
+ // Don't intercept requests for Profiles that were not created by CEF.
+ // For example, the User Manager profile created via
+ // profiles::CreateSystemProfileForUserManager.
+ auto profile = Profile::FromBrowserContext(browser_context);
+ if (!CefBrowserContext::FromProfile(profile)) {
+ return ChromeContentBrowserClient::WillCreateURLLoaderFactory(
+ browser_context, frame, render_process_id, type, request_initiator,
+ navigation_id, ukm_source_id, factory_receiver, header_client,
+ bypass_redirect_checks, disable_secure_dns, factory_override);
+ }
+
+ // Based on content/browser/devtools/devtools_instrumentation.cc
+ // WillCreateURLLoaderFactoryInternal.
+ network::mojom::URLLoaderFactoryOverridePtr cef_override(
+ network::mojom::URLLoaderFactoryOverride::New());
+ // If caller passed some existing overrides, use those.
+ // Otherwise, use our local var, then if handlers actually
+ // decide to intercept, move it to |factory_override|.
+ network::mojom::URLLoaderFactoryOverridePtr* handler_override =
+ factory_override && *factory_override ? factory_override : &cef_override;
+ network::mojom::URLLoaderFactoryOverride* intercepting_factory =
+ handler_override->get();
+
+ // If we're the first interceptor to install an override, make a
+ // remote/receiver pair, then handle this similarly to appending
+ // a proxy to existing override.
+ if (!intercepting_factory->overriding_factory) {
+ DCHECK(!intercepting_factory->overridden_factory_receiver);
+ intercepting_factory->overridden_factory_receiver =
+ intercepting_factory->overriding_factory
+ .InitWithNewPipeAndPassReceiver();
+ }
+
+ // TODO(chrome): Is it necessary to proxy |header_client| callbacks?
+ bool use_proxy = ChromeContentBrowserClient::WillCreateURLLoaderFactory(
+ browser_context, frame, render_process_id, type, request_initiator,
+ navigation_id, ukm_source_id,
+ &(intercepting_factory->overridden_factory_receiver),
+ /*header_client=*/nullptr, bypass_redirect_checks, disable_secure_dns,
+ handler_override);
+
+ if (use_proxy) {
+ DCHECK(intercepting_factory->overriding_factory);
+ DCHECK(intercepting_factory->overridden_factory_receiver);
+ if (!factory_override) {
+ // Not a subresource navigation, so just override the target receiver.
+ mojo::FusePipes(std::move(*factory_receiver),
+ std::move(cef_override->overriding_factory));
+ *factory_receiver = std::move(cef_override->overridden_factory_receiver);
+ } else if (!*factory_override) {
+ // No other overrides, so just returns ours as is.
+ *factory_override = network::mojom::URLLoaderFactoryOverride::New(
+ std::move(cef_override->overriding_factory),
+ std::move(cef_override->overridden_factory_receiver), false);
+ }
+ // ... else things are already taken care of, as handler_override was
+ // pointing to factory override and we've done all magic in-place.
+ DCHECK(!cef_override->overriding_factory);
+ DCHECK(!cef_override->overridden_factory_receiver);
+ }
+
+ auto request_handler = net_service::CreateInterceptedRequestHandler(
+ browser_context, frame, render_process_id,
+ type == URLLoaderFactoryType::kNavigation,
+ type == URLLoaderFactoryType::kDownload, request_initiator);
+
+ net_service::ProxyURLLoaderFactory::CreateProxy(
+ browser_context, factory_receiver, header_client,
+ std::move(request_handler));
+
+ return true;
+}
+
+bool ChromeContentBrowserClientCef::HandleExternalProtocol(
+ const GURL& url,
+ content::WebContents::Getter web_contents_getter,
+ int frame_tree_node_id,
+ content::NavigationUIData* navigation_data,
+ bool is_primary_main_frame,
+ bool is_in_fenced_frame_tree,
+ network::mojom::WebSandboxFlags sandbox_flags,
+ ui::PageTransition page_transition,
+ bool has_user_gesture,
+ const absl::optional<url::Origin>& initiating_origin,
+ content::RenderFrameHost* initiator_document,
+ mojo::PendingRemote<network::mojom::URLLoaderFactory>* out_factory) {
+ // |out_factory| will be non-nullptr when this method is initially called
+ // from NavigationURLLoaderImpl::PrepareForNonInterceptedRequest.
+ if (out_factory) {
+ // Let the other HandleExternalProtocol variant handle the request.
+ return false;
+ }
+
+ // The request was unhandled and we've recieved a callback from
+ // HandleExternalProtocolHelper. Forward to the chrome layer for default
+ // handling.
+ return ChromeContentBrowserClient::HandleExternalProtocol(
+ url, web_contents_getter, frame_tree_node_id, navigation_data,
+ is_primary_main_frame, is_in_fenced_frame_tree, sandbox_flags,
+ page_transition, has_user_gesture, initiating_origin, initiator_document,
+ nullptr);
+}
+
+bool ChromeContentBrowserClientCef::HandleExternalProtocol(
+ content::WebContents::Getter web_contents_getter,
+ int frame_tree_node_id,
+ content::NavigationUIData* navigation_data,
+ bool is_primary_main_frame,
+ bool is_in_fenced_frame_tree,
+ network::mojom::WebSandboxFlags sandbox_flags,
+ const network::ResourceRequest& resource_request,
+ const absl::optional<url::Origin>& initiating_origin,
+ content::RenderFrameHost* initiator_document,
+ mojo::PendingRemote<network::mojom::URLLoaderFactory>* out_factory) {
+ mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver =
+ out_factory->InitWithNewPipeAndPassReceiver();
+
+ auto weak_initiator_document = initiator_document
+ ? initiator_document->GetWeakDocumentPtr()
+ : content::WeakDocumentPtr();
+
+ // HandleExternalProtocolHelper may be called if nothing handles the request.
+ auto request_handler = net_service::CreateInterceptedRequestHandler(
+ web_contents_getter, frame_tree_node_id, resource_request,
+ base::BindRepeating(HandleExternalProtocolHelper, base::Unretained(this),
+ web_contents_getter, frame_tree_node_id,
+ navigation_data, is_primary_main_frame,
+ is_in_fenced_frame_tree, sandbox_flags,
+ resource_request, initiating_origin,
+ std::move(weak_initiator_document)));
+
+ net_service::ProxyURLLoaderFactory::CreateProxy(
+ web_contents_getter, std::move(receiver), std::move(request_handler));
+ return true;
+}
+
+std::vector<std::unique_ptr<content::NavigationThrottle>>
+ChromeContentBrowserClientCef::CreateThrottlesForNavigation(
+ content::NavigationHandle* navigation_handle) {
+ auto throttles = ChromeContentBrowserClient::CreateThrottlesForNavigation(
+ navigation_handle);
+ throttle::CreateThrottlesForNavigation(navigation_handle, throttles);
+ return throttles;
+}
+
+bool ChromeContentBrowserClientCef::ConfigureNetworkContextParams(
+ content::BrowserContext* context,
+ bool in_memory,
+ const base::FilePath& relative_partition_path,
+ network::mojom::NetworkContextParams* network_context_params,
+ cert_verifier::mojom::CertVerifierCreationParams*
+ cert_verifier_creation_params) {
+ // This method may be called during shutdown when using multi-threaded
+ // message loop mode. In that case exit early to avoid crashes.
+ if (!SystemNetworkContextManager::GetInstance()) {
+ // Cancel NetworkContext creation in
+ // StoragePartitionImpl::InitNetworkContext.
+ return false;
+ }
+
+ ChromeContentBrowserClient::ConfigureNetworkContextParams(
+ context, in_memory, relative_partition_path, network_context_params,
+ cert_verifier_creation_params);
+
+ auto cef_context = CefBrowserContext::FromBrowserContext(context);
+ network_context_params->cookieable_schemes =
+ cef_context ? cef_context->GetCookieableSchemes()
+ : CefBrowserContext::GetGlobalCookieableSchemes();
+
+ // Prefer the CEF settings configuration, if specified, instead of the
+ // kAcceptLanguages preference which is controlled by the
+ // chrome://settings/languages configuration.
+ const std::string& accept_language_list =
+ browser_prefs::GetAcceptLanguageList(cef_context, /*browser=*/nullptr,
+ /*expand=*/true);
+ if (!accept_language_list.empty() &&
+ accept_language_list != network_context_params->accept_language) {
+ network_context_params->accept_language = accept_language_list;
+ }
+
+ return true;
+}
+
+std::unique_ptr<content::LoginDelegate>
+ChromeContentBrowserClientCef::CreateLoginDelegate(
+ const net::AuthChallengeInfo& auth_info,
+ content::WebContents* web_contents,
+ const content::GlobalRequestID& request_id,
+ bool is_request_for_main_frame,
+ const GURL& url,
+ scoped_refptr<net::HttpResponseHeaders> response_headers,
+ bool first_auth_attempt,
+ LoginAuthRequiredCallback auth_required_callback) {
+ // |web_contents| is nullptr for CefURLRequests without an associated frame.
+ if (!web_contents || base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableChromeLoginPrompt)) {
+ // Delegate auth callbacks to GetAuthCredentials.
+ return std::make_unique<net_service::LoginDelegate>(
+ auth_info, web_contents, request_id, url,
+ std::move(auth_required_callback));
+ }
+
+ return ChromeContentBrowserClient::CreateLoginDelegate(
+ auth_info, web_contents, request_id, is_request_for_main_frame, url,
+ response_headers, first_auth_attempt, std::move(auth_required_callback));
+}
+
+void ChromeContentBrowserClientCef::BrowserURLHandlerCreated(
+ content::BrowserURLHandler* handler) {
+ // Register the Chrome handlers first for proper URL rewriting.
+ ChromeContentBrowserClient::BrowserURLHandlerCreated(handler);
+ scheme::BrowserURLHandlerCreated(handler);
+}
+
+bool ChromeContentBrowserClientCef::IsWebUIAllowedToMakeNetworkRequests(
+ const url::Origin& origin) {
+ return scheme::IsWebUIAllowedToMakeNetworkRequests(origin);
+}
+
+void ChromeContentBrowserClientCef::ExposeInterfacesToRenderer(
+ service_manager::BinderRegistry* registry,
+ blink::AssociatedInterfaceRegistry* associated_registry,
+ content::RenderProcessHost* host) {
+ ChromeContentBrowserClient::ExposeInterfacesToRenderer(
+ registry, associated_registry, host);
+
+ CefBrowserManager::ExposeInterfacesToRenderer(registry, associated_registry,
+ host);
+}
+
+void ChromeContentBrowserClientCef::RegisterBrowserInterfaceBindersForFrame(
+ content::RenderFrameHost* render_frame_host,
+ mojo::BinderMapWithContext<content::RenderFrameHost*>* map) {
+ ChromeContentBrowserClient::RegisterBrowserInterfaceBindersForFrame(
+ render_frame_host, map);
+
+ CefBrowserFrame::RegisterBrowserInterfaceBindersForFrame(render_frame_host,
+ map);
+}
+
+CefRefPtr<CefRequestContextImpl>
+ChromeContentBrowserClientCef::request_context() const {
+ return browser_main_parts_->request_context();
+}
+
+scoped_refptr<base::SingleThreadTaskRunner>
+ChromeContentBrowserClientCef::background_task_runner() const {
+ return browser_main_parts_->background_task_runner();
+}
+
+scoped_refptr<base::SingleThreadTaskRunner>
+ChromeContentBrowserClientCef::user_visible_task_runner() const {
+ return browser_main_parts_->user_visible_task_runner();
+}
+
+scoped_refptr<base::SingleThreadTaskRunner>
+ChromeContentBrowserClientCef::user_blocking_task_runner() const {
+ return browser_main_parts_->user_blocking_task_runner();
+}
diff --git a/libcef/browser/chrome/chrome_content_browser_client_cef.h b/libcef/browser/chrome/chrome_content_browser_client_cef.h
new file mode 100644
index 00000000..ef2cdd75
--- /dev/null
+++ b/libcef/browser/chrome/chrome_content_browser_client_cef.h
@@ -0,0 +1,137 @@
+// Copyright 2020 The Chromium Embedded Framework Authors.
+// Portions copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_CHROME_CHROME_CONTENT_BROWSER_CLIENT_CEF_
+#define CEF_LIBCEF_BROWSER_CHROME_CHROME_CONTENT_BROWSER_CLIENT_CEF_
+
+#include <memory>
+
+#include "libcef/browser/request_context_impl.h"
+
+#include "chrome/browser/chrome_content_browser_client.h"
+
+class ChromeBrowserMainExtraPartsCef;
+
+// CEF override of ChromeContentBrowserClient.
+class ChromeContentBrowserClientCef : public ChromeContentBrowserClient {
+ public:
+ ChromeContentBrowserClientCef();
+
+ ChromeContentBrowserClientCef(const ChromeContentBrowserClientCef&) = delete;
+ ChromeContentBrowserClientCef& operator=(
+ const ChromeContentBrowserClientCef&) = delete;
+
+ ~ChromeContentBrowserClientCef() override;
+
+ // ChromeContentBrowserClient overrides.
+ std::unique_ptr<content::BrowserMainParts> CreateBrowserMainParts(
+ bool is_integration_test) override;
+ void AppendExtraCommandLineSwitches(base::CommandLine* command_line,
+ int child_process_id) override;
+ void RenderProcessWillLaunch(content::RenderProcessHost* host) override;
+ void AllowCertificateError(
+ content::WebContents* web_contents,
+ int cert_error,
+ const net::SSLInfo& ssl_info,
+ const GURL& request_url,
+ bool is_main_frame_request,
+ bool strict_enforcement,
+ base::OnceCallback<void(content::CertificateRequestResultType)> callback)
+ override;
+ bool CanCreateWindow(content::RenderFrameHost* opener,
+ const GURL& opener_url,
+ const GURL& opener_top_level_frame_url,
+ const url::Origin& source_origin,
+ content::mojom::WindowContainerType container_type,
+ const GURL& target_url,
+ const content::Referrer& referrer,
+ const std::string& frame_name,
+ WindowOpenDisposition disposition,
+ const blink::mojom::WindowFeatures& features,
+ bool user_gesture,
+ bool opener_suppressed,
+ bool* no_javascript_access) override;
+ void OverrideWebkitPrefs(content::WebContents* web_contents,
+ blink::web_pref::WebPreferences* prefs) override;
+ bool WillCreateURLLoaderFactory(
+ content::BrowserContext* browser_context,
+ content::RenderFrameHost* frame,
+ int render_process_id,
+ URLLoaderFactoryType type,
+ const url::Origin& request_initiator,
+ absl::optional<int64_t> navigation_id,
+ ukm::SourceIdObj ukm_source_id,
+ mojo::PendingReceiver<network::mojom::URLLoaderFactory>* factory_receiver,
+ mojo::PendingRemote<network::mojom::TrustedURLLoaderHeaderClient>*
+ header_client,
+ bool* bypass_redirect_checks,
+ bool* disable_secure_dns,
+ network::mojom::URLLoaderFactoryOverridePtr* factory_override) override;
+ bool HandleExternalProtocol(
+ const GURL& url,
+ content::WebContents::Getter web_contents_getter,
+ int frame_tree_node_id,
+ content::NavigationUIData* navigation_data,
+ bool is_primary_main_frame,
+ bool is_in_fenced_frame_tree,
+ network::mojom::WebSandboxFlags sandbox_flags,
+ ui::PageTransition page_transition,
+ bool has_user_gesture,
+ const absl::optional<url::Origin>& initiating_origin,
+ content::RenderFrameHost* initiator_document,
+ mojo::PendingRemote<network::mojom::URLLoaderFactory>* out_factory)
+ override;
+ bool HandleExternalProtocol(
+ content::WebContents::Getter web_contents_getter,
+ int frame_tree_node_id,
+ content::NavigationUIData* navigation_data,
+ bool is_primary_main_frame,
+ bool is_in_fenced_frame_tree,
+ network::mojom::WebSandboxFlags sandbox_flags,
+ const network::ResourceRequest& request,
+ const absl::optional<url::Origin>& initiating_origin,
+ content::RenderFrameHost* initiator_document,
+ mojo::PendingRemote<network::mojom::URLLoaderFactory>* out_factory)
+ override;
+ std::vector<std::unique_ptr<content::NavigationThrottle>>
+ CreateThrottlesForNavigation(
+ content::NavigationHandle* navigation_handle) override;
+ bool ConfigureNetworkContextParams(
+ content::BrowserContext* context,
+ bool in_memory,
+ const base::FilePath& relative_partition_path,
+ network::mojom::NetworkContextParams* network_context_params,
+ cert_verifier::mojom::CertVerifierCreationParams*
+ cert_verifier_creation_params) override;
+ std::unique_ptr<content::LoginDelegate> CreateLoginDelegate(
+ const net::AuthChallengeInfo& auth_info,
+ content::WebContents* web_contents,
+ const content::GlobalRequestID& request_id,
+ bool is_request_for_main_frame,
+ const GURL& url,
+ scoped_refptr<net::HttpResponseHeaders> response_headers,
+ bool first_auth_attempt,
+ LoginAuthRequiredCallback auth_required_callback) override;
+ void BrowserURLHandlerCreated(content::BrowserURLHandler* handler) override;
+ bool IsWebUIAllowedToMakeNetworkRequests(const url::Origin& origin) override;
+ void ExposeInterfacesToRenderer(
+ service_manager::BinderRegistry* registry,
+ blink::AssociatedInterfaceRegistry* associated_registry,
+ content::RenderProcessHost* render_process_host) override;
+ void RegisterBrowserInterfaceBindersForFrame(
+ content::RenderFrameHost* render_frame_host,
+ mojo::BinderMapWithContext<content::RenderFrameHost*>* map) override;
+
+ CefRefPtr<CefRequestContextImpl> request_context() const;
+
+ scoped_refptr<base::SingleThreadTaskRunner> background_task_runner() const;
+ scoped_refptr<base::SingleThreadTaskRunner> user_visible_task_runner() const;
+ scoped_refptr<base::SingleThreadTaskRunner> user_blocking_task_runner() const;
+
+ private:
+ ChromeBrowserMainExtraPartsCef* browser_main_parts_ = nullptr;
+};
+
+#endif // CEF_LIBCEF_BROWSER_CHROME_CHROME_CONTENT_BROWSER_CLIENT_CEF_
diff --git a/libcef/browser/chrome/chrome_context_menu_handler.cc b/libcef/browser/chrome/chrome_context_menu_handler.cc
new file mode 100644
index 00000000..95fa5403
--- /dev/null
+++ b/libcef/browser/chrome/chrome_context_menu_handler.cc
@@ -0,0 +1,214 @@
+// Copyright (c) 2021 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#include "libcef/browser/chrome/chrome_context_menu_handler.h"
+
+#include "libcef/browser/browser_host_base.h"
+#include "libcef/browser/context_menu_params_impl.h"
+#include "libcef/browser/simple_menu_model_impl.h"
+
+#include "chrome/browser/renderer_context_menu/render_view_context_menu.h"
+
+namespace context_menu {
+
+namespace {
+
+// Lifespan is controlled by RenderViewContextMenu.
+class CefContextMenuObserver : public RenderViewContextMenuObserver,
+ public CefSimpleMenuModelImpl::StateDelegate {
+ public:
+ CefContextMenuObserver(RenderViewContextMenu* context_menu,
+ CefRefPtr<CefBrowserHostBase> browser,
+ CefRefPtr<CefContextMenuHandler> handler)
+ : context_menu_(context_menu), browser_(browser), handler_(handler) {}
+
+ CefContextMenuObserver(const CefContextMenuObserver&) = delete;
+ CefContextMenuObserver& operator=(const CefContextMenuObserver&) = delete;
+
+ // RenderViewContextMenuObserver methods:
+
+ void InitMenu(const content::ContextMenuParams& params) override {
+ params_ = new CefContextMenuParamsImpl(
+ const_cast<content::ContextMenuParams*>(&context_menu_->params()));
+ model_ = new CefSimpleMenuModelImpl(
+ const_cast<ui::SimpleMenuModel*>(&context_menu_->menu_model()),
+ context_menu_, this, /*is_owned=*/false, /*is_popup=*/false);
+
+ handler_->OnBeforeContextMenu(browser_, GetFrame(), params_, model_);
+ }
+
+ bool IsCommandIdSupported(int command_id) override {
+ // Always claim support for the reserved user ID range.
+ if (command_id >= MENU_ID_USER_FIRST && command_id <= MENU_ID_USER_LAST) {
+ return true;
+ }
+
+ // Also claim support in specific cases where an ItemInfo exists.
+ return GetItemInfo(command_id) != nullptr;
+ }
+
+ // Only called if IsCommandIdSupported() returns true.
+ bool IsCommandIdEnabled(int command_id) override {
+ // Always return true to use the SimpleMenuModel state.
+ return true;
+ }
+
+ // Only called if IsCommandIdSupported() returns true.
+ bool IsCommandIdChecked(int command_id) override {
+ auto* info = GetItemInfo(command_id);
+ return info ? info->checked : false;
+ }
+
+ // Only called if IsCommandIdSupported() returns true.
+ bool GetAccelerator(int command_id, ui::Accelerator* accel) override {
+ auto* info = GetItemInfo(command_id);
+ if (info && info->accel) {
+ *accel = *info->accel;
+ return true;
+ }
+ return false;
+ }
+
+ void CommandWillBeExecuted(int command_id) override {
+ if (handler_->OnContextMenuCommand(browser_, GetFrame(), params_,
+ command_id, EVENTFLAG_NONE)) {
+ // Create an ItemInfo so that we get the ExecuteCommand() callback
+ // instead of the default handler.
+ GetOrCreateItemInfo(command_id);
+ }
+ }
+
+ // Only called if IsCommandIdSupported() returns true.
+ void ExecuteCommand(int command_id) override {
+ auto* info = GetItemInfo(command_id);
+ if (info) {
+ // In case it was added in CommandWillBeExecuted().
+ MaybeDeleteItemInfo(command_id, info);
+ }
+ }
+
+ void OnMenuClosed() override {
+ handler_->OnContextMenuDismissed(browser_, GetFrame());
+ model_->Detach();
+
+ // Clear stored state because this object won't be deleted until a new
+ // context menu is created or the associated browser is destroyed.
+ browser_ = nullptr;
+ handler_ = nullptr;
+ params_ = nullptr;
+ model_ = nullptr;
+ iteminfomap_.clear();
+ }
+
+ // CefSimpleMenuModelImpl::StateDelegate methods:
+
+ void SetChecked(int command_id, bool checked) override {
+ // No-op if already at the default state.
+ if (!checked && !GetItemInfo(command_id)) {
+ return;
+ }
+
+ auto* info = GetOrCreateItemInfo(command_id);
+ info->checked = checked;
+ if (!checked) {
+ MaybeDeleteItemInfo(command_id, info);
+ }
+ }
+
+ void SetAccelerator(int command_id,
+ absl::optional<ui::Accelerator> accel) override {
+ // No-op if already at the default state.
+ if (!accel && !GetItemInfo(command_id)) {
+ return;
+ }
+
+ auto* info = GetOrCreateItemInfo(command_id);
+ info->accel = accel;
+ if (!accel) {
+ MaybeDeleteItemInfo(command_id, info);
+ }
+ }
+
+ private:
+ struct ItemInfo {
+ ItemInfo() {}
+
+ bool checked = false;
+ absl::optional<ui::Accelerator> accel;
+ };
+
+ ItemInfo* GetItemInfo(int command_id) {
+ auto it = iteminfomap_.find(command_id);
+ if (it != iteminfomap_.end()) {
+ return &it->second;
+ }
+ return nullptr;
+ }
+
+ ItemInfo* GetOrCreateItemInfo(int command_id) {
+ if (auto info = GetItemInfo(command_id)) {
+ return info;
+ }
+
+ auto result = iteminfomap_.insert(std::make_pair(command_id, ItemInfo()));
+ return &result.first->second;
+ }
+
+ void MaybeDeleteItemInfo(int command_id, ItemInfo* info) {
+ // Remove if all info has reverted to the default state.
+ if (!info->checked && !info->accel) {
+ auto it = iteminfomap_.find(command_id);
+ iteminfomap_.erase(it);
+ }
+ }
+
+ CefRefPtr<CefFrame> GetFrame() const {
+ CefRefPtr<CefFrame> frame;
+
+ // May return nullptr if the frame is destroyed while the menu is pending.
+ auto* rfh = context_menu_->GetRenderFrameHost();
+ if (rfh) {
+ frame = browser_->GetFrameForHost(rfh);
+ }
+ if (!frame) {
+ frame = browser_->GetMainFrame();
+ }
+ return frame;
+ }
+
+ RenderViewContextMenu* const context_menu_;
+ CefRefPtr<CefBrowserHostBase> browser_;
+ CefRefPtr<CefContextMenuHandler> handler_;
+ CefRefPtr<CefContextMenuParams> params_;
+ CefRefPtr<CefSimpleMenuModelImpl> model_;
+
+ // Map of command_id to ItemInfo.
+ using ItemInfoMap = std::map<int, ItemInfo>;
+ ItemInfoMap iteminfomap_;
+};
+
+std::unique_ptr<RenderViewContextMenuObserver> MenuCreatedCallback(
+ RenderViewContextMenu* context_menu) {
+ auto browser = CefBrowserHostBase::GetBrowserForContents(
+ context_menu->source_web_contents());
+ if (browser) {
+ if (auto client = browser->GetClient()) {
+ if (auto handler = client->GetContextMenuHandler()) {
+ return std::make_unique<CefContextMenuObserver>(context_menu, browser,
+ handler);
+ }
+ }
+ }
+
+ return nullptr;
+}
+
+} // namespace
+
+void RegisterMenuCreatedCallback() {
+ RenderViewContextMenu::RegisterMenuCreatedCallback(
+ base::BindRepeating(&MenuCreatedCallback));
+}
+
+} // namespace context_menu
diff --git a/libcef/browser/chrome/chrome_context_menu_handler.h b/libcef/browser/chrome/chrome_context_menu_handler.h
new file mode 100644
index 00000000..12c31f19
--- /dev/null
+++ b/libcef/browser/chrome/chrome_context_menu_handler.h
@@ -0,0 +1,16 @@
+// Copyright (c) 2021 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_CHROME_CHROME_CONTEXT_MENU_HANDLER_H_
+#define CEF_LIBCEF_BROWSER_CHROME_CHROME_CONTEXT_MENU_HANDLER_H_
+#pragma once
+
+namespace context_menu {
+
+// Register the context menu created callback.
+void RegisterMenuCreatedCallback();
+
+} // namespace context_menu
+
+#endif // CEF_LIBCEF_BROWSER_CHROME_CHROME_CONTEXT_MENU_HANDLER_H_
diff --git a/libcef/browser/chrome/extensions/chrome_mime_handler_view_guest_delegate_cef.cc b/libcef/browser/chrome/extensions/chrome_mime_handler_view_guest_delegate_cef.cc
new file mode 100644
index 00000000..1dea1605
--- /dev/null
+++ b/libcef/browser/chrome/extensions/chrome_mime_handler_view_guest_delegate_cef.cc
@@ -0,0 +1,48 @@
+// Copyright 2015 The Chromium Embedded Framework Authors.
+// Portions copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/chrome/extensions/chrome_mime_handler_view_guest_delegate_cef.h"
+
+#include "libcef/browser/browser_host_base.h"
+#include "libcef/browser/browser_info.h"
+
+#include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h"
+
+namespace extensions {
+
+ChromeMimeHandlerViewGuestDelegateCef::ChromeMimeHandlerViewGuestDelegateCef(
+ MimeHandlerViewGuest* guest)
+ : guest_(guest), owner_web_contents_(guest_->owner_web_contents()) {}
+
+ChromeMimeHandlerViewGuestDelegateCef::
+ ~ChromeMimeHandlerViewGuestDelegateCef() = default;
+
+void ChromeMimeHandlerViewGuestDelegateCef::OnGuestAttached() {
+ content::WebContents* web_contents = guest_->web_contents();
+ DCHECK(web_contents);
+
+ auto owner_browser =
+ CefBrowserHostBase::GetBrowserForContents(owner_web_contents_);
+ DCHECK(owner_browser);
+
+ // Associate guest state information with the owner browser.
+ owner_browser->browser_info()->MaybeCreateFrame(
+ web_contents->GetPrimaryMainFrame(), true /* is_guest_view */);
+}
+
+void ChromeMimeHandlerViewGuestDelegateCef::OnGuestDetached() {
+ content::WebContents* web_contents = guest_->web_contents();
+ DCHECK(web_contents);
+
+ auto owner_browser =
+ CefBrowserHostBase::GetBrowserForContents(owner_web_contents_);
+ DCHECK(owner_browser);
+
+ // Disassociate guest state information with the owner browser.
+ owner_browser->browser_info()->RemoveFrame(
+ web_contents->GetPrimaryMainFrame());
+}
+
+} // namespace extensions
diff --git a/libcef/browser/chrome/extensions/chrome_mime_handler_view_guest_delegate_cef.h b/libcef/browser/chrome/extensions/chrome_mime_handler_view_guest_delegate_cef.h
new file mode 100644
index 00000000..8d9216b6
--- /dev/null
+++ b/libcef/browser/chrome/extensions/chrome_mime_handler_view_guest_delegate_cef.h
@@ -0,0 +1,37 @@
+// Copyright 2015 The Chromium Embedded Framework Authors.
+// Portions copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_CHROME_EXTENSIONS_CHROME_MIME_HANDLER_VIEW_GUEST_DELEGATE_CEF_H_
+#define CEF_LIBCEF_BROWSER_CHROME_EXTENSIONS_CHROME_MIME_HANDLER_VIEW_GUEST_DELEGATE_CEF_H_
+
+#include "chrome/browser/guest_view/mime_handler_view/chrome_mime_handler_view_guest_delegate.h"
+#include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h"
+
+namespace extensions {
+
+class ChromeMimeHandlerViewGuestDelegateCef
+ : public ChromeMimeHandlerViewGuestDelegate {
+ public:
+ explicit ChromeMimeHandlerViewGuestDelegateCef(MimeHandlerViewGuest* guest);
+
+ ChromeMimeHandlerViewGuestDelegateCef(
+ const ChromeMimeHandlerViewGuestDelegateCef&) = delete;
+ ChromeMimeHandlerViewGuestDelegateCef& operator=(
+ const ChromeMimeHandlerViewGuestDelegateCef&) = delete;
+
+ ~ChromeMimeHandlerViewGuestDelegateCef() override;
+
+ // MimeHandlerViewGuestDelegate methods.
+ void OnGuestAttached() override;
+ void OnGuestDetached() override;
+
+ private:
+ MimeHandlerViewGuest* guest_; // Owns us.
+ content::WebContents* owner_web_contents_;
+};
+
+} // namespace extensions
+
+#endif // CEF_LIBCEF_BROWSER_CHROME_EXTENSIONS_CHROME_MIME_HANDLER_VIEW_GUEST_DELEGATE_CEF_H_
diff --git a/libcef/browser/chrome/views/browser_platform_delegate_chrome_child_window.cc b/libcef/browser/chrome/views/browser_platform_delegate_chrome_child_window.cc
new file mode 100644
index 00000000..c650090c
--- /dev/null
+++ b/libcef/browser/chrome/views/browser_platform_delegate_chrome_child_window.cc
@@ -0,0 +1,29 @@
+// Copyright 2022 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/chrome/views/browser_platform_delegate_chrome_child_window.h"
+
+#include "include/views/cef_browser_view.h"
+#include "libcef/browser/chrome/views/chrome_child_window.h"
+
+CefBrowserPlatformDelegateChromeChildWindow::
+ CefBrowserPlatformDelegateChromeChildWindow(
+ std::unique_ptr<CefBrowserPlatformDelegateNative> native_delegate,
+ CefRefPtr<CefBrowserViewImpl> browser_view)
+ : CefBrowserPlatformDelegateChromeViews(std::move(native_delegate),
+ browser_view) {}
+
+void CefBrowserPlatformDelegateChromeChildWindow::CloseHostWindow() {
+ native_delegate_->CloseHostWindow();
+}
+
+void CefBrowserPlatformDelegateChromeChildWindow::SetFocus(bool focus) {
+ native_delegate_->SetFocus(focus);
+}
+
+#if BUILDFLAG(IS_WIN) || (BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC))
+void CefBrowserPlatformDelegateChromeChildWindow::NotifyMoveOrResizeStarted() {
+ native_delegate_->NotifyMoveOrResizeStarted();
+}
+#endif
diff --git a/libcef/browser/chrome/views/browser_platform_delegate_chrome_child_window.h b/libcef/browser/chrome/views/browser_platform_delegate_chrome_child_window.h
new file mode 100644
index 00000000..b709510d
--- /dev/null
+++ b/libcef/browser/chrome/views/browser_platform_delegate_chrome_child_window.h
@@ -0,0 +1,29 @@
+// Copyright 2022 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_CHROME_VIEWS_BROWSER_PLATFORM_DELEGATE_CHROME_CHILD_WINDOW_H_
+#define CEF_LIBCEF_BROWSER_CHROME_VIEWS_BROWSER_PLATFORM_DELEGATE_CHROME_CHILD_WINDOW_H_
+
+#include "libcef/browser/chrome/views/browser_platform_delegate_chrome_views.h"
+
+// Implementation of Chrome-based browser functionality.
+class CefBrowserPlatformDelegateChromeChildWindow
+ : public CefBrowserPlatformDelegateChromeViews {
+ public:
+ CefBrowserPlatformDelegateChromeChildWindow(
+ std::unique_ptr<CefBrowserPlatformDelegateNative> native_delegate,
+ CefRefPtr<CefBrowserViewImpl> browser_view);
+
+ // CefBrowserPlatformDelegate overrides.
+ void CloseHostWindow() override;
+ void SetFocus(bool focus) override;
+
+#if BUILDFLAG(IS_WIN) || (BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC))
+ void NotifyMoveOrResizeStarted() override;
+#endif
+
+ bool HasExternalParent() const override { return true; }
+};
+
+#endif // CEF_LIBCEF_BROWSER_CHROME_VIEWS_BROWSER_PLATFORM_DELEGATE_CHROME_CHILD_WINDOW_H_
diff --git a/libcef/browser/chrome/views/browser_platform_delegate_chrome_views.cc b/libcef/browser/chrome/views/browser_platform_delegate_chrome_views.cc
new file mode 100644
index 00000000..f54e6bb8
--- /dev/null
+++ b/libcef/browser/chrome/views/browser_platform_delegate_chrome_views.cc
@@ -0,0 +1,175 @@
+// Copyright 2021 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/chrome/views/browser_platform_delegate_chrome_views.h"
+
+#include "include/views/cef_window.h"
+
+#include "chrome/browser/ui/browser.h"
+#include "ui/views/widget/widget.h"
+
+namespace {
+
+// Default popup window delegate implementation.
+class PopupWindowDelegate : public CefWindowDelegate {
+ public:
+ explicit PopupWindowDelegate(CefRefPtr<CefBrowserView> browser_view)
+ : browser_view_(browser_view) {}
+
+ PopupWindowDelegate(const PopupWindowDelegate&) = delete;
+ PopupWindowDelegate& operator=(const PopupWindowDelegate&) = delete;
+
+ void OnWindowCreated(CefRefPtr<CefWindow> window) override {
+ window->AddChildView(browser_view_);
+ window->Show();
+ browser_view_->RequestFocus();
+ }
+
+ void OnWindowDestroyed(CefRefPtr<CefWindow> window) override {
+ browser_view_ = nullptr;
+ }
+
+ bool CanClose(CefRefPtr<CefWindow> window) override {
+ CefRefPtr<CefBrowser> browser = browser_view_->GetBrowser();
+ if (browser) {
+ return browser->GetHost()->TryCloseBrowser();
+ }
+ return true;
+ }
+
+ private:
+ CefRefPtr<CefBrowserView> browser_view_;
+
+ IMPLEMENT_REFCOUNTING(PopupWindowDelegate);
+};
+
+} // namespace
+
+CefBrowserPlatformDelegateChromeViews::CefBrowserPlatformDelegateChromeViews(
+ std::unique_ptr<CefBrowserPlatformDelegateNative> native_delegate,
+ CefRefPtr<CefBrowserViewImpl> browser_view)
+ : CefBrowserPlatformDelegateChrome(std::move(native_delegate)) {
+ if (browser_view) {
+ SetBrowserView(browser_view);
+ }
+}
+
+void CefBrowserPlatformDelegateChromeViews::SetBrowserView(
+ CefRefPtr<CefBrowserViewImpl> browser_view) {
+ DCHECK(!browser_view_);
+ DCHECK(browser_view);
+ browser_view_ = browser_view;
+}
+
+void CefBrowserPlatformDelegateChromeViews::WebContentsCreated(
+ content::WebContents* web_contents,
+ bool owned) {
+ CefBrowserPlatformDelegateChrome::WebContentsCreated(web_contents, owned);
+ browser_view_->WebContentsCreated(web_contents);
+}
+
+void CefBrowserPlatformDelegateChromeViews::BrowserCreated(
+ CefBrowserHostBase* browser) {
+ CefBrowserPlatformDelegateChrome::BrowserCreated(browser);
+ browser_view_->BrowserCreated(browser, base::RepeatingClosure());
+}
+
+void CefBrowserPlatformDelegateChromeViews::NotifyBrowserCreated() {
+ if (browser_view_->delegate()) {
+ browser_view_->delegate()->OnBrowserCreated(browser_view_, browser_);
+ }
+}
+
+void CefBrowserPlatformDelegateChromeViews::NotifyBrowserDestroyed() {
+ if (browser_view_->delegate()) {
+ browser_view_->delegate()->OnBrowserDestroyed(browser_view_, browser_);
+ }
+}
+
+void CefBrowserPlatformDelegateChromeViews::BrowserDestroyed(
+ CefBrowserHostBase* browser) {
+ CefBrowserPlatformDelegateChrome::BrowserDestroyed(browser);
+ browser_view_->BrowserDestroyed(browser);
+}
+
+void CefBrowserPlatformDelegateChromeViews::CloseHostWindow() {
+ views::Widget* widget = GetWindowWidget();
+ if (widget && !widget->IsClosed()) {
+ widget->Close();
+ }
+}
+
+CefWindowHandle CefBrowserPlatformDelegateChromeViews::GetHostWindowHandle()
+ const {
+ return view_util::GetWindowHandle(GetWindowWidget());
+}
+
+views::Widget* CefBrowserPlatformDelegateChromeViews::GetWindowWidget() const {
+ if (browser_view_->root_view()) {
+ return browser_view_->root_view()->GetWidget();
+ }
+ return nullptr;
+}
+
+CefRefPtr<CefBrowserView>
+CefBrowserPlatformDelegateChromeViews::GetBrowserView() const {
+ return browser_view_.get();
+}
+
+void CefBrowserPlatformDelegateChromeViews::PopupWebContentsCreated(
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefClient> client,
+ content::WebContents* new_web_contents,
+ CefBrowserPlatformDelegate* new_platform_delegate,
+ bool is_devtools) {
+ // Default popup handling may not be Views-hosted.
+ if (!new_platform_delegate->IsViewsHosted()) {
+ return;
+ }
+
+ auto* new_platform_delegate_impl =
+ static_cast<CefBrowserPlatformDelegateChromeViews*>(
+ new_platform_delegate);
+
+ CefRefPtr<CefBrowserViewDelegate> new_delegate;
+ if (browser_view_->delegate()) {
+ new_delegate = browser_view_->delegate()->GetDelegateForPopupBrowserView(
+ browser_view_.get(), settings, client, is_devtools);
+ }
+
+ // Create a new BrowserView for the popup.
+ CefRefPtr<CefBrowserViewImpl> new_browser_view =
+ CefBrowserViewImpl::CreateForPopup(settings, new_delegate);
+
+ // Associate the PlatformDelegate with the new BrowserView.
+ new_platform_delegate_impl->SetBrowserView(new_browser_view);
+}
+
+void CefBrowserPlatformDelegateChromeViews::PopupBrowserCreated(
+ CefBrowserHostBase* new_browser,
+ bool is_devtools) {
+ // Default popup handling may not be Views-hosted.
+ if (!new_browser->HasView()) {
+ return;
+ }
+
+ CefRefPtr<CefBrowserView> new_browser_view =
+ CefBrowserView::GetForBrowser(new_browser);
+ DCHECK(new_browser_view);
+
+ bool popup_handled = false;
+ if (browser_view_->delegate()) {
+ popup_handled = browser_view_->delegate()->OnPopupBrowserViewCreated(
+ browser_view_.get(), new_browser_view.get(), is_devtools);
+ }
+
+ if (!popup_handled) {
+ CefWindow::CreateTopLevelWindow(
+ new PopupWindowDelegate(new_browser_view.get()));
+ }
+}
+
+bool CefBrowserPlatformDelegateChromeViews::IsViewsHosted() const {
+ return true;
+}
diff --git a/libcef/browser/chrome/views/browser_platform_delegate_chrome_views.h b/libcef/browser/chrome/views/browser_platform_delegate_chrome_views.h
new file mode 100644
index 00000000..4b41b411
--- /dev/null
+++ b/libcef/browser/chrome/views/browser_platform_delegate_chrome_views.h
@@ -0,0 +1,48 @@
+// Copyright 2021 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_CHROME_VIEWS_BROWSER_PLATFORM_DELEGATE_CHROME_VIEWS_H_
+#define CEF_LIBCEF_BROWSER_CHROME_VIEWS_BROWSER_PLATFORM_DELEGATE_CHROME_VIEWS_H_
+
+#include "libcef/browser/chrome/browser_platform_delegate_chrome.h"
+#include "libcef/browser/views/browser_view_impl.h"
+
+// Implementation of Chrome-based browser functionality.
+class CefBrowserPlatformDelegateChromeViews
+ : public CefBrowserPlatformDelegateChrome {
+ public:
+ explicit CefBrowserPlatformDelegateChromeViews(
+ std::unique_ptr<CefBrowserPlatformDelegateNative> native_delegate,
+ CefRefPtr<CefBrowserViewImpl> browser_view);
+
+ // CefBrowserPlatformDelegate overrides.
+ void WebContentsCreated(content::WebContents* web_contents,
+ bool owned) override;
+ void BrowserCreated(CefBrowserHostBase* browser) override;
+ void NotifyBrowserCreated() override;
+ void NotifyBrowserDestroyed() override;
+ void BrowserDestroyed(CefBrowserHostBase* browser) override;
+ void CloseHostWindow() override;
+ CefWindowHandle GetHostWindowHandle() const override;
+ views::Widget* GetWindowWidget() const override;
+ CefRefPtr<CefBrowserView> GetBrowserView() const override;
+ void PopupWebContentsCreated(
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefClient> client,
+ content::WebContents* new_web_contents,
+ CefBrowserPlatformDelegate* new_platform_delegate,
+ bool is_devtools) override;
+ void PopupBrowserCreated(CefBrowserHostBase* new_browser,
+ bool is_devtools) override;
+ bool IsViewsHosted() const override;
+
+ CefRefPtr<CefBrowserViewImpl> browser_view() const { return browser_view_; }
+
+ private:
+ void SetBrowserView(CefRefPtr<CefBrowserViewImpl> browser_view);
+
+ CefRefPtr<CefBrowserViewImpl> browser_view_;
+};
+
+#endif // CEF_LIBCEF_BROWSER_CHROME_VIEWS_BROWSER_PLATFORM_DELEGATE_CHROME_VIEWS_H_
diff --git a/libcef/browser/chrome/views/chrome_browser_frame.cc b/libcef/browser/chrome/views/chrome_browser_frame.cc
new file mode 100644
index 00000000..7a20b31a
--- /dev/null
+++ b/libcef/browser/chrome/views/chrome_browser_frame.cc
@@ -0,0 +1,35 @@
+// Copyright 2021 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#include "libcef/browser/chrome/views/chrome_browser_frame.h"
+
+#include "chrome/browser/themes/theme_service.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
+
+void ChromeBrowserFrame::Init(BrowserView* browser_view,
+ std::unique_ptr<Browser> browser) {
+ DCHECK(browser_view);
+
+ DCHECK(!browser_);
+ browser_ = browser.get();
+ DCHECK(browser_);
+
+ // Initialize BrowserFrame state.
+ InitBrowserView(browser_view);
+
+ // Initialize BrowserView state.
+ browser_view->InitBrowser(std::move(browser));
+}
+
+views::internal::RootView* ChromeBrowserFrame::CreateRootView() {
+ // Bypass the BrowserFrame implementation.
+ return views::Widget::CreateRootView();
+}
+
+std::unique_ptr<views::NonClientFrameView>
+ChromeBrowserFrame::CreateNonClientFrameView() {
+ // Bypass the BrowserFrame implementation.
+ return views::Widget::CreateNonClientFrameView();
+}
diff --git a/libcef/browser/chrome/views/chrome_browser_frame.h b/libcef/browser/chrome/views/chrome_browser_frame.h
new file mode 100644
index 00000000..472c1ef9
--- /dev/null
+++ b/libcef/browser/chrome/views/chrome_browser_frame.h
@@ -0,0 +1,109 @@
+// Copyright 2021 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_CHROME_VIEWS_CHROME_BROWSER_FRAME_H_
+#define CEF_LIBCEF_BROWSER_CHROME_VIEWS_CHROME_BROWSER_FRAME_H_
+#pragma once
+
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/views/frame/browser_frame.h"
+
+// An overview of the Chrome Browser object model is provided below. Object
+// creation normally begins with a call to Browser::Create(CreateParams) which
+// then creates the necessary Browser view, window and frame objects. CEF has
+// modified the default object creation model are described below to better
+// integrate with the existing CEF Views APIs.
+//
+// OVERVIEW
+//
+// Browser and BrowserWindow are the primary Chrome objects. Browser provides
+// the concrete state and mutation methods while BrowserWindow is an interface
+// implemented by the platform-specific "view" of the Browser window.
+//
+// Browser:
+// - Creates a BrowserView (aka BrowserWindow) and BrowserFrame (aka Widget) via
+// a call to BrowserWindow::CreateBrowserWindow() in the Browser constructor.
+// - An existing BrowserWindow can alternately be specified via the
+// Browser::CreateParams::window parameter.
+// - Owned by the BrowserView after creation.
+//
+// The Chrome Views implementation uses BrowserView to represent the browser
+// client area and BrowserFrame (plus helpers) to represent the non-client
+// window frame.
+//
+// BrowserView:
+// - Extends BrowserWindow, views::ClientView, views::WidgetDelegate.
+// - Owns the Browser.
+// - References the BrowserFrame.
+// - Passed to Widget::Init() via Widget::InitParams::delegate to receive
+// WidgetDelegate callbacks.
+// - Extended by CEF as ChromeBrowserView.
+// BrowserFrame:
+// - Extends Widget (aka views::internal::NativeWidgetDelegate).
+// - References the BrowserView.
+// - Creates/owns a DesktopBrowserFrameAura (aka NativeBrowserFrame) via
+// BrowserFrame::InitBrowserFrame().
+// - Extended by CEF as ChromeBrowserFrame.
+//
+// Chrome custom window/frame handling is implemented using platform-specific
+// objects.
+//
+// DesktopBrowserFrameAura:
+// - Extends NativeBrowserFrame, DesktopNativeWidgetAura.
+// - Acts as a helper for BrowserFrame.
+// - Creates/references a BrowserDesktopWindowTreeHostWin via
+// DesktopBrowserFrameAura::InitNativeWidget().
+// BrowserDesktopWindowTreeHostWin (for Windows):
+// - Extends DesktopWindowTreeHost.
+// - References DesktopBrowserFrameAura, BrowserView, BrowserFrame.
+// - Passed to Widget::Init() via Widget::InitParams::desktop_window_tree_host.
+//
+// CEF MODIFICATIONS
+//
+// The CEF Views integration uses an alternative approach of creating the
+// ChromeBrowserFrame in CefWindowView::CreateWidget() and the
+// ChromeBrowserView in CefBrowserViewImpl::CreateRootView().
+// The object associations described above are then configured via
+// ChromeBrowserView::AddedToWidget() and ChromeBrowserHostImpl::Create()
+// after the BrowserView is added to the Widget. The Chromium code has been
+// patched to allow later initialization of the Browser, BrowserFrame and
+// BrowserView members to support this model.
+//
+// CEF does not use Chrome's NativeBrowserFrame (aka DesktopBrowserFrameAura),
+// BrowserNonClientFrameView or BrowserRootView objects (all normally created by
+// BrowserFrame during Widget initialization). Consequently
+// |BrowserFrame::native_browser_frame_| and |BrowserFrame::browser_frame_view_|
+// (sometimes retrieved via BrowserFrame::GetFrameView) will be nullptr and the
+// Chromium code has been patched to add the necessary null checks.
+//
+// CEF does not pass ChromeBrowserView as the WidgetDelegate when the Widget is
+// initialized in CefWindowView::CreateWidget(). Some of the WidgetDelegate
+// callbacks may need to be routed from CefWindowView to ChromeBrowserView in
+// the future.
+//
+// See the chrome_runtime_views.patch file for the complete set of related
+// modifications.
+
+class BrowserView;
+
+// Widget for a Views-hosted Chrome browser. Created in
+// CefWindowView::CreateWidget() when the Chrome runtime is enabled.
+class ChromeBrowserFrame : public BrowserFrame {
+ public:
+ ChromeBrowserFrame() {}
+ ChromeBrowserFrame(const ChromeBrowserFrame&) = delete;
+ ChromeBrowserFrame& operator=(const ChromeBrowserFrame&) = delete;
+
+ void Init(BrowserView* browser_view, std::unique_ptr<Browser> browser);
+
+ // views::Widget methods:
+ views::internal::RootView* CreateRootView() override;
+ std::unique_ptr<views::NonClientFrameView> CreateNonClientFrameView()
+ override;
+
+ private:
+ Browser* browser_ = nullptr;
+};
+
+#endif // CEF_LIBCEF_BROWSER_CHROME_VIEWS_CHROME_BROWSER_FRAME_H_
diff --git a/libcef/browser/chrome/views/chrome_browser_view.cc b/libcef/browser/chrome/views/chrome_browser_view.cc
new file mode 100644
index 00000000..b7c94a64
--- /dev/null
+++ b/libcef/browser/chrome/views/chrome_browser_view.cc
@@ -0,0 +1,99 @@
+// Copyright 2021 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#include "libcef/browser/chrome/views/chrome_browser_view.h"
+
+#include "libcef/browser/chrome/views/chrome_browser_frame.h"
+#include "libcef/browser/views/browser_view_impl.h"
+
+ChromeBrowserView::ChromeBrowserView(CefBrowserViewDelegate* cef_delegate,
+ Delegate* browser_view_delegate)
+ : ParentClass(cef_delegate), browser_view_delegate_(browser_view_delegate) {
+ DCHECK(browser_view_delegate_);
+}
+
+void ChromeBrowserView::InitBrowser(std::unique_ptr<Browser> browser,
+ CefRefPtr<CefBrowserView> browser_view) {
+ DCHECK(!browser_);
+ DCHECK(!web_view_);
+
+ browser_ = browser.get();
+ DCHECK(browser_);
+
+ // Initialize the BrowserFrame and BrowserView.
+ auto chrome_widget = static_cast<ChromeBrowserFrame*>(GetWidget());
+ chrome_widget->Init(this, std::move(browser));
+
+ // Retrieve the views::WebView that was created by the above initializations.
+ auto view_impl = static_cast<CefBrowserViewImpl*>(browser_view.get());
+ web_view_ = view_impl->web_view();
+ DCHECK(web_view_);
+
+ ParentClass::AddedToWidget();
+}
+
+void ChromeBrowserView::Destroyed() {
+ DCHECK(!destroyed_);
+ destroyed_ = true;
+ browser_ = nullptr;
+ web_view_ = nullptr;
+}
+
+void ChromeBrowserView::ViewHierarchyChanged(
+ const views::ViewHierarchyChangedDetails& details) {
+ ParentClass::ViewHierarchyChanged(details);
+ if (details.is_add && details.child == this) {
+ gfx::Size size = GetPreferredSize();
+ if (size.IsEmpty()) {
+ // No size was provided for this View. Size it to the parent by default
+ // or, depending on the Layout, the browser may be initially 0x0 size and
+ // will not display until the parent is next resized (resulting in a call
+ // to WebView::OnBoundsChanged). For example, this can happen when adding
+ // this View to a CefWindow with FillLayout and then calling
+ // CefWindow::Show() without first resizing the CefWindow.
+ size = details.parent->GetPreferredSize();
+ if (!size.IsEmpty()) {
+ SetSize(size);
+ }
+ }
+ }
+}
+
+void ChromeBrowserView::AddedToWidget() {
+ // Results in a call to InitBrowser which calls ParentClass::AddedToWidget.
+ browser_view_delegate_->OnBrowserViewAdded();
+}
+
+void ChromeBrowserView::OnBoundsChanged(const gfx::Rect& previous_bounds) {
+ ParentClass::OnBoundsChanged(previous_bounds);
+ browser_view_delegate_->OnBoundsChanged();
+}
+
+ToolbarView* ChromeBrowserView::OverrideCreateToolbar(
+ Browser* browser,
+ BrowserView* browser_view) {
+ if (cef_delegate()) {
+ auto toolbar_type = cef_delegate()->GetChromeToolbarType();
+ absl::optional<ToolbarView::DisplayMode> display_mode;
+ switch (toolbar_type) {
+ case CEF_CTT_NORMAL:
+ display_mode = ToolbarView::DisplayMode::NORMAL;
+ break;
+ case CEF_CTT_LOCATION:
+ display_mode = ToolbarView::DisplayMode::LOCATION;
+ break;
+ default:
+ break;
+ }
+ if (display_mode) {
+ cef_toolbar_ = CefToolbarViewImpl::Create(nullptr, browser, browser_view,
+ display_mode);
+ // Ownership will be taken by BrowserView.
+ view_util::PassOwnership(cef_toolbar_).release();
+ return cef_toolbar_->root_view();
+ }
+ }
+
+ return nullptr;
+}
diff --git a/libcef/browser/chrome/views/chrome_browser_view.h b/libcef/browser/chrome/views/chrome_browser_view.h
new file mode 100644
index 00000000..93077466
--- /dev/null
+++ b/libcef/browser/chrome/views/chrome_browser_view.h
@@ -0,0 +1,67 @@
+// Copyright 2021 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_CHROME_VIEWS_CHROME_BROWSER_VIEW_H_
+#define CEF_LIBCEF_BROWSER_CHROME_VIEWS_CHROME_BROWSER_VIEW_H_
+#pragma once
+
+#include "include/views/cef_browser_view.h"
+#include "include/views/cef_browser_view_delegate.h"
+#include "libcef/browser/chrome/views/toolbar_view_impl.h"
+#include "libcef/browser/views/browser_view_view.h"
+#include "libcef/browser/views/view_view.h"
+
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
+
+namespace views {
+class WebView;
+} // namespace views
+
+// A variant of CefBrowserViewView that extends BrowserView instead of
+// views::WebView. See chrome_browser_frame.h for related documentation.
+class ChromeBrowserView
+ : public CefViewView<BrowserView, CefBrowserViewDelegate> {
+ public:
+ using ParentClass = CefViewView<BrowserView, CefBrowserViewDelegate>;
+ using Delegate = CefBrowserViewView::Delegate;
+
+ // |cef_delegate| may be nullptr.
+ // |browser_view_delegate| must be non-nullptr.
+ ChromeBrowserView(CefBrowserViewDelegate* cef_delegate,
+ Delegate* browser_view_delegate);
+
+ ChromeBrowserView(const ChromeBrowserView&) = delete;
+ ChromeBrowserView& operator=(const ChromeBrowserView&) = delete;
+
+ // Called by ChromeBrowserHostImpl.
+ void InitBrowser(std::unique_ptr<Browser> browser,
+ CefRefPtr<CefBrowserView> browser_view);
+ void Destroyed();
+
+ // View methods:
+ void ViewHierarchyChanged(
+ const views::ViewHierarchyChangedDetails& details) override;
+ void AddedToWidget() override;
+ void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
+
+ // BrowserView methods:
+ ToolbarView* OverrideCreateToolbar(Browser* browser,
+ BrowserView* browser_view) override;
+
+ CefRefPtr<CefToolbarViewImpl> cef_toolbar() const { return cef_toolbar_; }
+
+ private:
+ // Not owned by this object.
+ Delegate* browser_view_delegate_;
+
+ Browser* browser_ = nullptr;
+ views::WebView* web_view_ = nullptr;
+
+ bool destroyed_ = false;
+
+ CefRefPtr<CefToolbarViewImpl> cef_toolbar_;
+};
+
+#endif // CEF_LIBCEF_BROWSER_CHROME_VIEWS_CHROME_BROWSER_VIEW_H_
diff --git a/libcef/browser/chrome/views/chrome_child_window.cc b/libcef/browser/chrome/views/chrome_child_window.cc
new file mode 100644
index 00000000..9d1368ac
--- /dev/null
+++ b/libcef/browser/chrome/views/chrome_child_window.cc
@@ -0,0 +1,203 @@
+// Copyright 2022 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#include "libcef/browser/chrome/views/chrome_child_window.h"
+
+#include "libcef/browser/chrome/views/browser_platform_delegate_chrome_views.h"
+#include "libcef/browser/views/browser_view_impl.h"
+#include "libcef/browser/views/window_impl.h"
+
+#if BUILDFLAG(IS_WIN)
+#include "libcef/browser/native/browser_platform_delegate_native_win.h"
+#include "ui/views/win/hwnd_util.h"
+#endif
+
+namespace {
+
+class ChildWindowDelegate : public CefWindowDelegate {
+ public:
+ ChildWindowDelegate(const ChildWindowDelegate&) = delete;
+ ChildWindowDelegate& operator=(const ChildWindowDelegate&) = delete;
+
+ static void Create(CefRefPtr<CefBrowserView> browser_view,
+ const CefWindowInfo& window_info,
+ gfx::AcceleratedWidget parent_handle) {
+ DCHECK(parent_handle != gfx::kNullAcceleratedWidget);
+
+ // Create the Window. It will show itself after creation.
+ CefWindowImpl::Create(new ChildWindowDelegate(browser_view, window_info),
+ parent_handle);
+ }
+
+ void OnWindowCreated(CefRefPtr<CefWindow> window) override {
+ DCHECK(!window_);
+ window_ = window;
+
+ // Add the browser view. It will now have an associated Widget.
+ window_->AddChildView(browser_view_);
+
+ ShowWindow();
+ }
+
+ void OnWindowDestroyed(CefRefPtr<CefWindow> window) override {
+ browser_view_ = nullptr;
+ window_ = nullptr;
+ }
+
+ CefRect GetInitialBounds(CefRefPtr<CefWindow> window) override {
+ CefRect initial_bounds(window_info_.bounds);
+ if (initial_bounds.IsEmpty()) {
+ return CefRect(0, 0, 800, 600);
+ }
+ return initial_bounds;
+ }
+
+ void ShowWindow() {
+#if BUILDFLAG(IS_WIN)
+ auto widget = static_cast<CefWindowImpl*>(window_.get())->widget();
+ DCHECK(widget);
+ const HWND widget_hwnd = HWNDForWidget(widget);
+ DCHECK(widget_hwnd);
+
+ // The native delegate needs state to perform some actions.
+ auto browser =
+ static_cast<CefBrowserHostBase*>(browser_view_->GetBrowser().get());
+ auto platform_delegate = browser->platform_delegate();
+ DCHECK(platform_delegate->IsViewsHosted());
+ auto chrome_delegate =
+ static_cast<CefBrowserPlatformDelegateChromeViews*>(platform_delegate);
+ auto native_delegate = static_cast<CefBrowserPlatformDelegateNativeWin*>(
+ chrome_delegate->native_delegate());
+ native_delegate->set_widget(widget, widget_hwnd);
+
+ if (window_info_.ex_style & WS_EX_NOACTIVATE) {
+ const DWORD widget_ex_styles = GetWindowLongPtr(widget_hwnd, GWL_EXSTYLE);
+
+ // Add the WS_EX_NOACTIVATE style on the DesktopWindowTreeHostWin HWND
+ // so that HWNDMessageHandler::Show() called via Widget::Show() does not
+ // activate the window.
+ SetWindowLongPtr(widget_hwnd, GWL_EXSTYLE,
+ widget_ex_styles | WS_EX_NOACTIVATE);
+
+ window_->Show();
+
+ // Remove the WS_EX_NOACTIVATE style so that future mouse clicks inside
+ // the browser correctly activate and focus the window.
+ SetWindowLongPtr(widget_hwnd, GWL_EXSTYLE, widget_ex_styles);
+ return;
+ }
+#endif // BUILDFLAG(IS_WIN)
+
+ window_->Show();
+
+ // Give keyboard focus to the browser view.
+ browser_view_->RequestFocus();
+ }
+
+ private:
+ ChildWindowDelegate(CefRefPtr<CefBrowserView> browser_view,
+ const CefWindowInfo& window_info)
+ : browser_view_(browser_view), window_info_(window_info) {}
+
+ CefRefPtr<CefBrowserView> browser_view_;
+ const CefWindowInfo window_info_;
+
+ CefRefPtr<CefWindow> window_;
+
+ IMPLEMENT_REFCOUNTING(ChildWindowDelegate);
+};
+
+class ChildBrowserViewDelegate : public CefBrowserViewDelegate {
+ public:
+ ChildBrowserViewDelegate() = default;
+
+ ChildBrowserViewDelegate(const ChildBrowserViewDelegate&) = delete;
+ ChildBrowserViewDelegate& operator=(const ChildBrowserViewDelegate&) = delete;
+
+ CefRefPtr<CefBrowserViewDelegate> GetDelegateForPopupBrowserView(
+ CefRefPtr<CefBrowserView> browser_view,
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefClient> client,
+ bool is_devtools) override {
+ return new ChildBrowserViewDelegate();
+ }
+
+ bool OnPopupBrowserViewCreated(CefRefPtr<CefBrowserView> browser_view,
+ CefRefPtr<CefBrowserView> popup_browser_view,
+ bool is_devtools) override {
+ DCHECK(!is_devtools);
+
+ auto new_browser = static_cast<CefBrowserHostBase*>(
+ popup_browser_view->GetBrowser().get());
+ auto new_platform_delegate = new_browser->platform_delegate();
+ DCHECK(new_platform_delegate->IsViewsHosted());
+ auto new_platform_delegate_impl =
+ static_cast<CefBrowserPlatformDelegateChromeViews*>(
+ new_platform_delegate);
+
+ const auto& window_info =
+ new_platform_delegate_impl->native_delegate()->window_info();
+ const auto parent_handle =
+ chrome_child_window::GetParentHandle(window_info);
+ if (parent_handle != gfx::kNullAcceleratedWidget) {
+ ChildWindowDelegate::Create(popup_browser_view, window_info,
+ parent_handle);
+ return true;
+ }
+
+ // Use the default implementation that creates a new Views-hosted top-level
+ // window.
+ return false;
+ }
+
+ private:
+ IMPLEMENT_REFCOUNTING(ChildBrowserViewDelegate);
+};
+
+} // namespace
+
+namespace chrome_child_window {
+
+bool HasParentHandle(const CefWindowInfo& window_info) {
+ return GetParentHandle(window_info) != gfx::kNullAcceleratedWidget;
+}
+
+gfx::AcceleratedWidget GetParentHandle(const CefWindowInfo& window_info) {
+#if !BUILDFLAG(IS_MAC)
+ return window_info.parent_window;
+#else
+ return gfx::kNullAcceleratedWidget;
+#endif
+}
+
+CefRefPtr<CefBrowserHostBase> MaybeCreateChildBrowser(
+ const CefBrowserCreateParams& create_params) {
+ // If the BrowserView already exists it means that we're dealing with a popup
+ // and we'll instead create the Window in OnPopupBrowserViewCreated.
+ if (create_params.browser_view) {
+ return nullptr;
+ }
+
+ if (!create_params.window_info) {
+ return nullptr;
+ }
+
+ const auto parent_handle = GetParentHandle(*create_params.window_info);
+ if (parent_handle == gfx::kNullAcceleratedWidget) {
+ return nullptr;
+ }
+
+ // Create the BrowserView.
+ auto browser_view = CefBrowserViewImpl::Create(
+ *create_params.window_info, create_params.client, create_params.url,
+ create_params.settings, create_params.extra_info,
+ create_params.request_context, new ChildBrowserViewDelegate());
+
+ ChildWindowDelegate::Create(browser_view, *create_params.window_info,
+ parent_handle);
+
+ return static_cast<CefBrowserHostBase*>(browser_view->GetBrowser().get());
+}
+
+} // namespace chrome_child_window
diff --git a/libcef/browser/chrome/views/chrome_child_window.h b/libcef/browser/chrome/views/chrome_child_window.h
new file mode 100644
index 00000000..ac77481d
--- /dev/null
+++ b/libcef/browser/chrome/views/chrome_child_window.h
@@ -0,0 +1,24 @@
+// Copyright 2022 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_CHROME_VIEWS_CHROME_CHILD_WINDOW_H_
+#define CEF_LIBCEF_BROWSER_CHROME_VIEWS_CHROME_CHILD_WINDOW_H_
+#pragma once
+
+#include "libcef/browser/browser_host_base.h"
+
+#include "ui/gfx/native_widget_types.h"
+
+namespace chrome_child_window {
+
+bool HasParentHandle(const CefWindowInfo& window_info);
+gfx::AcceleratedWidget GetParentHandle(const CefWindowInfo& window_info);
+
+// Called from CefBrowserHostBase::Create.
+CefRefPtr<CefBrowserHostBase> MaybeCreateChildBrowser(
+ const CefBrowserCreateParams& create_params);
+
+} // namespace chrome_child_window
+
+#endif // CEF_LIBCEF_BROWSER_CHROME_VIEWS_CHROME_CHILD_WINDOW_H_
diff --git a/libcef/browser/chrome/views/chrome_views_util.cc b/libcef/browser/chrome/views/chrome_views_util.cc
new file mode 100644
index 00000000..83254ab0
--- /dev/null
+++ b/libcef/browser/chrome/views/chrome_views_util.cc
@@ -0,0 +1,15 @@
+// Copyright 2021 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#include "libcef/browser/chrome/views/chrome_views_util.h"
+
+#include "libcef/browser/views/view_util.h"
+
+namespace cef {
+
+bool IsCefView(views::View* view) {
+ return view_util::GetFor(view, /*find_known_parent=*/false) != nullptr;
+}
+
+} // namespace cef
diff --git a/libcef/browser/chrome/views/chrome_views_util.h b/libcef/browser/chrome/views/chrome_views_util.h
new file mode 100644
index 00000000..20f528ab
--- /dev/null
+++ b/libcef/browser/chrome/views/chrome_views_util.h
@@ -0,0 +1,20 @@
+// Copyright 2021 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_CHROME_VIEWS_CHROME_VIEWS_H_
+#define CEF_LIBCEF_BROWSER_CHROME_VIEWS_CHROME_VIEWS_H_
+#pragma once
+
+namespace views {
+class View;
+}
+
+namespace cef {
+
+// Returns true if |view| is a CefView.
+bool IsCefView(views::View* view);
+
+} // namespace cef
+
+#endif // CEF_LIBCEF_BROWSER_CHROME_VIEWS_CHROME_VIEWS_H_
diff --git a/libcef/browser/chrome/views/toolbar_view_impl.cc b/libcef/browser/chrome/views/toolbar_view_impl.cc
new file mode 100644
index 00000000..fcc17552
--- /dev/null
+++ b/libcef/browser/chrome/views/toolbar_view_impl.cc
@@ -0,0 +1,40 @@
+// Copyright 2021 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#include "libcef/browser/chrome/views/toolbar_view_impl.h"
+
+// static
+CefRefPtr<CefToolbarViewImpl> CefToolbarViewImpl::Create(
+ CefRefPtr<CefViewDelegate> delegate,
+ Browser* browser,
+ BrowserView* browser_view,
+ absl::optional<ToolbarView::DisplayMode> display_mode) {
+ CEF_REQUIRE_UIT_RETURN(nullptr);
+ CefRefPtr<CefToolbarViewImpl> view =
+ new CefToolbarViewImpl(delegate, browser, browser_view, display_mode);
+ view->Initialize();
+ return view;
+}
+
+// static
+const char* const CefToolbarViewImpl::kTypeString = "ToolbarView";
+
+CefToolbarViewImpl::CefToolbarViewImpl(
+ CefRefPtr<CefViewDelegate> delegate,
+ Browser* browser,
+ BrowserView* browser_view,
+ absl::optional<ToolbarView::DisplayMode> display_mode)
+ : ParentClass(delegate),
+ browser_(browser),
+ browser_view_(browser_view),
+ display_mode_(display_mode) {}
+
+CefToolbarViewView* CefToolbarViewImpl::CreateRootView() {
+ return new CefToolbarViewView(delegate(), browser_, browser_view_,
+ display_mode_);
+}
+
+void CefToolbarViewImpl::InitializeRootView() {
+ static_cast<CefToolbarViewView*>(root_view())->Initialize();
+}
diff --git a/libcef/browser/chrome/views/toolbar_view_impl.h b/libcef/browser/chrome/views/toolbar_view_impl.h
new file mode 100644
index 00000000..9248614d
--- /dev/null
+++ b/libcef/browser/chrome/views/toolbar_view_impl.h
@@ -0,0 +1,57 @@
+// Copyright 2021 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_CHROME_VIEWS_TOOLBAR_VIEW_IMPL_H_
+#define CEF_LIBCEF_BROWSER_CHROME_VIEWS_TOOLBAR_VIEW_IMPL_H_
+#pragma once
+
+#include "include/views/cef_view_delegate.h"
+
+#include "libcef/browser/chrome/views/toolbar_view_view.h"
+#include "libcef/browser/views/view_impl.h"
+
+class Browser;
+class BrowserView;
+
+class CefToolbarViewImpl
+ : public CefViewImpl<CefToolbarViewView, CefView, CefViewDelegate> {
+ public:
+ using ParentClass = CefViewImpl<CefToolbarViewView, CefView, CefViewDelegate>;
+
+ CefToolbarViewImpl(const CefToolbarViewImpl&) = delete;
+ CefToolbarViewImpl& operator=(const CefToolbarViewImpl&) = delete;
+
+ // Create a new CefToolbarViewImpl instance. |delegate| may be nullptr.
+ static CefRefPtr<CefToolbarViewImpl> Create(
+ CefRefPtr<CefViewDelegate> delegate,
+ Browser* browser,
+ BrowserView* browser_view,
+ absl::optional<ToolbarView::DisplayMode> display_mode);
+
+ static const char* const kTypeString;
+
+ // CefViewAdapter methods:
+ std::string GetDebugType() override { return kTypeString; }
+
+ private:
+ // Create a new implementation object.
+ // Always call Initialize() after creation.
+ // |delegate| may be nullptr.
+ CefToolbarViewImpl(CefRefPtr<CefViewDelegate> delegate,
+ Browser* browser,
+ BrowserView* browser_view,
+ absl::optional<ToolbarView::DisplayMode> display_mode);
+
+ // CefViewImpl methods:
+ CefToolbarViewView* CreateRootView() override;
+ void InitializeRootView() override;
+
+ Browser* const browser_;
+ BrowserView* const browser_view_;
+ absl::optional<ToolbarView::DisplayMode> const display_mode_;
+
+ IMPLEMENT_REFCOUNTING_DELETE_ON_UIT(CefToolbarViewImpl);
+};
+
+#endif // CEF_LIBCEF_BROWSER_VIEWS_SCROLL_VIEW_IMPL_H_
diff --git a/libcef/browser/chrome/views/toolbar_view_view.cc b/libcef/browser/chrome/views/toolbar_view_view.cc
new file mode 100644
index 00000000..ad986bd5
--- /dev/null
+++ b/libcef/browser/chrome/views/toolbar_view_view.cc
@@ -0,0 +1,11 @@
+// Copyright 2021 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#include "libcef/browser/chrome/views/toolbar_view_view.h"
+
+CefToolbarViewView::CefToolbarViewView(CefViewDelegate* cef_delegate,
+ Browser* browser,
+ BrowserView* browser_view,
+ absl::optional<DisplayMode> display_mode)
+ : ParentClass(cef_delegate, browser, browser_view, display_mode) {}
diff --git a/libcef/browser/chrome/views/toolbar_view_view.h b/libcef/browser/chrome/views/toolbar_view_view.h
new file mode 100644
index 00000000..48920008
--- /dev/null
+++ b/libcef/browser/chrome/views/toolbar_view_view.h
@@ -0,0 +1,27 @@
+// Copyright 2021 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_CHROME_VIEWS_TOOLBAR_VIEW_VIEW_H_
+#define CEF_LIBCEF_BROWSER_CHROME_VIEWS_TOOLBAR_VIEW_VIEW_H_
+#pragma once
+
+#include "libcef/browser/views/view_view.h"
+
+#include "chrome/browser/ui/views/toolbar/toolbar_view.h"
+
+class CefToolbarViewView : public CefViewView<ToolbarView, CefViewDelegate> {
+ public:
+ using ParentClass = CefViewView<ToolbarView, CefViewDelegate>;
+
+ // |cef_delegate| may be nullptr.
+ explicit CefToolbarViewView(CefViewDelegate* cef_delegate,
+ Browser* browser,
+ BrowserView* browser_view,
+ absl::optional<DisplayMode> display_mode);
+
+ CefToolbarViewView(const CefToolbarViewView&) = delete;
+ CefToolbarViewView& operator=(const CefToolbarViewView&) = delete;
+};
+
+#endif // CEF_LIBCEF_BROWSER_CHROME_VIEWS_TOOLBAR_VIEW_VIEW_H_
diff --git a/libcef/browser/chrome_crash_reporter_client_stub.cc b/libcef/browser/chrome_crash_reporter_client_stub.cc
new file mode 100644
index 00000000..247f3234
--- /dev/null
+++ b/libcef/browser/chrome_crash_reporter_client_stub.cc
@@ -0,0 +1,15 @@
+// Copyright (c) 2019 The Chromium Embedded Framework Authors.
+// Portions copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "build/build_config.h"
+
+#if BUILDFLAG(IS_MAC)
+
+#include "chrome/app/chrome_crash_reporter_client.h"
+
+// Required due to https://crrev.com/1c9f89a06f
+void ChromeCrashReporterClient::Create() {}
+
+#endif // BUILDFLAG(IS_MAC)
diff --git a/libcef/browser/context.cc b/libcef/browser/context.cc
new file mode 100644
index 00000000..e4539f31
--- /dev/null
+++ b/libcef/browser/context.cc
@@ -0,0 +1,624 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#include "libcef/browser/context.h"
+
+#include "libcef/browser/browser_info_manager.h"
+#include "libcef/browser/request_context_impl.h"
+#include "libcef/browser/thread_util.h"
+#include "libcef/browser/trace_subscriber.h"
+#include "libcef/common/cef_switches.h"
+
+#include "base/files/file_util.h"
+#include "base/functional/bind.h"
+#include "base/run_loop.h"
+#include "base/task/current_thread.h"
+#include "base/threading/thread_restrictions.h"
+#include "components/network_session_configurator/common/network_switches.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/browser/notification_types.h"
+#include "ui/base/ui_base_switches.h"
+
+#if BUILDFLAG(IS_WIN)
+#include "base/debug/alias.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/win/win_util.h"
+#include "chrome/chrome_elf/chrome_elf_main.h"
+#include "chrome/install_static/initialize_from_primary_module.h"
+#include "include/internal/cef_win.h"
+#endif
+
+namespace {
+
+CefContext* g_context = nullptr;
+
+#if DCHECK_IS_ON()
+// When the process terminates check if CefShutdown() has been called.
+class CefShutdownChecker {
+ public:
+ ~CefShutdownChecker() { DCHECK(!g_context) << "CefShutdown was not called"; }
+} g_shutdown_checker;
+#endif // DCHECK_IS_ON()
+
+#if BUILDFLAG(IS_WIN)
+
+// Transfer state from chrome_elf.dll to the libcef.dll. Accessed when
+// loading chrome://system.
+void InitInstallDetails() {
+ static bool initialized = false;
+ if (initialized) {
+ return;
+ }
+ initialized = true;
+ install_static::InitializeFromPrimaryModule();
+}
+
+// Signal chrome_elf to initialize crash reporting, rather than doing it in
+// DllMain. See https://crbug.com/656800 for details.
+void InitCrashReporter() {
+ static bool initialized = false;
+ if (initialized) {
+ return;
+ }
+ initialized = true;
+ SignalInitializeCrashReporting();
+}
+
+#endif // BUILDFLAG(IS_WIN)
+
+bool GetColor(const cef_color_t cef_in, bool is_windowless, SkColor* sk_out) {
+ // Windowed browser colors must be fully opaque.
+ if (!is_windowless && CefColorGetA(cef_in) != SK_AlphaOPAQUE) {
+ return false;
+ }
+
+ // Windowless browser colors may be fully transparent.
+ if (is_windowless && CefColorGetA(cef_in) == SK_AlphaTRANSPARENT) {
+ *sk_out = SK_ColorTRANSPARENT;
+ return true;
+ }
+
+ // Ignore the alpha component.
+ *sk_out = SkColorSetRGB(CefColorGetR(cef_in), CefColorGetG(cef_in),
+ CefColorGetB(cef_in));
+ return true;
+}
+
+// Convert |path_str| to a normalized FilePath.
+base::FilePath NormalizePath(const cef_string_t& path_str,
+ const char* name,
+ bool* has_error = nullptr) {
+ if (has_error) {
+ *has_error = false;
+ }
+
+ base::FilePath path = base::FilePath(CefString(&path_str));
+ if (path.EndsWithSeparator()) {
+ // Remove the trailing separator because it will interfere with future
+ // equality checks.
+ path = path.StripTrailingSeparators();
+ }
+
+ if (!path.empty() && !path.IsAbsolute()) {
+ LOG(ERROR) << "The " << name << " directory (" << path.value()
+ << ") is not an absolute path. Defaulting to empty.";
+ if (has_error) {
+ *has_error = true;
+ }
+ path = base::FilePath();
+ }
+
+ return path;
+}
+
+void SetPath(cef_string_t& path_str, const base::FilePath& path) {
+#if BUILDFLAG(IS_WIN)
+ CefString(&path_str).FromWString(path.value());
+#else
+ CefString(&path_str).FromString(path.value());
+#endif
+}
+
+// Convert |path_str| to a normalized FilePath and update the |path_str| value.
+base::FilePath NormalizePathAndSet(cef_string_t& path_str, const char* name) {
+ const base::FilePath& path = NormalizePath(path_str, name);
+ SetPath(path_str, path);
+ return path;
+}
+
+// Verify that |cache_path| is valid and create it if necessary.
+bool ValidateCachePath(const base::FilePath& cache_path,
+ const base::FilePath& root_cache_path) {
+ if (cache_path.empty()) {
+ return true;
+ }
+
+ if (!root_cache_path.empty() && root_cache_path != cache_path &&
+ !root_cache_path.IsParent(cache_path)) {
+ LOG(ERROR) << "The cache_path directory (" << cache_path.value()
+ << ") is not a child of the root_cache_path directory ("
+ << root_cache_path.value() << ")";
+ return false;
+ }
+
+ base::ScopedAllowBlockingForTesting allow_blocking;
+ if (!base::DirectoryExists(cache_path) &&
+ !base::CreateDirectory(cache_path)) {
+ LOG(ERROR) << "The cache_path directory (" << cache_path.value()
+ << ") could not be created.";
+ return false;
+ }
+
+ return true;
+}
+
+// Like NormalizePathAndSet but with additional checks specific to the
+// cache_path value.
+base::FilePath NormalizeCachePathAndSet(cef_string_t& path_str,
+ const base::FilePath& root_cache_path) {
+ bool has_error = false;
+ base::FilePath path = NormalizePath(path_str, "cache_path", &has_error);
+ if (has_error || !ValidateCachePath(path, root_cache_path)) {
+ LOG(ERROR) << "The cache_path is invalid. Defaulting to in-memory storage.";
+ path = base::FilePath();
+ }
+ SetPath(path_str, path);
+ return path;
+}
+
+// Based on chrome/app/chrome_exe_main_win.cc.
+// In 32-bit builds, the main thread starts with the default (small) stack size.
+// The ARCH_CPU_32_BITS blocks here and below are in support of moving the main
+// thread to a fiber with a larger stack size.
+#if BUILDFLAG(IS_WIN) && defined(ARCH_CPU_32_BITS)
+// The information needed to transfer control to the large-stack fiber and later
+// pass the main routine's exit code back to the small-stack fiber prior to
+// termination.
+struct FiberState {
+ FiberState(wWinMainPtr wWinMain,
+ HINSTANCE hInstance,
+ LPWSTR lpCmdLine,
+ int nCmdShow) {
+ this->wWinMain = wWinMain;
+ this->hInstance = hInstance;
+ this->lpCmdLine = lpCmdLine;
+ this->nCmdShow = nCmdShow;
+ }
+
+ FiberState(mainPtr main, int argc, char** argv) {
+ this->main = main;
+ this->argc = argc;
+ this->argv = argv;
+ }
+
+ wWinMainPtr wWinMain = nullptr;
+ HINSTANCE hInstance;
+ LPWSTR lpCmdLine;
+ int nCmdShow;
+
+ mainPtr main = nullptr;
+ int argc;
+ char** argv;
+
+ LPVOID original_fiber;
+ int fiber_result;
+};
+
+// A PFIBER_START_ROUTINE function run on a large-stack fiber that calls the
+// main routine, stores its return value, and returns control to the small-stack
+// fiber. |params| must be a pointer to a FiberState struct.
+void WINAPI FiberBinder(void* params) {
+ auto* fiber_state = static_cast<FiberState*>(params);
+ // Call the main routine from the fiber. Reusing the entry point minimizes
+ // confusion when examining call stacks in crash reports - seeing wWinMain on
+ // the stack is a handy hint that this is the main thread of the process.
+ if (fiber_state->main) {
+ fiber_state->fiber_result =
+ fiber_state->main(fiber_state->argc, fiber_state->argv);
+ } else {
+ fiber_state->fiber_result =
+ fiber_state->wWinMain(fiber_state->hInstance, nullptr,
+ fiber_state->lpCmdLine, fiber_state->nCmdShow);
+ }
+
+ // Switch back to the main thread to exit.
+ ::SwitchToFiber(fiber_state->original_fiber);
+}
+
+int RunMainWithPreferredStackSize(FiberState& fiber_state) {
+ enum class FiberStatus { kConvertFailed, kCreateFiberFailed, kSuccess };
+ FiberStatus fiber_status = FiberStatus::kSuccess;
+ // GetLastError result if fiber conversion failed.
+ DWORD fiber_error = ERROR_SUCCESS;
+ if (!::IsThreadAFiber()) {
+ // Make the main thread's stack size 4 MiB so that it has roughly the same
+ // effective size as the 64-bit build's 8 MiB stack.
+ constexpr size_t kStackSize = 4 * 1024 * 1024; // 4 MiB
+ // Leak the fiber on exit.
+ LPVOID original_fiber =
+ ::ConvertThreadToFiberEx(nullptr, FIBER_FLAG_FLOAT_SWITCH);
+ if (original_fiber) {
+ fiber_state.original_fiber = original_fiber;
+ // Create a fiber with a bigger stack and switch to it. Leak the fiber on
+ // exit.
+ LPVOID big_stack_fiber = ::CreateFiberEx(
+ 0, kStackSize, FIBER_FLAG_FLOAT_SWITCH, FiberBinder, &fiber_state);
+ if (big_stack_fiber) {
+ ::SwitchToFiber(big_stack_fiber);
+ // The fibers must be cleaned up to avoid obscure TLS-related shutdown
+ // crashes.
+ ::DeleteFiber(big_stack_fiber);
+ ::ConvertFiberToThread();
+ // Control returns here after CEF has finished running on FiberMain.
+ return fiber_state.fiber_result;
+ }
+ fiber_status = FiberStatus::kCreateFiberFailed;
+ } else {
+ fiber_status = FiberStatus::kConvertFailed;
+ }
+ // If we reach here then creating and switching to a fiber has failed. This
+ // probably means we are low on memory and will soon crash. Try to report
+ // this error once crash reporting is initialized.
+ fiber_error = ::GetLastError();
+ base::debug::Alias(&fiber_error);
+ }
+
+ // If we are already a fiber then continue normal execution.
+ // Intentionally crash if converting to a fiber failed.
+ CHECK_EQ(fiber_status, FiberStatus::kSuccess);
+ return -1;
+}
+#endif // BUILDFLAG(IS_WIN) && defined(ARCH_CPU_32_BITS)
+
+} // namespace
+
+int CefExecuteProcess(const CefMainArgs& args,
+ CefRefPtr<CefApp> application,
+ void* windows_sandbox_info) {
+#if BUILDFLAG(IS_WIN)
+ InitInstallDetails();
+ InitCrashReporter();
+#endif
+
+ return CefMainRunner::RunAsHelperProcess(args, application,
+ windows_sandbox_info);
+}
+
+bool CefInitialize(const CefMainArgs& args,
+ const CefSettings& settings,
+ CefRefPtr<CefApp> application,
+ void* windows_sandbox_info) {
+#if BUILDFLAG(IS_WIN)
+ InitInstallDetails();
+ InitCrashReporter();
+#endif
+
+ // Return true if the global context already exists.
+ if (g_context) {
+ return true;
+ }
+
+ if (settings.size != sizeof(cef_settings_t)) {
+ NOTREACHED() << "invalid CefSettings structure size";
+ return false;
+ }
+
+ // Create the new global context object.
+ g_context = new CefContext();
+
+ // Initialize the global context.
+ return g_context->Initialize(args, settings, application,
+ windows_sandbox_info);
+}
+
+void CefShutdown() {
+ // Verify that the context is in a valid state.
+ if (!CONTEXT_STATE_VALID()) {
+ NOTREACHED() << "context not valid";
+ return;
+ }
+
+ // Must always be called on the same thread as Initialize.
+ if (!g_context->OnInitThread()) {
+ NOTREACHED() << "called on invalid thread";
+ return;
+ }
+
+ // Shut down the global context. This will block until shutdown is complete.
+ g_context->Shutdown();
+
+ // Delete the global context object.
+ delete g_context;
+ g_context = nullptr;
+}
+
+void CefDoMessageLoopWork() {
+ // Verify that the context is in a valid state.
+ if (!CONTEXT_STATE_VALID()) {
+ NOTREACHED() << "context not valid";
+ return;
+ }
+
+ // Must always be called on the same thread as Initialize.
+ if (!g_context->OnInitThread()) {
+ NOTREACHED() << "called on invalid thread";
+ return;
+ }
+
+ base::RunLoop run_loop;
+ run_loop.RunUntilIdle();
+}
+
+void CefRunMessageLoop() {
+ // Verify that the context is in a valid state.
+ if (!CONTEXT_STATE_VALID()) {
+ NOTREACHED() << "context not valid";
+ return;
+ }
+
+ // Must always be called on the same thread as Initialize.
+ if (!g_context->OnInitThread()) {
+ NOTREACHED() << "called on invalid thread";
+ return;
+ }
+
+ g_context->RunMessageLoop();
+}
+
+void CefQuitMessageLoop() {
+ // Verify that the context is in a valid state.
+ if (!CONTEXT_STATE_VALID()) {
+ NOTREACHED() << "context not valid";
+ return;
+ }
+
+ // Must always be called on the same thread as Initialize.
+ if (!g_context->OnInitThread()) {
+ NOTREACHED() << "called on invalid thread";
+ return;
+ }
+
+ g_context->QuitMessageLoop();
+}
+
+#if BUILDFLAG(IS_WIN)
+
+#if defined(ARCH_CPU_32_BITS)
+int CefRunWinMainWithPreferredStackSize(wWinMainPtr wWinMain,
+ HINSTANCE hInstance,
+ LPWSTR lpCmdLine,
+ int nCmdShow) {
+ CHECK(wWinMain && hInstance);
+ FiberState fiber_state(wWinMain, hInstance, lpCmdLine, nCmdShow);
+ return RunMainWithPreferredStackSize(fiber_state);
+}
+
+int CefRunMainWithPreferredStackSize(mainPtr main, int argc, char* argv[]) {
+ CHECK(main);
+ FiberState fiber_state(main, argc, argv);
+ return RunMainWithPreferredStackSize(fiber_state);
+}
+#endif // defined(ARCH_CPU_32_BITS)
+
+void CefEnableHighDPISupport() {
+ base::win::EnableHighDPISupport();
+}
+
+void CefSetOSModalLoop(bool osModalLoop) {
+ // Verify that the context is in a valid state.
+ if (!CONTEXT_STATE_VALID()) {
+ NOTREACHED() << "context not valid";
+ return;
+ }
+
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(CEF_UIT, base::BindOnce(CefSetOSModalLoop, osModalLoop));
+ return;
+ }
+
+ base::CurrentThread::Get()->set_os_modal_loop(osModalLoop);
+}
+
+#endif // BUILDFLAG(IS_WIN)
+
+// CefContext
+
+CefContext::CefContext()
+ : initialized_(false), shutting_down_(false), init_thread_id_(0) {}
+
+CefContext::~CefContext() {}
+
+// static
+CefContext* CefContext::Get() {
+ return g_context;
+}
+
+bool CefContext::Initialize(const CefMainArgs& args,
+ const CefSettings& settings,
+ CefRefPtr<CefApp> application,
+ void* windows_sandbox_info) {
+ init_thread_id_ = base::PlatformThread::CurrentId();
+ settings_ = settings;
+ application_ = application;
+
+#if !(BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX))
+ if (settings.multi_threaded_message_loop) {
+ NOTIMPLEMENTED() << "multi_threaded_message_loop is not supported.";
+ return false;
+ }
+#endif
+
+#if BUILDFLAG(IS_WIN)
+ // Signal Chrome Elf that Chrome has begun to start.
+ SignalChromeElf();
+#endif
+
+ const base::FilePath& root_cache_path =
+ NormalizePathAndSet(settings_.root_cache_path, "root_cache_path");
+ const base::FilePath& cache_path =
+ NormalizeCachePathAndSet(settings_.cache_path, root_cache_path);
+ if (root_cache_path.empty() && !cache_path.empty()) {
+ CefString(&settings_.root_cache_path) = cache_path.value();
+ }
+
+ // All other paths that need to be normalized.
+ NormalizePathAndSet(settings_.browser_subprocess_path,
+ "browser_subprocess_path");
+ NormalizePathAndSet(settings_.framework_dir_path, "framework_dir_path");
+ NormalizePathAndSet(settings_.main_bundle_path, "main_bundle_path");
+ NormalizePathAndSet(settings_.user_data_path, "user_data_path");
+ NormalizePathAndSet(settings_.resources_dir_path, "resources_dir_path");
+ NormalizePathAndSet(settings_.locales_dir_path, "locales_dir_path");
+
+ browser_info_manager_.reset(new CefBrowserInfoManager);
+
+ main_runner_.reset(new CefMainRunner(settings_.multi_threaded_message_loop,
+ settings_.external_message_pump));
+ return main_runner_->Initialize(
+ &settings_, application, args, windows_sandbox_info, &initialized_,
+ base::BindOnce(&CefContext::OnContextInitialized,
+ base::Unretained(this)));
+}
+
+void CefContext::RunMessageLoop() {
+ // Must always be called on the same thread as Initialize.
+ DCHECK(OnInitThread());
+
+ // Blocks until QuitMessageLoop() is called.
+ main_runner_->RunMessageLoop();
+}
+
+void CefContext::QuitMessageLoop() {
+ // Must always be called on the same thread as Initialize.
+ DCHECK(OnInitThread());
+
+ main_runner_->QuitMessageLoop();
+}
+
+void CefContext::Shutdown() {
+ // Must always be called on the same thread as Initialize.
+ DCHECK(OnInitThread());
+
+ shutting_down_ = true;
+
+ main_runner_->Shutdown(
+ base::BindOnce(&CefContext::ShutdownOnUIThread, base::Unretained(this)),
+ base::BindOnce(&CefContext::FinalizeShutdown, base::Unretained(this)));
+}
+
+bool CefContext::OnInitThread() {
+ return (base::PlatformThread::CurrentId() == init_thread_id_);
+}
+
+SkColor CefContext::GetBackgroundColor(
+ const CefBrowserSettings* browser_settings,
+ cef_state_t windowless_state) const {
+ bool is_windowless = windowless_state == STATE_ENABLED
+ ? true
+ : (windowless_state == STATE_DISABLED
+ ? false
+ : !!settings_.windowless_rendering_enabled);
+
+ // Default to opaque white if no acceptable color values are found.
+ SkColor sk_color = SK_ColorWHITE;
+
+ if (!browser_settings ||
+ !GetColor(browser_settings->background_color, is_windowless, &sk_color)) {
+ GetColor(settings_.background_color, is_windowless, &sk_color);
+ }
+ return sk_color;
+}
+
+CefTraceSubscriber* CefContext::GetTraceSubscriber() {
+ CEF_REQUIRE_UIT();
+ if (shutting_down_) {
+ return nullptr;
+ }
+ if (!trace_subscriber_.get()) {
+ trace_subscriber_.reset(new CefTraceSubscriber());
+ }
+ return trace_subscriber_.get();
+}
+
+void CefContext::PopulateGlobalRequestContextSettings(
+ CefRequestContextSettings* settings) {
+ CefRefPtr<CefCommandLine> command_line =
+ CefCommandLine::GetGlobalCommandLine();
+
+ // This value was already normalized in Initialize.
+ CefString(&settings->cache_path) = CefString(&settings_.cache_path);
+
+ settings->persist_session_cookies =
+ settings_.persist_session_cookies ||
+ command_line->HasSwitch(switches::kPersistSessionCookies);
+ settings->persist_user_preferences =
+ settings_.persist_user_preferences ||
+ command_line->HasSwitch(switches::kPersistUserPreferences);
+
+ CefString(&settings->cookieable_schemes_list) =
+ CefString(&settings_.cookieable_schemes_list);
+ settings->cookieable_schemes_exclude_defaults =
+ settings_.cookieable_schemes_exclude_defaults;
+}
+
+void CefContext::NormalizeRequestContextSettings(
+ CefRequestContextSettings* settings) {
+ // The |root_cache_path| value was already normalized in Initialize.
+ const base::FilePath& root_cache_path = CefString(&settings_.root_cache_path);
+ NormalizeCachePathAndSet(settings->cache_path, root_cache_path);
+}
+
+void CefContext::AddObserver(Observer* observer) {
+ CEF_REQUIRE_UIT();
+ observers_.AddObserver(observer);
+}
+
+void CefContext::RemoveObserver(Observer* observer) {
+ CEF_REQUIRE_UIT();
+ observers_.RemoveObserver(observer);
+}
+
+bool CefContext::HasObserver(Observer* observer) const {
+ CEF_REQUIRE_UIT();
+ return observers_.HasObserver(observer);
+}
+
+void CefContext::OnContextInitialized() {
+ CEF_REQUIRE_UIT();
+
+ if (application_) {
+ // Notify the handler after the global browser context has initialized.
+ CefRefPtr<CefRequestContext> request_context =
+ CefRequestContext::GetGlobalContext();
+ auto impl = static_cast<CefRequestContextImpl*>(request_context.get());
+ impl->ExecuteWhenBrowserContextInitialized(base::BindOnce(
+ [](CefRefPtr<CefApp> app) {
+ CefRefPtr<CefBrowserProcessHandler> handler =
+ app->GetBrowserProcessHandler();
+ if (handler) {
+ handler->OnContextInitialized();
+ }
+ },
+ application_));
+ }
+}
+
+void CefContext::ShutdownOnUIThread() {
+ CEF_REQUIRE_UIT();
+
+ browser_info_manager_->DestroyAllBrowsers();
+
+ for (auto& observer : observers_) {
+ observer.OnContextDestroyed();
+ }
+
+ if (trace_subscriber_.get()) {
+ trace_subscriber_.reset(nullptr);
+ }
+}
+
+void CefContext::FinalizeShutdown() {
+ browser_info_manager_.reset(nullptr);
+ application_ = nullptr;
+}
diff --git a/libcef/browser/context.h b/libcef/browser/context.h
new file mode 100644
index 00000000..40530c01
--- /dev/null
+++ b/libcef/browser/context.h
@@ -0,0 +1,123 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_CONTEXT_H_
+#define CEF_LIBCEF_BROWSER_CONTEXT_H_
+#pragma once
+
+#include <list>
+#include <map>
+#include <string>
+
+#include "include/cef_app.h"
+#include "libcef/browser/main_runner.h"
+
+#include "base/observer_list.h"
+#include "base/threading/platform_thread.h"
+#include "third_party/skia/include/core/SkColor.h"
+
+class CefBrowserInfoManager;
+class CefTraceSubscriber;
+
+class CefContext {
+ public:
+ // Interface to implement for observers that wish to be informed of changes
+ // to the context. All methods will be called on the UI thread.
+ class Observer {
+ public:
+ // Called before the context is destroyed.
+ virtual void OnContextDestroyed() = 0;
+
+ protected:
+ virtual ~Observer() {}
+ };
+
+ CefContext();
+ ~CefContext();
+
+ // Returns the singleton CefContext instance.
+ static CefContext* Get();
+
+ // These methods will be called on the main application thread.
+ bool Initialize(const CefMainArgs& args,
+ const CefSettings& settings,
+ CefRefPtr<CefApp> application,
+ void* windows_sandbox_info);
+ void RunMessageLoop();
+ void QuitMessageLoop();
+ void Shutdown();
+
+ // Returns true if the current thread is the initialization thread.
+ bool OnInitThread();
+
+ // Returns true if the context is initialized.
+ bool initialized() { return initialized_; }
+
+ // Returns true if the context is shutting down.
+ bool shutting_down() { return shutting_down_; }
+
+ const CefSettings& settings() const { return settings_; }
+
+ // Returns the background color for the browser. If |browser_settings| is
+ // nullptr or does not specify a color then the global settings will be used.
+ // The alpha component will be either SK_AlphaTRANSPARENT or SK_AlphaOPAQUE
+ // (e.g. fully transparent or fully opaque). If |is_windowless| is
+ // STATE_DISABLED then SK_AlphaTRANSPARENT will always be returned. If
+ // |is_windowless| is STATE_ENABLED then SK_ColorTRANSPARENT may be returned
+ // to enable transparency for windowless browsers. See additional comments on
+ // CefSettings.background_color and CefBrowserSettings.background_color.
+ SkColor GetBackgroundColor(const CefBrowserSettings* browser_settings,
+ cef_state_t windowless_state) const;
+
+ CefTraceSubscriber* GetTraceSubscriber();
+
+ // Populate request context settings for the global system context based on
+ // CefSettings and command-line flags.
+ void PopulateGlobalRequestContextSettings(
+ CefRequestContextSettings* settings);
+
+ // Normalize and validate request context settings for user-created contexts.
+ void NormalizeRequestContextSettings(CefRequestContextSettings* settings);
+
+ // Manage observer objects. The observer must either outlive this object or
+ // remove itself before destruction. These methods can only be called on the
+ // UI thread.
+ void AddObserver(Observer* observer);
+ void RemoveObserver(Observer* observer);
+ bool HasObserver(Observer* observer) const;
+
+ private:
+ void OnContextInitialized();
+
+ // Performs shutdown actions that need to occur on the UI thread before any
+ // threads are destroyed.
+ void ShutdownOnUIThread();
+
+ // Destroys the main runner and related objects.
+ void FinalizeShutdown();
+
+ // Track context state.
+ bool initialized_;
+ bool shutting_down_;
+
+ // The thread on which the context was initialized.
+ base::PlatformThreadId init_thread_id_;
+
+ CefSettings settings_;
+ CefRefPtr<CefApp> application_;
+
+ std::unique_ptr<CefMainRunner> main_runner_;
+ std::unique_ptr<CefTraceSubscriber> trace_subscriber_;
+ std::unique_ptr<CefBrowserInfoManager> browser_info_manager_;
+
+ // Observers that want to be notified of changes to this object.
+ base::ObserverList<Observer>::Unchecked observers_;
+};
+
+// Helper macro that returns true if the global context is in a valid state.
+#define CONTEXT_STATE_VALID() \
+ (CefContext::Get() && CefContext::Get()->initialized() && \
+ !CefContext::Get()->shutting_down())
+
+#endif // CEF_LIBCEF_BROWSER_CONTEXT_H_
diff --git a/libcef/browser/context_menu_params_impl.cc b/libcef/browser/context_menu_params_impl.cc
new file mode 100644
index 00000000..fe3be41d
--- /dev/null
+++ b/libcef/browser/context_menu_params_impl.cc
@@ -0,0 +1,158 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "libcef/browser/context_menu_params_impl.h"
+
+#include "base/logging.h"
+#include "third_party/blink/public/mojom/context_menu/context_menu.mojom.h"
+
+CefContextMenuParamsImpl::CefContextMenuParamsImpl(
+ content::ContextMenuParams* value)
+ : CefValueBase<CefContextMenuParams, content::ContextMenuParams>(
+ value,
+ nullptr,
+ kOwnerNoDelete,
+ true,
+ new CefValueControllerNonThreadSafe()) {
+ // Indicate that this object owns the controller.
+ SetOwnsController();
+}
+
+int CefContextMenuParamsImpl::GetXCoord() {
+ CEF_VALUE_VERIFY_RETURN(false, 0);
+ return const_value().x;
+}
+
+int CefContextMenuParamsImpl::GetYCoord() {
+ CEF_VALUE_VERIFY_RETURN(false, 0);
+ return const_value().y;
+}
+
+CefContextMenuParamsImpl::TypeFlags CefContextMenuParamsImpl::GetTypeFlags() {
+ CEF_VALUE_VERIFY_RETURN(false, CM_TYPEFLAG_NONE);
+ const content::ContextMenuParams& params = const_value();
+ int type_flags = CM_TYPEFLAG_NONE;
+ if (!params.page_url.is_empty()) {
+ type_flags |= CM_TYPEFLAG_PAGE;
+ }
+ if (!params.frame_url.is_empty()) {
+ type_flags |= CM_TYPEFLAG_FRAME;
+ }
+ if (!params.link_url.is_empty()) {
+ type_flags |= CM_TYPEFLAG_LINK;
+ }
+ if (params.media_type != blink::mojom::ContextMenuDataMediaType::kNone) {
+ type_flags |= CM_TYPEFLAG_MEDIA;
+ }
+ if (!params.selection_text.empty()) {
+ type_flags |= CM_TYPEFLAG_SELECTION;
+ }
+ if (params.is_editable) {
+ type_flags |= CM_TYPEFLAG_EDITABLE;
+ }
+ return static_cast<TypeFlags>(type_flags);
+}
+
+CefString CefContextMenuParamsImpl::GetLinkUrl() {
+ CEF_VALUE_VERIFY_RETURN(false, CefString());
+ return const_value().link_url.spec();
+}
+
+CefString CefContextMenuParamsImpl::GetUnfilteredLinkUrl() {
+ CEF_VALUE_VERIFY_RETURN(false, CefString());
+ return const_value().unfiltered_link_url.spec();
+}
+
+CefString CefContextMenuParamsImpl::GetSourceUrl() {
+ CEF_VALUE_VERIFY_RETURN(false, CefString());
+ return const_value().src_url.spec();
+}
+
+bool CefContextMenuParamsImpl::HasImageContents() {
+ CEF_VALUE_VERIFY_RETURN(false, true);
+ return const_value().has_image_contents;
+}
+
+CefString CefContextMenuParamsImpl::GetTitleText() {
+ CEF_VALUE_VERIFY_RETURN(false, CefString());
+ return const_value().title_text;
+}
+
+CefString CefContextMenuParamsImpl::GetPageUrl() {
+ CEF_VALUE_VERIFY_RETURN(false, CefString());
+ return const_value().page_url.spec();
+}
+
+CefString CefContextMenuParamsImpl::GetFrameUrl() {
+ CEF_VALUE_VERIFY_RETURN(false, CefString());
+ return const_value().frame_url.spec();
+}
+
+CefString CefContextMenuParamsImpl::GetFrameCharset() {
+ CEF_VALUE_VERIFY_RETURN(false, CefString());
+ return const_value().frame_charset;
+}
+
+CefContextMenuParamsImpl::MediaType CefContextMenuParamsImpl::GetMediaType() {
+ CEF_VALUE_VERIFY_RETURN(false, CM_MEDIATYPE_NONE);
+ return static_cast<MediaType>(const_value().media_type);
+}
+
+CefContextMenuParamsImpl::MediaStateFlags
+CefContextMenuParamsImpl::GetMediaStateFlags() {
+ CEF_VALUE_VERIFY_RETURN(false, CM_MEDIAFLAG_NONE);
+ return static_cast<MediaStateFlags>(const_value().media_flags);
+}
+
+CefString CefContextMenuParamsImpl::GetSelectionText() {
+ CEF_VALUE_VERIFY_RETURN(false, CefString());
+ return const_value().selection_text;
+}
+
+CefString CefContextMenuParamsImpl::GetMisspelledWord() {
+ CEF_VALUE_VERIFY_RETURN(false, CefString());
+ return const_value().misspelled_word;
+}
+
+bool CefContextMenuParamsImpl::GetDictionarySuggestions(
+ std::vector<CefString>& suggestions) {
+ CEF_VALUE_VERIFY_RETURN(false, false);
+
+ if (!suggestions.empty()) {
+ suggestions.clear();
+ }
+
+ if (const_value().dictionary_suggestions.empty()) {
+ return false;
+ }
+
+ std::vector<std::u16string>::const_iterator it =
+ const_value().dictionary_suggestions.begin();
+ for (; it != const_value().dictionary_suggestions.end(); ++it) {
+ suggestions.push_back(*it);
+ }
+
+ return true;
+}
+
+bool CefContextMenuParamsImpl::IsEditable() {
+ CEF_VALUE_VERIFY_RETURN(false, false);
+ return const_value().is_editable;
+}
+
+bool CefContextMenuParamsImpl::IsSpellCheckEnabled() {
+ CEF_VALUE_VERIFY_RETURN(false, false);
+ return const_value().spellcheck_enabled;
+}
+
+CefContextMenuParamsImpl::EditStateFlags
+CefContextMenuParamsImpl::GetEditStateFlags() {
+ CEF_VALUE_VERIFY_RETURN(false, CM_EDITFLAG_NONE);
+ return static_cast<EditStateFlags>(const_value().edit_flags);
+}
+
+bool CefContextMenuParamsImpl::IsCustomMenu() {
+ CEF_VALUE_VERIFY_RETURN(false, false);
+ return !const_value().custom_items.empty();
+}
diff --git a/libcef/browser/context_menu_params_impl.h b/libcef/browser/context_menu_params_impl.h
new file mode 100644
index 00000000..782848a0
--- /dev/null
+++ b/libcef/browser/context_menu_params_impl.h
@@ -0,0 +1,46 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_CONTEXT_MENU_PARAMS_IMPL_H_
+#define CEF_LIBCEF_BROWSER_CONTEXT_MENU_PARAMS_IMPL_H_
+#pragma once
+
+#include "include/cef_context_menu_handler.h"
+#include "libcef/common/value_base.h"
+
+#include "content/public/browser/context_menu_params.h"
+
+// CefContextMenuParams implementation. This class is not thread safe.
+class CefContextMenuParamsImpl
+ : public CefValueBase<CefContextMenuParams, content::ContextMenuParams> {
+ public:
+ explicit CefContextMenuParamsImpl(content::ContextMenuParams* value);
+
+ CefContextMenuParamsImpl(const CefContextMenuParamsImpl&) = delete;
+ CefContextMenuParamsImpl& operator=(const CefContextMenuParamsImpl&) = delete;
+
+ // CefContextMenuParams methods.
+ int GetXCoord() override;
+ int GetYCoord() override;
+ TypeFlags GetTypeFlags() override;
+ CefString GetLinkUrl() override;
+ CefString GetUnfilteredLinkUrl() override;
+ CefString GetSourceUrl() override;
+ bool HasImageContents() override;
+ CefString GetTitleText() override;
+ CefString GetPageUrl() override;
+ CefString GetFrameUrl() override;
+ CefString GetFrameCharset() override;
+ MediaType GetMediaType() override;
+ MediaStateFlags GetMediaStateFlags() override;
+ CefString GetSelectionText() override;
+ CefString GetMisspelledWord() override;
+ bool GetDictionarySuggestions(std::vector<CefString>& suggestions) override;
+ bool IsEditable() override;
+ bool IsSpellCheckEnabled() override;
+ EditStateFlags GetEditStateFlags() override;
+ bool IsCustomMenu() override;
+};
+
+#endif // CEF_LIBCEF_BROWSER_CONTEXT_MENU_PARAMS_IMPL_H_
diff --git a/libcef/browser/devtools/devtools_controller.cc b/libcef/browser/devtools/devtools_controller.cc
new file mode 100644
index 00000000..30f57761
--- /dev/null
+++ b/libcef/browser/devtools/devtools_controller.cc
@@ -0,0 +1,143 @@
+// Copyright (c) 2020 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "libcef/browser/devtools/devtools_controller.h"
+
+#include "libcef/browser/devtools/devtools_util.h"
+#include "libcef/browser/thread_util.h"
+
+#include "base/json/json_reader.h"
+#include "base/json/json_writer.h"
+#include "content/public/browser/devtools_agent_host.h"
+
+CefDevToolsController::CefDevToolsController(
+ content::WebContents* inspected_contents)
+ : inspected_contents_(inspected_contents), weak_ptr_factory_(this) {
+ DCHECK(inspected_contents_);
+}
+
+CefDevToolsController::~CefDevToolsController() {
+ if (agent_host_) {
+ agent_host_->DetachClient(this);
+ AgentHostClosed(agent_host_.get());
+ }
+
+ for (auto& observer : observers_) {
+ observer.OnDevToolsControllerDestroyed();
+ }
+}
+
+bool CefDevToolsController::SendDevToolsMessage(
+ const base::StringPiece& message) {
+ CEF_REQUIRE_UIT();
+ if (!EnsureAgentHost()) {
+ return false;
+ }
+
+ agent_host_->DispatchProtocolMessage(
+ this, base::as_bytes(base::make_span(message)));
+ return true;
+}
+
+int CefDevToolsController::ExecuteDevToolsMethod(
+ int suggested_message_id,
+ const std::string& method,
+ const base::Value::Dict* params) {
+ CEF_REQUIRE_UIT();
+ if (!EnsureAgentHost()) {
+ return 0;
+ }
+
+ // Message IDs must always be increasing and unique.
+ int message_id = suggested_message_id;
+ if (message_id < next_message_id_) {
+ message_id = next_message_id_++;
+ } else {
+ next_message_id_ = message_id + 1;
+ }
+
+ base::Value::Dict message;
+ message.Set("id", message_id);
+ message.Set("method", method);
+ if (params) {
+ message.Set("params", params->Clone());
+ }
+
+ std::string protocol_message;
+ if (!base::JSONWriter::Write(message, &protocol_message)) {
+ return 0;
+ }
+
+ agent_host_->DispatchProtocolMessage(
+ this, base::as_bytes(base::make_span(protocol_message)));
+ return message_id;
+}
+
+void CefDevToolsController::AgentHostClosed(
+ content::DevToolsAgentHost* agent_host) {
+ DCHECK(agent_host == agent_host_.get());
+ agent_host_ = nullptr;
+ for (auto& observer : observers_) {
+ observer.OnDevToolsAgentDetached();
+ }
+}
+
+void CefDevToolsController::AddObserver(Observer* observer) {
+ CEF_REQUIRE_UIT();
+ observers_.AddObserver(observer);
+}
+
+void CefDevToolsController::RemoveObserver(Observer* observer) {
+ CEF_REQUIRE_UIT();
+ observers_.RemoveObserver(observer);
+}
+
+void CefDevToolsController::DispatchProtocolMessage(
+ content::DevToolsAgentHost* agent_host,
+ base::span<const uint8_t> message) {
+ if (observers_.empty()) {
+ return;
+ }
+
+ base::StringPiece str_message(reinterpret_cast<const char*>(message.data()),
+ message.size());
+ if (!devtools_util::ProtocolParser::IsValidMessage(str_message)) {
+ LOG(WARNING) << "Invalid message: " << str_message.substr(0, 100);
+ return;
+ }
+
+ devtools_util::ProtocolParser parser;
+
+ for (auto& observer : observers_) {
+ if (observer.OnDevToolsMessage(str_message)) {
+ continue;
+ }
+
+ // Only perform parsing a single time.
+ if (parser.Initialize(str_message) && parser.IsFailure()) {
+ LOG(WARNING) << "Failed to parse message: " << str_message.substr(0, 100);
+ }
+
+ if (parser.IsEvent()) {
+ observer.OnDevToolsEvent(parser.method_, parser.params_);
+ } else if (parser.IsResult()) {
+ observer.OnDevToolsMethodResult(parser.message_id_, parser.success_,
+ parser.params_);
+ }
+ }
+}
+
+bool CefDevToolsController::EnsureAgentHost() {
+ if (!agent_host_) {
+ agent_host_ =
+ content::DevToolsAgentHost::GetOrCreateFor(inspected_contents_);
+ if (agent_host_) {
+ agent_host_->AttachClient(this);
+ for (auto& observer : observers_) {
+ observer.OnDevToolsAgentAttached();
+ }
+ }
+ }
+ return !!agent_host_;
+}
diff --git a/libcef/browser/devtools/devtools_controller.h b/libcef/browser/devtools/devtools_controller.h
new file mode 100644
index 00000000..3bed09ff
--- /dev/null
+++ b/libcef/browser/devtools/devtools_controller.h
@@ -0,0 +1,81 @@
+// Copyright (c) 2020 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_DEVTOOLS_DEVTOOLS_CONTROLLER_H_
+#define CEF_LIBCEF_BROWSER_DEVTOOLS_DEVTOOLS_CONTROLLER_H_
+
+#include <memory>
+
+#include "content/public/browser/devtools_agent_host_client.h"
+
+#include "base/containers/span.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/observer_list.h"
+#include "base/values.h"
+
+namespace content {
+class WebContents;
+}
+
+class CefDevToolsController : public content::DevToolsAgentHostClient {
+ public:
+ class Observer : public base::CheckedObserver {
+ public:
+ // See CefDevToolsMessageObserver documentation.
+ virtual bool OnDevToolsMessage(const base::StringPiece& message) = 0;
+ virtual void OnDevToolsMethodResult(int message_id,
+ bool success,
+ const base::StringPiece& result) = 0;
+ virtual void OnDevToolsEvent(const base::StringPiece& method,
+ const base::StringPiece& params) = 0;
+ virtual void OnDevToolsAgentAttached() = 0;
+ virtual void OnDevToolsAgentDetached() = 0;
+
+ virtual void OnDevToolsControllerDestroyed() = 0;
+
+ protected:
+ ~Observer() override {}
+ };
+
+ // |inspected_contents| will outlive this object.
+ explicit CefDevToolsController(content::WebContents* inspected_contents);
+
+ CefDevToolsController(const CefDevToolsController&) = delete;
+ CefDevToolsController& operator=(const CefDevToolsController&) = delete;
+
+ ~CefDevToolsController() override;
+
+ // See CefBrowserHost methods of the same name for documentation.
+ bool SendDevToolsMessage(const base::StringPiece& message);
+ int ExecuteDevToolsMethod(int message_id,
+ const std::string& method,
+ const base::Value::Dict* params);
+
+ // |observer| must outlive this object or be removed.
+ void AddObserver(Observer* observer);
+ void RemoveObserver(Observer* observer);
+
+ base::WeakPtr<CefDevToolsController> GetWeakPtr() {
+ return weak_ptr_factory_.GetWeakPtr();
+ }
+
+ private:
+ // content::DevToolsAgentHostClient implementation:
+ void AgentHostClosed(content::DevToolsAgentHost* agent_host) override;
+ void DispatchProtocolMessage(content::DevToolsAgentHost* agent_host,
+ base::span<const uint8_t> message) override;
+
+ bool EnsureAgentHost();
+
+ content::WebContents* const inspected_contents_;
+ scoped_refptr<content::DevToolsAgentHost> agent_host_;
+ int next_message_id_ = 1;
+
+ base::ObserverList<Observer> observers_;
+
+ base::WeakPtrFactory<CefDevToolsController> weak_ptr_factory_;
+};
+
+#endif // CEF_LIBCEF_BROWSER_DEVTOOLS_DEVTOOLS_CONTROLLER_H_
diff --git a/libcef/browser/devtools/devtools_file_manager.cc b/libcef/browser/devtools/devtools_file_manager.cc
new file mode 100644
index 00000000..2d8220b4
--- /dev/null
+++ b/libcef/browser/devtools/devtools_file_manager.cc
@@ -0,0 +1,206 @@
+// Copyright 2019 The Chromium Embedded Framework Authors. Portions copyright
+// 2013 The Chromium Authors. All rights reserved. Use of this source code is
+// governed by a BSD-style license that can be found in the LICENSE file.
+
+#include "libcef/browser/devtools/devtools_file_manager.h"
+
+#include "libcef/browser/alloy/alloy_browser_host_impl.h"
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/functional/bind.h"
+#include "base/functional/callback.h"
+#include "base/json/json_writer.h"
+#include "base/json/values_util.h"
+#include "base/lazy_instance.h"
+#include "base/path_service.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/task/sequenced_task_runner.h"
+#include "base/task/thread_pool.h"
+#include "base/values.h"
+#include "chrome/common/pref_names.h"
+#include "components/prefs/scoped_user_pref_update.h"
+#include "content/public/browser/web_contents.h"
+
+namespace {
+
+base::LazyInstance<base::FilePath>::Leaky g_last_save_path =
+ LAZY_INSTANCE_INITIALIZER;
+
+void WriteToFile(const base::FilePath& path, const std::string& content) {
+ DCHECK(!path.empty());
+ base::WriteFile(path, content.c_str(), content.length());
+}
+
+void AppendToFile(const base::FilePath& path, const std::string& content) {
+ DCHECK(!path.empty());
+ base::AppendToFile(path, base::StringPiece(content));
+}
+
+} // namespace
+
+CefDevToolsFileManager::CefDevToolsFileManager(
+ AlloyBrowserHostImpl* browser_impl,
+ PrefService* prefs)
+ : browser_impl_(browser_impl),
+ prefs_(prefs),
+ file_task_runner_(
+ base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()})),
+ weak_factory_(this) {}
+
+void CefDevToolsFileManager::SaveToFile(const std::string& url,
+ const std::string& content,
+ bool save_as) {
+ Save(url, content, save_as,
+ base::BindOnce(&CefDevToolsFileManager::FileSavedAs,
+ weak_factory_.GetWeakPtr(), url),
+ base::BindOnce(&CefDevToolsFileManager::CanceledFileSaveAs,
+ weak_factory_.GetWeakPtr(), url));
+}
+
+void CefDevToolsFileManager::AppendToFile(const std::string& url,
+ const std::string& content) {
+ Append(url, content,
+ base::BindOnce(&CefDevToolsFileManager::AppendedTo,
+ weak_factory_.GetWeakPtr(), url));
+}
+
+void CefDevToolsFileManager::Save(const std::string& url,
+ const std::string& content,
+ bool save_as,
+ SaveCallback saveCallback,
+ CancelCallback cancelCallback) {
+ auto it = saved_files_.find(url);
+ if (it != saved_files_.end() && !save_as) {
+ SaveAsFileSelected(url, content, std::move(saveCallback), it->second);
+ return;
+ }
+
+ const base::Value::Dict& file_map =
+ prefs_->GetDict(prefs::kDevToolsEditedFiles);
+ base::FilePath initial_path;
+
+ if (const base::Value* path_value = file_map.Find(base::MD5String(url))) {
+ absl::optional<base::FilePath> path = base::ValueToFilePath(*path_value);
+ if (path) {
+ initial_path = std::move(*path);
+ }
+ }
+
+ if (initial_path.empty()) {
+ GURL gurl(url);
+ std::string suggested_file_name =
+ gurl.is_valid() ? gurl.ExtractFileName() : url;
+
+ if (suggested_file_name.length() > 64) {
+ suggested_file_name = suggested_file_name.substr(0, 64);
+ }
+
+ if (!g_last_save_path.Pointer()->empty()) {
+ initial_path = g_last_save_path.Pointer()->DirName().AppendASCII(
+ suggested_file_name);
+ } else {
+ // Use the temp directory. It may be an empty value.
+ base::PathService::Get(base::DIR_TEMP, &initial_path);
+ initial_path = initial_path.AppendASCII(suggested_file_name);
+ }
+ }
+
+ blink::mojom::FileChooserParams params;
+ params.mode = blink::mojom::FileChooserParams::Mode::kSave;
+ if (!initial_path.empty()) {
+ params.default_file_name = initial_path;
+ if (!initial_path.Extension().empty()) {
+ params.accept_types.push_back(CefString(initial_path.Extension()));
+ }
+ }
+
+ browser_impl_->RunFileChooserForBrowser(
+ params,
+ base::BindOnce(&CefDevToolsFileManager::SaveAsDialogDismissed,
+ weak_factory_.GetWeakPtr(), url, content,
+ std::move(saveCallback), std::move(cancelCallback)));
+}
+
+void CefDevToolsFileManager::SaveAsDialogDismissed(
+ const std::string& url,
+ const std::string& content,
+ SaveCallback saveCallback,
+ CancelCallback cancelCallback,
+ const std::vector<base::FilePath>& file_paths) {
+ if (file_paths.size() == 1) {
+ SaveAsFileSelected(url, content, std::move(saveCallback), file_paths[0]);
+ } else {
+ std::move(cancelCallback).Run();
+ }
+}
+
+void CefDevToolsFileManager::SaveAsFileSelected(const std::string& url,
+ const std::string& content,
+ SaveCallback callback,
+ const base::FilePath& path) {
+ *g_last_save_path.Pointer() = path;
+ saved_files_[url] = path;
+
+ ScopedDictPrefUpdate update(prefs_, prefs::kDevToolsEditedFiles);
+ update->Set(base::MD5String(url), base::FilePathToValue(path));
+ std::string file_system_path = path.AsUTF8Unsafe();
+ std::move(callback).Run(file_system_path);
+ file_task_runner_->PostTask(FROM_HERE,
+ base::BindOnce(&::WriteToFile, path, content));
+}
+
+void CefDevToolsFileManager::FileSavedAs(const std::string& url,
+ const std::string& file_system_path) {
+ base::Value url_value(url);
+ base::Value file_system_path_value(file_system_path);
+ CallClientFunction("DevToolsAPI.savedURL", &url_value,
+ &file_system_path_value, nullptr);
+}
+
+void CefDevToolsFileManager::CanceledFileSaveAs(const std::string& url) {
+ base::Value url_value(url);
+ CallClientFunction("DevToolsAPI.canceledSaveURL", &url_value, nullptr,
+ nullptr);
+}
+
+void CefDevToolsFileManager::Append(const std::string& url,
+ const std::string& content,
+ AppendCallback callback) {
+ auto it = saved_files_.find(url);
+ if (it == saved_files_.end()) {
+ return;
+ }
+ std::move(callback).Run();
+ file_task_runner_->PostTask(
+ FROM_HERE, base::BindOnce(&::AppendToFile, it->second, content));
+}
+
+void CefDevToolsFileManager::AppendedTo(const std::string& url) {
+ base::Value url_value(url);
+ CallClientFunction("DevToolsAPI.appendedToURL", &url_value, nullptr, nullptr);
+}
+
+void CefDevToolsFileManager::CallClientFunction(
+ const std::string& function_name,
+ const base::Value* arg1,
+ const base::Value* arg2,
+ const base::Value* arg3) {
+ std::string javascript = function_name + "(";
+ if (arg1) {
+ std::string json;
+ base::JSONWriter::Write(*arg1, &json);
+ javascript.append(json);
+ if (arg2) {
+ base::JSONWriter::Write(*arg2, &json);
+ javascript.append(", ").append(json);
+ if (arg3) {
+ base::JSONWriter::Write(*arg3, &json);
+ javascript.append(", ").append(json);
+ }
+ }
+ }
+ javascript.append(");");
+ browser_impl_->web_contents()->GetPrimaryMainFrame()->ExecuteJavaScript(
+ base::UTF8ToUTF16(javascript), base::NullCallback());
+}
diff --git a/libcef/browser/devtools/devtools_file_manager.h b/libcef/browser/devtools/devtools_file_manager.h
new file mode 100644
index 00000000..08b2b830
--- /dev/null
+++ b/libcef/browser/devtools/devtools_file_manager.h
@@ -0,0 +1,82 @@
+// Copyright 2019 The Chromium Embedded Framework Authors. Portions copyright
+// 2013 The Chromium Authors. All rights reserved. Use of this source code is
+// governed by a BSD-style license that can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_DEVTOOLS_DEVTOOLS_FILE_MANAGER_H_
+#define CEF_LIBCEF_BROWSER_DEVTOOLS_DEVTOOLS_FILE_MANAGER_H_
+
+#include "base/functional/callback_forward.h"
+#include "base/memory/weak_ptr.h"
+
+#include <map>
+#include <string>
+
+namespace base {
+class FilePath;
+class SequencedTaskRunner;
+class Value;
+} // namespace base
+
+class AlloyBrowserHostImpl;
+class PrefService;
+
+// File management helper for DevTools.
+// Based on chrome/browser/devtools/devtools_ui_bindings.cc and
+// chrome/browser/devtools/devtools_file_helper.cc.
+class CefDevToolsFileManager {
+ public:
+ CefDevToolsFileManager(AlloyBrowserHostImpl* browser_impl,
+ PrefService* prefs);
+
+ CefDevToolsFileManager(const CefDevToolsFileManager&) = delete;
+ CefDevToolsFileManager& operator=(const CefDevToolsFileManager&) = delete;
+
+ void SaveToFile(const std::string& url,
+ const std::string& content,
+ bool save_as);
+ void AppendToFile(const std::string& url, const std::string& content);
+
+ private:
+ // SaveToFile implementation:
+ using SaveCallback = base::OnceCallback<void(const std::string&)>;
+ using CancelCallback = base::OnceCallback<void()>;
+ void Save(const std::string& url,
+ const std::string& content,
+ bool save_as,
+ SaveCallback saveCallback,
+ CancelCallback cancelCallback);
+ void SaveAsDialogDismissed(const std::string& url,
+ const std::string& content,
+ SaveCallback saveCallback,
+ CancelCallback cancelCallback,
+ const std::vector<base::FilePath>& file_paths);
+ void SaveAsFileSelected(const std::string& url,
+ const std::string& content,
+ SaveCallback callback,
+ const base::FilePath& path);
+ void FileSavedAs(const std::string& url, const std::string& file_system_path);
+ void CanceledFileSaveAs(const std::string& url);
+
+ // AppendToFile implementation:
+ using AppendCallback = base::OnceCallback<void(void)>;
+ void Append(const std::string& url,
+ const std::string& content,
+ AppendCallback callback);
+ void AppendedTo(const std::string& url);
+
+ void CallClientFunction(const std::string& function_name,
+ const base::Value* arg1,
+ const base::Value* arg2,
+ const base::Value* arg3);
+
+ // Guaranteed to outlive this object.
+ AlloyBrowserHostImpl* browser_impl_;
+ PrefService* prefs_;
+
+ using PathsMap = std::map<std::string, base::FilePath>;
+ PathsMap saved_files_;
+ scoped_refptr<base::SequencedTaskRunner> file_task_runner_;
+ base::WeakPtrFactory<CefDevToolsFileManager> weak_factory_;
+};
+
+#endif // CEF_LIBCEF_BROWSER_DEVTOOLS_DEVTOOLS_FILE_MANAGER_H_
diff --git a/libcef/browser/devtools/devtools_frontend.cc b/libcef/browser/devtools/devtools_frontend.cc
new file mode 100644
index 00000000..b778fad7
--- /dev/null
+++ b/libcef/browser/devtools/devtools_frontend.cc
@@ -0,0 +1,665 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/devtools/devtools_frontend.h"
+
+#include <stddef.h>
+
+#include <iomanip>
+#include <utility>
+
+#include "libcef/browser/browser_context.h"
+#include "libcef/browser/devtools/devtools_manager_delegate.h"
+#include "libcef/browser/net/devtools_scheme_handler.h"
+#include "libcef/browser/thread_util.h"
+#include "libcef/common/cef_switches.h"
+#include "libcef/common/task_runner_manager.h"
+
+#include "base/base64.h"
+#include "base/command_line.h"
+#include "base/files/file_util.h"
+#include "base/guid.h"
+#include "base/json/json_reader.h"
+#include "base/json/json_writer.h"
+#include "base/json/string_escape.h"
+#include "base/memory/ptr_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/pref_names.h"
+#include "components/prefs/scoped_user_pref_update.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/file_url_loader.h"
+#include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/shared_cors_origin_access_list.h"
+#include "content/public/browser/storage_partition.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/common/content_client.h"
+#include "content/public/common/url_constants.h"
+#include "content/public/common/url_utils.h"
+#include "ipc/ipc_channel.h"
+#include "net/base/completion_once_callback.h"
+#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
+#include "net/http/http_response_headers.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
+#include "services/network/public/cpp/simple_url_loader.h"
+#include "services/network/public/cpp/simple_url_loader_stream_consumer.h"
+#include "services/network/public/cpp/wrapper_shared_url_loader_factory.h"
+#include "services/network/public/mojom/url_response_head.mojom.h"
+#include "storage/browser/file_system/native_file_util.h"
+
+#if BUILDFLAG(IS_WIN)
+#include <windows.h>
+#elif BUILDFLAG(IS_POSIX)
+#include <time.h>
+#endif
+
+namespace {
+
+// This constant should be in sync with the constant in
+// chrome/browser/devtools/devtools_ui_bindings.cc.
+constexpr size_t kMaxMessageChunkSize = IPC::Channel::kMaximumMessageSize / 4;
+
+constexpr int kMaxLogLineLength = 1024;
+
+static std::string GetFrontendURL() {
+ return base::StringPrintf("%s://%s/devtools_app.html",
+ content::kChromeDevToolsScheme,
+ scheme::kChromeDevToolsHost);
+}
+
+base::Value::Dict BuildObjectForResponse(const net::HttpResponseHeaders* rh,
+ bool success,
+ int net_error) {
+ base::Value::Dict response;
+ int responseCode = 200;
+ if (rh) {
+ responseCode = rh->response_code();
+ } else if (!success) {
+ // In case of no headers, assume file:// URL and failed to load
+ responseCode = 404;
+ }
+ response.Set("statusCode", responseCode);
+ response.Set("netError", net_error);
+ response.Set("netErrorName", net::ErrorToString(net_error));
+
+ base::Value::Dict headers;
+ size_t iterator = 0;
+ std::string name;
+ std::string value;
+ // TODO(caseq): this probably needs to handle duplicate header names
+ // correctly by folding them.
+ while (rh && rh->EnumerateHeaderLines(&iterator, &name, &value)) {
+ headers.Set(name, value);
+ }
+
+ response.Set("headers", std::move(headers));
+ return response;
+}
+
+void WriteTimestamp(std::stringstream& stream) {
+#if BUILDFLAG(IS_WIN)
+ SYSTEMTIME local_time;
+ GetLocalTime(&local_time);
+ stream << std::setfill('0') << std::setw(2) << local_time.wMonth
+ << std::setw(2) << local_time.wDay << '/' << std::setw(2)
+ << local_time.wHour << std::setw(2) << local_time.wMinute
+ << std::setw(2) << local_time.wSecond << '.' << std::setw(3)
+ << local_time.wMilliseconds;
+#elif BUILDFLAG(IS_POSIX)
+ timeval tv;
+ gettimeofday(&tv, nullptr);
+ time_t t = tv.tv_sec;
+ struct tm local_time;
+ localtime_r(&t, &local_time);
+ struct tm* tm_time = &local_time;
+ stream << std::setfill('0') << std::setw(2) << 1 + tm_time->tm_mon
+ << std::setw(2) << tm_time->tm_mday << '/' << std::setw(2)
+ << tm_time->tm_hour << std::setw(2) << tm_time->tm_min << std::setw(2)
+ << tm_time->tm_sec << '.' << std::setw(6) << tv.tv_usec;
+#else
+#error Unsupported platform
+#endif
+}
+
+void LogProtocolMessage(const base::FilePath& log_file,
+ ProtocolMessageType type,
+ std::string to_log) {
+ // Track if logging has failed, in which case we don't keep trying.
+ static bool log_error = false;
+ if (log_error) {
+ return;
+ }
+
+ if (storage::NativeFileUtil::EnsureFileExists(log_file, nullptr) !=
+ base::File::FILE_OK) {
+ LOG(ERROR) << "Failed to create file " << log_file.value();
+ log_error = true;
+ return;
+ }
+
+ std::string type_label;
+ switch (type) {
+ case ProtocolMessageType::METHOD:
+ type_label = "METHOD";
+ break;
+ case ProtocolMessageType::RESULT:
+ type_label = "RESULT";
+ break;
+ case ProtocolMessageType::EVENT:
+ type_label = "EVENT";
+ break;
+ }
+
+ std::stringstream stream;
+ WriteTimestamp(stream);
+ stream << ": " << type_label << ": " << to_log << "\n";
+ const std::string& str = stream.str();
+ if (!base::AppendToFile(log_file, base::StringPiece(str))) {
+ LOG(ERROR) << "Failed to write file " << log_file.value();
+ log_error = true;
+ }
+}
+
+} // namespace
+
+class CefDevToolsFrontend::NetworkResourceLoader
+ : public network::SimpleURLLoaderStreamConsumer {
+ public:
+ NetworkResourceLoader(int stream_id,
+ CefDevToolsFrontend* bindings,
+ std::unique_ptr<network::SimpleURLLoader> loader,
+ network::mojom::URLLoaderFactory* url_loader_factory,
+ int request_id)
+ : stream_id_(stream_id),
+ bindings_(bindings),
+ loader_(std::move(loader)),
+ request_id_(request_id) {
+ loader_->SetOnResponseStartedCallback(base::BindOnce(
+ &NetworkResourceLoader::OnResponseStarted, base::Unretained(this)));
+ loader_->DownloadAsStream(url_loader_factory, this);
+ }
+
+ NetworkResourceLoader(const NetworkResourceLoader&) = delete;
+ NetworkResourceLoader& operator=(const NetworkResourceLoader&) = delete;
+
+ private:
+ void OnResponseStarted(const GURL& final_url,
+ const network::mojom::URLResponseHead& response_head) {
+ response_headers_ = response_head.headers;
+ }
+
+ void OnDataReceived(base::StringPiece chunk,
+ base::OnceClosure resume) override {
+ base::Value chunkValue;
+
+ bool encoded = !base::IsStringUTF8(chunk);
+ if (encoded) {
+ std::string encoded_string;
+ base::Base64Encode(chunk, &encoded_string);
+ chunkValue = base::Value(std::move(encoded_string));
+ } else {
+ chunkValue = base::Value(chunk);
+ }
+ base::Value id(stream_id_);
+ base::Value encodedValue(encoded);
+
+ bindings_->CallClientFunction("DevToolsAPI", "streamWrite", std::move(id),
+ std::move(chunkValue),
+ std::move(encodedValue));
+ std::move(resume).Run();
+ }
+
+ void OnComplete(bool success) override {
+ auto response = BuildObjectForResponse(response_headers_.get(), success,
+ loader_->NetError());
+ bindings_->SendMessageAck(request_id_, std::move(response));
+
+ bindings_->loaders_.erase(bindings_->loaders_.find(this));
+ }
+
+ void OnRetry(base::OnceClosure start_retry) override { NOTREACHED(); }
+
+ const int stream_id_;
+ CefDevToolsFrontend* const bindings_;
+ std::unique_ptr<network::SimpleURLLoader> loader_;
+ int request_id_;
+ scoped_refptr<net::HttpResponseHeaders> response_headers_;
+};
+
+// static
+CefDevToolsFrontend* CefDevToolsFrontend::Show(
+ AlloyBrowserHostImpl* inspected_browser,
+ const CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient> client,
+ const CefBrowserSettings& settings,
+ const CefPoint& inspect_element_at,
+ base::OnceClosure frontend_destroyed_callback) {
+ CefBrowserSettings new_settings = settings;
+ if (!windowInfo.windowless_rendering_enabled &&
+ CefColorGetA(new_settings.background_color) != SK_AlphaOPAQUE) {
+ // Use white as the default background color for windowed DevTools instead
+ // of the CefSettings.background_color value.
+ new_settings.background_color = SK_ColorWHITE;
+ }
+
+ CefBrowserCreateParams create_params;
+ if (inspected_browser->is_views_hosted()) {
+ create_params.popup_with_views_hosted_opener = true;
+ } else {
+ create_params.window_info.reset(new CefWindowInfo(windowInfo));
+ }
+ create_params.client = client;
+ create_params.settings = new_settings;
+ create_params.devtools_opener = inspected_browser;
+ create_params.request_context = inspected_browser->GetRequestContext();
+ create_params.extra_info = inspected_browser->browser_info()->extra_info();
+
+ CefRefPtr<AlloyBrowserHostImpl> frontend_browser =
+ AlloyBrowserHostImpl::Create(create_params);
+
+ content::WebContents* inspected_contents = inspected_browser->web_contents();
+
+ // CefDevToolsFrontend will delete itself when the frontend WebContents is
+ // destroyed.
+ CefDevToolsFrontend* devtools_frontend = new CefDevToolsFrontend(
+ static_cast<AlloyBrowserHostImpl*>(frontend_browser.get()),
+ inspected_contents, inspect_element_at,
+ std::move(frontend_destroyed_callback));
+
+ // Need to load the URL after creating the DevTools objects.
+ frontend_browser->GetMainFrame()->LoadURL(GetFrontendURL());
+
+ return devtools_frontend;
+}
+
+void CefDevToolsFrontend::Activate() {
+ frontend_browser_->ActivateContents(web_contents());
+}
+
+void CefDevToolsFrontend::Focus() {
+ frontend_browser_->SetFocus(true);
+}
+
+void CefDevToolsFrontend::InspectElementAt(int x, int y) {
+ if (inspect_element_at_.x != x || inspect_element_at_.y != y) {
+ inspect_element_at_.Set(x, y);
+ }
+ if (agent_host_) {
+ agent_host_->InspectElement(inspected_contents_->GetFocusedFrame(), x, y);
+ }
+}
+
+void CefDevToolsFrontend::Close() {
+ CEF_POST_TASK(CEF_UIT, base::BindOnce(&AlloyBrowserHostImpl::CloseBrowser,
+ frontend_browser_.get(), true));
+}
+
+CefDevToolsFrontend::CefDevToolsFrontend(
+ AlloyBrowserHostImpl* frontend_browser,
+ content::WebContents* inspected_contents,
+ const CefPoint& inspect_element_at,
+ base::OnceClosure frontend_destroyed_callback)
+ : content::WebContentsObserver(frontend_browser->web_contents()),
+ frontend_browser_(frontend_browser),
+ inspected_contents_(inspected_contents),
+ inspect_element_at_(inspect_element_at),
+ frontend_destroyed_callback_(std::move(frontend_destroyed_callback)),
+ file_manager_(frontend_browser, GetPrefs()),
+ protocol_log_file_(
+ base::CommandLine::ForCurrentProcess()->GetSwitchValuePath(
+ switches::kDevToolsProtocolLogFile)),
+ weak_factory_(this) {
+ DCHECK(!frontend_destroyed_callback_.is_null());
+}
+
+CefDevToolsFrontend::~CefDevToolsFrontend() {}
+
+void CefDevToolsFrontend::ReadyToCommitNavigation(
+ content::NavigationHandle* navigation_handle) {
+ content::RenderFrameHost* frame = navigation_handle->GetRenderFrameHost();
+ if (navigation_handle->IsInMainFrame()) {
+ frontend_host_ = content::DevToolsFrontendHost::Create(
+ frame, base::BindRepeating(
+ &CefDevToolsFrontend::HandleMessageFromDevToolsFrontend,
+ base::Unretained(this)));
+ return;
+ }
+
+ std::string origin =
+ navigation_handle->GetURL().DeprecatedGetOriginAsURL().spec();
+ auto it = extensions_api_.find(origin);
+ if (it == extensions_api_.end()) {
+ return;
+ }
+ std::string script = base::StringPrintf("%s(\"%s\")", it->second.c_str(),
+ base::GenerateGUID().c_str());
+ content::DevToolsFrontendHost::SetupExtensionsAPI(frame, script);
+}
+
+void CefDevToolsFrontend::PrimaryMainDocumentElementAvailable() {
+ // Don't call AttachClient multiple times for the same DevToolsAgentHost.
+ // Otherwise it will call AgentHostClosed which closes the DevTools window.
+ // This may happen in cases where the DevTools content fails to load.
+ scoped_refptr<content::DevToolsAgentHost> agent_host =
+ content::DevToolsAgentHost::GetOrCreateFor(inspected_contents_);
+ if (agent_host != agent_host_) {
+ if (agent_host_) {
+ agent_host_->DetachClient(this);
+ }
+ agent_host_ = agent_host;
+ agent_host_->AttachClient(this);
+ if (!inspect_element_at_.IsEmpty()) {
+ agent_host_->InspectElement(inspected_contents_->GetFocusedFrame(),
+ inspect_element_at_.x, inspect_element_at_.y);
+ }
+ }
+}
+
+void CefDevToolsFrontend::WebContentsDestroyed() {
+ if (agent_host_) {
+ agent_host_->DetachClient(this);
+ agent_host_ = nullptr;
+ }
+ std::move(frontend_destroyed_callback_).Run();
+ delete this;
+}
+
+void CefDevToolsFrontend::HandleMessageFromDevToolsFrontend(
+ base::Value::Dict message) {
+ const std::string* method = message.FindString("method");
+ if (!method) {
+ return;
+ }
+
+ int request_id = message.FindInt("id").value_or(0);
+ base::Value::List* params_value = message.FindList("params");
+
+ // Since we've received message by value, we can take the list.
+ base::Value::List params;
+ if (params_value) {
+ params = std::move(*params_value);
+ }
+
+ if (*method == "dispatchProtocolMessage") {
+ if (params.size() < 1) {
+ return;
+ }
+ const std::string* protocol_message = params[0].GetIfString();
+ if (!agent_host_ || !protocol_message) {
+ return;
+ }
+ if (ProtocolLoggingEnabled()) {
+ LogProtocolMessage(ProtocolMessageType::METHOD, *protocol_message);
+ }
+ agent_host_->DispatchProtocolMessage(
+ this, base::as_bytes(base::make_span(*protocol_message)));
+ } else if (*method == "loadCompleted") {
+ web_contents()->GetPrimaryMainFrame()->ExecuteJavaScriptForTests(
+ u"DevToolsAPI.setUseSoftMenu(true);", base::NullCallback());
+ } else if (*method == "loadNetworkResource") {
+ if (params.size() < 3) {
+ return;
+ }
+
+ // TODO(pfeldman): handle some of the embedder messages in content.
+ const std::string* url = params[0].GetIfString();
+ const std::string* headers = params[1].GetIfString();
+ absl::optional<const int> stream_id = params[2].GetIfInt();
+ if (!url || !headers || !stream_id.has_value()) {
+ return;
+ }
+
+ GURL gurl(*url);
+ if (!gurl.is_valid()) {
+ base::Value::Dict response;
+ response.Set("statusCode", 404);
+ response.Set("urlValid", false);
+ SendMessageAck(request_id, std::move(response));
+ return;
+ }
+
+ net::NetworkTrafficAnnotationTag traffic_annotation =
+ net::DefineNetworkTrafficAnnotation(
+ "devtools_handle_front_end_messages", R"(
+ semantics {
+ sender: "Developer Tools"
+ description:
+ "When user opens Developer Tools, the browser may fetch "
+ "additional resources from the network to enrich the debugging "
+ "experience (e.g. source map resources)."
+ trigger: "User opens Developer Tools to debug a web page."
+ data: "Any resources requested by Developer Tools."
+ destination: OTHER
+ }
+ policy {
+ cookies_allowed: YES
+ cookies_store: "user"
+ setting:
+ "It's not possible to disable this feature from settings."
+ chrome_policy {
+ DeveloperToolsAvailability {
+ policy_options {mode: MANDATORY}
+ DeveloperToolsAvailability: 2
+ }
+ }
+ })");
+
+ // Based on DevToolsUIBindings::LoadNetworkResource.
+ auto resource_request = std::make_unique<network::ResourceRequest>();
+ resource_request->url = gurl;
+ // TODO(caseq): this preserves behavior of URLFetcher-based
+ // implementation. We really need to pass proper first party origin from
+ // the front-end.
+ resource_request->site_for_cookies = net::SiteForCookies::FromUrl(gurl);
+ resource_request->headers.AddHeadersFromString(*headers);
+
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory;
+ if (gurl.SchemeIsFile()) {
+ mojo::PendingRemote<network::mojom::URLLoaderFactory> pending_remote =
+ content::CreateFileURLLoaderFactory(
+ base::FilePath() /* profile_path */,
+ nullptr /* shared_cors_origin_access_list */);
+ url_loader_factory = network::SharedURLLoaderFactory::Create(
+ std::make_unique<network::WrapperPendingSharedURLLoaderFactory>(
+ std::move(pending_remote)));
+ } else if (content::HasWebUIScheme(gurl)) {
+ base::Value::Dict response;
+ response.Set("statusCode", 403);
+ SendMessageAck(request_id, std::move(response));
+ return;
+ } else {
+ auto* partition =
+ inspected_contents_->GetPrimaryMainFrame()->GetStoragePartition();
+ url_loader_factory = partition->GetURLLoaderFactoryForBrowserProcess();
+ }
+
+ auto simple_url_loader = network::SimpleURLLoader::Create(
+ std::move(resource_request), traffic_annotation);
+ auto resource_loader = std::make_unique<NetworkResourceLoader>(
+ *stream_id, this, std::move(simple_url_loader),
+ url_loader_factory.get(), request_id);
+ loaders_.insert(std::move(resource_loader));
+ return;
+ } else if (*method == "getPreferences") {
+ SendMessageAck(request_id,
+ GetPrefs()->GetDict(prefs::kDevToolsPreferences).Clone());
+ return;
+ } else if (*method == "setPreference") {
+ if (params.size() < 2) {
+ return;
+ }
+ const std::string* name = params[0].GetIfString();
+
+ // We're just setting params[1] as a value anyways, so just make sure it's
+ // the type we want, but don't worry about getting it.
+ if (!name || !params[1].is_string()) {
+ return;
+ }
+
+ ScopedDictPrefUpdate update(GetPrefs(), prefs::kDevToolsPreferences);
+ update->Set(*name, std::move(params[1]));
+ } else if (*method == "removePreference") {
+ const std::string* name = params[0].GetIfString();
+ if (!name) {
+ return;
+ }
+ ScopedDictPrefUpdate update(GetPrefs(), prefs::kDevToolsPreferences);
+ update->Remove(*name);
+ } else if (*method == "requestFileSystems") {
+ web_contents()->GetPrimaryMainFrame()->ExecuteJavaScriptForTests(
+ u"DevToolsAPI.fileSystemsLoaded([]);", base::NullCallback());
+ } else if (*method == "reattach") {
+ if (!agent_host_) {
+ return;
+ }
+ agent_host_->DetachClient(this);
+ agent_host_->AttachClient(this);
+ } else if (*method == "registerExtensionsAPI") {
+ if (params.size() < 2) {
+ return;
+ }
+ const std::string* origin = params[0].GetIfString();
+ const std::string* script = params[1].GetIfString();
+ if (!origin || !script) {
+ return;
+ }
+ extensions_api_[*origin + "/"] = *script;
+ } else if (*method == "save") {
+ if (params.size() < 3) {
+ return;
+ }
+ const std::string* url = params[0].GetIfString();
+ const std::string* content = params[1].GetIfString();
+ absl::optional<bool> save_as = params[2].GetIfBool();
+ if (!url || !content || !save_as.has_value()) {
+ return;
+ }
+ file_manager_.SaveToFile(*url, *content, *save_as);
+ } else if (*method == "append") {
+ if (params.size() < 2) {
+ return;
+ }
+ const std::string* url = params[0].GetIfString();
+ const std::string* content = params[1].GetIfString();
+ if (!url || !content) {
+ return;
+ }
+ file_manager_.AppendToFile(*url, *content);
+ } else {
+ return;
+ }
+
+ if (request_id) {
+ SendMessageAck(request_id, base::Value::Dict());
+ }
+}
+
+void CefDevToolsFrontend::DispatchProtocolMessage(
+ content::DevToolsAgentHost* agent_host,
+ base::span<const uint8_t> message) {
+ if (!frontend_browser_->GetWebContents() ||
+ frontend_browser_->GetWebContents()->IsBeingDestroyed()) {
+ return;
+ }
+
+ base::StringPiece str_message(reinterpret_cast<const char*>(message.data()),
+ message.size());
+ if (ProtocolLoggingEnabled()) {
+ // Quick check to avoid parsing the JSON object. Events begin with a
+ // "method" value whereas method results begin with an "id" value.
+ LogProtocolMessage(base::StartsWith(str_message, "{\"method\":")
+ ? ProtocolMessageType::EVENT
+ : ProtocolMessageType::RESULT,
+ str_message);
+ }
+
+ if (str_message.length() < kMaxMessageChunkSize) {
+ CallClientFunction("DevToolsAPI", "dispatchMessage",
+ base::Value(std::string(str_message)));
+ } else {
+ size_t total_size = str_message.length();
+ for (size_t pos = 0; pos < str_message.length();
+ pos += kMaxMessageChunkSize) {
+ base::StringPiece str_message_chunk =
+ str_message.substr(pos, kMaxMessageChunkSize);
+
+ CallClientFunction(
+ "DevToolsAPI", "dispatchMessageChunk",
+ base::Value(std::string(str_message_chunk)),
+ base::Value(base::NumberToString(pos ? 0 : total_size)));
+ }
+ }
+}
+
+void CefDevToolsFrontend::CallClientFunction(
+ const std::string& object_name,
+ const std::string& method_name,
+ base::Value arg1,
+ base::Value arg2,
+ base::Value arg3,
+ base::OnceCallback<void(base::Value)> cb) {
+ std::string javascript;
+
+ web_contents()->GetPrimaryMainFrame()->AllowInjectingJavaScript();
+
+ base::Value::List arguments;
+ if (!arg1.is_none()) {
+ arguments.Append(std::move(arg1));
+ if (!arg2.is_none()) {
+ arguments.Append(std::move(arg2));
+ if (!arg3.is_none()) {
+ arguments.Append(std::move(arg3));
+ }
+ }
+ }
+ web_contents()->GetPrimaryMainFrame()->ExecuteJavaScriptMethod(
+ base::ASCIIToUTF16(object_name), base::ASCIIToUTF16(method_name),
+ std::move(arguments), std::move(cb));
+}
+
+void CefDevToolsFrontend::SendMessageAck(int request_id,
+ base::Value::Dict arg) {
+ CallClientFunction("DevToolsAPI", "embedderMessageAck",
+ base::Value(request_id), base::Value(std::move(arg)));
+}
+
+bool CefDevToolsFrontend::ProtocolLoggingEnabled() const {
+ return !protocol_log_file_.empty();
+}
+
+void CefDevToolsFrontend::LogProtocolMessage(ProtocolMessageType type,
+ const base::StringPiece& message) {
+ DCHECK(ProtocolLoggingEnabled());
+
+ std::string to_log(message.substr(0, kMaxLogLineLength));
+
+ // Execute in an ordered context that allows blocking.
+ auto task_runner = CefTaskRunnerManager::Get()->GetBackgroundTaskRunner();
+ task_runner->PostTask(
+ FROM_HERE, base::BindOnce(::LogProtocolMessage, protocol_log_file_, type,
+ std::move(to_log)));
+}
+
+void CefDevToolsFrontend::AgentHostClosed(
+ content::DevToolsAgentHost* agent_host) {
+ DCHECK(agent_host == agent_host_.get());
+ agent_host_ = nullptr;
+ Close();
+}
+
+PrefService* CefDevToolsFrontend::GetPrefs() const {
+ return CefBrowserContext::FromBrowserContext(
+ frontend_browser_->web_contents()->GetBrowserContext())
+ ->AsProfile()
+ ->GetPrefs();
+}
diff --git a/libcef/browser/devtools/devtools_frontend.h b/libcef/browser/devtools/devtools_frontend.h
new file mode 100644
index 00000000..36af6f11
--- /dev/null
+++ b/libcef/browser/devtools/devtools_frontend.h
@@ -0,0 +1,114 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_DEVTOOLS_DEVTOOLS_FRONTEND_H_
+#define CEF_LIBCEF_BROWSER_DEVTOOLS_DEVTOOLS_FRONTEND_H_
+
+#include <memory>
+
+#include "libcef/browser/alloy/alloy_browser_host_impl.h"
+#include "libcef/browser/devtools/devtools_file_manager.h"
+
+#include "base/files/file_path.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "base/values.h"
+#include "content/public/browser/devtools_agent_host.h"
+#include "content/public/browser/devtools_frontend_host.h"
+#include "content/public/browser/web_contents_observer.h"
+
+namespace base {
+class Value;
+}
+
+namespace content {
+class NavigationHandle;
+class RenderViewHost;
+class WebContents;
+} // namespace content
+
+class PrefService;
+
+enum class ProtocolMessageType {
+ METHOD,
+ RESULT,
+ EVENT,
+};
+
+class CefDevToolsFrontend : public content::WebContentsObserver,
+ public content::DevToolsAgentHostClient {
+ public:
+ CefDevToolsFrontend(const CefDevToolsFrontend&) = delete;
+ CefDevToolsFrontend& operator=(const CefDevToolsFrontend&) = delete;
+
+ static CefDevToolsFrontend* Show(
+ AlloyBrowserHostImpl* inspected_browser,
+ const CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient> client,
+ const CefBrowserSettings& settings,
+ const CefPoint& inspect_element_at,
+ base::OnceClosure frontend_destroyed_callback);
+
+ void Activate();
+ void Focus();
+ void InspectElementAt(int x, int y);
+ void Close();
+
+ void CallClientFunction(
+ const std::string& object_name,
+ const std::string& method_name,
+ const base::Value arg1 = {},
+ const base::Value arg2 = {},
+ const base::Value arg3 = {},
+ base::OnceCallback<void(base::Value)> cb = base::NullCallback());
+
+ private:
+ CefDevToolsFrontend(AlloyBrowserHostImpl* frontend_browser,
+ content::WebContents* inspected_contents,
+ const CefPoint& inspect_element_at,
+ base::OnceClosure destroyed_callback);
+ ~CefDevToolsFrontend() override;
+
+ // content::DevToolsAgentHostClient implementation.
+ void AgentHostClosed(content::DevToolsAgentHost* agent_host) override;
+ void DispatchProtocolMessage(content::DevToolsAgentHost* agent_host,
+ base::span<const uint8_t> message) override;
+ void HandleMessageFromDevToolsFrontend(base::Value::Dict message);
+
+ private:
+ // WebContentsObserver overrides
+ void ReadyToCommitNavigation(
+ content::NavigationHandle* navigation_handle) override;
+ void PrimaryMainDocumentElementAvailable() override;
+ void WebContentsDestroyed() override;
+
+ void SendMessageAck(int request_id, base::Value::Dict arg);
+
+ bool ProtocolLoggingEnabled() const;
+ void LogProtocolMessage(ProtocolMessageType type,
+ const base::StringPiece& message);
+
+ PrefService* GetPrefs() const;
+
+ CefRefPtr<AlloyBrowserHostImpl> frontend_browser_;
+ content::WebContents* inspected_contents_;
+ scoped_refptr<content::DevToolsAgentHost> agent_host_;
+ CefPoint inspect_element_at_;
+ base::OnceClosure frontend_destroyed_callback_;
+ std::unique_ptr<content::DevToolsFrontendHost> frontend_host_;
+
+ class NetworkResourceLoader;
+ std::set<std::unique_ptr<NetworkResourceLoader>, base::UniquePtrComparator>
+ loaders_;
+
+ using ExtensionsAPIs = std::map<std::string, std::string>;
+ ExtensionsAPIs extensions_api_;
+ CefDevToolsFileManager file_manager_;
+
+ const base::FilePath protocol_log_file_;
+
+ base::WeakPtrFactory<CefDevToolsFrontend> weak_factory_;
+};
+
+#endif // CEF_LIBCEF_BROWSER_DEVTOOLS_DEVTOOLS_FRONTEND_H_
diff --git a/libcef/browser/devtools/devtools_manager.cc b/libcef/browser/devtools/devtools_manager.cc
new file mode 100644
index 00000000..170f6095
--- /dev/null
+++ b/libcef/browser/devtools/devtools_manager.cc
@@ -0,0 +1,216 @@
+// Copyright (c) 2020 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "libcef/browser/devtools/devtools_manager.h"
+
+#include "libcef/browser/devtools/devtools_controller.h"
+#include "libcef/browser/devtools/devtools_frontend.h"
+#include "libcef/features/runtime.h"
+
+#include "content/public/browser/web_contents.h"
+
+namespace {
+
+// May be created on any thread but will be destroyed on the UI thread.
+class CefDevToolsRegistrationImpl : public CefRegistration,
+ public CefDevToolsController::Observer {
+ public:
+ explicit CefDevToolsRegistrationImpl(
+ CefRefPtr<CefDevToolsMessageObserver> observer)
+ : observer_(observer) {
+ DCHECK(observer_);
+ }
+
+ CefDevToolsRegistrationImpl(const CefDevToolsRegistrationImpl&) = delete;
+ CefDevToolsRegistrationImpl& operator=(const CefDevToolsRegistrationImpl&) =
+ delete;
+
+ ~CefDevToolsRegistrationImpl() override {
+ CEF_REQUIRE_UIT();
+
+ // May be null if OnDevToolsControllerDestroyed was called.
+ if (!controller_) {
+ return;
+ }
+
+ controller_->RemoveObserver(this);
+ }
+
+ void Initialize(CefBrowserHostBase* browser,
+ base::WeakPtr<CefDevToolsController> controller) {
+ CEF_REQUIRE_UIT();
+ DCHECK(browser && controller);
+ DCHECK(!browser_ && !controller_);
+ browser_ = browser;
+ controller_ = controller;
+
+ controller_->AddObserver(this);
+ }
+
+ private:
+ // CefDevToolsController::Observer methods:
+ bool OnDevToolsMessage(const base::StringPiece& message) override {
+ CEF_REQUIRE_UIT();
+ return observer_->OnDevToolsMessage(browser_, message.data(),
+ message.size());
+ }
+
+ void OnDevToolsMethodResult(int message_id,
+ bool success,
+ const base::StringPiece& result) override {
+ CEF_REQUIRE_UIT();
+ observer_->OnDevToolsMethodResult(browser_, message_id, success,
+ result.data(), result.size());
+ }
+
+ void OnDevToolsEvent(const base::StringPiece& method,
+ const base::StringPiece& params) override {
+ CEF_REQUIRE_UIT();
+ observer_->OnDevToolsEvent(browser_, std::string(method), params.data(),
+ params.size());
+ }
+
+ void OnDevToolsAgentAttached() override {
+ CEF_REQUIRE_UIT();
+ observer_->OnDevToolsAgentAttached(browser_);
+ }
+
+ void OnDevToolsAgentDetached() override {
+ CEF_REQUIRE_UIT();
+ observer_->OnDevToolsAgentDetached(browser_);
+ }
+
+ void OnDevToolsControllerDestroyed() override {
+ CEF_REQUIRE_UIT();
+ browser_ = nullptr;
+ controller_.reset();
+ }
+
+ CefRefPtr<CefDevToolsMessageObserver> observer_;
+
+ CefBrowserHostBase* browser_ = nullptr;
+ base::WeakPtr<CefDevToolsController> controller_;
+
+ IMPLEMENT_REFCOUNTING_DELETE_ON_UIT(CefDevToolsRegistrationImpl);
+};
+
+} // namespace
+
+CefDevToolsManager::CefDevToolsManager(CefBrowserHostBase* inspected_browser)
+ : inspected_browser_(inspected_browser), weak_ptr_factory_(this) {
+ CEF_REQUIRE_UIT();
+}
+
+CefDevToolsManager::~CefDevToolsManager() {
+ CEF_REQUIRE_UIT();
+}
+
+void CefDevToolsManager::ShowDevTools(const CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient> client,
+ const CefBrowserSettings& settings,
+ const CefPoint& inspect_element_at) {
+ CEF_REQUIRE_UIT();
+ if (devtools_frontend_) {
+ if (!inspect_element_at.IsEmpty()) {
+ devtools_frontend_->InspectElementAt(inspect_element_at.x,
+ inspect_element_at.y);
+ }
+ devtools_frontend_->Focus();
+ return;
+ }
+
+ if (cef::IsChromeRuntimeEnabled()) {
+ NOTIMPLEMENTED();
+ } else {
+ auto alloy_browser = static_cast<AlloyBrowserHostImpl*>(inspected_browser_);
+ devtools_frontend_ = CefDevToolsFrontend::Show(
+ alloy_browser, windowInfo, client, settings, inspect_element_at,
+ base::BindOnce(&CefDevToolsManager::OnFrontEndDestroyed,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
+}
+
+void CefDevToolsManager::CloseDevTools() {
+ CEF_REQUIRE_UIT();
+ if (!devtools_frontend_) {
+ return;
+ }
+ devtools_frontend_->Close();
+}
+
+bool CefDevToolsManager::HasDevTools() {
+ CEF_REQUIRE_UIT();
+ return !!devtools_frontend_;
+}
+
+bool CefDevToolsManager::SendDevToolsMessage(const void* message,
+ size_t message_size) {
+ CEF_REQUIRE_UIT();
+ if (!message || message_size == 0) {
+ return false;
+ }
+
+ if (!EnsureController()) {
+ return false;
+ }
+
+ return devtools_controller_->SendDevToolsMessage(
+ base::StringPiece(static_cast<const char*>(message), message_size));
+}
+
+int CefDevToolsManager::ExecuteDevToolsMethod(
+ int message_id,
+ const CefString& method,
+ CefRefPtr<CefDictionaryValue> params) {
+ CEF_REQUIRE_UIT();
+ if (method.empty()) {
+ return 0;
+ }
+
+ if (!EnsureController()) {
+ return 0;
+ }
+
+ if (params && params->IsValid()) {
+ CefDictionaryValueImpl* impl =
+ static_cast<CefDictionaryValueImpl*>(params.get());
+ CefValueController::AutoLock lock_scope(impl->controller());
+ return devtools_controller_->ExecuteDevToolsMethod(
+ message_id, method, impl->GetValueUnsafe()->GetIfDict());
+ } else {
+ return devtools_controller_->ExecuteDevToolsMethod(message_id, method,
+ nullptr);
+ }
+}
+
+// static
+CefRefPtr<CefRegistration> CefDevToolsManager::CreateRegistration(
+ CefRefPtr<CefDevToolsMessageObserver> observer) {
+ DCHECK(observer);
+ return new CefDevToolsRegistrationImpl(observer);
+}
+
+void CefDevToolsManager::InitializeRegistrationOnUIThread(
+ CefRefPtr<CefRegistration> registration) {
+ CEF_REQUIRE_UIT();
+
+ if (!EnsureController()) {
+ return;
+ }
+
+ static_cast<CefDevToolsRegistrationImpl*>(registration.get())
+ ->Initialize(inspected_browser_, devtools_controller_->GetWeakPtr());
+}
+
+void CefDevToolsManager::OnFrontEndDestroyed() {
+ devtools_frontend_ = nullptr;
+}
+
+bool CefDevToolsManager::EnsureController() {
+ if (!devtools_controller_) {
+ devtools_controller_.reset(new CefDevToolsController(
+ inspected_browser_->contents_delegate()->web_contents()));
+ }
+ return true;
+}
diff --git a/libcef/browser/devtools/devtools_manager.h b/libcef/browser/devtools/devtools_manager.h
new file mode 100644
index 00000000..d390e498
--- /dev/null
+++ b/libcef/browser/devtools/devtools_manager.h
@@ -0,0 +1,71 @@
+// Copyright (c) 2020 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_DEVTOOLS_DEVTOOLS_MANAGER_H_
+#define CEF_LIBCEF_BROWSER_DEVTOOLS_DEVTOOLS_MANAGER_H_
+#pragma once
+
+#include "include/cef_browser.h"
+
+#include "base/memory/weak_ptr.h"
+
+class CefBrowserHostBase;
+class CefDevToolsController;
+class CefDevToolsFrontend;
+
+namespace content {
+class WebContents;
+}
+
+// Manages DevTools instances. Methods must be called on the UI thread unless
+// otherwise indicated.
+class CefDevToolsManager {
+ public:
+ // |inspected_browser| will outlive this object.
+ explicit CefDevToolsManager(CefBrowserHostBase* inspected_browser);
+
+ CefDevToolsManager(const CefDevToolsManager&) = delete;
+ CefDevToolsManager& operator=(const CefDevToolsManager&) = delete;
+
+ ~CefDevToolsManager();
+
+ // See CefBrowserHost methods of the same name for documentation.
+ void ShowDevTools(const CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient> client,
+ const CefBrowserSettings& settings,
+ const CefPoint& inspect_element_at);
+ void CloseDevTools();
+ bool HasDevTools();
+ bool SendDevToolsMessage(const void* message, size_t message_size);
+ int ExecuteDevToolsMethod(int message_id,
+ const CefString& method,
+ CefRefPtr<CefDictionaryValue> param);
+
+ // These methods are used to implement
+ // CefBrowserHost::AddDevToolsMessageObserver. CreateRegistration is safe to
+ // call on any thread. InitializeRegistrationOnUIThread should be called
+ // immediately afterwards on the UI thread.
+ static CefRefPtr<CefRegistration> CreateRegistration(
+ CefRefPtr<CefDevToolsMessageObserver> observer);
+ void InitializeRegistrationOnUIThread(
+ CefRefPtr<CefRegistration> registration);
+
+ private:
+ void OnFrontEndDestroyed();
+
+ bool EnsureController();
+
+ CefBrowserHostBase* const inspected_browser_;
+
+ // CefDevToolsFrontend will delete itself when the frontend WebContents is
+ // destroyed.
+ CefDevToolsFrontend* devtools_frontend_ = nullptr;
+
+ // Used for sending DevTools protocol messages without an active frontend.
+ std::unique_ptr<CefDevToolsController> devtools_controller_;
+
+ base::WeakPtrFactory<CefDevToolsManager> weak_ptr_factory_;
+};
+
+#endif // CEF_LIBCEF_BROWSER_DEVTOOLS_DEVTOOLS_MANAGER_H_
diff --git a/libcef/browser/devtools/devtools_manager_delegate.cc b/libcef/browser/devtools/devtools_manager_delegate.cc
new file mode 100644
index 00000000..7f23370d
--- /dev/null
+++ b/libcef/browser/devtools/devtools_manager_delegate.cc
@@ -0,0 +1,145 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/devtools/devtools_manager_delegate.h"
+
+#include <stdint.h>
+
+#include <vector>
+
+#include "base/atomicops.h"
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/functional/bind.h"
+#include "base/memory/ptr_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
+#include "cef/grit/cef_resources.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/devtools_agent_host.h"
+#include "content/public/browser/devtools_frontend_host.h"
+#include "content/public/browser/devtools_socket_factory.h"
+#include "content/public/browser/favicon_status.h"
+#include "content/public/browser/navigation_entry.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/common/url_constants.h"
+#include "content/public/common/user_agent.h"
+#include "net/base/net_errors.h"
+#include "net/log/net_log_source.h"
+#include "net/socket/tcp_server_socket.h"
+#include "ui/base/resource/resource_bundle.h"
+
+namespace {
+
+const int kBackLog = 10;
+
+class TCPServerSocketFactory : public content::DevToolsSocketFactory {
+ public:
+ TCPServerSocketFactory(const std::string& address, uint16_t port)
+ : address_(address), port_(port) {}
+
+ TCPServerSocketFactory(const TCPServerSocketFactory&) = delete;
+ TCPServerSocketFactory& operator=(const TCPServerSocketFactory&) = delete;
+
+ private:
+ // content::DevToolsSocketFactory.
+ std::unique_ptr<net::ServerSocket> CreateForHttpServer() override {
+ std::unique_ptr<net::ServerSocket> socket(
+ new net::TCPServerSocket(nullptr, net::NetLogSource()));
+ if (socket->ListenWithAddressAndPort(address_, port_, kBackLog) !=
+ net::OK) {
+ return std::unique_ptr<net::ServerSocket>();
+ }
+ return socket;
+ }
+
+ std::unique_ptr<net::ServerSocket> CreateForTethering(
+ std::string* out_name) override {
+ return nullptr;
+ }
+
+ std::string address_;
+ uint16_t port_;
+};
+
+std::unique_ptr<content::DevToolsSocketFactory> CreateSocketFactory() {
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
+ // See if the user specified a port on the command line. Specifying 0 would
+ // result in the selection of an ephemeral port but that doesn't make sense
+ // for CEF where the URL is otherwise undiscoverable. Also, don't allow
+ // binding of ports between 0 and 1024 exclusive because they're normally
+ // restricted to root on Posix-based systems.
+ uint16_t port = 0;
+ if (command_line.HasSwitch(switches::kRemoteDebuggingPort)) {
+ int temp_port;
+ std::string port_str =
+ command_line.GetSwitchValueASCII(switches::kRemoteDebuggingPort);
+ if (base::StringToInt(port_str, &temp_port) && temp_port >= 1024 &&
+ temp_port < 65535) {
+ port = static_cast<uint16_t>(temp_port);
+ } else {
+ DLOG(WARNING) << "Invalid http debugger port number " << temp_port;
+ }
+ }
+ if (port == 0) {
+ return nullptr;
+ }
+ return std::unique_ptr<content::DevToolsSocketFactory>(
+ new TCPServerSocketFactory("127.0.0.1", port));
+}
+
+} // namespace
+
+// CefDevToolsManagerDelegate ----------------------------------------------
+
+// static
+void CefDevToolsManagerDelegate::StartHttpHandler(
+ content::BrowserContext* browser_context) {
+ std::unique_ptr<content::DevToolsSocketFactory> socket_factory =
+ CreateSocketFactory();
+ if (!socket_factory) {
+ return;
+ }
+ content::DevToolsAgentHost::StartRemoteDebuggingServer(
+ std::move(socket_factory), browser_context->GetPath(), base::FilePath());
+
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
+ if (command_line.HasSwitch(switches::kRemoteDebuggingPipe)) {
+ content::DevToolsAgentHost::StartRemoteDebuggingPipeHandler(
+ base::OnceClosure());
+ }
+}
+
+// static
+void CefDevToolsManagerDelegate::StopHttpHandler() {
+ // This is a no-op if the server was never started.
+ content::DevToolsAgentHost::StopRemoteDebuggingServer();
+}
+
+CefDevToolsManagerDelegate::CefDevToolsManagerDelegate() {}
+
+CefDevToolsManagerDelegate::~CefDevToolsManagerDelegate() {}
+
+scoped_refptr<content::DevToolsAgentHost>
+CefDevToolsManagerDelegate::CreateNewTarget(const GURL& url, bool for_tab) {
+ // This is reached when the user selects "Open link in new tab" from the
+ // DevTools interface.
+ // TODO(cef): Consider exposing new API to support this.
+ return nullptr;
+}
+
+std::string CefDevToolsManagerDelegate::GetDiscoveryPageHTML() {
+ return ui::ResourceBundle::GetSharedInstance().LoadDataResourceString(
+ IDR_CEF_DEVTOOLS_DISCOVERY_PAGE);
+}
+
+bool CefDevToolsManagerDelegate::HasBundledFrontendResources() {
+ return true;
+}
diff --git a/libcef/browser/devtools/devtools_manager_delegate.h b/libcef/browser/devtools/devtools_manager_delegate.h
new file mode 100644
index 00000000..69dc3df2
--- /dev/null
+++ b/libcef/browser/devtools/devtools_manager_delegate.h
@@ -0,0 +1,35 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_DEVTOOLS_DEVTOOLS_MANAGER_DELEGATE_H_
+#define CEF_LIBCEF_BROWSER_DEVTOOLS_DEVTOOLS_MANAGER_DELEGATE_H_
+
+#include "content/public/browser/devtools_manager_delegate.h"
+
+namespace content {
+class BrowserContext;
+}
+
+class CefDevToolsManagerDelegate : public content::DevToolsManagerDelegate {
+ public:
+ static void StartHttpHandler(content::BrowserContext* browser_context);
+ static void StopHttpHandler();
+
+ CefDevToolsManagerDelegate();
+
+ CefDevToolsManagerDelegate(const CefDevToolsManagerDelegate&) = delete;
+ CefDevToolsManagerDelegate& operator=(const CefDevToolsManagerDelegate&) =
+ delete;
+
+ ~CefDevToolsManagerDelegate() override;
+
+ // DevToolsManagerDelegate implementation.
+ scoped_refptr<content::DevToolsAgentHost> CreateNewTarget(
+ const GURL& url,
+ bool for_tab) override;
+ std::string GetDiscoveryPageHTML() override;
+ bool HasBundledFrontendResources() override;
+};
+
+#endif // CEF_LIBCEF_BROWSER_DEVTOOLS_DEVTOOLS_MANAGER_DELEGATE_H_
diff --git a/libcef/browser/devtools/devtools_util.cc b/libcef/browser/devtools/devtools_util.cc
new file mode 100644
index 00000000..1ba53b12
--- /dev/null
+++ b/libcef/browser/devtools/devtools_util.cc
@@ -0,0 +1,141 @@
+// Copyright (c) 2020 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "libcef/browser/devtools/devtools_util.h"
+
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+
+namespace devtools_util {
+
+namespace {
+
+bool IsValidDictionary(const base::StringPiece& str, bool allow_empty) {
+ return str.length() >= (allow_empty ? 2 : 3) && str[0] == '{' &&
+ str[str.length() - 1] == '}';
+}
+
+// Example:
+// {"method":"Target.targetDestroyed","params":{"targetId":"1234..."}}
+bool ParseEvent(const base::StringPiece& message,
+ base::StringPiece& method,
+ base::StringPiece& params) {
+ static const char kMethodStart[] = "{\"method\":\"";
+ static const char kMethodEnd[] = "\"";
+ static const char kParamsStart[] = ",\"params\":";
+
+ if (!base::StartsWith(message, kMethodStart)) {
+ return false;
+ }
+
+ const size_t method_start = sizeof(kMethodStart) - 1;
+ const size_t method_end = message.find(kMethodEnd, method_start);
+ if (method_end == base::StringPiece::npos) {
+ return false;
+ }
+ method = message.substr(method_start, method_end - method_start);
+ if (method.empty()) {
+ return false;
+ }
+
+ size_t remainder_start = method_end + sizeof(kMethodEnd) - 1;
+ if (remainder_start == message.size() - 1) {
+ // No more contents.
+ params = base::StringPiece();
+ } else {
+ const base::StringPiece& remainder = message.substr(remainder_start);
+ if (base::StartsWith(remainder, kParamsStart)) {
+ // Stop immediately before the message closing bracket.
+ remainder_start += sizeof(kParamsStart) - 1;
+ params =
+ message.substr(remainder_start, message.size() - 1 - remainder_start);
+ } else {
+ // Invalid format.
+ return false;
+ }
+
+ if (!IsValidDictionary(params, /*allow_empty=*/true)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// Examples:
+// {"id":3,"result":{}}
+// {"id":4,"result":{"debuggerId":"-2193881606781505058.81393575456727957"}}
+// {"id":5,"error":{"code":-32000,"message":"Not supported"}}
+bool ParseResult(const base::StringPiece& message,
+ int& message_id,
+ bool& success,
+ base::StringPiece& result) {
+ static const char kIdStart[] = "{\"id\":";
+ static const char kIdEnd[] = ",";
+ static const char kResultStart[] = "\"result\":";
+ static const char kErrorStart[] = "\"error\":";
+
+ if (!base::StartsWith(message, kIdStart)) {
+ return false;
+ }
+
+ const size_t id_start = sizeof(kIdStart) - 1;
+ const size_t id_end = message.find(kIdEnd, id_start);
+ if (id_end == base::StringPiece::npos) {
+ return false;
+ }
+ const base::StringPiece& id_str = message.substr(id_start, id_end - id_start);
+ if (id_str.empty() || !base::StringToInt(id_str, &message_id)) {
+ return false;
+ }
+
+ size_t remainder_start = id_end + sizeof(kIdEnd) - 1;
+ const base::StringPiece& remainder = message.substr(remainder_start);
+ if (base::StartsWith(remainder, kResultStart)) {
+ // Stop immediately before the message closing bracket.
+ remainder_start += sizeof(kResultStart) - 1;
+ result =
+ message.substr(remainder_start, message.size() - 1 - remainder_start);
+ success = true;
+ } else if (base::StartsWith(remainder, kErrorStart)) {
+ // Stop immediately before the message closing bracket.
+ remainder_start += sizeof(kErrorStart) - 1;
+ result =
+ message.substr(remainder_start, message.size() - 1 - remainder_start);
+ success = false;
+ } else {
+ // Invalid format.
+ return false;
+ }
+
+ if (!IsValidDictionary(result, /*allow_empty=*/true)) {
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace
+
+// static
+bool ProtocolParser::IsValidMessage(const base::StringPiece& message) {
+ return IsValidDictionary(message, /*allow_empty=*/false);
+}
+
+bool ProtocolParser::Initialize(const base::StringPiece& message) {
+ if (status_ != UNINITIALIZED) {
+ return false;
+ }
+
+ if (ParseEvent(message, method_, params_)) {
+ status_ = EVENT;
+ } else if (ParseResult(message, message_id_, success_, params_)) {
+ status_ = RESULT;
+ } else {
+ status_ = FAILURE;
+ }
+ return true;
+}
+
+} // namespace devtools_util
diff --git a/libcef/browser/devtools/devtools_util.h b/libcef/browser/devtools/devtools_util.h
new file mode 100644
index 00000000..848e1684
--- /dev/null
+++ b/libcef/browser/devtools/devtools_util.h
@@ -0,0 +1,72 @@
+// Copyright (c) 2020 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_DEVTOOLS_DEVTOOLS_UTIL_H_
+#define CEF_LIBCEF_BROWSER_DEVTOOLS_DEVTOOLS_UTIL_H_
+#pragma once
+
+#include "base/strings/string_piece.h"
+
+namespace devtools_util {
+
+// Fast parser for DevTools JSON protocol messages. This implementation makes
+// certain assumptions about the JSON object structure (value order and
+// formatting) to avoid stateful parsing of messages that may be large
+// (sometimes > 1MB in size). The message must be a JSON dictionary that starts
+// with a "method" or "id" value which is non-empty and of the expected data
+// type. Messages that have a "method" value (event message) may optionally have
+// a "params" dictionary. Messages that have an "id" value (result message) must
+// have a "result" or "error" dictionary. The dictionary contents are not
+// validated and may be empty ("{}").
+//
+// Example event message:
+// {"method":"Target.targetDestroyed","params":{"targetId":"1234..."}}
+//
+// Example result messages:
+// {"id":3,"result":{}}
+// {"id":4,"result":{"debuggerId":"-2193881606781505058.81393575456727957"}}
+// {"id":5,"error":{"code":-32000,"message":"Not supported"}}
+struct ProtocolParser {
+ ProtocolParser() = default;
+
+ // Checks for a non-empty JSON dictionary.
+ static bool IsValidMessage(const base::StringPiece& message);
+
+ // Returns false if already initialized.
+ bool Initialize(const base::StringPiece& message);
+
+ bool IsInitialized() const { return status_ != UNINITIALIZED; }
+ bool IsEvent() const { return status_ == EVENT; }
+ bool IsResult() const { return status_ == RESULT; }
+ bool IsFailure() const { return status_ == FAILURE; }
+
+ void Reset() { status_ = UNINITIALIZED; }
+
+ // For event messages:
+ // "method" string:
+ base::StringPiece method_;
+
+ // For result messages:
+ // "id" int:
+ int message_id_ = 0;
+ // true if "result" value, false if "error" value:
+ bool success_ = false;
+
+ // For both:
+ // "params", "result" or "error" dictionary:
+ base::StringPiece params_;
+
+ private:
+ enum Status {
+ UNINITIALIZED,
+ EVENT, // Event message.
+ RESULT, // Result message.
+ FAILURE, // Parsing failure.
+ };
+ Status status_ = UNINITIALIZED;
+};
+
+} // namespace devtools_util
+
+#endif // CEF_LIBCEF_BROWSER_DEVTOOLS_DEVTOOLS_UTIL_H_ \ No newline at end of file
diff --git a/libcef/browser/devtools/devtools_util_unittest.cc b/libcef/browser/devtools/devtools_util_unittest.cc
new file mode 100644
index 00000000..ec41edef
--- /dev/null
+++ b/libcef/browser/devtools/devtools_util_unittest.cc
@@ -0,0 +1,220 @@
+// Copyright (c) 2020 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "libcef/browser/devtools/devtools_util.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+using namespace devtools_util;
+
+TEST(DevToolsUtil, ProtocolParser_IsValidMessage) {
+ // Empty dictionary is not valid.
+ EXPECT_FALSE(ProtocolParser::IsValidMessage(""));
+ EXPECT_FALSE(ProtocolParser::IsValidMessage("{}"));
+
+ // Incorrectly formatted dictionary is not valid.
+ EXPECT_FALSE(ProtocolParser::IsValidMessage("{ ]"));
+
+ // Everything else is valid (we don't verify JSON structure).
+ EXPECT_TRUE(ProtocolParser::IsValidMessage("{ }"));
+ EXPECT_TRUE(ProtocolParser::IsValidMessage("{blah blah}"));
+ EXPECT_TRUE(ProtocolParser::IsValidMessage("{method:\"foobar\"}"));
+}
+
+TEST(DevToolsUtil, ProtocolParser_Initialize_IsFailure_Unknown) {
+ ProtocolParser parser;
+ EXPECT_FALSE(parser.IsInitialized());
+
+ // Empty message is invalid.
+ EXPECT_TRUE(parser.Initialize(""));
+ EXPECT_TRUE(parser.IsInitialized());
+ EXPECT_TRUE(parser.IsFailure());
+
+ parser.Reset();
+ EXPECT_FALSE(parser.IsInitialized());
+
+ // Empty dictionary is invalid.
+ EXPECT_TRUE(parser.Initialize("{}"));
+ EXPECT_TRUE(parser.IsInitialized());
+ EXPECT_TRUE(parser.IsFailure());
+
+ parser.Reset();
+ EXPECT_FALSE(parser.IsInitialized());
+
+ // Unrecognized dictionary type is invalid.
+ EXPECT_TRUE(parser.Initialize("{blah blah}"));
+ EXPECT_TRUE(parser.IsInitialized());
+ EXPECT_TRUE(parser.IsFailure());
+}
+
+TEST(DevToolsUtil, ProtocolParser_Initialize_IsFailure_EventMalformed) {
+ ProtocolParser parser;
+ EXPECT_FALSE(parser.IsInitialized());
+
+ // Empty method is invalid.
+ EXPECT_TRUE(parser.Initialize("{\"method\":\"\"}"));
+ EXPECT_TRUE(parser.IsInitialized());
+ EXPECT_TRUE(parser.IsFailure());
+
+ parser.Reset();
+ EXPECT_FALSE(parser.IsInitialized());
+
+ // Unrecognized value is invalid.
+ EXPECT_TRUE(parser.Initialize("{\"method\":\"foo\",oops:false}"));
+ EXPECT_TRUE(parser.IsInitialized());
+ EXPECT_TRUE(parser.IsFailure());
+
+ parser.Reset();
+ EXPECT_FALSE(parser.IsInitialized());
+
+ // Params must be a dictionary.
+ EXPECT_TRUE(parser.Initialize("{\"method\":\",params:[]}"));
+ EXPECT_TRUE(parser.IsInitialized());
+ EXPECT_TRUE(parser.IsFailure());
+}
+
+TEST(DevToolsUtil, ProtocolParser_Initialize_IsEvent) {
+ ProtocolParser parser;
+ EXPECT_FALSE(parser.IsInitialized());
+
+ // Method without params is valid.
+ std::string message = "{\"method\":\"Test.myMethod\"}";
+ EXPECT_TRUE(parser.Initialize(message));
+ EXPECT_TRUE(parser.IsInitialized());
+ EXPECT_TRUE(parser.IsEvent());
+ EXPECT_EQ("Test.myMethod", parser.method_);
+ EXPECT_TRUE(parser.params_.empty());
+
+ parser.Reset();
+ EXPECT_FALSE(parser.IsInitialized());
+
+ // Method with empty params dictionary is valid.
+ message = "{\"method\":\"Test.myMethod2\",\"params\":{}}";
+ EXPECT_TRUE(parser.Initialize(message));
+ EXPECT_TRUE(parser.IsInitialized());
+ EXPECT_TRUE(parser.IsEvent());
+ EXPECT_EQ("Test.myMethod2", parser.method_);
+ EXPECT_EQ("{}", parser.params_);
+
+ parser.Reset();
+ EXPECT_FALSE(parser.IsInitialized());
+
+ // Method with non-empty params dictionary is valid.
+ message = "{\"method\":\"Test.myMethod3\",\"params\":{\"foo\":\"bar\"}}";
+ EXPECT_TRUE(parser.Initialize(message));
+ EXPECT_TRUE(parser.IsInitialized());
+ EXPECT_TRUE(parser.IsEvent());
+ EXPECT_EQ("Test.myMethod3", parser.method_);
+ EXPECT_EQ("{\"foo\":\"bar\"}", parser.params_);
+}
+
+TEST(DevToolsUtil, ProtocolParser_Initialize_IsFailure_ResultMalformed) {
+ ProtocolParser parser;
+ EXPECT_FALSE(parser.IsInitialized());
+
+ // Empty ID is invalid.
+ EXPECT_TRUE(parser.Initialize("{\"id\":,result:{}}"));
+ EXPECT_TRUE(parser.IsInitialized());
+ EXPECT_TRUE(parser.IsFailure());
+
+ parser.Reset();
+ EXPECT_FALSE(parser.IsInitialized());
+
+ // Missing result or error value is invalid.
+ EXPECT_TRUE(parser.Initialize("{\"id\":1}"));
+ EXPECT_TRUE(parser.IsInitialized());
+ EXPECT_TRUE(parser.IsFailure());
+
+ parser.Reset();
+ EXPECT_FALSE(parser.IsInitialized());
+
+ // Unrecognized value is invalid.
+ EXPECT_TRUE(parser.Initialize("{\"id\":1,oops:false}"));
+ EXPECT_TRUE(parser.IsInitialized());
+ EXPECT_TRUE(parser.IsFailure());
+
+ parser.Reset();
+ EXPECT_FALSE(parser.IsInitialized());
+
+ // Result must be a dictionary.
+ EXPECT_TRUE(parser.Initialize("{\"id\":1,\"result\":[]}"));
+ EXPECT_TRUE(parser.IsInitialized());
+ EXPECT_TRUE(parser.IsFailure());
+
+ parser.Reset();
+ EXPECT_FALSE(parser.IsInitialized());
+
+ // Error must be a dictionary.
+ EXPECT_TRUE(parser.Initialize("{\"id\":1,\"error\":[]}"));
+ EXPECT_TRUE(parser.IsInitialized());
+ EXPECT_TRUE(parser.IsFailure());
+}
+
+TEST(DevToolsUtil, ProtocolParser_Initialize_IsResult_Result) {
+ ProtocolParser parser;
+ EXPECT_FALSE(parser.IsInitialized());
+
+ // Id with empty result dictionary is valid.
+ std::string message = "{\"id\":1,\"result\":{}}";
+ EXPECT_TRUE(parser.Initialize(message));
+ EXPECT_TRUE(parser.IsInitialized());
+ EXPECT_TRUE(parser.IsResult());
+ EXPECT_EQ(1, parser.message_id_);
+ EXPECT_TRUE(parser.success_);
+ EXPECT_EQ("{}", parser.params_);
+
+ parser.Reset();
+ EXPECT_FALSE(parser.IsInitialized());
+
+ // Id with non-empty result dictionary is valid.
+ message = "{\"id\":2,\"result\":{\"foo\":\"bar\"}}";
+ EXPECT_TRUE(parser.Initialize(message));
+ EXPECT_TRUE(parser.IsInitialized());
+ EXPECT_TRUE(parser.IsResult());
+ EXPECT_EQ(2, parser.message_id_);
+ EXPECT_TRUE(parser.success_);
+ EXPECT_EQ("{\"foo\":\"bar\"}", parser.params_);
+}
+
+TEST(DevToolsUtil, ProtocolParser_Initialize_IsResult_Error) {
+ ProtocolParser parser;
+ EXPECT_FALSE(parser.IsInitialized());
+
+ // Id with empty error dictionary is valid.
+ std::string message = "{\"id\":1,\"error\":{}}";
+ EXPECT_TRUE(parser.Initialize(message));
+ EXPECT_TRUE(parser.IsInitialized());
+ EXPECT_TRUE(parser.IsResult());
+ EXPECT_EQ(1, parser.message_id_);
+ EXPECT_FALSE(parser.success_);
+ EXPECT_EQ("{}", parser.params_);
+
+ parser.Reset();
+ EXPECT_FALSE(parser.IsInitialized());
+
+ // Id with non-empty error dictionary is valid.
+ message = "{\"id\":2,\"error\":{\"foo\":\"bar\"}}";
+ EXPECT_TRUE(parser.Initialize(message));
+ EXPECT_TRUE(parser.IsInitialized());
+ EXPECT_TRUE(parser.IsResult());
+ EXPECT_EQ(2, parser.message_id_);
+ EXPECT_FALSE(parser.success_);
+ EXPECT_EQ("{\"foo\":\"bar\"}", parser.params_);
+}
+
+TEST(DevToolsUtil, ProtocolParser_Can_Handle_MissingQuote) {
+ ProtocolParser parser;
+
+ const auto message = "{\"method\":\"Test.myMethod}";
+ EXPECT_TRUE(parser.Initialize(message));
+ EXPECT_TRUE(parser.IsFailure());
+}
+
+TEST(DevToolsUtil, ProtocolParser_Can_Handle_MissingComma) {
+ ProtocolParser parser;
+
+ const auto message = "{\"id\":1\"error\":{}}";
+ EXPECT_TRUE(parser.Initialize(message));
+ EXPECT_TRUE(parser.IsFailure());
+}
diff --git a/libcef/browser/download_item_impl.cc b/libcef/browser/download_item_impl.cc
new file mode 100644
index 00000000..d5e63981
--- /dev/null
+++ b/libcef/browser/download_item_impl.cc
@@ -0,0 +1,105 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "libcef/browser/download_item_impl.h"
+
+#include "libcef/common/time_util.h"
+
+#include "components/download/public/common/download_item.h"
+#include "url/gurl.h"
+
+CefDownloadItemImpl::CefDownloadItemImpl(download::DownloadItem* value)
+ : CefValueBase<CefDownloadItem, download::DownloadItem>(
+ value,
+ nullptr,
+ kOwnerNoDelete,
+ true,
+ new CefValueControllerNonThreadSafe()) {
+ // Indicate that this object owns the controller.
+ SetOwnsController();
+}
+
+bool CefDownloadItemImpl::IsValid() {
+ return !detached();
+}
+
+bool CefDownloadItemImpl::IsInProgress() {
+ CEF_VALUE_VERIFY_RETURN(false, false);
+ return const_value().GetState() == download::DownloadItem::IN_PROGRESS;
+}
+
+bool CefDownloadItemImpl::IsComplete() {
+ CEF_VALUE_VERIFY_RETURN(false, false);
+ return const_value().GetState() == download::DownloadItem::COMPLETE;
+}
+
+bool CefDownloadItemImpl::IsCanceled() {
+ CEF_VALUE_VERIFY_RETURN(false, false);
+ return const_value().GetState() == download::DownloadItem::CANCELLED;
+}
+
+int64 CefDownloadItemImpl::GetCurrentSpeed() {
+ CEF_VALUE_VERIFY_RETURN(false, 0);
+ return const_value().CurrentSpeed();
+}
+
+int CefDownloadItemImpl::GetPercentComplete() {
+ CEF_VALUE_VERIFY_RETURN(false, -1);
+ return const_value().PercentComplete();
+}
+
+int64 CefDownloadItemImpl::GetTotalBytes() {
+ CEF_VALUE_VERIFY_RETURN(false, 0);
+ return const_value().GetTotalBytes();
+}
+
+int64 CefDownloadItemImpl::GetReceivedBytes() {
+ CEF_VALUE_VERIFY_RETURN(false, 0);
+ return const_value().GetReceivedBytes();
+}
+
+CefBaseTime CefDownloadItemImpl::GetStartTime() {
+ CEF_VALUE_VERIFY_RETURN(false, CefBaseTime());
+ return const_value().GetStartTime();
+}
+
+CefBaseTime CefDownloadItemImpl::GetEndTime() {
+ CEF_VALUE_VERIFY_RETURN(false, CefBaseTime());
+ return const_value().GetEndTime();
+}
+
+CefString CefDownloadItemImpl::GetFullPath() {
+ CEF_VALUE_VERIFY_RETURN(false, CefString());
+ return const_value().GetFullPath().value();
+}
+
+uint32 CefDownloadItemImpl::GetId() {
+ CEF_VALUE_VERIFY_RETURN(false, 0);
+ return const_value().GetId();
+}
+
+CefString CefDownloadItemImpl::GetURL() {
+ CEF_VALUE_VERIFY_RETURN(false, CefString());
+ return const_value().GetURL().spec();
+}
+
+CefString CefDownloadItemImpl::GetOriginalUrl() {
+ CEF_VALUE_VERIFY_RETURN(false, CefString());
+ return const_value().GetOriginalUrl().spec();
+}
+
+CefString CefDownloadItemImpl::GetSuggestedFileName() {
+ CEF_VALUE_VERIFY_RETURN(false, CefString());
+ return const_value().GetSuggestedFilename();
+}
+
+CefString CefDownloadItemImpl::GetContentDisposition() {
+ CEF_VALUE_VERIFY_RETURN(false, CefString());
+ return const_value().GetContentDisposition();
+}
+
+CefString CefDownloadItemImpl::GetMimeType() {
+ CEF_VALUE_VERIFY_RETURN(false, CefString());
+ return const_value().GetMimeType();
+}
diff --git a/libcef/browser/download_item_impl.h b/libcef/browser/download_item_impl.h
new file mode 100644
index 00000000..8a02e629
--- /dev/null
+++ b/libcef/browser/download_item_impl.h
@@ -0,0 +1,45 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_DOWNLOAD_ITEM_IMPL_H_
+#define CEF_LIBCEF_BROWSER_DOWNLOAD_ITEM_IMPL_H_
+#pragma once
+
+#include "include/cef_download_item.h"
+#include "libcef/common/value_base.h"
+
+namespace download {
+class DownloadItem;
+}
+
+// CefDownloadItem implementation
+class CefDownloadItemImpl
+ : public CefValueBase<CefDownloadItem, download::DownloadItem> {
+ public:
+ explicit CefDownloadItemImpl(download::DownloadItem* value);
+
+ CefDownloadItemImpl(const CefDownloadItemImpl&) = delete;
+ CefDownloadItemImpl& operator=(const CefDownloadItemImpl&) = delete;
+
+ // CefDownloadItem methods.
+ bool IsValid() override;
+ bool IsInProgress() override;
+ bool IsComplete() override;
+ bool IsCanceled() override;
+ int64 GetCurrentSpeed() override;
+ int GetPercentComplete() override;
+ int64 GetTotalBytes() override;
+ int64 GetReceivedBytes() override;
+ CefBaseTime GetStartTime() override;
+ CefBaseTime GetEndTime() override;
+ CefString GetFullPath() override;
+ uint32 GetId() override;
+ CefString GetURL() override;
+ CefString GetOriginalUrl() override;
+ CefString GetSuggestedFileName() override;
+ CefString GetContentDisposition() override;
+ CefString GetMimeType() override;
+};
+
+#endif // CEF_LIBCEF_BROWSER_DOWNLOAD_ITEM_IMPL_H_
diff --git a/libcef/browser/download_manager_delegate.cc b/libcef/browser/download_manager_delegate.cc
new file mode 100644
index 00000000..dc684232
--- /dev/null
+++ b/libcef/browser/download_manager_delegate.cc
@@ -0,0 +1,485 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/download_manager_delegate.h"
+
+#include <tuple>
+
+#include "include/cef_download_handler.h"
+#include "libcef/browser/alloy/alloy_browser_host_impl.h"
+#include "libcef/browser/context.h"
+#include "libcef/browser/download_item_impl.h"
+#include "libcef/browser/thread_util.h"
+
+#include "base/files/file_util.h"
+#include "base/functional/bind.h"
+#include "base/logging.h"
+#include "base/path_service.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/common/chrome_constants.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/download_item_utils.h"
+#include "content/public/browser/web_contents.h"
+#include "net/base/filename_util.h"
+#include "third_party/blink/public/mojom/choosers/file_chooser.mojom.h"
+
+using content::DownloadManager;
+using content::WebContents;
+using download::DownloadItem;
+
+namespace {
+
+// Helper function to retrieve the CefDownloadHandler.
+CefRefPtr<CefDownloadHandler> GetDownloadHandler(
+ CefRefPtr<AlloyBrowserHostImpl> browser) {
+ CefRefPtr<CefClient> client = browser->GetClient();
+ if (client.get()) {
+ return client->GetDownloadHandler();
+ }
+ return nullptr;
+}
+
+// CefBeforeDownloadCallback implementation.
+class CefBeforeDownloadCallbackImpl : public CefBeforeDownloadCallback {
+ public:
+ CefBeforeDownloadCallbackImpl(const base::WeakPtr<DownloadManager>& manager,
+ uint32 download_id,
+ const base::FilePath& suggested_name,
+ content::DownloadTargetCallback callback)
+ : manager_(manager),
+ download_id_(download_id),
+ suggested_name_(suggested_name),
+ callback_(std::move(callback)) {}
+
+ CefBeforeDownloadCallbackImpl(const CefBeforeDownloadCallbackImpl&) = delete;
+ CefBeforeDownloadCallbackImpl& operator=(
+ const CefBeforeDownloadCallbackImpl&) = delete;
+
+ void Continue(const CefString& download_path, bool show_dialog) override {
+ if (CEF_CURRENTLY_ON_UIT()) {
+ if (download_id_ <= 0) {
+ return;
+ }
+
+ if (manager_) {
+ base::FilePath path = base::FilePath(download_path);
+ CEF_POST_USER_VISIBLE_TASK(
+ base::BindOnce(&CefBeforeDownloadCallbackImpl::GenerateFilename,
+ manager_, download_id_, suggested_name_, path,
+ show_dialog, std::move(callback_)));
+ }
+
+ download_id_ = 0;
+ } else {
+ CEF_POST_TASK(CEF_UIT,
+ base::BindOnce(&CefBeforeDownloadCallbackImpl::Continue,
+ this, download_path, show_dialog));
+ }
+ }
+
+ private:
+ static void GenerateFilename(base::WeakPtr<DownloadManager> manager,
+ uint32 download_id,
+ const base::FilePath& suggested_name,
+ const base::FilePath& download_path,
+ bool show_dialog,
+ content::DownloadTargetCallback callback) {
+ CEF_REQUIRE_BLOCKING();
+
+ base::FilePath suggested_path = download_path;
+ if (!suggested_path.empty()) {
+ // Create the directory if necessary.
+ base::FilePath dir_path = suggested_path.DirName();
+ if (!base::DirectoryExists(dir_path) &&
+ !base::CreateDirectory(dir_path)) {
+ NOTREACHED() << "failed to create the download directory";
+ suggested_path.clear();
+ }
+ }
+
+ if (suggested_path.empty()) {
+ if (base::PathService::Get(base::DIR_TEMP, &suggested_path)) {
+ // Use the temp directory.
+ suggested_path = suggested_path.Append(suggested_name);
+ } else {
+ // Use the current working directory.
+ suggested_path = suggested_name;
+ }
+ }
+
+ CEF_POST_TASK(
+ CEF_UIT,
+ base::BindOnce(&CefBeforeDownloadCallbackImpl::ChooseDownloadPath,
+ manager, download_id, suggested_path, show_dialog,
+ std::move(callback)));
+ }
+
+ static void ChooseDownloadPath(base::WeakPtr<DownloadManager> manager,
+ uint32 download_id,
+ const base::FilePath& suggested_path,
+ bool show_dialog,
+ content::DownloadTargetCallback callback) {
+ if (!manager) {
+ return;
+ }
+
+ DownloadItem* item = manager->GetDownload(download_id);
+ if (!item || item->GetState() != DownloadItem::IN_PROGRESS) {
+ return;
+ }
+
+ bool handled = false;
+
+ if (show_dialog) {
+ WebContents* web_contents =
+ content::DownloadItemUtils::GetWebContents(item);
+ CefRefPtr<AlloyBrowserHostImpl> browser =
+ AlloyBrowserHostImpl::GetBrowserForContents(web_contents);
+ if (browser.get()) {
+ handled = true;
+
+ blink::mojom::FileChooserParams params;
+ params.mode = blink::mojom::FileChooserParams::Mode::kSave;
+ if (!suggested_path.empty()) {
+ params.default_file_name = suggested_path;
+ if (!suggested_path.Extension().empty()) {
+ params.accept_types.push_back(
+ CefString(suggested_path.Extension()));
+ }
+ }
+
+ browser->RunFileChooserForBrowser(
+ params,
+ base::BindOnce(
+ &CefBeforeDownloadCallbackImpl::ChooseDownloadPathCallback,
+ std::move(callback)));
+ }
+ }
+
+ if (!handled) {
+ std::move(callback).Run(
+ suggested_path, DownloadItem::TARGET_DISPOSITION_OVERWRITE,
+ download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
+ download::DownloadItem::InsecureDownloadStatus::UNKNOWN,
+ suggested_path, base::FilePath(), std::string() /*mime_type*/,
+ download::DOWNLOAD_INTERRUPT_REASON_NONE);
+ }
+ }
+
+ static void ChooseDownloadPathCallback(
+ content::DownloadTargetCallback callback,
+ const std::vector<base::FilePath>& file_paths) {
+ DCHECK_LE(file_paths.size(), (size_t)1);
+
+ base::FilePath path;
+ if (file_paths.size() > 0) {
+ path = file_paths.front();
+ }
+
+ // The download will be cancelled if |path| is empty.
+ std::move(callback).Run(
+ path, DownloadItem::TARGET_DISPOSITION_OVERWRITE,
+ download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
+ download::DownloadItem::InsecureDownloadStatus::UNKNOWN, path,
+ base::FilePath(), std::string() /*mime_type*/,
+ download::DOWNLOAD_INTERRUPT_REASON_NONE);
+ }
+
+ base::WeakPtr<DownloadManager> manager_;
+ uint32 download_id_;
+ base::FilePath suggested_name_;
+ content::DownloadTargetCallback callback_;
+
+ IMPLEMENT_REFCOUNTING(CefBeforeDownloadCallbackImpl);
+};
+
+// CefDownloadItemCallback implementation.
+class CefDownloadItemCallbackImpl : public CefDownloadItemCallback {
+ public:
+ explicit CefDownloadItemCallbackImpl(
+ const base::WeakPtr<DownloadManager>& manager,
+ uint32 download_id)
+ : manager_(manager), download_id_(download_id) {}
+
+ CefDownloadItemCallbackImpl(const CefDownloadItemCallbackImpl&) = delete;
+ CefDownloadItemCallbackImpl& operator=(const CefDownloadItemCallbackImpl&) =
+ delete;
+
+ void Cancel() override {
+ CEF_POST_TASK(CEF_UIT,
+ base::BindOnce(&CefDownloadItemCallbackImpl::DoCancel, this));
+ }
+
+ void Pause() override {
+ CEF_POST_TASK(CEF_UIT,
+ base::BindOnce(&CefDownloadItemCallbackImpl::DoPause, this));
+ }
+
+ void Resume() override {
+ CEF_POST_TASK(CEF_UIT,
+ base::BindOnce(&CefDownloadItemCallbackImpl::DoResume, this));
+ }
+
+ private:
+ void DoCancel() {
+ if (download_id_ <= 0) {
+ return;
+ }
+
+ if (manager_) {
+ DownloadItem* item = manager_->GetDownload(download_id_);
+ if (item && item->GetState() == DownloadItem::IN_PROGRESS) {
+ item->Cancel(true);
+ }
+ }
+
+ download_id_ = 0;
+ }
+
+ void DoPause() {
+ if (download_id_ <= 0) {
+ return;
+ }
+
+ if (manager_) {
+ DownloadItem* item = manager_->GetDownload(download_id_);
+ if (item && item->GetState() == DownloadItem::IN_PROGRESS) {
+ item->Pause();
+ }
+ }
+ }
+
+ void DoResume() {
+ if (download_id_ <= 0) {
+ return;
+ }
+
+ if (manager_) {
+ DownloadItem* item = manager_->GetDownload(download_id_);
+ if (item && item->CanResume()) {
+ item->Resume(true);
+ }
+ }
+ }
+
+ base::WeakPtr<DownloadManager> manager_;
+ uint32 download_id_;
+
+ IMPLEMENT_REFCOUNTING(CefDownloadItemCallbackImpl);
+};
+
+} // namespace
+
+CefDownloadManagerDelegate::CefDownloadManagerDelegate(DownloadManager* manager)
+ : manager_(manager), manager_ptr_factory_(manager) {
+ DCHECK(manager);
+ manager->AddObserver(this);
+
+ DownloadManager::DownloadVector items;
+ manager->GetAllDownloads(&items);
+ DownloadManager::DownloadVector::const_iterator it = items.begin();
+ for (; it != items.end(); ++it) {
+ OnDownloadCreated(manager, *it);
+ }
+}
+
+CefDownloadManagerDelegate::~CefDownloadManagerDelegate() {
+ if (manager_) {
+ manager_->SetDelegate(nullptr);
+ manager_->RemoveObserver(this);
+ }
+
+ while (!item_browser_map_.empty()) {
+ OnDownloadDestroyed(item_browser_map_.begin()->first);
+ }
+}
+
+void CefDownloadManagerDelegate::OnDownloadUpdated(DownloadItem* download) {
+ CefRefPtr<AlloyBrowserHostImpl> browser = GetBrowser(download);
+ CefRefPtr<CefDownloadHandler> handler;
+ if (browser.get()) {
+ handler = GetDownloadHandler(browser);
+ }
+
+ if (handler.get()) {
+ CefRefPtr<CefDownloadItemImpl> download_item(
+ new CefDownloadItemImpl(download));
+ CefRefPtr<CefDownloadItemCallback> callback(new CefDownloadItemCallbackImpl(
+ manager_ptr_factory_.GetWeakPtr(), download->GetId()));
+
+ handler->OnDownloadUpdated(browser.get(), download_item.get(), callback);
+
+ std::ignore = download_item->Detach(nullptr);
+ }
+}
+
+void CefDownloadManagerDelegate::OnDownloadDestroyed(DownloadItem* item) {
+ item->RemoveObserver(this);
+
+ AlloyBrowserHostImpl* browser = nullptr;
+
+ ItemBrowserMap::iterator it = item_browser_map_.find(item);
+ DCHECK(it != item_browser_map_.end());
+ if (it != item_browser_map_.end()) {
+ browser = it->second;
+ item_browser_map_.erase(it);
+ }
+
+ if (browser) {
+ // Determine if any remaining DownloadItems are associated with the same
+ // browser. If not, then unregister as an observer.
+ bool has_remaining = false;
+ ItemBrowserMap::const_iterator it2 = item_browser_map_.begin();
+ for (; it2 != item_browser_map_.end(); ++it2) {
+ if (it2->second == browser) {
+ has_remaining = true;
+ break;
+ }
+ }
+
+ if (!has_remaining) {
+ browser->RemoveObserver(this);
+ }
+ }
+}
+
+void CefDownloadManagerDelegate::OnDownloadCreated(DownloadManager* manager,
+ DownloadItem* item) {
+ // This callback may arrive after DetermineDownloadTarget, so we allow
+ // association from either method.
+ CefRefPtr<AlloyBrowserHostImpl> browser = GetOrAssociateBrowser(item);
+ if (!browser) {
+ // If the download is rejected (e.g. ALT+click on an invalid protocol link)
+ // then an "interrupted" download will be started via DownloadManagerImpl::
+ // StartDownloadWithId (originating from CreateInterruptedDownload) with no
+ // associated WebContents and consequently no associated CEF browser. In
+ // that case DetermineDownloadTarget will be called before this method.
+ // TODO(cef): Figure out how to expose this via a client callback.
+ const std::vector<GURL>& url_chain = item->GetUrlChain();
+ if (!url_chain.empty()) {
+ LOG(INFO) << "Rejected download of " << url_chain.back().spec();
+ }
+ item->Cancel(true);
+ }
+}
+
+void CefDownloadManagerDelegate::ManagerGoingDown(DownloadManager* manager) {
+ DCHECK_EQ(manager, manager_);
+ manager->SetDelegate(nullptr);
+ manager->RemoveObserver(this);
+ manager_ptr_factory_.InvalidateWeakPtrs();
+ manager_ = nullptr;
+}
+
+bool CefDownloadManagerDelegate::DetermineDownloadTarget(
+ DownloadItem* item,
+ content::DownloadTargetCallback* callback) {
+ if (!item->GetForcedFilePath().empty()) {
+ std::move(*callback).Run(
+ item->GetForcedFilePath(), DownloadItem::TARGET_DISPOSITION_OVERWRITE,
+ download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
+ download::DownloadItem::InsecureDownloadStatus::UNKNOWN,
+ item->GetForcedFilePath(), base::FilePath(),
+ std::string() /*mime_type*/, download::DOWNLOAD_INTERRUPT_REASON_NONE);
+ return true;
+ }
+
+ // This callback may arrive before OnDownloadCreated, so we allow association
+ // from either method.
+ CefRefPtr<AlloyBrowserHostImpl> browser = GetOrAssociateBrowser(item);
+ CefRefPtr<CefDownloadHandler> handler;
+ if (browser.get()) {
+ handler = GetDownloadHandler(browser);
+ }
+
+ if (handler.get()) {
+ base::FilePath suggested_name = net::GenerateFileName(
+ item->GetURL(), item->GetContentDisposition(), std::string(),
+ item->GetSuggestedFilename(), item->GetMimeType(), "download");
+
+ CefRefPtr<CefDownloadItemImpl> download_item(new CefDownloadItemImpl(item));
+ CefRefPtr<CefBeforeDownloadCallback> callbackObj(
+ new CefBeforeDownloadCallbackImpl(manager_ptr_factory_.GetWeakPtr(),
+ item->GetId(), suggested_name,
+ std::move(*callback)));
+
+ handler->OnBeforeDownload(browser.get(), download_item.get(),
+ suggested_name.value(), callbackObj);
+
+ std::ignore = download_item->Detach(nullptr);
+ }
+
+ return true;
+}
+
+void CefDownloadManagerDelegate::GetNextId(
+ content::DownloadIdCallback callback) {
+ static uint32 next_id = DownloadItem::kInvalidId + 1;
+ std::move(callback).Run(next_id++);
+}
+
+std::string CefDownloadManagerDelegate::ApplicationClientIdForFileScanning() {
+ return std::string(chrome::kApplicationClientIDStringForAVScanning);
+}
+
+void CefDownloadManagerDelegate::OnBrowserDestroyed(
+ CefBrowserHostBase* browser) {
+ ItemBrowserMap::iterator it = item_browser_map_.begin();
+ for (; it != item_browser_map_.end(); ++it) {
+ if (it->second == browser) {
+ // Don't call back into browsers that have been destroyed. We're not
+ // canceling the download so it will continue silently until it completes
+ // or until the associated browser context is destroyed.
+ it->second = nullptr;
+ }
+ }
+}
+
+AlloyBrowserHostImpl* CefDownloadManagerDelegate::GetOrAssociateBrowser(
+ download::DownloadItem* item) {
+ ItemBrowserMap::const_iterator it = item_browser_map_.find(item);
+ if (it != item_browser_map_.end()) {
+ return it->second;
+ }
+
+ AlloyBrowserHostImpl* browser = nullptr;
+ content::WebContents* contents =
+ content::DownloadItemUtils::GetWebContents(item);
+ if (contents) {
+ browser = AlloyBrowserHostImpl::GetBrowserForContents(contents).get();
+ DCHECK(browser);
+ }
+ if (!browser) {
+ return nullptr;
+ }
+
+ item->AddObserver(this);
+
+ item_browser_map_.insert(std::make_pair(item, browser));
+
+ // Register as an observer so that we can cancel associated DownloadItems when
+ // the browser is destroyed.
+ if (!browser->HasObserver(this)) {
+ browser->AddObserver(this);
+ }
+
+ return browser;
+}
+
+AlloyBrowserHostImpl* CefDownloadManagerDelegate::GetBrowser(
+ DownloadItem* item) {
+ ItemBrowserMap::const_iterator it = item_browser_map_.find(item);
+ if (it != item_browser_map_.end()) {
+ return it->second;
+ }
+
+ // If the download is rejected (e.g. ALT+click on an invalid protocol link)
+ // then an "interrupted" download will be started via DownloadManagerImpl::
+ // StartDownloadWithId (originating from CreateInterruptedDownload) with no
+ // associated WebContents and consequently no associated CEF browser. In that
+ // case DetermineDownloadTarget will be called before OnDownloadCreated.
+ DCHECK(!content::DownloadItemUtils::GetWebContents(item));
+ return nullptr;
+}
diff --git a/libcef/browser/download_manager_delegate.h b/libcef/browser/download_manager_delegate.h
new file mode 100644
index 00000000..46c13bf8
--- /dev/null
+++ b/libcef/browser/download_manager_delegate.h
@@ -0,0 +1,67 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_DOWNLOAD_MANAGER_DELEGATE_H_
+#define CEF_LIBCEF_BROWSER_DOWNLOAD_MANAGER_DELEGATE_H_
+#pragma once
+
+#include <set>
+
+#include "libcef/browser/browser_host_base.h"
+
+#include "base/memory/weak_ptr.h"
+#include "components/download/public/common/download_item.h"
+#include "content/public/browser/download_manager.h"
+#include "content/public/browser/download_manager_delegate.h"
+
+class AlloyBrowserHostImpl;
+
+class CefDownloadManagerDelegate : public download::DownloadItem::Observer,
+ public content::DownloadManager::Observer,
+ public content::DownloadManagerDelegate,
+ public CefBrowserHostBase::Observer {
+ public:
+ explicit CefDownloadManagerDelegate(content::DownloadManager* manager);
+
+ CefDownloadManagerDelegate(const CefDownloadManagerDelegate&) = delete;
+ CefDownloadManagerDelegate& operator=(const CefDownloadManagerDelegate&) =
+ delete;
+
+ ~CefDownloadManagerDelegate() override;
+
+ private:
+ // DownloadItem::Observer methods.
+ void OnDownloadUpdated(download::DownloadItem* item) override;
+ void OnDownloadDestroyed(download::DownloadItem* item) override;
+
+ // DownloadManager::Observer methods.
+ void OnDownloadCreated(content::DownloadManager* manager,
+ download::DownloadItem* item) override;
+ void ManagerGoingDown(content::DownloadManager* manager) override;
+
+ // DownloadManagerDelegate methods.
+ bool DetermineDownloadTarget(
+ download::DownloadItem* item,
+ content::DownloadTargetCallback* callback) override;
+ void GetNextId(content::DownloadIdCallback callback) override;
+ std::string ApplicationClientIdForFileScanning() override;
+
+ // CefBrowserHostBase::Observer methods.
+ void OnBrowserDestroyed(CefBrowserHostBase* browser) override;
+
+ AlloyBrowserHostImpl* GetOrAssociateBrowser(download::DownloadItem* item);
+ AlloyBrowserHostImpl* GetBrowser(download::DownloadItem* item);
+
+ content::DownloadManager* manager_;
+ base::WeakPtrFactory<content::DownloadManager> manager_ptr_factory_;
+
+ // Map of DownloadItem to originating AlloyBrowserHostImpl. Maintaining this
+ // map is necessary because DownloadItem::GetWebContents() may return NULL if
+ // the browser navigates while the download is in progress.
+ using ItemBrowserMap =
+ std::map<download::DownloadItem*, AlloyBrowserHostImpl*>;
+ ItemBrowserMap item_browser_map_;
+};
+
+#endif // CEF_LIBCEF_BROWSER_DOWNLOAD_MANAGER_DELEGATE_H_
diff --git a/libcef/browser/extension_impl.cc b/libcef/browser/extension_impl.cc
new file mode 100644
index 00000000..d1ef91ae
--- /dev/null
+++ b/libcef/browser/extension_impl.cc
@@ -0,0 +1,117 @@
+// Copyright (c) 2017 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "libcef/browser/extension_impl.h"
+
+#include "libcef/browser/request_context_impl.h"
+#include "libcef/browser/thread_util.h"
+#include "libcef/common/values_impl.h"
+
+#include "extensions/common/extension.h"
+
+CefExtensionImpl::CefExtensionImpl(const extensions::Extension* extension,
+ CefRequestContext* loader_context,
+ CefRefPtr<CefExtensionHandler> handler)
+ : id_(extension->id()),
+ path_(extension->path().value()),
+ manifest_(
+ new CefDictionaryValueImpl(extension->manifest()->value()->Clone(),
+ /*read_only=*/true)),
+ loader_context_(loader_context),
+ handler_(handler) {}
+
+CefString CefExtensionImpl::GetIdentifier() {
+ return id_;
+}
+
+CefString CefExtensionImpl::GetPath() {
+ return path_;
+}
+
+CefRefPtr<CefDictionaryValue> CefExtensionImpl::GetManifest() {
+ return manifest_;
+}
+
+bool CefExtensionImpl::IsSame(CefRefPtr<CefExtension> that) {
+ CefExtensionImpl* that_impl = static_cast<CefExtensionImpl*>(that.get());
+ if (!that_impl) {
+ return false;
+ }
+
+ // Maybe the same object.
+ if (this == that_impl) {
+ return true;
+ }
+
+ return id_ == that_impl->id_ && path_ == that_impl->path_ &&
+ loader_context_ == that_impl->loader_context_;
+}
+
+CefRefPtr<CefExtensionHandler> CefExtensionImpl::GetHandler() {
+ return handler_;
+}
+
+CefRefPtr<CefRequestContext> CefExtensionImpl::GetLoaderContext() {
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ NOTREACHED() << "called on invalid thread";
+ return nullptr;
+ }
+
+ return loader_context_;
+}
+
+bool CefExtensionImpl::IsLoaded() {
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ NOTREACHED() << "called on invalid thread";
+ return false;
+ }
+
+ return !unloaded_;
+}
+
+void CefExtensionImpl::Unload() {
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(CEF_UIT, base::BindOnce(&CefExtensionImpl::Unload, this));
+ return;
+ }
+
+ // Will be NULL for internal extensions. They can't be unloaded.
+ if (!loader_context_) {
+ return;
+ }
+
+ if (unloaded_) {
+ return;
+ }
+
+ // CefExtensionHandler callbacks triggered by UnloadExtension may check this
+ // flag, so set it here.
+ unloaded_ = true;
+
+ [[maybe_unused]] const bool result =
+ static_cast<CefRequestContextImpl*>(loader_context_)
+ ->GetBrowserContext()
+ ->UnloadExtension(id_);
+ DCHECK(result);
+}
+
+void CefExtensionImpl::OnExtensionLoaded() {
+ CEF_REQUIRE_UIT();
+ if (handler_) {
+ handler_->OnExtensionLoaded(this);
+ }
+}
+
+void CefExtensionImpl::OnExtensionUnloaded() {
+ CEF_REQUIRE_UIT();
+ // Should not be called for internal extensions.
+ DCHECK(loader_context_);
+
+ unloaded_ = true;
+ loader_context_ = nullptr;
+
+ if (handler_) {
+ handler_->OnExtensionUnloaded(this);
+ }
+}
diff --git a/libcef/browser/extension_impl.h b/libcef/browser/extension_impl.h
new file mode 100644
index 00000000..482e98c2
--- /dev/null
+++ b/libcef/browser/extension_impl.h
@@ -0,0 +1,60 @@
+// Copyright (c) 2017 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_EXTENSION_IMPL_H_
+#define CEF_LIBCEF_BROWSER_EXTENSION_IMPL_H_
+#pragma once
+
+#include <memory>
+
+#include "include/cef_extension.h"
+#include "include/cef_extension_handler.h"
+#include "include/cef_request_context.h"
+
+namespace extensions {
+class Extension;
+}
+
+// CefNavigationEntry implementation
+class CefExtensionImpl : public CefExtension {
+ public:
+ CefExtensionImpl(const extensions::Extension* extension,
+ CefRequestContext* loader_context,
+ CefRefPtr<CefExtensionHandler> handler);
+
+ CefExtensionImpl(const CefExtensionImpl&) = delete;
+ CefExtensionImpl& operator=(const CefExtensionImpl&) = delete;
+
+ // CefExtension methods.
+ CefString GetIdentifier() override;
+ CefString GetPath() override;
+ CefRefPtr<CefDictionaryValue> GetManifest() override;
+ bool IsSame(CefRefPtr<CefExtension> that) override;
+ CefRefPtr<CefExtensionHandler> GetHandler() override;
+ CefRefPtr<CefRequestContext> GetLoaderContext() override;
+ bool IsLoaded() override;
+ void Unload() override;
+
+ void OnExtensionLoaded();
+ void OnExtensionUnloaded();
+
+ // Use this instead of the GetLoaderContext version during
+ // CefRequestContext destruction.
+ CefRequestContext* loader_context() const { return loader_context_; }
+
+ private:
+ CefString id_;
+ CefString path_;
+ CefRefPtr<CefDictionaryValue> manifest_;
+
+ CefRequestContext* loader_context_;
+ CefRefPtr<CefExtensionHandler> handler_;
+
+ // Only accessed on the UI thread.
+ bool unloaded_ = false;
+
+ IMPLEMENT_REFCOUNTING(CefExtensionImpl);
+};
+
+#endif // CEF_LIBCEF_BROWSER_EXTENSION_IMPL_H_
diff --git a/libcef/browser/extensions/alloy_extensions_util.cc b/libcef/browser/extensions/alloy_extensions_util.cc
new file mode 100644
index 00000000..a802ab1b
--- /dev/null
+++ b/libcef/browser/extensions/alloy_extensions_util.cc
@@ -0,0 +1,21 @@
+// Copyright 2021 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#include "libcef/browser/extensions/alloy_extensions_util.h"
+
+#include "libcef/browser/alloy/alloy_browser_host_impl.h"
+
+namespace extensions {
+namespace alloy {
+
+int GetTabIdForWebContents(content::WebContents* web_contents) {
+ auto browser = AlloyBrowserHostImpl::GetBrowserForContents(web_contents);
+ if (!browser) {
+ return -1;
+ }
+ return browser->GetIdentifier();
+}
+
+} // namespace alloy
+} // namespace extensions
diff --git a/libcef/browser/extensions/alloy_extensions_util.h b/libcef/browser/extensions/alloy_extensions_util.h
new file mode 100644
index 00000000..e68c0c2e
--- /dev/null
+++ b/libcef/browser/extensions/alloy_extensions_util.h
@@ -0,0 +1,21 @@
+// Copyright 2021 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_EXTENSIONS_ALLOY_EXTENSIONS_UTIL_H_
+#define CEF_LIBCEF_BROWSER_EXTENSIONS_ALLOY_EXTENSIONS_UTIL_H_
+
+namespace content {
+class WebContents;
+}
+
+namespace extensions {
+namespace alloy {
+
+// Returns the tabId for |web_contents|, or -1 if not found.
+int GetTabIdForWebContents(content::WebContents* web_contents);
+
+} // namespace alloy
+} // namespace extensions
+
+#endif // CEF_LIBCEF_BROWSER_EXTENSIONS_ALLOY_EXTENSIONS_UTIL_H_
diff --git a/libcef/browser/extensions/api/file_system/cef_file_system_delegate.cc b/libcef/browser/extensions/api/file_system/cef_file_system_delegate.cc
new file mode 100644
index 00000000..abe577b9
--- /dev/null
+++ b/libcef/browser/extensions/api/file_system/cef_file_system_delegate.cc
@@ -0,0 +1,89 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/extensions/api/file_system/cef_file_system_delegate.h"
+
+#include "apps/saved_files_service.h"
+#include "base/files/file_path.h"
+#include "base/functional/callback.h"
+#include "chrome/browser/extensions/api/file_system/file_entry_picker.h"
+#include "chrome/grit/generated_resources.h"
+#include "content/public/browser/web_contents.h"
+#include "extensions/common/api/file_system.h"
+#include "extensions/common/extension.h"
+
+namespace extensions {
+namespace cef {
+
+CefFileSystemDelegate::CefFileSystemDelegate() = default;
+
+CefFileSystemDelegate::~CefFileSystemDelegate() = default;
+
+base::FilePath CefFileSystemDelegate::GetDefaultDirectory() {
+ return base::FilePath();
+}
+
+base::FilePath CefFileSystemDelegate::GetManagedSaveAsDirectory(
+ content::BrowserContext* browser_context,
+ const Extension& extension) {
+ return base::FilePath();
+}
+
+bool CefFileSystemDelegate::ShowSelectFileDialog(
+ scoped_refptr<ExtensionFunction> extension_function,
+ ui::SelectFileDialog::Type type,
+ const base::FilePath& default_path,
+ const ui::SelectFileDialog::FileTypeInfo* file_types,
+ FileSystemDelegate::FilesSelectedCallback files_selected_callback,
+ base::OnceClosure file_selection_canceled_callback) {
+ auto web_contents = extension_function->GetSenderWebContents();
+ if (!web_contents) {
+ return false;
+ }
+
+ // The file picker will hold a reference to the ExtensionFunction
+ // instance, preventing its destruction (and subsequent sending of the
+ // function response) until the user has selected a file or cancelled the
+ // picker. At that point, the picker will delete itself, which will also free
+ // the function instance.
+ new FileEntryPicker(web_contents, default_path, *file_types, type,
+ std::move(files_selected_callback),
+ std::move(file_selection_canceled_callback));
+ return true;
+}
+
+void CefFileSystemDelegate::ConfirmSensitiveDirectoryAccess(
+ bool has_write_permission,
+ const std::u16string& app_name,
+ content::WebContents* web_contents,
+ base::OnceClosure on_accept,
+ base::OnceClosure on_cancel) {
+ NOTIMPLEMENTED();
+
+ // Run the cancel callback by default.
+ std::move(on_cancel).Run();
+}
+
+// Based on ChromeFileSystemDelegate::GetDescriptionIdForAcceptType.
+int CefFileSystemDelegate::GetDescriptionIdForAcceptType(
+ const std::string& accept_type) {
+ if (accept_type == "image/*") {
+ return IDS_IMAGE_FILES;
+ }
+ if (accept_type == "audio/*") {
+ return IDS_AUDIO_FILES;
+ }
+ if (accept_type == "video/*") {
+ return IDS_VIDEO_FILES;
+ }
+ return 0;
+}
+
+SavedFilesServiceInterface* CefFileSystemDelegate::GetSavedFilesService(
+ content::BrowserContext* browser_context) {
+ return apps::SavedFilesService::Get(browser_context);
+}
+
+} // namespace cef
+} // namespace extensions
diff --git a/libcef/browser/extensions/api/file_system/cef_file_system_delegate.h b/libcef/browser/extensions/api/file_system/cef_file_system_delegate.h
new file mode 100644
index 00000000..bfcb0203
--- /dev/null
+++ b/libcef/browser/extensions/api/file_system/cef_file_system_delegate.h
@@ -0,0 +1,58 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_EXTENSIONS_API_FILE_SYSTEM_FILE_SYSTEM_DELEGATE_H_
+#define CEF_LIBCEF_BROWSER_EXTENSIONS_API_FILE_SYSTEM_FILE_SYSTEM_DELEGATE_H_
+
+#include <memory>
+
+#include "base/compiler_specific.h"
+#include "base/functional/callback.h"
+#include "base/memory/ref_counted.h"
+#include "extensions/browser/api/execute_code_function.h"
+#include "extensions/browser/api/file_system/file_system_delegate.h"
+#include "extensions/browser/extension_function.h"
+
+namespace content {
+class WebContents;
+}
+
+namespace extensions {
+namespace cef {
+
+class CefFileSystemDelegate : public FileSystemDelegate {
+ public:
+ CefFileSystemDelegate();
+
+ CefFileSystemDelegate(const CefFileSystemDelegate&) = delete;
+ CefFileSystemDelegate& operator=(const CefFileSystemDelegate&) = delete;
+
+ ~CefFileSystemDelegate() override;
+
+ // FileSystemDelegate
+ base::FilePath GetDefaultDirectory() override;
+ base::FilePath GetManagedSaveAsDirectory(
+ content::BrowserContext* browser_context,
+ const Extension& extension) override;
+ bool ShowSelectFileDialog(
+ scoped_refptr<ExtensionFunction> extension_function,
+ ui::SelectFileDialog::Type type,
+ const base::FilePath& default_path,
+ const ui::SelectFileDialog::FileTypeInfo* file_types,
+ FileSystemDelegate::FilesSelectedCallback files_selected_callback,
+ base::OnceClosure file_selection_canceled_callback) override;
+ void ConfirmSensitiveDirectoryAccess(bool has_write_permission,
+ const std::u16string& app_name,
+ content::WebContents* web_contents,
+ base::OnceClosure on_accept,
+ base::OnceClosure on_cancel) override;
+ int GetDescriptionIdForAcceptType(const std::string& accept_type) override;
+ SavedFilesServiceInterface* GetSavedFilesService(
+ content::BrowserContext* browser_context) override;
+};
+
+} // namespace cef
+} // namespace extensions
+
+#endif // CEF_LIBCEF_BROWSER_EXTENSIONS_API_FILE_SYSTEM_FILE_SYSTEM_DELEGATE_H_
diff --git a/libcef/browser/extensions/api/storage/sync_value_store_cache.cc b/libcef/browser/extensions/api/storage/sync_value_store_cache.cc
new file mode 100644
index 00000000..5dff6f61
--- /dev/null
+++ b/libcef/browser/extensions/api/storage/sync_value_store_cache.cc
@@ -0,0 +1,105 @@
+// Copyright 2017 The Chromium Embedded Framework Authors.
+// Portions copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/extensions/api/storage/sync_value_store_cache.h"
+
+#include <stddef.h>
+
+#include <limits>
+#include <utility>
+
+#include "components/value_store/value_store_factory.h"
+#include "content/public/browser/browser_thread.h"
+#include "extensions/browser/api/storage/backend_task_runner.h"
+#include "extensions/browser/api/storage/value_store_util.h"
+#include "extensions/browser/api/storage/weak_unlimited_settings_storage.h"
+#include "extensions/common/api/storage.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/permissions/permissions_data.h"
+
+using content::BrowserThread;
+
+namespace extensions {
+
+namespace cef {
+
+namespace {
+
+// Returns the quota limit for local storage, taken from the schema in
+// extensions/common/api/storage.json.
+SettingsStorageQuotaEnforcer::Limits GetLocalQuotaLimits() {
+ SettingsStorageQuotaEnforcer::Limits limits = {
+ static_cast<size_t>(api::storage::local::QUOTA_BYTES),
+ std::numeric_limits<size_t>::max(), std::numeric_limits<size_t>::max()};
+ return limits;
+}
+
+} // namespace
+
+SyncValueStoreCache::SyncValueStoreCache(
+ scoped_refptr<value_store::ValueStoreFactory> factory)
+ : storage_factory_(std::move(factory)), quota_(GetLocalQuotaLimits()) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+}
+
+SyncValueStoreCache::~SyncValueStoreCache() {
+ DCHECK(IsOnBackendSequence());
+}
+
+void SyncValueStoreCache::RunWithValueStoreForExtension(
+ StorageCallback callback,
+ scoped_refptr<const Extension> extension) {
+ DCHECK(IsOnBackendSequence());
+
+ value_store::ValueStore* storage = GetStorage(extension.get());
+
+ // A neat way to implement unlimited storage; if the extension has the
+ // unlimited storage permission, force through all calls to Set().
+ if (extension->permissions_data()->HasAPIPermission(
+ mojom::APIPermissionID::kUnlimitedStorage)) {
+ WeakUnlimitedSettingsStorage unlimited_storage(storage);
+ std::move(callback).Run(&unlimited_storage);
+ } else {
+ std::move(callback).Run(storage);
+ }
+}
+
+void SyncValueStoreCache::DeleteStorageSoon(const std::string& extension_id) {
+ DCHECK(IsOnBackendSequence());
+ storage_map_.erase(extension_id);
+
+ value_store_util::DeleteValueStore(settings_namespace::SYNC,
+ value_store_util::ModelType::APP,
+ extension_id, storage_factory_);
+
+ value_store_util::DeleteValueStore(settings_namespace::SYNC,
+ value_store_util::ModelType::EXTENSION,
+ extension_id, storage_factory_);
+}
+
+value_store::ValueStore* SyncValueStoreCache::GetStorage(
+ const Extension* extension) {
+ auto iter = storage_map_.find(extension->id());
+ if (iter != storage_map_.end()) {
+ return iter->second.get();
+ }
+
+ value_store_util::ModelType model_type =
+ extension->is_app() ? value_store_util::ModelType::APP
+ : value_store_util::ModelType::EXTENSION;
+ std::unique_ptr<value_store::ValueStore> store =
+ value_store_util::CreateSettingsStore(settings_namespace::LOCAL,
+ model_type, extension->id(),
+ storage_factory_);
+ std::unique_ptr<SettingsStorageQuotaEnforcer> storage(
+ new SettingsStorageQuotaEnforcer(quota_, std::move(store)));
+ DCHECK(storage.get());
+
+ value_store::ValueStore* storage_ptr = storage.get();
+ storage_map_[extension->id()] = std::move(storage);
+ return storage_ptr;
+}
+} // namespace cef
+} // namespace extensions
diff --git a/libcef/browser/extensions/api/storage/sync_value_store_cache.h b/libcef/browser/extensions/api/storage/sync_value_store_cache.h
new file mode 100644
index 00000000..626c182f
--- /dev/null
+++ b/libcef/browser/extensions/api/storage/sync_value_store_cache.h
@@ -0,0 +1,60 @@
+// Copyright 2017 The Chromium Embedded Framework Authors.
+// Portions copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_EXTENSIONS_API_STORAGE_SYNC_VALUE_STORE_CACHE_H_
+#define CEF_LIBCEF_BROWSER_EXTENSIONS_API_STORAGE_SYNC_VALUE_STORE_CACHE_H_
+
+#include <memory>
+
+#include "base/memory/ref_counted.h"
+#include "extensions/browser/api/storage/settings_storage_quota_enforcer.h"
+#include "extensions/browser/api/storage/value_store_cache.h"
+
+namespace value_store {
+class ValueStoreFactory;
+}
+
+namespace extensions {
+namespace cef {
+
+// Based on LocalValueStoreCache
+// ValueStoreCache for the SYNC namespace. It owns a backend for apps and
+// another for extensions. Each backend takes care of persistence.
+class SyncValueStoreCache : public ValueStoreCache {
+ public:
+ explicit SyncValueStoreCache(
+ scoped_refptr<value_store::ValueStoreFactory> factory);
+
+ SyncValueStoreCache(const SyncValueStoreCache&) = delete;
+ SyncValueStoreCache& operator=(const SyncValueStoreCache&) = delete;
+
+ ~SyncValueStoreCache() override;
+
+ // ValueStoreCache implementation:
+ void RunWithValueStoreForExtension(
+ StorageCallback callback,
+ scoped_refptr<const Extension> extension) override;
+ void DeleteStorageSoon(const std::string& extension_id) override;
+
+ private:
+ using StorageMap =
+ std::map<std::string, std::unique_ptr<value_store::ValueStore>>;
+
+ value_store::ValueStore* GetStorage(const Extension* extension);
+
+ // The Factory to use for creating new ValueStores.
+ const scoped_refptr<value_store::ValueStoreFactory> storage_factory_;
+
+ // Quota limits (see SettingsStorageQuotaEnforcer).
+ const SettingsStorageQuotaEnforcer::Limits quota_;
+
+ // The collection of ValueStores for local storage.
+ StorageMap storage_map_;
+};
+
+} // namespace cef
+} // namespace extensions
+
+#endif // CEF_LIBCEF_BROWSER_EXTENSIONS_API_STORAGE_SYNC_VALUE_STORE_CACHE_H_
diff --git a/libcef/browser/extensions/api/tabs/tabs_api.cc b/libcef/browser/extensions/api/tabs/tabs_api.cc
new file mode 100644
index 00000000..3fc19ef2
--- /dev/null
+++ b/libcef/browser/extensions/api/tabs/tabs_api.cc
@@ -0,0 +1,544 @@
+// Copyright 2017 The Chromium Embedded Framework Authors. Portions copyright
+// 2012 The Chromium Authors. All rights reserved. Use of this source code is
+// governed by a BSD-style license that can be found in the LICENSE file.
+
+#include "libcef/browser/extensions/api/tabs/tabs_api.h"
+
+#include "libcef/browser/extensions/extension_web_contents_observer.h"
+
+#include "base/notreached.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "chrome/browser/extensions/api/tabs/tabs_constants.h"
+#include "chrome/browser/extensions/extension_tab_util.h"
+#include "components/zoom/zoom_controller.h"
+#include "content/public/browser/navigation_controller.h"
+#include "content/public/browser/navigation_entry.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/site_instance.h"
+#include "extensions/browser/extension_api_frame_id_map.h"
+#include "extensions/browser/extension_zoom_request_client.h"
+#include "extensions/common/error_utils.h"
+#include "extensions/common/manifest_constants.h"
+#include "extensions/common/permissions/permissions_data.h"
+#include "third_party/blink/public/common/page/page_zoom.h"
+
+using zoom::ZoomController;
+
+namespace extensions {
+namespace cef {
+
+namespace keys = extensions::tabs_constants;
+namespace tabs = api::tabs;
+
+using api::extension_types::InjectDetails;
+
+namespace {
+
+const char kNotImplementedError[] = "Not implemented";
+
+void ZoomModeToZoomSettings(zoom::ZoomController::ZoomMode zoom_mode,
+ api::tabs::ZoomSettings* zoom_settings) {
+ DCHECK(zoom_settings);
+ switch (zoom_mode) {
+ case zoom::ZoomController::ZOOM_MODE_DEFAULT:
+ zoom_settings->mode = api::tabs::ZOOM_SETTINGS_MODE_AUTOMATIC;
+ zoom_settings->scope = api::tabs::ZOOM_SETTINGS_SCOPE_PER_ORIGIN;
+ break;
+ case zoom::ZoomController::ZOOM_MODE_ISOLATED:
+ zoom_settings->mode = api::tabs::ZOOM_SETTINGS_MODE_AUTOMATIC;
+ zoom_settings->scope = api::tabs::ZOOM_SETTINGS_SCOPE_PER_TAB;
+ break;
+ case zoom::ZoomController::ZOOM_MODE_MANUAL:
+ zoom_settings->mode = api::tabs::ZOOM_SETTINGS_MODE_MANUAL;
+ zoom_settings->scope = api::tabs::ZOOM_SETTINGS_SCOPE_PER_TAB;
+ break;
+ case zoom::ZoomController::ZOOM_MODE_DISABLED:
+ zoom_settings->mode = api::tabs::ZOOM_SETTINGS_MODE_DISABLED;
+ zoom_settings->scope = api::tabs::ZOOM_SETTINGS_SCOPE_PER_TAB;
+ break;
+ }
+}
+
+} // namespace
+
+ExtensionFunction::ResponseAction TabsGetFunction::Run() {
+ return RespondNow(Error(kNotImplementedError));
+}
+
+TabsCreateFunction::TabsCreateFunction() : cef_details_(this) {}
+
+ExtensionFunction::ResponseAction TabsCreateFunction::Run() {
+ std::unique_ptr<tabs::Create::Params> params(
+ tabs::Create::Params::Create(args()));
+ EXTENSION_FUNCTION_VALIDATE(params.get());
+
+ CefExtensionFunctionDetails::OpenTabParams options;
+ options.window_id = params->create_properties.window_id;
+ options.opener_tab_id = params->create_properties.opener_tab_id;
+ options.active = params->create_properties.selected;
+ // The 'active' property has replaced the 'selected' property.
+ options.active = params->create_properties.active;
+ options.pinned = params->create_properties.pinned;
+ options.index = params->create_properties.index;
+ options.url = params->create_properties.url;
+
+ std::string error;
+ auto result = cef_details_.OpenTab(options, user_gesture(), &error);
+ if (!result) {
+ return RespondNow(Error(error));
+ }
+
+ // Return data about the newly created tab.
+ return RespondNow(has_callback() ? OneArgument(base::Value(result->ToValue()))
+ : NoArguments());
+}
+
+BaseAPIFunction::BaseAPIFunction() : cef_details_(this) {}
+
+content::WebContents* BaseAPIFunction::GetWebContents(int tab_id) {
+ // Find a browser that we can access, or set |error_| and return nullptr.
+ CefRefPtr<AlloyBrowserHostImpl> browser =
+ cef_details_.GetBrowserForTabIdFirstTime(tab_id, &error_);
+ if (!browser) {
+ return nullptr;
+ }
+
+ return browser->web_contents();
+}
+
+ExtensionFunction::ResponseAction TabsUpdateFunction::Run() {
+ std::unique_ptr<tabs::Update::Params> params(
+ tabs::Update::Params::Create(args()));
+ EXTENSION_FUNCTION_VALIDATE(params.get());
+
+ tab_id_ = params->tab_id ? *params->tab_id : -1;
+ content::WebContents* web_contents = GetWebContents(tab_id_);
+ if (!web_contents) {
+ return RespondNow(Error(std::move(error_)));
+ }
+
+ web_contents_ = web_contents;
+
+ // TODO(rafaelw): handle setting remaining tab properties:
+ // -title
+ // -favIconUrl
+
+ // Navigate the tab to a new location if the url is different.
+ if (params->update_properties.url.has_value()) {
+ std::string updated_url = *params->update_properties.url;
+ if (!UpdateURL(updated_url, tab_id_, &error_)) {
+ return RespondNow(Error(std::move(error_)));
+ }
+ }
+
+ bool active = false;
+ // TODO(rafaelw): Setting |active| from js doesn't make much sense.
+ // Move tab selection management up to window.
+ if (params->update_properties.selected.has_value()) {
+ active = *params->update_properties.selected;
+ }
+
+ // The 'active' property has replaced 'selected'.
+ if (params->update_properties.active.has_value()) {
+ active = *params->update_properties.active;
+ }
+
+ if (active) {
+ // TODO: Activate the tab at |tab_id_|.
+ NOTIMPLEMENTED();
+ return RespondNow(Error(tabs_constants::kTabStripNotEditableError));
+ }
+
+ if (params->update_properties.highlighted.has_value() &&
+ *params->update_properties.highlighted) {
+ // TODO: Highlight the tab at |tab_id_|.
+ NOTIMPLEMENTED();
+ return RespondNow(Error(tabs_constants::kTabStripNotEditableError));
+ }
+
+ if (params->update_properties.pinned.has_value() &&
+ *params->update_properties.pinned) {
+ // TODO: Pin the tab at |tab_id_|.
+ NOTIMPLEMENTED();
+ return RespondNow(Error(tabs_constants::kTabStripNotEditableError));
+ }
+
+ if (params->update_properties.muted.has_value()) {
+ // TODO: Mute/unmute the tab at |tab_id_|.
+ NOTIMPLEMENTED();
+ return RespondNow(Error(ErrorUtils::FormatErrorMessage(
+ tabs_constants::kCannotUpdateMuteCaptured,
+ base::NumberToString(tab_id_))));
+ }
+
+ if (params->update_properties.opener_tab_id.has_value()) {
+ int opener_id = *params->update_properties.opener_tab_id;
+ if (opener_id == tab_id_) {
+ return RespondNow(Error("Cannot set a tab's opener to itself."));
+ }
+
+ // TODO: Set the opener for the tab at |tab_id_|.
+ NOTIMPLEMENTED();
+ return RespondNow(Error(tabs_constants::kTabStripNotEditableError));
+ }
+
+ if (params->update_properties.auto_discardable.has_value()) {
+ // TODO: Set auto-discardable state for the tab at |tab_id_|.
+ NOTIMPLEMENTED();
+ }
+
+ return RespondNow(GetResult());
+}
+
+bool TabsUpdateFunction::UpdateURL(const std::string& url_string,
+ int tab_id,
+ std::string* error) {
+ GURL url;
+ if (!ExtensionTabUtil::PrepareURLForNavigation(url_string, extension(), &url,
+ error)) {
+ return false;
+ }
+
+ const bool is_javascript_scheme = url.SchemeIs(url::kJavaScriptScheme);
+ // JavaScript URLs are forbidden in chrome.tabs.update().
+ if (is_javascript_scheme) {
+ *error = tabs_constants::kJavaScriptUrlsNotAllowedInTabsUpdate;
+ return false;
+ }
+
+ content::NavigationController::LoadURLParams load_params(url);
+
+ // Treat extension-initiated navigations as renderer-initiated so that the URL
+ // does not show in the omnibox until it commits. This avoids URL spoofs
+ // since URLs can be opened on behalf of untrusted content.
+ load_params.is_renderer_initiated = true;
+ // All renderer-initiated navigations need to have an initiator origin.
+ load_params.initiator_origin = extension()->origin();
+ // |source_site_instance| needs to be set so that a renderer process
+ // compatible with |initiator_origin| is picked by Site Isolation.
+ load_params.source_site_instance = content::SiteInstance::CreateForURL(
+ web_contents_->GetBrowserContext(),
+ load_params.initiator_origin->GetURL());
+
+ // Marking the navigation as initiated via an API means that the focus
+ // will stay in the omnibox - see https://crbug.com/1085779.
+ load_params.transition_type = ui::PAGE_TRANSITION_FROM_API;
+
+ web_contents_->GetController().LoadURLWithParams(load_params);
+
+ DCHECK_EQ(url,
+ web_contents_->GetController().GetPendingEntry()->GetVirtualURL());
+
+ return true;
+}
+
+ExtensionFunction::ResponseValue TabsUpdateFunction::GetResult() {
+ if (!has_callback()) {
+ return NoArguments();
+ }
+
+ return ArgumentList(tabs::Get::Results::Create(cef_details_.CreateTabObject(
+ AlloyBrowserHostImpl::GetBrowserForContents(web_contents_),
+ /*opener_browser_id=*/-1, /*active=*/true, tab_id_)));
+}
+
+ExecuteCodeInTabFunction::ExecuteCodeInTabFunction()
+ : cef_details_(this), execute_tab_id_(-1) {}
+
+ExecuteCodeInTabFunction::~ExecuteCodeInTabFunction() {}
+
+ExecuteCodeFunction::InitResult ExecuteCodeInTabFunction::Init() {
+ if (init_result_) {
+ return init_result_.value();
+ }
+
+ if (args().size() < 2) {
+ return set_init_result(VALIDATION_FAILURE);
+ }
+
+ const auto& tab_id_value = args()[0];
+ // |tab_id| is optional so it's ok if it's not there.
+ int tab_id = -1;
+ if (tab_id_value.is_int()) {
+ // But if it is present, it needs to be non-negative.
+ tab_id = tab_id_value.GetInt();
+ if (tab_id < 0) {
+ return set_init_result(VALIDATION_FAILURE);
+ }
+ }
+
+ // |details| are not optional.
+ const base::Value& details_value = args()[1];
+ if (!details_value.is_dict()) {
+ return set_init_result(VALIDATION_FAILURE);
+ }
+ std::unique_ptr<InjectDetails> details(new InjectDetails());
+ if (!InjectDetails::Populate(details_value, details.get())) {
+ return set_init_result(VALIDATION_FAILURE);
+ }
+
+ // Find a browser that we can access, or fail with error.
+ std::string error;
+ CefRefPtr<AlloyBrowserHostImpl> browser =
+ cef_details_.GetBrowserForTabIdFirstTime(tab_id, &error);
+ if (!browser) {
+ return set_init_result_error(error);
+ }
+
+ execute_tab_id_ = browser->GetIdentifier();
+ details_ = std::move(details);
+ set_host_id(
+ mojom::HostID(mojom::HostID::HostType::kExtensions, extension()->id()));
+ return set_init_result(SUCCESS);
+}
+
+bool ExecuteCodeInTabFunction::ShouldInsertCSS() const {
+ return false;
+}
+
+bool ExecuteCodeInTabFunction::ShouldRemoveCSS() const {
+ return false;
+}
+
+bool ExecuteCodeInTabFunction::CanExecuteScriptOnPage(std::string* error) {
+ CHECK_GE(execute_tab_id_, 0);
+
+ CefRefPtr<AlloyBrowserHostImpl> browser =
+ cef_details_.GetBrowserForTabIdAgain(execute_tab_id_, error);
+ if (!browser) {
+ return false;
+ }
+
+ int frame_id = details_->frame_id ? *details_->frame_id
+ : ExtensionApiFrameIdMap::kTopFrameId;
+ content::RenderFrameHost* rfh =
+ ExtensionApiFrameIdMap::GetRenderFrameHostById(browser->web_contents(),
+ frame_id);
+ if (!rfh) {
+ *error = ErrorUtils::FormatErrorMessage(
+ keys::kFrameNotFoundError, base::NumberToString(frame_id),
+ base::NumberToString(execute_tab_id_));
+ return false;
+ }
+
+ // Content scripts declared in manifest.json can access frames at about:-URLs
+ // if the extension has permission to access the frame's origin, so also allow
+ // programmatic content scripts at about:-URLs for allowed origins.
+ GURL effective_document_url(rfh->GetLastCommittedURL());
+ bool is_about_url = effective_document_url.SchemeIs(url::kAboutScheme);
+ if (is_about_url && details_->match_about_blank &&
+ *details_->match_about_blank) {
+ effective_document_url = GURL(rfh->GetLastCommittedOrigin().Serialize());
+ }
+
+ if (!effective_document_url.is_valid()) {
+ // Unknown URL, e.g. because no load was committed yet. Allow for now, the
+ // renderer will check again and fail the injection if needed.
+ return true;
+ }
+
+ // NOTE: This can give the wrong answer due to race conditions, but it is OK,
+ // we check again in the renderer.
+ if (!extension()->permissions_data()->CanAccessPage(effective_document_url,
+ execute_tab_id_, error)) {
+ if (is_about_url &&
+ extension()->permissions_data()->active_permissions().HasAPIPermission(
+ mojom::APIPermissionID::kTab)) {
+ *error = ErrorUtils::FormatErrorMessage(
+ manifest_errors::kCannotAccessAboutUrl,
+ rfh->GetLastCommittedURL().spec(),
+ rfh->GetLastCommittedOrigin().Serialize());
+ }
+ return false;
+ }
+
+ return true;
+}
+
+ScriptExecutor* ExecuteCodeInTabFunction::GetScriptExecutor(
+ std::string* error) {
+ CHECK_GE(execute_tab_id_, 0);
+
+ CefRefPtr<AlloyBrowserHostImpl> browser =
+ cef_details_.GetBrowserForTabIdAgain(execute_tab_id_, error);
+ if (!browser) {
+ return nullptr;
+ }
+
+ return CefExtensionWebContentsObserver::FromWebContents(
+ browser->web_contents())
+ ->script_executor();
+}
+
+bool ExecuteCodeInTabFunction::IsWebView() const {
+ return false;
+}
+
+const GURL& ExecuteCodeInTabFunction::GetWebViewSrc() const {
+ return GURL::EmptyGURL();
+}
+
+bool ExecuteCodeInTabFunction::LoadFile(const std::string& file,
+ std::string* error) {
+ if (cef_details_.LoadFile(
+ file, base::BindOnce(&ExecuteCodeInTabFunction::LoadFileComplete,
+ this, file))) {
+ return true;
+ }
+
+ // Default handling.
+ return ExecuteCodeFunction::LoadFile(file, error);
+}
+
+void ExecuteCodeInTabFunction::LoadFileComplete(
+ const std::string& file,
+ std::unique_ptr<std::string> data) {
+ std::vector<std::unique_ptr<std::string>> data_list;
+ absl::optional<std::string> error;
+ const bool success = !!data.get();
+ if (success) {
+ DCHECK(data);
+ data_list.push_back(std::move(data));
+ } else {
+ error = base::StringPrintf("Failed to load file '%s'.", file.c_str());
+ }
+ DidLoadAndLocalizeFile(file, std::move(data_list), std::move(error));
+}
+
+bool TabsInsertCSSFunction::ShouldInsertCSS() const {
+ return true;
+}
+
+bool TabsRemoveCSSFunction::ShouldRemoveCSS() const {
+ return true;
+}
+
+ExtensionFunction::ResponseAction TabsSetZoomFunction::Run() {
+ std::unique_ptr<tabs::SetZoom::Params> params(
+ tabs::SetZoom::Params::Create(args()));
+ EXTENSION_FUNCTION_VALIDATE(params);
+
+ int tab_id = params->tab_id ? *params->tab_id : -1;
+ content::WebContents* web_contents = GetWebContents(tab_id);
+ if (!web_contents) {
+ return RespondNow(Error(std::move(error_)));
+ }
+
+ GURL url(web_contents->GetVisibleURL());
+ if (extension()->permissions_data()->IsRestrictedUrl(url, &error_)) {
+ return RespondNow(Error(std::move(error_)));
+ }
+
+ ZoomController* zoom_controller =
+ ZoomController::FromWebContents(web_contents);
+ double zoom_level =
+ params->zoom_factor > 0
+ ? blink::PageZoomFactorToZoomLevel(params->zoom_factor)
+ : zoom_controller->GetDefaultZoomLevel();
+
+ auto client = base::MakeRefCounted<ExtensionZoomRequestClient>(extension());
+ if (!zoom_controller->SetZoomLevelByClient(zoom_level, client)) {
+ // Tried to zoom a tab in disabled mode.
+ return RespondNow(Error(tabs_constants::kCannotZoomDisabledTabError));
+ }
+
+ return RespondNow(NoArguments());
+}
+
+ExtensionFunction::ResponseAction TabsGetZoomFunction::Run() {
+ std::unique_ptr<tabs::GetZoom::Params> params(
+ tabs::GetZoom::Params::Create(args()));
+ EXTENSION_FUNCTION_VALIDATE(params);
+
+ int tab_id = params->tab_id ? *params->tab_id : -1;
+ content::WebContents* web_contents = GetWebContents(tab_id);
+ if (!web_contents) {
+ return RespondNow(Error(std::move(error_)));
+ }
+
+ double zoom_level =
+ zoom::ZoomController::FromWebContents(web_contents)->GetZoomLevel();
+ double zoom_factor = blink::PageZoomLevelToZoomFactor(zoom_level);
+
+ return RespondNow(ArgumentList(tabs::GetZoom::Results::Create(zoom_factor)));
+}
+
+ExtensionFunction::ResponseAction TabsSetZoomSettingsFunction::Run() {
+ using api::tabs::ZoomSettings;
+
+ std::unique_ptr<tabs::SetZoomSettings::Params> params(
+ tabs::SetZoomSettings::Params::Create(args()));
+ EXTENSION_FUNCTION_VALIDATE(params);
+
+ int tab_id = params->tab_id ? *params->tab_id : -1;
+ content::WebContents* web_contents = GetWebContents(tab_id);
+ if (!web_contents) {
+ return RespondNow(Error(std::move(error_)));
+ }
+
+ GURL url(web_contents->GetVisibleURL());
+ std::string error;
+ if (extension()->permissions_data()->IsRestrictedUrl(url, &error_)) {
+ return RespondNow(Error(std::move(error_)));
+ }
+
+ // "per-origin" scope is only available in "automatic" mode.
+ if (params->zoom_settings.scope == tabs::ZOOM_SETTINGS_SCOPE_PER_ORIGIN &&
+ params->zoom_settings.mode != tabs::ZOOM_SETTINGS_MODE_AUTOMATIC &&
+ params->zoom_settings.mode != tabs::ZOOM_SETTINGS_MODE_NONE) {
+ return RespondNow(Error(tabs_constants::kPerOriginOnlyInAutomaticError));
+ }
+
+ // Determine the correct internal zoom mode to set |web_contents| to from the
+ // user-specified |zoom_settings|.
+ ZoomController::ZoomMode zoom_mode = ZoomController::ZOOM_MODE_DEFAULT;
+ switch (params->zoom_settings.mode) {
+ case tabs::ZOOM_SETTINGS_MODE_NONE:
+ case tabs::ZOOM_SETTINGS_MODE_AUTOMATIC:
+ switch (params->zoom_settings.scope) {
+ case tabs::ZOOM_SETTINGS_SCOPE_NONE:
+ case tabs::ZOOM_SETTINGS_SCOPE_PER_ORIGIN:
+ zoom_mode = ZoomController::ZOOM_MODE_DEFAULT;
+ break;
+ case tabs::ZOOM_SETTINGS_SCOPE_PER_TAB:
+ zoom_mode = ZoomController::ZOOM_MODE_ISOLATED;
+ }
+ break;
+ case tabs::ZOOM_SETTINGS_MODE_MANUAL:
+ zoom_mode = ZoomController::ZOOM_MODE_MANUAL;
+ break;
+ case tabs::ZOOM_SETTINGS_MODE_DISABLED:
+ zoom_mode = ZoomController::ZOOM_MODE_DISABLED;
+ }
+
+ ZoomController::FromWebContents(web_contents)->SetZoomMode(zoom_mode);
+
+ return RespondNow(NoArguments());
+}
+
+ExtensionFunction::ResponseAction TabsGetZoomSettingsFunction::Run() {
+ std::unique_ptr<tabs::GetZoomSettings::Params> params(
+ tabs::GetZoomSettings::Params::Create(args()));
+ EXTENSION_FUNCTION_VALIDATE(params);
+
+ int tab_id = params->tab_id ? *params->tab_id : -1;
+ content::WebContents* web_contents = GetWebContents(tab_id);
+ if (!web_contents) {
+ return RespondNow(Error(std::move(error_)));
+ }
+ ZoomController* zoom_controller =
+ ZoomController::FromWebContents(web_contents);
+
+ ZoomController::ZoomMode zoom_mode = zoom_controller->zoom_mode();
+ api::tabs::ZoomSettings zoom_settings;
+ ZoomModeToZoomSettings(zoom_mode, &zoom_settings);
+ zoom_settings.default_zoom_factor =
+ blink::PageZoomLevelToZoomFactor(zoom_controller->GetDefaultZoomLevel());
+
+ return RespondNow(
+ ArgumentList(api::tabs::GetZoomSettings::Results::Create(zoom_settings)));
+}
+
+} // namespace cef
+} // namespace extensions
diff --git a/libcef/browser/extensions/api/tabs/tabs_api.h b/libcef/browser/extensions/api/tabs/tabs_api.h
new file mode 100644
index 00000000..409d758d
--- /dev/null
+++ b/libcef/browser/extensions/api/tabs/tabs_api.h
@@ -0,0 +1,187 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_EXTENSIONS_API_TABS_TABS_API_H_
+#define CEF_LIBCEF_BROWSER_EXTENSIONS_API_TABS_TABS_API_H_
+
+#include "libcef/browser/extensions/extension_function_details.h"
+
+#include "chrome/common/extensions/api/tabs.h"
+#include "extensions/browser/api/execute_code_function.h"
+#include "extensions/browser/extension_function.h"
+
+// The contents of this file are extracted from
+// chrome/browser/extensions/api/tabs/tabs_api.h.
+
+namespace content {
+class WebContents;
+}
+
+namespace extensions {
+namespace cef {
+
+class TabsGetFunction : public ExtensionFunction {
+ ~TabsGetFunction() override {}
+
+ ResponseAction Run() override;
+
+ DECLARE_EXTENSION_FUNCTION("tabs.get", TABS_GET)
+};
+
+class TabsCreateFunction : public ExtensionFunction {
+ public:
+ TabsCreateFunction();
+ ~TabsCreateFunction() override {}
+
+ ResponseAction Run() override;
+
+ DECLARE_EXTENSION_FUNCTION("tabs.create", TABS_CREATE)
+
+ private:
+ const CefExtensionFunctionDetails cef_details_;
+};
+
+class BaseAPIFunction : public ExtensionFunction {
+ public:
+ BaseAPIFunction();
+
+ protected:
+ ~BaseAPIFunction() override {}
+
+ // Gets the WebContents for |tab_id| if it is specified. Otherwise get the
+ // WebContents for the active tab in the current window. Calling this function
+ // may set |error_|.
+ content::WebContents* GetWebContents(int tab_id);
+
+ std::string error_;
+ const CefExtensionFunctionDetails cef_details_;
+};
+
+class TabsUpdateFunction : public BaseAPIFunction {
+ private:
+ ~TabsUpdateFunction() override {}
+
+ ResponseAction Run() override;
+
+ bool UpdateURL(const std::string& url, int tab_id, std::string* error);
+ ResponseValue GetResult();
+
+ DECLARE_EXTENSION_FUNCTION("tabs.update", TABS_UPDATE)
+
+ int tab_id_ = -1;
+ content::WebContents* web_contents_ = nullptr;
+};
+
+// Implement API calls tabs.executeScript, tabs.insertCSS, and tabs.removeCSS.
+class ExecuteCodeInTabFunction : public ExecuteCodeFunction {
+ public:
+ ExecuteCodeInTabFunction();
+
+ protected:
+ ~ExecuteCodeInTabFunction() override;
+
+ // Initializes |execute_tab_id_| and |details_|.
+ InitResult Init() override;
+ bool ShouldInsertCSS() const override;
+ bool ShouldRemoveCSS() const override;
+ bool CanExecuteScriptOnPage(std::string* error) override;
+ ScriptExecutor* GetScriptExecutor(std::string* error) override;
+ bool IsWebView() const override;
+ const GURL& GetWebViewSrc() const override;
+ bool LoadFile(const std::string& file, std::string* error) override;
+
+ private:
+ const CefExtensionFunctionDetails cef_details_;
+
+ void LoadFileComplete(const std::string& file,
+ std::unique_ptr<std::string> data);
+
+ // Id of tab which executes code.
+ int execute_tab_id_;
+};
+
+class TabsExecuteScriptFunction : public ExecuteCodeInTabFunction {
+ private:
+ ~TabsExecuteScriptFunction() override {}
+
+ DECLARE_EXTENSION_FUNCTION("tabs.executeScript", TABS_EXECUTESCRIPT)
+};
+
+class TabsInsertCSSFunction : public ExecuteCodeInTabFunction {
+ private:
+ ~TabsInsertCSSFunction() override {}
+
+ bool ShouldInsertCSS() const override;
+
+ DECLARE_EXTENSION_FUNCTION("tabs.insertCSS", TABS_INSERTCSS)
+};
+
+class TabsRemoveCSSFunction : public ExecuteCodeInTabFunction {
+ private:
+ ~TabsRemoveCSSFunction() override {}
+
+ bool ShouldRemoveCSS() const override;
+
+ DECLARE_EXTENSION_FUNCTION("tabs.removeCSS", TABS_INSERTCSS)
+};
+
+// Based on ChromeAsyncExtensionFunction.
+class ZoomAPIFunction : public ExtensionFunction {
+ public:
+ ZoomAPIFunction();
+
+ protected:
+ ~ZoomAPIFunction() override {}
+
+ // Gets the WebContents for |tab_id| if it is specified. Otherwise get the
+ // WebContents for the active tab in the current window. Calling this function
+ // may set |error_|.
+ content::WebContents* GetWebContents(int tab_id);
+
+ std::string error_;
+
+ private:
+ const CefExtensionFunctionDetails cef_details_;
+};
+
+class TabsSetZoomFunction : public BaseAPIFunction {
+ private:
+ ~TabsSetZoomFunction() override {}
+
+ ResponseAction Run() override;
+
+ DECLARE_EXTENSION_FUNCTION("tabs.setZoom", TABS_SETZOOM)
+};
+
+class TabsGetZoomFunction : public BaseAPIFunction {
+ private:
+ ~TabsGetZoomFunction() override {}
+
+ ResponseAction Run() override;
+
+ DECLARE_EXTENSION_FUNCTION("tabs.getZoom", TABS_GETZOOM)
+};
+
+class TabsSetZoomSettingsFunction : public BaseAPIFunction {
+ private:
+ ~TabsSetZoomSettingsFunction() override {}
+
+ ResponseAction Run() override;
+
+ DECLARE_EXTENSION_FUNCTION("tabs.setZoomSettings", TABS_SETZOOMSETTINGS)
+};
+
+class TabsGetZoomSettingsFunction : public BaseAPIFunction {
+ private:
+ ~TabsGetZoomSettingsFunction() override {}
+
+ ResponseAction Run() override;
+
+ DECLARE_EXTENSION_FUNCTION("tabs.getZoomSettings", TABS_GETZOOMSETTINGS)
+};
+
+} // namespace cef
+} // namespace extensions
+
+#endif // CEF_LIBCEF_BROWSER_EXTENSIONS_API_TABS_TABS_API_H_
diff --git a/libcef/browser/extensions/browser_extensions_util.cc b/libcef/browser/extensions/browser_extensions_util.cc
new file mode 100644
index 00000000..9a780e22
--- /dev/null
+++ b/libcef/browser/extensions/browser_extensions_util.cc
@@ -0,0 +1,180 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "libcef/browser/extensions/browser_extensions_util.h"
+
+#include "libcef/browser/alloy/alloy_browser_host_impl.h"
+#include "libcef/browser/browser_context.h"
+#include "libcef/browser/browser_host_base.h"
+#include "libcef/browser/browser_info_manager.h"
+#include "libcef/browser/thread_util.h"
+#include "libcef/common/extensions/extensions_util.h"
+#include "libcef/common/frame_util.h"
+#include "libcef/features/runtime_checks.h"
+
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/printing/print_preview_dialog_controller.h"
+#include "content/browser/browser_plugin/browser_plugin_guest.h"
+#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/browser_plugin_guest_manager.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_view_host.h"
+#include "extensions/browser/extension_registry.h"
+
+namespace extensions {
+
+namespace {
+
+bool InsertWebContents(std::vector<content::WebContents*>* vector,
+ content::WebContents* web_contents) {
+ vector->push_back(web_contents);
+ return false; // Continue iterating.
+}
+
+} // namespace
+
+void GetAllGuestsForOwnerContents(content::WebContents* owner,
+ std::vector<content::WebContents*>* guests) {
+ content::BrowserPluginGuestManager* plugin_guest_manager =
+ owner->GetBrowserContext()->GetGuestManager();
+ plugin_guest_manager->ForEachGuest(
+ owner, base::BindRepeating(InsertWebContents, guests));
+}
+
+content::WebContents* GetOwnerForGuestContents(content::WebContents* guest) {
+ content::WebContentsImpl* guest_impl =
+ static_cast<content::WebContentsImpl*>(guest);
+ content::BrowserPluginGuest* plugin_guest =
+ guest_impl->GetBrowserPluginGuest();
+ if (plugin_guest) {
+ return plugin_guest->owner_web_contents();
+ }
+
+ // Maybe it's a print preview dialog.
+ auto print_preview_controller =
+ g_browser_process->print_preview_dialog_controller();
+ return print_preview_controller->GetInitiator(guest);
+}
+
+CefRefPtr<CefBrowserHostBase> GetOwnerBrowserForGlobalId(
+ const content::GlobalRenderFrameHostId& global_id,
+ bool* is_guest_view) {
+ if (CEF_CURRENTLY_ON_UIT()) {
+ // Use the non-thread-safe but potentially faster approach.
+ content::RenderFrameHost* host =
+ content::RenderFrameHost::FromID(global_id);
+ if (host) {
+ return GetOwnerBrowserForHost(host, is_guest_view);
+ }
+ return nullptr;
+ } else {
+ // Use the thread-safe approach.
+ scoped_refptr<CefBrowserInfo> info =
+ CefBrowserInfoManager::GetInstance()->GetBrowserInfo(global_id,
+ is_guest_view);
+ if (info.get()) {
+ CefRefPtr<CefBrowserHostBase> browser = info->browser();
+ if (!browser.get()) {
+ LOG(WARNING) << "Found browser id " << info->browser_id()
+ << " but no browser object matching frame "
+ << frame_util::GetFrameDebugString(global_id);
+ }
+ return browser;
+ }
+ return nullptr;
+ }
+}
+
+CefRefPtr<CefBrowserHostBase> GetOwnerBrowserForHost(
+ content::RenderViewHost* host,
+ bool* is_guest_view) {
+ if (is_guest_view) {
+ *is_guest_view = false;
+ }
+
+ CefRefPtr<CefBrowserHostBase> browser =
+ CefBrowserHostBase::GetBrowserForHost(host);
+ if (!browser.get() && ExtensionsEnabled()) {
+ // Retrieve the owner browser, if any.
+ content::WebContents* owner = GetOwnerForGuestContents(
+ content::WebContents::FromRenderViewHost(host));
+ if (owner) {
+ browser = CefBrowserHostBase::GetBrowserForContents(owner);
+ if (browser.get() && is_guest_view) {
+ *is_guest_view = true;
+ }
+ }
+ }
+ return browser;
+}
+
+CefRefPtr<CefBrowserHostBase> GetOwnerBrowserForHost(
+ content::RenderFrameHost* host,
+ bool* is_guest_view) {
+ if (is_guest_view) {
+ *is_guest_view = false;
+ }
+
+ CefRefPtr<CefBrowserHostBase> browser =
+ CefBrowserHostBase::GetBrowserForHost(host);
+ if (!browser.get() && ExtensionsEnabled()) {
+ // Retrieve the owner browser, if any.
+ content::WebContents* owner = GetOwnerForGuestContents(
+ content::WebContents::FromRenderFrameHost(host));
+ if (owner) {
+ browser = CefBrowserHostBase::GetBrowserForContents(owner);
+ if (browser.get() && is_guest_view) {
+ *is_guest_view = true;
+ }
+ }
+ }
+ return browser;
+}
+
+CefRefPtr<AlloyBrowserHostImpl> GetBrowserForTabId(
+ int tab_id,
+ content::BrowserContext* browser_context) {
+ REQUIRE_ALLOY_RUNTIME();
+ CEF_REQUIRE_UIT();
+ DCHECK(browser_context);
+ if (tab_id < 0 || !browser_context) {
+ return nullptr;
+ }
+
+ auto cef_browser_context =
+ CefBrowserContext::FromBrowserContext(browser_context);
+
+ for (const auto& browser_info :
+ CefBrowserInfoManager::GetInstance()->GetBrowserInfoList()) {
+ CefRefPtr<AlloyBrowserHostImpl> current_browser =
+ static_cast<AlloyBrowserHostImpl*>(browser_info->browser().get());
+ if (current_browser && current_browser->GetIdentifier() == tab_id) {
+ // Make sure we're operating in the same CefBrowserContext.
+ if (CefBrowserContext::FromBrowserContext(
+ current_browser->GetBrowserContext()) == cef_browser_context) {
+ return current_browser;
+ } else {
+ LOG(WARNING) << "Browser with tabId " << tab_id
+ << " cannot be accessed because is uses a different "
+ "CefRequestContext";
+ break;
+ }
+ }
+ }
+
+ return nullptr;
+}
+
+const Extension* GetExtensionForUrl(content::BrowserContext* browser_context,
+ const GURL& url) {
+ ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context);
+ if (!registry) {
+ return nullptr;
+ }
+ std::string extension_id = url.host();
+ return registry->enabled_extensions().GetByID(extension_id);
+}
+
+} // namespace extensions
diff --git a/libcef/browser/extensions/browser_extensions_util.h b/libcef/browser/extensions/browser_extensions_util.h
new file mode 100644
index 00000000..b4adb7ba
--- /dev/null
+++ b/libcef/browser/extensions/browser_extensions_util.h
@@ -0,0 +1,70 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_EXTENSIONS_BROWSER_EXTENSIONS_UTIL_H_
+#define CEF_LIBCEF_BROWSER_EXTENSIONS_BROWSER_EXTENSIONS_UTIL_H_
+
+#include <vector>
+
+#include "include/internal/cef_ptr.h"
+
+#include "url/gurl.h"
+
+namespace content {
+class BrowserContext;
+struct GlobalRenderFrameHostId;
+class RenderFrameHost;
+class RenderViewHost;
+class WebContents;
+} // namespace content
+
+class CefBrowserHostBase;
+class AlloyBrowserHostImpl;
+
+namespace extensions {
+
+class Extension;
+
+// Populates |guests| with all guest WebContents with the specified |owner|.
+void GetAllGuestsForOwnerContents(content::WebContents* owner,
+ std::vector<content::WebContents*>* guests);
+
+// Returns the WebContents that owns the specified |guest|, if any.
+content::WebContents* GetOwnerForGuestContents(content::WebContents* guest);
+
+// Returns the CefBrowserHostBase that owns the host identified by the specified
+// global ID, if any. |is_guest_view| will be set to true if the ID
+// matches a guest view associated with the returned browser instead of the
+// browser itself.
+CefRefPtr<CefBrowserHostBase> GetOwnerBrowserForGlobalId(
+ const content::GlobalRenderFrameHostId& global_id,
+ bool* is_guest_view);
+
+// Returns the CefBrowserHostBase that owns the specified |host|, if any.
+// |is_guest_view| will be set to true if the host matches a guest view
+// associated with the returned browser instead of the browser itself.
+// TODO(cef): Delete the RVH variant once the remaining use case
+// (via AlloyContentBrowserClient::OverrideWebkitPrefs) has been removed.
+CefRefPtr<CefBrowserHostBase> GetOwnerBrowserForHost(
+ content::RenderViewHost* host,
+ bool* is_guest_view);
+CefRefPtr<CefBrowserHostBase> GetOwnerBrowserForHost(
+ content::RenderFrameHost* host,
+ bool* is_guest_view);
+
+// Returns the browser matching |tab_id| and |browser_context|. Returns false if
+// |tab_id| is < 0 or a matching browser cannot be found within
+// |browser_context|. Similar in concept to ExtensionTabUtil::GetTabById.
+CefRefPtr<AlloyBrowserHostImpl> GetBrowserForTabId(
+ int tab_id,
+ content::BrowserContext* browser_context);
+
+// Returns the extension associated with |url| in |profile|. Returns nullptr
+// if the extension does not exist.
+const Extension* GetExtensionForUrl(content::BrowserContext* browser_context,
+ const GURL& url);
+
+} // namespace extensions
+
+#endif // CEF_LIBCEF_BROWSER_EXTENSIONS_BROWSER_EXTENSIONS_UTIL_H_
diff --git a/libcef/browser/extensions/browser_platform_delegate_background.cc b/libcef/browser/extensions/browser_platform_delegate_background.cc
new file mode 100644
index 00000000..949f3470
--- /dev/null
+++ b/libcef/browser/extensions/browser_platform_delegate_background.cc
@@ -0,0 +1,121 @@
+// Copyright 2017 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/extensions/browser_platform_delegate_background.h"
+
+#include <utility>
+
+#include "libcef/browser/alloy/alloy_browser_host_impl.h"
+#include "libcef/browser/thread_util.h"
+#include "libcef/features/runtime_checks.h"
+
+#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
+
+CefBrowserPlatformDelegateBackground::CefBrowserPlatformDelegateBackground(
+ std::unique_ptr<CefBrowserPlatformDelegateNative> native_delegate)
+ : native_delegate_(std::move(native_delegate)) {
+ REQUIRE_ALLOY_RUNTIME();
+ native_delegate_->set_windowless_handler(this);
+}
+
+bool CefBrowserPlatformDelegateBackground::CreateHostWindow() {
+ // Nothing to do here.
+ return true;
+}
+
+void CefBrowserPlatformDelegateBackground::CloseHostWindow() {
+ // No host window, so continue browser destruction now. Do it asynchronously
+ // so the call stack has a chance to unwind.
+ CEF_POST_TASK(CEF_UIT,
+ base::BindOnce(&AlloyBrowserHostImpl::WindowDestroyed,
+ static_cast<AlloyBrowserHostImpl*>(browser_)));
+}
+
+CefWindowHandle CefBrowserPlatformDelegateBackground::GetHostWindowHandle()
+ const {
+ return kNullWindowHandle;
+}
+
+SkColor CefBrowserPlatformDelegateBackground::GetBackgroundColor() const {
+ return native_delegate_->GetBackgroundColor();
+}
+
+void CefBrowserPlatformDelegateBackground::WasResized() {
+ // Nothing to do here.
+}
+
+void CefBrowserPlatformDelegateBackground::SendKeyEvent(
+ const CefKeyEvent& event) {
+ // Nothing to do here.
+}
+
+void CefBrowserPlatformDelegateBackground::SendMouseClickEvent(
+ const CefMouseEvent& event,
+ CefBrowserHost::MouseButtonType type,
+ bool mouseUp,
+ int clickCount) {
+ // Nothing to do here.
+}
+
+void CefBrowserPlatformDelegateBackground::SendMouseMoveEvent(
+ const CefMouseEvent& event,
+ bool mouseLeave) {
+ // Nothing to do here.
+}
+
+void CefBrowserPlatformDelegateBackground::SendMouseWheelEvent(
+ const CefMouseEvent& event,
+ int deltaX,
+ int deltaY) {
+ // Nothing to do here.
+}
+
+void CefBrowserPlatformDelegateBackground::SendTouchEvent(
+ const CefTouchEvent& event) {
+ // Nothing to do here.
+}
+
+void CefBrowserPlatformDelegateBackground::SetFocus(bool setFocus) {
+ // Nothing to do here.
+}
+
+gfx::Point CefBrowserPlatformDelegateBackground::GetScreenPoint(
+ const gfx::Point& view_pt,
+ bool want_dip_coords) const {
+ // Nothing to do here.
+ return view_pt;
+}
+
+void CefBrowserPlatformDelegateBackground::ViewText(const std::string& text) {
+ native_delegate_->ViewText(text);
+}
+
+bool CefBrowserPlatformDelegateBackground::HandleKeyboardEvent(
+ const content::NativeWebKeyboardEvent& event) {
+ // Nothing to do here.
+ return false;
+}
+
+CefEventHandle CefBrowserPlatformDelegateBackground::GetEventHandle(
+ const content::NativeWebKeyboardEvent& event) const {
+ return native_delegate_->GetEventHandle(event);
+}
+
+std::unique_ptr<CefMenuRunner>
+CefBrowserPlatformDelegateBackground::CreateMenuRunner() {
+ // No default menu implementation for background browsers.
+ return nullptr;
+}
+
+CefWindowHandle CefBrowserPlatformDelegateBackground::GetParentWindowHandle()
+ const {
+ return GetHostWindowHandle();
+}
+
+gfx::Point CefBrowserPlatformDelegateBackground::GetParentScreenPoint(
+ const gfx::Point& view,
+ bool want_dip_coords) const {
+ return GetScreenPoint(view, want_dip_coords);
+}
diff --git a/libcef/browser/extensions/browser_platform_delegate_background.h b/libcef/browser/extensions/browser_platform_delegate_background.h
new file mode 100644
index 00000000..39ae59f2
--- /dev/null
+++ b/libcef/browser/extensions/browser_platform_delegate_background.h
@@ -0,0 +1,55 @@
+// Copyright 2017 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_VIEWS_BROWSER_PLATFORM_DELEGATE_BACKGROUND_H_
+#define CEF_LIBCEF_BROWSER_VIEWS_BROWSER_PLATFORM_DELEGATE_BACKGROUND_H_
+
+#include "libcef/browser/alloy/browser_platform_delegate_alloy.h"
+#include "libcef/browser/native/browser_platform_delegate_native.h"
+
+// Implementation of browser functionality for background script hosts.
+class CefBrowserPlatformDelegateBackground
+ : public CefBrowserPlatformDelegateAlloy,
+ public CefBrowserPlatformDelegateNative::WindowlessHandler {
+ public:
+ // Platform-specific behaviors will be delegated to |native_delegate|.
+ CefBrowserPlatformDelegateBackground(
+ std::unique_ptr<CefBrowserPlatformDelegateNative> native_delegate);
+
+ // CefBrowserPlatformDelegate methods:
+ bool CreateHostWindow() override;
+ void CloseHostWindow() override;
+ CefWindowHandle GetHostWindowHandle() const override;
+ SkColor GetBackgroundColor() const override;
+ void WasResized() override;
+ void SendKeyEvent(const CefKeyEvent& event) override;
+ void SendMouseClickEvent(const CefMouseEvent& event,
+ CefBrowserHost::MouseButtonType type,
+ bool mouseUp,
+ int clickCount) override;
+ void SendMouseMoveEvent(const CefMouseEvent& event, bool mouseLeave) override;
+ void SendMouseWheelEvent(const CefMouseEvent& event,
+ int deltaX,
+ int deltaY) override;
+ void SendTouchEvent(const CefTouchEvent& event) override;
+ void SetFocus(bool setFocus) override;
+ gfx::Point GetScreenPoint(const gfx::Point& view,
+ bool want_dip_coords) const override;
+ void ViewText(const std::string& text) override;
+ bool HandleKeyboardEvent(
+ const content::NativeWebKeyboardEvent& event) override;
+ CefEventHandle GetEventHandle(
+ const content::NativeWebKeyboardEvent& event) const override;
+ std::unique_ptr<CefMenuRunner> CreateMenuRunner() override;
+
+ // CefBrowserPlatformDelegateNative::WindowlessHandler methods:
+ CefWindowHandle GetParentWindowHandle() const override;
+ gfx::Point GetParentScreenPoint(const gfx::Point& view,
+ bool want_dip_coords) const override;
+
+ private:
+ std::unique_ptr<CefBrowserPlatformDelegateNative> native_delegate_;
+};
+
+#endif // CEF_LIBCEF_BROWSER_VIEWS_BROWSER_PLATFORM_DELEGATE_BACKGROUND_H_
diff --git a/libcef/browser/extensions/chrome_api_registration.cc b/libcef/browser/extensions/chrome_api_registration.cc
new file mode 100644
index 00000000..d1198ddc
--- /dev/null
+++ b/libcef/browser/extensions/chrome_api_registration.cc
@@ -0,0 +1,114 @@
+// Copyright (c) 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// APIs must also be registered in
+// libcef/common/extensions/api/_*_features.json files and possibly
+// CefExtensionsDispatcherDelegate::PopulateSourceMap. See
+// libcef/common/extensions/api/README.txt for additional details.
+
+#include "libcef/browser/extensions/chrome_api_registration.h"
+
+#include "libcef/browser/extensions/api/tabs/tabs_api.h"
+
+#include "chrome/browser/extensions/api/content_settings/content_settings_api.h"
+#include "chrome/browser/extensions/api/pdf_viewer_private/pdf_viewer_private_api.h"
+#include "chrome/browser/extensions/api/resources_private/resources_private_api.h"
+#include "extensions/browser/api/alarms/alarms_api.h"
+#include "extensions/browser/api/storage/storage_api.h"
+#include "extensions/browser/extension_function_registry.h"
+
+namespace extensions {
+namespace api {
+namespace cef {
+
+namespace cefimpl = extensions::cef;
+
+#define EXTENSION_FUNCTION_NAME(classname) classname::static_function_name()
+
+// Maintain the same order as https://developer.chrome.com/extensions/api_index
+// so chrome://extensions-support looks nice.
+const char* const kSupportedAPIs[] = {
+ "alarms",
+ EXTENSION_FUNCTION_NAME(AlarmsCreateFunction),
+ EXTENSION_FUNCTION_NAME(AlarmsGetFunction),
+ EXTENSION_FUNCTION_NAME(AlarmsGetAllFunction),
+ EXTENSION_FUNCTION_NAME(AlarmsClearFunction),
+ EXTENSION_FUNCTION_NAME(AlarmsClearAllFunction),
+ "contentSettings",
+ EXTENSION_FUNCTION_NAME(ContentSettingsContentSettingClearFunction),
+ EXTENSION_FUNCTION_NAME(ContentSettingsContentSettingGetFunction),
+ EXTENSION_FUNCTION_NAME(ContentSettingsContentSettingSetFunction),
+ EXTENSION_FUNCTION_NAME(
+ ContentSettingsContentSettingGetResourceIdentifiersFunction),
+ "pdfViewerPrivate",
+ EXTENSION_FUNCTION_NAME(PdfViewerPrivateIsAllowedLocalFileAccessFunction),
+ "resourcesPrivate",
+ EXTENSION_FUNCTION_NAME(ResourcesPrivateGetStringsFunction),
+ "storage",
+ EXTENSION_FUNCTION_NAME(StorageStorageAreaGetFunction),
+ EXTENSION_FUNCTION_NAME(StorageStorageAreaSetFunction),
+ EXTENSION_FUNCTION_NAME(StorageStorageAreaRemoveFunction),
+ EXTENSION_FUNCTION_NAME(StorageStorageAreaClearFunction),
+ EXTENSION_FUNCTION_NAME(StorageStorageAreaGetBytesInUseFunction),
+ "tabs",
+ EXTENSION_FUNCTION_NAME(cefimpl::TabsGetFunction),
+ EXTENSION_FUNCTION_NAME(cefimpl::TabsCreateFunction),
+ EXTENSION_FUNCTION_NAME(cefimpl::TabsUpdateFunction),
+ EXTENSION_FUNCTION_NAME(cefimpl::TabsExecuteScriptFunction),
+ EXTENSION_FUNCTION_NAME(cefimpl::TabsInsertCSSFunction),
+ EXTENSION_FUNCTION_NAME(cefimpl::TabsRemoveCSSFunction),
+ EXTENSION_FUNCTION_NAME(cefimpl::TabsSetZoomFunction),
+ EXTENSION_FUNCTION_NAME(cefimpl::TabsGetZoomFunction),
+ EXTENSION_FUNCTION_NAME(cefimpl::TabsSetZoomSettingsFunction),
+ EXTENSION_FUNCTION_NAME(cefimpl::TabsGetZoomSettingsFunction),
+ nullptr, // Indicates end of array.
+};
+
+// Only add APIs to this list that have been tested in CEF.
+// static
+bool ChromeFunctionRegistry::IsSupported(const std::string& name) {
+ for (size_t i = 0; kSupportedAPIs[i] != nullptr; ++i) {
+ if (name == kSupportedAPIs[i]) {
+ return true;
+ }
+ }
+ return false;
+}
+
+// Only add APIs to this list that have been tested in CEF.
+// static
+void ChromeFunctionRegistry::RegisterAll(ExtensionFunctionRegistry* registry) {
+ registry->RegisterFunction<AlarmsCreateFunction>();
+ registry->RegisterFunction<AlarmsGetFunction>();
+ registry->RegisterFunction<AlarmsGetAllFunction>();
+ registry->RegisterFunction<AlarmsClearFunction>();
+ registry->RegisterFunction<AlarmsClearAllFunction>();
+ registry->RegisterFunction<ContentSettingsContentSettingClearFunction>();
+ registry->RegisterFunction<ContentSettingsContentSettingGetFunction>();
+ registry->RegisterFunction<ContentSettingsContentSettingSetFunction>();
+ registry->RegisterFunction<
+ ContentSettingsContentSettingGetResourceIdentifiersFunction>();
+ registry
+ ->RegisterFunction<PdfViewerPrivateIsAllowedLocalFileAccessFunction>();
+ registry->RegisterFunction<ResourcesPrivateGetStringsFunction>();
+ registry->RegisterFunction<StorageStorageAreaGetFunction>();
+ registry->RegisterFunction<StorageStorageAreaSetFunction>();
+ registry->RegisterFunction<StorageStorageAreaRemoveFunction>();
+ registry->RegisterFunction<StorageStorageAreaClearFunction>();
+ registry->RegisterFunction<StorageStorageAreaGetBytesInUseFunction>();
+ registry->RegisterFunction<cefimpl::TabsExecuteScriptFunction>();
+ registry->RegisterFunction<cefimpl::TabsInsertCSSFunction>();
+ registry->RegisterFunction<cefimpl::TabsRemoveCSSFunction>();
+ registry->RegisterFunction<cefimpl::TabsGetFunction>();
+ registry->RegisterFunction<cefimpl::TabsCreateFunction>();
+ registry->RegisterFunction<cefimpl::TabsUpdateFunction>();
+ registry->RegisterFunction<cefimpl::TabsSetZoomFunction>();
+ registry->RegisterFunction<cefimpl::TabsGetZoomFunction>();
+ registry->RegisterFunction<cefimpl::TabsSetZoomSettingsFunction>();
+ registry->RegisterFunction<cefimpl::TabsGetZoomSettingsFunction>();
+}
+
+} // namespace cef
+} // namespace api
+} // namespace extensions
diff --git a/libcef/browser/extensions/chrome_api_registration.h b/libcef/browser/extensions/chrome_api_registration.h
new file mode 100644
index 00000000..52e86c39
--- /dev/null
+++ b/libcef/browser/extensions/chrome_api_registration.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_EXTENSIONS_CHROME_API_REGISTRATION_H_
+#define CEF_LIBCEF_BROWSER_EXTENSIONS_CHROME_API_REGISTRATION_H_
+
+#include <string>
+
+class ExtensionFunctionRegistry;
+
+namespace extensions {
+namespace api {
+namespace cef {
+
+// Array of currently supported APIs.
+extern const char* const kSupportedAPIs[];
+
+class ChromeFunctionRegistry {
+ public:
+ static bool IsSupported(const std::string& name);
+ static void RegisterAll(ExtensionFunctionRegistry* registry);
+};
+
+} // namespace cef
+} // namespace api
+} // namespace extensions
+
+#endif // CEF_LIBCEF_BROWSER_EXTENSIONS_CHROME_API_REGISTRATION_H_
diff --git a/libcef/browser/extensions/component_extension_resource_manager.cc b/libcef/browser/extensions/component_extension_resource_manager.cc
new file mode 100644
index 00000000..c7a3af04
--- /dev/null
+++ b/libcef/browser/extensions/component_extension_resource_manager.cc
@@ -0,0 +1,81 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/extensions/component_extension_resource_manager.h"
+
+#include "base/containers/contains.h"
+#include "base/logging.h"
+#include "base/path_service.h"
+#include "base/values.h"
+#include "chrome/browser/pdf/pdf_extension_util.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/grit/component_extension_resources_map.h"
+#include "chrome/grit/pdf_resources_map.h"
+#include "extensions/common/constants.h"
+
+namespace extensions {
+
+CefComponentExtensionResourceManager::CefComponentExtensionResourceManager() {
+ AddComponentResourceEntries(kComponentExtensionResources,
+ kComponentExtensionResourcesSize);
+ AddComponentResourceEntries(kPdfResources, kPdfResourcesSize);
+
+ base::Value::Dict dict;
+ pdf_extension_util::AddStrings(
+ pdf_extension_util::PdfViewerContext::kPdfViewer, &dict);
+ pdf_extension_util::AddAdditionalData(/*enable_printing=*/true,
+ /*enable_annotations=*/true, &dict);
+
+ ui::TemplateReplacements pdf_viewer_replacements;
+ ui::TemplateReplacementsFromDictionaryValue(dict, &pdf_viewer_replacements);
+ template_replacements_[extension_misc::kPdfExtensionId] =
+ std::move(pdf_viewer_replacements);
+}
+
+CefComponentExtensionResourceManager::~CefComponentExtensionResourceManager() {}
+
+bool CefComponentExtensionResourceManager::IsComponentExtensionResource(
+ const base::FilePath& extension_path,
+ const base::FilePath& resource_path,
+ int* resource_id) const {
+ base::FilePath directory_path = extension_path;
+ base::FilePath resources_dir;
+ base::FilePath relative_path;
+ if (!base::PathService::Get(chrome::DIR_RESOURCES, &resources_dir) ||
+ !resources_dir.AppendRelativePath(directory_path, &relative_path)) {
+ return false;
+ }
+ relative_path = relative_path.Append(resource_path);
+ relative_path = relative_path.NormalizePathSeparators();
+
+ auto entry = path_to_resource_info_.find(relative_path);
+ if (entry != path_to_resource_info_.end()) {
+ *resource_id = entry->second;
+ return true;
+ }
+
+ return false;
+}
+
+const ui::TemplateReplacements*
+CefComponentExtensionResourceManager::GetTemplateReplacementsForExtension(
+ const std::string& extension_id) const {
+ auto it = template_replacements_.find(extension_id);
+ return it != template_replacements_.end() ? &it->second : nullptr;
+}
+
+void CefComponentExtensionResourceManager::AddComponentResourceEntries(
+ const webui::ResourcePath* entries,
+ size_t size) {
+ for (size_t i = 0; i < size; ++i) {
+ base::FilePath resource_path =
+ base::FilePath().AppendASCII(entries[i].path);
+ resource_path = resource_path.NormalizePathSeparators();
+
+ DCHECK(!base::Contains(path_to_resource_info_, resource_path));
+ path_to_resource_info_[resource_path] = entries[i].id;
+ }
+}
+
+} // namespace extensions
diff --git a/libcef/browser/extensions/component_extension_resource_manager.h b/libcef/browser/extensions/component_extension_resource_manager.h
new file mode 100644
index 00000000..d541d9cb
--- /dev/null
+++ b/libcef/browser/extensions/component_extension_resource_manager.h
@@ -0,0 +1,54 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_EXTENSIONS_COMPONENT_EXTENSION_RESOURCE_MANAGER_H_
+#define CEF_LIBCEF_BROWSER_EXTENSIONS_COMPONENT_EXTENSION_RESOURCE_MANAGER_H_
+
+#include <map>
+
+#include "base/files/file_path.h"
+#include "extensions/browser/component_extension_resource_manager.h"
+
+namespace webui {
+struct ResourcePath;
+}
+
+namespace extensions {
+
+class CefComponentExtensionResourceManager
+ : public ComponentExtensionResourceManager {
+ public:
+ CefComponentExtensionResourceManager();
+
+ CefComponentExtensionResourceManager(
+ const CefComponentExtensionResourceManager&) = delete;
+ CefComponentExtensionResourceManager& operator=(
+ const CefComponentExtensionResourceManager&) = delete;
+
+ ~CefComponentExtensionResourceManager() override;
+
+ // Overridden from ComponentExtensionResourceManager:
+ bool IsComponentExtensionResource(const base::FilePath& extension_path,
+ const base::FilePath& resource_path,
+ int* resource_id) const override;
+ const ui::TemplateReplacements* GetTemplateReplacementsForExtension(
+ const std::string& extension_id) const override;
+
+ private:
+ void AddComponentResourceEntries(const webui::ResourcePath* entries,
+ size_t size);
+
+ // A map from a resource path to the resource ID. Used by
+ // IsComponentExtensionResource.
+ std::map<base::FilePath, int> path_to_resource_info_;
+
+ // A map from an extension ID to its i18n template replacements.
+ using TemplateReplacementMap =
+ std::map<std::string, ui::TemplateReplacements>;
+ TemplateReplacementMap template_replacements_;
+};
+
+} // namespace extensions
+
+#endif // CEF_LIBCEF_BROWSER_EXTENSIONS_COMPONENT_EXTENSION_RESOURCE_MANAGER_H_
diff --git a/libcef/browser/extensions/extension_background_host.cc b/libcef/browser/extensions/extension_background_host.cc
new file mode 100644
index 00000000..37fe38b8
--- /dev/null
+++ b/libcef/browser/extensions/extension_background_host.cc
@@ -0,0 +1,46 @@
+// Copyright 2017 the Chromium Embedded Framework Authors. Portions copyright
+// 2013 The Chromium Authors. All rights reserved. Use of this source code is
+// governed by a BSD-style license that can be found in the LICENSE file.
+
+#include "libcef/browser/extensions/extension_background_host.h"
+
+#include "libcef/browser/alloy/alloy_browser_host_impl.h"
+#include "libcef/browser/extensions/extension_host_delegate.h"
+
+#include "base/functional/callback.h"
+
+namespace extensions {
+
+CefExtensionBackgroundHost::CefExtensionBackgroundHost(
+ AlloyBrowserHostImpl* browser,
+ base::OnceClosure deleted_callback,
+ const Extension* extension,
+ content::WebContents* host_contents,
+ const GURL& url,
+ mojom::ViewType host_type)
+ : ExtensionHost(new CefExtensionHostDelegate(browser),
+ extension,
+ host_contents->GetBrowserContext(),
+ host_contents,
+ url,
+ host_type),
+ deleted_callback_(std::move(deleted_callback)) {
+ DCHECK(!deleted_callback_.is_null());
+
+ // Only used for background pages.
+ DCHECK(host_type == mojom::ViewType::kExtensionBackgroundPage);
+}
+
+CefExtensionBackgroundHost::~CefExtensionBackgroundHost() {
+ std::move(deleted_callback_).Run();
+}
+
+bool CefExtensionBackgroundHost::
+ ShouldAllowRendererInitiatedCrossProcessNavigation(
+ bool is_main_frame_navigation) {
+ // Block navigations that cause the main frame to navigate to non-extension
+ // content (i.e. to web content).
+ return !is_main_frame_navigation;
+}
+
+} // namespace extensions
diff --git a/libcef/browser/extensions/extension_background_host.h b/libcef/browser/extensions/extension_background_host.h
new file mode 100644
index 00000000..ed7f6c80
--- /dev/null
+++ b/libcef/browser/extensions/extension_background_host.h
@@ -0,0 +1,50 @@
+// Copyright 2017 the Chromium Embedded Framework Authors. Portions copyright
+// 2013 The Chromium Authors. All rights reserved. Use of this source code is
+// governed by a BSD-style license that can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_EXTENSIONS_EXTENSION_BACKGROUND_HOST_H_
+#define CEF_LIBCEF_BROWSER_EXTENSIONS_EXTENSION_BACKGROUND_HOST_H_
+
+#include <memory>
+
+#include "base/functional/callback_forward.h"
+#include "extensions/browser/extension_host.h"
+
+class AlloyBrowserHostImpl;
+
+namespace content {
+class WebContents;
+} // namespace content
+
+namespace extensions {
+
+// The ExtensionHost for a background page. This is a thin wrapper around the
+// ExtensionHost base class to support CEF-specific constructor. Object lifespan
+// is managed by ProcessManager.
+class CefExtensionBackgroundHost : public ExtensionHost {
+ public:
+ CefExtensionBackgroundHost(AlloyBrowserHostImpl* browser,
+ base::OnceClosure deleted_callback,
+ const Extension* extension,
+ content::WebContents* host_contents,
+ const GURL& url,
+ mojom::ViewType host_type);
+
+ CefExtensionBackgroundHost(const CefExtensionBackgroundHost&) = delete;
+ CefExtensionBackgroundHost& operator=(const CefExtensionBackgroundHost&) =
+ delete;
+
+ ~CefExtensionBackgroundHost() override;
+
+ // content::WebContentsDelegate methods:
+ bool ShouldAllowRendererInitiatedCrossProcessNavigation(
+ bool is_main_frame_navigation) override;
+
+ private:
+ // Callback that will be executed on host deletion.
+ base::OnceClosure deleted_callback_;
+};
+
+} // namespace extensions
+
+#endif // CEF_LIBCEF_BROWSER_EXTENSIONS_EXTENSION_BACKGROUND_HOST_H_
diff --git a/libcef/browser/extensions/extension_function_details.cc b/libcef/browser/extensions/extension_function_details.cc
new file mode 100644
index 00000000..7b512644
--- /dev/null
+++ b/libcef/browser/extensions/extension_function_details.cc
@@ -0,0 +1,475 @@
+// Copyright 2017 the Chromium Embedded Framework Authors. Portions copyright
+// 2014 The Chromium Authors. All rights reserved. Use of this source code is
+// governed by a BSD-style license that can be found in the LICENSE file.
+
+#include "libcef/browser/extensions/extension_function_details.h"
+
+#include "libcef/browser/browser_context.h"
+#include "libcef/browser/extensions/browser_extensions_util.h"
+#include "libcef/browser/extensions/extension_system.h"
+#include "libcef/browser/thread_util.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "base/task/thread_pool.h"
+#include "chrome/browser/extensions/api/tabs/tabs_constants.h"
+#include "chrome/browser/extensions/extension_tab_util.h"
+#include "chrome/browser/profiles/profile.h"
+#include "content/public/browser/favicon_status.h"
+#include "content/public/browser/navigation_entry.h"
+#include "extensions/browser/extension_function.h"
+#include "extensions/browser/extension_function_dispatcher.h"
+#include "extensions/common/error_utils.h"
+
+using content::RenderViewHost;
+using content::WebContents;
+
+namespace extensions {
+
+namespace keys = extensions::tabs_constants;
+
+namespace {
+
+class CefGetExtensionLoadFileCallbackImpl
+ : public CefGetExtensionResourceCallback {
+ public:
+ CefGetExtensionLoadFileCallbackImpl(
+ const std::string& file,
+ CefExtensionFunctionDetails::LoadFileCallback callback)
+ : file_(file), callback_(std::move(callback)) {}
+
+ CefGetExtensionLoadFileCallbackImpl(
+ const CefGetExtensionLoadFileCallbackImpl&) = delete;
+ CefGetExtensionLoadFileCallbackImpl& operator=(
+ const CefGetExtensionLoadFileCallbackImpl&) = delete;
+
+ ~CefGetExtensionLoadFileCallbackImpl() {
+ if (!callback_.is_null()) {
+ // The callback is still pending. Cancel it now.
+ if (CEF_CURRENTLY_ON_UIT()) {
+ RunNow(file_, std::move(callback_), nullptr);
+ } else {
+ CEF_POST_TASK(CEF_UIT, base::BindOnce(
+ &CefGetExtensionLoadFileCallbackImpl::RunNow,
+ file_, std::move(callback_), nullptr));
+ }
+ }
+ }
+
+ void Continue(CefRefPtr<CefStreamReader> stream) override {
+ if (CEF_CURRENTLY_ON_UIT()) {
+ if (!callback_.is_null()) {
+ // Always continue asynchronously.
+ CEF_POST_TASK(CEF_UIT, base::BindOnce(
+ &CefGetExtensionLoadFileCallbackImpl::RunNow,
+ file_, std::move(callback_), stream));
+ }
+ } else {
+ CEF_POST_TASK(CEF_UIT, base::BindOnce(
+ &CefGetExtensionLoadFileCallbackImpl::Continue,
+ this, stream));
+ }
+ }
+
+ void Cancel() override { Continue(nullptr); }
+
+ void Disconnect() { callback_.Reset(); }
+
+ private:
+ static void RunNow(const std::string& file,
+ CefExtensionFunctionDetails::LoadFileCallback callback,
+ CefRefPtr<CefStreamReader> stream) {
+ CEF_REQUIRE_UIT();
+
+ if (!stream) {
+ std::move(callback).Run(nullptr);
+ return;
+ }
+
+ base::ThreadPool::PostTaskAndReplyWithResult(
+ FROM_HERE,
+ {base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
+ base::BindOnce(LoadFileFromStream, file, stream), std::move(callback));
+ }
+
+ static std::unique_ptr<std::string> LoadFileFromStream(
+ const std::string& file,
+ CefRefPtr<CefStreamReader> stream) {
+ CEF_REQUIRE_BLOCKING();
+
+ // Move to the end of the stream.
+ stream->Seek(0, SEEK_END);
+ const int64 size = stream->Tell();
+ if (size == 0) {
+ LOG(WARNING) << "Extension resource " << file << " is empty.";
+ return nullptr;
+ }
+
+ std::unique_ptr<std::string> result(new std::string());
+ result->resize(size);
+
+ // Move to the beginning of the stream.
+ stream->Seek(0, SEEK_SET);
+
+ // Read all stream contents into the string.
+ int64 read, offset = 0;
+ do {
+ read =
+ static_cast<int>(stream->Read(&(*result)[offset], 1, size - offset));
+ offset += read;
+ } while (read > 0 && offset < size);
+
+ if (offset != size) {
+ LOG(WARNING) << "Extension resource " << file << " read failed; expected "
+ << size << ", got " << offset << " bytes.";
+ return nullptr;
+ }
+
+ return result;
+ }
+
+ const std::string file_;
+ CefExtensionFunctionDetails::LoadFileCallback callback_;
+
+ IMPLEMENT_REFCOUNTING(CefGetExtensionLoadFileCallbackImpl);
+};
+
+} // namespace
+
+CefExtensionFunctionDetails::CefExtensionFunctionDetails(
+ ExtensionFunction* function)
+ : function_(function) {}
+
+CefExtensionFunctionDetails::~CefExtensionFunctionDetails() {}
+
+Profile* CefExtensionFunctionDetails::GetProfile() const {
+ return Profile::FromBrowserContext(function_->browser_context());
+}
+
+CefRefPtr<AlloyBrowserHostImpl> CefExtensionFunctionDetails::GetSenderBrowser()
+ const {
+ content::WebContents* web_contents = function_->GetSenderWebContents();
+ if (web_contents) {
+ return AlloyBrowserHostImpl::GetBrowserForContents(web_contents);
+ }
+ return nullptr;
+}
+
+CefRefPtr<AlloyBrowserHostImpl> CefExtensionFunctionDetails::GetCurrentBrowser()
+ const {
+ // Start with the browser hosting the extension.
+ CefRefPtr<AlloyBrowserHostImpl> browser = GetSenderBrowser();
+ if (browser && browser->client()) {
+ CefRefPtr<CefExtensionHandler> handler = GetCefExtension()->GetHandler();
+ if (handler) {
+ // Give the handler an opportunity to specify a different browser.
+ CefRefPtr<CefBrowser> active_browser =
+ handler->GetActiveBrowser(GetCefExtension(), browser.get(),
+ function_->include_incognito_information());
+ if (active_browser && active_browser != browser) {
+ CefRefPtr<AlloyBrowserHostImpl> active_browser_impl =
+ static_cast<AlloyBrowserHostImpl*>(active_browser.get());
+
+ // Make sure we're operating in the same CefBrowserContext.
+ if (CefBrowserContext::FromBrowserContext(
+ browser->GetBrowserContext()) ==
+ CefBrowserContext::FromBrowserContext(
+ active_browser_impl->GetBrowserContext())) {
+ browser = active_browser_impl;
+ } else {
+ LOG(WARNING) << "Browser with tabId "
+ << active_browser->GetIdentifier()
+ << " cannot be accessed because is uses a different "
+ "CefRequestContext";
+ }
+ }
+ }
+ }
+
+ // May be null during startup/shutdown.
+ return browser;
+}
+
+bool CefExtensionFunctionDetails::CanAccessBrowser(
+ CefRefPtr<AlloyBrowserHostImpl> target) const {
+ DCHECK(target);
+
+ // Start with the browser hosting the extension.
+ CefRefPtr<AlloyBrowserHostImpl> browser = GetSenderBrowser();
+ if (browser == target) {
+ // A sender can always access itself.
+ return true;
+ }
+
+ if (browser && browser->client()) {
+ CefRefPtr<CefExtensionHandler> handler = GetCefExtension()->GetHandler();
+ if (handler) {
+ return handler->CanAccessBrowser(
+ GetCefExtension(), browser.get(),
+ function_->include_incognito_information(), target);
+ }
+ }
+
+ // Default to allowing access.
+ return true;
+}
+
+CefRefPtr<AlloyBrowserHostImpl>
+CefExtensionFunctionDetails::GetBrowserForTabIdFirstTime(
+ int tab_id,
+ std::string* error_message) const {
+ DCHECK(!get_browser_called_first_time_);
+ get_browser_called_first_time_ = true;
+
+ CefRefPtr<AlloyBrowserHostImpl> browser;
+
+ if (tab_id >= 0) {
+ // May be an invalid tabId or in the wrong BrowserContext.
+ browser = GetBrowserForTabId(tab_id, function_->browser_context());
+ if (!browser || !browser->web_contents() || !CanAccessBrowser(browser)) {
+ if (error_message) {
+ *error_message = ErrorUtils::FormatErrorMessage(
+ keys::kTabNotFoundError, base::NumberToString(tab_id));
+ }
+ return nullptr;
+ }
+ } else {
+ // May return NULL during shutdown.
+ browser = GetCurrentBrowser();
+ if (!browser || !browser->web_contents()) {
+ if (error_message) {
+ *error_message = keys::kNoCurrentWindowError;
+ }
+ return nullptr;
+ }
+ }
+
+ return browser;
+}
+
+CefRefPtr<AlloyBrowserHostImpl>
+CefExtensionFunctionDetails::GetBrowserForTabIdAgain(
+ int tab_id,
+ std::string* error_message) const {
+ DCHECK_GE(tab_id, 0);
+ DCHECK(get_browser_called_first_time_);
+
+ // May return NULL during shutdown.
+ CefRefPtr<AlloyBrowserHostImpl> browser =
+ GetBrowserForTabId(tab_id, function_->browser_context());
+ if (!browser || !browser->web_contents()) {
+ if (error_message) {
+ *error_message = ErrorUtils::FormatErrorMessage(
+ keys::kTabNotFoundError, base::NumberToString(tab_id));
+ }
+ }
+ return browser;
+}
+
+bool CefExtensionFunctionDetails::LoadFile(const std::string& file,
+ LoadFileCallback callback) const {
+ // Start with the browser hosting the extension.
+ CefRefPtr<AlloyBrowserHostImpl> browser = GetSenderBrowser();
+ if (browser && browser->client()) {
+ CefRefPtr<CefExtensionHandler> handler = GetCefExtension()->GetHandler();
+ if (handler) {
+ CefRefPtr<CefGetExtensionLoadFileCallbackImpl> cef_callback(
+ new CefGetExtensionLoadFileCallbackImpl(file, std::move(callback)));
+ if (handler->GetExtensionResource(GetCefExtension(), browser.get(), file,
+ cef_callback)) {
+ return true;
+ }
+ cef_callback->Disconnect();
+ }
+ }
+
+ return false;
+}
+
+CefExtensionFunctionDetails::OpenTabParams::OpenTabParams() {}
+
+CefExtensionFunctionDetails::OpenTabParams::~OpenTabParams() {}
+
+std::unique_ptr<api::tabs::Tab> CefExtensionFunctionDetails::OpenTab(
+ const OpenTabParams& params,
+ bool user_gesture,
+ std::string* error_message) const {
+ CefRefPtr<AlloyBrowserHostImpl> sender_browser = GetSenderBrowser();
+ if (!sender_browser) {
+ return nullptr;
+ }
+
+ // windowId defaults to "current" window.
+ int window_id = extension_misc::kCurrentWindowId;
+ if (params.window_id.has_value()) {
+ window_id = *params.window_id;
+ }
+
+ // CEF doesn't have the concept of windows containing tab strips so we'll
+ // select an "active browser" for BrowserContext sharing instead.
+ CefRefPtr<AlloyBrowserHostImpl> active_browser =
+ GetBrowserForTabIdFirstTime(window_id, error_message);
+ if (!active_browser) {
+ return nullptr;
+ }
+
+ // If an opener browser was specified then we expect it to exist.
+ int opener_browser_id = -1;
+ if (params.opener_tab_id.has_value() && *params.opener_tab_id >= 0) {
+ if (GetBrowserForTabIdAgain(*params.opener_tab_id, error_message)) {
+ opener_browser_id = *params.opener_tab_id;
+ } else {
+ return nullptr;
+ }
+ }
+
+ GURL url;
+ if (params.url.has_value()) {
+ std::string url_string = *params.url;
+ if (!ExtensionTabUtil::PrepareURLForNavigation(
+ url_string, function()->extension(), &url, error_message)) {
+ return nullptr;
+ }
+ }
+
+ // Default to foreground for the new tab. The presence of 'active' property
+ // will override this default.
+ bool active = true;
+ if (params.active.has_value()) {
+ active = *params.active;
+ }
+
+ // CEF doesn't use the index value but we let the client see/modify it.
+ int index = 0;
+ if (params.index.has_value()) {
+ index = *params.index;
+ }
+
+ auto cef_browser_context = CefBrowserContext::FromBrowserContext(
+ active_browser->GetBrowserContext());
+
+ // A CEF representation should always exist.
+ CefRefPtr<CefExtension> cef_extension =
+ cef_browser_context->GetExtension(function()->extension()->id());
+ DCHECK(cef_extension);
+ if (!cef_extension) {
+ return nullptr;
+ }
+
+ // Always use the same request context that the extension was registered with.
+ // GetLoaderContext() will return NULL for internal extensions.
+ CefRefPtr<CefRequestContext> request_context =
+ cef_extension->GetLoaderContext();
+ if (!request_context) {
+ return nullptr;
+ }
+
+ CefBrowserCreateParams create_params;
+ create_params.url = url.spec();
+ create_params.request_context = request_context;
+ create_params.window_info.reset(new CefWindowInfo);
+
+#if BUILDFLAG(IS_WIN)
+ create_params.window_info->SetAsPopup(nullptr, CefString());
+#endif
+
+ // Start with the active browser's settings.
+ create_params.client = active_browser->GetClient();
+ create_params.settings = active_browser->settings();
+
+ CefRefPtr<CefExtensionHandler> handler = cef_extension->GetHandler();
+ if (handler &&
+ handler->OnBeforeBrowser(cef_extension, sender_browser.get(),
+ active_browser.get(), index, create_params.url,
+ active, *create_params.window_info,
+ create_params.client, create_params.settings)) {
+ // Cancel the browser creation.
+ return nullptr;
+ }
+
+ if (active_browser->is_views_hosted()) {
+ // The new browser will also be Views hosted.
+ create_params.popup_with_views_hosted_opener = true;
+ create_params.window_info.reset();
+ }
+
+ // Browser creation may fail under certain rare circumstances.
+ CefRefPtr<AlloyBrowserHostImpl> new_browser =
+ AlloyBrowserHostImpl::Create(create_params);
+ if (!new_browser) {
+ return nullptr;
+ }
+
+ // Return data about the newly created tab.
+ auto extension = function()->extension();
+ auto web_contents = new_browser->web_contents();
+ auto result = CreateTabObject(new_browser, opener_browser_id, active, index);
+ auto scrub_tab_behavior = ExtensionTabUtil::GetScrubTabBehavior(
+ extension, extensions::Feature::Context::UNSPECIFIED_CONTEXT,
+ web_contents);
+ ExtensionTabUtil::ScrubTabForExtension(extension, web_contents, &result,
+ scrub_tab_behavior);
+ return base::WrapUnique(new api::tabs::Tab(std::move(result)));
+}
+
+api::tabs::Tab CefExtensionFunctionDetails::CreateTabObject(
+ CefRefPtr<AlloyBrowserHostImpl> new_browser,
+ int opener_browser_id,
+ bool active,
+ int index) const {
+ content::WebContents* contents = new_browser->web_contents();
+
+ bool is_loading = contents->IsLoading();
+ api::tabs::Tab tab_object;
+ tab_object.id = new_browser->GetIdentifier();
+ tab_object.index = index;
+ tab_object.window_id = *tab_object.id;
+ tab_object.status = is_loading ? api::tabs::TAB_STATUS_LOADING
+ : api::tabs::TAB_STATUS_COMPLETE;
+ tab_object.active = active;
+ tab_object.selected = true;
+ tab_object.highlighted = true;
+ tab_object.pinned = false;
+ // TODO(extensions): Use RecentlyAudibleHelper to populate |audible|.
+ tab_object.discarded = false;
+ tab_object.auto_discardable = false;
+ tab_object.muted_info = CreateMutedInfo(contents);
+ tab_object.incognito = false;
+ gfx::Size contents_size = contents->GetContainerBounds().size();
+ tab_object.width = contents_size.width();
+ tab_object.height = contents_size.height();
+ tab_object.url = contents->GetURL().spec();
+ tab_object.title = base::UTF16ToUTF8(contents->GetTitle());
+
+ content::NavigationEntry* entry = contents->GetController().GetVisibleEntry();
+ if (entry && entry->GetFavicon().valid) {
+ tab_object.fav_icon_url = entry->GetFavicon().url.spec();
+ }
+
+ if (opener_browser_id >= 0) {
+ tab_object.opener_tab_id = opener_browser_id;
+ }
+
+ return tab_object;
+}
+
+// static
+api::tabs::MutedInfo CefExtensionFunctionDetails::CreateMutedInfo(
+ content::WebContents* contents) {
+ DCHECK(contents);
+ api::tabs::MutedInfo info;
+ info.muted = contents->IsAudioMuted();
+ // TODO(cef): Maybe populate |info.reason|.
+ return info;
+}
+
+CefRefPtr<CefExtension> CefExtensionFunctionDetails::GetCefExtension() const {
+ if (!cef_extension_) {
+ cef_extension_ =
+ CefBrowserContext::FromBrowserContext(function_->browser_context())
+ ->GetExtension(function_->extension_id());
+ DCHECK(cef_extension_);
+ }
+ return cef_extension_;
+}
+
+} // namespace extensions
diff --git a/libcef/browser/extensions/extension_function_details.h b/libcef/browser/extensions/extension_function_details.h
new file mode 100644
index 00000000..e47b3b48
--- /dev/null
+++ b/libcef/browser/extensions/extension_function_details.h
@@ -0,0 +1,151 @@
+// Copyright 2017 the Chromium Embedded Framework Authors. Portions copyright
+// 2014 The Chromium Authors. All rights reserved. Use of this source code is
+// governed by a BSD-style license that can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_EXTENSIONS_EXTENSION_FUNCTION_DETAILS_H_
+#define CEF_LIBCEF_BROWSER_EXTENSIONS_EXTENSION_FUNCTION_DETAILS_H_
+
+#include "libcef/browser/alloy/alloy_browser_host_impl.h"
+
+#include "include/cef_extension.h"
+
+#include "base/functional/callback_forward.h"
+#include "chrome/common/extensions/api/tabs.h"
+#include "ui/gfx/native_widget_types.h"
+
+class Profile;
+class ExtensionFunction;
+
+namespace content {
+class WebContents;
+}
+
+namespace extensions {
+
+// Provides CEF-specific details to ExtensionFunction implementations.
+// Based on chrome/browser/extensions/chrome_extension_function_details.h.
+class CefExtensionFunctionDetails {
+ public:
+ // Constructs a new ChromeExtensionFunctionDetails instance for |function|.
+ // This instance does not own |function| and must outlive it.
+ explicit CefExtensionFunctionDetails(ExtensionFunction* function);
+
+ CefExtensionFunctionDetails(const CefExtensionFunctionDetails&) = delete;
+ CefExtensionFunctionDetails& operator=(const CefExtensionFunctionDetails&) =
+ delete;
+
+ ~CefExtensionFunctionDetails();
+
+ Profile* GetProfile() const;
+
+ // Get the "sender" browser that is hosting the extension. May return NULL
+ // during startup/shutdown.
+ CefRefPtr<AlloyBrowserHostImpl> GetSenderBrowser() const;
+
+ // Get the "current" browser that will be acted on by this extension function,
+ // if any. When mapping from a tabId use the GetBrowserForTabId* methods
+ // instead of calling this method directly.
+ //
+ // Many extension APIs operate relative to the browser that the calling code
+ // is running inside of. For example, popups and tabs all have a containing
+ // browser, but background pages and notification bubbles do not. Other APIs,
+ // like chrome.tabs.*, can act on either a specific browser (specified via the
+ // tabId parameter) or should allow the client to determine the most
+ // appropriate browser (for example, the browser that representing the
+ // foreground window).
+ //
+ // Incognito browsers should not be considered unless the calling extension
+ // has incognito access enabled. CEF does not internally enforce incognito
+ // status so we pass this flag to client callbacks for consideration.
+ //
+ // This method can return NULL if there is no matching browser, which can
+ // happen if only incognito windows are open, or early in startup or shutdown
+ // shutdown when there are no active windows.
+ CefRefPtr<AlloyBrowserHostImpl> GetCurrentBrowser() const;
+
+ // Returns true if the sender browser can access |target|. When mapping from a
+ // tabId use the GetBrowserForTabId* methods instead of calling this method
+ // directly.
+ bool CanAccessBrowser(CefRefPtr<AlloyBrowserHostImpl> target) const;
+
+ // Returns the browser matching |tab_id| or NULL if the browser cannot be
+ // found or does not have a WebContents. If |tab_id| is < 0 the "current"
+ // browser will be returned. |error_message| can optionally be passed in and
+ // will be set with an appropriate message on error. This method should only
+ // be called one time per extension function and will check all necessary
+ // client permissions.
+ CefRefPtr<AlloyBrowserHostImpl> GetBrowserForTabIdFirstTime(
+ int tab_id,
+ std::string* error_message) const;
+
+ // Returns the browser matching |tab_id| or NULL if the browser cannot be
+ // found or does not have a WebContents. |tab_id| must be >= 0.
+ // |error_message| can optionally be passed in and will be set with an
+ // appropriate message on error. This method should be called only after
+ // GetBrowserForTabIdFirstTime() has succeeded for the same |tab_id|.
+ CefRefPtr<AlloyBrowserHostImpl> GetBrowserForTabIdAgain(
+ int tab_id,
+ std::string* error_message) const;
+
+ // Give the client a chance to handle |file|. |callback| will be executed
+ // once the file contents have been loaded. Returns false if the file is
+ // unhandled.
+ using LoadFileCallback =
+ base::OnceCallback<void(std::unique_ptr<std::string>)>;
+ bool LoadFile(const std::string& file, LoadFileCallback callback) const;
+
+ struct OpenTabParams {
+ OpenTabParams();
+ ~OpenTabParams();
+
+ bool create_browser_if_needed = false;
+ absl::optional<int> window_id;
+ absl::optional<int> opener_tab_id;
+ absl::optional<std::string> url;
+ absl::optional<bool> active;
+ absl::optional<bool> pinned;
+ absl::optional<int> index;
+ absl::optional<int> bookmark_id;
+ };
+
+ // Opens a new tab given creation parameters |params|. Returns a Tab object
+ // if successful, or NULL and optionally sets |error_message| if an error
+ // occurs.
+ std::unique_ptr<api::tabs::Tab> OpenTab(const OpenTabParams& params,
+ bool user_gesture,
+ std::string* error_message) const;
+
+ // Creates a Tab object (see chrome/common/extensions/api/tabs.json) with
+ // information about the state of a browser tab. Depending on the
+ // permissions of the extension, the object may or may not include sensitive
+ // data such as the tab's URL.
+ api::tabs::Tab CreateTabObject(CefRefPtr<AlloyBrowserHostImpl> new_browser,
+ int opener_browser_id,
+ bool active,
+ int index) const;
+
+ // Creates a tab MutedInfo object (see chrome/common/extensions/api/tabs.json)
+ // with information about the mute state of a browser tab.
+ static api::tabs::MutedInfo CreateMutedInfo(content::WebContents* contents);
+
+ // Returns a pointer to the associated ExtensionFunction
+ ExtensionFunction* function() { return function_; }
+ const ExtensionFunction* function() const { return function_; }
+
+ protected:
+ CefRefPtr<CefExtension> GetCefExtension() const;
+
+ private:
+ // The function for which these details have been created. Must outlive the
+ // CefExtensionFunctionDetails instance.
+ ExtensionFunction* function_;
+
+ mutable CefRefPtr<CefExtension> cef_extension_;
+
+ // Verifies correct usage of GetBrowserForTabId* methods.
+ mutable bool get_browser_called_first_time_ = false;
+};
+
+} // namespace extensions
+
+#endif // CEF_LIBCEF_BROWSER_EXTENSIONS_EXTENSION_FUNCTION_DETAILS_H_
diff --git a/libcef/browser/extensions/extension_host_delegate.cc b/libcef/browser/extensions/extension_host_delegate.cc
new file mode 100644
index 00000000..901920f7
--- /dev/null
+++ b/libcef/browser/extensions/extension_host_delegate.cc
@@ -0,0 +1,72 @@
+// Copyright 2017 the Chromium Embedded Framework Authors. Portions copyright
+// 2014 The Chromium Authors. All rights reserved. Use of this source code is
+// governed by a BSD-style license that can be found in the LICENSE file.
+
+#include "libcef/browser/extensions/extension_host_delegate.h"
+
+#include "libcef/browser/extensions/extensions_browser_client.h"
+
+#include "base/logging.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_delegate.h"
+
+namespace extensions {
+
+CefExtensionHostDelegate::CefExtensionHostDelegate(
+ AlloyBrowserHostImpl* browser) {}
+
+CefExtensionHostDelegate::~CefExtensionHostDelegate() {}
+
+void CefExtensionHostDelegate::OnExtensionHostCreated(
+ content::WebContents* web_contents) {}
+
+void CefExtensionHostDelegate::OnMainFrameCreatedForBackgroundPage(
+ ExtensionHost* host) {}
+
+content::JavaScriptDialogManager*
+CefExtensionHostDelegate::GetJavaScriptDialogManager() {
+ // Never routed here from AlloyBrowserHostImpl.
+ NOTREACHED();
+ return nullptr;
+}
+
+void CefExtensionHostDelegate::CreateTab(
+ std::unique_ptr<content::WebContents> web_contents,
+ const std::string& extension_id,
+ WindowOpenDisposition disposition,
+ const gfx::Rect& initial_rect,
+ bool user_gesture) {
+ // TODO(cef): Add support for extensions opening popup windows.
+ NOTIMPLEMENTED();
+}
+
+void CefExtensionHostDelegate::ProcessMediaAccessRequest(
+ content::WebContents* web_contents,
+ const content::MediaStreamRequest& request,
+ content::MediaResponseCallback callback,
+ const Extension* extension) {
+ // Never routed here from AlloyBrowserHostImpl.
+ NOTREACHED();
+}
+
+bool CefExtensionHostDelegate::CheckMediaAccessPermission(
+ content::RenderFrameHost* render_frame_host,
+ const GURL& security_origin,
+ blink::mojom::MediaStreamType type,
+ const Extension* extension) {
+ // Never routed here from AlloyBrowserHostImpl.
+ NOTREACHED();
+ return false;
+}
+
+content::PictureInPictureResult CefExtensionHostDelegate::EnterPictureInPicture(
+ content::WebContents* web_contents) {
+ NOTREACHED();
+ return content::PictureInPictureResult::kNotSupported;
+}
+
+void CefExtensionHostDelegate::ExitPictureInPicture() {
+ NOTREACHED();
+}
+
+} // namespace extensions
diff --git a/libcef/browser/extensions/extension_host_delegate.h b/libcef/browser/extensions/extension_host_delegate.h
new file mode 100644
index 00000000..60f456ac
--- /dev/null
+++ b/libcef/browser/extensions/extension_host_delegate.h
@@ -0,0 +1,47 @@
+// Copyright 2017 the Chromium Embedded Framework Authors. Portions copyright
+// 2014 The Chromium Authors. All rights reserved. Use of this source code is
+// governed by a BSD-style license that can be found in the LICENSE file.
+
+#ifndef LIBCEF_BROWSER_EXTENSIONS_EXTENSION_HOST_DELEGATE_H_
+#define LIBCEF_BROWSER_EXTENSIONS_EXTENSION_HOST_DELEGATE_H_
+
+#include "extensions/browser/extension_host_delegate.h"
+
+class AlloyBrowserHostImpl;
+
+namespace extensions {
+
+class CefExtensionHostDelegate : public ExtensionHostDelegate {
+ public:
+ explicit CefExtensionHostDelegate(AlloyBrowserHostImpl* browser);
+
+ CefExtensionHostDelegate(const CefExtensionHostDelegate&) = delete;
+ CefExtensionHostDelegate& operator=(const CefExtensionHostDelegate&) = delete;
+
+ ~CefExtensionHostDelegate() override;
+
+ // ExtensionHostDelegate implementation.
+ void OnExtensionHostCreated(content::WebContents* web_contents) override;
+ void OnMainFrameCreatedForBackgroundPage(ExtensionHost* host) override;
+ content::JavaScriptDialogManager* GetJavaScriptDialogManager() override;
+ void CreateTab(std::unique_ptr<content::WebContents> web_contents,
+ const std::string& extension_id,
+ WindowOpenDisposition disposition,
+ const gfx::Rect& initial_rect,
+ bool user_gesture) override;
+ void ProcessMediaAccessRequest(content::WebContents* web_contents,
+ const content::MediaStreamRequest& request,
+ content::MediaResponseCallback callback,
+ const Extension* extension) override;
+ bool CheckMediaAccessPermission(content::RenderFrameHost* render_frame_host,
+ const GURL& security_origin,
+ blink::mojom::MediaStreamType type,
+ const Extension* extension) override;
+ content::PictureInPictureResult EnterPictureInPicture(
+ content::WebContents* web_contents) override;
+ void ExitPictureInPicture() override;
+};
+
+} // namespace extensions
+
+#endif // LIBCEF_BROWSER_EXTENSIONS_EXTENSION_HOST_DELEGATE_H_
diff --git a/libcef/browser/extensions/extension_system.cc b/libcef/browser/extensions/extension_system.cc
new file mode 100644
index 00000000..605493f5
--- /dev/null
+++ b/libcef/browser/extensions/extension_system.cc
@@ -0,0 +1,725 @@
+// Copyright 2015 The Chromium Embedded Framework Authors.
+// Portions copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/extensions/extension_system.h"
+
+#include <string>
+
+#include "libcef/browser/extension_impl.h"
+#include "libcef/browser/extensions/value_store/cef_value_store_factory.h"
+#include "libcef/browser/thread_util.h"
+#include "libcef/common/extensions/extensions_util.h"
+
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/functional/bind.h"
+#include "base/json/json_string_value_serializer.h"
+#include "base/path_service.h"
+#include "base/strings/string_tokenizer.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_restrictions.h"
+#include "chrome/browser/pdf/pdf_extension_util.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/chrome_paths.h"
+#include "components/crx_file/id_util.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/notification_details.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/browser/notification_source.h"
+#include "content/public/browser/plugin_service.h"
+#include "content/public/browser/render_process_host.h"
+#include "extensions/browser/api/app_runtime/app_runtime_api.h"
+#include "extensions/browser/extension_prefs.h"
+#include "extensions/browser/extension_registry.h"
+#include "extensions/browser/info_map.h"
+#include "extensions/browser/notification_types.h"
+#include "extensions/browser/null_app_sorting.h"
+#include "extensions/browser/quota_service.h"
+#include "extensions/browser/renderer_startup_helper.h"
+#include "extensions/browser/service_worker_manager.h"
+#include "extensions/browser/state_store.h"
+#include "extensions/browser/unloaded_extension_reason.h"
+#include "extensions/common/constants.h"
+#include "extensions/common/extension_messages.h"
+#include "extensions/common/file_util.h"
+#include "extensions/common/manifest_constants.h"
+#include "extensions/common/manifest_handlers/mime_types_handler.h"
+#include "extensions/common/switches.h"
+#include "net/base/mime_util.h"
+
+using content::BrowserContext;
+
+namespace extensions {
+
+namespace {
+
+// Implementation based on ComponentLoader::ParseManifest.
+absl::optional<base::Value::Dict> ParseManifest(
+ base::StringPiece manifest_contents) {
+ JSONStringValueDeserializer deserializer(manifest_contents);
+ std::unique_ptr<base::Value> manifest =
+ deserializer.Deserialize(nullptr, nullptr);
+
+ if (!manifest.get() || !manifest->is_dict()) {
+ LOG(ERROR) << "Failed to parse extension manifest.";
+ return absl::nullopt;
+ }
+
+ return std::move(*manifest).TakeDict();
+}
+
+void ExecuteLoadFailure(CefRefPtr<CefExtensionHandler> handler,
+ cef_errorcode_t result) {
+ if (!handler) {
+ return;
+ }
+
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(CEF_UIT, base::BindOnce(ExecuteLoadFailure, handler, result));
+ return;
+ }
+
+ handler->OnExtensionLoadFailed(result);
+}
+
+void LoadExtensionOnUIThread(base::WeakPtr<CefExtensionSystem> context,
+ base::Value::Dict manifest,
+ const base::FilePath& root_directory,
+ bool internal,
+ CefRefPtr<CefRequestContext> loader_context,
+ CefRefPtr<CefExtensionHandler> handler) {
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(CEF_UIT, base::BindOnce(LoadExtensionOnUIThread, context,
+ std::move(manifest), root_directory,
+ internal, loader_context, handler));
+ return;
+ }
+
+ if (context) {
+ context->LoadExtension(std::move(manifest), root_directory, internal,
+ loader_context, handler);
+ }
+}
+
+void LoadExtensionWithManifest(base::WeakPtr<CefExtensionSystem> context,
+ const std::string& manifest_contents,
+ const base::FilePath& root_directory,
+ bool internal,
+ CefRefPtr<CefRequestContext> loader_context,
+ CefRefPtr<CefExtensionHandler> handler) {
+ CEF_REQUIRE_BLOCKING();
+
+ auto manifest = ParseManifest(manifest_contents);
+ if (!manifest) {
+ LOG(WARNING) << "Failed to parse extension manifest";
+ ExecuteLoadFailure(handler, ERR_INVALID_ARGUMENT);
+ return;
+ }
+
+ LoadExtensionOnUIThread(context, std::move(*manifest), root_directory,
+ internal, loader_context, handler);
+}
+
+void LoadExtensionFromDisk(base::WeakPtr<CefExtensionSystem> context,
+ const base::FilePath& root_directory,
+ bool internal,
+ CefRefPtr<CefRequestContext> loader_context,
+ CefRefPtr<CefExtensionHandler> handler) {
+ CEF_REQUIRE_BLOCKING();
+
+ base::FilePath manifest_path = root_directory.AppendASCII("manifest.json");
+ std::string manifest_contents;
+ if (!base::ReadFileToString(manifest_path, &manifest_contents)) {
+ LOG(WARNING) << "Failed to read extension manifest from "
+ << manifest_path.MaybeAsASCII();
+ ExecuteLoadFailure(handler, ERR_FILE_NOT_FOUND);
+ return;
+ }
+
+ LoadExtensionWithManifest(context, manifest_contents, root_directory,
+ internal, loader_context, handler);
+}
+
+} // namespace
+
+CefExtensionSystem::CefExtensionSystem(BrowserContext* browser_context)
+ : browser_context_(browser_context),
+ initialized_(false),
+ registry_(ExtensionRegistry::Get(browser_context)),
+ renderer_helper_(
+ extensions::RendererStartupHelperFactory::GetForBrowserContext(
+ browser_context)),
+ weak_ptr_factory_(this) {
+ InitPrefs();
+}
+
+CefExtensionSystem::~CefExtensionSystem() {}
+
+void CefExtensionSystem::Init() {
+ DCHECK(!initialized_);
+
+ // There's complexity here related to the ordering of message delivery. For
+ // an extension to load correctly both the ExtensionMsg_Loaded and
+ // ExtensionMsg_ActivateExtension messages must be sent. These messages are
+ // currently sent by RendererStartupHelper, ExtensionWebContentsObserver, and
+ // this class. ExtensionMsg_Loaded is handled by Dispatcher::OnLoaded and adds
+ // the extension to |extensions_|. ExtensionMsg_ActivateExtension is handled
+ // by Dispatcher::OnActivateExtension and adds the extension to
+ // |active_extension_ids_|. If these messages are not sent correctly then
+ // ScriptContextSet::Register called from Dispatcher::DidCreateScriptContext
+ // will classify the extension incorrectly and API bindings will not be added.
+
+ // Inform the rest of the extensions system to start.
+ ready_.Signal();
+
+ // Add the internal PDF extension. PDF loading works as follows:
+ // 1. The PDF plugin is registered in libcef/common/content_client.cc
+ // ComputeBuiltInPlugins to handle the pdf::kInternalPluginMimeType.
+ // 2. The PDF extension is registered by the below call to AddExtension and
+ // associated with the "application/pdf" mime type.
+ // 3. Web content running in the owner CefBrowser requests to load a PDF file
+ // resource with the "application/pdf" mime type. This can be via a frame
+ // (main frame/iframe) or object/embed tag.
+ // 4. PluginResponseInterceptorURLLoaderThrottle intercepts the PDF resource
+ // load in the browser process and registers the PDF resource as a stream
+ // via MimeHandlerStreamManager::AddStream.
+ // 5. PluginResponseInterceptorURLLoaderThrottle::WillProcessResponse triggers
+ // creation of a MimeHandlerViewEmbedder in the browser process via
+ // MimeHandlerViewAttachHelper::OverrideBodyForInterceptedResponse.
+ // 6. MimeHandlerViewEmbedder::ReadyToCommitNavigation is called and sends a
+ // Mojo message to MimeHandlerViewContainerManager::SetInternalId in the
+ // owner renderer process.
+ // 7. The MimeHandlerViewContainerManager is created in the owner renderer
+ // process via MimeHandlerViewContainerManager::BindReceiver and the
+ // SetInternalId call arrives.
+ // 8. HTMLPlugInElement::RequestObject is called in the owner renderer process
+ // to handle the PDF file frame/object/embed tag. This results in calls to
+ // ContentBrowserClient::GetPluginMimeTypesWithExternalHandlers (browser
+ // process) and ContentRendererClient::IsPluginHandledExternally (owner
+ // renderer process), and determines that the plugin should be handled
+ // externally (handled_externally=true).
+ // 9. MimeHandlerViewContainerManager::IsManagedByContainerManager sends a
+ // Mojo message to MimeHandlerViewEmbedder::ReadyToCreateMimeHandlerView
+ // in the browser process.
+ // 10.MimeHandlerViewEmbedder::RenderFrameCreated triggers creation of a
+ // MimeHandlerViewGuest and CefMimeHandlerViewGuestDelegate in the browser
+ // process.
+ // 11.MimeHandlerViewGuest::CreateWebContents creates a new guest WebContents
+ // (is_guest_view=true) to host the PDF extension and the PDF resource
+ // stream is retrieved via MimeHandlerStreamManager::ReleaseStream.
+ // 12.MimeHandlerViewGuest::DidAttachToEmbedder calls
+ // CefMimeHandlerViewGuestDelegate::OnGuestAttached to associate the guest
+ // WebContents routing IDs with the owner CefBrowser. MimeHandlerViewGuest
+ // then loads the extension URL (index.html) in the guest WebContents.
+ // 13.Creation of the RenderFrame in the guest renderer process triggers a
+ // sync IPC call from AlloyContentRendererClient::MaybeCreateBrowser to
+ // CefBrowserInfoManager::GetBrowserInfo in the browser process to retrieve
+ // the CefBrowser information, which will be immediately available due to
+ // step 12.
+ // 14.The PDF extension begins to load. Extension resource requests are
+ // handled via ExtensionURLLoaderFactory::CreateLoaderAndStart in the
+ // browser process. Access to PDF extension resources is checked by
+ // CefExtensionsBrowserClient::AllowCrossRendererResourceLoad and
+ // PDF extension resources are provided from bundle via
+ // CefExtensionsBrowserClient::LoadResourceFromResourceBundle
+ // and CefComponentExtensionResourceManager. Access to chrome://resources
+ // is granted via CefExtensionWebContentsObserver::RenderViewCreated.
+ // 15.The PDF extension requests the PDF plugin to handle
+ // pdf::kInternalPluginMimeType. Approval arrives in the guest renderer
+ // process via ExtensionFrameHelper::OnExtensionResponse which calls
+ // NativeExtensionBindingsSystem::HandleResponse. This triggers creation of
+ // an HTMLPlugInElement via native V8 bindings to host the PDF plugin.
+ // 16.- With the old PPAPI plugin:
+ // The PDF extension calls chrome.mimeHandlerPrivate.getStreamInfo
+ // (chrome/browser/resources/pdf/browser_api.js) to retrieve the PDF
+ // resource stream. This API is implemented using Mojo as described in
+ // libcef/common/extensions/api/README.txt.
+ // - With the new PdfUnseasoned plugin:
+ // The PDF resource navigation is redirected by PdfNavigationThrottle and
+ // the stream contents are replaced by PdfURLLoaderRequestInterceptor.
+ // 17.HTMLPlugInElement::RequestObject is called in the guest renderer process
+ // and determines that the PDF plugin should be handled internally
+ // (handled_externally=false). A PluginDocument is created and
+ // AlloyContentRendererClient::OverrideCreatePlugin is called to create a
+ // WebPlugin.
+ // 18.- With the old PPAPI plugin:
+ // The PDF plugin is loaded by ChromeContentRendererClient::CreatePlugin
+ // calling RenderFrameImpl::CreatePlugin.
+ // - With the new PdfUnseasoned plugin:
+ // The PDF plugin is loaded by ChromeContentRendererClient::CreatePlugin
+ // calling pdf::CreateInternalPlugin.
+ // 19.The PDF extension and PDF plugin are now loaded. Print commands, if
+ // any, are handled in the guest renderer process by ChromePDFPrintClient
+ // and CefPrintRenderFrameHelperDelegate.
+ // 20.When navigating away from the PDF file or closing the owner CefBrowser
+ // the guest WebContents will be destroyed. This triggers a call to
+ // CefMimeHandlerViewGuestDelegate::OnGuestDetached which removes the
+ // routing ID association with the owner CefBrowser.
+ if (PdfExtensionEnabled()) {
+ if (auto manifest = ParseManifest(pdf_extension_util::GetManifest())) {
+ LoadExtension(std::move(*manifest),
+ base::FilePath(FILE_PATH_LITERAL("pdf")),
+ true /* internal */, nullptr, nullptr);
+ }
+ }
+
+ initialized_ = true;
+}
+
+void CefExtensionSystem::LoadExtension(
+ const base::FilePath& root_directory,
+ bool internal,
+ CefRefPtr<CefRequestContext> loader_context,
+ CefRefPtr<CefExtensionHandler> handler) {
+ CEF_REQUIRE_UIT();
+ CEF_POST_USER_VISIBLE_TASK(
+ base::BindOnce(LoadExtensionFromDisk, weak_ptr_factory_.GetWeakPtr(),
+ root_directory, internal, loader_context, handler));
+}
+
+void CefExtensionSystem::LoadExtension(
+ const std::string& manifest_contents,
+ const base::FilePath& root_directory,
+ bool internal,
+ CefRefPtr<CefRequestContext> loader_context,
+ CefRefPtr<CefExtensionHandler> handler) {
+ CEF_REQUIRE_UIT();
+ CEF_POST_USER_VISIBLE_TASK(base::BindOnce(
+ LoadExtensionWithManifest, weak_ptr_factory_.GetWeakPtr(),
+ manifest_contents, root_directory, internal, loader_context, handler));
+}
+
+// Implementation based on ComponentLoader::Add.
+void CefExtensionSystem::LoadExtension(
+ base::Value::Dict manifest,
+ const base::FilePath& root_directory,
+ bool internal,
+ CefRefPtr<CefRequestContext> loader_context,
+ CefRefPtr<CefExtensionHandler> handler) {
+ CEF_REQUIRE_UIT();
+
+// Internal extensions don't have a loader context. External extensions should.
+#if DCHECK_IS_ON()
+ if (internal) {
+ DCHECK(!loader_context);
+ } else {
+ DCHECK(loader_context);
+ }
+#endif
+
+ ComponentExtensionInfo info(std::move(manifest), root_directory, internal);
+ const Extension* extension = LoadExtension(info, loader_context, handler);
+ if (!extension) {
+ ExecuteLoadFailure(handler, ERR_FAILED);
+ }
+}
+
+// Implementation based on ExtensionService::RemoveComponentExtension.
+bool CefExtensionSystem::UnloadExtension(const std::string& extension_id) {
+ CEF_REQUIRE_UIT();
+ ExtensionMap::iterator it = extension_map_.find(extension_id);
+ if (it == extension_map_.end()) {
+ // No CEF representation so we've already unloaded it.
+ return false;
+ }
+
+ CefRefPtr<CefExtensionImpl> cef_extension =
+ static_cast<CefExtensionImpl*>(it->second.get());
+
+ // Erase first so that callbacks can't retrieve the unloaded extension.
+ extension_map_.erase(it);
+
+ cef_extension->OnExtensionUnloaded();
+
+ scoped_refptr<const Extension> extension(
+ registry_->GetInstalledExtension(extension_id));
+ UnloadExtension(extension_id, UnloadedExtensionReason::UNINSTALL);
+ if (extension.get()) {
+ registry_->TriggerOnUninstalled(
+ extension.get(), extensions::UNINSTALL_REASON_COMPONENT_REMOVED);
+ }
+
+ return true;
+}
+
+bool CefExtensionSystem::HasExtension(const std::string& extension_id) const {
+ return !!GetExtension(extension_id);
+}
+
+CefRefPtr<CefExtension> CefExtensionSystem::GetExtension(
+ const std::string& extension_id) const {
+ CEF_REQUIRE_UIT();
+ ExtensionMap::const_iterator it = extension_map_.find(extension_id);
+ if (it != extension_map_.end()) {
+ return it->second;
+ }
+ return nullptr;
+}
+
+CefExtensionSystem::ExtensionMap CefExtensionSystem::GetExtensions() const {
+ CEF_REQUIRE_UIT();
+ return extension_map_;
+}
+
+void CefExtensionSystem::OnRequestContextDeleted(CefRequestContext* context) {
+ CEF_REQUIRE_UIT();
+ DCHECK(context);
+
+ // Make a copy of the map because UnloadExtension will modify it.
+ // Don't add any references to |context|.
+ ExtensionMap map = extension_map_;
+ ExtensionMap::const_iterator it = map.begin();
+ for (; it != map.end(); ++it) {
+ CefRefPtr<CefExtensionImpl> cef_extension =
+ static_cast<CefExtensionImpl*>(it->second.get());
+ if (cef_extension->loader_context() == context) {
+ UnloadExtension(it->first);
+ }
+ }
+}
+
+void CefExtensionSystem::Shutdown() {
+ CEF_REQUIRE_UIT();
+// Only internal extensions should exist at this point.
+#if DCHECK_IS_ON()
+ ExtensionMap::iterator it = extension_map_.begin();
+ for (; it != extension_map_.end(); ++it) {
+ CefRefPtr<CefExtensionImpl> cef_extension =
+ static_cast<CefExtensionImpl*>(it->second.get());
+ DCHECK(!cef_extension->loader_context());
+ }
+#endif
+ extension_map_.clear();
+}
+
+void CefExtensionSystem::InitForRegularProfile(bool extensions_enabled) {
+ DCHECK(!initialized_);
+ service_worker_manager_.reset(new ServiceWorkerManager(browser_context_));
+ quota_service_.reset(new QuotaService);
+ app_sorting_.reset(new NullAppSorting);
+}
+
+ExtensionService* CefExtensionSystem::extension_service() {
+ return nullptr;
+}
+
+ManagementPolicy* CefExtensionSystem::management_policy() {
+ return nullptr;
+}
+
+ServiceWorkerManager* CefExtensionSystem::service_worker_manager() {
+ return service_worker_manager_.get();
+}
+
+UserScriptManager* CefExtensionSystem::user_script_manager() {
+ return nullptr;
+}
+
+StateStore* CefExtensionSystem::state_store() {
+ return state_store_.get();
+}
+
+StateStore* CefExtensionSystem::rules_store() {
+ return rules_store_.get();
+}
+
+StateStore* CefExtensionSystem::dynamic_user_scripts_store() {
+ return nullptr;
+}
+
+scoped_refptr<value_store::ValueStoreFactory>
+CefExtensionSystem::store_factory() {
+ return store_factory_;
+}
+
+InfoMap* CefExtensionSystem::info_map() {
+ if (!info_map_.get()) {
+ info_map_ = new InfoMap;
+ }
+ return info_map_.get();
+}
+
+QuotaService* CefExtensionSystem::quota_service() {
+ return quota_service_.get();
+}
+
+AppSorting* CefExtensionSystem::app_sorting() {
+ return app_sorting_.get();
+}
+
+// Implementation based on
+// ExtensionSystemImpl::RegisterExtensionWithRequestContexts.
+void CefExtensionSystem::RegisterExtensionWithRequestContexts(
+ const Extension* extension,
+ base::OnceClosure callback) {
+ // TODO(extensions): The |incognito_enabled| value should be set based on
+ // manifest settings.
+ content::GetIOThreadTaskRunner({})->PostTaskAndReply(
+ FROM_HERE,
+ base::BindOnce(&InfoMap::AddExtension, info_map(),
+ base::RetainedRef(extension), base::Time::Now(),
+ true, // incognito_enabled
+ false), // notifications_disabled
+ std::move(callback));
+}
+
+// Implementation based on
+// ExtensionSystemImpl::UnregisterExtensionWithRequestContexts.
+void CefExtensionSystem::UnregisterExtensionWithRequestContexts(
+ const std::string& extension_id) {
+ content::GetIOThreadTaskRunner({})->PostTask(
+ FROM_HERE,
+ base::BindOnce(&InfoMap::RemoveExtension, info_map(), extension_id));
+}
+
+const base::OneShotEvent& CefExtensionSystem::ready() const {
+ return ready_;
+}
+
+bool CefExtensionSystem::is_ready() const {
+ return ready_.is_signaled();
+}
+
+ContentVerifier* CefExtensionSystem::content_verifier() {
+ return nullptr;
+}
+
+std::unique_ptr<ExtensionSet> CefExtensionSystem::GetDependentExtensions(
+ const Extension* extension) {
+ return std::make_unique<ExtensionSet>();
+}
+
+void CefExtensionSystem::InstallUpdate(
+ const std::string& extension_id,
+ const std::string& public_key,
+ const base::FilePath& temp_dir,
+ bool install_immediately,
+ InstallUpdateCallback install_update_callback) {
+ NOTREACHED();
+ base::DeletePathRecursively(temp_dir);
+}
+
+void CefExtensionSystem::PerformActionBasedOnOmahaAttributes(
+ const std::string& extension_id,
+ const base::Value& attributes) {
+ NOTREACHED();
+}
+
+bool CefExtensionSystem::FinishDelayedInstallationIfReady(
+ const std::string& extension_id,
+ bool install_immediately) {
+ NOTREACHED();
+ return false;
+}
+
+CefExtensionSystem::ComponentExtensionInfo::ComponentExtensionInfo(
+ base::Value::Dict manifest,
+ const base::FilePath& directory,
+ bool internal)
+ : manifest(std::move(manifest)),
+ root_directory(directory),
+ internal(internal) {
+ if (!root_directory.IsAbsolute()) {
+ // This path structure is required by
+ // url_request_util::MaybeCreateURLRequestResourceBundleJob.
+ CHECK(base::PathService::Get(chrome::DIR_RESOURCES, &root_directory));
+ root_directory = root_directory.Append(directory);
+ }
+}
+
+void CefExtensionSystem::InitPrefs() {
+ store_factory_ =
+ new value_store::CefValueStoreFactory(browser_context_->GetPath());
+
+ Profile* profile = Profile::FromBrowserContext(browser_context_);
+
+ // Two state stores. The latter, which contains declarative rules, must be
+ // loaded immediately so that the rules are ready before we issue network
+ // requests.
+ state_store_ = std::make_unique<StateStore>(
+ profile, store_factory_, StateStore::BackendType::STATE, true);
+
+ rules_store_ = std::make_unique<StateStore>(
+ profile, store_factory_, StateStore::BackendType::RULES, false);
+}
+
+// Implementation based on ComponentLoader::CreateExtension.
+scoped_refptr<const Extension> CefExtensionSystem::CreateExtension(
+ const ComponentExtensionInfo& info,
+ std::string* utf8_error) {
+ // TODO(abarth): We should REQUIRE_MODERN_MANIFEST_VERSION once we've updated
+ // our component extensions to the new manifest version.
+ int flags = 0;
+ if (info.internal) {
+ // Internal extensions must have kPublicKey in the manifest.
+ flags |= Extension::REQUIRE_KEY;
+ }
+ return Extension::Create(
+ info.root_directory,
+ // Tests should continue to use the Manifest::COMMAND_LINE value here
+ // Some Chrome APIs will cause undesired effects if this is incorrect
+ // e.g.: alarms API has 1 minute minimum applied to Packed Extensions
+ info.internal ? mojom::ManifestLocation::kComponent
+ : mojom::ManifestLocation::kCommandLine,
+ info.manifest, flags, utf8_error);
+}
+
+// Implementation based on ComponentLoader::Load and
+// ExtensionService::AddExtension.
+const Extension* CefExtensionSystem::LoadExtension(
+ const ComponentExtensionInfo& info,
+ CefRefPtr<CefRequestContext> loader_context,
+ CefRefPtr<CefExtensionHandler> handler) {
+ std::string error;
+ scoped_refptr<const Extension> extension(CreateExtension(info, &error));
+ if (!extension.get()) {
+ LOG(ERROR) << error;
+ return nullptr;
+ }
+
+ if (registry_->GetInstalledExtension(extension->id())) {
+ LOG(ERROR) << "Extension with id " << extension->id()
+ << "is already installed";
+ return nullptr;
+ }
+
+ CefRefPtr<CefExtensionImpl> cef_extension =
+ new CefExtensionImpl(extension.get(), loader_context.get(), handler);
+
+ // Insert first so that callbacks can retrieve the loaded extension.
+ extension_map_.insert(std::make_pair(extension->id(), cef_extension));
+
+ // This may trigger additional callbacks.
+ registry_->AddEnabled(extension.get());
+ NotifyExtensionLoaded(extension.get());
+
+ cef_extension->OnExtensionLoaded();
+
+ return extension.get();
+}
+
+// Implementation based on ExtensionService::UnloadExtension.
+void CefExtensionSystem::UnloadExtension(const std::string& extension_id,
+ UnloadedExtensionReason reason) {
+ // Make sure the extension gets deleted after we return from this function.
+ int include_mask =
+ ExtensionRegistry::EVERYTHING & ~ExtensionRegistry::TERMINATED;
+ scoped_refptr<const Extension> extension(
+ registry_->GetExtensionById(extension_id, include_mask));
+
+ // This method can be called via PostTask, so the extension may have been
+ // unloaded by the time this runs.
+ if (!extension.get()) {
+ // In case the extension may have crashed/uninstalled. Allow the profile to
+ // clean up its RequestContexts.
+ UnregisterExtensionWithRequestContexts(extension_id);
+ return;
+ }
+
+ if (registry_->disabled_extensions().Contains(extension->id())) {
+ registry_->RemoveDisabled(extension->id());
+ // Make sure the profile cleans up its RequestContexts when an already
+ // disabled extension is unloaded (since they are also tracking the disabled
+ // extensions).
+ UnregisterExtensionWithRequestContexts(extension_id);
+ // Don't send the unloaded notification. It was sent when the extension
+ // was disabled.
+ } else {
+ // Remove the extension from the enabled list.
+ registry_->RemoveEnabled(extension->id());
+ NotifyExtensionUnloaded(extension.get(), reason);
+ }
+}
+
+// Implementation based on ExtensionService::NotifyExtensionLoaded.
+void CefExtensionSystem::NotifyExtensionLoaded(const Extension* extension) {
+ // The URLRequestContexts need to be first to know that the extension
+ // was loaded, otherwise a race can arise where a renderer that is created
+ // for the extension may try to load an extension URL with an extension id
+ // that the request context doesn't yet know about. The profile is responsible
+ // for ensuring its URLRequestContexts appropriately discover the loaded
+ // extension.
+ RegisterExtensionWithRequestContexts(
+ extension,
+ base::BindOnce(
+ &CefExtensionSystem::OnExtensionRegisteredWithRequestContexts,
+ weak_ptr_factory_.GetWeakPtr(), base::WrapRefCounted(extension)));
+
+ // Tell renderers about the loaded extension.
+ renderer_helper_->OnExtensionLoaded(*extension);
+
+ // Tell subsystems that use the ExtensionRegistryObserver::OnExtensionLoaded
+ // about the new extension.
+ //
+ // NOTE: It is important that this happen after notifying the renderers about
+ // the new extensions so that if we navigate to an extension URL in
+ // ExtensionRegistryObserver::OnExtensionLoaded the renderer is guaranteed to
+ // know about it.
+ registry_->TriggerOnLoaded(extension);
+
+ // Register plugins included with the extension.
+ // Implementation based on PluginManager::OnExtensionLoaded.
+ const MimeTypesHandler* handler = MimeTypesHandler::GetHandler(extension);
+ if (handler && !handler->handler_url().empty()) {
+ content::WebPluginInfo info;
+ info.type = content::WebPluginInfo::PLUGIN_TYPE_BROWSER_PLUGIN;
+ info.name = base::UTF8ToUTF16(extension->name());
+ info.path = base::FilePath::FromUTF8Unsafe(extension->url().spec());
+
+ for (std::set<std::string>::const_iterator mime_type =
+ handler->mime_type_set().begin();
+ mime_type != handler->mime_type_set().end(); ++mime_type) {
+ content::WebPluginMimeType mime_type_info;
+ mime_type_info.mime_type = *mime_type;
+ base::FilePath::StringType file_extension;
+ if (net::GetPreferredExtensionForMimeType(*mime_type, &file_extension)) {
+ mime_type_info.file_extensions.push_back(
+ base::FilePath(file_extension).AsUTF8Unsafe());
+ }
+ info.mime_types.push_back(mime_type_info);
+ }
+ content::PluginService* plugin_service =
+ content::PluginService::GetInstance();
+ plugin_service->RefreshPlugins();
+ plugin_service->RegisterInternalPlugin(info, true);
+ }
+}
+
+void CefExtensionSystem::OnExtensionRegisteredWithRequestContexts(
+ scoped_refptr<const extensions::Extension> extension) {
+ registry_->AddReady(extension);
+ if (registry_->enabled_extensions().Contains(extension->id())) {
+ registry_->TriggerOnReady(extension.get());
+ }
+}
+
+// Implementation based on ExtensionService::NotifyExtensionUnloaded.
+void CefExtensionSystem::NotifyExtensionUnloaded(
+ const Extension* extension,
+ UnloadedExtensionReason reason) {
+ // Unregister plugins included with the extension.
+ // Implementation based on PluginManager::OnExtensionUnloaded.
+ const MimeTypesHandler* handler = MimeTypesHandler::GetHandler(extension);
+ if (handler && !handler->handler_url().empty()) {
+ base::FilePath path =
+ base::FilePath::FromUTF8Unsafe(extension->url().spec());
+ content::PluginService* plugin_service =
+ content::PluginService::GetInstance();
+ plugin_service->UnregisterInternalPlugin(path);
+ plugin_service->RefreshPlugins();
+ }
+
+ registry_->TriggerOnUnloaded(extension, reason);
+
+ // Tell renderers about the unloaded extension.
+ renderer_helper_->OnExtensionUnloaded(*extension);
+
+ UnregisterExtensionWithRequestContexts(extension->id());
+}
+
+} // namespace extensions
diff --git a/libcef/browser/extensions/extension_system.h b/libcef/browser/extensions/extension_system.h
new file mode 100644
index 00000000..a3063285
--- /dev/null
+++ b/libcef/browser/extensions/extension_system.h
@@ -0,0 +1,201 @@
+// Copyright 2015 The Chromium Embedded Framework Authors.
+// Portions copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_EXTENSIONS_EXTENSION_SYSTEM_H_
+#define CEF_LIBCEF_BROWSER_EXTENSIONS_EXTENSION_SYSTEM_H_
+
+#include <map>
+#include <memory>
+
+#include "include/cef_extension_handler.h"
+#include "include/cef_request_context.h"
+
+#include "base/memory/weak_ptr.h"
+#include "base/one_shot_event.h"
+#include "extensions/browser/extension_system.h"
+
+namespace base {
+class DictionaryValue;
+}
+
+namespace content {
+class BrowserContext;
+}
+
+namespace extensions {
+
+class ExtensionRegistry;
+class ProcessManager;
+class RendererStartupHelper;
+
+// Used to manage extensions.
+class CefExtensionSystem : public ExtensionSystem {
+ public:
+ explicit CefExtensionSystem(content::BrowserContext* browser_context);
+
+ CefExtensionSystem(const CefExtensionSystem&) = delete;
+ CefExtensionSystem& operator=(const CefExtensionSystem&) = delete;
+
+ ~CefExtensionSystem() override;
+
+ // Initializes the extension system.
+ void Init();
+
+ // Load an extension. For internal (built-in) extensions set |internal| to
+ // true and |loader_context| and |handler| to NULL. For external extensions
+ // set |internal| to false and |loader_context| must be the request context
+ // that loaded the extension. |handler| is optional for internal extensions
+ // and, if specified, will receive extension-related callbacks.
+ void LoadExtension(const base::FilePath& root_directory,
+ bool internal,
+ CefRefPtr<CefRequestContext> loader_context,
+ CefRefPtr<CefExtensionHandler> handler);
+ void LoadExtension(const std::string& manifest_contents,
+ const base::FilePath& root_directory,
+ bool internal,
+ CefRefPtr<CefRequestContext> loader_context,
+ CefRefPtr<CefExtensionHandler> handler);
+ void LoadExtension(base::Value::Dict manifest,
+ const base::FilePath& root_directory,
+ bool internal,
+ CefRefPtr<CefRequestContext> loader_context,
+ CefRefPtr<CefExtensionHandler> handler);
+
+ // Unload the external extension identified by |extension_id|.
+ bool UnloadExtension(const std::string& extension_id);
+
+ // Returns true if an extension matching |extension_id| is loaded.
+ bool HasExtension(const std::string& extension_id) const;
+
+ // Returns the loaded extention matching |extension_id| or NULL if not found.
+ CefRefPtr<CefExtension> GetExtension(const std::string& extension_id) const;
+
+ using ExtensionMap = std::map<std::string, CefRefPtr<CefExtension>>;
+
+ // Returns the map of all loaded extensions.
+ ExtensionMap GetExtensions() const;
+
+ // Called when a request context is deleted. Unregisters any external
+ // extensions that were registered with this context.
+ void OnRequestContextDeleted(CefRequestContext* context);
+
+ // KeyedService implementation:
+ void Shutdown() override;
+
+ // ExtensionSystem implementation:
+ void InitForRegularProfile(bool extensions_enabled) override;
+ ExtensionService* extension_service() override;
+ ManagementPolicy* management_policy() override;
+ ServiceWorkerManager* service_worker_manager() override;
+ UserScriptManager* user_script_manager() override;
+ StateStore* state_store() override;
+ StateStore* rules_store() override;
+ StateStore* dynamic_user_scripts_store() override;
+ scoped_refptr<value_store::ValueStoreFactory> store_factory() override;
+ InfoMap* info_map() override;
+ QuotaService* quota_service() override;
+ AppSorting* app_sorting() override;
+ void RegisterExtensionWithRequestContexts(
+ const Extension* extension,
+ base::OnceClosure callback) override;
+ void UnregisterExtensionWithRequestContexts(
+ const std::string& extension_id) override;
+ const base::OneShotEvent& ready() const override;
+ bool is_ready() const override;
+ ContentVerifier* content_verifier() override;
+ std::unique_ptr<ExtensionSet> GetDependentExtensions(
+ const Extension* extension) override;
+ void InstallUpdate(const std::string& extension_id,
+ const std::string& public_key,
+ const base::FilePath& temp_dir,
+ bool install_immediately,
+ InstallUpdateCallback install_update_callback) override;
+ void PerformActionBasedOnOmahaAttributes(
+ const std::string& extension_id,
+ const base::Value& attributes) override;
+ bool FinishDelayedInstallationIfReady(const std::string& extension_id,
+ bool install_immediately) override;
+
+ bool initialized() const { return initialized_; }
+
+ private:
+ virtual void InitPrefs();
+
+ // Information about a registered component extension.
+ struct ComponentExtensionInfo {
+ ComponentExtensionInfo(base::Value::Dict manifest,
+ const base::FilePath& root_directory,
+ bool internal);
+
+ // The parsed contents of the extensions's manifest file.
+ base::Value::Dict manifest;
+
+ // Directory where the extension is stored.
+ base::FilePath root_directory;
+
+ // True if the extension is an internal (built-in) component.
+ bool internal;
+ };
+
+ scoped_refptr<const Extension> CreateExtension(
+ const ComponentExtensionInfo& info,
+ std::string* utf8_error);
+
+ // Loads a registered component extension.
+ const Extension* LoadExtension(const ComponentExtensionInfo& info,
+ CefRefPtr<CefRequestContext> loader_context,
+ CefRefPtr<CefExtensionHandler> handler);
+
+ // Unload the specified extension.
+ void UnloadExtension(const std::string& extension_id,
+ extensions::UnloadedExtensionReason reason);
+
+ // Handles sending notification that |extension| was loaded.
+ void NotifyExtensionLoaded(const Extension* extension);
+
+ // Handles sending notification that |extension| was unloaded.
+ void NotifyExtensionUnloaded(const Extension* extension,
+ UnloadedExtensionReason reason);
+
+ // Completes extension loading after URLRequestContexts have been updated
+ // on the IO thread.
+ void OnExtensionRegisteredWithRequestContexts(
+ scoped_refptr<const extensions::Extension> extension);
+
+ content::BrowserContext* browser_context_; // Not owned.
+
+ bool initialized_;
+
+ // Data to be accessed on the IO thread. Must outlive process_manager_.
+ scoped_refptr<InfoMap> info_map_;
+
+ std::unique_ptr<ServiceWorkerManager> service_worker_manager_;
+ std::unique_ptr<QuotaService> quota_service_;
+ std::unique_ptr<AppSorting> app_sorting_;
+
+ std::unique_ptr<StateStore> state_store_;
+ std::unique_ptr<StateStore> rules_store_;
+ scoped_refptr<value_store::ValueStoreFactory> store_factory_;
+
+ // Signaled when the extension system has completed its startup tasks.
+ base::OneShotEvent ready_;
+
+ // Sets of enabled/disabled/terminated/blacklisted extensions. Not owned.
+ ExtensionRegistry* registry_;
+
+ // The associated RendererStartupHelper. Guaranteed to outlive the
+ // ExtensionSystem, and thus us.
+ extensions::RendererStartupHelper* renderer_helper_;
+
+ // Map of extension ID to CEF extension object.
+ ExtensionMap extension_map_;
+
+ // Must be the last member.
+ base::WeakPtrFactory<CefExtensionSystem> weak_ptr_factory_;
+};
+
+} // namespace extensions
+
+#endif // CEF_LIBCEF_BROWSER_EXTENSIONS_EXTENSION_SYSTEM_H_
diff --git a/libcef/browser/extensions/extension_system_factory.cc b/libcef/browser/extensions/extension_system_factory.cc
new file mode 100644
index 00000000..ed8d9f12
--- /dev/null
+++ b/libcef/browser/extensions/extension_system_factory.cc
@@ -0,0 +1,55 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/extensions/extension_system_factory.h"
+
+#include "libcef/browser/extensions/extension_system.h"
+
+#include "chrome/browser/profiles/incognito_helpers.h"
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "extensions/browser/extension_prefs_factory.h"
+#include "extensions/browser/extension_registry_factory.h"
+
+using content::BrowserContext;
+
+namespace extensions {
+
+ExtensionSystem* CefExtensionSystemFactory::GetForBrowserContext(
+ BrowserContext* context) {
+ return static_cast<CefExtensionSystem*>(
+ GetInstance()->GetServiceForBrowserContext(context, true));
+}
+
+// static
+CefExtensionSystemFactory* CefExtensionSystemFactory::GetInstance() {
+ return base::Singleton<CefExtensionSystemFactory>::get();
+}
+
+CefExtensionSystemFactory::CefExtensionSystemFactory()
+ : ExtensionSystemProvider("CefExtensionSystem",
+ BrowserContextDependencyManager::GetInstance()) {
+ // Other factories that this factory depends on. See
+ // libcef/common/extensions/api/README.txt for additional details.
+ DependsOn(ExtensionPrefsFactory::GetInstance());
+ DependsOn(ExtensionRegistryFactory::GetInstance());
+}
+
+CefExtensionSystemFactory::~CefExtensionSystemFactory() {}
+
+KeyedService* CefExtensionSystemFactory::BuildServiceInstanceFor(
+ BrowserContext* context) const {
+ return new CefExtensionSystem(context);
+}
+
+BrowserContext* CefExtensionSystemFactory::GetBrowserContextToUse(
+ BrowserContext* context) const {
+ // Use a separate instance for incognito.
+ return chrome::GetBrowserContextOwnInstanceInIncognito(context);
+}
+
+bool CefExtensionSystemFactory::ServiceIsCreatedWithBrowserContext() const {
+ return true;
+}
+
+} // namespace extensions
diff --git a/libcef/browser/extensions/extension_system_factory.h b/libcef/browser/extensions/extension_system_factory.h
new file mode 100644
index 00000000..004ee93e
--- /dev/null
+++ b/libcef/browser/extensions/extension_system_factory.h
@@ -0,0 +1,42 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_EXTENSIONS_EXTENSION_SYSTEM_FACTORY_H_
+#define CEF_LIBCEF_BROWSER_EXTENSIONS_EXTENSION_SYSTEM_FACTORY_H_
+
+#include "base/memory/singleton.h"
+#include "extensions/browser/extension_system_provider.h"
+
+namespace extensions {
+
+// Factory that provides CefExtensionSystem.
+class CefExtensionSystemFactory : public ExtensionSystemProvider {
+ public:
+ CefExtensionSystemFactory(const CefExtensionSystemFactory&) = delete;
+ CefExtensionSystemFactory& operator=(const CefExtensionSystemFactory&) =
+ delete;
+
+ // ExtensionSystemProvider implementation:
+ ExtensionSystem* GetForBrowserContext(
+ content::BrowserContext* context) override;
+
+ static CefExtensionSystemFactory* GetInstance();
+
+ private:
+ friend struct base::DefaultSingletonTraits<CefExtensionSystemFactory>;
+
+ CefExtensionSystemFactory();
+ ~CefExtensionSystemFactory() override;
+
+ // BrowserContextKeyedServiceFactory implementation:
+ KeyedService* BuildServiceInstanceFor(
+ content::BrowserContext* context) const override;
+ content::BrowserContext* GetBrowserContextToUse(
+ content::BrowserContext* context) const override;
+ bool ServiceIsCreatedWithBrowserContext() const override;
+};
+
+} // namespace extensions
+
+#endif // CEF_LIBCEF_BROWSER_EXTENSIONS_EXTENSION_SYSTEM_FACTORY_H_
diff --git a/libcef/browser/extensions/extension_view_host.cc b/libcef/browser/extensions/extension_view_host.cc
new file mode 100644
index 00000000..8f2b19f3
--- /dev/null
+++ b/libcef/browser/extensions/extension_view_host.cc
@@ -0,0 +1,100 @@
+// Copyright 2017 the Chromium Embedded Framework Authors. Portions copyright
+// 2013 The Chromium Authors. All rights reserved. Use of this source code is
+// governed by a BSD-style license that can be found in the LICENSE file.
+
+#include "libcef/browser/extensions/extension_view_host.h"
+
+#include "libcef/browser/browser_platform_delegate.h"
+#include "libcef/browser/extensions/extension_host_delegate.h"
+
+#include "content/public/browser/web_contents.h"
+#include "extensions/browser/process_util.h"
+#include "third_party/blink/public/common/input/web_gesture_event.h"
+
+using content::NativeWebKeyboardEvent;
+using content::OpenURLParams;
+using content::WebContents;
+using content::WebContentsObserver;
+
+namespace extensions {
+
+CefExtensionViewHost::CefExtensionViewHost(AlloyBrowserHostImpl* browser,
+ const Extension* extension,
+ content::WebContents* host_contents,
+ const GURL& url,
+ mojom::ViewType host_type)
+ : ExtensionHost(new CefExtensionHostDelegate(browser),
+ extension,
+ host_contents->GetBrowserContext(),
+ host_contents,
+ url,
+ host_type) {
+ // Only used for dialogs and popups.
+ DCHECK(host_type == mojom::ViewType::kExtensionDialog ||
+ host_type == mojom::ViewType::kExtensionPopup);
+}
+
+CefExtensionViewHost::~CefExtensionViewHost() {}
+
+void CefExtensionViewHost::OnDidStopFirstLoad() {
+ // Nothing to do here, but don't call the base class method.
+}
+
+void CefExtensionViewHost::LoadInitialURL() {
+ if (process_util::GetPersistentBackgroundPageState(*extension(),
+ browser_context()) ==
+ process_util::PersistentBackgroundPageState::kNotReady) {
+ // Make sure the background page loads before any others.
+ host_registry_observation_.Observe(
+ ExtensionHostRegistry::Get(browser_context()));
+ return;
+ }
+
+ ExtensionHost::LoadInitialURL();
+}
+
+bool CefExtensionViewHost::IsBackgroundPage() const {
+ return false;
+}
+
+bool CefExtensionViewHost::ShouldAllowRendererInitiatedCrossProcessNavigation(
+ bool is_main_frame_navigation) {
+ // Block navigations that cause the main frame to navigate to non-extension
+ // content (i.e. to web content).
+ return !is_main_frame_navigation;
+}
+
+bool CefExtensionViewHost::PreHandleGestureEvent(
+ content::WebContents* source,
+ const blink::WebGestureEvent& event) {
+ // Disable pinch zooming.
+ return blink::WebInputEvent::IsPinchGestureEventType(event.GetType());
+}
+
+WebContents* CefExtensionViewHost::GetVisibleWebContents() const {
+ if (extension_host_type() == mojom::ViewType::kExtensionPopup) {
+ return host_contents();
+ }
+ return nullptr;
+}
+
+void CefExtensionViewHost::OnExtensionHostDocumentElementAvailable(
+ content::BrowserContext* host_browser_context,
+ ExtensionHost* extension_host) {
+ DCHECK(extension_host->extension());
+ if (host_browser_context != browser_context() ||
+ extension_host->extension() != extension() ||
+ extension_host->extension_host_type() !=
+ mojom::ViewType::kExtensionBackgroundPage) {
+ return;
+ }
+
+ DCHECK_EQ(process_util::PersistentBackgroundPageState::kReady,
+ process_util::GetPersistentBackgroundPageState(*extension(),
+ browser_context()));
+ // We only needed to wait for the background page to load, so stop observing.
+ host_registry_observation_.Reset();
+ LoadInitialURL();
+}
+
+} // namespace extensions
diff --git a/libcef/browser/extensions/extension_view_host.h b/libcef/browser/extensions/extension_view_host.h
new file mode 100644
index 00000000..2557e9e7
--- /dev/null
+++ b/libcef/browser/extensions/extension_view_host.h
@@ -0,0 +1,67 @@
+// Copyright 2017 the Chromium Embedded Framework Authors. Portions copyright
+// 2013 The Chromium Authors. All rights reserved. Use of this source code is
+// governed by a BSD-style license that can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_EXTENSIONS_EXTENSION_VIEW_HOST_H_
+#define CEF_LIBCEF_BROWSER_EXTENSIONS_EXTENSION_VIEW_HOST_H_
+
+#include <memory>
+
+#include "base/scoped_observation.h"
+#include "extensions/browser/extension_host.h"
+#include "extensions/browser/extension_host_registry.h"
+
+class AlloyBrowserHostImpl;
+
+namespace content {
+class WebContents;
+} // namespace content
+
+namespace extensions {
+
+// The ExtensionHost for an extension that backs a view in the browser UI. For
+// example, this could be an extension popup or dialog, but not a background
+// page. Object lifespan is managed by AlloyBrowserHostImpl. Based on
+// chrome/browser/extensions/extension_view_host.h.
+class CefExtensionViewHost : public ExtensionHost,
+ public ExtensionHostRegistry::Observer {
+ public:
+ CefExtensionViewHost(AlloyBrowserHostImpl* browser,
+ const Extension* extension,
+ content::WebContents* host_contents,
+ const GURL& url,
+ mojom::ViewType host_type);
+
+ CefExtensionViewHost(const CefExtensionViewHost&) = delete;
+ CefExtensionViewHost& operator=(const CefExtensionViewHost&) = delete;
+
+ ~CefExtensionViewHost() override;
+
+ // ExtensionHost methods:
+ void OnDidStopFirstLoad() override;
+ void LoadInitialURL() override;
+ bool IsBackgroundPage() const override;
+
+ // content::WebContentsDelegate methods:
+ bool ShouldAllowRendererInitiatedCrossProcessNavigation(
+ bool is_main_frame_navigation) override;
+ bool PreHandleGestureEvent(content::WebContents* source,
+ const blink::WebGestureEvent& event) override;
+
+ // extensions::ExtensionFunctionDispatcher::Delegate methods:
+ content::WebContents* GetVisibleWebContents() const override;
+
+ // ExtensionHostRegistry::Observer methods:
+ void OnExtensionHostDocumentElementAvailable(
+ content::BrowserContext* browser_context,
+ ExtensionHost* extension_host) override;
+
+ private:
+ base::ScopedObservation<ExtensionHostRegistry,
+ ExtensionHostRegistry::Observer>
+ host_registry_observation_{this};
+};
+
+} // namespace extensions
+
+#endif // CEF_LIBCEF_BROWSER_EXTENSIONS_EXTENSION_VIEW_HOST_H_
diff --git a/libcef/browser/extensions/extension_web_contents_observer.cc b/libcef/browser/extensions/extension_web_contents_observer.cc
new file mode 100644
index 00000000..6e50ebea
--- /dev/null
+++ b/libcef/browser/extensions/extension_web_contents_observer.cc
@@ -0,0 +1,60 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/extensions/extension_web_contents_observer.h"
+
+#include "chrome/common/webui_url_constants.h"
+#include "content/public/browser/child_process_security_policy.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/common/url_constants.h"
+#include "third_party/blink/public/common/chrome_debug_urls.h"
+
+namespace extensions {
+
+CefExtensionWebContentsObserver::CefExtensionWebContentsObserver(
+ content::WebContents* web_contents)
+ : ExtensionWebContentsObserver(web_contents),
+ content::WebContentsUserData<CefExtensionWebContentsObserver>(
+ *web_contents),
+ script_executor_(new ScriptExecutor(web_contents)) {}
+
+CefExtensionWebContentsObserver::~CefExtensionWebContentsObserver() {}
+
+// static
+void CefExtensionWebContentsObserver::CreateForWebContents(
+ content::WebContents* web_contents) {
+ content::WebContentsUserData<
+ CefExtensionWebContentsObserver>::CreateForWebContents(web_contents);
+
+ // Initialize this instance if necessary.
+ FromWebContents(web_contents)->Initialize();
+}
+
+void CefExtensionWebContentsObserver::RenderFrameCreated(
+ content::RenderFrameHost* render_frame_host) {
+ ExtensionWebContentsObserver::RenderFrameCreated(render_frame_host);
+
+ const Extension* extension = GetExtensionFromFrame(render_frame_host, false);
+ if (!extension) {
+ return;
+ }
+
+ int process_id = render_frame_host->GetProcess()->GetID();
+ auto policy = content::ChildProcessSecurityPolicy::GetInstance();
+
+ // Components of chrome that are implemented as extensions or platform apps
+ // are allowed to use chrome://resources/ and chrome://theme/ URLs.
+ if ((extension->is_extension() || extension->is_platform_app()) &&
+ Manifest::IsComponentLocation(extension->location())) {
+ policy->GrantRequestOrigin(
+ process_id, url::Origin::Create(GURL(blink::kChromeUIResourcesURL)));
+ policy->GrantRequestOrigin(
+ process_id, url::Origin::Create(GURL(chrome::kChromeUIThemeURL)));
+ }
+}
+
+WEB_CONTENTS_USER_DATA_KEY_IMPL(CefExtensionWebContentsObserver);
+
+} // namespace extensions
diff --git a/libcef/browser/extensions/extension_web_contents_observer.h b/libcef/browser/extensions/extension_web_contents_observer.h
new file mode 100644
index 00000000..f40b9750
--- /dev/null
+++ b/libcef/browser/extensions/extension_web_contents_observer.h
@@ -0,0 +1,50 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_EXTENSIONS_EXTENSION_WEB_CONTENTS_OBSERVER_H_
+#define CEF_LIBCEF_BROWSER_EXTENSIONS_EXTENSION_WEB_CONTENTS_OBSERVER_H_
+
+#include <memory>
+
+#include "base/observer_list.h"
+#include "content/public/browser/web_contents_user_data.h"
+#include "extensions/browser/extension_web_contents_observer.h"
+#include "extensions/browser/script_executor.h"
+
+namespace extensions {
+
+// The CEF version of ExtensionWebContentsObserver.
+class CefExtensionWebContentsObserver
+ : public ExtensionWebContentsObserver,
+ public content::WebContentsUserData<CefExtensionWebContentsObserver> {
+ public:
+ CefExtensionWebContentsObserver(const CefExtensionWebContentsObserver&) =
+ delete;
+ CefExtensionWebContentsObserver& operator=(
+ const CefExtensionWebContentsObserver&) = delete;
+
+ ~CefExtensionWebContentsObserver() override;
+
+ // Creates and initializes an instance of this class for the given
+ // |web_contents|, if it doesn't already exist.
+ static void CreateForWebContents(content::WebContents* web_contents);
+
+ ScriptExecutor* script_executor() { return script_executor_.get(); }
+
+ private:
+ friend class content::WebContentsUserData<CefExtensionWebContentsObserver>;
+
+ explicit CefExtensionWebContentsObserver(content::WebContents* web_contents);
+
+ // content::WebContentsObserver overrides.
+ void RenderFrameCreated(content::RenderFrameHost* render_frame_host) override;
+
+ std::unique_ptr<ScriptExecutor> script_executor_;
+
+ WEB_CONTENTS_USER_DATA_KEY_DECL();
+};
+
+} // namespace extensions
+
+#endif // CEF_LIBCEF_BROWSER_EXTENSIONS_EXTENSION_WEB_CONTENTS_OBSERVER_H_
diff --git a/libcef/browser/extensions/extensions_api_client.cc b/libcef/browser/extensions/extensions_api_client.cc
new file mode 100644
index 00000000..1d385ca9
--- /dev/null
+++ b/libcef/browser/extensions/extensions_api_client.cc
@@ -0,0 +1,84 @@
+// Copyright 2015 The Chromium Embedded Framework Authors.
+// Portions copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/extensions/extensions_api_client.h"
+
+#include "include/internal/cef_types_wrappers.h"
+#include "libcef/browser/browser_context.h"
+#include "libcef/browser/extensions/api/file_system/cef_file_system_delegate.h"
+#include "libcef/browser/extensions/api/storage/sync_value_store_cache.h"
+#include "libcef/browser/extensions/extension_web_contents_observer.h"
+#include "libcef/browser/extensions/mime_handler_view_guest_delegate.h"
+
+#include "base/memory/ptr_util.h"
+#include "chrome/browser/printing/print_view_manager.h"
+#include "chrome/browser/ui/pdf/chrome_pdf_web_contents_helper_client.h"
+#include "chrome/browser/ui/prefs/prefs_tab_helper.h"
+#include "components/pdf/browser/pdf_web_contents_helper.h"
+#include "components/zoom/zoom_controller.h"
+#include "extensions/browser/guest_view/extensions_guest_view_manager_delegate.h"
+#include "printing/mojom/print.mojom.h"
+
+namespace extensions {
+
+CefExtensionsAPIClient::CefExtensionsAPIClient() {}
+
+AppViewGuestDelegate* CefExtensionsAPIClient::CreateAppViewGuestDelegate()
+ const {
+ // TODO(extensions): Implement to support Apps.
+ NOTREACHED();
+ return nullptr;
+}
+
+std::unique_ptr<guest_view::GuestViewManagerDelegate>
+CefExtensionsAPIClient::CreateGuestViewManagerDelegate(
+ content::BrowserContext* context) const {
+ // The GuestViewManager instance associated with the returned Delegate, which
+ // will be retrieved in the future via GuestViewManager::FromBrowserContext,
+ // will be associated with the CefBrowserContext.
+ return base::WrapUnique(
+ new extensions::ExtensionsGuestViewManagerDelegate(context));
+}
+
+std::unique_ptr<MimeHandlerViewGuestDelegate>
+CefExtensionsAPIClient::CreateMimeHandlerViewGuestDelegate(
+ MimeHandlerViewGuest* guest) const {
+ return base::WrapUnique(new CefMimeHandlerViewGuestDelegate(guest));
+}
+
+void CefExtensionsAPIClient::AttachWebContentsHelpers(
+ content::WebContents* web_contents) const {
+ PrefsTabHelper::CreateForWebContents(web_contents);
+ printing::PrintViewManager::CreateForWebContents(web_contents);
+
+ // Used by the PDF extension.
+ pdf::PDFWebContentsHelper::CreateForWebContentsWithClient(
+ web_contents, std::unique_ptr<pdf::PDFWebContentsHelperClient>(
+ new ChromePDFWebContentsHelperClient()));
+
+ // Used by the tabs extension API.
+ zoom::ZoomController::CreateForWebContents(web_contents);
+}
+
+void CefExtensionsAPIClient::AddAdditionalValueStoreCaches(
+ content::BrowserContext* context,
+ const scoped_refptr<value_store::ValueStoreFactory>& factory,
+ SettingsChangedCallback observer,
+ std::map<settings_namespace::Namespace, ValueStoreCache*>* caches) {
+ // Add support for chrome.storage.sync.
+ // Because we don't support syncing with Google, we follow the behavior of
+ // chrome.storage.sync as if Chrome were permanently offline, by using a local
+ // store see: https://developer.chrome.com/apps/storage for more information
+ (*caches)[settings_namespace::SYNC] = new cef::SyncValueStoreCache(factory);
+}
+
+FileSystemDelegate* CefExtensionsAPIClient::GetFileSystemDelegate() {
+ if (!file_system_delegate_) {
+ file_system_delegate_ = std::make_unique<cef::CefFileSystemDelegate>();
+ }
+ return file_system_delegate_.get();
+}
+
+} // namespace extensions
diff --git a/libcef/browser/extensions/extensions_api_client.h b/libcef/browser/extensions/extensions_api_client.h
new file mode 100644
index 00000000..f1760a37
--- /dev/null
+++ b/libcef/browser/extensions/extensions_api_client.h
@@ -0,0 +1,47 @@
+// Copyright 2015 The Chromium Embedded Framework Authors.
+// Portions copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_EXTENSIONS_EXTENSIONS_API_CLIENT_H_
+#define CEF_LIBCEF_BROWSER_EXTENSIONS_EXTENSIONS_API_CLIENT_H_
+
+#include "components/value_store/value_store_factory.h"
+#include "extensions/browser/api/extensions_api_client.h"
+
+namespace extensions {
+
+class CefExtensionsAPIClient : public ExtensionsAPIClient {
+ public:
+ CefExtensionsAPIClient();
+
+ // ExtensionsAPIClient implementation.
+ AppViewGuestDelegate* CreateAppViewGuestDelegate() const override;
+ std::unique_ptr<guest_view::GuestViewManagerDelegate>
+ CreateGuestViewManagerDelegate(
+ content::BrowserContext* context) const override;
+ std::unique_ptr<MimeHandlerViewGuestDelegate>
+ CreateMimeHandlerViewGuestDelegate(
+ MimeHandlerViewGuest* guest) const override;
+ void AttachWebContentsHelpers(
+ content::WebContents* web_contents) const override;
+ FileSystemDelegate* GetFileSystemDelegate() override;
+
+ // Storage API support.
+
+ // Add any additional value store caches (e.g. for chrome.storage.managed)
+ // to |caches|. By default adds nothing.
+ void AddAdditionalValueStoreCaches(
+ content::BrowserContext* context,
+ const scoped_refptr<value_store::ValueStoreFactory>& factory,
+ SettingsChangedCallback observer,
+ std::map<settings_namespace::Namespace, ValueStoreCache*>* caches)
+ override;
+
+ private:
+ std::unique_ptr<FileSystemDelegate> file_system_delegate_;
+};
+
+} // namespace extensions
+
+#endif // CEF_LIBCEF_BROWSER_EXTENSIONS_EXTENSIONS_API_CLIENT_H_
diff --git a/libcef/browser/extensions/extensions_browser_api_provider.cc b/libcef/browser/extensions/extensions_browser_api_provider.cc
new file mode 100644
index 00000000..5abc340d
--- /dev/null
+++ b/libcef/browser/extensions/extensions_browser_api_provider.cc
@@ -0,0 +1,27 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/extensions/extensions_browser_api_provider.h"
+#include "libcef/browser/extensions/chrome_api_registration.h"
+
+// #include "cef/libcef/browser/extensions/api/generated_api_registration.h"
+#include "extensions/browser/api/generated_api_registration.h"
+
+namespace extensions {
+
+CefExtensionsBrowserAPIProvider::CefExtensionsBrowserAPIProvider() = default;
+CefExtensionsBrowserAPIProvider::~CefExtensionsBrowserAPIProvider() = default;
+
+void CefExtensionsBrowserAPIProvider::RegisterExtensionFunctions(
+ ExtensionFunctionRegistry* registry) {
+ // CEF-only APIs.
+ // TODO(cef): Enable if/when CEF exposes its own Mojo APIs. See
+ // libcef/common/extensions/api/README.txt for details.
+ // api::cef::CefGeneratedFunctionRegistry::RegisterAll(registry);
+
+ // Chrome APIs whitelisted by CEF.
+ api::cef::ChromeFunctionRegistry::RegisterAll(registry);
+}
+
+} // namespace extensions
diff --git a/libcef/browser/extensions/extensions_browser_api_provider.h b/libcef/browser/extensions/extensions_browser_api_provider.h
new file mode 100644
index 00000000..d2131b72
--- /dev/null
+++ b/libcef/browser/extensions/extensions_browser_api_provider.h
@@ -0,0 +1,28 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_EXTENSIONS_EXTENSIONS_BROWSER_API_PROVIDER_H_
+#define CEF_LIBCEF_BROWSER_EXTENSIONS_EXTENSIONS_BROWSER_API_PROVIDER_H_
+
+#include "extensions/browser/extensions_browser_api_provider.h"
+
+namespace extensions {
+
+class CefExtensionsBrowserAPIProvider : public ExtensionsBrowserAPIProvider {
+ public:
+ CefExtensionsBrowserAPIProvider();
+
+ CefExtensionsBrowserAPIProvider(const CefExtensionsBrowserAPIProvider&) =
+ delete;
+ CefExtensionsBrowserAPIProvider& operator=(
+ const CefExtensionsBrowserAPIProvider&) = delete;
+
+ ~CefExtensionsBrowserAPIProvider() override;
+
+ void RegisterExtensionFunctions(ExtensionFunctionRegistry* registry) override;
+};
+
+} // namespace extensions
+
+#endif // CEF_LIBCEF_BROWSER_EXTENSIONS_EXTENSIONS_BROWSER_API_PROVIDER_H_
diff --git a/libcef/browser/extensions/extensions_browser_client.cc b/libcef/browser/extensions/extensions_browser_client.cc
new file mode 100644
index 00000000..0f76a2ac
--- /dev/null
+++ b/libcef/browser/extensions/extensions_browser_client.cc
@@ -0,0 +1,416 @@
+// Copyright 2015 The Chromium Embedded Framework Authors.
+// Portions copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/extensions/extensions_browser_client.h"
+
+#include <utility>
+
+#include "libcef/browser/alloy/alloy_browser_host_impl.h"
+#include "libcef/browser/browser_context.h"
+#include "libcef/browser/extensions/component_extension_resource_manager.h"
+#include "libcef/browser/extensions/extension_system.h"
+#include "libcef/browser/extensions/extension_system_factory.h"
+#include "libcef/browser/extensions/extension_web_contents_observer.h"
+#include "libcef/browser/extensions/extensions_api_client.h"
+#include "libcef/browser/extensions/extensions_browser_api_provider.h"
+#include "libcef/browser/request_context_impl.h"
+
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/extensions/chrome_url_request_util.h"
+#include "chrome/browser/extensions/event_router_forwarder.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_frame_host.h"
+#include "extensions/browser/api/core_extensions_browser_api_provider.h"
+#include "extensions/browser/api/extensions_api_client.h"
+#include "extensions/browser/api/mime_handler_private/mime_handler_private.h"
+#include "extensions/browser/api/runtime/runtime_api_delegate.h"
+#include "extensions/browser/app_sorting.h"
+#include "extensions/browser/event_router.h"
+#include "extensions/browser/extension_host_delegate.h"
+#include "extensions/browser/extensions_browser_interface_binders.h"
+#include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h"
+#include "extensions/browser/kiosk/kiosk_delegate.h"
+#include "extensions/browser/url_request_util.h"
+#include "extensions/common/api/mime_handler.mojom.h"
+#include "extensions/common/constants.h"
+
+using content::BrowserContext;
+using content::BrowserThread;
+
+namespace extensions {
+
+namespace {
+
+void BindMimeHandlerService(
+ content::RenderFrameHost* frame_host,
+ mojo::PendingReceiver<extensions::mime_handler::MimeHandlerService>
+ receiver) {
+ auto* web_contents = content::WebContents::FromRenderFrameHost(frame_host);
+ if (!web_contents) {
+ return;
+ }
+
+ auto* guest_view =
+ extensions::MimeHandlerViewGuest::FromWebContents(web_contents);
+ if (!guest_view) {
+ return;
+ }
+ extensions::MimeHandlerServiceImpl::Create(guest_view->GetStreamWeakPtr(),
+ std::move(receiver));
+}
+
+void BindBeforeUnloadControl(
+ content::RenderFrameHost* frame_host,
+ mojo::PendingReceiver<extensions::mime_handler::BeforeUnloadControl>
+ receiver) {
+ auto* web_contents = content::WebContents::FromRenderFrameHost(frame_host);
+ if (!web_contents) {
+ return;
+ }
+
+ auto* guest_view =
+ extensions::MimeHandlerViewGuest::FromWebContents(web_contents);
+ if (!guest_view) {
+ return;
+ }
+ guest_view->FuseBeforeUnloadControl(std::move(receiver));
+}
+
+// Dummy KiosDelegate that always returns false
+class CefKioskDelegate : public extensions::KioskDelegate {
+ public:
+ CefKioskDelegate() = default;
+ ~CefKioskDelegate() override = default;
+
+ // KioskDelegate overrides:
+ bool IsAutoLaunchedKioskApp(const ExtensionId& id) const override {
+ return false;
+ }
+};
+
+} // namespace
+
+CefExtensionsBrowserClient::CefExtensionsBrowserClient()
+ : api_client_(new CefExtensionsAPIClient) {
+ AddAPIProvider(std::make_unique<CoreExtensionsBrowserAPIProvider>());
+ AddAPIProvider(std::make_unique<CefExtensionsBrowserAPIProvider>());
+}
+
+CefExtensionsBrowserClient::~CefExtensionsBrowserClient() {}
+
+// static
+CefExtensionsBrowserClient* CefExtensionsBrowserClient::Get() {
+ return static_cast<CefExtensionsBrowserClient*>(
+ ExtensionsBrowserClient::Get());
+}
+
+bool CefExtensionsBrowserClient::IsShuttingDown() {
+ return false;
+}
+
+bool CefExtensionsBrowserClient::AreExtensionsDisabled(
+ const base::CommandLine& command_line,
+ BrowserContext* context) {
+ return false;
+}
+
+bool CefExtensionsBrowserClient::IsValidContext(BrowserContext* context) {
+ return GetOriginalContext(context) != nullptr;
+}
+
+bool CefExtensionsBrowserClient::IsSameContext(BrowserContext* first,
+ BrowserContext* second) {
+ // Returns true if |first| and |second| share the same underlying
+ // CefBrowserContext.
+ return GetOriginalContext(first) == GetOriginalContext(second);
+}
+
+bool CefExtensionsBrowserClient::HasOffTheRecordContext(
+ BrowserContext* context) {
+ // CEF doesn't use incognito contexts.
+ return false;
+}
+
+BrowserContext* CefExtensionsBrowserClient::GetOffTheRecordContext(
+ BrowserContext* context) {
+ return nullptr;
+}
+
+BrowserContext* CefExtensionsBrowserClient::GetOriginalContext(
+ BrowserContext* context) {
+ auto cef_browser_context = CefBrowserContext::FromBrowserContext(context);
+ if (cef_browser_context) {
+ return cef_browser_context->AsBrowserContext();
+ }
+ return nullptr;
+}
+
+content::BrowserContext*
+CefExtensionsBrowserClient::GetRedirectedContextInIncognito(
+ content::BrowserContext* context,
+ bool force_guest_profile,
+ bool force_system_profile) {
+ return context;
+}
+
+content::BrowserContext*
+CefExtensionsBrowserClient::GetContextForRegularAndIncognito(
+ content::BrowserContext* context,
+ bool force_guest_profile,
+ bool force_system_profile) {
+ return context;
+}
+
+content::BrowserContext* CefExtensionsBrowserClient::GetRegularProfile(
+ content::BrowserContext* context,
+ bool force_guest_profile,
+ bool force_system_profile) {
+ return context;
+}
+
+bool CefExtensionsBrowserClient::IsGuestSession(BrowserContext* context) const {
+ return false;
+}
+
+bool CefExtensionsBrowserClient::IsExtensionIncognitoEnabled(
+ const std::string& extension_id,
+ content::BrowserContext* context) const {
+ return false;
+}
+
+bool CefExtensionsBrowserClient::CanExtensionCrossIncognito(
+ const Extension* extension,
+ content::BrowserContext* context) const {
+ return false;
+}
+
+base::FilePath CefExtensionsBrowserClient::GetBundleResourcePath(
+ const network::ResourceRequest& request,
+ const base::FilePath& extension_resources_path,
+ int* resource_id) const {
+ return chrome_url_request_util::GetBundleResourcePath(
+ request, extension_resources_path, resource_id);
+}
+
+void CefExtensionsBrowserClient::LoadResourceFromResourceBundle(
+ const network::ResourceRequest& request,
+ mojo::PendingReceiver<network::mojom::URLLoader> loader,
+ const base::FilePath& resource_relative_path,
+ const int resource_id,
+ scoped_refptr<net::HttpResponseHeaders> headers,
+ mojo::PendingRemote<network::mojom::URLLoaderClient> client) {
+ chrome_url_request_util::LoadResourceFromResourceBundle(
+ request, std::move(loader), resource_relative_path, resource_id,
+ std::move(headers), std::move(client));
+}
+
+bool CefExtensionsBrowserClient::AllowCrossRendererResourceLoad(
+ const network::ResourceRequest& request,
+ network::mojom::RequestDestination destination,
+ ui::PageTransition page_transition,
+ int child_id,
+ bool is_incognito,
+ const Extension* extension,
+ const ExtensionSet& extensions,
+ const ProcessMap& process_map) {
+ bool allowed = false;
+ if (url_request_util::AllowCrossRendererResourceLoad(
+ request, destination, page_transition, child_id, is_incognito,
+ extension, extensions, process_map, &allowed)) {
+ return allowed;
+ }
+
+ // Couldn't determine if resource is allowed. Block the load.
+ return false;
+}
+
+PrefService* CefExtensionsBrowserClient::GetPrefServiceForContext(
+ BrowserContext* context) {
+ return CefBrowserContext::FromBrowserContext(context)
+ ->AsProfile()
+ ->GetPrefs();
+}
+
+void CefExtensionsBrowserClient::GetEarlyExtensionPrefsObservers(
+ content::BrowserContext* context,
+ std::vector<EarlyExtensionPrefsObserver*>* observers) const {}
+
+ProcessManagerDelegate* CefExtensionsBrowserClient::GetProcessManagerDelegate()
+ const {
+ return nullptr;
+}
+
+std::unique_ptr<ExtensionHostDelegate>
+CefExtensionsBrowserClient::CreateExtensionHostDelegate() {
+ // CEF does not use the ExtensionHost constructor that calls this method.
+ NOTREACHED();
+ return std::unique_ptr<ExtensionHostDelegate>();
+}
+
+bool CefExtensionsBrowserClient::CreateBackgroundExtensionHost(
+ const Extension* extension,
+ content::BrowserContext* browser_context,
+ const GURL& url,
+ ExtensionHost** host) {
+ auto cef_browser_context =
+ CefBrowserContext::FromBrowserContext(browser_context);
+
+ // A CEF representation should always exist.
+ CefRefPtr<CefExtension> cef_extension =
+ cef_browser_context->GetExtension(extension->id());
+ DCHECK(cef_extension);
+ if (!cef_extension) {
+ // Cancel the background host creation.
+ return true;
+ }
+
+ // Always use the same request context that the extension was registered with.
+ // GetLoaderContext() will return NULL for internal extensions.
+ CefRefPtr<CefRequestContext> request_context =
+ cef_extension->GetLoaderContext();
+ if (!request_context) {
+ // Cancel the background host creation.
+ return true;
+ }
+
+ CefBrowserCreateParams create_params;
+ create_params.url = url.spec();
+ create_params.request_context = request_context;
+
+ CefRefPtr<CefExtensionHandler> handler = cef_extension->GetHandler();
+ if (handler.get() && handler->OnBeforeBackgroundBrowser(
+ cef_extension, create_params.url,
+ create_params.client, create_params.settings)) {
+ // Cancel the background host creation.
+ return true;
+ }
+
+ // This triggers creation of the background host.
+ create_params.extension = extension;
+ create_params.extension_host_type = mojom::ViewType::kExtensionBackgroundPage;
+
+ // Browser creation may fail under certain rare circumstances. Fail the
+ // background host creation in that case.
+ CefRefPtr<AlloyBrowserHostImpl> browser =
+ AlloyBrowserHostImpl::Create(create_params);
+ if (browser) {
+ *host = browser->GetExtensionHost();
+ DCHECK(*host);
+ }
+ return true;
+}
+
+bool CefExtensionsBrowserClient::DidVersionUpdate(BrowserContext* context) {
+ // TODO(jamescook): We might want to tell extensions when app_shell updates.
+ return false;
+}
+
+void CefExtensionsBrowserClient::PermitExternalProtocolHandler() {}
+
+bool CefExtensionsBrowserClient::IsInDemoMode() {
+ return false;
+}
+
+bool CefExtensionsBrowserClient::IsScreensaverInDemoMode(
+ const std::string& app_id) {
+ return false;
+}
+
+bool CefExtensionsBrowserClient::IsRunningInForcedAppMode() {
+ return false;
+}
+
+bool CefExtensionsBrowserClient::IsAppModeForcedForApp(
+ const ExtensionId& extension_id) {
+ return false;
+}
+
+bool CefExtensionsBrowserClient::IsLoggedInAsPublicAccount() {
+ return false;
+}
+
+ExtensionSystemProvider*
+CefExtensionsBrowserClient::GetExtensionSystemFactory() {
+ return CefExtensionSystemFactory::GetInstance();
+}
+
+void CefExtensionsBrowserClient::RegisterBrowserInterfaceBindersForFrame(
+ mojo::BinderMapWithContext<content::RenderFrameHost*>* map,
+ content::RenderFrameHost* render_frame_host,
+ const Extension* extension) const {
+ PopulateExtensionFrameBinders(map, render_frame_host, extension);
+
+ map->Add<extensions::mime_handler::MimeHandlerService>(
+ base::BindRepeating(&BindMimeHandlerService));
+ map->Add<extensions::mime_handler::BeforeUnloadControl>(
+ base::BindRepeating(&BindBeforeUnloadControl));
+}
+
+std::unique_ptr<RuntimeAPIDelegate>
+CefExtensionsBrowserClient::CreateRuntimeAPIDelegate(
+ content::BrowserContext* context) const {
+ // TODO(extensions): Implement to support Apps.
+ NOTREACHED();
+ return nullptr;
+}
+
+const ComponentExtensionResourceManager*
+CefExtensionsBrowserClient::GetComponentExtensionResourceManager() {
+ if (!resource_manager_) {
+ resource_manager_ =
+ std::make_unique<CefComponentExtensionResourceManager>();
+ }
+ return resource_manager_.get();
+}
+
+void CefExtensionsBrowserClient::BroadcastEventToRenderers(
+ events::HistogramValue histogram_value,
+ const std::string& event_name,
+ base::Value::List args,
+ bool dispatch_to_off_the_record_profiles) {
+ g_browser_process->extension_event_router_forwarder()
+ ->BroadcastEventToRenderers(histogram_value, event_name, std::move(args),
+ GURL(), dispatch_to_off_the_record_profiles);
+}
+
+ExtensionCache* CefExtensionsBrowserClient::GetExtensionCache() {
+ // Only used by Chrome via ExtensionService.
+ NOTREACHED();
+ return nullptr;
+}
+
+bool CefExtensionsBrowserClient::IsBackgroundUpdateAllowed() {
+ return true;
+}
+
+bool CefExtensionsBrowserClient::IsMinBrowserVersionSupported(
+ const std::string& min_version) {
+ return true;
+}
+
+ExtensionWebContentsObserver*
+CefExtensionsBrowserClient::GetExtensionWebContentsObserver(
+ content::WebContents* web_contents) {
+ return CefExtensionWebContentsObserver::FromWebContents(web_contents);
+}
+
+KioskDelegate* CefExtensionsBrowserClient::GetKioskDelegate() {
+ if (!kiosk_delegate_) {
+ kiosk_delegate_.reset(new CefKioskDelegate());
+ }
+ return kiosk_delegate_.get();
+}
+
+bool CefExtensionsBrowserClient::IsLockScreenContext(
+ content::BrowserContext* context) {
+ return false;
+}
+
+std::string CefExtensionsBrowserClient::GetApplicationLocale() {
+ return g_browser_process->GetApplicationLocale();
+}
+
+} // namespace extensions
diff --git a/libcef/browser/extensions/extensions_browser_client.h b/libcef/browser/extensions/extensions_browser_client.h
new file mode 100644
index 00000000..fd8540e3
--- /dev/null
+++ b/libcef/browser/extensions/extensions_browser_client.h
@@ -0,0 +1,134 @@
+// Copyright 2015 The Chromium Embedded Framework Authors.
+// Portions copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_EXTENSIONS_EXTENSIONS_BROWSER_CLIENT_H_
+#define CEF_LIBCEF_BROWSER_EXTENSIONS_EXTENSIONS_BROWSER_CLIENT_H_
+
+#include "extensions/browser/extensions_browser_client.h"
+
+namespace extensions {
+
+class ExtensionsAPIClient;
+
+// An ExtensionsBrowserClient that supports a single content::BrowserContent
+// with no related incognito context.
+class CefExtensionsBrowserClient : public ExtensionsBrowserClient {
+ public:
+ CefExtensionsBrowserClient();
+
+ CefExtensionsBrowserClient(const CefExtensionsBrowserClient&) = delete;
+ CefExtensionsBrowserClient& operator=(const CefExtensionsBrowserClient&) =
+ delete;
+
+ ~CefExtensionsBrowserClient() override;
+
+ // Returns the singleton CefExtensionsBrowserClient instance.
+ static CefExtensionsBrowserClient* Get();
+
+ // ExtensionsBrowserClient overrides:
+ bool IsShuttingDown() override;
+ bool AreExtensionsDisabled(const base::CommandLine& command_line,
+ content::BrowserContext* context) override;
+ bool IsValidContext(content::BrowserContext* context) override;
+ bool IsSameContext(content::BrowserContext* first,
+ content::BrowserContext* second) override;
+ bool HasOffTheRecordContext(content::BrowserContext* context) override;
+ content::BrowserContext* GetOffTheRecordContext(
+ content::BrowserContext* context) override;
+ content::BrowserContext* GetOriginalContext(
+ content::BrowserContext* context) override;
+ content::BrowserContext* GetRedirectedContextInIncognito(
+ content::BrowserContext* context,
+ bool force_guest_profile,
+ bool force_system_profile) override;
+ content::BrowserContext* GetContextForRegularAndIncognito(
+ content::BrowserContext* context,
+ bool force_guest_profile,
+ bool force_system_profile) override;
+ content::BrowserContext* GetRegularProfile(
+ content::BrowserContext* context,
+ bool force_guest_profile,
+ bool force_system_profile) override;
+ bool IsGuestSession(content::BrowserContext* context) const override;
+ bool IsExtensionIncognitoEnabled(
+ const std::string& extension_id,
+ content::BrowserContext* context) const override;
+ bool CanExtensionCrossIncognito(
+ const Extension* extension,
+ content::BrowserContext* context) const override;
+ base::FilePath GetBundleResourcePath(
+ const network::ResourceRequest& request,
+ const base::FilePath& extension_resources_path,
+ int* resource_id) const override;
+ void LoadResourceFromResourceBundle(
+ const network::ResourceRequest& request,
+ mojo::PendingReceiver<network::mojom::URLLoader> loader,
+ const base::FilePath& resource_relative_path,
+ const int resource_id,
+ scoped_refptr<net::HttpResponseHeaders> headers,
+ mojo::PendingRemote<network::mojom::URLLoaderClient> client) override;
+ bool AllowCrossRendererResourceLoad(
+ const network::ResourceRequest& request,
+ network::mojom::RequestDestination destination,
+ ui::PageTransition page_transition,
+ int child_id,
+ bool is_incognito,
+ const Extension* extension,
+ const ExtensionSet& extensions,
+ const ProcessMap& process_map) override;
+ PrefService* GetPrefServiceForContext(
+ content::BrowserContext* context) override;
+ void GetEarlyExtensionPrefsObservers(
+ content::BrowserContext* context,
+ std::vector<EarlyExtensionPrefsObserver*>* observers) const override;
+ ProcessManagerDelegate* GetProcessManagerDelegate() const override;
+ std::unique_ptr<ExtensionHostDelegate> CreateExtensionHostDelegate() override;
+ bool CreateBackgroundExtensionHost(const Extension* extension,
+ content::BrowserContext* browser_context,
+ const GURL& url,
+ ExtensionHost** host) override;
+ bool DidVersionUpdate(content::BrowserContext* context) override;
+ void PermitExternalProtocolHandler() override;
+ bool IsInDemoMode() override;
+ bool IsScreensaverInDemoMode(const std::string& app_id) override;
+ bool IsRunningInForcedAppMode() override;
+ bool IsAppModeForcedForApp(const ExtensionId& extension_id) override;
+ bool IsLoggedInAsPublicAccount() override;
+ ExtensionSystemProvider* GetExtensionSystemFactory() override;
+ void RegisterBrowserInterfaceBindersForFrame(
+ mojo::BinderMapWithContext<content::RenderFrameHost*>* binder_map,
+ content::RenderFrameHost* render_frame_host,
+ const Extension* extension) const override;
+ std::unique_ptr<RuntimeAPIDelegate> CreateRuntimeAPIDelegate(
+ content::BrowserContext* context) const override;
+ const ComponentExtensionResourceManager*
+ GetComponentExtensionResourceManager() override;
+ void BroadcastEventToRenderers(
+ events::HistogramValue histogram_value,
+ const std::string& event_name,
+ base::Value::List args,
+ bool dispatch_to_off_the_record_profiles) override;
+ ExtensionCache* GetExtensionCache() override;
+ bool IsBackgroundUpdateAllowed() override;
+ bool IsMinBrowserVersionSupported(const std::string& min_version) override;
+ ExtensionWebContentsObserver* GetExtensionWebContentsObserver(
+ content::WebContents* web_contents) override;
+ KioskDelegate* GetKioskDelegate() override;
+ bool IsLockScreenContext(content::BrowserContext* context) override;
+ std::string GetApplicationLocale() override;
+
+ private:
+ // Support for extension APIs.
+ std::unique_ptr<ExtensionsAPIClient> api_client_;
+
+ // Resource manager used to supply resources from pak files.
+ std::unique_ptr<ComponentExtensionResourceManager> resource_manager_;
+
+ std::unique_ptr<KioskDelegate> kiosk_delegate_;
+};
+
+} // namespace extensions
+
+#endif // CEF_LIBCEF_BROWSER_EXTENSIONS_EXTENSIONS_BROWSER_CLIENT_H_
diff --git a/libcef/browser/extensions/mime_handler_view_guest_delegate.cc b/libcef/browser/extensions/mime_handler_view_guest_delegate.cc
new file mode 100644
index 00000000..ae5b67b3
--- /dev/null
+++ b/libcef/browser/extensions/mime_handler_view_guest_delegate.cc
@@ -0,0 +1,76 @@
+// Copyright 2015 The Chromium Embedded Framework Authors.
+// Portions copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/extensions/mime_handler_view_guest_delegate.h"
+
+#include "libcef/browser/alloy/alloy_browser_host_impl.h"
+#include "libcef/browser/alloy/alloy_content_browser_client.h"
+#include "libcef/browser/browser_context.h"
+#include "libcef/browser/browser_info.h"
+#include "libcef/browser/osr/web_contents_view_osr.h"
+
+#include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h"
+
+namespace extensions {
+
+CefMimeHandlerViewGuestDelegate::CefMimeHandlerViewGuestDelegate(
+ MimeHandlerViewGuest* guest)
+ : guest_(guest), owner_web_contents_(guest_->owner_web_contents()) {}
+
+CefMimeHandlerViewGuestDelegate::~CefMimeHandlerViewGuestDelegate() {}
+
+void CefMimeHandlerViewGuestDelegate::OverrideWebContentsCreateParams(
+ content::WebContents::CreateParams* params) {
+ DCHECK(params->guest_delegate);
+
+ CefRefPtr<AlloyBrowserHostImpl> owner_browser =
+ AlloyBrowserHostImpl::GetBrowserForContents(owner_web_contents_);
+ DCHECK(owner_browser);
+
+ if (owner_browser->IsWindowless()) {
+ CefWebContentsViewOSR* view_osr = new CefWebContentsViewOSR(
+ owner_browser->GetBackgroundColor(), false, false);
+ params->view = view_osr;
+ params->delegate_view = view_osr;
+ }
+}
+
+void CefMimeHandlerViewGuestDelegate::OnGuestAttached() {
+ content::WebContents* web_contents = guest_->web_contents();
+ DCHECK(web_contents);
+
+ CefRefPtr<AlloyBrowserHostImpl> owner_browser =
+ AlloyBrowserHostImpl::GetBrowserForContents(owner_web_contents_);
+ DCHECK(owner_browser);
+
+ // Associate guest state information with the owner browser.
+ owner_browser->browser_info()->MaybeCreateFrame(
+ web_contents->GetPrimaryMainFrame(), true /* is_guest_view */);
+}
+
+void CefMimeHandlerViewGuestDelegate::OnGuestDetached() {
+ content::WebContents* web_contents = guest_->web_contents();
+ DCHECK(web_contents);
+
+ CefRefPtr<AlloyBrowserHostImpl> owner_browser =
+ AlloyBrowserHostImpl::GetBrowserForContents(owner_web_contents_);
+ DCHECK(owner_browser);
+
+ // Disassociate guest state information with the owner browser.
+ owner_browser->browser_info()->RemoveFrame(
+ web_contents->GetPrimaryMainFrame());
+}
+
+bool CefMimeHandlerViewGuestDelegate::HandleContextMenu(
+ content::RenderFrameHost& render_frame_host,
+ const content::ContextMenuParams& params) {
+ CefRefPtr<AlloyBrowserHostImpl> owner_browser =
+ AlloyBrowserHostImpl::GetBrowserForContents(owner_web_contents_);
+ DCHECK(owner_browser);
+
+ return owner_browser->ShowContextMenu(params);
+}
+
+} // namespace extensions
diff --git a/libcef/browser/extensions/mime_handler_view_guest_delegate.h b/libcef/browser/extensions/mime_handler_view_guest_delegate.h
new file mode 100644
index 00000000..96b413b7
--- /dev/null
+++ b/libcef/browser/extensions/mime_handler_view_guest_delegate.h
@@ -0,0 +1,44 @@
+// Copyright 2015 The Chromium Embedded Framework Authors.
+// Portions copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_EXTENSIONS_MIME_HANDLER_VIEW_GUEST_DELEGATE_H_
+#define CEF_LIBCEF_BROWSER_EXTENSIONS_MIME_HANDLER_VIEW_GUEST_DELEGATE_H_
+
+#include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h"
+#include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest_delegate.h"
+
+namespace content {
+struct ContextMenuParams;
+}
+
+namespace extensions {
+
+class CefMimeHandlerViewGuestDelegate : public MimeHandlerViewGuestDelegate {
+ public:
+ explicit CefMimeHandlerViewGuestDelegate(MimeHandlerViewGuest* guest);
+
+ CefMimeHandlerViewGuestDelegate(const CefMimeHandlerViewGuestDelegate&) =
+ delete;
+ CefMimeHandlerViewGuestDelegate& operator=(
+ const CefMimeHandlerViewGuestDelegate&) = delete;
+
+ ~CefMimeHandlerViewGuestDelegate() override;
+
+ // MimeHandlerViewGuestDelegate methods.
+ void OverrideWebContentsCreateParams(
+ content::WebContents::CreateParams* params) override;
+ void OnGuestAttached() override;
+ void OnGuestDetached() override;
+ bool HandleContextMenu(content::RenderFrameHost& render_frame_host,
+ const content::ContextMenuParams& params) override;
+
+ private:
+ MimeHandlerViewGuest* guest_; // Owns us.
+ content::WebContents* owner_web_contents_;
+};
+
+} // namespace extensions
+
+#endif // CEF_LIBCEF_BROWSER_EXTENSIONS_MIME_HANDLER_VIEW_GUEST_DELEGATE_H_
diff --git a/libcef/browser/extensions/value_store/cef_value_store.cc b/libcef/browser/extensions/value_store/cef_value_store.cc
new file mode 100644
index 00000000..ee1153b1
--- /dev/null
+++ b/libcef/browser/extensions/value_store/cef_value_store.cc
@@ -0,0 +1,141 @@
+// Copyright 2017 The Chromium Embedded Framework Authors.
+// Portions copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/extensions/value_store/cef_value_store.h"
+
+#include <memory>
+#include <ostream>
+#include <utility>
+
+#include "base/notreached.h"
+
+namespace value_store {
+
+namespace {
+
+const char kGenericErrorMessage[] = "CefValueStore configured to error";
+
+// Having this utility function allows ValueStore::Status to not have a copy
+// constructor.
+ValueStore::Status CreateStatusCopy(const ValueStore::Status& status) {
+ return ValueStore::Status(status.code, status.restore_status, status.message);
+}
+
+} // namespace
+
+CefValueStore::CefValueStore() = default;
+CefValueStore::~CefValueStore() = default;
+
+void CefValueStore::set_status_code(StatusCode status_code) {
+ status_ = ValueStore::Status(status_code, kGenericErrorMessage);
+}
+
+size_t CefValueStore::GetBytesInUse(const std::string& key) {
+ // Let SettingsStorageQuotaEnforcer implement this.
+ NOTREACHED() << "Not implemented";
+ return 0;
+}
+
+size_t CefValueStore::GetBytesInUse(const std::vector<std::string>& keys) {
+ // Let SettingsStorageQuotaEnforcer implement this.
+ NOTREACHED() << "Not implemented";
+ return 0;
+}
+
+size_t CefValueStore::GetBytesInUse() {
+ // Let SettingsStorageQuotaEnforcer implement this.
+ NOTREACHED() << "Not implemented";
+ return 0;
+}
+
+ValueStore::ReadResult CefValueStore::Get(const std::string& key) {
+ return Get(std::vector<std::string>(1, key));
+}
+
+ValueStore::ReadResult CefValueStore::Get(
+ const std::vector<std::string>& keys) {
+ read_count_++;
+ if (!status_.ok()) {
+ return ReadResult(CreateStatusCopy(status_));
+ }
+
+ base::Value::Dict settings;
+ for (const auto& key : keys) {
+ base::Value* value = storage_.Find(key);
+ if (value) {
+ settings.Set(key, value->Clone());
+ }
+ }
+ return ReadResult(std::move(settings), CreateStatusCopy(status_));
+}
+
+ValueStore::ReadResult CefValueStore::Get() {
+ read_count_++;
+ if (!status_.ok()) {
+ return ReadResult(CreateStatusCopy(status_));
+ }
+ return ReadResult(storage_.Clone(), CreateStatusCopy(status_));
+}
+
+ValueStore::WriteResult CefValueStore::Set(WriteOptions options,
+ const std::string& key,
+ const base::Value& value) {
+ base::Value::Dict settings;
+ settings.Set(key, value.Clone());
+ return Set(options, settings);
+}
+
+ValueStore::WriteResult CefValueStore::Set(WriteOptions options,
+ const base::Value::Dict& settings) {
+ write_count_++;
+ if (!status_.ok()) {
+ return WriteResult(CreateStatusCopy(status_));
+ }
+
+ ValueStoreChangeList changes;
+ for (const auto [key, value] : settings) {
+ base::Value* old_value = storage_.Find(key);
+ if (!old_value || *old_value != value) {
+ changes.emplace_back(key,
+ old_value
+ ? absl::optional<base::Value>(old_value->Clone())
+ : absl::nullopt,
+ value.Clone());
+ storage_.Set(key, value.Clone());
+ }
+ }
+ return WriteResult(std::move(changes), CreateStatusCopy(status_));
+}
+
+ValueStore::WriteResult CefValueStore::Remove(const std::string& key) {
+ return Remove(std::vector<std::string>(1, key));
+}
+
+ValueStore::WriteResult CefValueStore::Remove(
+ const std::vector<std::string>& keys) {
+ write_count_++;
+ if (!status_.ok()) {
+ return WriteResult(CreateStatusCopy(status_));
+ }
+
+ ValueStoreChangeList changes;
+ for (auto const& key : keys) {
+ absl::optional<base::Value> old_value = storage_.Extract(key);
+ if (old_value.has_value()) {
+ changes.emplace_back(key, std::move(*old_value), absl::nullopt);
+ }
+ }
+ return WriteResult(std::move(changes), CreateStatusCopy(status_));
+}
+
+ValueStore::WriteResult CefValueStore::Clear() {
+ std::vector<std::string> keys;
+ for (const auto [key, value] : storage_) {
+ keys.push_back(key);
+ }
+ return Remove(keys);
+}
+
+} // namespace value_store
diff --git a/libcef/browser/extensions/value_store/cef_value_store.h b/libcef/browser/extensions/value_store/cef_value_store.h
new file mode 100644
index 00000000..fe41c342
--- /dev/null
+++ b/libcef/browser/extensions/value_store/cef_value_store.h
@@ -0,0 +1,65 @@
+// Copyright 2017 The Chromium Embedded Framework Authors.
+// Portions copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_EXTENSIONS_VALUE_STORE_CEF_VALUE_STORE_H_
+#define CEF_LIBCEF_BROWSER_EXTENSIONS_VALUE_STORE_CEF_VALUE_STORE_H_
+
+#include <stddef.h>
+
+#include <string>
+#include <vector>
+
+#include "components/value_store/value_store.h"
+
+namespace value_store {
+
+// Implementation Based on TestingValueStore.
+// ValueStore with an in-memory storage but the ability to optionally fail all
+// operations.
+class CefValueStore : public ValueStore {
+ public:
+ CefValueStore();
+ ~CefValueStore() override;
+ CefValueStore(const CefValueStore&) = delete;
+ CefValueStore& operator=(const CefValueStore&) = delete;
+
+ // Sets the error code for requests. If OK, errors won't be thrown.
+ // Defaults to OK.
+ void set_status_code(StatusCode status_code);
+
+ // Accessors for the number of reads/writes done by this value store. Each
+ // Get* operation (except for the BytesInUse ones) counts as one read, and
+ // each Set*/Remove/Clear operation counts as one write. This is useful in
+ // tests seeking to assert that some number of reads/writes to their
+ // underlying value store have (or have not) happened.
+ int read_count() { return read_count_; }
+ int write_count() { return write_count_; }
+
+ // ValueStore implementation.
+ size_t GetBytesInUse(const std::string& key) override;
+ size_t GetBytesInUse(const std::vector<std::string>& keys) override;
+ size_t GetBytesInUse() override;
+ ReadResult Get(const std::string& key) override;
+ ReadResult Get(const std::vector<std::string>& keys) override;
+ ReadResult Get() override;
+ WriteResult Set(WriteOptions options,
+ const std::string& key,
+ const base::Value& value) override;
+ WriteResult Set(WriteOptions options,
+ const base::Value::Dict& values) override;
+ WriteResult Remove(const std::string& key) override;
+ WriteResult Remove(const std::vector<std::string>& keys) override;
+ WriteResult Clear() override;
+
+ private:
+ base::Value::Dict storage_;
+ int read_count_ = 0;
+ int write_count_ = 0;
+ ValueStore::Status status_;
+};
+
+} // namespace value_store
+
+#endif // CEF_LIBCEF_BROWSER_EXTENSIONS_VALUE_STORE_CEF_VALUE_STORE_H_
diff --git a/libcef/browser/extensions/value_store/cef_value_store_factory.cc b/libcef/browser/extensions/value_store/cef_value_store_factory.cc
new file mode 100644
index 00000000..b655210a
--- /dev/null
+++ b/libcef/browser/extensions/value_store/cef_value_store_factory.cc
@@ -0,0 +1,75 @@
+// Copyright 2017 The Chromium Embedded Framework Authors.
+// Portions copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/extensions/value_store/cef_value_store_factory.h"
+
+#include "libcef/browser/extensions/value_store/cef_value_store.h"
+
+#include "base/containers/contains.h"
+#include "base/memory/ptr_util.h"
+#include "components/value_store/leveldb_value_store.h"
+
+namespace {
+
+const char kUMAClientName[] = "Cef";
+
+} // namespace
+
+namespace value_store {
+
+CefValueStoreFactory::CefValueStoreFactory() = default;
+
+CefValueStoreFactory::CefValueStoreFactory(const base::FilePath& db_path)
+ : db_path_(db_path) {}
+
+CefValueStoreFactory::~CefValueStoreFactory() = default;
+
+std::unique_ptr<ValueStore> CefValueStoreFactory::CreateValueStore(
+ const base::FilePath& directory,
+ const std::string& uma_client_name) {
+ std::unique_ptr<ValueStore> value_store(CreateStore());
+ // This factory is purposely keeping the raw pointers to each ValueStore
+ // created. Cefs using CefValueStoreFactory must be careful to keep
+ // those ValueStore's alive for the duration of their test.
+ value_store_map_[directory] = value_store.get();
+ return value_store;
+}
+
+ValueStore* CefValueStoreFactory::LastCreatedStore() const {
+ return last_created_store_;
+}
+
+void CefValueStoreFactory::DeleteValueStore(const base::FilePath& directory) {
+ value_store_map_.erase(directory);
+}
+
+bool CefValueStoreFactory::HasValueStore(const base::FilePath& directory) {
+ return base::Contains(value_store_map_, directory);
+}
+
+ValueStore* CefValueStoreFactory::GetExisting(
+ const base::FilePath& directory) const {
+ auto it = value_store_map_.find(directory);
+ DCHECK(it != value_store_map_.end());
+ return it->second;
+}
+
+void CefValueStoreFactory::Reset() {
+ last_created_store_ = nullptr;
+ value_store_map_.clear();
+}
+
+std::unique_ptr<ValueStore> CefValueStoreFactory::CreateStore() {
+ std::unique_ptr<ValueStore> store;
+ if (db_path_.empty()) {
+ store = std::make_unique<CefValueStore>();
+ } else {
+ store = std::make_unique<LeveldbValueStore>(kUMAClientName, db_path_);
+ }
+ last_created_store_ = store.get();
+ return store;
+}
+
+} // namespace value_store
diff --git a/libcef/browser/extensions/value_store/cef_value_store_factory.h b/libcef/browser/extensions/value_store/cef_value_store_factory.h
new file mode 100644
index 00000000..3a60e657
--- /dev/null
+++ b/libcef/browser/extensions/value_store/cef_value_store_factory.h
@@ -0,0 +1,61 @@
+// Copyright 2017 The Chromium Embedded Framework Authors.
+// Portions copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_EXTENSIONS_VALUE_STORE_CEF_VALUE_STORE_FACTORY_H_
+#define CEF_LIBCEF_BROWSER_EXTENSIONS_VALUE_STORE_CEF_VALUE_STORE_FACTORY_H_
+
+#include <map>
+#include <memory>
+
+#include "base/files/file_path.h"
+#include "components/value_store/value_store_factory.h"
+
+namespace value_store {
+
+class ValueStore;
+
+// Based on TestValueStoreFactory. Will either open a database on disk (if path
+// provided) returning a |LeveldbValueStore|. Otherwise a new |CefingValueStore|
+// instance will be returned.
+class CefValueStoreFactory : public ValueStoreFactory {
+ public:
+ CefValueStoreFactory();
+ explicit CefValueStoreFactory(const base::FilePath& db_path);
+ CefValueStoreFactory(const CefValueStoreFactory&) = delete;
+ CefValueStoreFactory& operator=(const CefValueStoreFactory&) = delete;
+
+ // ValueStoreFactory
+ std::unique_ptr<ValueStore> CreateValueStore(
+ const base::FilePath& directory,
+ const std::string& uma_client_name) override;
+ void DeleteValueStore(const base::FilePath& directory) override;
+ bool HasValueStore(const base::FilePath& directory) override;
+
+ // Return the last created |ValueStore|. Use with caution as this may return
+ // a dangling pointer since the creator now owns the ValueStore which can be
+ // deleted at any time.
+ ValueStore* LastCreatedStore() const;
+ // Return the previously created |ValueStore| in the given directory.
+ ValueStore* GetExisting(const base::FilePath& directory) const;
+ // Reset this class (as if just created).
+ void Reset();
+
+ private:
+ ~CefValueStoreFactory() override;
+
+ std::unique_ptr<ValueStore> CreateStore();
+
+ base::FilePath db_path_;
+ ValueStore* last_created_store_ = nullptr;
+
+ // A mapping from directories to their ValueStore. None of these value
+ // stores are owned by this factory, so care must be taken when calling
+ // GetExisting.
+ std::map<base::FilePath, ValueStore*> value_store_map_;
+};
+
+} // namespace value_store
+
+#endif // CEF_LIBCEF_BROWSER_EXTENSIONS_VALUE_STORE_CEF_VALUE_STORE_FACTORY_H_
diff --git a/libcef/browser/file_dialog_manager.cc b/libcef/browser/file_dialog_manager.cc
new file mode 100644
index 00000000..2e450898
--- /dev/null
+++ b/libcef/browser/file_dialog_manager.cc
@@ -0,0 +1,572 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors.
+// Portions copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/file_dialog_manager.h"
+
+#include <utility>
+
+#include "include/cef_dialog_handler.h"
+#include "libcef/browser/browser_host_base.h"
+#include "libcef/browser/context.h"
+#include "libcef/browser/thread_util.h"
+
+#include "chrome/browser/file_select_helper.h"
+#include "content/public/browser/file_select_listener.h"
+#include "content/public/browser/render_frame_host.h"
+#include "ui/shell_dialogs/select_file_policy.h"
+
+using blink::mojom::FileChooserParams;
+
+namespace {
+
+class CefFileDialogCallbackImpl : public CefFileDialogCallback {
+ public:
+ using CallbackType = CefFileDialogManager::RunFileChooserCallback;
+
+ explicit CefFileDialogCallbackImpl(CallbackType callback)
+ : callback_(std::move(callback)) {}
+
+ ~CefFileDialogCallbackImpl() override {
+ if (!callback_.is_null()) {
+ // The callback is still pending. Cancel it now.
+ if (CEF_CURRENTLY_ON_UIT()) {
+ CancelNow(std::move(callback_));
+ } else {
+ CEF_POST_TASK(CEF_UIT,
+ base::BindOnce(&CefFileDialogCallbackImpl::CancelNow,
+ std::move(callback_)));
+ }
+ }
+ }
+
+ void Continue(const std::vector<CefString>& file_paths) override {
+ if (CEF_CURRENTLY_ON_UIT()) {
+ if (!callback_.is_null()) {
+ std::vector<base::FilePath> vec;
+ if (!file_paths.empty()) {
+ std::vector<CefString>::const_iterator it = file_paths.begin();
+ for (; it != file_paths.end(); ++it) {
+ vec.push_back(base::FilePath(*it));
+ }
+ }
+ std::move(callback_).Run(vec);
+ }
+ } else {
+ CEF_POST_TASK(CEF_UIT,
+ base::BindOnce(&CefFileDialogCallbackImpl::Continue, this,
+ file_paths));
+ }
+ }
+
+ void Cancel() override {
+ if (CEF_CURRENTLY_ON_UIT()) {
+ if (!callback_.is_null()) {
+ CancelNow(std::move(callback_));
+ }
+ } else {
+ CEF_POST_TASK(CEF_UIT,
+ base::BindOnce(&CefFileDialogCallbackImpl::Cancel, this));
+ }
+ }
+
+ [[nodiscard]] CallbackType Disconnect() { return std::move(callback_); }
+
+ private:
+ static void CancelNow(CallbackType callback) {
+ CEF_REQUIRE_UIT();
+ std::vector<base::FilePath> file_paths;
+ std::move(callback).Run(file_paths);
+ }
+
+ CallbackType callback_;
+
+ IMPLEMENT_REFCOUNTING(CefFileDialogCallbackImpl);
+};
+
+void RunFileDialogDismissed(CefRefPtr<CefRunFileDialogCallback> callback,
+ const std::vector<base::FilePath>& file_paths) {
+ std::vector<CefString> paths;
+ if (file_paths.size() > 0) {
+ for (size_t i = 0; i < file_paths.size(); ++i) {
+ paths.push_back(file_paths[i].value());
+ }
+ }
+ callback->OnFileDialogDismissed(paths);
+}
+
+// Based on net/base/filename_util_internal.cc FilePathToString16().
+std::u16string FilePathTypeToString16(const base::FilePath::StringType& str) {
+ std::u16string result;
+#if BUILDFLAG(IS_WIN)
+ result.assign(str.begin(), str.end());
+#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
+ if (!str.empty()) {
+ base::UTF8ToUTF16(str.c_str(), str.size(), &result);
+ }
+#endif
+ return result;
+}
+
+FileChooserParams SelectFileToFileChooserParams(
+ ui::SelectFileDialog::Type type,
+ const std::u16string& title,
+ const base::FilePath& default_path,
+ const ui::SelectFileDialog::FileTypeInfo* file_types) {
+ FileChooserParams params;
+
+ absl::optional<FileChooserParams::Mode> mode;
+ switch (type) {
+ case ui::SelectFileDialog::Type::SELECT_UPLOAD_FOLDER:
+ mode = FileChooserParams::Mode::kUploadFolder;
+ break;
+ case ui::SelectFileDialog::Type::SELECT_SAVEAS_FILE:
+ mode = FileChooserParams::Mode::kSave;
+ break;
+ case ui::SelectFileDialog::Type::SELECT_OPEN_FILE:
+ mode = FileChooserParams::Mode::kOpen;
+ break;
+ case ui::SelectFileDialog::Type::SELECT_OPEN_MULTI_FILE:
+ mode = FileChooserParams::Mode::kOpenMultiple;
+ break;
+ default:
+ NOTIMPLEMENTED();
+ return params;
+ }
+
+ params.mode = *mode;
+ params.title = title;
+ params.default_file_name = default_path;
+
+ // Note that this translation will lose any mime-type based filters that
+ // may have existed in the original FileChooserParams::accept_types if this
+ // dialog was created via FileSelectHelper::RunFileChooser.
+ if (file_types) {
+ // A list of allowed extensions. For example, it might be
+ // { { "htm", "html" }, { "txt" } }
+ for (auto& vec : file_types->extensions) {
+ for (auto& ext : vec) {
+ params.accept_types.push_back(
+ FilePathTypeToString16(FILE_PATH_LITERAL(".") + ext));
+ }
+ }
+ }
+
+ return params;
+}
+
+class CefFileSelectListener : public content::FileSelectListener {
+ public:
+ using CallbackType = CefFileDialogManager::RunFileChooserCallback;
+
+ explicit CefFileSelectListener(CallbackType callback)
+ : callback_(std::move(callback)) {}
+
+ private:
+ ~CefFileSelectListener() override = default;
+
+ void FileSelected(std::vector<blink::mojom::FileChooserFileInfoPtr> files,
+ const base::FilePath& base_dir,
+ FileChooserParams::Mode mode) override {
+ std::vector<base::FilePath> paths;
+ if (mode == FileChooserParams::Mode::kUploadFolder) {
+ if (!base_dir.empty()) {
+ paths.push_back(base_dir);
+ }
+ } else if (!files.empty()) {
+ for (auto& file : files) {
+ if (file->is_native_file()) {
+ paths.push_back(file->get_native_file()->file_path);
+ } else {
+ NOTIMPLEMENTED();
+ }
+ }
+ }
+
+ std::move(callback_).Run(paths);
+ }
+
+ void FileSelectionCanceled() override { std::move(callback_).Run({}); }
+
+ CallbackType callback_;
+};
+
+} // namespace
+
+class CefSelectFileDialogListener : public ui::SelectFileDialog::Listener {
+ public:
+ CefSelectFileDialogListener(ui::SelectFileDialog::Listener* listener,
+ void* params,
+ base::OnceClosure callback)
+ : listener_(listener), params_(params), callback_(std::move(callback)) {}
+
+ CefSelectFileDialogListener(const CefSelectFileDialogListener&) = delete;
+ CefSelectFileDialogListener& operator=(const CefSelectFileDialogListener&) =
+ delete;
+
+ void Cancel(bool listener_destroyed) {
+ if (executing_) {
+ // We're likely still on the stack. Do nothing and wait for Destroy().
+ return;
+ }
+ if (listener_destroyed) {
+ // Don't execute the listener.
+ Destroy();
+ } else {
+ FileSelectionCanceled(params_);
+ }
+ }
+
+ ui::SelectFileDialog::Listener* listener() const { return listener_; }
+
+ private:
+ ~CefSelectFileDialogListener() override = default;
+
+ void FileSelected(const base::FilePath& path,
+ int index,
+ void* params) override {
+ DCHECK_EQ(params, params_);
+ executing_ = true;
+ listener_->FileSelected(path, index, params);
+ Destroy();
+ }
+
+ void FileSelectedWithExtraInfo(const ui::SelectedFileInfo& file,
+ int index,
+ void* params) override {
+ DCHECK_EQ(params, params_);
+ executing_ = true;
+ listener_->FileSelectedWithExtraInfo(file, index, params);
+ Destroy();
+ }
+
+ void MultiFilesSelected(const std::vector<base::FilePath>& files,
+ void* params) override {
+ DCHECK_EQ(params, params_);
+ executing_ = true;
+ listener_->MultiFilesSelected(files, params);
+ Destroy();
+ }
+
+ void MultiFilesSelectedWithExtraInfo(
+ const std::vector<ui::SelectedFileInfo>& files,
+ void* params) override {
+ DCHECK_EQ(params, params_);
+ executing_ = true;
+ listener_->MultiFilesSelectedWithExtraInfo(files, params);
+ Destroy();
+ }
+
+ void FileSelectionCanceled(void* params) override {
+ DCHECK_EQ(params, params_);
+ executing_ = true;
+ listener_->FileSelectionCanceled(params);
+ Destroy();
+ }
+
+ void Destroy() {
+ std::move(callback_).Run();
+ delete this;
+ }
+
+ ui::SelectFileDialog::Listener* const listener_;
+ void* const params_;
+ base::OnceClosure callback_;
+
+ // Used to avoid re-entrancy from Cancel().
+ bool executing_ = false;
+};
+
+CefFileDialogManager::CefFileDialogManager(CefBrowserHostBase* browser)
+ : browser_(browser) {}
+
+CefFileDialogManager::~CefFileDialogManager() = default;
+
+void CefFileDialogManager::Destroy() {
+ if (dialog_listener_) {
+ // Cancel the listener and delete related objects.
+ SelectFileDoneByListenerCallback(/*listener_destroyed=*/false);
+ }
+ DCHECK(!dialog_);
+ DCHECK(!dialog_listener_);
+ DCHECK(active_listeners_.empty());
+}
+
+void CefFileDialogManager::RunFileDialog(
+ cef_file_dialog_mode_t mode,
+ const CefString& title,
+ const CefString& default_file_path,
+ const std::vector<CefString>& accept_filters,
+ CefRefPtr<CefRunFileDialogCallback> callback) {
+ DCHECK(callback.get());
+ if (!callback.get()) {
+ return;
+ }
+
+ blink::mojom::FileChooserParams params;
+ switch (mode) {
+ case FILE_DIALOG_OPEN:
+ params.mode = blink::mojom::FileChooserParams::Mode::kOpen;
+ break;
+ case FILE_DIALOG_OPEN_MULTIPLE:
+ params.mode = blink::mojom::FileChooserParams::Mode::kOpenMultiple;
+ break;
+ case FILE_DIALOG_OPEN_FOLDER:
+ params.mode = blink::mojom::FileChooserParams::Mode::kUploadFolder;
+ break;
+ case FILE_DIALOG_SAVE:
+ params.mode = blink::mojom::FileChooserParams::Mode::kSave;
+ break;
+ }
+
+ params.title = title;
+ if (!default_file_path.empty()) {
+ params.default_file_name = base::FilePath(default_file_path);
+ }
+
+ if (!accept_filters.empty()) {
+ std::vector<CefString>::const_iterator it = accept_filters.begin();
+ for (; it != accept_filters.end(); ++it) {
+ params.accept_types.push_back(*it);
+ }
+ }
+
+ RunFileChooser(params, base::BindOnce(RunFileDialogDismissed, callback));
+}
+
+void CefFileDialogManager::RunFileChooser(
+ const blink::mojom::FileChooserParams& params,
+ RunFileChooserCallback callback) {
+ CEF_REQUIRE_UIT();
+
+ // Execute the delegate with the most exact version of |params|. If not
+ // handled here there will be another call to the delegate from RunSelectFile.
+ // It might be better to execute the delegate only the single time here, but
+ // we don't currently have sufficient state in RunSelectFile to know that the
+ // delegate has already been executed.
+ callback = MaybeRunDelegate(params, std::move(callback));
+ if (callback.is_null()) {
+ // The delegate kept the callback.
+ return;
+ }
+
+ FileChooserParams new_params = params;
+
+ // Make sure we get native files in CefFileSelectListener.
+ new_params.need_local_path = true;
+
+ // Requirements of FileSelectHelper.
+ if (params.mode != FileChooserParams::Mode::kSave) {
+ new_params.default_file_name = base::FilePath();
+ } else {
+ new_params.default_file_name = new_params.default_file_name.BaseName();
+ }
+
+ // FileSelectHelper is usually only used for renderer-initiated dialogs via
+ // WebContentsDelegate::RunFileChooser. We choose to use it here instead of
+ // calling ui::SelectFileDialog::Create directly because it provides some nice
+ // functionality related to default dialog settings and filter list
+ // generation. We customize the behavior slightly for non-renderer-initiated
+ // dialogs by passing the |run_from_cef=true| flag. FileSelectHelper uses
+ // ui::SelectFileDialog::Create internally and that call will be intercepted
+ // by CefSelectFileDialogFactory, resulting in call to RunSelectFile below.
+ // See related comments on CefSelectFileDialogFactory.
+ FileSelectHelper::RunFileChooser(
+ browser_->GetWebContents()->GetPrimaryMainFrame(),
+ base::MakeRefCounted<CefFileSelectListener>(std::move(callback)),
+ new_params, /*run_from_cef=*/true);
+}
+
+void CefFileDialogManager::RunSelectFile(
+ ui::SelectFileDialog::Listener* listener,
+ std::unique_ptr<ui::SelectFilePolicy> policy,
+ ui::SelectFileDialog::Type type,
+ const std::u16string& title,
+ const base::FilePath& default_path,
+ const ui::SelectFileDialog::FileTypeInfo* file_types,
+ int file_type_index,
+ const base::FilePath::StringType& default_extension,
+ gfx::NativeWindow owning_window,
+ void* params) {
+ CEF_REQUIRE_UIT();
+
+ active_listeners_.insert(listener);
+
+ // This will not be an exact representation of the original params.
+ auto chooser_params =
+ SelectFileToFileChooserParams(type, title, default_path, file_types);
+ auto callback =
+ base::BindOnce(&CefFileDialogManager::SelectFileDoneByDelegateCallback,
+ weak_ptr_factory_.GetWeakPtr(), base::Unretained(listener),
+ base::Unretained(params));
+ callback = MaybeRunDelegate(chooser_params, std::move(callback));
+ if (callback.is_null()) {
+ // The delegate kept the callback.
+ return;
+ }
+
+ if (dialog_) {
+ LOG(ERROR) << "Multiple simultaneous dialogs are not supported; "
+ "canceling the file dialog";
+ std::move(callback).Run({});
+ return;
+ }
+
+#if BUILDFLAG(IS_LINUX)
+ // We can't use GtkUi in combination with multi-threaded-message-loop because
+ // Chromium's GTK implementation doesn't use GDK threads.
+ if (!!CefContext::Get()->settings().multi_threaded_message_loop) {
+ LOG(ERROR) << "Default dialog implementation is not available; "
+ "canceling the file dialog";
+ std::move(callback).Run({});
+ return;
+ }
+#endif
+
+ // |callback| is no longer used at this point.
+ callback.Reset();
+
+ DCHECK(!dialog_listener_);
+
+ // This object will delete itself.
+ dialog_listener_ = new CefSelectFileDialogListener(
+ listener, params,
+ base::BindOnce(&CefFileDialogManager::SelectFileDoneByListenerCallback,
+ weak_ptr_factory_.GetWeakPtr(),
+ /*listener_destroyed=*/false));
+
+ // This call will not be intercepted by CefSelectFileDialogFactory due to the
+ // |run_from_cef=true| flag.
+ // See related comments on CefSelectFileDialogFactory.
+ dialog_ = ui::SelectFileDialog::Create(dialog_listener_, std::move(policy),
+ /*run_from_cef=*/true);
+
+ // With windowless rendering use the parent handle specified by the client.
+ if (browser_->IsWindowless()) {
+ DCHECK(!owning_window);
+ dialog_->set_owning_widget(browser_->GetWindowHandle());
+ }
+
+ dialog_->SelectFile(type, title, default_path, file_types, file_type_index,
+ default_extension, owning_window, params);
+}
+
+void CefFileDialogManager::SelectFileListenerDestroyed(
+ ui::SelectFileDialog::Listener* listener) {
+ CEF_REQUIRE_UIT();
+ DCHECK(listener);
+
+ // This notification will arrive from whomever owns |listener|, so we don't
+ // want to execute any |listener| methods after this point.
+ if (dialog_listener_ && listener == dialog_listener_->listener()) {
+ // Cancel the currently active dialog.
+ SelectFileDoneByListenerCallback(/*listener_destroyed=*/true);
+ } else {
+ // Any future SelectFileDoneByDelegateCallback call for |listener| becomes a
+ // no-op.
+ active_listeners_.erase(listener);
+ }
+}
+
+CefFileDialogManager::RunFileChooserCallback
+CefFileDialogManager::MaybeRunDelegate(
+ const blink::mojom::FileChooserParams& params,
+ RunFileChooserCallback callback) {
+ if (auto client = browser_->client()) {
+ if (auto handler = browser_->client()->GetDialogHandler()) {
+ int mode = FILE_DIALOG_OPEN;
+ switch (params.mode) {
+ case blink::mojom::FileChooserParams::Mode::kOpen:
+ mode = FILE_DIALOG_OPEN;
+ break;
+ case blink::mojom::FileChooserParams::Mode::kOpenMultiple:
+ mode = FILE_DIALOG_OPEN_MULTIPLE;
+ break;
+ case blink::mojom::FileChooserParams::Mode::kUploadFolder:
+ mode = FILE_DIALOG_OPEN_FOLDER;
+ break;
+ case blink::mojom::FileChooserParams::Mode::kSave:
+ mode = FILE_DIALOG_SAVE;
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+
+ std::vector<std::u16string>::const_iterator it;
+
+ std::vector<CefString> accept_filters;
+ it = params.accept_types.begin();
+ for (; it != params.accept_types.end(); ++it) {
+ accept_filters.push_back(*it);
+ }
+
+ CefRefPtr<CefFileDialogCallbackImpl> callbackImpl(
+ new CefFileDialogCallbackImpl(std::move(callback)));
+ const bool handled = handler->OnFileDialog(
+ browser_, static_cast<cef_file_dialog_mode_t>(mode), params.title,
+ params.default_file_name.value(), accept_filters, callbackImpl.get());
+ if (!handled) {
+ // May return nullptr if the client has already executed the callback.
+ callback = callbackImpl->Disconnect();
+ }
+ }
+ }
+
+ return callback;
+}
+
+void CefFileDialogManager::SelectFileDoneByDelegateCallback(
+ ui::SelectFileDialog::Listener* listener,
+ void* params,
+ const std::vector<base::FilePath>& paths) {
+ CEF_REQUIRE_UIT();
+
+ // The listener may already be gone. This can occur if the client holds a
+ // RunFileChooserCallback past the call to SelectFileListenerDestroyed().
+ if (active_listeners_.find(listener) == active_listeners_.end()) {
+ return;
+ }
+
+ active_listeners_.erase(listener);
+
+ if (paths.empty()) {
+ listener->FileSelectionCanceled(params);
+ } else if (paths.size() == 1) {
+ listener->FileSelected(paths[0], /*index=*/0, params);
+ } else {
+ listener->MultiFilesSelected(paths, params);
+ }
+ // |listener| is likely deleted at this point.
+}
+
+void CefFileDialogManager::SelectFileDoneByListenerCallback(
+ bool listener_destroyed) {
+ CEF_REQUIRE_UIT();
+
+ // Avoid re-entrancy of this method. CefSelectFileDialogListener callbacks to
+ // the delegated listener may result in an immediate call to
+ // SelectFileListenerDestroyed() while |dialog_listener_| is still on the
+ // stack, followed by another execution from
+ // CefSelectFileDialogListener::Destroy(). Similarly, the below call to
+ // Cancel() may trigger another execution from
+ // CefSelectFileDialogListener::Destroy().
+ if (!dialog_listener_) {
+ return;
+ }
+
+ DCHECK(dialog_);
+ DCHECK(dialog_listener_);
+
+ active_listeners_.erase(dialog_listener_->listener());
+
+ // Clear |dialog_listener_| before calling Cancel() to avoid re-entrancy.
+ auto dialog_listener = dialog_listener_;
+ dialog_listener_ = nullptr;
+ dialog_listener->Cancel(listener_destroyed);
+
+ // There should be no further listener callbacks after this call.
+ dialog_->ListenerDestroyed();
+ dialog_ = nullptr;
+}
diff --git a/libcef/browser/file_dialog_manager.h b/libcef/browser/file_dialog_manager.h
new file mode 100644
index 00000000..dba19fc6
--- /dev/null
+++ b/libcef/browser/file_dialog_manager.h
@@ -0,0 +1,99 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors.
+// Portions copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_FILE_DIALOG_MANAGER_H_
+#define CEF_LIBCEF_BROWSER_FILE_DIALOG_MANAGER_H_
+#pragma once
+
+#include <memory>
+#include <set>
+
+#include "include/cef_browser.h"
+
+#include "base/memory/scoped_refptr.h"
+#include "third_party/blink/public/mojom/choosers/file_chooser.mojom.h"
+#include "ui/shell_dialogs/select_file_dialog.h"
+
+namespace content {
+class FileSelectListener;
+} // namespace content
+
+class CefBrowserHostBase;
+class CefSelectFileDialogListener;
+
+class CefFileDialogManager {
+ public:
+ explicit CefFileDialogManager(CefBrowserHostBase* browser);
+
+ CefFileDialogManager(const CefFileDialogManager&) = delete;
+ CefFileDialogManager& operator=(const CefFileDialogManager&) = delete;
+
+ ~CefFileDialogManager();
+
+ // Delete the runner to free any platform constructs.
+ void Destroy();
+
+ // Run a file dialog with the specified parameters. See
+ // CefBrowserHost::RunFileDialog for usage documentation. This method should
+ // be called via CefBrowserHostBase::RunFileDialog.
+ void RunFileDialog(cef_file_dialog_mode_t mode,
+ const CefString& title,
+ const CefString& default_file_path,
+ const std::vector<CefString>& accept_filters,
+ CefRefPtr<CefRunFileDialogCallback> callback);
+
+ // The argument vector will be empty if the dialog was canceled.
+ using RunFileChooserCallback =
+ base::OnceCallback<void(const std::vector<base::FilePath>&)>;
+
+ // Run the file dialog specified by |params|. |callback| will be executed
+ // synchronously or asynchronously after the dialog is dismissed. This method
+ // should be called via CefBrowserHostBase::RunFileChooser.
+ void RunFileChooser(const blink::mojom::FileChooserParams& params,
+ RunFileChooserCallback callback);
+
+ // Run a ui::SelectFileDialog with the specified parameters. See
+ // ui::SelectFileDialog for usage documentation. This method should be called
+ // via CefBrowserHostBase::RunSelectFile. It will be called for all file
+ // dialogs after interception via CefSelectFileDialog::SelectFileImpl.
+ void RunSelectFile(ui::SelectFileDialog::Listener* listener,
+ std::unique_ptr<ui::SelectFilePolicy> policy,
+ ui::SelectFileDialog::Type type,
+ const std::u16string& title,
+ const base::FilePath& default_path,
+ const ui::SelectFileDialog::FileTypeInfo* file_types,
+ int file_type_index,
+ const base::FilePath::StringType& default_extension,
+ gfx::NativeWindow owning_window,
+ void* params);
+
+ // Must be called when the |listener| passed to RunSelectFile is destroyed.
+ void SelectFileListenerDestroyed(ui::SelectFileDialog::Listener* listener);
+
+ private:
+ [[nodiscard]] RunFileChooserCallback MaybeRunDelegate(
+ const blink::mojom::FileChooserParams& params,
+ RunFileChooserCallback callback);
+
+ void SelectFileDoneByDelegateCallback(
+ ui::SelectFileDialog::Listener* listener,
+ void* params,
+ const std::vector<base::FilePath>& paths);
+ void SelectFileDoneByListenerCallback(bool listener_destroyed);
+
+ // CefBrowserHostBase pointer is guaranteed to outlive this object.
+ CefBrowserHostBase* const browser_;
+
+ // Used when running a platform dialog via RunSelectFile.
+ scoped_refptr<ui::SelectFileDialog> dialog_;
+ CefSelectFileDialogListener* dialog_listener_ = nullptr;
+
+ // List of all currently active listeners.
+ std::set<ui::SelectFileDialog::Listener*> active_listeners_;
+
+ base::WeakPtrFactory<CefFileDialogManager> weak_ptr_factory_{this};
+};
+
+#endif // CEF_LIBCEF_BROWSER_JAVASCRIPT_DIALOG_MANAGER_H_
diff --git a/libcef/browser/file_dialog_runner.cc b/libcef/browser/file_dialog_runner.cc
new file mode 100644
index 00000000..40eb2a33
--- /dev/null
+++ b/libcef/browser/file_dialog_runner.cc
@@ -0,0 +1,165 @@
+// Copyright (c) 2022 The Chromium Embedded Framework Authors.
+// Portions copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/file_dialog_runner.h"
+
+#include "libcef/browser/browser_host_base.h"
+#include "libcef/browser/extensions/browser_extensions_util.h"
+
+#include "base/memory/singleton.h"
+#include "chrome/browser/file_select_helper.h"
+#include "chrome/browser/ui/chrome_select_file_policy.h"
+#include "ui/shell_dialogs/select_file_dialog_factory.h"
+#include "ui/shell_dialogs/select_file_policy.h"
+
+using blink::mojom::FileChooserParams;
+
+namespace {
+
+// Creation of a file dialog can be triggered via various code paths, but they
+// all eventually result in a call to ui::SelectFileDialog::Create. We intercept
+// that call with CefSelectFileDialogFactory and redirect it to
+// CefFileDialogManager::RunSelectFile. After triggering the CefDialogHandler
+// callbacks that method calls ui::SelectFileDialog::Create again with
+// |run_from_cef=false| to trigger creation of the default platform dialog.
+class CefSelectFileDialogFactory final : public ui::SelectFileDialogFactory {
+ public:
+ CefSelectFileDialogFactory(const CefSelectFileDialogFactory&) = delete;
+ CefSelectFileDialogFactory& operator=(const CefSelectFileDialogFactory&) =
+ delete;
+
+ static CefSelectFileDialogFactory* GetInstance() {
+ // Leaky because there is no useful cleanup to do.
+ return base::Singleton<
+ CefSelectFileDialogFactory,
+ base::LeakySingletonTraits<CefSelectFileDialogFactory>>::get();
+ }
+
+ ui::SelectFileDialog* Create(
+ ui::SelectFileDialog::Listener* listener,
+ std::unique_ptr<ui::SelectFilePolicy> policy) override;
+
+ bool IsCefFactory() const override { return true; }
+
+ private:
+ friend struct base::DefaultSingletonTraits<CefSelectFileDialogFactory>;
+
+ CefSelectFileDialogFactory() { ui::SelectFileDialog::SetFactory(this); }
+};
+
+// Delegates the running of the dialog to CefFileDialogManager.
+class CefSelectFileDialog final : public ui::SelectFileDialog {
+ public:
+ CefSelectFileDialog(ui::SelectFileDialog::Listener* listener,
+ std::unique_ptr<ui::SelectFilePolicy> policy)
+ : ui::SelectFileDialog(listener, std::move(policy)) {
+ DCHECK(listener_);
+ }
+
+ CefSelectFileDialog(const CefSelectFileDialog&) = delete;
+ CefSelectFileDialog& operator=(const CefSelectFileDialog&) = delete;
+
+ void SelectFileImpl(Type type,
+ const std::u16string& title,
+ const base::FilePath& default_path,
+ const FileTypeInfo* file_types,
+ int file_type_index,
+ const base::FilePath::StringType& default_extension,
+ gfx::NativeWindow owning_window,
+ void* params,
+ const GURL* caller) override {
+ // Try to determine the associated browser (with decreasing levels of
+ // confidence).
+ // 1. Browser associated with the SelectFilePolicy. This is the most
+ // reliable mechanism if specified at the SelectFileDialog::Create call
+ // site.
+ if (select_file_policy_) {
+ auto chrome_policy =
+ static_cast<ChromeSelectFilePolicy*>(select_file_policy_.get());
+ auto web_contents = chrome_policy->source_contents();
+ if (web_contents) {
+ browser_ = extensions::GetOwnerBrowserForHost(
+ web_contents->GetRenderViewHost(), nullptr);
+ }
+ if (!browser_) {
+ LOG(WARNING) << "No browser associated with SelectFilePolicy";
+ }
+ }
+
+ // 2. Browser associated with the top-level native window (owning_window).
+ // This should be reliable with windowed browsers. However, |owning_window|
+ // will always be nullptr with windowless browsers.
+ if (!browser_ && owning_window) {
+ browser_ =
+ CefBrowserHostBase::GetBrowserForTopLevelNativeWindow(owning_window);
+ if (!browser_) {
+ LOG(WARNING) << "No browser associated with top-level native window";
+ }
+ }
+
+ // 3. Browser most likely to be focused. This may be somewhat iffy with
+ // windowless browsers as there is no guarantee that the client has only
+ // one browser focused at a time.
+ if (!browser_) {
+ browser_ = CefBrowserHostBase::GetLikelyFocusedBrowser();
+ if (!browser_) {
+ LOG(WARNING) << "No likely focused browser";
+ }
+ }
+
+ if (!browser_) {
+ LOG(ERROR)
+ << "Failed to identify associated browser; canceling the file dialog";
+ listener_->FileSelectionCanceled(params);
+ return;
+ }
+
+ owning_window_ = owning_window;
+ has_multiple_file_choices_ =
+ file_types ? file_types->extensions.size() > 1 : true;
+
+ browser_->RunSelectFile(listener_, std::move(select_file_policy_), type,
+ title, default_path, file_types, file_type_index,
+ default_extension, owning_window, params);
+ }
+
+ bool IsRunning(gfx::NativeWindow owning_window) const override {
+ return owning_window == owning_window_;
+ }
+
+ void ListenerDestroyed() override {
+ if (browser_) {
+ browser_->SelectFileListenerDestroyed(listener_);
+ }
+ listener_ = nullptr;
+ }
+
+ bool HasMultipleFileTypeChoicesImpl() override {
+ return has_multiple_file_choices_;
+ }
+
+ private:
+ gfx::NativeWindow owning_window_ = nullptr;
+ bool has_multiple_file_choices_ = false;
+
+ CefRefPtr<CefBrowserHostBase> browser_;
+};
+
+ui::SelectFileDialog* CefSelectFileDialogFactory::Create(
+ ui::SelectFileDialog::Listener* listener,
+ std::unique_ptr<ui::SelectFilePolicy> policy) {
+ return new CefSelectFileDialog(listener, std::move(policy));
+}
+
+} // namespace
+
+namespace file_dialog_runner {
+
+void RegisterFactory() {
+ // Implicitly registers on creation.
+ CefSelectFileDialogFactory::GetInstance();
+}
+
+} // namespace file_dialog_runner
diff --git a/libcef/browser/file_dialog_runner.h b/libcef/browser/file_dialog_runner.h
new file mode 100644
index 00000000..679a2c6a
--- /dev/null
+++ b/libcef/browser/file_dialog_runner.h
@@ -0,0 +1,17 @@
+// Copyright (c) 2022 The Chromium Embedded Framework Authors.
+// Portions copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_FILE_DIALOG_RUNNER_H_
+#define CEF_LIBCEF_BROWSER_FILE_DIALOG_RUNNER_H_
+#pragma once
+
+namespace file_dialog_runner {
+
+// One-time registration on startup.
+void RegisterFactory();
+
+} // namespace file_dialog_runner
+
+#endif // CEF_LIBCEF_BROWSER_FILE_DIALOG_RUNNER_H_
diff --git a/libcef/browser/frame_host_impl.cc b/libcef/browser/frame_host_impl.cc
new file mode 100644
index 00000000..6c7d68c2
--- /dev/null
+++ b/libcef/browser/frame_host_impl.cc
@@ -0,0 +1,730 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#include "libcef/browser/frame_host_impl.h"
+
+#include "include/cef_request.h"
+#include "include/cef_stream.h"
+#include "include/cef_v8.h"
+#include "include/test/cef_test_helpers.h"
+#include "libcef/browser/browser_host_base.h"
+#include "libcef/browser/net_service/browser_urlrequest_impl.h"
+#include "libcef/common/frame_util.h"
+#include "libcef/common/net/url_util.h"
+#include "libcef/common/process_message_impl.h"
+#include "libcef/common/process_message_smr_impl.h"
+#include "libcef/common/request_impl.h"
+#include "libcef/common/string_util.h"
+#include "libcef/common/task_runner_impl.h"
+
+#include "content/browser/renderer_host/frame_tree_node.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/render_view_host.h"
+#include "services/service_manager/public/cpp/interface_provider.h"
+
+namespace {
+
+void StringVisitCallback(CefRefPtr<CefStringVisitor> visitor,
+ base::ReadOnlySharedMemoryRegion response) {
+ string_util::ExecuteWithScopedCefString(
+ std::move(response),
+ base::BindOnce([](CefRefPtr<CefStringVisitor> visitor,
+ const CefString& str) { visitor->Visit(str); },
+ visitor));
+}
+
+void ViewTextCallback(CefRefPtr<CefFrameHostImpl> frame,
+ base::ReadOnlySharedMemoryRegion response) {
+ if (auto browser = frame->GetBrowser()) {
+ string_util::ExecuteWithScopedCefString(
+ std::move(response),
+ base::BindOnce(
+ [](CefRefPtr<CefBrowser> browser, const CefString& str) {
+ static_cast<CefBrowserHostBase*>(browser.get())->ViewText(str);
+ },
+ browser));
+ }
+}
+
+using CefFrameHostImplCommand = void (CefFrameHostImpl::*)();
+using WebContentsCommand = void (content::WebContents::*)();
+
+void ExecWebContentsCommand(CefFrameHostImpl* fh,
+ CefFrameHostImplCommand fh_func,
+ WebContentsCommand wc_func,
+ const std::string& command) {
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(CEF_UIT, base::BindOnce(fh_func, fh));
+ return;
+ }
+ auto rfh = fh->GetRenderFrameHost();
+ if (rfh) {
+ auto web_contents = content::WebContents::FromRenderFrameHost(rfh);
+ if (web_contents) {
+ std::invoke(wc_func, web_contents);
+ return;
+ }
+ }
+ fh->SendCommand(command);
+}
+
+#define EXEC_WEBCONTENTS_COMMAND(name) \
+ ExecWebContentsCommand(this, &CefFrameHostImpl::name, \
+ &content::WebContents::name, #name);
+
+} // namespace
+
+CefFrameHostImpl::CefFrameHostImpl(scoped_refptr<CefBrowserInfo> browser_info,
+ int64_t parent_frame_id)
+ : is_main_frame_(false),
+ frame_id_(kInvalidFrameId),
+ browser_info_(browser_info),
+ is_focused_(is_main_frame_), // The main frame always starts focused.
+ parent_frame_id_(parent_frame_id) {
+#if DCHECK_IS_ON()
+ DCHECK(browser_info_);
+ if (is_main_frame_) {
+ DCHECK_EQ(parent_frame_id_, kInvalidFrameId);
+ } else {
+ DCHECK_GT(parent_frame_id_, 0);
+ }
+#endif
+}
+
+CefFrameHostImpl::CefFrameHostImpl(scoped_refptr<CefBrowserInfo> browser_info,
+ content::RenderFrameHost* render_frame_host)
+ : is_main_frame_(render_frame_host->GetParent() == nullptr),
+ frame_id_(frame_util::MakeFrameId(render_frame_host->GetGlobalId())),
+ browser_info_(browser_info),
+ is_focused_(is_main_frame_), // The main frame always starts focused.
+ url_(render_frame_host->GetLastCommittedURL().spec()),
+ name_(render_frame_host->GetFrameName()),
+ parent_frame_id_(
+ is_main_frame_ ? kInvalidFrameId
+ : frame_util::MakeFrameId(
+ render_frame_host->GetParent()->GetGlobalId())),
+ render_frame_host_(render_frame_host) {
+ DCHECK(browser_info_);
+}
+
+CefFrameHostImpl::~CefFrameHostImpl() {
+ // Should have been Detached if not temporary.
+ DCHECK(is_temporary() || !browser_info_);
+ DCHECK(!render_frame_host_);
+}
+
+bool CefFrameHostImpl::IsValid() {
+ return !!GetBrowserHostBase();
+}
+
+void CefFrameHostImpl::Undo() {
+ EXEC_WEBCONTENTS_COMMAND(Undo);
+}
+
+void CefFrameHostImpl::Redo() {
+ EXEC_WEBCONTENTS_COMMAND(Redo);
+}
+
+void CefFrameHostImpl::Cut() {
+ EXEC_WEBCONTENTS_COMMAND(Cut);
+}
+
+void CefFrameHostImpl::Copy() {
+ EXEC_WEBCONTENTS_COMMAND(Copy);
+}
+
+void CefFrameHostImpl::Paste() {
+ EXEC_WEBCONTENTS_COMMAND(Paste);
+}
+
+void CefFrameHostImpl::Delete() {
+ EXEC_WEBCONTENTS_COMMAND(Delete);
+}
+
+void CefFrameHostImpl::SelectAll() {
+ EXEC_WEBCONTENTS_COMMAND(SelectAll);
+}
+
+void CefFrameHostImpl::ViewSource() {
+ SendCommandWithResponse(
+ "GetSource",
+ base::BindOnce(&ViewTextCallback, CefRefPtr<CefFrameHostImpl>(this)));
+}
+
+void CefFrameHostImpl::GetSource(CefRefPtr<CefStringVisitor> visitor) {
+ SendCommandWithResponse("GetSource",
+ base::BindOnce(&StringVisitCallback, visitor));
+}
+
+void CefFrameHostImpl::GetText(CefRefPtr<CefStringVisitor> visitor) {
+ SendCommandWithResponse("GetText",
+ base::BindOnce(&StringVisitCallback, visitor));
+}
+
+void CefFrameHostImpl::LoadRequest(CefRefPtr<CefRequest> request) {
+ auto params = cef::mojom::RequestParams::New();
+ static_cast<CefRequestImpl*>(request.get())->Get(params);
+ LoadRequest(std::move(params));
+}
+
+void CefFrameHostImpl::LoadURL(const CefString& url) {
+ LoadURLWithExtras(url, content::Referrer(), kPageTransitionExplicit,
+ std::string());
+}
+
+void CefFrameHostImpl::ExecuteJavaScript(const CefString& jsCode,
+ const CefString& scriptUrl,
+ int startLine) {
+ SendJavaScript(jsCode, scriptUrl, startLine);
+}
+
+bool CefFrameHostImpl::IsMain() {
+ return is_main_frame_;
+}
+
+bool CefFrameHostImpl::IsFocused() {
+ base::AutoLock lock_scope(state_lock_);
+ return is_focused_;
+}
+
+CefString CefFrameHostImpl::GetName() {
+ base::AutoLock lock_scope(state_lock_);
+ return name_;
+}
+
+int64 CefFrameHostImpl::GetIdentifier() {
+ base::AutoLock lock_scope(state_lock_);
+ return frame_id_;
+}
+
+CefRefPtr<CefFrame> CefFrameHostImpl::GetParent() {
+ int64 parent_frame_id;
+
+ {
+ base::AutoLock lock_scope(state_lock_);
+ if (is_main_frame_ || parent_frame_id_ == kInvalidFrameId) {
+ return nullptr;
+ }
+ parent_frame_id = parent_frame_id_;
+ }
+
+ auto browser = GetBrowserHostBase();
+ if (browser) {
+ return browser->GetFrame(parent_frame_id);
+ }
+
+ return nullptr;
+}
+
+CefString CefFrameHostImpl::GetURL() {
+ base::AutoLock lock_scope(state_lock_);
+ return url_;
+}
+
+CefRefPtr<CefBrowser> CefFrameHostImpl::GetBrowser() {
+ return GetBrowserHostBase().get();
+}
+
+CefRefPtr<CefV8Context> CefFrameHostImpl::GetV8Context() {
+ NOTREACHED() << "GetV8Context cannot be called from the browser process";
+ return nullptr;
+}
+
+void CefFrameHostImpl::VisitDOM(CefRefPtr<CefDOMVisitor> visitor) {
+ NOTREACHED() << "VisitDOM cannot be called from the browser process";
+}
+
+CefRefPtr<CefURLRequest> CefFrameHostImpl::CreateURLRequest(
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefURLRequestClient> client) {
+ if (!request || !client) {
+ return nullptr;
+ }
+
+ if (!CefTaskRunnerImpl::GetCurrentTaskRunner()) {
+ NOTREACHED() << "called on invalid thread";
+ return nullptr;
+ }
+
+ auto browser = GetBrowserHostBase();
+ if (!browser) {
+ return nullptr;
+ }
+
+ auto request_context = browser->request_context();
+
+ CefRefPtr<CefBrowserURLRequest> impl =
+ new CefBrowserURLRequest(this, request, client, request_context);
+ if (impl->Start()) {
+ return impl.get();
+ }
+ return nullptr;
+}
+
+void CefFrameHostImpl::SendProcessMessage(
+ CefProcessId target_process,
+ CefRefPtr<CefProcessMessage> message) {
+ DCHECK_EQ(PID_RENDERER, target_process);
+ DCHECK(message && message->IsValid());
+ if (!message || !message->IsValid()) {
+ return;
+ }
+
+ if (message->GetArgumentList() != nullptr) {
+ // Invalidate the message object immediately by taking the argument list.
+ auto argument_list =
+ static_cast<CefProcessMessageImpl*>(message.get())->TakeArgumentList();
+ SendToRenderFrame(
+ __FUNCTION__,
+ base::BindOnce(
+ [](const CefString& name, base::Value::List argument_list,
+ const RenderFrameType& render_frame) {
+ render_frame->SendMessage(name, std::move(argument_list));
+ },
+ message->GetName(), std::move(argument_list)));
+ } else {
+ auto region =
+ static_cast<CefProcessMessageSMRImpl*>(message.get())->TakeRegion();
+ SendToRenderFrame(
+ __FUNCTION__,
+ base::BindOnce(
+ [](const CefString& name, base::ReadOnlySharedMemoryRegion region,
+ const RenderFrameType& render_frame) {
+ render_frame->SendSharedMemoryRegion(name, std::move(region));
+ },
+ message->GetName(), std::move(region)));
+ }
+}
+
+void CefFrameHostImpl::SetFocused(bool focused) {
+ base::AutoLock lock_scope(state_lock_);
+ is_focused_ = focused;
+}
+
+void CefFrameHostImpl::RefreshAttributes() {
+ CEF_REQUIRE_UIT();
+
+ base::AutoLock lock_scope(state_lock_);
+ if (!render_frame_host_) {
+ return;
+ }
+ url_ = render_frame_host_->GetLastCommittedURL().spec();
+
+ // Use the assigned name if it is non-empty. This represents the name property
+ // on the frame DOM element. If the assigned name is empty, revert to the
+ // internal unique name. This matches the logic in render_frame_util::GetName.
+ name_ = render_frame_host_->GetFrameName();
+ if (name_.empty()) {
+ const auto node = content::FrameTreeNode::GloballyFindByID(
+ render_frame_host_->GetFrameTreeNodeId());
+ if (node) {
+ name_ = node->unique_name();
+ }
+ }
+
+ if (!is_main_frame_) {
+ parent_frame_id_ =
+ frame_util::MakeFrameId(render_frame_host_->GetParent()->GetGlobalId());
+ }
+}
+
+void CefFrameHostImpl::NotifyMoveOrResizeStarted() {
+ SendToRenderFrame(__FUNCTION__,
+ base::BindOnce([](const RenderFrameType& render_frame) {
+ render_frame->MoveOrResizeStarted();
+ }));
+}
+
+void CefFrameHostImpl::LoadRequest(cef::mojom::RequestParamsPtr params) {
+ if (!url_util::FixupGURL(params->url)) {
+ return;
+ }
+
+ SendToRenderFrame(__FUNCTION__,
+ base::BindOnce(
+ [](cef::mojom::RequestParamsPtr params,
+ const RenderFrameType& render_frame) {
+ render_frame->LoadRequest(std::move(params));
+ },
+ std::move(params)));
+
+ auto browser = GetBrowserHostBase();
+ if (browser) {
+ browser->OnSetFocus(FOCUS_SOURCE_NAVIGATION);
+ }
+}
+
+void CefFrameHostImpl::LoadURLWithExtras(const std::string& url,
+ const content::Referrer& referrer,
+ ui::PageTransition transition,
+ const std::string& extra_headers) {
+ // Only known frame ids or kMainFrameId are supported.
+ const auto frame_id = GetFrameId();
+ if (frame_id < CefFrameHostImpl::kMainFrameId) {
+ return;
+ }
+
+ // Any necessary fixup will occur in LoadRequest.
+ GURL gurl = url_util::MakeGURL(url, /*fixup=*/false);
+
+ if (frame_id == CefFrameHostImpl::kMainFrameId) {
+ // Load via the browser using NavigationController.
+ auto browser = GetBrowserHostBase();
+ if (browser) {
+ content::OpenURLParams params(
+ gurl, referrer, WindowOpenDisposition::CURRENT_TAB, transition,
+ /*is_renderer_initiated=*/false);
+ params.extra_headers = extra_headers;
+
+ browser->LoadMainFrameURL(params);
+ }
+ } else {
+ auto params = cef::mojom::RequestParams::New();
+ params->url = gurl;
+ params->referrer =
+ blink::mojom::Referrer::New(referrer.url, referrer.policy);
+ params->headers = extra_headers;
+ LoadRequest(std::move(params));
+ }
+}
+
+void CefFrameHostImpl::SendCommand(const std::string& command) {
+ DCHECK(!command.empty());
+ SendToRenderFrame(__FUNCTION__, base::BindOnce(
+ [](const std::string& command,
+ const RenderFrameType& render_frame) {
+ render_frame->SendCommand(command);
+ },
+ command));
+}
+
+void CefFrameHostImpl::SendCommandWithResponse(
+ const std::string& command,
+ cef::mojom::RenderFrame::SendCommandWithResponseCallback
+ response_callback) {
+ DCHECK(!command.empty());
+ SendToRenderFrame(
+ __FUNCTION__,
+ base::BindOnce(
+ [](const std::string& command,
+ cef::mojom::RenderFrame::SendCommandWithResponseCallback
+ response_callback,
+ const RenderFrameType& render_frame) {
+ render_frame->SendCommandWithResponse(command,
+ std::move(response_callback));
+ },
+ command, std::move(response_callback)));
+}
+
+void CefFrameHostImpl::SendJavaScript(const std::u16string& jsCode,
+ const std::string& scriptUrl,
+ int startLine) {
+ if (jsCode.empty()) {
+ return;
+ }
+ if (startLine <= 0) {
+ // A value of 0 is v8::Message::kNoLineNumberInfo in V8. There is code in
+ // V8 that will assert on that value (e.g. V8StackTraceImpl::Frame::Frame
+ // if a JS exception is thrown) so make sure |startLine| > 0.
+ startLine = 1;
+ }
+
+ SendToRenderFrame(
+ __FUNCTION__,
+ base::BindOnce(
+ [](const std::u16string& jsCode, const std::string& scriptUrl,
+ int startLine, const RenderFrameType& render_frame) {
+ render_frame->SendJavaScript(jsCode, scriptUrl, startLine);
+ },
+ jsCode, scriptUrl, startLine));
+}
+
+void CefFrameHostImpl::MaybeSendDidStopLoading() {
+ auto rfh = GetRenderFrameHost();
+ if (!rfh) {
+ return;
+ }
+
+ // We only want to notify for the highest-level LocalFrame in this frame's
+ // renderer process subtree. If this frame has a parent in the same process
+ // then the notification will be sent via the parent instead.
+ auto rfh_parent = rfh->GetParent();
+ if (rfh_parent && rfh_parent->GetProcess() == rfh->GetProcess()) {
+ return;
+ }
+
+ SendToRenderFrame(__FUNCTION__,
+ base::BindOnce([](const RenderFrameType& render_frame) {
+ render_frame->DidStopLoading();
+ }));
+}
+
+void CefFrameHostImpl::ExecuteJavaScriptWithUserGestureForTests(
+ const CefString& javascript) {
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(
+ CEF_UIT,
+ base::BindOnce(
+ &CefFrameHostImpl::ExecuteJavaScriptWithUserGestureForTests, this,
+ javascript));
+ return;
+ }
+
+ content::RenderFrameHost* rfh = GetRenderFrameHost();
+ if (rfh) {
+ rfh->ExecuteJavaScriptWithUserGestureForTests(javascript,
+ base::NullCallback());
+ }
+}
+
+content::RenderFrameHost* CefFrameHostImpl::GetRenderFrameHost() const {
+ CEF_REQUIRE_UIT();
+ return render_frame_host_;
+}
+
+bool CefFrameHostImpl::Detach(DetachReason reason) {
+ CEF_REQUIRE_UIT();
+
+ if (VLOG_IS_ON(1)) {
+ std::string reason_str;
+ switch (reason) {
+ case DetachReason::RENDER_FRAME_DELETED:
+ reason_str = "RENDER_FRAME_DELETED";
+ break;
+ case DetachReason::NEW_MAIN_FRAME:
+ reason_str = "NEW_MAIN_FRAME";
+ break;
+ case DetachReason::BROWSER_DESTROYED:
+ reason_str = "BROWSER_DESTROYED";
+ break;
+ };
+
+ VLOG(1) << GetDebugString() << " detached (reason=" << reason_str
+ << ", is_connected=" << render_frame_.is_bound() << ")";
+ }
+
+ // May be called multiple times (e.g. from CefBrowserInfo SetMainFrame and
+ // RemoveFrame).
+ bool first_detach = false;
+
+ // Should not be called for temporary frames.
+ DCHECK(!is_temporary());
+
+ {
+ base::AutoLock lock_scope(state_lock_);
+ if (browser_info_) {
+ first_detach = true;
+ browser_info_ = nullptr;
+ }
+ }
+
+ // In case we never attached, clean up.
+ while (!queued_renderer_actions_.empty()) {
+ queued_renderer_actions_.pop();
+ }
+
+ if (render_frame_.is_bound()) {
+ render_frame_->FrameDetached();
+ }
+
+ render_frame_.reset();
+ render_frame_host_ = nullptr;
+
+ return first_detach;
+}
+
+void CefFrameHostImpl::MaybeReAttach(
+ scoped_refptr<CefBrowserInfo> browser_info,
+ content::RenderFrameHost* render_frame_host) {
+ CEF_REQUIRE_UIT();
+ if (render_frame_.is_bound() && render_frame_host_ == render_frame_host) {
+ // Nothing to do here.
+ return;
+ }
+
+ // We expect that Detach() was called previously.
+ CHECK(!is_temporary());
+ CHECK(!render_frame_.is_bound());
+ CHECK(!render_frame_host_);
+
+ // The RFH may change but the GlobalId should remain the same.
+ CHECK_EQ(frame_id_,
+ frame_util::MakeFrameId(render_frame_host->GetGlobalId()));
+
+ {
+ base::AutoLock lock_scope(state_lock_);
+ browser_info_ = browser_info;
+ }
+
+ render_frame_host_ = render_frame_host;
+ RefreshAttributes();
+
+ // We expect a reconnect to be triggered via FrameAttached().
+}
+
+// kMainFrameId must be -1 to align with renderer expectations.
+const int64_t CefFrameHostImpl::kMainFrameId = -1;
+const int64_t CefFrameHostImpl::kFocusedFrameId = -2;
+const int64_t CefFrameHostImpl::kUnspecifiedFrameId = -3;
+const int64_t CefFrameHostImpl::kInvalidFrameId = -4;
+
+// This equates to (TT_EXPLICIT | TT_DIRECT_LOAD_FLAG).
+const ui::PageTransition CefFrameHostImpl::kPageTransitionExplicit =
+ static_cast<ui::PageTransition>(ui::PAGE_TRANSITION_TYPED |
+ ui::PAGE_TRANSITION_FROM_ADDRESS_BAR);
+
+int64 CefFrameHostImpl::GetFrameId() const {
+ base::AutoLock lock_scope(state_lock_);
+ return is_main_frame_ ? kMainFrameId : frame_id_;
+}
+
+scoped_refptr<CefBrowserInfo> CefFrameHostImpl::GetBrowserInfo() const {
+ base::AutoLock lock_scope(state_lock_);
+ return browser_info_;
+}
+
+CefRefPtr<CefBrowserHostBase> CefFrameHostImpl::GetBrowserHostBase() const {
+ if (auto browser_info = GetBrowserInfo()) {
+ return browser_info->browser();
+ }
+ return nullptr;
+}
+
+void CefFrameHostImpl::SendToRenderFrame(const std::string& function_name,
+ RenderFrameAction action) {
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(CEF_UIT,
+ base::BindOnce(&CefFrameHostImpl::SendToRenderFrame, this,
+ function_name, std::move(action)));
+ return;
+ }
+
+ if (is_temporary()) {
+ LOG(WARNING) << function_name
+ << " sent to temporary subframe will be ignored.";
+ return;
+ } else if (!render_frame_host_) {
+ // We've been detached.
+ LOG(WARNING) << function_name << " sent to detached " << GetDebugString()
+ << " will be ignored";
+ return;
+ }
+
+ if (!render_frame_.is_bound()) {
+ // Queue actions until we're notified by the renderer that it's ready to
+ // handle them.
+ queued_renderer_actions_.push(
+ std::make_pair(function_name, std::move(action)));
+ return;
+ }
+
+ std::move(action).Run(render_frame_);
+}
+
+void CefFrameHostImpl::OnRenderFrameDisconnect() {
+ CEF_REQUIRE_UIT();
+
+ // Reconnect, if any, will be triggered via FrameAttached().
+ render_frame_.reset();
+}
+
+void CefFrameHostImpl::SendMessage(const std::string& name,
+ base::Value::List arguments) {
+ if (auto browser = GetBrowserHostBase()) {
+ if (auto client = browser->GetClient()) {
+ CefRefPtr<CefProcessMessageImpl> message(
+ new CefProcessMessageImpl(name, std::move(arguments),
+ /*read_only=*/true));
+ browser->GetClient()->OnProcessMessageReceived(
+ browser.get(), this, PID_RENDERER, message.get());
+ }
+ }
+}
+
+void CefFrameHostImpl::SendSharedMemoryRegion(
+ const std::string& name,
+ base::ReadOnlySharedMemoryRegion region) {
+ if (auto browser = GetBrowserHostBase()) {
+ if (auto client = browser->GetClient()) {
+ CefRefPtr<CefProcessMessage> message(
+ new CefProcessMessageSMRImpl(name, std::move(region)));
+ browser->GetClient()->OnProcessMessageReceived(browser.get(), this,
+ PID_RENDERER, message);
+ }
+ }
+}
+
+void CefFrameHostImpl::FrameAttached(
+ mojo::PendingRemote<cef::mojom::RenderFrame> render_frame_remote,
+ bool reattached) {
+ CEF_REQUIRE_UIT();
+ CHECK(render_frame_remote);
+
+ auto browser_info = GetBrowserInfo();
+ if (!browser_info) {
+ // Already Detached.
+ return;
+ }
+
+ VLOG(1) << GetDebugString() << " " << (reattached ? "re" : "") << "connected";
+
+ render_frame_.Bind(std::move(render_frame_remote));
+ render_frame_.set_disconnect_handler(
+ base::BindOnce(&CefFrameHostImpl::OnRenderFrameDisconnect, this));
+
+ // Notify the renderer process that it can start sending messages.
+ render_frame_->FrameAttachedAck();
+
+ while (!queued_renderer_actions_.empty()) {
+ std::move(queued_renderer_actions_.front().second).Run(render_frame_);
+ queued_renderer_actions_.pop();
+ }
+
+ browser_info->MaybeExecuteFrameNotification(base::BindOnce(
+ [](CefRefPtr<CefFrameHostImpl> self, bool reattached,
+ CefRefPtr<CefFrameHandler> handler) {
+ if (auto browser = self->GetBrowserHostBase()) {
+ handler->OnFrameAttached(browser, self, reattached);
+ }
+ },
+ CefRefPtr<CefFrameHostImpl>(this), reattached));
+}
+
+void CefFrameHostImpl::UpdateDraggableRegions(
+ absl::optional<std::vector<cef::mojom::DraggableRegionEntryPtr>> regions) {
+ auto browser = GetBrowserHostBase();
+ if (!browser) {
+ return;
+ }
+
+ std::vector<CefDraggableRegion> draggable_regions;
+ if (regions) {
+ draggable_regions.reserve(regions->size());
+
+ for (const auto& region : *regions) {
+ const auto& rect = region->bounds;
+ const CefRect bounds(rect.x(), rect.y(), rect.width(), rect.height());
+ draggable_regions.push_back(
+ CefDraggableRegion(bounds, region->draggable));
+ }
+ }
+
+ // Delegate to BrowserInfo so that current state is maintained with
+ // cross-origin navigation.
+ browser_info_->MaybeNotifyDraggableRegionsChanged(
+ browser, this, std::move(draggable_regions));
+}
+
+std::string CefFrameHostImpl::GetDebugString() const {
+ return "frame " + frame_util::GetFrameDebugString(frame_id_) +
+ (is_main_frame_ ? " (main)" : " (sub)");
+}
+
+void CefExecuteJavaScriptWithUserGestureForTests(CefRefPtr<CefFrame> frame,
+ const CefString& javascript) {
+ CefFrameHostImpl* impl = static_cast<CefFrameHostImpl*>(frame.get());
+ if (impl) {
+ impl->ExecuteJavaScriptWithUserGestureForTests(javascript);
+ }
+}
diff --git a/libcef/browser/frame_host_impl.h b/libcef/browser/frame_host_impl.h
new file mode 100644
index 00000000..71b234d6
--- /dev/null
+++ b/libcef/browser/frame_host_impl.h
@@ -0,0 +1,197 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_FRAME_HOST_IMPL_H_
+#define CEF_LIBCEF_BROWSER_FRAME_HOST_IMPL_H_
+#pragma once
+
+#include <memory>
+#include <queue>
+#include <string>
+
+#include "include/cef_frame.h"
+
+#include "base/synchronization/lock.h"
+#include "cef/libcef/common/mojom/cef.mojom.h"
+#include "mojo/public/cpp/bindings/receiver_set.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "ui/base/page_transition_types.h"
+
+namespace content {
+class RenderFrameHost;
+struct Referrer;
+} // namespace content
+
+class GURL;
+
+class CefBrowserInfo;
+class CefBrowserHostBase;
+
+// Implementation of CefFrame. CefFrameHostImpl objects should always be created
+// or retrieved via CefBrowerInfo.
+class CefFrameHostImpl : public CefFrame, public cef::mojom::BrowserFrame {
+ public:
+ // Create a temporary sub-frame.
+ CefFrameHostImpl(scoped_refptr<CefBrowserInfo> browser_info,
+ int64_t parent_frame_id);
+
+ // Create a frame backed by a RFH and owned by CefBrowserInfo.
+ CefFrameHostImpl(scoped_refptr<CefBrowserInfo> browser_info,
+ content::RenderFrameHost* render_frame_host);
+
+ CefFrameHostImpl(const CefFrameHostImpl&) = delete;
+ CefFrameHostImpl& operator=(const CefFrameHostImpl&) = delete;
+
+ ~CefFrameHostImpl() override;
+
+ // CefFrame methods
+ bool IsValid() override;
+ void Undo() override;
+ void Redo() override;
+ void Cut() override;
+ void Copy() override;
+ void Paste() override;
+ void Delete() override;
+ void SelectAll() override;
+ void ViewSource() override;
+ void GetSource(CefRefPtr<CefStringVisitor> visitor) override;
+ void GetText(CefRefPtr<CefStringVisitor> visitor) override;
+ void LoadRequest(CefRefPtr<CefRequest> request) override;
+ void LoadURL(const CefString& url) override;
+ void ExecuteJavaScript(const CefString& jsCode,
+ const CefString& scriptUrl,
+ int startLine) override;
+ bool IsMain() override;
+ bool IsFocused() override;
+ CefString GetName() override;
+ int64 GetIdentifier() override;
+ CefRefPtr<CefFrame> GetParent() override;
+ CefString GetURL() override;
+ CefRefPtr<CefBrowser> GetBrowser() override;
+ CefRefPtr<CefV8Context> GetV8Context() override;
+ void VisitDOM(CefRefPtr<CefDOMVisitor> visitor) override;
+ CefRefPtr<CefURLRequest> CreateURLRequest(
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefURLRequestClient> client) override;
+ void SendProcessMessage(CefProcessId target_process,
+ CefRefPtr<CefProcessMessage> message) override;
+
+ bool is_temporary() const { return frame_id_ == kInvalidFrameId; }
+
+ void SetFocused(bool focused);
+ void RefreshAttributes();
+
+ // Notification that a move or resize of the renderer's containing window has
+ // started. Used on Windows and Linux with the Alloy runtime.
+ void NotifyMoveOrResizeStarted();
+
+ // Load the specified request.
+ void LoadRequest(cef::mojom::RequestParamsPtr params);
+
+ // Load the specified URL.
+ void LoadURLWithExtras(const std::string& url,
+ const content::Referrer& referrer,
+ ui::PageTransition transition,
+ const std::string& extra_headers);
+
+ // Send a command to the renderer for execution.
+ void SendCommand(const std::string& command);
+ void SendCommandWithResponse(
+ const std::string& command,
+ cef::mojom::RenderFrame::SendCommandWithResponseCallback
+ response_callback);
+
+ // Send JavaScript to the renderer for execution.
+ void SendJavaScript(const std::u16string& jsCode,
+ const std::string& scriptUrl,
+ int startLine);
+
+ // Called from CefBrowserHostBase::DidStopLoading.
+ void MaybeSendDidStopLoading();
+
+ void ExecuteJavaScriptWithUserGestureForTests(const CefString& javascript);
+
+ // Returns the RFH associated with this frame. Must be called on the UI
+ // thread.
+ content::RenderFrameHost* GetRenderFrameHost() const;
+
+ enum class DetachReason {
+ RENDER_FRAME_DELETED,
+ NEW_MAIN_FRAME,
+ BROWSER_DESTROYED,
+ };
+
+ // Owned frame objects will be detached explicitly when the associated
+ // RenderFrame is deleted. Temporary frame objects will be detached
+ // implicitly via CefBrowserInfo::browser() returning nullptr. Returns true
+ // if this was the first call to Detach() for the frame.
+ bool Detach(DetachReason reason);
+
+ // A frame has swapped to active status from prerendering or the back-forward
+ // cache. We may need to re-attach if the RFH has changed. See
+ // https://crbug.com/1179502#c8 for additional background.
+ void MaybeReAttach(scoped_refptr<CefBrowserInfo> browser_info,
+ content::RenderFrameHost* render_frame_host);
+
+ // cef::mojom::BrowserFrame methods forwarded from CefBrowserFrame.
+ void SendMessage(const std::string& name,
+ base::Value::List arguments) override;
+ void SendSharedMemoryRegion(const std::string& name,
+ base::ReadOnlySharedMemoryRegion region) override;
+ void FrameAttached(mojo::PendingRemote<cef::mojom::RenderFrame> render_frame,
+ bool reattached) override;
+ void UpdateDraggableRegions(
+ absl::optional<std::vector<cef::mojom::DraggableRegionEntryPtr>> regions)
+ override;
+
+ static const int64_t kMainFrameId;
+ static const int64_t kFocusedFrameId;
+ static const int64_t kUnspecifiedFrameId;
+ static const int64_t kInvalidFrameId;
+
+ // PageTransition type for explicit navigations. This must pass the check in
+ // ContentBrowserClient::IsExplicitNavigation for debug URLs (HandleDebugURL)
+ // to work as expected.
+ static const ui::PageTransition kPageTransitionExplicit;
+
+ private:
+ int64 GetFrameId() const;
+ scoped_refptr<CefBrowserInfo> GetBrowserInfo() const;
+ CefRefPtr<CefBrowserHostBase> GetBrowserHostBase() const;
+
+ // Send an action to the remote RenderFrame. This will queue the action if the
+ // remote frame is not yet attached.
+ using RenderFrameType = mojo::Remote<cef::mojom::RenderFrame>;
+ using RenderFrameAction = base::OnceCallback<void(const RenderFrameType&)>;
+ void SendToRenderFrame(const std::string& function_name,
+ RenderFrameAction action);
+
+ void OnRenderFrameDisconnect();
+
+ std::string GetDebugString() const;
+
+ const bool is_main_frame_;
+
+ // The following members may be read/modified from any thread. All access must
+ // be protected by |state_lock_|.
+ mutable base::Lock state_lock_;
+ int64 frame_id_;
+ scoped_refptr<CefBrowserInfo> browser_info_;
+ bool is_focused_;
+ CefString url_;
+ CefString name_;
+ int64 parent_frame_id_;
+
+ // The following members are only accessed on the UI thread.
+ content::RenderFrameHost* render_frame_host_ = nullptr;
+
+ std::queue<std::pair<std::string, RenderFrameAction>>
+ queued_renderer_actions_;
+
+ mojo::Remote<cef::mojom::RenderFrame> render_frame_;
+
+ IMPLEMENT_REFCOUNTING(CefFrameHostImpl);
+};
+
+#endif // CEF_LIBCEF_BROWSER_FRAME_HOST_IMPL_H_
diff --git a/libcef/browser/frame_service_base.h b/libcef/browser/frame_service_base.h
new file mode 100644
index 00000000..795ac299
--- /dev/null
+++ b/libcef/browser/frame_service_base.h
@@ -0,0 +1,126 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_FRAME_SERVICE_BASE_H_
+#define CEF_LIBCEF_BROWSER_FRAME_SERVICE_BASE_H_
+
+#include <utility>
+
+#include "base/functional/bind.h"
+#include "base/logging.h"
+#include "base/threading/thread_checker.h"
+#include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "url/origin.h"
+
+namespace content {
+
+// Base class for mojo interface implementations tied to a document's lifetime.
+// The service will be destroyed when any of the following happens:
+// 1. mojo interface connection error happened,
+// 2. the RenderFrameHost was deleted, or
+// 3. navigation was committed on the RenderFrameHost (not same document) and
+// ShouldCloseOnFinishNavigation() returns true.
+//
+// WARNING: To avoid race conditions, subclasses MUST only get the origin via
+// origin() instead of from |render_frame_host| passed in the constructor.
+// See https://crbug.com/769189 for an example of such a race.
+//
+// Based on the old implementation of DocumentServiceBase that existed prior to
+// https://crrev.com/2809effa24. CEF requires the old implementation to support
+// bindings that outlive navigation.
+template <typename Interface>
+class FrameServiceBase : public Interface, public WebContentsObserver {
+ public:
+ FrameServiceBase(RenderFrameHost* render_frame_host,
+ mojo::PendingReceiver<Interface> pending_receiver)
+ : WebContentsObserver(
+ WebContents::FromRenderFrameHost(render_frame_host)),
+ render_frame_host_(render_frame_host),
+ origin_(render_frame_host_->GetLastCommittedOrigin()),
+ receiver_(this, std::move(pending_receiver)) {
+ // |this| owns |receiver_|, so unretained is safe.
+ receiver_.set_disconnect_handler(
+ base::BindOnce(&FrameServiceBase::Close, base::Unretained(this)));
+ }
+
+ protected:
+ // Make the destructor private since |this| can only be deleted by Close().
+ virtual ~FrameServiceBase() = default;
+
+ // All subclasses should use this function to obtain the origin instead of
+ // trying to get it from the RenderFrameHost pointer directly.
+ const url::Origin& origin() const { return origin_; }
+
+ // Returns the RenderFrameHost held by this object.
+ RenderFrameHost* render_frame_host() const { return render_frame_host_; }
+
+ // Subclasses can use this to check thread safety.
+ // For example: DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ THREAD_CHECKER(thread_checker_);
+
+ private:
+ // Disallow calling web_contents() directly from the subclasses to ensure that
+ // tab-level state doesn't get queried or updated when the RenderFrameHost is
+ // not active.
+ // Use WebContents::From(render_frame_host()) instead, but please keep in mind
+ // that the render_frame_host() might not be active. See
+ // RenderFrameHost::IsActive() for details.
+ using WebContentsObserver::web_contents;
+
+ // WebContentsObserver implementation.
+ void RenderFrameDeleted(RenderFrameHost* render_frame_host) final {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+ if (render_frame_host == render_frame_host_) {
+ DVLOG(1) << __func__ << ": RenderFrame destroyed.";
+ Close();
+ }
+ }
+
+ void DidFinishNavigation(NavigationHandle* navigation_handle) final {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ if (!ShouldCloseOnFinishNavigation()) {
+ return;
+ }
+
+ if (!navigation_handle->HasCommitted() ||
+ navigation_handle->IsSameDocument() ||
+ navigation_handle->IsPageActivation()) {
+ return;
+ }
+
+ if (navigation_handle->GetRenderFrameHost() == render_frame_host_) {
+ // FrameServiceBase is destroyed either when RenderFrameHost is
+ // destroyed (covered by RenderFrameDeleted) or when a new document
+ // commits in the same RenderFrameHost (covered by DidFinishNavigation).
+ // Only committed non-same-document non-bfcache non-prerendering
+ // activation navigations replace a document in existing RenderFrameHost.
+ DVLOG(1) << __func__ << ": Close connection on navigation.";
+ Close();
+ }
+ }
+
+ // Used for CEF bindings that outlive navigation.
+ virtual bool ShouldCloseOnFinishNavigation() const { return true; }
+
+ // Stops observing WebContents and delete |this|.
+ void Close() {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ DVLOG(1) << __func__;
+ delete this;
+ }
+
+ RenderFrameHost* const render_frame_host_ = nullptr;
+ const url::Origin origin_;
+ mojo::Receiver<Interface> receiver_;
+};
+
+} // namespace content
+
+#endif // CEF_LIBCEF_BROWSER_FRAME_SERVICE_BASE_H_
diff --git a/libcef/browser/global_preference_manager_impl.cc b/libcef/browser/global_preference_manager_impl.cc
new file mode 100644
index 00000000..8a58aba6
--- /dev/null
+++ b/libcef/browser/global_preference_manager_impl.cc
@@ -0,0 +1,54 @@
+// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "libcef/browser/global_preference_manager_impl.h"
+
+#include "libcef/browser/context.h"
+#include "libcef/browser/prefs/pref_helper.h"
+#include "libcef/browser/thread_util.h"
+
+#include "chrome/browser/browser_process.h"
+
+bool CefGlobalPreferenceManagerImpl::HasPreference(const CefString& name) {
+ CEF_REQUIRE_UIT_RETURN(false);
+ return pref_helper::HasPreference(g_browser_process->local_state(), name);
+}
+
+CefRefPtr<CefValue> CefGlobalPreferenceManagerImpl::GetPreference(
+ const CefString& name) {
+ CEF_REQUIRE_UIT_RETURN(nullptr);
+ return pref_helper::GetPreference(g_browser_process->local_state(), name);
+}
+
+CefRefPtr<CefDictionaryValue> CefGlobalPreferenceManagerImpl::GetAllPreferences(
+ bool include_defaults) {
+ CEF_REQUIRE_UIT_RETURN(nullptr);
+ return pref_helper::GetAllPreferences(g_browser_process->local_state(),
+ include_defaults);
+}
+
+bool CefGlobalPreferenceManagerImpl::CanSetPreference(const CefString& name) {
+ CEF_REQUIRE_UIT_RETURN(false);
+ return pref_helper::CanSetPreference(g_browser_process->local_state(), name);
+}
+
+bool CefGlobalPreferenceManagerImpl::SetPreference(const CefString& name,
+ CefRefPtr<CefValue> value,
+ CefString& error) {
+ CEF_REQUIRE_UIT_RETURN(false);
+ return pref_helper::SetPreference(g_browser_process->local_state(), name,
+ value, error);
+}
+
+// static
+CefRefPtr<CefPreferenceManager>
+CefPreferenceManager::GetGlobalPreferenceManager() {
+ // Verify that the context is in a valid state.
+ if (!CONTEXT_STATE_VALID()) {
+ NOTREACHED() << "context not valid";
+ return nullptr;
+ }
+
+ return new CefGlobalPreferenceManagerImpl();
+}
diff --git a/libcef/browser/global_preference_manager_impl.h b/libcef/browser/global_preference_manager_impl.h
new file mode 100644
index 00000000..d10a7f5b
--- /dev/null
+++ b/libcef/browser/global_preference_manager_impl.h
@@ -0,0 +1,35 @@
+// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_GLOBAL_PREFERENCE_MANAGER_IMPL_H_
+#define CEF_LIBCEF_BROWSER_GLOBAL_PREFERENCE_MANAGER_IMPL_H_
+#pragma once
+
+#include "include/cef_preference.h"
+
+// Implementation of the CefPreferenceManager interface for global preferences.
+class CefGlobalPreferenceManagerImpl : public CefPreferenceManager {
+ public:
+ CefGlobalPreferenceManagerImpl() = default;
+
+ CefGlobalPreferenceManagerImpl(const CefGlobalPreferenceManagerImpl&) =
+ delete;
+ CefGlobalPreferenceManagerImpl& operator=(
+ const CefGlobalPreferenceManagerImpl&) = delete;
+
+ // CefPreferenceManager methods.
+ bool HasPreference(const CefString& name) override;
+ CefRefPtr<CefValue> GetPreference(const CefString& name) override;
+ CefRefPtr<CefDictionaryValue> GetAllPreferences(
+ bool include_defaults) override;
+ bool CanSetPreference(const CefString& name) override;
+ bool SetPreference(const CefString& name,
+ CefRefPtr<CefValue> value,
+ CefString& error) override;
+
+ private:
+ IMPLEMENT_REFCOUNTING(CefGlobalPreferenceManagerImpl);
+};
+
+#endif // CEF_LIBCEF_BROWSER_GLOBAL_PREFERENCE_MANAGER_IMPL_H_
diff --git a/libcef/browser/gpu/external_texture_manager.cc b/libcef/browser/gpu/external_texture_manager.cc
new file mode 100644
index 00000000..cf06c107
--- /dev/null
+++ b/libcef/browser/gpu/external_texture_manager.cc
@@ -0,0 +1,341 @@
+// Copyright 2018 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cef/libcef/browser/gpu/external_texture_manager.h"
+
+#include "gpu/command_buffer/service/service_utils.h"
+#include "third_party/khronos/EGL/egl.h"
+#include "third_party/khronos/EGL/eglext.h"
+#include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_context_egl.h"
+#include "ui/gl/gl_image.h"
+#include "ui/gl/gl_surface_egl.h"
+#include "ui/gl/init/gl_factory.h"
+
+#if BUILDFLAG(IS_WIN)
+#include <d3d11_1.h>
+#include "ui/gl/gl_angle_util_win.h"
+#include "ui/gl/gl_image_dxgi.h"
+#endif
+
+#ifndef EGL_ANGLE_d3d_texture_client_buffer
+#define EGL_ANGLE_d3d_texture_client_buffer 1
+#define EGL_D3D_TEXTURE_ANGLE 0x33A3
+#endif
+
+namespace gpu {
+namespace gles2 {
+
+namespace {
+
+#if BUILDFLAG(IS_WIN)
+
+class GLImageDXGISharedHandle : public gl::GLImageDXGI {
+ public:
+ GLImageDXGISharedHandle(const gfx::Size& size)
+ : GLImageDXGI(size, nullptr),
+ handle_((HANDLE)0),
+ surface_(EGL_NO_SURFACE),
+ texture_id_(0) {}
+
+ void* share_handle() const { return handle_; }
+
+ bool Initialize() {
+ Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device =
+ gl::QueryD3D11DeviceObjectFromANGLE();
+ if (!d3d11_device) {
+ return false;
+ }
+
+ Microsoft::WRL::ComPtr<ID3D11Device1> d3d11_device1;
+ HRESULT hr = d3d11_device.As(&d3d11_device1);
+ if (FAILED(hr)) {
+ return false;
+ }
+
+ D3D11_TEXTURE2D_DESC td = {0};
+ td.ArraySize = 1;
+ td.CPUAccessFlags = 0;
+ td.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
+ td.Width = GetSize().width();
+ td.Height = GetSize().height();
+ td.MipLevels = 1;
+ td.SampleDesc.Count = 1;
+ td.SampleDesc.Quality = 0;
+ td.Usage = D3D11_USAGE_DEFAULT;
+ td.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
+ td.MiscFlags = 0;
+
+ hr = d3d11_device1->CreateTexture2D(&td, nullptr, texture_.GetAddressOf());
+ if (FAILED(hr)) {
+ return false;
+ }
+
+ // Create a staging texture that will not be a render-target, but will be
+ // shared. We could make the render target directly shareable, but the
+ // staged copy is safer for synchronization and less problematic
+ td.BindFlags = D3D11_BIND_SHADER_RESOURCE;
+ td.MiscFlags = D3D11_RESOURCE_MISC_SHARED;
+ hr = d3d11_device1->CreateTexture2D(&td, nullptr,
+ staging_texture_.GetAddressOf());
+ if (FAILED(hr)) {
+ return false;
+ }
+
+ // If using a staging texture ... then we need the shared handle for that
+ Microsoft::WRL::ComPtr<IDXGIResource> dxgi_res;
+ if (staging_texture_.Get()) {
+ hr = staging_texture_.As(&dxgi_res);
+ } else {
+ hr = texture_.As(&dxgi_res);
+ }
+ if (SUCCEEDED(hr)) {
+ dxgi_res->GetSharedHandle(&handle_);
+ }
+
+ return true;
+ }
+
+ void Lock() {
+ // In the future a keyed mutex could be utilized here.
+ }
+
+ void Unlock() {
+ if (staging_texture_.Get() && texture_.Get()) {
+ Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device;
+ staging_texture_->GetDevice(&d3d11_device);
+ if (d3d11_device.Get()) {
+ Microsoft::WRL::ComPtr<ID3D11DeviceContext> d3d11_ctx;
+ d3d11_device->GetImmediateContext(&d3d11_ctx);
+ if (d3d11_ctx.Get()) {
+ d3d11_ctx->CopyResource(staging_texture_.Get(), texture_.Get());
+ }
+ }
+ }
+ }
+
+ void SetSurface(EGLSurface surface, GLuint texture_id) {
+ surface_ = surface;
+ texture_id_ = texture_id;
+ }
+
+ EGLSurface surface() const { return surface_; }
+
+ GLuint texture_id() const { return texture_id_; }
+
+ protected:
+ ~GLImageDXGISharedHandle() override {}
+
+ private:
+ HANDLE handle_;
+ Microsoft::WRL::ComPtr<ID3D11Texture2D> staging_texture_;
+ EGLSurface surface_;
+ GLuint texture_id_;
+};
+
+#endif // BUILDFLAG(IS_WIN)
+
+} // namespace
+
+ExternalTextureManager::ExternalTextureManager() {}
+
+ExternalTextureManager::~ExternalTextureManager() {}
+
+void* ExternalTextureManager::CreateTexture(GLuint texture_id,
+ uint32_t width,
+ uint32_t height,
+ TextureManager* tex_man) {
+ void* share_handle = nullptr;
+
+#if BUILDFLAG(IS_WIN)
+ EGLDisplay egl_display = gl::GLSurfaceEGL::GetHardwareDisplay();
+ if (egl_display == EGL_NO_DISPLAY) {
+ return nullptr;
+ }
+
+ EGLContext curContext = eglGetCurrentContext();
+ if (curContext == EGL_NO_CONTEXT) {
+ return nullptr;
+ }
+
+ gfx::Size size(width, height);
+ scoped_refptr<gl::GLImage> image;
+ void* texture = nullptr;
+
+ GLImageDXGISharedHandle* dxgi_image = new GLImageDXGISharedHandle(size);
+ if (!dxgi_image->Initialize()) {
+ return nullptr;
+ }
+ image = dxgi_image;
+ share_handle = dxgi_image->share_handle();
+ texture = dxgi_image->texture().Get();
+
+ if (!image) { // this check seems unnecessary
+ return nullptr;
+ }
+
+ EGLint numConfigs = 0;
+ EGLint configAttrs[] = {
+ EGL_RENDERABLE_TYPE,
+ EGL_OPENGL_ES3_BIT, // must remain in this position for ES2 fallback
+ EGL_SURFACE_TYPE,
+ EGL_PBUFFER_BIT,
+ EGL_BUFFER_SIZE,
+ 32,
+ EGL_RED_SIZE,
+ 8,
+ EGL_GREEN_SIZE,
+ 8,
+ EGL_BLUE_SIZE,
+ 8,
+ EGL_ALPHA_SIZE,
+ 8,
+ EGL_DEPTH_SIZE,
+ 0,
+ EGL_STENCIL_SIZE,
+ 0,
+ EGL_SAMPLE_BUFFERS,
+ 0,
+ EGL_NONE};
+
+ EGLConfig config = nullptr;
+ if (eglChooseConfig(egl_display, configAttrs, &config, 1, &numConfigs) !=
+ EGL_TRUE) {
+ return nullptr;
+ }
+
+ EGLSurface surface = EGL_NO_SURFACE;
+ EGLint surfAttrs[] = {EGL_WIDTH,
+ width,
+ EGL_HEIGHT,
+ height,
+ EGL_TEXTURE_TARGET,
+ EGL_TEXTURE_2D,
+ EGL_TEXTURE_FORMAT,
+ EGL_TEXTURE_RGBA,
+ EGL_NONE};
+
+ surface = eglCreatePbufferFromClientBuffer(egl_display, EGL_D3D_TEXTURE_ANGLE,
+ texture, config, surfAttrs);
+ if (surface == EGL_NO_SURFACE) {
+ // fallback to ES2 - it could be that we're running on older hardware
+ // and ES3 isn't available
+
+ // EGL_RENDERABLE_TYPE is the bit at configAttrs[0]
+ configAttrs[1] = EGL_OPENGL_ES2_BIT;
+ config = nullptr;
+ if (eglChooseConfig(egl_display, configAttrs, &config, 1, &numConfigs) ==
+ EGL_TRUE) {
+ surface = eglCreatePbufferFromClientBuffer(
+ egl_display, EGL_D3D_TEXTURE_ANGLE, texture, config, surfAttrs);
+ }
+
+ // still no surface? we're done
+ if (surface == EGL_NO_SURFACE) {
+ return nullptr;
+ }
+ }
+
+ dxgi_image->SetSurface(surface, texture_id);
+
+ surfaceMap_[share_handle] = image;
+
+ EGLSurface drawSurface = eglGetCurrentSurface(EGL_DRAW);
+ EGLSurface readSurface = eglGetCurrentSurface(EGL_READ);
+
+ eglMakeCurrent(egl_display, surface, surface, curContext);
+
+ if (eglBindTexImage(egl_display, surface, EGL_BACK_BUFFER)) {
+ if (tex_man) {
+ TextureRef* texture_ref = tex_man->GetTexture(texture_id);
+ tex_man->SetLevelInfo(texture_ref, GL_TEXTURE_2D, 0, GL_BGRA_EXT, width,
+ height, 1, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE,
+ gfx::Rect(size));
+ tex_man->SetLevelImage(texture_ref, GL_TEXTURE_2D, 0, image.get(),
+ Texture::BOUND);
+ }
+ }
+
+ eglMakeCurrent(egl_display, drawSurface, readSurface, curContext);
+
+#endif // BUILDFLAG(IS_WIN)
+
+ return share_handle;
+}
+
+void ExternalTextureManager::LockTexture(void* handle) {
+#if BUILDFLAG(IS_WIN)
+ auto const img = surfaceMap_.find(handle);
+ if (img != surfaceMap_.end()) {
+ GLImageDXGISharedHandle* dxgi_image =
+ reinterpret_cast<GLImageDXGISharedHandle*>(img->second.get());
+ dxgi_image->Lock();
+ }
+#endif // BUILDFLAG(IS_WIN)
+}
+
+void ExternalTextureManager::UnlockTexture(void* handle) {
+#if BUILDFLAG(IS_WIN)
+ auto const img = surfaceMap_.find(handle);
+ if (img != surfaceMap_.end()) {
+ GLImageDXGISharedHandle* dxgi_image =
+ reinterpret_cast<GLImageDXGISharedHandle*>(img->second.get());
+ dxgi_image->Unlock();
+ }
+#endif // BUILDFLAG(IS_WIN)
+}
+
+void ExternalTextureManager::DeleteTexture(void* handle,
+ TextureManager* tex_man) {
+#if BUILDFLAG(IS_WIN)
+ EGLDisplay egl_display = gl::GLSurfaceEGL::GetHardwareDisplay();
+ if (egl_display == EGL_NO_DISPLAY) {
+ return;
+ }
+ auto const img = surfaceMap_.find(handle);
+ if (img == surfaceMap_.end()) {
+ return;
+ }
+
+ EGLSurface surface = EGL_NO_SURFACE;
+ GLuint texture_id = 0;
+
+ GLImageDXGISharedHandle* dxgi_image =
+ reinterpret_cast<GLImageDXGISharedHandle*>(img->second.get());
+ surface = dxgi_image->surface();
+ texture_id = dxgi_image->texture_id();
+
+ if (surface != EGL_NO_SURFACE) {
+ EGLContext curContext = eglGetCurrentContext();
+ if (curContext != EGL_NO_CONTEXT) {
+ EGLSurface drawSurface = eglGetCurrentSurface(EGL_DRAW);
+ EGLSurface readSurface = eglGetCurrentSurface(EGL_READ);
+
+ eglMakeCurrent(egl_display, surface, surface, curContext);
+
+ TextureRef* texture_ref = nullptr;
+ if (tex_man) {
+ texture_ref = tex_man->GetTexture(texture_id);
+ }
+
+ eglReleaseTexImage(egl_display, surface, EGL_BACK_BUFFER);
+
+ if (tex_man && texture_ref) {
+ tex_man->SetLevelInfo(texture_ref, GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 1,
+ 0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect());
+ tex_man->SetLevelImage(texture_ref, GL_TEXTURE_2D, 0, nullptr,
+ Texture::UNBOUND);
+ }
+
+ eglMakeCurrent(egl_display, drawSurface, readSurface, curContext);
+
+ eglDestroySurface(egl_display, surface);
+ }
+ }
+ surfaceMap_.erase(img);
+#endif // BUILDFLAG(IS_WIN)
+}
+
+} // namespace gles2
+} // namespace gpu
diff --git a/libcef/browser/gpu/external_texture_manager.h b/libcef/browser/gpu/external_texture_manager.h
new file mode 100644
index 00000000..02a1cfde
--- /dev/null
+++ b/libcef/browser/gpu/external_texture_manager.h
@@ -0,0 +1,46 @@
+// Copyright 2018 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_GPU_EXTERNAL_TEXTURE_MANAGER_H_
+#define CEF_LIBCEF_BROWSER_GPU_EXTERNAL_TEXTURE_MANAGER_H_
+#pragma once
+
+#include <map>
+
+#include "gpu/command_buffer/service/texture_manager.h"
+#include "gpu/gpu_export.h"
+#include "ui/gl/gl_image.h"
+#include "ui/gl/gl_surface_egl.h"
+
+namespace gl {
+class GLImage;
+}
+
+namespace gpu {
+namespace gles2 {
+
+class GPU_GLES2_EXPORT ExternalTextureManager {
+ public:
+ ExternalTextureManager();
+ ~ExternalTextureManager();
+
+ void* CreateTexture(GLuint texture_id,
+ uint32_t width,
+ uint32_t height,
+ TextureManager* tex_man);
+
+ void LockTexture(void* handle);
+ void UnlockTexture(void* handle);
+
+ void DeleteTexture(void* handle, TextureManager* tex_man);
+
+ private:
+ using ExternalSurfaceMap = std::map<void*, scoped_refptr<gl::GLImage>>;
+ ExternalSurfaceMap surfaceMap_;
+};
+
+} // namespace gles2
+} // namespace gpu
+
+#endif // CEF_LIBCEF_BROWSER_GPU_EXTERNAL_TEXTURE_MANAGER_H_
diff --git a/libcef/browser/image_impl.cc b/libcef/browser/image_impl.cc
new file mode 100644
index 00000000..20a3cd0e
--- /dev/null
+++ b/libcef/browser/image_impl.cc
@@ -0,0 +1,427 @@
+// Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "libcef/browser/image_impl.h"
+
+#include <algorithm>
+
+#include "skia/ext/skia_utils_base.h"
+#include "ui/gfx/codec/jpeg_codec.h"
+#include "ui/gfx/codec/png_codec.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/image/image_png_rep.h"
+#include "ui/gfx/image/image_skia.h"
+#include "ui/gfx/image/image_skia_rep.h"
+
+namespace {
+
+SkColorType GetSkColorType(cef_color_type_t color_type) {
+ switch (color_type) {
+ case CEF_COLOR_TYPE_RGBA_8888:
+ return kRGBA_8888_SkColorType;
+ case CEF_COLOR_TYPE_BGRA_8888:
+ return kBGRA_8888_SkColorType;
+ default:
+ break;
+ }
+
+ NOTREACHED();
+ return kUnknown_SkColorType;
+}
+
+SkAlphaType GetSkAlphaType(cef_alpha_type_t alpha_type) {
+ switch (alpha_type) {
+ case CEF_ALPHA_TYPE_OPAQUE:
+ return kOpaque_SkAlphaType;
+ case CEF_ALPHA_TYPE_PREMULTIPLIED:
+ return kPremul_SkAlphaType;
+ case CEF_ALPHA_TYPE_POSTMULTIPLIED:
+ return kUnpremul_SkAlphaType;
+ default:
+ break;
+ }
+
+ NOTREACHED();
+ return kUnknown_SkAlphaType;
+}
+
+// Compress as PNG. Requires post-multiplied alpha.
+bool PNGMethod(bool with_transparency,
+ const SkBitmap& bitmap,
+ std::vector<unsigned char>* compressed) {
+ return gfx::PNGCodec::Encode(
+ reinterpret_cast<unsigned char*>(bitmap.getPixels()),
+ bitmap.colorType() == kBGRA_8888_SkColorType ? gfx::PNGCodec::FORMAT_BGRA
+ : gfx::PNGCodec::FORMAT_RGBA,
+ gfx::Size(bitmap.width(), bitmap.height()),
+ static_cast<int>(bitmap.rowBytes()),
+ bitmap.alphaType() == kOpaque_SkAlphaType || !with_transparency,
+ std::vector<gfx::PNGCodec::Comment>(), compressed);
+}
+
+// Compress as JPEG. This internally uses JCS_EXT_RGBX or JCS_EXT_BGRX which
+// causes the alpha channel to be ignored. Requires post-multiplied alpha.
+bool JPEGMethod(int quality,
+ const SkBitmap& bitmap,
+ std::vector<unsigned char>* compressed) {
+ return gfx::JPEGCodec::Encode(bitmap, quality, compressed);
+}
+
+} // namespace
+
+// static
+CefRefPtr<CefImage> CefImage::CreateImage() {
+ return new CefImageImpl();
+}
+
+CefImageImpl::CefImageImpl(const gfx::ImageSkia& image_skia)
+ : image_(image_skia) {}
+
+bool CefImageImpl::IsEmpty() {
+ base::AutoLock lock_scope(lock_);
+ return image_.IsEmpty();
+}
+
+bool CefImageImpl::IsSame(CefRefPtr<CefImage> that) {
+ CefImageImpl* that_impl = static_cast<CefImageImpl*>(that.get());
+ if (!that_impl) {
+ return false;
+ }
+
+ // Quick check for the same object.
+ if (this == that_impl) {
+ return true;
+ }
+
+ base::AutoLock lock_scope(lock_);
+ return image_.AsImageSkia().BackedBySameObjectAs(
+ that_impl->image_.AsImageSkia());
+}
+
+bool CefImageImpl::AddBitmap(float scale_factor,
+ int pixel_width,
+ int pixel_height,
+ cef_color_type_t color_type,
+ cef_alpha_type_t alpha_type,
+ const void* pixel_data,
+ size_t pixel_data_size) {
+ const SkColorType ct = GetSkColorType(color_type);
+ const SkAlphaType at = GetSkAlphaType(alpha_type);
+
+ // Make sure the client passed in the expected values.
+ if (ct != kBGRA_8888_SkColorType && ct != kRGBA_8888_SkColorType) {
+ return false;
+ }
+ if (pixel_data_size != pixel_width * pixel_height * 4U) {
+ return false;
+ }
+
+ SkBitmap bitmap;
+ if (!bitmap.tryAllocPixels(
+ SkImageInfo::Make(pixel_width, pixel_height, ct, at))) {
+ return false;
+ }
+
+ DCHECK_EQ(pixel_data_size, bitmap.computeByteSize());
+ memcpy(bitmap.getPixels(), pixel_data, pixel_data_size);
+
+ return AddBitmap(scale_factor, bitmap);
+}
+
+bool CefImageImpl::AddPNG(float scale_factor,
+ const void* png_data,
+ size_t png_data_size) {
+ SkBitmap bitmap;
+ if (!gfx::PNGCodec::Decode(static_cast<const unsigned char*>(png_data),
+ png_data_size, &bitmap)) {
+ return false;
+ }
+
+ return AddBitmap(scale_factor, bitmap);
+}
+
+bool CefImageImpl::AddJPEG(float scale_factor,
+ const void* jpeg_data,
+ size_t jpeg_data_size) {
+ std::unique_ptr<SkBitmap> bitmap(gfx::JPEGCodec::Decode(
+ static_cast<const unsigned char*>(jpeg_data), jpeg_data_size));
+ if (!bitmap.get()) {
+ return false;
+ }
+
+ return AddBitmap(scale_factor, *bitmap);
+}
+
+size_t CefImageImpl::GetWidth() {
+ base::AutoLock lock_scope(lock_);
+ return image_.Width();
+}
+
+size_t CefImageImpl::GetHeight() {
+ base::AutoLock lock_scope(lock_);
+ return image_.Height();
+}
+
+bool CefImageImpl::HasRepresentation(float scale_factor) {
+ base::AutoLock lock_scope(lock_);
+ return image_.AsImageSkia().HasRepresentation(scale_factor);
+}
+
+bool CefImageImpl::RemoveRepresentation(float scale_factor) {
+ base::AutoLock lock_scope(lock_);
+ gfx::ImageSkia image_skia = image_.AsImageSkia();
+ if (image_skia.HasRepresentation(scale_factor)) {
+ image_skia.RemoveRepresentation(scale_factor);
+ return true;
+ }
+ return false;
+}
+
+bool CefImageImpl::GetRepresentationInfo(float scale_factor,
+ float& actual_scale_factor,
+ int& pixel_width,
+ int& pixel_height) {
+ base::AutoLock lock_scope(lock_);
+ gfx::ImageSkia image_skia = image_.AsImageSkia();
+ if (image_skia.isNull()) {
+ return false;
+ }
+
+ const gfx::ImageSkiaRep& rep = image_skia.GetRepresentation(scale_factor);
+ if (rep.is_null()) {
+ return false;
+ }
+
+ actual_scale_factor = rep.scale();
+ pixel_width = rep.GetBitmap().width();
+ pixel_height = rep.GetBitmap().height();
+ return true;
+}
+
+CefRefPtr<CefBinaryValue> CefImageImpl::GetAsBitmap(float scale_factor,
+ cef_color_type_t color_type,
+ cef_alpha_type_t alpha_type,
+ int& pixel_width,
+ int& pixel_height) {
+ const SkColorType desired_ct = GetSkColorType(color_type);
+ const SkAlphaType desired_at = GetSkAlphaType(alpha_type);
+
+ base::AutoLock lock_scope(lock_);
+ const SkBitmap* bitmap = GetBitmap(scale_factor);
+ if (!bitmap) {
+ return nullptr;
+ }
+
+ DCHECK(bitmap->readyToDraw());
+
+ pixel_width = bitmap->width();
+ pixel_height = bitmap->height();
+
+ if (bitmap->colorType() == desired_ct && bitmap->alphaType() == desired_at) {
+ // No conversion necessary.
+ return CefBinaryValue::Create(bitmap->getPixels(),
+ bitmap->computeByteSize());
+ } else {
+ SkBitmap desired_bitmap;
+ if (!ConvertBitmap(*bitmap, &desired_bitmap, desired_ct, desired_at)) {
+ return nullptr;
+ }
+ DCHECK(desired_bitmap.readyToDraw());
+ return CefBinaryValue::Create(desired_bitmap.getPixels(),
+ desired_bitmap.computeByteSize());
+ }
+}
+
+CefRefPtr<CefBinaryValue> CefImageImpl::GetAsPNG(float scale_factor,
+ bool with_transparency,
+ int& pixel_width,
+ int& pixel_height) {
+ base::AutoLock lock_scope(lock_);
+ const SkBitmap* bitmap = GetBitmap(scale_factor);
+ if (!bitmap) {
+ return nullptr;
+ }
+
+ std::vector<unsigned char> compressed;
+ if (!WritePNG(*bitmap, &compressed, with_transparency)) {
+ return nullptr;
+ }
+
+ pixel_width = bitmap->width();
+ pixel_height = bitmap->height();
+
+ return CefBinaryValue::Create(&compressed.front(), compressed.size());
+}
+
+CefRefPtr<CefBinaryValue> CefImageImpl::GetAsJPEG(float scale_factor,
+ int quality,
+ int& pixel_width,
+ int& pixel_height) {
+ base::AutoLock lock_scope(lock_);
+ const SkBitmap* bitmap = GetBitmap(scale_factor);
+ if (!bitmap) {
+ return nullptr;
+ }
+
+ std::vector<unsigned char> compressed;
+ if (!WriteJPEG(*bitmap, &compressed, quality)) {
+ return nullptr;
+ }
+
+ pixel_width = bitmap->width();
+ pixel_height = bitmap->height();
+
+ return CefBinaryValue::Create(&compressed.front(), compressed.size());
+}
+
+void CefImageImpl::AddBitmaps(int32_t scale_1x_size,
+ const std::vector<SkBitmap>& bitmaps) {
+ if (scale_1x_size == 0) {
+ // Set the scale 1x size to the smallest bitmap pixel size.
+ int32_t min_size = std::numeric_limits<int32_t>::max();
+ for (const SkBitmap& bitmap : bitmaps) {
+ const int32_t size = std::max(bitmap.width(), bitmap.height());
+ if (size < min_size) {
+ min_size = size;
+ }
+ }
+ scale_1x_size = min_size;
+ }
+
+ for (const SkBitmap& bitmap : bitmaps) {
+ const int32_t size = std::max(bitmap.width(), bitmap.height());
+ const float scale_factor =
+ static_cast<float>(size) / static_cast<float>(scale_1x_size);
+ AddBitmap(scale_factor, bitmap);
+ }
+}
+
+gfx::ImageSkia CefImageImpl::GetForced1xScaleRepresentation(
+ float scale_factor) const {
+ base::AutoLock lock_scope(lock_);
+ if (scale_factor == 1.0f) {
+ // We can use the existing image without modification.
+ return image_.AsImageSkia();
+ }
+
+ const SkBitmap* bitmap = GetBitmap(scale_factor);
+ gfx::ImageSkia image_skia;
+ if (bitmap) {
+ image_skia.AddRepresentation(gfx::ImageSkiaRep(*bitmap, 1.0f));
+ }
+ return image_skia;
+}
+
+gfx::ImageSkia CefImageImpl::AsImageSkia() const {
+ base::AutoLock lock_scope(lock_);
+ return image_.AsImageSkia();
+}
+
+bool CefImageImpl::AddBitmap(float scale_factor, const SkBitmap& bitmap) {
+#if DCHECK_IS_ON()
+ DCHECK(bitmap.readyToDraw());
+#endif
+ DCHECK(bitmap.colorType() == kBGRA_8888_SkColorType ||
+ bitmap.colorType() == kRGBA_8888_SkColorType);
+
+ // Convert to N32 (e.g. native encoding) format if not already in that format.
+ // N32 is expected by the Views framework and this early conversion avoids
+ // CHECKs in ImageSkiaRep and eventual conversion to N32 at some later point
+ // in the compositing pipeline.
+ SkBitmap n32_bitmap;
+ if (!skia::SkBitmapToN32OpaqueOrPremul(bitmap, &n32_bitmap)) {
+ return false;
+ }
+
+ gfx::ImageSkiaRep skia_rep(n32_bitmap, scale_factor);
+ base::AutoLock lock_scope(lock_);
+ if (image_.IsEmpty()) {
+ image_ = gfx::Image(gfx::ImageSkia(skia_rep));
+ } else {
+ image_.AsImageSkia().AddRepresentation(skia_rep);
+ }
+ return true;
+}
+
+const SkBitmap* CefImageImpl::GetBitmap(float scale_factor) const {
+ lock_.AssertAcquired();
+ gfx::ImageSkia image_skia = image_.AsImageSkia();
+ if (image_skia.isNull()) {
+ return nullptr;
+ }
+
+ const gfx::ImageSkiaRep& rep = image_skia.GetRepresentation(scale_factor);
+ if (rep.is_null()) {
+ return nullptr;
+ }
+
+ return &rep.GetBitmap();
+}
+
+// static
+bool CefImageImpl::ConvertBitmap(const SkBitmap& src_bitmap,
+ SkBitmap* target_bitmap,
+ SkColorType target_ct,
+ SkAlphaType target_at) {
+ DCHECK(src_bitmap.readyToDraw());
+ DCHECK(src_bitmap.colorType() != target_ct ||
+ src_bitmap.alphaType() != target_at);
+ DCHECK(target_bitmap);
+
+ SkImageInfo target_info = SkImageInfo::Make(
+ src_bitmap.width(), src_bitmap.height(), target_ct, target_at);
+ if (!target_bitmap->tryAllocPixels(target_info)) {
+ return false;
+ }
+
+ if (!src_bitmap.readPixels(target_info, target_bitmap->getPixels(),
+ target_bitmap->rowBytes(), 0, 0)) {
+ return false;
+ }
+
+ DCHECK(target_bitmap->readyToDraw());
+ return true;
+}
+
+// static
+bool CefImageImpl::WriteCompressedFormat(const SkBitmap& bitmap,
+ std::vector<unsigned char>* compressed,
+ CompressionMethod method) {
+ const SkBitmap* bitmap_ptr = nullptr;
+ SkBitmap bitmap_postalpha;
+ if (bitmap.alphaType() == kPremul_SkAlphaType) {
+ // Compression methods require post-multiplied alpha values.
+ if (!ConvertBitmap(bitmap, &bitmap_postalpha, bitmap.colorType(),
+ kUnpremul_SkAlphaType)) {
+ return false;
+ }
+ bitmap_ptr = &bitmap_postalpha;
+ } else {
+ bitmap_ptr = &bitmap;
+ }
+
+ DCHECK(bitmap_ptr->readyToDraw());
+ DCHECK(bitmap_ptr->colorType() == kBGRA_8888_SkColorType ||
+ bitmap_ptr->colorType() == kRGBA_8888_SkColorType);
+ DCHECK(bitmap_ptr->alphaType() == kOpaque_SkAlphaType ||
+ bitmap_ptr->alphaType() == kUnpremul_SkAlphaType);
+
+ return std::move(method).Run(*bitmap_ptr, compressed);
+}
+
+// static
+bool CefImageImpl::WritePNG(const SkBitmap& bitmap,
+ std::vector<unsigned char>* compressed,
+ bool with_transparency) {
+ return WriteCompressedFormat(bitmap, compressed,
+ base::BindOnce(PNGMethod, with_transparency));
+}
+
+// static
+bool CefImageImpl::WriteJPEG(const SkBitmap& bitmap,
+ std::vector<unsigned char>* compressed,
+ int quality) {
+ return WriteCompressedFormat(bitmap, compressed,
+ base::BindOnce(JPEGMethod, quality));
+}
diff --git a/libcef/browser/image_impl.h b/libcef/browser/image_impl.h
new file mode 100644
index 00000000..36d75f4e
--- /dev/null
+++ b/libcef/browser/image_impl.h
@@ -0,0 +1,129 @@
+// Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_IMAGE_IMPL_H_
+#define CEF_LIBCEF_BROWSER_IMAGE_IMPL_H_
+#pragma once
+
+#include "include/cef_image.h"
+#include "libcef/browser/thread_util.h"
+
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/gfx/image/image.h"
+
+class CefImageImpl : public CefImage {
+ public:
+ // Creates an empty image with no representations.
+ CefImageImpl() = default;
+
+ // Creates a new image by copying the ImageSkia for use as the default
+ // representation.
+ explicit CefImageImpl(const gfx::ImageSkia& image_skia);
+
+ CefImageImpl(const CefImageImpl&) = delete;
+ CefImageImpl& operator=(const CefImageImpl&) = delete;
+
+ // Deletes the image and, if the only owner of the storage, all of its cached
+ // representations.
+ ~CefImageImpl() override = default;
+
+ // CefImage methods:
+ bool IsEmpty() override;
+ bool IsSame(CefRefPtr<CefImage> that) override;
+ bool AddBitmap(float scale_factor,
+ int pixel_width,
+ int pixel_height,
+ cef_color_type_t color_type,
+ cef_alpha_type_t alpha_type,
+ const void* pixel_data,
+ size_t pixel_data_size) override;
+ bool AddPNG(float scale_factor,
+ const void* png_data,
+ size_t png_data_size) override;
+ bool AddJPEG(float scale_factor,
+ const void* jpeg_data,
+ size_t jpeg_data_size) override;
+ size_t GetWidth() override;
+ size_t GetHeight() override;
+ bool HasRepresentation(float scale_factor) override;
+ bool RemoveRepresentation(float scale_factor) override;
+ bool GetRepresentationInfo(float scale_factor,
+ float& actual_scale_factor,
+ int& pixel_width,
+ int& pixel_height) override;
+ CefRefPtr<CefBinaryValue> GetAsBitmap(float scale_factor,
+ cef_color_type_t color_type,
+ cef_alpha_type_t alpha_type,
+ int& pixel_width,
+ int& pixel_height) override;
+ CefRefPtr<CefBinaryValue> GetAsPNG(float scale_factor,
+ bool with_transparency,
+ int& pixel_width,
+ int& pixel_height) override;
+ CefRefPtr<CefBinaryValue> GetAsJPEG(float scale_factor,
+ int quality,
+ int& pixel_width,
+ int& pixel_height) override;
+
+ // Add |bitmaps| which should be the same image at different scale factors.
+ // |scale_1x_size| is the size in pixels of the 1x factor image. If
+ // |scale_1x_size| is 0 the smallest image size in pixels will be used as the
+ // 1x factor size.
+ void AddBitmaps(int32_t scale_1x_size, const std::vector<SkBitmap>& bitmaps);
+
+ // Return a representation of this Image that contains only the bitmap nearest
+ // |scale_factor| as the 1x scale representation. Conceptually this is an
+ // incorrect representation but is necessary to work around bugs in the views
+ // architecture.
+ // TODO(cef): Remove once https://crbug.com/597732 is resolved.
+ gfx::ImageSkia GetForced1xScaleRepresentation(float scale_factor) const;
+
+ // Returns the skia representation of this Image.
+ gfx::ImageSkia AsImageSkia() const;
+
+ private:
+ // Add a bitmap.
+ bool AddBitmap(float scale_factor, const SkBitmap& bitmap);
+
+ // Returns the bitmap that most closely matches |scale_factor| or nullptr if
+ // one doesn't exist.
+ const SkBitmap* GetBitmap(float scale_factor) const;
+
+ // Convert |src_bitmap| to |target_bitmap| with |target_ct| and |target_at|.
+ static bool ConvertBitmap(const SkBitmap& src_bitmap,
+ SkBitmap* target_bitmap,
+ SkColorType target_ct,
+ SkAlphaType target_at);
+
+ // The |bitmap| argument will be RGBA or BGRA and either opaque or transparent
+ // with post-multiplied alpha. Writes the compressed output into |compressed|.
+ using CompressionMethod =
+ base::OnceCallback<bool(const SkBitmap& /*bitmap*/,
+ std::vector<unsigned char>* /*compressed*/)>;
+
+ // Write |bitmap| into |compressed| using |method|.
+ static bool WriteCompressedFormat(const SkBitmap& bitmap,
+ std::vector<unsigned char>* compressed,
+ CompressionMethod method);
+
+ // Write |bitmap| into |compressed| using PNG encoding.
+ static bool WritePNG(const SkBitmap& bitmap,
+ std::vector<unsigned char>* compressed,
+ bool with_transparency);
+
+ // Write |bitmap| into |compressed| using JPEG encoding. The alpha channel
+ // will be ignored.
+ static bool WriteJPEG(const SkBitmap& bitmap,
+ std::vector<unsigned char>* compressed,
+ int quality);
+
+ mutable base::Lock lock_;
+
+ // Access to |image_| must be protected by |lock_|.
+ gfx::Image image_;
+
+ IMPLEMENT_REFCOUNTING_DELETE_ON_UIT(CefImageImpl);
+};
+
+#endif // CEF_LIBCEF_BROWSER_IMAGE_IMPL_H_
diff --git a/libcef/browser/iothread_state.cc b/libcef/browser/iothread_state.cc
new file mode 100644
index 00000000..4b4d3b16
--- /dev/null
+++ b/libcef/browser/iothread_state.cc
@@ -0,0 +1,129 @@
+// Copyright (c) 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/iothread_state.h"
+
+#include "libcef/browser/net/scheme_handler.h"
+#include "libcef/browser/thread_util.h"
+#include "libcef/common/net/scheme_registration.h"
+
+#include "base/i18n/case_conversion.h"
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "content/browser/resource_context_impl.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/global_routing_id.h"
+
+CefIOThreadState::CefIOThreadState() {
+ // Using base::Unretained() is safe because both this callback and possible
+ // deletion of |this| will execute on the IO thread, and this callback will
+ // be executed first.
+ CEF_POST_TASK(CEF_IOT, base::BindOnce(&CefIOThreadState::InitOnIOThread,
+ base::Unretained(this)));
+}
+
+CefIOThreadState::~CefIOThreadState() {
+ CEF_REQUIRE_IOT();
+}
+
+void CefIOThreadState::AddHandler(
+ const content::GlobalRenderFrameHostId& global_id,
+ CefRefPtr<CefRequestContextHandler> handler) {
+ CEF_REQUIRE_IOT();
+ handler_map_.AddHandler(global_id, handler);
+}
+
+void CefIOThreadState::RemoveHandler(
+ const content::GlobalRenderFrameHostId& global_id) {
+ CEF_REQUIRE_IOT();
+ handler_map_.RemoveHandler(global_id);
+}
+
+CefRefPtr<CefRequestContextHandler> CefIOThreadState::GetHandler(
+ const content::GlobalRenderFrameHostId& global_id,
+ bool require_frame_match) const {
+ CEF_REQUIRE_IOT();
+ return handler_map_.GetHandler(global_id, require_frame_match);
+}
+
+void CefIOThreadState::RegisterSchemeHandlerFactory(
+ const std::string& scheme_name,
+ const std::string& domain_name,
+ CefRefPtr<CefSchemeHandlerFactory> factory) {
+ CEF_REQUIRE_IOT();
+
+ const std::string& scheme_lower = base::ToLowerASCII(scheme_name);
+ std::string domain_lower;
+
+ // Hostname is only supported for standard schemes.
+ if (scheme::IsStandardScheme(scheme_lower)) {
+ // Hostname might contain Unicode characters.
+ domain_lower =
+ base::UTF16ToUTF8(base::i18n::ToLower(base::UTF8ToUTF16(domain_name)));
+ }
+
+ const auto key = std::make_pair(scheme_lower, domain_lower);
+
+ if (factory) {
+ // Add or replace the factory.
+ scheme_handler_factory_map_[key] = factory;
+ } else {
+ // Remove the existing factory, if any.
+ auto it = scheme_handler_factory_map_.find(key);
+ if (it != scheme_handler_factory_map_.end()) {
+ scheme_handler_factory_map_.erase(it);
+ }
+ }
+}
+
+void CefIOThreadState::ClearSchemeHandlerFactories() {
+ CEF_REQUIRE_IOT();
+
+ scheme_handler_factory_map_.clear();
+
+ // Restore the default internal handlers.
+ scheme::RegisterInternalHandlers(this);
+}
+
+CefRefPtr<CefSchemeHandlerFactory> CefIOThreadState::GetSchemeHandlerFactory(
+ const GURL& url) {
+ CEF_REQUIRE_IOT();
+
+ if (scheme_handler_factory_map_.empty()) {
+ return nullptr;
+ }
+
+ const std::string& scheme_lower = url.scheme();
+ const std::string& domain_lower =
+ url.IsStandard() ? url.host() : std::string();
+
+ if (!domain_lower.empty()) {
+ // Sanity check.
+ DCHECK(scheme::IsStandardScheme(scheme_lower)) << scheme_lower;
+
+ // Try for a match with hostname first.
+ const auto it = scheme_handler_factory_map_.find(
+ std::make_pair(scheme_lower, domain_lower));
+ if (it != scheme_handler_factory_map_.end()) {
+ return it->second;
+ }
+ }
+
+ // Try for a match with no specified hostname.
+ const auto it = scheme_handler_factory_map_.find(
+ std::make_pair(scheme_lower, std::string()));
+ if (it != scheme_handler_factory_map_.end()) {
+ return it->second;
+ }
+
+ return nullptr;
+}
+
+void CefIOThreadState::InitOnIOThread() {
+ CEF_REQUIRE_IOT();
+
+ // Add the default internal handlers.
+ scheme::RegisterInternalHandlers(this);
+}
diff --git a/libcef/browser/iothread_state.h b/libcef/browser/iothread_state.h
new file mode 100644
index 00000000..71457fd5
--- /dev/null
+++ b/libcef/browser/iothread_state.h
@@ -0,0 +1,68 @@
+// Copyright (c) 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_IOTHREAD_STATE_H_
+#define CEF_LIBCEF_BROWSER_IOTHREAD_STATE_H_
+#pragma once
+
+#include "include/cef_request_context.h"
+#include "include/cef_request_context_handler.h"
+#include "include/cef_scheme.h"
+
+#include "libcef/browser/request_context_handler_map.h"
+
+#include "content/public/browser/browser_thread.h"
+
+namespace content {
+struct GlobalRenderFrameHostId;
+}
+
+class GURL;
+
+// Stores state that will be accessed on the IO thread. Life span is controlled
+// by CefBrowserContext. Created on the UI thread but accessed and destroyed on
+// the IO thread. See browser_context.h for an object relationship diagram.
+class CefIOThreadState : public base::RefCountedThreadSafe<
+ CefIOThreadState,
+ content::BrowserThread::DeleteOnIOThread> {
+ public:
+ CefIOThreadState();
+
+ CefIOThreadState(const CefIOThreadState&) = delete;
+ CefIOThreadState& operator=(const CefIOThreadState&) = delete;
+
+ // See comments in CefRequestContextHandlerMap.
+ void AddHandler(const content::GlobalRenderFrameHostId& global_id,
+ CefRefPtr<CefRequestContextHandler> handler);
+ void RemoveHandler(const content::GlobalRenderFrameHostId& global_id);
+ CefRefPtr<CefRequestContextHandler> GetHandler(
+ const content::GlobalRenderFrameHostId& global_id,
+ bool require_frame_match) const;
+
+ // Manage scheme handler factories associated with this context.
+ void RegisterSchemeHandlerFactory(const std::string& scheme_name,
+ const std::string& domain_name,
+ CefRefPtr<CefSchemeHandlerFactory> factory);
+ void ClearSchemeHandlerFactories();
+ CefRefPtr<CefSchemeHandlerFactory> GetSchemeHandlerFactory(const GURL& url);
+
+ private:
+ friend struct content::BrowserThread::DeleteOnThread<
+ content::BrowserThread::IO>;
+ friend class base::DeleteHelper<CefIOThreadState>;
+
+ ~CefIOThreadState();
+
+ void InitOnIOThread();
+
+ // Map IDs to CefRequestContextHandler objects.
+ CefRequestContextHandlerMap handler_map_;
+
+ // Map (scheme, domain) to factories.
+ using SchemeHandlerFactoryMap = std::map<std::pair<std::string, std::string>,
+ CefRefPtr<CefSchemeHandlerFactory>>;
+ SchemeHandlerFactoryMap scheme_handler_factory_map_;
+};
+
+#endif // CEF_LIBCEF_BROWSER_IOTHREAD_STATE_H_
diff --git a/libcef/browser/javascript_dialog_manager.cc b/libcef/browser/javascript_dialog_manager.cc
new file mode 100644
index 00000000..1debbf12
--- /dev/null
+++ b/libcef/browser/javascript_dialog_manager.cc
@@ -0,0 +1,311 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors.
+// Portions copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/javascript_dialog_manager.h"
+
+#include <utility>
+
+#include "libcef/browser/browser_host_base.h"
+#include "libcef/browser/thread_util.h"
+
+#include "base/functional/bind.h"
+#include "base/functional/callback_helpers.h"
+#include "base/logging.h"
+#include "components/javascript_dialogs/tab_modal_dialog_manager.h"
+
+namespace {
+
+class CefJSDialogCallbackImpl : public CefJSDialogCallback {
+ public:
+ using CallbackType = content::JavaScriptDialogManager::DialogClosedCallback;
+
+ CefJSDialogCallbackImpl(CallbackType callback)
+ : callback_(std::move(callback)) {}
+ ~CefJSDialogCallbackImpl() override {
+ if (!callback_.is_null()) {
+ // The callback is still pending. Cancel it now.
+ if (CEF_CURRENTLY_ON_UIT()) {
+ CancelNow(std::move(callback_));
+ } else {
+ CEF_POST_TASK(CEF_UIT,
+ base::BindOnce(&CefJSDialogCallbackImpl::CancelNow,
+ std::move(callback_)));
+ }
+ }
+ }
+
+ void Continue(bool success, const CefString& user_input) override {
+ if (CEF_CURRENTLY_ON_UIT()) {
+ if (!callback_.is_null()) {
+ std::move(callback_).Run(success, user_input);
+ }
+ } else {
+ CEF_POST_TASK(CEF_UIT, base::BindOnce(&CefJSDialogCallbackImpl::Continue,
+ this, success, user_input));
+ }
+ }
+
+ [[nodiscard]] CallbackType Disconnect() { return std::move(callback_); }
+
+ private:
+ static void CancelNow(CallbackType callback) {
+ CEF_REQUIRE_UIT();
+ std::move(callback).Run(false, std::u16string());
+ }
+
+ CallbackType callback_;
+
+ IMPLEMENT_REFCOUNTING(CefJSDialogCallbackImpl);
+};
+
+javascript_dialogs::TabModalDialogManager* GetTabModalDialogManager(
+ content::WebContents* web_contents) {
+ return javascript_dialogs::TabModalDialogManager::FromWebContents(
+ web_contents);
+}
+
+} // namespace
+
+CefJavaScriptDialogManager::CefJavaScriptDialogManager(
+ CefBrowserHostBase* browser)
+ : browser_(browser), weak_ptr_factory_(this) {}
+
+CefJavaScriptDialogManager::~CefJavaScriptDialogManager() {}
+
+void CefJavaScriptDialogManager::Destroy() {
+ if (handler_) {
+ CancelDialogs(nullptr, false);
+ }
+ if (runner_) {
+ runner_.reset();
+ }
+}
+
+void CefJavaScriptDialogManager::RunJavaScriptDialog(
+ content::WebContents* web_contents,
+ content::RenderFrameHost* render_frame_host,
+ content::JavaScriptDialogType message_type,
+ const std::u16string& message_text,
+ const std::u16string& default_prompt_text,
+ DialogClosedCallback callback,
+ bool* did_suppress_message) {
+ *did_suppress_message = false;
+
+ const GURL& origin_url = render_frame_host->GetLastCommittedURL();
+
+ // Always call DialogClosed().
+ callback =
+ base::BindOnce(&CefJavaScriptDialogManager::DialogClosed,
+ weak_ptr_factory_.GetWeakPtr(), std::move(callback));
+
+ if (auto client = browser_->GetClient()) {
+ if (auto handler = client->GetJSDialogHandler()) {
+ // If the dialog is handled this will be cleared in DialogClosed().
+ handler_ = handler;
+
+ CefRefPtr<CefJSDialogCallbackImpl> callbackPtr(
+ new CefJSDialogCallbackImpl(std::move(callback)));
+
+ // Execute the user callback.
+ bool handled = handler->OnJSDialog(
+ browser_, origin_url.spec(),
+ static_cast<cef_jsdialog_type_t>(message_type), message_text,
+ default_prompt_text, callbackPtr.get(), *did_suppress_message);
+ if (handled) {
+ // Invalid combination of values. Crash sooner rather than later.
+ CHECK(!*did_suppress_message);
+ return;
+ }
+
+ // |callback| may be null if the user executed it despite returning false.
+ callback = callbackPtr->Disconnect();
+ if (callback.is_null()) {
+ LOG(WARNING)
+ << "OnJSDialog should return true when executing the callback";
+ return;
+ }
+
+ if (*did_suppress_message) {
+ // Call OnResetDialogState but don't execute |callback|.
+ CancelDialogs(web_contents, /*reset_state=*/true);
+ return;
+ }
+
+ handler_ = nullptr;
+ }
+ }
+
+ DCHECK(!handler_);
+
+ if (InitializeRunner()) {
+ runner_->Run(browser_, message_type, origin_url, message_text,
+ default_prompt_text, std::move(callback));
+ return;
+ }
+
+ if (!CanUseChromeDialogs()) {
+ // Dismiss the dialog.
+ std::move(callback).Run(false, std::u16string());
+ return;
+ }
+
+ auto manager = GetTabModalDialogManager(web_contents);
+ manager->RunJavaScriptDialog(web_contents, render_frame_host, message_type,
+ message_text, default_prompt_text,
+ std::move(callback), did_suppress_message);
+}
+
+void CefJavaScriptDialogManager::RunBeforeUnloadDialog(
+ content::WebContents* web_contents,
+ content::RenderFrameHost* render_frame_host,
+ bool is_reload,
+ DialogClosedCallback callback) {
+ if (browser_->WillBeDestroyed()) {
+ // Currently destroying the browser. Accept the unload without showing
+ // the prompt.
+ std::move(callback).Run(true, std::u16string());
+ return;
+ }
+
+ const std::u16string& message_text = u"Is it OK to leave/reload this page?";
+
+ // Always call DialogClosed().
+ callback =
+ base::BindOnce(&CefJavaScriptDialogManager::DialogClosed,
+ weak_ptr_factory_.GetWeakPtr(), std::move(callback));
+
+ if (auto client = browser_->GetClient()) {
+ if (auto handler = client->GetJSDialogHandler()) {
+ // If the dialog is handled this will be cleared in DialogClosed().
+ handler_ = handler;
+
+ CefRefPtr<CefJSDialogCallbackImpl> callbackPtr(
+ new CefJSDialogCallbackImpl(std::move(callback)));
+
+ // Execute the user callback.
+ bool handled = handler->OnBeforeUnloadDialog(
+ browser_, message_text, is_reload, callbackPtr.get());
+ if (handled) {
+ return;
+ }
+
+ // |callback| may be null if the user executed it despite returning false.
+ callback = callbackPtr->Disconnect();
+ if (callback.is_null()) {
+ LOG(WARNING) << "OnBeforeUnloadDialog should return true when "
+ "executing the callback";
+ return;
+ }
+
+ handler_ = nullptr;
+ }
+ }
+
+ DCHECK(!handler_);
+
+ if (InitializeRunner()) {
+ runner_->Run(browser_, content::JAVASCRIPT_DIALOG_TYPE_CONFIRM,
+ /*origin_url=*/GURL(), message_text,
+ /*default_prompt_text=*/std::u16string(), std::move(callback));
+ return;
+ }
+
+ if (!CanUseChromeDialogs()) {
+ // Accept the unload without showing the prompt.
+ std::move(callback).Run(true, std::u16string());
+ return;
+ }
+
+ auto manager = GetTabModalDialogManager(web_contents);
+ manager->RunBeforeUnloadDialog(web_contents, render_frame_host, is_reload,
+ std::move(callback));
+}
+
+bool CefJavaScriptDialogManager::HandleJavaScriptDialog(
+ content::WebContents* web_contents,
+ bool accept,
+ const std::u16string* prompt_override) {
+ if (handler_) {
+ DialogClosed(base::NullCallback(), accept,
+ prompt_override ? *prompt_override : std::u16string());
+ return true;
+ }
+
+ if (runner_) {
+ runner_->Handle(accept, prompt_override);
+ return true;
+ }
+
+ if (!CanUseChromeDialogs()) {
+ return true;
+ }
+
+ auto manager = GetTabModalDialogManager(web_contents);
+ return manager->HandleJavaScriptDialog(web_contents, accept, prompt_override);
+}
+
+void CefJavaScriptDialogManager::CancelDialogs(
+ content::WebContents* web_contents,
+ bool reset_state) {
+ if (handler_) {
+ if (reset_state) {
+ handler_->OnResetDialogState(browser_);
+ }
+ handler_ = nullptr;
+ return;
+ }
+
+ if (runner_) {
+ runner_->Cancel();
+ return;
+ }
+
+ // Null when called from DialogClosed() or Destroy().
+ if (!web_contents) {
+ return;
+ }
+
+ if (!CanUseChromeDialogs()) {
+ return;
+ }
+
+ auto manager = GetTabModalDialogManager(web_contents);
+ manager->CancelDialogs(web_contents, reset_state);
+}
+
+void CefJavaScriptDialogManager::DialogClosed(
+ DialogClosedCallback callback,
+ bool success,
+ const std::u16string& user_input) {
+ if (handler_) {
+ handler_->OnDialogClosed(browser_);
+ // Call OnResetDialogState.
+ CancelDialogs(/*web_contents=*/nullptr, /*reset_state=*/true);
+ }
+
+ // Null when called from HandleJavaScriptDialog().
+ if (!callback.is_null()) {
+ std::move(callback).Run(success, user_input);
+ }
+}
+
+bool CefJavaScriptDialogManager::InitializeRunner() {
+ if (!runner_initialized_) {
+ runner_ = browser_->platform_delegate()->CreateJavaScriptDialogRunner();
+ runner_initialized_ = true;
+ }
+ return !!runner_.get();
+}
+
+bool CefJavaScriptDialogManager::CanUseChromeDialogs() const {
+ if (browser_->IsWindowless() &&
+ browser_->GetWindowHandle() == kNullWindowHandle) {
+ LOG(ERROR) << "Default dialog implementation requires a parent window "
+ "handle; canceling the JS dialog";
+ return false;
+ }
+
+ return true;
+} \ No newline at end of file
diff --git a/libcef/browser/javascript_dialog_manager.h b/libcef/browser/javascript_dialog_manager.h
new file mode 100644
index 00000000..241b4c1b
--- /dev/null
+++ b/libcef/browser/javascript_dialog_manager.h
@@ -0,0 +1,75 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors.
+// Portions copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_JAVASCRIPT_DIALOG_MANAGER_H_
+#define CEF_LIBCEF_BROWSER_JAVASCRIPT_DIALOG_MANAGER_H_
+#pragma once
+
+#include <memory>
+#include <string>
+
+#include "include/cef_jsdialog_handler.h"
+#include "libcef/browser/javascript_dialog_runner.h"
+
+#include "base/memory/weak_ptr.h"
+#include "content/public/browser/javascript_dialog_manager.h"
+
+class CefBrowserHostBase;
+
+class CefJavaScriptDialogManager : public content::JavaScriptDialogManager {
+ public:
+ // |runner| may be NULL if the platform doesn't implement dialogs.
+ explicit CefJavaScriptDialogManager(CefBrowserHostBase* browser);
+
+ CefJavaScriptDialogManager(const CefJavaScriptDialogManager&) = delete;
+ CefJavaScriptDialogManager& operator=(const CefJavaScriptDialogManager&) =
+ delete;
+
+ ~CefJavaScriptDialogManager() override;
+
+ // Delete the runner to free any platform constructs.
+ void Destroy();
+
+ // JavaScriptDialogManager methods.
+ void RunJavaScriptDialog(content::WebContents* web_contents,
+ content::RenderFrameHost* render_frame_host,
+ content::JavaScriptDialogType message_type,
+ const std::u16string& message_text,
+ const std::u16string& default_prompt_text,
+ DialogClosedCallback callback,
+ bool* did_suppress_message) override;
+ void RunBeforeUnloadDialog(content::WebContents* web_contents,
+ content::RenderFrameHost* render_frame_host,
+ bool is_reload,
+ DialogClosedCallback callback) override;
+ bool HandleJavaScriptDialog(content::WebContents* web_contents,
+ bool accept,
+ const std::u16string* prompt_override) override;
+ void CancelDialogs(content::WebContents* web_contents,
+ bool reset_state) override;
+
+ private:
+ // Method executed by the callback passed to CefJavaScriptDialogRunner::Run.
+ void DialogClosed(DialogClosedCallback callback,
+ bool success,
+ const std::u16string& user_input);
+
+ bool InitializeRunner();
+
+ bool CanUseChromeDialogs() const;
+
+ // CefBrowserHostBase pointer is guaranteed to outlive this object.
+ CefBrowserHostBase* const browser_;
+
+ CefRefPtr<CefJSDialogHandler> handler_;
+
+ std::unique_ptr<CefJavaScriptDialogRunner> runner_;
+ bool runner_initialized_ = false;
+
+ // Must be the last member.
+ base::WeakPtrFactory<CefJavaScriptDialogManager> weak_ptr_factory_;
+};
+
+#endif // CEF_LIBCEF_BROWSER_JAVASCRIPT_DIALOG_MANAGER_H_
diff --git a/libcef/browser/javascript_dialog_runner.h b/libcef/browser/javascript_dialog_runner.h
new file mode 100644
index 00000000..bbceece2
--- /dev/null
+++ b/libcef/browser/javascript_dialog_runner.h
@@ -0,0 +1,46 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors.
+// Portions copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_JAVASCRIPT_DIALOG_RUNNER_H_
+#define CEF_LIBCEF_BROWSER_JAVASCRIPT_DIALOG_RUNNER_H_
+#pragma once
+
+#include "content/public/browser/javascript_dialog_manager.h"
+#include "content/public/common/javascript_dialog_type.h"
+
+class CefBrowserHostBase;
+
+class CefJavaScriptDialogRunner {
+ public:
+ CefJavaScriptDialogRunner(const CefJavaScriptDialogRunner&) = delete;
+ CefJavaScriptDialogRunner& operator=(const CefJavaScriptDialogRunner&) =
+ delete;
+
+ using DialogClosedCallback =
+ content::JavaScriptDialogManager::DialogClosedCallback;
+
+ // Run the dialog. Execute |callback| on completion.
+ virtual void Run(CefBrowserHostBase* browser,
+ content::JavaScriptDialogType message_type,
+ const GURL& origin_url,
+ const std::u16string& message_text,
+ const std::u16string& default_prompt_text,
+ DialogClosedCallback callback) = 0;
+
+ // Dismiss the dialog with the specified results.
+ virtual void Handle(bool accept, const std::u16string* prompt_override) = 0;
+
+ // Cancel a dialog mid-flight.
+ virtual void Cancel() = 0;
+
+ protected:
+ // Allow deletion via std::unique_ptr only.
+ friend std::default_delete<CefJavaScriptDialogRunner>;
+
+ CefJavaScriptDialogRunner() = default;
+ virtual ~CefJavaScriptDialogRunner() = default;
+};
+
+#endif // CEF_LIBCEF_BROWSER_JAVASCRIPT_DIALOG_RUNNER_H_
diff --git a/libcef/browser/main_runner.cc b/libcef/browser/main_runner.cc
new file mode 100644
index 00000000..82916923
--- /dev/null
+++ b/libcef/browser/main_runner.cc
@@ -0,0 +1,541 @@
+// Copyright 2020 The Chromium Embedded Framework Authors.
+// Portions copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/main_runner.h"
+
+#include "libcef/browser/browser_message_loop.h"
+#include "libcef/browser/thread_util.h"
+#include "libcef/common/alloy/alloy_main_runner_delegate.h"
+#include "libcef/common/cef_switches.h"
+#include "libcef/common/chrome/chrome_main_runner_delegate.h"
+#include "libcef/features/runtime.h"
+
+#include "base/at_exit.h"
+#include "base/base_switches.h"
+#include "base/command_line.h"
+#include "base/debug/debugger.h"
+#include "base/run_loop.h"
+#include "base/sequence_checker.h"
+#include "base/synchronization/lock.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
+#include "components/crash/core/app/crash_switches.h"
+#include "content/app/content_main_runner_impl.h"
+#include "content/browser/scheduler/browser_task_executor.h"
+#include "content/public/app/content_main.h"
+#include "content/public/app/content_main_runner.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/common/content_switches.h"
+#include "third_party/crashpad/crashpad/handler/handler_main.h"
+
+#if BUILDFLAG(IS_WIN)
+#include <Objbase.h>
+#include <windows.h>
+#include "content/public/app/sandbox_helper_win.h"
+#include "sandbox/win/src/sandbox_types.h"
+#endif
+
+namespace {
+
+enum class RuntimeType {
+ UNINITIALIZED,
+ ALLOY,
+ CHROME,
+};
+RuntimeType g_runtime_type = RuntimeType::UNINITIALIZED;
+
+std::unique_ptr<CefMainRunnerDelegate> MakeDelegate(
+ RuntimeType type,
+ CefMainRunnerHandler* runner,
+ CefSettings* settings,
+ CefRefPtr<CefApp> application) {
+ if (type == RuntimeType::ALLOY) {
+ g_runtime_type = RuntimeType::ALLOY;
+ return std::make_unique<AlloyMainRunnerDelegate>(runner, settings,
+ application);
+ } else {
+ g_runtime_type = RuntimeType::CHROME;
+ return std::make_unique<ChromeMainRunnerDelegate>(runner, settings,
+ application);
+ }
+}
+
+// Based on components/crash/core/app/run_as_crashpad_handler_win.cc
+// Remove the "--type=crashpad-handler" command-line flag that will otherwise
+// confuse the crashpad handler.
+// Chrome uses an embedded crashpad handler on Windows only and imports this
+// function via the existing "run_as_crashpad_handler" target defined in
+// components/crash/core/app/BUILD.gn. CEF uses an embedded handler on all
+// platforms so we define the function here instead of using the existing
+// target (because we can't use that target on macOS).
+int RunAsCrashpadHandler(const base::CommandLine& command_line) {
+ base::CommandLine::StringVector argv = command_line.argv();
+ const base::CommandLine::StringType process_type =
+ FILE_PATH_LITERAL("--type=");
+ argv.erase(
+ std::remove_if(argv.begin(), argv.end(),
+ [&process_type](const base::CommandLine::StringType& str) {
+ return base::StartsWith(str, process_type,
+ base::CompareCase::SENSITIVE) ||
+ (!str.empty() && str[0] == L'/');
+ }),
+ argv.end());
+
+#if BUILDFLAG(IS_POSIX)
+ // HandlerMain on POSIX uses the system version of getopt_long which expects
+ // the first argument to be the program name.
+ argv.insert(argv.begin(), command_line.GetProgram().value());
+#endif
+
+ std::unique_ptr<char*[]> argv_as_utf8(new char*[argv.size() + 1]);
+ std::vector<std::string> storage;
+ storage.reserve(argv.size());
+ for (size_t i = 0; i < argv.size(); ++i) {
+#if BUILDFLAG(IS_WIN)
+ storage.push_back(base::WideToUTF8(argv[i]));
+#else
+ storage.push_back(argv[i]);
+#endif
+ argv_as_utf8[i] = &storage[i][0];
+ }
+ argv_as_utf8[argv.size()] = nullptr;
+ argv.clear();
+ return crashpad::HandlerMain(static_cast<int>(storage.size()),
+ argv_as_utf8.get(), nullptr);
+}
+
+} // namespace
+
+// Used to run the UI on a separate thread.
+class CefUIThread : public base::PlatformThread::Delegate {
+ public:
+ CefUIThread(CefMainRunner* runner, base::OnceClosure setup_callback)
+ : runner_(runner), setup_callback_(std::move(setup_callback)) {}
+ ~CefUIThread() override { Stop(); }
+
+ void Start() {
+ base::AutoLock lock(thread_lock_);
+ bool success = base::PlatformThread::CreateWithType(
+ 0, this, &thread_, base::ThreadType::kDefault);
+ if (!success) {
+ LOG(FATAL) << "failed to UI create thread";
+ }
+ }
+
+ void Stop() {
+ base::AutoLock lock(thread_lock_);
+
+ if (!stopping_) {
+ stopping_ = true;
+ CEF_POST_TASK(CEF_UIT, base::BindOnce(&CefMainRunner::QuitMessageLoop,
+ base::Unretained(runner_)));
+ }
+
+ // Can't join if the |thread_| is either already gone or is non-joinable.
+ if (thread_.is_null()) {
+ return;
+ }
+
+ base::PlatformThread::Join(thread_);
+ thread_ = base::PlatformThreadHandle();
+
+ stopping_ = false;
+ }
+
+ bool WaitUntilThreadStarted() const {
+ DCHECK(owning_sequence_checker_.CalledOnValidSequence());
+ start_event_.Wait();
+ return true;
+ }
+
+ void InitializeBrowserRunner(
+ content::MainFunctionParams main_function_params) {
+ // Use our own browser process runner.
+ browser_runner_ = content::BrowserMainRunner::Create();
+
+ // Initialize browser process state. Uses the current thread's message loop.
+ int exit_code =
+ browser_runner_->Initialize(std::move(main_function_params));
+ CHECK_EQ(exit_code, -1);
+ }
+
+ protected:
+ void ThreadMain() override {
+ base::PlatformThread::SetName("CefUIThread");
+
+#if BUILDFLAG(IS_WIN)
+ // Initializes the COM library on the current thread.
+ CoInitialize(nullptr);
+#endif
+
+ start_event_.Signal();
+
+ std::move(setup_callback_).Run();
+
+ runner_->RunMessageLoop();
+
+ browser_runner_->Shutdown();
+ browser_runner_.reset();
+
+ content::BrowserTaskExecutor::Shutdown();
+
+ // Run exit callbacks on the UI thread to avoid sequence check failures.
+ base::AtExitManager::ProcessCallbacksNow();
+
+#if BUILDFLAG(IS_WIN)
+ // Closes the COM library on the current thread. CoInitialize must
+ // be balanced by a corresponding call to CoUninitialize.
+ CoUninitialize();
+#endif
+ }
+
+ CefMainRunner* const runner_;
+ base::OnceClosure setup_callback_;
+
+ std::unique_ptr<content::BrowserMainRunner> browser_runner_;
+
+ bool stopping_ = false;
+
+ // The thread's handle.
+ base::PlatformThreadHandle thread_;
+ mutable base::Lock thread_lock_; // Protects |thread_|.
+
+ mutable base::WaitableEvent start_event_;
+
+ // This class is not thread-safe, use this to verify access from the owning
+ // sequence of the Thread.
+ base::SequenceChecker owning_sequence_checker_;
+};
+
+CefMainRunner::CefMainRunner(bool multi_threaded_message_loop,
+ bool external_message_pump)
+ : multi_threaded_message_loop_(multi_threaded_message_loop),
+ external_message_pump_(external_message_pump) {}
+
+CefMainRunner::~CefMainRunner() = default;
+
+bool CefMainRunner::Initialize(CefSettings* settings,
+ CefRefPtr<CefApp> application,
+ const CefMainArgs& args,
+ void* windows_sandbox_info,
+ bool* initialized,
+ base::OnceClosure context_initialized) {
+ DCHECK(!main_delegate_);
+ main_delegate_ = MakeDelegate(
+ settings->chrome_runtime ? RuntimeType::CHROME : RuntimeType::ALLOY, this,
+ settings, application);
+
+ const int exit_code =
+ ContentMainInitialize(args, windows_sandbox_info, &settings->no_sandbox);
+ if (exit_code >= 0) {
+ NOTREACHED() << "ContentMainInitialize failed";
+ return false;
+ }
+
+ if (!ContentMainRun(initialized, std::move(context_initialized))) {
+ NOTREACHED() << "ContentMainRun failed";
+ return false;
+ }
+
+ return true;
+}
+
+void CefMainRunner::Shutdown(base::OnceClosure shutdown_on_ui_thread,
+ base::OnceClosure finalize_shutdown) {
+ if (multi_threaded_message_loop_) {
+ // Events that will be used to signal when shutdown is complete. Start in
+ // non-signaled mode so that the event will block.
+ base::WaitableEvent uithread_shutdown_event(
+ base::WaitableEvent::ResetPolicy::AUTOMATIC,
+ base::WaitableEvent::InitialState::NOT_SIGNALED);
+
+ // Finish shutdown on the UI thread.
+ CEF_POST_TASK(
+ CEF_UIT,
+ base::BindOnce(&CefMainRunner::FinishShutdownOnUIThread,
+ base::Unretained(this), std::move(shutdown_on_ui_thread),
+ &uithread_shutdown_event));
+
+ /// Block until UI thread shutdown is complete.
+ uithread_shutdown_event.Wait();
+
+ FinalizeShutdown(std::move(finalize_shutdown));
+ } else {
+ // Finish shutdown on the current thread, which should be the UI thread.
+ FinishShutdownOnUIThread(std::move(shutdown_on_ui_thread), nullptr);
+
+ FinalizeShutdown(std::move(finalize_shutdown));
+ }
+}
+
+void CefMainRunner::RunMessageLoop() {
+ base::RunLoop run_loop;
+
+ DCHECK(quit_when_idle_callback_.is_null());
+ quit_when_idle_callback_ = run_loop.QuitWhenIdleClosure();
+
+ main_delegate_->BeforeMainMessageLoopRun(&run_loop);
+
+ // Blocks until QuitMessageLoop() is called.
+ run_loop.Run();
+}
+
+void CefMainRunner::QuitMessageLoop() {
+ if (!quit_when_idle_callback_.is_null()) {
+ if (main_delegate_->HandleMainMessageLoopQuit()) {
+ return;
+ }
+ std::move(quit_when_idle_callback_).Run();
+ }
+}
+
+// static
+int CefMainRunner::RunAsHelperProcess(const CefMainArgs& args,
+ CefRefPtr<CefApp> application,
+ void* windows_sandbox_info) {
+ base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
+#if BUILDFLAG(IS_WIN)
+ command_line.ParseFromString(::GetCommandLineW());
+#else
+ command_line.InitFromArgv(args.argc, args.argv);
+#endif
+
+ // Wait for the debugger as early in process initialization as possible.
+ if (command_line.HasSwitch(switches::kWaitForDebugger)) {
+ base::debug::WaitForDebugger(60, true);
+ }
+
+ // If no process type is specified then it represents the browser process and
+ // we do nothing.
+ const std::string& process_type =
+ command_line.GetSwitchValueASCII(switches::kProcessType);
+ if (process_type.empty()) {
+ return -1;
+ }
+
+ auto runtime_type = command_line.HasSwitch(switches::kEnableChromeRuntime)
+ ? RuntimeType::CHROME
+ : RuntimeType::ALLOY;
+ auto main_delegate = MakeDelegate(runtime_type, /*runner=*/nullptr,
+ /*settings=*/nullptr, application);
+ main_delegate->BeforeExecuteProcess(args);
+
+ int result;
+
+ if (process_type == crash_reporter::switches::kCrashpadHandler) {
+ result = RunAsCrashpadHandler(command_line);
+ main_delegate->AfterExecuteProcess();
+ return result;
+ }
+
+ // Execute the secondary process.
+ content::ContentMainParams main_params(
+ main_delegate->GetContentMainDelegate());
+#if BUILDFLAG(IS_WIN)
+ sandbox::SandboxInterfaceInfo sandbox_info = {nullptr};
+ if (windows_sandbox_info == nullptr) {
+ content::InitializeSandboxInfo(&sandbox_info);
+ windows_sandbox_info = &sandbox_info;
+ }
+
+ main_params.instance = args.instance;
+ main_params.sandbox_info =
+ static_cast<sandbox::SandboxInterfaceInfo*>(windows_sandbox_info);
+#else
+ main_params.argc = args.argc;
+ main_params.argv = const_cast<const char**>(args.argv);
+#endif
+ result = content::ContentMain(std::move(main_params));
+
+ main_delegate->AfterExecuteProcess();
+
+ return result;
+}
+
+int CefMainRunner::ContentMainInitialize(const CefMainArgs& args,
+ void* windows_sandbox_info,
+ int* no_sandbox) {
+ main_delegate_->BeforeMainThreadInitialize(args);
+
+ // Initialize the content runner.
+ main_runner_ = content::ContentMainRunner::Create();
+ content::ContentMainParams main_params(
+ main_delegate_->GetContentMainDelegate());
+
+#if BUILDFLAG(IS_WIN)
+ sandbox::SandboxInterfaceInfo sandbox_info = {nullptr};
+ if (windows_sandbox_info == nullptr) {
+ windows_sandbox_info = &sandbox_info;
+ *no_sandbox = true;
+ }
+
+ main_params.instance = args.instance;
+ main_params.sandbox_info =
+ static_cast<sandbox::SandboxInterfaceInfo*>(windows_sandbox_info);
+#else
+ main_params.argc = args.argc;
+ main_params.argv = const_cast<const char**>(args.argv);
+#endif
+
+ return content::ContentMainInitialize(std::move(main_params),
+ main_runner_.get());
+}
+
+bool CefMainRunner::ContentMainRun(bool* initialized,
+ base::OnceClosure context_initialized) {
+ main_delegate_->BeforeMainThreadRun();
+
+ if (multi_threaded_message_loop_) {
+ base::WaitableEvent uithread_startup_event(
+ base::WaitableEvent::ResetPolicy::AUTOMATIC,
+ base::WaitableEvent::InitialState::NOT_SIGNALED);
+
+ if (!CreateUIThread(base::BindOnce(
+ [](CefMainRunner* runner, base::WaitableEvent* event) {
+ runner->main_delegate_->BeforeUIThreadInitialize();
+ content::ContentMainRun(runner->main_runner_.get());
+ event->Signal();
+ },
+ base::Unretained(this),
+ base::Unretained(&uithread_startup_event)))) {
+ return false;
+ }
+
+ *initialized = true;
+
+ // We need to wait until content::ContentMainRun has finished.
+ uithread_startup_event.Wait();
+ } else {
+ *initialized = true;
+ main_delegate_->BeforeUIThreadInitialize();
+ content::ContentMainRun(main_runner_.get());
+ }
+
+ if (CEF_CURRENTLY_ON_UIT()) {
+ OnContextInitialized(std::move(context_initialized));
+ } else {
+ // Continue initialization on the UI thread.
+ CEF_POST_TASK(CEF_UIT, base::BindOnce(&CefMainRunner::OnContextInitialized,
+ base::Unretained(this),
+ std::move(context_initialized)));
+ }
+
+ return true;
+}
+
+void CefMainRunner::PreBrowserMain() {
+ if (external_message_pump_) {
+ InitExternalMessagePumpFactoryForUI();
+ }
+}
+
+int CefMainRunner::RunMainProcess(
+ content::MainFunctionParams main_function_params) {
+ if (!multi_threaded_message_loop_) {
+ // Use our own browser process runner.
+ browser_runner_ = content::BrowserMainRunner::Create();
+
+ // Initialize browser process state. Results in a call to
+ // AlloyBrowserMain::PreBrowserMain() which creates the UI message
+ // loop.
+ int exit_code =
+ browser_runner_->Initialize(std::move(main_function_params));
+ if (exit_code >= 0) {
+ return exit_code;
+ }
+ } else {
+ // Running on the separate UI thread.
+ DCHECK(ui_thread_);
+ ui_thread_->InitializeBrowserRunner(std::move(main_function_params));
+ }
+
+ return 0;
+}
+
+bool CefMainRunner::CreateUIThread(base::OnceClosure setup_callback) {
+ DCHECK(!ui_thread_);
+
+ ui_thread_.reset(new CefUIThread(this, std::move(setup_callback)));
+ ui_thread_->Start();
+ ui_thread_->WaitUntilThreadStarted();
+
+ if (external_message_pump_) {
+ InitExternalMessagePumpFactoryForUI();
+ }
+ return true;
+}
+
+void CefMainRunner::OnContextInitialized(
+ base::OnceClosure context_initialized) {
+ CEF_REQUIRE_UIT();
+
+ main_delegate_->AfterUIThreadInitialize();
+ std::move(context_initialized).Run();
+}
+
+void CefMainRunner::FinishShutdownOnUIThread(
+ base::OnceClosure shutdown_on_ui_thread,
+ base::WaitableEvent* uithread_shutdown_event) {
+ CEF_REQUIRE_UIT();
+
+ // Execute all pending tasks now before proceeding with shutdown. Otherwise,
+ // objects bound to tasks and released at the end of shutdown via
+ // BrowserTaskExecutor::Shutdown may attempt to access other objects that have
+ // already been destroyed (for example, if teardown results in a call to
+ // RenderProcessHostImpl::Cleanup).
+ content::BrowserTaskExecutor::RunAllPendingTasksOnThreadForTesting(
+ content::BrowserThread::UI);
+ content::BrowserTaskExecutor::RunAllPendingTasksOnThreadForTesting(
+ content::BrowserThread::IO);
+
+ static_cast<content::ContentMainRunnerImpl*>(main_runner_.get())
+ ->ShutdownOnUIThread();
+
+ std::move(shutdown_on_ui_thread).Run();
+ main_delegate_->AfterUIThreadShutdown();
+
+ if (uithread_shutdown_event) {
+ uithread_shutdown_event->Signal();
+ }
+}
+
+void CefMainRunner::FinalizeShutdown(base::OnceClosure finalize_shutdown) {
+ main_delegate_->BeforeMainThreadShutdown();
+
+ if (browser_runner_.get()) {
+ browser_runner_->Shutdown();
+ browser_runner_.reset();
+ }
+
+ if (ui_thread_.get()) {
+ // Blocks until the thread has stopped.
+ ui_thread_->Stop();
+ ui_thread_.reset();
+ }
+
+ // Shut down the content runner.
+ content::ContentMainShutdown(main_runner_.get());
+
+ main_runner_.reset();
+
+ std::move(finalize_shutdown).Run();
+ main_delegate_->AfterMainThreadShutdown();
+
+ main_delegate_.reset();
+ g_runtime_type = RuntimeType::UNINITIALIZED;
+}
+
+// From libcef/features/runtime.h:
+namespace cef {
+
+bool IsAlloyRuntimeEnabled() {
+ return g_runtime_type == RuntimeType::ALLOY;
+}
+
+bool IsChromeRuntimeEnabled() {
+ return g_runtime_type == RuntimeType::CHROME;
+}
+
+} // namespace cef
diff --git a/libcef/browser/main_runner.h b/libcef/browser/main_runner.h
new file mode 100644
index 00000000..3b612fd1
--- /dev/null
+++ b/libcef/browser/main_runner.h
@@ -0,0 +1,95 @@
+// Copyright 2020 The Chromium Embedded Framework Authors.
+// Portions copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_MAIN_RUNNER_H_
+#define CEF_LIBCEF_BROWSER_MAIN_RUNNER_H_
+#pragma once
+
+#include "include/cef_app.h"
+#include "libcef/common/main_runner_delegate.h"
+#include "libcef/common/main_runner_handler.h"
+
+#include "base/functional/callback.h"
+#include "content/public/browser/browser_main_runner.h"
+
+namespace base {
+class WaitableEvent;
+}
+
+namespace content {
+class ContentMainRunner;
+} // namespace content
+
+class CefUIThread;
+
+// Manages the main process lifespan and related objects.
+class CefMainRunner : public CefMainRunnerHandler {
+ public:
+ CefMainRunner(bool multi_threaded_message_loop, bool external_message_pump);
+
+ CefMainRunner(const CefMainRunner&) = delete;
+ CefMainRunner& operator=(const CefMainRunner&) = delete;
+
+ ~CefMainRunner();
+
+ // Called from CefContext::Initialize.
+ bool Initialize(CefSettings* settings,
+ CefRefPtr<CefApp> application,
+ const CefMainArgs& args,
+ void* windows_sandbox_info,
+ bool* initialized,
+ base::OnceClosure context_initialized);
+
+ // Called from CefContext::Shutdown.
+ void Shutdown(base::OnceClosure shutdown_on_ui_thread,
+ base::OnceClosure finalize_shutdown);
+
+ void RunMessageLoop();
+ void QuitMessageLoop();
+
+ // Called from CefExecuteProcess.
+ static int RunAsHelperProcess(const CefMainArgs& args,
+ CefRefPtr<CefApp> application,
+ void* windows_sandbox_info);
+
+ private:
+ // Called from Initialize().
+ int ContentMainInitialize(const CefMainArgs& args,
+ void* windows_sandbox_info,
+ int* no_sandbox);
+ bool ContentMainRun(bool* initialized, base::OnceClosure context_initialized);
+
+ // CefMainRunnerHandler methods:
+ void PreBrowserMain() override;
+ int RunMainProcess(content::MainFunctionParams main_function_params) override;
+
+ // Create the UI thread when running with multi-threaded message loop mode.
+ bool CreateUIThread(base::OnceClosure setup_callback);
+
+ // Called on the UI thread after the context is initialized.
+ void OnContextInitialized(base::OnceClosure context_initialized);
+
+ // Performs shutdown actions that need to occur on the UI thread before any
+ // threads are destroyed.
+ void FinishShutdownOnUIThread(base::OnceClosure shutdown_on_ui_thread,
+ base::WaitableEvent* uithread_shutdown_event);
+
+ // Destroys the runtime and related objects.
+ void FinalizeShutdown(base::OnceClosure finalize_shutdown);
+
+ const bool multi_threaded_message_loop_;
+ const bool external_message_pump_;
+
+ std::unique_ptr<CefMainRunnerDelegate> main_delegate_;
+ std::unique_ptr<content::ContentMainRunner> main_runner_;
+
+ std::unique_ptr<content::BrowserMainRunner> browser_runner_;
+ std::unique_ptr<CefUIThread> ui_thread_;
+
+ // Used to quit the current base::RunLoop.
+ base::OnceClosure quit_when_idle_callback_;
+};
+
+#endif // CEF_LIBCEF_BROWSER_MAIN_RUNNER_H_
diff --git a/libcef/browser/media_access_query.cc b/libcef/browser/media_access_query.cc
new file mode 100644
index 00000000..44f54349
--- /dev/null
+++ b/libcef/browser/media_access_query.cc
@@ -0,0 +1,359 @@
+// Copyright 2022 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#include "libcef/browser/media_access_query.h"
+
+#include "include/cef_permission_handler.h"
+#include "libcef/browser/browser_host_base.h"
+#include "libcef/browser/media_capture_devices_dispatcher.h"
+#include "libcef/browser/media_stream_registrar.h"
+#include "libcef/common/cef_switches.h"
+
+#include "base/command_line.h"
+#include "base/functional/callback_helpers.h"
+#include "third_party/blink/public/mojom/mediastream/media_stream.mojom.h"
+
+namespace media_access_query {
+
+namespace {
+
+class CefMediaAccessQuery {
+ public:
+ using CallbackType = content::MediaResponseCallback;
+
+ CefMediaAccessQuery(CefBrowserHostBase* const browser,
+ const content::MediaStreamRequest& request,
+ CallbackType&& callback)
+ : browser_(browser), request_(request), callback_(std::move(callback)) {}
+
+ CefMediaAccessQuery(CefMediaAccessQuery&& query)
+ : browser_(query.browser_),
+ request_(query.request_),
+ callback_(std::move(query.callback_)) {}
+ CefMediaAccessQuery& operator=(CefMediaAccessQuery&& query) {
+ browser_ = query.browser_;
+ request_ = query.request_;
+ callback_ = std::move(query.callback_);
+ return *this;
+ }
+
+ CefMediaAccessQuery(const CefMediaAccessQuery&) = delete;
+ CefMediaAccessQuery& operator=(const CefMediaAccessQuery&) = delete;
+
+ bool is_null() const { return callback_.is_null(); }
+
+ uint32_t requested_permissions() const {
+ int requested_permissions = CEF_MEDIA_PERMISSION_NONE;
+ if (device_audio_requested()) {
+ requested_permissions |= CEF_MEDIA_PERMISSION_DEVICE_AUDIO_CAPTURE;
+ }
+ if (device_video_requested()) {
+ requested_permissions |= CEF_MEDIA_PERMISSION_DEVICE_VIDEO_CAPTURE;
+ }
+ if (desktop_audio_requested()) {
+ requested_permissions |= CEF_MEDIA_PERMISSION_DESKTOP_AUDIO_CAPTURE;
+ }
+ if (desktop_video_requested()) {
+ requested_permissions |= CEF_MEDIA_PERMISSION_DESKTOP_VIDEO_CAPTURE;
+ }
+ return requested_permissions;
+ }
+
+ [[nodiscard]] CallbackType DisconnectCallback() {
+ return std::move(callback_);
+ }
+
+ void ExecuteCallback(uint32_t allowed_permissions) {
+ CEF_REQUIRE_UIT();
+
+ blink::mojom::MediaStreamRequestResult result;
+ blink::mojom::StreamDevicesSetPtr stream_devices_set;
+
+ if (allowed_permissions == CEF_MEDIA_PERMISSION_NONE) {
+ result = blink::mojom::MediaStreamRequestResult::PERMISSION_DENIED;
+ stream_devices_set = blink::mojom::StreamDevicesSet::New();
+ } else {
+ bool error = false;
+ if (allowed_permissions == requested_permissions()) {
+ stream_devices_set = GetRequestedMediaDevices();
+ } else {
+ stream_devices_set = GetAllowedMediaDevices(allowed_permissions, error);
+ }
+ result = error ? blink::mojom::MediaStreamRequestResult::INVALID_STATE
+ : blink::mojom::MediaStreamRequestResult::OK;
+ }
+
+ bool has_video = false;
+ bool has_audio = false;
+ if (!stream_devices_set->stream_devices.empty()) {
+ blink::mojom::StreamDevices& devices =
+ *stream_devices_set->stream_devices[0];
+ has_video = devices.video_device.has_value();
+ has_audio = devices.audio_device.has_value();
+ }
+ auto media_stream_ui =
+ browser_->GetMediaStreamRegistrar()->MaybeCreateMediaStreamUI(
+ has_video, has_audio);
+
+ std::move(callback_).Run(*stream_devices_set, result,
+ std::move(media_stream_ui));
+ }
+
+ private:
+ bool device_audio_requested() const {
+ return request_.audio_type ==
+ blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE;
+ }
+
+ bool device_video_requested() const {
+ return request_.video_type ==
+ blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE;
+ }
+
+ bool desktop_audio_requested() const {
+ return (request_.audio_type ==
+ blink::mojom::MediaStreamType::GUM_DESKTOP_AUDIO_CAPTURE) ||
+ (request_.audio_type ==
+ blink::mojom::MediaStreamType::DISPLAY_AUDIO_CAPTURE);
+ }
+
+ bool desktop_video_requested() const {
+ return (request_.video_type ==
+ blink::mojom::MediaStreamType::GUM_DESKTOP_VIDEO_CAPTURE) ||
+ (request_.video_type ==
+ blink::mojom::MediaStreamType::DISPLAY_VIDEO_CAPTURE);
+ }
+
+ blink::mojom::StreamDevicesSetPtr GetRequestedMediaDevices() const {
+ CEF_REQUIRE_UIT();
+
+ blink::MediaStreamDevices audio_devices;
+ blink::MediaStreamDevices video_devices;
+
+ if (device_audio_requested()) {
+ // Pick the desired device or fall back to the first available of the
+ // given type.
+ CefMediaCaptureDevicesDispatcher::GetInstance()->GetRequestedDevice(
+ request_.requested_audio_device_id, true, false, &audio_devices);
+ }
+
+ if (device_video_requested()) {
+ // Pick the desired device or fall back to the first available of the
+ // given type.
+ CefMediaCaptureDevicesDispatcher::GetInstance()->GetRequestedDevice(
+ request_.requested_video_device_id, false, true, &video_devices);
+ }
+
+ if (desktop_audio_requested()) {
+ audio_devices.push_back(blink::MediaStreamDevice(
+ request_.audio_type, "loopback", "System Audio"));
+ }
+
+ if (desktop_video_requested()) {
+ content::DesktopMediaID media_id;
+ if (request_.requested_video_device_id.empty()) {
+ media_id =
+ content::DesktopMediaID(content::DesktopMediaID::TYPE_SCREEN,
+ -1 /* webrtc::kFullDesktopScreenId */);
+ } else {
+ media_id =
+ content::DesktopMediaID::Parse(request_.requested_video_device_id);
+ }
+ video_devices.push_back(blink::MediaStreamDevice(
+ request_.video_type, media_id.ToString(), "Screen"));
+ }
+
+ blink::mojom::StreamDevicesSetPtr stream_devices_set =
+ blink::mojom::StreamDevicesSet::New();
+ stream_devices_set->stream_devices.emplace_back(
+ blink::mojom::StreamDevices::New());
+ blink::mojom::StreamDevices& devices =
+ *stream_devices_set->stream_devices[0];
+
+ // At most one audio device and one video device can be used in a stream.
+ if (!audio_devices.empty()) {
+ devices.audio_device = audio_devices.front();
+ }
+ if (!video_devices.empty()) {
+ devices.video_device = video_devices.front();
+ }
+
+ return stream_devices_set;
+ }
+
+ blink::mojom::StreamDevicesSetPtr GetAllowedMediaDevices(
+ uint32_t allowed_permissions,
+ bool& error) {
+ error = false;
+
+ const auto req_permissions = requested_permissions();
+
+ const bool device_audio_allowed =
+ allowed_permissions & CEF_MEDIA_PERMISSION_DEVICE_AUDIO_CAPTURE;
+ const bool device_video_allowed =
+ allowed_permissions & CEF_MEDIA_PERMISSION_DEVICE_VIDEO_CAPTURE;
+ const bool desktop_audio_allowed =
+ allowed_permissions & CEF_MEDIA_PERMISSION_DESKTOP_AUDIO_CAPTURE;
+ const bool desktop_video_allowed =
+ allowed_permissions & CEF_MEDIA_PERMISSION_DESKTOP_VIDEO_CAPTURE;
+
+ blink::mojom::StreamDevicesSetPtr stream_devices_set;
+
+ // getDisplayMedia must always request video
+ if (desktop_video_requested() &&
+ (!desktop_video_allowed && desktop_audio_allowed)) {
+ LOG(WARNING) << "Response to getDisplayMedia is not allowed to only "
+ "return Audio";
+ error = true;
+ } else if (!desktop_video_requested() &&
+ req_permissions != allowed_permissions) {
+ LOG(WARNING)
+ << "Response to getUserMedia must match requested permissions ("
+ << req_permissions << " vs " << allowed_permissions << ")";
+ error = true;
+ }
+
+ if (error) {
+ stream_devices_set = blink::mojom::StreamDevicesSet::New();
+ } else {
+ if (!device_audio_allowed && !desktop_audio_allowed) {
+ request_.audio_type = blink::mojom::MediaStreamType::NO_SERVICE;
+ }
+ if (!device_video_allowed && !desktop_video_allowed) {
+ request_.video_type = blink::mojom::MediaStreamType::NO_SERVICE;
+ }
+ stream_devices_set = GetRequestedMediaDevices();
+ }
+
+ return stream_devices_set;
+ }
+
+ CefRefPtr<CefBrowserHostBase> browser_;
+ content::MediaStreamRequest request_;
+ CallbackType callback_;
+};
+
+class CefMediaAccessCallbackImpl : public CefMediaAccessCallback {
+ public:
+ using CallbackType = CefMediaAccessQuery;
+
+ explicit CefMediaAccessCallbackImpl(CallbackType&& callback)
+ : callback_(std::move(callback)) {}
+
+ CefMediaAccessCallbackImpl(const CefMediaAccessCallbackImpl&) = delete;
+ CefMediaAccessCallbackImpl& operator=(const CefMediaAccessCallbackImpl&) =
+ delete;
+
+ ~CefMediaAccessCallbackImpl() override {
+ if (!callback_.is_null()) {
+ // The callback is still pending. Cancel it now.
+ if (CEF_CURRENTLY_ON_UIT()) {
+ RunNow(std::move(callback_), CEF_MEDIA_PERMISSION_NONE);
+ } else {
+ CEF_POST_TASK(
+ CEF_UIT,
+ base::BindOnce(&CefMediaAccessCallbackImpl::RunNow,
+ std::move(callback_), CEF_MEDIA_PERMISSION_NONE));
+ }
+ }
+ }
+
+ void Continue(uint32_t allowed_permissions) override {
+ if (CEF_CURRENTLY_ON_UIT()) {
+ if (!callback_.is_null()) {
+ RunNow(std::move(callback_), allowed_permissions);
+ }
+ } else {
+ CEF_POST_TASK(CEF_UIT,
+ base::BindOnce(&CefMediaAccessCallbackImpl::Continue, this,
+ allowed_permissions));
+ }
+ }
+
+ void Cancel() override { Continue(CEF_MEDIA_PERMISSION_NONE); }
+
+ [[nodiscard]] CallbackType Disconnect() { return std::move(callback_); }
+ bool IsDisconnected() const { return callback_.is_null(); }
+
+ private:
+ static void RunNow(CallbackType callback, uint32_t allowed_permissions) {
+ callback.ExecuteCallback(allowed_permissions);
+ }
+
+ CallbackType callback_;
+
+ IMPLEMENT_REFCOUNTING(CefMediaAccessCallbackImpl);
+};
+
+bool CheckCommandLinePermission() {
+ const base::CommandLine* command_line =
+ base::CommandLine::ForCurrentProcess();
+ return command_line->HasSwitch(switches::kEnableMediaStream);
+}
+
+} // namespace
+
+bool CheckMediaAccessPermission(CefBrowserHostBase* browser,
+ content::RenderFrameHost* render_frame_host,
+ const GURL& security_origin,
+ blink::mojom::MediaStreamType type) {
+ // Always allowed here. RequestMediaAccessPermission will be called.
+ return true;
+}
+
+content::MediaResponseCallback RequestMediaAccessPermission(
+ CefBrowserHostBase* browser,
+ const content::MediaStreamRequest& request,
+ content::MediaResponseCallback callback,
+ bool default_disallow) {
+ CEF_REQUIRE_UIT();
+
+ CefMediaAccessQuery query(browser, request, std::move(callback));
+
+ if (CheckCommandLinePermission()) {
+ // Allow all requested permissions.
+ query.ExecuteCallback(query.requested_permissions());
+ return base::NullCallback();
+ }
+
+ bool handled = false;
+
+ if (auto client = browser->GetClient()) {
+ if (auto handler = client->GetPermissionHandler()) {
+ const auto requested_permissions = query.requested_permissions();
+ CefRefPtr<CefMediaAccessCallbackImpl> callbackImpl(
+ new CefMediaAccessCallbackImpl(std::move(query)));
+
+ auto frame =
+ browser->GetFrameForGlobalId(content::GlobalRenderFrameHostId(
+ request.render_process_id, request.render_frame_id));
+ if (!frame) {
+ frame = browser->GetMainFrame();
+ }
+ handled = handler->OnRequestMediaAccessPermission(
+ browser, frame, request.security_origin.spec(), requested_permissions,
+ callbackImpl.get());
+ if (!handled) {
+ LOG_IF(ERROR, callbackImpl->IsDisconnected())
+ << "Should return true from OnRequestMediaAccessPermission when "
+ "executing the callback";
+ query = callbackImpl->Disconnect();
+ }
+ }
+ }
+
+ if (!query.is_null()) {
+ if (default_disallow && !handled) {
+ // Disallow access by default.
+ query.ExecuteCallback(CEF_MEDIA_PERMISSION_NONE);
+ } else {
+ // Proceed with default handling.
+ return query.DisconnectCallback();
+ }
+ }
+
+ return base::NullCallback();
+}
+
+} // namespace media_access_query
diff --git a/libcef/browser/media_access_query.h b/libcef/browser/media_access_query.h
new file mode 100644
index 00000000..1af6c266
--- /dev/null
+++ b/libcef/browser/media_access_query.h
@@ -0,0 +1,37 @@
+// Copyright 2022 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_MEDIA_ACCESS_QUERY_H_
+#define CEF_LIBCEF_BROWSER_MEDIA_ACCESS_QUERY_H_
+#pragma once
+
+#include "content/public/browser/media_stream_request.h"
+
+namespace content {
+class RenderFrameHost;
+}
+
+class CefBrowserHostBase;
+class GURL;
+
+namespace media_access_query {
+
+// Called from WebContentsDelegate::CheckMediaAccessPermission.
+bool CheckMediaAccessPermission(CefBrowserHostBase* browser,
+ content::RenderFrameHost* render_frame_host,
+ const GURL& security_origin,
+ blink::mojom::MediaStreamType type);
+
+// Called from WebContentsDelegate::RequestMediaAccessPermission.
+// |callback| will be returned if the request is unhandled and
+// |default_disallow| is false.
+[[nodiscard]] content::MediaResponseCallback RequestMediaAccessPermission(
+ CefBrowserHostBase* browser,
+ const content::MediaStreamRequest& request,
+ content::MediaResponseCallback callback,
+ bool default_disallow);
+
+} // namespace media_access_query
+
+#endif // CEF_LIBCEF_BROWSER_MEDIA_ACCESS_QUERY_H_
diff --git a/libcef/browser/media_capture_devices_dispatcher.cc b/libcef/browser/media_capture_devices_dispatcher.cc
new file mode 100644
index 00000000..25d53017
--- /dev/null
+++ b/libcef/browser/media_capture_devices_dispatcher.cc
@@ -0,0 +1,133 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/media_capture_devices_dispatcher.h"
+
+#include "chrome/common/pref_names.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/pref_service.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/media_capture_devices.h"
+
+using blink::MediaStreamDevices;
+using content::BrowserThread;
+
+namespace {
+
+const blink::MediaStreamDevice* FindDefaultDeviceWithId(
+ const blink::MediaStreamDevices& devices,
+ const std::string& device_id) {
+ if (devices.empty()) {
+ return nullptr;
+ }
+
+ blink::MediaStreamDevices::const_iterator iter = devices.begin();
+ for (; iter != devices.end(); ++iter) {
+ if (iter->id == device_id) {
+ return &(*iter);
+ }
+ }
+
+ return &(*devices.begin());
+}
+
+} // namespace
+
+CefMediaCaptureDevicesDispatcher*
+CefMediaCaptureDevicesDispatcher::GetInstance() {
+ return base::Singleton<CefMediaCaptureDevicesDispatcher>::get();
+}
+
+CefMediaCaptureDevicesDispatcher::CefMediaCaptureDevicesDispatcher() {}
+
+CefMediaCaptureDevicesDispatcher::~CefMediaCaptureDevicesDispatcher() {}
+
+void CefMediaCaptureDevicesDispatcher::RegisterPrefs(
+ PrefRegistrySimple* registry) {
+ registry->RegisterStringPref(prefs::kDefaultAudioCaptureDevice,
+ std::string());
+ registry->RegisterStringPref(prefs::kDefaultVideoCaptureDevice,
+ std::string());
+}
+
+void CefMediaCaptureDevicesDispatcher::GetDefaultDevices(
+ PrefService* prefs,
+ bool audio,
+ bool video,
+ blink::MediaStreamDevices* devices) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK(audio || video);
+
+ std::string default_device;
+ if (audio) {
+ default_device = prefs->GetString(prefs::kDefaultAudioCaptureDevice);
+ GetRequestedDevice(default_device, true, false, devices);
+ }
+
+ if (video) {
+ default_device = prefs->GetString(prefs::kDefaultVideoCaptureDevice);
+ GetRequestedDevice(default_device, false, true, devices);
+ }
+}
+
+void CefMediaCaptureDevicesDispatcher::GetRequestedDevice(
+ const std::string& requested_device_id,
+ bool audio,
+ bool video,
+ blink::MediaStreamDevices* devices) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK(audio || video);
+
+ if (audio) {
+ const blink::MediaStreamDevices& audio_devices = GetAudioCaptureDevices();
+ const blink::MediaStreamDevice* const device =
+ FindDefaultDeviceWithId(audio_devices, requested_device_id);
+ if (device) {
+ devices->push_back(*device);
+ }
+ }
+ if (video) {
+ const blink::MediaStreamDevices& video_devices = GetVideoCaptureDevices();
+ const blink::MediaStreamDevice* const device =
+ FindDefaultDeviceWithId(video_devices, requested_device_id);
+ if (device) {
+ devices->push_back(*device);
+ }
+ }
+}
+
+void CefMediaCaptureDevicesDispatcher::OnAudioCaptureDevicesChanged() {}
+
+void CefMediaCaptureDevicesDispatcher::OnVideoCaptureDevicesChanged() {}
+
+void CefMediaCaptureDevicesDispatcher::OnMediaRequestStateChanged(
+ int render_process_id,
+ int render_frame_id,
+ int page_request_id,
+ const GURL& security_origin,
+ blink::mojom::MediaStreamType stream_type,
+ content::MediaRequestState state) {}
+
+void CefMediaCaptureDevicesDispatcher::OnCreatingAudioStream(
+ int render_process_id,
+ int render_view_id) {}
+
+void CefMediaCaptureDevicesDispatcher::OnSetCapturingLinkSecured(
+ int render_process_id,
+ int render_frame_id,
+ int page_request_id,
+ blink::mojom::MediaStreamType stream_type,
+ bool is_secure) {}
+
+const MediaStreamDevices&
+CefMediaCaptureDevicesDispatcher::GetAudioCaptureDevices() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ return content::MediaCaptureDevices::GetInstance()->GetAudioCaptureDevices();
+}
+
+const MediaStreamDevices&
+CefMediaCaptureDevicesDispatcher::GetVideoCaptureDevices() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ return content::MediaCaptureDevices::GetInstance()->GetVideoCaptureDevices();
+}
diff --git a/libcef/browser/media_capture_devices_dispatcher.h b/libcef/browser/media_capture_devices_dispatcher.h
new file mode 100644
index 00000000..3082bf1a
--- /dev/null
+++ b/libcef/browser/media_capture_devices_dispatcher.h
@@ -0,0 +1,70 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_MEDIA_CAPTURE_DEVICES_DISPATCHER_H_
+#define CEF_LIBCEF_BROWSER_MEDIA_CAPTURE_DEVICES_DISPATCHER_H_
+
+#include "base/functional/callback.h"
+#include "base/memory/singleton.h"
+#include "base/observer_list.h"
+#include "content/public/browser/media_observer.h"
+#include "content/public/browser/media_stream_request.h"
+
+class PrefRegistrySimple;
+class PrefService;
+
+// This singleton is used to receive updates about media events from the content
+// layer. Based on chrome/browser/media/media_capture_devices_dispatcher.[h|cc].
+class CefMediaCaptureDevicesDispatcher : public content::MediaObserver {
+ public:
+ static CefMediaCaptureDevicesDispatcher* GetInstance();
+
+ // Registers the preferences related to Media Stream default devices.
+ static void RegisterPrefs(PrefRegistrySimple* registry);
+
+ // Helper to get the default devices which can be used by the media request,
+ // if the return list is empty, it means there is no available device on the
+ // OS. Called on the UI thread.
+ void GetDefaultDevices(PrefService* prefs,
+ bool audio,
+ bool video,
+ blink::MediaStreamDevices* devices);
+
+ // Helper for picking the device that was requested for an OpenDevice request.
+ // If the device requested is not available it will revert to using the first
+ // available one instead or will return an empty list if no devices of the
+ // requested kind are present. Called on the UI thread.
+ void GetRequestedDevice(const std::string& requested_device_id,
+ bool audio,
+ bool video,
+ blink::MediaStreamDevices* devices);
+
+ // Overridden from content::MediaObserver:
+ void OnAudioCaptureDevicesChanged() override;
+ void OnVideoCaptureDevicesChanged() override;
+ void OnMediaRequestStateChanged(int render_process_id,
+ int render_frame_id,
+ int page_request_id,
+ const GURL& security_origin,
+ blink::mojom::MediaStreamType stream_type,
+ content::MediaRequestState state) override;
+ void OnCreatingAudioStream(int render_process_id,
+ int render_view_id) override;
+ void OnSetCapturingLinkSecured(int render_process_id,
+ int render_frame_id,
+ int page_request_id,
+ blink::mojom::MediaStreamType stream_type,
+ bool is_secure) override;
+
+ private:
+ friend struct base::DefaultSingletonTraits<CefMediaCaptureDevicesDispatcher>;
+
+ CefMediaCaptureDevicesDispatcher();
+ ~CefMediaCaptureDevicesDispatcher() override;
+
+ const blink::MediaStreamDevices& GetAudioCaptureDevices();
+ const blink::MediaStreamDevices& GetVideoCaptureDevices();
+};
+
+#endif // CEF_LIBCEF_BROWSER_MEDIA_CAPTURE_DEVICES_DISPATCHER_H_
diff --git a/libcef/browser/media_router/media_route_impl.cc b/libcef/browser/media_router/media_route_impl.cc
new file mode 100644
index 00000000..243f5854
--- /dev/null
+++ b/libcef/browser/media_router/media_route_impl.cc
@@ -0,0 +1,89 @@
+// Copyright (c) 2020 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "libcef/browser/media_router/media_route_impl.h"
+
+#include "libcef/browser/media_router/media_router_manager.h"
+#include "libcef/browser/media_router/media_sink_impl.h"
+#include "libcef/browser/media_router/media_source_impl.h"
+#include "libcef/browser/thread_util.h"
+
+namespace {
+
+// Do not keep a reference to the object returned by this method.
+CefBrowserContext* GetBrowserContext(const CefBrowserContext::Getter& getter) {
+ CEF_REQUIRE_UIT();
+ DCHECK(!getter.is_null());
+
+ // Will return nullptr if the BrowserContext has been shut down.
+ return getter.Run();
+}
+
+} // namespace
+
+CefMediaRouteImpl::CefMediaRouteImpl(
+ const media_router::MediaRoute& route,
+ const CefBrowserContext::Getter& browser_context_getter)
+ : route_(route), browser_context_getter_(browser_context_getter) {
+ CEF_REQUIRE_UIT();
+}
+
+CefString CefMediaRouteImpl::GetId() {
+ return route_.media_route_id();
+}
+
+CefRefPtr<CefMediaSource> CefMediaRouteImpl::GetSource() {
+ return new CefMediaSourceImpl(route_.media_source().id());
+}
+
+CefRefPtr<CefMediaSink> CefMediaRouteImpl::GetSink() {
+ return new CefMediaSinkImpl(
+ route_.media_sink_id(), route_.media_sink_name(),
+ route_.media_source().IsDialSource()
+ ? media_router::mojom::MediaRouteProviderId::DIAL
+ : media_router::mojom::MediaRouteProviderId::CAST);
+}
+
+void CefMediaRouteImpl::SendRouteMessage(const void* message,
+ size_t message_size) {
+ std::string message_str(reinterpret_cast<const char*>(message), message_size);
+
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(
+ CEF_UIT,
+ base::BindOnce(
+ [](CefRefPtr<CefMediaRouteImpl> self, std::string message_str) {
+ self->SendRouteMessageInternal(std::move(message_str));
+ },
+ CefRefPtr<CefMediaRouteImpl>(this), std::move(message_str)));
+ return;
+ }
+
+ SendRouteMessageInternal(std::move(message_str));
+}
+
+void CefMediaRouteImpl::Terminate() {
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(CEF_UIT, base::BindOnce(&CefMediaRouteImpl::Terminate, this));
+ return;
+ }
+
+ auto browser_context = GetBrowserContext(browser_context_getter_);
+ if (!browser_context) {
+ return;
+ }
+
+ browser_context->GetMediaRouterManager()->TerminateRoute(
+ route_.media_route_id());
+}
+
+void CefMediaRouteImpl::SendRouteMessageInternal(std::string message) {
+ auto browser_context = GetBrowserContext(browser_context_getter_);
+ if (!browser_context) {
+ return;
+ }
+
+ browser_context->GetMediaRouterManager()->SendRouteMessage(
+ route_.media_route_id(), message);
+}
diff --git a/libcef/browser/media_router/media_route_impl.h b/libcef/browser/media_router/media_route_impl.h
new file mode 100644
index 00000000..8ca65c70
--- /dev/null
+++ b/libcef/browser/media_router/media_route_impl.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2020 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_MEDIA_ROUTER_MEDIA_ROUTE_IMPL_H_
+#define CEF_LIBCEF_BROWSER_MEDIA_ROUTER_MEDIA_ROUTE_IMPL_H_
+#pragma once
+
+#include "include/cef_media_router.h"
+#include "libcef/browser/browser_context.h"
+
+#include "components/media_router/common/media_route.h"
+
+// Implementation of the CefMediaRoute interface. Only created on the UI thread.
+class CefMediaRouteImpl : public CefMediaRoute {
+ public:
+ CefMediaRouteImpl(const media_router::MediaRoute& route,
+ const CefBrowserContext::Getter& browser_context_getter);
+
+ CefMediaRouteImpl(const CefMediaRouteImpl&) = delete;
+ CefMediaRouteImpl& operator=(const CefMediaRouteImpl&) = delete;
+
+ // CefMediaRoute methods.
+ CefString GetId() override;
+ CefRefPtr<CefMediaSource> GetSource() override;
+ CefRefPtr<CefMediaSink> GetSink() override;
+ void SendRouteMessage(const void* message, size_t message_size) override;
+ void Terminate() override;
+
+ const media_router::MediaRoute& route() const { return route_; }
+
+ private:
+ void SendRouteMessageInternal(std::string message);
+
+ // Read-only after creation.
+ const media_router::MediaRoute route_;
+ const CefBrowserContext::Getter browser_context_getter_;
+
+ IMPLEMENT_REFCOUNTING(CefMediaRouteImpl);
+};
+
+#endif // CEF_LIBCEF_BROWSER_MEDIA_ROUTER_MEDIA_ROUTE_IMPL_H_
diff --git a/libcef/browser/media_router/media_router_impl.cc b/libcef/browser/media_router/media_router_impl.cc
new file mode 100644
index 00000000..4955fc76
--- /dev/null
+++ b/libcef/browser/media_router/media_router_impl.cc
@@ -0,0 +1,335 @@
+// Copyright (c) 2020 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "libcef/browser/media_router/media_router_impl.h"
+
+#include "libcef/browser/media_router/media_route_impl.h"
+#include "libcef/browser/media_router/media_router_manager.h"
+#include "libcef/browser/media_router/media_sink_impl.h"
+#include "libcef/browser/media_router/media_source_impl.h"
+#include "libcef/browser/thread_util.h"
+
+namespace {
+
+// Do not keep a reference to the object returned by this method.
+CefBrowserContext* GetBrowserContext(const CefBrowserContext::Getter& getter) {
+ CEF_REQUIRE_UIT();
+ DCHECK(!getter.is_null());
+
+ // Will return nullptr if the BrowserContext has been shut down.
+ return getter.Run();
+}
+
+} // namespace
+
+class CefRegistrationImpl : public CefRegistration,
+ public CefMediaRouterManager::Observer {
+ public:
+ explicit CefRegistrationImpl(CefRefPtr<CefMediaObserver> observer)
+ : observer_(observer) {
+ DCHECK(observer_);
+ }
+
+ CefRegistrationImpl(const CefRegistrationImpl&) = delete;
+ CefRegistrationImpl& operator=(const CefRegistrationImpl&) = delete;
+
+ ~CefRegistrationImpl() override {
+ CEF_REQUIRE_UIT();
+
+ // May be null if OnMediaRouterDestroyed was called.
+ if (browser_context_getter_.is_null()) {
+ return;
+ }
+
+ auto browser_context = GetBrowserContext(browser_context_getter_);
+ if (!browser_context) {
+ return;
+ }
+
+ browser_context->GetMediaRouterManager()->RemoveObserver(this);
+ }
+
+ void Initialize(const CefBrowserContext::Getter& browser_context_getter) {
+ CEF_REQUIRE_UIT();
+ DCHECK(!browser_context_getter.is_null());
+ DCHECK(browser_context_getter_.is_null());
+ browser_context_getter_ = browser_context_getter;
+
+ auto browser_context = GetBrowserContext(browser_context_getter_);
+ if (!browser_context) {
+ return;
+ }
+
+ browser_context->GetMediaRouterManager()->AddObserver(this);
+ }
+
+ private:
+ // CefMediaRouterManager::Observer methods:
+ void OnMediaRouterDestroyed() override { browser_context_getter_.Reset(); }
+
+ void OnMediaSinks(
+ const CefMediaRouterManager::MediaSinkVector& sinks) override {
+ std::vector<CefRefPtr<CefMediaSink>> cef_sinks;
+ for (const auto& sink : sinks) {
+ cef_sinks.push_back(new CefMediaSinkImpl(sink.sink));
+ }
+ observer_->OnSinks(cef_sinks);
+ }
+
+ void OnMediaRoutes(
+ const CefMediaRouterManager::MediaRouteVector& routes) override {
+ std::vector<CefRefPtr<CefMediaRoute>> cef_routes;
+ for (const auto& route : routes) {
+ cef_routes.push_back(MakeCefRoute(route));
+ }
+ observer_->OnRoutes(cef_routes);
+ }
+
+ void OnMediaRouteMessages(
+ const media_router::MediaRoute& route,
+ const CefMediaRouterManager::MediaMessageVector& messages) override {
+ CefRefPtr<CefMediaRoute> cef_route = MakeCefRoute(route);
+ for (const auto& message : messages) {
+ if (message->type == media_router::mojom::RouteMessage::Type::TEXT) {
+ if (message->message.has_value()) {
+ const std::string& str = *(message->message);
+ observer_->OnRouteMessageReceived(cef_route, str.c_str(), str.size());
+ }
+ } else if (message->type ==
+ media_router::mojom::RouteMessage::Type::BINARY) {
+ if (message->data.has_value()) {
+ const std::vector<uint8_t>& data = *(message->data);
+ observer_->OnRouteMessageReceived(cef_route, data.data(),
+ data.size());
+ }
+ }
+ }
+ }
+
+ void OnMediaRouteStateChange(
+ const media_router::MediaRoute& route,
+ const content::PresentationConnectionStateChangeInfo& info) override {
+ observer_->OnRouteStateChanged(MakeCefRoute(route),
+ ToConnectionState(info.state));
+ }
+
+ CefRefPtr<CefMediaRoute> MakeCefRoute(const media_router::MediaRoute& route) {
+ return new CefMediaRouteImpl(route, browser_context_getter_);
+ }
+
+ static CefMediaObserver::ConnectionState ToConnectionState(
+ blink::mojom::PresentationConnectionState state) {
+ switch (state) {
+ case blink::mojom::PresentationConnectionState::CONNECTING:
+ return CEF_MRCS_CONNECTING;
+ case blink::mojom::PresentationConnectionState::CONNECTED:
+ return CEF_MRCS_CONNECTED;
+ case blink::mojom::PresentationConnectionState::CLOSED:
+ return CEF_MRCS_CLOSED;
+ case blink::mojom::PresentationConnectionState::TERMINATED:
+ return CEF_MRCS_TERMINATED;
+ }
+ NOTREACHED();
+ return CEF_MRCS_UNKNOWN;
+ }
+
+ CefRefPtr<CefMediaObserver> observer_;
+ CefBrowserContext::Getter browser_context_getter_;
+
+ IMPLEMENT_REFCOUNTING_DELETE_ON_UIT(CefRegistrationImpl);
+};
+
+CefMediaRouterImpl::CefMediaRouterImpl() = default;
+
+void CefMediaRouterImpl::Initialize(
+ const CefBrowserContext::Getter& browser_context_getter,
+ CefRefPtr<CefCompletionCallback> callback) {
+ CEF_REQUIRE_UIT();
+ DCHECK(!initialized_);
+ DCHECK(!browser_context_getter.is_null());
+ DCHECK(browser_context_getter_.is_null());
+ browser_context_getter_ = browser_context_getter;
+
+ initialized_ = true;
+ if (!init_callbacks_.empty()) {
+ for (auto& init_callback : init_callbacks_) {
+ std::move(init_callback).Run();
+ }
+ init_callbacks_.clear();
+ }
+
+ if (callback) {
+ // Execute client callback asynchronously for consistency.
+ CEF_POST_TASK(CEF_UIT, base::BindOnce(&CefCompletionCallback::OnComplete,
+ callback.get()));
+ }
+}
+
+CefRefPtr<CefRegistration> CefMediaRouterImpl::AddObserver(
+ CefRefPtr<CefMediaObserver> observer) {
+ if (!observer) {
+ return nullptr;
+ }
+ CefRefPtr<CefRegistrationImpl> registration =
+ new CefRegistrationImpl(observer);
+ StoreOrTriggerInitCallback(base::BindOnce(
+ &CefMediaRouterImpl::InitializeRegistrationInternal, this, registration));
+ return registration.get();
+}
+
+CefRefPtr<CefMediaSource> CefMediaRouterImpl::GetSource(const CefString& urn) {
+ if (urn.empty()) {
+ return nullptr;
+ }
+
+ // Check for a valid URL and supported Cast/DIAL schemes.
+ GURL presentation_url(urn.ToString());
+ if (!media_router::IsValidPresentationUrl(presentation_url)) {
+ return nullptr;
+ }
+
+ if (presentation_url.SchemeIsHTTPOrHTTPS()) {
+ // We don't support tab/desktop mirroring, which is what Cast uses for
+ // arbitrary HTTP/HTTPS URLs (see CastMediaSource).
+ return nullptr;
+ }
+
+ return new CefMediaSourceImpl(presentation_url);
+}
+
+void CefMediaRouterImpl::NotifyCurrentSinks() {
+ StoreOrTriggerInitCallback(
+ base::BindOnce(&CefMediaRouterImpl::NotifyCurrentSinksInternal, this));
+}
+
+void CefMediaRouterImpl::CreateRoute(
+ CefRefPtr<CefMediaSource> source,
+ CefRefPtr<CefMediaSink> sink,
+ CefRefPtr<CefMediaRouteCreateCallback> callback) {
+ StoreOrTriggerInitCallback(base::BindOnce(
+ &CefMediaRouterImpl::CreateRouteInternal, this, source, sink, callback));
+}
+
+void CefMediaRouterImpl::NotifyCurrentRoutes() {
+ StoreOrTriggerInitCallback(
+ base::BindOnce(&CefMediaRouterImpl::NotifyCurrentRoutesInternal, this));
+}
+
+void CefMediaRouterImpl::InitializeRegistrationInternal(
+ CefRefPtr<CefRegistrationImpl> registration) {
+ DCHECK(ValidContext());
+
+ registration->Initialize(browser_context_getter_);
+}
+
+void CefMediaRouterImpl::NotifyCurrentSinksInternal() {
+ DCHECK(ValidContext());
+
+ auto browser_context = GetBrowserContext(browser_context_getter_);
+ if (!browser_context) {
+ return;
+ }
+
+ browser_context->GetMediaRouterManager()->NotifyCurrentSinks();
+}
+
+void CefMediaRouterImpl::CreateRouteInternal(
+ CefRefPtr<CefMediaSource> source,
+ CefRefPtr<CefMediaSink> sink,
+ CefRefPtr<CefMediaRouteCreateCallback> callback) {
+ DCHECK(ValidContext());
+
+ std::string error;
+
+ auto browser_context = GetBrowserContext(browser_context_getter_);
+ if (!browser_context) {
+ error = "Context is not valid";
+ } else if (!source) {
+ error = "Source is empty or invalid";
+ } else if (!sink) {
+ error = "Sink is empty or invalid";
+ } else if (!sink->IsCompatibleWith(source)) {
+ error = "Sink is not compatible with source";
+ }
+
+ if (!error.empty()) {
+ LOG(WARNING) << "Media route creation failed: " << error;
+ if (callback) {
+ callback->OnMediaRouteCreateFinished(CEF_MRCR_UNKNOWN_ERROR, error,
+ nullptr);
+ }
+ return;
+ }
+
+ auto source_impl = static_cast<CefMediaSourceImpl*>(source.get());
+ auto sink_impl = static_cast<CefMediaSinkImpl*>(sink.get());
+
+ browser_context->GetMediaRouterManager()->CreateRoute(
+ source_impl->source().id(), sink_impl->sink().id(), url::Origin(),
+ base::BindOnce(&CefMediaRouterImpl::CreateRouteCallback, this, callback));
+}
+
+void CefMediaRouterImpl::NotifyCurrentRoutesInternal() {
+ DCHECK(ValidContext());
+
+ auto browser_context = GetBrowserContext(browser_context_getter_);
+ if (!browser_context) {
+ return;
+ }
+
+ browser_context->GetMediaRouterManager()->NotifyCurrentRoutes();
+}
+
+void CefMediaRouterImpl::CreateRouteCallback(
+ CefRefPtr<CefMediaRouteCreateCallback> callback,
+ const media_router::RouteRequestResult& result) {
+ DCHECK(ValidContext());
+
+ if (result.result_code() != media_router::mojom::RouteRequestResultCode::OK) {
+ LOG(WARNING) << "Media route creation failed: " << result.error() << " ("
+ << result.result_code() << ")";
+ }
+
+ if (!callback) {
+ return;
+ }
+
+ CefRefPtr<CefMediaRoute> route;
+ if (result.result_code() == media_router::mojom::RouteRequestResultCode::OK &&
+ result.route()) {
+ route = new CefMediaRouteImpl(*result.route(), browser_context_getter_);
+ }
+
+ callback->OnMediaRouteCreateFinished(
+ static_cast<cef_media_route_create_result_t>(result.result_code()),
+ result.error(), route);
+}
+
+void CefMediaRouterImpl::StoreOrTriggerInitCallback(
+ base::OnceClosure callback) {
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(
+ CEF_UIT, base::BindOnce(&CefMediaRouterImpl::StoreOrTriggerInitCallback,
+ this, std::move(callback)));
+ return;
+ }
+
+ if (initialized_) {
+ std::move(callback).Run();
+ } else {
+ init_callbacks_.emplace_back(std::move(callback));
+ }
+}
+
+bool CefMediaRouterImpl::ValidContext() const {
+ return CEF_CURRENTLY_ON_UIT() && initialized_;
+}
+
+// CefMediaRouter methods ------------------------------------------------------
+
+// static
+CefRefPtr<CefMediaRouter> CefMediaRouter::GetGlobalMediaRouter(
+ CefRefPtr<CefCompletionCallback> callback) {
+ return CefRequestContext::GetGlobalContext()->GetMediaRouter(callback);
+}
diff --git a/libcef/browser/media_router/media_router_impl.h b/libcef/browser/media_router/media_router_impl.h
new file mode 100644
index 00000000..f0aba10e
--- /dev/null
+++ b/libcef/browser/media_router/media_router_impl.h
@@ -0,0 +1,66 @@
+// Copyright (c) 2020 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_MEDIA_ROUTER_MEDIA_ROUTER_IMPL_H_
+#define CEF_LIBCEF_BROWSER_MEDIA_ROUTER_MEDIA_ROUTER_IMPL_H_
+#pragma once
+
+#include "include/cef_media_router.h"
+#include "libcef/browser/browser_context.h"
+
+#include "components/media_router/common/mojom/media_router.mojom.h"
+
+class CefRegistrationImpl;
+
+// Implementation of the CefMediaRouter interface. May be created on any thread.
+class CefMediaRouterImpl : public CefMediaRouter {
+ public:
+ CefMediaRouterImpl();
+
+ CefMediaRouterImpl(const CefMediaRouterImpl&) = delete;
+ CefMediaRouterImpl& operator=(const CefMediaRouterImpl&) = delete;
+
+ // Called on the UI thread after object creation and before any other object
+ // methods are executed on the UI thread.
+ void Initialize(const CefBrowserContext::Getter& browser_context_getter,
+ CefRefPtr<CefCompletionCallback> callback);
+
+ // CefMediaRouter methods.
+ CefRefPtr<CefRegistration> AddObserver(
+ CefRefPtr<CefMediaObserver> observer) override;
+ CefRefPtr<CefMediaSource> GetSource(const CefString& urn) override;
+ void NotifyCurrentSinks() override;
+ void CreateRoute(CefRefPtr<CefMediaSource> source,
+ CefRefPtr<CefMediaSink> sink,
+ CefRefPtr<CefMediaRouteCreateCallback> callback) override;
+ void NotifyCurrentRoutes() override;
+
+ private:
+ void InitializeRegistrationInternal(
+ CefRefPtr<CefRegistrationImpl> registration);
+ void NotifyCurrentSinksInternal();
+ void CreateRouteInternal(CefRefPtr<CefMediaSource> source,
+ CefRefPtr<CefMediaSink> sink,
+ CefRefPtr<CefMediaRouteCreateCallback> callback);
+ void NotifyCurrentRoutesInternal();
+
+ void CreateRouteCallback(CefRefPtr<CefMediaRouteCreateCallback> callback,
+ const media_router::RouteRequestResult& result);
+
+ // If the context is fully initialized execute |callback|, otherwise
+ // store it until the context is fully initialized.
+ void StoreOrTriggerInitCallback(base::OnceClosure callback);
+
+ bool ValidContext() const;
+
+ // Only accessed on the UI thread. Will be non-null after Initialize().
+ CefBrowserContext::Getter browser_context_getter_;
+
+ bool initialized_ = false;
+ std::vector<base::OnceClosure> init_callbacks_;
+
+ IMPLEMENT_REFCOUNTING(CefMediaRouterImpl);
+};
+
+#endif // CEF_LIBCEF_BROWSER_MEDIA_ROUTER_MEDIA_ROUTER_IMPL_H_
diff --git a/libcef/browser/media_router/media_router_manager.cc b/libcef/browser/media_router/media_router_manager.cc
new file mode 100644
index 00000000..6015439c
--- /dev/null
+++ b/libcef/browser/media_router/media_router_manager.cc
@@ -0,0 +1,303 @@
+// Copyright (c) 2020 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "libcef/browser/media_router/media_router_manager.h"
+
+#include "libcef/browser/browser_context.h"
+#include "libcef/browser/thread_util.h"
+
+#include "components/media_router/browser/media_router_factory.h"
+#include "components/media_router/browser/media_routes_observer.h"
+#include "components/media_router/browser/presentation_connection_message_observer.h"
+#include "components/media_router/browser/route_message_util.h"
+
+namespace {
+
+const int kTimeoutMs = 5 * 1000;
+const char kDefaultPresentationUrl[] = "https://google.com";
+
+} // namespace
+
+class CefMediaRoutesObserver : public media_router::MediaRoutesObserver {
+ public:
+ explicit CefMediaRoutesObserver(CefMediaRouterManager* manager)
+ : media_router::MediaRoutesObserver(manager->GetMediaRouter()),
+ manager_(manager) {}
+
+ CefMediaRoutesObserver(const CefMediaRoutesObserver&) = delete;
+ CefMediaRoutesObserver& operator=(const CefMediaRoutesObserver&) = delete;
+
+ void OnRoutesUpdated(
+ const std::vector<media_router::MediaRoute>& routes) override {
+ manager_->routes_ = routes;
+ manager_->NotifyCurrentRoutes();
+ }
+
+ private:
+ CefMediaRouterManager* const manager_;
+};
+
+// Used to receive messages if PresentationConnection is not supported.
+class CefPresentationConnectionMessageObserver
+ : public media_router::PresentationConnectionMessageObserver {
+ public:
+ CefPresentationConnectionMessageObserver(
+ CefMediaRouterManager* manager,
+ const media_router::MediaRoute& route)
+ : media_router::PresentationConnectionMessageObserver(
+ manager->GetMediaRouter(),
+ route.media_route_id()),
+ manager_(manager),
+ route_(route) {}
+
+ CefPresentationConnectionMessageObserver(
+ const CefPresentationConnectionMessageObserver&) = delete;
+ CefPresentationConnectionMessageObserver& operator=(
+ const CefPresentationConnectionMessageObserver&) = delete;
+
+ void OnMessagesReceived(
+ CefMediaRouterManager::MediaMessageVector messages) override {
+ manager_->OnMessagesReceived(route_, messages);
+ }
+
+ private:
+ CefMediaRouterManager* const manager_;
+ const media_router::MediaRoute route_;
+};
+
+// Used for messaging and route status notifications with Cast.
+class CefPresentationConnection : public blink::mojom::PresentationConnection {
+ public:
+ explicit CefPresentationConnection(
+ CefMediaRouterManager* manager,
+ const media_router::MediaRoute& route,
+ media_router::mojom::RoutePresentationConnectionPtr connections)
+ : manager_(manager),
+ route_(route),
+ connection_receiver_(this, std::move(connections->connection_receiver)),
+ connection_remote_(std::move(connections->connection_remote)) {}
+
+ CefPresentationConnection(const CefPresentationConnection&) = delete;
+ CefPresentationConnection& operator=(const CefPresentationConnection&) =
+ delete;
+
+ void OnMessage(
+ blink::mojom::PresentationConnectionMessagePtr message) override {
+ CefMediaRouterManager::MediaMessageVector messages;
+ if (message->is_message()) {
+ messages.push_back(media_router::message_util::RouteMessageFromString(
+ message->get_message()));
+ } else if (message->is_data()) {
+ messages.push_back(media_router::message_util::RouteMessageFromData(
+ message->get_data()));
+ }
+ if (!messages.empty()) {
+ manager_->OnMessagesReceived(route_, messages);
+ }
+ }
+
+ void DidChangeState(
+ blink::mojom::PresentationConnectionState state) override {
+ // May result in |this| being deleted, so post async and allow the call
+ // stack to unwind.
+ CEF_POST_TASK(
+ CEF_UIT,
+ base::BindOnce(&CefMediaRouterManager::OnRouteStateChange,
+ manager_->weak_ptr_factory_.GetWeakPtr(), route_,
+ content::PresentationConnectionStateChangeInfo(state)));
+ }
+
+ void DidClose(
+ blink::mojom::PresentationConnectionCloseReason reason) override {
+ DidChangeState(blink::mojom::PresentationConnectionState::CLOSED);
+ }
+
+ void SendRouteMessage(const std::string& message) {
+ connection_remote_->OnMessage(
+ blink::mojom::PresentationConnectionMessage::NewMessage(message));
+ }
+
+ private:
+ CefMediaRouterManager* const manager_;
+ const media_router::MediaRoute route_;
+
+ // Used to receive messages from the MRP.
+ mojo::Receiver<blink::mojom::PresentationConnection> connection_receiver_;
+
+ // Used to send messages to the MRP.
+ mojo::Remote<blink::mojom::PresentationConnection> connection_remote_;
+};
+
+CefMediaRouterManager::CefMediaRouterManager(
+ content::BrowserContext* browser_context)
+ : browser_context_(browser_context),
+ query_result_manager_(GetMediaRouter()),
+ weak_ptr_factory_(this) {
+ // Perform initialization.
+ GetMediaRouter()->OnUserGesture();
+
+ query_result_manager_.AddObserver(this);
+
+ // A non-empty presentation URL to required for discovery of Cast devices.
+ query_result_manager_.SetSourcesForCastMode(
+ media_router::MediaCastMode::PRESENTATION,
+ {media_router::MediaSource::ForPresentationUrl(
+ GURL(kDefaultPresentationUrl))},
+ url::Origin());
+
+ routes_observer_ = std::make_unique<CefMediaRoutesObserver>(this);
+}
+
+CefMediaRouterManager::~CefMediaRouterManager() {
+ CEF_REQUIRE_UIT();
+ for (auto& observer : observers_) {
+ observers_.RemoveObserver(&observer);
+ observer.OnMediaRouterDestroyed();
+ }
+
+ query_result_manager_.RemoveObserver(this);
+}
+
+void CefMediaRouterManager::AddObserver(Observer* observer) {
+ CEF_REQUIRE_UIT();
+ observers_.AddObserver(observer);
+}
+
+void CefMediaRouterManager::RemoveObserver(Observer* observer) {
+ CEF_REQUIRE_UIT();
+ observers_.RemoveObserver(observer);
+}
+
+void CefMediaRouterManager::NotifyCurrentSinks() {
+ CEF_REQUIRE_UIT();
+ for (auto& observer : observers_) {
+ observer.OnMediaSinks(sinks_);
+ }
+}
+
+void CefMediaRouterManager::NotifyCurrentRoutes() {
+ CEF_REQUIRE_UIT();
+ for (auto& observer : observers_) {
+ observer.OnMediaRoutes(routes_);
+ }
+}
+
+void CefMediaRouterManager::CreateRoute(
+ const media_router::MediaSource::Id& source_id,
+ const media_router::MediaSink::Id& sink_id,
+ const url::Origin& origin,
+ CreateRouteResultCallback callback) {
+ GetMediaRouter()->CreateRoute(
+ source_id, sink_id, origin, nullptr /* web_contents */,
+ base::BindOnce(&CefMediaRouterManager::OnCreateRoute,
+ weak_ptr_factory_.GetWeakPtr(), std::move(callback)),
+ base::Milliseconds(kTimeoutMs), false /* incognito */);
+}
+
+void CefMediaRouterManager::SendRouteMessage(
+ const media_router::MediaRoute::Id& route_id,
+ const std::string& message) {
+ // Must use PresentationConnection to send messages if it exists.
+ auto state = GetRouteState(route_id);
+ if (state && state->presentation_connection_) {
+ state->presentation_connection_->SendRouteMessage(message);
+ return;
+ }
+
+ GetMediaRouter()->SendRouteMessage(route_id, message);
+}
+
+void CefMediaRouterManager::TerminateRoute(
+ const media_router::MediaRoute::Id& route_id) {
+ GetMediaRouter()->TerminateRoute(route_id);
+}
+
+void CefMediaRouterManager::OnSinksUpdated(const MediaSinkVector& sinks) {
+ sinks_ = sinks;
+ NotifyCurrentSinks();
+}
+
+media_router::MediaRouter* CefMediaRouterManager::GetMediaRouter() const {
+ CEF_REQUIRE_UIT();
+ return media_router::MediaRouterFactory::GetApiForBrowserContext(
+ browser_context_);
+}
+
+void CefMediaRouterManager::OnCreateRoute(
+ CreateRouteResultCallback callback,
+ media_router::mojom::RoutePresentationConnectionPtr connection,
+ const media_router::RouteRequestResult& result) {
+ CEF_REQUIRE_UIT();
+ if (result.route()) {
+ CreateRouteState(*result.route(), std::move(connection));
+ }
+
+ std::move(callback).Run(result);
+}
+
+void CefMediaRouterManager::OnRouteStateChange(
+ const media_router::MediaRoute& route,
+ const content::PresentationConnectionStateChangeInfo& info) {
+ CEF_REQUIRE_UIT();
+ if (info.state == blink::mojom::PresentationConnectionState::CLOSED ||
+ info.state == blink::mojom::PresentationConnectionState::TERMINATED) {
+ RemoveRouteState(route.media_route_id());
+ }
+
+ for (auto& observer : observers_) {
+ observer.OnMediaRouteStateChange(route, info);
+ }
+}
+
+void CefMediaRouterManager::OnMessagesReceived(
+ const media_router::MediaRoute& route,
+ const MediaMessageVector& messages) {
+ CEF_REQUIRE_UIT();
+ for (auto& observer : observers_) {
+ observer.OnMediaRouteMessages(route, messages);
+ }
+}
+
+void CefMediaRouterManager::CreateRouteState(
+ const media_router::MediaRoute& route,
+ media_router::mojom::RoutePresentationConnectionPtr connection) {
+ const auto route_id = route.media_route_id();
+ auto state = std::make_unique<RouteState>();
+
+ if (!connection.is_null()) {
+ // PresentationConnection must be used for messaging and status
+ // notifications if it exists.
+ state->presentation_connection_ =
+ std::make_unique<CefPresentationConnection>(this, route,
+ std::move(connection));
+ } else {
+ // Fallback if PresentationConnection is not supported.
+ state->message_observer_ =
+ std::make_unique<CefPresentationConnectionMessageObserver>(this, route);
+ state->state_subscription_ =
+ GetMediaRouter()->AddPresentationConnectionStateChangedCallback(
+ route_id,
+ base::BindRepeating(&CefMediaRouterManager::OnRouteStateChange,
+ weak_ptr_factory_.GetWeakPtr(), route));
+ }
+
+ route_state_map_.insert(std::make_pair(route_id, std::move(state)));
+}
+
+CefMediaRouterManager::RouteState* CefMediaRouterManager::GetRouteState(
+ const media_router::MediaRoute::Id& route_id) {
+ const auto it = route_state_map_.find(route_id);
+ if (it != route_state_map_.end()) {
+ return it->second.get();
+ }
+ return nullptr;
+}
+
+void CefMediaRouterManager::RemoveRouteState(
+ const media_router::MediaRoute::Id& route_id) {
+ auto it = route_state_map_.find(route_id);
+ if (it != route_state_map_.end()) {
+ route_state_map_.erase(it);
+ }
+}
diff --git a/libcef/browser/media_router/media_router_manager.h b/libcef/browser/media_router/media_router_manager.h
new file mode 100644
index 00000000..10f831d6
--- /dev/null
+++ b/libcef/browser/media_router/media_router_manager.h
@@ -0,0 +1,128 @@
+// Copyright (c) 2020 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_MEDIA_ROUTER_MEDIA_ROUTER_MANAGER_H_
+#define CEF_LIBCEF_BROWSER_MEDIA_ROUTER_MEDIA_ROUTER_MANAGER_H_
+#pragma once
+
+#include "include/cef_media_router.h"
+
+#include "base/memory/weak_ptr.h"
+#include "base/observer_list.h"
+#include "chrome/browser/ui/media_router/query_result_manager.h"
+#include "components/media_router/browser/media_router.h"
+#include "components/media_router/common/mojom/media_router.mojom.h"
+
+namespace content {
+class BrowserContext;
+}
+
+class CefMediaRoutesObserver;
+class CefPresentationConnection;
+class CefPresentationConnectionMessageObserver;
+
+// Manages CEF usage of MediaRouter. Owned by CefBrowserContext and only
+// accessed on the UI thread.
+class CefMediaRouterManager
+ : public media_router::MediaSinkWithCastModesObserver {
+ public:
+ using MediaRouteVector = std::vector<media_router::MediaRoute>;
+ using MediaSinkVector = std::vector<media_router::MediaSinkWithCastModes>;
+ using MediaMessageVector = std::vector<media_router::mojom::RouteMessagePtr>;
+
+ class Observer : public base::CheckedObserver {
+ public:
+ virtual void OnMediaRouterDestroyed() = 0;
+
+ virtual void OnMediaSinks(const MediaSinkVector& sinks) = 0;
+ virtual void OnMediaRoutes(const MediaRouteVector& routes) = 0;
+
+ virtual void OnMediaRouteMessages(const media_router::MediaRoute& route,
+ const MediaMessageVector& messages) = 0;
+ virtual void OnMediaRouteStateChange(
+ const media_router::MediaRoute& route,
+ const content::PresentationConnectionStateChangeInfo& info) = 0;
+
+ protected:
+ ~Observer() override {}
+ };
+
+ explicit CefMediaRouterManager(content::BrowserContext* browser_context);
+
+ CefMediaRouterManager(const CefMediaRouterManager&) = delete;
+ CefMediaRouterManager& operator=(const CefMediaRouterManager&) = delete;
+
+ ~CefMediaRouterManager() override;
+
+ // |observer| must outlive this object or be removed.
+ void AddObserver(Observer* observer);
+ void RemoveObserver(Observer* observer);
+
+ void NotifyCurrentSinks();
+ void NotifyCurrentRoutes();
+
+ using CreateRouteResultCallback =
+ base::OnceCallback<void(const media_router::RouteRequestResult& result)>;
+
+ void CreateRoute(const media_router::MediaSource::Id& source_id,
+ const media_router::MediaSink::Id& sink_id,
+ const url::Origin& origin,
+ CreateRouteResultCallback callback);
+
+ void SendRouteMessage(const media_router::MediaRoute::Id& route_id,
+ const std::string& message);
+ void TerminateRoute(const media_router::MediaRoute::Id& route_id);
+
+ // MediaSinkWithCastModesObserver methods.
+ void OnSinksUpdated(const MediaSinkVector& sinks) override;
+
+ private:
+ friend class CefMediaRoutesObserver;
+ friend class CefPresentationConnection;
+ friend class CefPresentationConnectionMessageObserver;
+
+ // Do not keep a reference to the object returned by this method.
+ media_router::MediaRouter* GetMediaRouter() const;
+
+ void OnCreateRoute(
+ CreateRouteResultCallback callback,
+ media_router::mojom::RoutePresentationConnectionPtr connection,
+ const media_router::RouteRequestResult& result);
+ void OnRouteStateChange(
+ const media_router::MediaRoute& route,
+ const content::PresentationConnectionStateChangeInfo& info);
+ void OnMessagesReceived(const media_router::MediaRoute& route,
+ const MediaMessageVector& messages);
+
+ struct RouteState {
+ std::unique_ptr<CefPresentationConnection> presentation_connection_;
+
+ // Used if there is no RoutePresentationConnectionPtr.
+ std::unique_ptr<CefPresentationConnectionMessageObserver> message_observer_;
+ base::CallbackListSubscription state_subscription_;
+ };
+ void CreateRouteState(
+ const media_router::MediaRoute& route,
+ media_router::mojom::RoutePresentationConnectionPtr connection);
+ RouteState* GetRouteState(const media_router::MediaRoute::Id& route_id);
+ void RemoveRouteState(const media_router::MediaRoute::Id& route_id);
+
+ content::BrowserContext* const browser_context_;
+
+ base::ObserverList<Observer> observers_;
+
+ media_router::QueryResultManager query_result_manager_;
+ std::unique_ptr<CefMediaRoutesObserver> routes_observer_;
+
+ MediaRouteVector routes_;
+ MediaSinkVector sinks_;
+
+ using RouteStateMap =
+ std::map<media_router::MediaRoute::Id, std::unique_ptr<RouteState>>;
+ RouteStateMap route_state_map_;
+
+ base::WeakPtrFactory<CefMediaRouterManager> weak_ptr_factory_;
+};
+
+#endif // CEF_LIBCEF_BROWSER_MEDIA_ROUTER_MEDIA_ROUTER_MANAGER_H_
diff --git a/libcef/browser/media_router/media_sink_impl.cc b/libcef/browser/media_router/media_sink_impl.cc
new file mode 100644
index 00000000..b66ad20e
--- /dev/null
+++ b/libcef/browser/media_router/media_sink_impl.cc
@@ -0,0 +1,139 @@
+// Copyright (c) 2020 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "libcef/browser/media_router/media_sink_impl.h"
+
+#include "libcef/browser/thread_util.h"
+
+#include "base/strings/string_number_conversions.h"
+#include "chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl.h"
+#include "chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.h"
+#include "chrome/browser/media/router/providers/cast/dual_media_sink_service.h"
+#include "components/media_router/common/discovery/media_sink_internal.h"
+#include "components/media_router/common/discovery/media_sink_service_base.h"
+
+namespace {
+
+using SinkServiceVector = std::vector<media_router::MediaSinkServiceBase*>;
+
+SinkServiceVector GetSinkServices() {
+ CEF_REQUIRE_UIT();
+ auto sink_service = media_router::DualMediaSinkService::GetInstance();
+ return {sink_service->GetCastMediaSinkServiceImpl(),
+ sink_service->GetDialMediaSinkServiceImpl()};
+}
+
+void GetSinkInternalAndContinue(
+ SinkServiceVector services,
+ const media_router::MediaSink::Id& sink_id,
+ CefRefPtr<CefMediaSinkDeviceInfoCallback> callback) {
+ CEF_REQUIRE_IOT();
+
+ CefMediaSinkDeviceInfo device_info;
+ const media_router::MediaSinkInternal* sink_internal = nullptr;
+
+ for (auto service : services) {
+ sink_internal = service->GetSinkById(sink_id);
+ if (sink_internal) {
+ break;
+ }
+ }
+
+ if (sink_internal) {
+ if (sink_internal->is_cast_sink()) {
+ const auto& cast_data = sink_internal->cast_data();
+ CefString(&device_info.ip_address) =
+ cast_data.ip_endpoint.ToStringWithoutPort();
+ device_info.port = cast_data.ip_endpoint.port();
+ CefString(&device_info.model_name) = cast_data.model_name;
+ } else if (sink_internal->is_dial_sink()) {
+ const auto& dial_data = sink_internal->dial_data();
+ CefString(&device_info.ip_address) = dial_data.ip_address.ToString();
+ if (dial_data.app_url.is_valid() && dial_data.app_url.has_port()) {
+ base::StringToInt(dial_data.app_url.port_piece(), &device_info.port);
+ }
+ CefString(&device_info.model_name) = dial_data.model_name;
+ }
+ }
+
+ // Execute the callback on the UI thread.
+ CEF_POST_TASK(
+ CEF_UIT,
+ base::BindOnce(&CefMediaSinkDeviceInfoCallback::OnMediaSinkDeviceInfo,
+ callback, device_info));
+}
+
+void GetDeviceInfo(const media_router::MediaSink::Id& sink_id,
+ CefRefPtr<CefMediaSinkDeviceInfoCallback> callback) {
+ auto next_step = base::BindOnce(
+ [](const media_router::MediaSink::Id& sink_id,
+ CefRefPtr<CefMediaSinkDeviceInfoCallback> callback) {
+ CEF_POST_TASK(CEF_IOT,
+ base::BindOnce(GetSinkInternalAndContinue,
+ GetSinkServices(), sink_id, callback));
+ },
+ sink_id, callback);
+
+ if (CEF_CURRENTLY_ON(CEF_UIT)) {
+ std::move(next_step).Run();
+ } else {
+ CEF_POST_TASK(CEF_UIT, std::move(next_step));
+ }
+}
+
+} // namespace
+
+CefMediaSinkImpl::CefMediaSinkImpl(const media_router::MediaSink& sink)
+ : sink_(sink) {}
+
+CefMediaSinkImpl::CefMediaSinkImpl(
+ const media_router::MediaSink::Id& sink_id,
+ const std::string& sink_name,
+ media_router::mojom::MediaRouteProviderId provider_id)
+ : sink_(sink_id,
+ sink_name,
+ media_router::SinkIconType::GENERIC,
+ provider_id) {}
+
+CefString CefMediaSinkImpl::GetId() {
+ return sink_.id();
+}
+
+CefString CefMediaSinkImpl::GetName() {
+ return sink_.name();
+}
+
+CefMediaSink::IconType CefMediaSinkImpl::GetIconType() {
+ // Verify that our enum matches Chromium's values.
+ static_assert(static_cast<int>(CEF_MSIT_TOTAL_COUNT) ==
+ static_cast<int>(media_router::SinkIconType::TOTAL_COUNT),
+ "enum mismatch");
+
+ return static_cast<CefMediaSink::IconType>(sink_.icon_type());
+}
+
+void CefMediaSinkImpl::GetDeviceInfo(
+ CefRefPtr<CefMediaSinkDeviceInfoCallback> callback) {
+ ::GetDeviceInfo(sink_.id(), callback);
+}
+
+bool CefMediaSinkImpl::IsCastSink() {
+ return sink_.provider_id() == media_router::mojom::MediaRouteProviderId::CAST;
+}
+
+bool CefMediaSinkImpl::IsDialSink() {
+ return sink_.provider_id() == media_router::mojom::MediaRouteProviderId::DIAL;
+}
+
+bool CefMediaSinkImpl::IsCompatibleWith(CefRefPtr<CefMediaSource> source) {
+ if (source) {
+ if (IsCastSink()) {
+ return source->IsCastSource();
+ }
+ if (IsDialSink()) {
+ return source->IsDialSource();
+ }
+ }
+ return false;
+}
diff --git a/libcef/browser/media_router/media_sink_impl.h b/libcef/browser/media_router/media_sink_impl.h
new file mode 100644
index 00000000..20dbdefd
--- /dev/null
+++ b/libcef/browser/media_router/media_sink_impl.h
@@ -0,0 +1,43 @@
+// Copyright (c) 2020 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_MEDIA_ROUTER_MEDIA_SINK_IMPL_H_
+#define CEF_LIBCEF_BROWSER_MEDIA_ROUTER_MEDIA_SINK_IMPL_H_
+#pragma once
+
+#include "include/cef_media_router.h"
+
+#include "components/media_router/common/media_sink.h"
+
+// Implementation of the CefMediaSink interface. May be created on any thread.
+class CefMediaSinkImpl : public CefMediaSink {
+ public:
+ explicit CefMediaSinkImpl(const media_router::MediaSink& sink);
+ CefMediaSinkImpl(const media_router::MediaSink::Id& sink_id,
+ const std::string& sink_name,
+ media_router::mojom::MediaRouteProviderId provider_id);
+
+ CefMediaSinkImpl(const CefMediaSinkImpl&) = delete;
+ CefMediaSinkImpl& operator=(const CefMediaSinkImpl&) = delete;
+
+ // CefMediaSink methods.
+ CefString GetId() override;
+ CefString GetName() override;
+ IconType GetIconType() override;
+ void GetDeviceInfo(
+ CefRefPtr<CefMediaSinkDeviceInfoCallback> callback) override;
+ bool IsCastSink() override;
+ bool IsDialSink() override;
+ bool IsCompatibleWith(CefRefPtr<CefMediaSource> source) override;
+
+ const media_router::MediaSink& sink() const { return sink_; }
+
+ private:
+ // Read-only after creation.
+ const media_router::MediaSink sink_;
+
+ IMPLEMENT_REFCOUNTING(CefMediaSinkImpl);
+};
+
+#endif // CEF_LIBCEF_BROWSER_MEDIA_ROUTER_MEDIA_SINK_IMPL_H_
diff --git a/libcef/browser/media_router/media_source_impl.cc b/libcef/browser/media_router/media_source_impl.cc
new file mode 100644
index 00000000..e8e18a41
--- /dev/null
+++ b/libcef/browser/media_router/media_source_impl.cc
@@ -0,0 +1,24 @@
+// Copyright (c) 2020 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "libcef/browser/media_router/media_source_impl.h"
+
+CefMediaSourceImpl::CefMediaSourceImpl(
+ const media_router::MediaSource::Id& source_id)
+ : source_(source_id) {}
+
+CefMediaSourceImpl::CefMediaSourceImpl(const GURL& presentation_url)
+ : source_(presentation_url) {}
+
+CefString CefMediaSourceImpl::GetId() {
+ return source_.id();
+}
+
+bool CefMediaSourceImpl::IsCastSource() {
+ return !IsDialSource();
+}
+
+bool CefMediaSourceImpl::IsDialSource() {
+ return source_.IsDialSource();
+}
diff --git a/libcef/browser/media_router/media_source_impl.h b/libcef/browser/media_router/media_source_impl.h
new file mode 100644
index 00000000..0c9664d0
--- /dev/null
+++ b/libcef/browser/media_router/media_source_impl.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2020 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_MEDIA_ROUTER_MEDIA_SOURCE_IMPL_H_
+#define CEF_LIBCEF_BROWSER_MEDIA_ROUTER_MEDIA_SOURCE_IMPL_H_
+#pragma once
+
+#include "include/cef_media_router.h"
+
+#include "components/media_router/common/media_source.h"
+
+// Implementation of the CefMediaSource interface. May be created on any thread.
+class CefMediaSourceImpl : public CefMediaSource {
+ public:
+ explicit CefMediaSourceImpl(const media_router::MediaSource::Id& source_id);
+ explicit CefMediaSourceImpl(const GURL& presentation_url);
+
+ CefMediaSourceImpl(const CefMediaSourceImpl&) = delete;
+ CefMediaSourceImpl& operator=(const CefMediaSourceImpl&) = delete;
+
+ // CefMediaSource methods.
+ CefString GetId() override;
+ bool IsCastSource() override;
+ bool IsDialSource() override;
+
+ const media_router::MediaSource& source() const { return source_; }
+
+ private:
+ // Read-only after creation.
+ const media_router::MediaSource source_;
+
+ IMPLEMENT_REFCOUNTING(CefMediaSourceImpl);
+};
+
+#endif // CEF_LIBCEF_BROWSER_MEDIA_ROUTER_MEDIA_SOURCE_IMPL_H_
diff --git a/libcef/browser/media_stream_registrar.cc b/libcef/browser/media_stream_registrar.cc
new file mode 100644
index 00000000..bdf3dd92
--- /dev/null
+++ b/libcef/browser/media_stream_registrar.cc
@@ -0,0 +1,110 @@
+// Copyright 2022 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/media_stream_registrar.h"
+
+#include "libcef/browser/browser_host_base.h"
+#include "libcef/browser/thread_util.h"
+
+class CefMediaStreamUI : public content::MediaStreamUI {
+ public:
+ CefMediaStreamUI(base::WeakPtr<CefMediaStreamRegistrar> registrar,
+ bool has_video,
+ bool has_audio)
+ : registrar_(registrar), has_video_(has_video), has_audio_(has_audio) {}
+
+ ~CefMediaStreamUI() override {
+ if (registrar_) {
+ registrar_->UnregisterMediaStream(label_);
+ }
+ }
+
+ CefMediaStreamUI(const CefMediaStreamUI&) = delete;
+ CefMediaStreamUI& operator=(const CefMediaStreamUI&) = delete;
+
+ gfx::NativeViewId OnStarted(
+ base::RepeatingClosure stop,
+ SourceCallback source,
+ const std::string& label,
+ std::vector<content::DesktopMediaID> screen_capture_ids,
+ StateChangeCallback state_change) override {
+ if (registrar_) {
+ label_ = label;
+ registrar_->RegisterMediaStream(label, has_video_, has_audio_);
+ }
+ return 0;
+ }
+
+ void OnDeviceStoppedForSourceChange(
+ const std::string& label,
+ const content::DesktopMediaID& old_media_id,
+ const content::DesktopMediaID& new_media_id) override {}
+
+ void OnDeviceStopped(const std::string& label,
+ const content::DesktopMediaID& media_id) override {}
+
+ private:
+ base::WeakPtr<CefMediaStreamRegistrar> registrar_;
+ const bool has_video_;
+ const bool has_audio_;
+ std::string label_;
+};
+
+CefMediaStreamRegistrar::CefMediaStreamRegistrar(CefBrowserHostBase* browser)
+ : browser_(browser) {}
+
+std::unique_ptr<content::MediaStreamUI>
+CefMediaStreamRegistrar::MaybeCreateMediaStreamUI(bool has_video,
+ bool has_audio) {
+ // Only create the object if the callback will be executed.
+ if (auto client = browser_->GetClient()) {
+ if (auto handler = client->GetDisplayHandler()) {
+ return std::make_unique<CefMediaStreamUI>(weak_ptr_factory_.GetWeakPtr(),
+ has_video, has_audio);
+ }
+ }
+ return nullptr;
+}
+
+void CefMediaStreamRegistrar::RegisterMediaStream(const std::string& label,
+ bool video,
+ bool audio) {
+ CEF_REQUIRE_UIT();
+ MediaStreamInfo info = {video, audio};
+ registered_streams_.insert(std::make_pair(label, info));
+ NotifyMediaStreamChange();
+}
+
+void CefMediaStreamRegistrar::UnregisterMediaStream(const std::string& label) {
+ CEF_REQUIRE_UIT();
+ registered_streams_.erase(label);
+ NotifyMediaStreamChange();
+}
+
+void CefMediaStreamRegistrar::NotifyMediaStreamChange() {
+ bool video = false;
+ bool audio = false;
+ for (const auto& media_stream : registered_streams_) {
+ const auto& info = media_stream.second;
+ if (!video) {
+ video = info.video;
+ }
+ if (!audio) {
+ audio = info.audio;
+ }
+ }
+
+ if (audio == last_notified_info_.audio &&
+ video == last_notified_info_.video) {
+ return;
+ }
+
+ last_notified_info_ = {video, audio};
+
+ if (auto client = browser_->GetClient()) {
+ if (auto handler = client->GetDisplayHandler()) {
+ handler->OnMediaAccessChange(browser_, video, audio);
+ }
+ }
+}
diff --git a/libcef/browser/media_stream_registrar.h b/libcef/browser/media_stream_registrar.h
new file mode 100644
index 00000000..c6fc3754
--- /dev/null
+++ b/libcef/browser/media_stream_registrar.h
@@ -0,0 +1,56 @@
+// Copyright 2022 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_MEDIA_STREAM_REGISTRAR_H_
+#define CEF_LIBCEF_BROWSER_MEDIA_STREAM_REGISTRAR_H_
+#pragma once
+
+#include <map>
+#include <memory>
+#include <string>
+
+#include "base/memory/weak_ptr.h"
+#include "content/public/browser/media_stream_request.h"
+
+class CefBrowserHostBase;
+class CefMediaStreamUI;
+
+class CefMediaStreamRegistrar {
+ public:
+ explicit CefMediaStreamRegistrar(CefBrowserHostBase* browser);
+
+ CefMediaStreamRegistrar(const CefMediaStreamRegistrar&) = delete;
+ CefMediaStreamRegistrar& operator=(const CefMediaStreamRegistrar&) = delete;
+
+ std::unique_ptr<content::MediaStreamUI> MaybeCreateMediaStreamUI(
+ bool has_video,
+ bool has_audio);
+
+ private:
+ friend class CefMediaStreamUI;
+
+ // Called from CefMediaStreamUI.
+ void RegisterMediaStream(const std::string& label, bool video, bool audio);
+ void UnregisterMediaStream(const std::string& label);
+
+ void NotifyMediaStreamChange();
+
+ // Guaranteed to outlive this object.
+ CefBrowserHostBase* const browser_;
+
+ struct MediaStreamInfo {
+ bool video;
+ bool audio;
+ };
+
+ // Current in use media streams.
+ std::map<std::string, MediaStreamInfo> registered_streams_;
+
+ // Last notified media stream info.
+ MediaStreamInfo last_notified_info_{};
+
+ base::WeakPtrFactory<CefMediaStreamRegistrar> weak_ptr_factory_{this};
+};
+
+#endif // CEF_LIBCEF_BROWSER_MEDIA_STREAM_REGISTRAR_H_
diff --git a/libcef/browser/menu_manager.cc b/libcef/browser/menu_manager.cc
new file mode 100644
index 00000000..ccc4fc02
--- /dev/null
+++ b/libcef/browser/menu_manager.cc
@@ -0,0 +1,507 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#include "libcef/browser/menu_manager.h"
+
+#include <tuple>
+#include <utility>
+
+#include "libcef/browser/alloy/alloy_browser_host_impl.h"
+#include "libcef/browser/context_menu_params_impl.h"
+#include "libcef/browser/menu_runner.h"
+#include "libcef/browser/thread_util.h"
+#include "libcef/common/app_manager.h"
+
+#include "base/logging.h"
+#include "cef/grit/cef_strings.h"
+#include "chrome/grit/generated_resources.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/render_widget_host_view.h"
+#include "third_party/blink/public/mojom/context_menu/context_menu.mojom.h"
+
+namespace {
+
+CefString GetLabel(int message_id) {
+ std::u16string label =
+ CefAppManager::Get()->GetContentClient()->GetLocalizedString(message_id);
+ DCHECK(!label.empty());
+ return label;
+}
+
+const int kInvalidCommandId = -1;
+const cef_event_flags_t kEmptyEventFlags = static_cast<cef_event_flags_t>(0);
+
+class CefRunContextMenuCallbackImpl : public CefRunContextMenuCallback {
+ public:
+ using Callback = base::OnceCallback<void(int, cef_event_flags_t)>;
+
+ explicit CefRunContextMenuCallbackImpl(Callback callback)
+ : callback_(std::move(callback)) {}
+
+ CefRunContextMenuCallbackImpl(const CefRunContextMenuCallbackImpl&) = delete;
+ CefRunContextMenuCallbackImpl& operator=(
+ const CefRunContextMenuCallbackImpl&) = delete;
+
+ ~CefRunContextMenuCallbackImpl() {
+ if (!callback_.is_null()) {
+ // The callback is still pending. Cancel it now.
+ if (CEF_CURRENTLY_ON_UIT()) {
+ RunNow(std::move(callback_), kInvalidCommandId, kEmptyEventFlags);
+ } else {
+ CEF_POST_TASK(CEF_UIT,
+ base::BindOnce(&CefRunContextMenuCallbackImpl::RunNow,
+ std::move(callback_), kInvalidCommandId,
+ kEmptyEventFlags));
+ }
+ }
+ }
+
+ void Continue(int command_id, cef_event_flags_t event_flags) override {
+ if (CEF_CURRENTLY_ON_UIT()) {
+ if (!callback_.is_null()) {
+ RunNow(std::move(callback_), command_id, event_flags);
+ callback_.Reset();
+ }
+ } else {
+ CEF_POST_TASK(CEF_UIT,
+ base::BindOnce(&CefRunContextMenuCallbackImpl::Continue,
+ this, command_id, event_flags));
+ }
+ }
+
+ void Cancel() override { Continue(kInvalidCommandId, kEmptyEventFlags); }
+
+ void Disconnect() { callback_.Reset(); }
+
+ private:
+ static void RunNow(Callback callback,
+ int command_id,
+ cef_event_flags_t event_flags) {
+ CEF_REQUIRE_UIT();
+ std::move(callback).Run(command_id, event_flags);
+ }
+
+ Callback callback_;
+
+ IMPLEMENT_REFCOUNTING(CefRunContextMenuCallbackImpl);
+};
+
+} // namespace
+
+CefMenuManager::CefMenuManager(AlloyBrowserHostImpl* browser,
+ std::unique_ptr<CefMenuRunner> runner)
+ : content::WebContentsObserver(browser->web_contents()),
+ browser_(browser),
+ runner_(std::move(runner)),
+ custom_menu_callback_(nullptr),
+ weak_ptr_factory_(this) {
+ DCHECK(web_contents());
+ model_ = new CefMenuModelImpl(this, nullptr, false);
+}
+
+CefMenuManager::~CefMenuManager() {
+ // The model may outlive the delegate if the context menu is visible when the
+ // application is closed.
+ model_->set_delegate(nullptr);
+}
+
+void CefMenuManager::Destroy() {
+ CancelContextMenu();
+ if (runner_) {
+ runner_.reset(nullptr);
+ }
+}
+
+bool CefMenuManager::IsShowingContextMenu() {
+ if (!web_contents()) {
+ return false;
+ }
+ return web_contents()->IsShowingContextMenu();
+}
+
+bool CefMenuManager::CreateContextMenu(
+ const content::ContextMenuParams& params) {
+ // The renderer may send the "show context menu" message multiple times, one
+ // for each right click mouse event it receives. Normally, this doesn't happen
+ // because mouse events are not forwarded once the context menu is showing.
+ // However, there's a race - the context menu may not yet be showing when
+ // the second mouse event arrives. In this case, |HandleContextMenu()| will
+ // get called multiple times - if so, don't create another context menu.
+ // TODO(asvitkine): Fix the renderer so that it doesn't do this.
+ if (IsShowingContextMenu()) {
+ return true;
+ }
+
+ params_ = params;
+ model_->Clear();
+
+ // Create the default menu model.
+ CreateDefaultModel();
+
+ bool custom_menu = false;
+ DCHECK(!custom_menu_callback_);
+
+ // Give the client a chance to modify the model.
+ CefRefPtr<CefClient> client = browser_->GetClient();
+ if (client.get()) {
+ CefRefPtr<CefContextMenuHandler> handler = client->GetContextMenuHandler();
+ if (handler.get()) {
+ CefRefPtr<CefContextMenuParamsImpl> paramsPtr(
+ new CefContextMenuParamsImpl(&params_));
+ CefRefPtr<CefFrame> frame = browser_->GetFocusedFrame();
+
+ handler->OnBeforeContextMenu(browser_, frame, paramsPtr.get(),
+ model_.get());
+
+ MenuWillShow(model_);
+
+ if (model_->GetCount() > 0) {
+ CefRefPtr<CefRunContextMenuCallbackImpl> callbackImpl(
+ new CefRunContextMenuCallbackImpl(
+ base::BindOnce(&CefMenuManager::ExecuteCommandCallback,
+ weak_ptr_factory_.GetWeakPtr())));
+
+ // This reference will be cleared when the callback is executed or
+ // the callback object is deleted.
+ custom_menu_callback_ = callbackImpl.get();
+
+ if (handler->RunContextMenu(browser_, frame, paramsPtr.get(),
+ model_.get(), callbackImpl.get())) {
+ custom_menu = true;
+ } else {
+ // Callback should not be executed if the handler returns false.
+ DCHECK(custom_menu_callback_);
+ custom_menu_callback_ = nullptr;
+ callbackImpl->Disconnect();
+ }
+ }
+
+ // Do not keep references to the parameters in the callback.
+ std::ignore = paramsPtr->Detach(nullptr);
+ DCHECK(paramsPtr->HasOneRef());
+ DCHECK(model_->VerifyRefCount());
+
+ // Menu is empty so notify the client and return.
+ if (model_->GetCount() == 0 && !custom_menu) {
+ MenuClosed(model_);
+ return true;
+ }
+ }
+ }
+
+ if (custom_menu) {
+ return true;
+ }
+
+ if (!runner_ || !runner_->RunContextMenu(browser_, model_.get(), params_)) {
+ LOG(ERROR) << "Default context menu implementation is not available; "
+ "canceling the menu";
+ return false;
+ }
+ return true;
+}
+
+void CefMenuManager::CancelContextMenu() {
+ if (IsShowingContextMenu()) {
+ if (custom_menu_callback_) {
+ custom_menu_callback_->Cancel();
+ } else if (runner_) {
+ runner_->CancelContextMenu();
+ }
+ }
+}
+
+void CefMenuManager::ExecuteCommand(CefRefPtr<CefMenuModelImpl> source,
+ int command_id,
+ cef_event_flags_t event_flags) {
+ // Give the client a chance to handle the command.
+ CefRefPtr<CefClient> client = browser_->GetClient();
+ if (client.get()) {
+ CefRefPtr<CefContextMenuHandler> handler = client->GetContextMenuHandler();
+ if (handler.get()) {
+ CefRefPtr<CefContextMenuParamsImpl> paramsPtr(
+ new CefContextMenuParamsImpl(&params_));
+
+ bool handled = handler->OnContextMenuCommand(
+ browser_, browser_->GetFocusedFrame(), paramsPtr.get(), command_id,
+ event_flags);
+
+ // Do not keep references to the parameters in the callback.
+ std::ignore = paramsPtr->Detach(nullptr);
+ DCHECK(paramsPtr->HasOneRef());
+
+ if (handled) {
+ return;
+ }
+ }
+ }
+
+ // Execute the default command handling.
+ ExecuteDefaultCommand(command_id);
+}
+
+void CefMenuManager::MenuWillShow(CefRefPtr<CefMenuModelImpl> source) {
+ // May be called for sub-menus as well.
+ if (source.get() != model_.get()) {
+ return;
+ }
+
+ if (!web_contents()) {
+ return;
+ }
+
+ // May be called multiple times.
+ if (IsShowingContextMenu()) {
+ return;
+ }
+
+ // Notify the host before showing the context menu.
+ web_contents()->SetShowingContextMenu(true);
+}
+
+void CefMenuManager::MenuClosed(CefRefPtr<CefMenuModelImpl> source) {
+ // May be called for sub-menus as well.
+ if (source.get() != model_.get()) {
+ return;
+ }
+
+ if (!web_contents()) {
+ return;
+ }
+
+ DCHECK(IsShowingContextMenu());
+
+ // Notify the client.
+ CefRefPtr<CefClient> client = browser_->GetClient();
+ if (client.get()) {
+ CefRefPtr<CefContextMenuHandler> handler = client->GetContextMenuHandler();
+ if (handler.get()) {
+ handler->OnContextMenuDismissed(browser_, browser_->GetFocusedFrame());
+ }
+ }
+
+ // Notify the host after closing the context menu.
+ web_contents()->SetShowingContextMenu(false);
+ web_contents()->NotifyContextMenuClosed(params_.link_followed);
+}
+
+bool CefMenuManager::FormatLabel(CefRefPtr<CefMenuModelImpl> source,
+ std::u16string& label) {
+ if (!runner_) {
+ return false;
+ }
+ return runner_->FormatLabel(label);
+}
+
+void CefMenuManager::ExecuteCommandCallback(int command_id,
+ cef_event_flags_t event_flags) {
+ DCHECK(IsShowingContextMenu());
+ DCHECK(custom_menu_callback_);
+ if (command_id != kInvalidCommandId) {
+ ExecuteCommand(model_, command_id, event_flags);
+ }
+ MenuClosed(model_);
+ custom_menu_callback_ = nullptr;
+}
+
+void CefMenuManager::CreateDefaultModel() {
+ if (!params_.custom_items.empty()) {
+ // Custom menu items originating from the renderer process. For example,
+ // plugin placeholder menu items.
+ for (auto& item : params_.custom_items) {
+ auto new_item = item->Clone();
+ new_item->action += MENU_ID_CUSTOM_FIRST;
+ DCHECK_LE(static_cast<int>(new_item->action), MENU_ID_CUSTOM_LAST);
+ model_->AddMenuItem(*new_item);
+ }
+ return;
+ }
+
+ if (params_.is_editable) {
+ // Editable node.
+ model_->AddItem(MENU_ID_UNDO, GetLabel(IDS_CONTENT_CONTEXT_UNDO));
+ model_->AddItem(MENU_ID_REDO, GetLabel(IDS_CONTENT_CONTEXT_REDO));
+
+ model_->AddSeparator();
+ model_->AddItem(MENU_ID_CUT, GetLabel(IDS_CONTENT_CONTEXT_CUT));
+ model_->AddItem(MENU_ID_COPY, GetLabel(IDS_CONTENT_CONTEXT_COPY));
+ model_->AddItem(MENU_ID_PASTE, GetLabel(IDS_CONTENT_CONTEXT_PASTE));
+
+ model_->AddSeparator();
+ model_->AddItem(MENU_ID_SELECT_ALL,
+ GetLabel(IDS_CONTENT_CONTEXT_SELECTALL));
+
+ if (!(params_.edit_flags & CM_EDITFLAG_CAN_UNDO)) {
+ model_->SetEnabled(MENU_ID_UNDO, false);
+ }
+ if (!(params_.edit_flags & CM_EDITFLAG_CAN_REDO)) {
+ model_->SetEnabled(MENU_ID_REDO, false);
+ }
+ if (!(params_.edit_flags & CM_EDITFLAG_CAN_CUT)) {
+ model_->SetEnabled(MENU_ID_CUT, false);
+ }
+ if (!(params_.edit_flags & CM_EDITFLAG_CAN_COPY)) {
+ model_->SetEnabled(MENU_ID_COPY, false);
+ }
+ if (!(params_.edit_flags & CM_EDITFLAG_CAN_PASTE)) {
+ model_->SetEnabled(MENU_ID_PASTE, false);
+ }
+ if (!(params_.edit_flags & CM_EDITFLAG_CAN_DELETE)) {
+ model_->SetEnabled(MENU_ID_DELETE, false);
+ }
+ if (!(params_.edit_flags & CM_EDITFLAG_CAN_SELECT_ALL)) {
+ model_->SetEnabled(MENU_ID_SELECT_ALL, false);
+ }
+
+ if (!params_.misspelled_word.empty()) {
+ // Always add a separator before the list of dictionary suggestions or
+ // "No spelling suggestions".
+ model_->AddSeparator();
+
+ if (!params_.dictionary_suggestions.empty()) {
+ for (size_t i = 0; i < params_.dictionary_suggestions.size() &&
+ MENU_ID_SPELLCHECK_SUGGESTION_0 + i <=
+ MENU_ID_SPELLCHECK_SUGGESTION_LAST;
+ ++i) {
+ model_->AddItem(MENU_ID_SPELLCHECK_SUGGESTION_0 + static_cast<int>(i),
+ params_.dictionary_suggestions[i]);
+ }
+
+ // When there are dictionary suggestions add a separator before "Add to
+ // dictionary".
+ model_->AddSeparator();
+ } else {
+ model_->AddItem(MENU_ID_NO_SPELLING_SUGGESTIONS,
+ GetLabel(IDS_CONTENT_CONTEXT_NO_SPELLING_SUGGESTIONS));
+ model_->SetEnabled(MENU_ID_NO_SPELLING_SUGGESTIONS, false);
+ }
+
+ model_->AddItem(MENU_ID_ADD_TO_DICTIONARY,
+ GetLabel(IDS_CONTENT_CONTEXT_ADD_TO_DICTIONARY));
+ }
+ } else if (!params_.selection_text.empty()) {
+ // Something is selected.
+ model_->AddItem(MENU_ID_COPY, GetLabel(IDS_CONTENT_CONTEXT_COPY));
+ } else if (!params_.page_url.is_empty() || !params_.frame_url.is_empty()) {
+ // Page or frame.
+ model_->AddItem(MENU_ID_BACK, GetLabel(IDS_CONTENT_CONTEXT_BACK));
+ model_->AddItem(MENU_ID_FORWARD, GetLabel(IDS_CONTENT_CONTEXT_FORWARD));
+
+ model_->AddSeparator();
+ model_->AddItem(MENU_ID_PRINT, GetLabel(IDS_CONTENT_CONTEXT_PRINT));
+ model_->AddItem(MENU_ID_VIEW_SOURCE,
+ GetLabel(IDS_CONTENT_CONTEXT_VIEWPAGESOURCE));
+
+ if (!browser_->CanGoBack()) {
+ model_->SetEnabled(MENU_ID_BACK, false);
+ }
+ if (!browser_->CanGoForward()) {
+ model_->SetEnabled(MENU_ID_FORWARD, false);
+ }
+ }
+}
+
+void CefMenuManager::ExecuteDefaultCommand(int command_id) {
+ if (IsCustomContextMenuCommand(command_id)) {
+ if (web_contents()) {
+ web_contents()->ExecuteCustomContextMenuCommand(
+ command_id - MENU_ID_CUSTOM_FIRST, params_.link_followed);
+ }
+ return;
+ }
+
+ // If the user chose a replacement word for a misspelling, replace it here.
+ if (command_id >= MENU_ID_SPELLCHECK_SUGGESTION_0 &&
+ command_id <= MENU_ID_SPELLCHECK_SUGGESTION_LAST) {
+ const size_t suggestion_index =
+ static_cast<size_t>(command_id) - MENU_ID_SPELLCHECK_SUGGESTION_0;
+ if (suggestion_index < params_.dictionary_suggestions.size()) {
+ browser_->ReplaceMisspelling(
+ params_.dictionary_suggestions[suggestion_index]);
+ }
+ return;
+ }
+
+ switch (command_id) {
+ // Navigation.
+ case MENU_ID_BACK:
+ browser_->GoBack();
+ break;
+ case MENU_ID_FORWARD:
+ browser_->GoForward();
+ break;
+ case MENU_ID_RELOAD:
+ browser_->Reload();
+ break;
+ case MENU_ID_RELOAD_NOCACHE:
+ browser_->ReloadIgnoreCache();
+ break;
+ case MENU_ID_STOPLOAD:
+ browser_->StopLoad();
+ break;
+
+ // Editing.
+ case MENU_ID_UNDO:
+ browser_->GetFocusedFrame()->Undo();
+ break;
+ case MENU_ID_REDO:
+ browser_->GetFocusedFrame()->Redo();
+ break;
+ case MENU_ID_CUT:
+ browser_->GetFocusedFrame()->Cut();
+ break;
+ case MENU_ID_COPY:
+ browser_->GetFocusedFrame()->Copy();
+ break;
+ case MENU_ID_PASTE:
+ browser_->GetFocusedFrame()->Paste();
+ break;
+ case MENU_ID_DELETE:
+ browser_->GetFocusedFrame()->Delete();
+ break;
+ case MENU_ID_SELECT_ALL:
+ browser_->GetFocusedFrame()->SelectAll();
+ break;
+
+ // Miscellaneous.
+ case MENU_ID_FIND:
+ // TODO(cef): Implement.
+ NOTIMPLEMENTED();
+ break;
+ case MENU_ID_PRINT:
+ browser_->Print();
+ break;
+ case MENU_ID_VIEW_SOURCE:
+ browser_->GetFocusedFrame()->ViewSource();
+ break;
+
+ // Spell checking.
+ case MENU_ID_ADD_TO_DICTIONARY:
+ browser_->GetHost()->AddWordToDictionary(params_.misspelled_word);
+ break;
+
+ default:
+ break;
+ }
+}
+
+bool CefMenuManager::IsCustomContextMenuCommand(int command_id) {
+ // Verify that the command ID is in the correct range.
+ if (command_id < MENU_ID_CUSTOM_FIRST || command_id > MENU_ID_CUSTOM_LAST) {
+ return false;
+ }
+
+ command_id -= MENU_ID_CUSTOM_FIRST;
+
+ // Verify that the specific command ID was passed from the renderer process.
+ if (!params_.custom_items.empty()) {
+ for (size_t i = 0; i < params_.custom_items.size(); ++i) {
+ if (static_cast<int>(params_.custom_items[i]->action) == command_id) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
diff --git a/libcef/browser/menu_manager.h b/libcef/browser/menu_manager.h
new file mode 100644
index 00000000..239e3b7c
--- /dev/null
+++ b/libcef/browser/menu_manager.h
@@ -0,0 +1,81 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_MENU_MANAGER_H_
+#define CEF_LIBCEF_BROWSER_MENU_MANAGER_H_
+#pragma once
+
+#include "libcef/browser/menu_model_impl.h"
+
+#include "libcef/browser/menu_runner.h"
+
+#include "base/memory/weak_ptr.h"
+#include "content/public/browser/context_menu_params.h"
+#include "content/public/browser/web_contents_observer.h"
+
+namespace content {
+class RenderFrameHost;
+class WebContents;
+} // namespace content
+
+class AlloyBrowserHostImpl;
+class CefRunContextMenuCallback;
+
+class CefMenuManager : public CefMenuModelImpl::Delegate,
+ public content::WebContentsObserver {
+ public:
+ CefMenuManager(AlloyBrowserHostImpl* browser,
+ std::unique_ptr<CefMenuRunner> runner);
+
+ CefMenuManager(const CefMenuManager&) = delete;
+ CefMenuManager& operator=(const CefMenuManager&) = delete;
+
+ ~CefMenuManager() override;
+
+ // Delete the runner to free any platform constructs.
+ void Destroy();
+
+ // Returns true if the context menu is currently showing.
+ bool IsShowingContextMenu();
+
+ // Create the context menu.
+ bool CreateContextMenu(const content::ContextMenuParams& params);
+ void CancelContextMenu();
+
+ private:
+ // CefMenuModelImpl::Delegate methods.
+ void ExecuteCommand(CefRefPtr<CefMenuModelImpl> source,
+ int command_id,
+ cef_event_flags_t event_flags) override;
+ void MenuWillShow(CefRefPtr<CefMenuModelImpl> source) override;
+ void MenuClosed(CefRefPtr<CefMenuModelImpl> source) override;
+ bool FormatLabel(CefRefPtr<CefMenuModelImpl> source,
+ std::u16string& label) override;
+
+ void ExecuteCommandCallback(int command_id, cef_event_flags_t event_flags);
+
+ // Create the default menu model.
+ void CreateDefaultModel();
+ // Execute the default command handling.
+ void ExecuteDefaultCommand(int command_id);
+
+ // Returns true if the specified id is a custom context menu command.
+ bool IsCustomContextMenuCommand(int command_id);
+
+ // AlloyBrowserHostImpl pointer is guaranteed to outlive this object.
+ AlloyBrowserHostImpl* browser_;
+
+ std::unique_ptr<CefMenuRunner> runner_;
+
+ CefRefPtr<CefMenuModelImpl> model_;
+ content::ContextMenuParams params_;
+
+ // Not owned by this class.
+ CefRunContextMenuCallback* custom_menu_callback_;
+
+ // Must be the last member.
+ base::WeakPtrFactory<CefMenuManager> weak_ptr_factory_;
+};
+
+#endif // CEF_LIBCEF_BROWSER_MENU_MANAGER_H_
diff --git a/libcef/browser/menu_model_impl.cc b/libcef/browser/menu_model_impl.cc
new file mode 100644
index 00000000..f1f3433e
--- /dev/null
+++ b/libcef/browser/menu_model_impl.cc
@@ -0,0 +1,1117 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors.
+// Portions copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/menu_model_impl.h"
+
+#include <vector>
+
+#include "libcef/browser/thread_util.h"
+#include "libcef/common/task_runner_impl.h"
+
+#include "base/functional/bind.h"
+#include "base/logging.h"
+#include "third_party/blink/public/mojom/context_menu/context_menu.mojom.h"
+#include "ui/base/accelerators/accelerator.h"
+#include "ui/base/models/image_model.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/image/image.h"
+
+namespace {
+
+const int kSeparatorId = -1;
+const int kInvalidGroupId = -1;
+const int kInvalidCommandId = -1;
+const int kDefaultIndex = -1;
+const int kInvalidIndex = -2;
+
+// A simple MenuModel implementation that delegates to CefMenuModelImpl.
+class CefSimpleMenuModel : public ui::MenuModel {
+ public:
+ // The Delegate can be NULL, though if it is items can't be checked or
+ // disabled.
+ explicit CefSimpleMenuModel(CefMenuModelImpl* impl) : impl_(impl) {}
+
+ CefSimpleMenuModel(const CefSimpleMenuModel&) = delete;
+ CefSimpleMenuModel& operator=(const CefSimpleMenuModel&) = delete;
+
+ // MenuModel methods.
+ bool HasIcons() const override { return false; }
+
+ size_t GetItemCount() const override { return impl_->GetCount(); }
+
+ ItemType GetTypeAt(size_t index) const override {
+ switch (impl_->GetTypeAt(index)) {
+ case MENUITEMTYPE_COMMAND:
+ return TYPE_COMMAND;
+ case MENUITEMTYPE_CHECK:
+ return TYPE_CHECK;
+ case MENUITEMTYPE_RADIO:
+ return TYPE_RADIO;
+ case MENUITEMTYPE_SEPARATOR:
+ return TYPE_SEPARATOR;
+ case MENUITEMTYPE_SUBMENU:
+ return TYPE_SUBMENU;
+ default:
+ NOTREACHED();
+ return TYPE_COMMAND;
+ }
+ }
+
+ ui::MenuSeparatorType GetSeparatorTypeAt(size_t index) const override {
+ return ui::NORMAL_SEPARATOR;
+ }
+
+ int GetCommandIdAt(size_t index) const override {
+ return impl_->GetCommandIdAt(index);
+ }
+
+ std::u16string GetLabelAt(size_t index) const override {
+ return impl_->GetFormattedLabelAt(index);
+ }
+
+ bool IsItemDynamicAt(size_t index) const override { return false; }
+
+ const gfx::FontList* GetLabelFontListAt(size_t index) const override {
+ return impl_->GetLabelFontListAt(index);
+ }
+
+ bool GetAcceleratorAt(size_t index,
+ ui::Accelerator* accelerator) const override {
+ int key_code = 0;
+ bool shift_pressed = false;
+ bool ctrl_pressed = false;
+ bool alt_pressed = false;
+ if (impl_->GetAcceleratorAt(index, key_code, shift_pressed, ctrl_pressed,
+ alt_pressed)) {
+ int modifiers = 0;
+ if (shift_pressed) {
+ modifiers |= ui::EF_SHIFT_DOWN;
+ }
+ if (ctrl_pressed) {
+ modifiers |= ui::EF_CONTROL_DOWN;
+ }
+ if (alt_pressed) {
+ modifiers |= ui::EF_ALT_DOWN;
+ }
+
+ *accelerator =
+ ui::Accelerator(static_cast<ui::KeyboardCode>(key_code), modifiers);
+ return true;
+ }
+ return false;
+ }
+
+ bool IsItemCheckedAt(size_t index) const override {
+ return impl_->IsCheckedAt(index);
+ }
+
+ int GetGroupIdAt(size_t index) const override {
+ return impl_->GetGroupIdAt(index);
+ }
+
+ ui::ImageModel GetIconAt(size_t index) const override {
+ return ui::ImageModel();
+ }
+
+ ui::ButtonMenuItemModel* GetButtonMenuItemAt(size_t index) const override {
+ return nullptr;
+ }
+
+ bool IsEnabledAt(size_t index) const override {
+ return impl_->IsEnabledAt(index);
+ }
+
+ bool IsVisibleAt(size_t index) const override {
+ return impl_->IsVisibleAt(index);
+ }
+
+ void ActivatedAt(size_t index) override { ActivatedAt(index, 0); }
+
+ void ActivatedAt(size_t index, int event_flags) override {
+ impl_->ActivatedAt(index, static_cast<cef_event_flags_t>(event_flags));
+ }
+
+ MenuModel* GetSubmenuModelAt(size_t index) const override {
+ CefRefPtr<CefMenuModel> submenu = impl_->GetSubMenuAt(index);
+ if (submenu.get()) {
+ return static_cast<CefMenuModelImpl*>(submenu.get())->model();
+ }
+ return nullptr;
+ }
+
+ void MouseOutsideMenu(const gfx::Point& screen_point) override {
+ impl_->MouseOutsideMenu(screen_point);
+ }
+
+ void UnhandledOpenSubmenu(bool is_rtl) override {
+ impl_->UnhandledOpenSubmenu(is_rtl);
+ }
+
+ void UnhandledCloseSubmenu(bool is_rtl) override {
+ impl_->UnhandledCloseSubmenu(is_rtl);
+ }
+
+ bool GetTextColor(size_t index,
+ bool is_minor,
+ bool is_hovered,
+ SkColor* override_color) const override {
+ return impl_->GetTextColor(index, is_minor, is_hovered, override_color);
+ }
+
+ bool GetBackgroundColor(size_t index,
+ bool is_hovered,
+ SkColor* override_color) const override {
+ return impl_->GetBackgroundColor(index, is_hovered, override_color);
+ }
+
+ void MenuWillShow() override { impl_->MenuWillShow(); }
+
+ void MenuWillClose() override { impl_->MenuWillClose(); }
+
+ private:
+ CefMenuModelImpl* impl_;
+};
+
+cef_menu_color_type_t GetMenuColorType(bool is_text,
+ bool is_accelerator,
+ bool is_hovered) {
+ if (is_text) {
+ if (is_accelerator) {
+ return is_hovered ? CEF_MENU_COLOR_TEXT_ACCELERATOR_HOVERED
+ : CEF_MENU_COLOR_TEXT_ACCELERATOR;
+ }
+ return is_hovered ? CEF_MENU_COLOR_TEXT_HOVERED : CEF_MENU_COLOR_TEXT;
+ }
+
+ DCHECK(!is_accelerator);
+ return is_hovered ? CEF_MENU_COLOR_BACKGROUND_HOVERED
+ : CEF_MENU_COLOR_BACKGROUND;
+}
+
+} // namespace
+
+// static
+CefRefPtr<CefMenuModel> CefMenuModel::CreateMenuModel(
+ CefRefPtr<CefMenuModelDelegate> delegate) {
+ CEF_REQUIRE_UIT_RETURN(nullptr);
+ DCHECK(delegate);
+ if (!delegate) {
+ return nullptr;
+ }
+
+ CefRefPtr<CefMenuModelImpl> menu_model =
+ new CefMenuModelImpl(nullptr, delegate, false);
+ return menu_model;
+}
+
+struct CefMenuModelImpl::Item {
+ Item(cef_menu_item_type_t type,
+ int command_id,
+ const CefString& label,
+ int group_id)
+ : type_(type),
+ command_id_(command_id),
+ label_(label),
+ group_id_(group_id) {}
+
+ // Basic information.
+ cef_menu_item_type_t type_;
+ int command_id_;
+ CefString label_;
+ int group_id_;
+ CefRefPtr<CefMenuModelImpl> submenu_;
+
+ // State information.
+ bool enabled_ = true;
+ bool visible_ = true;
+ bool checked_ = false;
+
+ // Accelerator information.
+ bool has_accelerator_ = false;
+ int key_code_ = 0;
+ bool shift_pressed_ = false;
+ bool ctrl_pressed_ = false;
+ bool alt_pressed_ = false;
+
+ cef_color_t colors_[CEF_MENU_COLOR_COUNT] = {0};
+ gfx::FontList font_list_;
+ bool has_font_list_ = false;
+};
+
+CefMenuModelImpl::CefMenuModelImpl(
+ Delegate* delegate,
+ CefRefPtr<CefMenuModelDelegate> menu_model_delegate,
+ bool is_submenu)
+ : supported_thread_id_(base::PlatformThread::CurrentId()),
+ delegate_(delegate),
+ menu_model_delegate_(menu_model_delegate),
+ is_submenu_(is_submenu) {
+ DCHECK(delegate_ || menu_model_delegate_);
+ model_.reset(new CefSimpleMenuModel(this));
+}
+
+CefMenuModelImpl::~CefMenuModelImpl() {}
+
+bool CefMenuModelImpl::IsSubMenu() {
+ if (!VerifyContext()) {
+ return false;
+ }
+ return is_submenu_;
+}
+
+bool CefMenuModelImpl::Clear() {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ items_.clear();
+ return true;
+}
+
+size_t CefMenuModelImpl::GetCount() {
+ if (!VerifyContext()) {
+ return 0;
+ }
+
+ return items_.size();
+}
+
+bool CefMenuModelImpl::AddSeparator() {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ AppendItem(
+ Item(MENUITEMTYPE_SEPARATOR, kSeparatorId, CefString(), kInvalidGroupId));
+ return true;
+}
+
+bool CefMenuModelImpl::AddItem(int command_id, const CefString& label) {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ AppendItem(Item(MENUITEMTYPE_COMMAND, command_id, label, kInvalidGroupId));
+ return true;
+}
+
+bool CefMenuModelImpl::AddCheckItem(int command_id, const CefString& label) {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ AppendItem(Item(MENUITEMTYPE_CHECK, command_id, label, kInvalidGroupId));
+ return true;
+}
+
+bool CefMenuModelImpl::AddRadioItem(int command_id,
+ const CefString& label,
+ int group_id) {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ AppendItem(Item(MENUITEMTYPE_RADIO, command_id, label, group_id));
+ return true;
+}
+
+CefRefPtr<CefMenuModel> CefMenuModelImpl::AddSubMenu(int command_id,
+ const CefString& label) {
+ if (!VerifyContext()) {
+ return nullptr;
+ }
+
+ Item item(MENUITEMTYPE_SUBMENU, command_id, label, kInvalidGroupId);
+ item.submenu_ = new CefMenuModelImpl(delegate_, menu_model_delegate_, true);
+ AppendItem(item);
+ return item.submenu_.get();
+}
+
+bool CefMenuModelImpl::InsertSeparatorAt(size_t index) {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ InsertItemAt(
+ Item(MENUITEMTYPE_SEPARATOR, kSeparatorId, CefString(), kInvalidGroupId),
+ index);
+ return true;
+}
+
+bool CefMenuModelImpl::InsertItemAt(size_t index,
+ int command_id,
+ const CefString& label) {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ InsertItemAt(Item(MENUITEMTYPE_COMMAND, command_id, label, kInvalidGroupId),
+ index);
+ return true;
+}
+
+bool CefMenuModelImpl::InsertCheckItemAt(size_t index,
+ int command_id,
+ const CefString& label) {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ InsertItemAt(Item(MENUITEMTYPE_CHECK, command_id, label, kInvalidGroupId),
+ index);
+ return true;
+}
+
+bool CefMenuModelImpl::InsertRadioItemAt(size_t index,
+ int command_id,
+ const CefString& label,
+ int group_id) {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ InsertItemAt(Item(MENUITEMTYPE_RADIO, command_id, label, group_id), index);
+ return true;
+}
+
+CefRefPtr<CefMenuModel> CefMenuModelImpl::InsertSubMenuAt(
+ size_t index,
+ int command_id,
+ const CefString& label) {
+ if (!VerifyContext()) {
+ return nullptr;
+ }
+
+ Item item(MENUITEMTYPE_SUBMENU, command_id, label, kInvalidGroupId);
+ item.submenu_ = new CefMenuModelImpl(delegate_, menu_model_delegate_, true);
+ InsertItemAt(item, index);
+ return item.submenu_.get();
+}
+
+bool CefMenuModelImpl::Remove(int command_id) {
+ return RemoveAt(GetIndexOf(command_id));
+}
+
+bool CefMenuModelImpl::RemoveAt(size_t index) {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ if (index < items_.size()) {
+ items_.erase(items_.begin() + index);
+ return true;
+ }
+ return false;
+}
+
+int CefMenuModelImpl::GetIndexOf(int command_id) {
+ if (!VerifyContext()) {
+ return kInvalidIndex;
+ }
+
+ for (ItemVector::iterator i = items_.begin(); i != items_.end(); ++i) {
+ if ((*i).command_id_ == command_id) {
+ return static_cast<int>(std::distance(items_.begin(), i));
+ }
+ }
+ return kInvalidIndex;
+}
+
+int CefMenuModelImpl::GetCommandIdAt(size_t index) {
+ if (!VerifyContext()) {
+ return kInvalidCommandId;
+ }
+
+ if (index < items_.size()) {
+ return items_[index].command_id_;
+ }
+ return kInvalidCommandId;
+}
+
+bool CefMenuModelImpl::SetCommandIdAt(size_t index, int command_id) {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ if (index < items_.size()) {
+ items_[index].command_id_ = command_id;
+ return true;
+ }
+ return false;
+}
+
+CefString CefMenuModelImpl::GetLabel(int command_id) {
+ return GetLabelAt(GetIndexOf(command_id));
+}
+
+CefString CefMenuModelImpl::GetLabelAt(size_t index) {
+ if (!VerifyContext()) {
+ return CefString();
+ }
+
+ if (index < items_.size()) {
+ return items_[index].label_;
+ }
+ return CefString();
+}
+
+bool CefMenuModelImpl::SetLabel(int command_id, const CefString& label) {
+ return SetLabelAt(GetIndexOf(command_id), label);
+}
+
+bool CefMenuModelImpl::SetLabelAt(size_t index, const CefString& label) {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ if (index < items_.size()) {
+ items_[index].label_ = label;
+ return true;
+ }
+ return false;
+}
+
+CefMenuModelImpl::MenuItemType CefMenuModelImpl::GetType(int command_id) {
+ return GetTypeAt(GetIndexOf(command_id));
+}
+
+CefMenuModelImpl::MenuItemType CefMenuModelImpl::GetTypeAt(size_t index) {
+ if (!VerifyContext()) {
+ return MENUITEMTYPE_NONE;
+ }
+
+ if (index < items_.size()) {
+ return items_[index].type_;
+ }
+ return MENUITEMTYPE_NONE;
+}
+
+int CefMenuModelImpl::GetGroupId(int command_id) {
+ return GetGroupIdAt(GetIndexOf(command_id));
+}
+
+int CefMenuModelImpl::GetGroupIdAt(size_t index) {
+ if (!VerifyContext()) {
+ return kInvalidGroupId;
+ }
+
+ if (index < items_.size()) {
+ return items_[index].group_id_;
+ }
+ return kInvalidGroupId;
+}
+
+bool CefMenuModelImpl::SetGroupId(int command_id, int group_id) {
+ return SetGroupIdAt(GetIndexOf(command_id), group_id);
+}
+
+bool CefMenuModelImpl::SetGroupIdAt(size_t index, int group_id) {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ if (index < items_.size()) {
+ items_[index].group_id_ = group_id;
+ return true;
+ }
+ return false;
+}
+
+CefRefPtr<CefMenuModel> CefMenuModelImpl::GetSubMenu(int command_id) {
+ return GetSubMenuAt(GetIndexOf(command_id));
+}
+
+CefRefPtr<CefMenuModel> CefMenuModelImpl::GetSubMenuAt(size_t index) {
+ if (!VerifyContext()) {
+ return nullptr;
+ }
+
+ if (index < items_.size()) {
+ return items_[index].submenu_.get();
+ }
+ return nullptr;
+}
+
+bool CefMenuModelImpl::IsVisible(int command_id) {
+ return IsVisibleAt(GetIndexOf(command_id));
+}
+
+bool CefMenuModelImpl::IsVisibleAt(size_t index) {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ if (index < items_.size()) {
+ return items_[index].visible_;
+ }
+ return false;
+}
+
+bool CefMenuModelImpl::SetVisible(int command_id, bool visible) {
+ return SetVisibleAt(GetIndexOf(command_id), visible);
+}
+
+bool CefMenuModelImpl::SetVisibleAt(size_t index, bool visible) {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ if (index < items_.size()) {
+ items_[index].visible_ = visible;
+ return true;
+ }
+ return false;
+}
+
+bool CefMenuModelImpl::IsEnabled(int command_id) {
+ return IsEnabledAt(GetIndexOf(command_id));
+}
+
+bool CefMenuModelImpl::IsEnabledAt(size_t index) {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ if (index < items_.size()) {
+ return items_[index].enabled_;
+ }
+ return false;
+}
+
+bool CefMenuModelImpl::SetEnabled(int command_id, bool enabled) {
+ return SetEnabledAt(GetIndexOf(command_id), enabled);
+}
+
+bool CefMenuModelImpl::SetEnabledAt(size_t index, bool enabled) {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ if (index < items_.size()) {
+ items_[index].enabled_ = enabled;
+ return true;
+ }
+ return false;
+}
+
+bool CefMenuModelImpl::IsChecked(int command_id) {
+ return IsCheckedAt(GetIndexOf(command_id));
+}
+
+bool CefMenuModelImpl::IsCheckedAt(size_t index) {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ if (index < items_.size()) {
+ return items_[index].checked_;
+ }
+ return false;
+}
+
+bool CefMenuModelImpl::SetChecked(int command_id, bool checked) {
+ return SetCheckedAt(GetIndexOf(command_id), checked);
+}
+
+bool CefMenuModelImpl::SetCheckedAt(size_t index, bool checked) {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ if (index < items_.size()) {
+ items_[index].checked_ = checked;
+ return true;
+ }
+ return false;
+}
+
+bool CefMenuModelImpl::HasAccelerator(int command_id) {
+ return HasAcceleratorAt(GetIndexOf(command_id));
+}
+
+bool CefMenuModelImpl::HasAcceleratorAt(size_t index) {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ if (index < items_.size()) {
+ return items_[index].has_accelerator_;
+ }
+ return false;
+}
+
+bool CefMenuModelImpl::SetAccelerator(int command_id,
+ int key_code,
+ bool shift_pressed,
+ bool ctrl_pressed,
+ bool alt_pressed) {
+ return SetAcceleratorAt(GetIndexOf(command_id), key_code, shift_pressed,
+ ctrl_pressed, alt_pressed);
+}
+
+bool CefMenuModelImpl::SetAcceleratorAt(size_t index,
+ int key_code,
+ bool shift_pressed,
+ bool ctrl_pressed,
+ bool alt_pressed) {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ if (index < items_.size()) {
+ Item& item = items_[index];
+ item.has_accelerator_ = true;
+ item.key_code_ = key_code;
+ item.shift_pressed_ = shift_pressed;
+ item.ctrl_pressed_ = ctrl_pressed;
+ item.alt_pressed_ = alt_pressed;
+ return true;
+ }
+ return false;
+}
+
+bool CefMenuModelImpl::RemoveAccelerator(int command_id) {
+ return RemoveAcceleratorAt(GetIndexOf(command_id));
+}
+
+bool CefMenuModelImpl::RemoveAcceleratorAt(size_t index) {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ if (index < items_.size()) {
+ Item& item = items_[index];
+ if (item.has_accelerator_) {
+ item.has_accelerator_ = false;
+ item.key_code_ = 0;
+ item.shift_pressed_ = false;
+ item.ctrl_pressed_ = false;
+ item.alt_pressed_ = false;
+ }
+ return true;
+ }
+ return false;
+}
+
+bool CefMenuModelImpl::GetAccelerator(int command_id,
+ int& key_code,
+ bool& shift_pressed,
+ bool& ctrl_pressed,
+ bool& alt_pressed) {
+ return GetAcceleratorAt(GetIndexOf(command_id), key_code, shift_pressed,
+ ctrl_pressed, alt_pressed);
+}
+
+bool CefMenuModelImpl::GetAcceleratorAt(size_t index,
+ int& key_code,
+ bool& shift_pressed,
+ bool& ctrl_pressed,
+ bool& alt_pressed) {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ if (index < items_.size()) {
+ const Item& item = items_[index];
+ if (item.has_accelerator_) {
+ key_code = item.key_code_;
+ shift_pressed = item.shift_pressed_;
+ ctrl_pressed = item.ctrl_pressed_;
+ alt_pressed = item.alt_pressed_;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool CefMenuModelImpl::SetColor(int command_id,
+ cef_menu_color_type_t color_type,
+ cef_color_t color) {
+ return SetColorAt(GetIndexOf(command_id), color_type, color);
+}
+
+bool CefMenuModelImpl::SetColorAt(int index,
+ cef_menu_color_type_t color_type,
+ cef_color_t color) {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ if (color_type < 0 || color_type >= CEF_MENU_COLOR_COUNT) {
+ return false;
+ }
+
+ if (index == kDefaultIndex) {
+ default_colors_[color_type] = color;
+ return true;
+ }
+
+ if (index >= 0 && index < static_cast<int>(items_.size())) {
+ Item& item = items_[index];
+ item.colors_[color_type] = color;
+ return true;
+ }
+
+ return false;
+}
+
+bool CefMenuModelImpl::GetColor(int command_id,
+ cef_menu_color_type_t color_type,
+ cef_color_t& color) {
+ return GetColorAt(GetIndexOf(command_id), color_type, color);
+}
+
+bool CefMenuModelImpl::GetColorAt(int index,
+ cef_menu_color_type_t color_type,
+ cef_color_t& color) {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ if (color_type < 0 || color_type >= CEF_MENU_COLOR_COUNT) {
+ return false;
+ }
+
+ if (index == kDefaultIndex) {
+ color = default_colors_[color_type];
+ return true;
+ }
+
+ if (index >= 0 && index < static_cast<int>(items_.size())) {
+ Item& item = items_[index];
+ color = item.colors_[color_type];
+ return true;
+ }
+
+ return false;
+}
+
+bool CefMenuModelImpl::SetFontList(int command_id, const CefString& font_list) {
+ return SetFontListAt(GetIndexOf(command_id), font_list);
+}
+
+bool CefMenuModelImpl::SetFontListAt(int index, const CefString& font_list) {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ if (index == kDefaultIndex) {
+ if (font_list.empty()) {
+ has_default_font_list_ = false;
+ } else {
+ default_font_list_ = gfx::FontList(font_list);
+ has_default_font_list_ = true;
+ }
+ return true;
+ }
+
+ if (index >= 0 && index < static_cast<int>(items_.size())) {
+ Item& item = items_[index];
+ if (font_list.empty()) {
+ item.has_font_list_ = false;
+ } else {
+ item.font_list_ = gfx::FontList(font_list);
+ item.has_font_list_ = true;
+ }
+ return true;
+ }
+ return false;
+}
+
+void CefMenuModelImpl::ActivatedAt(size_t index,
+ cef_event_flags_t event_flags) {
+ if (!VerifyContext()) {
+ return;
+ }
+
+ const int command_id = GetCommandIdAt(index);
+ if (delegate_) {
+ delegate_->ExecuteCommand(this, command_id, event_flags);
+ }
+ if (menu_model_delegate_) {
+ menu_model_delegate_->ExecuteCommand(this, command_id, event_flags);
+ }
+}
+
+void CefMenuModelImpl::MouseOutsideMenu(const gfx::Point& screen_point) {
+ if (!VerifyContext()) {
+ return;
+ }
+
+ // Allow the callstack to unwind before notifying the delegate since it may
+ // result in the menu being destroyed.
+ CefTaskRunnerImpl::GetCurrentTaskRunner()->PostTask(
+ FROM_HERE, base::BindOnce(&CefMenuModelImpl::OnMouseOutsideMenu, this,
+ screen_point));
+}
+
+void CefMenuModelImpl::UnhandledOpenSubmenu(bool is_rtl) {
+ if (!VerifyContext()) {
+ return;
+ }
+
+ // Allow the callstack to unwind before notifying the delegate since it may
+ // result in the menu being destroyed.
+ CefTaskRunnerImpl::GetCurrentTaskRunner()->PostTask(
+ FROM_HERE,
+ base::BindOnce(&CefMenuModelImpl::OnUnhandledOpenSubmenu, this, is_rtl));
+}
+
+void CefMenuModelImpl::UnhandledCloseSubmenu(bool is_rtl) {
+ if (!VerifyContext()) {
+ return;
+ }
+
+ // Allow the callstack to unwind before notifying the delegate since it may
+ // result in the menu being destroyed.
+ CefTaskRunnerImpl::GetCurrentTaskRunner()->PostTask(
+ FROM_HERE,
+ base::BindOnce(&CefMenuModelImpl::OnUnhandledCloseSubmenu, this, is_rtl));
+}
+
+bool CefMenuModelImpl::GetTextColor(size_t index,
+ bool is_accelerator,
+ bool is_hovered,
+ SkColor* override_color) const {
+ if (index < items_.size()) {
+ const Item& item = items_[index];
+ if (!item.enabled_) {
+ // Use accelerator color for disabled item text.
+ is_accelerator = true;
+ }
+
+ const cef_menu_color_type_t color_type =
+ GetMenuColorType(true, is_accelerator, is_hovered);
+ if (item.colors_[color_type] != 0) {
+ *override_color = item.colors_[color_type];
+ return true;
+ }
+ }
+
+ const cef_menu_color_type_t color_type =
+ GetMenuColorType(true, is_accelerator, is_hovered);
+ if (default_colors_[color_type] != 0) {
+ *override_color = default_colors_[color_type];
+ return true;
+ }
+
+ return false;
+}
+
+bool CefMenuModelImpl::GetBackgroundColor(size_t index,
+ bool is_hovered,
+ SkColor* override_color) const {
+ const cef_menu_color_type_t color_type =
+ GetMenuColorType(false, false, is_hovered);
+
+ if (index < items_.size()) {
+ const Item& item = items_[index];
+ if (item.colors_[color_type] != 0) {
+ *override_color = item.colors_[color_type];
+ return true;
+ }
+ }
+
+ if (default_colors_[color_type] != 0) {
+ *override_color = default_colors_[color_type];
+ return true;
+ }
+
+ return false;
+}
+
+void CefMenuModelImpl::MenuWillShow() {
+ if (!VerifyContext()) {
+ return;
+ }
+
+ if (delegate_) {
+ delegate_->MenuWillShow(this);
+ }
+ if (menu_model_delegate_) {
+ menu_model_delegate_->MenuWillShow(this);
+ }
+}
+
+void CefMenuModelImpl::MenuWillClose() {
+ if (!VerifyContext()) {
+ return;
+ }
+
+ if (!auto_notify_menu_closed_) {
+ return;
+ }
+
+ // Due to how menus work on the different platforms, ActivatedAt will be
+ // called after this. It's more convenient for the delegate to be called
+ // afterwards, though, so post a task.
+ CefTaskRunnerImpl::GetCurrentTaskRunner()->PostTask(
+ FROM_HERE, base::BindOnce(&CefMenuModelImpl::OnMenuClosed, this));
+}
+
+std::u16string CefMenuModelImpl::GetFormattedLabelAt(size_t index) {
+ std::u16string label = GetLabelAt(index).ToString16();
+ if (delegate_) {
+ delegate_->FormatLabel(this, label);
+ }
+ if (menu_model_delegate_) {
+ CefString new_label = label;
+ if (menu_model_delegate_->FormatLabel(this, new_label)) {
+ label = new_label;
+ }
+ }
+ return label;
+}
+
+const gfx::FontList* CefMenuModelImpl::GetLabelFontListAt(size_t index) const {
+ if (index < items_.size()) {
+ const Item& item = items_[index];
+ if (item.has_font_list_) {
+ return &item.font_list_;
+ }
+ }
+
+ if (has_default_font_list_) {
+ return &default_font_list_;
+ }
+ return nullptr;
+}
+
+bool CefMenuModelImpl::VerifyRefCount() {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ if (!HasOneRef()) {
+ return false;
+ }
+
+ for (ItemVector::iterator i = items_.begin(); i != items_.end(); ++i) {
+ if ((*i).submenu_.get()) {
+ if (!(*i).submenu_->VerifyRefCount()) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+void CefMenuModelImpl::AddMenuItem(
+ const blink::mojom::CustomContextMenuItem& menu_item) {
+ const int command_id = static_cast<int>(menu_item.action);
+
+ switch (menu_item.type) {
+ case blink::mojom::CustomContextMenuItemType::kOption:
+ AddItem(command_id, menu_item.label);
+ break;
+ case blink::mojom::CustomContextMenuItemType::kCheckableOption:
+ AddCheckItem(command_id, menu_item.label);
+ break;
+ case blink::mojom::CustomContextMenuItemType::kGroup:
+ AddRadioItem(command_id, menu_item.label, 0);
+ break;
+ case blink::mojom::CustomContextMenuItemType::kSeparator:
+ AddSeparator();
+ break;
+ case blink::mojom::CustomContextMenuItemType::kSubMenu: {
+ CefRefPtr<CefMenuModelImpl> sub_menu = static_cast<CefMenuModelImpl*>(
+ AddSubMenu(command_id, menu_item.label).get());
+ for (size_t i = 0; i < menu_item.submenu.size(); ++i) {
+ sub_menu->AddMenuItem(*menu_item.submenu[i]);
+ }
+ break;
+ }
+ }
+
+ if (!menu_item.enabled &&
+ menu_item.type != blink::mojom::CustomContextMenuItemType::kSeparator) {
+ SetEnabled(command_id, false);
+ }
+
+ if (menu_item.checked &&
+ (menu_item.type ==
+ blink::mojom::CustomContextMenuItemType::kCheckableOption ||
+ menu_item.type == blink::mojom::CustomContextMenuItemType::kGroup)) {
+ SetChecked(command_id, true);
+ }
+}
+
+void CefMenuModelImpl::NotifyMenuClosed() {
+ DCHECK(!auto_notify_menu_closed_);
+ OnMenuClosed();
+}
+
+void CefMenuModelImpl::AppendItem(const Item& item) {
+ ValidateItem(item);
+ items_.push_back(item);
+}
+
+void CefMenuModelImpl::InsertItemAt(const Item& item, size_t index) {
+ // Sanitize the index.
+ if (index > items_.size()) {
+ index = items_.size();
+ }
+
+ ValidateItem(item);
+ items_.insert(items_.begin() + index, item);
+}
+
+void CefMenuModelImpl::ValidateItem(const Item& item) {
+#if DCHECK_IS_ON()
+ if (item.type_ == MENUITEMTYPE_SEPARATOR) {
+ DCHECK_EQ(item.command_id_, kSeparatorId);
+ } else {
+ DCHECK_GE(item.command_id_, 0);
+ }
+#endif
+}
+
+void CefMenuModelImpl::OnMouseOutsideMenu(const gfx::Point& screen_point) {
+ if (delegate_) {
+ delegate_->MouseOutsideMenu(this, screen_point);
+ }
+ if (menu_model_delegate_) {
+ menu_model_delegate_->MouseOutsideMenu(
+ this, CefPoint(screen_point.x(), screen_point.y()));
+ }
+}
+
+void CefMenuModelImpl::OnUnhandledOpenSubmenu(bool is_rtl) {
+ if (delegate_) {
+ delegate_->UnhandledOpenSubmenu(this, is_rtl);
+ }
+ if (menu_model_delegate_) {
+ menu_model_delegate_->UnhandledOpenSubmenu(this, is_rtl);
+ }
+}
+
+void CefMenuModelImpl::OnUnhandledCloseSubmenu(bool is_rtl) {
+ if (delegate_) {
+ delegate_->UnhandledCloseSubmenu(this, is_rtl);
+ }
+ if (menu_model_delegate_) {
+ menu_model_delegate_->UnhandledCloseSubmenu(this, is_rtl);
+ }
+}
+
+void CefMenuModelImpl::OnMenuClosed() {
+ if (delegate_) {
+ delegate_->MenuClosed(this);
+ }
+ if (menu_model_delegate_) {
+ menu_model_delegate_->MenuClosed(this);
+ }
+}
+
+bool CefMenuModelImpl::VerifyContext() {
+ if (base::PlatformThread::CurrentId() != supported_thread_id_) {
+ // This object should only be accessed from the thread that created it.
+ NOTREACHED();
+ return false;
+ }
+
+ return true;
+}
diff --git a/libcef/browser/menu_model_impl.h b/libcef/browser/menu_model_impl.h
new file mode 100644
index 00000000..b8965121
--- /dev/null
+++ b/libcef/browser/menu_model_impl.h
@@ -0,0 +1,237 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors.
+// Portions copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_MENU_MODEL_IMPL_H_
+#define CEF_LIBCEF_BROWSER_MENU_MODEL_IMPL_H_
+#pragma once
+
+#include <vector>
+
+#include "include/cef_menu_model.h"
+#include "include/cef_menu_model_delegate.h"
+
+#include "base/threading/platform_thread.h"
+#include "third_party/blink/public/mojom/context_menu/context_menu.mojom-forward.h"
+#include "ui/base/models/menu_model.h"
+#include "ui/gfx/font_list.h"
+
+class CefMenuModelImpl : public CefMenuModel {
+ public:
+ class Delegate {
+ public:
+ // Perform the action associated with the specified |command_id| and
+ // optional |event_flags|.
+ virtual void ExecuteCommand(CefRefPtr<CefMenuModelImpl> source,
+ int command_id,
+ cef_event_flags_t event_flags) = 0;
+
+ // Called when the user moves the mouse outside the menu and over the owning
+ // window.
+ virtual void MouseOutsideMenu(CefRefPtr<CefMenuModelImpl> source,
+ const gfx::Point& screen_point) {}
+
+ // Called on unhandled open/close submenu keyboard commands. |is_rtl| will
+ // be true if the menu is displaying a right-to-left language.
+ virtual void UnhandledOpenSubmenu(CefRefPtr<CefMenuModelImpl> source,
+ bool is_rtl) {}
+ virtual void UnhandledCloseSubmenu(CefRefPtr<CefMenuModelImpl> source,
+ bool is_rtl) {}
+
+ // Called when the menu is about to show.
+ virtual void MenuWillShow(CefRefPtr<CefMenuModelImpl> source) = 0;
+
+ // Called when the menu has closed.
+ virtual void MenuClosed(CefRefPtr<CefMenuModelImpl> source) = 0;
+
+ // Allows the delegate to modify a menu item label before it's displayed.
+ virtual bool FormatLabel(CefRefPtr<CefMenuModelImpl> source,
+ std::u16string& label) = 0;
+
+ protected:
+ virtual ~Delegate() {}
+ };
+
+ // Either |delegate| or |menu_model_delegate| must be non-nullptr.
+ // If |delegate| is non-nullptr it must outlive this class.
+ CefMenuModelImpl(Delegate* delegate,
+ CefRefPtr<CefMenuModelDelegate> menu_model_delegate,
+ bool is_submenu);
+
+ CefMenuModelImpl(const CefMenuModelImpl&) = delete;
+ CefMenuModelImpl& operator=(const CefMenuModelImpl&) = delete;
+
+ ~CefMenuModelImpl() override;
+
+ // CefMenuModel methods.
+ bool IsSubMenu() override;
+ bool Clear() override;
+ size_t GetCount() override;
+ bool AddSeparator() override;
+ bool AddItem(int command_id, const CefString& label) override;
+ bool AddCheckItem(int command_id, const CefString& label) override;
+ bool AddRadioItem(int command_id,
+ const CefString& label,
+ int group_id) override;
+ CefRefPtr<CefMenuModel> AddSubMenu(int command_id,
+ const CefString& label) override;
+ bool InsertSeparatorAt(size_t index) override;
+ bool InsertItemAt(size_t index,
+ int command_id,
+ const CefString& label) override;
+ bool InsertCheckItemAt(size_t index,
+ int command_id,
+ const CefString& label) override;
+ bool InsertRadioItemAt(size_t index,
+ int command_id,
+ const CefString& label,
+ int group_id) override;
+ CefRefPtr<CefMenuModel> InsertSubMenuAt(size_t index,
+ int command_id,
+ const CefString& label) override;
+ bool Remove(int command_id) override;
+ bool RemoveAt(size_t index) override;
+ int GetIndexOf(int command_id) override;
+ int GetCommandIdAt(size_t index) override;
+ bool SetCommandIdAt(size_t index, int command_id) override;
+ CefString GetLabel(int command_id) override;
+ CefString GetLabelAt(size_t index) override;
+ bool SetLabel(int command_id, const CefString& label) override;
+ bool SetLabelAt(size_t index, const CefString& label) override;
+ MenuItemType GetType(int command_id) override;
+ MenuItemType GetTypeAt(size_t index) override;
+ int GetGroupId(int command_id) override;
+ int GetGroupIdAt(size_t index) override;
+ bool SetGroupId(int command_id, int group_id) override;
+ bool SetGroupIdAt(size_t index, int group_id) override;
+ CefRefPtr<CefMenuModel> GetSubMenu(int command_id) override;
+ CefRefPtr<CefMenuModel> GetSubMenuAt(size_t index) override;
+ bool IsVisible(int command_id) override;
+ bool IsVisibleAt(size_t index) override;
+ bool SetVisible(int command_id, bool visible) override;
+ bool SetVisibleAt(size_t index, bool visible) override;
+ bool IsEnabled(int command_id) override;
+ bool IsEnabledAt(size_t index) override;
+ bool SetEnabled(int command_id, bool enabled) override;
+ bool SetEnabledAt(size_t index, bool enabled) override;
+ bool IsChecked(int command_id) override;
+ bool IsCheckedAt(size_t index) override;
+ bool SetChecked(int command_id, bool checked) override;
+ bool SetCheckedAt(size_t index, bool checked) override;
+ bool HasAccelerator(int command_id) override;
+ bool HasAcceleratorAt(size_t index) override;
+ bool SetAccelerator(int command_id,
+ int key_code,
+ bool shift_pressed,
+ bool ctrl_pressed,
+ bool alt_pressed) override;
+ bool SetAcceleratorAt(size_t index,
+ int key_code,
+ bool shift_pressed,
+ bool ctrl_pressed,
+ bool alt_pressed) override;
+ bool RemoveAccelerator(int command_id) override;
+ bool RemoveAcceleratorAt(size_t index) override;
+ bool GetAccelerator(int command_id,
+ int& key_code,
+ bool& shift_pressed,
+ bool& ctrl_pressed,
+ bool& alt_pressed) override;
+ bool GetAcceleratorAt(size_t index,
+ int& key_code,
+ bool& shift_pressed,
+ bool& ctrl_pressed,
+ bool& alt_pressed) override;
+ bool SetColor(int command_id,
+ cef_menu_color_type_t color_type,
+ cef_color_t color) override;
+ bool SetColorAt(int index,
+ cef_menu_color_type_t color_type,
+ cef_color_t color) override;
+ bool GetColor(int command_id,
+ cef_menu_color_type_t color_type,
+ cef_color_t& color) override;
+ bool GetColorAt(int index,
+ cef_menu_color_type_t color_type,
+ cef_color_t& color) override;
+ bool SetFontList(int command_id, const CefString& font_list) override;
+ bool SetFontListAt(int index, const CefString& font_list) override;
+
+ // Callbacks from the ui::MenuModel implementation.
+ void ActivatedAt(size_t index, cef_event_flags_t event_flags);
+ void MouseOutsideMenu(const gfx::Point& screen_point);
+ void UnhandledOpenSubmenu(bool is_rtl);
+ void UnhandledCloseSubmenu(bool is_rtl);
+ bool GetTextColor(size_t index,
+ bool is_accelerator,
+ bool is_hovered,
+ SkColor* override_color) const;
+ bool GetBackgroundColor(size_t index,
+ bool is_hovered,
+ SkColor* override_color) const;
+ void MenuWillShow();
+ void MenuWillClose();
+ std::u16string GetFormattedLabelAt(size_t index);
+ const gfx::FontList* GetLabelFontListAt(size_t index) const;
+
+ // Verify that only a single reference exists to all CefMenuModelImpl objects.
+ bool VerifyRefCount();
+
+ // Helper for adding custom menu items originating from the renderer process.
+ void AddMenuItem(const blink::mojom::CustomContextMenuItem& menu_item);
+
+ ui::MenuModel* model() const { return model_.get(); }
+
+ // Used when created via CefMenuManager.
+ Delegate* delegate() const { return delegate_; }
+ void set_delegate(Delegate* delegate) { delegate_ = delegate; }
+
+ // Used for menus run via CefWindowImpl::ShowMenu to provide more accurate
+ // menu close notification.
+ void set_auto_notify_menu_closed(bool val) { auto_notify_menu_closed_ = val; }
+ void NotifyMenuClosed();
+
+ private:
+ struct Item;
+
+ using ItemVector = std::vector<Item>;
+
+ // Functions for inserting items into |items_|.
+ void AppendItem(const Item& item);
+ void InsertItemAt(const Item& item, size_t index);
+ void ValidateItem(const Item& item);
+
+ // Notify the delegate asynchronously.
+ void OnMouseOutsideMenu(const gfx::Point& screen_point);
+ void OnUnhandledOpenSubmenu(bool is_rtl);
+ void OnUnhandledCloseSubmenu(bool is_rtl);
+ void OnMenuClosed();
+
+ // Verify that the object is being accessed from the correct thread.
+ bool VerifyContext();
+
+ base::PlatformThreadId supported_thread_id_;
+
+ // Used when created via CefMenuManager.
+ Delegate* delegate_;
+
+ // Used when created via CefMenuModel::CreateMenuModel().
+ CefRefPtr<CefMenuModelDelegate> menu_model_delegate_;
+
+ const bool is_submenu_;
+
+ ItemVector items_;
+ std::unique_ptr<ui::MenuModel> model_;
+
+ // Style information.
+ cef_color_t default_colors_[CEF_MENU_COLOR_COUNT] = {0};
+ gfx::FontList default_font_list_;
+ bool has_default_font_list_ = false;
+
+ bool auto_notify_menu_closed_ = true;
+
+ IMPLEMENT_REFCOUNTING(CefMenuModelImpl);
+};
+
+#endif // CEF_LIBCEF_BROWSER_MENU_MODEL_IMPL_H_
diff --git a/libcef/browser/menu_runner.h b/libcef/browser/menu_runner.h
new file mode 100644
index 00000000..a0107dbe
--- /dev/null
+++ b/libcef/browser/menu_runner.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_MENU_RUNNER_H_
+#define CEF_LIBCEF_BROWSER_MENU_RUNNER_H_
+
+#include <memory>
+#include <string>
+
+namespace content {
+struct ContextMenuParams;
+}
+
+class AlloyBrowserHostImpl;
+class CefMenuModelImpl;
+
+// Provides platform-specific menu implementations for CefMenuCreator.
+class CefMenuRunner {
+ public:
+ CefMenuRunner(const CefMenuRunner&) = delete;
+ CefMenuRunner& operator=(const CefMenuRunner&) = delete;
+
+ virtual bool RunContextMenu(AlloyBrowserHostImpl* browser,
+ CefMenuModelImpl* model,
+ const content::ContextMenuParams& params) = 0;
+ virtual void CancelContextMenu() {}
+ virtual bool FormatLabel(std::u16string& label) { return false; }
+
+ protected:
+ // Allow deletion via std::unique_ptr only.
+ friend std::default_delete<CefMenuRunner>;
+
+ CefMenuRunner() = default;
+ virtual ~CefMenuRunner() = default;
+};
+
+#endif // CEF_LIBCEF_BROWSER_MENU_RUNNER_H_
diff --git a/libcef/browser/native/browser_platform_delegate_native.cc b/libcef/browser/native/browser_platform_delegate_native.cc
new file mode 100644
index 00000000..6547a137
--- /dev/null
+++ b/libcef/browser/native/browser_platform_delegate_native.cc
@@ -0,0 +1,29 @@
+// Copyright 2015 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/native/browser_platform_delegate_native.h"
+
+#include "libcef/browser/alloy/alloy_browser_host_impl.h"
+
+#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
+#include "third_party/blink/public/common/input/web_mouse_event.h"
+
+CefBrowserPlatformDelegateNative::CefBrowserPlatformDelegateNative(
+ const CefWindowInfo& window_info,
+ SkColor background_color)
+ : window_info_(window_info),
+ background_color_(background_color),
+ windowless_handler_(nullptr) {}
+
+SkColor CefBrowserPlatformDelegateNative::GetBackgroundColor() const {
+ return background_color_;
+}
+
+void CefBrowserPlatformDelegateNative::WasResized() {
+ content::RenderViewHost* host = web_contents_->GetRenderViewHost();
+ if (host) {
+ host->GetWidget()->SynchronizeVisualProperties();
+ }
+}
diff --git a/libcef/browser/native/browser_platform_delegate_native.h b/libcef/browser/native/browser_platform_delegate_native.h
new file mode 100644
index 00000000..704da0d1
--- /dev/null
+++ b/libcef/browser/native/browser_platform_delegate_native.h
@@ -0,0 +1,75 @@
+// Copyright 2015 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_NATIVE_BROWSER_PLATFORM_DELEGATE_NATIVE_H_
+#define CEF_LIBCEF_BROWSER_NATIVE_BROWSER_PLATFORM_DELEGATE_NATIVE_H_
+
+#include "libcef/browser/alloy/browser_platform_delegate_alloy.h"
+
+// Base implementation of native browser functionality.
+class CefBrowserPlatformDelegateNative
+ : public CefBrowserPlatformDelegateAlloy {
+ public:
+ // Used by the windowless implementation to override specific functionality
+ // when delegating to the native implementation.
+ class WindowlessHandler {
+ public:
+ // Returns the parent window handle.
+ virtual CefWindowHandle GetParentWindowHandle() const = 0;
+
+ // Convert from view DIP coordinates to screen coordinates. If
+ // |want_dip_coords| is true return DIP instead of device (pixel)
+ // coordinates on Windows/Linux.
+ virtual gfx::Point GetParentScreenPoint(const gfx::Point& view,
+ bool want_dip_coords) const = 0;
+
+ protected:
+ virtual ~WindowlessHandler() {}
+ };
+
+ // CefBrowserPlatformDelegate methods:
+ SkColor GetBackgroundColor() const override;
+ void WasResized() override;
+
+ // Translate CEF events to Chromium/Blink Web events.
+ virtual content::NativeWebKeyboardEvent TranslateWebKeyEvent(
+ const CefKeyEvent& key_event) const = 0;
+ virtual blink::WebMouseEvent TranslateWebClickEvent(
+ const CefMouseEvent& mouse_event,
+ CefBrowserHost::MouseButtonType type,
+ bool mouseUp,
+ int clickCount) const = 0;
+ virtual blink::WebMouseEvent TranslateWebMoveEvent(
+ const CefMouseEvent& mouse_event,
+ bool mouseLeave) const = 0;
+ virtual blink::WebMouseWheelEvent TranslateWebWheelEvent(
+ const CefMouseEvent& mouse_event,
+ int deltaX,
+ int deltaY) const = 0;
+
+ const CefWindowInfo& window_info() const { return window_info_; }
+
+ protected:
+ // Delegates that can wrap a native delegate.
+ friend class CefBrowserPlatformDelegateBackground;
+ friend class CefBrowserPlatformDelegateChrome;
+ friend class CefBrowserPlatformDelegateOsr;
+ friend class CefBrowserPlatformDelegateViews;
+
+ CefBrowserPlatformDelegateNative(const CefWindowInfo& window_info,
+ SkColor background_color);
+
+ // Methods used by delegates that can wrap a native delegate.
+ void set_windowless_handler(WindowlessHandler* handler) {
+ windowless_handler_ = handler;
+ set_as_secondary();
+ }
+
+ CefWindowInfo window_info_;
+ const SkColor background_color_;
+
+ WindowlessHandler* windowless_handler_; // Not owned by this object.
+};
+
+#endif // CEF_LIBCEF_BROWSER_NATIVE_BROWSER_PLATFORM_DELEGATE_NATIVE_H_
diff --git a/libcef/browser/native/browser_platform_delegate_native_aura.cc b/libcef/browser/native/browser_platform_delegate_native_aura.cc
new file mode 100644
index 00000000..81d3862d
--- /dev/null
+++ b/libcef/browser/native/browser_platform_delegate_native_aura.cc
@@ -0,0 +1,300 @@
+// Copyright 2020 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/native/browser_platform_delegate_native_aura.h"
+
+#include "libcef/browser/native/menu_runner_views_aura.h"
+#include "libcef/browser/views/view_util.h"
+
+#include "content/browser/renderer_host/render_widget_host_view_aura.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
+#include "ui/events/blink/blink_event_util.h"
+#include "ui/events/blink/web_input_event.h"
+#include "ui/gfx/geometry/vector2d.h"
+#include "ui/views/widget/widget.h"
+
+CefBrowserPlatformDelegateNativeAura::CefBrowserPlatformDelegateNativeAura(
+ const CefWindowInfo& window_info,
+ SkColor background_color)
+ : CefBrowserPlatformDelegateNative(window_info, background_color) {}
+
+void CefBrowserPlatformDelegateNativeAura::SendKeyEvent(
+ const CefKeyEvent& event) {
+ auto view = GetHostView();
+ if (!view) {
+ return;
+ }
+
+ ui::KeyEvent ui_event = TranslateUiKeyEvent(event);
+ view->OnKeyEvent(&ui_event);
+}
+
+void CefBrowserPlatformDelegateNativeAura::SendMouseClickEvent(
+ const CefMouseEvent& event,
+ CefBrowserHost::MouseButtonType type,
+ bool mouseUp,
+ int clickCount) {
+ auto view = GetHostView();
+ if (!view) {
+ return;
+ }
+
+ ui::MouseEvent ui_event =
+ TranslateUiClickEvent(event, type, mouseUp, clickCount);
+ view->OnMouseEvent(&ui_event);
+}
+
+void CefBrowserPlatformDelegateNativeAura::SendMouseMoveEvent(
+ const CefMouseEvent& event,
+ bool mouseLeave) {
+ auto view = GetHostView();
+ if (!view) {
+ return;
+ }
+
+ ui::MouseEvent ui_event = TranslateUiMoveEvent(event, mouseLeave);
+ view->OnMouseEvent(&ui_event);
+}
+
+void CefBrowserPlatformDelegateNativeAura::SendMouseWheelEvent(
+ const CefMouseEvent& event,
+ int deltaX,
+ int deltaY) {
+ auto view = GetHostView();
+ if (!view) {
+ return;
+ }
+
+ ui::MouseWheelEvent ui_event = TranslateUiWheelEvent(event, deltaX, deltaY);
+ view->OnMouseEvent(&ui_event);
+}
+
+void CefBrowserPlatformDelegateNativeAura::SendTouchEvent(
+ const CefTouchEvent& event) {
+ NOTIMPLEMENTED();
+}
+
+std::unique_ptr<CefMenuRunner>
+CefBrowserPlatformDelegateNativeAura::CreateMenuRunner() {
+ return base::WrapUnique(new CefMenuRunnerViewsAura);
+}
+
+gfx::Point CefBrowserPlatformDelegateNativeAura::GetScreenPoint(
+ const gfx::Point& view,
+ bool want_dip_coords) const {
+ if (windowless_handler_) {
+ return windowless_handler_->GetParentScreenPoint(view, want_dip_coords);
+ }
+
+ if (!window_widget_) {
+ return view;
+ }
+
+ gfx::Point screen_pt(view);
+ if (!view_util::ConvertPointToScreen(
+ window_widget_->GetRootView(), &screen_pt,
+ /*output_pixel_coords=*/!want_dip_coords)) {
+ return view;
+ }
+
+ return screen_pt;
+}
+
+content::NativeWebKeyboardEvent
+CefBrowserPlatformDelegateNativeAura::TranslateWebKeyEvent(
+ const CefKeyEvent& key_event) const {
+ return content::NativeWebKeyboardEvent(TranslateUiKeyEvent(key_event));
+}
+
+blink::WebMouseEvent
+CefBrowserPlatformDelegateNativeAura::TranslateWebClickEvent(
+ const CefMouseEvent& mouse_event,
+ CefBrowserHost::MouseButtonType type,
+ bool mouseUp,
+ int clickCount) const {
+ return ui::MakeWebMouseEvent(
+ TranslateUiClickEvent(mouse_event, type, mouseUp, clickCount));
+}
+
+blink::WebMouseEvent
+CefBrowserPlatformDelegateNativeAura::TranslateWebMoveEvent(
+ const CefMouseEvent& mouse_event,
+ bool mouseLeave) const {
+ return ui::MakeWebMouseEvent(TranslateUiMoveEvent(mouse_event, mouseLeave));
+}
+
+blink::WebMouseWheelEvent
+CefBrowserPlatformDelegateNativeAura::TranslateWebWheelEvent(
+ const CefMouseEvent& mouse_event,
+ int deltaX,
+ int deltaY) const {
+ return ui::MakeWebMouseWheelEvent(
+ TranslateUiWheelEvent(mouse_event, deltaX, deltaY));
+}
+
+ui::MouseEvent CefBrowserPlatformDelegateNativeAura::TranslateUiClickEvent(
+ const CefMouseEvent& mouse_event,
+ CefBrowserHost::MouseButtonType type,
+ bool mouseUp,
+ int clickCount) const {
+ DCHECK_GE(clickCount, 1);
+
+ ui::EventType event_type =
+ mouseUp ? ui::ET_MOUSE_RELEASED : ui::ET_MOUSE_PRESSED;
+ gfx::PointF location(mouse_event.x, mouse_event.y);
+ gfx::PointF root_location(GetScreenPoint(
+ gfx::Point(mouse_event.x, mouse_event.y), /*want_dip_coords=*/false));
+ base::TimeTicks time_stamp = GetEventTimeStamp();
+ int flags = TranslateUiEventModifiers(mouse_event.modifiers);
+
+ int changed_button_flags = 0;
+ switch (type) {
+ case MBT_LEFT:
+ changed_button_flags |= ui::EF_LEFT_MOUSE_BUTTON;
+ break;
+ case MBT_MIDDLE:
+ changed_button_flags |= ui::EF_MIDDLE_MOUSE_BUTTON;
+ break;
+ case MBT_RIGHT:
+ changed_button_flags |= ui::EF_RIGHT_MOUSE_BUTTON;
+ break;
+ default:
+ NOTREACHED();
+ }
+
+ ui::MouseEvent result(event_type, location, root_location, time_stamp, flags,
+ changed_button_flags);
+ result.SetClickCount(clickCount);
+ return result;
+}
+
+ui::MouseEvent CefBrowserPlatformDelegateNativeAura::TranslateUiMoveEvent(
+ const CefMouseEvent& mouse_event,
+ bool mouseLeave) const {
+ ui::EventType event_type =
+ mouseLeave ? ui::ET_MOUSE_EXITED : ui::ET_MOUSE_MOVED;
+ gfx::PointF location(mouse_event.x, mouse_event.y);
+ gfx::PointF root_location(GetScreenPoint(
+ gfx::Point(mouse_event.x, mouse_event.y), /*want_dip_coords=*/false));
+ base::TimeTicks time_stamp = GetEventTimeStamp();
+ int flags = TranslateUiEventModifiers(mouse_event.modifiers);
+
+ int changed_button_flags = 0;
+ if (!mouseLeave) {
+ changed_button_flags = TranslateUiChangedButtonFlags(mouse_event.modifiers);
+ }
+
+ return ui::MouseEvent(event_type, location, root_location, time_stamp, flags,
+ changed_button_flags);
+}
+
+ui::MouseWheelEvent CefBrowserPlatformDelegateNativeAura::TranslateUiWheelEvent(
+ const CefMouseEvent& mouse_event,
+ int deltaX,
+ int deltaY) const {
+ gfx::Vector2d offset(GetUiWheelEventOffset(deltaX, deltaY));
+ DCHECK(!offset.IsZero());
+
+ gfx::PointF location(mouse_event.x, mouse_event.y);
+ gfx::PointF root_location(GetScreenPoint(
+ gfx::Point(mouse_event.x, mouse_event.y), /*want_dip_coords=*/false));
+ base::TimeTicks time_stamp = GetEventTimeStamp();
+ int flags = TranslateUiEventModifiers(mouse_event.modifiers);
+ int changed_button_flags =
+ TranslateUiChangedButtonFlags(mouse_event.modifiers);
+
+ return ui::MouseWheelEvent(offset, location, root_location, time_stamp,
+ (ui::EF_PRECISION_SCROLLING_DELTA | flags),
+ changed_button_flags);
+}
+
+gfx::Vector2d CefBrowserPlatformDelegateNativeAura::GetUiWheelEventOffset(
+ int deltaX,
+ int deltaY) const {
+ return gfx::Vector2d(deltaX, deltaY);
+}
+
+base::OnceClosure
+CefBrowserPlatformDelegateNativeAura::GetWidgetDeleteCallback() {
+ return base::BindOnce(&CefBrowserPlatformDelegateNativeAura::WidgetDeleted,
+ weak_ptr_factory_.GetWeakPtr());
+}
+
+// static
+base::TimeTicks CefBrowserPlatformDelegateNativeAura::GetEventTimeStamp() {
+ return base::TimeTicks::Now();
+}
+
+// static
+int CefBrowserPlatformDelegateNativeAura::TranslateUiEventModifiers(
+ uint32 cef_modifiers) {
+ int result = 0;
+ // Set modifiers based on key state.
+ if (cef_modifiers & EVENTFLAG_CAPS_LOCK_ON) {
+ result |= ui::EF_CAPS_LOCK_ON;
+ }
+ if (cef_modifiers & EVENTFLAG_SHIFT_DOWN) {
+ result |= ui::EF_SHIFT_DOWN;
+ }
+ if (cef_modifiers & EVENTFLAG_CONTROL_DOWN) {
+ result |= ui::EF_CONTROL_DOWN;
+ }
+ if (cef_modifiers & EVENTFLAG_ALT_DOWN) {
+ result |= ui::EF_ALT_DOWN;
+ }
+ if (cef_modifiers & EVENTFLAG_LEFT_MOUSE_BUTTON) {
+ result |= ui::EF_LEFT_MOUSE_BUTTON;
+ }
+ if (cef_modifiers & EVENTFLAG_MIDDLE_MOUSE_BUTTON) {
+ result |= ui::EF_MIDDLE_MOUSE_BUTTON;
+ }
+ if (cef_modifiers & EVENTFLAG_RIGHT_MOUSE_BUTTON) {
+ result |= ui::EF_RIGHT_MOUSE_BUTTON;
+ }
+ if (cef_modifiers & EVENTFLAG_COMMAND_DOWN) {
+ result |= ui::EF_COMMAND_DOWN;
+ }
+ if (cef_modifiers & EVENTFLAG_NUM_LOCK_ON) {
+ result |= ui::EF_NUM_LOCK_ON;
+ }
+ if (cef_modifiers & EVENTFLAG_IS_KEY_PAD) {
+ result |= ui::EF_IS_EXTENDED_KEY;
+ }
+ if (cef_modifiers & EVENTFLAG_ALTGR_DOWN) {
+ result |= ui::EF_ALTGR_DOWN;
+ }
+ if (cef_modifiers & EVENTFLAG_IS_REPEAT) {
+ result |= ui::EF_IS_REPEAT;
+ }
+ return result;
+}
+
+// static
+int CefBrowserPlatformDelegateNativeAura::TranslateUiChangedButtonFlags(
+ uint32 cef_modifiers) {
+ int result = 0;
+ if (cef_modifiers & EVENTFLAG_LEFT_MOUSE_BUTTON) {
+ result |= ui::EF_LEFT_MOUSE_BUTTON;
+ } else if (cef_modifiers & EVENTFLAG_MIDDLE_MOUSE_BUTTON) {
+ result |= ui::EF_MIDDLE_MOUSE_BUTTON;
+ } else if (cef_modifiers & EVENTFLAG_RIGHT_MOUSE_BUTTON) {
+ result |= ui::EF_RIGHT_MOUSE_BUTTON;
+ }
+ return result;
+}
+
+void CefBrowserPlatformDelegateNativeAura::WidgetDeleted() {
+ DCHECK(window_widget_);
+ window_widget_ = nullptr;
+}
+
+content::RenderWidgetHostViewAura*
+CefBrowserPlatformDelegateNativeAura::GetHostView() const {
+ if (!web_contents_) {
+ return nullptr;
+ }
+ return static_cast<content::RenderWidgetHostViewAura*>(
+ web_contents_->GetRenderWidgetHostView());
+}
diff --git a/libcef/browser/native/browser_platform_delegate_native_aura.h b/libcef/browser/native/browser_platform_delegate_native_aura.h
new file mode 100644
index 00000000..a3c61fb2
--- /dev/null
+++ b/libcef/browser/native/browser_platform_delegate_native_aura.h
@@ -0,0 +1,96 @@
+// Copyright 2020 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_NATIVE_BROWSER_PLATFORM_DELEGATE_NATIVE_AURA_H_
+#define CEF_LIBCEF_BROWSER_NATIVE_BROWSER_PLATFORM_DELEGATE_NATIVE_AURA_H_
+
+#include "libcef/browser/native/browser_platform_delegate_native.h"
+
+#include "base/memory/weak_ptr.h"
+#include "ui/events/event.h"
+
+namespace content {
+class RenderWidgetHostViewAura;
+}
+
+namespace gfx {
+class Vector2d;
+}
+
+// Windowed browser implementation for Aura platforms.
+class CefBrowserPlatformDelegateNativeAura
+ : public CefBrowserPlatformDelegateNative {
+ public:
+ CefBrowserPlatformDelegateNativeAura(const CefWindowInfo& window_info,
+ SkColor background_color);
+
+ // CefBrowserPlatformDelegate methods:
+ void SendKeyEvent(const CefKeyEvent& event) override;
+ void SendMouseClickEvent(const CefMouseEvent& event,
+ CefBrowserHost::MouseButtonType type,
+ bool mouseUp,
+ int clickCount) override;
+ void SendMouseMoveEvent(const CefMouseEvent& event, bool mouseLeave) override;
+ void SendMouseWheelEvent(const CefMouseEvent& event,
+ int deltaX,
+ int deltaY) override;
+ void SendTouchEvent(const CefTouchEvent& event) override;
+ std::unique_ptr<CefMenuRunner> CreateMenuRunner() override;
+ gfx::Point GetScreenPoint(const gfx::Point& view,
+ bool want_dip_coords) const override;
+
+ // CefBrowserPlatformDelegateNative methods:
+ content::NativeWebKeyboardEvent TranslateWebKeyEvent(
+ const CefKeyEvent& key_event) const override;
+ blink::WebMouseEvent TranslateWebClickEvent(
+ const CefMouseEvent& mouse_event,
+ CefBrowserHost::MouseButtonType type,
+ bool mouseUp,
+ int clickCount) const override;
+ blink::WebMouseEvent TranslateWebMoveEvent(const CefMouseEvent& mouse_event,
+ bool mouseLeave) const override;
+ blink::WebMouseWheelEvent TranslateWebWheelEvent(
+ const CefMouseEvent& mouse_event,
+ int deltaX,
+ int deltaY) const override;
+
+ // Translate CEF events to Chromium UI events.
+ virtual ui::KeyEvent TranslateUiKeyEvent(
+ const CefKeyEvent& key_event) const = 0;
+ virtual ui::MouseEvent TranslateUiClickEvent(
+ const CefMouseEvent& mouse_event,
+ CefBrowserHost::MouseButtonType type,
+ bool mouseUp,
+ int clickCount) const;
+ virtual ui::MouseEvent TranslateUiMoveEvent(const CefMouseEvent& mouse_event,
+ bool mouseLeave) const;
+ virtual ui::MouseWheelEvent TranslateUiWheelEvent(
+ const CefMouseEvent& mouse_event,
+ int deltaX,
+ int deltaY) const;
+ virtual gfx::Vector2d GetUiWheelEventOffset(int deltaX, int deltaY) const;
+
+ protected:
+ base::OnceClosure GetWidgetDeleteCallback();
+
+ static base::TimeTicks GetEventTimeStamp();
+ static int TranslateUiEventModifiers(uint32 cef_modifiers);
+ static int TranslateUiChangedButtonFlags(uint32 cef_modifiers);
+
+ // Widget hosting the web contents. It will be deleted automatically when the
+ // associated root window is destroyed.
+ views::Widget* window_widget_ = nullptr;
+
+ private:
+ // Will only be called if the Widget is deleted before
+ // CefBrowserHostBase::DestroyBrowser() is called.
+ void WidgetDeleted();
+
+ content::RenderWidgetHostViewAura* GetHostView() const;
+
+ base::WeakPtrFactory<CefBrowserPlatformDelegateNativeAura> weak_ptr_factory_{
+ this};
+};
+
+#endif // CEF_LIBCEF_BROWSER_NATIVE_BROWSER_PLATFORM_DELEGATE_NATIVE_AURA_H_
diff --git a/libcef/browser/native/browser_platform_delegate_native_linux.cc b/libcef/browser/native/browser_platform_delegate_native_linux.cc
new file mode 100644
index 00000000..50e7a950
--- /dev/null
+++ b/libcef/browser/native/browser_platform_delegate_native_linux.cc
@@ -0,0 +1,299 @@
+// Copyright 2015 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/native/browser_platform_delegate_native_linux.h"
+
+#include "libcef/browser/browser_host_base.h"
+#include "libcef/browser/context.h"
+#include "libcef/browser/native/window_delegate_view.h"
+#include "libcef/browser/thread_util.h"
+
+#include "base/no_destructor.h"
+#include "content/browser/renderer_host/render_widget_host_impl.h"
+#include "content/public/browser/native_web_keyboard_event.h"
+#include "content/public/browser/render_view_host.h"
+#include "third_party/blink/public/mojom/renderer_preferences.mojom.h"
+#include "ui/events/keycodes/dom/dom_key.h"
+#include "ui/events/keycodes/dom/keycode_converter.h"
+#include "ui/events/keycodes/keysym_to_unicode.h"
+#include "ui/gfx/font_render_params.h"
+#include "ui/views/widget/widget.h"
+
+#if BUILDFLAG(OZONE_PLATFORM_X11)
+#include "libcef/browser/native/window_x11.h"
+#include "ui/events/keycodes/keyboard_code_conversion_x.h"
+#include "ui/events/keycodes/keyboard_code_conversion_xkb.h"
+#include "ui/views/widget/desktop_aura/desktop_window_tree_host_linux.h"
+#endif
+
+CefBrowserPlatformDelegateNativeLinux::CefBrowserPlatformDelegateNativeLinux(
+ const CefWindowInfo& window_info,
+ SkColor background_color)
+ : CefBrowserPlatformDelegateNativeAura(window_info, background_color) {}
+
+void CefBrowserPlatformDelegateNativeLinux::BrowserDestroyed(
+ CefBrowserHostBase* browser) {
+ CefBrowserPlatformDelegateNativeAura::BrowserDestroyed(browser);
+
+ if (host_window_created_) {
+ // Release the reference added in CreateHostWindow().
+ browser->Release();
+ }
+}
+
+bool CefBrowserPlatformDelegateNativeLinux::CreateHostWindow() {
+ DCHECK(!window_widget_);
+
+ if (window_info_.bounds.width == 0) {
+ window_info_.bounds.width = 800;
+ }
+ if (window_info_.bounds.height == 0) {
+ window_info_.bounds.height = 600;
+ }
+
+ gfx::Rect rect(window_info_.bounds.x, window_info_.bounds.y,
+ window_info_.bounds.width, window_info_.bounds.height);
+
+#if BUILDFLAG(OZONE_PLATFORM_X11)
+ DCHECK(!window_x11_);
+
+ x11::Window parent_window = x11::Window::None;
+ if (window_info_.parent_window != kNullWindowHandle) {
+ parent_window = static_cast<x11::Window>(window_info_.parent_window);
+ }
+
+ // Create a new window object. It will delete itself when the associated X11
+ // window is destroyed.
+ window_x11_ =
+ new CefWindowX11(browser_, parent_window, rect,
+ CefString(&window_info_.window_name).ToString());
+ DCHECK_NE(window_x11_->xwindow(), x11::Window::None);
+ window_info_.window =
+ static_cast<cef_window_handle_t>(window_x11_->xwindow());
+
+ host_window_created_ = true;
+
+ // Add a reference that will be released in BrowserDestroyed().
+ browser_->AddRef();
+
+ CefWindowDelegateView* delegate_view = new CefWindowDelegateView(
+ GetBackgroundColor(), window_x11_->TopLevelAlwaysOnTop(),
+ GetBoundsChangedCallback(), GetWidgetDeleteCallback());
+ delegate_view->Init(static_cast<gfx::AcceleratedWidget>(window_info_.window),
+ web_contents_, gfx::Rect(gfx::Point(), rect.size()));
+
+ window_widget_ = delegate_view->GetWidget();
+ window_widget_->Show();
+
+ window_x11_->Show();
+#endif // BUILDFLAG(OZONE_PLATFORM_X11)
+
+ // As an additional requirement on Linux, we must set the colors for the
+ // render widgets in webkit.
+ auto prefs = web_contents_->GetMutableRendererPrefs();
+ prefs->focus_ring_color = SkColorSetARGB(255, 229, 151, 0);
+
+ prefs->active_selection_bg_color = SkColorSetRGB(30, 144, 255);
+ prefs->active_selection_fg_color = SK_ColorWHITE;
+ prefs->inactive_selection_bg_color = SkColorSetRGB(200, 200, 200);
+ prefs->inactive_selection_fg_color = SkColorSetRGB(50, 50, 50);
+
+ // Set font-related attributes.
+ static const gfx::FontRenderParams params(
+ gfx::GetFontRenderParams(gfx::FontRenderParamsQuery(), nullptr));
+ prefs->should_antialias_text = params.antialiasing;
+ prefs->use_subpixel_positioning = params.subpixel_positioning;
+ prefs->hinting = params.hinting;
+ prefs->use_autohinter = params.autohinter;
+ prefs->use_bitmaps = params.use_bitmaps;
+ prefs->subpixel_rendering = params.subpixel_rendering;
+
+ web_contents_->SyncRendererPrefs();
+
+ return true;
+}
+
+void CefBrowserPlatformDelegateNativeLinux::CloseHostWindow() {
+#if BUILDFLAG(OZONE_PLATFORM_X11)
+ if (window_x11_) {
+ window_x11_->Close();
+ }
+#endif
+}
+
+CefWindowHandle CefBrowserPlatformDelegateNativeLinux::GetHostWindowHandle()
+ const {
+ if (windowless_handler_) {
+ return windowless_handler_->GetParentWindowHandle();
+ }
+ return window_info_.window;
+}
+
+views::Widget* CefBrowserPlatformDelegateNativeLinux::GetWindowWidget() const {
+ return window_widget_;
+}
+
+void CefBrowserPlatformDelegateNativeLinux::SetFocus(bool setFocus) {
+ if (!setFocus) {
+ return;
+ }
+
+ if (web_contents_) {
+ // Give logical focus to the RenderWidgetHostViewAura in the views
+ // hierarchy. This does not change the native keyboard focus.
+ web_contents_->Focus();
+ }
+
+#if BUILDFLAG(OZONE_PLATFORM_X11)
+ if (window_x11_) {
+ // Give native focus to the DesktopNativeWidgetAura for the root window.
+ // Needs to be done via the ::Window so that keyboard focus is assigned
+ // correctly.
+ window_x11_->Focus();
+ }
+#endif // BUILDFLAG(OZONE_PLATFORM_X11)
+}
+
+void CefBrowserPlatformDelegateNativeLinux::NotifyMoveOrResizeStarted() {
+ // Call the parent method to dismiss any existing popups.
+ CefBrowserPlatformDelegateNativeAura::NotifyMoveOrResizeStarted();
+
+ if (!web_contents_) {
+ return;
+ }
+
+#if BUILDFLAG(OZONE_PLATFORM_X11)
+ if (!window_x11_) {
+ return;
+ }
+
+ views::DesktopWindowTreeHostLinux* tree_host = window_x11_->GetHost();
+ if (!tree_host) {
+ return;
+ }
+
+ // Explicitly set the screen bounds so that WindowTreeHost::*Screen()
+ // methods return the correct results.
+ const gfx::Rect& bounds = window_x11_->GetBoundsInScreen();
+ tree_host->set_screen_bounds(bounds);
+
+ // Send updated screen rectangle information to the renderer process so that
+ // popups are displayed in the correct location.
+ content::RenderWidgetHostImpl::From(
+ web_contents_->GetRenderViewHost()->GetWidget())
+ ->SendScreenRects();
+#endif // BUILDFLAG(OZONE_PLATFORM_X11)
+}
+
+void CefBrowserPlatformDelegateNativeLinux::SizeTo(int width, int height) {
+#if BUILDFLAG(OZONE_PLATFORM_X11)
+ if (window_x11_) {
+ window_x11_->SetBounds(
+ gfx::Rect(window_x11_->bounds().origin(), gfx::Size(width, height)));
+ }
+#endif // BUILDFLAG(OZONE_PLATFORM_X11)
+}
+
+void CefBrowserPlatformDelegateNativeLinux::ViewText(const std::string& text) {
+ char buff[] = "/tmp/CEFSourceXXXXXX";
+ int fd = mkstemp(buff);
+
+ if (fd == -1) {
+ return;
+ }
+
+ FILE* srcOutput = fdopen(fd, "w+");
+ if (!srcOutput) {
+ return;
+ }
+
+ if (fputs(text.c_str(), srcOutput) < 0) {
+ fclose(srcOutput);
+ return;
+ }
+
+ fclose(srcOutput);
+
+ std::string newName(buff);
+ newName.append(".txt");
+ if (rename(buff, newName.c_str()) != 0) {
+ return;
+ }
+
+ std::string openCommand("xdg-open ");
+ openCommand += newName;
+
+ [[maybe_unused]] int result = system(openCommand.c_str());
+}
+
+bool CefBrowserPlatformDelegateNativeLinux::HandleKeyboardEvent(
+ const content::NativeWebKeyboardEvent& event) {
+ // TODO(cef): Is something required here to handle shortcut keys?
+ return false;
+}
+
+// static
+void CefBrowserPlatformDelegate::HandleExternalProtocol(const GURL& url) {}
+
+CefEventHandle CefBrowserPlatformDelegateNativeLinux::GetEventHandle(
+ const content::NativeWebKeyboardEvent& event) const {
+ // TODO(cef): We need to return an XEvent* from this method, but
+ // |event.os_event->native_event()| now returns a ui::Event* instead.
+ // See https://crbug.com/965991.
+ return nullptr;
+}
+
+ui::KeyEvent CefBrowserPlatformDelegateNativeLinux::TranslateUiKeyEvent(
+ const CefKeyEvent& key_event) const {
+ int flags = TranslateUiEventModifiers(key_event.modifiers);
+ ui::KeyboardCode key_code =
+ static_cast<ui::KeyboardCode>(key_event.windows_key_code);
+ ui::DomCode dom_code =
+ ui::KeycodeConverter::NativeKeycodeToDomCode(key_event.native_key_code);
+
+#if BUILDFLAG(OZONE_PLATFORM_X11)
+ int keysym = ui::XKeysymForWindowsKeyCode(
+ key_code, !!(key_event.modifiers & EVENTFLAG_SHIFT_DOWN));
+ char16_t character = ui::GetUnicodeCharacterFromXKeySym(keysym);
+#else
+ char16_t character = key_event.character;
+#endif
+
+ base::TimeTicks time_stamp = GetEventTimeStamp();
+
+ if (key_event.type == KEYEVENT_CHAR) {
+ return ui::KeyEvent(character, key_code, dom_code, flags, time_stamp);
+ }
+
+ ui::EventType type = ui::ET_UNKNOWN;
+ switch (key_event.type) {
+ case KEYEVENT_RAWKEYDOWN:
+ case KEYEVENT_KEYDOWN:
+ type = ui::ET_KEY_PRESSED;
+ break;
+ case KEYEVENT_KEYUP:
+ type = ui::ET_KEY_RELEASED;
+ break;
+ default:
+ NOTREACHED();
+ }
+
+#if BUILDFLAG(OZONE_PLATFORM_X11)
+ ui::DomKey dom_key = ui::XKeySymToDomKey(keysym, character);
+#else
+ ui::DomKey dom_key = ui::DomKey::NONE;
+#endif
+
+ return ui::KeyEvent(type, key_code, dom_code, flags, dom_key, time_stamp);
+}
+
+content::NativeWebKeyboardEvent
+CefBrowserPlatformDelegateNativeLinux::TranslateWebKeyEvent(
+ const CefKeyEvent& key_event) const {
+ ui::KeyEvent ui_event = TranslateUiKeyEvent(key_event);
+ if (key_event.type == KEYEVENT_CHAR) {
+ return content::NativeWebKeyboardEvent(ui_event, key_event.character);
+ }
+ return content::NativeWebKeyboardEvent(ui_event);
+}
diff --git a/libcef/browser/native/browser_platform_delegate_native_linux.h b/libcef/browser/native/browser_platform_delegate_native_linux.h
new file mode 100644
index 00000000..0da0cc83
--- /dev/null
+++ b/libcef/browser/native/browser_platform_delegate_native_linux.h
@@ -0,0 +1,52 @@
+// Copyright 2015 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_NATIVE_BROWSER_PLATFORM_DELEGATE_NATIVE_LINUX_H_
+#define CEF_LIBCEF_BROWSER_NATIVE_BROWSER_PLATFORM_DELEGATE_NATIVE_LINUX_H_
+
+#include "libcef/browser/native/browser_platform_delegate_native_aura.h"
+
+#include "ui/ozone/buildflags.h"
+
+#if BUILDFLAG(OZONE_PLATFORM_X11)
+class CefWindowX11;
+#endif
+
+// Windowed browser implementation for Linux.
+class CefBrowserPlatformDelegateNativeLinux
+ : public CefBrowserPlatformDelegateNativeAura {
+ public:
+ CefBrowserPlatformDelegateNativeLinux(const CefWindowInfo& window_info,
+ SkColor background_color);
+
+ // CefBrowserPlatformDelegate methods:
+ void BrowserDestroyed(CefBrowserHostBase* browser) override;
+ bool CreateHostWindow() override;
+ void CloseHostWindow() override;
+ CefWindowHandle GetHostWindowHandle() const override;
+ views::Widget* GetWindowWidget() const override;
+ void SetFocus(bool setFocus) override;
+ void NotifyMoveOrResizeStarted() override;
+ void SizeTo(int width, int height) override;
+ void ViewText(const std::string& text) override;
+ bool HandleKeyboardEvent(
+ const content::NativeWebKeyboardEvent& event) override;
+ CefEventHandle GetEventHandle(
+ const content::NativeWebKeyboardEvent& event) const override;
+
+ // CefBrowserPlatformDelegateNativeAura methods:
+ ui::KeyEvent TranslateUiKeyEvent(const CefKeyEvent& key_event) const override;
+ content::NativeWebKeyboardEvent TranslateWebKeyEvent(
+ const CefKeyEvent& key_event) const override;
+
+ private:
+ // True if the host window has been created.
+ bool host_window_created_ = false;
+
+#if BUILDFLAG(OZONE_PLATFORM_X11)
+ CefWindowX11* window_x11_ = nullptr;
+#endif
+};
+
+#endif // CEF_LIBCEF_BROWSER_NATIVE_BROWSER_PLATFORM_DELEGATE_NATIVE_LINUX_H_
diff --git a/libcef/browser/native/browser_platform_delegate_native_mac.h b/libcef/browser/native/browser_platform_delegate_native_mac.h
new file mode 100644
index 00000000..ba7211df
--- /dev/null
+++ b/libcef/browser/native/browser_platform_delegate_native_mac.h
@@ -0,0 +1,73 @@
+// Copyright 2015 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_NATIVE_BROWSER_PLATFORM_DELEGATE_NATIVE_MAC_H_
+#define CEF_LIBCEF_BROWSER_NATIVE_BROWSER_PLATFORM_DELEGATE_NATIVE_MAC_H_
+
+#include "libcef/browser/native/browser_platform_delegate_native.h"
+
+namespace content {
+class RenderWidgetHostViewMac;
+}
+
+// Windowed browser implementation for Mac OS X.
+class CefBrowserPlatformDelegateNativeMac
+ : public CefBrowserPlatformDelegateNative {
+ public:
+ CefBrowserPlatformDelegateNativeMac(const CefWindowInfo& window_info,
+ SkColor background_color);
+
+ // CefBrowserPlatformDelegate methods:
+ void BrowserDestroyed(CefBrowserHostBase* browser) override;
+ bool CreateHostWindow() override;
+ void CloseHostWindow() override;
+ CefWindowHandle GetHostWindowHandle() const override;
+ void SendKeyEvent(const CefKeyEvent& event) override;
+ void SendMouseClickEvent(const CefMouseEvent& event,
+ CefBrowserHost::MouseButtonType type,
+ bool mouseUp,
+ int clickCount) override;
+ void SendMouseMoveEvent(const CefMouseEvent& event, bool mouseLeave) override;
+ void SendMouseWheelEvent(const CefMouseEvent& event,
+ int deltaX,
+ int deltaY) override;
+ void SendTouchEvent(const CefTouchEvent& event) override;
+ void SetFocus(bool setFocus) override;
+ gfx::Point GetScreenPoint(const gfx::Point& view,
+ bool want_dip_coords) const override;
+ void ViewText(const std::string& text) override;
+ bool HandleKeyboardEvent(
+ const content::NativeWebKeyboardEvent& event) override;
+ CefEventHandle GetEventHandle(
+ const content::NativeWebKeyboardEvent& event) const override;
+ std::unique_ptr<CefJavaScriptDialogRunner> CreateJavaScriptDialogRunner()
+ override;
+ std::unique_ptr<CefMenuRunner> CreateMenuRunner() override;
+
+ // CefBrowserPlatformDelegateNative methods:
+ content::NativeWebKeyboardEvent TranslateWebKeyEvent(
+ const CefKeyEvent& key_event) const override;
+ blink::WebMouseEvent TranslateWebClickEvent(
+ const CefMouseEvent& mouse_event,
+ CefBrowserHost::MouseButtonType type,
+ bool mouseUp,
+ int clickCount) const override;
+ blink::WebMouseEvent TranslateWebMoveEvent(const CefMouseEvent& mouse_event,
+ bool mouseLeave) const override;
+ blink::WebMouseWheelEvent TranslateWebWheelEvent(
+ const CefMouseEvent& mouse_event,
+ int deltaX,
+ int deltaY) const override;
+
+ private:
+ void TranslateWebMouseEvent(blink::WebMouseEvent& result,
+ const CefMouseEvent& mouse_event) const;
+
+ content::RenderWidgetHostViewMac* GetHostView() const;
+
+ // True if the host window has been created.
+ bool host_window_created_;
+};
+
+#endif // CEF_LIBCEF_BROWSER_NATIVE_BROWSER_PLATFORM_DELEGATE_NATIVE_MAC_H_
diff --git a/libcef/browser/native/browser_platform_delegate_native_mac.mm b/libcef/browser/native/browser_platform_delegate_native_mac.mm
new file mode 100644
index 00000000..92d93c0d
--- /dev/null
+++ b/libcef/browser/native/browser_platform_delegate_native_mac.mm
@@ -0,0 +1,661 @@
+// Copyright 2015 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/native/browser_platform_delegate_native_mac.h"
+
+#import <Cocoa/Cocoa.h>
+#import <CoreServices/CoreServices.h>
+
+#include "libcef/browser/alloy/alloy_browser_host_impl.h"
+#include "libcef/browser/context.h"
+#include "libcef/browser/native/javascript_dialog_runner_mac.h"
+#include "libcef/browser/native/menu_runner_mac.h"
+#include "libcef/browser/thread_util.h"
+
+#include "base/mac/scoped_nsautorelease_pool.h"
+#include "base/memory/ptr_util.h"
+#include "base/threading/thread_restrictions.h"
+#include "content/browser/renderer_host/render_widget_host_view_mac.h"
+#include "content/public/browser/native_web_keyboard_event.h"
+#include "content/public/browser/render_widget_host_view.h"
+#include "content/public/browser/web_contents.h"
+#include "third_party/blink/public/common/input/web_input_event.h"
+#include "third_party/blink/public/common/input/web_mouse_event.h"
+#include "third_party/blink/public/common/input/web_mouse_wheel_event.h"
+#import "ui/base/cocoa/cocoa_base_utils.h"
+#import "ui/base/cocoa/underlay_opengl_hosting_window.h"
+#include "ui/display/screen.h"
+#include "ui/events/base_event_utils.h"
+#include "ui/events/keycodes/keyboard_codes_posix.h"
+#include "ui/gfx/geometry/rect.h"
+
+// Wrapper NSView for the native view. Necessary to destroy the browser when
+// the view is deleted.
+@interface CefBrowserHostView : NSView {
+ @private
+ CefBrowserHostBase* browser_; // weak
+}
+
+@property(nonatomic, assign) CefBrowserHostBase* browser;
+
+@end
+
+@implementation CefBrowserHostView
+
+@synthesize browser = browser_;
+
+- (void)dealloc {
+ if (browser_) {
+ // Force the browser to be destroyed and release the reference added in
+ // PlatformCreateWindow().
+ static_cast<AlloyBrowserHostImpl*>(browser_)->WindowDestroyed();
+ }
+
+ [super dealloc];
+}
+
+@end
+
+// Receives notifications from the browser window. Will delete itself when done.
+@interface CefWindowDelegate : NSObject <NSWindowDelegate> {
+ @private
+ CefBrowserHostBase* browser_; // weak
+ NSWindow* window_;
+}
+- (id)initWithWindow:(NSWindow*)window andBrowser:(CefBrowserHostBase*)browser;
+@end
+
+@implementation CefWindowDelegate
+
+- (id)initWithWindow:(NSWindow*)window andBrowser:(CefBrowserHostBase*)browser {
+ if (self = [super init]) {
+ window_ = window;
+ browser_ = browser;
+
+ [window_ setDelegate:self];
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+
+ [super dealloc];
+}
+
+- (BOOL)windowShouldClose:(id)window {
+ if (browser_ && !browser_->TryCloseBrowser()) {
+ // Cancel the close.
+ return NO;
+ }
+
+ // Clean ourselves up after clearing the stack of anything that might have the
+ // window on it.
+ [self performSelectorOnMainThread:@selector(cleanup:)
+ withObject:window
+ waitUntilDone:NO];
+
+ // Allow the close.
+ return YES;
+}
+
+- (void)cleanup:(id)window {
+ [window_ setDelegate:nil];
+ [self release];
+}
+
+@end
+
+namespace {
+
+NSTimeInterval currentEventTimestamp() {
+ NSEvent* currentEvent = [NSApp currentEvent];
+ if (currentEvent) {
+ return [currentEvent timestamp];
+ } else {
+ // FIXME(API): In case there is no current event, the timestamp could be
+ // obtained by getting the time since the application started. This involves
+ // taking some more static functions from Chromium code.
+ // Another option is to have the timestamp as a field in CefEvent structures
+ // and let the client provide it.
+ return 0;
+ }
+}
+
+NSUInteger NativeModifiers(int cef_modifiers) {
+ NSUInteger native_modifiers = 0;
+ if (cef_modifiers & EVENTFLAG_SHIFT_DOWN) {
+ native_modifiers |= NSEventModifierFlagShift;
+ }
+ if (cef_modifiers & EVENTFLAG_CONTROL_DOWN) {
+ native_modifiers |= NSEventModifierFlagControl;
+ }
+ if (cef_modifiers & EVENTFLAG_ALT_DOWN) {
+ native_modifiers |= NSEventModifierFlagOption;
+ }
+ if (cef_modifiers & EVENTFLAG_COMMAND_DOWN) {
+ native_modifiers |= NSEventModifierFlagCommand;
+ }
+ if (cef_modifiers & EVENTFLAG_CAPS_LOCK_ON) {
+ native_modifiers |= NSEventModifierFlagCapsLock;
+ }
+ if (cef_modifiers & EVENTFLAG_NUM_LOCK_ON) {
+ native_modifiers |= NSEventModifierFlagNumericPad;
+ }
+
+ return native_modifiers;
+}
+
+constexpr int kDefaultHeight = 750;
+constexpr int kDefaultWidth = 750;
+constexpr NSWindowStyleMask kDefaultStyleMask =
+ NSWindowStyleMaskTitled | NSWindowStyleMaskClosable |
+ NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable;
+
+// Keep the frame bounds inside the display work area.
+NSRect ClampNSBoundsToWorkArea(const NSRect& frame_bounds,
+ const gfx::Rect& display_bounds,
+ const gfx::Rect& work_area) {
+ NSRect bounds = frame_bounds;
+
+ // Convert from DIP coordinates (top-left origin) to macOS coordinates
+ // (bottom-left origin).
+ const int work_area_y =
+ display_bounds.height() - work_area.height() - work_area.y();
+
+ if (bounds.size.width > work_area.width()) {
+ bounds.size.width = work_area.width();
+ }
+ if (bounds.size.height > work_area.height()) {
+ bounds.size.height = work_area.height();
+ }
+
+ if (bounds.origin.x < work_area.x()) {
+ bounds.origin.x = work_area.x();
+ } else if (bounds.origin.x + bounds.size.width >=
+ work_area.x() + work_area.width()) {
+ bounds.origin.x = work_area.x() + work_area.width() - bounds.size.width;
+ }
+
+ if (bounds.origin.y < work_area_y) {
+ bounds.origin.y = work_area_y;
+ } else if (bounds.origin.y + bounds.size.height >=
+ work_area_y + work_area.height()) {
+ bounds.origin.y = work_area_y + work_area.height() - bounds.size.height;
+ }
+
+ return bounds;
+}
+
+// Get frame and content area rects matching the input DIP screen bounds. The
+// resulting window frame will be kept inside the closest display work area. If
+// |input_content_bounds| is true the input size is used for the content area
+// and the input origin is used for the frame. Otherwise, both input size and
+// origin are used for the frame.
+void GetNSBoundsInDisplay(const gfx::Rect& dip_bounds,
+ bool input_content_bounds,
+ NSWindowStyleMask style_mask,
+ NSRect& frame_rect,
+ NSRect& content_rect) {
+ // Identify the closest display.
+ const auto display =
+ display::Screen::GetScreen()->GetDisplayMatching(dip_bounds);
+ const auto& display_bounds = display.bounds();
+ const auto& display_work_area = display.work_area();
+
+ // Convert from DIP coordinates (top-left origin) to macOS coordinates
+ // (bottom-left origin).
+ NSRect requested_rect = NSMakeRect(dip_bounds.x(), dip_bounds.y(),
+ dip_bounds.width(), dip_bounds.height());
+ requested_rect.origin.y = display_bounds.height() -
+ requested_rect.size.height -
+ requested_rect.origin.y;
+
+ // Calculate the equivalent frame and content bounds.
+ if (input_content_bounds) {
+ // Compute frame rect from content rect. Keep the requested origin.
+ content_rect = requested_rect;
+ frame_rect = [NSWindow frameRectForContentRect:content_rect
+ styleMask:style_mask];
+ frame_rect.origin = requested_rect.origin;
+ } else {
+ // Compute content rect from frame rect.
+ frame_rect = requested_rect;
+ content_rect = [NSWindow contentRectForFrameRect:frame_rect
+ styleMask:style_mask];
+ }
+
+ // Keep the frame inside the display work area.
+ const NSRect new_frame_rect =
+ ClampNSBoundsToWorkArea(frame_rect, display_bounds, display_work_area);
+ if (!NSEqualRects(frame_rect, new_frame_rect)) {
+ frame_rect = new_frame_rect;
+ content_rect = [NSWindow contentRectForFrameRect:frame_rect
+ styleMask:style_mask];
+ }
+}
+
+} // namespace
+
+CefBrowserPlatformDelegateNativeMac::CefBrowserPlatformDelegateNativeMac(
+ const CefWindowInfo& window_info,
+ SkColor background_color)
+ : CefBrowserPlatformDelegateNative(window_info, background_color),
+ host_window_created_(false) {}
+
+void CefBrowserPlatformDelegateNativeMac::BrowserDestroyed(
+ CefBrowserHostBase* browser) {
+ CefBrowserPlatformDelegateNative::BrowserDestroyed(browser);
+
+ if (host_window_created_) {
+ // Release the reference added in CreateHostWindow().
+ browser->Release();
+ }
+}
+
+bool CefBrowserPlatformDelegateNativeMac::CreateHostWindow() {
+ base::mac::ScopedNSAutoreleasePool autorelease_pool;
+
+ NSWindow* new_window = nil;
+
+ NSView* parent_view =
+ CAST_CEF_WINDOW_HANDLE_TO_NSVIEW(window_info_.parent_view);
+ NSRect browser_view_rect =
+ NSMakeRect(window_info_.bounds.x, window_info_.bounds.y,
+ window_info_.bounds.width, window_info_.bounds.height);
+
+ if (parent_view == nil) {
+ // TODO(port): If no x,y position is specified the window will always appear
+ // in the upper-left corner. Maybe there's a better default place to put it?
+ const gfx::Rect dip_bounds(
+ window_info_.bounds.x, window_info_.bounds.y,
+ window_info_.bounds.width <= 0 ? kDefaultWidth
+ : window_info_.bounds.width,
+ window_info_.bounds.height <= 0 ? kDefaultHeight
+ : window_info_.bounds.height);
+
+ // Calculate the equivalent frame and content area bounds.
+ NSRect frame_rect, content_rect;
+ GetNSBoundsInDisplay(dip_bounds, /*input_content_bounds=*/true,
+ kDefaultStyleMask, frame_rect, content_rect);
+
+ // Create a new window.
+ new_window = [[UnderlayOpenGLHostingWindow alloc]
+ initWithContentRect:content_rect
+ styleMask:kDefaultStyleMask
+ backing:NSBackingStoreBuffered
+ defer:NO];
+
+ // Create the delegate for control and browser window events.
+ [[CefWindowDelegate alloc] initWithWindow:new_window andBrowser:browser_];
+
+ parent_view = [new_window contentView];
+ browser_view_rect = [parent_view bounds];
+
+ window_info_.parent_view = parent_view;
+
+ // Make the content view for the window have a layer. This will make all
+ // sub-views have layers. This is necessary to ensure correct layer
+ // ordering of all child views and their layers.
+ [parent_view setWantsLayer:YES];
+
+ // Place the window at the target point. This is required for proper
+ // placement if the point is on a secondary display.
+ [new_window setFrameOrigin:frame_rect.origin];
+ }
+
+ host_window_created_ = true;
+
+ // Add a reference that will be released in BrowserDestroyed().
+ browser_->AddRef();
+
+ // Create the browser view.
+ CefBrowserHostView* browser_view =
+ [[CefBrowserHostView alloc] initWithFrame:browser_view_rect];
+ browser_view.browser = browser_;
+ [parent_view addSubview:browser_view];
+ [browser_view setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
+ [browser_view setNeedsDisplay:YES];
+ [browser_view release];
+
+ // Parent the WebContents to the browser view.
+ const NSRect bounds = [browser_view bounds];
+ NSView* native_view = web_contents_->GetNativeView().GetNativeNSView();
+ [browser_view addSubview:native_view];
+ [native_view setFrame:bounds];
+ [native_view setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
+ [native_view setNeedsDisplay:YES];
+
+ window_info_.view = browser_view;
+
+ if (new_window != nil && !window_info_.hidden) {
+ // Show the window.
+ [new_window makeKeyAndOrderFront:nil];
+ }
+
+ return true;
+}
+
+void CefBrowserPlatformDelegateNativeMac::CloseHostWindow() {
+ NSView* nsview = CAST_CEF_WINDOW_HANDLE_TO_NSVIEW(window_info_.view);
+ if (nsview != nil) {
+ [[nsview window] performSelectorOnMainThread:@selector(performClose:)
+ withObject:nil
+ waitUntilDone:NO];
+ }
+}
+
+CefWindowHandle CefBrowserPlatformDelegateNativeMac::GetHostWindowHandle()
+ const {
+ if (windowless_handler_) {
+ return windowless_handler_->GetParentWindowHandle();
+ }
+ return window_info_.view;
+}
+
+void CefBrowserPlatformDelegateNativeMac::SendKeyEvent(
+ const CefKeyEvent& event) {
+ auto view = GetHostView();
+ if (!view) {
+ return;
+ }
+
+ content::NativeWebKeyboardEvent web_event = TranslateWebKeyEvent(event);
+ view->ForwardKeyboardEvent(web_event, ui::LatencyInfo());
+}
+
+void CefBrowserPlatformDelegateNativeMac::SendMouseClickEvent(
+ const CefMouseEvent& event,
+ CefBrowserHost::MouseButtonType type,
+ bool mouseUp,
+ int clickCount) {
+ auto view = GetHostView();
+ if (!view) {
+ return;
+ }
+
+ blink::WebMouseEvent web_event =
+ TranslateWebClickEvent(event, type, mouseUp, clickCount);
+ view->RouteOrProcessMouseEvent(web_event);
+}
+
+void CefBrowserPlatformDelegateNativeMac::SendMouseMoveEvent(
+ const CefMouseEvent& event,
+ bool mouseLeave) {
+ auto view = GetHostView();
+ if (!view) {
+ return;
+ }
+
+ blink::WebMouseEvent web_event = TranslateWebMoveEvent(event, mouseLeave);
+ view->RouteOrProcessMouseEvent(web_event);
+}
+
+void CefBrowserPlatformDelegateNativeMac::SendMouseWheelEvent(
+ const CefMouseEvent& event,
+ int deltaX,
+ int deltaY) {
+ auto view = GetHostView();
+ if (!view) {
+ return;
+ }
+
+ blink::WebMouseWheelEvent web_event =
+ TranslateWebWheelEvent(event, deltaX, deltaY);
+ view->RouteOrProcessMouseEvent(web_event);
+}
+
+void CefBrowserPlatformDelegateNativeMac::SendTouchEvent(
+ const CefTouchEvent& event) {
+ NOTIMPLEMENTED();
+}
+
+void CefBrowserPlatformDelegateNativeMac::SetFocus(bool setFocus) {
+ auto view = GetHostView();
+ if (view) {
+ view->SetActive(setFocus);
+
+ if (setFocus) {
+ // Give keyboard focus to the native view.
+ NSView* nsview = web_contents_->GetContentNativeView().GetNativeNSView();
+ DCHECK([nsview canBecomeKeyView]);
+ [[nsview window] makeFirstResponder:nsview];
+ }
+ }
+}
+
+gfx::Point CefBrowserPlatformDelegateNativeMac::GetScreenPoint(
+ const gfx::Point& view,
+ bool want_dip_coords) const {
+ // Mac always operates in DIP coordinates so |want_dip_coords| is ignored.
+ if (windowless_handler_) {
+ return windowless_handler_->GetParentScreenPoint(view, want_dip_coords);
+ }
+
+ NSView* nsview = CAST_CEF_WINDOW_HANDLE_TO_NSVIEW(window_info_.parent_view);
+ if (nsview) {
+ NSRect bounds = [nsview bounds];
+ NSPoint view_pt = {static_cast<CGFloat>(view.x()),
+ bounds.size.height - static_cast<CGFloat>(view.y())};
+ NSPoint window_pt = [nsview convertPoint:view_pt toView:nil];
+ NSPoint screen_pt =
+ ui::ConvertPointFromWindowToScreen([nsview window], window_pt);
+ return gfx::Point(screen_pt.x, screen_pt.y);
+ }
+ return gfx::Point();
+}
+
+void CefBrowserPlatformDelegateNativeMac::ViewText(const std::string& text) {
+ // TODO(cef): Implement this functionality.
+ NOTIMPLEMENTED();
+}
+
+bool CefBrowserPlatformDelegateNativeMac::HandleKeyboardEvent(
+ const content::NativeWebKeyboardEvent& event) {
+ // Give the top level menu equivalents a chance to handle the event.
+ if ([event.os_event type] == NSEventTypeKeyDown) {
+ return [[NSApp mainMenu] performKeyEquivalent:event.os_event];
+ }
+ return false;
+}
+
+// static
+void CefBrowserPlatformDelegate::HandleExternalProtocol(const GURL& url) {}
+
+CefEventHandle CefBrowserPlatformDelegateNativeMac::GetEventHandle(
+ const content::NativeWebKeyboardEvent& event) const {
+ return event.os_event;
+}
+
+std::unique_ptr<CefJavaScriptDialogRunner>
+CefBrowserPlatformDelegateNativeMac::CreateJavaScriptDialogRunner() {
+ return base::WrapUnique(new CefJavaScriptDialogRunnerMac);
+}
+
+std::unique_ptr<CefMenuRunner>
+CefBrowserPlatformDelegateNativeMac::CreateMenuRunner() {
+ return base::WrapUnique(new CefMenuRunnerMac);
+}
+
+content::NativeWebKeyboardEvent
+CefBrowserPlatformDelegateNativeMac::TranslateWebKeyEvent(
+ const CefKeyEvent& key_event) const {
+ content::NativeWebKeyboardEvent result(
+ blink::WebInputEvent::Type::kUndefined,
+ blink::WebInputEvent::Modifiers::kNoModifiers, ui::EventTimeForNow());
+
+ // Use a synthetic NSEvent in order to obtain the windowsKeyCode member from
+ // the NativeWebKeyboardEvent constructor. This is the only member which can
+ // not be easily translated (without hardcoding keyCodes)
+ // Determining whether a modifier key is left or right seems to be done
+ // through the key code as well.
+ NSEventType event_type;
+ if (key_event.character == 0 && key_event.unmodified_character == 0) {
+ // Check if both character and unmodified_characther are empty to determine
+ // if this was a NSEventTypeFlagsChanged event.
+ // A dead key will have an empty character, but a non-empty unmodified
+ // character
+ event_type = NSEventTypeFlagsChanged;
+ } else {
+ switch (key_event.type) {
+ case KEYEVENT_RAWKEYDOWN:
+ case KEYEVENT_KEYDOWN:
+ case KEYEVENT_CHAR:
+ event_type = NSEventTypeKeyDown;
+ break;
+ case KEYEVENT_KEYUP:
+ event_type = NSEventTypeKeyUp;
+ break;
+ }
+ }
+
+ NSString* charactersIgnoringModifiers =
+ [[[NSString alloc] initWithCharacters:&key_event.unmodified_character
+ length:1] autorelease];
+ NSString* characters =
+ [[[NSString alloc] initWithCharacters:&key_event.character
+ length:1] autorelease];
+
+ NSEvent* synthetic_event =
+ [NSEvent keyEventWithType:event_type
+ location:NSMakePoint(0, 0)
+ modifierFlags:NativeModifiers(key_event.modifiers)
+ timestamp:currentEventTimestamp()
+ windowNumber:0
+ context:nil
+ characters:characters
+ charactersIgnoringModifiers:charactersIgnoringModifiers
+ isARepeat:NO
+ keyCode:key_event.native_key_code];
+
+ result = content::NativeWebKeyboardEvent(synthetic_event);
+ if (key_event.type == KEYEVENT_CHAR) {
+ result.SetType(blink::WebInputEvent::Type::kChar);
+ }
+
+ result.is_system_key = key_event.is_system_key;
+
+ return result;
+}
+
+blink::WebMouseEvent
+CefBrowserPlatformDelegateNativeMac::TranslateWebClickEvent(
+ const CefMouseEvent& mouse_event,
+ CefBrowserHost::MouseButtonType type,
+ bool mouseUp,
+ int clickCount) const {
+ blink::WebMouseEvent result;
+ TranslateWebMouseEvent(result, mouse_event);
+
+ switch (type) {
+ case MBT_LEFT:
+ result.SetType(mouseUp ? blink::WebInputEvent::Type::kMouseUp
+ : blink::WebInputEvent::Type::kMouseDown);
+ result.button = blink::WebMouseEvent::Button::kLeft;
+ break;
+ case MBT_MIDDLE:
+ result.SetType(mouseUp ? blink::WebInputEvent::Type::kMouseUp
+ : blink::WebInputEvent::Type::kMouseDown);
+ result.button = blink::WebMouseEvent::Button::kMiddle;
+ break;
+ case MBT_RIGHT:
+ result.SetType(mouseUp ? blink::WebInputEvent::Type::kMouseUp
+ : blink::WebInputEvent::Type::kMouseDown);
+ result.button = blink::WebMouseEvent::Button::kRight;
+ break;
+ default:
+ NOTREACHED();
+ }
+
+ result.click_count = clickCount;
+
+ return result;
+}
+
+blink::WebMouseEvent CefBrowserPlatformDelegateNativeMac::TranslateWebMoveEvent(
+ const CefMouseEvent& mouse_event,
+ bool mouseLeave) const {
+ blink::WebMouseEvent result;
+ TranslateWebMouseEvent(result, mouse_event);
+
+ if (!mouseLeave) {
+ result.SetType(blink::WebInputEvent::Type::kMouseMove);
+ if (mouse_event.modifiers & EVENTFLAG_LEFT_MOUSE_BUTTON) {
+ result.button = blink::WebMouseEvent::Button::kLeft;
+ } else if (mouse_event.modifiers & EVENTFLAG_MIDDLE_MOUSE_BUTTON) {
+ result.button = blink::WebMouseEvent::Button::kMiddle;
+ } else if (mouse_event.modifiers & EVENTFLAG_RIGHT_MOUSE_BUTTON) {
+ result.button = blink::WebMouseEvent::Button::kRight;
+ } else {
+ result.button = blink::WebMouseEvent::Button::kNoButton;
+ }
+ } else {
+ result.SetType(blink::WebInputEvent::Type::kMouseLeave);
+ result.button = blink::WebMouseEvent::Button::kNoButton;
+ }
+
+ result.click_count = 0;
+
+ return result;
+}
+
+blink::WebMouseWheelEvent
+CefBrowserPlatformDelegateNativeMac::TranslateWebWheelEvent(
+ const CefMouseEvent& mouse_event,
+ int deltaX,
+ int deltaY) const {
+ blink::WebMouseWheelEvent result;
+ TranslateWebMouseEvent(result, mouse_event);
+
+ result.SetType(blink::WebInputEvent::Type::kMouseWheel);
+
+ static const double scrollbarPixelsPerCocoaTick = 40.0;
+ result.delta_x = deltaX;
+ result.delta_y = deltaY;
+ result.wheel_ticks_x = deltaX / scrollbarPixelsPerCocoaTick;
+ result.wheel_ticks_y = deltaY / scrollbarPixelsPerCocoaTick;
+ result.delta_units = ui::ScrollGranularity::kScrollByPrecisePixel;
+
+ if (mouse_event.modifiers & EVENTFLAG_LEFT_MOUSE_BUTTON) {
+ result.button = blink::WebMouseEvent::Button::kLeft;
+ } else if (mouse_event.modifiers & EVENTFLAG_MIDDLE_MOUSE_BUTTON) {
+ result.button = blink::WebMouseEvent::Button::kMiddle;
+ } else if (mouse_event.modifiers & EVENTFLAG_RIGHT_MOUSE_BUTTON) {
+ result.button = blink::WebMouseEvent::Button::kRight;
+ } else {
+ result.button = blink::WebMouseEvent::Button::kNoButton;
+ }
+
+ return result;
+}
+
+void CefBrowserPlatformDelegateNativeMac::TranslateWebMouseEvent(
+ blink::WebMouseEvent& result,
+ const CefMouseEvent& mouse_event) const {
+ // position
+ result.SetPositionInWidget(mouse_event.x, mouse_event.y);
+
+ const gfx::Point& screen_pt = GetScreenPoint(
+ gfx::Point(mouse_event.x, mouse_event.y), /*want_dip_coords=*/true);
+ result.SetPositionInScreen(screen_pt.x(), screen_pt.y());
+
+ // modifiers
+ result.SetModifiers(result.GetModifiers() |
+ TranslateWebEventModifiers(mouse_event.modifiers));
+
+ // timestamp
+ result.SetTimeStamp(base::TimeTicks() +
+ base::Seconds(currentEventTimestamp()));
+
+ result.pointer_type = blink::WebPointerProperties::PointerType::kMouse;
+}
+
+content::RenderWidgetHostViewMac*
+CefBrowserPlatformDelegateNativeMac::GetHostView() const {
+ if (!web_contents_) {
+ return nullptr;
+ }
+ return static_cast<content::RenderWidgetHostViewMac*>(
+ web_contents_->GetRenderWidgetHostView());
+}
diff --git a/libcef/browser/native/browser_platform_delegate_native_win.cc b/libcef/browser/native/browser_platform_delegate_native_win.cc
new file mode 100644
index 00000000..d983f532
--- /dev/null
+++ b/libcef/browser/native/browser_platform_delegate_native_win.cc
@@ -0,0 +1,706 @@
+// Copyright 2015 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/native/browser_platform_delegate_native_win.h"
+
+#include <shellapi.h>
+#include <wininet.h>
+#include <winspool.h>
+
+#include "libcef/browser/alloy/alloy_browser_host_impl.h"
+#include "libcef/browser/context.h"
+#include "libcef/browser/native/window_delegate_view.h"
+#include "libcef/browser/screen_util.h"
+#include "libcef/browser/thread_util.h"
+
+#include "base/base_paths_win.h"
+#include "base/files/file_util.h"
+#include "base/path_service.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/win/registry.h"
+#include "base/win/win_util.h"
+#include "content/public/browser/native_web_keyboard_event.h"
+#include "third_party/blink/public/common/input/web_mouse_event.h"
+#include "third_party/blink/public/common/input/web_mouse_wheel_event.h"
+#include "ui/aura/window.h"
+#include "ui/base/win/shell.h"
+#include "ui/display/display.h"
+#include "ui/display/screen.h"
+#include "ui/display/win/screen_win.h"
+#include "ui/events/keycodes/dom/dom_key.h"
+#include "ui/events/keycodes/dom/keycode_converter.h"
+#include "ui/events/keycodes/keyboard_code_conversion_win.h"
+#include "ui/events/keycodes/platform_key_map_win.h"
+#include "ui/gfx/geometry/vector2d.h"
+#include "ui/gfx/win/hwnd_util.h"
+#include "ui/views/widget/desktop_aura/desktop_window_tree_host_win.h"
+#include "ui/views/widget/widget.h"
+#include "ui/views/win/hwnd_util.h"
+
+#pragma comment(lib, "dwmapi.lib")
+
+namespace {
+
+void WriteTempFileAndView(const std::string& data) {
+ CEF_REQUIRE_BLOCKING();
+
+ base::FilePath tmp_file;
+ if (!base::CreateTemporaryFile(&tmp_file)) {
+ return;
+ }
+
+ // The shell command will look at the file extension to identify the correct
+ // program to open.
+ tmp_file = tmp_file.AddExtension(L"txt");
+
+ int write_ct = base::WriteFile(tmp_file, data.c_str(), data.size());
+ DCHECK_EQ(static_cast<int>(data.size()), write_ct);
+
+ ui::win::OpenFileViaShell(tmp_file);
+}
+
+bool HasExternalHandler(const std::string& scheme) {
+ base::win::RegKey key;
+ const std::wstring registry_path =
+ base::ASCIIToWide(scheme + "\\shell\\open\\command");
+ key.Open(HKEY_CLASSES_ROOT, registry_path.c_str(), KEY_READ);
+ if (key.Valid()) {
+ DWORD size = 0;
+ key.ReadValue(NULL, NULL, &size, NULL);
+ if (size > 2) {
+ // ShellExecute crashes the process when the command is empty.
+ // We check for "2" because it always returns the trailing NULL.
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// Match the logic in chrome/browser/platform_util_win.cc
+// OpenExternalOnWorkerThread.
+void ExecuteExternalProtocol(const GURL& url) {
+ CEF_REQUIRE_BLOCKING();
+
+ if (!HasExternalHandler(url.scheme())) {
+ return;
+ }
+
+ // Quote the input scheme to be sure that the command does not have
+ // parameters unexpected by the external program. This url should already
+ // have been escaped.
+ std::string escaped_url = url.spec();
+ escaped_url.insert(0, "\"");
+ escaped_url += "\"";
+
+ // According to Mozilla in uriloader/exthandler/win/nsOSHelperAppService.cpp:
+ // "Some versions of windows (Win2k before SP3, Win XP before SP1) crash in
+ // ShellExecute on long URLs (bug 161357 on bugzilla.mozilla.org). IE 5 and 6
+ // support URLS of 2083 chars in length, 2K is safe."
+ //
+ // It may be possible to increase this. https://crbug.com/727909
+ const size_t kMaxUrlLength = 2048;
+ if (escaped_url.length() > kMaxUrlLength) {
+ return;
+ }
+
+ // Specify %windir%\system32 as the CWD so that any new proc spawned does not
+ // inherit this proc's CWD. Without this, uninstalls may be broken by a
+ // long-lived child proc that holds a handle to the browser's version
+ // directory (the browser's CWD). A process's CWD is in the standard list of
+ // directories to search when loading a DLL, and precedes the system directory
+ // when safe DLL search mode is disabled (not the default). Setting the CWD to
+ // the system directory is a nice way to mitigate a potential DLL search order
+ // hijack for processes that don't implement their own mitigation.
+ base::FilePath system_dir;
+ base::PathService::Get(base::DIR_SYSTEM, &system_dir);
+ if (reinterpret_cast<ULONG_PTR>(ShellExecuteA(
+ NULL, "open", escaped_url.c_str(), NULL,
+ system_dir.AsUTF8Unsafe().c_str(), SW_SHOWNORMAL)) <= 32) {
+ // On failure, it may be good to display a message to the user.
+ // https://crbug.com/727913
+ return;
+ }
+}
+
+gfx::Rect GetDisplayWorkAreaNearestPoint(gfx::Point dip_point) {
+ const auto display =
+ display::Screen::GetScreen()->GetDisplayNearestPoint(dip_point);
+ // Work area in DIP.
+ return display.work_area();
+}
+
+CefRect GetScreenFrameRectFromDIPContentRect(HWND window,
+ gfx::Rect dip_rect,
+ DWORD style,
+ DWORD ex_style,
+ bool has_menu) {
+ // Convert from DIP using a method that can handle multiple displays with
+ // different DPI. If |window| is nullptr the closest display will be used.
+ const auto screen_rect =
+ display::win::ScreenWin::DIPToScreenRect(window, dip_rect);
+
+ RECT rect = {screen_rect.x(), screen_rect.y(),
+ screen_rect.x() + screen_rect.width(),
+ screen_rect.y() + screen_rect.height()};
+
+ AdjustWindowRectEx(&rect, style, has_menu, ex_style);
+
+ // Keep the original origin while potentially increasing the size to include
+ // the frame non-client area.
+ return CefRect(screen_rect.x(), screen_rect.y(), rect.right - rect.left,
+ rect.bottom - rect.top);
+}
+
+CefRect GetAdjustedScreenFrameRect(CefRect screen_rect,
+ DWORD style,
+ DWORD ex_style,
+ bool has_menu) {
+ // If height or width is not provided let the OS determine the position and
+ // size similar to Chromium behavior. Note that |CW_USEDEFAULT| cannot be
+ // stored in a gfx::Rect due to clamping.
+ if (screen_rect.width == CW_USEDEFAULT ||
+ screen_rect.height == CW_USEDEFAULT) {
+ return CefRect(CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT);
+ }
+
+ if (screen_rect.x == CW_USEDEFAULT) {
+ screen_rect.x = 0;
+ }
+
+ if (screen_rect.y == CW_USEDEFAULT) {
+ screen_rect.y = 0;
+ }
+
+ // Convert to DIP using a method that can handle multiple displays with
+ // different DPI.
+ const auto dip_rect = display::win::ScreenWin::ScreenToDIPRect(
+ nullptr, gfx::Rect(screen_rect.x, screen_rect.y, screen_rect.width,
+ screen_rect.height));
+ const auto visible_dip_rect = MakeVisibleOnScreenRect(
+ dip_rect, GetDisplayWorkAreaNearestPoint(dip_rect.origin()));
+
+ return GetScreenFrameRectFromDIPContentRect(
+ /*window=*/nullptr, visible_dip_rect, style, ex_style, has_menu);
+}
+
+} // namespace
+
+CefBrowserPlatformDelegateNativeWin::CefBrowserPlatformDelegateNativeWin(
+ const CefWindowInfo& window_info,
+ SkColor background_color)
+ : CefBrowserPlatformDelegateNativeAura(window_info, background_color) {}
+
+void CefBrowserPlatformDelegateNativeWin::set_widget(
+ views::Widget* widget,
+ CefWindowHandle widget_handle) {
+ DCHECK(!window_widget_);
+ window_widget_ = widget;
+ DCHECK(!window_info_.window);
+ window_info_.window = widget_handle;
+}
+
+void CefBrowserPlatformDelegateNativeWin::BrowserDestroyed(
+ CefBrowserHostBase* browser) {
+ CefBrowserPlatformDelegateNativeAura::BrowserDestroyed(browser);
+
+ if (host_window_created_) {
+ // Release the reference added in CreateHostWindow().
+ browser->Release();
+ }
+}
+
+bool CefBrowserPlatformDelegateNativeWin::CreateHostWindow() {
+ RegisterWindowClass();
+
+ if (window_info_.style == 0) {
+ // Client didn't intialize the CefWindowInfo. Provide reasonable defaults.
+ window_info_.SetAsPopup(nullptr, CefString());
+ }
+
+ has_frame_ = !(window_info_.style & WS_CHILD);
+
+ const std::wstring windowName(CefString(&window_info_.window_name));
+
+ CefRect window_rect = window_info_.bounds;
+
+ if (!window_info_.parent_window) {
+ const bool has_menu =
+ !(window_info_.style & WS_CHILD) && (window_info_.menu != NULL);
+ window_rect = GetAdjustedScreenFrameRect(window_rect, window_info_.style,
+ window_info_.ex_style, has_menu);
+ }
+
+ // Create the new browser window.
+ CreateWindowEx(window_info_.ex_style, GetWndClass(), windowName.c_str(),
+ window_info_.style, window_rect.x, window_rect.y,
+ window_rect.width, window_rect.height,
+ window_info_.parent_window, window_info_.menu,
+ ::GetModuleHandle(NULL), this);
+
+ // It's possible for CreateWindowEx to fail if the parent window was
+ // destroyed between the call to CreateBrowser and the above one.
+ DCHECK(window_info_.window);
+ if (!window_info_.window) {
+ return false;
+ }
+
+ host_window_created_ = true;
+
+ // Add a reference that will later be released in DestroyBrowser().
+ browser_->AddRef();
+
+ if (!called_enable_non_client_dpi_scaling_ && has_frame_ &&
+ base::win::IsProcessPerMonitorDpiAware()) {
+ // This call gets Windows to scale the non-client area when WM_DPICHANGED
+ // is fired on Windows versions < 10.0.14393.0.
+ // Derived signature; not available in headers.
+ static auto enable_child_window_dpi_message_func = []() {
+ using EnableChildWindowDpiMessagePtr = LRESULT(WINAPI*)(HWND, BOOL);
+ return reinterpret_cast<EnableChildWindowDpiMessagePtr>(GetProcAddress(
+ GetModuleHandle(L"user32.dll"), "EnableChildWindowDpiMessage"));
+ }();
+ if (enable_child_window_dpi_message_func) {
+ enable_child_window_dpi_message_func(window_info_.window, TRUE);
+ }
+ }
+
+ DCHECK(!window_widget_);
+
+ RECT cr;
+ GetClientRect(window_info_.window, &cr);
+
+ // Convert to DIP using a method that can handle multiple displays with
+ // different DPI. Client coordinates always have origin (0,0).
+ const gfx::Rect dip_rect = display::win::ScreenWin::ScreenToDIPRect(
+ window_info_.window, gfx::Rect(0, 0, cr.right, cr.bottom));
+
+ // Stay on top if top-most window hosting the web view is topmost.
+ HWND top_level_window = GetAncestor(window_info_.window, GA_ROOT);
+ DWORD top_level_window_ex_styles =
+ GetWindowLongPtr(top_level_window, GWL_EXSTYLE);
+ bool always_on_top =
+ (top_level_window_ex_styles & WS_EX_TOPMOST) == WS_EX_TOPMOST;
+
+ CefWindowDelegateView* delegate_view = new CefWindowDelegateView(
+ GetBackgroundColor(), always_on_top, GetBoundsChangedCallback(),
+ GetWidgetDeleteCallback());
+ delegate_view->Init(window_info_.window, web_contents_,
+ gfx::Rect(0, 0, dip_rect.width(), dip_rect.height()));
+
+ window_widget_ = delegate_view->GetWidget();
+
+ const HWND widget_hwnd = HWNDForWidget(window_widget_);
+ DCHECK(widget_hwnd);
+ const DWORD widget_ex_styles = GetWindowLongPtr(widget_hwnd, GWL_EXSTYLE);
+
+ if (window_info_.ex_style & WS_EX_NOACTIVATE) {
+ // Add the WS_EX_NOACTIVATE style on the DesktopWindowTreeHostWin HWND
+ // so that HWNDMessageHandler::Show() called via Widget::Show() does not
+ // activate the window.
+ SetWindowLongPtr(widget_hwnd, GWL_EXSTYLE,
+ widget_ex_styles | WS_EX_NOACTIVATE);
+ }
+
+ window_widget_->Show();
+
+ if (window_info_.ex_style & WS_EX_NOACTIVATE) {
+ // Remove the WS_EX_NOACTIVATE style so that future mouse clicks inside the
+ // browser correctly activate and focus the window.
+ SetWindowLongPtr(widget_hwnd, GWL_EXSTYLE, widget_ex_styles);
+ }
+
+ return true;
+}
+
+void CefBrowserPlatformDelegateNativeWin::CloseHostWindow() {
+ if (window_info_.window != NULL) {
+ HWND frameWnd = GetAncestor(window_info_.window, GA_ROOT);
+ PostMessage(frameWnd, WM_CLOSE, 0, 0);
+ }
+}
+
+CefWindowHandle CefBrowserPlatformDelegateNativeWin::GetHostWindowHandle()
+ const {
+ if (windowless_handler_) {
+ return windowless_handler_->GetParentWindowHandle();
+ }
+ return window_info_.window;
+}
+
+views::Widget* CefBrowserPlatformDelegateNativeWin::GetWindowWidget() const {
+ return window_widget_;
+}
+
+void CefBrowserPlatformDelegateNativeWin::SetFocus(bool setFocus) {
+ if (!setFocus) {
+ return;
+ }
+
+ if (window_widget_) {
+ // Give native focus to the DesktopWindowTreeHostWin ("Chrome_WidgetWin_0")
+ // associated with the root window. The currently focused HWND may be
+ // "CefBrowserWindow" if we're called in response to our WndProc receiving
+ // the WM_SETFOCUS event (possibly due to "CefBrowserWindow" recieving the
+ // top-level WM_ACTIVATE event), or some other HWND if the client calls
+ // CefBrowserHost::SetFocus(true) directly. DesktopWindowTreeHostWin may
+ // also receive focus/blur and mouse click events from the OS directly, in
+ // which case this method will not be called but the below discussion still
+ // applies.
+ //
+ // The DesktopWindowTreeHostWin::HandleNativeFocus/HandleNativeBlur methods
+ // are called in response to WM_SETFOCUS/WM_KILLFOCUS respectively. The
+ // DesktopWindowTreeHostWin::HandleMouseEvent method is called if the user
+ // clicks on the WebContents. These methods have all been patched to call
+ // HandleActivationChanged (indirectly via ::SetFocus in the case of mouse
+ // clicks). HandleActivationChanged will then trigger the following
+ // behaviors:
+ // 1. Update focus/activation state of the aura::Window indirectly via
+ // wm::FocusController. This allows focus-related behaviors (e.g. focus
+ // rings, flashing caret, onFocus/onBlur JS events, etc.) to work as
+ // expected (see issue #1677) and also triggers an initial call to
+ // WebContents::Focus which gives logical focus to the
+ // RenderWidgetHostViewAura in the views hierarchy (see issue #3306).
+ // 2. Update focus state of the ui::InputMethod. If this does not occur
+ // then:
+ // (a) InputMethodBase::GetTextInputClient will return NULL and
+ // InputMethodWin::OnChar will fail to send character events to the
+ // renderer (see issue #1700); and
+ // (b) InputMethodWinBase::IsWindowFocused will return false due to
+ // ::GetFocus() returning the currently focused HWND (e.g.
+ // "CefBrowserWindow") instead of the expected "Chrome_WidgetWin_0" HWND,
+ // causing TSF not to handle IME events (see issue #3306). For this same
+ // reason, ::SetFocus needs to be called before WebContents::Focus which
+ // sends the InputMethod OnWillChangeFocusedClient notification that then
+ // calls IsWindowFocused (e.g. WebContents::Focus is intentionally called
+ // multiple times).
+ //
+ // This differs from activation in Chrome which is handled via
+ // HWNDMessageHandler::PostProcessActivateMessage (Widget::Show indirectly
+ // calls HWNDMessageHandler::Activate which calls ::SetForegroundWindow
+ // resulting in a WM_ACTIVATE message being sent to the window). The Chrome
+ // code path doesn't work for CEF because IsTopLevelWindow in
+ // hwnd_message_handler.cc will return false and consequently
+ // HWNDMessageHandler::PostProcessActivateMessage will not be called.
+ //
+ // Activation events are usually reserved for the top-level window so
+ // triggering activation based on focus events may be incorrect in some
+ // circumstances. Revisit this implementation if additional problems are
+ // discovered.
+ ::SetFocus(HWNDForWidget(window_widget_));
+ }
+
+ if (web_contents_) {
+ // Give logical focus to the RenderWidgetHostViewAura in the views
+ // hierarchy. This does not change the native keyboard focus. When
+ // |window_widget_| exists this additional Focus() call is necessary to
+ // correctly assign focus/input state after native focus resulting from
+ // window activation (see the InputMethod discussion above).
+ web_contents_->Focus();
+ }
+}
+
+void CefBrowserPlatformDelegateNativeWin::NotifyMoveOrResizeStarted() {
+ // Call the parent method to dismiss any existing popups.
+ CefBrowserPlatformDelegateNativeAura::NotifyMoveOrResizeStarted();
+
+ if (!window_widget_) {
+ return;
+ }
+
+ // Notify DesktopWindowTreeHostWin of move events so that screen rectangle
+ // information is communicated to the renderer process and popups are
+ // displayed in the correct location.
+ views::DesktopWindowTreeHostWin* tree_host =
+ static_cast<views::DesktopWindowTreeHostWin*>(
+ aura::WindowTreeHost::GetForAcceleratedWidget(
+ HWNDForWidget(window_widget_)));
+ DCHECK(tree_host);
+ if (tree_host) {
+ // Cast to HWNDMessageHandlerDelegate so we can access HandleMove().
+ static_cast<views::HWNDMessageHandlerDelegate*>(tree_host)->HandleMove();
+ }
+}
+
+void CefBrowserPlatformDelegateNativeWin::SizeTo(int width, int height) {
+ HWND window = window_info_.window;
+
+ const DWORD style = GetWindowLong(window, GWL_STYLE);
+ const DWORD ex_style = GetWindowLong(window, GWL_EXSTYLE);
+ const bool has_menu = !(style & WS_CHILD) && (GetMenu(window) != NULL);
+
+ const auto frame_rect = GetScreenFrameRectFromDIPContentRect(
+ window, gfx::Rect(0, 0, width, height), style, ex_style, has_menu);
+
+ // Size the window. The left/top values may be negative.
+ SetWindowPos(window, NULL, 0, 0, frame_rect.width, frame_rect.height,
+ SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
+}
+
+void CefBrowserPlatformDelegateNativeWin::ViewText(const std::string& text) {
+ CEF_POST_USER_VISIBLE_TASK(base::BindOnce(WriteTempFileAndView, text));
+}
+
+bool CefBrowserPlatformDelegateNativeWin::HandleKeyboardEvent(
+ const content::NativeWebKeyboardEvent& event) {
+ // Any unhandled keyboard/character messages are sent to DefWindowProc so that
+ // shortcut keys work correctly.
+ if (event.os_event) {
+ const auto& msg = event.os_event->native_event();
+ return !DefWindowProc(msg.hwnd, msg.message, msg.wParam, msg.lParam);
+ } else {
+ MSG msg = {};
+
+ msg.hwnd = GetHostWindowHandle();
+ if (!msg.hwnd) {
+ return false;
+ }
+
+ switch (event.GetType()) {
+ case blink::WebInputEvent::Type::kRawKeyDown:
+ msg.message = event.is_system_key ? WM_SYSKEYDOWN : WM_KEYDOWN;
+ break;
+ case blink::WebInputEvent::Type::kKeyUp:
+ msg.message = event.is_system_key ? WM_SYSKEYUP : WM_KEYUP;
+ break;
+ case blink::WebInputEvent::Type::kChar:
+ msg.message = event.is_system_key ? WM_SYSCHAR : WM_CHAR;
+ break;
+ default:
+ NOTREACHED();
+ return false;
+ }
+
+ msg.wParam = event.windows_key_code;
+
+ UINT scan_code = ::MapVirtualKeyW(event.windows_key_code, MAPVK_VK_TO_VSC);
+ msg.lParam = (scan_code << 16) | // key scan code
+ 1; // key repeat count
+ if (event.GetModifiers() & content::NativeWebKeyboardEvent::kAltKey) {
+ msg.lParam |= (1 << 29);
+ }
+
+ return !DefWindowProc(msg.hwnd, msg.message, msg.wParam, msg.lParam);
+ }
+}
+
+// static
+void CefBrowserPlatformDelegate::HandleExternalProtocol(const GURL& url) {
+ CEF_POST_USER_VISIBLE_TASK(base::BindOnce(ExecuteExternalProtocol, url));
+}
+
+CefEventHandle CefBrowserPlatformDelegateNativeWin::GetEventHandle(
+ const content::NativeWebKeyboardEvent& event) const {
+ if (!event.os_event) {
+ return NULL;
+ }
+ return ChromeToWindowsType(
+ const_cast<CHROME_MSG*>(&event.os_event->native_event()));
+}
+
+ui::KeyEvent CefBrowserPlatformDelegateNativeWin::TranslateUiKeyEvent(
+ const CefKeyEvent& key_event) const {
+ int flags = TranslateUiEventModifiers(key_event.modifiers);
+ ui::KeyboardCode key_code =
+ ui::KeyboardCodeForWindowsKeyCode(key_event.windows_key_code);
+ ui::DomCode dom_code =
+ ui::KeycodeConverter::NativeKeycodeToDomCode(key_event.native_key_code);
+ base::TimeTicks time_stamp = GetEventTimeStamp();
+
+ if (key_event.type == KEYEVENT_CHAR) {
+ return ui::KeyEvent(key_event.windows_key_code /* character */, key_code,
+ dom_code, flags, time_stamp);
+ }
+
+ ui::EventType type = ui::ET_UNKNOWN;
+ switch (key_event.type) {
+ case KEYEVENT_RAWKEYDOWN:
+ case KEYEVENT_KEYDOWN:
+ type = ui::ET_KEY_PRESSED;
+ break;
+ case KEYEVENT_KEYUP:
+ type = ui::ET_KEY_RELEASED;
+ break;
+ default:
+ NOTREACHED();
+ }
+
+ ui::DomKey dom_key =
+ ui::PlatformKeyMap::DomKeyFromKeyboardCode(key_code, &flags);
+ return ui::KeyEvent(type, key_code, dom_code, flags, dom_key, time_stamp);
+}
+
+gfx::Vector2d CefBrowserPlatformDelegateNativeWin::GetUiWheelEventOffset(
+ int deltaX,
+ int deltaY) const {
+ static const ULONG defaultScrollCharsPerWheelDelta = 1;
+ static const FLOAT scrollbarPixelsPerLine = 100.0f / 3.0f;
+ static const ULONG defaultScrollLinesPerWheelDelta = 3;
+
+ float wheelDeltaX = float(deltaX) / WHEEL_DELTA;
+ float wheelDeltaY = float(deltaY) / WHEEL_DELTA;
+ float scrollDeltaX = wheelDeltaX;
+ float scrollDeltaY = wheelDeltaY;
+
+ ULONG scrollChars = defaultScrollCharsPerWheelDelta;
+ SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0, &scrollChars, 0);
+ scrollDeltaX *= static_cast<FLOAT>(scrollChars) * scrollbarPixelsPerLine;
+
+ ULONG scrollLines = defaultScrollLinesPerWheelDelta;
+ SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &scrollLines, 0);
+ scrollDeltaY *= static_cast<FLOAT>(scrollLines) * scrollbarPixelsPerLine;
+
+ return gfx::Vector2d(scrollDeltaX, scrollDeltaY);
+}
+
+// static
+void CefBrowserPlatformDelegateNativeWin::RegisterWindowClass() {
+ static bool registered = false;
+ if (registered) {
+ return;
+ }
+
+ // Register the window class
+ WNDCLASSEX wcex = {
+ /* cbSize = */ sizeof(WNDCLASSEX),
+ /* style = */ CS_HREDRAW | CS_VREDRAW,
+ /* lpfnWndProc = */ CefBrowserPlatformDelegateNativeWin::WndProc,
+ /* cbClsExtra = */ 0,
+ /* cbWndExtra = */ 0,
+ /* hInstance = */ ::GetModuleHandle(NULL),
+ /* hIcon = */ NULL,
+ /* hCursor = */ LoadCursor(NULL, IDC_ARROW),
+ /* hbrBackground = */ 0,
+ /* lpszMenuName = */ NULL,
+ /* lpszClassName = */ CefBrowserPlatformDelegateNativeWin::GetWndClass(),
+ /* hIconSm = */ NULL,
+ };
+ RegisterClassEx(&wcex);
+
+ registered = true;
+}
+
+// static
+LPCTSTR CefBrowserPlatformDelegateNativeWin::GetWndClass() {
+ return L"CefBrowserWindow";
+}
+
+// static
+LRESULT CALLBACK CefBrowserPlatformDelegateNativeWin::WndProc(HWND hwnd,
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam) {
+ CefBrowserPlatformDelegateNativeWin* platform_delegate = nullptr;
+ CefBrowserHostBase* browser = nullptr;
+
+ if (message != WM_NCCREATE) {
+ platform_delegate = static_cast<CefBrowserPlatformDelegateNativeWin*>(
+ gfx::GetWindowUserData(hwnd));
+ if (platform_delegate) {
+ browser = platform_delegate->browser_;
+ }
+ }
+
+ switch (message) {
+ case WM_CLOSE:
+ if (browser && !browser->TryCloseBrowser()) {
+ // Cancel the close.
+ return 0;
+ }
+
+ // Allow the close.
+ break;
+
+ case WM_NCCREATE: {
+ CREATESTRUCT* cs = reinterpret_cast<CREATESTRUCT*>(lParam);
+ platform_delegate =
+ reinterpret_cast<CefBrowserPlatformDelegateNativeWin*>(
+ cs->lpCreateParams);
+ DCHECK(platform_delegate);
+ // Associate |platform_delegate| with the window handle.
+ gfx::SetWindowUserData(hwnd, platform_delegate);
+ platform_delegate->window_info_.window = hwnd;
+
+ if (platform_delegate->has_frame_ &&
+ base::win::IsProcessPerMonitorDpiAware()) {
+ // This call gets Windows to scale the non-client area when
+ // WM_DPICHANGED is fired on Windows versions >= 10.0.14393.0.
+ static auto enable_non_client_dpi_scaling_func = []() {
+ return reinterpret_cast<decltype(::EnableNonClientDpiScaling)*>(
+ GetProcAddress(GetModuleHandle(L"user32.dll"),
+ "EnableNonClientDpiScaling"));
+ }();
+ platform_delegate->called_enable_non_client_dpi_scaling_ =
+ !!(enable_non_client_dpi_scaling_func &&
+ enable_non_client_dpi_scaling_func(hwnd));
+ }
+ } break;
+
+ case WM_NCDESTROY:
+ if (platform_delegate) {
+ // Clear the user data pointer.
+ gfx::SetWindowUserData(hwnd, NULL);
+
+ // Force the browser to be destroyed. This will result in a call to
+ // BrowserDestroyed() that will release the reference added in
+ // CreateHostWindow().
+ static_cast<AlloyBrowserHostImpl*>(browser)->WindowDestroyed();
+ }
+ break;
+
+ case WM_SIZE:
+ if (platform_delegate && platform_delegate->window_widget_) {
+ // Pass window resize events to the HWND for the DesktopNativeWidgetAura
+ // root window. Passing size 0x0 (wParam == SIZE_MINIMIZED, for example)
+ // will cause the widget to be hidden which reduces resource usage.
+ RECT rc;
+ GetClientRect(hwnd, &rc);
+ SetWindowPos(HWNDForWidget(platform_delegate->window_widget_), NULL,
+ rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
+ SWP_NOZORDER);
+ }
+ return 0;
+
+ case WM_MOVING:
+ case WM_MOVE:
+ if (browser) {
+ browser->NotifyMoveOrResizeStarted();
+ }
+ return 0;
+
+ case WM_SETFOCUS:
+ // Selecting "Close window" from the task bar menu may send a focus
+ // notification even though the window is currently disabled (e.g. while
+ // a modal JS dialog is displayed).
+ if (browser && ::IsWindowEnabled(hwnd)) {
+ browser->SetFocus(true);
+ }
+ return 0;
+
+ case WM_ERASEBKGND:
+ return 0;
+
+ case WM_DPICHANGED:
+ if (platform_delegate && platform_delegate->has_frame_) {
+ // Suggested size and position of the current window scaled for the
+ // new DPI.
+ const RECT* rect = reinterpret_cast<RECT*>(lParam);
+ SetWindowPos(platform_delegate->GetHostWindowHandle(), NULL, rect->left,
+ rect->top, rect->right - rect->left,
+ rect->bottom - rect->top, SWP_NOZORDER | SWP_NOACTIVATE);
+ }
+ break;
+
+ case WM_ENABLE:
+ if (wParam == TRUE && browser) {
+ // Give focus to the browser after EnableWindow enables this window
+ // (e.g. after a modal dialog is dismissed).
+ browser->SetFocus(true);
+ return 0;
+ }
+ break;
+ }
+
+ return DefWindowProc(hwnd, message, wParam, lParam);
+}
diff --git a/libcef/browser/native/browser_platform_delegate_native_win.h b/libcef/browser/native/browser_platform_delegate_native_win.h
new file mode 100644
index 00000000..6d26b5a3
--- /dev/null
+++ b/libcef/browser/native/browser_platform_delegate_native_win.h
@@ -0,0 +1,56 @@
+// Copyright 2015 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_NATIVE_BROWSER_PLATFORM_DELEGATE_NATIVE_WIN_H_
+#define CEF_LIBCEF_BROWSER_NATIVE_BROWSER_PLATFORM_DELEGATE_NATIVE_WIN_H_
+
+#include <windows.h>
+
+#include "libcef/browser/native/browser_platform_delegate_native_aura.h"
+
+// Windowed browser implementation for Windows.
+class CefBrowserPlatformDelegateNativeWin
+ : public CefBrowserPlatformDelegateNativeAura {
+ public:
+ CefBrowserPlatformDelegateNativeWin(const CefWindowInfo& window_info,
+ SkColor background_color);
+
+ // Called from chrome_child_window.cc after |widget| is created.
+ void set_widget(views::Widget* widget, CefWindowHandle widget_handle);
+
+ // CefBrowserPlatformDelegate methods:
+ void BrowserDestroyed(CefBrowserHostBase* browser) override;
+ bool CreateHostWindow() override;
+ void CloseHostWindow() override;
+ CefWindowHandle GetHostWindowHandle() const override;
+ views::Widget* GetWindowWidget() const override;
+ void SetFocus(bool setFocus) override;
+ void NotifyMoveOrResizeStarted() override;
+ void SizeTo(int width, int height) override;
+ void ViewText(const std::string& text) override;
+ bool HandleKeyboardEvent(
+ const content::NativeWebKeyboardEvent& event) override;
+ CefEventHandle GetEventHandle(
+ const content::NativeWebKeyboardEvent& event) const override;
+
+ // CefBrowserPlatformDelegateNativeAura methods:
+ ui::KeyEvent TranslateUiKeyEvent(const CefKeyEvent& key_event) const override;
+ gfx::Vector2d GetUiWheelEventOffset(int deltaX, int deltaY) const override;
+
+ private:
+ static void RegisterWindowClass();
+ static LPCTSTR GetWndClass();
+ static LRESULT CALLBACK WndProc(HWND hwnd,
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam);
+
+ // True if the host window has been created.
+ bool host_window_created_ = false;
+
+ bool has_frame_ = false;
+ bool called_enable_non_client_dpi_scaling_ = false;
+};
+
+#endif // CEF_LIBCEF_BROWSER_NATIVE_BROWSER_PLATFORM_DELEGATE_NATIVE_WIN_H_
diff --git a/libcef/browser/native/cursor_util.cc b/libcef/browser/native/cursor_util.cc
new file mode 100644
index 00000000..2fb9204a
--- /dev/null
+++ b/libcef/browser/native/cursor_util.cc
@@ -0,0 +1,42 @@
+// Copyright 2020 The Chromium Embedded Framework Authors. Portions copyright
+// 2012 The Chromium Authors. All rights reserved. Use of this source code is
+// governed by a BSD-style license that can be found in the LICENSE file.
+
+#include "libcef/browser/native/cursor_util.h"
+
+#include "include/cef_client.h"
+
+#include "ui/base/cursor/mojom/cursor_type.mojom.h"
+
+namespace cursor_util {
+
+bool OnCursorChange(CefRefPtr<CefBrowser> browser,
+ const ui::Cursor& ui_cursor) {
+ auto client = browser->GetHost()->GetClient();
+ if (!client) {
+ return false;
+ }
+ auto handler = client->GetDisplayHandler();
+ if (!handler) {
+ return false;
+ }
+
+ const cef_cursor_type_t cursor_type =
+ static_cast<cef_cursor_type_t>(ui_cursor.type());
+ CefCursorInfo custom_cursor_info;
+ if (ui_cursor.type() == ui::mojom::CursorType::kCustom) {
+ custom_cursor_info.hotspot.x = ui_cursor.custom_hotspot().x();
+ custom_cursor_info.hotspot.y = ui_cursor.custom_hotspot().y();
+ custom_cursor_info.image_scale_factor = ui_cursor.image_scale_factor();
+ custom_cursor_info.buffer = ui_cursor.custom_bitmap().getPixels();
+ custom_cursor_info.size.width = ui_cursor.custom_bitmap().width();
+ custom_cursor_info.size.height = ui_cursor.custom_bitmap().height();
+ }
+
+ auto scoped_cursor_handle(ScopedCursorHandle::Create(browser, ui_cursor));
+ return handler->OnCursorChange(browser,
+ scoped_cursor_handle->GetCursorHandle(),
+ cursor_type, custom_cursor_info);
+}
+
+} // namespace cursor_util
diff --git a/libcef/browser/native/cursor_util.h b/libcef/browser/native/cursor_util.h
new file mode 100644
index 00000000..629d0fa6
--- /dev/null
+++ b/libcef/browser/native/cursor_util.h
@@ -0,0 +1,38 @@
+// Copyright 2020 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_NATIVE_CURSOR_UTIL_H_
+#define CEF_LIBCEF_BROWSER_NATIVE_CURSOR_UTIL_H_
+
+#include "include/cef_browser.h"
+
+#include <memory>
+
+#include "ui/base/cursor/cursor.h"
+#include "ui/base/cursor/mojom/cursor_type.mojom-forward.h"
+
+#if defined(USE_AURA)
+#include "ui/base/cursor/platform_cursor.h"
+#endif
+
+namespace cursor_util {
+
+// Scoped ownership of a native cursor handle.
+class ScopedCursorHandle {
+ public:
+ virtual ~ScopedCursorHandle() = default;
+
+ static std::unique_ptr<ScopedCursorHandle> Create(
+ CefRefPtr<CefBrowser> browser,
+ const ui::Cursor& ui_cursor);
+
+ virtual cef_cursor_handle_t GetCursorHandle() = 0;
+};
+
+// Returns true if the client handled the cursor change.
+bool OnCursorChange(CefRefPtr<CefBrowser> browser, const ui::Cursor& ui_cursor);
+
+} // namespace cursor_util
+
+#endif // CEF_LIBCEF_BROWSER_NATIVE_CURSOR_UTIL_H_
diff --git a/libcef/browser/native/cursor_util_aura.cc b/libcef/browser/native/cursor_util_aura.cc
new file mode 100644
index 00000000..ef3fc6b2
--- /dev/null
+++ b/libcef/browser/native/cursor_util_aura.cc
@@ -0,0 +1,153 @@
+// Copyright 2023 The Chromium Embedded Framework Authors. Portions copyright
+// 2012 The Chromium Authors. All rights reserved. Use of this source code is
+// governed by a BSD-style license that can be found in the LICENSE file.
+
+#include "libcef/browser/native/cursor_util.h"
+
+#include "libcef/browser/browser_host_base.h"
+
+#include "content/common/cursors/webcursor.h"
+#include "content/public/browser/render_widget_host_view.h"
+#include "ui/base/cursor/cursor_factory.h"
+#include "ui/base/cursor/mojom/cursor_type.mojom.h"
+#include "ui/display/display_util.h"
+#include "ui/wm/core/cursor_loader.h"
+
+#if BUILDFLAG(IS_LINUX)
+#include "ui/ozone/buildflags.h"
+#if BUILDFLAG(OZONE_PLATFORM_X11)
+#include "ui/base/x/x11_cursor.h"
+#elif BUILDFLAG(IS_OZONE)
+#include "ui/ozone/common/bitmap_cursor.h"
+#endif
+#endif // BUILDFLAG(IS_LINUX)
+
+#if BUILDFLAG(IS_WIN)
+#include "ui/base/win/win_cursor.h"
+#endif
+
+namespace cursor_util {
+
+namespace {
+
+display::ScreenInfo GetScreenInfo(CefRefPtr<CefBrowser> browser) {
+ display::ScreenInfo screen_info;
+
+ bool screen_info_set = false;
+ if (auto web_contents =
+ static_cast<CefBrowserHostBase*>(browser.get())->GetWebContents()) {
+ if (auto view = web_contents->GetRenderWidgetHostView()) {
+ const auto screen_infos = view->GetScreenInfos();
+ if (!screen_infos.screen_infos.empty()) {
+ screen_info = screen_infos.current();
+ screen_info_set = true;
+ }
+ }
+ }
+
+ if (!screen_info_set) {
+ display::DisplayUtil::GetDefaultScreenInfo(&screen_info);
+ }
+
+ return screen_info;
+}
+
+display::Display::Rotation OrientationAngleToRotation(
+ uint16_t orientation_angle) {
+ // The Display rotation and the ScreenInfo orientation are not the same
+ // angle. The former is the physical display rotation while the later is the
+ // rotation required by the content to be shown properly on the screen, in
+ // other words, relative to the physical display.
+ if (orientation_angle == 0) {
+ return display::Display::ROTATE_0;
+ }
+ if (orientation_angle == 90) {
+ return display::Display::ROTATE_270;
+ }
+ if (orientation_angle == 180) {
+ return display::Display::ROTATE_180;
+ }
+ if (orientation_angle == 270) {
+ return display::Display::ROTATE_90;
+ }
+ NOTREACHED();
+ return display::Display::ROTATE_0;
+}
+
+scoped_refptr<ui::PlatformCursor> ToPlatformCursor(
+ CefRefPtr<CefBrowser> browser,
+ const ui::Cursor& ui_cursor) {
+ wm::CursorLoader cursor_loader;
+ scoped_refptr<ui::PlatformCursor> platform_cursor;
+
+ ui::Cursor loaded_cursor = ui_cursor;
+
+ if (ui_cursor.type() == ui::mojom::CursorType::kCustom) {
+ platform_cursor = ui::CursorFactory::GetInstance()->CreateImageCursor(
+ ui::mojom::CursorType::kCustom, ui_cursor.custom_bitmap(),
+ ui_cursor.custom_hotspot());
+ } else {
+ const auto& screen_info = GetScreenInfo(browser);
+ cursor_loader.SetDisplayData(
+ OrientationAngleToRotation(screen_info.orientation_angle),
+ screen_info.device_scale_factor);
+
+ // Attempts to load the cursor via the platform or from pak resources.
+ cursor_loader.SetPlatformCursor(&loaded_cursor);
+ platform_cursor = loaded_cursor.platform();
+ }
+
+ return platform_cursor;
+}
+
+#if BUILDFLAG(IS_WIN)
+using CursorType = ui::WinCursor;
+inline cef_cursor_handle_t GetCursorHandleImpl(CursorType* cursor) {
+ return cursor->hcursor();
+}
+#elif BUILDFLAG(OZONE_PLATFORM_X11)
+// See https://crbug.com/1029142 for background.
+using CursorType = ui::X11Cursor;
+inline cef_cursor_handle_t GetCursorHandleImpl(CursorType* cursor) {
+ return static_cast<cef_cursor_handle_t>(cursor->xcursor());
+}
+#elif BUILDFLAG(IS_OZONE)
+using CursorType = ui::BitmapCursor;
+inline cef_cursor_handle_t GetCursorHandleImpl(CursorType* cursor) {
+ return static_cast<cef_cursor_handle_t>(cursor->platform_data());
+}
+#else
+#error Unsupported platform
+#endif
+
+class ScopedCursorHandleImpl : public ScopedCursorHandle {
+ public:
+ explicit ScopedCursorHandleImpl(
+ scoped_refptr<ui::PlatformCursor> platform_cursor) {
+ if (platform_cursor) {
+ cursor_ = CursorType::FromPlatformCursor(platform_cursor);
+ }
+ }
+
+ cef_cursor_handle_t GetCursorHandle() override {
+ if (cursor_) {
+ return GetCursorHandleImpl(cursor_.get());
+ }
+ return kNullCursorHandle;
+ }
+
+ private:
+ scoped_refptr<CursorType> cursor_;
+};
+
+} // namespace
+
+// static
+std::unique_ptr<ScopedCursorHandle> ScopedCursorHandle::Create(
+ CefRefPtr<CefBrowser> browser,
+ const ui::Cursor& ui_cursor) {
+ return std::make_unique<ScopedCursorHandleImpl>(
+ ToPlatformCursor(browser, ui_cursor));
+}
+
+} // namespace cursor_util
diff --git a/libcef/browser/native/cursor_util_mac.mm b/libcef/browser/native/cursor_util_mac.mm
new file mode 100644
index 00000000..c2ed9ac5
--- /dev/null
+++ b/libcef/browser/native/cursor_util_mac.mm
@@ -0,0 +1,38 @@
+// Copyright 2023 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#include "libcef/browser/native/cursor_util.h"
+
+#import "base/mac/scoped_nsobject.h"
+#import "ui/base/cocoa/cursor_utils.h"
+
+namespace cursor_util {
+
+namespace {
+
+class ScopedCursorHandleImpl : public ScopedCursorHandle {
+ public:
+ explicit ScopedCursorHandleImpl(NSCursor* native_cursor) {
+ if (native_cursor) {
+ cursor_.reset([native_cursor retain]);
+ }
+ }
+
+ cef_cursor_handle_t GetCursorHandle() override { return cursor_.get(); }
+
+ private:
+ base::scoped_nsobject<NSCursor> cursor_;
+};
+
+} // namespace
+
+// static
+std::unique_ptr<ScopedCursorHandle> ScopedCursorHandle::Create(
+ CefRefPtr<CefBrowser> /*browser*/,
+ const ui::Cursor& ui_cursor) {
+ return std::make_unique<ScopedCursorHandleImpl>(
+ ui::GetNativeCursor(ui_cursor));
+}
+
+} // namespace cursor_util
diff --git a/libcef/browser/native/javascript_dialog_runner_mac.h b/libcef/browser/native/javascript_dialog_runner_mac.h
new file mode 100644
index 00000000..6cfc99d6
--- /dev/null
+++ b/libcef/browser/native/javascript_dialog_runner_mac.h
@@ -0,0 +1,49 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors.
+// Portions copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_NATIVE_JAVASCRIPT_DIALOG_RUNNER_MAC_H_
+#define CEF_LIBCEF_BROWSER_NATIVE_JAVASCRIPT_DIALOG_RUNNER_MAC_H_
+#pragma once
+
+#include "libcef/browser/javascript_dialog_runner.h"
+
+#include "base/functional/callback.h"
+#include "base/mac/scoped_nsobject.h"
+#include "base/memory/weak_ptr.h"
+
+#if __OBJC__
+@class CefJavaScriptDialogHelper;
+#else
+class CefJavaScriptDialogHelper;
+#endif // __OBJC__
+
+class CefJavaScriptDialogRunnerMac : public CefJavaScriptDialogRunner {
+ public:
+ CefJavaScriptDialogRunnerMac();
+ ~CefJavaScriptDialogRunnerMac() override;
+
+ // CefJavaScriptDialogRunner methods:
+ void Run(CefBrowserHostBase* browser,
+ content::JavaScriptDialogType message_type,
+ const GURL& origin_url,
+ const std::u16string& message_text,
+ const std::u16string& default_prompt_text,
+ DialogClosedCallback callback) override;
+ void Handle(bool accept, const std::u16string* prompt_override) override;
+ void Cancel() override;
+
+ // Callback from CefJavaScriptDialogHelper when the dialog is closed.
+ void DialogClosed(bool success, const std::u16string& user_input);
+
+ private:
+ DialogClosedCallback callback_;
+
+ base::scoped_nsobject<CefJavaScriptDialogHelper> helper_;
+
+ // Must be the last member.
+ base::WeakPtrFactory<CefJavaScriptDialogRunnerMac> weak_ptr_factory_;
+};
+
+#endif // CEF_LIBCEF_BROWSER_NATIVE_JAVASCRIPT_DIALOG_RUNNER_MAC_H_
diff --git a/libcef/browser/native/javascript_dialog_runner_mac.mm b/libcef/browser/native/javascript_dialog_runner_mac.mm
new file mode 100644
index 00000000..5769aff8
--- /dev/null
+++ b/libcef/browser/native/javascript_dialog_runner_mac.mm
@@ -0,0 +1,188 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors.
+// Portions copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/native/javascript_dialog_runner_mac.h"
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/functional/bind.h"
+#include "base/strings/sys_string_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/url_formatter/elide_url.h"
+
+// Helper object that receives the notification that the dialog/sheet is
+// going away. Is responsible for cleaning itself up.
+@interface CefJavaScriptDialogHelper : NSObject <NSAlertDelegate> {
+ @private
+ base::scoped_nsobject<NSAlert> alert_;
+ NSTextField* textField_; // WEAK; owned by alert_
+
+ // Copies of the fields in CefJavaScriptDialog because they're private.
+ CefJavaScriptDialogRunner::DialogClosedCallback callback_;
+}
+
+- (id)initHelperWithCallback:
+ (CefJavaScriptDialogRunner::DialogClosedCallback)callback;
+- (NSAlert*)alert;
+- (NSTextField*)textField;
+- (void)alertDidEnd:(NSAlert*)alert
+ returnCode:(int)returnCode
+ contextInfo:(void*)contextInfo;
+- (void)cancel;
+
+@end
+
+@implementation CefJavaScriptDialogHelper
+
+- (id)initHelperWithCallback:
+ (CefJavaScriptDialogRunner::DialogClosedCallback)callback {
+ if (self = [super init]) {
+ callback_ = std::move(callback);
+ }
+
+ return self;
+}
+
+- (NSAlert*)alert {
+ alert_.reset([[NSAlert alloc] init]);
+ return alert_;
+}
+
+- (NSTextField*)textField {
+ textField_ = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 300, 22)];
+ [[textField_ cell] setLineBreakMode:NSLineBreakByTruncatingTail];
+ [alert_ setAccessoryView:textField_];
+ [[alert_ window] setInitialFirstResponder:textField_];
+ [textField_ release];
+
+ return textField_;
+}
+
+- (void)alertDidEnd:(NSAlert*)alert
+ returnCode:(int)returnCode
+ contextInfo:(void*)contextInfo {
+ if (returnCode == NSModalResponseStop) {
+ return;
+ }
+
+ bool success = returnCode == NSAlertFirstButtonReturn;
+ std::u16string input;
+ if (textField_) {
+ input = base::SysNSStringToUTF16([textField_ stringValue]);
+ }
+
+ std::move(callback_).Run(success, input);
+}
+
+- (void)cancel {
+ [NSApp endSheet:[alert_ window]];
+ alert_.reset();
+}
+
+@end
+
+CefJavaScriptDialogRunnerMac::CefJavaScriptDialogRunnerMac()
+ : weak_ptr_factory_(this) {}
+
+CefJavaScriptDialogRunnerMac::~CefJavaScriptDialogRunnerMac() {
+ Cancel();
+}
+
+void CefJavaScriptDialogRunnerMac::Run(
+ CefBrowserHostBase* browser,
+ content::JavaScriptDialogType message_type,
+ const GURL& origin_url,
+ const std::u16string& message_text,
+ const std::u16string& default_prompt_text,
+ DialogClosedCallback callback) {
+ DCHECK(!helper_.get());
+ callback_ = std::move(callback);
+
+ bool text_field = message_type == content::JAVASCRIPT_DIALOG_TYPE_PROMPT;
+ bool one_button = message_type == content::JAVASCRIPT_DIALOG_TYPE_ALERT;
+
+ helper_.reset([[CefJavaScriptDialogHelper alloc]
+ initHelperWithCallback:base::BindOnce(
+ &CefJavaScriptDialogRunnerMac::DialogClosed,
+ weak_ptr_factory_.GetWeakPtr())]);
+
+ // Show the modal dialog.
+ NSAlert* alert = [helper_ alert];
+ NSTextField* field = nil;
+ if (text_field) {
+ field = [helper_ textField];
+ [field setStringValue:base::SysUTF16ToNSString(default_prompt_text)];
+ }
+ [alert setDelegate:helper_];
+ [alert setInformativeText:base::SysUTF16ToNSString(message_text)];
+
+ std::u16string label;
+ switch (message_type) {
+ case content::JAVASCRIPT_DIALOG_TYPE_ALERT:
+ label = u"JavaScript Alert";
+ break;
+ case content::JAVASCRIPT_DIALOG_TYPE_PROMPT:
+ label = u"JavaScript Prompt";
+ break;
+ case content::JAVASCRIPT_DIALOG_TYPE_CONFIRM:
+ label = u"JavaScript Confirm";
+ break;
+ }
+
+ const std::u16string& display_url =
+ url_formatter::FormatUrlForSecurityDisplay(origin_url);
+ if (!display_url.empty()) {
+ label += u" - " + display_url;
+ }
+
+ [alert setMessageText:base::SysUTF16ToNSString(label)];
+
+ [alert addButtonWithTitle:@"OK"];
+ if (!one_button) {
+ NSButton* other = [alert addButtonWithTitle:@"Cancel"];
+ [other setKeyEquivalent:@"\e"];
+ }
+
+ // Calling beginSheetModalForWindow:nil is wrong API usage. For now work
+ // around the "callee requires a non-null argument" error that occurs when
+ // building with the 10.11 SDK. See http://crbug.com/383820 for related
+ // discussion.
+ // We can't use the newer beginSheetModalForWindow:completionHandler: variant
+ // because it fails silently when passed a nil argument (see issue #2726).
+ id nilArg = nil;
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+ [alert beginSheetModalForWindow:nilArg // nil here makes it app-modal
+ modalDelegate:helper_
+ didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:)
+ contextInfo:this];
+#pragma clang diagnostic pop
+
+ if ([alert accessoryView]) {
+ [[alert window] makeFirstResponder:[alert accessoryView]];
+ }
+}
+
+void CefJavaScriptDialogRunnerMac::Handle(
+ bool accept,
+ const std::u16string* prompt_override) {
+ if (helper_.get()) {
+ DialogClosed(accept, prompt_override ? *prompt_override : std::u16string());
+ }
+}
+
+void CefJavaScriptDialogRunnerMac::Cancel() {
+ if (helper_.get()) {
+ [helper_ cancel];
+ helper_.reset(nil);
+ }
+}
+
+void CefJavaScriptDialogRunnerMac::DialogClosed(
+ bool success,
+ const std::u16string& user_input) {
+ helper_.reset(nil);
+ std::move(callback_).Run(success, user_input);
+}
diff --git a/libcef/browser/native/menu_runner_mac.h b/libcef/browser/native/menu_runner_mac.h
new file mode 100644
index 00000000..44f3ef50
--- /dev/null
+++ b/libcef/browser/native/menu_runner_mac.h
@@ -0,0 +1,34 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_NATIVE_MENU_RUNNER_MAC_H_
+#define CEF_LIBCEF_BROWSER_NATIVE_MENU_RUNNER_MAC_H_
+#pragma once
+
+#include "libcef/browser/menu_runner.h"
+
+#include "base/mac/scoped_nsobject.h"
+
+#if __OBJC__
+@class MenuControllerCocoa;
+#else
+class MenuControllerCocoa;
+#endif
+
+class CefMenuRunnerMac : public CefMenuRunner {
+ public:
+ CefMenuRunnerMac();
+ ~CefMenuRunnerMac() override;
+
+ // CefMenuRunner methods.
+ bool RunContextMenu(AlloyBrowserHostImpl* browser,
+ CefMenuModelImpl* model,
+ const content::ContextMenuParams& params) override;
+ void CancelContextMenu() override;
+
+ private:
+ base::scoped_nsobject<MenuControllerCocoa> menu_controller_;
+};
+
+#endif // CEF_LIBCEF_BROWSER_NATIVE_MENU_RUNNER_MAC_H_
diff --git a/libcef/browser/native/menu_runner_mac.mm b/libcef/browser/native/menu_runner_mac.mm
new file mode 100644
index 00000000..9b3c766a
--- /dev/null
+++ b/libcef/browser/native/menu_runner_mac.mm
@@ -0,0 +1,92 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#include "libcef/browser/native/menu_runner_mac.h"
+
+#include "libcef/browser/alloy/alloy_browser_host_impl.h"
+
+#import "base/mac/scoped_sending_event.h"
+#include "base/task/current_thread.h"
+#import "ui/base/cocoa/menu_controller.h"
+#include "ui/gfx/geometry/point.h"
+
+CefMenuRunnerMac::CefMenuRunnerMac() {}
+
+CefMenuRunnerMac::~CefMenuRunnerMac() {}
+
+bool CefMenuRunnerMac::RunContextMenu(
+ AlloyBrowserHostImpl* browser,
+ CefMenuModelImpl* model,
+ const content::ContextMenuParams& params) {
+ // Create a menu controller based on the model.
+ menu_controller_.reset([[MenuControllerCocoa alloc]
+ initWithModel:model->model()
+ delegate:nil
+ useWithPopUpButtonCell:NO]);
+
+ // Keep the menu controller alive (by adding an additional retain) until after
+ // the menu has been dismissed. Otherwise it will crash if the browser is
+ // destroyed (and consequently the menu controller is destroyed) while the
+ // menu is still pending.
+ base::scoped_nsobject<MenuControllerCocoa> menu_controller_ref(
+ menu_controller_);
+
+ // Make sure events can be pumped while the menu is up.
+ base::CurrentThread::ScopedAllowApplicationTasksInNativeNestedLoop allow;
+
+ // One of the events that could be pumped is |window.close()|.
+ // User-initiated event-tracking loops protect against this by
+ // setting flags in -[CrApplication sendEvent:], but since
+ // web-content menus are initiated by IPC message the setup has to
+ // be done manually.
+ base::mac::ScopedSendingEvent sendingEventScoper;
+
+ // Show the menu. Blocks until the menu is dismissed.
+ if (browser->IsWindowless()) {
+ // Don't show the menu unless a native window handle exists.
+ if (!browser->GetWindowHandle()) {
+ return false;
+ }
+
+ const gfx::Point& screen_point = browser->GetScreenPoint(
+ gfx::Point(params.x, params.y), /*want_dip_coords=*/true);
+ NSPoint screen_position = NSPointFromCGPoint(screen_point.ToCGPoint());
+ [[menu_controller_ menu] popUpMenuPositioningItem:nil
+ atLocation:screen_position
+ inView:nil];
+ } else {
+ NSView* parent_view =
+ browser->web_contents()->GetContentNativeView().GetNativeNSView();
+
+ // Synthesize an event for the click, as there is no certainty that
+ // [NSApp currentEvent] will return a valid event.
+ NSEvent* currentEvent = [NSApp currentEvent];
+ NSWindow* window = [parent_view window];
+
+ NSPoint position = [window mouseLocationOutsideOfEventStream];
+
+ NSTimeInterval eventTime = [currentEvent timestamp];
+ NSEvent* clickEvent = [NSEvent mouseEventWithType:NSEventTypeRightMouseDown
+ location:position
+ modifierFlags:0
+ timestamp:eventTime
+ windowNumber:[window windowNumber]
+ context:nil
+ eventNumber:0
+ clickCount:1
+ pressure:1.0];
+
+ [NSMenu popUpContextMenu:[menu_controller_ menu]
+ withEvent:clickEvent
+ forView:parent_view];
+ }
+
+ return true;
+}
+
+void CefMenuRunnerMac::CancelContextMenu() {
+ if (menu_controller_.get()) {
+ [menu_controller_ cancel];
+ }
+}
diff --git a/libcef/browser/native/menu_runner_views_aura.cc b/libcef/browser/native/menu_runner_views_aura.cc
new file mode 100644
index 00000000..2b0accc4
--- /dev/null
+++ b/libcef/browser/native/menu_runner_views_aura.cc
@@ -0,0 +1,53 @@
+// Copyright 2014 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#include "libcef/browser/native/menu_runner_views_aura.h"
+
+#include "libcef/browser/alloy/alloy_browser_host_impl.h"
+
+#include "base/strings/string_util.h"
+#include "ui/gfx/geometry/point.h"
+
+CefMenuRunnerViewsAura::CefMenuRunnerViewsAura() {}
+
+bool CefMenuRunnerViewsAura::RunContextMenu(
+ AlloyBrowserHostImpl* browser,
+ CefMenuModelImpl* model,
+ const content::ContextMenuParams& params) {
+ views::Widget* widget = nullptr;
+ gfx::AcceleratedWidget parent_widget = gfx::kNullAcceleratedWidget;
+ if (browser->IsWindowless()) {
+ parent_widget = browser->GetWindowHandle();
+ if (!parent_widget) {
+ LOG(ERROR) << "Window handle is required for default OSR context menu.";
+ return false;
+ }
+ } else {
+ widget = browser->GetWindowWidget();
+ }
+
+ menu_.reset(
+ new views::MenuRunner(model->model(), views::MenuRunner::CONTEXT_MENU));
+
+ gfx::Point screen_point = browser->GetScreenPoint(
+ gfx::Point(params.x, params.y), /*want_dip_coords=*/true);
+
+ menu_->RunMenuAt(widget, nullptr, gfx::Rect(screen_point, gfx::Size()),
+ views::MenuAnchorPosition::kTopRight, ui::MENU_SOURCE_NONE,
+ /*native_view_for_gestures=*/nullptr, parent_widget);
+
+ return true;
+}
+
+void CefMenuRunnerViewsAura::CancelContextMenu() {
+ if (menu_) {
+ menu_->Cancel();
+ }
+}
+
+bool CefMenuRunnerViewsAura::FormatLabel(std::u16string& label) {
+ // Remove the accelerator indicator (&) from label strings.
+ const std::u16string::value_type replace[] = {u'&', 0};
+ return base::ReplaceChars(label, replace, std::u16string(), &label);
+}
diff --git a/libcef/browser/native/menu_runner_views_aura.h b/libcef/browser/native/menu_runner_views_aura.h
new file mode 100644
index 00000000..c930441b
--- /dev/null
+++ b/libcef/browser/native/menu_runner_views_aura.h
@@ -0,0 +1,28 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_NATIVE_MENU_RUNNER_VIEWS_AURA_H_
+#define CEF_LIBCEF_BROWSER_NATIVE_MENU_RUNNER_VIEWS_AURA_H_
+#pragma once
+
+#include "libcef/browser/menu_runner.h"
+
+#include "ui/views/controls/menu/menu_runner.h"
+
+class CefMenuRunnerViewsAura : public CefMenuRunner {
+ public:
+ CefMenuRunnerViewsAura();
+
+ // CefMenuRunner methods.
+ bool RunContextMenu(AlloyBrowserHostImpl* browser,
+ CefMenuModelImpl* model,
+ const content::ContextMenuParams& params) override;
+ void CancelContextMenu() override;
+ bool FormatLabel(std::u16string& label) override;
+
+ private:
+ std::unique_ptr<views::MenuRunner> menu_;
+};
+
+#endif // CEF_LIBCEF_BROWSER_NATIVE_MENU_RUNNER_VIEWS_AURA_H_
diff --git a/libcef/browser/native/window_delegate_view.cc b/libcef/browser/native/window_delegate_view.cc
new file mode 100644
index 00000000..13b30590
--- /dev/null
+++ b/libcef/browser/native/window_delegate_view.cc
@@ -0,0 +1,98 @@
+// Copyright 2014 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#include "libcef/browser/native/window_delegate_view.h"
+
+#include <utility>
+
+#include "content/public/browser/web_contents.h"
+#include "ui/views/background.h"
+#include "ui/views/controls/webview/webview.h"
+#include "ui/views/layout/fill_layout.h"
+#include "ui/views/widget/widget.h"
+
+CefWindowDelegateView::CefWindowDelegateView(
+ SkColor background_color,
+ bool always_on_top,
+ base::RepeatingClosure on_bounds_changed,
+ base::OnceClosure on_delete)
+ : background_color_(background_color),
+ always_on_top_(always_on_top),
+ on_bounds_changed_(std::move(on_bounds_changed)),
+ on_delete_(std::move(on_delete)) {}
+
+void CefWindowDelegateView::Init(gfx::AcceleratedWidget parent_widget,
+ content::WebContents* web_contents,
+ const gfx::Rect& bounds) {
+ DCHECK(!web_view_);
+ web_view_ = new views::WebView(web_contents->GetBrowserContext());
+ web_view_->SetWebContents(web_contents);
+ web_view_->SetPreferredSize(bounds.size());
+
+ SetCanResize(true);
+
+ views::Widget* widget = new views::Widget;
+
+ // See CalculateWindowStylesFromInitParams in
+ // ui/views/widget/widget_hwnd_utils.cc for the conversion of |params| to
+ // Windows style flags.
+ views::Widget::InitParams params;
+ params.parent_widget = parent_widget;
+ params.bounds = bounds;
+ params.delegate = this;
+ // Set the WS_CHILD flag.
+ params.child = true;
+ // Set the WS_VISIBLE flag.
+ params.type = views::Widget::InitParams::TYPE_CONTROL;
+ // Don't set the WS_EX_COMPOSITED flag.
+ params.opacity = views::Widget::InitParams::WindowOpacity::kOpaque;
+ // Tell Aura not to draw the window frame on resize.
+ params.remove_standard_frame = true;
+ // Cause WidgetDelegate::CanActivate to return true. See comments in
+ // AlloyBrowserHostImpl::PlatformSetFocus.
+ params.activatable = views::Widget::InitParams::Activatable::kYes;
+
+ params.z_order = always_on_top_ ? ui::ZOrderLevel::kFloatingWindow
+ : ui::ZOrderLevel::kNormal;
+
+ // Results in a call to InitContent().
+ widget->Init(std::move(params));
+
+ // |widget| should now be associated with |this|.
+ DCHECK_EQ(widget, GetWidget());
+ // |widget| must be top-level for focus handling to work correctly.
+ DCHECK(widget->is_top_level());
+ // |widget| must be activatable for focus handling to work correctly.
+ DCHECK(widget->widget_delegate()->CanActivate());
+
+ // WidgetDelegate::DeleteDelegate() will execute the registered callback.
+ RegisterDeleteDelegateCallback(base::BindOnce(
+ &CefWindowDelegateView::DeleteDelegate, base::Unretained(this)));
+}
+
+void CefWindowDelegateView::InitContent() {
+ SetBackground(views::CreateSolidBackground(background_color_));
+ SetLayoutManager(std::make_unique<views::FillLayout>());
+ AddChildView(web_view_);
+}
+
+void CefWindowDelegateView::DeleteDelegate() {
+ if (!on_delete_.is_null()) {
+ std::move(on_delete_).Run();
+ }
+}
+
+void CefWindowDelegateView::ViewHierarchyChanged(
+ const views::ViewHierarchyChangedDetails& details) {
+ if (details.is_add && details.child == this) {
+ InitContent();
+ }
+}
+
+void CefWindowDelegateView::OnBoundsChanged(const gfx::Rect& previous_bounds) {
+ views::WidgetDelegateView::OnBoundsChanged(previous_bounds);
+ if (!on_bounds_changed_.is_null()) {
+ on_bounds_changed_.Run();
+ }
+}
diff --git a/libcef/browser/native/window_delegate_view.h b/libcef/browser/native/window_delegate_view.h
new file mode 100644
index 00000000..1205aea9
--- /dev/null
+++ b/libcef/browser/native/window_delegate_view.h
@@ -0,0 +1,60 @@
+// Copyright 2014 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_NATIVE_WINDOW_DELEGATE_VIEW_H_
+#define CEF_LIBCEF_BROWSER_NATIVE_WINDOW_DELEGATE_VIEW_H_
+#pragma once
+
+#include "ui/views/widget/widget_delegate.h"
+
+namespace content {
+class WebContents;
+}
+
+namespace views {
+class WebView;
+}
+
+// Manages the views-based root window that hosts the web contents. This object
+// will be deleted automatically when the associated root window is destroyed.
+class CefWindowDelegateView : public views::WidgetDelegateView {
+ public:
+ CefWindowDelegateView(SkColor background_color,
+ bool always_on_top,
+ base::RepeatingClosure on_bounds_changed,
+ base::OnceClosure on_delete);
+
+ CefWindowDelegateView(const CefWindowDelegateView&) = delete;
+ CefWindowDelegateView& operator=(const CefWindowDelegateView&) = delete;
+
+ // Create the Widget and associated root window.
+ void Init(gfx::AcceleratedWidget parent_widget,
+ content::WebContents* web_contents,
+ const gfx::Rect& bounds);
+
+ private:
+ // Initialize the Widget's content.
+ void InitContent();
+
+ void DeleteDelegate();
+
+ // WidgetDelegateView methods:
+ bool CanMaximize() const override { return true; }
+ View* GetContentsView() override { return this; }
+
+ // View methods:
+ void ViewHierarchyChanged(
+ const views::ViewHierarchyChangedDetails& details) override;
+ void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
+
+ private:
+ const SkColor background_color_;
+ const bool always_on_top_;
+ base::RepeatingClosure on_bounds_changed_;
+ base::OnceClosure on_delete_;
+
+ views::WebView* web_view_ = nullptr;
+};
+
+#endif // CEF_LIBCEF_BROWSER_NATIVE_WINDOW_DELEGATE_VIEW_H_
diff --git a/libcef/browser/native/window_x11.cc b/libcef/browser/native/window_x11.cc
new file mode 100644
index 00000000..7de60066
--- /dev/null
+++ b/libcef/browser/native/window_x11.cc
@@ -0,0 +1,475 @@
+// Copyright 2014 The Chromium Embedded Framework Authors.
+// Portions copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/native/window_x11.h"
+
+#include "libcef/browser/alloy/alloy_browser_host_impl.h"
+#include "libcef/browser/browser_host_base.h"
+#include "libcef/browser/thread_util.h"
+
+#include "net/base/network_interfaces.h"
+#include "ui/base/x/x11_util.h"
+#include "ui/events/platform/platform_event_source.h"
+#include "ui/events/platform/x11/x11_event_source.h"
+#include "ui/events/x/x11_event_translation.h"
+#include "ui/gfx/x/connection.h"
+#include "ui/gfx/x/x11_window_event_manager.h"
+#include "ui/gfx/x/xproto_util.h"
+#include "ui/views/widget/desktop_aura/desktop_window_tree_host_linux.h"
+
+namespace {
+
+const char kNetWMPid[] = "_NET_WM_PID";
+const char kNetWMPing[] = "_NET_WM_PING";
+const char kNetWMState[] = "_NET_WM_STATE";
+const char kNetWMStateKeepAbove[] = "_NET_WM_STATE_KEEP_ABOVE";
+const char kWMDeleteWindow[] = "WM_DELETE_WINDOW";
+const char kWMProtocols[] = "WM_PROTOCOLS";
+const char kXdndProxy[] = "XdndProxy";
+
+// Return true if |window| has any property with |property_name|.
+// Deleted from ui/base/x/x11_util.h in https://crrev.com/62fc260067.
+bool PropertyExists(x11::Window window, x11::Atom property) {
+ auto response = x11::Connection::Get()
+ ->GetProperty(x11::GetPropertyRequest{
+ .window = window,
+ .property = property,
+ .long_length = 1,
+ })
+ .Sync();
+ return response && response->format;
+}
+
+// Returns true if |window| is visible.
+// Deleted from ui/base/x/x11_util.h in https://crrev.com/62fc260067.
+bool IsWindowVisible(x11::Window window) {
+ auto response = x11::Connection::Get()->GetWindowAttributes({window}).Sync();
+ if (!response || response->map_state != x11::MapState::Viewable) {
+ return false;
+ }
+
+ // Minimized windows are not visible.
+ std::vector<x11::Atom> wm_states;
+ if (x11::GetArrayProperty(window, x11::GetAtom("_NET_WM_STATE"),
+ &wm_states)) {
+ x11::Atom hidden_atom = x11::GetAtom("_NET_WM_STATE_HIDDEN");
+ if (base::Contains(wm_states, hidden_atom)) {
+ return false;
+ }
+ }
+
+ // Do not check _NET_CURRENT_DESKTOP/_NET_WM_DESKTOP since some
+ // window managers (eg. i3) have per-monitor workspaces where more
+ // than one workspace can be visible at once, but only one will be
+ // "active".
+ return true;
+}
+
+x11::Window FindChild(x11::Window window) {
+ auto query_tree = x11::Connection::Get()->QueryTree({window}).Sync();
+ if (query_tree && query_tree->children.size() == 1U) {
+ return query_tree->children[0];
+ }
+
+ return x11::Window::None;
+}
+
+x11::Window FindToplevelParent(x11::Window window) {
+ x11::Window top_level_window = window;
+
+ do {
+ auto query_tree = x11::Connection::Get()->QueryTree({window}).Sync();
+ if (!query_tree) {
+ break;
+ }
+
+ top_level_window = window;
+ if (!PropertyExists(query_tree->parent, x11::GetAtom(kNetWMPid)) ||
+ query_tree->parent == query_tree->root) {
+ break;
+ }
+
+ window = query_tree->parent;
+ } while (true);
+
+ return top_level_window;
+}
+
+} // namespace
+
+CEF_EXPORT XDisplay* cef_get_xdisplay() {
+ if (!CEF_CURRENTLY_ON(CEF_UIT)) {
+ return nullptr;
+ }
+ return x11::Connection::Get()->GetXlibDisplay();
+}
+
+CefWindowX11::CefWindowX11(CefRefPtr<CefBrowserHostBase> browser,
+ x11::Window parent_xwindow,
+ const gfx::Rect& bounds,
+ const std::string& title)
+ : browser_(browser),
+ connection_(x11::Connection::Get()),
+ parent_xwindow_(parent_xwindow),
+ bounds_(bounds),
+ weak_ptr_factory_(this) {
+ if (parent_xwindow_ == x11::Window::None) {
+ parent_xwindow_ = ui::GetX11RootWindow();
+ }
+
+ x11::VisualId visual;
+ uint8_t depth;
+ x11::ColorMap colormap;
+ ui::XVisualManager::GetInstance()->ChooseVisualForWindow(
+ /*want_argb_visual=*/false, &visual, &depth, &colormap,
+ /*visual_has_alpha=*/nullptr);
+
+ xwindow_ = connection_->GenerateId<x11::Window>();
+ connection_->CreateWindow({
+ .depth = depth,
+ .wid = xwindow_,
+ .parent = parent_xwindow_,
+ .x = static_cast<int16_t>(bounds.x()),
+ .y = static_cast<int16_t>(bounds.y()),
+ .width = static_cast<uint16_t>(bounds.width()),
+ .height = static_cast<uint16_t>(bounds.height()),
+ .c_class = x11::WindowClass::InputOutput,
+ .visual = visual,
+ .background_pixel = 0,
+ .border_pixel = 0,
+ .override_redirect = x11::Bool32(false),
+ .event_mask = x11::EventMask::FocusChange |
+ x11::EventMask::StructureNotify |
+ x11::EventMask::PropertyChange,
+ .colormap = colormap,
+ });
+
+ connection_->Flush();
+
+ DCHECK(ui::X11EventSource::HasInstance());
+ connection_->AddEventObserver(this);
+ ui::X11EventSource::GetInstance()->AddPlatformEventDispatcher(this);
+
+ std::vector<x11::Atom> protocols = {
+ x11::GetAtom(kWMDeleteWindow),
+ x11::GetAtom(kNetWMPing),
+ };
+ x11::SetArrayProperty(xwindow_, x11::GetAtom(kWMProtocols), x11::Atom::ATOM,
+ protocols);
+
+ // We need a WM_CLIENT_MACHINE value so we integrate with the desktop
+ // environment.
+ x11::SetStringProperty(xwindow_, x11::Atom::WM_CLIENT_MACHINE,
+ x11::Atom::STRING, net::GetHostName());
+
+ // Likewise, the X server needs to know this window's pid so it knows which
+ // program to kill if the window hangs.
+ // XChangeProperty() expects "pid" to be long.
+ static_assert(sizeof(uint32_t) >= sizeof(pid_t),
+ "pid_t should not be larger than uint32_t");
+ uint32_t pid = getpid();
+ x11::SetProperty(xwindow_, x11::GetAtom(kNetWMPid), x11::Atom::CARDINAL, pid);
+
+ // Set the initial window name, if provided.
+ if (!title.empty()) {
+ x11::SetStringProperty(xwindow_, x11::Atom::WM_NAME, x11::Atom::STRING,
+ title);
+ x11::SetStringProperty(xwindow_, x11::Atom::WM_ICON_NAME, x11::Atom::STRING,
+ title);
+ }
+}
+
+CefWindowX11::~CefWindowX11() {
+ DCHECK_EQ(xwindow_, x11::Window::None);
+ DCHECK(ui::X11EventSource::HasInstance());
+ connection_->RemoveEventObserver(this);
+ ui::X11EventSource::GetInstance()->RemovePlatformEventDispatcher(this);
+}
+
+void CefWindowX11::Close() {
+ if (xwindow_ == x11::Window::None) {
+ return;
+ }
+
+ ui::SendClientMessage(
+ xwindow_, xwindow_, x11::GetAtom(kWMProtocols),
+ {static_cast<uint32_t>(x11::GetAtom(kWMDeleteWindow)),
+ static_cast<uint32_t>(x11::Time::CurrentTime), 0, 0, 0},
+ x11::EventMask::NoEvent);
+
+ auto host = GetHost();
+ if (host) {
+ host->Close();
+ }
+}
+
+void CefWindowX11::Show() {
+ if (xwindow_ == x11::Window::None) {
+ return;
+ }
+
+ if (!window_mapped_) {
+ // Before we map the window, set size hints. Otherwise, some window managers
+ // will ignore toplevel XMoveWindow commands.
+ ui::SizeHints size_hints;
+ memset(&size_hints, 0, sizeof(size_hints));
+ ui::GetWmNormalHints(xwindow_, &size_hints);
+ size_hints.flags |= ui::SIZE_HINT_P_POSITION;
+ size_hints.x = bounds_.x();
+ size_hints.y = bounds_.y();
+ ui::SetWmNormalHints(xwindow_, size_hints);
+
+ connection_->MapWindow({xwindow_});
+
+ // TODO(thomasanderson): Find out why this flush is necessary.
+ connection_->Flush();
+ window_mapped_ = true;
+
+ // Setup the drag and drop proxy on the top level window of the application
+ // to be the child of this window.
+ auto child = FindChild(xwindow_);
+ auto toplevel_window = FindToplevelParent(xwindow_);
+ DCHECK_NE(toplevel_window, x11::Window::None);
+ if (child != x11::Window::None && toplevel_window != x11::Window::None) {
+ // Configure the drag&drop proxy property for the top-most window so
+ // that all drag&drop-related messages will be sent to the child
+ // DesktopWindowTreeHostLinux. The proxy property is referenced by
+ // DesktopDragDropClientAuraX11::FindWindowFor.
+ x11::Window window = x11::Window::None;
+ auto dndproxy_atom = x11::GetAtom(kXdndProxy);
+ x11::GetProperty(toplevel_window, dndproxy_atom, &window);
+
+ if (window != child) {
+ // Set the proxy target for the top-most window.
+ x11::SetProperty(toplevel_window, dndproxy_atom, x11::Atom::WINDOW,
+ child);
+ // Do the same for the proxy target per the spec.
+ x11::SetProperty(child, dndproxy_atom, x11::Atom::WINDOW, child);
+ }
+ }
+ }
+}
+
+void CefWindowX11::Hide() {
+ if (xwindow_ == x11::Window::None) {
+ return;
+ }
+
+ if (window_mapped_) {
+ ui::WithdrawWindow(xwindow_);
+ window_mapped_ = false;
+ }
+}
+
+void CefWindowX11::Focus() {
+ if (xwindow_ == x11::Window::None || !window_mapped_) {
+ return;
+ }
+
+ x11::Window focus_target = xwindow_;
+
+ if (browser_.get()) {
+ auto child = FindChild(xwindow_);
+ if (child != x11::Window::None && IsWindowVisible(child)) {
+ // Give focus to the child DesktopWindowTreeHostLinux.
+ focus_target = child;
+ }
+ }
+
+ // Directly ask the X server to give focus to the window. Note that the call
+ // would have raised an X error if the window is not mapped.
+ connection_
+ ->SetInputFocus(
+ {x11::InputFocus::Parent, focus_target, x11::Time::CurrentTime})
+ .IgnoreError();
+}
+
+void CefWindowX11::SetBounds(const gfx::Rect& bounds) {
+ if (xwindow_ == x11::Window::None) {
+ return;
+ }
+
+ x11::ConfigureWindowRequest req{.window = xwindow_};
+
+ bool origin_changed = bounds_.origin() != bounds.origin();
+ bool size_changed = bounds_.size() != bounds.size();
+
+ if (size_changed) {
+ req.width = bounds.width();
+ req.height = bounds.height();
+ }
+
+ if (origin_changed) {
+ req.x = bounds.x();
+ req.y = bounds.y();
+ }
+
+ if (origin_changed || size_changed) {
+ connection_->ConfigureWindow(req);
+ }
+}
+
+gfx::Rect CefWindowX11::GetBoundsInScreen() {
+ if (auto coords =
+ connection_
+ ->TranslateCoordinates({xwindow_, ui::GetX11RootWindow(), 0, 0})
+ .Sync()) {
+ return gfx::Rect(gfx::Point(coords->dst_x, coords->dst_y), bounds_.size());
+ }
+
+ return gfx::Rect();
+}
+
+views::DesktopWindowTreeHostLinux* CefWindowX11::GetHost() {
+ if (browser_.get()) {
+ auto child = FindChild(xwindow_);
+ if (child != x11::Window::None) {
+ return static_cast<views::DesktopWindowTreeHostLinux*>(
+ views::DesktopWindowTreeHostLinux::GetHostForWidget(
+ static_cast<gfx::AcceleratedWidget>(child)));
+ }
+ }
+ return nullptr;
+}
+
+bool CefWindowX11::CanDispatchEvent(const ui::PlatformEvent& event) {
+ auto* dispatching_event = connection_->dispatching_event();
+ return dispatching_event && dispatching_event->window() == xwindow_;
+}
+
+uint32_t CefWindowX11::DispatchEvent(const ui::PlatformEvent& event) {
+ DCHECK_NE(xwindow_, x11::Window::None);
+ DCHECK(event);
+
+ auto* current_xevent = connection_->dispatching_event();
+ ProcessXEvent(*current_xevent);
+ return ui::POST_DISPATCH_STOP_PROPAGATION;
+}
+
+void CefWindowX11::OnEvent(const x11::Event& event) {
+ if (event.window() != xwindow_) {
+ return;
+ }
+ ProcessXEvent(event);
+}
+
+void CefWindowX11::ContinueFocus() {
+ if (!focus_pending_) {
+ return;
+ }
+ if (browser_.get()) {
+ browser_->SetFocus(true);
+ }
+ focus_pending_ = false;
+}
+
+bool CefWindowX11::TopLevelAlwaysOnTop() const {
+ auto toplevel_window = FindToplevelParent(xwindow_);
+ if (toplevel_window == x11::Window::None) {
+ return false;
+ }
+
+ std::vector<x11::Atom> wm_states;
+ if (x11::GetArrayProperty(toplevel_window, x11::GetAtom(kNetWMState),
+ &wm_states)) {
+ x11::Atom keep_above_atom = x11::GetAtom(kNetWMStateKeepAbove);
+ if (base::Contains(wm_states, keep_above_atom)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void CefWindowX11::ProcessXEvent(const x11::Event& event) {
+ if (auto* configure = event.As<x11::ConfigureNotifyEvent>()) {
+ DCHECK_EQ(xwindow_, configure->event);
+ // It's possible that the X window may be resized by some other means
+ // than from within Aura (e.g. the X window manager can change the
+ // size). Make sure the root window size is maintained properly.
+ bounds_ = gfx::Rect(configure->x, configure->y, configure->width,
+ configure->height);
+
+ if (browser_.get()) {
+ auto child = FindChild(xwindow_);
+ if (child != x11::Window::None) {
+ // Resize the child DesktopWindowTreeHostLinux to match this window.
+ x11::ConfigureWindowRequest req{
+ .window = child,
+ .width = bounds_.width(),
+ .height = bounds_.height(),
+ };
+ connection_->ConfigureWindow(req);
+
+ browser_->NotifyMoveOrResizeStarted();
+ }
+ }
+ } else if (auto* client = event.As<x11::ClientMessageEvent>()) {
+ if (client->type == x11::GetAtom(kWMProtocols)) {
+ x11::Atom protocol = static_cast<x11::Atom>(client->data.data32[0]);
+ if (protocol == x11::GetAtom(kWMDeleteWindow)) {
+ // We have received a close message from the window manager.
+ if (!browser_ || browser_->TryCloseBrowser()) {
+ // Allow the close.
+ connection_->DestroyWindow({xwindow_});
+ xwindow_ = x11::Window::None;
+
+ if (browser_) {
+ // Force the browser to be destroyed and release the reference
+ // added in PlatformCreateWindow().
+ static_cast<AlloyBrowserHostImpl*>(browser_.get())
+ ->WindowDestroyed();
+ }
+
+ delete this;
+ }
+ } else if (protocol == x11::GetAtom(kNetWMPing)) {
+ x11::ClientMessageEvent reply_event = *client;
+ reply_event.window = parent_xwindow_;
+ x11::SendEvent(reply_event, reply_event.window,
+ x11::EventMask::SubstructureNotify |
+ x11::EventMask::SubstructureRedirect);
+ }
+ }
+ } else if (auto* focus = event.As<x11::FocusEvent>()) {
+ if (focus->opcode == x11::FocusEvent::In) {
+ // This message is received first followed by a "_NET_ACTIVE_WINDOW"
+ // message sent to the root window. When X11DesktopHandler handles the
+ // "_NET_ACTIVE_WINDOW" message it will erroneously mark the WebView
+ // (hosted in a DesktopWindowTreeHostLinux) as unfocused. Use a delayed
+ // task here to restore the WebView's focus state.
+ if (!focus_pending_) {
+ focus_pending_ = true;
+ CEF_POST_DELAYED_TASK(CEF_UIT,
+ base::BindOnce(&CefWindowX11::ContinueFocus,
+ weak_ptr_factory_.GetWeakPtr()),
+ 100);
+ }
+ } else {
+ // Cancel the pending focus change if some other window has gained focus
+ // while waiting for the async task to run. Otherwise we can get stuck in
+ // a focus change loop.
+ if (focus_pending_) {
+ focus_pending_ = false;
+ }
+ }
+ } else if (auto* property = event.As<x11::PropertyNotifyEvent>()) {
+ const auto& wm_state_atom = x11::GetAtom(kNetWMState);
+ if (property->atom == wm_state_atom) {
+ // State change event like minimize/maximize.
+ if (browser_.get()) {
+ auto child = FindChild(xwindow_);
+ if (child != x11::Window::None) {
+ // Forward the state change to the child DesktopWindowTreeHostLinux
+ // window so that resource usage will be reduced while the window is
+ // minimized. |atom_list| may be empty.
+ std::vector<x11::Atom> atom_list;
+ x11::GetArrayProperty(xwindow_, wm_state_atom, &atom_list);
+ x11::SetArrayProperty(child, wm_state_atom, x11::Atom::ATOM,
+ atom_list);
+ }
+ }
+ }
+ }
+}
diff --git a/libcef/browser/native/window_x11.h b/libcef/browser/native/window_x11.h
new file mode 100644
index 00000000..3f9616b7
--- /dev/null
+++ b/libcef/browser/native/window_x11.h
@@ -0,0 +1,97 @@
+// Copyright 2014 The Chromium Embedded Framework Authors.
+// Portions copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_NATIVE_WINDOW_X11_H_
+#define CEF_LIBCEF_BROWSER_NATIVE_WINDOW_X11_H_
+#pragma once
+
+#include <memory>
+
+#include "include/internal/cef_ptr.h"
+
+#include "base/memory/weak_ptr.h"
+#include "ui/events/platform/platform_event_dispatcher.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/x/connection.h"
+#include "ui/gfx/x/x11_atom_cache.h"
+
+namespace x11 {
+class XScopedEventSelector;
+}
+
+namespace views {
+class DesktopWindowTreeHostLinux;
+}
+
+class CefBrowserHostBase;
+
+// Object wrapper for an X11 Window.
+// Based on WindowTreeHostX11 and DesktopWindowTreeHostX11.
+class CefWindowX11 : public ui::PlatformEventDispatcher,
+ public x11::EventObserver {
+ public:
+ CefWindowX11(CefRefPtr<CefBrowserHostBase> browser,
+ x11::Window parent_xwindow,
+ const gfx::Rect& bounds,
+ const std::string& title);
+
+ CefWindowX11(const CefWindowX11&) = delete;
+ CefWindowX11& operator=(const CefWindowX11&) = delete;
+
+ ~CefWindowX11() override;
+
+ void Close();
+
+ void Show();
+ void Hide();
+
+ void Focus();
+
+ void SetBounds(const gfx::Rect& bounds);
+
+ gfx::Rect GetBoundsInScreen();
+
+ views::DesktopWindowTreeHostLinux* GetHost();
+
+ // ui::PlatformEventDispatcher methods:
+ bool CanDispatchEvent(const ui::PlatformEvent& event) override;
+ uint32_t DispatchEvent(const ui::PlatformEvent& event) override;
+
+ // x11::EventObserver methods:
+ void OnEvent(const x11::Event& event) override;
+
+ x11::Window xwindow() const { return xwindow_; }
+ gfx::Rect bounds() const { return bounds_; }
+
+ bool TopLevelAlwaysOnTop() const;
+
+ private:
+ void ContinueFocus();
+
+ void ProcessXEvent(const x11::Event& xev);
+
+ CefRefPtr<CefBrowserHostBase> browser_;
+
+ // The display and the native X window hosting the root window.
+ x11::Connection* const connection_;
+ x11::Window parent_xwindow_;
+ x11::Window xwindow_;
+
+ // Events selected on |xwindow_|.
+ std::unique_ptr<x11::XScopedEventSelector> xwindow_events_;
+
+ // Is the window mapped to the screen?
+ bool window_mapped_ = false;
+
+ // The bounds of |xwindow_|.
+ gfx::Rect bounds_;
+
+ bool focus_pending_ = false;
+
+ // Must always be the last member.
+ base::WeakPtrFactory<CefWindowX11> weak_ptr_factory_;
+};
+
+#endif // CEF_LIBCEF_BROWSER_NATIVE_WINDOW_X11_H_
diff --git a/libcef/browser/navigation_entry_impl.cc b/libcef/browser/navigation_entry_impl.cc
new file mode 100644
index 00000000..669424be
--- /dev/null
+++ b/libcef/browser/navigation_entry_impl.cc
@@ -0,0 +1,71 @@
+// Copyright (c) 2014 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "libcef/browser/navigation_entry_impl.h"
+
+#include "libcef/browser/ssl_status_impl.h"
+#include "libcef/common/time_util.h"
+
+#include "content/public/browser/navigation_entry.h"
+#include "url/gurl.h"
+
+CefNavigationEntryImpl::CefNavigationEntryImpl(content::NavigationEntry* value)
+ : CefValueBase<CefNavigationEntry, content::NavigationEntry>(
+ value,
+ nullptr,
+ kOwnerNoDelete,
+ false,
+ new CefValueControllerNonThreadSafe()) {
+ // Indicate that this object owns the controller.
+ SetOwnsController();
+}
+
+bool CefNavigationEntryImpl::IsValid() {
+ return !detached();
+}
+
+CefString CefNavigationEntryImpl::GetURL() {
+ CEF_VALUE_VERIFY_RETURN(false, CefString());
+ return mutable_value()->GetURL().spec();
+}
+
+CefString CefNavigationEntryImpl::GetDisplayURL() {
+ CEF_VALUE_VERIFY_RETURN(false, CefString());
+ return mutable_value()->GetVirtualURL().spec();
+}
+
+CefString CefNavigationEntryImpl::GetOriginalURL() {
+ CEF_VALUE_VERIFY_RETURN(false, CefString());
+ return mutable_value()->GetUserTypedURL().spec();
+}
+
+CefString CefNavigationEntryImpl::GetTitle() {
+ CEF_VALUE_VERIFY_RETURN(false, CefString());
+ return mutable_value()->GetTitle();
+}
+
+CefNavigationEntry::TransitionType CefNavigationEntryImpl::GetTransitionType() {
+ CEF_VALUE_VERIFY_RETURN(false, TT_EXPLICIT);
+ return static_cast<TransitionType>(mutable_value()->GetTransitionType());
+}
+
+bool CefNavigationEntryImpl::HasPostData() {
+ CEF_VALUE_VERIFY_RETURN(false, false);
+ return mutable_value()->GetHasPostData();
+}
+
+CefBaseTime CefNavigationEntryImpl::GetCompletionTime() {
+ CEF_VALUE_VERIFY_RETURN(false, CefBaseTime());
+ return mutable_value()->GetTimestamp();
+}
+
+int CefNavigationEntryImpl::GetHttpStatusCode() {
+ CEF_VALUE_VERIFY_RETURN(false, 0);
+ return mutable_value()->GetHttpStatusCode();
+}
+
+CefRefPtr<CefSSLStatus> CefNavigationEntryImpl::GetSSLStatus() {
+ CEF_VALUE_VERIFY_RETURN(false, nullptr);
+ return new CefSSLStatusImpl(mutable_value()->GetSSL());
+}
diff --git a/libcef/browser/navigation_entry_impl.h b/libcef/browser/navigation_entry_impl.h
new file mode 100644
index 00000000..98e89f39
--- /dev/null
+++ b/libcef/browser/navigation_entry_impl.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2014 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_NAVIGATION_ENTRY_IMPL_H_
+#define CEF_LIBCEF_BROWSER_NAVIGATION_ENTRY_IMPL_H_
+#pragma once
+
+#include "include/cef_navigation_entry.h"
+#include "libcef/common/value_base.h"
+
+namespace content {
+class NavigationEntry;
+}
+
+// CefNavigationEntry implementation
+class CefNavigationEntryImpl
+ : public CefValueBase<CefNavigationEntry, content::NavigationEntry> {
+ public:
+ explicit CefNavigationEntryImpl(content::NavigationEntry* value);
+
+ CefNavigationEntryImpl(const CefNavigationEntryImpl&) = delete;
+ CefNavigationEntryImpl& operator=(const CefNavigationEntryImpl&) = delete;
+
+ // CefNavigationEntry methods.
+ bool IsValid() override;
+ CefString GetURL() override;
+ CefString GetDisplayURL() override;
+ CefString GetOriginalURL() override;
+ CefString GetTitle() override;
+ TransitionType GetTransitionType() override;
+ bool HasPostData() override;
+ CefBaseTime GetCompletionTime() override;
+ int GetHttpStatusCode() override;
+ CefRefPtr<CefSSLStatus> GetSSLStatus() override;
+};
+
+#endif // CEF_LIBCEF_BROWSER_NAVIGATION_ENTRY_IMPL_H_
diff --git a/libcef/browser/net/chrome_scheme_handler.cc b/libcef/browser/net/chrome_scheme_handler.cc
new file mode 100644
index 00000000..a54aa812
--- /dev/null
+++ b/libcef/browser/net/chrome_scheme_handler.cc
@@ -0,0 +1,724 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors.
+// Portions copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/net/chrome_scheme_handler.h"
+
+#include <algorithm>
+#include <map>
+#include <string>
+#include <utility>
+
+#include "include/cef_version.h"
+#include "libcef/browser/extensions/chrome_api_registration.h"
+#include "libcef/browser/frame_host_impl.h"
+#include "libcef/browser/net/internal_scheme_handler.h"
+#include "libcef/browser/thread_util.h"
+#include "libcef/common/app_manager.h"
+#include "libcef/features/runtime.h"
+
+#include "base/command_line.h"
+#include "base/files/file_util.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/path_service.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "cef/grit/cef_resources.h"
+#include "chrome/browser/browser_about_handler.h"
+#include "chrome/browser/devtools/devtools_ui_bindings.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/webui/chrome_untrusted_web_ui_configs.h"
+#include "chrome/browser/ui/webui/chrome_web_ui_controller_factory.h"
+#include "chrome/browser/ui/webui/theme_source.h"
+#include "chrome/common/url_constants.h"
+#include "content/browser/renderer_host/debug_urls.h"
+#include "content/public/browser/browser_url_handler.h"
+#include "content/public/browser/content_browser_client.h"
+#include "content/public/browser/url_data_source.h"
+#include "content/public/browser/web_ui_controller.h"
+#include "content/public/browser/webui_config_map.h"
+#include "content/public/common/url_constants.h"
+#include "content/public/common/url_utils.h"
+#include "content/public/common/user_agent.h"
+#include "ipc/ipc_channel.h"
+#include "third_party/blink/public/common/chrome_debug_urls.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "v8/include/v8.h"
+
+using extensions::api::cef::kSupportedAPIs;
+
+namespace scheme {
+
+const char kChromeURL[] = "chrome://";
+
+namespace {
+
+const char kChromeUIExtensionsSupportHost[] = "extensions-support";
+const char kChromeUILicenseHost[] = "license";
+const char kChromeUIWebUIHostsHost[] = "webui-hosts";
+
+// TODO(network): Consider handling content::kChromeDevToolsScheme via WebUI
+// (DevToolsUI class) with the following changes:
+// 1. Add an entry for content::kChromeDevToolsScheme in
+// AlloyContentBrowserClient::GetAdditionalWebUISchemes.
+// 2. Allow the scheme in CefWebUIControllerFactory::AllowWebUIForURL.
+// 3. Add an entry for chrome::kChromeUIDevToolsHost in kAllowedWebUIHosts and
+// kUnlistedHosts.
+// 4. Remove scheme::RegisterInternalHandlers and related plumbing.
+
+// Chrome hosts implemented by WebUI.
+// Some WebUI handlers have Chrome dependencies that may fail in CEF without
+// additional changes. Do not add new hosts to this list without also manually
+// testing all related functionality in CEF.
+const char* kAllowedWebUIHosts[] = {
+ chrome::kChromeUIAccessibilityHost,
+ content::kChromeUIBlobInternalsHost,
+ chrome::kChromeUIChromeURLsHost,
+ chrome::kChromeUICreditsHost,
+ kChromeUIExtensionsSupportHost,
+ content::kChromeUIGpuHost,
+ content::kChromeUIHistogramHost,
+ content::kChromeUIIndexedDBInternalsHost,
+ kChromeUILicenseHost,
+ content::kChromeUIMediaInternalsHost,
+ chrome::kChromeUINetExportHost,
+ chrome::kChromeUINetInternalsHost,
+ content::kChromeUINetworkErrorHost,
+ content::kChromeUINetworkErrorsListingHost,
+ chrome::kChromeUIPrintHost,
+ content::kChromeUIProcessInternalsHost,
+ content::kChromeUIResourcesHost,
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX)
+ chrome::kChromeUISandboxHost,
+#endif
+ content::kChromeUIServiceWorkerInternalsHost,
+ chrome::kChromeUISystemInfoHost,
+ chrome::kChromeUIThemeHost,
+ content::kChromeUITracingHost,
+ chrome::kChromeUIVersionHost,
+ content::kChromeUIWebRTCInternalsHost,
+ kChromeUIWebUIHostsHost,
+};
+
+// Hosts that don't have useful output when linked directly. They'll be excluded
+// from the "chrome://webui-hosts" listing.
+const char* kUnlistedHosts[] = {
+ content::kChromeUINetworkErrorHost,
+ content::kChromeUIResourcesHost,
+ chrome::kChromeUIThemeHost,
+};
+
+enum ChromeHostId {
+ CHROME_UNKNOWN = 0,
+ CHROME_EXTENSIONS_SUPPORT,
+ CHROME_LICENSE,
+ CHROME_VERSION,
+ CHROME_WEBUI_HOSTS,
+};
+
+// Chrome hosts implemented by CEF.
+const struct {
+ const char* host;
+ ChromeHostId host_id;
+} kAllowedCefHosts[] = {
+ {chrome::kChromeUIChromeURLsHost, CHROME_WEBUI_HOSTS},
+ {kChromeUIExtensionsSupportHost, CHROME_EXTENSIONS_SUPPORT},
+ {kChromeUILicenseHost, CHROME_LICENSE},
+ {chrome::kChromeUIVersionHost, CHROME_VERSION},
+ {kChromeUIWebUIHostsHost, CHROME_WEBUI_HOSTS},
+};
+
+ChromeHostId GetChromeHostId(const std::string& host) {
+ for (size_t i = 0; i < sizeof(kAllowedCefHosts) / sizeof(kAllowedCefHosts[0]);
+ ++i) {
+ if (base::EqualsCaseInsensitiveASCII(kAllowedCefHosts[i].host,
+ host.c_str())) {
+ return kAllowedCefHosts[i].host_id;
+ }
+ }
+
+ return CHROME_UNKNOWN;
+}
+
+// Returns WebUI hosts. Does not include chrome debug hosts (for crashing, etc).
+void GetAllowedHosts(std::vector<std::string>* hosts) {
+ // Explicitly whitelisted WebUI hosts.
+ for (size_t i = 0;
+ i < sizeof(kAllowedWebUIHosts) / sizeof(kAllowedWebUIHosts[0]); ++i) {
+ hosts->push_back(kAllowedWebUIHosts[i]);
+ }
+}
+
+// Returns true if a host should not be listed on "chrome://webui-hosts".
+bool IsUnlistedHost(const std::string& host) {
+ for (size_t i = 0; i < sizeof(kUnlistedHosts) / sizeof(kUnlistedHosts[0]);
+ ++i) {
+ if (host == kUnlistedHosts[i]) {
+ return true;
+ }
+ }
+ return false;
+}
+
+// Returns true if a host is WebUI and should be allowed to load.
+bool IsAllowedWebUIHost(const std::string& host) {
+ // Chrome runtime allows all WebUI hosts.
+ if (cef::IsChromeRuntimeEnabled()) {
+ return true;
+ }
+
+ // Explicitly whitelisted WebUI hosts.
+ for (size_t i = 0;
+ i < sizeof(kAllowedWebUIHosts) / sizeof(kAllowedWebUIHosts[0]); ++i) {
+ if (base::EqualsCaseInsensitiveASCII(kAllowedWebUIHosts[i], host.c_str())) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// Additional debug URLs that are not included in chrome::kChromeDebugURLs.
+const char* kAllowedDebugURLs[] = {
+ blink::kChromeUIBrowserCrashURL,
+};
+
+void GetDebugURLs(std::vector<std::string>* urls) {
+ for (size_t i = 0; i < chrome::kNumberOfChromeDebugURLs; ++i) {
+ urls->push_back(chrome::kChromeDebugURLs[i]);
+ }
+
+ for (size_t i = 0;
+ i < sizeof(kAllowedDebugURLs) / sizeof(kAllowedDebugURLs[0]); ++i) {
+ urls->push_back(kAllowedDebugURLs[i]);
+ }
+}
+
+std::string GetOSType() {
+#if BUILDFLAG(IS_WIN)
+ return "Windows";
+#elif BUILDFLAG(IS_MAC)
+ return "Mac OS X";
+#elif BUILDFLAG(IS_LINUX)
+ return "Linux";
+#else
+ return "Unknown";
+#endif
+}
+
+std::string GetCommandLine() {
+#if BUILDFLAG(IS_WIN)
+ return base::WideToUTF8(
+ base::CommandLine::ForCurrentProcess()->GetCommandLineString());
+#elif BUILDFLAG(IS_POSIX)
+ std::string command_line = "";
+ using ArgvList = std::vector<std::string>;
+ const ArgvList& argv = base::CommandLine::ForCurrentProcess()->argv();
+ for (ArgvList::const_iterator iter = argv.begin(); iter != argv.end();
+ iter++) {
+ command_line += " " + *iter;
+ }
+ // TODO(viettrungluu): |command_line| could really have any encoding, whereas
+ // below we assumes it's UTF-8.
+ return command_line;
+#endif
+}
+
+std::string GetModulePath() {
+ base::FilePath path;
+ if (base::PathService::Get(base::FILE_MODULE, &path)) {
+ return CefString(path.value());
+ }
+ return std::string();
+}
+
+class TemplateParser {
+ public:
+ TemplateParser() : ident_start_("$$"), ident_end_("$$") {}
+
+ TemplateParser(const std::string& ident_start, const std::string& ident_end)
+ : ident_start_(ident_start), ident_end_(ident_end) {}
+
+ void Add(const std::string& key, const std::string& value) {
+ values_.insert(std::make_pair(key, value));
+ }
+
+ void Parse(std::string* tmpl) {
+ int start_pos, end_pos = 0;
+ int ident_start_len = ident_start_.length();
+ int ident_end_len = ident_end_.length();
+
+ while (true) {
+ start_pos = tmpl->find(ident_start_, end_pos);
+ if (start_pos >= 0) {
+ end_pos = tmpl->find(ident_end_, start_pos + ident_start_len);
+ if (end_pos >= 0) {
+ // Found an identifier. Check if a substitution exists.
+ std::string key = tmpl->substr(start_pos + ident_start_len,
+ end_pos - start_pos - ident_start_len);
+ KeyMap::const_iterator it = values_.find(key);
+ if (it != values_.end()) {
+ // Peform the substitution.
+ tmpl->replace(start_pos, end_pos + ident_end_len - start_pos,
+ it->second);
+ end_pos = start_pos + it->second.length();
+ } else {
+ // Leave the unknown identifier in place.
+ end_pos += ident_end_len;
+ }
+
+ if (end_pos >= static_cast<int>(tmpl->length()) - ident_start_len -
+ ident_end_len) {
+ // Not enough room remaining for more identifiers.
+ break;
+ }
+ } else {
+ // No end identifier found.
+ break;
+ }
+ } else {
+ // No start identifier found.
+ break;
+ }
+ }
+ }
+
+ private:
+ using KeyMap = std::map<std::string, std::string>;
+ KeyMap values_;
+ std::string ident_start_;
+ std::string ident_end_;
+};
+
+bool OnExtensionsSupportUI(std::string* mime_type, std::string* output) {
+ *mime_type = "text/html";
+
+ if (cef::IsChromeRuntimeEnabled()) {
+ // Redirect to the Chrome documentation.
+ *output =
+ "<html><head>\n"
+ "<meta http-equiv=\"refresh\" "
+ "content=\"0;URL='https://developer.chrome.com/docs/extensions/'\"/>\n"
+ "</head></html>\n";
+ return true;
+ }
+
+ static const char kDevURL[] = "https://developer.chrome.com/extensions/";
+
+ std::string html =
+ "<html>\n<head><title>Extensions Support</title></head>\n"
+ "<body bgcolor=\"white\"><h3>Supported Chrome Extensions "
+ "APIs</h3>\nFollow <a "
+ "href=\"https://github.com/chromiumembedded/cef/issues/1947\" "
+ "target=\"new\">issue #1947</a> for development progress.\n<ul>\n";
+
+ bool has_top_level_name = false;
+ for (size_t i = 0; kSupportedAPIs[i] != nullptr; ++i) {
+ const std::string& api_name = kSupportedAPIs[i];
+ if (api_name.find("Private") != std::string::npos) {
+ // Don't list private APIs.
+ continue;
+ }
+
+ const size_t dot_pos = api_name.find('.');
+ if (dot_pos == std::string::npos) {
+ if (has_top_level_name) {
+ // End the previous top-level API entry.
+ html += "</ul></li>\n";
+ } else {
+ has_top_level_name = true;
+ }
+
+ // Start a new top-level API entry.
+ html += "<li><a href=\"" + std::string(kDevURL) + api_name +
+ "\" target=\"new\">" + api_name + "</a><ul>\n";
+ } else {
+ // Function name.
+ const std::string& group_name = api_name.substr(0, dot_pos);
+ const std::string& function_name = api_name.substr(dot_pos + 1);
+ html += "\t<li><a href=\"" + std::string(kDevURL) + group_name +
+ "#method-" + function_name + "\" target=\"new\">" + api_name +
+ "</a></li>\n";
+ }
+ }
+
+ if (has_top_level_name) {
+ // End the last top-level API entry.
+ html += "</ul></li>\n";
+ }
+
+ html += "</ul>\n</body>\n</html>";
+
+ *output = html;
+ return true;
+}
+
+bool OnLicenseUI(std::string* mime_type, std::string* output) {
+ std::string piece =
+ ui::ResourceBundle::GetSharedInstance().LoadDataResourceString(
+ IDR_CEF_LICENSE_TXT);
+ if (piece.empty()) {
+ NOTREACHED() << "Failed to load license txt resource.";
+ return false;
+ }
+
+ *mime_type = "text/html";
+ *output = "<html><head><title>License</title></head><body><pre>" + piece +
+ "</pre></body></html>";
+
+ return true;
+}
+
+bool OnVersionUI(Profile* profile,
+ std::string* mime_type,
+ std::string* output) {
+ std::string tmpl =
+ ui::ResourceBundle::GetSharedInstance().LoadDataResourceString(
+ IDR_CEF_VERSION_HTML);
+ if (tmpl.empty()) {
+ NOTREACHED() << "Failed to load version html resource.";
+ return false;
+ }
+
+ TemplateParser parser;
+ parser.Add("YEAR", MAKE_STRING(COPYRIGHT_YEAR));
+ parser.Add("CEF", CEF_VERSION);
+ parser.Add("CHROMIUM",
+ base::StringPrintf("%d.%d.%d.%d", CHROME_VERSION_MAJOR,
+ CHROME_VERSION_MINOR, CHROME_VERSION_BUILD,
+ CHROME_VERSION_PATCH));
+ parser.Add("OS", GetOSType());
+ parser.Add("WEBKIT", content::GetWebKitVersion());
+ parser.Add("JAVASCRIPT", v8::V8::GetVersion());
+ parser.Add(
+ "USERAGENT",
+ CefAppManager::Get()->GetContentClient()->browser()->GetUserAgent());
+ parser.Add("COMMANDLINE", GetCommandLine());
+ parser.Add("MODULEPATH", GetModulePath());
+ parser.Add("CACHEPATH", CefString(profile->GetPath().value()));
+
+ parser.Parse(&tmpl);
+
+ *mime_type = "text/html";
+ *output = tmpl;
+
+ return true;
+}
+
+bool OnWebUIHostsUI(std::string* mime_type, std::string* output) {
+ std::string html =
+ "<html>\n<head><title>Chrome URLs</title></head>\n"
+ "<body bgcolor=\"white\"><h3>List of Chrome URLs</h3>\n<ul>\n";
+
+ std::vector<std::string> list;
+ GetAllowedHosts(&list);
+ std::sort(list.begin(), list.end());
+
+ for (size_t i = 0U; i < list.size(); ++i) {
+ if (IsUnlistedHost(list[i])) {
+ continue;
+ }
+
+ html += "<li><a href=\"chrome://" + list[i] + "\">chrome://" + list[i] +
+ "</a></li>\n";
+ }
+
+ list.clear();
+ GetDebugURLs(&list);
+ std::sort(list.begin(), list.end());
+
+ html +=
+ "</ul>\n<h3>For Debug</h3>\n"
+ "<p>The following pages are for debugging purposes only. Because they "
+ "crash or hang the renderer, they're not linked directly; you can type "
+ "them into the address bar if you need them.</p>\n<ul>\n";
+ for (size_t i = 0U; i < list.size(); ++i) {
+ html += "<li>" + std::string(list[i]) + "</li>\n";
+ }
+ html += "</ul>\n";
+
+ html += "</body>\n</html>";
+
+ *mime_type = "text/html";
+ *output = html;
+
+ return true;
+}
+
+const content::WebUI::TypeID kCefWebUITypeID = &kCefWebUITypeID;
+
+class CefURLDataSource : public content::URLDataSource {
+ public:
+ CefURLDataSource(const std::string& host,
+ ChromeHostId host_id,
+ Profile* profile)
+ : host_(host), host_id_(host_id), profile_(profile) {
+ CEF_REQUIRE_UIT();
+ output_ = new base::RefCountedString();
+ bool handled = false;
+ switch (host_id_) {
+ case CHROME_EXTENSIONS_SUPPORT:
+ handled = OnExtensionsSupportUI(&mime_type_, &output_->data());
+ break;
+ case CHROME_LICENSE:
+ handled = OnLicenseUI(&mime_type_, &output_->data());
+ break;
+ case CHROME_VERSION:
+ handled = OnVersionUI(profile_, &mime_type_, &output_->data());
+ break;
+ case CHROME_WEBUI_HOSTS:
+ handled = OnWebUIHostsUI(&mime_type_, &output_->data());
+ break;
+ default:
+ break;
+ }
+ DCHECK(handled) << "Unhandled WebUI host: " << host;
+ }
+
+ CefURLDataSource(const CefURLDataSource&) = delete;
+ CefURLDataSource& operator=(const CefURLDataSource&) = delete;
+
+ ~CefURLDataSource() override = default;
+
+ // content::URLDataSource implementation.
+ std::string GetSource() override { return host_; }
+
+ void StartDataRequest(
+ const GURL& path,
+ const content::WebContents::Getter& wc_getter,
+ content::URLDataSource::GotDataCallback callback) override {
+ std::move(callback).Run(output_);
+ }
+
+ std::string GetMimeType(const GURL& url) override { return mime_type_; }
+
+ bool AllowCaching() override { return false; }
+
+ private:
+ const std::string host_;
+ const ChromeHostId host_id_;
+ Profile* const profile_;
+
+ std::string mime_type_;
+ scoped_refptr<base::RefCountedString> output_;
+};
+
+class CefWebUIController : public content::WebUIController {
+ public:
+ CefWebUIController(content::WebUI* web_ui,
+ const std::string& host,
+ ChromeHostId host_id)
+ : content::WebUIController(web_ui) {
+ Profile* profile = Profile::FromWebUI(web_ui);
+ content::URLDataSource::Add(
+ profile, std::make_unique<CefURLDataSource>(host, host_id, profile));
+ }
+
+ CefWebUIController(const CefWebUIController&) = delete;
+ CefWebUIController& operator=(const CefWebUIController&) = delete;
+
+ ~CefWebUIController() override = default;
+};
+
+// Intercepts all WebUI calls and either blocks them or forwards them to the
+// Content or Chrome WebUI factory as appropriate.
+class CefWebUIControllerFactory : public content::WebUIControllerFactory {
+ public:
+ CefWebUIControllerFactory(const CefWebUIControllerFactory&) = delete;
+ CefWebUIControllerFactory& operator=(const CefWebUIControllerFactory&) =
+ delete;
+
+ // Returns true if WebUI is allowed to handle the specified |url|.
+ static bool AllowWebUIForURL(const GURL& url) {
+ if (cef::IsChromeRuntimeEnabled() &&
+ url.SchemeIs(content::kChromeDevToolsScheme)) {
+ return DevToolsUIBindings::IsValidFrontendURL(url);
+ }
+
+ if (!url.SchemeIs(content::kChromeUIScheme) &&
+ !url.SchemeIs(content::kChromeUIUntrustedScheme)) {
+ return false;
+ }
+
+ if (IsAllowedWebUIHost(url.host())) {
+ return true;
+ }
+
+ return false;
+ }
+
+ // Returns true if WebUI is allowed to make network requests.
+ static bool IsWebUIAllowedToMakeNetworkRequests(const url::Origin& origin) {
+ if (!AllowWebUIForURL(origin.GetURL())) {
+ return false;
+ }
+
+ if (ChromeWebUIControllerFactory::IsWebUIAllowedToMakeNetworkRequests(
+ origin)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ std::unique_ptr<content::WebUIController> CreateWebUIControllerForURL(
+ content::WebUI* web_ui,
+ const GURL& url) override {
+ std::unique_ptr<content::WebUIController> controller;
+ if (!AllowWebUIForURL(url)) {
+ return controller;
+ }
+
+ // Set up the chrome://theme/ source. These URLs are referenced from many
+ // places (WebUI and chrome://resources which live in //ui). WebUI code
+ // can live in both //content and //chrome. Since ThemeSource lives in
+ // //chrome the WebUI from //content is not performing this setup despite
+ // the fact that it's needed for proper handling of theme resource requests.
+ // See https://crbug.com/1011280.
+ Profile* profile = Profile::FromWebUI(web_ui);
+ content::URLDataSource::Add(profile,
+ std::make_unique<ThemeSource>(profile));
+
+ const auto host_id = GetChromeHostId(url.host());
+ if (host_id != CHROME_UNKNOWN) {
+ return std::make_unique<CefWebUIController>(web_ui, url.host(), host_id);
+ }
+
+ controller = content::WebUIConfigMap::GetInstance()
+ .controller_factory()
+ ->CreateWebUIControllerForURL(web_ui, url);
+ if (controller) {
+ return controller;
+ }
+
+ return ChromeWebUIControllerFactory::GetInstance()
+ ->CreateWebUIControllerForURL(web_ui, url);
+ }
+
+ content::WebUI::TypeID GetWebUIType(content::BrowserContext* browser_context,
+ const GURL& url) override {
+ content::WebUI::TypeID type = content::WebUI::kNoWebUI;
+ if (!AllowWebUIForURL(url)) {
+ return type;
+ }
+
+ const auto host_id = GetChromeHostId(url.host());
+ if (host_id != CHROME_UNKNOWN) {
+ return kCefWebUITypeID;
+ }
+
+ type = content::WebUIConfigMap::GetInstance()
+ .controller_factory()
+ ->GetWebUIType(browser_context, url);
+ if (type != content::WebUI::kNoWebUI) {
+ return type;
+ }
+
+ type = ChromeWebUIControllerFactory::GetInstance()->GetWebUIType(
+ browser_context, url);
+ if (type != content::WebUI::kNoWebUI) {
+ return type;
+ }
+
+ return content::WebUI::kNoWebUI;
+ }
+
+ bool UseWebUIForURL(content::BrowserContext* browser_context,
+ const GURL& url) override {
+ if (!AllowWebUIForURL(url)) {
+ return false;
+ }
+
+ const auto host_id = GetChromeHostId(url.host());
+ if (host_id != CHROME_UNKNOWN) {
+ return true;
+ }
+
+ if (content::WebUIConfigMap::GetInstance()
+ .controller_factory()
+ ->UseWebUIForURL(browser_context, url) ||
+ ChromeWebUIControllerFactory::GetInstance()->UseWebUIForURL(
+ browser_context, url)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ static void BrowserURLHandlerCreated(content::BrowserURLHandler* handler) {
+ // For Chrome runtime this is registered in
+ // ChromeContentBrowserClient::BrowserURLHandlerCreated().
+ if (cef::IsAlloyRuntimeEnabled()) {
+ // Handler to rewrite chrome://about and chrome://sync URLs.
+ handler->AddHandlerPair(&HandleChromeAboutAndChromeSyncRewrite,
+ content::BrowserURLHandler::null_handler());
+ }
+
+ // chrome: & friends. For Chrome runtime the default registration is
+ // disabled is ChromeContentBrowserClient::BrowserURLHandlerCreated().
+ handler->AddHandlerPair(&HandleWebUI, &HandleWebUIReverse);
+ }
+
+ static CefWebUIControllerFactory* GetInstance();
+
+ protected:
+ CefWebUIControllerFactory() = default;
+ ~CefWebUIControllerFactory() override = default;
+
+ private:
+ friend struct base::LazyInstanceTraitsBase<CefWebUIControllerFactory>;
+
+ // From chrome/browser/chrome_content_browser_client.cc
+
+ // Handles rewriting Web UI URLs.
+ static bool HandleWebUI(GURL* url, content::BrowserContext* browser_context) {
+ if (!GetInstance()->UseWebUIForURL(browser_context, *url)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ // Reverse URL handler for Web UI.
+ static bool HandleWebUIReverse(GURL* url,
+ content::BrowserContext* browser_context) {
+ // No need to actually reverse-rewrite the URL.
+ return false;
+ }
+};
+
+base::LazyInstance<CefWebUIControllerFactory>::Leaky
+ g_web_ui_controller_factory = LAZY_INSTANCE_INITIALIZER;
+
+// static
+CefWebUIControllerFactory* CefWebUIControllerFactory::GetInstance() {
+ return &g_web_ui_controller_factory.Get();
+}
+
+} // namespace
+
+void RegisterWebUIControllerFactory() {
+ // Channel all WebUI handling through CefWebUIControllerFactory.
+ content::WebUIControllerFactory::UnregisterFactoryForTesting(
+ content::WebUIConfigMap::GetInstance().controller_factory());
+
+ content::WebUIControllerFactory::RegisterFactory(
+ CefWebUIControllerFactory::GetInstance());
+
+ RegisterChromeUntrustedWebUIConfigs();
+}
+
+void BrowserURLHandlerCreated(content::BrowserURLHandler* handler) {
+ CefWebUIControllerFactory::BrowserURLHandlerCreated(handler);
+}
+
+bool IsWebUIAllowedToMakeNetworkRequests(const url::Origin& origin) {
+ return CefWebUIControllerFactory::IsWebUIAllowedToMakeNetworkRequests(origin);
+}
+
+} // namespace scheme
diff --git a/libcef/browser/net/chrome_scheme_handler.h b/libcef/browser/net/chrome_scheme_handler.h
new file mode 100644
index 00000000..6d28be54
--- /dev/null
+++ b/libcef/browser/net/chrome_scheme_handler.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_NET_CHROME_SCHEME_HANDLER_H_
+#define CEF_LIBCEF_BROWSER_NET_CHROME_SCHEME_HANDLER_H_
+#pragma once
+
+#include <string>
+
+#include "include/cef_browser.h"
+#include "include/cef_frame.h"
+#include "include/cef_process_message.h"
+
+#include "url/gurl.h"
+
+namespace base {
+class ListValue;
+}
+
+namespace content {
+class BrowserURLHandler;
+}
+
+namespace url {
+class Origin;
+}
+
+namespace scheme {
+
+extern const char kChromeURL[];
+
+// Register the WebUI controller factory.
+void RegisterWebUIControllerFactory();
+
+// Register the WebUI handler.
+void BrowserURLHandlerCreated(content::BrowserURLHandler* handler);
+
+// Returns true if WebUI is allowed to make network requests.
+bool IsWebUIAllowedToMakeNetworkRequests(const url::Origin& origin);
+
+} // namespace scheme
+
+#endif // CEF_LIBCEF_BROWSER_CHROME_SCHEME_HANDLER_H_
diff --git a/libcef/browser/net/crlset_file_util_impl.cc b/libcef/browser/net/crlset_file_util_impl.cc
new file mode 100644
index 00000000..fecd791a
--- /dev/null
+++ b/libcef/browser/net/crlset_file_util_impl.cc
@@ -0,0 +1,46 @@
+// Copyright 2017 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#include "include/cef_file_util.h"
+
+#include "libcef/browser/context.h"
+#include "libcef/browser/thread_util.h"
+
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "content/public/browser/network_service_instance.h"
+#include "services/network/network_service.h"
+
+namespace {
+
+void UpdateCRLSet(const std::string& crl_set_bytes) {
+ CEF_REQUIRE_UIT();
+ content::GetNetworkService()->UpdateCRLSet(
+ base::as_bytes(base::make_span(crl_set_bytes)), base::DoNothing());
+}
+
+void LoadFromDisk(const base::FilePath& path) {
+ CEF_REQUIRE_BLOCKING();
+
+ std::string crl_set_bytes;
+ if (!base::ReadFileToString(path, &crl_set_bytes)) {
+ LOG(WARNING) << "Failed to read CRL set from " << path.MaybeAsASCII();
+ return;
+ }
+
+ VLOG(1) << "Loading " << crl_set_bytes.size()
+ << " bytes of CRL set from disk";
+ CEF_POST_TASK(CEF_UIT, base::BindOnce(&UpdateCRLSet, crl_set_bytes));
+}
+
+} // namespace
+
+void CefLoadCRLSetsFile(const CefString& path) {
+ if (!CONTEXT_STATE_VALID()) {
+ NOTREACHED() << "context not valid";
+ return;
+ }
+
+ CEF_POST_USER_VISIBLE_TASK(base::BindOnce(&LoadFromDisk, path));
+}
diff --git a/libcef/browser/net/devtools_scheme_handler.cc b/libcef/browser/net/devtools_scheme_handler.cc
new file mode 100644
index 00000000..97f12042
--- /dev/null
+++ b/libcef/browser/net/devtools_scheme_handler.cc
@@ -0,0 +1,50 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#include "libcef/browser/net/devtools_scheme_handler.h"
+
+#include <string>
+
+#include "libcef/browser/iothread_state.h"
+#include "libcef/browser/net/internal_scheme_handler.h"
+
+#include "base/memory/ptr_util.h"
+#include "base/strings/string_util.h"
+#include "content/public/browser/devtools_frontend_host.h"
+#include "content/public/common/url_constants.h"
+
+namespace scheme {
+
+const char kChromeDevToolsHost[] = "devtools";
+
+namespace {
+
+class Delegate : public InternalHandlerDelegate {
+ public:
+ Delegate() {}
+
+ bool OnRequest(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefRequest> request,
+ Action* action) override {
+ GURL url = GURL(request->GetURL().ToString());
+ std::string path = url.path();
+ if (path.length() > 0) {
+ path = path.substr(1);
+ }
+
+ action->bytes =
+ content::DevToolsFrontendHost::GetFrontendResourceBytes(path);
+ return !!action->bytes;
+ }
+};
+
+} // namespace
+
+void RegisterChromeDevToolsHandler(CefIOThreadState* iothread_state) {
+ iothread_state->RegisterSchemeHandlerFactory(
+ content::kChromeDevToolsScheme, kChromeDevToolsHost,
+ CreateInternalHandlerFactory(base::WrapUnique(new Delegate())));
+}
+
+} // namespace scheme
diff --git a/libcef/browser/net/devtools_scheme_handler.h b/libcef/browser/net/devtools_scheme_handler.h
new file mode 100644
index 00000000..bcde8d62
--- /dev/null
+++ b/libcef/browser/net/devtools_scheme_handler.h
@@ -0,0 +1,20 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_NET_DEVTOOLS_SCHEME_HANDLER_H_
+#define CEF_LIBCEF_BROWSER_NET_DEVTOOLS_SCHEME_HANDLER_H_
+#pragma once
+
+class CefIOThreadState;
+
+namespace scheme {
+
+extern const char kChromeDevToolsHost[];
+
+// Register the chrome-devtools scheme handler.
+void RegisterChromeDevToolsHandler(CefIOThreadState* iothread_state);
+
+} // namespace scheme
+
+#endif // CEF_LIBCEF_BROWSER_NET_DEVTOOLS_SCHEME_HANDLER_H_
diff --git a/libcef/browser/net/internal_scheme_handler.cc b/libcef/browser/net/internal_scheme_handler.cc
new file mode 100644
index 00000000..707147b2
--- /dev/null
+++ b/libcef/browser/net/internal_scheme_handler.cc
@@ -0,0 +1,220 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors.
+// Portions copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/net/internal_scheme_handler.h"
+
+#include <string>
+#include <utility>
+
+#include "libcef/common/app_manager.h"
+
+#include "base/notreached.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_restrictions.h"
+#include "net/base/mime_util.h"
+#include "ui/base/resource/resource_bundle.h"
+
+namespace scheme {
+
+namespace {
+
+base::FilePath FilePathFromASCII(const std::string& str) {
+#if BUILDFLAG(IS_WIN)
+ return base::FilePath(base::ASCIIToWide(str));
+#else
+ return base::FilePath(str);
+#endif
+}
+
+std::string GetMimeType(const std::string& filename) {
+ // Requests should not block on the disk! On POSIX this goes to disk.
+ // http://code.google.com/p/chromium/issues/detail?id=59849
+ base::ScopedAllowBlockingForTesting allow_blocking;
+
+ std::string mime_type;
+ const base::FilePath& file_path = FilePathFromASCII(filename);
+ if (net::GetMimeTypeFromFile(file_path, &mime_type)) {
+ return mime_type;
+ }
+
+ // Check for newer extensions used by internal resources but not yet
+ // recognized by the mime type detector.
+ const std::string& extension = CefString(file_path.FinalExtension());
+ if (extension == ".md") {
+ return "text/markdown";
+ }
+ if (extension == ".woff2") {
+ return "application/font-woff2";
+ }
+
+ NOTREACHED() << "No known mime type for file: " << filename.c_str();
+ return "text/plain";
+}
+
+class RedirectHandler : public CefResourceHandler {
+ public:
+ explicit RedirectHandler(const GURL& url) : url_(url) {}
+
+ RedirectHandler(const RedirectHandler&) = delete;
+ RedirectHandler& operator=(const RedirectHandler&) = delete;
+
+ bool Open(CefRefPtr<CefRequest> request,
+ bool& handle_request,
+ CefRefPtr<CefCallback> callback) override {
+ // Continue immediately.
+ handle_request = true;
+ return true;
+ }
+
+ void GetResponseHeaders(CefRefPtr<CefResponse> response,
+ int64& response_length,
+ CefString& redirectUrl) override {
+ response_length = 0;
+ redirectUrl = url_.spec();
+ }
+
+ bool Read(void* data_out,
+ int bytes_to_read,
+ int& bytes_read,
+ CefRefPtr<CefResourceReadCallback> callback) override {
+ NOTREACHED();
+ return false;
+ }
+
+ void Cancel() override {}
+
+ private:
+ GURL url_;
+
+ IMPLEMENT_REFCOUNTING(RedirectHandler);
+};
+
+class InternalHandler : public CefResourceHandler {
+ public:
+ InternalHandler(const std::string& mime_type,
+ CefRefPtr<CefStreamReader> reader,
+ int size)
+ : mime_type_(mime_type), reader_(reader), size_(size) {}
+
+ InternalHandler(const InternalHandler&) = delete;
+ InternalHandler& operator=(const InternalHandler&) = delete;
+
+ bool Open(CefRefPtr<CefRequest> request,
+ bool& handle_request,
+ CefRefPtr<CefCallback> callback) override {
+ // Continue immediately.
+ handle_request = true;
+ return true;
+ }
+
+ void GetResponseHeaders(CefRefPtr<CefResponse> response,
+ int64& response_length,
+ CefString& redirectUrl) override {
+ response_length = size_;
+
+ response->SetMimeType(mime_type_);
+ response->SetStatus(200);
+ }
+
+ bool Read(void* data_out,
+ int bytes_to_read,
+ int& bytes_read,
+ CefRefPtr<CefResourceReadCallback> callback) override {
+ // Read until the buffer is full or until Read() returns 0 to indicate no
+ // more data.
+ bytes_read = 0;
+ int read = 0;
+ do {
+ read = static_cast<int>(
+ reader_->Read(static_cast<char*>(data_out) + bytes_read, 1,
+ bytes_to_read - bytes_read));
+ bytes_read += read;
+ } while (read != 0 && bytes_read < bytes_to_read);
+
+ return (bytes_read > 0);
+ }
+
+ void Cancel() override {}
+
+ private:
+ std::string mime_type_;
+ CefRefPtr<CefStreamReader> reader_;
+ int size_;
+
+ IMPLEMENT_REFCOUNTING(InternalHandler);
+};
+
+class InternalHandlerFactory : public CefSchemeHandlerFactory {
+ public:
+ explicit InternalHandlerFactory(
+ std::unique_ptr<InternalHandlerDelegate> delegate)
+ : delegate_(std::move(delegate)) {}
+
+ InternalHandlerFactory(const InternalHandlerFactory&) = delete;
+ InternalHandlerFactory& operator=(const InternalHandlerFactory&) = delete;
+
+ CefRefPtr<CefResourceHandler> Create(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const CefString& scheme_name,
+ CefRefPtr<CefRequest> request) override {
+ GURL url = GURL(request->GetURL().ToString());
+
+ InternalHandlerDelegate::Action action;
+ if (delegate_->OnRequest(browser, request, &action)) {
+ if (!action.redirect_url.is_empty() && action.redirect_url.is_valid()) {
+ return new RedirectHandler(action.redirect_url);
+ }
+
+ if (action.mime_type.empty()) {
+ action.mime_type = GetMimeType(url.path());
+ }
+
+ if (!action.bytes && action.resource_id >= 0) {
+ std::string str =
+ ui::ResourceBundle::GetSharedInstance().LoadDataResourceString(
+ action.resource_id);
+ if (str.empty()) {
+ NOTREACHED() << "Failed to load internal resource for id: "
+ << action.resource_id << " URL: " << url.spec().c_str();
+ return nullptr;
+ }
+ action.bytes =
+ base::MakeRefCounted<base::RefCountedString>(std::move(str));
+ }
+
+ if (action.bytes) {
+ action.stream = CefStreamReader::CreateForData(
+ const_cast<unsigned char*>(action.bytes->data()),
+ action.bytes->size());
+ action.stream_size = action.bytes->size();
+ }
+
+ if (action.stream.get()) {
+ return new InternalHandler(action.mime_type, action.stream,
+ action.stream_size);
+ }
+ }
+
+ return nullptr;
+ }
+
+ private:
+ std::unique_ptr<InternalHandlerDelegate> delegate_;
+
+ IMPLEMENT_REFCOUNTING(InternalHandlerFactory);
+};
+
+} // namespace
+
+InternalHandlerDelegate::Action::Action() : stream_size(-1), resource_id(-1) {}
+
+CefRefPtr<CefSchemeHandlerFactory> CreateInternalHandlerFactory(
+ std::unique_ptr<InternalHandlerDelegate> delegate) {
+ DCHECK(delegate.get());
+ return new InternalHandlerFactory(std::move(delegate));
+}
+
+} // namespace scheme
diff --git a/libcef/browser/net/internal_scheme_handler.h b/libcef/browser/net/internal_scheme_handler.h
new file mode 100644
index 00000000..3db3ef07
--- /dev/null
+++ b/libcef/browser/net/internal_scheme_handler.h
@@ -0,0 +1,59 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_NET_INTERNAL_SCHEME_HANDLER_H_
+#define CEF_LIBCEF_BROWSER_NET_INTERNAL_SCHEME_HANDLER_H_
+#pragma once
+
+#include <string>
+
+#include "include/cef_scheme.h"
+
+#include "base/memory/ref_counted_memory.h"
+#include "url/gurl.h"
+
+namespace scheme {
+
+// All methods will be called on the browser process IO thread.
+class InternalHandlerDelegate {
+ public:
+ class Action {
+ public:
+ Action();
+
+ // Set to the appropriate value or leave empty to have it determined based
+ // on the file extension.
+ std::string mime_type;
+
+ // Option 1: Provide a stream for the resource contents. Set |stream_size|
+ // to the stream size or to -1 if unknown.
+ CefRefPtr<CefStreamReader> stream;
+ int stream_size;
+
+ // Option 2: Provide a base::RefCountedMemory for the resource contents.
+ scoped_refptr<base::RefCountedMemory> bytes;
+
+ // Option 3: Specify a resource id to load static content.
+ int resource_id;
+
+ // Option 4: Redirect to the specified URL.
+ GURL redirect_url;
+ };
+
+ virtual ~InternalHandlerDelegate() {}
+
+ // Populate |action| and return true if the request was handled.
+ virtual bool OnRequest(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefRequest> request,
+ Action* action) = 0;
+};
+
+// Create an internal scheme handler factory. The factory will take ownership of
+// |delegate|.
+CefRefPtr<CefSchemeHandlerFactory> CreateInternalHandlerFactory(
+ std::unique_ptr<InternalHandlerDelegate> delegate);
+
+} // namespace scheme
+
+#endif // CEF_LIBCEF_BROWSER_NET_INTERNAL_SCHEME_HANDLER_H_
diff --git a/libcef/browser/net/scheme_handler.cc b/libcef/browser/net/scheme_handler.cc
new file mode 100644
index 00000000..347d21fa
--- /dev/null
+++ b/libcef/browser/net/scheme_handler.cc
@@ -0,0 +1,26 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "libcef/browser/net/scheme_handler.h"
+
+#include <string>
+
+#include "libcef/browser/net/chrome_scheme_handler.h"
+#include "libcef/browser/net/devtools_scheme_handler.h"
+#include "libcef/common/net/scheme_registration.h"
+#include "libcef/features/runtime.h"
+
+#include "content/public/common/url_constants.h"
+
+namespace scheme {
+
+void RegisterInternalHandlers(CefIOThreadState* iothread_state) {
+ if (!cef::IsAlloyRuntimeEnabled()) {
+ return;
+ }
+
+ scheme::RegisterChromeDevToolsHandler(iothread_state);
+}
+
+} // namespace scheme
diff --git a/libcef/browser/net/scheme_handler.h b/libcef/browser/net/scheme_handler.h
new file mode 100644
index 00000000..a991be38
--- /dev/null
+++ b/libcef/browser/net/scheme_handler.h
@@ -0,0 +1,23 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_NET_SCHEME_HANDLER_H_
+#define CEF_LIBCEF_BROWSER_NET_SCHEME_HANDLER_H_
+#pragma once
+
+#include "include/cef_frame.h"
+
+#include "content/public/browser/browser_context.h"
+#include "url/gurl.h"
+
+class CefIOThreadState;
+
+namespace scheme {
+
+// Register the internal scheme handlers that can be overridden.
+void RegisterInternalHandlers(CefIOThreadState* iothread_state);
+
+} // namespace scheme
+
+#endif // CEF_LIBCEF_BROWSER_NET_SCHEME_HANDLER_H_
diff --git a/libcef/browser/net/throttle_handler.cc b/libcef/browser/net/throttle_handler.cc
new file mode 100644
index 00000000..0665b446
--- /dev/null
+++ b/libcef/browser/net/throttle_handler.cc
@@ -0,0 +1,103 @@
+// Copyright 2020 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#include "libcef/browser/net/throttle_handler.h"
+
+#include "libcef/browser/browser_host_base.h"
+#include "libcef/browser/browser_info_manager.h"
+#include "libcef/browser/frame_host_impl.h"
+#include "libcef/common/frame_util.h"
+#include "libcef/common/request_impl.h"
+
+#include "components/navigation_interception/intercept_navigation_throttle.h"
+#include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/navigation_throttle.h"
+#include "content/public/browser/page_navigator.h"
+
+namespace throttle {
+
+namespace {
+
+bool NavigationOnUIThread(content::NavigationHandle* navigation_handle) {
+ CEF_REQUIRE_UIT();
+
+ const bool is_main_frame = navigation_handle->IsInMainFrame();
+ const auto global_id = frame_util::GetGlobalId(navigation_handle);
+
+ // Identify the RenderFrameHost that originated the navigation.
+ const auto parent_global_id =
+ !is_main_frame ? navigation_handle->GetParentFrame()->GetGlobalId()
+ : frame_util::InvalidGlobalId();
+
+ const content::Referrer referrer(navigation_handle->GetReferrer().url,
+ navigation_handle->GetReferrer().policy);
+
+ content::OpenURLParams open_params(navigation_handle->GetURL(), referrer,
+ WindowOpenDisposition::CURRENT_TAB,
+ navigation_handle->GetPageTransition(),
+ navigation_handle->IsRendererInitiated());
+ open_params.user_gesture = navigation_handle->HasUserGesture();
+ open_params.initiator_origin = navigation_handle->GetInitiatorOrigin();
+ open_params.is_pdf = navigation_handle->IsPdf();
+
+ CefRefPtr<CefBrowserHostBase> browser;
+ if (!CefBrowserInfoManager::GetInstance()->MaybeAllowNavigation(
+ navigation_handle->GetWebContents()->GetPrimaryMainFrame(),
+ open_params, browser)) {
+ // Cancel the navigation.
+ return true;
+ }
+
+ bool ignore_navigation = false;
+
+ if (browser) {
+ if (auto client = browser->GetClient()) {
+ if (auto handler = client->GetRequestHandler()) {
+ CefRefPtr<CefFrame> frame;
+ if (is_main_frame) {
+ frame = browser->GetMainFrame();
+ } else {
+ frame = browser->GetFrameForGlobalId(global_id);
+ }
+ if (!frame) {
+ // Create a temporary frame object for navigation of sub-frames that
+ // don't yet exist.
+ frame = browser->browser_info()->CreateTempSubFrame(parent_global_id);
+ }
+
+ CefRefPtr<CefRequestImpl> request = new CefRequestImpl();
+ request->Set(navigation_handle);
+ request->SetReadOnly(true);
+
+ // Initiating a new navigation in OnBeforeBrowse will delete the
+ // InterceptNavigationThrottle that currently owns this callback,
+ // resulting in a crash. Use the lock to prevent that.
+ auto navigation_lock = browser->browser_info()->CreateNavigationLock();
+ ignore_navigation =
+ handler->OnBeforeBrowse(browser.get(), frame, request.get(),
+ navigation_handle->HasUserGesture(),
+ navigation_handle->WasServerRedirect());
+ }
+ }
+ }
+
+ return ignore_navigation;
+}
+
+} // namespace
+
+void CreateThrottlesForNavigation(content::NavigationHandle* navigation_handle,
+ NavigationThrottleList& throttles) {
+ CEF_REQUIRE_UIT();
+
+ // Must use SynchronyMode::kSync to ensure that OnBeforeBrowse is always
+ // called before OnBeforeResourceLoad.
+ std::unique_ptr<content::NavigationThrottle> throttle =
+ std::make_unique<navigation_interception::InterceptNavigationThrottle>(
+ navigation_handle, base::BindRepeating(&NavigationOnUIThread),
+ navigation_interception::SynchronyMode::kSync);
+ throttles.push_back(std::move(throttle));
+}
+
+} // namespace throttle
diff --git a/libcef/browser/net/throttle_handler.h b/libcef/browser/net/throttle_handler.h
new file mode 100644
index 00000000..5810fb4f
--- /dev/null
+++ b/libcef/browser/net/throttle_handler.h
@@ -0,0 +1,27 @@
+// Copyright 2020 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_NET_THROTTLE_HANDLER_H_
+#define CEF_LIBCEF_BROWSER_NET_THROTTLE_HANDLER_H_
+#pragma once
+
+#include <memory>
+#include <vector>
+
+namespace content {
+class NavigationHandle;
+class NavigationThrottle;
+} // namespace content
+
+namespace throttle {
+
+using NavigationThrottleList =
+ std::vector<std::unique_ptr<content::NavigationThrottle>>;
+
+void CreateThrottlesForNavigation(content::NavigationHandle* navigation_handle,
+ NavigationThrottleList& throttles);
+
+} // namespace throttle
+
+#endif // CEF_LIBCEF_BROWSER_NET_THROTTLE_HANDLER_H_
diff --git a/libcef/browser/net_service/browser_urlrequest_impl.cc b/libcef/browser/net_service/browser_urlrequest_impl.cc
new file mode 100644
index 00000000..a8247e27
--- /dev/null
+++ b/libcef/browser/net_service/browser_urlrequest_impl.cc
@@ -0,0 +1,702 @@
+// Copyright (c) 2019 The Chromium Embedded Framework Authors. Portions
+// Copyright (c) 2018 The Chromium Authors. All rights reserved. Use of this
+// source code is governed by a BSD-style license that can be found in the
+// LICENSE file.
+
+#include "libcef/browser/net_service/browser_urlrequest_impl.h"
+
+#include <string>
+#include <utility>
+
+#include "libcef/browser/browser_context.h"
+#include "libcef/browser/frame_host_impl.h"
+#include "libcef/browser/net_service/url_loader_factory_getter.h"
+#include "libcef/browser/request_context_impl.h"
+#include "libcef/browser/thread_util.h"
+#include "libcef/common/net_service/net_service_util.h"
+#include "libcef/common/request_impl.h"
+#include "libcef/common/response_impl.h"
+#include "libcef/common/task_runner_impl.h"
+
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/memory/weak_ptr.h"
+#include "base/strings/string_util.h"
+#include "content/browser/renderer_host/render_frame_host_impl.h"
+#include "content/browser/storage_partition_impl.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/global_request_id.h"
+#include "content/public/browser/render_frame_host.h"
+#include "net/base/mime_util.h"
+#include "net/base/net_errors.h"
+#include "net/http/http_response_headers.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "services/network/public/cpp/simple_url_loader.h"
+#include "services/network/public/cpp/simple_url_loader_stream_consumer.h"
+#include "third_party/blink/public/mojom/loader/resource_load_info.mojom.h"
+
+namespace {
+
+const int32_t kInitialRequestID = -2;
+
+// Request ID for requests initiated by CefBrowserURLRequest. request_ids
+// generated by child processes are counted up from 0, while browser
+// created requests start at -2 and go down from there. (We need to start at -2
+// because -1 is used as a special value all over the resource_dispatcher_host
+// for uninitialized variables.) The resource_dispatcher_host code path is not
+// used when NetworkService is enabled so it's safe to repurpose the -2 and
+// below range here.
+// This method is only called on the UI thread.
+int32_t MakeRequestID() {
+ static int32_t request_id = kInitialRequestID;
+ return --request_id;
+}
+
+bool IsValidRequestID(int32_t request_id) {
+ return request_id < kInitialRequestID;
+}
+
+// Manages the mapping of request IDs to request objects.
+class RequestManager {
+ public:
+ RequestManager() {}
+
+ RequestManager(const RequestManager&) = delete;
+ RequestManager& operator=(const RequestManager&) = delete;
+
+ ~RequestManager() { DCHECK(map_.empty()); }
+
+ void Add(int32_t request_id,
+ CefRefPtr<CefBrowserURLRequest> request,
+ CefRefPtr<CefURLRequestClient> client) {
+ DCHECK_LE(request_id, kInitialRequestID);
+
+ base::AutoLock lock_scope(lock_);
+ DCHECK(map_.find(request_id) == map_.end());
+ map_.insert(std::make_pair(request_id, std::make_pair(request, client)));
+ }
+
+ void Remove(int32_t request_id) {
+ if (request_id > kInitialRequestID) {
+ return;
+ }
+
+ base::AutoLock lock_scope(lock_);
+ RequestMap::iterator it = map_.find(request_id);
+ DCHECK(it != map_.end());
+ map_.erase(it);
+ }
+
+ absl::optional<CefBrowserURLRequest::RequestInfo> Get(int32_t request_id) {
+ if (request_id > kInitialRequestID) {
+ return absl::nullopt;
+ }
+
+ base::AutoLock lock_scope(lock_);
+ RequestMap::const_iterator it = map_.find(request_id);
+ if (it != map_.end()) {
+ return it->second;
+ }
+ return absl::nullopt;
+ }
+
+ private:
+ base::Lock lock_;
+
+ using RequestMap = std::map<int32_t, CefBrowserURLRequest::RequestInfo>;
+ RequestMap map_;
+};
+
+#if DCHECK_IS_ON()
+// Because of DCHECK()s in the object destructor.
+base::LazyInstance<RequestManager>::DestructorAtExit g_manager =
+ LAZY_INSTANCE_INITIALIZER;
+#else
+base::LazyInstance<RequestManager>::Leaky g_manager = LAZY_INSTANCE_INITIALIZER;
+#endif
+
+} // namespace
+
+// CefBrowserURLRequest::Context ----------------------------------------------
+
+class CefBrowserURLRequest::Context
+ : public network::SimpleURLLoaderStreamConsumer {
+ public:
+ Context(CefRefPtr<CefBrowserURLRequest> url_request,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefURLRequestClient> client,
+ CefRefPtr<CefRequestContext> request_context)
+ : url_request_(url_request),
+ frame_(frame),
+ request_(static_cast<CefRequestImpl*>(request.get())),
+ client_(client),
+ request_context_(request_context),
+ task_runner_(CefTaskRunnerImpl::GetCurrentTaskRunner()),
+ response_(new CefResponseImpl()),
+ weak_ptr_factory_(this) {
+ // Mark the request/response objects as read-only.
+ request_->SetReadOnly(true);
+ response_->SetReadOnly(true);
+ }
+ ~Context() override = default;
+
+ bool Start() {
+ DCHECK(CalledOnValidThread());
+
+ const GURL& url = GURL(request_->GetURL().ToString());
+ if (!url.is_valid()) {
+ return false;
+ }
+
+ if (!request_context_) {
+ request_context_ = CefRequestContext::GetGlobalContext();
+ }
+
+ auto request_context_impl =
+ static_cast<CefRequestContextImpl*>(request_context_.get());
+
+ // Wait for the browser context to be initialized before continuing.
+ request_context_impl->ExecuteWhenBrowserContextInitialized(base::BindOnce(
+ &CefBrowserURLRequest::Context::GetURLLoaderFactoryGetterOnUIThread,
+ frame_, request_context_, weak_ptr_factory_.GetWeakPtr(),
+ task_runner_));
+
+ return true;
+ }
+
+ void Cancel() {
+ DCHECK(CalledOnValidThread());
+
+ // The request may already be complete or canceled.
+ if (!url_request_) {
+ return;
+ }
+
+ DCHECK_EQ(status_, UR_IO_PENDING);
+ status_ = UR_CANCELED;
+
+ response_->SetReadOnly(false);
+ response_->SetError(ERR_ABORTED);
+ response_->SetReadOnly(true);
+
+ cleanup_immediately_ = true;
+ OnComplete(false);
+ }
+
+ CefRefPtr<CefRequest> request() const { return request_.get(); }
+ CefRefPtr<CefURLRequestClient> client() const { return client_; }
+ CefURLRequest::Status status() const { return status_; }
+ CefRefPtr<CefResponse> response() const { return response_.get(); }
+ bool response_was_cached() const { return response_was_cached_; }
+
+ inline bool CalledOnValidThread() {
+ return task_runner_->RunsTasksInCurrentSequence();
+ }
+
+ private:
+ static void GetURLLoaderFactoryGetterOnUIThread(
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequestContext> request_context,
+ base::WeakPtr<CefBrowserURLRequest::Context> self,
+ scoped_refptr<base::SequencedTaskRunner> task_runner) {
+ CEF_REQUIRE_UIT();
+
+ // Get or create the request context and browser context.
+ CefRefPtr<CefRequestContextImpl> request_context_impl =
+ CefRequestContextImpl::GetOrCreateForRequestContext(request_context);
+ CHECK(request_context_impl);
+ CefBrowserContext* cef_browser_context =
+ request_context_impl->GetBrowserContext();
+ CHECK(cef_browser_context);
+ auto browser_context = cef_browser_context->AsBrowserContext();
+ CHECK(browser_context);
+
+ scoped_refptr<net_service::URLLoaderFactoryGetter> loader_factory_getter;
+
+ // Used to route authentication and certificate callbacks through the
+ // associated StoragePartition instance.
+ mojo::PendingRemote<network::mojom::URLLoaderNetworkServiceObserver>
+ url_loader_network_observer;
+
+ if (frame) {
+ // The request will be associated with this frame/browser if it's valid,
+ // otherwise the request will be canceled.
+ content::RenderFrameHost* rfh =
+ static_cast<CefFrameHostImpl*>(frame.get())->GetRenderFrameHost();
+ if (rfh) {
+ loader_factory_getter =
+ net_service::URLLoaderFactoryGetter::Create(rfh, browser_context);
+ url_loader_network_observer =
+ static_cast<content::RenderFrameHostImpl*>(rfh)
+ ->CreateURLLoaderNetworkObserver();
+ }
+ } else {
+ loader_factory_getter =
+ net_service::URLLoaderFactoryGetter::Create(nullptr, browser_context);
+ url_loader_network_observer =
+ static_cast<content::StoragePartitionImpl*>(
+ browser_context->GetDefaultStoragePartition())
+ ->CreateAuthCertObserverForServiceWorker();
+ }
+
+ task_runner->PostTask(
+ FROM_HERE,
+ base::BindOnce(
+ &CefBrowserURLRequest::Context::ContinueOnOriginatingThread, self,
+ MakeRequestID(), loader_factory_getter,
+ std::move(url_loader_network_observer)));
+ }
+
+ void ContinueOnOriginatingThread(
+ int32_t request_id,
+ scoped_refptr<net_service::URLLoaderFactoryGetter> loader_factory_getter,
+ mojo::PendingRemote<network::mojom::URLLoaderNetworkServiceObserver>
+ url_loader_network_observer) {
+ DCHECK(CalledOnValidThread());
+
+ // The request may have been canceled.
+ if (!url_request_) {
+ return;
+ }
+
+ if (!loader_factory_getter) {
+ // Cancel the request immediately.
+ Cancel();
+ return;
+ }
+
+ DCHECK_EQ(status_, UR_IO_PENDING);
+
+ loader_factory_getter_ = loader_factory_getter;
+
+ const int request_flags = request_->GetFlags();
+
+ // Create the URLLoaderFactory and bind to this thread.
+ auto loader_factory = loader_factory_getter_->GetURLLoaderFactory();
+
+ auto resource_request = std::make_unique<network::ResourceRequest>();
+ static_cast<CefRequestImpl*>(request_.get())
+ ->Get(resource_request.get(), false);
+
+ // Behave the same as a subresource load.
+ resource_request->resource_type =
+ static_cast<int>(blink::mojom::ResourceType::kSubResource);
+
+ // Set the origin to match the request.
+ const GURL& url = GURL(request_->GetURL().ToString());
+ resource_request->request_initiator = url::Origin::Create(url);
+
+ if (request_flags & UR_FLAG_ALLOW_STORED_CREDENTIALS) {
+ // Include SameSite cookies.
+ resource_request->site_for_cookies =
+ net::SiteForCookies::FromOrigin(*resource_request->request_initiator);
+ }
+
+ if (url_loader_network_observer) {
+ resource_request->trusted_params =
+ network::ResourceRequest::TrustedParams();
+ resource_request->trusted_params->url_loader_network_observer =
+ std::move(url_loader_network_observer);
+ }
+
+ // SimpleURLLoader is picky about the body contents. Try to populate them
+ // correctly below.
+ auto request_body = resource_request->request_body;
+ resource_request->request_body = nullptr;
+
+ std::string content_type;
+ std::string method = resource_request->method;
+ if (request_body) {
+ if (method == "GET" || method == "HEAD") {
+ // Fix the method value to allow a request body.
+ method = "POST";
+ resource_request->method = method;
+
+ request_->SetReadOnly(false);
+ request_->SetMethod(method);
+ request_->SetReadOnly(true);
+ }
+ resource_request->headers.GetHeader(net::HttpRequestHeaders::kContentType,
+ &content_type);
+ }
+
+ loader_ = network::SimpleURLLoader::Create(std::move(resource_request),
+ MISSING_TRAFFIC_ANNOTATION);
+
+ // Associate the request with |request_id|.
+ request_id_ = request_id;
+ loader_->SetRequestID(request_id);
+ g_manager.Get().Add(request_id, url_request_, client_);
+
+ if (request_body) {
+ if (request_body->elements()->size() == 1) {
+ const auto& element = (*request_body->elements())[0];
+ if (element.type() == network::DataElement::Tag::kFile) {
+ const auto& file_element = element.As<network::DataElementFile>();
+ if (content_type.empty()) {
+ const auto& extension = file_element.path().Extension();
+ if (!extension.empty()) {
+ // Requests should not block on the disk! On POSIX this goes to
+ // disk. http://code.google.com/p/chromium/issues/detail?id=59849
+ base::ScopedAllowBlockingForTesting allow_blocking;
+ // Also remove the leading period.
+ net::GetMimeTypeFromExtension(extension.substr(1), &content_type);
+ }
+ }
+ loader_->AttachFileForUpload(file_element.path(), content_type);
+ } else if (element.type() == network::DataElement::Tag::kBytes) {
+ const auto& bytes_element = element.As<network::DataElementBytes>();
+ const auto& bytes = bytes_element.bytes();
+ if (content_type.empty()) {
+ content_type = net_service::kContentTypeApplicationFormURLEncoded;
+ }
+ loader_->AttachStringForUpload(
+ std::string(bytes_element.AsStringPiece()), content_type);
+
+ if (request_flags & UR_FLAG_REPORT_UPLOAD_PROGRESS) {
+ // Report the expected upload data size.
+ upload_data_size_ = bytes.size();
+ }
+ } else {
+ NOTIMPLEMENTED() << "Unsupported element type: "
+ << static_cast<int>(element.type());
+ }
+ } else if (request_body->elements()->size() > 1) {
+ NOTIMPLEMENTED() << "Multi-part form data is not supported";
+ }
+ }
+
+ // Allow delivery of non-2xx response bodies.
+ loader_->SetAllowHttpErrorResults(true);
+
+ if (!(request_flags & UR_FLAG_NO_RETRY_ON_5XX)) {
+ // Allow 2 retries on 5xx response or network change.
+ // TODO(network): Consider exposing configuration of max retries and/or
+ // RETRY_ON_NETWORK_CHANGE as a separate flag.
+ loader_->SetRetryOptions(
+ 2, network::SimpleURLLoader::RETRY_ON_5XX |
+ network::SimpleURLLoader::RETRY_ON_NETWORK_CHANGE);
+ }
+
+ if (request_flags & UR_FLAG_STOP_ON_REDIRECT) {
+ // The request will be canceled in OnRedirect.
+ loader_->SetOnRedirectCallback(
+ base::BindRepeating(&CefBrowserURLRequest::Context::OnRedirect,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
+
+ if (request_flags & UR_FLAG_REPORT_UPLOAD_PROGRESS) {
+ loader_->SetOnUploadProgressCallback(
+ base::BindRepeating(&CefBrowserURLRequest::Context::OnUploadProgress,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
+
+ if ((request_flags & UR_FLAG_NO_DOWNLOAD_DATA) || method == "HEAD") {
+ loader_->DownloadHeadersOnly(
+ loader_factory.get(),
+ base::BindOnce(&CefBrowserURLRequest::Context::OnHeadersOnly,
+ weak_ptr_factory_.GetWeakPtr()));
+ } else {
+ loader_->SetOnResponseStartedCallback(
+ base::BindOnce(&CefBrowserURLRequest::Context::OnResponseStarted,
+ weak_ptr_factory_.GetWeakPtr()));
+ loader_->SetOnDownloadProgressCallback(base::BindRepeating(
+ &CefBrowserURLRequest::Context::OnDownloadProgress,
+ weak_ptr_factory_.GetWeakPtr()));
+
+ loader_->DownloadAsStream(loader_factory.get(), this);
+ }
+ }
+
+ void OnHeadersOnly(scoped_refptr<net::HttpResponseHeaders> headers) {
+ DCHECK(CalledOnValidThread());
+ DCHECK_EQ(status_, UR_IO_PENDING);
+
+ cleanup_immediately_ = true;
+
+ if (headers) {
+ response_->SetReadOnly(false);
+ response_->SetResponseHeaders(*headers);
+ response_->SetReadOnly(true);
+
+ // Match the previous behavior of sending download progress notifications
+ // for UR_FLAG_NO_DOWNLOAD_DATA requests but not HEAD requests.
+ if (request_->GetMethod().ToString() != "HEAD") {
+ download_data_size_ = headers->GetContentLength();
+ OnDownloadProgress(0);
+ }
+
+ OnComplete(true);
+ } else {
+ OnComplete(false);
+ }
+ }
+
+ void OnRedirect(const net::RedirectInfo& redirect_info,
+ const network::mojom::URLResponseHead& response_head,
+ std::vector<std::string>* removed_headers) {
+ DCHECK(CalledOnValidThread());
+ DCHECK_EQ(status_, UR_IO_PENDING);
+
+ // This method is only called if we intend to stop on redirects.
+ DCHECK(request_->GetFlags() | UR_FLAG_STOP_ON_REDIRECT);
+
+ response_->SetReadOnly(false);
+ response_->SetURL(redirect_info.new_url.spec());
+ response_->SetResponseHeaders(*response_head.headers);
+ response_->SetReadOnly(true);
+
+ Cancel();
+ }
+
+ void OnResponseStarted(const GURL& final_url,
+ const network::mojom::URLResponseHead& response_head) {
+ DCHECK(CalledOnValidThread());
+ DCHECK_EQ(status_, UR_IO_PENDING);
+
+ response_->SetReadOnly(false);
+ response_->SetURL(final_url.spec());
+ response_->SetResponseHeaders(*response_head.headers);
+ response_->SetReadOnly(true);
+
+ download_data_size_ = response_head.content_length;
+ }
+
+ void OnUploadProgress(uint64_t position, uint64_t total) {
+ DCHECK(CalledOnValidThread());
+ DCHECK_EQ(status_, UR_IO_PENDING);
+
+ upload_data_size_ = total;
+ if (position == total) {
+ got_upload_progress_complete_ = true;
+ }
+
+ client_->OnUploadProgress(url_request_.get(), position, total);
+ }
+
+ void OnDownloadProgress(uint64_t current) {
+ DCHECK(CalledOnValidThread());
+ DCHECK_EQ(status_, UR_IO_PENDING);
+
+ if (response_->GetStatus() == 0) {
+ // With failed requests this callback may arrive without a proceeding
+ // OnHeadersOnly or OnResponseStarted.
+ return;
+ }
+
+ NotifyUploadProgressIfNecessary();
+
+ client_->OnDownloadProgress(url_request_.get(), current,
+ download_data_size_);
+ }
+
+ void NotifyUploadProgressIfNecessary() {
+ if (!got_upload_progress_complete_ && upload_data_size_ > 0) {
+ // URLLoader sends upload notifications using a timer and will not send
+ // a notification if the request completes too quickly. We therefore
+ // send the notification here if necessary.
+ client_->OnUploadProgress(url_request_.get(), upload_data_size_,
+ upload_data_size_);
+ got_upload_progress_complete_ = true;
+ }
+ }
+
+ // SimpleURLLoaderStreamConsumer methods:
+ void OnDataReceived(base::StringPiece string_piece,
+ base::OnceClosure resume) override {
+ DCHECK(CalledOnValidThread());
+ DCHECK_EQ(status_, UR_IO_PENDING);
+
+ client_->OnDownloadData(url_request_.get(), string_piece.data(),
+ string_piece.length());
+ std::move(resume).Run();
+ }
+
+ void OnComplete(bool success) override {
+ DCHECK(CalledOnValidThread());
+
+ // The request may already be complete or canceled.
+ if (!url_request_) {
+ return;
+ }
+
+ // Status will be UR_IO_PENDING if we're called when the request is complete
+ // (via SimpleURLLoaderStreamConsumer or OnHeadersOnly). We can only call
+ // these SimpleURLLoader methods if the request is complete.
+ if (status_ == UR_IO_PENDING) {
+ status_ = success ? UR_SUCCESS : UR_FAILED;
+
+ response_->SetReadOnly(false);
+ response_->SetURL(loader_->GetFinalURL().spec());
+ response_->SetError(static_cast<cef_errorcode_t>(loader_->NetError()));
+ response_->SetReadOnly(true);
+
+ response_was_cached_ = loader_->LoadedFromCache();
+ }
+
+ if (success) {
+ NotifyUploadProgressIfNecessary();
+ }
+
+ client_->OnRequestComplete(url_request_.get());
+
+ // When called via SimpleURLLoaderStreamConsumer we need to cleanup
+ // asynchronously. If the load is still pending this will also cancel it.
+ Cleanup();
+ }
+
+ void OnRetry(base::OnceClosure start_retry) override {
+ DCHECK(CalledOnValidThread());
+ DCHECK_EQ(status_, UR_IO_PENDING);
+ std::move(start_retry).Run();
+ }
+
+ void Cleanup() {
+ DCHECK(CalledOnValidThread());
+ DCHECK(url_request_);
+
+ g_manager.Get().Remove(request_id_);
+
+ client_ = nullptr;
+ request_context_ = nullptr;
+
+ // We may be canceled before the loader is created.
+ if (loader_) {
+ // Must delete the loader before the factory.
+ if (cleanup_immediately_) {
+ // Most SimpleURLLoader callbacks let us delete the URLLoader objects
+ // immediately.
+ loader_.reset();
+ loader_factory_getter_ = nullptr;
+ } else {
+ // Delete the URLLoader objects asynchronously on the correct thread.
+ task_runner_->DeleteSoon(FROM_HERE, std::move(loader_));
+ task_runner_->ReleaseSoon(FROM_HERE, std::move(loader_factory_getter_));
+ }
+ }
+
+ // We may be holding the last reference to |url_request_|, destruction of
+ // which will delete |this|. Use a local variable to keep |url_request_|
+ // alive until this method returns.
+ auto url_request = url_request_;
+ url_request_ = nullptr;
+ }
+
+ // Members only accessed on the initialization thread.
+ CefRefPtr<CefBrowserURLRequest> url_request_;
+ CefRefPtr<CefFrame> frame_;
+ CefRefPtr<CefRequestImpl> request_;
+ CefRefPtr<CefURLRequestClient> client_;
+ CefRefPtr<CefRequestContext> request_context_;
+ scoped_refptr<base::SequencedTaskRunner> task_runner_;
+
+ scoped_refptr<net_service::URLLoaderFactoryGetter> loader_factory_getter_;
+ std::unique_ptr<network::SimpleURLLoader> loader_;
+
+ int32_t request_id_ = 0;
+
+ CefURLRequest::Status status_ = UR_IO_PENDING;
+ CefRefPtr<CefResponseImpl> response_;
+ bool response_was_cached_ = false;
+ int64 upload_data_size_ = 0;
+ int64 download_data_size_ = -1;
+ bool got_upload_progress_complete_ = false;
+ bool cleanup_immediately_ = false;
+
+ // Must be the last member.
+ base::WeakPtrFactory<CefBrowserURLRequest::Context> weak_ptr_factory_;
+};
+
+// CefBrowserURLRequest -------------------------------------------------------
+
+// static
+absl::optional<CefBrowserURLRequest::RequestInfo>
+CefBrowserURLRequest::FromRequestID(int32_t request_id) {
+ if (IsValidRequestID(request_id)) {
+ return g_manager.Get().Get(request_id);
+ }
+ return absl::nullopt;
+}
+
+// static
+absl::optional<CefBrowserURLRequest::RequestInfo>
+CefBrowserURLRequest::FromRequestID(
+ const content::GlobalRequestID& request_id) {
+ return FromRequestID(request_id.request_id);
+}
+
+CefBrowserURLRequest::CefBrowserURLRequest(
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefURLRequestClient> client,
+ CefRefPtr<CefRequestContext> request_context) {
+ context_.reset(new Context(this, frame, request, client, request_context));
+}
+
+CefBrowserURLRequest::~CefBrowserURLRequest() {}
+
+bool CefBrowserURLRequest::Start() {
+ if (!VerifyContext()) {
+ return false;
+ }
+ return context_->Start();
+}
+
+CefRefPtr<CefRequest> CefBrowserURLRequest::GetRequest() {
+ if (!VerifyContext()) {
+ return nullptr;
+ }
+ return context_->request();
+}
+
+CefRefPtr<CefURLRequestClient> CefBrowserURLRequest::GetClient() {
+ if (!VerifyContext()) {
+ return nullptr;
+ }
+ return context_->client();
+}
+
+CefURLRequest::Status CefBrowserURLRequest::GetRequestStatus() {
+ if (!VerifyContext()) {
+ return UR_UNKNOWN;
+ }
+ return context_->status();
+}
+
+CefURLRequest::ErrorCode CefBrowserURLRequest::GetRequestError() {
+ if (!VerifyContext()) {
+ return ERR_NONE;
+ }
+ return context_->response()->GetError();
+}
+
+CefRefPtr<CefResponse> CefBrowserURLRequest::GetResponse() {
+ if (!VerifyContext()) {
+ return nullptr;
+ }
+ return context_->response();
+}
+
+bool CefBrowserURLRequest::ResponseWasCached() {
+ if (!VerifyContext()) {
+ return false;
+ }
+ return context_->response_was_cached();
+}
+
+void CefBrowserURLRequest::Cancel() {
+ if (!VerifyContext()) {
+ return;
+ }
+ return context_->Cancel();
+}
+
+bool CefBrowserURLRequest::VerifyContext() {
+ if (!context_->CalledOnValidThread()) {
+ NOTREACHED() << "called on invalid thread";
+ return false;
+ }
+
+ return true;
+}
diff --git a/libcef/browser/net_service/browser_urlrequest_impl.h b/libcef/browser/net_service/browser_urlrequest_impl.h
new file mode 100644
index 00000000..21843b9b
--- /dev/null
+++ b/libcef/browser/net_service/browser_urlrequest_impl.h
@@ -0,0 +1,61 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_NET_SERVICE_BROWSER_URLREQUEST_IMPL_H_
+#define CEF_LIBCEF_BROWSER_NET_SERVICE_BROWSER_URLREQUEST_IMPL_H_
+
+#include <memory>
+
+#include "include/cef_urlrequest.h"
+
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace content {
+struct GlobalRequestID;
+}
+
+class CefBrowserURLRequest : public CefURLRequest {
+ public:
+ class Context;
+
+ // TODO(network): After the old network code path is deleted move the
+ // CefURLRequestClient::GetAuthCredentials callback to the context thread and
+ // return just the CefBrowserURLRequest object here. The *Client object can
+ // then be retrieved by calling GetClient() from the required thread.
+ using RequestInfo = std::pair<CefRefPtr<CefBrowserURLRequest>,
+ CefRefPtr<CefURLRequestClient>>;
+
+ // Retrieve the request objects, if any, associated with |request_id|.
+ static absl::optional<RequestInfo> FromRequestID(int32_t request_id);
+ static absl::optional<RequestInfo> FromRequestID(
+ const content::GlobalRequestID& request_id);
+
+ // If |frame| is nullptr requests can still be intercepted but no
+ // browser/frame will be associated with them.
+ CefBrowserURLRequest(CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefURLRequestClient> client,
+ CefRefPtr<CefRequestContext> request_context);
+ ~CefBrowserURLRequest() override;
+
+ bool Start();
+
+ // CefURLRequest methods.
+ CefRefPtr<CefRequest> GetRequest() override;
+ CefRefPtr<CefURLRequestClient> GetClient() override;
+ Status GetRequestStatus() override;
+ ErrorCode GetRequestError() override;
+ CefRefPtr<CefResponse> GetResponse() override;
+ bool ResponseWasCached() override;
+ void Cancel() override;
+
+ private:
+ bool VerifyContext();
+
+ std::unique_ptr<Context> context_;
+
+ IMPLEMENT_REFCOUNTING(CefBrowserURLRequest);
+};
+
+#endif // CEF_LIBCEF_BROWSER_NET_SERVICE_BROWSER_URLREQUEST_IMPL_H_
diff --git a/libcef/browser/net_service/cookie_helper.cc b/libcef/browser/net_service/cookie_helper.cc
new file mode 100644
index 00000000..b0f75365
--- /dev/null
+++ b/libcef/browser/net_service/cookie_helper.cc
@@ -0,0 +1,321 @@
+// Copyright (c) 2019 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#include "libcef/browser/net_service/cookie_helper.h"
+
+#include "libcef/browser/thread_util.h"
+#include "libcef/common/net_service/net_service_util.h"
+
+#include "base/functional/bind.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/storage_partition.h"
+#include "content/public/common/url_constants.h"
+#include "net/base/load_flags.h"
+#include "net/cookies/cookie_options.h"
+#include "net/cookies/cookie_util.h"
+#include "services/network/cookie_manager.h"
+#include "services/network/public/cpp/resource_request.h"
+
+namespace net_service {
+namespace cookie_helper {
+
+namespace {
+
+// Do not keep a reference to the object returned by this method.
+CefBrowserContext* GetBrowserContext(const CefBrowserContext::Getter& getter) {
+ CEF_REQUIRE_UIT();
+ DCHECK(!getter.is_null());
+
+ // Will return nullptr if the BrowserContext has been shut down.
+ return getter.Run();
+}
+
+// Do not keep a reference to the object returned by this method.
+network::mojom::CookieManager* GetCookieManager(
+ content::BrowserContext* browser_context) {
+ CEF_REQUIRE_UIT();
+ return browser_context->GetDefaultStoragePartition()
+ ->GetCookieManagerForBrowserProcess();
+}
+
+net::CookieOptions GetCookieOptions(const network::ResourceRequest& request,
+ bool for_loading_cookies) {
+ // Match the logic from InterceptionJob::FetchCookies and
+ // ChromeContentBrowserClient::ShouldIgnoreSameSiteCookieRestrictionsWhenTopLevel.
+ bool should_treat_as_first_party =
+ request.url.SchemeIsCryptographic() &&
+ request.site_for_cookies.scheme() == content::kChromeUIScheme;
+ bool is_main_frame_navigation =
+ request.trusted_params &&
+ request.trusted_params->isolation_info.request_type() ==
+ net::IsolationInfo::RequestType::kMainFrame;
+
+ // Match the logic from URLRequest::SetURLChain.
+ std::vector<GURL> url_chain{request.url};
+ if (request.navigation_redirect_chain.size() >= 2) {
+ // Keep |request.url| as the final entry in the chain.
+ url_chain.insert(url_chain.begin(),
+ request.navigation_redirect_chain.begin(),
+ request.navigation_redirect_chain.begin() +
+ request.navigation_redirect_chain.size() - 1);
+ }
+
+ net::CookieOptions options;
+ options.set_include_httponly();
+ if (for_loading_cookies) {
+ // Match the logic from URLRequestHttpJob::AddCookieHeaderAndStart.
+ options.set_same_site_cookie_context(
+ net::cookie_util::ComputeSameSiteContextForRequest(
+ request.method, url_chain, request.site_for_cookies,
+ request.request_initiator, is_main_frame_navigation,
+ should_treat_as_first_party));
+ } else {
+ // Match the logic from
+ // URLRequestHttpJob::SaveCookiesAndNotifyHeadersComplete.
+ options.set_same_site_cookie_context(
+ net::cookie_util::ComputeSameSiteContextForResponse(
+ url_chain, request.site_for_cookies, request.request_initiator,
+ is_main_frame_navigation, should_treat_as_first_party));
+ }
+
+ return options;
+}
+
+//
+// LOADING COOKIES.
+//
+
+void ContinueWithLoadedCookies(const AllowCookieCallback& allow_cookie_callback,
+ DoneCookieCallback done_callback,
+ const net::CookieAccessResultList& cookies) {
+ CEF_REQUIRE_IOT();
+ net::CookieList allowed_cookies;
+ for (const auto& status : cookies) {
+ bool allow = false;
+ allow_cookie_callback.Run(status.cookie, &allow);
+ if (allow) {
+ allowed_cookies.push_back(status.cookie);
+ }
+ }
+ std::move(done_callback).Run(cookies.size(), std::move(allowed_cookies));
+}
+
+void GetCookieListCallback(const AllowCookieCallback& allow_cookie_callback,
+ DoneCookieCallback done_callback,
+ const net::CookieAccessResultList& included_cookies,
+ const net::CookieAccessResultList&) {
+ CEF_REQUIRE_UIT();
+ CEF_POST_TASK(CEF_IOT,
+ base::BindOnce(ContinueWithLoadedCookies, allow_cookie_callback,
+ std::move(done_callback), included_cookies));
+}
+
+void LoadCookiesOnUIThread(
+ const CefBrowserContext::Getter& browser_context_getter,
+ const GURL& url,
+ const net::CookieOptions& options,
+ net::CookiePartitionKeyCollection cookie_partition_key_collection,
+ const AllowCookieCallback& allow_cookie_callback,
+ DoneCookieCallback done_callback) {
+ auto cef_browser_context = GetBrowserContext(browser_context_getter);
+ auto browser_context =
+ cef_browser_context ? cef_browser_context->AsBrowserContext() : nullptr;
+ if (!browser_context) {
+ GetCookieListCallback(allow_cookie_callback, std::move(done_callback),
+ net::CookieAccessResultList(),
+ net::CookieAccessResultList());
+ return;
+ }
+
+ GetCookieManager(browser_context)
+ ->GetCookieList(
+ url, options, cookie_partition_key_collection,
+ base::BindOnce(GetCookieListCallback, allow_cookie_callback,
+ std::move(done_callback)));
+}
+
+//
+// SAVING COOKIES.
+//
+
+struct SaveCookiesProgress {
+ DoneCookieCallback done_callback_;
+ int total_count_;
+ net::CookieList allowed_cookies_;
+ int num_cookie_lines_left_;
+};
+
+void SetCanonicalCookieCallback(SaveCookiesProgress* progress,
+ const net::CanonicalCookie& cookie,
+ net::CookieAccessResult access_result) {
+ CEF_REQUIRE_UIT();
+ progress->num_cookie_lines_left_--;
+ if (access_result.status.IsInclude()) {
+ progress->allowed_cookies_.push_back(cookie);
+ }
+
+ // If all the cookie lines have been handled the request can be continued.
+ if (progress->num_cookie_lines_left_ == 0) {
+ CEF_POST_TASK(CEF_IOT,
+ base::BindOnce(std::move(progress->done_callback_),
+ progress->total_count_,
+ std::move(progress->allowed_cookies_)));
+ delete progress;
+ }
+}
+
+void SaveCookiesOnUIThread(
+ const CefBrowserContext::Getter& browser_context_getter,
+ const GURL& url,
+ const net::CookieOptions& options,
+ int total_count,
+ net::CookieList cookies,
+ DoneCookieCallback done_callback) {
+ DCHECK(!cookies.empty());
+
+ auto cef_browser_context = GetBrowserContext(browser_context_getter);
+ auto browser_context =
+ cef_browser_context ? cef_browser_context->AsBrowserContext() : nullptr;
+ if (!browser_context) {
+ std::move(done_callback).Run(0, net::CookieList());
+ return;
+ }
+
+ network::mojom::CookieManager* cookie_manager =
+ GetCookieManager(browser_context);
+
+ // |done_callback| needs to be executed once and only once after the list has
+ // been fully processed. |num_cookie_lines_left_| keeps track of how many
+ // async callbacks are currently pending.
+ auto progress = new SaveCookiesProgress;
+ progress->done_callback_ = std::move(done_callback);
+ progress->total_count_ = total_count;
+
+ // Make sure to wait for the loop to complete.
+ progress->num_cookie_lines_left_ = 1;
+
+ for (const auto& cookie : cookies) {
+ progress->num_cookie_lines_left_++;
+ cookie_manager->SetCanonicalCookie(
+ cookie, url, options,
+ base::BindOnce(&SetCanonicalCookieCallback, base::Unretained(progress),
+ cookie));
+ }
+
+ SetCanonicalCookieCallback(
+ progress, net::CanonicalCookie(),
+ net::CookieAccessResult(net::CookieInclusionStatus(
+ net::CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR)));
+}
+
+} // namespace
+
+bool IsCookieableScheme(
+ const GURL& url,
+ const absl::optional<std::vector<std::string>>& cookieable_schemes) {
+ if (!url.has_scheme()) {
+ return false;
+ }
+
+ if (cookieable_schemes) {
+ // The client has explicitly registered the full set of schemes that should
+ // be supported.
+ const auto url_scheme = url.scheme_piece();
+ for (auto scheme : *cookieable_schemes) {
+ if (url_scheme == scheme) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // Schemes that support cookies by default.
+ // This should match CookieMonster::kDefaultCookieableSchemes.
+ return url.SchemeIsHTTPOrHTTPS() || url.SchemeIsWSOrWSS();
+}
+
+void LoadCookies(const CefBrowserContext::Getter& browser_context_getter,
+ const network::ResourceRequest& request,
+ const AllowCookieCallback& allow_cookie_callback,
+ DoneCookieCallback done_callback) {
+ CEF_REQUIRE_IOT();
+
+ if ((request.load_flags & net::LOAD_DO_NOT_SEND_COOKIES) ||
+ request.credentials_mode == network::mojom::CredentialsMode::kOmit ||
+ request.url.IsAboutBlank()) {
+ // Continue immediately without loading cookies.
+ std::move(done_callback).Run(0, {});
+ return;
+ }
+
+ CEF_POST_TASK(
+ CEF_UIT,
+ base::BindOnce(LoadCookiesOnUIThread, browser_context_getter, request.url,
+ GetCookieOptions(request, /*for_loading_cookies=*/true),
+ net::CookiePartitionKeyCollection(), allow_cookie_callback,
+ std::move(done_callback)));
+}
+
+void SaveCookies(const CefBrowserContext::Getter& browser_context_getter,
+ const network::ResourceRequest& request,
+ net::HttpResponseHeaders* headers,
+ const AllowCookieCallback& allow_cookie_callback,
+ DoneCookieCallback done_callback) {
+ CEF_REQUIRE_IOT();
+
+ if (request.credentials_mode == network::mojom::CredentialsMode::kOmit ||
+ request.url.IsAboutBlank() || !headers ||
+ !headers->HasHeader(net_service::kHTTPSetCookieHeaderName)) {
+ // Continue immediately without saving cookies.
+ std::move(done_callback).Run(0, {});
+ return;
+ }
+
+ // Match the logic in
+ // URLRequestHttpJob::SaveCookiesAndNotifyHeadersComplete.
+ base::Time response_date;
+ if (!headers->GetDateValue(&response_date)) {
+ response_date = base::Time();
+ }
+
+ const base::StringPiece name(net_service::kHTTPSetCookieHeaderName);
+ std::string cookie_string;
+ size_t iter = 0;
+ net::CookieList allowed_cookies;
+ int total_count = 0;
+
+ while (headers->EnumerateHeader(&iter, name, &cookie_string)) {
+ total_count++;
+
+ net::CookieInclusionStatus returned_status;
+ std::unique_ptr<net::CanonicalCookie> cookie = net::CanonicalCookie::Create(
+ request.url, cookie_string, base::Time::Now(),
+ absl::make_optional(response_date), /*partition_key=*/absl::nullopt,
+ &returned_status);
+ if (!returned_status.IsInclude()) {
+ continue;
+ }
+
+ bool allow = false;
+ allow_cookie_callback.Run(*cookie, &allow);
+ if (allow) {
+ allowed_cookies.push_back(*cookie);
+ }
+ }
+
+ if (!allowed_cookies.empty()) {
+ CEF_POST_TASK(
+ CEF_UIT,
+ base::BindOnce(
+ SaveCookiesOnUIThread, browser_context_getter, request.url,
+ GetCookieOptions(request, /*for_loading_cookies=*/false),
+ total_count, std::move(allowed_cookies), std::move(done_callback)));
+
+ } else {
+ std::move(done_callback).Run(total_count, std::move(allowed_cookies));
+ }
+}
+
+} // namespace cookie_helper
+} // namespace net_service \ No newline at end of file
diff --git a/libcef/browser/net_service/cookie_helper.h b/libcef/browser/net_service/cookie_helper.h
new file mode 100644
index 00000000..c975fd1f
--- /dev/null
+++ b/libcef/browser/net_service/cookie_helper.h
@@ -0,0 +1,65 @@
+// Copyright (c) 2019 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_NET_SERVICE_COOKIE_HELPER_H_
+#define CEF_LIBCEF_BROWSER_NET_SERVICE_COOKIE_HELPER_H_
+
+#include "libcef/browser/browser_context.h"
+
+#include "base/functional/callback_forward.h"
+#include "net/cookies/canonical_cookie.h"
+
+namespace net {
+class HttpResponseHeaders;
+}
+
+namespace network {
+struct ResourceRequest;
+} // namespace network
+
+namespace net_service {
+namespace cookie_helper {
+
+// Returns true if the scheme for |url| supports cookies. |cookieable_schemes|
+// is the optional list of schemes that the client has explicitly registered as
+// cookieable, which may intentionally exclude standard schemes.
+bool IsCookieableScheme(
+ const GURL& url,
+ const absl::optional<std::vector<std::string>>& cookieable_schemes);
+
+using AllowCookieCallback =
+ base::RepeatingCallback<void(const net::CanonicalCookie&,
+ bool* /* allow */)>;
+using DoneCookieCallback =
+ base::OnceCallback<void(int /* total_count */,
+ net::CookieList /* allowed_cookies */)>;
+
+// Load cookies for |request|. |allow_cookie_callback| will be executed for each
+// cookie and should return true to allow it. |done_callback| will be executed
+// on completion with |total_count| representing the total number of cookies
+// retrieved, and |allowed_cookies| representing the list of cookies that were
+// both retrieved and allowed by |allow_cookie_callback|. The loaded cookies
+// will not be set on |request|; that should be done in |done_callback|. Must be
+// called on the IO thread.
+void LoadCookies(const CefBrowserContext::Getter& browser_context_getter,
+ const network::ResourceRequest& request,
+ const AllowCookieCallback& allow_cookie_callback,
+ DoneCookieCallback done_callback);
+
+// Save cookies from |head|. |allow_cookie_callback| will be executed for each
+// cookie and should return true to allow it. |done_callback| will be executed
+// on completion with |total_count| representing the total number of cookies
+// retrieved, and |allowed_cookies| representing the list of cookies that were
+// both allowed by |allow_cookie_callback| an successfully saved. Must be called
+// on the IO thread.
+void SaveCookies(const CefBrowserContext::Getter& browser_context_getter,
+ const network::ResourceRequest& request,
+ net::HttpResponseHeaders* headers,
+ const AllowCookieCallback& allow_cookie_callback,
+ DoneCookieCallback done_callback);
+
+} // namespace cookie_helper
+} // namespace net_service
+
+#endif // CEF_LIBCEF_BROWSER_NET_SERVICE_COOKIE_HELPER_H_
diff --git a/libcef/browser/net_service/cookie_manager_impl.cc b/libcef/browser/net_service/cookie_manager_impl.cc
new file mode 100644
index 00000000..ef323825
--- /dev/null
+++ b/libcef/browser/net_service/cookie_manager_impl.cc
@@ -0,0 +1,409 @@
+// Copyright (c) 2019 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#include "libcef/browser/net_service/cookie_manager_impl.h"
+
+#include "libcef/common/net_service/net_service_util.h"
+#include "libcef/common/time_util.h"
+
+#include "base/functional/bind.h"
+#include "base/logging.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/storage_partition.h"
+#include "services/network/public/mojom/cookie_manager.mojom.h"
+#include "url/gurl.h"
+
+using network::mojom::CookieManager;
+
+namespace {
+
+// Do not keep a reference to the object returned by this method.
+CefBrowserContext* GetBrowserContext(const CefBrowserContext::Getter& getter) {
+ CEF_REQUIRE_UIT();
+ DCHECK(!getter.is_null());
+
+ // Will return nullptr if the BrowserContext has been shut down.
+ return getter.Run();
+}
+
+// Do not keep a reference to the object returned by this method.
+CookieManager* GetCookieManager(CefBrowserContext* browser_context) {
+ CEF_REQUIRE_UIT();
+ return browser_context->AsBrowserContext()
+ ->GetDefaultStoragePartition()
+ ->GetCookieManagerForBrowserProcess();
+}
+
+// Always execute the callback asynchronously.
+void RunAsyncCompletionOnUIThread(CefRefPtr<CefCompletionCallback> callback) {
+ if (!callback.get()) {
+ return;
+ }
+ CEF_POST_TASK(CEF_UIT, base::BindOnce(&CefCompletionCallback::OnComplete,
+ callback.get()));
+}
+
+// Always execute the callback asynchronously.
+void SetCookieCallbackImpl(CefRefPtr<CefSetCookieCallback> callback,
+ net::CookieAccessResult access_result) {
+ if (!callback.get()) {
+ return;
+ }
+ const bool is_include = access_result.status.IsInclude();
+ if (!is_include) {
+ LOG(WARNING) << "SetCookie failed with reason: "
+ << access_result.status.GetDebugString();
+ }
+ CEF_POST_TASK(CEF_UIT, base::BindOnce(&CefSetCookieCallback::OnComplete,
+ callback.get(), is_include));
+}
+
+// Always execute the callback asynchronously.
+void DeleteCookiesCallbackImpl(CefRefPtr<CefDeleteCookiesCallback> callback,
+ uint32_t num_deleted) {
+ if (!callback.get()) {
+ return;
+ }
+ CEF_POST_TASK(CEF_UIT, base::BindOnce(&CefDeleteCookiesCallback::OnComplete,
+ callback.get(), num_deleted));
+}
+
+void ExecuteVisitor(CefRefPtr<CefCookieVisitor> visitor,
+ const CefBrowserContext::Getter& browser_context_getter,
+ const std::vector<net::CanonicalCookie>& cookies) {
+ CEF_REQUIRE_UIT();
+
+ auto browser_context = GetBrowserContext(browser_context_getter);
+ if (!browser_context) {
+ return;
+ }
+
+ auto cookie_manager = GetCookieManager(browser_context);
+
+ int total = cookies.size(), count = 0;
+ for (const auto& cc : cookies) {
+ CefCookie cookie;
+ net_service::MakeCefCookie(cc, cookie);
+
+ bool deleteCookie = false;
+ bool keepLooping = visitor->Visit(cookie, count, total, deleteCookie);
+ if (deleteCookie) {
+ cookie_manager->DeleteCanonicalCookie(
+ cc, CookieManager::DeleteCanonicalCookieCallback());
+ }
+ if (!keepLooping) {
+ break;
+ }
+ count++;
+ }
+}
+
+// Always execute the callback asynchronously.
+void GetAllCookiesCallbackImpl(
+ CefRefPtr<CefCookieVisitor> visitor,
+ const CefBrowserContext::Getter& browser_context_getter,
+ const net::CookieList& cookies) {
+ CEF_POST_TASK(CEF_UIT, base::BindOnce(&ExecuteVisitor, visitor,
+ browser_context_getter, cookies));
+}
+
+void GetCookiesCallbackImpl(
+ CefRefPtr<CefCookieVisitor> visitor,
+ const CefBrowserContext::Getter& browser_context_getter,
+ const net::CookieAccessResultList& include_cookies,
+ const net::CookieAccessResultList&) {
+ net::CookieList cookies;
+ for (const auto& status : include_cookies) {
+ cookies.push_back(status.cookie);
+ }
+ GetAllCookiesCallbackImpl(visitor, browser_context_getter, cookies);
+}
+
+} // namespace
+
+CefCookieManagerImpl::CefCookieManagerImpl() {}
+
+void CefCookieManagerImpl::Initialize(
+ CefBrowserContext::Getter browser_context_getter,
+ CefRefPtr<CefCompletionCallback> callback) {
+ CEF_REQUIRE_UIT();
+ DCHECK(!initialized_);
+ DCHECK(!browser_context_getter.is_null());
+ DCHECK(browser_context_getter_.is_null());
+ browser_context_getter_ = browser_context_getter;
+
+ initialized_ = true;
+ if (!init_callbacks_.empty()) {
+ for (auto& init_callback : init_callbacks_) {
+ std::move(init_callback).Run();
+ }
+ init_callbacks_.clear();
+ }
+
+ RunAsyncCompletionOnUIThread(callback);
+}
+
+bool CefCookieManagerImpl::VisitAllCookies(
+ CefRefPtr<CefCookieVisitor> visitor) {
+ if (!visitor.get()) {
+ return false;
+ }
+
+ if (!ValidContext()) {
+ StoreOrTriggerInitCallback(base::BindOnce(
+ base::IgnoreResult(&CefCookieManagerImpl::VisitAllCookiesInternal),
+ this, visitor));
+ return true;
+ }
+
+ return VisitAllCookiesInternal(visitor);
+}
+
+bool CefCookieManagerImpl::VisitUrlCookies(
+ const CefString& url,
+ bool includeHttpOnly,
+ CefRefPtr<CefCookieVisitor> visitor) {
+ if (!visitor.get()) {
+ return false;
+ }
+
+ GURL gurl = GURL(url.ToString());
+ if (!gurl.is_valid()) {
+ return false;
+ }
+
+ if (!ValidContext()) {
+ StoreOrTriggerInitCallback(base::BindOnce(
+ base::IgnoreResult(&CefCookieManagerImpl::VisitUrlCookiesInternal),
+ this, gurl, includeHttpOnly, visitor));
+ return true;
+ }
+
+ return VisitUrlCookiesInternal(gurl, includeHttpOnly, visitor);
+}
+
+bool CefCookieManagerImpl::SetCookie(const CefString& url,
+ const CefCookie& cookie,
+ CefRefPtr<CefSetCookieCallback> callback) {
+ GURL gurl = GURL(url.ToString());
+ if (!gurl.is_valid()) {
+ return false;
+ }
+
+ if (!ValidContext()) {
+ StoreOrTriggerInitCallback(base::BindOnce(
+ base::IgnoreResult(&CefCookieManagerImpl::SetCookieInternal), this,
+ gurl, cookie, callback));
+ return true;
+ }
+
+ return SetCookieInternal(gurl, cookie, callback);
+}
+
+bool CefCookieManagerImpl::DeleteCookies(
+ const CefString& url,
+ const CefString& cookie_name,
+ CefRefPtr<CefDeleteCookiesCallback> callback) {
+ // Empty URLs are allowed but not invalid URLs.
+ GURL gurl = GURL(url.ToString());
+ if (!gurl.is_empty() && !gurl.is_valid()) {
+ return false;
+ }
+
+ if (!ValidContext()) {
+ StoreOrTriggerInitCallback(base::BindOnce(
+ base::IgnoreResult(&CefCookieManagerImpl::DeleteCookiesInternal), this,
+ gurl, cookie_name, callback));
+ return true;
+ }
+
+ return DeleteCookiesInternal(gurl, cookie_name, callback);
+}
+
+bool CefCookieManagerImpl::FlushStore(
+ CefRefPtr<CefCompletionCallback> callback) {
+ if (!ValidContext()) {
+ StoreOrTriggerInitCallback(base::BindOnce(
+ base::IgnoreResult(&CefCookieManagerImpl::FlushStoreInternal), this,
+ callback));
+ return true;
+ }
+
+ return FlushStoreInternal(callback);
+}
+
+bool CefCookieManagerImpl::VisitAllCookiesInternal(
+ CefRefPtr<CefCookieVisitor> visitor) {
+ DCHECK(ValidContext());
+ DCHECK(visitor);
+
+ auto browser_context = GetBrowserContext(browser_context_getter_);
+ if (!browser_context) {
+ return false;
+ }
+
+ GetCookieManager(browser_context)
+ ->GetAllCookies(base::BindOnce(&GetAllCookiesCallbackImpl, visitor,
+ browser_context_getter_));
+ return true;
+}
+
+bool CefCookieManagerImpl::VisitUrlCookiesInternal(
+ const GURL& url,
+ bool includeHttpOnly,
+ CefRefPtr<CefCookieVisitor> visitor) {
+ DCHECK(ValidContext());
+ DCHECK(visitor);
+ DCHECK(url.is_valid());
+
+ net::CookieOptions options;
+ if (includeHttpOnly) {
+ options.set_include_httponly();
+ }
+ options.set_same_site_cookie_context(
+ net::CookieOptions::SameSiteCookieContext::MakeInclusive());
+
+ auto browser_context = GetBrowserContext(browser_context_getter_);
+ if (!browser_context) {
+ return false;
+ }
+
+ GetCookieManager(browser_context)
+ ->GetCookieList(url, options, net::CookiePartitionKeyCollection(),
+ base::BindOnce(&GetCookiesCallbackImpl, visitor,
+ browser_context_getter_));
+ return true;
+}
+
+bool CefCookieManagerImpl::SetCookieInternal(
+ const GURL& url,
+ const CefCookie& cookie,
+ CefRefPtr<CefSetCookieCallback> callback) {
+ DCHECK(ValidContext());
+ DCHECK(url.is_valid());
+
+ std::string name = CefString(&cookie.name).ToString();
+ std::string value = CefString(&cookie.value).ToString();
+ std::string domain = CefString(&cookie.domain).ToString();
+ std::string path = CefString(&cookie.path).ToString();
+
+ base::Time expiration_time;
+ if (cookie.has_expires) {
+ expiration_time = CefBaseTime(cookie.expires);
+ }
+
+ net::CookieSameSite same_site =
+ net_service::MakeCookieSameSite(cookie.same_site);
+ net::CookiePriority priority =
+ net_service::MakeCookiePriority(cookie.priority);
+
+ auto canonical_cookie = net::CanonicalCookie::CreateSanitizedCookie(
+ url, name, value, domain, path,
+ base::Time(), // Creation time.
+ expiration_time,
+ base::Time(), // Last access time.
+ cookie.secure ? true : false, cookie.httponly ? true : false, same_site,
+ priority, /*same_party=*/false, /*partition_key=*/absl::nullopt);
+
+ if (!canonical_cookie) {
+ SetCookieCallbackImpl(
+ callback, net::CookieAccessResult(net::CookieInclusionStatus(
+ net::CookieInclusionStatus::EXCLUDE_UNKNOWN_ERROR)));
+ return true;
+ }
+
+ net::CookieOptions options;
+ if (cookie.httponly) {
+ options.set_include_httponly();
+ }
+ options.set_same_site_cookie_context(
+ net::CookieOptions::SameSiteCookieContext::MakeInclusive());
+
+ auto browser_context = GetBrowserContext(browser_context_getter_);
+ if (!browser_context) {
+ return false;
+ }
+
+ GetCookieManager(browser_context)
+ ->SetCanonicalCookie(*canonical_cookie, url, options,
+ base::BindOnce(SetCookieCallbackImpl, callback));
+ return true;
+}
+
+bool CefCookieManagerImpl::DeleteCookiesInternal(
+ const GURL& url,
+ const CefString& cookie_name,
+ CefRefPtr<CefDeleteCookiesCallback> callback) {
+ DCHECK(ValidContext());
+ DCHECK(url.is_empty() || url.is_valid());
+
+ network::mojom::CookieDeletionFilterPtr deletion_filter =
+ network::mojom::CookieDeletionFilter::New();
+
+ if (url.is_empty()) {
+ // Delete all cookies.
+ } else if (cookie_name.empty()) {
+ // Delete all matching host cookies.
+ deletion_filter->host_name = url.host();
+ } else {
+ // Delete all matching host and domain cookies.
+ deletion_filter->url = url;
+ deletion_filter->cookie_name = cookie_name;
+ }
+
+ auto browser_context = GetBrowserContext(browser_context_getter_);
+ if (!browser_context) {
+ return false;
+ }
+
+ GetCookieManager(browser_context)
+ ->DeleteCookies(std::move(deletion_filter),
+ base::BindOnce(DeleteCookiesCallbackImpl, callback));
+ return true;
+}
+
+bool CefCookieManagerImpl::FlushStoreInternal(
+ CefRefPtr<CefCompletionCallback> callback) {
+ DCHECK(ValidContext());
+
+ auto browser_context = GetBrowserContext(browser_context_getter_);
+ if (!browser_context) {
+ return false;
+ }
+
+ GetCookieManager(browser_context)
+ ->FlushCookieStore(
+ base::BindOnce(RunAsyncCompletionOnUIThread, callback));
+ return true;
+}
+
+void CefCookieManagerImpl::StoreOrTriggerInitCallback(
+ base::OnceClosure callback) {
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(
+ CEF_UIT,
+ base::BindOnce(&CefCookieManagerImpl::StoreOrTriggerInitCallback, this,
+ std::move(callback)));
+ return;
+ }
+
+ if (initialized_) {
+ std::move(callback).Run();
+ } else {
+ init_callbacks_.emplace_back(std::move(callback));
+ }
+}
+
+bool CefCookieManagerImpl::ValidContext() const {
+ return CEF_CURRENTLY_ON_UIT() && initialized_;
+}
+
+// CefCookieManager methods ----------------------------------------------------
+
+// static
+CefRefPtr<CefCookieManager> CefCookieManager::GetGlobalManager(
+ CefRefPtr<CefCompletionCallback> callback) {
+ CefRefPtr<CefRequestContext> context = CefRequestContext::GetGlobalContext();
+ return context ? context->GetCookieManager(callback) : nullptr;
+}
diff --git a/libcef/browser/net_service/cookie_manager_impl.h b/libcef/browser/net_service/cookie_manager_impl.h
new file mode 100644
index 00000000..9ae1b9cb
--- /dev/null
+++ b/libcef/browser/net_service/cookie_manager_impl.h
@@ -0,0 +1,69 @@
+// Copyright (c) 2019 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_NET_SERVICE_COOKIE_MANAGER_IMPL_H_
+#define CEF_LIBCEF_BROWSER_NET_SERVICE_COOKIE_MANAGER_IMPL_H_
+
+#include "include/cef_cookie.h"
+#include "libcef/browser/browser_context.h"
+#include "libcef/browser/thread_util.h"
+
+#include "base/files/file_path.h"
+
+// Implementation of the CefCookieManager interface. May be created on any
+// thread.
+class CefCookieManagerImpl : public CefCookieManager {
+ public:
+ CefCookieManagerImpl();
+
+ CefCookieManagerImpl(const CefCookieManagerImpl&) = delete;
+ CefCookieManagerImpl& operator=(const CefCookieManagerImpl&) = delete;
+
+ // Called on the UI thread after object creation and before any other object
+ // methods are executed on the UI thread.
+ void Initialize(CefBrowserContext::Getter browser_context_getter,
+ CefRefPtr<CefCompletionCallback> callback);
+
+ // CefCookieManager methods.
+ bool VisitAllCookies(CefRefPtr<CefCookieVisitor> visitor) override;
+ bool VisitUrlCookies(const CefString& url,
+ bool includeHttpOnly,
+ CefRefPtr<CefCookieVisitor> visitor) override;
+ bool SetCookie(const CefString& url,
+ const CefCookie& cookie,
+ CefRefPtr<CefSetCookieCallback> callback) override;
+ bool DeleteCookies(const CefString& url,
+ const CefString& cookie_name,
+ CefRefPtr<CefDeleteCookiesCallback> callback) override;
+ bool FlushStore(CefRefPtr<CefCompletionCallback> callback) override;
+
+ private:
+ bool VisitAllCookiesInternal(CefRefPtr<CefCookieVisitor> visitor);
+ bool VisitUrlCookiesInternal(const GURL& url,
+ bool includeHttpOnly,
+ CefRefPtr<CefCookieVisitor> visitor);
+ bool SetCookieInternal(const GURL& url,
+ const CefCookie& cookie,
+ CefRefPtr<CefSetCookieCallback> callback);
+ bool DeleteCookiesInternal(const GURL& url,
+ const CefString& cookie_name,
+ CefRefPtr<CefDeleteCookiesCallback> callback);
+ bool FlushStoreInternal(CefRefPtr<CefCompletionCallback> callback);
+
+ // If the context is fully initialized execute |callback|, otherwise
+ // store it until the context is fully initialized.
+ void StoreOrTriggerInitCallback(base::OnceClosure callback);
+
+ bool ValidContext() const;
+
+ // Only accessed on the UI thread. Will be non-null after Initialize().
+ CefBrowserContext::Getter browser_context_getter_;
+
+ bool initialized_ = false;
+ std::vector<base::OnceClosure> init_callbacks_;
+
+ IMPLEMENT_REFCOUNTING(CefCookieManagerImpl);
+};
+
+#endif // CEF_LIBCEF_BROWSER_NET_SERVICE_COOKIE_MANAGER_IMPL_H_
diff --git a/libcef/browser/net_service/login_delegate.cc b/libcef/browser/net_service/login_delegate.cc
new file mode 100644
index 00000000..da16c321
--- /dev/null
+++ b/libcef/browser/net_service/login_delegate.cc
@@ -0,0 +1,174 @@
+// Copyright (c) 2019 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#include "libcef/browser/net_service/login_delegate.h"
+
+#include "libcef/browser/browser_host_base.h"
+#include "libcef/browser/net_service/browser_urlrequest_impl.h"
+#include "libcef/browser/thread_util.h"
+
+#include "base/memory/scoped_refptr.h"
+#include "base/task/sequenced_task_runner.h"
+#include "content/public/browser/global_request_id.h"
+#include "content/public/browser/web_contents.h"
+
+namespace net_service {
+
+namespace {
+
+class AuthCallbackImpl : public CefAuthCallback {
+ public:
+ explicit AuthCallbackImpl(base::WeakPtr<LoginDelegate> delegate)
+ : delegate_(delegate),
+ task_runner_(base::SequencedTaskRunner::GetCurrentDefault()) {}
+
+ AuthCallbackImpl(const AuthCallbackImpl&) = delete;
+ AuthCallbackImpl& operator=(const AuthCallbackImpl&) = delete;
+
+ ~AuthCallbackImpl() override {
+ if (delegate_.MaybeValid()) {
+ // If |delegate_| isn't valid this will be a no-op.
+ task_runner_->PostTask(FROM_HERE,
+ base::BindOnce(&LoginDelegate::Cancel, delegate_));
+ }
+ }
+
+ void Continue(const CefString& username, const CefString& password) override {
+ if (!task_runner_->RunsTasksInCurrentSequence()) {
+ task_runner_->PostTask(
+ FROM_HERE, base::BindOnce(&AuthCallbackImpl::Continue, this, username,
+ password));
+ return;
+ }
+
+ if (delegate_) {
+ delegate_->Continue(username, password);
+ delegate_ = nullptr;
+ }
+ }
+
+ void Cancel() override {
+ if (!task_runner_->RunsTasksInCurrentSequence()) {
+ task_runner_->PostTask(FROM_HERE,
+ base::BindOnce(&AuthCallbackImpl::Cancel, this));
+ return;
+ }
+
+ if (delegate_) {
+ delegate_->Cancel();
+ delegate_ = nullptr;
+ }
+ }
+
+ private:
+ base::WeakPtr<LoginDelegate> delegate_;
+ scoped_refptr<base::SequencedTaskRunner> task_runner_;
+
+ IMPLEMENT_REFCOUNTING(AuthCallbackImpl);
+};
+
+void RunCallbackOnIOThread(
+ CefRefPtr<CefBrowserHostBase> browser,
+ absl::optional<CefBrowserURLRequest::RequestInfo> url_request_info,
+ const net::AuthChallengeInfo& auth_info,
+ const GURL& origin_url,
+ CefRefPtr<AuthCallbackImpl> callback_impl) {
+ CEF_REQUIRE_IOT();
+
+ // TODO(network): After the old network code path is deleted move this
+ // callback to the BrowserURLRequest's context thread.
+ if (url_request_info) {
+ bool handled = url_request_info->second->GetAuthCredentials(
+ auth_info.is_proxy, auth_info.challenger.host(),
+ auth_info.challenger.port(), auth_info.realm, auth_info.scheme,
+ callback_impl.get());
+ if (handled) {
+ // The user will execute the callback, or the request will be canceled on
+ // AuthCallbackImpl destruction.
+ return;
+ }
+ }
+
+ if (browser) {
+ CefRefPtr<CefClient> client = browser->GetClient();
+ if (client) {
+ CefRefPtr<CefRequestHandler> handler = client->GetRequestHandler();
+ if (handler) {
+ bool handled = handler->GetAuthCredentials(
+ browser.get(), origin_url.spec(), auth_info.is_proxy,
+ auth_info.challenger.host(), auth_info.challenger.port(),
+ auth_info.realm, auth_info.scheme, callback_impl.get());
+ if (handled) {
+ // The user will execute the callback, or the request will be canceled
+ // on AuthCallbackImpl destruction.
+ return;
+ }
+ }
+ }
+ }
+
+ callback_impl->Cancel();
+}
+} // namespace
+
+LoginDelegate::LoginDelegate(const net::AuthChallengeInfo& auth_info,
+ content::WebContents* web_contents,
+ const content::GlobalRequestID& request_id,
+ const GURL& origin_url,
+ LoginAuthRequiredCallback callback)
+ : callback_(std::move(callback)), weak_ptr_factory_(this) {
+ CEF_REQUIRE_UIT();
+
+ // May be nullptr for requests originating from CefURLRequest.
+ CefRefPtr<CefBrowserHostBase> browser;
+ if (web_contents) {
+ browser = CefBrowserHostBase::GetBrowserForContents(web_contents);
+ }
+
+ // |callback| needs to be executed asynchronously.
+ CEF_POST_TASK(CEF_UIT, base::BindOnce(&LoginDelegate::Start,
+ weak_ptr_factory_.GetWeakPtr(), browser,
+ auth_info, request_id, origin_url));
+}
+
+void LoginDelegate::Continue(const CefString& username,
+ const CefString& password) {
+ CEF_REQUIRE_UIT();
+ if (!callback_.is_null()) {
+ std::move(callback_).Run(
+ net::AuthCredentials(username.ToString16(), password.ToString16()));
+ }
+}
+
+void LoginDelegate::Cancel() {
+ CEF_REQUIRE_UIT();
+ if (!callback_.is_null()) {
+ std::move(callback_).Run(absl::nullopt);
+ }
+}
+
+void LoginDelegate::Start(CefRefPtr<CefBrowserHostBase> browser,
+ const net::AuthChallengeInfo& auth_info,
+ const content::GlobalRequestID& request_id,
+ const GURL& origin_url) {
+ CEF_REQUIRE_UIT();
+
+ auto url_request_info = CefBrowserURLRequest::FromRequestID(request_id);
+
+ if (browser || url_request_info) {
+ // AuthCallbackImpl is bound to the current thread.
+ CefRefPtr<AuthCallbackImpl> callbackImpl =
+ new AuthCallbackImpl(weak_ptr_factory_.GetWeakPtr());
+
+ // Execute callbacks on the IO thread to maintain the "old"
+ // network_delegate callback behaviour.
+ CEF_POST_TASK(CEF_IOT, base::BindOnce(&RunCallbackOnIOThread, browser,
+ url_request_info, auth_info,
+ origin_url, callbackImpl));
+ } else {
+ Cancel();
+ }
+}
+
+} // namespace net_service \ No newline at end of file
diff --git a/libcef/browser/net_service/login_delegate.h b/libcef/browser/net_service/login_delegate.h
new file mode 100644
index 00000000..8732ea7b
--- /dev/null
+++ b/libcef/browser/net_service/login_delegate.h
@@ -0,0 +1,50 @@
+// Copyright (c) 2019 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_NET_SERVICE_LOGIN_DELEGATE_H_
+#define CEF_LIBCEF_BROWSER_NET_SERVICE_LOGIN_DELEGATE_H_
+
+#include "include/cef_base.h"
+
+#include "base/memory/weak_ptr.h"
+#include "content/public/browser/content_browser_client.h"
+#include "content/public/browser/login_delegate.h"
+#include "net/base/auth.h"
+
+namespace content {
+struct GlobalRequestID;
+class WebContents;
+} // namespace content
+
+class CefBrowserHostBase;
+class GURL;
+
+namespace net_service {
+
+class LoginDelegate : public content::LoginDelegate {
+ public:
+ // This object will be deleted when |callback| is executed or the request is
+ // canceled. |callback| should not be executed after this object is deleted.
+ LoginDelegate(const net::AuthChallengeInfo& auth_info,
+ content::WebContents* web_contents,
+ const content::GlobalRequestID& request_id,
+ const GURL& origin_url,
+ LoginAuthRequiredCallback callback);
+
+ void Continue(const CefString& username, const CefString& password);
+ void Cancel();
+
+ private:
+ void Start(CefRefPtr<CefBrowserHostBase> browser,
+ const net::AuthChallengeInfo& auth_info,
+ const content::GlobalRequestID& request_id,
+ const GURL& origin_url);
+
+ LoginAuthRequiredCallback callback_;
+ base::WeakPtrFactory<LoginDelegate> weak_ptr_factory_;
+};
+
+} // namespace net_service
+
+#endif // CEF_LIBCEF_BROWSER_NET_SERVICE_LOGIN_DELEGATE_H_
diff --git a/libcef/browser/net_service/proxy_url_loader_factory.cc b/libcef/browser/net_service/proxy_url_loader_factory.cc
new file mode 100644
index 00000000..96fcc392
--- /dev/null
+++ b/libcef/browser/net_service/proxy_url_loader_factory.cc
@@ -0,0 +1,1439 @@
+// Copyright (c) 2019 The Chromium Embedded Framework Authors. Portions
+// Copyright (c) 2018 The Chromium Authors. All rights reserved. Use of this
+// source code is governed by a BSD-style license that can be found in the
+// LICENSE file.
+
+#include "libcef/browser/net_service/proxy_url_loader_factory.h"
+
+#include <tuple>
+
+#include "libcef/browser/context.h"
+#include "libcef/browser/origin_whitelist_impl.h"
+#include "libcef/browser/thread_util.h"
+#include "libcef/common/cef_switches.h"
+#include "libcef/common/net/scheme_registration.h"
+#include "libcef/common/net_service/net_service_util.h"
+
+#include "base/barrier_closure.h"
+#include "base/command_line.h"
+#include "base/strings/string_number_conversions.h"
+#include "components/safe_browsing/core/common/safebrowsing_constants.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/resource_context.h"
+#include "content/public/browser/web_contents.h"
+#include "mojo/public/cpp/base/big_buffer.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "net/http/http_status_code.h"
+#include "net/url_request/redirect_util.h"
+#include "net/url_request/url_request.h"
+#include "services/network/public/cpp/cors/cors.h"
+#include "services/network/public/cpp/features.h"
+#include "services/network/public/mojom/early_hints.mojom.h"
+
+namespace net_service {
+
+namespace {
+
+// User data key for ResourceContextData.
+const void* const kResourceContextUserDataKey = &kResourceContextUserDataKey;
+
+absl::optional<std::string> GetHeaderString(
+ const net::HttpResponseHeaders* headers,
+ const std::string& header_name) {
+ std::string header_value;
+ if (!headers || !headers->GetNormalizedHeader(header_name, &header_value)) {
+ return absl::nullopt;
+ }
+ return header_value;
+}
+
+void CreateProxyHelper(
+ content::WebContents::Getter web_contents_getter,
+ mojo::PendingReceiver<network::mojom::URLLoaderFactory> loader_receiver,
+ std::unique_ptr<InterceptedRequestHandler> request_handler) {
+ ProxyURLLoaderFactory::CreateProxy(web_contents_getter,
+ std::move(loader_receiver),
+ std::move(request_handler));
+}
+
+bool DisableRequestHandlingForTesting() {
+ static bool disabled([]() -> bool {
+ return base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableRequestHandlingForTesting);
+ }());
+ return disabled;
+}
+
+} // namespace
+
+// Owns all of the ProxyURLLoaderFactorys for a given BrowserContext. Since
+// these live on the IO thread this is done indirectly through the
+// ResourceContext.
+class ResourceContextData : public base::SupportsUserData::Data {
+ public:
+ ResourceContextData(const ResourceContextData&) = delete;
+ ResourceContextData& operator=(const ResourceContextData&) = delete;
+
+ ~ResourceContextData() override {}
+
+ static void AddProxyOnUIThread(
+ ProxyURLLoaderFactory* proxy,
+ content::WebContents::Getter web_contents_getter) {
+ CEF_REQUIRE_UIT();
+
+ content::WebContents* web_contents = web_contents_getter.Run();
+
+ // Maybe the browser was destroyed while AddProxyOnUIThread was pending.
+ if (!web_contents) {
+ // Delete on the IO thread as expected by mojo bindings.
+ content::BrowserThread::DeleteSoon(content::BrowserThread::IO, FROM_HERE,
+ proxy);
+ return;
+ }
+
+ content::BrowserContext* browser_context =
+ web_contents->GetBrowserContext();
+ DCHECK(browser_context);
+
+ content::ResourceContext* resource_context =
+ browser_context->GetResourceContext();
+ DCHECK(resource_context);
+
+ CEF_POST_TASK(CEF_IOT, base::BindOnce(ResourceContextData::AddProxy,
+ base::Unretained(proxy),
+ base::Unretained(resource_context)));
+ }
+
+ static void AddProxy(ProxyURLLoaderFactory* proxy,
+ content::ResourceContext* resource_context) {
+ CEF_REQUIRE_IOT();
+
+ // Maybe the proxy was destroyed while AddProxyOnUIThread was pending.
+ if (proxy->destroyed_) {
+ delete proxy;
+ return;
+ }
+
+ auto* self = static_cast<ResourceContextData*>(
+ resource_context->GetUserData(kResourceContextUserDataKey));
+ if (!self) {
+ self = new ResourceContextData();
+ resource_context->SetUserData(kResourceContextUserDataKey,
+ base::WrapUnique(self));
+ }
+
+ proxy->SetDisconnectCallback(base::BindOnce(
+ &ResourceContextData::RemoveProxy, self->weak_factory_.GetWeakPtr()));
+ self->proxies_.emplace(base::WrapUnique(proxy));
+ }
+
+ private:
+ void RemoveProxy(ProxyURLLoaderFactory* proxy) {
+ CEF_REQUIRE_IOT();
+
+ auto it = proxies_.find(proxy);
+ DCHECK(it != proxies_.end());
+ proxies_.erase(it);
+ }
+
+ ResourceContextData() : weak_factory_(this) {}
+
+ std::set<std::unique_ptr<ProxyURLLoaderFactory>, base::UniquePtrComparator>
+ proxies_;
+
+ base::WeakPtrFactory<ResourceContextData> weak_factory_;
+};
+
+// CORS preflight requests are handled in the network process, so we just need
+// to continue all of the callbacks and then delete ourself.
+class CorsPreflightRequest : public network::mojom::TrustedHeaderClient {
+ public:
+ explicit CorsPreflightRequest(
+ mojo::PendingReceiver<network::mojom::TrustedHeaderClient> receiver)
+ : weak_factory_(this) {
+ header_client_receiver_.Bind(std::move(receiver));
+
+ header_client_receiver_.set_disconnect_handler(base::BindOnce(
+ &CorsPreflightRequest::OnDestroy, weak_factory_.GetWeakPtr()));
+ }
+
+ CorsPreflightRequest(const CorsPreflightRequest&) = delete;
+ CorsPreflightRequest& operator=(const CorsPreflightRequest&) = delete;
+
+ // mojom::TrustedHeaderClient methods:
+ void OnBeforeSendHeaders(const net::HttpRequestHeaders& headers,
+ OnBeforeSendHeadersCallback callback) override {
+ std::move(callback).Run(net::OK, headers);
+ }
+
+ void OnHeadersReceived(const std::string& headers,
+ const net::IPEndPoint& remote_endpoint,
+ OnHeadersReceivedCallback callback) override {
+ std::move(callback).Run(net::OK, headers, /*redirect_url=*/GURL());
+ OnDestroy();
+ }
+
+ private:
+ void OnDestroy() { delete this; }
+
+ mojo::Receiver<network::mojom::TrustedHeaderClient> header_client_receiver_{
+ this};
+
+ base::WeakPtrFactory<CorsPreflightRequest> weak_factory_;
+};
+
+//==============================
+// InterceptedRequest
+//=============================
+
+// Handles intercepted, in-progress requests/responses, so that they can be
+// controlled and modified accordingly.
+class InterceptedRequest : public network::mojom::URLLoader,
+ public network::mojom::URLLoaderClient,
+ public network::mojom::TrustedHeaderClient {
+ public:
+ InterceptedRequest(
+ ProxyURLLoaderFactory* factory,
+ int32_t id,
+ uint32_t options,
+ const network::ResourceRequest& request,
+ const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
+ mojo::PendingReceiver<network::mojom::URLLoader> loader_receiver,
+ mojo::PendingRemote<network::mojom::URLLoaderClient> client,
+ mojo::PendingRemote<network::mojom::URLLoaderFactory> target_factory);
+
+ InterceptedRequest(const InterceptedRequest&) = delete;
+ InterceptedRequest& operator=(const InterceptedRequest&) = delete;
+
+ ~InterceptedRequest() override;
+
+ // Restart the request. This happens on initial start and after redirect.
+ void Restart();
+
+ // Called from ProxyURLLoaderFactory::OnLoaderCreated.
+ void OnLoaderCreated(
+ mojo::PendingReceiver<network::mojom::TrustedHeaderClient> receiver);
+
+ // Called from InterceptDelegate::OnInputStreamOpenFailed.
+ void InputStreamFailed(bool restart_needed);
+
+ // mojom::TrustedHeaderClient methods:
+ void OnBeforeSendHeaders(const net::HttpRequestHeaders& headers,
+ OnBeforeSendHeadersCallback callback) override;
+ void OnHeadersReceived(const std::string& headers,
+ const net::IPEndPoint& remote_endpoint,
+ OnHeadersReceivedCallback callback) override;
+
+ // mojom::URLLoaderClient methods:
+ void OnReceiveEarlyHints(network::mojom::EarlyHintsPtr early_hints) override;
+ void OnReceiveResponse(
+ network::mojom::URLResponseHeadPtr head,
+ mojo::ScopedDataPipeConsumerHandle body,
+ absl::optional<mojo_base::BigBuffer> cached_metadata) override;
+ void OnReceiveRedirect(const net::RedirectInfo& redirect_info,
+ network::mojom::URLResponseHeadPtr head) override;
+ void OnUploadProgress(int64_t current_position,
+ int64_t total_size,
+ OnUploadProgressCallback callback) override;
+ void OnTransferSizeUpdated(int32_t transfer_size_diff) override;
+ void OnComplete(const network::URLLoaderCompletionStatus& status) override;
+
+ // mojom::URLLoader methods:
+ void FollowRedirect(
+ const std::vector<std::string>& removed_headers,
+ const net::HttpRequestHeaders& modified_headers,
+ const net::HttpRequestHeaders& modified_cors_exempt_headers,
+ const absl::optional<GURL>& new_url) override;
+ void SetPriority(net::RequestPriority priority,
+ int32_t intra_priority_value) override;
+ void PauseReadingBodyFromNet() override;
+ void ResumeReadingBodyFromNet() override;
+
+ int32_t id() const { return id_; }
+
+ private:
+ // Helpers for determining the request handler.
+ void BeforeRequestReceived(const GURL& original_url,
+ bool intercept_request,
+ bool intercept_only);
+ void InterceptResponseReceived(const GURL& original_url,
+ std::unique_ptr<ResourceResponse> response);
+ void ContinueAfterIntercept();
+ void ContinueAfterInterceptWithOverride(
+ std::unique_ptr<ResourceResponse> response);
+
+ // Helpers for optionally overriding headers.
+ void HandleResponseOrRedirectHeaders(
+ absl::optional<net::RedirectInfo> redirect_info,
+ net::CompletionOnceCallback continuation);
+ void ContinueResponseOrRedirect(
+ net::CompletionOnceCallback continuation,
+ InterceptedRequestHandler::ResponseMode response_mode,
+ scoped_refptr<net::HttpResponseHeaders> override_headers,
+ const GURL& redirect_url);
+ void ContinueToHandleOverrideHeaders(int error_code);
+ net::RedirectInfo MakeRedirectResponseAndInfo(const GURL& new_location);
+
+ // Helpers for redirect handling.
+ void ContinueToBeforeRedirect(const net::RedirectInfo& redirect_info,
+ int error_code);
+
+ // Helpers for response handling.
+ void ContinueToResponseStarted(int error_code);
+
+ void OnDestroy();
+
+ void OnProcessRequestHeaders(const GURL& redirect_url,
+ net::HttpRequestHeaders* modified_headers,
+ std::vector<std::string>* removed_headers);
+
+ // This is called when the original URLLoaderClient has a connection error.
+ void OnURLLoaderClientError();
+
+ // This is called when the original URLLoader has a connection error.
+ void OnURLLoaderError(uint32_t custom_reason, const std::string& description);
+
+ // Call OnComplete on |target_client_|. If |wait_for_loader_error| is true
+ // then this object will wait for |proxied_loader_receiver_| to have a
+ // connection error before destructing.
+ void CallOnComplete(const network::URLLoaderCompletionStatus& status,
+ bool wait_for_loader_error);
+
+ void SendErrorAndCompleteImmediately(int error_code);
+ void SendErrorStatusAndCompleteImmediately(
+ const network::URLLoaderCompletionStatus& status);
+
+ void SendErrorCallback(int error_code, bool safebrowsing_hit);
+
+ void OnUploadProgressACK();
+
+ ProxyURLLoaderFactory* const factory_;
+ const int32_t id_;
+ const uint32_t options_;
+ bool input_stream_previously_failed_ = false;
+ bool request_was_redirected_ = false;
+ int redirect_limit_ = net::URLRequest::kMaxRedirects;
+ bool redirect_in_progress_ = false;
+
+ // To avoid sending multiple OnReceivedError callbacks.
+ bool sent_error_callback_ = false;
+
+ // When true, the loader will provide the option to intercept the request.
+ bool intercept_request_ = true;
+
+ // When true, the loader will not proceed unless the intercept request
+ // callback provided a non-null response.
+ bool intercept_only_ = false;
+
+ network::URLLoaderCompletionStatus status_;
+ bool got_loader_error_ = false;
+
+ // Used for rate limiting OnUploadProgress callbacks.
+ bool waiting_for_upload_progress_ack_ = false;
+
+ network::ResourceRequest request_;
+ network::mojom::URLResponseHeadPtr current_response_;
+ mojo::ScopedDataPipeConsumerHandle current_body_;
+ absl::optional<mojo_base::BigBuffer> current_cached_metadata_;
+ scoped_refptr<net::HttpResponseHeaders> current_headers_;
+ scoped_refptr<net::HttpResponseHeaders> override_headers_;
+ GURL original_url_;
+ GURL redirect_url_;
+ GURL header_client_redirect_url_;
+ const net::MutableNetworkTrafficAnnotationTag traffic_annotation_;
+
+ mojo::Receiver<network::mojom::URLLoader> proxied_loader_receiver_;
+ mojo::Remote<network::mojom::URLLoaderClient> target_client_;
+
+ mojo::Receiver<network::mojom::URLLoaderClient> proxied_client_receiver_{
+ this};
+ mojo::Remote<network::mojom::URLLoader> target_loader_;
+ mojo::Remote<network::mojom::URLLoaderFactory> target_factory_;
+
+ bool current_request_uses_header_client_ = false;
+ OnHeadersReceivedCallback on_headers_received_callback_;
+ mojo::Receiver<network::mojom::TrustedHeaderClient> header_client_receiver_{
+ this};
+
+ StreamReaderURLLoader* stream_loader_ = nullptr;
+
+ base::WeakPtrFactory<InterceptedRequest> weak_factory_;
+};
+
+class InterceptDelegate : public StreamReaderURLLoader::Delegate {
+ public:
+ explicit InterceptDelegate(std::unique_ptr<ResourceResponse> response,
+ base::WeakPtr<InterceptedRequest> request)
+ : response_(std::move(response)), request_(request) {}
+
+ bool OpenInputStream(int32_t request_id,
+ const network::ResourceRequest& request,
+ OpenCallback callback) override {
+ return response_->OpenInputStream(request_id, request, std::move(callback));
+ }
+
+ void OnInputStreamOpenFailed(int32_t request_id, bool* restarted) override {
+ request_->InputStreamFailed(false /* restart_needed */);
+ *restarted = false;
+ }
+
+ void GetResponseHeaders(int32_t request_id,
+ int* status_code,
+ std::string* reason_phrase,
+ std::string* mime_type,
+ std::string* charset,
+ int64_t* content_length,
+ HeaderMap* extra_headers) override {
+ response_->GetResponseHeaders(request_id, status_code, reason_phrase,
+ mime_type, charset, content_length,
+ extra_headers);
+ }
+
+ private:
+ std::unique_ptr<ResourceResponse> response_;
+ base::WeakPtr<InterceptedRequest> request_;
+};
+
+InterceptedRequest::InterceptedRequest(
+ ProxyURLLoaderFactory* factory,
+ int32_t id,
+ uint32_t options,
+ const network::ResourceRequest& request,
+ const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
+ mojo::PendingReceiver<network::mojom::URLLoader> loader_receiver,
+ mojo::PendingRemote<network::mojom::URLLoaderClient> client,
+ mojo::PendingRemote<network::mojom::URLLoaderFactory> target_factory)
+ : factory_(factory),
+ id_(id),
+ options_(options),
+ request_(request),
+ traffic_annotation_(traffic_annotation),
+ proxied_loader_receiver_(this, std::move(loader_receiver)),
+ target_client_(std::move(client)),
+ target_factory_(std::move(target_factory)),
+ weak_factory_(this) {
+ status_ = network::URLLoaderCompletionStatus(net::OK);
+
+ net::HttpRequestHeaders modified_headers;
+ std::vector<std::string> removed_headers;
+ OnProcessRequestHeaders(GURL() /* redirect_url */, &modified_headers,
+ &removed_headers);
+
+ // If there is a client error, clean up the request.
+ target_client_.set_disconnect_handler(base::BindOnce(
+ &InterceptedRequest::OnURLLoaderClientError, base::Unretained(this)));
+ proxied_loader_receiver_.set_disconnect_with_reason_handler(base::BindOnce(
+ &InterceptedRequest::OnURLLoaderError, base::Unretained(this)));
+}
+
+InterceptedRequest::~InterceptedRequest() {
+ if (status_.error_code != net::OK) {
+ SendErrorCallback(status_.error_code, false);
+ }
+ if (on_headers_received_callback_) {
+ std::move(on_headers_received_callback_)
+ .Run(net::ERR_ABORTED, absl::nullopt, GURL());
+ }
+}
+
+void InterceptedRequest::Restart() {
+ stream_loader_ = nullptr;
+ if (proxied_client_receiver_.is_bound()) {
+ proxied_client_receiver_.reset();
+ target_loader_.reset();
+ }
+
+ if (header_client_receiver_.is_bound()) {
+ std::ignore = header_client_receiver_.Unbind();
+ }
+
+ current_request_uses_header_client_ =
+ factory_->url_loader_header_client_receiver_.is_bound();
+
+ if (request_.request_initiator &&
+ network::cors::ShouldCheckCors(request_.url, request_.request_initiator,
+ request_.mode)) {
+ if (scheme::IsCorsEnabledScheme(request_.url.scheme())) {
+ // Add the Origin header for CORS-enabled scheme requests.
+ request_.headers.SetHeaderIfMissing(
+ net::HttpRequestHeaders::kOrigin,
+ request_.request_initiator->Serialize());
+ } else if (!HasCrossOriginWhitelistEntry(
+ *request_.request_initiator,
+ url::Origin::Create(request_.url))) {
+ // Fail requests if a CORS check is required and the scheme is not CORS
+ // enabled. This matches the error condition that would be generated by
+ // CorsURLLoader::StartRequest in the network process.
+ SendErrorStatusAndCompleteImmediately(
+ network::URLLoaderCompletionStatus(network::CorsErrorStatus(
+ network::mojom::CorsError::kCorsDisabledScheme)));
+ return;
+ }
+ }
+
+ const GURL original_url = request_.url;
+
+ factory_->request_handler_->OnBeforeRequest(
+ id_, &request_, request_was_redirected_,
+ base::BindOnce(&InterceptedRequest::BeforeRequestReceived,
+ weak_factory_.GetWeakPtr(), original_url),
+ base::BindOnce(&InterceptedRequest::SendErrorAndCompleteImmediately,
+ weak_factory_.GetWeakPtr()));
+}
+
+void InterceptedRequest::OnLoaderCreated(
+ mojo::PendingReceiver<network::mojom::TrustedHeaderClient> receiver) {
+ DCHECK(current_request_uses_header_client_);
+
+ // Only called if we're using the default loader.
+ header_client_receiver_.Bind(std::move(receiver));
+}
+
+void InterceptedRequest::InputStreamFailed(bool restart_needed) {
+ DCHECK(!input_stream_previously_failed_);
+
+ if (intercept_only_) {
+ // This can happen for unsupported schemes, when no proper
+ // response from the intercept handler is received, i.e.
+ // the provided input stream in response failed to load. In
+ // this case we send and error and stop loading.
+ SendErrorAndCompleteImmediately(net::ERR_UNKNOWN_URL_SCHEME);
+ return;
+ }
+
+ if (!restart_needed) {
+ return;
+ }
+
+ input_stream_previously_failed_ = true;
+ Restart();
+}
+
+// TrustedHeaderClient methods.
+
+void InterceptedRequest::OnBeforeSendHeaders(
+ const net::HttpRequestHeaders& headers,
+ OnBeforeSendHeadersCallback callback) {
+ if (!current_request_uses_header_client_) {
+ std::move(callback).Run(net::OK, absl::nullopt);
+ return;
+ }
+
+ request_.headers = headers;
+ std::move(callback).Run(net::OK, absl::nullopt);
+
+ // Resume handling of client messages after continuing from an async callback.
+ if (proxied_client_receiver_.is_bound()) {
+ proxied_client_receiver_.Resume();
+ }
+}
+
+void InterceptedRequest::OnHeadersReceived(
+ const std::string& headers,
+ const net::IPEndPoint& remote_endpoint,
+ OnHeadersReceivedCallback callback) {
+ if (!current_request_uses_header_client_) {
+ std::move(callback).Run(net::OK, absl::nullopt, GURL());
+ return;
+ }
+
+ current_headers_ = base::MakeRefCounted<net::HttpResponseHeaders>(headers);
+ on_headers_received_callback_ = std::move(callback);
+
+ absl::optional<net::RedirectInfo> redirect_info;
+ std::string location;
+ if (current_headers_->IsRedirect(&location)) {
+ const GURL new_url = request_.url.Resolve(location);
+ redirect_info =
+ MakeRedirectInfo(request_, current_headers_.get(), new_url, 0);
+ }
+
+ HandleResponseOrRedirectHeaders(
+ redirect_info,
+ base::BindOnce(&InterceptedRequest::ContinueToHandleOverrideHeaders,
+ weak_factory_.GetWeakPtr()));
+}
+
+// URLLoaderClient methods.
+
+void InterceptedRequest::OnReceiveEarlyHints(
+ network::mojom::EarlyHintsPtr early_hints) {
+ target_client_->OnReceiveEarlyHints(std::move(early_hints));
+}
+
+void InterceptedRequest::OnReceiveResponse(
+ network::mojom::URLResponseHeadPtr head,
+ mojo::ScopedDataPipeConsumerHandle body,
+ absl::optional<mojo_base::BigBuffer> cached_metadata) {
+ current_response_ = std::move(head);
+ current_body_ = std::move(body);
+ current_cached_metadata_ = std::move(cached_metadata);
+
+ // |current_headers_| may be null for cached responses where OnHeadersReceived
+ // is not called.
+ if (current_request_uses_header_client_ && current_headers_) {
+ // Use the headers we got from OnHeadersReceived as that'll contain
+ // Set-Cookie if it existed.
+ current_response_->headers = current_headers_;
+ current_headers_ = nullptr;
+ ContinueToResponseStarted(net::OK);
+ } else {
+ HandleResponseOrRedirectHeaders(
+ absl::nullopt,
+ base::BindOnce(&InterceptedRequest::ContinueToResponseStarted,
+ weak_factory_.GetWeakPtr()));
+ }
+}
+
+void InterceptedRequest::OnReceiveRedirect(
+ const net::RedirectInfo& redirect_info,
+ network::mojom::URLResponseHeadPtr head) {
+ // Whether to notify the client. True by default so that we always notify for
+ // internal redirects that originate from the network process (for HSTS, etc).
+ // False while a redirect is in-progress to avoid duplicate notifications.
+ bool notify_client = !redirect_in_progress_;
+
+ current_response_ = std::move(head);
+ current_body_.reset();
+ current_cached_metadata_.reset();
+
+ // |current_headers_| may be null for synthetic redirects where
+ // OnHeadersReceived is not called.
+ if (current_request_uses_header_client_ && current_headers_) {
+ // Use the headers we got from OnHeadersReceived as that'll contain
+ // Set-Cookie if it existed.
+ current_response_->headers = current_headers_;
+ current_headers_ = nullptr;
+ }
+
+ if (--redirect_limit_ == 0) {
+ SendErrorAndCompleteImmediately(net::ERR_TOO_MANY_REDIRECTS);
+ return;
+ }
+
+ net::RedirectInfo new_redirect_info;
+
+ // When we redirect via ContinueToHandleOverrideHeaders the |redirect_info|
+ // value is sometimes nonsense (HTTP_OK). Also, we won't get another call to
+ // OnHeadersReceived for the new URL so we need to notify the client here.
+ if (header_client_redirect_url_.is_valid() &&
+ redirect_info.status_code == net::HTTP_OK) {
+ DCHECK(current_request_uses_header_client_);
+ notify_client = true;
+ new_redirect_info =
+ MakeRedirectResponseAndInfo(header_client_redirect_url_);
+ } else {
+ new_redirect_info = redirect_info;
+ }
+
+ if (notify_client) {
+ HandleResponseOrRedirectHeaders(
+ new_redirect_info,
+ base::BindOnce(&InterceptedRequest::ContinueToBeforeRedirect,
+ weak_factory_.GetWeakPtr(), new_redirect_info));
+ } else {
+ ContinueToBeforeRedirect(new_redirect_info, net::OK);
+ }
+}
+
+void InterceptedRequest::OnUploadProgress(int64_t current_position,
+ int64_t total_size,
+ OnUploadProgressCallback callback) {
+ // Implement our own rate limiting for OnUploadProgress calls.
+ if (!waiting_for_upload_progress_ack_) {
+ waiting_for_upload_progress_ack_ = true;
+ target_client_->OnUploadProgress(
+ current_position, total_size,
+ base::BindOnce(&InterceptedRequest::OnUploadProgressACK,
+ weak_factory_.GetWeakPtr()));
+ }
+
+ // Always execute the callback immediately to avoid a race between
+ // URLLoaderClient_OnUploadProgress_ProxyToResponder::Run() (which would
+ // otherwise be blocked on the target client executing the callback) and
+ // CallOnComplete(). If CallOnComplete() is executed first the interface pipe
+ // will be closed and the callback destructor will generate an assertion like:
+ // "URLLoaderClient::OnUploadProgressCallback was destroyed without first
+ // either being run or its corresponding binding being closed. It is an error
+ // to drop response callbacks which still correspond to an open interface
+ // pipe."
+ std::move(callback).Run();
+}
+
+void InterceptedRequest::OnTransferSizeUpdated(int32_t transfer_size_diff) {
+ target_client_->OnTransferSizeUpdated(transfer_size_diff);
+}
+
+void InterceptedRequest::OnComplete(
+ const network::URLLoaderCompletionStatus& status) {
+ // Only wait for the original loader to possibly have a custom error if the
+ // target loader exists and succeeded. If the target loader failed, then it
+ // was a race as to whether that error or the safe browsing error would be
+ // reported.
+ CallOnComplete(status, !stream_loader_ && status.error_code == net::OK);
+}
+
+// URLLoader methods.
+
+void InterceptedRequest::FollowRedirect(
+ const std::vector<std::string>& removed_headers_ext,
+ const net::HttpRequestHeaders& modified_headers_ext,
+ const net::HttpRequestHeaders& modified_cors_exempt_headers,
+ const absl::optional<GURL>& new_url) {
+ std::vector<std::string> removed_headers = removed_headers_ext;
+ net::HttpRequestHeaders modified_headers = modified_headers_ext;
+ OnProcessRequestHeaders(new_url.value_or(GURL()), &modified_headers,
+ &removed_headers);
+
+ // If |OnURLLoaderClientError| was called then we're just waiting for the
+ // connection error handler of |proxied_loader_receiver_|. Don't restart the
+ // job since that'll create another URLLoader.
+ if (!target_client_) {
+ return;
+ }
+
+ // Normally we would call FollowRedirect on the target loader and it would
+ // begin loading the redirected request. However, the client might want to
+ // intercept that request so restart the job instead.
+ Restart();
+}
+
+void InterceptedRequest::SetPriority(net::RequestPriority priority,
+ int32_t intra_priority_value) {
+ if (target_loader_) {
+ target_loader_->SetPriority(priority, intra_priority_value);
+ }
+}
+
+void InterceptedRequest::PauseReadingBodyFromNet() {
+ if (target_loader_) {
+ target_loader_->PauseReadingBodyFromNet();
+ }
+}
+
+void InterceptedRequest::ResumeReadingBodyFromNet() {
+ if (target_loader_) {
+ target_loader_->ResumeReadingBodyFromNet();
+ }
+}
+
+// Helper methods.
+
+void InterceptedRequest::BeforeRequestReceived(const GURL& original_url,
+ bool intercept_request,
+ bool intercept_only) {
+ intercept_request_ = intercept_request;
+ intercept_only_ = intercept_only;
+
+ if (input_stream_previously_failed_ || !intercept_request_) {
+ // Equivalent to no interception.
+ InterceptResponseReceived(original_url, nullptr);
+ } else {
+ // TODO(network): Verify the case when WebContents::RenderFrameDeleted is
+ // called before network request is intercepted (i.e. if that's possible
+ // and whether it can result in any issues).
+ factory_->request_handler_->ShouldInterceptRequest(
+ id_, &request_,
+ base::BindOnce(&InterceptedRequest::InterceptResponseReceived,
+ weak_factory_.GetWeakPtr(), original_url));
+ }
+}
+
+void InterceptedRequest::InterceptResponseReceived(
+ const GURL& original_url,
+ std::unique_ptr<ResourceResponse> response) {
+ if (request_.url != original_url) {
+ // A response object shouldn't be created if we're redirecting.
+ DCHECK(!response);
+
+ // Perform the redirect.
+ current_response_ = network::mojom::URLResponseHead::New();
+ current_response_->request_start = base::TimeTicks::Now();
+ current_response_->response_start = base::TimeTicks::Now();
+ current_body_.reset();
+ current_cached_metadata_.reset();
+
+ auto headers = MakeResponseHeaders(
+ net::HTTP_TEMPORARY_REDIRECT, std::string(), std::string(),
+ std::string(), -1, {}, false /* allow_existing_header_override */);
+ current_response_->headers = headers;
+
+ current_response_->encoded_data_length = headers->raw_headers().length();
+ current_response_->content_length = 0;
+ current_response_->encoded_body_length = 0;
+
+ std::string origin;
+ if (request_.headers.GetHeader(net::HttpRequestHeaders::kOrigin, &origin) &&
+ origin != url::Origin().Serialize()) {
+ // Allow redirects of cross-origin resource loads.
+ headers->AddHeader(network::cors::header_names::kAccessControlAllowOrigin,
+ origin);
+ }
+
+ if (request_.credentials_mode ==
+ network::mojom::CredentialsMode::kInclude) {
+ headers->AddHeader(
+ network::cors::header_names::kAccessControlAllowCredentials, "true");
+ }
+
+ const net::RedirectInfo& redirect_info =
+ MakeRedirectInfo(request_, headers.get(), request_.url, 0);
+ HandleResponseOrRedirectHeaders(
+ redirect_info,
+ base::BindOnce(&InterceptedRequest::ContinueToBeforeRedirect,
+ weak_factory_.GetWeakPtr(), redirect_info));
+ return;
+ }
+
+ if (response) {
+ // Non-null response: make sure to use it as an override for the
+ // normal network data.
+ ContinueAfterInterceptWithOverride(std::move(response));
+ } else {
+ // Request was not intercepted/overridden. Proceed with loading
+ // from network, unless this is a special |intercept_only_| loader,
+ // which happens for external schemes (e.g. unsupported schemes).
+ if (intercept_only_) {
+ SendErrorAndCompleteImmediately(net::ERR_UNKNOWN_URL_SCHEME);
+ return;
+ }
+ ContinueAfterIntercept();
+ }
+}
+
+void InterceptedRequest::ContinueAfterIntercept() {
+ if (!target_loader_ && target_factory_) {
+ // Even if this request does not use the header client, future redirects
+ // might, so we need to set the option on the loader.
+ uint32_t options = options_ | network::mojom::kURLLoadOptionUseHeaderClient;
+ target_factory_->CreateLoaderAndStart(
+ target_loader_.BindNewPipeAndPassReceiver(), id_, options, request_,
+ proxied_client_receiver_.BindNewPipeAndPassRemote(),
+ traffic_annotation_);
+ }
+}
+
+void InterceptedRequest::ContinueAfterInterceptWithOverride(
+ std::unique_ptr<ResourceResponse> response) {
+ // StreamReaderURLLoader will synthesize TrustedHeaderClient callbacks to
+ // avoid having Set-Cookie headers stripped by the IPC layer.
+ current_request_uses_header_client_ = true;
+
+ stream_loader_ = new StreamReaderURLLoader(
+ id_, request_, proxied_client_receiver_.BindNewPipeAndPassRemote(),
+ header_client_receiver_.BindNewPipeAndPassRemote(), traffic_annotation_,
+ std::move(current_cached_metadata_),
+ std::make_unique<InterceptDelegate>(std::move(response),
+ weak_factory_.GetWeakPtr()));
+ stream_loader_->Start();
+}
+
+void InterceptedRequest::HandleResponseOrRedirectHeaders(
+ absl::optional<net::RedirectInfo> redirect_info,
+ net::CompletionOnceCallback continuation) {
+ override_headers_ = nullptr;
+ redirect_url_ = redirect_info.has_value() ? redirect_info->new_url : GURL();
+ original_url_ = request_.url;
+
+ if (!redirect_url_.is_empty()) {
+ redirect_in_progress_ = true;
+ }
+
+ // |current_response_| may be nullptr when called from OnHeadersReceived.
+ auto headers =
+ current_response_ ? current_response_->headers : current_headers_;
+
+ // Even though |head| is const we can get a non-const pointer to the headers
+ // and modifications we make are passed to the target client.
+ factory_->request_handler_->ProcessResponseHeaders(
+ id_, request_, redirect_url_, headers.get());
+
+ // Pause handling of client messages before waiting on an async callback.
+ if (proxied_client_receiver_.is_bound()) {
+ proxied_client_receiver_.Pause();
+ }
+
+ factory_->request_handler_->OnRequestResponse(
+ id_, &request_, headers.get(), redirect_info,
+ base::BindOnce(&InterceptedRequest::ContinueResponseOrRedirect,
+ weak_factory_.GetWeakPtr(), std::move(continuation)));
+}
+
+void InterceptedRequest::ContinueResponseOrRedirect(
+ net::CompletionOnceCallback continuation,
+ InterceptedRequestHandler::ResponseMode response_mode,
+ scoped_refptr<net::HttpResponseHeaders> override_headers,
+ const GURL& redirect_url) {
+ if (response_mode == InterceptedRequestHandler::ResponseMode::CANCEL) {
+ std::move(continuation).Run(net::ERR_ABORTED);
+ return;
+ } else if (response_mode ==
+ InterceptedRequestHandler::ResponseMode::RESTART) {
+ Restart();
+ return;
+ }
+
+ override_headers_ = override_headers;
+ if (override_headers_) {
+ // Make sure to update current_response_, since when OnReceiveResponse
+ // is called we will not use its headers as it might be missing the
+ // Set-Cookie line (which gets stripped by the IPC layer).
+ current_response_->headers = override_headers_;
+ }
+ redirect_url_ = redirect_url;
+
+ std::move(continuation).Run(net::OK);
+}
+
+void InterceptedRequest::ContinueToHandleOverrideHeaders(int error_code) {
+ if (error_code != net::OK) {
+ SendErrorAndCompleteImmediately(error_code);
+ return;
+ }
+
+ DCHECK(on_headers_received_callback_);
+ absl::optional<std::string> headers;
+ if (override_headers_) {
+ headers = override_headers_->raw_headers();
+ }
+ header_client_redirect_url_ = redirect_url_;
+ std::move(on_headers_received_callback_).Run(net::OK, headers, redirect_url_);
+
+ override_headers_ = nullptr;
+ redirect_url_ = GURL();
+
+ // Resume handling of client messages after continuing from an async callback.
+ if (proxied_client_receiver_.is_bound()) {
+ proxied_client_receiver_.Resume();
+ }
+}
+
+net::RedirectInfo InterceptedRequest::MakeRedirectResponseAndInfo(
+ const GURL& new_location) {
+ // Clear the Content-Type values.
+ current_response_->mime_type = current_response_->charset = std::string();
+ current_response_->headers->RemoveHeader(
+ net::HttpRequestHeaders::kContentType);
+
+ // Clear the Content-Length values.
+ current_response_->content_length = 0;
+ current_response_->encoded_body_length = 0;
+ current_response_->headers->RemoveHeader(
+ net::HttpRequestHeaders::kContentLength);
+
+ current_response_->encoded_data_length =
+ current_response_->headers->raw_headers().size();
+
+ const net::RedirectInfo& redirect_info = MakeRedirectInfo(
+ request_, current_response_->headers.get(), new_location, 0);
+ current_response_->headers->ReplaceStatusLine(
+ MakeStatusLine(redirect_info.status_code, std::string(), true));
+
+ return redirect_info;
+}
+
+void InterceptedRequest::ContinueToBeforeRedirect(
+ const net::RedirectInfo& redirect_info,
+ int error_code) {
+ if (error_code != net::OK) {
+ SendErrorAndCompleteImmediately(error_code);
+ return;
+ }
+
+ request_was_redirected_ = true;
+ redirect_in_progress_ = false;
+
+ if (header_client_redirect_url_.is_valid()) {
+ header_client_redirect_url_ = GURL();
+ }
+
+ const GURL redirect_url = redirect_url_;
+ override_headers_ = nullptr;
+ redirect_url_ = GURL();
+
+ // Resume handling of client messages after continuing from an async callback.
+ if (proxied_client_receiver_.is_bound()) {
+ proxied_client_receiver_.Resume();
+ }
+
+ const auto original_url = request_.url;
+ const auto original_method = request_.method;
+
+ net::RedirectInfo new_redirect_info = redirect_info;
+ if (redirect_url.is_valid()) {
+ new_redirect_info.new_url = redirect_url;
+ new_redirect_info.new_site_for_cookies =
+ net::SiteForCookies::FromUrl(redirect_url);
+ }
+
+ target_client_->OnReceiveRedirect(new_redirect_info,
+ std::move(current_response_));
+
+ request_.url = new_redirect_info.new_url;
+ request_.method = new_redirect_info.new_method;
+ request_.site_for_cookies = new_redirect_info.new_site_for_cookies;
+ request_.referrer = GURL(new_redirect_info.new_referrer);
+ request_.referrer_policy = new_redirect_info.new_referrer_policy;
+
+ if (request_.trusted_params) {
+ request_.trusted_params->isolation_info =
+ request_.trusted_params->isolation_info.CreateForRedirect(
+ url::Origin::Create(request_.url));
+ }
+
+ // Remove existing Cookie headers. They may be re-added after Restart().
+ const std::vector<std::string> remove_headers{
+ net::HttpRequestHeaders::kCookie};
+
+ // Use common logic for sanitizing request headers including Origin and
+ // Content-*.
+ bool should_clear_upload;
+ net::RedirectUtil::UpdateHttpRequest(original_url, original_method,
+ new_redirect_info,
+ absl::make_optional(remove_headers),
+ /*modified_headers=*/absl::nullopt,
+ &request_.headers, &should_clear_upload);
+
+ if (should_clear_upload) {
+ request_.request_body = nullptr;
+ }
+}
+
+void InterceptedRequest::ContinueToResponseStarted(int error_code) {
+ if (error_code != net::OK) {
+ SendErrorAndCompleteImmediately(error_code);
+ return;
+ }
+
+ const GURL redirect_url = redirect_url_;
+ override_headers_ = nullptr;
+ redirect_url_ = GURL();
+
+ scoped_refptr<net::HttpResponseHeaders> headers =
+ current_response_ ? current_response_->headers : nullptr;
+
+ std::string location;
+ const bool is_redirect =
+ redirect_url.is_valid() || (headers && headers->IsRedirect(&location));
+ if (stream_loader_ && is_redirect) {
+ // Redirecting from OnReceiveResponse generally isn't supported by the
+ // NetworkService, so we can only support it when using a custom loader.
+ // TODO(network): Remove this special case.
+ const GURL new_location = redirect_url.is_valid()
+ ? redirect_url
+ : original_url_.Resolve(location);
+ const net::RedirectInfo& redirect_info =
+ MakeRedirectResponseAndInfo(new_location);
+
+ HandleResponseOrRedirectHeaders(
+ redirect_info,
+ base::BindOnce(&InterceptedRequest::ContinueToBeforeRedirect,
+ weak_factory_.GetWeakPtr(), redirect_info));
+ } else {
+ LOG_IF(WARNING, is_redirect) << "Redirect at this time is not supported by "
+ "the default network loader.";
+
+ // CORS check for requests that are handled by the client. Requests handled
+ // by the network process will be checked there.
+ if (stream_loader_ && !is_redirect && request_.request_initiator &&
+ network::cors::ShouldCheckCors(request_.url, request_.request_initiator,
+ request_.mode)) {
+ const auto result = network::cors::CheckAccess(
+ request_.url,
+ GetHeaderString(
+ headers.get(),
+ network::cors::header_names::kAccessControlAllowOrigin),
+ GetHeaderString(
+ headers.get(),
+ network::cors::header_names::kAccessControlAllowCredentials),
+ request_.credentials_mode, *request_.request_initiator);
+ if (!result.has_value() &&
+ !HasCrossOriginWhitelistEntry(*request_.request_initiator,
+ url::Origin::Create(request_.url))) {
+ SendErrorStatusAndCompleteImmediately(
+ network::URLLoaderCompletionStatus(result.error()));
+ return;
+ }
+ }
+
+ // Resume handling of client messages after continuing from an async
+ // callback.
+ if (proxied_client_receiver_.is_bound()) {
+ proxied_client_receiver_.Resume();
+ }
+
+ target_client_->OnReceiveResponse(
+ std::move(current_response_),
+ factory_->request_handler_->OnFilterResponseBody(
+ id_, request_, std::move(current_body_)),
+ std::move(current_cached_metadata_));
+ }
+}
+
+void InterceptedRequest::OnDestroy() {
+ // We don't want any callbacks after this point.
+ weak_factory_.InvalidateWeakPtrs();
+
+ factory_->request_handler_->OnRequestComplete(id_, request_, status_);
+
+ // Destroys |this|.
+ factory_->RemoveRequest(this);
+}
+
+void InterceptedRequest::OnProcessRequestHeaders(
+ const GURL& redirect_url,
+ net::HttpRequestHeaders* modified_headers,
+ std::vector<std::string>* removed_headers) {
+ factory_->request_handler_->ProcessRequestHeaders(
+ id_, request_, redirect_url, modified_headers, removed_headers);
+
+ if (!modified_headers->IsEmpty() || !removed_headers->empty()) {
+ request_.headers.MergeFrom(*modified_headers);
+ for (const std::string& name : *removed_headers) {
+ request_.headers.RemoveHeader(name);
+ }
+ }
+}
+
+void InterceptedRequest::OnURLLoaderClientError() {
+ // We set |wait_for_loader_error| to true because if the loader did have a
+ // custom_reason error then the client would be reset as well and it would be
+ // a race as to which connection error we saw first.
+ CallOnComplete(network::URLLoaderCompletionStatus(net::ERR_ABORTED),
+ true /* wait_for_loader_error */);
+}
+
+void InterceptedRequest::OnURLLoaderError(uint32_t custom_reason,
+ const std::string& description) {
+ if (custom_reason == network::mojom::URLLoader::kClientDisconnectReason) {
+ SendErrorCallback(safe_browsing::kNetErrorCodeForSafeBrowsing, true);
+ }
+
+ got_loader_error_ = true;
+
+ // If CallOnComplete was already called, then this object is ready to be
+ // deleted.
+ if (!target_client_) {
+ OnDestroy();
+ }
+}
+
+void InterceptedRequest::CallOnComplete(
+ const network::URLLoaderCompletionStatus& status,
+ bool wait_for_loader_error) {
+ status_ = status;
+
+ if (target_client_) {
+ target_client_->OnComplete(status);
+ }
+
+ if (proxied_loader_receiver_.is_bound() &&
+ (wait_for_loader_error && !got_loader_error_)) {
+ // Don't delete |this| yet, in case the |proxied_loader_receiver_|'s
+ // error_handler is called with a reason to indicate an error which we want
+ // to send to the client bridge. Also reset |target_client_| so we don't
+ // get its error_handler called and then delete |this|.
+ target_client_.reset();
+
+ // Since the original client is gone no need to continue loading the
+ // request.
+ proxied_client_receiver_.reset();
+ header_client_receiver_.reset();
+ target_loader_.reset();
+
+ // In case there are pending checks as to whether this request should be
+ // intercepted, we don't want that causing |target_client_| to be used
+ // later.
+ weak_factory_.InvalidateWeakPtrs();
+ } else {
+ OnDestroy();
+ }
+}
+
+void InterceptedRequest::SendErrorAndCompleteImmediately(int error_code) {
+ SendErrorStatusAndCompleteImmediately(
+ network::URLLoaderCompletionStatus(error_code));
+}
+
+void InterceptedRequest::SendErrorStatusAndCompleteImmediately(
+ const network::URLLoaderCompletionStatus& status) {
+ status_ = status;
+ SendErrorCallback(status_.error_code, false);
+ target_client_->OnComplete(status_);
+ OnDestroy();
+}
+
+void InterceptedRequest::SendErrorCallback(int error_code,
+ bool safebrowsing_hit) {
+ // Ensure we only send one error callback, e.g. to avoid sending two if
+ // there's both a networking error and safe browsing blocked the request.
+ if (sent_error_callback_) {
+ return;
+ }
+
+ sent_error_callback_ = true;
+ factory_->request_handler_->OnRequestError(id_, request_, error_code,
+ safebrowsing_hit);
+}
+
+void InterceptedRequest::OnUploadProgressACK() {
+ DCHECK(waiting_for_upload_progress_ack_);
+ waiting_for_upload_progress_ack_ = false;
+}
+
+//==============================
+// InterceptedRequestHandler
+//==============================
+
+InterceptedRequestHandler::InterceptedRequestHandler() {}
+InterceptedRequestHandler::~InterceptedRequestHandler() {}
+
+void InterceptedRequestHandler::OnBeforeRequest(
+ int32_t request_id,
+ network::ResourceRequest* request,
+ bool request_was_redirected,
+ OnBeforeRequestResultCallback callback,
+ CancelRequestCallback cancel_callback) {
+ std::move(callback).Run(false, false);
+}
+
+void InterceptedRequestHandler::ShouldInterceptRequest(
+ int32_t request_id,
+ network::ResourceRequest* request,
+ ShouldInterceptRequestResultCallback callback) {
+ std::move(callback).Run(nullptr);
+}
+
+void InterceptedRequestHandler::OnRequestResponse(
+ int32_t request_id,
+ network::ResourceRequest* request,
+ net::HttpResponseHeaders* headers,
+ absl::optional<net::RedirectInfo> redirect_info,
+ OnRequestResponseResultCallback callback) {
+ std::move(callback).Run(
+ ResponseMode::CONTINUE, nullptr,
+ redirect_info.has_value() ? redirect_info->new_url : GURL());
+}
+
+mojo::ScopedDataPipeConsumerHandle
+InterceptedRequestHandler::OnFilterResponseBody(
+ int32_t request_id,
+ const network::ResourceRequest& request,
+ mojo::ScopedDataPipeConsumerHandle body) {
+ return body;
+}
+
+//==============================
+// ProxyURLLoaderFactory
+//==============================
+
+ProxyURLLoaderFactory::ProxyURLLoaderFactory(
+ mojo::PendingReceiver<network::mojom::URLLoaderFactory> factory_receiver,
+ mojo::PendingRemote<network::mojom::URLLoaderFactory> target_factory_remote,
+ mojo::PendingReceiver<network::mojom::TrustedURLLoaderHeaderClient>
+ header_client_receiver,
+ std::unique_ptr<InterceptedRequestHandler> request_handler)
+ : request_handler_(std::move(request_handler)), weak_factory_(this) {
+ CEF_REQUIRE_IOT();
+ DCHECK(request_handler_);
+
+ // Actual creation of the factory.
+ if (target_factory_remote) {
+ target_factory_.Bind(std::move(target_factory_remote));
+ target_factory_.set_disconnect_handler(base::BindOnce(
+ &ProxyURLLoaderFactory::OnTargetFactoryError, base::Unretained(this)));
+ }
+ proxy_receivers_.Add(this, std::move(factory_receiver));
+ proxy_receivers_.set_disconnect_handler(base::BindRepeating(
+ &ProxyURLLoaderFactory::OnProxyBindingError, base::Unretained(this)));
+
+ if (header_client_receiver) {
+ url_loader_header_client_receiver_.Bind(std::move(header_client_receiver));
+ }
+}
+
+ProxyURLLoaderFactory::~ProxyURLLoaderFactory() {
+ CEF_REQUIRE_IOT();
+}
+
+// static
+void ProxyURLLoaderFactory::CreateOnIOThread(
+ mojo::PendingReceiver<network::mojom::URLLoaderFactory> factory_receiver,
+ mojo::PendingRemote<network::mojom::URLLoaderFactory> target_factory,
+ mojo::PendingReceiver<network::mojom::TrustedURLLoaderHeaderClient>
+ header_client_receiver,
+ content::ResourceContext* resource_context,
+ std::unique_ptr<InterceptedRequestHandler> request_handler) {
+ CEF_REQUIRE_IOT();
+ auto proxy = new ProxyURLLoaderFactory(
+ std::move(factory_receiver), std::move(target_factory),
+ std::move(header_client_receiver), std::move(request_handler));
+ ResourceContextData::AddProxy(proxy, resource_context);
+}
+
+void ProxyURLLoaderFactory::SetDisconnectCallback(
+ DisconnectCallback on_disconnect) {
+ CEF_REQUIRE_IOT();
+ DCHECK(!destroyed_);
+ DCHECK(!on_disconnect_);
+ on_disconnect_ = std::move(on_disconnect);
+}
+
+// static
+void ProxyURLLoaderFactory::CreateProxy(
+ content::BrowserContext* browser_context,
+ mojo::PendingReceiver<network::mojom::URLLoaderFactory>* factory_receiver,
+ mojo::PendingRemote<network::mojom::TrustedURLLoaderHeaderClient>*
+ header_client,
+ std::unique_ptr<InterceptedRequestHandler> request_handler) {
+ CEF_REQUIRE_UIT();
+ DCHECK(request_handler);
+
+ auto proxied_receiver = std::move(*factory_receiver);
+ mojo::PendingRemote<network::mojom::URLLoaderFactory> target_factory_remote;
+ *factory_receiver = target_factory_remote.InitWithNewPipeAndPassReceiver();
+
+ mojo::PendingReceiver<network::mojom::TrustedURLLoaderHeaderClient>
+ header_client_receiver;
+ if (header_client) {
+ header_client_receiver = header_client->InitWithNewPipeAndPassReceiver();
+ }
+
+ content::ResourceContext* resource_context =
+ browser_context->GetResourceContext();
+ DCHECK(resource_context);
+
+ CEF_POST_TASK(
+ CEF_IOT,
+ base::BindOnce(
+ &ProxyURLLoaderFactory::CreateOnIOThread, std::move(proxied_receiver),
+ std::move(target_factory_remote), std::move(header_client_receiver),
+ base::Unretained(resource_context), std::move(request_handler)));
+}
+
+// static
+void ProxyURLLoaderFactory::CreateProxy(
+ content::WebContents::Getter web_contents_getter,
+ mojo::PendingReceiver<network::mojom::URLLoaderFactory> loader_receiver,
+ std::unique_ptr<InterceptedRequestHandler> request_handler) {
+ DCHECK(request_handler);
+
+ if (!CEF_CURRENTLY_ON_IOT()) {
+ CEF_POST_TASK(
+ CEF_IOT,
+ base::BindOnce(CreateProxyHelper, web_contents_getter,
+ std::move(loader_receiver), std::move(request_handler)));
+ return;
+ }
+
+ auto proxy = new ProxyURLLoaderFactory(
+ std::move(loader_receiver),
+ mojo::PendingRemote<network::mojom::URLLoaderFactory>(),
+ mojo::PendingReceiver<network::mojom::TrustedURLLoaderHeaderClient>(),
+ std::move(request_handler));
+ CEF_POST_TASK(CEF_UIT,
+ base::BindOnce(ResourceContextData::AddProxyOnUIThread,
+ base::Unretained(proxy), web_contents_getter));
+}
+
+void ProxyURLLoaderFactory::CreateLoaderAndStart(
+ mojo::PendingReceiver<network::mojom::URLLoader> receiver,
+ int32_t request_id,
+ uint32_t options,
+ const network::ResourceRequest& request,
+ mojo::PendingRemote<network::mojom::URLLoaderClient> client,
+ const net::MutableNetworkTrafficAnnotationTag& traffic_annotation) {
+ CEF_REQUIRE_IOT();
+ if (!CONTEXT_STATE_VALID()) {
+ // Don't start a request while we're shutting down.
+ return;
+ }
+
+ if (DisableRequestHandlingForTesting() && request.url.SchemeIsHTTPOrHTTPS()) {
+ // This is the so-called pass-through, no-op option.
+ if (target_factory_) {
+ target_factory_->CreateLoaderAndStart(std::move(receiver), request_id,
+ options, request, std::move(client),
+ traffic_annotation);
+ }
+ return;
+ }
+
+ mojo::PendingRemote<network::mojom::URLLoaderFactory> target_factory_clone;
+ if (target_factory_) {
+ target_factory_->Clone(
+ target_factory_clone.InitWithNewPipeAndPassReceiver());
+ }
+
+ InterceptedRequest* req = new InterceptedRequest(
+ this, request_id, options, request, traffic_annotation,
+ std::move(receiver), std::move(client), std::move(target_factory_clone));
+ requests_.insert(std::make_pair(request_id, base::WrapUnique(req)));
+ req->Restart();
+}
+
+void ProxyURLLoaderFactory::Clone(
+ mojo::PendingReceiver<network::mojom::URLLoaderFactory> factory) {
+ CEF_REQUIRE_IOT();
+ proxy_receivers_.Add(this, std::move(factory));
+}
+
+void ProxyURLLoaderFactory::OnLoaderCreated(
+ int32_t request_id,
+ mojo::PendingReceiver<network::mojom::TrustedHeaderClient> receiver) {
+ CEF_REQUIRE_IOT();
+ auto request_it = requests_.find(request_id);
+ if (request_it != requests_.end()) {
+ request_it->second->OnLoaderCreated(std::move(receiver));
+ }
+}
+
+void ProxyURLLoaderFactory::OnLoaderForCorsPreflightCreated(
+ const network::ResourceRequest& request,
+ mojo::PendingReceiver<network::mojom::TrustedHeaderClient> receiver) {
+ CEF_REQUIRE_IOT();
+ new CorsPreflightRequest(std::move(receiver));
+}
+
+void ProxyURLLoaderFactory::OnTargetFactoryError() {
+ // Stop calls to CreateLoaderAndStart() when |target_factory_| is invalid.
+ target_factory_.reset();
+ proxy_receivers_.Clear();
+
+ MaybeDestroySelf();
+}
+
+void ProxyURLLoaderFactory::OnProxyBindingError() {
+ if (proxy_receivers_.empty()) {
+ target_factory_.reset();
+ }
+
+ MaybeDestroySelf();
+}
+
+void ProxyURLLoaderFactory::RemoveRequest(InterceptedRequest* request) {
+ auto it = requests_.find(request->id());
+ DCHECK(it != requests_.end());
+ requests_.erase(it);
+
+ MaybeDestroySelf();
+}
+
+void ProxyURLLoaderFactory::MaybeDestroySelf() {
+ // Even if all URLLoaderFactory pipes connected to this object have been
+ // closed it has to stay alive until all active requests have completed.
+ if (target_factory_.is_bound() || !requests_.empty()) {
+ return;
+ }
+
+ destroyed_ = true;
+
+ // In some cases we may be destroyed before SetDisconnectCallback is called.
+ if (on_disconnect_) {
+ // Deletes |this|.
+ std::move(on_disconnect_).Run(this);
+ }
+}
+
+} // namespace net_service
diff --git a/libcef/browser/net_service/proxy_url_loader_factory.h b/libcef/browser/net_service/proxy_url_loader_factory.h
new file mode 100644
index 00000000..b9fdeae6
--- /dev/null
+++ b/libcef/browser/net_service/proxy_url_loader_factory.h
@@ -0,0 +1,229 @@
+// Copyright (c) 2019 The Chromium Embedded Framework Authors. Portions
+// Copyright (c) 2018 The Chromium Authors. All rights reserved. Use of this
+// source code is governed by a BSD-style license that can be found in the
+// LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_NET_SERVICE_PROXY_URL_LOADER_FACTORY_H_
+#define CEF_LIBCEF_BROWSER_NET_SERVICE_PROXY_URL_LOADER_FACTORY_H_
+
+#include "libcef/browser/net_service/stream_reader_url_loader.h"
+
+#include "base/containers/unique_ptr_adapters.h"
+#include "base/functional/callback.h"
+#include "base/hash/hash.h"
+#include "base/strings/string_piece.h"
+#include "content/public/browser/content_browser_client.h"
+#include "content/public/browser/web_contents.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/receiver_set.h"
+#include "services/network/public/mojom/network_context.mojom.h"
+#include "services/network/public/mojom/url_loader_factory.mojom.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace content {
+class ResourceContext;
+}
+
+namespace net_service {
+
+class InterceptedRequest;
+class ResourceContextData;
+
+// Implement this interface to to evaluate requests. All methods are called on
+// the IO thread, and all callbacks must be executed on the IO thread.
+class InterceptedRequestHandler {
+ public:
+ InterceptedRequestHandler();
+
+ InterceptedRequestHandler(const InterceptedRequestHandler&) = delete;
+ InterceptedRequestHandler& operator=(const InterceptedRequestHandler&) =
+ delete;
+
+ virtual ~InterceptedRequestHandler();
+
+ // Optionally modify |request| and execute |callback| to continue the request.
+ // Set |intercept_request| to false if the request will not be intercepted.
+ // Set |intercept_only| to true if the loader should not proceed unless the
+ // request is intercepted. Keep a reference to |cancel_callback| and execute
+ // at any time to cancel the request.
+ using OnBeforeRequestResultCallback =
+ base::OnceCallback<void(bool /* intercept_request */,
+ bool /* intercept_only */)>;
+ using CancelRequestCallback = base::OnceCallback<void(int /* error_code */)>;
+ virtual void OnBeforeRequest(int32_t request_id,
+ network::ResourceRequest* request,
+ bool request_was_redirected,
+ OnBeforeRequestResultCallback callback,
+ CancelRequestCallback cancel_callback);
+
+ // Optionally modify |request| and execute |callback| after determining if the
+ // request hould be intercepted.
+ using ShouldInterceptRequestResultCallback =
+ base::OnceCallback<void(std::unique_ptr<ResourceResponse>)>;
+ virtual void ShouldInterceptRequest(
+ int32_t request_id,
+ network::ResourceRequest* request,
+ ShouldInterceptRequestResultCallback callback);
+
+ // Called to evaluate and optionally modify request headers. |request| is the
+ // current request information. |redirect_url| will be non-empty if this
+ // method is called in response to a redirect. The |modified_headers| and
+ // |removed_headers| may be modified. If non-empty the |modified_headers|
+ // values will be merged first, and then any |removed_headers| values will be
+ // removed. This comparison is case sensitive.
+ virtual void ProcessRequestHeaders(
+ int32_t request_id,
+ const network::ResourceRequest& request,
+ const GURL& redirect_url,
+ net::HttpRequestHeaders* modified_headers,
+ std::vector<std::string>* removed_headers) {}
+
+ // Called to evaluate and optionally modify response headers. |request| is the
+ // current request information. |redirect_url| will be non-empty if this
+ // method is called in response to a redirect. Even though |head| is const the
+ // |head.headers| value is non-const and any changes will be passed to the
+ // client.
+ virtual void ProcessResponseHeaders(int32_t request_id,
+ const network::ResourceRequest& request,
+ const GURL& redirect_url,
+ net::HttpResponseHeaders* headers) {}
+
+ enum class ResponseMode {
+ // Continue the request.
+ CONTINUE,
+ // Restart the request.
+ RESTART,
+ // Cancel the request.
+ CANCEL
+ };
+
+ // Called on response. |request| is the current request information.
+ // |redirect_info| will be non-empty for redirect responses.
+ // Optionally modify |request| and execute the callback as appropriate.
+ using OnRequestResponseResultCallback = base::OnceCallback<void(
+ ResponseMode /* response_mode */,
+ scoped_refptr<net::HttpResponseHeaders> /* override_headers */,
+ const GURL& /* redirect_url */)>;
+ virtual void OnRequestResponse(
+ int32_t request_id,
+ network::ResourceRequest* request,
+ net::HttpResponseHeaders* headers,
+ absl::optional<net::RedirectInfo> redirect_info,
+ OnRequestResponseResultCallback callback);
+
+ // Called to optionally filter the response body.
+ virtual mojo::ScopedDataPipeConsumerHandle OnFilterResponseBody(
+ int32_t request_id,
+ const network::ResourceRequest& request,
+ mojo::ScopedDataPipeConsumerHandle body);
+
+ // Called on completion notification from the loader (successful or not).
+ virtual void OnRequestComplete(
+ int32_t request_id,
+ const network::ResourceRequest& request,
+ const network::URLLoaderCompletionStatus& status) {}
+
+ // Called on error.
+ virtual void OnRequestError(int32_t request_id,
+ const network::ResourceRequest& request,
+ int error_code,
+ bool safebrowsing_hit) {}
+};
+
+// URL Loader Factory that supports request/response interception, processing
+// and callback invocation.
+// Based on android_webview/browser/network_service/
+// aw_proxying_url_loader_factory.cc
+class ProxyURLLoaderFactory
+ : public network::mojom::URLLoaderFactory,
+ public network::mojom::TrustedURLLoaderHeaderClient {
+ public:
+ ProxyURLLoaderFactory(const ProxyURLLoaderFactory&) = delete;
+ ProxyURLLoaderFactory& operator=(const ProxyURLLoaderFactory&) = delete;
+
+ ~ProxyURLLoaderFactory() override;
+
+ // Create a proxy object on the UI thread.
+ static void CreateProxy(
+ content::BrowserContext* browser_context,
+ mojo::PendingReceiver<network::mojom::URLLoaderFactory>* factory_receiver,
+ mojo::PendingRemote<network::mojom::TrustedURLLoaderHeaderClient>*
+ header_client,
+ std::unique_ptr<InterceptedRequestHandler> request_handler);
+
+ // Create a proxy object on the IO thread.
+ static void CreateProxy(
+ content::WebContents::Getter web_contents_getter,
+ mojo::PendingReceiver<network::mojom::URLLoaderFactory> loader_request,
+ std::unique_ptr<InterceptedRequestHandler> request_handler);
+
+ // mojom::URLLoaderFactory methods:
+ void CreateLoaderAndStart(
+ mojo::PendingReceiver<network::mojom::URLLoader> receiver,
+ int32_t request_id,
+ uint32_t options,
+ const network::ResourceRequest& request,
+ mojo::PendingRemote<network::mojom::URLLoaderClient> client,
+ const net::MutableNetworkTrafficAnnotationTag& traffic_annotation)
+ override;
+ void Clone(
+ mojo::PendingReceiver<network::mojom::URLLoaderFactory> factory) override;
+
+ // network::mojom::TrustedURLLoaderHeaderClient:
+ void OnLoaderCreated(
+ int32_t request_id,
+ mojo::PendingReceiver<network::mojom::TrustedHeaderClient> receiver)
+ override;
+ void OnLoaderForCorsPreflightCreated(
+ const network::ResourceRequest& request,
+ mojo::PendingReceiver<network::mojom::TrustedHeaderClient> receiver)
+ override;
+
+ private:
+ friend class InterceptedRequest;
+ friend class ResourceContextData;
+
+ ProxyURLLoaderFactory(
+ mojo::PendingReceiver<network::mojom::URLLoaderFactory> factory_receiver,
+ mojo::PendingRemote<network::mojom::URLLoaderFactory>
+ target_factory_remote,
+ mojo::PendingReceiver<network::mojom::TrustedURLLoaderHeaderClient>
+ header_client_receiver,
+ std::unique_ptr<InterceptedRequestHandler> request_handler);
+
+ static void CreateOnIOThread(
+ mojo::PendingReceiver<network::mojom::URLLoaderFactory> factory_receiver,
+ mojo::PendingRemote<network::mojom::URLLoaderFactory>
+ target_factory_remote,
+ mojo::PendingReceiver<network::mojom::TrustedURLLoaderHeaderClient>
+ header_client_receiver,
+ content::ResourceContext* resource_context,
+ std::unique_ptr<InterceptedRequestHandler> request_handler);
+
+ using DisconnectCallback = base::OnceCallback<void(ProxyURLLoaderFactory*)>;
+ void SetDisconnectCallback(DisconnectCallback on_disconnect);
+
+ void OnTargetFactoryError();
+ void OnProxyBindingError();
+ void RemoveRequest(InterceptedRequest* request);
+ void MaybeDestroySelf();
+
+ mojo::ReceiverSet<network::mojom::URLLoaderFactory> proxy_receivers_;
+ mojo::Remote<network::mojom::URLLoaderFactory> target_factory_;
+ mojo::Receiver<network::mojom::TrustedURLLoaderHeaderClient>
+ url_loader_header_client_receiver_{this};
+
+ std::unique_ptr<InterceptedRequestHandler> request_handler_;
+
+ bool destroyed_ = false;
+ DisconnectCallback on_disconnect_;
+
+ // Map of request ID to request object.
+ std::map<int32_t, std::unique_ptr<InterceptedRequest>> requests_;
+
+ base::WeakPtrFactory<ProxyURLLoaderFactory> weak_factory_;
+};
+
+} // namespace net_service
+
+#endif // CEF_LIBCEF_BROWSER_NET_SERVICE_PROXY_URL_LOADER_FACTORY_H_
diff --git a/libcef/browser/net_service/resource_handler_wrapper.cc b/libcef/browser/net_service/resource_handler_wrapper.cc
new file mode 100644
index 00000000..f1acc40c
--- /dev/null
+++ b/libcef/browser/net_service/resource_handler_wrapper.cc
@@ -0,0 +1,523 @@
+// Copyright (c) 2019 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "libcef/browser/net_service/resource_handler_wrapper.h"
+
+#include "libcef/browser/net_service/proxy_url_loader_factory.h"
+#include "libcef/browser/thread_util.h"
+#include "libcef/common/net_service/net_service_util.h"
+#include "libcef/common/request_impl.h"
+
+#include "base/strings/string_number_conversions.h"
+#include "net/http/http_status_code.h"
+
+namespace net_service {
+
+namespace {
+
+class SkipCallbackWrapper : public CefResourceSkipCallback {
+ public:
+ explicit SkipCallbackWrapper(InputStream::SkipCallback callback)
+ : callback_(std::move(callback)),
+ work_thread_task_runner_(
+ base::SequencedTaskRunner::GetCurrentDefault()) {}
+
+ SkipCallbackWrapper(const SkipCallbackWrapper&) = delete;
+ SkipCallbackWrapper& operator=(const SkipCallbackWrapper&) = delete;
+
+ ~SkipCallbackWrapper() override {
+ if (!callback_.is_null()) {
+ // Make sure it executes on the correct thread.
+ work_thread_task_runner_->PostTask(
+ FROM_HERE, base::BindOnce(std::move(callback_), net::ERR_FAILED));
+ }
+ }
+
+ void Continue(int64 bytes_skipped) override {
+ if (!work_thread_task_runner_->RunsTasksInCurrentSequence()) {
+ work_thread_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(&SkipCallbackWrapper::Continue, this, bytes_skipped));
+ return;
+ }
+ if (!callback_.is_null()) {
+ std::move(callback_).Run(bytes_skipped);
+ }
+ }
+
+ void Disconnect() { callback_.Reset(); }
+
+ private:
+ InputStream::SkipCallback callback_;
+
+ scoped_refptr<base::SequencedTaskRunner> work_thread_task_runner_;
+
+ IMPLEMENT_REFCOUNTING(SkipCallbackWrapper);
+};
+
+class ReadCallbackWrapper : public CefResourceReadCallback {
+ public:
+ explicit ReadCallbackWrapper(InputStream::ReadCallback callback)
+ : callback_(std::move(callback)),
+ work_thread_task_runner_(
+ base::SequencedTaskRunner::GetCurrentDefault()) {}
+
+ ReadCallbackWrapper(const ReadCallbackWrapper&) = delete;
+ ReadCallbackWrapper& operator=(const ReadCallbackWrapper&) = delete;
+
+ ~ReadCallbackWrapper() override {
+ if (!callback_.is_null()) {
+ // Make sure it executes on the correct thread.
+ work_thread_task_runner_->PostTask(
+ FROM_HERE, base::BindOnce(std::move(callback_), net::ERR_FAILED));
+ }
+ }
+
+ void Continue(int bytes_read) override {
+ if (!work_thread_task_runner_->RunsTasksInCurrentSequence()) {
+ work_thread_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(&ReadCallbackWrapper::Continue, this, bytes_read));
+ return;
+ }
+ if (!callback_.is_null()) {
+ std::move(callback_).Run(bytes_read);
+ }
+ }
+
+ void Disconnect() { callback_.Reset(); }
+
+ private:
+ InputStream::ReadCallback callback_;
+
+ scoped_refptr<base::SequencedTaskRunner> work_thread_task_runner_;
+
+ IMPLEMENT_REFCOUNTING(ReadCallbackWrapper);
+};
+
+// Helper for accessing a CefResourceHandler without creating reference loops.
+class HandlerProvider : public base::RefCountedThreadSafe<HandlerProvider> {
+ public:
+ explicit HandlerProvider(CefRefPtr<CefResourceHandler> handler)
+ : handler_(handler) {
+ DCHECK(handler_);
+ }
+ virtual ~HandlerProvider() {
+ // Detach should have been called.
+ DCHECK(!handler_);
+ }
+
+ CefRefPtr<CefResourceHandler> handler() const {
+ base::AutoLock lock_scope(lock_);
+ return handler_;
+ }
+
+ void Detach() {
+ base::AutoLock lock_scope(lock_);
+ if (!handler_) {
+ return;
+ }
+
+ // Execute on the expected thread.
+ CEF_POST_TASK(CEF_IOT,
+ base::BindOnce(&CefResourceHandler::Cancel, handler_));
+
+ handler_ = nullptr;
+ }
+
+ private:
+ mutable base::Lock lock_;
+ CefRefPtr<CefResourceHandler> handler_;
+};
+
+class ReadResponseCallbackWrapper : public CefCallback {
+ public:
+ ReadResponseCallbackWrapper(const ReadResponseCallbackWrapper&) = delete;
+ ReadResponseCallbackWrapper& operator=(const ReadResponseCallbackWrapper&) =
+ delete;
+
+ ~ReadResponseCallbackWrapper() override {
+ if (callback_) {
+ // This will post to the correct thread if necessary.
+ callback_->Continue(net::ERR_FAILED);
+ }
+ }
+
+ void Continue() override {
+ CEF_POST_TASK(CEF_IOT,
+ base::BindOnce(&ReadResponseCallbackWrapper::DoRead, this));
+ }
+
+ void Cancel() override {
+ CEF_POST_TASK(CEF_IOT,
+ base::BindOnce(&ReadResponseCallbackWrapper::DoCancel, this));
+ }
+
+ static void ReadResponse(scoped_refptr<HandlerProvider> handler_provider,
+ net::IOBuffer* dest,
+ int length,
+ CefRefPtr<ReadCallbackWrapper> callback) {
+ CEF_POST_TASK(
+ CEF_IOT,
+ base::BindOnce(ReadResponseCallbackWrapper::ReadResponseOnIOThread,
+ handler_provider, base::Unretained(dest), length,
+ callback));
+ }
+
+ private:
+ ReadResponseCallbackWrapper(scoped_refptr<HandlerProvider> handler_provider,
+ net::IOBuffer* dest,
+ int length,
+ CefRefPtr<ReadCallbackWrapper> callback)
+ : handler_provider_(handler_provider),
+ dest_(dest),
+ length_(length),
+ callback_(callback) {}
+
+ static void ReadResponseOnIOThread(
+ scoped_refptr<HandlerProvider> handler_provider,
+ net::IOBuffer* dest,
+ int length,
+ CefRefPtr<ReadCallbackWrapper> callback) {
+ CEF_REQUIRE_IOT();
+ CefRefPtr<ReadResponseCallbackWrapper> callbackWrapper =
+ new ReadResponseCallbackWrapper(handler_provider, dest, length,
+ callback);
+ callbackWrapper->DoRead();
+ }
+
+ void DoRead() {
+ CEF_REQUIRE_IOT();
+ if (!callback_) {
+ return;
+ }
+
+ auto handler = handler_provider_->handler();
+ if (!handler) {
+ DoCancel();
+ return;
+ }
+
+ int bytes_read = 0;
+ bool result =
+ handler->ReadResponse(dest_->data(), length_, bytes_read, this);
+ if (result) {
+ if (bytes_read > 0) {
+ // Continue immediately.
+ callback_->Continue(bytes_read);
+ callback_ = nullptr;
+ }
+ return;
+ }
+
+ // Signal response completion immediately.
+ callback_->Continue(0);
+ callback_ = nullptr;
+ }
+
+ void DoCancel() {
+ CEF_REQUIRE_IOT();
+ if (callback_) {
+ callback_->Continue(net::ERR_FAILED);
+ callback_ = nullptr;
+ }
+ }
+
+ scoped_refptr<HandlerProvider> handler_provider_;
+ net::IOBuffer* const dest_;
+ int length_;
+ CefRefPtr<ReadCallbackWrapper> callback_;
+
+ IMPLEMENT_REFCOUNTING(ReadResponseCallbackWrapper);
+};
+
+class InputStreamWrapper : public InputStream {
+ public:
+ explicit InputStreamWrapper(scoped_refptr<HandlerProvider> handler_provider)
+ : handler_provider_(handler_provider) {}
+
+ InputStreamWrapper(const InputStreamWrapper&) = delete;
+ InputStreamWrapper& operator=(const InputStreamWrapper&) = delete;
+
+ ~InputStreamWrapper() override { Cancel(); }
+
+ // InputStream methods:
+ bool Skip(int64_t n, int64_t* bytes_skipped, SkipCallback callback) override {
+ auto handler = handler_provider_->handler();
+ if (!handler) {
+ // Cancel immediately.
+ *bytes_skipped = net::ERR_FAILED;
+ return false;
+ }
+
+ CefRefPtr<SkipCallbackWrapper> callbackWrapper =
+ new SkipCallbackWrapper(std::move(callback));
+ bool result = handler->Skip(n, *bytes_skipped, callbackWrapper.get());
+ if (result) {
+ if (*bytes_skipped > 0) {
+ // Continue immediately.
+ callbackWrapper->Disconnect();
+ }
+ return true;
+ }
+
+ // Cancel immediately.
+ return false;
+ }
+
+ bool Read(net::IOBuffer* dest,
+ int length,
+ int* bytes_read,
+ ReadCallback callback) override {
+ auto handler = handler_provider_->handler();
+ if (!handler) {
+ // Cancel immediately.
+ *bytes_read = net::ERR_FAILED;
+ return false;
+ }
+
+ CefRefPtr<ReadCallbackWrapper> callbackWrapper =
+ new ReadCallbackWrapper(std::move(callback));
+ bool result =
+ handler->Read(dest->data(), length, *bytes_read, callbackWrapper.get());
+ if (result) {
+ if (*bytes_read > 0) {
+ // Continue immediately.
+ callbackWrapper->Disconnect();
+ }
+ return true;
+ }
+
+ if (*bytes_read == -1) {
+ // Call ReadResponse on the IO thread.
+ ReadResponseCallbackWrapper::ReadResponse(handler_provider_, dest, length,
+ callbackWrapper);
+ *bytes_read = 0;
+ return true;
+ }
+
+ // Complete or cancel immediately.
+ return false;
+ }
+
+ void Cancel() {
+ // Triggers a call to Cancel on the handler.
+ handler_provider_->Detach();
+ }
+
+ private:
+ scoped_refptr<HandlerProvider> handler_provider_;
+};
+
+class OpenCallbackWrapper : public CefCallback {
+ public:
+ OpenCallbackWrapper(ResourceResponse::OpenCallback callback,
+ std::unique_ptr<InputStreamWrapper> stream)
+ : callback_(std::move(callback)),
+ stream_(std::move(stream)),
+ work_thread_task_runner_(
+ base::SequencedTaskRunner::GetCurrentDefault()) {}
+
+ OpenCallbackWrapper(const OpenCallbackWrapper&) = delete;
+ OpenCallbackWrapper& operator=(const OpenCallbackWrapper&) = delete;
+
+ ~OpenCallbackWrapper() override {
+ if (!callback_.is_null()) {
+ // Make sure it executes on the correct thread.
+ work_thread_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(&OpenCallbackWrapper::Execute, std::move(callback_),
+ std::move(stream_), false));
+ }
+ }
+
+ void Continue() override {
+ if (!work_thread_task_runner_->RunsTasksInCurrentSequence()) {
+ work_thread_task_runner_->PostTask(
+ FROM_HERE, base::BindOnce(&OpenCallbackWrapper::Continue, this));
+ return;
+ }
+ if (!callback_.is_null()) {
+ Execute(std::move(callback_), std::move(stream_), true);
+ }
+ }
+
+ void Cancel() override {
+ if (!work_thread_task_runner_->RunsTasksInCurrentSequence()) {
+ work_thread_task_runner_->PostTask(
+ FROM_HERE, base::BindOnce(&OpenCallbackWrapper::Cancel, this));
+ return;
+ }
+ if (!callback_.is_null()) {
+ Execute(std::move(callback_), std::move(stream_), false);
+ }
+ }
+
+ private:
+ static void Execute(ResourceResponse::OpenCallback callback,
+ std::unique_ptr<InputStreamWrapper> stream,
+ bool cont) {
+ std::move(callback).Run(cont ? std::move(stream) : nullptr);
+ }
+
+ ResourceResponse::OpenCallback callback_;
+ std::unique_ptr<InputStreamWrapper> stream_;
+
+ scoped_refptr<base::SequencedTaskRunner> work_thread_task_runner_;
+
+ IMPLEMENT_REFCOUNTING(OpenCallbackWrapper);
+};
+
+void CallProcessRequestOnIOThread(
+ scoped_refptr<HandlerProvider> handler_provider,
+ CefRefPtr<CefRequestImpl> request,
+ CefRefPtr<OpenCallbackWrapper> callbackWrapper) {
+ CEF_REQUIRE_IOT();
+ auto handler = handler_provider->handler();
+ if (!handler) {
+ callbackWrapper->Cancel();
+ return;
+ }
+
+ if (!handler->ProcessRequest(request.get(), callbackWrapper.get())) {
+ callbackWrapper->Cancel();
+ }
+}
+
+class ResourceResponseWrapper : public ResourceResponse {
+ public:
+ ResourceResponseWrapper(const int32_t request_id,
+ CefRefPtr<CefResourceHandler> handler)
+ : request_id_(request_id),
+ handler_provider_(new HandlerProvider(handler)) {}
+
+ ResourceResponseWrapper(const ResourceResponseWrapper&) = delete;
+ ResourceResponseWrapper& operator=(const ResourceResponseWrapper&) = delete;
+
+ ~ResourceResponseWrapper() override {
+ // Triggers a call to Cancel on the handler.
+ handler_provider_->Detach();
+ }
+
+ // ResourceResponse methods:
+ bool OpenInputStream(int32_t request_id,
+ const network::ResourceRequest& request,
+ OpenCallback callback) override {
+ DCHECK_EQ(request_id, request_id_);
+
+ auto handler = handler_provider_->handler();
+ if (!handler) {
+ // Cancel immediately.
+ return false;
+ }
+
+ // May be recreated on redirect.
+ request_ = new CefRequestImpl();
+ request_->Set(&request, request_id);
+ request_->SetReadOnly(true);
+
+ CefRefPtr<OpenCallbackWrapper> callbackWrapper = new OpenCallbackWrapper(
+ std::move(callback),
+ std::make_unique<InputStreamWrapper>(handler_provider_));
+ bool handle_request = false;
+ bool result =
+ handler->Open(request_.get(), handle_request, callbackWrapper.get());
+ if (result) {
+ if (handle_request) {
+ // Continue immediately.
+ callbackWrapper->Continue();
+ }
+ return true;
+ }
+
+ if (handle_request) {
+ // Cancel immediately.
+ callbackWrapper->Cancel();
+ return true;
+ }
+
+ // Call ProcessRequest on the IO thread.
+ CEF_POST_TASK(
+ CEF_IOT, base::BindOnce(CallProcessRequestOnIOThread, handler_provider_,
+ request_, callbackWrapper));
+ return true;
+ }
+
+ void GetResponseHeaders(int32_t request_id,
+ int* status_code,
+ std::string* reason_phrase,
+ std::string* mime_type,
+ std::string* charset,
+ int64_t* content_length,
+ HeaderMap* extra_headers) override {
+ DCHECK_EQ(request_id, request_id_);
+ CEF_REQUIRE_IOT();
+
+ auto handler = handler_provider_->handler();
+ if (!handler) {
+ // Cancel immediately.
+ *status_code = net::ERR_FAILED;
+ return;
+ }
+
+ CefRefPtr<CefResponse> response = CefResponse::Create();
+ int64_t response_length = -1;
+ CefString redirect_url;
+ handler->GetResponseHeaders(response, response_length, redirect_url);
+
+ const auto error_code = response->GetError();
+ if (error_code != ERR_NONE) {
+ // Early exit if the handler reported an error.
+ *status_code = error_code;
+ return;
+ }
+
+ if (!redirect_url.empty()) {
+ // Perform a redirect.
+ *status_code = net::HTTP_TEMPORARY_REDIRECT;
+ *reason_phrase = std::string();
+ extra_headers->insert(
+ std::make_pair(kHTTPLocationHeaderName, redirect_url));
+ } else {
+ *status_code = response->GetStatus();
+ *reason_phrase = response->GetStatusText();
+ }
+
+ if (reason_phrase->empty() && *status_code > 0) {
+ *reason_phrase = net::GetHttpReasonPhrase(
+ static_cast<net::HttpStatusCode>(*status_code));
+ }
+
+ *mime_type = response->GetMimeType();
+ *charset = response->GetCharset();
+
+ // A |content_length| value may already be specified if the request included
+ // a Range header.
+ if (response_length >= 0 && *content_length == -1) {
+ *content_length = response_length;
+ }
+
+ CefResponse::HeaderMap headerMap;
+ response->GetHeaderMap(headerMap);
+ for (const auto& value : headerMap) {
+ extra_headers->insert(std::make_pair(value.first, value.second));
+ }
+ }
+
+ private:
+ const int32_t request_id_;
+
+ CefRefPtr<CefRequestImpl> request_;
+ scoped_refptr<HandlerProvider> handler_provider_;
+};
+
+} // namespace
+
+std::unique_ptr<ResourceResponse> CreateResourceResponse(
+ int32_t request_id,
+ CefRefPtr<CefResourceHandler> handler) {
+ return std::make_unique<ResourceResponseWrapper>(request_id, handler);
+}
+
+} // namespace net_service
diff --git a/libcef/browser/net_service/resource_handler_wrapper.h b/libcef/browser/net_service/resource_handler_wrapper.h
new file mode 100644
index 00000000..b47c95b0
--- /dev/null
+++ b/libcef/browser/net_service/resource_handler_wrapper.h
@@ -0,0 +1,24 @@
+// Copyright (c) 2019 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_NET_SERVICE_RESOURCE_HANDLER_WRAPPER_H_
+#define CEF_LIBCEF_BROWSER_NET_SERVICE_RESOURCE_HANDLER_WRAPPER_H_
+
+#include "include/cef_request.h"
+#include "include/cef_resource_handler.h"
+
+namespace net_service {
+
+class ResourceResponse;
+
+// Create a ResourceResponse that delegates to |handler|.
+// The resulting object should be passed to
+// InterceptedRequestHandler::ShouldInterceptRequestResultCallback.
+std::unique_ptr<ResourceResponse> CreateResourceResponse(
+ int32_t request_id,
+ CefRefPtr<CefResourceHandler> handler);
+
+} // namespace net_service
+
+#endif // CEF_LIBCEF_BROWSER_NET_SERVICE_RESOURCE_HANDLER_WRAPPER_H_
diff --git a/libcef/browser/net_service/resource_request_handler_wrapper.cc b/libcef/browser/net_service/resource_request_handler_wrapper.cc
new file mode 100644
index 00000000..f5ca9c59
--- /dev/null
+++ b/libcef/browser/net_service/resource_request_handler_wrapper.cc
@@ -0,0 +1,1432 @@
+// Copyright (c) 2019 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "libcef/browser/net_service/resource_request_handler_wrapper.h"
+
+#include "libcef/browser/browser_host_base.h"
+#include "libcef/browser/context.h"
+#include "libcef/browser/iothread_state.h"
+#include "libcef/browser/net_service/cookie_helper.h"
+#include "libcef/browser/net_service/proxy_url_loader_factory.h"
+#include "libcef/browser/net_service/resource_handler_wrapper.h"
+#include "libcef/browser/net_service/response_filter_wrapper.h"
+#include "libcef/browser/prefs/browser_prefs.h"
+#include "libcef/browser/thread_util.h"
+#include "libcef/common/app_manager.h"
+#include "libcef/common/net/scheme_registration.h"
+#include "libcef/common/net_service/net_service_util.h"
+#include "libcef/common/request_impl.h"
+#include "libcef/common/response_impl.h"
+
+#include "chrome/browser/profiles/profile.h"
+#include "components/language/core/browser/pref_names.h"
+#include "components/prefs/pref_service.h"
+#include "content/browser/renderer_host/frame_tree_node.h"
+#include "content/browser/renderer_host/render_frame_host_impl.h"
+#include "content/browser/storage_partition_impl.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/web_contents.h"
+#include "net/base/load_flags.h"
+#include "net/http/http_status_code.h"
+#include "third_party/blink/public/mojom/loader/resource_load_info.mojom-shared.h"
+#include "ui/base/page_transition_types.h"
+#include "url/origin.h"
+
+namespace net_service {
+
+namespace {
+
+const int kLoadNoCookiesFlags =
+ net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES;
+
+class RequestCallbackWrapper : public CefCallback {
+ public:
+ using Callback = base::OnceCallback<void(bool /* allow */)>;
+ explicit RequestCallbackWrapper(Callback callback)
+ : callback_(std::move(callback)),
+ work_thread_task_runner_(
+ base::SequencedTaskRunner::GetCurrentDefault()) {}
+
+ RequestCallbackWrapper(const RequestCallbackWrapper&) = delete;
+ RequestCallbackWrapper& operator=(const RequestCallbackWrapper&) = delete;
+
+ ~RequestCallbackWrapper() override {
+ if (!callback_.is_null()) {
+ // Make sure it executes on the correct thread.
+ work_thread_task_runner_->PostTask(
+ FROM_HERE, base::BindOnce(std::move(callback_), true));
+ }
+ }
+
+ void Continue() override { ContinueNow(true); }
+
+ void Cancel() override { ContinueNow(false); }
+
+ private:
+ void ContinueNow(bool allow) {
+ if (!work_thread_task_runner_->RunsTasksInCurrentSequence()) {
+ work_thread_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(&RequestCallbackWrapper::ContinueNow, this, allow));
+ return;
+ }
+ if (!callback_.is_null()) {
+ std::move(callback_).Run(allow);
+ }
+ }
+
+ Callback callback_;
+
+ scoped_refptr<base::SequencedTaskRunner> work_thread_task_runner_;
+
+ IMPLEMENT_REFCOUNTING(RequestCallbackWrapper);
+};
+
+class InterceptedRequestHandlerWrapper : public InterceptedRequestHandler {
+ public:
+ struct RequestState {
+ RequestState() {}
+
+ void Reset(CefRefPtr<CefResourceRequestHandler> handler,
+ CefRefPtr<CefSchemeHandlerFactory> scheme_factory,
+ CefRefPtr<CefRequestImpl> request,
+ bool request_was_redirected,
+ CancelRequestCallback cancel_callback) {
+ handler_ = handler;
+ scheme_factory_ = scheme_factory;
+ cookie_filter_ = nullptr;
+ pending_request_ = request;
+ pending_response_ = nullptr;
+ request_was_redirected_ = request_was_redirected;
+ was_custom_handled_ = false;
+ cancel_callback_ = std::move(cancel_callback);
+ }
+
+ CefRefPtr<CefResourceRequestHandler> handler_;
+ CefRefPtr<CefSchemeHandlerFactory> scheme_factory_;
+ CefRefPtr<CefCookieAccessFilter> cookie_filter_;
+ CefRefPtr<CefRequestImpl> pending_request_;
+ CefRefPtr<CefResponseImpl> pending_response_;
+ bool request_was_redirected_ = false;
+ bool was_custom_handled_ = false;
+ bool accept_language_added_ = false;
+ CancelRequestCallback cancel_callback_;
+ };
+
+ struct PendingRequest {
+ PendingRequest(int32_t request_id,
+ network::ResourceRequest* request,
+ bool request_was_redirected,
+ OnBeforeRequestResultCallback callback,
+ CancelRequestCallback cancel_callback)
+ : id_(request_id),
+ request_(request),
+ request_was_redirected_(request_was_redirected),
+ callback_(std::move(callback)),
+ cancel_callback_(std::move(cancel_callback)) {}
+
+ ~PendingRequest() {
+ if (cancel_callback_) {
+ std::move(cancel_callback_).Run(net::ERR_ABORTED);
+ }
+ }
+
+ void Run(InterceptedRequestHandlerWrapper* self) {
+ self->OnBeforeRequest(id_, request_, request_was_redirected_,
+ std::move(callback_), std::move(cancel_callback_));
+ }
+
+ const int32_t id_;
+ network::ResourceRequest* const request_;
+ const bool request_was_redirected_;
+ OnBeforeRequestResultCallback callback_;
+ CancelRequestCallback cancel_callback_;
+ };
+
+ // Observer to receive notification of CEF context or associated browser
+ // destruction. Only one of the *Destroyed() methods will be called.
+ class DestructionObserver : public CefBrowserHostBase::Observer,
+ public CefContext::Observer {
+ public:
+ explicit DestructionObserver(CefBrowserHostBase* browser) {
+ if (browser) {
+ browser_info_ = browser->browser_info();
+ browser->AddObserver(this);
+ } else {
+ CefContext::Get()->AddObserver(this);
+ }
+ }
+
+ DestructionObserver(const DestructionObserver&) = delete;
+ DestructionObserver& operator=(const DestructionObserver&) = delete;
+
+ virtual ~DestructionObserver() {
+ CEF_REQUIRE_UIT();
+ if (!registered_) {
+ return;
+ }
+
+ // Verify that the browser or context still exists before attempting to
+ // remove the observer.
+ if (browser_info_) {
+ auto browser = browser_info_->browser();
+ if (browser) {
+ browser->RemoveObserver(this);
+ }
+ } else if (CefContext::Get()) {
+ // Network requests may be torn down during shutdown, so we can't check
+ // CONTEXT_STATE_VALID() here.
+ CefContext::Get()->RemoveObserver(this);
+ }
+ }
+
+ void SetWrapper(base::WeakPtr<InterceptedRequestHandlerWrapper> wrapper) {
+ CEF_REQUIRE_IOT();
+ wrapper_ = wrapper;
+ }
+
+ void OnBrowserDestroyed(CefBrowserHostBase* browser) override {
+ CEF_REQUIRE_UIT();
+ browser->RemoveObserver(this);
+ registered_ = false;
+ browser_info_ = nullptr;
+ NotifyOnDestroyed();
+ }
+
+ void OnContextDestroyed() override {
+ CEF_REQUIRE_UIT();
+ CefContext::Get()->RemoveObserver(this);
+ registered_ = false;
+ NotifyOnDestroyed();
+ }
+
+ private:
+ void NotifyOnDestroyed() {
+ if (wrapper_.MaybeValid()) {
+ // This will be a no-op if the WeakPtr is invalid.
+ CEF_POST_TASK(
+ CEF_IOT,
+ base::BindOnce(&InterceptedRequestHandlerWrapper::OnDestroyed,
+ wrapper_));
+ }
+ }
+
+ scoped_refptr<CefBrowserInfo> browser_info_;
+ bool registered_ = true;
+
+ base::WeakPtr<InterceptedRequestHandlerWrapper> wrapper_;
+ };
+
+ // Holds state information for InterceptedRequestHandlerWrapper. State is
+ // initialized on the UI thread and later passed to the *Wrapper object on
+ // the IO thread.
+ struct InitState {
+ InitState() {}
+
+ ~InitState() {
+ if (destruction_observer_) {
+ if (initialized_) {
+ // Clear the reference added in
+ // InterceptedRequestHandlerWrapper::SetInitialized().
+ destruction_observer_->SetWrapper(nullptr);
+ }
+ DeleteDestructionObserver();
+ }
+ }
+
+ void Initialize(content::BrowserContext* browser_context,
+ CefRefPtr<CefBrowserHostBase> browser,
+ CefRefPtr<CefFrame> frame,
+ const content::GlobalRenderFrameHostId& global_id,
+ bool is_navigation,
+ bool is_download,
+ const url::Origin& request_initiator,
+ const base::RepeatingClosure& unhandled_request_callback) {
+ CEF_REQUIRE_UIT();
+
+ auto profile = Profile::FromBrowserContext(browser_context);
+ auto cef_browser_context = CefBrowserContext::FromProfile(profile);
+ browser_context_getter_ = cef_browser_context->getter();
+ iothread_state_ = cef_browser_context->iothread_state();
+ CHECK(iothread_state_);
+ cookieable_schemes_ = cef_browser_context->GetCookieableSchemes();
+
+ // We register to be notified of CEF context or browser destruction so
+ // that we can stop accepting new requests and cancel pending/in-progress
+ // requests in a timely manner (e.g. before we start asserting about
+ // leaked objects during CEF shutdown).
+ destruction_observer_.reset(new DestructionObserver(browser.get()));
+
+ if (browser) {
+ // These references will be released in OnDestroyed().
+ browser_ = browser;
+ frame_ = frame;
+ }
+
+ global_id_ = global_id;
+ is_navigation_ = is_navigation;
+ is_download_ = is_download;
+ request_initiator_ = request_initiator.Serialize();
+ unhandled_request_callback_ = unhandled_request_callback;
+
+ // Default values for standard headers.
+ accept_language_ = browser_prefs::GetAcceptLanguageList(
+ cef_browser_context, browser.get(), /*expand=*/true);
+ DCHECK(!accept_language_.empty());
+ user_agent_ =
+ CefAppManager::Get()->GetContentClient()->browser()->GetUserAgent();
+ DCHECK(!user_agent_.empty());
+ }
+
+ void DeleteDestructionObserver() {
+ DCHECK(destruction_observer_);
+ CEF_POST_TASK(
+ CEF_UIT,
+ base::BindOnce(&InitState::DeleteDestructionObserverOnUIThread,
+ std::move(destruction_observer_)));
+ }
+
+ static void DeleteDestructionObserverOnUIThread(
+ std::unique_ptr<DestructionObserver> observer) {}
+
+ // Only accessed on the UI thread.
+ CefBrowserContext::Getter browser_context_getter_;
+
+ bool initialized_ = false;
+
+ CefRefPtr<CefBrowserHostBase> browser_;
+ CefRefPtr<CefFrame> frame_;
+ scoped_refptr<CefIOThreadState> iothread_state_;
+ CefBrowserContext::CookieableSchemes cookieable_schemes_;
+ content::GlobalRenderFrameHostId global_id_;
+ bool is_navigation_ = true;
+ bool is_download_ = false;
+ CefString request_initiator_;
+ base::RepeatingClosure unhandled_request_callback_;
+
+ // Default values for standard headers.
+ std::string accept_language_;
+ std::string user_agent_;
+
+ // Used to route authentication and certificate callbacks through the
+ // associated StoragePartition instance.
+ mojo::PendingRemote<network::mojom::URLLoaderNetworkServiceObserver>
+ url_loader_network_observer_;
+ bool did_try_create_url_loader_network_observer_ = false;
+
+ // Used to receive destruction notification.
+ std::unique_ptr<DestructionObserver> destruction_observer_;
+ };
+
+ // Manages InterceptedRequestHandlerWrapper initialization. The *Wrapper
+ // object is owned by ProxyURLLoaderFactory and may be deleted before
+ // SetInitialized() is called.
+ struct InitHelper : base::RefCountedThreadSafe<InitHelper> {
+ public:
+ explicit InitHelper(InterceptedRequestHandlerWrapper* wrapper)
+ : wrapper_(wrapper) {}
+
+ InitHelper(const InitHelper&) = delete;
+ InitHelper& operator=(const InitHelper&) = delete;
+
+ void MaybeSetInitialized(std::unique_ptr<InitState> init_state) {
+ CEF_POST_TASK(CEF_IOT, base::BindOnce(&InitHelper::SetInitialized, this,
+ std::move(init_state)));
+ }
+
+ void Disconnect() {
+ base::AutoLock lock_scope(lock_);
+ wrapper_ = nullptr;
+ }
+
+ private:
+ void SetInitialized(std::unique_ptr<InitState> init_state) {
+ base::AutoLock lock_scope(lock_);
+ // May be nullptr if the InterceptedRequestHandlerWrapper has already
+ // been deleted.
+ if (!wrapper_) {
+ return;
+ }
+ wrapper_->SetInitialized(std::move(init_state));
+ wrapper_ = nullptr;
+ }
+
+ base::Lock lock_;
+ InterceptedRequestHandlerWrapper* wrapper_;
+ };
+
+ InterceptedRequestHandlerWrapper()
+ : init_helper_(base::MakeRefCounted<InitHelper>(this)),
+ weak_ptr_factory_(this) {}
+
+ InterceptedRequestHandlerWrapper(const InterceptedRequestHandlerWrapper&) =
+ delete;
+ InterceptedRequestHandlerWrapper& operator=(
+ const InterceptedRequestHandlerWrapper&) = delete;
+
+ ~InterceptedRequestHandlerWrapper() override {
+ CEF_REQUIRE_IOT();
+
+ // There should be no in-progress requests during destruction.
+ DCHECK(request_map_.empty());
+
+ // Don't continue with initialization if we get deleted before
+ // SetInitialized is called asynchronously.
+ init_helper_->Disconnect();
+ }
+
+ scoped_refptr<InitHelper> init_helper() const { return init_helper_; }
+
+ void SetInitialized(std::unique_ptr<InitState> init_state) {
+ CEF_REQUIRE_IOT();
+ DCHECK(!init_state_);
+ init_state_ = std::move(init_state);
+
+ // Check that the CEF context or associated browser was not destroyed
+ // between the calls to Initialize and SetInitialized, in which case
+ // we won't get an OnDestroyed callback from DestructionObserver.
+ if (init_state_->browser_) {
+ if (!init_state_->browser_->browser_info()->browser()) {
+ OnDestroyed();
+ return;
+ }
+ } else if (!CONTEXT_STATE_VALID()) {
+ OnDestroyed();
+ return;
+ }
+
+ init_state_->initialized_ = true;
+ init_state_->destruction_observer_->SetWrapper(
+ weak_ptr_factory_.GetWeakPtr());
+
+ // Continue any pending requests.
+ if (!pending_requests_.empty()) {
+ for (const auto& request : pending_requests_) {
+ request->Run(this);
+ }
+ pending_requests_.clear();
+ }
+ }
+
+ static void TryCreateURLLoaderNetworkObserver(
+ std::unique_ptr<PendingRequest> pending_request,
+ CefRefPtr<CefFrame> frame,
+ const CefBrowserContext::Getter& browser_context_getter,
+ base::WeakPtr<InterceptedRequestHandlerWrapper> self) {
+ CEF_REQUIRE_UIT();
+
+ mojo::PendingRemote<network::mojom::URLLoaderNetworkServiceObserver>
+ url_loader_network_observer;
+
+ if (frame) {
+ // The request will be associated with this frame/browser if it's valid,
+ // otherwise the request will be canceled.
+ content::RenderFrameHostImpl* rfh =
+ static_cast<content::RenderFrameHostImpl*>(
+ static_cast<CefFrameHostImpl*>(frame.get())
+ ->GetRenderFrameHost());
+ if (rfh) {
+ if (rfh->frame_tree_node() &&
+ rfh->frame_tree_node()->navigation_request()) {
+ // Associate the Observer with the current NavigationRequest. This is
+ // necessary for |is_main_frame_request| to report true (the expected
+ // value) in AllowCertificateError.
+ // TODO(cef): This approach for retrieving the NavigationRequest is
+ // deprecated, see https://crbug.com/1179502#c36.
+ url_loader_network_observer =
+ rfh->GetStoragePartition()
+ ->CreateURLLoaderNetworkObserverForNavigationRequest(
+ *(rfh->frame_tree_node()->navigation_request()));
+ } else {
+ // Associate the Observer with the RenderFrameHost.
+ url_loader_network_observer = rfh->CreateURLLoaderNetworkObserver();
+ }
+ }
+ } else {
+ auto cef_browser_context = browser_context_getter.Run();
+ auto browser_context = cef_browser_context
+ ? cef_browser_context->AsBrowserContext()
+ : nullptr;
+ if (browser_context) {
+ url_loader_network_observer =
+ static_cast<content::StoragePartitionImpl*>(
+ browser_context->GetDefaultStoragePartition())
+ ->CreateAuthCertObserverForServiceWorker();
+ }
+ }
+
+ CEF_POST_TASK(CEF_IOT,
+ base::BindOnce(&InterceptedRequestHandlerWrapper::
+ ContinueCreateURLLoaderNetworkObserver,
+ self, std::move(pending_request),
+ std::move(url_loader_network_observer)));
+ }
+
+ void ContinueCreateURLLoaderNetworkObserver(
+ std::unique_ptr<PendingRequest> pending_request,
+ mojo::PendingRemote<network::mojom::URLLoaderNetworkServiceObserver>
+ url_loader_network_observer) {
+ CEF_REQUIRE_IOT();
+
+ DCHECK(!init_state_->did_try_create_url_loader_network_observer_);
+ init_state_->did_try_create_url_loader_network_observer_ = true;
+ init_state_->url_loader_network_observer_ =
+ std::move(url_loader_network_observer);
+ pending_request->Run(this);
+ }
+
+ // InterceptedRequestHandler methods:
+ void OnBeforeRequest(int32_t request_id,
+ network::ResourceRequest* request,
+ bool request_was_redirected,
+ OnBeforeRequestResultCallback callback,
+ CancelRequestCallback cancel_callback) override {
+ CEF_REQUIRE_IOT();
+
+ if (shutting_down_) {
+ // Abort immediately.
+ std::move(cancel_callback).Run(net::ERR_ABORTED);
+ return;
+ }
+
+ if (!init_state_) {
+ // Queue requests until we're initialized.
+ pending_requests_.push_back(std::make_unique<PendingRequest>(
+ request_id, request, request_was_redirected, std::move(callback),
+ std::move(cancel_callback)));
+ return;
+ }
+
+ if (request->trusted_params &&
+ !request->trusted_params->url_loader_network_observer &&
+ !init_state_->did_try_create_url_loader_network_observer_) {
+ // Restarted/redirected requests won't already have an observer, so we
+ // need to create one.
+ CEF_POST_TASK(
+ CEF_UIT,
+ base::BindOnce(&InterceptedRequestHandlerWrapper::
+ TryCreateURLLoaderNetworkObserver,
+ std::make_unique<PendingRequest>(
+ request_id, request, request_was_redirected,
+ std::move(callback), std::move(cancel_callback)),
+ init_state_->frame_,
+ init_state_->browser_context_getter_,
+ weak_ptr_factory_.GetWeakPtr()));
+ return;
+ }
+
+ // State may already exist for restarted requests.
+ RequestState* state = GetOrCreateState(request_id);
+
+ if (init_state_->did_try_create_url_loader_network_observer_) {
+ if (init_state_->url_loader_network_observer_) {
+ request->trusted_params->url_loader_network_observer =
+ std::move(init_state_->url_loader_network_observer_);
+ }
+
+ // Reset state so that the observer will be recreated on the next
+ // restart/redirect.
+ init_state_->did_try_create_url_loader_network_observer_ = false;
+ }
+
+ // Add standard headers, if currently unspecified.
+ if (!request->headers.HasHeader(net::HttpRequestHeaders::kAcceptLanguage)) {
+ request->headers.SetHeaderIfMissing(
+ net::HttpRequestHeaders::kAcceptLanguage,
+ init_state_->accept_language_);
+ state->accept_language_added_ = true;
+ }
+ request->headers.SetHeaderIfMissing(net::HttpRequestHeaders::kUserAgent,
+ init_state_->user_agent_);
+
+ const bool is_external = IsExternalRequest(request);
+
+ // External requests will not have a default handler.
+ bool intercept_only = is_external;
+
+ CefRefPtr<CefRequestImpl> requestPtr;
+ CefRefPtr<CefResourceRequestHandler> handler =
+ GetHandler(request_id, request, &intercept_only, requestPtr);
+
+ CefRefPtr<CefSchemeHandlerFactory> scheme_factory =
+ init_state_->iothread_state_->GetSchemeHandlerFactory(request->url);
+ if (scheme_factory && !requestPtr) {
+ requestPtr = MakeRequest(request, request_id, true);
+ }
+
+ // True if there's a possibility that the client might handle the request.
+ const bool maybe_intercept_request = handler || scheme_factory;
+ if (!maybe_intercept_request && requestPtr) {
+ requestPtr = nullptr;
+ }
+
+ // May have a handler and/or scheme factory.
+ state->Reset(handler, scheme_factory, requestPtr, request_was_redirected,
+ std::move(cancel_callback));
+
+ if (handler) {
+ state->cookie_filter_ = handler->GetCookieAccessFilter(
+ init_state_->browser_, init_state_->frame_, requestPtr.get());
+ }
+
+ auto exec_callback =
+ base::BindOnce(std::move(callback), maybe_intercept_request,
+ is_external ? true : intercept_only);
+
+ if (!maybe_intercept_request) {
+ // Cookies will be handled by the NetworkService.
+ std::move(exec_callback).Run();
+ return;
+ }
+
+ MaybeLoadCookies(request_id, state, request, std::move(exec_callback));
+ }
+
+ void MaybeLoadCookies(int32_t request_id,
+ RequestState* state,
+ network::ResourceRequest* request,
+ base::OnceClosure callback) {
+ CEF_REQUIRE_IOT();
+
+ if (!cookie_helper::IsCookieableScheme(request->url,
+ init_state_->cookieable_schemes_)) {
+ // The scheme does not support cookies.
+ std::move(callback).Run();
+ return;
+ }
+
+ // We need to load/save cookies ourselves for custom-handled requests, or
+ // if we're using a cookie filter.
+ auto allow_cookie_callback =
+ state->cookie_filter_
+ ? base::BindRepeating(
+ &InterceptedRequestHandlerWrapper::AllowCookieLoad,
+ weak_ptr_factory_.GetWeakPtr(), request_id)
+ : base::BindRepeating(
+ &InterceptedRequestHandlerWrapper::AllowCookieAlways);
+ auto done_cookie_callback = base::BindOnce(
+ &InterceptedRequestHandlerWrapper::ContinueWithLoadedCookies,
+ weak_ptr_factory_.GetWeakPtr(), request_id, request,
+ std::move(callback));
+ cookie_helper::LoadCookies(init_state_->browser_context_getter_, *request,
+ allow_cookie_callback,
+ std::move(done_cookie_callback));
+ }
+
+ static void AllowCookieAlways(const net::CanonicalCookie& cookie,
+ bool* allow) {
+ *allow = true;
+ }
+
+ void AllowCookieLoad(int32_t request_id,
+ const net::CanonicalCookie& cookie,
+ bool* allow) {
+ CEF_REQUIRE_IOT();
+
+ RequestState* state = GetState(request_id);
+ if (!state) {
+ // The request may have been canceled while the async callback was
+ // pending.
+ return;
+ }
+
+ DCHECK(state->cookie_filter_);
+
+ CefCookie cef_cookie;
+ if (net_service::MakeCefCookie(cookie, cef_cookie)) {
+ *allow = state->cookie_filter_->CanSendCookie(
+ init_state_->browser_, init_state_->frame_,
+ state->pending_request_.get(), cef_cookie);
+ }
+ }
+
+ void ContinueWithLoadedCookies(int32_t request_id,
+ network::ResourceRequest* request,
+ base::OnceClosure callback,
+ int total_count,
+ net::CookieList allowed_cookies) {
+ CEF_REQUIRE_IOT();
+
+ RequestState* state = GetState(request_id);
+ if (!state) {
+ // The request may have been canceled while the async callback was
+ // pending.
+ return;
+ }
+
+ if (state->cookie_filter_) {
+ // Also add/save cookies ourselves for default-handled network requests
+ // so that we can filter them. This will be a no-op for custom-handled
+ // requests.
+ request->load_flags |= kLoadNoCookiesFlags;
+ }
+
+ if (!allowed_cookies.empty()) {
+ const std::string& cookie_line =
+ net::CanonicalCookie::BuildCookieLine(allowed_cookies);
+ request->headers.SetHeader(net::HttpRequestHeaders::kCookie, cookie_line);
+
+ state->pending_request_->SetReadOnly(false);
+ state->pending_request_->SetHeaderByName(net::HttpRequestHeaders::kCookie,
+ cookie_line, true);
+ state->pending_request_->SetReadOnly(true);
+ }
+
+ std::move(callback).Run();
+ }
+
+ void ShouldInterceptRequest(
+ int32_t request_id,
+ network::ResourceRequest* request,
+ ShouldInterceptRequestResultCallback callback) override {
+ CEF_REQUIRE_IOT();
+
+ RequestState* state = GetState(request_id);
+ if (!state) {
+ // The request may have been canceled during destruction.
+ return;
+ }
+
+ // Must have a handler and/or scheme factory.
+ DCHECK(state->handler_ || state->scheme_factory_);
+ DCHECK(state->pending_request_);
+
+ if (state->handler_) {
+ // The client may modify |pending_request_| before executing the callback.
+ state->pending_request_->SetReadOnly(false);
+ state->pending_request_->SetTrackChanges(true,
+ true /* backup_on_change */);
+
+ CefRefPtr<RequestCallbackWrapper> callbackPtr =
+ new RequestCallbackWrapper(base::BindOnce(
+ &InterceptedRequestHandlerWrapper::ContinueShouldInterceptRequest,
+ weak_ptr_factory_.GetWeakPtr(), request_id,
+ base::Unretained(request), std::move(callback)));
+
+ cef_return_value_t retval = state->handler_->OnBeforeResourceLoad(
+ init_state_->browser_, init_state_->frame_,
+ state->pending_request_.get(), callbackPtr.get());
+ if (retval != RV_CONTINUE_ASYNC) {
+ if (retval == RV_CONTINUE) {
+ // Continue the request immediately.
+ callbackPtr->Continue();
+ } else {
+ // Cancel the request immediately.
+ callbackPtr->Cancel();
+ }
+ }
+ } else {
+ // The scheme factory may choose to handle it.
+ ContinueShouldInterceptRequest(request_id, request, std::move(callback),
+ true);
+ }
+ }
+
+ void ContinueShouldInterceptRequest(
+ int32_t request_id,
+ network::ResourceRequest* request,
+ ShouldInterceptRequestResultCallback callback,
+ bool allow) {
+ CEF_REQUIRE_IOT();
+
+ RequestState* state = GetState(request_id);
+ if (!state) {
+ // The request may have been canceled while the async callback was
+ // pending.
+ return;
+ }
+
+ // Must have a handler and/or scheme factory.
+ DCHECK(state->handler_ || state->scheme_factory_);
+ DCHECK(state->pending_request_);
+
+ if (state->handler_) {
+ if (allow) {
+ // Apply any |requestPtr| changes to |request|.
+ state->pending_request_->Get(request, true /* changed_only */);
+ }
+
+ const bool redirect =
+ (state->pending_request_->GetChanges() & CefRequestImpl::kChangedUrl);
+ if (redirect) {
+ // Revert any changes for now. We'll get them back after the redirect.
+ state->pending_request_->RevertChanges();
+ }
+
+ state->pending_request_->SetReadOnly(true);
+ state->pending_request_->SetTrackChanges(false);
+
+ if (!allow) {
+ // Cancel the request.
+ if (state->cancel_callback_) {
+ std::move(state->cancel_callback_).Run(net::ERR_ABORTED);
+ }
+ return;
+ }
+
+ if (redirect) {
+ // Performing a redirect.
+ std::move(callback).Run(nullptr);
+ return;
+ }
+ }
+
+ CefRefPtr<CefResourceHandler> resource_handler;
+
+ if (state->handler_) {
+ // Does the client want to handle the request?
+ resource_handler = state->handler_->GetResourceHandler(
+ init_state_->browser_, init_state_->frame_,
+ state->pending_request_.get());
+ }
+ if (!resource_handler && state->scheme_factory_) {
+ // Does the scheme factory want to handle the request?
+ resource_handler = state->scheme_factory_->Create(
+ init_state_->browser_, init_state_->frame_, request->url.scheme(),
+ state->pending_request_.get());
+ }
+
+ std::unique_ptr<ResourceResponse> resource_response;
+ if (resource_handler) {
+ resource_response = CreateResourceResponse(request_id, resource_handler);
+ DCHECK(resource_response);
+ state->was_custom_handled_ = true;
+ } else if (state->accept_language_added_) {
+ // The request will be handled by the NetworkService. Remove the
+ // "Accept-Language" header here so that it can be re-added in
+ // URLRequestHttpJob::AddExtraHeaders with correct ordering applied.
+ request->headers.RemoveHeader(net::HttpRequestHeaders::kAcceptLanguage);
+ }
+
+ // Continue the request.
+ std::move(callback).Run(std::move(resource_response));
+ }
+
+ void ProcessResponseHeaders(int32_t request_id,
+ const network::ResourceRequest& request,
+ const GURL& redirect_url,
+ net::HttpResponseHeaders* headers) override {
+ CEF_REQUIRE_IOT();
+
+ RequestState* state = GetState(request_id);
+ if (!state) {
+ // The request may have been canceled during destruction.
+ return;
+ }
+
+ if (!state->handler_) {
+ return;
+ }
+
+ if (!state->pending_response_) {
+ state->pending_response_ = new CefResponseImpl();
+ } else {
+ state->pending_response_->SetReadOnly(false);
+ }
+
+ if (headers) {
+ state->pending_response_->SetResponseHeaders(*headers);
+ }
+
+ state->pending_response_->SetReadOnly(true);
+ }
+
+ void OnRequestResponse(int32_t request_id,
+ network::ResourceRequest* request,
+ net::HttpResponseHeaders* headers,
+ absl::optional<net::RedirectInfo> redirect_info,
+ OnRequestResponseResultCallback callback) override {
+ CEF_REQUIRE_IOT();
+
+ RequestState* state = GetState(request_id);
+ if (!state) {
+ // The request may have been canceled during destruction.
+ return;
+ }
+
+ if (state->cookie_filter_) {
+ // Remove the flags that were added in ContinueWithLoadedCookies.
+ request->load_flags &= ~kLoadNoCookiesFlags;
+ }
+
+ if (!state->handler_) {
+ // Cookies may come from a scheme handler.
+ MaybeSaveCookies(
+ request_id, state, request, headers,
+ base::BindOnce(
+ std::move(callback), ResponseMode::CONTINUE, nullptr,
+ redirect_info.has_value() ? redirect_info->new_url : GURL()));
+ return;
+ }
+
+ DCHECK(state->pending_request_);
+ DCHECK(state->pending_response_);
+
+ if (redirect_info.has_value()) {
+ HandleRedirect(request_id, state, request, headers, *redirect_info,
+ std::move(callback));
+ } else {
+ HandleResponse(request_id, state, request, headers, std::move(callback));
+ }
+ }
+
+ void HandleRedirect(int32_t request_id,
+ RequestState* state,
+ network::ResourceRequest* request,
+ net::HttpResponseHeaders* headers,
+ const net::RedirectInfo& redirect_info,
+ OnRequestResponseResultCallback callback) {
+ GURL new_url = redirect_info.new_url;
+ CefString newUrl = redirect_info.new_url.spec();
+ CefString oldUrl = newUrl;
+ bool url_changed = false;
+ state->handler_->OnResourceRedirect(
+ init_state_->browser_, init_state_->frame_,
+ state->pending_request_.get(), state->pending_response_.get(), newUrl);
+ if (newUrl != oldUrl) {
+ // Also support relative URLs.
+ const GURL& url = redirect_info.new_url.Resolve(newUrl.ToString());
+ if (url.is_valid()) {
+ url_changed = true;
+ new_url = url;
+ }
+ }
+
+ // Update the |pending_request_| object with the new info.
+ state->pending_request_->SetReadOnly(false);
+ state->pending_request_->Set(redirect_info);
+ if (url_changed) {
+ state->pending_request_->SetURL(new_url.spec());
+ }
+ state->pending_request_->SetReadOnly(true);
+
+ auto exec_callback = base::BindOnce(
+ std::move(callback), ResponseMode::CONTINUE, nullptr, new_url);
+
+ MaybeSaveCookies(request_id, state, request, headers,
+ std::move(exec_callback));
+ }
+
+ void HandleResponse(int32_t request_id,
+ RequestState* state,
+ network::ResourceRequest* request,
+ net::HttpResponseHeaders* headers,
+ OnRequestResponseResultCallback callback) {
+ // The client may modify |pending_request_| in OnResourceResponse.
+ state->pending_request_->SetReadOnly(false);
+ state->pending_request_->SetTrackChanges(true, true /* backup_on_change */);
+
+ auto response_mode = ResponseMode::CONTINUE;
+ GURL new_url;
+
+ if (state->handler_->OnResourceResponse(
+ init_state_->browser_, init_state_->frame_,
+ state->pending_request_.get(), state->pending_response_.get())) {
+ // The request may have been modified.
+ const auto changes = state->pending_request_->GetChanges();
+ if (changes) {
+ state->pending_request_->Get(request, true /* changed_only */);
+
+ if (changes & CefRequestImpl::kChangedUrl) {
+ // Redirect to the new URL.
+ new_url = GURL(state->pending_request_->GetURL().ToString());
+ } else {
+ // Restart the request.
+ response_mode = ResponseMode::RESTART;
+ }
+ }
+ }
+
+ // Revert any changes for now. We'll get them back after the redirect or
+ // restart.
+ state->pending_request_->RevertChanges();
+
+ state->pending_request_->SetReadOnly(true);
+ state->pending_request_->SetTrackChanges(false);
+
+ auto exec_callback =
+ base::BindOnce(std::move(callback), response_mode, nullptr, new_url);
+
+ if (response_mode == ResponseMode::RESTART) {
+ // Get any cookies after the restart.
+ std::move(exec_callback).Run();
+ return;
+ }
+
+ MaybeSaveCookies(request_id, state, request, headers,
+ std::move(exec_callback));
+ }
+
+ void MaybeSaveCookies(int32_t request_id,
+ RequestState* state,
+ network::ResourceRequest* request,
+ net::HttpResponseHeaders* headers,
+ base::OnceClosure callback) {
+ CEF_REQUIRE_IOT();
+
+ if (!state->cookie_filter_ && !state->was_custom_handled_) {
+ // The NetworkService saves the cookies for default-handled requests.
+ std::move(callback).Run();
+ return;
+ }
+
+ if (!cookie_helper::IsCookieableScheme(request->url,
+ init_state_->cookieable_schemes_)) {
+ // The scheme does not support cookies.
+ std::move(callback).Run();
+ return;
+ }
+
+ // We need to load/save cookies ourselves for custom-handled requests, or
+ // if we're using a cookie filter.
+ auto allow_cookie_callback =
+ state->cookie_filter_
+ ? base::BindRepeating(
+ &InterceptedRequestHandlerWrapper::AllowCookieSave,
+ weak_ptr_factory_.GetWeakPtr(), request_id)
+ : base::BindRepeating(
+ &InterceptedRequestHandlerWrapper::AllowCookieAlways);
+ auto done_cookie_callback = base::BindOnce(
+ &InterceptedRequestHandlerWrapper::ContinueWithSavedCookies,
+ weak_ptr_factory_.GetWeakPtr(), request_id, std::move(callback));
+ cookie_helper::SaveCookies(init_state_->browser_context_getter_, *request,
+ headers, allow_cookie_callback,
+ std::move(done_cookie_callback));
+ }
+
+ void AllowCookieSave(int32_t request_id,
+ const net::CanonicalCookie& cookie,
+ bool* allow) {
+ CEF_REQUIRE_IOT();
+
+ RequestState* state = GetState(request_id);
+ if (!state) {
+ // The request may have been canceled while the async callback was
+ // pending.
+ return;
+ }
+
+ DCHECK(state->cookie_filter_);
+
+ CefCookie cef_cookie;
+ if (net_service::MakeCefCookie(cookie, cef_cookie)) {
+ *allow = state->cookie_filter_->CanSaveCookie(
+ init_state_->browser_, init_state_->frame_,
+ state->pending_request_.get(), state->pending_response_.get(),
+ cef_cookie);
+ }
+ }
+
+ void ContinueWithSavedCookies(int32_t request_id,
+ base::OnceClosure callback,
+ int total_count,
+ net::CookieList allowed_cookies) {
+ CEF_REQUIRE_IOT();
+ std::move(callback).Run();
+ }
+
+ mojo::ScopedDataPipeConsumerHandle OnFilterResponseBody(
+ int32_t request_id,
+ const network::ResourceRequest& request,
+ mojo::ScopedDataPipeConsumerHandle body) override {
+ CEF_REQUIRE_IOT();
+
+ RequestState* state = GetState(request_id);
+ if (!state) {
+ // The request may have been canceled during destruction.
+ return body;
+ }
+
+ if (state->handler_) {
+ auto filter = state->handler_->GetResourceResponseFilter(
+ init_state_->browser_, init_state_->frame_,
+ state->pending_request_.get(), state->pending_response_.get());
+ if (filter) {
+ return CreateResponseFilterHandler(
+ filter, std::move(body),
+ base::BindOnce(&InterceptedRequestHandlerWrapper::OnFilterError,
+ weak_ptr_factory_.GetWeakPtr(), request_id));
+ }
+ }
+
+ return body;
+ }
+
+ void OnFilterError(int32_t request_id) {
+ CEF_REQUIRE_IOT();
+
+ RequestState* state = GetState(request_id);
+ if (!state) {
+ // The request may have been canceled while the async callback was
+ // pending.
+ return;
+ }
+
+ if (state->cancel_callback_) {
+ std::move(state->cancel_callback_).Run(net::ERR_CONTENT_DECODING_FAILED);
+ }
+ }
+
+ void OnRequestComplete(
+ int32_t request_id,
+ const network::ResourceRequest& request,
+ const network::URLLoaderCompletionStatus& status) override {
+ CEF_REQUIRE_IOT();
+
+ RequestState* state = GetState(request_id);
+ if (!state) {
+ // The request may have been aborted during initialization or canceled
+ // during destruction. This method will always be called before a request
+ // is deleted, so if the request is currently pending also remove it from
+ // the list.
+ if (!pending_requests_.empty()) {
+ PendingRequests::iterator it = pending_requests_.begin();
+ for (; it != pending_requests_.end(); ++it) {
+ if ((*it)->id_ == request_id) {
+ pending_requests_.erase(it);
+ break;
+ }
+ }
+ }
+ return;
+ }
+
+ const bool is_external = IsExternalRequest(&request);
+
+ // Redirection of standard custom schemes is handled with a restart, so we
+ // get completion notifications for both the original (redirected) request
+ // and the final request. Don't report completion of the redirected request.
+ const bool ignore_result = is_external && request.url.IsStandard() &&
+ status.error_code == net::ERR_ABORTED &&
+ state->pending_response_.get() &&
+ net::HttpResponseHeaders::IsRedirectResponseCode(
+ state->pending_response_->GetStatus());
+
+ if (state->handler_ && !ignore_result) {
+ DCHECK(state->pending_request_);
+
+ CallHandlerOnComplete(state, status);
+
+ if (status.error_code != 0 && status.error_code != ERR_ABORTED &&
+ is_external) {
+ bool allow_os_execution = false;
+ state->handler_->OnProtocolExecution(
+ init_state_->browser_, init_state_->frame_,
+ state->pending_request_.get(), allow_os_execution);
+ if (allow_os_execution && init_state_->unhandled_request_callback_) {
+ init_state_->unhandled_request_callback_.Run();
+ }
+ }
+ }
+
+ RemoveState(request_id);
+ }
+
+ private:
+ void CallHandlerOnComplete(RequestState* state,
+ const network::URLLoaderCompletionStatus& status) {
+ if (!state->handler_ || !state->pending_request_) {
+ return;
+ }
+
+ // The request object may be currently flagged as writable in cases where we
+ // abort a request that is waiting on a pending callack.
+ if (!state->pending_request_->IsReadOnly()) {
+ state->pending_request_->SetReadOnly(true);
+ }
+
+ if (!state->pending_response_) {
+ // If the request failed there may not be a response object yet.
+ state->pending_response_ = new CefResponseImpl();
+ } else {
+ state->pending_response_->SetReadOnly(false);
+ }
+ state->pending_response_->SetError(
+ static_cast<cef_errorcode_t>(status.error_code));
+ state->pending_response_->SetReadOnly(true);
+
+ state->handler_->OnResourceLoadComplete(
+ init_state_->browser_, init_state_->frame_,
+ state->pending_request_.get(), state->pending_response_.get(),
+ status.error_code == 0 ? UR_SUCCESS : UR_FAILED,
+ status.encoded_body_length);
+ }
+
+ // Returns the handler, if any, that should be used for this request.
+ CefRefPtr<CefResourceRequestHandler> GetHandler(
+ int32_t request_id,
+ network::ResourceRequest* request,
+ bool* intercept_only,
+ CefRefPtr<CefRequestImpl>& requestPtr) const {
+ CefRefPtr<CefResourceRequestHandler> handler;
+
+ if (init_state_->browser_) {
+ // Maybe the browser's client wants to handle it?
+ CefRefPtr<CefClient> client =
+ init_state_->browser_->GetHost()->GetClient();
+ if (client) {
+ CefRefPtr<CefRequestHandler> request_handler =
+ client->GetRequestHandler();
+ if (request_handler) {
+ requestPtr = MakeRequest(request, request_id, true);
+
+ handler = request_handler->GetResourceRequestHandler(
+ init_state_->browser_, init_state_->frame_, requestPtr.get(),
+ init_state_->is_navigation_, init_state_->is_download_,
+ init_state_->request_initiator_, *intercept_only);
+ }
+ }
+ }
+
+ if (!handler) {
+ // Maybe the request context wants to handle it?
+ CefRefPtr<CefRequestContextHandler> context_handler =
+ init_state_->iothread_state_->GetHandler(
+ init_state_->global_id_, /*require_frame_match=*/false);
+ if (context_handler) {
+ if (!requestPtr) {
+ requestPtr = MakeRequest(request, request_id, true);
+ }
+
+ handler = context_handler->GetResourceRequestHandler(
+ init_state_->browser_, init_state_->frame_, requestPtr.get(),
+ init_state_->is_navigation_, init_state_->is_download_,
+ init_state_->request_initiator_, *intercept_only);
+ }
+ }
+
+ return handler;
+ }
+
+ RequestState* GetOrCreateState(int32_t request_id) {
+ RequestState* state = GetState(request_id);
+ if (!state) {
+ state = new RequestState();
+ request_map_.insert(std::make_pair(request_id, base::WrapUnique(state)));
+ }
+ return state;
+ }
+
+ RequestState* GetState(int32_t request_id) const {
+ RequestMap::const_iterator it = request_map_.find(request_id);
+ if (it != request_map_.end()) {
+ return it->second.get();
+ }
+ return nullptr;
+ }
+
+ void RemoveState(int32_t request_id) {
+ RequestMap::iterator it = request_map_.find(request_id);
+ DCHECK(it != request_map_.end());
+ if (it != request_map_.end()) {
+ request_map_.erase(it);
+ }
+ }
+
+ // Stop accepting new requests and cancel pending/in-flight requests when the
+ // CEF context or associated browser is destroyed.
+ void OnDestroyed() {
+ CEF_REQUIRE_IOT();
+ DCHECK(init_state_);
+
+ init_state_->DeleteDestructionObserver();
+
+ // Stop accepting new requests.
+ shutting_down_ = true;
+
+ // Stop the delivery of pending callbacks.
+ weak_ptr_factory_.InvalidateWeakPtrs();
+
+ // Take ownership of any pending requests.
+ PendingRequests pending_requests;
+ pending_requests.swap(pending_requests_);
+
+ // Take ownership of any in-progress requests.
+ RequestMap request_map;
+ request_map.swap(request_map_);
+
+ // Notify handlers for in-progress requests.
+ for (const auto& pair : request_map) {
+ CallHandlerOnComplete(
+ pair.second.get(),
+ network::URLLoaderCompletionStatus(net::ERR_ABORTED));
+ }
+
+ if (init_state_->browser_) {
+ // Clear objects that reference the browser.
+ init_state_->browser_ = nullptr;
+ init_state_->frame_ = nullptr;
+ }
+
+ // Execute cancel callbacks and delete pending and in-progress requests.
+ // This may result in the request being torn down sooner, or it may be
+ // ignored if the request is already in the process of being torn down. When
+ // the last callback is executed it may result in |this| being deleted.
+ pending_requests.clear();
+
+ for (auto& pair : request_map) {
+ auto state = std::move(pair.second);
+ if (state->cancel_callback_) {
+ std::move(state->cancel_callback_).Run(net::ERR_ABORTED);
+ }
+ }
+ }
+
+ static CefRefPtr<CefRequestImpl> MakeRequest(
+ const network::ResourceRequest* request,
+ int64 request_id,
+ bool read_only) {
+ CefRefPtr<CefRequestImpl> requestPtr = new CefRequestImpl();
+ requestPtr->Set(request, request_id);
+ if (read_only) {
+ requestPtr->SetReadOnly(true);
+ } else {
+ requestPtr->SetTrackChanges(true);
+ }
+ return requestPtr;
+ }
+
+ // Returns true if |request| cannot be handled internally.
+ static bool IsExternalRequest(const network::ResourceRequest* request) {
+ return !scheme::IsInternalHandledScheme(request->url.scheme());
+ }
+
+ scoped_refptr<InitHelper> init_helper_;
+ std::unique_ptr<InitState> init_state_;
+
+ bool shutting_down_ = false;
+
+ using RequestMap = std::map<int32_t, std::unique_ptr<RequestState>>;
+ RequestMap request_map_;
+
+ using PendingRequests = std::vector<std::unique_ptr<PendingRequest>>;
+ PendingRequests pending_requests_;
+
+ base::WeakPtrFactory<InterceptedRequestHandlerWrapper> weak_ptr_factory_;
+};
+
+} // namespace
+
+std::unique_ptr<InterceptedRequestHandler> CreateInterceptedRequestHandler(
+ content::BrowserContext* browser_context,
+ content::RenderFrameHost* frame,
+ int render_process_id,
+ bool is_navigation,
+ bool is_download,
+ const url::Origin& request_initiator) {
+ CEF_REQUIRE_UIT();
+ CHECK(browser_context);
+
+ CefRefPtr<CefBrowserHostBase> browserPtr;
+ CefRefPtr<CefFrame> framePtr;
+
+ // Default to handlers for the same process in case |frame| doesn't have an
+ // associated CefBrowserHost.
+ content::GlobalRenderFrameHostId global_id(render_process_id,
+ MSG_ROUTING_NONE);
+
+ // |frame| may be nullptr for service worker requests.
+ if (frame) {
+ // May return nullptr for requests originating from guest views.
+ browserPtr = CefBrowserHostBase::GetBrowserForHost(frame);
+ if (browserPtr) {
+ framePtr = browserPtr->GetFrameForHost(frame);
+ CHECK(framePtr);
+ global_id = frame->GetGlobalId();
+ }
+ }
+
+ auto init_state =
+ std::make_unique<InterceptedRequestHandlerWrapper::InitState>();
+ init_state->Initialize(browser_context, browserPtr, framePtr, global_id,
+ is_navigation, is_download, request_initiator,
+ base::RepeatingClosure());
+
+ auto wrapper = std::make_unique<InterceptedRequestHandlerWrapper>();
+ wrapper->init_helper()->MaybeSetInitialized(std::move(init_state));
+
+ return wrapper;
+}
+
+std::unique_ptr<InterceptedRequestHandler> CreateInterceptedRequestHandler(
+ content::WebContents::Getter web_contents_getter,
+ int frame_tree_node_id,
+ const network::ResourceRequest& request,
+ const base::RepeatingClosure& unhandled_request_callback) {
+ CEF_REQUIRE_UIT();
+
+ content::WebContents* web_contents = web_contents_getter.Run();
+ CHECK(web_contents);
+
+ content::BrowserContext* browser_context = web_contents->GetBrowserContext();
+ CHECK(browser_context);
+
+ content::RenderFrameHost* frame = nullptr;
+
+ if (request.is_outermost_main_frame ||
+ static_cast<blink::mojom::ResourceType>(request.resource_type) ==
+ blink::mojom::ResourceType::kMainFrame) {
+ frame = web_contents->GetPrimaryMainFrame();
+ CHECK(frame);
+ } else {
+ // May return nullptr for frames in inner WebContents.
+ auto node = content::FrameTreeNode::GloballyFindByID(frame_tree_node_id);
+ if (node) {
+ frame = node->current_frame_host();
+
+ // RFHs can move between FrameTreeNodes. Make sure this one hasn't. See
+ // documentation on RenderFrameHost::GetFrameTreeNodeId() for background.
+ if (content::WebContents::FromRenderFrameHost(frame) != web_contents) {
+ frame = nullptr;
+ }
+ }
+
+ if (!frame) {
+ // Use the main frame for the CefBrowserHost.
+ frame = web_contents->GetPrimaryMainFrame();
+ CHECK(frame);
+ }
+ }
+
+ CefRefPtr<CefBrowserHostBase> browserPtr;
+ CefRefPtr<CefFrame> framePtr;
+
+ // Default to handlers for the same process in case |frame| doesn't have an
+ // associated CefBrowserHost.
+ content::GlobalRenderFrameHostId global_id(frame->GetProcess()->GetID(),
+ MSG_ROUTING_NONE);
+
+ // May return nullptr for requests originating from guest views.
+ browserPtr = CefBrowserHostBase::GetBrowserForHost(frame);
+ if (browserPtr) {
+ framePtr = browserPtr->GetFrameForHost(frame);
+ DCHECK(framePtr);
+ global_id = frame->GetGlobalId();
+ }
+
+ const bool is_navigation = ui::PageTransitionIsNewNavigation(
+ static_cast<ui::PageTransition>(request.transition_type));
+ // TODO(navigation): Can we determine the |is_download| value?
+ const bool is_download = false;
+ url::Origin request_initiator;
+ if (request.request_initiator.has_value()) {
+ request_initiator = *request.request_initiator;
+ }
+
+ auto init_state =
+ std::make_unique<InterceptedRequestHandlerWrapper::InitState>();
+ init_state->Initialize(browser_context, browserPtr, framePtr, global_id,
+ is_navigation, is_download, request_initiator,
+ unhandled_request_callback);
+
+ auto wrapper = std::make_unique<InterceptedRequestHandlerWrapper>();
+ wrapper->init_helper()->MaybeSetInitialized(std::move(init_state));
+
+ return wrapper;
+}
+
+} // namespace net_service
diff --git a/libcef/browser/net_service/resource_request_handler_wrapper.h b/libcef/browser/net_service/resource_request_handler_wrapper.h
new file mode 100644
index 00000000..6052a767
--- /dev/null
+++ b/libcef/browser/net_service/resource_request_handler_wrapper.h
@@ -0,0 +1,50 @@
+// Copyright (c) 2019 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_NET_SERVICE_RESOURCE_REQUEST_HANDLER_WRAPPER_H_
+#define CEF_LIBCEF_BROWSER_NET_SERVICE_RESOURCE_REQUEST_HANDLER_WRAPPER_H_
+
+#include "base/functional/callback_forward.h"
+#include "content/public/browser/web_contents.h"
+
+namespace content {
+class BrowserContext;
+class RenderFrameHost;
+} // namespace content
+
+namespace network {
+struct ResourceRequest;
+}
+
+namespace url {
+class Origin;
+}
+
+namespace net_service {
+
+class InterceptedRequestHandler;
+
+// Create an InterceptedRequestHandler that will delegate to a
+// CefResourceRequestHandler. The resulting object should be passed to
+// ProxyURLLoaderFactory::CreateProxy. Called on the UI thread only.
+std::unique_ptr<InterceptedRequestHandler> CreateInterceptedRequestHandler(
+ content::BrowserContext* browser_context,
+ content::RenderFrameHost* frame,
+ int render_process_id,
+ bool is_navigation,
+ bool is_download,
+ const url::Origin& request_initiator);
+
+// Create an InterceptedRequestHandler that will delegate to a
+// CefResourceRequestHandler. The resulting object should be passed to
+// ProxyURLLoaderFactory::CreateProxy. Called on the UI thread only.
+std::unique_ptr<InterceptedRequestHandler> CreateInterceptedRequestHandler(
+ content::WebContents::Getter web_contents_getter,
+ int frame_tree_node_id,
+ const network::ResourceRequest& request,
+ const base::RepeatingClosure& unhandled_request_callback);
+
+} // namespace net_service
+
+#endif // CEF_LIBCEF_BROWSER_NET_SERVICE_RESOURCE_REQUEST_HANDLER_WRAPPER_H_
diff --git a/libcef/browser/net_service/response_filter_wrapper.cc b/libcef/browser/net_service/response_filter_wrapper.cc
new file mode 100644
index 00000000..bc185a1b
--- /dev/null
+++ b/libcef/browser/net_service/response_filter_wrapper.cc
@@ -0,0 +1,302 @@
+// Copyright (c) 2019 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "libcef/browser/net_service/response_filter_wrapper.h"
+
+#include <queue>
+
+#include "base/logging.h"
+#include "mojo/public/cpp/system/simple_watcher.h"
+#include "mojo/public/cpp/system/string_data_source.h"
+
+namespace net_service {
+
+namespace {
+
+// Match the default |capacity_num_bytes| value from mojo::Core::CreateDataPipe.
+static const size_t kBufferSize = 64 * 1024; // 64 Kbytes.
+static const size_t kMinBufferSpace = 1024; // 1 Kbytes.
+
+class ResponseFilterWrapper {
+ public:
+ ResponseFilterWrapper(CefRefPtr<CefResponseFilter> filter,
+ mojo::ScopedDataPipeConsumerHandle source_handle,
+ base::OnceClosure error_callback);
+
+ ResponseFilterWrapper(const ResponseFilterWrapper&) = delete;
+ ResponseFilterWrapper& operator=(const ResponseFilterWrapper&) = delete;
+
+ // Creates and returns the output handle, or |source_handle| on failure.
+ bool CreateOutputHandle(mojo::ScopedDataPipeConsumerHandle* output_handle);
+
+ private:
+ void OnSourceReadable(MojoResult, const mojo::HandleSignalsState&);
+ void Filter(const char* data, size_t size);
+ void Write(std::unique_ptr<std::string> data);
+ void OnWriteComplete(std::unique_ptr<std::string>, MojoResult result);
+ void Drain(bool complete);
+ void MaybeSuccess();
+ void Cleanup(bool success);
+
+ CefRefPtr<CefResponseFilter> filter_;
+ mojo::ScopedDataPipeConsumerHandle source_handle_;
+ base::OnceClosure error_callback_;
+
+ std::unique_ptr<mojo::DataPipeProducer> forwarder_;
+ mojo::SimpleWatcher source_watcher_;
+
+ bool read_pending_ = false;
+ bool write_pending_ = false;
+ std::queue<std::unique_ptr<std::string>> pending_data_;
+ cef_response_filter_status_t last_status_ = RESPONSE_FILTER_NEED_MORE_DATA;
+};
+
+ResponseFilterWrapper::ResponseFilterWrapper(
+ CefRefPtr<CefResponseFilter> filter,
+ mojo::ScopedDataPipeConsumerHandle source_handle,
+ base::OnceClosure error_callback)
+ : filter_(filter),
+ source_handle_(std::move(source_handle)),
+ error_callback_(std::move(error_callback)),
+ source_watcher_(FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::MANUAL) {}
+
+bool ResponseFilterWrapper::CreateOutputHandle(
+ mojo::ScopedDataPipeConsumerHandle* output_handle) {
+ if (!filter_->InitFilter()) {
+ *output_handle = std::move(source_handle_);
+ return false;
+ }
+
+ mojo::ScopedDataPipeProducerHandle forwarding_handle;
+ if (CreateDataPipe(nullptr, forwarding_handle, *output_handle) !=
+ MOJO_RESULT_OK) {
+ *output_handle = std::move(source_handle_);
+ return false;
+ }
+
+ forwarder_ =
+ std::make_unique<mojo::DataPipeProducer>(std::move(forwarding_handle));
+
+ source_watcher_.Watch(
+ source_handle_.get(),
+ MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
+ base::BindRepeating(&ResponseFilterWrapper::OnSourceReadable,
+ base::Unretained(this)));
+ source_watcher_.ArmOrNotify();
+ read_pending_ = true;
+
+ return true;
+}
+
+void ResponseFilterWrapper::OnSourceReadable(MojoResult,
+ const mojo::HandleSignalsState&) {
+ const void* buffer = nullptr;
+ uint32_t read_bytes = 0;
+ MojoResult result = source_handle_->BeginReadData(&buffer, &read_bytes,
+ MOJO_READ_DATA_FLAG_NONE);
+ if (result == MOJO_RESULT_SHOULD_WAIT) {
+ source_watcher_.ArmOrNotify();
+ return;
+ }
+
+ if (result != MOJO_RESULT_OK) {
+ // Whole body has been read, or something went wrong.
+ Drain(result == MOJO_RESULT_FAILED_PRECONDITION);
+ return;
+ }
+
+ Filter(static_cast<const char*>(buffer), read_bytes);
+ if (last_status_ == RESPONSE_FILTER_ERROR) {
+ // Something went wrong.
+ Drain(false);
+ return;
+ }
+
+ source_handle_->EndReadData(read_bytes);
+ source_watcher_.ArmOrNotify();
+}
+
+void ResponseFilterWrapper::Filter(const char* data, size_t size) {
+ size_t data_in_size = size;
+ auto data_in_ptr = data_in_size > 0 ? data : nullptr;
+
+ size_t data_out_offset = 0;
+ std::unique_ptr<std::string> data_out;
+
+ while (true) {
+ size_t data_in_read = 0;
+
+ if (!data_out) {
+ // Start a new buffer. Should have no offset to begin with.
+ DCHECK_EQ(0U, data_out_offset);
+ data_out = std::make_unique<std::string>();
+ data_out->resize(kBufferSize);
+ }
+
+ auto data_out_ptr = data_out->data() + data_out_offset;
+ size_t data_out_size = kBufferSize - data_out_offset;
+ size_t data_out_written = 0;
+
+ last_status_ = filter_->Filter(
+ const_cast<char*>(data_in_ptr), data_in_size, data_in_read,
+ const_cast<char*>(data_out_ptr), data_out_size, data_out_written);
+ if (last_status_ == RESPONSE_FILTER_ERROR) {
+ break;
+ }
+
+ // Validate the out values.
+ if (data_in_read > data_in_size) {
+ LOG(ERROR) << "potential buffer overflow; data_in_read > data_in_size";
+ last_status_ = RESPONSE_FILTER_ERROR;
+ break;
+ }
+ if (data_out_written > data_out_size) {
+ LOG(ERROR)
+ << "potential buffer overflow; data_out_written > data_out_size";
+ last_status_ = RESPONSE_FILTER_ERROR;
+ break;
+ }
+ if (data_out_written == 0 && data_in_read != data_in_size) {
+ LOG(ERROR) << "when no data is written all input must be consumed; "
+ "data_out_written == 0 && data_in_read != data_in_size";
+ last_status_ = RESPONSE_FILTER_ERROR;
+ break;
+ }
+
+ if (data_out_written > 0) {
+ data_out_offset += data_out_written;
+ if (data_out_offset > kBufferSize - kMinBufferSpace) {
+ // The buffer is full or almost full. Write the data that we've
+ // received so far and start a new buffer.
+ data_out->resize(data_out_offset);
+ Write(std::move(data_out));
+ data_out_offset = 0;
+ }
+ }
+
+ if (data_in_read < data_in_size) {
+ // Keep going until the user reads all data.
+ data_in_ptr += data_in_read;
+ data_in_size -= data_in_read;
+ continue;
+ }
+
+ // At this point the user has read all data...
+ if (data_in_ptr) {
+ // Clear the input buffer.
+ data_in_read = data_in_size = 0;
+ data_in_ptr = nullptr;
+ }
+
+ if (data_out_written == data_out_size &&
+ last_status_ == RESPONSE_FILTER_NEED_MORE_DATA) {
+ // Output buffer was filled, but data is still pending.
+ continue;
+ }
+
+ if (data_out_offset > 0) {
+ // Write the last of the data that we've received.
+ data_out->resize(data_out_offset);
+ Write(std::move(data_out));
+ }
+
+ break;
+ }
+}
+
+void ResponseFilterWrapper::Write(std::unique_ptr<std::string> data) {
+ if (write_pending_) {
+ // Only one write at a time is supported.
+ pending_data_.push(std::move(data));
+ return;
+ }
+
+ write_pending_ = true;
+
+ base::StringPiece string_piece(*data);
+ forwarder_->Write(std::make_unique<mojo::StringDataSource>(
+ string_piece, mojo::StringDataSource::AsyncWritingMode::
+ STRING_STAYS_VALID_UNTIL_COMPLETION),
+ base::BindOnce(&ResponseFilterWrapper::OnWriteComplete,
+ base::Unretained(this), std::move(data)));
+}
+
+void ResponseFilterWrapper::OnWriteComplete(std::unique_ptr<std::string>,
+ MojoResult result) {
+ write_pending_ = false;
+
+ if (result != MOJO_RESULT_OK) {
+ // Something went wrong.
+ Cleanup(false);
+ return;
+ }
+
+ MaybeSuccess();
+}
+
+void ResponseFilterWrapper::Drain(bool complete) {
+ read_pending_ = false;
+ source_handle_.reset();
+ source_watcher_.Cancel();
+
+ if (!complete) {
+ // Something went wrong.
+ Cleanup(false);
+ return;
+ }
+
+ if (last_status_ == RESPONSE_FILTER_NEED_MORE_DATA) {
+ // Let the user write any remaining data.
+ Filter(nullptr, 0);
+ if (last_status_ != RESPONSE_FILTER_DONE) {
+ // Something went wrong.
+ Cleanup(false);
+ return;
+ }
+ }
+
+ MaybeSuccess();
+}
+
+void ResponseFilterWrapper::MaybeSuccess() {
+ if (!write_pending_ && !pending_data_.empty()) {
+ // Write the next data segment.
+ auto next = std::move(pending_data_.front());
+ pending_data_.pop();
+ Write(std::move(next));
+ return;
+ }
+
+ if (!read_pending_ && !write_pending_) {
+ Cleanup(true);
+ }
+}
+
+void ResponseFilterWrapper::Cleanup(bool success) {
+ if (!success && error_callback_) {
+ std::move(error_callback_).Run();
+ }
+ delete this;
+}
+
+} // namespace
+
+mojo::ScopedDataPipeConsumerHandle CreateResponseFilterHandler(
+ CefRefPtr<CefResponseFilter> filter,
+ mojo::ScopedDataPipeConsumerHandle source_handle,
+ base::OnceClosure error_callback) {
+ // |filter_wrapper| will delete itself when filtering is complete if
+ // CreateOutputHandle returns true. Otherwise, it will return the
+ // original |source_handle|.
+ auto filter_wrapper = new ResponseFilterWrapper(
+ filter, std::move(source_handle), std::move(error_callback));
+ mojo::ScopedDataPipeConsumerHandle output_handle;
+ if (!filter_wrapper->CreateOutputHandle(&output_handle)) {
+ delete filter_wrapper;
+ }
+ return output_handle;
+}
+
+} // namespace net_service
diff --git a/libcef/browser/net_service/response_filter_wrapper.h b/libcef/browser/net_service/response_filter_wrapper.h
new file mode 100644
index 00000000..a85d0959
--- /dev/null
+++ b/libcef/browser/net_service/response_filter_wrapper.h
@@ -0,0 +1,27 @@
+// Copyright (c) 2019 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_NET_SERVICE_RESPONSE_FILTER_WRAPPER_H_
+#define CEF_LIBCEF_BROWSER_NET_SERVICE_RESPONSE_FILTER_WRAPPER_H_
+
+#include "include/cef_response_filter.h"
+
+#include "base/functional/callback_forward.h"
+#include "mojo/public/cpp/system/data_pipe.h"
+
+namespace net_service {
+
+// Create a filter handler that will read from |source_handle| and pass the data
+// through |filter|. If filtering cannot be initialized then |source_handle|
+// will be returned, otherwise a new handle for retrieving the filtered output
+// will be returned. If filtering fails after initialization then
+// |error_callback| will be executed.
+mojo::ScopedDataPipeConsumerHandle CreateResponseFilterHandler(
+ CefRefPtr<CefResponseFilter> filter,
+ mojo::ScopedDataPipeConsumerHandle source_handle,
+ base::OnceClosure error_callback);
+
+} // namespace net_service
+
+#endif // CEF_LIBCEF_BROWSER_NET_SERVICE_RESPONSE_FILTER_WRAPPER_H_
diff --git a/libcef/browser/net_service/stream_reader_url_loader.cc b/libcef/browser/net_service/stream_reader_url_loader.cc
new file mode 100644
index 00000000..71168336
--- /dev/null
+++ b/libcef/browser/net_service/stream_reader_url_loader.cc
@@ -0,0 +1,855 @@
+// Copyright (c) 2019 The Chromium Embedded Framework Authors. Portions
+// Copyright (c) 2018 The Chromium Authors. All rights reserved. Use of this
+// source code is governed by a BSD-style license that can be found in the
+// LICENSE file.
+
+#include "libcef/browser/net_service/stream_reader_url_loader.h"
+
+#include "libcef/browser/thread_util.h"
+#include "libcef/common/net_service/net_service_util.h"
+
+#include "base/functional/bind.h"
+#include "base/functional/callback.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/task/single_thread_task_runner.h"
+#include "base/task/thread_pool.h"
+#include "base/threading/thread.h"
+#include "content/public/browser/browser_thread.h"
+#include "net/base/io_buffer.h"
+#include "net/http/http_status_code.h"
+#include "net/http/http_util.h"
+#include "services/network/public/cpp/url_loader_completion_status.h"
+
+namespace net_service {
+
+namespace {
+
+using OnInputStreamOpenedCallback =
+ base::OnceCallback<void(std::unique_ptr<StreamReaderURLLoader::Delegate>,
+ std::unique_ptr<InputStream>)>;
+
+// Helper for executing the OnInputStreamOpenedCallback.
+class OpenInputStreamWrapper
+ : public base::RefCountedThreadSafe<OpenInputStreamWrapper> {
+ public:
+ OpenInputStreamWrapper(const OpenInputStreamWrapper&) = delete;
+ OpenInputStreamWrapper& operator=(const OpenInputStreamWrapper&) = delete;
+
+ [[nodiscard]] static base::OnceClosure Open(
+ std::unique_ptr<StreamReaderURLLoader::Delegate> delegate,
+ scoped_refptr<base::SequencedTaskRunner> work_thread_task_runner,
+ int32_t request_id,
+ const network::ResourceRequest& request,
+ OnInputStreamOpenedCallback callback) {
+ scoped_refptr<OpenInputStreamWrapper> wrapper = new OpenInputStreamWrapper(
+ std::move(delegate), work_thread_task_runner,
+ base::SingleThreadTaskRunner::GetCurrentDefault(), std::move(callback));
+ wrapper->Start(request_id, request);
+
+ return wrapper->GetCancelCallback();
+ }
+
+ private:
+ friend class base::RefCountedThreadSafe<OpenInputStreamWrapper>;
+
+ OpenInputStreamWrapper(
+ std::unique_ptr<StreamReaderURLLoader::Delegate> delegate,
+ scoped_refptr<base::SequencedTaskRunner> work_thread_task_runner,
+ scoped_refptr<base::SingleThreadTaskRunner> job_thread_task_runner,
+ OnInputStreamOpenedCallback callback)
+ : delegate_(std::move(delegate)),
+ work_thread_task_runner_(work_thread_task_runner),
+ job_thread_task_runner_(job_thread_task_runner),
+ callback_(std::move(callback)) {}
+ virtual ~OpenInputStreamWrapper() = default;
+
+ void Start(int32_t request_id, const network::ResourceRequest& request) {
+ work_thread_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(&OpenInputStreamWrapper::OpenOnWorkThread,
+ base::WrapRefCounted(this), request_id, request));
+ }
+
+ base::OnceClosure GetCancelCallback() {
+ return base::BindOnce(&OpenInputStreamWrapper::CancelOnJobThread,
+ base::WrapRefCounted(this));
+ }
+
+ void CancelOnJobThread() {
+ DCHECK(job_thread_task_runner_->RunsTasksInCurrentSequence());
+ if (callback_.is_null()) {
+ return;
+ }
+
+ callback_.Reset();
+
+ work_thread_task_runner_->PostTask(
+ FROM_HERE, base::BindOnce(&OpenInputStreamWrapper::CancelOnWorkThread,
+ base::WrapRefCounted(this)));
+ }
+
+ void CancelOnWorkThread() {
+ DCHECK(work_thread_task_runner_->RunsTasksInCurrentSequence());
+ if (is_canceled_) {
+ return;
+ }
+ is_canceled_ = true;
+ OnCallback(nullptr);
+ }
+
+ void OpenOnWorkThread(int32_t request_id,
+ const network::ResourceRequest& request) {
+ DCHECK(work_thread_task_runner_->RunsTasksInCurrentSequence());
+ if (is_canceled_) {
+ return;
+ }
+
+ // |delegate_| will remain valid until OnCallback() is executed on
+ // |job_thread_task_runner_|.
+ if (!delegate_->OpenInputStream(
+ request_id, request,
+ base::BindOnce(&OpenInputStreamWrapper::OnCallback,
+ base::WrapRefCounted(this)))) {
+ is_canceled_ = true;
+ OnCallback(nullptr);
+ }
+ }
+
+ void OnCallback(std::unique_ptr<InputStream> input_stream) {
+ if (!job_thread_task_runner_->RunsTasksInCurrentSequence()) {
+ job_thread_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(&OpenInputStreamWrapper::OnCallback,
+ base::WrapRefCounted(this), std::move(input_stream)));
+ return;
+ }
+
+ // May be null if CancelOnJobThread() was called on
+ // |job_thread_task_runner_| while OpenOnWorkThread() was pending on
+ // |work_thread_task_runner_|.
+ if (callback_.is_null()) {
+ delegate_.reset();
+ return;
+ }
+
+ std::move(callback_).Run(std::move(delegate_), std::move(input_stream));
+ }
+
+ std::unique_ptr<StreamReaderURLLoader::Delegate> delegate_;
+
+ scoped_refptr<base::SequencedTaskRunner> work_thread_task_runner_;
+ scoped_refptr<base::SingleThreadTaskRunner> job_thread_task_runner_;
+
+ // Only accessed on |job_thread_task_runner_|.
+ OnInputStreamOpenedCallback callback_;
+
+ // Only accessed on |work_thread_task_runner_|.
+ bool is_canceled_ = false;
+};
+
+} // namespace
+
+//==============================
+// InputStreamReader
+//=============================
+
+// Class responsible for reading from the InputStream.
+class InputStreamReader : public base::RefCountedThreadSafe<InputStreamReader> {
+ public:
+ // The constructor is called on the IO thread, not on the worker thread.
+ // Callbacks will be executed on the IO thread.
+ InputStreamReader(
+ std::unique_ptr<InputStream> stream,
+ scoped_refptr<base::SequencedTaskRunner> work_thread_task_runner);
+
+ InputStreamReader(const InputStreamReader&) = delete;
+ InputStreamReader& operator=(const InputStreamReader&) = delete;
+
+ // Skip |skip_bytes| number of bytes from |stream_|. |callback| will be
+ // executed asynchronously on the IO thread. A negative value passed to
+ // |callback| will indicate an error code, a positive value will indicate the
+ // number of bytes skipped.
+ void Skip(int64_t skip_bytes, InputStream::SkipCallback callback);
+
+ // Read up to |dest_size| bytes from |stream_| into |dest|. |callback| will be
+ // executed asynchronously on the IO thread. A negative value passed to
+ // |callback| will indicate an error code, a positive value will indicate the
+ // number of bytes read.
+ void Read(scoped_refptr<net::IOBuffer> dest,
+ int dest_size,
+ InputStream::ReadCallback callback);
+
+ private:
+ friend class base::RefCountedThreadSafe<InputStreamReader>;
+ virtual ~InputStreamReader();
+
+ void SkipOnWorkThread(int64_t skip_bytes, InputStream::SkipCallback callback);
+ void ReadOnWorkThread(scoped_refptr<net::IOBuffer> buffer,
+ int buffer_size,
+ InputStream::ReadCallback callback);
+
+ void SkipToRequestedRange();
+
+ static void ContinueSkipCallback(
+ scoped_refptr<InputStreamReader> stream,
+ scoped_refptr<base::SequencedTaskRunner> work_thread_task_runner,
+ int callback_id,
+ int64_t bytes_skipped);
+ static void ContinueReadCallback(
+ scoped_refptr<InputStreamReader> stream,
+ scoped_refptr<base::SequencedTaskRunner> work_thread_task_runner,
+ int callback_id,
+ int bytes_read);
+
+ void ContinueSkipCallbackOnWorkThread(int callback_id, int64_t bytes_skipped);
+ void ContinueReadCallbackOnWorkThread(int callback_id, int bytes_read);
+
+ void RunSkipCallback(int64_t bytes_skipped);
+ void RunReadCallback(int bytes_read);
+
+ static void RunSkipCallbackOnJobThread(
+ int64_t bytes_skipped,
+ InputStream::SkipCallback skip_callback);
+ static void RunReadCallbackOnJobThread(
+ int bytes_read,
+ InputStream::ReadCallback read_callback);
+
+ std::unique_ptr<InputStream> stream_;
+
+ // All InputStream methods are called this task runner.
+ scoped_refptr<base::SequencedTaskRunner> work_thread_task_runner_;
+
+ // All callbacks are executed on this task runner.
+ scoped_refptr<base::SingleThreadTaskRunner> job_thread_task_runner_;
+
+ // The below members are only accessed on the work thread.
+ int64_t bytes_skipped_;
+ int64_t bytes_to_skip_;
+ InputStream::SkipCallback pending_skip_callback_;
+
+ scoped_refptr<net::IOBuffer> buffer_;
+ InputStream::ReadCallback pending_read_callback_;
+
+ int pending_callback_id_ = -1;
+
+ int next_callback_id_ = 0;
+};
+
+InputStreamReader::InputStreamReader(
+ std::unique_ptr<InputStream> stream,
+ scoped_refptr<base::SequencedTaskRunner> work_thread_task_runner)
+ : stream_(std::move(stream)),
+ work_thread_task_runner_(work_thread_task_runner),
+ job_thread_task_runner_(
+ base::SingleThreadTaskRunner::GetCurrentDefault()) {
+ CEF_REQUIRE_IOT();
+ DCHECK(stream_);
+ DCHECK(work_thread_task_runner_);
+}
+
+InputStreamReader::~InputStreamReader() {}
+
+void InputStreamReader::Skip(int64_t skip_bytes,
+ InputStream::SkipCallback callback) {
+ work_thread_task_runner_->PostTask(
+ FROM_HERE, base::BindOnce(&InputStreamReader::SkipOnWorkThread,
+ base::WrapRefCounted(this), skip_bytes,
+ std::move(callback)));
+}
+
+void InputStreamReader::Read(scoped_refptr<net::IOBuffer> dest,
+ int dest_size,
+ InputStream::ReadCallback callback) {
+ work_thread_task_runner_->PostTask(
+ FROM_HERE, base::BindOnce(&InputStreamReader::ReadOnWorkThread,
+ base::WrapRefCounted(this), dest, dest_size,
+ std::move(callback)));
+}
+
+void InputStreamReader::SkipOnWorkThread(int64_t skip_bytes,
+ InputStream::SkipCallback callback) {
+ DCHECK(work_thread_task_runner_->RunsTasksInCurrentSequence());
+
+ // No callback should currently be pending.
+ DCHECK_EQ(pending_callback_id_, -1);
+ DCHECK(pending_skip_callback_.is_null());
+
+ pending_skip_callback_ = std::move(callback);
+
+ if (skip_bytes <= 0) {
+ RunSkipCallback(0);
+ return;
+ }
+
+ bytes_skipped_ = bytes_to_skip_ = skip_bytes;
+ SkipToRequestedRange();
+}
+
+void InputStreamReader::ReadOnWorkThread(scoped_refptr<net::IOBuffer> dest,
+ int dest_size,
+ InputStream::ReadCallback callback) {
+ DCHECK(work_thread_task_runner_->RunsTasksInCurrentSequence());
+
+ // No callback should currently be pending.
+ DCHECK_EQ(pending_callback_id_, -1);
+ DCHECK(pending_read_callback_.is_null());
+
+ pending_read_callback_ = std::move(callback);
+
+ if (!dest_size) {
+ RunReadCallback(0);
+ return;
+ }
+
+ DCHECK_GT(dest_size, 0);
+
+ buffer_ = dest;
+ pending_callback_id_ = ++next_callback_id_;
+
+ int bytes_read = 0;
+ bool result = stream_->Read(
+ buffer_.get(), dest_size, &bytes_read,
+ base::BindOnce(&InputStreamReader::ContinueReadCallback,
+ base::WrapRefCounted(this), work_thread_task_runner_,
+ pending_callback_id_));
+
+ // Check if the callback will execute asynchronously.
+ if (result && bytes_read == 0) {
+ return;
+ }
+
+ RunReadCallback(result || bytes_read <= 0 ? bytes_read : net::ERR_FAILED);
+}
+
+void InputStreamReader::SkipToRequestedRange() {
+ DCHECK(work_thread_task_runner_->RunsTasksInCurrentSequence());
+
+ // Skip to the start of the requested data. This has to be done in a loop
+ // because the underlying InputStream is not guaranteed to skip the requested
+ // number of bytes.
+ do {
+ pending_callback_id_ = ++next_callback_id_;
+
+ int64_t skipped = 0;
+ bool result = stream_->Skip(
+ bytes_to_skip_, &skipped,
+ base::BindOnce(&InputStreamReader::ContinueSkipCallback,
+ base::WrapRefCounted(this), work_thread_task_runner_,
+ pending_callback_id_));
+
+ // Check if the callback will execute asynchronously.
+ if (result && skipped == 0) {
+ return;
+ }
+
+ if (!result || skipped <= 0) {
+ RunSkipCallback(net::ERR_REQUEST_RANGE_NOT_SATISFIABLE);
+ return;
+ }
+ DCHECK_LE(skipped, bytes_to_skip_);
+
+ bytes_to_skip_ -= skipped;
+ } while (bytes_to_skip_ > 0);
+
+ // All done, the requested number of bytes were skipped.
+ RunSkipCallback(bytes_skipped_);
+}
+
+// static
+void InputStreamReader::ContinueSkipCallback(
+ scoped_refptr<InputStreamReader> stream,
+ scoped_refptr<base::SequencedTaskRunner> work_thread_task_runner,
+ int callback_id,
+ int64_t bytes_skipped) {
+ // Always execute asynchronously.
+ work_thread_task_runner->PostTask(
+ FROM_HERE,
+ base::BindOnce(&InputStreamReader::ContinueSkipCallbackOnWorkThread,
+ stream, callback_id, bytes_skipped));
+}
+
+// static
+void InputStreamReader::ContinueReadCallback(
+ scoped_refptr<InputStreamReader> stream,
+ scoped_refptr<base::SequencedTaskRunner> work_thread_task_runner,
+ int callback_id,
+ int bytes_read) {
+ // Always execute asynchronously.
+ work_thread_task_runner->PostTask(
+ FROM_HERE,
+ base::BindOnce(&InputStreamReader::ContinueReadCallbackOnWorkThread,
+ stream, callback_id, bytes_read));
+}
+
+void InputStreamReader::ContinueSkipCallbackOnWorkThread(
+ int callback_id,
+ int64_t bytes_skipped) {
+ DCHECK(work_thread_task_runner_->RunsTasksInCurrentSequence());
+
+ // Check for out of order callbacks.
+ if (pending_callback_id_ != callback_id) {
+ return;
+ }
+
+ DCHECK_LE(bytes_skipped, bytes_to_skip_);
+
+ if (bytes_to_skip_ > 0 && bytes_skipped > 0) {
+ bytes_to_skip_ -= bytes_skipped;
+ }
+
+ if (bytes_skipped <= 0) {
+ RunSkipCallback(net::ERR_REQUEST_RANGE_NOT_SATISFIABLE);
+ } else if (bytes_to_skip_ > 0) {
+ // Continue execution asynchronously.
+ work_thread_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(&InputStreamReader::SkipToRequestedRange, this));
+ } else {
+ // All done, the requested number of bytes were skipped.
+ RunSkipCallback(bytes_skipped_);
+ }
+}
+
+void InputStreamReader::ContinueReadCallbackOnWorkThread(int callback_id,
+ int bytes_read) {
+ DCHECK(work_thread_task_runner_->RunsTasksInCurrentSequence());
+
+ // Check for out of order callbacks.
+ if (pending_callback_id_ != callback_id) {
+ return;
+ }
+
+ RunReadCallback(bytes_read);
+}
+
+void InputStreamReader::RunSkipCallback(int64_t bytes_skipped) {
+ DCHECK(work_thread_task_runner_->RunsTasksInCurrentSequence());
+
+ DCHECK(!pending_skip_callback_.is_null());
+ job_thread_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(InputStreamReader::RunSkipCallbackOnJobThread,
+ bytes_skipped, std::move(pending_skip_callback_)));
+
+ // Reset callback state.
+ pending_callback_id_ = -1;
+ bytes_skipped_ = bytes_to_skip_ = -1;
+}
+
+void InputStreamReader::RunReadCallback(int bytes_read) {
+ DCHECK(work_thread_task_runner_->RunsTasksInCurrentSequence());
+
+ DCHECK(!pending_read_callback_.is_null());
+ job_thread_task_runner_->PostTask(
+ FROM_HERE, base::BindOnce(InputStreamReader::RunReadCallbackOnJobThread,
+ bytes_read, std::move(pending_read_callback_)));
+
+ // Reset callback state.
+ pending_callback_id_ = -1;
+ buffer_ = nullptr;
+}
+
+// static
+void InputStreamReader::RunSkipCallbackOnJobThread(
+ int64_t bytes_skipped,
+ InputStream::SkipCallback skip_callback) {
+ std::move(skip_callback).Run(bytes_skipped);
+}
+
+// static
+void InputStreamReader::RunReadCallbackOnJobThread(
+ int bytes_read,
+ InputStream::ReadCallback read_callback) {
+ std::move(read_callback).Run(bytes_read);
+}
+
+//==============================
+// StreamReaderURLLoader
+//=============================
+
+StreamReaderURLLoader::StreamReaderURLLoader(
+ int32_t request_id,
+ const network::ResourceRequest& request,
+ mojo::PendingRemote<network::mojom::URLLoaderClient> client,
+ mojo::PendingRemote<network::mojom::TrustedHeaderClient> header_client,
+ const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
+ absl::optional<mojo_base::BigBuffer> cached_metadata,
+ std::unique_ptr<Delegate> response_delegate)
+ : request_id_(request_id),
+ request_(request),
+ client_(std::move(client)),
+ header_client_(std::move(header_client)),
+ traffic_annotation_(traffic_annotation),
+ cached_metadata_(std::move(cached_metadata)),
+ response_delegate_(std::move(response_delegate)),
+ writable_handle_watcher_(FROM_HERE,
+ mojo::SimpleWatcher::ArmingPolicy::MANUAL,
+ base::SequencedTaskRunner::GetCurrentDefault()),
+ weak_factory_(this) {
+ DCHECK(response_delegate_);
+ // If there is a client error, clean up the request.
+ client_.set_disconnect_handler(
+ base::BindOnce(&StreamReaderURLLoader::RequestComplete,
+ weak_factory_.GetWeakPtr(), net::ERR_ABORTED));
+
+ // All InputStream work will be performed on this task runner.
+ stream_work_task_runner_ =
+ base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()});
+}
+
+StreamReaderURLLoader::~StreamReaderURLLoader() {
+ if (open_cancel_callback_) {
+ // Release the Delegate held by OpenInputStreamWrapper.
+ std::move(open_cancel_callback_).Run();
+ }
+}
+
+void StreamReaderURLLoader::Start() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ if (!ParseRange(request_.headers)) {
+ RequestComplete(net::ERR_REQUEST_RANGE_NOT_SATISFIABLE);
+ return;
+ }
+
+ if (header_client_.is_bound()) {
+ header_client_->OnBeforeSendHeaders(
+ request_.headers,
+ base::BindOnce(&StreamReaderURLLoader::ContinueWithRequestHeaders,
+ weak_factory_.GetWeakPtr()));
+ } else {
+ ContinueWithRequestHeaders(net::OK, absl::nullopt);
+ }
+}
+
+void StreamReaderURLLoader::ContinueWithRequestHeaders(
+ int32_t result,
+ const absl::optional<net::HttpRequestHeaders>& headers) {
+ if (result != net::OK) {
+ RequestComplete(result);
+ return;
+ }
+
+ if (headers) {
+ DCHECK(header_client_.is_bound());
+ request_.headers = *headers;
+ }
+
+ open_cancel_callback_ = OpenInputStreamWrapper::Open(
+ // This is intentional - the loader could be deleted while
+ // the callback is executing on the background thread. The
+ // delegate will be "returned" to the loader once the
+ // InputStream open attempt is completed.
+ std::move(response_delegate_), stream_work_task_runner_, request_id_,
+ request_,
+ base::BindOnce(&StreamReaderURLLoader::OnInputStreamOpened,
+ weak_factory_.GetWeakPtr()));
+}
+
+void StreamReaderURLLoader::FollowRedirect(
+ const std::vector<std::string>& removed_headers,
+ const net::HttpRequestHeaders& modified_headers,
+ const net::HttpRequestHeaders& modified_cors_exempt_headers,
+ const absl::optional<GURL>& new_url) {
+ NOTREACHED();
+}
+
+void StreamReaderURLLoader::SetPriority(net::RequestPriority priority,
+ int intra_priority_value) {}
+
+void StreamReaderURLLoader::PauseReadingBodyFromNet() {}
+
+void StreamReaderURLLoader::ResumeReadingBodyFromNet() {}
+
+void StreamReaderURLLoader::OnInputStreamOpened(
+ std::unique_ptr<StreamReaderURLLoader::Delegate> returned_delegate,
+ std::unique_ptr<InputStream> input_stream) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(returned_delegate);
+ response_delegate_ = std::move(returned_delegate);
+ open_cancel_callback_.Reset();
+
+ if (!input_stream) {
+ bool restarted = false;
+ response_delegate_->OnInputStreamOpenFailed(request_id_, &restarted);
+ if (restarted) {
+ // The request has been restarted with a new loader.
+ // |this| will be deleted.
+ CleanUp();
+ } else {
+ HeadersComplete(net::HTTP_NOT_FOUND, -1);
+ }
+ return;
+ }
+
+ input_stream_reader_ = base::MakeRefCounted<InputStreamReader>(
+ std::move(input_stream), stream_work_task_runner_);
+
+ if (!byte_range_valid()) {
+ OnReaderSkipCompleted(0);
+ } else {
+ input_stream_reader_->Skip(
+ byte_range_.first_byte_position(),
+ base::BindOnce(&StreamReaderURLLoader::OnReaderSkipCompleted,
+ weak_factory_.GetWeakPtr()));
+ }
+}
+
+void StreamReaderURLLoader::OnReaderSkipCompleted(int64_t bytes_skipped) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ if (!byte_range_valid()) {
+ // Expected content length is unspecified.
+ HeadersComplete(net::HTTP_OK, -1);
+ } else if (bytes_skipped == byte_range_.first_byte_position()) {
+ // We skipped the expected number of bytes.
+ int64_t expected_content_length = -1;
+ if (byte_range_.HasLastBytePosition()) {
+ expected_content_length = byte_range_.last_byte_position() -
+ byte_range_.first_byte_position() + 1;
+ DCHECK_GE(expected_content_length, 0);
+ }
+ HeadersComplete(net::HTTP_OK, expected_content_length);
+ } else {
+ RequestComplete(bytes_skipped < 0 ? bytes_skipped : net::ERR_FAILED);
+ }
+}
+
+void StreamReaderURLLoader::HeadersComplete(int orig_status_code,
+ int64_t expected_content_length) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ int status_code = orig_status_code;
+ std::string status_text =
+ net::GetHttpReasonPhrase(static_cast<net::HttpStatusCode>(status_code));
+ std::string mime_type, charset;
+ int64_t content_length = expected_content_length;
+ ResourceResponse::HeaderMap extra_headers;
+ response_delegate_->GetResponseHeaders(request_id_, &status_code,
+ &status_text, &mime_type, &charset,
+ &content_length, &extra_headers);
+
+ if (status_code < 0) {
+ // Early exit if the handler reported an error.
+ RequestComplete(status_code);
+ return;
+ }
+
+ auto pending_response = network::mojom::URLResponseHead::New();
+ pending_response->request_start = base::TimeTicks::Now();
+ pending_response->response_start = base::TimeTicks::Now();
+
+ auto headers = MakeResponseHeaders(
+ status_code, status_text, mime_type, charset, content_length,
+ extra_headers, false /* allow_existing_header_override */);
+ pending_response->headers = headers;
+
+ if (content_length >= 0) {
+ pending_response->content_length = content_length;
+ }
+
+ if (!mime_type.empty()) {
+ pending_response->mime_type = mime_type;
+ if (!charset.empty()) {
+ pending_response->charset = charset;
+ }
+ }
+
+ if (header_client_.is_bound()) {
+ header_client_->OnHeadersReceived(
+ headers->raw_headers(), net::IPEndPoint(),
+ base::BindOnce(&StreamReaderURLLoader::ContinueWithResponseHeaders,
+ weak_factory_.GetWeakPtr(),
+ std::move(pending_response)));
+ } else {
+ ContinueWithResponseHeaders(std::move(pending_response), net::OK,
+ absl::nullopt, absl::nullopt);
+ }
+}
+
+void StreamReaderURLLoader::ContinueWithResponseHeaders(
+ network::mojom::URLResponseHeadPtr pending_response,
+ int32_t result,
+ const absl::optional<std::string>& headers,
+ const absl::optional<GURL>& redirect_url) {
+ if (result != net::OK) {
+ RequestComplete(result);
+ return;
+ }
+
+ if (headers) {
+ DCHECK(header_client_.is_bound());
+ pending_response->headers =
+ base::MakeRefCounted<net::HttpResponseHeaders>(*headers);
+ }
+
+ auto pending_headers = pending_response->headers;
+
+ // What the length would be if we sent headers over the network. Used to
+ // calculate data length.
+ header_length_ = pending_headers->raw_headers().length();
+
+ DCHECK(client_.is_bound());
+
+ std::string location;
+ const auto has_redirect_url = redirect_url && !redirect_url->is_empty();
+ if (has_redirect_url || pending_headers->IsRedirect(&location)) {
+ pending_response->encoded_data_length = header_length_;
+ pending_response->content_length = 0;
+ pending_response->encoded_body_length = 0;
+ const GURL new_location =
+ has_redirect_url ? *redirect_url : request_.url.Resolve(location);
+ client_->OnReceiveRedirect(
+ MakeRedirectInfo(request_, pending_headers.get(), new_location,
+ pending_headers->response_code()),
+ std::move(pending_response));
+ // The client will restart the request with a new loader.
+ // |this| will be deleted.
+ CleanUp();
+ } else {
+ mojo::ScopedDataPipeConsumerHandle consumer_handle;
+ if (CreateDataPipe(nullptr /*options*/, producer_handle_,
+ consumer_handle) != MOJO_RESULT_OK) {
+ RequestComplete(net::ERR_FAILED);
+ return;
+ }
+ writable_handle_watcher_.Watch(
+ producer_handle_.get(), MOJO_HANDLE_SIGNAL_WRITABLE,
+ base::BindRepeating(&StreamReaderURLLoader::OnDataPipeWritable,
+ base::Unretained(this)));
+
+ client_->OnReceiveResponse(std::move(pending_response),
+ std::move(consumer_handle),
+ std::move(cached_metadata_));
+ ReadMore();
+ }
+}
+
+void StreamReaderURLLoader::ReadMore() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(!pending_buffer_.get());
+
+ uint32_t num_bytes;
+ MojoResult mojo_result = network::NetToMojoPendingBuffer::BeginWrite(
+ &producer_handle_, &pending_buffer_, &num_bytes);
+ if (mojo_result == MOJO_RESULT_SHOULD_WAIT) {
+ // The pipe is full. We need to wait for it to have more space.
+ writable_handle_watcher_.ArmOrNotify();
+ return;
+ } else if (mojo_result == MOJO_RESULT_FAILED_PRECONDITION) {
+ // The data pipe consumer handle has been closed.
+ RequestComplete(net::ERR_ABORTED);
+ return;
+ } else if (mojo_result != MOJO_RESULT_OK) {
+ // The body stream is in a bad state. Bail out.
+ RequestComplete(net::ERR_UNEXPECTED);
+ return;
+ }
+ scoped_refptr<net::IOBuffer> buffer(
+ new network::NetToMojoIOBuffer(pending_buffer_.get()));
+
+ if (!input_stream_reader_.get()) {
+ // This will happen if opening the InputStream fails in which case the
+ // error is communicated by setting the HTTP response status header rather
+ // than failing the request during the header fetch phase.
+ OnReaderReadCompleted(0);
+ return;
+ }
+
+ input_stream_reader_->Read(
+ buffer, base::checked_cast<int>(num_bytes),
+ base::BindOnce(&StreamReaderURLLoader::OnReaderReadCompleted,
+ weak_factory_.GetWeakPtr()));
+}
+
+void StreamReaderURLLoader::OnDataPipeWritable(MojoResult result) {
+ if (result == MOJO_RESULT_FAILED_PRECONDITION) {
+ RequestComplete(net::ERR_ABORTED);
+ return;
+ }
+ DCHECK_EQ(result, MOJO_RESULT_OK) << result;
+
+ ReadMore();
+}
+
+void StreamReaderURLLoader::OnReaderReadCompleted(int bytes_read) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ DCHECK(pending_buffer_);
+ if (bytes_read < 0) {
+ // Error case.
+ RequestComplete(bytes_read);
+ return;
+ }
+ if (bytes_read == 0) {
+ // Eof, read completed.
+ pending_buffer_->Complete(0);
+ RequestComplete(net::OK);
+ return;
+ }
+ producer_handle_ = pending_buffer_->Complete(bytes_read);
+ pending_buffer_ = nullptr;
+
+ client_->OnTransferSizeUpdated(bytes_read);
+ total_bytes_read_ += bytes_read;
+
+ base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
+ FROM_HERE, base::BindOnce(&StreamReaderURLLoader::ReadMore,
+ weak_factory_.GetWeakPtr()));
+}
+
+void StreamReaderURLLoader::RequestComplete(int status_code) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ auto status = network::URLLoaderCompletionStatus(status_code);
+ status.completion_time = base::TimeTicks::Now();
+ status.encoded_data_length = total_bytes_read_ + header_length_;
+ status.encoded_body_length = total_bytes_read_;
+ // We don't support decoders, so use the same value.
+ status.decoded_body_length = total_bytes_read_;
+
+ client_->OnComplete(status);
+ CleanUp();
+}
+
+void StreamReaderURLLoader::CleanUp() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ // Resets the watchers and pipes, so that we will never be called back.
+ writable_handle_watcher_.Cancel();
+ pending_buffer_ = nullptr;
+ producer_handle_.reset();
+
+ // Manages its own lifetime.
+ delete this;
+}
+
+bool StreamReaderURLLoader::ParseRange(const net::HttpRequestHeaders& headers) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ std::string range_header;
+ if (headers.GetHeader(net::HttpRequestHeaders::kRange, &range_header)) {
+ // This loader only cares about the Range header so that we know how many
+ // bytes in the stream to skip and how many to read after that.
+ std::vector<net::HttpByteRange> ranges;
+ if (net::HttpUtil::ParseRangeHeader(range_header, &ranges)) {
+ // In case of multi-range request only use the first range.
+ // We don't support multirange requests.
+ if (ranges.size() == 1) {
+ byte_range_ = ranges[0];
+ }
+ } else {
+ // This happens if the range header could not be parsed or is invalid.
+ return false;
+ }
+ }
+ return true;
+}
+
+bool StreamReaderURLLoader::byte_range_valid() const {
+ return byte_range_.IsValid() && byte_range_.first_byte_position() >= 0;
+}
+
+} // namespace net_service \ No newline at end of file
diff --git a/libcef/browser/net_service/stream_reader_url_loader.h b/libcef/browser/net_service/stream_reader_url_loader.h
new file mode 100644
index 00000000..ea3ec46b
--- /dev/null
+++ b/libcef/browser/net_service/stream_reader_url_loader.h
@@ -0,0 +1,194 @@
+// Copyright (c) 2019 The Chromium Embedded Framework Authors. Portions
+// Copyright (c) 2018 The Chromium Authors. All rights reserved. Use of this
+// source code is governed by a BSD-style license that can be found in the
+// LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_NET_SERVICE_STREAM_READER_URL_LOADER_H_
+#define CEF_LIBCEF_BROWSER_NET_SERVICE_STREAM_READER_URL_LOADER_H_
+
+#include <map>
+
+#include "base/functional/callback.h"
+#include "base/threading/thread_checker.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "mojo/public/cpp/system/simple_watcher.h"
+#include "net/http/http_byte_range.h"
+#include "services/network/public/cpp/net_adapters.h"
+#include "services/network/public/cpp/resource_request.h"
+#include "services/network/public/mojom/network_context.mojom.h"
+#include "services/network/public/mojom/url_loader.mojom.h"
+#include "services/network/public/mojom/url_response_head.mojom.h"
+
+namespace net_service {
+
+class InputStreamReader;
+
+// Abstract class representing an input stream. All methods are called in
+// sequence on a worker thread, but not necessarily on the same thread.
+class InputStream {
+ public:
+ virtual ~InputStream() {}
+
+ // Callback for asynchronous continuation of Skip(). If |bytes_skipped| > 0
+ // then either Skip() will be called again until the requested number of
+ // bytes have been skipped or the request will proceed. If |bytes_skipped|
+ // <= 0 the request will fail with net::ERR_REQUEST_RANGE_NOT_SATISFIABLE.
+ using SkipCallback = base::OnceCallback<void(int64_t /* bytes_skipped */)>;
+
+ // Skip over and discard |n| bytes of data from this input stream. If data
+ // is available immediately set |bytes_skipped| to the number of of bytes
+ // skipped and return true. To read the data at a later time set
+ // |bytes_skipped| to 0, return true and execute |callback| when the data is
+ // available. To indicate failure set |bytes_skipped| to < 0 (e.g.
+ // net::ERR_FAILED) and return false.
+ virtual bool Skip(int64_t n,
+ int64_t* bytes_skipped,
+ SkipCallback callback) = 0;
+
+ // Callback for asynchronous continuation of Read(). If |bytes_read| == 0
+ // the response will be considered complete. If |bytes_read| > 0 then Read()
+ // will be called again until the request is complete (based on either the
+ // result or the expected content length). If |bytes_read| < 0 then the
+ // request will fail and the |bytes_read| value will be treated as the error
+ // code.
+ using ReadCallback = base::OnceCallback<void(int /* bytes_read */)>;
+
+ // Read response data. If data is available immediately copy up to |length|
+ // bytes into |dest|, set |bytes_read| to the number of bytes copied, and
+ // return true. To read the data at a later time set |bytes_read| to 0, return
+ // true and execute |callback| when the data is available. To indicate
+ // response completion set |bytes_read| to 0 and return false. To indicate
+ // failure set |bytes_read| to < 0 (e.g. net::ERR_FAILED) and return false.
+ virtual bool Read(net::IOBuffer* dest,
+ int length,
+ int* bytes_read,
+ ReadCallback callback) = 0;
+};
+
+// Abstract class for handling intercepted resource responses. All methods are
+// called on the IO thread unless otherwise indicated.
+class ResourceResponse {
+ public:
+ virtual ~ResourceResponse() {}
+
+ // Callback for asynchronous continuation of Open(). If the InputStream is
+ // null the request will be canceled.
+ using OpenCallback = base::OnceCallback<void(std::unique_ptr<InputStream>)>;
+
+ // This method is called on a worker thread. Return true and execute
+ // |callback| to continue the request. Return false to cancel the request.
+ // |request| may be different from the request used to create the
+ // StreamReaderURLLoader if a redirect was followed.
+ virtual bool OpenInputStream(int32_t request_id,
+ const network::ResourceRequest& request,
+ OpenCallback callback) = 0;
+
+ // This method is called to populate the response headers.
+ using HeaderMap = std::multimap<std::string, std::string>;
+ virtual void GetResponseHeaders(int32_t request_id,
+ int* status_code,
+ std::string* reason_phrase,
+ std::string* mime_type,
+ std::string* charset,
+ int64_t* content_length,
+ HeaderMap* extra_headers) = 0;
+};
+
+// Custom URLLoader implementation for loading network responses from stream.
+// Methods are called on the IO thread unless otherwise indicated.
+// Based on android_webview/browser/network_service/
+// android_stream_reader_url_loader.h
+class StreamReaderURLLoader : public network::mojom::URLLoader {
+ public:
+ // Delegate abstraction for obtaining input streams. All methods are called
+ // on the IO thread unless otherwise indicated.
+ class Delegate : public ResourceResponse {
+ public:
+ // This method is called if the result of calling OpenInputStream was null.
+ // The |restarted| parameter is set to true if the request was restarted
+ // with a new loader.
+ virtual void OnInputStreamOpenFailed(int32_t request_id,
+ bool* restarted) = 0;
+ };
+
+ StreamReaderURLLoader(
+ int32_t request_id,
+ const network::ResourceRequest& request,
+ mojo::PendingRemote<network::mojom::URLLoaderClient> client,
+ mojo::PendingRemote<network::mojom::TrustedHeaderClient> header_client,
+ const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
+ absl::optional<mojo_base::BigBuffer> cached_metadata,
+ std::unique_ptr<Delegate> response_delegate);
+
+ StreamReaderURLLoader(const StreamReaderURLLoader&) = delete;
+ StreamReaderURLLoader& operator=(const StreamReaderURLLoader&) = delete;
+
+ ~StreamReaderURLLoader() override;
+
+ void Start();
+
+ // network::mojom::URLLoader methods:
+ void FollowRedirect(
+ const std::vector<std::string>& removed_headers,
+ const net::HttpRequestHeaders& modified_headers,
+ const net::HttpRequestHeaders& modified_cors_exempt_headers,
+ const absl::optional<GURL>& new_url) override;
+ void SetPriority(net::RequestPriority priority,
+ int intra_priority_value) override;
+ void PauseReadingBodyFromNet() override;
+ void ResumeReadingBodyFromNet() override;
+
+ private:
+ void ContinueWithRequestHeaders(
+ int32_t result,
+ const absl::optional<net::HttpRequestHeaders>& headers);
+ void OnInputStreamOpened(std::unique_ptr<Delegate> returned_delegate,
+ std::unique_ptr<InputStream> input_stream);
+
+ void OnReaderSkipCompleted(int64_t bytes_skipped);
+ void HeadersComplete(int status_code, int64_t expected_content_length);
+ void ContinueWithResponseHeaders(
+ network::mojom::URLResponseHeadPtr pending_response,
+ int32_t result,
+ const absl::optional<std::string>& headers,
+ const absl::optional<GURL>& redirect_url);
+
+ void ReadMore();
+ void OnDataPipeWritable(MojoResult result);
+ void OnReaderReadCompleted(int bytes_read);
+ void RequestComplete(int status_code);
+
+ void CleanUp();
+
+ bool ParseRange(const net::HttpRequestHeaders& headers);
+ bool byte_range_valid() const;
+
+ const int32_t request_id_;
+
+ size_t header_length_ = 0;
+ int64_t total_bytes_read_ = 0;
+
+ net::HttpByteRange byte_range_;
+ network::ResourceRequest request_;
+ mojo::Remote<network::mojom::URLLoaderClient> client_;
+ mojo::Remote<network::mojom::TrustedHeaderClient> header_client_;
+ const net::MutableNetworkTrafficAnnotationTag traffic_annotation_;
+ absl::optional<mojo_base::BigBuffer> cached_metadata_;
+ std::unique_ptr<Delegate> response_delegate_;
+ scoped_refptr<InputStreamReader> input_stream_reader_;
+
+ mojo::ScopedDataPipeProducerHandle producer_handle_;
+ scoped_refptr<network::NetToMojoPendingBuffer> pending_buffer_;
+ mojo::SimpleWatcher writable_handle_watcher_;
+ base::ThreadChecker thread_checker_;
+
+ scoped_refptr<base::SequencedTaskRunner> stream_work_task_runner_;
+
+ base::OnceClosure open_cancel_callback_;
+
+ base::WeakPtrFactory<StreamReaderURLLoader> weak_factory_;
+};
+
+} // namespace net_service
+
+#endif // CEF_LIBCEF_BROWSER_NET_SERVICE_STREAM_READER_URL_LOADER_H_
diff --git a/libcef/browser/net_service/url_loader_factory_getter.cc b/libcef/browser/net_service/url_loader_factory_getter.cc
new file mode 100644
index 00000000..4223f909
--- /dev/null
+++ b/libcef/browser/net_service/url_loader_factory_getter.cc
@@ -0,0 +1,136 @@
+// Copyright (c) 2019 The Chromium Embedded Framework Authors. Portions
+// Copyright (c) 2018 The Chromium Authors. All rights reserved. Use of this
+// source code is governed by a BSD-style license that can be found in the
+// LICENSE file.
+
+#include "libcef/browser/net_service/url_loader_factory_getter.h"
+
+#include "libcef/browser/thread_util.h"
+#include "libcef/common/app_manager.h"
+
+#include "base/task/single_thread_task_runner.h"
+#include "content/browser/devtools/devtools_instrumentation.h"
+#include "content/browser/renderer_host/render_frame_host_impl.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/storage_partition.h"
+#include "content/public/common/content_client.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "services/network/public/cpp/wrapper_shared_url_loader_factory.h"
+
+namespace net_service {
+
+// Based on CreatePendingSharedURLLoaderFactory from
+// content/browser/download/download_manager_impl.cc.
+// static
+scoped_refptr<URLLoaderFactoryGetter> URLLoaderFactoryGetter::Create(
+ content::RenderFrameHost* render_frame_host,
+ content::BrowserContext* browser_context) {
+ CEF_REQUIRE_UIT();
+ DCHECK(browser_context);
+
+ // Call this early because newly created BrowserContexts may need to
+ // initialize additional state, and that should be done on the UI thread
+ // instead of potentially racing with the WillCreateURLLoaderFactory
+ // implementation.
+ auto loader_factory = browser_context->GetDefaultStoragePartition()
+ ->GetURLLoaderFactoryForBrowserProcess();
+
+ mojo::PendingRemote<network::mojom::URLLoaderFactory> proxy_factory_remote;
+ mojo::PendingReceiver<network::mojom::URLLoaderFactory>
+ proxy_factory_receiver;
+
+ // Create an intermediate pipe that can be used to proxy the request's
+ // URLLoaderFactory.
+ mojo::PendingRemote<network::mojom::URLLoaderFactory>
+ maybe_proxy_factory_remote;
+ mojo::PendingReceiver<network::mojom::URLLoaderFactory>
+ maybe_proxy_factory_receiver =
+ maybe_proxy_factory_remote.InitWithNewPipeAndPassReceiver();
+
+ bool should_proxy = false;
+ int render_process_id = -1;
+
+ if (render_frame_host) {
+ render_process_id = render_frame_host->GetProcess()->GetID();
+
+ // Allow DevTools to potentially inject itself into the proxy pipe.
+ should_proxy =
+ content::devtools_instrumentation::WillCreateURLLoaderFactory(
+ static_cast<content::RenderFrameHostImpl*>(render_frame_host),
+ false /* is_navigation */, false /* is_download */,
+ &maybe_proxy_factory_receiver, nullptr /* factory_override */);
+ }
+
+ auto browser_client = CefAppManager::Get()->GetContentClient()->browser();
+
+ // Allow the Content embedder to inject itself if it wants to.
+ should_proxy |= browser_client->WillCreateURLLoaderFactory(
+ browser_context, render_frame_host, render_process_id,
+ content::ContentBrowserClient::URLLoaderFactoryType::kDocumentSubResource,
+ url::Origin(), absl::nullopt /* navigation_id */, ukm::SourceIdObj(),
+ &maybe_proxy_factory_receiver, nullptr /* header_client */,
+ nullptr /* bypass_redirect_checks */, nullptr /* disable_secure_dns */,
+ nullptr /* factory_override */);
+
+ // If anyone above indicated that they care about proxying, pass the
+ // intermediate pipe along to the URLLoaderFactoryGetter.
+ if (should_proxy) {
+ proxy_factory_remote = std::move(maybe_proxy_factory_remote);
+ proxy_factory_receiver = std::move(maybe_proxy_factory_receiver);
+ }
+
+ return base::WrapRefCounted(new URLLoaderFactoryGetter(
+ loader_factory->Clone(), std::move(proxy_factory_remote),
+ std::move(proxy_factory_receiver)));
+}
+
+// Based on CreateFactory from
+// content/browser/download/network_download_pending_url_loader_factory.cc.
+scoped_refptr<network::SharedURLLoaderFactory>
+URLLoaderFactoryGetter::GetURLLoaderFactory() {
+ // On first call we associate with the current thread.
+ if (!task_runner_) {
+ task_runner_ = base::SingleThreadTaskRunner::GetCurrentDefault();
+ } else {
+ DCHECK(task_runner_->RunsTasksInCurrentSequence());
+ }
+
+ if (lazy_factory_) {
+ return lazy_factory_;
+ }
+
+ // Bind on the current thread.
+ auto loader_factory =
+ network::SharedURLLoaderFactory::Create(std::move(loader_factory_info_));
+
+ if (proxy_factory_receiver_.is_valid()) {
+ loader_factory->Clone(std::move(proxy_factory_receiver_));
+ lazy_factory_ =
+ base::MakeRefCounted<network::WrapperSharedURLLoaderFactory>(
+ std::move(proxy_factory_remote_));
+ } else {
+ lazy_factory_ = loader_factory;
+ }
+ return lazy_factory_;
+}
+
+URLLoaderFactoryGetter::URLLoaderFactoryGetter(
+ std::unique_ptr<network::PendingSharedURLLoaderFactory> loader_factory_info,
+ mojo::PendingRemote<network::mojom::URLLoaderFactory> proxy_factory_remote,
+ mojo::PendingReceiver<network::mojom::URLLoaderFactory>
+ proxy_factory_receiver)
+ : loader_factory_info_(std::move(loader_factory_info)),
+ proxy_factory_remote_(std::move(proxy_factory_remote)),
+ proxy_factory_receiver_(std::move(proxy_factory_receiver)) {}
+
+URLLoaderFactoryGetter::~URLLoaderFactoryGetter() = default;
+
+void URLLoaderFactoryGetter::DeleteOnCorrectThread() const {
+ if (task_runner_ && !task_runner_->RunsTasksInCurrentSequence()) {
+ task_runner_->DeleteSoon(FROM_HERE, this);
+ return;
+ }
+ delete this;
+}
+
+} // namespace net_service \ No newline at end of file
diff --git a/libcef/browser/net_service/url_loader_factory_getter.h b/libcef/browser/net_service/url_loader_factory_getter.h
new file mode 100644
index 00000000..554c8159
--- /dev/null
+++ b/libcef/browser/net_service/url_loader_factory_getter.h
@@ -0,0 +1,79 @@
+// Copyright (c) 2019 The Chromium Embedded Framework Authors. Portions
+// Copyright (c) 2018 The Chromium Authors. All rights reserved. Use of this
+// source code is governed by a BSD-style license that can be found in the
+// LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_NET_SERVICE_URL_LOADER_FACTORY_GETTER_H_
+#define CEF_LIBCEF_BROWSER_NET_SERVICE_URL_LOADER_FACTORY_GETTER_H_
+
+#include "base/memory/ref_counted.h"
+#include "base/task/sequenced_task_runner.h"
+#include "base/task/sequenced_task_runner_helpers.h"
+#include "services/network/public/mojom/url_loader_factory.mojom.h"
+
+namespace content {
+class BrowserContext;
+class RenderFrameHost;
+} // namespace content
+
+namespace network {
+class SharedURLLoaderFactory;
+class PendingSharedURLLoaderFactory;
+} // namespace network
+
+namespace net_service {
+
+struct URLLoaderFactoryGetterDeleter;
+
+// Helper class for retrieving a URLLoaderFactory that can be bound on any
+// thread, and that correctly handles proxied requests.
+class URLLoaderFactoryGetter
+ : public base::RefCountedThreadSafe<URLLoaderFactoryGetter,
+ URLLoaderFactoryGetterDeleter> {
+ public:
+ URLLoaderFactoryGetter(const URLLoaderFactoryGetter&) = delete;
+ URLLoaderFactoryGetter& operator=(const URLLoaderFactoryGetter&) = delete;
+
+ // Create a URLLoaderFactoryGetter on the UI thread.
+ // |render_frame_host| may be nullptr.
+ static scoped_refptr<URLLoaderFactoryGetter> Create(
+ content::RenderFrameHost* render_frame_host,
+ content::BrowserContext* browser_context);
+
+ // Create a SharedURLLoaderFactory on the current thread. All future calls
+ // to this method must be on the same thread.
+ scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory();
+
+ private:
+ friend class base::DeleteHelper<URLLoaderFactoryGetter>;
+ friend class base::RefCountedThreadSafe<URLLoaderFactoryGetter,
+ URLLoaderFactoryGetterDeleter>;
+ friend struct URLLoaderFactoryGetterDeleter;
+
+ URLLoaderFactoryGetter(std::unique_ptr<network::PendingSharedURLLoaderFactory>
+ loader_factory_info,
+ mojo::PendingRemote<network::mojom::URLLoaderFactory>
+ proxy_factory_remote,
+ mojo::PendingReceiver<network::mojom::URLLoaderFactory>
+ proxy_factory_receiver);
+ ~URLLoaderFactoryGetter();
+
+ void DeleteOnCorrectThread() const;
+
+ std::unique_ptr<network::PendingSharedURLLoaderFactory> loader_factory_info_;
+ scoped_refptr<network::SharedURLLoaderFactory> lazy_factory_;
+ mojo::PendingRemote<network::mojom::URLLoaderFactory> proxy_factory_remote_;
+ mojo::PendingReceiver<network::mojom::URLLoaderFactory>
+ proxy_factory_receiver_;
+ scoped_refptr<base::SequencedTaskRunner> task_runner_;
+};
+
+struct URLLoaderFactoryGetterDeleter {
+ static void Destruct(const URLLoaderFactoryGetter* factory_getter) {
+ factory_getter->DeleteOnCorrectThread();
+ }
+};
+
+} // namespace net_service
+
+#endif // CEF_LIBCEF_BROWSER_NET_SERVICE_URL_LOADER_FACTORY_GETTER_H_
diff --git a/libcef/browser/origin_whitelist_impl.cc b/libcef/browser/origin_whitelist_impl.cc
new file mode 100644
index 00000000..0b98c4c7
--- /dev/null
+++ b/libcef/browser/origin_whitelist_impl.cc
@@ -0,0 +1,311 @@
+// Copyright (c) 2011 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "libcef/browser/origin_whitelist_impl.h"
+
+#include <string>
+#include <vector>
+
+#include "include/cef_origin_whitelist.h"
+#include "libcef/browser/browser_manager.h"
+#include "libcef/browser/context.h"
+#include "libcef/browser/thread_util.h"
+
+#include "base/functional/bind.h"
+#include "base/lazy_instance.h"
+#include "base/synchronization/lock.h"
+#include "cef/libcef/common/mojom/cef.mojom.h"
+#include "chrome/common/webui_url_constants.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/common/url_constants.h"
+#include "extensions/common/constants.h"
+#include "url/gurl.h"
+#include "url/origin.h"
+
+namespace {
+
+// Class that manages cross-origin whitelist registrations.
+class CefOriginWhitelistManager {
+ public:
+ CefOriginWhitelistManager() = default;
+
+ CefOriginWhitelistManager(const CefOriginWhitelistManager&) = delete;
+ CefOriginWhitelistManager& operator=(const CefOriginWhitelistManager&) =
+ delete;
+
+ // Retrieve the singleton instance.
+ static CefOriginWhitelistManager* GetInstance();
+
+ bool AddOriginEntry(const std::string& source_origin,
+ const std::string& target_protocol,
+ const std::string& target_domain,
+ bool allow_target_subdomains) {
+ auto info = cef::mojom::CrossOriginWhiteListEntry::New();
+ info->source_origin = source_origin;
+ info->target_protocol = target_protocol;
+ info->target_domain = target_domain;
+ info->allow_target_subdomains = allow_target_subdomains;
+
+ {
+ base::AutoLock lock_scope(lock_);
+
+ // Verify that the origin entry doesn't already exist.
+ for (const auto& entry : origin_list_) {
+ if (entry == info) {
+ return false;
+ }
+ }
+
+ origin_list_.push_back(info->Clone());
+ }
+
+ SendModifyCrossOriginWhitelistEntry(true, info);
+ return true;
+ }
+
+ bool RemoveOriginEntry(const std::string& source_origin,
+ const std::string& target_protocol,
+ const std::string& target_domain,
+ bool allow_target_subdomains) {
+ auto info = cef::mojom::CrossOriginWhiteListEntry::New();
+ info->source_origin = source_origin;
+ info->target_protocol = target_protocol;
+ info->target_domain = target_domain;
+ info->allow_target_subdomains = allow_target_subdomains;
+
+ bool found = false;
+
+ {
+ base::AutoLock lock_scope(lock_);
+
+ CrossOriginWhiteList::iterator it = origin_list_.begin();
+ for (; it != origin_list_.end(); ++it) {
+ if (*it == info) {
+ origin_list_.erase(it);
+ found = true;
+ break;
+ }
+ }
+ }
+
+ if (!found) {
+ return false;
+ }
+
+ SendModifyCrossOriginWhitelistEntry(false, info);
+ return true;
+ }
+
+ void ClearOrigins() {
+ {
+ base::AutoLock lock_scope(lock_);
+ origin_list_.clear();
+ }
+
+ SendClearCrossOriginWhitelist();
+ }
+
+ void GetCrossOriginWhitelistEntries(
+ absl::optional<CrossOriginWhiteList>* entries) const {
+ base::AutoLock lock_scope(lock_);
+
+ if (!origin_list_.empty()) {
+ CrossOriginWhiteList vec;
+ for (const auto& entry : origin_list_) {
+ vec.push_back(entry->Clone());
+ }
+ *entries = std::move(vec);
+ }
+ }
+
+ bool HasCrossOriginWhitelistEntry(const url::Origin& source,
+ const url::Origin& target) const {
+ base::AutoLock lock_scope(lock_);
+
+ if (!origin_list_.empty()) {
+ for (const auto& entry : origin_list_) {
+ if (IsMatch(source, target, entry)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private:
+ // Send the modify cross-origin whitelist entry message to all currently
+ // existing hosts.
+ static void SendModifyCrossOriginWhitelistEntry(
+ bool add,
+ const cef::mojom::CrossOriginWhiteListEntryPtr& info) {
+ CEF_REQUIRE_UIT();
+
+ content::RenderProcessHost::iterator i(
+ content::RenderProcessHost::AllHostsIterator());
+ for (; !i.IsAtEnd(); i.Advance()) {
+ auto render_manager =
+ CefBrowserManager::GetRenderManagerForProcess(i.GetCurrentValue());
+ render_manager->ModifyCrossOriginWhitelistEntry(add, info->Clone());
+ }
+ }
+
+ // Send the clear cross-origin whitelists message to all currently existing
+ // hosts.
+ static void SendClearCrossOriginWhitelist() {
+ CEF_REQUIRE_UIT();
+
+ content::RenderProcessHost::iterator i(
+ content::RenderProcessHost::AllHostsIterator());
+ for (; !i.IsAtEnd(); i.Advance()) {
+ auto render_manager =
+ CefBrowserManager::GetRenderManagerForProcess(i.GetCurrentValue());
+ render_manager->ClearCrossOriginWhitelist();
+ }
+ }
+
+ static bool IsMatch(const url::Origin& source_origin,
+ const url::Origin& target_origin,
+ const cef::mojom::CrossOriginWhiteListEntryPtr& param) {
+ if (!source_origin.IsSameOriginWith(
+ url::Origin::Create(GURL(param->source_origin)))) {
+ // Source origin does not match.
+ return false;
+ }
+
+ if (target_origin.scheme() != param->target_protocol) {
+ // Target scheme does not match.
+ return false;
+ }
+
+ if (param->allow_target_subdomains) {
+ if (param->target_domain.empty()) {
+ // Any domain will match.
+ return true;
+ } else {
+ // Match sub-domains.
+ return target_origin.DomainIs(param->target_domain.c_str());
+ }
+ } else {
+ // Match full domain.
+ return (target_origin.host() == param->target_domain);
+ }
+ }
+
+ mutable base::Lock lock_;
+
+ // List of registered origins. Access must be protected by |lock_|.
+ CrossOriginWhiteList origin_list_;
+};
+
+base::LazyInstance<CefOriginWhitelistManager>::Leaky g_manager =
+ LAZY_INSTANCE_INITIALIZER;
+
+CefOriginWhitelistManager* CefOriginWhitelistManager::GetInstance() {
+ return g_manager.Pointer();
+}
+
+} // namespace
+
+bool CefAddCrossOriginWhitelistEntry(const CefString& source_origin,
+ const CefString& target_protocol,
+ const CefString& target_domain,
+ bool allow_target_subdomains) {
+ // Verify that the context is in a valid state.
+ if (!CONTEXT_STATE_VALID()) {
+ NOTREACHED();
+ return false;
+ }
+
+ std::string source_url = source_origin;
+ GURL gurl = GURL(source_url);
+ if (gurl.is_empty() || !gurl.is_valid()) {
+ NOTREACHED() << "Invalid source_origin URL: " << source_url;
+ return false;
+ }
+
+ if (CEF_CURRENTLY_ON_UIT()) {
+ return CefOriginWhitelistManager::GetInstance()->AddOriginEntry(
+ source_origin, target_protocol, target_domain, allow_target_subdomains);
+ } else {
+ CEF_POST_TASK(
+ CEF_UIT,
+ base::BindOnce(base::IgnoreResult(&CefAddCrossOriginWhitelistEntry),
+ source_origin, target_protocol, target_domain,
+ allow_target_subdomains));
+ }
+
+ return true;
+}
+
+bool CefRemoveCrossOriginWhitelistEntry(const CefString& source_origin,
+ const CefString& target_protocol,
+ const CefString& target_domain,
+ bool allow_target_subdomains) {
+ // Verify that the context is in a valid state.
+ if (!CONTEXT_STATE_VALID()) {
+ NOTREACHED();
+ return false;
+ }
+
+ std::string source_url = source_origin;
+ GURL gurl = GURL(source_url);
+ if (gurl.is_empty() || !gurl.is_valid()) {
+ NOTREACHED() << "Invalid source_origin URL: " << source_url;
+ return false;
+ }
+
+ if (CEF_CURRENTLY_ON_UIT()) {
+ return CefOriginWhitelistManager::GetInstance()->RemoveOriginEntry(
+ source_origin, target_protocol, target_domain, allow_target_subdomains);
+ } else {
+ CEF_POST_TASK(
+ CEF_UIT,
+ base::BindOnce(base::IgnoreResult(&CefRemoveCrossOriginWhitelistEntry),
+ source_origin, target_protocol, target_domain,
+ allow_target_subdomains));
+ }
+
+ return true;
+}
+
+bool CefClearCrossOriginWhitelist() {
+ // Verify that the context is in a valid state.
+ if (!CONTEXT_STATE_VALID()) {
+ NOTREACHED();
+ return false;
+ }
+
+ if (CEF_CURRENTLY_ON_UIT()) {
+ CefOriginWhitelistManager::GetInstance()->ClearOrigins();
+ } else {
+ CEF_POST_TASK(
+ CEF_UIT,
+ base::BindOnce(base::IgnoreResult(&CefClearCrossOriginWhitelist)));
+ }
+
+ return true;
+}
+
+void GetCrossOriginWhitelistEntries(
+ absl::optional<CrossOriginWhiteList>* entries) {
+ CefOriginWhitelistManager::GetInstance()->GetCrossOriginWhitelistEntries(
+ entries);
+}
+
+bool HasCrossOriginWhitelistEntry(const url::Origin& source,
+ const url::Origin& target) {
+ // Components of chrome that are implemented as extensions or platform apps
+ // are allowed to use chrome://resources/ and chrome://theme/ URLs.
+ // See also RegisterNonNetworkSubresourceURLLoaderFactories.
+ if (source.scheme() == extensions::kExtensionScheme &&
+ target.scheme() == content::kChromeUIScheme &&
+ (target.host() == chrome::kChromeUIThemeHost ||
+ target.host() == content::kChromeUIResourcesHost)) {
+ return true;
+ }
+
+ return CefOriginWhitelistManager::GetInstance()->HasCrossOriginWhitelistEntry(
+ source, target);
+}
diff --git a/libcef/browser/origin_whitelist_impl.h b/libcef/browser/origin_whitelist_impl.h
new file mode 100644
index 00000000..c5f8236d
--- /dev/null
+++ b/libcef/browser/origin_whitelist_impl.h
@@ -0,0 +1,35 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_ORIGIN_WHITELIST_IMPL_H_
+#define CEF_LIBCEF_BROWSER_ORIGIN_WHITELIST_IMPL_H_
+
+#include <vector>
+
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+#include "cef/libcef/common/mojom/cef.mojom-forward.h"
+
+namespace content {
+class RenderProcessHost;
+}
+
+namespace url {
+class Origin;
+}
+
+using CrossOriginWhiteList =
+ std::vector<cef::mojom::CrossOriginWhiteListEntryPtr>;
+
+// Called to retrieve the current list of cross-origin white list entries. This
+// method is thread safe.
+void GetCrossOriginWhitelistEntries(
+ absl::optional<CrossOriginWhiteList>* entries);
+
+// Returns true if |source| can access |target| based on the cross-origin white
+// list settings.
+bool HasCrossOriginWhitelistEntry(const url::Origin& source,
+ const url::Origin& target);
+
+#endif // CEF_LIBCEF_BROWSER_ORIGIN_WHITELIST_IMPL_H_
diff --git a/libcef/browser/osr/browser_platform_delegate_osr.cc b/libcef/browser/osr/browser_platform_delegate_osr.cc
new file mode 100644
index 00000000..12391bd1
--- /dev/null
+++ b/libcef/browser/osr/browser_platform_delegate_osr.cc
@@ -0,0 +1,658 @@
+// Copyright 2015 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/osr/browser_platform_delegate_osr.h"
+
+#include <utility>
+
+#include "libcef/browser/image_impl.h"
+#include "libcef/browser/osr/osr_accessibility_util.h"
+#include "libcef/browser/osr/render_widget_host_view_osr.h"
+#include "libcef/browser/osr/touch_selection_controller_client_osr.h"
+#include "libcef/browser/osr/web_contents_view_osr.h"
+#include "libcef/browser/views/view_util.h"
+#include "libcef/common/drag_data_impl.h"
+
+#include "base/task/current_thread.h"
+#include "content/browser/renderer_host/render_widget_host_input_event_router.h"
+#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/public/browser/render_view_host.h"
+#include "ui/display/screen.h"
+#include "ui/events/base_event_utils.h"
+
+CefBrowserPlatformDelegateOsr::CefBrowserPlatformDelegateOsr(
+ std::unique_ptr<CefBrowserPlatformDelegateNative> native_delegate,
+ bool use_shared_texture,
+ bool use_external_begin_frame)
+ : native_delegate_(std::move(native_delegate)),
+ use_shared_texture_(use_shared_texture),
+ use_external_begin_frame_(use_external_begin_frame) {
+ native_delegate_->set_windowless_handler(this);
+}
+
+void CefBrowserPlatformDelegateOsr::CreateViewForWebContents(
+ content::WebContentsView** view,
+ content::RenderViewHostDelegateView** delegate_view) {
+ DCHECK(!view_osr_);
+
+ // Use the OSR view instead of the default platform view.
+ view_osr_ = new CefWebContentsViewOSR(
+ GetBackgroundColor(), use_shared_texture_, use_external_begin_frame_);
+ *view = view_osr_;
+ *delegate_view = view_osr_;
+}
+
+void CefBrowserPlatformDelegateOsr::WebContentsCreated(
+ content::WebContents* web_contents,
+ bool owned) {
+ CefBrowserPlatformDelegateAlloy::WebContentsCreated(web_contents, owned);
+
+ DCHECK(view_osr_);
+ DCHECK(!view_osr_->web_contents());
+
+ // Associate the WebContents with the OSR view.
+ view_osr_->WebContentsCreated(web_contents);
+}
+
+void CefBrowserPlatformDelegateOsr::RenderViewCreated(
+ content::RenderViewHost* render_view_host) {
+ if (view_osr_) {
+ view_osr_->RenderViewCreated();
+ }
+}
+
+void CefBrowserPlatformDelegateOsr::BrowserCreated(
+ CefBrowserHostBase* browser) {
+ CefBrowserPlatformDelegateAlloy::BrowserCreated(browser);
+
+ if (browser->IsPopup()) {
+ // Associate the RenderWidget host view with the browser now because the
+ // browser wasn't known at the time that the host view was created.
+ content::RenderViewHost* host = web_contents_->GetRenderViewHost();
+ DCHECK(host);
+ CefRenderWidgetHostViewOSR* view =
+ static_cast<CefRenderWidgetHostViewOSR*>(host->GetWidget()->GetView());
+ // |view| will be null if the popup is a DevTools window.
+ if (view) {
+ view->set_browser_impl(static_cast<AlloyBrowserHostImpl*>(browser));
+ }
+ }
+}
+
+void CefBrowserPlatformDelegateOsr::NotifyBrowserDestroyed() {
+ content::RenderViewHost* host = web_contents_->GetRenderViewHost();
+ if (host) {
+ CefRenderWidgetHostViewOSR* view =
+ static_cast<CefRenderWidgetHostViewOSR*>(host->GetWidget()->GetView());
+ if (view) {
+ view->ReleaseCompositor();
+ }
+ }
+
+ CefBrowserPlatformDelegateAlloy::NotifyBrowserDestroyed();
+}
+
+void CefBrowserPlatformDelegateOsr::BrowserDestroyed(
+ CefBrowserHostBase* browser) {
+ CefBrowserPlatformDelegateAlloy::BrowserDestroyed(browser);
+
+ view_osr_ = nullptr;
+}
+
+SkColor CefBrowserPlatformDelegateOsr::GetBackgroundColor() const {
+ return native_delegate_->GetBackgroundColor();
+}
+
+void CefBrowserPlatformDelegateOsr::WasResized() {
+ CefRenderWidgetHostViewOSR* view = GetOSRHostView();
+ if (view) {
+ view->WasResized();
+ }
+}
+
+void CefBrowserPlatformDelegateOsr::SendKeyEvent(const CefKeyEvent& event) {
+ CefRenderWidgetHostViewOSR* view = GetOSRHostView();
+ if (!view) {
+ return;
+ }
+
+ content::NativeWebKeyboardEvent web_event =
+ native_delegate_->TranslateWebKeyEvent(event);
+ view->SendKeyEvent(web_event);
+}
+
+void CefBrowserPlatformDelegateOsr::SendMouseClickEvent(
+ const CefMouseEvent& event,
+ CefBrowserHost::MouseButtonType type,
+ bool mouseUp,
+ int clickCount) {
+ CefRenderWidgetHostViewOSR* view = GetOSRHostView();
+ if (!view) {
+ return;
+ }
+
+ blink::WebMouseEvent web_event = native_delegate_->TranslateWebClickEvent(
+ event, type, mouseUp, clickCount);
+ view->SendMouseEvent(web_event);
+}
+
+void CefBrowserPlatformDelegateOsr::SendMouseMoveEvent(
+ const CefMouseEvent& event,
+ bool mouseLeave) {
+ CefRenderWidgetHostViewOSR* view = GetOSRHostView();
+ if (!view) {
+ return;
+ }
+
+ blink::WebMouseEvent web_event =
+ native_delegate_->TranslateWebMoveEvent(event, mouseLeave);
+ view->SendMouseEvent(web_event);
+}
+
+void CefBrowserPlatformDelegateOsr::SendMouseWheelEvent(
+ const CefMouseEvent& event,
+ int deltaX,
+ int deltaY) {
+ CefRenderWidgetHostViewOSR* view = GetOSRHostView();
+ if (!view) {
+ return;
+ }
+
+ blink::WebMouseWheelEvent web_event =
+ native_delegate_->TranslateWebWheelEvent(event, deltaX, deltaY);
+ view->SendMouseWheelEvent(web_event);
+}
+
+void CefBrowserPlatformDelegateOsr::SendTouchEvent(const CefTouchEvent& event) {
+ CefRenderWidgetHostViewOSR* view = GetOSRHostView();
+ if (view) {
+ view->SendTouchEvent(event);
+ }
+}
+
+void CefBrowserPlatformDelegateOsr::SetFocus(bool setFocus) {
+ CefRenderWidgetHostViewOSR* view = GetOSRHostView();
+ if (view) {
+ view->SetFocus(setFocus);
+ }
+}
+
+gfx::Point CefBrowserPlatformDelegateOsr::GetScreenPoint(
+ const gfx::Point& view,
+ bool want_dip_coords) const {
+ CefRefPtr<CefRenderHandler> handler = browser_->client()->GetRenderHandler();
+ if (handler.get()) {
+ int screenX = 0, screenY = 0;
+ if (handler->GetScreenPoint(browser_, view.x(), view.y(), screenX,
+ screenY)) {
+ gfx::Point screen_point(screenX, screenY);
+#if !BUILDFLAG(IS_MAC)
+ // Mac always operates in DIP coordinates so |want_dip_coords| is ignored.
+ if (want_dip_coords) {
+ // Convert to DIP coordinates.
+ const auto& display = view_util::GetDisplayNearestPoint(
+ screen_point, /*input_pixel_coords=*/true);
+ view_util::ConvertPointFromPixels(&screen_point,
+ display.device_scale_factor());
+ }
+#endif
+ return screen_point;
+ }
+ }
+ return view;
+}
+
+void CefBrowserPlatformDelegateOsr::ViewText(const std::string& text) {
+ native_delegate_->ViewText(text);
+}
+
+bool CefBrowserPlatformDelegateOsr::HandleKeyboardEvent(
+ const content::NativeWebKeyboardEvent& event) {
+ return native_delegate_->HandleKeyboardEvent(event);
+}
+
+CefEventHandle CefBrowserPlatformDelegateOsr::GetEventHandle(
+ const content::NativeWebKeyboardEvent& event) const {
+ return native_delegate_->GetEventHandle(event);
+}
+
+std::unique_ptr<CefJavaScriptDialogRunner>
+CefBrowserPlatformDelegateOsr::CreateJavaScriptDialogRunner() {
+ return native_delegate_->CreateJavaScriptDialogRunner();
+}
+
+std::unique_ptr<CefMenuRunner>
+CefBrowserPlatformDelegateOsr::CreateMenuRunner() {
+ return native_delegate_->CreateMenuRunner();
+}
+
+bool CefBrowserPlatformDelegateOsr::IsWindowless() const {
+ return true;
+}
+
+void CefBrowserPlatformDelegateOsr::WasHidden(bool hidden) {
+ // The WebContentsImpl will notify the OSR view.
+ content::WebContentsImpl* web_contents =
+ static_cast<content::WebContentsImpl*>(web_contents_);
+ if (web_contents) {
+ if (hidden) {
+ web_contents->WasHidden();
+ } else {
+ web_contents->WasShown();
+ }
+ }
+}
+
+bool CefBrowserPlatformDelegateOsr::IsHidden() const {
+ CefRenderWidgetHostViewOSR* view = GetOSRHostView();
+ if (view) {
+ return view->is_hidden();
+ }
+ return true;
+}
+
+void CefBrowserPlatformDelegateOsr::NotifyScreenInfoChanged() {
+ CefRenderWidgetHostViewOSR* view = GetOSRHostView();
+ if (view) {
+ view->OnScreenInfoChanged();
+ }
+}
+
+void CefBrowserPlatformDelegateOsr::Invalidate(cef_paint_element_type_t type) {
+ CefRenderWidgetHostViewOSR* view = GetOSRHostView();
+ if (view) {
+ view->Invalidate(type);
+ }
+}
+
+void CefBrowserPlatformDelegateOsr::SendExternalBeginFrame() {
+ CefRenderWidgetHostViewOSR* view = GetOSRHostView();
+ if (view) {
+ view->SendExternalBeginFrame();
+ }
+}
+
+void CefBrowserPlatformDelegateOsr::SetWindowlessFrameRate(int frame_rate) {
+ CefRenderWidgetHostViewOSR* view = GetOSRHostView();
+ if (view) {
+ view->UpdateFrameRate();
+ }
+}
+
+void CefBrowserPlatformDelegateOsr::ImeSetComposition(
+ const CefString& text,
+ const std::vector<CefCompositionUnderline>& underlines,
+ const CefRange& replacement_range,
+ const CefRange& selection_range) {
+ CefRenderWidgetHostViewOSR* view = GetOSRHostView();
+ if (view) {
+ view->ImeSetComposition(text, underlines, replacement_range,
+ selection_range);
+ }
+}
+
+void CefBrowserPlatformDelegateOsr::ImeCommitText(
+ const CefString& text,
+ const CefRange& replacement_range,
+ int relative_cursor_pos) {
+ CefRenderWidgetHostViewOSR* view = GetOSRHostView();
+ if (view) {
+ view->ImeCommitText(text, replacement_range, relative_cursor_pos);
+ }
+}
+
+void CefBrowserPlatformDelegateOsr::ImeFinishComposingText(
+ bool keep_selection) {
+ CefRenderWidgetHostViewOSR* view = GetOSRHostView();
+ if (view) {
+ view->ImeFinishComposingText(keep_selection);
+ }
+}
+
+void CefBrowserPlatformDelegateOsr::ImeCancelComposition() {
+ CefRenderWidgetHostViewOSR* view = GetOSRHostView();
+ if (view) {
+ view->ImeCancelComposition();
+ }
+}
+
+void CefBrowserPlatformDelegateOsr::DragTargetDragEnter(
+ CefRefPtr<CefDragData> drag_data,
+ const CefMouseEvent& event,
+ cef_drag_operations_mask_t allowed_ops) {
+ content::WebContentsImpl* web_contents =
+ static_cast<content::WebContentsImpl*>(web_contents_);
+ if (!web_contents) {
+ return;
+ }
+
+ if (current_rvh_for_drag_) {
+ DragTargetDragLeave();
+ }
+
+ const gfx::Point client_pt(event.x, event.y);
+ gfx::PointF transformed_pt;
+ current_rwh_for_drag_ =
+ web_contents->GetInputEventRouter()
+ ->GetRenderWidgetHostAtPoint(
+ web_contents->GetRenderViewHost()->GetWidget()->GetView(),
+ gfx::PointF(client_pt), &transformed_pt)
+ ->GetWeakPtr();
+ current_rvh_for_drag_ = web_contents->GetRenderViewHost();
+
+ drag_data_ = drag_data;
+ drag_allowed_ops_ = allowed_ops;
+
+ CefDragDataImpl* data_impl = static_cast<CefDragDataImpl*>(drag_data.get());
+ base::AutoLock lock_scope(data_impl->lock());
+ content::DropData* drop_data = data_impl->drop_data();
+ const gfx::Point& screen_pt =
+ GetScreenPoint(client_pt, /*want_dip_coords=*/false);
+ blink::DragOperationsMask ops =
+ static_cast<blink::DragOperationsMask>(allowed_ops);
+ int modifiers = TranslateWebEventModifiers(event.modifiers);
+
+ current_rwh_for_drag_->FilterDropData(drop_data);
+
+ // Give the delegate an opportunity to cancel the drag.
+ if (web_contents->GetDelegate() && !web_contents->GetDelegate()->CanDragEnter(
+ web_contents, *drop_data, ops)) {
+ drag_data_ = nullptr;
+ return;
+ }
+
+ current_rwh_for_drag_->DragTargetDragEnter(*drop_data, transformed_pt,
+ gfx::PointF(screen_pt), ops,
+ modifiers, base::DoNothing());
+}
+
+void CefBrowserPlatformDelegateOsr::DragTargetDragOver(
+ const CefMouseEvent& event,
+ cef_drag_operations_mask_t allowed_ops) {
+ if (!drag_data_) {
+ return;
+ }
+
+ content::WebContentsImpl* web_contents =
+ static_cast<content::WebContentsImpl*>(web_contents_);
+ if (!web_contents) {
+ return;
+ }
+
+ const gfx::Point client_pt(event.x, event.y);
+ const gfx::Point& screen_pt =
+ GetScreenPoint(client_pt, /*want_dip_coords=*/false);
+
+ gfx::PointF transformed_pt;
+ content::RenderWidgetHostImpl* target_rwh =
+ web_contents->GetInputEventRouter()->GetRenderWidgetHostAtPoint(
+ web_contents->GetRenderViewHost()->GetWidget()->GetView(),
+ gfx::PointF(client_pt), &transformed_pt);
+
+ if (target_rwh != current_rwh_for_drag_.get()) {
+ if (current_rwh_for_drag_) {
+ gfx::PointF transformed_leave_point(client_pt);
+ gfx::PointF transformed_screen_point(screen_pt);
+ static_cast<content::RenderWidgetHostViewBase*>(
+ web_contents->GetRenderWidgetHostView())
+ ->TransformPointToCoordSpaceForView(
+ gfx::PointF(client_pt),
+ static_cast<content::RenderWidgetHostViewBase*>(
+ current_rwh_for_drag_->GetView()),
+ &transformed_leave_point);
+ static_cast<content::RenderWidgetHostViewBase*>(
+ web_contents->GetRenderWidgetHostView())
+ ->TransformPointToCoordSpaceForView(
+ gfx::PointF(screen_pt),
+ static_cast<content::RenderWidgetHostViewBase*>(
+ current_rwh_for_drag_->GetView()),
+ &transformed_screen_point);
+ current_rwh_for_drag_->DragTargetDragLeave(transformed_leave_point,
+ transformed_screen_point);
+ }
+ DragTargetDragEnter(drag_data_, event, drag_allowed_ops_);
+ }
+
+ if (!drag_data_) {
+ return;
+ }
+
+ blink::DragOperationsMask ops =
+ static_cast<blink::DragOperationsMask>(allowed_ops);
+ int modifiers = TranslateWebEventModifiers(event.modifiers);
+
+ target_rwh->DragTargetDragOver(transformed_pt, gfx::PointF(screen_pt), ops,
+ modifiers, base::DoNothing());
+}
+
+void CefBrowserPlatformDelegateOsr::DragTargetDragLeave() {
+ if (current_rvh_for_drag_ != web_contents_->GetRenderViewHost() ||
+ !drag_data_) {
+ return;
+ }
+
+ if (current_rwh_for_drag_) {
+ current_rwh_for_drag_->DragTargetDragLeave(gfx::PointF(), gfx::PointF());
+ current_rwh_for_drag_.reset();
+ }
+
+ drag_data_ = nullptr;
+}
+
+void CefBrowserPlatformDelegateOsr::DragTargetDrop(const CefMouseEvent& event) {
+ if (!drag_data_) {
+ return;
+ }
+
+ content::WebContentsImpl* web_contents =
+ static_cast<content::WebContentsImpl*>(web_contents_);
+ if (!web_contents) {
+ return;
+ }
+
+ gfx::Point client_pt(event.x, event.y);
+ const gfx::Point& screen_pt =
+ GetScreenPoint(client_pt, /*want_dip_coords=*/false);
+
+ gfx::PointF transformed_pt;
+ content::RenderWidgetHostImpl* target_rwh =
+ web_contents->GetInputEventRouter()->GetRenderWidgetHostAtPoint(
+ web_contents->GetRenderViewHost()->GetWidget()->GetView(),
+ gfx::PointF(client_pt), &transformed_pt);
+
+ if (target_rwh != current_rwh_for_drag_.get()) {
+ if (current_rwh_for_drag_) {
+ gfx::PointF transformed_leave_point(client_pt);
+ gfx::PointF transformed_screen_point(screen_pt);
+ static_cast<content::RenderWidgetHostViewBase*>(
+ web_contents->GetRenderWidgetHostView())
+ ->TransformPointToCoordSpaceForView(
+ gfx::PointF(client_pt),
+ static_cast<content::RenderWidgetHostViewBase*>(
+ current_rwh_for_drag_->GetView()),
+ &transformed_leave_point);
+ static_cast<content::RenderWidgetHostViewBase*>(
+ web_contents->GetRenderWidgetHostView())
+ ->TransformPointToCoordSpaceForView(
+ gfx::PointF(screen_pt),
+ static_cast<content::RenderWidgetHostViewBase*>(
+ current_rwh_for_drag_->GetView()),
+ &transformed_screen_point);
+ current_rwh_for_drag_->DragTargetDragLeave(transformed_leave_point,
+ transformed_screen_point);
+ }
+ DragTargetDragEnter(drag_data_, event, drag_allowed_ops_);
+ }
+
+ if (!drag_data_) {
+ return;
+ }
+
+ {
+ CefDragDataImpl* data_impl =
+ static_cast<CefDragDataImpl*>(drag_data_.get());
+ base::AutoLock lock_scope(data_impl->lock());
+ content::DropData* drop_data = data_impl->drop_data();
+ int modifiers = TranslateWebEventModifiers(event.modifiers);
+
+ target_rwh->DragTargetDrop(*drop_data, transformed_pt,
+ gfx::PointF(screen_pt), modifiers,
+ base::DoNothing());
+ }
+
+ drag_data_ = nullptr;
+}
+
+void CefBrowserPlatformDelegateOsr::StartDragging(
+ const content::DropData& drop_data,
+ blink::DragOperationsMask allowed_ops,
+ const gfx::ImageSkia& image,
+ const gfx::Vector2d& image_offset,
+ const blink::mojom::DragEventSourceInfo& event_info,
+ content::RenderWidgetHostImpl* source_rwh) {
+ drag_start_rwh_ = source_rwh->GetWeakPtr();
+
+ bool handled = false;
+
+ CefRefPtr<CefRenderHandler> handler =
+ browser_->GetClient()->GetRenderHandler();
+ if (handler.get()) {
+ CefRefPtr<CefImage> cef_image(new CefImageImpl(image));
+ CefPoint cef_image_pos(image_offset.x(), image_offset.y());
+ CefRefPtr<CefDragDataImpl> drag_data(
+ new CefDragDataImpl(drop_data, cef_image, cef_image_pos));
+ drag_data->SetReadOnly(true);
+ base::CurrentThread::ScopedAllowApplicationTasksInNativeNestedLoop allow;
+ handled = handler->StartDragging(
+ browser_, drag_data.get(),
+ static_cast<CefRenderHandler::DragOperationsMask>(allowed_ops),
+ event_info.location.x(), event_info.location.y());
+ }
+
+ if (!handled) {
+ DragSourceSystemDragEnded();
+ }
+}
+
+void CefBrowserPlatformDelegateOsr::UpdateDragCursor(
+ ui::mojom::DragOperation operation) {
+ CefRefPtr<CefRenderHandler> handler =
+ browser_->GetClient()->GetRenderHandler();
+ if (handler.get()) {
+ handler->UpdateDragCursor(
+ browser_, static_cast<CefRenderHandler::DragOperation>(operation));
+ }
+}
+
+void CefBrowserPlatformDelegateOsr::DragSourceEndedAt(
+ int x,
+ int y,
+ cef_drag_operations_mask_t op) {
+ if (!drag_start_rwh_) {
+ return;
+ }
+
+ content::WebContentsImpl* web_contents =
+ static_cast<content::WebContentsImpl*>(web_contents_);
+ if (!web_contents) {
+ return;
+ }
+
+ content::RenderWidgetHostImpl* source_rwh = drag_start_rwh_.get();
+ const gfx::Point client_loc(gfx::Point(x, y));
+ const gfx::Point& screen_loc =
+ GetScreenPoint(client_loc, /*want_dip_coords=*/false);
+ ui::mojom::DragOperation drag_op = static_cast<ui::mojom::DragOperation>(op);
+
+ // |client_loc| and |screen_loc| are in the root coordinate space, for
+ // non-root RenderWidgetHosts they need to be transformed.
+ gfx::PointF transformed_point(client_loc);
+ gfx::PointF transformed_screen_point(screen_loc);
+ if (source_rwh && web_contents->GetRenderWidgetHostView()) {
+ static_cast<content::RenderWidgetHostViewBase*>(
+ web_contents->GetRenderWidgetHostView())
+ ->TransformPointToCoordSpaceForView(
+ gfx::PointF(client_loc),
+ static_cast<content::RenderWidgetHostViewBase*>(
+ source_rwh->GetView()),
+ &transformed_point);
+ static_cast<content::RenderWidgetHostViewBase*>(
+ web_contents->GetRenderWidgetHostView())
+ ->TransformPointToCoordSpaceForView(
+ gfx::PointF(screen_loc),
+ static_cast<content::RenderWidgetHostViewBase*>(
+ source_rwh->GetView()),
+ &transformed_screen_point);
+ }
+
+ web_contents->DragSourceEndedAt(transformed_point.x(), transformed_point.y(),
+ transformed_screen_point.x(),
+ transformed_screen_point.y(), drag_op,
+ source_rwh);
+}
+
+void CefBrowserPlatformDelegateOsr::DragSourceSystemDragEnded() {
+ if (!drag_start_rwh_) {
+ return;
+ }
+
+ content::WebContentsImpl* web_contents =
+ static_cast<content::WebContentsImpl*>(web_contents_);
+ if (!web_contents) {
+ return;
+ }
+
+ web_contents->SystemDragEnded(drag_start_rwh_.get());
+
+ drag_start_rwh_ = nullptr;
+}
+
+void CefBrowserPlatformDelegateOsr::AccessibilityEventReceived(
+ const content::AXEventNotificationDetails& eventData) {
+ CefRefPtr<CefRenderHandler> handler = browser_->client()->GetRenderHandler();
+ if (handler.get()) {
+ CefRefPtr<CefAccessibilityHandler> acchandler =
+ handler->GetAccessibilityHandler();
+
+ if (acchandler.get()) {
+ acchandler->OnAccessibilityTreeChange(
+ osr_accessibility_util::ParseAccessibilityEventData(eventData));
+ }
+ }
+}
+
+void CefBrowserPlatformDelegateOsr::AccessibilityLocationChangesReceived(
+ const std::vector<content::AXLocationChangeNotificationDetails>& locData) {
+ CefRefPtr<CefRenderHandler> handler = browser_->client()->GetRenderHandler();
+ if (handler.get()) {
+ CefRefPtr<CefAccessibilityHandler> acchandler =
+ handler->GetAccessibilityHandler();
+
+ if (acchandler.get()) {
+ acchandler->OnAccessibilityLocationChange(
+ osr_accessibility_util::ParseAccessibilityLocationData(locData));
+ }
+ }
+}
+
+CefWindowHandle CefBrowserPlatformDelegateOsr::GetParentWindowHandle() const {
+ return GetHostWindowHandle();
+}
+
+gfx::Point CefBrowserPlatformDelegateOsr::GetParentScreenPoint(
+ const gfx::Point& view,
+ bool want_dip_coords) const {
+ return GetScreenPoint(view, want_dip_coords);
+}
+
+CefRenderWidgetHostViewOSR* CefBrowserPlatformDelegateOsr::GetOSRHostView()
+ const {
+ content::RenderViewHost* host = web_contents_->GetRenderViewHost();
+ if (host) {
+ return static_cast<CefRenderWidgetHostViewOSR*>(
+ host->GetWidget()->GetView());
+ }
+
+ return nullptr;
+}
diff --git a/libcef/browser/osr/browser_platform_delegate_osr.h b/libcef/browser/osr/browser_platform_delegate_osr.h
new file mode 100644
index 00000000..dac93134
--- /dev/null
+++ b/libcef/browser/osr/browser_platform_delegate_osr.h
@@ -0,0 +1,135 @@
+// Copyright 2015 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_OSR_BROWSER_PLATFORM_DELEGATE_OSR_H_
+#define CEF_LIBCEF_BROWSER_OSR_BROWSER_PLATFORM_DELEGATE_OSR_H_
+
+#include "libcef/browser/alloy/browser_platform_delegate_alloy.h"
+#include "libcef/browser/native/browser_platform_delegate_native.h"
+
+class CefRenderWidgetHostViewOSR;
+class CefWebContentsViewOSR;
+
+namespace content {
+class RenderWidgetHostImpl;
+} // namespace content
+
+// Base implementation of windowless browser functionality.
+class CefBrowserPlatformDelegateOsr
+ : public CefBrowserPlatformDelegateAlloy,
+ public CefBrowserPlatformDelegateNative::WindowlessHandler {
+ public:
+ // CefBrowserPlatformDelegate methods:
+ void CreateViewForWebContents(
+ content::WebContentsView** view,
+ content::RenderViewHostDelegateView** delegate_view) override;
+ void WebContentsCreated(content::WebContents* web_contents,
+ bool owned) override;
+ void RenderViewCreated(content::RenderViewHost* render_view_host) override;
+ void BrowserCreated(CefBrowserHostBase* browser) override;
+ void NotifyBrowserDestroyed() override;
+ void BrowserDestroyed(CefBrowserHostBase* browser) override;
+ SkColor GetBackgroundColor() const override;
+ void WasResized() override;
+ void SendKeyEvent(const CefKeyEvent& event) override;
+ void SendMouseClickEvent(const CefMouseEvent& event,
+ CefBrowserHost::MouseButtonType type,
+ bool mouseUp,
+ int clickCount) override;
+ void SendMouseMoveEvent(const CefMouseEvent& event, bool mouseLeave) override;
+ void SendMouseWheelEvent(const CefMouseEvent& event,
+ int deltaX,
+ int deltaY) override;
+ void SendTouchEvent(const CefTouchEvent& event) override;
+ void SetFocus(bool setFocus) override;
+ gfx::Point GetScreenPoint(const gfx::Point& view,
+ bool want_dip_coords) const override;
+ void ViewText(const std::string& text) override;
+ bool HandleKeyboardEvent(
+ const content::NativeWebKeyboardEvent& event) override;
+ CefEventHandle GetEventHandle(
+ const content::NativeWebKeyboardEvent& event) const override;
+ std::unique_ptr<CefJavaScriptDialogRunner> CreateJavaScriptDialogRunner()
+ override;
+ std::unique_ptr<CefMenuRunner> CreateMenuRunner() override;
+ bool IsWindowless() const override;
+ void WasHidden(bool hidden) override;
+ bool IsHidden() const override;
+ void NotifyScreenInfoChanged() override;
+ void Invalidate(cef_paint_element_type_t type) override;
+ void SendExternalBeginFrame() override;
+ void SetWindowlessFrameRate(int frame_rate) override;
+ void ImeSetComposition(const CefString& text,
+ const std::vector<CefCompositionUnderline>& underlines,
+ const CefRange& replacement_range,
+ const CefRange& selection_range) override;
+ void ImeCommitText(const CefString& text,
+ const CefRange& replacement_range,
+ int relative_cursor_pos) override;
+ void ImeFinishComposingText(bool keep_selection) override;
+ void ImeCancelComposition() override;
+ void DragTargetDragEnter(CefRefPtr<CefDragData> drag_data,
+ const CefMouseEvent& event,
+ cef_drag_operations_mask_t allowed_ops) override;
+ void DragTargetDragOver(const CefMouseEvent& event,
+ cef_drag_operations_mask_t allowed_ops) override;
+ void DragTargetDragLeave() override;
+ void DragTargetDrop(const CefMouseEvent& event) override;
+ void StartDragging(const content::DropData& drop_data,
+ blink::DragOperationsMask allowed_ops,
+ const gfx::ImageSkia& image,
+ const gfx::Vector2d& image_offset,
+ const blink::mojom::DragEventSourceInfo& event_info,
+ content::RenderWidgetHostImpl* source_rwh) override;
+ void UpdateDragCursor(ui::mojom::DragOperation operation) override;
+ void DragSourceEndedAt(int x, int y, cef_drag_operations_mask_t op) override;
+ void DragSourceSystemDragEnded() override;
+ void AccessibilityEventReceived(
+ const content::AXEventNotificationDetails& eventData) override;
+ void AccessibilityLocationChangesReceived(
+ const std::vector<content::AXLocationChangeNotificationDetails>& locData)
+ override;
+
+ // CefBrowserPlatformDelegateNative::WindowlessHandler methods:
+ CefWindowHandle GetParentWindowHandle() const override;
+ gfx::Point GetParentScreenPoint(const gfx::Point& view,
+ bool want_dip_coords) const override;
+
+ protected:
+ // Platform-specific behaviors will be delegated to |native_delegate|.
+ CefBrowserPlatformDelegateOsr(
+ std::unique_ptr<CefBrowserPlatformDelegateNative> native_delegate,
+ bool use_shared_texture,
+ bool use_external_begin_frame);
+
+ // Returns the primary OSR host view for the underlying browser. If a
+ // full-screen host view currently exists then it will be returned. Otherwise,
+ // the main host view will be returned.
+ CefRenderWidgetHostViewOSR* GetOSRHostView() const;
+
+ std::unique_ptr<CefBrowserPlatformDelegateNative> native_delegate_;
+ const bool use_shared_texture_;
+ const bool use_external_begin_frame_;
+
+ CefWebContentsViewOSR* view_osr_ = nullptr; // Not owned by this class.
+
+ // Pending drag/drop data.
+ CefRefPtr<CefDragData> drag_data_;
+ cef_drag_operations_mask_t drag_allowed_ops_;
+
+ // We keep track of the RenderWidgetHost we're dragging over. If it changes
+ // during a drag, we need to re-send the DragEnter message.
+ base::WeakPtr<content::RenderWidgetHostImpl> current_rwh_for_drag_;
+
+ // We also keep track of the RenderViewHost we're dragging over to avoid
+ // sending the drag exited message after leaving the current
+ // view. |current_rvh_for_drag_| should not be dereferenced.
+ void* current_rvh_for_drag_;
+
+ // We keep track of the RenderWidgetHost from which the current drag started,
+ // in order to properly route the drag end message to it.
+ base::WeakPtr<content::RenderWidgetHostImpl> drag_start_rwh_;
+};
+
+#endif // CEF_LIBCEF_BROWSER_OSR_BROWSER_PLATFORM_DELEGATE_OSR_H_
diff --git a/libcef/browser/osr/browser_platform_delegate_osr_linux.cc b/libcef/browser/osr/browser_platform_delegate_osr_linux.cc
new file mode 100644
index 00000000..0834e645
--- /dev/null
+++ b/libcef/browser/osr/browser_platform_delegate_osr_linux.cc
@@ -0,0 +1,19 @@
+// Copyright 2015 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/osr/browser_platform_delegate_osr_linux.h"
+
+#include <utility>
+
+CefBrowserPlatformDelegateOsrLinux::CefBrowserPlatformDelegateOsrLinux(
+ std::unique_ptr<CefBrowserPlatformDelegateNative> native_delegate,
+ bool use_external_begin_frame)
+ : CefBrowserPlatformDelegateOsr(std::move(native_delegate),
+ /*use_shared_texture=*/false,
+ use_external_begin_frame) {}
+
+CefWindowHandle CefBrowserPlatformDelegateOsrLinux::GetHostWindowHandle()
+ const {
+ return native_delegate_->window_info().parent_window;
+}
diff --git a/libcef/browser/osr/browser_platform_delegate_osr_linux.h b/libcef/browser/osr/browser_platform_delegate_osr_linux.h
new file mode 100644
index 00000000..071a2cdd
--- /dev/null
+++ b/libcef/browser/osr/browser_platform_delegate_osr_linux.h
@@ -0,0 +1,22 @@
+// Copyright 2015 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_OSR_BROWSER_PLATFORM_DELEGATE_OSR_LINUX_H_
+#define CEF_LIBCEF_BROWSER_OSR_BROWSER_PLATFORM_DELEGATE_OSR_LINUX_H_
+
+#include "libcef/browser/osr/browser_platform_delegate_osr.h"
+
+// Windowless browser implementation for Linux.
+class CefBrowserPlatformDelegateOsrLinux
+ : public CefBrowserPlatformDelegateOsr {
+ public:
+ CefBrowserPlatformDelegateOsrLinux(
+ std::unique_ptr<CefBrowserPlatformDelegateNative> native_delegate,
+ bool use_external_begin_frame);
+
+ // CefBrowserPlatformDelegate methods:
+ CefWindowHandle GetHostWindowHandle() const override;
+};
+
+#endif // CEF_LIBCEF_BROWSER_NATIVE_BROWSER_PLATFORM_DELEGATE_OSR_LINUX_H_
diff --git a/libcef/browser/osr/browser_platform_delegate_osr_mac.h b/libcef/browser/osr/browser_platform_delegate_osr_mac.h
new file mode 100644
index 00000000..923e3c40
--- /dev/null
+++ b/libcef/browser/osr/browser_platform_delegate_osr_mac.h
@@ -0,0 +1,20 @@
+// Copyright 2015 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_OSR_BROWSER_PLATFORM_DELEGATE_OSR_MAC_H_
+#define CEF_LIBCEF_BROWSER_OSR_BROWSER_PLATFORM_DELEGATE_OSR_MAC_H_
+
+#include "libcef/browser/osr/browser_platform_delegate_osr.h"
+
+// Windowless browser implementation for Mac OS X.
+class CefBrowserPlatformDelegateOsrMac : public CefBrowserPlatformDelegateOsr {
+ public:
+ explicit CefBrowserPlatformDelegateOsrMac(
+ std::unique_ptr<CefBrowserPlatformDelegateNative> native_delegate);
+
+ // CefBrowserPlatformDelegate methods:
+ CefWindowHandle GetHostWindowHandle() const override;
+};
+
+#endif // CEF_LIBCEF_BROWSER_NATIVE_BROWSER_PLATFORM_DELEGATE_OSR_MAC_H_
diff --git a/libcef/browser/osr/browser_platform_delegate_osr_mac.mm b/libcef/browser/osr/browser_platform_delegate_osr_mac.mm
new file mode 100644
index 00000000..d67734ff
--- /dev/null
+++ b/libcef/browser/osr/browser_platform_delegate_osr_mac.mm
@@ -0,0 +1,17 @@
+// Copyright 2015 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/osr/browser_platform_delegate_osr_mac.h"
+
+#include <utility>
+
+CefBrowserPlatformDelegateOsrMac::CefBrowserPlatformDelegateOsrMac(
+ std::unique_ptr<CefBrowserPlatformDelegateNative> native_delegate)
+ : CefBrowserPlatformDelegateOsr(std::move(native_delegate),
+ /*use_shared_texture=*/false,
+ /*use_external_begin_frame=*/false) {}
+
+CefWindowHandle CefBrowserPlatformDelegateOsrMac::GetHostWindowHandle() const {
+ return native_delegate_->window_info().parent_view;
+}
diff --git a/libcef/browser/osr/browser_platform_delegate_osr_win.cc b/libcef/browser/osr/browser_platform_delegate_osr_win.cc
new file mode 100644
index 00000000..9307bac5
--- /dev/null
+++ b/libcef/browser/osr/browser_platform_delegate_osr_win.cc
@@ -0,0 +1,19 @@
+// Copyright 2015 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/osr/browser_platform_delegate_osr_win.h"
+
+#include <utility>
+
+CefBrowserPlatformDelegateOsrWin::CefBrowserPlatformDelegateOsrWin(
+ std::unique_ptr<CefBrowserPlatformDelegateNative> native_delegate,
+ bool use_shared_texture,
+ bool use_external_begin_frame)
+ : CefBrowserPlatformDelegateOsr(std::move(native_delegate),
+ use_shared_texture,
+ use_external_begin_frame) {}
+
+CefWindowHandle CefBrowserPlatformDelegateOsrWin::GetHostWindowHandle() const {
+ return native_delegate_->window_info().parent_window;
+}
diff --git a/libcef/browser/osr/browser_platform_delegate_osr_win.h b/libcef/browser/osr/browser_platform_delegate_osr_win.h
new file mode 100644
index 00000000..8c07a153
--- /dev/null
+++ b/libcef/browser/osr/browser_platform_delegate_osr_win.h
@@ -0,0 +1,22 @@
+// Copyright 2015 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_OSR_BROWSER_PLATFORM_DELEGATE_OSR_WIN_H_
+#define CEF_LIBCEF_BROWSER_OSR_BROWSER_PLATFORM_DELEGATE_OSR_WIN_H_
+
+#include "libcef/browser/osr/browser_platform_delegate_osr.h"
+
+// Windowless browser implementation for Windows.
+class CefBrowserPlatformDelegateOsrWin : public CefBrowserPlatformDelegateOsr {
+ public:
+ explicit CefBrowserPlatformDelegateOsrWin(
+ std::unique_ptr<CefBrowserPlatformDelegateNative> native_delegate,
+ bool use_shared_texture,
+ bool use_external_begin_frame);
+
+ // CefBrowserPlatformDelegate methods:
+ CefWindowHandle GetHostWindowHandle() const override;
+};
+
+#endif // CEF_LIBCEF_BROWSER_NATIVE_BROWSER_PLATFORM_DELEGATE_OSR_WIN_H_
diff --git a/libcef/browser/osr/host_display_client_osr.cc b/libcef/browser/osr/host_display_client_osr.cc
new file mode 100644
index 00000000..937f6bbd
--- /dev/null
+++ b/libcef/browser/osr/host_display_client_osr.cc
@@ -0,0 +1,143 @@
+// Copyright 2019 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/osr/host_display_client_osr.h"
+
+#include <utility>
+
+#include "libcef/browser/osr/render_widget_host_view_osr.h"
+
+#include "base/memory/shared_memory_mapping.h"
+#include "components/viz/common/resources/resource_format.h"
+#include "components/viz/common/resources/resource_sizes.h"
+#include "mojo/public/cpp/system/platform_handle.h"
+#include "services/viz/privileged/mojom/compositing/layered_window_updater.mojom.h"
+#include "skia/ext/platform_canvas.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "third_party/skia/include/core/SkRect.h"
+#include "third_party/skia/src/core/SkDevice.h"
+#include "ui/gfx/skia_util.h"
+
+#if BUILDFLAG(IS_WIN)
+#include "skia/ext/skia_utils_win.h"
+#endif
+
+class CefLayeredWindowUpdaterOSR : public viz::mojom::LayeredWindowUpdater {
+ public:
+ CefLayeredWindowUpdaterOSR(
+ CefRenderWidgetHostViewOSR* const view,
+ mojo::PendingReceiver<viz::mojom::LayeredWindowUpdater> receiver);
+
+ CefLayeredWindowUpdaterOSR(const CefLayeredWindowUpdaterOSR&) = delete;
+ CefLayeredWindowUpdaterOSR& operator=(const CefLayeredWindowUpdaterOSR&) =
+ delete;
+
+ ~CefLayeredWindowUpdaterOSR() override;
+
+ void SetActive(bool active);
+ const void* GetPixelMemory() const;
+ gfx::Size GetPixelSize() const;
+
+ // viz::mojom::LayeredWindowUpdater implementation.
+ void OnAllocatedSharedMemory(const gfx::Size& pixel_size,
+ base::UnsafeSharedMemoryRegion region) override;
+ void Draw(const gfx::Rect& damage_rect, DrawCallback draw_callback) override;
+
+ private:
+ CefRenderWidgetHostViewOSR* const view_;
+ mojo::Receiver<viz::mojom::LayeredWindowUpdater> receiver_;
+ bool active_ = false;
+ base::WritableSharedMemoryMapping shared_memory_;
+ gfx::Size pixel_size_;
+};
+
+CefLayeredWindowUpdaterOSR::CefLayeredWindowUpdaterOSR(
+ CefRenderWidgetHostViewOSR* const view,
+ mojo::PendingReceiver<viz::mojom::LayeredWindowUpdater> receiver)
+ : view_(view), receiver_(this, std::move(receiver)) {}
+
+CefLayeredWindowUpdaterOSR::~CefLayeredWindowUpdaterOSR() = default;
+
+void CefLayeredWindowUpdaterOSR::SetActive(bool active) {
+ active_ = active;
+}
+
+const void* CefLayeredWindowUpdaterOSR::GetPixelMemory() const {
+ return shared_memory_.memory();
+}
+
+gfx::Size CefLayeredWindowUpdaterOSR::GetPixelSize() const {
+ return pixel_size_;
+}
+
+void CefLayeredWindowUpdaterOSR::OnAllocatedSharedMemory(
+ const gfx::Size& pixel_size,
+ base::UnsafeSharedMemoryRegion region) {
+ // Make sure |pixel_size| is sane.
+ size_t expected_bytes;
+ bool size_result = viz::ResourceSizes::MaybeSizeInBytes(
+ pixel_size, viz::ResourceFormat::RGBA_8888, &expected_bytes);
+ if (!size_result) {
+ return;
+ }
+
+ pixel_size_ = pixel_size;
+ shared_memory_ = region.Map();
+ DCHECK(shared_memory_.IsValid());
+}
+
+void CefLayeredWindowUpdaterOSR::Draw(const gfx::Rect& damage_rect,
+ DrawCallback draw_callback) {
+ if (active_) {
+ const void* memory = GetPixelMemory();
+ if (memory) {
+ view_->OnPaint(damage_rect, pixel_size_, memory);
+ } else {
+ LOG(WARNING) << "Failed to read pixels";
+ }
+ }
+
+ std::move(draw_callback).Run();
+}
+
+CefHostDisplayClientOSR::CefHostDisplayClientOSR(
+ CefRenderWidgetHostViewOSR* const view,
+ gfx::AcceleratedWidget widget)
+ : viz::HostDisplayClient(widget), view_(view) {}
+
+CefHostDisplayClientOSR::~CefHostDisplayClientOSR() {}
+
+void CefHostDisplayClientOSR::SetActive(bool active) {
+ active_ = active;
+ if (layered_window_updater_) {
+ layered_window_updater_->SetActive(active_);
+ }
+}
+
+const void* CefHostDisplayClientOSR::GetPixelMemory() const {
+ return layered_window_updater_ ? layered_window_updater_->GetPixelMemory()
+ : nullptr;
+}
+
+gfx::Size CefHostDisplayClientOSR::GetPixelSize() const {
+ return layered_window_updater_ ? layered_window_updater_->GetPixelSize()
+ : gfx::Size{};
+}
+
+void CefHostDisplayClientOSR::UseProxyOutputDevice(
+ UseProxyOutputDeviceCallback callback) {
+ std::move(callback).Run(true);
+}
+
+void CefHostDisplayClientOSR::CreateLayeredWindowUpdater(
+ mojo::PendingReceiver<viz::mojom::LayeredWindowUpdater> receiver) {
+ layered_window_updater_ =
+ std::make_unique<CefLayeredWindowUpdaterOSR>(view_, std::move(receiver));
+ layered_window_updater_->SetActive(active_);
+}
+
+#if BUILDFLAG(IS_LINUX)
+void CefHostDisplayClientOSR::DidCompleteSwapWithNewSize(
+ const gfx::Size& size) {}
+#endif
diff --git a/libcef/browser/osr/host_display_client_osr.h b/libcef/browser/osr/host_display_client_osr.h
new file mode 100644
index 00000000..c0987f8d
--- /dev/null
+++ b/libcef/browser/osr/host_display_client_osr.h
@@ -0,0 +1,49 @@
+// Copyright 2019 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_OSR_HOST_DISPLAY_CLIENT_OSR_H_
+#define CEF_LIBCEF_BROWSER_OSR_HOST_DISPLAY_CLIENT_OSR_H_
+
+#include <memory>
+
+#include "base/functional/callback.h"
+#include "base/memory/shared_memory_mapping.h"
+#include "components/viz/host/host_display_client.h"
+#include "ui/gfx/native_widget_types.h"
+
+class CefLayeredWindowUpdaterOSR;
+class CefRenderWidgetHostViewOSR;
+
+class CefHostDisplayClientOSR : public viz::HostDisplayClient {
+ public:
+ CefHostDisplayClientOSR(CefRenderWidgetHostViewOSR* const view,
+ gfx::AcceleratedWidget widget);
+
+ CefHostDisplayClientOSR(const CefHostDisplayClientOSR&) = delete;
+ CefHostDisplayClientOSR& operator=(const CefHostDisplayClientOSR&) = delete;
+
+ ~CefHostDisplayClientOSR() override;
+
+ void SetActive(bool active);
+ const void* GetPixelMemory() const;
+ gfx::Size GetPixelSize() const;
+
+ private:
+ // mojom::DisplayClient implementation.
+ void UseProxyOutputDevice(UseProxyOutputDeviceCallback callback) override;
+
+ void CreateLayeredWindowUpdater(
+ mojo::PendingReceiver<viz::mojom::LayeredWindowUpdater> receiver)
+ override;
+
+#if BUILDFLAG(IS_LINUX)
+ void DidCompleteSwapWithNewSize(const gfx::Size& size) override;
+#endif
+
+ CefRenderWidgetHostViewOSR* const view_;
+ std::unique_ptr<CefLayeredWindowUpdaterOSR> layered_window_updater_;
+ bool active_ = false;
+};
+
+#endif // CEF_LIBCEF_BROWSER_OSR_HOST_DISPLAY_CLIENT_OSR_H_
diff --git a/libcef/browser/osr/motion_event_osr.cc b/libcef/browser/osr/motion_event_osr.cc
new file mode 100644
index 00000000..69d4b80a
--- /dev/null
+++ b/libcef/browser/osr/motion_event_osr.cc
@@ -0,0 +1,259 @@
+// Copyright (c) 2017 The Chromium Embedded Framework Authors.
+// Portions copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/osr/motion_event_osr.h"
+
+#include <algorithm>
+
+#include "ui/events/base_event_utils.h"
+#include "ui/events/gesture_detection/gesture_configuration.h"
+
+namespace {
+
+ui::MotionEvent::ToolType CefPointerTypeToMotionEventToolType(
+ cef_pointer_type_t pointer_type) {
+ switch (pointer_type) {
+ case CEF_POINTER_TYPE_TOUCH:
+ return ui::MotionEvent::ToolType::FINGER;
+ case CEF_POINTER_TYPE_MOUSE:
+ return ui::MotionEvent::ToolType::MOUSE;
+ case CEF_POINTER_TYPE_PEN:
+ return ui::MotionEvent::ToolType::STYLUS;
+ case CEF_POINTER_TYPE_ERASER:
+ return ui::MotionEvent::ToolType::ERASER;
+ case CEF_POINTER_TYPE_UNKNOWN:
+ return ui::MotionEvent::ToolType::UNKNOWN;
+ }
+ NOTREACHED();
+ return ui::MotionEvent::ToolType::UNKNOWN;
+}
+
+} // namespace
+
+CefMotionEventOSR::CefMotionEventOSR() {
+ std::fill(id_map_, id_map_ + blink::WebTouchEvent::kTouchesLengthCap, -1);
+}
+
+CefMotionEventOSR::~CefMotionEventOSR() {}
+
+int CefMotionEventOSR::GetSourceDeviceId(size_t pointer_index) const {
+ if (IsValidIndex(pointer_index)) {
+ return pointer(pointer_index).source_device_id;
+ } else {
+ return -1;
+ }
+}
+
+// Returns true if the touch was valid.
+bool CefMotionEventOSR::OnTouch(const CefTouchEvent& touch) {
+ int id = LookupId(touch.id);
+ bool pointer_id_is_active = id != -1;
+
+ if (touch.type == CEF_TET_PRESSED && pointer_id_is_active) {
+ // Ignore pressed events for already active touches.
+ return false;
+ } else if (touch.type != CEF_TET_PRESSED && !pointer_id_is_active) {
+ // When a window begins capturing touch events, we could have an active
+ // touch stream transfered to us, resulting in touch move or touch up
+ // events without associated touch down events. Ignore them.
+ return false;
+ }
+
+ switch (touch.type) {
+ case CEF_TET_PRESSED:
+ id = AddId(touch.id);
+ if (id == -1) {
+ return false;
+ }
+ if (!AddTouch(touch, id)) {
+ return false;
+ }
+ break;
+
+ case CEF_TET_MOVED: {
+ // Discard if touch is stationary.
+ int index = FindPointerIndexOfId(id);
+ if (IsValidIndex(index) &&
+ (touch.x == GetX(index) && touch.y == GetY(index))) {
+ return false;
+ }
+ }
+ [[fallthrough]];
+ // No break.
+ case CEF_TET_RELEASED:
+ case CEF_TET_CANCELLED:
+ // Removing these touch points needs to be postponed until after the
+ // MotionEvent has been dispatched. This cleanup occurs in
+ // CleanupRemovedTouchPoints.
+ UpdateTouch(touch, id);
+ break;
+ }
+
+ UpdateCachedAction(touch, id);
+ set_unique_event_id(ui::GetNextTouchEventId());
+ set_flags(touch.modifiers);
+ set_event_time(base::TimeTicks::Now());
+ return true;
+}
+
+// We can't cleanup removed touch points immediately upon receipt of a
+// TouchCancel or TouchRelease, as the MotionEvent needs to be able to report
+// information about those touch events. Once the MotionEvent has been
+// processed, we call CleanupRemovedTouchPoints to do the required
+// book-keeping.
+void CefMotionEventOSR::CleanupRemovedTouchPoints(const CefTouchEvent& event) {
+ if (event.type != CEF_TET_RELEASED && event.type != CEF_TET_CANCELLED) {
+ return;
+ }
+
+ DCHECK(GetPointerCount());
+
+ int id = LookupId(event.id);
+ int index_to_delete = FindPointerIndexOfId(id);
+ set_action_index(-1);
+ set_action(ui::MotionEvent::Action::NONE);
+ if (IsValidIndex(index_to_delete)) {
+ pointer(index_to_delete) = pointer(GetPointerCount() - 1);
+ PopPointer();
+ RemoveId(event.id);
+ }
+}
+
+// Reset unchanged touch point to StateStationary for touchmove and touchcancel.
+void CefMotionEventOSR::MarkUnchangedTouchPointsAsStationary(
+ blink::WebTouchEvent* event,
+ const CefTouchEvent& cef_event) {
+ int id = LookupId(cef_event.id);
+ if (event->GetType() == blink::WebInputEvent::Type::kTouchMove ||
+ event->GetType() == blink::WebInputEvent::Type::kTouchCancel) {
+ for (size_t i = 0; i < event->touches_length; ++i) {
+ if (event->touches[i].id != id) {
+ event->touches[i].state = blink::WebTouchPoint::State::kStateStationary;
+ }
+ }
+ }
+}
+
+int CefMotionEventOSR::LookupId(int id) {
+ if (id == -1) {
+ return -1;
+ }
+
+ for (int i = 0; i < blink::WebTouchEvent::kTouchesLengthCap; i++) {
+ if (id_map_[i] == id) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+int CefMotionEventOSR::AddId(int id) {
+ if (id == -1 || LookupId(id) >= 0) {
+ return -1;
+ }
+
+ for (int i = 0; i < blink::WebTouchEvent::kTouchesLengthCap; i++) {
+ if (id_map_[i] == -1) {
+ id_map_[i] = id;
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+void CefMotionEventOSR::RemoveId(int id) {
+ for (int i = 0; i < blink::WebTouchEvent::kTouchesLengthCap; i++) {
+ if (id_map_[i] == id) {
+ id_map_[i] = -1;
+ }
+ }
+}
+
+bool CefMotionEventOSR::AddTouch(const CefTouchEvent& touch, int id) {
+ if (GetPointerCount() == MotionEvent::MAX_TOUCH_POINT_COUNT) {
+ return false;
+ }
+
+ PushPointer(GetPointerPropertiesFromTouchEvent(touch, id));
+ return true;
+}
+
+void CefMotionEventOSR::UpdateTouch(const CefTouchEvent& touch, int id) {
+ int index_to_update = FindPointerIndexOfId(id);
+ if (IsValidIndex(index_to_update)) {
+ pointer(index_to_update) = GetPointerPropertiesFromTouchEvent(touch, id);
+ }
+}
+
+void CefMotionEventOSR::UpdateCachedAction(const CefTouchEvent& touch, int id) {
+ DCHECK(GetPointerCount());
+ switch (touch.type) {
+ case CEF_TET_PRESSED:
+ if (GetPointerCount() == 1) {
+ set_action(ui::MotionEvent::Action::DOWN);
+ } else {
+ set_action(ui::MotionEvent::Action::POINTER_DOWN);
+ set_action_index(FindPointerIndexOfId(id));
+ }
+ break;
+ case CEF_TET_RELEASED:
+ if (GetPointerCount() == 1) {
+ set_action(ui::MotionEvent::Action::UP);
+ } else {
+ set_action(ui::MotionEvent::Action::POINTER_UP);
+ set_action_index(FindPointerIndexOfId(id));
+ }
+ break;
+ case CEF_TET_CANCELLED:
+ set_action(ui::MotionEvent::Action::CANCEL);
+ break;
+ case CEF_TET_MOVED:
+ set_action(ui::MotionEvent::Action::MOVE);
+ break;
+ }
+}
+
+bool CefMotionEventOSR::IsValidIndex(int index) const {
+ return (index >= 0) && (index < static_cast<int>(GetPointerCount()));
+}
+
+ui::PointerProperties CefMotionEventOSR::GetPointerPropertiesFromTouchEvent(
+ const CefTouchEvent& touch,
+ int id) {
+ ui::PointerProperties pointer_properties;
+ pointer_properties.x = touch.x;
+ pointer_properties.y = touch.y;
+ pointer_properties.raw_x = touch.x;
+ pointer_properties.raw_y = touch.y;
+ pointer_properties.id = id;
+ pointer_properties.pressure = touch.pressure;
+ pointer_properties.source_device_id = 0;
+
+ pointer_properties.SetAxesAndOrientation(touch.radius_x, touch.radius_y,
+ touch.rotation_angle);
+ if (!pointer_properties.touch_major) {
+ float default_size;
+ switch (touch.pointer_type) {
+ case CEF_POINTER_TYPE_PEN:
+ case CEF_POINTER_TYPE_ERASER:
+ // Default size for stylus events is 1x1.
+ default_size = 1;
+ break;
+ default:
+ default_size =
+ 2.f * ui::GestureConfiguration::GetInstance()->default_radius();
+ break;
+ }
+ pointer_properties.touch_major = pointer_properties.touch_minor =
+ default_size;
+ pointer_properties.orientation = 0;
+ }
+
+ pointer_properties.tool_type =
+ CefPointerTypeToMotionEventToolType(touch.pointer_type);
+
+ return pointer_properties;
+}
diff --git a/libcef/browser/osr/motion_event_osr.h b/libcef/browser/osr/motion_event_osr.h
new file mode 100644
index 00000000..ffc2402b
--- /dev/null
+++ b/libcef/browser/osr/motion_event_osr.h
@@ -0,0 +1,61 @@
+// Copyright (c) 2017 The Chromium Embedded Framework Authors.
+// Portions copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_OSR_MOTION_EVENT_OSR_H_
+#define CEF_LIBCEF_BROWSER_OSR_MOTION_EVENT_OSR_H_
+#pragma once
+
+#include "include/cef_base.h"
+
+#include "third_party/blink/public/common/input/web_touch_event.h"
+#include "ui/events/gesture_detection/motion_event_generic.h"
+
+// Implementation of MotionEvent which takes a stream of CefTouchEvents.
+// This class is based on ui::MotionEventAura.
+class CefMotionEventOSR : public ui::MotionEventGeneric {
+ public:
+ CefMotionEventOSR();
+
+ CefMotionEventOSR(const CefMotionEventOSR&) = delete;
+ CefMotionEventOSR& operator=(const CefMotionEventOSR&) = delete;
+
+ ~CefMotionEventOSR() override;
+
+ int GetSourceDeviceId(size_t pointer_index) const override;
+
+ // Returns true if the touch was valid.
+ bool OnTouch(const CefTouchEvent& touch);
+
+ // We can't cleanup removed touch points immediately upon receipt of a
+ // TouchCancel or TouchRelease, as the MotionEvent needs to be able to report
+ // information about those touch events. Once the MotionEvent has been
+ // processed, we call CleanupRemovedTouchPoints to do the required
+ // book-keeping.
+ void CleanupRemovedTouchPoints(const CefTouchEvent& event);
+
+ // Reset unchanged touch point to StateStationary for touchmove and
+ // touchcancel to make sure only send one ack per WebTouchEvent.
+ void MarkUnchangedTouchPointsAsStationary(blink::WebTouchEvent* event,
+ const CefTouchEvent& cef_event);
+
+ private:
+ // Chromium can't cope with touch ids >31, so let's map the incoming
+ // ids to a safe range.
+ int id_map_[blink::WebTouchEvent::kTouchesLengthCap];
+
+ int LookupId(int id);
+ int AddId(int id);
+ void RemoveId(int id);
+
+ bool AddTouch(const CefTouchEvent& touch, int id);
+ void UpdateTouch(const CefTouchEvent& touch, int id);
+ void UpdateCachedAction(const CefTouchEvent& touch, int id);
+ bool IsValidIndex(int index) const;
+ ui::PointerProperties GetPointerPropertiesFromTouchEvent(
+ const CefTouchEvent& touch,
+ int id);
+};
+
+#endif
diff --git a/libcef/browser/osr/osr_accessibility_util.cc b/libcef/browser/osr/osr_accessibility_util.cc
new file mode 100644
index 00000000..19d74f64
--- /dev/null
+++ b/libcef/browser/osr/osr_accessibility_util.cc
@@ -0,0 +1,558 @@
+// Copyright 2017 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#include "libcef/browser/osr/osr_accessibility_util.h"
+
+#include <algorithm>
+#include <string>
+#include <utility>
+
+#include "base/json/string_escape.h"
+#include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "content/public/browser/ax_event_notification_details.h"
+#include "ui/accessibility/ax_enum_util.h"
+#include "ui/accessibility/ax_enums.mojom.h"
+#include "ui/accessibility/ax_text_utils.h"
+#include "ui/accessibility/ax_tree_update.h"
+#include "ui/gfx/geometry/transform.h"
+
+namespace {
+using ui::ToString;
+
+template <typename T>
+CefRefPtr<CefListValue> ToCefValue(const std::vector<T>& vecData);
+
+template <>
+CefRefPtr<CefListValue> ToCefValue<int>(const std::vector<int>& vecData) {
+ CefRefPtr<CefListValue> value = CefListValue::Create();
+ for (size_t i = 0; i < vecData.size(); i++) {
+ value->SetInt(i, vecData[i]);
+ }
+
+ return value;
+}
+
+// Helper function for AXNodeData::ToCefValue - Converts AXState attributes to
+// CefListValue.
+CefRefPtr<CefListValue> ToCefValue(uint32_t state) {
+ CefRefPtr<CefListValue> value = CefListValue::Create();
+
+ int index = 0;
+ // Iterate and find which states are set.
+ for (unsigned i = static_cast<unsigned>(ax::mojom::Role::kMinValue) + 1;
+ i <= static_cast<unsigned>(ax::mojom::Role::kMaxValue); i++) {
+ if (state & (1 << i)) {
+ value->SetString(index++, ToString(static_cast<ax::mojom::State>(i)));
+ }
+ }
+ return value;
+}
+
+// Helper function for AXNodeData::ToCefValue - converts GfxRect to
+// CefDictionaryValue.
+CefRefPtr<CefDictionaryValue> ToCefValue(const gfx::RectF& bounds) {
+ CefRefPtr<CefDictionaryValue> value = CefDictionaryValue::Create();
+ value->SetDouble("x", bounds.x());
+ value->SetDouble("y", bounds.y());
+ value->SetDouble("width", bounds.width());
+ value->SetDouble("height", bounds.height());
+ return value;
+}
+
+// Helper Functor for adding AxNodeData::attributes to AXNodeData::ToCefValue.
+struct PopulateAxNodeAttributes {
+ CefRefPtr<CefDictionaryValue> attributes;
+
+ explicit PopulateAxNodeAttributes(CefRefPtr<CefDictionaryValue> attrs)
+ : attributes(attrs) {}
+
+ // Int Attributes
+ void operator()(const std::pair<ax::mojom::IntAttribute, int32_t> attr) {
+ if (attr.first == ax::mojom::IntAttribute::kNone) {
+ return;
+ }
+
+ switch (attr.first) {
+ case ax::mojom::IntAttribute::kNone:
+ break;
+ case ax::mojom::IntAttribute::kScrollX:
+ case ax::mojom::IntAttribute::kScrollXMin:
+ case ax::mojom::IntAttribute::kScrollXMax:
+ case ax::mojom::IntAttribute::kScrollY:
+ case ax::mojom::IntAttribute::kScrollYMin:
+ case ax::mojom::IntAttribute::kScrollYMax:
+ case ax::mojom::IntAttribute::kHasPopup:
+ case ax::mojom::IntAttribute::kIsPopup:
+ case ax::mojom::IntAttribute::kHierarchicalLevel:
+ case ax::mojom::IntAttribute::kTextSelStart:
+ case ax::mojom::IntAttribute::kTextSelEnd:
+ case ax::mojom::IntAttribute::kAriaColumnCount:
+ case ax::mojom::IntAttribute::kAriaCellColumnIndex:
+ case ax::mojom::IntAttribute::kAriaRowCount:
+ case ax::mojom::IntAttribute::kAriaCellRowIndex:
+ case ax::mojom::IntAttribute::kTableRowCount:
+ case ax::mojom::IntAttribute::kTableColumnCount:
+ case ax::mojom::IntAttribute::kTableCellColumnIndex:
+ case ax::mojom::IntAttribute::kTableCellRowIndex:
+ case ax::mojom::IntAttribute::kTableCellColumnSpan:
+ case ax::mojom::IntAttribute::kTableCellRowSpan:
+ case ax::mojom::IntAttribute::kTableColumnHeaderId:
+ case ax::mojom::IntAttribute::kTableColumnIndex:
+ case ax::mojom::IntAttribute::kTableHeaderId:
+ case ax::mojom::IntAttribute::kTableRowHeaderId:
+ case ax::mojom::IntAttribute::kTableRowIndex:
+ case ax::mojom::IntAttribute::kActivedescendantId:
+ case ax::mojom::IntAttribute::kInPageLinkTargetId:
+ case ax::mojom::IntAttribute::kErrormessageId:
+ case ax::mojom::IntAttribute::kDOMNodeId:
+ case ax::mojom::IntAttribute::kDropeffect:
+ case ax::mojom::IntAttribute::kMemberOfId:
+ case ax::mojom::IntAttribute::kNextFocusId:
+ case ax::mojom::IntAttribute::kNextOnLineId:
+ case ax::mojom::IntAttribute::kPreviousFocusId:
+ case ax::mojom::IntAttribute::kPreviousOnLineId:
+ case ax::mojom::IntAttribute::kSetSize:
+ case ax::mojom::IntAttribute::kPosInSet:
+ case ax::mojom::IntAttribute::kPopupForId:
+ attributes->SetInt(ToString(attr.first), attr.second);
+ break;
+ case ax::mojom::IntAttribute::kDefaultActionVerb:
+ attributes->SetString(
+ ToString(attr.first),
+ ui::ToString(
+ static_cast<ax::mojom::DefaultActionVerb>(attr.second)));
+ break;
+ case ax::mojom::IntAttribute::kInvalidState: {
+ auto state = static_cast<ax::mojom::InvalidState>(attr.second);
+ if (ax::mojom::InvalidState::kNone != state) {
+ attributes->SetString(ToString(attr.first), ToString(state));
+ }
+ } break;
+ case ax::mojom::IntAttribute::kCheckedState: {
+ auto state = static_cast<ax::mojom::CheckedState>(attr.second);
+ if (ax::mojom::CheckedState::kNone != state) {
+ attributes->SetString(ToString(attr.first), ToString(state));
+ }
+ } break;
+ case ax::mojom::IntAttribute::kRestriction:
+ attributes->SetString(
+ ToString(attr.first),
+ ToString(static_cast<ax::mojom::Restriction>(attr.second)));
+ break;
+ case ax::mojom::IntAttribute::kListStyle: {
+ auto state = static_cast<ax::mojom::ListStyle>(attr.second);
+ if (ax::mojom::ListStyle::kNone != state) {
+ attributes->SetString(ToString(attr.first), ToString(state));
+ }
+ } break;
+ case ax::mojom::IntAttribute::kSortDirection: {
+ auto state = static_cast<ax::mojom::SortDirection>(attr.second);
+ if (ax::mojom::SortDirection::kNone != state) {
+ attributes->SetString(ToString(attr.first), ToString(state));
+ }
+ } break;
+ case ax::mojom::IntAttribute::kTextAlign: {
+ auto state = static_cast<ax::mojom::TextAlign>(attr.second);
+ if (ax::mojom::TextAlign::kNone != state) {
+ attributes->SetString(ToString(attr.first), ToString(state));
+ }
+ } break;
+ case ax::mojom::IntAttribute::kNameFrom:
+ attributes->SetString(
+ ToString(attr.first),
+ ToString(static_cast<ax::mojom::NameFrom>(attr.second)));
+ break;
+ case ax::mojom::IntAttribute::kColorValue:
+ case ax::mojom::IntAttribute::kBackgroundColor:
+ case ax::mojom::IntAttribute::kColor:
+ attributes->SetString(ToString(attr.first),
+ base::StringPrintf("0x%X", attr.second));
+ break;
+ case ax::mojom::IntAttribute::kDescriptionFrom:
+ attributes->SetString(
+ ToString(attr.first),
+ ToString(static_cast<ax::mojom::DescriptionFrom>(attr.second)));
+ break;
+ case ax::mojom::IntAttribute::kAriaCurrentState: {
+ auto state = static_cast<ax::mojom::AriaCurrentState>(attr.second);
+ if (ax::mojom::AriaCurrentState::kNone != state) {
+ attributes->SetString(ToString(attr.first), ToString(state));
+ }
+ } break;
+ case ax::mojom::IntAttribute::kTextDirection: {
+ auto state = static_cast<ax::mojom::WritingDirection>(attr.second);
+ if (ax::mojom::WritingDirection::kNone != state) {
+ attributes->SetString(ToString(attr.first), ToString(state));
+ }
+ } break;
+ case ax::mojom::IntAttribute::kTextPosition: {
+ auto state = static_cast<ax::mojom::TextPosition>(attr.second);
+ if (ax::mojom::TextPosition::kNone != state) {
+ attributes->SetString(ToString(attr.first), ToString(state));
+ }
+ } break;
+ case ax::mojom::IntAttribute::kTextStyle: {
+ static ax::mojom::TextStyle textStyleArr[] = {
+ ax::mojom::TextStyle::kBold, ax::mojom::TextStyle::kItalic,
+ ax::mojom::TextStyle::kUnderline,
+ ax::mojom::TextStyle::kLineThrough,
+ ax::mojom::TextStyle::kOverline};
+
+ CefRefPtr<CefListValue> list = CefListValue::Create();
+ int index = 0;
+ // Iterate and find which states are set.
+ for (unsigned i = 0; i < std::size(textStyleArr); i++) {
+ if (attr.second & static_cast<int>(textStyleArr[i])) {
+ list->SetString(index++, ToString(textStyleArr[i]));
+ }
+ }
+ attributes->SetList(ToString(attr.first), list);
+ } break;
+ case ax::mojom::IntAttribute::kTextOverlineStyle:
+ case ax::mojom::IntAttribute::kTextStrikethroughStyle:
+ case ax::mojom::IntAttribute::kTextUnderlineStyle: {
+ auto state = static_cast<ax::mojom::TextDecorationStyle>(attr.second);
+ if (ax::mojom::TextDecorationStyle::kNone != state) {
+ attributes->SetString(ToString(attr.first), ToString(state));
+ }
+ } break;
+ case ax::mojom::IntAttribute::kAriaCellColumnSpan:
+ case ax::mojom::IntAttribute::kAriaCellRowSpan:
+ case ax::mojom::IntAttribute::kImageAnnotationStatus: {
+ // TODO(cef): Implement support for Image Annotation Status,
+ // kAriaCellColumnSpan and kAriaCellRowSpan
+ } break;
+ }
+ }
+
+ // Set Bool Attributes.
+ void operator()(const std::pair<ax::mojom::BoolAttribute, bool> attr) {
+ if (attr.first != ax::mojom::BoolAttribute::kNone) {
+ attributes->SetBool(ToString(attr.first), attr.second);
+ }
+ }
+ // Set String Attributes.
+ void operator()(
+ const std::pair<ax::mojom::StringAttribute, std::string>& attr) {
+ if (attr.first != ax::mojom::StringAttribute::kNone) {
+ attributes->SetString(ToString(attr.first), attr.second);
+ }
+ }
+ // Set Float attributes.
+ void operator()(const std::pair<ax::mojom::FloatAttribute, float>& attr) {
+ if (attr.first != ax::mojom::FloatAttribute::kNone) {
+ attributes->SetDouble(ToString(attr.first), attr.second);
+ }
+ }
+
+ // Set Int list attributes.
+ void operator()(const std::pair<ax::mojom::IntListAttribute,
+ std::vector<int32_t>>& attr) {
+ if (attr.first != ax::mojom::IntListAttribute::kNone) {
+ CefRefPtr<CefListValue> list;
+
+ if (ax::mojom::IntListAttribute::kMarkerTypes == attr.first) {
+ list = CefListValue::Create();
+ int index = 0;
+ for (size_t i = 0; i < attr.second.size(); ++i) {
+ auto type = static_cast<ax::mojom::MarkerType>(attr.second[i]);
+
+ if (type == ax::mojom::MarkerType::kNone) {
+ continue;
+ }
+
+ static ax::mojom::MarkerType marktypeArr[] = {
+ ax::mojom::MarkerType::kSpelling, ax::mojom::MarkerType::kGrammar,
+ ax::mojom::MarkerType::kTextMatch};
+
+ // Iterate and find which markers are set.
+ for (unsigned j = 0; j < std::size(marktypeArr); j++) {
+ if (attr.second[i] & static_cast<int>(marktypeArr[j])) {
+ list->SetString(index++, ToString(marktypeArr[j]));
+ }
+ }
+ }
+ } else {
+ list = ToCefValue(attr.second);
+ }
+ attributes->SetList(ToString(attr.first), list);
+ }
+ }
+};
+
+// Converts AXNodeData to CefDictionaryValue(like AXNodeData::ToString).
+CefRefPtr<CefDictionaryValue> ToCefValue(const ui::AXNodeData& node) {
+ CefRefPtr<CefDictionaryValue> value = CefDictionaryValue::Create();
+
+ if (node.id != -1) {
+ value->SetInt("id", node.id);
+ }
+
+ value->SetString("role", ToString(node.role));
+ value->SetList("state", ToCefValue(node.state));
+
+ if (node.relative_bounds.offset_container_id != -1) {
+ value->SetInt("offset_container_id",
+ node.relative_bounds.offset_container_id);
+ }
+
+ value->SetDictionary("location", ToCefValue(node.relative_bounds.bounds));
+
+ // Transform matrix is private, so we set the string that Clients can parse
+ // and use if needed.
+ if (node.relative_bounds.transform &&
+ !node.relative_bounds.transform->IsIdentity()) {
+ value->SetString("transform", node.relative_bounds.transform->ToString());
+ }
+
+ if (!node.child_ids.empty()) {
+ value->SetList("child_ids", ToCefValue(node.child_ids));
+ }
+
+ CefRefPtr<CefListValue> actions_strings;
+ size_t actions_idx = 0;
+ for (int action_index = static_cast<int>(ax::mojom::Action::kMinValue) + 1;
+ action_index <= static_cast<int>(ax::mojom::Action::kMaxValue);
+ ++action_index) {
+ auto action = static_cast<ax::mojom::Action>(action_index);
+ if (node.HasAction(action)) {
+ if (!actions_strings) {
+ actions_strings = CefListValue::Create();
+ }
+ actions_strings->SetString(actions_idx++, ToString(action));
+ }
+ }
+ if (actions_strings) {
+ value->SetList("actions", actions_strings);
+ }
+
+ CefRefPtr<CefDictionaryValue> attributes = CefDictionaryValue::Create();
+ PopulateAxNodeAttributes func(attributes);
+
+ // Poupulate Int Attributes.
+ std::for_each(node.int_attributes.begin(), node.int_attributes.end(), func);
+
+ // Poupulate String Attributes.
+ std::for_each(node.string_attributes.begin(), node.string_attributes.end(),
+ func);
+
+ // Poupulate Float Attributes.
+ std::for_each(node.float_attributes.begin(), node.float_attributes.end(),
+ func);
+
+ // Poupulate Bool Attributes.
+ std::for_each(node.bool_attributes.begin(), node.bool_attributes.end(), func);
+
+ // Populate int list attributes.
+ std::for_each(node.intlist_attributes.begin(), node.intlist_attributes.end(),
+ func);
+
+ value->SetDictionary("attributes", attributes);
+
+ return value;
+}
+
+// Converts AXTreeData to CefDictionaryValue(like AXTreeData::ToString).
+CefRefPtr<CefDictionaryValue> ToCefValue(const ui::AXTreeData& treeData) {
+ CefRefPtr<CefDictionaryValue> value = CefDictionaryValue::Create();
+
+ if (!treeData.tree_id.ToString().empty()) {
+ value->SetString("tree_id", treeData.tree_id.ToString());
+ }
+
+ if (!treeData.parent_tree_id.ToString().empty()) {
+ value->SetString("parent_tree_id", treeData.parent_tree_id.ToString());
+ }
+
+ if (!treeData.focused_tree_id.ToString().empty()) {
+ value->SetString("focused_tree_id", treeData.focused_tree_id.ToString());
+ }
+
+ if (!treeData.doctype.empty()) {
+ value->SetString("doctype", treeData.doctype);
+ }
+
+ value->SetBool("loaded", treeData.loaded);
+
+ if (treeData.loading_progress != 0.0) {
+ value->SetDouble("loading_progress", treeData.loading_progress);
+ }
+
+ if (!treeData.mimetype.empty()) {
+ value->SetString("mimetype", treeData.mimetype);
+ }
+ if (!treeData.url.empty()) {
+ value->SetString("url", treeData.url);
+ }
+ if (!treeData.title.empty()) {
+ value->SetString("title", treeData.title);
+ }
+
+ if (treeData.sel_anchor_object_id != -1) {
+ value->SetInt("sel_anchor_object_id", treeData.sel_anchor_object_id);
+ value->SetInt("sel_anchor_offset", treeData.sel_anchor_offset);
+ value->SetString("sel_anchor_affinity",
+ ToString(treeData.sel_anchor_affinity));
+ }
+ if (treeData.sel_focus_object_id != -1) {
+ value->SetInt("sel_focus_object_id", treeData.sel_anchor_object_id);
+ value->SetInt("sel_focus_offset", treeData.sel_anchor_offset);
+ value->SetString("sel_focus_affinity",
+ ToString(treeData.sel_anchor_affinity));
+ }
+
+ if (treeData.focus_id != -1) {
+ value->SetInt("focus_id", treeData.focus_id);
+ }
+
+ return value;
+}
+
+// Converts AXTreeUpdate to CefDictionaryValue(like AXTreeUpdate::ToString).
+CefRefPtr<CefDictionaryValue> ToCefValue(const ui::AXTreeUpdate& update) {
+ CefRefPtr<CefDictionaryValue> value = CefDictionaryValue::Create();
+
+ if (update.has_tree_data) {
+ value->SetBool("has_tree_data", true);
+ value->SetDictionary("tree_data", ToCefValue(update.tree_data));
+ }
+
+ if (update.node_id_to_clear != 0) {
+ value->SetInt("node_id_to_clear", update.node_id_to_clear);
+ }
+
+ if (update.root_id != 0) {
+ value->SetInt("root_id", update.root_id);
+ }
+
+ value->SetList("nodes", ToCefValue(update.nodes));
+
+ return value;
+}
+
+// Converts AXEvent to CefDictionaryValue.
+CefRefPtr<CefDictionaryValue> ToCefValue(const ui::AXEvent& event) {
+ CefRefPtr<CefDictionaryValue> value = CefDictionaryValue::Create();
+
+ if (event.event_type != ax::mojom::Event::kNone) {
+ value->SetString("event_type", ToString(event.event_type));
+ }
+
+ if (event.id != -1) {
+ value->SetInt("id", event.id);
+ }
+
+ if (event.event_from != ax::mojom::EventFrom::kNone) {
+ value->SetString("event_from", ToString(event.event_from));
+ }
+
+ if (event.action_request_id != -1) {
+ value->SetInt("action_request_id", event.action_request_id);
+ }
+
+ return value;
+}
+
+// Convert AXEventNotificationDetails to CefDictionaryValue.
+CefRefPtr<CefDictionaryValue> ToCefValue(
+ const content::AXEventNotificationDetails& eventData) {
+ CefRefPtr<CefDictionaryValue> value = CefDictionaryValue::Create();
+
+ if (!eventData.ax_tree_id.ToString().empty()) {
+ value->SetString("ax_tree_id", eventData.ax_tree_id.ToString());
+ }
+
+ if (eventData.updates.size() > 0) {
+ CefRefPtr<CefListValue> updates = CefListValue::Create();
+ updates->SetSize(eventData.updates.size());
+ size_t i = 0;
+ for (const auto& update : eventData.updates) {
+ updates->SetDictionary(i++, ToCefValue(update));
+ }
+ value->SetList("updates", updates);
+ }
+
+ if (eventData.events.size() > 0) {
+ CefRefPtr<CefListValue> events = CefListValue::Create();
+ events->SetSize(eventData.events.size());
+ size_t i = 0;
+ for (const auto& event : eventData.events) {
+ events->SetDictionary(i++, ToCefValue(event));
+ }
+ value->SetList("events", events);
+ }
+
+ return value;
+}
+
+// Convert AXRelativeBounds to CefDictionaryValue. Similar to
+// AXRelativeBounds::ToString. See that for more details
+CefRefPtr<CefDictionaryValue> ToCefValue(const ui::AXRelativeBounds& location) {
+ CefRefPtr<CefDictionaryValue> value = CefDictionaryValue::Create();
+
+ if (location.offset_container_id != -1) {
+ value->SetInt("offset_container_id", location.offset_container_id);
+ }
+
+ value->SetDictionary("bounds", ToCefValue(location.bounds));
+
+ // Transform matrix is private, so we set the string that Clients can parse
+ // and use if needed.
+ if (location.transform && !location.transform->IsIdentity()) {
+ value->SetString("transform", location.transform->ToString());
+ }
+
+ return value;
+}
+
+// Convert AXLocationChangeNotificationDetails to CefDictionaryValue.
+CefRefPtr<CefDictionaryValue> ToCefValue(
+ const content::AXLocationChangeNotificationDetails& locData) {
+ CefRefPtr<CefDictionaryValue> value = CefDictionaryValue::Create();
+
+ if (locData.id != -1) {
+ value->SetInt("id", locData.id);
+ }
+
+ if (!locData.ax_tree_id.ToString().empty()) {
+ value->SetString("ax_tree_id", locData.ax_tree_id.ToString());
+ }
+
+ value->SetDictionary("new_location", ToCefValue(locData.new_location));
+
+ return value;
+}
+
+template <typename T>
+CefRefPtr<CefListValue> ToCefValue(const std::vector<T>& vecData) {
+ CefRefPtr<CefListValue> value = CefListValue::Create();
+
+ for (size_t i = 0; i < vecData.size(); i++) {
+ value->SetDictionary(i, ToCefValue(vecData[i]));
+ }
+
+ return value;
+}
+
+} // namespace
+
+namespace osr_accessibility_util {
+
+CefRefPtr<CefValue> ParseAccessibilityEventData(
+ const content::AXEventNotificationDetails& data) {
+ CefRefPtr<CefValue> value = CefValue::Create();
+ value->SetDictionary(ToCefValue(data));
+ return value;
+}
+
+CefRefPtr<CefValue> ParseAccessibilityLocationData(
+ const std::vector<content::AXLocationChangeNotificationDetails>& data) {
+ CefRefPtr<CefValue> value = CefValue::Create();
+ value->SetList(ToCefValue(data));
+ return value;
+}
+
+} // namespace osr_accessibility_util
diff --git a/libcef/browser/osr/osr_accessibility_util.h b/libcef/browser/osr/osr_accessibility_util.h
new file mode 100644
index 00000000..486c91aa
--- /dev/null
+++ b/libcef/browser/osr/osr_accessibility_util.h
@@ -0,0 +1,29 @@
+// Copyright 2017 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_OSR_ACCESSIBILITY_UTIL_H_
+#define CEF_LIBCEF_BROWSER_OSR_ACCESSIBILITY_UTIL_H_
+#pragma once
+
+#include <vector>
+#include "include/cef_values.h"
+
+namespace content {
+struct AXEventNotificationDetails;
+struct AXLocationChangeNotificationDetails;
+} // namespace content
+
+namespace osr_accessibility_util {
+
+// Convert Accessibility Event and location updates to CefValue, which may be
+// consumed or serialized with CefJSONWrite.
+CefRefPtr<CefValue> ParseAccessibilityEventData(
+ const content::AXEventNotificationDetails& data);
+
+CefRefPtr<CefValue> ParseAccessibilityLocationData(
+ const std::vector<content::AXLocationChangeNotificationDetails>& data);
+
+} // namespace osr_accessibility_util
+
+#endif // CEF_LIBCEF_BROWSER_ACCESSIBILITY_UTIL_H_
diff --git a/libcef/browser/osr/osr_util.cc b/libcef/browser/osr/osr_util.cc
new file mode 100644
index 00000000..d1069b69
--- /dev/null
+++ b/libcef/browser/osr/osr_util.cc
@@ -0,0 +1,24 @@
+// Copyright 2015 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/osr/osr_util.h"
+
+namespace osr_util {
+
+namespace {
+
+// The rate at which new calls to OnPaint will be generated.
+const int kDefaultFrameRate = 30;
+
+} // namespace
+
+int ClampFrameRate(int frame_rate) {
+ if (frame_rate < 1) {
+ return kDefaultFrameRate;
+ }
+
+ return frame_rate;
+}
+
+} // namespace osr_util
diff --git a/libcef/browser/osr/osr_util.h b/libcef/browser/osr/osr_util.h
new file mode 100644
index 00000000..e04039a3
--- /dev/null
+++ b/libcef/browser/osr/osr_util.h
@@ -0,0 +1,14 @@
+// Copyright 2015 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_OSR_OSR_UTIL_H_
+#define CEF_LIBCEF_BROWSER_OSR_OSR_UTIL_H_
+
+namespace osr_util {
+
+int ClampFrameRate(int frame_rate);
+
+} // namespace osr_util
+
+#endif // CEF_LIBCEF_BROWSER_OSR_OSR_UTIL_H_
diff --git a/libcef/browser/osr/render_widget_host_view_osr.cc b/libcef/browser/osr/render_widget_host_view_osr.cc
new file mode 100644
index 00000000..cf2de6e1
--- /dev/null
+++ b/libcef/browser/osr/render_widget_host_view_osr.cc
@@ -0,0 +1,1831 @@
+// Copyright (c) 2014 The Chromium Embedded Framework Authors.
+// Portions copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/osr/render_widget_host_view_osr.h"
+
+#include <stdint.h>
+#include <utility>
+
+#include "libcef/browser/alloy/alloy_browser_host_impl.h"
+#include "libcef/browser/osr/osr_util.h"
+#include "libcef/browser/osr/synthetic_gesture_target_osr.h"
+#include "libcef/browser/osr/touch_selection_controller_client_osr.h"
+#include "libcef/browser/osr/video_consumer_osr.h"
+#include "libcef/browser/thread_util.h"
+
+#include "base/command_line.h"
+#include "base/functional/callback_helpers.h"
+#include "base/memory/ptr_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "cc/base/switches.h"
+#include "components/viz/common/features.h"
+#include "components/viz/common/frame_sinks/begin_frame_args.h"
+#include "components/viz/common/frame_sinks/copy_output_request.h"
+#include "components/viz/common/frame_sinks/delay_based_time_source.h"
+#include "components/viz/common/surfaces/frame_sink_id_allocator.h"
+#include "components/viz/common/switches.h"
+#include "content/browser/bad_message.h"
+#include "content/browser/gpu/gpu_data_manager_impl.h"
+#include "content/browser/renderer_host/cursor_manager.h"
+#include "content/browser/renderer_host/delegated_frame_host.h"
+#include "content/browser/renderer_host/dip_util.h"
+#include "content/browser/renderer_host/input/motion_event_web.h"
+#include "content/browser/renderer_host/input/synthetic_gesture_target_base.h"
+#include "content/browser/renderer_host/render_widget_host_delegate.h"
+#include "content/browser/renderer_host/render_widget_host_impl.h"
+#include "content/browser/renderer_host/render_widget_host_input_event_router.h"
+#include "content/common/content_switches_internal.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/context_factory.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/common/content_switches.h"
+#include "media/base/video_frame.h"
+#include "media/capture/mojom/video_capture_buffer.mojom.h"
+#include "ui/compositor/compositor.h"
+#include "ui/events/blink/blink_event_util.h"
+#include "ui/events/gesture_detection/gesture_provider_config_helper.h"
+#include "ui/events/gesture_detection/motion_event.h"
+#include "ui/gfx/geometry/dip_util.h"
+#include "ui/gfx/geometry/size_conversions.h"
+#include "ui/touch_selection/touch_selection_controller.h"
+
+namespace {
+
+// The maximum number of damage rects to cache for outstanding frame requests
+// (for OnAcceleratedPaint).
+const size_t kMaxDamageRects = 10;
+
+const float kDefaultScaleFactor = 1.0;
+
+display::ScreenInfo ScreenInfoFrom(const CefScreenInfo& src) {
+ display::ScreenInfo screenInfo;
+ screenInfo.device_scale_factor = src.device_scale_factor;
+ screenInfo.depth = src.depth;
+ screenInfo.depth_per_component = src.depth_per_component;
+ screenInfo.is_monochrome = src.is_monochrome ? true : false;
+ screenInfo.rect =
+ gfx::Rect(src.rect.x, src.rect.y, src.rect.width, src.rect.height);
+ screenInfo.available_rect =
+ gfx::Rect(src.available_rect.x, src.available_rect.y,
+ src.available_rect.width, src.available_rect.height);
+
+ return screenInfo;
+}
+
+class CefDelegatedFrameHostClient : public content::DelegatedFrameHostClient {
+ public:
+ explicit CefDelegatedFrameHostClient(CefRenderWidgetHostViewOSR* view)
+ : view_(view) {}
+
+ CefDelegatedFrameHostClient(const CefDelegatedFrameHostClient&) = delete;
+ CefDelegatedFrameHostClient& operator=(const CefDelegatedFrameHostClient&) =
+ delete;
+
+ ui::Layer* DelegatedFrameHostGetLayer() const override {
+ return view_->GetRootLayer();
+ }
+
+ bool DelegatedFrameHostIsVisible() const override {
+ // Called indirectly from DelegatedFrameHost::WasShown.
+ return view_->IsShowing();
+ }
+
+ SkColor DelegatedFrameHostGetGutterColor() const override {
+ // When making an element on the page fullscreen the element's background
+ // may not match the page's, so use black as the gutter color to avoid
+ // flashes of brighter colors during the transition.
+ if (view_->render_widget_host()->delegate() &&
+ view_->render_widget_host()->delegate()->IsFullscreen()) {
+ return SK_ColorBLACK;
+ }
+ return *view_->GetBackgroundColor();
+ }
+
+ void OnFrameTokenChanged(uint32_t frame_token,
+ base::TimeTicks activation_time) override {
+ view_->render_widget_host()->DidProcessFrame(frame_token, activation_time);
+ }
+
+ float GetDeviceScaleFactor() const override {
+ return view_->GetDeviceScaleFactor();
+ }
+
+ std::vector<viz::SurfaceId> CollectSurfaceIdsForEviction() override {
+ return view_->render_widget_host()->CollectSurfaceIdsForEviction();
+ }
+
+ void InvalidateLocalSurfaceIdOnEviction() override {
+ view_->InvalidateLocalSurfaceId();
+ }
+
+ bool ShouldShowStaleContentOnEviction() override { return false; }
+
+ private:
+ CefRenderWidgetHostViewOSR* const view_;
+};
+
+ui::GestureProvider::Config CreateGestureProviderConfig() {
+ ui::GestureProvider::Config config = ui::GetGestureProviderConfig(
+ ui::GestureProviderConfigType::CURRENT_PLATFORM);
+ return config;
+}
+
+ui::LatencyInfo CreateLatencyInfo(const blink::WebInputEvent& event) {
+ ui::LatencyInfo latency_info;
+ // The latency number should only be added if the timestamp is valid.
+ base::TimeTicks time = event.TimeStamp();
+ if (!time.is_null()) {
+ latency_info.AddLatencyNumberWithTimestamp(
+ ui::INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, time);
+ }
+ return latency_info;
+}
+
+gfx::Rect GetViewBounds(AlloyBrowserHostImpl* browser) {
+ if (!browser) {
+ return gfx::Rect();
+ }
+
+ CefRect rc;
+ CefRefPtr<CefRenderHandler> handler =
+ browser->GetClient()->GetRenderHandler();
+ CHECK(handler);
+
+ handler->GetViewRect(browser, rc);
+ CHECK_GT(rc.width, 0);
+ CHECK_GT(rc.height, 0);
+
+ return gfx::Rect(rc.x, rc.y, rc.width, rc.height);
+}
+
+ui::ImeTextSpan::UnderlineStyle GetImeUnderlineStyle(
+ cef_composition_underline_style_t style) {
+ switch (style) {
+ case CEF_CUS_SOLID:
+ return ui::ImeTextSpan::UnderlineStyle::kSolid;
+ case CEF_CUS_DOT:
+ return ui::ImeTextSpan::UnderlineStyle::kDot;
+ case CEF_CUS_DASH:
+ return ui::ImeTextSpan::UnderlineStyle::kDash;
+ case CEF_CUS_NONE:
+ return ui::ImeTextSpan::UnderlineStyle::kNone;
+ }
+
+ NOTREACHED();
+ return ui::ImeTextSpan::UnderlineStyle::kSolid;
+}
+
+} // namespace
+
+// Logic copied from RenderWidgetHostViewAura::CreateSelectionController.
+void CefRenderWidgetHostViewOSR::CreateSelectionController() {
+ ui::TouchSelectionController::Config tsc_config;
+ tsc_config.max_tap_duration = base::Milliseconds(
+ ui::GestureConfiguration::GetInstance()->long_press_time_in_ms());
+ tsc_config.tap_slop = ui::GestureConfiguration::GetInstance()
+ ->max_touch_move_in_pixels_for_click();
+ tsc_config.enable_longpress_drag_selection = false;
+ selection_controller_ = std::make_unique<ui::TouchSelectionController>(
+ selection_controller_client_.get(), tsc_config);
+}
+
+CefRenderWidgetHostViewOSR::CefRenderWidgetHostViewOSR(
+ SkColor background_color,
+ bool use_shared_texture,
+ bool use_external_begin_frame,
+ content::RenderWidgetHost* widget,
+ CefRenderWidgetHostViewOSR* parent_host_view)
+ : content::RenderWidgetHostViewBase(widget),
+ background_color_(background_color),
+ render_widget_host_(content::RenderWidgetHostImpl::From(widget)),
+ has_parent_(parent_host_view != nullptr),
+ parent_host_view_(parent_host_view),
+ pinch_zoom_enabled_(content::IsPinchToZoomEnabled()),
+ mouse_wheel_phase_handler_(this),
+ gesture_provider_(CreateGestureProviderConfig(), this),
+ weak_ptr_factory_(this) {
+ DCHECK(render_widget_host_);
+ DCHECK(!render_widget_host_->GetView());
+
+ if (parent_host_view_) {
+ browser_impl_ = parent_host_view_->browser_impl();
+ DCHECK(browser_impl_);
+ } else if (content::RenderViewHost::From(render_widget_host_)) {
+ // AlloyBrowserHostImpl might not be created at this time for popups.
+ browser_impl_ = AlloyBrowserHostImpl::GetBrowserForHost(
+ content::RenderViewHost::From(render_widget_host_));
+ }
+
+ delegated_frame_host_client_.reset(new CefDelegatedFrameHostClient(this));
+
+ // Matching the attributes from BrowserCompositorMac.
+ delegated_frame_host_ = std::make_unique<content::DelegatedFrameHost>(
+ AllocateFrameSinkId(), delegated_frame_host_client_.get(),
+ false /* should_register_frame_sink_id */);
+
+ root_layer_.reset(new ui::Layer(ui::LAYER_SOLID_COLOR));
+
+ bool opaque = SkColorGetA(background_color_) == SK_AlphaOPAQUE;
+ GetRootLayer()->SetFillsBoundsOpaquely(opaque);
+ GetRootLayer()->SetColor(background_color_);
+
+ external_begin_frame_enabled_ = use_external_begin_frame;
+
+ auto context_factory = content::GetContextFactory();
+
+ // Matching the attributes from RecyclableCompositorMac.
+ compositor_.reset(new ui::Compositor(
+ context_factory->AllocateFrameSinkId(), context_factory,
+ base::SingleThreadTaskRunner::GetCurrentDefault(),
+ false /* enable_pixel_canvas */, use_external_begin_frame));
+ compositor_->SetAcceleratedWidget(gfx::kNullAcceleratedWidget);
+
+ compositor_->SetDelegate(this);
+ compositor_->SetRootLayer(root_layer_.get());
+ compositor_->AddChildFrameSink(GetFrameSinkId());
+
+ content::RenderWidgetHostImpl* render_widget_host_impl =
+ content::RenderWidgetHostImpl::From(render_widget_host_);
+ if (render_widget_host_impl) {
+ render_widget_host_impl->SetCompositorForFlingScheduler(compositor_.get());
+ }
+
+ cursor_manager_.reset(new content::CursorManager(this));
+
+ // This may result in a call to GetFrameSinkId().
+ render_widget_host_->SetView(this);
+
+ if (GetTextInputManager()) {
+ GetTextInputManager()->AddObserver(this);
+ }
+
+ if (render_widget_host_->delegate() &&
+ render_widget_host_->delegate()->GetInputEventRouter()) {
+ render_widget_host_->delegate()->GetInputEventRouter()->AddFrameSinkIdOwner(
+ GetFrameSinkId(), this);
+ }
+
+ if (browser_impl_ && !parent_host_view_) {
+ // For child/popup views this will be called from the associated InitAs*()
+ // method.
+ SetRootLayerSize(false /* force */);
+ if (!render_widget_host_->is_hidden()) {
+ Show();
+ }
+ }
+
+ selection_controller_client_ =
+ std::make_unique<CefTouchSelectionControllerClientOSR>(this);
+ CreateSelectionController();
+}
+
+CefRenderWidgetHostViewOSR::~CefRenderWidgetHostViewOSR() {
+ ReleaseCompositor();
+ root_layer_.reset(nullptr);
+
+ DCHECK(!parent_host_view_);
+ DCHECK(!popup_host_view_);
+ DCHECK(!child_host_view_);
+ DCHECK(guest_host_views_.empty());
+
+ if (text_input_manager_) {
+ text_input_manager_->RemoveObserver(this);
+ }
+}
+
+void CefRenderWidgetHostViewOSR::ReleaseCompositor() {
+ if (!compositor_) {
+ return; // already released
+ }
+
+ // Marking the DelegatedFrameHost as removed from the window hierarchy is
+ // necessary to remove all connections to its old ui::Compositor.
+ if (is_showing_) {
+ delegated_frame_host_->WasHidden(
+ content::DelegatedFrameHost::HiddenCause::kOther);
+ }
+ delegated_frame_host_->DetachFromCompositor();
+
+ delegated_frame_host_.reset(nullptr);
+ compositor_.reset(nullptr);
+}
+
+// Called for full-screen widgets.
+void CefRenderWidgetHostViewOSR::InitAsChild(gfx::NativeView parent_view) {
+ DCHECK(parent_host_view_);
+ DCHECK(browser_impl_);
+
+ if (parent_host_view_->child_host_view_) {
+ // Cancel the previous popup widget.
+ parent_host_view_->child_host_view_->CancelWidget();
+ }
+
+ parent_host_view_->set_child_host_view(this);
+
+ // The parent view should not render while the full-screen view exists.
+ parent_host_view_->Hide();
+
+ SetRootLayerSize(false /* force */);
+ Show();
+}
+
+void CefRenderWidgetHostViewOSR::SetSize(const gfx::Size& size) {}
+
+void CefRenderWidgetHostViewOSR::SetBounds(const gfx::Rect& rect) {}
+
+gfx::NativeView CefRenderWidgetHostViewOSR::GetNativeView() {
+ return gfx::NativeView();
+}
+
+gfx::NativeViewAccessible
+CefRenderWidgetHostViewOSR::GetNativeViewAccessible() {
+ return gfx::NativeViewAccessible();
+}
+
+void CefRenderWidgetHostViewOSR::Focus() {}
+
+bool CefRenderWidgetHostViewOSR::HasFocus() {
+ return false;
+}
+
+bool CefRenderWidgetHostViewOSR::IsSurfaceAvailableForCopy() {
+ return delegated_frame_host_
+ ? delegated_frame_host_->CanCopyFromCompositingSurface()
+ : false;
+}
+
+void CefRenderWidgetHostViewOSR::ShowWithVisibility(
+ content::PageVisibilityState) {
+ if (is_showing_) {
+ return;
+ }
+
+ if (!content::GpuDataManagerImpl::GetInstance()->IsGpuCompositingDisabled() &&
+ !browser_impl_ &&
+ (!parent_host_view_ || !parent_host_view_->browser_impl_)) {
+ return;
+ }
+
+ is_showing_ = true;
+
+ // If the viz::LocalSurfaceId is invalid, we may have been evicted,
+ // and no other visual properties have since been changed. Allocate a new id
+ // and start synchronizing.
+ if (!GetLocalSurfaceId().is_valid()) {
+ AllocateLocalSurfaceId();
+ SynchronizeVisualProperties(cc::DeadlinePolicy::UseDefaultDeadline(),
+ GetLocalSurfaceId());
+ }
+
+ if (render_widget_host_) {
+ render_widget_host_->WasShown(
+ /*record_tab_switch_time_request=*/{});
+
+ // Call OnRenderFrameMetadataChangedAfterActivation for every frame.
+ auto provider = content::RenderWidgetHostImpl::From(render_widget_host_)
+ ->render_frame_metadata_provider();
+ provider->AddObserver(this);
+ provider->ReportAllFrameSubmissionsForTesting(true);
+ }
+
+ if (delegated_frame_host_) {
+ delegated_frame_host_->AttachToCompositor(compositor_.get());
+ delegated_frame_host_->WasShown(GetLocalSurfaceId(), GetViewBounds().size(),
+ /*record_tab_switch_time_request=*/{});
+ }
+
+ if (!content::GpuDataManagerImpl::GetInstance()->IsGpuCompositingDisabled()) {
+ // Start generating frames when we're visible and at the correct size.
+ if (!video_consumer_) {
+ video_consumer_.reset(new CefVideoConsumerOSR(this));
+ UpdateFrameRate();
+ } else {
+ video_consumer_->SetActive(true);
+ }
+ }
+}
+
+void CefRenderWidgetHostViewOSR::Hide() {
+ if (!is_showing_) {
+ return;
+ }
+
+ is_showing_ = false;
+
+ if (browser_impl_) {
+ browser_impl_->CancelContextMenu();
+ }
+
+ if (selection_controller_client_) {
+ selection_controller_client_->CloseQuickMenuAndHideHandles();
+ }
+
+ if (video_consumer_) {
+ video_consumer_->SetActive(false);
+ }
+
+ if (render_widget_host_) {
+ render_widget_host_->WasHidden();
+
+ auto provider = content::RenderWidgetHostImpl::From(render_widget_host_)
+ ->render_frame_metadata_provider();
+ provider->RemoveObserver(this);
+ }
+
+ if (delegated_frame_host_) {
+ delegated_frame_host_->WasHidden(
+ content::DelegatedFrameHost::HiddenCause::kOther);
+ delegated_frame_host_->DetachFromCompositor();
+ }
+}
+
+bool CefRenderWidgetHostViewOSR::IsShowing() {
+ return is_showing_;
+}
+
+void CefRenderWidgetHostViewOSR::EnsureSurfaceSynchronizedForWebTest() {
+ ++latest_capture_sequence_number_;
+ SynchronizeVisualProperties(cc::DeadlinePolicy::UseInfiniteDeadline(),
+ absl::nullopt);
+}
+
+content::TouchSelectionControllerClientManager*
+CefRenderWidgetHostViewOSR::GetTouchSelectionControllerClientManager() {
+ return selection_controller_client_.get();
+}
+
+gfx::Rect CefRenderWidgetHostViewOSR::GetViewBounds() {
+ if (IsPopupWidget()) {
+ return popup_position_;
+ }
+
+ return current_view_bounds_;
+}
+
+void CefRenderWidgetHostViewOSR::SetBackgroundColor(SkColor color) {
+ // The renderer will feed its color back to us with the first CompositorFrame.
+ // We short-cut here to show a sensible color before that happens.
+ UpdateBackgroundColorFromRenderer(color);
+
+ DCHECK(SkColorGetA(color) == SK_AlphaOPAQUE ||
+ SkColorGetA(color) == SK_AlphaTRANSPARENT);
+ content::RenderWidgetHostViewBase::SetBackgroundColor(color);
+}
+
+absl::optional<SkColor> CefRenderWidgetHostViewOSR::GetBackgroundColor() {
+ return background_color_;
+}
+
+void CefRenderWidgetHostViewOSR::UpdateBackgroundColor() {}
+
+absl::optional<content::DisplayFeature>
+CefRenderWidgetHostViewOSR::GetDisplayFeature() {
+ return absl::nullopt;
+}
+
+void CefRenderWidgetHostViewOSR::SetDisplayFeatureForTesting(
+ const content::DisplayFeature* display_feature) {
+ NOTREACHED();
+}
+
+blink::mojom::PointerLockResult CefRenderWidgetHostViewOSR::LockMouse(
+ bool request_unadjusted_movement) {
+ return blink::mojom::PointerLockResult::kPermissionDenied;
+}
+
+blink::mojom::PointerLockResult CefRenderWidgetHostViewOSR::ChangeMouseLock(
+ bool request_unadjusted_movement) {
+ return blink::mojom::PointerLockResult::kPermissionDenied;
+}
+
+void CefRenderWidgetHostViewOSR::UnlockMouse() {}
+
+void CefRenderWidgetHostViewOSR::TakeFallbackContentFrom(
+ content::RenderWidgetHostView* view) {
+ DCHECK(!static_cast<RenderWidgetHostViewBase*>(view)
+ ->IsRenderWidgetHostViewChildFrame());
+ CefRenderWidgetHostViewOSR* view_cef =
+ static_cast<CefRenderWidgetHostViewOSR*>(view);
+ SetBackgroundColor(view_cef->background_color_);
+ if (delegated_frame_host_ && view_cef->delegated_frame_host_) {
+ delegated_frame_host_->TakeFallbackContentFrom(
+ view_cef->delegated_frame_host_.get());
+ }
+ host()->GetContentRenderingTimeoutFrom(view_cef->host());
+}
+
+void CefRenderWidgetHostViewOSR::OnPresentCompositorFrame() {}
+
+void CefRenderWidgetHostViewOSR::OnDidUpdateVisualPropertiesComplete(
+ const cc::RenderFrameMetadata& metadata) {
+ if (host()->is_hidden()) {
+ // When an embedded child responds, we want to accept its changes to the
+ // viz::LocalSurfaceId. However we do not want to embed surfaces while
+ // hidden. Nor do we want to embed invalid ids when we are evicted. Becoming
+ // visible will generate a new id, if necessary, and begin embedding.
+ UpdateLocalSurfaceIdFromEmbeddedClient(metadata.local_surface_id);
+ } else {
+ SynchronizeVisualProperties(cc::DeadlinePolicy::UseDefaultDeadline(),
+ metadata.local_surface_id);
+ }
+}
+
+void CefRenderWidgetHostViewOSR::AllocateLocalSurfaceId() {
+ if (!parent_local_surface_id_allocator_) {
+ parent_local_surface_id_allocator_ =
+ std::make_unique<viz::ParentLocalSurfaceIdAllocator>();
+ }
+ parent_local_surface_id_allocator_->GenerateId();
+}
+
+const viz::LocalSurfaceId&
+CefRenderWidgetHostViewOSR::GetCurrentLocalSurfaceId() const {
+ return parent_local_surface_id_allocator_->GetCurrentLocalSurfaceId();
+}
+
+void CefRenderWidgetHostViewOSR::UpdateLocalSurfaceIdFromEmbeddedClient(
+ const absl::optional<viz::LocalSurfaceId>&
+ embedded_client_local_surface_id) {
+ if (embedded_client_local_surface_id) {
+ parent_local_surface_id_allocator_->UpdateFromChild(
+ *embedded_client_local_surface_id);
+ } else {
+ AllocateLocalSurfaceId();
+ }
+}
+
+const viz::LocalSurfaceId&
+CefRenderWidgetHostViewOSR::GetOrCreateLocalSurfaceId() {
+ if (!parent_local_surface_id_allocator_) {
+ AllocateLocalSurfaceId();
+ }
+ return GetCurrentLocalSurfaceId();
+}
+
+void CefRenderWidgetHostViewOSR::InvalidateLocalSurfaceId() {
+ if (!parent_local_surface_id_allocator_) {
+ return;
+ }
+ parent_local_surface_id_allocator_->Invalidate();
+}
+
+void CefRenderWidgetHostViewOSR::AddDamageRect(uint32_t sequence,
+ const gfx::Rect& rect) {
+ // Associate the given damage rect with the presentation token.
+ // For OnAcceleratedPaint we'll lookup the corresponding damage area based on
+ // the frame token which is passed back to OnPresentCompositorFrame.
+ base::AutoLock lock_scope(damage_rect_lock_);
+
+ // We assume our presentation_token is a counter. Since we're using an ordered
+ // map we can enforce a max size and remove oldest from the front. Worst case,
+ // if a damage rect isn't associated, we can simply pass the entire view size.
+ while (damage_rects_.size() >= kMaxDamageRects) {
+ damage_rects_.erase(damage_rects_.begin());
+ }
+ damage_rects_[sequence] = rect;
+}
+
+void CefRenderWidgetHostViewOSR::ResetFallbackToFirstNavigationSurface() {
+ if (delegated_frame_host_) {
+ delegated_frame_host_->ResetFallbackToFirstNavigationSurface();
+ }
+}
+
+void CefRenderWidgetHostViewOSR::InitAsPopup(
+ content::RenderWidgetHostView* parent_host_view,
+ const gfx::Rect& bounds,
+ const gfx::Rect& anchor_rect) {
+ DCHECK_EQ(parent_host_view_, parent_host_view);
+ DCHECK(browser_impl_);
+
+ if (parent_host_view_->popup_host_view_) {
+ // Cancel the previous popup widget.
+ parent_host_view_->popup_host_view_->CancelWidget();
+ }
+
+ parent_host_view_->set_popup_host_view(this);
+
+ CefRefPtr<CefRenderHandler> handler =
+ browser_impl_->GetClient()->GetRenderHandler();
+ CHECK(handler);
+
+ handler->OnPopupShow(browser_impl_.get(), true);
+
+ CefRect view_rect;
+ handler->GetViewRect(browser_impl_.get(), view_rect);
+ gfx::Rect client_pos(bounds.x() - view_rect.x, bounds.y() - view_rect.y,
+ bounds.width(), bounds.height());
+
+ popup_position_ = client_pos;
+
+ CefRect widget_pos(client_pos.x(), client_pos.y(), client_pos.width(),
+ client_pos.height());
+
+ if (handler.get()) {
+ handler->OnPopupSize(browser_impl_.get(), widget_pos);
+ }
+
+ // The size doesn't change for popups so we need to force the
+ // initialization.
+ SetRootLayerSize(true /* force */);
+ Show();
+}
+
+void CefRenderWidgetHostViewOSR::UpdateCursor(const ui::Cursor& cursor) {}
+
+content::CursorManager* CefRenderWidgetHostViewOSR::GetCursorManager() {
+ return cursor_manager_.get();
+}
+
+void CefRenderWidgetHostViewOSR::SetIsLoading(bool is_loading) {
+ if (!is_loading) {
+ return;
+ }
+ // Make sure gesture detection is fresh.
+ gesture_provider_.ResetDetection();
+ forward_touch_to_popup_ = false;
+}
+
+void CefRenderWidgetHostViewOSR::RenderProcessGone() {
+ Destroy();
+}
+
+void CefRenderWidgetHostViewOSR::Destroy() {
+ if (!is_destroyed_) {
+ is_destroyed_ = true;
+
+ if (has_parent_) {
+ CancelWidget();
+ } else {
+ if (popup_host_view_) {
+ popup_host_view_->CancelWidget();
+ }
+ if (child_host_view_) {
+ child_host_view_->CancelWidget();
+ }
+ if (!guest_host_views_.empty()) {
+ // Guest RWHVs will be destroyed when the associated RWHVGuest is
+ // destroyed. This parent RWHV may be destroyed first, so disassociate
+ // the guest RWHVs here without destroying them.
+ for (auto guest_host_view : guest_host_views_) {
+ guest_host_view->parent_host_view_ = nullptr;
+ }
+ guest_host_views_.clear();
+ }
+ Hide();
+ }
+ }
+
+ delete this;
+}
+
+void CefRenderWidgetHostViewOSR::UpdateTooltipUnderCursor(
+ const std::u16string& tooltip_text) {
+ if (!browser_impl_.get()) {
+ return;
+ }
+
+ CefString tooltip(tooltip_text);
+ CefRefPtr<CefDisplayHandler> handler =
+ browser_impl_->GetClient()->GetDisplayHandler();
+ if (handler.get()) {
+ handler->OnTooltip(browser_impl_.get(), tooltip);
+ }
+}
+
+gfx::Size CefRenderWidgetHostViewOSR::GetCompositorViewportPixelSize() {
+ return gfx::ScaleToCeiledSize(GetRequestedRendererSize(),
+ GetDeviceScaleFactor());
+}
+
+uint32_t CefRenderWidgetHostViewOSR::GetCaptureSequenceNumber() const {
+ return latest_capture_sequence_number_;
+}
+
+void CefRenderWidgetHostViewOSR::CopyFromSurface(
+ const gfx::Rect& src_rect,
+ const gfx::Size& output_size,
+ base::OnceCallback<void(const SkBitmap&)> callback) {
+ if (delegated_frame_host_) {
+ delegated_frame_host_->CopyFromCompositingSurface(src_rect, output_size,
+ std::move(callback));
+ }
+}
+
+display::ScreenInfos CefRenderWidgetHostViewOSR::GetNewScreenInfosForUpdate() {
+ display::ScreenInfo display_screen_info;
+
+ if (browser_impl_) {
+ CefScreenInfo screen_info(kDefaultScaleFactor, 0, 0, false, CefRect(),
+ CefRect());
+
+ CefRefPtr<CefRenderHandler> handler =
+ browser_impl_->client()->GetRenderHandler();
+ CHECK(handler);
+ if (!handler->GetScreenInfo(browser_impl_.get(), screen_info) ||
+ screen_info.rect.width == 0 || screen_info.rect.height == 0 ||
+ screen_info.available_rect.width == 0 ||
+ screen_info.available_rect.height == 0) {
+ // If a screen rectangle was not provided, try using the view rectangle
+ // instead. Otherwise, popup views may be drawn incorrectly, or not at
+ // all.
+ CefRect screenRect;
+ handler->GetViewRect(browser_impl_.get(), screenRect);
+ CHECK_GT(screenRect.width, 0);
+ CHECK_GT(screenRect.height, 0);
+
+ if (screen_info.rect.width == 0 || screen_info.rect.height == 0) {
+ screen_info.rect = screenRect;
+ }
+
+ if (screen_info.available_rect.width == 0 ||
+ screen_info.available_rect.height == 0) {
+ screen_info.available_rect = screenRect;
+ }
+ }
+
+ display_screen_info = ScreenInfoFrom(screen_info);
+ }
+
+ return display::ScreenInfos(display_screen_info);
+}
+
+void CefRenderWidgetHostViewOSR::TransformPointToRootSurface(
+ gfx::PointF* point) {}
+
+gfx::Rect CefRenderWidgetHostViewOSR::GetBoundsInRootWindow() {
+ if (!browser_impl_.get()) {
+ return gfx::Rect();
+ }
+
+ CefRect rc;
+ CefRefPtr<CefRenderHandler> handler =
+ browser_impl_->client()->GetRenderHandler();
+ CHECK(handler);
+ if (handler->GetRootScreenRect(browser_impl_.get(), rc)) {
+ return gfx::Rect(rc.x, rc.y, rc.width, rc.height);
+ }
+ return GetViewBounds();
+}
+
+#if !BUILDFLAG(IS_MAC)
+viz::ScopedSurfaceIdAllocator
+CefRenderWidgetHostViewOSR::DidUpdateVisualProperties(
+ const cc::RenderFrameMetadata& metadata) {
+ base::OnceCallback<void()> allocation_task = base::BindOnce(
+ &CefRenderWidgetHostViewOSR::OnDidUpdateVisualPropertiesComplete,
+ weak_ptr_factory_.GetWeakPtr(), metadata);
+ return viz::ScopedSurfaceIdAllocator(std::move(allocation_task));
+}
+#endif
+
+viz::SurfaceId CefRenderWidgetHostViewOSR::GetCurrentSurfaceId() const {
+ return delegated_frame_host_ ? delegated_frame_host_->GetCurrentSurfaceId()
+ : viz::SurfaceId();
+}
+
+void CefRenderWidgetHostViewOSR::ImeSetComposition(
+ const CefString& text,
+ const std::vector<CefCompositionUnderline>& underlines,
+ const CefRange& replacement_range,
+ const CefRange& selection_range) {
+ TRACE_EVENT0("cef", "CefRenderWidgetHostViewOSR::ImeSetComposition");
+ if (!render_widget_host_) {
+ return;
+ }
+
+ std::vector<ui::ImeTextSpan> web_underlines;
+ web_underlines.reserve(underlines.size());
+ for (const CefCompositionUnderline& line : underlines) {
+ web_underlines.push_back(ui::ImeTextSpan(
+ ui::ImeTextSpan::Type::kComposition, line.range.from, line.range.to,
+ line.thick ? ui::ImeTextSpan::Thickness::kThick
+ : ui::ImeTextSpan::Thickness::kThin,
+ GetImeUnderlineStyle(line.style), line.background_color, line.color,
+ std::vector<std::string>()));
+ }
+ gfx::Range range(replacement_range.from, replacement_range.to);
+
+ // Start Monitoring for composition updates before we set.
+ RequestImeCompositionUpdate(true);
+
+ render_widget_host_->ImeSetComposition(
+ text, web_underlines, range, selection_range.from, selection_range.to);
+}
+
+void CefRenderWidgetHostViewOSR::ImeCommitText(
+ const CefString& text,
+ const CefRange& replacement_range,
+ int relative_cursor_pos) {
+ TRACE_EVENT0("cef", "CefRenderWidgetHostViewOSR::ImeCommitText");
+ if (!render_widget_host_) {
+ return;
+ }
+
+ gfx::Range range(replacement_range.from, replacement_range.to);
+ render_widget_host_->ImeCommitText(text, std::vector<ui::ImeTextSpan>(),
+ range, relative_cursor_pos);
+
+ // Stop Monitoring for composition updates after we are done.
+ RequestImeCompositionUpdate(false);
+}
+
+void CefRenderWidgetHostViewOSR::ImeFinishComposingText(bool keep_selection) {
+ TRACE_EVENT0("cef", "CefRenderWidgetHostViewOSR::ImeFinishComposingText");
+ if (!render_widget_host_) {
+ return;
+ }
+
+ render_widget_host_->ImeFinishComposingText(keep_selection);
+
+ // Stop Monitoring for composition updates after we are done.
+ RequestImeCompositionUpdate(false);
+}
+
+void CefRenderWidgetHostViewOSR::ImeCancelComposition() {
+ TRACE_EVENT0("cef", "CefRenderWidgetHostViewOSR::ImeCancelComposition");
+ if (!render_widget_host_) {
+ return;
+ }
+
+ render_widget_host_->ImeCancelComposition();
+
+ // Stop Monitoring for composition updates after we are done.
+ RequestImeCompositionUpdate(false);
+}
+
+void CefRenderWidgetHostViewOSR::SelectionChanged(const std::u16string& text,
+ size_t offset,
+ const gfx::Range& range) {
+ RenderWidgetHostViewBase::SelectionChanged(text, offset, range);
+
+ if (!browser_impl_.get()) {
+ return;
+ }
+
+ CefString selected_text;
+ if (!range.is_empty() && !text.empty()) {
+ size_t pos = range.GetMin() - offset;
+ size_t n = range.length();
+ if (pos + n <= text.length()) {
+ selected_text = text.substr(pos, n);
+ }
+ }
+
+ CefRefPtr<CefRenderHandler> handler =
+ browser_impl_->GetClient()->GetRenderHandler();
+ CHECK(handler);
+
+ CefRange cef_range(range.start(), range.end());
+ handler->OnTextSelectionChanged(browser_impl_.get(), selected_text,
+ cef_range);
+}
+
+const viz::LocalSurfaceId& CefRenderWidgetHostViewOSR::GetLocalSurfaceId()
+ const {
+ return const_cast<CefRenderWidgetHostViewOSR*>(this)
+ ->GetOrCreateLocalSurfaceId();
+}
+
+const viz::FrameSinkId& CefRenderWidgetHostViewOSR::GetFrameSinkId() const {
+ return delegated_frame_host_
+ ? delegated_frame_host_->frame_sink_id()
+ : viz::FrameSinkIdAllocator::InvalidFrameSinkId();
+}
+
+viz::FrameSinkId CefRenderWidgetHostViewOSR::GetRootFrameSinkId() {
+ return compositor_ ? compositor_->frame_sink_id() : viz::FrameSinkId();
+}
+
+void CefRenderWidgetHostViewOSR::NotifyHostAndDelegateOnWasShown(
+ blink::mojom::RecordContentToVisibleTimeRequestPtr visible_time_request) {
+ // We don't call RenderWidgetHostViewBase::OnShowWithPageVisibility, so this
+ // method should not be called.
+ NOTREACHED();
+}
+
+void CefRenderWidgetHostViewOSR::RequestPresentationTimeFromHostOrDelegate(
+ blink::mojom::RecordContentToVisibleTimeRequestPtr visible_time_request) {
+ // We don't call RenderWidgetHostViewBase::OnShowWithPageVisibility, so this
+ // method should not be called.
+ NOTREACHED();
+}
+
+void CefRenderWidgetHostViewOSR::
+ CancelPresentationTimeRequestForHostAndDelegate() {
+ // We don't call RenderWidgetHostViewBase::OnShowWithPageVisibility, so this
+ // method should not be called.
+ NOTREACHED();
+}
+
+std::unique_ptr<content::SyntheticGestureTarget>
+CefRenderWidgetHostViewOSR::CreateSyntheticGestureTarget() {
+ return std::make_unique<CefSyntheticGestureTargetOSR>(host());
+}
+
+bool CefRenderWidgetHostViewOSR::TransformPointToCoordSpaceForView(
+ const gfx::PointF& point,
+ RenderWidgetHostViewBase* target_view,
+ gfx::PointF* transformed_point) {
+ if (target_view == this) {
+ *transformed_point = point;
+ return true;
+ }
+
+ return target_view->TransformPointToLocalCoordSpace(
+ point, GetCurrentSurfaceId(), transformed_point);
+}
+
+void CefRenderWidgetHostViewOSR::DidNavigate() {
+ if (!IsShowing()) {
+ // Navigating while hidden should not allocate a new LocalSurfaceID. Once
+ // sizes are ready, or we begin to Show, we can then allocate the new
+ // LocalSurfaceId.
+ InvalidateLocalSurfaceId();
+ } else {
+ if (is_first_navigation_) {
+ // The first navigation does not need a new LocalSurfaceID. The renderer
+ // can use the ID that was already provided.
+ SynchronizeVisualProperties(cc::DeadlinePolicy::UseExistingDeadline(),
+ GetLocalSurfaceId());
+ } else {
+ SynchronizeVisualProperties(cc::DeadlinePolicy::UseExistingDeadline(),
+ absl::nullopt);
+ }
+ }
+ if (delegated_frame_host_) {
+ delegated_frame_host_->DidNavigate();
+ }
+ is_first_navigation_ = false;
+}
+
+void CefRenderWidgetHostViewOSR::OnFrameComplete(
+ const viz::BeginFrameAck& ack) {
+ DCHECK(begin_frame_pending_);
+ DCHECK_EQ(begin_frame_source_.source_id(), ack.frame_id.source_id);
+ DCHECK_EQ(begin_frame_number_, ack.frame_id.sequence_number);
+ begin_frame_pending_ = false;
+}
+
+void CefRenderWidgetHostViewOSR::OnRenderFrameMetadataChangedAfterActivation(
+ base::TimeTicks activation_time) {
+ auto metadata =
+ host_->render_frame_metadata_provider()->LastRenderFrameMetadata();
+
+ if (video_consumer_) {
+ // Need to wait for the first frame of the new size before calling
+ // SizeChanged. Otherwise, the video frame will be letterboxed.
+ video_consumer_->SizeChanged(metadata.viewport_size_in_pixels);
+ }
+
+ gfx::PointF root_scroll_offset;
+ if (metadata.root_scroll_offset) {
+ root_scroll_offset = *metadata.root_scroll_offset;
+ }
+ if (root_scroll_offset != last_scroll_offset_) {
+ last_scroll_offset_ = root_scroll_offset;
+
+ if (!is_scroll_offset_changed_pending_) {
+ is_scroll_offset_changed_pending_ = true;
+
+ // Send the notification asynchronously.
+ CEF_POST_TASK(
+ CEF_UIT,
+ base::BindOnce(&CefRenderWidgetHostViewOSR::OnScrollOffsetChanged,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
+ }
+
+ if (metadata.selection.start != selection_start_ ||
+ metadata.selection.end != selection_end_) {
+ selection_start_ = metadata.selection.start;
+ selection_end_ = metadata.selection.end;
+ selection_controller_client_->UpdateClientSelectionBounds(selection_start_,
+ selection_end_);
+ }
+}
+
+std::unique_ptr<viz::HostDisplayClient>
+CefRenderWidgetHostViewOSR::CreateHostDisplayClient() {
+ host_display_client_ =
+ new CefHostDisplayClientOSR(this, gfx::kNullAcceleratedWidget);
+ host_display_client_->SetActive(true);
+ return base::WrapUnique(host_display_client_);
+}
+
+bool CefRenderWidgetHostViewOSR::InstallTransparency() {
+ if (background_color_ == SK_ColorTRANSPARENT) {
+ SetBackgroundColor(background_color_);
+ if (compositor_) {
+ compositor_->SetBackgroundColor(background_color_);
+ }
+ return true;
+ }
+ return false;
+}
+
+void CefRenderWidgetHostViewOSR::WasResized() {
+ // Only one resize will be in-flight at a time.
+ if (hold_resize_) {
+ if (!pending_resize_) {
+ pending_resize_ = true;
+ }
+ return;
+ }
+
+ SynchronizeVisualProperties(cc::DeadlinePolicy::UseExistingDeadline(),
+ absl::nullopt);
+}
+
+void CefRenderWidgetHostViewOSR::SynchronizeVisualProperties(
+ const cc::DeadlinePolicy& deadline_policy,
+ const absl::optional<viz::LocalSurfaceId>& child_local_surface_id) {
+ SetFrameRate();
+
+ const bool resized = ResizeRootLayer();
+ bool surface_id_updated = false;
+
+ if (!resized && child_local_surface_id) {
+ // Update the current surface ID.
+ parent_local_surface_id_allocator_->UpdateFromChild(
+ *child_local_surface_id);
+ surface_id_updated = true;
+ }
+
+ // Allocate a new surface ID if the surface has been resized or if the current
+ // ID is invalid (meaning we may have been evicted).
+ if (resized || !GetCurrentLocalSurfaceId().is_valid()) {
+ AllocateLocalSurfaceId();
+ surface_id_updated = true;
+ }
+
+ if (surface_id_updated) {
+ delegated_frame_host_->EmbedSurface(
+ GetCurrentLocalSurfaceId(), GetViewBounds().size(), deadline_policy);
+
+ // |render_widget_host_| will retrieve resize parameters from the
+ // DelegatedFrameHost and this view, so SynchronizeVisualProperties must be
+ // called last.
+ if (render_widget_host_) {
+ render_widget_host_->SynchronizeVisualProperties();
+ }
+ }
+}
+
+void CefRenderWidgetHostViewOSR::OnScreenInfoChanged() {
+ TRACE_EVENT0("cef", "CefRenderWidgetHostViewOSR::OnScreenInfoChanged");
+ InvalidateLocalSurfaceId();
+ if (!render_widget_host_) {
+ return;
+ }
+
+ SynchronizeVisualProperties(cc::DeadlinePolicy::UseDefaultDeadline(),
+ absl::nullopt);
+
+ if (render_widget_host_->delegate()) {
+ render_widget_host_->delegate()->SendScreenRects();
+ } else {
+ render_widget_host_->SendScreenRects();
+ }
+
+ render_widget_host_->NotifyScreenInfoChanged();
+
+ // We might want to change the cursor scale factor here as well - see the
+ // cache for the current_cursor_, as passed by UpdateCursor from the
+ // renderer in the rwhv_aura (current_cursor_.SetScaleFactor)
+
+ // Notify the guest hosts if any.
+ for (auto guest_host_view : guest_host_views_) {
+ guest_host_view->OnScreenInfoChanged();
+ }
+}
+
+void CefRenderWidgetHostViewOSR::Invalidate(
+ CefBrowserHost::PaintElementType type) {
+ TRACE_EVENT1("cef", "CefRenderWidgetHostViewOSR::Invalidate", "type", type);
+ if (!IsPopupWidget() && type == PET_POPUP) {
+ if (popup_host_view_) {
+ popup_host_view_->Invalidate(type);
+ }
+ return;
+ }
+ InvalidateInternal(gfx::Rect(SizeInPixels()));
+}
+
+void CefRenderWidgetHostViewOSR::SendExternalBeginFrame() {
+ DCHECK(external_begin_frame_enabled_);
+
+ if (begin_frame_pending_) {
+ return;
+ }
+ begin_frame_pending_ = true;
+
+ base::TimeTicks frame_time = base::TimeTicks::Now();
+ base::TimeTicks deadline = base::TimeTicks();
+ base::TimeDelta interval = viz::BeginFrameArgs::DefaultInterval();
+
+ viz::BeginFrameArgs begin_frame_args = viz::BeginFrameArgs::Create(
+ BEGINFRAME_FROM_HERE, begin_frame_source_.source_id(),
+ ++begin_frame_number_, frame_time, deadline, interval,
+ viz::BeginFrameArgs::NORMAL);
+
+ DCHECK(begin_frame_args.IsValid());
+
+ if (render_widget_host_) {
+ render_widget_host_->ProgressFlingIfNeeded(frame_time);
+ }
+
+ if (compositor_) {
+ compositor_->IssueExternalBeginFrame(
+ begin_frame_args, /* force= */ true,
+ base::BindOnce(&CefRenderWidgetHostViewOSR::OnFrameComplete,
+ weak_ptr_factory_.GetWeakPtr()));
+ } else {
+ begin_frame_pending_ = false;
+ }
+
+ if (!IsPopupWidget() && popup_host_view_) {
+ popup_host_view_->SendExternalBeginFrame();
+ }
+}
+
+void CefRenderWidgetHostViewOSR::SendKeyEvent(
+ const content::NativeWebKeyboardEvent& event) {
+ TRACE_EVENT0("cef", "CefRenderWidgetHostViewOSR::SendKeyEvent");
+ content::RenderWidgetHostImpl* target_host = render_widget_host_;
+
+ if (selection_controller_client_) {
+ selection_controller_client_->CloseQuickMenuAndHideHandles();
+ }
+
+ // If there are multiple widgets on the page (such as when there are
+ // out-of-process iframes), pick the one that should process this event.
+ if (render_widget_host_ && render_widget_host_->delegate()) {
+ target_host = render_widget_host_->delegate()->GetFocusedRenderWidgetHost(
+ render_widget_host_);
+ }
+
+ if (target_host && target_host->GetView()) {
+ // Direct routing requires that events go directly to the View.
+ target_host->ForwardKeyboardEventWithLatencyInfo(
+ event,
+ ui::LatencyInfo(event.GetType() == blink::WebInputEvent::Type::kChar ||
+ event.GetType() ==
+ blink::WebInputEvent::Type::kRawKeyDown
+ ? ui::SourceEventType::KEY_PRESS
+ : ui::SourceEventType::OTHER));
+ }
+}
+
+void CefRenderWidgetHostViewOSR::SendMouseEvent(
+ const blink::WebMouseEvent& event) {
+ TRACE_EVENT0("cef", "CefRenderWidgetHostViewOSR::SendMouseEvent");
+ if (!IsPopupWidget()) {
+ if (browser_impl_ &&
+ event.GetType() == blink::WebMouseEvent::Type::kMouseDown &&
+ event.button != blink::WebPointerProperties::Button::kRight) {
+ browser_impl_->CancelContextMenu();
+ }
+
+ if (selection_controller_client_) {
+ selection_controller_client_->CloseQuickMenuAndHideHandles();
+ }
+
+ if (popup_host_view_) {
+ if (popup_host_view_->popup_position_.Contains(
+ event.PositionInWidget().x(), event.PositionInWidget().y())) {
+ blink::WebMouseEvent popup_event(event);
+ popup_event.SetPositionInWidget(
+ event.PositionInWidget().x() -
+ popup_host_view_->popup_position_.x(),
+ event.PositionInWidget().y() -
+ popup_host_view_->popup_position_.y());
+ popup_event.SetPositionInScreen(popup_event.PositionInWidget().x(),
+ popup_event.PositionInWidget().y());
+
+ popup_host_view_->SendMouseEvent(popup_event);
+ return;
+ }
+ } else if (!guest_host_views_.empty()) {
+ for (auto guest_host_view : guest_host_views_) {
+ if (!guest_host_view->render_widget_host_ ||
+ !guest_host_view->render_widget_host_->GetView()) {
+ continue;
+ }
+ const gfx::Rect& guest_bounds =
+ guest_host_view->render_widget_host_->GetView()->GetViewBounds();
+ if (guest_bounds.Contains(event.PositionInWidget().x(),
+ event.PositionInWidget().y())) {
+ blink::WebMouseEvent guest_event(event);
+ guest_event.SetPositionInWidget(
+ event.PositionInWidget().x() - guest_bounds.x(),
+ event.PositionInWidget().y() - guest_bounds.y());
+ guest_event.SetPositionInScreen(guest_event.PositionInWidget().x(),
+ guest_event.PositionInWidget().y());
+
+ guest_host_view->SendMouseEvent(guest_event);
+ return;
+ }
+ }
+ }
+ }
+
+ if (render_widget_host_ && render_widget_host_->GetView()) {
+ if (ShouldRouteEvents()) {
+ // RouteMouseEvent wants non-const pointer to WebMouseEvent, but it only
+ // forwards it to RenderWidgetTargeter::FindTargetAndDispatch as a const
+ // reference, so const_cast here is safe.
+ render_widget_host_->delegate()->GetInputEventRouter()->RouteMouseEvent(
+ this, const_cast<blink::WebMouseEvent*>(&event),
+ ui::LatencyInfo(ui::SourceEventType::OTHER));
+ } else {
+ render_widget_host_->GetView()->ProcessMouseEvent(
+ event, ui::LatencyInfo(ui::SourceEventType::OTHER));
+ }
+ }
+}
+
+void CefRenderWidgetHostViewOSR::SendMouseWheelEvent(
+ const blink::WebMouseWheelEvent& event) {
+ TRACE_EVENT0("cef", "CefRenderWidgetHostViewOSR::SendMouseWheelEvent");
+
+ if (!IsPopupWidget()) {
+ if (browser_impl_) {
+ browser_impl_->CancelContextMenu();
+ }
+
+ if (selection_controller_client_) {
+ selection_controller_client_->CloseQuickMenuAndHideHandles();
+ }
+
+ if (popup_host_view_) {
+ if (popup_host_view_->popup_position_.Contains(
+ event.PositionInWidget().x(), event.PositionInWidget().y())) {
+ blink::WebMouseWheelEvent popup_mouse_wheel_event(event);
+ popup_mouse_wheel_event.SetPositionInWidget(
+ event.PositionInWidget().x() -
+ popup_host_view_->popup_position_.x(),
+ event.PositionInWidget().y() -
+ popup_host_view_->popup_position_.y());
+ popup_mouse_wheel_event.SetPositionInScreen(
+ popup_mouse_wheel_event.PositionInWidget().x(),
+ popup_mouse_wheel_event.PositionInWidget().y());
+
+ popup_host_view_->SendMouseWheelEvent(popup_mouse_wheel_event);
+ return;
+ } else {
+ // Scrolling outside of the popup widget so destroy it.
+ // Execute asynchronously to avoid deleting the widget from inside
+ // some other callback.
+ CEF_POST_TASK(
+ CEF_UIT,
+ base::BindOnce(&CefRenderWidgetHostViewOSR::CancelWidget,
+ popup_host_view_->weak_ptr_factory_.GetWeakPtr()));
+ }
+ } else if (!guest_host_views_.empty()) {
+ for (auto guest_host_view : guest_host_views_) {
+ if (!guest_host_view->render_widget_host_ ||
+ !guest_host_view->render_widget_host_->GetView()) {
+ continue;
+ }
+ const gfx::Rect& guest_bounds =
+ guest_host_view->render_widget_host_->GetView()->GetViewBounds();
+ if (guest_bounds.Contains(event.PositionInWidget().x(),
+ event.PositionInWidget().y())) {
+ blink::WebMouseWheelEvent guest_mouse_wheel_event(event);
+ guest_mouse_wheel_event.SetPositionInWidget(
+ event.PositionInWidget().x() - guest_bounds.x(),
+ event.PositionInWidget().y() - guest_bounds.y());
+ guest_mouse_wheel_event.SetPositionInScreen(
+ guest_mouse_wheel_event.PositionInWidget().x(),
+ guest_mouse_wheel_event.PositionInWidget().y());
+
+ guest_host_view->SendMouseWheelEvent(guest_mouse_wheel_event);
+ return;
+ }
+ }
+ }
+ }
+
+ if (render_widget_host_ && render_widget_host_->GetView()) {
+ blink::WebMouseWheelEvent mouse_wheel_event(event);
+
+ mouse_wheel_phase_handler_.SendWheelEndForTouchpadScrollingIfNeeded(false);
+ mouse_wheel_phase_handler_.AddPhaseIfNeededAndScheduleEndEvent(
+ mouse_wheel_event, false);
+
+ if (ShouldRouteEvents()) {
+ render_widget_host_->delegate()
+ ->GetInputEventRouter()
+ ->RouteMouseWheelEvent(
+ this, const_cast<blink::WebMouseWheelEvent*>(&mouse_wheel_event),
+ ui::LatencyInfo(ui::SourceEventType::WHEEL));
+ } else {
+ render_widget_host_->GetView()->ProcessMouseWheelEvent(
+ mouse_wheel_event, ui::LatencyInfo(ui::SourceEventType::WHEEL));
+ }
+ }
+}
+
+void CefRenderWidgetHostViewOSR::SendTouchEvent(const CefTouchEvent& event) {
+ TRACE_EVENT0("cef", "CefRenderWidgetHostViewOSR::SendTouchEvent");
+
+ if (!IsPopupWidget() && popup_host_view_) {
+ if (!forward_touch_to_popup_ && event.type == CEF_TET_PRESSED &&
+ pointer_state_.GetPointerCount() == 0) {
+ forward_touch_to_popup_ =
+ popup_host_view_->popup_position_.Contains(event.x, event.y);
+ }
+
+ if (forward_touch_to_popup_) {
+ CefTouchEvent popup_event(event);
+ popup_event.x -= popup_host_view_->popup_position_.x();
+ popup_event.y -= popup_host_view_->popup_position_.y();
+ popup_host_view_->SendTouchEvent(popup_event);
+ return;
+ }
+ }
+
+ // Update the touch event first.
+ if (!pointer_state_.OnTouch(event)) {
+ return;
+ }
+
+ if (selection_controller_->WillHandleTouchEvent(pointer_state_)) {
+ pointer_state_.CleanupRemovedTouchPoints(event);
+ return;
+ }
+
+ ui::FilteredGestureProvider::TouchHandlingResult result =
+ gesture_provider_.OnTouchEvent(pointer_state_);
+
+ blink::WebTouchEvent touch_event = ui::CreateWebTouchEventFromMotionEvent(
+ pointer_state_, result.moved_beyond_slop_region, false);
+
+ pointer_state_.CleanupRemovedTouchPoints(event);
+
+ // Set unchanged touch point to StateStationary for touchmove and
+ // touchcancel to make sure only send one ack per WebTouchEvent.
+ if (!result.succeeded) {
+ pointer_state_.MarkUnchangedTouchPointsAsStationary(&touch_event, event);
+ }
+
+ if (!render_widget_host_) {
+ return;
+ }
+
+ ui::LatencyInfo latency_info = CreateLatencyInfo(touch_event);
+ if (ShouldRouteEvents()) {
+ render_widget_host_->delegate()->GetInputEventRouter()->RouteTouchEvent(
+ this, &touch_event, latency_info);
+ } else {
+ render_widget_host_->ForwardTouchEventWithLatencyInfo(touch_event,
+ latency_info);
+ }
+
+ bool touch_end =
+ touch_event.GetType() == blink::WebInputEvent::Type::kTouchEnd ||
+ touch_event.GetType() == blink::WebInputEvent::Type::kTouchCancel;
+
+ if (touch_end && IsPopupWidget() && parent_host_view_ &&
+ parent_host_view_->popup_host_view_ == this) {
+ parent_host_view_->forward_touch_to_popup_ = false;
+ }
+}
+
+bool CefRenderWidgetHostViewOSR::ShouldRouteEvents() const {
+ if (!render_widget_host_->delegate()) {
+ return false;
+ }
+
+ // Do not route events that are currently targeted to page popups such as
+ // <select> element drop-downs, since these cannot contain cross-process
+ // frames.
+ if (!render_widget_host_->delegate()->IsWidgetForPrimaryMainFrame(
+ render_widget_host_)) {
+ return false;
+ }
+
+ return !!render_widget_host_->delegate()->GetInputEventRouter();
+}
+
+void CefRenderWidgetHostViewOSR::SetFocus(bool focus) {
+ if (!render_widget_host_) {
+ return;
+ }
+
+ content::RenderWidgetHostImpl* widget =
+ content::RenderWidgetHostImpl::From(render_widget_host_);
+ if (focus) {
+ widget->GotFocus();
+ widget->SetActive(true);
+ } else {
+ if (browser_impl_) {
+ browser_impl_->CancelContextMenu();
+ }
+
+ if (selection_controller_client_) {
+ selection_controller_client_->CloseQuickMenuAndHideHandles();
+ }
+
+ widget->SetActive(false);
+ widget->LostFocus();
+ }
+}
+
+void CefRenderWidgetHostViewOSR::OnUpdateTextInputStateCalled(
+ content::TextInputManager* text_input_manager,
+ content::RenderWidgetHostViewBase* updated_view,
+ bool did_update_state) {
+ const auto state = text_input_manager->GetTextInputState();
+ if (state && !state->show_ime_if_needed) {
+ return;
+ }
+
+ CefRenderHandler::TextInputMode mode = CEF_TEXT_INPUT_MODE_NONE;
+ if (state && state->type != ui::TEXT_INPUT_TYPE_NONE) {
+ static_assert(
+ static_cast<int>(CEF_TEXT_INPUT_MODE_MAX) ==
+ static_cast<int>(ui::TEXT_INPUT_MODE_MAX),
+ "Enum values in cef_text_input_mode_t must match ui::TextInputMode");
+ mode = static_cast<CefRenderHandler::TextInputMode>(state->mode);
+ }
+
+ CefRefPtr<CefRenderHandler> handler =
+ browser_impl_->GetClient()->GetRenderHandler();
+ CHECK(handler);
+
+ handler->OnVirtualKeyboardRequested(browser_impl_->GetBrowser(), mode);
+}
+
+void CefRenderWidgetHostViewOSR::ProcessAckedTouchEvent(
+ const content::TouchEventWithLatencyInfo& touch,
+ blink::mojom::InputEventResultState ack_result) {
+ const bool event_consumed =
+ ack_result == blink::mojom::InputEventResultState::kConsumed;
+ gesture_provider_.OnTouchEventAck(touch.event.unique_touch_event_id,
+ event_consumed, false);
+}
+
+void CefRenderWidgetHostViewOSR::OnGestureEvent(
+ const ui::GestureEventData& gesture) {
+ if ((gesture.type() == ui::ET_GESTURE_PINCH_BEGIN ||
+ gesture.type() == ui::ET_GESTURE_PINCH_UPDATE ||
+ gesture.type() == ui::ET_GESTURE_PINCH_END) &&
+ !pinch_zoom_enabled_) {
+ return;
+ }
+
+ blink::WebGestureEvent web_event =
+ ui::CreateWebGestureEventFromGestureEventData(gesture);
+
+ // without this check, forwarding gestures does not work!
+ if (web_event.GetType() == blink::WebInputEvent::Type::kUndefined) {
+ return;
+ }
+
+ ui::LatencyInfo latency_info = CreateLatencyInfo(web_event);
+ if (ShouldRouteEvents()) {
+ render_widget_host_->delegate()->GetInputEventRouter()->RouteGestureEvent(
+ this, &web_event, latency_info);
+ } else {
+ render_widget_host_->ForwardGestureEventWithLatencyInfo(web_event,
+ latency_info);
+ }
+}
+
+void CefRenderWidgetHostViewOSR::UpdateFrameRate() {
+ frame_rate_threshold_us_ = 0;
+ SetFrameRate();
+
+ if (video_consumer_) {
+ video_consumer_->SetFrameRate(base::Microseconds(frame_rate_threshold_us_));
+ }
+
+ // Notify the guest hosts if any.
+ for (auto guest_host_view : guest_host_views_) {
+ guest_host_view->UpdateFrameRate();
+ }
+}
+
+gfx::Size CefRenderWidgetHostViewOSR::SizeInPixels() {
+ return gfx::ScaleToCeiledSize(GetViewBounds().size(), GetDeviceScaleFactor());
+}
+
+#if BUILDFLAG(IS_MAC)
+void CefRenderWidgetHostViewOSR::SetActive(bool active) {}
+
+void CefRenderWidgetHostViewOSR::ShowDefinitionForSelection() {}
+
+void CefRenderWidgetHostViewOSR::SpeakSelection() {}
+
+void CefRenderWidgetHostViewOSR::SetWindowFrameInScreen(const gfx::Rect& rect) {
+}
+
+void CefRenderWidgetHostViewOSR::ShowSharePicker(
+ const std::string& title,
+ const std::string& text,
+ const std::string& url,
+ const std::vector<std::string>& file_paths,
+ blink::mojom::ShareService::ShareCallback callback) {
+ std::move(callback).Run(blink::mojom::ShareError::INTERNAL_ERROR);
+}
+#endif // BUILDFLAG(IS_MAC)
+
+void CefRenderWidgetHostViewOSR::OnPaint(const gfx::Rect& damage_rect,
+ const gfx::Size& pixel_size,
+ const void* pixels) {
+ TRACE_EVENT0("cef", "CefRenderWidgetHostViewOSR::OnPaint");
+
+ // Workaround for https://github.com/chromiumembedded/cef/issues/2817
+ if (!is_showing_) {
+ return;
+ }
+
+ if (!pixels) {
+ return;
+ }
+
+ CefRefPtr<CefRenderHandler> handler =
+ browser_impl_->client()->GetRenderHandler();
+ CHECK(handler);
+
+ gfx::Rect rect_in_pixels(0, 0, pixel_size.width(), pixel_size.height());
+ rect_in_pixels.Intersect(damage_rect);
+
+ CefRenderHandler::RectList rcList;
+ rcList.push_back(CefRect(rect_in_pixels.x(), rect_in_pixels.y(),
+ rect_in_pixels.width(), rect_in_pixels.height()));
+
+ handler->OnPaint(browser_impl_.get(), IsPopupWidget() ? PET_POPUP : PET_VIEW,
+ rcList, pixels, pixel_size.width(), pixel_size.height());
+
+ // Release the resize hold when we reach the desired size.
+ if (hold_resize_) {
+ DCHECK_GT(cached_scale_factor_, 0);
+ gfx::Size expected_size =
+ gfx::ScaleToCeiledSize(GetViewBounds().size(), cached_scale_factor_);
+ if (pixel_size == expected_size) {
+ ReleaseResizeHold();
+ }
+ }
+}
+
+ui::Layer* CefRenderWidgetHostViewOSR::GetRootLayer() const {
+ return root_layer_.get();
+}
+
+ui::TextInputType CefRenderWidgetHostViewOSR::GetTextInputType() {
+ if (text_input_manager_ && text_input_manager_->GetTextInputState()) {
+ return text_input_manager_->GetTextInputState()->type;
+ }
+
+ return ui::TEXT_INPUT_TYPE_NONE;
+}
+
+void CefRenderWidgetHostViewOSR::SetFrameRate() {
+ CefRefPtr<AlloyBrowserHostImpl> browser;
+ if (parent_host_view_) {
+ // Use the same frame rate as the embedding browser.
+ browser = parent_host_view_->browser_impl_;
+ } else {
+ browser = browser_impl_;
+ }
+ CHECK(browser);
+
+ // Only set the frame rate one time.
+ if (frame_rate_threshold_us_ != 0) {
+ return;
+ }
+
+ int frame_rate =
+ osr_util::ClampFrameRate(browser->settings().windowless_frame_rate);
+
+ frame_rate_threshold_us_ = 1000000 / frame_rate;
+
+ if (compositor_) {
+ compositor_->SetDisplayVSyncParameters(
+ base::TimeTicks::Now(), base::Microseconds(frame_rate_threshold_us_));
+ }
+
+ if (video_consumer_) {
+ video_consumer_->SetFrameRate(base::Microseconds(frame_rate_threshold_us_));
+ }
+}
+
+bool CefRenderWidgetHostViewOSR::SetScreenInfo() {
+ // This method should not be called while the resize hold is active.
+ DCHECK(!hold_resize_);
+
+ display::ScreenInfo current_info = screen_infos_.current();
+
+ // This will result in a call to GetNewScreenInfosForUpdate().
+ UpdateScreenInfo();
+ if (screen_infos_.current() == current_info) {
+ // Nothing changed.
+ return false;
+ }
+
+ // Notify the guest hosts if any.
+ for (auto guest_host_view : guest_host_views_) {
+ content::RenderWidgetHostImpl* rwhi = guest_host_view->render_widget_host();
+ if (!rwhi) {
+ continue;
+ }
+ auto guest_view_osr =
+ static_cast<CefRenderWidgetHostViewOSR*>(rwhi->GetView());
+ if (guest_view_osr) {
+ guest_view_osr->SetScreenInfo();
+ }
+ }
+
+ return true;
+}
+
+bool CefRenderWidgetHostViewOSR::SetViewBounds() {
+ // This method should not be called while the resize hold is active.
+ DCHECK(!hold_resize_);
+
+ // Popup bounds are set in InitAsPopup.
+ if (IsPopupWidget()) {
+ return false;
+ }
+
+ const gfx::Rect& new_bounds = ::GetViewBounds(browser_impl_.get());
+ if (new_bounds == current_view_bounds_) {
+ return false;
+ }
+
+ current_view_bounds_ = new_bounds;
+ return true;
+}
+
+bool CefRenderWidgetHostViewOSR::SetRootLayerSize(bool force) {
+ const bool screen_info_changed = SetScreenInfo();
+ const bool view_bounds_changed = SetViewBounds();
+ if (!force && !screen_info_changed && !view_bounds_changed) {
+ return false;
+ }
+
+ GetRootLayer()->SetBounds(gfx::Rect(GetViewBounds().size()));
+
+ if (compositor_) {
+ compositor_local_surface_id_allocator_.GenerateId();
+ compositor_->SetScaleAndSize(
+ GetDeviceScaleFactor(), SizeInPixels(),
+ compositor_local_surface_id_allocator_.GetCurrentLocalSurfaceId());
+ }
+
+ return (screen_info_changed || view_bounds_changed);
+}
+
+bool CefRenderWidgetHostViewOSR::ResizeRootLayer() {
+ if (!hold_resize_) {
+ // The resize hold is not currently active.
+ if (SetRootLayerSize(false /* force */)) {
+ // The size has changed. Avoid resizing again until ReleaseResizeHold() is
+ // called.
+ hold_resize_ = true;
+ cached_scale_factor_ = GetDeviceScaleFactor();
+ return true;
+ }
+ } else if (!pending_resize_) {
+ // The resize hold is currently active. Another resize will be triggered
+ // from ReleaseResizeHold().
+ pending_resize_ = true;
+ }
+ return false;
+}
+
+void CefRenderWidgetHostViewOSR::ReleaseResizeHold() {
+ DCHECK(hold_resize_);
+ hold_resize_ = false;
+ cached_scale_factor_ = -1;
+ if (pending_resize_) {
+ pending_resize_ = false;
+ CEF_POST_TASK(CEF_UIT,
+ base::BindOnce(&CefRenderWidgetHostViewOSR::WasResized,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
+}
+
+void CefRenderWidgetHostViewOSR::CancelWidget() {
+ if (render_widget_host_) {
+ render_widget_host_->LostCapture();
+ }
+
+ Hide();
+
+ if (IsPopupWidget() && browser_impl_.get()) {
+ CefRefPtr<CefRenderHandler> handler =
+ browser_impl_->client()->GetRenderHandler();
+ CHECK(handler);
+ handler->OnPopupShow(browser_impl_.get(), false);
+ browser_impl_ = nullptr;
+ }
+
+ if (parent_host_view_) {
+ if (parent_host_view_->popup_host_view_ == this) {
+ parent_host_view_->set_popup_host_view(nullptr);
+ } else if (parent_host_view_->child_host_view_ == this) {
+ parent_host_view_->set_child_host_view(nullptr);
+
+ // Start rendering the parent view again.
+ parent_host_view_->Show();
+ } else {
+ parent_host_view_->RemoveGuestHostView(this);
+ }
+ parent_host_view_ = nullptr;
+ }
+
+ if (render_widget_host_ && !is_destroyed_) {
+ is_destroyed_ = true;
+
+ // Don't delete the RWHI manually while owned by a std::unique_ptr in RVHI.
+ // This matches a CHECK() in RenderWidgetHostImpl::Destroy().
+ const bool also_delete = !render_widget_host_->owner_delegate();
+
+ // Results in a call to Destroy().
+ render_widget_host_->ShutdownAndDestroyWidget(also_delete);
+ }
+}
+
+void CefRenderWidgetHostViewOSR::OnScrollOffsetChanged() {
+ if (browser_impl_.get()) {
+ CefRefPtr<CefRenderHandler> handler =
+ browser_impl_->client()->GetRenderHandler();
+ CHECK(handler);
+ handler->OnScrollOffsetChanged(browser_impl_.get(), last_scroll_offset_.x(),
+ last_scroll_offset_.y());
+ }
+ is_scroll_offset_changed_pending_ = false;
+}
+
+void CefRenderWidgetHostViewOSR::AddGuestHostView(
+ CefRenderWidgetHostViewOSR* guest_host) {
+ guest_host_views_.insert(guest_host);
+}
+
+void CefRenderWidgetHostViewOSR::RemoveGuestHostView(
+ CefRenderWidgetHostViewOSR* guest_host) {
+ guest_host_views_.erase(guest_host);
+}
+
+void CefRenderWidgetHostViewOSR::InvalidateInternal(
+ const gfx::Rect& bounds_in_pixels) {
+ if (video_consumer_) {
+ video_consumer_->RequestRefreshFrame(bounds_in_pixels);
+ } else if (host_display_client_) {
+ OnPaint(bounds_in_pixels, host_display_client_->GetPixelSize(),
+ host_display_client_->GetPixelMemory());
+ }
+}
+
+void CefRenderWidgetHostViewOSR::RequestImeCompositionUpdate(
+ bool start_monitoring) {
+ if (!render_widget_host_) {
+ return;
+ }
+ render_widget_host_->RequestCompositionUpdates(false, start_monitoring);
+}
+
+void CefRenderWidgetHostViewOSR::ImeCompositionRangeChanged(
+ const gfx::Range& range,
+ const std::vector<gfx::Rect>& character_bounds) {
+ if (browser_impl_.get()) {
+ CefRange cef_range(range.start(), range.end());
+ CefRenderHandler::RectList rcList;
+
+ for (size_t i = 0; i < character_bounds.size(); ++i) {
+ rcList.push_back(CefRect(character_bounds[i].x(), character_bounds[i].y(),
+ character_bounds[i].width(),
+ character_bounds[i].height()));
+ }
+
+ CefRefPtr<CefRenderHandler> handler =
+ browser_impl_->GetClient()->GetRenderHandler();
+ CHECK(handler);
+ handler->OnImeCompositionRangeChanged(browser_impl_->GetBrowser(),
+ cef_range, rcList);
+ }
+}
+
+viz::FrameSinkId CefRenderWidgetHostViewOSR::AllocateFrameSinkId() {
+ return render_widget_host_->GetFrameSinkId();
+}
+
+void CefRenderWidgetHostViewOSR::UpdateBackgroundColorFromRenderer(
+ SkColor color) {
+ if (color == background_color_) {
+ return;
+ }
+ background_color_ = color;
+
+ bool opaque = SkColorGetA(color) == SK_AlphaOPAQUE;
+ GetRootLayer()->SetFillsBoundsOpaquely(opaque);
+ GetRootLayer()->SetColor(color);
+}
diff --git a/libcef/browser/osr/render_widget_host_view_osr.h b/libcef/browser/osr/render_widget_host_view_osr.h
new file mode 100644
index 00000000..6a603b32
--- /dev/null
+++ b/libcef/browser/osr/render_widget_host_view_osr.h
@@ -0,0 +1,457 @@
+// Copyright (c) 2014 The Chromium Embedded Framework Authors.
+// Portions copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_OSR_RENDER_WIDGET_HOST_VIEW_OSR_H_
+#define CEF_LIBCEF_BROWSER_OSR_RENDER_WIDGET_HOST_VIEW_OSR_H_
+#pragma once
+
+#include <map>
+#include <set>
+#include <vector>
+
+#include "include/cef_base.h"
+#include "include/cef_browser.h"
+
+#include "libcef/browser/alloy/alloy_browser_host_impl.h"
+#include "libcef/browser/osr/host_display_client_osr.h"
+#include "libcef/browser/osr/motion_event_osr.h"
+
+#include "base/memory/weak_ptr.h"
+#include "build/build_config.h"
+#include "cc/layers/deadline_policy.h"
+#include "components/viz/common/frame_sinks/begin_frame_source.h"
+#include "components/viz/common/surfaces/parent_local_surface_id_allocator.h"
+#include "content/browser/renderer_host/input/mouse_wheel_phase_handler.h"
+#include "content/browser/renderer_host/render_widget_host_view_base.h"
+#include "content/browser/renderer_host/text_input_manager.h"
+#include "content/public/browser/render_frame_metadata_provider.h"
+#include "content/public/common/widget_type.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "third_party/blink/public/mojom/widget/record_content_to_visible_time_request.mojom-forward.h"
+#include "ui/base/cursor/cursor.h"
+#include "ui/base/cursor/mojom/cursor_type.mojom-shared.h"
+#include "ui/base/ime/text_input_client.h"
+#include "ui/compositor/compositor.h"
+#include "ui/events/base_event_utils.h"
+#include "ui/events/gesture_detection/filtered_gesture_provider.h"
+#include "ui/events/gesture_detection/gesture_configuration.h"
+#include "ui/events/gesture_detection/motion_event_generic.h"
+#include "ui/gfx/geometry/rect.h"
+
+#if BUILDFLAG(IS_MAC)
+#include "content/browser/renderer_host/browser_compositor_view_mac.h"
+#endif
+
+#if BUILDFLAG(IS_WIN)
+#include "ui/gfx/win/window_impl.h"
+#endif
+
+namespace ui {
+class TouchSelectionController;
+} // namespace ui
+
+namespace content {
+class BackingStore;
+class CursorManager;
+class DelegatedFrameHost;
+class DelegatedFrameHostClient;
+class RenderWidgetHost;
+class RenderWidgetHostImpl;
+class RenderWidgetHostViewGuest;
+} // namespace content
+
+class CefCopyFrameGenerator;
+class CefSoftwareOutputDeviceOSR;
+class CefTouchSelectionControllerClientOSR;
+class CefVideoConsumerOSR;
+class CefWebContentsViewOSR;
+
+///////////////////////////////////////////////////////////////////////////////
+// CefRenderWidgetHostViewOSR
+//
+// An object representing the "View" of a rendered web page. This object is
+// responsible for sending paint events to the the CefRenderHandler
+// when window rendering is disabled. It is the implementation of the
+// RenderWidgetHostView that the cross-platform RenderWidgetHost object uses
+// to display the data.
+//
+// Comment excerpted from render_widget_host.h:
+//
+// "The lifetime of the RenderWidgetHostView is tied to the render process.
+// If the render process dies, the RenderWidgetHostView goes away and all
+// references to it must become NULL."
+//
+// RenderWidgetHostView class hierarchy described in render_widget_host_view.h.
+///////////////////////////////////////////////////////////////////////////////
+
+#if BUILDFLAG(IS_MAC)
+class MacHelper;
+#endif
+
+class CefRenderWidgetHostViewOSR
+ : public content::RenderWidgetHostViewBase,
+ public content::RenderFrameMetadataProvider::Observer,
+ public ui::CompositorDelegate,
+ public content::TextInputManager::Observer,
+ public ui::GestureProviderClient {
+ public:
+ CefRenderWidgetHostViewOSR(SkColor background_color,
+ bool use_shared_texture,
+ bool use_external_begin_frame,
+ content::RenderWidgetHost* widget,
+ CefRenderWidgetHostViewOSR* parent_host_view);
+
+ CefRenderWidgetHostViewOSR(const CefRenderWidgetHostViewOSR&) = delete;
+ CefRenderWidgetHostViewOSR& operator=(const CefRenderWidgetHostViewOSR&) =
+ delete;
+
+ ~CefRenderWidgetHostViewOSR() override;
+
+ // RenderWidgetHostView implementation.
+ void InitAsChild(gfx::NativeView parent_view) override;
+ void SetSize(const gfx::Size& size) override;
+ void SetBounds(const gfx::Rect& rect) override;
+ gfx::NativeView GetNativeView() override;
+ gfx::NativeViewAccessible GetNativeViewAccessible() override;
+ void Focus() override;
+ bool HasFocus() override;
+ uint32_t GetCaptureSequenceNumber() const override;
+ bool IsSurfaceAvailableForCopy() override;
+ void ShowWithVisibility(
+ content::PageVisibilityState page_visibility) override;
+ void Hide() override;
+ bool IsShowing() override;
+ void EnsureSurfaceSynchronizedForWebTest() override;
+ content::TouchSelectionControllerClientManager*
+ GetTouchSelectionControllerClientManager() override;
+ gfx::Rect GetViewBounds() override;
+ void SetBackgroundColor(SkColor color) override;
+ absl::optional<SkColor> GetBackgroundColor() override;
+ void UpdateBackgroundColor() override;
+ absl::optional<content::DisplayFeature> GetDisplayFeature() override;
+ void SetDisplayFeatureForTesting(
+ const content::DisplayFeature* display_feature) override;
+ blink::mojom::PointerLockResult LockMouse(
+ bool request_unadjusted_movement) override;
+ blink::mojom::PointerLockResult ChangeMouseLock(
+ bool request_unadjusted_movement) override;
+ void UnlockMouse() override;
+ void TakeFallbackContentFrom(content::RenderWidgetHostView* view) override;
+
+#if BUILDFLAG(IS_MAC)
+ void SetActive(bool active) override;
+ void ShowDefinitionForSelection() override;
+ void SpeakSelection() override;
+ void SetWindowFrameInScreen(const gfx::Rect& rect) override;
+ void ShowSharePicker(
+ const std::string& title,
+ const std::string& text,
+ const std::string& url,
+ const std::vector<std::string>& file_paths,
+ blink::mojom::ShareService::ShareCallback callback) override;
+#endif // BUILDFLAG(IS_MAC)
+
+ // RenderWidgetHostViewBase implementation.
+ void ResetFallbackToFirstNavigationSurface() override;
+ void InitAsPopup(content::RenderWidgetHostView* parent_host_view,
+ const gfx::Rect& bounds,
+ const gfx::Rect& anchor_rect) override;
+ void UpdateCursor(const ui::Cursor& cursor) override;
+ void SetIsLoading(bool is_loading) override;
+ void RenderProcessGone() override;
+ void Destroy() override;
+ void UpdateTooltipUnderCursor(const std::u16string& tooltip_text) override;
+ content::CursorManager* GetCursorManager() override;
+ gfx::Size GetCompositorViewportPixelSize() override;
+ void CopyFromSurface(
+ const gfx::Rect& src_rect,
+ const gfx::Size& output_size,
+ base::OnceCallback<void(const SkBitmap&)> callback) override;
+ display::ScreenInfos GetNewScreenInfosForUpdate() override;
+ void TransformPointToRootSurface(gfx::PointF* point) override;
+ gfx::Rect GetBoundsInRootWindow() override;
+
+#if !BUILDFLAG(IS_MAC)
+ viz::ScopedSurfaceIdAllocator DidUpdateVisualProperties(
+ const cc::RenderFrameMetadata& metadata) override;
+#endif
+
+ viz::SurfaceId GetCurrentSurfaceId() const override;
+ void ImeCompositionRangeChanged(
+ const gfx::Range& range,
+ const std::vector<gfx::Rect>& character_bounds) override;
+ std::unique_ptr<content::SyntheticGestureTarget>
+ CreateSyntheticGestureTarget() override;
+ bool TransformPointToCoordSpaceForView(
+ const gfx::PointF& point,
+ RenderWidgetHostViewBase* target_view,
+ gfx::PointF* transformed_point) override;
+ void DidNavigate() override;
+ void SelectionChanged(const std::u16string& text,
+ size_t offset,
+ const gfx::Range& range) override;
+ const viz::LocalSurfaceId& GetLocalSurfaceId() const override;
+ const viz::FrameSinkId& GetFrameSinkId() const override;
+ viz::FrameSinkId GetRootFrameSinkId() override;
+ void NotifyHostAndDelegateOnWasShown(
+ blink::mojom::RecordContentToVisibleTimeRequestPtr visible_time_request)
+ override;
+ void RequestPresentationTimeFromHostOrDelegate(
+ blink::mojom::RecordContentToVisibleTimeRequestPtr visible_time_request)
+ override;
+ void CancelPresentationTimeRequestForHostAndDelegate() override;
+
+ void OnFrameComplete(const viz::BeginFrameAck& ack);
+
+ // RenderFrameMetadataProvider::Observer implementation.
+ void OnRenderFrameMetadataChangedBeforeActivation(
+ const cc::RenderFrameMetadata& metadata) override {}
+ void OnRenderFrameMetadataChangedAfterActivation(
+ base::TimeTicks activation_time) override;
+ void OnRenderFrameSubmission() override {}
+ void OnLocalSurfaceIdChanged(
+ const cc::RenderFrameMetadata& metadata) override {}
+
+ // ui::CompositorDelegate implementation.
+ std::unique_ptr<viz::HostDisplayClient> CreateHostDisplayClient() override;
+
+ // TextInputManager::Observer implementation.
+ void OnUpdateTextInputStateCalled(
+ content::TextInputManager* text_input_manager,
+ RenderWidgetHostViewBase* updated_view,
+ bool did_update_state) override;
+
+ // ui::GestureProviderClient implementation.
+ void ProcessAckedTouchEvent(
+ const content::TouchEventWithLatencyInfo& touch,
+ blink::mojom::InputEventResultState ack_result) override;
+ void OnGestureEvent(const ui::GestureEventData& gesture) override;
+
+ bool InstallTransparency();
+
+ void WasResized();
+ void SynchronizeVisualProperties(
+ const cc::DeadlinePolicy& deadline_policy,
+ const absl::optional<viz::LocalSurfaceId>& child_local_surface_id);
+ void OnScreenInfoChanged();
+ void Invalidate(CefBrowserHost::PaintElementType type);
+ void SendExternalBeginFrame();
+ void SendKeyEvent(const content::NativeWebKeyboardEvent& event);
+ void SendMouseEvent(const blink::WebMouseEvent& event);
+ void SendMouseWheelEvent(const blink::WebMouseWheelEvent& event);
+ void SendTouchEvent(const CefTouchEvent& event);
+ bool ShouldRouteEvents() const;
+ void SetFocus(bool focus);
+ void UpdateFrameRate();
+
+ gfx::Size SizeInPixels();
+ void OnPaint(const gfx::Rect& damage_rect,
+ const gfx::Size& pixel_size,
+ const void* pixels);
+
+ void OnBeginFame(base::TimeTicks frame_time);
+
+ bool IsPopupWidget() const {
+ return widget_type_ == content::WidgetType::kPopup;
+ }
+
+ void ImeSetComposition(const CefString& text,
+ const std::vector<CefCompositionUnderline>& underlines,
+ const CefRange& replacement_range,
+ const CefRange& selection_range);
+ void ImeCommitText(const CefString& text,
+ const CefRange& replacement_range,
+ int relative_cursor_pos);
+ void ImeFinishComposingText(bool keep_selection);
+ void ImeCancelComposition() override;
+
+ CefRefPtr<AlloyBrowserHostImpl> browser_impl() const { return browser_impl_; }
+ void set_browser_impl(CefRefPtr<AlloyBrowserHostImpl> browser) {
+ browser_impl_ = browser;
+ }
+
+ void set_popup_host_view(CefRenderWidgetHostViewOSR* popup_view) {
+ if (popup_view != popup_host_view_) {
+ forward_touch_to_popup_ = false;
+ }
+ popup_host_view_ = popup_view;
+ }
+ void set_child_host_view(CefRenderWidgetHostViewOSR* popup_view) {
+ child_host_view_ = popup_view;
+ }
+
+ content::RenderWidgetHostImpl* render_widget_host() const {
+ return render_widget_host_;
+ }
+ ui::Layer* GetRootLayer() const;
+
+ void OnPresentCompositorFrame();
+
+ void OnDidUpdateVisualPropertiesComplete(
+ const cc::RenderFrameMetadata& metadata);
+
+ void ReleaseCompositor();
+
+ // Marks the current viz::LocalSurfaceId as invalid. AllocateLocalSurfaceId
+ // must be called before submitting new CompositorFrames. May be called by
+ // content::DelegatedFrameHostClient::InvalidateLocalSurfaceIdOnEviction.
+ void InvalidateLocalSurfaceId();
+
+ ui::TouchSelectionController* selection_controller() const {
+ return selection_controller_.get();
+ }
+
+ CefTouchSelectionControllerClientOSR* selection_controller_client() const {
+ return selection_controller_client_.get();
+ }
+
+ ui::TextInputType GetTextInputType();
+
+ bool is_hidden() const { return !is_showing_; }
+
+ private:
+ void SetFrameRate();
+ bool SetScreenInfo();
+ bool SetViewBounds();
+ bool SetRootLayerSize(bool force);
+
+ // Manages resizing so that only one resize request is in-flight at a time.
+ bool ResizeRootLayer();
+ void ReleaseResizeHold();
+
+ void CancelWidget();
+
+ // Helper function to create a selection controller.
+ void CreateSelectionController();
+
+ void OnScrollOffsetChanged();
+
+ void AddGuestHostView(CefRenderWidgetHostViewOSR* guest_host);
+ void RemoveGuestHostView(CefRenderWidgetHostViewOSR* guest_host);
+
+ // Register a callback that will be executed when |guest_host_view| receives
+ // OnSwapCompositorFrame. The callback triggers repaint of the embedder view.
+ void RegisterGuestViewFrameSwappedCallback(
+ content::RenderWidgetHostViewGuest* guest_host_view);
+
+ void OnGuestViewFrameSwapped(
+ content::RenderWidgetHostViewGuest* guest_host_view);
+
+ void InvalidateInternal(const gfx::Rect& bounds_in_pixels);
+
+ void RequestImeCompositionUpdate(bool start_monitoring);
+
+ viz::FrameSinkId AllocateFrameSinkId();
+
+ // Forces the view to allocate a new viz::LocalSurfaceId for the next
+ // CompositorFrame submission in anticipation of a synchronization operation
+ // that does not involve a resize or a device scale factor change.
+ void AllocateLocalSurfaceId();
+ const viz::LocalSurfaceId& GetCurrentLocalSurfaceId() const;
+
+ // Sets the current viz::LocalSurfaceId, in cases where the embedded client
+ // has allocated one. Also sets child sequence number component of the
+ // viz::LocalSurfaceId allocator.
+ void UpdateLocalSurfaceIdFromEmbeddedClient(
+ const absl::optional<viz::LocalSurfaceId>& local_surface_id);
+
+ // Returns the current viz::LocalSurfaceIdAllocation.
+ const viz::LocalSurfaceId& GetOrCreateLocalSurfaceId();
+
+ void AddDamageRect(uint32_t sequence, const gfx::Rect& rect);
+
+ // Applies background color without notifying the RenderWidget about
+ // opaqueness changes.
+ void UpdateBackgroundColorFromRenderer(SkColor color);
+
+ // The last selection bounds reported to the view.
+ gfx::SelectionBound selection_start_;
+ gfx::SelectionBound selection_end_;
+
+ std::unique_ptr<CefTouchSelectionControllerClientOSR>
+ selection_controller_client_;
+ std::unique_ptr<ui::TouchSelectionController> selection_controller_;
+
+ // The background color of the web content.
+ SkColor background_color_;
+
+ int frame_rate_threshold_us_ = 0;
+
+ std::unique_ptr<ui::Compositor> compositor_;
+ std::unique_ptr<content::DelegatedFrameHost> delegated_frame_host_;
+ std::unique_ptr<content::DelegatedFrameHostClient>
+ delegated_frame_host_client_;
+ std::unique_ptr<ui::Layer> root_layer_;
+
+ // Used to allocate LocalSurfaceIds when this is embedding external content.
+ std::unique_ptr<viz::ParentLocalSurfaceIdAllocator>
+ parent_local_surface_id_allocator_;
+ viz::ParentLocalSurfaceIdAllocator compositor_local_surface_id_allocator_;
+
+ std::unique_ptr<content::CursorManager> cursor_manager_;
+
+ // Provides |source_id| for BeginFrameArgs that we create.
+ viz::StubBeginFrameSource begin_frame_source_;
+ uint64_t begin_frame_number_ = viz::BeginFrameArgs::kStartingFrameNumber;
+ bool begin_frame_pending_ = false;
+
+ bool sync_frame_rate_ = false;
+ bool external_begin_frame_enabled_ = false;
+ bool needs_external_begin_frames_ = false;
+
+ CefHostDisplayClientOSR* host_display_client_ = nullptr;
+ std::unique_ptr<CefVideoConsumerOSR> video_consumer_;
+
+ bool hold_resize_ = false;
+ bool pending_resize_ = false;
+
+ float cached_scale_factor_ = 0.0f;
+
+ // The associated Model. While |this| is being Destroyed,
+ // |render_widget_host_| is NULL and the message loop is run one last time
+ // Message handlers must check for a NULL |render_widget_host_|.
+ content::RenderWidgetHostImpl* render_widget_host_;
+
+ bool has_parent_;
+ CefRenderWidgetHostViewOSR* parent_host_view_;
+ CefRenderWidgetHostViewOSR* popup_host_view_ = nullptr;
+ CefRenderWidgetHostViewOSR* child_host_view_ = nullptr;
+ std::set<CefRenderWidgetHostViewOSR*> guest_host_views_;
+
+ CefRefPtr<AlloyBrowserHostImpl> browser_impl_;
+
+ bool is_showing_ = false;
+ bool is_destroyed_ = false;
+ bool is_first_navigation_ = true;
+ gfx::Rect current_view_bounds_;
+ gfx::Rect popup_position_;
+ base::Lock damage_rect_lock_;
+ std::map<uint32_t, gfx::Rect> damage_rects_;
+
+ // Whether pinch-to-zoom should be enabled and pinch events forwarded to the
+ // renderer.
+ bool pinch_zoom_enabled_;
+
+ // The last scroll offset of the view.
+ gfx::PointF last_scroll_offset_;
+ bool is_scroll_offset_changed_pending_ = false;
+
+ content::MouseWheelPhaseHandler mouse_wheel_phase_handler_;
+
+ // Latest capture sequence number which is incremented when the caller
+ // requests surfaces be synchronized via
+ // EnsureSurfaceSynchronizedForLayoutTest().
+ uint32_t latest_capture_sequence_number_ = 0u;
+
+ // ui::GestureProviderClient implementation.
+ ui::FilteredGestureProvider gesture_provider_;
+
+ CefMotionEventOSR pointer_state_;
+ bool forward_touch_to_popup_ = false;
+
+ base::WeakPtrFactory<CefRenderWidgetHostViewOSR> weak_ptr_factory_;
+};
+
+#endif // CEF_LIBCEF_BROWSER_OSR_RENDER_WIDGET_HOST_VIEW_OSR_H_
diff --git a/libcef/browser/osr/software_output_device_proxy.cc b/libcef/browser/osr/software_output_device_proxy.cc
new file mode 100644
index 00000000..85729698
--- /dev/null
+++ b/libcef/browser/osr/software_output_device_proxy.cc
@@ -0,0 +1,151 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cef/libcef/browser/osr/software_output_device_proxy.h"
+
+#include "base/memory/shared_memory_mapping.h"
+#include "base/trace_event/trace_event.h"
+#include "components/viz/common/resources/resource_sizes.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/system/platform_handle.h"
+#include "skia/ext/platform_canvas.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "ui/gfx/skia_util.h"
+
+#if BUILDFLAG(IS_WIN)
+#include <windows.h>
+#include "skia/ext/skia_utils_win.h"
+#include "ui/gfx/gdi_util.h"
+#include "ui/gfx/win/hwnd_util.h"
+#endif
+
+namespace viz {
+
+SoftwareOutputDeviceProxy::~SoftwareOutputDeviceProxy() = default;
+
+SoftwareOutputDeviceProxy::SoftwareOutputDeviceProxy(
+ mojo::PendingRemote<mojom::LayeredWindowUpdater> layered_window_updater)
+ : layered_window_updater_(std::move(layered_window_updater)) {
+ DCHECK(layered_window_updater_.is_bound());
+}
+
+void SoftwareOutputDeviceProxy::OnSwapBuffers(
+ SwapBuffersCallback swap_ack_callback,
+ gfx::FrameData data) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ DCHECK(swap_ack_callback_.is_null());
+
+ // We aren't waiting on DrawAck() and can immediately run the callback.
+ if (!waiting_on_draw_ack_) {
+ task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(std::move(swap_ack_callback), viewport_pixel_size_));
+ return;
+ }
+
+ swap_ack_callback_ =
+ base::BindOnce(std::move(swap_ack_callback), viewport_pixel_size_);
+}
+
+void SoftwareOutputDeviceProxy::Resize(const gfx::Size& viewport_pixel_size,
+ float scale_factor) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ DCHECK(!in_paint_);
+
+ if (viewport_pixel_size_ == viewport_pixel_size) {
+ return;
+ }
+
+ viewport_pixel_size_ = viewport_pixel_size;
+
+ canvas_.reset();
+
+ size_t required_bytes;
+ if (!ResourceSizes::MaybeSizeInBytes(
+ viewport_pixel_size_, ResourceFormat::RGBA_8888, &required_bytes)) {
+ DLOG(ERROR) << "Invalid viewport size " << viewport_pixel_size_.ToString();
+ return;
+ }
+
+ base::UnsafeSharedMemoryRegion region =
+ base::UnsafeSharedMemoryRegion::Create(required_bytes);
+ if (!region.IsValid()) {
+ DLOG(ERROR) << "Failed to allocate " << required_bytes << " bytes";
+ return;
+ }
+
+#if !BUILDFLAG(IS_WIN)
+ auto shm = base::ReadOnlySharedMemoryRegion::Create(required_bytes);
+ if (!shm.IsValid()) {
+ DLOG(ERROR) << "Failed to allocate " << required_bytes << " bytes";
+ return;
+ }
+
+ shm_ = region.Map();
+ if (!shm_.IsValid()) {
+ DLOG(ERROR) << "Failed to map " << required_bytes << " bytes";
+ return;
+ }
+
+ canvas_ = skia::CreatePlatformCanvasWithPixels(
+ viewport_pixel_size_.width(), viewport_pixel_size_.height(), false,
+ static_cast<uint8_t*>(shm_.memory()), skia::CRASH_ON_FAILURE);
+#else
+ canvas_ = skia::CreatePlatformCanvasWithSharedSection(
+ viewport_pixel_size_.width(), viewport_pixel_size_.height(), false,
+ region.GetPlatformHandle(), skia::CRASH_ON_FAILURE);
+#endif
+
+ // Transfer region ownership to the browser process.
+ layered_window_updater_->OnAllocatedSharedMemory(viewport_pixel_size_,
+ std::move(region));
+}
+
+SkCanvas* SoftwareOutputDeviceProxy::BeginPaint(const gfx::Rect& damage_rect) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ DCHECK(!in_paint_);
+
+ damage_rect_ = damage_rect;
+ in_paint_ = true;
+
+ return canvas_.get();
+}
+
+void SoftwareOutputDeviceProxy::EndPaint() {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ DCHECK(in_paint_);
+ DCHECK(!waiting_on_draw_ack_);
+
+ in_paint_ = false;
+
+ gfx::Rect intersected_damage_rect = damage_rect_;
+ intersected_damage_rect.Intersect(gfx::Rect(viewport_pixel_size_));
+ if (intersected_damage_rect.IsEmpty()) {
+ return;
+ }
+
+ if (!canvas_) {
+ return;
+ }
+
+ layered_window_updater_->Draw(
+ damage_rect_, base::BindOnce(&SoftwareOutputDeviceProxy::DrawAck,
+ base::Unretained(this)));
+ waiting_on_draw_ack_ = true;
+
+ TRACE_EVENT_ASYNC_BEGIN0("viz", "SoftwareOutputDeviceProxy::Draw", this);
+}
+
+void SoftwareOutputDeviceProxy::DrawAck() {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ DCHECK(waiting_on_draw_ack_);
+ DCHECK(!swap_ack_callback_.is_null());
+
+ TRACE_EVENT_ASYNC_END0("viz", "SoftwareOutputDeviceProxy::Draw", this);
+
+ waiting_on_draw_ack_ = false;
+ std::move(swap_ack_callback_).Run();
+}
+
+} // namespace viz
diff --git a/libcef/browser/osr/software_output_device_proxy.h b/libcef/browser/osr/software_output_device_proxy.h
new file mode 100644
index 00000000..fc29ae2e
--- /dev/null
+++ b/libcef/browser/osr/software_output_device_proxy.h
@@ -0,0 +1,56 @@
+#ifndef CEF_LIBCEF_BROWSER_OSR_SOFTWARE_OUTPUT_DEVICE_PROXY_H_
+#define CEF_LIBCEF_BROWSER_OSR_SOFTWARE_OUTPUT_DEVICE_PROXY_H_
+
+#include "base/memory/shared_memory_mapping.h"
+#include "base/threading/thread_checker.h"
+#include "components/viz/service/display/software_output_device.h"
+#include "components/viz/service/viz_service_export.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "services/viz/privileged/mojom/compositing/layered_window_updater.mojom.h"
+
+namespace viz {
+
+// SoftwareOutputDevice implementation that draws indirectly. An
+// implementation of mojom::LayeredWindowUpdater in the browser process
+// handles the actual drawing. Pixel backing is in SharedMemory so no copying
+// between processes is required.
+class VIZ_SERVICE_EXPORT SoftwareOutputDeviceProxy
+ : public SoftwareOutputDevice {
+ public:
+ explicit SoftwareOutputDeviceProxy(
+ mojo::PendingRemote<mojom::LayeredWindowUpdater> layered_window_updater);
+
+ SoftwareOutputDeviceProxy(const SoftwareOutputDeviceProxy&) = delete;
+ SoftwareOutputDeviceProxy& operator=(const SoftwareOutputDeviceProxy&) =
+ delete;
+
+ ~SoftwareOutputDeviceProxy() override;
+
+ // SoftwareOutputDevice implementation.
+ void OnSwapBuffers(SwapBuffersCallback swap_ack_callback,
+ gfx::FrameData data) override;
+
+ // SoftwareOutputDeviceBase implementation.
+ void Resize(const gfx::Size& viewport_pixel_size,
+ float scale_factor) override;
+ SkCanvas* BeginPaint(const gfx::Rect& damage_rect) override;
+ void EndPaint() override;
+
+ private:
+ // Runs |swap_ack_callback_| after draw has happened.
+ void DrawAck();
+
+ mojo::Remote<mojom::LayeredWindowUpdater> layered_window_updater_;
+
+ std::unique_ptr<SkCanvas> canvas_;
+ bool waiting_on_draw_ack_ = false;
+ bool in_paint_ = false;
+ base::OnceClosure swap_ack_callback_;
+ base::WritableSharedMemoryMapping shm_;
+
+ THREAD_CHECKER(thread_checker_);
+};
+
+} // namespace viz
+
+#endif // CEF_LIBCEF_BROWSER_OSR_SOFTWARE_OUTPUT_DEVICE_PROXY_H_ \ No newline at end of file
diff --git a/libcef/browser/osr/synthetic_gesture_target_osr.cc b/libcef/browser/osr/synthetic_gesture_target_osr.cc
new file mode 100644
index 00000000..1648d534
--- /dev/null
+++ b/libcef/browser/osr/synthetic_gesture_target_osr.cc
@@ -0,0 +1,60 @@
+// Copyright (c) 2019 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#include "libcef/browser/osr/synthetic_gesture_target_osr.h"
+
+#include "content/browser/renderer_host/render_widget_host_impl.h"
+#include "ui/events/gesture_detection/gesture_configuration.h"
+
+CefSyntheticGestureTargetOSR::CefSyntheticGestureTargetOSR(
+ content::RenderWidgetHostImpl* host)
+ : SyntheticGestureTargetBase(host) {}
+
+void CefSyntheticGestureTargetOSR::DispatchWebTouchEventToPlatform(
+ const blink::WebTouchEvent& web_touch,
+ const ui::LatencyInfo& latency_info) {
+ // We assume that platforms supporting touch have their own implementation of
+ // SyntheticGestureTarget to route the events through their respective input
+ // stack.
+ LOG(ERROR) << "Touch events not supported for this browser.";
+}
+
+void CefSyntheticGestureTargetOSR::DispatchWebMouseWheelEventToPlatform(
+ const blink::WebMouseWheelEvent& web_wheel,
+ const ui::LatencyInfo& latency_info) {
+ render_widget_host()->ForwardWheelEventWithLatencyInfo(web_wheel,
+ latency_info);
+}
+
+void CefSyntheticGestureTargetOSR::DispatchWebGestureEventToPlatform(
+ const blink::WebGestureEvent& web_gesture,
+ const ui::LatencyInfo& latency_info) {
+ render_widget_host()->ForwardGestureEventWithLatencyInfo(web_gesture,
+ latency_info);
+}
+
+void CefSyntheticGestureTargetOSR::DispatchWebMouseEventToPlatform(
+ const blink::WebMouseEvent& web_mouse,
+ const ui::LatencyInfo& latency_info) {
+ render_widget_host()->ForwardMouseEventWithLatencyInfo(web_mouse,
+ latency_info);
+}
+
+content::mojom::GestureSourceType
+CefSyntheticGestureTargetOSR::GetDefaultSyntheticGestureSourceType() const {
+ return content::mojom::GestureSourceType::kMouseInput;
+}
+
+float CefSyntheticGestureTargetOSR::GetTouchSlopInDips() const {
+ return ui::GestureConfiguration::GetInstance()
+ ->max_touch_move_in_pixels_for_click();
+}
+
+float CefSyntheticGestureTargetOSR::GetSpanSlopInDips() const {
+ return ui::GestureConfiguration::GetInstance()->span_slop();
+}
+
+float CefSyntheticGestureTargetOSR::GetMinScalingSpanInDips() const {
+ return ui::GestureConfiguration::GetInstance()->min_scaling_span_in_pixels();
+}
diff --git a/libcef/browser/osr/synthetic_gesture_target_osr.h b/libcef/browser/osr/synthetic_gesture_target_osr.h
new file mode 100644
index 00000000..5e96534b
--- /dev/null
+++ b/libcef/browser/osr/synthetic_gesture_target_osr.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2019 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_OSR_SYNTHETIC_GESTURE_TARGET_OSR_H_
+#define CEF_LIBCEF_BROWSER_OSR_SYNTHETIC_GESTURE_TARGET_OSR_H_
+
+#include "content/browser/renderer_host/input/synthetic_gesture_target_base.h"
+
+// SyntheticGestureTarget implementation for OSR.
+class CefSyntheticGestureTargetOSR
+ : public content::SyntheticGestureTargetBase {
+ public:
+ explicit CefSyntheticGestureTargetOSR(content::RenderWidgetHostImpl* host);
+
+ CefSyntheticGestureTargetOSR(const CefSyntheticGestureTargetOSR&) = delete;
+ CefSyntheticGestureTargetOSR& operator=(const CefSyntheticGestureTargetOSR&) =
+ delete;
+
+ // SyntheticGestureTargetBase:
+ void DispatchWebTouchEventToPlatform(
+ const blink::WebTouchEvent& web_touch,
+ const ui::LatencyInfo& latency_info) override;
+ void DispatchWebMouseWheelEventToPlatform(
+ const blink::WebMouseWheelEvent& web_wheel,
+ const ui::LatencyInfo& latency_info) override;
+ void DispatchWebGestureEventToPlatform(
+ const blink::WebGestureEvent& web_gesture,
+ const ui::LatencyInfo& latency_info) override;
+ void DispatchWebMouseEventToPlatform(
+ const blink::WebMouseEvent& web_mouse,
+ const ui::LatencyInfo& latency_info) override;
+
+ // SyntheticGestureTarget:
+ content::mojom::GestureSourceType GetDefaultSyntheticGestureSourceType()
+ const override;
+ float GetTouchSlopInDips() const override;
+ float GetSpanSlopInDips() const override;
+ float GetMinScalingSpanInDips() const override;
+};
+
+#endif // CEF_LIBCEF_BROWSER_OSR_SYNTHETIC_GESTURE_TARGET_OSR_H_
diff --git a/libcef/browser/osr/touch_handle_drawable_osr.cc b/libcef/browser/osr/touch_handle_drawable_osr.cc
new file mode 100644
index 00000000..96b0e8d5
--- /dev/null
+++ b/libcef/browser/osr/touch_handle_drawable_osr.cc
@@ -0,0 +1,132 @@
+// Copyright 2022 The Chromium Embedded Framework Authors.
+// Portions copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/osr/touch_handle_drawable_osr.h"
+
+#include <cmath>
+
+#include "libcef/browser/osr/render_widget_host_view_osr.h"
+
+#include "ui/gfx/geometry/rect_f.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace {
+// Copied from touch_handle_drawable_aura.cc
+
+// The distance by which a handle image is offset from the focal point (i.e.
+// text baseline) downwards.
+constexpr int kSelectionHandleVerticalVisualOffset = 2;
+
+// The padding around the selection handle image can be used to extend the
+// handle so that touch events near the selection handle image are
+// targeted to the selection handle.
+constexpr int kSelectionHandlePadding = 0;
+
+} // namespace
+
+int CefTouchHandleDrawableOSR::counter_ = 0;
+
+CefTouchHandleDrawableOSR::CefTouchHandleDrawableOSR(
+ CefRenderWidgetHostViewOSR* rwhv)
+ : rwhv_(rwhv), id_(counter_++) {}
+
+void CefTouchHandleDrawableOSR::SetEnabled(bool enabled) {
+ if (enabled == enabled_) {
+ return;
+ }
+
+ enabled_ = enabled;
+
+ CefTouchHandleState touch_handle_state;
+ touch_handle_state.touch_handle_id = id_;
+ touch_handle_state.flags = CEF_THS_FLAG_ENABLED;
+ touch_handle_state.enabled = enabled_;
+ TouchHandleStateChanged(touch_handle_state);
+}
+
+void CefTouchHandleDrawableOSR::SetOrientation(
+ ui::TouchHandleOrientation orientation,
+ bool mirror_vertical,
+ bool mirror_horizontal) {
+ if (orientation == orientation_) {
+ return;
+ }
+
+ orientation_ = orientation;
+
+ CefSize size;
+ auto browser = rwhv_->browser_impl();
+ auto handler = browser->GetClient()->GetRenderHandler();
+ handler->GetTouchHandleSize(
+ browser.get(), static_cast<cef_horizontal_alignment_t>(orientation_),
+ size);
+
+ const gfx::Size& image_size = gfx::Size(size.width, size.height);
+ int handle_width = image_size.width() + 2 * kSelectionHandlePadding;
+ int handle_height = image_size.height() + 2 * kSelectionHandlePadding;
+ relative_bounds_ =
+ gfx::RectF(-kSelectionHandlePadding,
+ kSelectionHandleVerticalVisualOffset - kSelectionHandlePadding,
+ handle_width, handle_height);
+
+ CefTouchHandleState touch_handle_state;
+ touch_handle_state.touch_handle_id = id_;
+ touch_handle_state.flags = CEF_THS_FLAG_ORIENTATION;
+ touch_handle_state.orientation =
+ static_cast<cef_horizontal_alignment_t>(orientation_);
+ touch_handle_state.mirror_vertical = mirror_vertical;
+ touch_handle_state.mirror_horizontal = mirror_horizontal;
+ TouchHandleStateChanged(touch_handle_state);
+}
+
+void CefTouchHandleDrawableOSR::SetOrigin(const gfx::PointF& position) {
+ if (position == origin_position_) {
+ return;
+ }
+
+ origin_position_ = position;
+
+ CefTouchHandleState touch_handle_state;
+ touch_handle_state.touch_handle_id = id_;
+ touch_handle_state.flags = CEF_THS_FLAG_ORIGIN;
+ touch_handle_state.origin = {static_cast<int>(std::round(position.x())),
+ static_cast<int>(std::round(position.y()))};
+ TouchHandleStateChanged(touch_handle_state);
+}
+
+void CefTouchHandleDrawableOSR::SetAlpha(float alpha) {
+ if (alpha == alpha_) {
+ return;
+ }
+
+ alpha_ = alpha;
+
+ CefTouchHandleState touch_handle_state;
+ touch_handle_state.touch_handle_id = id_;
+ touch_handle_state.flags = CEF_THS_FLAG_ALPHA;
+ touch_handle_state.alpha = alpha_;
+ TouchHandleStateChanged(touch_handle_state);
+}
+
+gfx::RectF CefTouchHandleDrawableOSR::GetVisibleBounds() const {
+ gfx::RectF bounds = relative_bounds_;
+ bounds.Offset(origin_position_.x(), origin_position_.y());
+ bounds.Inset(gfx::InsetsF::TLBR(
+ kSelectionHandlePadding,
+ kSelectionHandlePadding + kSelectionHandleVerticalVisualOffset,
+ kSelectionHandlePadding, kSelectionHandlePadding));
+ return bounds;
+}
+
+float CefTouchHandleDrawableOSR::GetDrawableHorizontalPaddingRatio() const {
+ return 0.0f;
+}
+
+void CefTouchHandleDrawableOSR::TouchHandleStateChanged(
+ const CefTouchHandleState& state) {
+ auto browser = rwhv_->browser_impl();
+ auto handler = browser->GetClient()->GetRenderHandler();
+ handler->OnTouchHandleStateChanged(browser.get(), state);
+}
diff --git a/libcef/browser/osr/touch_handle_drawable_osr.h b/libcef/browser/osr/touch_handle_drawable_osr.h
new file mode 100644
index 00000000..4de5c265
--- /dev/null
+++ b/libcef/browser/osr/touch_handle_drawable_osr.h
@@ -0,0 +1,59 @@
+// Copyright 2022 The Chromium Embedded Framework Authors.
+// Portions copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_OSR_TOUCH_HANDLE_DRAWABLE_OSR_H_
+#define CEF_LIBCEF_BROWSER_OSR_TOUCH_HANDLE_DRAWABLE_OSR_H_
+
+#include "include/internal/cef_types_wrappers.h"
+
+#include "base/memory/raw_ptr.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/touch_selection/touch_handle.h"
+#include "ui/touch_selection/touch_handle_orientation.h"
+#include "ui/touch_selection/ui_touch_selection_export.h"
+
+class CefRenderWidgetHostViewOSR;
+
+// Copied from TouchHandleDrawableAura.
+class CefTouchHandleDrawableOSR : public ui::TouchHandleDrawable {
+ public:
+ explicit CefTouchHandleDrawableOSR(CefRenderWidgetHostViewOSR* rwhv);
+
+ CefTouchHandleDrawableOSR(const CefTouchHandleDrawableOSR&) = delete;
+ CefTouchHandleDrawableOSR& operator=(const CefTouchHandleDrawableOSR&) =
+ delete;
+
+ private:
+ // TouchHandleDrawable:
+ void SetEnabled(bool enabled) override;
+ void SetOrientation(ui::TouchHandleOrientation orientation,
+ bool mirror_vertical,
+ bool mirror_horizontal) override;
+ void SetOrigin(const gfx::PointF& position) override;
+ void SetAlpha(float alpha) override;
+ gfx::RectF GetVisibleBounds() const override;
+ float GetDrawableHorizontalPaddingRatio() const override;
+
+ // Pass the current touch handle state to the CefRenderHandler.
+ void TouchHandleStateChanged(const CefTouchHandleState& state);
+
+ raw_ptr<CefRenderWidgetHostViewOSR> rwhv_;
+
+ float alpha_ = 0.f;
+ static int counter_;
+ bool enabled_ = false;
+ int id_;
+ ui::TouchHandleOrientation orientation_ =
+ ui::TouchHandleOrientation::UNDEFINED;
+
+ // Origin position of the handle set via SetOrigin, in coordinate space of
+ // selection controller client (i.e. handle's parent).
+ gfx::PointF origin_position_;
+
+ // Handle bounds relative to the focal position.
+ gfx::RectF relative_bounds_ = gfx::RectF(0.0F, 0.0F, 24.0F, 24.0F);
+};
+
+#endif
diff --git a/libcef/browser/osr/touch_selection_controller_client_osr.cc b/libcef/browser/osr/touch_selection_controller_client_osr.cc
new file mode 100644
index 00000000..3b9bb059
--- /dev/null
+++ b/libcef/browser/osr/touch_selection_controller_client_osr.cc
@@ -0,0 +1,529 @@
+// Copyright 2022 The Chromium Embedded Framework Authors.
+// Portions copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/osr/touch_selection_controller_client_osr.h"
+
+#include <cmath>
+#include <set>
+
+#include "libcef/browser/osr/render_widget_host_view_osr.h"
+#include "libcef/browser/osr/touch_handle_drawable_osr.h"
+
+#include "base/functional/bind.h"
+#include "content/browser/renderer_host/render_widget_host_delegate.h"
+#include "content/browser/renderer_host/render_widget_host_impl.h"
+#include "content/public/browser/context_menu_params.h"
+#include "content/public/browser/render_view_host.h"
+#include "ui/base/clipboard/clipboard.h"
+#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
+#include "ui/base/pointer/touch_editing_controller.h"
+#include "ui/gfx/geometry/point_conversions.h"
+#include "ui/gfx/geometry/size_conversions.h"
+
+namespace {
+
+// Delay before showing the quick menu, in milliseconds.
+constexpr int kQuickMenuDelayInMs = 100;
+
+constexpr cef_quick_menu_edit_state_flags_t kMenuCommands[] = {
+ QM_EDITFLAG_CAN_ELLIPSIS, QM_EDITFLAG_CAN_CUT, QM_EDITFLAG_CAN_COPY,
+ QM_EDITFLAG_CAN_PASTE};
+
+constexpr int kInvalidCommandId = -1;
+constexpr cef_event_flags_t kEmptyEventFlags =
+ static_cast<cef_event_flags_t>(0);
+
+class CefRunQuickMenuCallbackImpl : public CefRunQuickMenuCallback {
+ public:
+ using Callback = base::OnceCallback<void(int, int)>;
+
+ explicit CefRunQuickMenuCallbackImpl(Callback callback)
+ : callback_(std::move(callback)) {}
+
+ CefRunQuickMenuCallbackImpl(const CefRunQuickMenuCallbackImpl&) = delete;
+ CefRunQuickMenuCallbackImpl& operator=(const CefRunQuickMenuCallbackImpl&) =
+ delete;
+
+ ~CefRunQuickMenuCallbackImpl() {
+ if (!callback_.is_null()) {
+ // The callback is still pending. Cancel it now.
+ if (CEF_CURRENTLY_ON_UIT()) {
+ RunNow(std::move(callback_), kInvalidCommandId, kEmptyEventFlags);
+ } else {
+ CEF_POST_TASK(CEF_UIT,
+ base::BindOnce(&CefRunQuickMenuCallbackImpl::RunNow,
+ std::move(callback_), kInvalidCommandId,
+ kEmptyEventFlags));
+ }
+ }
+ }
+
+ void Continue(int command_id, cef_event_flags_t event_flags) override {
+ if (CEF_CURRENTLY_ON_UIT()) {
+ if (!callback_.is_null()) {
+ RunNow(std::move(callback_), command_id, event_flags);
+ }
+ } else {
+ CEF_POST_TASK(CEF_UIT,
+ base::BindOnce(&CefRunQuickMenuCallbackImpl::Continue, this,
+ command_id, event_flags));
+ }
+ }
+
+ void Cancel() override { Continue(kInvalidCommandId, kEmptyEventFlags); }
+
+ void Disconnect() { callback_.Reset(); }
+
+ private:
+ static void RunNow(Callback callback,
+ int command_id,
+ cef_event_flags_t event_flags) {
+ CEF_REQUIRE_UIT();
+ std::move(callback).Run(command_id, event_flags);
+ }
+
+ Callback callback_;
+
+ IMPLEMENT_REFCOUNTING(CefRunQuickMenuCallbackImpl);
+};
+
+} // namespace
+
+CefTouchSelectionControllerClientOSR::CefTouchSelectionControllerClientOSR(
+ CefRenderWidgetHostViewOSR* rwhv)
+ : rwhv_(rwhv),
+ internal_client_(rwhv),
+ active_client_(&internal_client_),
+ active_menu_client_(this),
+ quick_menu_timer_(
+ FROM_HERE,
+ base::Milliseconds(kQuickMenuDelayInMs),
+ base::BindRepeating(
+ &CefTouchSelectionControllerClientOSR::ShowQuickMenu,
+ base::Unretained(this))),
+ weak_ptr_factory_(this) {
+ DCHECK(rwhv_);
+}
+
+CefTouchSelectionControllerClientOSR::~CefTouchSelectionControllerClientOSR() {
+ for (auto& observer : observers_) {
+ observer.OnManagerWillDestroy(this);
+ }
+}
+
+void CefTouchSelectionControllerClientOSR::CloseQuickMenuAndHideHandles() {
+ CloseQuickMenu();
+ rwhv_->selection_controller()->HideAndDisallowShowingAutomatically();
+}
+
+void CefTouchSelectionControllerClientOSR::OnWindowMoved() {
+ UpdateQuickMenu();
+}
+
+void CefTouchSelectionControllerClientOSR::OnTouchDown() {
+ touch_down_ = true;
+ UpdateQuickMenu();
+}
+
+void CefTouchSelectionControllerClientOSR::OnTouchUp() {
+ touch_down_ = false;
+ UpdateQuickMenu();
+}
+
+void CefTouchSelectionControllerClientOSR::OnScrollStarted() {
+ scroll_in_progress_ = true;
+ rwhv_->selection_controller()->SetTemporarilyHidden(true);
+ UpdateQuickMenu();
+}
+
+void CefTouchSelectionControllerClientOSR::OnScrollCompleted() {
+ scroll_in_progress_ = false;
+ active_client_->DidScroll();
+ rwhv_->selection_controller()->SetTemporarilyHidden(false);
+ UpdateQuickMenu();
+}
+
+bool CefTouchSelectionControllerClientOSR::HandleContextMenu(
+ const content::ContextMenuParams& params) {
+ if ((params.source_type == ui::MENU_SOURCE_LONG_PRESS ||
+ params.source_type == ui::MENU_SOURCE_LONG_TAP) &&
+ params.is_editable && params.selection_text.empty() &&
+ IsQuickMenuAvailable()) {
+ quick_menu_requested_ = true;
+ UpdateQuickMenu();
+ return true;
+ }
+
+ const bool from_touch = params.source_type == ui::MENU_SOURCE_LONG_PRESS ||
+ params.source_type == ui::MENU_SOURCE_LONG_TAP ||
+ params.source_type == ui::MENU_SOURCE_TOUCH;
+ if (from_touch && !params.selection_text.empty()) {
+ return true;
+ }
+
+ rwhv_->selection_controller()->HideAndDisallowShowingAutomatically();
+ return false;
+}
+
+void CefTouchSelectionControllerClientOSR::DidStopFlinging() {
+ OnScrollCompleted();
+}
+
+void CefTouchSelectionControllerClientOSR::UpdateClientSelectionBounds(
+ const gfx::SelectionBound& start,
+ const gfx::SelectionBound& end) {
+ UpdateClientSelectionBounds(start, end, &internal_client_, this);
+}
+
+void CefTouchSelectionControllerClientOSR::UpdateClientSelectionBounds(
+ const gfx::SelectionBound& start,
+ const gfx::SelectionBound& end,
+ ui::TouchSelectionControllerClient* client,
+ ui::TouchSelectionMenuClient* menu_client) {
+ if (client != active_client_ &&
+ (start.type() == gfx::SelectionBound::EMPTY || !start.visible()) &&
+ (end.type() == gfx::SelectionBound::EMPTY || !end.visible()) &&
+ (manager_selection_start_.type() != gfx::SelectionBound::EMPTY ||
+ manager_selection_end_.type() != gfx::SelectionBound::EMPTY)) {
+ return;
+ }
+
+ active_client_ = client;
+ active_menu_client_ = menu_client;
+ manager_selection_start_ = start;
+ manager_selection_end_ = end;
+
+ // Notify TouchSelectionController if anything should change here. Only
+ // update if the client is different and not making a change to empty, or
+ // is the same client.
+ GetTouchSelectionController()->OnSelectionBoundsChanged(start, end);
+}
+
+void CefTouchSelectionControllerClientOSR::InvalidateClient(
+ ui::TouchSelectionControllerClient* client) {
+ DCHECK(client != &internal_client_);
+ if (client == active_client_) {
+ active_client_ = &internal_client_;
+ active_menu_client_ = this;
+ }
+}
+
+ui::TouchSelectionController*
+CefTouchSelectionControllerClientOSR::GetTouchSelectionController() {
+ return rwhv_->selection_controller();
+}
+
+void CefTouchSelectionControllerClientOSR::AddObserver(
+ TouchSelectionControllerClientManager::Observer* observer) {
+ observers_.AddObserver(observer);
+}
+
+void CefTouchSelectionControllerClientOSR::RemoveObserver(
+ TouchSelectionControllerClientManager::Observer* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+bool CefTouchSelectionControllerClientOSR::IsQuickMenuAvailable() const {
+ DCHECK(active_menu_client_);
+
+ const auto is_enabled = [this](cef_quick_menu_edit_state_flags_t command) {
+ return active_menu_client_->IsCommandIdEnabled(command);
+ };
+ return std::any_of(std::cbegin(kMenuCommands), std::cend(kMenuCommands),
+ is_enabled);
+}
+
+void CefTouchSelectionControllerClientOSR::CloseQuickMenu() {
+ if (!quick_menu_running_) {
+ return;
+ }
+
+ quick_menu_running_ = false;
+
+ auto browser = rwhv_->browser_impl();
+ if (auto handler = browser->client()->GetContextMenuHandler()) {
+ handler->OnQuickMenuDismissed(browser.get(), browser->GetFocusedFrame());
+ }
+}
+
+void CefTouchSelectionControllerClientOSR::ShowQuickMenu() {
+ auto browser = rwhv_->browser_impl();
+ if (auto handler = browser->client()->GetContextMenuHandler()) {
+ gfx::RectF rect =
+ rwhv_->selection_controller()->GetVisibleRectBetweenBounds();
+
+ gfx::PointF origin = rect.origin();
+ gfx::PointF bottom_right = rect.bottom_right();
+ auto client_bounds = gfx::RectF(rwhv_->GetViewBounds());
+ origin.SetToMax(client_bounds.origin());
+ bottom_right.SetToMin(client_bounds.bottom_right());
+ if (origin.x() > bottom_right.x() || origin.y() > bottom_right.y()) {
+ return;
+ }
+
+ gfx::Vector2dF diagonal = bottom_right - origin;
+ gfx::SizeF size(diagonal.x(), diagonal.y());
+
+ int quickmenuflags = 0;
+ for (const auto& command : kMenuCommands) {
+ if (active_menu_client_->IsCommandIdEnabled(command)) {
+ quickmenuflags |= command;
+ }
+ }
+
+ CefRefPtr<CefRunQuickMenuCallbackImpl> callbackImpl(
+ new CefRunQuickMenuCallbackImpl(base::BindOnce(
+ &CefTouchSelectionControllerClientOSR::ExecuteCommand,
+ weak_ptr_factory_.GetWeakPtr())));
+
+ quick_menu_running_ = true;
+ if (!handler->RunQuickMenu(
+ browser, browser->GetFocusedFrame(),
+ {static_cast<int>(std::round(origin.x())),
+ static_cast<int>(std::round(origin.y()))},
+ {static_cast<int>(std::round(size.width())),
+ static_cast<int>(std::round(size.height()))},
+ static_cast<CefContextMenuHandler::QuickMenuEditStateFlags>(
+ quickmenuflags),
+ callbackImpl)) {
+ callbackImpl->Disconnect();
+ CloseQuickMenu();
+ }
+ }
+}
+
+void CefTouchSelectionControllerClientOSR::UpdateQuickMenu() {
+ // Hide the quick menu if there is any. This should happen even if the menu
+ // should be shown again, in order to update its location or content.
+ if (quick_menu_running_) {
+ CloseQuickMenu();
+ } else {
+ quick_menu_timer_.Stop();
+ }
+
+ // Start timer to show quick menu if necessary.
+ if (ShouldShowQuickMenu()) {
+ quick_menu_timer_.Reset();
+ }
+}
+
+bool CefTouchSelectionControllerClientOSR::SupportsAnimation() const {
+ return false;
+}
+
+bool CefTouchSelectionControllerClientOSR::InternalClient::SupportsAnimation()
+ const {
+ NOTREACHED();
+ return false;
+}
+
+void CefTouchSelectionControllerClientOSR::SetNeedsAnimate() {
+ NOTREACHED();
+}
+
+void CefTouchSelectionControllerClientOSR::InternalClient::SetNeedsAnimate() {
+ NOTREACHED();
+}
+
+void CefTouchSelectionControllerClientOSR::MoveCaret(
+ const gfx::PointF& position) {
+ active_client_->MoveCaret(position);
+}
+
+void CefTouchSelectionControllerClientOSR::InternalClient::MoveCaret(
+ const gfx::PointF& position) {
+ if (auto host_delegate = rwhv_->host()->delegate()) {
+ host_delegate->MoveCaret(gfx::ToRoundedPoint(position));
+ }
+}
+
+void CefTouchSelectionControllerClientOSR::MoveRangeSelectionExtent(
+ const gfx::PointF& extent) {
+ active_client_->MoveRangeSelectionExtent(extent);
+}
+
+void CefTouchSelectionControllerClientOSR::InternalClient::
+ MoveRangeSelectionExtent(const gfx::PointF& extent) {
+ if (auto host_delegate = rwhv_->host()->delegate()) {
+ host_delegate->MoveRangeSelectionExtent(gfx::ToRoundedPoint(extent));
+ }
+}
+
+void CefTouchSelectionControllerClientOSR::SelectBetweenCoordinates(
+ const gfx::PointF& base,
+ const gfx::PointF& extent) {
+ active_client_->SelectBetweenCoordinates(base, extent);
+}
+
+void CefTouchSelectionControllerClientOSR::InternalClient::
+ SelectBetweenCoordinates(const gfx::PointF& base,
+ const gfx::PointF& extent) {
+ if (auto host_delegate = rwhv_->host()->delegate()) {
+ host_delegate->SelectRange(gfx::ToRoundedPoint(base),
+ gfx::ToRoundedPoint(extent));
+ }
+}
+
+void CefTouchSelectionControllerClientOSR::OnSelectionEvent(
+ ui::SelectionEventType event) {
+ // This function (implicitly) uses active_menu_client_, so we don't go to the
+ // active view for this.
+ switch (event) {
+ case ui::SELECTION_HANDLES_SHOWN:
+ quick_menu_requested_ = true;
+ [[fallthrough]];
+ case ui::INSERTION_HANDLE_SHOWN:
+ UpdateQuickMenu();
+ break;
+ case ui::SELECTION_HANDLES_CLEARED:
+ case ui::INSERTION_HANDLE_CLEARED:
+ quick_menu_requested_ = false;
+ UpdateQuickMenu();
+ break;
+ case ui::SELECTION_HANDLE_DRAG_STARTED:
+ case ui::INSERTION_HANDLE_DRAG_STARTED:
+ handle_drag_in_progress_ = true;
+ UpdateQuickMenu();
+ break;
+ case ui::SELECTION_HANDLE_DRAG_STOPPED:
+ case ui::INSERTION_HANDLE_DRAG_STOPPED:
+ handle_drag_in_progress_ = false;
+ UpdateQuickMenu();
+ break;
+ case ui::SELECTION_HANDLES_MOVED:
+ case ui::INSERTION_HANDLE_MOVED:
+ UpdateQuickMenu();
+ break;
+ case ui::INSERTION_HANDLE_TAPPED:
+ quick_menu_requested_ = !quick_menu_requested_;
+ UpdateQuickMenu();
+ break;
+ }
+}
+
+void CefTouchSelectionControllerClientOSR::InternalClient::OnSelectionEvent(
+ ui::SelectionEventType event) {
+ NOTREACHED();
+}
+
+void CefTouchSelectionControllerClientOSR::OnDragUpdate(
+ const ui::TouchSelectionDraggable::Type type,
+ const gfx::PointF& position) {}
+
+void CefTouchSelectionControllerClientOSR::InternalClient::OnDragUpdate(
+ const ui::TouchSelectionDraggable::Type type,
+ const gfx::PointF& position) {
+ NOTREACHED();
+}
+
+std::unique_ptr<ui::TouchHandleDrawable>
+CefTouchSelectionControllerClientOSR::CreateDrawable() {
+ return std::make_unique<CefTouchHandleDrawableOSR>(rwhv_);
+}
+
+void CefTouchSelectionControllerClientOSR::DidScroll() {}
+
+std::unique_ptr<ui::TouchHandleDrawable>
+CefTouchSelectionControllerClientOSR::InternalClient::CreateDrawable() {
+ NOTREACHED();
+ return nullptr;
+}
+
+void CefTouchSelectionControllerClientOSR::InternalClient::DidScroll() {
+ NOTREACHED();
+}
+
+bool CefTouchSelectionControllerClientOSR::IsCommandIdEnabled(
+ int command_id) const {
+ bool editable = rwhv_->GetTextInputType() != ui::TEXT_INPUT_TYPE_NONE;
+ bool readable = rwhv_->GetTextInputType() != ui::TEXT_INPUT_TYPE_PASSWORD;
+ bool has_selection = !rwhv_->GetSelectedText().empty();
+ switch (command_id) {
+ case QM_EDITFLAG_CAN_ELLIPSIS:
+ return true; // Always allowed to show the ellipsis button.
+ case QM_EDITFLAG_CAN_CUT:
+ return editable && readable && has_selection;
+ case QM_EDITFLAG_CAN_COPY:
+ return readable && has_selection;
+ case QM_EDITFLAG_CAN_PASTE: {
+ std::u16string result;
+ ui::DataTransferEndpoint data_dst = ui::DataTransferEndpoint(
+ ui::EndpointType::kDefault, /*notify_if_restricted=*/false);
+ ui::Clipboard::GetForCurrentThread()->ReadText(
+ ui::ClipboardBuffer::kCopyPaste, &data_dst, &result);
+ return editable && !result.empty();
+ }
+ default:
+ return false;
+ }
+}
+
+void CefTouchSelectionControllerClientOSR::ExecuteCommand(int command_id,
+ int event_flags) {
+ if (command_id == kInvalidCommandId) {
+ return;
+ }
+
+ if (command_id != QM_EDITFLAG_CAN_ELLIPSIS) {
+ rwhv_->selection_controller()->HideAndDisallowShowingAutomatically();
+ }
+
+ content::RenderWidgetHostDelegate* host_delegate = rwhv_->host()->delegate();
+ if (!host_delegate) {
+ return;
+ }
+
+ auto browser = rwhv_->browser_impl();
+ if (auto handler = browser->client()->GetContextMenuHandler()) {
+ if (handler->OnQuickMenuCommand(
+ browser.get(), browser->GetFocusedFrame(), command_id,
+ static_cast<cef_event_flags_t>(event_flags))) {
+ return;
+ }
+ }
+
+ switch (command_id) {
+ case QM_EDITFLAG_CAN_CUT:
+ host_delegate->Cut();
+ break;
+ case QM_EDITFLAG_CAN_COPY:
+ host_delegate->Copy();
+ break;
+ case QM_EDITFLAG_CAN_PASTE:
+ host_delegate->Paste();
+ break;
+ case QM_EDITFLAG_CAN_ELLIPSIS:
+ CloseQuickMenu();
+ RunContextMenu();
+ break;
+ default:
+ // Invalid command, do nothing.
+ // Also reached when callback is destroyed/cancelled.
+ break;
+ }
+}
+
+void CefTouchSelectionControllerClientOSR::RunContextMenu() {
+ const gfx::RectF anchor_rect =
+ rwhv_->selection_controller()->GetVisibleRectBetweenBounds();
+ const gfx::PointF anchor_point =
+ gfx::PointF(anchor_rect.CenterPoint().x(), anchor_rect.y());
+ rwhv_->host()->ShowContextMenuAtPoint(gfx::ToRoundedPoint(anchor_point),
+ ui::MENU_SOURCE_TOUCH_EDIT_MENU);
+
+ // Hide selection handles after getting rect-between-bounds from touch
+ // selection controller; otherwise, rect would be empty and the above
+ // calculations would be invalid.
+ rwhv_->selection_controller()->HideAndDisallowShowingAutomatically();
+}
+
+bool CefTouchSelectionControllerClientOSR::ShouldShowQuickMenu() {
+ return quick_menu_requested_ && !touch_down_ && !scroll_in_progress_ &&
+ !handle_drag_in_progress_ && IsQuickMenuAvailable();
+}
+
+std::u16string CefTouchSelectionControllerClientOSR::GetSelectedText() {
+ return rwhv_->GetSelectedText();
+}
diff --git a/libcef/browser/osr/touch_selection_controller_client_osr.h b/libcef/browser/osr/touch_selection_controller_client_osr.h
new file mode 100644
index 00000000..690c0a42
--- /dev/null
+++ b/libcef/browser/osr/touch_selection_controller_client_osr.h
@@ -0,0 +1,156 @@
+// Copyright 2022 The Chromium Embedded Framework Authors.
+// Portions copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_OSR_TOUCH_SELECTION_CONTROLLER_CLIENT_OSR_H_
+#define CEF_LIBCEF_BROWSER_OSR_TOUCH_SELECTION_CONTROLLER_CLIENT_OSR_H_
+
+#include <memory>
+
+#include "base/memory/raw_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/observer_list.h"
+#include "base/timer/timer.h"
+#include "content/common/content_export.h"
+#include "content/public/browser/touch_selection_controller_client_manager.h"
+#include "ui/touch_selection/touch_selection_controller.h"
+#include "ui/touch_selection/touch_selection_menu_runner.h"
+
+namespace content {
+struct ContextMenuParams;
+}
+
+class CefRenderWidgetHostViewOSR;
+
+// An implementation of |TouchSelectionControllerClient| to be used in OSR's
+// implementation of touch selection for contents.
+// Copied from TouchSelectionControllerClientAura.
+class CefTouchSelectionControllerClientOSR
+ : public ui::TouchSelectionControllerClient,
+ public ui::TouchSelectionMenuClient,
+ public content::TouchSelectionControllerClientManager {
+ public:
+ explicit CefTouchSelectionControllerClientOSR(
+ CefRenderWidgetHostViewOSR* rwhv);
+
+ CefTouchSelectionControllerClientOSR(
+ const CefTouchSelectionControllerClientOSR&) = delete;
+ CefTouchSelectionControllerClientOSR& operator=(
+ const CefTouchSelectionControllerClientOSR&) = delete;
+
+ ~CefTouchSelectionControllerClientOSR() override;
+
+ void CloseQuickMenuAndHideHandles();
+
+ void OnWindowMoved();
+
+ // Called on first touch down/last touch up to hide/show the quick menu.
+ void OnTouchDown();
+
+ void OnTouchUp();
+
+ // Called when touch scroll starts/completes to hide/show touch handles and
+ // the quick menu.
+ void OnScrollStarted();
+
+ void OnScrollCompleted();
+
+ // Gives an opportunity to the client to handle context menu request and show
+ // the quick menu instead, if appropriate. Returns |true| to indicate that no
+ // further handling is needed.
+ // TODO(mohsen): This is to match Chrome on Android behavior. However, it is
+ // better not to send context menu request from the renderer in this case and
+ // instead decide in the client about showing the quick menu in response to
+ // selection events. (http://crbug.com/548245)
+ bool HandleContextMenu(const content::ContextMenuParams& params);
+
+ void UpdateClientSelectionBounds(const gfx::SelectionBound& start,
+ const gfx::SelectionBound& end);
+
+ // TouchSelectionControllerClientManager.
+ void DidStopFlinging() override;
+ void UpdateClientSelectionBounds(
+ const gfx::SelectionBound& start,
+ const gfx::SelectionBound& end,
+ ui::TouchSelectionControllerClient* client,
+ ui::TouchSelectionMenuClient* menu_client) override;
+ void InvalidateClient(ui::TouchSelectionControllerClient* client) override;
+ ui::TouchSelectionController* GetTouchSelectionController() override;
+ void AddObserver(
+ TouchSelectionControllerClientManager::Observer* observer) override;
+ void RemoveObserver(
+ TouchSelectionControllerClientManager::Observer* observer) override;
+
+ private:
+ class EnvEventObserver;
+
+ bool IsQuickMenuAvailable() const;
+ void CloseQuickMenu();
+ void ShowQuickMenu();
+ void UpdateQuickMenu();
+
+ // ui::TouchSelectionControllerClient:
+ bool SupportsAnimation() const override;
+ void SetNeedsAnimate() override;
+ void MoveCaret(const gfx::PointF& position) override;
+ void MoveRangeSelectionExtent(const gfx::PointF& extent) override;
+ void SelectBetweenCoordinates(const gfx::PointF& base,
+ const gfx::PointF& extent) override;
+ void OnSelectionEvent(ui::SelectionEventType event) override;
+ void OnDragUpdate(const ui::TouchSelectionDraggable::Type type,
+ const gfx::PointF& position) override;
+ std::unique_ptr<ui::TouchHandleDrawable> CreateDrawable() override;
+ void DidScroll() override;
+
+ // ui::TouchSelectionMenuClient:
+ bool IsCommandIdEnabled(int command_id) const override;
+ void ExecuteCommand(int command_id, int event_flags) override;
+ void RunContextMenu() override;
+ bool ShouldShowQuickMenu() override;
+ std::u16string GetSelectedText() override;
+
+ // Not owned, non-null for the lifetime of this object.
+ raw_ptr<CefRenderWidgetHostViewOSR> rwhv_;
+
+ class InternalClient final : public ui::TouchSelectionControllerClient {
+ public:
+ explicit InternalClient(CefRenderWidgetHostViewOSR* rwhv) : rwhv_(rwhv) {}
+ ~InternalClient() final {}
+
+ bool SupportsAnimation() const final;
+ void SetNeedsAnimate() final;
+ void MoveCaret(const gfx::PointF& position) final;
+ void MoveRangeSelectionExtent(const gfx::PointF& extent) final;
+ void SelectBetweenCoordinates(const gfx::PointF& base,
+ const gfx::PointF& extent) final;
+ void OnSelectionEvent(ui::SelectionEventType event) final;
+ void OnDragUpdate(const ui::TouchSelectionDraggable::Type type,
+ const gfx::PointF& position) final;
+ std::unique_ptr<ui::TouchHandleDrawable> CreateDrawable() final;
+ void DidScroll() override;
+
+ private:
+ raw_ptr<CefRenderWidgetHostViewOSR> rwhv_;
+ } internal_client_;
+
+ // Keep track of which client interface to use.
+ raw_ptr<TouchSelectionControllerClient> active_client_;
+ raw_ptr<TouchSelectionMenuClient> active_menu_client_;
+ gfx::SelectionBound manager_selection_start_;
+ gfx::SelectionBound manager_selection_end_;
+
+ base::ObserverList<TouchSelectionControllerClientManager::Observer>
+ observers_;
+
+ base::RetainingOneShotTimer quick_menu_timer_;
+ bool quick_menu_requested_ = false;
+ bool quick_menu_running_ = false;
+ bool touch_down_ = false;
+ bool scroll_in_progress_ = false;
+ bool handle_drag_in_progress_ = false;
+
+ base::WeakPtrFactory<CefTouchSelectionControllerClientOSR> weak_ptr_factory_;
+};
+
+#endif
diff --git a/libcef/browser/osr/video_consumer_osr.cc b/libcef/browser/osr/video_consumer_osr.cc
new file mode 100644
index 00000000..ee0e0c98
--- /dev/null
+++ b/libcef/browser/osr/video_consumer_osr.cc
@@ -0,0 +1,142 @@
+// Copyright (c) 2015 GitHub, Inc.
+// Use of this source code is governed by the MIT license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/osr/video_consumer_osr.h"
+
+#include "libcef/browser/osr/render_widget_host_view_osr.h"
+
+#include "media/base/video_frame_metadata.h"
+#include "media/capture/mojom/video_capture_buffer.mojom.h"
+#include "media/capture/mojom/video_capture_types.mojom.h"
+#include "ui/gfx/skbitmap_operations.h"
+
+namespace {
+
+// Helper to always call Done() at the end of OnFrameCaptured().
+class ScopedVideoFrameDone {
+ public:
+ explicit ScopedVideoFrameDone(
+ mojo::PendingRemote<viz::mojom::FrameSinkVideoConsumerFrameCallbacks>
+ callbacks)
+ : callbacks_(std::move(callbacks)) {}
+ ~ScopedVideoFrameDone() { callbacks_->Done(); }
+
+ private:
+ mojo::Remote<viz::mojom::FrameSinkVideoConsumerFrameCallbacks> callbacks_;
+};
+
+} // namespace
+
+CefVideoConsumerOSR::CefVideoConsumerOSR(CefRenderWidgetHostViewOSR* view)
+ : view_(view), video_capturer_(view->CreateVideoCapturer()) {
+ video_capturer_->SetFormat(media::PIXEL_FORMAT_ARGB);
+
+ // Always use the highest resolution within constraints that doesn't exceed
+ // the source size.
+ video_capturer_->SetAutoThrottlingEnabled(false);
+ video_capturer_->SetMinSizeChangePeriod(base::TimeDelta());
+
+ SizeChanged(view_->SizeInPixels());
+ SetActive(true);
+}
+
+CefVideoConsumerOSR::~CefVideoConsumerOSR() = default;
+
+void CefVideoConsumerOSR::SetActive(bool active) {
+ if (active) {
+ video_capturer_->Start(this, viz::mojom::BufferFormatPreference::kDefault);
+ } else {
+ video_capturer_->Stop();
+ }
+}
+
+void CefVideoConsumerOSR::SetFrameRate(base::TimeDelta frame_rate) {
+ video_capturer_->SetMinCapturePeriod(frame_rate);
+}
+
+void CefVideoConsumerOSR::SizeChanged(const gfx::Size& size_in_pixels) {
+ if (size_in_pixels_ == size_in_pixels) {
+ return;
+ }
+ size_in_pixels_ = size_in_pixels;
+
+ // Capture resolution will be held constant.
+ video_capturer_->SetResolutionConstraints(size_in_pixels, size_in_pixels,
+ true /* use_fixed_aspect_ratio */);
+}
+
+void CefVideoConsumerOSR::RequestRefreshFrame(
+ const absl::optional<gfx::Rect>& bounds_in_pixels) {
+ bounds_in_pixels_ = bounds_in_pixels;
+ video_capturer_->RequestRefreshFrame();
+}
+
+// Frame size values are as follows:
+// info->coded_size = Width and height of the video frame. Not all pixels in
+// this region are valid.
+// info->visible_rect = Region of coded_size that contains image data, also
+// known as the clean aperture.
+// content_rect = Region of the frame that contains the captured content, with
+// the rest of the frame having been letterboxed to adhere to resolution
+// constraints.
+void CefVideoConsumerOSR::OnFrameCaptured(
+ media::mojom::VideoBufferHandlePtr data,
+ media::mojom::VideoFrameInfoPtr info,
+ const gfx::Rect& content_rect,
+ mojo::PendingRemote<viz::mojom::FrameSinkVideoConsumerFrameCallbacks>
+ callbacks) {
+ ScopedVideoFrameDone scoped_done(std::move(callbacks));
+
+ CHECK(data->is_read_only_shmem_region());
+ base::ReadOnlySharedMemoryRegion& shmem_region =
+ data->get_read_only_shmem_region();
+
+ // The |data| parameter is not nullable and mojo type mapping for
+ // `base::ReadOnlySharedMemoryRegion` defines that nullable version of it is
+ // the same type, with null check being equivalent to IsValid() check. Given
+ // the above, we should never be able to receive a read only shmem region that
+ // is not valid - mojo will enforce it for us.
+ DCHECK(shmem_region.IsValid());
+
+ base::ReadOnlySharedMemoryMapping mapping = shmem_region.Map();
+ if (!mapping.IsValid()) {
+ DLOG(ERROR) << "Shared memory mapping failed.";
+ return;
+ }
+ if (mapping.size() <
+ media::VideoFrame::AllocationSize(info->pixel_format, info->coded_size)) {
+ DLOG(ERROR) << "Shared memory size was less than expected.";
+ return;
+ }
+
+ // The SkBitmap's pixels will be marked as immutable, but the installPixels()
+ // API requires a non-const pointer. So, cast away the const.
+ void* const pixels = const_cast<void*>(mapping.memory());
+
+ media::VideoFrameMetadata metadata = info->metadata;
+ gfx::Rect damage_rect;
+
+ if (bounds_in_pixels_) {
+ // Use the bounds passed to RequestRefreshFrame().
+ damage_rect = gfx::Rect(info->coded_size);
+ damage_rect.Intersect(*bounds_in_pixels_);
+ bounds_in_pixels_ = absl::nullopt;
+ } else {
+ // Retrieve the rectangular region of the frame that has changed since the
+ // frame with the directly preceding CAPTURE_COUNTER. If that frame was not
+ // received, typically because it was dropped during transport from the
+ // producer, clients must assume that the entire frame has changed.
+ // This rectangle is relative to the full frame data, i.e. [0, 0,
+ // coded_size.width(), coded_size.height()]. It does not have to be
+ // fully contained within visible_rect.
+ if (metadata.capture_update_rect) {
+ damage_rect = *metadata.capture_update_rect;
+ }
+ if (damage_rect.IsEmpty()) {
+ damage_rect = gfx::Rect(info->coded_size);
+ }
+ }
+
+ view_->OnPaint(damage_rect, info->coded_size, pixels);
+}
diff --git a/libcef/browser/osr/video_consumer_osr.h b/libcef/browser/osr/video_consumer_osr.h
new file mode 100644
index 00000000..4616b053
--- /dev/null
+++ b/libcef/browser/osr/video_consumer_osr.h
@@ -0,0 +1,45 @@
+#ifndef LIBCEF_BROWSER_OSR_VIDEO_CONSUMER_OSR_H_
+#define LIBCEF_BROWSER_OSR_VIDEO_CONSUMER_OSR_H_
+
+#include "base/functional/callback.h"
+#include "components/viz/host/client_frame_sink_video_capturer.h"
+#include "media/capture/mojom/video_capture_types.mojom.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+class CefRenderWidgetHostViewOSR;
+
+class CefVideoConsumerOSR : public viz::mojom::FrameSinkVideoConsumer {
+ public:
+ explicit CefVideoConsumerOSR(CefRenderWidgetHostViewOSR* view);
+
+ CefVideoConsumerOSR(const CefVideoConsumerOSR&) = delete;
+ CefVideoConsumerOSR& operator=(const CefVideoConsumerOSR&) = delete;
+
+ ~CefVideoConsumerOSR() override;
+
+ void SetActive(bool active);
+ void SetFrameRate(base::TimeDelta frame_rate);
+ void SizeChanged(const gfx::Size& size_in_pixels);
+ void RequestRefreshFrame(const absl::optional<gfx::Rect>& bounds_in_pixels);
+
+ private:
+ // viz::mojom::FrameSinkVideoConsumer implementation.
+ void OnFrameCaptured(
+ media::mojom::VideoBufferHandlePtr data,
+ media::mojom::VideoFrameInfoPtr info,
+ const gfx::Rect& content_rect,
+ mojo::PendingRemote<viz::mojom::FrameSinkVideoConsumerFrameCallbacks>
+ callbacks) override;
+ void OnNewCropVersion(uint32_t crop_version) override {}
+ void OnFrameWithEmptyRegionCapture() override {}
+ void OnStopped() override {}
+ void OnLog(const std::string& message) override {}
+
+ CefRenderWidgetHostViewOSR* const view_;
+ std::unique_ptr<viz::ClientFrameSinkVideoCapturer> video_capturer_;
+
+ gfx::Size size_in_pixels_;
+ absl::optional<gfx::Rect> bounds_in_pixels_;
+};
+
+#endif // LIBCEF_BROWSER_OSR_VIDEO_CONSUMER_OSR_H_ \ No newline at end of file
diff --git a/libcef/browser/osr/web_contents_view_osr.cc b/libcef/browser/osr/web_contents_view_osr.cc
new file mode 100644
index 00000000..abb6af5e
--- /dev/null
+++ b/libcef/browser/osr/web_contents_view_osr.cc
@@ -0,0 +1,223 @@
+// Copyright (c) 2014 The Chromium Embedded Framework Authors.
+// Portions copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/osr/web_contents_view_osr.h"
+
+#include "libcef/browser/alloy/alloy_browser_host_impl.h"
+#include "libcef/browser/osr/render_widget_host_view_osr.h"
+#include "libcef/browser/osr/touch_selection_controller_client_osr.h"
+#include "libcef/common/drag_data_impl.h"
+
+#include "content/browser/browser_plugin/browser_plugin_embedder.h"
+#include "content/browser/browser_plugin/browser_plugin_guest.h"
+#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/public/browser/render_widget_host.h"
+
+CefWebContentsViewOSR::CefWebContentsViewOSR(SkColor background_color,
+ bool use_shared_texture,
+ bool use_external_begin_frame)
+ : background_color_(background_color),
+ use_shared_texture_(use_shared_texture),
+ use_external_begin_frame_(use_external_begin_frame),
+ web_contents_(nullptr) {}
+
+CefWebContentsViewOSR::~CefWebContentsViewOSR() {}
+
+void CefWebContentsViewOSR::WebContentsCreated(
+ content::WebContents* web_contents) {
+ DCHECK(!web_contents_);
+ web_contents_ = web_contents;
+
+ RenderViewCreated();
+}
+
+void CefWebContentsViewOSR::RenderViewCreated() {
+ if (web_contents_) {
+ auto host = web_contents_->GetRenderViewHost();
+ CefRenderWidgetHostViewOSR* view =
+ static_cast<CefRenderWidgetHostViewOSR*>(host->GetWidget()->GetView());
+ if (view) {
+ view->InstallTransparency();
+ }
+ }
+}
+
+gfx::NativeView CefWebContentsViewOSR::GetNativeView() const {
+ return gfx::NativeView();
+}
+
+gfx::NativeView CefWebContentsViewOSR::GetContentNativeView() const {
+ return gfx::NativeView();
+}
+
+gfx::NativeWindow CefWebContentsViewOSR::GetTopLevelNativeWindow() const {
+ return gfx::NativeWindow();
+}
+
+gfx::Rect CefWebContentsViewOSR::GetContainerBounds() const {
+ return GetViewBounds();
+}
+
+void CefWebContentsViewOSR::Focus() {}
+
+void CefWebContentsViewOSR::SetInitialFocus() {}
+
+void CefWebContentsViewOSR::StoreFocus() {}
+
+void CefWebContentsViewOSR::RestoreFocus() {}
+
+void CefWebContentsViewOSR::FocusThroughTabTraversal(bool reverse) {}
+
+void CefWebContentsViewOSR::GotFocus(
+ content::RenderWidgetHostImpl* render_widget_host) {
+ if (web_contents_) {
+ content::WebContentsImpl* web_contents_impl =
+ static_cast<content::WebContentsImpl*>(web_contents_);
+ if (web_contents_impl) {
+ web_contents_impl->NotifyWebContentsFocused(render_widget_host);
+ }
+ }
+}
+
+void CefWebContentsViewOSR::LostFocus(
+ content::RenderWidgetHostImpl* render_widget_host) {
+ if (web_contents_) {
+ content::WebContentsImpl* web_contents_impl =
+ static_cast<content::WebContentsImpl*>(web_contents_);
+ if (web_contents_impl) {
+ web_contents_impl->NotifyWebContentsLostFocus(render_widget_host);
+ }
+ }
+}
+
+void CefWebContentsViewOSR::TakeFocus(bool reverse) {
+ if (web_contents_->GetDelegate()) {
+ web_contents_->GetDelegate()->TakeFocus(web_contents_, reverse);
+ }
+}
+
+void CefWebContentsViewOSR::FullscreenStateChanged(bool is_fullscreen) {}
+
+content::DropData* CefWebContentsViewOSR::GetDropData() const {
+ return nullptr;
+}
+
+gfx::Rect CefWebContentsViewOSR::GetViewBounds() const {
+ CefRenderWidgetHostViewOSR* view = GetView();
+ return view ? view->GetViewBounds() : gfx::Rect();
+}
+
+void CefWebContentsViewOSR::CreateView(gfx::NativeView context) {}
+
+content::RenderWidgetHostViewBase* CefWebContentsViewOSR::CreateViewForWidget(
+ content::RenderWidgetHost* render_widget_host) {
+ if (render_widget_host->GetView()) {
+ return static_cast<content::RenderWidgetHostViewBase*>(
+ render_widget_host->GetView());
+ }
+
+ return new CefRenderWidgetHostViewOSR(background_color_, use_shared_texture_,
+ use_external_begin_frame_,
+ render_widget_host, nullptr);
+}
+
+// Called for popup and fullscreen widgets.
+content::RenderWidgetHostViewBase*
+CefWebContentsViewOSR::CreateViewForChildWidget(
+ content::RenderWidgetHost* render_widget_host) {
+ CefRenderWidgetHostViewOSR* view = GetView();
+ CHECK(view);
+
+ return new CefRenderWidgetHostViewOSR(background_color_, use_shared_texture_,
+ use_external_begin_frame_,
+ render_widget_host, view);
+}
+
+void CefWebContentsViewOSR::SetPageTitle(const std::u16string& title) {}
+
+void CefWebContentsViewOSR::RenderViewReady() {
+ RenderViewCreated();
+}
+
+void CefWebContentsViewOSR::RenderViewHostChanged(
+ content::RenderViewHost* old_host,
+ content::RenderViewHost* new_host) {}
+
+void CefWebContentsViewOSR::SetOverscrollControllerEnabled(bool enabled) {}
+
+void CefWebContentsViewOSR::OnCapturerCountChanged() {}
+
+void CefWebContentsViewOSR::UpdateWindowControlsOverlay(
+ const gfx::Rect& bounding_rect) {}
+
+#if BUILDFLAG(IS_MAC)
+bool CefWebContentsViewOSR::CloseTabAfterEventTrackingIfNeeded() {
+ return false;
+}
+#endif // BUILDFLAG(IS_MAC)
+
+void CefWebContentsViewOSR::ShowContextMenu(
+ content::RenderFrameHost& render_frame_host,
+ const content::ContextMenuParams& params) {
+ auto selection_controller_client = GetSelectionControllerClient();
+ if (selection_controller_client &&
+ selection_controller_client->HandleContextMenu(params)) {
+ // Context menu display, if any, will be handled via
+ // AlloyWebContentsViewDelegate::ShowContextMenu.
+ return;
+ }
+
+ if (auto browser = GetBrowser()) {
+ browser->ShowContextMenu(params);
+ }
+}
+
+void CefWebContentsViewOSR::StartDragging(
+ const content::DropData& drop_data,
+ blink::DragOperationsMask allowed_ops,
+ const gfx::ImageSkia& image,
+ const gfx::Vector2d& cursor_offset,
+ const gfx::Rect& drag_obj_rect,
+ const blink::mojom::DragEventSourceInfo& event_info,
+ content::RenderWidgetHostImpl* source_rwh) {
+ CefRefPtr<AlloyBrowserHostImpl> browser = GetBrowser();
+ if (browser.get()) {
+ browser->StartDragging(drop_data, allowed_ops, image, cursor_offset,
+ event_info, source_rwh);
+ } else if (web_contents_) {
+ static_cast<content::WebContentsImpl*>(web_contents_)
+ ->SystemDragEnded(source_rwh);
+ }
+}
+
+void CefWebContentsViewOSR::UpdateDragCursor(
+ ui::mojom::DragOperation operation) {
+ CefRefPtr<AlloyBrowserHostImpl> browser = GetBrowser();
+ if (browser.get()) {
+ browser->UpdateDragCursor(operation);
+ }
+}
+
+CefRenderWidgetHostViewOSR* CefWebContentsViewOSR::GetView() const {
+ if (web_contents_) {
+ return static_cast<CefRenderWidgetHostViewOSR*>(
+ web_contents_->GetRenderViewHost()->GetWidget()->GetView());
+ }
+ return nullptr;
+}
+
+AlloyBrowserHostImpl* CefWebContentsViewOSR::GetBrowser() const {
+ CefRenderWidgetHostViewOSR* view = GetView();
+ if (view) {
+ return view->browser_impl().get();
+ }
+ return nullptr;
+}
+
+CefTouchSelectionControllerClientOSR*
+CefWebContentsViewOSR::GetSelectionControllerClient() const {
+ CefRenderWidgetHostViewOSR* view = GetView();
+ return view ? view->selection_controller_client() : nullptr;
+}
diff --git a/libcef/browser/osr/web_contents_view_osr.h b/libcef/browser/osr/web_contents_view_osr.h
new file mode 100644
index 00000000..d3fc78d3
--- /dev/null
+++ b/libcef/browser/osr/web_contents_view_osr.h
@@ -0,0 +1,100 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors.
+// Portions copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_OSR_WEB_CONTENTS_VIEW_OSR_H_
+#define CEF_LIBCEF_BROWSER_OSR_WEB_CONTENTS_VIEW_OSR_H_
+
+#include "content/browser/renderer_host/render_view_host_delegate_view.h"
+#include "content/browser/web_contents/web_contents_view.h"
+#include "third_party/skia/include/core/SkColor.h"
+
+namespace content {
+class BrowserPluginGuest;
+class WebContents;
+class WebContentsViewDelegate;
+} // namespace content
+
+class AlloyBrowserHostImpl;
+class CefRenderWidgetHostViewOSR;
+class CefTouchSelectionControllerClientOSR;
+
+// An implementation of WebContentsView for off-screen rendering.
+class CefWebContentsViewOSR : public content::WebContentsView,
+ public content::RenderViewHostDelegateView {
+ public:
+ explicit CefWebContentsViewOSR(SkColor background_color,
+ bool use_shared_texture,
+ bool use_external_begin_frame);
+
+ CefWebContentsViewOSR(const CefWebContentsViewOSR&) = delete;
+ CefWebContentsViewOSR& operator=(const CefWebContentsViewOSR&) = delete;
+
+ ~CefWebContentsViewOSR() override;
+
+ void WebContentsCreated(content::WebContents* web_contents);
+ content::WebContents* web_contents() const { return web_contents_; }
+
+ void RenderViewCreated();
+
+ // WebContentsView methods.
+ gfx::NativeView GetNativeView() const override;
+ gfx::NativeView GetContentNativeView() const override;
+ gfx::NativeWindow GetTopLevelNativeWindow() const override;
+ gfx::Rect GetContainerBounds() const override;
+ void Focus() override;
+ void SetInitialFocus() override;
+ void StoreFocus() override;
+ void RestoreFocus() override;
+ void FocusThroughTabTraversal(bool reverse) override;
+ content::DropData* GetDropData() const override;
+ gfx::Rect GetViewBounds() const override;
+ void CreateView(gfx::NativeView context) override;
+ content::RenderWidgetHostViewBase* CreateViewForWidget(
+ content::RenderWidgetHost* render_widget_host) override;
+ content::RenderWidgetHostViewBase* CreateViewForChildWidget(
+ content::RenderWidgetHost* render_widget_host) override;
+ void SetPageTitle(const std::u16string& title) override;
+ void RenderViewReady() override;
+ void RenderViewHostChanged(content::RenderViewHost* old_host,
+ content::RenderViewHost* new_host) override;
+ void SetOverscrollControllerEnabled(bool enabled) override;
+ void OnCapturerCountChanged() override;
+ void UpdateWindowControlsOverlay(const gfx::Rect& bounding_rect) override;
+
+#if BUILDFLAG(IS_MAC)
+ bool CloseTabAfterEventTrackingIfNeeded() override;
+#endif
+
+ // RenderViewHostDelegateView methods.
+ void ShowContextMenu(content::RenderFrameHost& render_frame_host,
+ const content::ContextMenuParams& params) override;
+ void StartDragging(const content::DropData& drop_data,
+ blink::DragOperationsMask allowed_ops,
+ const gfx::ImageSkia& image,
+ const gfx::Vector2d& cursor_offset,
+ const gfx::Rect& drag_obj_rect,
+ const blink::mojom::DragEventSourceInfo& event_info,
+ content::RenderWidgetHostImpl* source_rwh) override;
+ void UpdateDragCursor(ui::mojom::DragOperation operation) override;
+ virtual void GotFocus(
+ content::RenderWidgetHostImpl* render_widget_host) override;
+ virtual void LostFocus(
+ content::RenderWidgetHostImpl* render_widget_host) override;
+ virtual void TakeFocus(bool reverse) override;
+ virtual void FullscreenStateChanged(bool is_fullscreen) override;
+
+ private:
+ CefRenderWidgetHostViewOSR* GetView() const;
+ AlloyBrowserHostImpl* GetBrowser() const;
+ CefTouchSelectionControllerClientOSR* GetSelectionControllerClient() const;
+
+ const SkColor background_color_;
+ const bool use_shared_texture_;
+ const bool use_external_begin_frame_;
+
+ content::WebContents* web_contents_;
+};
+
+#endif // CEF_LIBCEF_BROWSER_OSR_WEB_CONTENTS_VIEW_OSR_H_
diff --git a/libcef/browser/path_util_impl.cc b/libcef/browser/path_util_impl.cc
new file mode 100644
index 00000000..2b008905
--- /dev/null
+++ b/libcef/browser/path_util_impl.cc
@@ -0,0 +1,57 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "include/cef_path_util.h"
+
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/notreached.h"
+#include "base/path_service.h"
+#include "chrome/common/chrome_paths.h"
+
+bool CefGetPath(PathKey key, CefString& path) {
+ int pref_key = base::PATH_START;
+ switch (key) {
+ case PK_DIR_CURRENT:
+ pref_key = base::DIR_CURRENT;
+ break;
+ case PK_DIR_EXE:
+ pref_key = base::DIR_EXE;
+ break;
+ case PK_DIR_MODULE:
+ pref_key = base::DIR_MODULE;
+ break;
+ case PK_DIR_TEMP:
+ pref_key = base::DIR_TEMP;
+ break;
+ case PK_FILE_EXE:
+ pref_key = base::FILE_EXE;
+ break;
+ case PK_FILE_MODULE:
+ pref_key = base::FILE_MODULE;
+ break;
+#if BUILDFLAG(IS_WIN)
+ case PK_LOCAL_APP_DATA:
+ pref_key = base::DIR_LOCAL_APP_DATA;
+ break;
+#endif
+ case PK_USER_DATA:
+ pref_key = chrome::DIR_USER_DATA;
+ break;
+ case PK_DIR_RESOURCES:
+ pref_key = chrome::DIR_RESOURCES;
+ break;
+ default:
+ NOTREACHED() << "invalid argument";
+ return false;
+ }
+
+ base::FilePath file_path;
+ if (base::PathService::Get(pref_key, &file_path)) {
+ path = file_path.value();
+ return true;
+ }
+
+ return false;
+}
diff --git a/libcef/browser/permission_prompt.cc b/libcef/browser/permission_prompt.cc
new file mode 100644
index 00000000..784aab65
--- /dev/null
+++ b/libcef/browser/permission_prompt.cc
@@ -0,0 +1,298 @@
+// Copyright 2022 The Chromium Embedded Framework Authors. Portions copyright
+// 2016 The Chromium Authors. All rights reserved. Use of this source code is
+// governed by a BSD-style license that can be found in the LICENSE file.
+
+#include "libcef/browser/permission_prompt.h"
+
+#include "libcef/browser/browser_host_base.h"
+#include "libcef/features/runtime.h"
+
+#include "base/logging.h"
+#include "base/memory/weak_ptr.h"
+#include "base/notreached.h"
+#include "chrome/browser/ui/permission_bubble/permission_prompt.h"
+
+namespace permission_prompt {
+
+namespace {
+
+uint64_t g_next_prompt_id = 0;
+
+using DelegateCallback =
+ base::OnceCallback<void(cef_permission_request_result_t)>;
+
+class CefPermissionPromptCallbackImpl : public CefPermissionPromptCallback {
+ public:
+ using CallbackType = base::OnceCallback<void(cef_permission_request_result_t,
+ bool /*notify_delegate*/)>;
+
+ explicit CefPermissionPromptCallbackImpl(CallbackType&& callback)
+ : callback_(std::move(callback)) {}
+
+ CefPermissionPromptCallbackImpl(const CefPermissionPromptCallbackImpl&) =
+ delete;
+ CefPermissionPromptCallbackImpl& operator=(
+ const CefPermissionPromptCallbackImpl&) = delete;
+
+ // Don't need to execute the callback in this destructor because this object
+ // will always be kept alive until after the CefPermissionPrompt is destroyed,
+ // and that object will disconnect/execute the callback in its destructor.
+ ~CefPermissionPromptCallbackImpl() override = default;
+
+ void Continue(cef_permission_request_result_t result) override {
+ if (CEF_CURRENTLY_ON_UIT()) {
+ if (!callback_.is_null()) {
+ auto callback = base::BindOnce(std::move(callback_), result,
+ /*notify_delegate=*/true);
+ if (safe_to_run_sync_) {
+ std::move(callback).Run();
+ } else {
+ CEF_POST_TASK(CEF_UIT, std::move(callback));
+ }
+ }
+ } else {
+ CEF_POST_TASK(CEF_UIT,
+ base::BindOnce(&CefPermissionPromptCallbackImpl::Continue,
+ this, result));
+ }
+ }
+
+ [[nodiscard]] CallbackType Disconnect() { return std::move(callback_); }
+ bool IsDisconnected() const { return callback_.is_null(); }
+
+ void MarkSafeToRunSync() { safe_to_run_sync_ = true; }
+
+ private:
+ // Callback execution from inside CreatePermissionPromptImpl must be async,
+ // otherwise PermissionRequestManager state will be incorrect.
+ bool safe_to_run_sync_ = false;
+
+ CallbackType callback_;
+
+ IMPLEMENT_REFCOUNTING(CefPermissionPromptCallbackImpl);
+};
+
+// Implementation based on PermissionPromptAndroid.
+class CefPermissionPrompt : public permissions::PermissionPrompt {
+ public:
+ explicit CefPermissionPrompt(Delegate* delegate) : delegate_(delegate) {
+ DCHECK(delegate_);
+ }
+
+ CefPermissionPrompt(const CefPermissionPrompt&) = delete;
+ CefPermissionPrompt& operator=(const CefPermissionPrompt&) = delete;
+
+ // Expect to be destroyed (and the UI needs to go) when:
+ // 1. A navigation happens, tab/webcontents is being closed; with the current
+ // GetTabSwitchingBehavior() implementation, this instance survives the tab
+ // being backgrounded.
+ // 2. The permission request is resolved (accept, deny, dismiss).
+ // 3. A higher priority request comes in.
+ ~CefPermissionPrompt() override {
+ CEF_REQUIRE_UIT();
+ if (callback_) {
+ // If the callback is non-null at this point then we still need to execute
+ // it in order to notify the client.
+ auto callback = callback_->Disconnect();
+ if (!callback.is_null()) {
+ std::move(callback).Run(CEF_PERMISSION_RESULT_IGNORE,
+ /*notify_delegate=*/false);
+ }
+ }
+ }
+
+ // Used to associate the client callback when OnShowPermissionPrompt is
+ // handled.
+ void AttachClientCallback(
+ CefRefPtr<CefPermissionPromptCallbackImpl> callback) {
+ DCHECK(callback);
+ callback_ = callback;
+ callback_->MarkSafeToRunSync();
+ }
+
+ // Used to tie Delegate access to this object's lifespan.
+ DelegateCallback MakeDelegateCallback() {
+ return base::BindOnce(&CefPermissionPrompt::NotifyDelegate,
+ weak_ptr_factory_.GetWeakPtr());
+ }
+
+ // PermissionPrompt methods:
+ bool UpdateAnchor() override { return true; }
+ TabSwitchingBehavior GetTabSwitchingBehavior() override {
+ return TabSwitchingBehavior::kKeepPromptAlive;
+ }
+ permissions::PermissionPromptDisposition GetPromptDisposition()
+ const override {
+ return permissions::PermissionPromptDisposition::CUSTOM_MODAL_DIALOG;
+ }
+
+ private:
+ // We don't expose AcceptThisTime() because it's a special case for
+ // Geolocation (see DCHECK in PrefProvider::SetWebsiteSetting).
+ void NotifyDelegate(cef_permission_request_result_t result) {
+ switch (result) {
+ case CEF_PERMISSION_RESULT_ACCEPT:
+ delegate_->Accept();
+ break;
+ case CEF_PERMISSION_RESULT_DENY:
+ delegate_->Deny();
+ break;
+ case CEF_PERMISSION_RESULT_DISMISS:
+ delegate_->Dismiss();
+ break;
+ case CEF_PERMISSION_RESULT_IGNORE:
+ delegate_->Ignore();
+ break;
+ }
+ }
+
+ // |delegate_| is the PermissionRequestManager, which owns this object.
+ const raw_ptr<Delegate> delegate_;
+
+ CefRefPtr<CefPermissionPromptCallbackImpl> callback_;
+
+ base::WeakPtrFactory<CefPermissionPrompt> weak_ptr_factory_{this};
+};
+
+// |notify_delegate| will be false if called from the CefPermissionPrompt
+// destructor.
+void ExecuteResult(CefRefPtr<CefBrowserHostBase> browser,
+ uint64_t prompt_id,
+ DelegateCallback delegate_callback,
+ cef_permission_request_result_t result,
+ bool notify_delegate) {
+ CEF_REQUIRE_UIT();
+
+ if (auto client = browser->GetClient()) {
+ if (auto handler = client->GetPermissionHandler()) {
+ handler->OnDismissPermissionPrompt(browser, prompt_id, result);
+ }
+ }
+
+ if (notify_delegate) {
+ // Will be a no-op if this executes after the CefPermissionPrompt was
+ // destroyed.
+ std::move(delegate_callback).Run(result);
+ }
+}
+
+cef_permission_request_types_t GetCefRequestType(
+ permissions::RequestType type) {
+ switch (type) {
+ case permissions::RequestType::kAccessibilityEvents:
+ return CEF_PERMISSION_TYPE_ACCESSIBILITY_EVENTS;
+ case permissions::RequestType::kArSession:
+ return CEF_PERMISSION_TYPE_AR_SESSION;
+ case permissions::RequestType::kCameraPanTiltZoom:
+ return CEF_PERMISSION_TYPE_CAMERA_PAN_TILT_ZOOM;
+ case permissions::RequestType::kCameraStream:
+ return CEF_PERMISSION_TYPE_CAMERA_STREAM;
+ case permissions::RequestType::kClipboard:
+ return CEF_PERMISSION_TYPE_CLIPBOARD;
+ case permissions::RequestType::kDiskQuota:
+ return CEF_PERMISSION_TYPE_DISK_QUOTA;
+ case permissions::RequestType::kLocalFonts:
+ return CEF_PERMISSION_TYPE_LOCAL_FONTS;
+ case permissions::RequestType::kGeolocation:
+ return CEF_PERMISSION_TYPE_GEOLOCATION;
+ case permissions::RequestType::kIdleDetection:
+ return CEF_PERMISSION_TYPE_IDLE_DETECTION;
+ case permissions::RequestType::kMicStream:
+ return CEF_PERMISSION_TYPE_MIC_STREAM;
+ case permissions::RequestType::kMidiSysex:
+ return CEF_PERMISSION_TYPE_MIDI_SYSEX;
+ case permissions::RequestType::kMultipleDownloads:
+ return CEF_PERMISSION_TYPE_MULTIPLE_DOWNLOADS;
+ case permissions::RequestType::kNotifications:
+ return CEF_PERMISSION_TYPE_NOTIFICATIONS;
+#if BUILDFLAG(IS_WIN)
+ case permissions::RequestType::kProtectedMediaIdentifier:
+ return CEF_PERMISSION_TYPE_PROTECTED_MEDIA_IDENTIFIER;
+#endif
+ case permissions::RequestType::kRegisterProtocolHandler:
+ return CEF_PERMISSION_TYPE_REGISTER_PROTOCOL_HANDLER;
+ case permissions::RequestType::kSecurityAttestation:
+ return CEF_PERMISSION_TYPE_SECURITY_ATTESTATION;
+ case permissions::RequestType::kStorageAccess:
+ return CEF_PERMISSION_TYPE_STORAGE_ACCESS;
+ case permissions::RequestType::kTopLevelStorageAccess:
+ return CEF_PERMISSION_TYPE_TOP_LEVEL_STORAGE_ACCESS;
+ case permissions::RequestType::kU2fApiRequest:
+ return CEF_PERMISSION_TYPE_U2F_API_REQUEST;
+ case permissions::RequestType::kVrSession:
+ return CEF_PERMISSION_TYPE_VR_SESSION;
+ case permissions::RequestType::kWindowManagement:
+ return CEF_PERMISSION_TYPE_WINDOW_MANAGEMENT;
+ }
+
+ NOTREACHED();
+ return CEF_PERMISSION_TYPE_NONE;
+}
+
+uint32_t GetRequestedPermissions(
+ permissions::PermissionPrompt::Delegate* delegate) {
+ uint32_t permissions = CEF_PERMISSION_TYPE_NONE;
+ for (const auto* request : delegate->Requests()) {
+ permissions |= GetCefRequestType(request->request_type());
+ }
+ return permissions;
+}
+
+std::unique_ptr<permissions::PermissionPrompt> CreatePermissionPromptImpl(
+ content::WebContents* web_contents,
+ permissions::PermissionPrompt::Delegate* delegate,
+ bool* default_handling) {
+ CEF_REQUIRE_UIT();
+
+ if (auto browser = CefBrowserHostBase::GetBrowserForContents(web_contents)) {
+ if (auto client = browser->GetClient()) {
+ if (auto handler = client->GetPermissionHandler()) {
+ auto permission_prompt =
+ std::make_unique<CefPermissionPrompt>(delegate);
+
+ const auto prompt_id = ++g_next_prompt_id;
+ auto callback =
+ base::BindOnce(&ExecuteResult, browser, prompt_id,
+ permission_prompt->MakeDelegateCallback());
+
+ CefRefPtr<CefPermissionPromptCallbackImpl> callbackImpl(
+ new CefPermissionPromptCallbackImpl(std::move(callback)));
+ bool handled = handler->OnShowPermissionPrompt(
+ browser, prompt_id, delegate->GetRequestingOrigin().spec(),
+ GetRequestedPermissions(delegate), callbackImpl.get());
+
+ if (callbackImpl->IsDisconnected() || handled) {
+ // Callback execution will be async.
+ LOG_IF(ERROR, !handled)
+ << "Should return true from OnShowPermissionPrompt when "
+ "executing the callback";
+ *default_handling = false;
+ permission_prompt->AttachClientCallback(callbackImpl);
+ return permission_prompt;
+ } else {
+ // Proceed with default handling. |callback| is discarded without
+ // execution.
+ callback = callbackImpl->Disconnect();
+ }
+ }
+ }
+ }
+
+ if (cef::IsAlloyRuntimeEnabled()) {
+ LOG(INFO) << "Implement OnShowPermissionPrompt to override default IGNORE "
+ "handling of permission prompts.";
+ }
+
+ // Proceed with default handling. This will be IGNORE with the Alloy runtime
+ // and default UI prompt with the Chrome runtime.
+ *default_handling = true;
+ return nullptr;
+}
+
+} // namespace
+
+void RegisterCreateCallback() {
+ SetCreatePermissionPromptFunction(&CreatePermissionPromptImpl);
+}
+
+} // namespace permission_prompt
diff --git a/libcef/browser/permission_prompt.h b/libcef/browser/permission_prompt.h
new file mode 100644
index 00000000..224eb045
--- /dev/null
+++ b/libcef/browser/permission_prompt.h
@@ -0,0 +1,15 @@
+// Copyright 2022 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_PERMISSION_PROMPT_H_
+#define CEF_LIBCEF_BROWSER_PERMISSION_PROMPT_H_
+#pragma once
+
+namespace permission_prompt {
+
+void RegisterCreateCallback();
+
+} // namespace permission_prompt
+
+#endif // CEF_LIBCEF_BROWSER_PERMISSION_PROMPT_H_
diff --git a/libcef/browser/prefs/browser_prefs.cc b/libcef/browser/prefs/browser_prefs.cc
new file mode 100644
index 00000000..c42a0231
--- /dev/null
+++ b/libcef/browser/prefs/browser_prefs.cc
@@ -0,0 +1,377 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#include "libcef/browser/prefs/browser_prefs.h"
+
+#include "libcef/browser/browser_context.h"
+#include "libcef/browser/browser_host_base.h"
+#include "libcef/browser/context.h"
+#include "libcef/browser/media_capture_devices_dispatcher.h"
+#include "libcef/browser/prefs/pref_registrar.h"
+#include "libcef/browser/prefs/pref_store.h"
+#include "libcef/browser/prefs/renderer_prefs.h"
+#include "libcef/common/cef_switches.h"
+#include "libcef/common/extensions/extensions_util.h"
+
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/task/thread_pool.h"
+#include "base/values.h"
+#include "chrome/browser/accessibility/accessibility_ui.h"
+#include "chrome/browser/download/download_prefs.h"
+#include "chrome/browser/media/media_device_id_salt.h"
+#include "chrome/browser/media/router/media_router_feature.h"
+#include "chrome/browser/media/webrtc/permission_bubble_media_access_handler.h"
+#include "chrome/browser/net/profile_network_context_service.h"
+#include "chrome/browser/net/system_network_context_manager.h"
+#include "chrome/browser/plugins/plugin_info_host_impl.h"
+#include "chrome/browser/prefetch/prefetch_prefs.h"
+#include "chrome/browser/prefs/chrome_command_line_pref_store.h"
+#include "chrome/browser/printing/print_preview_sticky_settings.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ssl/ssl_config_service_manager.h"
+#include "chrome/browser/themes/theme_service.h"
+#include "chrome/browser/ui/webui/print_preview/policy_settings.h"
+#include "chrome/common/buildflags.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/net/safe_search_util.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/grit/locale_settings.h"
+#include "components/certificate_transparency/pref_names.h"
+#include "components/component_updater/component_updater_service.h"
+#include "components/content_settings/core/browser/cookie_settings.h"
+#include "components/content_settings/core/browser/host_content_settings_map.h"
+#include "components/domain_reliability/domain_reliability_prefs.h"
+#include "components/flags_ui/pref_service_flags_storage.h"
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "components/language/core/browser/language_prefs.h"
+#include "components/language/core/browser/pref_names.h"
+#include "components/permissions/permission_actions_history.h"
+#include "components/pref_registry/pref_registry_syncable.h"
+#include "components/prefs/json_pref_store.h"
+#include "components/prefs/pref_filter.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/pref_service.h"
+#include "components/privacy_sandbox/privacy_sandbox_prefs.h"
+#include "components/proxy_config/pref_proxy_config_tracker_impl.h"
+#include "components/proxy_config/proxy_config_dictionary.h"
+#include "components/safe_browsing/core/common/safe_browsing_prefs.h"
+#include "components/spellcheck/browser/pref_names.h"
+#include "components/sync_preferences/pref_service_syncable.h"
+#include "components/sync_preferences/pref_service_syncable_factory.h"
+#include "components/update_client/update_client.h"
+#include "content/public/browser/browser_thread.h"
+#include "extensions/browser/extension_prefs.h"
+#include "extensions/buildflags/buildflags.h"
+#include "net/http/http_util.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/ui_base_switches.h"
+
+#if BUILDFLAG(IS_WIN)
+#include "components/os_crypt/os_crypt.h"
+#endif
+
+#if BUILDFLAG(ENABLE_SUPERVISED_USERS)
+#include "chrome/browser/supervised_user/supervised_user_pref_store.h"
+#include "chrome/browser/supervised_user/supervised_user_settings_service.h"
+#include "chrome/browser/supervised_user/supervised_user_settings_service_factory.h"
+#endif
+
+namespace browser_prefs {
+
+namespace {
+
+// Match the logic in chrome/browser/net/profile_network_context_service.cc.
+std::string ComputeAcceptLanguageFromPref(const std::string& language_pref) {
+ std::string accept_languages_str =
+ net::HttpUtil::ExpandLanguageList(language_pref);
+ return net::HttpUtil::GenerateAcceptLanguageHeader(accept_languages_str);
+}
+
+// Return the most relevant setting based on |browser_context| and |browser|.
+std::string GetAcceptLanguageListSetting(CefBrowserContext* browser_context,
+ CefBrowserHostBase* browser) {
+ if (browser) {
+ const auto& settings = browser->settings();
+ if (settings.accept_language_list.length > 0) {
+ return CefString(&settings.accept_language_list);
+ }
+ }
+
+ if (browser_context) {
+ const auto& settings = browser_context->settings();
+ if (settings.accept_language_list.length > 0) {
+ return CefString(&settings.accept_language_list);
+ }
+ }
+
+ const auto& settings = CefContext::Get()->settings();
+ if (settings.accept_language_list.length > 0) {
+ return CefString(&settings.accept_language_list);
+ }
+
+ return std::string();
+}
+
+} // namespace
+
+const char kUserPrefsFileName[] = "UserPrefs.json";
+const char kLocalPrefsFileName[] = "LocalPrefs.json";
+
+void RegisterLocalStatePrefs(PrefRegistrySimple* registry) {
+ pref_registrar::RegisterCustomPrefs(CEF_PREFERENCES_TYPE_GLOBAL, registry);
+}
+
+void RegisterProfilePrefs(PrefRegistrySimple* registry) {
+ pref_registrar::RegisterCustomPrefs(CEF_PREFERENCES_TYPE_REQUEST_CONTEXT,
+ registry);
+}
+
+std::unique_ptr<PrefService> CreatePrefService(Profile* profile,
+ const base::FilePath& cache_path,
+ bool persist_user_preferences) {
+ const base::CommandLine* command_line =
+ base::CommandLine::ForCurrentProcess();
+
+ // Use of PrefServiceSyncable is required by Chrome code such as
+ // HostContentSettingsMapFactory that calls PrefServiceSyncableFromProfile.
+ sync_preferences::PrefServiceSyncableFactory factory;
+
+ // Used to store command-line preferences, most of which will be evaluated in
+ // the CommandLinePrefStore constructor. Preferences set in this manner cannot
+ // be overridden by the user.
+ scoped_refptr<ChromeCommandLinePrefStore> command_line_pref_store(
+ new ChromeCommandLinePrefStore(command_line));
+ renderer_prefs::SetCommandLinePrefDefaults(command_line_pref_store.get());
+ factory.set_command_line_prefs(command_line_pref_store);
+
+ // True if preferences will be stored on disk.
+ const bool store_on_disk = !cache_path.empty() && persist_user_preferences;
+
+ scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner;
+ if (store_on_disk) {
+ // Get sequenced task runner for making sure that file operations are
+ // executed in expected order (what was previously assured by the FILE
+ // thread).
+ sequenced_task_runner = base::ThreadPool::CreateSequencedTaskRunner(
+ {base::MayBlock(), base::TaskShutdownBehavior::BLOCK_SHUTDOWN});
+ }
+
+ // Used to store user preferences.
+ scoped_refptr<PersistentPrefStore> user_pref_store;
+ if (store_on_disk) {
+ const base::FilePath& pref_path = cache_path.AppendASCII(
+ profile ? kUserPrefsFileName : kLocalPrefsFileName);
+ scoped_refptr<JsonPrefStore> json_pref_store = new JsonPrefStore(
+ pref_path, std::unique_ptr<PrefFilter>(), sequenced_task_runner);
+ factory.set_user_prefs(json_pref_store.get());
+ } else {
+ scoped_refptr<CefPrefStore> cef_pref_store = new CefPrefStore();
+ cef_pref_store->SetInitializationCompleted();
+ factory.set_user_prefs(cef_pref_store.get());
+ }
+
+#if BUILDFLAG(ENABLE_SUPERVISED_USERS)
+ if (profile) {
+ // Used to store supervised user preferences.
+ SupervisedUserSettingsService* supervised_user_settings =
+ SupervisedUserSettingsServiceFactory::GetForKey(
+ profile->GetProfileKey());
+
+ if (store_on_disk) {
+ supervised_user_settings->Init(cache_path, sequenced_task_runner.get(),
+ true);
+ } else {
+ scoped_refptr<CefPrefStore> cef_pref_store = new CefPrefStore();
+ cef_pref_store->SetInitializationCompleted();
+ supervised_user_settings->Init(cef_pref_store);
+ }
+
+ scoped_refptr<PrefStore> supervised_user_prefs =
+ base::MakeRefCounted<SupervisedUserPrefStore>(supervised_user_settings);
+ DCHECK(supervised_user_prefs->IsInitializationComplete());
+ factory.set_supervised_user_prefs(supervised_user_prefs);
+ }
+#endif // BUILDFLAG(ENABLE_SUPERVISED_USERS)
+
+ // Registry that will be populated with all known preferences. Preferences
+ // are registered with default values that may be changed via a *PrefStore.
+ scoped_refptr<user_prefs::PrefRegistrySyncable> registry(
+ new user_prefs::PrefRegistrySyncable());
+
+ // Some preferences are specific to CEF and others are defined in Chromium.
+ // The preferred approach for registering preferences defined in Chromium is
+ // as follows:
+ //
+ // 1. If a non-static RegisterProfilePrefs() method exists in a *Factory
+ // class then add a *Factory::GetInstance() call in
+ // EnsureBrowserContextKeyedServiceFactoriesBuilt().
+ // 2. If a static RegisterPrefs() method exists then call that method in the
+ // "Default preferences" section below.
+ // 3. If the default values are not appropriate but the set of registered
+ // preferences is otherwise fine then change the defaults by calling
+ // SetDefaultPrefValue after calling the existing registration method.
+ // 4. If the original registration method contains many unused preferences or
+ // otherwise inappropiate logic (e.g. calls to objects that CEF doesn't
+ // use) then register the preferences directly instead of calling the
+ // existing registration method.
+
+ // Default preferences.
+ CefMediaCaptureDevicesDispatcher::RegisterPrefs(registry.get());
+ certificate_transparency::prefs::RegisterPrefs(registry.get());
+ flags_ui::PrefServiceFlagsStorage::RegisterPrefs(registry.get());
+ media_router::RegisterLocalStatePrefs(registry.get());
+ PluginInfoHostImpl::RegisterUserPrefs(registry.get());
+ PrefProxyConfigTrackerImpl::RegisterPrefs(registry.get());
+ ProfileNetworkContextService::RegisterLocalStatePrefs(registry.get());
+ SSLConfigServiceManager::RegisterPrefs(registry.get());
+ update_client::RegisterPrefs(registry.get());
+
+ if (!profile) {
+ component_updater::RegisterComponentUpdateServicePrefs(registry.get());
+ domain_reliability::RegisterPrefs(registry.get());
+ SystemNetworkContextManager::RegisterPrefs(registry.get());
+#if BUILDFLAG(IS_WIN)
+ OSCrypt::RegisterLocalPrefs(registry.get());
+#endif
+ }
+
+ // Browser process preferences.
+ // Based on chrome/browser/browser_process_impl.cc RegisterPrefs.
+ registry->RegisterBooleanPref(prefs::kAllowCrossOriginAuthPrompt, false);
+
+ // Browser UI preferences.
+ // Based on chrome/browser/ui/browser_ui_prefs.cc RegisterBrowserPrefs.
+ registry->RegisterBooleanPref(prefs::kAllowFileSelectionDialogs, true);
+
+ // Based on chrome/browser/ui/browser_ui_prefs.cc RegisterBrowserUserPrefs.
+ registry->RegisterBooleanPref(prefs::kPrintPreviewUseSystemDefaultPrinter,
+ false);
+ registry->RegisterBooleanPref(prefs::kWebRTCAllowLegacyTLSProtocols, false);
+
+ // Profile preferences.
+ // Based on chrome/browser/profiles/profiles_state.cc RegisterPrefs.
+ registry->RegisterStringPref(prefs::kProfileLastUsed, std::string());
+
+ if (profile) {
+ // Call RegisterProfilePrefs() for all services listed by
+ // EnsureBrowserContextKeyedServiceFactoriesBuilt().
+ BrowserContextDependencyManager::GetInstance()
+ ->RegisterProfilePrefsForServices(registry.get());
+
+ // Default profile preferences.
+ AccessibilityUIMessageHandler::RegisterProfilePrefs(registry.get());
+ extensions::ExtensionPrefs::RegisterProfilePrefs(registry.get());
+ HostContentSettingsMap::RegisterProfilePrefs(registry.get());
+ language::LanguagePrefs::RegisterProfilePrefs(registry.get());
+ media_router::RegisterProfilePrefs(registry.get());
+ MediaDeviceIDSalt::RegisterProfilePrefs(registry.get());
+ PermissionBubbleMediaAccessHandler::RegisterProfilePrefs(registry.get());
+ permissions::PermissionActionsHistory::RegisterProfilePrefs(registry.get());
+ prefetch::RegisterPredictionOptionsProfilePrefs(registry.get());
+ privacy_sandbox::RegisterProfilePrefs(registry.get());
+ ProfileNetworkContextService::RegisterProfilePrefs(registry.get());
+ safe_browsing::RegisterProfilePrefs(registry.get());
+
+ const std::string& locale =
+ command_line->GetSwitchValueASCII(switches::kLang);
+ DCHECK(!locale.empty());
+ renderer_prefs::RegisterProfilePrefs(registry.get(), locale);
+
+ // Print preferences.
+ // Based on ProfileImpl::RegisterProfilePrefs.
+ registry->RegisterBooleanPref(prefs::kForceGoogleSafeSearch, false);
+ registry->RegisterIntegerPref(prefs::kForceYouTubeRestrict,
+ safe_search_util::YOUTUBE_RESTRICT_OFF);
+ registry->RegisterStringPref(prefs::kAllowedDomainsForApps, std::string());
+ registry->RegisterBooleanPref(prefs::kPrintingEnabled, true);
+ registry->RegisterBooleanPref(prefs::kPrintPreviewDisabled,
+ !extensions::PrintPreviewEnabled());
+ registry->RegisterStringPref(
+ prefs::kPrintPreviewDefaultDestinationSelectionRules, std::string());
+ registry->RegisterBooleanPref(prefs::kCloudPrintSubmitEnabled, false);
+ registry->RegisterBooleanPref(prefs::kEnableMediaRouter, true);
+ printing::PolicySettings::RegisterProfilePrefs(registry.get());
+ printing::PrintPreviewStickySettings::RegisterProfilePrefs(registry.get());
+ DownloadPrefs::RegisterProfilePrefs(registry.get());
+
+ // Cache preferences.
+ // Based on ProfileImpl::RegisterProfilePrefs.
+ registry->RegisterFilePathPref(prefs::kDiskCacheDir, cache_path);
+ registry->RegisterIntegerPref(prefs::kDiskCacheSize, 0);
+
+ // Based on Profile::RegisterProfilePrefs.
+ registry->RegisterBooleanPref(prefs::kSearchSuggestEnabled, false);
+ registry->RegisterStringPref(prefs::kSessionExitType, std::string());
+
+ // Based on ChromeContentBrowserClient::RegisterProfilePrefs.
+ registry->RegisterBooleanPref(
+ prefs::kAccessControlAllowMethodsInCORSPreflightSpecConformant, true);
+
+ // Spell checking preferences.
+ // Modify defaults from SpellcheckServiceFactory::RegisterProfilePrefs.
+ std::string spellcheck_lang =
+ command_line->GetSwitchValueASCII(switches::kOverrideSpellCheckLang);
+ if (!spellcheck_lang.empty()) {
+ registry->SetDefaultPrefValue(spellcheck::prefs::kSpellCheckDictionary,
+ base::Value(spellcheck_lang));
+ }
+ const bool enable_spelling_service_ =
+ command_line->HasSwitch(switches::kEnableSpellingService);
+ registry->SetDefaultPrefValue(
+ spellcheck::prefs::kSpellCheckUseSpellingService,
+ base::Value(enable_spelling_service_));
+ registry->SetDefaultPrefValue(spellcheck::prefs::kSpellCheckEnable,
+ base::Value(!enable_spelling_service_));
+
+ // DevTools preferences.
+ // Based on DevToolsWindow::RegisterProfilePrefs.
+ registry->RegisterDictionaryPref(prefs::kDevToolsPreferences);
+ registry->RegisterDictionaryPref(prefs::kDevToolsEditedFiles);
+
+ // Language preferences. Used by ProfileNetworkContextService and
+ // InterceptedRequestHandlerWrapper.
+ const std::string& accept_language_list = GetAcceptLanguageListSetting(
+ CefBrowserContext::FromProfile(profile), /*browser=*/nullptr);
+ if (!accept_language_list.empty()) {
+ registry->SetDefaultPrefValue(language::prefs::kAcceptLanguages,
+ base::Value(accept_language_list));
+ }
+ registry->RegisterListPref(prefs::kWebRtcLocalIpsAllowedUrls);
+
+ // Always do this after all other profile prefs.
+ RegisterProfilePrefs(registry.get());
+ } else {
+ // Always do this after all other local state prefs.
+ RegisterLocalStatePrefs(registry.get());
+ }
+
+ // Build the PrefService that manages the PrefRegistry and PrefStores.
+ return factory.CreateSyncable(registry.get());
+}
+
+std::string GetAcceptLanguageList(CefBrowserContext* browser_context,
+ CefBrowserHostBase* browser,
+ bool expand) {
+ // Always prefer to the CEF settings configuration, if specified.
+ std::string accept_language_list =
+ GetAcceptLanguageListSetting(browser_context, browser);
+ if (accept_language_list.empty() && browser_context) {
+ // Fall back to the preference value. For the Alloy runtime the default
+ // value comes from browser_prefs::CreatePrefService() above. For the Chrome
+ // runtime the default value comes from the configured locale
+ // (IDS_ACCEPT_LANGUAGES) which is then overridden by the user preference in
+ // chrome://settings/languages, all managed by language::LanguagePrefs.
+ auto prefs = browser_context->AsProfile()->GetPrefs();
+ accept_language_list = prefs->GetString(language::prefs::kAcceptLanguages);
+ }
+
+ if (!accept_language_list.empty() && expand) {
+ return ComputeAcceptLanguageFromPref(accept_language_list);
+ }
+ return std::string();
+}
+
+} // namespace browser_prefs
diff --git a/libcef/browser/prefs/browser_prefs.h b/libcef/browser/prefs/browser_prefs.h
new file mode 100644
index 00000000..85ee6626
--- /dev/null
+++ b/libcef/browser/prefs/browser_prefs.h
@@ -0,0 +1,45 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_PREFS_BROWSER_PREFS_H_
+#define CEF_LIBCEF_BROWSER_PREFS_BROWSER_PREFS_H_
+
+#include <memory>
+
+namespace base {
+class FilePath;
+}
+
+class CefBrowserContext;
+class CefBrowserHostBase;
+class PrefRegistrySimple;
+class PrefService;
+class Profile;
+
+namespace browser_prefs {
+
+// Name for the user prefs JSON file.
+extern const char kUserPrefsFileName[];
+
+// Register preferences specific to CEF.
+void RegisterLocalStatePrefs(PrefRegistrySimple* registry);
+void RegisterProfilePrefs(PrefRegistrySimple* registry);
+
+// Create the PrefService used to manage pref registration and storage.
+// |profile| will be nullptr for the system-level PrefService. Used with the
+// Alloy runtime only.
+std::unique_ptr<PrefService> CreatePrefService(Profile* profile,
+ const base::FilePath& cache_path,
+ bool persist_user_preferences);
+
+// Returns the value for populating the accept-language HTTP request header.
+// |browser_context| and/or |browser| may be nullptr. If |expand| is true then
+// base languages and Q values may be added.
+std::string GetAcceptLanguageList(CefBrowserContext* browser_context,
+ CefBrowserHostBase* browser,
+ bool expand);
+
+} // namespace browser_prefs
+
+#endif // CEF_LIBCEF_BROWSER_PREFS_BROWSER_PREFS_H_
diff --git a/libcef/browser/prefs/pref_helper.cc b/libcef/browser/prefs/pref_helper.cc
new file mode 100644
index 00000000..714882fe
--- /dev/null
+++ b/libcef/browser/prefs/pref_helper.cc
@@ -0,0 +1,118 @@
+// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#include "libcef/browser/prefs/pref_helper.h"
+
+#include "libcef/browser/thread_util.h"
+#include "libcef/common/values_impl.h"
+
+#include "base/notreached.h"
+#include "base/strings/stringprintf.h"
+#include "components/prefs/pref_service.h"
+
+namespace pref_helper {
+
+namespace {
+
+const char* GetTypeString(base::Value::Type type) {
+ switch (type) {
+ case base::Value::Type::NONE:
+ return "NULL";
+ case base::Value::Type::BOOLEAN:
+ return "BOOLEAN";
+ case base::Value::Type::INTEGER:
+ return "INTEGER";
+ case base::Value::Type::DOUBLE:
+ return "DOUBLE";
+ case base::Value::Type::STRING:
+ return "STRING";
+ case base::Value::Type::BINARY:
+ return "BINARY";
+ case base::Value::Type::DICTIONARY:
+ return "DICTIONARY";
+ case base::Value::Type::LIST:
+ return "LIST";
+ }
+
+ NOTREACHED();
+ return "UNKNOWN";
+}
+
+} // namespace
+
+bool HasPreference(PrefService* pref_service, const CefString& name) {
+ return (pref_service->FindPreference(name) != nullptr);
+}
+
+CefRefPtr<CefValue> GetPreference(PrefService* pref_service,
+ const CefString& name) {
+ const PrefService::Preference* pref = pref_service->FindPreference(name);
+ if (!pref) {
+ return nullptr;
+ }
+ return new CefValueImpl(pref->GetValue()->Clone());
+}
+
+CefRefPtr<CefDictionaryValue> GetAllPreferences(PrefService* pref_service,
+ bool include_defaults) {
+ // Returns a DeepCopy of the value.
+ base::Value values = pref_service->GetPreferenceValues(
+ include_defaults ? PrefService::INCLUDE_DEFAULTS
+ : PrefService::EXCLUDE_DEFAULTS);
+
+ // CefDictionaryValueImpl takes ownership of |values| contents.
+ return new CefDictionaryValueImpl(std::move(values), /*read_only=*/false);
+}
+
+bool CanSetPreference(PrefService* pref_service, const CefString& name) {
+ const PrefService::Preference* pref = pref_service->FindPreference(name);
+ return (pref && pref->IsUserModifiable());
+}
+
+bool SetPreference(PrefService* pref_service,
+ const CefString& name,
+ CefRefPtr<CefValue> value,
+ CefString& error) {
+ // The below validation logic should match PrefService::SetUserPrefValue.
+
+ const PrefService::Preference* pref = pref_service->FindPreference(name);
+ if (!pref) {
+ error = "Trying to modify an unregistered preference";
+ return false;
+ }
+
+ if (!pref->IsUserModifiable()) {
+ error = "Trying to modify a preference that is not user modifiable";
+ return false;
+ }
+
+ if (!value.get()) {
+ // Reset the preference to its default value.
+ pref_service->ClearPref(name);
+ return true;
+ }
+
+ if (!value->IsValid()) {
+ error = "A valid value is required";
+ return false;
+ }
+
+ CefValueImpl* impl = static_cast<CefValueImpl*>(value.get());
+
+ CefValueImpl::ScopedLockedValue scoped_locked_value(impl);
+ base::Value* impl_value = impl->GetValueUnsafe();
+
+ if (pref->GetType() != impl_value->type()) {
+ error = base::StringPrintf(
+ "Trying to set a preference of type %s to value of type %s",
+ GetTypeString(pref->GetType()), GetTypeString(impl_value->type()));
+ return false;
+ }
+
+ // PrefService will make a DeepCopy of |impl_value|.
+ pref_service->Set(name, *impl_value);
+ return true;
+}
+
+} // namespace pref_helper
diff --git a/libcef/browser/prefs/pref_helper.h b/libcef/browser/prefs/pref_helper.h
new file mode 100644
index 00000000..8c85208a
--- /dev/null
+++ b/libcef/browser/prefs/pref_helper.h
@@ -0,0 +1,33 @@
+// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_PREFS_PREF_HELPER_H_
+#define CEF_LIBCEF_BROWSER_PREFS_PREF_HELPER_H_
+
+#include "include/cef_values.h"
+
+class PrefService;
+
+namespace pref_helper {
+
+// Function names and arguments match the CefPreferenceManager interface.
+
+bool HasPreference(PrefService* pref_service, const CefString& name);
+
+CefRefPtr<CefValue> GetPreference(PrefService* pref_service,
+ const CefString& name);
+
+CefRefPtr<CefDictionaryValue> GetAllPreferences(PrefService* pref_service,
+ bool include_defaults);
+
+bool CanSetPreference(PrefService* pref_service, const CefString& name);
+
+bool SetPreference(PrefService* pref_service,
+ const CefString& name,
+ CefRefPtr<CefValue> value,
+ CefString& error);
+
+} // namespace pref_helper
+
+#endif // CEF_LIBCEF_BROWSER_PREFS_PREF_HELPER_H_
diff --git a/libcef/browser/prefs/pref_registrar.cc b/libcef/browser/prefs/pref_registrar.cc
new file mode 100644
index 00000000..70e3044a
--- /dev/null
+++ b/libcef/browser/prefs/pref_registrar.cc
@@ -0,0 +1,96 @@
+// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#include "libcef/browser/prefs/pref_registrar.h"
+
+#include "include/cef_app.h"
+#include "include/cef_browser_process_handler.h"
+#include "include/cef_preference.h"
+#include "libcef/common/app_manager.h"
+#include "libcef/common/values_impl.h"
+
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/pref_store.h"
+
+namespace pref_registrar {
+
+namespace {
+
+class CefPreferenceRegistrarImpl : public CefPreferenceRegistrar {
+ public:
+ explicit CefPreferenceRegistrarImpl(PrefRegistrySimple* registry)
+ : registry_(registry) {}
+
+ CefPreferenceRegistrarImpl(const CefPreferenceRegistrarImpl&) = delete;
+ CefPreferenceRegistrarImpl& operator=(const CefPreferenceRegistrarImpl&) =
+ delete;
+
+ // CefPreferenceRegistrar methods.
+ bool AddPreference(const CefString& name,
+ CefRefPtr<CefValue> default_value) override {
+ const std::string nameStr = name;
+ if (registry_->defaults()->GetValue(nameStr, nullptr)) {
+ LOG(ERROR) << "Trying to register a previously registered preference: "
+ << nameStr;
+ return false;
+ }
+
+ switch (default_value->GetType()) {
+ case VTYPE_INVALID:
+ case VTYPE_NULL:
+ case VTYPE_BINARY:
+ break;
+ case VTYPE_BOOL:
+ registry_->RegisterBooleanPref(nameStr, default_value->GetBool());
+ return true;
+ case VTYPE_INT:
+ registry_->RegisterIntegerPref(nameStr, default_value->GetInt());
+ return true;
+ case VTYPE_DOUBLE:
+ registry_->RegisterDoublePref(nameStr, default_value->GetDouble());
+ return true;
+ case VTYPE_STRING:
+ registry_->RegisterStringPref(nameStr, default_value->GetString());
+ return true;
+ case VTYPE_DICTIONARY:
+ case VTYPE_LIST:
+ RegisterComplexPref(nameStr, default_value);
+ return true;
+ };
+
+ LOG(ERROR) << "Invalid value type for preference: " << nameStr;
+ return false;
+ }
+
+ private:
+ void RegisterComplexPref(const std::string& name,
+ CefRefPtr<CefValue> default_value) {
+ CefValueImpl* impl = static_cast<CefValueImpl*>(default_value.get());
+ auto impl_value = impl->CopyValue();
+
+ if (impl_value.type() == base::Value::Type::DICT) {
+ registry_->RegisterDictionaryPref(name, std::move(impl_value));
+ } else if (impl_value.type() == base::Value::Type::LIST) {
+ registry_->RegisterListPref(name, std::move(impl_value));
+ } else {
+ NOTREACHED();
+ }
+ }
+
+ PrefRegistrySimple* const registry_;
+};
+
+} // namespace
+
+void RegisterCustomPrefs(cef_preferences_type_t type,
+ PrefRegistrySimple* registry) {
+ if (auto app = CefAppManager::Get()->GetApplication()) {
+ if (auto handler = app->GetBrowserProcessHandler()) {
+ CefPreferenceRegistrarImpl registrar(registry);
+ handler->OnRegisterCustomPreferences(type, &registrar);
+ }
+ }
+}
+
+} // namespace pref_registrar
diff --git a/libcef/browser/prefs/pref_registrar.h b/libcef/browser/prefs/pref_registrar.h
new file mode 100644
index 00000000..b6edcf44
--- /dev/null
+++ b/libcef/browser/prefs/pref_registrar.h
@@ -0,0 +1,19 @@
+// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_PREFS_PREF_REGISTRAR_H_
+#define CEF_LIBCEF_BROWSER_PREFS_PREF_REGISTRAR_H_
+
+#include "include/internal/cef_types.h"
+
+class PrefRegistrySimple;
+
+namespace pref_registrar {
+
+void RegisterCustomPrefs(cef_preferences_type_t type,
+ PrefRegistrySimple* registry);
+
+} // namespace pref_registrar
+
+#endif // CEF_LIBCEF_BROWSER_PREFS_PREF_REGISTRAR_H_
diff --git a/libcef/browser/prefs/pref_store.cc b/libcef/browser/prefs/pref_store.cc
new file mode 100644
index 00000000..0fb170bf
--- /dev/null
+++ b/libcef/browser/prefs/pref_store.cc
@@ -0,0 +1,217 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/prefs/pref_store.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/memory/ptr_util.h"
+#include "base/values.h"
+
+CefPrefStore::CefPrefStore()
+ : read_only_(true),
+ read_success_(true),
+ read_error_(PersistentPrefStore::PREF_READ_ERROR_NONE),
+ block_async_read_(false),
+ pending_async_read_(false),
+ init_complete_(false),
+ committed_(true) {}
+
+bool CefPrefStore::GetValue(base::StringPiece key,
+ const base::Value** value) const {
+ return prefs_.GetValue(key, value);
+}
+
+base::Value::Dict CefPrefStore::GetValues() const {
+ return prefs_.AsDict();
+}
+
+bool CefPrefStore::GetMutableValue(const std::string& key,
+ base::Value** value) {
+ return prefs_.GetValue(key, value);
+}
+
+void CefPrefStore::AddObserver(PrefStore::Observer* observer) {
+ observers_.AddObserver(observer);
+}
+
+void CefPrefStore::RemoveObserver(PrefStore::Observer* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+bool CefPrefStore::HasObservers() const {
+ return !observers_.empty();
+}
+
+bool CefPrefStore::IsInitializationComplete() const {
+ return init_complete_;
+}
+
+void CefPrefStore::SetValue(const std::string& key,
+ base::Value value,
+ uint32_t flags) {
+ if (prefs_.SetValue(key, std::move(value))) {
+ committed_ = false;
+ NotifyPrefValueChanged(key);
+ }
+}
+
+void CefPrefStore::SetValueSilently(const std::string& key,
+ base::Value value,
+ uint32_t flags) {
+ if (prefs_.SetValue(key, std::move(value))) {
+ committed_ = false;
+ }
+}
+
+void CefPrefStore::RemoveValuesByPrefixSilently(const std::string& prefix) {
+ prefs_.ClearWithPrefix(prefix);
+ committed_ = false;
+}
+
+void CefPrefStore::RemoveValue(const std::string& key, uint32_t flags) {
+ if (prefs_.RemoveValue(key)) {
+ committed_ = false;
+ NotifyPrefValueChanged(key);
+ }
+}
+
+bool CefPrefStore::ReadOnly() const {
+ return read_only_;
+}
+
+PersistentPrefStore::PrefReadError CefPrefStore::GetReadError() const {
+ return read_error_;
+}
+
+PersistentPrefStore::PrefReadError CefPrefStore::ReadPrefs() {
+ NotifyInitializationCompleted();
+ return read_error_;
+}
+
+void CefPrefStore::ReadPrefsAsync(ReadErrorDelegate* error_delegate) {
+ DCHECK(!pending_async_read_);
+ error_delegate_.reset(error_delegate);
+ if (block_async_read_) {
+ pending_async_read_ = true;
+ } else {
+ NotifyInitializationCompleted();
+ }
+}
+
+void CefPrefStore::CommitPendingWrite(
+ base::OnceClosure done_callback,
+ base::OnceClosure synchronous_done_callback) {
+ committed_ = true;
+ PersistentPrefStore::CommitPendingWrite(std::move(done_callback),
+ std::move(synchronous_done_callback));
+}
+
+void CefPrefStore::SchedulePendingLossyWrites() {}
+
+void CefPrefStore::OnStoreDeletionFromDisk() {}
+
+void CefPrefStore::SetInitializationCompleted() {
+ NotifyInitializationCompleted();
+}
+
+void CefPrefStore::NotifyPrefValueChanged(const std::string& key) {
+ for (Observer& observer : observers_) {
+ observer.OnPrefValueChanged(key);
+ }
+}
+
+void CefPrefStore::NotifyInitializationCompleted() {
+ DCHECK(!init_complete_);
+ init_complete_ = true;
+ if (read_success_ && read_error_ != PREF_READ_ERROR_NONE && error_delegate_) {
+ error_delegate_->OnError(read_error_);
+ }
+ for (Observer& observer : observers_) {
+ observer.OnInitializationCompleted(read_success_);
+ }
+}
+
+void CefPrefStore::ReportValueChanged(const std::string& key, uint32_t flags) {
+ for (Observer& observer : observers_) {
+ observer.OnPrefValueChanged(key);
+ }
+}
+
+void CefPrefStore::SetString(const std::string& key, const std::string& value) {
+ SetValue(key, base::Value(value), DEFAULT_PREF_WRITE_FLAGS);
+}
+
+void CefPrefStore::SetInteger(const std::string& key, int value) {
+ SetValue(key, base::Value(value), DEFAULT_PREF_WRITE_FLAGS);
+}
+
+void CefPrefStore::SetBoolean(const std::string& key, bool value) {
+ SetValue(key, base::Value(value), DEFAULT_PREF_WRITE_FLAGS);
+}
+
+bool CefPrefStore::GetString(const std::string& key, std::string* value) const {
+ const base::Value* stored_value;
+ if (!prefs_.GetValue(key, &stored_value) || !stored_value) {
+ return false;
+ }
+
+ if (value && stored_value->is_string()) {
+ *value = stored_value->GetString();
+ return true;
+ }
+ return stored_value->is_string();
+}
+
+bool CefPrefStore::GetInteger(const std::string& key, int* value) const {
+ const base::Value* stored_value;
+ if (!prefs_.GetValue(key, &stored_value) || !stored_value) {
+ return false;
+ }
+
+ if (value && stored_value->is_int()) {
+ *value = stored_value->GetInt();
+ return true;
+ }
+ return stored_value->is_int();
+}
+
+bool CefPrefStore::GetBoolean(const std::string& key, bool* value) const {
+ const base::Value* stored_value;
+ if (!prefs_.GetValue(key, &stored_value) || !stored_value) {
+ return false;
+ }
+
+ if (value && stored_value->is_bool()) {
+ *value = stored_value->GetBool();
+ return true;
+ }
+ return stored_value->is_bool();
+}
+
+void CefPrefStore::SetBlockAsyncRead(bool block_async_read) {
+ DCHECK(!init_complete_);
+ block_async_read_ = block_async_read;
+ if (pending_async_read_ && !block_async_read_) {
+ NotifyInitializationCompleted();
+ }
+}
+
+void CefPrefStore::set_read_only(bool read_only) {
+ read_only_ = read_only;
+}
+
+void CefPrefStore::set_read_success(bool read_success) {
+ DCHECK(!init_complete_);
+ read_success_ = read_success;
+}
+
+void CefPrefStore::set_read_error(
+ PersistentPrefStore::PrefReadError read_error) {
+ DCHECK(!init_complete_);
+ read_error_ = read_error;
+}
+
+CefPrefStore::~CefPrefStore() {}
diff --git a/libcef/browser/prefs/pref_store.h b/libcef/browser/prefs/pref_store.h
new file mode 100644
index 00000000..c5dc4218
--- /dev/null
+++ b/libcef/browser/prefs/pref_store.h
@@ -0,0 +1,118 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_PREFS_PREF_STORE_H_
+#define CEF_LIBCEF_BROWSER_PREFS_PREF_STORE_H_
+
+#include <stdint.h>
+
+#include <string>
+
+#include "base/observer_list.h"
+#include "components/prefs/persistent_pref_store.h"
+#include "components/prefs/pref_value_map.h"
+
+// Preference store implementation that supports explicit manipulation of the
+// contents of the store, triggering notifications where appropriate.
+// Based on components/prefs/testing_pref_store.h.
+class CefPrefStore : public PersistentPrefStore {
+ public:
+ CefPrefStore();
+
+ CefPrefStore(const CefPrefStore&) = delete;
+ CefPrefStore& operator=(const CefPrefStore&) = delete;
+
+ // Overriden from PrefStore.
+ bool GetValue(base::StringPiece key,
+ const base::Value** result) const override;
+ base::Value::Dict GetValues() const override;
+ void AddObserver(PrefStore::Observer* observer) override;
+ void RemoveObserver(PrefStore::Observer* observer) override;
+ bool HasObservers() const override;
+ bool IsInitializationComplete() const override;
+
+ // PersistentPrefStore overrides:
+ bool GetMutableValue(const std::string& key, base::Value** result) override;
+ void ReportValueChanged(const std::string& key, uint32_t flags) override;
+ void SetValue(const std::string& key,
+ base::Value value,
+ uint32_t flags) override;
+ void SetValueSilently(const std::string& key,
+ base::Value value,
+ uint32_t flags) override;
+ void RemoveValuesByPrefixSilently(const std::string& prefix) override;
+ void RemoveValue(const std::string& key, uint32_t flags) override;
+ bool ReadOnly() const override;
+ PrefReadError GetReadError() const override;
+ PersistentPrefStore::PrefReadError ReadPrefs() override;
+ void ReadPrefsAsync(ReadErrorDelegate* error_delegate) override;
+ virtual void CommitPendingWrite(
+ base::OnceClosure done_callback,
+ base::OnceClosure synchronous_done_callback) override;
+ void SchedulePendingLossyWrites() override;
+ void OnStoreDeletionFromDisk() override;
+
+ // Marks the store as having completed initialization.
+ void SetInitializationCompleted();
+
+ // Used for tests to trigger notifications explicitly.
+ void NotifyPrefValueChanged(const std::string& key);
+ void NotifyInitializationCompleted();
+
+ // Some convenience getters/setters.
+ void SetString(const std::string& key, const std::string& value);
+ void SetInteger(const std::string& key, int value);
+ void SetBoolean(const std::string& key, bool value);
+
+ bool GetString(const std::string& key, std::string* value) const;
+ bool GetInteger(const std::string& key, int* value) const;
+ bool GetBoolean(const std::string& key, bool* value) const;
+
+ // Determines whether ReadPrefsAsync completes immediately. Defaults to false
+ // (non-blocking). To block, invoke this with true (blocking) before the call
+ // to ReadPrefsAsync. To unblock, invoke again with false (non-blocking) after
+ // the call to ReadPrefsAsync.
+ void SetBlockAsyncRead(bool block_async_read);
+
+ // Getter and Setter methods for setting and getting the state of the
+ // |TestingPrefStore|.
+ virtual void set_read_only(bool read_only);
+ void set_read_success(bool read_success);
+ void set_read_error(PersistentPrefStore::PrefReadError read_error);
+ bool committed() { return committed_; }
+
+ protected:
+ ~CefPrefStore() override;
+
+ private:
+ // Stores the preference values.
+ PrefValueMap prefs_;
+
+ // Flag that indicates if the PrefStore is read-only
+ bool read_only_;
+
+ // The result to pass to PrefStore::Observer::OnInitializationCompleted
+ bool read_success_;
+
+ // The result to return from ReadPrefs or ReadPrefsAsync.
+ PersistentPrefStore::PrefReadError read_error_;
+
+ // Whether a call to ReadPrefsAsync should block.
+ bool block_async_read_;
+
+ // Whether there is a pending call to ReadPrefsAsync.
+ bool pending_async_read_;
+
+ // Whether initialization has been completed.
+ bool init_complete_;
+
+ // Whether the store contents have been committed to disk since the last
+ // mutation.
+ bool committed_;
+
+ std::unique_ptr<ReadErrorDelegate> error_delegate_;
+ base::ObserverList<PrefStore::Observer, true>::Unchecked observers_;
+};
+
+#endif // COMPONENTS_PREFS_TESTING_PREF_STORE_H_
diff --git a/libcef/browser/prefs/renderer_prefs.cc b/libcef/browser/prefs/renderer_prefs.cc
new file mode 100644
index 00000000..2411c485
--- /dev/null
+++ b/libcef/browser/prefs/renderer_prefs.cc
@@ -0,0 +1,451 @@
+// Copyright (c) 2010 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#include "libcef/browser/prefs/renderer_prefs.h"
+
+#include <string>
+
+#include "libcef/browser/alloy/alloy_browser_host_impl.h"
+#include "libcef/browser/context.h"
+#include "libcef/browser/extensions/browser_extensions_util.h"
+#include "libcef/common/cef_switches.h"
+#include "libcef/common/extensions/extensions_util.h"
+#include "libcef/features/runtime_checks.h"
+
+#include "base/command_line.h"
+#include "base/i18n/character_encoding.h"
+#include "base/memory/ptr_util.h"
+#include "base/values.h"
+#include "chrome/browser/accessibility/animation_policy_prefs.h"
+#include "chrome/browser/defaults.h"
+#include "chrome/browser/extensions/extension_webkit_preferences.h"
+#include "chrome/browser/font_family_cache.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/prefs/prefs_tab_helper.h"
+#include "chrome/common/chrome_features.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/pref_names.h"
+#include "components/pref_registry/pref_registry_syncable.h"
+#include "components/prefs/command_line_pref_store.h"
+#include "components/prefs/pref_service.h"
+#include "components/prefs/pref_store.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/site_instance.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/common/url_constants.h"
+#include "extensions/browser/extension_registry.h"
+#include "extensions/browser/view_type_utils.h"
+#include "extensions/common/constants.h"
+#include "media/media_buildflags.h"
+#include "third_party/blink/public/common/peerconnection/webrtc_ip_handling_policy.h"
+#include "third_party/blink/public/common/web_preferences/web_preferences.h"
+#include "ui/native_theme/native_theme.h"
+
+namespace renderer_prefs {
+
+namespace {
+
+// Chrome preferences.
+// Should match ChromeContentBrowserClient::OverrideWebkitPrefs.
+void SetChromePrefs(Profile* profile, blink::web_pref::WebPreferences& web) {
+ PrefService* prefs = profile->GetPrefs();
+
+ // Fill per-script font preferences.
+ FontFamilyCache::FillFontFamilyMap(profile,
+ prefs::kWebKitStandardFontFamilyMap,
+ &web.standard_font_family_map);
+ FontFamilyCache::FillFontFamilyMap(profile, prefs::kWebKitFixedFontFamilyMap,
+ &web.fixed_font_family_map);
+ FontFamilyCache::FillFontFamilyMap(profile, prefs::kWebKitSerifFontFamilyMap,
+ &web.serif_font_family_map);
+ FontFamilyCache::FillFontFamilyMap(profile,
+ prefs::kWebKitSansSerifFontFamilyMap,
+ &web.sans_serif_font_family_map);
+ FontFamilyCache::FillFontFamilyMap(profile,
+ prefs::kWebKitCursiveFontFamilyMap,
+ &web.cursive_font_family_map);
+ FontFamilyCache::FillFontFamilyMap(profile,
+ prefs::kWebKitFantasyFontFamilyMap,
+ &web.fantasy_font_family_map);
+
+ web.default_font_size = prefs->GetInteger(prefs::kWebKitDefaultFontSize);
+ web.default_fixed_font_size =
+ prefs->GetInteger(prefs::kWebKitDefaultFixedFontSize);
+ web.minimum_font_size = prefs->GetInteger(prefs::kWebKitMinimumFontSize);
+ web.minimum_logical_font_size =
+ prefs->GetInteger(prefs::kWebKitMinimumLogicalFontSize);
+
+ web.default_encoding = prefs->GetString(prefs::kDefaultCharset);
+
+ web.dom_paste_enabled = prefs->GetBoolean(prefs::kWebKitDomPasteEnabled);
+ web.tabs_to_links = prefs->GetBoolean(prefs::kWebkitTabsToLinks);
+
+ if (!prefs->GetBoolean(prefs::kWebKitJavascriptEnabled)) {
+ web.javascript_enabled = false;
+ }
+ if (!prefs->GetBoolean(prefs::kWebKitWebSecurityEnabled)) {
+ web.web_security_enabled = false;
+ }
+ if (!prefs->GetBoolean(prefs::kWebKitPluginsEnabled)) {
+ web.plugins_enabled = false;
+ }
+ web.loads_images_automatically =
+ prefs->GetBoolean(prefs::kWebKitLoadsImagesAutomatically);
+
+ if (prefs->GetBoolean(prefs::kDisable3DAPIs)) {
+ web.webgl1_enabled = false;
+ web.webgl2_enabled = false;
+ }
+
+ web.allow_running_insecure_content =
+ prefs->GetBoolean(prefs::kWebKitAllowRunningInsecureContent);
+
+ web.password_echo_enabled = browser_defaults::kPasswordEchoEnabled;
+
+ web.text_areas_are_resizable =
+ prefs->GetBoolean(prefs::kWebKitTextAreasAreResizable);
+ web.hyperlink_auditing_enabled =
+ prefs->GetBoolean(prefs::kEnableHyperlinkAuditing);
+
+ if (extensions::ExtensionsEnabled()) {
+ std::string image_animation_policy =
+ prefs->GetString(prefs::kAnimationPolicy);
+ if (image_animation_policy == kAnimationPolicyOnce) {
+ web.animation_policy =
+ blink::mojom::ImageAnimationPolicy::kImageAnimationPolicyAnimateOnce;
+ } else if (image_animation_policy == kAnimationPolicyNone) {
+ web.animation_policy =
+ blink::mojom::ImageAnimationPolicy::kImageAnimationPolicyNoAnimation;
+ } else {
+ web.animation_policy =
+ blink::mojom::ImageAnimationPolicy::kImageAnimationPolicyAllowed;
+ }
+ }
+
+ // Make sure we will set the default_encoding with canonical encoding name.
+ web.default_encoding =
+ base::GetCanonicalEncodingNameByAliasName(web.default_encoding);
+ if (web.default_encoding.empty()) {
+ prefs->ClearPref(prefs::kDefaultCharset);
+ web.default_encoding = prefs->GetString(prefs::kDefaultCharset);
+ }
+ DCHECK(!web.default_encoding.empty());
+
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnablePotentiallyAnnoyingSecurityFeatures)) {
+ web.disable_reading_from_canvas = true;
+ web.strict_mixed_content_checking = true;
+ web.strict_powerful_feature_restrictions = true;
+ }
+}
+
+// Extension preferences.
+// Should match ChromeContentBrowserClientExtensionsPart::OverrideWebkitPrefs.
+void SetExtensionPrefs(content::WebContents* web_contents,
+ content::RenderViewHost* rvh,
+ blink::web_pref::WebPreferences& web) {
+ if (!extensions::ExtensionsEnabled()) {
+ return;
+ }
+
+ const extensions::ExtensionRegistry* registry =
+ extensions::ExtensionRegistry::Get(
+ rvh->GetProcess()->GetBrowserContext());
+ if (!registry) {
+ return;
+ }
+
+ // Note: it's not possible for kExtensionsScheme to change during the lifetime
+ // of the process.
+ //
+ // Ensure that we are only granting extension preferences to URLs with the
+ // correct scheme. Without this check, chrome-guest:// schemes used by webview
+ // tags as well as hosts that happen to match the id of an installed extension
+ // would get the wrong preferences.
+ const GURL& site_url =
+ web_contents->GetPrimaryMainFrame()->GetSiteInstance()->GetSiteURL();
+ if (!site_url.SchemeIs(extensions::kExtensionScheme)) {
+ return;
+ }
+
+ const extensions::Extension* extension =
+ registry->enabled_extensions().GetByID(site_url.host());
+ extension_webkit_preferences::SetPreferences(extension, &web);
+}
+
+void SetString(CommandLinePrefStore* prefs,
+ const std::string& key,
+ const std::string& value) {
+ prefs->SetValue(key, base::Value(value),
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+}
+
+void SetBool(CommandLinePrefStore* prefs, const std::string& key, bool value) {
+ prefs->SetValue(key, base::Value(value),
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+}
+
+blink::mojom::PreferredColorScheme ToBlinkPreferredColorScheme(
+ ui::NativeTheme::PreferredColorScheme native_theme_scheme) {
+ switch (native_theme_scheme) {
+ case ui::NativeTheme::PreferredColorScheme::kDark:
+ return blink::mojom::PreferredColorScheme::kDark;
+ case ui::NativeTheme::PreferredColorScheme::kLight:
+ return blink::mojom::PreferredColorScheme::kLight;
+ }
+
+ NOTREACHED();
+}
+
+// From chrome/browser/chrome_content_browser_client.cc
+// Returns true if preferred color scheme is modified based on at least one of
+// the following -
+// |url| - Last committed url.
+// |native_theme| - For other platforms based on native theme scheme.
+bool UpdatePreferredColorScheme(blink::web_pref::WebPreferences* web_prefs,
+ const GURL& url,
+ const ui::NativeTheme* native_theme) {
+ auto old_preferred_color_scheme = web_prefs->preferred_color_scheme;
+
+ // Update based on native theme scheme.
+ web_prefs->preferred_color_scheme =
+ ToBlinkPreferredColorScheme(native_theme->GetPreferredColorScheme());
+
+ // Force a light preferred color scheme on certain URLs if kWebUIDarkMode is
+ // disabled; some of the UI is not yet correctly themed.
+ if (!base::FeatureList::IsEnabled(features::kWebUIDarkMode)) {
+ // Update based on last committed url.
+ bool force_light = url.SchemeIs(content::kChromeUIScheme);
+ if (!force_light) {
+ force_light = url.SchemeIs(extensions::kExtensionScheme) &&
+ url.host_piece() == extension_misc::kPdfExtensionId;
+ }
+ if (force_light) {
+ web_prefs->preferred_color_scheme =
+ blink::mojom::PreferredColorScheme::kLight;
+ }
+ }
+
+ return old_preferred_color_scheme != web_prefs->preferred_color_scheme;
+}
+
+} // namespace
+
+void SetCommandLinePrefDefaults(CommandLinePrefStore* prefs) {
+ const base::CommandLine* command_line =
+ base::CommandLine::ForCurrentProcess();
+
+ if (command_line->HasSwitch(switches::kDefaultEncoding)) {
+ SetString(prefs, prefs::kDefaultCharset,
+ command_line->GetSwitchValueASCII(switches::kDefaultEncoding));
+ }
+
+ if (command_line->HasSwitch(switches::kDisableJavascriptDomPaste)) {
+ SetBool(prefs, prefs::kWebKitDomPasteEnabled, false);
+ }
+ if (command_line->HasSwitch(switches::kDisableImageLoading)) {
+ SetBool(prefs, prefs::kWebKitLoadsImagesAutomatically, false);
+ }
+ if (command_line->HasSwitch(switches::kDisableTabToLinks)) {
+ SetBool(prefs, prefs::kWebkitTabsToLinks, false);
+ }
+}
+
+void SetDefaultPrefs(blink::web_pref::WebPreferences& web) {
+ const base::CommandLine* command_line =
+ base::CommandLine::ForCurrentProcess();
+
+ web.javascript_enabled =
+ !command_line->HasSwitch(switches::kDisableJavascript);
+ web.allow_scripts_to_close_windows =
+ !command_line->HasSwitch(switches::kDisableJavascriptCloseWindows);
+ web.javascript_can_access_clipboard =
+ !command_line->HasSwitch(switches::kDisableJavascriptAccessClipboard);
+ web.allow_universal_access_from_file_urls =
+ command_line->HasSwitch(switches::kAllowUniversalAccessFromFileUrls);
+ web.shrinks_standalone_images_to_fit =
+ command_line->HasSwitch(switches::kImageShrinkStandaloneToFit);
+ web.text_areas_are_resizable =
+ !command_line->HasSwitch(switches::kDisableTextAreaResize);
+}
+
+// Helper macro for setting a WebPreferences variable based on the value of a
+// CefBrowserSettings variable.
+#define SET_STATE(cef_var, web_var) \
+ if (cef_var == STATE_ENABLED) \
+ web_var = true; \
+ else if (cef_var == STATE_DISABLED) \
+ web_var = false;
+
+void SetCefPrefs(const CefBrowserSettings& cef,
+ blink::web_pref::WebPreferences& web) {
+ if (cef.standard_font_family.length > 0) {
+ web.standard_font_family_map[blink::web_pref::kCommonScript] =
+ CefString(&cef.standard_font_family);
+ }
+ if (cef.fixed_font_family.length > 0) {
+ web.fixed_font_family_map[blink::web_pref::kCommonScript] =
+ CefString(&cef.fixed_font_family);
+ }
+ if (cef.serif_font_family.length > 0) {
+ web.serif_font_family_map[blink::web_pref::kCommonScript] =
+ CefString(&cef.serif_font_family);
+ }
+ if (cef.sans_serif_font_family.length > 0) {
+ web.sans_serif_font_family_map[blink::web_pref::kCommonScript] =
+ CefString(&cef.sans_serif_font_family);
+ }
+ if (cef.cursive_font_family.length > 0) {
+ web.cursive_font_family_map[blink::web_pref::kCommonScript] =
+ CefString(&cef.cursive_font_family);
+ }
+ if (cef.fantasy_font_family.length > 0) {
+ web.fantasy_font_family_map[blink::web_pref::kCommonScript] =
+ CefString(&cef.fantasy_font_family);
+ }
+
+ if (cef.default_font_size > 0) {
+ web.default_font_size = cef.default_font_size;
+ }
+ if (cef.default_fixed_font_size > 0) {
+ web.default_fixed_font_size = cef.default_fixed_font_size;
+ }
+ if (cef.minimum_font_size > 0) {
+ web.minimum_font_size = cef.minimum_font_size;
+ }
+ if (cef.minimum_logical_font_size > 0) {
+ web.minimum_logical_font_size = cef.minimum_logical_font_size;
+ }
+
+ if (cef.default_encoding.length > 0) {
+ web.default_encoding = CefString(&cef.default_encoding);
+ }
+
+ SET_STATE(cef.remote_fonts, web.remote_fonts_enabled);
+ SET_STATE(cef.javascript, web.javascript_enabled);
+ SET_STATE(cef.javascript_close_windows, web.allow_scripts_to_close_windows);
+ SET_STATE(cef.javascript_access_clipboard,
+ web.javascript_can_access_clipboard);
+ SET_STATE(cef.javascript_dom_paste, web.dom_paste_enabled);
+ SET_STATE(cef.image_loading, web.loads_images_automatically);
+ SET_STATE(cef.image_shrink_standalone_to_fit,
+ web.shrinks_standalone_images_to_fit);
+ SET_STATE(cef.text_area_resize, web.text_areas_are_resizable);
+ SET_STATE(cef.tab_to_links, web.tabs_to_links);
+ SET_STATE(cef.local_storage, web.local_storage_enabled);
+ SET_STATE(cef.databases, web.databases_enabled);
+
+ // Never explicitly enable GPU-related functions in this method because the
+ // GPU blacklist is not being checked here.
+ if (cef.webgl == STATE_DISABLED) {
+ web.webgl1_enabled = false;
+ web.webgl2_enabled = false;
+ }
+}
+
+void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry,
+ const std::string& locale) {
+ PrefsTabHelper::RegisterProfilePrefs(registry, locale);
+ RegisterAnimationPolicyPrefs(registry);
+
+ // From chrome/browser/ui/browser_ui_prefs.cc RegisterBrowserUserPrefs.
+ registry->RegisterBooleanPref(
+ prefs::kEnableDoNotTrack, false,
+ user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+ registry->RegisterBooleanPref(prefs::kCaretBrowsingEnabled, false);
+
+ registry->RegisterStringPref(prefs::kWebRTCIPHandlingPolicy,
+ blink::kWebRTCIPHandlingDefault);
+ registry->RegisterStringPref(prefs::kWebRTCUDPPortRange, std::string());
+
+#if !BUILDFLAG(IS_MAC)
+ registry->RegisterBooleanPref(prefs::kFullscreenAllowed, true);
+#endif
+
+ // From ChromeContentBrowserClient::RegisterProfilePrefs.
+ registry->RegisterBooleanPref(prefs::kDisable3DAPIs, false);
+ registry->RegisterBooleanPref(prefs::kEnableHyperlinkAuditing, true);
+
+ // From Profile::RegisterProfilePrefs.
+ registry->RegisterDictionaryPref(prefs::kPartitionDefaultZoomLevel);
+ registry->RegisterDictionaryPref(prefs::kPartitionPerHostZoomLevels);
+}
+
+void PopulateWebPreferences(content::RenderViewHost* rvh,
+ blink::web_pref::WebPreferences& web,
+ SkColor& base_background_color) {
+ REQUIRE_ALLOY_RUNTIME();
+ CefRefPtr<AlloyBrowserHostImpl> browser = static_cast<AlloyBrowserHostImpl*>(
+ extensions::GetOwnerBrowserForHost(rvh, nullptr).get());
+
+ // Set defaults for preferences that are not handled by PrefService.
+ SetDefaultPrefs(web);
+
+ // Set preferences based on the context's PrefService.
+ if (browser) {
+ auto profile = Profile::FromBrowserContext(
+ browser->web_contents()->GetBrowserContext());
+ SetChromePrefs(profile, web);
+ }
+
+ auto* native_theme = ui::NativeTheme::GetInstanceForWeb();
+ switch (native_theme->GetPreferredColorScheme()) {
+ case ui::NativeTheme::PreferredColorScheme::kDark:
+ web.preferred_color_scheme = blink::mojom::PreferredColorScheme::kDark;
+ break;
+ case ui::NativeTheme::PreferredColorScheme::kLight:
+ web.preferred_color_scheme = blink::mojom::PreferredColorScheme::kLight;
+ break;
+ }
+
+ switch (native_theme->GetPreferredContrast()) {
+ case ui::NativeTheme::PreferredContrast::kNoPreference:
+ web.preferred_contrast = blink::mojom::PreferredContrast::kNoPreference;
+ break;
+ case ui::NativeTheme::PreferredContrast::kMore:
+ web.preferred_contrast = blink::mojom::PreferredContrast::kMore;
+ break;
+ case ui::NativeTheme::PreferredContrast::kLess:
+ web.preferred_contrast = blink::mojom::PreferredContrast::kLess;
+ break;
+ case ui::NativeTheme::PreferredContrast::kCustom:
+ web.preferred_contrast = blink::mojom::PreferredContrast::kCustom;
+ break;
+ }
+
+ auto web_contents = content::WebContents::FromRenderViewHost(rvh);
+ UpdatePreferredColorScheme(
+ &web,
+ web_contents->GetPrimaryMainFrame()->GetSiteInstance()->GetSiteURL(),
+ native_theme);
+
+ // Set preferences based on the extension.
+ SetExtensionPrefs(web_contents, rvh, web);
+
+ if (browser) {
+ // Set preferences based on CefBrowserSettings.
+ SetCefPrefs(browser->settings(), web);
+
+ web.picture_in_picture_enabled = browser->IsPictureInPictureSupported();
+
+ // Set the background color for the WebView.
+ base_background_color = browser->GetBackgroundColor();
+ } else {
+ // We don't know for sure that the browser will be windowless but assume
+ // that the global windowless state is likely to be accurate.
+ base_background_color =
+ CefContext::Get()->GetBackgroundColor(nullptr, STATE_DEFAULT);
+ }
+}
+
+bool PopulateWebPreferencesAfterNavigation(
+ content::WebContents* web_contents,
+ blink::web_pref::WebPreferences& web) {
+ auto* native_theme = ui::NativeTheme::GetInstanceForWeb();
+ return UpdatePreferredColorScheme(&web, web_contents->GetLastCommittedURL(),
+ native_theme);
+}
+
+} // namespace renderer_prefs
diff --git a/libcef/browser/prefs/renderer_prefs.h b/libcef/browser/prefs/renderer_prefs.h
new file mode 100644
index 00000000..7222d6ec
--- /dev/null
+++ b/libcef/browser/prefs/renderer_prefs.h
@@ -0,0 +1,61 @@
+// Copyright (c) 2010 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_PREFS_RENDERER_PREFS_H_
+#define CEF_LIBCEF_BROWSER_PREFS_RENDERER_PREFS_H_
+#pragma once
+
+#include "include/internal/cef_types_wrappers.h"
+
+#include "third_party/skia/include/core/SkColor.h"
+
+class CommandLinePrefStore;
+
+namespace blink {
+namespace web_pref {
+struct WebPreferences;
+}
+} // namespace blink
+
+namespace content {
+class RenderViewHost;
+class WebContents;
+} // namespace content
+
+namespace user_prefs {
+class PrefRegistrySyncable;
+}
+
+namespace renderer_prefs {
+
+// Register additional renderer-related preferences.
+void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry,
+ const std::string& locale);
+
+// Set default values based on CEF command-line flags for preferences that are
+// available via the PrefService. Chromium command-line flags should not exist
+// for these preferences.
+void SetCommandLinePrefDefaults(CommandLinePrefStore* prefs);
+
+// Set default values based on CEF command-line flags for preferences that are
+// not available via the PrefService. Chromium command-line flags should not
+// exist for these preferences.
+void SetDefaultPrefs(blink::web_pref::WebPreferences& web);
+
+// Set preferences based on CefBrowserSettings.
+void SetCefPrefs(const CefBrowserSettings& cef,
+ blink::web_pref::WebPreferences& web);
+
+// Populate WebPreferences based on a combination of command-line values,
+// PrefService and CefBrowserSettings.
+void PopulateWebPreferences(content::RenderViewHost* rvh,
+ blink::web_pref::WebPreferences& web,
+ SkColor& base_background_color);
+bool PopulateWebPreferencesAfterNavigation(
+ content::WebContents* web_contents,
+ blink::web_pref::WebPreferences& web);
+
+} // namespace renderer_prefs
+
+#endif // CEF_LIBCEF_BROWSER_PREFS_RENDERER_PREFS_H_
diff --git a/libcef/browser/print_settings_impl.cc b/libcef/browser/print_settings_impl.cc
new file mode 100644
index 00000000..b789c8ff
--- /dev/null
+++ b/libcef/browser/print_settings_impl.cc
@@ -0,0 +1,165 @@
+// Copyright (c) 2014 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "libcef/browser/print_settings_impl.h"
+
+#include "base/logging.h"
+
+#include "printing/mojom/print.mojom.h"
+
+CefPrintSettingsImpl::CefPrintSettingsImpl(
+ std::unique_ptr<printing::PrintSettings> settings,
+ bool read_only)
+ : CefValueBase<CefPrintSettings, printing::PrintSettings>(
+ settings.release(),
+ nullptr,
+ kOwnerWillDelete,
+ read_only,
+ nullptr) {}
+
+bool CefPrintSettingsImpl::IsValid() {
+ return !detached();
+}
+
+bool CefPrintSettingsImpl::IsReadOnly() {
+ return read_only();
+}
+
+void CefPrintSettingsImpl::SetOrientation(bool landscape) {
+ CEF_VALUE_VERIFY_RETURN_VOID(true);
+ mutable_value()->SetOrientation(landscape);
+}
+
+bool CefPrintSettingsImpl::IsLandscape() {
+ CEF_VALUE_VERIFY_RETURN(false, false);
+ return const_value().landscape();
+}
+
+void CefPrintSettingsImpl::SetPrinterPrintableArea(
+ const CefSize& physical_size_device_units,
+ const CefRect& printable_area_device_units,
+ bool landscape_needs_flip) {
+ CEF_VALUE_VERIFY_RETURN_VOID(true);
+ gfx::Size size(physical_size_device_units.width,
+ physical_size_device_units.height);
+ gfx::Rect rect(printable_area_device_units.x, printable_area_device_units.y,
+ printable_area_device_units.width,
+ printable_area_device_units.height);
+ mutable_value()->SetPrinterPrintableArea(size, rect, landscape_needs_flip);
+}
+
+void CefPrintSettingsImpl::SetDeviceName(const CefString& name) {
+ CEF_VALUE_VERIFY_RETURN_VOID(true);
+ mutable_value()->set_device_name(name.ToString16());
+}
+
+CefString CefPrintSettingsImpl::GetDeviceName() {
+ CEF_VALUE_VERIFY_RETURN(false, CefString());
+ return const_value().device_name();
+}
+
+void CefPrintSettingsImpl::SetDPI(int dpi) {
+ CEF_VALUE_VERIFY_RETURN_VOID(true);
+ mutable_value()->set_dpi(dpi);
+}
+
+int CefPrintSettingsImpl::GetDPI() {
+ CEF_VALUE_VERIFY_RETURN(false, 0);
+ return const_value().dpi();
+}
+
+void CefPrintSettingsImpl::SetPageRanges(const PageRangeList& ranges) {
+ CEF_VALUE_VERIFY_RETURN_VOID(true);
+ printing::PageRanges page_ranges;
+ PageRangeList::const_iterator it = ranges.begin();
+ for (; it != ranges.end(); ++it) {
+ const CefRange& cef_range = *it;
+ printing::PageRange range;
+ range.from = cef_range.from;
+ range.to = cef_range.to;
+ page_ranges.push_back(range);
+ }
+ mutable_value()->set_ranges(page_ranges);
+}
+
+size_t CefPrintSettingsImpl::GetPageRangesCount() {
+ CEF_VALUE_VERIFY_RETURN(false, 0);
+ return const_value().ranges().size();
+}
+
+void CefPrintSettingsImpl::GetPageRanges(PageRangeList& ranges) {
+ CEF_VALUE_VERIFY_RETURN_VOID(false);
+ if (!ranges.empty()) {
+ ranges.clear();
+ }
+ const printing::PageRanges& page_ranges = const_value().ranges();
+ printing::PageRanges::const_iterator it = page_ranges.begin();
+ for (; it != page_ranges.end(); ++it) {
+ const printing::PageRange& range = *it;
+ ranges.push_back(CefRange(range.from, range.to));
+ }
+}
+
+void CefPrintSettingsImpl::SetSelectionOnly(bool selection_only) {
+ CEF_VALUE_VERIFY_RETURN_VOID(true);
+ mutable_value()->set_selection_only(selection_only);
+}
+
+bool CefPrintSettingsImpl::IsSelectionOnly() {
+ CEF_VALUE_VERIFY_RETURN(false, false);
+ return const_value().selection_only();
+}
+
+void CefPrintSettingsImpl::SetCollate(bool collate) {
+ CEF_VALUE_VERIFY_RETURN_VOID(true);
+ mutable_value()->set_collate(collate);
+}
+
+bool CefPrintSettingsImpl::WillCollate() {
+ CEF_VALUE_VERIFY_RETURN(false, false);
+ return const_value().collate();
+}
+
+void CefPrintSettingsImpl::SetColorModel(ColorModel model) {
+ CEF_VALUE_VERIFY_RETURN_VOID(true);
+ mutable_value()->set_color(static_cast<printing::mojom::ColorModel>(model));
+}
+
+CefPrintSettings::ColorModel CefPrintSettingsImpl::GetColorModel() {
+ CEF_VALUE_VERIFY_RETURN(false, COLOR_MODEL_UNKNOWN);
+ return static_cast<ColorModel>(const_value().color());
+}
+
+void CefPrintSettingsImpl::SetCopies(int copies) {
+ CEF_VALUE_VERIFY_RETURN_VOID(true);
+ mutable_value()->set_copies(copies);
+}
+
+int CefPrintSettingsImpl::GetCopies() {
+ CEF_VALUE_VERIFY_RETURN(false, false);
+ return const_value().copies();
+}
+
+void CefPrintSettingsImpl::SetDuplexMode(DuplexMode mode) {
+ CEF_VALUE_VERIFY_RETURN_VOID(true);
+ mutable_value()->set_duplex_mode(
+ static_cast<printing::mojom::DuplexMode>(mode));
+}
+
+CefPrintSettings::DuplexMode CefPrintSettingsImpl::GetDuplexMode() {
+ CEF_VALUE_VERIFY_RETURN(false, DUPLEX_MODE_UNKNOWN);
+ return static_cast<DuplexMode>(const_value().duplex_mode());
+}
+
+std::unique_ptr<printing::PrintSettings> CefPrintSettingsImpl::TakeOwnership() {
+ return base::WrapUnique(Detach(nullptr));
+}
+
+// CefPrintSettings implementation.
+
+// static
+CefRefPtr<CefPrintSettings> CefPrintSettings::Create() {
+ return new CefPrintSettingsImpl(std::make_unique<printing::PrintSettings>(),
+ false);
+}
diff --git a/libcef/browser/print_settings_impl.h b/libcef/browser/print_settings_impl.h
new file mode 100644
index 00000000..2bc356b8
--- /dev/null
+++ b/libcef/browser/print_settings_impl.h
@@ -0,0 +1,53 @@
+// Copyright (c) 2014 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_PRINT_SETTINGS_IMPL_H_
+#define CEF_LIBCEF_BROWSER_PRINT_SETTINGS_IMPL_H_
+#pragma once
+
+#include "include/cef_print_settings.h"
+#include "libcef/common/value_base.h"
+
+#include "printing/print_settings.h"
+
+// CefPrintSettings implementation
+class CefPrintSettingsImpl
+ : public CefValueBase<CefPrintSettings, printing::PrintSettings> {
+ public:
+ CefPrintSettingsImpl(std::unique_ptr<printing::PrintSettings> settings,
+ bool read_only);
+
+ CefPrintSettingsImpl(const CefPrintSettingsImpl&) = delete;
+ CefPrintSettingsImpl& operator=(const CefPrintSettingsImpl&) = delete;
+
+ // CefPrintSettings methods.
+ bool IsValid() override;
+ bool IsReadOnly() override;
+ void SetOrientation(bool landscape) override;
+ bool IsLandscape() override;
+ void SetPrinterPrintableArea(const CefSize& physical_size_device_units,
+ const CefRect& printable_area_device_units,
+ bool landscape_needs_flip) override;
+ void SetDeviceName(const CefString& name) override;
+ CefString GetDeviceName() override;
+ void SetDPI(int dpi) override;
+ int GetDPI() override;
+ void SetPageRanges(const PageRangeList& ranges) override;
+ size_t GetPageRangesCount() override;
+ void GetPageRanges(PageRangeList& ranges) override;
+ void SetSelectionOnly(bool selection_only) override;
+ bool IsSelectionOnly() override;
+ void SetCollate(bool collate) override;
+ bool WillCollate() override;
+ void SetColorModel(ColorModel model) override;
+ ColorModel GetColorModel() override;
+ void SetCopies(int copies) override;
+ int GetCopies() override;
+ void SetDuplexMode(DuplexMode mode) override;
+ DuplexMode GetDuplexMode() override;
+
+ [[nodiscard]] std::unique_ptr<printing::PrintSettings> TakeOwnership();
+};
+
+#endif // CEF_LIBCEF_BROWSER_PRINT_SETTINGS_IMPL_H_
diff --git a/libcef/browser/printing/print_dialog_linux.cc b/libcef/browser/printing/print_dialog_linux.cc
new file mode 100644
index 00000000..262391db
--- /dev/null
+++ b/libcef/browser/printing/print_dialog_linux.cc
@@ -0,0 +1,340 @@
+// Copyright (c) 2014 The Chromium Embedded Framework Authors.
+// Portions copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/printing/print_dialog_linux.h"
+
+#include <string>
+#include <vector>
+
+#include "libcef/browser/extensions/browser_extensions_util.h"
+#include "libcef/browser/print_settings_impl.h"
+#include "libcef/browser/thread_util.h"
+#include "libcef/common/app_manager.h"
+#include "libcef/common/frame_util.h"
+
+#include "base/files/file_util.h"
+#include "base/functional/bind.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "content/public/browser/global_routing_id.h"
+#include "printing/metafile.h"
+#include "printing/mojom/print.mojom-shared.h"
+#include "printing/print_job_constants.h"
+#include "printing/print_settings.h"
+
+using content::BrowserThread;
+using printing::PageRanges;
+using printing::PrintSettings;
+
+namespace {
+
+CefRefPtr<CefBrowserHostBase> GetBrowserForContext(
+ printing::PrintingContextLinux* context) {
+ // The print preview dialog won't have a valid child ID.
+ if (!frame_util::IsValidChildId(context->render_process_id())) {
+ return nullptr;
+ }
+
+ return extensions::GetOwnerBrowserForGlobalId(
+ frame_util::MakeGlobalId(context->render_process_id(),
+ context->render_frame_id()),
+ nullptr);
+}
+
+CefRefPtr<CefPrintHandler> GetPrintHandlerForBrowser(
+ CefRefPtr<CefBrowserHostBase> browser) {
+ if (browser) {
+ if (auto client = browser->GetClient()) {
+ return client->GetPrintHandler();
+ }
+ }
+ return nullptr;
+}
+
+} // namespace
+
+class CefPrintDialogCallbackImpl : public CefPrintDialogCallback {
+ public:
+ explicit CefPrintDialogCallbackImpl(CefRefPtr<CefPrintDialogLinux> dialog)
+ : dialog_(dialog) {}
+
+ CefPrintDialogCallbackImpl(const CefPrintDialogCallbackImpl&) = delete;
+ CefPrintDialogCallbackImpl& operator=(const CefPrintDialogCallbackImpl&) =
+ delete;
+
+ void Continue(CefRefPtr<CefPrintSettings> settings) override {
+ if (CEF_CURRENTLY_ON_UIT()) {
+ if (dialog_.get()) {
+ dialog_->OnPrintContinue(settings);
+ dialog_ = nullptr;
+ }
+ } else {
+ CEF_POST_TASK(CEF_UIT,
+ base::BindOnce(&CefPrintDialogCallbackImpl::Continue, this,
+ settings));
+ }
+ }
+
+ void Cancel() override {
+ if (CEF_CURRENTLY_ON_UIT()) {
+ if (dialog_.get()) {
+ dialog_->OnPrintCancel();
+ dialog_ = nullptr;
+ }
+ } else {
+ CEF_POST_TASK(CEF_UIT,
+ base::BindOnce(&CefPrintDialogCallbackImpl::Cancel, this));
+ }
+ }
+
+ void Disconnect() { dialog_ = nullptr; }
+
+ private:
+ CefRefPtr<CefPrintDialogLinux> dialog_;
+
+ IMPLEMENT_REFCOUNTING(CefPrintDialogCallbackImpl);
+};
+
+class CefPrintJobCallbackImpl : public CefPrintJobCallback {
+ public:
+ explicit CefPrintJobCallbackImpl(CefRefPtr<CefPrintDialogLinux> dialog)
+ : dialog_(dialog) {}
+
+ CefPrintJobCallbackImpl(const CefPrintJobCallbackImpl&) = delete;
+ CefPrintJobCallbackImpl& operator=(const CefPrintJobCallbackImpl&) = delete;
+
+ void Continue() override {
+ if (CEF_CURRENTLY_ON_UIT()) {
+ if (dialog_.get()) {
+ dialog_->OnJobCompleted();
+ dialog_ = nullptr;
+ }
+ } else {
+ CEF_POST_TASK(CEF_UIT,
+ base::BindOnce(&CefPrintJobCallbackImpl::Continue, this));
+ }
+ }
+
+ void Disconnect() { dialog_ = nullptr; }
+
+ private:
+ CefRefPtr<CefPrintDialogLinux> dialog_;
+
+ IMPLEMENT_REFCOUNTING(CefPrintJobCallbackImpl);
+};
+
+CefPrintingContextLinuxDelegate::CefPrintingContextLinuxDelegate() = default;
+
+printing::PrintDialogLinuxInterface*
+CefPrintingContextLinuxDelegate::CreatePrintDialog(
+ printing::PrintingContextLinux* context) {
+ CEF_REQUIRE_UIT();
+
+ printing::PrintDialogLinuxInterface* interface = nullptr;
+
+ auto browser = GetBrowserForContext(context);
+ if (!browser) {
+ LOG(ERROR) << "No associated browser in CreatePrintDialog; using default "
+ "printing implementation.";
+ }
+
+ auto handler = GetPrintHandlerForBrowser(browser);
+ if (!handler) {
+ if (default_delegate_) {
+ interface = default_delegate_->CreatePrintDialog(context);
+ DCHECK(interface);
+ }
+ } else {
+ interface = new CefPrintDialogLinux(context, browser, handler);
+ }
+
+ if (!interface) {
+ LOG(ERROR) << "Null interface in CreatePrintDialog; printing will fail.";
+ }
+
+ return interface;
+}
+
+gfx::Size CefPrintingContextLinuxDelegate::GetPdfPaperSize(
+ printing::PrintingContextLinux* context) {
+ CEF_REQUIRE_UIT();
+
+ gfx::Size size;
+
+ auto browser = GetBrowserForContext(context);
+ if (!browser) {
+ LOG(ERROR) << "No associated browser in GetPdfPaperSize; using default "
+ "printing implementation.";
+ }
+
+ auto handler = GetPrintHandlerForBrowser(browser);
+ if (!handler) {
+ if (default_delegate_) {
+ size = default_delegate_->GetPdfPaperSize(context);
+ DCHECK(!size.IsEmpty());
+ }
+ } else {
+ const printing::PrintSettings& settings = context->settings();
+ CefSize cef_size = handler->GetPdfPaperSize(
+ browser.get(), settings.device_units_per_inch());
+ size.SetSize(cef_size.width, cef_size.height);
+ }
+
+ if (size.IsEmpty()) {
+ LOG(ERROR) << "Empty size value returned in GetPdfPaperSize; PDF printing "
+ "will fail.";
+ }
+ return size;
+}
+
+void CefPrintingContextLinuxDelegate::SetDefaultDelegate(
+ ui::PrintingContextLinuxDelegate* delegate) {
+ DCHECK(!default_delegate_);
+ default_delegate_ = delegate;
+}
+
+CefPrintDialogLinux::CefPrintDialogLinux(PrintingContextLinux* context,
+ CefRefPtr<CefBrowserHostBase> browser,
+ CefRefPtr<CefPrintHandler> handler)
+ : context_(context), browser_(browser), handler_(handler) {
+ CEF_REQUIRE_UIT();
+ DCHECK(context_);
+ DCHECK(browser_);
+ DCHECK(handler_);
+
+ // Paired with the ReleaseDialog() call.
+ AddRef();
+
+ handler->OnPrintStart(browser_.get());
+}
+
+CefPrintDialogLinux::~CefPrintDialogLinux() {
+ // It's not safe to dereference |context_| during the destruction of this
+ // object because the PrintJobWorker which owns |context_| may already have
+ // been deleted.
+ CEF_REQUIRE_UIT();
+ handler_->OnPrintReset(browser_.get());
+}
+
+void CefPrintDialogLinux::UseDefaultSettings() {
+ UpdateSettings(std::make_unique<PrintSettings>(), true);
+}
+
+void CefPrintDialogLinux::UpdateSettings(
+ std::unique_ptr<PrintSettings> settings) {
+ UpdateSettings(std::move(settings), false);
+}
+
+void CefPrintDialogLinux::ShowDialog(
+ gfx::NativeView parent_view,
+ bool has_selection,
+ PrintingContextLinux::PrintSettingsCallback callback) {
+ CEF_REQUIRE_UIT();
+
+ callback_ = std::move(callback);
+
+ CefRefPtr<CefPrintDialogCallbackImpl> callback_impl(
+ new CefPrintDialogCallbackImpl(this));
+
+ if (!handler_->OnPrintDialog(browser_.get(), has_selection,
+ callback_impl.get())) {
+ callback_impl->Disconnect();
+ OnPrintCancel();
+ }
+}
+
+void CefPrintDialogLinux::PrintDocument(
+ const printing::MetafilePlayer& metafile,
+ const std::u16string& document_name) {
+ // This runs on the print worker thread, does not block the UI thread.
+ DCHECK(!CEF_CURRENTLY_ON_UIT());
+
+ // The document printing tasks can outlive the PrintingContext that created
+ // this dialog.
+ AddRef();
+
+ bool success = base::CreateTemporaryFile(&path_to_pdf_);
+
+ if (success) {
+ base::File file;
+ file.Initialize(path_to_pdf_,
+ base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
+ success = metafile.SaveTo(&file);
+ file.Close();
+ if (!success) {
+ base::DeleteFile(path_to_pdf_);
+ }
+ }
+
+ if (!success) {
+ LOG(ERROR) << "Saving metafile failed";
+ // Matches AddRef() above.
+ Release();
+ return;
+ }
+
+ // No errors, continue printing.
+ CEF_POST_TASK(
+ CEF_UIT, base::BindOnce(&CefPrintDialogLinux::SendDocumentToPrinter, this,
+ document_name));
+}
+
+void CefPrintDialogLinux::ReleaseDialog() {
+ context_ = nullptr;
+ Release();
+}
+
+bool CefPrintDialogLinux::UpdateSettings(
+ std::unique_ptr<PrintSettings> settings,
+ bool get_defaults) {
+ CEF_REQUIRE_UIT();
+
+ CefRefPtr<CefPrintSettingsImpl> settings_impl(
+ new CefPrintSettingsImpl(std::move(settings), false));
+ handler_->OnPrintSettings(browser_.get(), settings_impl.get(), get_defaults);
+
+ context_->InitWithSettings(settings_impl->TakeOwnership());
+ return true;
+}
+
+void CefPrintDialogLinux::SendDocumentToPrinter(
+ const std::u16string& document_name) {
+ CEF_REQUIRE_UIT();
+
+ if (!handler_.get()) {
+ OnJobCompleted();
+ return;
+ }
+
+ CefRefPtr<CefPrintJobCallbackImpl> callback_impl(
+ new CefPrintJobCallbackImpl(this));
+
+ if (!handler_->OnPrintJob(browser_.get(), document_name, path_to_pdf_.value(),
+ callback_impl.get())) {
+ callback_impl->Disconnect();
+ OnJobCompleted();
+ }
+}
+
+void CefPrintDialogLinux::OnPrintContinue(
+ CefRefPtr<CefPrintSettings> settings) {
+ CefPrintSettingsImpl* impl =
+ static_cast<CefPrintSettingsImpl*>(settings.get());
+ context_->InitWithSettings(impl->TakeOwnership());
+ std::move(callback_).Run(printing::mojom::ResultCode::kSuccess);
+}
+
+void CefPrintDialogLinux::OnPrintCancel() {
+ std::move(callback_).Run(printing::mojom::ResultCode::kCanceled);
+}
+
+void CefPrintDialogLinux::OnJobCompleted() {
+ CEF_POST_BACKGROUND_TASK(base::GetDeleteFileCallback(path_to_pdf_));
+
+ // Printing finished. Matches AddRef() in PrintDocument();
+ Release();
+}
diff --git a/libcef/browser/printing/print_dialog_linux.h b/libcef/browser/printing/print_dialog_linux.h
new file mode 100644
index 00000000..dd7be26e
--- /dev/null
+++ b/libcef/browser/printing/print_dialog_linux.h
@@ -0,0 +1,106 @@
+// Copyright (c) 2014 The Chromium Embedded Framework Authors.
+// Portions copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef LIBCEF_BROWSER_PRINTING_PRINT_DIALOG_LINUX_H_
+#define LIBCEF_BROWSER_PRINTING_PRINT_DIALOG_LINUX_H_
+
+#include "include/cef_print_handler.h"
+#include "libcef/browser/browser_host_base.h"
+
+#include "base/files/file_path.h"
+#include "base/memory/ref_counted.h"
+#include "base/task/sequenced_task_runner_helpers.h"
+#include "content/public/browser/browser_thread.h"
+#include "printing/print_dialog_linux_interface.h"
+#include "ui/linux/linux_ui.h"
+
+namespace printing {
+class MetafilePlayer;
+class PrintSettings;
+} // namespace printing
+
+using printing::PrintingContextLinux;
+
+class CefPrintingContextLinuxDelegate
+ : public ui::PrintingContextLinuxDelegate {
+ public:
+ CefPrintingContextLinuxDelegate();
+
+ CefPrintingContextLinuxDelegate(const CefPrintingContextLinuxDelegate&) =
+ delete;
+ CefPrintingContextLinuxDelegate& operator=(
+ const CefPrintingContextLinuxDelegate&) = delete;
+
+ printing::PrintDialogLinuxInterface* CreatePrintDialog(
+ printing::PrintingContextLinux* context) override;
+ gfx::Size GetPdfPaperSize(printing::PrintingContextLinux* context) override;
+
+ void SetDefaultDelegate(ui::PrintingContextLinuxDelegate* delegate);
+
+ private:
+ ui::PrintingContextLinuxDelegate* default_delegate_ = nullptr;
+};
+
+// Needs to be freed on the UI thread to clean up its member variables.
+class CefPrintDialogLinux : public printing::PrintDialogLinuxInterface,
+ public base::RefCountedThreadSafe<
+ CefPrintDialogLinux,
+ content::BrowserThread::DeleteOnUIThread> {
+ public:
+ CefPrintDialogLinux(const CefPrintDialogLinux&) = delete;
+ CefPrintDialogLinux& operator=(const CefPrintDialogLinux&) = delete;
+
+ // PrintDialogLinuxInterface implementation.
+ void UseDefaultSettings() override;
+ void UpdateSettings(
+ std::unique_ptr<printing::PrintSettings> settings) override;
+ void ShowDialog(
+ gfx::NativeView parent_view,
+ bool has_selection,
+ PrintingContextLinux::PrintSettingsCallback callback) override;
+ void PrintDocument(const printing::MetafilePlayer& metafile,
+ const std::u16string& document_name) override;
+ void ReleaseDialog() override;
+
+ private:
+ friend class base::DeleteHelper<CefPrintDialogLinux>;
+ friend class base::RefCountedThreadSafe<
+ CefPrintDialogLinux,
+ content::BrowserThread::DeleteOnUIThread>;
+ friend struct content::BrowserThread::DeleteOnThread<
+ content::BrowserThread::UI>;
+ friend class CefPrintDialogCallbackImpl;
+ friend class CefPrintJobCallbackImpl;
+ friend class CefPrintingContextLinuxDelegate;
+
+ CefPrintDialogLinux(PrintingContextLinux* context,
+ CefRefPtr<CefBrowserHostBase> browser,
+ CefRefPtr<CefPrintHandler> handler);
+ ~CefPrintDialogLinux() override;
+
+ bool UpdateSettings(std::unique_ptr<printing::PrintSettings> settings,
+ bool get_defaults);
+
+ // Prints document named |document_name|.
+ void SendDocumentToPrinter(const std::u16string& document_name);
+
+ // Handles print dialog response.
+ void OnPrintContinue(CefRefPtr<CefPrintSettings> settings);
+ void OnPrintCancel();
+
+ // Handles print job response.
+ void OnJobCompleted();
+
+ // Printing dialog callback.
+ PrintingContextLinux::PrintSettingsCallback callback_;
+
+ PrintingContextLinux* context_;
+ CefRefPtr<CefBrowserHostBase> browser_;
+ CefRefPtr<CefPrintHandler> handler_;
+
+ base::FilePath path_to_pdf_;
+};
+
+#endif // LIBCEF_BROWSER_PRINTING_PRINT_DIALOG_LINUX_H_
diff --git a/libcef/browser/printing/print_util.cc b/libcef/browser/printing/print_util.cc
new file mode 100644
index 00000000..c6a1527c
--- /dev/null
+++ b/libcef/browser/printing/print_util.cc
@@ -0,0 +1,149 @@
+// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "libcef/browser/printing/print_util.h"
+
+#include "libcef/browser/thread_util.h"
+
+#include "base/files/file_util.h"
+#include "chrome/browser/printing/print_view_manager.h"
+#include "chrome/browser/printing/print_view_manager_common.h"
+#include "components/printing/browser/print_to_pdf/pdf_print_utils.h"
+
+namespace print_util {
+
+namespace {
+
+// Write the PDF file to disk.
+void SavePdfFile(const CefString& path,
+ CefRefPtr<CefPdfPrintCallback> callback,
+ scoped_refptr<base::RefCountedMemory> data) {
+ CEF_REQUIRE_BLOCKING();
+ DCHECK_GT(data->size(), 0U);
+
+ const bool ok =
+ base::WriteFile(path, reinterpret_cast<const char*>(data->data()),
+ data->size()) == static_cast<int>(data->size());
+
+ if (callback) {
+ CEF_POST_TASK(CEF_UIT,
+ base::BindOnce(&CefPdfPrintCallback::OnPdfPrintFinished,
+ callback, path, ok));
+ }
+}
+
+void OnPDFCreated(const CefString& path,
+ CefRefPtr<CefPdfPrintCallback> callback,
+ print_to_pdf::PdfPrintResult print_result,
+ scoped_refptr<base::RefCountedMemory> data) {
+ if (print_result != print_to_pdf::PdfPrintResult::kPrintSuccess) {
+ LOG(ERROR) << "PrintToPDF failed with error: "
+ << print_to_pdf::PdfPrintResultToString(print_result);
+ callback->OnPdfPrintFinished(CefString(), false);
+ return;
+ }
+
+ // Save the PDF file to disk and then execute the callback.
+ CEF_POST_USER_VISIBLE_TASK(
+ base::BindOnce(&SavePdfFile, path, callback, std::move(data)));
+}
+
+} // namespace
+
+void Print(content::WebContents* web_contents, bool print_preview_disabled) {
+ // Like chrome::Print() but specifying the WebContents.
+ printing::StartPrint(web_contents,
+ /*print_renderer=*/mojo::NullAssociatedRemote(),
+ print_preview_disabled,
+ /*has_selection=*/false);
+}
+
+// Implementation based on PageHandler::PrintToPDF.
+void PrintToPDF(content::WebContents* web_contents,
+ const CefString& path,
+ const CefPdfPrintSettings& settings,
+ CefRefPtr<CefPdfPrintCallback> callback) {
+ const bool display_header_footer = !!settings.display_header_footer;
+
+ // Defaults to no header/footer.
+ absl::optional<std::string> header_template, footer_template;
+ if (display_header_footer) {
+ if (settings.header_template.length > 0) {
+ header_template = CefString(&settings.header_template);
+ }
+ if (settings.footer_template.length > 0) {
+ footer_template = CefString(&settings.footer_template);
+ }
+ }
+
+ // Defaults to 1.0.
+ absl::optional<double> scale;
+ if (settings.scale > 0) {
+ scale = settings.scale;
+ }
+
+ // Defaults to letter size.
+ absl::optional<double> paper_width, paper_height;
+ if (settings.paper_width > 0 && settings.paper_height > 0) {
+ paper_width = settings.paper_width;
+ paper_height = settings.paper_height;
+ }
+
+ // Defaults to kDefaultMarginInInches.
+ absl::optional<double> margin_top, margin_bottom, margin_left, margin_right;
+ if (settings.margin_type == PDF_PRINT_MARGIN_NONE) {
+ margin_top = 0;
+ margin_bottom = 0;
+ margin_left = 0;
+ margin_right = 0;
+ } else if (settings.margin_type == PDF_PRINT_MARGIN_CUSTOM) {
+ if (settings.margin_top >= 0) {
+ margin_top = settings.margin_top;
+ }
+ if (settings.margin_bottom >= 0) {
+ margin_bottom = settings.margin_bottom;
+ }
+ if (settings.margin_left >= 0) {
+ margin_left = settings.margin_left;
+ }
+ if (settings.margin_right >= 0) {
+ margin_right = settings.margin_right;
+ }
+ }
+
+ absl::variant<printing::mojom::PrintPagesParamsPtr, std::string>
+ print_pages_params = print_to_pdf::GetPrintPagesParams(
+ web_contents->GetPrimaryMainFrame()->GetLastCommittedURL(),
+ !!settings.landscape, display_header_footer,
+ !!settings.print_background, scale, paper_width, paper_height,
+ margin_top, margin_bottom, margin_left, margin_right,
+ CefString(&settings.header_template),
+ CefString(&settings.footer_template),
+ !!settings.prefer_css_page_size);
+
+ if (absl::holds_alternative<std::string>(print_pages_params)) {
+ LOG(ERROR) << "PrintToPDF failed with error: "
+ << absl::get<std::string>(print_pages_params);
+ callback->OnPdfPrintFinished(CefString(), false);
+ return;
+ }
+
+ DCHECK(absl::holds_alternative<printing::mojom::PrintPagesParamsPtr>(
+ print_pages_params));
+
+ if (auto* print_manager =
+ printing::PrintViewManager::FromWebContents(web_contents)) {
+ print_manager->PrintToPdf(
+ web_contents->GetPrimaryMainFrame(), CefString(&settings.page_ranges),
+ std::move(absl::get<printing::mojom::PrintPagesParamsPtr>(
+ print_pages_params)),
+ base::BindOnce(&OnPDFCreated, path, callback));
+ return;
+ }
+
+ LOG(ERROR) << "PrintToPDF was not handled.";
+ callback->OnPdfPrintFinished(CefString(), false);
+}
+
+} // namespace print_util
diff --git a/libcef/browser/printing/print_util.h b/libcef/browser/printing/print_util.h
new file mode 100644
index 00000000..fe12ec54
--- /dev/null
+++ b/libcef/browser/printing/print_util.h
@@ -0,0 +1,28 @@
+// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_PRINTING_PRINT_UTIL_H_
+#define CEF_LIBCEF_BROWSER_PRINTING_PRINT_UTIL_H_
+#pragma once
+
+#include "include/cef_browser.h"
+
+namespace content {
+class WebContents;
+}
+
+namespace print_util {
+
+// Called from CefBrowserHostBase::Print.
+void Print(content::WebContents* web_contents, bool print_preview_disabled);
+
+// Called from CefBrowserHostBase::PrintToPDF.
+void PrintToPDF(content::WebContents* web_contents,
+ const CefString& path,
+ const CefPdfPrintSettings& settings,
+ CefRefPtr<CefPdfPrintCallback> callback);
+
+} // namespace print_util
+
+#endif // CEF_LIBCEF_BROWSER_PRINTING_PRINT_UTIL_H_
diff --git a/libcef/browser/process_util_impl.cc b/libcef/browser/process_util_impl.cc
new file mode 100644
index 00000000..31a5fe8d
--- /dev/null
+++ b/libcef/browser/process_util_impl.cc
@@ -0,0 +1,31 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "include/cef_process_util.h"
+#include "libcef/common/command_line_impl.h"
+
+#include "base/logging.h"
+#include "base/notreached.h"
+#include "base/process/launch.h"
+#include "content/public/browser/child_process_launcher_utils.h"
+
+bool CefLaunchProcess(CefRefPtr<CefCommandLine> command_line) {
+ if (!command_line.get()) {
+ NOTREACHED() << "invalid parameter";
+ return false;
+ }
+
+ if (!content::CurrentlyOnProcessLauncherTaskRunner()) {
+ NOTREACHED() << "called on invalid thread";
+ return false;
+ }
+
+ CefCommandLineImpl* impl =
+ static_cast<CefCommandLineImpl*>(command_line.get());
+
+ CefValueController::AutoLock lock_scope(impl->controller());
+
+ base::LaunchOptions options;
+ return base::LaunchProcess(impl->command_line(), options).IsValid();
+}
diff --git a/libcef/browser/request_context_handler_map.cc b/libcef/browser/request_context_handler_map.cc
new file mode 100644
index 00000000..eca2290e
--- /dev/null
+++ b/libcef/browser/request_context_handler_map.cc
@@ -0,0 +1,51 @@
+// Copyright (c) 2019 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "libcef/browser/request_context_handler_map.h"
+
+#include "libcef/common/frame_util.h"
+
+CefRequestContextHandlerMap::CefRequestContextHandlerMap() = default;
+CefRequestContextHandlerMap::~CefRequestContextHandlerMap() = default;
+
+void CefRequestContextHandlerMap::AddHandler(
+ const content::GlobalRenderFrameHostId& global_id,
+ CefRefPtr<CefRequestContextHandler> handler) {
+ DCHECK(frame_util::IsValidGlobalId(global_id));
+ DCHECK(handler);
+
+ render_id_handler_map_.insert(std::make_pair(global_id, handler));
+}
+
+void CefRequestContextHandlerMap::RemoveHandler(
+ const content::GlobalRenderFrameHostId& global_id) {
+ DCHECK(frame_util::IsValidGlobalId(global_id));
+
+ auto it1 = render_id_handler_map_.find(global_id);
+ if (it1 != render_id_handler_map_.end()) {
+ render_id_handler_map_.erase(it1);
+ }
+}
+
+CefRefPtr<CefRequestContextHandler> CefRequestContextHandlerMap::GetHandler(
+ const content::GlobalRenderFrameHostId& global_id,
+ bool require_frame_match) const {
+ if (frame_util::IsValidGlobalId(global_id)) {
+ const auto it1 = render_id_handler_map_.find(global_id);
+ if (it1 != render_id_handler_map_.end()) {
+ return it1->second;
+ }
+ }
+
+ if (frame_util::IsValidChildId(global_id.child_id) && !require_frame_match) {
+ // Choose an arbitrary handler for the same process.
+ for (auto& kv : render_id_handler_map_) {
+ if (kv.first.child_id == global_id.child_id) {
+ return kv.second;
+ }
+ }
+ }
+
+ return nullptr;
+}
diff --git a/libcef/browser/request_context_handler_map.h b/libcef/browser/request_context_handler_map.h
new file mode 100644
index 00000000..8f2422dc
--- /dev/null
+++ b/libcef/browser/request_context_handler_map.h
@@ -0,0 +1,52 @@
+// Copyright (c) 2019 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_REQUEST_CONTEXT_HANDLER_MAP_
+#define CEF_LIBCEF_BROWSER_REQUEST_CONTEXT_HANDLER_MAP_
+#pragma once
+
+#include <map>
+
+#include "include/cef_request_context.h"
+#include "include/cef_request_context_handler.h"
+
+#include "content/public/browser/global_routing_id.h"
+
+// Tracks CefRequestContextHandler associations on a single thread.
+class CefRequestContextHandlerMap {
+ public:
+ CefRequestContextHandlerMap();
+
+ CefRequestContextHandlerMap(const CefRequestContextHandlerMap&) = delete;
+ CefRequestContextHandlerMap& operator=(const CefRequestContextHandlerMap&) =
+ delete;
+
+ ~CefRequestContextHandlerMap();
+
+ // Keep track of handlers associated with specific frames. This information
+ // originates from frame create/delete notifications in
+ // CefBrowserContentsDelegate or CefMimeHandlerViewGuestDelegate which are
+ // forwarded via CefRequestContextImpl and CefBrowserContext.
+ void AddHandler(const content::GlobalRenderFrameHostId& global_id,
+ CefRefPtr<CefRequestContextHandler> handler);
+ void RemoveHandler(const content::GlobalRenderFrameHostId& global_id);
+
+ // Returns the handler that matches the specified IDs. If
+ // |require_frame_match| is true only exact matches will be returned. If
+ // |require_frame_match| is false, and there is not an exact match, then the
+ // first handler for the same |global_id.child_id| will be returned.
+ CefRefPtr<CefRequestContextHandler> GetHandler(
+ const content::GlobalRenderFrameHostId& global_id,
+ bool require_frame_match) const;
+
+ private:
+ // Map of global ID to handler. These IDs are guaranteed to uniquely
+ // identify a RFH for its complete lifespan. See documentation on
+ // RenderFrameHost::GetFrameTreeNodeId() for background.
+ using RenderIdHandlerMap = std::map<content::GlobalRenderFrameHostId,
+ CefRefPtr<CefRequestContextHandler>>;
+ RenderIdHandlerMap render_id_handler_map_;
+};
+
+#endif // CEF_LIBCEF_BROWSER_REQUEST_CONTEXT_HANDLER_MAP_
diff --git a/libcef/browser/request_context_impl.cc b/libcef/browser/request_context_impl.cc
new file mode 100644
index 00000000..72d10796
--- /dev/null
+++ b/libcef/browser/request_context_impl.cc
@@ -0,0 +1,704 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "libcef/browser/request_context_impl.h"
+#include "libcef/browser/browser_context.h"
+#include "libcef/browser/context.h"
+#include "libcef/browser/prefs/pref_helper.h"
+#include "libcef/browser/thread_util.h"
+#include "libcef/common/app_manager.h"
+#include "libcef/common/task_runner_impl.h"
+
+#include "base/atomic_sequence_num.h"
+#include "base/logging.h"
+#include "base/strings/stringprintf.h"
+#include "chrome/browser/profiles/profile.h"
+#include "components/prefs/pref_service.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/child_process_host.h"
+#include "content/public/browser/ssl_host_state_delegate.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "net/dns/host_resolver.h"
+#include "services/network/public/cpp/resolve_host_client_base.h"
+#include "services/network/public/mojom/network_context.mojom.h"
+
+using content::BrowserThread;
+
+namespace {
+
+base::AtomicSequenceNumber g_next_id;
+
+class ResolveHostHelper : public network::ResolveHostClientBase {
+ public:
+ explicit ResolveHostHelper(CefRefPtr<CefResolveCallback> callback)
+ : callback_(callback), receiver_(this) {}
+
+ ResolveHostHelper(const ResolveHostHelper&) = delete;
+ ResolveHostHelper& operator=(const ResolveHostHelper&) = delete;
+
+ void Start(CefBrowserContext* browser_context, const CefString& origin) {
+ CEF_REQUIRE_UIT();
+
+ browser_context->GetNetworkContext()->CreateHostResolver(
+ net::DnsConfigOverrides(), host_resolver_.BindNewPipeAndPassReceiver());
+
+ host_resolver_.set_disconnect_handler(base::BindOnce(
+ &ResolveHostHelper::OnComplete, base::Unretained(this), net::ERR_FAILED,
+ net::ResolveErrorInfo(net::ERR_FAILED), absl::nullopt, absl::nullopt));
+
+ host_resolver_->ResolveHost(
+ network::mojom::HostResolverHost::NewHostPortPair(
+ net::HostPortPair::FromURL(GURL(origin.ToString()))),
+ net::NetworkAnonymizationKey::CreateTransient(), nullptr,
+ receiver_.BindNewPipeAndPassRemote());
+ }
+
+ private:
+ void OnComplete(int result,
+ const net::ResolveErrorInfo& resolve_error_info,
+ const absl::optional<net::AddressList>& resolved_addresses,
+ const absl::optional<net::HostResolverEndpointResults>&
+ endpoint_results_with_metadat) override {
+ CEF_REQUIRE_UIT();
+
+ host_resolver_.reset();
+ receiver_.reset();
+
+ std::vector<CefString> resolved_ips;
+
+ if (result == net::OK && resolved_addresses.has_value()) {
+ DCHECK(!resolved_addresses->empty());
+ for (const auto& value : *resolved_addresses) {
+ resolved_ips.push_back(value.ToStringWithoutPort());
+ }
+ }
+
+ callback_->OnResolveCompleted(static_cast<cef_errorcode_t>(result),
+ resolved_ips);
+ delete this;
+ }
+
+ CefRefPtr<CefResolveCallback> callback_;
+
+ mojo::Remote<network::mojom::HostResolver> host_resolver_;
+ mojo::Receiver<network::mojom::ResolveHostClient> receiver_{this};
+};
+
+} // namespace
+
+// CefBrowserContext
+
+// static
+CefRefPtr<CefRequestContext> CefRequestContext::GetGlobalContext() {
+ // Verify that the context is in a valid state.
+ if (!CONTEXT_STATE_VALID()) {
+ NOTREACHED() << "context not valid";
+ return nullptr;
+ }
+
+ CefRequestContextImpl::Config config;
+ config.is_global = true;
+ return CefRequestContextImpl::GetOrCreateRequestContext(config);
+}
+
+// static
+CefRefPtr<CefRequestContext> CefRequestContext::CreateContext(
+ const CefRequestContextSettings& settings,
+ CefRefPtr<CefRequestContextHandler> handler) {
+ // Verify that the context is in a valid state.
+ if (!CONTEXT_STATE_VALID()) {
+ NOTREACHED() << "context not valid";
+ return nullptr;
+ }
+
+ CefRequestContextImpl::Config config;
+ config.settings = settings;
+ config.handler = handler;
+ config.unique_id = g_next_id.GetNext();
+ return CefRequestContextImpl::GetOrCreateRequestContext(config);
+}
+
+// static
+CefRefPtr<CefRequestContext> CefRequestContext::CreateContext(
+ CefRefPtr<CefRequestContext> other,
+ CefRefPtr<CefRequestContextHandler> handler) {
+ // Verify that the context is in a valid state.
+ if (!CONTEXT_STATE_VALID()) {
+ NOTREACHED() << "context not valid";
+ return nullptr;
+ }
+
+ if (!other.get()) {
+ return nullptr;
+ }
+
+ CefRequestContextImpl::Config config;
+ config.other = static_cast<CefRequestContextImpl*>(other.get());
+ config.handler = handler;
+ config.unique_id = g_next_id.GetNext();
+ return CefRequestContextImpl::GetOrCreateRequestContext(config);
+}
+
+// CefRequestContextImpl
+
+CefRequestContextImpl::~CefRequestContextImpl() {
+ CEF_REQUIRE_UIT();
+
+ if (browser_context_) {
+ // May result in |browser_context_| being deleted if no other
+ // CefRequestContextImpl are referencing it.
+ browser_context_->RemoveCefRequestContext(this);
+ }
+}
+
+// static
+CefRefPtr<CefRequestContextImpl>
+CefRequestContextImpl::CreateGlobalRequestContext(
+ const CefRequestContextSettings& settings) {
+ // Create and initialize the global context immediately.
+ Config config;
+ config.is_global = true;
+ config.settings = settings;
+ CefRefPtr<CefRequestContextImpl> impl = new CefRequestContextImpl(config);
+ impl->Initialize();
+ return impl;
+}
+
+// static
+CefRefPtr<CefRequestContextImpl>
+CefRequestContextImpl::GetOrCreateForRequestContext(
+ CefRefPtr<CefRequestContext> request_context) {
+ if (request_context.get()) {
+ // Use the context from the provided CefRequestContext.
+ return static_cast<CefRequestContextImpl*>(request_context.get());
+ }
+
+ // Use the global context.
+ Config config;
+ config.is_global = true;
+ return CefRequestContextImpl::GetOrCreateRequestContext(config);
+}
+
+bool CefRequestContextImpl::VerifyBrowserContext() const {
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ NOTREACHED() << "called on invalid thread";
+ return false;
+ }
+
+ if (!browser_context() || !browser_context()->IsInitialized()) {
+ NOTREACHED() << "Uninitialized context";
+ return false;
+ }
+
+ return true;
+}
+
+CefBrowserContext* CefRequestContextImpl::GetBrowserContext() {
+ CHECK(VerifyBrowserContext());
+ return browser_context();
+}
+
+void CefRequestContextImpl::ExecuteWhenBrowserContextInitialized(
+ base::OnceClosure callback) {
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(
+ CEF_UIT,
+ base::BindOnce(
+ &CefRequestContextImpl::ExecuteWhenBrowserContextInitialized, this,
+ std::move(callback)));
+ return;
+ }
+
+ EnsureBrowserContext();
+ browser_context()->StoreOrTriggerInitCallback(std::move(callback));
+}
+
+void CefRequestContextImpl::GetBrowserContext(
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ BrowserContextCallback callback) {
+ if (!task_runner.get()) {
+ task_runner = CefTaskRunnerImpl::GetCurrentTaskRunner();
+ }
+
+ ExecuteWhenBrowserContextInitialized(base::BindOnce(
+ [](CefRefPtr<CefRequestContextImpl> context,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ BrowserContextCallback callback) {
+ CEF_REQUIRE_UIT();
+
+ auto browser_context = context->browser_context();
+ DCHECK(browser_context->IsInitialized());
+
+ if (task_runner->BelongsToCurrentThread()) {
+ // Execute the callback immediately.
+ std::move(callback).Run(browser_context->getter());
+ } else {
+ // Execute the callback on the target thread.
+ task_runner->PostTask(
+ FROM_HERE,
+ base::BindOnce(std::move(callback), browser_context->getter()));
+ }
+ },
+ CefRefPtr<CefRequestContextImpl>(this), task_runner,
+ std::move(callback)));
+}
+
+bool CefRequestContextImpl::IsSame(CefRefPtr<CefRequestContext> other) {
+ CefRequestContextImpl* other_impl =
+ static_cast<CefRequestContextImpl*>(other.get());
+ if (!other_impl) {
+ return false;
+ }
+
+ // Compare whether both are the global context.
+ if (config_.is_global && other_impl->config_.is_global) {
+ return true;
+ }
+
+ // Compare CefBrowserContext pointers if one has been associated.
+ if (browser_context() && other_impl->browser_context()) {
+ return (browser_context() == other_impl->browser_context());
+ } else if (browser_context() || other_impl->browser_context()) {
+ return false;
+ }
+
+ // Otherwise compare unique IDs.
+ return (config_.unique_id == other_impl->config_.unique_id);
+}
+
+bool CefRequestContextImpl::IsSharingWith(CefRefPtr<CefRequestContext> other) {
+ CefRequestContextImpl* other_impl =
+ static_cast<CefRequestContextImpl*>(other.get());
+ if (!other_impl) {
+ return false;
+ }
+
+ if (IsSame(other)) {
+ return true;
+ }
+
+ CefRefPtr<CefRequestContext> pending_other = config_.other;
+ if (pending_other.get()) {
+ // This object is not initialized but we know what context this object will
+ // share with. Compare to that other context instead.
+ return pending_other->IsSharingWith(other);
+ }
+
+ pending_other = other_impl->config_.other;
+ if (pending_other.get()) {
+ // The other object is not initialized but we know what context that object
+ // will share with. Compare to that other context instead.
+ return pending_other->IsSharingWith(this);
+ }
+
+ // This or the other object is not initialized. Compare the cache path values.
+ // If both are non-empty and the same then they'll share the same storage.
+ if (config_.settings.cache_path.length > 0 &&
+ other_impl->config_.settings.cache_path.length > 0) {
+ return (
+ base::FilePath(CefString(&config_.settings.cache_path)) ==
+ base::FilePath(CefString(&other_impl->config_.settings.cache_path)));
+ }
+
+ return false;
+}
+
+bool CefRequestContextImpl::IsGlobal() {
+ return config_.is_global;
+}
+
+CefRefPtr<CefRequestContextHandler> CefRequestContextImpl::GetHandler() {
+ return config_.handler;
+}
+
+CefString CefRequestContextImpl::GetCachePath() {
+ return CefString(&config_.settings.cache_path);
+}
+
+CefRefPtr<CefCookieManager> CefRequestContextImpl::GetCookieManager(
+ CefRefPtr<CefCompletionCallback> callback) {
+ CefRefPtr<CefCookieManagerImpl> cookie_manager = new CefCookieManagerImpl();
+ InitializeCookieManagerInternal(cookie_manager, callback);
+ return cookie_manager.get();
+}
+
+bool CefRequestContextImpl::RegisterSchemeHandlerFactory(
+ const CefString& scheme_name,
+ const CefString& domain_name,
+ CefRefPtr<CefSchemeHandlerFactory> factory) {
+ GetBrowserContext(
+ content::GetUIThreadTaskRunner({}),
+ base::BindOnce(
+ [](const CefString& scheme_name, const CefString& domain_name,
+ CefRefPtr<CefSchemeHandlerFactory> factory,
+ CefBrowserContext::Getter browser_context_getter) {
+ auto browser_context = browser_context_getter.Run();
+ if (browser_context) {
+ browser_context->RegisterSchemeHandlerFactory(
+ scheme_name, domain_name, factory);
+ }
+ },
+ scheme_name, domain_name, factory));
+
+ return true;
+}
+
+bool CefRequestContextImpl::ClearSchemeHandlerFactories() {
+ GetBrowserContext(
+ content::GetUIThreadTaskRunner({}),
+ base::BindOnce([](CefBrowserContext::Getter browser_context_getter) {
+ auto browser_context = browser_context_getter.Run();
+ if (browser_context) {
+ browser_context->ClearSchemeHandlerFactories();
+ }
+ }));
+
+ return true;
+}
+
+bool CefRequestContextImpl::HasPreference(const CefString& name) {
+ if (!VerifyBrowserContext()) {
+ return false;
+ }
+
+ PrefService* pref_service = browser_context()->AsProfile()->GetPrefs();
+ return pref_helper::HasPreference(pref_service, name);
+}
+
+CefRefPtr<CefValue> CefRequestContextImpl::GetPreference(
+ const CefString& name) {
+ if (!VerifyBrowserContext()) {
+ return nullptr;
+ }
+
+ PrefService* pref_service = browser_context()->AsProfile()->GetPrefs();
+ return pref_helper::GetPreference(pref_service, name);
+}
+
+CefRefPtr<CefDictionaryValue> CefRequestContextImpl::GetAllPreferences(
+ bool include_defaults) {
+ if (!VerifyBrowserContext()) {
+ return nullptr;
+ }
+
+ PrefService* pref_service = browser_context()->AsProfile()->GetPrefs();
+ return pref_helper::GetAllPreferences(pref_service, include_defaults);
+}
+
+bool CefRequestContextImpl::CanSetPreference(const CefString& name) {
+ if (!VerifyBrowserContext()) {
+ return false;
+ }
+
+ PrefService* pref_service = browser_context()->AsProfile()->GetPrefs();
+ return pref_helper::CanSetPreference(pref_service, name);
+}
+
+bool CefRequestContextImpl::SetPreference(const CefString& name,
+ CefRefPtr<CefValue> value,
+ CefString& error) {
+ if (!VerifyBrowserContext()) {
+ return false;
+ }
+
+ PrefService* pref_service = browser_context()->AsProfile()->GetPrefs();
+ return pref_helper::SetPreference(pref_service, name, value, error);
+}
+
+void CefRequestContextImpl::ClearCertificateExceptions(
+ CefRefPtr<CefCompletionCallback> callback) {
+ GetBrowserContext(
+ content::GetUIThreadTaskRunner({}),
+ base::BindOnce(&CefRequestContextImpl::ClearCertificateExceptionsInternal,
+ this, callback));
+}
+
+void CefRequestContextImpl::ClearHttpAuthCredentials(
+ CefRefPtr<CefCompletionCallback> callback) {
+ GetBrowserContext(
+ content::GetUIThreadTaskRunner({}),
+ base::BindOnce(&CefRequestContextImpl::ClearHttpAuthCredentialsInternal,
+ this, callback));
+}
+
+void CefRequestContextImpl::CloseAllConnections(
+ CefRefPtr<CefCompletionCallback> callback) {
+ GetBrowserContext(
+ content::GetUIThreadTaskRunner({}),
+ base::BindOnce(&CefRequestContextImpl::CloseAllConnectionsInternal, this,
+ callback));
+}
+
+void CefRequestContextImpl::ResolveHost(
+ const CefString& origin,
+ CefRefPtr<CefResolveCallback> callback) {
+ GetBrowserContext(content::GetUIThreadTaskRunner({}),
+ base::BindOnce(&CefRequestContextImpl::ResolveHostInternal,
+ this, origin, callback));
+}
+
+void CefRequestContextImpl::LoadExtension(
+ const CefString& root_directory,
+ CefRefPtr<CefDictionaryValue> manifest,
+ CefRefPtr<CefExtensionHandler> handler) {
+ GetBrowserContext(content::GetUIThreadTaskRunner({}),
+ base::BindOnce(
+ [](const CefString& root_directory,
+ CefRefPtr<CefDictionaryValue> manifest,
+ CefRefPtr<CefExtensionHandler> handler,
+ CefRefPtr<CefRequestContextImpl> self,
+ CefBrowserContext::Getter browser_context_getter) {
+ auto browser_context = browser_context_getter.Run();
+ if (browser_context) {
+ browser_context->LoadExtension(
+ root_directory, manifest, handler, self);
+ }
+ },
+ root_directory, manifest, handler,
+ CefRefPtr<CefRequestContextImpl>(this)));
+}
+
+bool CefRequestContextImpl::DidLoadExtension(const CefString& extension_id) {
+ CefRefPtr<CefExtension> extension = GetExtension(extension_id);
+ // GetLoaderContext() will return NULL for internal extensions.
+ return extension && IsSame(extension->GetLoaderContext());
+}
+
+bool CefRequestContextImpl::HasExtension(const CefString& extension_id) {
+ return !!GetExtension(extension_id);
+}
+
+bool CefRequestContextImpl::GetExtensions(
+ std::vector<CefString>& extension_ids) {
+ extension_ids.clear();
+
+ if (!VerifyBrowserContext()) {
+ return false;
+ }
+
+ return browser_context()->GetExtensions(extension_ids);
+}
+
+CefRefPtr<CefExtension> CefRequestContextImpl::GetExtension(
+ const CefString& extension_id) {
+ if (!VerifyBrowserContext()) {
+ return nullptr;
+ }
+
+ return browser_context()->GetExtension(extension_id);
+}
+
+CefRefPtr<CefMediaRouter> CefRequestContextImpl::GetMediaRouter(
+ CefRefPtr<CefCompletionCallback> callback) {
+ CefRefPtr<CefMediaRouterImpl> media_router = new CefMediaRouterImpl();
+ InitializeMediaRouterInternal(media_router, callback);
+ return media_router.get();
+}
+
+void CefRequestContextImpl::OnRenderFrameCreated(
+ const content::GlobalRenderFrameHostId& global_id,
+ bool is_main_frame,
+ bool is_guest_view) {
+ browser_context_->OnRenderFrameCreated(this, global_id, is_main_frame,
+ is_guest_view);
+}
+
+void CefRequestContextImpl::OnRenderFrameDeleted(
+ const content::GlobalRenderFrameHostId& global_id,
+ bool is_main_frame,
+ bool is_guest_view) {
+ browser_context_->OnRenderFrameDeleted(this, global_id, is_main_frame,
+ is_guest_view);
+}
+
+// static
+CefRefPtr<CefRequestContextImpl>
+CefRequestContextImpl::GetOrCreateRequestContext(const Config& config) {
+ if (config.is_global ||
+ (config.other && config.other->IsGlobal() && !config.handler)) {
+ // Return the singleton global context.
+ return static_cast<CefRequestContextImpl*>(
+ CefAppManager::Get()->GetGlobalRequestContext().get());
+ }
+
+ // The new context will be initialized later by EnsureBrowserContext().
+ CefRefPtr<CefRequestContextImpl> context = new CefRequestContextImpl(config);
+
+ // Initialize ASAP so that any tasks blocked on initialization will execute.
+ if (CEF_CURRENTLY_ON_UIT()) {
+ context->Initialize();
+ } else {
+ CEF_POST_TASK(CEF_UIT,
+ base::BindOnce(&CefRequestContextImpl::Initialize, context));
+ }
+
+ return context;
+}
+
+CefRequestContextImpl::CefRequestContextImpl(
+ const CefRequestContextImpl::Config& config)
+ : config_(config) {}
+
+void CefRequestContextImpl::Initialize() {
+ CEF_REQUIRE_UIT();
+
+ DCHECK(!browser_context_);
+
+ if (config_.other) {
+ // Share storage with |config_.other|.
+ browser_context_ = config_.other->browser_context();
+ CHECK(browser_context_);
+ }
+
+ if (!browser_context_) {
+ if (!config_.is_global) {
+ // User-specified settings need to be normalized.
+ CefContext::Get()->NormalizeRequestContextSettings(&config_.settings);
+ }
+
+ const base::FilePath& cache_path =
+ base::FilePath(CefString(&config_.settings.cache_path));
+ if (!cache_path.empty()) {
+ // Check if a CefBrowserContext is already globally registered for
+ // the specified cache path. If so then use it.
+ browser_context_ = CefBrowserContext::FromCachePath(cache_path);
+ }
+ }
+
+ auto initialized_cb =
+ base::BindOnce(&CefRequestContextImpl::BrowserContextInitialized, this);
+
+ if (!browser_context_) {
+ // Create a new CefBrowserContext instance. If the cache path is non-
+ // empty then this new instance will become the globally registered
+ // CefBrowserContext for that path. Otherwise, this new instance will
+ // be a completely isolated "incognito mode" context.
+ browser_context_ = CefAppManager::Get()->CreateNewBrowserContext(
+ config_.settings, std::move(initialized_cb));
+ } else {
+ // Share the same settings as the existing context.
+ config_.settings = browser_context_->settings();
+ browser_context_->StoreOrTriggerInitCallback(std::move(initialized_cb));
+ }
+
+ // We'll disassociate from |browser_context_| on destruction.
+ browser_context_->AddCefRequestContext(this);
+
+ if (config_.other) {
+ // Clear the reference to |config_.other| after setting
+ // |request_context_getter_|. This is the reverse order of checks in
+ // IsSharedWith().
+ config_.other = nullptr;
+ }
+}
+
+void CefRequestContextImpl::BrowserContextInitialized() {
+ if (config_.handler) {
+ // Always execute asynchronously so the current call stack can unwind.
+ CEF_POST_TASK(
+ CEF_UIT,
+ base::BindOnce(&CefRequestContextHandler::OnRequestContextInitialized,
+ config_.handler, CefRefPtr<CefRequestContext>(this)));
+ }
+}
+
+void CefRequestContextImpl::EnsureBrowserContext() {
+ CEF_REQUIRE_UIT();
+ if (!browser_context()) {
+ Initialize();
+ }
+ DCHECK(browser_context());
+}
+
+void CefRequestContextImpl::ClearCertificateExceptionsInternal(
+ CefRefPtr<CefCompletionCallback> callback,
+ CefBrowserContext::Getter browser_context_getter) {
+ auto browser_context = browser_context_getter.Run();
+ if (!browser_context) {
+ return;
+ }
+
+ content::SSLHostStateDelegate* ssl_delegate =
+ browser_context->AsBrowserContext()->GetSSLHostStateDelegate();
+ if (ssl_delegate) {
+ ssl_delegate->Clear(base::NullCallback());
+ }
+
+ if (callback) {
+ CEF_POST_TASK(CEF_UIT,
+ base::BindOnce(&CefCompletionCallback::OnComplete, callback));
+ }
+}
+
+void CefRequestContextImpl::ClearHttpAuthCredentialsInternal(
+ CefRefPtr<CefCompletionCallback> callback,
+ CefBrowserContext::Getter browser_context_getter) {
+ auto browser_context = browser_context_getter.Run();
+ if (!browser_context) {
+ return;
+ }
+
+ browser_context->GetNetworkContext()->ClearHttpAuthCache(
+ /*start_time=*/base::Time(), /*end_time=*/base::Time::Max(),
+ base::BindOnce(&CefCompletionCallback::OnComplete, callback));
+}
+
+void CefRequestContextImpl::CloseAllConnectionsInternal(
+ CefRefPtr<CefCompletionCallback> callback,
+ CefBrowserContext::Getter browser_context_getter) {
+ auto browser_context = browser_context_getter.Run();
+ if (!browser_context) {
+ return;
+ }
+
+ browser_context->GetNetworkContext()->CloseAllConnections(
+ base::BindOnce(&CefCompletionCallback::OnComplete, callback));
+}
+
+void CefRequestContextImpl::ResolveHostInternal(
+ const CefString& origin,
+ CefRefPtr<CefResolveCallback> callback,
+ CefBrowserContext::Getter browser_context_getter) {
+ auto browser_context = browser_context_getter.Run();
+ if (!browser_context) {
+ return;
+ }
+
+ // |helper| will be deleted in ResolveHostHelper::OnComplete().
+ ResolveHostHelper* helper = new ResolveHostHelper(callback);
+ helper->Start(browser_context, origin);
+}
+
+void CefRequestContextImpl::InitializeCookieManagerInternal(
+ CefRefPtr<CefCookieManagerImpl> cookie_manager,
+ CefRefPtr<CefCompletionCallback> callback) {
+ GetBrowserContext(content::GetUIThreadTaskRunner({}),
+ base::BindOnce(
+ [](CefRefPtr<CefCookieManagerImpl> cookie_manager,
+ CefRefPtr<CefCompletionCallback> callback,
+ CefBrowserContext::Getter browser_context_getter) {
+ cookie_manager->Initialize(browser_context_getter,
+ callback);
+ },
+ cookie_manager, callback));
+}
+
+void CefRequestContextImpl::InitializeMediaRouterInternal(
+ CefRefPtr<CefMediaRouterImpl> media_router,
+ CefRefPtr<CefCompletionCallback> callback) {
+ GetBrowserContext(content::GetUIThreadTaskRunner({}),
+ base::BindOnce(
+ [](CefRefPtr<CefMediaRouterImpl> media_router,
+ CefRefPtr<CefCompletionCallback> callback,
+ CefBrowserContext::Getter browser_context_getter) {
+ media_router->Initialize(browser_context_getter,
+ callback);
+ },
+ media_router, callback));
+}
+
+CefBrowserContext* CefRequestContextImpl::browser_context() const {
+ return browser_context_;
+}
diff --git a/libcef/browser/request_context_impl.h b/libcef/browser/request_context_impl.h
new file mode 100644
index 00000000..9cf34d3f
--- /dev/null
+++ b/libcef/browser/request_context_impl.h
@@ -0,0 +1,179 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_REQUEST_CONTEXT_IMPL_H_
+#define CEF_LIBCEF_BROWSER_REQUEST_CONTEXT_IMPL_H_
+#pragma once
+
+#include "include/cef_request_context.h"
+#include "libcef/browser/browser_context.h"
+#include "libcef/browser/media_router/media_router_impl.h"
+#include "libcef/browser/net_service/cookie_manager_impl.h"
+#include "libcef/browser/thread_util.h"
+
+namespace content {
+struct GlobalRenderFrameHostId;
+}
+
+class CefBrowserContext;
+
+// Implementation of the CefRequestContext interface. All methods are thread-
+// safe unless otherwise indicated. Will be deleted on the UI thread.
+class CefRequestContextImpl : public CefRequestContext {
+ public:
+ CefRequestContextImpl(const CefRequestContextImpl&) = delete;
+ CefRequestContextImpl& operator=(const CefRequestContextImpl&) = delete;
+
+ ~CefRequestContextImpl() override;
+
+ // Creates the singleton global RequestContext. Called from
+ // AlloyBrowserMainParts::PreMainMessageLoopRun and
+ // ChromeBrowserMainExtraPartsCef::PostProfileInit.
+ static CefRefPtr<CefRequestContextImpl> CreateGlobalRequestContext(
+ const CefRequestContextSettings& settings);
+
+ // Returns a CefRequestContextImpl for the specified |request_context|.
+ // Will return the global context if |request_context| is NULL.
+ static CefRefPtr<CefRequestContextImpl> GetOrCreateForRequestContext(
+ CefRefPtr<CefRequestContext> request_context);
+
+ // Verify that the browser context can be directly accessed (e.g. on the UI
+ // thread and initialized).
+ bool VerifyBrowserContext() const;
+
+ // Returns the browser context object. Can only be called on the UI thread
+ // after the browser context has been initialized.
+ CefBrowserContext* GetBrowserContext();
+
+ // If the context is fully initialized execute |callback|, otherwise
+ // store it until the context is fully initialized.
+ void ExecuteWhenBrowserContextInitialized(base::OnceClosure callback);
+
+ // Executes |callback| either synchronously or asynchronously after the
+ // browser context object has been initialized. If |task_runner| is NULL the
+ // callback will be executed on the originating thread. The resulting getter
+ // can only be executed on the UI thread.
+ using BrowserContextCallback =
+ base::OnceCallback<void(CefBrowserContext::Getter)>;
+ void GetBrowserContext(
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ BrowserContextCallback callback);
+
+ bool IsSame(CefRefPtr<CefRequestContext> other) override;
+ bool IsSharingWith(CefRefPtr<CefRequestContext> other) override;
+ bool IsGlobal() override;
+ CefRefPtr<CefRequestContextHandler> GetHandler() override;
+ CefString GetCachePath() override;
+ CefRefPtr<CefCookieManager> GetCookieManager(
+ CefRefPtr<CefCompletionCallback> callback) override;
+ bool RegisterSchemeHandlerFactory(
+ const CefString& scheme_name,
+ const CefString& domain_name,
+ CefRefPtr<CefSchemeHandlerFactory> factory) override;
+ bool ClearSchemeHandlerFactories() override;
+ bool HasPreference(const CefString& name) override;
+ CefRefPtr<CefValue> GetPreference(const CefString& name) override;
+ CefRefPtr<CefDictionaryValue> GetAllPreferences(
+ bool include_defaults) override;
+ bool CanSetPreference(const CefString& name) override;
+ bool SetPreference(const CefString& name,
+ CefRefPtr<CefValue> value,
+ CefString& error) override;
+ void ClearCertificateExceptions(
+ CefRefPtr<CefCompletionCallback> callback) override;
+ void ClearHttpAuthCredentials(
+ CefRefPtr<CefCompletionCallback> callback) override;
+ void CloseAllConnections(CefRefPtr<CefCompletionCallback> callback) override;
+ void ResolveHost(const CefString& origin,
+ CefRefPtr<CefResolveCallback> callback) override;
+ void LoadExtension(const CefString& root_directory,
+ CefRefPtr<CefDictionaryValue> manifest,
+ CefRefPtr<CefExtensionHandler> handler) override;
+ bool DidLoadExtension(const CefString& extension_id) override;
+ bool HasExtension(const CefString& extension_id) override;
+ bool GetExtensions(std::vector<CefString>& extension_ids) override;
+ CefRefPtr<CefExtension> GetExtension(const CefString& extension_id) override;
+ CefRefPtr<CefMediaRouter> GetMediaRouter(
+ CefRefPtr<CefCompletionCallback> callback) override;
+
+ const CefRequestContextSettings& settings() const { return config_.settings; }
+
+ // Called from CefBrowserContentsDelegate::RenderFrameCreated or
+ // CefMimeHandlerViewGuestDelegate::OnGuestAttached when a render frame is
+ // created.
+ void OnRenderFrameCreated(const content::GlobalRenderFrameHostId& global_id,
+ bool is_main_frame,
+ bool is_guest_view);
+
+ // Called from CefBrowserContentsDelegate::RenderFrameDeleted or
+ // CefMimeHandlerViewGuestDelegate::OnGuestDetached when a render frame is
+ // deleted.
+ void OnRenderFrameDeleted(const content::GlobalRenderFrameHostId& global_id,
+ bool is_main_frame,
+ bool is_guest_view);
+
+ private:
+ friend class CefRequestContext;
+
+ struct Config {
+ // True if wrapping the global context.
+ bool is_global = false;
+
+ // |settings| or |other| will be set when creating a new CefRequestContext
+ // via the API. When wrapping an existing CefBrowserContext* both will be
+ // empty and Initialize(CefBrowserContext*) will be called immediately after
+ // CefRequestContextImpl construction.
+ CefRequestContextSettings settings;
+ CefRefPtr<CefRequestContextImpl> other;
+
+ // Optionally use this handler.
+ CefRefPtr<CefRequestContextHandler> handler;
+
+ // Used to uniquely identify CefRequestContext objects before an associated
+ // CefBrowserContext has been created. Should be set when a new
+ // CefRequestContext via the API.
+ int unique_id = -1;
+ };
+
+ static CefRefPtr<CefRequestContextImpl> GetOrCreateRequestContext(
+ const Config& config);
+
+ explicit CefRequestContextImpl(const Config& config);
+
+ void Initialize();
+ void BrowserContextInitialized();
+
+ // Make sure the browser context exists. Only called on the UI thread.
+ void EnsureBrowserContext();
+
+ void ClearCertificateExceptionsInternal(
+ CefRefPtr<CefCompletionCallback> callback,
+ CefBrowserContext::Getter browser_context_getter);
+ void ClearHttpAuthCredentialsInternal(
+ CefRefPtr<CefCompletionCallback> callback,
+ CefBrowserContext::Getter browser_context_getter);
+ void CloseAllConnectionsInternal(
+ CefRefPtr<CefCompletionCallback> callback,
+ CefBrowserContext::Getter browser_context_getter);
+ void ResolveHostInternal(const CefString& origin,
+ CefRefPtr<CefResolveCallback> callback,
+ CefBrowserContext::Getter browser_context_getter);
+
+ void InitializeCookieManagerInternal(
+ CefRefPtr<CefCookieManagerImpl> cookie_manager,
+ CefRefPtr<CefCompletionCallback> callback);
+ void InitializeMediaRouterInternal(CefRefPtr<CefMediaRouterImpl> media_router,
+ CefRefPtr<CefCompletionCallback> callback);
+
+ CefBrowserContext* browser_context() const;
+
+ // We must disassociate from this on destruction.
+ CefBrowserContext* browser_context_ = nullptr;
+
+ Config config_;
+
+ IMPLEMENT_REFCOUNTING_DELETE_ON_UIT(CefRequestContextImpl);
+};
+
+#endif // CEF_LIBCEF_BROWSER_REQUEST_CONTEXT_IMPL_H_
diff --git a/libcef/browser/scheme_impl.cc b/libcef/browser/scheme_impl.cc
new file mode 100644
index 00000000..f5423c05
--- /dev/null
+++ b/libcef/browser/scheme_impl.cc
@@ -0,0 +1,32 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#include "include/cef_scheme.h"
+#include "libcef/browser/context.h"
+
+#include "base/logging.h"
+
+bool CefRegisterSchemeHandlerFactory(
+ const CefString& scheme_name,
+ const CefString& domain_name,
+ CefRefPtr<CefSchemeHandlerFactory> factory) {
+ // Verify that the context is in a valid state.
+ if (!CONTEXT_STATE_VALID()) {
+ NOTREACHED() << "context not valid";
+ return false;
+ }
+
+ return CefRequestContext::GetGlobalContext()->RegisterSchemeHandlerFactory(
+ scheme_name, domain_name, factory);
+}
+
+bool CefClearSchemeHandlerFactories() {
+ // Verify that the context is in a valid state.
+ if (!CONTEXT_STATE_VALID()) {
+ NOTREACHED() << "context not valid";
+ return false;
+ }
+
+ return CefRequestContext::GetGlobalContext()->ClearSchemeHandlerFactories();
+}
diff --git a/libcef/browser/screen_util.cc b/libcef/browser/screen_util.cc
new file mode 100644
index 00000000..ac1023cd
--- /dev/null
+++ b/libcef/browser/screen_util.cc
@@ -0,0 +1,44 @@
+// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "libcef/browser/screen_util.h"
+
+#include <algorithm>
+
+#include "ui/gfx/geometry/rect.h"
+
+namespace {
+
+constexpr int kMinWidth = 0;
+constexpr int kMinHeight = 0;
+
+// Makes sure that line segment lies entirely between min and max.
+int clamp_segment_start(int start, int len, int min, int max) {
+ start = std::clamp(start, min, max);
+ const int end = start + len;
+ const int excess = end - max;
+
+ if (excess > 0) {
+ start = start - excess;
+ }
+
+ return start;
+}
+
+} // namespace
+
+gfx::Rect MakeVisibleOnScreenRect(const gfx::Rect& rect,
+ const gfx::Rect& screen) {
+ const int width = std::clamp(rect.width(), kMinWidth, screen.width());
+ const int height = std::clamp(rect.height(), kMinHeight, screen.height());
+
+ const int right_border = screen.x() + screen.width();
+ const int x = clamp_segment_start(rect.x(), width, screen.x(), right_border);
+
+ const int bottom_border = screen.y() + screen.height();
+ const int y =
+ clamp_segment_start(rect.y(), height, screen.y(), bottom_border);
+
+ return gfx::Rect(x, y, width, height);
+}
diff --git a/libcef/browser/screen_util.h b/libcef/browser/screen_util.h
new file mode 100644
index 00000000..1cadf971
--- /dev/null
+++ b/libcef/browser/screen_util.h
@@ -0,0 +1,20 @@
+// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_SCREEN_UTIL_H_
+#define CEF_LIBCEF_BROWSER_SCREEN_UTIL_H_
+#pragma once
+
+namespace gfx {
+class Rect;
+}
+
+// Create a new rectangle from the input |rect| rectangle that is fully visible
+// on provided |screen_rect| screen. The width and height of the resulting
+// rectangle are clamped to the screen width and height respectively if they
+// would overflow.
+gfx::Rect MakeVisibleOnScreenRect(const gfx::Rect& rect,
+ const gfx::Rect& screen);
+
+#endif // CEF_LIBCEF_BROWSER_SCREEN_UTIL_H_
diff --git a/libcef/browser/screen_util_unittest.cc b/libcef/browser/screen_util_unittest.cc
new file mode 100644
index 00000000..3beefa07
--- /dev/null
+++ b/libcef/browser/screen_util_unittest.cc
@@ -0,0 +1,83 @@
+// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "cef/libcef/browser/screen_util.h"
+#include "tests/gtest/include/gtest/gtest.h"
+
+#include "ui/gfx/geometry/rect.h"
+
+namespace {
+
+constexpr int kScreenWidth = 1024;
+constexpr int kScreenHeight = 768;
+const gfx::Rect kMainScreen(0, 0, kScreenWidth, kScreenHeight);
+const gfx::Rect kLeftScreen(-1024, 0, kScreenWidth, kScreenHeight);
+
+} // namespace
+
+TEST(MakeVisibleOnScreenRect, RectSizeIsBiggerThanScreen) {
+ const gfx::Rect rect{400, 500, 1500, 800};
+
+ auto result = MakeVisibleOnScreenRect(rect, kMainScreen);
+
+ EXPECT_EQ(result.x(), 0);
+ EXPECT_EQ(result.width(), kMainScreen.width());
+ EXPECT_EQ(result.y(), 0);
+ EXPECT_EQ(result.height(), kMainScreen.height());
+}
+
+TEST(MakeVisibleOnScreenRect, RightBorderIsOutsideTheScreen) {
+ const gfx::Rect rect{600, 400, 500, 300};
+
+ auto result = MakeVisibleOnScreenRect(rect, kMainScreen);
+
+ EXPECT_EQ(result.x(), 524);
+ EXPECT_EQ(result.width(), rect.width());
+ EXPECT_EQ(result.y(), rect.y());
+ EXPECT_EQ(result.height(), rect.height());
+}
+
+TEST(MakeVisibleOnScreenRect, LeftBorderIsOutsideTheScreen) {
+ const gfx::Rect rect{-400, 400, 500, 300};
+
+ auto result = MakeVisibleOnScreenRect(rect, kMainScreen);
+
+ EXPECT_EQ(result.x(), 0);
+ EXPECT_EQ(result.width(), rect.width());
+ EXPECT_EQ(result.y(), rect.y());
+ EXPECT_EQ(result.height(), rect.height());
+}
+
+TEST(MakeVisibleOnScreenRect, BottomBorderIsOutsideTheScreen) {
+ const gfx::Rect rect{600, 500, 300, 300};
+
+ auto result = MakeVisibleOnScreenRect(rect, kMainScreen);
+
+ EXPECT_EQ(result.x(), 600);
+ EXPECT_EQ(result.width(), rect.width());
+ EXPECT_EQ(result.y(), 468);
+ EXPECT_EQ(result.height(), rect.height());
+}
+
+TEST(MakeVisibleOnScreenRect, RectIsVisibleOnTheLeftScreen) {
+ const gfx::Rect rect{-500, 300, 300, 300};
+
+ auto result = MakeVisibleOnScreenRect(rect, kLeftScreen);
+
+ EXPECT_EQ(result.x(), rect.x());
+ EXPECT_EQ(result.width(), rect.width());
+ EXPECT_EQ(result.y(), rect.y());
+ EXPECT_EQ(result.height(), rect.height());
+}
+
+TEST(MakeVisibleOnScreenRect, RectSizeIsBiggerThanLeftScreen) {
+ const gfx::Rect rect{-500, 300, 3000, 3000};
+
+ auto result = MakeVisibleOnScreenRect(rect, kLeftScreen);
+
+ EXPECT_EQ(result.x(), kLeftScreen.x());
+ EXPECT_EQ(result.width(), kLeftScreen.width());
+ EXPECT_EQ(result.y(), kLeftScreen.y());
+ EXPECT_EQ(result.height(), kLeftScreen.height());
+} \ No newline at end of file
diff --git a/libcef/browser/server_impl.cc b/libcef/browser/server_impl.cc
new file mode 100644
index 00000000..a9faff45
--- /dev/null
+++ b/libcef/browser/server_impl.cc
@@ -0,0 +1,699 @@
+// Copyright (c) 2017 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "libcef/browser/server_impl.h"
+
+#include "libcef/browser/thread_util.h"
+#include "libcef/common/request_impl.h"
+#include "libcef/common/task_runner_impl.h"
+
+#include "base/format_macros.h"
+#include "base/functional/bind.h"
+#include "base/memory/ptr_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/task/thread_pool.h"
+#include "base/threading/thread.h"
+#include "net/base/net_errors.h"
+#include "net/http/http_request_headers.h"
+#include "net/server/http_server_request_info.h"
+#include "net/server/http_server_response_info.h"
+#include "net/socket/server_socket.h"
+#include "net/socket/tcp_server_socket.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
+
+#define CEF_CURRENTLY_ON_HT() CurrentlyOnHandlerThread()
+#define CEF_REQUIRE_HT() DCHECK(CEF_CURRENTLY_ON_HT())
+
+#define CEF_REQUIRE_HT_RETURN(var) \
+ if (!CEF_CURRENTLY_ON_HT()) { \
+ NOTREACHED() << "called on invalid thread"; \
+ return var; \
+ }
+
+#define CEF_REQUIRE_HT_RETURN_VOID() \
+ if (!CEF_CURRENTLY_ON_HT()) { \
+ NOTREACHED() << "called on invalid thread"; \
+ return; \
+ }
+
+#define CEF_POST_TASK_HT(task) task_runner_->PostTask(FROM_HERE, task);
+
+namespace {
+
+// Wrap a string in a unique_ptr to avoid extra copies.
+std::unique_ptr<std::string> CreateUniqueString(const void* data,
+ size_t data_size) {
+ std::unique_ptr<std::string> ptr;
+ if (data && data_size > 0) {
+ ptr.reset(new std::string(static_cast<const char*>(data), data_size));
+ } else {
+ ptr.reset(new std::string());
+ }
+ return ptr;
+}
+
+CefRefPtr<CefRequest> CreateRequest(const std::string& address,
+ const net::HttpServerRequestInfo& info,
+ bool is_websocket) {
+ DCHECK(!address.empty());
+ DCHECK(!info.method.empty());
+ DCHECK(!info.path.empty());
+
+ CefRefPtr<CefPostData> post_data;
+ if (!info.data.empty()) {
+ post_data = CefPostData::Create();
+ CefRefPtr<CefPostDataElement> post_element = CefPostDataElement::Create();
+ post_element->SetToBytes(info.data.size(), info.data.data());
+ post_data->AddElement(post_element);
+ }
+
+ std::string referer;
+
+ CefRequest::HeaderMap header_map;
+ if (!info.headers.empty()) {
+ net::HttpServerRequestInfo::HeadersMap::const_iterator it =
+ info.headers.begin();
+ for (; it != info.headers.end(); ++it) {
+ // Don't include Referer in the header map.
+ if (base::EqualsCaseInsensitiveASCII(it->first,
+ net::HttpRequestHeaders::kReferer)) {
+ referer = it->second;
+ } else {
+ header_map.insert(std::make_pair(it->first, it->second));
+ }
+ }
+ }
+
+ CefRefPtr<CefRequestImpl> request = new CefRequestImpl();
+ request->Set((is_websocket ? "ws://" : "http://") + address + info.path,
+ info.method, post_data, header_map);
+ if (!referer.empty()) {
+ request->SetReferrer(referer, REFERRER_POLICY_DEFAULT);
+ }
+ request->SetReadOnly(true);
+ return request;
+}
+
+// Callback implementation for WebSocket acceptance. Always executes on the UI
+// thread so we can avoid multiple execution by clearing the |impl_| reference.
+class AcceptWebSocketCallback : public CefCallback {
+ public:
+ AcceptWebSocketCallback(CefRefPtr<CefServerImpl> impl,
+ int connection_id,
+ net::HttpServerRequestInfo request_info)
+ : impl_(impl),
+ connection_id_(connection_id),
+ request_info_(request_info) {}
+
+ AcceptWebSocketCallback(const AcceptWebSocketCallback&) = delete;
+ AcceptWebSocketCallback& operator=(const AcceptWebSocketCallback&) = delete;
+
+ ~AcceptWebSocketCallback() override {
+ if (impl_) {
+ impl_->ContinueWebSocketRequest(connection_id_, request_info_, false);
+ }
+ }
+
+ void Continue() override {
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(CEF_UIT,
+ base::BindOnce(&AcceptWebSocketCallback::Continue, this));
+ return;
+ }
+ if (!impl_) {
+ return;
+ }
+ impl_->ContinueWebSocketRequest(connection_id_, request_info_, true);
+ impl_ = nullptr;
+ }
+
+ void Cancel() override {
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ CEF_POST_TASK(CEF_UIT,
+ base::BindOnce(&AcceptWebSocketCallback::Cancel, this));
+ return;
+ }
+ if (!impl_) {
+ return;
+ }
+ impl_->ContinueWebSocketRequest(connection_id_, request_info_, false);
+ impl_ = nullptr;
+ }
+
+ private:
+ CefRefPtr<CefServerImpl> impl_;
+ int connection_id_;
+ net::HttpServerRequestInfo request_info_;
+
+ IMPLEMENT_REFCOUNTING_DELETE_ON_UIT(AcceptWebSocketCallback);
+};
+
+} // namespace
+
+// CefServer
+
+// static
+void CefServer::CreateServer(const CefString& address,
+ uint16 port,
+ int backlog,
+ CefRefPtr<CefServerHandler> handler) {
+ CefRefPtr<CefServerImpl> server(new CefServerImpl(handler));
+ server->Start(address, port, backlog);
+}
+
+// CefServerImpl
+
+struct CefServerImpl::ConnectionInfo {
+ ConnectionInfo() : is_websocket(false), is_websocket_pending(false) {}
+
+ // True if this connection is a WebSocket connection.
+ bool is_websocket;
+ bool is_websocket_pending;
+};
+
+CefServerImpl::CefServerImpl(CefRefPtr<CefServerHandler> handler)
+ : handler_(handler) {
+ DCHECK(handler_);
+}
+
+void CefServerImpl::Start(const std::string& address,
+ uint16 port,
+ int backlog) {
+ DCHECK(!address.empty());
+ CEF_POST_TASK(CEF_UIT, base::BindOnce(&CefServerImpl::StartOnUIThread, this,
+ address, port, backlog));
+}
+
+CefRefPtr<CefTaskRunner> CefServerImpl::GetTaskRunner() {
+ if (task_runner_) {
+ return new CefTaskRunnerImpl(task_runner_);
+ }
+ return nullptr;
+}
+
+void CefServerImpl::Shutdown() {
+ CEF_POST_TASK_HT(
+ base::BindOnce(&CefServerImpl::ShutdownOnHandlerThread, this));
+}
+
+bool CefServerImpl::IsRunning() {
+ CEF_REQUIRE_HT_RETURN(false);
+ return !!server_.get();
+}
+
+CefString CefServerImpl::GetAddress() {
+ return address_;
+}
+
+bool CefServerImpl::HasConnection() {
+ CEF_REQUIRE_HT_RETURN(false);
+ return !connection_info_map_.empty();
+}
+
+bool CefServerImpl::IsValidConnection(int connection_id) {
+ CEF_REQUIRE_HT_RETURN(false);
+ return connection_info_map_.find(connection_id) != connection_info_map_.end();
+}
+
+void CefServerImpl::SendHttp200Response(int connection_id,
+ const CefString& content_type,
+ const void* data,
+ size_t data_size) {
+ SendHttp200ResponseInternal(connection_id, content_type,
+ CreateUniqueString(data, data_size));
+}
+
+void CefServerImpl::SendHttp404Response(int connection_id) {
+ if (!CEF_CURRENTLY_ON_HT()) {
+ CEF_POST_TASK_HT(base::BindOnce(&CefServerImpl::SendHttp404Response, this,
+ connection_id));
+ return;
+ }
+
+ if (!ValidateServer()) {
+ return;
+ }
+
+ ConnectionInfo* info = GetConnectionInfo(connection_id);
+ if (!info) {
+ return;
+ }
+
+ if (info->is_websocket) {
+ LOG(ERROR) << "Invalid attempt to send HTTP response for connection_id "
+ << connection_id;
+ return;
+ }
+
+ server_->Send404(connection_id, MISSING_TRAFFIC_ANNOTATION);
+ server_->Close(connection_id);
+}
+
+void CefServerImpl::SendHttp500Response(int connection_id,
+ const CefString& error_message) {
+ if (!CEF_CURRENTLY_ON_HT()) {
+ CEF_POST_TASK_HT(base::BindOnce(&CefServerImpl::SendHttp500Response, this,
+ connection_id, error_message));
+ return;
+ }
+
+ if (!ValidateServer()) {
+ return;
+ }
+
+ ConnectionInfo* info = GetConnectionInfo(connection_id);
+ if (!info) {
+ return;
+ }
+
+ if (info->is_websocket) {
+ LOG(ERROR) << "Invalid attempt to send HTTP response for connection_id "
+ << connection_id;
+ return;
+ }
+
+ server_->Send500(connection_id, error_message, MISSING_TRAFFIC_ANNOTATION);
+ server_->Close(connection_id);
+}
+
+void CefServerImpl::SendHttpResponse(int connection_id,
+ int response_code,
+ const CefString& content_type,
+ int64 content_length,
+ const HeaderMap& extra_headers) {
+ if (!CEF_CURRENTLY_ON_HT()) {
+ CEF_POST_TASK_HT(base::BindOnce(&CefServerImpl::SendHttpResponse, this,
+ connection_id, response_code, content_type,
+ content_length, extra_headers));
+ return;
+ }
+
+ if (!ValidateServer()) {
+ return;
+ }
+
+ ConnectionInfo* info = GetConnectionInfo(connection_id);
+ if (!info) {
+ return;
+ }
+
+ if (info->is_websocket) {
+ LOG(ERROR) << "Invalid attempt to send HTTP response for connection_id "
+ << connection_id;
+ return;
+ }
+
+ net::HttpServerResponseInfo response(
+ static_cast<net::HttpStatusCode>(response_code));
+
+ HeaderMap::const_iterator it = extra_headers.begin();
+ for (; it != extra_headers.end(); ++it) {
+ response.AddHeader(it->first, it->second);
+ }
+
+ response.AddHeader(net::HttpRequestHeaders::kContentType, content_type);
+ if (content_length >= 0) {
+ response.AddHeader(
+ net::HttpRequestHeaders::kContentLength,
+ base::StringPrintf("%" PRIuS, static_cast<size_t>(content_length)));
+ }
+
+ server_->SendResponse(connection_id, response, MISSING_TRAFFIC_ANNOTATION);
+ if (content_length == 0) {
+ server_->Close(connection_id);
+ }
+}
+
+void CefServerImpl::SendRawData(int connection_id,
+ const void* data,
+ size_t data_size) {
+ if (!data || data_size == 0) {
+ return;
+ }
+ SendRawDataInternal(connection_id, CreateUniqueString(data, data_size));
+}
+
+void CefServerImpl::CloseConnection(int connection_id) {
+ if (!CEF_CURRENTLY_ON_HT()) {
+ CEF_POST_TASK_HT(
+ base::BindOnce(&CefServerImpl::CloseConnection, this, connection_id));
+ return;
+ }
+
+ if (ValidateServer() && GetConnectionInfo(connection_id)) {
+ server_->Close(connection_id);
+ }
+}
+
+void CefServerImpl::SendWebSocketMessage(int connection_id,
+ const void* data,
+ size_t data_size) {
+ if (!data || data_size == 0) {
+ return;
+ }
+ SendWebSocketMessageInternal(connection_id,
+ CreateUniqueString(data, data_size));
+}
+
+void CefServerImpl::ContinueWebSocketRequest(
+ int connection_id,
+ const net::HttpServerRequestInfo& request_info,
+ bool allow) {
+ if (!CEF_CURRENTLY_ON_HT()) {
+ CEF_POST_TASK_HT(base::BindOnce(&CefServerImpl::ContinueWebSocketRequest,
+ this, connection_id, request_info, allow));
+ return;
+ }
+
+ if (!ValidateServer()) {
+ return;
+ }
+
+ ConnectionInfo* info = GetConnectionInfo(connection_id);
+ DCHECK(info);
+ if (!info) {
+ return;
+ }
+
+ DCHECK(info->is_websocket);
+ DCHECK(info->is_websocket_pending);
+ if (!info->is_websocket || !info->is_websocket_pending) {
+ return;
+ }
+
+ info->is_websocket_pending = false;
+
+ if (allow) {
+ server_->AcceptWebSocket(connection_id, request_info,
+ MISSING_TRAFFIC_ANNOTATION);
+ handler_->OnWebSocketConnected(this, connection_id);
+ } else {
+ server_->Close(connection_id);
+ }
+}
+
+void CefServerImpl::SendHttp200ResponseInternal(
+ int connection_id,
+ const CefString& content_type,
+ std::unique_ptr<std::string> data) {
+ if (!CEF_CURRENTLY_ON_HT()) {
+ CEF_POST_TASK_HT(base::BindOnce(&CefServerImpl::SendHttp200ResponseInternal,
+ this, connection_id, content_type,
+ std::move(data)));
+ return;
+ }
+
+ if (!ValidateServer()) {
+ return;
+ }
+
+ ConnectionInfo* info = GetConnectionInfo(connection_id);
+ if (!info) {
+ return;
+ }
+
+ if (info->is_websocket) {
+ LOG(ERROR) << "Invalid attempt to send HTTP response for connection_id "
+ << connection_id;
+ return;
+ }
+
+ server_->Send200(connection_id, *data, content_type,
+ MISSING_TRAFFIC_ANNOTATION);
+ server_->Close(connection_id);
+}
+
+void CefServerImpl::SendRawDataInternal(int connection_id,
+ std::unique_ptr<std::string> data) {
+ if (!CEF_CURRENTLY_ON_HT()) {
+ CEF_POST_TASK_HT(base::BindOnce(&CefServerImpl::SendRawDataInternal, this,
+ connection_id, std::move(data)));
+ return;
+ }
+
+ if (!ValidateServer()) {
+ return;
+ }
+
+ if (!GetConnectionInfo(connection_id)) {
+ return;
+ }
+
+ server_->SendRaw(connection_id, *data, MISSING_TRAFFIC_ANNOTATION);
+}
+
+void CefServerImpl::SendWebSocketMessageInternal(
+ int connection_id,
+ std::unique_ptr<std::string> data) {
+ if (!CEF_CURRENTLY_ON_HT()) {
+ CEF_POST_TASK_HT(
+ base::BindOnce(&CefServerImpl::SendWebSocketMessageInternal, this,
+ connection_id, std::move(data)));
+ return;
+ }
+
+ if (!ValidateServer()) {
+ return;
+ }
+
+ ConnectionInfo* info = GetConnectionInfo(connection_id);
+ if (!info) {
+ return;
+ }
+
+ if (!info->is_websocket || info->is_websocket_pending) {
+ LOG(ERROR) << "Invalid attempt to send WebSocket message for connection_id "
+ << connection_id;
+ return;
+ }
+
+ server_->SendOverWebSocket(connection_id, *data, MISSING_TRAFFIC_ANNOTATION);
+}
+
+void CefServerImpl::OnConnect(int connection_id) {
+ CEF_REQUIRE_HT();
+
+ CreateConnectionInfo(connection_id);
+ handler_->OnClientConnected(this, connection_id);
+}
+
+void CefServerImpl::OnHttpRequest(
+ int connection_id,
+ const net::HttpServerRequestInfo& request_info) {
+ CEF_REQUIRE_HT();
+
+ ConnectionInfo* info = GetConnectionInfo(connection_id);
+ DCHECK(info);
+ if (!info) {
+ return;
+ }
+
+ DCHECK(!info->is_websocket);
+
+ handler_->OnHttpRequest(this, connection_id, request_info.peer.ToString(),
+ CreateRequest(address_, request_info, false));
+}
+
+void CefServerImpl::OnWebSocketRequest(
+ int connection_id,
+ const net::HttpServerRequestInfo& request_info) {
+ CEF_REQUIRE_HT();
+
+ ConnectionInfo* info = GetConnectionInfo(connection_id);
+ DCHECK(info);
+ if (!info) {
+ return;
+ }
+
+ DCHECK(!info->is_websocket);
+ info->is_websocket = true;
+ info->is_websocket_pending = true;
+
+ // Will eventually result in a call to ContinueWebSocketRequest.
+ CefRefPtr<CefCallback> callback =
+ new AcceptWebSocketCallback(this, connection_id, request_info);
+ handler_->OnWebSocketRequest(
+ this, connection_id, request_info.peer.ToString(),
+ CreateRequest(address_, request_info, true), callback);
+}
+
+void CefServerImpl::OnWebSocketMessage(int connection_id, std::string data) {
+ CEF_REQUIRE_HT();
+
+ ConnectionInfo* info = GetConnectionInfo(connection_id);
+ if (!info) {
+ return;
+ }
+
+ DCHECK(info->is_websocket);
+ DCHECK(!info->is_websocket_pending);
+
+ handler_->OnWebSocketMessage(this, connection_id, data.data(), data.size());
+}
+
+void CefServerImpl::OnClose(int connection_id) {
+ CEF_REQUIRE_HT();
+
+ RemoveConnectionInfo(connection_id);
+ handler_->OnClientDisconnected(this, connection_id);
+}
+
+void CefServerImpl::StartOnUIThread(const std::string& address,
+ uint16 port,
+ int backlog) {
+ CEF_REQUIRE_UIT();
+ DCHECK(!thread_);
+
+ std::unique_ptr<base::Thread> thread(
+ new base::Thread(base::StringPrintf("%s:%d", address.c_str(), port)));
+ base::Thread::Options options;
+ options.message_pump_type = base::MessagePumpType::IO;
+ if (thread->StartWithOptions(std::move(options))) {
+ // Add a reference that will be released in ShutdownOnUIThread().
+ AddRef();
+
+ thread_ = std::move(thread);
+ task_runner_ = thread_->task_runner();
+
+ CEF_POST_TASK_HT(base::BindOnce(&CefServerImpl::StartOnHandlerThread, this,
+ address, port, backlog));
+ }
+}
+
+void CefServerImpl::StartOnHandlerThread(const std::string& address,
+ uint16 port,
+ int backlog) {
+ CEF_REQUIRE_HT();
+
+ std::unique_ptr<net::ServerSocket> socket(
+ new net::TCPServerSocket(nullptr, net::NetLogSource()));
+ if (socket->ListenWithAddressAndPort(address, port, backlog) == net::OK) {
+ server_.reset(new net::HttpServer(std::move(socket), this));
+
+ net::IPEndPoint ip_address;
+ if (server_->GetLocalAddress(&ip_address) == net::OK) {
+ address_ = ip_address.ToString();
+ }
+ }
+
+ handler_->OnServerCreated(this);
+
+ if (!server_) {
+ // Server failed to start.
+ handler_->OnServerDestroyed(this);
+
+ CEF_POST_TASK(CEF_UIT,
+ base::BindOnce(&CefServerImpl::ShutdownOnUIThread, this));
+ }
+}
+
+void CefServerImpl::ShutdownOnHandlerThread() {
+ CEF_REQUIRE_HT();
+
+ if (server_) {
+ // Stop the server.
+ server_.reset();
+
+ if (!connection_info_map_.empty()) {
+ // Clear |connection_info_map_| first so any calls from
+ // OnClientDisconnected will fail as expected.
+ ConnectionInfoMap temp_map;
+ temp_map.swap(connection_info_map_);
+
+ // OnClose won't be called for clients that are connected when the server
+ // shuts down, so send the disconnected notification here.
+ ConnectionInfoMap::const_iterator it = temp_map.begin();
+ for (; it != temp_map.end(); ++it) {
+ handler_->OnClientDisconnected(this, it->first);
+ }
+ }
+
+ handler_->OnServerDestroyed(this);
+ }
+
+ CEF_POST_TASK(CEF_UIT,
+ base::BindOnce(&CefServerImpl::ShutdownOnUIThread, this));
+}
+
+void CefServerImpl::ShutdownOnUIThread() {
+ CEF_REQUIRE_UIT();
+
+ handler_ = nullptr;
+
+ if (thread_) {
+ // Stop the handler thread as a background task so the UI thread isn't
+ // blocked.
+ auto task = base::BindOnce(
+ [](std::unique_ptr<base::Thread> thread) {
+ // Calling PlatformThread::Join() on the UI thread is otherwise
+ // disallowed.
+ base::ScopedAllowBaseSyncPrimitivesForTesting
+ scoped_allow_sync_primitives;
+ thread.reset();
+ },
+ std::move(thread_));
+
+ // Make sure the task is executed on shutdown. Otherwise, |thread| might
+ // be released outside of the correct scope.
+ base::ThreadPool::PostTask(
+ FROM_HERE,
+ {base::TaskPriority::BEST_EFFORT,
+ base::TaskShutdownBehavior::BLOCK_SHUTDOWN, base::MayBlock()},
+ std::move(task));
+
+ // Release the reference that was added in StartupOnUIThread().
+ Release();
+ }
+}
+
+bool CefServerImpl::ValidateServer() const {
+ CEF_REQUIRE_HT();
+ if (!server_) {
+ LOG(ERROR) << "Server is not running";
+ return false;
+ }
+ return true;
+}
+
+CefServerImpl::ConnectionInfo* CefServerImpl::CreateConnectionInfo(
+ int connection_id) {
+ CEF_REQUIRE_HT();
+
+#if DCHECK_IS_ON()
+ ConnectionInfoMap::const_iterator it =
+ connection_info_map_.find(connection_id);
+ DCHECK(it == connection_info_map_.end());
+#endif
+
+ ConnectionInfo* info = new ConnectionInfo();
+ connection_info_map_.insert(
+ std::make_pair(connection_id, base::WrapUnique(info)));
+ return info;
+}
+
+CefServerImpl::ConnectionInfo* CefServerImpl::GetConnectionInfo(
+ int connection_id) const {
+ CEF_REQUIRE_HT();
+ ConnectionInfoMap::const_iterator it =
+ connection_info_map_.find(connection_id);
+ if (it != connection_info_map_.end()) {
+ return it->second.get();
+ }
+
+ LOG(ERROR) << "Invalid connection_id " << connection_id;
+ return nullptr;
+}
+
+void CefServerImpl::RemoveConnectionInfo(int connection_id) {
+ CEF_REQUIRE_HT();
+ ConnectionInfoMap::iterator it = connection_info_map_.find(connection_id);
+ DCHECK(it != connection_info_map_.end());
+ if (it != connection_info_map_.end()) {
+ connection_info_map_.erase(it);
+ }
+}
+
+bool CefServerImpl::CurrentlyOnHandlerThread() const {
+ return task_runner_ && task_runner_->BelongsToCurrentThread();
+}
diff --git a/libcef/browser/server_impl.h b/libcef/browser/server_impl.h
new file mode 100644
index 00000000..59fb8260
--- /dev/null
+++ b/libcef/browser/server_impl.h
@@ -0,0 +1,115 @@
+// Copyright (c) 2017 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_SERVER_IMPL_H_
+#define CEF_LIBCEF_BROWSER_SERVER_IMPL_H_
+#pragma once
+
+#include <map>
+#include <memory>
+
+#include "include/cef_server.h"
+
+#include "base/task/single_thread_task_runner.h"
+#include "net/server/http_server.h"
+
+namespace base {
+class Thread;
+}
+
+class CefServerImpl : public CefServer, net::HttpServer::Delegate {
+ public:
+ explicit CefServerImpl(CefRefPtr<CefServerHandler> handler);
+
+ CefServerImpl(const CefServerImpl&) = delete;
+ CefServerImpl& operator=(const CefServerImpl&) = delete;
+
+ void Start(const std::string& address, uint16 port, int backlog);
+
+ // CefServer methods:
+ CefRefPtr<CefTaskRunner> GetTaskRunner() override;
+ void Shutdown() override;
+ bool IsRunning() override;
+ CefString GetAddress() override;
+ bool HasConnection() override;
+ bool IsValidConnection(int connection_id) override;
+ void SendHttp200Response(int connection_id,
+ const CefString& content_type,
+ const void* data,
+ size_t data_size) override;
+ void SendHttp404Response(int connection_id) override;
+ void SendHttp500Response(int connection_id,
+ const CefString& error_message) override;
+ void SendHttpResponse(int connection_id,
+ int response_code,
+ const CefString& content_type,
+ int64 content_length,
+ const HeaderMap& extra_headers) override;
+ void SendRawData(int connection_id,
+ const void* data,
+ size_t data_size) override;
+ void CloseConnection(int connection_id) override;
+ void SendWebSocketMessage(int connection_id,
+ const void* data,
+ size_t data_size) override;
+
+ void ContinueWebSocketRequest(int connection_id,
+ const net::HttpServerRequestInfo& request_info,
+ bool allow);
+
+ private:
+ void SendHttp200ResponseInternal(int connection_id,
+ const CefString& content_type,
+ std::unique_ptr<std::string> data);
+ void SendRawDataInternal(int connection_id,
+ std::unique_ptr<std::string> data);
+ void SendWebSocketMessageInternal(int connection_id,
+ std::unique_ptr<std::string> data);
+
+ // HttpServer::Delegate methods:
+ void OnConnect(int connection_id) override;
+ void OnHttpRequest(int connection_id,
+ const net::HttpServerRequestInfo& request_info) override;
+ void OnWebSocketRequest(
+ int connection_id,
+ const net::HttpServerRequestInfo& request_info) override;
+ void OnWebSocketMessage(int connection_id, std::string data) override;
+ void OnClose(int connection_id) override;
+
+ void StartOnUIThread(const std::string& address, uint16 port, int backlog);
+ void StartOnHandlerThread(const std::string& address,
+ uint16 port,
+ int backlog);
+
+ void ShutdownOnHandlerThread();
+ void ShutdownOnUIThread();
+
+ bool ValidateServer() const;
+
+ struct ConnectionInfo;
+ ConnectionInfo* CreateConnectionInfo(int connection_id);
+ ConnectionInfo* GetConnectionInfo(int connection_id) const;
+ void RemoveConnectionInfo(int connection_id);
+
+ bool CurrentlyOnHandlerThread() const;
+
+ // Safe to access from any thread.
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+ std::string address_;
+
+ // Only accessed on the UI thread.
+ std::unique_ptr<base::Thread> thread_;
+
+ // Only accessed on the server thread.
+ CefRefPtr<CefServerHandler> handler_;
+ std::unique_ptr<net::HttpServer> server_;
+
+ // Map of connection_id to ConnectionInfo.
+ using ConnectionInfoMap = std::map<int, std::unique_ptr<ConnectionInfo>>;
+ ConnectionInfoMap connection_info_map_;
+
+ IMPLEMENT_REFCOUNTING(CefServerImpl);
+};
+
+#endif // CEF_LIBCEF_BROWSER_SERVER_IMPL_H_
diff --git a/libcef/browser/simple_menu_model_impl.cc b/libcef/browser/simple_menu_model_impl.cc
new file mode 100644
index 00000000..917082ad
--- /dev/null
+++ b/libcef/browser/simple_menu_model_impl.cc
@@ -0,0 +1,570 @@
+// Copyright (c) 2021 The Chromium Embedded Framework Authors.
+// Portions copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/simple_menu_model_impl.h"
+
+#include <vector>
+
+#include "libcef/browser/thread_util.h"
+#include "libcef/common/task_runner_impl.h"
+
+namespace {
+
+// Value based on the documentation on SimpleMenuModel::GetIndexOfCommandId().
+const int kInvalidIndex = -1;
+const int kInvalidCommandId = -1;
+const int kInvalidGroupId = -1;
+
+cef_menu_item_type_t GetCefItemType(ui::MenuModel::ItemType type) {
+ switch (type) {
+ case ui::MenuModel::TYPE_COMMAND:
+ return MENUITEMTYPE_COMMAND;
+ case ui::MenuModel::TYPE_CHECK:
+ return MENUITEMTYPE_CHECK;
+ case ui::MenuModel::TYPE_RADIO:
+ return MENUITEMTYPE_RADIO;
+ case ui::MenuModel::TYPE_SEPARATOR:
+ return MENUITEMTYPE_SEPARATOR;
+ case ui::MenuModel::TYPE_SUBMENU:
+ return MENUITEMTYPE_SUBMENU;
+ default:
+ return MENUITEMTYPE_NONE;
+ }
+}
+
+} // namespace
+
+CefSimpleMenuModelImpl::CefSimpleMenuModelImpl(
+ ui::SimpleMenuModel* model,
+ ui::SimpleMenuModel::Delegate* delegate,
+ StateDelegate* state_delegate,
+ bool is_owned,
+ bool is_submenu)
+ : supported_thread_id_(base::PlatformThread::CurrentId()),
+ model_(model),
+ delegate_(delegate),
+ state_delegate_(state_delegate),
+ is_owned_(is_owned),
+ is_submenu_(is_submenu) {
+ DCHECK(model_);
+ DCHECK(delegate_);
+ DCHECK(state_delegate_);
+}
+
+CefSimpleMenuModelImpl::~CefSimpleMenuModelImpl() {
+ // Detach() must be called before object destruction.
+ DCHECK(!model_);
+ DCHECK(submenumap_.empty());
+}
+
+void CefSimpleMenuModelImpl::Detach() {
+ DCHECK(VerifyContext());
+
+ if (!submenumap_.empty()) {
+ auto it = submenumap_.begin();
+ for (; it != submenumap_.end(); ++it) {
+ it->second->Detach();
+ }
+ submenumap_.clear();
+ }
+
+ if (is_owned_) {
+ delete model_;
+ }
+ model_ = nullptr;
+}
+
+bool CefSimpleMenuModelImpl::IsSubMenu() {
+ if (!VerifyContext()) {
+ return false;
+ }
+ return is_submenu_;
+}
+
+bool CefSimpleMenuModelImpl::Clear() {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ model_->Clear();
+ return true;
+}
+
+size_t CefSimpleMenuModelImpl::GetCount() {
+ if (!VerifyContext()) {
+ return 0;
+ }
+
+ return model_->GetItemCount();
+}
+
+bool CefSimpleMenuModelImpl::AddSeparator() {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ model_->AddSeparator(ui::NORMAL_SEPARATOR);
+ return true;
+}
+
+bool CefSimpleMenuModelImpl::AddItem(int command_id, const CefString& label) {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ model_->AddItem(command_id, label);
+ return true;
+}
+
+bool CefSimpleMenuModelImpl::AddCheckItem(int command_id,
+ const CefString& label) {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ model_->AddCheckItem(command_id, label);
+ return true;
+}
+
+bool CefSimpleMenuModelImpl::AddRadioItem(int command_id,
+ const CefString& label,
+ int group_id) {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ model_->AddRadioItem(command_id, label, group_id);
+ return true;
+}
+
+CefRefPtr<CefMenuModel> CefSimpleMenuModelImpl::AddSubMenu(
+ int command_id,
+ const CefString& label) {
+ if (!VerifyContext()) {
+ return nullptr;
+ }
+
+ auto new_menu = CreateNewSubMenu(nullptr);
+ model_->AddSubMenu(command_id, label, new_menu->model());
+ return new_menu;
+}
+
+bool CefSimpleMenuModelImpl::InsertSeparatorAt(size_t index) {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ model_->InsertSeparatorAt(index, ui::NORMAL_SEPARATOR);
+ return true;
+}
+
+bool CefSimpleMenuModelImpl::InsertItemAt(size_t index,
+ int command_id,
+ const CefString& label) {
+ if (!VerifyContext() || !ValidIndex(index)) {
+ return false;
+ }
+
+ model_->InsertItemAt(index, command_id, label);
+ return true;
+}
+
+bool CefSimpleMenuModelImpl::InsertCheckItemAt(size_t index,
+ int command_id,
+ const CefString& label) {
+ if (!VerifyContext() || !ValidIndex(index)) {
+ return false;
+ }
+
+ model_->InsertCheckItemAt(index, command_id, label);
+ return true;
+}
+
+bool CefSimpleMenuModelImpl::InsertRadioItemAt(size_t index,
+ int command_id,
+ const CefString& label,
+ int group_id) {
+ if (!VerifyContext() || !ValidIndex(index)) {
+ return false;
+ }
+
+ model_->InsertRadioItemAt(index, command_id, label, group_id);
+ return true;
+}
+
+CefRefPtr<CefMenuModel> CefSimpleMenuModelImpl::InsertSubMenuAt(
+ size_t index,
+ int command_id,
+ const CefString& label) {
+ if (!VerifyContext() || !ValidIndex(index)) {
+ return nullptr;
+ }
+
+ auto new_menu = CreateNewSubMenu(nullptr);
+ model_->InsertSubMenuAt(index, command_id, label, new_menu->model());
+ return new_menu;
+}
+
+bool CefSimpleMenuModelImpl::Remove(int command_id) {
+ return RemoveAt(GetIndexOf(command_id));
+}
+
+bool CefSimpleMenuModelImpl::RemoveAt(size_t index) {
+ if (!VerifyContext() || !ValidIndex(index)) {
+ return false;
+ }
+
+ auto* sub_menu =
+ static_cast<ui::SimpleMenuModel*>(model_->GetSubmenuModelAt(index));
+ if (sub_menu) {
+ auto it = submenumap_.find(sub_menu);
+ if (it != submenumap_.end()) {
+ it->second->Detach();
+ submenumap_.erase(it);
+ }
+ }
+
+ model_->RemoveItemAt(index);
+ return true;
+}
+
+int CefSimpleMenuModelImpl::GetIndexOf(int command_id) {
+ if (!VerifyContext()) {
+ return kInvalidIndex;
+ }
+
+ auto index = model_->GetIndexOfCommandId(command_id);
+ if (index.has_value()) {
+ return static_cast<int>(*index);
+ }
+ return -1;
+}
+
+int CefSimpleMenuModelImpl::GetCommandIdAt(size_t index) {
+ if (!VerifyContext() || !ValidIndex(index)) {
+ return kInvalidCommandId;
+ }
+
+ return model_->GetCommandIdAt(index);
+}
+
+bool CefSimpleMenuModelImpl::SetCommandIdAt(size_t index, int command_id) {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+CefString CefSimpleMenuModelImpl::GetLabel(int command_id) {
+ return GetLabelAt(GetIndexOf(command_id));
+}
+
+CefString CefSimpleMenuModelImpl::GetLabelAt(size_t index) {
+ if (!VerifyContext() || !ValidIndex(index)) {
+ return CefString();
+ }
+
+ return model_->GetLabelAt(index);
+}
+
+bool CefSimpleMenuModelImpl::SetLabel(int command_id, const CefString& label) {
+ return SetLabelAt(GetIndexOf(command_id), label);
+}
+
+bool CefSimpleMenuModelImpl::SetLabelAt(size_t index, const CefString& label) {
+ if (!VerifyContext() || !ValidIndex(index)) {
+ return false;
+ }
+
+ model_->SetLabel(index, label);
+ return true;
+}
+
+CefSimpleMenuModelImpl::MenuItemType CefSimpleMenuModelImpl::GetType(
+ int command_id) {
+ return GetTypeAt(GetIndexOf(command_id));
+}
+
+CefSimpleMenuModelImpl::MenuItemType CefSimpleMenuModelImpl::GetTypeAt(
+ size_t index) {
+ if (!VerifyContext() || !ValidIndex(index)) {
+ return MENUITEMTYPE_NONE;
+ }
+
+ return GetCefItemType(model_->GetTypeAt(index));
+}
+
+int CefSimpleMenuModelImpl::GetGroupId(int command_id) {
+ return GetGroupIdAt(GetIndexOf(command_id));
+}
+
+int CefSimpleMenuModelImpl::GetGroupIdAt(size_t index) {
+ if (!VerifyContext() || !ValidIndex(index)) {
+ return kInvalidGroupId;
+ }
+
+ return model_->GetGroupIdAt(index);
+}
+
+bool CefSimpleMenuModelImpl::SetGroupId(int command_id, int group_id) {
+ return SetGroupIdAt(GetIndexOf(command_id), group_id);
+}
+
+bool CefSimpleMenuModelImpl::SetGroupIdAt(size_t index, int group_id) {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+CefRefPtr<CefMenuModel> CefSimpleMenuModelImpl::GetSubMenu(int command_id) {
+ return GetSubMenuAt(GetIndexOf(command_id));
+}
+
+CefRefPtr<CefMenuModel> CefSimpleMenuModelImpl::GetSubMenuAt(size_t index) {
+ if (!VerifyContext() || !ValidIndex(index)) {
+ return nullptr;
+ }
+
+ auto* sub_model =
+ static_cast<ui::SimpleMenuModel*>(model_->GetSubmenuModelAt(index));
+ auto it = submenumap_.find(sub_model);
+ if (it != submenumap_.end()) {
+ return it->second;
+ }
+ return CreateNewSubMenu(sub_model);
+}
+
+bool CefSimpleMenuModelImpl::IsVisible(int command_id) {
+ return IsVisibleAt(GetIndexOf(command_id));
+}
+
+bool CefSimpleMenuModelImpl::IsVisibleAt(size_t index) {
+ if (!VerifyContext() || !ValidIndex(index)) {
+ return false;
+ }
+
+ return model_->IsVisibleAt(index);
+}
+
+bool CefSimpleMenuModelImpl::SetVisible(int command_id, bool visible) {
+ return SetVisibleAt(GetIndexOf(command_id), visible);
+}
+
+bool CefSimpleMenuModelImpl::SetVisibleAt(size_t index, bool visible) {
+ if (!VerifyContext() || !ValidIndex(index)) {
+ return false;
+ }
+
+ model_->SetVisibleAt(index, visible);
+ return true;
+}
+
+bool CefSimpleMenuModelImpl::IsEnabled(int command_id) {
+ return IsEnabledAt(GetIndexOf(command_id));
+}
+
+bool CefSimpleMenuModelImpl::IsEnabledAt(size_t index) {
+ if (!VerifyContext() || !ValidIndex(index)) {
+ return false;
+ }
+
+ return model_->IsEnabledAt(index);
+}
+
+bool CefSimpleMenuModelImpl::SetEnabled(int command_id, bool enabled) {
+ return SetEnabledAt(GetIndexOf(command_id), enabled);
+}
+
+bool CefSimpleMenuModelImpl::SetEnabledAt(size_t index, bool enabled) {
+ if (!VerifyContext() || !ValidIndex(index)) {
+ return false;
+ }
+
+ model_->SetEnabledAt(index, enabled);
+ return true;
+}
+
+bool CefSimpleMenuModelImpl::IsChecked(int command_id) {
+ return IsCheckedAt(GetIndexOf(command_id));
+}
+
+bool CefSimpleMenuModelImpl::IsCheckedAt(size_t index) {
+ if (!VerifyContext() || !ValidIndex(index)) {
+ return false;
+ }
+
+ return model_->IsItemCheckedAt(index);
+}
+
+bool CefSimpleMenuModelImpl::SetChecked(int command_id, bool checked) {
+ if (!VerifyContext() || command_id == kInvalidIndex) {
+ return false;
+ }
+
+ state_delegate_->SetChecked(command_id, checked);
+ return true;
+}
+
+bool CefSimpleMenuModelImpl::SetCheckedAt(size_t index, bool checked) {
+ return SetChecked(GetCommandIdAt(index), checked);
+}
+
+bool CefSimpleMenuModelImpl::HasAccelerator(int command_id) {
+ return HasAcceleratorAt(GetIndexOf(command_id));
+}
+
+bool CefSimpleMenuModelImpl::HasAcceleratorAt(size_t index) {
+ if (!VerifyContext() || !ValidIndex(index)) {
+ return false;
+ }
+
+ ui::Accelerator accelerator;
+ return model_->GetAcceleratorAt(index, &accelerator);
+}
+
+bool CefSimpleMenuModelImpl::SetAccelerator(int command_id,
+ int key_code,
+ bool shift_pressed,
+ bool ctrl_pressed,
+ bool alt_pressed) {
+ if (!VerifyContext() || command_id == kInvalidIndex) {
+ return false;
+ }
+
+ int modifiers = 0;
+ if (shift_pressed) {
+ modifiers |= ui::EF_SHIFT_DOWN;
+ }
+ if (ctrl_pressed) {
+ modifiers |= ui::EF_CONTROL_DOWN;
+ }
+ if (alt_pressed) {
+ modifiers |= ui::EF_ALT_DOWN;
+ }
+
+ state_delegate_->SetAccelerator(
+ command_id,
+ ui::Accelerator(static_cast<ui::KeyboardCode>(key_code), modifiers));
+ return true;
+}
+
+bool CefSimpleMenuModelImpl::SetAcceleratorAt(size_t index,
+ int key_code,
+ bool shift_pressed,
+ bool ctrl_pressed,
+ bool alt_pressed) {
+ return SetAccelerator(GetCommandIdAt(index), key_code, shift_pressed,
+ ctrl_pressed, alt_pressed);
+}
+
+bool CefSimpleMenuModelImpl::RemoveAccelerator(int command_id) {
+ if (!VerifyContext() || command_id == kInvalidIndex) {
+ return false;
+ }
+ state_delegate_->SetAccelerator(command_id, absl::nullopt);
+ return true;
+}
+
+bool CefSimpleMenuModelImpl::RemoveAcceleratorAt(size_t index) {
+ return RemoveAccelerator(GetCommandIdAt(index));
+}
+
+bool CefSimpleMenuModelImpl::GetAccelerator(int command_id,
+ int& key_code,
+ bool& shift_pressed,
+ bool& ctrl_pressed,
+ bool& alt_pressed) {
+ return GetAcceleratorAt(GetIndexOf(command_id), key_code, shift_pressed,
+ ctrl_pressed, alt_pressed);
+}
+
+bool CefSimpleMenuModelImpl::GetAcceleratorAt(size_t index,
+ int& key_code,
+ bool& shift_pressed,
+ bool& ctrl_pressed,
+ bool& alt_pressed) {
+ if (!VerifyContext() || !ValidIndex(index)) {
+ return false;
+ }
+
+ ui::Accelerator accel;
+ if (model_->GetAcceleratorAt(index, &accel)) {
+ key_code = accel.key_code();
+ shift_pressed = accel.modifiers() & ui::EF_SHIFT_DOWN;
+ ctrl_pressed = accel.modifiers() & ui::EF_CONTROL_DOWN;
+ alt_pressed = accel.modifiers() & ui::EF_ALT_DOWN;
+ return true;
+ }
+ return false;
+}
+
+bool CefSimpleMenuModelImpl::SetColor(int command_id,
+ cef_menu_color_type_t color_type,
+ cef_color_t color) {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+bool CefSimpleMenuModelImpl::SetColorAt(int index,
+ cef_menu_color_type_t color_type,
+ cef_color_t color) {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+bool CefSimpleMenuModelImpl::GetColor(int command_id,
+ cef_menu_color_type_t color_type,
+ cef_color_t& color) {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+bool CefSimpleMenuModelImpl::GetColorAt(int index,
+ cef_menu_color_type_t color_type,
+ cef_color_t& color) {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+bool CefSimpleMenuModelImpl::SetFontList(int command_id,
+ const CefString& font_list) {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+bool CefSimpleMenuModelImpl::SetFontListAt(int index,
+ const CefString& font_list) {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+bool CefSimpleMenuModelImpl::VerifyContext() {
+ if (base::PlatformThread::CurrentId() != supported_thread_id_) {
+ // This object should only be accessed from the thread that created it.
+ NOTREACHED();
+ return false;
+ }
+
+ if (!model_) {
+ return false;
+ }
+
+ return true;
+}
+
+bool CefSimpleMenuModelImpl::ValidIndex(size_t index) {
+ return index < model_->GetItemCount();
+}
+
+CefRefPtr<CefSimpleMenuModelImpl> CefSimpleMenuModelImpl::CreateNewSubMenu(
+ ui::SimpleMenuModel* model) {
+ bool is_owned = false;
+ if (!model) {
+ model = new ui::SimpleMenuModel(delegate_);
+ is_owned = true;
+ }
+
+ CefRefPtr<CefSimpleMenuModelImpl> new_impl = new CefSimpleMenuModelImpl(
+ model, delegate_, state_delegate_, is_owned, /*is_submodel=*/true);
+ submenumap_.insert(std::make_pair(model, new_impl));
+ return new_impl;
+}
diff --git a/libcef/browser/simple_menu_model_impl.h b/libcef/browser/simple_menu_model_impl.h
new file mode 100644
index 00000000..00f348ac
--- /dev/null
+++ b/libcef/browser/simple_menu_model_impl.h
@@ -0,0 +1,172 @@
+// Copyright (c) 2021 The Chromium Embedded Framework Authors.
+// Portions copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_SIMPLE_MENU_MODEL_IMPL_H_
+#define CEF_LIBCEF_BROWSER_SIMPLE_MENU_MODEL_IMPL_H_
+#pragma once
+
+#include <vector>
+
+#include "include/cef_menu_model.h"
+
+#include "base/threading/platform_thread.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "ui/base/models/simple_menu_model.h"
+
+// Implementation of CefMenuModel that wraps an existing ui::SimpleMenuModel.
+class CefSimpleMenuModelImpl : public CefMenuModel {
+ public:
+ // Interface for setting state using CefMenuModel methods that will later be
+ // retrieved via the ui::SimpleMenuModel::Delegate implementation.
+ class StateDelegate {
+ public:
+ virtual void SetChecked(int command_id, bool checked) = 0;
+ virtual void SetAccelerator(int command_id,
+ absl::optional<ui::Accelerator> accel) = 0;
+
+ protected:
+ virtual ~StateDelegate() {}
+ };
+
+ // |delegate| should be the same that was used to create |model|.
+ // If |is_owned| is true then |model| will be deleted on Detach().
+ CefSimpleMenuModelImpl(ui::SimpleMenuModel* model,
+ ui::SimpleMenuModel::Delegate* delegate,
+ StateDelegate* state_delegate,
+ bool is_owned,
+ bool is_submenu);
+
+ CefSimpleMenuModelImpl(const CefSimpleMenuModelImpl&) = delete;
+ CefSimpleMenuModelImpl& operator=(const CefSimpleMenuModelImpl&) = delete;
+
+ ~CefSimpleMenuModelImpl() override;
+
+ // Must be called before the object is deleted.
+ void Detach();
+
+ // CefMenuModel methods.
+ bool IsSubMenu() override;
+ bool Clear() override;
+ size_t GetCount() override;
+ bool AddSeparator() override;
+ bool AddItem(int command_id, const CefString& label) override;
+ bool AddCheckItem(int command_id, const CefString& label) override;
+ bool AddRadioItem(int command_id,
+ const CefString& label,
+ int group_id) override;
+ CefRefPtr<CefMenuModel> AddSubMenu(int command_id,
+ const CefString& label) override;
+ bool InsertSeparatorAt(size_t index) override;
+ bool InsertItemAt(size_t index,
+ int command_id,
+ const CefString& label) override;
+ bool InsertCheckItemAt(size_t index,
+ int command_id,
+ const CefString& label) override;
+ bool InsertRadioItemAt(size_t index,
+ int command_id,
+ const CefString& label,
+ int group_id) override;
+ CefRefPtr<CefMenuModel> InsertSubMenuAt(size_t index,
+ int command_id,
+ const CefString& label) override;
+ bool Remove(int command_id) override;
+ bool RemoveAt(size_t index) override;
+ int GetIndexOf(int command_id) override;
+ int GetCommandIdAt(size_t index) override;
+ bool SetCommandIdAt(size_t index, int command_id) override;
+ CefString GetLabel(int command_id) override;
+ CefString GetLabelAt(size_t index) override;
+ bool SetLabel(int command_id, const CefString& label) override;
+ bool SetLabelAt(size_t index, const CefString& label) override;
+ MenuItemType GetType(int command_id) override;
+ MenuItemType GetTypeAt(size_t index) override;
+ int GetGroupId(int command_id) override;
+ int GetGroupIdAt(size_t index) override;
+ bool SetGroupId(int command_id, int group_id) override;
+ bool SetGroupIdAt(size_t index, int group_id) override;
+ CefRefPtr<CefMenuModel> GetSubMenu(int command_id) override;
+ CefRefPtr<CefMenuModel> GetSubMenuAt(size_t index) override;
+ bool IsVisible(int command_id) override;
+ bool IsVisibleAt(size_t index) override;
+ bool SetVisible(int command_id, bool visible) override;
+ bool SetVisibleAt(size_t index, bool visible) override;
+ bool IsEnabled(int command_id) override;
+ bool IsEnabledAt(size_t index) override;
+ bool SetEnabled(int command_id, bool enabled) override;
+ bool SetEnabledAt(size_t index, bool enabled) override;
+ bool IsChecked(int command_id) override;
+ bool IsCheckedAt(size_t index) override;
+ bool SetChecked(int command_id, bool checked) override;
+ bool SetCheckedAt(size_t index, bool checked) override;
+ bool HasAccelerator(int command_id) override;
+ bool HasAcceleratorAt(size_t index) override;
+ bool SetAccelerator(int command_id,
+ int key_code,
+ bool shift_pressed,
+ bool ctrl_pressed,
+ bool alt_pressed) override;
+ bool SetAcceleratorAt(size_t index,
+ int key_code,
+ bool shift_pressed,
+ bool ctrl_pressed,
+ bool alt_pressed) override;
+ bool RemoveAccelerator(int command_id) override;
+ bool RemoveAcceleratorAt(size_t index) override;
+ bool GetAccelerator(int command_id,
+ int& key_code,
+ bool& shift_pressed,
+ bool& ctrl_pressed,
+ bool& alt_pressed) override;
+ bool GetAcceleratorAt(size_t index,
+ int& key_code,
+ bool& shift_pressed,
+ bool& ctrl_pressed,
+ bool& alt_pressed) override;
+ bool SetColor(int command_id,
+ cef_menu_color_type_t color_type,
+ cef_color_t color) override;
+ bool SetColorAt(int index,
+ cef_menu_color_type_t color_type,
+ cef_color_t color) override;
+ bool GetColor(int command_id,
+ cef_menu_color_type_t color_type,
+ cef_color_t& color) override;
+ bool GetColorAt(int index,
+ cef_menu_color_type_t color_type,
+ cef_color_t& color) override;
+ bool SetFontList(int command_id, const CefString& font_list) override;
+ bool SetFontListAt(int index, const CefString& font_list) override;
+
+ ui::SimpleMenuModel* model() const { return model_; }
+
+ private:
+ // Verify that the object is attached and being accessed from the correct
+ // thread.
+ bool VerifyContext();
+
+ // Returns true if |index| is valid.
+ bool ValidIndex(size_t index);
+
+ CefRefPtr<CefSimpleMenuModelImpl> CreateNewSubMenu(
+ ui::SimpleMenuModel* model);
+
+ base::PlatformThreadId supported_thread_id_;
+
+ ui::SimpleMenuModel* model_;
+ ui::SimpleMenuModel::Delegate* const delegate_;
+ StateDelegate* const state_delegate_;
+ const bool is_owned_;
+ const bool is_submenu_;
+
+ // Keep the submenus alive until they're removed, or we're destroyed.
+ using SubMenuMap =
+ std::map<ui::SimpleMenuModel*, CefRefPtr<CefSimpleMenuModelImpl>>;
+ SubMenuMap submenumap_;
+
+ IMPLEMENT_REFCOUNTING(CefSimpleMenuModelImpl);
+};
+
+#endif // CEF_LIBCEF_BROWSER_SIMPLE_MENU_MODEL_IMPL_H_
diff --git a/libcef/browser/speech_recognition_manager_delegate.cc b/libcef/browser/speech_recognition_manager_delegate.cc
new file mode 100644
index 00000000..1a7c669a
--- /dev/null
+++ b/libcef/browser/speech_recognition_manager_delegate.cc
@@ -0,0 +1,90 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/speech_recognition_manager_delegate.h"
+
+#include <set>
+#include <string>
+
+#include "libcef/browser/thread_util.h"
+#include "libcef/common/cef_switches.h"
+
+#include "base/command_line.h"
+#include "base/functional/bind.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
+#include "content/public/browser/notification_source.h"
+#include "content/public/browser/notification_types.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/speech_recognition_manager.h"
+#include "content/public/browser/speech_recognition_session_context.h"
+#include "content/public/browser/web_contents.h"
+
+using content::BrowserThread;
+using content::SpeechRecognitionManager;
+using content::WebContents;
+
+CefSpeechRecognitionManagerDelegate ::CefSpeechRecognitionManagerDelegate() {
+ const base::CommandLine* command_line =
+ base::CommandLine::ForCurrentProcess();
+ filter_profanities_ =
+ command_line->HasSwitch(switches::kEnableProfanityFilter);
+}
+
+CefSpeechRecognitionManagerDelegate ::~CefSpeechRecognitionManagerDelegate() {}
+
+void CefSpeechRecognitionManagerDelegate::OnRecognitionStart(int session_id) {}
+
+void CefSpeechRecognitionManagerDelegate::OnAudioStart(int session_id) {}
+
+void CefSpeechRecognitionManagerDelegate::OnEnvironmentEstimationComplete(
+ int session_id) {}
+
+void CefSpeechRecognitionManagerDelegate::OnSoundStart(int session_id) {}
+
+void CefSpeechRecognitionManagerDelegate::OnSoundEnd(int session_id) {}
+
+void CefSpeechRecognitionManagerDelegate::OnAudioEnd(int session_id) {}
+
+void CefSpeechRecognitionManagerDelegate::OnRecognitionResults(
+ int session_id,
+ const std::vector<blink::mojom::SpeechRecognitionResultPtr>& result) {}
+
+void CefSpeechRecognitionManagerDelegate::OnRecognitionError(
+ int session_id,
+ const blink::mojom::SpeechRecognitionError& error) {}
+
+void CefSpeechRecognitionManagerDelegate::OnAudioLevelsChange(
+ int session_id,
+ float volume,
+ float noise_volume) {}
+
+void CefSpeechRecognitionManagerDelegate::OnRecognitionEnd(int session_id) {}
+
+void CefSpeechRecognitionManagerDelegate::CheckRecognitionIsAllowed(
+ int session_id,
+ base::OnceCallback<void(bool ask_user, bool is_allowed)> callback) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+ const content::SpeechRecognitionSessionContext& context =
+ SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id);
+
+ // Make sure that initiators properly set the |render_process_id| field.
+ DCHECK_NE(context.render_process_id, 0);
+
+ CEF_POST_TASK(CEF_IOT, base::BindOnce(std::move(callback), false, true));
+}
+
+content::SpeechRecognitionEventListener*
+CefSpeechRecognitionManagerDelegate::GetEventListener() {
+ return this;
+}
+
+bool CefSpeechRecognitionManagerDelegate::FilterProfanities(
+ int render_process_id) {
+ return filter_profanities_;
+}
diff --git a/libcef/browser/speech_recognition_manager_delegate.h b/libcef/browser/speech_recognition_manager_delegate.h
new file mode 100644
index 00000000..4897495c
--- /dev/null
+++ b/libcef/browser/speech_recognition_manager_delegate.h
@@ -0,0 +1,60 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_SPEECH_RECOGNITION_MANAGER_DELEGATE_H_
+#define CEF_LIBCEF_BROWSER_SPEECH_RECOGNITION_MANAGER_DELEGATE_H_
+
+#include "base/memory/ref_counted.h"
+#include "content/public/browser/speech_recognition_event_listener.h"
+#include "content/public/browser/speech_recognition_manager_delegate.h"
+
+// This is CEF's implementation of the SpeechRecognitionManagerDelegate
+// interface. Based on chrome/browser/speech/
+// chrome_speech_recognition_manager_delegate.[cc|h]
+class CefSpeechRecognitionManagerDelegate
+ : public content::SpeechRecognitionManagerDelegate,
+ public content::SpeechRecognitionEventListener {
+ public:
+ CefSpeechRecognitionManagerDelegate();
+
+ CefSpeechRecognitionManagerDelegate(
+ const CefSpeechRecognitionManagerDelegate&) = delete;
+ CefSpeechRecognitionManagerDelegate& operator=(
+ const CefSpeechRecognitionManagerDelegate&) = delete;
+
+ ~CefSpeechRecognitionManagerDelegate() override;
+
+ protected:
+ // SpeechRecognitionEventListener methods.
+ void OnRecognitionStart(int session_id) override;
+ void OnAudioStart(int session_id) override;
+ void OnEnvironmentEstimationComplete(int session_id) override;
+ void OnSoundStart(int session_id) override;
+ void OnSoundEnd(int session_id) override;
+ void OnAudioEnd(int session_id) override;
+ void OnRecognitionEnd(int session_id) override;
+ void OnRecognitionResults(
+ int session_id,
+ const std::vector<blink::mojom::SpeechRecognitionResultPtr>& result)
+ override;
+ void OnRecognitionError(
+ int session_id,
+ const blink::mojom::SpeechRecognitionError& error) override;
+ void OnAudioLevelsChange(int session_id,
+ float volume,
+ float noise_volume) override;
+
+ // SpeechRecognitionManagerDelegate methods.
+ void CheckRecognitionIsAllowed(
+ int session_id,
+ base::OnceCallback<void(bool ask_user, bool is_allowed)> callback)
+ override;
+ content::SpeechRecognitionEventListener* GetEventListener() override;
+ bool FilterProfanities(int render_process_id) override;
+
+ private:
+ bool filter_profanities_;
+};
+
+#endif // CEF_LIBCEF_BROWSER_SPEECH_RECOGNITION_MANAGER_DELEGATE_H_
diff --git a/libcef/browser/ssl_host_state_delegate.cc b/libcef/browser/ssl_host_state_delegate.cc
new file mode 100644
index 00000000..15a98cad
--- /dev/null
+++ b/libcef/browser/ssl_host_state_delegate.cc
@@ -0,0 +1,120 @@
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/ssl_host_state_delegate.h"
+
+#include "base/functional/callback.h"
+#include "net/base/hash_value.h"
+
+using content::SSLHostStateDelegate;
+
+namespace internal {
+
+CertPolicy::CertPolicy() {}
+CertPolicy::~CertPolicy() {}
+
+// For an allowance, we consider a given |cert| to be a match to a saved
+// allowed cert if the |error| is an exact match to or subset of the errors
+// in the saved CertStatus.
+bool CertPolicy::Check(const net::X509Certificate& cert, int error) const {
+ net::SHA256HashValue fingerprint = cert.CalculateChainFingerprint256();
+ const auto& allowed_iter = allowed_.find(fingerprint);
+ if ((allowed_iter != allowed_.end()) && (allowed_iter->second & error) &&
+ ((allowed_iter->second & error) == error)) {
+ return true;
+ }
+ return false;
+}
+
+void CertPolicy::Allow(const net::X509Certificate& cert, int error) {
+ // If this same cert had already been saved with a different error status,
+ // this will replace it with the new error status.
+ net::SHA256HashValue fingerprint = cert.CalculateChainFingerprint256();
+ allowed_[fingerprint] = error;
+}
+
+} // namespace internal
+
+CefSSLHostStateDelegate::CefSSLHostStateDelegate() {}
+
+CefSSLHostStateDelegate::~CefSSLHostStateDelegate() {}
+
+void CefSSLHostStateDelegate::HostRanInsecureContent(
+ const std::string& host,
+ int child_id,
+ InsecureContentType content_type) {
+ // Intentional no-op.
+}
+
+bool CefSSLHostStateDelegate::DidHostRunInsecureContent(
+ const std::string& host,
+ int child_id,
+ InsecureContentType content_type) {
+ // Intentional no-op.
+ return false;
+}
+
+void CefSSLHostStateDelegate::AllowHttpForHost(
+ const std::string& host,
+ content::StoragePartition* storage_partition) {
+ // Intentional no-op.
+}
+
+bool CefSSLHostStateDelegate::IsHttpAllowedForHost(
+ const std::string& host,
+ content::StoragePartition* storage_partition) {
+ // Intentional no-op. Return value does not matter as HTTPS-Only Mode is not
+ // enabled.
+ return false;
+}
+
+void CefSSLHostStateDelegate::AllowCert(
+ const std::string& host,
+ const net::X509Certificate& cert,
+ int error,
+ content::StoragePartition* storage_partition) {
+ cert_policy_for_host_[host].Allow(cert, error);
+}
+
+void CefSSLHostStateDelegate::Clear(
+ const base::RepeatingCallback<bool(const std::string&)> host_filter) {
+ if (host_filter.is_null()) {
+ cert_policy_for_host_.clear();
+ return;
+ }
+
+ for (auto it = cert_policy_for_host_.begin();
+ it != cert_policy_for_host_.end();) {
+ auto next_it = std::next(it);
+
+ if (host_filter.Run(it->first)) {
+ cert_policy_for_host_.erase(it);
+ }
+
+ it = next_it;
+ }
+}
+
+SSLHostStateDelegate::CertJudgment CefSSLHostStateDelegate::QueryPolicy(
+ const std::string& host,
+ const net::X509Certificate& cert,
+ int error,
+ content::StoragePartition* storage_partition) {
+ return cert_policy_for_host_[host].Check(cert, error)
+ ? SSLHostStateDelegate::ALLOWED
+ : SSLHostStateDelegate::DENIED;
+}
+
+void CefSSLHostStateDelegate::RevokeUserAllowExceptions(
+ const std::string& host) {
+ cert_policy_for_host_.erase(host);
+}
+
+bool CefSSLHostStateDelegate::HasAllowException(
+ const std::string& host,
+ content::StoragePartition* storage_partition) {
+ auto policy_iterator = cert_policy_for_host_.find(host);
+ return policy_iterator != cert_policy_for_host_.end() &&
+ policy_iterator->second.HasAllowException();
+}
diff --git a/libcef/browser/ssl_host_state_delegate.h b/libcef/browser/ssl_host_state_delegate.h
new file mode 100644
index 00000000..ea140bac
--- /dev/null
+++ b/libcef/browser/ssl_host_state_delegate.h
@@ -0,0 +1,85 @@
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_SSL_HOST_STATE_DELEGATE_H_
+#define CEF_LIBCEF_BROWSER_SSL_HOST_STATE_DELEGATE_H_
+
+#include <map>
+#include <string>
+
+#include "content/public/browser/ssl_host_state_delegate.h"
+#include "net/base/hash_value.h"
+#include "net/cert/x509_certificate.h"
+
+// Implementation based on android_webview/browser/aw_ssl_host_state_delegate.h.
+
+namespace internal {
+
+// This class maintains the policy for storing actions on certificate errors.
+class CertPolicy {
+ public:
+ CertPolicy();
+ ~CertPolicy();
+ // Returns true if the user has decided to proceed through the ssl error
+ // before. For a certificate to be allowed, it must not have any
+ // *additional* errors from when it was allowed.
+ bool Check(const net::X509Certificate& cert, int error) const;
+
+ // Causes the policy to allow this certificate for a given |error|. And
+ // remember the user's choice.
+ void Allow(const net::X509Certificate& cert, int error);
+
+ // Returns true if and only if there exists a user allow exception for some
+ // certificate.
+ bool HasAllowException() const { return allowed_.size() > 0; }
+
+ private:
+ // The set of fingerprints of allowed certificates.
+ std::map<net::SHA256HashValue, int> allowed_;
+};
+
+} // namespace internal
+
+class CefSSLHostStateDelegate : public content::SSLHostStateDelegate {
+ public:
+ CefSSLHostStateDelegate();
+
+ CefSSLHostStateDelegate(const CefSSLHostStateDelegate&) = delete;
+ CefSSLHostStateDelegate& operator=(const CefSSLHostStateDelegate&) = delete;
+
+ ~CefSSLHostStateDelegate() override;
+
+ // SSLHostStateDelegate methods:
+ void AllowCert(const std::string& host,
+ const net::X509Certificate& cert,
+ int error,
+ content::StoragePartition* storage_partition) override;
+ void Clear(const base::RepeatingCallback<bool(const std::string&)>
+ host_filter) override;
+ content::SSLHostStateDelegate::CertJudgment QueryPolicy(
+ const std::string& host,
+ const net::X509Certificate& cert,
+ int error,
+ content::StoragePartition* storage_partition) override;
+ void HostRanInsecureContent(const std::string& host,
+ int child_id,
+ InsecureContentType content_type) override;
+ bool DidHostRunInsecureContent(const std::string& host,
+ int child_id,
+ InsecureContentType content_type) override;
+ void AllowHttpForHost(const std::string& host,
+ content::StoragePartition* storage_partition) override;
+ bool IsHttpAllowedForHost(
+ const std::string& host,
+ content::StoragePartition* storage_partition) override;
+ void RevokeUserAllowExceptions(const std::string& host) override;
+ bool HasAllowException(const std::string& host,
+ content::StoragePartition* storage_partition) override;
+
+ private:
+ // Certificate policies for each host.
+ std::map<std::string, internal::CertPolicy> cert_policy_for_host_;
+};
+
+#endif // CEF_LIBCEF_BROWSER_SSL_HOST_STATE_DELEGATE_H_
diff --git a/libcef/browser/ssl_info_impl.cc b/libcef/browser/ssl_info_impl.cc
new file mode 100644
index 00000000..7c881275
--- /dev/null
+++ b/libcef/browser/ssl_info_impl.cc
@@ -0,0 +1,28 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "libcef/browser/ssl_info_impl.h"
+#include "libcef/browser/x509_certificate_impl.h"
+
+#include "net/cert/cert_status_flags.h"
+
+CefSSLInfoImpl::CefSSLInfoImpl(const net::SSLInfo& value)
+ : cert_status_(CERT_STATUS_NONE) {
+ cert_status_ = static_cast<cef_cert_status_t>(value.cert_status);
+ if (value.cert.get()) {
+ cert_ = new CefX509CertificateImpl(value.cert);
+ }
+}
+
+cef_cert_status_t CefSSLInfoImpl::GetCertStatus() {
+ return cert_status_;
+}
+
+CefRefPtr<CefX509Certificate> CefSSLInfoImpl::GetX509Certificate() {
+ return cert_;
+}
+
+bool CefIsCertStatusError(cef_cert_status_t status) {
+ return net::IsCertStatusError(status);
+}
diff --git a/libcef/browser/ssl_info_impl.h b/libcef/browser/ssl_info_impl.h
new file mode 100644
index 00000000..2179a0f9
--- /dev/null
+++ b/libcef/browser/ssl_info_impl.h
@@ -0,0 +1,32 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_SSL_INFO_IMPL_H_
+#define CEF_LIBCEF_BROWSER_SSL_INFO_IMPL_H_
+#pragma once
+
+#include "include/cef_ssl_info.h"
+
+#include "net/ssl/ssl_info.h"
+
+// CefSSLInfo implementation
+class CefSSLInfoImpl : public CefSSLInfo {
+ public:
+ explicit CefSSLInfoImpl(const net::SSLInfo& value);
+
+ CefSSLInfoImpl(const CefSSLInfoImpl&) = delete;
+ CefSSLInfoImpl& operator=(const CefSSLInfoImpl&) = delete;
+
+ // CefSSLInfo methods.
+ cef_cert_status_t GetCertStatus() override;
+ CefRefPtr<CefX509Certificate> GetX509Certificate() override;
+
+ private:
+ cef_cert_status_t cert_status_;
+ CefRefPtr<CefX509Certificate> cert_;
+
+ IMPLEMENT_REFCOUNTING(CefSSLInfoImpl);
+};
+
+#endif // CEF_LIBCEF_BROWSER_SSL_INFO_IMPL_H_
diff --git a/libcef/browser/ssl_status_impl.cc b/libcef/browser/ssl_status_impl.cc
new file mode 100644
index 00000000..f119bfaf
--- /dev/null
+++ b/libcef/browser/ssl_status_impl.cc
@@ -0,0 +1,40 @@
+// Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "libcef/browser/ssl_status_impl.h"
+
+#include "libcef/browser/x509_certificate_impl.h"
+
+#include "net/ssl/ssl_connection_status_flags.h"
+
+CefSSLStatusImpl::CefSSLStatusImpl(const content::SSLStatus& value) {
+ cert_status_ = static_cast<cef_cert_status_t>(value.cert_status);
+ content_status_ = static_cast<cef_ssl_content_status_t>(value.content_status);
+ ssl_version_ = static_cast<cef_ssl_version_t>(
+ net::SSLConnectionStatusToVersion(value.connection_status));
+ certificate_ = value.certificate;
+}
+
+bool CefSSLStatusImpl::IsSecureConnection() {
+ return !!certificate_.get();
+}
+
+cef_cert_status_t CefSSLStatusImpl::GetCertStatus() {
+ return cert_status_;
+}
+
+cef_ssl_version_t CefSSLStatusImpl::GetSSLVersion() {
+ return ssl_version_;
+}
+
+cef_ssl_content_status_t CefSSLStatusImpl::GetContentStatus() {
+ return content_status_;
+}
+
+CefRefPtr<CefX509Certificate> CefSSLStatusImpl::GetX509Certificate() {
+ if (certificate_ && !cef_certificate_) {
+ cef_certificate_ = new CefX509CertificateImpl(certificate_);
+ }
+ return cef_certificate_;
+}
diff --git a/libcef/browser/ssl_status_impl.h b/libcef/browser/ssl_status_impl.h
new file mode 100644
index 00000000..43ef322e
--- /dev/null
+++ b/libcef/browser/ssl_status_impl.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_SSL_STATUS_IMPL_H_
+#define CEF_LIBCEF_BROWSER_SSL_STATUS_IMPL_H_
+#pragma once
+
+#include "include/cef_ssl_status.h"
+
+#include "content/public/browser/ssl_status.h"
+
+// CefSSLStatus implementation
+class CefSSLStatusImpl : public CefSSLStatus {
+ public:
+ explicit CefSSLStatusImpl(const content::SSLStatus& value);
+
+ CefSSLStatusImpl(const CefSSLStatusImpl&) = delete;
+ CefSSLStatusImpl& operator=(const CefSSLStatusImpl&) = delete;
+
+ // CefSSLStatus methods.
+ bool IsSecureConnection() override;
+ cef_cert_status_t GetCertStatus() override;
+ cef_ssl_version_t GetSSLVersion() override;
+ cef_ssl_content_status_t GetContentStatus() override;
+ CefRefPtr<CefX509Certificate> GetX509Certificate() override;
+
+ private:
+ cef_cert_status_t cert_status_;
+ cef_ssl_version_t ssl_version_;
+ cef_ssl_content_status_t content_status_;
+
+ // Don't create a CefX509Certificate object until requested.
+ scoped_refptr<net::X509Certificate> certificate_;
+ CefRefPtr<CefX509Certificate> cef_certificate_;
+
+ IMPLEMENT_REFCOUNTING(CefSSLStatusImpl);
+};
+
+#endif // CEF_LIBCEF_BROWSER_SSL_STATUS_IMPL_H_
diff --git a/libcef/browser/stream_impl.cc b/libcef/browser/stream_impl.cc
new file mode 100644
index 00000000..1e4e40e6
--- /dev/null
+++ b/libcef/browser/stream_impl.cc
@@ -0,0 +1,322 @@
+// Copyright (c) 2008 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "libcef/browser/stream_impl.h"
+#include <stdlib.h>
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/threading/thread_restrictions.h"
+
+// Static functions
+
+CefRefPtr<CefStreamReader> CefStreamReader::CreateForFile(
+ const CefString& fileName) {
+ DCHECK(!fileName.empty());
+
+ // TODO(cef): Do not allow file IO on all threads (issue #1187).
+ base::ScopedAllowBlockingForTesting allow_blocking;
+
+ CefRefPtr<CefStreamReader> reader;
+ FILE* file = base::OpenFile(base::FilePath(fileName), "rb");
+ if (file) {
+ reader = new CefFileReader(file, true);
+ }
+ return reader;
+}
+
+CefRefPtr<CefStreamReader> CefStreamReader::CreateForData(void* data,
+ size_t size) {
+ DCHECK(data != nullptr);
+ DCHECK(size > 0);
+ CefRefPtr<CefStreamReader> reader;
+ if (data && size > 0) {
+ reader = new CefBytesReader(data, size, true);
+ }
+ return reader;
+}
+
+CefRefPtr<CefStreamReader> CefStreamReader::CreateForHandler(
+ CefRefPtr<CefReadHandler> handler) {
+ DCHECK(handler.get());
+ CefRefPtr<CefStreamReader> reader;
+ if (handler.get()) {
+ reader = new CefHandlerReader(handler);
+ }
+ return reader;
+}
+
+CefRefPtr<CefStreamWriter> CefStreamWriter::CreateForFile(
+ const CefString& fileName) {
+ DCHECK(!fileName.empty());
+
+ // TODO(cef): Do not allow file IO on all threads (issue #1187).
+ base::ScopedAllowBlockingForTesting allow_blocking;
+
+ CefRefPtr<CefStreamWriter> writer;
+ FILE* file = base::OpenFile(base::FilePath(fileName), "wb");
+ if (file) {
+ writer = new CefFileWriter(file, true);
+ }
+ return writer;
+}
+
+CefRefPtr<CefStreamWriter> CefStreamWriter::CreateForHandler(
+ CefRefPtr<CefWriteHandler> handler) {
+ DCHECK(handler.get());
+ CefRefPtr<CefStreamWriter> writer;
+ if (handler.get()) {
+ writer = new CefHandlerWriter(handler);
+ }
+ return writer;
+}
+
+// CefFileReader
+
+CefFileReader::CefFileReader(FILE* file, bool close)
+ : close_(close), file_(file) {}
+
+CefFileReader::~CefFileReader() {
+ base::AutoLock lock_scope(lock_);
+ if (close_) {
+ base::CloseFile(file_);
+ }
+}
+
+size_t CefFileReader::Read(void* ptr, size_t size, size_t n) {
+ base::AutoLock lock_scope(lock_);
+ return fread(ptr, size, n, file_);
+}
+
+int CefFileReader::Seek(int64 offset, int whence) {
+ base::AutoLock lock_scope(lock_);
+#if BUILDFLAG(IS_WIN)
+ return _fseeki64(file_, offset, whence);
+#else
+ return fseek(file_, offset, whence);
+#endif
+}
+
+int64 CefFileReader::Tell() {
+ base::AutoLock lock_scope(lock_);
+#if BUILDFLAG(IS_WIN)
+ return _ftelli64(file_);
+#else
+ return ftell(file_);
+#endif
+}
+
+int CefFileReader::Eof() {
+ base::AutoLock lock_scope(lock_);
+ return feof(file_);
+}
+
+// CefFileWriter
+
+CefFileWriter::CefFileWriter(FILE* file, bool close)
+ : file_(file), close_(close) {}
+
+CefFileWriter::~CefFileWriter() {
+ base::AutoLock lock_scope(lock_);
+ if (close_) {
+ base::CloseFile(file_);
+ }
+}
+
+size_t CefFileWriter::Write(const void* ptr, size_t size, size_t n) {
+ base::AutoLock lock_scope(lock_);
+ return (size_t)fwrite(ptr, size, n, file_);
+}
+
+int CefFileWriter::Seek(int64 offset, int whence) {
+ base::AutoLock lock_scope(lock_);
+ return fseek(file_, offset, whence);
+}
+
+int64 CefFileWriter::Tell() {
+ base::AutoLock lock_scope(lock_);
+ return ftell(file_);
+}
+
+int CefFileWriter::Flush() {
+ base::AutoLock lock_scope(lock_);
+ return fflush(file_);
+}
+
+// CefBytesReader
+
+CefBytesReader::CefBytesReader(void* data, int64 datasize, bool copy)
+ : data_(nullptr), datasize_(0), copy_(false), offset_(0) {
+ SetData(data, datasize, copy);
+}
+
+CefBytesReader::~CefBytesReader() {
+ SetData(nullptr, 0, false);
+}
+
+size_t CefBytesReader::Read(void* ptr, size_t size, size_t n) {
+ base::AutoLock lock_scope(lock_);
+ size_t s = (datasize_ - offset_) / size;
+ size_t ret = (n < s ? n : s);
+ memcpy(ptr, (reinterpret_cast<char*>(data_)) + offset_, ret * size);
+ offset_ += ret * size;
+ return ret;
+}
+
+int CefBytesReader::Seek(int64 offset, int whence) {
+ int rv = -1L;
+ base::AutoLock lock_scope(lock_);
+ switch (whence) {
+ case SEEK_CUR:
+ if (offset_ + offset > datasize_ || offset_ + offset < 0) {
+ break;
+ }
+ offset_ += offset;
+ rv = 0;
+ break;
+ case SEEK_END: {
+ int64 offset_abs = std::abs(offset);
+ if (offset_abs > datasize_) {
+ break;
+ }
+ offset_ = datasize_ - offset_abs;
+ rv = 0;
+ break;
+ }
+ case SEEK_SET:
+ if (offset > datasize_ || offset < 0) {
+ break;
+ }
+ offset_ = offset;
+ rv = 0;
+ break;
+ }
+
+ return rv;
+}
+
+int64 CefBytesReader::Tell() {
+ base::AutoLock lock_scope(lock_);
+ return offset_;
+}
+
+int CefBytesReader::Eof() {
+ base::AutoLock lock_scope(lock_);
+ return (offset_ >= datasize_);
+}
+
+void CefBytesReader::SetData(void* data, int64 datasize, bool copy) {
+ base::AutoLock lock_scope(lock_);
+ if (copy_) {
+ free(data_);
+ }
+
+ copy_ = copy;
+ offset_ = 0;
+ datasize_ = datasize;
+
+ if (copy) {
+ data_ = malloc(datasize);
+ DCHECK(data_ != nullptr);
+ if (data_) {
+ memcpy(data_, data, datasize);
+ }
+ } else {
+ data_ = data;
+ }
+}
+
+// CefBytesWriter
+
+CefBytesWriter::CefBytesWriter(size_t grow)
+ : grow_(grow), datasize_(grow), offset_(0) {
+ DCHECK(grow > 0);
+ data_ = malloc(grow);
+ DCHECK(data_ != nullptr);
+}
+
+CefBytesWriter::~CefBytesWriter() {
+ base::AutoLock lock_scope(lock_);
+ if (data_) {
+ free(data_);
+ }
+}
+
+size_t CefBytesWriter::Write(const void* ptr, size_t size, size_t n) {
+ base::AutoLock lock_scope(lock_);
+ size_t rv;
+ if (offset_ + static_cast<int64>(size * n) >= datasize_ &&
+ Grow(size * n) == 0) {
+ rv = 0;
+ } else {
+ memcpy(reinterpret_cast<char*>(data_) + offset_, ptr, size * n);
+ offset_ += size * n;
+ rv = n;
+ }
+
+ return rv;
+}
+
+int CefBytesWriter::Seek(int64 offset, int whence) {
+ int rv = -1L;
+ base::AutoLock lock_scope(lock_);
+ switch (whence) {
+ case SEEK_CUR:
+ if (offset_ + offset > datasize_ || offset_ + offset < 0) {
+ break;
+ }
+ offset_ += offset;
+ rv = 0;
+ break;
+ case SEEK_END: {
+ int64 offset_abs = std::abs(offset);
+ if (offset_abs > datasize_) {
+ break;
+ }
+ offset_ = datasize_ - offset_abs;
+ rv = 0;
+ break;
+ }
+ case SEEK_SET:
+ if (offset > datasize_ || offset < 0) {
+ break;
+ }
+ offset_ = offset;
+ rv = 0;
+ break;
+ }
+
+ return rv;
+}
+
+int64 CefBytesWriter::Tell() {
+ base::AutoLock lock_scope(lock_);
+ return offset_;
+}
+
+int CefBytesWriter::Flush() {
+ return 0;
+}
+
+std::string CefBytesWriter::GetDataString() {
+ base::AutoLock lock_scope(lock_);
+ std::string str(reinterpret_cast<char*>(data_), offset_);
+ return str;
+}
+
+size_t CefBytesWriter::Grow(size_t size) {
+ base::AutoLock lock_scope(lock_);
+ size_t rv;
+ size_t s = (size > grow_ ? size : grow_);
+ void* tmp = realloc(data_, datasize_ + s);
+ DCHECK(tmp != nullptr);
+ if (tmp) {
+ data_ = tmp;
+ datasize_ += s;
+ rv = datasize_;
+ } else {
+ rv = 0;
+ }
+
+ return rv;
+}
diff --git a/libcef/browser/stream_impl.h b/libcef/browser/stream_impl.h
new file mode 100644
index 00000000..dde3d602
--- /dev/null
+++ b/libcef/browser/stream_impl.h
@@ -0,0 +1,159 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_STREAM_IMPL_H_
+#define CEF_LIBCEF_BROWSER_STREAM_IMPL_H_
+#pragma once
+
+#include "include/cef_stream.h"
+
+#include <stdio.h>
+#include <string>
+
+#include "base/synchronization/lock.h"
+
+// Implementation of CefStreamReader for files.
+class CefFileReader : public CefStreamReader {
+ public:
+ CefFileReader(FILE* file, bool close);
+ ~CefFileReader() override;
+
+ size_t Read(void* ptr, size_t size, size_t n) override;
+ int Seek(int64 offset, int whence) override;
+ int64 Tell() override;
+ int Eof() override;
+ bool MayBlock() override { return true; }
+
+ protected:
+ bool close_;
+ FILE* file_;
+
+ base::Lock lock_;
+
+ IMPLEMENT_REFCOUNTING(CefFileReader);
+};
+
+// Implementation of CefStreamWriter for files.
+class CefFileWriter : public CefStreamWriter {
+ public:
+ CefFileWriter(FILE* file, bool close);
+ ~CefFileWriter() override;
+
+ size_t Write(const void* ptr, size_t size, size_t n) override;
+ int Seek(int64 offset, int whence) override;
+ int64 Tell() override;
+ int Flush() override;
+ bool MayBlock() override { return true; }
+
+ protected:
+ FILE* file_;
+ bool close_;
+
+ base::Lock lock_;
+
+ IMPLEMENT_REFCOUNTING(CefFileWriter);
+};
+
+// Implementation of CefStreamReader for byte buffers.
+class CefBytesReader : public CefStreamReader {
+ public:
+ CefBytesReader(void* data, int64 datasize, bool copy);
+ ~CefBytesReader() override;
+
+ size_t Read(void* ptr, size_t size, size_t n) override;
+ int Seek(int64 offset, int whence) override;
+ int64 Tell() override;
+ int Eof() override;
+ bool MayBlock() override { return false; }
+
+ void SetData(void* data, int64 datasize, bool copy);
+
+ void* GetData() { return data_; }
+ size_t GetDataSize() { return offset_; }
+
+ protected:
+ void* data_;
+ int64 datasize_;
+ bool copy_;
+ int64 offset_;
+
+ base::Lock lock_;
+
+ IMPLEMENT_REFCOUNTING(CefBytesReader);
+};
+
+// Implementation of CefStreamWriter for byte buffers.
+class CefBytesWriter : public CefStreamWriter {
+ public:
+ explicit CefBytesWriter(size_t grow);
+ ~CefBytesWriter() override;
+
+ size_t Write(const void* ptr, size_t size, size_t n) override;
+ int Seek(int64 offset, int whence) override;
+ int64 Tell() override;
+ int Flush() override;
+ bool MayBlock() override { return false; }
+
+ void* GetData() { return data_; }
+ int64 GetDataSize() { return offset_; }
+ std::string GetDataString();
+
+ protected:
+ size_t Grow(size_t size);
+
+ size_t grow_;
+ void* data_;
+ int64 datasize_;
+ int64 offset_;
+
+ base::Lock lock_;
+
+ IMPLEMENT_REFCOUNTING(CefBytesWriter);
+};
+
+// Implementation of CefStreamReader for handlers.
+class CefHandlerReader : public CefStreamReader {
+ public:
+ explicit CefHandlerReader(CefRefPtr<CefReadHandler> handler)
+ : handler_(handler) {}
+
+ size_t Read(void* ptr, size_t size, size_t n) override {
+ return handler_->Read(ptr, size, n);
+ }
+ int Seek(int64 offset, int whence) override {
+ return handler_->Seek(offset, whence);
+ }
+ int64 Tell() override { return handler_->Tell(); }
+ int Eof() override { return handler_->Eof(); }
+ bool MayBlock() override { return handler_->MayBlock(); }
+
+ protected:
+ CefRefPtr<CefReadHandler> handler_;
+
+ IMPLEMENT_REFCOUNTING(CefHandlerReader);
+};
+
+// Implementation of CefStreamWriter for handlers.
+class CefHandlerWriter : public CefStreamWriter {
+ public:
+ explicit CefHandlerWriter(CefRefPtr<CefWriteHandler> handler)
+ : handler_(handler) {}
+
+ size_t Write(const void* ptr, size_t size, size_t n) override {
+ return handler_->Write(ptr, size, n);
+ }
+ int Seek(int64 offset, int whence) override {
+ return handler_->Seek(offset, whence);
+ }
+ int64 Tell() override { return handler_->Tell(); }
+ int Flush() override { return handler_->Flush(); }
+ bool MayBlock() override { return handler_->MayBlock(); }
+
+ protected:
+ CefRefPtr<CefWriteHandler> handler_;
+
+ IMPLEMENT_REFCOUNTING(CefHandlerWriter);
+};
+
+#endif // CEF_LIBCEF_BROWSER_STREAM_IMPL_H_
diff --git a/libcef/browser/test/test_helpers_impl.cc b/libcef/browser/test/test_helpers_impl.cc
new file mode 100644
index 00000000..1e0ea9c1
--- /dev/null
+++ b/libcef/browser/test/test_helpers_impl.cc
@@ -0,0 +1,14 @@
+// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "include/test/cef_test_helpers.h"
+
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+
+void CefSetDataDirectoryForTests(const CefString& dir) {
+ base::PathService::OverrideAndCreateIfNeeded(
+ base::DIR_SRC_TEST_DATA_ROOT, base::FilePath(dir), /*is_absolute=*/true,
+ /*create=*/false);
+}
diff --git a/libcef/browser/test/test_server_impl.cc b/libcef/browser/test/test_server_impl.cc
new file mode 100644
index 00000000..73719625
--- /dev/null
+++ b/libcef/browser/test/test_server_impl.cc
@@ -0,0 +1,293 @@
+// Copyright 2022 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#include "libcef/browser/test/test_server_impl.h"
+
+#include "libcef/common/net/http_header_utils.h"
+
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+#include "base/task/single_thread_task_runner.h"
+#include "base/threading/thread_checker.h"
+#include "net/http/http_request_headers.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "net/test/embedded_test_server/http_response.h"
+
+using namespace net::test_server;
+
+namespace {
+
+class CefTestServerConnectionImpl : public CefTestServerConnection {
+ public:
+ explicit CefTestServerConnectionImpl(
+ base::WeakPtr<HttpResponseDelegate> delegate)
+ : delegate_(delegate),
+ task_runner_(base::SingleThreadTaskRunner::GetCurrentDefault()) {
+ DCHECK(delegate_);
+ DCHECK(task_runner_);
+ }
+
+ void SendHttp200Response(const CefString& content_type,
+ const void* data,
+ size_t data_size) override {
+ auto response = std::make_unique<BasicHttpResponse>();
+ response->set_code(net::HTTP_OK);
+ response->set_content_type(base::StringPiece(content_type.ToString()));
+ response->set_content(
+ base::StringPiece(reinterpret_cast<const char*>(data), data_size));
+ SendBasicHttpResponse(std::move(response));
+ }
+
+ void SendHttp404Response() override {
+ auto response = std::make_unique<BasicHttpResponse>();
+ response->set_code(net::HTTP_NOT_FOUND);
+ SendBasicHttpResponse(std::move(response));
+ }
+
+ void SendHttp500Response(const CefString& error_message) override {
+ auto response = std::make_unique<BasicHttpResponse>();
+ response->set_code(net::HTTP_INTERNAL_SERVER_ERROR);
+ response->set_content_type(base::StringPiece("text/html"));
+ response->set_content(base::StringPiece(error_message.ToString()));
+ SendBasicHttpResponse(std::move(response));
+ }
+
+ void SendHttpResponse(int response_code,
+ const CefString& content_type,
+ const void* data,
+ size_t data_size,
+ const HeaderMap& extra_headers) override {
+ auto response = std::make_unique<BasicHttpResponse>();
+ response->set_code(static_cast<net::HttpStatusCode>(response_code));
+ response->set_content_type(base::StringPiece(content_type.ToString()));
+ response->set_content(
+ base::StringPiece(reinterpret_cast<const char*>(data), data_size));
+ for (const auto& [key, value] : extra_headers) {
+ response->AddCustomHeader(key.ToString(), value.ToString());
+ }
+ SendBasicHttpResponse(std::move(response));
+ }
+
+ private:
+ void SendBasicHttpResponse(std::unique_ptr<BasicHttpResponse> response) {
+ if (!task_runner_->BelongsToCurrentThread()) {
+ task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(&CefTestServerConnectionImpl::SendBasicHttpResponse,
+ this, std::move(response)));
+ return;
+ }
+
+ if (delegate_) {
+ response->SendResponse(delegate_);
+ }
+ }
+
+ base::WeakPtr<HttpResponseDelegate> delegate_;
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+
+ IMPLEMENT_REFCOUNTING(CefTestServerConnectionImpl);
+};
+
+class CefHttpResponse : public HttpResponse {
+ public:
+ CefHttpResponse(CefRefPtr<CefTestServer> server,
+ CefRefPtr<CefTestServerHandler> handler,
+ CefRefPtr<CefRequest> request)
+ : server_(server), handler_(handler), request_(request) {
+ DCHECK(server_);
+ DCHECK(handler_);
+ DCHECK(request_);
+ }
+
+ CefHttpResponse(const CefHttpResponse&) = delete;
+ CefHttpResponse& operator=(const CefHttpResponse&) = delete;
+
+ void SendResponse(base::WeakPtr<HttpResponseDelegate> delegate) override {
+ CefRefPtr<CefTestServerConnectionImpl> connection(
+ new CefTestServerConnectionImpl(delegate));
+ const bool handled =
+ handler_->OnTestServerRequest(server_, request_, connection.get());
+ if (handled) {
+ return;
+ }
+
+ LOG(WARNING) << "Request not handled. Returning 404: "
+ << request_->GetURL().ToString();
+ connection->SendHttp404Response();
+ }
+
+ private:
+ CefRefPtr<CefTestServer> server_;
+ CefRefPtr<CefTestServerHandler> handler_;
+ CefRefPtr<CefRequest> request_;
+};
+
+CefRefPtr<CefRequest> CreateCefRequest(const HttpRequest& request) {
+ CefRefPtr<CefPostData> post_data;
+ if (!request.content.empty()) {
+ post_data = CefPostData::Create();
+ auto element = CefPostDataElement::Create();
+ element->SetToBytes(request.content.size(), request.content.c_str());
+ post_data->AddElement(element);
+ }
+
+ CefRequest::HeaderMap header_map;
+ CefString referer;
+
+ HttpHeaderUtils::ParseHeaders(request.all_headers, header_map);
+
+ // CefRequest will strip the Referer header from the map, so we don't need to
+ // do that here.
+ for (const auto& [key, value] : header_map) {
+ if (base::EqualsCaseInsensitiveASCII(key.ToString(),
+ net::HttpRequestHeaders::kReferer)) {
+ referer = value;
+ }
+ }
+
+ auto cef_request = CefRequest::Create();
+ cef_request->Set(request.GetURL().spec(), request.method_string, post_data,
+ header_map);
+ if (!referer.empty()) {
+ cef_request->SetReferrer(referer, REFERRER_POLICY_DEFAULT);
+ }
+ return cef_request;
+}
+
+} // namespace
+
+class CefTestServerImpl::Context {
+ public:
+ Context(CefRefPtr<CefTestServer> server,
+ CefRefPtr<CefTestServerHandler> handler)
+ : server_(server), handler_(handler) {
+ DCHECK(server_);
+ DCHECK(handler_);
+ }
+
+ Context(const Context&) = delete;
+ Context& operator=(const Context&) = delete;
+
+ ~Context() {
+ // The server should not be running.
+ DCHECK(!test_server_);
+ }
+
+ bool Start(uint16 port,
+ bool https_server,
+ cef_test_cert_type_t https_cert_type) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ DCHECK(!test_server_);
+ test_server_ = std::make_unique<EmbeddedTestServer>(
+ https_server ? EmbeddedTestServer::TYPE_HTTPS
+ : EmbeddedTestServer::TYPE_HTTP);
+
+ // Unretained is safe because Stop is called before |this| is destroyed.
+ test_server_->RegisterRequestHandler(
+ base::BindRepeating(&Context::HandleRequest, base::Unretained(this)));
+
+ if (https_server) {
+ switch (https_cert_type) {
+ case CEF_TEST_CERT_OK_IP:
+ // Default value.
+ break;
+ case CEF_TEST_CERT_OK_DOMAIN:
+ test_server_->SetSSLConfig(
+ EmbeddedTestServer::CERT_COMMON_NAME_IS_DOMAIN);
+ break;
+ case CEF_TEST_CERT_EXPIRED:
+ test_server_->SetSSLConfig(EmbeddedTestServer::CERT_EXPIRED);
+ break;
+ }
+ }
+
+ test_server_handle_ =
+ test_server_->StartAndReturnHandle(static_cast<int>(port));
+ if (!test_server_handle_) {
+ test_server_.reset();
+ return false;
+ }
+
+ origin_ = test_server_->base_url();
+ return true;
+ }
+
+ void Stop() {
+ // Should be called on the creation thread.
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ DCHECK(test_server_);
+
+ // Destruction of |test_server_handle_| will stop the server and block until
+ // the dedicated server thread has shut down.
+ test_server_handle_ = EmbeddedTestServerHandle();
+ test_server_.reset();
+
+ server_ = nullptr;
+ handler_ = nullptr;
+ }
+
+ const GURL& origin() const { return origin_; }
+
+ private:
+ std::unique_ptr<HttpResponse> HandleRequest(const HttpRequest& request) {
+ // Should be on the dedicated server thread.
+ DCHECK(!thread_checker_.CalledOnValidThread());
+ return std::make_unique<CefHttpResponse>(server_, handler_,
+ CreateCefRequest(request));
+ }
+
+ // Safe to access on any thread.
+ CefRefPtr<CefTestServer> server_;
+ CefRefPtr<CefTestServerHandler> handler_;
+ GURL origin_;
+
+ base::ThreadChecker thread_checker_;
+
+ // Only accessed on the creation thread.
+ std::unique_ptr<EmbeddedTestServer> test_server_;
+ EmbeddedTestServerHandle test_server_handle_;
+};
+
+bool CefTestServerImpl::Start(uint16 port,
+ bool https_server,
+ cef_test_cert_type_t https_cert_type,
+ CefRefPtr<CefTestServerHandler> handler) {
+ DCHECK(!context_);
+ context_ = std::make_unique<CefTestServerImpl::Context>(this, handler);
+ if (context_->Start(port, https_server, https_cert_type)) {
+ const auto& origin = context_->origin().spec();
+ // Remove the trailing '/'
+ origin_ = origin.substr(0, origin.length() - 1);
+ return true;
+ }
+
+ context_.reset();
+ return false;
+}
+
+void CefTestServerImpl::Stop() {
+ DCHECK(context_);
+ context_->Stop();
+ context_.reset();
+}
+
+CefString CefTestServerImpl::GetOrigin() {
+ return origin_;
+}
+
+// static
+CefRefPtr<CefTestServer> CefTestServer::CreateAndStart(
+ uint16 port,
+ bool https_server,
+ cef_test_cert_type_t https_cert_type,
+ CefRefPtr<CefTestServerHandler> handler) {
+ CefRefPtr<CefTestServerImpl> server(new CefTestServerImpl());
+ if (server->Start(port, https_server, https_cert_type, handler)) {
+ return server;
+ }
+ return nullptr;
+}
diff --git a/libcef/browser/test/test_server_impl.h b/libcef/browser/test/test_server_impl.h
new file mode 100644
index 00000000..53a4598c
--- /dev/null
+++ b/libcef/browser/test/test_server_impl.h
@@ -0,0 +1,40 @@
+// Copyright 2022 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_TEST_TEST_SERVER_IMPL_H_
+#define CEF_LIBCEF_BROWSER_TEST_TEST_SERVER_IMPL_H_
+#pragma once
+
+#include <memory>
+
+#include "include/test/cef_test_server.h"
+
+class CefTestServerImpl : public CefTestServer {
+ public:
+ CefTestServerImpl() = default;
+
+ CefTestServerImpl(const CefTestServerImpl&) = delete;
+ CefTestServerImpl& operator=(const CefTestServerImpl&) = delete;
+
+ bool Start(uint16 port,
+ bool https_server,
+ cef_test_cert_type_t https_cert_type,
+ CefRefPtr<CefTestServerHandler> handler);
+
+ // CefTestServer methods:
+ void Stop() override;
+ CefString GetOrigin() override;
+
+ private:
+ // Only accessed on the creation thread.
+ class Context;
+ std::unique_ptr<Context> context_;
+
+ // Safe to access on any thread.
+ CefString origin_;
+
+ IMPLEMENT_REFCOUNTING(CefTestServerImpl);
+};
+
+#endif // CEF_LIBCEF_BROWSER_TEST_TEST_SERVER_IMPL_H_
diff --git a/libcef/browser/thread_util.h b/libcef/browser/thread_util.h
new file mode 100644
index 00000000..f6651b78
--- /dev/null
+++ b/libcef/browser/thread_util.h
@@ -0,0 +1,119 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_THREAD_UTIL_H_
+#define CEF_LIBCEF_BROWSER_THREAD_UTIL_H_
+#pragma once
+
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/task/thread_pool.h"
+#include "base/threading/scoped_blocking_call.h"
+#include "base/threading/thread_restrictions.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/browser_thread.h"
+
+#define CEF_UIT content::BrowserThread::UI
+#define CEF_IOT content::BrowserThread::IO
+
+#define CEF_CURRENTLY_ON(id) content::BrowserThread::CurrentlyOn(id)
+#define CEF_CURRENTLY_ON_UIT() CEF_CURRENTLY_ON(CEF_UIT)
+#define CEF_CURRENTLY_ON_IOT() CEF_CURRENTLY_ON(CEF_IOT)
+
+#define CEF_REQUIRE(id) DCHECK(CEF_CURRENTLY_ON(id))
+#define CEF_REQUIRE_UIT() CEF_REQUIRE(CEF_UIT)
+#define CEF_REQUIRE_IOT() CEF_REQUIRE(CEF_IOT)
+
+#define CEF_REQUIRE_RETURN(id, var) \
+ if (!CEF_CURRENTLY_ON(id)) { \
+ NOTREACHED() << "called on invalid thread"; \
+ return var; \
+ }
+#define CEF_REQUIRE_UIT_RETURN(var) CEF_REQUIRE_RETURN(CEF_UIT, var)
+#define CEF_REQUIRE_IOT_RETURN(var) CEF_REQUIRE_RETURN(CEF_IOT, var)
+
+#define CEF_REQUIRE_RETURN_VOID(id) \
+ if (!CEF_CURRENTLY_ON(id)) { \
+ NOTREACHED() << "called on invalid thread"; \
+ return; \
+ }
+#define CEF_REQUIRE_UIT_RETURN_VOID() CEF_REQUIRE_RETURN_VOID(CEF_UIT)
+#define CEF_REQUIRE_IOT_RETURN_VOID() CEF_REQUIRE_RETURN_VOID(CEF_IOT)
+
+template <int id, std::enable_if_t<id == CEF_UIT, bool> = true>
+auto CEF_TASK_RUNNER() {
+ return content::GetUIThreadTaskRunner({});
+}
+template <int id, std::enable_if_t<id == CEF_IOT, bool> = true>
+auto CEF_TASK_RUNNER() {
+ return content::GetIOThreadTaskRunner({});
+}
+
+#define CEF_POST_TASK(id, task) CEF_TASK_RUNNER<id>()->PostTask(FROM_HERE, task)
+#define CEF_POST_DELAYED_TASK(id, task, delay_ms) \
+ CEF_TASK_RUNNER<id>()->PostDelayedTask(FROM_HERE, task, \
+ base::Milliseconds(delay_ms))
+
+// Post a blocking task with the specified |priority|. Tasks that have not
+// started executing at shutdown will never run. However, any task that has
+// already begun executing when shutdown is invoked will be allowed to continue
+// and will block shutdown until completion.
+// Tasks posted with this method are not guaranteed to run sequentially. Use
+// base::CreateSequencedTaskRunner instead if sequence is important.
+// Sequenced runners at various priorities that always execute all pending tasks
+// before shutdown are available via CefTaskRunnerManager and exposed by the CEF
+// API.
+#define CEF_POST_BLOCKING_TASK(priority, task) \
+ base::ThreadPool::PostTask( \
+ FROM_HERE, \
+ {priority, base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN, \
+ base::MayBlock()}, \
+ task)
+
+// Post a blocking task that affects UI or responsiveness of future user
+// interactions. Do not use if an immediate response to a user interaction is
+// expected.
+#define CEF_POST_USER_VISIBLE_TASK(task) \
+ CEF_POST_BLOCKING_TASK(base::TaskPriority::USER_VISIBLE, task)
+
+// Post a blocking task where the user won't notice if it takes an arbitrarily
+// long time to complete.
+#define CEF_POST_BACKGROUND_TASK(task) \
+ CEF_POST_BLOCKING_TASK(base::TaskPriority::BEST_EFFORT, task)
+
+// Assert that blocking is allowed on the current thread.
+#define CEF_REQUIRE_BLOCKING() \
+ base::ScopedBlockingCall scoped_blocking_call( \
+ FROM_HERE, base::BlockingType::WILL_BLOCK)
+
+// Same as IMPLEMENT_REFCOUNTING() but using the specified Destructor.
+#define IMPLEMENT_REFCOUNTING_EX(ClassName, Destructor) \
+ public: \
+ void AddRef() const override { \
+ ref_count_.AddRef(); \
+ } \
+ bool Release() const override { \
+ if (ref_count_.Release()) { \
+ Destructor::Destruct(this); \
+ return true; \
+ } \
+ return false; \
+ } \
+ bool HasOneRef() const override { \
+ return ref_count_.HasOneRef(); \
+ } \
+ bool HasAtLeastOneRef() const override { \
+ return ref_count_.HasAtLeastOneRef(); \
+ } \
+ \
+ private: \
+ CefRefCount ref_count_
+
+#define IMPLEMENT_REFCOUNTING_DELETE_ON_UIT(ClassName) \
+ IMPLEMENT_REFCOUNTING_EX(ClassName, content::BrowserThread::DeleteOnUIThread)
+
+#define IMPLEMENT_REFCOUNTING_DELETE_ON_IOT(ClassName) \
+ IMPLEMENT_REFCOUNTING_EX(ClassName, content::BrowserThread::DeleteOnIOThread)
+
+#endif // CEF_LIBCEF_BROWSER_THREAD_UTIL_H_
diff --git a/libcef/browser/trace_impl.cc b/libcef/browser/trace_impl.cc
new file mode 100644
index 00000000..8e7dc372
--- /dev/null
+++ b/libcef/browser/trace_impl.cc
@@ -0,0 +1,54 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#include "include/cef_trace.h"
+#include "libcef/browser/context.h"
+#include "libcef/browser/thread_util.h"
+#include "libcef/browser/trace_subscriber.h"
+
+#include "base/time/time.h"
+
+bool CefBeginTracing(const CefString& categories,
+ CefRefPtr<CefCompletionCallback> callback) {
+ if (!CONTEXT_STATE_VALID()) {
+ NOTREACHED() << "context not valid";
+ return false;
+ }
+
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ NOTREACHED() << "called on invalid thread";
+ return false;
+ }
+
+ CefTraceSubscriber* subscriber = CefContext::Get()->GetTraceSubscriber();
+ if (!subscriber) {
+ return false;
+ }
+
+ return subscriber->BeginTracing(categories, callback);
+}
+
+bool CefEndTracing(const CefString& tracing_file,
+ CefRefPtr<CefEndTracingCallback> callback) {
+ if (!CONTEXT_STATE_VALID()) {
+ NOTREACHED() << "context not valid";
+ return false;
+ }
+
+ if (!CEF_CURRENTLY_ON_UIT()) {
+ NOTREACHED() << "called on invalid thread";
+ return false;
+ }
+
+ CefTraceSubscriber* subscriber = CefContext::Get()->GetTraceSubscriber();
+ if (!subscriber) {
+ return false;
+ }
+
+ return subscriber->EndTracing(base::FilePath(tracing_file), callback);
+}
+
+int64 CefNowFromSystemTraceTime() {
+ return base::TimeTicks::Now().ToInternalValue();
+}
diff --git a/libcef/browser/trace_subscriber.cc b/libcef/browser/trace_subscriber.cc
new file mode 100644
index 00000000..1f6c0300
--- /dev/null
+++ b/libcef/browser/trace_subscriber.cc
@@ -0,0 +1,148 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#include "libcef/browser/trace_subscriber.h"
+#include "include/cef_trace.h"
+#include "libcef/browser/thread_util.h"
+
+#include "base/files/file_util.h"
+#include "base/task/single_thread_task_runner.h"
+#include "base/trace_event/trace_event.h"
+#include "content/public/browser/tracing_controller.h"
+
+namespace {
+
+// Create the temporary file and then execute |callback| on the thread
+// represented by |message_loop_proxy|.
+void CreateTemporaryFileOnBackgroundThread(
+ scoped_refptr<base::SequencedTaskRunner> message_loop_proxy,
+ base::OnceCallback<void(const base::FilePath&)> callback) {
+ CEF_REQUIRE_BLOCKING();
+ base::FilePath file_path;
+ if (!base::CreateTemporaryFile(&file_path)) {
+ LOG(ERROR) << "Failed to create temporary file.";
+ }
+ message_loop_proxy->PostTask(FROM_HERE,
+ base::BindOnce(std::move(callback), file_path));
+}
+
+// Release the wrapped callback object after completion.
+class CefCompletionCallbackWrapper : public CefCompletionCallback {
+ public:
+ explicit CefCompletionCallbackWrapper(
+ CefRefPtr<CefCompletionCallback> callback)
+ : callback_(callback) {}
+
+ CefCompletionCallbackWrapper(const CefCompletionCallbackWrapper&) = delete;
+ CefCompletionCallbackWrapper& operator=(const CefCompletionCallbackWrapper&) =
+ delete;
+
+ void OnComplete() override {
+ if (callback_) {
+ callback_->OnComplete();
+ callback_ = nullptr;
+ }
+ }
+
+ private:
+ CefRefPtr<CefCompletionCallback> callback_;
+
+ IMPLEMENT_REFCOUNTING(CefCompletionCallbackWrapper);
+};
+
+} // namespace
+
+using content::TracingController;
+
+CefTraceSubscriber::CefTraceSubscriber()
+ : collecting_trace_data_(false), weak_factory_(this) {
+ CEF_REQUIRE_UIT();
+}
+
+CefTraceSubscriber::~CefTraceSubscriber() {
+ CEF_REQUIRE_UIT();
+ if (collecting_trace_data_) {
+ TracingController::GetInstance()->StopTracing(nullptr);
+ }
+}
+
+bool CefTraceSubscriber::BeginTracing(
+ const std::string& categories,
+ CefRefPtr<CefCompletionCallback> callback) {
+ CEF_REQUIRE_UIT();
+
+ if (collecting_trace_data_) {
+ return false;
+ }
+
+ collecting_trace_data_ = true;
+
+ TracingController::StartTracingDoneCallback done_callback;
+ if (callback.get()) {
+ // Work around a bug introduced in http://crbug.com/542390#c22 that keeps a
+ // reference to |done_callback| after execution.
+ callback = new CefCompletionCallbackWrapper(callback);
+ done_callback =
+ base::BindOnce(&CefCompletionCallback::OnComplete, callback.get());
+ }
+
+ TracingController::GetInstance()->StartTracing(
+ base::trace_event::TraceConfig(categories, ""), std::move(done_callback));
+ return true;
+}
+
+bool CefTraceSubscriber::EndTracing(const base::FilePath& tracing_file,
+ CefRefPtr<CefEndTracingCallback> callback) {
+ CEF_REQUIRE_UIT();
+
+ if (!collecting_trace_data_) {
+ return false;
+ }
+
+ if (!callback.get()) {
+ // Discard the trace data.
+ collecting_trace_data_ = false;
+ TracingController::GetInstance()->StopTracing(nullptr);
+ return true;
+ }
+
+ if (tracing_file.empty()) {
+ // Create a new temporary file path on the FILE thread, then continue.
+ CEF_POST_USER_VISIBLE_TASK(
+ base::BindOnce(CreateTemporaryFileOnBackgroundThread,
+ base::SingleThreadTaskRunner::GetCurrentDefault(),
+ base::BindOnce(&CefTraceSubscriber::ContinueEndTracing,
+ weak_factory_.GetWeakPtr(), callback)));
+ return true;
+ }
+
+ auto result_callback =
+ base::BindOnce(&CefTraceSubscriber::OnTracingFileResult,
+ weak_factory_.GetWeakPtr(), callback, tracing_file);
+
+ TracingController::GetInstance()->StopTracing(
+ TracingController::CreateFileEndpoint(tracing_file,
+ std::move(result_callback),
+ base::TaskPriority::USER_VISIBLE));
+ return true;
+}
+
+void CefTraceSubscriber::ContinueEndTracing(
+ CefRefPtr<CefEndTracingCallback> callback,
+ const base::FilePath& tracing_file) {
+ CEF_REQUIRE_UIT();
+ if (!tracing_file.empty()) {
+ EndTracing(tracing_file, callback);
+ }
+}
+
+void CefTraceSubscriber::OnTracingFileResult(
+ CefRefPtr<CefEndTracingCallback> callback,
+ const base::FilePath& tracing_file) {
+ CEF_REQUIRE_UIT();
+
+ collecting_trace_data_ = false;
+
+ callback->OnEndTracingComplete(tracing_file.value());
+}
diff --git a/libcef/browser/trace_subscriber.h b/libcef/browser/trace_subscriber.h
new file mode 100644
index 00000000..007b15e1
--- /dev/null
+++ b/libcef/browser/trace_subscriber.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_TRACE_SUBSCRIBER_H_
+#define CEF_LIBCEF_BROWSER_TRACE_SUBSCRIBER_H_
+#pragma once
+
+#include "include/cef_trace.h"
+
+#include "base/files/file_path.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/memory/weak_ptr.h"
+
+// May only be accessed on the browser process UI thread.
+class CefTraceSubscriber {
+ public:
+ CefTraceSubscriber();
+ virtual ~CefTraceSubscriber();
+
+ bool BeginTracing(const std::string& categories,
+ CefRefPtr<CefCompletionCallback> callback);
+ bool EndTracing(const base::FilePath& tracing_file,
+ CefRefPtr<CefEndTracingCallback> callback);
+
+ private:
+ void ContinueEndTracing(CefRefPtr<CefEndTracingCallback> callback,
+ const base::FilePath& tracing_file);
+ void OnTracingFileResult(CefRefPtr<CefEndTracingCallback> callback,
+ const base::FilePath& tracing_file);
+
+ bool collecting_trace_data_;
+ base::WeakPtrFactory<CefTraceSubscriber> weak_factory_;
+};
+
+#endif // CEF_LIBCEF_BROWSER_TRACE_SUBSCRIBER_H_
diff --git a/libcef/browser/views/basic_label_button_impl.cc b/libcef/browser/views/basic_label_button_impl.cc
new file mode 100644
index 00000000..41ae1fe3
--- /dev/null
+++ b/libcef/browser/views/basic_label_button_impl.cc
@@ -0,0 +1,40 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#include "libcef/browser/views/basic_label_button_impl.h"
+
+#include "libcef/browser/views/basic_label_button_view.h"
+
+// static
+CefRefPtr<CefLabelButton> CefLabelButton::CreateLabelButton(
+ CefRefPtr<CefButtonDelegate> delegate,
+ const CefString& text) {
+ return CefBasicLabelButtonImpl::Create(delegate, text);
+}
+
+// static
+CefRefPtr<CefBasicLabelButtonImpl> CefBasicLabelButtonImpl::Create(
+ CefRefPtr<CefButtonDelegate> delegate,
+ const CefString& text) {
+ CEF_REQUIRE_UIT_RETURN(nullptr);
+ CefRefPtr<CefBasicLabelButtonImpl> label_button =
+ new CefBasicLabelButtonImpl(delegate);
+ label_button->Initialize();
+ if (!text.empty()) {
+ label_button->SetText(text);
+ }
+ return label_button;
+}
+
+CefBasicLabelButtonImpl::CefBasicLabelButtonImpl(
+ CefRefPtr<CefButtonDelegate> delegate)
+ : ParentClass(delegate) {}
+
+views::LabelButton* CefBasicLabelButtonImpl::CreateRootView() {
+ return new CefBasicLabelButtonView(delegate());
+}
+
+void CefBasicLabelButtonImpl::InitializeRootView() {
+ static_cast<CefBasicLabelButtonView*>(root_view())->Initialize();
+}
diff --git a/libcef/browser/views/basic_label_button_impl.h b/libcef/browser/views/basic_label_button_impl.h
new file mode 100644
index 00000000..8621c71c
--- /dev/null
+++ b/libcef/browser/views/basic_label_button_impl.h
@@ -0,0 +1,47 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_VIEWS_BASIC_LABEL_BUTTON_IMPL_H_
+#define CEF_LIBCEF_BROWSER_VIEWS_BASIC_LABEL_BUTTON_IMPL_H_
+#pragma once
+
+#include "include/views/cef_button_delegate.h"
+#include "include/views/cef_label_button.h"
+
+#include "libcef/browser/views/label_button_impl.h"
+
+#include "ui/views/controls/button/label_button.h"
+
+class CefBasicLabelButtonImpl : public CefLabelButtonImpl<views::LabelButton,
+ CefLabelButton,
+ CefButtonDelegate> {
+ public:
+ using ParentClass =
+ CefLabelButtonImpl<views::LabelButton, CefLabelButton, CefButtonDelegate>;
+
+ CefBasicLabelButtonImpl(const CefBasicLabelButtonImpl&) = delete;
+ CefBasicLabelButtonImpl& operator=(const CefBasicLabelButtonImpl&) = delete;
+
+ // Create a new CefLabelButton instance. |delegate| may be nullptr.
+ static CefRefPtr<CefBasicLabelButtonImpl> Create(
+ CefRefPtr<CefButtonDelegate> delegate,
+ const CefString& text);
+
+ // CefViewAdapter methods:
+ std::string GetDebugType() override { return "LabelButton"; }
+
+ private:
+ // Create a new implementation object.
+ // Always call Initialize() after creation.
+ // |delegate| may be nullptr.
+ explicit CefBasicLabelButtonImpl(CefRefPtr<CefButtonDelegate> delegate);
+
+ // CefViewImpl methods:
+ views::LabelButton* CreateRootView() override;
+ void InitializeRootView() override;
+
+ IMPLEMENT_REFCOUNTING_DELETE_ON_UIT(CefBasicLabelButtonImpl);
+};
+
+#endif // CEF_LIBCEF_BROWSER_VIEWS_BASIC_LABEL_BUTTON_IMPL_H_
diff --git a/libcef/browser/views/basic_label_button_view.cc b/libcef/browser/views/basic_label_button_view.cc
new file mode 100644
index 00000000..607806b1
--- /dev/null
+++ b/libcef/browser/views/basic_label_button_view.cc
@@ -0,0 +1,9 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#include "libcef/browser/views/basic_label_button_view.h"
+
+CefBasicLabelButtonView::CefBasicLabelButtonView(
+ CefButtonDelegate* cef_delegate)
+ : ParentClass(cef_delegate) {}
diff --git a/libcef/browser/views/basic_label_button_view.h b/libcef/browser/views/basic_label_button_view.h
new file mode 100644
index 00000000..adee1c3c
--- /dev/null
+++ b/libcef/browser/views/basic_label_button_view.h
@@ -0,0 +1,43 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_VIEWS_BASIC_LABEL_BUTTON_VIEW_H_
+#define CEF_LIBCEF_BROWSER_VIEWS_BASIC_LABEL_BUTTON_VIEW_H_
+#pragma once
+
+#include "include/views/cef_button_delegate.h"
+
+#include "libcef/browser/views/label_button_view.h"
+
+#include "ui/views/controls/button/label_button.h"
+
+// Extend views::LabelButton with a no-argument constructor as required by the
+// CefViewView template and extend views::ButtonListener as required by the
+// CefButtonView template.
+class LabelButtonEx : public views::LabelButton {
+ public:
+ LabelButtonEx()
+ : views::LabelButton(base::BindRepeating(
+ [](LabelButtonEx* self, const ui::Event& event) {
+ self->ButtonPressed(event);
+ },
+ base::Unretained(this)),
+ std::u16string()) {}
+
+ virtual void ButtonPressed(const ui::Event& event) = 0;
+};
+
+class CefBasicLabelButtonView
+ : public CefLabelButtonView<LabelButtonEx, CefButtonDelegate> {
+ public:
+ using ParentClass = CefLabelButtonView<LabelButtonEx, CefButtonDelegate>;
+
+ // |cef_delegate| may be nullptr.
+ explicit CefBasicLabelButtonView(CefButtonDelegate* cef_delegate);
+
+ CefBasicLabelButtonView(const CefBasicLabelButtonView&) = delete;
+ CefBasicLabelButtonView& operator=(const CefBasicLabelButtonView&) = delete;
+};
+
+#endif // CEF_LIBCEF_BROWSER_VIEWS_BASIC_LABEL_BUTTON_VIEW_H_
diff --git a/libcef/browser/views/basic_panel_impl.cc b/libcef/browser/views/basic_panel_impl.cc
new file mode 100644
index 00000000..e7b36b3e
--- /dev/null
+++ b/libcef/browser/views/basic_panel_impl.cc
@@ -0,0 +1,33 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#include "libcef/browser/views/basic_panel_impl.h"
+
+#include "libcef/browser/views/basic_panel_view.h"
+
+// static
+CefRefPtr<CefPanel> CefPanel::CreatePanel(
+ CefRefPtr<CefPanelDelegate> delegate) {
+ return CefBasicPanelImpl::Create(delegate);
+}
+
+// static
+CefRefPtr<CefBasicPanelImpl> CefBasicPanelImpl::Create(
+ CefRefPtr<CefPanelDelegate> delegate) {
+ CEF_REQUIRE_UIT_RETURN(nullptr);
+ CefRefPtr<CefBasicPanelImpl> panel = new CefBasicPanelImpl(delegate);
+ panel->Initialize();
+ return panel;
+}
+
+CefBasicPanelImpl::CefBasicPanelImpl(CefRefPtr<CefPanelDelegate> delegate)
+ : ParentClass(delegate) {}
+
+views::View* CefBasicPanelImpl::CreateRootView() {
+ return new CefBasicPanelView(delegate());
+}
+
+void CefBasicPanelImpl::InitializeRootView() {
+ static_cast<CefBasicPanelView*>(root_view())->Initialize();
+}
diff --git a/libcef/browser/views/basic_panel_impl.h b/libcef/browser/views/basic_panel_impl.h
new file mode 100644
index 00000000..06ffb7ee
--- /dev/null
+++ b/libcef/browser/views/basic_panel_impl.h
@@ -0,0 +1,44 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_VIEWS_BASIC_PANEL_IMPL_H_
+#define CEF_LIBCEF_BROWSER_VIEWS_BASIC_PANEL_IMPL_H_
+#pragma once
+
+#include "include/views/cef_panel.h"
+#include "include/views/cef_panel_delegate.h"
+
+#include "libcef/browser/views/panel_impl.h"
+
+#include "ui/views/view.h"
+
+class CefBasicPanelImpl
+ : public CefPanelImpl<views::View, CefPanel, CefPanelDelegate> {
+ public:
+ using ParentClass = CefPanelImpl<views::View, CefPanel, CefPanelDelegate>;
+
+ CefBasicPanelImpl(const CefBasicPanelImpl&) = delete;
+ CefBasicPanelImpl& operator=(const CefBasicPanelImpl&) = delete;
+
+ // Create a new CefPanel instance. |delegate| may be nullptr.
+ static CefRefPtr<CefBasicPanelImpl> Create(
+ CefRefPtr<CefPanelDelegate> delegate);
+
+ // CefViewAdapter methods:
+ std::string GetDebugType() override { return "Panel"; }
+
+ private:
+ // Create a new implementation object.
+ // Always call Initialize() after creation.
+ // |delegate| may be nullptr.
+ explicit CefBasicPanelImpl(CefRefPtr<CefPanelDelegate> delegate);
+
+ // CefViewImpl methods:
+ views::View* CreateRootView() override;
+ void InitializeRootView() override;
+
+ IMPLEMENT_REFCOUNTING_DELETE_ON_UIT(CefBasicPanelImpl);
+};
+
+#endif // CEF_LIBCEF_BROWSER_VIEWS_BASIC_PANEL_IMPL_H_
diff --git a/libcef/browser/views/basic_panel_view.cc b/libcef/browser/views/basic_panel_view.cc
new file mode 100644
index 00000000..7df66a36
--- /dev/null
+++ b/libcef/browser/views/basic_panel_view.cc
@@ -0,0 +1,8 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#include "libcef/browser/views/basic_panel_view.h"
+
+CefBasicPanelView::CefBasicPanelView(CefPanelDelegate* cef_delegate)
+ : ParentClass(cef_delegate) {}
diff --git a/libcef/browser/views/basic_panel_view.h b/libcef/browser/views/basic_panel_view.h
new file mode 100644
index 00000000..659b7cb1
--- /dev/null
+++ b/libcef/browser/views/basic_panel_view.h
@@ -0,0 +1,24 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_VIEWS_BASIC_PANEL_VIEW_H_
+#define CEF_LIBCEF_BROWSER_VIEWS_BASIC_PANEL_VIEW_H_
+#pragma once
+
+#include "include/views/cef_panel_delegate.h"
+
+#include "libcef/browser/views/panel_view.h"
+
+class CefBasicPanelView : public CefPanelView<views::View, CefPanelDelegate> {
+ public:
+ using ParentClass = CefPanelView<views::View, CefPanelDelegate>;
+
+ // |cef_delegate| may be nullptr.
+ explicit CefBasicPanelView(CefPanelDelegate* cef_delegate);
+
+ CefBasicPanelView(const CefBasicPanelView&) = delete;
+ CefBasicPanelView& operator=(const CefBasicPanelView&) = delete;
+};
+
+#endif // CEF_LIBCEF_BROWSER_VIEWS_BASIC_PANEL_VIEW_H_
diff --git a/libcef/browser/views/box_layout_impl.cc b/libcef/browser/views/box_layout_impl.cc
new file mode 100644
index 00000000..0305ef82
--- /dev/null
+++ b/libcef/browser/views/box_layout_impl.cc
@@ -0,0 +1,82 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#include "libcef/browser/views/box_layout_impl.h"
+
+#include "libcef/browser/thread_util.h"
+#include "libcef/browser/views/view_util.h"
+
+// static
+CefRefPtr<CefBoxLayoutImpl> CefBoxLayoutImpl::Create(
+ const CefBoxLayoutSettings& settings,
+ views::View* owner_view) {
+ CEF_REQUIRE_UIT_RETURN(nullptr);
+ CefRefPtr<CefBoxLayoutImpl> impl = new CefBoxLayoutImpl(settings);
+ impl->Initialize(owner_view);
+ return impl;
+}
+
+void CefBoxLayoutImpl::SetFlexForView(CefRefPtr<CefView> view, int flex) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ DCHECK_GE(flex, 0);
+ if (flex < 0) {
+ return;
+ }
+
+ DCHECK(view && view->IsValid() && view->IsAttached());
+ if (!view || !view->IsValid() || !view->IsAttached()) {
+ return;
+ }
+
+ views::View* view_ptr = view_util::GetFor(view);
+ DCHECK_EQ(view_ptr->parent(), owner_view());
+ if (view_ptr->parent() != owner_view()) {
+ return;
+ }
+
+ layout()->SetFlexForView(view_ptr, flex);
+}
+
+void CefBoxLayoutImpl::ClearFlexForView(CefRefPtr<CefView> view) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ DCHECK(view && view->IsValid() && view->IsAttached());
+ if (!view || !view->IsValid() || !view->IsAttached()) {
+ return;
+ }
+
+ views::View* view_ptr = view_util::GetFor(view);
+ DCHECK_EQ(view_ptr->parent(), owner_view());
+ if (view_ptr->parent() != owner_view()) {
+ return;
+ }
+
+ layout()->ClearFlexForView(view_ptr);
+}
+
+CefBoxLayoutImpl::CefBoxLayoutImpl(const CefBoxLayoutSettings& settings)
+ : settings_(settings) {}
+
+views::BoxLayout* CefBoxLayoutImpl::CreateLayout() {
+ views::BoxLayout* layout = new views::BoxLayout(
+ settings_.horizontal ? views::BoxLayout::Orientation::kHorizontal
+ : views::BoxLayout::Orientation::kVertical,
+ gfx::Insets::VH(settings_.inside_border_vertical_spacing,
+ settings_.inside_border_horizontal_spacing),
+ settings_.between_child_spacing);
+ layout->set_main_axis_alignment(
+ static_cast<views::BoxLayout::MainAxisAlignment>(
+ settings_.main_axis_alignment));
+ layout->set_cross_axis_alignment(
+ static_cast<views::BoxLayout::CrossAxisAlignment>(
+ settings_.cross_axis_alignment));
+ layout->set_inside_border_insets(gfx::Insets::TLBR(
+ settings_.inside_border_insets.top, settings_.inside_border_insets.left,
+ settings_.inside_border_insets.bottom,
+ settings_.inside_border_insets.right));
+ layout->set_minimum_cross_axis_size(settings_.minimum_cross_axis_size);
+ if (settings_.default_flex > 0) {
+ layout->SetDefaultFlex(settings_.default_flex);
+ }
+ return layout;
+}
diff --git a/libcef/browser/views/box_layout_impl.h b/libcef/browser/views/box_layout_impl.h
new file mode 100644
index 00000000..a6ae5f1c
--- /dev/null
+++ b/libcef/browser/views/box_layout_impl.h
@@ -0,0 +1,44 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_VIEWS_BOX_LAYOUT_IMPL_H_
+#define CEF_LIBCEF_BROWSER_VIEWS_BOX_LAYOUT_IMPL_H_
+#pragma once
+
+#include "include/views/cef_box_layout.h"
+
+#include "libcef/browser/views/layout_impl.h"
+#include "ui/views/layout/box_layout.h"
+
+class CefBoxLayoutImpl : public CefLayoutImpl<views::BoxLayout, CefBoxLayout> {
+ public:
+ // Necessary for the CEF_REQUIRE_VALID_*() macros to compile.
+ using ParentClass = CefLayoutImpl<views::BoxLayout, CefBoxLayout>;
+
+ CefBoxLayoutImpl(const CefBoxLayoutImpl&) = delete;
+ CefBoxLayoutImpl& operator=(const CefBoxLayoutImpl&) = delete;
+
+ // Create a new CefBoxLayout insance. |owner_view| must be non-nullptr.
+ static CefRefPtr<CefBoxLayoutImpl> Create(
+ const CefBoxLayoutSettings& settings,
+ views::View* owner_view);
+
+ // CefBoxLayout methods:
+ void SetFlexForView(CefRefPtr<CefView> view, int flex) override;
+ void ClearFlexForView(CefRefPtr<CefView> view) override;
+
+ // CefLayout methods:
+ CefRefPtr<CefBoxLayout> AsBoxLayout() override { return this; }
+
+ private:
+ explicit CefBoxLayoutImpl(const CefBoxLayoutSettings& settings);
+
+ views::BoxLayout* CreateLayout() override;
+
+ CefBoxLayoutSettings settings_;
+
+ IMPLEMENT_REFCOUNTING_DELETE_ON_UIT(CefBoxLayoutImpl);
+};
+
+#endif // CEF_LIBCEF_BROWSER_VIEWS_BOX_LAYOUT_IMPL_H_
diff --git a/libcef/browser/views/browser_platform_delegate_views.cc b/libcef/browser/views/browser_platform_delegate_views.cc
new file mode 100644
index 00000000..fc5af6b8
--- /dev/null
+++ b/libcef/browser/views/browser_platform_delegate_views.cc
@@ -0,0 +1,303 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/browser/views/browser_platform_delegate_views.h"
+
+#include <utility>
+
+#include "include/views/cef_window.h"
+#include "libcef/browser/alloy/alloy_browser_host_impl.h"
+#include "libcef/browser/views/browser_view_impl.h"
+#include "libcef/browser/views/menu_runner_views.h"
+
+#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host.h"
+#include "ui/views/widget/widget.h"
+
+namespace {
+
+// Default popup window delegate implementation.
+class PopupWindowDelegate : public CefWindowDelegate {
+ public:
+ explicit PopupWindowDelegate(CefRefPtr<CefBrowserView> browser_view)
+ : browser_view_(browser_view) {}
+
+ PopupWindowDelegate(const PopupWindowDelegate&) = delete;
+ PopupWindowDelegate& operator=(const PopupWindowDelegate&) = delete;
+
+ void OnWindowCreated(CefRefPtr<CefWindow> window) override {
+ window->AddChildView(browser_view_);
+ window->Show();
+ browser_view_->RequestFocus();
+ }
+
+ void OnWindowDestroyed(CefRefPtr<CefWindow> window) override {
+ browser_view_ = nullptr;
+ }
+
+ bool CanClose(CefRefPtr<CefWindow> window) override {
+ CefRefPtr<CefBrowser> browser = browser_view_->GetBrowser();
+ if (browser) {
+ return browser->GetHost()->TryCloseBrowser();
+ }
+ return true;
+ }
+
+ private:
+ CefRefPtr<CefBrowserView> browser_view_;
+
+ IMPLEMENT_REFCOUNTING(PopupWindowDelegate);
+};
+
+} // namespace
+
+CefBrowserPlatformDelegateViews::CefBrowserPlatformDelegateViews(
+ std::unique_ptr<CefBrowserPlatformDelegateNative> native_delegate,
+ CefRefPtr<CefBrowserViewImpl> browser_view)
+ : native_delegate_(std::move(native_delegate)) {
+ if (browser_view) {
+ SetBrowserView(browser_view);
+ }
+ native_delegate_->set_windowless_handler(this);
+}
+
+void CefBrowserPlatformDelegateViews::SetBrowserView(
+ CefRefPtr<CefBrowserViewImpl> browser_view) {
+ DCHECK(!browser_view_);
+ DCHECK(browser_view);
+ browser_view_ = browser_view;
+}
+
+void CefBrowserPlatformDelegateViews::WebContentsCreated(
+ content::WebContents* web_contents,
+ bool owned) {
+ CefBrowserPlatformDelegateAlloy::WebContentsCreated(web_contents, owned);
+ native_delegate_->WebContentsCreated(web_contents, /*owned=*/false);
+ browser_view_->WebContentsCreated(web_contents);
+}
+
+void CefBrowserPlatformDelegateViews::WebContentsDestroyed(
+ content::WebContents* web_contents) {
+ CefBrowserPlatformDelegateAlloy::WebContentsDestroyed(web_contents);
+ native_delegate_->WebContentsDestroyed(web_contents);
+}
+
+void CefBrowserPlatformDelegateViews::BrowserCreated(
+ CefBrowserHostBase* browser) {
+ CefBrowserPlatformDelegateAlloy::BrowserCreated(browser);
+
+ native_delegate_->BrowserCreated(browser);
+ browser_view_->BrowserCreated(browser, GetBoundsChangedCallback());
+}
+
+void CefBrowserPlatformDelegateViews::NotifyBrowserCreated() {
+ DCHECK(browser_view_);
+ DCHECK(browser_);
+ if (browser_view_->delegate()) {
+ browser_view_->delegate()->OnBrowserCreated(browser_view_, browser_);
+ }
+}
+
+void CefBrowserPlatformDelegateViews::NotifyBrowserDestroyed() {
+ DCHECK(browser_view_);
+ DCHECK(browser_);
+ if (browser_view_->delegate()) {
+ browser_view_->delegate()->OnBrowserDestroyed(browser_view_, browser_);
+ }
+}
+
+void CefBrowserPlatformDelegateViews::BrowserDestroyed(
+ CefBrowserHostBase* browser) {
+ CefBrowserPlatformDelegateAlloy::BrowserDestroyed(browser);
+
+ browser_view_->BrowserDestroyed(browser);
+ browser_view_ = nullptr;
+ native_delegate_->BrowserDestroyed(browser);
+}
+
+bool CefBrowserPlatformDelegateViews::CreateHostWindow() {
+ // Nothing to do here.
+ return true;
+}
+
+void CefBrowserPlatformDelegateViews::CloseHostWindow() {
+ views::Widget* widget = GetWindowWidget();
+ if (widget && !widget->IsClosed()) {
+ widget->Close();
+ }
+}
+
+CefWindowHandle CefBrowserPlatformDelegateViews::GetHostWindowHandle() const {
+ return view_util::GetWindowHandle(GetWindowWidget());
+}
+
+views::Widget* CefBrowserPlatformDelegateViews::GetWindowWidget() const {
+ if (browser_view_->root_view()) {
+ return browser_view_->root_view()->GetWidget();
+ }
+ return nullptr;
+}
+
+CefRefPtr<CefBrowserView> CefBrowserPlatformDelegateViews::GetBrowserView()
+ const {
+ return browser_view_.get();
+}
+
+void CefBrowserPlatformDelegateViews::PopupWebContentsCreated(
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefClient> client,
+ content::WebContents* new_web_contents,
+ CefBrowserPlatformDelegate* new_platform_delegate,
+ bool is_devtools) {
+ DCHECK(new_platform_delegate->IsViewsHosted());
+ CefBrowserPlatformDelegateViews* new_platform_delegate_impl =
+ static_cast<CefBrowserPlatformDelegateViews*>(new_platform_delegate);
+
+ CefRefPtr<CefBrowserViewDelegate> new_delegate;
+ if (browser_view_->delegate()) {
+ new_delegate = browser_view_->delegate()->GetDelegateForPopupBrowserView(
+ browser_view_.get(), settings, client, is_devtools);
+ }
+
+ // Create a new BrowserView for the popup.
+ CefRefPtr<CefBrowserViewImpl> new_browser_view =
+ CefBrowserViewImpl::CreateForPopup(settings, new_delegate);
+
+ // Associate the PlatformDelegate with the new BrowserView.
+ new_platform_delegate_impl->SetBrowserView(new_browser_view);
+}
+
+void CefBrowserPlatformDelegateViews::PopupBrowserCreated(
+ CefBrowserHostBase* new_browser,
+ bool is_devtools) {
+ CefRefPtr<CefBrowserView> new_browser_view =
+ CefBrowserView::GetForBrowser(new_browser);
+ DCHECK(new_browser_view);
+
+ bool popup_handled = false;
+ if (browser_view_->delegate()) {
+ popup_handled = browser_view_->delegate()->OnPopupBrowserViewCreated(
+ browser_view_.get(), new_browser_view.get(), is_devtools);
+ }
+
+ if (!popup_handled) {
+ CefWindow::CreateTopLevelWindow(
+ new PopupWindowDelegate(new_browser_view.get()));
+ }
+}
+
+SkColor CefBrowserPlatformDelegateViews::GetBackgroundColor() const {
+ return native_delegate_->GetBackgroundColor();
+}
+
+void CefBrowserPlatformDelegateViews::WasResized() {
+ native_delegate_->WasResized();
+}
+
+void CefBrowserPlatformDelegateViews::SendKeyEvent(const CefKeyEvent& event) {
+ native_delegate_->SendKeyEvent(event);
+}
+
+void CefBrowserPlatformDelegateViews::SendMouseClickEvent(
+ const CefMouseEvent& event,
+ CefBrowserHost::MouseButtonType type,
+ bool mouseUp,
+ int clickCount) {
+ native_delegate_->SendMouseClickEvent(event, type, mouseUp, clickCount);
+}
+
+void CefBrowserPlatformDelegateViews::SendMouseMoveEvent(
+ const CefMouseEvent& event,
+ bool mouseLeave) {
+ native_delegate_->SendMouseMoveEvent(event, mouseLeave);
+}
+
+void CefBrowserPlatformDelegateViews::SendMouseWheelEvent(
+ const CefMouseEvent& event,
+ int deltaX,
+ int deltaY) {
+ native_delegate_->SendMouseWheelEvent(event, deltaX, deltaY);
+}
+
+void CefBrowserPlatformDelegateViews::SendTouchEvent(
+ const CefTouchEvent& event) {
+ native_delegate_->SendTouchEvent(event);
+}
+
+void CefBrowserPlatformDelegateViews::SetFocus(bool setFocus) {
+ // Will activate the Widget and result in a call to WebContents::Focus().
+ if (setFocus && browser_view_->root_view()) {
+ if (auto widget = GetWindowWidget()) {
+ // Don't activate a minimized Widget, or it will be shown.
+ if (widget->IsMinimized()) {
+ return;
+ }
+ }
+ browser_view_->root_view()->RequestFocus();
+ }
+}
+
+gfx::Point CefBrowserPlatformDelegateViews::GetScreenPoint(
+ const gfx::Point& view_pt,
+ bool want_dip_coords) const {
+ if (!browser_view_->root_view()) {
+ return view_pt;
+ }
+
+ gfx::Point screen_point = view_pt;
+ view_util::ConvertPointToScreen(browser_view_->root_view(), &screen_point,
+ /*output_pixel_coords=*/!want_dip_coords);
+ return screen_point;
+}
+
+void CefBrowserPlatformDelegateViews::ViewText(const std::string& text) {
+ native_delegate_->ViewText(text);
+}
+
+bool CefBrowserPlatformDelegateViews::HandleKeyboardEvent(
+ const content::NativeWebKeyboardEvent& event) {
+ // The BrowserView will handle accelerators.
+ return browser_view_->HandleKeyboardEvent(event);
+}
+
+CefEventHandle CefBrowserPlatformDelegateViews::GetEventHandle(
+ const content::NativeWebKeyboardEvent& event) const {
+ return native_delegate_->GetEventHandle(event);
+}
+
+std::unique_ptr<CefMenuRunner>
+CefBrowserPlatformDelegateViews::CreateMenuRunner() {
+ return base::WrapUnique(new CefMenuRunnerViews(browser_view_.get()));
+}
+
+bool CefBrowserPlatformDelegateViews::IsViewsHosted() const {
+ return true;
+}
+
+gfx::Point CefBrowserPlatformDelegateViews::GetDialogPosition(
+ const gfx::Size& size) {
+ const gfx::Rect& bounds = browser_view_->root_view()->GetBoundsInScreen();
+
+ // Offset relative to the top-level content view.
+ gfx::Point offset = bounds.origin();
+ view_util::ConvertPointFromScreen(
+ browser_view_->root_view()->GetWidget()->GetRootView(), &offset, false);
+
+ return gfx::Point(offset.x() + (bounds.width() - size.width()) / 2,
+ offset.y() + (bounds.height() - size.height()) / 2);
+}
+
+gfx::Size CefBrowserPlatformDelegateViews::GetMaximumDialogSize() {
+ return browser_view_->root_view()->GetBoundsInScreen().size();
+}
+
+CefWindowHandle CefBrowserPlatformDelegateViews::GetParentWindowHandle() const {
+ return GetHostWindowHandle();
+}
+
+gfx::Point CefBrowserPlatformDelegateViews::GetParentScreenPoint(
+ const gfx::Point& view,
+ bool want_dip_coords) const {
+ return GetScreenPoint(view, want_dip_coords);
+}
diff --git a/libcef/browser/views/browser_platform_delegate_views.h b/libcef/browser/views/browser_platform_delegate_views.h
new file mode 100644
index 00000000..fb2714b9
--- /dev/null
+++ b/libcef/browser/views/browser_platform_delegate_views.h
@@ -0,0 +1,81 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_VIEWS_BROWSER_PLATFORM_DELEGATE_VIEWS_H_
+#define CEF_LIBCEF_BROWSER_VIEWS_BROWSER_PLATFORM_DELEGATE_VIEWS_H_
+
+#include "libcef/browser/alloy/browser_platform_delegate_alloy.h"
+#include "libcef/browser/native/browser_platform_delegate_native.h"
+#include "libcef/browser/views/browser_view_impl.h"
+
+// Implementation of Views-based browser functionality.
+class CefBrowserPlatformDelegateViews
+ : public CefBrowserPlatformDelegateAlloy,
+ public CefBrowserPlatformDelegateNative::WindowlessHandler {
+ public:
+ // Platform-specific behaviors will be delegated to |native_delegate|.
+ // |browser_view_getter| may be initially empty for popup browsers.
+ CefBrowserPlatformDelegateViews(
+ std::unique_ptr<CefBrowserPlatformDelegateNative> native_delegate,
+ CefRefPtr<CefBrowserViewImpl> browser_view);
+
+ // CefBrowserPlatformDelegate methods:
+ void WebContentsCreated(content::WebContents* web_contents,
+ bool owned) override;
+ void WebContentsDestroyed(content::WebContents* web_contents) override;
+ void BrowserCreated(CefBrowserHostBase* browser) override;
+ void NotifyBrowserCreated() override;
+ void NotifyBrowserDestroyed() override;
+ void BrowserDestroyed(CefBrowserHostBase* browser) override;
+ bool CreateHostWindow() override;
+ void CloseHostWindow() override;
+ CefWindowHandle GetHostWindowHandle() const override;
+ views::Widget* GetWindowWidget() const override;
+ CefRefPtr<CefBrowserView> GetBrowserView() const override;
+ void PopupWebContentsCreated(
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefClient> client,
+ content::WebContents* new_web_contents,
+ CefBrowserPlatformDelegate* new_platform_delegate,
+ bool is_devtools) override;
+ void PopupBrowserCreated(CefBrowserHostBase* new_browser,
+ bool is_devtools) override;
+ SkColor GetBackgroundColor() const override;
+ void WasResized() override;
+ void SendKeyEvent(const CefKeyEvent& event) override;
+ void SendMouseClickEvent(const CefMouseEvent& event,
+ CefBrowserHost::MouseButtonType type,
+ bool mouseUp,
+ int clickCount) override;
+ void SendMouseMoveEvent(const CefMouseEvent& event, bool mouseLeave) override;
+ void SendMouseWheelEvent(const CefMouseEvent& event,
+ int deltaX,
+ int deltaY) override;
+ void SendTouchEvent(const CefTouchEvent& event) override;
+ void SetFocus(bool setFocus) override;
+ gfx::Point GetScreenPoint(const gfx::Point& view,
+ bool want_dip_coords) const override;
+ void ViewText(const std::string& text) override;
+ bool HandleKeyboardEvent(
+ const content::NativeWebKeyboardEvent& event) override;
+ CefEventHandle GetEventHandle(
+ const content::NativeWebKeyboardEvent& event) const override;
+ std::unique_ptr<CefMenuRunner> CreateMenuRunner() override;
+ bool IsViewsHosted() const override;
+ gfx::Point GetDialogPosition(const gfx::Size& size) override;
+ gfx::Size GetMaximumDialogSize() override;
+
+ // CefBrowserPlatformDelegateNative::WindowlessHandler methods:
+ CefWindowHandle GetParentWindowHandle() const override;
+ gfx::Point GetParentScreenPoint(const gfx::Point& view,
+ bool want_dip_coords) const override;
+
+ private:
+ void SetBrowserView(CefRefPtr<CefBrowserViewImpl> browser_view);
+
+ std::unique_ptr<CefBrowserPlatformDelegateNative> native_delegate_;
+ CefRefPtr<CefBrowserViewImpl> browser_view_;
+};
+
+#endif // CEF_LIBCEF_BROWSER_VIEWS_BROWSER_PLATFORM_DELEGATE_VIEWS_H_
diff --git a/libcef/browser/views/browser_view_impl.cc b/libcef/browser/views/browser_view_impl.cc
new file mode 100644
index 00000000..74ccef21
--- /dev/null
+++ b/libcef/browser/views/browser_view_impl.cc
@@ -0,0 +1,315 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#include "libcef/browser/views/browser_view_impl.h"
+
+#include "libcef/browser/browser_host_base.h"
+#include "libcef/browser/browser_util.h"
+#include "libcef/browser/chrome/views/chrome_browser_view.h"
+#include "libcef/browser/context.h"
+#include "libcef/browser/request_context_impl.h"
+#include "libcef/browser/thread_util.h"
+#include "libcef/browser/views/window_impl.h"
+
+#include "content/public/browser/native_web_keyboard_event.h"
+#include "ui/content_accelerators/accelerator_util.h"
+
+// static
+CefRefPtr<CefBrowserView> CefBrowserView::CreateBrowserView(
+ CefRefPtr<CefClient> client,
+ const CefString& url,
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefDictionaryValue> extra_info,
+ CefRefPtr<CefRequestContext> request_context,
+ CefRefPtr<CefBrowserViewDelegate> delegate) {
+ return CefBrowserViewImpl::Create(CefWindowInfo(), client, url, settings,
+ extra_info, request_context, delegate);
+}
+
+// static
+CefRefPtr<CefBrowserView> CefBrowserView::GetForBrowser(
+ CefRefPtr<CefBrowser> browser) {
+ CEF_REQUIRE_UIT_RETURN(nullptr);
+
+ CefBrowserHostBase* browser_impl =
+ static_cast<CefBrowserHostBase*>(browser.get());
+ if (browser_impl && browser_impl->is_views_hosted()) {
+ return browser_impl->GetBrowserView();
+ }
+ return nullptr;
+}
+
+// static
+CefRefPtr<CefBrowserViewImpl> CefBrowserViewImpl::Create(
+ const CefWindowInfo& window_info,
+ CefRefPtr<CefClient> client,
+ const CefString& url,
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefDictionaryValue> extra_info,
+ CefRefPtr<CefRequestContext> request_context,
+ CefRefPtr<CefBrowserViewDelegate> delegate) {
+ CEF_REQUIRE_UIT_RETURN(nullptr);
+
+ if (!request_context) {
+ request_context = CefRequestContext::GetGlobalContext();
+ }
+
+ // Verify that the browser context is valid. Do this here instead of risking
+ // potential browser creation failure when this view is added to the window.
+ auto request_context_impl =
+ static_cast<CefRequestContextImpl*>(request_context.get());
+ if (!request_context_impl->VerifyBrowserContext()) {
+ return nullptr;
+ }
+
+ CefRefPtr<CefBrowserViewImpl> browser_view = new CefBrowserViewImpl(delegate);
+ browser_view->SetPendingBrowserCreateParams(
+ window_info, client, url, settings, extra_info, request_context);
+ browser_view->Initialize();
+ browser_view->SetDefaults(settings);
+ return browser_view;
+}
+
+// static
+CefRefPtr<CefBrowserViewImpl> CefBrowserViewImpl::CreateForPopup(
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefBrowserViewDelegate> delegate) {
+ CEF_REQUIRE_UIT_RETURN(nullptr);
+
+ CefRefPtr<CefBrowserViewImpl> browser_view = new CefBrowserViewImpl(delegate);
+ browser_view->Initialize();
+ browser_view->SetDefaults(settings);
+ return browser_view;
+}
+
+void CefBrowserViewImpl::WebContentsCreated(
+ content::WebContents* web_contents) {
+ if (web_view()) {
+ web_view()->SetWebContents(web_contents);
+ }
+}
+
+void CefBrowserViewImpl::BrowserCreated(
+ CefBrowserHostBase* browser,
+ base::RepeatingClosure on_bounds_changed) {
+ browser_ = browser;
+ on_bounds_changed_ = on_bounds_changed;
+}
+
+void CefBrowserViewImpl::BrowserDestroyed(CefBrowserHostBase* browser) {
+ DCHECK_EQ(browser, browser_);
+ browser_ = nullptr;
+
+ if (web_view()) {
+ web_view()->SetWebContents(nullptr);
+ }
+}
+
+bool CefBrowserViewImpl::HandleKeyboardEvent(
+ const content::NativeWebKeyboardEvent& event) {
+ if (!root_view()) {
+ return false;
+ }
+
+ views::FocusManager* focus_manager = root_view()->GetFocusManager();
+ if (!focus_manager) {
+ return false;
+ }
+
+ if (HandleAccelerator(event, focus_manager)) {
+ return true;
+ }
+
+ // Give the CefWindowDelegate a chance to handle the event.
+ CefRefPtr<CefWindow> window =
+ view_util::GetWindowFor(root_view()->GetWidget());
+ CefWindowImpl* window_impl = static_cast<CefWindowImpl*>(window.get());
+ if (window_impl) {
+ CefKeyEvent cef_event;
+ if (browser_util::GetCefKeyEvent(event, cef_event) &&
+ window_impl->OnKeyEvent(cef_event)) {
+ return true;
+ }
+ }
+
+ // Proceed with default native handling.
+ return unhandled_keyboard_event_handler_.HandleKeyboardEvent(event,
+ focus_manager);
+}
+
+CefRefPtr<CefBrowser> CefBrowserViewImpl::GetBrowser() {
+ CEF_REQUIRE_VALID_RETURN(nullptr);
+ return browser_;
+}
+
+CefRefPtr<CefView> CefBrowserViewImpl::GetChromeToolbar() {
+ CEF_REQUIRE_VALID_RETURN(nullptr);
+ if (cef::IsChromeRuntimeEnabled()) {
+ return static_cast<ChromeBrowserView*>(root_view())->cef_toolbar();
+ }
+
+ return nullptr;
+}
+
+void CefBrowserViewImpl::SetPreferAccelerators(bool prefer_accelerators) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ if (web_view()) {
+ web_view()->set_allow_accelerators(prefer_accelerators);
+ }
+}
+
+void CefBrowserViewImpl::RequestFocus() {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ // Always execute asynchronously to work around issue #3040.
+ CEF_POST_TASK(CEF_UIT,
+ base::BindOnce(&CefBrowserViewImpl::RequestFocusInternal,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void CefBrowserViewImpl::SetBackgroundColor(cef_color_t color) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ ParentClass::SetBackgroundColor(color);
+ if (web_view()) {
+ web_view()->SetResizeBackgroundColor(color);
+ }
+}
+
+void CefBrowserViewImpl::Detach() {
+ ParentClass::Detach();
+
+ // root_view() will be nullptr now.
+ DCHECK(!root_view());
+
+ if (browser_) {
+ // With the Alloy runtime |browser_| will disappear when WindowDestroyed()
+ // indirectly calls BrowserDestroyed() so keep a reference.
+ CefRefPtr<CefBrowserHostBase> browser = browser_;
+
+ // Force the browser to be destroyed.
+ browser->WindowDestroyed();
+ }
+}
+
+void CefBrowserViewImpl::GetDebugInfo(base::Value::Dict* info,
+ bool include_children) {
+ ParentClass::GetDebugInfo(info, include_children);
+ if (browser_) {
+ info->Set("url", browser_->GetMainFrame()->GetURL().ToString());
+ }
+}
+
+void CefBrowserViewImpl::OnBrowserViewAdded() {
+ if (!browser_ && pending_browser_create_params_) {
+ // Top-level browsers will be created when this view is added to the views
+ // hierarchy.
+ pending_browser_create_params_->browser_view = this;
+
+ CefBrowserHostBase::Create(*pending_browser_create_params_);
+ DCHECK(browser_);
+
+ pending_browser_create_params_.reset(nullptr);
+ }
+}
+
+void CefBrowserViewImpl::OnBoundsChanged() {
+ if (!on_bounds_changed_.is_null()) {
+ on_bounds_changed_.Run();
+ }
+}
+
+CefBrowserViewImpl::CefBrowserViewImpl(
+ CefRefPtr<CefBrowserViewDelegate> delegate)
+ : ParentClass(delegate), weak_ptr_factory_(this) {}
+
+void CefBrowserViewImpl::SetPendingBrowserCreateParams(
+ const CefWindowInfo& window_info,
+ CefRefPtr<CefClient> client,
+ const CefString& url,
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefDictionaryValue> extra_info,
+ CefRefPtr<CefRequestContext> request_context) {
+ DCHECK(!pending_browser_create_params_);
+ pending_browser_create_params_.reset(new CefBrowserCreateParams());
+ pending_browser_create_params_->MaybeSetWindowInfo(window_info);
+ pending_browser_create_params_->client = client;
+ pending_browser_create_params_->url = url;
+ pending_browser_create_params_->settings = settings;
+ pending_browser_create_params_->extra_info = extra_info;
+ pending_browser_create_params_->request_context = request_context;
+}
+
+void CefBrowserViewImpl::SetDefaults(const CefBrowserSettings& settings) {
+ SetBackgroundColor(
+ CefContext::Get()->GetBackgroundColor(&settings, STATE_DISABLED));
+}
+
+views::View* CefBrowserViewImpl::CreateRootView() {
+ if (cef::IsChromeRuntimeEnabled()) {
+ return new ChromeBrowserView(delegate(), this);
+ }
+
+ return new CefBrowserViewView(delegate(), this);
+}
+
+void CefBrowserViewImpl::InitializeRootView() {
+ if (cef::IsChromeRuntimeEnabled()) {
+ static_cast<ChromeBrowserView*>(root_view())->Initialize();
+ } else {
+ static_cast<CefBrowserViewView*>(root_view())->Initialize();
+ }
+}
+
+views::WebView* CefBrowserViewImpl::web_view() const {
+ if (!root_view()) {
+ return nullptr;
+ }
+
+ if (cef::IsChromeRuntimeEnabled()) {
+ return static_cast<ChromeBrowserView*>(root_view())->contents_web_view();
+ }
+
+ return static_cast<CefBrowserViewView*>(root_view());
+}
+
+bool CefBrowserViewImpl::HandleAccelerator(
+ const content::NativeWebKeyboardEvent& event,
+ views::FocusManager* focus_manager) {
+ // Previous calls to TranslateMessage can generate Char events as well as
+ // RawKeyDown events, even if the latter triggered an accelerator. In these
+ // cases, we discard the Char events.
+ if (event.GetType() == blink::WebInputEvent::Type::kChar &&
+ ignore_next_char_event_) {
+ ignore_next_char_event_ = false;
+ return true;
+ }
+
+ // It's necessary to reset this flag, because a RawKeyDown event may not
+ // always generate a Char event.
+ ignore_next_char_event_ = false;
+
+ if (event.GetType() == blink::WebInputEvent::Type::kRawKeyDown) {
+ ui::Accelerator accelerator =
+ ui::GetAcceleratorFromNativeWebKeyboardEvent(event);
+
+ // This is tricky: we want to set ignore_next_char_event_ if
+ // ProcessAccelerator returns true. But ProcessAccelerator might delete
+ // |this| if the accelerator is a "close tab" one. So we speculatively
+ // set the flag and fix it if no event was handled.
+ ignore_next_char_event_ = true;
+
+ if (focus_manager->ProcessAccelerator(accelerator)) {
+ return true;
+ }
+
+ // ProcessAccelerator didn't handle the accelerator, so we know both
+ // that |this| is still valid, and that we didn't want to set the flag.
+ ignore_next_char_event_ = false;
+ }
+
+ return false;
+}
+
+void CefBrowserViewImpl::RequestFocusInternal() {
+ ParentClass::RequestFocus();
+}
diff --git a/libcef/browser/views/browser_view_impl.h b/libcef/browser/views/browser_view_impl.h
new file mode 100644
index 00000000..90033d58
--- /dev/null
+++ b/libcef/browser/views/browser_view_impl.h
@@ -0,0 +1,123 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_VIEWS_BROWSER_VIEW_IMPL_H_
+#define CEF_LIBCEF_BROWSER_VIEWS_BROWSER_VIEW_IMPL_H_
+#pragma once
+
+#include "include/cef_client.h"
+#include "include/views/cef_browser_view.h"
+#include "include/views/cef_browser_view_delegate.h"
+#include "libcef/browser/browser_host_base.h"
+#include "libcef/browser/views/browser_view_view.h"
+#include "libcef/browser/views/view_impl.h"
+
+#include "base/functional/callback_forward.h"
+#include "base/memory/weak_ptr.h"
+#include "ui/views/controls/webview/unhandled_keyboard_event_handler.h"
+
+class CefBrowserHostBase;
+
+class CefBrowserViewImpl
+ : public CefViewImpl<views::View, CefBrowserView, CefBrowserViewDelegate>,
+ public CefBrowserViewView::Delegate {
+ public:
+ using ParentClass =
+ CefViewImpl<views::View, CefBrowserView, CefBrowserViewDelegate>;
+
+ CefBrowserViewImpl(const CefBrowserViewImpl&) = delete;
+ CefBrowserViewImpl& operator=(const CefBrowserViewImpl&) = delete;
+
+ // Create a new CefBrowserView instance. |delegate| may be nullptr.
+ // |window_info| will only be used when creating a Chrome child window.
+ static CefRefPtr<CefBrowserViewImpl> Create(
+ const CefWindowInfo& window_info,
+ CefRefPtr<CefClient> client,
+ const CefString& url,
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefDictionaryValue> extra_info,
+ CefRefPtr<CefRequestContext> request_context,
+ CefRefPtr<CefBrowserViewDelegate> delegate);
+
+ // Create a new CefBrowserView instance for a popup. |delegate| may be
+ // nullptr.
+ static CefRefPtr<CefBrowserViewImpl> CreateForPopup(
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefBrowserViewDelegate> delegate);
+
+ // Called from CefBrowserPlatformDelegateViews.
+ void WebContentsCreated(content::WebContents* web_contents);
+ void BrowserCreated(CefBrowserHostBase* browser,
+ base::RepeatingClosure on_bounds_changed);
+ void BrowserDestroyed(CefBrowserHostBase* browser);
+
+ // Called to handle accelerators when the event is unhandled by the web
+ // content and the browser client.
+ bool HandleKeyboardEvent(const content::NativeWebKeyboardEvent& event);
+
+ // CefBrowserView methods:
+ CefRefPtr<CefBrowser> GetBrowser() override;
+ CefRefPtr<CefView> GetChromeToolbar() override;
+ void SetPreferAccelerators(bool prefer_accelerators) override;
+
+ // CefView methods:
+ CefRefPtr<CefBrowserView> AsBrowserView() override { return this; }
+ void RequestFocus() override;
+ void SetBackgroundColor(cef_color_t color) override;
+
+ // CefViewAdapter methods:
+ void Detach() override;
+ std::string GetDebugType() override { return "BrowserView"; }
+ void GetDebugInfo(base::Value::Dict* info, bool include_children) override;
+
+ // CefBrowserViewView::Delegate methods:
+ void OnBrowserViewAdded() override;
+ void OnBoundsChanged() override;
+
+ // Return the WebView representation of this object.
+ views::WebView* web_view() const;
+
+ private:
+ // Create a new implementation object.
+ // Always call Initialize() after creation.
+ // |delegate| may be nullptr.
+ explicit CefBrowserViewImpl(CefRefPtr<CefBrowserViewDelegate> delegate);
+
+ void SetPendingBrowserCreateParams(
+ const CefWindowInfo& window_info,
+ CefRefPtr<CefClient> client,
+ const CefString& url,
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefDictionaryValue> extra_info,
+ CefRefPtr<CefRequestContext> request_context);
+
+ void SetDefaults(const CefBrowserSettings& settings);
+
+ // CefViewImpl methods:
+ views::View* CreateRootView() override;
+ void InitializeRootView() override;
+
+ // Logic extracted from UnhandledKeyboardEventHandler::HandleKeyboardEvent for
+ // the handling of accelerators. Returns true if the event was handled by the
+ // accelerator.
+ bool HandleAccelerator(const content::NativeWebKeyboardEvent& event,
+ views::FocusManager* focus_manager);
+
+ void RequestFocusInternal();
+
+ std::unique_ptr<CefBrowserCreateParams> pending_browser_create_params_;
+
+ CefRefPtr<CefBrowserHostBase> browser_;
+
+ views::UnhandledKeyboardEventHandler unhandled_keyboard_event_handler_;
+ bool ignore_next_char_event_ = false;
+
+ base::RepeatingClosure on_bounds_changed_;
+
+ base::WeakPtrFactory<CefBrowserViewImpl> weak_ptr_factory_;
+
+ IMPLEMENT_REFCOUNTING_DELETE_ON_UIT(CefBrowserViewImpl);
+};
+
+#endif // CEF_LIBCEF_BROWSER_VIEWS_BROWSER_VIEW_IMPL_H_
diff --git a/libcef/browser/views/browser_view_view.cc b/libcef/browser/views/browser_view_view.cc
new file mode 100644
index 00000000..70ee7720
--- /dev/null
+++ b/libcef/browser/views/browser_view_view.cc
@@ -0,0 +1,40 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#include "libcef/browser/views/browser_view_view.h"
+
+#include "libcef/browser/views/browser_view_impl.h"
+
+CefBrowserViewView::CefBrowserViewView(CefBrowserViewDelegate* cef_delegate,
+ Delegate* browser_view_delegate)
+ : ParentClass(cef_delegate), browser_view_delegate_(browser_view_delegate) {
+ DCHECK(browser_view_delegate_);
+}
+
+void CefBrowserViewView::ViewHierarchyChanged(
+ const views::ViewHierarchyChangedDetails& details) {
+ ParentClass::ViewHierarchyChanged(details);
+ if (details.is_add && details.child == this) {
+ gfx::Size size = GetPreferredSize();
+ if (size.IsEmpty()) {
+ // No size was provided for this View. Size it to the parent by default
+ // or, depending on the Layout, the browser may be initially 0x0 size and
+ // will not display until the parent is next resized (resulting in a call
+ // to WebView::OnBoundsChanged). For example, this can happen when adding
+ // this View to a CefWindow with FillLayout and then calling
+ // CefWindow::Show() without first resizing the CefWindow.
+ size = details.parent->GetPreferredSize();
+ if (!size.IsEmpty()) {
+ SetSize(size);
+ }
+ }
+
+ browser_view_delegate_->OnBrowserViewAdded();
+ }
+}
+
+void CefBrowserViewView::OnBoundsChanged(const gfx::Rect& previous_bounds) {
+ ParentClass::OnBoundsChanged(previous_bounds);
+ browser_view_delegate_->OnBoundsChanged();
+}
diff --git a/libcef/browser/views/browser_view_view.h b/libcef/browser/views/browser_view_view.h
new file mode 100644
index 00000000..bd47b9e0
--- /dev/null
+++ b/libcef/browser/views/browser_view_view.h
@@ -0,0 +1,63 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_VIEWS_BROWSER_VIEW_VIEW_H_
+#define CEF_LIBCEF_BROWSER_VIEWS_BROWSER_VIEW_VIEW_H_
+#pragma once
+
+#include "include/views/cef_browser_view_delegate.h"
+
+#include "libcef/browser/views/view_view.h"
+
+#include "ui/views/controls/webview/webview.h"
+
+// Extend views::WebView with a no-argument constructor as required by the
+// CefViewView template.
+class WebViewEx : public views::WebView {
+ public:
+ WebViewEx() : views::WebView(nullptr) {
+ // Mouse events on draggable regions will not be handled by the WebView.
+ // Avoid the resulting DCHECK in NativeViewHost::OnMousePressed by
+ // configuring the NativeViewHost not to process events via the view
+ // hierarchy.
+ holder()->SetCanProcessEventsWithinSubtree(false);
+ }
+};
+
+class CefBrowserViewView
+ : public CefViewView<WebViewEx, CefBrowserViewDelegate> {
+ public:
+ using ParentClass = CefViewView<WebViewEx, CefBrowserViewDelegate>;
+
+ CefBrowserViewView(const CefBrowserViewView&) = delete;
+ CefBrowserViewView& operator=(const CefBrowserViewView&) = delete;
+
+ class Delegate {
+ public:
+ // Called when the BrowserView has been added to a parent view.
+ virtual void OnBrowserViewAdded() = 0;
+
+ // Called when the BrowserView bounds have changed.
+ virtual void OnBoundsChanged() = 0;
+
+ protected:
+ virtual ~Delegate() {}
+ };
+
+ // |cef_delegate| may be nullptr.
+ // |browser_view_delegate| must be non-nullptr.
+ CefBrowserViewView(CefBrowserViewDelegate* cef_delegate,
+ Delegate* browser_view_delegate);
+
+ // View methods:
+ void ViewHierarchyChanged(
+ const views::ViewHierarchyChangedDetails& details) override;
+ void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
+
+ private:
+ // Not owned by this object.
+ Delegate* browser_view_delegate_;
+};
+
+#endif // CEF_LIBCEF_BROWSER_VIEWS_BROWSER_VIEW_VIEW_H_
diff --git a/libcef/browser/views/button_impl.h b/libcef/browser/views/button_impl.h
new file mode 100644
index 00000000..247b11be
--- /dev/null
+++ b/libcef/browser/views/button_impl.h
@@ -0,0 +1,110 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_VIEWS_BUTTON_IMPL_H_
+#define CEF_LIBCEF_BROWSER_VIEWS_BUTTON_IMPL_H_
+#pragma once
+
+#include "include/views/cef_button.h"
+#include "include/views/cef_label_button.h"
+
+#include "libcef/browser/views/view_impl.h"
+
+#include "base/logging.h"
+#include "ui/gfx/color_utils.h"
+#include "ui/views/animation/ink_drop.h"
+#include "ui/views/controls/button/button.h"
+
+// Helpers for template boiler-plate.
+#define CEF_BUTTON_IMPL_T CEF_VIEW_IMPL_T
+#define CEF_BUTTON_IMPL_A CEF_VIEW_IMPL_A
+#define CEF_BUTTON_IMPL_D CefButtonImpl<CEF_BUTTON_IMPL_A>
+
+// Template for implementing CefButton-derived classes. See comments in
+// view_impl.h for a usage overview.
+CEF_BUTTON_IMPL_T class CefButtonImpl : public CEF_VIEW_IMPL_D {
+ public:
+ using ParentClass = CEF_VIEW_IMPL_D;
+
+ // CefButton methods. When adding new As*() methods make sure to update
+ // CefViewAdapter::GetFor() in view_adapter.cc.
+ CefRefPtr<CefLabelButton> AsLabelButton() override { return nullptr; }
+ void SetState(cef_button_state_t state) override;
+ cef_button_state_t GetState() override;
+ void SetInkDropEnabled(bool enabled) override;
+ void SetTooltipText(const CefString& tooltip_text) override;
+ void SetAccessibleName(const CefString& name) override;
+
+ // CefView methods:
+ CefRefPtr<CefButton> AsButton() override { return this; }
+ void SetFocusable(bool focusable) override;
+
+ protected:
+ // Create a new implementation object.
+ // Always call Initialize() after creation.
+ // |delegate| may be nullptr.
+ explicit CefButtonImpl(CefRefPtr<CefViewDelegateClass> delegate)
+ : ParentClass(delegate) {}
+};
+
+CEF_BUTTON_IMPL_T void CEF_BUTTON_IMPL_D::SetState(cef_button_state_t state) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ views::Button::ButtonState old_state = ParentClass::root_view()->GetState();
+ views::Button::ButtonState new_state =
+ static_cast<views::Button::ButtonState>(state);
+
+ if (views::InkDrop::Get(ParentClass::root_view())->ink_drop_mode() !=
+ views::InkDropHost::InkDropMode::OFF &&
+ !ParentClass::root_view()->IsFocusable()) {
+ // Ink drop state does not get set properly on state change when the button
+ // is non-focusable.
+ views::InkDropState ink_state = views::InkDropState::HIDDEN;
+ if (new_state == views::Button::STATE_PRESSED) {
+ ink_state = views::InkDropState::ACTIVATED;
+ } else if (old_state == views::Button::STATE_PRESSED) {
+ ink_state = views::InkDropState::DEACTIVATED;
+ }
+ views::InkDrop::Get(ParentClass::root_view())
+ ->AnimateToState(ink_state, nullptr);
+ }
+
+ ParentClass::root_view()->SetState(new_state);
+}
+
+CEF_BUTTON_IMPL_T cef_button_state_t CEF_BUTTON_IMPL_D::GetState() {
+ CEF_REQUIRE_VALID_RETURN(CEF_BUTTON_STATE_NORMAL);
+ return static_cast<cef_button_state_t>(ParentClass::root_view()->GetState());
+}
+
+CEF_BUTTON_IMPL_T void CEF_BUTTON_IMPL_D::SetInkDropEnabled(bool enabled) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ views::InkDrop::Get(ParentClass::root_view())
+ ->SetMode(enabled ? views::InkDropHost::InkDropMode::ON
+ : views::InkDropHost::InkDropMode::OFF);
+ if (enabled) {
+ views::InkDrop::Get(ParentClass::root_view())
+ ->SetBaseColor(color_utils::BlendTowardMaxContrast(
+ ParentClass::root_view()->background()->get_color(), 0x61));
+ }
+}
+
+CEF_BUTTON_IMPL_T void CEF_BUTTON_IMPL_D::SetTooltipText(
+ const CefString& tooltip_text) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ ParentClass::root_view()->SetTooltipText(tooltip_text);
+}
+
+CEF_BUTTON_IMPL_T void CEF_BUTTON_IMPL_D::SetAccessibleName(
+ const CefString& name) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ ParentClass::root_view()->SetAccessibleName(name);
+}
+
+CEF_BUTTON_IMPL_T void CEF_BUTTON_IMPL_D::SetFocusable(bool focusable) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ ParentClass::root_view()->SetRequestFocusOnPress(focusable);
+ ParentClass::SetFocusable(focusable);
+}
+
+#endif // CEF_LIBCEF_BROWSER_VIEWS_BUTTON_IMPL_H_
diff --git a/libcef/browser/views/button_view.h b/libcef/browser/views/button_view.h
new file mode 100644
index 00000000..04441ccb
--- /dev/null
+++ b/libcef/browser/views/button_view.h
@@ -0,0 +1,78 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_VIEWS_BUTTON_VIEW_H_
+#define CEF_LIBCEF_BROWSER_VIEWS_BUTTON_VIEW_H_
+#pragma once
+
+#include "include/views/cef_button_delegate.h"
+
+#include "libcef/browser/thread_util.h"
+#include "libcef/browser/views/view_view.h"
+
+#include "base/logging.h"
+#include "ui/views/animation/ink_drop.h"
+#include "ui/views/controls/button/button.h"
+
+// Helpers for template boiler-plate.
+#define CEF_BUTTON_VIEW_T CEF_VIEW_VIEW_T
+#define CEF_BUTTON_VIEW_A CEF_VIEW_VIEW_A
+#define CEF_BUTTON_VIEW_D CefButtonView<CEF_BUTTON_VIEW_A>
+
+// Template for implementing views::Button-derived classes. The
+// views::Button-derived type passed to this template must extend
+// views::ButtonListener (for example, see LabelButtonEx from
+// basic_label_button_view.h). See comments in view_impl.h for a usage overview.
+CEF_BUTTON_VIEW_T class CefButtonView : public CEF_VIEW_VIEW_D {
+ public:
+ using ParentClass = CEF_VIEW_VIEW_D;
+
+ // |cef_delegate| may be nullptr.
+ template <typename... Args>
+ explicit CefButtonView(CefViewDelegateClass* cef_delegate, Args... args)
+ : ParentClass(cef_delegate, args...) {}
+
+ // Returns the CefButton associated with this view. See comments on
+ // CefViewView::GetCefView.
+ CefRefPtr<CefButton> GetCefButton() const {
+ CefRefPtr<CefButton> button = ParentClass::GetCefView()->AsButton();
+ DCHECK(button);
+ return button;
+ }
+
+ // views::Button methods:
+ void StateChanged(views::Button::ButtonState old_state) override;
+
+ // LabelButtonEx methods:
+ void ButtonPressed(const ui::Event& event) override;
+};
+
+CEF_BUTTON_VIEW_T void CEF_BUTTON_VIEW_D::StateChanged(
+ views::Button::ButtonState old_state) {
+ ParentClass::StateChanged(old_state);
+ if (ParentClass::cef_delegate()) {
+ ParentClass::cef_delegate()->OnButtonStateChanged(GetCefButton());
+ }
+}
+
+CEF_BUTTON_VIEW_T void CEF_BUTTON_VIEW_D::ButtonPressed(
+ const ui::Event& event) {
+ // Callback may trigger new animation state.
+ if (ParentClass::cef_delegate()) {
+ ParentClass::cef_delegate()->OnButtonPressed(GetCefButton());
+ }
+ if (views::InkDrop::Get(this)->ink_drop_mode() !=
+ views::InkDropHost::InkDropMode::OFF &&
+ !ParentClass::IsFocusable() &&
+ ParentClass::GetState() != views::Button::STATE_PRESSED) {
+ // Ink drop state does not get reset properly on click when the button is
+ // non-focusable. Reset the ink drop state here if the state has not been
+ // explicitly set to pressed by the OnButtonPressed callback calling
+ // SetState (which also sets the ink drop state).
+ views::InkDrop::Get(this)->AnimateToState(
+ views::InkDropState::HIDDEN, ui::LocatedEvent::FromIfValid(&event));
+ }
+}
+
+#endif // CEF_LIBCEF_BROWSER_VIEWS_BUTTON_VIEW_H_
diff --git a/libcef/browser/views/display_impl.cc b/libcef/browser/views/display_impl.cc
new file mode 100644
index 00000000..6c95c786
--- /dev/null
+++ b/libcef/browser/views/display_impl.cc
@@ -0,0 +1,155 @@
+// Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "libcef/browser/views/display_impl.h"
+
+#include "libcef/browser/views/view_util.h"
+
+#include "ui/display/screen.h"
+
+// static
+CefRefPtr<CefDisplay> CefDisplay::GetPrimaryDisplay() {
+ CEF_REQUIRE_UIT_RETURN(nullptr);
+ return new CefDisplayImpl(display::Screen::GetScreen()->GetPrimaryDisplay());
+}
+
+// static
+CefRefPtr<CefDisplay> CefDisplay::GetDisplayNearestPoint(
+ const CefPoint& point,
+ bool input_pixel_coords) {
+ CEF_REQUIRE_UIT_RETURN(nullptr);
+ return new CefDisplayImpl(view_util::GetDisplayNearestPoint(
+ gfx::Point(point.x, point.y), input_pixel_coords));
+}
+
+// static
+CefRefPtr<CefDisplay> CefDisplay::GetDisplayMatchingBounds(
+ const CefRect& bounds,
+ bool input_pixel_coords) {
+ CEF_REQUIRE_UIT_RETURN(nullptr);
+ return new CefDisplayImpl(view_util::GetDisplayMatchingBounds(
+ gfx::Rect(bounds.x, bounds.y, bounds.width, bounds.height),
+ input_pixel_coords));
+}
+
+// static
+size_t CefDisplay::GetDisplayCount() {
+ CEF_REQUIRE_UIT_RETURN(0U);
+ return static_cast<size_t>(display::Screen::GetScreen()->GetNumDisplays());
+}
+
+// static
+void CefDisplay::GetAllDisplays(std::vector<CefRefPtr<CefDisplay>>& displays) {
+ CEF_REQUIRE_UIT_RETURN_VOID();
+
+ displays.clear();
+
+ using DisplayVector = std::vector<display::Display>;
+ DisplayVector vec = display::Screen::GetScreen()->GetAllDisplays();
+ for (size_t i = 0; i < vec.size(); ++i) {
+ displays.push_back(new CefDisplayImpl(vec[i]));
+ }
+}
+
+// static
+CefPoint CefDisplay::ConvertScreenPointToPixels(const CefPoint& point) {
+ CEF_REQUIRE_UIT_RETURN(CefPoint());
+#if BUILDFLAG(IS_WIN)
+ const gfx::Point pix_point =
+ view_util::ConvertPointToPixels(gfx::Point(point.x, point.y));
+ return CefPoint(pix_point.x(), pix_point.y());
+#else
+ return point;
+#endif
+}
+
+// static
+CefPoint CefDisplay::ConvertScreenPointFromPixels(const CefPoint& point) {
+ CEF_REQUIRE_UIT_RETURN(CefPoint());
+#if BUILDFLAG(IS_WIN)
+ const gfx::Point dip_point =
+ view_util::ConvertPointFromPixels(gfx::Point(point.x, point.y));
+ return CefPoint(dip_point.x(), dip_point.y());
+#else
+ return point;
+#endif
+}
+
+// static
+CefRect CefDisplay::ConvertScreenRectToPixels(const CefRect& rect) {
+ CEF_REQUIRE_UIT_RETURN(CefRect());
+#if BUILDFLAG(IS_WIN)
+ const gfx::Rect pix_rect = view_util::ConvertRectToPixels(
+ gfx::Rect(rect.x, rect.y, rect.width, rect.height));
+ return CefRect(pix_rect.x(), pix_rect.y(), pix_rect.width(),
+ pix_rect.height());
+#else
+ return rect;
+#endif
+}
+
+// static
+CefRect CefDisplay::ConvertScreenRectFromPixels(const CefRect& rect) {
+ CEF_REQUIRE_UIT_RETURN(CefRect());
+#if BUILDFLAG(IS_WIN)
+ const gfx::Rect dip_rect = view_util::ConvertRectFromPixels(
+ gfx::Rect(rect.x, rect.y, rect.width, rect.height));
+ return CefRect(dip_rect.x(), dip_rect.y(), dip_rect.width(),
+ dip_rect.height());
+#else
+ return rect;
+#endif
+}
+
+CefDisplayImpl::CefDisplayImpl(const display::Display& display)
+ : display_(display) {
+ CEF_REQUIRE_UIT();
+}
+
+CefDisplayImpl::~CefDisplayImpl() {
+ CEF_REQUIRE_UIT();
+}
+
+int64 CefDisplayImpl::GetID() {
+ CEF_REQUIRE_UIT_RETURN(-1);
+ return display_.id();
+}
+
+float CefDisplayImpl::GetDeviceScaleFactor() {
+ CEF_REQUIRE_UIT_RETURN(0.0f);
+ return display_.device_scale_factor();
+}
+
+void CefDisplayImpl::ConvertPointToPixels(CefPoint& point) {
+ CEF_REQUIRE_UIT_RETURN_VOID();
+ gfx::Point gfx_point(point.x, point.y);
+ view_util::ConvertPointToPixels(&gfx_point, display_.device_scale_factor());
+ point = CefPoint(gfx_point.x(), gfx_point.y());
+}
+
+void CefDisplayImpl::ConvertPointFromPixels(CefPoint& point) {
+ CEF_REQUIRE_UIT_RETURN_VOID();
+ gfx::Point gfx_point(point.x, point.y);
+ view_util::ConvertPointFromPixels(&gfx_point, display_.device_scale_factor());
+ point = CefPoint(gfx_point.x(), gfx_point.y());
+}
+
+CefRect CefDisplayImpl::GetBounds() {
+ CEF_REQUIRE_UIT_RETURN(CefRect());
+ const gfx::Rect& gfx_rect = display_.bounds();
+ return CefRect(gfx_rect.x(), gfx_rect.y(), gfx_rect.width(),
+ gfx_rect.height());
+}
+
+CefRect CefDisplayImpl::GetWorkArea() {
+ CEF_REQUIRE_UIT_RETURN(CefRect());
+ const gfx::Rect& gfx_rect = display_.work_area();
+ return CefRect(gfx_rect.x(), gfx_rect.y(), gfx_rect.width(),
+ gfx_rect.height());
+}
+
+int CefDisplayImpl::GetRotation() {
+ CEF_REQUIRE_UIT_RETURN(0);
+ return display_.RotationAsDegree();
+}
diff --git a/libcef/browser/views/display_impl.h b/libcef/browser/views/display_impl.h
new file mode 100644
index 00000000..41fce2c0
--- /dev/null
+++ b/libcef/browser/views/display_impl.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_VIEWS_DISPLAY_IMPL_H_
+#define CEF_LIBCEF_BROWSER_VIEWS_DISPLAY_IMPL_H_
+#pragma once
+
+#include "include/views/cef_display.h"
+#include "libcef/browser/thread_util.h"
+
+#include "ui/display/display.h"
+
+class CefDisplayImpl : public CefDisplay {
+ public:
+ explicit CefDisplayImpl(const display::Display& display);
+
+ CefDisplayImpl(const CefDisplayImpl&) = delete;
+ CefDisplayImpl& operator=(const CefDisplayImpl&) = delete;
+
+ ~CefDisplayImpl() override;
+
+ // CefDisplay methods:
+ int64 GetID() override;
+ float GetDeviceScaleFactor() override;
+ void ConvertPointToPixels(CefPoint& point) override;
+ void ConvertPointFromPixels(CefPoint& point) override;
+ CefRect GetBounds() override;
+ CefRect GetWorkArea() override;
+ int GetRotation() override;
+
+ const display::Display& display() const { return display_; }
+
+ private:
+ display::Display display_;
+
+ IMPLEMENT_REFCOUNTING_DELETE_ON_UIT(CefDisplayImpl);
+};
+
+#endif // CEF_LIBCEF_BROWSER_VIEWS_DISPLAY_IMPL_H_
diff --git a/libcef/browser/views/fill_layout_impl.cc b/libcef/browser/views/fill_layout_impl.cc
new file mode 100644
index 00000000..fa7bdf93
--- /dev/null
+++ b/libcef/browser/views/fill_layout_impl.cc
@@ -0,0 +1,21 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#include "libcef/browser/views/fill_layout_impl.h"
+
+#include "libcef/browser/thread_util.h"
+
+// static
+CefRefPtr<CefFillLayout> CefFillLayoutImpl::Create(views::View* owner_view) {
+ CEF_REQUIRE_UIT_RETURN(nullptr);
+ CefRefPtr<CefFillLayoutImpl> impl = new CefFillLayoutImpl();
+ impl->Initialize(owner_view);
+ return impl;
+}
+
+CefFillLayoutImpl::CefFillLayoutImpl() {}
+
+views::FillLayout* CefFillLayoutImpl::CreateLayout() {
+ return new views::FillLayout();
+}
diff --git a/libcef/browser/views/fill_layout_impl.h b/libcef/browser/views/fill_layout_impl.h
new file mode 100644
index 00000000..f0757677
--- /dev/null
+++ b/libcef/browser/views/fill_layout_impl.h
@@ -0,0 +1,34 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_VIEWS_FILL_LAYOUT_IMPL_H_
+#define CEF_LIBCEF_BROWSER_VIEWS_FILL_LAYOUT_IMPL_H_
+#pragma once
+
+#include "include/views/cef_fill_layout.h"
+
+#include "libcef/browser/views/layout_impl.h"
+#include "ui/views/layout/fill_layout.h"
+
+class CefFillLayoutImpl
+ : public CefLayoutImpl<views::FillLayout, CefFillLayout> {
+ public:
+ CefFillLayoutImpl(const CefFillLayoutImpl&) = delete;
+ CefFillLayoutImpl& operator=(const CefFillLayoutImpl&) = delete;
+
+ // Create a new CefFillLayout insance. |owner_view| must be non-nullptr.
+ static CefRefPtr<CefFillLayout> Create(views::View* owner_view);
+
+ // CefLayout methods:
+ CefRefPtr<CefFillLayout> AsFillLayout() override { return this; }
+
+ private:
+ CefFillLayoutImpl();
+
+ views::FillLayout* CreateLayout() override;
+
+ IMPLEMENT_REFCOUNTING_DELETE_ON_UIT(CefFillLayoutImpl);
+};
+
+#endif // CEF_LIBCEF_BROWSER_VIEWS_FILL_LAYOUT_IMPL_H_
diff --git a/libcef/browser/views/label_button_impl.h b/libcef/browser/views/label_button_impl.h
new file mode 100644
index 00000000..40ca6244
--- /dev/null
+++ b/libcef/browser/views/label_button_impl.h
@@ -0,0 +1,137 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_VIEWS_LABEL_BUTTON_IMPL_H_
+#define CEF_LIBCEF_BROWSER_VIEWS_LABEL_BUTTON_IMPL_H_
+#pragma once
+
+#include "include/views/cef_button.h"
+#include "include/views/cef_label_button.h"
+#include "include/views/cef_menu_button.h"
+
+#include "libcef/browser/image_impl.h"
+#include "libcef/browser/views/button_impl.h"
+
+#include "base/logging.h"
+#include "ui/views/controls/button/label_button.h"
+
+// Helpers for template boiler-plate.
+#define CEF_LABEL_BUTTON_IMPL_T CEF_BUTTON_IMPL_T
+#define CEF_LABEL_BUTTON_IMPL_A CEF_BUTTON_IMPL_A
+#define CEF_LABEL_BUTTON_IMPL_D CefLabelButtonImpl<CEF_LABEL_BUTTON_IMPL_A>
+
+// Template for implementing CefLabelButton-derived classes. See comments in
+// view_impl.h for a usage overview.
+CEF_LABEL_BUTTON_IMPL_T class CefLabelButtonImpl : public CEF_BUTTON_IMPL_D {
+ public:
+ using ParentClass = CEF_BUTTON_IMPL_D;
+
+ // CefLabelButton methods. When adding new As*() methods make sure to update
+ // CefViewAdapter::GetFor() in view_adapter.cc.
+ void SetText(const CefString& text) override;
+ CefString GetText() override;
+ void SetImage(cef_button_state_t button_state,
+ CefRefPtr<CefImage> image) override;
+ CefRefPtr<CefImage> GetImage(cef_button_state_t button_state) override;
+ void SetTextColor(cef_button_state_t for_state, cef_color_t color) override;
+ void SetEnabledTextColors(cef_color_t color) override;
+ void SetFontList(const CefString& font_list) override;
+ void SetHorizontalAlignment(cef_horizontal_alignment_t alignment) override;
+ void SetMinimumSize(const CefSize& size) override;
+ void SetMaximumSize(const CefSize& size) override;
+
+ // CefLabelButton methods:
+ CefRefPtr<CefMenuButton> AsMenuButton() override { return nullptr; }
+
+ // CefButton methods:
+ CefRefPtr<CefLabelButton> AsLabelButton() override { return this; }
+
+ // CefViewAdapter methods:
+ void GetDebugInfo(base::Value::Dict* info, bool include_children) override {
+ ParentClass::GetDebugInfo(info, include_children);
+ info->Set("text", ParentClass::root_view()->GetText());
+ }
+
+ protected:
+ // Create a new implementation object.
+ // Always call Initialize() after creation.
+ // |delegate| may be nullptr.
+ explicit CefLabelButtonImpl(CefRefPtr<CefViewDelegateClass> delegate)
+ : ParentClass(delegate) {}
+};
+
+CEF_LABEL_BUTTON_IMPL_T void CEF_LABEL_BUTTON_IMPL_D::SetText(
+ const CefString& text) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ ParentClass::root_view()->SetText(text);
+}
+
+CEF_LABEL_BUTTON_IMPL_T CefString CEF_LABEL_BUTTON_IMPL_D::GetText() {
+ CEF_REQUIRE_VALID_RETURN(CefString());
+ return ParentClass::root_view()->GetText();
+}
+
+CEF_LABEL_BUTTON_IMPL_T void CEF_LABEL_BUTTON_IMPL_D::SetImage(
+ cef_button_state_t button_state,
+ CefRefPtr<CefImage> image) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ gfx::ImageSkia image_skia;
+ if (image) {
+ image_skia = static_cast<CefImageImpl*>(image.get())->AsImageSkia();
+ }
+ ParentClass::root_view()->SetImage(
+ static_cast<views::Button::ButtonState>(button_state), image_skia);
+}
+
+CEF_LABEL_BUTTON_IMPL_T CefRefPtr<CefImage> CEF_LABEL_BUTTON_IMPL_D::GetImage(
+ cef_button_state_t button_state) {
+ CEF_REQUIRE_VALID_RETURN(nullptr);
+ const gfx::ImageSkia& image_skia = ParentClass::root_view()->GetImage(
+ static_cast<views::Button::ButtonState>(button_state));
+ if (image_skia.isNull()) {
+ return nullptr;
+ }
+ return new CefImageImpl(image_skia);
+}
+
+CEF_LABEL_BUTTON_IMPL_T void CEF_LABEL_BUTTON_IMPL_D::SetTextColor(
+ cef_button_state_t for_state,
+ cef_color_t color) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ ParentClass::root_view()->SetTextColor(
+ static_cast<views::Button::ButtonState>(for_state), color);
+}
+
+CEF_LABEL_BUTTON_IMPL_T void CEF_LABEL_BUTTON_IMPL_D::SetEnabledTextColors(
+ cef_color_t color) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ ParentClass::root_view()->SetEnabledTextColors(color);
+}
+
+CEF_LABEL_BUTTON_IMPL_T void CEF_LABEL_BUTTON_IMPL_D::SetFontList(
+ const CefString& font_list) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ ParentClass::root_view()->SetFontList(gfx::FontList(font_list));
+}
+
+CEF_LABEL_BUTTON_IMPL_T void CEF_LABEL_BUTTON_IMPL_D::SetHorizontalAlignment(
+ cef_horizontal_alignment_t alignment) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ ParentClass::root_view()->SetHorizontalAlignment(
+ static_cast<gfx::HorizontalAlignment>(alignment));
+}
+
+CEF_LABEL_BUTTON_IMPL_T void CEF_LABEL_BUTTON_IMPL_D::SetMinimumSize(
+ const CefSize& size) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ ParentClass::root_view()->SetMinSize(gfx::Size(size.width, size.height));
+}
+
+CEF_LABEL_BUTTON_IMPL_T void CEF_LABEL_BUTTON_IMPL_D::SetMaximumSize(
+ const CefSize& size) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ ParentClass::root_view()->SetMaxSize(gfx::Size(size.width, size.height));
+}
+
+#endif // CEF_LIBCEF_BROWSER_VIEWS_LABEL_BUTTON_IMPL_H_
diff --git a/libcef/browser/views/label_button_view.h b/libcef/browser/views/label_button_view.h
new file mode 100644
index 00000000..a628dfd8
--- /dev/null
+++ b/libcef/browser/views/label_button_view.h
@@ -0,0 +1,52 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_VIEWS_LABEL_BUTTON_VIEW_H_
+#define CEF_LIBCEF_BROWSER_VIEWS_LABEL_BUTTON_VIEW_H_
+#pragma once
+
+#include "include/views/cef_label_button.h"
+#include "libcef/browser/views/button_view.h"
+
+#include "base/logging.h"
+#include "ui/gfx/font_list.h"
+
+// Helpers for template boiler-plate.
+#define CEF_LABEL_BUTTON_VIEW_T CEF_BUTTON_VIEW_T
+#define CEF_LABEL_BUTTON_VIEW_A CEF_BUTTON_VIEW_A
+#define CEF_LABEL_BUTTON_VIEW_D CefLabelButtonView<CEF_LABEL_BUTTON_VIEW_A>
+
+// Template for implementing views::View-derived classes that support adding and
+// removing children (called a Panel in CEF terminology). See comments in
+// view_impl.h for a usage overview.
+CEF_LABEL_BUTTON_VIEW_T class CefLabelButtonView : public CEF_BUTTON_VIEW_D {
+ public:
+ using ParentClass = CEF_BUTTON_VIEW_D;
+
+ // |cef_delegate| may be nullptr.
+ template <typename... Args>
+ explicit CefLabelButtonView(CefViewDelegateClass* cef_delegate, Args... args)
+ : ParentClass(cef_delegate, args...) {}
+
+ void Initialize() override {
+ ParentClass::Initialize();
+
+ // Use our defaults instead of the Views framework defaults.
+ ParentClass::SetFontList(gfx::FontList(view_util::kDefaultFontList));
+ }
+
+ // Returns the CefLabelButton associated with this view. See comments on
+ // CefViewView::GetCefView.
+ CefRefPtr<CefLabelButton> GetCefLabelButton() const {
+ CefRefPtr<CefLabelButton> label_button =
+ ParentClass::GetCefButton()->AsLabelButton();
+ DCHECK(label_button);
+ return label_button;
+ }
+
+ // CefViewView methods:
+ bool HasMinimumSize() const override { return true; }
+};
+
+#endif // CEF_LIBCEF_BROWSER_VIEWS_LABEL_BUTTON_VIEW_H_
diff --git a/libcef/browser/views/layout_adapter.cc b/libcef/browser/views/layout_adapter.cc
new file mode 100644
index 00000000..6d4cc6ab
--- /dev/null
+++ b/libcef/browser/views/layout_adapter.cc
@@ -0,0 +1,21 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#include "libcef/browser/views/layout_adapter.h"
+
+#include "libcef/browser/views/box_layout_impl.h"
+#include "libcef/browser/views/fill_layout_impl.h"
+
+// static
+CefLayoutAdapter* CefLayoutAdapter::GetFor(CefRefPtr<CefLayout> layout) {
+ CefLayoutAdapter* adapter = nullptr;
+ if (layout->AsBoxLayout()) {
+ adapter = static_cast<CefBoxLayoutImpl*>(layout->AsBoxLayout().get());
+ } else if (layout->AsFillLayout()) {
+ adapter = static_cast<CefFillLayoutImpl*>(layout->AsFillLayout().get());
+ }
+
+ DCHECK(adapter);
+ return adapter;
+}
diff --git a/libcef/browser/views/layout_adapter.h b/libcef/browser/views/layout_adapter.h
new file mode 100644
index 00000000..04a2d902
--- /dev/null
+++ b/libcef/browser/views/layout_adapter.h
@@ -0,0 +1,38 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_VIEWS_LAYOUT_ADAPTER_H_
+#define CEF_LIBCEF_BROWSER_VIEWS_LAYOUT_ADAPTER_H_
+#pragma once
+
+#include "include/views/cef_layout.h"
+
+namespace views {
+class LayoutManager;
+}
+
+// Exposes a common interface from all CefLayout implementation objects to
+// simplify the layout_util implementation. See comments in view_impl.h for a
+// usage overview.
+class CefLayoutAdapter {
+ public:
+ CefLayoutAdapter() {}
+
+ // Returns the CefLayoutAdapter for the specified |layout|.
+ static CefLayoutAdapter* GetFor(CefRefPtr<CefLayout> layout);
+
+ // Returns the underlying views::LayoutManager object. Does not transfer
+ // ownership.
+ virtual views::LayoutManager* Get() const = 0;
+
+ // Release all references to the views::LayoutManager object. This is called
+ // when the views::LayoutManager is deleted after being assigned to a
+ // views::View.
+ virtual void Detach() = 0;
+
+ protected:
+ virtual ~CefLayoutAdapter() {}
+};
+
+#endif // CEF_LIBCEF_BROWSER_VIEWS_LAYOUT_ADAPTER_H_
diff --git a/libcef/browser/views/layout_impl.h b/libcef/browser/views/layout_impl.h
new file mode 100644
index 00000000..9bfd8e9a
--- /dev/null
+++ b/libcef/browser/views/layout_impl.h
@@ -0,0 +1,77 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_VIEWS_LAYOUT_IMPL_H_
+#define CEF_LIBCEF_BROWSER_VIEWS_LAYOUT_IMPL_H_
+#pragma once
+
+#include "include/views/cef_box_layout.h"
+#include "include/views/cef_fill_layout.h"
+#include "include/views/cef_layout.h"
+
+#include "libcef/browser/thread_util.h"
+#include "libcef/browser/views/layout_adapter.h"
+#include "libcef/browser/views/layout_util.h"
+
+#include "base/logging.h"
+#include "ui/views/layout/layout_manager.h"
+#include "ui/views/view.h"
+
+// Base template for implementing CefLayout-derived classes. See comments in
+// view_impl.h for a usage overview.
+template <class ViewsLayoutClass, class CefLayoutClass>
+class CefLayoutImpl : public CefLayoutAdapter, public CefLayoutClass {
+ public:
+ // Returns the underlying views::LayoutManager object as the derived type.
+ // Does not transfer ownership.
+ ViewsLayoutClass* layout() const { return layout_ref_; }
+
+ // Returns the views::View that owns this object.
+ views::View* owner_view() const { return owner_view_; }
+
+ // CefLayoutAdapter methods:
+ views::LayoutManager* Get() const override { return layout(); }
+ void Detach() override {
+ owner_view_ = nullptr;
+ layout_ref_ = nullptr;
+ }
+
+ // CefLayout methods. When adding new As*() methods make sure to update
+ // CefLayoutAdapter::GetFor() in layout_adapter.cc.
+ CefRefPtr<CefBoxLayout> AsBoxLayout() override { return nullptr; }
+ CefRefPtr<CefFillLayout> AsFillLayout() override { return nullptr; }
+ bool IsValid() override {
+ CEF_REQUIRE_UIT_RETURN(false);
+ return !!layout_ref_;
+ }
+
+ protected:
+ // Create a new implementation object.
+ // Always call Initialize() after creation.
+ CefLayoutImpl() : layout_ref_(nullptr), owner_view_(nullptr) {}
+
+ // Initialize this object and assign ownership to |owner_view|.
+ void Initialize(views::View* owner_view) {
+ DCHECK(owner_view);
+ owner_view_ = owner_view;
+ layout_ref_ = CreateLayout();
+ DCHECK(layout_ref_);
+ owner_view->SetLayoutManager(base::WrapUnique(layout_ref_));
+ layout_util::Assign(this, owner_view);
+ }
+
+ // Create the views::LayoutManager object.
+ virtual ViewsLayoutClass* CreateLayout() = 0;
+
+ private:
+ // Unowned reference to the views::LayoutManager wrapped by this object. Will
+ // be nullptr after the views::LayoutManager is destroyed.
+ ViewsLayoutClass* layout_ref_;
+
+ // Unowned reference to the views::View that owns this object. Will be nullptr
+ // after the views::LayoutManager is destroyed.
+ views::View* owner_view_;
+};
+
+#endif // CEF_LIBCEF_BROWSER_VIEWS_LAYOUT_IMPL_H_
diff --git a/libcef/browser/views/layout_util.cc b/libcef/browser/views/layout_util.cc
new file mode 100644
index 00000000..1d5602ed
--- /dev/null
+++ b/libcef/browser/views/layout_util.cc
@@ -0,0 +1,75 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#include "libcef/browser/views/layout_util.h"
+
+#include <utility>
+
+#include "libcef/browser/views/layout_adapter.h"
+
+#include "ui/views/view.h"
+
+namespace layout_util {
+
+namespace {
+
+// Manages the association between views::View and CefLayout instances.
+class UserData : public base::SupportsUserData::Data {
+ public:
+ static CefRefPtr<CefLayout> GetFor(const views::View* view) {
+ UserData* data = static_cast<UserData*>(view->GetUserData(UserDataKey()));
+ if (data) {
+ return data->layout_;
+ }
+ return nullptr;
+ }
+
+ // Assign ownership of the underlying views::LayoutManager to |owner_view|.
+ // The views::View that owns the views::LayoutManager will gain a ref-counted
+ // reference to the CefLayout and the CefLayout will keep an unowned reference
+ // to the views::LayoutManager. Destruction of the views::View will release
+ // the reference to the CefLayout.
+ static void Assign(CefRefPtr<CefLayout> cef_layout, views::View* owner_view) {
+ DCHECK(owner_view);
+ DCHECK(cef_layout->IsValid());
+
+ views::LayoutManager* layout = CefLayoutAdapter::GetFor(cef_layout)->Get();
+ DCHECK(layout);
+
+ // The CefLayout previously associated with |owner_view|, if any, will be
+ // destroyed by this call.
+ owner_view->SetUserData(UserDataKey(),
+ base::WrapUnique(new UserData(cef_layout)));
+ }
+
+ private:
+ friend std::default_delete<UserData>;
+
+ explicit UserData(CefRefPtr<CefLayout> cef_layout) : layout_(cef_layout) {
+ DCHECK(layout_);
+ }
+
+ ~UserData() override { CefLayoutAdapter::GetFor(layout_)->Detach(); }
+
+ static void* UserDataKey() {
+ // We just need a unique constant. Use the address of a static that
+ // COMDAT folding won't touch in an optimizing linker.
+ static int data_key = 0;
+ return reinterpret_cast<void*>(&data_key);
+ }
+
+ CefRefPtr<CefLayout> layout_;
+};
+
+} // namespace
+
+CefRefPtr<CefLayout> GetFor(const views::View* view) {
+ return UserData::GetFor(view);
+}
+
+void Assign(CefRefPtr<CefLayout> layout, views::View* owner_view) {
+ return UserData::Assign(layout, owner_view);
+}
+
+} // namespace layout_util
diff --git a/libcef/browser/views/layout_util.h b/libcef/browser/views/layout_util.h
new file mode 100644
index 00000000..bd0555eb
--- /dev/null
+++ b/libcef/browser/views/layout_util.h
@@ -0,0 +1,32 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_VIEWS_LAYOUT_UTIL_H_
+#define CEF_LIBCEF_BROWSER_VIEWS_LAYOUT_UTIL_H_
+#pragma once
+
+#include "include/views/cef_layout.h"
+
+#include "ui/views/layout/layout_manager.h"
+
+namespace views {
+class View;
+}
+
+// The below functions manage the relationship between CefLayout and
+// views::LayoutManager instances. See comments in view_impl.h for a usage
+// overview.
+
+namespace layout_util {
+
+// Returns the CefLayout object associated with |owner_view|.
+CefRefPtr<CefLayout> GetFor(const views::View* owner_view);
+
+// Assign ownership of |layout| to |owner_view|. If a CefLayout is already
+// associated with |owner_view| it will be invalidated.
+void Assign(CefRefPtr<CefLayout> layout, views::View* owner_view);
+
+} // namespace layout_util
+
+#endif // CEF_LIBCEF_BROWSER_VIEWS_LAYOUT_UTIL_H_
diff --git a/libcef/browser/views/menu_button_impl.cc b/libcef/browser/views/menu_button_impl.cc
new file mode 100644
index 00000000..d74d2cf6
--- /dev/null
+++ b/libcef/browser/views/menu_button_impl.cc
@@ -0,0 +1,73 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#include "libcef/browser/views/menu_button_impl.h"
+
+#include "libcef/browser/views/menu_button_view.h"
+#include "libcef/browser/views/window_impl.h"
+
+#include "ui/gfx/canvas.h"
+
+// static
+CefRefPtr<CefMenuButton> CefMenuButton::CreateMenuButton(
+ CefRefPtr<CefMenuButtonDelegate> delegate,
+ const CefString& text) {
+ return CefMenuButtonImpl::Create(delegate, text);
+}
+
+// static
+CefRefPtr<CefMenuButtonImpl> CefMenuButtonImpl::Create(
+ CefRefPtr<CefMenuButtonDelegate> delegate,
+ const CefString& text) {
+ CEF_REQUIRE_UIT_RETURN(nullptr);
+ DCHECK(delegate);
+ if (!delegate) {
+ return nullptr;
+ }
+ CefRefPtr<CefMenuButtonImpl> menu_button = new CefMenuButtonImpl(delegate);
+ menu_button->Initialize();
+ if (!text.empty()) {
+ menu_button->SetText(text);
+ }
+ return menu_button;
+}
+
+void CefMenuButtonImpl::ShowMenu(CefRefPtr<CefMenuModel> menu_model,
+ const CefPoint& screen_point,
+ cef_menu_anchor_position_t anchor_position) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ CefRefPtr<CefWindow> window =
+ view_util::GetWindowFor(root_view()->GetWidget());
+ CefWindowImpl* window_impl = static_cast<CefWindowImpl*>(window.get());
+ if (window_impl) {
+ window_impl->ShowMenu(root_view(), menu_model, screen_point,
+ anchor_position);
+ }
+}
+
+void CefMenuButtonImpl::TriggerMenu() {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ root_view()->Activate(nullptr);
+}
+
+void CefMenuButtonImpl::SetFocusable(bool focusable) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ static_cast<CefMenuButtonView*>(root_view())
+ ->SetDrawStringsFlags(focusable ? gfx::Canvas::SHOW_PREFIX
+ : gfx::Canvas::HIDE_PREFIX);
+ ParentClass::SetFocusable(focusable);
+}
+
+CefMenuButtonImpl::CefMenuButtonImpl(CefRefPtr<CefMenuButtonDelegate> delegate)
+ : ParentClass(delegate) {
+ DCHECK(delegate);
+}
+
+views::MenuButton* CefMenuButtonImpl::CreateRootView() {
+ return new CefMenuButtonView(delegate());
+}
+
+void CefMenuButtonImpl::InitializeRootView() {
+ static_cast<CefMenuButtonView*>(root_view())->Initialize();
+}
diff --git a/libcef/browser/views/menu_button_impl.h b/libcef/browser/views/menu_button_impl.h
new file mode 100644
index 00000000..26bb14ff
--- /dev/null
+++ b/libcef/browser/views/menu_button_impl.h
@@ -0,0 +1,61 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_VIEWS_MENU_BUTTON_IMPL_H_
+#define CEF_LIBCEF_BROWSER_VIEWS_MENU_BUTTON_IMPL_H_
+#pragma once
+
+#include "include/views/cef_menu_button.h"
+#include "include/views/cef_menu_button_delegate.h"
+
+#include "libcef/browser/menu_model_impl.h"
+#include "libcef/browser/views/label_button_impl.h"
+
+#include "ui/views/controls/button/menu_button.h"
+
+class CefMenuButtonImpl : public CefLabelButtonImpl<views::MenuButton,
+ CefMenuButton,
+ CefMenuButtonDelegate> {
+ public:
+ using ParentClass = CefLabelButtonImpl<views::MenuButton,
+ CefMenuButton,
+ CefMenuButtonDelegate>;
+
+ CefMenuButtonImpl(const CefMenuButtonImpl&) = delete;
+ CefMenuButtonImpl& operator=(const CefMenuButtonImpl&) = delete;
+
+ // Create a new CefMenuButton instance. |delegate| must not be nullptr.
+ static CefRefPtr<CefMenuButtonImpl> Create(
+ CefRefPtr<CefMenuButtonDelegate> delegate,
+ const CefString& text);
+
+ // CefMenuButton methods:
+ void ShowMenu(CefRefPtr<CefMenuModel> menu_model,
+ const CefPoint& screen_point,
+ cef_menu_anchor_position_t anchor_position) override;
+ void TriggerMenu() override;
+
+ // CefLabelButton methods:
+ CefRefPtr<CefMenuButton> AsMenuButton() override { return this; }
+
+ // CefViewAdapter methods:
+ std::string GetDebugType() override { return "MenuButton"; }
+
+ // CefView methods:
+ void SetFocusable(bool focusable) override;
+
+ private:
+ // Create a new implementation object.
+ // Always call Initialize() after creation.
+ // |delegate| must not be nullptr.
+ explicit CefMenuButtonImpl(CefRefPtr<CefMenuButtonDelegate> delegate);
+
+ // CefViewImpl methods:
+ views::MenuButton* CreateRootView() override;
+ void InitializeRootView() override;
+
+ IMPLEMENT_REFCOUNTING_DELETE_ON_UIT(CefMenuButtonImpl);
+};
+
+#endif // CEF_LIBCEF_BROWSER_VIEWS_MENU_BUTTON_IMPL_H_
diff --git a/libcef/browser/views/menu_button_view.cc b/libcef/browser/views/menu_button_view.cc
new file mode 100644
index 00000000..3e8974fe
--- /dev/null
+++ b/libcef/browser/views/menu_button_view.cc
@@ -0,0 +1,61 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#include "libcef/browser/views/menu_button_view.h"
+
+#include "libcef/browser/thread_util.h"
+
+#include "ui/gfx/canvas.h"
+#include "ui/views/controls/button/menu_button_controller.h"
+#include "ui/views/controls/menu/menu_config.h"
+
+namespace {
+
+class ButtonPressedLock : public CefMenuButtonPressedLock {
+ public:
+ explicit ButtonPressedLock(views::MenuButton* menu_button)
+ : pressed_lock_(menu_button->button_controller()) {}
+
+ ButtonPressedLock(const ButtonPressedLock&) = delete;
+ ButtonPressedLock& operator=(const ButtonPressedLock&) = delete;
+
+ private:
+ views::MenuButtonController::PressedLock pressed_lock_;
+
+ IMPLEMENT_REFCOUNTING_DELETE_ON_UIT(ButtonPressedLock);
+};
+
+} // namespace
+
+CefMenuButtonView::CefMenuButtonView(CefMenuButtonDelegate* cef_delegate)
+ : ParentClass(cef_delegate) {
+ DCHECK(cef_delegate);
+}
+
+void CefMenuButtonView::Initialize() {
+ ParentClass::Initialize();
+
+ SetDrawStringsFlags(IsFocusable() ? gfx::Canvas::SHOW_PREFIX
+ : gfx::Canvas::HIDE_PREFIX);
+
+ // Use the same default font as MenuItemView.
+ SetFontList(views::MenuConfig::instance().font_list);
+}
+
+CefRefPtr<CefMenuButton> CefMenuButtonView::GetCefMenuButton() const {
+ CefRefPtr<CefMenuButton> menu_button = GetCefLabelButton()->AsMenuButton();
+ DCHECK(menu_button);
+ return menu_button;
+}
+
+void CefMenuButtonView::SetDrawStringsFlags(int flags) {
+ label()->SetDrawStringsFlags(flags);
+}
+
+void CefMenuButtonView::ButtonPressed(const ui::Event& event) {
+ auto position = GetMenuPosition();
+ cef_delegate()->OnMenuButtonPressed(GetCefMenuButton(),
+ CefPoint(position.x(), position.y()),
+ new ButtonPressedLock(this));
+}
diff --git a/libcef/browser/views/menu_button_view.h b/libcef/browser/views/menu_button_view.h
new file mode 100644
index 00000000..e5c94d72
--- /dev/null
+++ b/libcef/browser/views/menu_button_view.h
@@ -0,0 +1,55 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_VIEWS_MENU_BUTTON_VIEW_H_
+#define CEF_LIBCEF_BROWSER_VIEWS_MENU_BUTTON_VIEW_H_
+#pragma once
+
+#include "include/views/cef_menu_button.h"
+#include "include/views/cef_menu_button_delegate.h"
+
+#include "libcef/browser/views/label_button_view.h"
+
+#include "ui/views/controls/button/menu_button.h"
+
+// Extend views::LabelButton with a no-argument constructor as required by the
+// CefViewView template and extend views::ButtonListener as required by the
+// CefButtonView template.
+class MenuButtonEx : public views::MenuButton {
+ public:
+ MenuButtonEx()
+ : views::MenuButton(base::BindRepeating(
+ [](MenuButtonEx* self, const ui::Event& event) {
+ self->ButtonPressed(event);
+ },
+ base::Unretained(this))) {}
+
+ virtual void ButtonPressed(const ui::Event& event) = 0;
+};
+
+class CefMenuButtonView
+ : public CefLabelButtonView<MenuButtonEx, CefMenuButtonDelegate> {
+ public:
+ using ParentClass = CefLabelButtonView<MenuButtonEx, CefMenuButtonDelegate>;
+
+ // |cef_delegate| must not be nullptr.
+ explicit CefMenuButtonView(CefMenuButtonDelegate* cef_delegate);
+
+ CefMenuButtonView(const CefMenuButtonView&) = delete;
+ CefMenuButtonView& operator=(const CefMenuButtonView&) = delete;
+
+ void Initialize() override;
+
+ // Returns the CefMenuButton associated with this view. See comments on
+ // CefViewView::GetCefView.
+ CefRefPtr<CefMenuButton> GetCefMenuButton() const;
+
+ // Set the flags that control display of accelerator characters.
+ void SetDrawStringsFlags(int flags);
+
+ // MenuButtonEx methods:
+ void ButtonPressed(const ui::Event& event) override;
+};
+
+#endif // CEF_LIBCEF_BROWSER_VIEWS_MENU_BUTTON_VIEW_H_
diff --git a/libcef/browser/views/menu_runner_views.cc b/libcef/browser/views/menu_runner_views.cc
new file mode 100644
index 00000000..14b3b55d
--- /dev/null
+++ b/libcef/browser/views/menu_runner_views.cc
@@ -0,0 +1,40 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#include "libcef/browser/views/menu_runner_views.h"
+
+#include "libcef/browser/alloy/alloy_browser_host_impl.h"
+#include "libcef/browser/views/browser_view_impl.h"
+
+CefMenuRunnerViews::CefMenuRunnerViews(CefBrowserViewImpl* browser_view)
+ : browser_view_(browser_view) {}
+
+bool CefMenuRunnerViews::RunContextMenu(
+ AlloyBrowserHostImpl* browser,
+ CefMenuModelImpl* model,
+ const content::ContextMenuParams& params) {
+ CefRefPtr<CefWindow> window = browser_view_->GetWindow();
+ if (!window) {
+ return false;
+ }
+
+ CefPoint screen_point(params.x, params.y);
+ browser_view_->ConvertPointToScreen(screen_point);
+
+ window->ShowMenu(model, screen_point, CEF_MENU_ANCHOR_TOPRIGHT);
+ return true;
+}
+
+void CefMenuRunnerViews::CancelContextMenu() {
+ CefRefPtr<CefWindow> window = browser_view_->GetWindow();
+ if (window) {
+ window->CancelMenu();
+ }
+}
+
+bool CefMenuRunnerViews::FormatLabel(std::u16string& label) {
+ // Remove the accelerator indicator (&) from label strings.
+ const std::u16string::value_type replace[] = {L'&', 0};
+ return base::ReplaceChars(label, replace, std::u16string(), &label);
+}
diff --git a/libcef/browser/views/menu_runner_views.h b/libcef/browser/views/menu_runner_views.h
new file mode 100644
index 00000000..d77ce82c
--- /dev/null
+++ b/libcef/browser/views/menu_runner_views.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_VIEWS_MENU_RUNNER_VIEWS_H_
+#define CEF_LIBCEF_BROWSER_VIEWS_MENU_RUNNER_VIEWS_H_
+#pragma once
+
+#include "libcef/browser/menu_runner.h"
+
+class CefBrowserViewImpl;
+
+class CefMenuRunnerViews : public CefMenuRunner {
+ public:
+ // |browser_view| is guaranteed to outlive this object.
+ explicit CefMenuRunnerViews(CefBrowserViewImpl* browser_view);
+
+ // CefMenuRunner methods.
+ bool RunContextMenu(AlloyBrowserHostImpl* browser,
+ CefMenuModelImpl* model,
+ const content::ContextMenuParams& params) override;
+ void CancelContextMenu() override;
+ bool FormatLabel(std::u16string& label) override;
+
+ private:
+ CefBrowserViewImpl* browser_view_;
+};
+
+#endif // CEF_LIBCEF_BROWSER_VIEWS_MENU_RUNNER_VIEWS_H_
diff --git a/libcef/browser/views/native_widget_mac.h b/libcef/browser/views/native_widget_mac.h
new file mode 100644
index 00000000..b4745764
--- /dev/null
+++ b/libcef/browser/views/native_widget_mac.h
@@ -0,0 +1,39 @@
+// Copyright 2023 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_VIEWS_NATIVE_WIDGET_MAC_H_
+#define CEF_LIBCEF_BROWSER_VIEWS_NATIVE_WIDGET_MAC_H_
+#pragma once
+
+#include "include/internal/cef_ptr.h"
+
+#include "ui/views/widget/native_widget_mac.h"
+
+class CefWindow;
+class CefWindowDelegate;
+
+class CefNativeWidgetMac : public views::NativeWidgetMac {
+ public:
+ CefNativeWidgetMac(views::internal::NativeWidgetDelegate* delegate,
+ CefRefPtr<CefWindow> window,
+ CefWindowDelegate* window_delegate);
+ ~CefNativeWidgetMac() override = default;
+
+ CefNativeWidgetMac(const CefNativeWidgetMac&) = delete;
+ CefNativeWidgetMac& operator=(const CefNativeWidgetMac&) = delete;
+
+ protected:
+ // NativeWidgetMac:
+ NativeWidgetMacNSWindow* CreateNSWindow(
+ const remote_cocoa::mojom::CreateWindowParams* params) override;
+
+ void GetWindowFrameTitlebarHeight(bool* override_titlebar_height,
+ float* titlebar_height) override;
+
+ private:
+ const CefRefPtr<CefWindow> window_;
+ CefWindowDelegate* const window_delegate_;
+};
+
+#endif // CEF_LIBCEF_BROWSER_VIEWS_NATIVE_WIDGET_MAC_H_
diff --git a/libcef/browser/views/native_widget_mac.mm b/libcef/browser/views/native_widget_mac.mm
new file mode 100644
index 00000000..b722c373
--- /dev/null
+++ b/libcef/browser/views/native_widget_mac.mm
@@ -0,0 +1,54 @@
+// Copyright 2023 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#include "libcef/browser/views/native_widget_mac.h"
+
+#include "include/views/cef_window.h"
+#include "include/views/cef_window_delegate.h"
+#include "libcef/browser/views/ns_window.h"
+
+CefNativeWidgetMac::CefNativeWidgetMac(
+ views::internal::NativeWidgetDelegate* delegate,
+ CefRefPtr<CefWindow> window,
+ CefWindowDelegate* window_delegate)
+ : views::NativeWidgetMac(delegate),
+ window_(window),
+ window_delegate_(window_delegate) {}
+
+NativeWidgetMacNSWindow* CefNativeWidgetMac::CreateNSWindow(
+ const remote_cocoa::mojom::CreateWindowParams* params) {
+ NSUInteger style_mask =
+ NSWindowStyleMaskTitled | NSWindowStyleMaskMiniaturizable |
+ NSWindowStyleMaskClosable | NSWindowStyleMaskResizable |
+ NSWindowStyleMaskTexturedBackground;
+
+ bool is_frameless = window_delegate_->IsFrameless(window_);
+
+ auto window = [[CefNSWindow alloc] initWithStyle:style_mask
+ isFrameless:is_frameless];
+
+ if (is_frameless) {
+ [window setTitlebarAppearsTransparent:YES];
+ [window setTitleVisibility:NSWindowTitleHidden];
+ }
+
+ if (!window_delegate_->WithStandardWindowButtons(window_)) {
+ [[window standardWindowButton:NSWindowCloseButton] setHidden:YES];
+ [[window standardWindowButton:NSWindowMiniaturizeButton] setHidden:YES];
+ [[window standardWindowButton:NSWindowZoomButton] setHidden:YES];
+ }
+
+ return window;
+}
+
+void CefNativeWidgetMac::GetWindowFrameTitlebarHeight(
+ bool* override_titlebar_height,
+ float* titlebar_height) {
+ if (window_delegate_->GetTitlebarHeight(window_, titlebar_height)) {
+ *override_titlebar_height = true;
+ } else {
+ views::NativeWidgetMac::GetWindowFrameTitlebarHeight(
+ override_titlebar_height, titlebar_height);
+ }
+}
diff --git a/libcef/browser/views/ns_window.h b/libcef/browser/views/ns_window.h
new file mode 100644
index 00000000..2ed159c3
--- /dev/null
+++ b/libcef/browser/views/ns_window.h
@@ -0,0 +1,20 @@
+// Copyright 2023 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_VIEWS_NS_WINDOW_H_
+#define CEF_LIBCEF_BROWSER_VIEWS_NS_WINDOW_H_
+#pragma once
+
+#include "components/remote_cocoa/app_shim/native_widget_mac_nswindow.h"
+
+@interface CefNSWindow : NativeWidgetMacNSWindow {
+ @private
+ bool is_frameless_;
+}
+- (id)initWithStyle:(NSUInteger)style_mask isFrameless:(bool)is_frameless;
+
+- (BOOL)shouldCenterTrafficLights;
+@end
+
+#endif // CEF_LIBCEF_BROWSER_VIEWS_NS_WINDOW_H_
diff --git a/libcef/browser/views/ns_window.mm b/libcef/browser/views/ns_window.mm
new file mode 100644
index 00000000..b7d42ba0
--- /dev/null
+++ b/libcef/browser/views/ns_window.mm
@@ -0,0 +1,104 @@
+// Copyright 2023 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#include "libcef/browser/views/ns_window.h"
+
+#include "base/i18n/rtl.h"
+#include "components/remote_cocoa/app_shim/native_widget_ns_window_bridge.h"
+#include "components/remote_cocoa/common/native_widget_ns_window_host.mojom.h"
+#include "ui/base/cocoa/window_size_constants.h"
+
+@interface CefThemeFrame : NativeWidgetMacNSWindowTitledFrame
+@end
+
+// NSThemeFrame (PrivateAPI) definitions.
+@interface NSThemeFrame (PrivateAPI)
+- (void)setStyleMask:(NSUInteger)styleMask;
+- (CGFloat)_titlebarHeight;
+- (BOOL)_shouldCenterTrafficLights;
+@end
+
+@implementation CefThemeFrame {
+ bool in_full_screen_;
+}
+
+// NSThemeFrame (PrivateAPI) overrides.
+- (void)setStyleMask:(NSUInteger)styleMask {
+ in_full_screen_ = (styleMask & NSWindowStyleMaskFullScreen) != 0;
+ [super setStyleMask:styleMask];
+}
+
+- (CGFloat)_titlebarHeight {
+ if (!in_full_screen_) {
+ bool override_titlebar_height = false;
+ float titlebar_height = 0;
+ auto* window = base::mac::ObjCCast<CefNSWindow>([self window]);
+ if (auto* bridge = [window bridge]) {
+ bridge->host()->GetWindowFrameTitlebarHeight(&override_titlebar_height,
+ &titlebar_height);
+
+ if (override_titlebar_height)
+ return titlebar_height;
+ }
+ }
+
+ return [super _titlebarHeight];
+}
+
+- (BOOL)_shouldCenterTrafficLights {
+ auto* window = base::mac::ObjCCast<CefNSWindow>([self window]);
+ return [window shouldCenterTrafficLights];
+}
+
+- (BOOL)_shouldFlipTrafficLightsForRTL {
+ return base::i18n::IsRTL() ? YES : NO;
+}
+
+@end
+
+@interface NSWindow (PrivateAPI)
++ (Class)frameViewClassForStyleMask:(NSUInteger)windowStyle;
+@end
+
+@implementation CefNSWindow
+
+- (id)initWithStyle:(NSUInteger)style_mask isFrameless:(bool)is_frameless {
+ if ((self = [super initWithContentRect:ui::kWindowSizeDeterminedLater
+ styleMask:style_mask
+ backing:NSBackingStoreBuffered
+ defer:NO])) {
+ is_frameless_ = is_frameless;
+ }
+ return self;
+}
+
+- (BOOL)shouldCenterTrafficLights {
+ return is_frameless_ ? YES : NO;
+}
+
+// NSWindow overrides.
+- (NSRect)contentRectForFrameRect:(NSRect)frameRect {
+ if (is_frameless_) {
+ return frameRect;
+ }
+ return [super contentRectForFrameRect:frameRect];
+}
+
+- (NSRect)frameRectForContentRect:(NSRect)contentRect {
+ if (is_frameless_) {
+ return contentRect;
+ }
+ return [super frameRectForContentRect:contentRect];
+}
+
+// NSWindow (PrivateAPI) overrides.
++ (Class)frameViewClassForStyleMask:(NSUInteger)windowStyle {
+ if (Class custom_frame = [CefThemeFrame class]) {
+ return custom_frame;
+ }
+
+ return [super frameViewClassForStyleMask:windowStyle];
+}
+
+@end
diff --git a/libcef/browser/views/overlay_view_host.cc b/libcef/browser/views/overlay_view_host.cc
new file mode 100644
index 00000000..ec61fd65
--- /dev/null
+++ b/libcef/browser/views/overlay_view_host.cc
@@ -0,0 +1,336 @@
+// Copyright 2021 The Chromium Embedded Framework Authors. Portions copyright
+// 2011 The Chromium Authors. All rights reserved. Use of this source code is
+// governed by a BSD-style license that can be found in the LICENSE file.
+
+#include "libcef/browser/views/overlay_view_host.h"
+
+#include "libcef/browser/views/view_util.h"
+#include "libcef/browser/views/window_view.h"
+
+#include "base/i18n/rtl.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
+#include "chrome/browser/ui/views/theme_copying_widget.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "ui/compositor/compositor.h"
+#include "ui/compositor/layer.h"
+
+#if defined(USE_AURA)
+#include "ui/aura/window.h"
+#include "ui/views/view_constants_aura.h"
+#endif
+
+namespace {
+
+class CefOverlayControllerImpl : public CefOverlayController {
+ public:
+ CefOverlayControllerImpl(CefOverlayViewHost* host, CefRefPtr<CefView> view)
+ : host_(host), view_(view) {}
+
+ CefOverlayControllerImpl(const CefOverlayControllerImpl&) = delete;
+ CefOverlayControllerImpl& operator=(const CefOverlayControllerImpl&) = delete;
+
+ bool IsValid() override {
+ // View validity implies that CefOverlayViewHost is still valid, because the
+ // Widget that it owns (and that owns the View) is still valid.
+ return view_ && view_->IsValid();
+ }
+
+ bool IsSame(CefRefPtr<CefOverlayController> that) override {
+ return that && that->GetContentsView()->IsSame(view_);
+ }
+
+ CefRefPtr<CefView> GetContentsView() override { return view_; }
+
+ CefRefPtr<CefWindow> GetWindow() override {
+ if (IsValid()) {
+ return view_util::GetWindowFor(host_->window_view()->GetWidget());
+ }
+ return nullptr;
+ }
+
+ cef_docking_mode_t GetDockingMode() override {
+ if (IsValid()) {
+ return host_->docking_mode();
+ }
+ return CEF_DOCKING_MODE_TOP_LEFT;
+ }
+
+ void Destroy() override {
+ if (IsValid()) {
+ host_->Destroy();
+ view_ = nullptr;
+ }
+ }
+
+ void SetBounds(const CefRect& bounds) override {
+ if (IsValid() && host_->docking_mode() == CEF_DOCKING_MODE_CUSTOM) {
+ host_->SetOverlayBounds(
+ gfx::Rect(bounds.x, bounds.y, bounds.width, bounds.height));
+ }
+ }
+
+ CefRect GetBounds() override {
+ if (IsValid()) {
+ const auto& bounds = host_->bounds();
+ return CefRect(bounds.x(), bounds.y(), bounds.width(), bounds.height());
+ }
+ return CefRect();
+ }
+
+ CefRect GetBoundsInScreen() override {
+ if (IsValid()) {
+ const auto& bounds = host_->widget()->GetWindowBoundsInScreen();
+ return CefRect(bounds.x(), bounds.y(), bounds.width(), bounds.height());
+ }
+ return CefRect();
+ }
+
+ void SetSize(const CefSize& size) override {
+ if (IsValid() && host_->docking_mode() == CEF_DOCKING_MODE_CUSTOM) {
+ // Update the size without changing the origin.
+ const auto& origin = host_->bounds().origin();
+ host_->SetOverlayBounds(
+ gfx::Rect(origin, gfx::Size(size.width, size.height)));
+ }
+ }
+
+ CefSize GetSize() override {
+ const auto& bounds = GetBounds();
+ return CefSize(bounds.width, bounds.height);
+ }
+
+ void SetPosition(const CefPoint& position) override {
+ if (IsValid() && host_->docking_mode() == CEF_DOCKING_MODE_CUSTOM) {
+ // Update the origin without changing the size.
+ const auto& size = host_->bounds().size();
+ host_->SetOverlayBounds(
+ gfx::Rect(gfx::Point(position.x, position.y), size));
+ }
+ }
+
+ CefPoint GetPosition() override {
+ const auto& bounds = GetBounds();
+ return CefPoint(bounds.x, bounds.y);
+ }
+
+ void SetInsets(const CefInsets& insets) override {
+ if (IsValid() && host_->docking_mode() != CEF_DOCKING_MODE_CUSTOM) {
+ host_->SetOverlayInsets(insets);
+ }
+ }
+
+ CefInsets GetInsets() override {
+ if (IsValid()) {
+ return host_->insets();
+ }
+ return CefInsets();
+ }
+
+ void SizeToPreferredSize() override {
+ if (IsValid()) {
+ if (host_->docking_mode() == CEF_DOCKING_MODE_CUSTOM) {
+ // Update the size without changing the origin.
+ const auto& origin = host_->bounds().origin();
+ const auto& preferred_size = host_->view()->GetPreferredSize();
+ host_->SetOverlayBounds(gfx::Rect(origin, preferred_size));
+ } else {
+ host_->MoveIfNecessary();
+ }
+ }
+ }
+
+ void SetVisible(bool visible) override {
+ if (IsValid()) {
+ if (visible) {
+ host_->MoveIfNecessary();
+ host_->widget()->Show();
+ } else {
+ host_->widget()->Hide();
+ }
+ }
+ }
+
+ bool IsVisible() override {
+ if (IsValid()) {
+ return host_->widget()->IsVisible();
+ }
+ return false;
+ }
+
+ bool IsDrawn() override { return IsVisible(); }
+
+ private:
+ CefOverlayViewHost* const host_;
+ CefRefPtr<CefView> view_;
+
+ IMPLEMENT_REFCOUNTING(CefOverlayControllerImpl);
+};
+
+} // namespace
+
+CefOverlayViewHost::CefOverlayViewHost(CefWindowView* window_view,
+ cef_docking_mode_t docking_mode)
+ : window_view_(window_view), docking_mode_(docking_mode) {}
+
+void CefOverlayViewHost::Init(views::View* widget_view,
+ CefRefPtr<CefView> view) {
+ DCHECK(view);
+
+ // Match the logic in CEF_PANEL_IMPL_D::AddChildView().
+ auto controls_view = view->IsAttached()
+ ? base::WrapUnique(view_util::GetFor(view))
+ : view_util::PassOwnership(view);
+ DCHECK(controls_view.get());
+
+ cef_controller_ = new CefOverlayControllerImpl(this, view);
+
+ // Initialize the Widget.
+ widget_ = std::make_unique<ThemeCopyingWidget>(window_view_->GetWidget());
+ views::Widget::InitParams params(views::Widget::InitParams::TYPE_CONTROL);
+ params.delegate = this;
+ params.name = "CefOverlayViewHost";
+ params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+ params.parent = window_view_->GetWidget()->GetNativeView();
+ params.opacity = views::Widget::InitParams::WindowOpacity::kTranslucent;
+ params.activatable = views::Widget::InitParams::Activatable::kNo;
+ widget_->Init(std::move(params));
+
+ view_ = widget_->GetContentsView()->AddChildView(std::move(controls_view));
+
+ // Make the Widget background transparent. The View might still be opaque.
+ if (widget_->GetCompositor()) {
+ widget_->GetCompositor()->SetBackgroundColor(SK_ColorTRANSPARENT);
+ }
+
+#if defined(USE_AURA)
+ // See matching logic in view_util::GetWindowFor.
+ widget_->GetNativeView()->SetProperty(views::kHostViewKey, widget_view);
+#endif
+
+ if (cef::IsChromeRuntimeEnabled()) {
+ // Some attributes associated with a Chrome toolbar are located via the
+ // Widget. See matching logic in BrowserView::AddedToWidget.
+ auto browser_view = BrowserView::GetBrowserViewForNativeWindow(
+ view_util::GetNativeWindow(window_view_->GetWidget()));
+ if (browser_view) {
+ widget_->SetNativeWindowProperty(BrowserView::kBrowserViewKey,
+ browser_view);
+ }
+ }
+
+ // Set the initial bounds after the View has been added to the Widget.
+ // Otherwise, preferred size won't calculate correctly.
+ gfx::Rect bounds;
+ if (docking_mode_ == CEF_DOCKING_MODE_CUSTOM) {
+ if (view_->size().IsEmpty()) {
+ // Size to the preferred size to start.
+ view_->SizeToPreferredSize();
+ }
+
+ // Top-left origin with existing size.
+ bounds = gfx::Rect(gfx::Point(), view_->size());
+ } else {
+ bounds = ComputeBounds();
+ }
+ SetOverlayBounds(bounds);
+
+ // Register for future bounds change notifications.
+ view_->AddObserver(this);
+
+ // Initially hidden.
+ widget_->Hide();
+}
+
+void CefOverlayViewHost::Destroy() {
+ if (widget_ && !widget_->IsClosed()) {
+ // Remove the child View immediately. It may be reused by the client.
+ auto view = view_util::GetFor(view_, /*find_known_parent=*/false);
+ widget_->GetContentsView()->RemoveChildView(view_);
+ if (view) {
+ view_util::ResumeOwnership(view);
+ }
+
+ widget_->Close();
+ }
+}
+
+void CefOverlayViewHost::MoveIfNecessary() {
+ if (bounds_changing_ || docking_mode_ == CEF_DOCKING_MODE_CUSTOM) {
+ return;
+ }
+ SetOverlayBounds(ComputeBounds());
+}
+
+void CefOverlayViewHost::SetOverlayBounds(const gfx::Rect& bounds) {
+ // Avoid re-entrancy of this method.
+ if (bounds_changing_) {
+ return;
+ }
+
+ gfx::Rect new_bounds = bounds;
+
+ // Keep the result inside the widget.
+ new_bounds.Intersect(window_view_->bounds());
+
+ if (new_bounds == bounds_) {
+ return;
+ }
+
+ bounds_changing_ = true;
+
+ bounds_ = new_bounds;
+ if (view_->size() != bounds_.size()) {
+ view_->SetSize(bounds_.size());
+ }
+ widget_->SetBounds(bounds_);
+
+ bounds_changing_ = false;
+}
+
+void CefOverlayViewHost::SetOverlayInsets(const CefInsets& insets) {
+ if (insets == insets_) {
+ return;
+ }
+ insets_ = insets;
+ MoveIfNecessary();
+}
+
+void CefOverlayViewHost::OnViewBoundsChanged(views::View* observed_view) {
+ MoveIfNecessary();
+}
+
+gfx::Rect CefOverlayViewHost::ComputeBounds() const {
+ // This method is only used with corner docking.
+ DCHECK_NE(docking_mode_, CEF_DOCKING_MODE_CUSTOM);
+
+ // Find the area we have to work with.
+ const auto& widget_bounds = window_view_->bounds();
+
+ // Ask the view how large an area it needs to draw on.
+ const auto& prefsize = view_->GetPreferredSize();
+
+ // Swap left/right docking with RTL.
+ const bool is_rtl = base::i18n::IsRTL();
+
+ // Dock to the correct corner, considering insets in the docking corner only.
+ int x = widget_bounds.x();
+ int y = widget_bounds.y();
+ if (((docking_mode_ == CEF_DOCKING_MODE_TOP_RIGHT ||
+ docking_mode_ == CEF_DOCKING_MODE_BOTTOM_RIGHT) &&
+ !is_rtl) ||
+ ((docking_mode_ == CEF_DOCKING_MODE_TOP_LEFT ||
+ docking_mode_ == CEF_DOCKING_MODE_BOTTOM_LEFT) &&
+ is_rtl)) {
+ x += widget_bounds.width() - prefsize.width() - insets_.right;
+ } else {
+ x += insets_.left;
+ }
+ if (docking_mode_ == CEF_DOCKING_MODE_BOTTOM_LEFT ||
+ docking_mode_ == CEF_DOCKING_MODE_BOTTOM_RIGHT) {
+ y += widget_bounds.height() - prefsize.height() - insets_.bottom;
+ } else {
+ y += insets_.top;
+ }
+
+ return gfx::Rect(x, y, prefsize.width(), prefsize.height());
+}
diff --git a/libcef/browser/views/overlay_view_host.h b/libcef/browser/views/overlay_view_host.h
new file mode 100644
index 00000000..32c7d601
--- /dev/null
+++ b/libcef/browser/views/overlay_view_host.h
@@ -0,0 +1,78 @@
+// Copyright 2021 The Chromium Embedded Framework Authors. Portions copyright
+// 2011 The Chromium Authors. All rights reserved. Use of this source code is
+// governed by a BSD-style license that can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_VIEWS_OVERLAY_VIEW_HOST_H_
+#define CEF_LIBCEF_BROWSER_VIEWS_OVERLAY_VIEW_HOST_H_
+#pragma once
+
+#include <memory>
+
+#include "include/views/cef_overlay_controller.h"
+#include "include/views/cef_view.h"
+
+#include "ui/views/view_observer.h"
+#include "ui/views/widget/widget_delegate.h"
+
+class CefWindowView;
+
+// Host class for a child Widget that behaves as an overlay control. Based on
+// Chrome's DropdownBarHost.
+class CefOverlayViewHost : public views::WidgetDelegate,
+ public views::ViewObserver {
+ public:
+ // |window_view| is the top-level view that contains this overlay.
+ CefOverlayViewHost(CefWindowView* window_view,
+ cef_docking_mode_t docking_mode);
+
+ CefOverlayViewHost(const CefOverlayViewHost&) = delete;
+ CefOverlayViewHost& operator=(const CefOverlayViewHost&) = delete;
+
+ // Initializes the CefOverlayViewHost. This creates the Widget that |view|
+ // paints into. |host_view| is the view whose position in the |window_view_|
+ // view hierarchy determines the z-order of the widget relative to views with
+ // layers and views with associated NativeViews.
+ void Init(views::View* host_view, CefRefPtr<CefView> view);
+
+ void Destroy();
+
+ void MoveIfNecessary();
+
+ void SetOverlayBounds(const gfx::Rect& bounds);
+ void SetOverlayInsets(const CefInsets& insets);
+
+ // views::ViewObserver methods:
+ void OnViewBoundsChanged(views::View* observed_view) override;
+
+ cef_docking_mode_t docking_mode() const { return docking_mode_; }
+ CefRefPtr<CefOverlayController> controller() const { return cef_controller_; }
+ CefWindowView* window_view() const { return window_view_; }
+ views::Widget* widget() const { return widget_.get(); }
+ views::View* view() const { return view_; }
+ gfx::Rect bounds() const { return bounds_; }
+ CefInsets insets() const { return insets_; }
+
+ private:
+ gfx::Rect ComputeBounds() const;
+
+ // The CefWindowView that created us.
+ CefWindowView* const window_view_;
+
+ const cef_docking_mode_t docking_mode_;
+
+ // Our view, which is responsible for drawing the UI.
+ views::View* view_ = nullptr;
+
+ // The Widget implementation that is created and maintained by the overlay.
+ // It contains |view_|.
+ std::unique_ptr<views::Widget> widget_;
+
+ CefRefPtr<CefOverlayController> cef_controller_;
+
+ gfx::Rect bounds_;
+ bool bounds_changing_ = false;
+
+ CefInsets insets_;
+};
+
+#endif // CEF_LIBCEF_BROWSER_VIEWS_OVERLAY_VIEW_HOST_H_
diff --git a/libcef/browser/views/panel_impl.h b/libcef/browser/views/panel_impl.h
new file mode 100644
index 00000000..56083b27
--- /dev/null
+++ b/libcef/browser/views/panel_impl.h
@@ -0,0 +1,219 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_VIEWS_PANEL_IMPL_H_
+#define CEF_LIBCEF_BROWSER_VIEWS_PANEL_IMPL_H_
+#pragma once
+
+#include "include/views/cef_fill_layout.h"
+#include "include/views/cef_layout.h"
+#include "include/views/cef_panel.h"
+#include "include/views/cef_window.h"
+
+#include "libcef/browser/views/box_layout_impl.h"
+#include "libcef/browser/views/fill_layout_impl.h"
+#include "libcef/browser/views/layout_util.h"
+#include "libcef/browser/views/view_impl.h"
+
+#include "base/logging.h"
+
+// Helpers for template boiler-plate.
+#define CEF_PANEL_IMPL_T CEF_VIEW_IMPL_T
+#define CEF_PANEL_IMPL_A CEF_VIEW_IMPL_A
+#define CEF_PANEL_IMPL_D CefPanelImpl<CEF_PANEL_IMPL_A>
+
+// Template for implementing CefPanel-derived classes. See comments in
+// view_impl.h for a usage overview.
+CEF_PANEL_IMPL_T class CefPanelImpl : public CEF_VIEW_IMPL_D {
+ public:
+ using ParentClass = CEF_VIEW_IMPL_D;
+
+ // CefPanel methods. When adding new As*() methods make sure to update
+ // CefViewAdapter::GetFor() in view_adapter.cc.
+ CefRefPtr<CefWindow> AsWindow() override { return nullptr; }
+ CefRefPtr<CefFillLayout> SetToFillLayout() override;
+ CefRefPtr<CefBoxLayout> SetToBoxLayout(
+ const CefBoxLayoutSettings& settings) override;
+ CefRefPtr<CefLayout> GetLayout() override;
+ void Layout() override;
+ void AddChildView(CefRefPtr<CefView> view) override;
+ void AddChildViewAt(CefRefPtr<CefView> view, int index) override;
+ void ReorderChildView(CefRefPtr<CefView> view, int index) override;
+ void RemoveChildView(CefRefPtr<CefView> view) override;
+ void RemoveAllChildViews() override;
+ size_t GetChildViewCount() override;
+ CefRefPtr<CefView> GetChildViewAt(int index) override;
+
+ // CefView methods:
+ CefRefPtr<CefPanel> AsPanel() override { return this; }
+
+ // CefViewAdapter methods:
+ void GetDebugInfo(base::Value::Dict* info, bool include_children) override {
+ ParentClass::GetDebugInfo(info, include_children);
+ if (include_children) {
+ const size_t count = ParentClass::content_view()->children().size();
+ if (count > 0U) {
+ base::Value::List children;
+
+ for (size_t i = 0U; i < count; ++i) {
+ views::View* view = ParentClass::content_view()->children()[i];
+ CefViewAdapter* adapter = CefViewAdapter::GetFor(view);
+ if (adapter) {
+ base::Value::Dict child_info;
+ adapter->GetDebugInfo(&child_info, include_children);
+ children.Append(std::move(child_info));
+ }
+ }
+
+ info->Set("children", std::move(children));
+ }
+ }
+ }
+
+ protected:
+ // Create a new implementation object.
+ // Always call Initialize() after creation.
+ // |delegate| may be nullptr.
+ explicit CefPanelImpl(CefRefPtr<CefViewDelegateClass> delegate)
+ : ParentClass(delegate) {}
+
+ void Initialize() override {
+ ParentClass::Initialize();
+
+ // Create the default layout object.
+ SetToFillLayout();
+ }
+};
+
+CEF_PANEL_IMPL_T CefRefPtr<CefFillLayout> CEF_PANEL_IMPL_D::SetToFillLayout() {
+ CEF_REQUIRE_VALID_RETURN(nullptr);
+ return CefFillLayoutImpl::Create(ParentClass::content_view());
+}
+
+CEF_PANEL_IMPL_T CefRefPtr<CefBoxLayout> CEF_PANEL_IMPL_D::SetToBoxLayout(
+ const CefBoxLayoutSettings& settings) {
+ CEF_REQUIRE_VALID_RETURN(nullptr);
+ return CefBoxLayoutImpl::Create(settings, ParentClass::content_view());
+}
+
+CEF_PANEL_IMPL_T CefRefPtr<CefLayout> CEF_PANEL_IMPL_D::GetLayout() {
+ CEF_REQUIRE_VALID_RETURN(nullptr);
+ return layout_util::GetFor(ParentClass::content_view());
+}
+
+CEF_PANEL_IMPL_T void CEF_PANEL_IMPL_D::Layout() {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ return ParentClass::root_view()->Layout();
+}
+
+CEF_PANEL_IMPL_T void CEF_PANEL_IMPL_D::AddChildView(CefRefPtr<CefView> view) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ DCHECK(view.get());
+ DCHECK(view->IsValid());
+ if (!view.get() || !view->IsValid()) {
+ return;
+ }
+
+ auto* view_ptr = view->IsAttached()
+ ? view_util::GetFor(view)
+ : view_util::PassOwnership(view).release();
+ DCHECK(view_ptr);
+ ParentClass::content_view()->AddChildView(view_ptr);
+}
+
+CEF_PANEL_IMPL_T void CEF_PANEL_IMPL_D::AddChildViewAt(CefRefPtr<CefView> view,
+ int index) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ DCHECK(view.get());
+ DCHECK(view->IsValid());
+ DCHECK_GE(index, 0);
+ DCHECK_LE(static_cast<unsigned int>(index),
+ ParentClass::content_view()->children().size());
+ if (!view.get() || !view->IsValid() || index < 0 ||
+ (static_cast<unsigned int>(index) >
+ ParentClass::content_view()->children().size())) {
+ return;
+ }
+
+ auto* view_ptr = view->IsAttached()
+ ? view_util::GetFor(view)
+ : view_util::PassOwnership(view).release();
+ DCHECK(view_ptr);
+ ParentClass::content_view()->AddChildViewAt(view_ptr, index);
+}
+
+CEF_PANEL_IMPL_T void CEF_PANEL_IMPL_D::ReorderChildView(
+ CefRefPtr<CefView> view,
+ int index) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ DCHECK(view.get());
+ DCHECK(view->IsValid());
+ DCHECK(view->IsAttached());
+ if (!view.get() || !view->IsValid() || !view->IsAttached()) {
+ return;
+ }
+
+ views::View* view_ptr = view_util::GetFor(view);
+ DCHECK(view_ptr);
+ DCHECK_EQ(view_ptr->parent(), ParentClass::content_view());
+ if (!view_ptr || view_ptr->parent() != ParentClass::content_view()) {
+ return;
+ }
+
+ ParentClass::content_view()->ReorderChildView(view_ptr, index);
+}
+
+CEF_PANEL_IMPL_T void CEF_PANEL_IMPL_D::RemoveChildView(
+ CefRefPtr<CefView> view) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ DCHECK(view.get());
+ DCHECK(view->IsValid());
+ DCHECK(view->IsAttached());
+ if (!view.get() || !view->IsValid() || !view->IsAttached()) {
+ return;
+ }
+
+ views::View* view_ptr = view_util::GetFor(view);
+ DCHECK(view_ptr);
+ DCHECK_EQ(view_ptr->parent(), ParentClass::content_view());
+ if (!view_ptr || view_ptr->parent() != ParentClass::content_view()) {
+ return;
+ }
+
+ ParentClass::content_view()->RemoveChildView(view_ptr);
+ view_util::ResumeOwnership(view);
+}
+
+CEF_PANEL_IMPL_T void CEF_PANEL_IMPL_D::RemoveAllChildViews() {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ while (!ParentClass::content_view()->children().empty()) {
+ CefRefPtr<CefView> view = view_util::GetFor(
+ ParentClass::content_view()->children().front(), false);
+ RemoveChildView(view);
+ }
+}
+
+CEF_PANEL_IMPL_T size_t CEF_PANEL_IMPL_D::GetChildViewCount() {
+ CEF_REQUIRE_VALID_RETURN(0U);
+ return ParentClass::content_view()->children().size();
+}
+
+CEF_PANEL_IMPL_T CefRefPtr<CefView> CEF_PANEL_IMPL_D::GetChildViewAt(
+ int index) {
+ CEF_REQUIRE_VALID_RETURN(nullptr);
+ DCHECK_GE(index, 0);
+ DCHECK_LT(static_cast<unsigned int>(index),
+ ParentClass::content_view()->children().size());
+ if (index < 0 || (static_cast<unsigned int>(index) >=
+ ParentClass::content_view()->children().size())) {
+ return nullptr;
+ }
+
+ CefRefPtr<CefView> view =
+ view_util::GetFor(ParentClass::content_view()->children()[index], false);
+ DCHECK(view);
+ return view;
+}
+
+#endif // CEF_LIBCEF_BROWSER_VIEWS_PANEL_IMPL_H_
diff --git a/libcef/browser/views/panel_view.h b/libcef/browser/views/panel_view.h
new file mode 100644
index 00000000..ef6d0e22
--- /dev/null
+++ b/libcef/browser/views/panel_view.h
@@ -0,0 +1,42 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_VIEWS_PANEL_VIEW_H_
+#define CEF_LIBCEF_BROWSER_VIEWS_PANEL_VIEW_H_
+#pragma once
+
+#include "include/views/cef_panel_delegate.h"
+
+#include "libcef/browser/thread_util.h"
+#include "libcef/browser/views/view_view.h"
+
+#include "base/logging.h"
+
+// Helpers for template boiler-plate.
+#define CEF_PANEL_VIEW_T CEF_VIEW_VIEW_T
+#define CEF_PANEL_VIEW_A CEF_VIEW_VIEW_A
+#define CEF_PANEL_VIEW_D CefPanelView<CEF_PANEL_VIEW_A>
+
+// Template for implementing views::View-derived classes that support adding and
+// removing children (called a Panel in CEF terminology). See comments in
+// view_impl.h for a usage overview.
+CEF_PANEL_VIEW_T class CefPanelView : public CEF_VIEW_VIEW_D {
+ public:
+ using ParentClass = CEF_VIEW_VIEW_D;
+
+ // |cef_delegate| may be nullptr.
+ template <typename... Args>
+ explicit CefPanelView(CefViewDelegateClass* cef_delegate, Args... args)
+ : ParentClass(cef_delegate, args...) {}
+
+ // Returns the CefPanel associated with this view. See comments on
+ // CefViewView::GetCefView.
+ CefRefPtr<CefPanel> GetCefPanel() const {
+ CefRefPtr<CefPanel> panel = ParentClass::GetCefView()->AsPanel();
+ DCHECK(panel);
+ return panel;
+ }
+};
+
+#endif // CEF_LIBCEF_BROWSER_VIEWS_PANEL_VIEW_H_
diff --git a/libcef/browser/views/scroll_view_impl.cc b/libcef/browser/views/scroll_view_impl.cc
new file mode 100644
index 00000000..946f1e4d
--- /dev/null
+++ b/libcef/browser/views/scroll_view_impl.cc
@@ -0,0 +1,90 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#include "libcef/browser/views/scroll_view_impl.h"
+
+// static
+CefRefPtr<CefScrollView> CefScrollView::CreateScrollView(
+ CefRefPtr<CefViewDelegate> delegate) {
+ return CefScrollViewImpl::Create(delegate);
+}
+
+// static
+CefRefPtr<CefScrollViewImpl> CefScrollViewImpl::Create(
+ CefRefPtr<CefViewDelegate> delegate) {
+ CEF_REQUIRE_UIT_RETURN(nullptr);
+ CefRefPtr<CefScrollViewImpl> view = new CefScrollViewImpl(delegate);
+ view->Initialize();
+ return view;
+}
+
+void CefScrollViewImpl::SetContentView(CefRefPtr<CefView> view) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ DCHECK(view.get());
+ DCHECK(view->IsValid());
+ DCHECK(!view->IsAttached());
+ if (!view.get() || !view->IsValid() || view->IsAttached()) {
+ return;
+ }
+
+ root_view()->SetContents(view_util::PassOwnership(view));
+}
+
+CefRefPtr<CefView> CefScrollViewImpl::GetContentView() {
+ CEF_REQUIRE_VALID_RETURN(nullptr);
+ return view_util::GetFor(root_view()->contents(), false);
+}
+
+CefRect CefScrollViewImpl::GetVisibleContentRect() {
+ CEF_REQUIRE_VALID_RETURN(CefRect());
+ const gfx::Rect& rect = root_view()->GetVisibleRect();
+ return CefRect(rect.x(), rect.y(), rect.width(), rect.height());
+}
+
+bool CefScrollViewImpl::HasHorizontalScrollbar() {
+ CEF_REQUIRE_VALID_RETURN(false);
+ const views::ScrollBar* scrollbar = root_view()->horizontal_scroll_bar();
+ return scrollbar && scrollbar->GetVisible();
+}
+
+int CefScrollViewImpl::GetHorizontalScrollbarHeight() {
+ CEF_REQUIRE_VALID_RETURN(0);
+ return root_view()->GetScrollBarLayoutHeight();
+}
+
+bool CefScrollViewImpl::HasVerticalScrollbar() {
+ CEF_REQUIRE_VALID_RETURN(false);
+ const views::ScrollBar* scrollbar = root_view()->vertical_scroll_bar();
+ return scrollbar && scrollbar->GetVisible();
+}
+
+int CefScrollViewImpl::GetVerticalScrollbarWidth() {
+ CEF_REQUIRE_VALID_RETURN(0);
+ return root_view()->GetScrollBarLayoutWidth();
+}
+
+void CefScrollViewImpl::GetDebugInfo(base::Value::Dict* info,
+ bool include_children) {
+ ParentClass::GetDebugInfo(info, include_children);
+ if (include_children) {
+ views::View* view = root_view()->contents();
+ CefViewAdapter* adapter = CefViewAdapter::GetFor(view);
+ if (adapter) {
+ base::Value::Dict child_info;
+ adapter->GetDebugInfo(&child_info, include_children);
+ info->Set("content_view", std::move(child_info));
+ }
+ }
+}
+
+CefScrollViewImpl::CefScrollViewImpl(CefRefPtr<CefViewDelegate> delegate)
+ : ParentClass(delegate) {}
+
+CefScrollViewView* CefScrollViewImpl::CreateRootView() {
+ return new CefScrollViewView(delegate());
+}
+
+void CefScrollViewImpl::InitializeRootView() {
+ static_cast<CefScrollViewView*>(root_view())->Initialize();
+}
diff --git a/libcef/browser/views/scroll_view_impl.h b/libcef/browser/views/scroll_view_impl.h
new file mode 100644
index 00000000..47d47cfb
--- /dev/null
+++ b/libcef/browser/views/scroll_view_impl.h
@@ -0,0 +1,55 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_VIEWS_SCROLL_VIEW_IMPL_H_
+#define CEF_LIBCEF_BROWSER_VIEWS_SCROLL_VIEW_IMPL_H_
+#pragma once
+
+#include "include/views/cef_scroll_view.h"
+#include "include/views/cef_view_delegate.h"
+
+#include "libcef/browser/views/scroll_view_view.h"
+#include "libcef/browser/views/view_impl.h"
+
+class CefScrollViewImpl
+ : public CefViewImpl<CefScrollViewView, CefScrollView, CefViewDelegate> {
+ public:
+ using ParentClass =
+ CefViewImpl<CefScrollViewView, CefScrollView, CefViewDelegate>;
+
+ CefScrollViewImpl(const CefScrollViewImpl&) = delete;
+ CefScrollViewImpl& operator=(const CefScrollViewImpl&) = delete;
+
+ // Create a new CefScrollView instance. |delegate| may be nullptr.
+ static CefRefPtr<CefScrollViewImpl> Create(
+ CefRefPtr<CefViewDelegate> delegate);
+
+ // CefScrollView methods:
+ CefRefPtr<CefScrollView> AsScrollView() override { return this; }
+ void SetContentView(CefRefPtr<CefView> view) override;
+ CefRefPtr<CefView> GetContentView() override;
+ CefRect GetVisibleContentRect() override;
+ bool HasHorizontalScrollbar() override;
+ int GetHorizontalScrollbarHeight() override;
+ bool HasVerticalScrollbar() override;
+ int GetVerticalScrollbarWidth() override;
+
+ // CefViewAdapter methods:
+ std::string GetDebugType() override { return "ScrollView"; }
+ void GetDebugInfo(base::Value::Dict* info, bool include_children) override;
+
+ private:
+ // Create a new implementation object.
+ // Always call Initialize() after creation.
+ // |delegate| may be nullptr.
+ CefScrollViewImpl(CefRefPtr<CefViewDelegate> delegate);
+
+ // CefViewImpl methods:
+ CefScrollViewView* CreateRootView() override;
+ void InitializeRootView() override;
+
+ IMPLEMENT_REFCOUNTING_DELETE_ON_UIT(CefScrollViewImpl);
+};
+
+#endif // CEF_LIBCEF_BROWSER_VIEWS_SCROLL_VIEW_IMPL_H_
diff --git a/libcef/browser/views/scroll_view_view.cc b/libcef/browser/views/scroll_view_view.cc
new file mode 100644
index 00000000..39ac25cc
--- /dev/null
+++ b/libcef/browser/views/scroll_view_view.cc
@@ -0,0 +1,8 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#include "libcef/browser/views/scroll_view_view.h"
+
+CefScrollViewView::CefScrollViewView(CefViewDelegate* cef_delegate)
+ : ParentClass(cef_delegate) {}
diff --git a/libcef/browser/views/scroll_view_view.h b/libcef/browser/views/scroll_view_view.h
new file mode 100644
index 00000000..89d7e5d5
--- /dev/null
+++ b/libcef/browser/views/scroll_view_view.h
@@ -0,0 +1,27 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_VIEWS_SCROLL_VIEW_VIEW_H_
+#define CEF_LIBCEF_BROWSER_VIEWS_SCROLL_VIEW_VIEW_H_
+#pragma once
+
+#include "include/views/cef_panel_delegate.h"
+
+#include "libcef/browser/views/view_view.h"
+
+#include "ui/views/controls/scroll_view.h"
+
+class CefScrollViewView
+ : public CefViewView<views::ScrollView, CefViewDelegate> {
+ public:
+ using ParentClass = CefViewView<views::ScrollView, CefViewDelegate>;
+
+ // |cef_delegate| may be nullptr.
+ explicit CefScrollViewView(CefViewDelegate* cef_delegate);
+
+ CefScrollViewView(const CefScrollViewView&) = delete;
+ CefScrollViewView& operator=(const CefScrollViewView&) = delete;
+};
+
+#endif // CEF_LIBCEF_BROWSER_VIEWS_SCROLL_VIEW_VIEW_H_
diff --git a/libcef/browser/views/textfield_impl.cc b/libcef/browser/views/textfield_impl.cc
new file mode 100644
index 00000000..f1afd97d
--- /dev/null
+++ b/libcef/browser/views/textfield_impl.cc
@@ -0,0 +1,234 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#include "libcef/browser/views/textfield_impl.h"
+
+#include "libcef/browser/thread_util.h"
+
+namespace {
+static int CefCommandIdToChromeId(cef_text_field_commands_t command_id) {
+ switch (command_id) {
+ case cef_text_field_commands_t::CEF_TFC_CUT:
+ return views::Textfield::kCut;
+ case cef_text_field_commands_t::CEF_TFC_COPY:
+ return views::Textfield::kCopy;
+ case cef_text_field_commands_t::CEF_TFC_PASTE:
+ return views::Textfield::kPaste;
+ case cef_text_field_commands_t::CEF_TFC_UNDO:
+ return views::Textfield::kUndo;
+ case cef_text_field_commands_t::CEF_TFC_DELETE:
+ return views::Textfield::kDelete;
+ case cef_text_field_commands_t::CEF_TFC_SELECT_ALL:
+ return views::Textfield::kSelectAll;
+ }
+}
+} // namespace
+
+// static
+CefRefPtr<CefTextfield> CefTextfield::CreateTextfield(
+ CefRefPtr<CefTextfieldDelegate> delegate) {
+ return CefTextfieldImpl::Create(delegate);
+}
+
+// static
+CefRefPtr<CefTextfieldImpl> CefTextfieldImpl::Create(
+ CefRefPtr<CefTextfieldDelegate> delegate) {
+ CEF_REQUIRE_UIT_RETURN(nullptr);
+ CefRefPtr<CefTextfieldImpl> textfield = new CefTextfieldImpl(delegate);
+ textfield->Initialize();
+ return textfield;
+}
+
+void CefTextfieldImpl::SetPasswordInput(bool password_input) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ root_view()->SetTextInputType(password_input ? ui::TEXT_INPUT_TYPE_PASSWORD
+ : ui::TEXT_INPUT_TYPE_TEXT);
+}
+
+bool CefTextfieldImpl::IsPasswordInput() {
+ CEF_REQUIRE_VALID_RETURN(false);
+ return (root_view()->GetTextInputType() == ui::TEXT_INPUT_TYPE_PASSWORD);
+}
+
+void CefTextfieldImpl::SetReadOnly(bool read_only) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ root_view()->SetReadOnly(read_only);
+}
+
+bool CefTextfieldImpl::IsReadOnly() {
+ CEF_REQUIRE_VALID_RETURN(false);
+ return root_view()->GetReadOnly();
+}
+
+CefString CefTextfieldImpl::GetText() {
+ CEF_REQUIRE_VALID_RETURN(CefString());
+ return root_view()->GetText();
+}
+
+void CefTextfieldImpl::SetText(const CefString& text) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ root_view()->SetText(text);
+}
+
+void CefTextfieldImpl::AppendText(const CefString& text) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ root_view()->AppendText(text);
+}
+
+void CefTextfieldImpl::InsertOrReplaceText(const CefString& text) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ root_view()->InsertOrReplaceText(text);
+}
+
+bool CefTextfieldImpl::HasSelection() {
+ CEF_REQUIRE_VALID_RETURN(false);
+ return root_view()->HasSelection();
+}
+
+CefString CefTextfieldImpl::GetSelectedText() {
+ CEF_REQUIRE_VALID_RETURN(CefString());
+ return root_view()->GetSelectedText();
+}
+
+void CefTextfieldImpl::SelectAll(bool reversed) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ root_view()->SelectAll(reversed);
+}
+
+void CefTextfieldImpl::ClearSelection() {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ root_view()->ClearSelection();
+}
+
+CefRange CefTextfieldImpl::GetSelectedRange() {
+ CEF_REQUIRE_VALID_RETURN(CefRange());
+ const gfx::Range& range = root_view()->GetSelectedRange();
+ return CefRange(range.start(), range.end());
+}
+
+void CefTextfieldImpl::SelectRange(const CefRange& range) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ root_view()->SetSelectedRange(gfx::Range(range.from, range.to));
+}
+
+size_t CefTextfieldImpl::GetCursorPosition() {
+ CEF_REQUIRE_VALID_RETURN(0U);
+ return root_view()->GetCursorPosition();
+}
+
+void CefTextfieldImpl::SetTextColor(cef_color_t color) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ root_view()->SetTextColor(color);
+}
+
+cef_color_t CefTextfieldImpl::GetTextColor() {
+ CEF_REQUIRE_VALID_RETURN(0U);
+ return root_view()->GetTextColor();
+}
+
+void CefTextfieldImpl::SetSelectionTextColor(cef_color_t color) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ root_view()->SetSelectionTextColor(color);
+}
+
+cef_color_t CefTextfieldImpl::GetSelectionTextColor() {
+ CEF_REQUIRE_VALID_RETURN(0U);
+ return root_view()->GetSelectionTextColor();
+}
+
+void CefTextfieldImpl::SetSelectionBackgroundColor(cef_color_t color) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ root_view()->SetSelectionBackgroundColor(color);
+}
+
+cef_color_t CefTextfieldImpl::GetSelectionBackgroundColor() {
+ CEF_REQUIRE_VALID_RETURN(0U);
+ return root_view()->GetSelectionBackgroundColor();
+}
+
+void CefTextfieldImpl::SetFontList(const CefString& font_list) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ root_view()->SetFontList(gfx::FontList(font_list));
+}
+
+void CefTextfieldImpl::ApplyTextColor(cef_color_t color,
+ const CefRange& range) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ if (range.from == range.to) {
+ root_view()->SetColor(color);
+ } else {
+ root_view()->ApplyColor(color, gfx::Range(range.from, range.to));
+ }
+}
+
+void CefTextfieldImpl::ApplyTextStyle(cef_text_style_t style,
+ bool add,
+ const CefRange& range) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ if (range.from == range.to) {
+ root_view()->SetStyle(static_cast<gfx::TextStyle>(style), add);
+ } else {
+ root_view()->ApplyStyle(static_cast<gfx::TextStyle>(style), add,
+ gfx::Range(range.from, range.to));
+ }
+}
+
+bool CefTextfieldImpl::IsCommandEnabled(cef_text_field_commands_t command_id) {
+ CEF_REQUIRE_VALID_RETURN(false);
+ return root_view()->IsCommandIdEnabled(CefCommandIdToChromeId(command_id));
+}
+
+void CefTextfieldImpl::ExecuteCommand(cef_text_field_commands_t command_id) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ if (root_view()->IsCommandIdEnabled(CefCommandIdToChromeId(command_id))) {
+ root_view()->ExecuteCommand(CefCommandIdToChromeId(command_id),
+ ui::EF_NONE);
+ }
+}
+
+void CefTextfieldImpl::ClearEditHistory() {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ root_view()->ClearEditHistory();
+}
+
+void CefTextfieldImpl::SetPlaceholderText(const CefString& text) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ root_view()->SetPlaceholderText(text);
+}
+
+CefString CefTextfieldImpl::GetPlaceholderText() {
+ CEF_REQUIRE_VALID_RETURN(CefString());
+ return root_view()->GetPlaceholderText();
+}
+
+void CefTextfieldImpl::SetPlaceholderTextColor(cef_color_t color) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ root_view()->set_placeholder_text_color(color);
+}
+
+void CefTextfieldImpl::SetBackgroundColor(cef_color_t color) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ root_view()->SetBackgroundColor(color);
+}
+
+cef_color_t CefTextfieldImpl::GetBackgroundColor() {
+ CEF_REQUIRE_VALID_RETURN(0U);
+ return root_view()->GetBackgroundColor();
+}
+
+void CefTextfieldImpl::SetAccessibleName(const CefString& name) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ root_view()->SetAccessibleName(name);
+}
+
+CefTextfieldImpl::CefTextfieldImpl(CefRefPtr<CefTextfieldDelegate> delegate)
+ : ParentClass(delegate) {}
+
+CefTextfieldView* CefTextfieldImpl::CreateRootView() {
+ return new CefTextfieldView(delegate());
+}
+
+void CefTextfieldImpl::InitializeRootView() {
+ static_cast<CefTextfieldView*>(root_view())->Initialize();
+}
diff --git a/libcef/browser/views/textfield_impl.h b/libcef/browser/views/textfield_impl.h
new file mode 100644
index 00000000..8a5ac406
--- /dev/null
+++ b/libcef/browser/views/textfield_impl.h
@@ -0,0 +1,84 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_VIEWS_TEXTFIELD_IMPL_H_
+#define CEF_LIBCEF_BROWSER_VIEWS_TEXTFIELD_IMPL_H_
+#pragma once
+
+#include "include/views/cef_textfield.h"
+#include "include/views/cef_textfield_delegate.h"
+
+#include "libcef/browser/views/textfield_view.h"
+#include "libcef/browser/views/view_impl.h"
+
+class CefTextfieldImpl
+ : public CefViewImpl<CefTextfieldView, CefTextfield, CefTextfieldDelegate> {
+ public:
+ using ParentClass =
+ CefViewImpl<CefTextfieldView, CefTextfield, CefTextfieldDelegate>;
+
+ CefTextfieldImpl(const CefTextfieldImpl&) = delete;
+ CefTextfieldImpl& operator=(const CefTextfieldImpl&) = delete;
+
+ // Create a new CefTextfield instance. |delegate| may be nullptr.
+ static CefRefPtr<CefTextfieldImpl> Create(
+ CefRefPtr<CefTextfieldDelegate> delegate);
+
+ // CefTextfield methods:
+ void SetPasswordInput(bool password_input) override;
+ bool IsPasswordInput() override;
+ void SetReadOnly(bool read_only) override;
+ bool IsReadOnly() override;
+ CefString GetText() override;
+ void SetText(const CefString& text) override;
+ void AppendText(const CefString& text) override;
+ void InsertOrReplaceText(const CefString& text) override;
+ bool HasSelection() override;
+ CefString GetSelectedText() override;
+ void SelectAll(bool reversed) override;
+ void ClearSelection() override;
+ CefRange GetSelectedRange() override;
+ void SelectRange(const CefRange& range) override;
+ size_t GetCursorPosition() override;
+ void SetTextColor(cef_color_t color) override;
+ cef_color_t GetTextColor() override;
+ void SetSelectionTextColor(cef_color_t color) override;
+ cef_color_t GetSelectionTextColor() override;
+ void SetSelectionBackgroundColor(cef_color_t color) override;
+ cef_color_t GetSelectionBackgroundColor() override;
+ void SetFontList(const CefString& font_list) override;
+ void ApplyTextColor(cef_color_t color, const CefRange& range) override;
+ void ApplyTextStyle(cef_text_style_t style,
+ bool add,
+ const CefRange& range) override;
+ bool IsCommandEnabled(cef_text_field_commands_t command_id) override;
+ void ExecuteCommand(cef_text_field_commands_t command_id) override;
+ void ClearEditHistory() override;
+ void SetPlaceholderText(const CefString& text) override;
+ CefString GetPlaceholderText() override;
+ void SetPlaceholderTextColor(cef_color_t color) override;
+ void SetAccessibleName(const CefString& name) override;
+
+ // CefView methods:
+ CefRefPtr<CefTextfield> AsTextfield() override { return this; }
+ void SetBackgroundColor(cef_color_t color) override;
+ cef_color_t GetBackgroundColor() override;
+
+ // CefViewAdapter methods:
+ std::string GetDebugType() override { return "Textfield"; }
+
+ private:
+ // Create a new implementation object.
+ // Always call Initialize() after creation.
+ // |delegate| may be nullptr.
+ explicit CefTextfieldImpl(CefRefPtr<CefTextfieldDelegate> delegate);
+
+ // CefViewImpl methods:
+ CefTextfieldView* CreateRootView() override;
+ void InitializeRootView() override;
+
+ IMPLEMENT_REFCOUNTING_DELETE_ON_UIT(CefTextfieldImpl);
+};
+
+#endif // CEF_LIBCEF_BROWSER_VIEWS_TEXTFIELD_IMPL_H_
diff --git a/libcef/browser/views/textfield_view.cc b/libcef/browser/views/textfield_view.cc
new file mode 100644
index 00000000..103d108a
--- /dev/null
+++ b/libcef/browser/views/textfield_view.cc
@@ -0,0 +1,42 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#include "libcef/browser/views/textfield_view.h"
+
+#include "libcef/browser/browser_util.h"
+
+CefTextfieldView::CefTextfieldView(CefTextfieldDelegate* cef_delegate)
+ : ParentClass(cef_delegate) {
+ set_controller(this);
+}
+
+void CefTextfieldView::Initialize() {
+ ParentClass::Initialize();
+
+ // Use our defaults instead of the Views framework defaults.
+ SetFontList(gfx::FontList(view_util::kDefaultFontList));
+}
+
+bool CefTextfieldView::HandleKeyEvent(views::Textfield* sender,
+ const ui::KeyEvent& key_event) {
+ DCHECK_EQ(sender, this);
+
+ if (!cef_delegate()) {
+ return false;
+ }
+
+ CefKeyEvent cef_key_event;
+ if (!browser_util::GetCefKeyEvent(key_event, cef_key_event)) {
+ return false;
+ }
+
+ return cef_delegate()->OnKeyEvent(GetCefTextfield(), cef_key_event);
+}
+
+void CefTextfieldView::OnAfterUserAction(views::Textfield* sender) {
+ DCHECK_EQ(sender, this);
+ if (cef_delegate()) {
+ cef_delegate()->OnAfterUserAction(GetCefTextfield());
+ }
+}
diff --git a/libcef/browser/views/textfield_view.h b/libcef/browser/views/textfield_view.h
new file mode 100644
index 00000000..f4e4f5ee
--- /dev/null
+++ b/libcef/browser/views/textfield_view.h
@@ -0,0 +1,45 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_VIEWS_TEXTFIELD_VIEW_H_
+#define CEF_LIBCEF_BROWSER_VIEWS_TEXTFIELD_VIEW_H_
+#pragma once
+
+#include "include/views/cef_textfield_delegate.h"
+
+#include "include/views/cef_textfield.h"
+#include "libcef/browser/views/view_view.h"
+
+#include "ui/views/controls/textfield/textfield.h"
+#include "ui/views/controls/textfield/textfield_controller.h"
+
+class CefTextfieldView
+ : public CefViewView<views::Textfield, CefTextfieldDelegate>,
+ public views::TextfieldController {
+ public:
+ using ParentClass = CefViewView<views::Textfield, CefTextfieldDelegate>;
+
+ // |cef_delegate| may be nullptr.
+ explicit CefTextfieldView(CefTextfieldDelegate* cef_delegate);
+
+ CefTextfieldView(const CefTextfieldView&) = delete;
+ CefTextfieldView& operator=(const CefTextfieldView&) = delete;
+
+ void Initialize() override;
+
+ // Returns the CefTextfield associated with this view. See comments on
+ // CefViewView::GetCefView.
+ CefRefPtr<CefTextfield> GetCefTextfield() const {
+ CefRefPtr<CefTextfield> textfield = GetCefView()->AsTextfield();
+ DCHECK(textfield);
+ return textfield;
+ }
+
+ // TextfieldController methods:
+ bool HandleKeyEvent(views::Textfield* sender,
+ const ui::KeyEvent& key_event) override;
+ void OnAfterUserAction(views::Textfield* sender) override;
+};
+
+#endif // CEF_LIBCEF_BROWSER_VIEWS_TEXTFIELD_VIEW_H_
diff --git a/libcef/browser/views/view_adapter.cc b/libcef/browser/views/view_adapter.cc
new file mode 100644
index 00000000..5c325738
--- /dev/null
+++ b/libcef/browser/views/view_adapter.cc
@@ -0,0 +1,60 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#include "libcef/browser/views/view_adapter.h"
+
+#include "libcef/browser/chrome/views/toolbar_view_impl.h"
+#include "libcef/browser/views/basic_label_button_impl.h"
+#include "libcef/browser/views/basic_panel_impl.h"
+#include "libcef/browser/views/browser_view_impl.h"
+#include "libcef/browser/views/menu_button_impl.h"
+#include "libcef/browser/views/scroll_view_impl.h"
+#include "libcef/browser/views/textfield_impl.h"
+#include "libcef/browser/views/view_util.h"
+#include "libcef/browser/views/window_impl.h"
+
+// static
+CefViewAdapter* CefViewAdapter::GetFor(CefRefPtr<CefView> view) {
+ CefViewAdapter* adapter = nullptr;
+ if (view->AsBrowserView()) {
+ adapter = static_cast<CefBrowserViewImpl*>(view->AsBrowserView().get());
+ } else if (view->AsButton()) {
+ CefRefPtr<CefButton> button = view->AsButton();
+ if (button->AsLabelButton()) {
+ CefRefPtr<CefLabelButton> label_button = button->AsLabelButton();
+ if (label_button->AsMenuButton()) {
+ adapter =
+ static_cast<CefMenuButtonImpl*>(label_button->AsMenuButton().get());
+ } else {
+ adapter = static_cast<CefBasicLabelButtonImpl*>(label_button.get());
+ }
+ }
+ } else if (view->AsPanel()) {
+ CefRefPtr<CefPanel> panel = view->AsPanel();
+ if (panel->AsWindow()) {
+ adapter = static_cast<CefWindowImpl*>(panel->AsWindow().get());
+ } else {
+ adapter = static_cast<CefBasicPanelImpl*>(panel.get());
+ }
+ } else if (view->AsScrollView()) {
+ adapter = static_cast<CefScrollViewImpl*>(view->AsScrollView().get());
+ } else if (view->AsTextfield()) {
+ adapter = static_cast<CefTextfieldImpl*>(view->AsTextfield().get());
+ } else if (view->GetTypeString().ToString() ==
+ CefToolbarViewImpl::kTypeString) {
+ adapter = static_cast<CefToolbarViewImpl*>(view.get());
+ }
+
+ DCHECK(adapter);
+ return adapter;
+}
+
+// static
+CefViewAdapter* CefViewAdapter::GetFor(views::View* view) {
+ CefRefPtr<CefView> cef_view = view_util::GetFor(view, false);
+ if (cef_view) {
+ return GetFor(cef_view);
+ }
+ return nullptr;
+}
diff --git a/libcef/browser/views/view_adapter.h b/libcef/browser/views/view_adapter.h
new file mode 100644
index 00000000..958be7f7
--- /dev/null
+++ b/libcef/browser/views/view_adapter.h
@@ -0,0 +1,55 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_VIEWS_VIEW_ADAPTER_H_
+#define CEF_LIBCEF_BROWSER_VIEWS_VIEW_ADAPTER_H_
+#pragma once
+
+#include "include/views/cef_view.h"
+
+#include "base/values.h"
+
+namespace views {
+class View;
+}
+
+// Exposes a common interface from all CefView implementation objects to
+// simplify the view_util implementation. See comments in view_impl.h for a
+// usage overview.
+class CefViewAdapter {
+ public:
+ CefViewAdapter() {}
+
+ // Returns the CefViewAdapter for the specified |view|.
+ static CefViewAdapter* GetFor(CefRefPtr<CefView> view);
+ static CefViewAdapter* GetFor(views::View* view);
+
+ // Returns the underlying views::View object. Does not transfer ownership.
+ virtual views::View* Get() const = 0;
+
+ // Pass ownership of the underlying views::View object to the caller. This
+ // object keeps an unowned reference to the views::View object. This is called
+ // when the views::View is parented to another views::View.
+ virtual std::unique_ptr<views::View> PassOwnership() = 0;
+
+ // Resume ownership of the underlying views::View object. This is called when
+ // the views::View is no longer parented to another views::View.
+ virtual void ResumeOwnership() = 0;
+
+ // Release all references to the views::View object. This is called when the
+ // views::View is deleted after being parented to another views::View.
+ virtual void Detach() = 0;
+
+ // Override this method to provide a string representation of the View type.
+ // Only implement this method in concrete classes.
+ virtual std::string GetDebugType() = 0;
+
+ // Override this method to provide debug info specific to the View type.
+ virtual void GetDebugInfo(base::Value::Dict* info, bool include_children) = 0;
+
+ protected:
+ virtual ~CefViewAdapter() {}
+};
+
+#endif // CEF_LIBCEF_BROWSER_VIEWS_VIEW_ADAPTER_H_
diff --git a/libcef/browser/views/view_impl.h b/libcef/browser/views/view_impl.h
new file mode 100644
index 00000000..d9e105d8
--- /dev/null
+++ b/libcef/browser/views/view_impl.h
@@ -0,0 +1,760 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_VIEWS_VIEW_IMPL_H_
+#define CEF_LIBCEF_BROWSER_VIEWS_VIEW_IMPL_H_
+#pragma once
+
+// CEF exposes views framework functionality via a hierarchy of CefView and
+// related objects. While the goal is to accurately represent views framework
+// capabilities there is not always a direct 1:1 mapping between the CEF
+// implementation and the underlying views implementation. Certain liberties
+// have been taken with the CEF API design to clarify the user experience.
+//
+// CEF implementation overview:
+//
+// CefView-derived classes (CefPanel, CefLabelButton, etc.) are implemented
+// using a specialization of the CefViewImpl template. On Initialize() the
+// CefViewImpl object creates an underlying views::View object via the
+// CreateRootView() method. The views::View objects are implemented using a
+// specialization of the CefViewView template. CefViewView extends the
+// views::View-derived class and executes CefViewDelegate-derived callbacks by
+// overriding views::View methods.
+//
+// Example 1: The CefBasicPanelImpl object created via CefPanel::CreatePanel()
+// has the following object hierarchy:
+//
+// CefView => CefPanel =>
+// CefViewImpl<views::View, CefPanel, CefPanelDelegate> =>
+// CefPanelImpl<views::View, CefPanel, CefPanelDelegate> =>
+// CefBasicPanelImpl.
+//
+// And the CefBasicPanelView object created via
+// CefBasicPanelImpl::CreateRootView() has the following object hierarchy:
+//
+// views::View =>
+// CefViewView<views::View, CefPanelDelegate> =>
+// CefPanelView<views::View, CefPanelDelegate> =>
+// CefBasicPanelView.
+//
+// Example 2: In some cases an intermediary type is required to meet CEF
+// template requirements (e.g. CefViewView requires a no-argument constructor).
+// The CefBasicLabelButtonImpl object created via
+// CefLabelButton::CreateLabelButton() has the following object hierarchy:
+//
+// CefView => CefButton => CefLabelButton =>
+// CefViewImpl<views::LabelButton, CefLabelButton, CefButtonDelegate> =>
+// CefButtonImpl<views::LabelButton, CefLabelButton, CefButtonDelegate> =>
+// CefLabelButtonImpl<views::LabelButton, CefLabelButton,
+// CefButtonDelegate> =>
+// CefBasicLabelButtonImpl
+//
+// And the CefBasicLabelButtonView object created via
+// CefBasicLabelButtonImpl::CreateRootView() has the following object hierarchy:
+//
+// views::View => views::Button => views::LabelButton =>
+// LabelButtonEx (used to implement the required no-argument constructor) =>
+// CefViewView<LabelButtonEx, CefButtonDelegate> =>
+// CefButtonView<LabelButtonEx, CefButtonDelegate> =>
+// CefLabelButtonView<LabelButtonEx, CefButtonDelegate> =>
+// CefBasicLabelButtonView.
+//
+//
+// General design considerations:
+//
+// CefView classes are ref-counted whereas views::View classes are not. There
+// is generally a 1:1 relationship between CefView and views::View objects.
+// However, there may be intermediary views::View objects that are not exposed
+// by the CEF layer. For example:
+// - views::Widget creates views::RootView and views::ContentView child objects;
+// - views::ScrollView creates views::ScrollView::Viewport child objects.
+//
+// The views::View class exposes methods that are not applicable for a subset of
+// views implementations. For example:
+// - Calling AddChildView() on a views::LabelButton is unexpected;
+// - Adding a child to a views::ScrollView requires calling the SetContents()
+// method instead of AddChildView().
+// To avoid user confusion CEF introduces a CefPanel type that extends CefView
+// and exposes common child management functionality. Types that allow
+// arbitrary children extend CefPanel instead of CefView.
+//
+//
+// Object ownership considerations:
+//
+// On initial creation the CefViewImpl object owns an underlying views::View
+// object (created by overriding the CreateRootView() method) and the
+// views::View object holds a non-ref-counted reference to the CefViewImpl
+// object. If a CefViewImpl is destroyed (all refs released) then the underlying
+// views::View object is deleted.
+//
+// When a views::View object is parented to another views::View (via
+// CefPanel::AddChildView or similar) the ownership semantics change. The
+// CefViewImpl swaps its owned reference for an unowned reference and the
+// views::View gains a ref-counted reference to the CefViewImpl
+// (CefView::IsAttached() now returns true).
+//
+// When a parent views::View is deleted all child views::Views in the view
+// hierarchy are also deleted (see [1] for exceptions). When this happens the
+// ref-counted CefViewImpl reference held by the views::View is released. The
+// CefViewImpl is deleted if the client kept no references, otherwise the
+// CefViewImpl is marked as invalid (CefView::IsValid() now returns false).
+//
+// When a views::View is removed from the view hierarchy (via
+// CefPanel::RemoveChildView or similar) the initial ownership state is
+// restored. The CefViewImpl regains ownership of the views::View and the
+// ref-counted CefViewImpl reference held by the views::View is released.
+//
+// The relationship between CefViewImpl and views::View objects is managed using
+// the view_util:: functions. Type conversion is facilitated using the As*()
+// methods exposed by CefView-derived classes and the CefViewAdapter interface
+// implemented by CefViewImpl. See view_util.[cc|h] for implementation details.
+//
+// Some other object types are also tied to views::View lifetime. For example,
+// CefLayout and the underling views::LayoutManager objects are owned by the
+// views::View that they're assigned to. This relationship is managed using the
+// layout_util:: functions in layout_util.[cc|h].
+//
+// [1] By default views::View objects are deleted when the parent views::View
+// object is deleted. However, this behavior can be changed either
+// explicitly by calling set_owned_by_client() or implicitly by using
+// interfaces like WidgetDelegateView (where WidgetDelegate is-a View, and
+// the View is deleted when the native Widget is destroyed). CEF
+// implementations that utilize this behavior must take special care with
+// object ownership management.
+//
+//
+// To implement a new CefView-derived class:
+//
+// 1. Choose a views class to expose.
+// * We'll create a new CefFooBar class which exposes a hypothetical
+// views::FooBar class. The views::FooBar class might look like this:
+//
+// File ui/views/foo_bar.h:
+//
+// namespace views {
+//
+// // FooBar view does a task on child views.
+// class FooBar : public View {
+// public:
+// FooBar();
+//
+// // Do a task.
+// void DoTask();
+// // Called when the task is done.
+// virtual void OnTaskDone();
+//
+// // View methods:
+// void Layout() override; // Implements custom layout of child views.
+// };
+//
+// } // namespace views
+//
+// 2. Determine the existing CefView-derived class that the new view class
+// should extend.
+// * Since in this example CefFooBar can have arbitrary child views we'll
+// have it extend CefPanel.
+//
+// 3. Determine whether the new view class can use an existing delegate class
+// (like CefPanelDelegate) or whether it needs its own delegate class.
+// * Since CefFooBar has an OnTaskDone() callback we'll add a new
+// CefFooBarDelegate class to expose it.
+//
+// 4. Create new header files in the cef/include/views/ directory.
+// * Using existing files as a model, the resulting header contents might
+// look like this:
+//
+// File cef/include/views/cef_foo_bar.h:
+//
+// ///
+// // A FooBar view does a task on child views.
+// ///
+// /*--cef(source=library)--*/
+// class CefFooBar : public CefPanel {
+// public:
+// ///
+// // Create a new FooBar.
+// ///
+// /*--cef(optional_param=delegate)--*/
+// static CefRefPtr<CefFooBar> CreateFooBar(
+// CefRefPtr<CefFooBarDelegate> delegate);
+//
+// ///
+// // Do a task.
+// ///
+// /*--cef()--*/
+// virtual void DoTask() =0;
+// };
+//
+// File cef/include/views/cef_foo_bar_delegate.h:
+//
+// ///
+// // Implement this interface to handle FooBar events.
+// ///
+// /*--cef(source=client)--*/
+// class CefFooBarDelegate : public CefPanelDelegate {
+// public:
+// ///
+// // Called when the task is done.
+// ///
+// /*--cef()--*/
+// virtual void OnTaskDone(CefRefPtr<CefFooBar> foobar) {}
+// };
+//
+// 5. Add an As*() method to the CefView-derived class.
+// * Using existing file contents as a model, make the following changes in
+// cef/include/views/cef_panel.h:
+// * Forward declare the CefFooBar class.
+// * Add a new CefPanel::AsFooBar() method:
+//
+// ///
+// // Returns this Panel as a FooBar or NULL if this is not a FooBar.
+// ///
+// /*--cef()--*/
+// virtual CefRefPtr<CefFooBar> AsFooBar() =0;
+//
+// 6. Add a default implementation for the As*() method to the CefViewImpl-
+// derived class.
+// * Using existing file contents as a model, make the following changes in
+// cef/libcef/browser/views/panel_impl.h:
+// * Include "include/views/cef_foo_bar.h".
+// * Add a default CefPanelImpl::AsFooBar() implementation:
+//
+// CefRefPtr<CefFooBar> AsFooBar() override { return nullptr; }
+//
+// 7. Update the CefViewAdapter::GetFor() method implementation to call the
+// As*() method.
+// * Using existing file contents as a model, make the following changes in
+// cef/libcef/browser/views/view_adapter.cc:
+// * Include "include/views/cef_foo_bar.h".
+// * Call the AsFooBar() method to identify the adapter object:
+//
+// ... if (view->AsPanel()) {
+// CefRefPtr<CefPanel> panel = view->AsPanel();
+// if (panel->AsFooBar()) {
+// adapter = static_cast<CefFooBarImpl*>(panel->AsFooBar().get());
+// } else ...
+// } else ...
+//
+// 8. Implement the CefViewView-derived class.
+// * Using existing files as a model (for example, CefBasicPanelView), create
+// a CefFooBarView class at cef/libcef/browser/views/foo_bar_view.[cc|h].
+// This class:
+// * Extends CefPanelView<views::FooBar, CefFooBarDelegate>.
+// * Overrides the views::FooBar::OnTaskDone method to execute the
+// CefFooBarDelegate::OnTaskDone callback:
+//
+// void CefFooBarView::OnTaskDone() {
+// if (cef_delegate())
+// cef_delegate()->OnTaskDone(GetCefFooBar());
+// }
+//
+// 9. Implement the CefViewImpl-derived class.
+// * Use existing files as a model (for example, CefBasicPanelImpl), create a
+// CefFooBarImpl class at cef/libcef/browser/views/foo_bar_impl.[cc|h].
+// This class:
+// * Extends CefPanelImpl<views::FooBar, CefFooBar, CefFooBarDelegate>.
+// * Implements AsFooBar() to return |this|.
+// * Implements CreateRootView() to return a new CefFooBarView instance.
+// * Implements the CefFooBar::DoTask() method to call
+// views::FooBar::DoTask():
+//
+// void CefFooBarImpl::DoTask() {
+// CEF_REQUIRE_VALID_RETURN_VOID();
+// root_view()->DoTask();
+// }
+//
+// 10. Implement the static method that creates the CefViewImpl-derived object
+// instance.
+// * Use existing files as a model (for example, CefBasicPanelImpl),
+// implement the CefFooBar::CreateFooBar static method in
+// cef/libcef/browser/views/foo_bar_impl.cc. This method:
+// * Creates a new CefFooBarImpl object.
+// * Calls Initialize() on the CefFooBarImpl object.
+// * Returns the CefFooBarImpl object.
+//
+// 11. Add the new source files from #7 and #8 to the 'libcef_static' target in
+// cef.gyp.
+//
+// 12. Update the CEF project files and build.
+// * Run cef/tools/translator.[bat|sh] to update the translation layer for
+// the new/modified classes. This tool needs to be run whenever header
+// files in the cef/include/ directory are changed.
+// * Run cef/cef_create_projects.[bat|sh] to update the Ninja build files.
+// * Build CEF using Ninja.
+//
+
+#include "include/views/cef_browser_view.h"
+#include "include/views/cef_button.h"
+#include "include/views/cef_panel.h"
+#include "include/views/cef_scroll_view.h"
+#include "include/views/cef_textfield.h"
+#include "include/views/cef_view.h"
+
+#include "libcef/browser/thread_util.h"
+#include "libcef/browser/views/view_adapter.h"
+#include "libcef/browser/views/view_util.h"
+
+#include "base/json/json_writer.h"
+#include "base/logging.h"
+#include "base/values.h"
+#include "ui/views/background.h"
+#include "ui/views/border.h"
+#include "ui/views/view.h"
+
+// Helpers for template boiler-plate.
+#define CEF_VIEW_IMPL_T \
+ template <class ViewsViewClass, class CefViewClass, \
+ class CefViewDelegateClass>
+#define CEF_VIEW_IMPL_A ViewsViewClass, CefViewClass, CefViewDelegateClass
+#define CEF_VIEW_IMPL_D CefViewImpl<CEF_VIEW_IMPL_A>
+
+// Base template for implementing CefView-derived classes. See above comments
+// for a usage overview.
+CEF_VIEW_IMPL_T class CefViewImpl : public CefViewAdapter, public CefViewClass {
+ public:
+ // Necessary for the CEF_REQUIRE_VALID_*() macros to compile.
+ using ParentClass = CEF_VIEW_IMPL_D;
+
+ // Returns the content views::View object that should be the target of most
+ // customization actions. May be the root view or a child of the root view.
+ virtual views::View* content_view() const { return root_view(); }
+
+ // Returns the CEF delegate as the derived type which may be nullptr.
+ CefViewDelegateClass* delegate() const { return delegate_.get(); }
+
+ // Returns the root views::View object owned by this CefView.
+ ViewsViewClass* root_view() const { return root_view_ref_; }
+
+ // CefViewAdapter methods:
+ views::View* Get() const override { return root_view(); }
+ std::unique_ptr<views::View> PassOwnership() override {
+ DCHECK(root_view_);
+ return std::move(root_view_);
+ }
+ void ResumeOwnership() override {
+ DCHECK(root_view_ref_);
+ DCHECK(!root_view_);
+ root_view_.reset(root_view_ref_);
+ }
+ void Detach() override {
+ if (root_view_) {
+ root_view_.reset();
+ }
+ root_view_ref_ = nullptr;
+ }
+ void GetDebugInfo(base::Value::Dict* info, bool include_children) override {
+ info->Set("type", GetDebugType());
+ info->Set("id", root_view()->GetID());
+
+ // Use GetBounds() because some subclasses (like CefWindowImpl) override it.
+ const CefRect& bounds = GetBounds();
+ base::Value::Dict bounds_value;
+ bounds_value.Set("x", bounds.x);
+ bounds_value.Set("y", bounds.y);
+ bounds_value.Set("width", bounds.width);
+ bounds_value.Set("height", bounds.height);
+ info->Set("bounds", std::move(bounds_value));
+ }
+
+ // CefView methods. When adding new As*() methods make sure to update
+ // CefViewAdapter::GetFor() in view_adapter.cc.
+ CefRefPtr<CefBrowserView> AsBrowserView() override { return nullptr; }
+ CefRefPtr<CefButton> AsButton() override { return nullptr; }
+ CefRefPtr<CefPanel> AsPanel() override { return nullptr; }
+ CefRefPtr<CefScrollView> AsScrollView() override { return nullptr; }
+ CefRefPtr<CefTextfield> AsTextfield() override { return nullptr; }
+ CefString GetTypeString() override;
+ CefString ToString(bool include_children) override;
+ bool IsValid() override;
+ bool IsAttached() override;
+ bool IsSame(CefRefPtr<CefView> that) override;
+ CefRefPtr<CefViewDelegate> GetDelegate() override;
+ CefRefPtr<CefWindow> GetWindow() override;
+ int GetID() override;
+ void SetID(int id) override;
+ int GetGroupID() override;
+ void SetGroupID(int group_id) override;
+ CefRefPtr<CefView> GetParentView() override;
+ CefRefPtr<CefView> GetViewForID(int id) override;
+ void SetBounds(const CefRect& bounds) override;
+ CefRect GetBounds() override;
+ CefRect GetBoundsInScreen() override;
+ void SetSize(const CefSize& size) override;
+ CefSize GetSize() override;
+ void SetPosition(const CefPoint& position) override;
+ CefPoint GetPosition() override;
+ void SetInsets(const CefInsets& insets) override;
+ CefInsets GetInsets() override;
+ CefSize GetPreferredSize() override;
+ void SizeToPreferredSize() override;
+ CefSize GetMinimumSize() override;
+ CefSize GetMaximumSize() override;
+ int GetHeightForWidth(int width) override;
+ void InvalidateLayout() override;
+ void SetVisible(bool visible) override;
+ bool IsVisible() override;
+ bool IsDrawn() override;
+ void SetEnabled(bool enabled) override;
+ bool IsEnabled() override;
+ void SetFocusable(bool focusable) override;
+ bool IsFocusable() override;
+ bool IsAccessibilityFocusable() override;
+ void RequestFocus() override;
+ void SetBackgroundColor(cef_color_t color) override;
+ cef_color_t GetBackgroundColor() override;
+ bool ConvertPointToScreen(CefPoint& point) override;
+ bool ConvertPointFromScreen(CefPoint& point) override;
+ bool ConvertPointToWindow(CefPoint& point) override;
+ bool ConvertPointFromWindow(CefPoint& point) override;
+ bool ConvertPointToView(CefRefPtr<CefView> view, CefPoint& point) override;
+ bool ConvertPointFromView(CefRefPtr<CefView> view, CefPoint& point) override;
+
+ protected:
+ // Create a new implementation object.
+ // Always call Initialize() after creation.
+ // |delegate| may be nullptr.
+ explicit CefViewImpl(CefRefPtr<CefViewDelegateClass> delegate)
+ : delegate_(delegate), root_view_ref_(nullptr) {}
+
+ // Initialize this object.
+ virtual void Initialize() {
+ root_view_.reset(CreateRootView());
+ DCHECK(root_view_.get());
+ root_view_ref_ = root_view_.get();
+ view_util::Register(this);
+ InitializeRootView();
+ }
+
+ // Create the root views::View object.
+ virtual ViewsViewClass* CreateRootView() = 0;
+
+ // Perform required initialization of the root_view() object created by
+ // CreateRootView(). Called after this object has been registered.
+ virtual void InitializeRootView() = 0;
+
+ private:
+ CefRefPtr<CefViewDelegateClass> delegate_;
+
+ // Owned reference to the views::View wrapped by this object. Will be nullptr
+ // before the View is created and after the View's ownership is transferred.
+ std::unique_ptr<ViewsViewClass> root_view_;
+
+ // Unowned reference to the views::View wrapped by this object. Will be
+ // nullptr before the View is created and after the View is destroyed.
+ ViewsViewClass* root_view_ref_;
+};
+
+CEF_VIEW_IMPL_T CefString CEF_VIEW_IMPL_D::GetTypeString() {
+ CEF_REQUIRE_UIT_RETURN(CefString());
+ return GetDebugType();
+}
+
+CEF_VIEW_IMPL_T CefString CEF_VIEW_IMPL_D::ToString(bool include_children) {
+ CEF_REQUIRE_UIT_RETURN(CefString());
+ base::Value::Dict info;
+ if (IsValid()) {
+ GetDebugInfo(&info, include_children);
+ } else {
+ info.Set("type", GetDebugType());
+ }
+
+ std::string json_string;
+ base::JSONWriter::WriteWithOptions(info, 0, &json_string);
+ return json_string;
+}
+
+CEF_VIEW_IMPL_T bool CEF_VIEW_IMPL_D::IsValid() {
+ CEF_REQUIRE_UIT_RETURN(false);
+ return !!root_view_ref_;
+}
+
+CEF_VIEW_IMPL_T bool CEF_VIEW_IMPL_D::IsAttached() {
+ CEF_REQUIRE_UIT_RETURN(false);
+ return !root_view_.get();
+}
+
+CEF_VIEW_IMPL_T bool CEF_VIEW_IMPL_D::IsSame(CefRefPtr<CefView> that) {
+ CEF_REQUIRE_UIT_RETURN(false);
+ CefViewImpl* that_impl = static_cast<CefViewImpl*>(that.get());
+ if (!that_impl) {
+ return false;
+ }
+ return this == that_impl;
+}
+
+CEF_VIEW_IMPL_T CefRefPtr<CefViewDelegate> CEF_VIEW_IMPL_D::GetDelegate() {
+ CEF_REQUIRE_UIT_RETURN(nullptr);
+ return delegate();
+}
+
+CEF_VIEW_IMPL_T CefRefPtr<CefWindow> CEF_VIEW_IMPL_D::GetWindow() {
+ CEF_REQUIRE_UIT_RETURN(nullptr);
+ if (root_view()) {
+ return view_util::GetWindowFor(root_view()->GetWidget());
+ }
+ return nullptr;
+}
+
+CEF_VIEW_IMPL_T int CEF_VIEW_IMPL_D::GetID() {
+ CEF_REQUIRE_VALID_RETURN(0);
+ return root_view()->GetID();
+}
+
+CEF_VIEW_IMPL_T void CEF_VIEW_IMPL_D::SetID(int id) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ root_view()->SetID(id);
+}
+
+CEF_VIEW_IMPL_T int CEF_VIEW_IMPL_D::GetGroupID() {
+ CEF_REQUIRE_VALID_RETURN(0);
+ return root_view()->GetGroup();
+}
+
+CEF_VIEW_IMPL_T void CEF_VIEW_IMPL_D::SetGroupID(int group_id) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ if (root_view()->GetGroup() != -1) {
+ return;
+ }
+ root_view()->SetGroup(group_id);
+}
+
+CEF_VIEW_IMPL_T CefRefPtr<CefView> CEF_VIEW_IMPL_D::GetParentView() {
+ CEF_REQUIRE_VALID_RETURN(nullptr);
+ views::View* view = root_view()->parent();
+ if (!view) {
+ return nullptr;
+ }
+ return view_util::GetFor(view, true);
+}
+
+CEF_VIEW_IMPL_T CefRefPtr<CefView> CEF_VIEW_IMPL_D::GetViewForID(int id) {
+ CEF_REQUIRE_VALID_RETURN(nullptr);
+ views::View* view = root_view()->GetViewByID(id);
+ if (!view) {
+ return nullptr;
+ }
+ return view_util::GetFor(view, true);
+}
+
+CEF_VIEW_IMPL_T void CEF_VIEW_IMPL_D::SetBounds(const CefRect& bounds) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ root_view()->SetBoundsRect(
+ gfx::Rect(bounds.x, bounds.y, bounds.width, bounds.height));
+}
+
+CEF_VIEW_IMPL_T CefRect CEF_VIEW_IMPL_D::GetBounds() {
+ CEF_REQUIRE_VALID_RETURN(CefRect());
+ const gfx::Rect& bounds = root_view()->bounds();
+ return CefRect(bounds.x(), bounds.y(), bounds.width(), bounds.height());
+}
+
+CEF_VIEW_IMPL_T CefRect CEF_VIEW_IMPL_D::GetBoundsInScreen() {
+ CEF_REQUIRE_VALID_RETURN(CefRect());
+ const gfx::Rect& bounds = root_view()->GetBoundsInScreen();
+ return CefRect(bounds.x(), bounds.y(), bounds.width(), bounds.height());
+}
+
+CEF_VIEW_IMPL_T void CEF_VIEW_IMPL_D::SetSize(const CefSize& size) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ root_view()->SetSize(gfx::Size(size.width, size.height));
+}
+
+CEF_VIEW_IMPL_T CefSize CEF_VIEW_IMPL_D::GetSize() {
+ CEF_REQUIRE_VALID_RETURN(CefSize());
+ // Call GetBounds() since child classes may override it.
+ const CefRect& bounds = GetBounds();
+ return CefSize(bounds.width, bounds.height);
+}
+
+CEF_VIEW_IMPL_T void CEF_VIEW_IMPL_D::SetPosition(const CefPoint& position) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ root_view()->SetPosition(gfx::Point(position.x, position.y));
+}
+
+CEF_VIEW_IMPL_T CefPoint CEF_VIEW_IMPL_D::GetPosition() {
+ CEF_REQUIRE_VALID_RETURN(CefPoint());
+ // Call GetBounds() since child classes may override it.
+ const CefRect& bounds = GetBounds();
+ return CefPoint(bounds.x, bounds.y);
+}
+
+CEF_VIEW_IMPL_T void CEF_VIEW_IMPL_D::SetInsets(const CefInsets& insets) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ const gfx::Insets& gfx_insets =
+ gfx::Insets::TLBR(insets.top, insets.left, insets.bottom, insets.right);
+ root_view()->SetBorder(
+ gfx_insets.IsEmpty() ? nullptr : views::CreateEmptyBorder(gfx_insets));
+}
+
+CEF_VIEW_IMPL_T CefInsets CEF_VIEW_IMPL_D::GetInsets() {
+ CEF_REQUIRE_VALID_RETURN(CefInsets());
+ const auto insets = root_view()->GetInsets();
+ return CefInsets(insets.top(), insets.left(), insets.bottom(),
+ insets.right());
+}
+
+CEF_VIEW_IMPL_T CefSize CEF_VIEW_IMPL_D::GetPreferredSize() {
+ CEF_REQUIRE_VALID_RETURN(CefSize());
+ const gfx::Size& size = root_view()->GetPreferredSize();
+ return CefSize(size.width(), size.height());
+}
+
+CEF_VIEW_IMPL_T void CEF_VIEW_IMPL_D::SizeToPreferredSize() {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ root_view()->SizeToPreferredSize();
+}
+
+CEF_VIEW_IMPL_T CefSize CEF_VIEW_IMPL_D::GetMinimumSize() {
+ CEF_REQUIRE_VALID_RETURN(CefSize());
+ const gfx::Size& size = root_view()->GetMinimumSize();
+ return CefSize(size.width(), size.height());
+}
+
+CEF_VIEW_IMPL_T CefSize CEF_VIEW_IMPL_D::GetMaximumSize() {
+ CEF_REQUIRE_VALID_RETURN(CefSize());
+ const gfx::Size& size = root_view()->GetMaximumSize();
+ return CefSize(size.width(), size.height());
+}
+
+CEF_VIEW_IMPL_T int CEF_VIEW_IMPL_D::GetHeightForWidth(int width) {
+ CEF_REQUIRE_VALID_RETURN(0);
+ return root_view()->GetHeightForWidth(width);
+}
+
+CEF_VIEW_IMPL_T void CEF_VIEW_IMPL_D::InvalidateLayout() {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ root_view()->InvalidateLayout();
+}
+
+CEF_VIEW_IMPL_T void CEF_VIEW_IMPL_D::SetVisible(bool visible) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ root_view()->SetVisible(visible);
+}
+
+CEF_VIEW_IMPL_T bool CEF_VIEW_IMPL_D::IsVisible() {
+ CEF_REQUIRE_VALID_RETURN(false);
+ return root_view()->GetVisible();
+}
+
+CEF_VIEW_IMPL_T bool CEF_VIEW_IMPL_D::IsDrawn() {
+ CEF_REQUIRE_VALID_RETURN(false);
+ return root_view()->IsDrawn();
+}
+
+CEF_VIEW_IMPL_T void CEF_VIEW_IMPL_D::SetEnabled(bool enabled) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ root_view()->SetEnabled(enabled);
+}
+
+CEF_VIEW_IMPL_T bool CEF_VIEW_IMPL_D::IsEnabled() {
+ CEF_REQUIRE_VALID_RETURN(false);
+ return root_view()->GetEnabled();
+}
+
+CEF_VIEW_IMPL_T void CEF_VIEW_IMPL_D::SetFocusable(bool focusable) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ root_view()->SetFocusBehavior(focusable ? views::View::FocusBehavior::ALWAYS
+ : views::View::FocusBehavior::NEVER);
+}
+
+CEF_VIEW_IMPL_T bool CEF_VIEW_IMPL_D::IsFocusable() {
+ CEF_REQUIRE_VALID_RETURN(false);
+ return root_view()->IsFocusable();
+}
+
+CEF_VIEW_IMPL_T bool CEF_VIEW_IMPL_D::IsAccessibilityFocusable() {
+ CEF_REQUIRE_VALID_RETURN(false);
+ return root_view()->IsAccessibilityFocusable();
+}
+
+CEF_VIEW_IMPL_T void CEF_VIEW_IMPL_D::RequestFocus() {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ root_view()->RequestFocus();
+}
+
+CEF_VIEW_IMPL_T void CEF_VIEW_IMPL_D::SetBackgroundColor(cef_color_t color) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ content_view()->SetBackground(views::CreateSolidBackground(color));
+}
+
+CEF_VIEW_IMPL_T cef_color_t CEF_VIEW_IMPL_D::GetBackgroundColor() {
+ CEF_REQUIRE_VALID_RETURN(0U);
+ return content_view()->background()->get_color();
+}
+
+CEF_VIEW_IMPL_T bool CEF_VIEW_IMPL_D::ConvertPointToScreen(CefPoint& point) {
+ CEF_REQUIRE_VALID_RETURN(false);
+ gfx::Point gfx_point = gfx::Point(point.x, point.y);
+ if (!view_util::ConvertPointToScreen(root_view(), &gfx_point, false)) {
+ return false;
+ }
+ point = CefPoint(gfx_point.x(), gfx_point.y());
+ return true;
+}
+
+CEF_VIEW_IMPL_T bool CEF_VIEW_IMPL_D::ConvertPointFromScreen(CefPoint& point) {
+ CEF_REQUIRE_VALID_RETURN(false);
+ gfx::Point gfx_point = gfx::Point(point.x, point.y);
+ if (!view_util::ConvertPointFromScreen(root_view(), &gfx_point, false)) {
+ return false;
+ }
+ point = CefPoint(gfx_point.x(), gfx_point.y());
+ return true;
+}
+
+CEF_VIEW_IMPL_T bool CEF_VIEW_IMPL_D::ConvertPointToWindow(CefPoint& point) {
+ CEF_REQUIRE_VALID_RETURN(false);
+ gfx::Point gfx_point = gfx::Point(point.x, point.y);
+ if (!view_util::ConvertPointToWindow(root_view(), &gfx_point)) {
+ return false;
+ }
+ point = CefPoint(gfx_point.x(), gfx_point.y());
+ return true;
+}
+
+CEF_VIEW_IMPL_T bool CEF_VIEW_IMPL_D::ConvertPointFromWindow(CefPoint& point) {
+ CEF_REQUIRE_VALID_RETURN(false);
+ gfx::Point gfx_point = gfx::Point(point.x, point.y);
+ if (!view_util::ConvertPointFromWindow(root_view(), &gfx_point)) {
+ return false;
+ }
+ point = CefPoint(gfx_point.x(), gfx_point.y());
+ return true;
+}
+
+CEF_VIEW_IMPL_T bool CEF_VIEW_IMPL_D::ConvertPointToView(
+ CefRefPtr<CefView> view,
+ CefPoint& point) {
+ CEF_REQUIRE_VALID_RETURN(false);
+ if (!root_view()->GetWidget()) {
+ return false;
+ }
+ views::View* target_view = view_util::GetFor(view);
+ if (!target_view || target_view->GetWidget() != root_view()->GetWidget()) {
+ return false;
+ }
+ gfx::Point gfx_point = gfx::Point(point.x, point.y);
+ views::View::ConvertPointToTarget(root_view(), target_view, &gfx_point);
+ point = CefPoint(gfx_point.x(), gfx_point.y());
+ return true;
+}
+
+CEF_VIEW_IMPL_T bool CEF_VIEW_IMPL_D::ConvertPointFromView(
+ CefRefPtr<CefView> view,
+ CefPoint& point) {
+ CEF_REQUIRE_VALID_RETURN(false);
+ if (!root_view()->GetWidget()) {
+ return false;
+ }
+ views::View* target_view = view_util::GetFor(view);
+ if (!target_view || target_view->GetWidget() != root_view()->GetWidget()) {
+ return false;
+ }
+ gfx::Point gfx_point = gfx::Point(point.x, point.y);
+ views::View::ConvertPointToTarget(target_view, root_view(), &gfx_point);
+ point = CefPoint(gfx_point.x(), gfx_point.y());
+ return true;
+}
+
+#endif // CEF_LIBCEF_BROWSER_VIEWS_VIEW_IMPL_H_
diff --git a/libcef/browser/views/view_util.cc b/libcef/browser/views/view_util.cc
new file mode 100644
index 00000000..5283f48c
--- /dev/null
+++ b/libcef/browser/views/view_util.cc
@@ -0,0 +1,336 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#include "libcef/browser/views/view_util.h"
+
+#include <utility>
+
+#include "libcef/browser/views/view_adapter.h"
+
+#include "ui/display/display.h"
+#include "ui/display/screen.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/point_conversions.h"
+#include "ui/views/widget/widget.h"
+#include "ui/views/widget/widget_delegate.h"
+#include "ui/views/window/non_client_view.h"
+
+#if BUILDFLAG(IS_WIN)
+#include "ui/display/win/screen_win.h"
+#endif
+
+#if defined(USE_AURA)
+#include "ui/aura/window.h"
+#include "ui/views/view_constants_aura.h"
+#endif
+
+namespace view_util {
+
+namespace {
+
+// Manages the association between views::View and CefView instances.
+class UserData : public base::SupportsUserData::Data {
+ public:
+ // Create the initial association between the views::View and the CefView. The
+ // CefView owns the views::View at this stage.
+ static void Register(CefRefPtr<CefView> cef_view) {
+ DCHECK(cef_view->IsValid());
+ DCHECK(!cef_view->IsAttached());
+
+ views::View* view = CefViewAdapter::GetFor(cef_view)->Get();
+ DCHECK(view);
+
+ // The CefView should not already be registered.
+ DCHECK(!view->GetUserData(UserDataKey()));
+
+ view->SetUserData(UserDataKey(), base::WrapUnique(new UserData(cef_view)));
+ }
+
+ static CefRefPtr<CefView> GetFor(const views::View* view) {
+ DCHECK(view);
+ UserData* data = static_cast<UserData*>(view->GetUserData(UserDataKey()));
+ if (data) {
+ return data->view_ref_;
+ }
+ return nullptr;
+ }
+
+ // Transfer ownership of the views::View to the caller. The views::View will
+ // gain a ref-counted reference to the CefView and the CefView will keep an
+ // unowned reference to the views::View. Destruction of the views::View will
+ // release the ref-counted reference to the CefView.
+ [[nodiscard]] static std::unique_ptr<views::View> PassOwnership(
+ CefRefPtr<CefView> cef_view) {
+ DCHECK(cef_view->IsValid());
+ DCHECK(!cef_view->IsAttached());
+
+ std::unique_ptr<views::View> view =
+ CefViewAdapter::GetFor(cef_view)->PassOwnership();
+ DCHECK(view);
+
+ UserData* data = static_cast<UserData*>(view->GetUserData(UserDataKey()));
+ DCHECK(data);
+ data->TakeReference();
+
+ return view;
+ }
+
+ // The CefView resumes ownership of the views::View. The views::View no longer
+ // keeps a ref-counted reference to the CefView.
+ static void ResumeOwnership(CefRefPtr<CefView> cef_view) {
+ DCHECK(cef_view->IsValid());
+ DCHECK(cef_view->IsAttached());
+
+ CefViewAdapter* adapter = CefViewAdapter::GetFor(cef_view);
+ adapter->ResumeOwnership();
+
+ views::View* view = adapter->Get();
+ DCHECK(view);
+
+ UserData* data = static_cast<UserData*>(view->GetUserData(UserDataKey()));
+ DCHECK(data);
+ data->ReleaseReference();
+ }
+
+ private:
+ friend std::default_delete<UserData>;
+
+ explicit UserData(CefRefPtr<CefView> cef_view) : view_ref_(cef_view.get()) {
+ DCHECK(view_ref_);
+ }
+
+ ~UserData() override {
+ if (view_) {
+ // The CefView does not own the views::View. Remove the CefView's
+ // reference to the views::View.
+ CefViewAdapter::GetFor(view_)->Detach();
+ }
+ }
+
+ void TakeReference() { view_ = view_ref_; }
+
+ void ReleaseReference() { view_ = nullptr; }
+
+ static void* UserDataKey() {
+ // We just need a unique constant. Use the address of a static that
+ // COMDAT folding won't touch in an optimizing linker.
+ static int data_key = 0;
+ return reinterpret_cast<void*>(&data_key);
+ }
+
+ CefRefPtr<CefView> view_;
+ CefView* view_ref_;
+};
+
+} // namespace
+
+const SkColor kDefaultBackgroundColor = SkColorSetARGB(255, 255, 255, 255);
+const char kDefaultFontList[] = "Arial, Helvetica, 14px";
+
+void Register(CefRefPtr<CefView> view) {
+ UserData::Register(view);
+}
+
+CefRefPtr<CefView> GetFor(const views::View* view, bool find_known_parent) {
+ if (!view) {
+ return nullptr;
+ }
+
+ if (!find_known_parent) {
+ return UserData::GetFor(view);
+ }
+
+ CefRefPtr<CefView> cef_view;
+ const views::View* current_view = view;
+ do {
+ cef_view = UserData::GetFor(current_view);
+ if (cef_view) {
+ break;
+ }
+ current_view = current_view->parent();
+ } while (current_view);
+
+ return cef_view;
+}
+
+views::View* GetFor(CefRefPtr<CefView> view) {
+ return CefViewAdapter::GetFor(view)->Get();
+}
+
+std::unique_ptr<views::View> PassOwnership(CefRefPtr<CefView> view) {
+ return UserData::PassOwnership(view);
+}
+
+void ResumeOwnership(CefRefPtr<CefView> view) {
+ UserData::ResumeOwnership(view);
+}
+
+CefRefPtr<CefWindow> GetWindowFor(views::Widget* widget) {
+ CefRefPtr<CefWindow> window;
+
+#if defined(USE_AURA)
+ // Retrieve the parent Widget for an overlay.
+ if (widget) {
+ // See matching logic in CefOverlayViewHost::Init.
+ auto widget_view =
+ widget->GetNativeView()->GetProperty(views::kHostViewKey);
+ if (widget_view) {
+ widget = widget_view->GetWidget();
+ }
+ }
+#endif // defined(USE_AURA)
+
+ if (widget) {
+ // The views::WidgetDelegate should be a CefWindowView and |content_view|
+ // should be the same CefWindowView. However, just in case the views::Widget
+ // was created by something else let's go about this the safer way.
+ views::View* content_view = widget->widget_delegate()->GetContentsView();
+ CefRefPtr<CefView> cef_view = GetFor(content_view, false);
+ if (cef_view && cef_view->AsPanel()) {
+ window = cef_view->AsPanel()->AsWindow();
+ }
+
+ // The Window should always exist if we created the views::Widget.
+ DCHECK(window);
+ }
+
+ return window;
+}
+
+display::Display GetDisplayNearestPoint(const gfx::Point& point,
+ bool input_pixel_coords) {
+ gfx::Point find_point = point;
+#if BUILDFLAG(IS_WIN)
+ if (input_pixel_coords) {
+ find_point = gfx::ToFlooredPoint(
+ display::win::ScreenWin::ScreenToDIPPoint(gfx::PointF(point)));
+ }
+#endif
+ return display::Screen::GetScreen()->GetDisplayNearestPoint(find_point);
+}
+
+display::Display GetDisplayMatchingBounds(const gfx::Rect& bounds,
+ bool input_pixel_coords) {
+ gfx::Rect find_bounds = bounds;
+#if BUILDFLAG(IS_WIN)
+ if (input_pixel_coords) {
+ find_bounds =
+ display::win::ScreenWin::ScreenToDIPRect(nullptr, find_bounds);
+ }
+#endif
+ return display::Screen::GetScreen()->GetDisplayMatching(find_bounds);
+}
+
+void ConvertPointFromPixels(gfx::Point* point, float device_scale_factor) {
+ *point = gfx::ToFlooredPoint(
+ gfx::ScalePoint(gfx::PointF(*point), 1.0f / device_scale_factor));
+}
+
+void ConvertPointToPixels(gfx::Point* point, float device_scale_factor) {
+ *point = gfx::ToFlooredPoint(
+ gfx::ScalePoint(gfx::PointF(*point), device_scale_factor));
+}
+
+#if BUILDFLAG(IS_WIN)
+gfx::Point ConvertPointFromPixels(const gfx::Point& point) {
+ return gfx::ToFlooredPoint(
+ display::win::ScreenWin::ScreenToDIPPoint(gfx::PointF(point)));
+}
+
+gfx::Point ConvertPointToPixels(const gfx::Point& point) {
+ return display::win::ScreenWin::DIPToScreenPoint(point);
+}
+
+gfx::Rect ConvertRectFromPixels(const gfx::Rect& rect) {
+ return display::win::ScreenWin::ScreenToDIPRect(nullptr, rect);
+}
+
+gfx::Rect ConvertRectToPixels(const gfx::Rect& rect) {
+ return display::win::ScreenWin::DIPToScreenRect(nullptr, rect);
+}
+#endif // BUILDFLAG(IS_WIN)
+
+bool ConvertPointToScreen(views::View* view,
+ gfx::Point* point,
+ bool output_pixel_coords) {
+ if (!view->GetWidget()) {
+ return false;
+ }
+
+ views::View::ConvertPointToScreen(view, point);
+
+ if (output_pixel_coords) {
+ const display::Display& display = GetDisplayNearestPoint(*point, false);
+ ConvertPointToPixels(point, display.device_scale_factor());
+ }
+
+ return true;
+}
+
+bool ConvertPointFromScreen(views::View* view,
+ gfx::Point* point,
+ bool input_pixel_coords) {
+ if (!view->GetWidget()) {
+ return false;
+ }
+
+ if (input_pixel_coords) {
+ const display::Display& display = GetDisplayNearestPoint(*point, true);
+ ConvertPointFromPixels(point, display.device_scale_factor());
+ }
+
+ views::View::ConvertPointFromScreen(view, point);
+
+ return true;
+}
+
+bool ConvertPointToWindow(views::View* view, gfx::Point* point) {
+ views::Widget* widget = view->GetWidget();
+ if (!widget) {
+ return false;
+ }
+
+ views::View::ConvertPointToWidget(view, point);
+
+ if (widget->non_client_view()) {
+ views::NonClientFrameView* non_client_frame_view =
+ widget->non_client_view()->frame_view();
+ if (non_client_frame_view) {
+ // When using a custom drawn NonClientFrameView the native Window will not
+ // know the actual client bounds. Adjust the native Window bounds for the
+ // reported client bounds.
+ const gfx::Rect& client_bounds =
+ non_client_frame_view->GetBoundsForClientView();
+ *point -= client_bounds.OffsetFromOrigin();
+ }
+ }
+
+ return true;
+}
+
+bool ConvertPointFromWindow(views::View* view, gfx::Point* point) {
+ views::Widget* widget = view->GetWidget();
+ if (!widget) {
+ return false;
+ }
+
+ if (widget->non_client_view()) {
+ views::NonClientFrameView* non_client_frame_view =
+ widget->non_client_view()->frame_view();
+ if (non_client_frame_view) {
+ // When using a custom drawn NonClientFrameView the native Window will not
+ // know the actual client bounds. Adjust the native Window bounds for the
+ // reported client bounds.
+ const gfx::Rect& client_bounds =
+ non_client_frame_view->GetBoundsForClientView();
+ *point += client_bounds.OffsetFromOrigin();
+ }
+ }
+
+ views::View::ConvertPointFromWidget(view, point);
+
+ return true;
+}
+
+} // namespace view_util
diff --git a/libcef/browser/views/view_util.h b/libcef/browser/views/view_util.h
new file mode 100644
index 00000000..50828da9
--- /dev/null
+++ b/libcef/browser/views/view_util.h
@@ -0,0 +1,157 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_VIEWS_VIEW_UTIL_H_
+#define CEF_LIBCEF_BROWSER_VIEWS_VIEW_UTIL_H_
+#pragma once
+
+#include "include/views/cef_view.h"
+#include "include/views/cef_window.h"
+
+#include "ui/gfx/native_widget_types.h"
+#include "ui/views/view.h"
+
+namespace display {
+class Display;
+}
+
+namespace gfx {
+class Point;
+}
+
+namespace views {
+class NativeWidget;
+class Widget;
+namespace internal {
+class NativeWidgetDelegate;
+}
+} // namespace views
+
+class CefWindowDelegate;
+
+#define CEF_REQUIRE_VALID_RETURN(ret) \
+ if (!ParentClass::IsValid()) \
+ return ret;
+
+#define CEF_REQUIRE_VALID_RETURN_VOID() \
+ if (!ParentClass::IsValid()) \
+ return;
+
+// The below functions manage the relationship between CefView and views::View
+// instances. See comments in view_impl.h for a usage overview.
+
+namespace view_util {
+
+// Default values.
+extern const SkColor kDefaultBackgroundColor;
+extern const char kDefaultFontList[];
+
+// Called when a CefView is initialized to create the initial association
+// between the underlying views::View and |view|. The CefView owns the
+// views::View at this stage.
+void Register(CefRefPtr<CefView> view);
+
+// Returns the CefView object associated with the specified |view|. If no
+// CefView is associated with |view| and |find_known_parent| is true then this
+// function will return the closest parent views::View with an associated
+// CefView.
+CefRefPtr<CefView> GetFor(const views::View* view, bool find_known_parent);
+
+// Returns the views::View object associated with the specified |view|.
+// Ownership of the views::View object does not change.
+views::View* GetFor(CefRefPtr<CefView> view);
+
+// Returns the views::View object associated with the specified |view| and
+// passes ownership to the caller. The views::View object should then be passed
+// to another views::View via views::View or views::LayoutManager methods. The
+// views::View will keep a ref-counted reference to |view|, and |view| will keep
+// an un-owned reference to the views::View. These references will reset when
+// the views::View object is deleted or when ResumeOwnership() is called.
+[[nodiscard]] std::unique_ptr<views::View> PassOwnership(
+ CefRefPtr<CefView> view);
+
+// Causes |view| to resume ownership of the views::View object. Should be called
+// after removing the views::View object from its previous parent.
+void ResumeOwnership(CefRefPtr<CefView> view);
+
+// Returns the Window associated with |widget|.
+CefRefPtr<CefWindow> GetWindowFor(views::Widget* widget);
+
+// Returns the Display nearest |point|. Set |input_pixel_coords| to true if
+// |point| is in pixel coordinates instead of density independent pixels (DIP).
+display::Display GetDisplayNearestPoint(const gfx::Point& point,
+ bool input_pixel_coords);
+
+// Returns the Display that most closely intersects |bounds|. Set
+// |input_pixel_coords| to true if |bounds| is in pixel coordinates instead of
+// density independent pixels (DIP).
+display::Display GetDisplayMatchingBounds(const gfx::Rect& bounds,
+ bool input_pixel_coords);
+
+// Convert |point| from pixel coordinates to density independent pixels (DIP)
+// using |device_scale_factor|.
+void ConvertPointFromPixels(gfx::Point* point, float device_scale_factor);
+
+// Convert |point| to pixel coordinates from density independent pixels (DIP)
+// using |device_scale_factor|.
+void ConvertPointToPixels(gfx::Point* point, float device_scale_factor);
+
+#if BUILDFLAG(IS_WIN)
+// Convert |point| from pixel screen coordinates to DIP screen coordinates.
+gfx::Point ConvertPointFromPixels(const gfx::Point& point);
+
+// Convert |point| from DIP screen coordinates to pixel screen coordinates.
+gfx::Point ConvertPointToPixels(const gfx::Point& point);
+
+// Convert |rect| from pixel screen coordinates to DIP screen coordinates.
+gfx::Rect ConvertRectFromPixels(const gfx::Rect& rect);
+
+// Convert |rect| from DIP screen coordinates to pixel screen coordinates.
+gfx::Rect ConvertRectToPixels(const gfx::Rect& rect);
+#endif // BUILDFLAG(IS_WIN)
+
+// Convert |point| from |view| to screen coordinates. If |output_pixel_coords|
+// is true then |point| will be output in pixel coordinates instead of density
+// independent pixels (DIP). Returns false if |view| does not currently belong
+// to a Widget.
+bool ConvertPointToScreen(views::View* view,
+ gfx::Point* point,
+ bool output_pixel_coords);
+
+// Convert |point| from screen to |view| coordinates. Set |input_pixel_coords|
+// to true when |point| is being input in pixel coordinates instead of density
+// independent pixels (DIP). Returns false if |view| does not currently belong
+// to a Widget.
+bool ConvertPointFromScreen(views::View* view,
+ gfx::Point* point,
+ bool input_pixel_coords);
+
+// Convert |point| from |view| to window (Widget) coordinates. Returns false if
+// |view| does not currently belong to a Widget.
+bool ConvertPointToWindow(views::View* view, gfx::Point* point);
+
+// Convert |point| from window (Widget) to |view| coordinates. Returns false if
+// |view| does not currently belong to a Widget.
+bool ConvertPointFromWindow(views::View* view, gfx::Point* point);
+
+// Returns the native window handle for |widget|. May return nullptr.
+gfx::NativeWindow GetNativeWindow(views::Widget* widget);
+
+// Returns the native view handle for |widget|. May return nullptr.
+gfx::NativeView GetNativeView(views::Widget* widget);
+
+// Returns the platform window handle for |widget|. May return nullptr.
+CefWindowHandle GetWindowHandle(views::Widget* widget);
+
+// Returns the platform window handle for |window|. May return nullptr.
+CefWindowHandle GetWindowHandle(gfx::NativeWindow window);
+
+views::NativeWidget* CreateNativeWidget(
+ views::internal::NativeWidgetDelegate* delegate,
+ CefRefPtr<CefWindow> window,
+ CefWindowDelegate* window_delegate);
+
+} // namespace view_util
+
+#endif // CEF_LIBCEF_BROWSER_VIEWS_VIEW_UTIL_H_
diff --git a/libcef/browser/views/view_util_aura.cc b/libcef/browser/views/view_util_aura.cc
new file mode 100644
index 00000000..f28d5526
--- /dev/null
+++ b/libcef/browser/views/view_util_aura.cc
@@ -0,0 +1,52 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#include "libcef/browser/views/view_util.h"
+
+#include "ui/aura/window.h"
+#include "ui/aura/window_tree_host.h"
+#include "ui/views/widget/native_widget.h"
+#include "ui/views/widget/native_widget_delegate.h"
+#include "ui/views/widget/widget.h"
+
+namespace view_util {
+
+gfx::NativeWindow GetNativeWindow(views::Widget* widget) {
+ if (widget) {
+ aura::Window* window = widget->GetNativeWindow();
+ if (window) {
+ return window->GetRootWindow();
+ }
+ }
+ return nullptr;
+}
+
+gfx::NativeView GetNativeView(views::Widget* widget) {
+ return GetNativeWindow(widget);
+}
+
+CefWindowHandle GetWindowHandle(views::Widget* widget) {
+ // Same implementation as views::HWNDForView() but cross-platform.
+ if (widget) {
+ return GetWindowHandle(widget->GetNativeWindow());
+ }
+ return kNullWindowHandle;
+}
+
+CefWindowHandle GetWindowHandle(gfx::NativeWindow window) {
+ // |window| is an aura::Window*.
+ if (window && window->GetRootWindow()) {
+ return window->GetHost()->GetAcceleratedWidget();
+ }
+ return kNullWindowHandle;
+}
+
+views::NativeWidget* CreateNativeWidget(
+ views::internal::NativeWidgetDelegate* delegate,
+ CefRefPtr<CefWindow> window,
+ CefWindowDelegate* window_delegate) {
+ return nullptr;
+}
+
+} // namespace view_util
diff --git a/libcef/browser/views/view_util_mac.mm b/libcef/browser/views/view_util_mac.mm
new file mode 100644
index 00000000..2bab6b47
--- /dev/null
+++ b/libcef/browser/views/view_util_mac.mm
@@ -0,0 +1,54 @@
+// Copyright 2021 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#include "libcef/browser/views/view_util.h"
+
+#import <Cocoa/Cocoa.h>
+
+#include "include/internal/cef_types_mac.h"
+#include "libcef/browser/views/native_widget_mac.h"
+
+#include "ui/views/widget/widget.h"
+
+namespace view_util {
+
+gfx::NativeWindow GetNativeWindow(views::Widget* widget) {
+ if (widget) {
+ return widget->GetNativeWindow();
+ }
+ return gfx::NativeWindow();
+}
+
+gfx::NativeView GetNativeView(views::Widget* widget) {
+ if (widget) {
+ return widget->GetNativeView();
+ }
+ return gfx::NativeView();
+}
+
+CefWindowHandle GetWindowHandle(views::Widget* widget) {
+ // |view| is a wrapper type from native_widget_types.h.
+ auto view = GetNativeView(widget);
+ if (view) {
+ return CAST_NSVIEW_TO_CEF_WINDOW_HANDLE(view.GetNativeNSView());
+ }
+ return kNullWindowHandle;
+}
+
+CefWindowHandle GetWindowHandle(gfx::NativeWindow window) {
+ // |window| is a wrapper type from native_widget_types.h.
+ if (window) {
+ NSWindow* nswindow = window.GetNativeNSWindow();
+ return CAST_NSVIEW_TO_CEF_WINDOW_HANDLE([nswindow contentView]);
+ }
+ return kNullWindowHandle;
+}
+
+views::NativeWidget* CreateNativeWidget(
+ views::internal::NativeWidgetDelegate* delegate,
+ CefRefPtr<CefWindow> window,
+ CefWindowDelegate* window_delegate) {
+ return new CefNativeWidgetMac(delegate, window, window_delegate);
+}
+} // namespace view_util
diff --git a/libcef/browser/views/view_view.h b/libcef/browser/views/view_view.h
new file mode 100644
index 00000000..23e66965
--- /dev/null
+++ b/libcef/browser/views/view_view.h
@@ -0,0 +1,257 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_VIEWS_VIEW_VIEW_H_
+#define CEF_LIBCEF_BROWSER_VIEWS_VIEW_VIEW_H_
+#pragma once
+
+#include "include/views/cef_view.h"
+#include "include/views/cef_view_delegate.h"
+
+#include "libcef/browser/thread_util.h"
+#include "libcef/browser/views/view_util.h"
+
+#include "base/logging.h"
+#include "ui/views/accessibility/accessibility_paint_checks.h"
+#include "ui/views/background.h"
+#include "ui/views/view.h"
+
+// Helpers for template boiler-plate.
+#define CEF_VIEW_VIEW_T \
+ template <class ViewsViewClass, class CefViewDelegateClass>
+#define CEF_VIEW_VIEW_A ViewsViewClass, CefViewDelegateClass
+#define CEF_VIEW_VIEW_D CefViewView<CEF_VIEW_VIEW_A>
+
+// Base template for implementing views::View-derived classes. The views::View-
+// derived type passed to this template must provide a no-argument constructor
+// (for example, see LabelButtonEx from basic_label_button_view.h). See comments
+// in view_impl.h for a usage overview.
+CEF_VIEW_VIEW_T class CefViewView : public ViewsViewClass {
+ public:
+ using ParentClass = ViewsViewClass;
+
+ // Should be created from CreateRootView() in a CefViewImpl-derived class.
+ // Do not call complex views::View-derived methods from a CefViewView-derived
+ // constructor as they may attempt to call back into CefViewImpl before
+ // registration has been performed. |cef_delegate| may be nullptr.
+ template <typename... Args>
+ explicit CefViewView(CefViewDelegateClass* cef_delegate, Args... args)
+ : ParentClass(args...), cef_delegate_(cef_delegate) {}
+
+ // Should be called from InitializeRootView() in the CefViewImpl-derived
+ // class that created this object. This method will be called after
+ // CefViewImpl registration has completed so it is safe to call complex
+ // views::View-derived methods here.
+ virtual void Initialize() {
+ // Use our defaults instead of the Views framework defaults.
+ ParentClass::SetBackground(
+ views::CreateSolidBackground(view_util::kDefaultBackgroundColor));
+
+ // TODO(crbug.com/1218186): Remove this, if this view is focusable then it
+ // needs to add a name so that the screen reader knows what to announce.
+ ParentClass::SetProperty(views::kSkipAccessibilityPaintChecks, true);
+ }
+
+ // Returns the CefViewDelegate-derived delegate associated with this view.
+ // May return nullptr.
+ CefViewDelegateClass* cef_delegate() const { return cef_delegate_; }
+
+ // Returns the CefView associated with this view. May return nullptr during
+ // CefViewImpl initialization. If callbacks to the CefViewImpl-derived class
+ // are required define an interface that the CefViewImpl-derived class can
+ // implement and pass as an unowned instance to this object's constructor (see
+ // for example CefWindowView).
+ CefRefPtr<CefView> GetCefView() const {
+ CefRefPtr<CefView> view = view_util::GetFor(this, false);
+ DCHECK(view);
+ return view;
+ }
+
+ // views::View methods:
+ gfx::Size CalculatePreferredSize() const override;
+ gfx::Size GetMinimumSize() const override;
+ gfx::Size GetMaximumSize() const override;
+ int GetHeightForWidth(int w) const override;
+ void Layout() override;
+ void ViewHierarchyChanged(
+ const views::ViewHierarchyChangedDetails& details) override;
+ void AddedToWidget() override;
+ void RemovedFromWidget() override;
+ void OnFocus() override;
+ void OnBlur() override;
+
+ // Return true if this View is expected to have a minimum size (for example,
+ // a button where the minimum size is based on the label).
+ virtual bool HasMinimumSize() const { return false; }
+
+ private:
+ void NotifyChildViewChanged(
+ const views::ViewHierarchyChangedDetails& details);
+ void NotifyParentViewChanged(
+ const views::ViewHierarchyChangedDetails& details);
+
+ // Not owned by this object.
+ CefViewDelegateClass* const cef_delegate_;
+};
+
+CEF_VIEW_VIEW_T gfx::Size CEF_VIEW_VIEW_D::CalculatePreferredSize() const {
+ gfx::Size result;
+ if (cef_delegate()) {
+ CefSize cef_size = cef_delegate()->GetPreferredSize(GetCefView());
+ if (!cef_size.IsEmpty()) {
+ result = gfx::Size(cef_size.width, cef_size.height);
+ }
+ }
+ if (result.IsEmpty()) {
+ result = ParentClass::CalculatePreferredSize();
+ }
+ if (result.IsEmpty()) {
+ // Some layouts like BoxLayout expect the preferred size to be non-empty.
+ // The user may have set the size explicitly. Therefore return the current
+ // size as the preferred size.
+ result = ParentClass::size();
+ }
+ return result;
+}
+
+CEF_VIEW_VIEW_T gfx::Size CEF_VIEW_VIEW_D::GetMinimumSize() const {
+ gfx::Size result;
+ if (cef_delegate()) {
+ CefSize cef_size = cef_delegate()->GetMinimumSize(GetCefView());
+ if (!cef_size.IsEmpty()) {
+ result = gfx::Size(cef_size.width, cef_size.height);
+ }
+ }
+ // We don't want to call ParentClass::GetMinimumSize() in all cases because
+ // the default views::View implementation will call GetPreferredSize(). That
+ // may result in size() being returned which keeps the View from shrinking.
+ if (result.IsEmpty() && HasMinimumSize()) {
+ result = ParentClass::GetMinimumSize();
+ }
+ return result;
+}
+
+CEF_VIEW_VIEW_T gfx::Size CEF_VIEW_VIEW_D::GetMaximumSize() const {
+ gfx::Size result;
+ if (cef_delegate()) {
+ CefSize cef_size = cef_delegate()->GetMaximumSize(GetCefView());
+ if (!cef_size.IsEmpty()) {
+ result = gfx::Size(cef_size.width, cef_size.height);
+ }
+ }
+ if (result.IsEmpty()) {
+ result = ParentClass::GetMaximumSize();
+ }
+ return result;
+}
+
+CEF_VIEW_VIEW_T int CEF_VIEW_VIEW_D::GetHeightForWidth(int w) const {
+ int result = 0;
+ if (cef_delegate()) {
+ result = cef_delegate()->GetHeightForWidth(GetCefView(), w);
+ }
+ if (result == 0) {
+ result = ParentClass::GetHeightForWidth(w);
+ }
+ if (result == 0) {
+ // Some layouts like FillLayout will ignore the preferred size if this view
+ // has no children. We want to use the preferred size if not otherwise
+ // specified.
+ result = ParentClass::GetPreferredSize().height();
+ }
+ return result;
+}
+
+CEF_VIEW_VIEW_T void CEF_VIEW_VIEW_D::Layout() {
+ ParentClass::Layout();
+
+ // If Layout() did not provide a size then use the preferred size.
+ if (ParentClass::size().IsEmpty()) {
+ ParentClass::SizeToPreferredSize();
+ }
+
+ if (cef_delegate()) {
+ const auto new_bounds = ParentClass::bounds();
+ CefRect new_rect(new_bounds.x(), new_bounds.y(), new_bounds.width(),
+ new_bounds.height());
+ cef_delegate()->OnLayoutChanged(GetCefView(), new_rect);
+ }
+}
+
+CEF_VIEW_VIEW_T void CEF_VIEW_VIEW_D::ViewHierarchyChanged(
+ const views::ViewHierarchyChangedDetails& details) {
+ NotifyChildViewChanged(details);
+ NotifyParentViewChanged(details);
+ ParentClass::ViewHierarchyChanged(details);
+}
+
+CEF_VIEW_VIEW_T void CEF_VIEW_VIEW_D::AddedToWidget() {
+ ParentClass::AddedToWidget();
+ if (cef_delegate()) {
+ cef_delegate()->OnWindowChanged(GetCefView(), /*added=*/true);
+ }
+}
+
+CEF_VIEW_VIEW_T void CEF_VIEW_VIEW_D::RemovedFromWidget() {
+ if (cef_delegate()) {
+ cef_delegate()->OnWindowChanged(GetCefView(), /*added=*/false);
+ }
+ ParentClass::RemovedFromWidget();
+}
+
+CEF_VIEW_VIEW_T void CEF_VIEW_VIEW_D::OnFocus() {
+ if (cef_delegate()) {
+ cef_delegate()->OnFocus(GetCefView());
+ }
+ ParentClass::OnFocus();
+}
+
+CEF_VIEW_VIEW_T void CEF_VIEW_VIEW_D::OnBlur() {
+ if (cef_delegate()) {
+ cef_delegate()->OnBlur(GetCefView());
+ }
+ ParentClass::OnBlur();
+}
+
+CEF_VIEW_VIEW_T void CEF_VIEW_VIEW_D::NotifyChildViewChanged(
+ const views::ViewHierarchyChangedDetails& details) {
+ if (!cef_delegate()) {
+ return;
+ }
+
+ // Only interested with the parent is |this| object and the notification is
+ // about an immediate child (notifications are also sent for grandchildren).
+ if (details.parent != this || details.child->parent() != this) {
+ return;
+ }
+
+ // Only notify for children that have a known CEF root view. For example,
+ // don't notify when ScrollView adds child scroll bars.
+ CefRefPtr<CefView> child = view_util::GetFor(details.child, false);
+ if (child) {
+ cef_delegate()->OnChildViewChanged(GetCefView(), details.is_add, child);
+ }
+}
+
+CEF_VIEW_VIEW_T void CEF_VIEW_VIEW_D::NotifyParentViewChanged(
+ const views::ViewHierarchyChangedDetails& details) {
+ if (!cef_delegate()) {
+ return;
+ }
+
+ // Only interested when the child is |this| object and notification is about
+ // the immediate parent (notifications are sent for all parents).
+ if (details.child != this || details.parent != ParentClass::parent()) {
+ return;
+ }
+
+ // The immediate parent might be an intermediate view so find the closest
+ // known CEF root view. |parent| might be nullptr for overlays.
+ CefRefPtr<CefView> parent = view_util::GetFor(details.parent, true);
+ if (parent) {
+ cef_delegate()->OnParentViewChanged(GetCefView(), details.is_add, parent);
+ }
+}
+
+#endif // CEF_LIBCEF_BROWSER_VIEWS_VIEW_VIEW_H_
diff --git a/libcef/browser/views/window_impl.cc b/libcef/browser/views/window_impl.cc
new file mode 100644
index 00000000..ecd69b44
--- /dev/null
+++ b/libcef/browser/views/window_impl.cc
@@ -0,0 +1,717 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#include "libcef/browser/views/window_impl.h"
+
+#include "libcef/browser/browser_util.h"
+#include "libcef/browser/thread_util.h"
+#include "libcef/browser/views/display_impl.h"
+#include "libcef/browser/views/fill_layout_impl.h"
+#include "libcef/browser/views/layout_util.h"
+#include "libcef/browser/views/view_util.h"
+#include "libcef/browser/views/window_view.h"
+
+#include "base/i18n/rtl.h"
+#include "ui/base/test/ui_controls.h"
+#include "ui/compositor/compositor.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/views/controls/button/menu_button.h"
+#include "ui/views/controls/menu/menu_runner.h"
+
+#if defined(USE_AURA)
+#include "ui/aura/test/ui_controls_factory_aura.h"
+#include "ui/aura/window.h"
+#include "ui/base/test/ui_controls_aura.h"
+#if BUILDFLAG(IS_OZONE)
+#include "ui/views/test/ui_controls_factory_desktop_aura_ozone.h"
+#endif
+#endif // defined(USE_AURA)
+
+#if BUILDFLAG(IS_WIN)
+#include "ui/display/win/screen_win.h"
+#endif
+
+namespace {
+
+// Based on chrome/test/base/interactive_ui_tests_main.cc.
+void InitializeUITesting() {
+ static bool initialized = false;
+ if (!initialized) {
+ ui_controls::EnableUIControls();
+
+#if defined(USE_AURA)
+#if BUILDFLAG(IS_WIN)
+ ui_controls::InstallUIControlsAura(
+ aura::test::CreateUIControlsAura(nullptr));
+#elif BUILDFLAG(IS_OZONE)
+ ui_controls::InstallUIControlsAura(
+ views::test::CreateUIControlsDesktopAuraOzone());
+#endif
+#endif // defined(USE_AURA)
+
+ initialized = true;
+ }
+}
+
+#if defined(USE_AURA)
+
+// This class forwards KeyEvents to the CefWindowImpl associated with a widget.
+// This allows KeyEvents to be processed after all other targets.
+// Events originating from CefBrowserView will instead be delivered via
+// CefBrowserViewImpl::HandleKeyboardEvent.
+class CefUnhandledKeyEventHandler : public ui::EventHandler {
+ public:
+ CefUnhandledKeyEventHandler(CefWindowImpl* window_impl, views::Widget* widget)
+ : window_impl_(window_impl),
+ widget_(widget),
+ window_(widget->GetNativeWindow()) {
+ DCHECK(window_);
+ window_->AddPostTargetHandler(this);
+ }
+
+ CefUnhandledKeyEventHandler(const CefUnhandledKeyEventHandler&) = delete;
+ CefUnhandledKeyEventHandler& operator=(const CefUnhandledKeyEventHandler&) =
+ delete;
+
+ ~CefUnhandledKeyEventHandler() override {
+ window_->RemovePostTargetHandler(this);
+ }
+
+ // Implementation of ui::EventHandler:
+ void OnKeyEvent(ui::KeyEvent* event) override {
+ // Give the FocusManager a chance to handle accelerators first.
+ // Widget::OnKeyEvent would normally call this after all EventHandlers have
+ // had a shot but we don't want to wait.
+ if (widget_->GetFocusManager() &&
+ !widget_->GetFocusManager()->OnKeyEvent(*event)) {
+ event->StopPropagation();
+ return;
+ }
+
+ CefKeyEvent cef_event;
+ if (browser_util::GetCefKeyEvent(*event, cef_event) &&
+ window_impl_->OnKeyEvent(cef_event)) {
+ event->StopPropagation();
+ }
+ }
+
+ private:
+ // Members are guaranteed to outlive this object.
+ CefWindowImpl* window_impl_;
+ views::Widget* widget_;
+
+ // |window_| is the event target that is associated with this class.
+ aura::Window* window_;
+};
+
+#endif // defined(USE_AURA)
+
+} // namespace
+
+// static
+CefRefPtr<CefWindow> CefWindow::CreateTopLevelWindow(
+ CefRefPtr<CefWindowDelegate> delegate) {
+ return CefWindowImpl::Create(delegate, gfx::kNullAcceleratedWidget);
+}
+
+// static
+CefRefPtr<CefWindowImpl> CefWindowImpl::Create(
+ CefRefPtr<CefWindowDelegate> delegate,
+ gfx::AcceleratedWidget parent_widget) {
+ CEF_REQUIRE_UIT_RETURN(nullptr);
+ CefRefPtr<CefWindowImpl> window = new CefWindowImpl(delegate);
+ window->Initialize();
+ window->CreateWidget(parent_widget);
+ if (delegate) {
+ delegate->OnWindowCreated(window.get());
+ }
+ return window;
+}
+
+void CefWindowImpl::Show() {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ if (widget_) {
+ widget_->Show();
+ }
+}
+
+void CefWindowImpl::Hide() {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ if (widget_) {
+ widget_->Hide();
+ }
+}
+
+void CefWindowImpl::CenterWindow(const CefSize& size) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ if (widget_) {
+ widget_->CenterWindow(gfx::Size(size.width, size.height));
+ }
+}
+
+void CefWindowImpl::Close() {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ if (widget_ && !widget_->IsClosed()) {
+ widget_->Close();
+ }
+}
+
+bool CefWindowImpl::IsClosed() {
+ CEF_REQUIRE_UIT_RETURN(false);
+ return destroyed_ || (widget_ && widget_->IsClosed());
+}
+
+void CefWindowImpl::Activate() {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ if (widget_ && widget_->CanActivate() && !widget_->IsActive()) {
+ widget_->Activate();
+ }
+}
+
+void CefWindowImpl::Deactivate() {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ if (widget_ && widget_->CanActivate() && widget_->IsActive()) {
+ widget_->Deactivate();
+ }
+}
+
+bool CefWindowImpl::IsActive() {
+ CEF_REQUIRE_VALID_RETURN(false);
+ if (widget_) {
+ return widget_->IsActive();
+ }
+ return false;
+}
+
+void CefWindowImpl::BringToTop() {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ if (widget_) {
+ widget_->StackAtTop();
+ }
+}
+
+void CefWindowImpl::SetAlwaysOnTop(bool on_top) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ if (widget_ && on_top != (widget_->GetZOrderLevel() ==
+ ui::ZOrderLevel::kFloatingWindow)) {
+ widget_->SetZOrderLevel(on_top ? ui::ZOrderLevel::kFloatingWindow
+ : ui::ZOrderLevel::kNormal);
+ }
+}
+
+bool CefWindowImpl::IsAlwaysOnTop() {
+ CEF_REQUIRE_VALID_RETURN(false);
+ if (widget_) {
+ return widget_->GetZOrderLevel() == ui::ZOrderLevel::kFloatingWindow;
+ }
+ return false;
+}
+
+void CefWindowImpl::Maximize() {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ if (widget_ && !widget_->IsMaximized()) {
+ widget_->Maximize();
+ }
+}
+
+void CefWindowImpl::Minimize() {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ if (widget_ && !widget_->IsMinimized()) {
+ widget_->Minimize();
+ }
+}
+
+void CefWindowImpl::Restore() {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ if (widget_ && (widget_->IsMaximized() || widget_->IsMinimized())) {
+ widget_->Restore();
+ }
+}
+
+void CefWindowImpl::SetFullscreen(bool fullscreen) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ if (widget_ && fullscreen != widget_->IsFullscreen()) {
+ widget_->SetFullscreen(fullscreen);
+ }
+}
+
+bool CefWindowImpl::IsMaximized() {
+ CEF_REQUIRE_VALID_RETURN(false);
+ if (widget_) {
+ return widget_->IsMaximized();
+ }
+ return false;
+}
+
+bool CefWindowImpl::IsMinimized() {
+ CEF_REQUIRE_VALID_RETURN(false);
+ if (widget_) {
+ return widget_->IsMinimized();
+ }
+ return false;
+}
+
+bool CefWindowImpl::IsFullscreen() {
+ CEF_REQUIRE_VALID_RETURN(false);
+ if (widget_) {
+ return widget_->IsFullscreen();
+ }
+ return false;
+}
+
+void CefWindowImpl::SetTitle(const CefString& title) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ if (root_view()) {
+ root_view()->SetTitle(title);
+ }
+}
+
+CefString CefWindowImpl::GetTitle() {
+ CEF_REQUIRE_VALID_RETURN(CefString());
+ if (root_view()) {
+ return root_view()->title();
+ }
+ return CefString();
+}
+
+void CefWindowImpl::SetWindowIcon(CefRefPtr<CefImage> image) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ if (root_view()) {
+ root_view()->SetWindowIcon(image);
+ }
+}
+
+CefRefPtr<CefImage> CefWindowImpl::GetWindowIcon() {
+ CEF_REQUIRE_VALID_RETURN(nullptr);
+ if (root_view()) {
+ return root_view()->window_icon();
+ }
+ return nullptr;
+}
+
+void CefWindowImpl::SetWindowAppIcon(CefRefPtr<CefImage> image) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ if (root_view()) {
+ root_view()->SetWindowAppIcon(image);
+ }
+}
+
+CefRefPtr<CefImage> CefWindowImpl::GetWindowAppIcon() {
+ CEF_REQUIRE_VALID_RETURN(nullptr);
+ if (root_view()) {
+ return root_view()->window_app_icon();
+ }
+ return nullptr;
+}
+
+CefRefPtr<CefOverlayController> CefWindowImpl::AddOverlayView(
+ CefRefPtr<CefView> view,
+ cef_docking_mode_t docking_mode) {
+ CEF_REQUIRE_VALID_RETURN(nullptr);
+ if (root_view()) {
+ return root_view()->AddOverlayView(view, docking_mode);
+ }
+ return nullptr;
+}
+
+void CefWindowImpl::GetDebugInfo(base::Value::Dict* info,
+ bool include_children) {
+ ParentClass::GetDebugInfo(info, include_children);
+ if (root_view()) {
+ info->Set("title", root_view()->title());
+ }
+}
+
+void CefWindowImpl::ShowMenu(CefRefPtr<CefMenuModel> menu_model,
+ const CefPoint& screen_point,
+ cef_menu_anchor_position_t anchor_position) {
+ ShowMenu(nullptr, menu_model, screen_point, anchor_position);
+}
+
+void CefWindowImpl::Detach() {
+ // OnDeleteDelegate should always be called before Detach().
+ DCHECK(!widget_);
+
+ ParentClass::Detach();
+}
+
+void CefWindowImpl::SetBounds(const CefRect& bounds) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ if (widget_) {
+ widget_->SetBounds(
+ gfx::Rect(bounds.x, bounds.y, bounds.width, bounds.height));
+ }
+}
+
+CefRect CefWindowImpl::GetBounds() {
+ CEF_REQUIRE_VALID_RETURN(CefRect());
+ gfx::Rect bounds;
+ if (widget_) {
+ bounds = widget_->GetWindowBoundsInScreen();
+ }
+ return CefRect(bounds.x(), bounds.y(), bounds.width(), bounds.height());
+}
+
+CefRect CefWindowImpl::GetBoundsInScreen() {
+ return GetBounds();
+}
+
+void CefWindowImpl::SetSize(const CefSize& size) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ if (widget_) {
+ widget_->SetSize(gfx::Size(size.width, size.height));
+ }
+}
+
+void CefWindowImpl::SetPosition(const CefPoint& position) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ if (widget_) {
+ gfx::Rect bounds = widget_->GetWindowBoundsInScreen();
+ bounds.set_origin(gfx::Point(position.x, position.y));
+ widget_->SetBounds(bounds);
+ }
+}
+
+void CefWindowImpl::SizeToPreferredSize() {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ if (widget_) {
+ if (widget_->non_client_view()) {
+ widget_->SetSize(widget_->non_client_view()->GetPreferredSize());
+ } else {
+ widget_->SetSize(root_view()->GetPreferredSize());
+ }
+ }
+}
+
+void CefWindowImpl::SetVisible(bool visible) {
+ if (visible) {
+ Show();
+ } else {
+ Hide();
+ }
+}
+
+bool CefWindowImpl::IsVisible() {
+ CEF_REQUIRE_VALID_RETURN(false);
+ if (widget_) {
+ return widget_->IsVisible();
+ }
+ return false;
+}
+
+bool CefWindowImpl::IsDrawn() {
+ return IsVisible();
+}
+
+void CefWindowImpl::SetBackgroundColor(cef_color_t color) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ ParentClass::SetBackgroundColor(color);
+ if (widget_ && widget_->GetCompositor()) {
+ widget_->GetCompositor()->SetBackgroundColor(color);
+ }
+}
+
+bool CefWindowImpl::CanWidgetClose() {
+ if (delegate()) {
+ return delegate()->CanClose(this);
+ }
+ return true;
+}
+
+void CefWindowImpl::OnWindowClosing() {
+#if defined(USE_AURA)
+ unhandled_key_event_handler_.reset();
+#endif
+
+ if (delegate()) {
+ delegate()->OnWindowClosing(this);
+ }
+}
+
+void CefWindowImpl::OnWindowViewDeleted() {
+ CancelMenu();
+
+ destroyed_ = true;
+ widget_ = nullptr;
+
+ if (delegate()) {
+ delegate()->OnWindowDestroyed(this);
+ }
+
+ // Call Detach() here instead of waiting for the root View to be deleted so
+ // that any following attempts to call CefWindow methods from the delegate
+ // will fail.
+ Detach();
+}
+
+// Will only be called if CanHandleAccelerators() returns true.
+bool CefWindowImpl::AcceleratorPressed(const ui::Accelerator& accelerator) {
+ for (const auto& entry : accelerator_map_) {
+ if (entry.second == accelerator) {
+ return delegate()->OnAccelerator(this, entry.first);
+ }
+ }
+ return false;
+}
+
+bool CefWindowImpl::CanHandleAccelerators() const {
+ if (delegate() && widget_) {
+ return widget_->IsActive();
+ }
+ return false;
+}
+
+bool CefWindowImpl::OnKeyEvent(const CefKeyEvent& event) {
+ if (delegate()) {
+ return delegate()->OnKeyEvent(this, event);
+ }
+ return false;
+}
+
+void CefWindowImpl::ShowMenu(views::MenuButton* menu_button,
+ CefRefPtr<CefMenuModel> menu_model,
+ const CefPoint& screen_point,
+ cef_menu_anchor_position_t anchor_position) {
+ CancelMenu();
+
+ if (!widget_) {
+ return;
+ }
+
+ CefMenuModelImpl* menu_model_impl =
+ static_cast<CefMenuModelImpl*>(menu_model.get());
+ if (!menu_model_impl || !menu_model_impl->model()) {
+ return;
+ }
+
+ menu_model_ = menu_model_impl;
+
+ // We'll send the MenuClosed notification manually for better accuracy.
+ menu_model_->set_auto_notify_menu_closed(false);
+
+ menu_runner_.reset(new views::MenuRunner(
+ menu_model_impl->model(),
+ menu_button ? views::MenuRunner::HAS_MNEMONICS
+ : views::MenuRunner::CONTEXT_MENU,
+ base::BindRepeating(&CefWindowImpl::MenuClosed, this)));
+
+ menu_runner_->RunMenuAt(
+ widget_, menu_button ? menu_button->button_controller() : nullptr,
+ gfx::Rect(gfx::Point(screen_point.x, screen_point.y), gfx::Size()),
+ static_cast<views::MenuAnchorPosition>(anchor_position),
+ ui::MENU_SOURCE_NONE);
+}
+
+void CefWindowImpl::MenuClosed() {
+ menu_model_->NotifyMenuClosed();
+ menu_model_ = nullptr;
+ menu_runner_.reset(nullptr);
+}
+
+void CefWindowImpl::CancelMenu() {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ if (menu_runner_) {
+ menu_runner_->Cancel();
+ }
+ DCHECK(!menu_model_);
+ DCHECK(!menu_runner_);
+}
+
+CefRefPtr<CefDisplay> CefWindowImpl::GetDisplay() {
+ CEF_REQUIRE_VALID_RETURN(nullptr);
+ if (widget_ && root_view()) {
+ const display::Display& display = root_view()->GetDisplay();
+ if (display.is_valid()) {
+ return new CefDisplayImpl(display);
+ }
+ }
+ return nullptr;
+}
+
+CefRect CefWindowImpl::GetClientAreaBoundsInScreen() {
+ CEF_REQUIRE_VALID_RETURN(CefRect());
+ if (widget_) {
+ gfx::Rect bounds = widget_->GetClientAreaBoundsInScreen();
+
+ views::NonClientFrameView* non_client_frame_view =
+ root_view()->GetNonClientFrameView();
+ if (non_client_frame_view) {
+ // When using a custom drawn NonClientFrameView the native Window will not
+ // know the actual client bounds. Adjust the native Window bounds for the
+ // reported client bounds.
+ const gfx::Rect& client_bounds =
+ non_client_frame_view->GetBoundsForClientView();
+ bounds.set_origin(bounds.origin() + client_bounds.OffsetFromOrigin());
+ bounds.set_size(client_bounds.size());
+ }
+
+ return CefRect(bounds.x(), bounds.y(), bounds.width(), bounds.height());
+ }
+ return CefRect();
+}
+
+void CefWindowImpl::SetDraggableRegions(
+ const std::vector<CefDraggableRegion>& regions) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ if (root_view()) {
+ root_view()->SetDraggableRegions(regions);
+ }
+}
+
+CefWindowHandle CefWindowImpl::GetWindowHandle() {
+ CEF_REQUIRE_VALID_RETURN(kNullWindowHandle);
+ return view_util::GetWindowHandle(widget_);
+}
+
+void CefWindowImpl::SendKeyPress(int key_code, uint32 event_flags) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ InitializeUITesting();
+
+ gfx::NativeWindow native_window = view_util::GetNativeWindow(widget_);
+ if (!native_window) {
+ return;
+ }
+
+ ui_controls::SendKeyPress(native_window,
+ static_cast<ui::KeyboardCode>(key_code),
+ !!(event_flags & EVENTFLAG_CONTROL_DOWN),
+ !!(event_flags & EVENTFLAG_SHIFT_DOWN),
+ !!(event_flags & EVENTFLAG_ALT_DOWN),
+ false); // Command key is not supported by Aura.
+}
+
+void CefWindowImpl::SendMouseMove(int screen_x, int screen_y) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ InitializeUITesting();
+
+ // Converts to pixel coordinates internally on Windows.
+ gfx::Point point(screen_x, screen_y);
+ ui_controls::SendMouseMove(point.x(), point.y());
+}
+
+void CefWindowImpl::SendMouseEvents(cef_mouse_button_type_t button,
+ bool mouse_down,
+ bool mouse_up) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ if (!mouse_down && !mouse_up) {
+ return;
+ }
+
+ InitializeUITesting();
+
+ ui_controls::MouseButton type = ui_controls::LEFT;
+ if (button == MBT_MIDDLE) {
+ type = ui_controls::MIDDLE;
+ } else if (button == MBT_RIGHT) {
+ type = ui_controls::RIGHT;
+ }
+
+ int state = 0;
+ if (mouse_down) {
+ state |= ui_controls::DOWN;
+ }
+ if (mouse_up) {
+ state |= ui_controls::UP;
+ }
+
+ ui_controls::SendMouseEvents(type, state);
+}
+
+void CefWindowImpl::SetAccelerator(int command_id,
+ int key_code,
+ bool shift_pressed,
+ bool ctrl_pressed,
+ bool alt_pressed) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ if (!widget_) {
+ return;
+ }
+
+ AcceleratorMap::const_iterator it = accelerator_map_.find(command_id);
+ if (it != accelerator_map_.end()) {
+ RemoveAccelerator(command_id);
+ }
+
+ int modifiers = 0;
+ if (shift_pressed) {
+ modifiers |= ui::EF_SHIFT_DOWN;
+ }
+ if (ctrl_pressed) {
+ modifiers |= ui::EF_CONTROL_DOWN;
+ }
+ if (alt_pressed) {
+ modifiers |= ui::EF_ALT_DOWN;
+ }
+ ui::Accelerator accelerator(static_cast<ui::KeyboardCode>(key_code),
+ modifiers);
+
+ accelerator_map_.insert(std::make_pair(command_id, accelerator));
+
+ views::FocusManager* focus_manager = widget_->GetFocusManager();
+ DCHECK(focus_manager);
+ focus_manager->RegisterAccelerator(
+ accelerator, ui::AcceleratorManager::kNormalPriority, this);
+}
+
+void CefWindowImpl::RemoveAccelerator(int command_id) {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ if (!widget_) {
+ return;
+ }
+
+ AcceleratorMap::iterator it = accelerator_map_.find(command_id);
+ if (it == accelerator_map_.end()) {
+ return;
+ }
+
+ ui::Accelerator accelerator = it->second;
+
+ accelerator_map_.erase(it);
+
+ views::FocusManager* focus_manager = widget_->GetFocusManager();
+ DCHECK(focus_manager);
+ focus_manager->UnregisterAccelerator(accelerator, this);
+}
+
+void CefWindowImpl::RemoveAllAccelerators() {
+ CEF_REQUIRE_VALID_RETURN_VOID();
+ if (!widget_) {
+ return;
+ }
+
+ accelerator_map_.clear();
+
+ views::FocusManager* focus_manager = widget_->GetFocusManager();
+ DCHECK(focus_manager);
+ focus_manager->UnregisterAccelerators(this);
+}
+
+CefWindowImpl::CefWindowImpl(CefRefPtr<CefWindowDelegate> delegate)
+ : ParentClass(delegate), widget_(nullptr), destroyed_(false) {}
+
+CefWindowView* CefWindowImpl::CreateRootView() {
+ return new CefWindowView(delegate(), this);
+}
+
+void CefWindowImpl::InitializeRootView() {
+ static_cast<CefWindowView*>(root_view())->Initialize();
+}
+
+void CefWindowImpl::CreateWidget(gfx::AcceleratedWidget parent_widget) {
+ DCHECK(!widget_);
+
+ root_view()->CreateWidget(parent_widget);
+ widget_ = root_view()->GetWidget();
+ DCHECK(widget_);
+
+#if defined(USE_AURA)
+ unhandled_key_event_handler_ =
+ std::make_unique<CefUnhandledKeyEventHandler>(this, widget_);
+#endif
+
+ // The Widget and root View are owned by the native window. Therefore don't
+ // keep an owned reference.
+ std::unique_ptr<views::View> view_ptr = view_util::PassOwnership(this);
+ [[maybe_unused]] views::View* view = view_ptr.release();
+}
diff --git a/libcef/browser/views/window_impl.h b/libcef/browser/views/window_impl.h
new file mode 100644
index 00000000..a226d0f8
--- /dev/null
+++ b/libcef/browser/views/window_impl.h
@@ -0,0 +1,168 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_VIEWS_WINDOW_IMPL_H_
+#define CEF_LIBCEF_BROWSER_VIEWS_WINDOW_IMPL_H_
+#pragma once
+
+#include <map>
+
+#include "include/views/cef_window.h"
+#include "include/views/cef_window_delegate.h"
+
+#include "libcef/browser/menu_model_impl.h"
+#include "libcef/browser/views/panel_impl.h"
+#include "libcef/browser/views/window_view.h"
+
+#include "ui/base/accelerators/accelerator.h"
+#include "ui/views/controls/menu/menu_runner.h"
+#include "ui/views/widget/widget.h"
+
+namespace views {
+class MenuButton;
+}
+
+class CefWindowImpl
+ : public CefPanelImpl<CefWindowView, CefWindow, CefWindowDelegate>,
+ public CefWindowView::Delegate,
+ public ui::AcceleratorTarget {
+ public:
+ using ParentClass = CefPanelImpl<CefWindowView, CefWindow, CefWindowDelegate>;
+
+ CefWindowImpl(const CefWindowImpl&) = delete;
+ CefWindowImpl& operator=(const CefWindowImpl&) = delete;
+
+ // Create a new CefWindow instance. |delegate| may be nullptr. |parent_widget|
+ // will be used when creating a Chrome child window.
+ static CefRefPtr<CefWindowImpl> Create(CefRefPtr<CefWindowDelegate> delegate,
+ gfx::AcceleratedWidget parent_widget);
+
+ // CefWindow methods:
+ void Show() override;
+ void Hide() override;
+ void CenterWindow(const CefSize& size) override;
+ void Close() override;
+ bool IsClosed() override;
+ void Activate() override;
+ void Deactivate() override;
+ bool IsActive() override;
+ void BringToTop() override;
+ void SetAlwaysOnTop(bool on_top) override;
+ bool IsAlwaysOnTop() override;
+ void Maximize() override;
+ void Minimize() override;
+ void Restore() override;
+ void SetFullscreen(bool fullscreen) override;
+ bool IsMaximized() override;
+ bool IsMinimized() override;
+ bool IsFullscreen() override;
+ void SetTitle(const CefString& title) override;
+ CefString GetTitle() override;
+ void SetWindowIcon(CefRefPtr<CefImage> image) override;
+ CefRefPtr<CefImage> GetWindowIcon() override;
+ void SetWindowAppIcon(CefRefPtr<CefImage> image) override;
+ CefRefPtr<CefImage> GetWindowAppIcon() override;
+ CefRefPtr<CefOverlayController> AddOverlayView(
+ CefRefPtr<CefView> view,
+ cef_docking_mode_t docking_mode) override;
+ void ShowMenu(CefRefPtr<CefMenuModel> menu_model,
+ const CefPoint& screen_point,
+ cef_menu_anchor_position_t anchor_position) override;
+ void CancelMenu() override;
+ CefRefPtr<CefDisplay> GetDisplay() override;
+ CefRect GetClientAreaBoundsInScreen() override;
+ void SetDraggableRegions(
+ const std::vector<CefDraggableRegion>& regions) override;
+ CefWindowHandle GetWindowHandle() override;
+ void SendKeyPress(int key_code, uint32 event_flags) override;
+ void SendMouseMove(int screen_x, int screen_y) override;
+ void SendMouseEvents(cef_mouse_button_type_t button,
+ bool mouse_down,
+ bool mouse_up) override;
+ void SetAccelerator(int command_id,
+ int key_code,
+ bool shift_pressed,
+ bool ctrl_pressed,
+ bool alt_pressed) override;
+ void RemoveAccelerator(int command_id) override;
+ void RemoveAllAccelerators() override;
+
+ // CefViewAdapter methods:
+ void Detach() override;
+
+ // CefPanel methods:
+ CefRefPtr<CefWindow> AsWindow() override { return this; }
+
+ // CefView methods:
+ void SetBounds(const CefRect& bounds) override;
+ CefRect GetBounds() override;
+ CefRect GetBoundsInScreen() override;
+ void SetSize(const CefSize& bounds) override;
+ void SetPosition(const CefPoint& position) override;
+ void SizeToPreferredSize() override;
+ void SetVisible(bool visible) override;
+ bool IsVisible() override;
+ bool IsDrawn() override;
+ void SetBackgroundColor(cef_color_t color) override;
+
+ // CefWindowView::Delegate methods:
+ bool CanWidgetClose() override;
+ void OnWindowClosing() override;
+ void OnWindowViewDeleted() override;
+
+ // CefViewAdapter methods:
+ std::string GetDebugType() override { return "Window"; }
+ void GetDebugInfo(base::Value::Dict* info, bool include_children) override;
+
+ // ui::AcceleratorTarget methods:
+ bool AcceleratorPressed(const ui::Accelerator& accelerator) override;
+ bool CanHandleAccelerators() const override;
+
+ // Called for key events that have not been handled by other controls in the
+ // window. Returns true if the event was handled.
+ bool OnKeyEvent(const CefKeyEvent& event);
+
+ void ShowMenu(views::MenuButton* menu_button,
+ CefRefPtr<CefMenuModel> menu_model,
+ const CefPoint& screen_point,
+ cef_menu_anchor_position_t anchor_position);
+ void MenuClosed();
+
+ views::Widget* widget() const { return widget_; }
+
+ private:
+ // Create a new implementation object.
+ // Always call Initialize() after creation.
+ // |delegate| may be nullptr.
+ explicit CefWindowImpl(CefRefPtr<CefWindowDelegate> delegate);
+
+ // CefViewImpl methods:
+ CefWindowView* CreateRootView() override;
+ void InitializeRootView() override;
+
+ // Initialize the Widget.
+ void CreateWidget(gfx::AcceleratedWidget parent_widget);
+
+ views::Widget* widget_;
+
+ // True if the window has been destroyed.
+ bool destroyed_;
+
+ // The currently active menu model and runner.
+ CefRefPtr<CefMenuModelImpl> menu_model_;
+ std::unique_ptr<views::MenuRunner> menu_runner_;
+
+ // Map of command_id to accelerator.
+ using AcceleratorMap = std::map<int, ui::Accelerator>;
+ AcceleratorMap accelerator_map_;
+
+#if defined(USE_AURA)
+ // Native widget's handler to receive events after the event target.
+ std::unique_ptr<ui::EventHandler> unhandled_key_event_handler_;
+#endif
+
+ IMPLEMENT_REFCOUNTING_DELETE_ON_UIT(CefWindowImpl);
+};
+
+#endif // CEF_LIBCEF_BROWSER_VIEWS_WINDOW_IMPL_H_
diff --git a/libcef/browser/views/window_view.cc b/libcef/browser/views/window_view.cc
new file mode 100644
index 00000000..0c5ee9eb
--- /dev/null
+++ b/libcef/browser/views/window_view.cc
@@ -0,0 +1,663 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#include "libcef/browser/views/window_view.h"
+
+#include "libcef/browser/chrome/views/chrome_browser_frame.h"
+#include "libcef/browser/image_impl.h"
+#include "libcef/browser/views/window_impl.h"
+#include "libcef/features/runtime.h"
+
+#include "ui/base/hit_test.h"
+#include "ui/views/widget/widget.h"
+#include "ui/views/window/native_frame_view.h"
+
+#if BUILDFLAG(IS_LINUX)
+#include "ui/ozone/buildflags.h"
+#if BUILDFLAG(OZONE_PLATFORM_X11)
+#include "ui/base/x/x11_util.h"
+#endif
+#endif
+
+#if BUILDFLAG(IS_WIN)
+#include "ui/display/screen.h"
+#include "ui/views/win/hwnd_util.h"
+#endif
+
+#if defined(USE_AURA)
+#include "ui/aura/window.h"
+#endif
+
+namespace {
+
+// Specialize ClientView to handle Widget-related events.
+class ClientViewEx : public views::ClientView {
+ public:
+ ClientViewEx(views::Widget* widget,
+ views::View* contents_view,
+ CefWindowView::Delegate* window_delegate)
+ : views::ClientView(widget, contents_view),
+ window_delegate_(window_delegate) {
+ DCHECK(window_delegate_);
+ }
+
+ ClientViewEx(const ClientViewEx&) = delete;
+ ClientViewEx& operator=(const ClientViewEx&) = delete;
+
+ views::CloseRequestResult OnWindowCloseRequested() override {
+ return window_delegate_->CanWidgetClose()
+ ? views::CloseRequestResult::kCanClose
+ : views::CloseRequestResult::kCannotClose;
+ }
+
+ private:
+ CefWindowView::Delegate* window_delegate_; // Not owned by this object.
+};
+
+// Extend NativeFrameView with draggable region handling.
+class NativeFrameViewEx : public views::NativeFrameView {
+ public:
+ NativeFrameViewEx(views::Widget* widget, CefWindowView* view)
+ : views::NativeFrameView(widget), widget_(widget), view_(view) {}
+
+ NativeFrameViewEx(const NativeFrameViewEx&) = delete;
+ NativeFrameViewEx& operator=(const NativeFrameViewEx&) = delete;
+
+ gfx::Rect GetWindowBoundsForClientBounds(
+ const gfx::Rect& client_bounds) const override {
+#if BUILDFLAG(IS_WIN)
+ // views::GetWindowBoundsForClientBounds() expects the input Rect to be in
+ // pixel coordinates. NativeFrameView does not implement this correctly so
+ // we need to provide our own implementation. See http://crbug.com/602692.
+ gfx::Rect pixel_bounds =
+ display::Screen::GetScreen()->DIPToScreenRectInWindow(
+ view_util::GetNativeWindow(widget_), client_bounds);
+ pixel_bounds = views::GetWindowBoundsForClientBounds(
+ static_cast<View*>(const_cast<NativeFrameViewEx*>(this)), pixel_bounds);
+ return display::Screen::GetScreen()->ScreenToDIPRectInWindow(
+ view_util::GetNativeWindow(widget_), pixel_bounds);
+#else
+ // Use the default implementation.
+ return views::NativeFrameView::GetWindowBoundsForClientBounds(
+ client_bounds);
+#endif
+ }
+
+ int NonClientHitTest(const gfx::Point& point) override {
+ if (widget_->IsFullscreen()) {
+ return HTCLIENT;
+ }
+
+ // Test for mouse clicks that fall within the draggable region.
+ SkRegion* draggable_region = view_->draggable_region();
+ if (draggable_region && draggable_region->contains(point.x(), point.y())) {
+ return HTCAPTION;
+ }
+
+ return views::NativeFrameView::NonClientHitTest(point);
+ }
+
+ private:
+ // Not owned by this object.
+ views::Widget* widget_;
+ CefWindowView* view_;
+};
+
+// The area inside the frame border that can be clicked and dragged for resizing
+// the window. Only used in restored mode.
+const int kResizeBorderThickness = 4;
+
+// The distance from each window corner that triggers diagonal resizing. Only
+// used in restored mode.
+const int kResizeAreaCornerSize = 16;
+
+// Implement NonClientFrameView without the system default caption and icon but
+// with a resizable border. Based on AppWindowFrameView and CustomFrameView.
+class CaptionlessFrameView : public views::NonClientFrameView {
+ public:
+ CaptionlessFrameView(views::Widget* widget, CefWindowView* view)
+ : widget_(widget), view_(view) {}
+
+ CaptionlessFrameView(const CaptionlessFrameView&) = delete;
+ CaptionlessFrameView& operator=(const CaptionlessFrameView&) = delete;
+
+ gfx::Rect GetBoundsForClientView() const override {
+ return client_view_bounds_;
+ }
+
+ gfx::Rect GetWindowBoundsForClientBounds(
+ const gfx::Rect& client_bounds) const override {
+ return client_bounds;
+ }
+
+ int NonClientHitTest(const gfx::Point& point) override {
+ if (widget_->IsFullscreen()) {
+ return HTCLIENT;
+ }
+
+ // Sanity check.
+ if (!bounds().Contains(point)) {
+ return HTNOWHERE;
+ }
+
+ // Check the frame first, as we allow a small area overlapping the contents
+ // to be used for resize handles.
+ bool can_ever_resize = widget_->widget_delegate()
+ ? widget_->widget_delegate()->CanResize()
+ : false;
+ // Don't allow overlapping resize handles when the window is maximized or
+ // fullscreen, as it can't be resized in those states.
+ int resize_border_thickness = ResizeBorderThickness();
+ int frame_component = GetHTComponentForFrame(
+ point,
+ gfx::Insets::VH(resize_border_thickness, resize_border_thickness),
+ kResizeAreaCornerSize, kResizeAreaCornerSize, can_ever_resize);
+ if (frame_component != HTNOWHERE) {
+ return frame_component;
+ }
+
+ // Test for mouse clicks that fall within the draggable region.
+ SkRegion* draggable_region = view_->draggable_region();
+ if (draggable_region && draggable_region->contains(point.x(), point.y())) {
+ return HTCAPTION;
+ }
+
+ int client_component = widget_->client_view()->NonClientHitTest(point);
+ if (client_component != HTNOWHERE) {
+ return client_component;
+ }
+
+ // Caption is a safe default.
+ return HTCAPTION;
+ }
+
+ void GetWindowMask(const gfx::Size& size, SkPath* window_mask) override {
+ // Nothing to do here.
+ }
+
+ void ResetWindowControls() override {
+ // Nothing to do here.
+ }
+
+ void UpdateWindowIcon() override {
+ // Nothing to do here.
+ }
+
+ void UpdateWindowTitle() override {
+ // Nothing to do here.
+ }
+
+ void SizeConstraintsChanged() override {
+ // Nothing to do here.
+ }
+
+ void OnPaint(gfx::Canvas* canvas) override {
+ // Nothing to do here.
+ }
+
+ void Layout() override {
+ client_view_bounds_.SetRect(0, 0, width(), height());
+ views::NonClientFrameView::Layout();
+ }
+
+ gfx::Size CalculatePreferredSize() const override {
+ return widget_->non_client_view()
+ ->GetWindowBoundsForClientBounds(
+ gfx::Rect(widget_->client_view()->GetPreferredSize()))
+ .size();
+ }
+
+ gfx::Size GetMinimumSize() const override {
+ return widget_->non_client_view()
+ ->GetWindowBoundsForClientBounds(
+ gfx::Rect(widget_->client_view()->GetMinimumSize()))
+ .size();
+ }
+
+ gfx::Size GetMaximumSize() const override {
+ gfx::Size max_size = widget_->client_view()->GetMaximumSize();
+ gfx::Size converted_size =
+ widget_->non_client_view()
+ ->GetWindowBoundsForClientBounds(gfx::Rect(max_size))
+ .size();
+ return gfx::Size(max_size.width() == 0 ? 0 : converted_size.width(),
+ max_size.height() == 0 ? 0 : converted_size.height());
+ }
+
+ private:
+ int ResizeBorderThickness() const {
+ return (widget_->IsMaximized() || widget_->IsFullscreen()
+ ? 0
+ : kResizeBorderThickness);
+ }
+
+ // Not owned by this object.
+ views::Widget* widget_;
+ CefWindowView* view_;
+
+ // The bounds of the client view, in this view's coordinates.
+ gfx::Rect client_view_bounds_;
+};
+
+bool IsWindowBorderHit(int code) {
+// On Windows HTLEFT = 10 and HTBORDER = 18. Values are not ordered the same
+// in base/hit_test.h for non-Windows platforms.
+#if BUILDFLAG(IS_WIN)
+ return code >= HTLEFT && code <= HTBORDER;
+#else
+ return code == HTLEFT || code == HTRIGHT || code == HTTOP ||
+ code == HTTOPLEFT || code == HTTOPRIGHT || code == HTBOTTOM ||
+ code == HTBOTTOMLEFT || code == HTBOTTOMRIGHT || code == HTBORDER;
+#endif
+}
+
+} // namespace
+
+CefWindowView::CefWindowView(CefWindowDelegate* cef_delegate,
+ Delegate* window_delegate)
+ : ParentClass(cef_delegate),
+ window_delegate_(window_delegate),
+ is_frameless_(false) {
+ DCHECK(window_delegate_);
+}
+
+void CefWindowView::CreateWidget(gfx::AcceleratedWidget parent_widget) {
+ DCHECK(!GetWidget());
+
+ // |widget| is owned by the NativeWidget and will be destroyed in response to
+ // a native destruction message.
+ views::Widget* widget = cef::IsChromeRuntimeEnabled() ? new ChromeBrowserFrame
+ : new views::Widget;
+
+ views::Widget::InitParams params;
+ params.delegate = this;
+
+ bool can_activate = true;
+ bool can_resize = true;
+
+ const bool has_native_parent = parent_widget != gfx::kNullAcceleratedWidget;
+ if (has_native_parent) {
+ params.parent_widget = parent_widget;
+
+ // Remove the window frame.
+ is_frameless_ = true;
+
+ // See CalculateWindowStylesFromInitParams in
+ // ui/views/widget/widget_hwnd_utils.cc for the conversion of |params| to
+ // Windows style flags.
+ // - Set the WS_CHILD flag.
+ params.child = true;
+ // - Set the WS_VISIBLE flag.
+ params.type = views::Widget::InitParams::TYPE_CONTROL;
+ // - Don't set the WS_EX_COMPOSITED flag.
+ params.opacity = views::Widget::InitParams::WindowOpacity::kOpaque;
+ } else {
+ params.type = views::Widget::InitParams::TYPE_WINDOW;
+ }
+
+ // WidgetDelegate::DeleteDelegate() will delete |this| after executing the
+ // registered callback.
+ SetOwnedByWidget(true);
+ RegisterDeleteDelegateCallback(
+ base::BindOnce(&CefWindowView::DeleteDelegate, base::Unretained(this)));
+
+ if (cef_delegate()) {
+ CefRefPtr<CefWindow> cef_window = GetCefWindow();
+
+ auto bounds = cef_delegate()->GetInitialBounds(cef_window);
+ params.bounds = gfx::Rect(bounds.x, bounds.y, bounds.width, bounds.height);
+
+ if (has_native_parent) {
+ DCHECK(!params.bounds.IsEmpty());
+ } else {
+ is_frameless_ = cef_delegate()->IsFrameless(cef_window);
+
+ params.native_widget =
+ view_util::CreateNativeWidget(widget, cef_window, cef_delegate());
+
+ can_resize = cef_delegate()->CanResize(cef_window);
+
+ const auto show_state = cef_delegate()->GetInitialShowState(cef_window);
+ switch (show_state) {
+ case CEF_SHOW_STATE_NORMAL:
+ params.show_state = ui::SHOW_STATE_NORMAL;
+ break;
+ case CEF_SHOW_STATE_MINIMIZED:
+ params.show_state = ui::SHOW_STATE_MINIMIZED;
+ break;
+ case CEF_SHOW_STATE_MAXIMIZED:
+ params.show_state = ui::SHOW_STATE_MAXIMIZED;
+ break;
+ case CEF_SHOW_STATE_FULLSCREEN:
+ params.show_state = ui::SHOW_STATE_FULLSCREEN;
+ break;
+ }
+
+ bool is_menu = false;
+ bool can_activate_menu = true;
+ CefRefPtr<CefWindow> parent_window = cef_delegate()->GetParentWindow(
+ cef_window, &is_menu, &can_activate_menu);
+ if (parent_window && !parent_window->IsSame(cef_window)) {
+ CefWindowImpl* parent_window_impl =
+ static_cast<CefWindowImpl*>(parent_window.get());
+ params.parent = view_util::GetNativeView(parent_window_impl->widget());
+ if (is_menu) {
+ // Don't clip the window to parent bounds.
+ params.type = views::Widget::InitParams::TYPE_MENU;
+
+ // Don't set "always on top" for the window.
+ params.z_order = ui::ZOrderLevel::kNormal;
+
+ can_activate = can_activate_menu;
+ }
+ }
+ }
+ }
+
+ if (params.bounds.IsEmpty()) {
+ // The window will be placed on the default screen with origin (0,0).
+ params.bounds = gfx::Rect(CalculatePreferredSize());
+ if (params.bounds.IsEmpty()) {
+ // Choose a reasonable default size.
+ params.bounds.set_size({800, 600});
+ }
+ }
+
+ if (can_activate) {
+ // Cause WidgetDelegate::CanActivate to return true.
+ params.activatable = views::Widget::InitParams::Activatable::kYes;
+ }
+
+ SetCanResize(can_resize);
+
+#if BUILDFLAG(IS_WIN)
+ if (is_frameless_) {
+ // Don't show the native window caption. Setting this value on Linux will
+ // result in window resize artifacts.
+ params.remove_standard_frame = true;
+ }
+#endif
+
+ widget->Init(std::move(params));
+ widget->AddObserver(this);
+
+ // |widget| should now be associated with |this|.
+ DCHECK_EQ(widget, GetWidget());
+ // |widget| must be top-level for focus handling to work correctly.
+ DCHECK(widget->is_top_level());
+
+ if (can_activate) {
+ // |widget| must be activatable for focus handling to work correctly.
+ DCHECK(widget->widget_delegate()->CanActivate());
+ }
+
+#if BUILDFLAG(IS_LINUX)
+#if BUILDFLAG(OZONE_PLATFORM_X11)
+ if (is_frameless_) {
+ auto window = view_util::GetWindowHandle(widget);
+ DCHECK(window);
+ ui::SetUseOSWindowFrame(static_cast<x11::Window>(window), false);
+ }
+#endif
+#endif
+}
+
+CefRefPtr<CefWindow> CefWindowView::GetCefWindow() const {
+ CefRefPtr<CefWindow> window = GetCefPanel()->AsWindow();
+ DCHECK(window);
+ return window;
+}
+
+void CefWindowView::DeleteDelegate() {
+ // Remove all child Views before deleting the Window so that notifications
+ // resolve correctly.
+ RemoveAllChildViews();
+
+ window_delegate_->OnWindowViewDeleted();
+}
+
+bool CefWindowView::CanMinimize() const {
+ if (!cef_delegate()) {
+ return true;
+ }
+ return cef_delegate()->CanMinimize(GetCefWindow());
+}
+
+bool CefWindowView::CanMaximize() const {
+ if (!cef_delegate()) {
+ return true;
+ }
+ return cef_delegate()->CanMaximize(GetCefWindow());
+}
+
+std::u16string CefWindowView::GetWindowTitle() const {
+ return title_;
+}
+
+ui::ImageModel CefWindowView::GetWindowIcon() {
+ if (!window_icon_) {
+ return ParentClass::GetWindowIcon();
+ }
+ auto image_skia =
+ static_cast<CefImageImpl*>(window_icon_.get())
+ ->GetForced1xScaleRepresentation(GetDisplay().device_scale_factor());
+ return ui::ImageModel::FromImageSkia(image_skia);
+}
+
+ui::ImageModel CefWindowView::GetWindowAppIcon() {
+ if (!window_app_icon_) {
+ return ParentClass::GetWindowAppIcon();
+ }
+ auto image_skia =
+ static_cast<CefImageImpl*>(window_app_icon_.get())
+ ->GetForced1xScaleRepresentation(GetDisplay().device_scale_factor());
+ return ui::ImageModel::FromImageSkia(image_skia);
+}
+
+void CefWindowView::WindowClosing() {
+ window_delegate_->OnWindowClosing();
+}
+
+views::View* CefWindowView::GetContentsView() {
+ // |this| will be the "Contents View" hosted by the Widget via ClientView and
+ // RootView.
+ return this;
+}
+
+views::ClientView* CefWindowView::CreateClientView(views::Widget* widget) {
+ return new ClientViewEx(widget, GetContentsView(), window_delegate_);
+}
+
+std::unique_ptr<views::NonClientFrameView>
+CefWindowView::CreateNonClientFrameView(views::Widget* widget) {
+ if (is_frameless_) {
+ // Custom frame type that doesn't render a caption.
+ return std::make_unique<CaptionlessFrameView>(widget, this);
+ } else if (widget->ShouldUseNativeFrame()) {
+ // DesktopNativeWidgetAura::CreateNonClientFrameView() returns
+ // NativeFrameView by default. Extend that type.
+ return std::make_unique<NativeFrameViewEx>(widget, this);
+ }
+
+ // Use Chromium provided CustomFrameView. In case if we would like to
+ // customize the frame, provide own implementation.
+ return nullptr;
+}
+
+bool CefWindowView::ShouldDescendIntoChildForEventHandling(
+ gfx::NativeView child,
+ const gfx::Point& location) {
+ if (is_frameless_) {
+ // If the window is resizable it should claim mouse events that fall on the
+ // window border.
+ views::NonClientFrameView* ncfv = GetNonClientFrameView();
+ if (ncfv) {
+ int result = ncfv->NonClientHitTest(location);
+ if (IsWindowBorderHit(result)) {
+ return false;
+ }
+ }
+ }
+
+ // The window should claim mouse events that fall within the draggable region.
+ return !draggable_region_.get() ||
+ !draggable_region_->contains(location.x(), location.y());
+}
+
+bool CefWindowView::MaybeGetMinimumSize(gfx::Size* size) const {
+#if BUILDFLAG(IS_LINUX)
+ // Resize is disabled on Linux by returning the preferred size as the min/max
+ // size.
+ if (!CanResize()) {
+ *size = CalculatePreferredSize();
+ return true;
+ }
+#endif
+ return false;
+}
+
+bool CefWindowView::MaybeGetMaximumSize(gfx::Size* size) const {
+#if BUILDFLAG(IS_LINUX)
+ // Resize is disabled on Linux by returning the preferred size as the min/max
+ // size.
+ if (!CanResize()) {
+ *size = CalculatePreferredSize();
+ return true;
+ }
+#endif
+ return false;
+}
+
+void CefWindowView::ViewHierarchyChanged(
+ const views::ViewHierarchyChangedDetails& details) {
+ if (details.child == this) {
+ // This View's parent types (RootView, ClientView) are not exposed via the
+ // CEF API. Therefore don't send notifications about this View's parent
+ // changes.
+ return;
+ }
+
+ ParentClass::ViewHierarchyChanged(details);
+}
+
+void CefWindowView::OnWidgetActivationChanged(views::Widget* widget,
+ bool active) {
+ if (cef_delegate()) {
+ cef_delegate()->OnWindowActivationChanged(GetCefWindow(), active);
+ }
+}
+
+void CefWindowView::OnWidgetBoundsChanged(views::Widget* widget,
+ const gfx::Rect& new_bounds) {
+ MoveOverlaysIfNecessary();
+
+ if (cef_delegate()) {
+ cef_delegate()->OnWindowBoundsChanged(
+ GetCefWindow(), {new_bounds.x(), new_bounds.y(), new_bounds.width(),
+ new_bounds.height()});
+ }
+}
+
+display::Display CefWindowView::GetDisplay() const {
+ const views::Widget* widget = GetWidget();
+ if (widget) {
+ return view_util::GetDisplayMatchingBounds(
+ widget->GetWindowBoundsInScreen(), false);
+ }
+ return display::Display();
+}
+
+void CefWindowView::SetTitle(const std::u16string& title) {
+ title_ = title;
+ views::Widget* widget = GetWidget();
+ if (widget) {
+ widget->UpdateWindowTitle();
+ }
+}
+
+void CefWindowView::SetWindowIcon(CefRefPtr<CefImage> window_icon) {
+ if (std::max(window_icon->GetWidth(), window_icon->GetHeight()) != 16U) {
+ DLOG(ERROR) << "Window icons must be 16 DIP in size.";
+ return;
+ }
+
+ window_icon_ = window_icon;
+ views::Widget* widget = GetWidget();
+ if (widget) {
+ widget->UpdateWindowIcon();
+ }
+}
+
+void CefWindowView::SetWindowAppIcon(CefRefPtr<CefImage> window_app_icon) {
+ window_app_icon_ = window_app_icon;
+ views::Widget* widget = GetWidget();
+ if (widget) {
+ widget->UpdateWindowIcon();
+ }
+}
+
+CefRefPtr<CefOverlayController> CefWindowView::AddOverlayView(
+ CefRefPtr<CefView> view,
+ cef_docking_mode_t docking_mode) {
+ DCHECK(view.get());
+ DCHECK(view->IsValid());
+ if (!view.get() || !view->IsValid()) {
+ return nullptr;
+ }
+
+ views::Widget* widget = GetWidget();
+ if (widget) {
+ // Owned by the View hierarchy. Acts as a z-order reference for the overlay.
+ auto overlay_host_view = AddChildView(std::make_unique<views::View>());
+
+ overlay_hosts_.push_back(
+ std::make_unique<CefOverlayViewHost>(this, docking_mode));
+
+ auto& overlay_host = overlay_hosts_.back();
+ overlay_host->Init(overlay_host_view, view);
+
+ return overlay_host->controller();
+ }
+
+ return nullptr;
+}
+
+void CefWindowView::MoveOverlaysIfNecessary() {
+ if (overlay_hosts_.empty()) {
+ return;
+ }
+ for (auto& overlay_host : overlay_hosts_) {
+ overlay_host->MoveIfNecessary();
+ }
+}
+
+void CefWindowView::SetDraggableRegions(
+ const std::vector<CefDraggableRegion>& regions) {
+ if (regions.empty()) {
+ if (draggable_region_) {
+ draggable_region_.reset(nullptr);
+ }
+ return;
+ }
+
+ draggable_region_.reset(new SkRegion);
+ for (const CefDraggableRegion& region : regions) {
+ draggable_region_->op(
+ {region.bounds.x, region.bounds.y,
+ region.bounds.x + region.bounds.width,
+ region.bounds.y + region.bounds.height},
+ region.draggable ? SkRegion::kUnion_Op : SkRegion::kDifference_Op);
+ }
+}
+
+views::NonClientFrameView* CefWindowView::GetNonClientFrameView() const {
+ const views::Widget* widget = GetWidget();
+ if (!widget) {
+ return nullptr;
+ }
+ if (!widget->non_client_view()) {
+ return nullptr;
+ }
+ return widget->non_client_view()->frame_view();
+}
diff --git a/libcef/browser/views/window_view.h b/libcef/browser/views/window_view.h
new file mode 100644
index 00000000..6789636b
--- /dev/null
+++ b/libcef/browser/views/window_view.h
@@ -0,0 +1,138 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_VIEWS_WINDOW_VIEW_H_
+#define CEF_LIBCEF_BROWSER_VIEWS_WINDOW_VIEW_H_
+#pragma once
+
+#include <vector>
+
+#include "include/views/cef_window.h"
+#include "include/views/cef_window_delegate.h"
+
+#include "libcef/browser/views/overlay_view_host.h"
+#include "libcef/browser/views/panel_view.h"
+
+#include "third_party/skia/include/core/SkRegion.h"
+#include "ui/display/display.h"
+#include "ui/views/widget/widget_delegate.h"
+#include "ui/views/widget/widget_observer.h"
+
+// Manages the views-based root window. This object will be deleted
+// automatically when the associated root window is destroyed.
+class CefWindowView
+ : public CefPanelView<views::WidgetDelegateView, CefWindowDelegate>,
+ public views::WidgetObserver {
+ public:
+ using ParentClass =
+ CefPanelView<views::WidgetDelegateView, CefWindowDelegate>;
+
+ class Delegate {
+ public:
+ // Returns true to signal that the Widget can be closed.
+ virtual bool CanWidgetClose() = 0;
+
+ // Called when the underlying platform window is closing.
+ virtual void OnWindowClosing() = 0;
+
+ // Called when the WindowView is about to be deleted.
+ virtual void OnWindowViewDeleted() = 0;
+
+ protected:
+ virtual ~Delegate() {}
+ };
+
+ // |cef_delegate| may be nullptr.
+ // |window_delegate| must be non-nullptr.
+ CefWindowView(CefWindowDelegate* cef_delegate, Delegate* window_delegate);
+
+ CefWindowView(const CefWindowView&) = delete;
+ CefWindowView& operator=(const CefWindowView&) = delete;
+
+ // Create the Widget.
+ void CreateWidget(gfx::AcceleratedWidget parent_widget);
+
+ // Returns the CefWindow associated with this view. See comments on
+ // CefViewView::GetCefView.
+ CefRefPtr<CefWindow> GetCefWindow() const;
+
+ // views::WidgetDelegate methods:
+ bool CanMinimize() const override;
+ bool CanMaximize() const override;
+ std::u16string GetWindowTitle() const override;
+ ui::ImageModel GetWindowIcon() override;
+ ui::ImageModel GetWindowAppIcon() override;
+ void WindowClosing() override;
+ views::View* GetContentsView() override;
+ views::ClientView* CreateClientView(views::Widget* widget) override;
+ std::unique_ptr<views::NonClientFrameView> CreateNonClientFrameView(
+ views::Widget* widget) override;
+ bool ShouldDescendIntoChildForEventHandling(
+ gfx::NativeView child,
+ const gfx::Point& location) override;
+ bool MaybeGetMinimumSize(gfx::Size* size) const override;
+ bool MaybeGetMaximumSize(gfx::Size* size) const override;
+
+ // views::View methods:
+ void ViewHierarchyChanged(
+ const views::ViewHierarchyChangedDetails& details) override;
+
+ // views::WidgetObserver methods:
+ void OnWidgetActivationChanged(views::Widget* widget, bool active) override;
+ void OnWidgetBoundsChanged(views::Widget* widget,
+ const gfx::Rect& new_bounds) override;
+
+ // Returns the Display containing this Window.
+ display::Display GetDisplay() const;
+
+ // Set/get the window title.
+ void SetTitle(const std::u16string& title);
+ std::u16string title() const { return title_; }
+
+ // Set/get the window icon. This should be a 16x16 icon suitable for use in
+ // the Windows's title bar.
+ void SetWindowIcon(CefRefPtr<CefImage> window_icon);
+ CefRefPtr<CefImage> window_icon() const { return window_icon_; }
+
+ // Set/get the window app icon. This should be a larger icon for use in the
+ // host environment app switching UI. On Windows, this is the ICON_BIG used in
+ // Alt-Tab list and Windows taskbar. The Window icon will be used by default
+ // if no Window App icon is specified.
+ void SetWindowAppIcon(CefRefPtr<CefImage> window_app_icon);
+ CefRefPtr<CefImage> window_app_icon() const { return window_app_icon_; }
+
+ CefRefPtr<CefOverlayController> AddOverlayView(
+ CefRefPtr<CefView> view,
+ cef_docking_mode_t docking_mode);
+
+ // Set/get the draggable regions.
+ void SetDraggableRegions(const std::vector<CefDraggableRegion>& regions);
+ SkRegion* draggable_region() const { return draggable_region_.get(); }
+
+ // Returns the NonClientFrameView for this Window. May be nullptr.
+ views::NonClientFrameView* GetNonClientFrameView() const;
+
+ private:
+ // Called when removed from the Widget and before |this| is deleted.
+ void DeleteDelegate();
+
+ void MoveOverlaysIfNecessary();
+
+ // Not owned by this object.
+ Delegate* window_delegate_;
+
+ // True if the window is frameless. It might still be resizable and draggable.
+ bool is_frameless_;
+
+ std::u16string title_;
+ CefRefPtr<CefImage> window_icon_;
+ CefRefPtr<CefImage> window_app_icon_;
+
+ std::unique_ptr<SkRegion> draggable_region_;
+
+ // Hosts for overlay widgets.
+ std::vector<std::unique_ptr<CefOverlayViewHost>> overlay_hosts_;
+};
+
+#endif // CEF_LIBCEF_BROWSER_VIEWS_WINDOW_VIEW_H_
diff --git a/libcef/browser/x509_cert_principal_impl.cc b/libcef/browser/x509_cert_principal_impl.cc
new file mode 100644
index 00000000..58922f02
--- /dev/null
+++ b/libcef/browser/x509_cert_principal_impl.cc
@@ -0,0 +1,67 @@
+// Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "libcef/browser/x509_cert_principal_impl.h"
+
+namespace {
+
+void TransferVector(const std::vector<std::string>& source,
+ std::vector<CefString>& target) {
+ if (!target.empty()) {
+ target.clear();
+ }
+
+ if (!source.empty()) {
+ std::vector<std::string>::const_iterator it = source.begin();
+ for (; it != source.end(); ++it) {
+ target.push_back(*it);
+ }
+ }
+}
+
+} // namespace
+
+CefX509CertPrincipalImpl::CefX509CertPrincipalImpl(
+ const net::CertPrincipal& value)
+ : value_(value) {}
+
+CefString CefX509CertPrincipalImpl::GetDisplayName() {
+ return value_.GetDisplayName();
+}
+
+CefString CefX509CertPrincipalImpl::GetCommonName() {
+ return value_.common_name;
+}
+
+CefString CefX509CertPrincipalImpl::GetLocalityName() {
+ return value_.locality_name;
+}
+
+CefString CefX509CertPrincipalImpl::GetStateOrProvinceName() {
+ return value_.state_or_province_name;
+}
+
+CefString CefX509CertPrincipalImpl::GetCountryName() {
+ return value_.country_name;
+}
+
+void CefX509CertPrincipalImpl::GetStreetAddresses(
+ std::vector<CefString>& addresses) {
+ TransferVector(value_.street_addresses, addresses);
+}
+
+void CefX509CertPrincipalImpl::GetOrganizationNames(
+ std::vector<CefString>& names) {
+ TransferVector(value_.organization_names, names);
+}
+
+void CefX509CertPrincipalImpl::GetOrganizationUnitNames(
+ std::vector<CefString>& names) {
+ TransferVector(value_.organization_unit_names, names);
+}
+
+void CefX509CertPrincipalImpl::GetDomainComponents(
+ std::vector<CefString>& components) {
+ TransferVector(value_.domain_components, components);
+}
diff --git a/libcef/browser/x509_cert_principal_impl.h b/libcef/browser/x509_cert_principal_impl.h
new file mode 100644
index 00000000..59f9fb8e
--- /dev/null
+++ b/libcef/browser/x509_cert_principal_impl.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_X509_CERT_PRINCIPAL_IMPL_H_
+#define CEF_LIBCEF_BROWSER_X509_CERT_PRINCIPAL_IMPL_H_
+#pragma once
+
+#include "include/cef_x509_certificate.h"
+
+#include "net/cert/x509_cert_types.h"
+
+// CefX509CertPrincipal implementation
+class CefX509CertPrincipalImpl : public CefX509CertPrincipal {
+ public:
+ explicit CefX509CertPrincipalImpl(const net::CertPrincipal& value);
+
+ CefX509CertPrincipalImpl(const CefX509CertPrincipalImpl&) = delete;
+ CefX509CertPrincipalImpl& operator=(const CefX509CertPrincipalImpl&) = delete;
+
+ // CefX509CertPrincipal methods.
+ CefString GetDisplayName() override;
+ CefString GetCommonName() override;
+ CefString GetLocalityName() override;
+ CefString GetStateOrProvinceName() override;
+ CefString GetCountryName() override;
+ void GetStreetAddresses(std::vector<CefString>& addresses) override;
+ void GetOrganizationNames(std::vector<CefString>& names) override;
+ void GetOrganizationUnitNames(std::vector<CefString>& names) override;
+ void GetDomainComponents(std::vector<CefString>& components) override;
+
+ private:
+ net::CertPrincipal value_;
+
+ IMPLEMENT_REFCOUNTING(CefX509CertPrincipalImpl);
+};
+
+#endif // CEF_LIBCEF_BROWSER_X509_CERT_PRINCIPAL_IMPL_H_
diff --git a/libcef/browser/x509_certificate_impl.cc b/libcef/browser/x509_certificate_impl.cc
new file mode 100644
index 00000000..2aeb00bb
--- /dev/null
+++ b/libcef/browser/x509_certificate_impl.cc
@@ -0,0 +1,140 @@
+// Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "libcef/browser/x509_certificate_impl.h"
+
+#include "libcef/browser/x509_cert_principal_impl.h"
+#include "libcef/common/time_util.h"
+
+#include "net/cert/x509_util.h"
+#include "net/ssl/ssl_private_key.h"
+
+namespace {
+
+CefRefPtr<CefBinaryValue> EncodeCertificate(const CRYPTO_BUFFER* cert_buffer,
+ bool der) {
+ std::string encoded;
+ if (der) {
+ encoded =
+ std::string(net::x509_util::CryptoBufferAsStringPiece(cert_buffer));
+ } else if (!net::X509Certificate::GetPEMEncoded(cert_buffer, &encoded)) {
+ return nullptr;
+ }
+ if (encoded.empty()) {
+ return nullptr;
+ }
+ return CefBinaryValue::Create(encoded.c_str(), encoded.size());
+}
+
+} // namespace
+
+CefX509CertificateImpl::CefX509CertificateImpl(
+ std::unique_ptr<net::ClientCertIdentity> identity)
+ : identity_(std::move(identity)), cert_(identity_->certificate()) {}
+
+CefX509CertificateImpl::CefX509CertificateImpl(
+ scoped_refptr<net::X509Certificate> cert)
+ : cert_(cert) {}
+
+CefRefPtr<CefX509CertPrincipal> CefX509CertificateImpl::GetSubject() {
+ if (cert_) {
+ return new CefX509CertPrincipalImpl(cert_->subject());
+ }
+ return nullptr;
+}
+
+CefRefPtr<CefX509CertPrincipal> CefX509CertificateImpl::GetIssuer() {
+ if (cert_) {
+ return new CefX509CertPrincipalImpl(cert_->issuer());
+ }
+ return nullptr;
+}
+
+CefRefPtr<CefBinaryValue> CefX509CertificateImpl::GetSerialNumber() {
+ if (cert_) {
+ const std::string& serial = cert_->serial_number();
+ return CefBinaryValue::Create(serial.c_str(), serial.size());
+ }
+ return nullptr;
+}
+
+CefBaseTime CefX509CertificateImpl::GetValidStart() {
+ if (cert_) {
+ return cert_->valid_start();
+ }
+ return CefBaseTime();
+}
+
+CefBaseTime CefX509CertificateImpl::GetValidExpiry() {
+ if (cert_) {
+ return cert_->valid_expiry();
+ }
+ return CefBaseTime();
+}
+
+CefRefPtr<CefBinaryValue> CefX509CertificateImpl::GetDEREncoded() {
+ if (cert_) {
+ const CRYPTO_BUFFER* cert_buffer = cert_->cert_buffer();
+ if (cert_buffer) {
+ return EncodeCertificate(cert_buffer, true);
+ }
+ }
+ return nullptr;
+}
+
+CefRefPtr<CefBinaryValue> CefX509CertificateImpl::GetPEMEncoded() {
+ if (cert_) {
+ const CRYPTO_BUFFER* cert_buffer = cert_->cert_buffer();
+ if (cert_buffer) {
+ return EncodeCertificate(cert_buffer, false);
+ }
+ }
+ return nullptr;
+}
+
+size_t CefX509CertificateImpl::GetIssuerChainSize() {
+ if (cert_) {
+ return cert_->intermediate_buffers().size();
+ }
+ return 0;
+}
+
+void CefX509CertificateImpl::AcquirePrivateKey(
+ base::OnceCallback<void(scoped_refptr<net::SSLPrivateKey>)>
+ private_key_callback) {
+ if (identity_) {
+ identity_->AcquirePrivateKey(std::move(private_key_callback));
+ } else {
+ std::move(private_key_callback).Run(nullptr);
+ }
+}
+
+void CefX509CertificateImpl::GetEncodedIssuerChain(
+ CefX509Certificate::IssuerChainBinaryList& chain,
+ bool der) {
+ chain.clear();
+ if (cert_) {
+ for (const auto& it : cert_->intermediate_buffers()) {
+ // Add each to the chain, even if one conversion unexpectedly failed.
+ // GetIssuerChainSize depends on these being the same length.
+ chain.push_back(EncodeCertificate(it.get(), der));
+ }
+ }
+}
+
+void CefX509CertificateImpl::GetDEREncodedIssuerChain(
+ CefX509Certificate::IssuerChainBinaryList& chain) {
+ if (der_encoded_issuer_chain_.empty()) {
+ GetEncodedIssuerChain(der_encoded_issuer_chain_, true);
+ }
+ chain = der_encoded_issuer_chain_;
+}
+
+void CefX509CertificateImpl::GetPEMEncodedIssuerChain(
+ CefX509Certificate::IssuerChainBinaryList& chain) {
+ if (pem_encoded_issuer_chain_.empty()) {
+ GetEncodedIssuerChain(pem_encoded_issuer_chain_, false);
+ }
+ chain = pem_encoded_issuer_chain_;
+}
diff --git a/libcef/browser/x509_certificate_impl.h b/libcef/browser/x509_certificate_impl.h
new file mode 100644
index 00000000..5178ca39
--- /dev/null
+++ b/libcef/browser/x509_certificate_impl.h
@@ -0,0 +1,55 @@
+// Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_X509_CERTIFICATE_IMPL_H_
+#define CEF_LIBCEF_BROWSER_X509_CERTIFICATE_IMPL_H_
+#pragma once
+
+#include "include/cef_x509_certificate.h"
+
+#include <memory>
+
+#include "net/ssl/client_cert_identity.h"
+
+// CefX509Certificate implementation
+class CefX509CertificateImpl : public CefX509Certificate {
+ public:
+ explicit CefX509CertificateImpl(scoped_refptr<net::X509Certificate> cert);
+
+ CefX509CertificateImpl(const CefX509CertificateImpl&) = delete;
+ CefX509CertificateImpl& operator=(const CefX509CertificateImpl&) = delete;
+
+ // Used with AlloyContentBrowserClient::SelectClientCertificate only.
+ explicit CefX509CertificateImpl(
+ std::unique_ptr<net::ClientCertIdentity> identity);
+
+ // CefX509Certificate methods.
+ CefRefPtr<CefX509CertPrincipal> GetSubject() override;
+ CefRefPtr<CefX509CertPrincipal> GetIssuer() override;
+ CefRefPtr<CefBinaryValue> GetSerialNumber() override;
+ CefBaseTime GetValidStart() override;
+ CefBaseTime GetValidExpiry() override;
+ CefRefPtr<CefBinaryValue> GetDEREncoded() override;
+ CefRefPtr<CefBinaryValue> GetPEMEncoded() override;
+ size_t GetIssuerChainSize() override;
+ void GetDEREncodedIssuerChain(IssuerChainBinaryList& chain) override;
+ void GetPEMEncodedIssuerChain(IssuerChainBinaryList& chain) override;
+
+ scoped_refptr<net::X509Certificate> GetInternalCertObject() { return cert_; }
+ void AcquirePrivateKey(
+ base::OnceCallback<void(scoped_refptr<net::SSLPrivateKey>)>
+ private_key_callback);
+
+ private:
+ void GetEncodedIssuerChain(IssuerChainBinaryList& chain, bool der);
+
+ std::unique_ptr<net::ClientCertIdentity> identity_;
+ scoped_refptr<net::X509Certificate> cert_;
+ IssuerChainBinaryList pem_encoded_issuer_chain_;
+ IssuerChainBinaryList der_encoded_issuer_chain_;
+
+ IMPLEMENT_REFCOUNTING(CefX509CertificateImpl);
+};
+
+#endif // CEF_LIBCEF_BROWSER_X509_CERTIFICATE_IMPL_H_
diff --git a/libcef/browser/xml_reader_impl.cc b/libcef/browser/xml_reader_impl.cc
new file mode 100644
index 00000000..84455bf4
--- /dev/null
+++ b/libcef/browser/xml_reader_impl.cc
@@ -0,0 +1,494 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "libcef/browser/xml_reader_impl.h"
+
+#include "include/cef_stream.h"
+
+#include "base/logging.h"
+#include "base/notreached.h"
+
+// Static functions
+
+// static
+CefRefPtr<CefXmlReader> CefXmlReader::Create(CefRefPtr<CefStreamReader> stream,
+ EncodingType encodingType,
+ const CefString& URI) {
+ CefRefPtr<CefXmlReaderImpl> impl(new CefXmlReaderImpl());
+ if (!impl->Initialize(stream, encodingType, URI)) {
+ return nullptr;
+ }
+ return impl.get();
+}
+
+// CefXmlReaderImpl
+
+namespace {
+
+/**
+ * xmlInputReadCallback:
+ * @context: an Input context
+ * @buffer: the buffer to store data read
+ * @len: the length of the buffer in bytes
+ *
+ * Callback used in the I/O Input API to read the resource
+ *
+ * Returns the number of bytes read or -1 in case of error
+ */
+int XMLCALL xml_read_callback(void* context, char* buffer, int len) {
+ CefRefPtr<CefStreamReader> reader(static_cast<CefStreamReader*>(context));
+ return reader->Read(buffer, 1, len);
+}
+
+/**
+ * xmlTextReaderErrorFunc:
+ * @arg: the user argument
+ * @msg: the message
+ * @severity: the severity of the error
+ * @locator: a locator indicating where the error occured
+ *
+ * Signature of an error callback from a reader parser
+ */
+void XMLCALL xml_error_callback(void* arg,
+ const char* msg,
+ xmlParserSeverities severity,
+ xmlTextReaderLocatorPtr locator) {
+ if (!msg) {
+ return;
+ }
+
+ std::string error_str(msg);
+ if (!error_str.empty() && error_str[error_str.length() - 1] == '\n') {
+ error_str.resize(error_str.length() - 1);
+ }
+
+ std::stringstream ss;
+ ss << error_str << ", line " << xmlTextReaderLocatorLineNumber(locator);
+
+ LOG(INFO) << ss.str();
+
+ CefRefPtr<CefXmlReaderImpl> impl(static_cast<CefXmlReaderImpl*>(arg));
+ impl->AppendError(ss.str());
+}
+
+/**
+ * xmlStructuredErrorFunc:
+ * @userData: user provided data for the error callback
+ * @error: the error being raised.
+ *
+ * Signature of the function to use when there is an error and
+ * the module handles the new error reporting mechanism.
+ */
+void XMLCALL xml_structured_error_callback(void* userData, xmlErrorPtr error) {
+ if (!error->message) {
+ return;
+ }
+
+ std::string error_str(error->message);
+ if (!error_str.empty() && error_str[error_str.length() - 1] == '\n') {
+ error_str.resize(error_str.length() - 1);
+ }
+
+ std::stringstream ss;
+ ss << error_str << ", line " << error->line;
+
+ LOG(INFO) << ss.str();
+
+ CefRefPtr<CefXmlReaderImpl> impl(static_cast<CefXmlReaderImpl*>(userData));
+ impl->AppendError(ss.str());
+}
+
+CefString xmlCharToString(const xmlChar* xmlStr, bool free) {
+ if (!xmlStr) {
+ return CefString();
+ }
+
+ const char* str = reinterpret_cast<const char*>(xmlStr);
+ CefString wstr = std::string(str);
+
+ if (free) {
+ xmlFree(const_cast<xmlChar*>(xmlStr));
+ }
+
+ return wstr;
+}
+
+} // namespace
+
+CefXmlReaderImpl::CefXmlReaderImpl()
+ : supported_thread_id_(base::PlatformThread::CurrentId()),
+ reader_(nullptr) {}
+
+CefXmlReaderImpl::~CefXmlReaderImpl() {
+ if (reader_ != nullptr) {
+ if (!VerifyContext()) {
+ // Close() is supposed to be called directly. We'll try to free the reader
+ // now on the wrong thread but there's no guarantee this call won't crash.
+ xmlFreeTextReader(reader_);
+ } else {
+ Close();
+ }
+ }
+}
+
+bool CefXmlReaderImpl::Initialize(CefRefPtr<CefStreamReader> stream,
+ EncodingType encodingType,
+ const CefString& URI) {
+ xmlCharEncoding enc = XML_CHAR_ENCODING_NONE;
+ switch (encodingType) {
+ case XML_ENCODING_UTF8:
+ enc = XML_CHAR_ENCODING_UTF8;
+ break;
+ case XML_ENCODING_UTF16LE:
+ enc = XML_CHAR_ENCODING_UTF16LE;
+ break;
+ case XML_ENCODING_UTF16BE:
+ enc = XML_CHAR_ENCODING_UTF16BE;
+ break;
+ case XML_ENCODING_ASCII:
+ enc = XML_CHAR_ENCODING_ASCII;
+ break;
+ default:
+ break;
+ }
+
+ // Create the input buffer.
+ xmlParserInputBufferPtr input_buffer = xmlAllocParserInputBuffer(enc);
+ if (!input_buffer) {
+ return false;
+ }
+
+ input_buffer->context = stream.get();
+ input_buffer->readcallback = xml_read_callback;
+
+ // Create the text reader.
+ std::string uriStr = URI;
+ reader_ = xmlNewTextReader(input_buffer, uriStr.c_str());
+ if (!reader_) {
+ // Free the input buffer.
+ xmlFreeParserInputBuffer(input_buffer);
+ return false;
+ }
+
+ // Keep a reference to the stream.
+ stream_ = stream;
+
+ // Register the error callbacks.
+ xmlTextReaderSetErrorHandler(reader_, xml_error_callback, this);
+ xmlTextReaderSetStructuredErrorHandler(reader_, xml_structured_error_callback,
+ this);
+
+ return true;
+}
+
+bool CefXmlReaderImpl::MoveToNextNode() {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ return xmlTextReaderRead(reader_) == 1 ? true : false;
+}
+
+bool CefXmlReaderImpl::Close() {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ // The input buffer will be freed automatically.
+ xmlFreeTextReader(reader_);
+ reader_ = nullptr;
+ return true;
+}
+
+bool CefXmlReaderImpl::HasError() {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ return !error_buf_.str().empty();
+}
+
+CefString CefXmlReaderImpl::GetError() {
+ if (!VerifyContext()) {
+ return CefString();
+ }
+
+ return error_buf_.str();
+}
+
+CefXmlReader::NodeType CefXmlReaderImpl::GetType() {
+ if (!VerifyContext()) {
+ return XML_NODE_UNSUPPORTED;
+ }
+
+ switch (xmlTextReaderNodeType(reader_)) {
+ case XML_READER_TYPE_ELEMENT:
+ return XML_NODE_ELEMENT_START;
+ case XML_READER_TYPE_END_ELEMENT:
+ return XML_NODE_ELEMENT_END;
+ case XML_READER_TYPE_ATTRIBUTE:
+ return XML_NODE_ATTRIBUTE;
+ case XML_READER_TYPE_TEXT:
+ return XML_NODE_TEXT;
+ case XML_READER_TYPE_SIGNIFICANT_WHITESPACE:
+ case XML_READER_TYPE_WHITESPACE:
+ return XML_NODE_WHITESPACE;
+ case XML_READER_TYPE_CDATA:
+ return XML_NODE_CDATA;
+ case XML_READER_TYPE_ENTITY_REFERENCE:
+ return XML_NODE_ENTITY_REFERENCE;
+ case XML_READER_TYPE_PROCESSING_INSTRUCTION:
+ return XML_NODE_PROCESSING_INSTRUCTION;
+ case XML_READER_TYPE_COMMENT:
+ return XML_NODE_COMMENT;
+ case XML_READER_TYPE_DOCUMENT_TYPE:
+ return XML_NODE_DOCUMENT_TYPE;
+ default:
+ break;
+ }
+
+ return XML_NODE_UNSUPPORTED;
+}
+
+int CefXmlReaderImpl::GetDepth() {
+ if (!VerifyContext()) {
+ return -1;
+ }
+
+ return xmlTextReaderDepth(reader_);
+}
+
+CefString CefXmlReaderImpl::GetLocalName() {
+ if (!VerifyContext()) {
+ return CefString();
+ }
+
+ return xmlCharToString(xmlTextReaderConstLocalName(reader_), false);
+}
+
+CefString CefXmlReaderImpl::GetPrefix() {
+ if (!VerifyContext()) {
+ return CefString();
+ }
+
+ return xmlCharToString(xmlTextReaderConstPrefix(reader_), false);
+}
+
+CefString CefXmlReaderImpl::GetQualifiedName() {
+ if (!VerifyContext()) {
+ return CefString();
+ }
+
+ return xmlCharToString(xmlTextReaderConstName(reader_), false);
+}
+
+CefString CefXmlReaderImpl::GetNamespaceURI() {
+ if (!VerifyContext()) {
+ return CefString();
+ }
+
+ return xmlCharToString(xmlTextReaderConstNamespaceUri(reader_), false);
+}
+
+CefString CefXmlReaderImpl::GetBaseURI() {
+ if (!VerifyContext()) {
+ return CefString();
+ }
+
+ return xmlCharToString(xmlTextReaderConstBaseUri(reader_), false);
+}
+
+CefString CefXmlReaderImpl::GetXmlLang() {
+ if (!VerifyContext()) {
+ return CefString();
+ }
+
+ return xmlCharToString(xmlTextReaderConstXmlLang(reader_), false);
+}
+
+bool CefXmlReaderImpl::IsEmptyElement() {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ return xmlTextReaderIsEmptyElement(reader_) == 1 ? true : false;
+}
+
+bool CefXmlReaderImpl::HasValue() {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ if (xmlTextReaderNodeType(reader_) == XML_READER_TYPE_ENTITY_REFERENCE) {
+ // Provide special handling to return entity reference values.
+ return true;
+ } else {
+ return xmlTextReaderHasValue(reader_) == 1 ? true : false;
+ }
+}
+
+CefString CefXmlReaderImpl::GetValue() {
+ if (!VerifyContext()) {
+ return CefString();
+ }
+
+ if (xmlTextReaderNodeType(reader_) == XML_READER_TYPE_ENTITY_REFERENCE) {
+ // Provide special handling to return entity reference values.
+ xmlNodePtr node = xmlTextReaderCurrentNode(reader_);
+ if (node->content != nullptr) {
+ return xmlCharToString(node->content, false);
+ }
+ return CefString();
+ } else {
+ return xmlCharToString(xmlTextReaderConstValue(reader_), false);
+ }
+}
+
+bool CefXmlReaderImpl::HasAttributes() {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ return xmlTextReaderHasAttributes(reader_) == 1 ? true : false;
+}
+
+size_t CefXmlReaderImpl::GetAttributeCount() {
+ if (!VerifyContext()) {
+ return 0;
+ }
+
+ return xmlTextReaderAttributeCount(reader_);
+}
+
+CefString CefXmlReaderImpl::GetAttribute(int index) {
+ if (!VerifyContext()) {
+ return CefString();
+ }
+
+ return xmlCharToString(xmlTextReaderGetAttributeNo(reader_, index), true);
+}
+
+CefString CefXmlReaderImpl::GetAttribute(const CefString& qualifiedName) {
+ if (!VerifyContext()) {
+ return CefString();
+ }
+
+ std::string qualifiedNameStr = qualifiedName;
+ return xmlCharToString(
+ xmlTextReaderGetAttribute(reader_, BAD_CAST qualifiedNameStr.c_str()),
+ true);
+}
+
+CefString CefXmlReaderImpl::GetAttribute(const CefString& localName,
+ const CefString& namespaceURI) {
+ if (!VerifyContext()) {
+ return CefString();
+ }
+
+ std::string localNameStr = localName;
+ std::string namespaceURIStr = namespaceURI;
+ return xmlCharToString(
+ xmlTextReaderGetAttributeNs(reader_, BAD_CAST localNameStr.c_str(),
+ BAD_CAST namespaceURIStr.c_str()),
+ true);
+}
+
+CefString CefXmlReaderImpl::GetInnerXml() {
+ if (!VerifyContext()) {
+ return CefString();
+ }
+
+ return xmlCharToString(xmlTextReaderReadInnerXml(reader_), true);
+}
+
+CefString CefXmlReaderImpl::GetOuterXml() {
+ if (!VerifyContext()) {
+ return CefString();
+ }
+
+ return xmlCharToString(xmlTextReaderReadOuterXml(reader_), true);
+}
+
+int CefXmlReaderImpl::GetLineNumber() {
+ if (!VerifyContext()) {
+ return -1;
+ }
+
+ return xmlTextReaderGetParserLineNumber(reader_);
+}
+
+bool CefXmlReaderImpl::MoveToAttribute(int index) {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ return xmlTextReaderMoveToAttributeNo(reader_, index) == 1 ? true : false;
+}
+
+bool CefXmlReaderImpl::MoveToAttribute(const CefString& qualifiedName) {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ std::string qualifiedNameStr = qualifiedName;
+ return xmlTextReaderMoveToAttribute(reader_,
+ BAD_CAST qualifiedNameStr.c_str()) == 1
+ ? true
+ : false;
+}
+
+bool CefXmlReaderImpl::MoveToAttribute(const CefString& localName,
+ const CefString& namespaceURI) {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ std::string localNameStr = localName;
+ std::string namespaceURIStr = namespaceURI;
+ return xmlTextReaderMoveToAttributeNs(reader_, BAD_CAST localNameStr.c_str(),
+ BAD_CAST namespaceURIStr.c_str()) == 1
+ ? true
+ : false;
+}
+
+bool CefXmlReaderImpl::MoveToFirstAttribute() {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ return xmlTextReaderMoveToFirstAttribute(reader_) == 1 ? true : false;
+}
+
+bool CefXmlReaderImpl::MoveToNextAttribute() {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ return xmlTextReaderMoveToNextAttribute(reader_) == 1 ? true : false;
+}
+
+bool CefXmlReaderImpl::MoveToCarryingElement() {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ return xmlTextReaderMoveToElement(reader_) == 1 ? true : false;
+}
+
+void CefXmlReaderImpl::AppendError(const CefString& error_str) {
+ if (!error_buf_.str().empty()) {
+ error_buf_ << L"\n";
+ }
+ error_buf_ << error_str.ToString();
+}
+
+bool CefXmlReaderImpl::VerifyContext() {
+ if (base::PlatformThread::CurrentId() != supported_thread_id_) {
+ // This object should only be accessed from the thread that created it.
+ NOTREACHED();
+ return false;
+ }
+
+ return (reader_ != nullptr);
+}
diff --git a/libcef/browser/xml_reader_impl.h b/libcef/browser/xml_reader_impl.h
new file mode 100644
index 00000000..eafa63f7
--- /dev/null
+++ b/libcef/browser/xml_reader_impl.h
@@ -0,0 +1,74 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_XML_READER_IMPL_H_
+#define CEF_LIBCEF_BROWSER_XML_READER_IMPL_H_
+#pragma once
+
+#include <libxml/xmlreader.h>
+#include <sstream>
+
+#include "base/threading/platform_thread.h"
+#include "include/cef_xml_reader.h"
+
+// Implementation of CefXmlReader
+class CefXmlReaderImpl : public CefXmlReader {
+ public:
+ CefXmlReaderImpl();
+ ~CefXmlReaderImpl() override;
+
+ // Initialize the reader context.
+ bool Initialize(CefRefPtr<CefStreamReader> stream,
+ EncodingType encodingType,
+ const CefString& URI);
+
+ bool MoveToNextNode() override;
+ bool Close() override;
+ bool HasError() override;
+ CefString GetError() override;
+ NodeType GetType() override;
+ int GetDepth() override;
+ CefString GetLocalName() override;
+ CefString GetPrefix() override;
+ CefString GetQualifiedName() override;
+ CefString GetNamespaceURI() override;
+ CefString GetBaseURI() override;
+ CefString GetXmlLang() override;
+ bool IsEmptyElement() override;
+ bool HasValue() override;
+ CefString GetValue() override;
+ bool HasAttributes() override;
+ size_t GetAttributeCount() override;
+ CefString GetAttribute(int index) override;
+ CefString GetAttribute(const CefString& qualifiedName) override;
+ CefString GetAttribute(const CefString& localName,
+ const CefString& namespaceURI) override;
+ CefString GetInnerXml() override;
+ CefString GetOuterXml() override;
+ int GetLineNumber() override;
+ bool MoveToAttribute(int index) override;
+ bool MoveToAttribute(const CefString& qualifiedName) override;
+ bool MoveToAttribute(const CefString& localName,
+ const CefString& namespaceURI) override;
+ bool MoveToFirstAttribute() override;
+ bool MoveToNextAttribute() override;
+ bool MoveToCarryingElement() override;
+
+ // Add another line to the error string.
+ void AppendError(const CefString& error_str);
+
+ // Verify that the reader exists and is being accessed from the correct
+ // thread.
+ bool VerifyContext();
+
+ protected:
+ base::PlatformThreadId supported_thread_id_;
+ CefRefPtr<CefStreamReader> stream_;
+ xmlTextReaderPtr reader_;
+ std::stringstream error_buf_;
+
+ IMPLEMENT_REFCOUNTING(CefXmlReaderImpl);
+};
+
+#endif // CEF_LIBCEF_BROWSER_XML_READER_IMPL_H_
diff --git a/libcef/browser/zip_reader_impl.cc b/libcef/browser/zip_reader_impl.cc
new file mode 100644
index 00000000..74643c6c
--- /dev/null
+++ b/libcef/browser/zip_reader_impl.cc
@@ -0,0 +1,303 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "libcef/browser/zip_reader_impl.h"
+#include <time.h>
+#include "base/logging.h"
+#include "base/notreached.h"
+#include "base/time/time.h"
+#include "include/cef_stream.h"
+
+// Static functions
+
+// static
+CefRefPtr<CefZipReader> CefZipReader::Create(
+ CefRefPtr<CefStreamReader> stream) {
+ CefRefPtr<CefZipReaderImpl> impl(new CefZipReaderImpl());
+ if (!impl->Initialize(stream)) {
+ return nullptr;
+ }
+ return impl.get();
+}
+
+// CefZipReaderImpl
+
+namespace {
+
+voidpf ZCALLBACK zlib_open_callback OF((voidpf opaque,
+ const void* filename,
+ int mode)) {
+ // The stream is already implicitly open so just return the pointer.
+ return opaque;
+}
+
+uLong ZCALLBACK zlib_read_callback
+OF((voidpf opaque, voidpf stream, void* buf, uLong size)) {
+ CefRefPtr<CefStreamReader> reader(static_cast<CefStreamReader*>(opaque));
+ return reader->Read(buf, 1, size);
+}
+
+ZPOS64_T ZCALLBACK zlib_tell_callback OF((voidpf opaque, voidpf stream)) {
+ CefRefPtr<CefStreamReader> reader(static_cast<CefStreamReader*>(opaque));
+ return reader->Tell();
+}
+
+long ZCALLBACK zlib_seek_callback
+OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)) {
+ CefRefPtr<CefStreamReader> reader(static_cast<CefStreamReader*>(opaque));
+ int whence;
+ switch (origin) {
+ case ZLIB_FILEFUNC_SEEK_CUR:
+ whence = SEEK_CUR;
+ break;
+ case ZLIB_FILEFUNC_SEEK_END:
+ whence = SEEK_END;
+ break;
+ case ZLIB_FILEFUNC_SEEK_SET:
+ whence = SEEK_SET;
+ break;
+ default:
+ NOTREACHED();
+ return -1;
+ }
+ return reader->Seek(offset, whence);
+}
+
+int ZCALLBACK zlib_close_callback OF((voidpf opaque, voidpf stream)) {
+ CefRefPtr<CefStreamReader> reader(static_cast<CefStreamReader*>(opaque));
+ // Release the reference added by CefZipReaderImpl::Initialize().
+ reader->Release();
+ return 0;
+}
+
+int ZCALLBACK zlib_error_callback OF((voidpf opaque, voidpf stream)) {
+ return 0;
+}
+
+} // namespace
+
+CefZipReaderImpl::CefZipReaderImpl()
+ : supported_thread_id_(base::PlatformThread::CurrentId()),
+ reader_(nullptr),
+ has_fileopen_(false),
+ has_fileinfo_(false),
+ filesize_(0),
+ filemodified_(0) {}
+
+CefZipReaderImpl::~CefZipReaderImpl() {
+ if (reader_ != nullptr) {
+ if (!VerifyContext()) {
+ // Close() is supposed to be called directly. We'll try to free the reader
+ // now on the wrong thread but there's no guarantee this call won't crash.
+ if (has_fileopen_) {
+ unzCloseCurrentFile(reader_);
+ }
+ unzClose(reader_);
+ } else {
+ Close();
+ }
+ }
+}
+
+bool CefZipReaderImpl::Initialize(CefRefPtr<CefStreamReader> stream) {
+ zlib_filefunc64_def filefunc_def;
+ filefunc_def.zopen64_file = zlib_open_callback;
+ filefunc_def.zread_file = zlib_read_callback;
+ filefunc_def.zwrite_file = nullptr;
+ filefunc_def.ztell64_file = zlib_tell_callback;
+ filefunc_def.zseek64_file = zlib_seek_callback;
+ filefunc_def.zclose_file = zlib_close_callback;
+ filefunc_def.zerror_file = zlib_error_callback;
+ filefunc_def.opaque = stream.get();
+
+ // Add a reference that will be released by zlib_close_callback().
+ stream->AddRef();
+
+ reader_ = unzOpen2_64("", &filefunc_def);
+ return (reader_ != nullptr);
+}
+
+bool CefZipReaderImpl::MoveToFirstFile() {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ if (has_fileopen_) {
+ CloseFile();
+ }
+
+ has_fileinfo_ = false;
+
+ return (unzGoToFirstFile(reader_) == UNZ_OK);
+}
+
+bool CefZipReaderImpl::MoveToNextFile() {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ if (has_fileopen_) {
+ CloseFile();
+ }
+
+ has_fileinfo_ = false;
+
+ return (unzGoToNextFile(reader_) == UNZ_OK);
+}
+
+bool CefZipReaderImpl::MoveToFile(const CefString& fileName,
+ bool caseSensitive) {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ if (has_fileopen_) {
+ CloseFile();
+ }
+
+ has_fileinfo_ = false;
+
+ std::string fileNameStr = fileName;
+ return (unzLocateFile(reader_, fileNameStr.c_str(),
+ (caseSensitive ? 1 : 2)) == UNZ_OK);
+}
+
+bool CefZipReaderImpl::Close() {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ if (has_fileopen_) {
+ CloseFile();
+ }
+
+ int result = unzClose(reader_);
+ reader_ = nullptr;
+ return (result == UNZ_OK);
+}
+
+CefString CefZipReaderImpl::GetFileName() {
+ if (!VerifyContext() || !GetFileInfo()) {
+ return CefString();
+ }
+
+ return filename_;
+}
+
+int64 CefZipReaderImpl::GetFileSize() {
+ if (!VerifyContext() || !GetFileInfo()) {
+ return -1;
+ }
+
+ return filesize_;
+}
+
+CefBaseTime CefZipReaderImpl::GetFileLastModified() {
+ if (!VerifyContext() || !GetFileInfo()) {
+ return CefBaseTime();
+ }
+
+ return base::Time::FromTimeT(filemodified_);
+}
+
+bool CefZipReaderImpl::OpenFile(const CefString& password) {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ if (has_fileopen_) {
+ CloseFile();
+ }
+
+ bool ret;
+
+ if (password.empty()) {
+ ret = (unzOpenCurrentFile(reader_) == UNZ_OK);
+ } else {
+ std::string passwordStr = password;
+ ret = (unzOpenCurrentFilePassword(reader_, passwordStr.c_str()) == UNZ_OK);
+ }
+
+ if (ret) {
+ has_fileopen_ = true;
+ }
+ return ret;
+}
+
+bool CefZipReaderImpl::CloseFile() {
+ if (!VerifyContext() || !has_fileopen_) {
+ return false;
+ }
+
+ has_fileopen_ = false;
+ has_fileinfo_ = false;
+
+ return (unzCloseCurrentFile(reader_) == UNZ_OK);
+}
+
+int CefZipReaderImpl::ReadFile(void* buffer, size_t bufferSize) {
+ if (!VerifyContext() || !has_fileopen_) {
+ return -1;
+ }
+
+ return unzReadCurrentFile(reader_, buffer, bufferSize);
+}
+
+int64 CefZipReaderImpl::Tell() {
+ if (!VerifyContext() || !has_fileopen_) {
+ return -1;
+ }
+
+ return unztell64(reader_);
+}
+
+bool CefZipReaderImpl::Eof() {
+ if (!VerifyContext() || !has_fileopen_) {
+ return true;
+ }
+
+ return (unzeof(reader_) == 1 ? true : false);
+}
+
+bool CefZipReaderImpl::GetFileInfo() {
+ if (has_fileinfo_) {
+ return true;
+ }
+
+ char file_name[512] = {0};
+ unz_file_info file_info;
+ memset(&file_info, 0, sizeof(file_info));
+
+ if (unzGetCurrentFileInfo(reader_, &file_info, file_name, sizeof(file_name),
+ NULL, 0, NULL, 0) != UNZ_OK) {
+ return false;
+ }
+
+ has_fileinfo_ = true;
+ filename_ = std::string(file_name);
+ filesize_ = file_info.uncompressed_size;
+
+ struct tm time;
+ memset(&time, 0, sizeof(time));
+ time.tm_sec = file_info.tmu_date.tm_sec;
+ time.tm_min = file_info.tmu_date.tm_min;
+ time.tm_hour = file_info.tmu_date.tm_hour;
+ time.tm_mday = file_info.tmu_date.tm_mday;
+ time.tm_mon = file_info.tmu_date.tm_mon;
+ time.tm_year = file_info.tmu_date.tm_year - 1900; // Years since 1900.
+ filemodified_ = mktime(&time);
+ DCHECK_NE(filemodified_, (time_t)-1);
+
+ return true;
+}
+
+bool CefZipReaderImpl::VerifyContext() {
+ if (base::PlatformThread::CurrentId() != supported_thread_id_) {
+ // This object should only be accessed from the thread that created it.
+ NOTREACHED();
+ return false;
+ }
+
+ return (reader_ != nullptr);
+}
diff --git a/libcef/browser/zip_reader_impl.h b/libcef/browser/zip_reader_impl.h
new file mode 100644
index 00000000..3b623a23
--- /dev/null
+++ b/libcef/browser/zip_reader_impl.h
@@ -0,0 +1,55 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_BROWSER_ZIP_READER_IMPL_H_
+#define CEF_LIBCEF_BROWSER_ZIP_READER_IMPL_H_
+#pragma once
+
+#include <sstream>
+
+#include "base/threading/platform_thread.h"
+#include "include/cef_zip_reader.h"
+#include "third_party/zlib/contrib/minizip/unzip.h"
+
+// Implementation of CefZipReader
+class CefZipReaderImpl : public CefZipReader {
+ public:
+ CefZipReaderImpl();
+ ~CefZipReaderImpl() override;
+
+ // Initialize the reader context.
+ bool Initialize(CefRefPtr<CefStreamReader> stream);
+
+ bool MoveToFirstFile() override;
+ bool MoveToNextFile() override;
+ bool MoveToFile(const CefString& fileName, bool caseSensitive) override;
+ bool Close() override;
+ CefString GetFileName() override;
+ int64 GetFileSize() override;
+ CefBaseTime GetFileLastModified() override;
+ bool OpenFile(const CefString& password) override;
+ bool CloseFile() override;
+ int ReadFile(void* buffer, size_t bufferSize) override;
+ int64 Tell() override;
+ bool Eof() override;
+
+ bool GetFileInfo();
+
+ // Verify that the reader exists and is being accessed from the correct
+ // thread.
+ bool VerifyContext();
+
+ protected:
+ base::PlatformThreadId supported_thread_id_;
+ unzFile reader_;
+ bool has_fileopen_;
+ bool has_fileinfo_;
+ CefString filename_;
+ int64 filesize_;
+ time_t filemodified_;
+
+ IMPLEMENT_REFCOUNTING(CefZipReaderImpl);
+};
+
+#endif // CEF_LIBCEF_BROWSER_ZIP_READER_IMPL_H_
diff --git a/libcef/common/alloy/alloy_content_client.cc b/libcef/common/alloy/alloy_content_client.cc
new file mode 100644
index 00000000..99d72f7b
--- /dev/null
+++ b/libcef/common/alloy/alloy_content_client.cc
@@ -0,0 +1,160 @@
+// Copyright 2015 The Chromium Embedded Framework Authors.
+// Portions copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/common/alloy/alloy_content_client.h"
+
+#include <stdint.h>
+
+#include "include/cef_stream.h"
+#include "include/cef_version.h"
+#include "libcef/common/app_manager.h"
+#include "libcef/common/cef_switches.h"
+#include "libcef/common/extensions/extensions_util.h"
+
+#include "base/command_line.h"
+#include "base/files/file_util.h"
+#include "base/json/json_reader.h"
+#include "base/logging.h"
+#include "base/path_service.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/common/chrome_constants.h"
+#include "chrome/common/chrome_content_client.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/media/cdm_registration.h"
+#include "components/pdf/common/internal_plugin_helpers.h"
+#include "content/public/common/cdm_info.h"
+#include "content/public/common/content_constants.h"
+#include "content/public/common/content_plugin_info.h"
+#include "content/public/common/content_switches.h"
+#include "ppapi/shared_impl/ppapi_permissions.h"
+#include "third_party/widevine/cdm/buildflags.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+
+#if BUILDFLAG(ENABLE_CDM_HOST_VERIFICATION)
+#include "libcef/common/cdm_host_file_path.h"
+#endif
+
+namespace {
+
+// The following plugin-related methods are from
+// chrome/common/chrome_content_client.cc
+
+constexpr char kPDFPluginName[] = "Chromium PDF Plugin";
+constexpr char kPDFPluginExtension[] = "pdf";
+constexpr char kPDFPluginDescription[] = "Portable Document Format";
+constexpr uint32_t kPDFPluginPermissions =
+ ppapi::PERMISSION_PDF | ppapi::PERMISSION_DEV;
+
+// Appends the known built-in plugins to the given vector. Some built-in
+// plugins are "internal" which means they are compiled into the Chrome binary,
+// and some are extra shared libraries distributed with the browser (these are
+// not marked internal, aside from being automatically registered, they're just
+// regular plugins).
+void ComputeBuiltInPlugins(std::vector<content::ContentPluginInfo>* plugins) {
+ if (extensions::PdfExtensionEnabled()) {
+ content::ContentPluginInfo pdf_info;
+ pdf_info.is_internal = true;
+ pdf_info.is_out_of_process = true;
+ pdf_info.name = kPDFPluginName;
+ pdf_info.description = kPDFPluginDescription;
+ pdf_info.path = base::FilePath(ChromeContentClient::kPDFInternalPluginPath);
+ content::WebPluginMimeType pdf_mime_type(pdf::kInternalPluginMimeType,
+ kPDFPluginExtension,
+ kPDFPluginDescription);
+ pdf_info.mime_types.push_back(pdf_mime_type);
+ pdf_info.permissions = kPDFPluginPermissions;
+ plugins->push_back(pdf_info);
+ }
+}
+
+} // namespace
+
+AlloyContentClient::AlloyContentClient() = default;
+AlloyContentClient::~AlloyContentClient() = default;
+
+void AlloyContentClient::AddPlugins(
+ std::vector<content::ContentPluginInfo>* plugins) {
+ ComputeBuiltInPlugins(plugins);
+}
+
+void AlloyContentClient::AddContentDecryptionModules(
+ std::vector<content::CdmInfo>* cdms,
+ std::vector<media::CdmHostFilePath>* cdm_host_file_paths) {
+ if (cdms) {
+ RegisterCdmInfo(cdms);
+ }
+
+#if BUILDFLAG(ENABLE_CDM_HOST_VERIFICATION)
+ if (cdm_host_file_paths) {
+ cef::AddCdmHostFilePaths(cdm_host_file_paths);
+ }
+#endif
+}
+
+void AlloyContentClient::AddAdditionalSchemes(Schemes* schemes) {
+ CefAppManager::Get()->AddAdditionalSchemes(schemes);
+}
+
+std::u16string AlloyContentClient::GetLocalizedString(int message_id) {
+ std::u16string value =
+ ui::ResourceBundle::GetSharedInstance().GetLocalizedString(message_id);
+ if (value.empty()) {
+ LOG(ERROR) << "No localized string available for id " << message_id;
+ }
+
+ return value;
+}
+
+std::u16string AlloyContentClient::GetLocalizedString(
+ int message_id,
+ const std::u16string& replacement) {
+ std::u16string value = l10n_util::GetStringFUTF16(message_id, replacement);
+ if (value.empty()) {
+ LOG(ERROR) << "No localized string available for id " << message_id;
+ }
+
+ return value;
+}
+
+base::StringPiece AlloyContentClient::GetDataResource(
+ int resource_id,
+ ui::ResourceScaleFactor scale_factor) {
+ base::StringPiece value =
+ ui::ResourceBundle::GetSharedInstance().GetRawDataResourceForScale(
+ resource_id, scale_factor);
+ if (value.empty()) {
+ LOG(ERROR) << "No data resource available for id " << resource_id;
+ }
+
+ return value;
+}
+
+base::RefCountedMemory* AlloyContentClient::GetDataResourceBytes(
+ int resource_id) {
+ base::RefCountedMemory* value =
+ ui::ResourceBundle::GetSharedInstance().LoadDataResourceBytes(
+ resource_id);
+ if (!value) {
+ LOG(ERROR) << "No data resource bytes available for id " << resource_id;
+ }
+
+ return value;
+}
+
+gfx::Image& AlloyContentClient::GetNativeImageNamed(int resource_id) {
+ gfx::Image& value =
+ ui::ResourceBundle::GetSharedInstance().GetNativeImageNamed(resource_id);
+ if (value.IsEmpty()) {
+ LOG(ERROR) << "No native image available for id " << resource_id;
+ }
+
+ return value;
+}
diff --git a/libcef/common/alloy/alloy_content_client.h b/libcef/common/alloy/alloy_content_client.h
new file mode 100644
index 00000000..968bb32c
--- /dev/null
+++ b/libcef/common/alloy/alloy_content_client.h
@@ -0,0 +1,33 @@
+// Copyright 2015 The Chromium Embedded Framework Authors.
+// Portions copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_COMMON_ALLOY_ALLOY_CONTENT_CLIENT_H_
+#define CEF_LIBCEF_COMMON_ALLOY_ALLOY_CONTENT_CLIENT_H_
+#pragma once
+
+#include "content/public/common/content_client.h"
+
+class AlloyContentClient : public content::ContentClient {
+ public:
+ AlloyContentClient();
+ ~AlloyContentClient() override;
+
+ // content::ContentClient overrides.
+ void AddPlugins(std::vector<content::ContentPluginInfo>* plugins) override;
+ void AddContentDecryptionModules(
+ std::vector<content::CdmInfo>* cdms,
+ std::vector<media::CdmHostFilePath>* cdm_host_file_paths) override;
+ void AddAdditionalSchemes(Schemes* schemes) override;
+ std::u16string GetLocalizedString(int message_id) override;
+ std::u16string GetLocalizedString(int message_id,
+ const std::u16string& replacement) override;
+ base::StringPiece GetDataResource(
+ int resource_id,
+ ui::ResourceScaleFactor scale_factor) override;
+ base::RefCountedMemory* GetDataResourceBytes(int resource_id) override;
+ gfx::Image& GetNativeImageNamed(int resource_id) override;
+};
+
+#endif // CEF_LIBCEF_COMMON_ALLOY_ALLOY_CONTENT_CLIENT_H_
diff --git a/libcef/common/alloy/alloy_main_delegate.cc b/libcef/common/alloy/alloy_main_delegate.cc
new file mode 100644
index 00000000..d79c6a8c
--- /dev/null
+++ b/libcef/common/alloy/alloy_main_delegate.cc
@@ -0,0 +1,599 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/common/alloy/alloy_main_delegate.h"
+
+#include <tuple>
+
+#include "libcef/browser/alloy/alloy_browser_context.h"
+#include "libcef/browser/alloy/alloy_content_browser_client.h"
+#include "libcef/common/cef_switches.h"
+#include "libcef/common/command_line_impl.h"
+#include "libcef/common/crash_reporting.h"
+#include "libcef/common/extensions/extensions_util.h"
+#include "libcef/common/resource_util.h"
+#include "libcef/renderer/alloy/alloy_content_renderer_client.h"
+
+#include "base/base_switches.h"
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/path_service.h"
+#include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/synchronization/waitable_event.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/child/pdf_child_init.h"
+#include "chrome/common/chrome_constants.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/utility/chrome_content_utility_client.h"
+#include "components/component_updater/component_updater_paths.h"
+#include "components/content_settings/core/common/content_settings_pattern.h"
+#include "components/embedder_support/switches.h"
+#include "components/spellcheck/common/spellcheck_features.h"
+#include "components/viz/common/features.h"
+#include "content/public/common/content_features.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/common/main_function_params.h"
+#include "content/public/common/url_constants.h"
+#include "extensions/common/constants.h"
+#include "net/base/features.h"
+#include "sandbox/policy/switches.h"
+#include "services/network/public/cpp/features.h"
+#include "third_party/blink/public/common/switches.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/base/ui_base_features.h"
+#include "ui/base/ui_base_paths.h"
+#include "ui/base/ui_base_switches.h"
+
+#if BUILDFLAG(IS_MAC)
+#include "libcef/common/util_mac.h"
+#elif BUILDFLAG(IS_POSIX)
+#include "libcef/common/util_linux.h"
+#endif
+
+#if BUILDFLAG(IS_WIN)
+#include "ui/base/resource/resource_bundle_win.h"
+#endif
+
+namespace {
+
+const char* const kNonWildcardDomainNonPortSchemes[] = {
+ extensions::kExtensionScheme, content::kChromeDevToolsScheme,
+ content::kChromeUIScheme, content::kChromeUIUntrustedScheme};
+const size_t kNonWildcardDomainNonPortSchemesSize =
+ std::size(kNonWildcardDomainNonPortSchemes);
+
+} // namespace
+
+AlloyMainDelegate::AlloyMainDelegate(CefMainRunnerHandler* runner,
+ CefSettings* settings,
+ CefRefPtr<CefApp> application)
+ : runner_(runner), settings_(settings), application_(application) {
+#if BUILDFLAG(IS_LINUX)
+ resource_util::OverrideAssetPath();
+#endif
+}
+
+AlloyMainDelegate::~AlloyMainDelegate() {}
+
+absl::optional<int> AlloyMainDelegate::PreBrowserMain() {
+ runner_->PreBrowserMain();
+ return absl::nullopt;
+}
+
+absl::optional<int> AlloyMainDelegate::BasicStartupComplete() {
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+ std::string process_type =
+ command_line->GetSwitchValueASCII(switches::kProcessType);
+
+#if BUILDFLAG(IS_POSIX)
+ // Read the crash configuration file. On Windows this is done from chrome_elf.
+ crash_reporting::BasicStartupComplete(command_line);
+#endif
+
+ if (process_type.empty()) {
+ // In the browser process. Populate the global command-line object.
+ if (settings_->command_line_args_disabled) {
+ // Remove any existing command-line arguments.
+ base::CommandLine::StringVector argv;
+ argv.push_back(command_line->GetProgram().value());
+ command_line->InitFromArgv(argv);
+
+ const base::CommandLine::SwitchMap& map = command_line->GetSwitches();
+ const_cast<base::CommandLine::SwitchMap*>(&map)->clear();
+ }
+
+ bool no_sandbox = settings_->no_sandbox ? true : false;
+
+ if (settings_->browser_subprocess_path.length > 0) {
+ base::FilePath file_path =
+ base::FilePath(CefString(&settings_->browser_subprocess_path));
+ if (!file_path.empty()) {
+ command_line->AppendSwitchPath(switches::kBrowserSubprocessPath,
+ file_path);
+
+#if BUILDFLAG(IS_WIN)
+ // The sandbox is not supported when using a separate subprocess
+ // executable on Windows.
+ no_sandbox = true;
+#endif
+ }
+ }
+
+#if BUILDFLAG(IS_MAC)
+ if (settings_->framework_dir_path.length > 0) {
+ base::FilePath file_path =
+ base::FilePath(CefString(&settings_->framework_dir_path));
+ if (!file_path.empty()) {
+ command_line->AppendSwitchPath(switches::kFrameworkDirPath, file_path);
+ }
+ }
+
+ if (settings_->main_bundle_path.length > 0) {
+ base::FilePath file_path =
+ base::FilePath(CefString(&settings_->main_bundle_path));
+ if (!file_path.empty()) {
+ command_line->AppendSwitchPath(switches::kMainBundlePath, file_path);
+ }
+ }
+#endif
+
+ if (no_sandbox) {
+ command_line->AppendSwitch(sandbox::policy::switches::kNoSandbox);
+ }
+
+ if (settings_->user_agent.length > 0) {
+ command_line->AppendSwitchASCII(
+ embedder_support::kUserAgent,
+ CefString(&settings_->user_agent).ToString());
+ } else if (settings_->user_agent_product.length > 0) {
+ command_line->AppendSwitchASCII(
+ switches::kUserAgentProductAndVersion,
+ CefString(&settings_->user_agent_product).ToString());
+ }
+
+ if (settings_->locale.length > 0) {
+ command_line->AppendSwitchASCII(switches::kLang,
+ CefString(&settings_->locale).ToString());
+ } else if (!command_line->HasSwitch(switches::kLang)) {
+ command_line->AppendSwitchASCII(switches::kLang, "en-US");
+ }
+
+ base::FilePath log_file;
+ bool has_log_file_cmdline = false;
+ if (settings_->log_file.length > 0) {
+ log_file = base::FilePath(CefString(&settings_->log_file));
+ }
+ if (log_file.empty() && command_line->HasSwitch(switches::kLogFile)) {
+ log_file = command_line->GetSwitchValuePath(switches::kLogFile);
+ if (!log_file.empty()) {
+ has_log_file_cmdline = true;
+ }
+ }
+ if (log_file.empty()) {
+ log_file = resource_util::GetDefaultLogFilePath();
+ }
+ DCHECK(!log_file.empty());
+ if (!has_log_file_cmdline) {
+ command_line->AppendSwitchPath(switches::kLogFile, log_file);
+ }
+
+ if (settings_->log_severity != LOGSEVERITY_DEFAULT) {
+ std::string log_severity;
+ switch (settings_->log_severity) {
+ case LOGSEVERITY_VERBOSE:
+ log_severity = switches::kLogSeverity_Verbose;
+ break;
+ case LOGSEVERITY_INFO:
+ log_severity = switches::kLogSeverity_Info;
+ break;
+ case LOGSEVERITY_WARNING:
+ log_severity = switches::kLogSeverity_Warning;
+ break;
+ case LOGSEVERITY_ERROR:
+ log_severity = switches::kLogSeverity_Error;
+ break;
+ case LOGSEVERITY_FATAL:
+ log_severity = switches::kLogSeverity_Fatal;
+ break;
+ case LOGSEVERITY_DISABLE:
+ log_severity = switches::kLogSeverity_Disable;
+ break;
+ default:
+ break;
+ }
+ if (!log_severity.empty()) {
+ command_line->AppendSwitchASCII(switches::kLogSeverity, log_severity);
+ }
+ }
+
+ if (settings_->javascript_flags.length > 0) {
+ command_line->AppendSwitchASCII(
+ blink::switches::kJavaScriptFlags,
+ CefString(&settings_->javascript_flags).ToString());
+ }
+
+ if (settings_->pack_loading_disabled) {
+ command_line->AppendSwitch(switches::kDisablePackLoading);
+ } else {
+ if (settings_->resources_dir_path.length > 0) {
+ base::FilePath file_path =
+ base::FilePath(CefString(&settings_->resources_dir_path));
+ if (!file_path.empty()) {
+ command_line->AppendSwitchPath(switches::kResourcesDirPath,
+ file_path);
+ }
+ }
+
+ if (settings_->locales_dir_path.length > 0) {
+ base::FilePath file_path =
+ base::FilePath(CefString(&settings_->locales_dir_path));
+ if (!file_path.empty()) {
+ command_line->AppendSwitchPath(switches::kLocalesDirPath, file_path);
+ }
+ }
+ }
+
+ if (settings_->remote_debugging_port >= 1024 &&
+ settings_->remote_debugging_port <= 65535) {
+ command_line->AppendSwitchASCII(
+ switches::kRemoteDebuggingPort,
+ base::NumberToString(settings_->remote_debugging_port));
+ }
+
+ if (settings_->uncaught_exception_stack_size > 0) {
+ command_line->AppendSwitchASCII(
+ switches::kUncaughtExceptionStackSize,
+ base::NumberToString(settings_->uncaught_exception_stack_size));
+ }
+
+ std::vector<std::string> disable_features;
+
+#if BUILDFLAG(IS_WIN)
+ if (features::kCalculateNativeWinOcclusion.default_state ==
+ base::FEATURE_ENABLED_BY_DEFAULT) {
+ // TODO: Add support for occlusion detection in combination with native
+ // parent windows (see issue #2805).
+ disable_features.push_back(features::kCalculateNativeWinOcclusion.name);
+ }
+
+ if (spellcheck::kWinUseBrowserSpellChecker.default_state ==
+ base::FEATURE_ENABLED_BY_DEFAULT) {
+ // TODO: Add support for windows spellcheck service (see issue #3055).
+ disable_features.push_back(spellcheck::kWinUseBrowserSpellChecker.name);
+ }
+#endif // BUILDFLAG(IS_WIN)
+
+ if (features::kBackForwardCache.default_state ==
+ base::FEATURE_ENABLED_BY_DEFAULT) {
+ // Disable BackForwardCache globally so that
+ // blink::RuntimeEnabledFeatures::BackForwardCacheEnabled reports the
+ // correct value in the renderer process (see issue #3374).
+ disable_features.push_back(features::kBackForwardCache.name);
+ }
+
+ if (!disable_features.empty()) {
+ DCHECK(!base::FeatureList::GetInstance());
+ std::string disable_features_str =
+ command_line->GetSwitchValueASCII(switches::kDisableFeatures);
+ for (auto feature_str : disable_features) {
+ if (!disable_features_str.empty()) {
+ disable_features_str += ",";
+ }
+ disable_features_str += feature_str;
+ }
+ command_line->AppendSwitchASCII(switches::kDisableFeatures,
+ disable_features_str);
+ }
+ }
+
+ if (application_) {
+ // Give the application a chance to view/modify the command line.
+ CefRefPtr<CefCommandLineImpl> commandLinePtr(
+ new CefCommandLineImpl(command_line, false, false));
+ application_->OnBeforeCommandLineProcessing(CefString(process_type),
+ commandLinePtr.get());
+ std::ignore = commandLinePtr->Detach(nullptr);
+ }
+
+ // Initialize logging.
+ logging::LoggingSettings log_settings;
+
+ const base::FilePath& log_file =
+ command_line->GetSwitchValuePath(switches::kLogFile);
+ DCHECK(!log_file.empty());
+ log_settings.log_file_path = log_file.value().c_str();
+
+ log_settings.lock_log = logging::DONT_LOCK_LOG_FILE;
+ log_settings.delete_old = logging::APPEND_TO_OLD_LOG_FILE;
+
+ logging::LogSeverity log_severity = logging::LOG_INFO;
+
+ std::string log_severity_str =
+ command_line->GetSwitchValueASCII(switches::kLogSeverity);
+ if (!log_severity_str.empty()) {
+ if (base::EqualsCaseInsensitiveASCII(log_severity_str,
+ switches::kLogSeverity_Verbose)) {
+ log_severity = logging::LOG_VERBOSE;
+ } else if (base::EqualsCaseInsensitiveASCII(
+ log_severity_str, switches::kLogSeverity_Warning)) {
+ log_severity = logging::LOG_WARNING;
+ } else if (base::EqualsCaseInsensitiveASCII(log_severity_str,
+ switches::kLogSeverity_Error)) {
+ log_severity = logging::LOG_ERROR;
+ } else if (base::EqualsCaseInsensitiveASCII(log_severity_str,
+ switches::kLogSeverity_Fatal)) {
+ log_severity = logging::LOG_FATAL;
+ } else if (base::EqualsCaseInsensitiveASCII(
+ log_severity_str, switches::kLogSeverity_Disable)) {
+ log_severity = LOGSEVERITY_DISABLE;
+ }
+ }
+
+ if (log_severity == LOGSEVERITY_DISABLE) {
+ log_settings.logging_dest = logging::LOG_NONE;
+ // By default, ERROR and FATAL messages will always be output to stderr due
+ // to the kAlwaysPrintErrorLevel value in base/logging.cc. We change the log
+ // level here so that only FATAL messages are output.
+ logging::SetMinLogLevel(logging::LOG_FATAL);
+ } else {
+ log_settings.logging_dest = logging::LOG_TO_ALL;
+ logging::SetMinLogLevel(log_severity);
+ }
+
+ logging::InitLogging(log_settings);
+
+ ContentSettingsPattern::SetNonWildcardDomainNonPortSchemes(
+ kNonWildcardDomainNonPortSchemes, kNonWildcardDomainNonPortSchemesSize);
+
+ content::SetContentClient(&content_client_);
+
+#if BUILDFLAG(IS_MAC)
+ util_mac::BasicStartupComplete();
+#endif
+
+ return absl::nullopt;
+}
+
+void AlloyMainDelegate::PreSandboxStartup() {
+ const base::CommandLine* command_line =
+ base::CommandLine::ForCurrentProcess();
+ const std::string& process_type =
+ command_line->GetSwitchValueASCII(switches::kProcessType);
+
+ if (process_type.empty()) {
+// Only override these paths when executing the main process.
+#if BUILDFLAG(IS_MAC)
+ util_mac::PreSandboxStartup();
+#elif BUILDFLAG(IS_POSIX)
+ util_linux::PreSandboxStartup();
+#endif
+
+ resource_util::OverrideDefaultDownloadDir();
+ }
+
+ resource_util::OverrideUserDataDir(settings_, command_line);
+
+ if (command_line->HasSwitch(switches::kDisablePackLoading)) {
+ resource_bundle_delegate_.set_pack_loading_disabled(true);
+ }
+
+ // Initialize crash reporting state for this process/module.
+ // chrome::DIR_CRASH_DUMPS must be configured before calling this function.
+ crash_reporting::PreSandboxStartup(*command_line, process_type);
+
+ // Register the component_updater PathProvider.
+ component_updater::RegisterPathProvider(chrome::DIR_COMPONENTS,
+ chrome::DIR_INTERNAL_PLUGINS,
+ chrome::DIR_USER_DATA);
+
+ InitializeResourceBundle();
+ MaybePatchGdiGetFontData();
+}
+
+absl::variant<int, content::MainFunctionParams> AlloyMainDelegate::RunProcess(
+ const std::string& process_type,
+ content::MainFunctionParams main_function_params) {
+ if (process_type.empty()) {
+ return runner_->RunMainProcess(std::move(main_function_params));
+ }
+
+ return std::move(main_function_params);
+}
+
+void AlloyMainDelegate::ProcessExiting(const std::string& process_type) {
+ ui::ResourceBundle::CleanupSharedInstance();
+}
+
+#if BUILDFLAG(IS_LINUX)
+void AlloyMainDelegate::ZygoteForked() {
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+ const std::string& process_type =
+ command_line->GetSwitchValueASCII(switches::kProcessType);
+ // Initialize crash reporting state for the newly forked process.
+ crash_reporting::ZygoteForked(command_line, process_type);
+}
+#endif
+
+content::ContentBrowserClient* AlloyMainDelegate::CreateContentBrowserClient() {
+ browser_client_.reset(new AlloyContentBrowserClient);
+ return browser_client_.get();
+}
+
+content::ContentRendererClient*
+AlloyMainDelegate::CreateContentRendererClient() {
+ renderer_client_.reset(new AlloyContentRendererClient);
+ return renderer_client_.get();
+}
+
+content::ContentUtilityClient* AlloyMainDelegate::CreateContentUtilityClient() {
+ utility_client_.reset(new ChromeContentUtilityClient);
+ return utility_client_.get();
+}
+
+CefRefPtr<CefRequestContext> AlloyMainDelegate::GetGlobalRequestContext() {
+ if (!browser_client_) {
+ return nullptr;
+ }
+ return browser_client_->request_context();
+}
+
+CefBrowserContext* AlloyMainDelegate::CreateNewBrowserContext(
+ const CefRequestContextSettings& settings,
+ base::OnceClosure initialized_cb) {
+ auto context = new AlloyBrowserContext(settings);
+ context->Initialize();
+ std::move(initialized_cb).Run();
+ return context;
+}
+
+scoped_refptr<base::SingleThreadTaskRunner>
+AlloyMainDelegate::GetBackgroundTaskRunner() {
+ if (browser_client_) {
+ return browser_client_->background_task_runner();
+ }
+ return nullptr;
+}
+
+scoped_refptr<base::SingleThreadTaskRunner>
+AlloyMainDelegate::GetUserVisibleTaskRunner() {
+ if (browser_client_) {
+ return browser_client_->user_visible_task_runner();
+ }
+ return nullptr;
+}
+
+scoped_refptr<base::SingleThreadTaskRunner>
+AlloyMainDelegate::GetUserBlockingTaskRunner() {
+ if (browser_client_) {
+ return browser_client_->user_blocking_task_runner();
+ }
+ return nullptr;
+}
+
+scoped_refptr<base::SingleThreadTaskRunner>
+AlloyMainDelegate::GetRenderTaskRunner() {
+ if (renderer_client_) {
+ return renderer_client_->render_task_runner();
+ }
+ return nullptr;
+}
+
+scoped_refptr<base::SingleThreadTaskRunner>
+AlloyMainDelegate::GetWebWorkerTaskRunner() {
+ if (renderer_client_) {
+ return renderer_client_->GetCurrentTaskRunner();
+ }
+ return nullptr;
+}
+
+void AlloyMainDelegate::InitializeResourceBundle() {
+ const base::CommandLine* command_line =
+ base::CommandLine::ForCurrentProcess();
+ base::FilePath resources_pak_file, chrome_100_percent_pak_file,
+ chrome_200_percent_pak_file, locales_dir;
+
+ base::FilePath resources_dir;
+ if (command_line->HasSwitch(switches::kResourcesDirPath)) {
+ resources_dir =
+ command_line->GetSwitchValuePath(switches::kResourcesDirPath);
+ }
+ if (resources_dir.empty()) {
+ resources_dir = resource_util::GetResourcesDir();
+ }
+ if (!resources_dir.empty()) {
+ base::PathService::Override(chrome::DIR_RESOURCES, resources_dir);
+ }
+
+ if (!resource_bundle_delegate_.pack_loading_disabled()) {
+ if (!resources_dir.empty()) {
+ CHECK(resources_dir.IsAbsolute());
+ resources_pak_file =
+ resources_dir.Append(FILE_PATH_LITERAL("resources.pak"));
+ chrome_100_percent_pak_file =
+ resources_dir.Append(FILE_PATH_LITERAL("chrome_100_percent.pak"));
+ chrome_200_percent_pak_file =
+ resources_dir.Append(FILE_PATH_LITERAL("chrome_200_percent.pak"));
+ }
+
+ if (command_line->HasSwitch(switches::kLocalesDirPath)) {
+ locales_dir = command_line->GetSwitchValuePath(switches::kLocalesDirPath);
+ }
+
+ if (!locales_dir.empty()) {
+ base::PathService::Override(ui::DIR_LOCALES, locales_dir);
+ }
+ }
+
+#if BUILDFLAG(IS_WIN)
+ // From chrome/app/chrome_main_delegate.cc
+ // Throbber icons and cursors are still stored in chrome.dll,
+ // this can be killed once those are merged into resources.pak. See
+ // GlassBrowserFrameView::InitThrobberIcons(), https://crbug.com/368327 and
+ // https://crbug.com/1178117.
+ auto module_handle =
+ ::GetModuleHandle(CefAppManager::Get()->GetResourceDllName());
+ if (!module_handle) {
+ module_handle = ::GetModuleHandle(NULL);
+ }
+
+ ui::SetResourcesDataDLL(module_handle);
+#endif
+
+ std::string locale = command_line->GetSwitchValueASCII(switches::kLang);
+ DCHECK(!locale.empty());
+
+ const std::string loaded_locale =
+ ui::ResourceBundle::InitSharedInstanceWithLocale(
+ locale, &resource_bundle_delegate_,
+ ui::ResourceBundle::LOAD_COMMON_RESOURCES);
+ if (!loaded_locale.empty() && g_browser_process) {
+ g_browser_process->SetApplicationLocale(loaded_locale);
+ }
+
+ ui::ResourceBundle& resource_bundle = ui::ResourceBundle::GetSharedInstance();
+
+ if (!resource_bundle_delegate_.pack_loading_disabled()) {
+ if (loaded_locale.empty()) {
+ LOG(ERROR) << "Could not load locale pak for " << locale;
+ }
+
+ resource_bundle_delegate_.set_allow_pack_file_load(true);
+
+ if (base::PathExists(resources_pak_file)) {
+ resource_bundle.AddDataPackFromPath(resources_pak_file,
+ ui::kScaleFactorNone);
+ } else {
+ LOG(ERROR) << "Could not load resources.pak";
+ }
+
+ // Always load the 1x data pack first as the 2x data pack contains both 1x
+ // and 2x images. The 1x data pack only has 1x images, thus passes in an
+ // accurate scale factor to gfx::ImageSkia::AddRepresentation.
+ if (resource_util::IsScaleFactorSupported(ui::k100Percent)) {
+ if (base::PathExists(chrome_100_percent_pak_file)) {
+ resource_bundle.AddDataPackFromPath(chrome_100_percent_pak_file,
+ ui::k100Percent);
+ } else {
+ LOG(ERROR) << "Could not load chrome_100_percent.pak";
+ }
+ }
+
+ if (resource_util::IsScaleFactorSupported(ui::k200Percent)) {
+ if (base::PathExists(chrome_200_percent_pak_file)) {
+ resource_bundle.AddDataPackFromPath(chrome_200_percent_pak_file,
+ ui::k200Percent);
+ } else {
+ LOG(ERROR) << "Could not load chrome_200_percent.pak";
+ }
+ }
+
+ // Skip the default pak file loading that would otherwise occur in
+ // ResourceBundle::LoadChromeResources().
+ resource_bundle_delegate_.set_allow_pack_file_load(false);
+ }
+}
diff --git a/libcef/common/alloy/alloy_main_delegate.h b/libcef/common/alloy/alloy_main_delegate.h
new file mode 100644
index 00000000..45652cc4
--- /dev/null
+++ b/libcef/common/alloy/alloy_main_delegate.h
@@ -0,0 +1,95 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_COMMON_ALLOY_ALLOY_MAIN_DELEGATE_H_
+#define CEF_LIBCEF_COMMON_ALLOY_ALLOY_MAIN_DELEGATE_H_
+#pragma once
+
+#include <string>
+
+#include "include/cef_app.h"
+#include "libcef/common/alloy/alloy_content_client.h"
+#include "libcef/common/app_manager.h"
+#include "libcef/common/main_runner_handler.h"
+#include "libcef/common/resource_bundle_delegate.h"
+#include "libcef/common/task_runner_manager.h"
+
+#include "content/public/app/content_main_delegate.h"
+
+namespace base {
+class CommandLine;
+}
+
+class AlloyContentBrowserClient;
+class AlloyContentRendererClient;
+class ChromeContentUtilityClient;
+
+// Manages state specific to the CEF runtime.
+class AlloyMainDelegate : public content::ContentMainDelegate,
+ public CefAppManager,
+ public CefTaskRunnerManager {
+ public:
+ // |runner| and |settings| will be non-nullptr for the main process only,
+ // and will outlive this object.
+ AlloyMainDelegate(CefMainRunnerHandler* runner,
+ CefSettings* settings,
+ CefRefPtr<CefApp> application);
+
+ AlloyMainDelegate(const AlloyMainDelegate&) = delete;
+ AlloyMainDelegate& operator=(const AlloyMainDelegate&) = delete;
+
+ ~AlloyMainDelegate() override;
+
+ // content::ContentMainDelegate overrides.
+ absl::optional<int> PreBrowserMain() override;
+ absl::optional<int> BasicStartupComplete() override;
+ void PreSandboxStartup() override;
+ absl::variant<int, content::MainFunctionParams> RunProcess(
+ const std::string& process_type,
+ content::MainFunctionParams main_function_params) override;
+ void ProcessExiting(const std::string& process_type) override;
+#if BUILDFLAG(IS_LINUX)
+ void ZygoteForked() override;
+#endif
+ content::ContentBrowserClient* CreateContentBrowserClient() override;
+ content::ContentRendererClient* CreateContentRendererClient() override;
+ content::ContentUtilityClient* CreateContentUtilityClient() override;
+
+ protected:
+ // CefAppManager overrides.
+ CefRefPtr<CefApp> GetApplication() override { return application_; }
+ content::ContentClient* GetContentClient() override {
+ return &content_client_;
+ }
+ CefRefPtr<CefRequestContext> GetGlobalRequestContext() override;
+ CefBrowserContext* CreateNewBrowserContext(
+ const CefRequestContextSettings& settings,
+ base::OnceClosure initialized_cb) override;
+
+ // CefTaskRunnerManager overrides.
+ scoped_refptr<base::SingleThreadTaskRunner> GetBackgroundTaskRunner()
+ override;
+ scoped_refptr<base::SingleThreadTaskRunner> GetUserVisibleTaskRunner()
+ override;
+ scoped_refptr<base::SingleThreadTaskRunner> GetUserBlockingTaskRunner()
+ override;
+ scoped_refptr<base::SingleThreadTaskRunner> GetRenderTaskRunner() override;
+ scoped_refptr<base::SingleThreadTaskRunner> GetWebWorkerTaskRunner() override;
+
+ private:
+ void InitializeResourceBundle();
+
+ CefMainRunnerHandler* const runner_;
+ CefSettings* const settings_;
+ CefRefPtr<CefApp> application_;
+
+ std::unique_ptr<AlloyContentBrowserClient> browser_client_;
+ std::unique_ptr<AlloyContentRendererClient> renderer_client_;
+ std::unique_ptr<ChromeContentUtilityClient> utility_client_;
+ AlloyContentClient content_client_;
+
+ CefResourceBundleDelegate resource_bundle_delegate_;
+};
+
+#endif // CEF_LIBCEF_COMMON_ALLOY_ALLOY_MAIN_DELEGATE_H_
diff --git a/libcef/common/alloy/alloy_main_runner_delegate.cc b/libcef/common/alloy/alloy_main_runner_delegate.cc
new file mode 100644
index 00000000..117c63fc
--- /dev/null
+++ b/libcef/common/alloy/alloy_main_runner_delegate.cc
@@ -0,0 +1,63 @@
+// Copyright 2020 The Chromium Embedded Framework Authors.
+// Portions copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/common/alloy/alloy_main_runner_delegate.h"
+
+#include "libcef/browser/alloy/chrome_browser_process_alloy.h"
+#include "libcef/common/alloy/alloy_main_delegate.h"
+#include "libcef/renderer/alloy/alloy_content_renderer_client.h"
+
+#include "content/public/browser/render_process_host.h"
+#include "ui/base/resource/resource_bundle.h"
+
+AlloyMainRunnerDelegate::AlloyMainRunnerDelegate(CefMainRunnerHandler* runner,
+ CefSettings* settings,
+ CefRefPtr<CefApp> application)
+ : runner_(runner), settings_(settings), application_(application) {}
+AlloyMainRunnerDelegate::~AlloyMainRunnerDelegate() = default;
+
+content::ContentMainDelegate*
+AlloyMainRunnerDelegate::GetContentMainDelegate() {
+ if (!main_delegate_) {
+ main_delegate_ =
+ std::make_unique<AlloyMainDelegate>(runner_, settings_, application_);
+ }
+ return main_delegate_.get();
+}
+
+void AlloyMainRunnerDelegate::BeforeMainThreadInitialize(
+ const CefMainArgs& args) {
+ g_browser_process = new ChromeBrowserProcessAlloy();
+}
+
+void AlloyMainRunnerDelegate::BeforeMainThreadRun() {
+ static_cast<ChromeBrowserProcessAlloy*>(g_browser_process)->Initialize();
+}
+
+void AlloyMainRunnerDelegate::AfterUIThreadInitialize() {
+ static_cast<ChromeBrowserProcessAlloy*>(g_browser_process)
+ ->OnContextInitialized();
+}
+
+void AlloyMainRunnerDelegate::AfterUIThreadShutdown() {
+ static_cast<ChromeBrowserProcessAlloy*>(g_browser_process)
+ ->CleanupOnUIThread();
+
+ ui::ResourceBundle::GetSharedInstance().CleanupOnUIThread();
+}
+
+void AlloyMainRunnerDelegate::BeforeMainThreadShutdown() {
+ if (content::RenderProcessHost::run_renderer_in_process()) {
+ // Blocks until RenderProcess cleanup is complete.
+ AlloyContentRendererClient::Get()->RunSingleProcessCleanup();
+ }
+}
+
+void AlloyMainRunnerDelegate::AfterMainThreadShutdown() {
+ if (g_browser_process) {
+ delete g_browser_process;
+ g_browser_process = nullptr;
+ }
+}
diff --git a/libcef/common/alloy/alloy_main_runner_delegate.h b/libcef/common/alloy/alloy_main_runner_delegate.h
new file mode 100644
index 00000000..0b774647
--- /dev/null
+++ b/libcef/common/alloy/alloy_main_runner_delegate.h
@@ -0,0 +1,48 @@
+// Copyright 2020 The Chromium Embedded Framework Authors.
+// Portions copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_COMMON_ALLOY_ALLOY_MAIN_RUNNER_DELEGATE_
+#define CEF_LIBCEF_COMMON_ALLOY_ALLOY_MAIN_RUNNER_DELEGATE_
+
+#include <memory>
+
+#include "include/cef_base.h"
+#include "libcef/common/main_runner_delegate.h"
+#include "libcef/common/main_runner_handler.h"
+
+class AlloyMainDelegate;
+
+class AlloyMainRunnerDelegate : public CefMainRunnerDelegate {
+ public:
+ // |runner| and |settings| will be non-nullptr for the main process only, and
+ // will outlive this object.
+ AlloyMainRunnerDelegate(CefMainRunnerHandler* runner,
+ CefSettings* settings,
+ CefRefPtr<CefApp> application);
+
+ AlloyMainRunnerDelegate(const AlloyMainRunnerDelegate&) = delete;
+ AlloyMainRunnerDelegate& operator=(const AlloyMainRunnerDelegate&) = delete;
+
+ ~AlloyMainRunnerDelegate() override;
+
+ protected:
+ // CefMainRunnerDelegate overrides.
+ content::ContentMainDelegate* GetContentMainDelegate() override;
+ void BeforeMainThreadInitialize(const CefMainArgs& args) override;
+ void BeforeMainThreadRun() override;
+ void AfterUIThreadInitialize() override;
+ void AfterUIThreadShutdown() override;
+ void BeforeMainThreadShutdown() override;
+ void AfterMainThreadShutdown() override;
+
+ private:
+ std::unique_ptr<AlloyMainDelegate> main_delegate_;
+
+ CefMainRunnerHandler* const runner_;
+ CefSettings* const settings_;
+ CefRefPtr<CefApp> application_;
+};
+
+#endif // CEF_LIBCEF_COMMON_ALLOY_ALLOY_MAIN_RUNNER_DELEGATE_
diff --git a/libcef/common/app_manager.cc b/libcef/common/app_manager.cc
new file mode 100644
index 00000000..167393a7
--- /dev/null
+++ b/libcef/common/app_manager.cc
@@ -0,0 +1,112 @@
+// Copyright 2020 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/common/app_manager.h"
+
+#include "libcef/common/net/scheme_info.h"
+#include "libcef/common/net/scheme_registration.h"
+#include "libcef/common/scheme_registrar_impl.h"
+
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "content/public/browser/child_process_security_policy.h"
+#include "content/public/common/content_switches.h"
+
+#if BUILDFLAG(IS_WIN)
+#include <windows.h>
+#include "base/path_service.h"
+#endif
+
+namespace {
+
+CefAppManager* g_manager = nullptr;
+
+} // namespace
+
+// static
+CefAppManager* CefAppManager::Get() {
+ return g_manager;
+}
+
+CefAppManager::CefAppManager() {
+ // Only a single instance should exist.
+ DCHECK(!g_manager);
+ g_manager = this;
+}
+
+CefAppManager::~CefAppManager() {
+ g_manager = nullptr;
+}
+
+void CefAppManager::AddCustomScheme(CefSchemeInfo* scheme_info) {
+ DCHECK(!scheme_info_list_locked_);
+ scheme_info_list_.push_back(*scheme_info);
+
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+ if (!command_line->HasSwitch(switches::kProcessType)) {
+ // Register as a Web-safe scheme in the browser process so that requests for
+ // the scheme from a render process will be allowed in
+ // resource_dispatcher_host_impl.cc ShouldServiceRequest.
+ content::ChildProcessSecurityPolicy* policy =
+ content::ChildProcessSecurityPolicy::GetInstance();
+ if (!policy->IsWebSafeScheme(scheme_info->scheme_name)) {
+ policy->RegisterWebSafeScheme(scheme_info->scheme_name);
+ }
+ }
+}
+
+bool CefAppManager::HasCustomScheme(const std::string& scheme_name) {
+ DCHECK(scheme_info_list_locked_);
+ if (scheme_info_list_.empty()) {
+ return false;
+ }
+
+ SchemeInfoList::const_iterator it = scheme_info_list_.begin();
+ for (; it != scheme_info_list_.end(); ++it) {
+ if (it->scheme_name == scheme_name) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+const CefAppManager::SchemeInfoList* CefAppManager::GetCustomSchemes() {
+ DCHECK(scheme_info_list_locked_);
+ return &scheme_info_list_;
+}
+
+void CefAppManager::AddAdditionalSchemes(
+ content::ContentClient::Schemes* schemes) {
+ DCHECK(!scheme_info_list_locked_);
+
+ auto application = GetApplication();
+ if (application) {
+ CefSchemeRegistrarImpl schemeRegistrar;
+ application->OnRegisterCustomSchemes(&schemeRegistrar);
+ schemeRegistrar.GetSchemes(schemes);
+ }
+
+ scheme::AddInternalSchemes(schemes);
+
+ scheme_info_list_locked_ = true;
+}
+
+#if BUILDFLAG(IS_WIN)
+const wchar_t* CefAppManager::GetResourceDllName() {
+ static wchar_t file_path[MAX_PATH + 1] = {0};
+
+ if (file_path[0] == 0) {
+ // Retrieve the module path (usually libcef.dll).
+ base::FilePath module;
+ base::PathService::Get(base::FILE_MODULE, &module);
+ const std::wstring wstr = module.value();
+ size_t count = std::min(static_cast<size_t>(MAX_PATH), wstr.size());
+ wcsncpy(file_path, wstr.c_str(), count);
+ file_path[count] = 0;
+ }
+
+ return file_path;
+}
+#endif // BUILDFLAG(IS_WIN)
diff --git a/libcef/common/app_manager.h b/libcef/common/app_manager.h
new file mode 100644
index 00000000..94ea9679
--- /dev/null
+++ b/libcef/common/app_manager.h
@@ -0,0 +1,72 @@
+// Copyright 2020 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_COMMON_APP_MANAGER_H_
+#define CEF_LIBCEF_COMMON_APP_MANAGER_H_
+#pragma once
+
+#include <list>
+
+#include "include/cef_app.h"
+#include "include/cef_request_context.h"
+
+#include "base/functional/callback.h"
+#include "build/build_config.h"
+#include "content/public/common/content_client.h"
+
+class CefBrowserContext;
+struct CefSchemeInfo;
+
+// Exposes global application state in the main and render processes.
+class CefAppManager {
+ public:
+ CefAppManager(const CefAppManager&) = delete;
+ CefAppManager& operator=(const CefAppManager&) = delete;
+
+ // Returns the singleton instance that is scoped to CEF lifespan.
+ static CefAppManager* Get();
+
+ // The following methods are available in both processes.
+
+ virtual CefRefPtr<CefApp> GetApplication() = 0;
+ virtual content::ContentClient* GetContentClient() = 0;
+
+ // Custom scheme information will be registered first with all processes
+ // (url/url_util.h) via ContentClient::AddAdditionalSchemes which calls
+ // AddCustomScheme, and second with Blink (SchemeRegistry) via
+ // ContentRendererClient::WebKitInitialized which calls GetCustomSchemes.
+ void AddCustomScheme(CefSchemeInfo* scheme_info);
+ bool HasCustomScheme(const std::string& scheme_name);
+
+ using SchemeInfoList = std::list<CefSchemeInfo>;
+ const SchemeInfoList* GetCustomSchemes();
+
+ // Called from ContentClient::AddAdditionalSchemes.
+ void AddAdditionalSchemes(content::ContentClient::Schemes* schemes);
+
+ // The following methods are only available in the main (browser) process.
+
+ // Called from CefRequestContextImpl. |initialized_cb| may be executed
+ // synchronously or asynchronously.
+ virtual CefRefPtr<CefRequestContext> GetGlobalRequestContext() = 0;
+ virtual CefBrowserContext* CreateNewBrowserContext(
+ const CefRequestContextSettings& settings,
+ base::OnceClosure initialized_cb) = 0;
+
+#if BUILDFLAG(IS_WIN)
+ // Returns the module name (usually libcef.dll).
+ const wchar_t* GetResourceDllName();
+#endif
+
+ protected:
+ CefAppManager();
+ virtual ~CefAppManager();
+
+ private:
+ // Custom schemes handled by the client.
+ SchemeInfoList scheme_info_list_;
+ bool scheme_info_list_locked_ = false;
+};
+
+#endif // CEF_LIBCEF_COMMON_APP_MANAGER_H_
diff --git a/libcef/common/base_impl.cc b/libcef/common/base_impl.cc
new file mode 100644
index 00000000..1a56c107
--- /dev/null
+++ b/libcef/common/base_impl.cc
@@ -0,0 +1,341 @@
+// Copyright 2014 The Chromium Embedded Framework Authors. Portions copyright
+// 2011 the Chromium Authors. All rights reserved. Use of this source code is
+// governed by a BSD-style license that can be found in the LICENSE file.
+
+#include "include/base/cef_build.h"
+
+#include "include/internal/cef_logging_internal.h"
+#include "include/internal/cef_thread_internal.h"
+#include "include/internal/cef_trace_event_internal.h"
+
+#include "base/logging.h"
+#include "base/threading/platform_thread.h"
+#include "base/trace_event/trace_event.h"
+
+namespace {
+
+constexpr const char kCategory[] = "cef.client";
+
+} // namespace
+
+CEF_EXPORT void cef_trace_event_instant(const char* /* category */,
+ const char* name,
+ const char* arg1_name,
+ uint64 arg1_val,
+ const char* arg2_name,
+ uint64 arg2_val,
+ int copy) {
+ DCHECK(name);
+ if (!name) {
+ return;
+ }
+
+ if (copy) {
+ if (arg1_name == nullptr && arg2_name == nullptr) {
+ TRACE_EVENT_COPY_INSTANT0(kCategory, name, TRACE_EVENT_SCOPE_THREAD);
+ } else if (arg2_name == nullptr) {
+ TRACE_EVENT_COPY_INSTANT1(kCategory, name, TRACE_EVENT_SCOPE_THREAD,
+ arg1_name, arg1_val);
+ } else {
+ TRACE_EVENT_COPY_INSTANT2(kCategory, name, TRACE_EVENT_SCOPE_THREAD,
+ arg1_name, arg1_val, arg2_name, arg2_val);
+ }
+ } else {
+ if (arg1_name == nullptr && arg2_name == nullptr) {
+ TRACE_EVENT_INSTANT0(kCategory, name, TRACE_EVENT_SCOPE_THREAD);
+ } else if (arg2_name == nullptr) {
+ TRACE_EVENT_INSTANT1(kCategory, name, TRACE_EVENT_SCOPE_THREAD, arg1_name,
+ arg1_val);
+ } else {
+ TRACE_EVENT_INSTANT2(kCategory, name, TRACE_EVENT_SCOPE_THREAD, arg1_name,
+ arg1_val, arg2_name, arg2_val);
+ }
+ }
+}
+
+CEF_EXPORT void cef_trace_event_begin(const char* /* category */,
+ const char* name,
+ const char* arg1_name,
+ uint64 arg1_val,
+ const char* arg2_name,
+ uint64 arg2_val,
+ int copy) {
+ DCHECK(name);
+ if (!name) {
+ return;
+ }
+
+ if (copy) {
+ if (arg1_name == nullptr && arg2_name == nullptr) {
+ TRACE_EVENT_BEGIN_WITH_FLAGS0(kCategory, name, TRACE_EVENT_FLAG_COPY);
+ } else if (arg2_name == nullptr) {
+ TRACE_EVENT_BEGIN_WITH_FLAGS1(kCategory, name, TRACE_EVENT_FLAG_COPY,
+ arg1_name, arg1_val);
+ } else {
+ TRACE_EVENT_COPY_BEGIN2(kCategory, name, arg1_name, arg1_val, arg2_name,
+ arg2_val);
+ }
+ } else {
+ if (arg1_name == nullptr && arg2_name == nullptr) {
+ TRACE_EVENT_BEGIN0(kCategory, name);
+ } else if (arg2_name == nullptr) {
+ TRACE_EVENT_BEGIN1(kCategory, name, arg1_name, arg1_val);
+ } else {
+ TRACE_EVENT_BEGIN2(kCategory, name, arg1_name, arg1_val, arg2_name,
+ arg2_val);
+ }
+ }
+}
+
+CEF_EXPORT void cef_trace_event_end(const char* /* category */,
+ const char* name,
+ const char* arg1_name,
+ uint64 arg1_val,
+ const char* arg2_name,
+ uint64 arg2_val,
+ int copy) {
+ DCHECK(name);
+ if (!name) {
+ return;
+ }
+
+ if (copy) {
+ if (arg1_name == nullptr && arg2_name == nullptr) {
+ TRACE_EVENT_END_WITH_FLAGS0(kCategory, name, TRACE_EVENT_FLAG_COPY);
+ } else if (arg2_name == nullptr) {
+ TRACE_EVENT_END_WITH_FLAGS1(kCategory, name, TRACE_EVENT_FLAG_COPY,
+ arg1_name, arg1_val);
+ } else {
+ TRACE_EVENT_COPY_END2(kCategory, name, arg1_name, arg1_val, arg2_name,
+ arg2_val);
+ }
+ } else {
+ if (arg1_name == nullptr && arg2_name == nullptr) {
+ TRACE_EVENT_END0(kCategory, name);
+ } else if (arg2_name == nullptr) {
+ TRACE_EVENT_END1(kCategory, name, arg1_name, arg1_val);
+ } else {
+ TRACE_EVENT_END2(kCategory, name, arg1_name, arg1_val, arg2_name,
+ arg2_val);
+ }
+ }
+}
+
+CEF_EXPORT void cef_trace_counter(const char* /* category */,
+ const char* name,
+ const char* value1_name,
+ uint64 value1_val,
+ const char* value2_name,
+ uint64 value2_val,
+ int copy) {
+ DCHECK(name);
+ if (!name) {
+ return;
+ }
+
+ if (copy) {
+ if (value1_name == nullptr && value2_name == nullptr) {
+ TRACE_COPY_COUNTER1(kCategory, name, value1_val);
+ } else {
+ TRACE_COPY_COUNTER2(kCategory, name, value1_name, value1_val, value2_name,
+ value2_val);
+ }
+ } else {
+ if (value1_name == nullptr && value2_name == nullptr) {
+ TRACE_COUNTER1(kCategory, name, value1_val);
+ } else {
+ TRACE_COUNTER2(kCategory, name, value1_name, value1_val, value2_name,
+ value2_val);
+ }
+ }
+}
+
+CEF_EXPORT void cef_trace_counter_id(const char* /* category */,
+ const char* name,
+ uint64 id,
+ const char* value1_name,
+ uint64 value1_val,
+ const char* value2_name,
+ uint64 value2_val,
+ int copy) {
+ DCHECK(name);
+ if (!name) {
+ return;
+ }
+
+ if (copy) {
+ if (value1_name == nullptr && value2_name == nullptr) {
+ TRACE_COPY_COUNTER_ID1(kCategory, name, id, value1_val);
+ } else {
+ TRACE_COPY_COUNTER_ID2(kCategory, name, id, value1_name, value1_val,
+ value2_name, value2_val);
+ }
+ } else {
+ if (value1_name == nullptr && value2_name == nullptr) {
+ TRACE_COUNTER_ID1(kCategory, name, id, value1_val);
+ } else {
+ TRACE_COUNTER_ID2(kCategory, name, id, value1_name, value1_val,
+ value2_name, value2_val);
+ }
+ }
+}
+
+CEF_EXPORT void cef_trace_event_async_begin(const char* /* category */,
+ const char* name,
+ uint64 id,
+ const char* arg1_name,
+ uint64 arg1_val,
+ const char* arg2_name,
+ uint64 arg2_val,
+ int copy) {
+ DCHECK(name);
+ if (!name) {
+ return;
+ }
+
+ if (copy) {
+ if (arg1_name == nullptr && arg2_name == nullptr) {
+ TRACE_EVENT_COPY_ASYNC_BEGIN0(kCategory, name, id);
+ } else if (arg2_name == nullptr) {
+ TRACE_EVENT_COPY_ASYNC_BEGIN1(kCategory, name, id, arg1_name, arg1_val);
+ } else {
+ TRACE_EVENT_COPY_ASYNC_BEGIN2(kCategory, name, id, arg1_name, arg1_val,
+ arg2_name, arg2_val);
+ }
+ } else {
+ if (arg1_name == nullptr && arg2_name == nullptr) {
+ TRACE_EVENT_ASYNC_BEGIN0(kCategory, name, id);
+ } else if (arg2_name == nullptr) {
+ TRACE_EVENT_ASYNC_BEGIN1(kCategory, name, id, arg1_name, arg1_val);
+ } else {
+ TRACE_EVENT_ASYNC_BEGIN2(kCategory, name, id, arg1_name, arg1_val,
+ arg2_name, arg2_val);
+ }
+ }
+}
+
+CEF_EXPORT void cef_trace_event_async_step_into(const char* /* category */,
+ const char* name,
+ uint64 id,
+ uint64 step,
+ const char* arg1_name,
+ uint64 arg1_val,
+ int copy) {
+ DCHECK(name);
+ if (!name) {
+ return;
+ }
+
+ if (copy) {
+ if (arg1_name == nullptr) {
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP_INTO,
+ kCategory, name, id,
+ TRACE_EVENT_FLAG_COPY, "step", step);
+ } else {
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(
+ TRACE_EVENT_PHASE_ASYNC_STEP_INTO, kCategory, name, id,
+ TRACE_EVENT_FLAG_COPY, "step", step, arg1_name, arg1_val);
+ }
+ } else {
+ if (arg1_name == nullptr) {
+ TRACE_EVENT_ASYNC_STEP_INTO0(kCategory, name, id, step);
+ } else {
+ TRACE_EVENT_ASYNC_STEP_INTO1(kCategory, name, id, step, arg1_name,
+ arg1_val);
+ }
+ }
+}
+
+CEF_EXPORT void cef_trace_event_async_step_past(const char* /* category */,
+ const char* name,
+ uint64 id,
+ uint64 step,
+ const char* arg1_name,
+ uint64 arg1_val,
+ int copy) {
+ DCHECK(name);
+ if (!name) {
+ return;
+ }
+
+ if (copy) {
+ if (arg1_name == nullptr) {
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP_PAST,
+ kCategory, name, id,
+ TRACE_EVENT_FLAG_COPY, "step", step);
+ } else {
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID(
+ TRACE_EVENT_PHASE_ASYNC_STEP_PAST, kCategory, name, id,
+ TRACE_EVENT_FLAG_COPY, "step", step, arg1_name, arg1_val);
+ }
+ } else {
+ if (arg1_name == nullptr) {
+ TRACE_EVENT_ASYNC_STEP_PAST0(kCategory, name, id, step);
+ } else {
+ TRACE_EVENT_ASYNC_STEP_PAST1(kCategory, name, id, step, arg1_name,
+ arg1_val);
+ }
+ }
+}
+
+CEF_EXPORT void cef_trace_event_async_end(const char* /* category */,
+ const char* name,
+ uint64 id,
+ const char* arg1_name,
+ uint64 arg1_val,
+ const char* arg2_name,
+ uint64 arg2_val,
+ int copy) {
+ DCHECK(name);
+ if (!name) {
+ return;
+ }
+
+ if (copy) {
+ if (arg1_name == nullptr && arg2_name == nullptr) {
+ TRACE_EVENT_COPY_ASYNC_END0(kCategory, name, id);
+ } else if (arg2_name == nullptr) {
+ TRACE_EVENT_COPY_ASYNC_END1(kCategory, name, id, arg1_name, arg1_val);
+ } else {
+ TRACE_EVENT_COPY_ASYNC_END2(kCategory, name, id, arg1_name, arg1_val,
+ arg2_name, arg2_val);
+ }
+ } else {
+ if (arg1_name == nullptr && arg2_name == nullptr) {
+ TRACE_EVENT_ASYNC_END0(kCategory, name, id);
+ } else if (arg2_name == nullptr) {
+ TRACE_EVENT_ASYNC_END1(kCategory, name, id, arg1_name, arg1_val);
+ } else {
+ TRACE_EVENT_ASYNC_END2(kCategory, name, id, arg1_name, arg1_val,
+ arg2_name, arg2_val);
+ }
+ }
+}
+
+CEF_EXPORT int cef_get_min_log_level() {
+ return logging::GetMinLogLevel();
+}
+
+CEF_EXPORT int cef_get_vlog_level(const char* file_start, size_t N) {
+ return logging::GetVlogLevelHelper(file_start, N);
+}
+
+CEF_EXPORT void cef_log(const char* file,
+ int line,
+ int severity,
+ const char* message) {
+ logging::LogMessage(file, line, severity).stream() << message;
+}
+
+CEF_EXPORT cef_platform_thread_id_t cef_get_current_platform_thread_id() {
+ return base::PlatformThread::CurrentId();
+}
+
+CEF_EXPORT cef_platform_thread_handle_t
+cef_get_current_platform_thread_handle() {
+#if BUILDFLAG(IS_WIN)
+ return base::PlatformThread::CurrentId();
+#else
+ return base::PlatformThread::CurrentHandle().platform_handle();
+#endif
+}
diff --git a/libcef/common/cdm_host_file_path.cc b/libcef/common/cdm_host_file_path.cc
new file mode 100644
index 00000000..d76009fa
--- /dev/null
+++ b/libcef/common/cdm_host_file_path.cc
@@ -0,0 +1,119 @@
+// Copyright 2022 The Chromium Embedded Framework Authors. Portions Copyright
+// 2017 The Chromium Authors. Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "libcef/common/cdm_host_file_path.h"
+
+#include "base/check.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/notreached.h"
+#include "base/path_service.h"
+#include "build/build_config.h"
+#include "chrome/common/chrome_constants.h"
+#include "chrome/common/chrome_version.h"
+
+#if BUILDFLAG(IS_MAC)
+#include "libcef/common/util_mac.h"
+#endif
+
+namespace cef {
+
+namespace {
+
+// TODO(xhwang): Move this to a common place if needed.
+const base::FilePath::CharType kSignatureFileExtension[] =
+ FILE_PATH_LITERAL(".sig");
+
+// Returns the signature file path given the |file_path|. This function should
+// only be used when the signature file and the file are located in the same
+// directory.
+base::FilePath GetSigFilePath(const base::FilePath& file_path) {
+ return file_path.AddExtension(kSignatureFileExtension);
+}
+
+bool FileExists(const base::FilePath& path) {
+ return base::PathExists(path) && !base::DirectoryExists(path);
+}
+
+} // namespace
+
+void AddCdmHostFilePaths(
+ std::vector<media::CdmHostFilePath>* cdm_host_file_paths) {
+ DVLOG(1) << __func__;
+ DCHECK(cdm_host_file_paths);
+ DCHECK(cdm_host_file_paths->empty());
+
+#if BUILDFLAG(IS_WIN)
+
+ // Find the full path to the current executable.
+ base::FilePath cef_exe;
+ CHECK(base::PathService::Get(base::FILE_EXE, &cef_exe));
+ const auto cef_exe_sig = GetSigFilePath(cef_exe);
+ DVLOG(2) << __func__ << ": exe_path=" << cef_exe.value()
+ << ", signature_path=" << cef_exe_sig.value();
+
+ if (FileExists(cef_exe_sig)) {
+ cdm_host_file_paths->emplace_back(cef_exe, cef_exe_sig);
+ }
+
+ // Find the full path to the module. This may be the same as the executable if
+ // libcef is statically linked.
+ base::FilePath cef_module;
+ CHECK(base::PathService::Get(base::FILE_MODULE, &cef_module));
+ if (cef_module != cef_exe) {
+ const auto cef_module_sig = GetSigFilePath(cef_module);
+ DVLOG(2) << __func__ << ": module_path=" << cef_module.value()
+ << ", signature_path=" << cef_module_sig.value();
+
+ if (FileExists(cef_module_sig)) {
+ cdm_host_file_paths->emplace_back(cef_module, cef_module_sig);
+ }
+ }
+
+#elif BUILDFLAG(IS_MAC)
+
+ // Find the full path to the current executable.
+ base::FilePath cef_exe;
+ CHECK(base::PathService::Get(base::FILE_EXE, &cef_exe));
+
+ // Find the sig file for the executable in the main Resources directory. This
+ // directory may be empty if we're not bundled.
+ const auto main_resources_path = util_mac::GetMainResourcesDirectory();
+ if (!main_resources_path.empty()) {
+ const auto exe_name = cef_exe.BaseName();
+ const auto exe_sig_path =
+ GetSigFilePath(main_resources_path.Append(exe_name));
+
+ DVLOG(2) << __func__ << ": exe_path=" << cef_exe.value()
+ << ", signature_path=" << exe_sig_path.value();
+
+ if (FileExists(exe_sig_path)) {
+ cdm_host_file_paths->emplace_back(cef_exe, exe_sig_path);
+ }
+ }
+
+ // Find the sig file for the framework in the framework Resources directory.
+ // This directory may be empty if we're not bundled.
+ const auto framework_resources_path =
+ util_mac::GetFrameworkResourcesDirectory();
+ if (!framework_resources_path.empty()) {
+ const auto framework_name = util_mac::GetFrameworkName();
+ const auto framework_path =
+ util_mac::GetFrameworkDirectory().Append(framework_name);
+ const auto framework_sig_path =
+ GetSigFilePath(framework_resources_path.Append(framework_name));
+
+ DVLOG(2) << __func__ << ": framework_path=" << framework_path.value()
+ << ", signature_path=" << framework_sig_path.value();
+
+ if (FileExists(framework_sig_path)) {
+ cdm_host_file_paths->emplace_back(framework_path, framework_sig_path);
+ }
+ }
+
+#endif // !BUILDFLAG(IS_MAC)
+}
+
+} // namespace cef
diff --git a/libcef/common/cdm_host_file_path.h b/libcef/common/cdm_host_file_path.h
new file mode 100644
index 00000000..4a41e696
--- /dev/null
+++ b/libcef/common/cdm_host_file_path.h
@@ -0,0 +1,20 @@
+// Copyright 2022 The Chromium Embedded Framework Authors. Portions Copyright
+// 2017 The Chromium Authors. Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_COMMON_CDM_HOST_FILE_PATH_H_
+#define CEF_LIBCEF_COMMON_CDM_HOST_FILE_PATH_H_
+
+#include <vector>
+
+#include "media/cdm/cdm_host_file.h"
+
+namespace cef {
+
+// Gets a list of CDM host file paths and put them in |cdm_host_file_paths|.
+void AddCdmHostFilePaths(
+ std::vector<media::CdmHostFilePath>* cdm_host_file_paths);
+
+} // namespace cef
+
+#endif // CEF_LIBCEF_COMMON_CDM_HOST_FILE_PATH_H_
diff --git a/libcef/common/cef_crash_report_upload_thread.cc b/libcef/common/cef_crash_report_upload_thread.cc
new file mode 100644
index 00000000..08677162
--- /dev/null
+++ b/libcef/common/cef_crash_report_upload_thread.cc
@@ -0,0 +1,220 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/common/cef_crash_report_upload_thread.h"
+
+#include "base/notreached.h"
+#include "libcef/common/cef_crash_report_utils.h"
+#include "third_party/crashpad/crashpad/client/settings.h"
+
+using namespace crashpad;
+
+CefCrashReportUploadThread::CefCrashReportUploadThread(
+ CrashReportDatabase* database,
+ const std::string& url,
+ const Options& options,
+ ProcessPendingReportsObservationCallback callback,
+ int max_uploads)
+ : CrashReportUploadThread(database, url, options, std::move(callback)),
+ max_uploads_(max_uploads) {}
+
+CefCrashReportUploadThread::~CefCrashReportUploadThread() {}
+
+void CefCrashReportUploadThread::ProcessPendingReports() {
+ if (BackoffPending()) {
+ // Try again later.
+ return;
+ }
+
+ if (MaxUploadsEnabled()) {
+ // Retrieve all completed reports.
+ std::vector<CrashReportDatabase::Report> reports;
+ if (database_->GetCompletedReports(&reports) !=
+ CrashReportDatabase::kNoError) {
+ // The database is sick. It might be prudent to stop trying to poke it
+ // from this thread by abandoning the thread altogether. On the other
+ // hand, if the problem is transient, it might be possible to talk to it
+ // again on the next pass. For now, take the latter approach.
+ return;
+ }
+
+ const time_t now = time(nullptr);
+ const int kSeconds = 60 * 60 * 24; // 24 hours
+
+ // Count how many reports have completed in the last 24 hours.
+ recent_upload_ct_ = 0;
+ for (const CrashReportDatabase::Report& report : reports) {
+ if (report.last_upload_attempt_time > now - kSeconds) {
+ recent_upload_ct_++;
+ }
+ }
+ }
+
+ // Continue with processing pending reports.
+ CrashReportUploadThread::ProcessPendingReports();
+}
+
+void CefCrashReportUploadThread::ProcessPendingReport(
+ const CrashReportDatabase::Report& report) {
+ // Always allow upload if it's been explicitly requested by the user.
+ if (!report.upload_explicitly_requested) {
+ if (!UploadsEnabled()) {
+ // Don't attempt an upload if there's no URL or if uploads have been
+ // disabled in the database's settings.
+ database_->SkipReportUpload(
+ report.uuid, Metrics::CrashSkippedReason::kUploadsDisabled);
+ return;
+ }
+
+ if (MaxUploadsExceeded()) {
+ // Don't send uploads if the rate limit has been exceeded.
+ database_->SkipReportUpload(
+ report.uuid, Metrics::CrashSkippedReason::kUploadThrottled);
+ return;
+ }
+ }
+
+ if (BackoffPending()) {
+ // Try again later.
+ return;
+ }
+
+ std::unique_ptr<const CrashReportDatabase::UploadReport> upload_report;
+ CrashReportDatabase::OperationStatus status =
+ database_->GetReportForUploading(report.uuid, &upload_report);
+ switch (status) {
+ case CrashReportDatabase::kNoError:
+ break;
+
+ case CrashReportDatabase::kBusyError:
+ return;
+
+ case CrashReportDatabase::kReportNotFound:
+ case CrashReportDatabase::kFileSystemError:
+ case CrashReportDatabase::kDatabaseError:
+ // In these cases, SkipReportUpload() might not work either, but it's best
+ // to at least try to get the report out of the way.
+ database_->SkipReportUpload(report.uuid,
+ Metrics::CrashSkippedReason::kDatabaseError);
+ return;
+
+ case CrashReportDatabase::kCannotRequestUpload:
+ NOTREACHED();
+ return;
+ }
+
+ std::string response_body;
+ UploadResult upload_result =
+ UploadReport(upload_report.get(), &response_body);
+ switch (upload_result) {
+ case UploadResult::kSuccess:
+ // The upload completed successfully.
+ database_->RecordUploadComplete(std::move(upload_report), response_body);
+ if (MaxUploadsEnabled()) {
+ recent_upload_ct_++;
+ }
+ ResetBackoff();
+ break;
+ case UploadResult::kPermanentFailure:
+ // The upload should never be retried.
+ database_->SkipReportUpload(report.uuid,
+ Metrics::CrashSkippedReason::kUploadFailed);
+ break;
+ case UploadResult::kRetry:
+ // The upload will be retried after a reasonable backoff delay. Since we
+ // didn't successfully upload it we won't count it against the rate limit.
+ IncreaseBackoff();
+ break;
+ }
+}
+
+CrashReportUploadThread::ParameterMap
+CefCrashReportUploadThread::FilterParameters(const ParameterMap& parameters) {
+ return crash_report_utils::FilterParameters(parameters);
+}
+
+bool CefCrashReportUploadThread::UploadsEnabled() const {
+ Settings* const settings = database_->GetSettings();
+ bool uploads_enabled;
+ return !url_.empty() && settings->GetUploadsEnabled(&uploads_enabled) &&
+ uploads_enabled;
+}
+
+bool CefCrashReportUploadThread::MaxUploadsEnabled() const {
+ return options_.rate_limit && max_uploads_ > 0;
+}
+
+bool CefCrashReportUploadThread::MaxUploadsExceeded() const {
+ return MaxUploadsEnabled() && recent_upload_ct_ >= max_uploads_;
+}
+
+bool CefCrashReportUploadThread::BackoffPending() const {
+ if (!options_.rate_limit) {
+ return false;
+ }
+
+ Settings* const settings = database_->GetSettings();
+
+ time_t next_upload_time;
+ if (settings->GetNextUploadAttemptTime(&next_upload_time) &&
+ next_upload_time > 0) {
+ const time_t now = time(nullptr);
+ if (now < next_upload_time) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void CefCrashReportUploadThread::IncreaseBackoff() {
+ if (!options_.rate_limit) {
+ return;
+ }
+
+ const int kHour = 60 * 60; // 1 hour
+ const int kBackoffSchedule[] = {
+ kHour / 4, // 15 minutes
+ kHour, // 1 hour
+ kHour * 2, // 2 hours
+ kHour * 4, // 4 hours
+ kHour * 8, // 8 hours
+ kHour * 24, // 24 hours
+ };
+ const int kBackoffScheduleSize =
+ sizeof(kBackoffSchedule) / sizeof(kBackoffSchedule[0]);
+
+ Settings* settings = database_->GetSettings();
+
+ int backoff_step = 0;
+ if (settings->GetBackoffStep(&backoff_step) && backoff_step < 0) {
+ backoff_step = 0;
+ }
+ if (++backoff_step > kBackoffScheduleSize) {
+ backoff_step = kBackoffScheduleSize;
+ }
+
+ time_t next_upload_time = time(nullptr); // now
+ next_upload_time += kBackoffSchedule[backoff_step - 1];
+
+ settings->SetBackoffStep(backoff_step);
+ settings->SetNextUploadAttemptTime(next_upload_time);
+
+ if (max_uploads_ > 1) {
+ // If the server is having trouble then we don't want to send many crash
+ // reports after the backoff expires. Reduce max uploads to 1 per 24 hours
+ // until the client is restarted.
+ max_uploads_ = 1;
+ }
+}
+
+void CefCrashReportUploadThread::ResetBackoff() {
+ if (!options_.rate_limit) {
+ return;
+ }
+
+ Settings* settings = database_->GetSettings();
+ settings->SetBackoffStep(0);
+ settings->SetNextUploadAttemptTime(0);
+}
diff --git a/libcef/common/cef_crash_report_upload_thread.h b/libcef/common/cef_crash_report_upload_thread.h
new file mode 100644
index 00000000..d0921ac0
--- /dev/null
+++ b/libcef/common/cef_crash_report_upload_thread.h
@@ -0,0 +1,47 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_COMMON_CEF_CRASH_REPORT_UPLOAD_THREAD_H_
+#define CEF_LIBCEF_COMMON_CEF_CRASH_REPORT_UPLOAD_THREAD_H_
+
+#include "third_party/crashpad/crashpad/handler/crash_report_upload_thread.h"
+
+class CefCrashReportUploadThread : public crashpad::CrashReportUploadThread {
+ public:
+ CefCrashReportUploadThread(crashpad::CrashReportDatabase* database,
+ const std::string& url,
+ const Options& options,
+ ProcessPendingReportsObservationCallback callback,
+ int max_uploads);
+
+ CefCrashReportUploadThread(const CefCrashReportUploadThread&) = delete;
+ CefCrashReportUploadThread& operator=(const CefCrashReportUploadThread&) =
+ delete;
+
+ ~CefCrashReportUploadThread();
+
+ private:
+ void ProcessPendingReports() override;
+ void ProcessPendingReport(
+ const crashpad::CrashReportDatabase::Report& report) override;
+ ParameterMap FilterParameters(const ParameterMap& parameters) override;
+
+ bool UploadsEnabled() const;
+
+ bool MaxUploadsEnabled() const;
+ bool MaxUploadsExceeded() const;
+
+ bool BackoffPending() const;
+ void IncreaseBackoff();
+ void ResetBackoff();
+
+ int max_uploads_;
+
+ // Track the number of uploads that have completed within the last 24 hours.
+ // Only used when RateLimitEnabled() is true. Value is reset each time
+ // ProcessPendingReports() is called.
+ int recent_upload_ct_ = 0;
+};
+
+#endif // CEF_LIBCEF_COMMON_CEF_CRASH_REPORT_UPLOAD_THREAD_H_
diff --git a/libcef/common/cef_crash_report_utils.cc b/libcef/common/cef_crash_report_utils.cc
new file mode 100644
index 00000000..2980643d
--- /dev/null
+++ b/libcef/common/cef_crash_report_utils.cc
@@ -0,0 +1,58 @@
+// Copyright 2018 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/common/cef_crash_report_utils.h"
+
+#include "base/strings/string_split.h"
+
+namespace crash_report_utils {
+
+ParameterMap FilterParameters(const ParameterMap& parameters) {
+ ParameterMap in_map = parameters;
+
+ // Extract the key map, if any. Must match the logic in
+ // CefCrashReporterClient::ReadCrashConfigFile.
+ std::string key_map;
+ for (size_t i = 0; true; ++i) {
+ const std::string& key = "K-" + std::string(1, 'A' + i);
+ ParameterMap::iterator it = in_map.find(key);
+ if (it == in_map.end()) {
+ break;
+ }
+ key_map += it->second;
+ in_map.erase(it);
+ }
+
+ if (key_map.empty()) {
+ // Nothing to substitute.
+ return parameters;
+ }
+
+ // Parse |key_map|.
+ base::StringPairs kv_pairs;
+ if (!base::SplitStringIntoKeyValuePairs(key_map, '=', ',', &kv_pairs)) {
+ return parameters;
+ }
+
+ ParameterMap subs;
+ for (const auto& pairs : kv_pairs) {
+ subs.insert(std::make_pair(pairs.first, pairs.second));
+ }
+
+ ParameterMap out_map;
+
+ // Perform key substitutions.
+ for (const auto& params : in_map) {
+ std::string key = params.first;
+ ParameterMap::const_iterator subs_it = subs.find(params.first);
+ if (subs_it != subs.end()) {
+ key = subs_it->second;
+ }
+ out_map.insert(std::make_pair(key, params.second));
+ }
+
+ return out_map;
+}
+
+} // namespace crash_report_utils
diff --git a/libcef/common/cef_crash_report_utils.h b/libcef/common/cef_crash_report_utils.h
new file mode 100644
index 00000000..ef9102ee
--- /dev/null
+++ b/libcef/common/cef_crash_report_utils.h
@@ -0,0 +1,19 @@
+// Copyright 2018 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_COMMON_CEF_CRASH_REPORT_UTILS_H_
+#define CEF_LIBCEF_COMMON_CEF_CRASH_REPORT_UTILS_H_
+
+#include <map>
+#include <string>
+
+namespace crash_report_utils {
+
+using ParameterMap = std::map<std::string, std::string>;
+
+ParameterMap FilterParameters(const ParameterMap& parameters);
+
+} // namespace crash_report_utils
+
+#endif // CEF_LIBCEF_COMMON_CEF_CRASH_REPORT_UTILS_H_
diff --git a/libcef/common/cef_switches.cc b/libcef/common/cef_switches.cc
new file mode 100644
index 00000000..a0cb34db
--- /dev/null
+++ b/libcef/common/cef_switches.cc
@@ -0,0 +1,124 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#include "libcef/common/cef_switches.h"
+
+namespace switches {
+
+// Severity of messages to log.
+const char kLogSeverity[] = "log-severity";
+const char kLogSeverity_Verbose[] = "verbose";
+const char kLogSeverity_Info[] = "info";
+const char kLogSeverity_Warning[] = "warning";
+const char kLogSeverity_Error[] = "error";
+const char kLogSeverity_Fatal[] = "fatal";
+const char kLogSeverity_Disable[] = "disable";
+
+// Path to resources directory.
+const char kResourcesDirPath[] = "resources-dir-path";
+
+// Path to locales directory.
+const char kLocalesDirPath[] = "locales-dir-path";
+
+// Path to locales directory.
+const char kDisablePackLoading[] = "disable-pack-loading";
+
+// Stack size for uncaught exceptions.
+const char kUncaughtExceptionStackSize[] = "uncaught-exception-stack-size";
+
+// Default encoding.
+const char kDefaultEncoding[] = "default-encoding";
+
+// Disable JavaScript.
+const char kDisableJavascript[] = "disable-javascript";
+
+// Disable closing of windows via JavaScript.
+const char kDisableJavascriptCloseWindows[] =
+ "disable-javascript-close-windows";
+
+// Disable clipboard access via JavaScript.
+const char kDisableJavascriptAccessClipboard[] =
+ "disable-javascript-access-clipboard";
+
+// Disable DOM paste via JavaScript execCommand("paste").
+const char kDisableJavascriptDomPaste[] = "disable-javascript-dom-paste";
+
+// Allow universal access from file URLs.
+const char kAllowUniversalAccessFromFileUrls[] =
+ "allow-universal-access-from-files";
+
+// Disable loading of images from the network. A cached image will still be
+// rendered if requested.
+const char kDisableImageLoading[] = "disable-image-loading";
+
+// Shrink stand-alone images to fit.
+const char kImageShrinkStandaloneToFit[] = "image-shrink-standalone-to-fit";
+
+// Disable resizing of text areas.
+const char kDisableTextAreaResize[] = "disable-text-area-resize";
+
+// Disable using the tab key to advance focus to links.
+const char kDisableTabToLinks[] = "disable-tab-to-links";
+
+// Persist session cookies.
+const char kPersistSessionCookies[] = "persist-session-cookies";
+
+// Persist user preferences.
+const char kPersistUserPreferences[] = "persist-user-preferences";
+
+// Enable media (WebRTC audio/video) streaming.
+const char kEnableMediaStream[] = "enable-media-stream";
+
+// Enable speech input (x-webkit-speech).
+const char kEnableSpeechInput[] = "enable-speech-input";
+
+// Enable the speech input profanity filter.
+const char kEnableProfanityFilter[] = "enable-profanity-filter";
+
+// Disable spell checking.
+const char kDisableSpellChecking[] = "disable-spell-checking";
+
+// Enable the remote spelling service.
+const char kEnableSpellingService[] = "enable-spelling-service";
+
+// Override the default spellchecking language which comes from locales.pak.
+const char kOverrideSpellCheckLang[] = "override-spell-check-lang";
+
+// Disable scroll bounce (rubber-banding) on OS X Lion and newer.
+const char kDisableScrollBounce[] = "disable-scroll-bounce";
+
+// Disable the PDF extension.
+const char kDisablePdfExtension[] = "disable-pdf-extension";
+
+// Enable print preview.
+const char kEnablePrintPreview[] = "enable-print-preview";
+
+// Disable the timeout for delivering new browser info to the renderer process.
+const char kDisableNewBrowserInfoTimeout[] = "disable-new-browser-info-timeout";
+
+// File used for logging DevTools protocol messages.
+const char kDevToolsProtocolLogFile[] = "devtools-protocol-log-file";
+
+// Enable use of the Chrome runtime in CEF. See issue #2969 for details.
+const char kEnableChromeRuntime[] = "enable-chrome-runtime";
+
+// Delegate all login requests to the client GetAuthCredentials callback when
+// using the Chrome runtime.
+const char kDisableChromeLoginPrompt[] = "disable-chrome-login-prompt";
+
+// Override the product component of the default User-Agent string.
+const char kUserAgentProductAndVersion[] = "user-agent-product";
+
+// Disable request handling in CEF to faciliate debugging of network-related
+// issues.
+const char kDisableRequestHandlingForTesting[] =
+ "disable-request-handling-for-testing";
+
+#if BUILDFLAG(IS_MAC)
+// Path to the framework directory.
+const char kFrameworkDirPath[] = "framework-dir-path";
+const char kMainBundlePath[] = "main-bundle-path";
+#endif
+
+} // namespace switches
diff --git a/libcef/common/cef_switches.h b/libcef/common/cef_switches.h
new file mode 100644
index 00000000..b2748dc8
--- /dev/null
+++ b/libcef/common/cef_switches.h
@@ -0,0 +1,61 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+// Defines all the "cef" command-line switches.
+
+#ifndef CEF_LIBCEF_COMMON_CEF_SWITCHES_H_
+#define CEF_LIBCEF_COMMON_CEF_SWITCHES_H_
+#pragma once
+
+#include "build/build_config.h"
+
+namespace switches {
+
+extern const char kLogSeverity[];
+extern const char kLogSeverity_Verbose[];
+extern const char kLogSeverity_Info[];
+extern const char kLogSeverity_Warning[];
+extern const char kLogSeverity_Error[];
+extern const char kLogSeverity_Fatal[];
+extern const char kLogSeverity_Disable[];
+extern const char kResourcesDirPath[];
+extern const char kLocalesDirPath[];
+extern const char kDisablePackLoading[];
+extern const char kUncaughtExceptionStackSize[];
+extern const char kDefaultEncoding[];
+extern const char kDisableJavascript[];
+extern const char kDisableJavascriptCloseWindows[];
+extern const char kDisableJavascriptAccessClipboard[];
+extern const char kDisableJavascriptDomPaste[];
+extern const char kAllowUniversalAccessFromFileUrls[];
+extern const char kDisableImageLoading[];
+extern const char kImageShrinkStandaloneToFit[];
+extern const char kDisableTextAreaResize[];
+extern const char kDisableTabToLinks[];
+extern const char kPersistSessionCookies[];
+extern const char kPersistUserPreferences[];
+extern const char kEnableMediaStream[];
+extern const char kEnableSpeechInput[];
+extern const char kEnableProfanityFilter[];
+extern const char kDisableSpellChecking[];
+extern const char kEnableSpellingService[];
+extern const char kOverrideSpellCheckLang[];
+extern const char kDisableScrollBounce[];
+extern const char kDisablePdfExtension[];
+extern const char kEnablePrintPreview[];
+extern const char kDisableNewBrowserInfoTimeout[];
+extern const char kDevToolsProtocolLogFile[];
+extern const char kEnableChromeRuntime[];
+extern const char kDisableChromeLoginPrompt[];
+extern const char kUserAgentProductAndVersion[];
+extern const char kDisableRequestHandlingForTesting[];
+
+#if BUILDFLAG(IS_MAC)
+extern const char kFrameworkDirPath[];
+extern const char kMainBundlePath[];
+#endif
+
+} // namespace switches
+
+#endif // CEF_LIBCEF_COMMON_CEF_SWITCHES_H_
diff --git a/libcef/common/chrome/chrome_content_client_cef.cc b/libcef/common/chrome/chrome_content_client_cef.cc
new file mode 100644
index 00000000..e64a6c3e
--- /dev/null
+++ b/libcef/common/chrome/chrome_content_client_cef.cc
@@ -0,0 +1,36 @@
+// Copyright 2015 The Chromium Embedded Framework Authors.
+// Portions copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/common/chrome/chrome_content_client_cef.h"
+
+#include "libcef/common/app_manager.h"
+
+#include "chrome/common/media/cdm_registration.h"
+
+#if BUILDFLAG(ENABLE_CDM_HOST_VERIFICATION)
+#include "libcef/common/cdm_host_file_path.h"
+#endif
+
+ChromeContentClientCef::ChromeContentClientCef() = default;
+ChromeContentClientCef::~ChromeContentClientCef() = default;
+
+void ChromeContentClientCef::AddContentDecryptionModules(
+ std::vector<content::CdmInfo>* cdms,
+ std::vector<media::CdmHostFilePath>* cdm_host_file_paths) {
+ if (cdms) {
+ RegisterCdmInfo(cdms);
+ }
+
+#if BUILDFLAG(ENABLE_CDM_HOST_VERIFICATION)
+ if (cdm_host_file_paths) {
+ cef::AddCdmHostFilePaths(cdm_host_file_paths);
+ }
+#endif
+}
+
+void ChromeContentClientCef::AddAdditionalSchemes(Schemes* schemes) {
+ ChromeContentClient::AddAdditionalSchemes(schemes);
+ CefAppManager::Get()->AddAdditionalSchemes(schemes);
+}
diff --git a/libcef/common/chrome/chrome_content_client_cef.h b/libcef/common/chrome/chrome_content_client_cef.h
new file mode 100644
index 00000000..e5ec8778
--- /dev/null
+++ b/libcef/common/chrome/chrome_content_client_cef.h
@@ -0,0 +1,23 @@
+// Copyright 2015 The Chromium Embedded Framework Authors.
+// Portions copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_COMMON_CHROME_CHROME_CONTENT_CLIENT_CEF_H_
+#define CEF_LIBCEF_COMMON_CHROME_CHROME_CONTENT_CLIENT_CEF_H_
+
+#include "chrome/common/chrome_content_client.h"
+
+class ChromeContentClientCef : public ChromeContentClient {
+ public:
+ ChromeContentClientCef();
+ ~ChromeContentClientCef() override;
+
+ // content::ContentClient overrides.
+ void AddContentDecryptionModules(
+ std::vector<content::CdmInfo>* cdms,
+ std::vector<media::CdmHostFilePath>* cdm_host_file_paths) override;
+ void AddAdditionalSchemes(Schemes* schemes) override;
+};
+
+#endif // CEF_LIBCEF_COMMON_CHROME_CHROME_CONTENT_CLIENT_CEF_H_
diff --git a/libcef/common/chrome/chrome_main_delegate_cef.cc b/libcef/common/chrome/chrome_main_delegate_cef.cc
new file mode 100644
index 00000000..de9dbf3e
--- /dev/null
+++ b/libcef/common/chrome/chrome_main_delegate_cef.cc
@@ -0,0 +1,346 @@
+// Copyright 2020 The Chromium Embedded Framework Authors.
+// Portions copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/common/chrome/chrome_main_delegate_cef.h"
+
+#include <tuple>
+
+#include "libcef/browser/chrome/chrome_browser_context.h"
+#include "libcef/browser/chrome/chrome_content_browser_client_cef.h"
+#include "libcef/common/cef_switches.h"
+#include "libcef/common/command_line_impl.h"
+#include "libcef/common/crash_reporting.h"
+#include "libcef/common/resource_util.h"
+#include "libcef/renderer/chrome/chrome_content_renderer_client_cef.h"
+
+#include "base/base_switches.h"
+#include "base/command_line.h"
+#include "base/lazy_instance.h"
+#include "base/threading/threading_features.h"
+#include "chrome/browser/metrics/chrome_feature_list_creator.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/pref_names.h"
+#include "components/embedder_support/switches.h"
+#include "content/public/common/content_switches.h"
+#include "sandbox/policy/switches.h"
+#include "third_party/blink/public/common/switches.h"
+#include "ui/base/ui_base_switches.h"
+
+#if BUILDFLAG(IS_MAC)
+#include "libcef/common/util_mac.h"
+#elif BUILDFLAG(IS_POSIX)
+#include "libcef/common/util_linux.h"
+#endif
+
+#if BUILDFLAG(IS_MAC)
+#include "libcef/common/util_mac.h"
+#endif
+
+namespace {
+
+base::LazyInstance<ChromeContentRendererClientCef>::DestructorAtExit
+ g_chrome_content_renderer_client = LAZY_INSTANCE_INITIALIZER;
+
+} // namespace
+
+ChromeMainDelegateCef::ChromeMainDelegateCef(CefMainRunnerHandler* runner,
+ CefSettings* settings,
+ CefRefPtr<CefApp> application)
+ : ChromeMainDelegate(base::TimeTicks::Now()),
+ runner_(runner),
+ settings_(settings),
+ application_(application) {
+#if BUILDFLAG(IS_LINUX)
+ resource_util::OverrideAssetPath();
+#endif
+}
+
+ChromeMainDelegateCef::~ChromeMainDelegateCef() = default;
+
+absl::optional<int> ChromeMainDelegateCef::BasicStartupComplete() {
+ // Returns false if startup should proceed.
+ auto result = ChromeMainDelegate::BasicStartupComplete();
+ if (result.has_value()) {
+ return result;
+ }
+
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+
+#if BUILDFLAG(IS_POSIX)
+ // Read the crash configuration file. On Windows this is done from chrome_elf.
+ crash_reporting::BasicStartupComplete(command_line);
+#endif
+
+ const std::string& process_type =
+ command_line->GetSwitchValueASCII(switches::kProcessType);
+ if (process_type.empty()) {
+ // In the browser process. Populate the global command-line object.
+ // TODO(chrome-runtime): Copy more settings from AlloyMainDelegate and test.
+ if (settings_->command_line_args_disabled) {
+ // Remove any existing command-line arguments.
+ base::CommandLine::StringVector argv;
+ argv.push_back(command_line->GetProgram().value());
+ command_line->InitFromArgv(argv);
+
+ const base::CommandLine::SwitchMap& map = command_line->GetSwitches();
+ const_cast<base::CommandLine::SwitchMap*>(&map)->clear();
+ }
+
+ bool no_sandbox = settings_->no_sandbox ? true : false;
+
+ if (no_sandbox) {
+ command_line->AppendSwitch(sandbox::policy::switches::kNoSandbox);
+ }
+
+ if (settings_->user_agent.length > 0) {
+ command_line->AppendSwitchASCII(
+ embedder_support::kUserAgent,
+ CefString(&settings_->user_agent).ToString());
+ } else if (settings_->user_agent_product.length > 0) {
+ command_line->AppendSwitchASCII(
+ switches::kUserAgentProductAndVersion,
+ CefString(&settings_->user_agent_product).ToString());
+ }
+
+ if (settings_->locale.length > 0) {
+ command_line->AppendSwitchASCII(switches::kLang,
+ CefString(&settings_->locale).ToString());
+ } else if (!command_line->HasSwitch(switches::kLang)) {
+ command_line->AppendSwitchASCII(switches::kLang, "en-US");
+ }
+
+ if (settings_->javascript_flags.length > 0) {
+ command_line->AppendSwitchASCII(
+ blink::switches::kJavaScriptFlags,
+ CefString(&settings_->javascript_flags).ToString());
+ }
+
+ if (settings_->remote_debugging_port >= 1024 &&
+ settings_->remote_debugging_port <= 65535) {
+ command_line->AppendSwitchASCII(
+ switches::kRemoteDebuggingPort,
+ base::NumberToString(settings_->remote_debugging_port));
+ }
+
+ if (settings_->uncaught_exception_stack_size > 0) {
+ command_line->AppendSwitchASCII(
+ switches::kUncaughtExceptionStackSize,
+ base::NumberToString(settings_->uncaught_exception_stack_size));
+ }
+
+ std::vector<std::string> disable_features;
+
+ if (!!settings_->multi_threaded_message_loop &&
+ base::kEnableHangWatcher.default_state ==
+ base::FEATURE_ENABLED_BY_DEFAULT) {
+ // Disable EnableHangWatcher when running with multi-threaded-message-loop
+ // to avoid shutdown crashes (see issue #3403).
+ disable_features.push_back(base::kEnableHangWatcher.name);
+ }
+
+ if (!disable_features.empty()) {
+ DCHECK(!base::FeatureList::GetInstance());
+ std::string disable_features_str =
+ command_line->GetSwitchValueASCII(switches::kDisableFeatures);
+ for (auto feature_str : disable_features) {
+ if (!disable_features_str.empty()) {
+ disable_features_str += ",";
+ }
+ disable_features_str += feature_str;
+ }
+ command_line->AppendSwitchASCII(switches::kDisableFeatures,
+ disable_features_str);
+ }
+ }
+
+ if (application_) {
+ // Give the application a chance to view/modify the command line.
+ CefRefPtr<CefCommandLineImpl> commandLinePtr(
+ new CefCommandLineImpl(command_line, false, false));
+ application_->OnBeforeCommandLineProcessing(process_type,
+ commandLinePtr.get());
+ std::ignore = commandLinePtr->Detach(nullptr);
+ }
+
+#if BUILDFLAG(IS_MAC)
+ util_mac::BasicStartupComplete();
+#endif
+
+ return absl::nullopt;
+}
+
+void ChromeMainDelegateCef::PreSandboxStartup() {
+ const base::CommandLine* command_line =
+ base::CommandLine::ForCurrentProcess();
+ const std::string& process_type =
+ command_line->GetSwitchValueASCII(switches::kProcessType);
+
+ if (process_type.empty()) {
+#if BUILDFLAG(IS_MAC)
+ util_mac::PreSandboxStartup();
+#elif BUILDFLAG(IS_POSIX)
+ util_linux::PreSandboxStartup();
+#endif
+ }
+
+ // Since this may be configured via CefSettings we override the value on
+ // all platforms. We can't use the default implementation on macOS because
+ // chrome::GetDefaultUserDataDirectory expects to find the Chromium version
+ // number in the app bundle path.
+ resource_util::OverrideUserDataDir(settings_, command_line);
+
+ ChromeMainDelegate::PreSandboxStartup();
+
+ // Initialize crash reporting state for this process/module.
+ // chrome::DIR_CRASH_DUMPS must be configured before calling this function.
+ crash_reporting::PreSandboxStartup(*command_line, process_type);
+}
+
+absl::optional<int> ChromeMainDelegateCef::PreBrowserMain() {
+ // The parent ChromeMainDelegate implementation creates the NSApplication
+ // instance on macOS, and we intentionally don't want to do that here.
+ // TODO(macos): Do we need l10n_util::OverrideLocaleWithCocoaLocale()?
+ runner_->PreBrowserMain();
+ return absl::nullopt;
+}
+
+absl::optional<int> ChromeMainDelegateCef::PostEarlyInitialization(
+ InvokedIn invoked_in) {
+ const auto result = ChromeMainDelegate::PostEarlyInitialization(invoked_in);
+ if (!result) {
+ const auto* invoked_in_browser =
+ absl::get_if<InvokedInBrowserProcess>(&invoked_in);
+ if (invoked_in_browser) {
+ // At this point local_state has been created but ownership has not yet
+ // been passed to BrowserProcessImpl (g_browser_process is nullptr).
+ auto* local_state = chrome_content_browser_client_->startup_data()
+ ->chrome_feature_list_creator()
+ ->local_state();
+
+ // Don't show the profile picker on startup (see issue #3440).
+ local_state->SetBoolean(prefs::kBrowserShowProfilePickerOnStartup, false);
+ }
+ }
+
+ return result;
+}
+
+absl::variant<int, content::MainFunctionParams>
+ChromeMainDelegateCef::RunProcess(
+ const std::string& process_type,
+ content::MainFunctionParams main_function_params) {
+ if (process_type.empty()) {
+ return runner_->RunMainProcess(std::move(main_function_params));
+ }
+
+ return ChromeMainDelegate::RunProcess(process_type,
+ std::move(main_function_params));
+}
+
+#if BUILDFLAG(IS_LINUX)
+void ChromeMainDelegateCef::ZygoteForked() {
+ ChromeMainDelegate::ZygoteForked();
+
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+ const std::string& process_type =
+ command_line->GetSwitchValueASCII(switches::kProcessType);
+
+ // Initialize crash reporting state for the newly forked process.
+ crash_reporting::ZygoteForked(command_line, process_type);
+}
+#endif // BUILDFLAG(IS_LINUX)
+
+content::ContentClient* ChromeMainDelegateCef::CreateContentClient() {
+ return &chrome_content_client_cef_;
+}
+
+content::ContentBrowserClient*
+ChromeMainDelegateCef::CreateContentBrowserClient() {
+ // Match the logic in the parent ChromeMainDelegate implementation, but create
+ // our own object type.
+ chrome_content_browser_client_ =
+ std::make_unique<ChromeContentBrowserClientCef>();
+ return chrome_content_browser_client_.get();
+}
+
+content::ContentRendererClient*
+ChromeMainDelegateCef::CreateContentRendererClient() {
+ return g_chrome_content_renderer_client.Pointer();
+}
+
+CefRefPtr<CefRequestContext> ChromeMainDelegateCef::GetGlobalRequestContext() {
+ auto browser_client = content_browser_client();
+ if (browser_client) {
+ return browser_client->request_context();
+ }
+ return nullptr;
+}
+
+CefBrowserContext* ChromeMainDelegateCef::CreateNewBrowserContext(
+ const CefRequestContextSettings& settings,
+ base::OnceClosure initialized_cb) {
+ auto context = new ChromeBrowserContext(settings);
+ context->InitializeAsync(std::move(initialized_cb));
+ return context;
+}
+
+scoped_refptr<base::SingleThreadTaskRunner>
+ChromeMainDelegateCef::GetBackgroundTaskRunner() {
+ auto browser_client = content_browser_client();
+ if (browser_client) {
+ return browser_client->background_task_runner();
+ }
+ return nullptr;
+}
+
+scoped_refptr<base::SingleThreadTaskRunner>
+ChromeMainDelegateCef::GetUserVisibleTaskRunner() {
+ auto browser_client = content_browser_client();
+ if (browser_client) {
+ return browser_client->user_visible_task_runner();
+ }
+ return nullptr;
+}
+
+scoped_refptr<base::SingleThreadTaskRunner>
+ChromeMainDelegateCef::GetUserBlockingTaskRunner() {
+ auto browser_client = content_browser_client();
+ if (browser_client) {
+ return browser_client->user_blocking_task_runner();
+ }
+ return nullptr;
+}
+
+scoped_refptr<base::SingleThreadTaskRunner>
+ChromeMainDelegateCef::GetRenderTaskRunner() {
+ auto renderer_client = content_renderer_client();
+ if (renderer_client) {
+ return renderer_client->render_task_runner();
+ }
+ return nullptr;
+}
+
+scoped_refptr<base::SingleThreadTaskRunner>
+ChromeMainDelegateCef::GetWebWorkerTaskRunner() {
+ auto renderer_client = content_renderer_client();
+ if (renderer_client) {
+ return renderer_client->GetCurrentTaskRunner();
+ }
+ return nullptr;
+}
+
+ChromeContentBrowserClientCef* ChromeMainDelegateCef::content_browser_client()
+ const {
+ return static_cast<ChromeContentBrowserClientCef*>(
+ chrome_content_browser_client_.get());
+}
+
+ChromeContentRendererClientCef* ChromeMainDelegateCef::content_renderer_client()
+ const {
+ if (!g_chrome_content_renderer_client.IsCreated()) {
+ return nullptr;
+ }
+ return g_chrome_content_renderer_client.Pointer();
+} \ No newline at end of file
diff --git a/libcef/common/chrome/chrome_main_delegate_cef.h b/libcef/common/chrome/chrome_main_delegate_cef.h
new file mode 100644
index 00000000..cfe768f0
--- /dev/null
+++ b/libcef/common/chrome/chrome_main_delegate_cef.h
@@ -0,0 +1,86 @@
+// Copyright 2020 The Chromium Embedded Framework Authors.
+// Portions copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_COMMON_CHROME_CHROME_MAIN_DELEGATE_CEF_
+#define CEF_LIBCEF_COMMON_CHROME_CHROME_MAIN_DELEGATE_CEF_
+
+#include <memory>
+
+#include "include/cef_app.h"
+#include "libcef/common/app_manager.h"
+#include "libcef/common/chrome/chrome_content_client_cef.h"
+#include "libcef/common/main_runner_handler.h"
+#include "libcef/common/task_runner_manager.h"
+
+#include "chrome/app/chrome_main_delegate.h"
+
+class ChromeContentBrowserClientCef;
+class ChromeContentRendererClientCef;
+
+// CEF override of ChromeMainDelegate
+class ChromeMainDelegateCef : public ChromeMainDelegate,
+ public CefAppManager,
+ public CefTaskRunnerManager {
+ public:
+ // |runner| will be non-nullptr for the main process only, and will outlive
+ // this object.
+ ChromeMainDelegateCef(CefMainRunnerHandler* runner,
+ CefSettings* settings,
+ CefRefPtr<CefApp> application);
+
+ ChromeMainDelegateCef(const ChromeMainDelegateCef&) = delete;
+ ChromeMainDelegateCef& operator=(const ChromeMainDelegateCef&) = delete;
+
+ ~ChromeMainDelegateCef() override;
+
+ // ChromeMainDelegate overrides.
+ absl::optional<int> BasicStartupComplete() override;
+ void PreSandboxStartup() override;
+ absl::optional<int> PreBrowserMain() override;
+ absl::optional<int> PostEarlyInitialization(InvokedIn invoked_in) override;
+ absl::variant<int, content::MainFunctionParams> RunProcess(
+ const std::string& process_type,
+ content::MainFunctionParams main_function_params) override;
+#if BUILDFLAG(IS_LINUX)
+ void ZygoteForked() override;
+#endif
+ content::ContentClient* CreateContentClient() override;
+ content::ContentBrowserClient* CreateContentBrowserClient() override;
+ content::ContentRendererClient* CreateContentRendererClient() override;
+
+ protected:
+ // CefAppManager overrides.
+ CefRefPtr<CefApp> GetApplication() override { return application_; }
+ content::ContentClient* GetContentClient() override {
+ return &chrome_content_client_cef_;
+ }
+ CefRefPtr<CefRequestContext> GetGlobalRequestContext() override;
+ CefBrowserContext* CreateNewBrowserContext(
+ const CefRequestContextSettings& settings,
+ base::OnceClosure initialized_cb) override;
+
+ // CefTaskRunnerManager overrides.
+ scoped_refptr<base::SingleThreadTaskRunner> GetBackgroundTaskRunner()
+ override;
+ scoped_refptr<base::SingleThreadTaskRunner> GetUserVisibleTaskRunner()
+ override;
+ scoped_refptr<base::SingleThreadTaskRunner> GetUserBlockingTaskRunner()
+ override;
+ scoped_refptr<base::SingleThreadTaskRunner> GetRenderTaskRunner() override;
+ scoped_refptr<base::SingleThreadTaskRunner> GetWebWorkerTaskRunner() override;
+
+ private:
+ ChromeContentBrowserClientCef* content_browser_client() const;
+ ChromeContentRendererClientCef* content_renderer_client() const;
+
+ CefMainRunnerHandler* const runner_;
+ CefSettings* const settings_;
+ CefRefPtr<CefApp> application_;
+
+ // We use this instead of ChromeMainDelegate::chrome_content_client_.
+ ChromeContentClientCef chrome_content_client_cef_;
+};
+
+#endif // CEF_LIBCEF_COMMON_CHROME_CHROME_MAIN_DELEGATE_CEF_
diff --git a/libcef/common/chrome/chrome_main_runner_delegate.cc b/libcef/common/chrome/chrome_main_runner_delegate.cc
new file mode 100644
index 00000000..57a92d93
--- /dev/null
+++ b/libcef/common/chrome/chrome_main_runner_delegate.cc
@@ -0,0 +1,90 @@
+// Copyright 2020 The Chromium Embedded Framework Authors.
+// Portions copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/common/chrome/chrome_main_runner_delegate.h"
+
+#include "libcef/common/app_manager.h"
+#include "libcef/common/chrome/chrome_main_delegate_cef.h"
+
+#include "base/command_line.h"
+#include "base/run_loop.h"
+#include "chrome/browser/browser_process_impl.h"
+#include "chrome/browser/chrome_content_browser_client.h"
+#include "chrome/common/profiler/main_thread_stack_sampling_profiler.h"
+#include "components/keep_alive_registry/keep_alive_types.h"
+#include "components/keep_alive_registry/scoped_keep_alive.h"
+
+ChromeMainRunnerDelegate::ChromeMainRunnerDelegate(
+ CefMainRunnerHandler* runner,
+ CefSettings* settings,
+ CefRefPtr<CefApp> application)
+ : runner_(runner), settings_(settings), application_(application) {}
+
+ChromeMainRunnerDelegate::~ChromeMainRunnerDelegate() = default;
+
+content::ContentMainDelegate*
+ChromeMainRunnerDelegate::GetContentMainDelegate() {
+ if (!main_delegate_) {
+ main_delegate_ = std::make_unique<ChromeMainDelegateCef>(runner_, settings_,
+ application_);
+ }
+ return main_delegate_.get();
+}
+
+void ChromeMainRunnerDelegate::BeforeMainThreadInitialize(
+ const CefMainArgs& args) {
+#if BUILDFLAG(IS_WIN)
+ base::CommandLine::Init(0, nullptr);
+#else
+ base::CommandLine::Init(args.argc, args.argv);
+#endif
+}
+
+void ChromeMainRunnerDelegate::BeforeMainMessageLoopRun(
+ base::RunLoop* run_loop) {
+ // The ScopedKeepAlive instance triggers shutdown logic when released on the
+ // UI thread before terminating the message loop (e.g. from CefQuitMessageLoop
+ // or FinishShutdownOnUIThread when running with multi-threaded message loop).
+ keep_alive_ = std::make_unique<ScopedKeepAlive>(
+ KeepAliveOrigin::APP_CONTROLLER, KeepAliveRestartOption::DISABLED);
+
+ // The idle callback will be executed from BrowserProcessImpl::Unpin() via
+ // KeepAliveRegistry when the last ScopedKeepAlive is released.
+ // ScopedKeepAlives are also held by Browser objects.
+ DCHECK(g_browser_process);
+ static_cast<BrowserProcessImpl*>(g_browser_process)
+ ->SetQuitClosure(run_loop->QuitWhenIdleClosure());
+}
+
+bool ChromeMainRunnerDelegate::HandleMainMessageLoopQuit() {
+ // May be called multiple times. See comments in RunMainMessageLoopBefore.
+ keep_alive_.reset();
+
+ // Cancel direct execution of the QuitWhenIdleClosure() in
+ // CefMainRunner::QuitMessageLoop. We instead wait for all Chrome browser
+ // windows to exit.
+ return true;
+}
+
+void ChromeMainRunnerDelegate::BeforeUIThreadInitialize() {
+ sampling_profiler_ = std::make_unique<MainThreadStackSamplingProfiler>();
+}
+
+void ChromeMainRunnerDelegate::AfterUIThreadShutdown() {
+ static_cast<ChromeContentBrowserClient*>(
+ CefAppManager::Get()->GetContentClient()->browser())
+ ->CleanupOnUIThread();
+ main_delegate_->CleanupOnUIThread();
+
+ sampling_profiler_.reset();
+}
+
+void ChromeMainRunnerDelegate::BeforeExecuteProcess(const CefMainArgs& args) {
+ BeforeMainThreadInitialize(args);
+}
+
+void ChromeMainRunnerDelegate::AfterExecuteProcess() {
+ AfterMainThreadShutdown();
+}
diff --git a/libcef/common/chrome/chrome_main_runner_delegate.h b/libcef/common/chrome/chrome_main_runner_delegate.h
new file mode 100644
index 00000000..970cecd1
--- /dev/null
+++ b/libcef/common/chrome/chrome_main_runner_delegate.h
@@ -0,0 +1,54 @@
+// Copyright 2020 The Chromium Embedded Framework Authors.
+// Portions copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_COMMON_CHROME_CHROME_MAIN_RUNNER_DELEGATE_CEF_
+#define CEF_LIBCEF_COMMON_CHROME_CHROME_MAIN_RUNNER_DELEGATE_CEF_
+
+#include <memory>
+
+#include "include/cef_app.h"
+#include "libcef/common/main_runner_delegate.h"
+#include "libcef/common/main_runner_handler.h"
+
+class ChromeMainDelegateCef;
+class MainThreadStackSamplingProfiler;
+class ScopedKeepAlive;
+
+class ChromeMainRunnerDelegate : public CefMainRunnerDelegate {
+ public:
+ // |runner| will be non-nullptr for the main process only, and will outlive
+ // this object.
+ ChromeMainRunnerDelegate(CefMainRunnerHandler* runner,
+ CefSettings* settings,
+ CefRefPtr<CefApp> application);
+
+ ChromeMainRunnerDelegate(const ChromeMainRunnerDelegate&) = delete;
+ ChromeMainRunnerDelegate& operator=(const ChromeMainRunnerDelegate&) = delete;
+
+ ~ChromeMainRunnerDelegate() override;
+
+ protected:
+ // CefMainRunnerDelegate overrides.
+ content::ContentMainDelegate* GetContentMainDelegate() override;
+ void BeforeMainThreadInitialize(const CefMainArgs& args) override;
+ void BeforeMainMessageLoopRun(base::RunLoop* run_loop) override;
+ bool HandleMainMessageLoopQuit() override;
+ void BeforeUIThreadInitialize() override;
+ void AfterUIThreadShutdown() override;
+ void BeforeExecuteProcess(const CefMainArgs& args) override;
+ void AfterExecuteProcess() override;
+
+ private:
+ std::unique_ptr<ChromeMainDelegateCef> main_delegate_;
+
+ std::unique_ptr<MainThreadStackSamplingProfiler> sampling_profiler_;
+ std::unique_ptr<ScopedKeepAlive> keep_alive_;
+
+ CefMainRunnerHandler* const runner_;
+ CefSettings* const settings_;
+ CefRefPtr<CefApp> application_;
+};
+
+#endif // CEF_LIBCEF_COMMON_CHROME_CHROME_MAIN_RUNNER_DELEGATE_CEF_
diff --git a/libcef/common/command_line_impl.cc b/libcef/common/command_line_impl.cc
new file mode 100644
index 00000000..6c7db788
--- /dev/null
+++ b/libcef/common/command_line_impl.cc
@@ -0,0 +1,179 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "libcef/common/command_line_impl.h"
+
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+
+CefCommandLineImpl::CefCommandLineImpl(base::CommandLine* value,
+ bool will_delete,
+ bool read_only)
+ : CefValueBase<CefCommandLine, base::CommandLine>(
+ value,
+ nullptr,
+ will_delete ? kOwnerWillDelete : kOwnerNoDelete,
+ read_only,
+ nullptr) {}
+
+bool CefCommandLineImpl::IsValid() {
+ return !detached();
+}
+
+bool CefCommandLineImpl::IsReadOnly() {
+ return read_only();
+}
+
+CefRefPtr<CefCommandLine> CefCommandLineImpl::Copy() {
+ CEF_VALUE_VERIFY_RETURN(false, nullptr);
+ return new CefCommandLineImpl(new base::CommandLine(const_value().argv()),
+ true, false);
+}
+
+void CefCommandLineImpl::InitFromArgv(int argc, const char* const* argv) {
+#if !BUILDFLAG(IS_WIN)
+ CEF_VALUE_VERIFY_RETURN_VOID(true);
+ mutable_value()->InitFromArgv(argc, argv);
+#else
+ NOTREACHED() << "method not supported on this platform";
+#endif
+}
+
+void CefCommandLineImpl::InitFromString(const CefString& command_line) {
+#if BUILDFLAG(IS_WIN)
+ CEF_VALUE_VERIFY_RETURN_VOID(true);
+ const std::wstring& str16 = command_line;
+ mutable_value()->ParseFromString(str16);
+#else
+ NOTREACHED() << "method not supported on this platform";
+#endif
+}
+
+void CefCommandLineImpl::Reset() {
+ CEF_VALUE_VERIFY_RETURN_VOID(true);
+ base::CommandLine::StringVector argv;
+ argv.push_back(mutable_value()->GetProgram().value());
+ mutable_value()->InitFromArgv(argv);
+
+ const base::CommandLine::SwitchMap& map = mutable_value()->GetSwitches();
+ const_cast<base::CommandLine::SwitchMap*>(&map)->clear();
+}
+
+void CefCommandLineImpl::GetArgv(std::vector<CefString>& argv) {
+ CEF_VALUE_VERIFY_RETURN_VOID(false);
+ const base::CommandLine::StringVector& cmd_argv = const_value().argv();
+ base::CommandLine::StringVector::const_iterator it = cmd_argv.begin();
+ for (; it != cmd_argv.end(); ++it) {
+ argv.push_back(*it);
+ }
+}
+
+CefString CefCommandLineImpl::GetCommandLineString() {
+ CEF_VALUE_VERIFY_RETURN(false, CefString());
+ return const_value().GetCommandLineString();
+}
+
+CefString CefCommandLineImpl::GetProgram() {
+ CEF_VALUE_VERIFY_RETURN(false, CefString());
+ return const_value().GetProgram().value();
+}
+
+void CefCommandLineImpl::SetProgram(const CefString& program) {
+ CEF_VALUE_VERIFY_RETURN_VOID(true);
+ mutable_value()->SetProgram(base::FilePath(program));
+}
+
+bool CefCommandLineImpl::HasSwitches() {
+ CEF_VALUE_VERIFY_RETURN(false, false);
+ return (const_value().GetSwitches().size() > 0);
+}
+
+bool CefCommandLineImpl::HasSwitch(const CefString& name) {
+ CEF_VALUE_VERIFY_RETURN(false, false);
+ return const_value().HasSwitch(base::ToLowerASCII(name.ToString()));
+}
+
+CefString CefCommandLineImpl::GetSwitchValue(const CefString& name) {
+ CEF_VALUE_VERIFY_RETURN(false, CefString());
+ return const_value().GetSwitchValueNative(
+ base::ToLowerASCII(name.ToString()));
+}
+
+void CefCommandLineImpl::GetSwitches(SwitchMap& switches) {
+ CEF_VALUE_VERIFY_RETURN_VOID(false);
+ const base::CommandLine::SwitchMap& map = const_value().GetSwitches();
+ base::CommandLine::SwitchMap::const_iterator it = map.begin();
+ for (; it != map.end(); ++it) {
+ switches.insert(std::make_pair(it->first, it->second));
+ }
+}
+
+void CefCommandLineImpl::AppendSwitch(const CefString& name) {
+ CEF_VALUE_VERIFY_RETURN_VOID(true);
+ mutable_value()->AppendSwitch(name.ToString());
+}
+
+void CefCommandLineImpl::AppendSwitchWithValue(const CefString& name,
+ const CefString& value) {
+ CEF_VALUE_VERIFY_RETURN_VOID(true);
+#if BUILDFLAG(IS_WIN)
+ mutable_value()->AppendSwitchNative(name.ToString(), value.ToWString());
+#else
+ mutable_value()->AppendSwitchNative(name.ToString(), value.ToString());
+#endif
+}
+
+bool CefCommandLineImpl::HasArguments() {
+ CEF_VALUE_VERIFY_RETURN(false, false);
+ return (const_value().GetArgs().size() > 0);
+}
+
+void CefCommandLineImpl::GetArguments(ArgumentList& arguments) {
+ CEF_VALUE_VERIFY_RETURN_VOID(false);
+ const base::CommandLine::StringVector& vec = const_value().GetArgs();
+ base::CommandLine::StringVector::const_iterator it = vec.begin();
+ for (; it != vec.end(); ++it) {
+ arguments.push_back(*it);
+ }
+}
+
+void CefCommandLineImpl::AppendArgument(const CefString& argument) {
+ CEF_VALUE_VERIFY_RETURN_VOID(true);
+#if BUILDFLAG(IS_WIN)
+ mutable_value()->AppendArgNative(argument.ToWString());
+#else
+ mutable_value()->AppendArgNative(argument.ToString());
+#endif
+}
+
+void CefCommandLineImpl::PrependWrapper(const CefString& wrapper) {
+ CEF_VALUE_VERIFY_RETURN_VOID(true);
+#if BUILDFLAG(IS_WIN)
+ mutable_value()->PrependWrapper(wrapper.ToWString());
+#else
+ mutable_value()->PrependWrapper(wrapper.ToString());
+#endif
+}
+
+// CefCommandLine implementation.
+
+// static
+CefRefPtr<CefCommandLine> CefCommandLine::CreateCommandLine() {
+ return new CefCommandLineImpl(
+ new base::CommandLine(base::CommandLine::NO_PROGRAM), true, false);
+}
+
+// static
+CefRefPtr<CefCommandLine> CefCommandLine::GetGlobalCommandLine() {
+ // Uses a singleton reference object.
+ static CefRefPtr<CefCommandLineImpl> commandLinePtr;
+ if (!commandLinePtr.get()) {
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+ if (command_line) {
+ commandLinePtr = new CefCommandLineImpl(command_line, false, true);
+ }
+ }
+ return commandLinePtr.get();
+}
diff --git a/libcef/common/command_line_impl.h b/libcef/common/command_line_impl.h
new file mode 100644
index 00000000..77181cd9
--- /dev/null
+++ b/libcef/common/command_line_impl.h
@@ -0,0 +1,52 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_COMMON_COMMAND_LINE_IMPL_H_
+#define CEF_LIBCEF_COMMON_COMMAND_LINE_IMPL_H_
+#pragma once
+
+#include "include/cef_command_line.h"
+#include "libcef/common/value_base.h"
+
+#include "base/command_line.h"
+
+// CefCommandLine implementation
+class CefCommandLineImpl
+ : public CefValueBase<CefCommandLine, base::CommandLine> {
+ public:
+ CefCommandLineImpl(base::CommandLine* value,
+ bool will_delete,
+ bool read_only);
+
+ CefCommandLineImpl(const CefCommandLineImpl&) = delete;
+ CefCommandLineImpl& operator=(const CefCommandLineImpl&) = delete;
+
+ // CefCommandLine methods.
+ bool IsValid() override;
+ bool IsReadOnly() override;
+ CefRefPtr<CefCommandLine> Copy() override;
+ void InitFromArgv(int argc, const char* const* argv) override;
+ void InitFromString(const CefString& command_line) override;
+ void Reset() override;
+ void GetArgv(std::vector<CefString>& argv) override;
+ CefString GetCommandLineString() override;
+ CefString GetProgram() override;
+ void SetProgram(const CefString& program) override;
+ bool HasSwitches() override;
+ bool HasSwitch(const CefString& name) override;
+ CefString GetSwitchValue(const CefString& name) override;
+ void GetSwitches(SwitchMap& switches) override;
+ void AppendSwitch(const CefString& name) override;
+ void AppendSwitchWithValue(const CefString& name,
+ const CefString& value) override;
+ bool HasArguments() override;
+ void GetArguments(ArgumentList& arguments) override;
+ void AppendArgument(const CefString& argument) override;
+ void PrependWrapper(const CefString& wrapper) override;
+
+ // Must hold the controller lock while using this value.
+ const base::CommandLine& command_line() { return const_value(); }
+};
+
+#endif // CEF_LIBCEF_COMMON_COMMAND_LINE_IMPL_H_
diff --git a/libcef/common/crash_reporter_client.cc b/libcef/common/crash_reporter_client.cc
new file mode 100644
index 00000000..da871280
--- /dev/null
+++ b/libcef/common/crash_reporter_client.cc
@@ -0,0 +1,805 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. Portions copyright
+// 2016 The Chromium Authors. All rights reserved. Use of this source code is
+// governed by a BSD-style license that can be found in the LICENSE file.
+
+#include "libcef/common/crash_reporter_client.h"
+
+#include <utility>
+
+#if BUILDFLAG(IS_WIN)
+#include <windows.h>
+#endif
+
+#include "base/environment.h"
+#include "base/logging.h"
+#include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/crash/core/common/crash_key.h"
+#include "content/public/common/content_switches.h"
+#include "third_party/crashpad/crashpad/client/annotation.h"
+
+#if BUILDFLAG(IS_MAC)
+#include "libcef/common/util_mac.h"
+#endif
+
+#if BUILDFLAG(IS_POSIX)
+// Don't use CommandLine, FilePath or PathService on Windows. FilePath has
+// dependencies outside of kernel32, which is disallowed by chrome_elf.
+// CommandLine and PathService depend on global state that will not be
+// initialized at the time the CefCrashReporterClient object is created.
+#include "base/command_line.h"
+#include "base/environment.h"
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+#include "chrome/common/chrome_paths.h"
+#endif
+
+#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC)
+#include "content/public/common/content_switches.h"
+#include "libcef/common/cef_crash_report_utils.h"
+#endif
+
+#if BUILDFLAG(IS_WIN)
+#include "base/debug/leak_annotations.h"
+#include "chrome/install_static/install_util.h"
+#include "components/crash/core/app/crashpad.h"
+#endif
+
+namespace {
+
+#if BUILDFLAG(IS_WIN)
+using PathString = std::wstring;
+const char kPathSep = '\\';
+#else
+using PathString = std::string;
+#endif
+
+PathString GetCrashConfigPath() {
+#if BUILDFLAG(IS_WIN)
+ // Start with the path to the running executable.
+ wchar_t module_path[MAX_PATH];
+ if (GetModuleFileName(nullptr, module_path, MAX_PATH) == 0) {
+ return PathString();
+ }
+
+ PathString config_path = module_path;
+
+ // Remove the executable file name.
+ PathString::size_type last_backslash =
+ config_path.rfind(kPathSep, config_path.size());
+ if (last_backslash != PathString::npos) {
+ config_path.erase(last_backslash + 1);
+ }
+
+ config_path += L"crash_reporter.cfg";
+ return config_path;
+#elif BUILDFLAG(IS_POSIX)
+ base::FilePath config_path;
+
+#if BUILDFLAG(IS_MAC)
+ // Start with the path to the main app Resources directory. May be empty if
+ // not running in an app bundle.
+ config_path = util_mac::GetMainResourcesDirectory();
+#endif
+
+ if (config_path.empty()) {
+ // Start with the path to the running executable.
+ if (!base::PathService::Get(base::DIR_EXE, &config_path)) {
+ return PathString();
+ }
+ }
+
+ return config_path.Append(FILE_PATH_LITERAL("crash_reporter.cfg")).value();
+#endif // BUILDFLAG(IS_POSIX)
+}
+
+#if BUILDFLAG(IS_WIN)
+
+// On Windows, FAT32 and NTFS both limit filenames to a maximum of 255
+// characters. On POSIX systems, the typical filename length limit is 255
+// character units. HFS+'s limit is actually 255 Unicode characters using
+// Apple's modification of Normalization Form D, but the differences aren't
+// really worth dealing with here.
+const unsigned maxFilenameLength = 255;
+
+const char kInvalidFileChars[] = "<>:\"/\\|?*";
+
+bool isInvalidFileCharacter(unsigned char c) {
+ if (c < ' ' || c == 0x7F) {
+ return true;
+ }
+ for (size_t i = 0; i < sizeof(kInvalidFileChars); ++i) {
+ if (c == kInvalidFileChars[i]) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool isAbsolutePath(const std::string& s) {
+ // Check for local paths (beginning with "c:\") and network paths
+ // (beginning with "\\").
+ return s.length() > 2 &&
+ ((isalpha(s[0]) && s[1] == ':' && s[2] == kPathSep) ||
+ (s[0] == kPathSep && s[1] == kPathSep));
+}
+
+std::string extractAbsolutePathStart(std::string& s) {
+ if (!isAbsolutePath(s)) {
+ return std::string();
+ }
+
+ std::string start;
+ if (s[0] == kPathSep) {
+ // Network path.
+ start = s.substr(0, 2);
+ s = s.substr(2);
+ } else {
+ // Local path.
+ start = s.substr(0, 3);
+ s = s.substr(3);
+ }
+ return start;
+}
+
+std::string sanitizePathComponentPart(const std::string& s) {
+ if (s.empty()) {
+ return std::string();
+ }
+
+ std::string result;
+ result.reserve(s.length());
+ for (size_t i = 0; i < s.length(); ++i) {
+ if (!isInvalidFileCharacter(s[i])) {
+ result.push_back(s[i]);
+ }
+ }
+ return result;
+}
+
+std::string sanitizePathComponent(const std::string& s) {
+ std::string name, ext;
+
+ // Separate name and extension, if any.
+ std::string::size_type pos = s.rfind('.');
+ if (pos != std::string::npos) {
+ name = s.substr(0, pos);
+ ext = s.substr(pos + 1);
+ } else {
+ name = s;
+ }
+
+ // Remove invalid characters.
+ name = sanitizePathComponentPart(name);
+ ext = sanitizePathComponentPart(ext);
+
+ // Remove a ridiculously-long extension.
+ if (ext.length() >= maxFilenameLength) {
+ ext = std::string();
+ }
+
+ // Truncate an overly-long filename, reserving one character for a dot.
+ std::string::size_type max_name_len = maxFilenameLength - ext.length() - 1;
+ if (name.length() > max_name_len) {
+ name = name.substr(0, max_name_len);
+ }
+
+ return ext.empty() ? name : name + "." + ext;
+}
+
+std::string sanitizePath(const std::string& s) {
+ std::string path = s;
+
+ // Extract the absolute path start component, if any (e.g. "c:\" on Windows).
+ std::string result = extractAbsolutePathStart(path);
+ result.reserve(s.length());
+
+ std::vector<std::string> parts =
+ base::SplitString(path, std::string() + kPathSep, base::KEEP_WHITESPACE,
+ base::SPLIT_WANT_NONEMPTY);
+ for (size_t i = 0; i < parts.size(); ++i) {
+ std::string part = parts[i];
+ if (part != "." && part != "..") {
+ part = sanitizePathComponent(part);
+ }
+ if (!result.empty() && result[result.length() - 1] != kPathSep) {
+ result += kPathSep;
+ }
+ result += part;
+ }
+
+ return result;
+}
+
+std::string joinPath(const std::string& s1, const std::string& s2) {
+ if (s1.empty() && s2.empty()) {
+ return std::string();
+ }
+ if (s1.empty()) {
+ return s2;
+ }
+ if (s2.empty()) {
+ return s1;
+ }
+
+ // Don't try to join absolute paths on Windows.
+ // Skip this check on POSIX where it's more difficult to differentiate.
+ if (isAbsolutePath(s2)) {
+ return s2;
+ }
+
+ std::string result = s1;
+ if (result[result.size() - 1] != kPathSep) {
+ result += kPathSep;
+ }
+ if (s2[0] == kPathSep) {
+ result += s2.substr(1);
+ } else {
+ result += s2;
+ }
+ return result;
+}
+
+// This will only be non-nullptr in the chrome_elf address space.
+CefCrashReporterClient* g_crash_reporter_client = nullptr;
+
+#endif // BUILDFLAG(IS_WIN)
+
+const char kKeyMapDelim = ',';
+
+std::string NormalizeCrashKey(const base::StringPiece& key) {
+ std::string str(key);
+ std::replace(str.begin(), str.end(), kKeyMapDelim, '-');
+ if (str.length() > crashpad::Annotation::kNameMaxLength) {
+ return str.substr(0, crashpad::Annotation::kNameMaxLength);
+ }
+ return str;
+}
+
+void ParseURL(const std::string& value, std::string* url) {
+ if (value.find("http://") == 0 || value.find("https://") == 0) {
+ *url = value;
+ if (url->rfind('/') <= 8) {
+ // Make sure the URL includes a path component. Otherwise, crash
+ // upload will fail on older Windows versions due to
+ // https://crbug.com/826564.
+ *url += "/";
+ }
+ }
+}
+
+bool ParseBool(const std::string& value) {
+ return base::EqualsCaseInsensitiveASCII(value, "true") || value == "1";
+}
+
+int ParseZeroBasedInt(const std::string& value) {
+ int int_val;
+ if (base::StringToInt(value, &int_val) && int_val > 0) {
+ return int_val;
+ }
+ return 0;
+}
+
+} // namespace
+
+#if BUILDFLAG(IS_WIN)
+
+extern "C" {
+
+// Export functions from chrome_elf that are required by crash_reporting.cc
+
+int __declspec(dllexport) __cdecl SetCrashKeyValueImpl(const char* key,
+ size_t key_size,
+ const char* value,
+ size_t value_size) {
+ if (g_crash_reporter_client) {
+ return g_crash_reporter_client->SetCrashKeyValue(
+ base::StringPiece(key, key_size), base::StringPiece(value, value_size));
+ }
+ return 0;
+}
+
+int __declspec(dllexport) __cdecl IsCrashReportingEnabledImpl() {
+ return g_crash_reporter_client &&
+ g_crash_reporter_client->HasCrashConfigFile();
+}
+
+} // extern "C"
+
+// The below functions were deleted from chrome/install_static/install_util.cc
+// in https://crbug.com/565446#c17.
+
+constexpr wchar_t kUserDataDirname[] = L"User Data";
+
+// Populates |result| with the default User Data directory for the current
+// user.This may be overidden by a command line option. Returns false if all
+// attempts at locating a User Data directory fail.
+bool GetDefaultUserDataDirectory(std::wstring* result,
+ const std::wstring& install_sub_directory) {
+ // This environment variable should be set on Windows Vista and later
+ // (https://msdn.microsoft.com/library/windows/desktop/dd378457.aspx).
+ std::wstring user_data_dir =
+ install_static::GetEnvironmentString(L"LOCALAPPDATA");
+
+ if (user_data_dir.empty()) {
+ // LOCALAPPDATA was not set; fallback to the temporary files path.
+ DWORD size = ::GetTempPath(0, nullptr);
+ if (!size) {
+ return false;
+ }
+ user_data_dir.resize(size + 1);
+ size = ::GetTempPath(size + 1, &user_data_dir[0]);
+ if (!size || size >= user_data_dir.size()) {
+ return false;
+ }
+ user_data_dir.resize(size);
+ }
+
+ result->swap(user_data_dir);
+ if ((*result)[result->length() - 1] != L'\\') {
+ result->push_back(L'\\');
+ }
+ result->append(install_sub_directory);
+ result->push_back(L'\\');
+ result->append(kUserDataDirname);
+ return true;
+}
+
+// Populates |crash_dir| with the default crash dump location regardless of
+// whether DIR_USER_DATA or DIR_CRASH_DUMPS has been overridden.
+bool GetDefaultCrashDumpLocation(std::wstring* crash_dir,
+ const std::wstring& install_sub_directory) {
+ // In order to be able to start crash handling very early, we do not rely on
+ // chrome's PathService entries (for DIR_CRASH_DUMPS) being available on
+ // Windows. See https://crbug.com/564398.
+ if (!GetDefaultUserDataDirectory(crash_dir, install_sub_directory)) {
+ return false;
+ }
+
+ // We have to make sure the user data dir exists on first run. See
+ // http://crbug.com/591504.
+ if (!install_static::RecursiveDirectoryCreate(*crash_dir)) {
+ return false;
+ }
+ crash_dir->append(L"\\Crashpad");
+ return true;
+}
+
+#endif // OS_WIN
+
+CefCrashReporterClient::CefCrashReporterClient() {}
+CefCrashReporterClient::~CefCrashReporterClient() {}
+
+// Be aware that logging is not initialized at the time this method is called.
+bool CefCrashReporterClient::ReadCrashConfigFile() {
+ if (has_crash_config_file_) {
+ return true;
+ }
+
+ PathString config_path = GetCrashConfigPath();
+ if (config_path.empty()) {
+ return false;
+ }
+
+#if BUILDFLAG(IS_WIN)
+ FILE* fp = _wfopen(config_path.c_str(), L"r");
+#else
+ FILE* fp = fopen(config_path.c_str(), "r");
+#endif
+ if (!fp) {
+ return false;
+ }
+
+ char line[1000];
+
+ size_t small_index = 0;
+ size_t medium_index = 0;
+ size_t large_index = 0;
+ std::string map_keys;
+
+ enum section {
+ kNoSection,
+ kConfigSection,
+ kCrashKeysSection,
+ } current_section = kNoSection;
+
+ while (fgets(line, sizeof(line) - 1, fp) != nullptr) {
+ std::string str = line;
+ base::TrimString(str, base::kWhitespaceASCII, &str);
+ if (str.empty() || str[0] == '#') {
+ continue;
+ }
+
+ if (str == "[Config]") {
+ current_section = kConfigSection;
+ continue;
+ } else if (str == "[CrashKeys]") {
+ current_section = kCrashKeysSection;
+ continue;
+ } else if (str[0] == '[') {
+ current_section = kNoSection;
+ continue;
+ }
+
+ if (current_section == kNoSection) {
+ continue;
+ }
+
+ size_t div = str.find('=');
+ if (div == std::string::npos) {
+ continue;
+ }
+
+ std::string name_str = str.substr(0, div);
+ base::TrimString(name_str, base::kWhitespaceASCII, &name_str);
+ std::string val_str = str.substr(div + 1);
+ base::TrimString(val_str, base::kWhitespaceASCII, &val_str);
+ if (name_str.empty()) {
+ continue;
+ }
+
+ if (current_section == kConfigSection) {
+ if (name_str == "ServerURL") {
+ ParseURL(val_str, &server_url_);
+ } else if (name_str == "ProductName") {
+ product_name_ = val_str;
+ } else if (name_str == "ProductVersion") {
+ product_version_ = val_str;
+ } else if (name_str == "RateLimitEnabled") {
+ rate_limit_ = ParseBool(val_str);
+ } else if (name_str == "MaxUploadsPerDay") {
+ max_uploads_ = ParseZeroBasedInt(val_str);
+ } else if (name_str == "MaxDatabaseSizeInMb") {
+ max_db_size_ = ParseZeroBasedInt(val_str);
+ } else if (name_str == "MaxDatabaseAgeInDays") {
+ max_db_age_ = ParseZeroBasedInt(val_str);
+ }
+#if BUILDFLAG(IS_WIN)
+ else if (name_str == "ExternalHandler") {
+ if (!val_str.empty()) {
+ external_handler_ = sanitizePath(val_str);
+ }
+ } else if (name_str == "AppName") {
+ if (!val_str.empty()) {
+ val_str = sanitizePathComponent(val_str);
+ if (!val_str.empty()) {
+ app_name_ = val_str;
+ }
+ }
+ }
+#elif BUILDFLAG(IS_MAC)
+ else if (name_str == "BrowserCrashForwardingEnabled") {
+ enable_browser_crash_forwarding_ = ParseBool(val_str);
+ }
+#endif
+ } else if (current_section == kCrashKeysSection) {
+ // Skip duplicate definitions.
+ if (!crash_keys_.empty() &&
+ crash_keys_.find(name_str) != crash_keys_.end()) {
+ continue;
+ }
+
+ KeySize size;
+ size_t index;
+ char group;
+ if (val_str == "small") {
+ size = SMALL_SIZE;
+ index = small_index++;
+ group = 'S';
+ } else if (val_str == "medium") {
+ size = MEDIUM_SIZE;
+ index = medium_index++;
+ group = 'M';
+ } else if (val_str == "large") {
+ size = LARGE_SIZE;
+ index = large_index++;
+ group = 'L';
+ } else {
+ continue;
+ }
+
+ name_str = NormalizeCrashKey(name_str);
+ crash_keys_.insert(std::make_pair(name_str, std::make_pair(size, index)));
+
+ const std::string& key =
+ std::string(1, group) + "-" + std::string(1, 'A' + index);
+ if (!map_keys.empty()) {
+ map_keys.append(std::string(1, kKeyMapDelim));
+ }
+ map_keys.append(key + "=" + name_str);
+ }
+ }
+
+ fclose(fp);
+
+ if (!map_keys.empty()) {
+ // Split |map_keys| across multiple Annotations if necessary.
+ // Must match the logic in crash_report_utils::FilterParameters.
+ using IDKey =
+ crash_reporter::CrashKeyString<crashpad::Annotation::kValueMaxSize>;
+ static IDKey ids[] = {
+ {"K-A", IDKey::Tag::kArray},
+ {"K-B", IDKey::Tag::kArray},
+ {"K-C", IDKey::Tag::kArray},
+ };
+
+ // Make sure we can fit all possible name/value pairs.
+ static_assert(std::size(ids) * crashpad::Annotation::kValueMaxSize >=
+ 3 * 26 /* sizes (small, medium, large) * slots (A to Z) */
+ * (3 + 2 /* key size ("S-A") + delim size ("=,") */
+ + crashpad::Annotation::kNameMaxLength),
+ "Not enough storage for key map");
+
+ size_t offset = 0;
+ for (size_t i = 0; i < std::size(ids); ++i) {
+ size_t length = std::min(map_keys.size() - offset,
+ crashpad::Annotation::kValueMaxSize);
+ ids[i].Set(base::StringPiece(map_keys.data() + offset, length));
+ offset += length;
+ if (offset >= map_keys.size()) {
+ break;
+ }
+ }
+ }
+
+ // Allow override of some values via environment variables.
+ {
+ std::unique_ptr<base::Environment> env(base::Environment::Create());
+ std::string val_str;
+
+ if (env->GetVar("CEF_CRASH_REPORTER_SERVER_URL", &val_str)) {
+ ParseURL(val_str, &server_url_);
+ }
+ if (env->GetVar("CEF_CRASH_REPORTER_RATE_LIMIT_ENABLED", &val_str)) {
+ rate_limit_ = ParseBool(val_str);
+ }
+ }
+
+ has_crash_config_file_ = true;
+ return true;
+}
+
+bool CefCrashReporterClient::HasCrashConfigFile() const {
+ return has_crash_config_file_;
+}
+
+#if BUILDFLAG(IS_WIN)
+
+// static
+void CefCrashReporterClient::InitializeCrashReportingForProcess() {
+ if (g_crash_reporter_client) {
+ return;
+ }
+
+ g_crash_reporter_client = new CefCrashReporterClient();
+ ANNOTATE_LEAKING_OBJECT_PTR(g_crash_reporter_client);
+
+ if (!g_crash_reporter_client->ReadCrashConfigFile()) {
+ return;
+ }
+
+ std::wstring process_type = install_static::GetSwitchValueFromCommandLine(
+ ::GetCommandLineW(), install_static::kProcessType);
+ if (process_type != install_static::kCrashpadHandler) {
+ crash_reporter::SetCrashReporterClient(g_crash_reporter_client);
+
+ // If |embedded_handler| is true then we launch another instance of the main
+ // executable as the crashpad-handler process.
+ const bool embedded_handler =
+ !g_crash_reporter_client->HasCrashExternalHandler();
+ if (embedded_handler) {
+ crash_reporter::InitializeCrashpadWithEmbeddedHandler(
+ process_type.empty(), install_static::WideToUTF8(process_type),
+ std::string(), base::FilePath());
+ } else {
+ crash_reporter::InitializeCrashpad(
+ process_type.empty(), install_static::WideToUTF8(process_type));
+ }
+ }
+}
+
+bool CefCrashReporterClient::GetAlternativeCrashDumpLocation(
+ std::wstring* crash_dir) {
+ // By setting the BREAKPAD_DUMP_LOCATION environment variable, an alternate
+ // location to write breakpad crash dumps can be set.
+ *crash_dir = install_static::GetEnvironmentString(L"BREAKPAD_DUMP_LOCATION");
+ return !crash_dir->empty();
+}
+
+void CefCrashReporterClient::GetProductNameAndVersion(
+ const std::wstring& exe_path,
+ std::wstring* product_name,
+ std::wstring* version,
+ std::wstring* special_build,
+ std::wstring* channel_name) {
+ *product_name = base::ASCIIToWide(product_name_);
+ *version = base::ASCIIToWide(product_version_);
+ *special_build = std::wstring();
+ *channel_name = std::wstring();
+}
+
+bool CefCrashReporterClient::GetCrashDumpLocation(std::wstring* crash_dir) {
+ // By setting the BREAKPAD_DUMP_LOCATION environment variable, an alternate
+ // location to write breakpad crash dumps can be set.
+ if (GetAlternativeCrashDumpLocation(crash_dir)) {
+ return true;
+ }
+
+ return GetDefaultCrashDumpLocation(crash_dir, base::UTF8ToWide(app_name_));
+}
+
+bool CefCrashReporterClient::GetCrashMetricsLocation(
+ std::wstring* metrics_dir) {
+ return GetDefaultUserDataDirectory(metrics_dir, base::UTF8ToWide(app_name_));
+}
+
+#elif BUILDFLAG(IS_POSIX)
+
+void CefCrashReporterClient::GetProductNameAndVersion(const char** product_name,
+ const char** version) {
+ *product_name = product_name_.c_str();
+ *version = product_version_.c_str();
+}
+
+void CefCrashReporterClient::GetProductNameAndVersion(std::string* product_name,
+ std::string* version,
+ std::string* channel) {
+ *product_name = product_name_;
+ *version = product_version_;
+}
+
+bool CefCrashReporterClient::GetCrashDumpLocation(base::FilePath* crash_dir) {
+ // By setting the BREAKPAD_DUMP_LOCATION environment variable, an alternate
+ // location to write breakpad crash dumps can be set.
+ std::unique_ptr<base::Environment> env(base::Environment::Create());
+ std::string alternate_crash_dump_location;
+ if (env->GetVar("BREAKPAD_DUMP_LOCATION", &alternate_crash_dump_location)) {
+ base::FilePath crash_dumps_dir_path =
+ base::FilePath::FromUTF8Unsafe(alternate_crash_dump_location);
+ base::PathService::Override(chrome::DIR_CRASH_DUMPS, crash_dumps_dir_path);
+ }
+ return base::PathService::Get(chrome::DIR_CRASH_DUMPS, crash_dir);
+}
+
+#endif // !BUILDFLAG(IS_POSIX)
+
+bool CefCrashReporterClient::GetCollectStatsConsent() {
+ return true;
+}
+
+bool CefCrashReporterClient::GetCollectStatsInSample() {
+ return true;
+}
+
+bool CefCrashReporterClient::ReportingIsEnforcedByPolicy(
+ bool* crashpad_enabled) {
+ *crashpad_enabled = true;
+ return true;
+}
+
+std::string CefCrashReporterClient::GetUploadUrl() {
+ return server_url_;
+}
+
+// See HandlerMain() in third_party/crashpad/crashpad/handler/handler_main.cc
+// for supported arguments.
+void CefCrashReporterClient::GetCrashOptionalArguments(
+ std::vector<std::string>* arguments) {
+ if (!rate_limit_) {
+ arguments->push_back(std::string("--no-rate-limit"));
+ }
+
+ if (max_uploads_ > 0) {
+ arguments->push_back(std::string("--max-uploads=") +
+ base::NumberToString(max_uploads_));
+ }
+
+ if (max_db_size_ > 0) {
+ arguments->push_back(std::string("--max-db-size=") +
+ base::NumberToString(max_db_size_));
+ }
+
+ if (max_db_age_ > 0) {
+ arguments->push_back(std::string("--max-db-age=") +
+ base::NumberToString(max_db_age_));
+ }
+}
+
+#if BUILDFLAG(IS_WIN)
+
+std::wstring CefCrashReporterClient::GetCrashExternalHandler(
+ const std::wstring& exe_dir) {
+ if (external_handler_.empty()) {
+ return CrashReporterClient::GetCrashExternalHandler(exe_dir);
+ }
+ if (isAbsolutePath(external_handler_)) {
+ return base::UTF8ToWide(external_handler_);
+ }
+ return base::UTF8ToWide(
+ joinPath(base::WideToUTF8(exe_dir), external_handler_));
+}
+
+bool CefCrashReporterClient::HasCrashExternalHandler() const {
+ return !external_handler_.empty();
+}
+
+#endif // BUILDFLAG(IS_WIN)
+
+#if BUILDFLAG(IS_MAC)
+bool CefCrashReporterClient::EnableBrowserCrashForwarding() {
+ return enable_browser_crash_forwarding_;
+}
+#endif
+
+// The new Crashpad Annotation API requires that annotations be declared using
+// static storage. We work around this limitation by defining a fixed amount of
+// storage for each key size and later substituting the actual key name during
+// crash dump processing.
+
+#define IDKEY(name) \
+ { name, IDKey::Tag::kArray }
+
+#define IDKEY_ENTRIES(n) \
+ IDKEY(n "-A"), IDKEY(n "-B"), IDKEY(n "-C"), IDKEY(n "-D"), IDKEY(n "-E"), \
+ IDKEY(n "-F"), IDKEY(n "-G"), IDKEY(n "-H"), IDKEY(n "-I"), \
+ IDKEY(n "-J"), IDKEY(n "-K"), IDKEY(n "-L"), IDKEY(n "-M"), \
+ IDKEY(n "-N"), IDKEY(n "-O"), IDKEY(n "-P"), IDKEY(n "-Q"), \
+ IDKEY(n "-R"), IDKEY(n "-S"), IDKEY(n "-T"), IDKEY(n "-U"), \
+ IDKEY(n "-V"), IDKEY(n "-W"), IDKEY(n "-X"), IDKEY(n "-Y"), \
+ IDKEY(n "-Z")
+
+#define IDKEY_FUNCTION(name, size_) \
+ static_assert(size_ <= crashpad::Annotation::kValueMaxSize, \
+ "Annotation size is too large."); \
+ bool Set##name##Annotation(size_t index, const base::StringPiece& value) { \
+ using IDKey = crash_reporter::CrashKeyString<size_>; \
+ static IDKey ids[] = {IDKEY_ENTRIES(#name)}; \
+ if (index < std::size(ids)) { \
+ if (value.empty()) { \
+ ids[index].Clear(); \
+ } else { \
+ ids[index].Set(value); \
+ } \
+ return true; \
+ } \
+ return false; \
+ }
+
+// The first argument must be kept synchronized with the logic in
+// CefCrashReporterClient::ReadCrashConfigFile and
+// crash_report_utils::FilterParameters.
+IDKEY_FUNCTION(S, 64)
+IDKEY_FUNCTION(M, 256)
+IDKEY_FUNCTION(L, 1024)
+
+bool CefCrashReporterClient::SetCrashKeyValue(const base::StringPiece& key,
+ const base::StringPiece& value) {
+ if (key.empty() || crash_keys_.empty()) {
+ return false;
+ }
+
+ KeyMap::const_iterator it = crash_keys_.find(NormalizeCrashKey(key));
+ if (it == crash_keys_.end()) {
+ return false;
+ }
+
+ const KeySize size = it->second.first;
+ const size_t index = it->second.second;
+
+ base::AutoLock lock_scope(crash_key_lock_);
+
+ switch (size) {
+ case SMALL_SIZE:
+ return SetSAnnotation(index, value);
+ case MEDIUM_SIZE:
+ return SetMAnnotation(index, value);
+ case LARGE_SIZE:
+ return SetLAnnotation(index, value);
+ }
+
+ return false;
+}
diff --git a/libcef/common/crash_reporter_client.h b/libcef/common/crash_reporter_client.h
new file mode 100644
index 00000000..cb804c33
--- /dev/null
+++ b/libcef/common/crash_reporter_client.h
@@ -0,0 +1,116 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. Portions copyright
+// 2016 The Chromium Authors. All rights reserved. Use of this source code is
+// governed by a BSD-style license that can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_COMMON_CRASH_REPORTER_CLIENT_H_
+#define CEF_LIBCEF_COMMON_CRASH_REPORTER_CLIENT_H_
+
+#include <string>
+#include <vector>
+
+#include "include/cef_version.h"
+
+#include "base/strings/string_piece_forward.h"
+#include "base/synchronization/lock.h"
+#include "build/build_config.h"
+#include "components/crash/core/app/crash_reporter_client.h"
+
+// Global object that is instantiated in each process and configures crash
+// reporting. On Windows this is created by the
+// InitializeCrashReportingForProcess() method called from chrome_elf. On
+// Linux and macOS this is created by crash_reporting::BasicStartupComplete().
+class CefCrashReporterClient : public crash_reporter::CrashReporterClient {
+ public:
+ CefCrashReporterClient();
+
+ CefCrashReporterClient(const CefCrashReporterClient&) = delete;
+ CefCrashReporterClient& operator=(const CefCrashReporterClient&) = delete;
+
+ ~CefCrashReporterClient() override;
+
+ // Reads the crash config file and returns true on success. Failure to read
+ // the crash config file will disable crash reporting. This method should be
+ // called immediately after the CefCrashReporterClient instance is created.
+ bool ReadCrashConfigFile();
+ bool HasCrashConfigFile() const;
+
+#if BUILDFLAG(IS_WIN)
+ // Called from chrome_elf (chrome_elf/crash/crash_helper.cc) to instantiate
+ // a process wide instance of CefCrashReporterClient and initialize crash
+ // reporting for the process. The instance is leaked.
+ // crash_reporting_win::InitializeCrashReportingForModule() will be called
+ // later from crash_reporting::PreSandboxStartup() to read global state into
+ // the module address space.
+ static void InitializeCrashReportingForProcess();
+
+ bool GetAlternativeCrashDumpLocation(std::wstring* crash_dir) override;
+ void GetProductNameAndVersion(const std::wstring& exe_path,
+ std::wstring* product_name,
+ std::wstring* version,
+ std::wstring* special_build,
+ std::wstring* channel_name) override;
+ bool GetCrashDumpLocation(std::wstring* crash_dir) override;
+ bool GetCrashMetricsLocation(std::wstring* metrics_dir) override;
+#elif BUILDFLAG(IS_POSIX)
+ void GetProductNameAndVersion(const char** product_name,
+ const char** version) override;
+ void GetProductNameAndVersion(std::string* product_name,
+ std::string* version,
+ std::string* channel) override;
+ bool GetCrashDumpLocation(base::FilePath* crash_dir) override;
+#endif // BUILDFLAG(IS_POSIX)
+
+ // All of these methods must return true to enable crash report upload.
+ bool GetCollectStatsConsent() override;
+ bool GetCollectStatsInSample() override;
+ bool ReportingIsEnforcedByPolicy(bool* crashpad_enabled) override;
+
+ std::string GetUploadUrl() override;
+ void GetCrashOptionalArguments(std::vector<std::string>* arguments) override;
+
+#if BUILDFLAG(IS_WIN)
+ std::wstring GetCrashExternalHandler(const std::wstring& exe_dir) override;
+ bool HasCrashExternalHandler() const;
+#endif
+
+#if BUILDFLAG(IS_MAC)
+ bool EnableBrowserCrashForwarding() override;
+#endif
+
+ // Set or clear a crash key value.
+ bool SetCrashKeyValue(const base::StringPiece& key,
+ const base::StringPiece& value);
+
+ private:
+ bool has_crash_config_file_ = false;
+
+ enum KeySize { SMALL_SIZE, MEDIUM_SIZE, LARGE_SIZE };
+
+ // Map of crash key name to (KeySize, index).
+ // Const access to |crash_keys_| is thread-safe after initialization.
+ using KeyMap = std::map<std::string, std::pair<KeySize, size_t>>;
+ KeyMap crash_keys_;
+
+ // Modification of CrashKeyString values must be synchronized.
+ base::Lock crash_key_lock_;
+
+ std::string server_url_;
+ bool rate_limit_ = true;
+ int max_uploads_ = 5;
+ int max_db_size_ = 20;
+ int max_db_age_ = 5;
+
+ std::string product_name_ = "cef";
+ std::string product_version_ = CEF_VERSION;
+
+#if BUILDFLAG(IS_WIN)
+ std::string app_name_ = "CEF";
+ std::string external_handler_;
+#endif
+
+#if BUILDFLAG(IS_MAC)
+ bool enable_browser_crash_forwarding_ = false;
+#endif
+};
+
+#endif // CEF_LIBCEF_COMMON_CRASH_REPORTER_CLIENT_H_
diff --git a/libcef/common/crash_reporting.cc b/libcef/common/crash_reporting.cc
new file mode 100644
index 00000000..61310ef5
--- /dev/null
+++ b/libcef/common/crash_reporting.cc
@@ -0,0 +1,267 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. Portions copyright
+// 2016 The Chromium Authors. All rights reserved. Use of this source code is
+// governed by a BSD-style license that can be found in the LICENSE file.
+
+#include "libcef/common/crash_reporting.h"
+
+#include "include/cef_crash_util.h"
+#include "libcef/common/cef_switches.h"
+#include "libcef/features/runtime.h"
+
+#include "base/base_switches.h"
+#include "base/command_line.h"
+#include "base/debug/crash_logging.h"
+#include "base/logging.h"
+#include "base/stl_util.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/string_util.h"
+#include "chrome/common/crash_keys.h"
+#include "components/crash/core/common/crash_key.h"
+#include "components/crash/core/common/crash_keys.h"
+#include "content/public/common/content_switches.h"
+
+#if BUILDFLAG(IS_MAC)
+#include "base/mac/foundation_util.h"
+#include "components/crash/core/common/crash_keys.h"
+#include "content/public/common/content_paths.h"
+#endif
+
+#if BUILDFLAG(IS_POSIX)
+#include "base/lazy_instance.h"
+#include "components/crash/core/app/crashpad.h"
+#include "libcef/common/crash_reporter_client.h"
+#endif
+
+namespace crash_reporting {
+
+namespace {
+
+#if BUILDFLAG(IS_WIN)
+
+const base::FilePath::CharType kChromeElfDllName[] =
+ FILE_PATH_LITERAL("chrome_elf.dll");
+
+// exported in crash_reporter_client.cc:
+// int __declspec(dllexport) __cdecl SetCrashKeyValueImpl.
+typedef int(__cdecl* SetCrashKeyValue)(const char*,
+ size_t,
+ const char*,
+ size_t);
+
+// int __declspec(dllexport) __cdecl IsCrashReportingEnabledImpl.
+typedef int(__cdecl* IsCrashReportingEnabled)();
+
+bool SetCrashKeyValueTrampoline(const base::StringPiece& key,
+ const base::StringPiece& value) {
+ static SetCrashKeyValue set_crash_key = []() {
+ HMODULE elf_module = GetModuleHandle(kChromeElfDllName);
+ return reinterpret_cast<SetCrashKeyValue>(
+ elf_module ? GetProcAddress(elf_module, "SetCrashKeyValueImpl")
+ : nullptr);
+ }();
+ if (set_crash_key) {
+ return !!(set_crash_key)(key.data(), key.size(), value.data(),
+ value.size());
+ }
+ return false;
+}
+
+bool IsCrashReportingEnabledTrampoline() {
+ static IsCrashReportingEnabled is_crash_reporting_enabled = []() {
+ HMODULE elf_module = GetModuleHandle(kChromeElfDllName);
+ return reinterpret_cast<IsCrashReportingEnabled>(
+ elf_module ? GetProcAddress(elf_module, "IsCrashReportingEnabledImpl")
+ : nullptr);
+ }();
+ if (is_crash_reporting_enabled) {
+ return !!(is_crash_reporting_enabled)();
+ }
+ return false;
+}
+
+#endif // BUILDFLAG(IS_WIN)
+
+bool g_crash_reporting_enabled = false;
+
+#if BUILDFLAG(IS_POSIX)
+base::LazyInstance<CefCrashReporterClient>::Leaky g_crash_reporter_client =
+ LAZY_INSTANCE_INITIALIZER;
+
+void InitCrashReporter(const base::CommandLine& command_line,
+ const std::string& process_type) {
+ CefCrashReporterClient* crash_client = g_crash_reporter_client.Pointer();
+ if (!crash_client->HasCrashConfigFile()) {
+ return;
+ }
+
+ crash_reporter::SetCrashReporterClient(crash_client);
+
+#if BUILDFLAG(IS_MAC)
+ // TODO(mark): Right now, InitializeCrashpad() needs to be called after
+ // CommandLine::Init() and configuration of chrome::DIR_CRASH_DUMPS. Ideally,
+ // Crashpad initialization could occur sooner, preferably even before the
+ // framework dylib is even loaded, to catch potential early crashes.
+ crash_reporter::InitializeCrashpad(process_type.empty(), process_type);
+
+ if (base::mac::AmIBundled()) {
+ // Mac Chrome is packaged with a main app bundle and a helper app bundle.
+ // The main app bundle should only be used for the browser process, so it
+ // should never see a --type switch (switches::kProcessType). Likewise,
+ // the helper should always have a --type switch.
+ //
+ // This check is done this late so there is already a call to
+ // base::mac::IsBackgroundOnlyProcess(), so there is no change in
+ // startup/initialization order.
+
+ // The helper's Info.plist marks it as a background only app.
+ if (base::mac::IsBackgroundOnlyProcess()) {
+ CHECK(command_line.HasSwitch(switches::kProcessType) &&
+ !process_type.empty())
+ << "Helper application requires --type.";
+ } else {
+ CHECK(!command_line.HasSwitch(switches::kProcessType) &&
+ process_type.empty())
+ << "Main application forbids --type, saw " << process_type;
+ }
+ }
+
+ g_crash_reporting_enabled = true;
+#else // !BUILDFLAG(IS_MAC)
+ if (process_type != switches::kZygoteProcess) {
+ // Crash reporting for subprocesses created using the zygote will be
+ // initialized in ZygoteForked.
+ crash_reporter::InitializeCrashpad(process_type.empty(), process_type);
+
+ g_crash_reporting_enabled = true;
+ }
+#endif // !BUILDFLAG(IS_MAC)
+}
+#endif // BUILDFLAG(IS_POSIX)
+
+// Used to exclude command-line flags from crash reporting.
+bool IsBoringCEFSwitch(const std::string& flag) {
+ if (crash_keys::IsBoringChromeSwitch(flag)) {
+ return true;
+ }
+
+ static const char* const kIgnoreSwitches[] = {
+ // CEF internals.
+ switches::kLogFile,
+
+ // Chromium internals.
+ "content-image-texture-target",
+ "mojo-platform-channel-handle",
+ "primordial-pipe-token",
+ "service-pipe-token",
+ "service-request-channel-token",
+ };
+
+ if (!base::StartsWith(flag, "--", base::CompareCase::SENSITIVE)) {
+ return false;
+ }
+
+ size_t end = flag.find("=");
+ size_t len = (end == std::string::npos) ? flag.length() - 2 : end - 2;
+ for (size_t i = 0; i < std::size(kIgnoreSwitches); ++i) {
+ if (flag.compare(2, len, kIgnoreSwitches[i]) == 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
+} // namespace
+
+bool Enabled() {
+ return g_crash_reporting_enabled;
+}
+
+bool SetCrashKeyValue(const base::StringPiece& key,
+ const base::StringPiece& value) {
+ if (!g_crash_reporting_enabled) {
+ return false;
+ }
+
+#if BUILDFLAG(IS_WIN)
+ return SetCrashKeyValueTrampoline(key, value);
+#else
+ return g_crash_reporter_client.Pointer()->SetCrashKeyValue(key, value);
+#endif
+}
+
+#if BUILDFLAG(IS_POSIX)
+// Be aware that logging is not initialized at the time this method is called.
+void BasicStartupComplete(base::CommandLine* command_line) {
+ CefCrashReporterClient* crash_client = g_crash_reporter_client.Pointer();
+ if (crash_client->ReadCrashConfigFile()) {
+#if !BUILDFLAG(IS_MAC)
+ // Crashpad requires this switch on Linux.
+ command_line->AppendSwitch(switches::kEnableCrashpad);
+#endif
+ }
+}
+#endif
+
+void PreSandboxStartup(const base::CommandLine& command_line,
+ const std::string& process_type) {
+#if BUILDFLAG(IS_POSIX)
+ // Initialize crash reporting here on macOS and Linux. Crash reporting on
+ // Windows is initialized from context.cc.
+ InitCrashReporter(command_line, process_type);
+#elif BUILDFLAG(IS_WIN)
+ g_crash_reporting_enabled = IsCrashReportingEnabledTrampoline();
+#endif
+
+ if (g_crash_reporting_enabled) {
+ LOG(INFO) << "Crash reporting enabled for process: "
+ << (process_type.empty() ? "browser" : process_type.c_str());
+ }
+
+ crash_reporter::InitializeCrashKeys();
+
+ // After platform crash reporting have been initialized, store the command
+ // line for crash reporting.
+ crash_keys::SetSwitchesFromCommandLine(command_line, &IsBoringCEFSwitch);
+}
+
+#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_MAC)
+void ZygoteForked(base::CommandLine* command_line,
+ const std::string& process_type) {
+ CefCrashReporterClient* crash_client = g_crash_reporter_client.Pointer();
+ if (crash_client->HasCrashConfigFile()) {
+ // Crashpad requires this switch on Linux.
+ command_line->AppendSwitch(switches::kEnableCrashpad);
+ }
+
+ InitCrashReporter(*command_line, process_type);
+
+ if (g_crash_reporting_enabled) {
+ LOG(INFO) << "Crash reporting enabled for process: " << process_type;
+ }
+
+ // Reset the command line for the newly spawned process.
+ crash_keys::SetSwitchesFromCommandLine(*command_line, &IsBoringCEFSwitch);
+}
+#endif
+
+} // namespace crash_reporting
+
+bool CefCrashReportingEnabled() {
+ return crash_reporting::Enabled();
+}
+
+void CefSetCrashKeyValue(const CefString& key, const CefString& value) {
+ if (!crash_reporting::SetCrashKeyValue(key.ToString(), value.ToString())) {
+ LOG(WARNING) << "Failed to set crash key: " << key.ToString()
+ << " with value: " << value.ToString();
+ }
+}
+
+// From libcef/features/runtime.h:
+namespace cef {
+
+bool IsCrashReportingEnabled() {
+ return crash_reporting::Enabled();
+}
+
+} // namespace cef
diff --git a/libcef/common/crash_reporting.h b/libcef/common/crash_reporting.h
new file mode 100644
index 00000000..38fcd577
--- /dev/null
+++ b/libcef/common/crash_reporting.h
@@ -0,0 +1,37 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. Portions copyright
+// 2016 The Chromium Authors. All rights reserved. Use of this source code is
+// governed by a BSD-style license that can be found in the LICENSE file.
+
+#include <string>
+
+#include "base/strings/string_piece_forward.h"
+#include "build/build_config.h"
+
+namespace base {
+class CommandLine;
+}
+
+namespace crash_reporting {
+
+// Returns true if crash reporting is enabled.
+bool Enabled();
+
+// Set or clear a crash key value.
+bool SetCrashKeyValue(const base::StringPiece& key,
+ const base::StringPiece& value);
+
+// Functions are called from similarly named methods in AlloyMainDelegate.
+
+#if BUILDFLAG(IS_POSIX)
+void BasicStartupComplete(base::CommandLine* command_line);
+#endif
+
+void PreSandboxStartup(const base::CommandLine& command_line,
+ const std::string& process_type);
+
+#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_MAC)
+void ZygoteForked(base::CommandLine* command_line,
+ const std::string& process_type);
+#endif
+
+} // namespace crash_reporting
diff --git a/libcef/common/drag_data_impl.cc b/libcef/common/drag_data_impl.cc
new file mode 100644
index 00000000..49ea0e1d
--- /dev/null
+++ b/libcef/common/drag_data_impl.cc
@@ -0,0 +1,217 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include <string>
+
+#include "base/files/file_path.h"
+#include "libcef/browser/stream_impl.h"
+#include "libcef/common/drag_data_impl.h"
+
+#define CHECK_READONLY_RETURN_VOID() \
+ if (read_only_) { \
+ NOTREACHED() << "object is read only"; \
+ return; \
+ }
+
+CefDragDataImpl::CefDragDataImpl(const content::DropData& data)
+ : data_(data), read_only_(false) {}
+
+CefDragDataImpl::CefDragDataImpl(const content::DropData& data,
+ CefRefPtr<CefImage> image,
+ const CefPoint& image_hotspot)
+ : data_(data),
+ image_(image),
+ image_hotspot_(image_hotspot),
+ read_only_(false) {}
+
+CefDragDataImpl::CefDragDataImpl() : read_only_(false) {}
+
+CefRefPtr<CefDragData> CefDragData::Create() {
+ return new CefDragDataImpl();
+}
+
+CefRefPtr<CefDragData> CefDragDataImpl::Clone() {
+ CefDragDataImpl* drag_data = nullptr;
+ {
+ base::AutoLock lock_scope(lock_);
+ drag_data = new CefDragDataImpl(data_, image_, image_hotspot_);
+ }
+ return drag_data;
+}
+
+bool CefDragDataImpl::IsReadOnly() {
+ base::AutoLock lock_scope(lock_);
+ return read_only_;
+}
+
+bool CefDragDataImpl::IsLink() {
+ base::AutoLock lock_scope(lock_);
+ return (data_.url.is_valid() &&
+ data_.file_contents_content_disposition.empty());
+}
+
+bool CefDragDataImpl::IsFragment() {
+ base::AutoLock lock_scope(lock_);
+ return (!data_.url.is_valid() &&
+ data_.file_contents_content_disposition.empty() &&
+ data_.filenames.empty());
+}
+
+bool CefDragDataImpl::IsFile() {
+ base::AutoLock lock_scope(lock_);
+ return (!data_.file_contents_content_disposition.empty() ||
+ !data_.filenames.empty());
+}
+
+CefString CefDragDataImpl::GetLinkURL() {
+ base::AutoLock lock_scope(lock_);
+ return data_.url.spec();
+}
+
+CefString CefDragDataImpl::GetLinkTitle() {
+ base::AutoLock lock_scope(lock_);
+ return data_.url_title;
+}
+
+CefString CefDragDataImpl::GetLinkMetadata() {
+ base::AutoLock lock_scope(lock_);
+ return data_.download_metadata;
+}
+
+CefString CefDragDataImpl::GetFragmentText() {
+ base::AutoLock lock_scope(lock_);
+ return data_.text ? CefString(*data_.text) : CefString();
+}
+
+CefString CefDragDataImpl::GetFragmentHtml() {
+ base::AutoLock lock_scope(lock_);
+ return data_.html ? CefString(*data_.html) : CefString();
+}
+
+CefString CefDragDataImpl::GetFragmentBaseURL() {
+ base::AutoLock lock_scope(lock_);
+ return data_.html_base_url.spec();
+}
+
+CefString CefDragDataImpl::GetFileName() {
+ base::AutoLock lock_scope(lock_);
+ auto filename = data_.GetSafeFilenameForImageFileContents();
+ return filename ? CefString(filename->value()) : CefString();
+}
+
+size_t CefDragDataImpl::GetFileContents(CefRefPtr<CefStreamWriter> writer) {
+ base::AutoLock lock_scope(lock_);
+ if (data_.file_contents.empty()) {
+ return 0;
+ }
+
+ char* data = const_cast<char*>(data_.file_contents.c_str());
+ size_t size = data_.file_contents.size();
+
+ if (!writer.get()) {
+ return size;
+ }
+
+ return writer->Write(data, 1, size);
+}
+
+bool CefDragDataImpl::GetFileNames(std::vector<CefString>& names) {
+ base::AutoLock lock_scope(lock_);
+ if (data_.filenames.empty()) {
+ return false;
+ }
+
+ std::vector<ui::FileInfo>::const_iterator it = data_.filenames.begin();
+ for (; it != data_.filenames.end(); ++it) {
+ auto name = it->display_name.value();
+ if (name.empty()) {
+ name = it->path.value();
+ }
+ names.push_back(name);
+ }
+
+ return true;
+}
+
+void CefDragDataImpl::SetLinkURL(const CefString& url) {
+ base::AutoLock lock_scope(lock_);
+ CHECK_READONLY_RETURN_VOID();
+ data_.url = GURL(url.ToString());
+}
+
+void CefDragDataImpl::SetLinkTitle(const CefString& title) {
+ base::AutoLock lock_scope(lock_);
+ CHECK_READONLY_RETURN_VOID();
+ data_.url_title = title.ToString16();
+}
+
+void CefDragDataImpl::SetLinkMetadata(const CefString& data) {
+ base::AutoLock lock_scope(lock_);
+ CHECK_READONLY_RETURN_VOID();
+ data_.download_metadata = data.ToString16();
+}
+
+void CefDragDataImpl::SetFragmentText(const CefString& text) {
+ base::AutoLock lock_scope(lock_);
+ CHECK_READONLY_RETURN_VOID();
+ data_.text = text.ToString16();
+}
+
+void CefDragDataImpl::SetFragmentHtml(const CefString& fragment) {
+ base::AutoLock lock_scope(lock_);
+ CHECK_READONLY_RETURN_VOID();
+ data_.html = fragment.ToString16();
+}
+
+void CefDragDataImpl::SetFragmentBaseURL(const CefString& fragment) {
+ base::AutoLock lock_scope(lock_);
+ CHECK_READONLY_RETURN_VOID();
+ data_.html_base_url = GURL(fragment.ToString());
+}
+
+void CefDragDataImpl::ResetFileContents() {
+ base::AutoLock lock_scope(lock_);
+ CHECK_READONLY_RETURN_VOID();
+ data_.file_contents.erase();
+ data_.file_contents_source_url = GURL();
+ data_.file_contents_filename_extension.erase();
+ data_.file_contents_content_disposition.erase();
+}
+
+void CefDragDataImpl::AddFile(const CefString& path,
+ const CefString& display_name) {
+ base::AutoLock lock_scope(lock_);
+ CHECK_READONLY_RETURN_VOID();
+ data_.filenames.push_back(
+ ui::FileInfo(base::FilePath(path), base::FilePath(display_name)));
+}
+
+void CefDragDataImpl::ClearFilenames() {
+ base::AutoLock lock_scope(lock_);
+ data_.filenames.clear();
+}
+
+void CefDragDataImpl::SetReadOnly(bool read_only) {
+ base::AutoLock lock_scope(lock_);
+ if (read_only_ == read_only) {
+ return;
+ }
+
+ read_only_ = read_only;
+}
+
+CefRefPtr<CefImage> CefDragDataImpl::GetImage() {
+ base::AutoLock lock_scope(lock_);
+ return image_;
+}
+
+CefPoint CefDragDataImpl::GetImageHotspot() {
+ base::AutoLock lock_scope(lock_);
+ return image_hotspot_;
+}
+
+bool CefDragDataImpl::HasImage() {
+ base::AutoLock lock_scope(lock_);
+ return image_ ? true : false;
+} \ No newline at end of file
diff --git a/libcef/common/drag_data_impl.h b/libcef/common/drag_data_impl.h
new file mode 100644
index 00000000..8acef05e
--- /dev/null
+++ b/libcef/common/drag_data_impl.h
@@ -0,0 +1,73 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_COMMON_DRAG_DATA_IMPL_H_
+#define CEF_LIBCEF_COMMON_DRAG_DATA_IMPL_H_
+#pragma once
+
+#include "include/cef_drag_data.h"
+#include "include/cef_image.h"
+
+#include <vector>
+
+#include "base/synchronization/lock.h"
+#include "content/public/common/drop_data.h"
+
+// Implementation of CefDragData.
+class CefDragDataImpl : public CefDragData {
+ public:
+ CefDragDataImpl();
+ explicit CefDragDataImpl(const content::DropData& data);
+ CefDragDataImpl(const content::DropData& data,
+ CefRefPtr<CefImage> image,
+ const CefPoint& image_hotspot);
+
+ CefRefPtr<CefDragData> Clone() override;
+ bool IsReadOnly() override;
+ bool IsLink() override;
+ bool IsFragment() override;
+ bool IsFile() override;
+ CefString GetLinkURL() override;
+ CefString GetLinkTitle() override;
+ CefString GetLinkMetadata() override;
+ CefString GetFragmentText() override;
+ CefString GetFragmentHtml() override;
+ CefString GetFragmentBaseURL() override;
+ CefString GetFileName() override;
+ size_t GetFileContents(CefRefPtr<CefStreamWriter> writer) override;
+ bool GetFileNames(std::vector<CefString>& names) override;
+ void SetLinkURL(const CefString& url) override;
+ void SetLinkTitle(const CefString& title) override;
+ void SetLinkMetadata(const CefString& data) override;
+ void SetFragmentText(const CefString& text) override;
+ void SetFragmentHtml(const CefString& fragment) override;
+ void SetFragmentBaseURL(const CefString& fragment) override;
+ void ResetFileContents() override;
+ void AddFile(const CefString& path, const CefString& display_name) override;
+ void ClearFilenames() override;
+ CefRefPtr<CefImage> GetImage() override;
+ CefPoint GetImageHotspot() override;
+ bool HasImage() override;
+
+ // This method is not safe. Use Lock/Unlock to get mutually exclusive access.
+ content::DropData* drop_data() { return &data_; }
+
+ void SetReadOnly(bool read_only);
+
+ base::Lock& lock() { return lock_; }
+
+ private:
+ content::DropData data_;
+ CefRefPtr<CefImage> image_;
+ CefPoint image_hotspot_;
+
+ // True if this object is read-only.
+ bool read_only_;
+
+ base::Lock lock_;
+
+ IMPLEMENT_REFCOUNTING(CefDragDataImpl);
+};
+
+#endif // CEF_LIBCEF_COMMON_DRAG_DATA_IMPL_H_
diff --git a/libcef/common/extensions/api/BUILD.gn b/libcef/common/extensions/api/BUILD.gn
new file mode 100644
index 00000000..aa2a1a4e
--- /dev/null
+++ b/libcef/common/extensions/api/BUILD.gn
@@ -0,0 +1,39 @@
+# Copyright 2016 The Chromium Embedded Framework Authors. Portions copyright
+# 2014 the Chromium Authors. All rights reserved. Use of this source code is
+# governed by a BSD-style license that can be found in the LICENSE file.
+
+import("//tools/json_schema_compiler/json_features.gni")
+
+json_features("cef_api_features") {
+ feature_type = "APIFeature"
+ method_name = "AddCEFAPIFeatures"
+ sources = [
+ "_api_features.json",
+ ]
+}
+
+json_features("cef_permission_features") {
+ feature_type = "PermissionFeature"
+ method_name = "AddCEFPermissionFeatures"
+ sources = [
+ "_permission_features.json",
+ ]
+}
+
+json_features("cef_manifest_features") {
+ feature_type = "ManifestFeature"
+ method_name = "AddCEFManifestFeatures"
+ sources = [
+ # Use the same manifest features as Chrome.
+ "//chrome/common/extensions/api/_manifest_features.json",
+ ]
+}
+
+group("extensions_features") {
+ public_deps = [
+ ":cef_api_features",
+ ":cef_manifest_features",
+ ":cef_permission_features",
+ "//extensions/common/api:extensions_features",
+ ]
+}
diff --git a/libcef/common/extensions/api/README.txt b/libcef/common/extensions/api/README.txt
new file mode 100644
index 00000000..5e423e7d
--- /dev/null
+++ b/libcef/common/extensions/api/README.txt
@@ -0,0 +1,66 @@
+This directory provides API definitions for CEF. Some extensions are implemented
+using Mojo and others use an older JSON-based format.
+
+ <api> is the name of the API definition (e.g. 'alarms').
+ <class> is the name of the class implementation (e.g. 'AlarmManager').
+
+To add a new extension API implemented only in CEF ***:
+
+1. Add libcef/common/extensions/api/<api>.idl or .json file which defines the
+ API.
+2. Add <api>.idl or .json to the 'schema_sources' list in
+ libcef/common/extensions/api/BUILD.gn. Serialization code will be
+ generated based on this list in step 4.
+3. Add libcef/browser/extensions/api/<api>/<api>_api.[h|cc] class implementation
+ files and associated entries to the 'libcef_static' target in BUILD.gn.
+4. Run the cef_create_projects script and build to generate the
+ cef/libcef/common/extensions/api/<api>.h file and other serialization code
+ required by the extensions system.
+5. Add an entry in the libcef/common/extensions/api/_*_features.json files if
+ necessary [1].
+6. Add an entry in the libcef/common/extensions/api/*_manifest_overlay.json
+ files if necessary [2].
+7. Call `<class>::GetInstance();` or `<class>Factory::GetFactoryInstance();` [3]
+ from EnsureBrowserContextKeyedServiceFactoriesBuilt in
+ libcef/browser/browser_context_keyed_service_factories.cc.
+8. Call `DependsOn(<class>Factory::GetInstance());` from
+ CefExtensionSystemFactory::CefExtensionSystemFactory in
+ libcef/browser/extensions/extension_system_factory.cc if necessary [3].
+
+*** Note that CEF does not currently expose its own Mojo APIs. Related code is
+commented out in:
+ cef/BUILD.gn
+ cef/libcef/common/extensions/api/BUILD.gn
+ CefExtensionsBrowserClient::RegisterExtensionFunctions
+ CefExtensionsClient::IsAPISchemaGenerated
+ CefExtensionsClient::GetAPISchema
+
+To add a new extension API implemented in Chrome:
+
+1. Register the API in libcef/browser/extensions/chrome_api_registration.cc
+2. Perform steps 5 through 8 above.
+
+See https://www.chromium.org/developers/design-documents/mojo for more
+information.
+
+[1] A feature can optionally express requirements for where it can be accessed.
+ See the _api_features.json and _permission_features.json files for
+ additional details. For Chrome extensions this should match the definitions
+ in the chrome/common/extensions/api/_*_features.json files.
+
+[2] Service Manifest InterfaceProviderSpecs control interfaces exposed between
+ processes. Mojo interfaces exposed at the frame level are controlled by the
+ "navigation:frame" dictionary. Those exposed at the process level are
+ controlled by the "service_manager:connector" dictionary. Failure to specify
+ this correctly may result in a console error like the following:
+
+ InterfaceProviderSpec "navigation:frame" prevented service:
+ service:content_renderer from binding interface:
+ mojom::Foo exposed by: service:content_browser
+
+[3] Some Mojo APIs use singleton Factory objects that create a one-to-one
+ relationship between a service and a BrowserContext. This is used primarily
+ to control shutdown/destruction order and implementors must explicitly state
+ which services are depended on. See comments in
+ components/keyed_service/content/browser_context_keyed_service_factory.h
+ for additional details.
diff --git a/libcef/common/extensions/api/_api_features.json b/libcef/common/extensions/api/_api_features.json
new file mode 100644
index 00000000..db253cfa
--- /dev/null
+++ b/libcef/common/extensions/api/_api_features.json
@@ -0,0 +1,46 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file defines extension APIs implemented in CEF.
+// See extensions/common/features/* to understand this file, in particular
+// feature.h, simple_feature.h, and feature_provider.h.
+
+// If APIs are defined in chrome then entries must also be added in
+// libcef/browser/extensions/chrome_api_registration.cc.
+
+{
+ // From chrome/common/extensions/api/_api_features.json.
+ // Required by the PDF extension which is hosted in a guest view.
+ "contentSettings": {
+ "dependencies": ["permission:contentSettings"],
+ "contexts": ["blessed_extension"]
+ },
+ "mimeHandlerViewGuestInternal": {
+ "internal": true,
+ "contexts": "all",
+ "channel": "stable",
+ "matches": ["<all_urls>"]
+ },
+ "pdfViewerPrivate": {
+ "dependencies": ["permission:pdfViewerPrivate"],
+ "contexts": ["blessed_extension"]
+ },
+ "resourcesPrivate": [
+ {
+ "dependencies": ["permission:resourcesPrivate"],
+ "contexts": ["blessed_extension"]
+ },
+ {
+ "channel": "stable",
+ "contexts": ["webui"],
+ "matches": ["chrome://print/*"]
+ }
+ ],
+ "tabs": {
+ "channel": "stable",
+ "extension_types": ["extension", "legacy_packaged_app"],
+ "contexts": ["blessed_extension"],
+ "disallow_for_service_workers": false
+ }
+}
diff --git a/libcef/common/extensions/api/_permission_features.json b/libcef/common/extensions/api/_permission_features.json
new file mode 100644
index 00000000..96013ada
--- /dev/null
+++ b/libcef/common/extensions/api/_permission_features.json
@@ -0,0 +1,43 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file defines permissions for extension APIs implemented by CEF.
+// See extensions/common/features/* to understand this file, in particular
+// feature.h, simple_feature.h, and feature_provider.h.
+
+// If APIs are defined in chrome then entries must also be added in
+// libcef/browser/extensions/chrome_api_registration.cc.
+
+{
+ // From chrome/common/extensions/api/_permission_features.json.
+ // Required by the PDF extension which is hosted in a guest view.
+ "contentSettings": {
+ "channel": "stable",
+ "extension_types": ["extension", "legacy_packaged_app"]
+ },
+ "pdfViewerPrivate": {
+ "channel": "stable",
+ "extension_types": ["extension"],
+ "allowlist": [
+ "CBCC42ABED43A4B58FE3810E62AFFA010EB0349F" // PDF Viewer
+ ]
+ },
+ "resourcesPrivate": {
+ "channel": "stable",
+ "extension_types": [
+ "extension", "legacy_packaged_app", "platform_app"
+ ],
+ "location": "component"
+ },
+ "tabs": [
+ {
+ "channel": "stable",
+ "extension_types": ["extension", "legacy_packaged_app"]
+ },
+ {
+ "channel": "stable",
+ "extension_types": ["platform_app"]
+ }
+ ]
+}
diff --git a/libcef/common/extensions/chrome_generated_schemas.cc b/libcef/common/extensions/chrome_generated_schemas.cc
new file mode 100644
index 00000000..a89519ce
--- /dev/null
+++ b/libcef/common/extensions/chrome_generated_schemas.cc
@@ -0,0 +1,33 @@
+// Copyright (c) 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/common/extensions/chrome_generated_schemas.h"
+
+#include "libcef/browser/extensions/chrome_api_registration.h"
+
+#include "chrome/common/extensions/api/generated_schemas.h"
+
+namespace extensions {
+namespace api {
+namespace cef {
+
+// static
+base::StringPiece ChromeGeneratedSchemas::Get(const std::string& name) {
+ if (!ChromeFunctionRegistry::IsSupported(name)) {
+ return base::StringPiece();
+ }
+ return extensions::api::ChromeGeneratedSchemas::Get(name);
+}
+
+// static
+bool ChromeGeneratedSchemas::IsGenerated(std::string name) {
+ if (!ChromeFunctionRegistry::IsSupported(name)) {
+ return false;
+ }
+ return extensions::api::ChromeGeneratedSchemas::IsGenerated(name);
+}
+
+} // namespace cef
+} // namespace api
+} // namespace extensions
diff --git a/libcef/common/extensions/chrome_generated_schemas.h b/libcef/common/extensions/chrome_generated_schemas.h
new file mode 100644
index 00000000..dbb6bd72
--- /dev/null
+++ b/libcef/common/extensions/chrome_generated_schemas.h
@@ -0,0 +1,34 @@
+// Copyright (c) 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// GENERATED FROM THE API DEFINITIONS IN
+// chrome\common\extensions\api
+// DO NOT EDIT.
+
+#ifndef CEF_LIBCEF_COMMON_EXTENSIONS_CHROME_GENERATED_SCHEMAS_H_
+#define CEF_LIBCEF_COMMON_EXTENSIONS_CHROME_GENERATED_SCHEMAS_H_
+
+#include <map>
+#include <string>
+
+#include "base/strings/string_piece.h"
+
+namespace extensions {
+namespace api {
+namespace cef {
+
+class ChromeGeneratedSchemas {
+ public:
+ // Determines if schema named |name| is generated.
+ static bool IsGenerated(std::string name);
+
+ // Gets the API schema named |name|.
+ static base::StringPiece Get(const std::string& name);
+};
+
+} // namespace cef
+} // namespace api
+} // namespace extensions
+
+#endif // CEF_LIBCEF_COMMON_EXTENSIONS_CHROME_GENERATED_SCHEMAS_H_
diff --git a/libcef/common/extensions/extensions_api_provider.cc b/libcef/common/extensions/extensions_api_provider.cc
new file mode 100644
index 00000000..eb376731
--- /dev/null
+++ b/libcef/common/extensions/extensions_api_provider.cc
@@ -0,0 +1,89 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/common/extensions/extensions_api_provider.h"
+
+#include "libcef/common/extensions/chrome_generated_schemas.h"
+
+#include "cef/grit/cef_resources.h"
+// #include "cef/libcef/common/extensions/api/generated_schemas.h"
+#include "cef/libcef/common/extensions/api/cef_api_features.h"
+#include "cef/libcef/common/extensions/api/cef_manifest_features.h"
+#include "cef/libcef/common/extensions/api/cef_permission_features.h"
+#include "chrome/common/extensions/chrome_manifest_handlers.h"
+#include "chrome/common/extensions/permissions/chrome_api_permissions.h"
+#include "extensions/common/features/json_feature_provider_source.h"
+#include "extensions/common/permissions/permissions_info.h"
+
+namespace extensions {
+
+CefExtensionsAPIProvider::CefExtensionsAPIProvider() {}
+
+void CefExtensionsAPIProvider::AddAPIFeatures(FeatureProvider* provider) {
+ AddCEFAPIFeatures(provider);
+}
+
+void CefExtensionsAPIProvider::AddManifestFeatures(FeatureProvider* provider) {
+ AddCEFManifestFeatures(provider);
+}
+
+void CefExtensionsAPIProvider::AddPermissionFeatures(
+ FeatureProvider* provider) {
+ AddCEFPermissionFeatures(provider);
+}
+
+void CefExtensionsAPIProvider::AddBehaviorFeatures(FeatureProvider* provider) {
+ // No CEF-specific behavior features.
+}
+
+void CefExtensionsAPIProvider::AddAPIJSONSources(
+ JSONFeatureProviderSource* json_source) {
+ // Extension API features specific to CEF. See
+ // libcef/common/extensions/api/README.txt for additional details.
+ json_source->LoadJSON(IDR_CEF_EXTENSION_API_FEATURES);
+}
+
+bool CefExtensionsAPIProvider::IsAPISchemaGenerated(const std::string& name) {
+ // Schema for CEF-only APIs.
+ // TODO(cef): Enable if/when CEF exposes its own Mojo APIs. See
+ // libcef/common/extensions/api/README.txt for details.
+ // if (api::cef::CefGeneratedSchemas::IsGenerated(name))
+ // return true;
+
+ // Chrome APIs whitelisted by CEF.
+ if (api::cef::ChromeGeneratedSchemas::IsGenerated(name)) {
+ return true;
+ }
+
+ return false;
+}
+
+base::StringPiece CefExtensionsAPIProvider::GetAPISchema(
+ const std::string& name) {
+ // Schema for CEF-only APIs.
+ // TODO(cef): Enable if/when CEF exposes its own Mojo APIs. See
+ // libcef/common/extensions/api/README.txt for details.
+ // if (api::cef::CefGeneratedSchemas::IsGenerated(name))
+ // return api::cef::CefGeneratedSchemas::Get(name);
+
+ // Chrome APIs whitelisted by CEF.
+ if (api::cef::ChromeGeneratedSchemas::IsGenerated(name)) {
+ return api::cef::ChromeGeneratedSchemas::Get(name);
+ }
+
+ return base::StringPiece();
+}
+
+void CefExtensionsAPIProvider::RegisterPermissions(
+ PermissionsInfo* permissions_info) {
+ permissions_info->RegisterPermissions(
+ chrome_api_permissions::GetPermissionInfos(),
+ chrome_api_permissions::GetPermissionAliases());
+}
+
+void CefExtensionsAPIProvider::RegisterManifestHandlers() {
+ RegisterChromeManifestHandlers();
+}
+
+} // namespace extensions
diff --git a/libcef/common/extensions/extensions_api_provider.h b/libcef/common/extensions/extensions_api_provider.h
new file mode 100644
index 00000000..106b3cc2
--- /dev/null
+++ b/libcef/common/extensions/extensions_api_provider.h
@@ -0,0 +1,33 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_COMMON_EXTENSIONS_EXTENSIONS_API_PROVIDER_H_
+#define CEF_LIBCEF_COMMON_EXTENSIONS_EXTENSIONS_API_PROVIDER_H_
+
+#include "extensions/common/extensions_api_provider.h"
+
+namespace extensions {
+
+class CefExtensionsAPIProvider : public ExtensionsAPIProvider {
+ public:
+ CefExtensionsAPIProvider();
+
+ CefExtensionsAPIProvider(const CefExtensionsAPIProvider&) = delete;
+ CefExtensionsAPIProvider& operator=(const CefExtensionsAPIProvider&) = delete;
+
+ // ExtensionsAPIProvider:
+ void AddAPIFeatures(FeatureProvider* provider) override;
+ void AddManifestFeatures(FeatureProvider* provider) override;
+ void AddPermissionFeatures(FeatureProvider* provider) override;
+ void AddBehaviorFeatures(FeatureProvider* provider) override;
+ void AddAPIJSONSources(JSONFeatureProviderSource* json_source) override;
+ bool IsAPISchemaGenerated(const std::string& name) override;
+ base::StringPiece GetAPISchema(const std::string& name) override;
+ void RegisterPermissions(PermissionsInfo* permissions_info) override;
+ void RegisterManifestHandlers() override;
+};
+
+} // namespace extensions
+
+#endif // CEF_LIBCEF_COMMON_EXTENSIONS_EXTENSIONS_API_PROVIDER_H_
diff --git a/libcef/common/extensions/extensions_client.cc b/libcef/common/extensions/extensions_client.cc
new file mode 100644
index 00000000..dfac5225
--- /dev/null
+++ b/libcef/common/extensions/extensions_client.cc
@@ -0,0 +1,102 @@
+// Copyright 2015 The Chromium Embedded Framework Authors.
+// Portions copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/common/extensions/extensions_client.h"
+
+#include <utility>
+
+#include "libcef/common/cef_switches.h"
+#include "libcef/common/extensions/extensions_api_provider.h"
+
+#include "base/logging.h"
+#include "extensions/common/core_extensions_api_provider.h"
+#include "extensions/common/extension_urls.h"
+#include "extensions/common/features/simple_feature.h"
+#include "extensions/common/permissions/permission_message_provider.h"
+#include "extensions/common/url_pattern_set.h"
+
+namespace extensions {
+
+namespace {
+
+template <class FeatureClass>
+SimpleFeature* CreateFeature() {
+ return new FeatureClass;
+}
+
+} // namespace
+
+CefExtensionsClient::CefExtensionsClient()
+ : webstore_base_url_(extension_urls::kChromeWebstoreBaseURL),
+ new_webstore_base_url_(extension_urls::kNewChromeWebstoreBaseURL),
+ webstore_update_url_(extension_urls::kChromeWebstoreUpdateURL) {
+ AddAPIProvider(std::make_unique<CoreExtensionsAPIProvider>());
+ AddAPIProvider(std::make_unique<CefExtensionsAPIProvider>());
+}
+
+CefExtensionsClient::~CefExtensionsClient() {}
+
+void CefExtensionsClient::Initialize() {}
+
+void CefExtensionsClient::InitializeWebStoreUrls(
+ base::CommandLine* command_line) {}
+
+const PermissionMessageProvider&
+CefExtensionsClient::GetPermissionMessageProvider() const {
+ return permission_message_provider_;
+}
+
+const std::string CefExtensionsClient::GetProductName() {
+ return "cef";
+}
+
+void CefExtensionsClient::FilterHostPermissions(
+ const URLPatternSet& hosts,
+ URLPatternSet* new_hosts,
+ PermissionIDSet* permissions) const {
+ NOTIMPLEMENTED();
+}
+
+void CefExtensionsClient::SetScriptingAllowlist(
+ const ScriptingAllowlist& allowlist) {
+ scripting_allowlist_ = allowlist;
+}
+
+const ExtensionsClient::ScriptingAllowlist&
+CefExtensionsClient::GetScriptingAllowlist() const {
+ // TODO(jamescook): Real allowlist.
+ return scripting_allowlist_;
+}
+
+URLPatternSet CefExtensionsClient::GetPermittedChromeSchemeHosts(
+ const Extension* extension,
+ const APIPermissionSet& api_permissions) const {
+ return URLPatternSet();
+}
+
+bool CefExtensionsClient::IsScriptableURL(const GURL& url,
+ std::string* error) const {
+ return true;
+}
+
+const GURL& CefExtensionsClient::GetWebstoreBaseURL() const {
+ return webstore_base_url_;
+}
+
+const GURL& CefExtensionsClient::GetNewWebstoreBaseURL() const {
+ return new_webstore_base_url_;
+}
+
+const GURL& CefExtensionsClient::GetWebstoreUpdateURL() const {
+ return webstore_update_url_;
+}
+
+bool CefExtensionsClient::IsBlocklistUpdateURL(const GURL& url) const {
+ // TODO(rockot): Maybe we want to do something else here. For now we accept
+ // any URL as a blocklist URL because we don't really care.
+ return true;
+}
+
+} // namespace extensions
diff --git a/libcef/common/extensions/extensions_client.h b/libcef/common/extensions/extensions_client.h
new file mode 100644
index 00000000..7caf763f
--- /dev/null
+++ b/libcef/common/extensions/extensions_client.h
@@ -0,0 +1,58 @@
+// Copyright 2015 The Chromium Embedded Framework Authors.
+// Portions copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_COMMON_EXTENSIONS_EXTENSIONS_CLIENT_H_
+#define CEF_LIBCEF_COMMON_EXTENSIONS_EXTENSIONS_CLIENT_H_
+
+#include "chrome/common/extensions/permissions/chrome_permission_message_provider.h"
+#include "extensions/common/extensions_client.h"
+#include "url/gurl.h"
+
+namespace extensions {
+
+// The CEF implementation of ExtensionsClient.
+class CefExtensionsClient : public ExtensionsClient {
+ public:
+ CefExtensionsClient();
+
+ CefExtensionsClient(const CefExtensionsClient&) = delete;
+ CefExtensionsClient& operator=(const CefExtensionsClient&) = delete;
+
+ ~CefExtensionsClient() override;
+
+ // ExtensionsClient overrides:
+ void Initialize() override;
+ void InitializeWebStoreUrls(base::CommandLine* command_line) override;
+ const PermissionMessageProvider& GetPermissionMessageProvider()
+ const override;
+ const std::string GetProductName() override;
+ void FilterHostPermissions(const URLPatternSet& hosts,
+ URLPatternSet* new_hosts,
+ PermissionIDSet* permissions) const override;
+ void SetScriptingAllowlist(const ScriptingAllowlist& allowlist) override;
+ const ScriptingAllowlist& GetScriptingAllowlist() const override;
+ URLPatternSet GetPermittedChromeSchemeHosts(
+ const Extension* extension,
+ const APIPermissionSet& api_permissions) const override;
+ bool IsScriptableURL(const GURL& url, std::string* error) const override;
+ const GURL& GetWebstoreBaseURL() const override;
+ const GURL& GetNewWebstoreBaseURL() const override;
+ const GURL& GetWebstoreUpdateURL() const override;
+ bool IsBlocklistUpdateURL(const GURL& url) const override;
+
+ private:
+ const ChromePermissionMessageProvider permission_message_provider_;
+
+ ScriptingAllowlist scripting_allowlist_;
+
+ // Mutable to allow caching in a const method.
+ const GURL webstore_base_url_;
+ const GURL new_webstore_base_url_;
+ const GURL webstore_update_url_;
+};
+
+} // namespace extensions
+
+#endif // CEF_LIBCEF_COMMON_EXTENSIONS_EXTENSIONS_CLIENT_H_
diff --git a/libcef/common/extensions/extensions_util.cc b/libcef/common/extensions/extensions_util.cc
new file mode 100644
index 00000000..f1265307
--- /dev/null
+++ b/libcef/common/extensions/extensions_util.cc
@@ -0,0 +1,46 @@
+// Copyright 2015 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#include "libcef/common/extensions/extensions_util.h"
+
+#include "libcef/common/cef_switches.h"
+
+#include "base/command_line.h"
+#include "chrome/common/chrome_switches.h"
+
+namespace extensions {
+
+bool ExtensionsEnabled() {
+ static bool enabled = !base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableExtensions);
+ return enabled;
+}
+
+bool PdfExtensionEnabled() {
+ static bool enabled =
+ ExtensionsEnabled() && !base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisablePdfExtension);
+ return enabled;
+}
+
+bool PrintPreviewEnabled() {
+#if BUILDFLAG(IS_MAC)
+ // Not currently supported on macOS.
+ return false;
+#else
+ if (!PdfExtensionEnabled()) {
+ return false;
+ }
+
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisablePrintPreview)) {
+ return false;
+ }
+
+ return base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnablePrintPreview);
+#endif
+}
+
+} // namespace extensions
diff --git a/libcef/common/extensions/extensions_util.h b/libcef/common/extensions/extensions_util.h
new file mode 100644
index 00000000..6bcbdde7
--- /dev/null
+++ b/libcef/common/extensions/extensions_util.h
@@ -0,0 +1,21 @@
+// Copyright 2015 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#ifndef CEF_LIBCEF_COMMON_EXTENSIONS_EXTENSIONS_UTIL_H_
+#define CEF_LIBCEF_COMMON_EXTENSIONS_EXTENSIONS_UTIL_H_
+
+namespace extensions {
+
+// Returns true if extensions have not been disabled via the command-line.
+bool ExtensionsEnabled();
+
+// Returns true if the PDF extension has not been disabled via the command-line.
+bool PdfExtensionEnabled();
+
+// Returns true if Print Preview has been enabled via the command-line.
+bool PrintPreviewEnabled();
+
+} // namespace extensions
+
+#endif // CEF_LIBCEF_COMMON_EXTENSIONS_EXTENSIONS_UTIL_H_
diff --git a/libcef/common/file_util_impl.cc b/libcef/common/file_util_impl.cc
new file mode 100644
index 00000000..e27609ae
--- /dev/null
+++ b/libcef/common/file_util_impl.cc
@@ -0,0 +1,97 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#include "include/cef_file_util.h"
+
+#include "include/cef_task.h"
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "third_party/zlib/google/zip.h"
+
+namespace {
+
+bool AllowFileIO() {
+ if (CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO)) {
+ NOTREACHED() << "file IO is not allowed on the current thread";
+ return false;
+ }
+ return true;
+}
+
+} // namespace
+
+bool CefCreateDirectory(const CefString& full_path) {
+ if (!AllowFileIO()) {
+ return false;
+ }
+ return base::CreateDirectory(full_path);
+}
+
+bool CefGetTempDirectory(CefString& temp_dir) {
+ if (!AllowFileIO()) {
+ return false;
+ }
+ base::FilePath result;
+ if (base::GetTempDir(&result)) {
+ temp_dir = result.value();
+ return true;
+ }
+ return false;
+}
+
+bool CefCreateNewTempDirectory(const CefString& prefix,
+ CefString& new_temp_path) {
+ if (!AllowFileIO()) {
+ return false;
+ }
+ base::FilePath result;
+ if (base::CreateNewTempDirectory(prefix, &result)) {
+ new_temp_path = result.value();
+ return true;
+ }
+ return false;
+}
+
+bool CefCreateTempDirectoryInDirectory(const CefString& base_dir,
+ const CefString& prefix,
+ CefString& new_dir) {
+ if (!AllowFileIO()) {
+ return false;
+ }
+ base::FilePath result;
+ if (base::CreateTemporaryDirInDir(base_dir, prefix, &result)) {
+ new_dir = result.value();
+ return true;
+ }
+ return false;
+}
+
+bool CefDirectoryExists(const CefString& path) {
+ if (!AllowFileIO()) {
+ return false;
+ }
+ return base::DirectoryExists(path);
+}
+
+bool CefDeleteFile(const CefString& path, bool recursive) {
+ if (!AllowFileIO()) {
+ return false;
+ }
+ if (recursive) {
+ return base::DeletePathRecursively(path);
+ } else {
+ return base::DeleteFile(path);
+ }
+}
+
+bool CefZipDirectory(const CefString& src_dir,
+ const CefString& dest_file,
+ bool include_hidden_files) {
+ if (!AllowFileIO()) {
+ return false;
+ }
+ return zip::Zip(src_dir, dest_file, include_hidden_files);
+}
diff --git a/libcef/common/frame_util.cc b/libcef/common/frame_util.cc
new file mode 100644
index 00000000..0ed3d03c
--- /dev/null
+++ b/libcef/common/frame_util.cc
@@ -0,0 +1,39 @@
+// Copyright (c) 2019 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#include "libcef/common/frame_util.h"
+
+#include "libcef/browser/thread_util.h"
+
+#include <limits>
+#include <sstream>
+
+#include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/render_frame_host.h"
+
+namespace frame_util {
+
+content::GlobalRenderFrameHostId GetGlobalId(
+ content::NavigationHandle* navigation_handle) {
+ CEF_REQUIRE_UIT();
+ return navigation_handle->HasCommitted()
+ ? navigation_handle->GetRenderFrameHost()->GetGlobalId()
+ : navigation_handle->GetPreviousRenderFrameHostId();
+}
+
+std::string GetFrameDebugString(int64_t frame_id) {
+ uint32_t process_id = frame_id >> 32;
+ uint32_t routing_id = std::numeric_limits<uint32_t>::max() & frame_id;
+
+ std::stringstream ss;
+ ss << frame_id << " [" << process_id << "," << routing_id << "]";
+ return ss.str();
+}
+
+std::string GetFrameDebugString(
+ const content::GlobalRenderFrameHostId& global_id) {
+ return GetFrameDebugString(MakeFrameId(global_id));
+}
+
+} // namespace frame_util
diff --git a/libcef/common/frame_util.h b/libcef/common/frame_util.h
new file mode 100644
index 00000000..7aeedbf0
--- /dev/null
+++ b/libcef/common/frame_util.h
@@ -0,0 +1,84 @@
+// Copyright (c) 2019 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_COMMON_FRAME_UTIL_H_
+#define CEF_LIBCEF_COMMON_FRAME_UTIL_H_
+
+#include <stdint.h>
+#include <string>
+
+#include "base/logging.h"
+#include "content/public/browser/child_process_host.h"
+#include "content/public/browser/global_routing_id.h"
+
+namespace content {
+class NavigationHandle;
+}
+
+namespace frame_util {
+
+// Create a frame ID in the format exposed by the CEF API.
+inline int64_t MakeFrameId(int child_id, int frame_routing_id) {
+ return (static_cast<uint64_t>(child_id) << 32) |
+ static_cast<uint64_t>(frame_routing_id);
+}
+
+// Create a frame ID in the format exposed by the CEF API.
+inline int64_t MakeFrameId(const content::GlobalRenderFrameHostId& global_id) {
+ return MakeFrameId(global_id.child_id, global_id.frame_routing_id);
+}
+
+// Returns true if |child_id| is valid.
+inline bool IsValidChildId(int child_id) {
+ // See comments in ChildProcessHostImpl::GenerateChildProcessUniqueId().
+ return child_id != content::ChildProcessHost::kInvalidUniqueID &&
+ child_id != 0;
+}
+
+// Returns true if |frame_routing_id| is valid.
+inline bool IsValidRoutingId(int frame_routing_id) {
+ return frame_routing_id != MSG_ROUTING_NONE;
+}
+
+// Returns true if |global_id| is valid.
+inline bool IsValidGlobalId(const content::GlobalRenderFrameHostId& global_id) {
+ return IsValidChildId(global_id.child_id) &&
+ IsValidRoutingId(global_id.frame_routing_id);
+}
+
+// Create a global ID from components.
+inline content::GlobalRenderFrameHostId MakeGlobalId(
+ int child_id,
+ int frame_routing_id,
+ bool allow_invalid_frame_id = false) {
+ DCHECK(IsValidChildId(child_id));
+ DCHECK(allow_invalid_frame_id || IsValidRoutingId(frame_routing_id));
+ return content::GlobalRenderFrameHostId(child_id, frame_routing_id);
+}
+
+// Create a global ID from a frame ID.
+inline content::GlobalRenderFrameHostId MakeGlobalId(int64_t frame_id) {
+ uint32_t child_id = frame_id >> 32;
+ uint32_t frame_routing_id = std::numeric_limits<uint32_t>::max() & frame_id;
+ return MakeGlobalId(child_id, frame_routing_id);
+}
+
+// Returns an invalid global ID value.
+inline content::GlobalRenderFrameHostId InvalidGlobalId() {
+ return content::GlobalRenderFrameHostId();
+}
+
+// Returns the best match of global ID for |navigation_handle|. For pre-commit
+// navigations this will return the current RFH, if any, or an invalid ID.
+content::GlobalRenderFrameHostId GetGlobalId(
+ content::NavigationHandle* navigation_handle);
+
+// Returns a human-readable version of the ID.
+std::string GetFrameDebugString(int64_t frame_id);
+std::string GetFrameDebugString(
+ const content::GlobalRenderFrameHostId& global_id);
+
+} // namespace frame_util
+
+#endif // CEF_LIBCEF_COMMON_FRAME_UTIL_H_
diff --git a/libcef/common/i18n_util_impl.cc b/libcef/common/i18n_util_impl.cc
new file mode 100644
index 00000000..b4f901b0
--- /dev/null
+++ b/libcef/common/i18n_util_impl.cc
@@ -0,0 +1,11 @@
+// Copyright 2021 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#include "include/cef_i18n_util.h"
+
+#include "base/i18n/rtl.h"
+
+bool CefIsRTL() {
+ return base::i18n::IsRTL();
+}
diff --git a/libcef/common/json_impl.cc b/libcef/common/json_impl.cc
new file mode 100644
index 00000000..1b5dca73
--- /dev/null
+++ b/libcef/common/json_impl.cc
@@ -0,0 +1,91 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#include "include/cef_parser.h"
+#include "libcef/common/values_impl.h"
+
+#include "base/json/json_reader.h"
+#include "base/json/json_writer.h"
+#include "base/values.h"
+
+namespace {
+
+int GetJSONReaderOptions(cef_json_parser_options_t options) {
+ int op = base::JSON_PARSE_RFC;
+ if (options & JSON_PARSER_ALLOW_TRAILING_COMMAS) {
+ op |= base::JSON_ALLOW_TRAILING_COMMAS;
+ }
+ return op;
+}
+
+int GetJSONWriterOptions(cef_json_writer_options_t options) {
+ int op = 0;
+ if (options & JSON_WRITER_OMIT_BINARY_VALUES) {
+ op |= base::JSONWriter::OPTIONS_OMIT_BINARY_VALUES;
+ }
+ if (options & JSON_WRITER_OMIT_DOUBLE_TYPE_PRESERVATION) {
+ op |= base::JSONWriter::OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION;
+ }
+ if (options & JSON_WRITER_PRETTY_PRINT) {
+ op |= base::JSONWriter::OPTIONS_PRETTY_PRINT;
+ }
+ return op;
+}
+
+} // namespace
+
+CefRefPtr<CefValue> CefParseJSON(const CefString& json_string,
+ cef_json_parser_options_t options) {
+ const std::string& json = json_string.ToString();
+ return CefParseJSON(json.data(), json.size(), options);
+}
+
+CefRefPtr<CefValue> CefParseJSON(const void* json,
+ size_t json_size,
+ cef_json_parser_options_t options) {
+ if (!json || json_size == 0) {
+ return nullptr;
+ }
+ absl::optional<base::Value> parse_result = base::JSONReader::Read(
+ base::StringPiece(static_cast<const char*>(json), json_size),
+ GetJSONReaderOptions(options));
+ if (parse_result) {
+ return new CefValueImpl(std::move(parse_result.value()));
+ }
+ return nullptr;
+}
+
+CefRefPtr<CefValue> CefParseJSONAndReturnError(
+ const CefString& json_string,
+ cef_json_parser_options_t options,
+ CefString& error_msg_out) {
+ const std::string& json = json_string.ToString();
+
+ std::string error_msg;
+ auto result = base::JSONReader::ReadAndReturnValueWithError(
+ json, GetJSONReaderOptions(options));
+ if (result.has_value()) {
+ return new CefValueImpl(std::move(*result));
+ }
+
+ error_msg_out = result.error().message;
+ return nullptr;
+}
+
+CefString CefWriteJSON(CefRefPtr<CefValue> node,
+ cef_json_writer_options_t options) {
+ if (!node.get() || !node->IsValid()) {
+ return CefString();
+ }
+
+ CefValueImpl* impl = static_cast<CefValueImpl*>(node.get());
+ CefValueImpl::ScopedLockedValue scoped_value(impl);
+
+ std::string json_string;
+ if (base::JSONWriter::WriteWithOptions(
+ *scoped_value.value(), GetJSONWriterOptions(options), &json_string)) {
+ return json_string;
+ }
+ return CefString();
+}
diff --git a/libcef/common/main_runner_delegate.h b/libcef/common/main_runner_delegate.h
new file mode 100644
index 00000000..335ab2b8
--- /dev/null
+++ b/libcef/common/main_runner_delegate.h
@@ -0,0 +1,38 @@
+// Copyright 2020 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_COMMON_MAIN_RUNNER_DELEGATE_H_
+#define CEF_LIBCEF_COMMON_MAIN_RUNNER_DELEGATE_H_
+#pragma once
+
+#include "include/cef_app.h"
+
+namespace base {
+class RunLoop;
+}
+
+namespace content {
+class ContentMainDelegate;
+}
+
+class CefMainRunnerDelegate {
+ public:
+ virtual content::ContentMainDelegate* GetContentMainDelegate() = 0;
+
+ virtual void BeforeMainThreadInitialize(const CefMainArgs& args) {}
+ virtual void BeforeMainThreadRun() {}
+ virtual void BeforeMainMessageLoopRun(base::RunLoop* run_loop) {}
+ virtual bool HandleMainMessageLoopQuit() { return false; }
+ virtual void BeforeUIThreadInitialize() {}
+ virtual void AfterUIThreadInitialize() {}
+ virtual void AfterUIThreadShutdown() {}
+ virtual void BeforeMainThreadShutdown() {}
+ virtual void AfterMainThreadShutdown() {}
+ virtual void BeforeExecuteProcess(const CefMainArgs& args) {}
+ virtual void AfterExecuteProcess() {}
+
+ virtual ~CefMainRunnerDelegate() {}
+};
+
+#endif // CEF_LIBCEF_COMMON_MAIN_RUNNER_DELEGATE_H_
diff --git a/libcef/common/main_runner_handler.h b/libcef/common/main_runner_handler.h
new file mode 100644
index 00000000..1314c72e
--- /dev/null
+++ b/libcef/common/main_runner_handler.h
@@ -0,0 +1,24 @@
+// Copyright 2020 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_COMMON_MAIN_RUNNER_HANDLER_H_
+#define CEF_LIBCEF_COMMON_MAIN_RUNNER_HANDLER_H_
+#pragma once
+
+namespace content {
+struct MainFunctionParams;
+}
+
+// Handles running of the main process.
+class CefMainRunnerHandler {
+ public:
+ virtual void PreBrowserMain() = 0;
+ virtual int RunMainProcess(
+ content::MainFunctionParams main_function_params) = 0;
+
+ protected:
+ virtual ~CefMainRunnerHandler() {}
+};
+
+#endif // CEF_LIBCEF_COMMON_MAIN_RUNNER_HANDLER_H_
diff --git a/libcef/common/mojom/BUILD.gn b/libcef/common/mojom/BUILD.gn
new file mode 100644
index 00000000..a8b59b55
--- /dev/null
+++ b/libcef/common/mojom/BUILD.gn
@@ -0,0 +1,29 @@
+# Copyright 2021 The Chromium Embedded Framework Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//mojo/public/tools/bindings/mojom.gni")
+
+mojom("mojom") {
+ sources = [ "cef.mojom" ]
+
+ cpp_only = true
+ disable_variants = true
+
+ public_deps = [
+ "//content/public/common:interfaces",
+ "//mojo/public/mojom/base",
+ "//services/network/public/mojom:cookies_mojom",
+ "//services/network/public/mojom:url_loader_base",
+ "//third_party/blink/public/mojom:mojom_platform",
+ "//ui/gfx/geometry/mojom",
+ "//url/mojom:url_mojom_gurl",
+ ]
+
+ overridden_deps = [
+ "//content/public/common:interfaces",
+ "//third_party/blink/public/mojom:mojom_platform",
+ ]
+
+ component_deps = [ "//content/public/common" ]
+}
diff --git a/libcef/common/mojom/cef.mojom b/libcef/common/mojom/cef.mojom
new file mode 100644
index 00000000..ee6fb087
--- /dev/null
+++ b/libcef/common/mojom/cef.mojom
@@ -0,0 +1,139 @@
+// Copyright 2021 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module cef.mojom;
+
+import "mojo/public/mojom/base/shared_memory.mojom";
+import "mojo/public/mojom/base/string16.mojom";
+import "mojo/public/mojom/base/values.mojom";
+import "services/network/public/mojom/site_for_cookies.mojom";
+import "services/network/public/mojom/url_request.mojom";
+import "third_party/blink/public/mojom/loader/referrer.mojom";
+import "ui/gfx/geometry/mojom/geometry.mojom";
+import "url/mojom/url.mojom";
+
+// Structure passed to UpdateDraggableRegions().
+struct DraggableRegionEntry {
+ gfx.mojom.Rect bounds;
+ bool draggable;
+};
+
+// Structure passed to LoadRequest().
+struct RequestParams {
+ // Request method.
+ string method;
+
+ // The URL to be loaded.
+ url.mojom.Url url;
+
+ // The referrer for the request.
+ blink.mojom.Referrer referrer;
+
+ // Usually the URL of the document in the top-level window, which may be
+ // checked by the third-party cookie blocking policy. Leaving it empty may
+ // lead to undesired cookie blocking. Third-party cookie blocking can be
+ // bypassed by setting site_for_cookies = url, but this should ideally
+ // only be done if there really is no way to determine the correct value.
+ network.mojom.SiteForCookies site_for_cookies;
+
+ // Additional HTTP request headers.
+ string headers;
+
+ // net::URLRequest load flags (0 by default).
+ int32 load_flags;
+
+ // Upload data (may be empty).
+ network.mojom.URLRequestBody? upload_data;
+};
+
+// Interface for communicating with a frame in the renderer process.
+interface RenderFrame {
+ // Browser process has received the FrameAttached() message.
+ FrameAttachedAck();
+
+ // Browser process has intentionally detached.
+ FrameDetached();
+
+ // Send a message to the render process.
+ SendMessage(string name, mojo_base.mojom.ListValue arguments);
+
+ // Send a shared memory region to the render process.
+ SendSharedMemoryRegion(string name, mojo_base.mojom.ReadOnlySharedMemoryRegion region);
+
+ // Send a command.
+ SendCommand(string command);
+
+ // Send a command that returns an async response.
+ // The returned |response| format is command-specific and will be invalid if
+ // an error occurred.
+ SendCommandWithResponse(string command) =>
+ (mojo_base.mojom.ReadOnlySharedMemoryRegion? response);
+
+ // Send JavaScript for execution.
+ SendJavaScript(mojo_base.mojom.String16 jsCode, string scriptUrl,
+ int32 startLine);
+
+ // Load a request.
+ LoadRequest(RequestParams params);
+
+ // Loading has stopped.
+ DidStopLoading();
+
+ // Move or resize of the renderer's containing window has started. Used on
+ // Windows and Linux with the Alloy runtime.
+ MoveOrResizeStarted();
+};
+
+// Interface for communicating with a frame in the browser process.
+interface BrowserFrame {
+ // Send a message to the browser process.
+ SendMessage(string name, mojo_base.mojom.ListValue arguments);
+
+ // Send a shared memory region to the browser process.
+ SendSharedMemoryRegion(string name, mojo_base.mojom.ReadOnlySharedMemoryRegion region);
+
+ // The render frame is ready to begin handling actions.
+ FrameAttached(pending_remote<RenderFrame> render_frame,
+ bool reattached);
+
+ // Draggable regions have updated.
+ UpdateDraggableRegions(array<DraggableRegionEntry>? regions);
+};
+
+struct CrossOriginWhiteListEntry {
+ string source_origin;
+ string target_protocol;
+ string target_domain;
+ bool allow_target_subdomains;
+};
+
+struct NewRenderThreadInfo {
+ array<CrossOriginWhiteListEntry>? cross_origin_whitelist_entries;
+};
+
+struct NewBrowserInfo {
+ int32 browser_id;
+ bool is_popup;
+ bool is_windowless;
+ bool is_guest_view;
+ mojo_base.mojom.DictionaryValue? extra_info;
+};
+
+// Interface for communicating with browser management in the browser process.
+interface BrowserManager {
+ // Retrieve info for a new RenderThread.
+ [Sync]
+ GetNewRenderThreadInfo() => (NewRenderThreadInfo info);
+
+ // Retrieve info for a new CefBrowser.
+ [Sync]
+ GetNewBrowserInfo(int32 render_frame_routing_id) => (NewBrowserInfo info);
+};
+
+// Interface for communicating with browser management to the render process.
+interface RenderManager {
+ // Manage cross-origin whitelist contents during the render process lifespan.
+ ModifyCrossOriginWhitelistEntry(bool add, CrossOriginWhiteListEntry entry);
+ ClearCrossOriginWhitelist();
+};
diff --git a/libcef/common/net/http_header_utils.cc b/libcef/common/net/http_header_utils.cc
new file mode 100644
index 00000000..60a7085d
--- /dev/null
+++ b/libcef/common/net/http_header_utils.cc
@@ -0,0 +1,62 @@
+// Copyright (c) 2011 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "libcef/common/net/http_header_utils.h"
+
+#include <algorithm>
+
+#include "base/strings/string_util.h"
+#include "net/http/http_response_headers.h"
+#include "net/http/http_util.h"
+
+using net::HttpResponseHeaders;
+
+namespace HttpHeaderUtils {
+
+std::string GenerateHeaders(const HeaderMap& map) {
+ std::string headers;
+
+ for (HeaderMap::const_iterator header = map.begin(); header != map.end();
+ ++header) {
+ const CefString& key = header->first;
+ const CefString& value = header->second;
+
+ if (!key.empty()) {
+ // Delimit with "\r\n".
+ if (!headers.empty()) {
+ headers += "\r\n";
+ }
+
+ headers += std::string(key) + ": " + std::string(value);
+ }
+ }
+
+ return headers;
+}
+
+void ParseHeaders(const std::string& header_str, HeaderMap& map) {
+ // Parse the request header values
+ for (net::HttpUtil::HeadersIterator i(header_str.begin(), header_str.end(),
+ "\n\r");
+ i.GetNext();) {
+ map.insert(std::make_pair(i.name(), i.values()));
+ }
+}
+
+void MakeASCIILower(std::string* str) {
+ std::transform(str->begin(), str->end(), str->begin(), ::tolower);
+}
+
+HeaderMap::iterator FindHeaderInMap(const std::string& nameLower,
+ HeaderMap& map) {
+ for (auto it = map.begin(); it != map.end(); ++it) {
+ if (base::EqualsCaseInsensitiveASCII(it->first.ToString(), nameLower)) {
+ return it;
+ }
+ }
+
+ return map.end();
+}
+
+} // namespace HttpHeaderUtils
diff --git a/libcef/common/net/http_header_utils.h b/libcef/common/net/http_header_utils.h
new file mode 100644
index 00000000..45886bca
--- /dev/null
+++ b/libcef/common/net/http_header_utils.h
@@ -0,0 +1,30 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_COMMON_NET_HTTP_HEADER_UTILS_H_
+#define CEF_LIBCEF_COMMON_NET_HTTP_HEADER_UTILS_H_
+#pragma once
+
+#include <map>
+#include <string>
+
+#include "include/cef_base.h"
+
+namespace HttpHeaderUtils {
+
+using HeaderMap = std::multimap<CefString, CefString>;
+
+std::string GenerateHeaders(const HeaderMap& map);
+void ParseHeaders(const std::string& header_str, HeaderMap& map);
+
+// Convert |str| to lower-case.
+void MakeASCIILower(std::string* str);
+
+// Finds the first instance of |name| (already lower-case) in |map| with
+// case-insensitive comparison.
+HeaderMap::iterator FindHeaderInMap(const std::string& name, HeaderMap& map);
+
+} // namespace HttpHeaderUtils
+
+#endif // CEF_LIBCEF_COMMON_NET_HTTP_HEADER_UTILS_H_
diff --git a/libcef/common/net/net_resource_provider.cc b/libcef/common/net/net_resource_provider.cc
new file mode 100644
index 00000000..eea3db75
--- /dev/null
+++ b/libcef/common/net/net_resource_provider.cc
@@ -0,0 +1,17 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "libcef/common/net/net_resource_provider.h"
+
+#include "base/logging.h"
+#include "chrome/common/net/net_resource_provider.h"
+
+scoped_refptr<base::RefCountedMemory> NetResourceProvider(int key) {
+ // Chrome performs substitution of localized strings for directory listings.
+ scoped_refptr<base::RefCountedMemory> value = ChromeNetResourceProvider(key);
+ if (!value) {
+ LOG(ERROR) << "No data resource available for id " << key;
+ }
+ return value;
+}
diff --git a/libcef/common/net/net_resource_provider.h b/libcef/common/net/net_resource_provider.h
new file mode 100644
index 00000000..8f6f6ed4
--- /dev/null
+++ b/libcef/common/net/net_resource_provider.h
@@ -0,0 +1,14 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_COMMON_NET_RESOURCE_PROVIDER_H_
+#define CEF_LIBCEF_COMMON_NET_RESOURCE_PROVIDER_H_
+#pragma once
+
+#include "base/memory/ref_counted_memory.h"
+
+// This is called indirectly by the network layer to access resources.
+scoped_refptr<base::RefCountedMemory> NetResourceProvider(int key);
+
+#endif // CEF_LIBCEF_COMMON_NET_RESOURCE_PROVIDER_H_
diff --git a/libcef/common/net/scheme_info.h b/libcef/common/net/scheme_info.h
new file mode 100644
index 00000000..4730d00e
--- /dev/null
+++ b/libcef/common/net/scheme_info.h
@@ -0,0 +1,53 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_COMMON_NET_SCHEME_INFO_H_
+#define CEF_LIBCEF_COMMON_NET_SCHEME_INFO_H_
+#pragma once
+
+#include <string>
+
+// Values are registered with all processes (url/url_util.h) and with Blink
+// (SchemeRegistry) unless otherwise indicated.
+struct CefSchemeInfo {
+ // Lower-case ASCII scheme name.
+ std::string scheme_name;
+
+ // A scheme that is subject to URL canonicalization and parsing rules as
+ // defined in the Common Internet Scheme Syntax RFC 1738 Section 3.1
+ // available at http://www.ietf.org/rfc/rfc1738.txt.
+ // This value is not registered with Blink.
+ bool is_standard;
+
+ // A scheme that will be treated the same as "file". For example, normal
+ // pages cannot link to or access URLs of this scheme.
+ bool is_local;
+
+ // A scheme that can only be displayed from other content hosted with the
+ // same scheme. For example, pages in other origins cannot create iframes or
+ // hyperlinks to URLs with the scheme. For schemes that must be accessible
+ // from other schemes set this value to false, set |is_cors_enabled| to
+ // true, and use CORS "Access-Control-Allow-Origin" headers to further
+ // restrict access.
+ // This value is registered with Blink only.
+ bool is_display_isolated;
+
+ // A scheme that will be treated the same as "https". For example, loading
+ // this scheme from other secure schemes will not trigger mixed content
+ // warnings.
+ bool is_secure;
+
+ // A scheme that can be sent CORS requests. This value should be true in
+ // most cases where |is_standard| is true.
+ bool is_cors_enabled;
+
+ // A scheme that can bypass Content-Security-Policy (CSP) checks. This value
+ // should be false in most cases where |is_standard| is true.
+ bool is_csp_bypassing;
+
+ // A scheme that can perform fetch request.
+ bool is_fetch_enabled;
+};
+
+#endif // CEF_LIBCEF_COMMON_NET_SCHEME_INFO_H_
diff --git a/libcef/common/net/scheme_registration.cc b/libcef/common/net/scheme_registration.cc
new file mode 100644
index 00000000..75569767
--- /dev/null
+++ b/libcef/common/net/scheme_registration.cc
@@ -0,0 +1,100 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "libcef/common/net/scheme_registration.h"
+
+#include "libcef/common/app_manager.h"
+#include "libcef/common/net/scheme_info.h"
+#include "libcef/features/runtime.h"
+
+#include "base/containers/contains.h"
+#include "content/public/common/url_constants.h"
+#include "extensions/common/constants.h"
+#include "url/url_constants.h"
+#include "url/url_util.h"
+
+namespace scheme {
+
+void AddInternalSchemes(content::ContentClient::Schemes* schemes) {
+ if (!cef::IsAlloyRuntimeEnabled()) {
+ return;
+ }
+
+ // chrome: and chrome-devtools: schemes are registered in
+ // RenderThreadImpl::RegisterSchemes().
+ // Access restrictions for chrome-extension: and chrome-extension-resource:
+ // schemes will be applied in AlloyContentRendererClient::WillSendRequest().
+ static CefSchemeInfo internal_schemes[] = {
+ {
+ extensions::kExtensionScheme, true, /* is_standard */
+ false, /* is_local */
+ false, /* is_display_isolated */
+ true, /* is_secure */
+ true, /* is_cors_enabled */
+ true, /* is_csp_bypassing */
+ },
+ };
+
+ // The |is_display_isolated| value is excluded here because it's registered
+ // with Blink only.
+ for (size_t i = 0; i < sizeof(internal_schemes) / sizeof(internal_schemes[0]);
+ ++i) {
+ if (internal_schemes[i].is_standard) {
+ schemes->standard_schemes.push_back(internal_schemes[i].scheme_name);
+ }
+ if (internal_schemes[i].is_local) {
+ schemes->local_schemes.push_back(internal_schemes[i].scheme_name);
+ }
+ if (internal_schemes[i].is_secure) {
+ schemes->secure_schemes.push_back(internal_schemes[i].scheme_name);
+ }
+ if (internal_schemes[i].is_cors_enabled) {
+ schemes->cors_enabled_schemes.push_back(internal_schemes[i].scheme_name);
+ }
+ if (internal_schemes[i].is_csp_bypassing) {
+ schemes->csp_bypassing_schemes.push_back(internal_schemes[i].scheme_name);
+ }
+ CefAppManager::Get()->AddCustomScheme(&internal_schemes[i]);
+ }
+}
+
+bool IsInternalHandledScheme(const std::string& scheme) {
+ static const char* schemes[] = {
+ url::kAboutScheme,
+ url::kBlobScheme,
+ content::kChromeDevToolsScheme,
+ content::kChromeUIScheme,
+ content::kChromeUIUntrustedScheme,
+ url::kDataScheme,
+ extensions::kExtensionScheme,
+ url::kFileScheme,
+ url::kFileSystemScheme,
+ url::kHttpScheme,
+ url::kHttpsScheme,
+ url::kJavaScriptScheme,
+ url::kWsScheme,
+ url::kWssScheme,
+ };
+
+ for (size_t i = 0; i < sizeof(schemes) / sizeof(schemes[0]); ++i) {
+ if (scheme == schemes[i]) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool IsStandardScheme(const std::string& scheme) {
+ url::Component scheme_comp(0, scheme.length());
+ return url::IsStandard(scheme.c_str(), scheme_comp);
+}
+
+// Should return the same value as SecurityOrigin::isLocal and
+// SchemeRegistry::shouldTreatURLSchemeAsCorsEnabled.
+bool IsCorsEnabledScheme(const std::string& scheme) {
+ return base::Contains(url::GetCorsEnabledSchemes(), scheme);
+}
+
+} // namespace scheme
diff --git a/libcef/common/net/scheme_registration.h b/libcef/common/net/scheme_registration.h
new file mode 100644
index 00000000..dcbdbb67
--- /dev/null
+++ b/libcef/common/net/scheme_registration.h
@@ -0,0 +1,30 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_COMMON_NET_SCHEME_REGISTRATION_H_
+#define CEF_LIBCEF_COMMON_NET_SCHEME_REGISTRATION_H_
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include "content/public/common/content_client.h"
+
+namespace scheme {
+
+// Add internal schemes.
+void AddInternalSchemes(content::ContentClient::Schemes* schemes);
+
+// Returns true if the specified |scheme| is handled internally.
+bool IsInternalHandledScheme(const std::string& scheme);
+
+// Returns true if the specified |scheme| is a registered standard scheme.
+bool IsStandardScheme(const std::string& scheme);
+
+// Returns true if the specified |scheme| is a registered CORS enabled scheme.
+bool IsCorsEnabledScheme(const std::string& scheme);
+
+} // namespace scheme
+
+#endif // CEF_LIBCEF_COMMON_NET_SCHEME_REGISTRATION_H_
diff --git a/libcef/common/net/url_util.cc b/libcef/common/net/url_util.cc
new file mode 100644
index 00000000..710601d8
--- /dev/null
+++ b/libcef/common/net/url_util.cc
@@ -0,0 +1,42 @@
+// Copyright (c) 2021 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "libcef/common/net/url_util.h"
+
+#include "base/logging.h"
+#include "components/url_formatter/url_fixer.h"
+
+namespace url_util {
+
+GURL MakeGURL(const CefString& url, bool fixup) {
+ GURL gurl = GURL(url.ToString());
+ if (!url.empty() && !gurl.is_valid() && !gurl.has_scheme()) {
+ std::string fixed_scheme(url::kHttpScheme);
+ fixed_scheme.append(url::kStandardSchemeSeparator);
+ std::string new_url = url;
+ new_url.insert(0, fixed_scheme);
+ gurl = GURL(new_url);
+ }
+ if (fixup) {
+ FixupGURL(gurl);
+ }
+ return gurl;
+}
+
+bool FixupGURL(GURL& gurl) {
+ if (!gurl.is_empty()) {
+ GURL fixup_url =
+ url_formatter::FixupURL(gurl.possibly_invalid_spec(), std::string());
+ if (fixup_url.is_valid()) {
+ gurl = fixup_url;
+ } else {
+ LOG(ERROR) << "Invalid URL: " << gurl.possibly_invalid_spec();
+ gurl = GURL();
+ return false;
+ }
+ }
+ return true;
+}
+
+} // namespace url_util
diff --git a/libcef/common/net/url_util.h b/libcef/common/net/url_util.h
new file mode 100644
index 00000000..d5c0112c
--- /dev/null
+++ b/libcef/common/net/url_util.h
@@ -0,0 +1,27 @@
+// Copyright (c) 2021 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_COMMON_NET_URL_UTIL_H_
+#define CEF_LIBCEF_COMMON_NET_URL_UTIL_H_
+#pragma once
+
+#include "include/cef_base.h"
+
+class GURL;
+
+namespace url_util {
+
+// Convert |url| to a GURL, adding a scheme prefix if necessary.
+// If |fixup| is true then FixupGURL() will also be called.
+GURL MakeGURL(const CefString& url, bool fixup);
+
+// Fix common problems with user-typed text. Among other things, this:
+// - Converts absolute file paths to "file://" URLs.
+// - Normalizes "about:" and "chrome:" to "chrome://" URLs
+// Modifies |gurl| if necessary. Returns true if |gurl| is empty or valid.
+bool FixupGURL(GURL& gurl);
+
+} // namespace url_util
+
+#endif // CEF_LIBCEF_COMMON_NET_URL_UTIL_H_
diff --git a/libcef/common/net_service/net_service_util.cc b/libcef/common/net_service/net_service_util.cc
new file mode 100644
index 00000000..d8cd3eb8
--- /dev/null
+++ b/libcef/common/net_service/net_service_util.cc
@@ -0,0 +1,287 @@
+// Copyright (c) 2019 The Chromium Embedded Framework Authors. Portions
+// Copyright (c) 2018 The Chromium Authors. All rights reserved. Use of this
+// source code is governed by a BSD-style license that can be found in the
+// LICENSE file.
+
+#include "libcef/common/net_service/net_service_util.h"
+
+#include "include/internal/cef_time_wrappers.h"
+#include "libcef/common/time_util.h"
+
+#include <set>
+
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "net/cookies/canonical_cookie.h"
+#include "net/cookies/cookie_util.h"
+#include "net/cookies/parsed_cookie.h"
+#include "net/http/http_request_headers.h"
+#include "net/http/http_response_headers.h"
+#include "net/http/http_status_code.h"
+#include "net/url_request/redirect_info.h"
+#include "net/url_request/redirect_util.h"
+#include "net/url_request/referrer_policy.h"
+#include "net/url_request/url_request.h"
+#include "services/network/public/cpp/resource_request.h"
+
+namespace net_service {
+
+namespace {
+
+// Determine the cookie domain to use for setting the specified cookie.
+// From net/cookies/canonical_cookie.cc.
+bool GetCookieDomain(const GURL& url,
+ const net::ParsedCookie& pc,
+ std::string* result) {
+ std::string domain_string;
+ if (pc.HasDomain()) {
+ domain_string = pc.Domain();
+ }
+ net::CookieInclusionStatus status;
+ return net::cookie_util::GetCookieDomainWithString(url, domain_string, status,
+ result);
+}
+
+cef_cookie_same_site_t MakeCefCookieSameSite(net::CookieSameSite value) {
+ switch (value) {
+ case net::CookieSameSite::UNSPECIFIED:
+ return CEF_COOKIE_SAME_SITE_UNSPECIFIED;
+ case net::CookieSameSite::NO_RESTRICTION:
+ return CEF_COOKIE_SAME_SITE_NO_RESTRICTION;
+ case net::CookieSameSite::LAX_MODE:
+ return CEF_COOKIE_SAME_SITE_LAX_MODE;
+ case net::CookieSameSite::STRICT_MODE:
+ return CEF_COOKIE_SAME_SITE_STRICT_MODE;
+ }
+}
+
+cef_cookie_priority_t MakeCefCookiePriority(net::CookiePriority value) {
+ switch (value) {
+ case net::COOKIE_PRIORITY_LOW:
+ return CEF_COOKIE_PRIORITY_LOW;
+ case net::COOKIE_PRIORITY_MEDIUM:
+ return CEF_COOKIE_PRIORITY_MEDIUM;
+ case net::COOKIE_PRIORITY_HIGH:
+ return CEF_COOKIE_PRIORITY_HIGH;
+ }
+}
+
+} // namespace
+
+const char kHTTPLocationHeaderName[] = "Location";
+const char kHTTPSetCookieHeaderName[] = "Set-Cookie";
+
+const char kContentTypeApplicationFormURLEncoded[] =
+ "application/x-www-form-urlencoded";
+
+std::string MakeStatusLine(int status_code,
+ const std::string& status_text,
+ bool for_replacement) {
+ std::string status("HTTP/1.1 ");
+ status.append(base::NumberToString(status_code));
+ status.append(" ");
+
+ if (status_text.empty()) {
+ const std::string& text =
+ net::GetHttpReasonPhrase(static_cast<net::HttpStatusCode>(status_code));
+ DCHECK(!text.empty());
+ status.append(text);
+ } else {
+ status.append(status_text);
+ }
+
+ if (!for_replacement) {
+ // The HttpResponseHeaders constructor expects its input string to be
+ // terminated by two NULs.
+ status.append("\0\0", 2);
+ }
+ return status;
+}
+
+std::string MakeContentTypeValue(const std::string& mime_type,
+ const std::string& charset) {
+ DCHECK(!mime_type.empty());
+ std::string value = mime_type;
+ if (!charset.empty()) {
+ value.append("; charset=");
+ value.append(charset);
+ }
+ return value;
+}
+
+scoped_refptr<net::HttpResponseHeaders> MakeResponseHeaders(
+ int status_code,
+ const std::string& status_text,
+ const std::string& mime_type,
+ const std::string& charset,
+ int64_t content_length,
+ const std::multimap<std::string, std::string>& extra_headers,
+ bool allow_existing_header_override) {
+ if (status_code <= 0) {
+ status_code = 200;
+ }
+
+ auto headers = WrapRefCounted(new net::HttpResponseHeaders(
+ MakeStatusLine(status_code, status_text, false)));
+
+ // Track the headers that have already been set. Perform all comparisons in
+ // lowercase.
+ std::set<std::string> set_headers_lowercase;
+ if ((status_code >= 200 && status_code < 300) &&
+ status_code != net::HTTP_NO_CONTENT &&
+ status_code != net::HTTP_RESET_CONTENT) {
+ if (!mime_type.empty()) {
+ headers->AddHeader(net::HttpRequestHeaders::kContentType,
+ MakeContentTypeValue(mime_type, charset));
+ set_headers_lowercase.insert(
+ base::ToLowerASCII(net::HttpRequestHeaders::kContentType));
+ }
+
+ if (content_length >= 0) {
+ headers->AddHeader(net::HttpRequestHeaders::kContentLength,
+ base::NumberToString(content_length));
+ set_headers_lowercase.insert(
+ base::ToLowerASCII(net::HttpRequestHeaders::kContentLength));
+ }
+ }
+
+ for (const auto& pair : extra_headers) {
+ if (!set_headers_lowercase.empty()) {
+ // Check if the header has already been set.
+ const std::string& name_lowercase = base::ToLowerASCII(pair.first);
+ if (set_headers_lowercase.find(name_lowercase) !=
+ set_headers_lowercase.end()) {
+ if (allow_existing_header_override) {
+ headers->RemoveHeader(pair.first);
+ } else {
+ continue;
+ }
+ }
+ }
+
+ headers->AddHeader(pair.first, pair.second);
+ }
+
+ return headers;
+}
+
+net::RedirectInfo MakeRedirectInfo(const network::ResourceRequest& request,
+ const net::HttpResponseHeaders* headers,
+ const GURL& new_location,
+ int status_code) {
+ bool insecure_scheme_was_upgraded = false;
+
+ GURL location = new_location;
+ if (status_code == 0) {
+ status_code = net::HTTP_TEMPORARY_REDIRECT;
+ }
+
+ // If this a redirect to HTTP of a request that had the
+ // 'upgrade-insecure-requests' policy set, upgrade it to HTTPS.
+ if (request.upgrade_if_insecure) {
+ if (location.SchemeIs("http")) {
+ insecure_scheme_was_upgraded = true;
+ GURL::Replacements replacements;
+ replacements.SetSchemeStr("https");
+ location = location.ReplaceComponents(replacements);
+ }
+ }
+
+ auto first_party_url_policy =
+ request.update_first_party_url_on_redirect
+ ? net::RedirectInfo::FirstPartyURLPolicy::UPDATE_URL_ON_REDIRECT
+ : net::RedirectInfo::FirstPartyURLPolicy::NEVER_CHANGE_URL;
+ return net::RedirectInfo::ComputeRedirectInfo(
+ request.method, request.url, request.site_for_cookies,
+ first_party_url_policy, request.referrer_policy, request.referrer.spec(),
+ status_code, location,
+ net::RedirectUtil::GetReferrerPolicyHeader(headers),
+ insecure_scheme_was_upgraded);
+}
+
+net::CookieSameSite MakeCookieSameSite(cef_cookie_same_site_t value) {
+ switch (value) {
+ case CEF_COOKIE_SAME_SITE_UNSPECIFIED:
+ return net::CookieSameSite::UNSPECIFIED;
+ case CEF_COOKIE_SAME_SITE_NO_RESTRICTION:
+ return net::CookieSameSite::NO_RESTRICTION;
+ case CEF_COOKIE_SAME_SITE_LAX_MODE:
+ return net::CookieSameSite::LAX_MODE;
+ case CEF_COOKIE_SAME_SITE_STRICT_MODE:
+ return net::CookieSameSite::STRICT_MODE;
+ }
+}
+
+net::CookiePriority MakeCookiePriority(cef_cookie_priority_t value) {
+ switch (value) {
+ case CEF_COOKIE_PRIORITY_LOW:
+ return net::COOKIE_PRIORITY_LOW;
+ case CEF_COOKIE_PRIORITY_MEDIUM:
+ return net::COOKIE_PRIORITY_MEDIUM;
+ case CEF_COOKIE_PRIORITY_HIGH:
+ return net::COOKIE_PRIORITY_HIGH;
+ }
+}
+
+bool MakeCefCookie(const net::CanonicalCookie& cc, CefCookie& cookie) {
+ CefString(&cookie.name).FromString(cc.Name());
+ CefString(&cookie.value).FromString(cc.Value());
+ CefString(&cookie.domain).FromString(cc.Domain());
+ CefString(&cookie.path).FromString(cc.Path());
+ cookie.secure = cc.IsSecure();
+ cookie.httponly = cc.IsHttpOnly();
+ cookie.creation = CefBaseTime(cc.CreationDate());
+ cookie.last_access = CefBaseTime(cc.LastAccessDate());
+ cookie.has_expires = cc.IsPersistent();
+ if (cookie.has_expires) {
+ cookie.expires = CefBaseTime(cc.ExpiryDate());
+ }
+ cookie.same_site = MakeCefCookieSameSite(cc.SameSite());
+ cookie.priority = MakeCefCookiePriority(cc.Priority());
+
+ return true;
+}
+
+bool MakeCefCookie(const GURL& url,
+ const std::string& cookie_line,
+ CefCookie& cookie) {
+ // Parse the cookie.
+ net::ParsedCookie pc(cookie_line);
+ if (!pc.IsValid()) {
+ return false;
+ }
+
+ std::string cookie_domain;
+ if (!GetCookieDomain(url, pc, &cookie_domain)) {
+ return false;
+ }
+
+ std::string path_string;
+ if (pc.HasPath()) {
+ path_string = pc.Path();
+ }
+ std::string cookie_path =
+ net::CanonicalCookie::CanonPathWithString(url, path_string);
+ base::Time creation_time = base::Time::Now();
+ base::Time cookie_expires =
+ net::CanonicalCookie::ParseExpiration(pc, creation_time, creation_time);
+
+ CefString(&cookie.name).FromString(pc.Name());
+ CefString(&cookie.value).FromString(pc.Value());
+ CefString(&cookie.domain).FromString(cookie_domain);
+ CefString(&cookie.path).FromString(cookie_path);
+ cookie.secure = pc.IsSecure();
+ cookie.httponly = pc.IsHttpOnly();
+ cookie.creation = CefBaseTime(creation_time);
+ cookie.last_access = CefBaseTime(creation_time);
+ cookie.has_expires = !cookie_expires.is_null();
+ if (cookie.has_expires) {
+ cookie.expires = CefBaseTime(cookie_expires);
+ }
+ cookie.same_site = MakeCefCookieSameSite(pc.SameSite());
+ cookie.priority = MakeCefCookiePriority(pc.Priority());
+
+ return true;
+}
+
+} // namespace net_service \ No newline at end of file
diff --git a/libcef/common/net_service/net_service_util.h b/libcef/common/net_service/net_service_util.h
new file mode 100644
index 00000000..0eaa62d5
--- /dev/null
+++ b/libcef/common/net_service/net_service_util.h
@@ -0,0 +1,76 @@
+// Copyright (c) 2019 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_COMMON_NET_SERVICE_NET_SERVICE_UTIL_H_
+#define CEF_LIBCEF_COMMON_NET_SERVICE_NET_SERVICE_UTIL_H_
+
+#include <map>
+#include <string>
+
+#include "include/internal/cef_types_wrappers.h"
+
+#include "base/memory/scoped_refptr.h"
+#include "net/cookies/cookie_constants.h"
+
+namespace net {
+class CanonicalCookie;
+class HttpResponseHeaders;
+struct RedirectInfo;
+} // namespace net
+
+namespace network {
+struct ResourceRequest;
+} // namespace network
+
+class GURL;
+
+namespace net_service {
+
+// HTTP header names.
+extern const char kHTTPLocationHeaderName[];
+extern const char kHTTPSetCookieHeaderName[];
+
+// HTTP header values.
+extern const char kContentTypeApplicationFormURLEncoded[];
+
+// Make an HTTP response status line.
+// Set |for_replacement| to true if the result will be passed to
+// HttpResponseHeaders::ReplaceStatusLine and false if the result will
+// be passed to the HttpResponseHeaders constructor.
+std::string MakeStatusLine(int status_code,
+ const std::string& status_text,
+ bool for_replacement);
+
+// Make an HTTP Content-Type response header value.
+std::string MakeContentTypeValue(const std::string& mime_type,
+ const std::string& charset);
+
+// Make a new HttpResponseHeaders object.
+scoped_refptr<net::HttpResponseHeaders> MakeResponseHeaders(
+ int status_code,
+ const std::string& status_text,
+ const std::string& mime_type,
+ const std::string& charset,
+ int64_t content_length,
+ const std::multimap<std::string, std::string>& extra_headers,
+ bool allow_existing_header_override);
+
+// Make a RedirectInfo structure.
+net::RedirectInfo MakeRedirectInfo(const network::ResourceRequest& request,
+ const net::HttpResponseHeaders* headers,
+ const GURL& new_location,
+ int status_code);
+
+// Populate |cookie|. Returns true on success.
+bool MakeCefCookie(const net::CanonicalCookie& cc, CefCookie& cookie);
+bool MakeCefCookie(const GURL& url,
+ const std::string& cookie_line,
+ CefCookie& cookie);
+
+net::CookieSameSite MakeCookieSameSite(cef_cookie_same_site_t value);
+net::CookiePriority MakeCookiePriority(cef_cookie_priority_t value);
+
+} // namespace net_service
+
+#endif // CEF_LIBCEF_COMMON_NET_SERVICE_NET_SERVICE_UTIL_H_
diff --git a/libcef/common/parser_impl.cc b/libcef/common/parser_impl.cc
new file mode 100644
index 00000000..c0e25c8f
--- /dev/null
+++ b/libcef/common/parser_impl.cc
@@ -0,0 +1,169 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#include <sstream>
+
+#include "include/cef_parser.h"
+
+#include "base/base64.h"
+#include "base/strings/escape.h"
+#include "base/threading/thread_restrictions.h"
+#include "components/url_formatter/elide_url.h"
+#include "net/base/mime_util.h"
+#include "url/gurl.h"
+
+bool CefResolveURL(const CefString& base_url,
+ const CefString& relative_url,
+ CefString& resolved_url) {
+ GURL base_gurl(base_url.ToString());
+ if (!base_gurl.is_valid()) {
+ return false;
+ }
+
+ GURL combined_gurl = base_gurl.Resolve(relative_url.ToString());
+ if (!combined_gurl.is_valid()) {
+ return false;
+ }
+
+ resolved_url = combined_gurl.spec();
+ return true;
+}
+
+bool CefParseURL(const CefString& url, CefURLParts& parts) {
+ GURL gurl(url.ToString());
+ if (!gurl.is_valid()) {
+ return false;
+ }
+
+ CefString(&parts.spec).FromString(gurl.spec());
+ CefString(&parts.scheme).FromString(gurl.scheme());
+ CefString(&parts.username).FromString(gurl.username());
+ CefString(&parts.password).FromString(gurl.password());
+ CefString(&parts.host).FromString(gurl.host());
+ CefString(&parts.origin).FromString(gurl.DeprecatedGetOriginAsURL().spec());
+ CefString(&parts.port).FromString(gurl.port());
+ CefString(&parts.path).FromString(gurl.path());
+ CefString(&parts.query).FromString(gurl.query());
+ CefString(&parts.fragment).FromString(gurl.ref());
+
+ return true;
+}
+
+bool CefCreateURL(const CefURLParts& parts, CefString& url) {
+ std::string spec = CefString(parts.spec.str, parts.spec.length, false);
+ std::string scheme = CefString(parts.scheme.str, parts.scheme.length, false);
+ std::string username =
+ CefString(parts.username.str, parts.username.length, false);
+ std::string password =
+ CefString(parts.password.str, parts.password.length, false);
+ std::string host = CefString(parts.host.str, parts.host.length, false);
+ std::string port = CefString(parts.port.str, parts.port.length, false);
+ std::string path = CefString(parts.path.str, parts.path.length, false);
+ std::string query = CefString(parts.query.str, parts.query.length, false);
+ std::string fragment =
+ CefString(parts.fragment.str, parts.fragment.length, false);
+
+ GURL gurl;
+ if (!spec.empty()) {
+ gurl = GURL(spec);
+ } else if (!scheme.empty() && !host.empty()) {
+ std::stringstream ss;
+ ss << scheme << "://";
+ if (!username.empty()) {
+ ss << username;
+ if (!password.empty()) {
+ ss << ":" << password;
+ }
+ ss << "@";
+ }
+ ss << host;
+ if (!port.empty()) {
+ ss << ":" << port;
+ }
+ if (!path.empty()) {
+ ss << path;
+ }
+ if (!query.empty()) {
+ ss << "?" << query;
+ }
+ if (!fragment.empty()) {
+ ss << "#" << fragment;
+ }
+ gurl = GURL(ss.str());
+ }
+
+ if (gurl.is_valid()) {
+ url = gurl.spec();
+ return true;
+ }
+
+ return false;
+}
+
+CefString CefFormatUrlForSecurityDisplay(const CefString& origin_url) {
+ return url_formatter::FormatUrlForSecurityDisplay(
+ GURL(origin_url.ToString()));
+}
+
+CefString CefGetMimeType(const CefString& extension) {
+ // Requests should not block on the disk! On POSIX this goes to disk.
+ // http://code.google.com/p/chromium/issues/detail?id=59849
+ base::ScopedAllowBlockingForTesting allow_blocking;
+
+ std::string mime_type;
+ net::GetMimeTypeFromExtension(extension, &mime_type);
+ return mime_type;
+}
+
+void CefGetExtensionsForMimeType(const CefString& mime_type,
+ std::vector<CefString>& extensions) {
+ using VectorType = std::vector<base::FilePath::StringType>;
+ VectorType ext;
+ net::GetExtensionsForMimeType(mime_type, &ext);
+ VectorType::const_iterator it = ext.begin();
+ for (; it != ext.end(); ++it) {
+ extensions.push_back(*it);
+ }
+}
+
+CefString CefBase64Encode(const void* data, size_t data_size) {
+ if (data_size == 0) {
+ return CefString();
+ }
+
+ base::StringPiece input(static_cast<const char*>(data), data_size);
+ std::string output;
+ base::Base64Encode(input, &output);
+ return output;
+}
+
+CefRefPtr<CefBinaryValue> CefBase64Decode(const CefString& data) {
+ if (data.size() == 0) {
+ return nullptr;
+ }
+
+ const std::string& input = data;
+ std::string output;
+ if (base::Base64Decode(input, &output)) {
+ return CefBinaryValue::Create(output.data(), output.size());
+ }
+ return nullptr;
+}
+
+CefString CefURIEncode(const CefString& text, bool use_plus) {
+ return base::EscapeQueryParamValue(text.ToString(), use_plus);
+}
+
+CefString CefURIDecode(const CefString& text,
+ bool convert_to_utf8,
+ cef_uri_unescape_rule_t unescape_rule) {
+ const base::UnescapeRule::Type type =
+ static_cast<base::UnescapeRule::Type>(unescape_rule);
+ if (convert_to_utf8) {
+ return base::UnescapeAndDecodeUTF8URLComponentWithAdjustments(
+ text.ToString(), type, nullptr);
+ } else {
+ return base::UnescapeURLComponent(text.ToString(), type);
+ }
+}
diff --git a/libcef/common/process_message_impl.cc b/libcef/common/process_message_impl.cc
new file mode 100644
index 00000000..e90ef83a
--- /dev/null
+++ b/libcef/common/process_message_impl.cc
@@ -0,0 +1,65 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "libcef/common/process_message_impl.h"
+
+#include <memory>
+
+#include "libcef/common/values_impl.h"
+
+#include "base/logging.h"
+
+// static
+CefRefPtr<CefProcessMessage> CefProcessMessage::Create(const CefString& name) {
+ return new CefProcessMessageImpl(name, CefListValue::Create());
+}
+
+CefProcessMessageImpl::CefProcessMessageImpl(const CefString& name,
+ CefRefPtr<CefListValue> arguments)
+ : name_(name), arguments_(arguments) {
+ DCHECK(!name_.empty());
+ DCHECK(arguments_ && arguments_->IsValid());
+}
+
+CefProcessMessageImpl::CefProcessMessageImpl(const CefString& name,
+ base::Value::List arguments,
+ bool read_only)
+ : name_(name) {
+ DCHECK(!name_.empty());
+
+ arguments_ = new CefListValueImpl(std::move(arguments), read_only);
+}
+
+CefProcessMessageImpl::~CefProcessMessageImpl() = default;
+
+base::Value::List CefProcessMessageImpl::TakeArgumentList() {
+ DCHECK(IsValid());
+ CefListValueImpl* value_impl =
+ static_cast<CefListValueImpl*>(arguments_.get());
+ auto value = value_impl->CopyOrDetachValue(nullptr);
+ return std::move(value->GetList());
+}
+
+bool CefProcessMessageImpl::IsValid() {
+ return arguments_->IsValid();
+}
+
+bool CefProcessMessageImpl::IsReadOnly() {
+ return arguments_->IsReadOnly();
+}
+
+CefRefPtr<CefProcessMessage> CefProcessMessageImpl::Copy() {
+ if (!IsValid()) {
+ return nullptr;
+ }
+ return new CefProcessMessageImpl(name_, arguments_->Copy());
+}
+
+CefString CefProcessMessageImpl::GetName() {
+ return name_;
+}
+
+CefRefPtr<CefListValue> CefProcessMessageImpl::GetArgumentList() {
+ return arguments_;
+}
diff --git a/libcef/common/process_message_impl.h b/libcef/common/process_message_impl.h
new file mode 100644
index 00000000..eadeca18
--- /dev/null
+++ b/libcef/common/process_message_impl.h
@@ -0,0 +1,54 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_COMMON_PROCESS_MESSAGE_IMPL_H_
+#define CEF_LIBCEF_COMMON_PROCESS_MESSAGE_IMPL_H_
+#pragma once
+
+#include "include/cef_process_message.h"
+
+#include "base/values.h"
+
+// CefProcessMessage implementation.
+class CefProcessMessageImpl : public CefProcessMessage {
+ public:
+ // Constructor for referencing existing |arguments|.
+ CefProcessMessageImpl(const CefString& name,
+ CefRefPtr<CefListValue> arguments);
+
+ // Constructor for creating a new CefListValue that takes ownership of
+ // |arguments|.
+ CefProcessMessageImpl(const CefString& name,
+ base::Value::List arguments,
+ bool read_only);
+
+ CefProcessMessageImpl(const CefProcessMessageImpl&) = delete;
+ CefProcessMessageImpl& operator=(const CefProcessMessageImpl&) = delete;
+
+ ~CefProcessMessageImpl() override;
+
+ // Transfer ownership of the underlying argument list to the caller, or create
+ // a copy if the argument list is already owned by something else.
+ // TODO: Pass by reference instead of ownership if/when Mojo adds support
+ // for that.
+ [[nodiscard]] base::Value::List TakeArgumentList();
+
+ // CefProcessMessage methods.
+ bool IsValid() override;
+ bool IsReadOnly() override;
+ CefRefPtr<CefProcessMessage> Copy() override;
+ CefString GetName() override;
+ CefRefPtr<CefListValue> GetArgumentList() override;
+ CefRefPtr<CefSharedMemoryRegion> GetSharedMemoryRegion() override {
+ return nullptr;
+ }
+
+ private:
+ const CefString name_;
+ CefRefPtr<CefListValue> arguments_;
+
+ IMPLEMENT_REFCOUNTING(CefProcessMessageImpl);
+};
+
+#endif // CEF_LIBCEF_COMMON_PROCESS_MESSAGE_IMPL_H_
diff --git a/libcef/common/process_message_smr_impl.cc b/libcef/common/process_message_smr_impl.cc
new file mode 100644
index 00000000..4e04eb57
--- /dev/null
+++ b/libcef/common/process_message_smr_impl.cc
@@ -0,0 +1,90 @@
+// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "libcef/common/process_message_smr_impl.h"
+
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/memory/shared_memory_mapping.h"
+
+namespace {
+
+class CefSharedMemoryRegionImpl final : public CefSharedMemoryRegion {
+ public:
+ CefSharedMemoryRegionImpl(base::ReadOnlySharedMemoryMapping&& mapping)
+ : mapping_(std::move(mapping)) {}
+ CefSharedMemoryRegionImpl(const CefSharedMemoryRegionImpl&) = delete;
+ CefSharedMemoryRegionImpl& operator=(const CefSharedMemoryRegionImpl&) =
+ delete;
+
+ // CefSharedMemoryRegion methods
+ bool IsValid() override { return mapping_.IsValid(); }
+ size_t Size() override { return IsValid() ? mapping_.size() : 0; }
+ const void* Memory() override { return mapping_.memory(); }
+
+ private:
+ base::ReadOnlySharedMemoryMapping mapping_;
+ IMPLEMENT_REFCOUNTING(CefSharedMemoryRegionImpl);
+};
+
+} // namespace
+
+CefProcessMessageSMRImpl::CefProcessMessageSMRImpl(
+ const CefString& name,
+ base::ReadOnlySharedMemoryRegion&& region)
+ : name_(name), region_(std::move(region)) {
+ DCHECK(!name_.empty());
+ DCHECK(region_.IsValid());
+}
+
+CefProcessMessageSMRImpl::~CefProcessMessageSMRImpl() = default;
+
+bool CefProcessMessageSMRImpl::IsValid() {
+ return region_.IsValid();
+}
+
+CefString CefProcessMessageSMRImpl::GetName() {
+ return name_;
+}
+
+CefRefPtr<CefSharedMemoryRegion>
+CefProcessMessageSMRImpl::GetSharedMemoryRegion() {
+ return new CefSharedMemoryRegionImpl(region_.Map());
+}
+
+base::ReadOnlySharedMemoryRegion CefProcessMessageSMRImpl::TakeRegion() {
+ return std::move(region_);
+}
+
+// static
+CefRefPtr<CefSharedProcessMessageBuilder>
+CefSharedProcessMessageBuilder::Create(const CefString& name,
+ size_t byte_size) {
+ return new CefSharedProcessMessageBuilderImpl(name, byte_size);
+}
+
+CefSharedProcessMessageBuilderImpl::CefSharedProcessMessageBuilderImpl(
+ const CefString& name,
+ size_t byte_size)
+ : name_(name),
+ region_(base::ReadOnlySharedMemoryRegion::Create(byte_size)) {}
+
+bool CefSharedProcessMessageBuilderImpl::IsValid() {
+ return region_.region.IsValid() && region_.mapping.IsValid();
+}
+
+size_t CefSharedProcessMessageBuilderImpl::Size() {
+ return !IsValid() ? 0 : region_.mapping.size();
+}
+
+void* CefSharedProcessMessageBuilderImpl::Memory() {
+ return !IsValid() ? nullptr : region_.mapping.memory();
+}
+
+CefRefPtr<CefProcessMessage> CefSharedProcessMessageBuilderImpl::Build() {
+ if (!IsValid()) {
+ return nullptr;
+ }
+ return new CefProcessMessageSMRImpl(name_, std::move(region_.region));
+} \ No newline at end of file
diff --git a/libcef/common/process_message_smr_impl.h b/libcef/common/process_message_smr_impl.h
new file mode 100644
index 00000000..abc2a9f6
--- /dev/null
+++ b/libcef/common/process_message_smr_impl.h
@@ -0,0 +1,58 @@
+// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_COMMON_PROCESS_MESSAGE_SMR_IMPL_H_
+#define CEF_LIBCEF_COMMON_PROCESS_MESSAGE_SMR_IMPL_H_
+#pragma once
+
+#include "include/cef_process_message.h"
+#include "include/cef_shared_process_message_builder.h"
+
+#include "base/memory/read_only_shared_memory_region.h"
+
+class CefProcessMessageSMRImpl final : public CefProcessMessage {
+ public:
+ CefProcessMessageSMRImpl(const CefString& name,
+ base::ReadOnlySharedMemoryRegion&& region);
+ CefProcessMessageSMRImpl(const CefProcessMessageSMRImpl&) = delete;
+ CefProcessMessageSMRImpl& operator=(const CefProcessMessageSMRImpl&) = delete;
+ ~CefProcessMessageSMRImpl() override;
+
+ // CefProcessMessage methods.
+ bool IsValid() override;
+ bool IsReadOnly() override { return true; }
+ CefRefPtr<CefProcessMessage> Copy() override { return nullptr; }
+ CefString GetName() override;
+ CefRefPtr<CefListValue> GetArgumentList() override { return nullptr; }
+ CefRefPtr<CefSharedMemoryRegion> GetSharedMemoryRegion() override;
+ [[nodiscard]] base::ReadOnlySharedMemoryRegion TakeRegion();
+
+ private:
+ const CefString name_;
+ base::ReadOnlySharedMemoryRegion region_;
+
+ IMPLEMENT_REFCOUNTING(CefProcessMessageSMRImpl);
+};
+
+class CefSharedProcessMessageBuilderImpl final
+ : public CefSharedProcessMessageBuilder {
+ public:
+ CefSharedProcessMessageBuilderImpl(const CefString& name, size_t byte_size);
+ CefSharedProcessMessageBuilderImpl(const CefProcessMessageSMRImpl&) = delete;
+ CefSharedProcessMessageBuilderImpl& operator=(
+ const CefSharedProcessMessageBuilderImpl&) = delete;
+
+ bool IsValid() override;
+ size_t Size() override;
+ void* Memory() override;
+ CefRefPtr<CefProcessMessage> Build() override;
+
+ private:
+ const CefString name_;
+ base::MappedReadOnlyRegion region_;
+
+ IMPLEMENT_REFCOUNTING(CefSharedProcessMessageBuilderImpl);
+};
+
+#endif // CEF_LIBCEF_COMMON_PROCESS_MESSAGE_SMR_IMPL_H_
diff --git a/libcef/common/request_impl.cc b/libcef/common/request_impl.cc
new file mode 100644
index 00000000..c2dcfb17
--- /dev/null
+++ b/libcef/common/request_impl.cc
@@ -0,0 +1,1229 @@
+// Copyright (c) 2008-2009 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include <algorithm>
+#include <limits>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "libcef/common/net/http_header_utils.h"
+#include "libcef/common/net_service/net_service_util.h"
+#include "libcef/common/request_impl.h"
+
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/navigation_handle.h"
+#include "content/public/common/content_switches.h"
+#include "net/base/elements_upload_data_stream.h"
+#include "net/base/load_flags.h"
+#include "net/base/upload_bytes_element_reader.h"
+#include "net/base/upload_data_stream.h"
+#include "net/base/upload_element_reader.h"
+#include "net/base/upload_file_element_reader.h"
+#include "net/http/http_request_headers.h"
+#include "net/http/http_util.h"
+#include "net/url_request/redirect_info.h"
+#include "net/url_request/referrer_policy.h"
+#include "services/network/public/cpp/data_element.h"
+#include "services/network/public/cpp/network_switches.h"
+#include "services/network/public/cpp/resource_request.h"
+#include "services/network/public/cpp/resource_request_body.h"
+#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-shared.h"
+#include "third_party/blink/public/platform/web_http_body.h"
+#include "third_party/blink/public/platform/web_security_origin.h"
+#include "third_party/blink/public/platform/web_string.h"
+#include "third_party/blink/public/platform/web_url.h"
+#include "third_party/blink/public/platform/web_url_error.h"
+#include "third_party/blink/public/platform/web_url_request.h"
+#include "third_party/blink/public/platform/web_url_request_util.h"
+#include "third_party/blink/public/web/web_security_policy.h"
+
+namespace {
+
+const char kCacheControlDirectiveNoCache[] = "no-cache";
+const char kCacheControlDirectiveNoStore[] = "no-store";
+const char kCacheControlDirectiveOnlyIfCached[] = "only-if-cached";
+
+// Mask of values that configure the cache policy.
+const int kURCachePolicyMask =
+ (UR_FLAG_SKIP_CACHE | UR_FLAG_ONLY_FROM_CACHE | UR_FLAG_DISABLE_CACHE);
+
+// Returns the cef_urlrequest_flags_t policy specified by the Cache-Control
+// request header directives, if any. The directives are case-insensitive and
+// some have an optional argument. Multiple directives are comma-separated.
+// See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control
+// for details.
+int GetCacheControlHeaderPolicy(CefRequest::HeaderMap headerMap) {
+ std::string line;
+
+ // Extract the Cache-Control header line.
+ {
+ CefRequest::HeaderMap::const_iterator it = headerMap.begin();
+ for (; it != headerMap.end(); ++it) {
+ if (base::EqualsCaseInsensitiveASCII(
+ it->first.ToString(), net::HttpRequestHeaders::kCacheControl)) {
+ line = it->second;
+ break;
+ }
+ }
+ }
+
+ int flags = 0;
+
+ if (!line.empty()) {
+ HttpHeaderUtils::MakeASCIILower(&line);
+
+ std::vector<base::StringPiece> pieces = base::SplitStringPiece(
+ line, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+ for (const auto& piece : pieces) {
+ if (base::EqualsCaseInsensitiveASCII(piece,
+ kCacheControlDirectiveNoCache)) {
+ flags |= UR_FLAG_SKIP_CACHE;
+ } else if (base::EqualsCaseInsensitiveASCII(
+ piece, kCacheControlDirectiveOnlyIfCached)) {
+ flags |= UR_FLAG_ONLY_FROM_CACHE;
+ } else if (base::EqualsCaseInsensitiveASCII(
+ piece, kCacheControlDirectiveNoStore)) {
+ flags |= UR_FLAG_DISABLE_CACHE;
+ }
+ }
+ }
+
+ return flags;
+}
+
+// Convert cef_urlrequest_flags_t to blink::WebCachePolicy.
+blink::mojom::FetchCacheMode GetFetchCacheMode(int ur_flags) {
+ const bool skip_cache{!!(ur_flags & UR_FLAG_SKIP_CACHE)};
+ const bool only_from_cache{!!(ur_flags & UR_FLAG_ONLY_FROM_CACHE)};
+ const bool disable_cache{!!(ur_flags & UR_FLAG_DISABLE_CACHE)};
+ if (only_from_cache && (skip_cache || disable_cache)) {
+ // The request will always fail because only_from_cache and
+ // skip_cache/disable_cache are mutually exclusive.
+ return blink::mojom::FetchCacheMode::kUnspecifiedForceCacheMiss;
+ } else if (disable_cache) {
+ // This additionally implies the skip_cache behavior.
+ return blink::mojom::FetchCacheMode::kNoStore;
+ } else if (skip_cache) {
+ return blink::mojom::FetchCacheMode::kBypassCache;
+ } else if (only_from_cache) {
+ return blink::mojom::FetchCacheMode::kOnlyIfCached;
+ }
+ return blink::mojom::FetchCacheMode::kDefault;
+}
+
+// Read |headers| into |map|.
+void GetHeaderMap(const net::HttpRequestHeaders& headers,
+ CefRequest::HeaderMap& map) {
+ map.clear();
+
+ if (headers.IsEmpty()) {
+ return;
+ }
+
+ net::HttpRequestHeaders::Iterator it(headers);
+ while (it.GetNext()) {
+ const std::string& name = it.name();
+
+ // Do not include Referer in the header map.
+ if (!base::EqualsCaseInsensitiveASCII(name,
+ net::HttpRequestHeaders::kReferer)) {
+ map.insert(std::make_pair(name, it.value()));
+ }
+ };
+}
+
+// Read |source| into |map|.
+void GetHeaderMap(const CefRequest::HeaderMap& source,
+ CefRequest::HeaderMap& map) {
+ map.clear();
+
+ CefRequest::HeaderMap::const_iterator it = source.begin();
+ for (; it != source.end(); ++it) {
+ const CefString& name = it->first;
+
+ // Do not include Referer in the header map.
+ if (!base::EqualsCaseInsensitiveASCII(name.ToString(),
+ net::HttpRequestHeaders::kReferer)) {
+ map.insert(std::make_pair(name, it->second));
+ }
+ }
+}
+
+} // namespace
+
+#define CHECK_READONLY_RETURN(val) \
+ if (read_only_) { \
+ NOTREACHED() << "object is read only"; \
+ return val; \
+ }
+
+#define CHECK_READONLY_RETURN_VOID() \
+ if (read_only_) { \
+ NOTREACHED() << "object is read only"; \
+ return; \
+ }
+
+#define SETBOOLFLAG(obj, flags, method, FLAG) \
+ obj.method((flags & (FLAG)) == (FLAG))
+
+// CefRequest -----------------------------------------------------------------
+
+// static
+CefRefPtr<CefRequest> CefRequest::Create() {
+ CefRefPtr<CefRequest> request(new CefRequestImpl());
+ return request;
+}
+
+// CefRequestImpl -------------------------------------------------------------
+
+CefRequestImpl::CefRequestImpl() {
+ // Verify that our enum matches Chromium's values.
+ static_assert(static_cast<int>(REFERRER_POLICY_LAST_VALUE) ==
+ static_cast<int>(net::ReferrerPolicy::MAX),
+ "enum mismatch");
+
+ base::AutoLock lock_scope(lock_);
+ Reset();
+}
+
+bool CefRequestImpl::IsReadOnly() {
+ base::AutoLock lock_scope(lock_);
+ return read_only_;
+}
+
+CefString CefRequestImpl::GetURL() {
+ base::AutoLock lock_scope(lock_);
+ return url_.spec();
+}
+
+void CefRequestImpl::SetURL(const CefString& url) {
+ base::AutoLock lock_scope(lock_);
+ CHECK_READONLY_RETURN_VOID();
+ const GURL& new_url = GURL(url.ToString());
+ if (url_ != new_url) {
+ Changed(kChangedUrl);
+ url_ = new_url;
+ }
+}
+
+CefString CefRequestImpl::GetMethod() {
+ base::AutoLock lock_scope(lock_);
+ return method_;
+}
+
+void CefRequestImpl::SetMethod(const CefString& method) {
+ base::AutoLock lock_scope(lock_);
+ CHECK_READONLY_RETURN_VOID();
+ const std::string& new_method = method;
+ if (method_ != new_method) {
+ Changed(kChangedMethod);
+ method_ = new_method;
+ }
+}
+
+void CefRequestImpl::SetReferrer(const CefString& referrer_url,
+ ReferrerPolicy policy) {
+ base::AutoLock lock_scope(lock_);
+ CHECK_READONLY_RETURN_VOID();
+
+ const auto& sanitized_referrer = content::Referrer::SanitizeForRequest(
+ url_, content::Referrer(GURL(referrer_url.ToString()),
+ NetReferrerPolicyToBlinkReferrerPolicy(policy)));
+ const auto sanitized_policy =
+ BlinkReferrerPolicyToNetReferrerPolicy(sanitized_referrer.policy);
+
+ if (referrer_url_ != sanitized_referrer.url ||
+ referrer_policy_ != sanitized_policy) {
+ Changed(kChangedReferrer);
+ referrer_url_ = sanitized_referrer.url;
+ referrer_policy_ = sanitized_policy;
+ }
+}
+
+CefString CefRequestImpl::GetReferrerURL() {
+ base::AutoLock lock_scope(lock_);
+ return referrer_url_.spec();
+}
+
+CefRequestImpl::ReferrerPolicy CefRequestImpl::GetReferrerPolicy() {
+ base::AutoLock lock_scope(lock_);
+ return referrer_policy_;
+}
+
+CefRefPtr<CefPostData> CefRequestImpl::GetPostData() {
+ base::AutoLock lock_scope(lock_);
+ return postdata_;
+}
+
+void CefRequestImpl::SetPostData(CefRefPtr<CefPostData> postData) {
+ base::AutoLock lock_scope(lock_);
+ CHECK_READONLY_RETURN_VOID();
+ Changed(kChangedPostData);
+ postdata_ = postData;
+}
+
+void CefRequestImpl::GetHeaderMap(HeaderMap& headerMap) {
+ base::AutoLock lock_scope(lock_);
+ headerMap = headermap_;
+}
+
+void CefRequestImpl::SetHeaderMap(const HeaderMap& headerMap) {
+ base::AutoLock lock_scope(lock_);
+ CHECK_READONLY_RETURN_VOID();
+ Changed(kChangedHeaderMap);
+ ::GetHeaderMap(headerMap, headermap_);
+}
+
+CefString CefRequestImpl::GetHeaderByName(const CefString& name) {
+ base::AutoLock lock_scope(lock_);
+
+ std::string nameLower = name;
+ HttpHeaderUtils::MakeASCIILower(&nameLower);
+
+ auto it = HttpHeaderUtils::FindHeaderInMap(nameLower, headermap_);
+ if (it != headermap_.end()) {
+ return it->second;
+ }
+
+ return CefString();
+}
+
+void CefRequestImpl::SetHeaderByName(const CefString& name,
+ const CefString& value,
+ bool overwrite) {
+ base::AutoLock lock_scope(lock_);
+ CHECK_READONLY_RETURN_VOID();
+
+ const std::string& nameStr = name;
+
+ // Do not include Referer in the header map.
+ if (base::EqualsCaseInsensitiveASCII(nameStr,
+ net::HttpRequestHeaders::kReferer)) {
+ return;
+ }
+
+ Changed(kChangedHeaderMap);
+
+ // There may be multiple values, so remove any first.
+ for (auto it = headermap_.begin(); it != headermap_.end();) {
+ if (base::EqualsCaseInsensitiveASCII(it->first.ToString(), nameStr)) {
+ if (!overwrite) {
+ return;
+ }
+ it = headermap_.erase(it);
+ } else {
+ ++it;
+ }
+ }
+
+ headermap_.insert(std::make_pair(name, value));
+}
+
+void CefRequestImpl::Set(const CefString& url,
+ const CefString& method,
+ CefRefPtr<CefPostData> postData,
+ const HeaderMap& headerMap) {
+ base::AutoLock lock_scope(lock_);
+ CHECK_READONLY_RETURN_VOID();
+ const GURL& new_url = GURL(url.ToString());
+ if (url_ != new_url) {
+ Changed(kChangedUrl);
+ url_ = new_url;
+ }
+ const std::string& new_method = method;
+ if (method_ != new_method) {
+ Changed(kChangedMethod);
+ method_ = new_method;
+ }
+ if (postdata_ != postData) {
+ Changed(kChangedPostData);
+ postdata_ = postData;
+ }
+ Changed(kChangedHeaderMap);
+ ::GetHeaderMap(headerMap, headermap_);
+}
+
+int CefRequestImpl::GetFlags() {
+ base::AutoLock lock_scope(lock_);
+ return flags_;
+}
+
+void CefRequestImpl::SetFlags(int flags) {
+ base::AutoLock lock_scope(lock_);
+ CHECK_READONLY_RETURN_VOID();
+ if (flags_ != flags) {
+ Changed(kChangedFlags);
+ flags_ = flags;
+ }
+}
+
+CefString CefRequestImpl::GetFirstPartyForCookies() {
+ base::AutoLock lock_scope(lock_);
+ return site_for_cookies_.RepresentativeUrl().spec();
+}
+
+void CefRequestImpl::SetFirstPartyForCookies(const CefString& url) {
+ base::AutoLock lock_scope(lock_);
+ CHECK_READONLY_RETURN_VOID();
+ auto new_site = net::SiteForCookies::FromUrl(GURL(url.ToString()));
+ if (!new_site.IsEquivalent(site_for_cookies_)) {
+ Changed(kChangedSiteForCookies);
+ site_for_cookies_ = new_site;
+ }
+}
+
+CefRequestImpl::ResourceType CefRequestImpl::GetResourceType() {
+ base::AutoLock lock_scope(lock_);
+ return resource_type_;
+}
+
+CefRequestImpl::TransitionType CefRequestImpl::GetTransitionType() {
+ base::AutoLock lock_scope(lock_);
+ return transition_type_;
+}
+
+uint64 CefRequestImpl::GetIdentifier() {
+ base::AutoLock lock_scope(lock_);
+ return identifier_;
+}
+
+void CefRequestImpl::Set(const network::ResourceRequest* request,
+ uint64 identifier) {
+ base::AutoLock lock_scope(lock_);
+ CHECK_READONLY_RETURN_VOID();
+
+ Reset();
+
+ url_ = request->url;
+ method_ = request->method;
+ identifier_ = identifier;
+
+ if (request->referrer.is_valid()) {
+ const auto& sanitized_referrer = content::Referrer::SanitizeForRequest(
+ request->url,
+ content::Referrer(
+ request->referrer,
+ NetReferrerPolicyToBlinkReferrerPolicy(
+ static_cast<cef_referrer_policy_t>(request->referrer_policy))));
+ referrer_url_ = sanitized_referrer.url;
+ referrer_policy_ =
+ BlinkReferrerPolicyToNetReferrerPolicy(sanitized_referrer.policy);
+ }
+
+ // Transfer request headers.
+ ::GetHeaderMap(request->headers, headermap_);
+
+ // Transfer post data, if any.
+ if (request->request_body) {
+ postdata_ = CefPostData::Create();
+ static_cast<CefPostDataImpl*>(postdata_.get())->Set(*request->request_body);
+ }
+
+ site_for_cookies_ = request->site_for_cookies;
+
+ resource_type_ = static_cast<cef_resource_type_t>(request->resource_type);
+ transition_type_ =
+ static_cast<cef_transition_type_t>(request->transition_type);
+}
+
+void CefRequestImpl::Get(network::ResourceRequest* request,
+ bool changed_only) const {
+ base::AutoLock lock_scope(lock_);
+
+ if (ShouldSet(kChangedUrl, changed_only)) {
+ request->url = url_;
+ }
+
+ if (ShouldSet(kChangedMethod, changed_only)) {
+ request->method = method_;
+ }
+
+ if (ShouldSet(kChangedReferrer, changed_only)) {
+ request->referrer = referrer_url_;
+ request->referrer_policy =
+ static_cast<net::ReferrerPolicy>(referrer_policy_);
+ }
+
+ if (ShouldSet(kChangedHeaderMap, changed_only)) {
+ net::HttpRequestHeaders headers;
+ headers.AddHeadersFromString(HttpHeaderUtils::GenerateHeaders(headermap_));
+ request->headers.Swap(&headers);
+ }
+
+ if (ShouldSet(kChangedPostData, changed_only)) {
+ if (postdata_.get()) {
+ request->request_body =
+ static_cast<CefPostDataImpl*>(postdata_.get())->GetBody();
+ } else if (request->request_body) {
+ request->request_body = nullptr;
+ }
+ }
+
+ if (!site_for_cookies_.IsNull() &&
+ ShouldSet(kChangedSiteForCookies, changed_only)) {
+ request->site_for_cookies = site_for_cookies_;
+ }
+
+ if (ShouldSet(kChangedFlags, changed_only)) {
+ int flags = flags_;
+ if (!(flags & kURCachePolicyMask)) {
+ // Only consider the Cache-Control directives when a cache policy is not
+ // explicitly set on the request.
+ flags |= GetCacheControlHeaderPolicy(headermap_);
+ }
+
+ int net_flags = 0;
+
+ if (flags & UR_FLAG_SKIP_CACHE) {
+ net_flags |= net::LOAD_BYPASS_CACHE;
+ }
+ if (flags & UR_FLAG_ONLY_FROM_CACHE) {
+ net_flags |= net::LOAD_ONLY_FROM_CACHE | net::LOAD_SKIP_CACHE_VALIDATION;
+ }
+ if (flags & UR_FLAG_DISABLE_CACHE) {
+ net_flags |= net::LOAD_DISABLE_CACHE;
+ }
+
+ if (!(flags & UR_FLAG_ALLOW_STORED_CREDENTIALS)) {
+ // This will disable all credentials including cookies, auth tokens, etc.
+ request->credentials_mode = network::mojom::CredentialsMode::kOmit;
+ }
+
+ request->load_flags = net_flags;
+ }
+}
+
+void CefRequestImpl::Set(const net::RedirectInfo& redirect_info) {
+ base::AutoLock lock_scope(lock_);
+ CHECK_READONLY_RETURN_VOID();
+
+ url_ = redirect_info.new_url;
+ method_ = redirect_info.new_method;
+ site_for_cookies_ = redirect_info.new_site_for_cookies;
+
+ const auto& sanitized_referrer = content::Referrer::SanitizeForRequest(
+ redirect_info.new_url,
+ content::Referrer(GURL(redirect_info.new_referrer),
+ NetReferrerPolicyToBlinkReferrerPolicy(
+ static_cast<cef_referrer_policy_t>(
+ redirect_info.new_referrer_policy))));
+ referrer_url_ = sanitized_referrer.url;
+ referrer_policy_ =
+ BlinkReferrerPolicyToNetReferrerPolicy(sanitized_referrer.policy);
+}
+
+void CefRequestImpl::Set(const net::HttpRequestHeaders& headers) {
+ base::AutoLock lock_scope(lock_);
+ CHECK_READONLY_RETURN_VOID();
+
+ ::GetHeaderMap(headers, headermap_);
+}
+
+void CefRequestImpl::Set(content::NavigationHandle* navigation_handle) {
+ base::AutoLock lock_scope(lock_);
+ CHECK_READONLY_RETURN_VOID();
+
+ Reset();
+
+ url_ = navigation_handle->GetURL();
+ method_ = navigation_handle->IsPost() ? "POST" : "GET";
+
+ const auto& sanitized_referrer = content::Referrer::SanitizeForRequest(
+ navigation_handle->GetURL(), navigation_handle->GetReferrer());
+ referrer_url_ = sanitized_referrer->url;
+ referrer_policy_ =
+ BlinkReferrerPolicyToNetReferrerPolicy(sanitized_referrer->policy);
+
+ resource_type_ =
+ navigation_handle->IsInMainFrame() ? RT_MAIN_FRAME : RT_SUB_FRAME;
+ transition_type_ = static_cast<cef_transition_type_t>(
+ navigation_handle->GetPageTransition());
+}
+
+// static
+void CefRequestImpl::Get(const cef::mojom::RequestParamsPtr& params,
+ blink::WebURLRequest& request) {
+ request.SetUrl(params->url);
+ request.SetRequestorOrigin(blink::WebSecurityOrigin::Create(params->url));
+ if (!params->method.empty()) {
+ request.SetHttpMethod(blink::WebString::FromASCII(params->method));
+ }
+
+ if (params->referrer && params->referrer->url.is_valid()) {
+ const blink::WebString& referrer =
+ blink::WebSecurityPolicy::GenerateReferrerHeader(
+ params->referrer->policy, params->url,
+ blink::WebString::FromUTF8(params->referrer->url.spec()));
+ if (!referrer.IsEmpty()) {
+ request.SetReferrerString(referrer);
+ request.SetReferrerPolicy(params->referrer->policy);
+ }
+ }
+
+ CefRequest::HeaderMap headerMap;
+ if (!params->headers.empty()) {
+ for (net::HttpUtil::HeadersIterator i(params->headers.begin(),
+ params->headers.end(), "\n\r");
+ i.GetNext();) {
+ request.AddHttpHeaderField(blink::WebString::FromUTF8(i.name()),
+ blink::WebString::FromUTF8(i.values()));
+ headerMap.insert(std::make_pair(i.name(), i.values()));
+ }
+ }
+
+ if (params->upload_data) {
+ const std::u16string& method = request.HttpMethod().Utf16();
+ if (method == u"GET" || method == u"HEAD") {
+ request.SetHttpMethod(blink::WebString::FromASCII("POST"));
+ }
+
+ // The comparison performed by httpHeaderField() is case insensitive.
+ if (request
+ .HttpHeaderField(blink::WebString::FromASCII(
+ net::HttpRequestHeaders::kContentType))
+ .length() == 0) {
+ request.SetHttpHeaderField(
+ blink::WebString::FromASCII(net::HttpRequestHeaders::kContentType),
+ blink::WebString::FromASCII(
+ net_service::kContentTypeApplicationFormURLEncoded));
+ }
+
+ request.SetHttpBody(
+ blink::GetWebHTTPBodyForRequestBody(*params->upload_data));
+ }
+
+ if (!params->site_for_cookies.IsNull()) {
+ request.SetSiteForCookies(params->site_for_cookies);
+ }
+
+ int flags = params->load_flags;
+ if (!(flags & kURCachePolicyMask)) {
+ // Only consider the Cache-Control directives when a cache policy is not
+ // explicitly set on the request.
+ flags |= GetCacheControlHeaderPolicy(headerMap);
+ }
+ request.SetCacheMode(GetFetchCacheMode(flags));
+
+ SETBOOLFLAG(request, params->load_flags, SetAllowStoredCredentials,
+ UR_FLAG_ALLOW_STORED_CREDENTIALS);
+ SETBOOLFLAG(request, params->load_flags, SetReportUploadProgress,
+ UR_FLAG_REPORT_UPLOAD_PROGRESS);
+}
+
+void CefRequestImpl::Get(cef::mojom::RequestParamsPtr& params) const {
+ base::AutoLock lock_scope(lock_);
+
+ params->url = url_;
+ params->method = method_;
+
+ // Referrer policy will be applied later in the request pipeline.
+ params->referrer = blink::mojom::Referrer::New(
+ referrer_url_, NetReferrerPolicyToBlinkReferrerPolicy(referrer_policy_));
+
+ if (!headermap_.empty()) {
+ params->headers = HttpHeaderUtils::GenerateHeaders(headermap_);
+ }
+
+ if (postdata_) {
+ CefPostDataImpl* impl = static_cast<CefPostDataImpl*>(postdata_.get());
+ params->upload_data = impl->GetBody();
+ }
+
+ params->site_for_cookies = site_for_cookies_;
+ params->load_flags = flags_;
+}
+
+void CefRequestImpl::SetReadOnly(bool read_only) {
+ base::AutoLock lock_scope(lock_);
+ if (read_only_ == read_only) {
+ return;
+ }
+
+ read_only_ = read_only;
+
+ if (postdata_.get()) {
+ static_cast<CefPostDataImpl*>(postdata_.get())->SetReadOnly(read_only);
+ }
+}
+
+void CefRequestImpl::SetTrackChanges(bool track_changes,
+ bool backup_on_change) {
+ base::AutoLock lock_scope(lock_);
+ if (track_changes_ == track_changes) {
+ return;
+ }
+
+ if (!track_changes && backup_on_change_) {
+ backup_.reset();
+ }
+
+ track_changes_ = track_changes;
+ backup_on_change_ = track_changes ? backup_on_change : false;
+ changes_ = kChangedNone;
+
+ if (postdata_.get()) {
+ static_cast<CefPostDataImpl*>(postdata_.get())
+ ->SetTrackChanges(track_changes);
+ }
+}
+
+void CefRequestImpl::RevertChanges() {
+ base::AutoLock lock_scope(lock_);
+ DCHECK(!read_only_);
+ DCHECK(track_changes_);
+ DCHECK(backup_on_change_);
+ if (!backup_) {
+ return;
+ }
+
+ // Restore the original values if a backup exists.
+ if (backup_->backups_ & kChangedUrl) {
+ url_ = backup_->url_;
+ }
+ if (backup_->backups_ & kChangedMethod) {
+ method_ = backup_->method_;
+ }
+ if (backup_->backups_ & kChangedReferrer) {
+ referrer_url_ = backup_->referrer_url_;
+ referrer_policy_ = backup_->referrer_policy_;
+ }
+ if (backup_->backups_ & kChangedPostData) {
+ postdata_ = backup_->postdata_;
+ }
+ if (backup_->backups_ & kChangedHeaderMap) {
+ DCHECK(backup_->headermap_);
+ headermap_.swap(*backup_->headermap_);
+ }
+ if (backup_->backups_ & kChangedFlags) {
+ flags_ = backup_->flags_;
+ }
+ if (backup_->backups_ & kChangedSiteForCookies) {
+ site_for_cookies_ = backup_->site_for_cookies_;
+ }
+
+ backup_.reset();
+}
+
+void CefRequestImpl::DiscardChanges() {
+ base::AutoLock lock_scope(lock_);
+ DCHECK(track_changes_);
+ DCHECK(backup_on_change_);
+ backup_.reset();
+}
+
+uint8_t CefRequestImpl::GetChanges() const {
+ base::AutoLock lock_scope(lock_);
+
+ uint8_t changes = changes_;
+ if (postdata_.get() &&
+ static_cast<CefPostDataImpl*>(postdata_.get())->HasChanges()) {
+ changes |= kChangedPostData;
+ }
+ return changes;
+}
+
+// From content/child/web_url_loader_impl.cc
+// static
+network::mojom::ReferrerPolicy
+CefRequestImpl::NetReferrerPolicyToBlinkReferrerPolicy(
+ cef_referrer_policy_t net_policy) {
+ switch (net_policy) {
+ case REFERRER_POLICY_CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE:
+ return network::mojom::ReferrerPolicy::kNoReferrerWhenDowngrade;
+ case REFERRER_POLICY_REDUCE_REFERRER_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN:
+ return network::mojom::ReferrerPolicy::kStrictOriginWhenCrossOrigin;
+ case REFERRER_POLICY_ORIGIN_ONLY_ON_TRANSITION_CROSS_ORIGIN:
+ return network::mojom::ReferrerPolicy::kOriginWhenCrossOrigin;
+ case REFERRER_POLICY_NEVER_CLEAR_REFERRER:
+ return network::mojom::ReferrerPolicy::kAlways;
+ case REFERRER_POLICY_ORIGIN:
+ return network::mojom::ReferrerPolicy::kOrigin;
+ case REFERRER_POLICY_CLEAR_REFERRER_ON_TRANSITION_CROSS_ORIGIN:
+ return network::mojom::ReferrerPolicy::kSameOrigin;
+ case REFERRER_POLICY_ORIGIN_CLEAR_ON_TRANSITION_FROM_SECURE_TO_INSECURE:
+ return network::mojom::ReferrerPolicy::kStrictOrigin;
+ case REFERRER_POLICY_NO_REFERRER:
+ return network::mojom::ReferrerPolicy::kNever;
+ }
+ NOTREACHED();
+ return network::mojom::ReferrerPolicy::kDefault;
+}
+
+// static
+cef_referrer_policy_t CefRequestImpl::BlinkReferrerPolicyToNetReferrerPolicy(
+ network::mojom::ReferrerPolicy blink_policy) {
+ switch (blink_policy) {
+ case network::mojom::ReferrerPolicy::kNoReferrerWhenDowngrade:
+ return REFERRER_POLICY_CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE;
+ case network::mojom::ReferrerPolicy::kStrictOriginWhenCrossOrigin:
+ return REFERRER_POLICY_REDUCE_REFERRER_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN;
+ case network::mojom::ReferrerPolicy::kOriginWhenCrossOrigin:
+ return REFERRER_POLICY_ORIGIN_ONLY_ON_TRANSITION_CROSS_ORIGIN;
+ case network::mojom::ReferrerPolicy::kAlways:
+ return REFERRER_POLICY_NEVER_CLEAR_REFERRER;
+ case network::mojom::ReferrerPolicy::kOrigin:
+ return REFERRER_POLICY_ORIGIN;
+ case network::mojom::ReferrerPolicy::kSameOrigin:
+ return REFERRER_POLICY_CLEAR_REFERRER_ON_TRANSITION_CROSS_ORIGIN;
+ case network::mojom::ReferrerPolicy::kStrictOrigin:
+ return REFERRER_POLICY_ORIGIN_CLEAR_ON_TRANSITION_FROM_SECURE_TO_INSECURE;
+ case network::mojom::ReferrerPolicy::kNever:
+ return REFERRER_POLICY_NO_REFERRER;
+ case network::mojom::ReferrerPolicy::kDefault:
+ return REFERRER_POLICY_DEFAULT;
+ }
+ NOTREACHED();
+ return REFERRER_POLICY_DEFAULT;
+}
+
+void CefRequestImpl::Changed(uint8_t changes) {
+ lock_.AssertAcquired();
+ if (!track_changes_) {
+ return;
+ }
+
+ if (backup_on_change_) {
+ if (!backup_) {
+ backup_.reset(new Backup());
+ }
+
+ // Set the backup values if not already set.
+ if ((changes & kChangedUrl) && !(backup_->backups_ & kChangedUrl)) {
+ backup_->url_ = url_;
+ backup_->backups_ |= kChangedUrl;
+ }
+ if ((changes & kChangedMethod) && !(backup_->backups_ & kChangedMethod)) {
+ backup_->method_ = method_;
+ backup_->backups_ |= kChangedMethod;
+ }
+ if ((changes & kChangedReferrer) &&
+ !(backup_->backups_ & kChangedReferrer)) {
+ backup_->referrer_url_ = referrer_url_;
+ backup_->referrer_policy_ = referrer_policy_;
+ backup_->backups_ |= kChangedReferrer;
+ }
+ if ((changes & kChangedPostData) &&
+ !(backup_->backups_ & kChangedPostData)) {
+ backup_->postdata_ = postdata_;
+ backup_->backups_ |= kChangedPostData;
+ }
+ if ((changes & kChangedHeaderMap) &&
+ !(backup_->backups_ & kChangedHeaderMap)) {
+ backup_->headermap_.reset(new HeaderMap());
+ if (!headermap_.empty()) {
+ backup_->headermap_->insert(headermap_.begin(), headermap_.end());
+ }
+ backup_->backups_ |= kChangedHeaderMap;
+ }
+ if ((changes & kChangedFlags) && !(backup_->backups_ & kChangedFlags)) {
+ backup_->flags_ = flags_;
+ backup_->backups_ |= kChangedFlags;
+ }
+ if ((changes & kChangedSiteForCookies) &&
+ !(backup_->backups_ & kChangedSiteForCookies)) {
+ backup_->site_for_cookies_ = site_for_cookies_;
+ backup_->backups_ |= kChangedSiteForCookies;
+ }
+ }
+
+ changes_ |= changes;
+}
+
+bool CefRequestImpl::ShouldSet(uint8_t changes, bool changed_only) const {
+ lock_.AssertAcquired();
+
+ // Always change if changes are not being tracked.
+ if (!track_changes_) {
+ return true;
+ }
+
+ // Always change if changed-only was not requested.
+ if (!changed_only) {
+ return true;
+ }
+
+ // Change if the |changes| bit flag has been set.
+ if ((changes_ & changes) == changes) {
+ return true;
+ }
+
+ if ((changes & kChangedPostData) == kChangedPostData) {
+ // Change if the post data object was modified directly.
+ if (postdata_.get() &&
+ static_cast<CefPostDataImpl*>(postdata_.get())->HasChanges()) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void CefRequestImpl::Reset() {
+ lock_.AssertAcquired();
+ DCHECK(!read_only_);
+
+ url_ = GURL();
+ method_ = "GET";
+ referrer_url_ = GURL();
+ referrer_policy_ = REFERRER_POLICY_DEFAULT;
+ postdata_ = nullptr;
+ headermap_.clear();
+ resource_type_ = RT_SUB_RESOURCE;
+ transition_type_ = TT_EXPLICIT;
+ identifier_ = 0U;
+ flags_ = UR_FLAG_NONE;
+ site_for_cookies_ = net::SiteForCookies();
+
+ changes_ = kChangedNone;
+}
+
+// CefPostData ----------------------------------------------------------------
+
+// static
+CefRefPtr<CefPostData> CefPostData::Create() {
+ CefRefPtr<CefPostData> postdata(new CefPostDataImpl());
+ return postdata;
+}
+
+// CefPostDataImpl ------------------------------------------------------------
+
+CefPostDataImpl::CefPostDataImpl()
+ : read_only_(false),
+ has_excluded_elements_(false),
+ track_changes_(false),
+ has_changes_(false) {}
+
+bool CefPostDataImpl::IsReadOnly() {
+ base::AutoLock lock_scope(lock_);
+ return read_only_;
+}
+
+bool CefPostDataImpl::HasExcludedElements() {
+ base::AutoLock lock_scope(lock_);
+ return has_excluded_elements_;
+}
+
+size_t CefPostDataImpl::GetElementCount() {
+ base::AutoLock lock_scope(lock_);
+ return elements_.size();
+}
+
+void CefPostDataImpl::GetElements(ElementVector& elements) {
+ base::AutoLock lock_scope(lock_);
+ elements = elements_;
+}
+
+bool CefPostDataImpl::RemoveElement(CefRefPtr<CefPostDataElement> element) {
+ base::AutoLock lock_scope(lock_);
+ CHECK_READONLY_RETURN(false);
+
+ ElementVector::iterator it = elements_.begin();
+ for (; it != elements_.end(); ++it) {
+ if (it->get() == element.get()) {
+ elements_.erase(it);
+ Changed();
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool CefPostDataImpl::AddElement(CefRefPtr<CefPostDataElement> element) {
+ bool found = false;
+
+ base::AutoLock lock_scope(lock_);
+ CHECK_READONLY_RETURN(false);
+
+ // check that the element isn't already in the list before adding
+ ElementVector::const_iterator it = elements_.begin();
+ for (; it != elements_.end(); ++it) {
+ if (it->get() == element.get()) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ elements_.push_back(element);
+ Changed();
+ }
+
+ return !found;
+}
+
+void CefPostDataImpl::RemoveElements() {
+ base::AutoLock lock_scope(lock_);
+ CHECK_READONLY_RETURN_VOID();
+ elements_.clear();
+ Changed();
+}
+
+void CefPostDataImpl::Set(const network::ResourceRequestBody& body) {
+ {
+ base::AutoLock lock_scope(lock_);
+ CHECK_READONLY_RETURN_VOID();
+ }
+
+ CefRefPtr<CefPostDataElement> postelem;
+
+ for (const auto& element : *body.elements()) {
+ postelem = CefPostDataElement::Create();
+ static_cast<CefPostDataElementImpl*>(postelem.get())->Set(element);
+ AddElement(postelem);
+ }
+}
+
+scoped_refptr<network::ResourceRequestBody> CefPostDataImpl::GetBody() const {
+ base::AutoLock lock_scope(lock_);
+
+ scoped_refptr<network::ResourceRequestBody> body =
+ new network::ResourceRequestBody();
+ for (const auto& element : elements_) {
+ static_cast<CefPostDataElementImpl*>(element.get())->Get(*body);
+ }
+ return body;
+}
+
+void CefPostDataImpl::SetReadOnly(bool read_only) {
+ base::AutoLock lock_scope(lock_);
+ if (read_only_ == read_only) {
+ return;
+ }
+
+ read_only_ = read_only;
+
+ ElementVector::const_iterator it = elements_.begin();
+ for (; it != elements_.end(); ++it) {
+ static_cast<CefPostDataElementImpl*>(it->get())->SetReadOnly(read_only);
+ }
+}
+
+void CefPostDataImpl::SetTrackChanges(bool track_changes) {
+ base::AutoLock lock_scope(lock_);
+ if (track_changes_ == track_changes) {
+ return;
+ }
+
+ track_changes_ = track_changes;
+ has_changes_ = false;
+
+ ElementVector::const_iterator it = elements_.begin();
+ for (; it != elements_.end(); ++it) {
+ static_cast<CefPostDataElementImpl*>(it->get())->SetTrackChanges(
+ track_changes);
+ }
+}
+
+bool CefPostDataImpl::HasChanges() const {
+ base::AutoLock lock_scope(lock_);
+ if (has_changes_) {
+ return true;
+ }
+
+ ElementVector::const_iterator it = elements_.begin();
+ for (; it != elements_.end(); ++it) {
+ if (static_cast<CefPostDataElementImpl*>(it->get())->HasChanges()) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void CefPostDataImpl::Changed() {
+ lock_.AssertAcquired();
+ if (track_changes_ && !has_changes_) {
+ has_changes_ = true;
+ }
+}
+
+// CefPostDataElement ---------------------------------------------------------
+
+// static
+CefRefPtr<CefPostDataElement> CefPostDataElement::Create() {
+ CefRefPtr<CefPostDataElement> element(new CefPostDataElementImpl());
+ return element;
+}
+
+// CefPostDataElementImpl -----------------------------------------------------
+
+CefPostDataElementImpl::CefPostDataElementImpl()
+ : type_(PDE_TYPE_EMPTY),
+ read_only_(false),
+ track_changes_(false),
+ has_changes_(false) {
+ memset(&data_, 0, sizeof(data_));
+}
+
+CefPostDataElementImpl::~CefPostDataElementImpl() {
+ Cleanup();
+}
+
+bool CefPostDataElementImpl::IsReadOnly() {
+ base::AutoLock lock_scope(lock_);
+ return read_only_;
+}
+
+void CefPostDataElementImpl::SetToEmpty() {
+ base::AutoLock lock_scope(lock_);
+ CHECK_READONLY_RETURN_VOID();
+
+ Cleanup();
+ Changed();
+}
+
+void CefPostDataElementImpl::SetToFile(const CefString& fileName) {
+ base::AutoLock lock_scope(lock_);
+ CHECK_READONLY_RETURN_VOID();
+
+ // Clear any data currently in the element
+ Cleanup();
+
+ // Assign the new data
+ type_ = PDE_TYPE_FILE;
+ cef_string_copy(fileName.c_str(), fileName.length(), &data_.filename);
+
+ Changed();
+}
+
+void CefPostDataElementImpl::SetToBytes(size_t size, const void* bytes) {
+ base::AutoLock lock_scope(lock_);
+ CHECK_READONLY_RETURN_VOID();
+
+ // Clear any data currently in the element
+ Cleanup();
+
+ // Assign the new data
+ void* data = malloc(size);
+ DCHECK(data != nullptr);
+ if (data == nullptr) {
+ return;
+ }
+
+ memcpy(data, bytes, size);
+
+ type_ = PDE_TYPE_BYTES;
+ data_.bytes.bytes = data;
+ data_.bytes.size = size;
+
+ Changed();
+}
+
+CefPostDataElement::Type CefPostDataElementImpl::GetType() {
+ base::AutoLock lock_scope(lock_);
+ return type_;
+}
+
+CefString CefPostDataElementImpl::GetFile() {
+ base::AutoLock lock_scope(lock_);
+ DCHECK(type_ == PDE_TYPE_FILE);
+ CefString filename;
+ if (type_ == PDE_TYPE_FILE) {
+ filename.FromString(data_.filename.str, data_.filename.length, false);
+ }
+ return filename;
+}
+
+size_t CefPostDataElementImpl::GetBytesCount() {
+ base::AutoLock lock_scope(lock_);
+ DCHECK(type_ == PDE_TYPE_BYTES);
+ size_t size = 0;
+ if (type_ == PDE_TYPE_BYTES) {
+ size = data_.bytes.size;
+ }
+ return size;
+}
+
+size_t CefPostDataElementImpl::GetBytes(size_t size, void* bytes) {
+ base::AutoLock lock_scope(lock_);
+ DCHECK(type_ == PDE_TYPE_BYTES);
+ size_t rv = 0;
+ if (type_ == PDE_TYPE_BYTES) {
+ rv = (size < data_.bytes.size ? size : data_.bytes.size);
+ memcpy(bytes, data_.bytes.bytes, rv);
+ }
+ return rv;
+}
+
+void CefPostDataElementImpl::Set(const network::DataElement& element) {
+ {
+ base::AutoLock lock_scope(lock_);
+ CHECK_READONLY_RETURN_VOID();
+ }
+
+ if (element.type() == network::DataElement::Tag::kBytes) {
+ const auto& bytes_element = element.As<network::DataElementBytes>();
+ const auto& bytes = bytes_element.bytes();
+ SetToBytes(bytes.size(), bytes.data());
+ } else if (element.type() == network::DataElement::Tag::kFile) {
+ const auto& file_element = element.As<network::DataElementFile>();
+ SetToFile(file_element.path().value());
+ }
+}
+
+void CefPostDataElementImpl::Get(network::ResourceRequestBody& body) const {
+ base::AutoLock lock_scope(lock_);
+
+ if (type_ == PDE_TYPE_BYTES) {
+ body.AppendBytes(static_cast<char*>(data_.bytes.bytes), data_.bytes.size);
+ } else if (type_ == PDE_TYPE_FILE) {
+ base::FilePath path = base::FilePath(CefString(&data_.filename));
+ body.AppendFileRange(path, 0, std::numeric_limits<uint64_t>::max(),
+ base::Time());
+ } else {
+ NOTREACHED();
+ }
+}
+
+void CefPostDataElementImpl::SetReadOnly(bool read_only) {
+ base::AutoLock lock_scope(lock_);
+ if (read_only_ == read_only) {
+ return;
+ }
+
+ read_only_ = read_only;
+}
+
+void CefPostDataElementImpl::SetTrackChanges(bool track_changes) {
+ base::AutoLock lock_scope(lock_);
+ if (track_changes_ == track_changes) {
+ return;
+ }
+
+ track_changes_ = track_changes;
+ has_changes_ = false;
+}
+
+bool CefPostDataElementImpl::HasChanges() const {
+ base::AutoLock lock_scope(lock_);
+ return has_changes_;
+}
+
+void CefPostDataElementImpl::Changed() {
+ lock_.AssertAcquired();
+ if (track_changes_ && !has_changes_) {
+ has_changes_ = true;
+ }
+}
+
+void CefPostDataElementImpl::Cleanup() {
+ if (type_ == PDE_TYPE_EMPTY) {
+ return;
+ }
+
+ if (type_ == PDE_TYPE_BYTES) {
+ free(data_.bytes.bytes);
+ } else if (type_ == PDE_TYPE_FILE) {
+ cef_string_clear(&data_.filename);
+ }
+ type_ = PDE_TYPE_EMPTY;
+ memset(&data_, 0, sizeof(data_));
+}
diff --git a/libcef/common/request_impl.h b/libcef/common/request_impl.h
new file mode 100644
index 00000000..9ef13f2b
--- /dev/null
+++ b/libcef/common/request_impl.h
@@ -0,0 +1,282 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_COMMON_REQUEST_IMPL_H_
+#define CEF_LIBCEF_COMMON_REQUEST_IMPL_H_
+#pragma once
+
+#include <stdint.h>
+
+#include <memory>
+
+#include "include/cef_request.h"
+
+#include "base/synchronization/lock.h"
+#include "cef/libcef/common/mojom/cef.mojom.h"
+#include "net/cookies/site_for_cookies.h"
+#include "services/network/public/mojom/referrer_policy.mojom-shared.h"
+#include "url/gurl.h"
+
+namespace blink {
+class WebURLRequest;
+} // namespace blink
+
+namespace content {
+class NavigationHandle;
+} // namespace content
+
+namespace net {
+class HttpRequestHeaders;
+struct RedirectInfo;
+} // namespace net
+
+namespace network {
+class DataElement;
+struct ResourceRequest;
+class ResourceRequestBody;
+} // namespace network
+
+// Implementation of CefRequest
+class CefRequestImpl : public CefRequest {
+ public:
+ enum Changes {
+ kChangedNone = 0,
+ kChangedUrl = 1 << 0,
+ kChangedMethod = 1 << 1,
+ kChangedReferrer = 1 << 2,
+ kChangedPostData = 1 << 3,
+ kChangedHeaderMap = 1 << 4,
+ kChangedFlags = 1 << 5,
+ kChangedSiteForCookies = 1 << 6,
+ };
+
+ CefRequestImpl();
+
+ bool IsReadOnly() override;
+ CefString GetURL() override;
+ void SetURL(const CefString& url) override;
+ CefString GetMethod() override;
+ void SetMethod(const CefString& method) override;
+ void SetReferrer(const CefString& referrer_url,
+ ReferrerPolicy policy) override;
+ CefString GetReferrerURL() override;
+ ReferrerPolicy GetReferrerPolicy() override;
+ CefRefPtr<CefPostData> GetPostData() override;
+ void SetPostData(CefRefPtr<CefPostData> postData) override;
+ void GetHeaderMap(HeaderMap& headerMap) override;
+ void SetHeaderMap(const HeaderMap& headerMap) override;
+ CefString GetHeaderByName(const CefString& name) override;
+ void SetHeaderByName(const CefString& name,
+ const CefString& value,
+ bool overwrite) override;
+ void Set(const CefString& url,
+ const CefString& method,
+ CefRefPtr<CefPostData> postData,
+ const HeaderMap& headerMap) override;
+ int GetFlags() override;
+ void SetFlags(int flags) override;
+ CefString GetFirstPartyForCookies() override;
+ void SetFirstPartyForCookies(const CefString& url) override;
+ ResourceType GetResourceType() override;
+ TransitionType GetTransitionType() override;
+ uint64 GetIdentifier() override;
+
+ // Populate this object from the ResourceRequest object.
+ void Set(const network::ResourceRequest* request, uint64 identifier);
+
+ // Populate the ResourceRequest object from this object.
+ // If |changed_only| is true then only the changed fields will be updated.
+ void Get(network::ResourceRequest* request, bool changed_only) const;
+
+ // Populate this object from the RedirectInfo object.
+ void Set(const net::RedirectInfo& redirect_info);
+
+ // Populate this object from the HttpRequestHeaders object.
+ void Set(const net::HttpRequestHeaders& headers);
+
+ // Populate this object from the NavigationParams object.
+ // Called from throttle_handler.cc NavigationOnUIThread().
+ void Set(content::NavigationHandle* navigation_handle);
+
+ // Populate the WebURLRequest object based on the contents of |params|.
+ // Called from CefBrowserImpl::LoadRequest().
+ static void Get(const cef::mojom::RequestParamsPtr& params,
+ blink::WebURLRequest& request);
+
+ // Populate the RequestParams object from this object.
+ // Called from CefFrameHostImpl::LoadRequest().
+ void Get(cef::mojom::RequestParamsPtr& params) const;
+
+ void SetReadOnly(bool read_only);
+
+ // Enable or disable tracking of changes. If |track_changes| is true the
+ // status of changes will be tracked, and retrievable via GetChanges(). If
+ // |backup_on_change| is true the original value will be backed up before the
+ // first change. The original values can later be restored by calling
+ // RevertChanges() before calling SetTrackChanges(false).
+ void SetTrackChanges(bool track_changes, bool backup_on_change = false);
+ void RevertChanges();
+ void DiscardChanges();
+ uint8_t GetChanges() const;
+
+ static network::mojom::ReferrerPolicy NetReferrerPolicyToBlinkReferrerPolicy(
+ cef_referrer_policy_t net_policy);
+ static cef_referrer_policy_t BlinkReferrerPolicyToNetReferrerPolicy(
+ network::mojom::ReferrerPolicy blink_policy);
+
+ private:
+ // Mark values as changed. Must be called before the new values are assigned.
+ void Changed(uint8_t changes);
+
+ // Used with the Set() methods that export data to other object types. Returns
+ // true if the values should be set on the export object. If |changed_only| is
+ // true then only return true if the value has been changed in combination
+ // with track changes.
+ bool ShouldSet(uint8_t changes, bool changed_only) const;
+
+ void Reset();
+
+ GURL url_;
+ std::string method_;
+ GURL referrer_url_;
+ ReferrerPolicy referrer_policy_;
+ CefRefPtr<CefPostData> postdata_;
+ HeaderMap headermap_;
+ ResourceType resource_type_;
+ TransitionType transition_type_;
+ uint64 identifier_;
+
+ // The below members are used by CefURLRequest.
+ int flags_;
+ net::SiteForCookies site_for_cookies_;
+
+ // Stores backup of values for use with track changes.
+ struct Backup {
+ // Bitmask of values that have been backed up.
+ uint8_t backups_ = kChangedNone;
+
+ GURL url_;
+ std::string method_;
+ GURL referrer_url_;
+ ReferrerPolicy referrer_policy_;
+ CefRefPtr<CefPostData> postdata_;
+ std::unique_ptr<HeaderMap> headermap_;
+ int flags_;
+ net::SiteForCookies site_for_cookies_;
+ };
+ std::unique_ptr<Backup> backup_;
+
+ // True if this object is read-only.
+ bool read_only_ = false;
+
+ // True if this object should track changes.
+ bool track_changes_ = false;
+
+ // True if original values should be backed up when |track_changes_| is true.
+ bool backup_on_change_ = false;
+
+ // Bitmask of |Changes| values which indicate which fields have changed.
+ uint8_t changes_ = kChangedNone;
+
+ mutable base::Lock lock_;
+
+ IMPLEMENT_REFCOUNTING(CefRequestImpl);
+};
+
+// Implementation of CefPostData
+class CefPostDataImpl : public CefPostData {
+ public:
+ CefPostDataImpl();
+
+ bool IsReadOnly() override;
+ bool HasExcludedElements() override;
+ size_t GetElementCount() override;
+ void GetElements(ElementVector& elements) override;
+ bool RemoveElement(CefRefPtr<CefPostDataElement> element) override;
+ bool AddElement(CefRefPtr<CefPostDataElement> element) override;
+ void RemoveElements() override;
+
+ void Set(const network::ResourceRequestBody& body);
+ scoped_refptr<network::ResourceRequestBody> GetBody() const;
+
+ void SetReadOnly(bool read_only);
+
+ void SetTrackChanges(bool track_changes);
+ bool HasChanges() const;
+
+ private:
+ void Changed();
+
+ ElementVector elements_;
+
+ // True if this object is read-only.
+ bool read_only_;
+
+ // True if this object has excluded elements.
+ bool has_excluded_elements_;
+
+ // True if this object should track changes.
+ bool track_changes_;
+
+ // True if this object has changes.
+ bool has_changes_;
+
+ mutable base::Lock lock_;
+
+ IMPLEMENT_REFCOUNTING(CefPostDataImpl);
+};
+
+// Implementation of CefPostDataElement
+class CefPostDataElementImpl : public CefPostDataElement {
+ public:
+ CefPostDataElementImpl();
+ ~CefPostDataElementImpl() override;
+
+ bool IsReadOnly() override;
+ void SetToEmpty() override;
+ void SetToFile(const CefString& fileName) override;
+ void SetToBytes(size_t size, const void* bytes) override;
+ Type GetType() override;
+ CefString GetFile() override;
+ size_t GetBytesCount() override;
+ size_t GetBytes(size_t size, void* bytes) override;
+
+ void* GetBytes() { return data_.bytes.bytes; }
+
+ void Set(const network::DataElement& element);
+ void Get(network::ResourceRequestBody& body) const;
+
+ void SetReadOnly(bool read_only);
+
+ void SetTrackChanges(bool track_changes);
+ bool HasChanges() const;
+
+ private:
+ void Changed();
+ void Cleanup();
+
+ Type type_;
+ union {
+ struct {
+ void* bytes;
+ size_t size;
+ } bytes;
+ cef_string_t filename;
+ } data_;
+
+ // True if this object is read-only.
+ bool read_only_;
+
+ // True if this object should track changes.
+ bool track_changes_;
+
+ // True if this object has changes.
+ bool has_changes_;
+
+ mutable base::Lock lock_;
+
+ IMPLEMENT_REFCOUNTING(CefPostDataElementImpl);
+};
+
+#endif // CEF_LIBCEF_COMMON_REQUEST_IMPL_H_
diff --git a/libcef/common/resource_bundle_delegate.cc b/libcef/common/resource_bundle_delegate.cc
new file mode 100644
index 00000000..bfa0da00
--- /dev/null
+++ b/libcef/common/resource_bundle_delegate.cc
@@ -0,0 +1,85 @@
+#include "libcef/common/resource_bundle_delegate.h"
+
+#include "libcef/common/app_manager.h"
+
+base::FilePath CefResourceBundleDelegate::GetPathForResourcePack(
+ const base::FilePath& pack_path,
+ ui::ResourceScaleFactor scale_factor) {
+ // Only allow the cef pack file to load.
+ if (!pack_loading_disabled_ && allow_pack_file_load_) {
+ return pack_path;
+ }
+ return base::FilePath();
+}
+
+base::FilePath CefResourceBundleDelegate::GetPathForLocalePack(
+ const base::FilePath& pack_path,
+ const std::string& locale) {
+ if (!pack_loading_disabled_) {
+ return pack_path;
+ }
+ return base::FilePath();
+}
+
+gfx::Image CefResourceBundleDelegate::GetImageNamed(int resource_id) {
+ return gfx::Image();
+}
+
+gfx::Image CefResourceBundleDelegate::GetNativeImageNamed(int resource_id) {
+ return gfx::Image();
+}
+
+base::RefCountedMemory* CefResourceBundleDelegate::LoadDataResourceBytes(
+ int resource_id,
+ ui::ResourceScaleFactor scale_factor) {
+ return nullptr;
+}
+
+absl::optional<std::string> CefResourceBundleDelegate::LoadDataResourceString(
+ int resource_id) {
+ return absl::nullopt;
+}
+
+bool CefResourceBundleDelegate::GetRawDataResource(
+ int resource_id,
+ ui::ResourceScaleFactor scale_factor,
+ base::StringPiece* value) const {
+ auto application = CefAppManager::Get()->GetApplication();
+ if (application) {
+ CefRefPtr<CefResourceBundleHandler> handler =
+ application->GetResourceBundleHandler();
+ if (handler.get()) {
+ void* data = nullptr;
+ size_t data_size = 0;
+ if (scale_factor != ui::kScaleFactorNone) {
+ if (handler->GetDataResourceForScale(
+ resource_id, static_cast<cef_scale_factor_t>(scale_factor),
+ data, data_size)) {
+ *value = base::StringPiece(static_cast<char*>(data), data_size);
+ }
+ } else if (handler->GetDataResource(resource_id, data, data_size)) {
+ *value = base::StringPiece(static_cast<char*>(data), data_size);
+ }
+ }
+ }
+
+ return (pack_loading_disabled_ || !value->empty());
+}
+
+bool CefResourceBundleDelegate::GetLocalizedString(
+ int message_id,
+ std::u16string* value) const {
+ auto application = CefAppManager::Get()->GetApplication();
+ if (application) {
+ CefRefPtr<CefResourceBundleHandler> handler =
+ application->GetResourceBundleHandler();
+ if (handler.get()) {
+ CefString cef_str;
+ if (handler->GetLocalizedString(message_id, cef_str)) {
+ *value = cef_str;
+ }
+ }
+ }
+
+ return (pack_loading_disabled_ || !value->empty());
+}
diff --git a/libcef/common/resource_bundle_delegate.h b/libcef/common/resource_bundle_delegate.h
new file mode 100644
index 00000000..7c8acefb
--- /dev/null
+++ b/libcef/common/resource_bundle_delegate.h
@@ -0,0 +1,46 @@
+// Copyright 2019 The Chromium Embedded Framework Authors.
+// Portions copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_COMMON_RESOURCE_BUNDLE_DELEGATE_H_
+#define CEF_LIBCEF_COMMON_RESOURCE_BUNDLE_DELEGATE_H_
+#pragma once
+
+#include "ui/base/resource/resource_bundle.h"
+
+class AlloyContentClient;
+
+class CefResourceBundleDelegate : public ui::ResourceBundle::Delegate {
+ public:
+ CefResourceBundleDelegate() {}
+
+ void set_pack_loading_disabled(bool val) { pack_loading_disabled_ = val; }
+ bool pack_loading_disabled() const { return pack_loading_disabled_; }
+ void set_allow_pack_file_load(bool val) { allow_pack_file_load_ = val; }
+ bool allow_pack_file_load() const { return allow_pack_file_load_; }
+
+ private:
+ // ui::ResourceBundle::Delegate methods.
+ base::FilePath GetPathForResourcePack(
+ const base::FilePath& pack_path,
+ ui::ResourceScaleFactor scale_factor) override;
+ base::FilePath GetPathForLocalePack(const base::FilePath& pack_path,
+ const std::string& locale) override;
+ gfx::Image GetImageNamed(int resource_id) override;
+ gfx::Image GetNativeImageNamed(int resource_id) override;
+ base::RefCountedMemory* LoadDataResourceBytes(
+ int resource_id,
+ ui::ResourceScaleFactor scale_factor) override;
+ absl::optional<std::string> LoadDataResourceString(int resource_id) override;
+ bool GetRawDataResource(int resource_id,
+ ui::ResourceScaleFactor scale_factor,
+ base::StringPiece* value) const override;
+ bool GetLocalizedString(int message_id, std::u16string* value) const override;
+
+ private:
+ bool pack_loading_disabled_ = false;
+ bool allow_pack_file_load_ = false;
+};
+
+#endif // CEF_LIBCEF_COMMON_RESOURCE_BUNDLE_DELEGATE_H_
diff --git a/libcef/common/resource_bundle_impl.cc b/libcef/common/resource_bundle_impl.cc
new file mode 100644
index 00000000..7af873b4
--- /dev/null
+++ b/libcef/common/resource_bundle_impl.cc
@@ -0,0 +1,45 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#include "libcef/common/resource_bundle_impl.h"
+
+#include "base/memory/ref_counted_memory.h"
+#include "ui/base/resource/resource_bundle.h"
+
+CefResourceBundleImpl::CefResourceBundleImpl() {}
+
+CefString CefResourceBundleImpl::GetLocalizedString(int string_id) {
+ if (!ui::ResourceBundle::HasSharedInstance()) {
+ return CefString();
+ }
+
+ return ui::ResourceBundle::GetSharedInstance().GetLocalizedString(string_id);
+}
+
+CefRefPtr<CefBinaryValue> CefResourceBundleImpl::GetDataResource(
+ int resource_id) {
+ return GetDataResourceForScale(resource_id, SCALE_FACTOR_NONE);
+}
+
+CefRefPtr<CefBinaryValue> CefResourceBundleImpl::GetDataResourceForScale(
+ int resource_id,
+ ScaleFactor scale_factor) {
+ if (!ui::ResourceBundle::HasSharedInstance()) {
+ return nullptr;
+ }
+
+ base::RefCountedMemory* result =
+ ui::ResourceBundle::GetSharedInstance().LoadDataResourceBytesForScale(
+ resource_id, static_cast<ui::ResourceScaleFactor>(scale_factor));
+ if (!result) {
+ return nullptr;
+ }
+
+ return CefBinaryValue::Create(result->data(), result->size());
+}
+
+// static
+CefRefPtr<CefResourceBundle> CefResourceBundle::GetGlobal() {
+ return new CefResourceBundleImpl();
+}
diff --git a/libcef/common/resource_bundle_impl.h b/libcef/common/resource_bundle_impl.h
new file mode 100644
index 00000000..e759dae5
--- /dev/null
+++ b/libcef/common/resource_bundle_impl.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_COMMON_RESOURCE_BUNDLE_IMPL_H_
+#define CEF_LIBCEF_COMMON_RESOURCE_BUNDLE_IMPL_H_
+#pragma once
+
+#include "include/cef_resource_bundle.h"
+
+class CefResourceBundleImpl : public CefResourceBundle {
+ public:
+ CefResourceBundleImpl();
+
+ CefResourceBundleImpl(const CefResourceBundleImpl&) = delete;
+ CefResourceBundleImpl& operator=(const CefResourceBundleImpl&) = delete;
+
+ // CefResourceBundle methods.
+ CefString GetLocalizedString(int string_id) override;
+ CefRefPtr<CefBinaryValue> GetDataResource(int resource_id) override;
+ CefRefPtr<CefBinaryValue> GetDataResourceForScale(
+ int resource_id,
+ ScaleFactor scale_factor) override;
+
+ private:
+ IMPLEMENT_REFCOUNTING(CefResourceBundleImpl);
+};
+
+#endif // CEF_LIBCEF_COMMON_RESOURCE_BUNDLE_IMPL_H_
diff --git a/libcef/common/resource_util.cc b/libcef/common/resource_util.cc
new file mode 100644
index 00000000..88941b17
--- /dev/null
+++ b/libcef/common/resource_util.cc
@@ -0,0 +1,245 @@
+// Copyright 2017 The Chromium Embedded Framework Authors. Portions copyright
+// 2011 The Chromium Authors. All rights reserved. Use of this source code is
+// governed by a BSD-style license that can be found in the LICENSE file.
+
+#include "libcef/common/resource_util.h"
+
+#if BUILDFLAG(IS_LINUX)
+#include <dlfcn.h>
+#endif
+
+#include "libcef/features/runtime.h"
+
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/notreached.h"
+#include "base/path_service.h"
+#include "chrome/common/chrome_constants.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/chrome_paths_internal.h"
+#include "chrome/common/chrome_switches.h"
+#include "ui/base/layout.h"
+
+#if BUILDFLAG(IS_MAC)
+#include "base/mac/foundation_util.h"
+#include "libcef/common/util_mac.h"
+#endif
+
+#if BUILDFLAG(IS_LINUX)
+#include "base/environment.h"
+#include "base/nix/xdg_util.h"
+#endif
+
+#if BUILDFLAG(IS_WIN)
+#include "base/win/registry.h"
+#endif
+
+namespace resource_util {
+
+namespace {
+
+#if BUILDFLAG(IS_LINUX)
+
+// Based on chrome/common/chrome_paths_linux.cc.
+// See http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
+// for a spec on where config files go. The net result on most systems is that
+// we use "~/.config/cef_user_data".
+bool GetDefaultUserDataDirectory(base::FilePath* result) {
+ std::unique_ptr<base::Environment> env(base::Environment::Create());
+ base::FilePath config_dir(base::nix::GetXDGDirectory(
+ env.get(), base::nix::kXdgConfigHomeEnvVar, base::nix::kDotConfigDir));
+ *result = config_dir.Append(FILE_PATH_LITERAL("cef_user_data"));
+ return true;
+}
+
+#elif BUILDFLAG(IS_MAC)
+
+// Based on chrome/common/chrome_paths_mac.mm.
+bool GetDefaultUserDataDirectory(base::FilePath* result) {
+ if (!base::PathService::Get(base::DIR_APP_DATA, result)) {
+ return false;
+ }
+ *result = result->Append(FILE_PATH_LITERAL("CEF"));
+ *result = result->Append(FILE_PATH_LITERAL("User Data"));
+ return true;
+}
+
+#elif BUILDFLAG(IS_WIN)
+
+// Based on chrome/common/chrome_paths_win.cc.
+bool GetDefaultUserDataDirectory(base::FilePath* result) {
+ if (!base::PathService::Get(base::DIR_LOCAL_APP_DATA, result)) {
+ return false;
+ }
+ *result = result->Append(FILE_PATH_LITERAL("CEF"));
+ *result = result->Append(FILE_PATH_LITERAL("User Data"));
+ return true;
+}
+
+#endif
+
+base::FilePath GetUserDataPath(CefSettings* settings,
+ const base::CommandLine* command_line) {
+ // |settings| will be non-nullptr in the main process only.
+ if (settings) {
+ // With the Chrome runtime Profile paths must always be relative to the
+ // user data directory, so defaulting to |root_cache_path| first is
+ // appropriate.
+ CefString user_data_path;
+ if (cef::IsChromeRuntimeEnabled() && settings->root_cache_path.length > 0) {
+ user_data_path = CefString(&settings->root_cache_path);
+ }
+ if (user_data_path.empty() && settings->user_data_path.length > 0) {
+ user_data_path = CefString(&settings->user_data_path);
+ }
+ if (!user_data_path.empty()) {
+ return base::FilePath(user_data_path);
+ }
+ }
+
+ // This may be set for sub-processes.
+ base::FilePath result =
+ command_line->GetSwitchValuePath(switches::kUserDataDir);
+ if (!result.empty()) {
+ return result;
+ }
+
+ if (GetDefaultUserDataDirectory(&result)) {
+ return result;
+ }
+
+ if (base::PathService::Get(base::DIR_TEMP, &result)) {
+ return result;
+ }
+
+ NOTREACHED();
+ return result;
+}
+
+// Consider downloads 'dangerous' if they go to the home directory on Linux and
+// to the desktop on any platform.
+// From chrome/browser/download/download_prefs.cc.
+bool DownloadPathIsDangerous(const base::FilePath& download_path) {
+#if BUILDFLAG(IS_LINUX)
+ base::FilePath home_dir = base::GetHomeDir();
+ if (download_path == home_dir) {
+ return true;
+ }
+#endif
+
+ base::FilePath desktop_dir;
+ if (!base::PathService::Get(base::DIR_USER_DESKTOP, &desktop_dir)) {
+ NOTREACHED();
+ return false;
+ }
+ return (download_path == desktop_dir);
+}
+
+bool GetDefaultDownloadDirectory(base::FilePath* result) {
+ // This will return the safe download directory if necessary.
+ return chrome::GetUserDownloadsDirectory(result);
+}
+
+bool GetDefaultDownloadSafeDirectory(base::FilePath* result) {
+ // Start with the default download directory.
+ if (!GetDefaultDownloadDirectory(result)) {
+ return false;
+ }
+
+ if (DownloadPathIsDangerous(*result)) {
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX)
+ // Explicitly switch to the safe download directory.
+ return chrome::GetUserDownloadsDirectorySafe(result);
+#else
+ // No viable alternative on macOS.
+ return false;
+#endif
+ }
+
+ return true;
+}
+
+} // namespace
+
+#if BUILDFLAG(IS_MAC)
+
+base::FilePath GetResourcesDir() {
+ return util_mac::GetFrameworkResourcesDirectory();
+}
+
+// Use a "~/Library/Logs/<app name>_debug.log" file where <app name> is the name
+// of the running executable.
+base::FilePath GetDefaultLogFilePath() {
+ std::string exe_name = util_mac::GetMainProcessPath().BaseName().value();
+ return base::mac::GetUserLibraryPath()
+ .Append(FILE_PATH_LITERAL("Logs"))
+ .Append(FILE_PATH_LITERAL(exe_name + "_debug.log"));
+}
+
+#else // !BUILDFLAG(IS_MAC)
+
+base::FilePath GetResourcesDir() {
+ base::FilePath pak_dir;
+ base::PathService::Get(base::DIR_ASSETS, &pak_dir);
+ return pak_dir;
+}
+
+// Use a "debug.log" file in the running executable's directory.
+base::FilePath GetDefaultLogFilePath() {
+ base::FilePath log_path;
+ base::PathService::Get(base::DIR_EXE, &log_path);
+ return log_path.Append(FILE_PATH_LITERAL("debug.log"));
+}
+
+#endif // !BUILDFLAG(IS_MAC)
+
+void OverrideDefaultDownloadDir() {
+ base::FilePath dir_default_download;
+ base::FilePath dir_default_download_safe;
+ if (GetDefaultDownloadDirectory(&dir_default_download)) {
+ base::PathService::Override(chrome::DIR_DEFAULT_DOWNLOADS,
+ dir_default_download);
+ }
+ if (GetDefaultDownloadSafeDirectory(&dir_default_download_safe)) {
+ base::PathService::Override(chrome::DIR_DEFAULT_DOWNLOADS_SAFE,
+ dir_default_download_safe);
+ }
+}
+
+void OverrideUserDataDir(CefSettings* settings,
+ const base::CommandLine* command_line) {
+ const base::FilePath& user_data_path =
+ GetUserDataPath(settings, command_line);
+ base::PathService::Override(chrome::DIR_USER_DATA, user_data_path);
+
+ // Path used for crash dumps.
+ base::PathService::Override(chrome::DIR_CRASH_DUMPS, user_data_path);
+
+ // Path used for spell checking dictionary files.
+ base::PathService::OverrideAndCreateIfNeeded(
+ chrome::DIR_APP_DICTIONARIES,
+ user_data_path.Append(FILE_PATH_LITERAL("Dictionaries")),
+ false, // May not be an absolute path.
+ true); // Create if necessary.
+}
+
+// Same as ui::ResourceBundle::IsScaleFactorSupported.
+bool IsScaleFactorSupported(ui::ResourceScaleFactor scale_factor) {
+ const auto& supported_scale_factors = ui::GetSupportedResourceScaleFactors();
+ return std::find(supported_scale_factors.begin(),
+ supported_scale_factors.end(),
+ scale_factor) != supported_scale_factors.end();
+}
+
+#if BUILDFLAG(IS_LINUX)
+void OverrideAssetPath() {
+ Dl_info dl_info;
+ if (dladdr(reinterpret_cast<const void*>(&OverrideAssetPath), &dl_info)) {
+ base::FilePath path = base::FilePath(dl_info.dli_fname).DirName();
+ base::PathService::Override(base::DIR_ASSETS, path);
+ }
+}
+#endif
+
+} // namespace resource_util
diff --git a/libcef/common/resource_util.h b/libcef/common/resource_util.h
new file mode 100644
index 00000000..a23912e7
--- /dev/null
+++ b/libcef/common/resource_util.h
@@ -0,0 +1,44 @@
+// Copyright 2017 The Chromium Embedded Framework Authors. Portions copyright
+// 2011 The Chromium Authors. All rights reserved. Use of this source code is
+// governed by a BSD-style license that can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_COMMON_RESOURCE_UTIL_H_
+#define CEF_LIBCEF_COMMON_RESOURCE_UTIL_H_
+#pragma once
+
+#include "include/cef_base.h"
+
+#include "ui/base/resource/resource_scale_factor.h"
+
+namespace base {
+class CommandLine;
+class FilePath;
+} // namespace base
+
+namespace resource_util {
+
+// Returns the directory that contains resource files (*.bin, *.dat, *.pak,
+// etc).
+base::FilePath GetResourcesDir();
+
+// Returns the default path for the debug.log file.
+base::FilePath GetDefaultLogFilePath();
+
+// Called from MainDelegate::PreSandboxStartup.
+void OverrideDefaultDownloadDir();
+void OverrideUserDataDir(CefSettings* settings,
+ const base::CommandLine* command_line);
+
+// Returns true if |scale_factor| is supported by this platform.
+bool IsScaleFactorSupported(ui::ResourceScaleFactor scale_factor);
+
+#if BUILDFLAG(IS_LINUX)
+// Look for binary files (*.bin, *.dat, *.pak, chrome-sandbox, libGLESv2.so,
+// libEGL.so, locales/*.pak, swiftshader/*.so) next to libcef instead of the exe
+// on Linux. This is already the default on Windows.
+void OverrideAssetPath();
+#endif
+
+} // namespace resource_util
+
+#endif // CEF_LIBCEF_COMMON_RESOURCE_UTIL_H_
diff --git a/libcef/common/response_impl.cc b/libcef/common/response_impl.cc
new file mode 100644
index 00000000..29e62270
--- /dev/null
+++ b/libcef/common/response_impl.cc
@@ -0,0 +1,241 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "libcef/common/response_impl.h"
+
+#include <string>
+
+#include "libcef/common/net/http_header_utils.h"
+#include "libcef/common/net_service/net_service_util.h"
+
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+#include "net/http/http_request_headers.h"
+#include "net/http/http_response_headers.h"
+#include "third_party/blink/public/platform/web_http_header_visitor.h"
+#include "third_party/blink/public/platform/web_string.h"
+#include "third_party/blink/public/platform/web_url.h"
+#include "third_party/blink/public/platform/web_url_response.h"
+
+#define CHECK_READONLY_RETURN_VOID() \
+ if (read_only_) { \
+ NOTREACHED() << "object is read only"; \
+ return; \
+ }
+
+// CefResponse ----------------------------------------------------------------
+
+// static
+CefRefPtr<CefResponse> CefResponse::Create() {
+ CefRefPtr<CefResponse> response(new CefResponseImpl());
+ return response;
+}
+
+// CefResponseImpl ------------------------------------------------------------
+
+CefResponseImpl::CefResponseImpl()
+ : error_code_(ERR_NONE), status_code_(0), read_only_(false) {}
+
+bool CefResponseImpl::IsReadOnly() {
+ base::AutoLock lock_scope(lock_);
+ return read_only_;
+}
+
+cef_errorcode_t CefResponseImpl::GetError() {
+ base::AutoLock lock_scope(lock_);
+ return error_code_;
+}
+
+void CefResponseImpl::SetError(cef_errorcode_t error) {
+ base::AutoLock lock_scope(lock_);
+ CHECK_READONLY_RETURN_VOID();
+ error_code_ = error;
+}
+
+int CefResponseImpl::GetStatus() {
+ base::AutoLock lock_scope(lock_);
+ return status_code_;
+}
+
+void CefResponseImpl::SetStatus(int status) {
+ base::AutoLock lock_scope(lock_);
+ CHECK_READONLY_RETURN_VOID();
+ status_code_ = status;
+}
+
+CefString CefResponseImpl::GetStatusText() {
+ base::AutoLock lock_scope(lock_);
+ return status_text_;
+}
+
+void CefResponseImpl::SetStatusText(const CefString& statusText) {
+ base::AutoLock lock_scope(lock_);
+ CHECK_READONLY_RETURN_VOID();
+ status_text_ = statusText;
+}
+
+CefString CefResponseImpl::GetMimeType() {
+ base::AutoLock lock_scope(lock_);
+ return mime_type_;
+}
+
+void CefResponseImpl::SetMimeType(const CefString& mimeType) {
+ base::AutoLock lock_scope(lock_);
+ CHECK_READONLY_RETURN_VOID();
+ mime_type_ = mimeType;
+}
+
+CefString CefResponseImpl::GetCharset() {
+ base::AutoLock lock_scope(lock_);
+ return charset_;
+}
+
+void CefResponseImpl::SetCharset(const CefString& charset) {
+ base::AutoLock lock_scope(lock_);
+ CHECK_READONLY_RETURN_VOID();
+ charset_ = charset;
+}
+
+CefString CefResponseImpl::GetHeaderByName(const CefString& name) {
+ base::AutoLock lock_scope(lock_);
+
+ std::string nameLower = name;
+ HttpHeaderUtils::MakeASCIILower(&nameLower);
+
+ auto it = HttpHeaderUtils::FindHeaderInMap(nameLower, header_map_);
+ if (it != header_map_.end()) {
+ return it->second;
+ }
+
+ return CefString();
+}
+
+void CefResponseImpl::SetHeaderByName(const CefString& name,
+ const CefString& value,
+ bool overwrite) {
+ base::AutoLock lock_scope(lock_);
+ CHECK_READONLY_RETURN_VOID();
+
+ std::string nameLower = name;
+ HttpHeaderUtils::MakeASCIILower(&nameLower);
+
+ // There may be multiple values, so remove any first.
+ for (auto it = header_map_.begin(); it != header_map_.end();) {
+ if (base::EqualsCaseInsensitiveASCII(it->first.ToString(), nameLower)) {
+ if (!overwrite) {
+ return;
+ }
+ it = header_map_.erase(it);
+ } else {
+ ++it;
+ }
+ }
+
+ header_map_.insert(std::make_pair(name, value));
+}
+
+CefString CefResponseImpl::GetURL() {
+ base::AutoLock lock_scope(lock_);
+ return url_;
+}
+
+void CefResponseImpl::SetURL(const CefString& url) {
+ base::AutoLock lock_scope(lock_);
+ CHECK_READONLY_RETURN_VOID();
+ url_ = url;
+}
+
+void CefResponseImpl::GetHeaderMap(HeaderMap& map) {
+ base::AutoLock lock_scope(lock_);
+ map = header_map_;
+}
+
+void CefResponseImpl::SetHeaderMap(const HeaderMap& headerMap) {
+ base::AutoLock lock_scope(lock_);
+ CHECK_READONLY_RETURN_VOID();
+ header_map_ = headerMap;
+}
+
+scoped_refptr<net::HttpResponseHeaders> CefResponseImpl::GetResponseHeaders() {
+ base::AutoLock lock_scope(lock_);
+
+ std::string mime_type = mime_type_;
+ if (mime_type.empty()) {
+ mime_type = "text/html";
+ }
+
+ std::multimap<std::string, std::string> extra_headers;
+ for (const auto& pair : header_map_) {
+ extra_headers.insert(std::make_pair(pair.first, pair.second));
+ }
+
+ return net_service::MakeResponseHeaders(
+ status_code_, status_text_, mime_type, charset_, -1, extra_headers,
+ true /* allow_existing_header_override */);
+}
+
+void CefResponseImpl::SetResponseHeaders(
+ const net::HttpResponseHeaders& headers) {
+ base::AutoLock lock_scope(lock_);
+ CHECK_READONLY_RETURN_VOID();
+
+ header_map_.clear();
+
+ size_t iter = 0;
+ std::string name, value;
+ while (headers.EnumerateHeaderLines(&iter, &name, &value)) {
+ header_map_.insert(std::make_pair(name, value));
+ }
+
+ status_code_ = headers.response_code();
+ status_text_ = headers.GetStatusText();
+
+ if (headers.IsRedirect(nullptr)) {
+ // Don't report Content-Type header values for redirects.
+ mime_type_.clear();
+ charset_.clear();
+ } else {
+ std::string mime_type, charset;
+ headers.GetMimeTypeAndCharset(&mime_type, &charset);
+ mime_type_ = mime_type;
+ charset_ = charset;
+ }
+}
+
+void CefResponseImpl::Set(const blink::WebURLResponse& response) {
+ DCHECK(!response.IsNull());
+
+ base::AutoLock lock_scope(lock_);
+ CHECK_READONLY_RETURN_VOID();
+
+ blink::WebString str;
+ status_code_ = response.HttpStatusCode();
+ str = response.HttpStatusText();
+ status_text_ = str.Utf16();
+ str = response.MimeType();
+ mime_type_ = str.Utf16();
+ str = response.CurrentRequestUrl().GetString();
+ url_ = str.Utf16();
+
+ class HeaderVisitor : public blink::WebHTTPHeaderVisitor {
+ public:
+ explicit HeaderVisitor(HeaderMap* map) : map_(map) {}
+
+ void VisitHeader(const blink::WebString& name,
+ const blink::WebString& value) override {
+ map_->insert(std::make_pair(name.Utf16(), value.Utf16()));
+ }
+
+ private:
+ HeaderMap* map_;
+ };
+
+ HeaderVisitor visitor(&header_map_);
+ response.VisitHttpHeaderFields(&visitor);
+}
+
+void CefResponseImpl::SetReadOnly(bool read_only) {
+ base::AutoLock lock_scope(lock_);
+ read_only_ = read_only;
+}
diff --git a/libcef/common/response_impl.h b/libcef/common/response_impl.h
new file mode 100644
index 00000000..5dab4519
--- /dev/null
+++ b/libcef/common/response_impl.h
@@ -0,0 +1,69 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_COMMON_RESPONSE_IMPL_H_
+#define CEF_LIBCEF_COMMON_RESPONSE_IMPL_H_
+#pragma once
+
+#include "include/cef_response.h"
+
+#include "base/synchronization/lock.h"
+
+namespace net {
+class HttpResponseHeaders;
+} // namespace net
+
+namespace blink {
+class WebURLResponse;
+}
+
+// Implementation of CefResponse.
+class CefResponseImpl : public CefResponse {
+ public:
+ CefResponseImpl();
+
+ // CefResponse methods.
+ bool IsReadOnly() override;
+ cef_errorcode_t GetError() override;
+ void SetError(cef_errorcode_t error) override;
+ int GetStatus() override;
+ void SetStatus(int status) override;
+ CefString GetStatusText() override;
+ void SetStatusText(const CefString& statusText) override;
+ CefString GetMimeType() override;
+ void SetMimeType(const CefString& mimeType) override;
+ CefString GetCharset() override;
+ void SetCharset(const CefString& charset) override;
+ CefString GetHeaderByName(const CefString& name) override;
+ void SetHeaderByName(const CefString& name,
+ const CefString& value,
+ bool overwrite) override;
+ void GetHeaderMap(HeaderMap& headerMap) override;
+ void SetHeaderMap(const HeaderMap& headerMap) override;
+ CefString GetURL() override;
+ void SetURL(const CefString& url) override;
+
+ scoped_refptr<net::HttpResponseHeaders> GetResponseHeaders();
+ void SetResponseHeaders(const net::HttpResponseHeaders& headers);
+
+ void Set(const blink::WebURLResponse& response);
+
+ void SetReadOnly(bool read_only);
+
+ protected:
+ cef_errorcode_t error_code_;
+ int status_code_;
+ CefString status_text_;
+ CefString mime_type_;
+ CefString charset_;
+ CefString url_;
+ HeaderMap header_map_;
+ bool read_only_;
+
+ base::Lock lock_;
+
+ IMPLEMENT_REFCOUNTING(CefResponseImpl);
+};
+
+#endif // CEF_LIBCEF_COMMON_RESPONSE_IMPL_H_
diff --git a/libcef/common/scheme_registrar_impl.cc b/libcef/common/scheme_registrar_impl.cc
new file mode 100644
index 00000000..a31734f7
--- /dev/null
+++ b/libcef/common/scheme_registrar_impl.cc
@@ -0,0 +1,81 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#include "libcef/common/scheme_registrar_impl.h"
+
+#include <string>
+
+#include "libcef/common/app_manager.h"
+#include "libcef/common/net/scheme_info.h"
+#include "libcef/common/net/scheme_registration.h"
+
+#include "base/functional/bind.h"
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+
+namespace {
+
+void AppendArray(const std::vector<std::string>& source,
+ std::vector<std::string>* target) {
+ if (source.empty()) {
+ return;
+ }
+ target->insert(target->end(), source.begin(), source.end());
+}
+} // namespace
+
+CefSchemeRegistrarImpl::CefSchemeRegistrarImpl() {}
+
+bool CefSchemeRegistrarImpl::AddCustomScheme(const CefString& scheme_name,
+ int options) {
+ const std::string& scheme = base::ToLowerASCII(scheme_name.ToString());
+ if (scheme::IsInternalHandledScheme(scheme) ||
+ registered_schemes_.find(scheme) != registered_schemes_.end()) {
+ return false;
+ }
+
+ registered_schemes_.insert(scheme);
+
+ const bool is_standard = options & CEF_SCHEME_OPTION_STANDARD;
+ const bool is_local = options & CEF_SCHEME_OPTION_LOCAL;
+ const bool is_display_isolated = options & CEF_SCHEME_OPTION_DISPLAY_ISOLATED;
+ const bool is_secure = options & CEF_SCHEME_OPTION_SECURE;
+ const bool is_cors_enabled = options & CEF_SCHEME_OPTION_CORS_ENABLED;
+ const bool is_csp_bypassing = options & CEF_SCHEME_OPTION_CSP_BYPASSING;
+ const bool is_fetch_enabled = options & CEF_SCHEME_OPTION_FETCH_ENABLED;
+
+ // The |is_display_isolated| value is excluded here because it's registered
+ // with Blink only.
+ if (is_standard) {
+ schemes_.standard_schemes.push_back(scheme);
+ }
+ if (is_local) {
+ schemes_.local_schemes.push_back(scheme);
+ }
+ if (is_secure) {
+ schemes_.secure_schemes.push_back(scheme);
+ }
+ if (is_cors_enabled) {
+ schemes_.cors_enabled_schemes.push_back(scheme);
+ }
+ if (is_csp_bypassing) {
+ schemes_.csp_bypassing_schemes.push_back(scheme);
+ }
+
+ CefSchemeInfo scheme_info = {
+ scheme, is_standard, is_local, is_display_isolated,
+ is_secure, is_cors_enabled, is_csp_bypassing, is_fetch_enabled};
+ CefAppManager::Get()->AddCustomScheme(&scheme_info);
+
+ return true;
+}
+
+void CefSchemeRegistrarImpl::GetSchemes(
+ content::ContentClient::Schemes* schemes) {
+ AppendArray(schemes_.standard_schemes, &schemes->standard_schemes);
+ AppendArray(schemes_.local_schemes, &schemes->local_schemes);
+ AppendArray(schemes_.secure_schemes, &schemes->secure_schemes);
+ AppendArray(schemes_.cors_enabled_schemes, &schemes->cors_enabled_schemes);
+ AppendArray(schemes_.csp_bypassing_schemes, &schemes->csp_bypassing_schemes);
+}
diff --git a/libcef/common/scheme_registrar_impl.h b/libcef/common/scheme_registrar_impl.h
new file mode 100644
index 00000000..375b437d
--- /dev/null
+++ b/libcef/common/scheme_registrar_impl.h
@@ -0,0 +1,33 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_COMMON_SCHEME_REGISTRAR_IMPL_H_
+#define CEF_LIBCEF_COMMON_SCHEME_REGISTRAR_IMPL_H_
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include "include/cef_scheme.h"
+
+#include "content/public/common/content_client.h"
+
+class CefSchemeRegistrarImpl : public CefSchemeRegistrar {
+ public:
+ CefSchemeRegistrarImpl();
+
+ CefSchemeRegistrarImpl(const CefSchemeRegistrarImpl&) = delete;
+ CefSchemeRegistrarImpl& operator=(const CefSchemeRegistrarImpl&) = delete;
+
+ // CefSchemeRegistrar methods.
+ bool AddCustomScheme(const CefString& scheme_name, int options) override;
+
+ void GetSchemes(content::ContentClient::Schemes* schemes);
+
+ private:
+ content::ContentClient::Schemes schemes_;
+ std::set<std::string> registered_schemes_;
+};
+
+#endif // CEF_LIBCEF_COMMON_SCHEME_REGISTRAR_IMPL_H_
diff --git a/libcef/common/string_list_impl.cc b/libcef/common/string_list_impl.cc
new file mode 100644
index 00000000..02c95653
--- /dev/null
+++ b/libcef/common/string_list_impl.cc
@@ -0,0 +1,62 @@
+// Copyright (c) 2009 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include <vector>
+
+#include "include/internal/cef_string_list.h"
+
+#include "base/logging.h"
+
+namespace {
+using StringList = std::vector<CefString>;
+} // namespace
+
+CEF_EXPORT cef_string_list_t cef_string_list_alloc() {
+ return new StringList;
+}
+
+CEF_EXPORT size_t cef_string_list_size(cef_string_list_t list) {
+ DCHECK(list);
+ StringList* impl = reinterpret_cast<StringList*>(list);
+ return impl->size();
+}
+
+CEF_EXPORT int cef_string_list_value(cef_string_list_t list,
+ size_t index,
+ cef_string_t* value) {
+ DCHECK(list);
+ DCHECK(value);
+ StringList* impl = reinterpret_cast<StringList*>(list);
+ DCHECK_LT(index, impl->size());
+ if (index >= impl->size()) {
+ return false;
+ }
+ const CefString& str = (*impl)[index];
+ return cef_string_copy(str.c_str(), str.length(), value);
+}
+
+CEF_EXPORT void cef_string_list_append(cef_string_list_t list,
+ const cef_string_t* value) {
+ DCHECK(list);
+ StringList* impl = reinterpret_cast<StringList*>(list);
+ impl->push_back(CefString(value));
+}
+
+CEF_EXPORT void cef_string_list_clear(cef_string_list_t list) {
+ DCHECK(list);
+ StringList* impl = reinterpret_cast<StringList*>(list);
+ impl->clear();
+}
+
+CEF_EXPORT void cef_string_list_free(cef_string_list_t list) {
+ DCHECK(list);
+ StringList* impl = reinterpret_cast<StringList*>(list);
+ delete impl;
+}
+
+CEF_EXPORT cef_string_list_t cef_string_list_copy(cef_string_list_t list) {
+ DCHECK(list);
+ StringList* impl = reinterpret_cast<StringList*>(list);
+ return new StringList(*impl);
+}
diff --git a/libcef/common/string_map_impl.cc b/libcef/common/string_map_impl.cc
new file mode 100644
index 00000000..e95dbd09
--- /dev/null
+++ b/libcef/common/string_map_impl.cc
@@ -0,0 +1,100 @@
+// Copyright (c) 2009 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include <map>
+
+#include "include/internal/cef_string_map.h"
+
+#include "base/logging.h"
+
+namespace {
+using StringMap = std::map<CefString, CefString>;
+} // namespace
+
+CEF_EXPORT cef_string_map_t cef_string_map_alloc() {
+ return new StringMap;
+}
+
+CEF_EXPORT size_t cef_string_map_size(cef_string_map_t map) {
+ DCHECK(map);
+ StringMap* impl = reinterpret_cast<StringMap*>(map);
+ return impl->size();
+}
+
+CEF_EXPORT int cef_string_map_find(cef_string_map_t map,
+ const cef_string_t* key,
+ cef_string_t* value) {
+ DCHECK(map);
+ DCHECK(value);
+ StringMap* impl = reinterpret_cast<StringMap*>(map);
+ StringMap::const_iterator it = impl->find(CefString(key));
+ if (it == impl->end()) {
+ return 0;
+ }
+
+ const CefString& val = it->second;
+ return cef_string_set(val.c_str(), val.length(), value, true);
+}
+
+CEF_EXPORT int cef_string_map_key(cef_string_map_t map,
+ size_t index,
+ cef_string_t* key) {
+ DCHECK(map);
+ DCHECK(key);
+ StringMap* impl = reinterpret_cast<StringMap*>(map);
+ DCHECK_LT(index, impl->size());
+ if (index >= impl->size()) {
+ return 0;
+ }
+
+ StringMap::const_iterator it = impl->begin();
+ for (size_t ct = 0; it != impl->end(); ++it, ct++) {
+ if (ct == index) {
+ return cef_string_set(it->first.c_str(), it->first.length(), key, true);
+ }
+ }
+ return 0;
+}
+
+CEF_EXPORT int cef_string_map_value(cef_string_map_t map,
+ size_t index,
+ cef_string_t* value) {
+ DCHECK(map);
+ DCHECK(value);
+ StringMap* impl = reinterpret_cast<StringMap*>(map);
+ DCHECK_LT(index, impl->size());
+ if (index >= impl->size()) {
+ return 0;
+ }
+
+ StringMap::const_iterator it = impl->begin();
+ for (size_t ct = 0; it != impl->end(); ++it, ct++) {
+ if (ct == index) {
+ return cef_string_set(it->second.c_str(), it->second.length(), value,
+ true);
+ }
+ }
+ return 0;
+}
+
+CEF_EXPORT int cef_string_map_append(cef_string_map_t map,
+ const cef_string_t* key,
+ const cef_string_t* value) {
+ DCHECK(map);
+ StringMap* impl = reinterpret_cast<StringMap*>(map);
+ impl->insert(std::make_pair(CefString(key), CefString(value)));
+ return 1;
+}
+
+CEF_EXPORT void cef_string_map_clear(cef_string_map_t map) {
+ DCHECK(map);
+ StringMap* impl = reinterpret_cast<StringMap*>(map);
+ impl->clear();
+}
+
+CEF_EXPORT void cef_string_map_free(cef_string_map_t map) {
+ DCHECK(map);
+ StringMap* impl = reinterpret_cast<StringMap*>(map);
+ delete impl;
+}
diff --git a/libcef/common/string_multimap_impl.cc b/libcef/common/string_multimap_impl.cc
new file mode 100644
index 00000000..24ff2307
--- /dev/null
+++ b/libcef/common/string_multimap_impl.cc
@@ -0,0 +1,125 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include <map>
+
+#include "include/internal/cef_string_multimap.h"
+
+#include "base/logging.h"
+
+namespace {
+using StringMultimap = std::multimap<CefString, CefString>;
+} // namespace
+
+CEF_EXPORT cef_string_multimap_t cef_string_multimap_alloc() {
+ return new StringMultimap;
+}
+
+CEF_EXPORT size_t cef_string_multimap_size(cef_string_multimap_t map) {
+ DCHECK(map);
+ StringMultimap* impl = reinterpret_cast<StringMultimap*>(map);
+ return impl->size();
+}
+
+CEF_EXPORT size_t cef_string_multimap_find_count(cef_string_multimap_t map,
+ const cef_string_t* key) {
+ DCHECK(map);
+ DCHECK(key);
+ StringMultimap* impl = reinterpret_cast<StringMultimap*>(map);
+ return impl->count(CefString(key));
+}
+
+CEF_EXPORT int cef_string_multimap_enumerate(cef_string_multimap_t map,
+ const cef_string_t* key,
+ size_t value_index,
+ cef_string_t* value) {
+ DCHECK(map);
+ DCHECK(key);
+ DCHECK(value);
+
+ StringMultimap* impl = reinterpret_cast<StringMultimap*>(map);
+ CefString key_str(key);
+
+ DCHECK_LT(value_index, impl->count(key_str));
+ if (value_index >= impl->count(key_str)) {
+ return 0;
+ }
+
+ std::pair<StringMultimap::iterator, StringMultimap::iterator> range_it =
+ impl->equal_range(key_str);
+
+ size_t count = value_index;
+ while (count-- && range_it.first != range_it.second) {
+ range_it.first++;
+ }
+
+ if (range_it.first == range_it.second) {
+ return 0;
+ }
+
+ const CefString& val = range_it.first->second;
+ return cef_string_set(val.c_str(), val.length(), value, true);
+}
+
+CEF_EXPORT int cef_string_multimap_key(cef_string_multimap_t map,
+ size_t index,
+ cef_string_t* key) {
+ DCHECK(map);
+ DCHECK(key);
+ StringMultimap* impl = reinterpret_cast<StringMultimap*>(map);
+ DCHECK_LT(index, impl->size());
+ if (index >= impl->size()) {
+ return 0;
+ }
+
+ StringMultimap::const_iterator it = impl->begin();
+ for (size_t ct = 0; it != impl->end(); ++it, ct++) {
+ if (ct == index) {
+ return cef_string_set(it->first.c_str(), it->first.length(), key, true);
+ }
+ }
+ return 0;
+}
+
+CEF_EXPORT int cef_string_multimap_value(cef_string_multimap_t map,
+ size_t index,
+ cef_string_t* value) {
+ DCHECK(map);
+ DCHECK(value);
+ StringMultimap* impl = reinterpret_cast<StringMultimap*>(map);
+ DCHECK_LT(index, impl->size());
+ if (index >= impl->size()) {
+ return 0;
+ }
+
+ StringMultimap::const_iterator it = impl->begin();
+ for (size_t ct = 0; it != impl->end(); ++it, ct++) {
+ if (ct == index) {
+ return cef_string_set(it->second.c_str(), it->second.length(), value,
+ true);
+ }
+ }
+ return 0;
+}
+
+CEF_EXPORT int cef_string_multimap_append(cef_string_multimap_t map,
+ const cef_string_t* key,
+ const cef_string_t* value) {
+ DCHECK(map);
+ StringMultimap* impl = reinterpret_cast<StringMultimap*>(map);
+ impl->insert(std::make_pair(CefString(key), CefString(value)));
+ return 1;
+}
+
+CEF_EXPORT void cef_string_multimap_clear(cef_string_multimap_t map) {
+ DCHECK(map);
+ StringMultimap* impl = reinterpret_cast<StringMultimap*>(map);
+ impl->clear();
+}
+
+CEF_EXPORT void cef_string_multimap_free(cef_string_multimap_t map) {
+ DCHECK(map);
+ StringMultimap* impl = reinterpret_cast<StringMultimap*>(map);
+ delete impl;
+}
diff --git a/libcef/common/string_types_impl.cc b/libcef/common/string_types_impl.cc
new file mode 100644
index 00000000..84cc8131
--- /dev/null
+++ b/libcef/common/string_types_impl.cc
@@ -0,0 +1,336 @@
+// Copyright (c) 2010 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include <algorithm>
+
+#include "include/internal/cef_string_types.h"
+
+#include "base/i18n/case_conversion.h"
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+
+namespace {
+
+void string_wide_dtor(wchar_t* str) {
+ delete[] str;
+}
+
+void string_utf8_dtor(char* str) {
+ delete[] str;
+}
+
+void string_utf16_dtor(char16* str) {
+ delete[] str;
+}
+
+// Originally from base/strings/utf_string_conversions.cc
+std::wstring ASCIIToWide(const base::StringPiece& ascii) {
+ DCHECK(base::IsStringASCII(ascii)) << ascii;
+ return std::wstring(ascii.begin(), ascii.end());
+}
+
+} // namespace
+
+CEF_EXPORT int cef_string_wide_set(const wchar_t* src,
+ size_t src_len,
+ cef_string_wide_t* output,
+ int copy) {
+ cef_string_wide_clear(output);
+
+ if (copy) {
+ if (src && src_len > 0) {
+ output->str = new wchar_t[src_len + 1];
+ if (!output->str) {
+ return 0;
+ }
+
+ memcpy(output->str, src, src_len * sizeof(wchar_t));
+ output->str[src_len] = 0;
+ output->length = src_len;
+ output->dtor = string_wide_dtor;
+ }
+ } else {
+ output->str = const_cast<wchar_t*>(src);
+ output->length = src_len;
+ output->dtor = nullptr;
+ }
+ return 1;
+}
+
+CEF_EXPORT int cef_string_utf8_set(const char* src,
+ size_t src_len,
+ cef_string_utf8_t* output,
+ int copy) {
+ cef_string_utf8_clear(output);
+ if (copy) {
+ if (src && src_len > 0) {
+ output->str = new char[src_len + 1];
+ if (!output->str) {
+ return 0;
+ }
+
+ memcpy(output->str, src, src_len * sizeof(char));
+ output->str[src_len] = 0;
+ output->length = src_len;
+ output->dtor = string_utf8_dtor;
+ }
+ } else {
+ output->str = const_cast<char*>(src);
+ output->length = src_len;
+ output->dtor = nullptr;
+ }
+ return 1;
+}
+
+CEF_EXPORT int cef_string_utf16_set(const char16* src,
+ size_t src_len,
+ cef_string_utf16_t* output,
+ int copy) {
+ cef_string_utf16_clear(output);
+
+ if (copy) {
+ if (src && src_len > 0) {
+ output->str = new char16[src_len + 1];
+ if (!output->str) {
+ return 0;
+ }
+
+ memcpy(output->str, src, src_len * sizeof(char16));
+ output->str[src_len] = 0;
+ output->length = src_len;
+ output->dtor = string_utf16_dtor;
+ }
+ } else {
+ output->str = const_cast<char16*>(src);
+ output->length = src_len;
+ output->dtor = nullptr;
+ }
+ return 1;
+}
+
+CEF_EXPORT void cef_string_wide_clear(cef_string_wide_t* str) {
+ DCHECK(str != nullptr);
+ if (str->dtor && str->str) {
+ str->dtor(str->str);
+ }
+
+ str->str = nullptr;
+ str->length = 0;
+ str->dtor = nullptr;
+}
+
+CEF_EXPORT void cef_string_utf8_clear(cef_string_utf8_t* str) {
+ DCHECK(str != nullptr);
+ if (str->dtor && str->str) {
+ str->dtor(str->str);
+ }
+
+ str->str = nullptr;
+ str->length = 0;
+ str->dtor = nullptr;
+}
+
+CEF_EXPORT void cef_string_utf16_clear(cef_string_utf16_t* str) {
+ DCHECK(str != nullptr);
+ if (str->dtor && str->str) {
+ str->dtor(str->str);
+ }
+
+ str->str = nullptr;
+ str->length = 0;
+ str->dtor = nullptr;
+}
+
+CEF_EXPORT int cef_string_wide_cmp(const cef_string_wide_t* str1,
+ const cef_string_wide_t* str2) {
+ if (str1->length == 0 && str2->length == 0) {
+ return 0;
+ }
+ int r = wcsncmp(str1->str, str2->str, std::min(str1->length, str2->length));
+ if (r == 0) {
+ if (str1->length > str2->length) {
+ return 1;
+ } else if (str1->length < str2->length) {
+ return -1;
+ }
+ }
+ return r;
+}
+
+CEF_EXPORT int cef_string_utf8_cmp(const cef_string_utf8_t* str1,
+ const cef_string_utf8_t* str2) {
+ if (str1->length == 0 && str2->length == 0) {
+ return 0;
+ }
+ int r = strncmp(str1->str, str2->str, std::min(str1->length, str2->length));
+ if (r == 0) {
+ if (str1->length > str2->length) {
+ return 1;
+ } else if (str1->length < str2->length) {
+ return -1;
+ }
+ }
+ return r;
+}
+
+CEF_EXPORT int cef_string_utf16_cmp(const cef_string_utf16_t* str1,
+ const cef_string_utf16_t* str2) {
+ if (str1->length == 0 && str2->length == 0) {
+ return 0;
+ }
+#if defined(WCHAR_T_IS_UTF32)
+ int r = std::char_traits<std::u16string::value_type>::compare(
+ reinterpret_cast<std::u16string::value_type*>(str1->str),
+ reinterpret_cast<std::u16string::value_type*>(str2->str),
+ std::min(str1->length, str2->length));
+#else
+ int r = wcsncmp(str1->str, str2->str, std::min(str1->length, str2->length));
+#endif
+ if (r == 0) {
+ if (str1->length > str2->length) {
+ return 1;
+ } else if (str1->length < str2->length) {
+ return -1;
+ }
+ }
+ return r;
+}
+
+CEF_EXPORT int cef_string_wide_to_utf8(const wchar_t* src,
+ size_t src_len,
+ cef_string_utf8_t* output) {
+ std::string str;
+ bool ret = base::WideToUTF8(src, src_len, &str);
+ if (!cef_string_utf8_set(str.c_str(), str.length(), output, true)) {
+ return false;
+ }
+ return ret;
+}
+
+CEF_EXPORT int cef_string_utf8_to_wide(const char* src,
+ size_t src_len,
+ cef_string_wide_t* output) {
+ std::wstring str;
+ bool ret = base::UTF8ToWide(src, src_len, &str);
+ if (!cef_string_wide_set(str.c_str(), str.length(), output, true)) {
+ return false;
+ }
+ return ret;
+}
+
+CEF_EXPORT int cef_string_wide_to_utf16(const wchar_t* src,
+ size_t src_len,
+ cef_string_utf16_t* output) {
+ std::u16string str;
+ bool ret = base::WideToUTF16(src, src_len, &str);
+ if (!cef_string_utf16_set(reinterpret_cast<const char16*>(str.c_str()),
+ str.length(), output, true)) {
+ return false;
+ }
+ return ret;
+}
+
+CEF_EXPORT int cef_string_utf16_to_wide(const char16* src,
+ size_t src_len,
+ cef_string_wide_t* output) {
+ std::wstring str;
+ bool ret = base::UTF16ToWide(
+ reinterpret_cast<const std::u16string::value_type*>(src), src_len, &str);
+ if (!cef_string_wide_set(str.c_str(), str.length(), output, true)) {
+ return false;
+ }
+ return ret;
+}
+
+CEF_EXPORT int cef_string_utf8_to_utf16(const char* src,
+ size_t src_len,
+ cef_string_utf16_t* output) {
+ std::u16string str;
+ bool ret = base::UTF8ToUTF16(src, src_len, &str);
+ if (!cef_string_utf16_set(reinterpret_cast<const char16*>(str.c_str()),
+ str.length(), output, true)) {
+ return false;
+ }
+ return ret;
+}
+
+CEF_EXPORT int cef_string_utf16_to_utf8(const char16* src,
+ size_t src_len,
+ cef_string_utf8_t* output) {
+ std::string str;
+ bool ret = base::UTF16ToUTF8(
+ reinterpret_cast<const std::u16string::value_type*>(src), src_len, &str);
+ if (!cef_string_utf8_set(str.c_str(), str.length(), output, true)) {
+ return false;
+ }
+ return ret;
+}
+
+CEF_EXPORT int cef_string_ascii_to_wide(const char* src,
+ size_t src_len,
+ cef_string_wide_t* output) {
+ const std::wstring& str = ASCIIToWide(std::string(src, src_len));
+ return cef_string_wide_set(str.c_str(), str.length(), output, true);
+}
+
+CEF_EXPORT int cef_string_ascii_to_utf16(const char* src,
+ size_t src_len,
+ cef_string_utf16_t* output) {
+ const std::u16string& str = base::ASCIIToUTF16(std::string(src, src_len));
+ return cef_string_utf16_set(reinterpret_cast<const char16*>(str.c_str()),
+ str.length(), output, true);
+}
+
+CEF_EXPORT cef_string_userfree_wide_t cef_string_userfree_wide_alloc() {
+ cef_string_wide_t* s = new cef_string_wide_t;
+ memset(s, 0, sizeof(cef_string_wide_t));
+ return s;
+}
+
+CEF_EXPORT cef_string_userfree_utf8_t cef_string_userfree_utf8_alloc() {
+ cef_string_utf8_t* s = new cef_string_utf8_t;
+ memset(s, 0, sizeof(cef_string_utf8_t));
+ return s;
+}
+
+CEF_EXPORT cef_string_userfree_utf16_t cef_string_userfree_utf16_alloc() {
+ cef_string_utf16_t* s = new cef_string_utf16_t;
+ memset(s, 0, sizeof(cef_string_utf16_t));
+ return s;
+}
+
+CEF_EXPORT void cef_string_userfree_wide_free(cef_string_userfree_wide_t str) {
+ cef_string_wide_clear(str);
+ delete str;
+}
+
+CEF_EXPORT void cef_string_userfree_utf8_free(cef_string_userfree_utf8_t str) {
+ cef_string_utf8_clear(str);
+ delete str;
+}
+
+CEF_EXPORT void cef_string_userfree_utf16_free(
+ cef_string_userfree_utf16_t str) {
+ cef_string_utf16_clear(str);
+ delete str;
+}
+
+CEF_EXPORT int cef_string_utf16_to_lower(const char16* src,
+ size_t src_len,
+ cef_string_utf16_t* output) {
+ const std::u16string& str = base::i18n::ToLower(std::u16string(
+ reinterpret_cast<const std::u16string::value_type*>(src), src_len));
+ return cef_string_utf16_set(reinterpret_cast<const char16*>(str.c_str()),
+ str.length(), output, true);
+}
+
+CEF_EXPORT int cef_string_utf16_to_upper(const char16* src,
+ size_t src_len,
+ cef_string_utf16_t* output) {
+ const std::u16string& str = base::i18n::ToUpper(std::u16string(
+ reinterpret_cast<const std::u16string::value_type*>(src), src_len));
+ return cef_string_utf16_set(reinterpret_cast<const char16*>(str.c_str()),
+ str.length(), output, true);
+}
diff --git a/libcef/common/string_util.cc b/libcef/common/string_util.cc
new file mode 100644
index 00000000..bb187797
--- /dev/null
+++ b/libcef/common/string_util.cc
@@ -0,0 +1,72 @@
+// Copyright 2021 The Chromium Embedded Framework Authors. Portions copyright
+// 2011 The Chromium Authors. All rights reserved. Use of this source code is
+// governed by a BSD-style license that can be found in the LICENSE file.
+
+#include "libcef/common/string_util.h"
+
+#include "base/memory/read_only_shared_memory_region.h"
+#include "base/memory/ref_counted_memory.h"
+#include "third_party/blink/public/platform/web_string.h"
+
+namespace string_util {
+
+void GetCefString(const blink::WebString& source, CefString& cef_string) {
+#if defined(CEF_STRING_TYPE_UTF8)
+ cef_string.FromString(source.Utf8());
+#else
+ cef_string.FromString16(source.Utf16());
+#endif
+}
+
+void GetCefString(scoped_refptr<base::RefCountedMemory> source,
+ CefString& cef_string) {
+ if (source && source->size() > 0U) {
+#if defined(CEF_STRING_TYPE_UTF8) || defined(CEF_STRING_TYPE_UTF16)
+ // Reference existing UTF8 or UTF16 data.
+ cef_string.FromString(source->front_as<CefString::char_type>(),
+ source->size() / sizeof(CefString::char_type),
+ /*copy=*/false);
+#else
+ // Must convert from UTF16.
+ cef_string.FromString16(
+ source->front_as<std::u16string::value_type>(),
+ source->size() / sizeof(std::u16string::value_type));
+#endif
+ } else {
+ cef_string.clear();
+ }
+}
+
+base::ReadOnlySharedMemoryRegion CreateSharedMemoryRegion(
+ const blink::WebString& source) {
+ base::ReadOnlySharedMemoryRegion region;
+
+ if (!source.IsEmpty()) {
+#if defined(CEF_STRING_TYPE_UTF8)
+ const std::string& string = source.Utf8();
+ const size_t byte_size = string.length();
+#else
+ const std::u16string& string = source.Utf16();
+ const size_t byte_size =
+ string.length() * sizeof(std::u16string::value_type);
+#endif
+ auto mapped_region = base::ReadOnlySharedMemoryRegion::Create(byte_size);
+ if (mapped_region.IsValid()) {
+ memcpy(mapped_region.mapping.memory(), string.data(), byte_size);
+ region = std::move(mapped_region.region);
+ }
+ }
+
+ return region;
+}
+
+void ExecuteWithScopedCefString(base::ReadOnlySharedMemoryRegion region,
+ ScopedCefStringCallback callback) {
+ auto shared_buf =
+ base::RefCountedSharedMemoryMapping::CreateFromWholeRegion(region);
+ CefString str;
+ GetCefString(shared_buf, str);
+ std::move(callback).Run(str);
+}
+
+} // namespace string_util \ No newline at end of file
diff --git a/libcef/common/string_util.h b/libcef/common/string_util.h
new file mode 100644
index 00000000..f9727653
--- /dev/null
+++ b/libcef/common/string_util.h
@@ -0,0 +1,44 @@
+// Copyright 2021 The Chromium Embedded Framework Authors. Portions copyright
+// 2011 The Chromium Authors. All rights reserved. Use of this source code is
+// governed by a BSD-style license that can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_COMMON_STRING_UTIL_H_
+#define CEF_LIBCEF_COMMON_STRING_UTIL_H_
+#pragma once
+
+#include "include/cef_base.h"
+
+#include "base/functional/callback.h"
+#include "base/memory/scoped_refptr.h"
+
+namespace base {
+class ReadOnlySharedMemoryRegion;
+class RefCountedMemory;
+} // namespace base
+
+namespace blink {
+class WebString;
+}
+
+namespace string_util {
+
+// Convert |source| to |cef_string|, avoiding UTF conversions if possible.
+void GetCefString(const blink::WebString& source, CefString& cef_string);
+void GetCefString(scoped_refptr<base::RefCountedMemory> source,
+ CefString& cef_string);
+
+// Read |source| into shared memory, avoiding UTF conversions if possible.
+// Use ExecuteWithScopedCefString() to retrieve the value on the receiving end
+// with zero UTF conversions and zero copies if possible.
+base::ReadOnlySharedMemoryRegion CreateSharedMemoryRegion(
+ const blink::WebString& source);
+
+using ScopedCefStringCallback = base::OnceCallback<void(const CefString&)>;
+
+// Helper for executing |callback| with |region| as a scoped CefString.
+void ExecuteWithScopedCefString(base::ReadOnlySharedMemoryRegion region,
+ ScopedCefStringCallback callback);
+
+} // namespace string_util
+
+#endif // CEF_LIBCEF_COMMON_STRING_UTIL_H_
diff --git a/libcef/common/task_impl.cc b/libcef/common/task_impl.cc
new file mode 100644
index 00000000..6e3bc087
--- /dev/null
+++ b/libcef/common/task_impl.cc
@@ -0,0 +1,49 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#include "include/cef_task.h"
+#include "libcef/common/task_runner_impl.h"
+
+#include "base/functional/bind.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/time/time.h"
+
+bool CefCurrentlyOn(CefThreadId threadId) {
+ scoped_refptr<base::SequencedTaskRunner> task_runner =
+ CefTaskRunnerImpl::GetTaskRunner(threadId);
+ if (task_runner.get()) {
+ return task_runner->RunsTasksInCurrentSequence();
+ }
+
+ LOG(WARNING) << "No task runner for threadId " << threadId;
+ return false;
+}
+
+bool CefPostTask(CefThreadId threadId, CefRefPtr<CefTask> task) {
+ scoped_refptr<base::SequencedTaskRunner> task_runner =
+ CefTaskRunnerImpl::GetTaskRunner(threadId);
+ if (task_runner.get()) {
+ return task_runner->PostTask(FROM_HERE,
+ base::BindOnce(&CefTask::Execute, task.get()));
+ }
+
+ LOG(WARNING) << "No task runner for threadId " << threadId;
+ return false;
+}
+
+bool CefPostDelayedTask(CefThreadId threadId,
+ CefRefPtr<CefTask> task,
+ int64 delay_ms) {
+ scoped_refptr<base::SequencedTaskRunner> task_runner =
+ CefTaskRunnerImpl::GetTaskRunner(threadId);
+ if (task_runner.get()) {
+ return task_runner->PostDelayedTask(
+ FROM_HERE, base::BindOnce(&CefTask::Execute, task.get()),
+ base::Milliseconds(delay_ms));
+ }
+
+ LOG(WARNING) << "No task runner for threadId " << threadId;
+ return false;
+}
diff --git a/libcef/common/task_runner_impl.cc b/libcef/common/task_runner_impl.cc
new file mode 100644
index 00000000..fe5b260d
--- /dev/null
+++ b/libcef/common/task_runner_impl.cc
@@ -0,0 +1,146 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "libcef/common/task_runner_impl.h"
+
+#include "libcef/common/task_runner_manager.h"
+
+#include "base/functional/bind.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/task/single_thread_task_runner.h"
+#include "base/task/thread_pool.h"
+#include "base/time/time.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/child_process_launcher_utils.h"
+
+using content::BrowserThread;
+
+// CefTaskRunner
+
+// static
+CefRefPtr<CefTaskRunner> CefTaskRunner::GetForCurrentThread() {
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner =
+ CefTaskRunnerImpl::GetCurrentTaskRunner();
+ if (task_runner.get()) {
+ return new CefTaskRunnerImpl(task_runner);
+ }
+ return nullptr;
+}
+
+// static
+CefRefPtr<CefTaskRunner> CefTaskRunner::GetForThread(CefThreadId threadId) {
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner =
+ CefTaskRunnerImpl::GetTaskRunner(threadId);
+ if (task_runner.get()) {
+ return new CefTaskRunnerImpl(task_runner);
+ }
+
+ LOG(WARNING) << "Invalid thread id " << threadId;
+ return nullptr;
+}
+
+// CefTaskRunnerImpl
+
+CefTaskRunnerImpl::CefTaskRunnerImpl(
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner)
+ : task_runner_(task_runner) {
+ DCHECK(task_runner_.get());
+}
+
+// static
+scoped_refptr<base::SingleThreadTaskRunner> CefTaskRunnerImpl::GetTaskRunner(
+ CefThreadId threadId) {
+ auto* manager = CefTaskRunnerManager::Get();
+ if (!manager) {
+ return nullptr;
+ }
+
+ switch (threadId) {
+ case TID_UI:
+ if (BrowserThread::IsThreadInitialized(BrowserThread::UI)) {
+ return content::GetUIThreadTaskRunner({});
+ }
+ break;
+ case TID_FILE_BACKGROUND:
+ return manager->GetBackgroundTaskRunner();
+ case TID_FILE_USER_VISIBLE:
+ return manager->GetUserVisibleTaskRunner();
+ case TID_FILE_USER_BLOCKING:
+ return manager->GetUserBlockingTaskRunner();
+ case TID_PROCESS_LAUNCHER:
+ return content::GetProcessLauncherTaskRunner();
+ case TID_IO:
+ if (BrowserThread::IsThreadInitialized(BrowserThread::IO)) {
+ return content::GetIOThreadTaskRunner({});
+ }
+ break;
+ case TID_RENDERER:
+ return manager->GetRenderTaskRunner();
+ default:
+ break;
+ };
+
+ return nullptr;
+}
+
+// static
+scoped_refptr<base::SingleThreadTaskRunner>
+CefTaskRunnerImpl::GetCurrentTaskRunner() {
+ auto* manager = CefTaskRunnerManager::Get();
+ if (!manager) {
+ return nullptr;
+ }
+
+ // For named browser process threads return the same TaskRunner as
+ // GetTaskRunner(). Otherwise BelongsToThread() will return incorrect results.
+ BrowserThread::ID current_id;
+ if (BrowserThread::GetCurrentThreadIdentifier(&current_id) &&
+ BrowserThread::IsThreadInitialized(current_id)) {
+ if (current_id == BrowserThread::UI) {
+ return content::GetUIThreadTaskRunner({});
+ } else if (current_id == BrowserThread::IO) {
+ return content::GetIOThreadTaskRunner({});
+ } else {
+ NOTREACHED();
+ }
+ }
+
+ // Check for a MessageLoopProxy. This covers all of the named browser and
+ // render process threads, plus a few extra.
+ if (auto task_runner = base::SingleThreadTaskRunner::GetCurrentDefault()) {
+ return task_runner;
+ }
+
+ // Check for a WebWorker thread.
+ return manager->GetWebWorkerTaskRunner();
+}
+
+bool CefTaskRunnerImpl::IsSame(CefRefPtr<CefTaskRunner> that) {
+ CefTaskRunnerImpl* impl = static_cast<CefTaskRunnerImpl*>(that.get());
+ return (impl && task_runner_ == impl->task_runner_);
+}
+
+bool CefTaskRunnerImpl::BelongsToCurrentThread() {
+ return task_runner_->RunsTasksInCurrentSequence();
+}
+
+bool CefTaskRunnerImpl::BelongsToThread(CefThreadId threadId) {
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner =
+ GetTaskRunner(threadId);
+ return (task_runner_ == task_runner);
+}
+
+bool CefTaskRunnerImpl::PostTask(CefRefPtr<CefTask> task) {
+ return task_runner_->PostTask(FROM_HERE,
+ base::BindOnce(&CefTask::Execute, task.get()));
+}
+
+bool CefTaskRunnerImpl::PostDelayedTask(CefRefPtr<CefTask> task,
+ int64 delay_ms) {
+ return task_runner_->PostDelayedTask(
+ FROM_HERE, base::BindOnce(&CefTask::Execute, task.get()),
+ base::Milliseconds(delay_ms));
+}
diff --git a/libcef/common/task_runner_impl.h b/libcef/common/task_runner_impl.h
new file mode 100644
index 00000000..de3d8307
--- /dev/null
+++ b/libcef/common/task_runner_impl.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_COMMON_TASK_RUNNER_IMPL_H_
+#define CEF_LIBCEF_COMMON_TASK_RUNNER_IMPL_H_
+#pragma once
+
+#include "include/cef_task.h"
+
+#include "base/task/single_thread_task_runner.h"
+
+class CefTaskRunnerImpl : public CefTaskRunner {
+ public:
+ explicit CefTaskRunnerImpl(
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner);
+
+ CefTaskRunnerImpl(const CefTaskRunnerImpl&) = delete;
+ CefTaskRunnerImpl& operator=(const CefTaskRunnerImpl&) = delete;
+
+ // Returns the task runner associated with |threadId|.
+ static scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner(
+ CefThreadId threadId);
+ // Returns the current task runner.
+ static scoped_refptr<base::SingleThreadTaskRunner> GetCurrentTaskRunner();
+
+ // CefTaskRunner methods:
+ bool IsSame(CefRefPtr<CefTaskRunner> that) override;
+ bool BelongsToCurrentThread() override;
+ bool BelongsToThread(CefThreadId threadId) override;
+ bool PostTask(CefRefPtr<CefTask> task) override;
+ bool PostDelayedTask(CefRefPtr<CefTask> task, int64 delay_ms) override;
+
+ private:
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+
+ IMPLEMENT_REFCOUNTING(CefTaskRunnerImpl);
+};
+
+#endif // CEF_LIBCEF_COMMON_TASK_RUNNER_IMPL_H_
diff --git a/libcef/common/task_runner_manager.cc b/libcef/common/task_runner_manager.cc
new file mode 100644
index 00000000..2318e58a
--- /dev/null
+++ b/libcef/common/task_runner_manager.cc
@@ -0,0 +1,28 @@
+// Copyright 2020 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/common/task_runner_manager.h"
+
+#include "base/logging.h"
+
+namespace {
+
+CefTaskRunnerManager* g_manager = nullptr;
+
+} // namespace
+
+// static
+CefTaskRunnerManager* CefTaskRunnerManager::Get() {
+ return g_manager;
+}
+
+CefTaskRunnerManager::CefTaskRunnerManager() {
+ // Only a single instance should exist.
+ DCHECK(!g_manager);
+ g_manager = this;
+}
+
+CefTaskRunnerManager::~CefTaskRunnerManager() {
+ g_manager = nullptr;
+}
diff --git a/libcef/common/task_runner_manager.h b/libcef/common/task_runner_manager.h
new file mode 100644
index 00000000..4f0ea131
--- /dev/null
+++ b/libcef/common/task_runner_manager.h
@@ -0,0 +1,37 @@
+// Copyright 2020 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_COMMON_TASK_RUNNER_MANAGER_H_
+#define CEF_LIBCEF_COMMON_TASK_RUNNER_MANAGER_H_
+#pragma once
+
+#include "base/task/single_thread_task_runner.h"
+
+// Exposes global sequenced task runners in the main and render processes.
+// Prefer using base::ThreadPool for tasks that do not need to be globally
+// sequenced and CefTaskRunner for retrieving named CefThreadId runners.
+class CefTaskRunnerManager {
+ public:
+ // Returns the singleton instance that is scoped to CEF lifespan.
+ static CefTaskRunnerManager* Get();
+
+ // Available in the main process:
+ virtual scoped_refptr<base::SingleThreadTaskRunner>
+ GetBackgroundTaskRunner() = 0;
+ virtual scoped_refptr<base::SingleThreadTaskRunner>
+ GetUserVisibleTaskRunner() = 0;
+ virtual scoped_refptr<base::SingleThreadTaskRunner>
+ GetUserBlockingTaskRunner() = 0;
+
+ // Available in the render process:
+ virtual scoped_refptr<base::SingleThreadTaskRunner> GetRenderTaskRunner() = 0;
+ virtual scoped_refptr<base::SingleThreadTaskRunner>
+ GetWebWorkerTaskRunner() = 0;
+
+ protected:
+ CefTaskRunnerManager();
+ virtual ~CefTaskRunnerManager();
+};
+
+#endif // CEF_LIBCEF_COMMON_TASK_RUNNER_MANAGER_H_
diff --git a/libcef/common/test/translator_test_impl.cc b/libcef/common/test/translator_test_impl.cc
new file mode 100644
index 00000000..93a8d5e9
--- /dev/null
+++ b/libcef/common/test/translator_test_impl.cc
@@ -0,0 +1,601 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#include "include/test/cef_translator_test.h"
+
+class CefTranslatorTestRefPtrLibraryImpl
+ : public CefTranslatorTestRefPtrLibrary {
+ public:
+ explicit CefTranslatorTestRefPtrLibraryImpl(int value) : value_(value) {}
+
+ CefTranslatorTestRefPtrLibraryImpl(
+ const CefTranslatorTestRefPtrLibraryImpl&) = delete;
+ CefTranslatorTestRefPtrLibraryImpl& operator=(
+ const CefTranslatorTestRefPtrLibraryImpl&) = delete;
+
+ int GetValue() override { return value_; }
+
+ void SetValue(int value) override { value_ = value; }
+
+ protected:
+ int value_;
+
+ private:
+ IMPLEMENT_REFCOUNTING(CefTranslatorTestRefPtrLibraryImpl);
+};
+
+// static
+CefRefPtr<CefTranslatorTestRefPtrLibrary>
+CefTranslatorTestRefPtrLibrary::Create(int value) {
+ return new CefTranslatorTestRefPtrLibraryImpl(value);
+}
+
+class CefTranslatorTestRefPtrLibraryChildImpl
+ : public CefTranslatorTestRefPtrLibraryChild {
+ public:
+ CefTranslatorTestRefPtrLibraryChildImpl(int value, int other_value)
+ : value_(value), other_value_(other_value) {}
+
+ CefTranslatorTestRefPtrLibraryChildImpl(
+ const CefTranslatorTestRefPtrLibraryChildImpl&) = delete;
+ CefTranslatorTestRefPtrLibraryChildImpl& operator=(
+ const CefTranslatorTestRefPtrLibraryChildImpl&) = delete;
+
+ int GetValue() override { return value_; }
+
+ void SetValue(int value) override { value_ = value; }
+
+ int GetOtherValue() override { return other_value_; }
+
+ void SetOtherValue(int value) override { other_value_ = value; }
+
+ protected:
+ int value_;
+ int other_value_;
+
+ private:
+ IMPLEMENT_REFCOUNTING(CefTranslatorTestRefPtrLibraryChildImpl);
+};
+
+// static
+CefRefPtr<CefTranslatorTestRefPtrLibraryChild>
+CefTranslatorTestRefPtrLibraryChild::Create(int value, int other_value) {
+ return new CefTranslatorTestRefPtrLibraryChildImpl(value, other_value);
+}
+
+class CefTranslatorTestRefPtrLibraryChildChildImpl
+ : public CefTranslatorTestRefPtrLibraryChildChild {
+ public:
+ CefTranslatorTestRefPtrLibraryChildChildImpl(int value,
+ int other_value,
+ int other_other_value)
+ : value_(value),
+ other_value_(other_value),
+ other_other_value_(other_other_value) {}
+
+ CefTranslatorTestRefPtrLibraryChildChildImpl(
+ const CefTranslatorTestRefPtrLibraryChildChildImpl&) = delete;
+ CefTranslatorTestRefPtrLibraryChildChildImpl& operator=(
+ const CefTranslatorTestRefPtrLibraryChildChildImpl&) = delete;
+
+ int GetValue() override { return value_; }
+
+ void SetValue(int value) override { value_ = value; }
+
+ int GetOtherValue() override { return other_value_; }
+
+ void SetOtherValue(int value) override { other_value_ = value; }
+
+ int GetOtherOtherValue() override { return other_other_value_; }
+
+ void SetOtherOtherValue(int value) override { other_other_value_ = value; }
+
+ protected:
+ int value_;
+ int other_value_;
+ int other_other_value_;
+
+ private:
+ IMPLEMENT_REFCOUNTING(CefTranslatorTestRefPtrLibraryChildChildImpl);
+};
+
+// static
+CefRefPtr<CefTranslatorTestRefPtrLibraryChildChild>
+CefTranslatorTestRefPtrLibraryChildChild::Create(int value,
+ int other_value,
+ int other_other_value) {
+ return new CefTranslatorTestRefPtrLibraryChildChildImpl(value, other_value,
+ other_other_value);
+}
+
+class CefTranslatorTestScopedLibraryImpl
+ : public CefTranslatorTestScopedLibrary {
+ public:
+ explicit CefTranslatorTestScopedLibraryImpl(int value) : value_(value) {}
+
+ CefTranslatorTestScopedLibraryImpl(
+ const CefTranslatorTestScopedLibraryImpl&) = delete;
+ CefTranslatorTestScopedLibraryImpl& operator=(
+ const CefTranslatorTestScopedLibraryImpl&) = delete;
+
+ int GetValue() override { return value_; }
+
+ void SetValue(int value) override { value_ = value; }
+
+ protected:
+ int value_;
+};
+
+// static
+CefOwnPtr<CefTranslatorTestScopedLibrary>
+CefTranslatorTestScopedLibrary::Create(int value) {
+ return CefOwnPtr<CefTranslatorTestScopedLibrary>(
+ new CefTranslatorTestScopedLibraryImpl(value));
+}
+
+class CefTranslatorTestScopedLibraryChildImpl
+ : public CefTranslatorTestScopedLibraryChild {
+ public:
+ CefTranslatorTestScopedLibraryChildImpl(int value, int other_value)
+ : value_(value), other_value_(other_value) {}
+
+ CefTranslatorTestScopedLibraryChildImpl(
+ const CefTranslatorTestScopedLibraryChildImpl&) = delete;
+ CefTranslatorTestScopedLibraryChildImpl& operator=(
+ const CefTranslatorTestScopedLibraryChildImpl&) = delete;
+
+ int GetValue() override { return value_; }
+
+ void SetValue(int value) override { value_ = value; }
+
+ int GetOtherValue() override { return other_value_; }
+
+ void SetOtherValue(int value) override { other_value_ = value; }
+
+ protected:
+ int value_;
+ int other_value_;
+};
+
+// static
+CefOwnPtr<CefTranslatorTestScopedLibraryChild>
+CefTranslatorTestScopedLibraryChild::Create(int value, int other_value) {
+ return CefOwnPtr<CefTranslatorTestScopedLibraryChild>(
+ new CefTranslatorTestScopedLibraryChildImpl(value, other_value));
+}
+
+class CefTranslatorTestScopedLibraryChildChildImpl
+ : public CefTranslatorTestScopedLibraryChildChild {
+ public:
+ CefTranslatorTestScopedLibraryChildChildImpl(int value,
+ int other_value,
+ int other_other_value)
+ : value_(value),
+ other_value_(other_value),
+ other_other_value_(other_other_value) {}
+
+ CefTranslatorTestScopedLibraryChildChildImpl(
+ const CefTranslatorTestScopedLibraryChildChildImpl&) = delete;
+ CefTranslatorTestScopedLibraryChildChildImpl& operator=(
+ const CefTranslatorTestScopedLibraryChildChildImpl&) = delete;
+
+ int GetValue() override { return value_; }
+
+ void SetValue(int value) override { value_ = value; }
+
+ int GetOtherValue() override { return other_value_; }
+
+ void SetOtherValue(int value) override { other_value_ = value; }
+
+ int GetOtherOtherValue() override { return other_other_value_; }
+
+ void SetOtherOtherValue(int value) override { other_other_value_ = value; }
+
+ protected:
+ int value_;
+ int other_value_;
+ int other_other_value_;
+};
+
+// static
+CefOwnPtr<CefTranslatorTestScopedLibraryChildChild>
+CefTranslatorTestScopedLibraryChildChild::Create(int value,
+ int other_value,
+ int other_other_value) {
+ return CefOwnPtr<CefTranslatorTestScopedLibraryChildChild>(
+ new CefTranslatorTestScopedLibraryChildChildImpl(value, other_value,
+ other_other_value));
+}
+
+class CefTranslatorTestImpl : public CefTranslatorTest {
+ public:
+ CefTranslatorTestImpl() = default;
+
+ CefTranslatorTestImpl(const CefTranslatorTestImpl&) = delete;
+ CefTranslatorTestImpl& operator=(const CefTranslatorTestImpl&) = delete;
+
+ // PRIMITIVE VALUES
+
+ void GetVoid() override {}
+
+ bool GetBool() override { return TEST_BOOL_VAL; }
+
+ int GetInt() override { return TEST_INT_VAL; }
+
+ double GetDouble() override { return TEST_DOUBLE_VAL; }
+
+ long GetLong() override { return TEST_LONG_VAL; }
+
+ size_t GetSizet() override { return TEST_SIZET_VAL; }
+
+ bool SetVoid() override { return true; }
+
+ bool SetBool(bool val) override { return (val == TEST_BOOL_VAL); }
+
+ bool SetInt(int val) override { return (val == TEST_INT_VAL); }
+
+ bool SetDouble(double val) override { return (val == TEST_DOUBLE_VAL); }
+
+ bool SetLong(long val) override { return (val == TEST_LONG_VAL); }
+
+ bool SetSizet(size_t val) override { return (val == TEST_SIZET_VAL); }
+
+ // PRIMITIVE LIST VALUES
+
+ bool SetIntList(const std::vector<int>& val) override {
+ if (val.size() != 2U) {
+ return false;
+ }
+ return val[0] == TEST_INT_VAL && val[1] == TEST_INT_VAL2;
+ }
+
+ bool GetIntListByRef(IntList& val) override {
+ if (val.size() != GetIntListSize()) {
+ return false;
+ }
+ val.clear();
+ val.push_back(TEST_INT_VAL);
+ val.push_back(TEST_INT_VAL2);
+ return true;
+ }
+
+ size_t GetIntListSize() override { return 2U; }
+
+ // STRING VALUES
+
+ CefString GetString() override { return TEST_STRING_VAL; }
+
+ bool SetString(const CefString& val) override {
+ return (val.ToString() == TEST_STRING_VAL);
+ }
+
+ void GetStringByRef(CefString& val) override { val = TEST_STRING_VAL; }
+
+ // STRING LIST VALUES
+
+ bool SetStringList(const std::vector<CefString>& val) override {
+ if (val.size() != 3U) {
+ return false;
+ }
+ return val[0] == TEST_STRING_VAL && val[1] == TEST_STRING_VAL2 &&
+ val[2] == TEST_STRING_VAL3;
+ }
+
+ bool GetStringListByRef(StringList& val) override {
+ if (val.size() != 0U) {
+ return false;
+ }
+ val.push_back(TEST_STRING_VAL);
+ val.push_back(TEST_STRING_VAL2);
+ val.push_back(TEST_STRING_VAL3);
+ return true;
+ }
+
+ // STRING MAP VALUES
+
+ bool SetStringMap(const StringMap& val) override {
+ if (val.size() != 3U) {
+ return false;
+ }
+
+ StringMap::const_iterator it;
+
+ it = val.find(TEST_STRING_KEY);
+ if (it == val.end() || it->second != TEST_STRING_VAL) {
+ return false;
+ }
+ it = val.find(TEST_STRING_KEY2);
+ if (it == val.end() || it->second != TEST_STRING_VAL2) {
+ return false;
+ }
+ it = val.find(TEST_STRING_KEY3);
+ if (it == val.end() || it->second != TEST_STRING_VAL3) {
+ return false;
+ }
+ return true;
+ }
+
+ bool GetStringMapByRef(std::map<CefString, CefString>& val) override {
+ if (val.size() != 0U) {
+ return false;
+ }
+
+ val.insert(std::make_pair(TEST_STRING_KEY, TEST_STRING_VAL));
+ val.insert(std::make_pair(TEST_STRING_KEY2, TEST_STRING_VAL2));
+ val.insert(std::make_pair(TEST_STRING_KEY3, TEST_STRING_VAL3));
+ return true;
+ }
+
+ // STRING MULTIMAP VALUES
+
+ bool SetStringMultimap(
+ const std::multimap<CefString, CefString>& val) override {
+ if (val.size() != 3U) {
+ return false;
+ }
+
+ StringMultimap::const_iterator it;
+
+ it = val.find(TEST_STRING_KEY);
+ if (it == val.end() || it->second != TEST_STRING_VAL) {
+ return false;
+ }
+ it = val.find(TEST_STRING_KEY2);
+ if (it == val.end() || it->second != TEST_STRING_VAL2) {
+ return false;
+ }
+ it = val.find(TEST_STRING_KEY3);
+ if (it == val.end() || it->second != TEST_STRING_VAL3) {
+ return false;
+ }
+ return true;
+ }
+
+ bool GetStringMultimapByRef(StringMultimap& val) override {
+ if (val.size() != 0U) {
+ return false;
+ }
+
+ val.insert(std::make_pair(TEST_STRING_KEY, TEST_STRING_VAL));
+ val.insert(std::make_pair(TEST_STRING_KEY2, TEST_STRING_VAL2));
+ val.insert(std::make_pair(TEST_STRING_KEY3, TEST_STRING_VAL3));
+ return true;
+ }
+
+ // STRUCT VALUES
+
+ CefPoint GetPoint() override { return CefPoint(TEST_X_VAL, TEST_Y_VAL); }
+
+ bool SetPoint(const CefPoint& val) override {
+ return val.x == TEST_X_VAL && val.y == TEST_Y_VAL;
+ }
+
+ void GetPointByRef(CefPoint& val) override {
+ val = CefPoint(TEST_X_VAL, TEST_Y_VAL);
+ }
+
+ // STRUCT LIST VALUES
+
+ bool SetPointList(const std::vector<CefPoint>& val) override {
+ if (val.size() != 2U) {
+ return false;
+ }
+ return val[0].x == TEST_X_VAL && val[0].y == TEST_Y_VAL &&
+ val[1].x == TEST_X_VAL2 && val[1].y == TEST_Y_VAL2;
+ }
+
+ bool GetPointListByRef(PointList& val) override {
+ if (val.size() != GetPointListSize()) {
+ return false;
+ }
+ val.clear();
+ val.push_back(CefPoint(TEST_X_VAL, TEST_Y_VAL));
+ val.push_back(CefPoint(TEST_X_VAL2, TEST_Y_VAL2));
+ return true;
+ }
+
+ size_t GetPointListSize() override { return 2U; }
+
+ // LIBRARY-SIDE REFPTR VALUES
+
+ CefRefPtr<CefTranslatorTestRefPtrLibrary> GetRefPtrLibrary(int val) override {
+ return new CefTranslatorTestRefPtrLibraryChildImpl(val, 0);
+ }
+
+ int SetRefPtrLibrary(CefRefPtr<CefTranslatorTestRefPtrLibrary> val) override {
+ return val->GetValue();
+ }
+
+ CefRefPtr<CefTranslatorTestRefPtrLibrary> SetRefPtrLibraryAndReturn(
+ CefRefPtr<CefTranslatorTestRefPtrLibrary> val) override {
+ return val;
+ }
+
+ int SetChildRefPtrLibrary(
+ CefRefPtr<CefTranslatorTestRefPtrLibraryChild> val) override {
+ return val->GetValue();
+ }
+
+ CefRefPtr<CefTranslatorTestRefPtrLibrary>
+ SetChildRefPtrLibraryAndReturnParent(
+ CefRefPtr<CefTranslatorTestRefPtrLibraryChild> val) override {
+ return val;
+ }
+
+ // LIBRARY-SIDE REFPTR LIST VALUES
+
+ bool SetRefPtrLibraryList(
+ const std::vector<CefRefPtr<CefTranslatorTestRefPtrLibrary>>& val,
+ int val1,
+ int val2) override {
+ if (val.size() != 2U) {
+ return false;
+ }
+ return val[0]->GetValue() == val1 && val[1]->GetValue() == val2;
+ }
+
+ bool GetRefPtrLibraryListByRef(RefPtrLibraryList& val,
+ int val1,
+ int val2) override {
+ if (val.size() != GetRefPtrLibraryListSize()) {
+ return false;
+ }
+ val.clear();
+ val.push_back(new CefTranslatorTestRefPtrLibraryChildImpl(val1, 0));
+ val.push_back(new CefTranslatorTestRefPtrLibraryImpl(val2));
+ return true;
+ }
+
+ size_t GetRefPtrLibraryListSize() override { return 2U; }
+
+ // CLIENT-SIDE REFPTR VALUES
+
+ int SetRefPtrClient(CefRefPtr<CefTranslatorTestRefPtrClient> val) override {
+ return val->GetValue();
+ }
+
+ CefRefPtr<CefTranslatorTestRefPtrClient> SetRefPtrClientAndReturn(
+ CefRefPtr<CefTranslatorTestRefPtrClient> val) override {
+ return val;
+ }
+
+ int SetChildRefPtrClient(
+ CefRefPtr<CefTranslatorTestRefPtrClientChild> val) override {
+ return val->GetValue();
+ }
+
+ CefRefPtr<CefTranslatorTestRefPtrClient> SetChildRefPtrClientAndReturnParent(
+ CefRefPtr<CefTranslatorTestRefPtrClientChild> val) override {
+ return val;
+ }
+
+ // CLIENT-SIDE REFPTR LIST VALUES
+
+ bool SetRefPtrClientList(
+ const std::vector<CefRefPtr<CefTranslatorTestRefPtrClient>>& val,
+ int val1,
+ int val2) override {
+ if (val.size() != 2U) {
+ return false;
+ }
+ return val[0]->GetValue() == val1 && val[1]->GetValue() == val2;
+ }
+
+ bool GetRefPtrClientListByRef(
+ RefPtrClientList& val,
+ CefRefPtr<CefTranslatorTestRefPtrClient> val1,
+ CefRefPtr<CefTranslatorTestRefPtrClient> val2) override {
+ if (val.size() != GetRefPtrClientListSize()) {
+ return false;
+ }
+ val.clear();
+ val.push_back(val1);
+ val.push_back(val2);
+ return true;
+ }
+
+ size_t GetRefPtrClientListSize() override { return 2U; }
+
+ // LIBRARY-SIDE OWNPTR VALUES
+
+ CefOwnPtr<CefTranslatorTestScopedLibrary> GetOwnPtrLibrary(int val) override {
+ return CefOwnPtr<CefTranslatorTestScopedLibrary>(
+ new CefTranslatorTestScopedLibraryChildImpl(val, 0));
+ }
+
+ int SetOwnPtrLibrary(CefOwnPtr<CefTranslatorTestScopedLibrary> val) override {
+ return val->GetValue();
+ }
+
+ CefOwnPtr<CefTranslatorTestScopedLibrary> SetOwnPtrLibraryAndReturn(
+ CefOwnPtr<CefTranslatorTestScopedLibrary> val) override {
+ return val;
+ }
+
+ int SetChildOwnPtrLibrary(
+ CefOwnPtr<CefTranslatorTestScopedLibraryChild> val) override {
+ return val->GetValue();
+ }
+
+ CefOwnPtr<CefTranslatorTestScopedLibrary>
+ SetChildOwnPtrLibraryAndReturnParent(
+ CefOwnPtr<CefTranslatorTestScopedLibraryChild> val) override {
+ return CefOwnPtr<CefTranslatorTestScopedLibrary>(val.release());
+ }
+
+ // CLIENT-SIDE OWNPTR VALUES
+
+ int SetOwnPtrClient(CefOwnPtr<CefTranslatorTestScopedClient> val) override {
+ return val->GetValue();
+ }
+
+ CefOwnPtr<CefTranslatorTestScopedClient> SetOwnPtrClientAndReturn(
+ CefOwnPtr<CefTranslatorTestScopedClient> val) override {
+ return val;
+ }
+
+ int SetChildOwnPtrClient(
+ CefOwnPtr<CefTranslatorTestScopedClientChild> val) override {
+ return val->GetValue();
+ }
+
+ CefOwnPtr<CefTranslatorTestScopedClient> SetChildOwnPtrClientAndReturnParent(
+ CefOwnPtr<CefTranslatorTestScopedClientChild> val) override {
+ return CefOwnPtr<CefTranslatorTestScopedClient>(val.release());
+ }
+
+ // LIBRARY-SIDE RAWPTR VALUES
+
+ int SetRawPtrLibrary(CefRawPtr<CefTranslatorTestScopedLibrary> val) override {
+ return val->GetValue();
+ }
+
+ int SetChildRawPtrLibrary(
+ CefRawPtr<CefTranslatorTestScopedLibraryChild> val) override {
+ return val->GetValue();
+ }
+
+ // LIBRARY-SIDE RAWPTR LIST VALUES
+
+ bool SetRawPtrLibraryList(
+ const std::vector<CefRawPtr<CefTranslatorTestScopedLibrary>>& val,
+ int val1,
+ int val2) override {
+ if (val.size() != 2U) {
+ return false;
+ }
+ return val[0]->GetValue() == val1 && val[1]->GetValue() == val2;
+ }
+
+ // CLIENT-SIDE RAWPTR VALUES
+
+ int SetRawPtrClient(CefRawPtr<CefTranslatorTestScopedClient> val) override {
+ return val->GetValue();
+ }
+
+ int SetChildRawPtrClient(
+ CefRawPtr<CefTranslatorTestScopedClientChild> val) override {
+ return val->GetValue();
+ }
+
+ // CLIENT-SIDE RAWPTR LIST VALUES
+
+ bool SetRawPtrClientList(
+ const std::vector<CefRawPtr<CefTranslatorTestScopedClient>>& val,
+ int val1,
+ int val2) override {
+ if (val.size() != 2U) {
+ return false;
+ }
+ return val[0]->GetValue() == val1 && val[1]->GetValue() == val2;
+ }
+
+ private:
+ IMPLEMENT_REFCOUNTING(CefTranslatorTestImpl);
+};
+
+// static
+CefRefPtr<CefTranslatorTest> CefTranslatorTest::Create() {
+ return new CefTranslatorTestImpl();
+}
diff --git a/libcef/common/thread_impl.cc b/libcef/common/thread_impl.cc
new file mode 100644
index 00000000..7c4a0946
--- /dev/null
+++ b/libcef/common/thread_impl.cc
@@ -0,0 +1,152 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#include "libcef/common/thread_impl.h"
+
+#include "libcef/common/task_runner_impl.h"
+
+#include "base/functional/bind.h"
+#include "base/threading/thread_restrictions.h"
+
+namespace {
+
+void StopAndDestroy(base::Thread* thread) {
+ // Calling PlatformThread::Join() on the UI thread is otherwise disallowed.
+ base::ScopedAllowBaseSyncPrimitivesForTesting scoped_allow_sync_primitives;
+
+ // Deleting |thread| will implicitly stop and join it.
+ delete thread;
+}
+
+} // namespace
+
+// static
+CefRefPtr<CefThread> CefThread::CreateThread(
+ const CefString& display_name,
+ cef_thread_priority_t priority,
+ cef_message_loop_type_t message_loop_type,
+ bool stoppable,
+ cef_com_init_mode_t com_init_mode) {
+ if (!CefTaskRunnerImpl::GetCurrentTaskRunner()) {
+ NOTREACHED() << "called on invalid thread";
+ return nullptr;
+ }
+
+ CefRefPtr<CefThreadImpl> thread_impl = new CefThreadImpl();
+ if (!thread_impl->Create(display_name, priority, message_loop_type, stoppable,
+ com_init_mode)) {
+ return nullptr;
+ }
+ return thread_impl;
+}
+
+CefThreadImpl::CefThreadImpl() : thread_id_(kInvalidPlatformThreadId) {}
+
+CefThreadImpl::~CefThreadImpl() {
+ if (thread_.get()) {
+ if (!owner_task_runner_->RunsTasksInCurrentSequence()) {
+ // Delete |thread_| on the correct thread.
+ owner_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(StopAndDestroy, base::Unretained(thread_.release())));
+ } else {
+ StopAndDestroy(thread_.release());
+ }
+ }
+}
+
+bool CefThreadImpl::Create(const CefString& display_name,
+ cef_thread_priority_t priority,
+ cef_message_loop_type_t message_loop_type,
+ bool stoppable,
+ cef_com_init_mode_t com_init_mode) {
+ owner_task_runner_ = CefTaskRunnerImpl::GetCurrentTaskRunner();
+ DCHECK(owner_task_runner_);
+ if (!owner_task_runner_) {
+ return false;
+ }
+
+ thread_.reset(new base::Thread(display_name));
+
+ base::Thread::Options options;
+
+ switch (priority) {
+ case TP_BACKGROUND:
+ options.thread_type = base::ThreadType::kBackground;
+ break;
+ case TP_DISPLAY:
+ options.thread_type = base::ThreadType::kDisplayCritical;
+ break;
+ case TP_REALTIME_AUDIO:
+ options.thread_type = base::ThreadType::kRealtimeAudio;
+ break;
+ default:
+ break;
+ }
+
+ switch (message_loop_type) {
+ case ML_TYPE_UI:
+ options.message_pump_type = base::MessagePumpType::UI;
+ break;
+ case ML_TYPE_IO:
+ options.message_pump_type = base::MessagePumpType::IO;
+ break;
+ default:
+ break;
+ }
+
+ options.joinable = stoppable;
+
+#if BUILDFLAG(IS_WIN)
+ if (com_init_mode != COM_INIT_MODE_NONE) {
+ if (com_init_mode == COM_INIT_MODE_STA) {
+ options.message_pump_type = base::MessagePumpType::UI;
+ }
+ thread_->init_com_with_mta(com_init_mode == COM_INIT_MODE_MTA);
+ }
+#endif
+
+ if (!thread_->StartWithOptions(std::move(options))) {
+ thread_.reset();
+ return false;
+ }
+
+ thread_task_runner_ = new CefTaskRunnerImpl(thread_->task_runner());
+ thread_id_ = thread_->GetThreadId();
+ return true;
+}
+
+CefRefPtr<CefTaskRunner> CefThreadImpl::GetTaskRunner() {
+ return thread_task_runner_;
+}
+
+cef_platform_thread_id_t CefThreadImpl::GetPlatformThreadId() {
+ return thread_id_;
+}
+
+void CefThreadImpl::Stop() {
+ if (!owner_task_runner_) {
+ return;
+ }
+ if (!owner_task_runner_->RunsTasksInCurrentSequence()) {
+ NOTREACHED() << "called on invalid thread";
+ return;
+ }
+
+ if (thread_) {
+ StopAndDestroy(thread_.release());
+ }
+}
+
+bool CefThreadImpl::IsRunning() {
+ if (!owner_task_runner_) {
+ return false;
+ }
+ if (!owner_task_runner_->RunsTasksInCurrentSequence()) {
+ NOTREACHED() << "called on invalid thread";
+ return false;
+ }
+
+ return thread_ && thread_->IsRunning();
+}
diff --git a/libcef/common/thread_impl.h b/libcef/common/thread_impl.h
new file mode 100644
index 00000000..49e0380e
--- /dev/null
+++ b/libcef/common/thread_impl.h
@@ -0,0 +1,45 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_COMMON_THREAD_IMPL_H_
+#define CEF_LIBCEF_COMMON_THREAD_IMPL_H_
+#pragma once
+
+#include "include/cef_thread.h"
+
+#include "base/threading/thread.h"
+
+class CefThreadImpl : public CefThread {
+ public:
+ CefThreadImpl();
+
+ CefThreadImpl(const CefThreadImpl&) = delete;
+ CefThreadImpl& operator=(const CefThreadImpl&) = delete;
+
+ ~CefThreadImpl();
+
+ bool Create(const CefString& display_name,
+ cef_thread_priority_t priority,
+ cef_message_loop_type_t message_loop_type,
+ bool stoppable,
+ cef_com_init_mode_t com_init_mode);
+
+ // CefThread methods:
+ CefRefPtr<CefTaskRunner> GetTaskRunner() override;
+ cef_platform_thread_id_t GetPlatformThreadId() override;
+ void Stop() override;
+ bool IsRunning() override;
+
+ private:
+ std::unique_ptr<base::Thread> thread_;
+ cef_platform_thread_id_t thread_id_;
+ CefRefPtr<CefTaskRunner> thread_task_runner_;
+
+ // TaskRunner for the owner thread.
+ scoped_refptr<base::SequencedTaskRunner> owner_task_runner_;
+
+ IMPLEMENT_REFCOUNTING(CefThreadImpl);
+};
+
+#endif // CEF_LIBCEF_COMMON_THREAD_IMPL_H_
diff --git a/libcef/common/time_impl.cc b/libcef/common/time_impl.cc
new file mode 100644
index 00000000..b2981ac1
--- /dev/null
+++ b/libcef/common/time_impl.cc
@@ -0,0 +1,172 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "include/internal/cef_time_wrappers.h"
+#include "include/internal/cef_types_wrappers.h"
+#include "libcef/common/time_util.h"
+
+#include <limits>
+#include <tuple>
+
+#if BUILDFLAG(IS_WIN)
+namespace {
+
+// From MSDN, FILETIME "Contains a 64-bit value representing the number of
+// 100-nanosecond intervals since January 1, 1601 (UTC)." This value must
+// be less than 0x8000000000000000. Otherwise, the function
+// FileTimeToSystemTime fails.
+// From base/time/time_win.cc:
+bool CanConvertToFileTime(int64_t us) {
+ return us >= 0 && us <= (std::numeric_limits<int64_t>::max() / 10);
+}
+
+} // namespace
+#endif // BUILDFLAG(IS_WIN)
+
+void cef_time_to_basetime(const cef_time_t& cef_time, base::Time& time) {
+ base::Time::Exploded exploded;
+ exploded.year = cef_time.year;
+ exploded.month = cef_time.month;
+ exploded.day_of_week = cef_time.day_of_week;
+ exploded.day_of_month = cef_time.day_of_month;
+ exploded.hour = cef_time.hour;
+ exploded.minute = cef_time.minute;
+ exploded.second = cef_time.second;
+ exploded.millisecond = cef_time.millisecond;
+ std::ignore = base::Time::FromUTCExploded(exploded, &time);
+}
+
+void cef_time_from_basetime(const base::Time& time, cef_time_t& cef_time) {
+#if BUILDFLAG(IS_WIN)
+ int64_t t = time.ToDeltaSinceWindowsEpoch().InMicroseconds();
+ if (!CanConvertToFileTime(t)) {
+ return;
+ }
+#endif
+
+ base::Time::Exploded exploded;
+ time.UTCExplode(&exploded);
+ cef_time.year = exploded.year;
+ cef_time.month = exploded.month;
+ cef_time.day_of_week = exploded.day_of_week;
+ cef_time.day_of_month = exploded.day_of_month;
+ cef_time.hour = exploded.hour;
+ cef_time.minute = exploded.minute;
+ cef_time.second = exploded.second;
+ cef_time.millisecond = exploded.millisecond;
+}
+
+CEF_EXPORT int cef_time_to_timet(const cef_time_t* cef_time, time_t* time) {
+ if (!cef_time || !time) {
+ return 0;
+ }
+
+ base::Time base_time;
+ cef_time_to_basetime(*cef_time, base_time);
+ *time = base_time.ToTimeT();
+ return 1;
+}
+
+CEF_EXPORT int cef_time_from_timet(time_t time, cef_time_t* cef_time) {
+ if (!cef_time) {
+ return 0;
+ }
+
+ base::Time base_time = base::Time::FromTimeT(time);
+ cef_time_from_basetime(base_time, *cef_time);
+ return 1;
+}
+
+CEF_EXPORT int cef_time_to_doublet(const cef_time_t* cef_time, double* time) {
+ if (!cef_time || !time) {
+ return 0;
+ }
+
+ base::Time base_time;
+ cef_time_to_basetime(*cef_time, base_time);
+ *time = base_time.ToDoubleT();
+ return 1;
+}
+
+CEF_EXPORT int cef_time_from_doublet(double time, cef_time_t* cef_time) {
+ if (!cef_time) {
+ return 0;
+ }
+
+ base::Time base_time = base::Time::FromDoubleT(time);
+ cef_time_from_basetime(base_time, *cef_time);
+ return 1;
+}
+
+CEF_EXPORT int cef_time_now(cef_time_t* cef_time) {
+ if (!cef_time) {
+ return 0;
+ }
+
+ base::Time base_time = base::Time::Now();
+ cef_time_from_basetime(base_time, *cef_time);
+ return 1;
+}
+
+CEF_EXPORT cef_basetime_t cef_basetime_now() {
+ return CefBaseTime(base::Time::Now());
+}
+
+CEF_EXPORT int cef_time_delta(const cef_time_t* cef_time1,
+ const cef_time_t* cef_time2,
+ long long* delta) {
+ if (!cef_time1 || !cef_time2 || !delta) {
+ return 0;
+ }
+
+ base::Time base_time1, base_time2;
+ cef_time_to_basetime(*cef_time1, base_time1);
+ cef_time_to_basetime(*cef_time2, base_time2);
+
+ base::TimeDelta time_delta = base_time2 - base_time1;
+ *delta = time_delta.InMilliseconds();
+ return 1;
+}
+
+CEF_EXPORT int cef_time_to_basetime(const cef_time_t* from,
+ cef_basetime_t* to) {
+ if (!from || !to) {
+ return 0;
+ }
+
+ base::Time::Exploded exploded;
+ exploded.year = from->year;
+ exploded.month = from->month;
+ exploded.day_of_week = from->day_of_week;
+ exploded.day_of_month = from->day_of_month;
+ exploded.hour = from->hour;
+ exploded.minute = from->minute;
+ exploded.second = from->second;
+ exploded.millisecond = from->millisecond;
+ base::Time time;
+ bool result = base::Time::FromUTCExploded(exploded, &time);
+ *to = CefBaseTime(time);
+ return result ? 1 : 0;
+}
+
+CEF_EXPORT int cef_time_from_basetime(const cef_basetime_t from,
+ cef_time_t* to) {
+ if (!to) {
+ return 0;
+ }
+
+ base::Time time = CefBaseTime(from);
+
+ base::Time::Exploded exploded;
+ time.UTCExplode(&exploded);
+ to->year = exploded.year;
+ to->month = exploded.month;
+ to->day_of_week = exploded.day_of_week;
+ to->day_of_month = exploded.day_of_month;
+ to->hour = exploded.hour;
+ to->minute = exploded.minute;
+ to->second = exploded.second;
+ to->millisecond = exploded.millisecond;
+ return exploded.HasValidValues() ? 1 : 0;
+}
diff --git a/libcef/common/time_util.h b/libcef/common/time_util.h
new file mode 100644
index 00000000..bbfa0748
--- /dev/null
+++ b/libcef/common/time_util.h
@@ -0,0 +1,16 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_COMMON_TIME_UTIL_H_
+#define CEF_LIBCEF_COMMON_TIME_UTIL_H_
+#pragma once
+
+#include "base/time/time.h"
+#include "include/internal/cef_time.h"
+
+// Converts cef_time_t to/from a base::Time object.
+void cef_time_to_basetime(const cef_time_t& cef_time, base::Time& time);
+void cef_time_from_basetime(const base::Time& time, cef_time_t& cef_time);
+
+#endif // CEF_LIBCEF_COMMON_TIME_UTIL_H_
diff --git a/libcef/common/tracker.cc b/libcef/common/tracker.cc
new file mode 100644
index 00000000..499f6d8b
--- /dev/null
+++ b/libcef/common/tracker.cc
@@ -0,0 +1,80 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "libcef/common/tracker.h"
+
+// CefTrackNode implementation.
+
+CefTrackNode::CefTrackNode() : track_next_(nullptr), track_prev_(nullptr) {}
+
+CefTrackNode::~CefTrackNode() {}
+
+void CefTrackNode::InsertTrackPrev(CefTrackNode* object) {
+ if (track_prev_) {
+ track_prev_->SetTrackNext(object);
+ }
+ object->SetTrackNext(this);
+ object->SetTrackPrev(track_prev_);
+ track_prev_ = object;
+}
+
+void CefTrackNode::InsertTrackNext(CefTrackNode* object) {
+ if (track_next_) {
+ track_next_->SetTrackPrev(object);
+ }
+ object->SetTrackPrev(this);
+ object->SetTrackNext(track_next_);
+ track_next_ = object;
+}
+
+void CefTrackNode::RemoveTracking() {
+ if (track_next_) {
+ track_next_->SetTrackPrev(track_prev_);
+ }
+ if (track_prev_) {
+ track_prev_->SetTrackNext(track_next_);
+ }
+ track_next_ = nullptr;
+ track_prev_ = nullptr;
+}
+
+// CefTrackManager implementation.
+
+CefTrackManager::CefTrackManager() : object_count_(0) {}
+
+CefTrackManager::~CefTrackManager() {
+ DeleteAll();
+}
+
+void CefTrackManager::Add(CefTrackNode* object) {
+ base::AutoLock lock_scope(lock_);
+ if (!object->IsTracked()) {
+ tracker_.InsertTrackNext(object);
+ ++object_count_;
+ }
+}
+
+bool CefTrackManager::Delete(CefTrackNode* object) {
+ base::AutoLock lock_scope(lock_);
+ if (object->IsTracked()) {
+ object->RemoveTracking();
+ delete object;
+ --object_count_;
+ return true;
+ }
+ return false;
+}
+
+void CefTrackManager::DeleteAll() {
+ base::AutoLock lock_scope(lock_);
+ CefTrackNode* next;
+ do {
+ next = tracker_.GetTrackNext();
+ if (next) {
+ next->RemoveTracking();
+ delete next;
+ }
+ } while (next != nullptr);
+ object_count_ = 0;
+}
diff --git a/libcef/common/tracker.h b/libcef/common/tracker.h
new file mode 100644
index 00000000..84aad628
--- /dev/null
+++ b/libcef/common/tracker.h
@@ -0,0 +1,77 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_COMMON_TRACKER_H_
+#define CEF_LIBCEF_COMMON_TRACKER_H_
+#pragma once
+
+#include "include/cef_base.h"
+
+#include "base/synchronization/lock.h"
+
+// Class extended by objects that must be tracked. After creating a tracked
+// object you should add it to the appropriate track manager.
+class CefTrackNode {
+ public:
+ CefTrackNode();
+ virtual ~CefTrackNode();
+
+ // Returns true if the object is currently being tracked.
+ inline bool IsTracked() { return (track_prev_ || track_next_); }
+
+ private:
+ inline CefTrackNode* GetTrackPrev() { return track_prev_; }
+ inline void SetTrackPrev(CefTrackNode* base) { track_prev_ = base; }
+ inline CefTrackNode* GetTrackNext() { return track_next_; }
+ inline void SetTrackNext(CefTrackNode* base) { track_next_ = base; }
+
+ // Insert a new object into the tracking list before this object.
+ void InsertTrackPrev(CefTrackNode* object);
+
+ // Insert a new object into the tracking list after this object.
+ void InsertTrackNext(CefTrackNode* object);
+
+ // Remove this object from the tracking list.
+ void RemoveTracking();
+
+ private:
+ CefTrackNode* track_next_;
+ CefTrackNode* track_prev_;
+
+ friend class CefTrackManager;
+};
+
+// Class used to manage tracked objects. A single instance of this class
+// should be created for each intended usage. Any objects that have not been
+// removed by explicit calls to the Destroy() method will be removed when the
+// manager object is destroyed. A manager object can be created as either a
+// member variable of another class or by using lazy initialization:
+// base::LazyInstance<CefTrackManager> g_singleton = LAZY_INSTANCE_INITIALIZER;
+class CefTrackManager : public CefBaseRefCounted {
+ public:
+ CefTrackManager();
+ ~CefTrackManager() override;
+
+ // Add an object to be tracked by this manager.
+ void Add(CefTrackNode* object);
+
+ // Delete an object tracked by this manager.
+ bool Delete(CefTrackNode* object);
+
+ // Delete all objects tracked by this manager.
+ void DeleteAll();
+
+ // Returns the number of objects currently being tracked.
+ inline int GetCount() { return object_count_; }
+
+ private:
+ CefTrackNode tracker_;
+ int object_count_;
+
+ base::Lock lock_;
+
+ IMPLEMENT_REFCOUNTING(CefTrackManager);
+};
+
+#endif // CEF_LIBCEF_COMMON_TRACKER_H_
diff --git a/libcef/common/urlrequest_impl.cc b/libcef/common/urlrequest_impl.cc
new file mode 100644
index 00000000..98688975
--- /dev/null
+++ b/libcef/common/urlrequest_impl.cc
@@ -0,0 +1,43 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#include "include/cef_urlrequest.h"
+#include "libcef/browser/net_service/browser_urlrequest_impl.h"
+#include "libcef/common/app_manager.h"
+#include "libcef/common/task_runner_impl.h"
+#include "libcef/features/runtime_checks.h"
+
+#include "base/logging.h"
+#include "base/notreached.h"
+#include "content/public/common/content_client.h"
+
+// static
+CefRefPtr<CefURLRequest> CefURLRequest::Create(
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefURLRequestClient> client,
+ CefRefPtr<CefRequestContext> request_context) {
+ if (!request.get() || !client.get()) {
+ NOTREACHED() << "called with invalid parameters";
+ return nullptr;
+ }
+
+ if (!CefTaskRunnerImpl::GetCurrentTaskRunner()) {
+ NOTREACHED() << "called on invalid thread";
+ return nullptr;
+ }
+
+ auto content_client = CefAppManager::Get()->GetContentClient();
+ if (content_client->browser()) {
+ // In the browser process.
+ CefRefPtr<CefBrowserURLRequest> impl =
+ new CefBrowserURLRequest(nullptr, request, client, request_context);
+ if (impl->Start()) {
+ return impl.get();
+ }
+ return nullptr;
+ } else {
+ NOTREACHED() << "called in unsupported process";
+ return nullptr;
+ }
+}
diff --git a/libcef/common/util_linux.cc b/libcef/common/util_linux.cc
new file mode 100644
index 00000000..42513458
--- /dev/null
+++ b/libcef/common/util_linux.cc
@@ -0,0 +1,35 @@
+// Copyright 2022 The Chromium Embedded Framework Authors. Portions copyright
+// 2011 The Chromium Authors. All rights reserved. Use of this source code is
+// governed by a BSD-style license that can be found in the LICENSE file.
+
+#include "libcef/common/util_linux.h"
+
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+#include "content/public/common/content_paths.h"
+#include "content/public/common/content_switches.h"
+
+namespace util_linux {
+
+namespace {
+
+void OverrideChildProcessPath() {
+ base::FilePath child_process_path =
+ base::CommandLine::ForCurrentProcess()->GetSwitchValuePath(
+ switches::kBrowserSubprocessPath);
+ if (child_process_path.empty()) {
+ return;
+ }
+
+ // Used by ChildProcessHost::GetChildPath and PlatformCrashpadInitialization.
+ base::PathService::Override(content::CHILD_PROCESS_EXE, child_process_path);
+}
+
+} // namespace
+
+void PreSandboxStartup() {
+ OverrideChildProcessPath();
+}
+
+} // namespace util_linux
diff --git a/libcef/common/util_linux.h b/libcef/common/util_linux.h
new file mode 100644
index 00000000..2eeb6ef1
--- /dev/null
+++ b/libcef/common/util_linux.h
@@ -0,0 +1,16 @@
+// Copyright 2022 The Chromium Embedded Framework Authors. Portions copyright
+// 2011 The Chromium Authors. All rights reserved. Use of this source code is
+// governed by a BSD-style license that can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_COMMON_UTIL_LINUX_H_
+#define CEF_LIBCEF_COMMON_UTIL_LINUX_H_
+#pragma once
+
+namespace util_linux {
+
+// Called from MainDelegate::PreSandboxStartup for the main process.
+void PreSandboxStartup();
+
+} // namespace util_linux
+
+#endif // CEF_LIBCEF_COMMON_UTIL_LINUX_H_
diff --git a/libcef/common/util_mac.h b/libcef/common/util_mac.h
new file mode 100644
index 00000000..5c8c3d11
--- /dev/null
+++ b/libcef/common/util_mac.h
@@ -0,0 +1,62 @@
+// Copyright 2017 The Chromium Embedded Framework Authors. Portions copyright
+// 2011 The Chromium Authors. All rights reserved. Use of this source code is
+// governed by a BSD-style license that can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_COMMON_UTIL_MAC_H_
+#define CEF_LIBCEF_COMMON_UTIL_MAC_H_
+#pragma once
+
+#include <string>
+
+#include "base/files/file_path.h"
+
+namespace util_mac {
+
+// Returns the path to the NSLibraryDirectory (e.g. "~/Library").
+bool GetLocalLibraryDirectory(base::FilePath* result);
+
+// Returns the framework name (e.g. "Chromium Embedded Framework").
+base::FilePath::StringType GetFrameworkName();
+
+// Returns the path to the CEF framework directory inside the top-level app
+// bundle (e.g. "myapp.app/Contents/Frameworks/Chromium Embedded
+// Framework.framework"). May return an empty value if not running in an app
+// bundle.
+base::FilePath GetFrameworkDirectory();
+
+// Returns the path to the Resources directory inside the CEF framework
+// directory (e.g. "myapp.app/Contents/Frameworks/Chromium Embedded
+// Framework.framework/Resources"). May return an empty value if not running in
+// an app bundle.
+base::FilePath GetFrameworkResourcesDirectory();
+
+// Returns the path to the main (running) process executable (e.g.
+// "myapp.app/Contents/MacOS/myapp").
+base::FilePath GetMainProcessPath();
+
+// Returns the path to the top-level app bundle that contains the main process
+// executable (e.g. "myapp.app").
+base::FilePath GetMainBundlePath();
+
+// Returns the identifier for the top-level app bundle.
+std::string GetMainBundleID();
+
+// Returns the path to the Resources directory inside the top-level app bundle
+// (e.g. "myapp.app/Contents/Resources"). May return an empty value if not
+// running in an app bundle.
+base::FilePath GetMainResourcesDirectory();
+
+// Returns the path to the child process executable (e.g. "myapp.app/
+// Contents/Frameworks/myapp Helper.app/Contents/MacOS/myapp Helper"). May
+// return an empty value if not running in an app bundle.
+base::FilePath GetChildProcessPath();
+
+// Called from MainDelegate::PreSandboxStartup for the main process.
+void PreSandboxStartup();
+
+// Called from MainDelegate::BasicStartupComplete for all processes.
+void BasicStartupComplete();
+
+} // namespace util_mac
+
+#endif // CEF_LIBCEF_COMMON_UTIL_MAC_H_
diff --git a/libcef/common/util_mac.mm b/libcef/common/util_mac.mm
new file mode 100644
index 00000000..762f6355
--- /dev/null
+++ b/libcef/common/util_mac.mm
@@ -0,0 +1,161 @@
+// Copyright 2017 The Chromium Embedded Framework Authors. Portions copyright
+// 2011 The Chromium Authors. All rights reserved. Use of this source code is
+// governed by a BSD-style license that can be found in the LICENSE file.
+
+#include "libcef/common/util_mac.h"
+
+#include "libcef/common/cef_switches.h"
+
+#include "base/base_paths.h"
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/mac/bundle_locations.h"
+#include "base/mac/foundation_util.h"
+#include "base/path_service.h"
+#include "base/strings/sys_string_conversions.h"
+#include "content/public/common/content_paths.h"
+#include "content/public/common/content_switches.h"
+
+namespace util_mac {
+
+namespace {
+
+// Returns the path to the Frameworks directory inside the top-level app bundle.
+base::FilePath GetFrameworksPath() {
+ base::FilePath bundle_path = GetMainBundlePath();
+ if (bundle_path.empty()) {
+ return base::FilePath();
+ }
+
+ return bundle_path.Append(FILE_PATH_LITERAL("Contents"))
+ .Append(FILE_PATH_LITERAL("Frameworks"));
+}
+
+void OverrideFrameworkBundlePath() {
+ base::FilePath framework_path = GetFrameworkDirectory();
+ DCHECK(!framework_path.empty());
+
+ base::mac::SetOverrideFrameworkBundlePath(framework_path);
+}
+
+void OverrideOuterBundlePath() {
+ base::FilePath bundle_path = GetMainBundlePath();
+ DCHECK(!bundle_path.empty());
+
+ base::mac::SetOverrideOuterBundlePath(bundle_path);
+}
+
+void OverrideBaseBundleID() {
+ std::string bundle_id = GetMainBundleID();
+ DCHECK(!bundle_id.empty());
+
+ base::mac::SetBaseBundleID(bundle_id.c_str());
+}
+
+void OverrideChildProcessPath() {
+ base::FilePath child_process_path =
+ base::CommandLine::ForCurrentProcess()->GetSwitchValuePath(
+ switches::kBrowserSubprocessPath);
+
+ if (child_process_path.empty()) {
+ child_process_path = util_mac::GetChildProcessPath();
+ DCHECK(!child_process_path.empty());
+ }
+
+ // Used by ChildProcessHost::GetChildPath and PlatformCrashpadInitialization.
+ base::PathService::Override(content::CHILD_PROCESS_EXE, child_process_path);
+}
+
+} // namespace
+
+bool GetLocalLibraryDirectory(base::FilePath* result) {
+ return base::mac::GetLocalDirectory(NSLibraryDirectory, result);
+}
+
+base::FilePath::StringType GetFrameworkName() {
+ return FILE_PATH_LITERAL("Chromium Embedded Framework");
+}
+
+base::FilePath GetFrameworkDirectory() {
+ base::FilePath frameworks_path =
+ base::CommandLine::ForCurrentProcess()->GetSwitchValuePath(
+ switches::kFrameworkDirPath);
+ if (!frameworks_path.empty()) {
+ return frameworks_path;
+ }
+
+ frameworks_path = GetFrameworksPath();
+ if (frameworks_path.empty()) {
+ return base::FilePath();
+ }
+
+ return frameworks_path.Append(GetFrameworkName())
+ .AddExtension(FILE_PATH_LITERAL(".framework"));
+}
+
+base::FilePath GetFrameworkResourcesDirectory() {
+ base::FilePath frameworks_path = GetFrameworkDirectory();
+ if (frameworks_path.empty()) {
+ return base::FilePath();
+ }
+
+ return frameworks_path.Append(FILE_PATH_LITERAL("Resources"));
+}
+
+base::FilePath GetMainProcessPath() {
+ base::FilePath path;
+ base::PathService::Get(base::FILE_EXE, &path);
+ DCHECK(!path.empty());
+ return path;
+}
+
+base::FilePath GetMainBundlePath() {
+ base::FilePath main_bundle_path =
+ base::CommandLine::ForCurrentProcess()->GetSwitchValuePath(
+ switches::kMainBundlePath);
+ if (!main_bundle_path.empty()) {
+ return main_bundle_path;
+ }
+
+ return base::mac::GetAppBundlePath(GetMainProcessPath());
+}
+
+std::string GetMainBundleID() {
+ NSBundle* bundle = base::mac::OuterBundle();
+ return base::SysNSStringToUTF8([bundle bundleIdentifier]);
+}
+
+base::FilePath GetMainResourcesDirectory() {
+ base::FilePath bundle_path = GetMainBundlePath();
+ if (bundle_path.empty()) {
+ return base::FilePath();
+ }
+
+ return bundle_path.Append(FILE_PATH_LITERAL("Contents"))
+ .Append(FILE_PATH_LITERAL("Resources"));
+}
+
+base::FilePath GetChildProcessPath() {
+ base::FilePath frameworks_path = GetFrameworksPath();
+ if (frameworks_path.empty()) {
+ return base::FilePath();
+ }
+
+ std::string exe_name = GetMainProcessPath().BaseName().value();
+ return frameworks_path.Append(FILE_PATH_LITERAL(exe_name + " Helper.app"))
+ .Append(FILE_PATH_LITERAL("Contents"))
+ .Append(FILE_PATH_LITERAL("MacOS"))
+ .Append(FILE_PATH_LITERAL(exe_name + " Helper"));
+}
+
+void PreSandboxStartup() {
+ OverrideChildProcessPath();
+}
+
+void BasicStartupComplete() {
+ OverrideFrameworkBundlePath();
+ OverrideOuterBundlePath();
+ OverrideBaseBundleID();
+}
+
+} // namespace util_mac
diff --git a/libcef/common/value_base.cc b/libcef/common/value_base.cc
new file mode 100644
index 00000000..55989be0
--- /dev/null
+++ b/libcef/common/value_base.cc
@@ -0,0 +1,242 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "libcef/common/value_base.h"
+
+CefValueController::CefValueController()
+ : owner_value_(nullptr), owner_object_(nullptr) {}
+
+CefValueController::~CefValueController() {
+ // Everything should already have been removed.
+ DCHECK(!owner_value_ && !owner_object_);
+ DCHECK(reference_map_.empty());
+ DCHECK(dependency_map_.empty());
+}
+
+void CefValueController::SetOwner(void* value, Object* object) {
+ DCHECK(value && object);
+
+ // Controller should already be locked.
+ DCHECK(locked());
+
+ // Owner should only be set once.
+ DCHECK(!owner_value_ && !owner_object_);
+
+ owner_value_ = value;
+ owner_object_ = object;
+}
+
+void CefValueController::AddReference(void* value, Object* object) {
+ DCHECK(value && object);
+
+ // Controller should already be locked.
+ DCHECK(locked());
+
+ // Controller should currently have an owner.
+ DCHECK(owner_value_);
+
+ // Values should only be added once.
+ DCHECK(reference_map_.find(value) == reference_map_.end());
+ DCHECK(value != owner_value_);
+
+ reference_map_.insert(std::make_pair(value, object));
+}
+
+void CefValueController::Remove(void* value, bool notify_object) {
+ DCHECK(value);
+
+ // Controller should already be locked.
+ DCHECK(locked());
+
+ // Controller should currently have an owner.
+ DCHECK(owner_value_);
+
+ if (value == owner_value_) {
+ // Should never notify when removing the owner object.
+ DCHECK(!notify_object);
+
+ owner_value_ = nullptr;
+ owner_object_ = nullptr;
+
+ // Remove all references.
+ if (reference_map_.size() > 0) {
+ ReferenceMap::iterator it = reference_map_.begin();
+ for (; it != reference_map_.end(); ++it) {
+ it->second->OnControlRemoved();
+ }
+ reference_map_.clear();
+ }
+
+ // Remove all dependencies.
+ dependency_map_.clear();
+ } else {
+ ReferenceMap::iterator it = reference_map_.find(value);
+ if (it != reference_map_.end()) {
+ // Remove the reference.
+ if (notify_object) {
+ it->second->OnControlRemoved();
+ }
+ reference_map_.erase(it);
+ }
+ }
+}
+
+CefValueController::Object* CefValueController::Get(void* value) {
+ DCHECK(value);
+
+ // Controller should already be locked.
+ DCHECK(locked());
+
+ if (value == owner_value_) {
+ return owner_object_;
+ } else {
+ ReferenceMap::iterator it = reference_map_.find(value);
+ if (it != reference_map_.end()) {
+ return it->second;
+ }
+ return nullptr;
+ }
+}
+
+void CefValueController::AddDependency(void* parent, void* child) {
+ DCHECK(parent && child && parent != child);
+
+ // Controller should already be locked.
+ DCHECK(locked());
+
+ DependencyMap::iterator it = dependency_map_.find(parent);
+ if (it == dependency_map_.end()) {
+ // New set.
+ DependencySet set;
+ set.insert(child);
+ dependency_map_.insert(std::make_pair(parent, set));
+ } else if (it->second.find(child) == it->second.end()) {
+ // Update existing set.
+ it->second.insert(child);
+ }
+}
+
+void CefValueController::RemoveDependencies(void* value) {
+ DCHECK(value);
+
+ // Controller should already be locked.
+ DCHECK(locked());
+
+ if (dependency_map_.empty()) {
+ return;
+ }
+
+ DependencyMap::iterator it_dependency = dependency_map_.find(value);
+ if (it_dependency == dependency_map_.end()) {
+ return;
+ }
+
+ // Start with the set of dependencies for the current value.
+ DependencySet remove_set = it_dependency->second;
+ dependency_map_.erase(it_dependency);
+
+ DependencySet::iterator it_value;
+ ReferenceMap::iterator it_reference;
+
+ while (remove_set.size() > 0) {
+ it_value = remove_set.begin();
+ value = *it_value;
+ remove_set.erase(it_value);
+
+ // Does the current value have dependencies?
+ it_dependency = dependency_map_.find(value);
+ if (it_dependency != dependency_map_.end()) {
+ // Append the dependency set to the remove set.
+ remove_set.insert(it_dependency->second.begin(),
+ it_dependency->second.end());
+ dependency_map_.erase(it_dependency);
+ }
+
+ // Does the current value have a reference?
+ it_reference = reference_map_.find(value);
+ if (it_reference != reference_map_.end()) {
+ // Remove the reference.
+ it_reference->second->OnControlRemoved();
+ reference_map_.erase(it_reference);
+ }
+ }
+}
+
+void CefValueController::TakeFrom(CefValueController* other) {
+ DCHECK(other);
+
+ // Both controllers should already be locked.
+ DCHECK(locked());
+ DCHECK(other->locked());
+
+ if (!other->reference_map_.empty()) {
+ // Transfer references from the other to this.
+ ReferenceMap::iterator it = other->reference_map_.begin();
+ for (; it != other->reference_map_.end(); ++it) {
+ // References should only be added once.
+ DCHECK(reference_map_.find(it->first) == reference_map_.end());
+ reference_map_.insert(std::make_pair(it->first, it->second));
+ }
+ other->reference_map_.clear();
+ }
+
+ if (!other->dependency_map_.empty()) {
+ // Transfer dependencies from the other to this.
+ DependencyMap::iterator it_other = other->dependency_map_.begin();
+ for (; it_other != other->dependency_map_.end(); ++it_other) {
+ DependencyMap::iterator it_me = dependency_map_.find(it_other->first);
+ if (it_me == dependency_map_.end()) {
+ // All children are new.
+ dependency_map_.insert(
+ std::make_pair(it_other->first, it_other->second));
+ } else {
+ // Evaluate each child.
+ DependencySet::iterator it_other_set = it_other->second.begin();
+ for (; it_other_set != it_other->second.end(); ++it_other_set) {
+ if (it_me->second.find(*it_other_set) == it_me->second.end()) {
+ it_me->second.insert(*it_other_set);
+ }
+ }
+ }
+ }
+ }
+}
+
+void CefValueController::Swap(void* old_value, void* new_value) {
+ DCHECK(old_value && new_value && old_value != new_value);
+
+ // Controller should already be locked.
+ DCHECK(locked());
+
+ if (owner_value_ == old_value) {
+ owner_value_ = new_value;
+ }
+
+ if (!reference_map_.empty()) {
+ ReferenceMap::iterator it = reference_map_.find(old_value);
+ if (it != reference_map_.end()) {
+ // References should only be added once.
+ DCHECK(reference_map_.find(new_value) == reference_map_.end());
+ reference_map_.insert(std::make_pair(new_value, it->second));
+ reference_map_.erase(it);
+ }
+ }
+
+ if (!dependency_map_.empty()) {
+ DependencyMap::iterator it = dependency_map_.find(old_value);
+ if (it != dependency_map_.end()) {
+ dependency_map_.insert(std::make_pair(new_value, it->second));
+ dependency_map_.erase(it);
+ }
+
+ it = dependency_map_.begin();
+ for (; it != dependency_map_.end(); ++it) {
+ DependencySet::iterator dit = it->second.find(old_value);
+ if (dit != it->second.end()) {
+ it->second.insert(new_value);
+ it->second.erase(dit);
+ }
+ }
+ }
+}
diff --git a/libcef/common/value_base.h b/libcef/common/value_base.h
new file mode 100644
index 00000000..ce50ba51
--- /dev/null
+++ b/libcef/common/value_base.h
@@ -0,0 +1,442 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_COMMON_VALUE_BASE_H_
+#define CEF_LIBCEF_COMMON_VALUE_BASE_H_
+#pragma once
+
+#include <map>
+#include <set>
+#include "include/cef_base.h"
+
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/notreached.h"
+#include "base/synchronization/lock.h"
+#include "base/thread_annotations.h"
+#include "base/threading/platform_thread.h"
+
+// Controller implementation base class.
+class CefValueController
+ : public base::RefCountedThreadSafe<CefValueController> {
+ public:
+ // Implemented by a class controlled using the access controller.
+ class Object {
+ public:
+ virtual ~Object() {}
+
+ // Called when the value has been removed.
+ virtual void OnControlRemoved() = 0;
+ };
+
+ // Encapsulates context locking and verification logic.
+ class AutoLock {
+ public:
+ explicit AutoLock(CefValueController* impl)
+ : impl_(impl), verified_(impl && impl->VerifyThread()) {
+ DCHECK(impl);
+ if (verified_) {
+ impl_->lock();
+ }
+ }
+
+ AutoLock(const AutoLock&) = delete;
+ AutoLock& operator=(const AutoLock&) = delete;
+
+ ~AutoLock() {
+ if (verified_) {
+ impl_->unlock();
+ }
+ }
+
+ inline bool verified() { return verified_; }
+
+ private:
+ scoped_refptr<CefValueController> impl_;
+ bool verified_;
+ };
+
+ CefValueController();
+
+ CefValueController(const CefValueController&) = delete;
+ CefValueController& operator=(const CefValueController&) = delete;
+
+ // Returns true if this controller is thread safe.
+ virtual bool thread_safe() = 0;
+
+ // Returns true if the current thread is allowed to access this controller.
+ virtual bool on_correct_thread() = 0;
+
+ // Lock the controller.
+ virtual void lock() = 0;
+
+ // Unlock the controller.
+ virtual void unlock() = 0;
+
+ // Returns true if the controller is locked on the current thread.
+ virtual bool locked() = 0;
+
+ // Assert that the lock has been acquired.
+ virtual void AssertLockAcquired() = 0;
+
+ // Verify that the current thread is correct for accessing the controller.
+ inline bool VerifyThread() {
+ if (!thread_safe() && !on_correct_thread()) {
+ // This object should only be accessed from the thread that created it.
+ NOTREACHED() << "object accessed from incorrect thread.";
+ return false;
+ }
+ return true;
+ }
+
+ // The controller must already be locked before calling the below methods.
+
+ // Set the owner for this controller.
+ void SetOwner(void* value, Object* object);
+
+ // Add a reference value and associated object.
+ void AddReference(void* value, Object* object);
+
+ // Remove the value. If |notify_object| is true the removed object will be
+ // notified. If |value| is the owner all reference objects will be removed.
+ // If |value| has dependencies those objects will also be removed.
+ void Remove(void* value, bool notify_object);
+
+ // Returns the object for the specified value.
+ Object* Get(void* value);
+
+ // Add a dependency between |parent| and |child|.
+ void AddDependency(void* parent, void* child);
+
+ // Recursively removes any dependent values.
+ void RemoveDependencies(void* value);
+
+ // Takes ownership of all references and dependencies currently controlled by
+ // |other|. The |other| controller must already be locked.
+ void TakeFrom(CefValueController* other);
+
+ // Replace all instances of |old_value| with |new_value|. Used in cases where
+ // move semantics may move the contents of an object without retaining the
+ // object pointer itself.
+ void Swap(void* old_value, void* new_value);
+
+ protected:
+ friend class base::RefCountedThreadSafe<CefValueController>;
+
+ virtual ~CefValueController();
+
+ private:
+ // Owner object.
+ void* owner_value_;
+ Object* owner_object_;
+
+ // Map of reference objects.
+ using ReferenceMap = std::map<void*, Object*>;
+ ReferenceMap reference_map_;
+
+ // Map of dependency objects.
+ using DependencySet = std::set<void*>;
+ using DependencyMap = std::map<void*, DependencySet>;
+ DependencyMap dependency_map_;
+};
+
+// Thread-safe access control implementation.
+class CefValueControllerThreadSafe : public CefValueController {
+ public:
+ explicit CefValueControllerThreadSafe() : locked_thread_id_(0) {}
+
+ CefValueControllerThreadSafe(const CefValueControllerThreadSafe&) = delete;
+ CefValueControllerThreadSafe& operator=(const CefValueControllerThreadSafe&) =
+ delete;
+
+ // CefValueController methods.
+ bool thread_safe() override { return true; }
+ bool on_correct_thread() override { return true; }
+ void lock() override NO_THREAD_SAFETY_ANALYSIS {
+ lock_.Acquire();
+ locked_thread_id_ = base::PlatformThread::CurrentId();
+ }
+ void unlock() override NO_THREAD_SAFETY_ANALYSIS {
+ locked_thread_id_ = 0;
+ lock_.Release();
+ }
+ bool locked() override {
+ return (locked_thread_id_ == base::PlatformThread::CurrentId());
+ }
+ void AssertLockAcquired() override { lock_.AssertAcquired(); }
+
+ private:
+ base::Lock lock_;
+ base::PlatformThreadId locked_thread_id_;
+};
+
+// Non-thread-safe access control implementation.
+class CefValueControllerNonThreadSafe : public CefValueController {
+ public:
+ explicit CefValueControllerNonThreadSafe()
+ : thread_id_(base::PlatformThread::CurrentId()) {}
+
+ CefValueControllerNonThreadSafe(const CefValueControllerNonThreadSafe&) =
+ delete;
+ CefValueControllerNonThreadSafe& operator=(
+ const CefValueControllerNonThreadSafe&) = delete;
+
+ // CefValueController methods.
+ bool thread_safe() override { return false; }
+ bool on_correct_thread() override {
+ return (thread_id_ == base::PlatformThread::CurrentId());
+ }
+ void lock() override {}
+ void unlock() override {}
+ bool locked() override { return on_correct_thread(); }
+ void AssertLockAcquired() override { DCHECK(locked()); }
+
+ private:
+ base::PlatformThreadId thread_id_;
+};
+
+// Helper macros for verifying context.
+
+#define CEF_VALUE_VERIFY_RETURN_VOID_EX(object, modify) \
+ if (!VerifyAttached()) \
+ return; \
+ AutoLock auto_lock(object, modify); \
+ if (!auto_lock.verified()) \
+ return;
+
+#define CEF_VALUE_VERIFY_RETURN_VOID(modify) \
+ CEF_VALUE_VERIFY_RETURN_VOID_EX(this, modify)
+
+#define CEF_VALUE_VERIFY_RETURN_EX(object, modify, error_val) \
+ if (!VerifyAttached()) \
+ return error_val; \
+ AutoLock auto_lock(object, modify); \
+ if (!auto_lock.verified()) \
+ return error_val;
+
+#define CEF_VALUE_VERIFY_RETURN(modify, error_val) \
+ CEF_VALUE_VERIFY_RETURN_EX(this, modify, error_val)
+
+// Template class for implementing CEF wrappers of other types.
+template <class CefType, class ValueType>
+class CefValueBase : public CefType, public CefValueController::Object {
+ public:
+ // Specifies how the value will be used.
+ enum ValueMode {
+ // A reference to a value managed by an existing controller. These values
+ // can be safely detached but ownership should not be transferred (make a
+ // copy of the value instead).
+ kReference,
+
+ // The value has its own controller and will be deleted on destruction.
+ // These values can only be detached to another controller otherwise any
+ // references will not be properly managed.
+ kOwnerWillDelete,
+
+ // The value has its own controller and will not be deleted on destruction.
+ // This should only be used for global values or scope-limited values that
+ // will be explicitly detached.
+ kOwnerNoDelete,
+ };
+
+ // Create a new object.
+ // If |read_only| is true mutable access will not be allowed.
+ // If |parent_value| is non-NULL and the value mode is kReference a dependency
+ // will be added.
+ CefValueBase(ValueType* value,
+ void* parent_value,
+ ValueMode value_mode,
+ bool read_only,
+ CefValueController* controller)
+ : value_(value),
+ value_mode_(value_mode),
+ read_only_(read_only),
+ controller_(controller) {
+ DCHECK(value_);
+
+ // Specifying a parent value for a non-reference doesn't make sense.
+ DCHECK(!(!reference() && parent_value));
+
+ if (!reference() && !controller_.get()) {
+ // For owned values default to using a new multi-threaded controller.
+ controller_ = new CefValueControllerThreadSafe();
+ SetOwnsController();
+ }
+
+ // A controller is required.
+ DCHECK(controller_.get());
+
+ if (reference()) {
+ // Register the reference with the controller.
+ controller_->AddReference(value_, this);
+
+ // Add a dependency on the parent value.
+ if (parent_value) {
+ controller_->AddDependency(parent_value, value_);
+ }
+ }
+ }
+
+ CefValueBase(const CefValueBase&) = delete;
+ CefValueBase& operator=(const CefValueBase&) = delete;
+
+ ~CefValueBase() override {
+ if (controller_.get() && value_) {
+ Delete();
+ }
+ }
+
+ // True if the underlying value is referenced instead of owned.
+ inline bool reference() const { return (value_mode_ == kReference); }
+
+ // True if the underlying value will be deleted.
+ inline bool will_delete() const { return (value_mode_ == kOwnerWillDelete); }
+
+ // True if access to the underlying value is read-only.
+ inline bool read_only() const { return read_only_; }
+
+ // True if the underlying value has been detached.
+ inline bool detached() const { return !controller_.get(); }
+
+ // Returns the controller.
+ inline CefValueController* controller() const { return controller_.get(); }
+
+ // Deletes the underlying value.
+ void Delete() {
+ CEF_VALUE_VERIFY_RETURN_VOID(false);
+
+ // Remove the object from the controller. If this is the owner object any
+ // references will be detached.
+ controller()->Remove(value_, false);
+
+ if (will_delete()) {
+ // Remove any dependencies.
+ controller()->RemoveDependencies(value_);
+
+ // Delete the value.
+ DeleteValue(value_);
+ }
+
+ controller_ = nullptr;
+ value_ = nullptr;
+ }
+
+ // Detaches the underlying value and returns a pointer to it. If this is an
+ // owner and a |new_controller| value is specified any existing references
+ // will be passed to the new controller.
+ [[nodiscard]] ValueType* Detach(CefValueController* new_controller) {
+ CEF_VALUE_VERIFY_RETURN(false, nullptr);
+
+ if (new_controller && !reference()) {
+ // Pass any existing references and dependencies to the new controller.
+ // They will be removed from this controller.
+ new_controller->TakeFrom(controller());
+ }
+
+ // Remove the object from the controller. If this is the owner object any
+ // references will be detached.
+ controller()->Remove(value_, false);
+ controller_ = nullptr;
+
+ // Return the old value.
+ ValueType* old_val = value_;
+ value_ = nullptr;
+ return old_val;
+ }
+
+ // Verify that the value is attached.
+ inline bool VerifyAttached() const {
+ if (detached()) {
+ // This object should not be accessed after being detached.
+ NOTREACHED() << "object accessed after being detached.";
+ return false;
+ }
+ return true;
+ }
+
+ protected:
+ // CefValueController::Object methods.
+ void OnControlRemoved() override {
+ DCHECK(controller()->locked());
+
+ // Only references should be removed in this manner.
+ DCHECK(reference());
+
+ controller_ = nullptr;
+ value_ = nullptr;
+ }
+
+ // Override to customize value deletion.
+ virtual void DeleteValue(ValueType* value) { delete value; }
+
+ // Returns a mutable reference to the value.
+ inline ValueType* mutable_value() const {
+ DCHECK(value_);
+ DCHECK(!read_only_);
+ DCHECK(controller()->locked());
+ return value_;
+ }
+
+ // Returns a const reference to the value.
+ inline const ValueType& const_value() const {
+ DCHECK(value_);
+ DCHECK(controller()->locked());
+ return *value_;
+ }
+
+ // Returns an mutable reference to the value without checking read-only state.
+ inline ValueType* mutable_value_unchecked() const {
+ return const_cast<ValueType*>(&const_value());
+ }
+
+ // Verify that the value can be accessed.
+ inline bool VerifyAccess(bool modify) const {
+ // The controller must already be locked.
+ DCHECK(controller()->locked());
+
+ if (read_only() && modify) {
+ // This object cannot be modified.
+ NOTREACHED() << "mutation attempted on read-only object.";
+ return false;
+ }
+
+ return true;
+ }
+
+ // Used to indicate that this object owns the controller.
+ inline void SetOwnsController() {
+ CefValueController::AutoLock lock_scope(controller_.get());
+ if (lock_scope.verified()) {
+ controller_->SetOwner(value_, this);
+ }
+ }
+
+ // Encapsulates value locking and verification logic.
+ class AutoLock {
+ public:
+ explicit AutoLock(CefValueBase* impl, bool modify)
+ : auto_lock_(impl->controller()) {
+ verified_ = (auto_lock_.verified() && impl->VerifyAccess(modify));
+ }
+
+ AutoLock(const AutoLock&) = delete;
+ AutoLock& operator=(const AutoLock&) = delete;
+
+ inline bool verified() { return verified_; }
+
+ private:
+ CefValueController::AutoLock auto_lock_;
+ bool verified_;
+ };
+
+ private:
+ ValueType* value_;
+ ValueMode value_mode_;
+ bool read_only_;
+ scoped_refptr<CefValueController> controller_;
+
+ IMPLEMENT_REFCOUNTING(CefValueBase);
+};
+
+#endif // CEF_LIBCEF_COMMON_VALUE_BASE_H_
diff --git a/libcef/common/values_impl.cc b/libcef/common/values_impl.cc
new file mode 100644
index 00000000..078410a0
--- /dev/null
+++ b/libcef/common/values_impl.cc
@@ -0,0 +1,1554 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "libcef/common/values_impl.h"
+
+#include <algorithm>
+#include <vector>
+
+#include "base/memory/ptr_util.h"
+
+namespace {
+
+// Removes empty dictionaries from |dict|, potentially nested.
+// Does not modify empty lists.
+// From chrome/browser/chromeos/extensions/echo_private/echo_private_api.cc
+void RemoveEmptyValueDicts(base::Value::Dict& dict) {
+ auto it = dict.begin();
+ while (it != dict.end()) {
+ base::Value& value = it->second;
+ if (value.is_dict()) {
+ base::Value::Dict& sub_dict = value.GetDict();
+ RemoveEmptyValueDicts(sub_dict);
+ if (sub_dict.empty()) {
+ it = dict.erase(it);
+ continue;
+ }
+ }
+ it++;
+ }
+}
+
+} // namespace
+
+// CefValueImpl implementation.
+
+// static
+CefRefPtr<CefValue> CefValue::Create() {
+ // Start with VTYPE_NULL instead of VTYPE_INVALID for backwards compatibility.
+ return new CefValueImpl(base::Value());
+}
+
+// static
+CefRefPtr<CefValue> CefValueImpl::GetOrCreateRefOrCopy(
+ base::Value* value,
+ void* parent_value,
+ bool read_only,
+ CefValueController* controller) {
+ DCHECK(value);
+
+ if (value->is_blob()) {
+ return new CefValueImpl(
+ CefBinaryValueImpl::GetOrCreateRef(value, parent_value, controller));
+ }
+
+ if (value->is_dict()) {
+ return new CefValueImpl(CefDictionaryValueImpl::GetOrCreateRef(
+ value, parent_value, read_only, controller));
+ }
+
+ if (value->is_list()) {
+ return new CefValueImpl(CefListValueImpl::GetOrCreateRef(
+ value, parent_value, read_only, controller));
+ }
+
+ return new CefValueImpl(value->Clone());
+}
+
+CefValueImpl::CefValueImpl() {}
+
+CefValueImpl::CefValueImpl(base::Value value) {
+ SetValue(std::move(value));
+}
+
+CefValueImpl::CefValueImpl(CefRefPtr<CefBinaryValue> value)
+ : binary_value_(value) {}
+
+CefValueImpl::CefValueImpl(CefRefPtr<CefDictionaryValue> value)
+ : dictionary_value_(value) {}
+
+CefValueImpl::CefValueImpl(CefRefPtr<CefListValue> value)
+ : list_value_(value) {}
+
+CefValueImpl::~CefValueImpl() {}
+
+void CefValueImpl::SetValue(base::Value value) {
+ base::AutoLock lock_scope(lock_);
+ SetValueInternal(absl::make_optional(std::move(value)));
+}
+
+base::Value CefValueImpl::CopyValue() {
+ base::AutoLock lock_scope(lock_);
+
+ if (binary_value_) {
+ return static_cast<CefBinaryValueImpl*>(binary_value_.get())->CopyValue();
+ }
+
+ if (dictionary_value_) {
+ return static_cast<CefDictionaryValueImpl*>(dictionary_value_.get())
+ ->CopyValue();
+ }
+
+ if (list_value_) {
+ return static_cast<CefListValueImpl*>(list_value_.get())->CopyValue();
+ }
+
+ return value_->Clone();
+}
+
+std::unique_ptr<base::Value> CefValueImpl::CopyOrDetachValue(
+ CefValueController* new_controller) {
+ base::AutoLock lock_scope(lock_);
+
+ if (binary_value_) {
+ return static_cast<CefBinaryValueImpl*>(binary_value_.get())
+ ->CopyOrDetachValue(new_controller);
+ }
+
+ if (dictionary_value_) {
+ return static_cast<CefDictionaryValueImpl*>(dictionary_value_.get())
+ ->CopyOrDetachValue(new_controller);
+ }
+
+ if (list_value_) {
+ return static_cast<CefListValueImpl*>(list_value_.get())
+ ->CopyOrDetachValue(new_controller);
+ }
+
+ return std::make_unique<base::Value>(value_->Clone());
+}
+
+void CefValueImpl::SwapValue(base::Value* new_value,
+ void* new_parent_value,
+ CefValueController* new_controller) {
+ base::AutoLock lock_scope(lock_);
+
+ if (binary_value_) {
+ binary_value_ = CefBinaryValueImpl::GetOrCreateRef(
+ new_value, new_parent_value, new_controller);
+ } else if (dictionary_value_) {
+ dictionary_value_ = CefDictionaryValueImpl::GetOrCreateRef(
+ new_value, new_parent_value, false, new_controller);
+ } else if (list_value_) {
+ list_value_ = CefListValueImpl::GetOrCreateRef(new_value, new_parent_value,
+ false, new_controller);
+ }
+}
+
+bool CefValueImpl::IsValid() {
+ base::AutoLock lock_scope(lock_);
+
+ if (binary_value_) {
+ return binary_value_->IsValid();
+ }
+ if (dictionary_value_) {
+ return dictionary_value_->IsValid();
+ }
+ if (list_value_) {
+ return list_value_->IsValid();
+ }
+
+ return (value_ != nullptr);
+}
+
+bool CefValueImpl::IsOwned() {
+ base::AutoLock lock_scope(lock_);
+
+ if (binary_value_) {
+ return binary_value_->IsOwned();
+ }
+ if (dictionary_value_) {
+ return dictionary_value_->IsOwned();
+ }
+ if (list_value_) {
+ return list_value_->IsOwned();
+ }
+
+ return false;
+}
+
+bool CefValueImpl::IsReadOnly() {
+ base::AutoLock lock_scope(lock_);
+
+ if (binary_value_) {
+ return true;
+ }
+ if (dictionary_value_) {
+ return dictionary_value_->IsReadOnly();
+ }
+ if (list_value_) {
+ return list_value_->IsReadOnly();
+ }
+
+ return false;
+}
+
+bool CefValueImpl::IsSame(CefRefPtr<CefValue> that) {
+ if (that.get() == this) {
+ return true;
+ }
+ if (!that.get() || that->GetType() != GetType()) {
+ return false;
+ }
+
+ CefValueImpl* impl = static_cast<CefValueImpl*>(that.get());
+
+ base::AutoLock lock_scope(lock_);
+ base::AutoLock lock_scope2(impl->lock_);
+
+ if (binary_value_) {
+ return binary_value_->IsSame(impl->binary_value_);
+ }
+ if (dictionary_value_) {
+ return dictionary_value_->IsSame(impl->dictionary_value_);
+ }
+ if (list_value_) {
+ return list_value_->IsSame(impl->list_value_);
+ }
+
+ // Simple types are never the same.
+ return false;
+}
+
+bool CefValueImpl::IsEqual(CefRefPtr<CefValue> that) {
+ if (that.get() == this) {
+ return true;
+ }
+ if (!that.get() || that->GetType() != GetType()) {
+ return false;
+ }
+
+ CefValueImpl* impl = static_cast<CefValueImpl*>(that.get());
+
+ base::AutoLock lock_scope(lock_);
+ base::AutoLock lock_scope2(impl->lock_);
+
+ if (binary_value_) {
+ return binary_value_->IsEqual(impl->binary_value_);
+ }
+ if (dictionary_value_) {
+ return dictionary_value_->IsEqual(impl->dictionary_value_);
+ }
+ if (list_value_) {
+ return list_value_->IsEqual(impl->list_value_);
+ }
+
+ if (!value_) { // Invalid types are equal.
+ return true;
+ }
+
+ return *value_ == *(impl->value_.get());
+}
+
+CefRefPtr<CefValue> CefValueImpl::Copy() {
+ base::AutoLock lock_scope(lock_);
+
+ if (binary_value_) {
+ return new CefValueImpl(binary_value_->Copy());
+ }
+ if (dictionary_value_) {
+ return new CefValueImpl(dictionary_value_->Copy(false));
+ }
+ if (list_value_) {
+ return new CefValueImpl(list_value_->Copy());
+ }
+ if (value_) {
+ return new CefValueImpl(value_->Clone());
+ }
+
+ return new CefValueImpl();
+}
+
+CefValueType CefValueImpl::GetType() {
+ base::AutoLock lock_scope(lock_);
+
+ if (binary_value_) {
+ return VTYPE_BINARY;
+ }
+ if (dictionary_value_) {
+ return VTYPE_DICTIONARY;
+ }
+ if (list_value_) {
+ return VTYPE_LIST;
+ }
+
+ if (value_) {
+ switch (value_->type()) {
+ case base::Value::Type::NONE:
+ return VTYPE_NULL;
+ case base::Value::Type::BOOLEAN:
+ return VTYPE_BOOL;
+ case base::Value::Type::INTEGER:
+ return VTYPE_INT;
+ case base::Value::Type::DOUBLE:
+ return VTYPE_DOUBLE;
+ case base::Value::Type::STRING:
+ return VTYPE_STRING;
+ default:
+ NOTREACHED();
+ break;
+ }
+ }
+
+ return VTYPE_INVALID;
+}
+
+bool CefValueImpl::GetBool() {
+ base::AutoLock lock_scope(lock_);
+
+ bool ret_value = false;
+ if (value_ && value_->is_bool()) {
+ ret_value = value_->GetBool();
+ }
+ return ret_value;
+}
+
+int CefValueImpl::GetInt() {
+ base::AutoLock lock_scope(lock_);
+
+ int ret_value = 0;
+ if (value_ && value_->is_int()) {
+ ret_value = value_->GetInt();
+ }
+ return ret_value;
+}
+
+double CefValueImpl::GetDouble() {
+ base::AutoLock lock_scope(lock_);
+
+ double ret_value = 0;
+ if (value_ && value_->is_double()) {
+ ret_value = value_->GetDouble();
+ }
+ return ret_value;
+}
+
+CefString CefValueImpl::GetString() {
+ base::AutoLock lock_scope(lock_);
+
+ std::string ret_value;
+ if (value_ && value_->is_string()) {
+ ret_value = value_->GetString();
+ }
+ return ret_value;
+}
+
+CefRefPtr<CefBinaryValue> CefValueImpl::GetBinary() {
+ base::AutoLock lock_scope(lock_);
+ return binary_value_;
+}
+
+CefRefPtr<CefDictionaryValue> CefValueImpl::GetDictionary() {
+ base::AutoLock lock_scope(lock_);
+ return dictionary_value_;
+}
+
+CefRefPtr<CefListValue> CefValueImpl::GetList() {
+ base::AutoLock lock_scope(lock_);
+ return list_value_;
+}
+
+bool CefValueImpl::SetNull() {
+ SetValue(base::Value());
+ return true;
+}
+
+bool CefValueImpl::SetBool(bool value) {
+ SetValue(base::Value(value));
+ return true;
+}
+
+bool CefValueImpl::SetInt(int value) {
+ SetValue(base::Value(value));
+ return true;
+}
+
+bool CefValueImpl::SetDouble(double value) {
+ SetValue(base::Value(value));
+ return true;
+}
+
+bool CefValueImpl::SetString(const CefString& value) {
+ SetValue(base::Value(value.ToString()));
+ return true;
+}
+
+bool CefValueImpl::SetBinary(CefRefPtr<CefBinaryValue> value) {
+ base::AutoLock lock_scope(lock_);
+ SetValueInternal(absl::nullopt);
+ binary_value_ = value;
+ return true;
+}
+
+bool CefValueImpl::SetDictionary(CefRefPtr<CefDictionaryValue> value) {
+ base::AutoLock lock_scope(lock_);
+ SetValueInternal(absl::nullopt);
+ dictionary_value_ = value;
+ return true;
+}
+
+bool CefValueImpl::SetList(CefRefPtr<CefListValue> value) {
+ base::AutoLock lock_scope(lock_);
+ SetValueInternal(absl::nullopt);
+ list_value_ = value;
+ return true;
+}
+
+void CefValueImpl::SetValueInternal(absl::optional<base::Value> value) {
+ lock_.AssertAcquired();
+
+ value_.reset(nullptr);
+ binary_value_ = nullptr;
+ dictionary_value_ = nullptr;
+ list_value_ = nullptr;
+
+ if (value) {
+ switch ((*value).type()) {
+ case base::Value::Type::BINARY:
+ binary_value_ = new CefBinaryValueImpl(std::move(*value));
+ break;
+ case base::Value::Type::DICTIONARY:
+ dictionary_value_ =
+ new CefDictionaryValueImpl(std::move(*value), /*read_only=*/false);
+ break;
+ case base::Value::Type::LIST:
+ list_value_ =
+ new CefListValueImpl(std::move(*value), /*read_only=*/false);
+ break;
+ default:
+ value_ = std::make_unique<base::Value>(std::move(*value));
+ break;
+ }
+ }
+}
+
+CefValueController* CefValueImpl::GetValueController() const {
+ lock_.AssertAcquired();
+
+ if (binary_value_) {
+ return static_cast<CefBinaryValueImpl*>(binary_value_.get())->controller();
+ } else if (dictionary_value_) {
+ return static_cast<CefDictionaryValueImpl*>(dictionary_value_.get())
+ ->controller();
+ } else if (list_value_) {
+ return static_cast<CefListValueImpl*>(list_value_.get())->controller();
+ }
+
+ return nullptr;
+}
+
+void CefValueImpl::AcquireLock() NO_THREAD_SAFETY_ANALYSIS {
+ lock_.Acquire();
+
+ CefValueController* controller = GetValueController();
+ if (controller) {
+ controller->lock();
+ }
+}
+
+void CefValueImpl::ReleaseLock() NO_THREAD_SAFETY_ANALYSIS {
+ CefValueController* controller = GetValueController();
+ if (controller) {
+ controller->AssertLockAcquired();
+ controller->unlock();
+ }
+
+ lock_.Release();
+}
+
+base::Value* CefValueImpl::GetValueUnsafe() const {
+ lock_.AssertAcquired();
+
+ if (binary_value_) {
+ return static_cast<CefBinaryValueImpl*>(binary_value_.get())
+ ->GetValueUnsafe();
+ } else if (dictionary_value_) {
+ return static_cast<CefDictionaryValueImpl*>(dictionary_value_.get())
+ ->GetValueUnsafe();
+ } else if (list_value_) {
+ return static_cast<CefListValueImpl*>(list_value_.get())->GetValueUnsafe();
+ }
+
+ return value_.get();
+}
+
+// CefBinaryValueImpl implementation.
+
+CefRefPtr<CefBinaryValue> CefBinaryValue::Create(const void* data,
+ size_t data_size) {
+ DCHECK(data);
+ DCHECK_GT(data_size, (size_t)0);
+ if (!data || data_size == 0) {
+ return nullptr;
+ }
+
+ return new CefBinaryValueImpl(static_cast<char*>(const_cast<void*>(data)),
+ data_size);
+}
+
+// static
+CefRefPtr<CefBinaryValue> CefBinaryValueImpl::GetOrCreateRef(
+ base::Value* value,
+ void* parent_value,
+ CefValueController* controller) {
+ DCHECK(value);
+ DCHECK(parent_value);
+ DCHECK(controller);
+
+ CefValueController::Object* object = controller->Get(value);
+ if (object) {
+ return static_cast<CefBinaryValueImpl*>(object);
+ }
+
+ return new CefBinaryValueImpl(value, parent_value,
+ CefBinaryValueImpl::kReference, controller);
+}
+
+CefBinaryValueImpl::CefBinaryValueImpl(base::Value value)
+ : CefBinaryValueImpl(new base::Value(std::move(value)),
+ /*will_delete=*/true) {}
+
+CefBinaryValueImpl::CefBinaryValueImpl(base::Value* value, bool will_delete)
+ : CefBinaryValueImpl(value,
+ nullptr,
+ will_delete ? kOwnerWillDelete : kOwnerNoDelete,
+ nullptr) {}
+
+CefBinaryValueImpl::CefBinaryValueImpl(char* data, size_t data_size)
+ : CefBinaryValueImpl(
+ new base::Value(std::vector<char>(data, data + data_size)),
+ nullptr,
+ kOwnerWillDelete,
+ nullptr) {}
+
+base::Value CefBinaryValueImpl::CopyValue() {
+ CEF_VALUE_VERIFY_RETURN(false, base::Value());
+ return const_value().Clone();
+}
+
+std::unique_ptr<base::Value> CefBinaryValueImpl::CopyOrDetachValue(
+ CefValueController* new_controller) {
+ if (!will_delete()) {
+ // Copy the value.
+ return std::make_unique<base::Value>(CopyValue());
+ }
+
+ // Take ownership of the value.
+ auto value = base::WrapUnique(Detach(new_controller));
+ DCHECK(value.get());
+ return value;
+}
+
+bool CefBinaryValueImpl::IsSameValue(const base::Value* that) {
+ CEF_VALUE_VERIFY_RETURN(false, false);
+ return (&const_value() == that);
+}
+
+bool CefBinaryValueImpl::IsEqualValue(const base::Value* that) {
+ CEF_VALUE_VERIFY_RETURN(false, false);
+ return const_value() == *that;
+}
+
+base::Value* CefBinaryValueImpl::GetValueUnsafe() const {
+ if (!VerifyAttached()) {
+ return nullptr;
+ }
+ controller()->AssertLockAcquired();
+ return mutable_value_unchecked();
+}
+
+bool CefBinaryValueImpl::IsValid() {
+ return !detached();
+}
+
+bool CefBinaryValueImpl::IsOwned() {
+ return !will_delete();
+}
+
+bool CefBinaryValueImpl::IsSame(CefRefPtr<CefBinaryValue> that) {
+ if (!that.get()) {
+ return false;
+ }
+ if (that.get() == this) {
+ return true;
+ }
+
+ CEF_VALUE_VERIFY_RETURN(false, false);
+ return static_cast<CefBinaryValueImpl*>(that.get())
+ ->IsSameValue(&const_value());
+}
+
+bool CefBinaryValueImpl::IsEqual(CefRefPtr<CefBinaryValue> that) {
+ if (!that.get()) {
+ return false;
+ }
+ if (that.get() == this) {
+ return true;
+ }
+
+ CEF_VALUE_VERIFY_RETURN(false, false);
+ return static_cast<CefBinaryValueImpl*>(that.get())
+ ->IsEqualValue(&const_value());
+}
+
+CefRefPtr<CefBinaryValue> CefBinaryValueImpl::Copy() {
+ CEF_VALUE_VERIFY_RETURN(false, nullptr);
+ return new CefBinaryValueImpl(const_value().Clone());
+}
+
+size_t CefBinaryValueImpl::GetSize() {
+ CEF_VALUE_VERIFY_RETURN(false, 0);
+ return const_value().GetBlob().size();
+}
+
+size_t CefBinaryValueImpl::GetData(void* buffer,
+ size_t buffer_size,
+ size_t data_offset) {
+ DCHECK(buffer);
+ DCHECK_GT(buffer_size, (size_t)0);
+ if (!buffer || buffer_size == 0) {
+ return 0;
+ }
+
+ CEF_VALUE_VERIFY_RETURN(false, 0);
+
+ size_t size = const_value().GetBlob().size();
+ DCHECK_LT(data_offset, size);
+ if (data_offset >= size) {
+ return 0;
+ }
+
+ size = std::min(buffer_size, size - data_offset);
+ auto* data = const_value().GetBlob().data();
+ memcpy(buffer, data + data_offset, size);
+ return size;
+}
+
+CefBinaryValueImpl::CefBinaryValueImpl(base::Value* value,
+ void* parent_value,
+ ValueMode value_mode,
+ CefValueController* controller)
+ : CefValueBase<CefBinaryValue, base::Value>(value,
+ parent_value,
+ value_mode,
+ /*read_only=*/true,
+ controller) {}
+
+// CefDictionaryValueImpl implementation.
+
+// static
+CefRefPtr<CefDictionaryValue> CefDictionaryValue::Create() {
+ return new CefDictionaryValueImpl(base::Value(base::Value::Type::DICT),
+ /*read_only=*/false);
+}
+
+// static
+CefRefPtr<CefDictionaryValue> CefDictionaryValueImpl::GetOrCreateRef(
+ base::Value* value,
+ void* parent_value,
+ bool read_only,
+ CefValueController* controller) {
+ CefValueController::Object* object = controller->Get(value);
+ if (object) {
+ return static_cast<CefDictionaryValueImpl*>(object);
+ }
+
+ return new CefDictionaryValueImpl(value, parent_value,
+ CefDictionaryValueImpl::kReference,
+ read_only, controller);
+}
+
+CefDictionaryValueImpl::CefDictionaryValueImpl(base::Value value,
+ bool read_only)
+ : CefDictionaryValueImpl(new base::Value(std::move(value)),
+ /*will_delete=*/true,
+ read_only) {}
+
+CefDictionaryValueImpl::CefDictionaryValueImpl(base::Value::Dict value,
+ bool read_only)
+ : CefDictionaryValueImpl(base::Value(std::move(value)), read_only) {}
+
+CefDictionaryValueImpl::CefDictionaryValueImpl(base::Value* value,
+ bool will_delete,
+ bool read_only)
+ : CefDictionaryValueImpl(value,
+ nullptr,
+ will_delete ? kOwnerWillDelete : kOwnerNoDelete,
+ read_only,
+ nullptr) {}
+
+base::Value CefDictionaryValueImpl::CopyValue() {
+ CEF_VALUE_VERIFY_RETURN(false, base::Value());
+ return const_value().Clone();
+}
+
+std::unique_ptr<base::Value> CefDictionaryValueImpl::CopyOrDetachValue(
+ CefValueController* new_controller) {
+ if (!will_delete()) {
+ // Copy the value.
+ return std::make_unique<base::Value>(CopyValue());
+ }
+
+ // Take ownership of the value.
+ auto value = base::WrapUnique(Detach(new_controller));
+ DCHECK(value.get());
+ return value;
+}
+
+bool CefDictionaryValueImpl::IsSameValue(const base::Value* that) {
+ CEF_VALUE_VERIFY_RETURN(false, false);
+ return (&const_value() == that);
+}
+
+bool CefDictionaryValueImpl::IsEqualValue(const base::Value* that) {
+ CEF_VALUE_VERIFY_RETURN(false, false);
+ return const_value() == *that;
+}
+
+base::Value* CefDictionaryValueImpl::GetValueUnsafe() const {
+ if (!VerifyAttached()) {
+ return nullptr;
+ }
+ controller()->AssertLockAcquired();
+ return mutable_value_unchecked();
+}
+
+bool CefDictionaryValueImpl::IsValid() {
+ return !detached();
+}
+
+bool CefDictionaryValueImpl::IsOwned() {
+ return !will_delete();
+}
+
+bool CefDictionaryValueImpl::IsReadOnly() {
+ return read_only();
+}
+
+bool CefDictionaryValueImpl::IsSame(CefRefPtr<CefDictionaryValue> that) {
+ if (!that.get()) {
+ return false;
+ }
+ if (that.get() == this) {
+ return true;
+ }
+
+ CEF_VALUE_VERIFY_RETURN(false, false);
+ return static_cast<CefDictionaryValueImpl*>(that.get())
+ ->IsSameValue(&const_value());
+}
+
+bool CefDictionaryValueImpl::IsEqual(CefRefPtr<CefDictionaryValue> that) {
+ if (!that.get()) {
+ return false;
+ }
+ if (that.get() == this) {
+ return true;
+ }
+
+ CEF_VALUE_VERIFY_RETURN(false, false);
+ return static_cast<CefDictionaryValueImpl*>(that.get())
+ ->IsEqualValue(&const_value());
+}
+
+CefRefPtr<CefDictionaryValue> CefDictionaryValueImpl::Copy(
+ bool exclude_empty_children) {
+ CEF_VALUE_VERIFY_RETURN(false, nullptr);
+
+ auto value = const_value().Clone();
+ if (exclude_empty_children) {
+ RemoveEmptyValueDicts(value.GetDict());
+ }
+
+ return new CefDictionaryValueImpl(std::move(value), /*read_only=*/false);
+}
+
+size_t CefDictionaryValueImpl::GetSize() {
+ CEF_VALUE_VERIFY_RETURN(false, 0);
+ return const_value().GetDict().size();
+}
+
+bool CefDictionaryValueImpl::Clear() {
+ CEF_VALUE_VERIFY_RETURN(true, false);
+
+ // Detach any dependent values.
+ controller()->RemoveDependencies(mutable_value());
+
+ mutable_value()->GetDict().clear();
+ return true;
+}
+
+bool CefDictionaryValueImpl::HasKey(const CefString& key) {
+ CEF_VALUE_VERIFY_RETURN(false, 0);
+ return const_value().GetDict().contains(base::StringPiece(key));
+}
+
+bool CefDictionaryValueImpl::GetKeys(KeyList& keys) {
+ CEF_VALUE_VERIFY_RETURN(false, 0);
+
+ for (const auto item : const_value().GetDict()) {
+ keys.push_back(item.first);
+ }
+
+ return true;
+}
+
+bool CefDictionaryValueImpl::Remove(const CefString& key) {
+ CEF_VALUE_VERIFY_RETURN(true, false);
+ return RemoveInternal(key);
+}
+
+CefValueType CefDictionaryValueImpl::GetType(const CefString& key) {
+ CEF_VALUE_VERIFY_RETURN(false, VTYPE_INVALID);
+
+ const base::Value* value =
+ const_value().GetDict().Find(base::StringPiece(key));
+ if (value) {
+ switch (value->type()) {
+ case base::Value::Type::NONE:
+ return VTYPE_NULL;
+ case base::Value::Type::BOOLEAN:
+ return VTYPE_BOOL;
+ case base::Value::Type::INTEGER:
+ return VTYPE_INT;
+ case base::Value::Type::DOUBLE:
+ return VTYPE_DOUBLE;
+ case base::Value::Type::STRING:
+ return VTYPE_STRING;
+ case base::Value::Type::BINARY:
+ return VTYPE_BINARY;
+ case base::Value::Type::DICTIONARY:
+ return VTYPE_DICTIONARY;
+ case base::Value::Type::LIST:
+ return VTYPE_LIST;
+ }
+ }
+
+ return VTYPE_INVALID;
+}
+
+CefRefPtr<CefValue> CefDictionaryValueImpl::GetValue(const CefString& key) {
+ CEF_VALUE_VERIFY_RETURN(false, nullptr);
+
+ const base::Value* value =
+ const_value().GetDict().Find(base::StringPiece(key));
+ if (value) {
+ return CefValueImpl::GetOrCreateRefOrCopy(const_cast<base::Value*>(value),
+ mutable_value_unchecked(),
+ read_only(), controller());
+ }
+
+ return nullptr;
+}
+
+bool CefDictionaryValueImpl::GetBool(const CefString& key) {
+ CEF_VALUE_VERIFY_RETURN(false, false);
+
+ bool ret_value = false;
+
+ const base::Value* value =
+ const_value().GetDict().Find(base::StringPiece(key));
+ if (value && value->is_bool()) {
+ ret_value = value->GetBool();
+ }
+
+ return ret_value;
+}
+
+int CefDictionaryValueImpl::GetInt(const CefString& key) {
+ CEF_VALUE_VERIFY_RETURN(false, 0);
+
+ int ret_value = 0;
+
+ const base::Value* value =
+ const_value().GetDict().Find(base::StringPiece(key));
+ if (value && value->is_int()) {
+ ret_value = value->GetInt();
+ }
+
+ return ret_value;
+}
+
+double CefDictionaryValueImpl::GetDouble(const CefString& key) {
+ CEF_VALUE_VERIFY_RETURN(false, 0);
+
+ double ret_value = 0;
+
+ const base::Value* value =
+ const_value().GetDict().Find(base::StringPiece(key));
+ if (value && value->is_double()) {
+ ret_value = value->GetDouble();
+ }
+
+ return ret_value;
+}
+
+CefString CefDictionaryValueImpl::GetString(const CefString& key) {
+ CEF_VALUE_VERIFY_RETURN(false, CefString());
+
+ std::string ret_value;
+
+ const base::Value* value =
+ const_value().GetDict().Find(base::StringPiece(key));
+ if (value && value->is_string()) {
+ ret_value = value->GetString();
+ }
+
+ return ret_value;
+}
+
+CefRefPtr<CefBinaryValue> CefDictionaryValueImpl::GetBinary(
+ const CefString& key) {
+ CEF_VALUE_VERIFY_RETURN(false, nullptr);
+
+ const base::Value* value =
+ const_value().GetDict().Find(base::StringPiece(key));
+ if (value && value->is_blob()) {
+ base::Value* binary_value = const_cast<base::Value*>(value);
+ return CefBinaryValueImpl::GetOrCreateRef(
+ binary_value, mutable_value_unchecked(), controller());
+ }
+
+ return nullptr;
+}
+
+CefRefPtr<CefDictionaryValue> CefDictionaryValueImpl::GetDictionary(
+ const CefString& key) {
+ CEF_VALUE_VERIFY_RETURN(false, nullptr);
+
+ const base::Value* value =
+ const_value().GetDict().Find(base::StringPiece(key));
+ if (value && value->is_dict()) {
+ base::Value* dict_value = const_cast<base::Value*>(value);
+ return CefDictionaryValueImpl::GetOrCreateRef(
+ dict_value, mutable_value_unchecked(), read_only(), controller());
+ }
+
+ return nullptr;
+}
+
+CefRefPtr<CefListValue> CefDictionaryValueImpl::GetList(const CefString& key) {
+ CEF_VALUE_VERIFY_RETURN(false, nullptr);
+
+ const base::Value* value =
+ const_value().GetDict().Find(base::StringPiece(key));
+ if (value && value->is_list()) {
+ base::Value* list_value = const_cast<base::Value*>(value);
+ return CefListValueImpl::GetOrCreateRef(
+ list_value, mutable_value_unchecked(), read_only(), controller());
+ }
+
+ return nullptr;
+}
+
+bool CefDictionaryValueImpl::SetValue(const CefString& key,
+ CefRefPtr<CefValue> value) {
+ CEF_VALUE_VERIFY_RETURN(true, false);
+
+ CefValueImpl* impl = static_cast<CefValueImpl*>(value.get());
+ DCHECK(impl);
+
+ base::Value* actual_value =
+ SetInternal(key, impl->CopyOrDetachValue(controller()));
+ impl->SwapValue(actual_value, mutable_value(), controller());
+ return true;
+}
+
+bool CefDictionaryValueImpl::SetNull(const CefString& key) {
+ CEF_VALUE_VERIFY_RETURN(true, false);
+ SetInternal(key, std::make_unique<base::Value>());
+ return true;
+}
+
+bool CefDictionaryValueImpl::SetBool(const CefString& key, bool value) {
+ CEF_VALUE_VERIFY_RETURN(true, false);
+ SetInternal(key, std::make_unique<base::Value>(value));
+ return true;
+}
+
+bool CefDictionaryValueImpl::SetInt(const CefString& key, int value) {
+ CEF_VALUE_VERIFY_RETURN(true, false);
+ SetInternal(key, std::make_unique<base::Value>(value));
+ return true;
+}
+
+bool CefDictionaryValueImpl::SetDouble(const CefString& key, double value) {
+ CEF_VALUE_VERIFY_RETURN(true, false);
+ SetInternal(key, std::make_unique<base::Value>(value));
+ return true;
+}
+
+bool CefDictionaryValueImpl::SetString(const CefString& key,
+ const CefString& value) {
+ CEF_VALUE_VERIFY_RETURN(true, false);
+ SetInternal(key, std::make_unique<base::Value>(value.ToString()));
+ return true;
+}
+
+bool CefDictionaryValueImpl::SetBinary(const CefString& key,
+ CefRefPtr<CefBinaryValue> value) {
+ CEF_VALUE_VERIFY_RETURN(true, false);
+
+ CefBinaryValueImpl* impl = static_cast<CefBinaryValueImpl*>(value.get());
+ DCHECK(impl);
+
+ SetInternal(key, impl->CopyOrDetachValue(controller()));
+ return true;
+}
+
+bool CefDictionaryValueImpl::SetDictionary(
+ const CefString& key,
+ CefRefPtr<CefDictionaryValue> value) {
+ CEF_VALUE_VERIFY_RETURN(true, false);
+
+ CefDictionaryValueImpl* impl =
+ static_cast<CefDictionaryValueImpl*>(value.get());
+ DCHECK(impl);
+
+ SetInternal(key, impl->CopyOrDetachValue(controller()));
+ return true;
+}
+
+bool CefDictionaryValueImpl::SetList(const CefString& key,
+ CefRefPtr<CefListValue> value) {
+ CEF_VALUE_VERIFY_RETURN(true, false);
+
+ CefListValueImpl* impl = static_cast<CefListValueImpl*>(value.get());
+ DCHECK(impl);
+
+ SetInternal(key, impl->CopyOrDetachValue(controller()));
+ return true;
+}
+
+bool CefDictionaryValueImpl::RemoveInternal(const CefString& key) {
+ // The ExtractKey() call below which removes the Value from the dictionary
+ // will return a new Value object with the moved contents of the Value that
+ // exists in the implementation std::map. Consequently we use FindKey() to
+ // retrieve the actual Value pointer as it current exists first, for later
+ // comparison purposes.
+ const base::Value* actual_value =
+ const_value().GetDict().Find(base::StringPiece(key));
+ if (!actual_value) {
+ return false;
+ }
+
+ // |actual_value| is no longer valid after this call.
+ absl::optional<base::Value> out_value =
+ mutable_value()->GetDict().Extract(base::StringPiece(key));
+ if (!out_value.has_value()) {
+ return false;
+ }
+
+ // Remove the value.
+ controller()->Remove(const_cast<base::Value*>(actual_value), true);
+
+ // Only list and dictionary types may have dependencies.
+ if (out_value->is_list() || out_value->is_dict()) {
+ controller()->RemoveDependencies(const_cast<base::Value*>(actual_value));
+ }
+
+ return true;
+}
+
+base::Value* CefDictionaryValueImpl::SetInternal(
+ const CefString& key,
+ std::unique_ptr<base::Value> value) {
+ DCHECK(value);
+
+ RemoveInternal(key);
+
+ // base::Value now uses move semantics which means that Set() will move the
+ // contents of the passed-in base::Value instead of keeping the same object.
+ // Set() then returns the actual Value pointer as it currently exists.
+ base::Value* actual_value =
+ mutable_value()->GetDict().Set(base::StringPiece(key), std::move(*value));
+ CHECK(actual_value);
+
+ // |value| will be deleted when this method returns. Update the controller to
+ // reference |actual_value| instead.
+ controller()->Swap(value.get(), actual_value);
+
+ return actual_value;
+}
+
+CefDictionaryValueImpl::CefDictionaryValueImpl(base::Value* value,
+ void* parent_value,
+ ValueMode value_mode,
+ bool read_only,
+ CefValueController* controller)
+ : CefValueBase<CefDictionaryValue, base::Value>(value,
+ parent_value,
+ value_mode,
+ read_only,
+ controller) {
+ DCHECK(value->is_dict());
+}
+
+// CefListValueImpl implementation.
+
+// static
+CefRefPtr<CefListValue> CefListValue::Create() {
+ return new CefListValueImpl(base::Value(base::Value::Type::LIST),
+ /*read_only=*/false);
+}
+
+// static
+CefRefPtr<CefListValue> CefListValueImpl::GetOrCreateRef(
+ base::Value* value,
+ void* parent_value,
+ bool read_only,
+ CefValueController* controller) {
+ CefValueController::Object* object = controller->Get(value);
+ if (object) {
+ return static_cast<CefListValueImpl*>(object);
+ }
+
+ return new CefListValueImpl(value, parent_value, CefListValueImpl::kReference,
+ read_only, controller);
+}
+
+CefListValueImpl::CefListValueImpl(base::Value value, bool read_only)
+ : CefListValueImpl(new base::Value(std::move(value)),
+ /*will_delete=*/true,
+ read_only) {}
+
+CefListValueImpl::CefListValueImpl(base::Value::List value, bool read_only)
+ : CefListValueImpl(base::Value(std::move(value)), read_only) {}
+
+CefListValueImpl::CefListValueImpl(base::Value* value,
+ bool will_delete,
+ bool read_only)
+ : CefListValueImpl(value,
+ nullptr,
+ will_delete ? kOwnerWillDelete : kOwnerNoDelete,
+ read_only,
+ nullptr) {}
+
+base::Value CefListValueImpl::CopyValue() {
+ CEF_VALUE_VERIFY_RETURN(false, base::Value());
+ return const_value().Clone();
+}
+
+std::unique_ptr<base::Value> CefListValueImpl::CopyOrDetachValue(
+ CefValueController* new_controller) {
+ if (!will_delete()) {
+ // Copy the value.
+ return std::make_unique<base::Value>(CopyValue());
+ }
+
+ // Take ownership of the value.
+ auto value = base::WrapUnique(Detach(new_controller));
+ DCHECK(value.get());
+ return value;
+}
+
+bool CefListValueImpl::IsSameValue(const base::Value* that) {
+ CEF_VALUE_VERIFY_RETURN(false, false);
+ return (&const_value() == that);
+}
+
+bool CefListValueImpl::IsEqualValue(const base::Value* that) {
+ CEF_VALUE_VERIFY_RETURN(false, false);
+ return const_value() == *that;
+}
+
+base::Value* CefListValueImpl::GetValueUnsafe() const {
+ if (!VerifyAttached()) {
+ return nullptr;
+ }
+ controller()->AssertLockAcquired();
+ return mutable_value_unchecked();
+}
+
+bool CefListValueImpl::IsValid() {
+ return !detached();
+}
+
+bool CefListValueImpl::IsOwned() {
+ return !will_delete();
+}
+
+bool CefListValueImpl::IsReadOnly() {
+ return read_only();
+}
+
+bool CefListValueImpl::IsSame(CefRefPtr<CefListValue> that) {
+ if (!that.get()) {
+ return false;
+ }
+ if (that.get() == this) {
+ return true;
+ }
+
+ CEF_VALUE_VERIFY_RETURN(false, false);
+ return static_cast<CefListValueImpl*>(that.get())
+ ->IsSameValue(&const_value());
+}
+
+bool CefListValueImpl::IsEqual(CefRefPtr<CefListValue> that) {
+ if (!that.get()) {
+ return false;
+ }
+ if (that.get() == this) {
+ return true;
+ }
+
+ CEF_VALUE_VERIFY_RETURN(false, false);
+ return static_cast<CefListValueImpl*>(that.get())
+ ->IsEqualValue(&const_value());
+}
+
+CefRefPtr<CefListValue> CefListValueImpl::Copy() {
+ CEF_VALUE_VERIFY_RETURN(false, nullptr);
+
+ return new CefListValueImpl(const_value().Clone(), /*read_only=*/false);
+}
+
+bool CefListValueImpl::SetSize(size_t size) {
+ CEF_VALUE_VERIFY_RETURN(true, false);
+
+ size_t current_size = const_value().GetList().size();
+ if (size < current_size) {
+ // Clean up any values above the requested size.
+ for (size_t i = current_size - 1; i >= size; --i) {
+ RemoveInternal(i);
+ }
+ } else if (size > 0) {
+ // Expand the list size.
+ // TODO: This approach seems inefficient. See https://crbug.com/1187066#c17
+ // for background.
+ auto& list = mutable_value()->GetList();
+ while (list.size() < size) {
+ list.Append(base::Value());
+ }
+ }
+ return true;
+}
+
+size_t CefListValueImpl::GetSize() {
+ CEF_VALUE_VERIFY_RETURN(false, 0);
+ return const_value().GetList().size();
+}
+
+bool CefListValueImpl::Clear() {
+ CEF_VALUE_VERIFY_RETURN(true, false);
+
+ // Detach any dependent values.
+ controller()->RemoveDependencies(mutable_value());
+
+ mutable_value()->GetList().clear();
+ return true;
+}
+
+bool CefListValueImpl::Remove(size_t index) {
+ CEF_VALUE_VERIFY_RETURN(true, false);
+ return RemoveInternal(index);
+}
+
+CefValueType CefListValueImpl::GetType(size_t index) {
+ CEF_VALUE_VERIFY_RETURN(false, VTYPE_INVALID);
+
+ const auto& list = const_value().GetList();
+ if (index < list.size()) {
+ const base::Value& value = list[index];
+ switch (value.type()) {
+ case base::Value::Type::NONE:
+ return VTYPE_NULL;
+ case base::Value::Type::BOOLEAN:
+ return VTYPE_BOOL;
+ case base::Value::Type::INTEGER:
+ return VTYPE_INT;
+ case base::Value::Type::DOUBLE:
+ return VTYPE_DOUBLE;
+ case base::Value::Type::STRING:
+ return VTYPE_STRING;
+ case base::Value::Type::BINARY:
+ return VTYPE_BINARY;
+ case base::Value::Type::DICTIONARY:
+ return VTYPE_DICTIONARY;
+ case base::Value::Type::LIST:
+ return VTYPE_LIST;
+ }
+ }
+
+ return VTYPE_INVALID;
+}
+
+CefRefPtr<CefValue> CefListValueImpl::GetValue(size_t index) {
+ CEF_VALUE_VERIFY_RETURN(false, nullptr);
+
+ const auto& list = const_value().GetList();
+ if (index < list.size()) {
+ const base::Value& value = list[index];
+ return CefValueImpl::GetOrCreateRefOrCopy(const_cast<base::Value*>(&value),
+ mutable_value_unchecked(),
+ read_only(), controller());
+ }
+
+ return nullptr;
+}
+
+bool CefListValueImpl::GetBool(size_t index) {
+ CEF_VALUE_VERIFY_RETURN(false, false);
+
+ bool ret_value = false;
+ const auto& list = const_value().GetList();
+ if (index < list.size()) {
+ const base::Value& value = list[index];
+ if (value.is_bool()) {
+ ret_value = value.GetBool();
+ }
+ }
+
+ return ret_value;
+}
+
+int CefListValueImpl::GetInt(size_t index) {
+ CEF_VALUE_VERIFY_RETURN(false, 0);
+
+ int ret_value = 0;
+ const auto& list = const_value().GetList();
+ if (index < list.size()) {
+ const base::Value& value = list[index];
+ if (value.is_int()) {
+ ret_value = value.GetInt();
+ }
+ }
+
+ return ret_value;
+}
+
+double CefListValueImpl::GetDouble(size_t index) {
+ CEF_VALUE_VERIFY_RETURN(false, 0);
+
+ double ret_value = 0;
+ const auto& list = const_value().GetList();
+ if (index < list.size()) {
+ const base::Value& value = list[index];
+ if (value.is_double()) {
+ ret_value = value.GetDouble();
+ }
+ }
+
+ return ret_value;
+}
+
+CefString CefListValueImpl::GetString(size_t index) {
+ CEF_VALUE_VERIFY_RETURN(false, CefString());
+
+ std::string ret_value;
+ const auto& list = const_value().GetList();
+ if (index < list.size()) {
+ const base::Value& value = list[index];
+ if (value.is_string()) {
+ ret_value = value.GetString();
+ }
+ }
+
+ return ret_value;
+}
+
+CefRefPtr<CefBinaryValue> CefListValueImpl::GetBinary(size_t index) {
+ CEF_VALUE_VERIFY_RETURN(false, nullptr);
+
+ const auto& list = const_value().GetList();
+ if (index < list.size()) {
+ base::Value& value = const_cast<base::Value&>(list[index]);
+ if (value.is_blob()) {
+ return CefBinaryValueImpl::GetOrCreateRef(
+ &value, mutable_value_unchecked(), controller());
+ }
+ }
+
+ return nullptr;
+}
+
+CefRefPtr<CefDictionaryValue> CefListValueImpl::GetDictionary(size_t index) {
+ CEF_VALUE_VERIFY_RETURN(false, nullptr);
+
+ const auto& list = const_value().GetList();
+ if (index < list.size()) {
+ base::Value& value = const_cast<base::Value&>(list[index]);
+ if (value.is_dict()) {
+ return CefDictionaryValueImpl::GetOrCreateRef(
+ &value, mutable_value_unchecked(), read_only(), controller());
+ }
+ }
+
+ return nullptr;
+}
+
+CefRefPtr<CefListValue> CefListValueImpl::GetList(size_t index) {
+ CEF_VALUE_VERIFY_RETURN(false, nullptr);
+
+ const auto& list = const_value().GetList();
+ if (index < list.size()) {
+ base::Value& value = const_cast<base::Value&>(list[index]);
+ if (value.is_list()) {
+ return CefListValueImpl::GetOrCreateRef(&value, mutable_value_unchecked(),
+ read_only(), controller());
+ }
+ }
+
+ return nullptr;
+}
+
+bool CefListValueImpl::SetValue(size_t index, CefRefPtr<CefValue> value) {
+ CEF_VALUE_VERIFY_RETURN(true, false);
+
+ CefValueImpl* impl = static_cast<CefValueImpl*>(value.get());
+ DCHECK(impl);
+
+ base::Value* actual_value =
+ SetInternal(index, impl->CopyOrDetachValue(controller()));
+ impl->SwapValue(actual_value, mutable_value(), controller());
+ return true;
+}
+
+bool CefListValueImpl::SetNull(size_t index) {
+ CEF_VALUE_VERIFY_RETURN(true, false);
+ SetInternal(index, std::make_unique<base::Value>());
+ return true;
+}
+
+bool CefListValueImpl::SetBool(size_t index, bool value) {
+ CEF_VALUE_VERIFY_RETURN(true, false);
+ SetInternal(index, std::make_unique<base::Value>(value));
+ return true;
+}
+
+bool CefListValueImpl::SetInt(size_t index, int value) {
+ CEF_VALUE_VERIFY_RETURN(true, false);
+ SetInternal(index, std::make_unique<base::Value>(value));
+ return true;
+}
+
+bool CefListValueImpl::SetDouble(size_t index, double value) {
+ CEF_VALUE_VERIFY_RETURN(true, false);
+ SetInternal(index, std::make_unique<base::Value>(value));
+ return true;
+}
+
+bool CefListValueImpl::SetString(size_t index, const CefString& value) {
+ CEF_VALUE_VERIFY_RETURN(true, false);
+ SetInternal(index, std::make_unique<base::Value>(value.ToString()));
+ return true;
+}
+
+bool CefListValueImpl::SetBinary(size_t index,
+ CefRefPtr<CefBinaryValue> value) {
+ CEF_VALUE_VERIFY_RETURN(true, false);
+
+ CefBinaryValueImpl* impl = static_cast<CefBinaryValueImpl*>(value.get());
+ DCHECK(impl);
+
+ SetInternal(index, impl->CopyOrDetachValue(controller()));
+ return true;
+}
+
+bool CefListValueImpl::SetDictionary(size_t index,
+ CefRefPtr<CefDictionaryValue> value) {
+ CEF_VALUE_VERIFY_RETURN(true, false);
+
+ CefDictionaryValueImpl* impl =
+ static_cast<CefDictionaryValueImpl*>(value.get());
+ DCHECK(impl);
+
+ SetInternal(index, impl->CopyOrDetachValue(controller()));
+ return true;
+}
+
+bool CefListValueImpl::SetList(size_t index, CefRefPtr<CefListValue> value) {
+ CEF_VALUE_VERIFY_RETURN(true, false);
+
+ CefListValueImpl* impl = static_cast<CefListValueImpl*>(value.get());
+ DCHECK(impl);
+
+ SetInternal(index, impl->CopyOrDetachValue(controller()));
+ return true;
+}
+
+bool CefListValueImpl::RemoveInternal(size_t index) {
+ auto& list = mutable_value()->GetList();
+ if (index >= list.size()) {
+ return false;
+ }
+
+ // The std::move() call below which removes the Value from the list will
+ // return a new Value object with the moved contents of the Value that exists
+ // in the implementation std::vector. Consequently we use operator[] to
+ // retrieve the actual Value pointer as it current exists first, for later
+ // comparison purposes.
+ const base::Value& actual_value = list[index];
+
+ // |actual_value| is no longer valid after this call.
+ auto out_value = std::move(list[index]);
+ list.erase(list.begin() + index);
+
+ // Remove the value.
+ controller()->Remove(const_cast<base::Value*>(&actual_value), true);
+
+ // Only list and dictionary types may have dependencies.
+ if (out_value.is_list() || out_value.is_dict()) {
+ controller()->RemoveDependencies(const_cast<base::Value*>(&actual_value));
+ }
+
+ return true;
+}
+
+base::Value* CefListValueImpl::SetInternal(size_t index,
+ std::unique_ptr<base::Value> value) {
+ DCHECK(value);
+
+ auto& list = mutable_value()->GetList();
+ if (RemoveInternal(index)) {
+ CHECK_LE(index, list.size());
+ list.Insert(list.begin() + index, std::move(*value));
+ } else {
+ if (index >= list.size()) {
+ // Expand the list size.
+ // TODO: This approach seems inefficient. See
+ // https://crbug.com/1187066#c17 for background.
+ while (list.size() <= index) {
+ list.Append(base::Value());
+ }
+ }
+ list[index] = std::move(*value);
+ }
+
+ // base::Value now uses move semantics which means that Insert()/Set() will
+ // move the contents of the passed-in base::Value instead of keeping the same
+ // object. Consequently we use operator[] to retrieve the actual base::Value
+ // pointer as it exists in the std::vector.
+ const base::Value& actual_value = list[index];
+
+ // |value| will be deleted when this method returns. Update the controller to
+ // reference |actual_value| instead.
+ controller()->Swap(value.get(), const_cast<base::Value*>(&actual_value));
+
+ return const_cast<base::Value*>(&actual_value);
+}
+
+CefListValueImpl::CefListValueImpl(base::Value* value,
+ void* parent_value,
+ ValueMode value_mode,
+ bool read_only,
+ CefValueController* controller)
+ : CefValueBase<CefListValue, base::Value>(value,
+ parent_value,
+ value_mode,
+ read_only,
+ controller) {
+ DCHECK(value->is_list());
+}
diff --git a/libcef/common/values_impl.h b/libcef/common/values_impl.h
new file mode 100644
index 00000000..db43299a
--- /dev/null
+++ b/libcef/common/values_impl.h
@@ -0,0 +1,363 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_COMMON_VALUES_IMPL_H_
+#define CEF_LIBCEF_COMMON_VALUES_IMPL_H_
+#pragma once
+
+#include <memory>
+#include <vector>
+
+#include "include/cef_values.h"
+#include "libcef/common/value_base.h"
+
+#include "base/threading/platform_thread.h"
+#include "base/values.h"
+
+// CefValue implementation
+class CefValueImpl : public CefValue {
+ public:
+ // Get or create a reference to a complex value or copy a simple value.
+ static CefRefPtr<CefValue> GetOrCreateRefOrCopy(
+ base::Value* value,
+ void* parent_value,
+ bool read_only,
+ CefValueController* controller);
+
+ CefValueImpl();
+
+ // Take ownership of |value|. Do not pass in a value owned by something else
+ // (use GetOrCreateRefOrCopy instead).
+ explicit CefValueImpl(base::Value value);
+
+ // Keep a reference to |value|.
+ explicit CefValueImpl(CefRefPtr<CefBinaryValue> value);
+ explicit CefValueImpl(CefRefPtr<CefDictionaryValue> value);
+ explicit CefValueImpl(CefRefPtr<CefListValue> value);
+
+ CefValueImpl(const CefValueImpl&) = delete;
+ CefValueImpl& operator=(const CefValueImpl&) = delete;
+
+ ~CefValueImpl() override;
+
+ // Take ownership of |value|. Do not pass in a value owned by something else
+ // (use GetOrCreateRefOrCopy or Set*() instead).
+ void SetValue(base::Value value);
+
+ // Return a copy of the value.
+ [[nodiscard]] base::Value CopyValue();
+
+ // Copy a simple value or transfer ownership of a complex value. If ownership
+ // of the value is tranferred then this object's internal reference to the
+ // value will be updated and remain valid. base::Value now uses move semantics
+ // so we need to perform the copy and swap in two steps.
+ [[nodiscard]] std::unique_ptr<base::Value> CopyOrDetachValue(
+ CefValueController* new_controller);
+ void SwapValue(base::Value* new_value,
+ void* new_parent_value,
+ CefValueController* new_controller);
+
+ // Returns a reference to the underlying data. Access must be protected by
+ // calling AcquireLock/ReleaseLock (e.g. use ScopedLockedValue).
+ base::Value* GetValueUnsafe() const;
+
+ // CefValue methods.
+ bool IsValid() override;
+ bool IsOwned() override;
+ bool IsReadOnly() override;
+ bool IsSame(CefRefPtr<CefValue> that) override;
+ bool IsEqual(CefRefPtr<CefValue> that) override;
+ CefRefPtr<CefValue> Copy() override;
+ CefValueType GetType() override;
+ bool GetBool() override;
+ int GetInt() override;
+ double GetDouble() override;
+ CefString GetString() override;
+ CefRefPtr<CefBinaryValue> GetBinary() override;
+ CefRefPtr<CefDictionaryValue> GetDictionary() override;
+ CefRefPtr<CefListValue> GetList() override;
+ bool SetNull() override;
+ bool SetBool(bool value) override;
+ bool SetInt(int value) override;
+ bool SetDouble(double value) override;
+ bool SetString(const CefString& value) override;
+ bool SetBinary(CefRefPtr<CefBinaryValue> value) override;
+ bool SetDictionary(CefRefPtr<CefDictionaryValue> value) override;
+ bool SetList(CefRefPtr<CefListValue> value) override;
+
+ // Ensures exclusive access to the underlying data for the life of this scoped
+ // object.
+ class ScopedLockedValue {
+ public:
+ explicit ScopedLockedValue(CefRefPtr<CefValueImpl> impl) : impl_(impl) {
+ impl_->AcquireLock();
+ }
+
+ ScopedLockedValue(const ScopedLockedValue&) = delete;
+ ScopedLockedValue& operator=(const ScopedLockedValue&) = delete;
+
+ ~ScopedLockedValue() { impl_->ReleaseLock(); }
+
+ base::Value* value() const { return impl_->GetValueUnsafe(); }
+
+ private:
+ CefRefPtr<CefValueImpl> impl_;
+ };
+
+ private:
+ void SetValueInternal(absl::optional<base::Value> value);
+
+ // Returns the controller for the current value, if any.
+ CefValueController* GetValueController() const;
+
+ // Explicitly lock/unlock this object and the underlying data.
+ void AcquireLock();
+ void ReleaseLock();
+
+ // Access to all members must be protected by |lock_|.
+ base::Lock lock_;
+
+ // Simple values only.
+ std::unique_ptr<base::Value> value_;
+
+ // Complex values.
+ CefRefPtr<CefBinaryValue> binary_value_;
+ CefRefPtr<CefDictionaryValue> dictionary_value_;
+ CefRefPtr<CefListValue> list_value_;
+
+ IMPLEMENT_REFCOUNTING(CefValueImpl);
+};
+
+// CefBinaryValue implementation
+class CefBinaryValueImpl : public CefValueBase<CefBinaryValue, base::Value> {
+ public:
+ // Get or create a reference value.
+ static CefRefPtr<CefBinaryValue> GetOrCreateRef(
+ base::Value* value,
+ void* parent_value,
+ CefValueController* controller);
+
+ // Take ownership of |value|. Do not pass in a value owned by something else
+ // (use GetOrCreateRef or constructor variant with |will_delete| argument).
+ explicit CefBinaryValueImpl(base::Value value);
+
+ // Reference an existing value (set |will_delete| to false) or take ownership
+ // of an existing value (set |will_delete| to true). When referencing an
+ // existing value you must explicitly call Detach(nullptr) when |value| is no
+ // longer valid. Use GetOrCreateRef instead of this constructor if |value| is
+ // owned by some other object and you do not plan to explicitly call
+ // Detach(nullptr).
+ CefBinaryValueImpl(base::Value* value, bool will_delete);
+
+ // The data will always be copied.
+ CefBinaryValueImpl(char* data, size_t data_size);
+
+ CefBinaryValueImpl(const CefBinaryValueImpl&) = delete;
+ CefBinaryValueImpl& operator=(const CefBinaryValueImpl&) = delete;
+
+ // Return a copy of the value.
+ [[nodiscard]] base::Value CopyValue();
+
+ // If this value is a reference then return a copy. Otherwise, detach and
+ // transfer ownership of the value.
+ [[nodiscard]] std::unique_ptr<base::Value> CopyOrDetachValue(
+ CefValueController* new_controller);
+
+ bool IsSameValue(const base::Value* that);
+ bool IsEqualValue(const base::Value* that);
+
+ // Returns the underlying value. Access must be protected by calling
+ // lock/unlock on the controller.
+ base::Value* GetValueUnsafe() const;
+
+ // CefBinaryValue methods.
+ bool IsValid() override;
+ bool IsOwned() override;
+ bool IsSame(CefRefPtr<CefBinaryValue> that) override;
+ bool IsEqual(CefRefPtr<CefBinaryValue> that) override;
+ CefRefPtr<CefBinaryValue> Copy() override;
+ size_t GetSize() override;
+ size_t GetData(void* buffer, size_t buffer_size, size_t data_offset) override;
+
+ private:
+ // See the CefValueBase constructor for usage. Binary values are always
+ // read-only.
+ CefBinaryValueImpl(base::Value* value,
+ void* parent_value,
+ ValueMode value_mode,
+ CefValueController* controller);
+};
+
+// CefDictionaryValue implementation
+class CefDictionaryValueImpl
+ : public CefValueBase<CefDictionaryValue, base::Value> {
+ public:
+ // Get or create a reference value.
+ static CefRefPtr<CefDictionaryValue> GetOrCreateRef(
+ base::Value* value,
+ void* parent_value,
+ bool read_only,
+ CefValueController* controller);
+
+ // Take ownership of |value|. Do not pass in a value owned by something else
+ // (use GetOrCreateRef or constructor variant with |will_delete| argument).
+ CefDictionaryValueImpl(base::Value value, bool read_only);
+ CefDictionaryValueImpl(base::Value::Dict value, bool read_only);
+
+ // Reference an existing value (set |will_delete| to false) or take ownership
+ // of an existing value (set |will_delete| to true). When referencing an
+ // existing value you must explicitly call Detach(nullptr) when |value| is no
+ // longer valid. Use GetOrCreateRef instead of this constructor if |value| is
+ // owned by some other object and you do not plan to explicitly call
+ // Detach(nullptr).
+ CefDictionaryValueImpl(base::Value* value, bool will_delete, bool read_only);
+
+ CefDictionaryValueImpl(const CefDictionaryValueImpl&) = delete;
+ CefDictionaryValueImpl& operator=(const CefDictionaryValueImpl&) = delete;
+
+ // Return a copy of the value.
+ [[nodiscard]] base::Value CopyValue();
+
+ // If this value is a reference then return a copy. Otherwise, detach and
+ // transfer ownership of the value.
+ [[nodiscard]] std::unique_ptr<base::Value> CopyOrDetachValue(
+ CefValueController* new_controller);
+
+ bool IsSameValue(const base::Value* that);
+ bool IsEqualValue(const base::Value* that);
+
+ // Returns the underlying value. Access must be protected by calling
+ // lock/unlock on the controller.
+ base::Value* GetValueUnsafe() const;
+
+ // CefDictionaryValue methods.
+ bool IsValid() override;
+ bool IsOwned() override;
+ bool IsReadOnly() override;
+ bool IsSame(CefRefPtr<CefDictionaryValue> that) override;
+ bool IsEqual(CefRefPtr<CefDictionaryValue> that) override;
+ CefRefPtr<CefDictionaryValue> Copy(bool exclude_empty_children) override;
+ size_t GetSize() override;
+ bool Clear() override;
+ bool HasKey(const CefString& key) override;
+ bool GetKeys(KeyList& keys) override;
+ bool Remove(const CefString& key) override;
+ CefValueType GetType(const CefString& key) override;
+ CefRefPtr<CefValue> GetValue(const CefString& key) override;
+ bool GetBool(const CefString& key) override;
+ int GetInt(const CefString& key) override;
+ double GetDouble(const CefString& key) override;
+ CefString GetString(const CefString& key) override;
+ CefRefPtr<CefBinaryValue> GetBinary(const CefString& key) override;
+ CefRefPtr<CefDictionaryValue> GetDictionary(const CefString& key) override;
+ CefRefPtr<CefListValue> GetList(const CefString& key) override;
+ bool SetValue(const CefString& key, CefRefPtr<CefValue> value) override;
+ bool SetNull(const CefString& key) override;
+ bool SetBool(const CefString& key, bool value) override;
+ bool SetInt(const CefString& key, int value) override;
+ bool SetDouble(const CefString& key, double value) override;
+ bool SetString(const CefString& key, const CefString& value) override;
+ bool SetBinary(const CefString& key,
+ CefRefPtr<CefBinaryValue> value) override;
+ bool SetDictionary(const CefString& key,
+ CefRefPtr<CefDictionaryValue> value) override;
+ bool SetList(const CefString& key, CefRefPtr<CefListValue> value) override;
+
+ private:
+ // See the CefValueBase constructor for usage.
+ CefDictionaryValueImpl(base::Value* value,
+ void* parent_value,
+ ValueMode value_mode,
+ bool read_only,
+ CefValueController* controller);
+
+ bool RemoveInternal(const CefString& key);
+ base::Value* SetInternal(const CefString& key,
+ std::unique_ptr<base::Value> value);
+};
+
+// CefListValue implementation
+class CefListValueImpl : public CefValueBase<CefListValue, base::Value> {
+ public:
+ // Get or create a reference value.
+ static CefRefPtr<CefListValue> GetOrCreateRef(base::Value* value,
+ void* parent_value,
+ bool read_only,
+ CefValueController* controller);
+
+ // Take ownership of |value|. Do not pass in a value owned by something else
+ // (use GetOrCreateRef or constructor variant with |will_delete| argument).
+ CefListValueImpl(base::Value value, bool read_only);
+ CefListValueImpl(base::Value::List value, bool read_only);
+
+ // Reference an existing value (set |will_delete| to false) or take ownership
+ // of an existing value (set |will_delete| to true). When referencing an
+ // existing value you must explicitly call Detach(nullptr) when |value| is no
+ // longer valid. Use GetOrCreateRef instead of this constructor if |value| is
+ // owned by some other object and you do not plan to explicitly call
+ // Detach(nullptr).
+ CefListValueImpl(base::Value* value, bool will_delete, bool read_only);
+
+ CefListValueImpl(const CefListValueImpl&) = delete;
+ CefListValueImpl& operator=(const CefListValueImpl&) = delete;
+
+ // Return a copy of the value.
+ [[nodiscard]] base::Value CopyValue();
+
+ // If this value is a reference then return a copy. Otherwise, detach and
+ // transfer ownership of the value.
+ [[nodiscard]] std::unique_ptr<base::Value> CopyOrDetachValue(
+ CefValueController* new_controller);
+
+ bool IsSameValue(const base::Value* that);
+ bool IsEqualValue(const base::Value* that);
+
+ // Returns the underlying value. Access must be protected by calling
+ // lock/unlock on the controller.
+ base::Value* GetValueUnsafe() const;
+
+ // CefListValue methods.
+ bool IsValid() override;
+ bool IsOwned() override;
+ bool IsReadOnly() override;
+ bool IsSame(CefRefPtr<CefListValue> that) override;
+ bool IsEqual(CefRefPtr<CefListValue> that) override;
+ CefRefPtr<CefListValue> Copy() override;
+ bool SetSize(size_t size) override;
+ size_t GetSize() override;
+ bool Clear() override;
+ bool Remove(size_t index) override;
+ CefValueType GetType(size_t index) override;
+ CefRefPtr<CefValue> GetValue(size_t index) override;
+ bool GetBool(size_t index) override;
+ int GetInt(size_t index) override;
+ double GetDouble(size_t index) override;
+ CefString GetString(size_t index) override;
+ CefRefPtr<CefBinaryValue> GetBinary(size_t index) override;
+ CefRefPtr<CefDictionaryValue> GetDictionary(size_t index) override;
+ CefRefPtr<CefListValue> GetList(size_t index) override;
+ bool SetValue(size_t index, CefRefPtr<CefValue> value) override;
+ bool SetNull(size_t index) override;
+ bool SetBool(size_t index, bool value) override;
+ bool SetInt(size_t index, int value) override;
+ bool SetDouble(size_t index, double value) override;
+ bool SetString(size_t index, const CefString& value) override;
+ bool SetBinary(size_t index, CefRefPtr<CefBinaryValue> value) override;
+ bool SetDictionary(size_t index,
+ CefRefPtr<CefDictionaryValue> value) override;
+ bool SetList(size_t index, CefRefPtr<CefListValue> value) override;
+
+ private:
+ // See the CefValueBase constructor for usage.
+ CefListValueImpl(base::Value* value,
+ void* parent_value,
+ ValueMode value_mode,
+ bool read_only,
+ CefValueController* controller);
+
+ bool RemoveInternal(size_t index);
+ base::Value* SetInternal(size_t index, std::unique_ptr<base::Value> value);
+};
+
+#endif // CEF_LIBCEF_COMMON_VALUES_IMPL_H_
diff --git a/libcef/common/waitable_event_impl.cc b/libcef/common/waitable_event_impl.cc
new file mode 100644
index 00000000..49f0ed0e
--- /dev/null
+++ b/libcef/common/waitable_event_impl.cc
@@ -0,0 +1,63 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#include "libcef/common/waitable_event_impl.h"
+
+#include "include/cef_task.h"
+
+#include "base/notreached.h"
+#include "base/time/time.h"
+
+namespace {
+
+bool AllowWait() {
+ if (CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO)) {
+ NOTREACHED() << "waiting is not allowed on the current thread";
+ return false;
+ }
+ return true;
+}
+
+} // namespace
+
+// static
+CefRefPtr<CefWaitableEvent> CefWaitableEvent::CreateWaitableEvent(
+ bool automatic_reset,
+ bool initially_signaled) {
+ return new CefWaitableEventImpl(automatic_reset, initially_signaled);
+}
+
+CefWaitableEventImpl::CefWaitableEventImpl(bool automatic_reset,
+ bool initially_signaled)
+ : event_(automatic_reset ? base::WaitableEvent::ResetPolicy::AUTOMATIC
+ : base::WaitableEvent::ResetPolicy::MANUAL,
+ initially_signaled
+ ? base::WaitableEvent::InitialState::SIGNALED
+ : base::WaitableEvent::InitialState::NOT_SIGNALED) {}
+
+void CefWaitableEventImpl::Reset() {
+ event_.Reset();
+}
+
+void CefWaitableEventImpl::Signal() {
+ event_.Signal();
+}
+
+bool CefWaitableEventImpl::IsSignaled() {
+ return event_.IsSignaled();
+}
+
+void CefWaitableEventImpl::Wait() {
+ if (!AllowWait()) {
+ return;
+ }
+ event_.Wait();
+}
+
+bool CefWaitableEventImpl::TimedWait(int64 max_ms) {
+ if (!AllowWait()) {
+ return false;
+ }
+ return event_.TimedWait(base::Milliseconds(max_ms));
+}
diff --git a/libcef/common/waitable_event_impl.h b/libcef/common/waitable_event_impl.h
new file mode 100644
index 00000000..ce6495e4
--- /dev/null
+++ b/libcef/common/waitable_event_impl.h
@@ -0,0 +1,33 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_COMMON_WAITABLE_EVENT_IMPL_H_
+#define CEF_LIBCEF_COMMON_WAITABLE_EVENT_IMPL_H_
+#pragma once
+
+#include "include/cef_waitable_event.h"
+
+#include "base/synchronization/waitable_event.h"
+
+class CefWaitableEventImpl : public CefWaitableEvent {
+ public:
+ CefWaitableEventImpl(bool automatic_reset, bool initially_signaled);
+
+ CefWaitableEventImpl(const CefWaitableEventImpl&) = delete;
+ CefWaitableEventImpl& operator=(const CefWaitableEventImpl&) = delete;
+
+ // CefWaitableEvent methods:
+ void Reset() override;
+ void Signal() override;
+ bool IsSignaled() override;
+ void Wait() override;
+ bool TimedWait(int64 max_ms) override;
+
+ private:
+ base::WaitableEvent event_;
+
+ IMPLEMENT_REFCOUNTING(CefWaitableEventImpl);
+};
+
+#endif // CEF_LIBCEF_COMMON_WAITABLE_EVENT_IMPL_H_
diff --git a/libcef/features/BUILD.gn b/libcef/features/BUILD.gn
new file mode 100644
index 00000000..79684293
--- /dev/null
+++ b/libcef/features/BUILD.gn
@@ -0,0 +1,101 @@
+# Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/buildflag_header.gni")
+import("//cef/libcef/features/features.gni")
+
+# This file is in a separate directory so all targets in the build can refer to
+# the buildflag header to get the necessary preprocessor defines without
+# bringing in any CEF targets. Other targets can depend on this target
+# regardless of whether CEF is being built. Set the `enable_cef=false` GN arg to
+# disable the CEF changes when building Chrome.
+#
+# Example usage:
+#
+# 1. An existing GN configuration file at path/to/foo/BUILD.gn:
+#
+# # Import the `enable_cef` arg.
+# import("//cef/libcef/features/features.gni")
+# ...
+#
+# # An existing target that is modified for CEF.
+# # The target type might instead be `component`, `source_set`, etc.
+# static_library("foo") {
+# sources = [ ... ]
+#
+# deps = [
+# # Always include the CEF features.
+# "//cef/libcef/features",
+# ...
+# ]
+#
+# if (enable_cef) {
+# # Actions to perform when the CEF build is enabled.
+#
+# # Optionally include CEF source files directly in this target. This
+# # approach is required for targets that are either directly or
+# # indirectly included in a `component` target (otherwise
+# # `is_component_build=true` builds will fail). Keep in mind that these
+# # files are part of this target instead of the `libcef_static` target
+# # and therefore subject to any target-specific configuration settings
+# # such as include paths, defines, compiler flags, etc.
+# sources += [
+# "//cef/libcef/browser/foo_helper.cc",
+# "//cef/libcef/browser/foo_helper.h",
+# ]
+#
+# # Always include the CEF configuration.
+# configs += [ "//cef/libcef/features:config" ]
+# }
+# ...
+# }
+#
+# 2. An existing C++ source file at path/to/foo/foo.cc:
+#
+# // Include the `BUILDFLAG(ENABLE_CEF)` definition.
+# #include "cef/libcef/features/features.h"
+# ...
+#
+# #if BUILDFLAG(ENABLE_CEF)
+# // CEF headers here...
+# #include "cef/libcef/browser/foo_helper.h"
+# #else
+# // Chrome headers here...
+# #endif
+#
+# // An existing function that is modified for CEF.
+# void DoFoo() {
+# #if BUILDFLAG(ENABLE_CEF)
+# // CEF implementation here...
+# cef_foo_helper::DoFoo();
+# #else
+# // Chrome implementation here...
+# #endif // !BUILDFLAG(ENABLE_CEF)
+# }
+# ...
+#
+
+buildflag_header("features") {
+ header = "features.h"
+
+ flags = [
+ "ENABLE_CEF=$enable_cef",
+ "IS_CEF_SANDBOX_BUILD=$is_cef_sandbox_build",
+ ]
+}
+
+# Configuration for all targets that include CEF source code library-side.
+config("config") {
+ # CEF sources use includes relative to the CEF root directory.
+ include_dirs = [
+ "//cef",
+
+ # CEF generates some header files that also need to be discoverable.
+ "$root_build_dir/includes",
+ ]
+ defines = [
+ "BUILDING_CEF_SHARED",
+ "USING_CHROMIUM_INCLUDES",
+ ]
+}
diff --git a/libcef/features/features.gni b/libcef/features/features.gni
new file mode 100644
index 00000000..7d7ae497
--- /dev/null
+++ b/libcef/features/features.gni
@@ -0,0 +1,14 @@
+# Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+declare_args() {
+ enable_cef = true
+
+ # Enables base target customizations necessary for distribution of the
+ # cef_sandbox static library. This value will be set via gn_args.py for the
+ # official sandbox build configurations only. DO NOT SET THIS VALUE MANUALLY
+ # FOR OTHER CHROMIUM/CEF BUILD CONFIGURATIONS AS ITS USE MAY HAVE SIGNIFICANT
+ # PERFORMANCE AND/OR SECURITY IMPLICATIONS.
+ is_cef_sandbox_build = false
+}
diff --git a/libcef/features/runtime.h b/libcef/features/runtime.h
new file mode 100644
index 00000000..f010d672
--- /dev/null
+++ b/libcef/features/runtime.h
@@ -0,0 +1,47 @@
+// Copyright 2020 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_FEATURES_RUNTIME_H_
+#define CEF_LIBCEF_FEATURES_RUNTIME_H_
+#pragma once
+
+#include "cef/libcef/features/features.h"
+
+namespace cef {
+
+#if BUILDFLAG(ENABLE_CEF)
+
+inline bool IsCefBuildEnabled() {
+ return true;
+}
+
+// True if CEF was initialized with the Alloy runtime.
+bool IsAlloyRuntimeEnabled();
+
+// True if CEF was initialized with the Chrome runtime.
+bool IsChromeRuntimeEnabled();
+
+// True if CEF crash reporting is enabled.
+bool IsCrashReportingEnabled();
+
+#else
+
+inline bool IsCefBuildEnabled() {
+ return false;
+}
+inline bool IsAlloyRuntimeEnabled() {
+ return false;
+}
+inline bool IsChromeRuntimeEnabled() {
+ return false;
+}
+inline bool IsCrashReportingEnabled() {
+ return false;
+}
+
+#endif
+
+} // namespace cef
+
+#endif // CEF_LIBCEF_FEATURES_RUNTIME_H_
diff --git a/libcef/features/runtime_checks.h b/libcef/features/runtime_checks.h
new file mode 100644
index 00000000..23f5c5e4
--- /dev/null
+++ b/libcef/features/runtime_checks.h
@@ -0,0 +1,18 @@
+// Copyright 2020 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_FEATURES_RUNTIME_CHECKS_H_
+#define CEF_LIBCEF_FEATURES_RUNTIME_CHECKS_H_
+#pragma once
+
+#include "base/logging.h"
+#include "cef/libcef/features/runtime.h"
+
+#define REQUIRE_ALLOY_RUNTIME() \
+ CHECK(cef::IsAlloyRuntimeEnabled()) << "Alloy runtime is required"
+
+#define REQUIRE_CHROME_RUNTIME() \
+ CHECK(cef::IsChromeRuntimeEnabled()) << "Chrome runtime is required"
+
+#endif // CEF_LIBCEF_FEATURES_RUNTIME_CHECKS_H_
diff --git a/libcef/renderer/alloy/alloy_content_renderer_client.cc b/libcef/renderer/alloy/alloy_content_renderer_client.cc
new file mode 100644
index 00000000..51d89cfd
--- /dev/null
+++ b/libcef/renderer/alloy/alloy_content_renderer_client.cc
@@ -0,0 +1,584 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors.
+// Portions copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/renderer/alloy/alloy_content_renderer_client.h"
+
+#include <utility>
+
+#include "build/build_config.h"
+
+// Enable deprecation warnings on Windows. See http://crbug.com/585142.
+#if BUILDFLAG(IS_WIN)
+#if defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic error "-Wdeprecated-declarations"
+#else
+#pragma warning(push)
+#pragma warning(default : 4996)
+#endif
+#endif
+
+#include "libcef/browser/alloy/alloy_content_browser_client.h"
+#include "libcef/browser/context.h"
+#include "libcef/common/alloy/alloy_content_client.h"
+#include "libcef/common/app_manager.h"
+#include "libcef/common/cef_switches.h"
+#include "libcef/common/extensions/extensions_client.h"
+#include "libcef/common/extensions/extensions_util.h"
+#include "libcef/common/request_impl.h"
+#include "libcef/features/runtime_checks.h"
+#include "libcef/renderer/alloy/alloy_render_thread_observer.h"
+#include "libcef/renderer/alloy/url_loader_throttle_provider_impl.h"
+#include "libcef/renderer/browser_impl.h"
+#include "libcef/renderer/extensions/extensions_renderer_client.h"
+#include "libcef/renderer/extensions/print_render_frame_helper_delegate.h"
+#include "libcef/renderer/render_frame_observer.h"
+#include "libcef/renderer/render_manager.h"
+#include "libcef/renderer/thread_util.h"
+
+#include "base/command_line.h"
+#include "base/memory/ptr_util.h"
+#include "base/metrics/user_metrics_action.h"
+#include "base/path_service.h"
+#include "base/process/current_process.h"
+#include "base/stl_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/pdf_util.h"
+#include "chrome/common/url_constants.h"
+#include "chrome/renderer/browser_exposed_renderer_interfaces.h"
+#include "chrome/renderer/chrome_content_renderer_client.h"
+#include "chrome/renderer/extensions/chrome_extensions_renderer_client.h"
+#include "chrome/renderer/loadtimes_extension_bindings.h"
+#include "chrome/renderer/media/chrome_key_systems.h"
+#include "chrome/renderer/plugins/chrome_plugin_placeholder.h"
+#include "components/content_settings/core/common/content_settings_types.h"
+#include "components/nacl/common/nacl_constants.h"
+#include "components/pdf/common/internal_plugin_helpers.h"
+#include "components/pdf/renderer/internal_plugin_renderer_helpers.h"
+#include "components/printing/renderer/print_render_frame_helper.h"
+#include "components/spellcheck/renderer/spellcheck.h"
+#include "components/spellcheck/renderer/spellcheck_provider.h"
+#include "components/visitedlink/renderer/visitedlink_reader.h"
+#include "components/web_cache/renderer/web_cache_impl.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/child/child_thread.h"
+#include "content/public/common/content_constants.h"
+#include "content/public/common/content_paths.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/common/url_constants.h"
+#include "extensions/common/manifest_handlers/csp_info.h"
+#include "extensions/common/switches.h"
+#include "extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container_manager.h"
+#include "extensions/renderer/renderer_extension_registry.h"
+#include "ipc/ipc_sync_channel.h"
+#include "media/base/media.h"
+#include "mojo/public/cpp/bindings/binder_map.h"
+#include "mojo/public/cpp/bindings/generic_pending_receiver.h"
+#include "printing/print_settings.h"
+#include "services/network/public/cpp/is_potentially_trustworthy.h"
+#include "services/service_manager/public/cpp/connector.h"
+#include "services/service_manager/public/cpp/interface_provider.h"
+#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
+#include "third_party/blink/public/common/associated_interfaces/associated_interface_registry.h"
+#include "third_party/blink/public/platform/scheduler/web_renderer_process_type.h"
+#include "third_party/blink/public/platform/url_conversion.h"
+#include "third_party/blink/public/platform/web_runtime_features.h"
+#include "third_party/blink/public/platform/web_string.h"
+#include "third_party/blink/public/platform/web_url.h"
+#include "third_party/blink/public/web/web_console_message.h"
+#include "third_party/blink/public/web/web_element.h"
+#include "third_party/blink/public/web/web_frame.h"
+#include "third_party/blink/public/web/web_local_frame.h"
+#include "third_party/blink/public/web/web_script_controller.h"
+#include "third_party/blink/public/web/web_security_policy.h"
+#include "third_party/blink/public/web/web_view.h"
+#include "ui/base/l10n/l10n_util.h"
+
+#if BUILDFLAG(IS_MAC)
+#include "base/mac/mac_util.h"
+#include "base/strings/sys_string_conversions.h"
+#endif
+
+AlloyContentRendererClient::AlloyContentRendererClient()
+ : main_entry_time_(base::TimeTicks::Now()),
+ render_manager_(new CefRenderManager) {
+ if (extensions::ExtensionsEnabled()) {
+ extensions_client_.reset(new extensions::CefExtensionsClient);
+ extensions::ExtensionsClient::Set(extensions_client_.get());
+ extensions_renderer_client_.reset(
+ new extensions::CefExtensionsRendererClient);
+ extensions::ExtensionsRendererClient::Set(
+ extensions_renderer_client_.get());
+ }
+}
+
+AlloyContentRendererClient::~AlloyContentRendererClient() {}
+
+// static
+AlloyContentRendererClient* AlloyContentRendererClient::Get() {
+ REQUIRE_ALLOY_RUNTIME();
+ return static_cast<AlloyContentRendererClient*>(
+ CefAppManager::Get()->GetContentClient()->renderer());
+}
+
+scoped_refptr<base::SingleThreadTaskRunner>
+AlloyContentRendererClient::GetCurrentTaskRunner() {
+ // Check if currently on the render thread.
+ if (CEF_CURRENTLY_ON_RT()) {
+ return render_task_runner_;
+ }
+ return nullptr;
+}
+
+void AlloyContentRendererClient::RunSingleProcessCleanup() {
+ DCHECK(content::RenderProcessHost::run_renderer_in_process());
+
+ // Make sure the render thread was actually started.
+ if (!render_task_runner_.get()) {
+ return;
+ }
+
+ if (content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) {
+ RunSingleProcessCleanupOnUIThread();
+ } else {
+ CEF_POST_TASK(
+ CEF_UIT,
+ base::BindOnce(
+ &AlloyContentRendererClient::RunSingleProcessCleanupOnUIThread,
+ base::Unretained(this)));
+ }
+
+ // Wait for the render thread cleanup to complete. Spin instead of using
+ // base::WaitableEvent because calling Wait() is not allowed on the UI
+ // thread.
+ bool complete = false;
+ do {
+ {
+ base::AutoLock lock_scope(single_process_cleanup_lock_);
+ complete = single_process_cleanup_complete_;
+ }
+ if (!complete) {
+ base::PlatformThread::YieldCurrentThread();
+ }
+ } while (!complete);
+}
+
+void AlloyContentRendererClient::PostIOThreadCreated(
+ base::SingleThreadTaskRunner*) {
+ // TODO(cef): Enable these once the implementation supports it.
+ blink::WebRuntimeFeatures::EnableNotifications(false);
+ blink::WebRuntimeFeatures::EnablePushMessaging(false);
+}
+
+void AlloyContentRendererClient::RenderThreadStarted() {
+ const base::CommandLine* command_line =
+ base::CommandLine::ForCurrentProcess();
+
+ render_task_runner_ = base::SingleThreadTaskRunner::GetCurrentDefault();
+ observer_ = std::make_unique<AlloyRenderThreadObserver>();
+ web_cache_impl_ = std::make_unique<web_cache::WebCacheImpl>();
+ visited_link_slave_ = std::make_unique<visitedlink::VisitedLinkReader>();
+
+ content::RenderThread* thread = content::RenderThread::Get();
+
+ const bool is_extension = CefRenderManager::IsExtensionProcess();
+
+ thread->SetRendererProcessType(
+ is_extension
+ ? blink::scheduler::WebRendererProcessType::kExtensionRenderer
+ : blink::scheduler::WebRendererProcessType::kRenderer);
+
+ if (is_extension) {
+ // The process name was set to "Renderer" in RendererMain(). Update it to
+ // "Extension Renderer" to highlight that it's hosting an extension.
+ base::CurrentProcess::GetInstance().SetProcessType(
+ base::CurrentProcessType::PROCESS_RENDERER_EXTENSION);
+ }
+
+ thread->AddObserver(observer_.get());
+
+ if (!command_line->HasSwitch(switches::kDisableSpellChecking)) {
+ spellcheck_ = std::make_unique<SpellCheck>(this);
+ }
+
+ if (content::RenderProcessHost::run_renderer_in_process()) {
+ // When running in single-process mode register as a destruction observer
+ // on the render thread's MessageLoop.
+ base::CurrentThread::Get()->AddDestructionObserver(this);
+ }
+
+#if BUILDFLAG(IS_MAC)
+ {
+ base::ScopedCFTypeRef<CFStringRef> key(
+ base::SysUTF8ToCFStringRef("NSScrollViewRubberbanding"));
+ base::ScopedCFTypeRef<CFStringRef> value;
+
+ // If the command-line switch is specified then set the value that will be
+ // checked in RenderThreadImpl::Init(). Otherwise, remove the application-
+ // level value.
+ if (command_line->HasSwitch(switches::kDisableScrollBounce)) {
+ value.reset(base::SysUTF8ToCFStringRef("false"));
+ }
+
+ CFPreferencesSetAppValue(key, value, kCFPreferencesCurrentApplication);
+ CFPreferencesAppSynchronize(kCFPreferencesCurrentApplication);
+ }
+#endif // BUILDFLAG(IS_MAC)
+
+ if (extensions::ExtensionsEnabled()) {
+ extensions_renderer_client_->RenderThreadStarted();
+ }
+}
+
+void AlloyContentRendererClient::ExposeInterfacesToBrowser(
+ mojo::BinderMap* binders) {
+ auto task_runner = base::SequencedTaskRunner::GetCurrentDefault();
+
+ binders->Add<web_cache::mojom::WebCache>(
+ base::BindRepeating(&web_cache::WebCacheImpl::BindReceiver,
+ base::Unretained(web_cache_impl_.get())),
+ task_runner);
+
+ binders->Add<visitedlink::mojom::VisitedLinkNotificationSink>(
+ visited_link_slave_->GetBindCallback(), task_runner);
+
+ if (spellcheck_) {
+ binders->Add<spellcheck::mojom::SpellChecker>(
+ base::BindRepeating(
+ [](SpellCheck* spellcheck,
+ mojo::PendingReceiver<spellcheck::mojom::SpellChecker>
+ receiver) { spellcheck->BindReceiver(std::move(receiver)); },
+ base::Unretained(spellcheck_.get())),
+ task_runner);
+ }
+
+ render_manager_->ExposeInterfacesToBrowser(binders);
+}
+
+void AlloyContentRendererClient::RenderThreadConnected() {
+ // Register extensions last because it will trigger WebKit initialization.
+ blink::WebScriptController::RegisterExtension(
+ extensions_v8::LoadTimesExtension::Get());
+
+ render_manager_->RenderThreadConnected();
+}
+
+void AlloyContentRendererClient::RenderFrameCreated(
+ content::RenderFrame* render_frame) {
+ auto render_frame_observer = new CefRenderFrameObserver(render_frame);
+
+ if (extensions::ExtensionsEnabled()) {
+ extensions_renderer_client_->RenderFrameCreated(
+ render_frame, render_frame_observer->registry());
+
+ render_frame_observer->associated_interfaces()
+ ->AddInterface<extensions::mojom::MimeHandlerViewContainerManager>(
+ base::BindRepeating(
+ &extensions::MimeHandlerViewContainerManager::BindReceiver,
+ render_frame->GetRoutingID()));
+ }
+
+ const base::CommandLine* command_line =
+ base::CommandLine::ForCurrentProcess();
+ if (!command_line->HasSwitch(switches::kDisableSpellChecking)) {
+ new SpellCheckProvider(render_frame, spellcheck_.get(), this);
+ }
+
+ bool browser_created;
+ absl::optional<bool> is_windowless;
+ render_manager_->RenderFrameCreated(render_frame, render_frame_observer,
+ browser_created, is_windowless);
+ if (browser_created) {
+ OnBrowserCreated(render_frame->GetWebView(), is_windowless);
+ }
+
+ if (is_windowless.has_value()) {
+ new printing::PrintRenderFrameHelper(
+ render_frame,
+ base::WrapUnique(
+ new extensions::CefPrintRenderFrameHelperDelegate(*is_windowless)));
+ }
+}
+
+void AlloyContentRendererClient::WebViewCreated(
+ blink::WebView* web_view,
+ bool was_created_by_renderer,
+ const url::Origin* outermost_origin) {
+ bool browser_created;
+ absl::optional<bool> is_windowless;
+ render_manager_->WebViewCreated(web_view, browser_created, is_windowless);
+ if (browser_created) {
+ OnBrowserCreated(web_view, is_windowless);
+ }
+}
+
+bool AlloyContentRendererClient::IsPluginHandledExternally(
+ content::RenderFrame* render_frame,
+ const blink::WebElement& plugin_element,
+ const GURL& original_url,
+ const std::string& mime_type) {
+ if (!extensions::ExtensionsEnabled()) {
+ return false;
+ }
+
+ DCHECK(plugin_element.HasHTMLTagName("object") ||
+ plugin_element.HasHTMLTagName("embed"));
+ // Blink will next try to load a WebPlugin which would end up in
+ // OverrideCreatePlugin, sending another IPC only to find out the plugin is
+ // not supported. Here it suffices to return false but there should perhaps be
+ // a more unified approach to avoid sending the IPC twice.
+ chrome::mojom::PluginInfoPtr plugin_info = chrome::mojom::PluginInfo::New();
+ ChromeContentRendererClient::GetPluginInfoHost()->GetPluginInfo(
+ original_url, render_frame->GetWebFrame()->Top()->GetSecurityOrigin(),
+ mime_type, &plugin_info);
+ // TODO(ekaramad): Not continuing here due to a disallowed status should take
+ // us to CreatePlugin. See if more in depths investigation of |status| is
+ // necessary here (see https://crbug.com/965747). For now, returning false
+ // should take us to CreatePlugin after HTMLPlugInElement which is called
+ // through HTMLPlugInElement::LoadPlugin code path.
+ if (plugin_info->status != chrome::mojom::PluginStatus::kAllowed &&
+ plugin_info->status !=
+ chrome::mojom::PluginStatus::kPlayImportantContent) {
+ // We could get here when a MimeHandlerView is loaded inside a <webview>
+ // which is using permissions API (see WebViewPluginTests).
+ ChromeExtensionsRendererClient::DidBlockMimeHandlerViewForDisallowedPlugin(
+ plugin_element);
+ return false;
+ }
+ if (plugin_info->actual_mime_type == pdf::kInternalPluginMimeType) {
+ // Only actually treat the internal PDF plugin as externally handled if
+ // used within an origin allowed to create the internal PDF plugin;
+ // otherwise, let Blink try to create the in-process PDF plugin.
+ if (IsPdfInternalPluginAllowedOrigin(
+ render_frame->GetWebFrame()->GetSecurityOrigin())) {
+ return true;
+ }
+ }
+ return ChromeExtensionsRendererClient::MaybeCreateMimeHandlerView(
+ plugin_element, original_url, plugin_info->actual_mime_type,
+ plugin_info->plugin);
+}
+
+bool AlloyContentRendererClient::OverrideCreatePlugin(
+ content::RenderFrame* render_frame,
+ const blink::WebPluginParams& params,
+ blink::WebPlugin** plugin) {
+ std::string orig_mime_type = params.mime_type.Utf8();
+ if (extensions::ExtensionsEnabled() &&
+ !extensions_renderer_client_->OverrideCreatePlugin(render_frame,
+ params)) {
+ return false;
+ }
+
+ GURL url(params.url);
+ chrome::mojom::PluginInfoPtr plugin_info = chrome::mojom::PluginInfo::New();
+ ChromeContentRendererClient::GetPluginInfoHost()->GetPluginInfo(
+ url, render_frame->GetWebFrame()->Top()->GetSecurityOrigin(),
+ orig_mime_type, &plugin_info);
+ *plugin = ChromeContentRendererClient::CreatePlugin(render_frame, params,
+ *plugin_info);
+ return true;
+}
+
+void AlloyContentRendererClient::WillSendRequest(
+ blink::WebLocalFrame* frame,
+ ui::PageTransition transition_type,
+ const blink::WebURL& url,
+ const net::SiteForCookies& site_for_cookies,
+ const url::Origin* initiator_origin,
+ GURL* new_url) {
+ if (extensions::ExtensionsEnabled()) {
+ extensions_renderer_client_->WillSendRequest(frame, transition_type, url,
+ site_for_cookies,
+ initiator_origin, new_url);
+ if (!new_url->is_empty()) {
+ return;
+ }
+ }
+}
+
+uint64_t AlloyContentRendererClient::VisitedLinkHash(const char* canonical_url,
+ size_t length) {
+ return visited_link_slave_->ComputeURLFingerprint(canonical_url, length);
+}
+
+bool AlloyContentRendererClient::IsLinkVisited(uint64_t link_hash) {
+ return visited_link_slave_->IsVisited(link_hash);
+}
+
+bool AlloyContentRendererClient::IsOriginIsolatedPepperPlugin(
+ const base::FilePath& plugin_path) {
+ // Isolate all the plugins (including the PDF plugin).
+ return true;
+}
+
+void AlloyContentRendererClient::GetSupportedKeySystems(
+ media::GetSupportedKeySystemsCB cb) {
+ GetChromeKeySystems(std::move(cb));
+}
+
+void AlloyContentRendererClient::RunScriptsAtDocumentStart(
+ content::RenderFrame* render_frame) {
+ if (extensions::ExtensionsEnabled()) {
+ extensions_renderer_client_->RunScriptsAtDocumentStart(render_frame);
+ }
+}
+
+void AlloyContentRendererClient::RunScriptsAtDocumentEnd(
+ content::RenderFrame* render_frame) {
+ if (extensions::ExtensionsEnabled()) {
+ extensions_renderer_client_->RunScriptsAtDocumentEnd(render_frame);
+ }
+}
+
+void AlloyContentRendererClient::RunScriptsAtDocumentIdle(
+ content::RenderFrame* render_frame) {
+ if (extensions::ExtensionsEnabled()) {
+ extensions_renderer_client_->RunScriptsAtDocumentIdle(render_frame);
+ }
+}
+
+void AlloyContentRendererClient::DevToolsAgentAttached() {
+ // WebWorkers may be creating agents on a different thread.
+ if (!render_task_runner_->BelongsToCurrentThread()) {
+ render_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(&AlloyContentRendererClient::DevToolsAgentAttached,
+ base::Unretained(this)));
+ return;
+ }
+
+ render_manager_->DevToolsAgentAttached();
+}
+
+void AlloyContentRendererClient::DevToolsAgentDetached() {
+ // WebWorkers may be creating agents on a different thread.
+ if (!render_task_runner_->BelongsToCurrentThread()) {
+ render_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(&AlloyContentRendererClient::DevToolsAgentDetached,
+ base::Unretained(this)));
+ return;
+ }
+
+ render_manager_->DevToolsAgentDetached();
+}
+
+std::unique_ptr<blink::URLLoaderThrottleProvider>
+AlloyContentRendererClient::CreateURLLoaderThrottleProvider(
+ blink::URLLoaderThrottleProviderType provider_type) {
+ return std::make_unique<CefURLLoaderThrottleProviderImpl>(provider_type);
+}
+
+void AlloyContentRendererClient::AppendContentSecurityPolicy(
+ const blink::WebURL& url,
+ blink::WebVector<blink::WebContentSecurityPolicyHeader>* csp) {
+ if (!extensions::ExtensionsEnabled()) {
+ return;
+ }
+
+ // Don't apply default CSP to PDF renderers.
+ // TODO(crbug.com/1252096): Lock down the CSP once style and script are no
+ // longer injected inline by `pdf::PluginResponseWriter`. That class may be a
+ // better place to define such CSP, or we may continue doing so here.
+ if (pdf::IsPdfRenderer()) {
+ return;
+ }
+
+ DCHECK(csp);
+ GURL gurl(url);
+ const extensions::Extension* extension =
+ extensions::RendererExtensionRegistry::Get()->GetExtensionOrAppByURL(
+ gurl);
+ if (!extension) {
+ return;
+ }
+
+ // Append a minimum CSP to ensure the extension can't relax the default
+ // applied CSP through means like Service Worker.
+ const std::string* default_csp =
+ extensions::CSPInfo::GetMinimumCSPToAppend(*extension, gurl.path());
+ if (!default_csp) {
+ return;
+ }
+
+ csp->push_back({blink::WebString::FromUTF8(*default_csp),
+ network::mojom::ContentSecurityPolicyType::kEnforce,
+ network::mojom::ContentSecurityPolicySource::kHTTP});
+}
+
+void AlloyContentRendererClient::GetInterface(
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle interface_pipe) {
+ // TODO(crbug.com/977637): Get rid of the use of this implementation of
+ // |service_manager::LocalInterfaceProvider|. This was done only to avoid
+ // churning spellcheck code while eliminating the "chrome" and
+ // "chrome_renderer" services. Spellcheck is (and should remain) the only
+ // consumer of this implementation.
+ content::RenderThread::Get()->BindHostReceiver(
+ mojo::GenericPendingReceiver(interface_name, std::move(interface_pipe)));
+}
+
+void AlloyContentRendererClient::WillDestroyCurrentMessageLoop() {
+ base::AutoLock lock_scope(single_process_cleanup_lock_);
+ single_process_cleanup_complete_ = true;
+}
+
+void AlloyContentRendererClient::OnBrowserCreated(
+ blink::WebView* web_view,
+ absl::optional<bool> is_windowless) {
+#if BUILDFLAG(IS_MAC)
+ const bool windowless = is_windowless.has_value() && *is_windowless;
+
+ // FIXME: It would be better if this API would be a callback from the
+ // WebKit layer, or if it would be exposed as an WebView instance method; the
+ // current implementation uses a static variable, and WebKit needs to be
+ // patched in order to make it work for each WebView instance
+ web_view->SetUseExternalPopupMenusThisInstance(!windowless);
+#endif
+}
+
+void AlloyContentRendererClient::RunSingleProcessCleanupOnUIThread() {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+
+ // Clean up the single existing RenderProcessHost.
+ content::RenderProcessHost* host = nullptr;
+ content::RenderProcessHost::iterator iterator(
+ content::RenderProcessHost::AllHostsIterator());
+ if (!iterator.IsAtEnd()) {
+ host = iterator.GetCurrentValue();
+ host->Cleanup();
+ iterator.Advance();
+ DCHECK(iterator.IsAtEnd());
+ }
+ DCHECK(host);
+
+ // Clear the run_renderer_in_process() flag to avoid a DCHECK in the
+ // RenderProcessHost destructor.
+ content::RenderProcessHost::SetRunRendererInProcess(false);
+
+ // Deletion of the RenderProcessHost object will stop the render thread and
+ // result in a call to WillDestroyCurrentMessageLoop.
+ // Cleanup() will cause deletion to be posted as a task on the UI thread but
+ // this task will only execute when running in multi-threaded message loop
+ // mode (because otherwise the UI message loop has already stopped). Therefore
+ // we need to explicitly delete the object when not running in this mode.
+ if (!CefContext::Get()->settings().multi_threaded_message_loop) {
+ delete host;
+ }
+}
+
+// Enable deprecation warnings on Windows. See http://crbug.com/585142.
+#if BUILDFLAG(IS_WIN)
+#if defined(__clang__)
+#pragma GCC diagnostic pop
+#else
+#pragma warning(pop)
+#endif
+#endif
diff --git a/libcef/renderer/alloy/alloy_content_renderer_client.h b/libcef/renderer/alloy/alloy_content_renderer_client.h
new file mode 100644
index 00000000..eef43f3c
--- /dev/null
+++ b/libcef/renderer/alloy/alloy_content_renderer_client.h
@@ -0,0 +1,152 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors.
+// Portions copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_RENDERER_ALLOY_ALLOY_CONTENT_RENDERER_CLIENT_H_
+#define CEF_LIBCEF_RENDERER_ALLOY_ALLOY_CONTENT_RENDERER_CLIENT_H_
+#pragma once
+
+#include <list>
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "libcef/renderer/browser_impl.h"
+
+#include "base/task/current_thread.h"
+#include "base/task/single_thread_task_runner.h"
+#include "chrome/common/plugin.mojom.h"
+#include "content/public/renderer/content_renderer_client.h"
+#include "content/public/renderer/render_thread.h"
+#include "mojo/public/cpp/bindings/generic_pending_receiver.h"
+#include "services/service_manager/public/cpp/local_interface_provider.h"
+
+namespace extensions {
+class CefExtensionsRendererClient;
+class Dispatcher;
+class DispatcherDelegate;
+class ExtensionsClient;
+class ExtensionsRendererClient;
+class ResourceRequestPolicy;
+} // namespace extensions
+
+namespace visitedlink {
+class VisitedLinkReader;
+}
+
+namespace web_cache {
+class WebCacheImpl;
+}
+
+class AlloyRenderThreadObserver;
+class CefRenderManager;
+class SpellCheck;
+
+class AlloyContentRendererClient
+ : public content::ContentRendererClient,
+ public service_manager::LocalInterfaceProvider,
+ public base::CurrentThread::DestructionObserver {
+ public:
+ AlloyContentRendererClient();
+
+ AlloyContentRendererClient(const AlloyContentRendererClient&) = delete;
+ AlloyContentRendererClient& operator=(const AlloyContentRendererClient&) =
+ delete;
+
+ ~AlloyContentRendererClient() override;
+
+ // Returns the singleton AlloyContentRendererClient instance.
+ // This method is deprecated and should not be used in new callsites.
+ static AlloyContentRendererClient* Get();
+
+ // Render thread task runner.
+ base::SingleThreadTaskRunner* render_task_runner() const {
+ return render_task_runner_.get();
+ }
+
+ // Returns the task runner for the current thread. Returns NULL if the current
+ // thread is not the main render process thread.
+ scoped_refptr<base::SingleThreadTaskRunner> GetCurrentTaskRunner();
+
+ // Perform cleanup work that needs to occur before shutdown when running in
+ // single-process mode. Blocks until cleanup is complete.
+ void RunSingleProcessCleanup();
+
+ // ContentRendererClient implementation.
+ void PostIOThreadCreated(
+ base::SingleThreadTaskRunner* io_thread_task_runner) override;
+ void RenderThreadStarted() override;
+ void ExposeInterfacesToBrowser(mojo::BinderMap* binders) override;
+ void RenderThreadConnected() override;
+ void RenderFrameCreated(content::RenderFrame* render_frame) override;
+ void WebViewCreated(blink::WebView* web_view,
+ bool was_created_by_renderer,
+ const url::Origin* outermost_origin) override;
+ bool IsPluginHandledExternally(content::RenderFrame* render_frame,
+ const blink::WebElement& plugin_element,
+ const GURL& original_url,
+ const std::string& mime_type) override;
+ bool OverrideCreatePlugin(content::RenderFrame* render_frame,
+ const blink::WebPluginParams& params,
+ blink::WebPlugin** plugin) override;
+ void WillSendRequest(blink::WebLocalFrame* frame,
+ ui::PageTransition transition_type,
+ const blink::WebURL& url,
+ const net::SiteForCookies& site_for_cookies,
+ const url::Origin* initiator_origin,
+ GURL* new_url) override;
+ uint64_t VisitedLinkHash(const char* canonical_url, size_t length) override;
+ bool IsLinkVisited(uint64_t link_hash) override;
+ bool IsOriginIsolatedPepperPlugin(const base::FilePath& plugin_path) override;
+ void GetSupportedKeySystems(media::GetSupportedKeySystemsCB cb) override;
+ void RunScriptsAtDocumentStart(content::RenderFrame* render_frame) override;
+ void RunScriptsAtDocumentEnd(content::RenderFrame* render_frame) override;
+ void RunScriptsAtDocumentIdle(content::RenderFrame* render_frame) override;
+ void DevToolsAgentAttached() override;
+ void DevToolsAgentDetached() override;
+ std::unique_ptr<blink::URLLoaderThrottleProvider>
+ CreateURLLoaderThrottleProvider(
+ blink::URLLoaderThrottleProviderType provider_type) override;
+ void AppendContentSecurityPolicy(
+ const blink::WebURL& url,
+ blink::WebVector<blink::WebContentSecurityPolicyHeader>* csp) override;
+
+ // service_manager::LocalInterfaceProvider implementation.
+ void GetInterface(const std::string& name,
+ mojo::ScopedMessagePipeHandle request_handle) override;
+
+ // MessageLoopCurrent::DestructionObserver implementation.
+ void WillDestroyCurrentMessageLoop() override;
+
+ private:
+ void OnBrowserCreated(blink::WebView* web_view,
+ absl::optional<bool> is_windowless);
+
+ // Perform cleanup work for single-process mode.
+ void RunSingleProcessCleanupOnUIThread();
+
+ // Time at which this object was created. This is very close to the time at
+ // which the RendererMain function was entered.
+ base::TimeTicks main_entry_time_;
+
+ std::unique_ptr<CefRenderManager> render_manager_;
+
+ scoped_refptr<base::SingleThreadTaskRunner> render_task_runner_;
+ std::unique_ptr<AlloyRenderThreadObserver> observer_;
+ std::unique_ptr<web_cache::WebCacheImpl> web_cache_impl_;
+ std::unique_ptr<SpellCheck> spellcheck_;
+ std::unique_ptr<visitedlink::VisitedLinkReader> visited_link_slave_;
+
+ std::unique_ptr<extensions::ExtensionsClient> extensions_client_;
+ std::unique_ptr<extensions::CefExtensionsRendererClient>
+ extensions_renderer_client_;
+
+ // Used in single-process mode to test when cleanup is complete.
+ // Access must be protected by |single_process_cleanup_lock_|.
+ bool single_process_cleanup_complete_ = false;
+ base::Lock single_process_cleanup_lock_;
+};
+
+#endif // CEF_LIBCEF_RENDERER_ALLOY_ALLOY_CONTENT_RENDERER_CLIENT_H_
diff --git a/libcef/renderer/alloy/alloy_render_thread_observer.cc b/libcef/renderer/alloy/alloy_render_thread_observer.cc
new file mode 100644
index 00000000..ce6ebca0
--- /dev/null
+++ b/libcef/renderer/alloy/alloy_render_thread_observer.cc
@@ -0,0 +1,69 @@
+/// Copyright (c) 2013 The Chromium Embedded Framework Authors.
+// Portions (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/renderer/alloy/alloy_render_thread_observer.h"
+
+#include "libcef/common/net/net_resource_provider.h"
+
+#include "base/no_destructor.h"
+#include "net/base/net_module.h"
+#include "services/service_manager/public/cpp/connector.h"
+#include "third_party/blink/public/common/associated_interfaces/associated_interface_registry.h"
+
+namespace {
+
+chrome::mojom::DynamicParams* GetDynamicConfigParams() {
+ static base::NoDestructor<chrome::mojom::DynamicParams> dynamic_params;
+ return dynamic_params.get();
+}
+
+} // namespace
+
+bool AlloyRenderThreadObserver::is_incognito_process_ = false;
+
+AlloyRenderThreadObserver::AlloyRenderThreadObserver() {
+ net::NetModule::SetResourceProvider(NetResourceProvider);
+}
+
+AlloyRenderThreadObserver::~AlloyRenderThreadObserver() {}
+
+// static
+const chrome::mojom::DynamicParams&
+AlloyRenderThreadObserver::GetDynamicParams() {
+ return *GetDynamicConfigParams();
+}
+
+void AlloyRenderThreadObserver::RegisterMojoInterfaces(
+ blink::AssociatedInterfaceRegistry* associated_interfaces) {
+ associated_interfaces->AddInterface<chrome::mojom::RendererConfiguration>(
+ base::BindRepeating(
+ &AlloyRenderThreadObserver::OnRendererConfigurationAssociatedRequest,
+ base::Unretained(this)));
+}
+
+void AlloyRenderThreadObserver::UnregisterMojoInterfaces(
+ blink::AssociatedInterfaceRegistry* associated_interfaces) {
+ associated_interfaces->RemoveInterface(
+ chrome::mojom::RendererConfiguration::Name_);
+}
+
+void AlloyRenderThreadObserver::SetInitialConfiguration(
+ bool is_incognito_process,
+ mojo::PendingReceiver<chrome::mojom::ChromeOSListener> chromeos_listener,
+ mojo::PendingRemote<content_settings::mojom::ContentSettingsManager>
+ content_settings_manager) {
+ is_incognito_process_ = is_incognito_process;
+}
+
+void AlloyRenderThreadObserver::SetConfiguration(
+ chrome::mojom::DynamicParamsPtr params) {
+ *GetDynamicConfigParams() = std::move(*params);
+}
+
+void AlloyRenderThreadObserver::OnRendererConfigurationAssociatedRequest(
+ mojo::PendingAssociatedReceiver<chrome::mojom::RendererConfiguration>
+ receiver) {
+ renderer_configuration_receivers_.Add(this, std::move(receiver));
+}
diff --git a/libcef/renderer/alloy/alloy_render_thread_observer.h b/libcef/renderer/alloy/alloy_render_thread_observer.h
new file mode 100644
index 00000000..909ac29c
--- /dev/null
+++ b/libcef/renderer/alloy/alloy_render_thread_observer.h
@@ -0,0 +1,59 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors.
+// Portions copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_RENDERER_ALLOY_ALLOY_RENDER_THREAD_OBSERVER_H_
+#define CEF_LIBCEF_RENDERER_ALLOY_ALLOY_RENDER_THREAD_OBSERVER_H_
+
+#include <memory>
+
+#include "chrome/common/renderer_configuration.mojom.h"
+#include "components/content_settings/core/common/content_settings.h"
+#include "content/public/renderer/render_thread_observer.h"
+#include "mojo/public/cpp/bindings/associated_receiver_set.h"
+
+// This class sends and receives control messages in the renderer process.
+class AlloyRenderThreadObserver : public content::RenderThreadObserver,
+ public chrome::mojom::RendererConfiguration {
+ public:
+ AlloyRenderThreadObserver();
+
+ AlloyRenderThreadObserver(const AlloyRenderThreadObserver&) = delete;
+ AlloyRenderThreadObserver& operator=(const AlloyRenderThreadObserver&) =
+ delete;
+
+ ~AlloyRenderThreadObserver() override;
+
+ static bool is_incognito_process() { return is_incognito_process_; }
+
+ // Return the dynamic parameters - those that may change while the
+ // render process is running.
+ static const chrome::mojom::DynamicParams& GetDynamicParams();
+
+ private:
+ // content::RenderThreadObserver:
+ void RegisterMojoInterfaces(
+ blink::AssociatedInterfaceRegistry* associated_interfaces) override;
+ void UnregisterMojoInterfaces(
+ blink::AssociatedInterfaceRegistry* associated_interfaces) override;
+
+ // chrome::mojom::RendererConfiguration:
+ void SetInitialConfiguration(
+ bool is_incognito_process,
+ mojo::PendingReceiver<chrome::mojom::ChromeOSListener> chromeos_listener,
+ mojo::PendingRemote<content_settings::mojom::ContentSettingsManager>
+ content_settings_manager) override;
+ void SetConfiguration(chrome::mojom::DynamicParamsPtr params) override;
+
+ void OnRendererConfigurationAssociatedRequest(
+ mojo::PendingAssociatedReceiver<chrome::mojom::RendererConfiguration>
+ receiver);
+
+ static bool is_incognito_process_;
+
+ mojo::AssociatedReceiverSet<chrome::mojom::RendererConfiguration>
+ renderer_configuration_receivers_;
+};
+
+#endif // CEF_LIBCEF_RENDERER_ALLOY_ALLOY_RENDER_THREAD_OBSERVER_H_
diff --git a/libcef/renderer/alloy/url_loader_throttle_provider_impl.cc b/libcef/renderer/alloy/url_loader_throttle_provider_impl.cc
new file mode 100644
index 00000000..09bd30d8
--- /dev/null
+++ b/libcef/renderer/alloy/url_loader_throttle_provider_impl.cc
@@ -0,0 +1,67 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/renderer/alloy/url_loader_throttle_provider_impl.h"
+
+#include "libcef/common/extensions/extensions_util.h"
+#include "libcef/renderer/alloy/alloy_render_thread_observer.h"
+
+#include <utility>
+
+#include "base/feature_list.h"
+#include "chrome/common/google_url_loader_throttle.h"
+#include "content/public/common/content_features.h"
+#include "content/public/renderer/render_frame.h"
+#include "services/network/public/cpp/features.h"
+#include "third_party/blink/public/common/loader/resource_type_util.h"
+#include "third_party/blink/public/platform/web_url.h"
+
+CefURLLoaderThrottleProviderImpl::CefURLLoaderThrottleProviderImpl(
+ blink::URLLoaderThrottleProviderType type)
+ : type_(type) {
+ DETACH_FROM_THREAD(thread_checker_);
+}
+
+CefURLLoaderThrottleProviderImpl::~CefURLLoaderThrottleProviderImpl() {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+}
+
+CefURLLoaderThrottleProviderImpl::CefURLLoaderThrottleProviderImpl(
+ const CefURLLoaderThrottleProviderImpl& other)
+ : type_(other.type_) {
+ DETACH_FROM_THREAD(thread_checker_);
+}
+
+std::unique_ptr<blink::URLLoaderThrottleProvider>
+CefURLLoaderThrottleProviderImpl::Clone() {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ return base::WrapUnique(new CefURLLoaderThrottleProviderImpl(*this));
+}
+
+blink::WebVector<std::unique_ptr<blink::URLLoaderThrottle>>
+CefURLLoaderThrottleProviderImpl::CreateThrottles(
+ int render_frame_id,
+ const blink::WebURLRequest& request) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+ blink::WebVector<std::unique_ptr<blink::URLLoaderThrottle>> throttles;
+
+ const network::mojom::RequestDestination request_destination =
+ request.GetRequestDestination();
+
+ // Some throttles have already been added in the browser for frame resources.
+ // Don't add them for frame requests.
+ bool is_frame_resource =
+ blink::IsRequestDestinationFrame(request_destination);
+
+ DCHECK(!is_frame_resource ||
+ type_ == blink::URLLoaderThrottleProviderType::kFrame);
+
+ throttles.emplace_back(std::make_unique<GoogleURLLoaderThrottle>(
+ AlloyRenderThreadObserver::GetDynamicParams()));
+
+ return throttles;
+}
+
+void CefURLLoaderThrottleProviderImpl::SetOnline(bool is_online) {}
diff --git a/libcef/renderer/alloy/url_loader_throttle_provider_impl.h b/libcef/renderer/alloy/url_loader_throttle_provider_impl.h
new file mode 100644
index 00000000..1adf0a23
--- /dev/null
+++ b/libcef/renderer/alloy/url_loader_throttle_provider_impl.h
@@ -0,0 +1,45 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_RENDERER_ALLOY_URL_LOADER_THROTTLE_PROVIDER_IMPL_H_
+#define CEF_LIBCEF_RENDERER_ALLOY_URL_LOADER_THROTTLE_PROVIDER_IMPL_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/threading/thread_checker.h"
+#include "third_party/blink/public/platform/url_loader_throttle_provider.h"
+
+// Instances must be constructed on the render thread, and then used and
+// destructed on a single thread, which can be different from the render thread.
+class CefURLLoaderThrottleProviderImpl
+ : public blink::URLLoaderThrottleProvider {
+ public:
+ explicit CefURLLoaderThrottleProviderImpl(
+ blink::URLLoaderThrottleProviderType type);
+
+ CefURLLoaderThrottleProviderImpl& operator=(
+ const CefURLLoaderThrottleProviderImpl&) = delete;
+
+ ~CefURLLoaderThrottleProviderImpl() override;
+
+ // blink::URLLoaderThrottleProvider implementation.
+ std::unique_ptr<blink::URLLoaderThrottleProvider> Clone() override;
+ blink::WebVector<std::unique_ptr<blink::URLLoaderThrottle>> CreateThrottles(
+ int render_frame_id,
+ const blink::WebURLRequest& request) override;
+ void SetOnline(bool is_online) override;
+
+ private:
+ // This copy constructor works in conjunction with Clone(), not intended for
+ // general use.
+ CefURLLoaderThrottleProviderImpl(
+ const CefURLLoaderThrottleProviderImpl& other);
+
+ blink::URLLoaderThrottleProviderType type_;
+
+ THREAD_CHECKER(thread_checker_);
+};
+
+#endif // CEF_LIBCEF_RENDERER_ALLOY_URL_LOADER_THROTTLE_PROVIDER_IMPL_H_
diff --git a/libcef/renderer/blink_glue.cc b/libcef/renderer/blink_glue.cc
new file mode 100644
index 00000000..4955a0e1
--- /dev/null
+++ b/libcef/renderer/blink_glue.cc
@@ -0,0 +1,338 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors.
+// Portions copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/renderer/blink_glue.h"
+
+#include "third_party/blink/public/mojom/v8_cache_options.mojom-blink.h"
+#include "third_party/blink/public/platform/scheduler/web_resource_loading_task_runner_handle.h"
+#include "third_party/blink/public/platform/web_string.h"
+#include "third_party/blink/public/platform/web_url_response.h"
+#include "third_party/blink/public/web/web_document.h"
+#include "third_party/blink/public/web/web_element.h"
+#include "third_party/blink/public/web/web_local_frame_client.h"
+#include "third_party/blink/public/web/web_node.h"
+#include "third_party/blink/public/web/web_view_client.h"
+
+#include "third_party/blink/renderer/bindings/core/v8/sanitize_script_errors.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_evaluation_result.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
+#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/dom/element.h"
+#include "third_party/blink/renderer/core/dom/node.h"
+#include "third_party/blink/renderer/core/editing/serializers/serialization.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_state_observer.h"
+#include "third_party/blink/renderer/core/exported/web_view_impl.h"
+#include "third_party/blink/renderer/core/frame/frame_owner.h"
+#include "third_party/blink/renderer/core/frame/local_dom_window.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/frame/settings.h"
+#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
+#include "third_party/blink/renderer/core/loader/frame_load_request.h"
+#include "third_party/blink/renderer/core/page/page.h"
+#include "third_party/blink/renderer/core/script/classic_script.h"
+#include "third_party/blink/renderer/platform/bindings/script_forbidden_scope.h"
+#include "third_party/blink/renderer/platform/bindings/v8_binding.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource_response.h"
+#include "third_party/blink/renderer/platform/loader/fetch/script_fetch_options.h"
+#include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h"
+#include "third_party/blink/renderer/platform/scheduler/public/page_scheduler.h"
+#include "third_party/blink/renderer/platform/weborigin/scheme_registry.h"
+#undef LOG
+
+#include "base/logging.h"
+
+namespace blink_glue {
+
+namespace {
+
+blink::ExecutionContext* GetExecutionContext(v8::Local<v8::Context> context) {
+ blink::LocalFrame* frame = blink::ToLocalFrameIfNotDetached(context);
+ if (frame &&
+ frame->DomWindow()->CanExecuteScripts(blink::kAboutToExecuteScript)) {
+ return frame->GetDocument()->GetExecutionContext();
+ }
+ return nullptr;
+}
+
+} // namespace
+
+const int64_t kInvalidFrameId = -1;
+
+bool CanGoBack(blink::WebView* view) {
+ if (!view) {
+ return false;
+ }
+ return view->HistoryBackListCount() > 0;
+}
+
+bool CanGoForward(blink::WebView* view) {
+ if (!view) {
+ return false;
+ }
+ return view->HistoryForwardListCount() > 0;
+}
+
+void GoBack(blink::WebView* view) {
+ if (!view) {
+ return;
+ }
+
+ blink::WebFrame* main_frame = view->MainFrame();
+ if (main_frame && main_frame->IsWebLocalFrame()) {
+ if (view->HistoryBackListCount() > 0) {
+ blink::Frame* core_frame = blink::WebFrame::ToCoreFrame(*main_frame);
+ blink::To<blink::LocalFrame>(core_frame)
+ ->GetLocalFrameHostRemote()
+ .GoToEntryAtOffset(-1, /*has_user_gesture=*/true, absl::nullopt);
+ }
+ }
+}
+
+void GoForward(blink::WebView* view) {
+ if (!view) {
+ return;
+ }
+
+ blink::WebFrame* main_frame = view->MainFrame();
+ if (main_frame && main_frame->IsWebLocalFrame()) {
+ if (view->HistoryForwardListCount() > 0) {
+ blink::Frame* core_frame = blink::WebFrame::ToCoreFrame(*main_frame);
+ blink::To<blink::LocalFrame>(core_frame)
+ ->GetLocalFrameHostRemote()
+ .GoToEntryAtOffset(1, /*has_user_gesture=*/true, absl::nullopt);
+ }
+ }
+}
+
+bool IsInBackForwardCache(blink::WebLocalFrame* frame) {
+ blink::Frame* core_frame = blink::WebFrame::ToCoreFrame(*frame);
+ return blink::To<blink::LocalFrame>(core_frame)
+ ->GetPage()
+ ->GetPageScheduler()
+ ->IsInBackForwardCache();
+}
+
+blink::WebString DumpDocumentText(blink::WebLocalFrame* frame) {
+ // We use the document element's text instead of the body text here because
+ // not all documents have a body, such as XML documents.
+ blink::WebElement document_element = frame->GetDocument().DocumentElement();
+ if (document_element.IsNull()) {
+ return blink::WebString();
+ }
+
+ blink::Element* web_element = document_element.Unwrap<blink::Element>();
+ return blink::WebString(web_element->innerText());
+}
+
+blink::WebString DumpDocumentMarkup(blink::WebLocalFrame* frame) {
+ return blink::CreateMarkup(
+ blink::To<blink::WebLocalFrameImpl>(frame)->GetFrame()->GetDocument());
+}
+
+cef_dom_node_type_t GetNodeType(const blink::WebNode& node) {
+ const blink::Node* web_node = node.ConstUnwrap<blink::Node>();
+ switch (web_node->getNodeType()) {
+ case blink::Node::kElementNode:
+ return DOM_NODE_TYPE_ELEMENT;
+ case blink::Node::kAttributeNode:
+ return DOM_NODE_TYPE_ATTRIBUTE;
+ case blink::Node::kTextNode:
+ return DOM_NODE_TYPE_TEXT;
+ case blink::Node::kCdataSectionNode:
+ return DOM_NODE_TYPE_CDATA_SECTION;
+ case blink::Node::kProcessingInstructionNode:
+ return DOM_NODE_TYPE_PROCESSING_INSTRUCTIONS;
+ case blink::Node::kCommentNode:
+ return DOM_NODE_TYPE_COMMENT;
+ case blink::Node::kDocumentNode:
+ return DOM_NODE_TYPE_DOCUMENT;
+ case blink::Node::kDocumentTypeNode:
+ return DOM_NODE_TYPE_DOCUMENT_TYPE;
+ case blink::Node::kDocumentFragmentNode:
+ return DOM_NODE_TYPE_DOCUMENT_FRAGMENT;
+ }
+ return DOM_NODE_TYPE_UNSUPPORTED;
+}
+
+blink::WebString GetNodeName(const blink::WebNode& node) {
+ const blink::Node* web_node = node.ConstUnwrap<blink::Node>();
+ return web_node->nodeName();
+}
+
+blink::WebString CreateNodeMarkup(const blink::WebNode& node) {
+ const blink::Node* web_node = node.ConstUnwrap<blink::Node>();
+ return blink::CreateMarkup(web_node);
+}
+
+bool SetNodeValue(blink::WebNode& node, const blink::WebString& value) {
+ blink::Node* web_node = node.Unwrap<blink::Node>();
+ web_node->setNodeValue(value);
+ return true;
+}
+
+v8::MaybeLocal<v8::Value> CallV8Function(v8::Local<v8::Context> context,
+ v8::Local<v8::Function> function,
+ v8::Local<v8::Object> receiver,
+ int argc,
+ v8::Local<v8::Value> args[],
+ v8::Isolate* isolate) {
+ v8::MaybeLocal<v8::Value> func_rv;
+
+ // Execute the function call using the V8ScriptRunner so that inspector
+ // instrumentation works.
+ if (auto execution_context = GetExecutionContext(context)) {
+ func_rv = blink::V8ScriptRunner::CallFunction(
+ function, execution_context, receiver, argc, args, isolate);
+ }
+
+ return func_rv;
+}
+
+bool IsTextControlElement(const blink::WebElement& element) {
+ const blink::Element* web_element = element.ConstUnwrap<blink::Element>();
+ return web_element->IsTextControl();
+}
+
+v8::Local<v8::Value> ExecuteV8ScriptAndReturnValue(
+ const blink::WebString& source,
+ const blink::WebString& source_url,
+ int start_line,
+ v8::Local<v8::Context> context,
+ v8::TryCatch& tryCatch) {
+ if (start_line < 1) {
+ start_line = 1;
+ }
+
+ blink::LocalFrame* frame = blink::ToLocalFrameIfNotDetached(context);
+ if (!frame) {
+ return v8::Local<v8::Value>();
+ }
+
+ auto* script = blink::ClassicScript::Create(
+ source, blink::KURL(source_url), blink::KURL(source_url),
+ blink::ScriptFetchOptions(), blink::ScriptSourceLocationType::kInternal,
+ blink::SanitizeScriptErrors::kDoNotSanitize, /*cache_handler=*/nullptr,
+ WTF::TextPosition(WTF::OrdinalNumber::FromOneBasedInt(start_line),
+ WTF::OrdinalNumber::FromZeroBasedInt(0)));
+
+ // The Rethrow() message is unused due to kDoNotSanitize but it still needs
+ // to be non-nullopt for exceptions to be re-thrown as expected.
+ auto result = blink::V8ScriptRunner::CompileAndRunScript(
+ blink::ScriptState::From(context), script,
+ blink::ExecuteScriptPolicy::kExecuteScriptWhenScriptsDisabled,
+ blink::V8ScriptRunner::RethrowErrorsOption::Rethrow(""));
+
+ if (result.GetResultType() ==
+ blink::ScriptEvaluationResult::ResultType::kSuccess) {
+ return result.GetSuccessValue();
+ }
+
+ DCHECK(tryCatch.HasCaught());
+ return v8::Local<v8::Value>();
+}
+
+v8::MicrotaskQueue* GetMicrotaskQueue(v8::Local<v8::Context> context) {
+ if (auto execution_context = GetExecutionContext(context)) {
+ return execution_context->GetMicrotaskQueue();
+ }
+ return nullptr;
+}
+
+bool IsScriptForbidden() {
+ return blink::ScriptForbiddenScope::IsScriptForbidden();
+}
+
+std::unique_ptr<CefObserverRegistration>
+RegisterExecutionContextLifecycleStateObserver(
+ v8::Local<v8::Context> context,
+ CefExecutionContextLifecycleStateObserver* observer) {
+ class Observer : public blink::GarbageCollected<Observer>,
+ public blink::ExecutionContextLifecycleStateObserver {
+ public:
+ Observer(blink::ExecutionContext* execution_context,
+ CefExecutionContextLifecycleStateObserver* observer)
+ : blink::ExecutionContextLifecycleStateObserver(execution_context),
+ observer_(observer) {
+ UpdateStateIfNeeded();
+ }
+
+ void ContextLifecycleStateChanged(
+ blink::mojom::blink::FrameLifecycleState state) override {
+ observer_->ContextLifecycleStateChanged(state);
+ }
+
+ void ContextDestroyed() override {}
+
+ private:
+ CefExecutionContextLifecycleStateObserver* observer_;
+ };
+
+ class Registration : public CefObserverRegistration {
+ public:
+ Registration(blink::Persistent<Observer> observer) : observer_(observer) {}
+
+ private:
+ blink::Persistent<Observer> observer_;
+ };
+
+ return std::make_unique<Registration>(blink::MakeGarbageCollected<Observer>(
+ blink::ExecutionContext::From(context), observer));
+}
+
+void RegisterURLSchemeAsSupportingFetchAPI(const blink::WebString& scheme) {
+ blink::SchemeRegistry::RegisterURLSchemeAsSupportingFetchAPI(scheme);
+}
+
+struct CefScriptForbiddenScope::Impl {
+ blink::ScriptForbiddenScope scope_;
+};
+
+CefScriptForbiddenScope::CefScriptForbiddenScope() : impl_(new Impl()) {}
+
+CefScriptForbiddenScope::~CefScriptForbiddenScope() {}
+
+bool ResponseWasCached(const blink::WebURLResponse& response) {
+ return response.ToResourceResponse().WasCached();
+}
+
+bool HasPluginFrameOwner(blink::WebLocalFrame* frame) {
+ blink::Frame* core_frame = blink::WebFrame::ToCoreFrame(*frame);
+ return core_frame->Owner() && core_frame->Owner()->IsPlugin();
+}
+
+// Based on WebLocalFrameImpl::StartNavigation which was removed in
+// https://crrev.com/de4fc2a5fe.
+void StartNavigation(blink::WebLocalFrame* frame,
+ const blink::WebURLRequest& request) {
+ DCHECK(!request.IsNull());
+ DCHECK(!request.Url().ProtocolIs("javascript"));
+
+ blink::FrameLoadRequest frame_load_request(nullptr,
+ request.ToResourceRequest());
+ blink::Frame* core_frame = blink::WebFrame::ToCoreFrame(*frame);
+ blink::To<blink::LocalFrame>(core_frame)
+ ->Loader()
+ .StartNavigation(frame_load_request, blink::WebFrameLoadType::kStandard);
+}
+
+std::unique_ptr<blink::scheduler::WebResourceLoadingTaskRunnerHandle>
+CreateResourceLoadingTaskRunnerHandle(blink::WebLocalFrame* frame) {
+ blink::Frame* core_frame = blink::WebFrame::ToCoreFrame(*frame);
+ return blink::To<blink::LocalFrame>(core_frame)
+ ->GetFrameScheduler()
+ ->CreateResourceLoadingTaskRunnerHandle();
+}
+
+std::unique_ptr<blink::scheduler::WebResourceLoadingTaskRunnerHandle>
+CreateResourceLoadingMaybeUnfreezableTaskRunnerHandle(
+ blink::WebLocalFrame* frame) {
+ blink::Frame* core_frame = blink::WebFrame::ToCoreFrame(*frame);
+ return blink::To<blink::LocalFrame>(core_frame)
+ ->GetFrameScheduler()
+ ->CreateResourceLoadingMaybeUnfreezableTaskRunnerHandle();
+}
+
+} // namespace blink_glue
diff --git a/libcef/renderer/blink_glue.h b/libcef/renderer/blink_glue.h
new file mode 100644
index 00000000..9a19aa30
--- /dev/null
+++ b/libcef/renderer/blink_glue.h
@@ -0,0 +1,142 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors.
+// Portions copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_RENDERER_BLINK_GLUE_H_
+#define CEF_LIBCEF_RENDERER_BLINK_GLUE_H_
+
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+
+#include "include/internal/cef_types.h"
+
+#include "third_party/blink/public/mojom/frame/lifecycle.mojom-blink-forward.h"
+#include "third_party/blink/public/platform/web_common.h"
+#include "v8/include/v8.h"
+
+namespace blink {
+class WebElement;
+class WebLocalFrame;
+class WebNode;
+class WebString;
+class WebURLRequest;
+class WebURLResponse;
+class WebView;
+
+namespace scheduler {
+class WebResourceLoadingTaskRunnerHandle;
+}
+} // namespace blink
+
+namespace blink_glue {
+
+BLINK_EXPORT extern const int64_t kInvalidFrameId;
+
+BLINK_EXPORT bool CanGoBack(blink::WebView* view);
+BLINK_EXPORT bool CanGoForward(blink::WebView* view);
+BLINK_EXPORT void GoBack(blink::WebView* view);
+BLINK_EXPORT void GoForward(blink::WebView* view);
+
+BLINK_EXPORT bool IsInBackForwardCache(blink::WebLocalFrame* frame);
+
+// Returns the text of the document element.
+BLINK_EXPORT blink::WebString DumpDocumentText(blink::WebLocalFrame* frame);
+// Returns the markup of the document element.
+BLINK_EXPORT blink::WebString DumpDocumentMarkup(blink::WebLocalFrame* frame);
+
+// Expose additional actions on WebNode.
+BLINK_EXPORT cef_dom_node_type_t GetNodeType(const blink::WebNode& node);
+BLINK_EXPORT blink::WebString GetNodeName(const blink::WebNode& node);
+BLINK_EXPORT blink::WebString CreateNodeMarkup(const blink::WebNode& node);
+BLINK_EXPORT bool SetNodeValue(blink::WebNode& node,
+ const blink::WebString& value);
+
+BLINK_EXPORT bool IsTextControlElement(const blink::WebElement& element);
+
+BLINK_EXPORT v8::MaybeLocal<v8::Value> CallV8Function(
+ v8::Local<v8::Context> context,
+ v8::Local<v8::Function> function,
+ v8::Local<v8::Object> receiver,
+ int argc,
+ v8::Local<v8::Value> args[],
+ v8::Isolate* isolate);
+
+BLINK_EXPORT v8::Local<v8::Value> ExecuteV8ScriptAndReturnValue(
+ const blink::WebString& source,
+ const blink::WebString& source_url,
+ int start_line,
+ v8::Local<v8::Context> context,
+ v8::TryCatch& tryCatch);
+
+BLINK_EXPORT v8::MicrotaskQueue* GetMicrotaskQueue(
+ v8::Local<v8::Context> context);
+
+BLINK_EXPORT bool IsScriptForbidden();
+
+class BLINK_EXPORT CefObserverRegistration {
+ public:
+ CefObserverRegistration() = default;
+
+ CefObserverRegistration(const CefObserverRegistration&) = delete;
+ CefObserverRegistration& operator=(const CefObserverRegistration&) = delete;
+
+ virtual ~CefObserverRegistration() = default;
+};
+
+class BLINK_EXPORT CefExecutionContextLifecycleStateObserver {
+ public:
+ virtual void ContextLifecycleStateChanged(
+ blink::mojom::blink::FrameLifecycleState state) {}
+
+ protected:
+ virtual ~CefExecutionContextLifecycleStateObserver() = default;
+};
+
+// Register an ExecutionContextLifecycleStateObserver. Remains registered until
+// the returned object is destroyed.
+BLINK_EXPORT std::unique_ptr<CefObserverRegistration>
+RegisterExecutionContextLifecycleStateObserver(
+ v8::Local<v8::Context> context,
+ CefExecutionContextLifecycleStateObserver* observer);
+
+BLINK_EXPORT void RegisterURLSchemeAsSupportingFetchAPI(
+ const blink::WebString& scheme);
+
+// Wrapper for blink::ScriptForbiddenScope.
+class BLINK_EXPORT CefScriptForbiddenScope final {
+ public:
+ CefScriptForbiddenScope();
+
+ CefScriptForbiddenScope(const CefScriptForbiddenScope&) = delete;
+ CefScriptForbiddenScope& operator=(const CefScriptForbiddenScope&) = delete;
+
+ ~CefScriptForbiddenScope();
+
+ private:
+ struct Impl;
+ std::unique_ptr<Impl> impl_;
+};
+
+BLINK_EXPORT bool ResponseWasCached(const blink::WebURLResponse& response);
+
+// Returns true if the frame owner is a plugin.
+BLINK_EXPORT bool HasPluginFrameOwner(blink::WebLocalFrame* frame);
+
+BLINK_EXPORT void StartNavigation(blink::WebLocalFrame* frame,
+ const blink::WebURLRequest& request);
+
+// Used by CefFrameImpl::CreateURLLoader.
+BLINK_EXPORT
+std::unique_ptr<blink::scheduler::WebResourceLoadingTaskRunnerHandle>
+CreateResourceLoadingTaskRunnerHandle(blink::WebLocalFrame* frame);
+BLINK_EXPORT
+std::unique_ptr<blink::scheduler::WebResourceLoadingTaskRunnerHandle>
+CreateResourceLoadingMaybeUnfreezableTaskRunnerHandle(
+ blink::WebLocalFrame* frame);
+
+} // namespace blink_glue
+
+#endif // CEF_LIBCEF_RENDERER_BLINK_GLUE_H_
diff --git a/libcef/renderer/browser_impl.cc b/libcef/renderer/browser_impl.cc
new file mode 100644
index 00000000..32628c45
--- /dev/null
+++ b/libcef/renderer/browser_impl.cc
@@ -0,0 +1,434 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors.
+// Portions copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/renderer/browser_impl.h"
+
+#include <string>
+#include <vector>
+
+#include "libcef/common/app_manager.h"
+#include "libcef/renderer/blink_glue.h"
+#include "libcef/renderer/render_frame_util.h"
+#include "libcef/renderer/render_manager.h"
+#include "libcef/renderer/thread_util.h"
+
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "content/public/renderer/render_frame.h"
+#include "content/renderer/document_state.h"
+#include "content/renderer/navigation_state.h"
+#include "third_party/blink/public/platform/web_string.h"
+#include "third_party/blink/public/platform/web_url_error.h"
+#include "third_party/blink/public/platform/web_url_response.h"
+#include "third_party/blink/public/web/web_document.h"
+#include "third_party/blink/public/web/web_frame.h"
+#include "third_party/blink/public/web/web_frame_content_dumper.h"
+#include "third_party/blink/public/web/web_local_frame.h"
+#include "third_party/blink/public/web/web_security_policy.h"
+#include "third_party/blink/public/web/web_view.h"
+
+// CefBrowserImpl static methods.
+// -----------------------------------------------------------------------------
+
+// static
+CefRefPtr<CefBrowserImpl> CefBrowserImpl::GetBrowserForView(
+ blink::WebView* view) {
+ return CefRenderManager::Get()->GetBrowserForView(view);
+}
+
+// static
+CefRefPtr<CefBrowserImpl> CefBrowserImpl::GetBrowserForMainFrame(
+ blink::WebFrame* frame) {
+ return CefRenderManager::Get()->GetBrowserForMainFrame(frame);
+}
+
+// CefBrowser methods.
+// -----------------------------------------------------------------------------
+
+bool CefBrowserImpl::IsValid() {
+ CEF_REQUIRE_RT_RETURN(false);
+ return !!GetWebView();
+}
+
+CefRefPtr<CefBrowserHost> CefBrowserImpl::GetHost() {
+ NOTREACHED() << "GetHost cannot be called from the render process";
+ return nullptr;
+}
+
+bool CefBrowserImpl::CanGoBack() {
+ CEF_REQUIRE_RT_RETURN(false);
+
+ return blink_glue::CanGoBack(GetWebView());
+}
+
+void CefBrowserImpl::GoBack() {
+ CEF_REQUIRE_RT_RETURN_VOID();
+
+ blink_glue::GoBack(GetWebView());
+}
+
+bool CefBrowserImpl::CanGoForward() {
+ CEF_REQUIRE_RT_RETURN(false);
+
+ return blink_glue::CanGoForward(GetWebView());
+}
+
+void CefBrowserImpl::GoForward() {
+ CEF_REQUIRE_RT_RETURN_VOID();
+
+ blink_glue::GoForward(GetWebView());
+}
+
+bool CefBrowserImpl::IsLoading() {
+ CEF_REQUIRE_RT_RETURN(false);
+
+ if (GetWebView()) {
+ blink::WebFrame* main_frame = GetWebView()->MainFrame();
+ if (main_frame) {
+ return main_frame->ToWebLocalFrame()->IsLoading();
+ }
+ }
+ return false;
+}
+
+void CefBrowserImpl::Reload() {
+ CEF_REQUIRE_RT_RETURN_VOID();
+
+ if (GetWebView()) {
+ blink::WebFrame* main_frame = GetWebView()->MainFrame();
+ if (main_frame && main_frame->IsWebLocalFrame()) {
+ main_frame->ToWebLocalFrame()->StartReload(
+ blink::WebFrameLoadType::kReload);
+ }
+ }
+}
+
+void CefBrowserImpl::ReloadIgnoreCache() {
+ CEF_REQUIRE_RT_RETURN_VOID();
+
+ if (GetWebView()) {
+ blink::WebFrame* main_frame = GetWebView()->MainFrame();
+ if (main_frame && main_frame->IsWebLocalFrame()) {
+ main_frame->ToWebLocalFrame()->StartReload(
+ blink::WebFrameLoadType::kReloadBypassingCache);
+ }
+ }
+}
+
+void CefBrowserImpl::StopLoad() {
+ CEF_REQUIRE_RT_RETURN_VOID();
+
+ if (GetWebView()) {
+ blink::WebFrame* main_frame = GetWebView()->MainFrame();
+ if (main_frame && main_frame->IsWebLocalFrame()) {
+ main_frame->ToWebLocalFrame()->DeprecatedStopLoading();
+ }
+ }
+}
+
+int CefBrowserImpl::GetIdentifier() {
+ CEF_REQUIRE_RT_RETURN(0);
+
+ return browser_id();
+}
+
+bool CefBrowserImpl::IsSame(CefRefPtr<CefBrowser> that) {
+ CEF_REQUIRE_RT_RETURN(false);
+
+ CefBrowserImpl* impl = static_cast<CefBrowserImpl*>(that.get());
+ return (impl == this);
+}
+
+bool CefBrowserImpl::IsPopup() {
+ CEF_REQUIRE_RT_RETURN(false);
+
+ return is_popup();
+}
+
+bool CefBrowserImpl::HasDocument() {
+ CEF_REQUIRE_RT_RETURN(false);
+
+ if (GetWebView()) {
+ blink::WebFrame* main_frame = GetWebView()->MainFrame();
+ if (main_frame && main_frame->IsWebLocalFrame()) {
+ return !main_frame->ToWebLocalFrame()->GetDocument().IsNull();
+ }
+ }
+ return false;
+}
+
+CefRefPtr<CefFrame> CefBrowserImpl::GetMainFrame() {
+ CEF_REQUIRE_RT_RETURN(nullptr);
+
+ if (GetWebView()) {
+ blink::WebFrame* main_frame = GetWebView()->MainFrame();
+ if (main_frame && main_frame->IsWebLocalFrame()) {
+ return GetWebFrameImpl(main_frame->ToWebLocalFrame()).get();
+ }
+ }
+ return nullptr;
+}
+
+CefRefPtr<CefFrame> CefBrowserImpl::GetFocusedFrame() {
+ CEF_REQUIRE_RT_RETURN(nullptr);
+
+ if (GetWebView() && GetWebView()->FocusedFrame()) {
+ return GetWebFrameImpl(GetWebView()->FocusedFrame()).get();
+ }
+ return nullptr;
+}
+
+CefRefPtr<CefFrame> CefBrowserImpl::GetFrame(int64 identifier) {
+ CEF_REQUIRE_RT_RETURN(nullptr);
+
+ return GetWebFrameImpl(identifier).get();
+}
+
+CefRefPtr<CefFrame> CefBrowserImpl::GetFrame(const CefString& name) {
+ CEF_REQUIRE_RT_RETURN(nullptr);
+
+ blink::WebView* web_view = GetWebView();
+ if (web_view) {
+ const blink::WebString& frame_name =
+ blink::WebString::FromUTF16(name.ToString16());
+ // Search by assigned frame name (Frame::name).
+ blink::WebFrame* frame = web_view->MainFrame();
+ if (frame && frame->IsWebLocalFrame()) {
+ frame = frame->ToWebLocalFrame()->FindFrameByName(frame_name);
+ }
+ if (!frame) {
+ // Search by unique frame name (Frame::uniqueName).
+ const std::string& searchname = name;
+ for (blink::WebFrame* cur_frame = web_view->MainFrame(); cur_frame;
+ cur_frame = cur_frame->TraverseNext()) {
+ if (cur_frame->IsWebLocalFrame() &&
+ render_frame_util::GetName(cur_frame->ToWebLocalFrame()) ==
+ searchname) {
+ frame = cur_frame;
+ break;
+ }
+ }
+ }
+ if (frame && frame->IsWebLocalFrame()) {
+ return GetWebFrameImpl(frame->ToWebLocalFrame()).get();
+ }
+ }
+
+ return nullptr;
+}
+
+size_t CefBrowserImpl::GetFrameCount() {
+ CEF_REQUIRE_RT_RETURN(0);
+
+ int count = 0;
+
+ if (GetWebView()) {
+ for (blink::WebFrame* frame = GetWebView()->MainFrame(); frame;
+ frame = frame->TraverseNext()) {
+ count++;
+ }
+ }
+
+ return count;
+}
+
+void CefBrowserImpl::GetFrameIdentifiers(std::vector<int64>& identifiers) {
+ CEF_REQUIRE_RT_RETURN_VOID();
+
+ if (identifiers.size() > 0) {
+ identifiers.clear();
+ }
+
+ if (GetWebView()) {
+ for (blink::WebFrame* frame = GetWebView()->MainFrame(); frame;
+ frame = frame->TraverseNext()) {
+ if (frame->IsWebLocalFrame()) {
+ identifiers.push_back(
+ render_frame_util::GetIdentifier(frame->ToWebLocalFrame()));
+ }
+ }
+ }
+}
+
+void CefBrowserImpl::GetFrameNames(std::vector<CefString>& names) {
+ CEF_REQUIRE_RT_RETURN_VOID();
+
+ if (names.size() > 0) {
+ names.clear();
+ }
+
+ if (GetWebView()) {
+ for (blink::WebFrame* frame = GetWebView()->MainFrame(); frame;
+ frame = frame->TraverseNext()) {
+ if (frame->IsWebLocalFrame()) {
+ names.push_back(render_frame_util::GetName(frame->ToWebLocalFrame()));
+ }
+ }
+ }
+}
+
+// CefBrowserImpl public methods.
+// -----------------------------------------------------------------------------
+
+CefBrowserImpl::CefBrowserImpl(blink::WebView* web_view,
+ int browser_id,
+ bool is_popup,
+ bool is_windowless)
+ : blink::WebViewObserver(web_view),
+ browser_id_(browser_id),
+ is_popup_(is_popup),
+ is_windowless_(is_windowless) {}
+
+CefBrowserImpl::~CefBrowserImpl() {}
+
+CefRefPtr<CefFrameImpl> CefBrowserImpl::GetWebFrameImpl(
+ blink::WebLocalFrame* frame) {
+ DCHECK(frame);
+ int64_t frame_id = render_frame_util::GetIdentifier(frame);
+
+ // Frames are re-used between page loads. Only add the frame to the map once.
+ FrameMap::const_iterator it = frames_.find(frame_id);
+ if (it != frames_.end()) {
+ return it->second;
+ }
+
+ CefRefPtr<CefFrameImpl> framePtr(new CefFrameImpl(this, frame, frame_id));
+ frames_.insert(std::make_pair(frame_id, framePtr));
+
+ return framePtr;
+}
+
+CefRefPtr<CefFrameImpl> CefBrowserImpl::GetWebFrameImpl(int64_t frame_id) {
+ if (frame_id == blink_glue::kInvalidFrameId) {
+ if (GetWebView()) {
+ blink::WebFrame* main_frame = GetWebView()->MainFrame();
+ if (main_frame && main_frame->IsWebLocalFrame()) {
+ return GetWebFrameImpl(main_frame->ToWebLocalFrame());
+ }
+ }
+ return nullptr;
+ }
+
+ // Check if we already know about the frame.
+ FrameMap::const_iterator it = frames_.find(frame_id);
+ if (it != frames_.end()) {
+ return it->second;
+ }
+
+ if (GetWebView()) {
+ // Check if the frame exists but we don't know about it yet.
+ for (blink::WebFrame* frame = GetWebView()->MainFrame(); frame;
+ frame = frame->TraverseNext()) {
+ if (frame->IsWebLocalFrame() &&
+ render_frame_util::GetIdentifier(frame->ToWebLocalFrame()) ==
+ frame_id) {
+ return GetWebFrameImpl(frame->ToWebLocalFrame());
+ }
+ }
+ }
+
+ return nullptr;
+}
+
+void CefBrowserImpl::AddFrameObject(int64_t frame_id,
+ CefTrackNode* tracked_object) {
+ CefRefPtr<CefTrackManager> manager;
+
+ if (!frame_objects_.empty()) {
+ FrameObjectMap::const_iterator it = frame_objects_.find(frame_id);
+ if (it != frame_objects_.end()) {
+ manager = it->second;
+ }
+ }
+
+ if (!manager.get()) {
+ manager = new CefTrackManager();
+ frame_objects_.insert(std::make_pair(frame_id, manager));
+ }
+
+ manager->Add(tracked_object);
+}
+
+// RenderViewObserver methods.
+// -----------------------------------------------------------------------------
+
+void CefBrowserImpl::OnDestruct() {
+ // Notify that the browser window has been destroyed.
+ CefRefPtr<CefApp> app = CefAppManager::Get()->GetApplication();
+ if (app.get()) {
+ CefRefPtr<CefRenderProcessHandler> handler = app->GetRenderProcessHandler();
+ if (handler.get()) {
+ handler->OnBrowserDestroyed(this);
+ }
+ }
+
+ CefRenderManager::Get()->OnBrowserDestroyed(this);
+}
+
+void CefBrowserImpl::FrameDetached(int64_t frame_id) {
+ if (!frames_.empty()) {
+ // Remove the frame from the map.
+ FrameMap::iterator it = frames_.find(frame_id);
+ if (it != frames_.end()) {
+ frames_.erase(it);
+ }
+ }
+
+ if (!frame_objects_.empty()) {
+ // Remove any tracked objects associated with the frame.
+ FrameObjectMap::iterator it = frame_objects_.find(frame_id);
+ if (it != frame_objects_.end()) {
+ frame_objects_.erase(it);
+ }
+ }
+}
+
+void CefBrowserImpl::OnLoadingStateChange(bool isLoading) {
+ CefRefPtr<CefApp> app = CefAppManager::Get()->GetApplication();
+ if (app.get()) {
+ CefRefPtr<CefRenderProcessHandler> handler = app->GetRenderProcessHandler();
+ if (handler.get()) {
+ CefRefPtr<CefLoadHandler> load_handler = handler->GetLoadHandler();
+ if (load_handler.get()) {
+ blink::WebView* web_view = GetWebView();
+ const bool canGoBack = blink_glue::CanGoBack(web_view);
+ const bool canGoForward = blink_glue::CanGoForward(web_view);
+
+ // Don't call OnLoadingStateChange multiple times with the same status.
+ // This can occur in cases where there are multiple highest-level
+ // LocalFrames in-process for the same browser.
+ if (last_loading_state_ &&
+ last_loading_state_->IsMatch(isLoading, canGoBack, canGoForward)) {
+ return;
+ }
+
+ if (was_in_bfcache_) {
+ // Send the expected callbacks when exiting the BFCache.
+ DCHECK(!isLoading);
+ load_handler->OnLoadingStateChange(this, /*isLoading=*/true,
+ canGoBack, canGoForward);
+
+ auto main_frame = GetMainFrame();
+ load_handler->OnLoadStart(this, main_frame, TT_EXPLICIT);
+ load_handler->OnLoadEnd(this, main_frame, 0);
+
+ was_in_bfcache_ = false;
+ }
+
+ load_handler->OnLoadingStateChange(this, isLoading, canGoBack,
+ canGoForward);
+ last_loading_state_.reset(
+ new LoadingState(isLoading, canGoBack, canGoForward));
+ }
+ }
+ }
+}
+
+void CefBrowserImpl::OnEnterBFCache() {
+ // Reset loading state so that notifications will be resent if/when exiting
+ // BFCache.
+ was_in_bfcache_ = true;
+ last_loading_state_.reset();
+}
diff --git a/libcef/renderer/browser_impl.h b/libcef/renderer/browser_impl.h
new file mode 100644
index 00000000..0733bd40
--- /dev/null
+++ b/libcef/renderer/browser_impl.h
@@ -0,0 +1,134 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors.
+// Portions copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_RENDERER_BROWSER_IMPL_H_
+#define CEF_LIBCEF_RENDERER_BROWSER_IMPL_H_
+#pragma once
+
+#include <stdint.h>
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "include/cef_browser.h"
+#include "include/cef_client.h"
+#include "libcef/common/tracker.h"
+#include "libcef/renderer/frame_impl.h"
+
+#include "third_party/blink/public/web/web_view_observer.h"
+
+namespace blink {
+class WebFrame;
+class WebNode;
+class WebView;
+} // namespace blink
+
+// Renderer plumbing for CEF features. There is a one-to-one relationship
+// between RenderView on the renderer side and RenderViewHost on the browser
+// side.
+//
+// RenderViewObserver: Interface for observing RenderView notifications.
+class CefBrowserImpl : public CefBrowser, public blink::WebViewObserver {
+ public:
+ // Returns the browser associated with the specified RenderView.
+ static CefRefPtr<CefBrowserImpl> GetBrowserForView(blink::WebView* view);
+ // Returns the browser associated with the specified main WebFrame.
+ static CefRefPtr<CefBrowserImpl> GetBrowserForMainFrame(
+ blink::WebFrame* frame);
+
+ // CefBrowser methods.
+ bool IsValid() override;
+ CefRefPtr<CefBrowserHost> GetHost() override;
+ bool CanGoBack() override;
+ void GoBack() override;
+ bool CanGoForward() override;
+ void GoForward() override;
+ bool IsLoading() override;
+ void Reload() override;
+ void ReloadIgnoreCache() override;
+ void StopLoad() override;
+ int GetIdentifier() override;
+ bool IsSame(CefRefPtr<CefBrowser> that) override;
+ bool IsPopup() override;
+ bool HasDocument() override;
+ CefRefPtr<CefFrame> GetMainFrame() override;
+ CefRefPtr<CefFrame> GetFocusedFrame() override;
+ CefRefPtr<CefFrame> GetFrame(int64 identifier) override;
+ CefRefPtr<CefFrame> GetFrame(const CefString& name) override;
+ size_t GetFrameCount() override;
+ void GetFrameIdentifiers(std::vector<int64>& identifiers) override;
+ void GetFrameNames(std::vector<CefString>& names) override;
+
+ CefBrowserImpl(blink::WebView* web_view,
+ int browser_id,
+ bool is_popup,
+ bool is_windowless);
+
+ CefBrowserImpl(const CefBrowserImpl&) = delete;
+ CefBrowserImpl& operator=(const CefBrowserImpl&) = delete;
+
+ ~CefBrowserImpl() override;
+
+ // Returns the matching CefFrameImpl reference or creates a new one.
+ CefRefPtr<CefFrameImpl> GetWebFrameImpl(blink::WebLocalFrame* frame);
+ CefRefPtr<CefFrameImpl> GetWebFrameImpl(int64_t frame_id);
+
+ // Frame objects will be deleted immediately before the frame is closed.
+ void AddFrameObject(int64_t frame_id, CefTrackNode* tracked_object);
+
+ int browser_id() const { return browser_id_; }
+ bool is_popup() const { return is_popup_; }
+ bool is_windowless() const { return is_windowless_; }
+
+ // blink::WebViewObserver methods.
+ void OnDestruct() override;
+ void FrameDetached(int64_t frame_id);
+
+ void OnLoadingStateChange(bool isLoading);
+ void OnEnterBFCache();
+
+ private:
+ // ID of the browser that this RenderView is associated with. During loading
+ // of cross-origin requests multiple RenderViews may be associated with the
+ // same browser ID.
+ int browser_id_;
+ bool is_popup_;
+ bool is_windowless_;
+
+ // Map of unique frame ids to CefFrameImpl references.
+ using FrameMap = std::map<int64, CefRefPtr<CefFrameImpl>>;
+ FrameMap frames_;
+
+ // True if the browser was in the BFCache.
+ bool was_in_bfcache_ = false;
+
+ // Map of unique frame ids to CefTrackManager objects that need to be cleaned
+ // up when the frame is deleted.
+ using FrameObjectMap = std::map<int64, CefRefPtr<CefTrackManager>>;
+ FrameObjectMap frame_objects_;
+
+ struct LoadingState {
+ LoadingState(bool is_loading, bool can_go_back, bool can_go_forward)
+ : is_loading_(is_loading),
+ can_go_back_(can_go_back),
+ can_go_forward_(can_go_forward) {}
+
+ bool IsMatch(bool is_loading, bool can_go_back, bool can_go_forward) const {
+ return is_loading_ == is_loading && can_go_back_ == can_go_back &&
+ can_go_forward_ == can_go_forward;
+ }
+
+ bool is_loading_;
+ bool can_go_back_;
+ bool can_go_forward_;
+ };
+ std::unique_ptr<LoadingState> last_loading_state_;
+
+ IMPLEMENT_REFCOUNTING(CefBrowserImpl);
+};
+
+#endif // CEF_LIBCEF_RENDERER_BROWSER_IMPL_H_
diff --git a/libcef/renderer/chrome/chrome_content_renderer_client_cef.cc b/libcef/renderer/chrome/chrome_content_renderer_client_cef.cc
new file mode 100644
index 00000000..5d234267
--- /dev/null
+++ b/libcef/renderer/chrome/chrome_content_renderer_client_cef.cc
@@ -0,0 +1,103 @@
+// Copyright 2020 The Chromium Embedded Framework Authors.
+// Portions copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/renderer/chrome/chrome_content_renderer_client_cef.h"
+
+#include "libcef/renderer/render_frame_observer.h"
+#include "libcef/renderer/render_manager.h"
+#include "libcef/renderer/thread_util.h"
+
+#include "content/public/renderer/render_thread.h"
+
+ChromeContentRendererClientCef::ChromeContentRendererClientCef()
+ : render_manager_(new CefRenderManager) {}
+
+ChromeContentRendererClientCef::~ChromeContentRendererClientCef() = default;
+
+scoped_refptr<base::SingleThreadTaskRunner>
+ChromeContentRendererClientCef::GetCurrentTaskRunner() {
+ // Check if currently on the render thread.
+ if (CEF_CURRENTLY_ON_RT()) {
+ return render_task_runner_;
+ }
+ return nullptr;
+}
+
+void ChromeContentRendererClientCef::RenderThreadStarted() {
+ ChromeContentRendererClient::RenderThreadStarted();
+
+ render_task_runner_ = base::SingleThreadTaskRunner::GetCurrentDefault();
+}
+
+void ChromeContentRendererClientCef::RenderThreadConnected() {
+ ChromeContentRendererClient::RenderThreadConnected();
+
+ render_manager_->RenderThreadConnected();
+}
+
+void ChromeContentRendererClientCef::RenderFrameCreated(
+ content::RenderFrame* render_frame) {
+ ChromeContentRendererClient::RenderFrameCreated(render_frame);
+
+ // Will delete itself when no longer needed.
+ CefRenderFrameObserver* render_frame_observer =
+ new CefRenderFrameObserver(render_frame);
+
+ bool browser_created;
+ absl::optional<bool> is_windowless;
+ render_manager_->RenderFrameCreated(render_frame, render_frame_observer,
+ browser_created, is_windowless);
+ if (is_windowless.has_value() && *is_windowless) {
+ LOG(ERROR) << "The chrome runtime does not support windowless browsers";
+ }
+}
+
+void ChromeContentRendererClientCef::WebViewCreated(
+ blink::WebView* web_view,
+ bool was_created_by_renderer,
+ const url::Origin* outermost_origin) {
+ ChromeContentRendererClient::WebViewCreated(web_view, was_created_by_renderer,
+ outermost_origin);
+
+ bool browser_created;
+ absl::optional<bool> is_windowless;
+ render_manager_->WebViewCreated(web_view, browser_created, is_windowless);
+ if (is_windowless.has_value() && *is_windowless) {
+ LOG(ERROR) << "The chrome runtime does not support windowless browsers";
+ }
+}
+
+void ChromeContentRendererClientCef::DevToolsAgentAttached() {
+ // WebWorkers may be creating agents on a different thread.
+ if (!render_task_runner_->BelongsToCurrentThread()) {
+ render_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(&ChromeContentRendererClientCef::DevToolsAgentAttached,
+ base::Unretained(this)));
+ return;
+ }
+
+ render_manager_->DevToolsAgentAttached();
+}
+
+void ChromeContentRendererClientCef::DevToolsAgentDetached() {
+ // WebWorkers may be creating agents on a different thread.
+ if (!render_task_runner_->BelongsToCurrentThread()) {
+ render_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(&ChromeContentRendererClientCef::DevToolsAgentDetached,
+ base::Unretained(this)));
+ return;
+ }
+
+ render_manager_->DevToolsAgentDetached();
+}
+
+void ChromeContentRendererClientCef::ExposeInterfacesToBrowser(
+ mojo::BinderMap* binders) {
+ ChromeContentRendererClient::ExposeInterfacesToBrowser(binders);
+
+ render_manager_->ExposeInterfacesToBrowser(binders);
+} \ No newline at end of file
diff --git a/libcef/renderer/chrome/chrome_content_renderer_client_cef.h b/libcef/renderer/chrome/chrome_content_renderer_client_cef.h
new file mode 100644
index 00000000..09e4951a
--- /dev/null
+++ b/libcef/renderer/chrome/chrome_content_renderer_client_cef.h
@@ -0,0 +1,55 @@
+// Copyright 2020 The Chromium Embedded Framework Authors.
+// Portions copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_RENDERER_CHROME_CHROME_CONTENT_RENDERER_CLIENT_CEF_
+#define CEF_LIBCEF_RENDERER_CHROME_CHROME_CONTENT_RENDERER_CLIENT_CEF_
+
+#include <memory>
+
+#include "base/memory/scoped_refptr.h"
+#include "base/task/single_thread_task_runner.h"
+#include "chrome/renderer/chrome_content_renderer_client.h"
+
+class CefRenderManager;
+
+// CEF override of ChromeContentRendererClient.
+class ChromeContentRendererClientCef : public ChromeContentRendererClient {
+ public:
+ ChromeContentRendererClientCef();
+
+ ChromeContentRendererClientCef(const ChromeContentRendererClientCef&) =
+ delete;
+ ChromeContentRendererClientCef& operator=(
+ const ChromeContentRendererClientCef&) = delete;
+
+ ~ChromeContentRendererClientCef() override;
+
+ // Render thread task runner.
+ base::SingleThreadTaskRunner* render_task_runner() const {
+ return render_task_runner_.get();
+ }
+
+ // Returns the task runner for the current thread. Returns NULL if the current
+ // thread is not the main render process thread.
+ scoped_refptr<base::SingleThreadTaskRunner> GetCurrentTaskRunner();
+
+ // ChromeContentRendererClient overrides.
+ void RenderThreadStarted() override;
+ void RenderThreadConnected() override;
+ void RenderFrameCreated(content::RenderFrame* render_frame) override;
+ void WebViewCreated(blink::WebView* web_view,
+ bool was_created_by_renderer,
+ const url::Origin* outermost_origin) override;
+ void DevToolsAgentAttached() override;
+ void DevToolsAgentDetached() override;
+ void ExposeInterfacesToBrowser(mojo::BinderMap* binders) override;
+
+ private:
+ std::unique_ptr<CefRenderManager> render_manager_;
+
+ scoped_refptr<base::SingleThreadTaskRunner> render_task_runner_;
+};
+
+#endif // CEF_LIBCEF_RENDERER_CHROME_CHROME_CONTENT_RENDERER_CLIENT_CEF_
diff --git a/libcef/renderer/dom_document_impl.cc b/libcef/renderer/dom_document_impl.cc
new file mode 100644
index 00000000..223462da
--- /dev/null
+++ b/libcef/renderer/dom_document_impl.cc
@@ -0,0 +1,278 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "libcef/renderer/dom_document_impl.h"
+#include "libcef/renderer/dom_node_impl.h"
+#include "libcef/renderer/thread_util.h"
+
+#include "base/logging.h"
+#include "third_party/blink/public/platform/web_string.h"
+#include "third_party/blink/public/platform/web_url.h"
+#include "third_party/blink/public/web/web_document.h"
+#include "third_party/blink/public/web/web_element.h"
+#include "third_party/blink/public/web/web_local_frame.h"
+#include "third_party/blink/public/web/web_node.h"
+#include "third_party/blink/public/web/web_range.h"
+
+using blink::WebDocument;
+using blink::WebElement;
+using blink::WebLocalFrame;
+using blink::WebNode;
+using blink::WebRange;
+using blink::WebString;
+using blink::WebURL;
+
+CefDOMDocumentImpl::CefDOMDocumentImpl(CefBrowserImpl* browser,
+ WebLocalFrame* frame)
+ : browser_(browser), frame_(frame) {
+ const WebDocument& document = frame_->GetDocument();
+ DCHECK(!document.IsNull());
+}
+
+CefDOMDocumentImpl::~CefDOMDocumentImpl() {
+ CEF_REQUIRE_RT();
+
+ // Verify that the Detach() method has been called.
+ DCHECK(frame_ == nullptr);
+}
+
+CefDOMDocumentImpl::Type CefDOMDocumentImpl::GetType() {
+ if (!VerifyContext()) {
+ return DOM_DOCUMENT_TYPE_UNKNOWN;
+ }
+
+ const WebDocument& document = frame_->GetDocument();
+ if (document.IsHTMLDocument()) {
+ return DOM_DOCUMENT_TYPE_HTML;
+ }
+ if (document.IsXHTMLDocument()) {
+ return DOM_DOCUMENT_TYPE_XHTML;
+ }
+ if (document.IsPluginDocument()) {
+ return DOM_DOCUMENT_TYPE_PLUGIN;
+ }
+ return DOM_DOCUMENT_TYPE_UNKNOWN;
+}
+
+CefRefPtr<CefDOMNode> CefDOMDocumentImpl::GetDocument() {
+ const WebDocument& document = frame_->GetDocument();
+ return GetOrCreateNode(document.GetDocument());
+}
+
+CefRefPtr<CefDOMNode> CefDOMDocumentImpl::GetBody() {
+ const WebDocument& document = frame_->GetDocument();
+ return GetOrCreateNode(document.Body());
+}
+
+CefRefPtr<CefDOMNode> CefDOMDocumentImpl::GetHead() {
+ WebDocument document = frame_->GetDocument();
+ return GetOrCreateNode(document.Head());
+}
+
+CefString CefDOMDocumentImpl::GetTitle() {
+ CefString str;
+ if (!VerifyContext()) {
+ return str;
+ }
+
+ const WebDocument& document = frame_->GetDocument();
+ const WebString& title = document.Title();
+ if (!title.IsNull()) {
+ str = title.Utf16();
+ }
+
+ return str;
+}
+
+CefRefPtr<CefDOMNode> CefDOMDocumentImpl::GetElementById(const CefString& id) {
+ const WebDocument& document = frame_->GetDocument();
+ return GetOrCreateNode(
+ document.GetElementById(WebString::FromUTF16(id.ToString16())));
+}
+
+CefRefPtr<CefDOMNode> CefDOMDocumentImpl::GetFocusedNode() {
+ const WebDocument& document = frame_->GetDocument();
+ return GetOrCreateNode(document.FocusedElement());
+}
+
+bool CefDOMDocumentImpl::HasSelection() {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ return frame_->HasSelection();
+}
+
+int CefDOMDocumentImpl::GetSelectionStartOffset() {
+ if (!VerifyContext()) {
+ return 0;
+ }
+
+ if (!frame_->HasSelection()) {
+ return 0;
+ }
+
+ const WebRange& range = frame_->SelectionRange();
+ if (range.IsNull()) {
+ return 0;
+ }
+
+ return range.StartOffset();
+}
+
+int CefDOMDocumentImpl::GetSelectionEndOffset() {
+ if (!VerifyContext()) {
+ return 0;
+ }
+
+ if (!frame_->HasSelection()) {
+ return 0;
+ }
+
+ const WebRange& range = frame_->SelectionRange();
+ if (range.IsNull()) {
+ return 0;
+ }
+
+ return range.EndOffset();
+}
+
+CefString CefDOMDocumentImpl::GetSelectionAsMarkup() {
+ CefString str;
+ if (!VerifyContext()) {
+ return str;
+ }
+
+ if (!frame_->HasSelection()) {
+ return str;
+ }
+
+ const WebString& markup = frame_->SelectionAsMarkup();
+ if (!markup.IsNull()) {
+ str = markup.Utf16();
+ }
+
+ return str;
+}
+
+CefString CefDOMDocumentImpl::GetSelectionAsText() {
+ CefString str;
+ if (!VerifyContext()) {
+ return str;
+ }
+
+ if (!frame_->HasSelection()) {
+ return str;
+ }
+
+ const WebString& text = frame_->SelectionAsText();
+ if (!text.IsNull()) {
+ str = text.Utf16();
+ }
+
+ return str;
+}
+
+CefString CefDOMDocumentImpl::GetBaseURL() {
+ CefString str;
+ if (!VerifyContext()) {
+ return str;
+ }
+
+ const WebDocument& document = frame_->GetDocument();
+ const WebURL& url = document.BaseURL();
+ if (!url.IsNull()) {
+ GURL gurl = url;
+ str = gurl.spec();
+ }
+
+ return str;
+}
+
+CefString CefDOMDocumentImpl::GetCompleteURL(const CefString& partialURL) {
+ CefString str;
+ if (!VerifyContext()) {
+ return str;
+ }
+
+ const WebDocument& document = frame_->GetDocument();
+ const WebURL& url =
+ document.CompleteURL(WebString::FromUTF16(partialURL.ToString16()));
+ if (!url.IsNull()) {
+ GURL gurl = url;
+ str = gurl.spec();
+ }
+
+ return str;
+}
+
+CefRefPtr<CefDOMNode> CefDOMDocumentImpl::GetOrCreateNode(
+ const blink::WebNode& node) {
+ if (!VerifyContext()) {
+ return nullptr;
+ }
+
+ // Nodes may potentially be null.
+ if (node.IsNull()) {
+ return nullptr;
+ }
+
+ if (!node_map_.empty()) {
+ // Locate the existing node, if any.
+ NodeMap::const_iterator it = node_map_.find(node);
+ if (it != node_map_.end()) {
+ return it->second;
+ }
+ }
+
+ // Create the new node object.
+ CefRefPtr<CefDOMNode> nodeImpl(new CefDOMNodeImpl(this, node));
+ node_map_.insert(std::make_pair(node, nodeImpl.get()));
+ return nodeImpl;
+}
+
+void CefDOMDocumentImpl::RemoveNode(const blink::WebNode& node) {
+ if (!VerifyContext()) {
+ return;
+ }
+
+ if (!node_map_.empty()) {
+ NodeMap::iterator it = node_map_.find(node);
+ if (it != node_map_.end()) {
+ node_map_.erase(it);
+ }
+ }
+}
+
+void CefDOMDocumentImpl::Detach() {
+ if (!VerifyContext()) {
+ return;
+ }
+
+ // If you hit this assert it means that you are keeping references to node
+ // objects beyond the valid scope.
+ DCHECK(node_map_.empty());
+
+ // If you hit this assert it means that you are keeping references to this
+ // document object beyond the valid scope.
+ DCHECK(HasOneRef());
+
+ if (!node_map_.empty()) {
+ NodeMap::const_iterator it = node_map_.begin();
+ for (; it != node_map_.end(); ++it) {
+ static_cast<CefDOMNodeImpl*>(it->second)->Detach();
+ }
+ node_map_.clear();
+ }
+
+ frame_ = nullptr;
+}
+
+bool CefDOMDocumentImpl::VerifyContext() {
+ if (!CEF_CURRENTLY_ON_RT() || frame_ == nullptr) {
+ NOTREACHED();
+ return false;
+ }
+ return true;
+}
diff --git a/libcef/renderer/dom_document_impl.h b/libcef/renderer/dom_document_impl.h
new file mode 100644
index 00000000..87d87016
--- /dev/null
+++ b/libcef/renderer/dom_document_impl.h
@@ -0,0 +1,63 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_DOM_DOCUMENT_IMPL_H_
+#define CEF_LIBCEF_DOM_DOCUMENT_IMPL_H_
+#pragma once
+
+#include <map>
+#include "include/cef_dom.h"
+
+namespace blink {
+class WebLocalFrame;
+class WebNode;
+} // namespace blink
+
+class CefBrowserImpl;
+
+class CefDOMDocumentImpl : public CefDOMDocument {
+ public:
+ CefDOMDocumentImpl(CefBrowserImpl* browser, blink::WebLocalFrame* frame);
+ ~CefDOMDocumentImpl() override;
+
+ // CefDOMDocument methods.
+ Type GetType() override;
+ CefRefPtr<CefDOMNode> GetDocument() override;
+ CefRefPtr<CefDOMNode> GetBody() override;
+ CefRefPtr<CefDOMNode> GetHead() override;
+ CefString GetTitle() override;
+ CefRefPtr<CefDOMNode> GetElementById(const CefString& id) override;
+ CefRefPtr<CefDOMNode> GetFocusedNode() override;
+ bool HasSelection() override;
+ int GetSelectionStartOffset() override;
+ int GetSelectionEndOffset() override;
+ CefString GetSelectionAsMarkup() override;
+ CefString GetSelectionAsText() override;
+ CefString GetBaseURL() override;
+ CefString GetCompleteURL(const CefString& partialURL) override;
+
+ CefBrowserImpl* GetBrowser() { return browser_; }
+ blink::WebLocalFrame* GetFrame() { return frame_; }
+
+ // The document maintains a map of all existing node objects.
+ CefRefPtr<CefDOMNode> GetOrCreateNode(const blink::WebNode& node);
+ void RemoveNode(const blink::WebNode& node);
+
+ // Must be called before the object is destroyed.
+ void Detach();
+
+ // Verify that the object exists and is being accessed on the UI thread.
+ bool VerifyContext();
+
+ protected:
+ CefBrowserImpl* browser_;
+ blink::WebLocalFrame* frame_;
+
+ using NodeMap = std::map<blink::WebNode, CefDOMNode*>;
+ NodeMap node_map_;
+
+ IMPLEMENT_REFCOUNTING(CefDOMDocumentImpl);
+};
+
+#endif // CEF_LIBCEF_DOM_DOCUMENT_IMPL_H_
diff --git a/libcef/renderer/dom_node_impl.cc b/libcef/renderer/dom_node_impl.cc
new file mode 100644
index 00000000..8ae90c08
--- /dev/null
+++ b/libcef/renderer/dom_node_impl.cc
@@ -0,0 +1,454 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "libcef/renderer/dom_node_impl.h"
+
+#include "libcef/common/tracker.h"
+#include "libcef/renderer/blink_glue.h"
+#include "libcef/renderer/browser_impl.h"
+#include "libcef/renderer/dom_document_impl.h"
+#include "libcef/renderer/thread_util.h"
+
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "third_party/blink/public/platform/web_string.h"
+#include "third_party/blink/public/web/web_document.h"
+#include "third_party/blink/public/web/web_dom_event.h"
+#include "third_party/blink/public/web/web_element.h"
+#include "third_party/blink/public/web/web_form_control_element.h"
+#include "third_party/blink/public/web/web_input_element.h"
+#include "third_party/blink/public/web/web_node.h"
+#include "third_party/blink/public/web/web_select_element.h"
+
+using blink::WebDocument;
+using blink::WebDOMEvent;
+using blink::WebElement;
+using blink::WebFormControlElement;
+using blink::WebInputElement;
+using blink::WebNode;
+using blink::WebSelectElement;
+using blink::WebString;
+
+CefDOMNodeImpl::CefDOMNodeImpl(CefRefPtr<CefDOMDocumentImpl> document,
+ const blink::WebNode& node)
+ : document_(document), node_(node) {}
+
+CefDOMNodeImpl::~CefDOMNodeImpl() {
+ CEF_REQUIRE_RT();
+
+ if (document_.get() && !node_.IsNull()) {
+ // Remove the node from the document.
+ document_->RemoveNode(node_);
+ }
+}
+
+CefDOMNodeImpl::Type CefDOMNodeImpl::GetType() {
+ if (!VerifyContext()) {
+ return DOM_NODE_TYPE_UNSUPPORTED;
+ }
+
+ return blink_glue::GetNodeType(node_);
+}
+
+bool CefDOMNodeImpl::IsText() {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ return node_.IsTextNode();
+}
+
+bool CefDOMNodeImpl::IsElement() {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ return node_.IsElementNode();
+}
+
+// Logic copied from RenderViewImpl::IsEditableNode.
+bool CefDOMNodeImpl::IsEditable() {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ if (node_.IsContentEditable()) {
+ return true;
+ }
+
+ if (node_.IsElementNode()) {
+ const WebElement& element = node_.To<WebElement>();
+ if (blink_glue::IsTextControlElement(element)) {
+ return true;
+ }
+
+ // Also return true if it has an ARIA role of 'textbox'.
+ for (unsigned i = 0; i < element.AttributeCount(); ++i) {
+ if (base::EqualsCaseInsensitiveASCII(element.AttributeLocalName(i).Utf8(),
+ "role")) {
+ if (base::EqualsCaseInsensitiveASCII(element.AttributeValue(i).Utf8(),
+ "textbox")) {
+ return true;
+ }
+ break;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool CefDOMNodeImpl::IsFormControlElement() {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ if (node_.IsElementNode()) {
+ const WebElement& element = node_.To<WebElement>();
+ return element.IsFormControlElement();
+ }
+
+ return false;
+}
+
+CefString CefDOMNodeImpl::GetFormControlElementType() {
+ CefString str;
+ if (!VerifyContext()) {
+ return str;
+ }
+
+ if (node_.IsElementNode()) {
+ const WebElement& element = node_.To<WebElement>();
+ if (element.IsFormControlElement()) {
+ // Retrieve the type from the form control element.
+ const WebFormControlElement& formElement =
+ node_.To<WebFormControlElement>();
+
+ const std::u16string& form_control_type =
+ formElement.FormControlType().Utf16();
+ str = form_control_type;
+ }
+ }
+
+ return str;
+}
+
+bool CefDOMNodeImpl::IsSame(CefRefPtr<CefDOMNode> that) {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ CefDOMNodeImpl* impl = static_cast<CefDOMNodeImpl*>(that.get());
+ if (!impl || !impl->VerifyContext()) {
+ return false;
+ }
+
+ return node_.Equals(impl->node_);
+}
+
+CefString CefDOMNodeImpl::GetName() {
+ CefString str;
+ if (!VerifyContext()) {
+ return str;
+ }
+
+ const WebString& name = blink_glue::GetNodeName(node_);
+ if (!name.IsNull()) {
+ str = name.Utf16();
+ }
+
+ return str;
+}
+
+CefString CefDOMNodeImpl::GetValue() {
+ CefString str;
+ if (!VerifyContext()) {
+ return str;
+ }
+
+ if (node_.IsElementNode()) {
+ const WebElement& element = node_.To<WebElement>();
+ if (element.IsFormControlElement()) {
+ // Retrieve the value from the form control element.
+ const WebFormControlElement& formElement =
+ node_.To<WebFormControlElement>();
+
+ std::u16string value;
+ const std::u16string& form_control_type =
+ formElement.FormControlType().Utf16();
+ if (form_control_type == u"text") {
+ const WebInputElement& input_element =
+ formElement.To<WebInputElement>();
+ value = input_element.Value().Utf16();
+ } else if (form_control_type == u"select-one") {
+ const WebSelectElement& select_element =
+ formElement.To<WebSelectElement>();
+ value = select_element.Value().Utf16();
+ }
+
+ base::TrimWhitespace(value, base::TRIM_LEADING, &value);
+ str = value;
+ }
+ }
+
+ if (str.empty()) {
+ const WebString& value = node_.NodeValue();
+ if (!value.IsNull()) {
+ str = value.Utf16();
+ }
+ }
+
+ return str;
+}
+
+bool CefDOMNodeImpl::SetValue(const CefString& value) {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ if (node_.IsElementNode()) {
+ return false;
+ }
+
+ return blink_glue::SetNodeValue(node_,
+ WebString::FromUTF16(value.ToString16()));
+}
+
+CefString CefDOMNodeImpl::GetAsMarkup() {
+ CefString str;
+ if (!VerifyContext()) {
+ return str;
+ }
+
+ const WebString& markup = blink_glue::CreateNodeMarkup(node_);
+ if (!markup.IsNull()) {
+ str = markup.Utf16();
+ }
+
+ return str;
+}
+
+CefRefPtr<CefDOMDocument> CefDOMNodeImpl::GetDocument() {
+ if (!VerifyContext()) {
+ return nullptr;
+ }
+
+ return document_.get();
+}
+
+CefRefPtr<CefDOMNode> CefDOMNodeImpl::GetParent() {
+ if (!VerifyContext()) {
+ return nullptr;
+ }
+
+ return document_->GetOrCreateNode(node_.ParentNode());
+}
+
+CefRefPtr<CefDOMNode> CefDOMNodeImpl::GetPreviousSibling() {
+ if (!VerifyContext()) {
+ return nullptr;
+ }
+
+ return document_->GetOrCreateNode(node_.PreviousSibling());
+}
+
+CefRefPtr<CefDOMNode> CefDOMNodeImpl::GetNextSibling() {
+ if (!VerifyContext()) {
+ return nullptr;
+ }
+
+ return document_->GetOrCreateNode(node_.NextSibling());
+}
+
+bool CefDOMNodeImpl::HasChildren() {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ return !node_.FirstChild().IsNull();
+}
+
+CefRefPtr<CefDOMNode> CefDOMNodeImpl::GetFirstChild() {
+ if (!VerifyContext()) {
+ return nullptr;
+ }
+
+ return document_->GetOrCreateNode(node_.FirstChild());
+}
+
+CefRefPtr<CefDOMNode> CefDOMNodeImpl::GetLastChild() {
+ if (!VerifyContext()) {
+ return nullptr;
+ }
+
+ return document_->GetOrCreateNode(node_.LastChild());
+}
+
+CefString CefDOMNodeImpl::GetElementTagName() {
+ CefString str;
+ if (!VerifyContext()) {
+ return str;
+ }
+
+ if (!node_.IsElementNode()) {
+ NOTREACHED();
+ return str;
+ }
+
+ const WebElement& element = node_.To<blink::WebElement>();
+ const WebString& tagname = element.TagName();
+ if (!tagname.IsNull()) {
+ str = tagname.Utf16();
+ }
+
+ return str;
+}
+
+bool CefDOMNodeImpl::HasElementAttributes() {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ if (!node_.IsElementNode()) {
+ NOTREACHED();
+ return false;
+ }
+
+ const WebElement& element = node_.To<blink::WebElement>();
+ return (element.AttributeCount() > 0);
+}
+
+bool CefDOMNodeImpl::HasElementAttribute(const CefString& attrName) {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ if (!node_.IsElementNode()) {
+ NOTREACHED();
+ return false;
+ }
+
+ const WebElement& element = node_.To<blink::WebElement>();
+ return element.HasAttribute(WebString::FromUTF16(attrName.ToString16()));
+}
+
+CefString CefDOMNodeImpl::GetElementAttribute(const CefString& attrName) {
+ CefString str;
+ if (!VerifyContext()) {
+ return str;
+ }
+
+ if (!node_.IsElementNode()) {
+ NOTREACHED();
+ return str;
+ }
+
+ const WebElement& element = node_.To<blink::WebElement>();
+ const WebString& attr =
+ element.GetAttribute(WebString::FromUTF16(attrName.ToString16()));
+ if (!attr.IsNull()) {
+ str = attr.Utf16();
+ }
+
+ return str;
+}
+
+void CefDOMNodeImpl::GetElementAttributes(AttributeMap& attrMap) {
+ if (!VerifyContext()) {
+ return;
+ }
+
+ if (!node_.IsElementNode()) {
+ NOTREACHED();
+ return;
+ }
+
+ const WebElement& element = node_.To<blink::WebElement>();
+ unsigned int len = element.AttributeCount();
+ if (len == 0) {
+ return;
+ }
+
+ for (unsigned int i = 0; i < len; ++i) {
+ std::u16string name = element.AttributeLocalName(i).Utf16();
+ std::u16string value = element.AttributeValue(i).Utf16();
+ attrMap.insert(std::make_pair(name, value));
+ }
+}
+
+bool CefDOMNodeImpl::SetElementAttribute(const CefString& attrName,
+ const CefString& value) {
+ if (!VerifyContext()) {
+ return false;
+ }
+
+ if (!node_.IsElementNode()) {
+ NOTREACHED();
+ return false;
+ }
+
+ WebElement element = node_.To<blink::WebElement>();
+ element.SetAttribute(WebString::FromUTF16(attrName.ToString16()),
+ WebString::FromUTF16(value.ToString16()));
+ return true;
+}
+
+CefString CefDOMNodeImpl::GetElementInnerText() {
+ CefString str;
+ if (!VerifyContext()) {
+ return str;
+ }
+
+ if (!node_.IsElementNode()) {
+ NOTREACHED();
+ return str;
+ }
+
+ WebElement element = node_.To<blink::WebElement>();
+ const WebString& text = element.TextContent();
+ if (!text.IsNull()) {
+ str = text.Utf16();
+ }
+
+ return str;
+}
+
+CefRect CefDOMNodeImpl::GetElementBounds() {
+ CefRect rect;
+ if (!VerifyContext()) {
+ return rect;
+ }
+
+ if (!node_.IsElementNode()) {
+ NOTREACHED();
+ return rect;
+ }
+
+ WebElement element = node_.To<blink::WebElement>();
+ const auto& rc = element.BoundsInWidget();
+ rect.Set(rc.x(), rc.y(), rc.width(), rc.height());
+
+ return rect;
+}
+
+void CefDOMNodeImpl::Detach() {
+ document_ = nullptr;
+ node_.Assign(WebNode());
+}
+
+bool CefDOMNodeImpl::VerifyContext() {
+ if (!document_.get()) {
+ NOTREACHED();
+ return false;
+ }
+ if (!document_->VerifyContext()) {
+ return false;
+ }
+ if (node_.IsNull()) {
+ NOTREACHED();
+ return false;
+ }
+ return true;
+}
diff --git a/libcef/renderer/dom_node_impl.h b/libcef/renderer/dom_node_impl.h
new file mode 100644
index 00000000..e7364776
--- /dev/null
+++ b/libcef/renderer/dom_node_impl.h
@@ -0,0 +1,62 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_DOM_NODE_IMPL_H_
+#define CEF_LIBCEF_DOM_NODE_IMPL_H_
+#pragma once
+
+#include "include/cef_dom.h"
+#include "third_party/blink/public/web/web_node.h"
+
+class CefDOMDocumentImpl;
+
+class CefDOMNodeImpl : public CefDOMNode {
+ public:
+ CefDOMNodeImpl(CefRefPtr<CefDOMDocumentImpl> document,
+ const blink::WebNode& node);
+ ~CefDOMNodeImpl() override;
+
+ // CefDOMNode methods.
+ Type GetType() override;
+ bool IsText() override;
+ bool IsElement() override;
+ bool IsEditable() override;
+ bool IsFormControlElement() override;
+ CefString GetFormControlElementType() override;
+ bool IsSame(CefRefPtr<CefDOMNode> that) override;
+ CefString GetName() override;
+ CefString GetValue() override;
+ bool SetValue(const CefString& value) override;
+ CefString GetAsMarkup() override;
+ CefRefPtr<CefDOMDocument> GetDocument() override;
+ CefRefPtr<CefDOMNode> GetParent() override;
+ CefRefPtr<CefDOMNode> GetPreviousSibling() override;
+ CefRefPtr<CefDOMNode> GetNextSibling() override;
+ bool HasChildren() override;
+ CefRefPtr<CefDOMNode> GetFirstChild() override;
+ CefRefPtr<CefDOMNode> GetLastChild() override;
+ CefString GetElementTagName() override;
+ bool HasElementAttributes() override;
+ bool HasElementAttribute(const CefString& attrName) override;
+ CefString GetElementAttribute(const CefString& attrName) override;
+ void GetElementAttributes(AttributeMap& attrMap) override;
+ bool SetElementAttribute(const CefString& attrName,
+ const CefString& value) override;
+ CefString GetElementInnerText() override;
+ CefRect GetElementBounds() override;
+
+ // Will be called from CefDOMDocumentImpl::Detach().
+ void Detach();
+
+ // Verify that the object exists and is being accessed on the UI thread.
+ bool VerifyContext();
+
+ protected:
+ CefRefPtr<CefDOMDocumentImpl> document_;
+ blink::WebNode node_;
+
+ IMPLEMENT_REFCOUNTING(CefDOMNodeImpl);
+};
+
+#endif // CEF_LIBCEF_DOM_NODE_IMPL_H_
diff --git a/libcef/renderer/extensions/extensions_dispatcher_delegate.cc b/libcef/renderer/extensions/extensions_dispatcher_delegate.cc
new file mode 100644
index 00000000..51d3751e
--- /dev/null
+++ b/libcef/renderer/extensions/extensions_dispatcher_delegate.cc
@@ -0,0 +1,21 @@
+// Copyright 2015 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/renderer/extensions/extensions_dispatcher_delegate.h"
+
+#include "base/feature_list.h"
+#include "chrome/grit/renderer_resources.h"
+#include "extensions/common/extension_features.h"
+#include "extensions/renderer/resource_bundle_source_map.h"
+
+namespace extensions {
+
+CefExtensionsDispatcherDelegate::CefExtensionsDispatcherDelegate() {}
+
+CefExtensionsDispatcherDelegate::~CefExtensionsDispatcherDelegate() {}
+
+void CefExtensionsDispatcherDelegate::PopulateSourceMap(
+ extensions::ResourceBundleSourceMap* source_map) {}
+
+} // namespace extensions
diff --git a/libcef/renderer/extensions/extensions_dispatcher_delegate.h b/libcef/renderer/extensions/extensions_dispatcher_delegate.h
new file mode 100644
index 00000000..5ccebb6d
--- /dev/null
+++ b/libcef/renderer/extensions/extensions_dispatcher_delegate.h
@@ -0,0 +1,29 @@
+// Copyright 2015 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_RENDERER_EXTENSIONS_EXTENSIONS_DISPATCHER_DELEGATE_H_
+#define CEF_LIBCEF_RENDERER_EXTENSIONS_EXTENSIONS_DISPATCHER_DELEGATE_H_
+
+#include "extensions/renderer/dispatcher_delegate.h"
+
+namespace extensions {
+
+class CefExtensionsDispatcherDelegate : public DispatcherDelegate {
+ public:
+ CefExtensionsDispatcherDelegate();
+
+ CefExtensionsDispatcherDelegate(const CefExtensionsDispatcherDelegate&) =
+ delete;
+ CefExtensionsDispatcherDelegate& operator=(
+ const CefExtensionsDispatcherDelegate&) = delete;
+
+ ~CefExtensionsDispatcherDelegate() override;
+
+ void PopulateSourceMap(
+ extensions::ResourceBundleSourceMap* source_map) override;
+};
+
+} // namespace extensions
+
+#endif // CEF_LIBCEF_RENDERER_EXTENSIONS_EXTENSIONS_DISPATCHER_DELEGATE_H_
diff --git a/libcef/renderer/extensions/extensions_renderer_client.cc b/libcef/renderer/extensions/extensions_renderer_client.cc
new file mode 100644
index 00000000..a571d42d
--- /dev/null
+++ b/libcef/renderer/extensions/extensions_renderer_client.cc
@@ -0,0 +1,146 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/renderer/extensions/extensions_renderer_client.h"
+
+#include "libcef/renderer/alloy/alloy_render_thread_observer.h"
+#include "libcef/renderer/extensions/extensions_dispatcher_delegate.h"
+
+#include "base/stl_util.h"
+#include "base/types/optional_util.h"
+#include "chrome/common/url_constants.h"
+#include "chrome/renderer/extensions/resource_request_policy.h"
+#include "content/public/common/content_constants.h"
+#include "content/public/renderer/render_frame.h"
+#include "content/public/renderer/render_thread.h"
+#include "extensions/common/constants.h"
+#include "extensions/common/permissions/permissions_data.h"
+#include "extensions/renderer/dispatcher.h"
+#include "extensions/renderer/extension_frame_helper.h"
+#include "extensions/renderer/extensions_render_frame_observer.h"
+#include "extensions/renderer/renderer_extension_registry.h"
+#include "extensions/renderer/script_context.h"
+#include "third_party/blink/public/web/web_document.h"
+#include "third_party/blink/public/web/web_local_frame.h"
+#include "third_party/blink/public/web/web_plugin_params.h"
+
+namespace extensions {
+
+namespace {
+
+void IsGuestViewApiAvailableToScriptContext(
+ bool* api_is_available,
+ extensions::ScriptContext* context) {
+ if (context->GetAvailability("guestViewInternal").is_available()) {
+ *api_is_available = true;
+ }
+}
+
+} // namespace
+
+CefExtensionsRendererClient::CefExtensionsRendererClient() {}
+
+CefExtensionsRendererClient::~CefExtensionsRendererClient() {}
+
+bool CefExtensionsRendererClient::IsIncognitoProcess() const {
+ return AlloyRenderThreadObserver::is_incognito_process();
+}
+
+int CefExtensionsRendererClient::GetLowestIsolatedWorldId() const {
+ // CEF doesn't need to reserve world IDs for anything other than extensions,
+ // so we always return 1. Note that 0 is reserved for the global world.
+ return 1;
+}
+
+extensions::Dispatcher* CefExtensionsRendererClient::GetDispatcher() {
+ return extension_dispatcher_.get();
+}
+
+void CefExtensionsRendererClient::OnExtensionLoaded(
+ const extensions::Extension& extension) {
+ resource_request_policy_->OnExtensionLoaded(extension);
+}
+
+void CefExtensionsRendererClient::OnExtensionUnloaded(
+ const extensions::ExtensionId& extension_id) {
+ resource_request_policy_->OnExtensionUnloaded(extension_id);
+}
+
+bool CefExtensionsRendererClient::ExtensionAPIEnabledForServiceWorkerScript(
+ const GURL& scope,
+ const GURL& script_url) const {
+ // TODO(extensions): Implement to support background sevice worker scripts
+ // in extensions
+ return false;
+}
+
+void CefExtensionsRendererClient::RenderThreadStarted() {
+ content::RenderThread* thread = content::RenderThread::Get();
+
+ extension_dispatcher_ = std::make_unique<extensions::Dispatcher>(
+ std::make_unique<extensions::CefExtensionsDispatcherDelegate>());
+ extension_dispatcher_->OnRenderThreadStarted(thread);
+ resource_request_policy_ =
+ std::make_unique<extensions::ResourceRequestPolicy>(
+ extension_dispatcher_.get());
+
+ thread->AddObserver(extension_dispatcher_.get());
+}
+
+void CefExtensionsRendererClient::RenderFrameCreated(
+ content::RenderFrame* render_frame,
+ service_manager::BinderRegistry* registry) {
+ new extensions::ExtensionsRenderFrameObserver(render_frame, registry);
+ new extensions::ExtensionFrameHelper(render_frame,
+ extension_dispatcher_.get());
+ extension_dispatcher_->OnRenderFrameCreated(render_frame);
+}
+
+bool CefExtensionsRendererClient::OverrideCreatePlugin(
+ content::RenderFrame* render_frame,
+ const blink::WebPluginParams& params) {
+ if (params.mime_type.Utf8() != content::kBrowserPluginMimeType) {
+ return true;
+ }
+
+ bool guest_view_api_available = false;
+ extension_dispatcher_->script_context_set_iterator()->ForEach(
+ render_frame, base::BindRepeating(&IsGuestViewApiAvailableToScriptContext,
+ &guest_view_api_available));
+ return !guest_view_api_available;
+}
+
+void CefExtensionsRendererClient::WillSendRequest(
+ blink::WebLocalFrame* frame,
+ ui::PageTransition transition_type,
+ const blink::WebURL& url,
+ const net::SiteForCookies& site_for_cookies,
+ const url::Origin* initiator_origin,
+ GURL* new_url) {
+ // Check whether the request should be allowed. If not allowed, we reset the
+ // URL to something invalid to prevent the request and cause an error.
+ if (url.ProtocolIs(extensions::kExtensionScheme) &&
+ !resource_request_policy_->CanRequestResource(
+ GURL(url), frame, transition_type,
+ base::OptionalFromPtr(initiator_origin))) {
+ *new_url = GURL(chrome::kExtensionInvalidRequestURL);
+ }
+}
+
+void CefExtensionsRendererClient::RunScriptsAtDocumentStart(
+ content::RenderFrame* render_frame) {
+ extension_dispatcher_->RunScriptsAtDocumentStart(render_frame);
+}
+
+void CefExtensionsRendererClient::RunScriptsAtDocumentEnd(
+ content::RenderFrame* render_frame) {
+ extension_dispatcher_->RunScriptsAtDocumentEnd(render_frame);
+}
+
+void CefExtensionsRendererClient::RunScriptsAtDocumentIdle(
+ content::RenderFrame* render_frame) {
+ extension_dispatcher_->RunScriptsAtDocumentIdle(render_frame);
+}
+
+} // namespace extensions
diff --git a/libcef/renderer/extensions/extensions_renderer_client.h b/libcef/renderer/extensions/extensions_renderer_client.h
new file mode 100644
index 00000000..36d0c1b8
--- /dev/null
+++ b/libcef/renderer/extensions/extensions_renderer_client.h
@@ -0,0 +1,88 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_RENDERER_EXTENSIONS_EXTENSIONS_RENDERER_CLIENT_H_
+#define CEF_LIBCEF_RENDERER_EXTENSIONS_EXTENSIONS_RENDERER_CLIENT_H_
+
+#include <memory>
+#include <string>
+
+#include "extensions/renderer/extensions_renderer_client.h"
+#include "services/service_manager/public/cpp/binder_registry.h"
+#include "ui/base/page_transition_types.h"
+
+class GURL;
+
+namespace blink {
+class WebFrame;
+class WebLocalFrame;
+struct WebPluginParams;
+class WebURL;
+} // namespace blink
+
+namespace net {
+class SiteForCookies;
+}
+
+namespace content {
+class BrowserPluginDelegate;
+class RenderFrame;
+struct WebPluginInfo;
+} // namespace content
+
+namespace url {
+class Origin;
+}
+
+namespace extensions {
+
+class Dispatcher;
+class DispatcherDelegate;
+class ResourceRequestPolicy;
+
+class CefExtensionsRendererClient : public ExtensionsRendererClient {
+ public:
+ CefExtensionsRendererClient();
+
+ CefExtensionsRendererClient(const CefExtensionsRendererClient&) = delete;
+ CefExtensionsRendererClient& operator=(const CefExtensionsRendererClient&) =
+ delete;
+
+ ~CefExtensionsRendererClient() override;
+
+ // ExtensionsRendererClient implementation.
+ bool IsIncognitoProcess() const override;
+ int GetLowestIsolatedWorldId() const override;
+ extensions::Dispatcher* GetDispatcher() override;
+ void OnExtensionLoaded(const extensions::Extension& extension) override;
+ void OnExtensionUnloaded(
+ const extensions::ExtensionId& extension_id) override;
+ bool ExtensionAPIEnabledForServiceWorkerScript(
+ const GURL& scope,
+ const GURL& script_url) const override;
+
+ // See AlloyContentRendererClient methods with the same names.
+ void RenderThreadStarted();
+ void RenderFrameCreated(content::RenderFrame* render_frame,
+ service_manager::BinderRegistry* registry);
+ bool OverrideCreatePlugin(content::RenderFrame* render_frame,
+ const blink::WebPluginParams& params);
+ void WillSendRequest(blink::WebLocalFrame* frame,
+ ui::PageTransition transition_type,
+ const blink::WebURL& url,
+ const net::SiteForCookies& site_for_cookies,
+ const url::Origin* initiator_origin,
+ GURL* new_url);
+ void RunScriptsAtDocumentStart(content::RenderFrame* render_frame);
+ void RunScriptsAtDocumentEnd(content::RenderFrame* render_frame);
+ void RunScriptsAtDocumentIdle(content::RenderFrame* render_frame);
+
+ private:
+ std::unique_ptr<extensions::Dispatcher> extension_dispatcher_;
+ std::unique_ptr<extensions::ResourceRequestPolicy> resource_request_policy_;
+};
+
+} // namespace extensions
+
+#endif // CEF_LIBCEF_RENDERER_EXTENSIONS_EXTENSIONS_RENDERER_CLIENT_H_
diff --git a/libcef/renderer/extensions/print_render_frame_helper_delegate.cc b/libcef/renderer/extensions/print_render_frame_helper_delegate.cc
new file mode 100644
index 00000000..690ee3d7
--- /dev/null
+++ b/libcef/renderer/extensions/print_render_frame_helper_delegate.cc
@@ -0,0 +1,72 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/renderer/extensions/print_render_frame_helper_delegate.h"
+
+#include <vector>
+
+#include "libcef/common/extensions/extensions_util.h"
+
+#include "base/command_line.h"
+#include "base/strings/string_util.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/extensions/extension_constants.h"
+#include "chrome/common/pdf_util.h"
+#include "chrome/common/url_constants.h"
+#include "content/public/renderer/render_frame.h"
+#include "extensions/common/constants.h"
+#include "extensions/renderer/guest_view/mime_handler_view/post_message_support.h"
+#include "services/service_manager/public/cpp/interface_provider.h"
+#include "third_party/blink/public/web/web_document.h"
+#include "third_party/blink/public/web/web_element.h"
+#include "third_party/blink/public/web/web_local_frame.h"
+
+namespace extensions {
+
+CefPrintRenderFrameHelperDelegate::CefPrintRenderFrameHelperDelegate(
+ bool is_windowless)
+ : is_windowless_(is_windowless) {}
+
+CefPrintRenderFrameHelperDelegate::~CefPrintRenderFrameHelperDelegate() =
+ default;
+
+// Return the PDF object element if |frame| is the out of process PDF extension.
+blink::WebElement CefPrintRenderFrameHelperDelegate::GetPdfElement(
+ blink::WebLocalFrame* frame) {
+ if (frame->Parent() &&
+ IsPdfInternalPluginAllowedOrigin(frame->Parent()->GetSecurityOrigin())) {
+ auto plugin_element = frame->GetDocument().QuerySelector("embed");
+ DCHECK(!plugin_element.IsNull());
+ return plugin_element;
+ }
+
+ return blink::WebElement();
+}
+
+bool CefPrintRenderFrameHelperDelegate::IsPrintPreviewEnabled() {
+ return !is_windowless_ && PrintPreviewEnabled();
+}
+
+bool CefPrintRenderFrameHelperDelegate::ShouldGenerateTaggedPDF() {
+ return true;
+}
+
+bool CefPrintRenderFrameHelperDelegate::OverridePrint(
+ blink::WebLocalFrame* frame) {
+ auto* post_message_support =
+ extensions::PostMessageSupport::FromWebLocalFrame(frame);
+ if (post_message_support) {
+ // This message is handled in chrome/browser/resources/pdf/pdf.js and
+ // instructs the PDF plugin to print. This is to make window.print() on a
+ // PDF plugin document correctly print the PDF. See
+ // https://crbug.com/448720.
+ base::Value::Dict message;
+ message.Set("type", "print");
+ post_message_support->PostMessageFromValue(base::Value(std::move(message)));
+ return true;
+ }
+ return false;
+}
+
+} // namespace extensions
diff --git a/libcef/renderer/extensions/print_render_frame_helper_delegate.h b/libcef/renderer/extensions/print_render_frame_helper_delegate.h
new file mode 100644
index 00000000..77eb591b
--- /dev/null
+++ b/libcef/renderer/extensions/print_render_frame_helper_delegate.h
@@ -0,0 +1,29 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_RENDERER_EXTENSIONS_PRINT_RENDER_FRAME_HELPER_DELEGATE_H_
+#define CEF_LIBCEF_RENDERER_EXTENSIONS_PRINT_RENDER_FRAME_HELPER_DELEGATE_H_
+
+#include "components/printing/renderer/print_render_frame_helper.h"
+
+namespace extensions {
+
+class CefPrintRenderFrameHelperDelegate
+ : public printing::PrintRenderFrameHelper::Delegate {
+ public:
+ explicit CefPrintRenderFrameHelperDelegate(bool is_windowless);
+ ~CefPrintRenderFrameHelperDelegate() override;
+
+ blink::WebElement GetPdfElement(blink::WebLocalFrame* frame) override;
+ bool IsPrintPreviewEnabled() override;
+ bool ShouldGenerateTaggedPDF() override;
+ bool OverridePrint(blink::WebLocalFrame* frame) override;
+
+ private:
+ bool is_windowless_;
+};
+
+} // namespace extensions
+
+#endif // CEF_LIBCEF_RENDERER_EXTENSIONS_PRINT_RENDER_FRAME_HELPER_DELEGATE_H_
diff --git a/libcef/renderer/frame_impl.cc b/libcef/renderer/frame_impl.cc
new file mode 100644
index 00000000..18e1ddd0
--- /dev/null
+++ b/libcef/renderer/frame_impl.cc
@@ -0,0 +1,863 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#include "libcef/renderer/frame_impl.h"
+
+#include "build/build_config.h"
+
+// Enable deprecation warnings on Windows. See http://crbug.com/585142.
+#if BUILDFLAG(IS_WIN)
+#if defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic error "-Wdeprecated-declarations"
+#else
+#pragma warning(push)
+#pragma warning(default : 4996)
+#endif
+#endif
+
+#include "libcef/common/app_manager.h"
+#include "libcef/common/frame_util.h"
+#include "libcef/common/net/http_header_utils.h"
+#include "libcef/common/process_message_impl.h"
+#include "libcef/common/process_message_smr_impl.h"
+#include "libcef/common/request_impl.h"
+#include "libcef/common/string_util.h"
+#include "libcef/renderer/blink_glue.h"
+#include "libcef/renderer/browser_impl.h"
+#include "libcef/renderer/dom_document_impl.h"
+#include "libcef/renderer/render_frame_util.h"
+#include "libcef/renderer/render_urlrequest_impl.h"
+#include "libcef/renderer/thread_util.h"
+#include "libcef/renderer/v8_impl.h"
+
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "content/renderer/render_frame_impl.h"
+#include "third_party/blink/public/mojom/frame/frame.mojom-blink.h"
+#include "third_party/blink/public/mojom/frame/lifecycle.mojom-blink.h"
+#include "third_party/blink/public/platform/web_back_forward_cache_loader_helper.h"
+#include "third_party/blink/public/platform/web_data.h"
+#include "third_party/blink/public/platform/web_string.h"
+#include "third_party/blink/public/platform/web_url.h"
+#include "third_party/blink/public/platform/web_url_loader.h"
+#include "third_party/blink/public/web/blink.h"
+#include "third_party/blink/public/web/web_document.h"
+#include "third_party/blink/public/web/web_document_loader.h"
+#include "third_party/blink/public/web/web_frame_content_dumper.h"
+#include "third_party/blink/public/web/web_local_frame.h"
+#include "third_party/blink/public/web/web_navigation_control.h"
+#include "third_party/blink/public/web/web_script_source.h"
+#include "third_party/blink/public/web/web_view.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
+
+namespace {
+
+// Maximum number of times to retry the browser connection.
+constexpr size_t kConnectionRetryMaxCt = 3U;
+
+// Length of time to wait before initiating a browser connection retry.
+constexpr auto kConnectionRetryDelay = base::Seconds(1);
+
+// Length of time to wait for the browser connection ACK before timing out.
+constexpr auto kConnectionTimeout = base::Seconds(10);
+
+} // namespace
+
+CefFrameImpl::CefFrameImpl(CefBrowserImpl* browser,
+ blink::WebLocalFrame* frame,
+ int64_t frame_id)
+ : browser_(browser), frame_(frame), frame_id_(frame_id) {}
+
+CefFrameImpl::~CefFrameImpl() {}
+
+bool CefFrameImpl::IsValid() {
+ CEF_REQUIRE_RT_RETURN(false);
+
+ return (frame_ != nullptr);
+}
+
+void CefFrameImpl::Undo() {
+ SendCommand("Undo");
+}
+
+void CefFrameImpl::Redo() {
+ SendCommand("Redo");
+}
+
+void CefFrameImpl::Cut() {
+ SendCommand("Cut");
+}
+
+void CefFrameImpl::Copy() {
+ SendCommand("Copy");
+}
+
+void CefFrameImpl::Paste() {
+ SendCommand("Paste");
+}
+
+void CefFrameImpl::Delete() {
+ SendCommand("Delete");
+}
+
+void CefFrameImpl::SelectAll() {
+ SendCommand("SelectAll");
+}
+
+void CefFrameImpl::ViewSource() {
+ NOTREACHED() << "ViewSource cannot be called from the renderer process";
+}
+
+void CefFrameImpl::GetSource(CefRefPtr<CefStringVisitor> visitor) {
+ CEF_REQUIRE_RT_RETURN_VOID();
+ if (frame_) {
+ CefString content;
+ string_util::GetCefString(blink_glue::DumpDocumentMarkup(frame_), content);
+ visitor->Visit(content);
+ }
+}
+
+void CefFrameImpl::GetText(CefRefPtr<CefStringVisitor> visitor) {
+ CEF_REQUIRE_RT_RETURN_VOID();
+ if (frame_) {
+ CefString content;
+ string_util::GetCefString(blink_glue::DumpDocumentText(frame_), content);
+ visitor->Visit(content);
+ }
+}
+
+void CefFrameImpl::LoadRequest(CefRefPtr<CefRequest> request) {
+ CEF_REQUIRE_RT_RETURN_VOID();
+
+ if (!frame_) {
+ return;
+ }
+
+ auto params = cef::mojom::RequestParams::New();
+ static_cast<CefRequestImpl*>(request.get())->Get(params);
+ LoadRequest(std::move(params));
+}
+
+void CefFrameImpl::LoadURL(const CefString& url) {
+ CEF_REQUIRE_RT_RETURN_VOID();
+
+ if (!frame_) {
+ return;
+ }
+
+ auto params = cef::mojom::RequestParams::New();
+ params->url = GURL(url.ToString());
+ params->method = "GET";
+ LoadRequest(std::move(params));
+}
+
+void CefFrameImpl::ExecuteJavaScript(const CefString& jsCode,
+ const CefString& scriptUrl,
+ int startLine) {
+ SendJavaScript(jsCode, scriptUrl, startLine);
+}
+
+bool CefFrameImpl::IsMain() {
+ CEF_REQUIRE_RT_RETURN(false);
+
+ if (frame_) {
+ return (frame_->Parent() == nullptr);
+ }
+ return false;
+}
+
+bool CefFrameImpl::IsFocused() {
+ CEF_REQUIRE_RT_RETURN(false);
+
+ if (frame_ && frame_->View()) {
+ return (frame_->View()->FocusedFrame() == frame_);
+ }
+ return false;
+}
+
+CefString CefFrameImpl::GetName() {
+ CefString name;
+ CEF_REQUIRE_RT_RETURN(name);
+
+ if (frame_) {
+ name = render_frame_util::GetName(frame_);
+ }
+ return name;
+}
+
+int64 CefFrameImpl::GetIdentifier() {
+ CEF_REQUIRE_RT_RETURN(0);
+
+ return frame_id_;
+}
+
+CefRefPtr<CefFrame> CefFrameImpl::GetParent() {
+ CEF_REQUIRE_RT_RETURN(nullptr);
+
+ if (frame_) {
+ blink::WebFrame* parent = frame_->Parent();
+ if (parent && parent->IsWebLocalFrame()) {
+ return browser_->GetWebFrameImpl(parent->ToWebLocalFrame()).get();
+ }
+ }
+
+ return nullptr;
+}
+
+CefString CefFrameImpl::GetURL() {
+ CefString url;
+ CEF_REQUIRE_RT_RETURN(url);
+
+ if (frame_) {
+ GURL gurl = frame_->GetDocument().Url();
+ url = gurl.spec();
+ }
+ return url;
+}
+
+CefRefPtr<CefBrowser> CefFrameImpl::GetBrowser() {
+ CEF_REQUIRE_RT_RETURN(nullptr);
+
+ return browser_;
+}
+
+CefRefPtr<CefV8Context> CefFrameImpl::GetV8Context() {
+ CEF_REQUIRE_RT_RETURN(nullptr);
+
+ if (frame_) {
+ v8::Isolate* isolate = blink::MainThreadIsolate();
+ v8::HandleScope handle_scope(isolate);
+ return new CefV8ContextImpl(isolate, frame_->MainWorldScriptContext());
+ } else {
+ return nullptr;
+ }
+}
+
+void CefFrameImpl::VisitDOM(CefRefPtr<CefDOMVisitor> visitor) {
+ CEF_REQUIRE_RT_RETURN_VOID();
+
+ if (!frame_) {
+ return;
+ }
+
+ // Create a CefDOMDocumentImpl object that is valid only for the scope of this
+ // method.
+ CefRefPtr<CefDOMDocumentImpl> documentImpl;
+ const blink::WebDocument& document = frame_->GetDocument();
+ if (!document.IsNull()) {
+ documentImpl = new CefDOMDocumentImpl(browser_, frame_);
+ }
+
+ visitor->Visit(documentImpl.get());
+
+ if (documentImpl.get()) {
+ documentImpl->Detach();
+ }
+}
+
+CefRefPtr<CefURLRequest> CefFrameImpl::CreateURLRequest(
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefURLRequestClient> client) {
+ CEF_REQUIRE_RT_RETURN(nullptr);
+
+ if (!request || !client || !frame_) {
+ return nullptr;
+ }
+
+ CefRefPtr<CefRenderURLRequest> impl =
+ new CefRenderURLRequest(this, request, client);
+ if (impl->Start()) {
+ return impl.get();
+ }
+ return nullptr;
+}
+
+void CefFrameImpl::SendProcessMessage(CefProcessId target_process,
+ CefRefPtr<CefProcessMessage> message) {
+ CEF_REQUIRE_RT_RETURN_VOID();
+ DCHECK_EQ(PID_BROWSER, target_process);
+ DCHECK(message && message->IsValid());
+ if (!message || !message->IsValid()) {
+ return;
+ }
+
+ if (message->GetArgumentList() != nullptr) {
+ // Invalidate the message object immediately by taking the argument list.
+ auto argument_list =
+ static_cast<CefProcessMessageImpl*>(message.get())->TakeArgumentList();
+ SendToBrowserFrame(
+ __FUNCTION__,
+ base::BindOnce(
+ [](const CefString& name, base::Value::List argument_list,
+ const BrowserFrameType& render_frame) {
+ render_frame->SendMessage(name, std::move(argument_list));
+ },
+ message->GetName(), std::move(argument_list)));
+ } else {
+ auto region =
+ static_cast<CefProcessMessageSMRImpl*>(message.get())->TakeRegion();
+ SendToBrowserFrame(
+ __FUNCTION__,
+ base::BindOnce(
+ [](const CefString& name, base::ReadOnlySharedMemoryRegion region,
+ const BrowserFrameType& render_frame) {
+ render_frame->SendSharedMemoryRegion(name, std::move(region));
+ },
+ message->GetName(), std::move(region)));
+ }
+}
+
+std::unique_ptr<blink::WebURLLoader> CefFrameImpl::CreateURLLoader() {
+ CEF_REQUIRE_RT();
+ if (!frame_) {
+ return nullptr;
+ }
+
+ if (!url_loader_factory_) {
+ auto render_frame = content::RenderFrameImpl::FromWebFrame(frame_);
+ if (render_frame) {
+ url_loader_factory_ = render_frame->CreateURLLoaderFactory();
+ }
+ }
+ if (!url_loader_factory_) {
+ return nullptr;
+ }
+
+ return url_loader_factory_->CreateURLLoader(
+ blink::WebURLRequest(),
+ blink_glue::CreateResourceLoadingTaskRunnerHandle(frame_),
+ blink_glue::CreateResourceLoadingMaybeUnfreezableTaskRunnerHandle(frame_),
+ /*keep_alive_handle=*/mojo::NullRemote(),
+ blink::WebBackForwardCacheLoaderHelper());
+}
+
+std::unique_ptr<blink::ResourceLoadInfoNotifierWrapper>
+CefFrameImpl::CreateResourceLoadInfoNotifierWrapper() {
+ CEF_REQUIRE_RT();
+ if (frame_) {
+ auto render_frame = content::RenderFrameImpl::FromWebFrame(frame_);
+ if (render_frame) {
+ return render_frame->CreateResourceLoadInfoNotifierWrapper();
+ }
+ }
+ return nullptr;
+}
+
+void CefFrameImpl::OnAttached() {
+ // Called indirectly from RenderFrameCreated.
+ ConnectBrowserFrame(ConnectReason::RENDER_FRAME_CREATED);
+}
+
+void CefFrameImpl::OnWasShown() {
+ if (browser_connection_state_ == ConnectionState::DISCONNECTED) {
+ // Reconnect a frame that has exited the bfcache.
+ ConnectBrowserFrame(ConnectReason::WAS_SHOWN);
+ }
+}
+
+void CefFrameImpl::OnDidCommitProvisionalLoad() {
+ did_commit_provisional_load_ = true;
+ MaybeInitializeScriptContext();
+}
+
+void CefFrameImpl::OnDidFinishLoad() {
+ // Ignore notifications from the embedded frame hosting a mime-type plugin.
+ // We'll eventually receive a notification from the owner frame.
+ if (blink_glue::HasPluginFrameOwner(frame_)) {
+ return;
+ }
+
+ if (!blink::RuntimeEnabledFeatures::BackForwardCacheEnabled() && IsMain()) {
+ // Refresh draggable regions. Otherwise, we may not receive updated regions
+ // after navigation because LocalFrameView::UpdateDocumentAnnotatedRegion
+ // lacks sufficient context. When bfcache is disabled we use this method
+ // instead of DidStopLoading() because it provides more accurate timing.
+ OnDraggableRegionsChanged();
+ }
+
+ blink::WebDocumentLoader* dl = frame_->GetDocumentLoader();
+ const int http_status_code = dl->GetWebResponse().HttpStatusCode();
+
+ CefRefPtr<CefApp> app = CefAppManager::Get()->GetApplication();
+ if (app) {
+ CefRefPtr<CefRenderProcessHandler> handler = app->GetRenderProcessHandler();
+ if (handler) {
+ CefRefPtr<CefLoadHandler> load_handler = handler->GetLoadHandler();
+ if (load_handler) {
+ load_handler->OnLoadEnd(browser_, this, http_status_code);
+ }
+ }
+ }
+}
+
+void CefFrameImpl::OnDraggableRegionsChanged() {
+ // Match the behavior in ChromeRenderFrameObserver::DraggableRegionsChanged.
+ // Only the main frame is allowed to control draggable regions, to avoid other
+ // frames manipulate the regions in the browser process.
+ if (frame_->Parent() != nullptr) {
+ return;
+ }
+
+ blink::WebVector<blink::WebDraggableRegion> webregions =
+ frame_->GetDocument().DraggableRegions();
+ std::vector<cef::mojom::DraggableRegionEntryPtr> regions;
+ if (!webregions.empty()) {
+ auto render_frame = content::RenderFrameImpl::FromWebFrame(frame_);
+
+ regions.reserve(webregions.size());
+ for (const auto& webregion : webregions) {
+ auto region = cef::mojom::DraggableRegionEntry::New(webregion.bounds,
+ webregion.draggable);
+ render_frame->ConvertViewportToWindow(&region->bounds);
+ regions.push_back(std::move(region));
+ }
+ }
+
+ using RegionsArg =
+ absl::optional<std::vector<cef::mojom::DraggableRegionEntryPtr>>;
+ RegionsArg regions_arg =
+ regions.empty() ? absl::nullopt : absl::make_optional(std::move(regions));
+
+ SendToBrowserFrame(
+ __FUNCTION__,
+ base::BindOnce(
+ [](RegionsArg regions_arg, const BrowserFrameType& browser_frame) {
+ browser_frame->UpdateDraggableRegions(std::move(regions_arg));
+ },
+ std::move(regions_arg)));
+}
+
+void CefFrameImpl::OnContextCreated(v8::Local<v8::Context> context) {
+ context_created_ = true;
+
+ CHECK(frame_);
+ while (!queued_context_actions_.empty()) {
+ auto& action = queued_context_actions_.front();
+ std::move(action.second).Run(frame_);
+ queued_context_actions_.pop();
+ }
+
+ execution_context_lifecycle_state_observer_ =
+ blink_glue::RegisterExecutionContextLifecycleStateObserver(context, this);
+}
+
+void CefFrameImpl::OnContextReleased() {
+ execution_context_lifecycle_state_observer_.reset();
+}
+
+void CefFrameImpl::OnDetached() {
+ // Called when this frame has been detached from the view. This *will* be
+ // called for child frames when a parent frame is detached.
+ // The browser may hold the last reference to |this|. Take a reference here to
+ // keep |this| alive until after this method returns.
+ CefRefPtr<CefFrameImpl> self = this;
+
+ frame_ = nullptr;
+
+ browser_->FrameDetached(frame_id_);
+
+ OnDisconnect(DisconnectReason::DETACHED);
+
+ browser_ = nullptr;
+ url_loader_factory_.reset();
+
+ // In case we never attached.
+ while (!queued_browser_actions_.empty()) {
+ auto& action = queued_browser_actions_.front();
+ LOG(WARNING) << action.first << " sent to detached " << GetDebugString()
+ << " will be ignored";
+ queued_browser_actions_.pop();
+ }
+
+ // In case we're destroyed without the context being created.
+ while (!queued_context_actions_.empty()) {
+ auto& action = queued_context_actions_.front();
+ LOG(WARNING) << action.first << " sent to detached " << GetDebugString()
+ << " will be ignored";
+ queued_context_actions_.pop();
+ }
+}
+
+void CefFrameImpl::ExecuteOnLocalFrame(const std::string& function_name,
+ LocalFrameAction action) {
+ CEF_REQUIRE_RT_RETURN_VOID();
+
+ if (!context_created_) {
+ queued_context_actions_.push(
+ std::make_pair(function_name, std::move(action)));
+ MaybeInitializeScriptContext();
+ return;
+ }
+
+ if (frame_) {
+ std::move(action).Run(frame_);
+ } else {
+ LOG(WARNING) << function_name << " sent to detached " << GetDebugString()
+ << " will be ignored";
+ }
+}
+
+void CefFrameImpl::ConnectBrowserFrame(ConnectReason reason) {
+ DCHECK(browser_connection_state_ == ConnectionState::DISCONNECTED ||
+ browser_connection_state_ == ConnectionState::RECONNECT_PENDING);
+
+ if (VLOG_IS_ON(1)) {
+ std::string reason_str;
+ switch (reason) {
+ case ConnectReason::RENDER_FRAME_CREATED:
+ reason_str = "RENDER_FRAME_CREATED";
+ break;
+ case ConnectReason::WAS_SHOWN:
+ reason_str = "WAS_SHOWN";
+ break;
+ case ConnectReason::RETRY:
+ reason_str = base::StringPrintf(
+ "RETRY %zu/%zu", browser_connect_retry_ct_, kConnectionRetryMaxCt);
+ break;
+ }
+ VLOG(1) << GetDebugString() << " connection request (reason=" << reason_str
+ << ")";
+ }
+
+ // Don't attempt to connect an invalid or bfcache'd frame. If a bfcache'd
+ // frame returns to active status a reconnect will be triggered via
+ // OnWasShown().
+ if (!frame_ || blink_glue::IsInBackForwardCache(frame_)) {
+ browser_connection_state_ = ConnectionState::DISCONNECTED;
+ browser_connect_timer_.Stop();
+ VLOG(1) << GetDebugString() << " connection retry canceled (reason="
+ << (frame_ ? "BFCACHED" : "INVALID") << ")";
+ return;
+ }
+
+ browser_connection_state_ = ConnectionState::CONNECTION_PENDING;
+ browser_connect_timer_.Start(FROM_HERE, kConnectionTimeout, this,
+ &CefFrameImpl::OnBrowserFrameTimeout);
+
+ auto& browser_frame = GetBrowserFrame(/*expect_acked=*/false);
+ CHECK(browser_frame);
+
+ // True if this connection is a retry or if the frame just exited the
+ // BackForwardCache.
+ const bool reattached =
+ browser_connect_retry_ct_ > 0 || reason == ConnectReason::WAS_SHOWN;
+
+ // If the channel is working we should get a call to FrameAttachedAck().
+ // Otherwise, OnDisconnect() should be called to retry the
+ // connection.
+ browser_frame->FrameAttached(receiver_.BindNewPipeAndPassRemote(),
+ reattached);
+ receiver_.set_disconnect_handler(
+ base::BindOnce(&CefFrameImpl::OnDisconnect, this,
+ DisconnectReason::RENDER_FRAME_DISCONNECT));
+}
+
+const mojo::Remote<cef::mojom::BrowserFrame>& CefFrameImpl::GetBrowserFrame(
+ bool expect_acked) {
+ DCHECK_EQ(expect_acked,
+ browser_connection_state_ == ConnectionState::CONNECTION_ACKED);
+
+ if (!browser_frame_.is_bound()) {
+ auto render_frame = content::RenderFrameImpl::FromWebFrame(frame_);
+ if (render_frame) {
+ // Triggers creation of a CefBrowserFrame in the browser process.
+ render_frame->GetBrowserInterfaceBroker()->GetInterface(
+ browser_frame_.BindNewPipeAndPassReceiver());
+ browser_frame_.set_disconnect_handler(
+ base::BindOnce(&CefFrameImpl::OnDisconnect, this,
+ DisconnectReason::BROWSER_FRAME_DISCONNECT));
+ }
+ }
+ return browser_frame_;
+}
+
+void CefFrameImpl::OnBrowserFrameTimeout() {
+ LOG(ERROR) << GetDebugString() << " connection timeout";
+ OnDisconnect(DisconnectReason::CONNECT_TIMEOUT);
+}
+
+void CefFrameImpl::OnDisconnect(DisconnectReason reason) {
+ // Ignore multiple calls in close proximity (which may occur if both
+ // |browser_frame_| and |receiver_| disconnect). |frame_| will be nullptr
+ // when called from/after OnDetached().
+ if (frame_ &&
+ browser_connection_state_ == ConnectionState::RECONNECT_PENDING) {
+ return;
+ }
+
+ if (VLOG_IS_ON(1)) {
+ std::string reason_str;
+ switch (reason) {
+ case DisconnectReason::DETACHED:
+ reason_str = "DETACHED";
+ break;
+ case DisconnectReason::BROWSER_FRAME_DETACHED:
+ reason_str = "BROWSER_FRAME_DETACHED";
+ break;
+ case DisconnectReason::CONNECT_TIMEOUT:
+ reason_str = "CONNECT_TIMEOUT";
+ break;
+ case DisconnectReason::RENDER_FRAME_DISCONNECT:
+ reason_str = "RENDER_FRAME_DISCONNECT";
+ break;
+ case DisconnectReason::BROWSER_FRAME_DISCONNECT:
+ reason_str = "BROWSER_FRAME_DISCONNECT";
+ break;
+ };
+
+ std::string state_str;
+ switch (browser_connection_state_) {
+ case ConnectionState::DISCONNECTED:
+ state_str = "DISCONNECTED";
+ break;
+ case ConnectionState::CONNECTION_PENDING:
+ state_str = "CONNECTION_PENDING";
+ break;
+ case ConnectionState::CONNECTION_ACKED:
+ state_str = "CONNECTION_ACKED";
+ break;
+ case ConnectionState::RECONNECT_PENDING:
+ state_str = "RECONNECT_PENDING";
+ break;
+ }
+
+ if (!frame_) {
+ state_str += ", FRAME_INVALID";
+ }
+
+ VLOG(1) << GetDebugString() << " disconnected (reason=" << reason_str
+ << ", current_state=" << state_str << ")";
+ }
+
+ browser_frame_.reset();
+ receiver_.reset();
+ browser_connection_state_ = ConnectionState::DISCONNECTED;
+ browser_connect_timer_.Stop();
+
+ // Only retry if the frame is still valid and the browser process has not
+ // intentionally detached.
+ if (frame_ && reason != DisconnectReason::BROWSER_FRAME_DETACHED) {
+ if (browser_connect_retry_ct_++ < kConnectionRetryMaxCt) {
+ VLOG(1) << GetDebugString() << " connection retry scheduled";
+
+ // Retry after a delay in case the frame is currently navigating, being
+ // destroyed, or entering the bfcache. In the navigation case the retry
+ // will likely succeed. In the destruction case the retry will be
+ // ignored/canceled due to OnDetached(). In the bfcache case the status
+ // may not be updated immediately, so we allow the reconnect timer to
+ // trigger and check the status in ConnectBrowserFrame() instead.
+ browser_connection_state_ = ConnectionState::RECONNECT_PENDING;
+ browser_connect_timer_.Start(
+ FROM_HERE, kConnectionRetryDelay,
+ base::BindOnce(&CefFrameImpl::ConnectBrowserFrame, this,
+ ConnectReason::RETRY));
+ } else {
+ // Trigger a crash in official builds.
+ LOG(FATAL) << GetDebugString() << " connection retry failed";
+ }
+ }
+}
+
+void CefFrameImpl::SendToBrowserFrame(const std::string& function_name,
+ BrowserFrameAction action) {
+ if (!frame_) {
+ // We've been detached.
+ LOG(WARNING) << function_name << " sent to detached " << GetDebugString()
+ << " will be ignored";
+ return;
+ }
+
+ if (browser_connection_state_ != ConnectionState::CONNECTION_ACKED) {
+ // Queue actions until we're notified by the browser that it's ready to
+ // handle them.
+ queued_browser_actions_.push(
+ std::make_pair(function_name, std::move(action)));
+ return;
+ }
+
+ auto& browser_frame = GetBrowserFrame();
+ CHECK(browser_frame);
+
+ std::move(action).Run(browser_frame);
+}
+
+void CefFrameImpl::MaybeInitializeScriptContext() {
+ if (did_initialize_script_context_) {
+ return;
+ }
+
+ if (!did_commit_provisional_load_) {
+ // Too soon for context initialization.
+ return;
+ }
+
+ if (queued_context_actions_.empty()) {
+ // Don't need early context initialization. Avoid it due to performance
+ // consequences.
+ return;
+ }
+
+ did_initialize_script_context_ = true;
+
+ // Explicitly force creation of the script context. This occurred implicitly
+ // via DidCommitProvisionalLoad prior to https://crrev.com/5150754880a.
+ // Otherwise, a script context may never be created for a frame that doesn't
+ // contain JS code.
+ v8::HandleScope handle_scope(blink::MainThreadIsolate());
+ frame_->MainWorldScriptContext();
+}
+
+void CefFrameImpl::FrameAttachedAck() {
+ // Sent from the browser process in response to ConnectBrowserFrame() sending
+ // FrameAttached().
+ CHECK_EQ(ConnectionState::CONNECTION_PENDING, browser_connection_state_);
+ browser_connection_state_ = ConnectionState::CONNECTION_ACKED;
+ browser_connect_retry_ct_ = 0;
+ browser_connect_timer_.Stop();
+
+ auto& browser_frame = GetBrowserFrame();
+ CHECK(browser_frame);
+
+ while (!queued_browser_actions_.empty()) {
+ std::move(queued_browser_actions_.front().second).Run(browser_frame);
+ queued_browser_actions_.pop();
+ }
+}
+
+void CefFrameImpl::FrameDetached() {
+ // Sent from the browser process in response to CefFrameHostImpl::Detach().
+ CHECK_EQ(ConnectionState::CONNECTION_ACKED, browser_connection_state_);
+ OnDisconnect(DisconnectReason::BROWSER_FRAME_DETACHED);
+}
+
+void CefFrameImpl::SendMessage(const std::string& name,
+ base::Value::List arguments) {
+ if (auto app = CefAppManager::Get()->GetApplication()) {
+ if (auto handler = app->GetRenderProcessHandler()) {
+ CefRefPtr<CefProcessMessageImpl> message(
+ new CefProcessMessageImpl(name, std::move(arguments),
+ /*read_only=*/true));
+ handler->OnProcessMessageReceived(browser_, this, PID_BROWSER,
+ message.get());
+ }
+ }
+}
+
+void CefFrameImpl::SendSharedMemoryRegion(
+ const std::string& name,
+ base::ReadOnlySharedMemoryRegion region) {
+ if (auto app = CefAppManager::Get()->GetApplication()) {
+ if (auto handler = app->GetRenderProcessHandler()) {
+ CefRefPtr<CefProcessMessage> message(
+ new CefProcessMessageSMRImpl(name, std::move(region)));
+ handler->OnProcessMessageReceived(browser_, this, PID_BROWSER, message);
+ }
+ }
+}
+
+void CefFrameImpl::SendCommand(const std::string& command) {
+ ExecuteOnLocalFrame(
+ __FUNCTION__,
+ base::BindOnce(
+ [](const std::string& command, blink::WebLocalFrame* frame) {
+ frame->ExecuteCommand(blink::WebString::FromUTF8(command));
+ },
+ command));
+}
+
+void CefFrameImpl::SendCommandWithResponse(
+ const std::string& command,
+ cef::mojom::RenderFrame::SendCommandWithResponseCallback callback) {
+ ExecuteOnLocalFrame(
+ __FUNCTION__,
+ base::BindOnce(
+ [](const std::string& command,
+ cef::mojom::RenderFrame::SendCommandWithResponseCallback callback,
+ blink::WebLocalFrame* frame) {
+ blink::WebString response;
+
+ if (base::EqualsCaseInsensitiveASCII(command, "getsource")) {
+ response = blink_glue::DumpDocumentMarkup(frame);
+ } else if (base::EqualsCaseInsensitiveASCII(command, "gettext")) {
+ response = blink_glue::DumpDocumentText(frame);
+ }
+
+ std::move(callback).Run(
+ string_util::CreateSharedMemoryRegion(response));
+ },
+ command, std::move(callback)));
+}
+
+void CefFrameImpl::SendJavaScript(const std::u16string& jsCode,
+ const std::string& scriptUrl,
+ int32_t startLine) {
+ ExecuteOnLocalFrame(
+ __FUNCTION__,
+ base::BindOnce(
+ [](const std::u16string& jsCode, const std::string& scriptUrl,
+ blink::WebLocalFrame* frame) {
+ frame->ExecuteScript(blink::WebScriptSource(
+ blink::WebString::FromUTF16(jsCode), GURL(scriptUrl)));
+ },
+ jsCode, scriptUrl));
+}
+
+void CefFrameImpl::LoadRequest(cef::mojom::RequestParamsPtr params) {
+ ExecuteOnLocalFrame(
+ __FUNCTION__,
+ base::BindOnce(
+ [](cef::mojom::RequestParamsPtr params, blink::WebLocalFrame* frame) {
+ blink::WebURLRequest request;
+ CefRequestImpl::Get(params, request);
+ blink_glue::StartNavigation(frame, request);
+ },
+ std::move(params)));
+}
+
+void CefFrameImpl::DidStopLoading() {
+ // We should only receive this notification for the highest-level LocalFrame
+ // in this frame's in-process subtree. If there are multiple of these for
+ // the same browser then the other occurrences will be discarded in
+ // OnLoadingStateChange.
+ browser_->OnLoadingStateChange(false);
+
+ if (blink::RuntimeEnabledFeatures::BackForwardCacheEnabled()) {
+ // Refresh draggable regions. Otherwise, we may not receive updated regions
+ // after navigation because LocalFrameView::UpdateDocumentAnnotatedRegion
+ // lacks sufficient context. When bfcache is enabled we can't rely on
+ // OnDidFinishLoad() as the frame may not actually be reloaded.
+ OnDraggableRegionsChanged();
+ }
+}
+
+void CefFrameImpl::MoveOrResizeStarted() {
+ if (frame_) {
+ auto web_view = frame_->View();
+ if (web_view) {
+ web_view->CancelPagePopup();
+ }
+ }
+}
+
+void CefFrameImpl::ContextLifecycleStateChanged(
+ blink::mojom::blink::FrameLifecycleState state) {
+ if (state == blink::mojom::FrameLifecycleState::kFrozen && IsMain() &&
+ blink_glue::IsInBackForwardCache(frame_)) {
+ browser_->OnEnterBFCache();
+ }
+}
+
+std::string CefFrameImpl::GetDebugString() const {
+ return "frame " + frame_util::GetFrameDebugString(frame_id_);
+}
+
+// Enable deprecation warnings on Windows. See http://crbug.com/585142.
+#if BUILDFLAG(IS_WIN)
+#if defined(__clang__)
+#pragma GCC diagnostic pop
+#else
+#pragma warning(pop)
+#endif
+#endif
diff --git a/libcef/renderer/frame_impl.h b/libcef/renderer/frame_impl.h
new file mode 100644
index 00000000..39d8de6c
--- /dev/null
+++ b/libcef/renderer/frame_impl.h
@@ -0,0 +1,214 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_RENDERER_FRAME_IMPL_H_
+#define CEF_LIBCEF_RENDERER_FRAME_IMPL_H_
+#pragma once
+
+#include <queue>
+#include <string>
+
+#include "include/cef_frame.h"
+#include "include/cef_v8.h"
+#include "libcef/renderer/blink_glue.h"
+
+#include "base/memory/weak_ptr.h"
+#include "base/timer/timer.h"
+#include "cef/libcef/common/mojom/cef.mojom.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
+
+namespace base {
+class ListValue;
+}
+
+namespace blink {
+class ResourceLoadInfoNotifierWrapper;
+class WebLocalFrame;
+class WebURLLoader;
+class WebURLLoaderFactory;
+} // namespace blink
+
+class GURL;
+
+class CefBrowserImpl;
+
+// Implementation of CefFrame. CefFrameImpl objects are owned by the
+// CefBrowerImpl and will be detached when the browser is notified that the
+// associated renderer WebFrame will close.
+class CefFrameImpl
+ : public CefFrame,
+ public cef::mojom::RenderFrame,
+ public blink_glue::CefExecutionContextLifecycleStateObserver {
+ public:
+ CefFrameImpl(CefBrowserImpl* browser,
+ blink::WebLocalFrame* frame,
+ int64_t frame_id);
+
+ CefFrameImpl(const CefFrameImpl&) = delete;
+ CefFrameImpl& operator=(const CefFrameImpl&) = delete;
+
+ ~CefFrameImpl() override;
+
+ // CefFrame implementation.
+ bool IsValid() override;
+ void Undo() override;
+ void Redo() override;
+ void Cut() override;
+ void Copy() override;
+ void Paste() override;
+ void Delete() override;
+ void SelectAll() override;
+ void ViewSource() override;
+ void GetSource(CefRefPtr<CefStringVisitor> visitor) override;
+ void GetText(CefRefPtr<CefStringVisitor> visitor) override;
+ void LoadRequest(CefRefPtr<CefRequest> request) override;
+ void LoadURL(const CefString& url) override;
+ void ExecuteJavaScript(const CefString& jsCode,
+ const CefString& scriptUrl,
+ int startLine) override;
+ bool IsMain() override;
+ bool IsFocused() override;
+ CefString GetName() override;
+ int64 GetIdentifier() override;
+ CefRefPtr<CefFrame> GetParent() override;
+ CefString GetURL() override;
+ CefRefPtr<CefBrowser> GetBrowser() override;
+ CefRefPtr<CefV8Context> GetV8Context() override;
+ void VisitDOM(CefRefPtr<CefDOMVisitor> visitor) override;
+ CefRefPtr<CefURLRequest> CreateURLRequest(
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefURLRequestClient> client) override;
+ void SendProcessMessage(CefProcessId target_process,
+ CefRefPtr<CefProcessMessage> message) override;
+
+ // Used by CefRenderURLRequest.
+ std::unique_ptr<blink::WebURLLoader> CreateURLLoader();
+ std::unique_ptr<blink::ResourceLoadInfoNotifierWrapper>
+ CreateResourceLoadInfoNotifierWrapper();
+
+ // Forwarded from CefRenderFrameObserver.
+ void OnAttached();
+ void OnWasShown();
+ void OnDidCommitProvisionalLoad();
+ void OnDidFinishLoad();
+ void OnDraggableRegionsChanged();
+ void OnContextCreated(v8::Local<v8::Context> context);
+ void OnContextReleased();
+ void OnDetached();
+
+ blink::WebLocalFrame* web_frame() const { return frame_; }
+
+ private:
+ // Execute an action on the associated WebLocalFrame. This will queue the
+ // action if the JavaScript context is not yet created.
+ using LocalFrameAction =
+ base::OnceCallback<void(blink::WebLocalFrame* frame)>;
+ void ExecuteOnLocalFrame(const std::string& function_name,
+ LocalFrameAction action);
+
+ enum class ConnectReason {
+ RENDER_FRAME_CREATED,
+ WAS_SHOWN,
+ RETRY,
+ };
+
+ // Initiate the connection to the BrowserFrame channel.
+ void ConnectBrowserFrame(ConnectReason reason);
+
+ // Returns the remote BrowserFrame object.
+ using BrowserFrameType = mojo::Remote<cef::mojom::BrowserFrame>;
+ const BrowserFrameType& GetBrowserFrame(bool expect_acked = true);
+
+ // Called if the BrowserFrame connection attempt times out.
+ void OnBrowserFrameTimeout();
+
+ enum class DisconnectReason {
+ DETACHED,
+ BROWSER_FRAME_DETACHED,
+ CONNECT_TIMEOUT,
+ RENDER_FRAME_DISCONNECT,
+ BROWSER_FRAME_DISCONNECT,
+ };
+
+ // Called if/when a disconnect occurs. This may occur due to frame navigation,
+ // destruction, or insertion into the bfcache (when the browser-side frame
+ // representation is destroyed and closes the connection).
+ void OnDisconnect(DisconnectReason reason);
+
+ // Send an action to the remote BrowserFrame. This will queue the action if
+ // the remote frame is not yet attached.
+ using BrowserFrameAction = base::OnceCallback<void(const BrowserFrameType&)>;
+ void SendToBrowserFrame(const std::string& function_name,
+ BrowserFrameAction action);
+
+ void MaybeInitializeScriptContext();
+
+ // cef::mojom::RenderFrame methods:
+ void FrameAttachedAck() override;
+ void FrameDetached() override;
+ void SendMessage(const std::string& name,
+ base::Value::List arguments) override;
+ void SendSharedMemoryRegion(const std::string& name,
+ base::ReadOnlySharedMemoryRegion region) override;
+ void SendCommand(const std::string& command) override;
+ void SendCommandWithResponse(
+ const std::string& command,
+ cef::mojom::RenderFrame::SendCommandWithResponseCallback callback)
+ override;
+ void SendJavaScript(const std::u16string& jsCode,
+ const std::string& scriptUrl,
+ int32_t startLine) override;
+ void LoadRequest(cef::mojom::RequestParamsPtr params) override;
+ void DidStopLoading() override;
+ void MoveOrResizeStarted() override;
+
+ // blink_glue::CefExecutionContextLifecycleStateObserver methods:
+ void ContextLifecycleStateChanged(
+ blink::mojom::blink::FrameLifecycleState state) override;
+
+ std::string GetDebugString() const;
+
+ CefBrowserImpl* browser_;
+ blink::WebLocalFrame* frame_;
+ const int64 frame_id_;
+
+ bool did_commit_provisional_load_ = false;
+ bool did_initialize_script_context_ = false;
+
+ bool context_created_ = false;
+ std::queue<std::pair<std::string, LocalFrameAction>> queued_context_actions_;
+
+ // Number of times that browser reconnect has been attempted.
+ size_t browser_connect_retry_ct_ = 0;
+
+ // Current browser connection state.
+ enum class ConnectionState {
+ DISCONNECTED,
+ CONNECTION_PENDING,
+ CONNECTION_ACKED,
+ RECONNECT_PENDING,
+ } browser_connection_state_ = ConnectionState::DISCONNECTED;
+
+ base::OneShotTimer browser_connect_timer_;
+
+ std::queue<std::pair<std::string, BrowserFrameAction>>
+ queued_browser_actions_;
+
+ std::unique_ptr<blink::WebURLLoaderFactory> url_loader_factory_;
+
+ mojo::Receiver<cef::mojom::RenderFrame> receiver_{this};
+
+ mojo::Remote<cef::mojom::BrowserFrame> browser_frame_;
+
+ std::unique_ptr<blink_glue::CefObserverRegistration>
+ execution_context_lifecycle_state_observer_;
+
+ base::WeakPtrFactory<CefFrameImpl> weak_ptr_factory_{this};
+
+ IMPLEMENT_REFCOUNTING(CefFrameImpl);
+};
+
+#endif // CEF_LIBCEF_RENDERER_FRAME_IMPL_H_
diff --git a/libcef/renderer/render_frame_observer.cc b/libcef/renderer/render_frame_observer.cc
new file mode 100644
index 00000000..45d59df0
--- /dev/null
+++ b/libcef/renderer/render_frame_observer.cc
@@ -0,0 +1,270 @@
+// Copyright 2014 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#include "build/build_config.h"
+
+// Enable deprecation warnings on Windows. See http://crbug.com/585142.
+#if BUILDFLAG(IS_WIN)
+#if defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic error "-Wdeprecated-declarations"
+#else
+#pragma warning(push)
+#pragma warning(default : 4996)
+#endif
+#endif
+
+#include "libcef/renderer/render_frame_observer.h"
+
+#include "libcef/common/app_manager.h"
+#include "libcef/renderer/blink_glue.h"
+#include "libcef/renderer/browser_impl.h"
+#include "libcef/renderer/dom_document_impl.h"
+#include "libcef/renderer/v8_impl.h"
+
+#include "content/public/renderer/render_frame.h"
+#include "third_party/blink/public/web/blink.h"
+#include "third_party/blink/public/web/web_document.h"
+#include "third_party/blink/public/web/web_element.h"
+#include "third_party/blink/public/web/web_local_frame.h"
+#include "third_party/blink/public/web/web_node.h"
+
+CefRenderFrameObserver::CefRenderFrameObserver(
+ content::RenderFrame* render_frame)
+ : content::RenderFrameObserver(render_frame) {}
+
+CefRenderFrameObserver::~CefRenderFrameObserver() = default;
+
+void CefRenderFrameObserver::DidCommitProvisionalLoad(
+ ui::PageTransition transition) {
+ if (!frame_) {
+ return;
+ }
+
+ frame_->OnDidCommitProvisionalLoad();
+
+ if (frame_->GetParent() == nullptr) {
+ blink::WebLocalFrame* frame = render_frame()->GetWebFrame();
+ CefRefPtr<CefBrowserImpl> browserPtr =
+ CefBrowserImpl::GetBrowserForMainFrame(frame->Top());
+ browserPtr->OnLoadingStateChange(true);
+ }
+ OnLoadStart();
+}
+
+void CefRenderFrameObserver::WasShown() {
+ if (frame_) {
+ frame_->OnWasShown();
+ }
+}
+
+void CefRenderFrameObserver::DidFailProvisionalLoad() {
+ if (frame_) {
+ OnLoadError();
+ }
+}
+
+void CefRenderFrameObserver::DidFinishLoad() {
+ if (frame_) {
+ frame_->OnDidFinishLoad();
+ }
+}
+
+void CefRenderFrameObserver::WillDetach() {
+ if (frame_) {
+ frame_->OnDetached();
+ frame_ = nullptr;
+ }
+}
+
+void CefRenderFrameObserver::FocusedElementChanged(
+ const blink::WebElement& element) {
+ if (!frame_) {
+ return;
+ }
+
+ blink::WebLocalFrame* frame = render_frame()->GetWebFrame();
+ CefRefPtr<CefBrowserImpl> browserPtr =
+ CefBrowserImpl::GetBrowserForMainFrame(frame->Top());
+ if (!browserPtr) {
+ return;
+ }
+
+ CefRefPtr<CefRenderProcessHandler> handler;
+ CefRefPtr<CefApp> application = CefAppManager::Get()->GetApplication();
+ if (application) {
+ handler = application->GetRenderProcessHandler();
+ }
+ if (!handler) {
+ return;
+ }
+
+ CefRefPtr<CefFrameImpl> framePtr = browserPtr->GetWebFrameImpl(frame);
+
+ if (element.IsNull()) {
+ handler->OnFocusedNodeChanged(browserPtr.get(), framePtr.get(), nullptr);
+ return;
+ }
+
+ if (element.GetDocument().IsNull()) {
+ return;
+ }
+
+ CefRefPtr<CefDOMDocumentImpl> documentImpl =
+ new CefDOMDocumentImpl(browserPtr.get(), frame);
+ handler->OnFocusedNodeChanged(browserPtr.get(), framePtr.get(),
+ documentImpl->GetOrCreateNode(element));
+ documentImpl->Detach();
+}
+
+void CefRenderFrameObserver::DraggableRegionsChanged() {
+ if (frame_) {
+ frame_->OnDraggableRegionsChanged();
+ }
+}
+
+void CefRenderFrameObserver::DidCreateScriptContext(
+ v8::Handle<v8::Context> context,
+ int world_id) {
+ if (!frame_) {
+ return;
+ }
+
+ blink::WebLocalFrame* frame = render_frame()->GetWebFrame();
+ CefRefPtr<CefBrowserImpl> browserPtr =
+ CefBrowserImpl::GetBrowserForMainFrame(frame->Top());
+ if (!browserPtr) {
+ return;
+ }
+
+ CefRefPtr<CefRenderProcessHandler> handler;
+ CefRefPtr<CefApp> application = CefAppManager::Get()->GetApplication();
+ if (application) {
+ handler = application->GetRenderProcessHandler();
+ }
+
+ CefRefPtr<CefFrameImpl> framePtr = browserPtr->GetWebFrameImpl(frame);
+
+ if (handler) {
+ v8::Isolate* isolate = blink::MainThreadIsolate();
+ v8::HandleScope handle_scope(isolate);
+ v8::Context::Scope scope(context);
+ v8::MicrotasksScope microtasks_scope(isolate,
+ v8::MicrotasksScope::kRunMicrotasks);
+
+ CefRefPtr<CefV8Context> contextPtr(new CefV8ContextImpl(isolate, context));
+
+ handler->OnContextCreated(browserPtr.get(), framePtr.get(), contextPtr);
+ }
+
+ // Do this last, in case the client callback modified the window object.
+ framePtr->OnContextCreated(context);
+}
+
+void CefRenderFrameObserver::WillReleaseScriptContext(
+ v8::Handle<v8::Context> context,
+ int world_id) {
+ blink::WebLocalFrame* frame = render_frame()->GetWebFrame();
+ CefRefPtr<CefBrowserImpl> browserPtr =
+ CefBrowserImpl::GetBrowserForMainFrame(frame->Top());
+ if (!browserPtr) {
+ return;
+ }
+
+ CefRefPtr<CefRenderProcessHandler> handler;
+ CefRefPtr<CefApp> application = CefAppManager::Get()->GetApplication();
+ if (application) {
+ handler = application->GetRenderProcessHandler();
+ }
+
+ CefRefPtr<CefFrameImpl> framePtr = browserPtr->GetWebFrameImpl(frame);
+
+ if (handler) {
+ v8::Isolate* isolate = blink::MainThreadIsolate();
+ v8::HandleScope handle_scope(isolate);
+
+ // The released context should not be used for script execution.
+ // Depending on how the context is released this may or may not already
+ // be set.
+ blink_glue::CefScriptForbiddenScope forbidScript;
+
+ CefRefPtr<CefV8Context> contextPtr(new CefV8ContextImpl(isolate, context));
+
+ handler->OnContextReleased(browserPtr.get(), framePtr.get(), contextPtr);
+ }
+
+ framePtr->OnContextReleased();
+
+ CefV8ReleaseContext(context);
+}
+
+void CefRenderFrameObserver::OnDestruct() {
+ delete this;
+}
+
+void CefRenderFrameObserver::OnInterfaceRequestForFrame(
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle* interface_pipe) {
+ registry_.TryBindInterface(interface_name, interface_pipe);
+}
+
+bool CefRenderFrameObserver::OnAssociatedInterfaceRequestForFrame(
+ const std::string& interface_name,
+ mojo::ScopedInterfaceEndpointHandle* handle) {
+ return associated_interfaces_.TryBindInterface(interface_name, handle);
+}
+
+void CefRenderFrameObserver::AttachFrame(CefFrameImpl* frame) {
+ DCHECK(frame);
+ DCHECK(!frame_);
+ frame_ = frame;
+ frame_->OnAttached();
+}
+
+void CefRenderFrameObserver::OnLoadStart() {
+ CefRefPtr<CefApp> app = CefAppManager::Get()->GetApplication();
+ if (app.get()) {
+ CefRefPtr<CefRenderProcessHandler> handler = app->GetRenderProcessHandler();
+ if (handler.get()) {
+ CefRefPtr<CefLoadHandler> load_handler = handler->GetLoadHandler();
+ if (load_handler.get()) {
+ blink::WebLocalFrame* frame = render_frame()->GetWebFrame();
+ CefRefPtr<CefBrowserImpl> browserPtr =
+ CefBrowserImpl::GetBrowserForMainFrame(frame->Top());
+ load_handler->OnLoadStart(browserPtr.get(), frame_, TT_EXPLICIT);
+ }
+ }
+ }
+}
+
+void CefRenderFrameObserver::OnLoadError() {
+ CefRefPtr<CefApp> app = CefAppManager::Get()->GetApplication();
+ if (app.get()) {
+ CefRefPtr<CefRenderProcessHandler> handler = app->GetRenderProcessHandler();
+ if (handler.get()) {
+ CefRefPtr<CefLoadHandler> load_handler = handler->GetLoadHandler();
+ // Error codes were removed from DidFailProvisionalLoad() so we now always
+ // pass the same value.
+ if (load_handler.get()) {
+ const cef_errorcode_t errorCode =
+ static_cast<cef_errorcode_t>(net::ERR_ABORTED);
+ const std::string& errorText = net::ErrorToString(errorCode);
+ blink::WebLocalFrame* frame = render_frame()->GetWebFrame();
+ CefRefPtr<CefBrowserImpl> browserPtr =
+ CefBrowserImpl::GetBrowserForMainFrame(frame->Top());
+ load_handler->OnLoadError(browserPtr.get(), frame_, errorCode,
+ errorText, frame_->GetURL());
+ }
+ }
+ }
+}
+
+// Enable deprecation warnings on Windows. See http://crbug.com/585142.
+#if BUILDFLAG(IS_WIN)
+#if defined(__clang__)
+#pragma GCC diagnostic pop
+#else
+#pragma warning(pop)
+#endif
+#endif
diff --git a/libcef/renderer/render_frame_observer.h b/libcef/renderer/render_frame_observer.h
new file mode 100644
index 00000000..49648324
--- /dev/null
+++ b/libcef/renderer/render_frame_observer.h
@@ -0,0 +1,70 @@
+// Copyright 2014 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#ifndef LIBCEF_RENDERER_RENDER_FRAME_OBSERVER_H_
+#define LIBCEF_RENDERER_RENDER_FRAME_OBSERVER_H_
+
+#include "content/public/renderer/render_frame_observer.h"
+
+#include "services/service_manager/public/cpp/binder_registry.h"
+#include "third_party/blink/public/common/associated_interfaces/associated_interface_registry.h"
+
+namespace content {
+class RenderFrame;
+class RenderView;
+} // namespace content
+
+class CefFrameImpl;
+
+class CefRenderFrameObserver : public content::RenderFrameObserver {
+ public:
+ explicit CefRenderFrameObserver(content::RenderFrame* render_frame);
+
+ CefRenderFrameObserver(const CefRenderFrameObserver&) = delete;
+ CefRenderFrameObserver& operator=(const CefRenderFrameObserver&) = delete;
+
+ ~CefRenderFrameObserver() override;
+
+ // RenderFrameObserver methods:
+ void WasShown() override;
+ void DidCommitProvisionalLoad(ui::PageTransition transition) override;
+ void DidFailProvisionalLoad() override;
+ void DidFinishLoad() override;
+ void WillDetach() override;
+ void FocusedElementChanged(const blink::WebElement& element) override;
+ void DraggableRegionsChanged() override;
+ void DidCreateScriptContext(v8::Handle<v8::Context> context,
+ int world_id) override;
+ void WillReleaseScriptContext(v8::Handle<v8::Context> context,
+ int world_id) override;
+ void OnDestruct() override;
+ void OnInterfaceRequestForFrame(
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle* interface_pipe) override;
+ bool OnAssociatedInterfaceRequestForFrame(
+ const std::string& interface_name,
+ mojo::ScopedInterfaceEndpointHandle* handle) override;
+
+ service_manager::BinderRegistry* registry() { return &registry_; }
+ blink::AssociatedInterfaceRegistry* associated_interfaces() {
+ return &associated_interfaces_;
+ }
+
+ void AttachFrame(CefFrameImpl* frame);
+
+ private:
+ void OnLoadStart();
+ void OnLoadError();
+
+ CefFrameImpl* frame_ = nullptr;
+
+ service_manager::BinderRegistry registry_;
+
+ // For interfaces which must be associated with some IPC::ChannelProxy,
+ // meaning that messages on the interface retain FIFO with respect to legacy
+ // Chrome IPC messages sent or dispatched on the channel.
+ blink::AssociatedInterfaceRegistry associated_interfaces_;
+};
+
+#endif // LIBCEF_RENDERER_RENDER_FRAME_OBSERVER_H_
diff --git a/libcef/renderer/render_frame_util.cc b/libcef/renderer/render_frame_util.cc
new file mode 100644
index 00000000..62d95496
--- /dev/null
+++ b/libcef/renderer/render_frame_util.cc
@@ -0,0 +1,45 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors.
+// Portions copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "libcef/renderer/render_frame_util.h"
+
+#include "libcef/common/frame_util.h"
+#include "libcef/renderer/blink_glue.h"
+
+#include "base/logging.h"
+#include "content/public/renderer/render_thread.h"
+#include "content/renderer/render_frame_impl.h"
+#include "third_party/blink/public/web/web_local_frame.h"
+
+namespace render_frame_util {
+
+int64_t GetIdentifier(blink::WebLocalFrame* frame) {
+ // Each WebFrame will have an associated RenderFrame. The RenderFrame
+ // routing IDs are unique within a given renderer process.
+ content::RenderFrame* render_frame =
+ content::RenderFrame::FromWebFrame(frame);
+ return frame_util::MakeFrameId(content::RenderThread::Get()->GetClientId(),
+ render_frame->GetRoutingID());
+}
+
+std::string GetName(blink::WebLocalFrame* frame) {
+ DCHECK(frame);
+ // Return the assigned name if it is non-empty. This represents the name
+ // property on the frame DOM element. If the assigned name is empty, revert to
+ // the internal unique name. This matches the logic in
+ // CefFrameHostImpl::RefreshAttributes.
+ if (frame->AssignedName().length() > 0) {
+ return frame->AssignedName().Utf8();
+ }
+ content::RenderFrameImpl* render_frame =
+ content::RenderFrameImpl::FromWebFrame(frame);
+ DCHECK(render_frame);
+ if (render_frame) {
+ return render_frame->unique_name();
+ }
+ return std::string();
+}
+
+} // namespace render_frame_util
diff --git a/libcef/renderer/render_frame_util.h b/libcef/renderer/render_frame_util.h
new file mode 100644
index 00000000..ee451e51
--- /dev/null
+++ b/libcef/renderer/render_frame_util.h
@@ -0,0 +1,24 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors.
+// Portions copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_RENDERER_RENDER_FRAME_UTIL_H_
+#define CEF_LIBCEF_RENDERER_RENDER_FRAME_UTIL_H_
+
+#include <stdint.h>
+
+#include <string>
+
+namespace blink {
+class WebLocalFrame;
+}
+
+namespace render_frame_util {
+
+int64_t GetIdentifier(blink::WebLocalFrame* frame);
+std::string GetName(blink::WebLocalFrame* frame);
+
+} // namespace render_frame_util
+
+#endif // CEF_LIBCEF_RENDERER_RENDER_FRAME_UTIL_H_
diff --git a/libcef/renderer/render_manager.cc b/libcef/renderer/render_manager.cc
new file mode 100644
index 00000000..77e2c59d
--- /dev/null
+++ b/libcef/renderer/render_manager.cc
@@ -0,0 +1,411 @@
+// Copyright 2015 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#include "libcef/renderer/render_manager.h"
+
+#include <tuple>
+
+#include "build/build_config.h"
+
+// Enable deprecation warnings on Windows. See http://crbug.com/585142.
+#if BUILDFLAG(IS_WIN)
+#if defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic error "-Wdeprecated-declarations"
+#else
+#pragma warning(push)
+#pragma warning(default : 4996)
+#endif
+#endif
+
+#include "libcef/common/app_manager.h"
+#include "libcef/common/cef_switches.h"
+#include "libcef/common/net/scheme_info.h"
+#include "libcef/common/values_impl.h"
+#include "libcef/renderer/blink_glue.h"
+#include "libcef/renderer/browser_impl.h"
+#include "libcef/renderer/render_frame_observer.h"
+#include "libcef/renderer/thread_util.h"
+#include "libcef/renderer/v8_impl.h"
+
+#include "base/command_line.h"
+#include "base/strings/string_number_conversions.h"
+#include "cef/libcef/common/mojom/cef.mojom.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/renderer/render_frame.h"
+#include "content/public/renderer/render_thread.h"
+#include "extensions/common/switches.h"
+#include "mojo/public/cpp/bindings/binder_map.h"
+#include "services/network/public/mojom/cors_origin_pattern.mojom.h"
+#include "third_party/blink/public/platform/web_string.h"
+#include "third_party/blink/public/platform/web_url.h"
+#include "third_party/blink/public/web/web_frame.h"
+#include "third_party/blink/public/web/web_security_policy.h"
+#include "third_party/blink/public/web/web_view.h"
+#include "third_party/blink/public/web/web_view_observer.h"
+
+namespace {
+
+CefRenderManager* g_manager = nullptr;
+
+} // namespace
+
+// Placeholder object for guest views.
+class CefGuestView : public blink::WebViewObserver {
+ public:
+ CefGuestView(CefRenderManager* manager,
+ blink::WebView* web_view,
+ bool is_windowless)
+ : blink::WebViewObserver(web_view),
+ manager_(manager),
+ is_windowless_(is_windowless) {}
+
+ bool is_windowless() const { return is_windowless_; }
+
+ private:
+ // RenderViewObserver methods.
+ void OnDestruct() override { manager_->OnGuestViewDestroyed(this); }
+
+ CefRenderManager* const manager_;
+ const bool is_windowless_;
+};
+
+CefRenderManager::CefRenderManager() {
+ DCHECK(!g_manager);
+ g_manager = this;
+}
+
+CefRenderManager::~CefRenderManager() {
+ g_manager = nullptr;
+}
+
+// static
+CefRenderManager* CefRenderManager::Get() {
+ CEF_REQUIRE_RT_RETURN(nullptr);
+ return g_manager;
+}
+
+void CefRenderManager::RenderThreadConnected() {
+ // Retrieve the new render thread information synchronously.
+ auto params = cef::mojom::NewRenderThreadInfo::New();
+ GetBrowserManager()->GetNewRenderThreadInfo(&params);
+
+ // Cross-origin entries need to be added after WebKit is initialized.
+ if (params->cross_origin_whitelist_entries) {
+ cross_origin_whitelist_entries_.swap(
+ *params->cross_origin_whitelist_entries);
+ }
+
+ WebKitInitialized();
+}
+
+void CefRenderManager::RenderFrameCreated(
+ content::RenderFrame* render_frame,
+ CefRenderFrameObserver* render_frame_observer,
+ bool& browser_created,
+ absl::optional<bool>& is_windowless) {
+ auto browser = MaybeCreateBrowser(render_frame->GetWebView(), render_frame,
+ &browser_created, &is_windowless);
+ if (browser) {
+ // Attach the frame to the observer for message routing purposes.
+ render_frame_observer->AttachFrame(
+ browser->GetWebFrameImpl(render_frame->GetWebFrame()).get());
+ }
+}
+
+void CefRenderManager::WebViewCreated(blink::WebView* web_view,
+ bool& browser_created,
+ absl::optional<bool>& is_windowless) {
+ content::RenderFrame* render_frame = nullptr;
+ if (web_view->MainFrame()->IsWebLocalFrame()) {
+ render_frame = content::RenderFrame::FromWebFrame(
+ web_view->MainFrame()->ToWebLocalFrame());
+ }
+
+ MaybeCreateBrowser(web_view, render_frame, &browser_created, &is_windowless);
+}
+
+void CefRenderManager::DevToolsAgentAttached() {
+ ++devtools_agent_count_;
+}
+
+void CefRenderManager::DevToolsAgentDetached() {
+ --devtools_agent_count_;
+ if (devtools_agent_count_ == 0 && uncaught_exception_stack_size_ > 0) {
+ // When the last DevToolsAgent is detached the stack size is set to 0.
+ // Restore the user-specified stack size here.
+ CefV8SetUncaughtExceptionStackSize(uncaught_exception_stack_size_);
+ }
+}
+
+void CefRenderManager::ExposeInterfacesToBrowser(mojo::BinderMap* binders) {
+ auto task_runner = base::SequencedTaskRunner::GetCurrentDefault();
+
+ binders->Add<cef::mojom::RenderManager>(
+ base::BindRepeating(
+ [](CefRenderManager* render_manager,
+ mojo::PendingReceiver<cef::mojom::RenderManager> receiver) {
+ render_manager->BindReceiver(std::move(receiver));
+ },
+ base::Unretained(this)),
+ task_runner);
+}
+
+CefRefPtr<CefBrowserImpl> CefRenderManager::GetBrowserForView(
+ blink::WebView* view) {
+ BrowserMap::const_iterator it = browsers_.find(view);
+ if (it != browsers_.end()) {
+ return it->second;
+ }
+ return nullptr;
+}
+
+CefRefPtr<CefBrowserImpl> CefRenderManager::GetBrowserForMainFrame(
+ blink::WebFrame* frame) {
+ BrowserMap::const_iterator it = browsers_.begin();
+ for (; it != browsers_.end(); ++it) {
+ auto web_view = it->second->GetWebView();
+ if (web_view && web_view->MainFrame() == frame) {
+ return it->second;
+ }
+ }
+
+ return nullptr;
+}
+
+mojo::Remote<cef::mojom::BrowserManager>&
+CefRenderManager::GetBrowserManager() {
+ if (!browser_manager_) {
+ content::RenderThread::Get()->BindHostReceiver(
+ browser_manager_.BindNewPipeAndPassReceiver());
+ }
+ return browser_manager_;
+}
+
+// static
+bool CefRenderManager::IsExtensionProcess() {
+ return base::CommandLine::ForCurrentProcess()->HasSwitch(
+ extensions::switches::kExtensionProcess);
+}
+
+// static
+bool CefRenderManager::IsPdfProcess() {
+ return base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kPdfRenderer);
+}
+
+void CefRenderManager::BindReceiver(
+ mojo::PendingReceiver<cef::mojom::RenderManager> receiver) {
+ receivers_.Add(this, std::move(receiver));
+}
+
+void CefRenderManager::ModifyCrossOriginWhitelistEntry(
+ bool add,
+ cef::mojom::CrossOriginWhiteListEntryPtr entry) {
+ GURL gurl = GURL(entry->source_origin);
+ if (add) {
+ blink::WebSecurityPolicy::AddOriginAccessAllowListEntry(
+ gurl, blink::WebString::FromUTF8(entry->target_protocol),
+ blink::WebString::FromUTF8(entry->target_domain),
+ /*destination_port=*/0,
+ entry->allow_target_subdomains
+ ? network::mojom::CorsDomainMatchMode::kAllowSubdomains
+ : network::mojom::CorsDomainMatchMode::kDisallowSubdomains,
+ network::mojom::CorsPortMatchMode::kAllowAnyPort,
+ network::mojom::CorsOriginAccessMatchPriority::kDefaultPriority);
+ } else {
+ blink::WebSecurityPolicy::ClearOriginAccessListForOrigin(gurl);
+ }
+}
+
+void CefRenderManager::ClearCrossOriginWhitelist() {
+ blink::WebSecurityPolicy::ClearOriginAccessList();
+}
+
+void CefRenderManager::WebKitInitialized() {
+ const base::CommandLine* command_line =
+ base::CommandLine::ForCurrentProcess();
+
+ // Create global objects associated with the default Isolate.
+ CefV8IsolateCreated();
+
+ const CefAppManager::SchemeInfoList* schemes =
+ CefAppManager::Get()->GetCustomSchemes();
+ if (!schemes->empty()) {
+ // Register the custom schemes. Some attributes are excluded here because
+ // they use url/url_util.h APIs instead.
+ CefAppManager::SchemeInfoList::const_iterator it = schemes->begin();
+ for (; it != schemes->end(); ++it) {
+ const CefSchemeInfo& info = *it;
+ const blink::WebString& scheme =
+ blink::WebString::FromUTF8(info.scheme_name);
+ if (info.is_display_isolated) {
+ blink::WebSecurityPolicy::RegisterURLSchemeAsDisplayIsolated(scheme);
+ }
+ if (info.is_fetch_enabled) {
+ blink_glue::RegisterURLSchemeAsSupportingFetchAPI(scheme);
+ }
+ }
+ }
+
+ if (!cross_origin_whitelist_entries_.empty()) {
+ // Add the cross-origin white list entries.
+ for (auto& entry : cross_origin_whitelist_entries_) {
+ ModifyCrossOriginWhitelistEntry(/*add=*/true, std::move(entry));
+ }
+ cross_origin_whitelist_entries_.clear();
+ }
+
+ // The number of stack trace frames to capture for uncaught exceptions.
+ if (command_line->HasSwitch(switches::kUncaughtExceptionStackSize)) {
+ int uncaught_exception_stack_size = 0;
+ base::StringToInt(command_line->GetSwitchValueASCII(
+ switches::kUncaughtExceptionStackSize),
+ &uncaught_exception_stack_size);
+
+ if (uncaught_exception_stack_size > 0) {
+ uncaught_exception_stack_size_ = uncaught_exception_stack_size;
+ CefV8SetUncaughtExceptionStackSize(uncaught_exception_stack_size_);
+ }
+ }
+
+ // Notify the render process handler.
+ CefRefPtr<CefApp> application = CefAppManager::Get()->GetApplication();
+ if (application.get()) {
+ CefRefPtr<CefRenderProcessHandler> handler =
+ application->GetRenderProcessHandler();
+ if (handler.get()) {
+ handler->OnWebKitInitialized();
+ }
+ }
+}
+
+CefRefPtr<CefBrowserImpl> CefRenderManager::MaybeCreateBrowser(
+ blink::WebView* web_view,
+ content::RenderFrame* render_frame,
+ bool* browser_created,
+ absl::optional<bool>* is_windowless) {
+ if (browser_created) {
+ *browser_created = false;
+ }
+
+ if (!web_view || !render_frame) {
+ return nullptr;
+ }
+
+ // Don't create another browser or guest view object if one already exists for
+ // the view.
+ auto browser = GetBrowserForView(web_view);
+ if (browser) {
+ if (is_windowless) {
+ *is_windowless = browser->is_windowless();
+ }
+ return browser;
+ }
+
+ auto guest_view = GetGuestViewForView(web_view);
+ if (guest_view) {
+ if (is_windowless) {
+ *is_windowless = guest_view->is_windowless();
+ }
+ return nullptr;
+ }
+
+ const bool is_pdf = IsPdfProcess();
+
+ auto params = cef::mojom::NewBrowserInfo::New();
+ if (!is_pdf) {
+ // Retrieve browser information synchronously.
+ GetBrowserManager()->GetNewBrowserInfo(render_frame->GetRoutingID(),
+ &params);
+ if (params->browser_id == 0) {
+ // The popup may have been canceled during creation.
+ return nullptr;
+ }
+ }
+
+ if (is_windowless) {
+ *is_windowless = params->is_windowless;
+ }
+
+ if (is_pdf || params->is_guest_view || params->browser_id < 0) {
+ // Don't create a CefBrowser for a PDF renderer, guest view, or if the new
+ // browser info response has timed out.
+ guest_views_.insert(std::make_pair(
+ web_view,
+ std::make_unique<CefGuestView>(this, web_view, params->is_windowless)));
+ return nullptr;
+ }
+
+ browser = new CefBrowserImpl(web_view, params->browser_id, params->is_popup,
+ params->is_windowless);
+ browsers_.insert(std::make_pair(web_view, browser));
+
+ // Notify the render process handler.
+ CefRefPtr<CefApp> application = CefAppManager::Get()->GetApplication();
+ if (application.get()) {
+ CefRefPtr<CefRenderProcessHandler> handler =
+ application->GetRenderProcessHandler();
+ if (handler.get()) {
+ CefRefPtr<CefDictionaryValueImpl> dictValuePtr;
+ if (params->extra_info) {
+ dictValuePtr =
+ new CefDictionaryValueImpl(std::move(*params->extra_info),
+ /*read_only=*/true);
+ }
+ handler->OnBrowserCreated(browser.get(), dictValuePtr.get());
+ }
+ }
+
+ if (browser_created) {
+ *browser_created = true;
+ }
+
+ return browser;
+}
+
+void CefRenderManager::OnBrowserDestroyed(CefBrowserImpl* browser) {
+ BrowserMap::iterator it = browsers_.begin();
+ for (; it != browsers_.end(); ++it) {
+ if (it->second.get() == browser) {
+ browsers_.erase(it);
+ return;
+ }
+ }
+
+ // No browser was found in the map.
+ NOTREACHED();
+}
+
+CefGuestView* CefRenderManager::GetGuestViewForView(blink::WebView* view) {
+ CEF_REQUIRE_RT_RETURN(nullptr);
+
+ GuestViewMap::const_iterator it = guest_views_.find(view);
+ if (it != guest_views_.end()) {
+ return it->second.get();
+ }
+ return nullptr;
+}
+
+void CefRenderManager::OnGuestViewDestroyed(CefGuestView* guest_view) {
+ GuestViewMap::iterator it = guest_views_.begin();
+ for (; it != guest_views_.end(); ++it) {
+ if (it->second.get() == guest_view) {
+ guest_views_.erase(it);
+ return;
+ }
+ }
+
+ // No guest view was found in the map.
+ NOTREACHED();
+}
+
+// Enable deprecation warnings on Windows. See http://crbug.com/585142.
+#if BUILDFLAG(IS_WIN)
+#if defined(__clang__)
+#pragma GCC diagnostic pop
+#else
+#pragma warning(pop)
+#endif
+#endif
diff --git a/libcef/renderer/render_manager.h b/libcef/renderer/render_manager.h
new file mode 100644
index 00000000..754ad2a8
--- /dev/null
+++ b/libcef/renderer/render_manager.h
@@ -0,0 +1,131 @@
+// Copyright 2015 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_RENDERER_RENDER_MANAGER_H_
+#define CEF_LIBCEF_RENDERER_RENDER_MANAGER_H_
+#pragma once
+
+#include <map>
+#include <memory>
+
+#include "include/internal/cef_ptr.h"
+
+#include "cef/libcef/common/mojom/cef.mojom.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/receiver_set.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+
+namespace blink {
+class WebFrame;
+class WebView;
+} // namespace blink
+
+namespace content {
+class RenderFrame;
+} // namespace content
+
+namespace mojo {
+class BinderMap;
+} // namespace mojo
+
+class CefBrowserImpl;
+class CefGuestView;
+class CefRenderFrameObserver;
+
+// Singleton object for managing BrowserImpl instances. Only accessed on the
+// main renderer thread.
+class CefRenderManager : public cef::mojom::RenderManager {
+ public:
+ CefRenderManager();
+
+ CefRenderManager(const CefRenderManager&) = delete;
+ CefRenderManager& operator=(const CefRenderManager&) = delete;
+
+ ~CefRenderManager();
+
+ // Returns this singleton instance of this class.
+ static CefRenderManager* Get();
+
+ // Called from ContentRendererClient methods of the same name.
+ void RenderThreadConnected();
+ void RenderFrameCreated(content::RenderFrame* render_frame,
+ CefRenderFrameObserver* render_frame_observer,
+ bool& browser_created,
+ absl::optional<bool>& is_windowless);
+ void WebViewCreated(blink::WebView* web_view,
+ bool& browser_created,
+ absl::optional<bool>& is_windowless);
+ void DevToolsAgentAttached();
+ void DevToolsAgentDetached();
+ void ExposeInterfacesToBrowser(mojo::BinderMap* binders);
+
+ // Returns the browser associated with the specified RenderView.
+ CefRefPtr<CefBrowserImpl> GetBrowserForView(blink::WebView* view);
+
+ // Returns the browser associated with the specified main WebFrame.
+ CefRefPtr<CefBrowserImpl> GetBrowserForMainFrame(blink::WebFrame* frame);
+
+ // Connects to CefBrowserManager in the browser process.
+ mojo::Remote<cef::mojom::BrowserManager>& GetBrowserManager();
+
+ // Returns true if this renderer process is hosting an extension.
+ static bool IsExtensionProcess();
+
+ // Returns true if this renderer process is hosting a PDF.
+ static bool IsPdfProcess();
+
+ private:
+ friend class CefBrowserImpl;
+ friend class CefGuestView;
+
+ // Binds receivers for the RenderManager interface.
+ void BindReceiver(mojo::PendingReceiver<cef::mojom::RenderManager> receiver);
+
+ // cef::mojom::RenderManager methods:
+ void ModifyCrossOriginWhitelistEntry(
+ bool add,
+ cef::mojom::CrossOriginWhiteListEntryPtr entry) override;
+ void ClearCrossOriginWhitelist() override;
+
+ void WebKitInitialized();
+
+ // Maybe create a new browser object, return the existing one, or return
+ // nullptr for guest views.
+ CefRefPtr<CefBrowserImpl> MaybeCreateBrowser(
+ blink::WebView* web_view,
+ content::RenderFrame* render_frame,
+ bool* browser_created,
+ absl::optional<bool>* is_windowless);
+
+ // Called from CefBrowserImpl::OnDestruct().
+ void OnBrowserDestroyed(CefBrowserImpl* browser);
+
+ // Returns the guest view associated with the specified RenderView if any.
+ CefGuestView* GetGuestViewForView(blink::WebView* view);
+
+ // Called from CefGuestView::OnDestruct().
+ void OnGuestViewDestroyed(CefGuestView* guest_view);
+
+ // Map of RenderView pointers to CefBrowserImpl references.
+ using BrowserMap = std::map<blink::WebView*, CefRefPtr<CefBrowserImpl>>;
+ BrowserMap browsers_;
+
+ // Map of RenderView poiners to CefGuestView implementations.
+ using GuestViewMap = std::map<blink::WebView*, std::unique_ptr<CefGuestView>>;
+ GuestViewMap guest_views_;
+
+ // Cross-origin white list entries that need to be registered with WebKit.
+ std::vector<cef::mojom::CrossOriginWhiteListEntryPtr>
+ cross_origin_whitelist_entries_;
+
+ int devtools_agent_count_ = 0;
+ int uncaught_exception_stack_size_ = 0;
+
+ mojo::ReceiverSet<cef::mojom::RenderManager> receivers_;
+
+ mojo::Remote<cef::mojom::BrowserManager> browser_manager_;
+};
+
+#endif // CEF_LIBCEF_RENDERER_RENDER_MANAGER_H_
diff --git a/libcef/renderer/render_urlrequest_impl.cc b/libcef/renderer/render_urlrequest_impl.cc
new file mode 100644
index 00000000..96aae6e0
--- /dev/null
+++ b/libcef/renderer/render_urlrequest_impl.cc
@@ -0,0 +1,501 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#include "libcef/renderer/render_urlrequest_impl.h"
+
+#include <stdint.h>
+
+#include "libcef/common/request_impl.h"
+#include "libcef/common/response_impl.h"
+#include "libcef/renderer/blink_glue.h"
+#include "libcef/renderer/frame_impl.h"
+#include "libcef/renderer/thread_util.h"
+
+#include "base/logging.h"
+#include "net/base/request_priority.h"
+#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom.h"
+#include "third_party/blink/public/mojom/loader/resource_load_info.mojom.h"
+#include "third_party/blink/public/platform/resource_load_info_notifier_wrapper.h"
+#include "third_party/blink/public/platform/web_security_origin.h"
+#include "third_party/blink/public/platform/web_string.h"
+#include "third_party/blink/public/platform/web_url.h"
+#include "third_party/blink/public/platform/web_url_error.h"
+#include "third_party/blink/public/platform/web_url_loader.h"
+#include "third_party/blink/public/platform/web_url_loader_client.h"
+#include "third_party/blink/public/platform/web_url_request.h"
+#include "third_party/blink/public/platform/web_url_request_extra_data.h"
+#include "third_party/blink/public/platform/web_url_response.h"
+
+using blink::WebString;
+using blink::WebURL;
+using blink::WebURLError;
+using blink::WebURLLoader;
+using blink::WebURLRequest;
+using blink::WebURLResponse;
+
+namespace {
+
+class CefWebURLLoaderClient : public blink::WebURLLoaderClient {
+ public:
+ CefWebURLLoaderClient(CefRenderURLRequest::Context* context,
+ int request_flags);
+ ~CefWebURLLoaderClient() override;
+
+ // blink::WebURLLoaderClient methods.
+ void DidSendData(uint64_t bytes_sent,
+ uint64_t total_bytes_to_be_sent) override;
+ void DidReceiveResponse(const WebURLResponse& response) override;
+ void DidReceiveData(const char* data, int dataLength) override;
+ void DidFinishLoading(
+ base::TimeTicks finish_time,
+ int64_t total_encoded_data_length,
+ uint64_t total_encoded_body_length,
+ int64_t total_decoded_body_length,
+ bool should_report_corb_blocking,
+ absl::optional<bool> pervasive_payload_requested) override;
+ void DidFail(const WebURLError&,
+ base::TimeTicks finish_time,
+ int64_t total_encoded_data_length,
+ uint64_t total_encoded_body_length,
+ int64_t total_decoded_body_length) override;
+ void DidStartLoadingResponseBody(
+ mojo::ScopedDataPipeConsumerHandle response_body) override;
+ bool WillFollowRedirect(const WebURL& new_url,
+ const net::SiteForCookies& new_site_for_cookies,
+ const WebString& new_referrer,
+ network::mojom::ReferrerPolicy new_referrer_policy,
+ const WebString& new_method,
+ const WebURLResponse& passed_redirect_response,
+ bool& report_raw_headers,
+ std::vector<std::string>* removed_headers,
+ bool insecure_scheme_was_upgraded) override;
+
+ protected:
+ // The context_ pointer will outlive this object.
+ CefRenderURLRequest::Context* context_;
+ int request_flags_;
+};
+
+} // namespace
+
+// CefRenderURLRequest::Context -----------------------------------------------
+
+class CefRenderURLRequest::Context
+ : public base::RefCountedThreadSafe<CefRenderURLRequest::Context> {
+ public:
+ Context(CefRefPtr<CefRenderURLRequest> url_request,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefURLRequestClient> client)
+ : url_request_(url_request),
+ frame_(frame),
+ request_(request),
+ client_(client),
+ status_(UR_IO_PENDING),
+ error_code_(ERR_NONE),
+ body_watcher_(FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::MANUAL),
+ response_was_cached_(false),
+ upload_data_size_(0),
+ got_upload_progress_complete_(false),
+ download_data_received_(0),
+ download_data_total_(-1) {
+ // Mark the request as read-only.
+ static_cast<CefRequestImpl*>(request_.get())->SetReadOnly(true);
+ }
+
+ bool Start() {
+ GURL url = GURL(request_->GetURL().ToString());
+ if (!url.is_valid()) {
+ return false;
+ }
+
+ url_client_.reset(new CefWebURLLoaderClient(this, request_->GetFlags()));
+
+ std::unique_ptr<network::ResourceRequest> resource_request =
+ std::make_unique<network::ResourceRequest>();
+ static_cast<CefRequestImpl*>(request_.get())
+ ->Get(resource_request.get(), false);
+ resource_request->priority = net::MEDIUM;
+
+ // Behave the same as a subresource load.
+ resource_request->resource_type =
+ static_cast<int>(blink::mojom::ResourceType::kSubResource);
+
+ // Need load timing info for WebURLLoaderImpl::PopulateURLResponse to
+ // properly set cached status.
+ resource_request->enable_load_timing = true;
+
+ // Set the origin to match the request. The requirement for an origin is
+ // DCHECK'd in ResourceDispatcherHostImpl::ContinuePendingBeginRequest.
+ resource_request->request_initiator = url::Origin::Create(url);
+
+ if (request_->GetFlags() & UR_FLAG_ALLOW_STORED_CREDENTIALS) {
+ // Include SameSite cookies.
+ resource_request->site_for_cookies =
+ net::SiteForCookies::FromOrigin(*resource_request->request_initiator);
+ }
+
+ if (resource_request->request_body) {
+ const auto& elements = *resource_request->request_body->elements();
+ if (elements.size() > 0) {
+ const auto& element = elements[0];
+ if (element.type() == network::DataElement::Tag::kBytes) {
+ const auto& bytes_element = element.As<network::DataElementBytes>();
+ upload_data_size_ = bytes_element.bytes().size();
+ }
+ }
+ }
+
+ auto frame_impl = static_cast<CefFrameImpl*>(frame_.get());
+ loader_ = frame_impl->CreateURLLoader();
+ loader_->LoadAsynchronously(
+ std::move(resource_request), /*extra_data=*/nullptr,
+ /*no_mime_sniffing=*/false,
+ frame_impl->CreateResourceLoadInfoNotifierWrapper(), url_client_.get());
+ return true;
+ }
+
+ void Cancel() {
+ // The request may already be complete.
+ if (!loader_.get() || status_ != UR_IO_PENDING) {
+ return;
+ }
+
+ status_ = UR_CANCELED;
+ error_code_ = ERR_ABORTED;
+
+ // Will result in a call to OnError().
+ loader_->Cancel();
+ }
+
+ void OnStopRedirect(const WebURL& redirect_url,
+ const WebURLResponse& response) {
+ response_was_cached_ = blink_glue::ResponseWasCached(response);
+ response_ = CefResponse::Create();
+ CefResponseImpl* responseImpl =
+ static_cast<CefResponseImpl*>(response_.get());
+
+ // In case of StopOnRedirect we only set these fields. Everything else is
+ // left blank. This also replicates the behaviour of the browser urlrequest
+ // fetcher.
+ responseImpl->SetStatus(response.HttpStatusCode());
+ responseImpl->SetURL(redirect_url.GetString().Utf16());
+ responseImpl->SetReadOnly(true);
+
+ status_ = UR_CANCELED;
+ error_code_ = ERR_ABORTED;
+
+ OnComplete();
+ }
+
+ void OnResponse(const WebURLResponse& response) {
+ response_was_cached_ = blink_glue::ResponseWasCached(response);
+ response_ = CefResponse::Create();
+ CefResponseImpl* responseImpl =
+ static_cast<CefResponseImpl*>(response_.get());
+ responseImpl->Set(response);
+ responseImpl->SetReadOnly(true);
+
+ download_data_total_ = response.ExpectedContentLength();
+ }
+
+ void OnError(const WebURLError& error) {
+ if (status_ == UR_IO_PENDING) {
+ status_ = UR_FAILED;
+ error_code_ = static_cast<cef_errorcode_t>(error.reason());
+ }
+
+ OnComplete();
+ }
+
+ void OnComplete() {
+ if (body_handle_.is_valid()) {
+ return;
+ }
+
+ if (status_ == UR_IO_PENDING) {
+ status_ = UR_SUCCESS;
+ NotifyUploadProgressIfNecessary();
+ }
+
+ if (loader_.get()) {
+ loader_.reset(nullptr);
+ }
+
+ DCHECK(url_request_.get());
+ client_->OnRequestComplete(url_request_.get());
+
+ // This may result in the Context object being deleted.
+ url_request_ = nullptr;
+ }
+
+ void OnBodyReadable(MojoResult, const mojo::HandleSignalsState&) {
+ const void* buffer = nullptr;
+ uint32_t read_bytes = 0;
+ MojoResult result = body_handle_->BeginReadData(&buffer, &read_bytes,
+ MOJO_READ_DATA_FLAG_NONE);
+ if (result == MOJO_RESULT_SHOULD_WAIT) {
+ body_watcher_.ArmOrNotify();
+ return;
+ }
+
+ if (result == MOJO_RESULT_FAILED_PRECONDITION) {
+ // Whole body has been read.
+ body_handle_.reset();
+ body_watcher_.Cancel();
+ OnComplete();
+ return;
+ }
+
+ if (result != MOJO_RESULT_OK) {
+ // Something went wrong.
+ body_handle_.reset();
+ body_watcher_.Cancel();
+ OnComplete();
+ return;
+ }
+
+ download_data_received_ += read_bytes;
+
+ client_->OnDownloadProgress(url_request_.get(), download_data_received_,
+ download_data_total_);
+
+ if (!(request_->GetFlags() & UR_FLAG_NO_DOWNLOAD_DATA)) {
+ client_->OnDownloadData(url_request_.get(), buffer, read_bytes);
+ }
+
+ body_handle_->EndReadData(read_bytes);
+ body_watcher_.ArmOrNotify();
+ }
+
+ void OnStartLoadingResponseBody(
+ mojo::ScopedDataPipeConsumerHandle response_body) {
+ DCHECK(response_body);
+ DCHECK(!body_handle_);
+ body_handle_ = std::move(response_body);
+
+ body_watcher_.Watch(
+ body_handle_.get(),
+ MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
+ base::BindRepeating(&CefRenderURLRequest::Context::OnBodyReadable,
+ base::Unretained(this)));
+ body_watcher_.ArmOrNotify();
+ }
+
+ void OnDownloadProgress(int64_t current) {
+ DCHECK(url_request_.get());
+
+ NotifyUploadProgressIfNecessary();
+
+ download_data_received_ += current;
+ client_->OnDownloadProgress(url_request_.get(), download_data_received_,
+ download_data_total_);
+ }
+
+ void OnDownloadData(const char* data, int dataLength) {
+ DCHECK(url_request_.get());
+ client_->OnDownloadData(url_request_.get(), data, dataLength);
+ }
+
+ void OnUploadProgress(int64_t current, int64_t total) {
+ DCHECK(url_request_.get());
+ if (current == total) {
+ got_upload_progress_complete_ = true;
+ }
+ client_->OnUploadProgress(url_request_.get(), current, total);
+ }
+
+ CefRefPtr<CefRequest> request() const { return request_; }
+ CefRefPtr<CefURLRequestClient> client() const { return client_; }
+ CefURLRequest::Status status() const { return status_; }
+ CefURLRequest::ErrorCode error_code() const { return error_code_; }
+ CefRefPtr<CefResponse> response() const { return response_; }
+ bool response_was_cached() const { return response_was_cached_; }
+
+ private:
+ friend class base::RefCountedThreadSafe<CefRenderURLRequest::Context>;
+
+ virtual ~Context() {}
+
+ void NotifyUploadProgressIfNecessary() {
+ if (!got_upload_progress_complete_ && upload_data_size_ > 0) {
+ // Upload notifications are sent using a timer and may not occur if the
+ // request completes too quickly. We therefore send the notification here
+ // if necessary.
+ url_client_->DidSendData(upload_data_size_, upload_data_size_);
+ got_upload_progress_complete_ = true;
+ }
+ }
+
+ // Members only accessed on the initialization thread.
+ CefRefPtr<CefRenderURLRequest> url_request_;
+ CefRefPtr<CefFrame> frame_;
+ CefRefPtr<CefRequest> request_;
+ CefRefPtr<CefURLRequestClient> client_;
+ CefURLRequest::Status status_;
+ CefURLRequest::ErrorCode error_code_;
+ CefRefPtr<CefResponse> response_;
+ mojo::ScopedDataPipeConsumerHandle body_handle_;
+ mojo::SimpleWatcher body_watcher_;
+ bool response_was_cached_;
+ std::unique_ptr<blink::WebURLLoader> loader_;
+ std::unique_ptr<CefWebURLLoaderClient> url_client_;
+ int64_t upload_data_size_;
+ bool got_upload_progress_complete_;
+ int64_t download_data_received_;
+ int64_t download_data_total_;
+};
+
+// CefWebURLLoaderClient --------------------------------------------------
+
+namespace {
+
+CefWebURLLoaderClient::CefWebURLLoaderClient(
+ CefRenderURLRequest::Context* context,
+ int request_flags)
+ : context_(context), request_flags_(request_flags) {}
+
+CefWebURLLoaderClient::~CefWebURLLoaderClient() {}
+
+void CefWebURLLoaderClient::DidSendData(uint64_t bytes_sent,
+ uint64_t total_bytes_to_be_sent) {
+ if (request_flags_ & UR_FLAG_REPORT_UPLOAD_PROGRESS) {
+ context_->OnUploadProgress(bytes_sent, total_bytes_to_be_sent);
+ }
+}
+
+void CefWebURLLoaderClient::DidReceiveResponse(const WebURLResponse& response) {
+ context_->OnResponse(response);
+}
+
+void CefWebURLLoaderClient::DidReceiveData(const char* data, int dataLength) {
+ context_->OnDownloadProgress(dataLength);
+
+ if (!(request_flags_ & UR_FLAG_NO_DOWNLOAD_DATA)) {
+ context_->OnDownloadData(data, dataLength);
+ }
+}
+
+void CefWebURLLoaderClient::DidFinishLoading(
+ base::TimeTicks finish_time,
+ int64_t total_encoded_data_length,
+ uint64_t total_encoded_body_length,
+ int64_t total_decoded_body_length,
+ bool should_report_corb_blocking,
+ absl::optional<bool> pervasive_payload_requested) {
+ context_->OnComplete();
+}
+
+void CefWebURLLoaderClient::DidFail(const WebURLError& error,
+ base::TimeTicks finish_time,
+ int64_t total_encoded_data_length,
+ uint64_t total_encoded_body_length,
+ int64_t total_decoded_body_length) {
+ context_->OnError(error);
+}
+
+void CefWebURLLoaderClient::DidStartLoadingResponseBody(
+ mojo::ScopedDataPipeConsumerHandle response_body) {
+ context_->OnStartLoadingResponseBody(std::move(response_body));
+}
+
+bool CefWebURLLoaderClient::WillFollowRedirect(
+ const WebURL& new_url,
+ const net::SiteForCookies& new_site_for_cookies,
+ const WebString& new_referrer,
+ network::mojom::ReferrerPolicy new_referrer_policy,
+ const WebString& new_method,
+ const WebURLResponse& passed_redirect_response,
+ bool& report_raw_headers,
+ std::vector<std::string>* removed_headers,
+ bool insecure_scheme_was_upgraded) {
+ if (request_flags_ & UR_FLAG_STOP_ON_REDIRECT) {
+ context_->OnStopRedirect(new_url, passed_redirect_response);
+ return false;
+ }
+ return true;
+}
+
+} // namespace
+
+// CefRenderURLRequest --------------------------------------------------------
+
+CefRenderURLRequest::CefRenderURLRequest(
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefURLRequestClient> client) {
+ DCHECK(frame);
+ DCHECK(request);
+ DCHECK(client);
+ context_ = new Context(this, frame, request, client);
+}
+
+CefRenderURLRequest::~CefRenderURLRequest() {}
+
+bool CefRenderURLRequest::Start() {
+ if (!VerifyContext()) {
+ return false;
+ }
+ return context_->Start();
+}
+
+CefRefPtr<CefRequest> CefRenderURLRequest::GetRequest() {
+ if (!VerifyContext()) {
+ return nullptr;
+ }
+ return context_->request();
+}
+
+CefRefPtr<CefURLRequestClient> CefRenderURLRequest::GetClient() {
+ if (!VerifyContext()) {
+ return nullptr;
+ }
+ return context_->client();
+}
+
+CefURLRequest::Status CefRenderURLRequest::GetRequestStatus() {
+ if (!VerifyContext()) {
+ return UR_UNKNOWN;
+ }
+ return context_->status();
+}
+
+CefURLRequest::ErrorCode CefRenderURLRequest::GetRequestError() {
+ if (!VerifyContext()) {
+ return ERR_NONE;
+ }
+ return context_->error_code();
+}
+
+CefRefPtr<CefResponse> CefRenderURLRequest::GetResponse() {
+ if (!VerifyContext()) {
+ return nullptr;
+ }
+ return context_->response();
+}
+
+bool CefRenderURLRequest::ResponseWasCached() {
+ if (!VerifyContext()) {
+ return false;
+ }
+ return context_->response_was_cached();
+}
+
+void CefRenderURLRequest::Cancel() {
+ if (!VerifyContext()) {
+ return;
+ }
+ return context_->Cancel();
+}
+
+bool CefRenderURLRequest::VerifyContext() {
+ DCHECK(context_.get());
+ if (!CEF_CURRENTLY_ON_RT()) {
+ NOTREACHED() << "called on invalid thread";
+ return false;
+ }
+
+ return true;
+}
diff --git a/libcef/renderer/render_urlrequest_impl.h b/libcef/renderer/render_urlrequest_impl.h
new file mode 100644
index 00000000..a7058645
--- /dev/null
+++ b/libcef/renderer/render_urlrequest_impl.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_RENDERER_RENDER_URLREQUEST_IMPL_H_
+#define CEF_LIBCEF_RENDERER_RENDER_URLREQUEST_IMPL_H_
+
+#include "include/cef_frame.h"
+#include "include/cef_urlrequest.h"
+
+#include "base/memory/ref_counted.h"
+
+class CefRenderURLRequest : public CefURLRequest {
+ public:
+ class Context;
+
+ // If |frame| is nullptr the default URLLoaderFactory will be used. That
+ // factory only supports http(s) and blob requests that cannot be
+ // intercepted in the browser process.
+ CefRenderURLRequest(CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefURLRequestClient> client);
+ ~CefRenderURLRequest() override;
+
+ bool Start();
+
+ // CefURLRequest methods.
+ CefRefPtr<CefRequest> GetRequest() override;
+ CefRefPtr<CefURLRequestClient> GetClient() override;
+ Status GetRequestStatus() override;
+ ErrorCode GetRequestError() override;
+ CefRefPtr<CefResponse> GetResponse() override;
+ bool ResponseWasCached() override;
+ void Cancel() override;
+
+ private:
+ bool VerifyContext();
+
+ scoped_refptr<Context> context_;
+
+ IMPLEMENT_REFCOUNTING(CefRenderURLRequest);
+};
+
+#endif // CEF_LIBCEF_RENDERER_RENDER_URLREQUEST_IMPL_H_
diff --git a/libcef/renderer/thread_util.h b/libcef/renderer/thread_util.h
new file mode 100644
index 00000000..768a3b36
--- /dev/null
+++ b/libcef/renderer/thread_util.h
@@ -0,0 +1,59 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_RENDERER_THREAD_UTIL_H_
+#define CEF_LIBCEF_RENDERER_THREAD_UTIL_H_
+#pragma once
+
+#include "libcef/common/task_runner_manager.h"
+
+#include "base/location.h"
+#include "base/logging.h"
+#include "content/public/renderer/render_thread.h"
+
+#define CEF_CURRENTLY_ON_RT() (!!content::RenderThread::Get())
+
+#define CEF_REQUIRE_RT() DCHECK(CEF_CURRENTLY_ON_RT())
+
+#define CEF_REQUIRE_RT_RETURN(var) \
+ if (!CEF_CURRENTLY_ON_RT()) { \
+ NOTREACHED() << "called on invalid thread"; \
+ return var; \
+ }
+
+#define CEF_REQUIRE_RT_RETURN_VOID() \
+ if (!CEF_CURRENTLY_ON_RT()) { \
+ NOTREACHED() << "called on invalid thread"; \
+ return; \
+ }
+
+#define CEF_RENDER_TASK_RUNNER() \
+ (CefTaskRunnerManager::Get()->GetRenderTaskRunner())
+
+#define CEF_POST_TASK_RT(task) \
+ CEF_RENDER_TASK_RUNNER()->PostTask(FROM_HERE, task)
+#define CEF_POST_DELAYED_TASK_RT(task, delay_ms) \
+ CEF_RENDER_TASK_RUNNER()->PostDelayedTask(FROM_HERE, task, \
+ base::Milliseconds(delay_ms))
+
+// Use this template in conjuction with RefCountedThreadSafe when you want to
+// ensure that an object is deleted on the render thread.
+struct CefDeleteOnRenderThread {
+ template <typename T>
+ static void Destruct(const T* x) {
+ if (CEF_CURRENTLY_ON_RT()) {
+ delete x;
+ } else {
+ if (!CEF_RENDER_TASK_RUNNER()->DeleteSoon(FROM_HERE, x)) {
+#if defined(UNIT_TEST)
+ // Only logged under unit testing because leaks at shutdown
+ // are acceptable under normal circumstances.
+ LOG(ERROR) << "DeleteSoon failed on thread " << thread;
+#endif // UNIT_TEST
+ }
+ }
+ }
+};
+
+#endif // CEF_LIBCEF_RENDERER_THREAD_UTIL_H_
diff --git a/libcef/renderer/v8_impl.cc b/libcef/renderer/v8_impl.cc
new file mode 100644
index 00000000..d8c6534e
--- /dev/null
+++ b/libcef/renderer/v8_impl.cc
@@ -0,0 +1,2731 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+// MSVC++ requires this to be set before any other includes to get M_PI.
+// Otherwise there will be compile errors in wtf/MathExtras.h.
+#define _USE_MATH_DEFINES
+
+#include <map>
+#include <string>
+
+#include "base/command_line.h"
+#include "build/build_config.h"
+
+// Enable deprecation warnings for MSVC and Clang. See http://crbug.com/585142.
+#if BUILDFLAG(IS_WIN)
+#if defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic error "-Wdeprecated-declarations"
+#else
+#pragma warning(push)
+#pragma warning(default : 4996)
+#endif
+#endif
+
+#include "libcef/renderer/v8_impl.h"
+
+#include "libcef/common/app_manager.h"
+#include "libcef/common/cef_switches.h"
+#include "libcef/common/task_runner_impl.h"
+#include "libcef/common/tracker.h"
+#include "libcef/renderer/blink_glue.h"
+#include "libcef/renderer/browser_impl.h"
+#include "libcef/renderer/render_frame_util.h"
+#include "libcef/renderer/thread_util.h"
+
+#include "base/functional/bind.h"
+#include "base/lazy_instance.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/threading/thread_local.h"
+#include "third_party/blink/public/web/blink.h"
+#include "third_party/blink/public/web/web_frame.h"
+#include "third_party/blink/public/web/web_local_frame.h"
+#include "third_party/blink/public/web/web_script_controller.h"
+#include "url/gurl.h"
+
+namespace {
+
+static const char kCefTrackObject[] = "Cef::TrackObject";
+
+void MessageListenerCallbackImpl(v8::Handle<v8::Message> message,
+ v8::Handle<v8::Value> data);
+
+// The following *Private functions are convenience wrappers for methods on
+// v8::Object with the corresponding names.
+// Based on extensions/renderer/object_backed_native_handler.cc.
+
+void SetPrivate(v8::Local<v8::Context> context,
+ v8::Local<v8::Object> obj,
+ const char* key,
+ v8::Local<v8::Value> value) {
+ v8::Isolate* isolate = context->GetIsolate();
+ obj->SetPrivate(context,
+ v8::Private::ForApi(
+ isolate, v8::String::NewFromUtf8(
+ isolate, key, v8::NewStringType::kNormal)
+ .ToLocalChecked()),
+ value)
+ .FromJust();
+}
+
+bool GetPrivate(v8::Local<v8::Context> context,
+ v8::Local<v8::Object> obj,
+ const char* key,
+ v8::Local<v8::Value>* result) {
+ v8::Isolate* isolate = context->GetIsolate();
+ return obj
+ ->GetPrivate(context,
+ v8::Private::ForApi(
+ isolate, v8::String::NewFromUtf8(
+ isolate, key, v8::NewStringType::kNormal)
+ .ToLocalChecked()))
+ .ToLocal(result);
+}
+
+// Manages memory and state information associated with a single Isolate.
+class CefV8IsolateManager {
+ public:
+ CefV8IsolateManager()
+ : isolate_(v8::Isolate::GetCurrent()),
+ task_runner_(CEF_RENDER_TASK_RUNNER()),
+ message_listener_registered_(false),
+ worker_id_(0) {
+ DCHECK(isolate_);
+ DCHECK(task_runner_.get());
+ }
+ ~CefV8IsolateManager() {
+ DCHECK_EQ(isolate_, v8::Isolate::GetCurrent());
+ DCHECK(context_map_.empty());
+ }
+
+ scoped_refptr<CefV8ContextState> GetContextState(
+ v8::Local<v8::Context> context) {
+ DCHECK_EQ(isolate_, v8::Isolate::GetCurrent());
+ DCHECK(context.IsEmpty() || isolate_ == context->GetIsolate());
+
+ if (context.IsEmpty()) {
+ if (isolate_->InContext()) {
+ context = isolate_->GetCurrentContext();
+ } else {
+ return scoped_refptr<CefV8ContextState>();
+ }
+ }
+
+ int hash = context->Global()->GetIdentityHash();
+ ContextMap::const_iterator it = context_map_.find(hash);
+ if (it != context_map_.end()) {
+ return it->second;
+ }
+
+ scoped_refptr<CefV8ContextState> state = new CefV8ContextState();
+ context_map_.insert(std::make_pair(hash, state));
+
+ return state;
+ }
+
+ void ReleaseContext(v8::Local<v8::Context> context) {
+ DCHECK_EQ(isolate_, v8::Isolate::GetCurrent());
+ DCHECK_EQ(isolate_, context->GetIsolate());
+
+ int hash = context->Global()->GetIdentityHash();
+ ContextMap::iterator it = context_map_.find(hash);
+ if (it != context_map_.end()) {
+ it->second->Detach();
+ context_map_.erase(it);
+ }
+ }
+
+ void AddGlobalTrackObject(CefTrackNode* object) {
+ DCHECK_EQ(isolate_, v8::Isolate::GetCurrent());
+ global_manager_.Add(object);
+ }
+
+ void DeleteGlobalTrackObject(CefTrackNode* object) {
+ DCHECK_EQ(isolate_, v8::Isolate::GetCurrent());
+ global_manager_.Delete(object);
+ }
+
+ void SetUncaughtExceptionStackSize(int stack_size) {
+ if (stack_size <= 0) {
+ return;
+ }
+
+ if (!message_listener_registered_) {
+ isolate_->AddMessageListener(&MessageListenerCallbackImpl);
+ message_listener_registered_ = true;
+ }
+
+ isolate_->SetCaptureStackTraceForUncaughtExceptions(
+ true, stack_size, v8::StackTrace::kDetailed);
+ }
+
+ void SetWorkerAttributes(int worker_id, const GURL& worker_url) {
+ worker_id_ = worker_id;
+ worker_url_ = worker_url;
+ }
+
+ v8::Isolate* isolate() const { return isolate_; }
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner() const {
+ return task_runner_;
+ }
+
+ int worker_id() const { return worker_id_; }
+
+ const GURL& worker_url() const { return worker_url_; }
+
+ private:
+ v8::Isolate* isolate_;
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+
+ using ContextMap = std::map<int, scoped_refptr<CefV8ContextState>>;
+ ContextMap context_map_;
+
+ // Used for globally tracked objects that are not associated with a particular
+ // context.
+ CefTrackManager global_manager_;
+
+ // True if the message listener has been registered.
+ bool message_listener_registered_;
+
+ // Attributes associated with WebWorker threads.
+ int worker_id_;
+ GURL worker_url_;
+};
+
+// Chromium uses the default Isolate for the main render process thread and a
+// new Isolate for each WebWorker thread. Continue this pattern by tracking
+// Isolate information on a per-thread basis. This implementation will need to
+// be re-worked (perhaps using a map keyed on v8::Isolate::GetCurrent()) if
+// in the future Chromium begins using the same Isolate across multiple threads.
+class CefV8StateManager {
+ public:
+ CefV8StateManager() {}
+
+ void CreateIsolateManager() {
+ DCHECK(!current_tls_.Get());
+ current_tls_.Set(new CefV8IsolateManager());
+ }
+
+ void DestroyIsolateManager() {
+ DCHECK(current_tls_.Get());
+ delete current_tls_.Get();
+ current_tls_.Set(nullptr);
+ }
+
+ CefV8IsolateManager* GetIsolateManager() {
+ CefV8IsolateManager* manager = current_tls_.Get();
+ DCHECK(manager);
+ return manager;
+ }
+
+ private:
+ base::ThreadLocalPointer<CefV8IsolateManager> current_tls_;
+};
+
+base::LazyInstance<CefV8StateManager>::Leaky g_v8_state =
+ LAZY_INSTANCE_INITIALIZER;
+
+CefV8IsolateManager* GetIsolateManager() {
+ return g_v8_state.Pointer()->GetIsolateManager();
+}
+
+class V8TrackObject : public CefTrackNode {
+ public:
+ explicit V8TrackObject(v8::Isolate* isolate)
+ : isolate_(isolate), external_memory_(0) {
+ DCHECK(isolate_);
+ isolate_->AdjustAmountOfExternalAllocatedMemory(
+ static_cast<int>(sizeof(V8TrackObject)));
+ }
+ ~V8TrackObject() {
+ isolate_->AdjustAmountOfExternalAllocatedMemory(
+ -static_cast<int>(sizeof(V8TrackObject)) - external_memory_);
+ }
+
+ inline int GetExternallyAllocatedMemory() { return external_memory_; }
+
+ int AdjustExternallyAllocatedMemory(int change_in_bytes) {
+ int new_value = external_memory_ + change_in_bytes;
+ if (new_value < 0) {
+ NOTREACHED() << "External memory usage cannot be less than 0 bytes";
+ change_in_bytes = -(external_memory_);
+ new_value = 0;
+ }
+
+ if (change_in_bytes != 0) {
+ isolate_->AdjustAmountOfExternalAllocatedMemory(change_in_bytes);
+ }
+ external_memory_ = new_value;
+
+ return new_value;
+ }
+
+ inline void SetAccessor(CefRefPtr<CefV8Accessor> accessor) {
+ accessor_ = accessor;
+ }
+
+ inline CefRefPtr<CefV8Accessor> GetAccessor() { return accessor_; }
+
+ inline void SetInterceptor(CefRefPtr<CefV8Interceptor> interceptor) {
+ interceptor_ = interceptor;
+ }
+
+ inline CefRefPtr<CefV8Interceptor> GetInterceptor() { return interceptor_; }
+
+ inline void SetHandler(CefRefPtr<CefV8Handler> handler) {
+ handler_ = handler;
+ }
+
+ inline CefRefPtr<CefV8Handler> GetHandler() { return handler_; }
+
+ inline void SetUserData(CefRefPtr<CefBaseRefCounted> user_data) {
+ user_data_ = user_data;
+ }
+
+ inline CefRefPtr<CefBaseRefCounted> GetUserData() { return user_data_; }
+
+ // Attach this track object to the specified V8 object.
+ void AttachTo(v8::Local<v8::Context> context, v8::Local<v8::Object> object) {
+ SetPrivate(context, object, kCefTrackObject,
+ v8::External::New(isolate_, this));
+ }
+
+ // Retrieve the track object for the specified V8 object.
+ static V8TrackObject* Unwrap(v8::Local<v8::Context> context,
+ v8::Local<v8::Object> object) {
+ v8::Local<v8::Value> value;
+ if (GetPrivate(context, object, kCefTrackObject, &value) &&
+ value->IsExternal()) {
+ return static_cast<V8TrackObject*>(v8::External::Cast(*value)->Value());
+ }
+
+ return nullptr;
+ }
+
+ private:
+ v8::Isolate* isolate_;
+ CefRefPtr<CefV8Accessor> accessor_;
+ CefRefPtr<CefV8Interceptor> interceptor_;
+ CefRefPtr<CefV8Handler> handler_;
+ CefRefPtr<CefBaseRefCounted> user_data_;
+ int external_memory_;
+};
+
+class V8TrackString : public CefTrackNode {
+ public:
+ explicit V8TrackString(const std::string& str) : string_(str) {}
+ const char* GetString() { return string_.c_str(); }
+
+ private:
+ std::string string_;
+};
+
+class V8TrackArrayBuffer : public CefTrackNode {
+ public:
+ explicit V8TrackArrayBuffer(
+ v8::Isolate* isolate,
+ CefRefPtr<CefV8ArrayBufferReleaseCallback> release_callback)
+ : isolate_(isolate), release_callback_(release_callback) {
+ DCHECK(isolate_);
+ isolate_->AdjustAmountOfExternalAllocatedMemory(
+ static_cast<int>(sizeof(V8TrackArrayBuffer)));
+ }
+
+ ~V8TrackArrayBuffer() {
+ isolate_->AdjustAmountOfExternalAllocatedMemory(
+ -static_cast<int>(sizeof(V8TrackArrayBuffer)));
+ }
+
+ CefRefPtr<CefV8ArrayBufferReleaseCallback> GetReleaseCallback() {
+ return release_callback_;
+ }
+
+ // Attach this track object to the specified V8 object.
+ void AttachTo(v8::Local<v8::Context> context,
+ v8::Local<v8::ArrayBuffer> arrayBuffer) {
+ SetPrivate(context, arrayBuffer, kCefTrackObject,
+ v8::External::New(isolate_, this));
+ }
+
+ // Retrieve the track object for the specified V8 object.
+ static V8TrackArrayBuffer* Unwrap(v8::Local<v8::Context> context,
+ v8::Local<v8::Object> object) {
+ v8::Local<v8::Value> value;
+ if (GetPrivate(context, object, kCefTrackObject, &value) &&
+ value->IsExternal()) {
+ return static_cast<V8TrackArrayBuffer*>(
+ v8::External::Cast(*value)->Value());
+ }
+
+ return nullptr;
+ }
+
+ private:
+ v8::Isolate* isolate_;
+ CefRefPtr<CefV8ArrayBufferReleaseCallback> release_callback_;
+};
+
+// Object wrapped in a v8::External and passed as the Data argument to
+// v8::FunctionTemplate::New.
+class V8FunctionData {
+ public:
+ static v8::Local<v8::External> Create(v8::Isolate* isolate,
+ const CefString& function_name,
+ CefRefPtr<CefV8Handler> handler) {
+ // |data| will be deleted if/when the returned v8::External is GC'd.
+ V8FunctionData* data = new V8FunctionData(isolate, function_name, handler);
+ return data->CreateExternal();
+ }
+
+ static V8FunctionData* Unwrap(v8::Local<v8::Value> data) {
+ DCHECK(data->IsExternal());
+ return static_cast<V8FunctionData*>(v8::External::Cast(*data)->Value());
+ }
+
+ CefString function_name() const { return function_name_; }
+
+ CefV8Handler* handler() const {
+ if (!handler_) {
+ return nullptr;
+ }
+ return handler_.get();
+ }
+
+ private:
+ V8FunctionData(v8::Isolate* isolate,
+ const CefString& function_name,
+ CefRefPtr<CefV8Handler> handler)
+ : isolate_(isolate), function_name_(function_name), handler_(handler) {
+ DCHECK(isolate_);
+ DCHECK(handler_);
+ }
+
+ ~V8FunctionData() {
+ isolate_->AdjustAmountOfExternalAllocatedMemory(
+ -static_cast<int>(sizeof(V8FunctionData)));
+ handler_ = nullptr;
+ function_name_ = "FreedFunction";
+ }
+
+ v8::Local<v8::External> CreateExternal() {
+ v8::Local<v8::External> external = v8::External::New(isolate_, this);
+
+ isolate_->AdjustAmountOfExternalAllocatedMemory(
+ static_cast<int>(sizeof(V8FunctionData)));
+
+ handle_.Reset(isolate_, external);
+ handle_.SetWeak(this, FirstWeakCallback, v8::WeakCallbackType::kParameter);
+
+ return external;
+ }
+
+ static void FirstWeakCallback(
+ const v8::WeakCallbackInfo<V8FunctionData>& data) {
+ V8FunctionData* wrapper = data.GetParameter();
+ wrapper->handle_.Reset();
+ data.SetSecondPassCallback(SecondWeakCallback);
+ }
+
+ static void SecondWeakCallback(
+ const v8::WeakCallbackInfo<V8FunctionData>& data) {
+ V8FunctionData* wrapper = data.GetParameter();
+ delete wrapper;
+ }
+
+ v8::Isolate* isolate_;
+ CefString function_name_;
+ CefRefPtr<CefV8Handler> handler_;
+ v8::Persistent<v8::External> handle_;
+};
+
+// Convert a CefString to a V8::String.
+v8::Local<v8::String> GetV8String(v8::Isolate* isolate, const CefString& str) {
+#if defined(CEF_STRING_TYPE_UTF16)
+ // Already a UTF16 string.
+ return v8::String::NewFromTwoByte(
+ isolate,
+ reinterpret_cast<uint16_t*>(
+ const_cast<CefString::char_type*>(str.c_str())),
+ v8::NewStringType::kNormal, str.length())
+ .ToLocalChecked();
+#elif defined(CEF_STRING_TYPE_UTF8)
+ // Already a UTF8 string.
+ return v8::String::NewFromUtf8(isolate, const_cast<char*>(str.c_str()),
+ v8::NewStringType::kNormal, str.length())
+ .ToLocalChecked();
+#else
+ // Convert the string to UTF8.
+ std::string tmpStr = str;
+ return v8::String::NewFromUtf8(isolate, tmpStr.c_str(),
+ v8::NewStringType::kNormal, tmpStr.length())
+ .ToLocalChecked();
+#endif
+}
+
+#if defined(CEF_STRING_TYPE_UTF16)
+void v8impl_string_dtor(char16* str) {
+ delete[] str;
+}
+#elif defined(CEF_STRING_TYPE_UTF8)
+void v8impl_string_dtor(char* str) {
+ delete[] str;
+}
+#endif
+
+// Convert a v8::String to CefString.
+void GetCefString(v8::Isolate* isolate,
+ v8::Local<v8::String> str,
+ CefString& out) {
+ if (str.IsEmpty()) {
+ return;
+ }
+
+#if defined(CEF_STRING_TYPE_WIDE)
+ // Allocate enough space for a worst-case conversion.
+ int len = str->Utf8Length();
+ if (len == 0) {
+ return;
+ }
+ char* buf = new char[len + 1];
+ str->WriteUtf8(isolate, buf, len + 1);
+
+ // Perform conversion to the wide type.
+ cef_string_t* retws = out.GetWritableStruct();
+ cef_string_utf8_to_wide(buf, len, retws);
+
+ delete[] buf;
+#else // !defined(CEF_STRING_TYPE_WIDE)
+#if defined(CEF_STRING_TYPE_UTF16)
+ int len = str->Length();
+ if (len == 0) {
+ return;
+ }
+ char16* buf = new char16[len + 1];
+ str->Write(isolate, reinterpret_cast<uint16_t*>(buf), 0, len + 1);
+#else
+ // Allocate enough space for a worst-case conversion.
+ int len = str->Utf8Length();
+ if (len == 0) {
+ return;
+ }
+ char* buf = new char[len + 1];
+ str->WriteUtf8(isolate, buf, len + 1);
+#endif
+
+ // Don't perform an extra string copy.
+ out.clear();
+ cef_string_t* retws = out.GetWritableStruct();
+ retws->str = buf;
+ retws->length = len;
+ retws->dtor = v8impl_string_dtor;
+#endif // !defined(CEF_STRING_TYPE_WIDE)
+}
+
+// V8 function callback.
+void FunctionCallbackImpl(const v8::FunctionCallbackInfo<v8::Value>& info) {
+ v8::Isolate* isolate = info.GetIsolate();
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+
+ V8FunctionData* data = V8FunctionData::Unwrap(info.Data());
+ if (!data->handler()) {
+ // handler has gone away, bail!
+ info.GetReturnValue().SetUndefined();
+ return;
+ }
+ CefV8ValueList params;
+ for (int i = 0; i < info.Length(); i++) {
+ params.push_back(new CefV8ValueImpl(isolate, context, info[i]));
+ }
+
+ CefRefPtr<CefV8Value> object =
+ new CefV8ValueImpl(isolate, context, info.This());
+ CefRefPtr<CefV8Value> retval;
+ CefString exception;
+
+ if (data->handler()->Execute(data->function_name(), object, params, retval,
+ exception)) {
+ if (!exception.empty()) {
+ info.GetReturnValue().Set(isolate->ThrowException(
+ v8::Exception::Error(GetV8String(isolate, exception))));
+ return;
+ } else {
+ CefV8ValueImpl* rv = static_cast<CefV8ValueImpl*>(retval.get());
+ if (rv && rv->IsValid()) {
+ info.GetReturnValue().Set(rv->GetV8Value(true));
+ return;
+ }
+ }
+ }
+
+ info.GetReturnValue().SetUndefined();
+}
+
+// V8 Accessor callbacks
+void AccessorNameGetterCallbackImpl(
+ v8::Local<v8::Name> property,
+ const v8::PropertyCallbackInfo<v8::Value>& info) {
+ v8::Isolate* isolate = info.GetIsolate();
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+
+ v8::Local<v8::Object> obj = info.This();
+
+ CefRefPtr<CefV8Accessor> accessorPtr;
+
+ V8TrackObject* tracker = V8TrackObject::Unwrap(context, obj);
+ if (tracker) {
+ accessorPtr = tracker->GetAccessor();
+ }
+
+ if (accessorPtr.get()) {
+ CefRefPtr<CefV8Value> retval;
+ CefRefPtr<CefV8Value> object = new CefV8ValueImpl(isolate, context, obj);
+ CefString name, exception;
+ GetCefString(isolate, v8::Local<v8::String>::Cast(property), name);
+ if (accessorPtr->Get(name, object, retval, exception)) {
+ if (!exception.empty()) {
+ info.GetReturnValue().Set(isolate->ThrowException(
+ v8::Exception::Error(GetV8String(isolate, exception))));
+ return;
+ } else {
+ CefV8ValueImpl* rv = static_cast<CefV8ValueImpl*>(retval.get());
+ if (rv && rv->IsValid()) {
+ info.GetReturnValue().Set(rv->GetV8Value(true));
+ return;
+ }
+ }
+ }
+ }
+
+ return info.GetReturnValue().SetUndefined();
+}
+
+void AccessorNameSetterCallbackImpl(
+ v8::Local<v8::Name> property,
+ v8::Local<v8::Value> value,
+ const v8::PropertyCallbackInfo<void>& info) {
+ v8::Isolate* isolate = info.GetIsolate();
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+
+ v8::Local<v8::Object> obj = info.This();
+
+ CefRefPtr<CefV8Accessor> accessorPtr;
+
+ V8TrackObject* tracker = V8TrackObject::Unwrap(context, obj);
+ if (tracker) {
+ accessorPtr = tracker->GetAccessor();
+ }
+
+ if (accessorPtr.get()) {
+ CefRefPtr<CefV8Value> object = new CefV8ValueImpl(isolate, context, obj);
+ CefRefPtr<CefV8Value> cefValue =
+ new CefV8ValueImpl(isolate, context, value);
+ CefString name, exception;
+ GetCefString(isolate, v8::Local<v8::String>::Cast(property), name);
+ accessorPtr->Set(name, object, cefValue, exception);
+ if (!exception.empty()) {
+ isolate->ThrowException(
+ v8::Exception::Error(GetV8String(isolate, exception)));
+ return;
+ }
+ }
+}
+
+// Two helper functions for V8 Interceptor callbacks.
+CefString PropertyToIndex(v8::Isolate* isolate, v8::Local<v8::Name> property) {
+ CefString name;
+ GetCefString(isolate, property.As<v8::String>(), name);
+ return name;
+}
+
+int PropertyToIndex(v8::Isolate* isolate, uint32_t index) {
+ return static_cast<int>(index);
+}
+
+// V8 Interceptor callbacks.
+// T == v8::Local<v8::Name> for named property handlers and
+// T == uint32_t for indexed property handlers
+template <typename T>
+void InterceptorGetterCallbackImpl(
+ T property,
+ const v8::PropertyCallbackInfo<v8::Value>& info) {
+ v8::Isolate* isolate = info.GetIsolate();
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+
+ v8::Handle<v8::Object> obj = info.This();
+ CefRefPtr<CefV8Interceptor> interceptorPtr;
+
+ V8TrackObject* tracker = V8TrackObject::Unwrap(context, obj);
+ if (tracker) {
+ interceptorPtr = tracker->GetInterceptor();
+ }
+ if (!interceptorPtr.get()) {
+ return;
+ }
+
+ CefRefPtr<CefV8Value> object = new CefV8ValueImpl(isolate, context, obj);
+ CefRefPtr<CefV8Value> retval;
+ CefString exception;
+ interceptorPtr->Get(PropertyToIndex(isolate, property), object, retval,
+ exception);
+ if (!exception.empty()) {
+ info.GetReturnValue().Set(isolate->ThrowException(
+ v8::Exception::Error(GetV8String(isolate, exception))));
+ } else {
+ CefV8ValueImpl* retval_impl = static_cast<CefV8ValueImpl*>(retval.get());
+ if (retval_impl && retval_impl->IsValid()) {
+ info.GetReturnValue().Set(retval_impl->GetV8Value(true));
+ }
+ }
+}
+
+template <typename T>
+void InterceptorSetterCallbackImpl(
+ T property,
+ v8::Local<v8::Value> value,
+ const v8::PropertyCallbackInfo<v8::Value>& info) {
+ v8::Isolate* isolate = info.GetIsolate();
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+ v8::Handle<v8::Object> obj = info.This();
+ CefRefPtr<CefV8Interceptor> interceptorPtr;
+
+ V8TrackObject* tracker = V8TrackObject::Unwrap(context, obj);
+ if (tracker) {
+ interceptorPtr = tracker->GetInterceptor();
+ }
+
+ if (!interceptorPtr.get()) {
+ return;
+ }
+ CefRefPtr<CefV8Value> object = new CefV8ValueImpl(isolate, context, obj);
+ CefRefPtr<CefV8Value> cefValue = new CefV8ValueImpl(isolate, context, value);
+ CefString exception;
+ interceptorPtr->Set(PropertyToIndex(isolate, property), object, cefValue,
+ exception);
+ if (!exception.empty()) {
+ isolate->ThrowException(
+ v8::Exception::Error(GetV8String(isolate, exception)));
+ }
+}
+
+// V8 extension registration.
+
+class ExtensionWrapper : public v8::Extension {
+ public:
+ ExtensionWrapper(const char* extension_name,
+ const char* javascript_code,
+ CefV8Handler* handler)
+ : v8::Extension(extension_name, javascript_code), handler_(handler) {}
+
+ v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
+ v8::Isolate* isolate,
+ v8::Handle<v8::String> name) override {
+ if (!handler_) {
+ return v8::Local<v8::FunctionTemplate>();
+ }
+
+ CefString func_name;
+ GetCefString(isolate, name, func_name);
+
+ v8::Local<v8::External> function_data =
+ V8FunctionData::Create(isolate, func_name, handler_);
+
+ return v8::FunctionTemplate::New(isolate, FunctionCallbackImpl,
+ function_data);
+ }
+
+ private:
+ CefV8Handler* handler_;
+};
+
+class CefV8ExceptionImpl : public CefV8Exception {
+ public:
+ CefV8ExceptionImpl(v8::Local<v8::Context> context,
+ v8::Local<v8::Message> message)
+ : line_number_(0),
+ start_position_(0),
+ end_position_(0),
+ start_column_(0),
+ end_column_(0) {
+ if (message.IsEmpty()) {
+ return;
+ }
+
+ v8::Isolate* isolate = context->GetIsolate();
+ GetCefString(isolate, message->Get(), message_);
+ v8::MaybeLocal<v8::String> source_line = message->GetSourceLine(context);
+ if (!source_line.IsEmpty()) {
+ GetCefString(isolate, source_line.ToLocalChecked(), source_line_);
+ }
+
+ if (!message->GetScriptResourceName().IsEmpty()) {
+ GetCefString(
+ isolate,
+ message->GetScriptResourceName()->ToString(context).ToLocalChecked(),
+ script_);
+ }
+
+ v8::Maybe<int> line_number = message->GetLineNumber(context);
+ if (!line_number.IsNothing()) {
+ line_number_ = line_number.ToChecked();
+ }
+ start_position_ = message->GetStartPosition();
+ end_position_ = message->GetEndPosition();
+ start_column_ = message->GetStartColumn(context).FromJust();
+ end_column_ = message->GetEndColumn(context).FromJust();
+ }
+
+ CefString GetMessage() override { return message_; }
+ CefString GetSourceLine() override { return source_line_; }
+ CefString GetScriptResourceName() override { return script_; }
+ int GetLineNumber() override { return line_number_; }
+ int GetStartPosition() override { return start_position_; }
+ int GetEndPosition() override { return end_position_; }
+ int GetStartColumn() override { return start_column_; }
+ int GetEndColumn() override { return end_column_; }
+
+ protected:
+ CefString message_;
+ CefString source_line_;
+ CefString script_;
+ int line_number_;
+ int start_position_;
+ int end_position_;
+ int start_column_;
+ int end_column_;
+
+ IMPLEMENT_REFCOUNTING(CefV8ExceptionImpl);
+};
+
+void MessageListenerCallbackImpl(v8::Handle<v8::Message> message,
+ v8::Handle<v8::Value> data) {
+ CefRefPtr<CefApp> application = CefAppManager::Get()->GetApplication();
+ if (!application.get()) {
+ return;
+ }
+
+ CefRefPtr<CefRenderProcessHandler> handler =
+ application->GetRenderProcessHandler();
+ if (!handler.get()) {
+ return;
+ }
+
+ v8::Isolate* isolate = GetIsolateManager()->isolate();
+ CefRefPtr<CefV8Context> context = CefV8Context::GetCurrentContext();
+ v8::Local<v8::StackTrace> v8Stack = message->GetStackTrace();
+ CefRefPtr<CefV8StackTrace> stackTrace =
+ new CefV8StackTraceImpl(isolate, v8Stack);
+
+ CefRefPtr<CefV8Exception> exception = new CefV8ExceptionImpl(
+ static_cast<CefV8ContextImpl*>(context.get())->GetV8Context(), message);
+
+ CefRefPtr<CefBrowser> browser = context->GetBrowser();
+ if (browser) {
+ handler->OnUncaughtException(browser, context->GetFrame(), context,
+ exception, stackTrace);
+ }
+}
+
+} // namespace
+
+// Global functions.
+
+void CefV8IsolateCreated() {
+ g_v8_state.Pointer()->CreateIsolateManager();
+}
+
+void CefV8IsolateDestroyed() {
+ g_v8_state.Pointer()->DestroyIsolateManager();
+}
+
+void CefV8ReleaseContext(v8::Local<v8::Context> context) {
+ GetIsolateManager()->ReleaseContext(context);
+}
+
+void CefV8SetUncaughtExceptionStackSize(int stack_size) {
+ GetIsolateManager()->SetUncaughtExceptionStackSize(stack_size);
+}
+
+void CefV8SetWorkerAttributes(int worker_id, const GURL& worker_url) {
+ GetIsolateManager()->SetWorkerAttributes(worker_id, worker_url);
+}
+
+bool CefRegisterExtension(const CefString& extension_name,
+ const CefString& javascript_code,
+ CefRefPtr<CefV8Handler> handler) {
+ // Verify that this method was called on the correct thread.
+ CEF_REQUIRE_RT_RETURN(false);
+
+ CefV8IsolateManager* isolate_manager = GetIsolateManager();
+
+ V8TrackString* name = new V8TrackString(extension_name);
+ isolate_manager->AddGlobalTrackObject(name);
+ V8TrackString* code = new V8TrackString(javascript_code);
+ isolate_manager->AddGlobalTrackObject(code);
+
+ if (handler.get()) {
+ // The reference will be released when the process exits.
+ V8TrackObject* object = new V8TrackObject(isolate_manager->isolate());
+ object->SetHandler(handler);
+ isolate_manager->AddGlobalTrackObject(object);
+ }
+
+ std::unique_ptr<v8::Extension> wrapper(new ExtensionWrapper(
+ name->GetString(), code->GetString(), handler.get()));
+
+ blink::WebScriptController::RegisterExtension(std::move(wrapper));
+ return true;
+}
+
+// Helper macros
+
+#define CEF_V8_HAS_ISOLATE() (!!GetIsolateManager())
+#define CEF_V8_REQUIRE_ISOLATE_RETURN(var) \
+ if (!CEF_V8_HAS_ISOLATE()) { \
+ NOTREACHED() << "V8 isolate is not valid"; \
+ return var; \
+ }
+
+#define CEF_V8_CURRENTLY_ON_MLT() \
+ (!handle_.get() || handle_->BelongsToCurrentThread())
+#define CEF_V8_REQUIRE_MLT_RETURN(var) \
+ CEF_V8_REQUIRE_ISOLATE_RETURN(var); \
+ if (!CEF_V8_CURRENTLY_ON_MLT()) { \
+ NOTREACHED() << "called on incorrect thread"; \
+ return var; \
+ }
+
+#define CEF_V8_HANDLE_IS_VALID() (handle_.get() && handle_->IsValid())
+#define CEF_V8_REQUIRE_VALID_HANDLE_RETURN(ret) \
+ CEF_V8_REQUIRE_MLT_RETURN(ret); \
+ if (!CEF_V8_HANDLE_IS_VALID()) { \
+ NOTREACHED() << "V8 handle is not valid"; \
+ return ret; \
+ }
+
+#define CEF_V8_IS_VALID() \
+ (CEF_V8_HAS_ISOLATE() && CEF_V8_CURRENTLY_ON_MLT() && \
+ CEF_V8_HANDLE_IS_VALID())
+
+#define CEF_V8_REQUIRE_OBJECT_RETURN(ret) \
+ CEF_V8_REQUIRE_VALID_HANDLE_RETURN(ret); \
+ if (type_ != TYPE_OBJECT) { \
+ NOTREACHED() << "V8 value is not an object"; \
+ return ret; \
+ }
+
+// CefV8HandleBase
+
+CefV8HandleBase::~CefV8HandleBase() {
+ DCHECK(BelongsToCurrentThread());
+}
+
+bool CefV8HandleBase::BelongsToCurrentThread() const {
+ return task_runner_->RunsTasksInCurrentSequence();
+}
+
+CefV8HandleBase::CefV8HandleBase(v8::Isolate* isolate,
+ v8::Local<v8::Context> context)
+ : isolate_(isolate) {
+ DCHECK(isolate_);
+
+ CefV8IsolateManager* manager = GetIsolateManager();
+ DCHECK(manager);
+ DCHECK_EQ(isolate_, manager->isolate());
+
+ task_runner_ = manager->task_runner();
+ context_state_ = manager->GetContextState(context);
+}
+
+// CefV8Context
+
+// static
+CefRefPtr<CefV8Context> CefV8Context::GetCurrentContext() {
+ CefRefPtr<CefV8Context> context;
+ CEF_V8_REQUIRE_ISOLATE_RETURN(context);
+ v8::Isolate* isolate = GetIsolateManager()->isolate();
+ if (isolate->InContext()) {
+ v8::HandleScope handle_scope(isolate);
+ context = new CefV8ContextImpl(isolate, isolate->GetCurrentContext());
+ }
+ return context;
+}
+
+// static
+CefRefPtr<CefV8Context> CefV8Context::GetEnteredContext() {
+ CefRefPtr<CefV8Context> context;
+ CEF_V8_REQUIRE_ISOLATE_RETURN(context);
+ v8::Isolate* isolate = GetIsolateManager()->isolate();
+ if (isolate->InContext()) {
+ v8::HandleScope handle_scope(isolate);
+ context =
+ new CefV8ContextImpl(isolate, isolate->GetEnteredOrMicrotaskContext());
+ }
+ return context;
+}
+
+// static
+bool CefV8Context::InContext() {
+ CEF_V8_REQUIRE_ISOLATE_RETURN(false);
+ v8::Isolate* isolate = GetIsolateManager()->isolate();
+ return isolate->InContext();
+}
+
+// CefV8ContextImpl
+
+CefV8ContextImpl::CefV8ContextImpl(v8::Isolate* isolate,
+ v8::Local<v8::Context> context)
+ : handle_(new Handle(isolate, context, context)),
+ microtask_queue_(blink_glue::GetMicrotaskQueue(context)) {}
+
+CefV8ContextImpl::~CefV8ContextImpl() {
+ DLOG_ASSERT(0 == enter_count_);
+}
+
+CefRefPtr<CefTaskRunner> CefV8ContextImpl::GetTaskRunner() {
+ return new CefTaskRunnerImpl(handle_->task_runner());
+}
+
+bool CefV8ContextImpl::IsValid() {
+ return CEF_V8_IS_VALID();
+}
+
+CefRefPtr<CefBrowser> CefV8ContextImpl::GetBrowser() {
+ CefRefPtr<CefBrowser> browser;
+ CEF_V8_REQUIRE_VALID_HANDLE_RETURN(browser);
+
+ blink::WebLocalFrame* webframe = GetWebFrame();
+ if (webframe) {
+ browser = CefBrowserImpl::GetBrowserForMainFrame(webframe->Top());
+ }
+
+ return browser;
+}
+
+CefRefPtr<CefFrame> CefV8ContextImpl::GetFrame() {
+ CefRefPtr<CefFrame> frame;
+ CEF_V8_REQUIRE_VALID_HANDLE_RETURN(frame);
+
+ blink::WebLocalFrame* webframe = GetWebFrame();
+ if (webframe) {
+ CefRefPtr<CefBrowserImpl> browser =
+ CefBrowserImpl::GetBrowserForMainFrame(webframe->Top());
+ if (browser) {
+ frame = browser->GetFrame(render_frame_util::GetIdentifier(webframe));
+ }
+ }
+
+ return frame;
+}
+
+CefRefPtr<CefV8Value> CefV8ContextImpl::GetGlobal() {
+ CEF_V8_REQUIRE_VALID_HANDLE_RETURN(nullptr);
+
+ if (blink_glue::IsScriptForbidden()) {
+ return nullptr;
+ }
+
+ v8::Isolate* isolate = handle_->isolate();
+ v8::HandleScope handle_scope(isolate);
+ v8::Local<v8::Context> context = GetV8Context();
+ v8::Context::Scope context_scope(context);
+ return new CefV8ValueImpl(isolate, context, context->Global());
+}
+
+bool CefV8ContextImpl::Enter() {
+ CEF_V8_REQUIRE_VALID_HANDLE_RETURN(false);
+
+ if (blink_glue::IsScriptForbidden()) {
+ return false;
+ }
+
+ v8::Isolate* isolate = handle_->isolate();
+ v8::HandleScope handle_scope(isolate);
+
+ if (!microtasks_scope_) {
+ // Increment the MicrotasksScope recursion level.
+ microtasks_scope_.reset(new v8::MicrotasksScope(
+ isolate, microtask_queue_, v8::MicrotasksScope::kRunMicrotasks));
+ }
+
+ ++enter_count_;
+ handle_->GetNewV8Handle()->Enter();
+
+ return true;
+}
+
+bool CefV8ContextImpl::Exit() {
+ CEF_V8_REQUIRE_VALID_HANDLE_RETURN(false);
+
+ if (blink_glue::IsScriptForbidden()) {
+ return false;
+ }
+
+ if (enter_count_ <= 0) {
+ LOG(ERROR) << "Call to CefV8Context::Exit() without matching call to "
+ "CefV8Context::Enter()";
+ return false;
+ }
+
+ v8::HandleScope handle_scope(handle_->isolate());
+
+ handle_->GetNewV8Handle()->Exit();
+
+ if (--enter_count_ == 0) {
+ // Decrement the MicrotasksScope recursion level.
+ microtasks_scope_.reset(nullptr);
+ }
+
+ return true;
+}
+
+bool CefV8ContextImpl::IsSame(CefRefPtr<CefV8Context> that) {
+ CEF_V8_REQUIRE_VALID_HANDLE_RETURN(false);
+
+ CefV8ContextImpl* impl = static_cast<CefV8ContextImpl*>(that.get());
+ if (!impl || !impl->IsValid()) {
+ return false;
+ }
+
+ return (handle_->GetPersistentV8Handle() ==
+ impl->handle_->GetPersistentV8Handle());
+}
+
+bool CefV8ContextImpl::Eval(const CefString& code,
+ const CefString& script_url,
+ int start_line,
+ CefRefPtr<CefV8Value>& retval,
+ CefRefPtr<CefV8Exception>& exception) {
+ retval = nullptr;
+ exception = nullptr;
+
+ CEF_V8_REQUIRE_VALID_HANDLE_RETURN(false);
+
+ if (blink_glue::IsScriptForbidden()) {
+ return false;
+ }
+
+ if (code.empty()) {
+ NOTREACHED() << "invalid input parameter";
+ return false;
+ }
+
+ v8::Isolate* isolate = handle_->isolate();
+ v8::HandleScope handle_scope(isolate);
+ v8::Local<v8::Context> context = GetV8Context();
+ v8::Context::Scope context_scope(context);
+
+ const blink::WebString& source =
+ blink::WebString::FromUTF16(code.ToString16());
+ const blink::WebString& source_url =
+ blink::WebString::FromUTF16(script_url.ToString16());
+
+ v8::TryCatch try_catch(isolate);
+ try_catch.SetVerbose(true);
+
+ v8::Local<v8::Value> func_rv = blink_glue::ExecuteV8ScriptAndReturnValue(
+ source, source_url, start_line, context, try_catch);
+
+ if (try_catch.HasCaught()) {
+ exception = new CefV8ExceptionImpl(context, try_catch.Message());
+ return false;
+ } else if (!func_rv.IsEmpty()) {
+ retval = new CefV8ValueImpl(isolate, context, func_rv);
+ return true;
+ }
+
+ NOTREACHED();
+ return false;
+}
+
+v8::Local<v8::Context> CefV8ContextImpl::GetV8Context() {
+ return handle_->GetNewV8Handle();
+}
+
+blink::WebLocalFrame* CefV8ContextImpl::GetWebFrame() {
+ CEF_REQUIRE_RT();
+
+ if (blink_glue::IsScriptForbidden()) {
+ return nullptr;
+ }
+
+ v8::HandleScope handle_scope(handle_->isolate());
+ v8::Local<v8::Context> context = GetV8Context();
+ v8::Context::Scope context_scope(context);
+ return blink::WebLocalFrame::FrameForContext(context);
+}
+
+// CefV8ValueImpl::Handle
+
+CefV8ValueImpl::Handle::Handle(v8::Isolate* isolate,
+ v8::Local<v8::Context> context,
+ handleType v,
+ CefTrackNode* tracker)
+ : CefV8HandleBase(isolate, context),
+ handle_(isolate, v),
+ tracker_(tracker),
+ should_persist_(false),
+ is_set_weak_(false) {}
+
+CefV8ValueImpl::Handle::~Handle() {
+ DCHECK(BelongsToCurrentThread());
+
+ if (tracker_) {
+ if (is_set_weak_) {
+ if (context_state_.get()) {
+ // If the associated context is still valid then delete |tracker_|.
+ // Otherwise, |tracker_| will already have been deleted.
+ if (context_state_->IsValid()) {
+ context_state_->DeleteTrackObject(tracker_);
+ }
+ } else {
+ GetIsolateManager()->DeleteGlobalTrackObject(tracker_);
+ }
+ } else {
+ delete tracker_;
+ }
+ }
+
+ if (is_set_weak_) {
+ isolate_->AdjustAmountOfExternalAllocatedMemory(
+ -static_cast<int>(sizeof(Handle)));
+ } else {
+ // SetWeak was not called so reset now.
+ handle_.Reset();
+ }
+}
+
+CefV8ValueImpl::Handle::handleType CefV8ValueImpl::Handle::GetNewV8Handle(
+ bool should_persist) {
+ DCHECK(IsValid());
+ if (should_persist && !should_persist_) {
+ should_persist_ = true;
+ }
+ return handleType::New(isolate(), handle_);
+}
+
+CefV8ValueImpl::Handle::persistentType&
+CefV8ValueImpl::Handle::GetPersistentV8Handle() {
+ return handle_;
+}
+
+void CefV8ValueImpl::Handle::SetWeakIfNecessary() {
+ if (!BelongsToCurrentThread()) {
+ task_runner()->PostTask(
+ FROM_HERE,
+ base::BindOnce(&CefV8ValueImpl::Handle::SetWeakIfNecessary, this));
+ return;
+ }
+
+ // Persist the handle (call SetWeak) if:
+ // A. The handle has been passed into a V8 function or used as a return value
+ // from a V8 callback, and
+ // B. The associated context, if any, is still valid.
+ if (should_persist_ && (!context_state_.get() || context_state_->IsValid())) {
+ is_set_weak_ = true;
+
+ if (tracker_) {
+ if (context_state_.get()) {
+ // |tracker_| will be deleted when:
+ // A. The associated context is released, or
+ // B. SecondWeakCallback is called for the weak handle.
+ DCHECK(context_state_->IsValid());
+ context_state_->AddTrackObject(tracker_);
+ } else {
+ // |tracker_| will be deleted when:
+ // A. The process shuts down, or
+ // B. SecondWeakCallback is called for the weak handle.
+ GetIsolateManager()->AddGlobalTrackObject(tracker_);
+ }
+ }
+
+ isolate_->AdjustAmountOfExternalAllocatedMemory(
+ static_cast<int>(sizeof(Handle)));
+
+ // The added reference will be released in SecondWeakCallback.
+ AddRef();
+ handle_.SetWeak(this, FirstWeakCallback, v8::WeakCallbackType::kParameter);
+ }
+}
+
+// static
+void CefV8ValueImpl::Handle::FirstWeakCallback(
+ const v8::WeakCallbackInfo<Handle>& data) {
+ Handle* wrapper = data.GetParameter();
+ wrapper->handle_.Reset();
+ data.SetSecondPassCallback(SecondWeakCallback);
+}
+
+// static
+void CefV8ValueImpl::Handle::SecondWeakCallback(
+ const v8::WeakCallbackInfo<Handle>& data) {
+ Handle* wrapper = data.GetParameter();
+ wrapper->Release();
+}
+
+// CefV8Value
+
+// static
+CefRefPtr<CefV8Value> CefV8Value::CreateUndefined() {
+ CEF_V8_REQUIRE_ISOLATE_RETURN(nullptr);
+ v8::Isolate* isolate = GetIsolateManager()->isolate();
+ CefRefPtr<CefV8ValueImpl> impl = new CefV8ValueImpl(isolate);
+ impl->InitUndefined();
+ return impl.get();
+}
+
+// static
+CefRefPtr<CefV8Value> CefV8Value::CreateNull() {
+ CEF_V8_REQUIRE_ISOLATE_RETURN(nullptr);
+ v8::Isolate* isolate = GetIsolateManager()->isolate();
+ CefRefPtr<CefV8ValueImpl> impl = new CefV8ValueImpl(isolate);
+ impl->InitNull();
+ return impl.get();
+}
+
+// static
+CefRefPtr<CefV8Value> CefV8Value::CreateBool(bool value) {
+ CEF_V8_REQUIRE_ISOLATE_RETURN(nullptr);
+ v8::Isolate* isolate = GetIsolateManager()->isolate();
+ CefRefPtr<CefV8ValueImpl> impl = new CefV8ValueImpl(isolate);
+ impl->InitBool(value);
+ return impl.get();
+}
+
+// static
+CefRefPtr<CefV8Value> CefV8Value::CreateInt(int32 value) {
+ CEF_V8_REQUIRE_ISOLATE_RETURN(nullptr);
+ v8::Isolate* isolate = GetIsolateManager()->isolate();
+ CefRefPtr<CefV8ValueImpl> impl = new CefV8ValueImpl(isolate);
+ impl->InitInt(value);
+ return impl.get();
+}
+
+// static
+CefRefPtr<CefV8Value> CefV8Value::CreateUInt(uint32 value) {
+ CEF_V8_REQUIRE_ISOLATE_RETURN(nullptr);
+ v8::Isolate* isolate = GetIsolateManager()->isolate();
+ CefRefPtr<CefV8ValueImpl> impl = new CefV8ValueImpl(isolate);
+ impl->InitUInt(value);
+ return impl.get();
+}
+
+// static
+CefRefPtr<CefV8Value> CefV8Value::CreateDouble(double value) {
+ CEF_V8_REQUIRE_ISOLATE_RETURN(nullptr);
+ v8::Isolate* isolate = GetIsolateManager()->isolate();
+ CefRefPtr<CefV8ValueImpl> impl = new CefV8ValueImpl(isolate);
+ impl->InitDouble(value);
+ return impl.get();
+}
+
+// static
+CefRefPtr<CefV8Value> CefV8Value::CreateDate(CefBaseTime value) {
+ CEF_V8_REQUIRE_ISOLATE_RETURN(nullptr);
+ v8::Isolate* isolate = GetIsolateManager()->isolate();
+ CefRefPtr<CefV8ValueImpl> impl = new CefV8ValueImpl(isolate);
+ impl->InitDate(value);
+ return impl.get();
+}
+
+// static
+CefRefPtr<CefV8Value> CefV8Value::CreateString(const CefString& value) {
+ CEF_V8_REQUIRE_ISOLATE_RETURN(nullptr);
+ v8::Isolate* isolate = GetIsolateManager()->isolate();
+ CefRefPtr<CefV8ValueImpl> impl = new CefV8ValueImpl(isolate);
+ CefString str(value);
+ impl->InitString(str);
+ return impl.get();
+}
+
+// static
+CefRefPtr<CefV8Value> CefV8Value::CreateObject(
+ CefRefPtr<CefV8Accessor> accessor,
+ CefRefPtr<CefV8Interceptor> interceptor) {
+ CEF_V8_REQUIRE_ISOLATE_RETURN(nullptr);
+
+ v8::Isolate* isolate = GetIsolateManager()->isolate();
+ v8::HandleScope handle_scope(isolate);
+
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+ if (context.IsEmpty()) {
+ NOTREACHED() << "not currently in a V8 context";
+ return nullptr;
+ }
+
+ // Create the new V8 object. If an interceptor is passed, create object from
+ // template and set property handlers.
+ v8::Local<v8::Object> obj;
+ if (interceptor.get()) {
+ v8::Local<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New(isolate);
+ tmpl->SetHandler(v8::NamedPropertyHandlerConfiguration(
+ InterceptorGetterCallbackImpl<v8::Local<v8::Name>>,
+ InterceptorSetterCallbackImpl<v8::Local<v8::Name>>, nullptr, nullptr,
+ nullptr, v8::Local<v8::Value>(),
+ v8::PropertyHandlerFlags::kOnlyInterceptStrings));
+
+ tmpl->SetIndexedPropertyHandler(InterceptorGetterCallbackImpl<uint32_t>,
+ InterceptorSetterCallbackImpl<uint32_t>);
+
+ v8::MaybeLocal<v8::Object> maybe_object = tmpl->NewInstance(context);
+ if (!maybe_object.ToLocal<v8::Object>(&obj)) {
+ NOTREACHED() << "Failed to create V8 Object with interceptor";
+ return nullptr;
+ }
+ } else {
+ obj = v8::Object::New(isolate);
+ }
+
+ // Create a tracker object that will cause the user data and/or accessor
+ // and/or interceptor reference to be released when the V8 object is
+ // destroyed.
+ V8TrackObject* tracker = new V8TrackObject(isolate);
+ tracker->SetAccessor(accessor);
+ tracker->SetInterceptor(interceptor);
+
+ // Attach the tracker object.
+ tracker->AttachTo(context, obj);
+
+ CefRefPtr<CefV8ValueImpl> impl = new CefV8ValueImpl(isolate);
+ impl->InitObject(obj, tracker);
+ return impl.get();
+}
+
+// static
+CefRefPtr<CefV8Value> CefV8Value::CreateArray(int length) {
+ CEF_V8_REQUIRE_ISOLATE_RETURN(nullptr);
+
+ v8::Isolate* isolate = GetIsolateManager()->isolate();
+ v8::HandleScope handle_scope(isolate);
+
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+ if (context.IsEmpty()) {
+ NOTREACHED() << "not currently in a V8 context";
+ return nullptr;
+ }
+
+ // Create a tracker object that will cause the user data reference to be
+ // released when the V8 object is destroyed.
+ V8TrackObject* tracker = new V8TrackObject(isolate);
+
+ // Create the new V8 array.
+ v8::Local<v8::Array> arr = v8::Array::New(isolate, length);
+
+ // Attach the tracker object.
+ tracker->AttachTo(context, arr);
+
+ CefRefPtr<CefV8ValueImpl> impl = new CefV8ValueImpl(isolate);
+ impl->InitObject(arr, tracker);
+ return impl.get();
+}
+
+// static
+CefRefPtr<CefV8Value> CefV8Value::CreateArrayBuffer(
+ void* buffer,
+ size_t length,
+ CefRefPtr<CefV8ArrayBufferReleaseCallback> release_callback) {
+ CEF_V8_REQUIRE_ISOLATE_RETURN(nullptr);
+
+ v8::Isolate* isolate = GetIsolateManager()->isolate();
+ v8::HandleScope handle_scope(isolate);
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+ if (context.IsEmpty()) {
+ NOTREACHED() << "not currently in a V8 context";
+ return nullptr;
+ }
+
+ // Create a tracker object that will cause the user data reference to be
+ // released when the V8 object is destroyed.
+ V8TrackArrayBuffer* tracker =
+ new V8TrackArrayBuffer(isolate, release_callback);
+
+ if (release_callback) {
+ release_callback->AddRef();
+ }
+
+ auto deleter = [](void* data, size_t length, void* deleter_data) {
+ auto* release_callback =
+ reinterpret_cast<CefV8ArrayBufferReleaseCallback*>(deleter_data);
+ if (release_callback) {
+ release_callback->ReleaseBuffer(data);
+ release_callback->Release();
+ }
+ };
+
+ std::unique_ptr<v8::BackingStore> backing = v8::ArrayBuffer::NewBackingStore(
+ buffer, length, deleter, release_callback.get());
+ v8::Local<v8::ArrayBuffer> ab =
+ v8::ArrayBuffer::New(isolate, std::move(backing));
+
+ // Attach the tracker object.
+ tracker->AttachTo(context, ab);
+
+ CefRefPtr<CefV8ValueImpl> impl = new CefV8ValueImpl(isolate);
+ impl->InitObject(ab, tracker);
+ return impl.get();
+}
+
+// static
+CefRefPtr<CefV8Value> CefV8Value::CreateFunction(
+ const CefString& name,
+ CefRefPtr<CefV8Handler> handler) {
+ CEF_V8_REQUIRE_ISOLATE_RETURN(nullptr);
+
+ if (!handler.get()) {
+ NOTREACHED() << "invalid parameter";
+ return nullptr;
+ }
+
+ v8::Isolate* isolate = GetIsolateManager()->isolate();
+ v8::HandleScope handle_scope(isolate);
+
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+ if (context.IsEmpty()) {
+ NOTREACHED() << "not currently in a V8 context";
+ return nullptr;
+ }
+
+ v8::Local<v8::External> function_data =
+ V8FunctionData::Create(isolate, name, handler);
+
+ // Create a new V8 function template.
+ v8::Local<v8::FunctionTemplate> tmpl =
+ v8::FunctionTemplate::New(isolate, FunctionCallbackImpl, function_data);
+
+ // Retrieve the function object and set the name.
+ v8::MaybeLocal<v8::Function> maybe_func = tmpl->GetFunction(context);
+ v8::Local<v8::Function> func;
+ if (!maybe_func.ToLocal(&func)) {
+ NOTREACHED() << "failed to create V8 function";
+ return nullptr;
+ }
+
+ func->SetName(GetV8String(isolate, name));
+
+ // Create a tracker object that will cause the user data and/or handler
+ // reference to be released when the V8 object is destroyed.
+ V8TrackObject* tracker = new V8TrackObject(isolate);
+ tracker->SetHandler(handler);
+
+ // Attach the tracker object.
+ tracker->AttachTo(context, func);
+
+ // Create the CefV8ValueImpl and provide a tracker object that will cause
+ // the handler reference to be released when the V8 object is destroyed.
+ CefRefPtr<CefV8ValueImpl> impl = new CefV8ValueImpl(isolate);
+ impl->InitObject(func, tracker);
+ return impl.get();
+}
+
+// static
+CefRefPtr<CefV8Value> CefV8Value::CreatePromise() {
+ CEF_V8_REQUIRE_ISOLATE_RETURN(nullptr);
+ v8::Isolate* isolate = GetIsolateManager()->isolate();
+ v8::HandleScope handle_scope(isolate);
+
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+ if (context.IsEmpty()) {
+ NOTREACHED() << "not currently in a V8 context";
+ return nullptr;
+ }
+
+ v8::Local<v8::Promise::Resolver> promise_resolver =
+ v8::Promise::Resolver::New(context).ToLocalChecked();
+
+ // Create a tracker object that will cause the user data reference to be
+ // released when the V8 object is destroyed.
+ V8TrackObject* tracker = new V8TrackObject(isolate);
+
+ // Attach the tracker object.
+ tracker->AttachTo(context, promise_resolver);
+
+ CefRefPtr<CefV8ValueImpl> impl = new CefV8ValueImpl(isolate);
+ impl->InitObject(promise_resolver, tracker);
+ return impl.get();
+}
+
+// CefV8ValueImpl
+
+CefV8ValueImpl::CefV8ValueImpl(v8::Isolate* isolate)
+ : isolate_(isolate), type_(TYPE_INVALID), rethrow_exceptions_(false) {
+ DCHECK(isolate_);
+}
+
+CefV8ValueImpl::CefV8ValueImpl(v8::Isolate* isolate,
+ v8::Local<v8::Context> context,
+ v8::Local<v8::Value> value)
+ : isolate_(isolate), type_(TYPE_INVALID), rethrow_exceptions_(false) {
+ DCHECK(isolate_);
+ InitFromV8Value(context, value);
+}
+
+CefV8ValueImpl::~CefV8ValueImpl() {
+ if (type_ == TYPE_STRING) {
+ cef_string_clear(&string_value_);
+ }
+ if (handle_.get()) {
+ handle_->SetWeakIfNecessary();
+ }
+}
+
+void CefV8ValueImpl::InitFromV8Value(v8::Local<v8::Context> context,
+ v8::Local<v8::Value> value) {
+ if (value->IsUndefined()) {
+ InitUndefined();
+ } else if (value->IsNull()) {
+ InitNull();
+ } else if (value->IsTrue()) {
+ InitBool(true);
+ } else if (value->IsFalse()) {
+ InitBool(false);
+ } else if (value->IsBoolean()) {
+ InitBool(value->ToBoolean(context->GetIsolate())->Value());
+ } else if (value->IsInt32()) {
+ InitInt(value->ToInt32(context).ToLocalChecked()->Value());
+ } else if (value->IsUint32()) {
+ InitUInt(value->ToUint32(context).ToLocalChecked()->Value());
+ } else if (value->IsNumber()) {
+ InitDouble(value->ToNumber(context).ToLocalChecked()->Value());
+ } else if (value->IsDate()) {
+ // Convert from milliseconds to seconds.
+ InitDate(base::Time::FromJsTime(
+ value->ToNumber(context).ToLocalChecked()->Value()));
+ } else if (value->IsString()) {
+ CefString rv;
+ GetCefString(context->GetIsolate(),
+ value->ToString(context).ToLocalChecked(), rv);
+ InitString(rv);
+ } else if (value->IsObject()) {
+ InitObject(value, nullptr);
+ }
+}
+
+void CefV8ValueImpl::InitUndefined() {
+ DCHECK_EQ(type_, TYPE_INVALID);
+ type_ = TYPE_UNDEFINED;
+}
+
+void CefV8ValueImpl::InitNull() {
+ DCHECK_EQ(type_, TYPE_INVALID);
+ type_ = TYPE_NULL;
+}
+
+void CefV8ValueImpl::InitBool(bool value) {
+ DCHECK_EQ(type_, TYPE_INVALID);
+ type_ = TYPE_BOOL;
+ bool_value_ = value;
+}
+
+void CefV8ValueImpl::InitInt(int32 value) {
+ DCHECK_EQ(type_, TYPE_INVALID);
+ type_ = TYPE_INT;
+ int_value_ = value;
+}
+
+void CefV8ValueImpl::InitUInt(uint32 value) {
+ DCHECK_EQ(type_, TYPE_INVALID);
+ type_ = TYPE_UINT;
+ uint_value_ = value;
+}
+
+void CefV8ValueImpl::InitDouble(double value) {
+ DCHECK_EQ(type_, TYPE_INVALID);
+ type_ = TYPE_DOUBLE;
+ double_value_ = value;
+}
+
+void CefV8ValueImpl::InitDate(CefBaseTime value) {
+ DCHECK_EQ(type_, TYPE_INVALID);
+ type_ = TYPE_DATE;
+ date_value_ = value;
+}
+
+void CefV8ValueImpl::InitString(CefString& value) {
+ DCHECK_EQ(type_, TYPE_INVALID);
+ type_ = TYPE_STRING;
+ // Take ownership of the underling string value.
+ const cef_string_t* str = value.GetStruct();
+ if (str) {
+ string_value_ = *str;
+ cef_string_t* writable_struct = value.GetWritableStruct();
+ writable_struct->str = nullptr;
+ writable_struct->length = 0;
+ } else {
+ string_value_.str = nullptr;
+ string_value_.length = 0;
+ }
+}
+
+void CefV8ValueImpl::InitObject(v8::Local<v8::Value> value,
+ CefTrackNode* tracker) {
+ DCHECK_EQ(type_, TYPE_INVALID);
+ type_ = TYPE_OBJECT;
+ handle_ = new Handle(isolate_, v8::Local<v8::Context>(), value, tracker);
+}
+
+v8::Local<v8::Value> CefV8ValueImpl::GetV8Value(bool should_persist) {
+ switch (type_) {
+ case TYPE_UNDEFINED:
+ return v8::Undefined(isolate_);
+ case TYPE_NULL:
+ return v8::Null(isolate_);
+ case TYPE_BOOL:
+ return v8::Boolean::New(isolate_, bool_value_);
+ case TYPE_INT:
+ return v8::Int32::New(isolate_, int_value_);
+ case TYPE_UINT:
+ return v8::Uint32::NewFromUnsigned(isolate_, uint_value_);
+ case TYPE_DOUBLE:
+ return v8::Number::New(isolate_, double_value_);
+ case TYPE_DATE:
+ // Convert from seconds to milliseconds.
+ return v8::Date::New(isolate_->GetCurrentContext(),
+ static_cast<base::Time>(CefBaseTime(date_value_))
+ .ToJsTimeIgnoringNull())
+ .ToLocalChecked();
+ case TYPE_STRING:
+ return GetV8String(isolate_, CefString(&string_value_));
+ case TYPE_OBJECT:
+ return handle_->GetNewV8Handle(should_persist);
+ default:
+ break;
+ }
+
+ NOTREACHED() << "Invalid type for CefV8ValueImpl";
+ return v8::Local<v8::Value>();
+}
+
+bool CefV8ValueImpl::IsValid() {
+ if (!CEF_V8_HAS_ISOLATE() || type_ == TYPE_INVALID ||
+ (type_ == TYPE_OBJECT &&
+ (!handle_->BelongsToCurrentThread() || !handle_->IsValid()))) {
+ return false;
+ }
+ return true;
+}
+
+bool CefV8ValueImpl::IsUndefined() {
+ CEF_V8_REQUIRE_ISOLATE_RETURN(false);
+ return (type_ == TYPE_UNDEFINED);
+}
+
+bool CefV8ValueImpl::IsNull() {
+ CEF_V8_REQUIRE_ISOLATE_RETURN(false);
+ return (type_ == TYPE_NULL);
+}
+
+bool CefV8ValueImpl::IsBool() {
+ CEF_V8_REQUIRE_ISOLATE_RETURN(false);
+ return (type_ == TYPE_BOOL);
+}
+
+bool CefV8ValueImpl::IsInt() {
+ CEF_V8_REQUIRE_ISOLATE_RETURN(false);
+ return (type_ == TYPE_INT || type_ == TYPE_UINT);
+}
+
+bool CefV8ValueImpl::IsUInt() {
+ CEF_V8_REQUIRE_ISOLATE_RETURN(false);
+ return (type_ == TYPE_INT || type_ == TYPE_UINT);
+}
+
+bool CefV8ValueImpl::IsDouble() {
+ CEF_V8_REQUIRE_ISOLATE_RETURN(false);
+ return (type_ == TYPE_INT || type_ == TYPE_UINT || type_ == TYPE_DOUBLE);
+}
+
+bool CefV8ValueImpl::IsDate() {
+ CEF_V8_REQUIRE_ISOLATE_RETURN(false);
+ return (type_ == TYPE_DATE);
+}
+
+bool CefV8ValueImpl::IsString() {
+ CEF_V8_REQUIRE_ISOLATE_RETURN(false);
+ return (type_ == TYPE_STRING);
+}
+
+bool CefV8ValueImpl::IsObject() {
+ CEF_V8_REQUIRE_ISOLATE_RETURN(false);
+ return (type_ == TYPE_OBJECT);
+}
+
+bool CefV8ValueImpl::IsArray() {
+ CEF_V8_REQUIRE_MLT_RETURN(false);
+ if (type_ == TYPE_OBJECT) {
+ v8::HandleScope handle_scope(handle_->isolate());
+ return handle_->GetNewV8Handle(false)->IsArray();
+ } else {
+ return false;
+ }
+}
+
+bool CefV8ValueImpl::IsArrayBuffer() {
+ CEF_V8_REQUIRE_MLT_RETURN(false);
+ if (type_ == TYPE_OBJECT) {
+ v8::HandleScope handle_scope(handle_->isolate());
+ return handle_->GetNewV8Handle(false)->IsArrayBuffer();
+ } else {
+ return false;
+ }
+}
+
+bool CefV8ValueImpl::IsFunction() {
+ CEF_V8_REQUIRE_MLT_RETURN(false);
+ if (type_ == TYPE_OBJECT) {
+ v8::HandleScope handle_scope(handle_->isolate());
+ return handle_->GetNewV8Handle(false)->IsFunction();
+ } else {
+ return false;
+ }
+}
+
+bool CefV8ValueImpl::IsPromise() {
+ CEF_V8_REQUIRE_MLT_RETURN(false);
+ if (type_ == TYPE_OBJECT) {
+ v8::HandleScope handle_scope(handle_->isolate());
+ return handle_->GetNewV8Handle(false)->IsPromise();
+ } else {
+ return false;
+ }
+}
+
+bool CefV8ValueImpl::IsSame(CefRefPtr<CefV8Value> that) {
+ CEF_V8_REQUIRE_MLT_RETURN(false);
+
+ CefV8ValueImpl* thatValue = static_cast<CefV8ValueImpl*>(that.get());
+ if (!thatValue || !thatValue->IsValid() || type_ != thatValue->type_) {
+ return false;
+ }
+
+ switch (type_) {
+ case TYPE_UNDEFINED:
+ case TYPE_NULL:
+ return true;
+ case TYPE_BOOL:
+ return (bool_value_ == thatValue->bool_value_);
+ case TYPE_INT:
+ return (int_value_ == thatValue->int_value_);
+ case TYPE_UINT:
+ return (uint_value_ == thatValue->uint_value_);
+ case TYPE_DOUBLE:
+ return (double_value_ == thatValue->double_value_);
+ case TYPE_DATE:
+ return (date_value_.val == thatValue->date_value_.val);
+ case TYPE_STRING:
+ return (CefString(&string_value_) ==
+ CefString(&thatValue->string_value_));
+ case TYPE_OBJECT: {
+ return (handle_->GetPersistentV8Handle() ==
+ thatValue->handle_->GetPersistentV8Handle());
+ }
+ default:
+ break;
+ }
+
+ return false;
+}
+
+bool CefV8ValueImpl::GetBoolValue() {
+ CEF_V8_REQUIRE_ISOLATE_RETURN(false);
+ if (type_ == TYPE_BOOL) {
+ return bool_value_;
+ }
+ return false;
+}
+
+int32 CefV8ValueImpl::GetIntValue() {
+ CEF_V8_REQUIRE_ISOLATE_RETURN(0);
+ if (type_ == TYPE_INT || type_ == TYPE_UINT) {
+ return int_value_;
+ }
+ return 0;
+}
+
+uint32 CefV8ValueImpl::GetUIntValue() {
+ CEF_V8_REQUIRE_ISOLATE_RETURN(0);
+ if (type_ == TYPE_INT || type_ == TYPE_UINT) {
+ return uint_value_;
+ }
+ return 0;
+}
+
+double CefV8ValueImpl::GetDoubleValue() {
+ CEF_V8_REQUIRE_ISOLATE_RETURN(0.);
+ if (type_ == TYPE_DOUBLE) {
+ return double_value_;
+ } else if (type_ == TYPE_INT) {
+ return int_value_;
+ } else if (type_ == TYPE_UINT) {
+ return uint_value_;
+ }
+ return 0.;
+}
+
+CefBaseTime CefV8ValueImpl::GetDateValue() {
+ CEF_V8_REQUIRE_ISOLATE_RETURN(CefBaseTime());
+ if (type_ == TYPE_DATE) {
+ return date_value_;
+ }
+ return CefBaseTime();
+}
+
+CefString CefV8ValueImpl::GetStringValue() {
+ CefString rv;
+ CEF_V8_REQUIRE_ISOLATE_RETURN(rv);
+ if (type_ == TYPE_STRING) {
+ rv = CefString(&string_value_);
+ }
+ return rv;
+}
+
+bool CefV8ValueImpl::IsUserCreated() {
+ CEF_V8_REQUIRE_OBJECT_RETURN(false);
+
+ v8::Isolate* isolate = handle_->isolate();
+ v8::HandleScope handle_scope(isolate);
+
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+ if (context.IsEmpty()) {
+ NOTREACHED() << "not currently in a V8 context";
+ return false;
+ }
+
+ v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
+ v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
+
+ V8TrackObject* tracker = V8TrackObject::Unwrap(context, obj);
+ return (tracker != nullptr);
+}
+
+bool CefV8ValueImpl::HasException() {
+ CEF_V8_REQUIRE_OBJECT_RETURN(false);
+
+ return (last_exception_.get() != nullptr);
+}
+
+CefRefPtr<CefV8Exception> CefV8ValueImpl::GetException() {
+ CEF_V8_REQUIRE_OBJECT_RETURN(nullptr);
+
+ return last_exception_;
+}
+
+bool CefV8ValueImpl::ClearException() {
+ CEF_V8_REQUIRE_OBJECT_RETURN(false);
+
+ last_exception_ = nullptr;
+ return true;
+}
+
+bool CefV8ValueImpl::WillRethrowExceptions() {
+ CEF_V8_REQUIRE_OBJECT_RETURN(false);
+
+ return rethrow_exceptions_;
+}
+
+bool CefV8ValueImpl::SetRethrowExceptions(bool rethrow) {
+ CEF_V8_REQUIRE_OBJECT_RETURN(false);
+
+ rethrow_exceptions_ = rethrow;
+ return true;
+}
+
+bool CefV8ValueImpl::HasValue(const CefString& key) {
+ CEF_V8_REQUIRE_OBJECT_RETURN(false);
+
+ v8::Isolate* isolate = handle_->isolate();
+ v8::HandleScope handle_scope(isolate);
+
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+ if (context.IsEmpty()) {
+ NOTREACHED() << "not currently in a V8 context";
+ return false;
+ }
+
+ v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
+ v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
+ return obj->Has(context, GetV8String(isolate, key)).FromJust();
+}
+
+bool CefV8ValueImpl::HasValue(int index) {
+ CEF_V8_REQUIRE_OBJECT_RETURN(false);
+
+ if (index < 0) {
+ NOTREACHED() << "invalid input parameter";
+ return false;
+ }
+
+ v8::Isolate* isolate = handle_->isolate();
+ v8::HandleScope handle_scope(isolate);
+
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+ if (context.IsEmpty()) {
+ NOTREACHED() << "not currently in a V8 context";
+ return false;
+ }
+
+ v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
+ v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
+ return obj->Has(context, index).FromJust();
+}
+
+bool CefV8ValueImpl::DeleteValue(const CefString& key) {
+ CEF_V8_REQUIRE_OBJECT_RETURN(false);
+
+ v8::Isolate* isolate = handle_->isolate();
+ v8::HandleScope handle_scope(isolate);
+
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+ if (context.IsEmpty()) {
+ NOTREACHED() << "not currently in a V8 context";
+ return false;
+ }
+
+ v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
+ v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
+
+ v8::TryCatch try_catch(isolate);
+ try_catch.SetVerbose(true);
+ v8::Maybe<bool> del = obj->Delete(context, GetV8String(isolate, key));
+ return (!HasCaught(context, try_catch) && del.FromJust());
+}
+
+bool CefV8ValueImpl::DeleteValue(int index) {
+ CEF_V8_REQUIRE_OBJECT_RETURN(false);
+
+ if (index < 0) {
+ NOTREACHED() << "invalid input parameter";
+ return false;
+ }
+
+ v8::Isolate* isolate = handle_->isolate();
+ v8::HandleScope handle_scope(isolate);
+
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+ if (context.IsEmpty()) {
+ NOTREACHED() << "not currently in a V8 context";
+ return false;
+ }
+
+ v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
+ v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
+
+ v8::TryCatch try_catch(isolate);
+ try_catch.SetVerbose(true);
+ v8::Maybe<bool> del = obj->Delete(context, index);
+ return (!HasCaught(context, try_catch) && del.FromJust());
+}
+
+CefRefPtr<CefV8Value> CefV8ValueImpl::GetValue(const CefString& key) {
+ CEF_V8_REQUIRE_OBJECT_RETURN(nullptr);
+
+ v8::Isolate* isolate = handle_->isolate();
+ v8::HandleScope handle_scope(isolate);
+
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+ if (context.IsEmpty()) {
+ NOTREACHED() << "not currently in a V8 context";
+ return nullptr;
+ }
+
+ v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
+ v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
+
+ v8::TryCatch try_catch(isolate);
+ try_catch.SetVerbose(true);
+ v8::MaybeLocal<v8::Value> ret_value =
+ obj->Get(context, GetV8String(isolate, key));
+ if (!HasCaught(context, try_catch) && !ret_value.IsEmpty()) {
+ return new CefV8ValueImpl(isolate, context, ret_value.ToLocalChecked());
+ }
+ return nullptr;
+}
+
+CefRefPtr<CefV8Value> CefV8ValueImpl::GetValue(int index) {
+ CEF_V8_REQUIRE_OBJECT_RETURN(nullptr);
+
+ if (index < 0) {
+ NOTREACHED() << "invalid input parameter";
+ return nullptr;
+ }
+
+ v8::Isolate* isolate = handle_->isolate();
+ v8::HandleScope handle_scope(isolate);
+
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+ if (context.IsEmpty()) {
+ NOTREACHED() << "not currently in a V8 context";
+ return nullptr;
+ }
+
+ v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
+ v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
+
+ v8::TryCatch try_catch(isolate);
+ try_catch.SetVerbose(true);
+ v8::MaybeLocal<v8::Value> ret_value =
+ obj->Get(context, v8::Number::New(isolate, index));
+ if (!HasCaught(context, try_catch) && !ret_value.IsEmpty()) {
+ return new CefV8ValueImpl(isolate, context, ret_value.ToLocalChecked());
+ }
+ return nullptr;
+}
+
+bool CefV8ValueImpl::SetValue(const CefString& key,
+ CefRefPtr<CefV8Value> value,
+ PropertyAttribute attribute) {
+ CEF_V8_REQUIRE_OBJECT_RETURN(false);
+
+ CefV8ValueImpl* impl = static_cast<CefV8ValueImpl*>(value.get());
+ if (impl && impl->IsValid()) {
+ v8::Isolate* isolate = handle_->isolate();
+ v8::HandleScope handle_scope(isolate);
+
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+ if (context.IsEmpty()) {
+ NOTREACHED() << "not currently in a V8 context";
+ return false;
+ }
+
+ v8::Local<v8::Value> v8value = handle_->GetNewV8Handle(false);
+ v8::Local<v8::Object> obj = v8value->ToObject(context).ToLocalChecked();
+
+ v8::TryCatch try_catch(isolate);
+ try_catch.SetVerbose(true);
+ // TODO(cef): This usage may not exactly match the previous implementation.
+ // Set will trigger interceptors and/or accessors whereas DefineOwnProperty
+ // will not. It might be better to split this functionality into separate
+ // methods.
+ if (attribute == V8_PROPERTY_ATTRIBUTE_NONE) {
+ v8::Maybe<bool> set =
+ obj->Set(context, GetV8String(isolate, key), impl->GetV8Value(true));
+ return (!HasCaught(context, try_catch) && set.FromJust());
+ } else {
+ v8::Maybe<bool> set = obj->DefineOwnProperty(
+ context, GetV8String(isolate, key), impl->GetV8Value(true),
+ static_cast<v8::PropertyAttribute>(attribute));
+ return (!HasCaught(context, try_catch) && set.FromJust());
+ }
+ } else {
+ NOTREACHED() << "invalid input parameter";
+ return false;
+ }
+}
+
+bool CefV8ValueImpl::SetValue(int index, CefRefPtr<CefV8Value> value) {
+ CEF_V8_REQUIRE_OBJECT_RETURN(false);
+
+ if (index < 0) {
+ NOTREACHED() << "invalid input parameter";
+ return false;
+ }
+
+ CefV8ValueImpl* impl = static_cast<CefV8ValueImpl*>(value.get());
+ if (impl && impl->IsValid()) {
+ v8::Isolate* isolate = handle_->isolate();
+ v8::HandleScope handle_scope(isolate);
+
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+ if (context.IsEmpty()) {
+ NOTREACHED() << "not currently in a V8 context";
+ return false;
+ }
+
+ v8::Local<v8::Value> v8value = handle_->GetNewV8Handle(false);
+ v8::Local<v8::Object> obj = v8value->ToObject(context).ToLocalChecked();
+
+ v8::TryCatch try_catch(isolate);
+ try_catch.SetVerbose(true);
+ v8::Maybe<bool> set = obj->Set(context, index, impl->GetV8Value(true));
+ return (!HasCaught(context, try_catch) && set.FromJust());
+ } else {
+ NOTREACHED() << "invalid input parameter";
+ return false;
+ }
+}
+
+bool CefV8ValueImpl::SetValue(const CefString& key,
+ AccessControl settings,
+ PropertyAttribute attribute) {
+ CEF_V8_REQUIRE_OBJECT_RETURN(false);
+
+ v8::Isolate* isolate = handle_->isolate();
+ v8::HandleScope handle_scope(isolate);
+
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+ if (context.IsEmpty()) {
+ NOTREACHED() << "not currently in a V8 context";
+ return false;
+ }
+
+ v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
+ v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
+
+ CefRefPtr<CefV8Accessor> accessorPtr;
+
+ V8TrackObject* tracker = V8TrackObject::Unwrap(context, obj);
+ if (tracker) {
+ accessorPtr = tracker->GetAccessor();
+ }
+
+ // Verify that an accessor exists for this object.
+ if (!accessorPtr.get()) {
+ return false;
+ }
+
+ v8::AccessorNameGetterCallback getter = AccessorNameGetterCallbackImpl;
+ v8::AccessorNameSetterCallback setter =
+ (attribute & V8_PROPERTY_ATTRIBUTE_READONLY)
+ ? nullptr
+ : AccessorNameSetterCallbackImpl;
+
+ v8::TryCatch try_catch(isolate);
+ try_catch.SetVerbose(true);
+ v8::Maybe<bool> set =
+ obj->SetAccessor(context, GetV8String(isolate, key), getter, setter, obj,
+ static_cast<v8::AccessControl>(settings),
+ static_cast<v8::PropertyAttribute>(attribute));
+ return (!HasCaught(context, try_catch) && set.FromJust());
+}
+
+bool CefV8ValueImpl::GetKeys(std::vector<CefString>& keys) {
+ CEF_V8_REQUIRE_OBJECT_RETURN(false);
+
+ v8::Isolate* isolate = handle_->isolate();
+ v8::HandleScope handle_scope(isolate);
+
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+ if (context.IsEmpty()) {
+ NOTREACHED() << "not currently in a V8 context";
+ return false;
+ }
+
+ v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
+ v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
+ v8::Local<v8::Array> arr_keys =
+ obj->GetPropertyNames(context).ToLocalChecked();
+
+ uint32_t len = arr_keys->Length();
+ for (uint32_t i = 0; i < len; ++i) {
+ v8::Local<v8::Value> arr_value =
+ arr_keys->Get(context, v8::Integer::New(isolate, i)).ToLocalChecked();
+ CefString str;
+ GetCefString(isolate, arr_value->ToString(context).ToLocalChecked(), str);
+ keys.push_back(str);
+ }
+ return true;
+}
+
+bool CefV8ValueImpl::SetUserData(CefRefPtr<CefBaseRefCounted> user_data) {
+ CEF_V8_REQUIRE_OBJECT_RETURN(false);
+
+ v8::Isolate* isolate = handle_->isolate();
+ v8::HandleScope handle_scope(isolate);
+
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+ if (context.IsEmpty()) {
+ NOTREACHED() << "not currently in a V8 context";
+ return false;
+ }
+
+ v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
+ v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
+
+ V8TrackObject* tracker = V8TrackObject::Unwrap(context, obj);
+ if (tracker) {
+ tracker->SetUserData(user_data);
+ return true;
+ }
+
+ return false;
+}
+
+CefRefPtr<CefBaseRefCounted> CefV8ValueImpl::GetUserData() {
+ CEF_V8_REQUIRE_OBJECT_RETURN(nullptr);
+
+ v8::Isolate* isolate = handle_->isolate();
+ v8::HandleScope handle_scope(isolate);
+
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+ if (context.IsEmpty()) {
+ NOTREACHED() << "not currently in a V8 context";
+ return nullptr;
+ }
+
+ v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
+ v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
+
+ V8TrackObject* tracker = V8TrackObject::Unwrap(context, obj);
+ if (tracker) {
+ return tracker->GetUserData();
+ }
+
+ return nullptr;
+}
+
+int CefV8ValueImpl::GetExternallyAllocatedMemory() {
+ CEF_V8_REQUIRE_OBJECT_RETURN(0);
+
+ v8::Isolate* isolate = handle_->isolate();
+ v8::HandleScope handle_scope(isolate);
+
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+ if (context.IsEmpty()) {
+ NOTREACHED() << "not currently in a V8 context";
+ return 0;
+ }
+
+ v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
+ v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
+
+ V8TrackObject* tracker = V8TrackObject::Unwrap(context, obj);
+ if (tracker) {
+ return tracker->GetExternallyAllocatedMemory();
+ }
+
+ return 0;
+}
+
+int CefV8ValueImpl::AdjustExternallyAllocatedMemory(int change_in_bytes) {
+ CEF_V8_REQUIRE_OBJECT_RETURN(0);
+
+ v8::Isolate* isolate = handle_->isolate();
+ v8::HandleScope handle_scope(isolate);
+
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+ if (context.IsEmpty()) {
+ NOTREACHED() << "not currently in a V8 context";
+ return 0;
+ }
+
+ v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
+ v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
+
+ V8TrackObject* tracker = V8TrackObject::Unwrap(context, obj);
+ if (tracker) {
+ return tracker->AdjustExternallyAllocatedMemory(change_in_bytes);
+ }
+
+ return 0;
+}
+
+int CefV8ValueImpl::GetArrayLength() {
+ CEF_V8_REQUIRE_OBJECT_RETURN(0);
+
+ v8::Isolate* isolate = handle_->isolate();
+ v8::HandleScope handle_scope(isolate);
+
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+ if (context.IsEmpty()) {
+ NOTREACHED() << "not currently in a V8 context";
+ return 0;
+ }
+
+ v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
+ if (!value->IsArray()) {
+ NOTREACHED() << "V8 value is not an array";
+ return 0;
+ }
+
+ v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
+ v8::Local<v8::Array> arr = v8::Local<v8::Array>::Cast(obj);
+ return arr->Length();
+}
+
+CefRefPtr<CefV8ArrayBufferReleaseCallback>
+CefV8ValueImpl::GetArrayBufferReleaseCallback() {
+ CEF_V8_REQUIRE_OBJECT_RETURN(nullptr);
+
+ v8::Isolate* isolate = handle_->isolate();
+ v8::HandleScope handle_scope(isolate);
+
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+ if (context.IsEmpty()) {
+ NOTREACHED() << "not currently in a V8 context";
+ return nullptr;
+ }
+
+ v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
+ if (!value->IsArrayBuffer()) {
+ NOTREACHED() << "V8 value is not an array buffer";
+ return nullptr;
+ }
+
+ v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
+
+ V8TrackArrayBuffer* tracker = V8TrackArrayBuffer::Unwrap(context, obj);
+ if (tracker) {
+ return tracker->GetReleaseCallback();
+ }
+
+ return nullptr;
+}
+
+bool CefV8ValueImpl::NeuterArrayBuffer() {
+ CEF_V8_REQUIRE_OBJECT_RETURN(0);
+
+ v8::Isolate* isolate = handle_->isolate();
+ v8::HandleScope handle_scope(isolate);
+
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+ if (context.IsEmpty()) {
+ NOTREACHED() << "not currently in a V8 context";
+ return false;
+ }
+
+ v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
+ if (!value->IsArrayBuffer()) {
+ NOTREACHED() << "V8 value is not an array buffer";
+ return false;
+ }
+ v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
+ v8::Local<v8::ArrayBuffer> arr = v8::Local<v8::ArrayBuffer>::Cast(obj);
+ if (!arr->IsDetachable()) {
+ return false;
+ }
+ arr->Detach();
+
+ return true;
+}
+
+CefString CefV8ValueImpl::GetFunctionName() {
+ CefString rv;
+ CEF_V8_REQUIRE_OBJECT_RETURN(rv);
+
+ v8::Isolate* isolate = handle_->isolate();
+ v8::HandleScope handle_scope(isolate);
+
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+ if (context.IsEmpty()) {
+ NOTREACHED() << "not currently in a V8 context";
+ return rv;
+ }
+
+ v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
+ if (!value->IsFunction()) {
+ NOTREACHED() << "V8 value is not a function";
+ return rv;
+ }
+
+ v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
+ v8::Local<v8::Function> func = v8::Local<v8::Function>::Cast(obj);
+ GetCefString(handle_->isolate(),
+ v8::Handle<v8::String>::Cast(func->GetName()), rv);
+ return rv;
+}
+
+CefRefPtr<CefV8Handler> CefV8ValueImpl::GetFunctionHandler() {
+ CEF_V8_REQUIRE_OBJECT_RETURN(nullptr);
+
+ v8::Isolate* isolate = handle_->isolate();
+ v8::HandleScope handle_scope(isolate);
+
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+ if (context.IsEmpty()) {
+ NOTREACHED() << "not currently in a V8 context";
+ return nullptr;
+ }
+
+ v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
+ if (!value->IsFunction()) {
+ NOTREACHED() << "V8 value is not a function";
+ return nullptr;
+ }
+
+ v8::Local<v8::Object> obj = value->ToObject(context).ToLocalChecked();
+ V8TrackObject* tracker = V8TrackObject::Unwrap(context, obj);
+ if (tracker) {
+ return tracker->GetHandler();
+ }
+
+ return nullptr;
+}
+
+CefRefPtr<CefV8Value> CefV8ValueImpl::ExecuteFunction(
+ CefRefPtr<CefV8Value> object,
+ const CefV8ValueList& arguments) {
+ // An empty context value defaults to the current context.
+ CefRefPtr<CefV8Context> context;
+ return ExecuteFunctionWithContext(context, object, arguments);
+}
+
+CefRefPtr<CefV8Value> CefV8ValueImpl::ExecuteFunctionWithContext(
+ CefRefPtr<CefV8Context> context,
+ CefRefPtr<CefV8Value> object,
+ const CefV8ValueList& arguments) {
+ CEF_V8_REQUIRE_OBJECT_RETURN(nullptr);
+
+ v8::Isolate* isolate = handle_->isolate();
+ v8::HandleScope handle_scope(isolate);
+ v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
+ if (!value->IsFunction()) {
+ NOTREACHED() << "V8 value is not a function";
+ return nullptr;
+ }
+
+ if (context.get() && !context->IsValid()) {
+ NOTREACHED() << "invalid V8 context parameter";
+ return nullptr;
+ }
+ if (object.get() && (!object->IsValid() || !object->IsObject())) {
+ NOTREACHED() << "invalid V8 object parameter";
+ return nullptr;
+ }
+
+ int argc = arguments.size();
+ if (argc > 0) {
+ for (int i = 0; i < argc; ++i) {
+ if (!arguments[i].get() || !arguments[i]->IsValid()) {
+ NOTREACHED() << "invalid V8 arguments parameter";
+ return nullptr;
+ }
+ }
+ }
+
+ v8::Local<v8::Context> context_local;
+ if (context.get()) {
+ CefV8ContextImpl* context_impl =
+ static_cast<CefV8ContextImpl*>(context.get());
+ context_local = context_impl->GetV8Context();
+ } else {
+ context_local = isolate->GetCurrentContext();
+ }
+
+ v8::Context::Scope context_scope(context_local);
+
+ v8::Local<v8::Object> obj = value->ToObject(context_local).ToLocalChecked();
+ v8::Local<v8::Function> func = v8::Local<v8::Function>::Cast(obj);
+ v8::Local<v8::Object> recv;
+
+ // Default to the global object if no object was provided.
+ if (object.get()) {
+ CefV8ValueImpl* recv_impl = static_cast<CefV8ValueImpl*>(object.get());
+ recv = v8::Local<v8::Object>::Cast(recv_impl->GetV8Value(true));
+ } else {
+ recv = context_local->Global();
+ }
+
+ v8::Local<v8::Value>* argv = nullptr;
+ if (argc > 0) {
+ argv = new v8::Local<v8::Value>[argc];
+ for (int i = 0; i < argc; ++i) {
+ argv[i] =
+ static_cast<CefV8ValueImpl*>(arguments[i].get())->GetV8Value(true);
+ }
+ }
+
+ CefRefPtr<CefV8Value> retval;
+
+ {
+ v8::TryCatch try_catch(isolate);
+ try_catch.SetVerbose(true);
+
+ v8::MaybeLocal<v8::Value> func_rv = blink_glue::CallV8Function(
+ context_local, func, recv, argc, argv, handle_->isolate());
+
+ if (!HasCaught(context_local, try_catch) && !func_rv.IsEmpty()) {
+ retval =
+ new CefV8ValueImpl(isolate, context_local, func_rv.ToLocalChecked());
+ }
+ }
+
+ if (argv) {
+ delete[] argv;
+ }
+
+ return retval;
+}
+
+bool CefV8ValueImpl::ResolvePromise(CefRefPtr<CefV8Value> arg) {
+ CEF_V8_REQUIRE_OBJECT_RETURN(false);
+
+ v8::Isolate* isolate = handle_->isolate();
+ v8::HandleScope handle_scope(isolate);
+ v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
+ if (!value->IsPromise()) {
+ NOTREACHED() << "V8 value is not a Promise";
+ return false;
+ }
+
+ if (arg.get() && !arg->IsValid()) {
+ NOTREACHED() << "invalid V8 arg parameter";
+ return false;
+ }
+
+ v8::Local<v8::Context> context_local = isolate->GetCurrentContext();
+
+ v8::Context::Scope context_scope(context_local);
+
+ v8::Local<v8::Object> obj = value->ToObject(context_local).ToLocalChecked();
+ v8::Local<v8::Promise::Resolver> promise =
+ v8::Local<v8::Promise::Resolver>::Cast(obj);
+
+ v8::TryCatch try_catch(isolate);
+ try_catch.SetVerbose(true);
+
+ if (arg.get()) {
+ promise
+ ->Resolve(context_local,
+ static_cast<CefV8ValueImpl*>(arg.get())->GetV8Value(true))
+ .ToChecked();
+ } else {
+ promise->Resolve(context_local, v8::Undefined(isolate)).ToChecked();
+ }
+
+ return !HasCaught(context_local, try_catch);
+}
+
+bool CefV8ValueImpl::RejectPromise(const CefString& errorMsg) {
+ CEF_V8_REQUIRE_OBJECT_RETURN(false);
+
+ v8::Isolate* isolate = handle_->isolate();
+ v8::HandleScope handle_scope(isolate);
+ v8::Local<v8::Value> value = handle_->GetNewV8Handle(false);
+ if (!value->IsPromise()) {
+ NOTREACHED() << "V8 value is not a Promise";
+ return false;
+ }
+
+ v8::Local<v8::Context> context_local = isolate->GetCurrentContext();
+
+ v8::Context::Scope context_scope(context_local);
+
+ v8::Local<v8::Object> obj = value->ToObject(context_local).ToLocalChecked();
+ v8::Local<v8::Promise::Resolver> promise =
+ v8::Local<v8::Promise::Resolver>::Cast(obj);
+
+ v8::TryCatch try_catch(isolate);
+ try_catch.SetVerbose(true);
+
+ promise
+ ->Reject(context_local,
+ v8::Exception::Error(GetV8String(isolate, errorMsg)))
+ .ToChecked();
+
+ return !HasCaught(context_local, try_catch);
+}
+
+bool CefV8ValueImpl::HasCaught(v8::Local<v8::Context> context,
+ v8::TryCatch& try_catch) {
+ if (try_catch.HasCaught()) {
+ last_exception_ = new CefV8ExceptionImpl(context, try_catch.Message());
+ if (rethrow_exceptions_) {
+ try_catch.ReThrow();
+ }
+ return true;
+ } else {
+ if (last_exception_.get()) {
+ last_exception_ = nullptr;
+ }
+ return false;
+ }
+}
+
+// CefV8StackTrace
+
+// static
+CefRefPtr<CefV8StackTrace> CefV8StackTrace::GetCurrent(int frame_limit) {
+ CEF_V8_REQUIRE_ISOLATE_RETURN(nullptr);
+
+ v8::Isolate* isolate = GetIsolateManager()->isolate();
+ v8::HandleScope handle_scope(isolate);
+ v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
+ isolate, frame_limit, v8::StackTrace::kDetailed);
+ if (stackTrace.IsEmpty()) {
+ return nullptr;
+ }
+ return new CefV8StackTraceImpl(isolate, stackTrace);
+}
+
+// CefV8StackTraceImpl
+
+CefV8StackTraceImpl::CefV8StackTraceImpl(v8::Isolate* isolate,
+ v8::Local<v8::StackTrace> handle) {
+ if (!handle.IsEmpty()) {
+ int frame_count = handle->GetFrameCount();
+ if (frame_count > 0) {
+ frames_.reserve(frame_count);
+ for (int i = 0; i < frame_count; ++i) {
+ frames_.push_back(
+ new CefV8StackFrameImpl(isolate, handle->GetFrame(isolate, i)));
+ }
+ }
+ }
+}
+
+CefV8StackTraceImpl::~CefV8StackTraceImpl() {}
+
+bool CefV8StackTraceImpl::IsValid() {
+ return true;
+}
+
+int CefV8StackTraceImpl::GetFrameCount() {
+ return frames_.size();
+}
+
+CefRefPtr<CefV8StackFrame> CefV8StackTraceImpl::GetFrame(int index) {
+ if (index < 0 || index >= static_cast<int>(frames_.size())) {
+ return nullptr;
+ }
+ return frames_[index];
+}
+
+// CefV8StackFrameImpl
+
+CefV8StackFrameImpl::CefV8StackFrameImpl(v8::Isolate* isolate,
+ v8::Local<v8::StackFrame> handle)
+ : line_number_(0), column_(0), is_eval_(false), is_constructor_(false) {
+ if (handle.IsEmpty()) {
+ return;
+ }
+ GetCefString(isolate, handle->GetScriptName(), script_name_);
+ GetCefString(isolate, handle->GetScriptNameOrSourceURL(),
+ script_name_or_source_url_);
+ GetCefString(isolate, handle->GetFunctionName(), function_name_);
+ line_number_ = handle->GetLineNumber();
+ column_ = handle->GetColumn();
+ is_eval_ = handle->IsEval();
+ is_constructor_ = handle->IsConstructor();
+}
+
+CefV8StackFrameImpl::~CefV8StackFrameImpl() {}
+
+bool CefV8StackFrameImpl::IsValid() {
+ return true;
+}
+
+CefString CefV8StackFrameImpl::GetScriptName() {
+ return script_name_;
+}
+
+CefString CefV8StackFrameImpl::GetScriptNameOrSourceURL() {
+ return script_name_or_source_url_;
+}
+
+CefString CefV8StackFrameImpl::GetFunctionName() {
+ return function_name_;
+}
+
+int CefV8StackFrameImpl::GetLineNumber() {
+ return line_number_;
+}
+
+int CefV8StackFrameImpl::GetColumn() {
+ return column_;
+}
+
+bool CefV8StackFrameImpl::IsEval() {
+ return is_eval_;
+}
+
+bool CefV8StackFrameImpl::IsConstructor() {
+ return is_constructor_;
+}
+
+// Enable deprecation warnings on Windows. See http://crbug.com/585142.
+#if BUILDFLAG(IS_WIN)
+#if defined(__clang__)
+#pragma GCC diagnostic pop
+#else
+#pragma warning(pop)
+#endif
+#endif
diff --git a/libcef/renderer/v8_impl.h b/libcef/renderer/v8_impl.h
new file mode 100644
index 00000000..af18e9c6
--- /dev/null
+++ b/libcef/renderer/v8_impl.h
@@ -0,0 +1,416 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_RENDERER_V8_IMPL_H_
+#define CEF_LIBCEF_RENDERER_V8_IMPL_H_
+#pragma once
+
+#include <vector>
+
+#include "include/cef_v8.h"
+#include "libcef/common/tracker.h"
+
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/task/single_thread_task_runner.h"
+#include "v8/include/v8.h"
+
+class CefTrackNode;
+class GURL;
+
+namespace blink {
+class WebLocalFrame;
+}
+
+// Call after a V8 Isolate has been created and entered for the first time.
+void CefV8IsolateCreated();
+
+// Call before a V8 Isolate is exited and destroyed.
+void CefV8IsolateDestroyed();
+
+// Call to detach all handles associated with the specified context.
+void CefV8ReleaseContext(v8::Local<v8::Context> context);
+
+// Set the stack size for uncaught exceptions.
+void CefV8SetUncaughtExceptionStackSize(int stack_size);
+
+// Set attributes associated with a WebWorker thread.
+void CefV8SetWorkerAttributes(int worker_id, const GURL& worker_url);
+
+// Used to detach handles when the associated context is released.
+class CefV8ContextState : public base::RefCounted<CefV8ContextState> {
+ public:
+ CefV8ContextState() : valid_(true) {}
+
+ bool IsValid() { return valid_; }
+ void Detach() {
+ DCHECK(valid_);
+ valid_ = false;
+ track_manager_.DeleteAll();
+ }
+
+ void AddTrackObject(CefTrackNode* object) {
+ DCHECK(valid_);
+ track_manager_.Add(object);
+ }
+
+ void DeleteTrackObject(CefTrackNode* object) {
+ DCHECK(valid_);
+ track_manager_.Delete(object);
+ }
+
+ private:
+ friend class base::RefCounted<CefV8ContextState>;
+
+ ~CefV8ContextState() {}
+
+ bool valid_;
+ CefTrackManager track_manager_;
+};
+
+// Use this template in conjuction with RefCountedThreadSafe to ensure that a
+// V8 object is deleted on the correct thread.
+struct CefV8DeleteOnMessageLoopThread {
+ template <typename T>
+ static void Destruct(const T* x) {
+ if (x->task_runner()->RunsTasksInCurrentSequence()) {
+ delete x;
+ } else {
+ if (!x->task_runner()->DeleteSoon(FROM_HERE, x)) {
+#if defined(UNIT_TEST)
+ // Only logged under unit testing because leaks at shutdown
+ // are acceptable under normal circumstances.
+ LOG(ERROR) << "DeleteSoon failed on thread " << thread;
+#endif // UNIT_TEST
+ }
+ }
+ }
+};
+
+// Base class for V8 Handle types.
+class CefV8HandleBase
+ : public base::RefCountedThreadSafe<CefV8HandleBase,
+ CefV8DeleteOnMessageLoopThread> {
+ public:
+ // Returns true if there is no underlying context or if the underlying context
+ // is valid.
+ bool IsValid() const {
+ return (!context_state_.get() || context_state_->IsValid());
+ }
+
+ bool BelongsToCurrentThread() const;
+
+ v8::Isolate* isolate() const { return isolate_; }
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner() const {
+ return task_runner_;
+ }
+
+ protected:
+ friend class base::DeleteHelper<CefV8HandleBase>;
+ friend class base::RefCountedThreadSafe<CefV8HandleBase,
+ CefV8DeleteOnMessageLoopThread>;
+ friend struct CefV8DeleteOnMessageLoopThread;
+
+ // |context| is the context that owns this handle. If empty the current
+ // context will be used.
+ CefV8HandleBase(v8::Isolate* isolate, v8::Local<v8::Context> context);
+ virtual ~CefV8HandleBase();
+
+ protected:
+ v8::Isolate* isolate_;
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+ scoped_refptr<CefV8ContextState> context_state_;
+};
+
+// Template for V8 Handle types. This class is used to ensure that V8 objects
+// are only released on the render thread.
+template <typename v8class>
+class CefV8Handle : public CefV8HandleBase {
+ public:
+ using handleType = v8::Local<v8class>;
+ using persistentType = v8::Persistent<v8class>;
+
+ CefV8Handle(v8::Isolate* isolate,
+ v8::Local<v8::Context> context,
+ handleType v)
+ : CefV8HandleBase(isolate, context), handle_(isolate, v) {}
+
+ CefV8Handle(const CefV8Handle&) = delete;
+ CefV8Handle& operator=(const CefV8Handle&) = delete;
+
+ handleType GetNewV8Handle() {
+ DCHECK(IsValid());
+ return handleType::New(isolate(), handle_);
+ }
+
+ persistentType& GetPersistentV8Handle() { return handle_; }
+
+ protected:
+ ~CefV8Handle() override { handle_.Reset(); }
+
+ persistentType handle_;
+};
+
+// Specialization for v8::Value with empty implementation to avoid incorrect
+// usage.
+template <>
+class CefV8Handle<v8::Value> {};
+
+class CefV8ContextImpl : public CefV8Context {
+ public:
+ CefV8ContextImpl(v8::Isolate* isolate, v8::Local<v8::Context> context);
+
+ CefV8ContextImpl(const CefV8ContextImpl&) = delete;
+ CefV8ContextImpl& operator=(const CefV8ContextImpl&) = delete;
+
+ ~CefV8ContextImpl() override;
+
+ CefRefPtr<CefTaskRunner> GetTaskRunner() override;
+ bool IsValid() override;
+ CefRefPtr<CefBrowser> GetBrowser() override;
+ CefRefPtr<CefFrame> GetFrame() override;
+ CefRefPtr<CefV8Value> GetGlobal() override;
+ bool Enter() override;
+ bool Exit() override;
+ bool IsSame(CefRefPtr<CefV8Context> that) override;
+ bool Eval(const CefString& code,
+ const CefString& script_url,
+ int start_line,
+ CefRefPtr<CefV8Value>& retval,
+ CefRefPtr<CefV8Exception>& exception) override;
+
+ v8::Local<v8::Context> GetV8Context();
+ blink::WebLocalFrame* GetWebFrame();
+
+ private:
+ using Handle = CefV8Handle<v8::Context>;
+ scoped_refptr<Handle> handle_;
+ v8::MicrotaskQueue* const microtask_queue_;
+
+ int enter_count_ = 0;
+ std::unique_ptr<v8::MicrotasksScope> microtasks_scope_;
+
+ IMPLEMENT_REFCOUNTING(CefV8ContextImpl);
+};
+
+class CefV8ValueImpl : public CefV8Value {
+ public:
+ explicit CefV8ValueImpl(v8::Isolate* isolate);
+ CefV8ValueImpl(v8::Isolate* isolate,
+ v8::Local<v8::Context> context,
+ v8::Local<v8::Value> value);
+
+ CefV8ValueImpl(const CefV8ValueImpl&) = delete;
+ CefV8ValueImpl& operator=(const CefV8ValueImpl&) = delete;
+
+ ~CefV8ValueImpl() override;
+
+ // Used for initializing the CefV8ValueImpl. Should be called a single time
+ // after the CefV8ValueImpl is created.
+ void InitFromV8Value(v8::Local<v8::Context> context,
+ v8::Local<v8::Value> value);
+ void InitUndefined();
+ void InitNull();
+ void InitBool(bool value);
+ void InitInt(int32 value);
+ void InitUInt(uint32 value);
+ void InitDouble(double value);
+ void InitDate(CefBaseTime value);
+ void InitString(CefString& value);
+ void InitObject(v8::Local<v8::Value> value, CefTrackNode* tracker);
+
+ // Creates a new V8 value for the underlying value or returns the existing
+ // object handle.
+ v8::Local<v8::Value> GetV8Value(bool should_persist);
+
+ bool IsValid() override;
+ bool IsUndefined() override;
+ bool IsNull() override;
+ bool IsBool() override;
+ bool IsInt() override;
+ bool IsUInt() override;
+ bool IsDouble() override;
+ bool IsDate() override;
+ bool IsString() override;
+ bool IsObject() override;
+ bool IsArray() override;
+ bool IsArrayBuffer() override;
+ bool IsFunction() override;
+ bool IsPromise() override;
+ bool IsSame(CefRefPtr<CefV8Value> value) override;
+ bool GetBoolValue() override;
+ int32 GetIntValue() override;
+ uint32 GetUIntValue() override;
+ double GetDoubleValue() override;
+ CefBaseTime GetDateValue() override;
+ CefString GetStringValue() override;
+ bool IsUserCreated() override;
+ bool HasException() override;
+ CefRefPtr<CefV8Exception> GetException() override;
+ bool ClearException() override;
+ bool WillRethrowExceptions() override;
+ bool SetRethrowExceptions(bool rethrow) override;
+ bool HasValue(const CefString& key) override;
+ bool HasValue(int index) override;
+ bool DeleteValue(const CefString& key) override;
+ bool DeleteValue(int index) override;
+ CefRefPtr<CefV8Value> GetValue(const CefString& key) override;
+ CefRefPtr<CefV8Value> GetValue(int index) override;
+ bool SetValue(const CefString& key,
+ CefRefPtr<CefV8Value> value,
+ PropertyAttribute attribute) override;
+ bool SetValue(int index, CefRefPtr<CefV8Value> value) override;
+ bool SetValue(const CefString& key,
+ AccessControl settings,
+ PropertyAttribute attribute) override;
+ bool GetKeys(std::vector<CefString>& keys) override;
+ bool SetUserData(CefRefPtr<CefBaseRefCounted> user_data) override;
+ CefRefPtr<CefBaseRefCounted> GetUserData() override;
+ int GetExternallyAllocatedMemory() override;
+ int AdjustExternallyAllocatedMemory(int change_in_bytes) override;
+ int GetArrayLength() override;
+ CefRefPtr<CefV8ArrayBufferReleaseCallback> GetArrayBufferReleaseCallback()
+ override;
+ bool NeuterArrayBuffer() override;
+ CefString GetFunctionName() override;
+ CefRefPtr<CefV8Handler> GetFunctionHandler() override;
+ CefRefPtr<CefV8Value> ExecuteFunction(
+ CefRefPtr<CefV8Value> object,
+ const CefV8ValueList& arguments) override;
+ CefRefPtr<CefV8Value> ExecuteFunctionWithContext(
+ CefRefPtr<CefV8Context> context,
+ CefRefPtr<CefV8Value> object,
+ const CefV8ValueList& arguments) override;
+
+ bool ResolvePromise(CefRefPtr<CefV8Value> arg) override;
+ bool RejectPromise(const CefString& errorMsg) override;
+
+ private:
+ // Test for and record any exception.
+ bool HasCaught(v8::Local<v8::Context> context, v8::TryCatch& try_catch);
+
+ class Handle : public CefV8HandleBase {
+ public:
+ using handleType = v8::Local<v8::Value>;
+ using persistentType = v8::Persistent<v8::Value>;
+
+ Handle(v8::Isolate* isolate,
+ v8::Local<v8::Context> context,
+ handleType v,
+ CefTrackNode* tracker);
+
+ Handle(const Handle&) = delete;
+ Handle& operator=(const Handle&) = delete;
+
+ handleType GetNewV8Handle(bool should_persist);
+
+ persistentType& GetPersistentV8Handle();
+
+ void SetWeakIfNecessary();
+
+ private:
+ ~Handle() override;
+
+ private:
+ // Callbacks for weak persistent reference destruction.
+ static void FirstWeakCallback(const v8::WeakCallbackInfo<Handle>& data);
+ static void SecondWeakCallback(const v8::WeakCallbackInfo<Handle>& data);
+
+ persistentType handle_;
+
+ // For Object and Function types, we need to hold on to a reference to their
+ // internal data or function handler objects that are reference counted.
+ CefTrackNode* tracker_;
+
+ // True if the handle needs to persist due to it being passed into V8.
+ bool should_persist_;
+
+ // True if the handle has been set as weak.
+ bool is_set_weak_;
+ };
+
+ v8::Isolate* isolate_;
+
+ enum {
+ TYPE_INVALID = 0,
+ TYPE_UNDEFINED,
+ TYPE_NULL,
+ TYPE_BOOL,
+ TYPE_INT,
+ TYPE_UINT,
+ TYPE_DOUBLE,
+ TYPE_DATE,
+ TYPE_STRING,
+ TYPE_OBJECT,
+ } type_;
+
+ union {
+ bool bool_value_;
+ int32 int_value_;
+ uint32 uint_value_;
+ double double_value_;
+ cef_basetime_t date_value_;
+ cef_string_t string_value_;
+ };
+
+ // Used with Object, Function and Array types.
+ scoped_refptr<Handle> handle_;
+
+ CefRefPtr<CefV8Exception> last_exception_;
+ bool rethrow_exceptions_;
+
+ IMPLEMENT_REFCOUNTING(CefV8ValueImpl);
+};
+
+class CefV8StackTraceImpl : public CefV8StackTrace {
+ public:
+ CefV8StackTraceImpl(v8::Isolate* isolate, v8::Local<v8::StackTrace> handle);
+
+ CefV8StackTraceImpl(const CefV8StackTraceImpl&) = delete;
+ CefV8StackTraceImpl& operator=(const CefV8StackTraceImpl&) = delete;
+
+ ~CefV8StackTraceImpl() override;
+
+ bool IsValid() override;
+ int GetFrameCount() override;
+ CefRefPtr<CefV8StackFrame> GetFrame(int index) override;
+
+ private:
+ std::vector<CefRefPtr<CefV8StackFrame>> frames_;
+
+ IMPLEMENT_REFCOUNTING(CefV8StackTraceImpl);
+};
+
+class CefV8StackFrameImpl : public CefV8StackFrame {
+ public:
+ CefV8StackFrameImpl(v8::Isolate* isolate, v8::Local<v8::StackFrame> handle);
+
+ CefV8StackFrameImpl(const CefV8StackFrameImpl&) = delete;
+ CefV8StackFrameImpl& operator=(const CefV8StackFrameImpl&) = delete;
+
+ ~CefV8StackFrameImpl() override;
+
+ bool IsValid() override;
+ CefString GetScriptName() override;
+ CefString GetScriptNameOrSourceURL() override;
+ CefString GetFunctionName() override;
+ int GetLineNumber() override;
+ int GetColumn() override;
+ bool IsEval() override;
+ bool IsConstructor() override;
+
+ private:
+ CefString script_name_;
+ CefString script_name_or_source_url_;
+ CefString function_name_;
+ int line_number_;
+ int column_;
+ bool is_eval_;
+ bool is_constructor_;
+
+ IMPLEMENT_REFCOUNTING(CefV8StackFrameImpl);
+};
+
+#endif // CEF_LIBCEF_RENDERER_V8_IMPL_H_
diff --git a/libcef/resources/about_version.html b/libcef/resources/about_version.html
new file mode 100644
index 00000000..024755f3
--- /dev/null
+++ b/libcef/resources/about_version.html
@@ -0,0 +1,120 @@
+<!DOCTYPE HTML>
+
+<!--
+about:version template page
+-->
+
+<html id="t" i18n-values="dir:textdirection;">
+ <head>
+ <title>About Version</title>
+
+ <style>/* Copyright (c) 2012 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+body {
+ background-color: white;
+ color: black;
+ font-family: Helvetica,Arial,sans-serif;
+ margin: 0;
+}
+
+#outer {
+ margin-left: auto;
+ margin-right: auto;
+ margin-top: 10px;
+ width: 820px;
+}
+
+#inner {
+ padding-top: 10px;
+ width: 550px;
+}
+
+.label {
+ -webkit-padding-end: 5px;
+ font-size: 0.9em;
+ font-weight: bold;
+ text-align: end;
+ white-space: nowrap;
+}
+
+.label:after {
+ content: ':';
+}
+
+#logo {
+ float: right;
+ margin-left: 40px;
+ text-align: right;
+ width: 200px;
+}
+
+#company {
+ font-size: 0.7em;
+ text-align: right;
+}
+
+#copyright {
+ font-size: 0.7em;
+ text-align: right;
+}
+
+.value {
+ font-family: monospace;
+ max-width: 430px;
+ padding-left: 5px;
+}
+</style>
+
+ </head>
+
+ <body>
+ <div id="outer">
+ <div id="logo">
+ <div id="company">Chromium Embedded Framework (CEF)</div>
+ <div id="copyright">Copyright &copy; $$YEAR$$ The Chromium Embedded Framework Authors.<br/>All rights reserved.<br/><a href="chrome://license">license</a> | <a href="chrome://credits">credits</a></div>
+ </div>
+ <table id="inner" cellpadding="0" cellspacing="0" border="0">
+ <tr>
+ <td class="label" valign="top">CEF</td>
+ <td class="value">$$CEF$$</td>
+ </tr>
+ <tr>
+ <td class="label" valign="top">Chromium</td>
+ <td class="value">$$CHROMIUM$$</td>
+ </tr>
+ <tr>
+ <td class="label" valign="top">OS</td>
+ <td class="value">$$OS$$</td>
+ </tr>
+ <tr>
+ <td class="label" valign="top">WebKit</td>
+ <td class="value">$$WEBKIT$$</td>
+ </tr>
+ <tr>
+ <td class="label" valign="top">JavaScript</td>
+ <td class="value">$$JAVASCRIPT$$</td>
+ </tr>
+ <tr>
+ <td class="label" valign="top">User Agent</td>
+ <td class="value">$$USERAGENT$$</td>
+ </tr>
+ <tr>
+ <td class="label" valign="top">Command Line</td>
+ <td class="value">$$COMMANDLINE$$</td>
+ </tr>
+ <tr>
+ <td class="label" valign="top">Module Path</td>
+ <td class="value">$$MODULEPATH$$</td>
+ </tr>
+ <tr>
+ <td class="label" valign="top">Cache Path</td>
+ <td class="value">$$CACHEPATH$$</td>
+ </tr>
+ </table>
+ </div>
+ </body>
+
+</html>
+
diff --git a/libcef/resources/cef_resources.grd b/libcef/resources/cef_resources.grd
new file mode 100644
index 00000000..39b102eb
--- /dev/null
+++ b/libcef/resources/cef_resources.grd
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<grit latest_public_release="0" current_release="1">
+ <outputs>
+ <output filename="grit/cef_resources.h" type="rc_header">
+ <emit emit_type='prepend'></emit>
+ </output>
+ <output filename="cef_resources.pak" type="data_package" />
+ </outputs>
+ <translations />
+ <release seq="1">
+ <includes>
+ <include name="IDR_CEF_DEVTOOLS_DISCOVERY_PAGE" file="devtools_discovery_page.html" type="BINDATA" />
+ <include name="IDR_CEF_LICENSE_TXT" file="..\..\LICENSE.txt" type="BINDATA" />
+ <include name="IDR_CEF_VERSION_HTML" file="about_version.html" type="BINDATA" />
+
+ <!-- Extension features supported by CEF. -->
+ <include name="IDR_CEF_EXTENSION_API_FEATURES" file="..\common\extensions\api\_api_features.json" type="BINDATA" />
+ </includes>
+ </release>
+</grit>
diff --git a/libcef/resources/cef_strings.grd b/libcef/resources/cef_strings.grd
new file mode 100644
index 00000000..a3d59a2d
--- /dev/null
+++ b/libcef/resources/cef_strings.grd
@@ -0,0 +1,129 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- This file contains definitions of resources that will be translated for
+each locale. Specifically, these are UI strings that are used by CEF that
+need to be translated for each locale.-->
+<grit base_dir="." latest_public_release="0" current_release="1"
+ source_lang_id="en" enc_check="möl">
+ <outputs>
+ <!-- Note that all output references are relative to the output directory
+ which is specified at build time. -->
+ <output filename="grit/cef_strings.h" type="rc_header">
+ <emit emit_type='prepend'></emit>
+ </output>
+
+ <output filename="cef_strings_af.pak" type="data_package" lang="af" />
+ <output filename="cef_strings_am.pak" type="data_package" lang="am" />
+ <output filename="cef_strings_ar.pak" type="data_package" lang="ar" />
+ <if expr="pp_ifdef('use_third_party_translations')">
+ <output filename="cef_strings_ast.pak" type="data_package" lang="ast" />
+ </if>
+ <output filename="cef_strings_bg.pak" type="data_package" lang="bg" />
+ <output filename="cef_strings_bn.pak" type="data_package" lang="bn" />
+ <if expr="pp_ifdef('use_third_party_translations')">
+ <output filename="cef_strings_bs.pak" type="data_package" lang="bs" />
+ </if>
+ <output filename="cef_strings_ca.pak" type="data_package" lang="ca" />
+ <if expr="pp_ifdef('use_third_party_translations')">
+ <output filename="cef_strings_ca@valencia.pak" type="data_package" lang="ca@valencia" />
+ </if>
+ <output filename="cef_strings_cs.pak" type="data_package" lang="cs" />
+ <output filename="cef_strings_da.pak" type="data_package" lang="da" />
+ <output filename="cef_strings_de.pak" type="data_package" lang="de" />
+ <output filename="cef_strings_el.pak" type="data_package" lang="el" />
+ <if expr="pp_ifdef('use_third_party_translations')">
+ <output filename="cef_strings_en-AU.pak" type="data_package" lang="en-AU" />
+ </if>
+ <output filename="cef_strings_en-GB.pak" type="data_package" lang="en-GB" />
+ <output filename="cef_strings_en-US.pak" type="data_package" lang="en" />
+ <if expr="pp_ifdef('use_third_party_translations')">
+ <output filename="cef_strings_eo.pak" type="data_package" lang="eo" />
+ </if>
+ <output filename="cef_strings_es.pak" type="data_package" lang="es" />
+ <output filename="cef_strings_es-419.pak" type="data_package" lang="es-419" />
+ <output filename="cef_strings_et.pak" type="data_package" lang="et" />
+ <if expr="pp_ifdef('use_third_party_translations')">
+ <output filename="cef_strings_eu.pak" type="data_package" lang="eu" />
+ </if>
+ <output filename="cef_strings_fa.pak" type="data_package" lang="fa" />
+ <output filename="cef_strings_fake-bidi.pak" type="data_package" lang="fake-bidi" />
+ <output filename="cef_strings_fi.pak" type="data_package" lang="fi" />
+ <output filename="cef_strings_fil.pak" type="data_package" lang="fil" />
+ <output filename="cef_strings_fr.pak" type="data_package" lang="fr" />
+ <if expr="pp_ifdef('use_third_party_translations')">
+ <output filename="cef_strings_gl.pak" type="data_package" lang="gl" />
+ </if>
+ <output filename="cef_strings_gu.pak" type="data_package" lang="gu" />
+ <output filename="cef_strings_he.pak" type="data_package" lang="he" />
+ <output filename="cef_strings_hi.pak" type="data_package" lang="hi" />
+ <output filename="cef_strings_hr.pak" type="data_package" lang="hr" />
+ <output filename="cef_strings_hu.pak" type="data_package" lang="hu" />
+ <if expr="pp_ifdef('use_third_party_translations')">
+ <output filename="cef_strings_hy.pak" type="data_package" lang="hy" />
+ <output filename="cef_strings_ia.pak" type="data_package" lang="ia" />
+ </if>
+ <output filename="cef_strings_id.pak" type="data_package" lang="id" />
+ <output filename="cef_strings_it.pak" type="data_package" lang="it" />
+ <output filename="cef_strings_ja.pak" type="data_package" lang="ja" />
+ <if expr="pp_ifdef('use_third_party_translations')">
+ <output filename="cef_strings_ka.pak" type="data_package" lang="ka" />
+ </if>
+ <output filename="cef_strings_kn.pak" type="data_package" lang="kn" />
+ <output filename="cef_strings_ko.pak" type="data_package" lang="ko" />
+ <if expr="pp_ifdef('use_third_party_translations')">
+ <output filename="cef_strings_ku.pak" type="data_package" lang="ku" />
+ <output filename="cef_strings_kw.pak" type="data_package" lang="kw" />
+ </if>
+ <output filename="cef_strings_lt.pak" type="data_package" lang="lt" />
+ <output filename="cef_strings_lv.pak" type="data_package" lang="lv" />
+ <output filename="cef_strings_ml.pak" type="data_package" lang="ml" />
+ <output filename="cef_strings_mr.pak" type="data_package" lang="mr" />
+ <output filename="cef_strings_ms.pak" type="data_package" lang="ms" />
+ <output filename="cef_strings_nl.pak" type="data_package" lang="nl" />
+ <!-- The translation console uses 'no' for Norwegian Bokmål. It should
+ be 'nb'. -->
+ <output filename="cef_strings_nb.pak" type="data_package" lang="no" />
+ <output filename="cef_strings_pl.pak" type="data_package" lang="pl" />
+ <output filename="cef_strings_pt-BR.pak" type="data_package" lang="pt-BR" />
+ <output filename="cef_strings_pt-PT.pak" type="data_package" lang="pt-PT" />
+ <output filename="cef_strings_ro.pak" type="data_package" lang="ro" />
+ <output filename="cef_strings_ru.pak" type="data_package" lang="ru" />
+ <output filename="cef_strings_sk.pak" type="data_package" lang="sk" />
+ <output filename="cef_strings_sl.pak" type="data_package" lang="sl" />
+ <output filename="cef_strings_sr.pak" type="data_package" lang="sr" />
+ <output filename="cef_strings_sv.pak" type="data_package" lang="sv" />
+ <output filename="cef_strings_sw.pak" type="data_package" lang="sw" />
+ <output filename="cef_strings_ta.pak" type="data_package" lang="ta" />
+ <output filename="cef_strings_te.pak" type="data_package" lang="te" />
+ <output filename="cef_strings_th.pak" type="data_package" lang="th" />
+ <output filename="cef_strings_tr.pak" type="data_package" lang="tr" />
+ <if expr="pp_ifdef('use_third_party_translations')">
+ <output filename="cef_strings_ug.pak" type="data_package" lang="ug" />
+ </if>
+ <output filename="cef_strings_uk.pak" type="data_package" lang="uk" />
+ <output filename="cef_strings_ur.pak" type="data_package" lang="ur" />
+ <output filename="cef_strings_vi.pak" type="data_package" lang="vi" />
+ <output filename="cef_strings_zh-CN.pak" type="data_package" lang="zh-CN" />
+ <output filename="cef_strings_zh-TW.pak" type="data_package" lang="zh-TW" />
+ <if expr="enable_pseudolocales">
+ <output filename="cef_strings_ar-XB.pak" type="data_package" lang="ar-XB" />
+ <output filename="cef_strings_en-XA.pak" type="data_package" lang="en-XA" />
+ </if>
+ </outputs>
+ <release seq="1" allow_pseudo="false">
+ <messages fallback_to_english="true">
+ <!-- TODO add all of your "string table" messages here. Remember to
+ change nontranslateable parts of the messages into placeholders (using the
+ <ph> element). You can also use the 'grit add' tool to help you identify
+ nontranslateable parts and create placeholders for them. -->
+
+ <!-- Other values come from chrome/app/generated_resources.grd -->
+ <message name="IDS_TEXT_FILES" desc="The description of the text file extensions in the select file dialog.">
+ Text Files
+ </message>
+ <message name="IDS_CONTENT_CONTEXT_NO_SPELLING_SUGGESTIONS" desc="The name of the No Spelling Suggestions display in the content area context menu">
+ &amp;No spelling suggestions
+ </message>
+ </messages>
+ </release>
+</grit>
diff --git a/libcef/resources/devtools_discovery_page.html b/libcef/resources/devtools_discovery_page.html
new file mode 100644
index 00000000..87933d1a
--- /dev/null
+++ b/libcef/resources/devtools_discovery_page.html
@@ -0,0 +1,54 @@
+<html>
+<head>
+<title>CEF remote debugging</title>
+<style>
+</style>
+
+<script>
+function onLoad() {
+ var tabs_list_request = new XMLHttpRequest();
+ tabs_list_request.open("GET", "/json/list?t=" + new Date().getTime(), true);
+ tabs_list_request.onreadystatechange = onReady;
+ tabs_list_request.send();
+}
+
+function onReady() {
+ if(this.readyState == 4 && this.status == 200) {
+ if(this.response != null)
+ var responseJSON = JSON.parse(this.response);
+ for (var i = 0; i < responseJSON.length; ++i)
+ appendItem(responseJSON[i]);
+ }
+}
+
+function appendItem(item_object) {
+ var frontend_ref;
+ if (item_object.devtoolsFrontendUrl) {
+ frontend_ref = document.createElement("a");
+ frontend_ref.href = item_object.devtoolsFrontendUrl;
+ frontend_ref.title = item_object.title;
+ } else {
+ frontend_ref = document.createElement("div");
+ frontend_ref.title = "The tab already has active debugging session";
+ }
+
+ var text = document.createElement("div");
+ if (item_object.title)
+ text.innerText = item_object.title;
+ else
+ text.innerText = "(untitled tab)";
+ text.style.cssText = "background-image:url(" + item_object.faviconUrl + ")";
+ frontend_ref.appendChild(text);
+
+ var item = document.createElement("p");
+ item.appendChild(frontend_ref);
+
+ document.getElementById("items").appendChild(item);
+}
+</script>
+</head>
+<body onload='onLoad()'>
+ <div id='caption'>Inspectable WebContents</div>
+ <div id='items'></div>
+</body>
+</html>
diff --git a/libcef/resources/framework-Info.plist b/libcef/resources/framework-Info.plist
new file mode 100644
index 00000000..a2169b3c
--- /dev/null
+++ b/libcef/resources/framework-Info.plist
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>en</string>
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleIdentifier</key>
+ <string>org.cef.framework</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundlePackageType</key>
+ <string>FMWK</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+</dict>
+</plist>
diff --git a/libcef_dll/CMakeLists.txt.in b/libcef_dll/CMakeLists.txt.in
new file mode 100644
index 00000000..72a2d99d
--- /dev/null
+++ b/libcef_dll/CMakeLists.txt.in
@@ -0,0 +1,50 @@
+# Copyright (c) 2014 The Chromium Embedded Framework Authors. All rights
+# reserved. Use of this source code is governed by a BSD-style license that
+# can be found in the LICENSE file.
+
+# Append platform specific sources to a list of sources.
+macro(LIBCEF_APPEND_PLATFORM_SOURCES name_of_list)
+ if("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin" AND ${name_of_list}_MAC)
+ list(APPEND ${name_of_list} ${${name_of_list}_MAC})
+ endif()
+ if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux" AND ${name_of_list}_LINUX)
+ list(APPEND ${name_of_list} ${${name_of_list}_LINUX})
+ endif()
+ if("${CMAKE_SYSTEM_NAME}" STREQUAL "Windows" AND ${name_of_list}_WINDOWS)
+ list(APPEND ${name_of_list} ${${name_of_list}_WINDOWS})
+ endif()
+endmacro()
+
+set(CEF_TARGET libcef_dll_wrapper)
+
+{{
+ 'prefix': 'libcef',
+ 'library': '${CEF_TARGET}',
+ 'append_macro': 'LIBCEF_APPEND_PLATFORM_SOURCES',
+ 'includes': [
+ 'includes_common',
+ 'includes_common_capi',
+ 'autogen_cpp_includes',
+ 'includes_capi',
+ 'autogen_capi_includes',
+ 'includes_wrapper',
+ 'includes_wrapper_mac:MAC',
+ 'includes_win:WINDOWS',
+ 'includes_win_capi:WINDOWS',
+ 'includes_mac:MAC',
+ 'includes_mac_capi:MAC',
+ 'includes_linux:LINUX',
+ 'includes_linux_capi:LINUX',
+ 'libcef_dll_wrapper_sources_base',
+ 'libcef_dll_wrapper_sources_common',
+ 'libcef_dll_wrapper_sources_mac:MAC',
+ 'autogen_client_side',
+ ],
+}}
+SET_LIBRARY_TARGET_PROPERTIES(${CEF_TARGET})
+
+# Creating the CEF wrapper library. Do not define this for dependent targets.
+target_compile_definitions(${CEF_TARGET} PRIVATE -DWRAPPING_CEF_SHARED)
+
+# Remove the default "lib" prefix from the resulting library.
+set_target_properties(${CEF_TARGET} PROPERTIES PREFIX "")
diff --git a/libcef_dll/base/cef_atomic_flag.cc b/libcef_dll/base/cef_atomic_flag.cc
new file mode 100644
index 00000000..94846db1
--- /dev/null
+++ b/libcef_dll/base/cef_atomic_flag.cc
@@ -0,0 +1,31 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "include/base/cef_atomic_flag.h"
+
+#include "include/base/cef_logging.h"
+
+namespace base {
+
+AtomicFlag::AtomicFlag() {
+ // It doesn't matter where the AtomicFlag is built so long as it's always
+ // Set() from the same sequence after. Note: the sequencing requirements are
+ // necessary for IsSet()'s callers to know which sequence's memory operations
+ // they are synchronized with.
+ set_thread_checker_.DetachFromThread();
+}
+
+AtomicFlag::~AtomicFlag() = default;
+
+void AtomicFlag::Set() {
+ DCHECK(set_thread_checker_.CalledOnValidThread());
+ flag_.store(1, std::memory_order_release);
+}
+
+void AtomicFlag::UnsafeResetForTesting() {
+ set_thread_checker_.DetachFromThread();
+ flag_.store(0, std::memory_order_release);
+}
+
+} // namespace base
diff --git a/libcef_dll/base/cef_callback_helpers.cc b/libcef_dll/base/cef_callback_helpers.cc
new file mode 100644
index 00000000..1f75fba3
--- /dev/null
+++ b/libcef_dll/base/cef_callback_helpers.cc
@@ -0,0 +1,44 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "include/base/cef_callback_helpers.h"
+
+namespace base {
+
+ScopedClosureRunner::ScopedClosureRunner() = default;
+
+ScopedClosureRunner::ScopedClosureRunner(OnceClosure closure)
+ : closure_(std::move(closure)) {}
+
+ScopedClosureRunner::ScopedClosureRunner(ScopedClosureRunner&& other)
+ : closure_(other.Release()) {}
+
+ScopedClosureRunner& ScopedClosureRunner::operator=(
+ ScopedClosureRunner&& other) {
+ if (this != &other) {
+ RunAndReset();
+ ReplaceClosure(other.Release());
+ }
+ return *this;
+}
+
+ScopedClosureRunner::~ScopedClosureRunner() {
+ RunAndReset();
+}
+
+void ScopedClosureRunner::RunAndReset() {
+ if (closure_) {
+ std::move(closure_).Run();
+ }
+}
+
+void ScopedClosureRunner::ReplaceClosure(OnceClosure closure) {
+ closure_ = std::move(closure);
+}
+
+OnceClosure ScopedClosureRunner::Release() {
+ return std::move(closure_);
+}
+
+} // namespace base
diff --git a/libcef_dll/base/cef_callback_internal.cc b/libcef_dll/base/cef_callback_internal.cc
new file mode 100644
index 00000000..5651187f
--- /dev/null
+++ b/libcef_dll/base/cef_callback_internal.cc
@@ -0,0 +1,101 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "include/base/internal/cef_callback_internal.h"
+
+#include "include/base/cef_logging.h"
+
+namespace base {
+namespace cef_internal {
+
+namespace {
+
+bool QueryCancellationTraitsForNonCancellables(
+ const BindStateBase*,
+ BindStateBase::CancellationQueryMode mode) {
+ switch (mode) {
+ case BindStateBase::IS_CANCELLED:
+ return false;
+ case BindStateBase::MAYBE_VALID:
+ return true;
+ }
+ NOTREACHED();
+ return false;
+}
+
+} // namespace
+
+void BindStateBaseRefCountTraits::Destruct(const BindStateBase* bind_state) {
+ bind_state->destructor_(bind_state);
+}
+
+BindStateBase::BindStateBase(InvokeFuncStorage polymorphic_invoke,
+ void (*destructor)(const BindStateBase*))
+ : BindStateBase(polymorphic_invoke,
+ destructor,
+ &QueryCancellationTraitsForNonCancellables) {}
+
+BindStateBase::BindStateBase(
+ InvokeFuncStorage polymorphic_invoke,
+ void (*destructor)(const BindStateBase*),
+ bool (*query_cancellation_traits)(const BindStateBase*,
+ CancellationQueryMode))
+ : polymorphic_invoke_(polymorphic_invoke),
+ destructor_(destructor),
+ query_cancellation_traits_(query_cancellation_traits) {}
+
+CallbackBase& CallbackBase::operator=(CallbackBase&& c) noexcept = default;
+CallbackBase::CallbackBase(const CallbackBaseCopyable& c)
+ : bind_state_(c.bind_state_) {}
+
+CallbackBase& CallbackBase::operator=(const CallbackBaseCopyable& c) {
+ bind_state_ = c.bind_state_;
+ return *this;
+}
+
+CallbackBase::CallbackBase(CallbackBaseCopyable&& c) noexcept
+ : bind_state_(std::move(c.bind_state_)) {}
+
+CallbackBase& CallbackBase::operator=(CallbackBaseCopyable&& c) noexcept {
+ bind_state_ = std::move(c.bind_state_);
+ return *this;
+}
+
+void CallbackBase::Reset() {
+ // NULL the bind_state_ last, since it may be holding the last ref to whatever
+ // object owns us, and we may be deleted after that.
+ bind_state_ = nullptr;
+}
+
+bool CallbackBase::IsCancelled() const {
+ DCHECK(bind_state_);
+ return bind_state_->IsCancelled();
+}
+
+bool CallbackBase::MaybeValid() const {
+ DCHECK(bind_state_);
+ return bind_state_->MaybeValid();
+}
+
+bool CallbackBase::EqualsInternal(const CallbackBase& other) const {
+ return bind_state_ == other.bind_state_;
+}
+
+CallbackBase::~CallbackBase() = default;
+
+CallbackBaseCopyable::CallbackBaseCopyable(const CallbackBaseCopyable& c) {
+ bind_state_ = c.bind_state_;
+}
+
+CallbackBaseCopyable& CallbackBaseCopyable::operator=(
+ const CallbackBaseCopyable& c) {
+ bind_state_ = c.bind_state_;
+ return *this;
+}
+
+CallbackBaseCopyable& CallbackBaseCopyable::operator=(
+ CallbackBaseCopyable&& c) noexcept = default;
+
+} // namespace cef_internal
+} // namespace base
diff --git a/libcef_dll/base/cef_lock.cc b/libcef_dll/base/cef_lock.cc
new file mode 100644
index 00000000..ea2ba3cf
--- /dev/null
+++ b/libcef_dll/base/cef_lock.cc
@@ -0,0 +1,45 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is used for debugging assertion support. The Lock class
+// is functionally a wrapper around the LockImpl class, so the only
+// real intelligence in the class is in the debugging logic.
+
+#include "include/base/cef_lock.h"
+#include "include/base/cef_logging.h"
+
+#if DCHECK_IS_ON()
+
+namespace base {
+namespace cef_internal {
+
+Lock::Lock() : lock_() {}
+
+Lock::~Lock() {
+ DCHECK(owning_thread_ref_.is_null());
+}
+
+void Lock::AssertAcquired() const {
+ DCHECK(owning_thread_ref_ == PlatformThread::CurrentRef());
+}
+
+void Lock::CheckHeldAndUnmark() {
+ DCHECK(owning_thread_ref_ == PlatformThread::CurrentRef());
+ owning_thread_ref_ = PlatformThreadRef();
+}
+
+void Lock::CheckUnheldAndMark() {
+ // Hitting this DCHECK means that your code is trying to re-enter a lock that
+ // is already held. The Chromium Lock implementation is not reentrant.
+ // See "Why can the holder of a Lock not reacquire it?" at
+ // http://www.chromium.org/developers/lock-and-condition-variable for more
+ // information.
+ DCHECK(owning_thread_ref_.is_null());
+ owning_thread_ref_ = PlatformThread::CurrentRef();
+}
+
+} // namespace cef_internal
+} // namespace base
+
+#endif // DCHECK_IS_ON()
diff --git a/libcef_dll/base/cef_lock_impl.cc b/libcef_dll/base/cef_lock_impl.cc
new file mode 100644
index 00000000..4afe75f0
--- /dev/null
+++ b/libcef_dll/base/cef_lock_impl.cc
@@ -0,0 +1,92 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "include/base/internal/cef_lock_impl.h"
+
+#if defined(OS_WIN)
+
+namespace base {
+namespace cef_internal {
+
+LockImpl::LockImpl() {
+ // The second parameter is the spin count, for short-held locks it avoid the
+ // contending thread from going to sleep which helps performance greatly.
+ ::InitializeCriticalSectionAndSpinCount(&native_handle_, 2000);
+}
+
+LockImpl::~LockImpl() {
+ ::DeleteCriticalSection(&native_handle_);
+}
+
+bool LockImpl::Try() {
+ if (::TryEnterCriticalSection(&native_handle_) != FALSE) {
+ return true;
+ }
+ return false;
+}
+
+void LockImpl::Lock() {
+ ::EnterCriticalSection(&native_handle_);
+}
+
+void LockImpl::Unlock() {
+ ::LeaveCriticalSection(&native_handle_);
+}
+
+} // namespace cef_internal
+} // namespace base
+
+#elif defined(OS_POSIX)
+
+#include <errno.h>
+#include <string.h>
+
+#include "include/base/cef_logging.h"
+
+namespace base {
+namespace cef_internal {
+
+LockImpl::LockImpl() {
+#if DCHECK_IS_ON()
+ // In debug, setup attributes for lock error checking.
+ pthread_mutexattr_t mta;
+ int rv = pthread_mutexattr_init(&mta);
+ DCHECK_EQ(rv, 0) << ". " << strerror(rv);
+ rv = pthread_mutexattr_settype(&mta, PTHREAD_MUTEX_ERRORCHECK);
+ DCHECK_EQ(rv, 0) << ". " << strerror(rv);
+ rv = pthread_mutex_init(&native_handle_, &mta);
+ DCHECK_EQ(rv, 0) << ". " << strerror(rv);
+ rv = pthread_mutexattr_destroy(&mta);
+ DCHECK_EQ(rv, 0) << ". " << strerror(rv);
+#else
+ // In release, go with the default lock attributes.
+ pthread_mutex_init(&native_handle_, NULL);
+#endif
+}
+
+LockImpl::~LockImpl() {
+ int rv = pthread_mutex_destroy(&native_handle_);
+ DCHECK_EQ(rv, 0) << ". " << strerror(rv);
+}
+
+bool LockImpl::Try() {
+ int rv = pthread_mutex_trylock(&native_handle_);
+ DCHECK(rv == 0 || rv == EBUSY) << ". " << strerror(rv);
+ return rv == 0;
+}
+
+void LockImpl::Lock() {
+ int rv = pthread_mutex_lock(&native_handle_);
+ DCHECK_EQ(rv, 0) << ". " << strerror(rv);
+}
+
+void LockImpl::Unlock() {
+ int rv = pthread_mutex_unlock(&native_handle_);
+ DCHECK_EQ(rv, 0) << ". " << strerror(rv);
+}
+
+} // namespace cef_internal
+} // namespace base
+
+#endif // defined(OS_POSIX)
diff --git a/libcef_dll/base/cef_logging.cc b/libcef_dll/base/cef_logging.cc
new file mode 100644
index 00000000..0d935507
--- /dev/null
+++ b/libcef_dll/base/cef_logging.cc
@@ -0,0 +1,267 @@
+// Copyright (c) 2014 The Chromium Embedded Framework Authors.
+// Portions copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "include/base/cef_logging.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#include <algorithm>
+#include <sstream>
+#elif defined(OS_POSIX)
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#endif
+
+#include "include/internal/cef_string_types.h"
+
+namespace cef {
+namespace logging {
+
+namespace {
+
+#if defined(OS_POSIX)
+// From base/posix/safe_strerror.cc
+
+#if defined(__GLIBC__) || defined(OS_NACL)
+#define USE_HISTORICAL_STRERRO_R 1
+#else
+#define USE_HISTORICAL_STRERRO_R 0
+#endif
+
+#if USE_HISTORICAL_STRERRO_R && defined(__GNUC__)
+// GCC will complain about the unused second wrap function unless we tell it
+// that we meant for them to be potentially unused, which is exactly what this
+// attribute is for.
+#define POSSIBLY_UNUSED __attribute__((unused))
+#else
+#define POSSIBLY_UNUSED
+#endif
+
+#if USE_HISTORICAL_STRERRO_R
+// glibc has two strerror_r functions: a historical GNU-specific one that
+// returns type char *, and a POSIX.1-2001 compliant one available since 2.3.4
+// that returns int. This wraps the GNU-specific one.
+static void POSSIBLY_UNUSED
+wrap_posix_strerror_r(char* (*strerror_r_ptr)(int, char*, size_t),
+ int err,
+ char* buf,
+ size_t len) {
+ // GNU version.
+ char* rc = (*strerror_r_ptr)(err, buf, len);
+ if (rc != buf) {
+ // glibc did not use buf and returned a static string instead. Copy it
+ // into buf.
+ buf[0] = '\0';
+ strncat(buf, rc, len - 1);
+ }
+ // The GNU version never fails. Unknown errors get an "unknown error" message.
+ // The result is always null terminated.
+}
+#endif // USE_HISTORICAL_STRERRO_R
+
+// Wrapper for strerror_r functions that implement the POSIX interface. POSIX
+// does not define the behaviour for some of the edge cases, so we wrap it to
+// guarantee that they are handled. This is compiled on all POSIX platforms, but
+// it will only be used on Linux if the POSIX strerror_r implementation is
+// being used (see below).
+static void POSSIBLY_UNUSED wrap_posix_strerror_r(int (*strerror_r_ptr)(int,
+ char*,
+ size_t),
+ int err,
+ char* buf,
+ size_t len) {
+ int old_errno = errno;
+ // Have to cast since otherwise we get an error if this is the GNU version
+ // (but in such a scenario this function is never called). Sadly we can't use
+ // C++-style casts because the appropriate one is reinterpret_cast but it's
+ // considered illegal to reinterpret_cast a type to itself, so we get an
+ // error in the opposite case.
+ int result = (*strerror_r_ptr)(err, buf, len);
+ if (result == 0) {
+ // POSIX is vague about whether the string will be terminated, although
+ // it indirectly implies that typically ERANGE will be returned, instead
+ // of truncating the string. We play it safe by always terminating the
+ // string explicitly.
+ buf[len - 1] = '\0';
+ } else {
+ // Error. POSIX is vague about whether the return value is itself a system
+ // error code or something else. On Linux currently it is -1 and errno is
+ // set. On BSD-derived systems it is a system error and errno is unchanged.
+ // We try and detect which case it is so as to put as much useful info as
+ // we can into our message.
+ int strerror_error; // The error encountered in strerror
+ int new_errno = errno;
+ if (new_errno != old_errno) {
+ // errno was changed, so probably the return value is just -1 or something
+ // else that doesn't provide any info, and errno is the error.
+ strerror_error = new_errno;
+ } else {
+ // Either the error from strerror_r was the same as the previous value, or
+ // errno wasn't used. Assume the latter.
+ strerror_error = result;
+ }
+ // snprintf truncates and always null-terminates.
+ snprintf(buf, len, "Error %d while retrieving error %d", strerror_error,
+ err);
+ }
+ errno = old_errno;
+}
+
+void safe_strerror_r(int err, char* buf, size_t len) {
+ if (buf == NULL || len <= 0) {
+ return;
+ }
+ // If using glibc (i.e., Linux), the compiler will automatically select the
+ // appropriate overloaded function based on the function type of strerror_r.
+ // The other one will be elided from the translation unit since both are
+ // static.
+ wrap_posix_strerror_r(&strerror_r, err, buf, len);
+}
+
+std::string safe_strerror(int err) {
+ const int buffer_size = 256;
+ char buf[buffer_size];
+ safe_strerror_r(err, buf, sizeof(buf));
+ return std::string(buf);
+}
+#endif // defined(OS_POSIX)
+
+} // namespace
+
+// MSVC doesn't like complex extern templates and DLLs.
+#if !defined(COMPILER_MSVC)
+// Explicit instantiations for commonly used comparisons.
+template std::string* MakeCheckOpString<int, int>(const int&,
+ const int&,
+ const char* names);
+template std::string* MakeCheckOpString<unsigned long, unsigned long>(
+ const unsigned long&,
+ const unsigned long&,
+ const char* names);
+template std::string* MakeCheckOpString<unsigned long, unsigned int>(
+ const unsigned long&,
+ const unsigned int&,
+ const char* names);
+template std::string* MakeCheckOpString<unsigned int, unsigned long>(
+ const unsigned int&,
+ const unsigned long&,
+ const char* names);
+template std::string* MakeCheckOpString<std::string, std::string>(
+ const std::string&,
+ const std::string&,
+ const char* name);
+#endif
+
+#if defined(OS_WIN)
+LogMessage::SaveLastError::SaveLastError() : last_error_(::GetLastError()) {}
+
+LogMessage::SaveLastError::~SaveLastError() {
+ ::SetLastError(last_error_);
+}
+#endif // defined(OS_WIN)
+
+LogMessage::LogMessage(const char* file, int line, LogSeverity severity)
+ : severity_(severity), file_(file), line_(line) {}
+
+LogMessage::LogMessage(const char* file, int line, std::string* result)
+ : severity_(LOG_FATAL), file_(file), line_(line) {
+ stream_ << "Check failed: " << *result;
+ delete result;
+}
+
+LogMessage::LogMessage(const char* file,
+ int line,
+ LogSeverity severity,
+ std::string* result)
+ : severity_(severity), file_(file), line_(line) {
+ stream_ << "Check failed: " << *result;
+ delete result;
+}
+
+LogMessage::~LogMessage() {
+ std::string str_newline(stream_.str());
+ cef_log(file_, line_, severity_, str_newline.c_str());
+}
+
+#if defined(OS_WIN)
+// This has already been defined in the header, but defining it again as DWORD
+// ensures that the type used in the header is equivalent to DWORD. If not,
+// the redefinition is a compile error.
+using SystemErrorCode = DWORD;
+#endif
+
+SystemErrorCode GetLastSystemErrorCode() {
+#if defined(OS_WIN)
+ return ::GetLastError();
+#elif defined(OS_POSIX)
+ return errno;
+#else
+#error Not implemented
+#endif
+}
+
+#if defined(OS_WIN)
+std::string SystemErrorCodeToString(SystemErrorCode error_code) {
+ const int error_message_buffer_size = 256;
+ char msgbuf[error_message_buffer_size];
+ DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
+ DWORD len = FormatMessageA(flags, NULL, error_code, 0, msgbuf,
+ static_cast<DWORD>(std::size(msgbuf)), NULL);
+ std::stringstream ss;
+ if (len) {
+ std::string s(msgbuf);
+ // Messages returned by system end with line breaks.
+ s.erase(std::remove_if(s.begin(), s.end(), ::isspace), s.end());
+ ss << s << " (0x" << std::hex << error_code << ")";
+ } else {
+ ss << "Error (0x" << std::hex << GetLastError()
+ << ") while retrieving error. (0x" << error_code << ")";
+ }
+ return ss.str();
+}
+#elif defined(OS_POSIX)
+std::string SystemErrorCodeToString(SystemErrorCode error_code) {
+ return safe_strerror(error_code);
+}
+#else
+#error Not implemented
+#endif
+
+#if defined(OS_WIN)
+Win32ErrorLogMessage::Win32ErrorLogMessage(const char* file,
+ int line,
+ LogSeverity severity,
+ SystemErrorCode err)
+ : err_(err), log_message_(file, line, severity) {}
+
+Win32ErrorLogMessage::~Win32ErrorLogMessage() {
+ stream() << ": " << SystemErrorCodeToString(err_);
+}
+#elif defined(OS_POSIX)
+ErrnoLogMessage::ErrnoLogMessage(const char* file,
+ int line,
+ LogSeverity severity,
+ SystemErrorCode err)
+ : err_(err), log_message_(file, line, severity) {}
+
+ErrnoLogMessage::~ErrnoLogMessage() {
+ stream() << ": " << SystemErrorCodeToString(err_);
+}
+#endif // OS_WIN
+
+} // namespace logging
+} // namespace cef
+
+std::ostream& operator<<(std::ostream& out, const wchar_t* wstr) {
+ std::wstring tmp_str(wstr);
+ if (!tmp_str.empty()) {
+ cef_string_utf8_t str = {0};
+ cef_string_wide_to_utf8(wstr, tmp_str.size(), &str);
+ out << str.str;
+ cef_string_utf8_clear(&str);
+ }
+ return out;
+}
diff --git a/libcef_dll/base/cef_ref_counted.cc b/libcef_dll/base/cef_ref_counted.cc
new file mode 100644
index 00000000..cb3ef851
--- /dev/null
+++ b/libcef_dll/base/cef_ref_counted.cc
@@ -0,0 +1,98 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "include/base/cef_ref_counted.h"
+
+#include <limits>
+#include <type_traits>
+
+namespace base {
+namespace {
+
+#if DCHECK_IS_ON()
+std::atomic_int g_cross_thread_ref_count_access_allow_count(0);
+#endif
+
+} // namespace
+
+namespace cef_subtle {
+
+bool RefCountedThreadSafeBase::HasOneRef() const {
+ return ref_count_.IsOne();
+}
+
+bool RefCountedThreadSafeBase::HasAtLeastOneRef() const {
+ return !ref_count_.IsZero();
+}
+
+#if DCHECK_IS_ON()
+RefCountedThreadSafeBase::~RefCountedThreadSafeBase() {
+ DCHECK(in_dtor_) << "RefCountedThreadSafe object deleted without "
+ "calling Release()";
+}
+#endif
+
+// For security and correctness, we check the arithmetic on ref counts.
+//
+// In an attempt to avoid binary bloat (from inlining the `CHECK`), we define
+// these functions out-of-line. However, compilers are wily. Further testing may
+// show that `NOINLINE` helps or hurts.
+//
+#if defined(ARCH_CPU_64_BITS)
+void RefCountedBase::AddRefImpl() const {
+ // An attacker could induce use-after-free bugs, and potentially exploit them,
+ // by creating so many references to a ref-counted object that the reference
+ // count overflows. On 32-bit architectures, there is not enough address space
+ // to succeed. But on 64-bit architectures, it might indeed be possible.
+ // Therefore, we can elide the check for arithmetic overflow on 32-bit, but we
+ // must check on 64-bit.
+ //
+ // Make sure the addition didn't wrap back around to 0. This form of check
+ // works because we assert that `ref_count_` is an unsigned integer type.
+ CHECK(++ref_count_ != 0);
+}
+
+void RefCountedBase::ReleaseImpl() const {
+ // Make sure the subtraction didn't wrap back around from 0 to the max value.
+ // That could cause memory leaks, and may induce application-semantic
+ // correctness or safety bugs. (E.g. what if we really needed that object to
+ // be destroyed at the right time?)
+ //
+ // Note that unlike with overflow, underflow could also happen on 32-bit
+ // architectures. Arguably, we should do this check on32-bit machines too.
+ CHECK(--ref_count_ != std::numeric_limits<decltype(ref_count_)>::max());
+}
+#endif
+
+#if !defined(ARCH_CPU_X86_FAMILY)
+bool RefCountedThreadSafeBase::Release() const {
+ return ReleaseImpl();
+}
+void RefCountedThreadSafeBase::AddRef() const {
+ AddRefImpl();
+}
+void RefCountedThreadSafeBase::AddRefWithCheck() const {
+ AddRefWithCheckImpl();
+}
+#endif
+
+#if DCHECK_IS_ON()
+bool RefCountedBase::CalledOnValidThread() const {
+ return thread_checker_.CalledOnValidThread() ||
+ g_cross_thread_ref_count_access_allow_count.load() != 0;
+}
+#endif
+
+#if DCHECK_IS_ON()
+ScopedAllowCrossThreadRefCountAccess::ScopedAllowCrossThreadRefCountAccess() {
+ ++g_cross_thread_ref_count_access_allow_count;
+}
+
+ScopedAllowCrossThreadRefCountAccess::~ScopedAllowCrossThreadRefCountAccess() {
+ --g_cross_thread_ref_count_access_allow_count;
+}
+#endif
+
+} // namespace cef_subtle
+} // namespace base
diff --git a/libcef_dll/base/cef_thread_checker_impl.cc b/libcef_dll/base/cef_thread_checker_impl.cc
new file mode 100644
index 00000000..4f5a9b0d
--- /dev/null
+++ b/libcef_dll/base/cef_thread_checker_impl.cc
@@ -0,0 +1,35 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "include/base/internal/cef_thread_checker_impl.h"
+
+namespace base {
+namespace cef_internal {
+
+ThreadCheckerImpl::ThreadCheckerImpl() : valid_thread_id_() {
+ EnsureThreadIdAssigned();
+}
+
+ThreadCheckerImpl::~ThreadCheckerImpl() {}
+
+bool ThreadCheckerImpl::CalledOnValidThread() const {
+ EnsureThreadIdAssigned();
+ AutoLock auto_lock(lock_);
+ return valid_thread_id_ == PlatformThread::CurrentRef();
+}
+
+void ThreadCheckerImpl::DetachFromThread() {
+ AutoLock auto_lock(lock_);
+ valid_thread_id_ = PlatformThreadRef();
+}
+
+void ThreadCheckerImpl::EnsureThreadIdAssigned() const {
+ AutoLock auto_lock(lock_);
+ if (valid_thread_id_.is_null()) {
+ valid_thread_id_ = PlatformThread::CurrentRef();
+ }
+}
+
+} // namespace cef_internal
+} // namespace base
diff --git a/libcef_dll/base/cef_weak_ptr.cc b/libcef_dll/base/cef_weak_ptr.cc
new file mode 100644
index 00000000..709500e6
--- /dev/null
+++ b/libcef_dll/base/cef_weak_ptr.cc
@@ -0,0 +1,101 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "include/base/cef_weak_ptr.h"
+
+namespace base {
+namespace internal {
+
+WeakReference::Flag::Flag() {
+ // Flags only become bound when checked for validity, or invalidated,
+ // so that we can check that later validity/invalidation operations on
+ // the same Flag take place on the same threadd thread.
+ thread_checker_.DetachFromThread();
+}
+
+void WeakReference::Flag::Invalidate() {
+ // The flag being invalidated with a single ref implies that there are no
+ // weak pointers in existence. Allow deletion on other thread in this case.
+#if DCHECK_IS_ON()
+ DCHECK(thread_checker_.CalledOnValidThread() || HasOneRef())
+ << "WeakPtrs must be invalidated on the same thread as where "
+ << "they are bound.\n";
+#endif
+ invalidated_.Set();
+}
+
+bool WeakReference::Flag::IsValid() const {
+ // WeakPtrs must be checked on the same threadd thread.
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return !invalidated_.IsSet();
+}
+
+bool WeakReference::Flag::MaybeValid() const {
+ return !invalidated_.IsSet();
+}
+
+void WeakReference::Flag::DetachFromThread() {
+ thread_checker_.DetachFromThread();
+}
+
+WeakReference::Flag::~Flag() = default;
+
+WeakReference::WeakReference() = default;
+
+WeakReference::WeakReference(const scoped_refptr<Flag>& flag) : flag_(flag) {}
+
+WeakReference::~WeakReference() = default;
+
+WeakReference::WeakReference(WeakReference&& other) noexcept = default;
+
+WeakReference::WeakReference(const WeakReference& other) = default;
+
+bool WeakReference::IsValid() const {
+ return flag_ && flag_->IsValid();
+}
+
+bool WeakReference::MaybeValid() const {
+ return flag_ && flag_->MaybeValid();
+}
+
+WeakReferenceOwner::WeakReferenceOwner()
+ : flag_(MakeRefCounted<WeakReference::Flag>()) {}
+
+WeakReferenceOwner::~WeakReferenceOwner() {
+ flag_->Invalidate();
+}
+
+WeakReference WeakReferenceOwner::GetRef() const {
+ // If we hold the last reference to the Flag then detach the ThreadChecker.
+ if (!HasRefs()) {
+ flag_->DetachFromThread();
+ }
+
+ return WeakReference(flag_);
+}
+
+void WeakReferenceOwner::Invalidate() {
+ flag_->Invalidate();
+ flag_ = MakeRefCounted<WeakReference::Flag>();
+}
+
+WeakPtrBase::WeakPtrBase() : ptr_(0) {}
+
+WeakPtrBase::~WeakPtrBase() = default;
+
+WeakPtrBase::WeakPtrBase(const WeakReference& ref, uintptr_t ptr)
+ : ref_(ref), ptr_(ptr) {
+ DCHECK(ptr_);
+}
+
+WeakPtrFactoryBase::WeakPtrFactoryBase(uintptr_t ptr) : ptr_(ptr) {
+ DCHECK(ptr_);
+}
+
+WeakPtrFactoryBase::~WeakPtrFactoryBase() {
+ ptr_ = 0;
+}
+
+} // namespace internal
+} // namespace base
diff --git a/libcef_dll/cpptoc/accessibility_handler_cpptoc.cc b/libcef_dll/cpptoc/accessibility_handler_cpptoc.cc
new file mode 100644
index 00000000..2a82e4fe
--- /dev/null
+++ b/libcef_dll/cpptoc/accessibility_handler_cpptoc.cc
@@ -0,0 +1,99 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=1ed29ea773cbebaa14bbd019d7902d98e336e964$
+//
+
+#include "libcef_dll/cpptoc/accessibility_handler_cpptoc.h"
+#include "libcef_dll/ctocpp/value_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK accessibility_handler_on_accessibility_tree_change(
+ struct _cef_accessibility_handler_t* self,
+ struct _cef_value_t* value) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: value; type: refptr_diff
+ DCHECK(value);
+ if (!value) {
+ return;
+ }
+
+ // Execute
+ CefAccessibilityHandlerCppToC::Get(self)->OnAccessibilityTreeChange(
+ CefValueCToCpp::Wrap(value));
+}
+
+void CEF_CALLBACK accessibility_handler_on_accessibility_location_change(
+ struct _cef_accessibility_handler_t* self,
+ struct _cef_value_t* value) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: value; type: refptr_diff
+ DCHECK(value);
+ if (!value) {
+ return;
+ }
+
+ // Execute
+ CefAccessibilityHandlerCppToC::Get(self)->OnAccessibilityLocationChange(
+ CefValueCToCpp::Wrap(value));
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefAccessibilityHandlerCppToC::CefAccessibilityHandlerCppToC() {
+ GetStruct()->on_accessibility_tree_change =
+ accessibility_handler_on_accessibility_tree_change;
+ GetStruct()->on_accessibility_location_change =
+ accessibility_handler_on_accessibility_location_change;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefAccessibilityHandlerCppToC::~CefAccessibilityHandlerCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefAccessibilityHandler> CefCppToCRefCounted<
+ CefAccessibilityHandlerCppToC,
+ CefAccessibilityHandler,
+ cef_accessibility_handler_t>::UnwrapDerived(CefWrapperType type,
+ cef_accessibility_handler_t*
+ s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefAccessibilityHandlerCppToC,
+ CefAccessibilityHandler,
+ cef_accessibility_handler_t>::kWrapperType =
+ WT_ACCESSIBILITY_HANDLER;
diff --git a/libcef_dll/cpptoc/accessibility_handler_cpptoc.h b/libcef_dll/cpptoc/accessibility_handler_cpptoc.h
new file mode 100644
index 00000000..faf27103
--- /dev/null
+++ b/libcef_dll/cpptoc/accessibility_handler_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=0d1469b1473cbef38092a2b0624ac33faa6e1d89$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_ACCESSIBILITY_HANDLER_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_ACCESSIBILITY_HANDLER_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_accessibility_handler_capi.h"
+#include "include/cef_accessibility_handler.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefAccessibilityHandlerCppToC
+ : public CefCppToCRefCounted<CefAccessibilityHandlerCppToC,
+ CefAccessibilityHandler,
+ cef_accessibility_handler_t> {
+ public:
+ CefAccessibilityHandlerCppToC();
+ virtual ~CefAccessibilityHandlerCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_ACCESSIBILITY_HANDLER_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/app_cpptoc.cc b/libcef_dll/cpptoc/app_cpptoc.cc
new file mode 100644
index 00000000..123f037d
--- /dev/null
+++ b/libcef_dll/cpptoc/app_cpptoc.cc
@@ -0,0 +1,150 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=f90f2c0c5749139bef7c914fbb4f17cfe585e4e8$
+//
+
+#include "libcef_dll/cpptoc/app_cpptoc.h"
+#include "libcef_dll/cpptoc/browser_process_handler_cpptoc.h"
+#include "libcef_dll/cpptoc/render_process_handler_cpptoc.h"
+#include "libcef_dll/cpptoc/resource_bundle_handler_cpptoc.h"
+#include "libcef_dll/ctocpp/command_line_ctocpp.h"
+#include "libcef_dll/ctocpp/scheme_registrar_ctocpp.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK app_on_before_command_line_processing(
+ struct _cef_app_t* self,
+ const cef_string_t* process_type,
+ struct _cef_command_line_t* command_line) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: command_line; type: refptr_diff
+ DCHECK(command_line);
+ if (!command_line) {
+ return;
+ }
+ // Unverified params: process_type
+
+ // Execute
+ CefAppCppToC::Get(self)->OnBeforeCommandLineProcessing(
+ CefString(process_type), CefCommandLineCToCpp::Wrap(command_line));
+}
+
+void CEF_CALLBACK
+app_on_register_custom_schemes(struct _cef_app_t* self,
+ struct _cef_scheme_registrar_t* registrar) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: registrar; type: rawptr_diff
+ DCHECK(registrar);
+ if (!registrar) {
+ return;
+ }
+
+ // Translate param: registrar; type: rawptr_diff
+ CefOwnPtr<CefSchemeRegistrar> registrarPtr(
+ CefSchemeRegistrarCToCpp::Wrap(registrar));
+
+ // Execute
+ CefAppCppToC::Get(self)->OnRegisterCustomSchemes(registrarPtr.get());
+}
+
+struct _cef_resource_bundle_handler_t* CEF_CALLBACK
+app_get_resource_bundle_handler(struct _cef_app_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefResourceBundleHandler> _retval =
+ CefAppCppToC::Get(self)->GetResourceBundleHandler();
+
+ // Return type: refptr_same
+ return CefResourceBundleHandlerCppToC::Wrap(_retval);
+}
+
+struct _cef_browser_process_handler_t* CEF_CALLBACK
+app_get_browser_process_handler(struct _cef_app_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefBrowserProcessHandler> _retval =
+ CefAppCppToC::Get(self)->GetBrowserProcessHandler();
+
+ // Return type: refptr_same
+ return CefBrowserProcessHandlerCppToC::Wrap(_retval);
+}
+
+struct _cef_render_process_handler_t* CEF_CALLBACK
+app_get_render_process_handler(struct _cef_app_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefRenderProcessHandler> _retval =
+ CefAppCppToC::Get(self)->GetRenderProcessHandler();
+
+ // Return type: refptr_same
+ return CefRenderProcessHandlerCppToC::Wrap(_retval);
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefAppCppToC::CefAppCppToC() {
+ GetStruct()->on_before_command_line_processing =
+ app_on_before_command_line_processing;
+ GetStruct()->on_register_custom_schemes = app_on_register_custom_schemes;
+ GetStruct()->get_resource_bundle_handler = app_get_resource_bundle_handler;
+ GetStruct()->get_browser_process_handler = app_get_browser_process_handler;
+ GetStruct()->get_render_process_handler = app_get_render_process_handler;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefAppCppToC::~CefAppCppToC() {}
+
+template <>
+CefRefPtr<CefApp>
+CefCppToCRefCounted<CefAppCppToC, CefApp, cef_app_t>::UnwrapDerived(
+ CefWrapperType type,
+ cef_app_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCppToCRefCounted<CefAppCppToC, CefApp, cef_app_t>::kWrapperType = WT_APP;
diff --git a/libcef_dll/cpptoc/app_cpptoc.h b/libcef_dll/cpptoc/app_cpptoc.h
new file mode 100644
index 00000000..fe94e858
--- /dev/null
+++ b/libcef_dll/cpptoc/app_cpptoc.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=a4d3edb584e87581659ded4e0bb20739b2b0efea$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_APP_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_APP_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_app_capi.h"
+#include "include/cef_app.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefAppCppToC
+ : public CefCppToCRefCounted<CefAppCppToC, CefApp, cef_app_t> {
+ public:
+ CefAppCppToC();
+ virtual ~CefAppCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_APP_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/audio_handler_cpptoc.cc b/libcef_dll/cpptoc/audio_handler_cpptoc.cc
new file mode 100644
index 00000000..d5f9b924
--- /dev/null
+++ b/libcef_dll/cpptoc/audio_handler_cpptoc.cc
@@ -0,0 +1,206 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=0e814467a4d428a493930a3e72123dfd6721786e$
+//
+
+#include "libcef_dll/cpptoc/audio_handler_cpptoc.h"
+#include "libcef_dll/ctocpp/browser_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK
+audio_handler_get_audio_parameters(struct _cef_audio_handler_t* self,
+ struct _cef_browser_t* browser,
+ cef_audio_parameters_t* params) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return 0;
+ }
+ // Verify param: params; type: simple_byref
+ DCHECK(params);
+ if (!params) {
+ return 0;
+ }
+
+ // Translate param: params; type: simple_byref
+ CefAudioParameters paramsVal = params ? *params : CefAudioParameters();
+
+ // Execute
+ bool _retval = CefAudioHandlerCppToC::Get(self)->GetAudioParameters(
+ CefBrowserCToCpp::Wrap(browser), paramsVal);
+
+ // Restore param: params; type: simple_byref
+ if (params) {
+ *params = paramsVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK
+audio_handler_on_audio_stream_started(struct _cef_audio_handler_t* self,
+ struct _cef_browser_t* browser,
+ const cef_audio_parameters_t* params,
+ int channels) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+ // Verify param: params; type: simple_byref_const
+ DCHECK(params);
+ if (!params) {
+ return;
+ }
+
+ // Translate param: params; type: simple_byref_const
+ CefAudioParameters paramsVal = params ? *params : CefAudioParameters();
+
+ // Execute
+ CefAudioHandlerCppToC::Get(self)->OnAudioStreamStarted(
+ CefBrowserCToCpp::Wrap(browser), paramsVal, channels);
+}
+
+void CEF_CALLBACK
+audio_handler_on_audio_stream_packet(struct _cef_audio_handler_t* self,
+ struct _cef_browser_t* browser,
+ const float** data,
+ int frames,
+ int64 pts) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+ // Verify param: data; type: simple_byaddr
+ DCHECK(data);
+ if (!data) {
+ return;
+ }
+
+ // Execute
+ CefAudioHandlerCppToC::Get(self)->OnAudioStreamPacket(
+ CefBrowserCToCpp::Wrap(browser), data, frames, pts);
+}
+
+void CEF_CALLBACK
+audio_handler_on_audio_stream_stopped(struct _cef_audio_handler_t* self,
+ struct _cef_browser_t* browser) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+
+ // Execute
+ CefAudioHandlerCppToC::Get(self)->OnAudioStreamStopped(
+ CefBrowserCToCpp::Wrap(browser));
+}
+
+void CEF_CALLBACK
+audio_handler_on_audio_stream_error(struct _cef_audio_handler_t* self,
+ struct _cef_browser_t* browser,
+ const cef_string_t* message) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+ // Verify param: message; type: string_byref_const
+ DCHECK(message);
+ if (!message) {
+ return;
+ }
+
+ // Execute
+ CefAudioHandlerCppToC::Get(self)->OnAudioStreamError(
+ CefBrowserCToCpp::Wrap(browser), CefString(message));
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefAudioHandlerCppToC::CefAudioHandlerCppToC() {
+ GetStruct()->get_audio_parameters = audio_handler_get_audio_parameters;
+ GetStruct()->on_audio_stream_started = audio_handler_on_audio_stream_started;
+ GetStruct()->on_audio_stream_packet = audio_handler_on_audio_stream_packet;
+ GetStruct()->on_audio_stream_stopped = audio_handler_on_audio_stream_stopped;
+ GetStruct()->on_audio_stream_error = audio_handler_on_audio_stream_error;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefAudioHandlerCppToC::~CefAudioHandlerCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefAudioHandler> CefCppToCRefCounted<
+ CefAudioHandlerCppToC,
+ CefAudioHandler,
+ cef_audio_handler_t>::UnwrapDerived(CefWrapperType type,
+ cef_audio_handler_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefAudioHandlerCppToC,
+ CefAudioHandler,
+ cef_audio_handler_t>::kWrapperType =
+ WT_AUDIO_HANDLER;
diff --git a/libcef_dll/cpptoc/audio_handler_cpptoc.h b/libcef_dll/cpptoc/audio_handler_cpptoc.h
new file mode 100644
index 00000000..1d574545
--- /dev/null
+++ b/libcef_dll/cpptoc/audio_handler_cpptoc.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=6d31cfb9774514e0a15c999903fa4eb9ce76634d$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_AUDIO_HANDLER_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_AUDIO_HANDLER_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_audio_handler_capi.h"
+#include "include/cef_audio_handler.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefAudioHandlerCppToC : public CefCppToCRefCounted<CefAudioHandlerCppToC,
+ CefAudioHandler,
+ cef_audio_handler_t> {
+ public:
+ CefAudioHandlerCppToC();
+ virtual ~CefAudioHandlerCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_AUDIO_HANDLER_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/auth_callback_cpptoc.cc b/libcef_dll/cpptoc/auth_callback_cpptoc.cc
new file mode 100644
index 00000000..d584293c
--- /dev/null
+++ b/libcef_dll/cpptoc/auth_callback_cpptoc.cc
@@ -0,0 +1,83 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=0a14f97c38bffa0ead433d74df13b04028c44a21$
+//
+
+#include "libcef_dll/cpptoc/auth_callback_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK auth_callback_cont(struct _cef_auth_callback_t* self,
+ const cef_string_t* username,
+ const cef_string_t* password) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Unverified params: username, password
+
+ // Execute
+ CefAuthCallbackCppToC::Get(self)->Continue(CefString(username),
+ CefString(password));
+}
+
+void CEF_CALLBACK auth_callback_cancel(struct _cef_auth_callback_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefAuthCallbackCppToC::Get(self)->Cancel();
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefAuthCallbackCppToC::CefAuthCallbackCppToC() {
+ GetStruct()->cont = auth_callback_cont;
+ GetStruct()->cancel = auth_callback_cancel;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefAuthCallbackCppToC::~CefAuthCallbackCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefAuthCallback> CefCppToCRefCounted<
+ CefAuthCallbackCppToC,
+ CefAuthCallback,
+ cef_auth_callback_t>::UnwrapDerived(CefWrapperType type,
+ cef_auth_callback_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefAuthCallbackCppToC,
+ CefAuthCallback,
+ cef_auth_callback_t>::kWrapperType =
+ WT_AUTH_CALLBACK;
diff --git a/libcef_dll/cpptoc/auth_callback_cpptoc.h b/libcef_dll/cpptoc/auth_callback_cpptoc.h
new file mode 100644
index 00000000..6a1dd700
--- /dev/null
+++ b/libcef_dll/cpptoc/auth_callback_cpptoc.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=be94cb2e319c4a42e8bc9ee41b78935834e8a59c$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_AUTH_CALLBACK_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_AUTH_CALLBACK_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_auth_callback_capi.h"
+#include "include/cef_auth_callback.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefAuthCallbackCppToC : public CefCppToCRefCounted<CefAuthCallbackCppToC,
+ CefAuthCallback,
+ cef_auth_callback_t> {
+ public:
+ CefAuthCallbackCppToC();
+ virtual ~CefAuthCallbackCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_AUTH_CALLBACK_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/base_ref_counted_cpptoc.cc b/libcef_dll/cpptoc/base_ref_counted_cpptoc.cc
new file mode 100644
index 00000000..78d7e95a
--- /dev/null
+++ b/libcef_dll/cpptoc/base_ref_counted_cpptoc.cc
@@ -0,0 +1,23 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "libcef_dll/cpptoc/base_ref_counted_cpptoc.h"
+
+CefBaseRefCountedCppToC::CefBaseRefCountedCppToC() {}
+
+template <>
+CefRefPtr<CefBaseRefCounted> CefCppToCRefCounted<
+ CefBaseRefCountedCppToC,
+ CefBaseRefCounted,
+ cef_base_ref_counted_t>::UnwrapDerived(CefWrapperType type,
+ cef_base_ref_counted_t* s) {
+ NOTREACHED();
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefBaseRefCountedCppToC,
+ CefBaseRefCounted,
+ cef_base_ref_counted_t>::kWrapperType =
+ WT_BASE_REF_COUNTED;
diff --git a/libcef_dll/cpptoc/base_ref_counted_cpptoc.h b/libcef_dll/cpptoc/base_ref_counted_cpptoc.h
new file mode 100644
index 00000000..a8e1eb1f
--- /dev/null
+++ b/libcef_dll/cpptoc/base_ref_counted_cpptoc.h
@@ -0,0 +1,26 @@
+// Copyright (c) 2009 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_BASE_REF_COUNTED_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_BASE_REF_COUNTED_CPPTOC_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+#include "include/cef_base.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+// Wrap a C++ class with a C structure.
+class CefBaseRefCountedCppToC
+ : public CefCppToCRefCounted<CefBaseRefCountedCppToC,
+ CefBaseRefCounted,
+ cef_base_ref_counted_t> {
+ public:
+ CefBaseRefCountedCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_BASE_REF_COUNTED_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/base_scoped_cpptoc.cc b/libcef_dll/cpptoc/base_scoped_cpptoc.cc
new file mode 100644
index 00000000..02387ca8
--- /dev/null
+++ b/libcef_dll/cpptoc/base_scoped_cpptoc.cc
@@ -0,0 +1,29 @@
+// Copyright (c) 2017 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "libcef_dll/cpptoc/base_scoped_cpptoc.h"
+
+CefBaseScopedCppToC::CefBaseScopedCppToC() {}
+
+template <>
+CefOwnPtr<CefBaseScoped>
+CefCppToCScoped<CefBaseScopedCppToC, CefBaseScoped, cef_base_scoped_t>::
+ UnwrapDerivedOwn(CefWrapperType type, cef_base_scoped_t* s) {
+ NOTREACHED();
+ return CefOwnPtr<CefBaseScoped>();
+}
+
+template <>
+CefRawPtr<CefBaseScoped>
+CefCppToCScoped<CefBaseScopedCppToC, CefBaseScoped, cef_base_scoped_t>::
+ UnwrapDerivedRaw(CefWrapperType type, cef_base_scoped_t* s) {
+ NOTREACHED();
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCScoped<CefBaseScopedCppToC,
+ CefBaseScoped,
+ cef_base_scoped_t>::kWrapperType =
+ WT_BASE_SCOPED;
diff --git a/libcef_dll/cpptoc/base_scoped_cpptoc.h b/libcef_dll/cpptoc/base_scoped_cpptoc.h
new file mode 100644
index 00000000..63a66883
--- /dev/null
+++ b/libcef_dll/cpptoc/base_scoped_cpptoc.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2009 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_BASE_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_BASE_CPPTOC_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+#include "include/cef_base.h"
+#include "libcef_dll/cpptoc/cpptoc_scoped.h"
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+// Wrap a C++ class with a C structure.
+class CefBaseScopedCppToC : public CefCppToCScoped<CefBaseScopedCppToC,
+ CefBaseScoped,
+ cef_base_scoped_t> {
+ public:
+ CefBaseScopedCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_BASE_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/before_download_callback_cpptoc.cc b/libcef_dll/cpptoc/before_download_callback_cpptoc.cc
new file mode 100644
index 00000000..34b47da0
--- /dev/null
+++ b/libcef_dll/cpptoc/before_download_callback_cpptoc.cc
@@ -0,0 +1,70 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=a4ba36a9532aa6e1a10f7e43e9ba26ab3e8faea0$
+//
+
+#include "libcef_dll/cpptoc/before_download_callback_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK
+before_download_callback_cont(struct _cef_before_download_callback_t* self,
+ const cef_string_t* download_path,
+ int show_dialog) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Unverified params: download_path
+
+ // Execute
+ CefBeforeDownloadCallbackCppToC::Get(self)->Continue(
+ CefString(download_path), show_dialog ? true : false);
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefBeforeDownloadCallbackCppToC::CefBeforeDownloadCallbackCppToC() {
+ GetStruct()->cont = before_download_callback_cont;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefBeforeDownloadCallbackCppToC::~CefBeforeDownloadCallbackCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefBeforeDownloadCallback>
+CefCppToCRefCounted<CefBeforeDownloadCallbackCppToC,
+ CefBeforeDownloadCallback,
+ cef_before_download_callback_t>::
+ UnwrapDerived(CefWrapperType type, cef_before_download_callback_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCppToCRefCounted<CefBeforeDownloadCallbackCppToC,
+ CefBeforeDownloadCallback,
+ cef_before_download_callback_t>::kWrapperType =
+ WT_BEFORE_DOWNLOAD_CALLBACK;
diff --git a/libcef_dll/cpptoc/before_download_callback_cpptoc.h b/libcef_dll/cpptoc/before_download_callback_cpptoc.h
new file mode 100644
index 00000000..9f2944cd
--- /dev/null
+++ b/libcef_dll/cpptoc/before_download_callback_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=76dfadaa2d0f5ef6cdb8621cad3136e89b33ae25$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_BEFORE_DOWNLOAD_CALLBACK_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_BEFORE_DOWNLOAD_CALLBACK_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_download_handler_capi.h"
+#include "include/cef_download_handler.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefBeforeDownloadCallbackCppToC
+ : public CefCppToCRefCounted<CefBeforeDownloadCallbackCppToC,
+ CefBeforeDownloadCallback,
+ cef_before_download_callback_t> {
+ public:
+ CefBeforeDownloadCallbackCppToC();
+ virtual ~CefBeforeDownloadCallbackCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_BEFORE_DOWNLOAD_CALLBACK_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/binary_value_cpptoc.cc b/libcef_dll/cpptoc/binary_value_cpptoc.cc
new file mode 100644
index 00000000..571b2122
--- /dev/null
+++ b/libcef_dll/cpptoc/binary_value_cpptoc.cc
@@ -0,0 +1,218 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=ae640fec7d7fd1ba5c4b373b0a4f5036f90ab744$
+//
+
+#include "libcef_dll/cpptoc/binary_value_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// GLOBAL FUNCTIONS - Body may be edited by hand.
+
+CEF_EXPORT cef_binary_value_t* cef_binary_value_create(const void* data,
+ size_t data_size) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: data; type: simple_byaddr
+ DCHECK(data);
+ if (!data) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefBinaryValue> _retval = CefBinaryValue::Create(data, data_size);
+
+ // Return type: refptr_same
+ return CefBinaryValueCppToC::Wrap(_retval);
+}
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK binary_value_is_valid(struct _cef_binary_value_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefBinaryValueCppToC::Get(self)->IsValid();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK binary_value_is_owned(struct _cef_binary_value_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefBinaryValueCppToC::Get(self)->IsOwned();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK binary_value_is_same(struct _cef_binary_value_t* self,
+ struct _cef_binary_value_t* that) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: that; type: refptr_same
+ DCHECK(that);
+ if (!that) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefBinaryValueCppToC::Get(self)->IsSame(
+ CefBinaryValueCppToC::Unwrap(that));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK binary_value_is_equal(struct _cef_binary_value_t* self,
+ struct _cef_binary_value_t* that) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: that; type: refptr_same
+ DCHECK(that);
+ if (!that) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefBinaryValueCppToC::Get(self)->IsEqual(
+ CefBinaryValueCppToC::Unwrap(that));
+
+ // Return type: bool
+ return _retval;
+}
+
+struct _cef_binary_value_t* CEF_CALLBACK
+binary_value_copy(struct _cef_binary_value_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefBinaryValue> _retval = CefBinaryValueCppToC::Get(self)->Copy();
+
+ // Return type: refptr_same
+ return CefBinaryValueCppToC::Wrap(_retval);
+}
+
+size_t CEF_CALLBACK binary_value_get_size(struct _cef_binary_value_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ size_t _retval = CefBinaryValueCppToC::Get(self)->GetSize();
+
+ // Return type: simple
+ return _retval;
+}
+
+size_t CEF_CALLBACK binary_value_get_data(struct _cef_binary_value_t* self,
+ void* buffer,
+ size_t buffer_size,
+ size_t data_offset) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: buffer; type: simple_byaddr
+ DCHECK(buffer);
+ if (!buffer) {
+ return 0;
+ }
+
+ // Execute
+ size_t _retval = CefBinaryValueCppToC::Get(self)->GetData(buffer, buffer_size,
+ data_offset);
+
+ // Return type: simple
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefBinaryValueCppToC::CefBinaryValueCppToC() {
+ GetStruct()->is_valid = binary_value_is_valid;
+ GetStruct()->is_owned = binary_value_is_owned;
+ GetStruct()->is_same = binary_value_is_same;
+ GetStruct()->is_equal = binary_value_is_equal;
+ GetStruct()->copy = binary_value_copy;
+ GetStruct()->get_size = binary_value_get_size;
+ GetStruct()->get_data = binary_value_get_data;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefBinaryValueCppToC::~CefBinaryValueCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefBinaryValue>
+CefCppToCRefCounted<CefBinaryValueCppToC, CefBinaryValue, cef_binary_value_t>::
+ UnwrapDerived(CefWrapperType type, cef_binary_value_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefBinaryValueCppToC,
+ CefBinaryValue,
+ cef_binary_value_t>::kWrapperType =
+ WT_BINARY_VALUE;
diff --git a/libcef_dll/cpptoc/binary_value_cpptoc.h b/libcef_dll/cpptoc/binary_value_cpptoc.h
new file mode 100644
index 00000000..3f6a9e36
--- /dev/null
+++ b/libcef_dll/cpptoc/binary_value_cpptoc.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=bdc631b2bd2c0a68146e823e0ff23e1b3a455023$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_BINARY_VALUE_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_BINARY_VALUE_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_values_capi.h"
+#include "include/cef_values.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefBinaryValueCppToC : public CefCppToCRefCounted<CefBinaryValueCppToC,
+ CefBinaryValue,
+ cef_binary_value_t> {
+ public:
+ CefBinaryValueCppToC();
+ virtual ~CefBinaryValueCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_BINARY_VALUE_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/browser_cpptoc.cc b/libcef_dll/cpptoc/browser_cpptoc.cc
new file mode 100644
index 00000000..4aaac890
--- /dev/null
+++ b/libcef_dll/cpptoc/browser_cpptoc.cc
@@ -0,0 +1,462 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=60cc6a84bbd0c6822e9722687de05d265a3d8a1b$
+//
+
+#include "libcef_dll/cpptoc/browser_cpptoc.h"
+#include <algorithm>
+#include "libcef_dll/cpptoc/browser_host_cpptoc.h"
+#include "libcef_dll/cpptoc/frame_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+#include "libcef_dll/transfer_util.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK browser_is_valid(struct _cef_browser_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefBrowserCppToC::Get(self)->IsValid();
+
+ // Return type: bool
+ return _retval;
+}
+
+struct _cef_browser_host_t* CEF_CALLBACK
+browser_get_host(struct _cef_browser_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefBrowserHost> _retval = CefBrowserCppToC::Get(self)->GetHost();
+
+ // Return type: refptr_same
+ return CefBrowserHostCppToC::Wrap(_retval);
+}
+
+int CEF_CALLBACK browser_can_go_back(struct _cef_browser_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefBrowserCppToC::Get(self)->CanGoBack();
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK browser_go_back(struct _cef_browser_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefBrowserCppToC::Get(self)->GoBack();
+}
+
+int CEF_CALLBACK browser_can_go_forward(struct _cef_browser_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefBrowserCppToC::Get(self)->CanGoForward();
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK browser_go_forward(struct _cef_browser_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefBrowserCppToC::Get(self)->GoForward();
+}
+
+int CEF_CALLBACK browser_is_loading(struct _cef_browser_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefBrowserCppToC::Get(self)->IsLoading();
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK browser_reload(struct _cef_browser_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefBrowserCppToC::Get(self)->Reload();
+}
+
+void CEF_CALLBACK browser_reload_ignore_cache(struct _cef_browser_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefBrowserCppToC::Get(self)->ReloadIgnoreCache();
+}
+
+void CEF_CALLBACK browser_stop_load(struct _cef_browser_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefBrowserCppToC::Get(self)->StopLoad();
+}
+
+int CEF_CALLBACK browser_get_identifier(struct _cef_browser_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefBrowserCppToC::Get(self)->GetIdentifier();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK browser_is_same(struct _cef_browser_t* self,
+ struct _cef_browser_t* that) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: that; type: refptr_same
+ DCHECK(that);
+ if (!that) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefBrowserCppToC::Get(self)->IsSame(CefBrowserCppToC::Unwrap(that));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK browser_is_popup(struct _cef_browser_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefBrowserCppToC::Get(self)->IsPopup();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK browser_has_document(struct _cef_browser_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefBrowserCppToC::Get(self)->HasDocument();
+
+ // Return type: bool
+ return _retval;
+}
+
+struct _cef_frame_t* CEF_CALLBACK
+browser_get_main_frame(struct _cef_browser_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefFrame> _retval = CefBrowserCppToC::Get(self)->GetMainFrame();
+
+ // Return type: refptr_same
+ return CefFrameCppToC::Wrap(_retval);
+}
+
+struct _cef_frame_t* CEF_CALLBACK
+browser_get_focused_frame(struct _cef_browser_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefFrame> _retval = CefBrowserCppToC::Get(self)->GetFocusedFrame();
+
+ // Return type: refptr_same
+ return CefFrameCppToC::Wrap(_retval);
+}
+
+struct _cef_frame_t* CEF_CALLBACK
+browser_get_frame_byident(struct _cef_browser_t* self, int64 identifier) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefFrame> _retval =
+ CefBrowserCppToC::Get(self)->GetFrame(identifier);
+
+ // Return type: refptr_same
+ return CefFrameCppToC::Wrap(_retval);
+}
+
+struct _cef_frame_t* CEF_CALLBACK browser_get_frame(struct _cef_browser_t* self,
+ const cef_string_t* name) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+ // Unverified params: name
+
+ // Execute
+ CefRefPtr<CefFrame> _retval =
+ CefBrowserCppToC::Get(self)->GetFrame(CefString(name));
+
+ // Return type: refptr_same
+ return CefFrameCppToC::Wrap(_retval);
+}
+
+size_t CEF_CALLBACK browser_get_frame_count(struct _cef_browser_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ size_t _retval = CefBrowserCppToC::Get(self)->GetFrameCount();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK browser_get_frame_identifiers(struct _cef_browser_t* self,
+ size_t* identifiersCount,
+ int64* identifiers) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: identifiers; type: simple_vec_byref
+ DCHECK(identifiersCount && (*identifiersCount == 0 || identifiers));
+ if (!identifiersCount || (*identifiersCount > 0 && !identifiers)) {
+ return;
+ }
+
+ // Translate param: identifiers; type: simple_vec_byref
+ std::vector<int64> identifiersList;
+ if (identifiersCount && *identifiersCount > 0 && identifiers) {
+ for (size_t i = 0; i < *identifiersCount; ++i) {
+ identifiersList.push_back(identifiers[i]);
+ }
+ }
+
+ // Execute
+ CefBrowserCppToC::Get(self)->GetFrameIdentifiers(identifiersList);
+
+ // Restore param: identifiers; type: simple_vec_byref
+ if (identifiersCount && identifiers) {
+ *identifiersCount = std::min(identifiersList.size(), *identifiersCount);
+ if (*identifiersCount > 0) {
+ for (size_t i = 0; i < *identifiersCount; ++i) {
+ identifiers[i] = identifiersList[i];
+ }
+ }
+ }
+}
+
+void CEF_CALLBACK browser_get_frame_names(struct _cef_browser_t* self,
+ cef_string_list_t names) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: names; type: string_vec_byref
+ DCHECK(names);
+ if (!names) {
+ return;
+ }
+
+ // Translate param: names; type: string_vec_byref
+ std::vector<CefString> namesList;
+ transfer_string_list_contents(names, namesList);
+
+ // Execute
+ CefBrowserCppToC::Get(self)->GetFrameNames(namesList);
+
+ // Restore param: names; type: string_vec_byref
+ cef_string_list_clear(names);
+ transfer_string_list_contents(namesList, names);
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefBrowserCppToC::CefBrowserCppToC() {
+ GetStruct()->is_valid = browser_is_valid;
+ GetStruct()->get_host = browser_get_host;
+ GetStruct()->can_go_back = browser_can_go_back;
+ GetStruct()->go_back = browser_go_back;
+ GetStruct()->can_go_forward = browser_can_go_forward;
+ GetStruct()->go_forward = browser_go_forward;
+ GetStruct()->is_loading = browser_is_loading;
+ GetStruct()->reload = browser_reload;
+ GetStruct()->reload_ignore_cache = browser_reload_ignore_cache;
+ GetStruct()->stop_load = browser_stop_load;
+ GetStruct()->get_identifier = browser_get_identifier;
+ GetStruct()->is_same = browser_is_same;
+ GetStruct()->is_popup = browser_is_popup;
+ GetStruct()->has_document = browser_has_document;
+ GetStruct()->get_main_frame = browser_get_main_frame;
+ GetStruct()->get_focused_frame = browser_get_focused_frame;
+ GetStruct()->get_frame_byident = browser_get_frame_byident;
+ GetStruct()->get_frame = browser_get_frame;
+ GetStruct()->get_frame_count = browser_get_frame_count;
+ GetStruct()->get_frame_identifiers = browser_get_frame_identifiers;
+ GetStruct()->get_frame_names = browser_get_frame_names;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefBrowserCppToC::~CefBrowserCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefBrowser>
+CefCppToCRefCounted<CefBrowserCppToC, CefBrowser, cef_browser_t>::UnwrapDerived(
+ CefWrapperType type,
+ cef_browser_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefBrowserCppToC,
+ CefBrowser,
+ cef_browser_t>::kWrapperType = WT_BROWSER;
diff --git a/libcef_dll/cpptoc/browser_cpptoc.h b/libcef_dll/cpptoc/browser_cpptoc.h
new file mode 100644
index 00000000..1a10254e
--- /dev/null
+++ b/libcef_dll/cpptoc/browser_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=01e044c521a174528e137e4b131d9df95875eb65$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_BROWSER_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_BROWSER_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_browser_capi.h"
+#include "include/capi/cef_client_capi.h"
+#include "include/cef_browser.h"
+#include "include/cef_client.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefBrowserCppToC
+ : public CefCppToCRefCounted<CefBrowserCppToC, CefBrowser, cef_browser_t> {
+ public:
+ CefBrowserCppToC();
+ virtual ~CefBrowserCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_BROWSER_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/browser_host_cpptoc.cc b/libcef_dll/cpptoc/browser_host_cpptoc.cc
new file mode 100644
index 00000000..2f424fc2
--- /dev/null
+++ b/libcef_dll/cpptoc/browser_host_cpptoc.cc
@@ -0,0 +1,1481 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=c4f784a8632ae70a588619db29e826fac26531e1$
+//
+
+#include "libcef_dll/cpptoc/browser_host_cpptoc.h"
+#include "libcef_dll/cpptoc/browser_cpptoc.h"
+#include "libcef_dll/cpptoc/dictionary_value_cpptoc.h"
+#include "libcef_dll/cpptoc/drag_data_cpptoc.h"
+#include "libcef_dll/cpptoc/extension_cpptoc.h"
+#include "libcef_dll/cpptoc/navigation_entry_cpptoc.h"
+#include "libcef_dll/cpptoc/registration_cpptoc.h"
+#include "libcef_dll/cpptoc/request_context_cpptoc.h"
+#include "libcef_dll/ctocpp/client_ctocpp.h"
+#include "libcef_dll/ctocpp/dev_tools_message_observer_ctocpp.h"
+#include "libcef_dll/ctocpp/download_image_callback_ctocpp.h"
+#include "libcef_dll/ctocpp/navigation_entry_visitor_ctocpp.h"
+#include "libcef_dll/ctocpp/pdf_print_callback_ctocpp.h"
+#include "libcef_dll/ctocpp/run_file_dialog_callback_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+#include "libcef_dll/template_util.h"
+#include "libcef_dll/transfer_util.h"
+
+// GLOBAL FUNCTIONS - Body may be edited by hand.
+
+CEF_EXPORT int cef_browser_host_create_browser(
+ const cef_window_info_t* windowInfo,
+ struct _cef_client_t* client,
+ const cef_string_t* url,
+ const struct _cef_browser_settings_t* settings,
+ struct _cef_dictionary_value_t* extra_info,
+ struct _cef_request_context_t* request_context) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: windowInfo; type: struct_byref_const
+ DCHECK(windowInfo);
+ if (!windowInfo) {
+ return 0;
+ }
+ if (!template_util::has_valid_size(windowInfo)) {
+ NOTREACHED() << "invalid windowInfo->[base.]size";
+ return 0;
+ }
+ // Verify param: settings; type: struct_byref_const
+ DCHECK(settings);
+ if (!settings) {
+ return 0;
+ }
+ if (!template_util::has_valid_size(settings)) {
+ NOTREACHED() << "invalid settings->[base.]size";
+ return 0;
+ }
+ // Unverified params: client, url, extra_info, request_context
+
+ // Translate param: windowInfo; type: struct_byref_const
+ CefWindowInfo windowInfoObj;
+ if (windowInfo) {
+ windowInfoObj.Set(*windowInfo, false);
+ }
+ // Translate param: settings; type: struct_byref_const
+ CefBrowserSettings settingsObj;
+ if (settings) {
+ settingsObj.Set(*settings, false);
+ }
+
+ // Execute
+ bool _retval = CefBrowserHost::CreateBrowser(
+ windowInfoObj, CefClientCToCpp::Wrap(client), CefString(url), settingsObj,
+ CefDictionaryValueCppToC::Unwrap(extra_info),
+ CefRequestContextCppToC::Unwrap(request_context));
+
+ // Return type: bool
+ return _retval;
+}
+
+CEF_EXPORT cef_browser_t* cef_browser_host_create_browser_sync(
+ const cef_window_info_t* windowInfo,
+ struct _cef_client_t* client,
+ const cef_string_t* url,
+ const struct _cef_browser_settings_t* settings,
+ struct _cef_dictionary_value_t* extra_info,
+ struct _cef_request_context_t* request_context) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: windowInfo; type: struct_byref_const
+ DCHECK(windowInfo);
+ if (!windowInfo) {
+ return NULL;
+ }
+ if (!template_util::has_valid_size(windowInfo)) {
+ NOTREACHED() << "invalid windowInfo->[base.]size";
+ return NULL;
+ }
+ // Verify param: settings; type: struct_byref_const
+ DCHECK(settings);
+ if (!settings) {
+ return NULL;
+ }
+ if (!template_util::has_valid_size(settings)) {
+ NOTREACHED() << "invalid settings->[base.]size";
+ return NULL;
+ }
+ // Unverified params: client, url, extra_info, request_context
+
+ // Translate param: windowInfo; type: struct_byref_const
+ CefWindowInfo windowInfoObj;
+ if (windowInfo) {
+ windowInfoObj.Set(*windowInfo, false);
+ }
+ // Translate param: settings; type: struct_byref_const
+ CefBrowserSettings settingsObj;
+ if (settings) {
+ settingsObj.Set(*settings, false);
+ }
+
+ // Execute
+ CefRefPtr<CefBrowser> _retval = CefBrowserHost::CreateBrowserSync(
+ windowInfoObj, CefClientCToCpp::Wrap(client), CefString(url), settingsObj,
+ CefDictionaryValueCppToC::Unwrap(extra_info),
+ CefRequestContextCppToC::Unwrap(request_context));
+
+ // Return type: refptr_same
+ return CefBrowserCppToC::Wrap(_retval);
+}
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+cef_browser_t* CEF_CALLBACK
+browser_host_get_browser(struct _cef_browser_host_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefBrowser> _retval = CefBrowserHostCppToC::Get(self)->GetBrowser();
+
+ // Return type: refptr_same
+ return CefBrowserCppToC::Wrap(_retval);
+}
+
+void CEF_CALLBACK browser_host_close_browser(struct _cef_browser_host_t* self,
+ int force_close) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefBrowserHostCppToC::Get(self)->CloseBrowser(force_close ? true : false);
+}
+
+int CEF_CALLBACK
+browser_host_try_close_browser(struct _cef_browser_host_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefBrowserHostCppToC::Get(self)->TryCloseBrowser();
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK browser_host_set_focus(struct _cef_browser_host_t* self,
+ int focus) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefBrowserHostCppToC::Get(self)->SetFocus(focus ? true : false);
+}
+
+cef_window_handle_t CEF_CALLBACK
+browser_host_get_window_handle(struct _cef_browser_host_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return kNullWindowHandle;
+ }
+
+ // Execute
+ cef_window_handle_t _retval =
+ CefBrowserHostCppToC::Get(self)->GetWindowHandle();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_window_handle_t CEF_CALLBACK
+browser_host_get_opener_window_handle(struct _cef_browser_host_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return kNullWindowHandle;
+ }
+
+ // Execute
+ cef_window_handle_t _retval =
+ CefBrowserHostCppToC::Get(self)->GetOpenerWindowHandle();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK browser_host_has_view(struct _cef_browser_host_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefBrowserHostCppToC::Get(self)->HasView();
+
+ // Return type: bool
+ return _retval;
+}
+
+struct _cef_client_t* CEF_CALLBACK
+browser_host_get_client(struct _cef_browser_host_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefClient> _retval = CefBrowserHostCppToC::Get(self)->GetClient();
+
+ // Return type: refptr_diff
+ return CefClientCToCpp::Unwrap(_retval);
+}
+
+struct _cef_request_context_t* CEF_CALLBACK
+browser_host_get_request_context(struct _cef_browser_host_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefRequestContext> _retval =
+ CefBrowserHostCppToC::Get(self)->GetRequestContext();
+
+ // Return type: refptr_same
+ return CefRequestContextCppToC::Wrap(_retval);
+}
+
+double CEF_CALLBACK
+browser_host_get_zoom_level(struct _cef_browser_host_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ double _retval = CefBrowserHostCppToC::Get(self)->GetZoomLevel();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK browser_host_set_zoom_level(struct _cef_browser_host_t* self,
+ double zoomLevel) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefBrowserHostCppToC::Get(self)->SetZoomLevel(zoomLevel);
+}
+
+void CEF_CALLBACK
+browser_host_run_file_dialog(struct _cef_browser_host_t* self,
+ cef_file_dialog_mode_t mode,
+ const cef_string_t* title,
+ const cef_string_t* default_file_path,
+ cef_string_list_t accept_filters,
+ cef_run_file_dialog_callback_t* callback) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: callback; type: refptr_diff
+ DCHECK(callback);
+ if (!callback) {
+ return;
+ }
+ // Unverified params: title, default_file_path, accept_filters
+
+ // Translate param: accept_filters; type: string_vec_byref_const
+ std::vector<CefString> accept_filtersList;
+ transfer_string_list_contents(accept_filters, accept_filtersList);
+
+ // Execute
+ CefBrowserHostCppToC::Get(self)->RunFileDialog(
+ mode, CefString(title), CefString(default_file_path), accept_filtersList,
+ CefRunFileDialogCallbackCToCpp::Wrap(callback));
+}
+
+void CEF_CALLBACK browser_host_start_download(struct _cef_browser_host_t* self,
+ const cef_string_t* url) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: url; type: string_byref_const
+ DCHECK(url);
+ if (!url) {
+ return;
+ }
+
+ // Execute
+ CefBrowserHostCppToC::Get(self)->StartDownload(CefString(url));
+}
+
+void CEF_CALLBACK
+browser_host_download_image(struct _cef_browser_host_t* self,
+ const cef_string_t* image_url,
+ int is_favicon,
+ uint32 max_image_size,
+ int bypass_cache,
+ cef_download_image_callback_t* callback) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: image_url; type: string_byref_const
+ DCHECK(image_url);
+ if (!image_url) {
+ return;
+ }
+ // Verify param: callback; type: refptr_diff
+ DCHECK(callback);
+ if (!callback) {
+ return;
+ }
+
+ // Execute
+ CefBrowserHostCppToC::Get(self)->DownloadImage(
+ CefString(image_url), is_favicon ? true : false, max_image_size,
+ bypass_cache ? true : false,
+ CefDownloadImageCallbackCToCpp::Wrap(callback));
+}
+
+void CEF_CALLBACK browser_host_print(struct _cef_browser_host_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefBrowserHostCppToC::Get(self)->Print();
+}
+
+void CEF_CALLBACK
+browser_host_print_to_pdf(struct _cef_browser_host_t* self,
+ const cef_string_t* path,
+ const struct _cef_pdf_print_settings_t* settings,
+ cef_pdf_print_callback_t* callback) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: path; type: string_byref_const
+ DCHECK(path);
+ if (!path) {
+ return;
+ }
+ // Verify param: settings; type: struct_byref_const
+ DCHECK(settings);
+ if (!settings) {
+ return;
+ }
+ if (!template_util::has_valid_size(settings)) {
+ NOTREACHED() << "invalid settings->[base.]size";
+ return;
+ }
+ // Unverified params: callback
+
+ // Translate param: settings; type: struct_byref_const
+ CefPdfPrintSettings settingsObj;
+ if (settings) {
+ settingsObj.Set(*settings, false);
+ }
+
+ // Execute
+ CefBrowserHostCppToC::Get(self)->PrintToPDF(
+ CefString(path), settingsObj, CefPdfPrintCallbackCToCpp::Wrap(callback));
+}
+
+void CEF_CALLBACK browser_host_find(struct _cef_browser_host_t* self,
+ const cef_string_t* searchText,
+ int forward,
+ int matchCase,
+ int findNext) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: searchText; type: string_byref_const
+ DCHECK(searchText);
+ if (!searchText) {
+ return;
+ }
+
+ // Execute
+ CefBrowserHostCppToC::Get(self)->Find(
+ CefString(searchText), forward ? true : false, matchCase ? true : false,
+ findNext ? true : false);
+}
+
+void CEF_CALLBACK browser_host_stop_finding(struct _cef_browser_host_t* self,
+ int clearSelection) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefBrowserHostCppToC::Get(self)->StopFinding(clearSelection ? true : false);
+}
+
+void CEF_CALLBACK
+browser_host_show_dev_tools(struct _cef_browser_host_t* self,
+ const cef_window_info_t* windowInfo,
+ struct _cef_client_t* client,
+ const struct _cef_browser_settings_t* settings,
+ const cef_point_t* inspect_element_at) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Unverified params: windowInfo, client, settings, inspect_element_at
+
+ // Translate param: windowInfo; type: struct_byref_const
+ CefWindowInfo windowInfoObj;
+ if (windowInfo) {
+ windowInfoObj.Set(*windowInfo, false);
+ }
+ // Translate param: settings; type: struct_byref_const
+ CefBrowserSettings settingsObj;
+ if (settings) {
+ settingsObj.Set(*settings, false);
+ }
+ // Translate param: inspect_element_at; type: simple_byref_const
+ CefPoint inspect_element_atVal =
+ inspect_element_at ? *inspect_element_at : CefPoint();
+
+ // Execute
+ CefBrowserHostCppToC::Get(self)->ShowDevTools(
+ windowInfoObj, CefClientCToCpp::Wrap(client), settingsObj,
+ inspect_element_atVal);
+}
+
+void CEF_CALLBACK
+browser_host_close_dev_tools(struct _cef_browser_host_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefBrowserHostCppToC::Get(self)->CloseDevTools();
+}
+
+int CEF_CALLBACK browser_host_has_dev_tools(struct _cef_browser_host_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefBrowserHostCppToC::Get(self)->HasDevTools();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+browser_host_send_dev_tools_message(struct _cef_browser_host_t* self,
+ const void* message,
+ size_t message_size) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: message; type: simple_byaddr
+ DCHECK(message);
+ if (!message) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefBrowserHostCppToC::Get(self)->SendDevToolsMessage(
+ message, message_size);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+browser_host_execute_dev_tools_method(struct _cef_browser_host_t* self,
+ int message_id,
+ const cef_string_t* method,
+ struct _cef_dictionary_value_t* params) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: method; type: string_byref_const
+ DCHECK(method);
+ if (!method) {
+ return 0;
+ }
+ // Unverified params: params
+
+ // Execute
+ int _retval = CefBrowserHostCppToC::Get(self)->ExecuteDevToolsMethod(
+ message_id, CefString(method), CefDictionaryValueCppToC::Unwrap(params));
+
+ // Return type: simple
+ return _retval;
+}
+
+struct _cef_registration_t* CEF_CALLBACK
+browser_host_add_dev_tools_message_observer(
+ struct _cef_browser_host_t* self,
+ struct _cef_dev_tools_message_observer_t* observer) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+ // Verify param: observer; type: refptr_diff
+ DCHECK(observer);
+ if (!observer) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefRegistration> _retval =
+ CefBrowserHostCppToC::Get(self)->AddDevToolsMessageObserver(
+ CefDevToolsMessageObserverCToCpp::Wrap(observer));
+
+ // Return type: refptr_same
+ return CefRegistrationCppToC::Wrap(_retval);
+}
+
+void CEF_CALLBACK
+browser_host_get_navigation_entries(struct _cef_browser_host_t* self,
+ cef_navigation_entry_visitor_t* visitor,
+ int current_only) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: visitor; type: refptr_diff
+ DCHECK(visitor);
+ if (!visitor) {
+ return;
+ }
+
+ // Execute
+ CefBrowserHostCppToC::Get(self)->GetNavigationEntries(
+ CefNavigationEntryVisitorCToCpp::Wrap(visitor),
+ current_only ? true : false);
+}
+
+void CEF_CALLBACK
+browser_host_replace_misspelling(struct _cef_browser_host_t* self,
+ const cef_string_t* word) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: word; type: string_byref_const
+ DCHECK(word);
+ if (!word) {
+ return;
+ }
+
+ // Execute
+ CefBrowserHostCppToC::Get(self)->ReplaceMisspelling(CefString(word));
+}
+
+void CEF_CALLBACK
+browser_host_add_word_to_dictionary(struct _cef_browser_host_t* self,
+ const cef_string_t* word) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: word; type: string_byref_const
+ DCHECK(word);
+ if (!word) {
+ return;
+ }
+
+ // Execute
+ CefBrowserHostCppToC::Get(self)->AddWordToDictionary(CefString(word));
+}
+
+int CEF_CALLBACK
+browser_host_is_window_rendering_disabled(struct _cef_browser_host_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefBrowserHostCppToC::Get(self)->IsWindowRenderingDisabled();
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK browser_host_was_resized(struct _cef_browser_host_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefBrowserHostCppToC::Get(self)->WasResized();
+}
+
+void CEF_CALLBACK browser_host_was_hidden(struct _cef_browser_host_t* self,
+ int hidden) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefBrowserHostCppToC::Get(self)->WasHidden(hidden ? true : false);
+}
+
+void CEF_CALLBACK
+browser_host_notify_screen_info_changed(struct _cef_browser_host_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefBrowserHostCppToC::Get(self)->NotifyScreenInfoChanged();
+}
+
+void CEF_CALLBACK browser_host_invalidate(struct _cef_browser_host_t* self,
+ cef_paint_element_type_t type) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefBrowserHostCppToC::Get(self)->Invalidate(type);
+}
+
+void CEF_CALLBACK
+browser_host_send_external_begin_frame(struct _cef_browser_host_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefBrowserHostCppToC::Get(self)->SendExternalBeginFrame();
+}
+
+void CEF_CALLBACK browser_host_send_key_event(struct _cef_browser_host_t* self,
+ const cef_key_event_t* event) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: event; type: simple_byref_const
+ DCHECK(event);
+ if (!event) {
+ return;
+ }
+
+ // Translate param: event; type: simple_byref_const
+ CefKeyEvent eventVal = event ? *event : CefKeyEvent();
+
+ // Execute
+ CefBrowserHostCppToC::Get(self)->SendKeyEvent(eventVal);
+}
+
+void CEF_CALLBACK
+browser_host_send_mouse_click_event(struct _cef_browser_host_t* self,
+ const cef_mouse_event_t* event,
+ cef_mouse_button_type_t type,
+ int mouseUp,
+ int clickCount) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: event; type: simple_byref_const
+ DCHECK(event);
+ if (!event) {
+ return;
+ }
+
+ // Translate param: event; type: simple_byref_const
+ CefMouseEvent eventVal = event ? *event : CefMouseEvent();
+
+ // Execute
+ CefBrowserHostCppToC::Get(self)->SendMouseClickEvent(
+ eventVal, type, mouseUp ? true : false, clickCount);
+}
+
+void CEF_CALLBACK
+browser_host_send_mouse_move_event(struct _cef_browser_host_t* self,
+ const cef_mouse_event_t* event,
+ int mouseLeave) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: event; type: simple_byref_const
+ DCHECK(event);
+ if (!event) {
+ return;
+ }
+
+ // Translate param: event; type: simple_byref_const
+ CefMouseEvent eventVal = event ? *event : CefMouseEvent();
+
+ // Execute
+ CefBrowserHostCppToC::Get(self)->SendMouseMoveEvent(
+ eventVal, mouseLeave ? true : false);
+}
+
+void CEF_CALLBACK
+browser_host_send_mouse_wheel_event(struct _cef_browser_host_t* self,
+ const cef_mouse_event_t* event,
+ int deltaX,
+ int deltaY) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: event; type: simple_byref_const
+ DCHECK(event);
+ if (!event) {
+ return;
+ }
+
+ // Translate param: event; type: simple_byref_const
+ CefMouseEvent eventVal = event ? *event : CefMouseEvent();
+
+ // Execute
+ CefBrowserHostCppToC::Get(self)->SendMouseWheelEvent(eventVal, deltaX,
+ deltaY);
+}
+
+void CEF_CALLBACK
+browser_host_send_touch_event(struct _cef_browser_host_t* self,
+ const cef_touch_event_t* event) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: event; type: simple_byref_const
+ DCHECK(event);
+ if (!event) {
+ return;
+ }
+
+ // Translate param: event; type: simple_byref_const
+ CefTouchEvent eventVal = event ? *event : CefTouchEvent();
+
+ // Execute
+ CefBrowserHostCppToC::Get(self)->SendTouchEvent(eventVal);
+}
+
+void CEF_CALLBACK
+browser_host_send_capture_lost_event(struct _cef_browser_host_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefBrowserHostCppToC::Get(self)->SendCaptureLostEvent();
+}
+
+void CEF_CALLBACK
+browser_host_notify_move_or_resize_started(struct _cef_browser_host_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefBrowserHostCppToC::Get(self)->NotifyMoveOrResizeStarted();
+}
+
+int CEF_CALLBACK
+browser_host_get_windowless_frame_rate(struct _cef_browser_host_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefBrowserHostCppToC::Get(self)->GetWindowlessFrameRate();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK
+browser_host_set_windowless_frame_rate(struct _cef_browser_host_t* self,
+ int frame_rate) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefBrowserHostCppToC::Get(self)->SetWindowlessFrameRate(frame_rate);
+}
+
+void CEF_CALLBACK
+browser_host_ime_set_composition(struct _cef_browser_host_t* self,
+ const cef_string_t* text,
+ size_t underlinesCount,
+ cef_composition_underline_t const* underlines,
+ const cef_range_t* replacement_range,
+ const cef_range_t* selection_range) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: replacement_range; type: simple_byref_const
+ DCHECK(replacement_range);
+ if (!replacement_range) {
+ return;
+ }
+ // Verify param: selection_range; type: simple_byref_const
+ DCHECK(selection_range);
+ if (!selection_range) {
+ return;
+ }
+ // Unverified params: text, underlines
+
+ // Translate param: underlines; type: simple_vec_byref_const
+ std::vector<CefCompositionUnderline> underlinesList;
+ if (underlinesCount > 0) {
+ for (size_t i = 0; i < underlinesCount; ++i) {
+ CefCompositionUnderline underlinesVal = underlines[i];
+ underlinesList.push_back(underlinesVal);
+ }
+ }
+ // Translate param: replacement_range; type: simple_byref_const
+ CefRange replacement_rangeVal =
+ replacement_range ? *replacement_range : CefRange();
+ // Translate param: selection_range; type: simple_byref_const
+ CefRange selection_rangeVal = selection_range ? *selection_range : CefRange();
+
+ // Execute
+ CefBrowserHostCppToC::Get(self)->ImeSetComposition(
+ CefString(text), underlinesList, replacement_rangeVal,
+ selection_rangeVal);
+}
+
+void CEF_CALLBACK
+browser_host_ime_commit_text(struct _cef_browser_host_t* self,
+ const cef_string_t* text,
+ const cef_range_t* replacement_range,
+ int relative_cursor_pos) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: replacement_range; type: simple_byref_const
+ DCHECK(replacement_range);
+ if (!replacement_range) {
+ return;
+ }
+ // Unverified params: text
+
+ // Translate param: replacement_range; type: simple_byref_const
+ CefRange replacement_rangeVal =
+ replacement_range ? *replacement_range : CefRange();
+
+ // Execute
+ CefBrowserHostCppToC::Get(self)->ImeCommitText(
+ CefString(text), replacement_rangeVal, relative_cursor_pos);
+}
+
+void CEF_CALLBACK
+browser_host_ime_finish_composing_text(struct _cef_browser_host_t* self,
+ int keep_selection) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefBrowserHostCppToC::Get(self)->ImeFinishComposingText(
+ keep_selection ? true : false);
+}
+
+void CEF_CALLBACK
+browser_host_ime_cancel_composition(struct _cef_browser_host_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefBrowserHostCppToC::Get(self)->ImeCancelComposition();
+}
+
+void CEF_CALLBACK
+browser_host_drag_target_drag_enter(struct _cef_browser_host_t* self,
+ struct _cef_drag_data_t* drag_data,
+ const cef_mouse_event_t* event,
+ cef_drag_operations_mask_t allowed_ops) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: drag_data; type: refptr_same
+ DCHECK(drag_data);
+ if (!drag_data) {
+ return;
+ }
+ // Verify param: event; type: simple_byref_const
+ DCHECK(event);
+ if (!event) {
+ return;
+ }
+
+ // Translate param: event; type: simple_byref_const
+ CefMouseEvent eventVal = event ? *event : CefMouseEvent();
+
+ // Execute
+ CefBrowserHostCppToC::Get(self)->DragTargetDragEnter(
+ CefDragDataCppToC::Unwrap(drag_data), eventVal, allowed_ops);
+}
+
+void CEF_CALLBACK
+browser_host_drag_target_drag_over(struct _cef_browser_host_t* self,
+ const cef_mouse_event_t* event,
+ cef_drag_operations_mask_t allowed_ops) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: event; type: simple_byref_const
+ DCHECK(event);
+ if (!event) {
+ return;
+ }
+
+ // Translate param: event; type: simple_byref_const
+ CefMouseEvent eventVal = event ? *event : CefMouseEvent();
+
+ // Execute
+ CefBrowserHostCppToC::Get(self)->DragTargetDragOver(eventVal, allowed_ops);
+}
+
+void CEF_CALLBACK
+browser_host_drag_target_drag_leave(struct _cef_browser_host_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefBrowserHostCppToC::Get(self)->DragTargetDragLeave();
+}
+
+void CEF_CALLBACK
+browser_host_drag_target_drop(struct _cef_browser_host_t* self,
+ const cef_mouse_event_t* event) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: event; type: simple_byref_const
+ DCHECK(event);
+ if (!event) {
+ return;
+ }
+
+ // Translate param: event; type: simple_byref_const
+ CefMouseEvent eventVal = event ? *event : CefMouseEvent();
+
+ // Execute
+ CefBrowserHostCppToC::Get(self)->DragTargetDrop(eventVal);
+}
+
+void CEF_CALLBACK
+browser_host_drag_source_ended_at(struct _cef_browser_host_t* self,
+ int x,
+ int y,
+ cef_drag_operations_mask_t op) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefBrowserHostCppToC::Get(self)->DragSourceEndedAt(x, y, op);
+}
+
+void CEF_CALLBACK
+browser_host_drag_source_system_drag_ended(struct _cef_browser_host_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefBrowserHostCppToC::Get(self)->DragSourceSystemDragEnded();
+}
+
+struct _cef_navigation_entry_t* CEF_CALLBACK
+browser_host_get_visible_navigation_entry(struct _cef_browser_host_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefNavigationEntry> _retval =
+ CefBrowserHostCppToC::Get(self)->GetVisibleNavigationEntry();
+
+ // Return type: refptr_same
+ return CefNavigationEntryCppToC::Wrap(_retval);
+}
+
+void CEF_CALLBACK
+browser_host_set_accessibility_state(struct _cef_browser_host_t* self,
+ cef_state_t accessibility_state) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefBrowserHostCppToC::Get(self)->SetAccessibilityState(accessibility_state);
+}
+
+void CEF_CALLBACK
+browser_host_set_auto_resize_enabled(struct _cef_browser_host_t* self,
+ int enabled,
+ const cef_size_t* min_size,
+ const cef_size_t* max_size) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: min_size; type: simple_byref_const
+ DCHECK(min_size);
+ if (!min_size) {
+ return;
+ }
+ // Verify param: max_size; type: simple_byref_const
+ DCHECK(max_size);
+ if (!max_size) {
+ return;
+ }
+
+ // Translate param: min_size; type: simple_byref_const
+ CefSize min_sizeVal = min_size ? *min_size : CefSize();
+ // Translate param: max_size; type: simple_byref_const
+ CefSize max_sizeVal = max_size ? *max_size : CefSize();
+
+ // Execute
+ CefBrowserHostCppToC::Get(self)->SetAutoResizeEnabled(
+ enabled ? true : false, min_sizeVal, max_sizeVal);
+}
+
+struct _cef_extension_t* CEF_CALLBACK
+browser_host_get_extension(struct _cef_browser_host_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefExtension> _retval =
+ CefBrowserHostCppToC::Get(self)->GetExtension();
+
+ // Return type: refptr_same
+ return CefExtensionCppToC::Wrap(_retval);
+}
+
+int CEF_CALLBACK
+browser_host_is_background_host(struct _cef_browser_host_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefBrowserHostCppToC::Get(self)->IsBackgroundHost();
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK browser_host_set_audio_muted(struct _cef_browser_host_t* self,
+ int mute) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefBrowserHostCppToC::Get(self)->SetAudioMuted(mute ? true : false);
+}
+
+int CEF_CALLBACK browser_host_is_audio_muted(struct _cef_browser_host_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefBrowserHostCppToC::Get(self)->IsAudioMuted();
+
+ // Return type: bool
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefBrowserHostCppToC::CefBrowserHostCppToC() {
+ GetStruct()->get_browser = browser_host_get_browser;
+ GetStruct()->close_browser = browser_host_close_browser;
+ GetStruct()->try_close_browser = browser_host_try_close_browser;
+ GetStruct()->set_focus = browser_host_set_focus;
+ GetStruct()->get_window_handle = browser_host_get_window_handle;
+ GetStruct()->get_opener_window_handle = browser_host_get_opener_window_handle;
+ GetStruct()->has_view = browser_host_has_view;
+ GetStruct()->get_client = browser_host_get_client;
+ GetStruct()->get_request_context = browser_host_get_request_context;
+ GetStruct()->get_zoom_level = browser_host_get_zoom_level;
+ GetStruct()->set_zoom_level = browser_host_set_zoom_level;
+ GetStruct()->run_file_dialog = browser_host_run_file_dialog;
+ GetStruct()->start_download = browser_host_start_download;
+ GetStruct()->download_image = browser_host_download_image;
+ GetStruct()->print = browser_host_print;
+ GetStruct()->print_to_pdf = browser_host_print_to_pdf;
+ GetStruct()->find = browser_host_find;
+ GetStruct()->stop_finding = browser_host_stop_finding;
+ GetStruct()->show_dev_tools = browser_host_show_dev_tools;
+ GetStruct()->close_dev_tools = browser_host_close_dev_tools;
+ GetStruct()->has_dev_tools = browser_host_has_dev_tools;
+ GetStruct()->send_dev_tools_message = browser_host_send_dev_tools_message;
+ GetStruct()->execute_dev_tools_method = browser_host_execute_dev_tools_method;
+ GetStruct()->add_dev_tools_message_observer =
+ browser_host_add_dev_tools_message_observer;
+ GetStruct()->get_navigation_entries = browser_host_get_navigation_entries;
+ GetStruct()->replace_misspelling = browser_host_replace_misspelling;
+ GetStruct()->add_word_to_dictionary = browser_host_add_word_to_dictionary;
+ GetStruct()->is_window_rendering_disabled =
+ browser_host_is_window_rendering_disabled;
+ GetStruct()->was_resized = browser_host_was_resized;
+ GetStruct()->was_hidden = browser_host_was_hidden;
+ GetStruct()->notify_screen_info_changed =
+ browser_host_notify_screen_info_changed;
+ GetStruct()->invalidate = browser_host_invalidate;
+ GetStruct()->send_external_begin_frame =
+ browser_host_send_external_begin_frame;
+ GetStruct()->send_key_event = browser_host_send_key_event;
+ GetStruct()->send_mouse_click_event = browser_host_send_mouse_click_event;
+ GetStruct()->send_mouse_move_event = browser_host_send_mouse_move_event;
+ GetStruct()->send_mouse_wheel_event = browser_host_send_mouse_wheel_event;
+ GetStruct()->send_touch_event = browser_host_send_touch_event;
+ GetStruct()->send_capture_lost_event = browser_host_send_capture_lost_event;
+ GetStruct()->notify_move_or_resize_started =
+ browser_host_notify_move_or_resize_started;
+ GetStruct()->get_windowless_frame_rate =
+ browser_host_get_windowless_frame_rate;
+ GetStruct()->set_windowless_frame_rate =
+ browser_host_set_windowless_frame_rate;
+ GetStruct()->ime_set_composition = browser_host_ime_set_composition;
+ GetStruct()->ime_commit_text = browser_host_ime_commit_text;
+ GetStruct()->ime_finish_composing_text =
+ browser_host_ime_finish_composing_text;
+ GetStruct()->ime_cancel_composition = browser_host_ime_cancel_composition;
+ GetStruct()->drag_target_drag_enter = browser_host_drag_target_drag_enter;
+ GetStruct()->drag_target_drag_over = browser_host_drag_target_drag_over;
+ GetStruct()->drag_target_drag_leave = browser_host_drag_target_drag_leave;
+ GetStruct()->drag_target_drop = browser_host_drag_target_drop;
+ GetStruct()->drag_source_ended_at = browser_host_drag_source_ended_at;
+ GetStruct()->drag_source_system_drag_ended =
+ browser_host_drag_source_system_drag_ended;
+ GetStruct()->get_visible_navigation_entry =
+ browser_host_get_visible_navigation_entry;
+ GetStruct()->set_accessibility_state = browser_host_set_accessibility_state;
+ GetStruct()->set_auto_resize_enabled = browser_host_set_auto_resize_enabled;
+ GetStruct()->get_extension = browser_host_get_extension;
+ GetStruct()->is_background_host = browser_host_is_background_host;
+ GetStruct()->set_audio_muted = browser_host_set_audio_muted;
+ GetStruct()->is_audio_muted = browser_host_is_audio_muted;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefBrowserHostCppToC::~CefBrowserHostCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefBrowserHost>
+CefCppToCRefCounted<CefBrowserHostCppToC, CefBrowserHost, cef_browser_host_t>::
+ UnwrapDerived(CefWrapperType type, cef_browser_host_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefBrowserHostCppToC,
+ CefBrowserHost,
+ cef_browser_host_t>::kWrapperType =
+ WT_BROWSER_HOST;
diff --git a/libcef_dll/cpptoc/browser_host_cpptoc.h b/libcef_dll/cpptoc/browser_host_cpptoc.h
new file mode 100644
index 00000000..2f88bb33
--- /dev/null
+++ b/libcef_dll/cpptoc/browser_host_cpptoc.h
@@ -0,0 +1,39 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=e51f496e40bd2b3b9573d2ca084e578bb1df1407$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_BROWSER_HOST_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_BROWSER_HOST_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_browser_capi.h"
+#include "include/capi/cef_client_capi.h"
+#include "include/cef_browser.h"
+#include "include/cef_client.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefBrowserHostCppToC : public CefCppToCRefCounted<CefBrowserHostCppToC,
+ CefBrowserHost,
+ cef_browser_host_t> {
+ public:
+ CefBrowserHostCppToC();
+ virtual ~CefBrowserHostCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_BROWSER_HOST_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/browser_process_handler_cpptoc.cc b/libcef_dll/cpptoc/browser_process_handler_cpptoc.cc
new file mode 100644
index 00000000..3cc25a61
--- /dev/null
+++ b/libcef_dll/cpptoc/browser_process_handler_cpptoc.cc
@@ -0,0 +1,150 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=a5446c4b823971a827d933afb128f94dddacd970$
+//
+
+#include "libcef_dll/cpptoc/browser_process_handler_cpptoc.h"
+#include "libcef_dll/cpptoc/client_cpptoc.h"
+#include "libcef_dll/ctocpp/command_line_ctocpp.h"
+#include "libcef_dll/ctocpp/preference_registrar_ctocpp.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK browser_process_handler_on_register_custom_preferences(
+ struct _cef_browser_process_handler_t* self,
+ cef_preferences_type_t type,
+ struct _cef_preference_registrar_t* registrar) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: registrar; type: rawptr_diff
+ DCHECK(registrar);
+ if (!registrar) {
+ return;
+ }
+
+ // Translate param: registrar; type: rawptr_diff
+ CefOwnPtr<CefPreferenceRegistrar> registrarPtr(
+ CefPreferenceRegistrarCToCpp::Wrap(registrar));
+
+ // Execute
+ CefBrowserProcessHandlerCppToC::Get(self)->OnRegisterCustomPreferences(
+ type, registrarPtr.get());
+}
+
+void CEF_CALLBACK browser_process_handler_on_context_initialized(
+ struct _cef_browser_process_handler_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefBrowserProcessHandlerCppToC::Get(self)->OnContextInitialized();
+}
+
+void CEF_CALLBACK browser_process_handler_on_before_child_process_launch(
+ struct _cef_browser_process_handler_t* self,
+ struct _cef_command_line_t* command_line) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: command_line; type: refptr_diff
+ DCHECK(command_line);
+ if (!command_line) {
+ return;
+ }
+
+ // Execute
+ CefBrowserProcessHandlerCppToC::Get(self)->OnBeforeChildProcessLaunch(
+ CefCommandLineCToCpp::Wrap(command_line));
+}
+
+void CEF_CALLBACK browser_process_handler_on_schedule_message_pump_work(
+ struct _cef_browser_process_handler_t* self,
+ int64 delay_ms) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefBrowserProcessHandlerCppToC::Get(self)->OnScheduleMessagePumpWork(
+ delay_ms);
+}
+
+struct _cef_client_t* CEF_CALLBACK browser_process_handler_get_default_client(
+ struct _cef_browser_process_handler_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefClient> _retval =
+ CefBrowserProcessHandlerCppToC::Get(self)->GetDefaultClient();
+
+ // Return type: refptr_same
+ return CefClientCppToC::Wrap(_retval);
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefBrowserProcessHandlerCppToC::CefBrowserProcessHandlerCppToC() {
+ GetStruct()->on_register_custom_preferences =
+ browser_process_handler_on_register_custom_preferences;
+ GetStruct()->on_context_initialized =
+ browser_process_handler_on_context_initialized;
+ GetStruct()->on_before_child_process_launch =
+ browser_process_handler_on_before_child_process_launch;
+ GetStruct()->on_schedule_message_pump_work =
+ browser_process_handler_on_schedule_message_pump_work;
+ GetStruct()->get_default_client = browser_process_handler_get_default_client;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefBrowserProcessHandlerCppToC::~CefBrowserProcessHandlerCppToC() {}
+
+template <>
+CefRefPtr<CefBrowserProcessHandler> CefCppToCRefCounted<
+ CefBrowserProcessHandlerCppToC,
+ CefBrowserProcessHandler,
+ cef_browser_process_handler_t>::UnwrapDerived(CefWrapperType type,
+ cef_browser_process_handler_t*
+ s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCppToCRefCounted<CefBrowserProcessHandlerCppToC,
+ CefBrowserProcessHandler,
+ cef_browser_process_handler_t>::kWrapperType =
+ WT_BROWSER_PROCESS_HANDLER;
diff --git a/libcef_dll/cpptoc/browser_process_handler_cpptoc.h b/libcef_dll/cpptoc/browser_process_handler_cpptoc.h
new file mode 100644
index 00000000..19b902d5
--- /dev/null
+++ b/libcef_dll/cpptoc/browser_process_handler_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=508373dbbfcb411f218ad9688d56b49380d8ca75$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_BROWSER_PROCESS_HANDLER_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_BROWSER_PROCESS_HANDLER_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_browser_process_handler_capi.h"
+#include "include/cef_browser_process_handler.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefBrowserProcessHandlerCppToC
+ : public CefCppToCRefCounted<CefBrowserProcessHandlerCppToC,
+ CefBrowserProcessHandler,
+ cef_browser_process_handler_t> {
+ public:
+ CefBrowserProcessHandlerCppToC();
+ virtual ~CefBrowserProcessHandlerCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_BROWSER_PROCESS_HANDLER_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/callback_cpptoc.cc b/libcef_dll/cpptoc/callback_cpptoc.cc
new file mode 100644
index 00000000..68e3f31c
--- /dev/null
+++ b/libcef_dll/cpptoc/callback_cpptoc.cc
@@ -0,0 +1,76 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=5cfe318d106b21ec761956734b0868ccb083620a$
+//
+
+#include "libcef_dll/cpptoc/callback_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK callback_cont(struct _cef_callback_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefCallbackCppToC::Get(self)->Continue();
+}
+
+void CEF_CALLBACK callback_cancel(struct _cef_callback_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefCallbackCppToC::Get(self)->Cancel();
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefCallbackCppToC::CefCallbackCppToC() {
+ GetStruct()->cont = callback_cont;
+ GetStruct()->cancel = callback_cancel;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefCallbackCppToC::~CefCallbackCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefCallback>
+CefCppToCRefCounted<CefCallbackCppToC, CefCallback, cef_callback_t>::
+ UnwrapDerived(CefWrapperType type, cef_callback_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefCallbackCppToC,
+ CefCallback,
+ cef_callback_t>::kWrapperType = WT_CALLBACK;
diff --git a/libcef_dll/cpptoc/callback_cpptoc.h b/libcef_dll/cpptoc/callback_cpptoc.h
new file mode 100644
index 00000000..611c202b
--- /dev/null
+++ b/libcef_dll/cpptoc/callback_cpptoc.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=f0c92901c6462ad03d3c95c0ba92129784c808e1$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_CALLBACK_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_CALLBACK_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_callback_capi.h"
+#include "include/cef_callback.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefCallbackCppToC : public CefCppToCRefCounted<CefCallbackCppToC,
+ CefCallback,
+ cef_callback_t> {
+ public:
+ CefCallbackCppToC();
+ virtual ~CefCallbackCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_CALLBACK_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/client_cpptoc.cc b/libcef_dll/cpptoc/client_cpptoc.cc
new file mode 100644
index 00000000..bcdf222c
--- /dev/null
+++ b/libcef_dll/cpptoc/client_cpptoc.cc
@@ -0,0 +1,426 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=8eec741d5a0ac7aec671b0e1f3a6dc502f94fa44$
+//
+
+#include "libcef_dll/cpptoc/client_cpptoc.h"
+#include "libcef_dll/cpptoc/audio_handler_cpptoc.h"
+#include "libcef_dll/cpptoc/command_handler_cpptoc.h"
+#include "libcef_dll/cpptoc/context_menu_handler_cpptoc.h"
+#include "libcef_dll/cpptoc/dialog_handler_cpptoc.h"
+#include "libcef_dll/cpptoc/display_handler_cpptoc.h"
+#include "libcef_dll/cpptoc/download_handler_cpptoc.h"
+#include "libcef_dll/cpptoc/drag_handler_cpptoc.h"
+#include "libcef_dll/cpptoc/find_handler_cpptoc.h"
+#include "libcef_dll/cpptoc/focus_handler_cpptoc.h"
+#include "libcef_dll/cpptoc/frame_handler_cpptoc.h"
+#include "libcef_dll/cpptoc/jsdialog_handler_cpptoc.h"
+#include "libcef_dll/cpptoc/keyboard_handler_cpptoc.h"
+#include "libcef_dll/cpptoc/life_span_handler_cpptoc.h"
+#include "libcef_dll/cpptoc/load_handler_cpptoc.h"
+#include "libcef_dll/cpptoc/permission_handler_cpptoc.h"
+#include "libcef_dll/cpptoc/print_handler_cpptoc.h"
+#include "libcef_dll/cpptoc/render_handler_cpptoc.h"
+#include "libcef_dll/cpptoc/request_handler_cpptoc.h"
+#include "libcef_dll/ctocpp/browser_ctocpp.h"
+#include "libcef_dll/ctocpp/frame_ctocpp.h"
+#include "libcef_dll/ctocpp/process_message_ctocpp.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+cef_audio_handler_t* CEF_CALLBACK
+client_get_audio_handler(struct _cef_client_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefAudioHandler> _retval =
+ CefClientCppToC::Get(self)->GetAudioHandler();
+
+ // Return type: refptr_same
+ return CefAudioHandlerCppToC::Wrap(_retval);
+}
+
+struct _cef_command_handler_t* CEF_CALLBACK
+client_get_command_handler(struct _cef_client_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefCommandHandler> _retval =
+ CefClientCppToC::Get(self)->GetCommandHandler();
+
+ // Return type: refptr_same
+ return CefCommandHandlerCppToC::Wrap(_retval);
+}
+
+struct _cef_context_menu_handler_t* CEF_CALLBACK
+client_get_context_menu_handler(struct _cef_client_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefContextMenuHandler> _retval =
+ CefClientCppToC::Get(self)->GetContextMenuHandler();
+
+ // Return type: refptr_same
+ return CefContextMenuHandlerCppToC::Wrap(_retval);
+}
+
+struct _cef_dialog_handler_t* CEF_CALLBACK
+client_get_dialog_handler(struct _cef_client_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefDialogHandler> _retval =
+ CefClientCppToC::Get(self)->GetDialogHandler();
+
+ // Return type: refptr_same
+ return CefDialogHandlerCppToC::Wrap(_retval);
+}
+
+struct _cef_display_handler_t* CEF_CALLBACK
+client_get_display_handler(struct _cef_client_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefDisplayHandler> _retval =
+ CefClientCppToC::Get(self)->GetDisplayHandler();
+
+ // Return type: refptr_same
+ return CefDisplayHandlerCppToC::Wrap(_retval);
+}
+
+struct _cef_download_handler_t* CEF_CALLBACK
+client_get_download_handler(struct _cef_client_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefDownloadHandler> _retval =
+ CefClientCppToC::Get(self)->GetDownloadHandler();
+
+ // Return type: refptr_same
+ return CefDownloadHandlerCppToC::Wrap(_retval);
+}
+
+struct _cef_drag_handler_t* CEF_CALLBACK
+client_get_drag_handler(struct _cef_client_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefDragHandler> _retval =
+ CefClientCppToC::Get(self)->GetDragHandler();
+
+ // Return type: refptr_same
+ return CefDragHandlerCppToC::Wrap(_retval);
+}
+
+struct _cef_find_handler_t* CEF_CALLBACK
+client_get_find_handler(struct _cef_client_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefFindHandler> _retval =
+ CefClientCppToC::Get(self)->GetFindHandler();
+
+ // Return type: refptr_same
+ return CefFindHandlerCppToC::Wrap(_retval);
+}
+
+struct _cef_focus_handler_t* CEF_CALLBACK
+client_get_focus_handler(struct _cef_client_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefFocusHandler> _retval =
+ CefClientCppToC::Get(self)->GetFocusHandler();
+
+ // Return type: refptr_same
+ return CefFocusHandlerCppToC::Wrap(_retval);
+}
+
+struct _cef_frame_handler_t* CEF_CALLBACK
+client_get_frame_handler(struct _cef_client_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefFrameHandler> _retval =
+ CefClientCppToC::Get(self)->GetFrameHandler();
+
+ // Return type: refptr_same
+ return CefFrameHandlerCppToC::Wrap(_retval);
+}
+
+struct _cef_permission_handler_t* CEF_CALLBACK
+client_get_permission_handler(struct _cef_client_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefPermissionHandler> _retval =
+ CefClientCppToC::Get(self)->GetPermissionHandler();
+
+ // Return type: refptr_same
+ return CefPermissionHandlerCppToC::Wrap(_retval);
+}
+
+struct _cef_jsdialog_handler_t* CEF_CALLBACK
+client_get_jsdialog_handler(struct _cef_client_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefJSDialogHandler> _retval =
+ CefClientCppToC::Get(self)->GetJSDialogHandler();
+
+ // Return type: refptr_same
+ return CefJSDialogHandlerCppToC::Wrap(_retval);
+}
+
+struct _cef_keyboard_handler_t* CEF_CALLBACK
+client_get_keyboard_handler(struct _cef_client_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefKeyboardHandler> _retval =
+ CefClientCppToC::Get(self)->GetKeyboardHandler();
+
+ // Return type: refptr_same
+ return CefKeyboardHandlerCppToC::Wrap(_retval);
+}
+
+struct _cef_life_span_handler_t* CEF_CALLBACK
+client_get_life_span_handler(struct _cef_client_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefLifeSpanHandler> _retval =
+ CefClientCppToC::Get(self)->GetLifeSpanHandler();
+
+ // Return type: refptr_same
+ return CefLifeSpanHandlerCppToC::Wrap(_retval);
+}
+
+struct _cef_load_handler_t* CEF_CALLBACK
+client_get_load_handler(struct _cef_client_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefLoadHandler> _retval =
+ CefClientCppToC::Get(self)->GetLoadHandler();
+
+ // Return type: refptr_same
+ return CefLoadHandlerCppToC::Wrap(_retval);
+}
+
+struct _cef_print_handler_t* CEF_CALLBACK
+client_get_print_handler(struct _cef_client_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefPrintHandler> _retval =
+ CefClientCppToC::Get(self)->GetPrintHandler();
+
+ // Return type: refptr_same
+ return CefPrintHandlerCppToC::Wrap(_retval);
+}
+
+struct _cef_render_handler_t* CEF_CALLBACK
+client_get_render_handler(struct _cef_client_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefRenderHandler> _retval =
+ CefClientCppToC::Get(self)->GetRenderHandler();
+
+ // Return type: refptr_same
+ return CefRenderHandlerCppToC::Wrap(_retval);
+}
+
+struct _cef_request_handler_t* CEF_CALLBACK
+client_get_request_handler(struct _cef_client_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefRequestHandler> _retval =
+ CefClientCppToC::Get(self)->GetRequestHandler();
+
+ // Return type: refptr_same
+ return CefRequestHandlerCppToC::Wrap(_retval);
+}
+
+int CEF_CALLBACK
+client_on_process_message_received(struct _cef_client_t* self,
+ cef_browser_t* browser,
+ struct _cef_frame_t* frame,
+ cef_process_id_t source_process,
+ struct _cef_process_message_t* message) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return 0;
+ }
+ // Verify param: frame; type: refptr_diff
+ DCHECK(frame);
+ if (!frame) {
+ return 0;
+ }
+ // Verify param: message; type: refptr_diff
+ DCHECK(message);
+ if (!message) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefClientCppToC::Get(self)->OnProcessMessageReceived(
+ CefBrowserCToCpp::Wrap(browser), CefFrameCToCpp::Wrap(frame),
+ source_process, CefProcessMessageCToCpp::Wrap(message));
+
+ // Return type: bool
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefClientCppToC::CefClientCppToC() {
+ GetStruct()->get_audio_handler = client_get_audio_handler;
+ GetStruct()->get_command_handler = client_get_command_handler;
+ GetStruct()->get_context_menu_handler = client_get_context_menu_handler;
+ GetStruct()->get_dialog_handler = client_get_dialog_handler;
+ GetStruct()->get_display_handler = client_get_display_handler;
+ GetStruct()->get_download_handler = client_get_download_handler;
+ GetStruct()->get_drag_handler = client_get_drag_handler;
+ GetStruct()->get_find_handler = client_get_find_handler;
+ GetStruct()->get_focus_handler = client_get_focus_handler;
+ GetStruct()->get_frame_handler = client_get_frame_handler;
+ GetStruct()->get_permission_handler = client_get_permission_handler;
+ GetStruct()->get_jsdialog_handler = client_get_jsdialog_handler;
+ GetStruct()->get_keyboard_handler = client_get_keyboard_handler;
+ GetStruct()->get_life_span_handler = client_get_life_span_handler;
+ GetStruct()->get_load_handler = client_get_load_handler;
+ GetStruct()->get_print_handler = client_get_print_handler;
+ GetStruct()->get_render_handler = client_get_render_handler;
+ GetStruct()->get_request_handler = client_get_request_handler;
+ GetStruct()->on_process_message_received = client_on_process_message_received;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefClientCppToC::~CefClientCppToC() {}
+
+template <>
+CefRefPtr<CefClient>
+CefCppToCRefCounted<CefClientCppToC, CefClient, cef_client_t>::UnwrapDerived(
+ CefWrapperType type,
+ cef_client_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefClientCppToC, CefClient, cef_client_t>::
+ kWrapperType = WT_CLIENT;
diff --git a/libcef_dll/cpptoc/client_cpptoc.h b/libcef_dll/cpptoc/client_cpptoc.h
new file mode 100644
index 00000000..3898b87e
--- /dev/null
+++ b/libcef_dll/cpptoc/client_cpptoc.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=6dd8a3977d8a7d75da7399a9c15a160afbfcf744$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_CLIENT_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_CLIENT_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_client_capi.h"
+#include "include/cef_client.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefClientCppToC
+ : public CefCppToCRefCounted<CefClientCppToC, CefClient, cef_client_t> {
+ public:
+ CefClientCppToC();
+ virtual ~CefClientCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_CLIENT_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/command_handler_cpptoc.cc b/libcef_dll/cpptoc/command_handler_cpptoc.cc
new file mode 100644
index 00000000..c1fdbb20
--- /dev/null
+++ b/libcef_dll/cpptoc/command_handler_cpptoc.cc
@@ -0,0 +1,78 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=bf815bb565ccf2570c6f6b881009fe7df20805f0$
+//
+
+#include "libcef_dll/cpptoc/command_handler_cpptoc.h"
+#include "libcef_dll/ctocpp/browser_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK
+command_handler_on_chrome_command(struct _cef_command_handler_t* self,
+ cef_browser_t* browser,
+ int command_id,
+ cef_window_open_disposition_t disposition) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefCommandHandlerCppToC::Get(self)->OnChromeCommand(
+ CefBrowserCToCpp::Wrap(browser), command_id, disposition);
+
+ // Return type: bool
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefCommandHandlerCppToC::CefCommandHandlerCppToC() {
+ GetStruct()->on_chrome_command = command_handler_on_chrome_command;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefCommandHandlerCppToC::~CefCommandHandlerCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefCommandHandler> CefCppToCRefCounted<
+ CefCommandHandlerCppToC,
+ CefCommandHandler,
+ cef_command_handler_t>::UnwrapDerived(CefWrapperType type,
+ cef_command_handler_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefCommandHandlerCppToC,
+ CefCommandHandler,
+ cef_command_handler_t>::kWrapperType =
+ WT_COMMAND_HANDLER;
diff --git a/libcef_dll/cpptoc/command_handler_cpptoc.h b/libcef_dll/cpptoc/command_handler_cpptoc.h
new file mode 100644
index 00000000..3c1a73e0
--- /dev/null
+++ b/libcef_dll/cpptoc/command_handler_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=beb365f3b4d93d967612c9d8505240d7b727fd08$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_COMMAND_HANDLER_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_COMMAND_HANDLER_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_command_handler_capi.h"
+#include "include/cef_command_handler.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefCommandHandlerCppToC
+ : public CefCppToCRefCounted<CefCommandHandlerCppToC,
+ CefCommandHandler,
+ cef_command_handler_t> {
+ public:
+ CefCommandHandlerCppToC();
+ virtual ~CefCommandHandlerCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_COMMAND_HANDLER_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/command_line_cpptoc.cc b/libcef_dll/cpptoc/command_line_cpptoc.cc
new file mode 100644
index 00000000..f02f8905
--- /dev/null
+++ b/libcef_dll/cpptoc/command_line_cpptoc.cc
@@ -0,0 +1,465 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=3e70ff63428c3bce590fe137945a2085b432e9ad$
+//
+
+#include "libcef_dll/cpptoc/command_line_cpptoc.h"
+#include "libcef_dll/transfer_util.h"
+
+// GLOBAL FUNCTIONS - Body may be edited by hand.
+
+CEF_EXPORT cef_command_line_t* cef_command_line_create() {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ CefRefPtr<CefCommandLine> _retval = CefCommandLine::CreateCommandLine();
+
+ // Return type: refptr_same
+ return CefCommandLineCppToC::Wrap(_retval);
+}
+
+CEF_EXPORT cef_command_line_t* cef_command_line_get_global() {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ CefRefPtr<CefCommandLine> _retval = CefCommandLine::GetGlobalCommandLine();
+
+ // Return type: refptr_same
+ return CefCommandLineCppToC::Wrap(_retval);
+}
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK command_line_is_valid(struct _cef_command_line_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefCommandLineCppToC::Get(self)->IsValid();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK command_line_is_read_only(struct _cef_command_line_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefCommandLineCppToC::Get(self)->IsReadOnly();
+
+ // Return type: bool
+ return _retval;
+}
+
+struct _cef_command_line_t* CEF_CALLBACK
+command_line_copy(struct _cef_command_line_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefCommandLine> _retval = CefCommandLineCppToC::Get(self)->Copy();
+
+ // Return type: refptr_same
+ return CefCommandLineCppToC::Wrap(_retval);
+}
+
+void CEF_CALLBACK command_line_init_from_argv(struct _cef_command_line_t* self,
+ int argc,
+ const char* const* argv) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: argv; type: simple_byaddr
+ DCHECK(argv);
+ if (!argv) {
+ return;
+ }
+
+ // Execute
+ CefCommandLineCppToC::Get(self)->InitFromArgv(argc, argv);
+}
+
+void CEF_CALLBACK
+command_line_init_from_string(struct _cef_command_line_t* self,
+ const cef_string_t* command_line) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: command_line; type: string_byref_const
+ DCHECK(command_line);
+ if (!command_line) {
+ return;
+ }
+
+ // Execute
+ CefCommandLineCppToC::Get(self)->InitFromString(CefString(command_line));
+}
+
+void CEF_CALLBACK command_line_reset(struct _cef_command_line_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefCommandLineCppToC::Get(self)->Reset();
+}
+
+void CEF_CALLBACK command_line_get_argv(struct _cef_command_line_t* self,
+ cef_string_list_t argv) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: argv; type: string_vec_byref
+ DCHECK(argv);
+ if (!argv) {
+ return;
+ }
+
+ // Translate param: argv; type: string_vec_byref
+ std::vector<CefString> argvList;
+ transfer_string_list_contents(argv, argvList);
+
+ // Execute
+ CefCommandLineCppToC::Get(self)->GetArgv(argvList);
+
+ // Restore param: argv; type: string_vec_byref
+ cef_string_list_clear(argv);
+ transfer_string_list_contents(argvList, argv);
+}
+
+cef_string_userfree_t CEF_CALLBACK
+command_line_get_command_line_string(struct _cef_command_line_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefCommandLineCppToC::Get(self)->GetCommandLineString();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_string_userfree_t CEF_CALLBACK
+command_line_get_program(struct _cef_command_line_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefCommandLineCppToC::Get(self)->GetProgram();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+void CEF_CALLBACK command_line_set_program(struct _cef_command_line_t* self,
+ const cef_string_t* program) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: program; type: string_byref_const
+ DCHECK(program);
+ if (!program) {
+ return;
+ }
+
+ // Execute
+ CefCommandLineCppToC::Get(self)->SetProgram(CefString(program));
+}
+
+int CEF_CALLBACK command_line_has_switches(struct _cef_command_line_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefCommandLineCppToC::Get(self)->HasSwitches();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK command_line_has_switch(struct _cef_command_line_t* self,
+ const cef_string_t* name) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: name; type: string_byref_const
+ DCHECK(name);
+ if (!name) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefCommandLineCppToC::Get(self)->HasSwitch(CefString(name));
+
+ // Return type: bool
+ return _retval;
+}
+
+cef_string_userfree_t CEF_CALLBACK
+command_line_get_switch_value(struct _cef_command_line_t* self,
+ const cef_string_t* name) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+ // Verify param: name; type: string_byref_const
+ DCHECK(name);
+ if (!name) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval =
+ CefCommandLineCppToC::Get(self)->GetSwitchValue(CefString(name));
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+void CEF_CALLBACK command_line_get_switches(struct _cef_command_line_t* self,
+ cef_string_map_t switches) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: switches; type: string_map_single_byref
+ DCHECK(switches);
+ if (!switches) {
+ return;
+ }
+
+ // Translate param: switches; type: string_map_single_byref
+ std::map<CefString, CefString> switchesMap;
+ transfer_string_map_contents(switches, switchesMap);
+
+ // Execute
+ CefCommandLineCppToC::Get(self)->GetSwitches(switchesMap);
+
+ // Restore param: switches; type: string_map_single_byref
+ cef_string_map_clear(switches);
+ transfer_string_map_contents(switchesMap, switches);
+}
+
+void CEF_CALLBACK command_line_append_switch(struct _cef_command_line_t* self,
+ const cef_string_t* name) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: name; type: string_byref_const
+ DCHECK(name);
+ if (!name) {
+ return;
+ }
+
+ // Execute
+ CefCommandLineCppToC::Get(self)->AppendSwitch(CefString(name));
+}
+
+void CEF_CALLBACK
+command_line_append_switch_with_value(struct _cef_command_line_t* self,
+ const cef_string_t* name,
+ const cef_string_t* value) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: name; type: string_byref_const
+ DCHECK(name);
+ if (!name) {
+ return;
+ }
+ // Verify param: value; type: string_byref_const
+ DCHECK(value);
+ if (!value) {
+ return;
+ }
+
+ // Execute
+ CefCommandLineCppToC::Get(self)->AppendSwitchWithValue(CefString(name),
+ CefString(value));
+}
+
+int CEF_CALLBACK command_line_has_arguments(struct _cef_command_line_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefCommandLineCppToC::Get(self)->HasArguments();
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK command_line_get_arguments(struct _cef_command_line_t* self,
+ cef_string_list_t arguments) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: arguments; type: string_vec_byref
+ DCHECK(arguments);
+ if (!arguments) {
+ return;
+ }
+
+ // Translate param: arguments; type: string_vec_byref
+ std::vector<CefString> argumentsList;
+ transfer_string_list_contents(arguments, argumentsList);
+
+ // Execute
+ CefCommandLineCppToC::Get(self)->GetArguments(argumentsList);
+
+ // Restore param: arguments; type: string_vec_byref
+ cef_string_list_clear(arguments);
+ transfer_string_list_contents(argumentsList, arguments);
+}
+
+void CEF_CALLBACK command_line_append_argument(struct _cef_command_line_t* self,
+ const cef_string_t* argument) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: argument; type: string_byref_const
+ DCHECK(argument);
+ if (!argument) {
+ return;
+ }
+
+ // Execute
+ CefCommandLineCppToC::Get(self)->AppendArgument(CefString(argument));
+}
+
+void CEF_CALLBACK command_line_prepend_wrapper(struct _cef_command_line_t* self,
+ const cef_string_t* wrapper) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: wrapper; type: string_byref_const
+ DCHECK(wrapper);
+ if (!wrapper) {
+ return;
+ }
+
+ // Execute
+ CefCommandLineCppToC::Get(self)->PrependWrapper(CefString(wrapper));
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefCommandLineCppToC::CefCommandLineCppToC() {
+ GetStruct()->is_valid = command_line_is_valid;
+ GetStruct()->is_read_only = command_line_is_read_only;
+ GetStruct()->copy = command_line_copy;
+ GetStruct()->init_from_argv = command_line_init_from_argv;
+ GetStruct()->init_from_string = command_line_init_from_string;
+ GetStruct()->reset = command_line_reset;
+ GetStruct()->get_argv = command_line_get_argv;
+ GetStruct()->get_command_line_string = command_line_get_command_line_string;
+ GetStruct()->get_program = command_line_get_program;
+ GetStruct()->set_program = command_line_set_program;
+ GetStruct()->has_switches = command_line_has_switches;
+ GetStruct()->has_switch = command_line_has_switch;
+ GetStruct()->get_switch_value = command_line_get_switch_value;
+ GetStruct()->get_switches = command_line_get_switches;
+ GetStruct()->append_switch = command_line_append_switch;
+ GetStruct()->append_switch_with_value = command_line_append_switch_with_value;
+ GetStruct()->has_arguments = command_line_has_arguments;
+ GetStruct()->get_arguments = command_line_get_arguments;
+ GetStruct()->append_argument = command_line_append_argument;
+ GetStruct()->prepend_wrapper = command_line_prepend_wrapper;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefCommandLineCppToC::~CefCommandLineCppToC() {}
+
+template <>
+CefRefPtr<CefCommandLine>
+CefCppToCRefCounted<CefCommandLineCppToC, CefCommandLine, cef_command_line_t>::
+ UnwrapDerived(CefWrapperType type, cef_command_line_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefCommandLineCppToC,
+ CefCommandLine,
+ cef_command_line_t>::kWrapperType =
+ WT_COMMAND_LINE;
diff --git a/libcef_dll/cpptoc/command_line_cpptoc.h b/libcef_dll/cpptoc/command_line_cpptoc.h
new file mode 100644
index 00000000..45eb004c
--- /dev/null
+++ b/libcef_dll/cpptoc/command_line_cpptoc.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=f8af58d9e62d25a46593ccebc487734730f6a1a3$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_COMMAND_LINE_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_COMMAND_LINE_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_command_line_capi.h"
+#include "include/cef_command_line.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefCommandLineCppToC : public CefCppToCRefCounted<CefCommandLineCppToC,
+ CefCommandLine,
+ cef_command_line_t> {
+ public:
+ CefCommandLineCppToC();
+ virtual ~CefCommandLineCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_COMMAND_LINE_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/completion_callback_cpptoc.cc b/libcef_dll/cpptoc/completion_callback_cpptoc.cc
new file mode 100644
index 00000000..7e22c880
--- /dev/null
+++ b/libcef_dll/cpptoc/completion_callback_cpptoc.cc
@@ -0,0 +1,65 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=71f2ac1fe5be9a4783d35211352a92b19f1a84c0$
+//
+
+#include "libcef_dll/cpptoc/completion_callback_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK
+completion_callback_on_complete(struct _cef_completion_callback_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefCompletionCallbackCppToC::Get(self)->OnComplete();
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefCompletionCallbackCppToC::CefCompletionCallbackCppToC() {
+ GetStruct()->on_complete = completion_callback_on_complete;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefCompletionCallbackCppToC::~CefCompletionCallbackCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefCompletionCallback> CefCppToCRefCounted<
+ CefCompletionCallbackCppToC,
+ CefCompletionCallback,
+ cef_completion_callback_t>::UnwrapDerived(CefWrapperType type,
+ cef_completion_callback_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefCompletionCallbackCppToC,
+ CefCompletionCallback,
+ cef_completion_callback_t>::kWrapperType =
+ WT_COMPLETION_CALLBACK;
diff --git a/libcef_dll/cpptoc/completion_callback_cpptoc.h b/libcef_dll/cpptoc/completion_callback_cpptoc.h
new file mode 100644
index 00000000..f57a9e4f
--- /dev/null
+++ b/libcef_dll/cpptoc/completion_callback_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=407df18b90244b245e73c4f69a199663df079f0d$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_COMPLETION_CALLBACK_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_COMPLETION_CALLBACK_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_callback_capi.h"
+#include "include/cef_callback.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefCompletionCallbackCppToC
+ : public CefCppToCRefCounted<CefCompletionCallbackCppToC,
+ CefCompletionCallback,
+ cef_completion_callback_t> {
+ public:
+ CefCompletionCallbackCppToC();
+ virtual ~CefCompletionCallbackCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_COMPLETION_CALLBACK_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/context_menu_handler_cpptoc.cc b/libcef_dll/cpptoc/context_menu_handler_cpptoc.cc
new file mode 100644
index 00000000..1a690f34
--- /dev/null
+++ b/libcef_dll/cpptoc/context_menu_handler_cpptoc.cc
@@ -0,0 +1,346 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=6b90c347c6cc6cfbd8aa5e92eebc19929bd8c2c2$
+//
+
+#include "libcef_dll/cpptoc/context_menu_handler_cpptoc.h"
+#include "libcef_dll/ctocpp/browser_ctocpp.h"
+#include "libcef_dll/ctocpp/context_menu_params_ctocpp.h"
+#include "libcef_dll/ctocpp/frame_ctocpp.h"
+#include "libcef_dll/ctocpp/menu_model_ctocpp.h"
+#include "libcef_dll/ctocpp/run_context_menu_callback_ctocpp.h"
+#include "libcef_dll/ctocpp/run_quick_menu_callback_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK context_menu_handler_on_before_context_menu(
+ struct _cef_context_menu_handler_t* self,
+ cef_browser_t* browser,
+ struct _cef_frame_t* frame,
+ struct _cef_context_menu_params_t* params,
+ struct _cef_menu_model_t* model) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+ // Verify param: frame; type: refptr_diff
+ DCHECK(frame);
+ if (!frame) {
+ return;
+ }
+ // Verify param: params; type: refptr_diff
+ DCHECK(params);
+ if (!params) {
+ return;
+ }
+ // Verify param: model; type: refptr_diff
+ DCHECK(model);
+ if (!model) {
+ return;
+ }
+
+ // Execute
+ CefContextMenuHandlerCppToC::Get(self)->OnBeforeContextMenu(
+ CefBrowserCToCpp::Wrap(browser), CefFrameCToCpp::Wrap(frame),
+ CefContextMenuParamsCToCpp::Wrap(params),
+ CefMenuModelCToCpp::Wrap(model));
+}
+
+int CEF_CALLBACK context_menu_handler_run_context_menu(
+ struct _cef_context_menu_handler_t* self,
+ cef_browser_t* browser,
+ struct _cef_frame_t* frame,
+ struct _cef_context_menu_params_t* params,
+ struct _cef_menu_model_t* model,
+ cef_run_context_menu_callback_t* callback) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return 0;
+ }
+ // Verify param: frame; type: refptr_diff
+ DCHECK(frame);
+ if (!frame) {
+ return 0;
+ }
+ // Verify param: params; type: refptr_diff
+ DCHECK(params);
+ if (!params) {
+ return 0;
+ }
+ // Verify param: model; type: refptr_diff
+ DCHECK(model);
+ if (!model) {
+ return 0;
+ }
+ // Verify param: callback; type: refptr_diff
+ DCHECK(callback);
+ if (!callback) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefContextMenuHandlerCppToC::Get(self)->RunContextMenu(
+ CefBrowserCToCpp::Wrap(browser), CefFrameCToCpp::Wrap(frame),
+ CefContextMenuParamsCToCpp::Wrap(params), CefMenuModelCToCpp::Wrap(model),
+ CefRunContextMenuCallbackCToCpp::Wrap(callback));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK context_menu_handler_on_context_menu_command(
+ struct _cef_context_menu_handler_t* self,
+ cef_browser_t* browser,
+ struct _cef_frame_t* frame,
+ struct _cef_context_menu_params_t* params,
+ int command_id,
+ cef_event_flags_t event_flags) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return 0;
+ }
+ // Verify param: frame; type: refptr_diff
+ DCHECK(frame);
+ if (!frame) {
+ return 0;
+ }
+ // Verify param: params; type: refptr_diff
+ DCHECK(params);
+ if (!params) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefContextMenuHandlerCppToC::Get(self)->OnContextMenuCommand(
+ CefBrowserCToCpp::Wrap(browser), CefFrameCToCpp::Wrap(frame),
+ CefContextMenuParamsCToCpp::Wrap(params), command_id, event_flags);
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK context_menu_handler_on_context_menu_dismissed(
+ struct _cef_context_menu_handler_t* self,
+ cef_browser_t* browser,
+ struct _cef_frame_t* frame) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+ // Verify param: frame; type: refptr_diff
+ DCHECK(frame);
+ if (!frame) {
+ return;
+ }
+
+ // Execute
+ CefContextMenuHandlerCppToC::Get(self)->OnContextMenuDismissed(
+ CefBrowserCToCpp::Wrap(browser), CefFrameCToCpp::Wrap(frame));
+}
+
+int CEF_CALLBACK context_menu_handler_run_quick_menu(
+ struct _cef_context_menu_handler_t* self,
+ cef_browser_t* browser,
+ struct _cef_frame_t* frame,
+ const cef_point_t* location,
+ const cef_size_t* size,
+ cef_quick_menu_edit_state_flags_t edit_state_flags,
+ cef_run_quick_menu_callback_t* callback) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return 0;
+ }
+ // Verify param: frame; type: refptr_diff
+ DCHECK(frame);
+ if (!frame) {
+ return 0;
+ }
+ // Verify param: location; type: simple_byref_const
+ DCHECK(location);
+ if (!location) {
+ return 0;
+ }
+ // Verify param: size; type: simple_byref_const
+ DCHECK(size);
+ if (!size) {
+ return 0;
+ }
+ // Verify param: callback; type: refptr_diff
+ DCHECK(callback);
+ if (!callback) {
+ return 0;
+ }
+
+ // Translate param: location; type: simple_byref_const
+ CefPoint locationVal = location ? *location : CefPoint();
+ // Translate param: size; type: simple_byref_const
+ CefSize sizeVal = size ? *size : CefSize();
+
+ // Execute
+ bool _retval = CefContextMenuHandlerCppToC::Get(self)->RunQuickMenu(
+ CefBrowserCToCpp::Wrap(browser), CefFrameCToCpp::Wrap(frame), locationVal,
+ sizeVal, edit_state_flags, CefRunQuickMenuCallbackCToCpp::Wrap(callback));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK context_menu_handler_on_quick_menu_command(
+ struct _cef_context_menu_handler_t* self,
+ cef_browser_t* browser,
+ struct _cef_frame_t* frame,
+ int command_id,
+ cef_event_flags_t event_flags) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return 0;
+ }
+ // Verify param: frame; type: refptr_diff
+ DCHECK(frame);
+ if (!frame) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefContextMenuHandlerCppToC::Get(self)->OnQuickMenuCommand(
+ CefBrowserCToCpp::Wrap(browser), CefFrameCToCpp::Wrap(frame), command_id,
+ event_flags);
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK context_menu_handler_on_quick_menu_dismissed(
+ struct _cef_context_menu_handler_t* self,
+ cef_browser_t* browser,
+ struct _cef_frame_t* frame) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+ // Verify param: frame; type: refptr_diff
+ DCHECK(frame);
+ if (!frame) {
+ return;
+ }
+
+ // Execute
+ CefContextMenuHandlerCppToC::Get(self)->OnQuickMenuDismissed(
+ CefBrowserCToCpp::Wrap(browser), CefFrameCToCpp::Wrap(frame));
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefContextMenuHandlerCppToC::CefContextMenuHandlerCppToC() {
+ GetStruct()->on_before_context_menu =
+ context_menu_handler_on_before_context_menu;
+ GetStruct()->run_context_menu = context_menu_handler_run_context_menu;
+ GetStruct()->on_context_menu_command =
+ context_menu_handler_on_context_menu_command;
+ GetStruct()->on_context_menu_dismissed =
+ context_menu_handler_on_context_menu_dismissed;
+ GetStruct()->run_quick_menu = context_menu_handler_run_quick_menu;
+ GetStruct()->on_quick_menu_command =
+ context_menu_handler_on_quick_menu_command;
+ GetStruct()->on_quick_menu_dismissed =
+ context_menu_handler_on_quick_menu_dismissed;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefContextMenuHandlerCppToC::~CefContextMenuHandlerCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefContextMenuHandler> CefCppToCRefCounted<
+ CefContextMenuHandlerCppToC,
+ CefContextMenuHandler,
+ cef_context_menu_handler_t>::UnwrapDerived(CefWrapperType type,
+ cef_context_menu_handler_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefContextMenuHandlerCppToC,
+ CefContextMenuHandler,
+ cef_context_menu_handler_t>::kWrapperType =
+ WT_CONTEXT_MENU_HANDLER;
diff --git a/libcef_dll/cpptoc/context_menu_handler_cpptoc.h b/libcef_dll/cpptoc/context_menu_handler_cpptoc.h
new file mode 100644
index 00000000..fe010bf8
--- /dev/null
+++ b/libcef_dll/cpptoc/context_menu_handler_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=68dd3aa1b0a216bdc63aa9ed3008b0b5815f8040$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_CONTEXT_MENU_HANDLER_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_CONTEXT_MENU_HANDLER_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_context_menu_handler_capi.h"
+#include "include/cef_context_menu_handler.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefContextMenuHandlerCppToC
+ : public CefCppToCRefCounted<CefContextMenuHandlerCppToC,
+ CefContextMenuHandler,
+ cef_context_menu_handler_t> {
+ public:
+ CefContextMenuHandlerCppToC();
+ virtual ~CefContextMenuHandlerCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_CONTEXT_MENU_HANDLER_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/context_menu_params_cpptoc.cc b/libcef_dll/cpptoc/context_menu_params_cpptoc.cc
new file mode 100644
index 00000000..5ed633f2
--- /dev/null
+++ b/libcef_dll/cpptoc/context_menu_params_cpptoc.cc
@@ -0,0 +1,458 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=c543b9784333ad4f48c459585d03b65241884d45$
+//
+
+#include "libcef_dll/cpptoc/context_menu_params_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+#include "libcef_dll/transfer_util.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK
+context_menu_params_get_xcoord(struct _cef_context_menu_params_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefContextMenuParamsCppToC::Get(self)->GetXCoord();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK
+context_menu_params_get_ycoord(struct _cef_context_menu_params_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefContextMenuParamsCppToC::Get(self)->GetYCoord();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_context_menu_type_flags_t CEF_CALLBACK
+context_menu_params_get_type_flags(struct _cef_context_menu_params_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CM_TYPEFLAG_NONE;
+ }
+
+ // Execute
+ cef_context_menu_type_flags_t _retval =
+ CefContextMenuParamsCppToC::Get(self)->GetTypeFlags();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_string_userfree_t CEF_CALLBACK
+context_menu_params_get_link_url(struct _cef_context_menu_params_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefContextMenuParamsCppToC::Get(self)->GetLinkUrl();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_string_userfree_t CEF_CALLBACK context_menu_params_get_unfiltered_link_url(
+ struct _cef_context_menu_params_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval =
+ CefContextMenuParamsCppToC::Get(self)->GetUnfilteredLinkUrl();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_string_userfree_t CEF_CALLBACK
+context_menu_params_get_source_url(struct _cef_context_menu_params_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefContextMenuParamsCppToC::Get(self)->GetSourceUrl();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+int CEF_CALLBACK context_menu_params_has_image_contents(
+ struct _cef_context_menu_params_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefContextMenuParamsCppToC::Get(self)->HasImageContents();
+
+ // Return type: bool
+ return _retval;
+}
+
+cef_string_userfree_t CEF_CALLBACK
+context_menu_params_get_title_text(struct _cef_context_menu_params_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefContextMenuParamsCppToC::Get(self)->GetTitleText();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_string_userfree_t CEF_CALLBACK
+context_menu_params_get_page_url(struct _cef_context_menu_params_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefContextMenuParamsCppToC::Get(self)->GetPageUrl();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_string_userfree_t CEF_CALLBACK
+context_menu_params_get_frame_url(struct _cef_context_menu_params_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefContextMenuParamsCppToC::Get(self)->GetFrameUrl();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_string_userfree_t CEF_CALLBACK
+context_menu_params_get_frame_charset(struct _cef_context_menu_params_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefContextMenuParamsCppToC::Get(self)->GetFrameCharset();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_context_menu_media_type_t CEF_CALLBACK
+context_menu_params_get_media_type(struct _cef_context_menu_params_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CM_MEDIATYPE_NONE;
+ }
+
+ // Execute
+ cef_context_menu_media_type_t _retval =
+ CefContextMenuParamsCppToC::Get(self)->GetMediaType();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_context_menu_media_state_flags_t CEF_CALLBACK
+context_menu_params_get_media_state_flags(
+ struct _cef_context_menu_params_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CM_MEDIAFLAG_NONE;
+ }
+
+ // Execute
+ cef_context_menu_media_state_flags_t _retval =
+ CefContextMenuParamsCppToC::Get(self)->GetMediaStateFlags();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_string_userfree_t CEF_CALLBACK context_menu_params_get_selection_text(
+ struct _cef_context_menu_params_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefContextMenuParamsCppToC::Get(self)->GetSelectionText();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_string_userfree_t CEF_CALLBACK context_menu_params_get_misspelled_word(
+ struct _cef_context_menu_params_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval =
+ CefContextMenuParamsCppToC::Get(self)->GetMisspelledWord();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+int CEF_CALLBACK context_menu_params_get_dictionary_suggestions(
+ struct _cef_context_menu_params_t* self,
+ cef_string_list_t suggestions) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: suggestions; type: string_vec_byref
+ DCHECK(suggestions);
+ if (!suggestions) {
+ return 0;
+ }
+
+ // Translate param: suggestions; type: string_vec_byref
+ std::vector<CefString> suggestionsList;
+ transfer_string_list_contents(suggestions, suggestionsList);
+
+ // Execute
+ bool _retval =
+ CefContextMenuParamsCppToC::Get(self)->GetDictionarySuggestions(
+ suggestionsList);
+
+ // Restore param: suggestions; type: string_vec_byref
+ cef_string_list_clear(suggestions);
+ transfer_string_list_contents(suggestionsList, suggestions);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+context_menu_params_is_editable(struct _cef_context_menu_params_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefContextMenuParamsCppToC::Get(self)->IsEditable();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK context_menu_params_is_spell_check_enabled(
+ struct _cef_context_menu_params_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefContextMenuParamsCppToC::Get(self)->IsSpellCheckEnabled();
+
+ // Return type: bool
+ return _retval;
+}
+
+cef_context_menu_edit_state_flags_t CEF_CALLBACK
+context_menu_params_get_edit_state_flags(
+ struct _cef_context_menu_params_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CM_EDITFLAG_NONE;
+ }
+
+ // Execute
+ cef_context_menu_edit_state_flags_t _retval =
+ CefContextMenuParamsCppToC::Get(self)->GetEditStateFlags();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK
+context_menu_params_is_custom_menu(struct _cef_context_menu_params_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefContextMenuParamsCppToC::Get(self)->IsCustomMenu();
+
+ // Return type: bool
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefContextMenuParamsCppToC::CefContextMenuParamsCppToC() {
+ GetStruct()->get_xcoord = context_menu_params_get_xcoord;
+ GetStruct()->get_ycoord = context_menu_params_get_ycoord;
+ GetStruct()->get_type_flags = context_menu_params_get_type_flags;
+ GetStruct()->get_link_url = context_menu_params_get_link_url;
+ GetStruct()->get_unfiltered_link_url =
+ context_menu_params_get_unfiltered_link_url;
+ GetStruct()->get_source_url = context_menu_params_get_source_url;
+ GetStruct()->has_image_contents = context_menu_params_has_image_contents;
+ GetStruct()->get_title_text = context_menu_params_get_title_text;
+ GetStruct()->get_page_url = context_menu_params_get_page_url;
+ GetStruct()->get_frame_url = context_menu_params_get_frame_url;
+ GetStruct()->get_frame_charset = context_menu_params_get_frame_charset;
+ GetStruct()->get_media_type = context_menu_params_get_media_type;
+ GetStruct()->get_media_state_flags =
+ context_menu_params_get_media_state_flags;
+ GetStruct()->get_selection_text = context_menu_params_get_selection_text;
+ GetStruct()->get_misspelled_word = context_menu_params_get_misspelled_word;
+ GetStruct()->get_dictionary_suggestions =
+ context_menu_params_get_dictionary_suggestions;
+ GetStruct()->is_editable = context_menu_params_is_editable;
+ GetStruct()->is_spell_check_enabled =
+ context_menu_params_is_spell_check_enabled;
+ GetStruct()->get_edit_state_flags = context_menu_params_get_edit_state_flags;
+ GetStruct()->is_custom_menu = context_menu_params_is_custom_menu;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefContextMenuParamsCppToC::~CefContextMenuParamsCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefContextMenuParams> CefCppToCRefCounted<
+ CefContextMenuParamsCppToC,
+ CefContextMenuParams,
+ cef_context_menu_params_t>::UnwrapDerived(CefWrapperType type,
+ cef_context_menu_params_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefContextMenuParamsCppToC,
+ CefContextMenuParams,
+ cef_context_menu_params_t>::kWrapperType =
+ WT_CONTEXT_MENU_PARAMS;
diff --git a/libcef_dll/cpptoc/context_menu_params_cpptoc.h b/libcef_dll/cpptoc/context_menu_params_cpptoc.h
new file mode 100644
index 00000000..ccae20ac
--- /dev/null
+++ b/libcef_dll/cpptoc/context_menu_params_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=289e9100aeb329f9ec7d1696354e31f2eb7d8ce9$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_CONTEXT_MENU_PARAMS_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_CONTEXT_MENU_PARAMS_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_context_menu_handler_capi.h"
+#include "include/cef_context_menu_handler.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefContextMenuParamsCppToC
+ : public CefCppToCRefCounted<CefContextMenuParamsCppToC,
+ CefContextMenuParams,
+ cef_context_menu_params_t> {
+ public:
+ CefContextMenuParamsCppToC();
+ virtual ~CefContextMenuParamsCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_CONTEXT_MENU_PARAMS_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/cookie_access_filter_cpptoc.cc b/libcef_dll/cpptoc/cookie_access_filter_cpptoc.cc
new file mode 100644
index 00000000..919820bd
--- /dev/null
+++ b/libcef_dll/cpptoc/cookie_access_filter_cpptoc.cc
@@ -0,0 +1,146 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=f175b71f11857a4362fcf79178ea3ab531b15891$
+//
+
+#include "libcef_dll/cpptoc/cookie_access_filter_cpptoc.h"
+#include "libcef_dll/ctocpp/browser_ctocpp.h"
+#include "libcef_dll/ctocpp/frame_ctocpp.h"
+#include "libcef_dll/ctocpp/request_ctocpp.h"
+#include "libcef_dll/ctocpp/response_ctocpp.h"
+#include "libcef_dll/template_util.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK
+cookie_access_filter_can_send_cookie(struct _cef_cookie_access_filter_t* self,
+ cef_browser_t* browser,
+ cef_frame_t* frame,
+ cef_request_t* request,
+ const struct _cef_cookie_t* cookie) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: request; type: refptr_diff
+ DCHECK(request);
+ if (!request) {
+ return 0;
+ }
+ // Verify param: cookie; type: struct_byref_const
+ DCHECK(cookie);
+ if (!cookie) {
+ return 0;
+ }
+ if (!template_util::has_valid_size(cookie)) {
+ NOTREACHED() << "invalid cookie->[base.]size";
+ return 0;
+ }
+ // Unverified params: browser, frame
+
+ // Translate param: cookie; type: struct_byref_const
+ CefCookie cookieObj;
+ if (cookie) {
+ cookieObj.Set(*cookie, false);
+ }
+
+ // Execute
+ bool _retval = CefCookieAccessFilterCppToC::Get(self)->CanSendCookie(
+ CefBrowserCToCpp::Wrap(browser), CefFrameCToCpp::Wrap(frame),
+ CefRequestCToCpp::Wrap(request), cookieObj);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+cookie_access_filter_can_save_cookie(struct _cef_cookie_access_filter_t* self,
+ cef_browser_t* browser,
+ cef_frame_t* frame,
+ cef_request_t* request,
+ struct _cef_response_t* response,
+ const struct _cef_cookie_t* cookie) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: request; type: refptr_diff
+ DCHECK(request);
+ if (!request) {
+ return 0;
+ }
+ // Verify param: response; type: refptr_diff
+ DCHECK(response);
+ if (!response) {
+ return 0;
+ }
+ // Verify param: cookie; type: struct_byref_const
+ DCHECK(cookie);
+ if (!cookie) {
+ return 0;
+ }
+ if (!template_util::has_valid_size(cookie)) {
+ NOTREACHED() << "invalid cookie->[base.]size";
+ return 0;
+ }
+ // Unverified params: browser, frame
+
+ // Translate param: cookie; type: struct_byref_const
+ CefCookie cookieObj;
+ if (cookie) {
+ cookieObj.Set(*cookie, false);
+ }
+
+ // Execute
+ bool _retval = CefCookieAccessFilterCppToC::Get(self)->CanSaveCookie(
+ CefBrowserCToCpp::Wrap(browser), CefFrameCToCpp::Wrap(frame),
+ CefRequestCToCpp::Wrap(request), CefResponseCToCpp::Wrap(response),
+ cookieObj);
+
+ // Return type: bool
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefCookieAccessFilterCppToC::CefCookieAccessFilterCppToC() {
+ GetStruct()->can_send_cookie = cookie_access_filter_can_send_cookie;
+ GetStruct()->can_save_cookie = cookie_access_filter_can_save_cookie;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefCookieAccessFilterCppToC::~CefCookieAccessFilterCppToC() {}
+
+template <>
+CefRefPtr<CefCookieAccessFilter> CefCppToCRefCounted<
+ CefCookieAccessFilterCppToC,
+ CefCookieAccessFilter,
+ cef_cookie_access_filter_t>::UnwrapDerived(CefWrapperType type,
+ cef_cookie_access_filter_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefCookieAccessFilterCppToC,
+ CefCookieAccessFilter,
+ cef_cookie_access_filter_t>::kWrapperType =
+ WT_COOKIE_ACCESS_FILTER;
diff --git a/libcef_dll/cpptoc/cookie_access_filter_cpptoc.h b/libcef_dll/cpptoc/cookie_access_filter_cpptoc.h
new file mode 100644
index 00000000..d3e15045
--- /dev/null
+++ b/libcef_dll/cpptoc/cookie_access_filter_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=e0b8da1120abbbb306c6cc789ec94e38dc07ceb0$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_COOKIE_ACCESS_FILTER_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_COOKIE_ACCESS_FILTER_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_resource_request_handler_capi.h"
+#include "include/cef_resource_request_handler.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefCookieAccessFilterCppToC
+ : public CefCppToCRefCounted<CefCookieAccessFilterCppToC,
+ CefCookieAccessFilter,
+ cef_cookie_access_filter_t> {
+ public:
+ CefCookieAccessFilterCppToC();
+ virtual ~CefCookieAccessFilterCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_COOKIE_ACCESS_FILTER_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/cookie_manager_cpptoc.cc b/libcef_dll/cpptoc/cookie_manager_cpptoc.cc
new file mode 100644
index 00000000..af9f9a08
--- /dev/null
+++ b/libcef_dll/cpptoc/cookie_manager_cpptoc.cc
@@ -0,0 +1,208 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=8ed89e1ba19cde7c43e1c9e8d30354cfc356a1aa$
+//
+
+#include "libcef_dll/cpptoc/cookie_manager_cpptoc.h"
+#include "libcef_dll/ctocpp/completion_callback_ctocpp.h"
+#include "libcef_dll/ctocpp/cookie_visitor_ctocpp.h"
+#include "libcef_dll/ctocpp/delete_cookies_callback_ctocpp.h"
+#include "libcef_dll/ctocpp/set_cookie_callback_ctocpp.h"
+#include "libcef_dll/template_util.h"
+
+// GLOBAL FUNCTIONS - Body may be edited by hand.
+
+CEF_EXPORT cef_cookie_manager_t* cef_cookie_manager_get_global_manager(
+ cef_completion_callback_t* callback) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: callback
+
+ // Execute
+ CefRefPtr<CefCookieManager> _retval = CefCookieManager::GetGlobalManager(
+ CefCompletionCallbackCToCpp::Wrap(callback));
+
+ // Return type: refptr_same
+ return CefCookieManagerCppToC::Wrap(_retval);
+}
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK
+cookie_manager_visit_all_cookies(struct _cef_cookie_manager_t* self,
+ struct _cef_cookie_visitor_t* visitor) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: visitor; type: refptr_diff
+ DCHECK(visitor);
+ if (!visitor) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefCookieManagerCppToC::Get(self)->VisitAllCookies(
+ CefCookieVisitorCToCpp::Wrap(visitor));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+cookie_manager_visit_url_cookies(struct _cef_cookie_manager_t* self,
+ const cef_string_t* url,
+ int includeHttpOnly,
+ struct _cef_cookie_visitor_t* visitor) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: url; type: string_byref_const
+ DCHECK(url);
+ if (!url) {
+ return 0;
+ }
+ // Verify param: visitor; type: refptr_diff
+ DCHECK(visitor);
+ if (!visitor) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefCookieManagerCppToC::Get(self)->VisitUrlCookies(
+ CefString(url), includeHttpOnly ? true : false,
+ CefCookieVisitorCToCpp::Wrap(visitor));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+cookie_manager_set_cookie(struct _cef_cookie_manager_t* self,
+ const cef_string_t* url,
+ const struct _cef_cookie_t* cookie,
+ struct _cef_set_cookie_callback_t* callback) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: url; type: string_byref_const
+ DCHECK(url);
+ if (!url) {
+ return 0;
+ }
+ // Verify param: cookie; type: struct_byref_const
+ DCHECK(cookie);
+ if (!cookie) {
+ return 0;
+ }
+ if (!template_util::has_valid_size(cookie)) {
+ NOTREACHED() << "invalid cookie->[base.]size";
+ return 0;
+ }
+ // Unverified params: callback
+
+ // Translate param: cookie; type: struct_byref_const
+ CefCookie cookieObj;
+ if (cookie) {
+ cookieObj.Set(*cookie, false);
+ }
+
+ // Execute
+ bool _retval = CefCookieManagerCppToC::Get(self)->SetCookie(
+ CefString(url), cookieObj, CefSetCookieCallbackCToCpp::Wrap(callback));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+cookie_manager_delete_cookies(struct _cef_cookie_manager_t* self,
+ const cef_string_t* url,
+ const cef_string_t* cookie_name,
+ struct _cef_delete_cookies_callback_t* callback) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Unverified params: url, cookie_name, callback
+
+ // Execute
+ bool _retval = CefCookieManagerCppToC::Get(self)->DeleteCookies(
+ CefString(url), CefString(cookie_name),
+ CefDeleteCookiesCallbackCToCpp::Wrap(callback));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+cookie_manager_flush_store(struct _cef_cookie_manager_t* self,
+ cef_completion_callback_t* callback) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Unverified params: callback
+
+ // Execute
+ bool _retval = CefCookieManagerCppToC::Get(self)->FlushStore(
+ CefCompletionCallbackCToCpp::Wrap(callback));
+
+ // Return type: bool
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefCookieManagerCppToC::CefCookieManagerCppToC() {
+ GetStruct()->visit_all_cookies = cookie_manager_visit_all_cookies;
+ GetStruct()->visit_url_cookies = cookie_manager_visit_url_cookies;
+ GetStruct()->set_cookie = cookie_manager_set_cookie;
+ GetStruct()->delete_cookies = cookie_manager_delete_cookies;
+ GetStruct()->flush_store = cookie_manager_flush_store;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefCookieManagerCppToC::~CefCookieManagerCppToC() {}
+
+template <>
+CefRefPtr<CefCookieManager> CefCppToCRefCounted<
+ CefCookieManagerCppToC,
+ CefCookieManager,
+ cef_cookie_manager_t>::UnwrapDerived(CefWrapperType type,
+ cef_cookie_manager_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefCookieManagerCppToC,
+ CefCookieManager,
+ cef_cookie_manager_t>::kWrapperType =
+ WT_COOKIE_MANAGER;
diff --git a/libcef_dll/cpptoc/cookie_manager_cpptoc.h b/libcef_dll/cpptoc/cookie_manager_cpptoc.h
new file mode 100644
index 00000000..9f4094fe
--- /dev/null
+++ b/libcef_dll/cpptoc/cookie_manager_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=3c70ed00438c00d85c27407d1c0947d2b310f401$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_COOKIE_MANAGER_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_COOKIE_MANAGER_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_cookie_capi.h"
+#include "include/cef_cookie.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefCookieManagerCppToC
+ : public CefCppToCRefCounted<CefCookieManagerCppToC,
+ CefCookieManager,
+ cef_cookie_manager_t> {
+ public:
+ CefCookieManagerCppToC();
+ virtual ~CefCookieManagerCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_COOKIE_MANAGER_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/cookie_visitor_cpptoc.cc b/libcef_dll/cpptoc/cookie_visitor_cpptoc.cc
new file mode 100644
index 00000000..3f2a985b
--- /dev/null
+++ b/libcef_dll/cpptoc/cookie_visitor_cpptoc.cc
@@ -0,0 +1,100 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=6706f5bf43d926b749840fb27aa7931111f1a638$
+//
+
+#include "libcef_dll/cpptoc/cookie_visitor_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+#include "libcef_dll/template_util.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK cookie_visitor_visit(struct _cef_cookie_visitor_t* self,
+ const struct _cef_cookie_t* cookie,
+ int count,
+ int total,
+ int* deleteCookie) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: cookie; type: struct_byref_const
+ DCHECK(cookie);
+ if (!cookie) {
+ return 0;
+ }
+ if (!template_util::has_valid_size(cookie)) {
+ NOTREACHED() << "invalid cookie->[base.]size";
+ return 0;
+ }
+ // Verify param: deleteCookie; type: bool_byref
+ DCHECK(deleteCookie);
+ if (!deleteCookie) {
+ return 0;
+ }
+
+ // Translate param: cookie; type: struct_byref_const
+ CefCookie cookieObj;
+ if (cookie) {
+ cookieObj.Set(*cookie, false);
+ }
+ // Translate param: deleteCookie; type: bool_byref
+ bool deleteCookieBool = (deleteCookie && *deleteCookie) ? true : false;
+
+ // Execute
+ bool _retval = CefCookieVisitorCppToC::Get(self)->Visit(
+ cookieObj, count, total, deleteCookieBool);
+
+ // Restore param: deleteCookie; type: bool_byref
+ if (deleteCookie) {
+ *deleteCookie = deleteCookieBool ? true : false;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefCookieVisitorCppToC::CefCookieVisitorCppToC() {
+ GetStruct()->visit = cookie_visitor_visit;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefCookieVisitorCppToC::~CefCookieVisitorCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefCookieVisitor> CefCppToCRefCounted<
+ CefCookieVisitorCppToC,
+ CefCookieVisitor,
+ cef_cookie_visitor_t>::UnwrapDerived(CefWrapperType type,
+ cef_cookie_visitor_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefCookieVisitorCppToC,
+ CefCookieVisitor,
+ cef_cookie_visitor_t>::kWrapperType =
+ WT_COOKIE_VISITOR;
diff --git a/libcef_dll/cpptoc/cookie_visitor_cpptoc.h b/libcef_dll/cpptoc/cookie_visitor_cpptoc.h
new file mode 100644
index 00000000..f0dd94f0
--- /dev/null
+++ b/libcef_dll/cpptoc/cookie_visitor_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=45985eb9f0544a0c90fea396ec66c921e44f55a5$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_COOKIE_VISITOR_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_COOKIE_VISITOR_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_cookie_capi.h"
+#include "include/cef_cookie.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefCookieVisitorCppToC
+ : public CefCppToCRefCounted<CefCookieVisitorCppToC,
+ CefCookieVisitor,
+ cef_cookie_visitor_t> {
+ public:
+ CefCookieVisitorCppToC();
+ virtual ~CefCookieVisitorCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_COOKIE_VISITOR_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/cpptoc_ref_counted.h b/libcef_dll/cpptoc/cpptoc_ref_counted.h
new file mode 100644
index 00000000..d7a04e76
--- /dev/null
+++ b/libcef_dll/cpptoc/cpptoc_ref_counted.h
@@ -0,0 +1,210 @@
+// Copyright (c) 2009 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_CPPTOC_REF_COUNTED_H_
+#define CEF_LIBCEF_DLL_CPPTOC_CPPTOC_REF_COUNTED_H_
+#pragma once
+
+#include "include/base/cef_logging.h"
+#include "include/capi/cef_base_capi.h"
+#include "include/cef_base.h"
+#include "libcef_dll/wrapper_types.h"
+
+// Wrap a C++ class with a C structure. This is used when the class
+// implementation exists on this side of the DLL boundary but will have methods
+// called from the other side of the DLL boundary.
+template <class ClassName, class BaseName, class StructName>
+class CefCppToCRefCounted : public CefBaseRefCounted {
+ public:
+ CefCppToCRefCounted(const CefCppToCRefCounted&) = delete;
+ CefCppToCRefCounted& operator=(const CefCppToCRefCounted&) = delete;
+
+ // Create a new wrapper instance and associated structure reference for
+ // passing an object instance the other side.
+ static StructName* Wrap(CefRefPtr<BaseName> c) {
+ if (!c.get()) {
+ return nullptr;
+ }
+
+ // Wrap our object with the CefCppToCRefCounted class.
+ ClassName* wrapper = new ClassName();
+ wrapper->wrapper_struct_.object_ = c.get();
+ // Add a reference to our wrapper object that will be released once our
+ // structure arrives on the other side.
+ wrapper->AddRef();
+ // Return the structure pointer that can now be passed to the other side.
+ return wrapper->GetStruct();
+ }
+
+ // Retrieve the underlying object instance for a structure reference passed
+ // back from the other side.
+ static CefRefPtr<BaseName> Unwrap(StructName* s) {
+ if (!s) {
+ return nullptr;
+ }
+
+ // Cast our structure to the wrapper structure type.
+ WrapperStruct* wrapperStruct = GetWrapperStruct(s);
+
+ // If the type does not match this object then we need to unwrap as the
+ // derived type.
+ if (wrapperStruct->type_ != kWrapperType) {
+ return UnwrapDerived(wrapperStruct->type_, s);
+ }
+
+ // Add the underlying object instance to a smart pointer.
+ CefRefPtr<BaseName> objectPtr(wrapperStruct->object_);
+ // Release the reference to our wrapper object that was added before the
+ // structure was passed back to us.
+ wrapperStruct->wrapper_->Release();
+ // Return the underlying object instance.
+ return objectPtr;
+ }
+
+ // Retrieve the underlying object instance from our own structure reference
+ // when the reference is passed as the required first parameter of a C API
+ // function call. No explicit reference counting is done in this case.
+ static CefRefPtr<BaseName> Get(StructName* s) {
+ DCHECK(s);
+ WrapperStruct* wrapperStruct = GetWrapperStruct(s);
+ // Verify that the wrapper offset was calculated correctly.
+ DCHECK_EQ(kWrapperType, wrapperStruct->type_);
+ return wrapperStruct->object_;
+ }
+
+ // If returning the structure across the DLL boundary you should call
+ // AddRef() on this CefCppToCRefCounted object. On the other side of the DLL
+ // boundary, call UnderlyingRelease() on the wrapping CefCToCpp object.
+ StructName* GetStruct() { return &wrapper_struct_.struct_; }
+
+ // CefBaseRefCounted methods increment/decrement reference counts on both this
+ // object and the underlying wrapper class.
+ void AddRef() const {
+ UnderlyingAddRef();
+ ref_count_.AddRef();
+ }
+ bool Release() const {
+ UnderlyingRelease();
+ if (ref_count_.Release()) {
+ delete this;
+ return true;
+ }
+ return false;
+ }
+ bool HasOneRef() const { return UnderlyingHasOneRef(); }
+ bool HasAtLeastOneRef() const { return UnderlyingHasAtLeastOneRef(); }
+
+ protected:
+ CefCppToCRefCounted() {
+ wrapper_struct_.type_ = kWrapperType;
+ wrapper_struct_.wrapper_ = this;
+ memset(GetStruct(), 0, sizeof(StructName));
+
+ cef_base_ref_counted_t* base =
+ reinterpret_cast<cef_base_ref_counted_t*>(GetStruct());
+ base->size = sizeof(StructName);
+ base->add_ref = struct_add_ref;
+ base->release = struct_release;
+ base->has_one_ref = struct_has_one_ref;
+ base->has_at_least_one_ref = struct_has_at_least_one_ref;
+ }
+
+ virtual ~CefCppToCRefCounted() = default;
+
+ private:
+ // Used to associate this wrapper object, the underlying object instance and
+ // the structure that will be passed to the other side.
+ struct WrapperStruct {
+ CefWrapperType type_;
+ BaseName* object_;
+ CefCppToCRefCounted<ClassName, BaseName, StructName>* wrapper_;
+ StructName struct_;
+ };
+
+ static WrapperStruct* GetWrapperStruct(StructName* s) {
+ // Offset using the WrapperStruct size instead of individual member sizes
+ // to avoid problems due to platform/compiler differences in structure
+ // padding.
+ return reinterpret_cast<WrapperStruct*>(
+ reinterpret_cast<char*>(s) -
+ (sizeof(WrapperStruct) - sizeof(StructName)));
+ }
+
+ // Unwrap as the derived type.
+ static CefRefPtr<BaseName> UnwrapDerived(CefWrapperType type, StructName* s);
+
+ // Increment/decrement reference counts on only the underlying class.
+ void UnderlyingAddRef() const { wrapper_struct_.object_->AddRef(); }
+ void UnderlyingRelease() const { wrapper_struct_.object_->Release(); }
+ bool UnderlyingHasOneRef() const {
+ return wrapper_struct_.object_->HasOneRef();
+ }
+ bool UnderlyingHasAtLeastOneRef() const {
+ return wrapper_struct_.object_->HasAtLeastOneRef();
+ }
+
+ static void CEF_CALLBACK struct_add_ref(cef_base_ref_counted_t* base) {
+ DCHECK(base);
+ if (!base) {
+ return;
+ }
+
+ WrapperStruct* wrapperStruct =
+ GetWrapperStruct(reinterpret_cast<StructName*>(base));
+ // Verify that the wrapper offset was calculated correctly.
+ DCHECK_EQ(kWrapperType, wrapperStruct->type_);
+
+ wrapperStruct->wrapper_->AddRef();
+ }
+
+ static int CEF_CALLBACK struct_release(cef_base_ref_counted_t* base) {
+ DCHECK(base);
+ if (!base) {
+ return 0;
+ }
+
+ WrapperStruct* wrapperStruct =
+ GetWrapperStruct(reinterpret_cast<StructName*>(base));
+ // Verify that the wrapper offset was calculated correctly.
+ DCHECK_EQ(kWrapperType, wrapperStruct->type_);
+
+ return wrapperStruct->wrapper_->Release();
+ }
+
+ static int CEF_CALLBACK struct_has_one_ref(cef_base_ref_counted_t* base) {
+ DCHECK(base);
+ if (!base) {
+ return 0;
+ }
+
+ WrapperStruct* wrapperStruct =
+ GetWrapperStruct(reinterpret_cast<StructName*>(base));
+ // Verify that the wrapper offset was calculated correctly.
+ DCHECK_EQ(kWrapperType, wrapperStruct->type_);
+
+ return wrapperStruct->wrapper_->HasOneRef();
+ }
+
+ static int CEF_CALLBACK
+ struct_has_at_least_one_ref(cef_base_ref_counted_t* base) {
+ DCHECK(base);
+ if (!base) {
+ return 0;
+ }
+
+ WrapperStruct* wrapperStruct =
+ GetWrapperStruct(reinterpret_cast<StructName*>(base));
+ // Verify that the wrapper offset was calculated correctly.
+ DCHECK_EQ(kWrapperType, wrapperStruct->type_);
+
+ return wrapperStruct->wrapper_->HasAtLeastOneRef();
+ }
+
+ WrapperStruct wrapper_struct_;
+ CefRefCount ref_count_;
+
+ static CefWrapperType kWrapperType;
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_CPPTOC_REF_COUNTED_H_
diff --git a/libcef_dll/cpptoc/cpptoc_scoped.h b/libcef_dll/cpptoc/cpptoc_scoped.h
new file mode 100644
index 00000000..11fe3d96
--- /dev/null
+++ b/libcef_dll/cpptoc/cpptoc_scoped.h
@@ -0,0 +1,236 @@
+// Copyright (c) 2017 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_CPPTOC_SCOPED_H_
+#define CEF_LIBCEF_DLL_CPPTOC_CPPTOC_SCOPED_H_
+#pragma once
+
+#include "include/base/cef_logging.h"
+#include "include/capi/cef_base_capi.h"
+#include "include/cef_base.h"
+#include "libcef_dll/wrapper_types.h"
+
+// Wrap a C++ class with a C structure. This is used when the class
+// implementation exists on this side of the DLL boundary but will have methods
+// called from the other side of the DLL boundary.
+template <class ClassName, class BaseName, class StructName>
+class CefCppToCScoped : public CefBaseScoped {
+ public:
+ CefCppToCScoped(const CefCppToCScoped&) = delete;
+ CefCppToCScoped& operator=(const CefCppToCScoped&) = delete;
+
+ // Create a new wrapper instance and associated structure reference for
+ // passing an object instance the other side. The wrapper object will be
+ // deleted when |del| is called on the associated structure. The wrapped
+ // object will be deleted when the wrapper object is deleted. For example:
+ //
+ // void MyMethod(CefOwnPtr<MyType> obj) {
+ // my_method(MyTypeCppToC::WrapOwn(obj));
+ // }
+ //
+ // void my_method(my_type_t* struct) {
+ // // Delete the MyTypeCppToC wrapper and the owned MyType object.
+ // struct->del(struct);
+ // }
+ static StructName* WrapOwn(CefOwnPtr<BaseName> c) {
+ if (!c) {
+ return nullptr;
+ }
+
+ // Wrap our object with the CefCppToC class.
+ ClassName* wrapper = new ClassName();
+ wrapper->Initialize(c.release(), true);
+
+ // Return the structure pointer that can now be passed to the other side.
+ return wrapper->GetStruct();
+ }
+
+ // Create a new wrapper instance and associated structure reference for
+ // passing an object instance to the other side. The wrapper object is owned
+ // by the caller. The wrapped object is unowned and must outlive the wrapper.
+ // For example:
+ //
+ // void MyMethod(MyType* obj) {
+ // CefOwnPtr<MyTypeCppToC> MyTypeWrapper = MyTypeCppToC::WrapRaw(obj);
+ // my_method(MyTypeWrapper->GetStruct());
+ // // MyTypeWrapper is deleted when MyMethod() goes out of scope.
+ // }
+ //
+ // void my_method(my_type_t* struct) {
+ // // Access |struct| here but you can't delete it.
+ // }
+ static CefOwnPtr<ClassName> WrapRaw(CefRawPtr<BaseName> c) {
+ if (!c) {
+ return CefOwnPtr<ClassName>();
+ }
+
+ // Wrap our object with the CefCppToC class.
+ ClassName* wrapper = new ClassName();
+ wrapper->Initialize(c, false);
+
+ // Return the owned wrapper object.
+ return CefOwnPtr<ClassName>(wrapper);
+ }
+
+ // Retrieve the underlying object instance for a structure reference passed
+ // back from the other side. The caller takes ownership of the object. For
+ // example:
+ //
+ // void my_method(my_type_t* struct) {
+ // CefOwnPtr<MyType> MyTypePtr = MyTypeCppToC::UnwrapOwn(struct);
+ // // |struct| has been deleted and should no longer be accessed.
+ // }
+ static CefOwnPtr<BaseName> UnwrapOwn(StructName* s) {
+ if (!s) {
+ return CefOwnPtr<BaseName>();
+ }
+
+ // Cast our structure to the wrapper structure type.
+ WrapperStruct* wrapperStruct = GetWrapperStruct(s);
+
+ // If the type does not match this object then we need to unwrap as the
+ // derived type.
+ if (wrapperStruct->type_ != kWrapperType) {
+ return UnwrapDerivedOwn(wrapperStruct->type_, s);
+ }
+
+ // We should own the underlying object currently.
+ DCHECK(wrapperStruct->wrapper_->owned_);
+ DCHECK(wrapperStruct->object_);
+
+ // We're giving up ownership of the underlying object. Clear the pointer so
+ // it doesn't get deleted.
+ BaseName* object = wrapperStruct->object_;
+ wrapperStruct->object_ = nullptr;
+
+ delete wrapperStruct->wrapper_;
+
+ // Return the underlying object instance.
+ return CefOwnPtr<BaseName>(object);
+ }
+
+ // Retrieve the underlying object instance for a structure reference passed
+ // back from the other side. Ownership does not change. For example:
+ //
+ // void my_method(my_type_t* struct) {
+ // CefRawPtr<MyType> MyTypePtr = MyTypeCppToC::UnwrapRaw(struct);
+ // // |struct| is still valid.
+ // }
+ static CefRawPtr<BaseName> UnwrapRaw(StructName* s) {
+ if (!s) {
+ return nullptr;
+ }
+
+ // Cast our structure to the wrapper structure type.
+ WrapperStruct* wrapperStruct = GetWrapperStruct(s);
+
+ // If the type does not match this object then we need to unwrap as the
+ // derived type.
+ if (wrapperStruct->type_ != kWrapperType) {
+ return UnwrapDerivedRaw(wrapperStruct->type_, s);
+ }
+
+ // Return the underlying object instance.
+ return wrapperStruct->object_;
+ }
+
+ // Retrieve the same side wrapper associated with the structure. Ownership
+ // does not change.
+ static ClassName* GetWrapper(StructName* s) {
+ DCHECK(s);
+ WrapperStruct* wrapperStruct = GetWrapperStruct(s);
+ // Verify that the wrapper offset was calculated correctly.
+ DCHECK_EQ(kWrapperType, wrapperStruct->type_);
+ return static_cast<ClassName*>(wrapperStruct->wrapper_);
+ }
+
+ // Retrieve the underlying object instance from our own structure reference
+ // when the reference is passed as the required first parameter of a C API
+ // function call. Ownership of the object does not change.
+ static BaseName* Get(StructName* s) {
+ DCHECK(s);
+ WrapperStruct* wrapperStruct = GetWrapperStruct(s);
+ // Verify that the wrapper offset was calculated correctly.
+ DCHECK_EQ(kWrapperType, wrapperStruct->type_);
+ return wrapperStruct->object_;
+ }
+
+ // If returning the structure across the DLL boundary you should call
+ // AddRef() on this CefCppToC object. On the other side of the DLL boundary,
+ // call UnderlyingRelease() on the wrapping CefCToCpp object.
+ StructName* GetStruct() { return &wrapper_struct_.struct_; }
+
+ protected:
+ CefCppToCScoped() {
+ wrapper_struct_.type_ = kWrapperType;
+ wrapper_struct_.wrapper_ = this;
+ memset(GetStruct(), 0, sizeof(StructName));
+ }
+
+ virtual ~CefCppToCScoped() {
+ // Only delete the underlying object if we own it.
+ if (owned_ && wrapper_struct_.object_) {
+ delete wrapper_struct_.object_;
+ }
+ }
+
+ private:
+ // Used to associate this wrapper object, the underlying object instance and
+ // the structure that will be passed to the other side.
+ struct WrapperStruct {
+ CefWrapperType type_;
+ BaseName* object_;
+ CefCppToCScoped<ClassName, BaseName, StructName>* wrapper_;
+ StructName struct_;
+ };
+
+ void Initialize(BaseName* obj, bool owned) {
+ wrapper_struct_.object_ = obj;
+ owned_ = owned;
+
+ cef_base_scoped_t* base = reinterpret_cast<cef_base_scoped_t*>(GetStruct());
+ base->size = sizeof(StructName);
+ if (owned) {
+ base->del = struct_del;
+ }
+ }
+
+ static WrapperStruct* GetWrapperStruct(StructName* s) {
+ // Offset using the WrapperStruct size instead of individual member sizes
+ // to avoid problems due to platform/compiler differences in structure
+ // padding.
+ return reinterpret_cast<WrapperStruct*>(
+ reinterpret_cast<char*>(s) -
+ (sizeof(WrapperStruct) - sizeof(StructName)));
+ }
+
+ // Unwrap as the derived type.
+ static CefOwnPtr<BaseName> UnwrapDerivedOwn(CefWrapperType type,
+ StructName* s);
+ static CefRawPtr<BaseName> UnwrapDerivedRaw(CefWrapperType type,
+ StructName* s);
+
+ static void CEF_CALLBACK struct_del(cef_base_scoped_t* base) {
+ DCHECK(base);
+ if (!base) {
+ return;
+ }
+
+ WrapperStruct* wrapperStruct =
+ GetWrapperStruct(reinterpret_cast<StructName*>(base));
+ // Verify that the wrapper offset was calculated correctly.
+ DCHECK_EQ(kWrapperType, wrapperStruct->type_);
+
+ // Should only be deleting wrappers that own the underlying object.
+ DCHECK(wrapperStruct->wrapper_->owned_);
+ delete wrapperStruct->wrapper_;
+ }
+
+ WrapperStruct wrapper_struct_;
+ bool owned_;
+
+ static CefWrapperType kWrapperType;
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_CPPTOC_SCOPED_H_
diff --git a/libcef_dll/cpptoc/delete_cookies_callback_cpptoc.cc b/libcef_dll/cpptoc/delete_cookies_callback_cpptoc.cc
new file mode 100644
index 00000000..2aa4ad52
--- /dev/null
+++ b/libcef_dll/cpptoc/delete_cookies_callback_cpptoc.cc
@@ -0,0 +1,68 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=b464cf54dd6dbbe3b7f45adaf8defd0b0015c9c3$
+//
+
+#include "libcef_dll/cpptoc/delete_cookies_callback_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK
+delete_cookies_callback_on_complete(struct _cef_delete_cookies_callback_t* self,
+ int num_deleted) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefDeleteCookiesCallbackCppToC::Get(self)->OnComplete(num_deleted);
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefDeleteCookiesCallbackCppToC::CefDeleteCookiesCallbackCppToC() {
+ GetStruct()->on_complete = delete_cookies_callback_on_complete;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefDeleteCookiesCallbackCppToC::~CefDeleteCookiesCallbackCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefDeleteCookiesCallback> CefCppToCRefCounted<
+ CefDeleteCookiesCallbackCppToC,
+ CefDeleteCookiesCallback,
+ cef_delete_cookies_callback_t>::UnwrapDerived(CefWrapperType type,
+ cef_delete_cookies_callback_t*
+ s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCppToCRefCounted<CefDeleteCookiesCallbackCppToC,
+ CefDeleteCookiesCallback,
+ cef_delete_cookies_callback_t>::kWrapperType =
+ WT_DELETE_COOKIES_CALLBACK;
diff --git a/libcef_dll/cpptoc/delete_cookies_callback_cpptoc.h b/libcef_dll/cpptoc/delete_cookies_callback_cpptoc.h
new file mode 100644
index 00000000..bc1ebd95
--- /dev/null
+++ b/libcef_dll/cpptoc/delete_cookies_callback_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=9ef76b4e16c9ee12b2c5956a3e4789fe2e40d9f0$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_DELETE_COOKIES_CALLBACK_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_DELETE_COOKIES_CALLBACK_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_cookie_capi.h"
+#include "include/cef_cookie.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefDeleteCookiesCallbackCppToC
+ : public CefCppToCRefCounted<CefDeleteCookiesCallbackCppToC,
+ CefDeleteCookiesCallback,
+ cef_delete_cookies_callback_t> {
+ public:
+ CefDeleteCookiesCallbackCppToC();
+ virtual ~CefDeleteCookiesCallbackCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_DELETE_COOKIES_CALLBACK_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/dev_tools_message_observer_cpptoc.cc b/libcef_dll/cpptoc/dev_tools_message_observer_cpptoc.cc
new file mode 100644
index 00000000..d9e89f86
--- /dev/null
+++ b/libcef_dll/cpptoc/dev_tools_message_observer_cpptoc.cc
@@ -0,0 +1,196 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=78a2561a28bab409e06b44eaff38cac7e156bdf4$
+//
+
+#include "libcef_dll/cpptoc/dev_tools_message_observer_cpptoc.h"
+#include "libcef_dll/ctocpp/browser_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK dev_tools_message_observer_on_dev_tools_message(
+ struct _cef_dev_tools_message_observer_t* self,
+ cef_browser_t* browser,
+ const void* message,
+ size_t message_size) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return 0;
+ }
+ // Verify param: message; type: simple_byaddr
+ DCHECK(message);
+ if (!message) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefDevToolsMessageObserverCppToC::Get(self)->OnDevToolsMessage(
+ CefBrowserCToCpp::Wrap(browser), message, message_size);
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK dev_tools_message_observer_on_dev_tools_method_result(
+ struct _cef_dev_tools_message_observer_t* self,
+ cef_browser_t* browser,
+ int message_id,
+ int success,
+ const void* result,
+ size_t result_size) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+ // Unverified params: result
+
+ // Execute
+ CefDevToolsMessageObserverCppToC::Get(self)->OnDevToolsMethodResult(
+ CefBrowserCToCpp::Wrap(browser), message_id, success ? true : false,
+ result, result_size);
+}
+
+void CEF_CALLBACK dev_tools_message_observer_on_dev_tools_event(
+ struct _cef_dev_tools_message_observer_t* self,
+ cef_browser_t* browser,
+ const cef_string_t* method,
+ const void* params,
+ size_t params_size) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+ // Verify param: method; type: string_byref_const
+ DCHECK(method);
+ if (!method) {
+ return;
+ }
+ // Unverified params: params
+
+ // Execute
+ CefDevToolsMessageObserverCppToC::Get(self)->OnDevToolsEvent(
+ CefBrowserCToCpp::Wrap(browser), CefString(method), params, params_size);
+}
+
+void CEF_CALLBACK dev_tools_message_observer_on_dev_tools_agent_attached(
+ struct _cef_dev_tools_message_observer_t* self,
+ cef_browser_t* browser) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+
+ // Execute
+ CefDevToolsMessageObserverCppToC::Get(self)->OnDevToolsAgentAttached(
+ CefBrowserCToCpp::Wrap(browser));
+}
+
+void CEF_CALLBACK dev_tools_message_observer_on_dev_tools_agent_detached(
+ struct _cef_dev_tools_message_observer_t* self,
+ cef_browser_t* browser) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+
+ // Execute
+ CefDevToolsMessageObserverCppToC::Get(self)->OnDevToolsAgentDetached(
+ CefBrowserCToCpp::Wrap(browser));
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefDevToolsMessageObserverCppToC::CefDevToolsMessageObserverCppToC() {
+ GetStruct()->on_dev_tools_message =
+ dev_tools_message_observer_on_dev_tools_message;
+ GetStruct()->on_dev_tools_method_result =
+ dev_tools_message_observer_on_dev_tools_method_result;
+ GetStruct()->on_dev_tools_event =
+ dev_tools_message_observer_on_dev_tools_event;
+ GetStruct()->on_dev_tools_agent_attached =
+ dev_tools_message_observer_on_dev_tools_agent_attached;
+ GetStruct()->on_dev_tools_agent_detached =
+ dev_tools_message_observer_on_dev_tools_agent_detached;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefDevToolsMessageObserverCppToC::~CefDevToolsMessageObserverCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefDevToolsMessageObserver>
+CefCppToCRefCounted<CefDevToolsMessageObserverCppToC,
+ CefDevToolsMessageObserver,
+ cef_dev_tools_message_observer_t>::
+ UnwrapDerived(CefWrapperType type, cef_dev_tools_message_observer_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCppToCRefCounted<CefDevToolsMessageObserverCppToC,
+ CefDevToolsMessageObserver,
+ cef_dev_tools_message_observer_t>::kWrapperType =
+ WT_DEV_TOOLS_MESSAGE_OBSERVER;
diff --git a/libcef_dll/cpptoc/dev_tools_message_observer_cpptoc.h b/libcef_dll/cpptoc/dev_tools_message_observer_cpptoc.h
new file mode 100644
index 00000000..6ab9e5c9
--- /dev/null
+++ b/libcef_dll/cpptoc/dev_tools_message_observer_cpptoc.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=4f034b01b5709e8012ff089e000216008f6232b6$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_DEV_TOOLS_MESSAGE_OBSERVER_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_DEV_TOOLS_MESSAGE_OBSERVER_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_browser_capi.h"
+#include "include/capi/cef_devtools_message_observer_capi.h"
+#include "include/cef_browser.h"
+#include "include/cef_devtools_message_observer.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefDevToolsMessageObserverCppToC
+ : public CefCppToCRefCounted<CefDevToolsMessageObserverCppToC,
+ CefDevToolsMessageObserver,
+ cef_dev_tools_message_observer_t> {
+ public:
+ CefDevToolsMessageObserverCppToC();
+ virtual ~CefDevToolsMessageObserverCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_DEV_TOOLS_MESSAGE_OBSERVER_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/dialog_handler_cpptoc.cc b/libcef_dll/cpptoc/dialog_handler_cpptoc.cc
new file mode 100644
index 00000000..fa4e15a2
--- /dev/null
+++ b/libcef_dll/cpptoc/dialog_handler_cpptoc.cc
@@ -0,0 +1,95 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=a71a7566407304bb219d211d4faf5c95c979b052$
+//
+
+#include "libcef_dll/cpptoc/dialog_handler_cpptoc.h"
+#include "libcef_dll/ctocpp/browser_ctocpp.h"
+#include "libcef_dll/ctocpp/file_dialog_callback_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+#include "libcef_dll/transfer_util.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK
+dialog_handler_on_file_dialog(struct _cef_dialog_handler_t* self,
+ cef_browser_t* browser,
+ cef_file_dialog_mode_t mode,
+ const cef_string_t* title,
+ const cef_string_t* default_file_path,
+ cef_string_list_t accept_filters,
+ cef_file_dialog_callback_t* callback) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return 0;
+ }
+ // Verify param: callback; type: refptr_diff
+ DCHECK(callback);
+ if (!callback) {
+ return 0;
+ }
+ // Unverified params: title, default_file_path, accept_filters
+
+ // Translate param: accept_filters; type: string_vec_byref_const
+ std::vector<CefString> accept_filtersList;
+ transfer_string_list_contents(accept_filters, accept_filtersList);
+
+ // Execute
+ bool _retval = CefDialogHandlerCppToC::Get(self)->OnFileDialog(
+ CefBrowserCToCpp::Wrap(browser), mode, CefString(title),
+ CefString(default_file_path), accept_filtersList,
+ CefFileDialogCallbackCToCpp::Wrap(callback));
+
+ // Return type: bool
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefDialogHandlerCppToC::CefDialogHandlerCppToC() {
+ GetStruct()->on_file_dialog = dialog_handler_on_file_dialog;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefDialogHandlerCppToC::~CefDialogHandlerCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefDialogHandler> CefCppToCRefCounted<
+ CefDialogHandlerCppToC,
+ CefDialogHandler,
+ cef_dialog_handler_t>::UnwrapDerived(CefWrapperType type,
+ cef_dialog_handler_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefDialogHandlerCppToC,
+ CefDialogHandler,
+ cef_dialog_handler_t>::kWrapperType =
+ WT_DIALOG_HANDLER;
diff --git a/libcef_dll/cpptoc/dialog_handler_cpptoc.h b/libcef_dll/cpptoc/dialog_handler_cpptoc.h
new file mode 100644
index 00000000..dcd88050
--- /dev/null
+++ b/libcef_dll/cpptoc/dialog_handler_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=fca3fb90b8a74c5cdf3dc16e1489668ce80c7c07$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_DIALOG_HANDLER_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_DIALOG_HANDLER_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_dialog_handler_capi.h"
+#include "include/cef_dialog_handler.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefDialogHandlerCppToC
+ : public CefCppToCRefCounted<CefDialogHandlerCppToC,
+ CefDialogHandler,
+ cef_dialog_handler_t> {
+ public:
+ CefDialogHandlerCppToC();
+ virtual ~CefDialogHandlerCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_DIALOG_HANDLER_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/dictionary_value_cpptoc.cc b/libcef_dll/cpptoc/dictionary_value_cpptoc.cc
new file mode 100644
index 00000000..eaa3a7f5
--- /dev/null
+++ b/libcef_dll/cpptoc/dictionary_value_cpptoc.cc
@@ -0,0 +1,803 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=3e9334efe52aaa876470421341bbd8ca2936f19e$
+//
+
+#include "libcef_dll/cpptoc/dictionary_value_cpptoc.h"
+#include "libcef_dll/cpptoc/binary_value_cpptoc.h"
+#include "libcef_dll/cpptoc/list_value_cpptoc.h"
+#include "libcef_dll/cpptoc/value_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+#include "libcef_dll/transfer_util.h"
+
+// GLOBAL FUNCTIONS - Body may be edited by hand.
+
+CEF_EXPORT cef_dictionary_value_t* cef_dictionary_value_create() {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ CefRefPtr<CefDictionaryValue> _retval = CefDictionaryValue::Create();
+
+ // Return type: refptr_same
+ return CefDictionaryValueCppToC::Wrap(_retval);
+}
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK
+dictionary_value_is_valid(struct _cef_dictionary_value_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefDictionaryValueCppToC::Get(self)->IsValid();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+dictionary_value_is_owned(struct _cef_dictionary_value_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefDictionaryValueCppToC::Get(self)->IsOwned();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+dictionary_value_is_read_only(struct _cef_dictionary_value_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefDictionaryValueCppToC::Get(self)->IsReadOnly();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+dictionary_value_is_same(struct _cef_dictionary_value_t* self,
+ struct _cef_dictionary_value_t* that) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: that; type: refptr_same
+ DCHECK(that);
+ if (!that) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefDictionaryValueCppToC::Get(self)->IsSame(
+ CefDictionaryValueCppToC::Unwrap(that));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+dictionary_value_is_equal(struct _cef_dictionary_value_t* self,
+ struct _cef_dictionary_value_t* that) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: that; type: refptr_same
+ DCHECK(that);
+ if (!that) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefDictionaryValueCppToC::Get(self)->IsEqual(
+ CefDictionaryValueCppToC::Unwrap(that));
+
+ // Return type: bool
+ return _retval;
+}
+
+struct _cef_dictionary_value_t* CEF_CALLBACK
+dictionary_value_copy(struct _cef_dictionary_value_t* self,
+ int exclude_empty_children) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefDictionaryValue> _retval =
+ CefDictionaryValueCppToC::Get(self)->Copy(exclude_empty_children ? true
+ : false);
+
+ // Return type: refptr_same
+ return CefDictionaryValueCppToC::Wrap(_retval);
+}
+
+size_t CEF_CALLBACK
+dictionary_value_get_size(struct _cef_dictionary_value_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ size_t _retval = CefDictionaryValueCppToC::Get(self)->GetSize();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK dictionary_value_clear(struct _cef_dictionary_value_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefDictionaryValueCppToC::Get(self)->Clear();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK dictionary_value_has_key(struct _cef_dictionary_value_t* self,
+ const cef_string_t* key) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: key; type: string_byref_const
+ DCHECK(key);
+ if (!key) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefDictionaryValueCppToC::Get(self)->HasKey(CefString(key));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK dictionary_value_get_keys(struct _cef_dictionary_value_t* self,
+ cef_string_list_t keys) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: keys; type: string_vec_byref
+ DCHECK(keys);
+ if (!keys) {
+ return 0;
+ }
+
+ // Translate param: keys; type: string_vec_byref
+ std::vector<CefString> keysList;
+ transfer_string_list_contents(keys, keysList);
+
+ // Execute
+ bool _retval = CefDictionaryValueCppToC::Get(self)->GetKeys(keysList);
+
+ // Restore param: keys; type: string_vec_byref
+ cef_string_list_clear(keys);
+ transfer_string_list_contents(keysList, keys);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK dictionary_value_remove(struct _cef_dictionary_value_t* self,
+ const cef_string_t* key) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: key; type: string_byref_const
+ DCHECK(key);
+ if (!key) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefDictionaryValueCppToC::Get(self)->Remove(CefString(key));
+
+ // Return type: bool
+ return _retval;
+}
+
+cef_value_type_t CEF_CALLBACK
+dictionary_value_get_type(struct _cef_dictionary_value_t* self,
+ const cef_string_t* key) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return VTYPE_INVALID;
+ }
+ // Verify param: key; type: string_byref_const
+ DCHECK(key);
+ if (!key) {
+ return VTYPE_INVALID;
+ }
+
+ // Execute
+ cef_value_type_t _retval =
+ CefDictionaryValueCppToC::Get(self)->GetType(CefString(key));
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_value_t* CEF_CALLBACK
+dictionary_value_get_value(struct _cef_dictionary_value_t* self,
+ const cef_string_t* key) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+ // Verify param: key; type: string_byref_const
+ DCHECK(key);
+ if (!key) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefValue> _retval =
+ CefDictionaryValueCppToC::Get(self)->GetValue(CefString(key));
+
+ // Return type: refptr_same
+ return CefValueCppToC::Wrap(_retval);
+}
+
+int CEF_CALLBACK dictionary_value_get_bool(struct _cef_dictionary_value_t* self,
+ const cef_string_t* key) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: key; type: string_byref_const
+ DCHECK(key);
+ if (!key) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefDictionaryValueCppToC::Get(self)->GetBool(CefString(key));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK dictionary_value_get_int(struct _cef_dictionary_value_t* self,
+ const cef_string_t* key) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: key; type: string_byref_const
+ DCHECK(key);
+ if (!key) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefDictionaryValueCppToC::Get(self)->GetInt(CefString(key));
+
+ // Return type: simple
+ return _retval;
+}
+
+double CEF_CALLBACK
+dictionary_value_get_double(struct _cef_dictionary_value_t* self,
+ const cef_string_t* key) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: key; type: string_byref_const
+ DCHECK(key);
+ if (!key) {
+ return 0;
+ }
+
+ // Execute
+ double _retval =
+ CefDictionaryValueCppToC::Get(self)->GetDouble(CefString(key));
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_string_userfree_t CEF_CALLBACK
+dictionary_value_get_string(struct _cef_dictionary_value_t* self,
+ const cef_string_t* key) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+ // Verify param: key; type: string_byref_const
+ DCHECK(key);
+ if (!key) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval =
+ CefDictionaryValueCppToC::Get(self)->GetString(CefString(key));
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_binary_value_t* CEF_CALLBACK
+dictionary_value_get_binary(struct _cef_dictionary_value_t* self,
+ const cef_string_t* key) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+ // Verify param: key; type: string_byref_const
+ DCHECK(key);
+ if (!key) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefBinaryValue> _retval =
+ CefDictionaryValueCppToC::Get(self)->GetBinary(CefString(key));
+
+ // Return type: refptr_same
+ return CefBinaryValueCppToC::Wrap(_retval);
+}
+
+struct _cef_dictionary_value_t* CEF_CALLBACK
+dictionary_value_get_dictionary(struct _cef_dictionary_value_t* self,
+ const cef_string_t* key) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+ // Verify param: key; type: string_byref_const
+ DCHECK(key);
+ if (!key) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefDictionaryValue> _retval =
+ CefDictionaryValueCppToC::Get(self)->GetDictionary(CefString(key));
+
+ // Return type: refptr_same
+ return CefDictionaryValueCppToC::Wrap(_retval);
+}
+
+struct _cef_list_value_t* CEF_CALLBACK
+dictionary_value_get_list(struct _cef_dictionary_value_t* self,
+ const cef_string_t* key) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+ // Verify param: key; type: string_byref_const
+ DCHECK(key);
+ if (!key) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefListValue> _retval =
+ CefDictionaryValueCppToC::Get(self)->GetList(CefString(key));
+
+ // Return type: refptr_same
+ return CefListValueCppToC::Wrap(_retval);
+}
+
+int CEF_CALLBACK
+dictionary_value_set_value(struct _cef_dictionary_value_t* self,
+ const cef_string_t* key,
+ cef_value_t* value) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: key; type: string_byref_const
+ DCHECK(key);
+ if (!key) {
+ return 0;
+ }
+ // Verify param: value; type: refptr_same
+ DCHECK(value);
+ if (!value) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefDictionaryValueCppToC::Get(self)->SetValue(
+ CefString(key), CefValueCppToC::Unwrap(value));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK dictionary_value_set_null(struct _cef_dictionary_value_t* self,
+ const cef_string_t* key) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: key; type: string_byref_const
+ DCHECK(key);
+ if (!key) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefDictionaryValueCppToC::Get(self)->SetNull(CefString(key));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK dictionary_value_set_bool(struct _cef_dictionary_value_t* self,
+ const cef_string_t* key,
+ int value) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: key; type: string_byref_const
+ DCHECK(key);
+ if (!key) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefDictionaryValueCppToC::Get(self)->SetBool(
+ CefString(key), value ? true : false);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK dictionary_value_set_int(struct _cef_dictionary_value_t* self,
+ const cef_string_t* key,
+ int value) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: key; type: string_byref_const
+ DCHECK(key);
+ if (!key) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefDictionaryValueCppToC::Get(self)->SetInt(CefString(key), value);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+dictionary_value_set_double(struct _cef_dictionary_value_t* self,
+ const cef_string_t* key,
+ double value) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: key; type: string_byref_const
+ DCHECK(key);
+ if (!key) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefDictionaryValueCppToC::Get(self)->SetDouble(CefString(key), value);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+dictionary_value_set_string(struct _cef_dictionary_value_t* self,
+ const cef_string_t* key,
+ const cef_string_t* value) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: key; type: string_byref_const
+ DCHECK(key);
+ if (!key) {
+ return 0;
+ }
+ // Unverified params: value
+
+ // Execute
+ bool _retval = CefDictionaryValueCppToC::Get(self)->SetString(
+ CefString(key), CefString(value));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+dictionary_value_set_binary(struct _cef_dictionary_value_t* self,
+ const cef_string_t* key,
+ cef_binary_value_t* value) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: key; type: string_byref_const
+ DCHECK(key);
+ if (!key) {
+ return 0;
+ }
+ // Verify param: value; type: refptr_same
+ DCHECK(value);
+ if (!value) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefDictionaryValueCppToC::Get(self)->SetBinary(
+ CefString(key), CefBinaryValueCppToC::Unwrap(value));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+dictionary_value_set_dictionary(struct _cef_dictionary_value_t* self,
+ const cef_string_t* key,
+ struct _cef_dictionary_value_t* value) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: key; type: string_byref_const
+ DCHECK(key);
+ if (!key) {
+ return 0;
+ }
+ // Verify param: value; type: refptr_same
+ DCHECK(value);
+ if (!value) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefDictionaryValueCppToC::Get(self)->SetDictionary(
+ CefString(key), CefDictionaryValueCppToC::Unwrap(value));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK dictionary_value_set_list(struct _cef_dictionary_value_t* self,
+ const cef_string_t* key,
+ struct _cef_list_value_t* value) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: key; type: string_byref_const
+ DCHECK(key);
+ if (!key) {
+ return 0;
+ }
+ // Verify param: value; type: refptr_same
+ DCHECK(value);
+ if (!value) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefDictionaryValueCppToC::Get(self)->SetList(
+ CefString(key), CefListValueCppToC::Unwrap(value));
+
+ // Return type: bool
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefDictionaryValueCppToC::CefDictionaryValueCppToC() {
+ GetStruct()->is_valid = dictionary_value_is_valid;
+ GetStruct()->is_owned = dictionary_value_is_owned;
+ GetStruct()->is_read_only = dictionary_value_is_read_only;
+ GetStruct()->is_same = dictionary_value_is_same;
+ GetStruct()->is_equal = dictionary_value_is_equal;
+ GetStruct()->copy = dictionary_value_copy;
+ GetStruct()->get_size = dictionary_value_get_size;
+ GetStruct()->clear = dictionary_value_clear;
+ GetStruct()->has_key = dictionary_value_has_key;
+ GetStruct()->get_keys = dictionary_value_get_keys;
+ GetStruct()->remove = dictionary_value_remove;
+ GetStruct()->get_type = dictionary_value_get_type;
+ GetStruct()->get_value = dictionary_value_get_value;
+ GetStruct()->get_bool = dictionary_value_get_bool;
+ GetStruct()->get_int = dictionary_value_get_int;
+ GetStruct()->get_double = dictionary_value_get_double;
+ GetStruct()->get_string = dictionary_value_get_string;
+ GetStruct()->get_binary = dictionary_value_get_binary;
+ GetStruct()->get_dictionary = dictionary_value_get_dictionary;
+ GetStruct()->get_list = dictionary_value_get_list;
+ GetStruct()->set_value = dictionary_value_set_value;
+ GetStruct()->set_null = dictionary_value_set_null;
+ GetStruct()->set_bool = dictionary_value_set_bool;
+ GetStruct()->set_int = dictionary_value_set_int;
+ GetStruct()->set_double = dictionary_value_set_double;
+ GetStruct()->set_string = dictionary_value_set_string;
+ GetStruct()->set_binary = dictionary_value_set_binary;
+ GetStruct()->set_dictionary = dictionary_value_set_dictionary;
+ GetStruct()->set_list = dictionary_value_set_list;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefDictionaryValueCppToC::~CefDictionaryValueCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefDictionaryValue> CefCppToCRefCounted<
+ CefDictionaryValueCppToC,
+ CefDictionaryValue,
+ cef_dictionary_value_t>::UnwrapDerived(CefWrapperType type,
+ cef_dictionary_value_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefDictionaryValueCppToC,
+ CefDictionaryValue,
+ cef_dictionary_value_t>::kWrapperType =
+ WT_DICTIONARY_VALUE;
diff --git a/libcef_dll/cpptoc/dictionary_value_cpptoc.h b/libcef_dll/cpptoc/dictionary_value_cpptoc.h
new file mode 100644
index 00000000..038b5738
--- /dev/null
+++ b/libcef_dll/cpptoc/dictionary_value_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=dd73e5b97103c4ad27620af89886e49bfbdc8d21$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_DICTIONARY_VALUE_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_DICTIONARY_VALUE_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_values_capi.h"
+#include "include/cef_values.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefDictionaryValueCppToC
+ : public CefCppToCRefCounted<CefDictionaryValueCppToC,
+ CefDictionaryValue,
+ cef_dictionary_value_t> {
+ public:
+ CefDictionaryValueCppToC();
+ virtual ~CefDictionaryValueCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_DICTIONARY_VALUE_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/display_handler_cpptoc.cc b/libcef_dll/cpptoc/display_handler_cpptoc.cc
new file mode 100644
index 00000000..27692b7a
--- /dev/null
+++ b/libcef_dll/cpptoc/display_handler_cpptoc.cc
@@ -0,0 +1,378 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=e898cf0b420fd86d6dd345fdae18f297da93a09b$
+//
+
+#include "libcef_dll/cpptoc/display_handler_cpptoc.h"
+#include "libcef_dll/ctocpp/browser_ctocpp.h"
+#include "libcef_dll/ctocpp/frame_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+#include "libcef_dll/transfer_util.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK
+display_handler_on_address_change(struct _cef_display_handler_t* self,
+ cef_browser_t* browser,
+ struct _cef_frame_t* frame,
+ const cef_string_t* url) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+ // Verify param: frame; type: refptr_diff
+ DCHECK(frame);
+ if (!frame) {
+ return;
+ }
+ // Verify param: url; type: string_byref_const
+ DCHECK(url);
+ if (!url) {
+ return;
+ }
+
+ // Execute
+ CefDisplayHandlerCppToC::Get(self)->OnAddressChange(
+ CefBrowserCToCpp::Wrap(browser), CefFrameCToCpp::Wrap(frame),
+ CefString(url));
+}
+
+void CEF_CALLBACK
+display_handler_on_title_change(struct _cef_display_handler_t* self,
+ cef_browser_t* browser,
+ const cef_string_t* title) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+ // Unverified params: title
+
+ // Execute
+ CefDisplayHandlerCppToC::Get(self)->OnTitleChange(
+ CefBrowserCToCpp::Wrap(browser), CefString(title));
+}
+
+void CEF_CALLBACK
+display_handler_on_favicon_urlchange(struct _cef_display_handler_t* self,
+ cef_browser_t* browser,
+ cef_string_list_t icon_urls) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+ // Unverified params: icon_urls
+
+ // Translate param: icon_urls; type: string_vec_byref_const
+ std::vector<CefString> icon_urlsList;
+ transfer_string_list_contents(icon_urls, icon_urlsList);
+
+ // Execute
+ CefDisplayHandlerCppToC::Get(self)->OnFaviconURLChange(
+ CefBrowserCToCpp::Wrap(browser), icon_urlsList);
+}
+
+void CEF_CALLBACK
+display_handler_on_fullscreen_mode_change(struct _cef_display_handler_t* self,
+ cef_browser_t* browser,
+ int fullscreen) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+
+ // Execute
+ CefDisplayHandlerCppToC::Get(self)->OnFullscreenModeChange(
+ CefBrowserCToCpp::Wrap(browser), fullscreen ? true : false);
+}
+
+int CEF_CALLBACK display_handler_on_tooltip(struct _cef_display_handler_t* self,
+ cef_browser_t* browser,
+ cef_string_t* text) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return 0;
+ }
+ // Unverified params: text
+
+ // Translate param: text; type: string_byref
+ CefString textStr(text);
+
+ // Execute
+ bool _retval = CefDisplayHandlerCppToC::Get(self)->OnTooltip(
+ CefBrowserCToCpp::Wrap(browser), textStr);
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK
+display_handler_on_status_message(struct _cef_display_handler_t* self,
+ cef_browser_t* browser,
+ const cef_string_t* value) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+ // Unverified params: value
+
+ // Execute
+ CefDisplayHandlerCppToC::Get(self)->OnStatusMessage(
+ CefBrowserCToCpp::Wrap(browser), CefString(value));
+}
+
+int CEF_CALLBACK
+display_handler_on_console_message(struct _cef_display_handler_t* self,
+ cef_browser_t* browser,
+ cef_log_severity_t level,
+ const cef_string_t* message,
+ const cef_string_t* source,
+ int line) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return 0;
+ }
+ // Unverified params: message, source
+
+ // Execute
+ bool _retval = CefDisplayHandlerCppToC::Get(self)->OnConsoleMessage(
+ CefBrowserCToCpp::Wrap(browser), level, CefString(message),
+ CefString(source), line);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+display_handler_on_auto_resize(struct _cef_display_handler_t* self,
+ cef_browser_t* browser,
+ const cef_size_t* new_size) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return 0;
+ }
+ // Verify param: new_size; type: simple_byref_const
+ DCHECK(new_size);
+ if (!new_size) {
+ return 0;
+ }
+
+ // Translate param: new_size; type: simple_byref_const
+ CefSize new_sizeVal = new_size ? *new_size : CefSize();
+
+ // Execute
+ bool _retval = CefDisplayHandlerCppToC::Get(self)->OnAutoResize(
+ CefBrowserCToCpp::Wrap(browser), new_sizeVal);
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK
+display_handler_on_loading_progress_change(struct _cef_display_handler_t* self,
+ cef_browser_t* browser,
+ double progress) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+
+ // Execute
+ CefDisplayHandlerCppToC::Get(self)->OnLoadingProgressChange(
+ CefBrowserCToCpp::Wrap(browser), progress);
+}
+
+int CEF_CALLBACK
+display_handler_on_cursor_change(struct _cef_display_handler_t* self,
+ cef_browser_t* browser,
+ cef_cursor_handle_t cursor,
+ cef_cursor_type_t type,
+ const cef_cursor_info_t* custom_cursor_info) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return 0;
+ }
+ // Verify param: custom_cursor_info; type: simple_byref_const
+ DCHECK(custom_cursor_info);
+ if (!custom_cursor_info) {
+ return 0;
+ }
+
+ // Translate param: custom_cursor_info; type: simple_byref_const
+ CefCursorInfo custom_cursor_infoVal =
+ custom_cursor_info ? *custom_cursor_info : CefCursorInfo();
+
+ // Execute
+ bool _retval = CefDisplayHandlerCppToC::Get(self)->OnCursorChange(
+ CefBrowserCToCpp::Wrap(browser), cursor, type, custom_cursor_infoVal);
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK
+display_handler_on_media_access_change(struct _cef_display_handler_t* self,
+ cef_browser_t* browser,
+ int has_video_access,
+ int has_audio_access) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+
+ // Execute
+ CefDisplayHandlerCppToC::Get(self)->OnMediaAccessChange(
+ CefBrowserCToCpp::Wrap(browser), has_video_access ? true : false,
+ has_audio_access ? true : false);
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefDisplayHandlerCppToC::CefDisplayHandlerCppToC() {
+ GetStruct()->on_address_change = display_handler_on_address_change;
+ GetStruct()->on_title_change = display_handler_on_title_change;
+ GetStruct()->on_favicon_urlchange = display_handler_on_favicon_urlchange;
+ GetStruct()->on_fullscreen_mode_change =
+ display_handler_on_fullscreen_mode_change;
+ GetStruct()->on_tooltip = display_handler_on_tooltip;
+ GetStruct()->on_status_message = display_handler_on_status_message;
+ GetStruct()->on_console_message = display_handler_on_console_message;
+ GetStruct()->on_auto_resize = display_handler_on_auto_resize;
+ GetStruct()->on_loading_progress_change =
+ display_handler_on_loading_progress_change;
+ GetStruct()->on_cursor_change = display_handler_on_cursor_change;
+ GetStruct()->on_media_access_change = display_handler_on_media_access_change;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefDisplayHandlerCppToC::~CefDisplayHandlerCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefDisplayHandler> CefCppToCRefCounted<
+ CefDisplayHandlerCppToC,
+ CefDisplayHandler,
+ cef_display_handler_t>::UnwrapDerived(CefWrapperType type,
+ cef_display_handler_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefDisplayHandlerCppToC,
+ CefDisplayHandler,
+ cef_display_handler_t>::kWrapperType =
+ WT_DISPLAY_HANDLER;
diff --git a/libcef_dll/cpptoc/display_handler_cpptoc.h b/libcef_dll/cpptoc/display_handler_cpptoc.h
new file mode 100644
index 00000000..ccc1e439
--- /dev/null
+++ b/libcef_dll/cpptoc/display_handler_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=8ba6fb9ce96e92ba80a05258060e530ddf822264$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_DISPLAY_HANDLER_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_DISPLAY_HANDLER_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_display_handler_capi.h"
+#include "include/cef_display_handler.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefDisplayHandlerCppToC
+ : public CefCppToCRefCounted<CefDisplayHandlerCppToC,
+ CefDisplayHandler,
+ cef_display_handler_t> {
+ public:
+ CefDisplayHandlerCppToC();
+ virtual ~CefDisplayHandlerCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_DISPLAY_HANDLER_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/domdocument_cpptoc.cc b/libcef_dll/cpptoc/domdocument_cpptoc.cc
new file mode 100644
index 00000000..aa500bdc
--- /dev/null
+++ b/libcef_dll/cpptoc/domdocument_cpptoc.cc
@@ -0,0 +1,330 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=bb85a1fcd9a95568fc9887f490e817ccb67a2971$
+//
+
+#include "libcef_dll/cpptoc/domdocument_cpptoc.h"
+#include "libcef_dll/cpptoc/domnode_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+cef_dom_document_type_t CEF_CALLBACK
+domdocument_get_type(struct _cef_domdocument_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return DOM_DOCUMENT_TYPE_UNKNOWN;
+ }
+
+ // Execute
+ cef_dom_document_type_t _retval = CefDOMDocumentCppToC::Get(self)->GetType();
+
+ // Return type: simple
+ return _retval;
+}
+
+struct _cef_domnode_t* CEF_CALLBACK
+domdocument_get_document(struct _cef_domdocument_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefDOMNode> _retval =
+ CefDOMDocumentCppToC::Get(self)->GetDocument();
+
+ // Return type: refptr_same
+ return CefDOMNodeCppToC::Wrap(_retval);
+}
+
+struct _cef_domnode_t* CEF_CALLBACK
+domdocument_get_body(struct _cef_domdocument_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefDOMNode> _retval = CefDOMDocumentCppToC::Get(self)->GetBody();
+
+ // Return type: refptr_same
+ return CefDOMNodeCppToC::Wrap(_retval);
+}
+
+struct _cef_domnode_t* CEF_CALLBACK
+domdocument_get_head(struct _cef_domdocument_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefDOMNode> _retval = CefDOMDocumentCppToC::Get(self)->GetHead();
+
+ // Return type: refptr_same
+ return CefDOMNodeCppToC::Wrap(_retval);
+}
+
+cef_string_userfree_t CEF_CALLBACK
+domdocument_get_title(struct _cef_domdocument_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefDOMDocumentCppToC::Get(self)->GetTitle();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+struct _cef_domnode_t* CEF_CALLBACK
+domdocument_get_element_by_id(struct _cef_domdocument_t* self,
+ const cef_string_t* id) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+ // Verify param: id; type: string_byref_const
+ DCHECK(id);
+ if (!id) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefDOMNode> _retval =
+ CefDOMDocumentCppToC::Get(self)->GetElementById(CefString(id));
+
+ // Return type: refptr_same
+ return CefDOMNodeCppToC::Wrap(_retval);
+}
+
+struct _cef_domnode_t* CEF_CALLBACK
+domdocument_get_focused_node(struct _cef_domdocument_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefDOMNode> _retval =
+ CefDOMDocumentCppToC::Get(self)->GetFocusedNode();
+
+ // Return type: refptr_same
+ return CefDOMNodeCppToC::Wrap(_retval);
+}
+
+int CEF_CALLBACK domdocument_has_selection(struct _cef_domdocument_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefDOMDocumentCppToC::Get(self)->HasSelection();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+domdocument_get_selection_start_offset(struct _cef_domdocument_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefDOMDocumentCppToC::Get(self)->GetSelectionStartOffset();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK
+domdocument_get_selection_end_offset(struct _cef_domdocument_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefDOMDocumentCppToC::Get(self)->GetSelectionEndOffset();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_string_userfree_t CEF_CALLBACK
+domdocument_get_selection_as_markup(struct _cef_domdocument_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefDOMDocumentCppToC::Get(self)->GetSelectionAsMarkup();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_string_userfree_t CEF_CALLBACK
+domdocument_get_selection_as_text(struct _cef_domdocument_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefDOMDocumentCppToC::Get(self)->GetSelectionAsText();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_string_userfree_t CEF_CALLBACK
+domdocument_get_base_url(struct _cef_domdocument_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefDOMDocumentCppToC::Get(self)->GetBaseURL();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_string_userfree_t CEF_CALLBACK
+domdocument_get_complete_url(struct _cef_domdocument_t* self,
+ const cef_string_t* partialURL) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+ // Verify param: partialURL; type: string_byref_const
+ DCHECK(partialURL);
+ if (!partialURL) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval =
+ CefDOMDocumentCppToC::Get(self)->GetCompleteURL(CefString(partialURL));
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefDOMDocumentCppToC::CefDOMDocumentCppToC() {
+ GetStruct()->get_type = domdocument_get_type;
+ GetStruct()->get_document = domdocument_get_document;
+ GetStruct()->get_body = domdocument_get_body;
+ GetStruct()->get_head = domdocument_get_head;
+ GetStruct()->get_title = domdocument_get_title;
+ GetStruct()->get_element_by_id = domdocument_get_element_by_id;
+ GetStruct()->get_focused_node = domdocument_get_focused_node;
+ GetStruct()->has_selection = domdocument_has_selection;
+ GetStruct()->get_selection_start_offset =
+ domdocument_get_selection_start_offset;
+ GetStruct()->get_selection_end_offset = domdocument_get_selection_end_offset;
+ GetStruct()->get_selection_as_markup = domdocument_get_selection_as_markup;
+ GetStruct()->get_selection_as_text = domdocument_get_selection_as_text;
+ GetStruct()->get_base_url = domdocument_get_base_url;
+ GetStruct()->get_complete_url = domdocument_get_complete_url;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefDOMDocumentCppToC::~CefDOMDocumentCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefDOMDocument>
+CefCppToCRefCounted<CefDOMDocumentCppToC, CefDOMDocument, cef_domdocument_t>::
+ UnwrapDerived(CefWrapperType type, cef_domdocument_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefDOMDocumentCppToC,
+ CefDOMDocument,
+ cef_domdocument_t>::kWrapperType =
+ WT_DOMDOCUMENT;
diff --git a/libcef_dll/cpptoc/domdocument_cpptoc.h b/libcef_dll/cpptoc/domdocument_cpptoc.h
new file mode 100644
index 00000000..bdf946cb
--- /dev/null
+++ b/libcef_dll/cpptoc/domdocument_cpptoc.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=6a5b9bb0155acb8c5e6f796e68463825e00a8e53$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_DOMDOCUMENT_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_DOMDOCUMENT_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_dom_capi.h"
+#include "include/cef_dom.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefDOMDocumentCppToC : public CefCppToCRefCounted<CefDOMDocumentCppToC,
+ CefDOMDocument,
+ cef_domdocument_t> {
+ public:
+ CefDOMDocumentCppToC();
+ virtual ~CefDOMDocumentCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_DOMDOCUMENT_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/domnode_cpptoc.cc b/libcef_dll/cpptoc/domnode_cpptoc.cc
new file mode 100644
index 00000000..20f190bd
--- /dev/null
+++ b/libcef_dll/cpptoc/domnode_cpptoc.cc
@@ -0,0 +1,585 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=92ad2a43af7fd73add03e0ed4c053d5e3d3595a7$
+//
+
+#include "libcef_dll/cpptoc/domnode_cpptoc.h"
+#include "libcef_dll/cpptoc/domdocument_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+#include "libcef_dll/transfer_util.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+cef_dom_node_type_t CEF_CALLBACK domnode_get_type(struct _cef_domnode_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return DOM_NODE_TYPE_UNSUPPORTED;
+ }
+
+ // Execute
+ cef_dom_node_type_t _retval = CefDOMNodeCppToC::Get(self)->GetType();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK domnode_is_text(struct _cef_domnode_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefDOMNodeCppToC::Get(self)->IsText();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK domnode_is_element(struct _cef_domnode_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefDOMNodeCppToC::Get(self)->IsElement();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK domnode_is_editable(struct _cef_domnode_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefDOMNodeCppToC::Get(self)->IsEditable();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK domnode_is_form_control_element(struct _cef_domnode_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefDOMNodeCppToC::Get(self)->IsFormControlElement();
+
+ // Return type: bool
+ return _retval;
+}
+
+cef_string_userfree_t CEF_CALLBACK
+domnode_get_form_control_element_type(struct _cef_domnode_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefDOMNodeCppToC::Get(self)->GetFormControlElementType();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+int CEF_CALLBACK domnode_is_same(struct _cef_domnode_t* self,
+ struct _cef_domnode_t* that) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: that; type: refptr_same
+ DCHECK(that);
+ if (!that) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefDOMNodeCppToC::Get(self)->IsSame(CefDOMNodeCppToC::Unwrap(that));
+
+ // Return type: bool
+ return _retval;
+}
+
+cef_string_userfree_t CEF_CALLBACK
+domnode_get_name(struct _cef_domnode_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefDOMNodeCppToC::Get(self)->GetName();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_string_userfree_t CEF_CALLBACK
+domnode_get_value(struct _cef_domnode_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefDOMNodeCppToC::Get(self)->GetValue();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+int CEF_CALLBACK domnode_set_value(struct _cef_domnode_t* self,
+ const cef_string_t* value) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: value; type: string_byref_const
+ DCHECK(value);
+ if (!value) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefDOMNodeCppToC::Get(self)->SetValue(CefString(value));
+
+ // Return type: bool
+ return _retval;
+}
+
+cef_string_userfree_t CEF_CALLBACK
+domnode_get_as_markup(struct _cef_domnode_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefDOMNodeCppToC::Get(self)->GetAsMarkup();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_domdocument_t* CEF_CALLBACK
+domnode_get_document(struct _cef_domnode_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefDOMDocument> _retval =
+ CefDOMNodeCppToC::Get(self)->GetDocument();
+
+ // Return type: refptr_same
+ return CefDOMDocumentCppToC::Wrap(_retval);
+}
+
+struct _cef_domnode_t* CEF_CALLBACK
+domnode_get_parent(struct _cef_domnode_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefDOMNode> _retval = CefDOMNodeCppToC::Get(self)->GetParent();
+
+ // Return type: refptr_same
+ return CefDOMNodeCppToC::Wrap(_retval);
+}
+
+struct _cef_domnode_t* CEF_CALLBACK
+domnode_get_previous_sibling(struct _cef_domnode_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefDOMNode> _retval =
+ CefDOMNodeCppToC::Get(self)->GetPreviousSibling();
+
+ // Return type: refptr_same
+ return CefDOMNodeCppToC::Wrap(_retval);
+}
+
+struct _cef_domnode_t* CEF_CALLBACK
+domnode_get_next_sibling(struct _cef_domnode_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefDOMNode> _retval = CefDOMNodeCppToC::Get(self)->GetNextSibling();
+
+ // Return type: refptr_same
+ return CefDOMNodeCppToC::Wrap(_retval);
+}
+
+int CEF_CALLBACK domnode_has_children(struct _cef_domnode_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefDOMNodeCppToC::Get(self)->HasChildren();
+
+ // Return type: bool
+ return _retval;
+}
+
+struct _cef_domnode_t* CEF_CALLBACK
+domnode_get_first_child(struct _cef_domnode_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefDOMNode> _retval = CefDOMNodeCppToC::Get(self)->GetFirstChild();
+
+ // Return type: refptr_same
+ return CefDOMNodeCppToC::Wrap(_retval);
+}
+
+struct _cef_domnode_t* CEF_CALLBACK
+domnode_get_last_child(struct _cef_domnode_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefDOMNode> _retval = CefDOMNodeCppToC::Get(self)->GetLastChild();
+
+ // Return type: refptr_same
+ return CefDOMNodeCppToC::Wrap(_retval);
+}
+
+cef_string_userfree_t CEF_CALLBACK
+domnode_get_element_tag_name(struct _cef_domnode_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefDOMNodeCppToC::Get(self)->GetElementTagName();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+int CEF_CALLBACK domnode_has_element_attributes(struct _cef_domnode_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefDOMNodeCppToC::Get(self)->HasElementAttributes();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK domnode_has_element_attribute(struct _cef_domnode_t* self,
+ const cef_string_t* attrName) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: attrName; type: string_byref_const
+ DCHECK(attrName);
+ if (!attrName) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefDOMNodeCppToC::Get(self)->HasElementAttribute(CefString(attrName));
+
+ // Return type: bool
+ return _retval;
+}
+
+cef_string_userfree_t CEF_CALLBACK
+domnode_get_element_attribute(struct _cef_domnode_t* self,
+ const cef_string_t* attrName) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+ // Verify param: attrName; type: string_byref_const
+ DCHECK(attrName);
+ if (!attrName) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval =
+ CefDOMNodeCppToC::Get(self)->GetElementAttribute(CefString(attrName));
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+void CEF_CALLBACK domnode_get_element_attributes(struct _cef_domnode_t* self,
+ cef_string_map_t attrMap) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: attrMap; type: string_map_single_byref
+ DCHECK(attrMap);
+ if (!attrMap) {
+ return;
+ }
+
+ // Translate param: attrMap; type: string_map_single_byref
+ std::map<CefString, CefString> attrMapMap;
+ transfer_string_map_contents(attrMap, attrMapMap);
+
+ // Execute
+ CefDOMNodeCppToC::Get(self)->GetElementAttributes(attrMapMap);
+
+ // Restore param: attrMap; type: string_map_single_byref
+ cef_string_map_clear(attrMap);
+ transfer_string_map_contents(attrMapMap, attrMap);
+}
+
+int CEF_CALLBACK domnode_set_element_attribute(struct _cef_domnode_t* self,
+ const cef_string_t* attrName,
+ const cef_string_t* value) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: attrName; type: string_byref_const
+ DCHECK(attrName);
+ if (!attrName) {
+ return 0;
+ }
+ // Verify param: value; type: string_byref_const
+ DCHECK(value);
+ if (!value) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefDOMNodeCppToC::Get(self)->SetElementAttribute(
+ CefString(attrName), CefString(value));
+
+ // Return type: bool
+ return _retval;
+}
+
+cef_string_userfree_t CEF_CALLBACK
+domnode_get_element_inner_text(struct _cef_domnode_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefDOMNodeCppToC::Get(self)->GetElementInnerText();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_rect_t CEF_CALLBACK
+domnode_get_element_bounds(struct _cef_domnode_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefRect();
+ }
+
+ // Execute
+ cef_rect_t _retval = CefDOMNodeCppToC::Get(self)->GetElementBounds();
+
+ // Return type: simple
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefDOMNodeCppToC::CefDOMNodeCppToC() {
+ GetStruct()->get_type = domnode_get_type;
+ GetStruct()->is_text = domnode_is_text;
+ GetStruct()->is_element = domnode_is_element;
+ GetStruct()->is_editable = domnode_is_editable;
+ GetStruct()->is_form_control_element = domnode_is_form_control_element;
+ GetStruct()->get_form_control_element_type =
+ domnode_get_form_control_element_type;
+ GetStruct()->is_same = domnode_is_same;
+ GetStruct()->get_name = domnode_get_name;
+ GetStruct()->get_value = domnode_get_value;
+ GetStruct()->set_value = domnode_set_value;
+ GetStruct()->get_as_markup = domnode_get_as_markup;
+ GetStruct()->get_document = domnode_get_document;
+ GetStruct()->get_parent = domnode_get_parent;
+ GetStruct()->get_previous_sibling = domnode_get_previous_sibling;
+ GetStruct()->get_next_sibling = domnode_get_next_sibling;
+ GetStruct()->has_children = domnode_has_children;
+ GetStruct()->get_first_child = domnode_get_first_child;
+ GetStruct()->get_last_child = domnode_get_last_child;
+ GetStruct()->get_element_tag_name = domnode_get_element_tag_name;
+ GetStruct()->has_element_attributes = domnode_has_element_attributes;
+ GetStruct()->has_element_attribute = domnode_has_element_attribute;
+ GetStruct()->get_element_attribute = domnode_get_element_attribute;
+ GetStruct()->get_element_attributes = domnode_get_element_attributes;
+ GetStruct()->set_element_attribute = domnode_set_element_attribute;
+ GetStruct()->get_element_inner_text = domnode_get_element_inner_text;
+ GetStruct()->get_element_bounds = domnode_get_element_bounds;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefDOMNodeCppToC::~CefDOMNodeCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefDOMNode>
+CefCppToCRefCounted<CefDOMNodeCppToC, CefDOMNode, cef_domnode_t>::UnwrapDerived(
+ CefWrapperType type,
+ cef_domnode_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefDOMNodeCppToC,
+ CefDOMNode,
+ cef_domnode_t>::kWrapperType = WT_DOMNODE;
diff --git a/libcef_dll/cpptoc/domnode_cpptoc.h b/libcef_dll/cpptoc/domnode_cpptoc.h
new file mode 100644
index 00000000..c11783f8
--- /dev/null
+++ b/libcef_dll/cpptoc/domnode_cpptoc.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=18f223a2671334b8bd8d463a94b5a3c0191141e8$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_DOMNODE_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_DOMNODE_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_dom_capi.h"
+#include "include/cef_dom.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefDOMNodeCppToC
+ : public CefCppToCRefCounted<CefDOMNodeCppToC, CefDOMNode, cef_domnode_t> {
+ public:
+ CefDOMNodeCppToC();
+ virtual ~CefDOMNodeCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_DOMNODE_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/domvisitor_cpptoc.cc b/libcef_dll/cpptoc/domvisitor_cpptoc.cc
new file mode 100644
index 00000000..867d2534
--- /dev/null
+++ b/libcef_dll/cpptoc/domvisitor_cpptoc.cc
@@ -0,0 +1,69 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=1e896513b946d3e3d3199a1fb6cccf31898d6cbc$
+//
+
+#include "libcef_dll/cpptoc/domvisitor_cpptoc.h"
+#include "libcef_dll/ctocpp/domdocument_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK domvisitor_visit(struct _cef_domvisitor_t* self,
+ struct _cef_domdocument_t* document) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: document; type: refptr_diff
+ DCHECK(document);
+ if (!document) {
+ return;
+ }
+
+ // Execute
+ CefDOMVisitorCppToC::Get(self)->Visit(CefDOMDocumentCToCpp::Wrap(document));
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefDOMVisitorCppToC::CefDOMVisitorCppToC() {
+ GetStruct()->visit = domvisitor_visit;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefDOMVisitorCppToC::~CefDOMVisitorCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefDOMVisitor>
+CefCppToCRefCounted<CefDOMVisitorCppToC, CefDOMVisitor, cef_domvisitor_t>::
+ UnwrapDerived(CefWrapperType type, cef_domvisitor_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefDOMVisitorCppToC,
+ CefDOMVisitor,
+ cef_domvisitor_t>::kWrapperType =
+ WT_DOMVISITOR;
diff --git a/libcef_dll/cpptoc/domvisitor_cpptoc.h b/libcef_dll/cpptoc/domvisitor_cpptoc.h
new file mode 100644
index 00000000..3cd81a5e
--- /dev/null
+++ b/libcef_dll/cpptoc/domvisitor_cpptoc.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=2a64ff6edd81d5158997158c91e75b85dbd8da39$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_DOMVISITOR_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_DOMVISITOR_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_dom_capi.h"
+#include "include/cef_dom.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefDOMVisitorCppToC : public CefCppToCRefCounted<CefDOMVisitorCppToC,
+ CefDOMVisitor,
+ cef_domvisitor_t> {
+ public:
+ CefDOMVisitorCppToC();
+ virtual ~CefDOMVisitorCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_DOMVISITOR_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/download_handler_cpptoc.cc b/libcef_dll/cpptoc/download_handler_cpptoc.cc
new file mode 100644
index 00000000..87741dd9
--- /dev/null
+++ b/libcef_dll/cpptoc/download_handler_cpptoc.cc
@@ -0,0 +1,172 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=91026e0ecc2c0ef824ed8727e1bdbc21c17eea74$
+//
+
+#include "libcef_dll/cpptoc/download_handler_cpptoc.h"
+#include "libcef_dll/ctocpp/before_download_callback_ctocpp.h"
+#include "libcef_dll/ctocpp/browser_ctocpp.h"
+#include "libcef_dll/ctocpp/download_item_callback_ctocpp.h"
+#include "libcef_dll/ctocpp/download_item_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK
+download_handler_can_download(struct _cef_download_handler_t* self,
+ cef_browser_t* browser,
+ const cef_string_t* url,
+ const cef_string_t* request_method) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return 0;
+ }
+ // Verify param: url; type: string_byref_const
+ DCHECK(url);
+ if (!url) {
+ return 0;
+ }
+ // Verify param: request_method; type: string_byref_const
+ DCHECK(request_method);
+ if (!request_method) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefDownloadHandlerCppToC::Get(self)->CanDownload(
+ CefBrowserCToCpp::Wrap(browser), CefString(url),
+ CefString(request_method));
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK
+download_handler_on_before_download(struct _cef_download_handler_t* self,
+ cef_browser_t* browser,
+ struct _cef_download_item_t* download_item,
+ const cef_string_t* suggested_name,
+ cef_before_download_callback_t* callback) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+ // Verify param: download_item; type: refptr_diff
+ DCHECK(download_item);
+ if (!download_item) {
+ return;
+ }
+ // Verify param: suggested_name; type: string_byref_const
+ DCHECK(suggested_name);
+ if (!suggested_name) {
+ return;
+ }
+ // Verify param: callback; type: refptr_diff
+ DCHECK(callback);
+ if (!callback) {
+ return;
+ }
+
+ // Execute
+ CefDownloadHandlerCppToC::Get(self)->OnBeforeDownload(
+ CefBrowserCToCpp::Wrap(browser),
+ CefDownloadItemCToCpp::Wrap(download_item), CefString(suggested_name),
+ CefBeforeDownloadCallbackCToCpp::Wrap(callback));
+}
+
+void CEF_CALLBACK
+download_handler_on_download_updated(struct _cef_download_handler_t* self,
+ cef_browser_t* browser,
+ struct _cef_download_item_t* download_item,
+ cef_download_item_callback_t* callback) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+ // Verify param: download_item; type: refptr_diff
+ DCHECK(download_item);
+ if (!download_item) {
+ return;
+ }
+ // Verify param: callback; type: refptr_diff
+ DCHECK(callback);
+ if (!callback) {
+ return;
+ }
+
+ // Execute
+ CefDownloadHandlerCppToC::Get(self)->OnDownloadUpdated(
+ CefBrowserCToCpp::Wrap(browser),
+ CefDownloadItemCToCpp::Wrap(download_item),
+ CefDownloadItemCallbackCToCpp::Wrap(callback));
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefDownloadHandlerCppToC::CefDownloadHandlerCppToC() {
+ GetStruct()->can_download = download_handler_can_download;
+ GetStruct()->on_before_download = download_handler_on_before_download;
+ GetStruct()->on_download_updated = download_handler_on_download_updated;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefDownloadHandlerCppToC::~CefDownloadHandlerCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefDownloadHandler> CefCppToCRefCounted<
+ CefDownloadHandlerCppToC,
+ CefDownloadHandler,
+ cef_download_handler_t>::UnwrapDerived(CefWrapperType type,
+ cef_download_handler_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefDownloadHandlerCppToC,
+ CefDownloadHandler,
+ cef_download_handler_t>::kWrapperType =
+ WT_DOWNLOAD_HANDLER;
diff --git a/libcef_dll/cpptoc/download_handler_cpptoc.h b/libcef_dll/cpptoc/download_handler_cpptoc.h
new file mode 100644
index 00000000..1c1c6ddb
--- /dev/null
+++ b/libcef_dll/cpptoc/download_handler_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=1b301493e2f905a2761858e2d6623765a540f918$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_DOWNLOAD_HANDLER_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_DOWNLOAD_HANDLER_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_download_handler_capi.h"
+#include "include/cef_download_handler.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefDownloadHandlerCppToC
+ : public CefCppToCRefCounted<CefDownloadHandlerCppToC,
+ CefDownloadHandler,
+ cef_download_handler_t> {
+ public:
+ CefDownloadHandlerCppToC();
+ virtual ~CefDownloadHandlerCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_DOWNLOAD_HANDLER_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/download_image_callback_cpptoc.cc b/libcef_dll/cpptoc/download_image_callback_cpptoc.cc
new file mode 100644
index 00000000..b2139c03
--- /dev/null
+++ b/libcef_dll/cpptoc/download_image_callback_cpptoc.cc
@@ -0,0 +1,79 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=d097e0275625031a367f9d2734f372c62ff6dfeb$
+//
+
+#include "libcef_dll/cpptoc/download_image_callback_cpptoc.h"
+#include "libcef_dll/ctocpp/image_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK download_image_callback_on_download_image_finished(
+ struct _cef_download_image_callback_t* self,
+ const cef_string_t* image_url,
+ int http_status_code,
+ struct _cef_image_t* image) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: image_url; type: string_byref_const
+ DCHECK(image_url);
+ if (!image_url) {
+ return;
+ }
+ // Unverified params: image
+
+ // Execute
+ CefDownloadImageCallbackCppToC::Get(self)->OnDownloadImageFinished(
+ CefString(image_url), http_status_code, CefImageCToCpp::Wrap(image));
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefDownloadImageCallbackCppToC::CefDownloadImageCallbackCppToC() {
+ GetStruct()->on_download_image_finished =
+ download_image_callback_on_download_image_finished;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefDownloadImageCallbackCppToC::~CefDownloadImageCallbackCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefDownloadImageCallback> CefCppToCRefCounted<
+ CefDownloadImageCallbackCppToC,
+ CefDownloadImageCallback,
+ cef_download_image_callback_t>::UnwrapDerived(CefWrapperType type,
+ cef_download_image_callback_t*
+ s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCppToCRefCounted<CefDownloadImageCallbackCppToC,
+ CefDownloadImageCallback,
+ cef_download_image_callback_t>::kWrapperType =
+ WT_DOWNLOAD_IMAGE_CALLBACK;
diff --git a/libcef_dll/cpptoc/download_image_callback_cpptoc.h b/libcef_dll/cpptoc/download_image_callback_cpptoc.h
new file mode 100644
index 00000000..8e517c7c
--- /dev/null
+++ b/libcef_dll/cpptoc/download_image_callback_cpptoc.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=9a9250d7e4f3d2018c4b441e6616930627625b59$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_DOWNLOAD_IMAGE_CALLBACK_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_DOWNLOAD_IMAGE_CALLBACK_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_browser_capi.h"
+#include "include/capi/cef_client_capi.h"
+#include "include/cef_browser.h"
+#include "include/cef_client.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefDownloadImageCallbackCppToC
+ : public CefCppToCRefCounted<CefDownloadImageCallbackCppToC,
+ CefDownloadImageCallback,
+ cef_download_image_callback_t> {
+ public:
+ CefDownloadImageCallbackCppToC();
+ virtual ~CefDownloadImageCallbackCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_DOWNLOAD_IMAGE_CALLBACK_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/download_item_callback_cpptoc.cc b/libcef_dll/cpptoc/download_item_callback_cpptoc.cc
new file mode 100644
index 00000000..2af2d223
--- /dev/null
+++ b/libcef_dll/cpptoc/download_item_callback_cpptoc.cc
@@ -0,0 +1,98 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=8b63291230c3edaf9568ebf29171722403232b0d$
+//
+
+#include "libcef_dll/cpptoc/download_item_callback_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK
+download_item_callback_cancel(struct _cef_download_item_callback_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefDownloadItemCallbackCppToC::Get(self)->Cancel();
+}
+
+void CEF_CALLBACK
+download_item_callback_pause(struct _cef_download_item_callback_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefDownloadItemCallbackCppToC::Get(self)->Pause();
+}
+
+void CEF_CALLBACK
+download_item_callback_resume(struct _cef_download_item_callback_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefDownloadItemCallbackCppToC::Get(self)->Resume();
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefDownloadItemCallbackCppToC::CefDownloadItemCallbackCppToC() {
+ GetStruct()->cancel = download_item_callback_cancel;
+ GetStruct()->pause = download_item_callback_pause;
+ GetStruct()->resume = download_item_callback_resume;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefDownloadItemCallbackCppToC::~CefDownloadItemCallbackCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefDownloadItemCallback> CefCppToCRefCounted<
+ CefDownloadItemCallbackCppToC,
+ CefDownloadItemCallback,
+ cef_download_item_callback_t>::UnwrapDerived(CefWrapperType type,
+ cef_download_item_callback_t*
+ s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefDownloadItemCallbackCppToC,
+ CefDownloadItemCallback,
+ cef_download_item_callback_t>::kWrapperType =
+ WT_DOWNLOAD_ITEM_CALLBACK;
diff --git a/libcef_dll/cpptoc/download_item_callback_cpptoc.h b/libcef_dll/cpptoc/download_item_callback_cpptoc.h
new file mode 100644
index 00000000..858baa2f
--- /dev/null
+++ b/libcef_dll/cpptoc/download_item_callback_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=1c85860b0d21f2efc1610ed47af70ed570f63926$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_DOWNLOAD_ITEM_CALLBACK_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_DOWNLOAD_ITEM_CALLBACK_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_download_handler_capi.h"
+#include "include/cef_download_handler.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefDownloadItemCallbackCppToC
+ : public CefCppToCRefCounted<CefDownloadItemCallbackCppToC,
+ CefDownloadItemCallback,
+ cef_download_item_callback_t> {
+ public:
+ CefDownloadItemCallbackCppToC();
+ virtual ~CefDownloadItemCallbackCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_DOWNLOAD_ITEM_CALLBACK_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/download_item_cpptoc.cc b/libcef_dll/cpptoc/download_item_cpptoc.cc
new file mode 100644
index 00000000..47f988c9
--- /dev/null
+++ b/libcef_dll/cpptoc/download_item_cpptoc.cc
@@ -0,0 +1,368 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=cb94a7a2bc730d84808942098434a9fa482e348d$
+//
+
+#include "libcef_dll/cpptoc/download_item_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK download_item_is_valid(struct _cef_download_item_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefDownloadItemCppToC::Get(self)->IsValid();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+download_item_is_in_progress(struct _cef_download_item_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefDownloadItemCppToC::Get(self)->IsInProgress();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK download_item_is_complete(struct _cef_download_item_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefDownloadItemCppToC::Get(self)->IsComplete();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK download_item_is_canceled(struct _cef_download_item_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefDownloadItemCppToC::Get(self)->IsCanceled();
+
+ // Return type: bool
+ return _retval;
+}
+
+int64 CEF_CALLBACK
+download_item_get_current_speed(struct _cef_download_item_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int64 _retval = CefDownloadItemCppToC::Get(self)->GetCurrentSpeed();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK
+download_item_get_percent_complete(struct _cef_download_item_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefDownloadItemCppToC::Get(self)->GetPercentComplete();
+
+ // Return type: simple
+ return _retval;
+}
+
+int64 CEF_CALLBACK
+download_item_get_total_bytes(struct _cef_download_item_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int64 _retval = CefDownloadItemCppToC::Get(self)->GetTotalBytes();
+
+ // Return type: simple
+ return _retval;
+}
+
+int64 CEF_CALLBACK
+download_item_get_received_bytes(struct _cef_download_item_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int64 _retval = CefDownloadItemCppToC::Get(self)->GetReceivedBytes();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_basetime_t CEF_CALLBACK
+download_item_get_start_time(struct _cef_download_item_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefBaseTime();
+ }
+
+ // Execute
+ cef_basetime_t _retval = CefDownloadItemCppToC::Get(self)->GetStartTime();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_basetime_t CEF_CALLBACK
+download_item_get_end_time(struct _cef_download_item_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefBaseTime();
+ }
+
+ // Execute
+ cef_basetime_t _retval = CefDownloadItemCppToC::Get(self)->GetEndTime();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_string_userfree_t CEF_CALLBACK
+download_item_get_full_path(struct _cef_download_item_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefDownloadItemCppToC::Get(self)->GetFullPath();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+uint32 CEF_CALLBACK download_item_get_id(struct _cef_download_item_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ uint32 _retval = CefDownloadItemCppToC::Get(self)->GetId();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_string_userfree_t CEF_CALLBACK
+download_item_get_url(struct _cef_download_item_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefDownloadItemCppToC::Get(self)->GetURL();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_string_userfree_t CEF_CALLBACK
+download_item_get_original_url(struct _cef_download_item_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefDownloadItemCppToC::Get(self)->GetOriginalUrl();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_string_userfree_t CEF_CALLBACK
+download_item_get_suggested_file_name(struct _cef_download_item_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefDownloadItemCppToC::Get(self)->GetSuggestedFileName();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_string_userfree_t CEF_CALLBACK
+download_item_get_content_disposition(struct _cef_download_item_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefDownloadItemCppToC::Get(self)->GetContentDisposition();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_string_userfree_t CEF_CALLBACK
+download_item_get_mime_type(struct _cef_download_item_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefDownloadItemCppToC::Get(self)->GetMimeType();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefDownloadItemCppToC::CefDownloadItemCppToC() {
+ GetStruct()->is_valid = download_item_is_valid;
+ GetStruct()->is_in_progress = download_item_is_in_progress;
+ GetStruct()->is_complete = download_item_is_complete;
+ GetStruct()->is_canceled = download_item_is_canceled;
+ GetStruct()->get_current_speed = download_item_get_current_speed;
+ GetStruct()->get_percent_complete = download_item_get_percent_complete;
+ GetStruct()->get_total_bytes = download_item_get_total_bytes;
+ GetStruct()->get_received_bytes = download_item_get_received_bytes;
+ GetStruct()->get_start_time = download_item_get_start_time;
+ GetStruct()->get_end_time = download_item_get_end_time;
+ GetStruct()->get_full_path = download_item_get_full_path;
+ GetStruct()->get_id = download_item_get_id;
+ GetStruct()->get_url = download_item_get_url;
+ GetStruct()->get_original_url = download_item_get_original_url;
+ GetStruct()->get_suggested_file_name = download_item_get_suggested_file_name;
+ GetStruct()->get_content_disposition = download_item_get_content_disposition;
+ GetStruct()->get_mime_type = download_item_get_mime_type;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefDownloadItemCppToC::~CefDownloadItemCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefDownloadItem> CefCppToCRefCounted<
+ CefDownloadItemCppToC,
+ CefDownloadItem,
+ cef_download_item_t>::UnwrapDerived(CefWrapperType type,
+ cef_download_item_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefDownloadItemCppToC,
+ CefDownloadItem,
+ cef_download_item_t>::kWrapperType =
+ WT_DOWNLOAD_ITEM;
diff --git a/libcef_dll/cpptoc/download_item_cpptoc.h b/libcef_dll/cpptoc/download_item_cpptoc.h
new file mode 100644
index 00000000..dcf26cfd
--- /dev/null
+++ b/libcef_dll/cpptoc/download_item_cpptoc.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=3817a67cd4da8a318fe118f775a86a3daa22af67$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_DOWNLOAD_ITEM_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_DOWNLOAD_ITEM_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_download_item_capi.h"
+#include "include/cef_download_item.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefDownloadItemCppToC : public CefCppToCRefCounted<CefDownloadItemCppToC,
+ CefDownloadItem,
+ cef_download_item_t> {
+ public:
+ CefDownloadItemCppToC();
+ virtual ~CefDownloadItemCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_DOWNLOAD_ITEM_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/drag_data_cpptoc.cc b/libcef_dll/cpptoc/drag_data_cpptoc.cc
new file mode 100644
index 00000000..576a126b
--- /dev/null
+++ b/libcef_dll/cpptoc/drag_data_cpptoc.cc
@@ -0,0 +1,555 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=978e101f569a95222ce4e962d681ff2b4df46955$
+//
+
+#include "libcef_dll/cpptoc/drag_data_cpptoc.h"
+#include "libcef_dll/cpptoc/image_cpptoc.h"
+#include "libcef_dll/cpptoc/stream_writer_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+#include "libcef_dll/transfer_util.h"
+
+// GLOBAL FUNCTIONS - Body may be edited by hand.
+
+CEF_EXPORT cef_drag_data_t* cef_drag_data_create() {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ CefRefPtr<CefDragData> _retval = CefDragData::Create();
+
+ // Return type: refptr_same
+ return CefDragDataCppToC::Wrap(_retval);
+}
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+struct _cef_drag_data_t* CEF_CALLBACK
+drag_data_clone(struct _cef_drag_data_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefDragData> _retval = CefDragDataCppToC::Get(self)->Clone();
+
+ // Return type: refptr_same
+ return CefDragDataCppToC::Wrap(_retval);
+}
+
+int CEF_CALLBACK drag_data_is_read_only(struct _cef_drag_data_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefDragDataCppToC::Get(self)->IsReadOnly();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK drag_data_is_link(struct _cef_drag_data_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefDragDataCppToC::Get(self)->IsLink();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK drag_data_is_fragment(struct _cef_drag_data_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefDragDataCppToC::Get(self)->IsFragment();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK drag_data_is_file(struct _cef_drag_data_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefDragDataCppToC::Get(self)->IsFile();
+
+ // Return type: bool
+ return _retval;
+}
+
+cef_string_userfree_t CEF_CALLBACK
+drag_data_get_link_url(struct _cef_drag_data_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefDragDataCppToC::Get(self)->GetLinkURL();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_string_userfree_t CEF_CALLBACK
+drag_data_get_link_title(struct _cef_drag_data_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefDragDataCppToC::Get(self)->GetLinkTitle();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_string_userfree_t CEF_CALLBACK
+drag_data_get_link_metadata(struct _cef_drag_data_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefDragDataCppToC::Get(self)->GetLinkMetadata();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_string_userfree_t CEF_CALLBACK
+drag_data_get_fragment_text(struct _cef_drag_data_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefDragDataCppToC::Get(self)->GetFragmentText();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_string_userfree_t CEF_CALLBACK
+drag_data_get_fragment_html(struct _cef_drag_data_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefDragDataCppToC::Get(self)->GetFragmentHtml();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_string_userfree_t CEF_CALLBACK
+drag_data_get_fragment_base_url(struct _cef_drag_data_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefDragDataCppToC::Get(self)->GetFragmentBaseURL();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_string_userfree_t CEF_CALLBACK
+drag_data_get_file_name(struct _cef_drag_data_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefDragDataCppToC::Get(self)->GetFileName();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+size_t CEF_CALLBACK
+drag_data_get_file_contents(struct _cef_drag_data_t* self,
+ struct _cef_stream_writer_t* writer) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Unverified params: writer
+
+ // Execute
+ size_t _retval = CefDragDataCppToC::Get(self)->GetFileContents(
+ CefStreamWriterCppToC::Unwrap(writer));
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK drag_data_get_file_names(struct _cef_drag_data_t* self,
+ cef_string_list_t names) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: names; type: string_vec_byref
+ DCHECK(names);
+ if (!names) {
+ return 0;
+ }
+
+ // Translate param: names; type: string_vec_byref
+ std::vector<CefString> namesList;
+ transfer_string_list_contents(names, namesList);
+
+ // Execute
+ bool _retval = CefDragDataCppToC::Get(self)->GetFileNames(namesList);
+
+ // Restore param: names; type: string_vec_byref
+ cef_string_list_clear(names);
+ transfer_string_list_contents(namesList, names);
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK drag_data_set_link_url(struct _cef_drag_data_t* self,
+ const cef_string_t* url) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Unverified params: url
+
+ // Execute
+ CefDragDataCppToC::Get(self)->SetLinkURL(CefString(url));
+}
+
+void CEF_CALLBACK drag_data_set_link_title(struct _cef_drag_data_t* self,
+ const cef_string_t* title) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Unverified params: title
+
+ // Execute
+ CefDragDataCppToC::Get(self)->SetLinkTitle(CefString(title));
+}
+
+void CEF_CALLBACK drag_data_set_link_metadata(struct _cef_drag_data_t* self,
+ const cef_string_t* data) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Unverified params: data
+
+ // Execute
+ CefDragDataCppToC::Get(self)->SetLinkMetadata(CefString(data));
+}
+
+void CEF_CALLBACK drag_data_set_fragment_text(struct _cef_drag_data_t* self,
+ const cef_string_t* text) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Unverified params: text
+
+ // Execute
+ CefDragDataCppToC::Get(self)->SetFragmentText(CefString(text));
+}
+
+void CEF_CALLBACK drag_data_set_fragment_html(struct _cef_drag_data_t* self,
+ const cef_string_t* html) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Unverified params: html
+
+ // Execute
+ CefDragDataCppToC::Get(self)->SetFragmentHtml(CefString(html));
+}
+
+void CEF_CALLBACK
+drag_data_set_fragment_base_url(struct _cef_drag_data_t* self,
+ const cef_string_t* base_url) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Unverified params: base_url
+
+ // Execute
+ CefDragDataCppToC::Get(self)->SetFragmentBaseURL(CefString(base_url));
+}
+
+void CEF_CALLBACK drag_data_reset_file_contents(struct _cef_drag_data_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefDragDataCppToC::Get(self)->ResetFileContents();
+}
+
+void CEF_CALLBACK drag_data_add_file(struct _cef_drag_data_t* self,
+ const cef_string_t* path,
+ const cef_string_t* display_name) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: path; type: string_byref_const
+ DCHECK(path);
+ if (!path) {
+ return;
+ }
+ // Unverified params: display_name
+
+ // Execute
+ CefDragDataCppToC::Get(self)->AddFile(CefString(path),
+ CefString(display_name));
+}
+
+void CEF_CALLBACK drag_data_clear_filenames(struct _cef_drag_data_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefDragDataCppToC::Get(self)->ClearFilenames();
+}
+
+struct _cef_image_t* CEF_CALLBACK
+drag_data_get_image(struct _cef_drag_data_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefImage> _retval = CefDragDataCppToC::Get(self)->GetImage();
+
+ // Return type: refptr_same
+ return CefImageCppToC::Wrap(_retval);
+}
+
+cef_point_t CEF_CALLBACK
+drag_data_get_image_hotspot(struct _cef_drag_data_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefPoint();
+ }
+
+ // Execute
+ cef_point_t _retval = CefDragDataCppToC::Get(self)->GetImageHotspot();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK drag_data_has_image(struct _cef_drag_data_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefDragDataCppToC::Get(self)->HasImage();
+
+ // Return type: bool
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefDragDataCppToC::CefDragDataCppToC() {
+ GetStruct()->clone = drag_data_clone;
+ GetStruct()->is_read_only = drag_data_is_read_only;
+ GetStruct()->is_link = drag_data_is_link;
+ GetStruct()->is_fragment = drag_data_is_fragment;
+ GetStruct()->is_file = drag_data_is_file;
+ GetStruct()->get_link_url = drag_data_get_link_url;
+ GetStruct()->get_link_title = drag_data_get_link_title;
+ GetStruct()->get_link_metadata = drag_data_get_link_metadata;
+ GetStruct()->get_fragment_text = drag_data_get_fragment_text;
+ GetStruct()->get_fragment_html = drag_data_get_fragment_html;
+ GetStruct()->get_fragment_base_url = drag_data_get_fragment_base_url;
+ GetStruct()->get_file_name = drag_data_get_file_name;
+ GetStruct()->get_file_contents = drag_data_get_file_contents;
+ GetStruct()->get_file_names = drag_data_get_file_names;
+ GetStruct()->set_link_url = drag_data_set_link_url;
+ GetStruct()->set_link_title = drag_data_set_link_title;
+ GetStruct()->set_link_metadata = drag_data_set_link_metadata;
+ GetStruct()->set_fragment_text = drag_data_set_fragment_text;
+ GetStruct()->set_fragment_html = drag_data_set_fragment_html;
+ GetStruct()->set_fragment_base_url = drag_data_set_fragment_base_url;
+ GetStruct()->reset_file_contents = drag_data_reset_file_contents;
+ GetStruct()->add_file = drag_data_add_file;
+ GetStruct()->clear_filenames = drag_data_clear_filenames;
+ GetStruct()->get_image = drag_data_get_image;
+ GetStruct()->get_image_hotspot = drag_data_get_image_hotspot;
+ GetStruct()->has_image = drag_data_has_image;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefDragDataCppToC::~CefDragDataCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefDragData>
+CefCppToCRefCounted<CefDragDataCppToC, CefDragData, cef_drag_data_t>::
+ UnwrapDerived(CefWrapperType type, cef_drag_data_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefDragDataCppToC,
+ CefDragData,
+ cef_drag_data_t>::kWrapperType =
+ WT_DRAG_DATA;
diff --git a/libcef_dll/cpptoc/drag_data_cpptoc.h b/libcef_dll/cpptoc/drag_data_cpptoc.h
new file mode 100644
index 00000000..1628e094
--- /dev/null
+++ b/libcef_dll/cpptoc/drag_data_cpptoc.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=4ce3b8cfc691f8cb7aa224a00d7835283c5039ab$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_DRAG_DATA_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_DRAG_DATA_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_drag_data_capi.h"
+#include "include/cef_drag_data.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefDragDataCppToC : public CefCppToCRefCounted<CefDragDataCppToC,
+ CefDragData,
+ cef_drag_data_t> {
+ public:
+ CefDragDataCppToC();
+ virtual ~CefDragDataCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_DRAG_DATA_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/drag_handler_cpptoc.cc b/libcef_dll/cpptoc/drag_handler_cpptoc.cc
new file mode 100644
index 00000000..12c92a8d
--- /dev/null
+++ b/libcef_dll/cpptoc/drag_handler_cpptoc.cc
@@ -0,0 +1,129 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=6c1d14cb706ab18d56a265e2eaa5567a526919e9$
+//
+
+#include "libcef_dll/cpptoc/drag_handler_cpptoc.h"
+#include "libcef_dll/ctocpp/browser_ctocpp.h"
+#include "libcef_dll/ctocpp/drag_data_ctocpp.h"
+#include "libcef_dll/ctocpp/frame_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK drag_handler_on_drag_enter(struct _cef_drag_handler_t* self,
+ cef_browser_t* browser,
+ cef_drag_data_t* dragData,
+ cef_drag_operations_mask_t mask) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return 0;
+ }
+ // Verify param: dragData; type: refptr_diff
+ DCHECK(dragData);
+ if (!dragData) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefDragHandlerCppToC::Get(self)->OnDragEnter(
+ CefBrowserCToCpp::Wrap(browser), CefDragDataCToCpp::Wrap(dragData), mask);
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK drag_handler_on_draggable_regions_changed(
+ struct _cef_drag_handler_t* self,
+ cef_browser_t* browser,
+ struct _cef_frame_t* frame,
+ size_t regionsCount,
+ cef_draggable_region_t const* regions) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+ // Verify param: frame; type: refptr_diff
+ DCHECK(frame);
+ if (!frame) {
+ return;
+ }
+ // Verify param: regions; type: simple_vec_byref_const
+ DCHECK(regionsCount == 0 || regions);
+ if (regionsCount > 0 && !regions) {
+ return;
+ }
+
+ // Translate param: regions; type: simple_vec_byref_const
+ std::vector<CefDraggableRegion> regionsList;
+ if (regionsCount > 0) {
+ for (size_t i = 0; i < regionsCount; ++i) {
+ CefDraggableRegion regionsVal = regions[i];
+ regionsList.push_back(regionsVal);
+ }
+ }
+
+ // Execute
+ CefDragHandlerCppToC::Get(self)->OnDraggableRegionsChanged(
+ CefBrowserCToCpp::Wrap(browser), CefFrameCToCpp::Wrap(frame),
+ regionsList);
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefDragHandlerCppToC::CefDragHandlerCppToC() {
+ GetStruct()->on_drag_enter = drag_handler_on_drag_enter;
+ GetStruct()->on_draggable_regions_changed =
+ drag_handler_on_draggable_regions_changed;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefDragHandlerCppToC::~CefDragHandlerCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefDragHandler>
+CefCppToCRefCounted<CefDragHandlerCppToC, CefDragHandler, cef_drag_handler_t>::
+ UnwrapDerived(CefWrapperType type, cef_drag_handler_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefDragHandlerCppToC,
+ CefDragHandler,
+ cef_drag_handler_t>::kWrapperType =
+ WT_DRAG_HANDLER;
diff --git a/libcef_dll/cpptoc/drag_handler_cpptoc.h b/libcef_dll/cpptoc/drag_handler_cpptoc.h
new file mode 100644
index 00000000..e8f136b9
--- /dev/null
+++ b/libcef_dll/cpptoc/drag_handler_cpptoc.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=9d82217b402aa41686392b0ba81169f4b41035e7$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_DRAG_HANDLER_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_DRAG_HANDLER_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_drag_handler_capi.h"
+#include "include/cef_drag_handler.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefDragHandlerCppToC : public CefCppToCRefCounted<CefDragHandlerCppToC,
+ CefDragHandler,
+ cef_drag_handler_t> {
+ public:
+ CefDragHandlerCppToC();
+ virtual ~CefDragHandlerCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_DRAG_HANDLER_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/end_tracing_callback_cpptoc.cc b/libcef_dll/cpptoc/end_tracing_callback_cpptoc.cc
new file mode 100644
index 00000000..2707c6cb
--- /dev/null
+++ b/libcef_dll/cpptoc/end_tracing_callback_cpptoc.cc
@@ -0,0 +1,73 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=ebc35ae1d69fc69861f74ff1531d1c849220fed8$
+//
+
+#include "libcef_dll/cpptoc/end_tracing_callback_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK end_tracing_callback_on_end_tracing_complete(
+ struct _cef_end_tracing_callback_t* self,
+ const cef_string_t* tracing_file) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: tracing_file; type: string_byref_const
+ DCHECK(tracing_file);
+ if (!tracing_file) {
+ return;
+ }
+
+ // Execute
+ CefEndTracingCallbackCppToC::Get(self)->OnEndTracingComplete(
+ CefString(tracing_file));
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefEndTracingCallbackCppToC::CefEndTracingCallbackCppToC() {
+ GetStruct()->on_end_tracing_complete =
+ end_tracing_callback_on_end_tracing_complete;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefEndTracingCallbackCppToC::~CefEndTracingCallbackCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefEndTracingCallback> CefCppToCRefCounted<
+ CefEndTracingCallbackCppToC,
+ CefEndTracingCallback,
+ cef_end_tracing_callback_t>::UnwrapDerived(CefWrapperType type,
+ cef_end_tracing_callback_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefEndTracingCallbackCppToC,
+ CefEndTracingCallback,
+ cef_end_tracing_callback_t>::kWrapperType =
+ WT_END_TRACING_CALLBACK;
diff --git a/libcef_dll/cpptoc/end_tracing_callback_cpptoc.h b/libcef_dll/cpptoc/end_tracing_callback_cpptoc.h
new file mode 100644
index 00000000..c6291697
--- /dev/null
+++ b/libcef_dll/cpptoc/end_tracing_callback_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=81dc12ded9752671497f775c397ca120632c4ddb$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_END_TRACING_CALLBACK_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_END_TRACING_CALLBACK_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_trace_capi.h"
+#include "include/cef_trace.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefEndTracingCallbackCppToC
+ : public CefCppToCRefCounted<CefEndTracingCallbackCppToC,
+ CefEndTracingCallback,
+ cef_end_tracing_callback_t> {
+ public:
+ CefEndTracingCallbackCppToC();
+ virtual ~CefEndTracingCallbackCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_END_TRACING_CALLBACK_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/extension_cpptoc.cc b/libcef_dll/cpptoc/extension_cpptoc.cc
new file mode 100644
index 00000000..0bd70aa8
--- /dev/null
+++ b/libcef_dll/cpptoc/extension_cpptoc.cc
@@ -0,0 +1,206 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=1be4d8919dc1f776e8c5b897757ed215df15fb06$
+//
+
+#include "libcef_dll/cpptoc/extension_cpptoc.h"
+#include "libcef_dll/cpptoc/dictionary_value_cpptoc.h"
+#include "libcef_dll/cpptoc/request_context_cpptoc.h"
+#include "libcef_dll/ctocpp/extension_handler_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+cef_string_userfree_t CEF_CALLBACK
+extension_get_identifier(struct _cef_extension_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefExtensionCppToC::Get(self)->GetIdentifier();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_string_userfree_t CEF_CALLBACK
+extension_get_path(struct _cef_extension_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefExtensionCppToC::Get(self)->GetPath();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+struct _cef_dictionary_value_t* CEF_CALLBACK
+extension_get_manifest(struct _cef_extension_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefDictionaryValue> _retval =
+ CefExtensionCppToC::Get(self)->GetManifest();
+
+ // Return type: refptr_same
+ return CefDictionaryValueCppToC::Wrap(_retval);
+}
+
+int CEF_CALLBACK extension_is_same(struct _cef_extension_t* self,
+ struct _cef_extension_t* that) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: that; type: refptr_same
+ DCHECK(that);
+ if (!that) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefExtensionCppToC::Get(self)->IsSame(CefExtensionCppToC::Unwrap(that));
+
+ // Return type: bool
+ return _retval;
+}
+
+struct _cef_extension_handler_t* CEF_CALLBACK
+extension_get_handler(struct _cef_extension_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefExtensionHandler> _retval =
+ CefExtensionCppToC::Get(self)->GetHandler();
+
+ // Return type: refptr_diff
+ return CefExtensionHandlerCToCpp::Unwrap(_retval);
+}
+
+struct _cef_request_context_t* CEF_CALLBACK
+extension_get_loader_context(struct _cef_extension_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefRequestContext> _retval =
+ CefExtensionCppToC::Get(self)->GetLoaderContext();
+
+ // Return type: refptr_same
+ return CefRequestContextCppToC::Wrap(_retval);
+}
+
+int CEF_CALLBACK extension_is_loaded(struct _cef_extension_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefExtensionCppToC::Get(self)->IsLoaded();
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK extension_unload(struct _cef_extension_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefExtensionCppToC::Get(self)->Unload();
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefExtensionCppToC::CefExtensionCppToC() {
+ GetStruct()->get_identifier = extension_get_identifier;
+ GetStruct()->get_path = extension_get_path;
+ GetStruct()->get_manifest = extension_get_manifest;
+ GetStruct()->is_same = extension_is_same;
+ GetStruct()->get_handler = extension_get_handler;
+ GetStruct()->get_loader_context = extension_get_loader_context;
+ GetStruct()->is_loaded = extension_is_loaded;
+ GetStruct()->unload = extension_unload;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefExtensionCppToC::~CefExtensionCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefExtension>
+CefCppToCRefCounted<CefExtensionCppToC, CefExtension, cef_extension_t>::
+ UnwrapDerived(CefWrapperType type, cef_extension_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefExtensionCppToC,
+ CefExtension,
+ cef_extension_t>::kWrapperType =
+ WT_EXTENSION;
diff --git a/libcef_dll/cpptoc/extension_cpptoc.h b/libcef_dll/cpptoc/extension_cpptoc.h
new file mode 100644
index 00000000..32eca733
--- /dev/null
+++ b/libcef_dll/cpptoc/extension_cpptoc.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=924265d65cc81f721d9757d8b4a325260e1848d1$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_EXTENSION_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_EXTENSION_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_extension_capi.h"
+#include "include/capi/cef_extension_handler_capi.h"
+#include "include/capi/cef_request_context_capi.h"
+#include "include/cef_extension.h"
+#include "include/cef_extension_handler.h"
+#include "include/cef_request_context.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefExtensionCppToC : public CefCppToCRefCounted<CefExtensionCppToC,
+ CefExtension,
+ cef_extension_t> {
+ public:
+ CefExtensionCppToC();
+ virtual ~CefExtensionCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_EXTENSION_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/extension_handler_cpptoc.cc b/libcef_dll/cpptoc/extension_handler_cpptoc.cc
new file mode 100644
index 00000000..c1f71b56
--- /dev/null
+++ b/libcef_dll/cpptoc/extension_handler_cpptoc.cc
@@ -0,0 +1,427 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=febb11e8ea976823bf839bc77bc129be40af20bb$
+//
+
+#include "libcef_dll/cpptoc/extension_handler_cpptoc.h"
+#include "libcef_dll/cpptoc/client_cpptoc.h"
+#include "libcef_dll/ctocpp/browser_ctocpp.h"
+#include "libcef_dll/ctocpp/extension_ctocpp.h"
+#include "libcef_dll/ctocpp/get_extension_resource_callback_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+#include "libcef_dll/template_util.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK extension_handler_on_extension_load_failed(
+ struct _cef_extension_handler_t* self,
+ cef_errorcode_t result) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefExtensionHandlerCppToC::Get(self)->OnExtensionLoadFailed(result);
+}
+
+void CEF_CALLBACK
+extension_handler_on_extension_loaded(struct _cef_extension_handler_t* self,
+ cef_extension_t* extension) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: extension; type: refptr_diff
+ DCHECK(extension);
+ if (!extension) {
+ return;
+ }
+
+ // Execute
+ CefExtensionHandlerCppToC::Get(self)->OnExtensionLoaded(
+ CefExtensionCToCpp::Wrap(extension));
+}
+
+void CEF_CALLBACK
+extension_handler_on_extension_unloaded(struct _cef_extension_handler_t* self,
+ cef_extension_t* extension) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: extension; type: refptr_diff
+ DCHECK(extension);
+ if (!extension) {
+ return;
+ }
+
+ // Execute
+ CefExtensionHandlerCppToC::Get(self)->OnExtensionUnloaded(
+ CefExtensionCToCpp::Wrap(extension));
+}
+
+int CEF_CALLBACK extension_handler_on_before_background_browser(
+ struct _cef_extension_handler_t* self,
+ cef_extension_t* extension,
+ const cef_string_t* url,
+ cef_client_t** client,
+ struct _cef_browser_settings_t* settings) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: extension; type: refptr_diff
+ DCHECK(extension);
+ if (!extension) {
+ return 0;
+ }
+ // Verify param: url; type: string_byref_const
+ DCHECK(url);
+ if (!url) {
+ return 0;
+ }
+ // Verify param: client; type: refptr_same_byref
+ DCHECK(client);
+ if (!client) {
+ return 0;
+ }
+ // Verify param: settings; type: struct_byref
+ DCHECK(settings);
+ if (!settings) {
+ return 0;
+ }
+ if (!template_util::has_valid_size(settings)) {
+ NOTREACHED() << "invalid settings->[base.]size";
+ return 0;
+ }
+
+ // Translate param: client; type: refptr_same_byref
+ CefRefPtr<CefClient> clientPtr;
+ if (client && *client) {
+ clientPtr = CefClientCppToC::Unwrap(*client);
+ }
+ CefClient* clientOrig = clientPtr.get();
+ // Translate param: settings; type: struct_byref
+ CefBrowserSettings settingsObj;
+ if (settings) {
+ settingsObj.AttachTo(*settings);
+ }
+
+ // Execute
+ bool _retval =
+ CefExtensionHandlerCppToC::Get(self)->OnBeforeBackgroundBrowser(
+ CefExtensionCToCpp::Wrap(extension), CefString(url), clientPtr,
+ settingsObj);
+
+ // Restore param: client; type: refptr_same_byref
+ if (client) {
+ if (clientPtr.get()) {
+ if (clientPtr.get() != clientOrig) {
+ *client = CefClientCppToC::Wrap(clientPtr);
+ }
+ } else {
+ *client = nullptr;
+ }
+ }
+ // Restore param: settings; type: struct_byref
+ if (settings) {
+ settingsObj.DetachTo(*settings);
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+extension_handler_on_before_browser(struct _cef_extension_handler_t* self,
+ cef_extension_t* extension,
+ cef_browser_t* browser,
+ cef_browser_t* active_browser,
+ int index,
+ const cef_string_t* url,
+ int active,
+ cef_window_info_t* windowInfo,
+ cef_client_t** client,
+ struct _cef_browser_settings_t* settings) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: extension; type: refptr_diff
+ DCHECK(extension);
+ if (!extension) {
+ return 0;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return 0;
+ }
+ // Verify param: active_browser; type: refptr_diff
+ DCHECK(active_browser);
+ if (!active_browser) {
+ return 0;
+ }
+ // Verify param: url; type: string_byref_const
+ DCHECK(url);
+ if (!url) {
+ return 0;
+ }
+ // Verify param: windowInfo; type: struct_byref
+ DCHECK(windowInfo);
+ if (!windowInfo) {
+ return 0;
+ }
+ if (!template_util::has_valid_size(windowInfo)) {
+ NOTREACHED() << "invalid windowInfo->[base.]size";
+ return 0;
+ }
+ // Verify param: client; type: refptr_same_byref
+ DCHECK(client);
+ if (!client) {
+ return 0;
+ }
+ // Verify param: settings; type: struct_byref
+ DCHECK(settings);
+ if (!settings) {
+ return 0;
+ }
+ if (!template_util::has_valid_size(settings)) {
+ NOTREACHED() << "invalid settings->[base.]size";
+ return 0;
+ }
+
+ // Translate param: windowInfo; type: struct_byref
+ CefWindowInfo windowInfoObj;
+ if (windowInfo) {
+ windowInfoObj.AttachTo(*windowInfo);
+ }
+ // Translate param: client; type: refptr_same_byref
+ CefRefPtr<CefClient> clientPtr;
+ if (client && *client) {
+ clientPtr = CefClientCppToC::Unwrap(*client);
+ }
+ CefClient* clientOrig = clientPtr.get();
+ // Translate param: settings; type: struct_byref
+ CefBrowserSettings settingsObj;
+ if (settings) {
+ settingsObj.AttachTo(*settings);
+ }
+
+ // Execute
+ bool _retval = CefExtensionHandlerCppToC::Get(self)->OnBeforeBrowser(
+ CefExtensionCToCpp::Wrap(extension), CefBrowserCToCpp::Wrap(browser),
+ CefBrowserCToCpp::Wrap(active_browser), index, CefString(url),
+ active ? true : false, windowInfoObj, clientPtr, settingsObj);
+
+ // Restore param: windowInfo; type: struct_byref
+ if (windowInfo) {
+ windowInfoObj.DetachTo(*windowInfo);
+ }
+ // Restore param: client; type: refptr_same_byref
+ if (client) {
+ if (clientPtr.get()) {
+ if (clientPtr.get() != clientOrig) {
+ *client = CefClientCppToC::Wrap(clientPtr);
+ }
+ } else {
+ *client = nullptr;
+ }
+ }
+ // Restore param: settings; type: struct_byref
+ if (settings) {
+ settingsObj.DetachTo(*settings);
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+cef_browser_t* CEF_CALLBACK
+extension_handler_get_active_browser(struct _cef_extension_handler_t* self,
+ cef_extension_t* extension,
+ cef_browser_t* browser,
+ int include_incognito) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+ // Verify param: extension; type: refptr_diff
+ DCHECK(extension);
+ if (!extension) {
+ return NULL;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefBrowser> _retval =
+ CefExtensionHandlerCppToC::Get(self)->GetActiveBrowser(
+ CefExtensionCToCpp::Wrap(extension), CefBrowserCToCpp::Wrap(browser),
+ include_incognito ? true : false);
+
+ // Return type: refptr_diff
+ return CefBrowserCToCpp::Unwrap(_retval);
+}
+
+int CEF_CALLBACK
+extension_handler_can_access_browser(struct _cef_extension_handler_t* self,
+ cef_extension_t* extension,
+ cef_browser_t* browser,
+ int include_incognito,
+ cef_browser_t* target_browser) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: extension; type: refptr_diff
+ DCHECK(extension);
+ if (!extension) {
+ return 0;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return 0;
+ }
+ // Verify param: target_browser; type: refptr_diff
+ DCHECK(target_browser);
+ if (!target_browser) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefExtensionHandlerCppToC::Get(self)->CanAccessBrowser(
+ CefExtensionCToCpp::Wrap(extension), CefBrowserCToCpp::Wrap(browser),
+ include_incognito ? true : false, CefBrowserCToCpp::Wrap(target_browser));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK extension_handler_get_extension_resource(
+ struct _cef_extension_handler_t* self,
+ cef_extension_t* extension,
+ cef_browser_t* browser,
+ const cef_string_t* file,
+ cef_get_extension_resource_callback_t* callback) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: extension; type: refptr_diff
+ DCHECK(extension);
+ if (!extension) {
+ return 0;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return 0;
+ }
+ // Verify param: file; type: string_byref_const
+ DCHECK(file);
+ if (!file) {
+ return 0;
+ }
+ // Verify param: callback; type: refptr_diff
+ DCHECK(callback);
+ if (!callback) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefExtensionHandlerCppToC::Get(self)->GetExtensionResource(
+ CefExtensionCToCpp::Wrap(extension), CefBrowserCToCpp::Wrap(browser),
+ CefString(file), CefGetExtensionResourceCallbackCToCpp::Wrap(callback));
+
+ // Return type: bool
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefExtensionHandlerCppToC::CefExtensionHandlerCppToC() {
+ GetStruct()->on_extension_load_failed =
+ extension_handler_on_extension_load_failed;
+ GetStruct()->on_extension_loaded = extension_handler_on_extension_loaded;
+ GetStruct()->on_extension_unloaded = extension_handler_on_extension_unloaded;
+ GetStruct()->on_before_background_browser =
+ extension_handler_on_before_background_browser;
+ GetStruct()->on_before_browser = extension_handler_on_before_browser;
+ GetStruct()->get_active_browser = extension_handler_get_active_browser;
+ GetStruct()->can_access_browser = extension_handler_can_access_browser;
+ GetStruct()->get_extension_resource =
+ extension_handler_get_extension_resource;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefExtensionHandlerCppToC::~CefExtensionHandlerCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefExtensionHandler> CefCppToCRefCounted<
+ CefExtensionHandlerCppToC,
+ CefExtensionHandler,
+ cef_extension_handler_t>::UnwrapDerived(CefWrapperType type,
+ cef_extension_handler_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefExtensionHandlerCppToC,
+ CefExtensionHandler,
+ cef_extension_handler_t>::kWrapperType =
+ WT_EXTENSION_HANDLER;
diff --git a/libcef_dll/cpptoc/extension_handler_cpptoc.h b/libcef_dll/cpptoc/extension_handler_cpptoc.h
new file mode 100644
index 00000000..13b489be
--- /dev/null
+++ b/libcef_dll/cpptoc/extension_handler_cpptoc.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=db012b196983395c9684bf1275b638e9ccc57949$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_EXTENSION_HANDLER_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_EXTENSION_HANDLER_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_client_capi.h"
+#include "include/capi/cef_extension_handler_capi.h"
+#include "include/cef_client.h"
+#include "include/cef_extension_handler.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefExtensionHandlerCppToC
+ : public CefCppToCRefCounted<CefExtensionHandlerCppToC,
+ CefExtensionHandler,
+ cef_extension_handler_t> {
+ public:
+ CefExtensionHandlerCppToC();
+ virtual ~CefExtensionHandlerCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_EXTENSION_HANDLER_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/file_dialog_callback_cpptoc.cc b/libcef_dll/cpptoc/file_dialog_callback_cpptoc.cc
new file mode 100644
index 00000000..90ff55d7
--- /dev/null
+++ b/libcef_dll/cpptoc/file_dialog_callback_cpptoc.cc
@@ -0,0 +1,88 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=a646b20f2a1836fded44c08db264012b6fa2bfb7$
+//
+
+#include "libcef_dll/cpptoc/file_dialog_callback_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+#include "libcef_dll/transfer_util.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK
+file_dialog_callback_cont(struct _cef_file_dialog_callback_t* self,
+ cef_string_list_t file_paths) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Unverified params: file_paths
+
+ // Translate param: file_paths; type: string_vec_byref_const
+ std::vector<CefString> file_pathsList;
+ transfer_string_list_contents(file_paths, file_pathsList);
+
+ // Execute
+ CefFileDialogCallbackCppToC::Get(self)->Continue(file_pathsList);
+}
+
+void CEF_CALLBACK
+file_dialog_callback_cancel(struct _cef_file_dialog_callback_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefFileDialogCallbackCppToC::Get(self)->Cancel();
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefFileDialogCallbackCppToC::CefFileDialogCallbackCppToC() {
+ GetStruct()->cont = file_dialog_callback_cont;
+ GetStruct()->cancel = file_dialog_callback_cancel;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefFileDialogCallbackCppToC::~CefFileDialogCallbackCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefFileDialogCallback> CefCppToCRefCounted<
+ CefFileDialogCallbackCppToC,
+ CefFileDialogCallback,
+ cef_file_dialog_callback_t>::UnwrapDerived(CefWrapperType type,
+ cef_file_dialog_callback_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefFileDialogCallbackCppToC,
+ CefFileDialogCallback,
+ cef_file_dialog_callback_t>::kWrapperType =
+ WT_FILE_DIALOG_CALLBACK;
diff --git a/libcef_dll/cpptoc/file_dialog_callback_cpptoc.h b/libcef_dll/cpptoc/file_dialog_callback_cpptoc.h
new file mode 100644
index 00000000..f0a754b9
--- /dev/null
+++ b/libcef_dll/cpptoc/file_dialog_callback_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=2db275ca5be351037a0e19531fb2ed4c3af4498d$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_FILE_DIALOG_CALLBACK_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_FILE_DIALOG_CALLBACK_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_dialog_handler_capi.h"
+#include "include/cef_dialog_handler.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefFileDialogCallbackCppToC
+ : public CefCppToCRefCounted<CefFileDialogCallbackCppToC,
+ CefFileDialogCallback,
+ cef_file_dialog_callback_t> {
+ public:
+ CefFileDialogCallbackCppToC();
+ virtual ~CefFileDialogCallbackCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_FILE_DIALOG_CALLBACK_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/find_handler_cpptoc.cc b/libcef_dll/cpptoc/find_handler_cpptoc.cc
new file mode 100644
index 00000000..ac5970d9
--- /dev/null
+++ b/libcef_dll/cpptoc/find_handler_cpptoc.cc
@@ -0,0 +1,84 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=ed6fc947aa34621a06ac238692de05015cb4f965$
+//
+
+#include "libcef_dll/cpptoc/find_handler_cpptoc.h"
+#include "libcef_dll/ctocpp/browser_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK find_handler_on_find_result(struct _cef_find_handler_t* self,
+ cef_browser_t* browser,
+ int identifier,
+ int count,
+ const cef_rect_t* selectionRect,
+ int activeMatchOrdinal,
+ int finalUpdate) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+ // Verify param: selectionRect; type: simple_byref_const
+ DCHECK(selectionRect);
+ if (!selectionRect) {
+ return;
+ }
+
+ // Translate param: selectionRect; type: simple_byref_const
+ CefRect selectionRectVal = selectionRect ? *selectionRect : CefRect();
+
+ // Execute
+ CefFindHandlerCppToC::Get(self)->OnFindResult(
+ CefBrowserCToCpp::Wrap(browser), identifier, count, selectionRectVal,
+ activeMatchOrdinal, finalUpdate ? true : false);
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefFindHandlerCppToC::CefFindHandlerCppToC() {
+ GetStruct()->on_find_result = find_handler_on_find_result;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefFindHandlerCppToC::~CefFindHandlerCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefFindHandler>
+CefCppToCRefCounted<CefFindHandlerCppToC, CefFindHandler, cef_find_handler_t>::
+ UnwrapDerived(CefWrapperType type, cef_find_handler_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefFindHandlerCppToC,
+ CefFindHandler,
+ cef_find_handler_t>::kWrapperType =
+ WT_FIND_HANDLER;
diff --git a/libcef_dll/cpptoc/find_handler_cpptoc.h b/libcef_dll/cpptoc/find_handler_cpptoc.h
new file mode 100644
index 00000000..cf30c541
--- /dev/null
+++ b/libcef_dll/cpptoc/find_handler_cpptoc.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=fd8c0866622e63f6564c0b00107ebcb0c82d60fe$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_FIND_HANDLER_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_FIND_HANDLER_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_find_handler_capi.h"
+#include "include/cef_find_handler.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefFindHandlerCppToC : public CefCppToCRefCounted<CefFindHandlerCppToC,
+ CefFindHandler,
+ cef_find_handler_t> {
+ public:
+ CefFindHandlerCppToC();
+ virtual ~CefFindHandlerCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_FIND_HANDLER_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/focus_handler_cpptoc.cc b/libcef_dll/cpptoc/focus_handler_cpptoc.cc
new file mode 100644
index 00000000..e4f0a2a1
--- /dev/null
+++ b/libcef_dll/cpptoc/focus_handler_cpptoc.cc
@@ -0,0 +1,120 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=434fcb10c5051958eb269c7c2d5bd5eb0d558a2b$
+//
+
+#include "libcef_dll/cpptoc/focus_handler_cpptoc.h"
+#include "libcef_dll/ctocpp/browser_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK focus_handler_on_take_focus(struct _cef_focus_handler_t* self,
+ cef_browser_t* browser,
+ int next) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+
+ // Execute
+ CefFocusHandlerCppToC::Get(self)->OnTakeFocus(CefBrowserCToCpp::Wrap(browser),
+ next ? true : false);
+}
+
+int CEF_CALLBACK focus_handler_on_set_focus(struct _cef_focus_handler_t* self,
+ cef_browser_t* browser,
+ cef_focus_source_t source) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefFocusHandlerCppToC::Get(self)->OnSetFocus(
+ CefBrowserCToCpp::Wrap(browser), source);
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK focus_handler_on_got_focus(struct _cef_focus_handler_t* self,
+ cef_browser_t* browser) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+
+ // Execute
+ CefFocusHandlerCppToC::Get(self)->OnGotFocus(CefBrowserCToCpp::Wrap(browser));
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefFocusHandlerCppToC::CefFocusHandlerCppToC() {
+ GetStruct()->on_take_focus = focus_handler_on_take_focus;
+ GetStruct()->on_set_focus = focus_handler_on_set_focus;
+ GetStruct()->on_got_focus = focus_handler_on_got_focus;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefFocusHandlerCppToC::~CefFocusHandlerCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefFocusHandler> CefCppToCRefCounted<
+ CefFocusHandlerCppToC,
+ CefFocusHandler,
+ cef_focus_handler_t>::UnwrapDerived(CefWrapperType type,
+ cef_focus_handler_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefFocusHandlerCppToC,
+ CefFocusHandler,
+ cef_focus_handler_t>::kWrapperType =
+ WT_FOCUS_HANDLER;
diff --git a/libcef_dll/cpptoc/focus_handler_cpptoc.h b/libcef_dll/cpptoc/focus_handler_cpptoc.h
new file mode 100644
index 00000000..1dc59c42
--- /dev/null
+++ b/libcef_dll/cpptoc/focus_handler_cpptoc.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=b4e1894b64083f0045302da4840abf664c5a2429$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_FOCUS_HANDLER_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_FOCUS_HANDLER_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_focus_handler_capi.h"
+#include "include/cef_focus_handler.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefFocusHandlerCppToC : public CefCppToCRefCounted<CefFocusHandlerCppToC,
+ CefFocusHandler,
+ cef_focus_handler_t> {
+ public:
+ CefFocusHandlerCppToC();
+ virtual ~CefFocusHandlerCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_FOCUS_HANDLER_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/frame_cpptoc.cc b/libcef_dll/cpptoc/frame_cpptoc.cc
new file mode 100644
index 00000000..a11aa43c
--- /dev/null
+++ b/libcef_dll/cpptoc/frame_cpptoc.cc
@@ -0,0 +1,526 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=00edde10c338f3a382c715675f086de7753f2267$
+//
+
+#include "libcef_dll/cpptoc/frame_cpptoc.h"
+#include "libcef_dll/cpptoc/browser_cpptoc.h"
+#include "libcef_dll/cpptoc/process_message_cpptoc.h"
+#include "libcef_dll/cpptoc/request_cpptoc.h"
+#include "libcef_dll/cpptoc/urlrequest_cpptoc.h"
+#include "libcef_dll/cpptoc/v8context_cpptoc.h"
+#include "libcef_dll/ctocpp/domvisitor_ctocpp.h"
+#include "libcef_dll/ctocpp/string_visitor_ctocpp.h"
+#include "libcef_dll/ctocpp/urlrequest_client_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK frame_is_valid(struct _cef_frame_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefFrameCppToC::Get(self)->IsValid();
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK frame_undo(struct _cef_frame_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefFrameCppToC::Get(self)->Undo();
+}
+
+void CEF_CALLBACK frame_redo(struct _cef_frame_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefFrameCppToC::Get(self)->Redo();
+}
+
+void CEF_CALLBACK frame_cut(struct _cef_frame_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefFrameCppToC::Get(self)->Cut();
+}
+
+void CEF_CALLBACK frame_copy(struct _cef_frame_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefFrameCppToC::Get(self)->Copy();
+}
+
+void CEF_CALLBACK frame_paste(struct _cef_frame_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefFrameCppToC::Get(self)->Paste();
+}
+
+void CEF_CALLBACK frame_del(struct _cef_frame_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefFrameCppToC::Get(self)->Delete();
+}
+
+void CEF_CALLBACK frame_select_all(struct _cef_frame_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefFrameCppToC::Get(self)->SelectAll();
+}
+
+void CEF_CALLBACK frame_view_source(struct _cef_frame_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefFrameCppToC::Get(self)->ViewSource();
+}
+
+void CEF_CALLBACK frame_get_source(struct _cef_frame_t* self,
+ struct _cef_string_visitor_t* visitor) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: visitor; type: refptr_diff
+ DCHECK(visitor);
+ if (!visitor) {
+ return;
+ }
+
+ // Execute
+ CefFrameCppToC::Get(self)->GetSource(CefStringVisitorCToCpp::Wrap(visitor));
+}
+
+void CEF_CALLBACK frame_get_text(struct _cef_frame_t* self,
+ struct _cef_string_visitor_t* visitor) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: visitor; type: refptr_diff
+ DCHECK(visitor);
+ if (!visitor) {
+ return;
+ }
+
+ // Execute
+ CefFrameCppToC::Get(self)->GetText(CefStringVisitorCToCpp::Wrap(visitor));
+}
+
+void CEF_CALLBACK frame_load_request(struct _cef_frame_t* self,
+ struct _cef_request_t* request) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: request; type: refptr_same
+ DCHECK(request);
+ if (!request) {
+ return;
+ }
+
+ // Execute
+ CefFrameCppToC::Get(self)->LoadRequest(CefRequestCppToC::Unwrap(request));
+}
+
+void CEF_CALLBACK frame_load_url(struct _cef_frame_t* self,
+ const cef_string_t* url) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: url; type: string_byref_const
+ DCHECK(url);
+ if (!url) {
+ return;
+ }
+
+ // Execute
+ CefFrameCppToC::Get(self)->LoadURL(CefString(url));
+}
+
+void CEF_CALLBACK frame_execute_java_script(struct _cef_frame_t* self,
+ const cef_string_t* code,
+ const cef_string_t* script_url,
+ int start_line) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: code; type: string_byref_const
+ DCHECK(code);
+ if (!code) {
+ return;
+ }
+ // Unverified params: script_url
+
+ // Execute
+ CefFrameCppToC::Get(self)->ExecuteJavaScript(
+ CefString(code), CefString(script_url), start_line);
+}
+
+int CEF_CALLBACK frame_is_main(struct _cef_frame_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefFrameCppToC::Get(self)->IsMain();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK frame_is_focused(struct _cef_frame_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefFrameCppToC::Get(self)->IsFocused();
+
+ // Return type: bool
+ return _retval;
+}
+
+cef_string_userfree_t CEF_CALLBACK frame_get_name(struct _cef_frame_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefFrameCppToC::Get(self)->GetName();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+int64 CEF_CALLBACK frame_get_identifier(struct _cef_frame_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int64 _retval = CefFrameCppToC::Get(self)->GetIdentifier();
+
+ // Return type: simple
+ return _retval;
+}
+
+struct _cef_frame_t* CEF_CALLBACK frame_get_parent(struct _cef_frame_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefFrame> _retval = CefFrameCppToC::Get(self)->GetParent();
+
+ // Return type: refptr_same
+ return CefFrameCppToC::Wrap(_retval);
+}
+
+cef_string_userfree_t CEF_CALLBACK frame_get_url(struct _cef_frame_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefFrameCppToC::Get(self)->GetURL();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_browser_t* CEF_CALLBACK frame_get_browser(struct _cef_frame_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefBrowser> _retval = CefFrameCppToC::Get(self)->GetBrowser();
+
+ // Return type: refptr_same
+ return CefBrowserCppToC::Wrap(_retval);
+}
+
+struct _cef_v8context_t* CEF_CALLBACK
+frame_get_v8context(struct _cef_frame_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefV8Context> _retval = CefFrameCppToC::Get(self)->GetV8Context();
+
+ // Return type: refptr_same
+ return CefV8ContextCppToC::Wrap(_retval);
+}
+
+void CEF_CALLBACK frame_visit_dom(struct _cef_frame_t* self,
+ cef_domvisitor_t* visitor) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: visitor; type: refptr_diff
+ DCHECK(visitor);
+ if (!visitor) {
+ return;
+ }
+
+ // Execute
+ CefFrameCppToC::Get(self)->VisitDOM(CefDOMVisitorCToCpp::Wrap(visitor));
+}
+
+struct _cef_urlrequest_t* CEF_CALLBACK
+frame_create_urlrequest(struct _cef_frame_t* self,
+ struct _cef_request_t* request,
+ struct _cef_urlrequest_client_t* client) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+ // Verify param: request; type: refptr_same
+ DCHECK(request);
+ if (!request) {
+ return NULL;
+ }
+ // Verify param: client; type: refptr_diff
+ DCHECK(client);
+ if (!client) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefURLRequest> _retval =
+ CefFrameCppToC::Get(self)->CreateURLRequest(
+ CefRequestCppToC::Unwrap(request),
+ CefURLRequestClientCToCpp::Wrap(client));
+
+ // Return type: refptr_same
+ return CefURLRequestCppToC::Wrap(_retval);
+}
+
+void CEF_CALLBACK
+frame_send_process_message(struct _cef_frame_t* self,
+ cef_process_id_t target_process,
+ struct _cef_process_message_t* message) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: message; type: refptr_same
+ DCHECK(message);
+ if (!message) {
+ return;
+ }
+
+ // Execute
+ CefFrameCppToC::Get(self)->SendProcessMessage(
+ target_process, CefProcessMessageCppToC::Unwrap(message));
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefFrameCppToC::CefFrameCppToC() {
+ GetStruct()->is_valid = frame_is_valid;
+ GetStruct()->undo = frame_undo;
+ GetStruct()->redo = frame_redo;
+ GetStruct()->cut = frame_cut;
+ GetStruct()->copy = frame_copy;
+ GetStruct()->paste = frame_paste;
+ GetStruct()->del = frame_del;
+ GetStruct()->select_all = frame_select_all;
+ GetStruct()->view_source = frame_view_source;
+ GetStruct()->get_source = frame_get_source;
+ GetStruct()->get_text = frame_get_text;
+ GetStruct()->load_request = frame_load_request;
+ GetStruct()->load_url = frame_load_url;
+ GetStruct()->execute_java_script = frame_execute_java_script;
+ GetStruct()->is_main = frame_is_main;
+ GetStruct()->is_focused = frame_is_focused;
+ GetStruct()->get_name = frame_get_name;
+ GetStruct()->get_identifier = frame_get_identifier;
+ GetStruct()->get_parent = frame_get_parent;
+ GetStruct()->get_url = frame_get_url;
+ GetStruct()->get_browser = frame_get_browser;
+ GetStruct()->get_v8context = frame_get_v8context;
+ GetStruct()->visit_dom = frame_visit_dom;
+ GetStruct()->create_urlrequest = frame_create_urlrequest;
+ GetStruct()->send_process_message = frame_send_process_message;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefFrameCppToC::~CefFrameCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefFrame>
+CefCppToCRefCounted<CefFrameCppToC, CefFrame, cef_frame_t>::UnwrapDerived(
+ CefWrapperType type,
+ cef_frame_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCppToCRefCounted<CefFrameCppToC, CefFrame, cef_frame_t>::kWrapperType =
+ WT_FRAME;
diff --git a/libcef_dll/cpptoc/frame_cpptoc.h b/libcef_dll/cpptoc/frame_cpptoc.h
new file mode 100644
index 00000000..dab94690
--- /dev/null
+++ b/libcef_dll/cpptoc/frame_cpptoc.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=e2af583c7a4b0b6b071e9e96ce8645375902673d$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_FRAME_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_FRAME_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_browser_capi.h"
+#include "include/capi/cef_frame_capi.h"
+#include "include/capi/cef_urlrequest_capi.h"
+#include "include/capi/cef_v8_capi.h"
+#include "include/cef_browser.h"
+#include "include/cef_frame.h"
+#include "include/cef_urlrequest.h"
+#include "include/cef_v8.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefFrameCppToC
+ : public CefCppToCRefCounted<CefFrameCppToC, CefFrame, cef_frame_t> {
+ public:
+ CefFrameCppToC();
+ virtual ~CefFrameCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_FRAME_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/frame_handler_cpptoc.cc b/libcef_dll/cpptoc/frame_handler_cpptoc.cc
new file mode 100644
index 00000000..93f692cf
--- /dev/null
+++ b/libcef_dll/cpptoc/frame_handler_cpptoc.cc
@@ -0,0 +1,167 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=42bab23e4d8596214bbc40591bc50c784eecbf4d$
+//
+
+#include "libcef_dll/cpptoc/frame_handler_cpptoc.h"
+#include "libcef_dll/ctocpp/browser_ctocpp.h"
+#include "libcef_dll/ctocpp/frame_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK
+frame_handler_on_frame_created(struct _cef_frame_handler_t* self,
+ cef_browser_t* browser,
+ cef_frame_t* frame) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+ // Verify param: frame; type: refptr_diff
+ DCHECK(frame);
+ if (!frame) {
+ return;
+ }
+
+ // Execute
+ CefFrameHandlerCppToC::Get(self)->OnFrameCreated(
+ CefBrowserCToCpp::Wrap(browser), CefFrameCToCpp::Wrap(frame));
+}
+
+void CEF_CALLBACK
+frame_handler_on_frame_attached(struct _cef_frame_handler_t* self,
+ cef_browser_t* browser,
+ cef_frame_t* frame,
+ int reattached) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+ // Verify param: frame; type: refptr_diff
+ DCHECK(frame);
+ if (!frame) {
+ return;
+ }
+
+ // Execute
+ CefFrameHandlerCppToC::Get(self)->OnFrameAttached(
+ CefBrowserCToCpp::Wrap(browser), CefFrameCToCpp::Wrap(frame),
+ reattached ? true : false);
+}
+
+void CEF_CALLBACK
+frame_handler_on_frame_detached(struct _cef_frame_handler_t* self,
+ cef_browser_t* browser,
+ cef_frame_t* frame) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+ // Verify param: frame; type: refptr_diff
+ DCHECK(frame);
+ if (!frame) {
+ return;
+ }
+
+ // Execute
+ CefFrameHandlerCppToC::Get(self)->OnFrameDetached(
+ CefBrowserCToCpp::Wrap(browser), CefFrameCToCpp::Wrap(frame));
+}
+
+void CEF_CALLBACK
+frame_handler_on_main_frame_changed(struct _cef_frame_handler_t* self,
+ cef_browser_t* browser,
+ cef_frame_t* old_frame,
+ cef_frame_t* new_frame) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+ // Unverified params: old_frame, new_frame
+
+ // Execute
+ CefFrameHandlerCppToC::Get(self)->OnMainFrameChanged(
+ CefBrowserCToCpp::Wrap(browser), CefFrameCToCpp::Wrap(old_frame),
+ CefFrameCToCpp::Wrap(new_frame));
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefFrameHandlerCppToC::CefFrameHandlerCppToC() {
+ GetStruct()->on_frame_created = frame_handler_on_frame_created;
+ GetStruct()->on_frame_attached = frame_handler_on_frame_attached;
+ GetStruct()->on_frame_detached = frame_handler_on_frame_detached;
+ GetStruct()->on_main_frame_changed = frame_handler_on_main_frame_changed;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefFrameHandlerCppToC::~CefFrameHandlerCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefFrameHandler> CefCppToCRefCounted<
+ CefFrameHandlerCppToC,
+ CefFrameHandler,
+ cef_frame_handler_t>::UnwrapDerived(CefWrapperType type,
+ cef_frame_handler_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefFrameHandlerCppToC,
+ CefFrameHandler,
+ cef_frame_handler_t>::kWrapperType =
+ WT_FRAME_HANDLER;
diff --git a/libcef_dll/cpptoc/frame_handler_cpptoc.h b/libcef_dll/cpptoc/frame_handler_cpptoc.h
new file mode 100644
index 00000000..c553a2dd
--- /dev/null
+++ b/libcef_dll/cpptoc/frame_handler_cpptoc.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=72b035624f1edff425da000635d111f72186fffc$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_FRAME_HANDLER_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_FRAME_HANDLER_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_frame_handler_capi.h"
+#include "include/cef_frame_handler.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefFrameHandlerCppToC : public CefCppToCRefCounted<CefFrameHandlerCppToC,
+ CefFrameHandler,
+ cef_frame_handler_t> {
+ public:
+ CefFrameHandlerCppToC();
+ virtual ~CefFrameHandlerCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_FRAME_HANDLER_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/get_extension_resource_callback_cpptoc.cc b/libcef_dll/cpptoc/get_extension_resource_callback_cpptoc.cc
new file mode 100644
index 00000000..6306d343
--- /dev/null
+++ b/libcef_dll/cpptoc/get_extension_resource_callback_cpptoc.cc
@@ -0,0 +1,88 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=632d5681b71f4729ae9b56380eab24dfc49eda3a$
+//
+
+#include "libcef_dll/cpptoc/get_extension_resource_callback_cpptoc.h"
+#include "libcef_dll/cpptoc/stream_reader_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK get_extension_resource_callback_cont(
+ struct _cef_get_extension_resource_callback_t* self,
+ struct _cef_stream_reader_t* stream) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Unverified params: stream
+
+ // Execute
+ CefGetExtensionResourceCallbackCppToC::Get(self)->Continue(
+ CefStreamReaderCppToC::Unwrap(stream));
+}
+
+void CEF_CALLBACK get_extension_resource_callback_cancel(
+ struct _cef_get_extension_resource_callback_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefGetExtensionResourceCallbackCppToC::Get(self)->Cancel();
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefGetExtensionResourceCallbackCppToC::CefGetExtensionResourceCallbackCppToC() {
+ GetStruct()->cont = get_extension_resource_callback_cont;
+ GetStruct()->cancel = get_extension_resource_callback_cancel;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefGetExtensionResourceCallbackCppToC::
+ ~CefGetExtensionResourceCallbackCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefGetExtensionResourceCallback>
+CefCppToCRefCounted<CefGetExtensionResourceCallbackCppToC,
+ CefGetExtensionResourceCallback,
+ cef_get_extension_resource_callback_t>::
+ UnwrapDerived(CefWrapperType type,
+ cef_get_extension_resource_callback_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCppToCRefCounted<CefGetExtensionResourceCallbackCppToC,
+ CefGetExtensionResourceCallback,
+ cef_get_extension_resource_callback_t>::kWrapperType =
+ WT_GET_EXTENSION_RESOURCE_CALLBACK;
diff --git a/libcef_dll/cpptoc/get_extension_resource_callback_cpptoc.h b/libcef_dll/cpptoc/get_extension_resource_callback_cpptoc.h
new file mode 100644
index 00000000..0056536b
--- /dev/null
+++ b/libcef_dll/cpptoc/get_extension_resource_callback_cpptoc.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=76b58a0d3f719bb4899c87ec701d89a96a45ae31$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_GET_EXTENSION_RESOURCE_CALLBACK_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_GET_EXTENSION_RESOURCE_CALLBACK_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_client_capi.h"
+#include "include/capi/cef_extension_handler_capi.h"
+#include "include/cef_client.h"
+#include "include/cef_extension_handler.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefGetExtensionResourceCallbackCppToC
+ : public CefCppToCRefCounted<CefGetExtensionResourceCallbackCppToC,
+ CefGetExtensionResourceCallback,
+ cef_get_extension_resource_callback_t> {
+ public:
+ CefGetExtensionResourceCallbackCppToC();
+ virtual ~CefGetExtensionResourceCallbackCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_GET_EXTENSION_RESOURCE_CALLBACK_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/image_cpptoc.cc b/libcef_dll/cpptoc/image_cpptoc.cc
new file mode 100644
index 00000000..218c3690
--- /dev/null
+++ b/libcef_dll/cpptoc/image_cpptoc.cc
@@ -0,0 +1,469 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=b10ecc805dee1dd8d653276cc2633a5e439b2fa8$
+//
+
+#include "libcef_dll/cpptoc/image_cpptoc.h"
+#include "libcef_dll/cpptoc/binary_value_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// GLOBAL FUNCTIONS - Body may be edited by hand.
+
+CEF_EXPORT cef_image_t* cef_image_create() {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ CefRefPtr<CefImage> _retval = CefImage::CreateImage();
+
+ // Return type: refptr_same
+ return CefImageCppToC::Wrap(_retval);
+}
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK image_is_empty(struct _cef_image_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefImageCppToC::Get(self)->IsEmpty();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK image_is_same(struct _cef_image_t* self,
+ struct _cef_image_t* that) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: that; type: refptr_same
+ DCHECK(that);
+ if (!that) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefImageCppToC::Get(self)->IsSame(CefImageCppToC::Unwrap(that));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK image_add_bitmap(struct _cef_image_t* self,
+ float scale_factor,
+ int pixel_width,
+ int pixel_height,
+ cef_color_type_t color_type,
+ cef_alpha_type_t alpha_type,
+ const void* pixel_data,
+ size_t pixel_data_size) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: pixel_data; type: simple_byaddr
+ DCHECK(pixel_data);
+ if (!pixel_data) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefImageCppToC::Get(self)->AddBitmap(
+ scale_factor, pixel_width, pixel_height, color_type, alpha_type,
+ pixel_data, pixel_data_size);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK image_add_png(struct _cef_image_t* self,
+ float scale_factor,
+ const void* png_data,
+ size_t png_data_size) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: png_data; type: simple_byaddr
+ DCHECK(png_data);
+ if (!png_data) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefImageCppToC::Get(self)->AddPNG(scale_factor, png_data, png_data_size);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK image_add_jpeg(struct _cef_image_t* self,
+ float scale_factor,
+ const void* jpeg_data,
+ size_t jpeg_data_size) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: jpeg_data; type: simple_byaddr
+ DCHECK(jpeg_data);
+ if (!jpeg_data) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefImageCppToC::Get(self)->AddJPEG(scale_factor, jpeg_data,
+ jpeg_data_size);
+
+ // Return type: bool
+ return _retval;
+}
+
+size_t CEF_CALLBACK image_get_width(struct _cef_image_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ size_t _retval = CefImageCppToC::Get(self)->GetWidth();
+
+ // Return type: simple
+ return _retval;
+}
+
+size_t CEF_CALLBACK image_get_height(struct _cef_image_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ size_t _retval = CefImageCppToC::Get(self)->GetHeight();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK image_has_representation(struct _cef_image_t* self,
+ float scale_factor) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefImageCppToC::Get(self)->HasRepresentation(scale_factor);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK image_remove_representation(struct _cef_image_t* self,
+ float scale_factor) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefImageCppToC::Get(self)->RemoveRepresentation(scale_factor);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK image_get_representation_info(struct _cef_image_t* self,
+ float scale_factor,
+ float* actual_scale_factor,
+ int* pixel_width,
+ int* pixel_height) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: actual_scale_factor; type: simple_byref
+ DCHECK(actual_scale_factor);
+ if (!actual_scale_factor) {
+ return 0;
+ }
+ // Verify param: pixel_width; type: simple_byref
+ DCHECK(pixel_width);
+ if (!pixel_width) {
+ return 0;
+ }
+ // Verify param: pixel_height; type: simple_byref
+ DCHECK(pixel_height);
+ if (!pixel_height) {
+ return 0;
+ }
+
+ // Translate param: actual_scale_factor; type: simple_byref
+ float actual_scale_factorVal = actual_scale_factor ? *actual_scale_factor : 0;
+ // Translate param: pixel_width; type: simple_byref
+ int pixel_widthVal = pixel_width ? *pixel_width : 0;
+ // Translate param: pixel_height; type: simple_byref
+ int pixel_heightVal = pixel_height ? *pixel_height : 0;
+
+ // Execute
+ bool _retval = CefImageCppToC::Get(self)->GetRepresentationInfo(
+ scale_factor, actual_scale_factorVal, pixel_widthVal, pixel_heightVal);
+
+ // Restore param: actual_scale_factor; type: simple_byref
+ if (actual_scale_factor) {
+ *actual_scale_factor = actual_scale_factorVal;
+ }
+ // Restore param: pixel_width; type: simple_byref
+ if (pixel_width) {
+ *pixel_width = pixel_widthVal;
+ }
+ // Restore param: pixel_height; type: simple_byref
+ if (pixel_height) {
+ *pixel_height = pixel_heightVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+struct _cef_binary_value_t* CEF_CALLBACK
+image_get_as_bitmap(struct _cef_image_t* self,
+ float scale_factor,
+ cef_color_type_t color_type,
+ cef_alpha_type_t alpha_type,
+ int* pixel_width,
+ int* pixel_height) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+ // Verify param: pixel_width; type: simple_byref
+ DCHECK(pixel_width);
+ if (!pixel_width) {
+ return NULL;
+ }
+ // Verify param: pixel_height; type: simple_byref
+ DCHECK(pixel_height);
+ if (!pixel_height) {
+ return NULL;
+ }
+
+ // Translate param: pixel_width; type: simple_byref
+ int pixel_widthVal = pixel_width ? *pixel_width : 0;
+ // Translate param: pixel_height; type: simple_byref
+ int pixel_heightVal = pixel_height ? *pixel_height : 0;
+
+ // Execute
+ CefRefPtr<CefBinaryValue> _retval = CefImageCppToC::Get(self)->GetAsBitmap(
+ scale_factor, color_type, alpha_type, pixel_widthVal, pixel_heightVal);
+
+ // Restore param: pixel_width; type: simple_byref
+ if (pixel_width) {
+ *pixel_width = pixel_widthVal;
+ }
+ // Restore param: pixel_height; type: simple_byref
+ if (pixel_height) {
+ *pixel_height = pixel_heightVal;
+ }
+
+ // Return type: refptr_same
+ return CefBinaryValueCppToC::Wrap(_retval);
+}
+
+struct _cef_binary_value_t* CEF_CALLBACK
+image_get_as_png(struct _cef_image_t* self,
+ float scale_factor,
+ int with_transparency,
+ int* pixel_width,
+ int* pixel_height) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+ // Verify param: pixel_width; type: simple_byref
+ DCHECK(pixel_width);
+ if (!pixel_width) {
+ return NULL;
+ }
+ // Verify param: pixel_height; type: simple_byref
+ DCHECK(pixel_height);
+ if (!pixel_height) {
+ return NULL;
+ }
+
+ // Translate param: pixel_width; type: simple_byref
+ int pixel_widthVal = pixel_width ? *pixel_width : 0;
+ // Translate param: pixel_height; type: simple_byref
+ int pixel_heightVal = pixel_height ? *pixel_height : 0;
+
+ // Execute
+ CefRefPtr<CefBinaryValue> _retval = CefImageCppToC::Get(self)->GetAsPNG(
+ scale_factor, with_transparency ? true : false, pixel_widthVal,
+ pixel_heightVal);
+
+ // Restore param: pixel_width; type: simple_byref
+ if (pixel_width) {
+ *pixel_width = pixel_widthVal;
+ }
+ // Restore param: pixel_height; type: simple_byref
+ if (pixel_height) {
+ *pixel_height = pixel_heightVal;
+ }
+
+ // Return type: refptr_same
+ return CefBinaryValueCppToC::Wrap(_retval);
+}
+
+struct _cef_binary_value_t* CEF_CALLBACK
+image_get_as_jpeg(struct _cef_image_t* self,
+ float scale_factor,
+ int quality,
+ int* pixel_width,
+ int* pixel_height) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+ // Verify param: pixel_width; type: simple_byref
+ DCHECK(pixel_width);
+ if (!pixel_width) {
+ return NULL;
+ }
+ // Verify param: pixel_height; type: simple_byref
+ DCHECK(pixel_height);
+ if (!pixel_height) {
+ return NULL;
+ }
+
+ // Translate param: pixel_width; type: simple_byref
+ int pixel_widthVal = pixel_width ? *pixel_width : 0;
+ // Translate param: pixel_height; type: simple_byref
+ int pixel_heightVal = pixel_height ? *pixel_height : 0;
+
+ // Execute
+ CefRefPtr<CefBinaryValue> _retval = CefImageCppToC::Get(self)->GetAsJPEG(
+ scale_factor, quality, pixel_widthVal, pixel_heightVal);
+
+ // Restore param: pixel_width; type: simple_byref
+ if (pixel_width) {
+ *pixel_width = pixel_widthVal;
+ }
+ // Restore param: pixel_height; type: simple_byref
+ if (pixel_height) {
+ *pixel_height = pixel_heightVal;
+ }
+
+ // Return type: refptr_same
+ return CefBinaryValueCppToC::Wrap(_retval);
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefImageCppToC::CefImageCppToC() {
+ GetStruct()->is_empty = image_is_empty;
+ GetStruct()->is_same = image_is_same;
+ GetStruct()->add_bitmap = image_add_bitmap;
+ GetStruct()->add_png = image_add_png;
+ GetStruct()->add_jpeg = image_add_jpeg;
+ GetStruct()->get_width = image_get_width;
+ GetStruct()->get_height = image_get_height;
+ GetStruct()->has_representation = image_has_representation;
+ GetStruct()->remove_representation = image_remove_representation;
+ GetStruct()->get_representation_info = image_get_representation_info;
+ GetStruct()->get_as_bitmap = image_get_as_bitmap;
+ GetStruct()->get_as_png = image_get_as_png;
+ GetStruct()->get_as_jpeg = image_get_as_jpeg;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefImageCppToC::~CefImageCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefImage>
+CefCppToCRefCounted<CefImageCppToC, CefImage, cef_image_t>::UnwrapDerived(
+ CefWrapperType type,
+ cef_image_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCppToCRefCounted<CefImageCppToC, CefImage, cef_image_t>::kWrapperType =
+ WT_IMAGE;
diff --git a/libcef_dll/cpptoc/image_cpptoc.h b/libcef_dll/cpptoc/image_cpptoc.h
new file mode 100644
index 00000000..3f63462f
--- /dev/null
+++ b/libcef_dll/cpptoc/image_cpptoc.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=4ce026e90daa0a4d5d4be0baf1e8dbd3ede5974f$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_IMAGE_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_IMAGE_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_image_capi.h"
+#include "include/cef_image.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefImageCppToC
+ : public CefCppToCRefCounted<CefImageCppToC, CefImage, cef_image_t> {
+ public:
+ CefImageCppToC();
+ virtual ~CefImageCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_IMAGE_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/jsdialog_callback_cpptoc.cc b/libcef_dll/cpptoc/jsdialog_callback_cpptoc.cc
new file mode 100644
index 00000000..d4d2016e
--- /dev/null
+++ b/libcef_dll/cpptoc/jsdialog_callback_cpptoc.cc
@@ -0,0 +1,68 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=40725194bb474305e418e57cf1a7bfc4a3b6af1d$
+//
+
+#include "libcef_dll/cpptoc/jsdialog_callback_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK jsdialog_callback_cont(struct _cef_jsdialog_callback_t* self,
+ int success,
+ const cef_string_t* user_input) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Unverified params: user_input
+
+ // Execute
+ CefJSDialogCallbackCppToC::Get(self)->Continue(success ? true : false,
+ CefString(user_input));
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefJSDialogCallbackCppToC::CefJSDialogCallbackCppToC() {
+ GetStruct()->cont = jsdialog_callback_cont;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefJSDialogCallbackCppToC::~CefJSDialogCallbackCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefJSDialogCallback> CefCppToCRefCounted<
+ CefJSDialogCallbackCppToC,
+ CefJSDialogCallback,
+ cef_jsdialog_callback_t>::UnwrapDerived(CefWrapperType type,
+ cef_jsdialog_callback_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefJSDialogCallbackCppToC,
+ CefJSDialogCallback,
+ cef_jsdialog_callback_t>::kWrapperType =
+ WT_JSDIALOG_CALLBACK;
diff --git a/libcef_dll/cpptoc/jsdialog_callback_cpptoc.h b/libcef_dll/cpptoc/jsdialog_callback_cpptoc.h
new file mode 100644
index 00000000..772ae287
--- /dev/null
+++ b/libcef_dll/cpptoc/jsdialog_callback_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=37aac75252a6f35a8abe927ca603849ce98ac1e1$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_JSDIALOG_CALLBACK_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_JSDIALOG_CALLBACK_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_jsdialog_handler_capi.h"
+#include "include/cef_jsdialog_handler.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefJSDialogCallbackCppToC
+ : public CefCppToCRefCounted<CefJSDialogCallbackCppToC,
+ CefJSDialogCallback,
+ cef_jsdialog_callback_t> {
+ public:
+ CefJSDialogCallbackCppToC();
+ virtual ~CefJSDialogCallbackCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_JSDIALOG_CALLBACK_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/jsdialog_handler_cpptoc.cc b/libcef_dll/cpptoc/jsdialog_handler_cpptoc.cc
new file mode 100644
index 00000000..3122efe5
--- /dev/null
+++ b/libcef_dll/cpptoc/jsdialog_handler_cpptoc.cc
@@ -0,0 +1,188 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=351f3f71bc8fcee33ee063c17f34f7a9e7a99053$
+//
+
+#include "libcef_dll/cpptoc/jsdialog_handler_cpptoc.h"
+#include "libcef_dll/ctocpp/browser_ctocpp.h"
+#include "libcef_dll/ctocpp/jsdialog_callback_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK
+jsdialog_handler_on_jsdialog(struct _cef_jsdialog_handler_t* self,
+ cef_browser_t* browser,
+ const cef_string_t* origin_url,
+ cef_jsdialog_type_t dialog_type,
+ const cef_string_t* message_text,
+ const cef_string_t* default_prompt_text,
+ cef_jsdialog_callback_t* callback,
+ int* suppress_message) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return 0;
+ }
+ // Verify param: callback; type: refptr_diff
+ DCHECK(callback);
+ if (!callback) {
+ return 0;
+ }
+ // Verify param: suppress_message; type: bool_byref
+ DCHECK(suppress_message);
+ if (!suppress_message) {
+ return 0;
+ }
+ // Unverified params: origin_url, message_text, default_prompt_text
+
+ // Translate param: suppress_message; type: bool_byref
+ bool suppress_messageBool =
+ (suppress_message && *suppress_message) ? true : false;
+
+ // Execute
+ bool _retval = CefJSDialogHandlerCppToC::Get(self)->OnJSDialog(
+ CefBrowserCToCpp::Wrap(browser), CefString(origin_url), dialog_type,
+ CefString(message_text), CefString(default_prompt_text),
+ CefJSDialogCallbackCToCpp::Wrap(callback), suppress_messageBool);
+
+ // Restore param: suppress_message; type: bool_byref
+ if (suppress_message) {
+ *suppress_message = suppress_messageBool ? true : false;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+jsdialog_handler_on_before_unload_dialog(struct _cef_jsdialog_handler_t* self,
+ cef_browser_t* browser,
+ const cef_string_t* message_text,
+ int is_reload,
+ cef_jsdialog_callback_t* callback) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return 0;
+ }
+ // Verify param: callback; type: refptr_diff
+ DCHECK(callback);
+ if (!callback) {
+ return 0;
+ }
+ // Unverified params: message_text
+
+ // Execute
+ bool _retval = CefJSDialogHandlerCppToC::Get(self)->OnBeforeUnloadDialog(
+ CefBrowserCToCpp::Wrap(browser), CefString(message_text),
+ is_reload ? true : false, CefJSDialogCallbackCToCpp::Wrap(callback));
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK
+jsdialog_handler_on_reset_dialog_state(struct _cef_jsdialog_handler_t* self,
+ cef_browser_t* browser) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+
+ // Execute
+ CefJSDialogHandlerCppToC::Get(self)->OnResetDialogState(
+ CefBrowserCToCpp::Wrap(browser));
+}
+
+void CEF_CALLBACK
+jsdialog_handler_on_dialog_closed(struct _cef_jsdialog_handler_t* self,
+ cef_browser_t* browser) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+
+ // Execute
+ CefJSDialogHandlerCppToC::Get(self)->OnDialogClosed(
+ CefBrowserCToCpp::Wrap(browser));
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefJSDialogHandlerCppToC::CefJSDialogHandlerCppToC() {
+ GetStruct()->on_jsdialog = jsdialog_handler_on_jsdialog;
+ GetStruct()->on_before_unload_dialog =
+ jsdialog_handler_on_before_unload_dialog;
+ GetStruct()->on_reset_dialog_state = jsdialog_handler_on_reset_dialog_state;
+ GetStruct()->on_dialog_closed = jsdialog_handler_on_dialog_closed;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefJSDialogHandlerCppToC::~CefJSDialogHandlerCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefJSDialogHandler> CefCppToCRefCounted<
+ CefJSDialogHandlerCppToC,
+ CefJSDialogHandler,
+ cef_jsdialog_handler_t>::UnwrapDerived(CefWrapperType type,
+ cef_jsdialog_handler_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefJSDialogHandlerCppToC,
+ CefJSDialogHandler,
+ cef_jsdialog_handler_t>::kWrapperType =
+ WT_JSDIALOG_HANDLER;
diff --git a/libcef_dll/cpptoc/jsdialog_handler_cpptoc.h b/libcef_dll/cpptoc/jsdialog_handler_cpptoc.h
new file mode 100644
index 00000000..93f193d1
--- /dev/null
+++ b/libcef_dll/cpptoc/jsdialog_handler_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=c6a25a7ceb346f562302df398305f3d09a7c587d$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_JSDIALOG_HANDLER_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_JSDIALOG_HANDLER_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_jsdialog_handler_capi.h"
+#include "include/cef_jsdialog_handler.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefJSDialogHandlerCppToC
+ : public CefCppToCRefCounted<CefJSDialogHandlerCppToC,
+ CefJSDialogHandler,
+ cef_jsdialog_handler_t> {
+ public:
+ CefJSDialogHandlerCppToC();
+ virtual ~CefJSDialogHandlerCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_JSDIALOG_HANDLER_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/keyboard_handler_cpptoc.cc b/libcef_dll/cpptoc/keyboard_handler_cpptoc.cc
new file mode 100644
index 00000000..b0da609c
--- /dev/null
+++ b/libcef_dll/cpptoc/keyboard_handler_cpptoc.cc
@@ -0,0 +1,137 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=d7c3e9ff25364593a84be3b1cf30ed09897ecbcb$
+//
+
+#include "libcef_dll/cpptoc/keyboard_handler_cpptoc.h"
+#include "libcef_dll/ctocpp/browser_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK
+keyboard_handler_on_pre_key_event(struct _cef_keyboard_handler_t* self,
+ cef_browser_t* browser,
+ const cef_key_event_t* event,
+ cef_event_handle_t os_event,
+ int* is_keyboard_shortcut) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return 0;
+ }
+ // Verify param: event; type: simple_byref_const
+ DCHECK(event);
+ if (!event) {
+ return 0;
+ }
+ // Verify param: is_keyboard_shortcut; type: bool_byaddr
+ DCHECK(is_keyboard_shortcut);
+ if (!is_keyboard_shortcut) {
+ return 0;
+ }
+
+ // Translate param: event; type: simple_byref_const
+ CefKeyEvent eventVal = event ? *event : CefKeyEvent();
+ // Translate param: is_keyboard_shortcut; type: bool_byaddr
+ bool is_keyboard_shortcutBool =
+ (is_keyboard_shortcut && *is_keyboard_shortcut) ? true : false;
+
+ // Execute
+ bool _retval = CefKeyboardHandlerCppToC::Get(self)->OnPreKeyEvent(
+ CefBrowserCToCpp::Wrap(browser), eventVal, os_event,
+ &is_keyboard_shortcutBool);
+
+ // Restore param: is_keyboard_shortcut; type: bool_byaddr
+ if (is_keyboard_shortcut) {
+ *is_keyboard_shortcut = is_keyboard_shortcutBool ? true : false;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+keyboard_handler_on_key_event(struct _cef_keyboard_handler_t* self,
+ cef_browser_t* browser,
+ const cef_key_event_t* event,
+ cef_event_handle_t os_event) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return 0;
+ }
+ // Verify param: event; type: simple_byref_const
+ DCHECK(event);
+ if (!event) {
+ return 0;
+ }
+
+ // Translate param: event; type: simple_byref_const
+ CefKeyEvent eventVal = event ? *event : CefKeyEvent();
+
+ // Execute
+ bool _retval = CefKeyboardHandlerCppToC::Get(self)->OnKeyEvent(
+ CefBrowserCToCpp::Wrap(browser), eventVal, os_event);
+
+ // Return type: bool
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefKeyboardHandlerCppToC::CefKeyboardHandlerCppToC() {
+ GetStruct()->on_pre_key_event = keyboard_handler_on_pre_key_event;
+ GetStruct()->on_key_event = keyboard_handler_on_key_event;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefKeyboardHandlerCppToC::~CefKeyboardHandlerCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefKeyboardHandler> CefCppToCRefCounted<
+ CefKeyboardHandlerCppToC,
+ CefKeyboardHandler,
+ cef_keyboard_handler_t>::UnwrapDerived(CefWrapperType type,
+ cef_keyboard_handler_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefKeyboardHandlerCppToC,
+ CefKeyboardHandler,
+ cef_keyboard_handler_t>::kWrapperType =
+ WT_KEYBOARD_HANDLER;
diff --git a/libcef_dll/cpptoc/keyboard_handler_cpptoc.h b/libcef_dll/cpptoc/keyboard_handler_cpptoc.h
new file mode 100644
index 00000000..9ce294a1
--- /dev/null
+++ b/libcef_dll/cpptoc/keyboard_handler_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=0798f508afacf2ed239982052247da9cd7f366e9$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_KEYBOARD_HANDLER_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_KEYBOARD_HANDLER_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_keyboard_handler_capi.h"
+#include "include/cef_keyboard_handler.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefKeyboardHandlerCppToC
+ : public CefCppToCRefCounted<CefKeyboardHandlerCppToC,
+ CefKeyboardHandler,
+ cef_keyboard_handler_t> {
+ public:
+ CefKeyboardHandlerCppToC();
+ virtual ~CefKeyboardHandlerCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_KEYBOARD_HANDLER_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/life_span_handler_cpptoc.cc b/libcef_dll/cpptoc/life_span_handler_cpptoc.cc
new file mode 100644
index 00000000..abde17c6
--- /dev/null
+++ b/libcef_dll/cpptoc/life_span_handler_cpptoc.cc
@@ -0,0 +1,272 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=c291a5ca7c2c70c74ad26a20cafe0dffd07b5a73$
+//
+
+#include "libcef_dll/cpptoc/life_span_handler_cpptoc.h"
+#include "libcef_dll/cpptoc/client_cpptoc.h"
+#include "libcef_dll/ctocpp/browser_ctocpp.h"
+#include "libcef_dll/ctocpp/dictionary_value_ctocpp.h"
+#include "libcef_dll/ctocpp/frame_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+#include "libcef_dll/template_util.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK life_span_handler_on_before_popup(
+ struct _cef_life_span_handler_t* self,
+ cef_browser_t* browser,
+ cef_frame_t* frame,
+ const cef_string_t* target_url,
+ const cef_string_t* target_frame_name,
+ cef_window_open_disposition_t target_disposition,
+ int user_gesture,
+ const cef_popup_features_t* popupFeatures,
+ cef_window_info_t* windowInfo,
+ cef_client_t** client,
+ struct _cef_browser_settings_t* settings,
+ struct _cef_dictionary_value_t** extra_info,
+ int* no_javascript_access) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return 0;
+ }
+ // Verify param: frame; type: refptr_diff
+ DCHECK(frame);
+ if (!frame) {
+ return 0;
+ }
+ // Verify param: popupFeatures; type: simple_byref_const
+ DCHECK(popupFeatures);
+ if (!popupFeatures) {
+ return 0;
+ }
+ // Verify param: windowInfo; type: struct_byref
+ DCHECK(windowInfo);
+ if (!windowInfo) {
+ return 0;
+ }
+ if (!template_util::has_valid_size(windowInfo)) {
+ NOTREACHED() << "invalid windowInfo->[base.]size";
+ return 0;
+ }
+ // Verify param: client; type: refptr_same_byref
+ DCHECK(client);
+ if (!client) {
+ return 0;
+ }
+ // Verify param: settings; type: struct_byref
+ DCHECK(settings);
+ if (!settings) {
+ return 0;
+ }
+ if (!template_util::has_valid_size(settings)) {
+ NOTREACHED() << "invalid settings->[base.]size";
+ return 0;
+ }
+ // Verify param: extra_info; type: refptr_diff_byref
+ DCHECK(extra_info);
+ if (!extra_info) {
+ return 0;
+ }
+ // Verify param: no_javascript_access; type: bool_byaddr
+ DCHECK(no_javascript_access);
+ if (!no_javascript_access) {
+ return 0;
+ }
+ // Unverified params: target_url, target_frame_name
+
+ // Translate param: popupFeatures; type: simple_byref_const
+ CefPopupFeatures popupFeaturesVal =
+ popupFeatures ? *popupFeatures : CefPopupFeatures();
+ // Translate param: windowInfo; type: struct_byref
+ CefWindowInfo windowInfoObj;
+ if (windowInfo) {
+ windowInfoObj.AttachTo(*windowInfo);
+ }
+ // Translate param: client; type: refptr_same_byref
+ CefRefPtr<CefClient> clientPtr;
+ if (client && *client) {
+ clientPtr = CefClientCppToC::Unwrap(*client);
+ }
+ CefClient* clientOrig = clientPtr.get();
+ // Translate param: settings; type: struct_byref
+ CefBrowserSettings settingsObj;
+ if (settings) {
+ settingsObj.AttachTo(*settings);
+ }
+ // Translate param: extra_info; type: refptr_diff_byref
+ CefRefPtr<CefDictionaryValue> extra_infoPtr;
+ if (extra_info && *extra_info) {
+ extra_infoPtr = CefDictionaryValueCToCpp::Wrap(*extra_info);
+ }
+ CefDictionaryValue* extra_infoOrig = extra_infoPtr.get();
+ // Translate param: no_javascript_access; type: bool_byaddr
+ bool no_javascript_accessBool =
+ (no_javascript_access && *no_javascript_access) ? true : false;
+
+ // Execute
+ bool _retval = CefLifeSpanHandlerCppToC::Get(self)->OnBeforePopup(
+ CefBrowserCToCpp::Wrap(browser), CefFrameCToCpp::Wrap(frame),
+ CefString(target_url), CefString(target_frame_name), target_disposition,
+ user_gesture ? true : false, popupFeaturesVal, windowInfoObj, clientPtr,
+ settingsObj, extra_infoPtr, &no_javascript_accessBool);
+
+ // Restore param: windowInfo; type: struct_byref
+ if (windowInfo) {
+ windowInfoObj.DetachTo(*windowInfo);
+ }
+ // Restore param: client; type: refptr_same_byref
+ if (client) {
+ if (clientPtr.get()) {
+ if (clientPtr.get() != clientOrig) {
+ *client = CefClientCppToC::Wrap(clientPtr);
+ }
+ } else {
+ *client = nullptr;
+ }
+ }
+ // Restore param: settings; type: struct_byref
+ if (settings) {
+ settingsObj.DetachTo(*settings);
+ }
+ // Restore param: extra_info; type: refptr_diff_byref
+ if (extra_info) {
+ if (extra_infoPtr.get()) {
+ if (extra_infoPtr.get() != extra_infoOrig) {
+ *extra_info = CefDictionaryValueCToCpp::Unwrap(extra_infoPtr);
+ }
+ } else {
+ *extra_info = nullptr;
+ }
+ }
+ // Restore param: no_javascript_access; type: bool_byaddr
+ if (no_javascript_access) {
+ *no_javascript_access = no_javascript_accessBool ? true : false;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK
+life_span_handler_on_after_created(struct _cef_life_span_handler_t* self,
+ cef_browser_t* browser) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+
+ // Execute
+ CefLifeSpanHandlerCppToC::Get(self)->OnAfterCreated(
+ CefBrowserCToCpp::Wrap(browser));
+}
+
+int CEF_CALLBACK
+life_span_handler_do_close(struct _cef_life_span_handler_t* self,
+ cef_browser_t* browser) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefLifeSpanHandlerCppToC::Get(self)->DoClose(
+ CefBrowserCToCpp::Wrap(browser));
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK
+life_span_handler_on_before_close(struct _cef_life_span_handler_t* self,
+ cef_browser_t* browser) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+
+ // Execute
+ CefLifeSpanHandlerCppToC::Get(self)->OnBeforeClose(
+ CefBrowserCToCpp::Wrap(browser));
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefLifeSpanHandlerCppToC::CefLifeSpanHandlerCppToC() {
+ GetStruct()->on_before_popup = life_span_handler_on_before_popup;
+ GetStruct()->on_after_created = life_span_handler_on_after_created;
+ GetStruct()->do_close = life_span_handler_do_close;
+ GetStruct()->on_before_close = life_span_handler_on_before_close;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefLifeSpanHandlerCppToC::~CefLifeSpanHandlerCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefLifeSpanHandler> CefCppToCRefCounted<
+ CefLifeSpanHandlerCppToC,
+ CefLifeSpanHandler,
+ cef_life_span_handler_t>::UnwrapDerived(CefWrapperType type,
+ cef_life_span_handler_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefLifeSpanHandlerCppToC,
+ CefLifeSpanHandler,
+ cef_life_span_handler_t>::kWrapperType =
+ WT_LIFE_SPAN_HANDLER;
diff --git a/libcef_dll/cpptoc/life_span_handler_cpptoc.h b/libcef_dll/cpptoc/life_span_handler_cpptoc.h
new file mode 100644
index 00000000..531314a0
--- /dev/null
+++ b/libcef_dll/cpptoc/life_span_handler_cpptoc.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=74c66feec24c563e6f3f32230dcb0dbf45ed9350$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_LIFE_SPAN_HANDLER_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_LIFE_SPAN_HANDLER_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_client_capi.h"
+#include "include/capi/cef_life_span_handler_capi.h"
+#include "include/cef_client.h"
+#include "include/cef_life_span_handler.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefLifeSpanHandlerCppToC
+ : public CefCppToCRefCounted<CefLifeSpanHandlerCppToC,
+ CefLifeSpanHandler,
+ cef_life_span_handler_t> {
+ public:
+ CefLifeSpanHandlerCppToC();
+ virtual ~CefLifeSpanHandlerCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_LIFE_SPAN_HANDLER_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/list_value_cpptoc.cc b/libcef_dll/cpptoc/list_value_cpptoc.cc
new file mode 100644
index 00000000..68f3b40f
--- /dev/null
+++ b/libcef_dll/cpptoc/list_value_cpptoc.cc
@@ -0,0 +1,641 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=92a7ef208f4d8ca0e0591cfbeea22ef60a0c031d$
+//
+
+#include "libcef_dll/cpptoc/list_value_cpptoc.h"
+#include "libcef_dll/cpptoc/binary_value_cpptoc.h"
+#include "libcef_dll/cpptoc/dictionary_value_cpptoc.h"
+#include "libcef_dll/cpptoc/value_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// GLOBAL FUNCTIONS - Body may be edited by hand.
+
+CEF_EXPORT cef_list_value_t* cef_list_value_create() {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ CefRefPtr<CefListValue> _retval = CefListValue::Create();
+
+ // Return type: refptr_same
+ return CefListValueCppToC::Wrap(_retval);
+}
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK list_value_is_valid(struct _cef_list_value_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefListValueCppToC::Get(self)->IsValid();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK list_value_is_owned(struct _cef_list_value_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefListValueCppToC::Get(self)->IsOwned();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK list_value_is_read_only(struct _cef_list_value_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefListValueCppToC::Get(self)->IsReadOnly();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK list_value_is_same(struct _cef_list_value_t* self,
+ struct _cef_list_value_t* that) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: that; type: refptr_same
+ DCHECK(that);
+ if (!that) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefListValueCppToC::Get(self)->IsSame(CefListValueCppToC::Unwrap(that));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK list_value_is_equal(struct _cef_list_value_t* self,
+ struct _cef_list_value_t* that) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: that; type: refptr_same
+ DCHECK(that);
+ if (!that) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefListValueCppToC::Get(self)->IsEqual(CefListValueCppToC::Unwrap(that));
+
+ // Return type: bool
+ return _retval;
+}
+
+struct _cef_list_value_t* CEF_CALLBACK
+list_value_copy(struct _cef_list_value_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefListValue> _retval = CefListValueCppToC::Get(self)->Copy();
+
+ // Return type: refptr_same
+ return CefListValueCppToC::Wrap(_retval);
+}
+
+int CEF_CALLBACK list_value_set_size(struct _cef_list_value_t* self,
+ size_t size) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefListValueCppToC::Get(self)->SetSize(size);
+
+ // Return type: bool
+ return _retval;
+}
+
+size_t CEF_CALLBACK list_value_get_size(struct _cef_list_value_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ size_t _retval = CefListValueCppToC::Get(self)->GetSize();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK list_value_clear(struct _cef_list_value_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefListValueCppToC::Get(self)->Clear();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK list_value_remove(struct _cef_list_value_t* self,
+ size_t index) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefListValueCppToC::Get(self)->Remove(index);
+
+ // Return type: bool
+ return _retval;
+}
+
+cef_value_type_t CEF_CALLBACK
+list_value_get_type(struct _cef_list_value_t* self, size_t index) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return VTYPE_INVALID;
+ }
+
+ // Execute
+ cef_value_type_t _retval = CefListValueCppToC::Get(self)->GetType(index);
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_value_t* CEF_CALLBACK list_value_get_value(struct _cef_list_value_t* self,
+ size_t index) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefValue> _retval = CefListValueCppToC::Get(self)->GetValue(index);
+
+ // Return type: refptr_same
+ return CefValueCppToC::Wrap(_retval);
+}
+
+int CEF_CALLBACK list_value_get_bool(struct _cef_list_value_t* self,
+ size_t index) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefListValueCppToC::Get(self)->GetBool(index);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK list_value_get_int(struct _cef_list_value_t* self,
+ size_t index) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefListValueCppToC::Get(self)->GetInt(index);
+
+ // Return type: simple
+ return _retval;
+}
+
+double CEF_CALLBACK list_value_get_double(struct _cef_list_value_t* self,
+ size_t index) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ double _retval = CefListValueCppToC::Get(self)->GetDouble(index);
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_string_userfree_t CEF_CALLBACK
+list_value_get_string(struct _cef_list_value_t* self, size_t index) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefListValueCppToC::Get(self)->GetString(index);
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_binary_value_t* CEF_CALLBACK
+list_value_get_binary(struct _cef_list_value_t* self, size_t index) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefBinaryValue> _retval =
+ CefListValueCppToC::Get(self)->GetBinary(index);
+
+ // Return type: refptr_same
+ return CefBinaryValueCppToC::Wrap(_retval);
+}
+
+cef_dictionary_value_t* CEF_CALLBACK
+list_value_get_dictionary(struct _cef_list_value_t* self, size_t index) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefDictionaryValue> _retval =
+ CefListValueCppToC::Get(self)->GetDictionary(index);
+
+ // Return type: refptr_same
+ return CefDictionaryValueCppToC::Wrap(_retval);
+}
+
+struct _cef_list_value_t* CEF_CALLBACK
+list_value_get_list(struct _cef_list_value_t* self, size_t index) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefListValue> _retval =
+ CefListValueCppToC::Get(self)->GetList(index);
+
+ // Return type: refptr_same
+ return CefListValueCppToC::Wrap(_retval);
+}
+
+int CEF_CALLBACK list_value_set_value(struct _cef_list_value_t* self,
+ size_t index,
+ cef_value_t* value) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: value; type: refptr_same
+ DCHECK(value);
+ if (!value) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefListValueCppToC::Get(self)->SetValue(
+ index, CefValueCppToC::Unwrap(value));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK list_value_set_null(struct _cef_list_value_t* self,
+ size_t index) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefListValueCppToC::Get(self)->SetNull(index);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK list_value_set_bool(struct _cef_list_value_t* self,
+ size_t index,
+ int value) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefListValueCppToC::Get(self)->SetBool(index, value ? true : false);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK list_value_set_int(struct _cef_list_value_t* self,
+ size_t index,
+ int value) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefListValueCppToC::Get(self)->SetInt(index, value);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK list_value_set_double(struct _cef_list_value_t* self,
+ size_t index,
+ double value) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefListValueCppToC::Get(self)->SetDouble(index, value);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK list_value_set_string(struct _cef_list_value_t* self,
+ size_t index,
+ const cef_string_t* value) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Unverified params: value
+
+ // Execute
+ bool _retval =
+ CefListValueCppToC::Get(self)->SetString(index, CefString(value));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK list_value_set_binary(struct _cef_list_value_t* self,
+ size_t index,
+ cef_binary_value_t* value) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: value; type: refptr_same
+ DCHECK(value);
+ if (!value) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefListValueCppToC::Get(self)->SetBinary(
+ index, CefBinaryValueCppToC::Unwrap(value));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK list_value_set_dictionary(struct _cef_list_value_t* self,
+ size_t index,
+ cef_dictionary_value_t* value) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: value; type: refptr_same
+ DCHECK(value);
+ if (!value) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefListValueCppToC::Get(self)->SetDictionary(
+ index, CefDictionaryValueCppToC::Unwrap(value));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK list_value_set_list(struct _cef_list_value_t* self,
+ size_t index,
+ struct _cef_list_value_t* value) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: value; type: refptr_same
+ DCHECK(value);
+ if (!value) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefListValueCppToC::Get(self)->SetList(
+ index, CefListValueCppToC::Unwrap(value));
+
+ // Return type: bool
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefListValueCppToC::CefListValueCppToC() {
+ GetStruct()->is_valid = list_value_is_valid;
+ GetStruct()->is_owned = list_value_is_owned;
+ GetStruct()->is_read_only = list_value_is_read_only;
+ GetStruct()->is_same = list_value_is_same;
+ GetStruct()->is_equal = list_value_is_equal;
+ GetStruct()->copy = list_value_copy;
+ GetStruct()->set_size = list_value_set_size;
+ GetStruct()->get_size = list_value_get_size;
+ GetStruct()->clear = list_value_clear;
+ GetStruct()->remove = list_value_remove;
+ GetStruct()->get_type = list_value_get_type;
+ GetStruct()->get_value = list_value_get_value;
+ GetStruct()->get_bool = list_value_get_bool;
+ GetStruct()->get_int = list_value_get_int;
+ GetStruct()->get_double = list_value_get_double;
+ GetStruct()->get_string = list_value_get_string;
+ GetStruct()->get_binary = list_value_get_binary;
+ GetStruct()->get_dictionary = list_value_get_dictionary;
+ GetStruct()->get_list = list_value_get_list;
+ GetStruct()->set_value = list_value_set_value;
+ GetStruct()->set_null = list_value_set_null;
+ GetStruct()->set_bool = list_value_set_bool;
+ GetStruct()->set_int = list_value_set_int;
+ GetStruct()->set_double = list_value_set_double;
+ GetStruct()->set_string = list_value_set_string;
+ GetStruct()->set_binary = list_value_set_binary;
+ GetStruct()->set_dictionary = list_value_set_dictionary;
+ GetStruct()->set_list = list_value_set_list;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefListValueCppToC::~CefListValueCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefListValue>
+CefCppToCRefCounted<CefListValueCppToC, CefListValue, cef_list_value_t>::
+ UnwrapDerived(CefWrapperType type, cef_list_value_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefListValueCppToC,
+ CefListValue,
+ cef_list_value_t>::kWrapperType =
+ WT_LIST_VALUE;
diff --git a/libcef_dll/cpptoc/list_value_cpptoc.h b/libcef_dll/cpptoc/list_value_cpptoc.h
new file mode 100644
index 00000000..3e7b9c51
--- /dev/null
+++ b/libcef_dll/cpptoc/list_value_cpptoc.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=bb4f6bacea8366b11d1526059c5ad4c3df495630$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_LIST_VALUE_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_LIST_VALUE_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_values_capi.h"
+#include "include/cef_values.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefListValueCppToC : public CefCppToCRefCounted<CefListValueCppToC,
+ CefListValue,
+ cef_list_value_t> {
+ public:
+ CefListValueCppToC();
+ virtual ~CefListValueCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_LIST_VALUE_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/load_handler_cpptoc.cc b/libcef_dll/cpptoc/load_handler_cpptoc.cc
new file mode 100644
index 00000000..48e7100a
--- /dev/null
+++ b/libcef_dll/cpptoc/load_handler_cpptoc.cc
@@ -0,0 +1,175 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=afd356d9f7ef20662f649b44d1349783b02b2da1$
+//
+
+#include "libcef_dll/cpptoc/load_handler_cpptoc.h"
+#include "libcef_dll/ctocpp/browser_ctocpp.h"
+#include "libcef_dll/ctocpp/frame_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK
+load_handler_on_loading_state_change(struct _cef_load_handler_t* self,
+ cef_browser_t* browser,
+ int isLoading,
+ int canGoBack,
+ int canGoForward) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+
+ // Execute
+ CefLoadHandlerCppToC::Get(self)->OnLoadingStateChange(
+ CefBrowserCToCpp::Wrap(browser), isLoading ? true : false,
+ canGoBack ? true : false, canGoForward ? true : false);
+}
+
+void CEF_CALLBACK
+load_handler_on_load_start(struct _cef_load_handler_t* self,
+ cef_browser_t* browser,
+ cef_frame_t* frame,
+ cef_transition_type_t transition_type) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+ // Verify param: frame; type: refptr_diff
+ DCHECK(frame);
+ if (!frame) {
+ return;
+ }
+
+ // Execute
+ CefLoadHandlerCppToC::Get(self)->OnLoadStart(CefBrowserCToCpp::Wrap(browser),
+ CefFrameCToCpp::Wrap(frame),
+ transition_type);
+}
+
+void CEF_CALLBACK load_handler_on_load_end(struct _cef_load_handler_t* self,
+ cef_browser_t* browser,
+ cef_frame_t* frame,
+ int httpStatusCode) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+ // Verify param: frame; type: refptr_diff
+ DCHECK(frame);
+ if (!frame) {
+ return;
+ }
+
+ // Execute
+ CefLoadHandlerCppToC::Get(self)->OnLoadEnd(CefBrowserCToCpp::Wrap(browser),
+ CefFrameCToCpp::Wrap(frame),
+ httpStatusCode);
+}
+
+void CEF_CALLBACK load_handler_on_load_error(struct _cef_load_handler_t* self,
+ cef_browser_t* browser,
+ cef_frame_t* frame,
+ cef_errorcode_t errorCode,
+ const cef_string_t* errorText,
+ const cef_string_t* failedUrl) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+ // Verify param: frame; type: refptr_diff
+ DCHECK(frame);
+ if (!frame) {
+ return;
+ }
+ // Verify param: failedUrl; type: string_byref_const
+ DCHECK(failedUrl);
+ if (!failedUrl) {
+ return;
+ }
+ // Unverified params: errorText
+
+ // Execute
+ CefLoadHandlerCppToC::Get(self)->OnLoadError(
+ CefBrowserCToCpp::Wrap(browser), CefFrameCToCpp::Wrap(frame), errorCode,
+ CefString(errorText), CefString(failedUrl));
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefLoadHandlerCppToC::CefLoadHandlerCppToC() {
+ GetStruct()->on_loading_state_change = load_handler_on_loading_state_change;
+ GetStruct()->on_load_start = load_handler_on_load_start;
+ GetStruct()->on_load_end = load_handler_on_load_end;
+ GetStruct()->on_load_error = load_handler_on_load_error;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefLoadHandlerCppToC::~CefLoadHandlerCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefLoadHandler>
+CefCppToCRefCounted<CefLoadHandlerCppToC, CefLoadHandler, cef_load_handler_t>::
+ UnwrapDerived(CefWrapperType type, cef_load_handler_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefLoadHandlerCppToC,
+ CefLoadHandler,
+ cef_load_handler_t>::kWrapperType =
+ WT_LOAD_HANDLER;
diff --git a/libcef_dll/cpptoc/load_handler_cpptoc.h b/libcef_dll/cpptoc/load_handler_cpptoc.h
new file mode 100644
index 00000000..b17e7746
--- /dev/null
+++ b/libcef_dll/cpptoc/load_handler_cpptoc.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=60feef3855499ffd313c9e10fe4e8a6304acc871$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_LOAD_HANDLER_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_LOAD_HANDLER_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_load_handler_capi.h"
+#include "include/cef_load_handler.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefLoadHandlerCppToC : public CefCppToCRefCounted<CefLoadHandlerCppToC,
+ CefLoadHandler,
+ cef_load_handler_t> {
+ public:
+ CefLoadHandlerCppToC();
+ virtual ~CefLoadHandlerCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_LOAD_HANDLER_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/media_access_callback_cpptoc.cc b/libcef_dll/cpptoc/media_access_callback_cpptoc.cc
new file mode 100644
index 00000000..371503be
--- /dev/null
+++ b/libcef_dll/cpptoc/media_access_callback_cpptoc.cc
@@ -0,0 +1,83 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=a6f40e6aedccd7784cad96c4e8097dae6a1add6b$
+//
+
+#include "libcef_dll/cpptoc/media_access_callback_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK
+media_access_callback_cont(struct _cef_media_access_callback_t* self,
+ uint32 allowed_permissions) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefMediaAccessCallbackCppToC::Get(self)->Continue(allowed_permissions);
+}
+
+void CEF_CALLBACK
+media_access_callback_cancel(struct _cef_media_access_callback_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefMediaAccessCallbackCppToC::Get(self)->Cancel();
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefMediaAccessCallbackCppToC::CefMediaAccessCallbackCppToC() {
+ GetStruct()->cont = media_access_callback_cont;
+ GetStruct()->cancel = media_access_callback_cancel;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefMediaAccessCallbackCppToC::~CefMediaAccessCallbackCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefMediaAccessCallback> CefCppToCRefCounted<
+ CefMediaAccessCallbackCppToC,
+ CefMediaAccessCallback,
+ cef_media_access_callback_t>::UnwrapDerived(CefWrapperType type,
+ cef_media_access_callback_t*
+ s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefMediaAccessCallbackCppToC,
+ CefMediaAccessCallback,
+ cef_media_access_callback_t>::kWrapperType =
+ WT_MEDIA_ACCESS_CALLBACK;
diff --git a/libcef_dll/cpptoc/media_access_callback_cpptoc.h b/libcef_dll/cpptoc/media_access_callback_cpptoc.h
new file mode 100644
index 00000000..9609f4e4
--- /dev/null
+++ b/libcef_dll/cpptoc/media_access_callback_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=4b3da65396a9a358cbcdb289e275062a7b4402d5$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_MEDIA_ACCESS_CALLBACK_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_MEDIA_ACCESS_CALLBACK_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_permission_handler_capi.h"
+#include "include/cef_permission_handler.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefMediaAccessCallbackCppToC
+ : public CefCppToCRefCounted<CefMediaAccessCallbackCppToC,
+ CefMediaAccessCallback,
+ cef_media_access_callback_t> {
+ public:
+ CefMediaAccessCallbackCppToC();
+ virtual ~CefMediaAccessCallbackCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_MEDIA_ACCESS_CALLBACK_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/media_observer_cpptoc.cc b/libcef_dll/cpptoc/media_observer_cpptoc.cc
new file mode 100644
index 00000000..6bc8fbb8
--- /dev/null
+++ b/libcef_dll/cpptoc/media_observer_cpptoc.cc
@@ -0,0 +1,170 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=77226fbe14eaa99f4adbf6573d6ee2a8687b936d$
+//
+
+#include "libcef_dll/cpptoc/media_observer_cpptoc.h"
+#include "libcef_dll/ctocpp/media_route_ctocpp.h"
+#include "libcef_dll/ctocpp/media_sink_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK
+media_observer_on_sinks(struct _cef_media_observer_t* self,
+ size_t sinksCount,
+ struct _cef_media_sink_t* const* sinks) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: sinks; type: refptr_vec_diff_byref_const
+ DCHECK(sinksCount == 0 || sinks);
+ if (sinksCount > 0 && !sinks) {
+ return;
+ }
+
+ // Translate param: sinks; type: refptr_vec_diff_byref_const
+ std::vector<CefRefPtr<CefMediaSink>> sinksList;
+ if (sinksCount > 0) {
+ for (size_t i = 0; i < sinksCount; ++i) {
+ CefRefPtr<CefMediaSink> sinksVal = CefMediaSinkCToCpp::Wrap(sinks[i]);
+ sinksList.push_back(sinksVal);
+ }
+ }
+
+ // Execute
+ CefMediaObserverCppToC::Get(self)->OnSinks(sinksList);
+}
+
+void CEF_CALLBACK
+media_observer_on_routes(struct _cef_media_observer_t* self,
+ size_t routesCount,
+ struct _cef_media_route_t* const* routes) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: routes; type: refptr_vec_diff_byref_const
+ DCHECK(routesCount == 0 || routes);
+ if (routesCount > 0 && !routes) {
+ return;
+ }
+
+ // Translate param: routes; type: refptr_vec_diff_byref_const
+ std::vector<CefRefPtr<CefMediaRoute>> routesList;
+ if (routesCount > 0) {
+ for (size_t i = 0; i < routesCount; ++i) {
+ CefRefPtr<CefMediaRoute> routesVal = CefMediaRouteCToCpp::Wrap(routes[i]);
+ routesList.push_back(routesVal);
+ }
+ }
+
+ // Execute
+ CefMediaObserverCppToC::Get(self)->OnRoutes(routesList);
+}
+
+void CEF_CALLBACK media_observer_on_route_state_changed(
+ struct _cef_media_observer_t* self,
+ struct _cef_media_route_t* route,
+ cef_media_route_connection_state_t state) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: route; type: refptr_diff
+ DCHECK(route);
+ if (!route) {
+ return;
+ }
+
+ // Execute
+ CefMediaObserverCppToC::Get(self)->OnRouteStateChanged(
+ CefMediaRouteCToCpp::Wrap(route), state);
+}
+
+void CEF_CALLBACK
+media_observer_on_route_message_received(struct _cef_media_observer_t* self,
+ struct _cef_media_route_t* route,
+ const void* message,
+ size_t message_size) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: route; type: refptr_diff
+ DCHECK(route);
+ if (!route) {
+ return;
+ }
+ // Verify param: message; type: simple_byaddr
+ DCHECK(message);
+ if (!message) {
+ return;
+ }
+
+ // Execute
+ CefMediaObserverCppToC::Get(self)->OnRouteMessageReceived(
+ CefMediaRouteCToCpp::Wrap(route), message, message_size);
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefMediaObserverCppToC::CefMediaObserverCppToC() {
+ GetStruct()->on_sinks = media_observer_on_sinks;
+ GetStruct()->on_routes = media_observer_on_routes;
+ GetStruct()->on_route_state_changed = media_observer_on_route_state_changed;
+ GetStruct()->on_route_message_received =
+ media_observer_on_route_message_received;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefMediaObserverCppToC::~CefMediaObserverCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefMediaObserver> CefCppToCRefCounted<
+ CefMediaObserverCppToC,
+ CefMediaObserver,
+ cef_media_observer_t>::UnwrapDerived(CefWrapperType type,
+ cef_media_observer_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefMediaObserverCppToC,
+ CefMediaObserver,
+ cef_media_observer_t>::kWrapperType =
+ WT_MEDIA_OBSERVER;
diff --git a/libcef_dll/cpptoc/media_observer_cpptoc.h b/libcef_dll/cpptoc/media_observer_cpptoc.h
new file mode 100644
index 00000000..0161197d
--- /dev/null
+++ b/libcef_dll/cpptoc/media_observer_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=79a189744a4f09ec791d9636b247f090aa2cae58$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_MEDIA_OBSERVER_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_MEDIA_OBSERVER_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_media_router_capi.h"
+#include "include/cef_media_router.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefMediaObserverCppToC
+ : public CefCppToCRefCounted<CefMediaObserverCppToC,
+ CefMediaObserver,
+ cef_media_observer_t> {
+ public:
+ CefMediaObserverCppToC();
+ virtual ~CefMediaObserverCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_MEDIA_OBSERVER_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/media_route_cpptoc.cc b/libcef_dll/cpptoc/media_route_cpptoc.cc
new file mode 100644
index 00000000..289c113d
--- /dev/null
+++ b/libcef_dll/cpptoc/media_route_cpptoc.cc
@@ -0,0 +1,145 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=117fcfcb178f8a8a08272186c250c4042fcd74c0$
+//
+
+#include "libcef_dll/cpptoc/media_route_cpptoc.h"
+#include "libcef_dll/cpptoc/media_sink_cpptoc.h"
+#include "libcef_dll/cpptoc/media_source_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+cef_string_userfree_t CEF_CALLBACK
+media_route_get_id(struct _cef_media_route_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefMediaRouteCppToC::Get(self)->GetId();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+struct _cef_media_source_t* CEF_CALLBACK
+media_route_get_source(struct _cef_media_route_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefMediaSource> _retval =
+ CefMediaRouteCppToC::Get(self)->GetSource();
+
+ // Return type: refptr_same
+ return CefMediaSourceCppToC::Wrap(_retval);
+}
+
+struct _cef_media_sink_t* CEF_CALLBACK
+media_route_get_sink(struct _cef_media_route_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefMediaSink> _retval = CefMediaRouteCppToC::Get(self)->GetSink();
+
+ // Return type: refptr_same
+ return CefMediaSinkCppToC::Wrap(_retval);
+}
+
+void CEF_CALLBACK
+media_route_send_route_message(struct _cef_media_route_t* self,
+ const void* message,
+ size_t message_size) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: message; type: simple_byaddr
+ DCHECK(message);
+ if (!message) {
+ return;
+ }
+
+ // Execute
+ CefMediaRouteCppToC::Get(self)->SendRouteMessage(message, message_size);
+}
+
+void CEF_CALLBACK media_route_terminate(struct _cef_media_route_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefMediaRouteCppToC::Get(self)->Terminate();
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefMediaRouteCppToC::CefMediaRouteCppToC() {
+ GetStruct()->get_id = media_route_get_id;
+ GetStruct()->get_source = media_route_get_source;
+ GetStruct()->get_sink = media_route_get_sink;
+ GetStruct()->send_route_message = media_route_send_route_message;
+ GetStruct()->terminate = media_route_terminate;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefMediaRouteCppToC::~CefMediaRouteCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefMediaRoute>
+CefCppToCRefCounted<CefMediaRouteCppToC, CefMediaRoute, cef_media_route_t>::
+ UnwrapDerived(CefWrapperType type, cef_media_route_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefMediaRouteCppToC,
+ CefMediaRoute,
+ cef_media_route_t>::kWrapperType =
+ WT_MEDIA_ROUTE;
diff --git a/libcef_dll/cpptoc/media_route_cpptoc.h b/libcef_dll/cpptoc/media_route_cpptoc.h
new file mode 100644
index 00000000..c204275d
--- /dev/null
+++ b/libcef_dll/cpptoc/media_route_cpptoc.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=3489d6674c9411c8240767db40adff59a6f2ae4e$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_MEDIA_ROUTE_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_MEDIA_ROUTE_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_media_router_capi.h"
+#include "include/cef_media_router.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefMediaRouteCppToC : public CefCppToCRefCounted<CefMediaRouteCppToC,
+ CefMediaRoute,
+ cef_media_route_t> {
+ public:
+ CefMediaRouteCppToC();
+ virtual ~CefMediaRouteCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_MEDIA_ROUTE_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/media_route_create_callback_cpptoc.cc b/libcef_dll/cpptoc/media_route_create_callback_cpptoc.cc
new file mode 100644
index 00000000..de6d3341
--- /dev/null
+++ b/libcef_dll/cpptoc/media_route_create_callback_cpptoc.cc
@@ -0,0 +1,73 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=5e5e23e9c36b269a49017fcb412e925b2124c409$
+//
+
+#include "libcef_dll/cpptoc/media_route_create_callback_cpptoc.h"
+#include "libcef_dll/ctocpp/media_route_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK media_route_create_callback_on_media_route_create_finished(
+ struct _cef_media_route_create_callback_t* self,
+ cef_media_route_create_result_t result,
+ const cef_string_t* error,
+ cef_media_route_t* route) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Unverified params: error, route
+
+ // Execute
+ CefMediaRouteCreateCallbackCppToC::Get(self)->OnMediaRouteCreateFinished(
+ result, CefString(error), CefMediaRouteCToCpp::Wrap(route));
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefMediaRouteCreateCallbackCppToC::CefMediaRouteCreateCallbackCppToC() {
+ GetStruct()->on_media_route_create_finished =
+ media_route_create_callback_on_media_route_create_finished;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefMediaRouteCreateCallbackCppToC::~CefMediaRouteCreateCallbackCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefMediaRouteCreateCallback>
+CefCppToCRefCounted<CefMediaRouteCreateCallbackCppToC,
+ CefMediaRouteCreateCallback,
+ cef_media_route_create_callback_t>::
+ UnwrapDerived(CefWrapperType type, cef_media_route_create_callback_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCppToCRefCounted<CefMediaRouteCreateCallbackCppToC,
+ CefMediaRouteCreateCallback,
+ cef_media_route_create_callback_t>::kWrapperType =
+ WT_MEDIA_ROUTE_CREATE_CALLBACK;
diff --git a/libcef_dll/cpptoc/media_route_create_callback_cpptoc.h b/libcef_dll/cpptoc/media_route_create_callback_cpptoc.h
new file mode 100644
index 00000000..b28004ce
--- /dev/null
+++ b/libcef_dll/cpptoc/media_route_create_callback_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=d40e59390639a5fb850103f7b8a458e3bc1c8f55$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_MEDIA_ROUTE_CREATE_CALLBACK_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_MEDIA_ROUTE_CREATE_CALLBACK_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_media_router_capi.h"
+#include "include/cef_media_router.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefMediaRouteCreateCallbackCppToC
+ : public CefCppToCRefCounted<CefMediaRouteCreateCallbackCppToC,
+ CefMediaRouteCreateCallback,
+ cef_media_route_create_callback_t> {
+ public:
+ CefMediaRouteCreateCallbackCppToC();
+ virtual ~CefMediaRouteCreateCallbackCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_MEDIA_ROUTE_CREATE_CALLBACK_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/media_router_cpptoc.cc b/libcef_dll/cpptoc/media_router_cpptoc.cc
new file mode 100644
index 00000000..586a63f2
--- /dev/null
+++ b/libcef_dll/cpptoc/media_router_cpptoc.cc
@@ -0,0 +1,192 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=d5e33d2f86d782fb59cd8d5a88596a65825e8de5$
+//
+
+#include "libcef_dll/cpptoc/media_router_cpptoc.h"
+#include "libcef_dll/cpptoc/media_sink_cpptoc.h"
+#include "libcef_dll/cpptoc/media_source_cpptoc.h"
+#include "libcef_dll/cpptoc/registration_cpptoc.h"
+#include "libcef_dll/ctocpp/completion_callback_ctocpp.h"
+#include "libcef_dll/ctocpp/media_observer_ctocpp.h"
+#include "libcef_dll/ctocpp/media_route_create_callback_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// GLOBAL FUNCTIONS - Body may be edited by hand.
+
+CEF_EXPORT cef_media_router_t* cef_media_router_get_global(
+ cef_completion_callback_t* callback) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: callback
+
+ // Execute
+ CefRefPtr<CefMediaRouter> _retval = CefMediaRouter::GetGlobalMediaRouter(
+ CefCompletionCallbackCToCpp::Wrap(callback));
+
+ // Return type: refptr_same
+ return CefMediaRouterCppToC::Wrap(_retval);
+}
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+struct _cef_registration_t* CEF_CALLBACK
+media_router_add_observer(struct _cef_media_router_t* self,
+ struct _cef_media_observer_t* observer) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+ // Verify param: observer; type: refptr_diff
+ DCHECK(observer);
+ if (!observer) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefRegistration> _retval =
+ CefMediaRouterCppToC::Get(self)->AddObserver(
+ CefMediaObserverCToCpp::Wrap(observer));
+
+ // Return type: refptr_same
+ return CefRegistrationCppToC::Wrap(_retval);
+}
+
+struct _cef_media_source_t* CEF_CALLBACK
+media_router_get_source(struct _cef_media_router_t* self,
+ const cef_string_t* urn) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+ // Verify param: urn; type: string_byref_const
+ DCHECK(urn);
+ if (!urn) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefMediaSource> _retval =
+ CefMediaRouterCppToC::Get(self)->GetSource(CefString(urn));
+
+ // Return type: refptr_same
+ return CefMediaSourceCppToC::Wrap(_retval);
+}
+
+void CEF_CALLBACK
+media_router_notify_current_sinks(struct _cef_media_router_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefMediaRouterCppToC::Get(self)->NotifyCurrentSinks();
+}
+
+void CEF_CALLBACK
+media_router_create_route(struct _cef_media_router_t* self,
+ struct _cef_media_source_t* source,
+ struct _cef_media_sink_t* sink,
+ struct _cef_media_route_create_callback_t* callback) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: source; type: refptr_same
+ DCHECK(source);
+ if (!source) {
+ return;
+ }
+ // Verify param: sink; type: refptr_same
+ DCHECK(sink);
+ if (!sink) {
+ return;
+ }
+ // Verify param: callback; type: refptr_diff
+ DCHECK(callback);
+ if (!callback) {
+ return;
+ }
+
+ // Execute
+ CefMediaRouterCppToC::Get(self)->CreateRoute(
+ CefMediaSourceCppToC::Unwrap(source), CefMediaSinkCppToC::Unwrap(sink),
+ CefMediaRouteCreateCallbackCToCpp::Wrap(callback));
+}
+
+void CEF_CALLBACK
+media_router_notify_current_routes(struct _cef_media_router_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefMediaRouterCppToC::Get(self)->NotifyCurrentRoutes();
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefMediaRouterCppToC::CefMediaRouterCppToC() {
+ GetStruct()->add_observer = media_router_add_observer;
+ GetStruct()->get_source = media_router_get_source;
+ GetStruct()->notify_current_sinks = media_router_notify_current_sinks;
+ GetStruct()->create_route = media_router_create_route;
+ GetStruct()->notify_current_routes = media_router_notify_current_routes;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefMediaRouterCppToC::~CefMediaRouterCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefMediaRouter>
+CefCppToCRefCounted<CefMediaRouterCppToC, CefMediaRouter, cef_media_router_t>::
+ UnwrapDerived(CefWrapperType type, cef_media_router_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefMediaRouterCppToC,
+ CefMediaRouter,
+ cef_media_router_t>::kWrapperType =
+ WT_MEDIA_ROUTER;
diff --git a/libcef_dll/cpptoc/media_router_cpptoc.h b/libcef_dll/cpptoc/media_router_cpptoc.h
new file mode 100644
index 00000000..f7d5c937
--- /dev/null
+++ b/libcef_dll/cpptoc/media_router_cpptoc.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=9b393780a7f736211be3b2ac604af8b59226db5e$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_MEDIA_ROUTER_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_MEDIA_ROUTER_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_media_router_capi.h"
+#include "include/cef_media_router.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefMediaRouterCppToC : public CefCppToCRefCounted<CefMediaRouterCppToC,
+ CefMediaRouter,
+ cef_media_router_t> {
+ public:
+ CefMediaRouterCppToC();
+ virtual ~CefMediaRouterCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_MEDIA_ROUTER_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/media_sink_cpptoc.cc b/libcef_dll/cpptoc/media_sink_cpptoc.cc
new file mode 100644
index 00000000..98e032a5
--- /dev/null
+++ b/libcef_dll/cpptoc/media_sink_cpptoc.cc
@@ -0,0 +1,192 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=9a49bd42c37e24a9f968dc703b91ac0a0d467471$
+//
+
+#include "libcef_dll/cpptoc/media_sink_cpptoc.h"
+#include "libcef_dll/cpptoc/media_source_cpptoc.h"
+#include "libcef_dll/ctocpp/media_sink_device_info_callback_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+cef_string_userfree_t CEF_CALLBACK
+media_sink_get_id(struct _cef_media_sink_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefMediaSinkCppToC::Get(self)->GetId();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_string_userfree_t CEF_CALLBACK
+media_sink_get_name(struct _cef_media_sink_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefMediaSinkCppToC::Get(self)->GetName();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_media_sink_icon_type_t CEF_CALLBACK
+media_sink_get_icon_type(struct _cef_media_sink_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CEF_MSIT_GENERIC;
+ }
+
+ // Execute
+ cef_media_sink_icon_type_t _retval =
+ CefMediaSinkCppToC::Get(self)->GetIconType();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK media_sink_get_device_info(
+ struct _cef_media_sink_t* self,
+ struct _cef_media_sink_device_info_callback_t* callback) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: callback; type: refptr_diff
+ DCHECK(callback);
+ if (!callback) {
+ return;
+ }
+
+ // Execute
+ CefMediaSinkCppToC::Get(self)->GetDeviceInfo(
+ CefMediaSinkDeviceInfoCallbackCToCpp::Wrap(callback));
+}
+
+int CEF_CALLBACK media_sink_is_cast_sink(struct _cef_media_sink_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefMediaSinkCppToC::Get(self)->IsCastSink();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK media_sink_is_dial_sink(struct _cef_media_sink_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefMediaSinkCppToC::Get(self)->IsDialSink();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+media_sink_is_compatible_with(struct _cef_media_sink_t* self,
+ struct _cef_media_source_t* source) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: source; type: refptr_same
+ DCHECK(source);
+ if (!source) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefMediaSinkCppToC::Get(self)->IsCompatibleWith(
+ CefMediaSourceCppToC::Unwrap(source));
+
+ // Return type: bool
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefMediaSinkCppToC::CefMediaSinkCppToC() {
+ GetStruct()->get_id = media_sink_get_id;
+ GetStruct()->get_name = media_sink_get_name;
+ GetStruct()->get_icon_type = media_sink_get_icon_type;
+ GetStruct()->get_device_info = media_sink_get_device_info;
+ GetStruct()->is_cast_sink = media_sink_is_cast_sink;
+ GetStruct()->is_dial_sink = media_sink_is_dial_sink;
+ GetStruct()->is_compatible_with = media_sink_is_compatible_with;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefMediaSinkCppToC::~CefMediaSinkCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefMediaSink>
+CefCppToCRefCounted<CefMediaSinkCppToC, CefMediaSink, cef_media_sink_t>::
+ UnwrapDerived(CefWrapperType type, cef_media_sink_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefMediaSinkCppToC,
+ CefMediaSink,
+ cef_media_sink_t>::kWrapperType =
+ WT_MEDIA_SINK;
diff --git a/libcef_dll/cpptoc/media_sink_cpptoc.h b/libcef_dll/cpptoc/media_sink_cpptoc.h
new file mode 100644
index 00000000..3252cf28
--- /dev/null
+++ b/libcef_dll/cpptoc/media_sink_cpptoc.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=233a4ba3634b10b92d605e85bb49ccb7f4e0abe3$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_MEDIA_SINK_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_MEDIA_SINK_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_media_router_capi.h"
+#include "include/cef_media_router.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefMediaSinkCppToC : public CefCppToCRefCounted<CefMediaSinkCppToC,
+ CefMediaSink,
+ cef_media_sink_t> {
+ public:
+ CefMediaSinkCppToC();
+ virtual ~CefMediaSinkCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_MEDIA_SINK_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/media_sink_device_info_callback_cpptoc.cc b/libcef_dll/cpptoc/media_sink_device_info_callback_cpptoc.cc
new file mode 100644
index 00000000..614bac25
--- /dev/null
+++ b/libcef_dll/cpptoc/media_sink_device_info_callback_cpptoc.cc
@@ -0,0 +1,86 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=820d68c7a5b1ccc305da5f644b2875a5db6fabc9$
+//
+
+#include "libcef_dll/cpptoc/media_sink_device_info_callback_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+#include "libcef_dll/template_util.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK media_sink_device_info_callback_on_media_sink_device_info(
+ struct _cef_media_sink_device_info_callback_t* self,
+ const struct _cef_media_sink_device_info_t* device_info) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: device_info; type: struct_byref_const
+ DCHECK(device_info);
+ if (!device_info) {
+ return;
+ }
+ if (!template_util::has_valid_size(device_info)) {
+ NOTREACHED() << "invalid device_info->[base.]size";
+ return;
+ }
+
+ // Translate param: device_info; type: struct_byref_const
+ CefMediaSinkDeviceInfo device_infoObj;
+ if (device_info) {
+ device_infoObj.Set(*device_info, false);
+ }
+
+ // Execute
+ CefMediaSinkDeviceInfoCallbackCppToC::Get(self)->OnMediaSinkDeviceInfo(
+ device_infoObj);
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefMediaSinkDeviceInfoCallbackCppToC::CefMediaSinkDeviceInfoCallbackCppToC() {
+ GetStruct()->on_media_sink_device_info =
+ media_sink_device_info_callback_on_media_sink_device_info;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefMediaSinkDeviceInfoCallbackCppToC::~CefMediaSinkDeviceInfoCallbackCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefMediaSinkDeviceInfoCallback>
+CefCppToCRefCounted<CefMediaSinkDeviceInfoCallbackCppToC,
+ CefMediaSinkDeviceInfoCallback,
+ cef_media_sink_device_info_callback_t>::
+ UnwrapDerived(CefWrapperType type,
+ cef_media_sink_device_info_callback_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCppToCRefCounted<CefMediaSinkDeviceInfoCallbackCppToC,
+ CefMediaSinkDeviceInfoCallback,
+ cef_media_sink_device_info_callback_t>::kWrapperType =
+ WT_MEDIA_SINK_DEVICE_INFO_CALLBACK;
diff --git a/libcef_dll/cpptoc/media_sink_device_info_callback_cpptoc.h b/libcef_dll/cpptoc/media_sink_device_info_callback_cpptoc.h
new file mode 100644
index 00000000..0522de76
--- /dev/null
+++ b/libcef_dll/cpptoc/media_sink_device_info_callback_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=66fb13a617c9405f7829e797b21a663e5275e61d$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_MEDIA_SINK_DEVICE_INFO_CALLBACK_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_MEDIA_SINK_DEVICE_INFO_CALLBACK_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_media_router_capi.h"
+#include "include/cef_media_router.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefMediaSinkDeviceInfoCallbackCppToC
+ : public CefCppToCRefCounted<CefMediaSinkDeviceInfoCallbackCppToC,
+ CefMediaSinkDeviceInfoCallback,
+ cef_media_sink_device_info_callback_t> {
+ public:
+ CefMediaSinkDeviceInfoCallbackCppToC();
+ virtual ~CefMediaSinkDeviceInfoCallbackCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_MEDIA_SINK_DEVICE_INFO_CALLBACK_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/media_source_cpptoc.cc b/libcef_dll/cpptoc/media_source_cpptoc.cc
new file mode 100644
index 00000000..d3bc03ec
--- /dev/null
+++ b/libcef_dll/cpptoc/media_source_cpptoc.cc
@@ -0,0 +1,102 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=0722c0684e9a958fd4a841994f5ab0db1bc903ff$
+//
+
+#include "libcef_dll/cpptoc/media_source_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+cef_string_userfree_t CEF_CALLBACK
+media_source_get_id(struct _cef_media_source_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefMediaSourceCppToC::Get(self)->GetId();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+int CEF_CALLBACK media_source_is_cast_source(struct _cef_media_source_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefMediaSourceCppToC::Get(self)->IsCastSource();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK media_source_is_dial_source(struct _cef_media_source_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefMediaSourceCppToC::Get(self)->IsDialSource();
+
+ // Return type: bool
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefMediaSourceCppToC::CefMediaSourceCppToC() {
+ GetStruct()->get_id = media_source_get_id;
+ GetStruct()->is_cast_source = media_source_is_cast_source;
+ GetStruct()->is_dial_source = media_source_is_dial_source;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefMediaSourceCppToC::~CefMediaSourceCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefMediaSource>
+CefCppToCRefCounted<CefMediaSourceCppToC, CefMediaSource, cef_media_source_t>::
+ UnwrapDerived(CefWrapperType type, cef_media_source_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefMediaSourceCppToC,
+ CefMediaSource,
+ cef_media_source_t>::kWrapperType =
+ WT_MEDIA_SOURCE;
diff --git a/libcef_dll/cpptoc/media_source_cpptoc.h b/libcef_dll/cpptoc/media_source_cpptoc.h
new file mode 100644
index 00000000..25f10d6e
--- /dev/null
+++ b/libcef_dll/cpptoc/media_source_cpptoc.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=ac61adb518bfd33bcc31e62410a1849dbf73dc3f$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_MEDIA_SOURCE_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_MEDIA_SOURCE_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_media_router_capi.h"
+#include "include/cef_media_router.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefMediaSourceCppToC : public CefCppToCRefCounted<CefMediaSourceCppToC,
+ CefMediaSource,
+ cef_media_source_t> {
+ public:
+ CefMediaSourceCppToC();
+ virtual ~CefMediaSourceCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_MEDIA_SOURCE_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/menu_model_cpptoc.cc b/libcef_dll/cpptoc/menu_model_cpptoc.cc
new file mode 100644
index 00000000..8712579a
--- /dev/null
+++ b/libcef_dll/cpptoc/menu_model_cpptoc.cc
@@ -0,0 +1,1389 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=7b74378527d1d6e92b30248f25704ef262106e6d$
+//
+
+#include "libcef_dll/cpptoc/menu_model_cpptoc.h"
+#include "libcef_dll/ctocpp/menu_model_delegate_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// GLOBAL FUNCTIONS - Body may be edited by hand.
+
+CEF_EXPORT cef_menu_model_t* cef_menu_model_create(
+ struct _cef_menu_model_delegate_t* delegate) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: delegate; type: refptr_diff
+ DCHECK(delegate);
+ if (!delegate) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefMenuModel> _retval =
+ CefMenuModel::CreateMenuModel(CefMenuModelDelegateCToCpp::Wrap(delegate));
+
+ // Return type: refptr_same
+ return CefMenuModelCppToC::Wrap(_retval);
+}
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK menu_model_is_sub_menu(struct _cef_menu_model_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefMenuModelCppToC::Get(self)->IsSubMenu();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK menu_model_clear(struct _cef_menu_model_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefMenuModelCppToC::Get(self)->Clear();
+
+ // Return type: bool
+ return _retval;
+}
+
+size_t CEF_CALLBACK menu_model_get_count(struct _cef_menu_model_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ size_t _retval = CefMenuModelCppToC::Get(self)->GetCount();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK menu_model_add_separator(struct _cef_menu_model_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefMenuModelCppToC::Get(self)->AddSeparator();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK menu_model_add_item(struct _cef_menu_model_t* self,
+ int command_id,
+ const cef_string_t* label) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: label; type: string_byref_const
+ DCHECK(label);
+ if (!label) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefMenuModelCppToC::Get(self)->AddItem(command_id, CefString(label));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK menu_model_add_check_item(struct _cef_menu_model_t* self,
+ int command_id,
+ const cef_string_t* label) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: label; type: string_byref_const
+ DCHECK(label);
+ if (!label) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefMenuModelCppToC::Get(self)->AddCheckItem(command_id, CefString(label));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK menu_model_add_radio_item(struct _cef_menu_model_t* self,
+ int command_id,
+ const cef_string_t* label,
+ int group_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: label; type: string_byref_const
+ DCHECK(label);
+ if (!label) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefMenuModelCppToC::Get(self)->AddRadioItem(
+ command_id, CefString(label), group_id);
+
+ // Return type: bool
+ return _retval;
+}
+
+struct _cef_menu_model_t* CEF_CALLBACK
+menu_model_add_sub_menu(struct _cef_menu_model_t* self,
+ int command_id,
+ const cef_string_t* label) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+ // Verify param: label; type: string_byref_const
+ DCHECK(label);
+ if (!label) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefMenuModel> _retval =
+ CefMenuModelCppToC::Get(self)->AddSubMenu(command_id, CefString(label));
+
+ // Return type: refptr_same
+ return CefMenuModelCppToC::Wrap(_retval);
+}
+
+int CEF_CALLBACK menu_model_insert_separator_at(struct _cef_menu_model_t* self,
+ size_t index) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefMenuModelCppToC::Get(self)->InsertSeparatorAt(index);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK menu_model_insert_item_at(struct _cef_menu_model_t* self,
+ size_t index,
+ int command_id,
+ const cef_string_t* label) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: label; type: string_byref_const
+ DCHECK(label);
+ if (!label) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefMenuModelCppToC::Get(self)->InsertItemAt(index, command_id,
+ CefString(label));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK menu_model_insert_check_item_at(struct _cef_menu_model_t* self,
+ size_t index,
+ int command_id,
+ const cef_string_t* label) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: label; type: string_byref_const
+ DCHECK(label);
+ if (!label) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefMenuModelCppToC::Get(self)->InsertCheckItemAt(
+ index, command_id, CefString(label));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK menu_model_insert_radio_item_at(struct _cef_menu_model_t* self,
+ size_t index,
+ int command_id,
+ const cef_string_t* label,
+ int group_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: label; type: string_byref_const
+ DCHECK(label);
+ if (!label) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefMenuModelCppToC::Get(self)->InsertRadioItemAt(
+ index, command_id, CefString(label), group_id);
+
+ // Return type: bool
+ return _retval;
+}
+
+struct _cef_menu_model_t* CEF_CALLBACK
+menu_model_insert_sub_menu_at(struct _cef_menu_model_t* self,
+ size_t index,
+ int command_id,
+ const cef_string_t* label) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+ // Verify param: label; type: string_byref_const
+ DCHECK(label);
+ if (!label) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefMenuModel> _retval =
+ CefMenuModelCppToC::Get(self)->InsertSubMenuAt(index, command_id,
+ CefString(label));
+
+ // Return type: refptr_same
+ return CefMenuModelCppToC::Wrap(_retval);
+}
+
+int CEF_CALLBACK menu_model_remove(struct _cef_menu_model_t* self,
+ int command_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefMenuModelCppToC::Get(self)->Remove(command_id);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK menu_model_remove_at(struct _cef_menu_model_t* self,
+ size_t index) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefMenuModelCppToC::Get(self)->RemoveAt(index);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK menu_model_get_index_of(struct _cef_menu_model_t* self,
+ int command_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefMenuModelCppToC::Get(self)->GetIndexOf(command_id);
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK menu_model_get_command_id_at(struct _cef_menu_model_t* self,
+ size_t index) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefMenuModelCppToC::Get(self)->GetCommandIdAt(index);
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK menu_model_set_command_id_at(struct _cef_menu_model_t* self,
+ size_t index,
+ int command_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefMenuModelCppToC::Get(self)->SetCommandIdAt(index, command_id);
+
+ // Return type: bool
+ return _retval;
+}
+
+cef_string_userfree_t CEF_CALLBACK
+menu_model_get_label(struct _cef_menu_model_t* self, int command_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefMenuModelCppToC::Get(self)->GetLabel(command_id);
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_string_userfree_t CEF_CALLBACK
+menu_model_get_label_at(struct _cef_menu_model_t* self, size_t index) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefMenuModelCppToC::Get(self)->GetLabelAt(index);
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+int CEF_CALLBACK menu_model_set_label(struct _cef_menu_model_t* self,
+ int command_id,
+ const cef_string_t* label) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: label; type: string_byref_const
+ DCHECK(label);
+ if (!label) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefMenuModelCppToC::Get(self)->SetLabel(command_id, CefString(label));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK menu_model_set_label_at(struct _cef_menu_model_t* self,
+ size_t index,
+ const cef_string_t* label) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: label; type: string_byref_const
+ DCHECK(label);
+ if (!label) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefMenuModelCppToC::Get(self)->SetLabelAt(index, CefString(label));
+
+ // Return type: bool
+ return _retval;
+}
+
+cef_menu_item_type_t CEF_CALLBACK
+menu_model_get_type(struct _cef_menu_model_t* self, int command_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return MENUITEMTYPE_NONE;
+ }
+
+ // Execute
+ cef_menu_item_type_t _retval =
+ CefMenuModelCppToC::Get(self)->GetType(command_id);
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_menu_item_type_t CEF_CALLBACK
+menu_model_get_type_at(struct _cef_menu_model_t* self, size_t index) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return MENUITEMTYPE_NONE;
+ }
+
+ // Execute
+ cef_menu_item_type_t _retval =
+ CefMenuModelCppToC::Get(self)->GetTypeAt(index);
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK menu_model_get_group_id(struct _cef_menu_model_t* self,
+ int command_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefMenuModelCppToC::Get(self)->GetGroupId(command_id);
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK menu_model_get_group_id_at(struct _cef_menu_model_t* self,
+ size_t index) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefMenuModelCppToC::Get(self)->GetGroupIdAt(index);
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK menu_model_set_group_id(struct _cef_menu_model_t* self,
+ int command_id,
+ int group_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefMenuModelCppToC::Get(self)->SetGroupId(command_id, group_id);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK menu_model_set_group_id_at(struct _cef_menu_model_t* self,
+ size_t index,
+ int group_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefMenuModelCppToC::Get(self)->SetGroupIdAt(index, group_id);
+
+ // Return type: bool
+ return _retval;
+}
+
+struct _cef_menu_model_t* CEF_CALLBACK
+menu_model_get_sub_menu(struct _cef_menu_model_t* self, int command_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefMenuModel> _retval =
+ CefMenuModelCppToC::Get(self)->GetSubMenu(command_id);
+
+ // Return type: refptr_same
+ return CefMenuModelCppToC::Wrap(_retval);
+}
+
+struct _cef_menu_model_t* CEF_CALLBACK
+menu_model_get_sub_menu_at(struct _cef_menu_model_t* self, size_t index) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefMenuModel> _retval =
+ CefMenuModelCppToC::Get(self)->GetSubMenuAt(index);
+
+ // Return type: refptr_same
+ return CefMenuModelCppToC::Wrap(_retval);
+}
+
+int CEF_CALLBACK menu_model_is_visible(struct _cef_menu_model_t* self,
+ int command_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefMenuModelCppToC::Get(self)->IsVisible(command_id);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK menu_model_is_visible_at(struct _cef_menu_model_t* self,
+ size_t index) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefMenuModelCppToC::Get(self)->IsVisibleAt(index);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK menu_model_set_visible(struct _cef_menu_model_t* self,
+ int command_id,
+ int visible) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefMenuModelCppToC::Get(self)->SetVisible(
+ command_id, visible ? true : false);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK menu_model_set_visible_at(struct _cef_menu_model_t* self,
+ size_t index,
+ int visible) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefMenuModelCppToC::Get(self)->SetVisibleAt(
+ index, visible ? true : false);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK menu_model_is_enabled(struct _cef_menu_model_t* self,
+ int command_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefMenuModelCppToC::Get(self)->IsEnabled(command_id);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK menu_model_is_enabled_at(struct _cef_menu_model_t* self,
+ size_t index) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefMenuModelCppToC::Get(self)->IsEnabledAt(index);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK menu_model_set_enabled(struct _cef_menu_model_t* self,
+ int command_id,
+ int enabled) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefMenuModelCppToC::Get(self)->SetEnabled(
+ command_id, enabled ? true : false);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK menu_model_set_enabled_at(struct _cef_menu_model_t* self,
+ size_t index,
+ int enabled) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefMenuModelCppToC::Get(self)->SetEnabledAt(
+ index, enabled ? true : false);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK menu_model_is_checked(struct _cef_menu_model_t* self,
+ int command_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefMenuModelCppToC::Get(self)->IsChecked(command_id);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK menu_model_is_checked_at(struct _cef_menu_model_t* self,
+ size_t index) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefMenuModelCppToC::Get(self)->IsCheckedAt(index);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK menu_model_set_checked(struct _cef_menu_model_t* self,
+ int command_id,
+ int checked) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefMenuModelCppToC::Get(self)->SetChecked(
+ command_id, checked ? true : false);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK menu_model_set_checked_at(struct _cef_menu_model_t* self,
+ size_t index,
+ int checked) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefMenuModelCppToC::Get(self)->SetCheckedAt(
+ index, checked ? true : false);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK menu_model_has_accelerator(struct _cef_menu_model_t* self,
+ int command_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefMenuModelCppToC::Get(self)->HasAccelerator(command_id);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK menu_model_has_accelerator_at(struct _cef_menu_model_t* self,
+ size_t index) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefMenuModelCppToC::Get(self)->HasAcceleratorAt(index);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK menu_model_set_accelerator(struct _cef_menu_model_t* self,
+ int command_id,
+ int key_code,
+ int shift_pressed,
+ int ctrl_pressed,
+ int alt_pressed) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefMenuModelCppToC::Get(self)->SetAccelerator(
+ command_id, key_code, shift_pressed ? true : false,
+ ctrl_pressed ? true : false, alt_pressed ? true : false);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK menu_model_set_accelerator_at(struct _cef_menu_model_t* self,
+ size_t index,
+ int key_code,
+ int shift_pressed,
+ int ctrl_pressed,
+ int alt_pressed) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefMenuModelCppToC::Get(self)->SetAcceleratorAt(
+ index, key_code, shift_pressed ? true : false,
+ ctrl_pressed ? true : false, alt_pressed ? true : false);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK menu_model_remove_accelerator(struct _cef_menu_model_t* self,
+ int command_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefMenuModelCppToC::Get(self)->RemoveAccelerator(command_id);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+menu_model_remove_accelerator_at(struct _cef_menu_model_t* self, size_t index) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefMenuModelCppToC::Get(self)->RemoveAcceleratorAt(index);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK menu_model_get_accelerator(struct _cef_menu_model_t* self,
+ int command_id,
+ int* key_code,
+ int* shift_pressed,
+ int* ctrl_pressed,
+ int* alt_pressed) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: key_code; type: simple_byref
+ DCHECK(key_code);
+ if (!key_code) {
+ return 0;
+ }
+ // Verify param: shift_pressed; type: bool_byref
+ DCHECK(shift_pressed);
+ if (!shift_pressed) {
+ return 0;
+ }
+ // Verify param: ctrl_pressed; type: bool_byref
+ DCHECK(ctrl_pressed);
+ if (!ctrl_pressed) {
+ return 0;
+ }
+ // Verify param: alt_pressed; type: bool_byref
+ DCHECK(alt_pressed);
+ if (!alt_pressed) {
+ return 0;
+ }
+
+ // Translate param: key_code; type: simple_byref
+ int key_codeVal = key_code ? *key_code : 0;
+ // Translate param: shift_pressed; type: bool_byref
+ bool shift_pressedBool = (shift_pressed && *shift_pressed) ? true : false;
+ // Translate param: ctrl_pressed; type: bool_byref
+ bool ctrl_pressedBool = (ctrl_pressed && *ctrl_pressed) ? true : false;
+ // Translate param: alt_pressed; type: bool_byref
+ bool alt_pressedBool = (alt_pressed && *alt_pressed) ? true : false;
+
+ // Execute
+ bool _retval = CefMenuModelCppToC::Get(self)->GetAccelerator(
+ command_id, key_codeVal, shift_pressedBool, ctrl_pressedBool,
+ alt_pressedBool);
+
+ // Restore param: key_code; type: simple_byref
+ if (key_code) {
+ *key_code = key_codeVal;
+ }
+ // Restore param: shift_pressed; type: bool_byref
+ if (shift_pressed) {
+ *shift_pressed = shift_pressedBool ? true : false;
+ }
+ // Restore param: ctrl_pressed; type: bool_byref
+ if (ctrl_pressed) {
+ *ctrl_pressed = ctrl_pressedBool ? true : false;
+ }
+ // Restore param: alt_pressed; type: bool_byref
+ if (alt_pressed) {
+ *alt_pressed = alt_pressedBool ? true : false;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK menu_model_get_accelerator_at(struct _cef_menu_model_t* self,
+ size_t index,
+ int* key_code,
+ int* shift_pressed,
+ int* ctrl_pressed,
+ int* alt_pressed) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: key_code; type: simple_byref
+ DCHECK(key_code);
+ if (!key_code) {
+ return 0;
+ }
+ // Verify param: shift_pressed; type: bool_byref
+ DCHECK(shift_pressed);
+ if (!shift_pressed) {
+ return 0;
+ }
+ // Verify param: ctrl_pressed; type: bool_byref
+ DCHECK(ctrl_pressed);
+ if (!ctrl_pressed) {
+ return 0;
+ }
+ // Verify param: alt_pressed; type: bool_byref
+ DCHECK(alt_pressed);
+ if (!alt_pressed) {
+ return 0;
+ }
+
+ // Translate param: key_code; type: simple_byref
+ int key_codeVal = key_code ? *key_code : 0;
+ // Translate param: shift_pressed; type: bool_byref
+ bool shift_pressedBool = (shift_pressed && *shift_pressed) ? true : false;
+ // Translate param: ctrl_pressed; type: bool_byref
+ bool ctrl_pressedBool = (ctrl_pressed && *ctrl_pressed) ? true : false;
+ // Translate param: alt_pressed; type: bool_byref
+ bool alt_pressedBool = (alt_pressed && *alt_pressed) ? true : false;
+
+ // Execute
+ bool _retval = CefMenuModelCppToC::Get(self)->GetAcceleratorAt(
+ index, key_codeVal, shift_pressedBool, ctrl_pressedBool, alt_pressedBool);
+
+ // Restore param: key_code; type: simple_byref
+ if (key_code) {
+ *key_code = key_codeVal;
+ }
+ // Restore param: shift_pressed; type: bool_byref
+ if (shift_pressed) {
+ *shift_pressed = shift_pressedBool ? true : false;
+ }
+ // Restore param: ctrl_pressed; type: bool_byref
+ if (ctrl_pressed) {
+ *ctrl_pressed = ctrl_pressedBool ? true : false;
+ }
+ // Restore param: alt_pressed; type: bool_byref
+ if (alt_pressed) {
+ *alt_pressed = alt_pressedBool ? true : false;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK menu_model_set_color(struct _cef_menu_model_t* self,
+ int command_id,
+ cef_menu_color_type_t color_type,
+ cef_color_t color) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefMenuModelCppToC::Get(self)->SetColor(command_id, color_type, color);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK menu_model_set_color_at(struct _cef_menu_model_t* self,
+ int index,
+ cef_menu_color_type_t color_type,
+ cef_color_t color) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefMenuModelCppToC::Get(self)->SetColorAt(index, color_type, color);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK menu_model_get_color(struct _cef_menu_model_t* self,
+ int command_id,
+ cef_menu_color_type_t color_type,
+ cef_color_t* color) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: color; type: simple_byref
+ DCHECK(color);
+ if (!color) {
+ return 0;
+ }
+
+ // Translate param: color; type: simple_byref
+ cef_color_t colorVal = color ? *color : 0;
+
+ // Execute
+ bool _retval =
+ CefMenuModelCppToC::Get(self)->GetColor(command_id, color_type, colorVal);
+
+ // Restore param: color; type: simple_byref
+ if (color) {
+ *color = colorVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK menu_model_get_color_at(struct _cef_menu_model_t* self,
+ int index,
+ cef_menu_color_type_t color_type,
+ cef_color_t* color) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: color; type: simple_byref
+ DCHECK(color);
+ if (!color) {
+ return 0;
+ }
+
+ // Translate param: color; type: simple_byref
+ cef_color_t colorVal = color ? *color : 0;
+
+ // Execute
+ bool _retval =
+ CefMenuModelCppToC::Get(self)->GetColorAt(index, color_type, colorVal);
+
+ // Restore param: color; type: simple_byref
+ if (color) {
+ *color = colorVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK menu_model_set_font_list(struct _cef_menu_model_t* self,
+ int command_id,
+ const cef_string_t* font_list) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Unverified params: font_list
+
+ // Execute
+ bool _retval = CefMenuModelCppToC::Get(self)->SetFontList(
+ command_id, CefString(font_list));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK menu_model_set_font_list_at(struct _cef_menu_model_t* self,
+ int index,
+ const cef_string_t* font_list) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Unverified params: font_list
+
+ // Execute
+ bool _retval =
+ CefMenuModelCppToC::Get(self)->SetFontListAt(index, CefString(font_list));
+
+ // Return type: bool
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefMenuModelCppToC::CefMenuModelCppToC() {
+ GetStruct()->is_sub_menu = menu_model_is_sub_menu;
+ GetStruct()->clear = menu_model_clear;
+ GetStruct()->get_count = menu_model_get_count;
+ GetStruct()->add_separator = menu_model_add_separator;
+ GetStruct()->add_item = menu_model_add_item;
+ GetStruct()->add_check_item = menu_model_add_check_item;
+ GetStruct()->add_radio_item = menu_model_add_radio_item;
+ GetStruct()->add_sub_menu = menu_model_add_sub_menu;
+ GetStruct()->insert_separator_at = menu_model_insert_separator_at;
+ GetStruct()->insert_item_at = menu_model_insert_item_at;
+ GetStruct()->insert_check_item_at = menu_model_insert_check_item_at;
+ GetStruct()->insert_radio_item_at = menu_model_insert_radio_item_at;
+ GetStruct()->insert_sub_menu_at = menu_model_insert_sub_menu_at;
+ GetStruct()->remove = menu_model_remove;
+ GetStruct()->remove_at = menu_model_remove_at;
+ GetStruct()->get_index_of = menu_model_get_index_of;
+ GetStruct()->get_command_id_at = menu_model_get_command_id_at;
+ GetStruct()->set_command_id_at = menu_model_set_command_id_at;
+ GetStruct()->get_label = menu_model_get_label;
+ GetStruct()->get_label_at = menu_model_get_label_at;
+ GetStruct()->set_label = menu_model_set_label;
+ GetStruct()->set_label_at = menu_model_set_label_at;
+ GetStruct()->get_type = menu_model_get_type;
+ GetStruct()->get_type_at = menu_model_get_type_at;
+ GetStruct()->get_group_id = menu_model_get_group_id;
+ GetStruct()->get_group_id_at = menu_model_get_group_id_at;
+ GetStruct()->set_group_id = menu_model_set_group_id;
+ GetStruct()->set_group_id_at = menu_model_set_group_id_at;
+ GetStruct()->get_sub_menu = menu_model_get_sub_menu;
+ GetStruct()->get_sub_menu_at = menu_model_get_sub_menu_at;
+ GetStruct()->is_visible = menu_model_is_visible;
+ GetStruct()->is_visible_at = menu_model_is_visible_at;
+ GetStruct()->set_visible = menu_model_set_visible;
+ GetStruct()->set_visible_at = menu_model_set_visible_at;
+ GetStruct()->is_enabled = menu_model_is_enabled;
+ GetStruct()->is_enabled_at = menu_model_is_enabled_at;
+ GetStruct()->set_enabled = menu_model_set_enabled;
+ GetStruct()->set_enabled_at = menu_model_set_enabled_at;
+ GetStruct()->is_checked = menu_model_is_checked;
+ GetStruct()->is_checked_at = menu_model_is_checked_at;
+ GetStruct()->set_checked = menu_model_set_checked;
+ GetStruct()->set_checked_at = menu_model_set_checked_at;
+ GetStruct()->has_accelerator = menu_model_has_accelerator;
+ GetStruct()->has_accelerator_at = menu_model_has_accelerator_at;
+ GetStruct()->set_accelerator = menu_model_set_accelerator;
+ GetStruct()->set_accelerator_at = menu_model_set_accelerator_at;
+ GetStruct()->remove_accelerator = menu_model_remove_accelerator;
+ GetStruct()->remove_accelerator_at = menu_model_remove_accelerator_at;
+ GetStruct()->get_accelerator = menu_model_get_accelerator;
+ GetStruct()->get_accelerator_at = menu_model_get_accelerator_at;
+ GetStruct()->set_color = menu_model_set_color;
+ GetStruct()->set_color_at = menu_model_set_color_at;
+ GetStruct()->get_color = menu_model_get_color;
+ GetStruct()->get_color_at = menu_model_get_color_at;
+ GetStruct()->set_font_list = menu_model_set_font_list;
+ GetStruct()->set_font_list_at = menu_model_set_font_list_at;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefMenuModelCppToC::~CefMenuModelCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefMenuModel>
+CefCppToCRefCounted<CefMenuModelCppToC, CefMenuModel, cef_menu_model_t>::
+ UnwrapDerived(CefWrapperType type, cef_menu_model_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefMenuModelCppToC,
+ CefMenuModel,
+ cef_menu_model_t>::kWrapperType =
+ WT_MENU_MODEL;
diff --git a/libcef_dll/cpptoc/menu_model_cpptoc.h b/libcef_dll/cpptoc/menu_model_cpptoc.h
new file mode 100644
index 00000000..9344a726
--- /dev/null
+++ b/libcef_dll/cpptoc/menu_model_cpptoc.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=5f39f05bb39da5ede094d0e9789c5ef1dee1cf7f$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_MENU_MODEL_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_MENU_MODEL_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_menu_model_capi.h"
+#include "include/cef_menu_model.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefMenuModelCppToC : public CefCppToCRefCounted<CefMenuModelCppToC,
+ CefMenuModel,
+ cef_menu_model_t> {
+ public:
+ CefMenuModelCppToC();
+ virtual ~CefMenuModelCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_MENU_MODEL_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/menu_model_delegate_cpptoc.cc b/libcef_dll/cpptoc/menu_model_delegate_cpptoc.cc
new file mode 100644
index 00000000..fce2b7d8
--- /dev/null
+++ b/libcef_dll/cpptoc/menu_model_delegate_cpptoc.cc
@@ -0,0 +1,238 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=6e9aa9c1da82a7a3b8fc6a6551bf24b9ec05f44a$
+//
+
+#include "libcef_dll/cpptoc/menu_model_delegate_cpptoc.h"
+#include "libcef_dll/ctocpp/menu_model_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK
+menu_model_delegate_execute_command(struct _cef_menu_model_delegate_t* self,
+ cef_menu_model_t* menu_model,
+ int command_id,
+ cef_event_flags_t event_flags) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: menu_model; type: refptr_diff
+ DCHECK(menu_model);
+ if (!menu_model) {
+ return;
+ }
+
+ // Execute
+ CefMenuModelDelegateCppToC::Get(self)->ExecuteCommand(
+ CefMenuModelCToCpp::Wrap(menu_model), command_id, event_flags);
+}
+
+void CEF_CALLBACK
+menu_model_delegate_mouse_outside_menu(struct _cef_menu_model_delegate_t* self,
+ cef_menu_model_t* menu_model,
+ const cef_point_t* screen_point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: menu_model; type: refptr_diff
+ DCHECK(menu_model);
+ if (!menu_model) {
+ return;
+ }
+ // Verify param: screen_point; type: simple_byref_const
+ DCHECK(screen_point);
+ if (!screen_point) {
+ return;
+ }
+
+ // Translate param: screen_point; type: simple_byref_const
+ CefPoint screen_pointVal = screen_point ? *screen_point : CefPoint();
+
+ // Execute
+ CefMenuModelDelegateCppToC::Get(self)->MouseOutsideMenu(
+ CefMenuModelCToCpp::Wrap(menu_model), screen_pointVal);
+}
+
+void CEF_CALLBACK menu_model_delegate_unhandled_open_submenu(
+ struct _cef_menu_model_delegate_t* self,
+ cef_menu_model_t* menu_model,
+ int is_rtl) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: menu_model; type: refptr_diff
+ DCHECK(menu_model);
+ if (!menu_model) {
+ return;
+ }
+
+ // Execute
+ CefMenuModelDelegateCppToC::Get(self)->UnhandledOpenSubmenu(
+ CefMenuModelCToCpp::Wrap(menu_model), is_rtl ? true : false);
+}
+
+void CEF_CALLBACK menu_model_delegate_unhandled_close_submenu(
+ struct _cef_menu_model_delegate_t* self,
+ cef_menu_model_t* menu_model,
+ int is_rtl) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: menu_model; type: refptr_diff
+ DCHECK(menu_model);
+ if (!menu_model) {
+ return;
+ }
+
+ // Execute
+ CefMenuModelDelegateCppToC::Get(self)->UnhandledCloseSubmenu(
+ CefMenuModelCToCpp::Wrap(menu_model), is_rtl ? true : false);
+}
+
+void CEF_CALLBACK
+menu_model_delegate_menu_will_show(struct _cef_menu_model_delegate_t* self,
+ cef_menu_model_t* menu_model) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: menu_model; type: refptr_diff
+ DCHECK(menu_model);
+ if (!menu_model) {
+ return;
+ }
+
+ // Execute
+ CefMenuModelDelegateCppToC::Get(self)->MenuWillShow(
+ CefMenuModelCToCpp::Wrap(menu_model));
+}
+
+void CEF_CALLBACK
+menu_model_delegate_menu_closed(struct _cef_menu_model_delegate_t* self,
+ cef_menu_model_t* menu_model) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: menu_model; type: refptr_diff
+ DCHECK(menu_model);
+ if (!menu_model) {
+ return;
+ }
+
+ // Execute
+ CefMenuModelDelegateCppToC::Get(self)->MenuClosed(
+ CefMenuModelCToCpp::Wrap(menu_model));
+}
+
+int CEF_CALLBACK
+menu_model_delegate_format_label(struct _cef_menu_model_delegate_t* self,
+ cef_menu_model_t* menu_model,
+ cef_string_t* label) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: menu_model; type: refptr_diff
+ DCHECK(menu_model);
+ if (!menu_model) {
+ return 0;
+ }
+ // Verify param: label; type: string_byref
+ DCHECK(label);
+ if (!label) {
+ return 0;
+ }
+
+ // Translate param: label; type: string_byref
+ CefString labelStr(label);
+
+ // Execute
+ bool _retval = CefMenuModelDelegateCppToC::Get(self)->FormatLabel(
+ CefMenuModelCToCpp::Wrap(menu_model), labelStr);
+
+ // Return type: bool
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefMenuModelDelegateCppToC::CefMenuModelDelegateCppToC() {
+ GetStruct()->execute_command = menu_model_delegate_execute_command;
+ GetStruct()->mouse_outside_menu = menu_model_delegate_mouse_outside_menu;
+ GetStruct()->unhandled_open_submenu =
+ menu_model_delegate_unhandled_open_submenu;
+ GetStruct()->unhandled_close_submenu =
+ menu_model_delegate_unhandled_close_submenu;
+ GetStruct()->menu_will_show = menu_model_delegate_menu_will_show;
+ GetStruct()->menu_closed = menu_model_delegate_menu_closed;
+ GetStruct()->format_label = menu_model_delegate_format_label;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefMenuModelDelegateCppToC::~CefMenuModelDelegateCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefMenuModelDelegate> CefCppToCRefCounted<
+ CefMenuModelDelegateCppToC,
+ CefMenuModelDelegate,
+ cef_menu_model_delegate_t>::UnwrapDerived(CefWrapperType type,
+ cef_menu_model_delegate_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefMenuModelDelegateCppToC,
+ CefMenuModelDelegate,
+ cef_menu_model_delegate_t>::kWrapperType =
+ WT_MENU_MODEL_DELEGATE;
diff --git a/libcef_dll/cpptoc/menu_model_delegate_cpptoc.h b/libcef_dll/cpptoc/menu_model_delegate_cpptoc.h
new file mode 100644
index 00000000..50a03ba4
--- /dev/null
+++ b/libcef_dll/cpptoc/menu_model_delegate_cpptoc.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=2277b8692532f706316bb97ffe611394a00e1023$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_MENU_MODEL_DELEGATE_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_MENU_MODEL_DELEGATE_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_menu_model_capi.h"
+#include "include/capi/cef_menu_model_delegate_capi.h"
+#include "include/cef_menu_model.h"
+#include "include/cef_menu_model_delegate.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefMenuModelDelegateCppToC
+ : public CefCppToCRefCounted<CefMenuModelDelegateCppToC,
+ CefMenuModelDelegate,
+ cef_menu_model_delegate_t> {
+ public:
+ CefMenuModelDelegateCppToC();
+ virtual ~CefMenuModelDelegateCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_MENU_MODEL_DELEGATE_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/navigation_entry_cpptoc.cc b/libcef_dll/cpptoc/navigation_entry_cpptoc.cc
new file mode 100644
index 00000000..0f66acef
--- /dev/null
+++ b/libcef_dll/cpptoc/navigation_entry_cpptoc.cc
@@ -0,0 +1,243 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=3a9dcb524638c4d9230b4513041aa9353db54e7f$
+//
+
+#include "libcef_dll/cpptoc/navigation_entry_cpptoc.h"
+#include "libcef_dll/cpptoc/sslstatus_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK
+navigation_entry_is_valid(struct _cef_navigation_entry_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefNavigationEntryCppToC::Get(self)->IsValid();
+
+ // Return type: bool
+ return _retval;
+}
+
+cef_string_userfree_t CEF_CALLBACK
+navigation_entry_get_url(struct _cef_navigation_entry_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefNavigationEntryCppToC::Get(self)->GetURL();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_string_userfree_t CEF_CALLBACK
+navigation_entry_get_display_url(struct _cef_navigation_entry_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefNavigationEntryCppToC::Get(self)->GetDisplayURL();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_string_userfree_t CEF_CALLBACK
+navigation_entry_get_original_url(struct _cef_navigation_entry_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefNavigationEntryCppToC::Get(self)->GetOriginalURL();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_string_userfree_t CEF_CALLBACK
+navigation_entry_get_title(struct _cef_navigation_entry_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefNavigationEntryCppToC::Get(self)->GetTitle();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_transition_type_t CEF_CALLBACK
+navigation_entry_get_transition_type(struct _cef_navigation_entry_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return TT_EXPLICIT;
+ }
+
+ // Execute
+ cef_transition_type_t _retval =
+ CefNavigationEntryCppToC::Get(self)->GetTransitionType();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK
+navigation_entry_has_post_data(struct _cef_navigation_entry_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefNavigationEntryCppToC::Get(self)->HasPostData();
+
+ // Return type: bool
+ return _retval;
+}
+
+cef_basetime_t CEF_CALLBACK
+navigation_entry_get_completion_time(struct _cef_navigation_entry_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefBaseTime();
+ }
+
+ // Execute
+ cef_basetime_t _retval =
+ CefNavigationEntryCppToC::Get(self)->GetCompletionTime();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK
+navigation_entry_get_http_status_code(struct _cef_navigation_entry_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefNavigationEntryCppToC::Get(self)->GetHttpStatusCode();
+
+ // Return type: simple
+ return _retval;
+}
+
+struct _cef_sslstatus_t* CEF_CALLBACK
+navigation_entry_get_sslstatus(struct _cef_navigation_entry_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefSSLStatus> _retval =
+ CefNavigationEntryCppToC::Get(self)->GetSSLStatus();
+
+ // Return type: refptr_same
+ return CefSSLStatusCppToC::Wrap(_retval);
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefNavigationEntryCppToC::CefNavigationEntryCppToC() {
+ GetStruct()->is_valid = navigation_entry_is_valid;
+ GetStruct()->get_url = navigation_entry_get_url;
+ GetStruct()->get_display_url = navigation_entry_get_display_url;
+ GetStruct()->get_original_url = navigation_entry_get_original_url;
+ GetStruct()->get_title = navigation_entry_get_title;
+ GetStruct()->get_transition_type = navigation_entry_get_transition_type;
+ GetStruct()->has_post_data = navigation_entry_has_post_data;
+ GetStruct()->get_completion_time = navigation_entry_get_completion_time;
+ GetStruct()->get_http_status_code = navigation_entry_get_http_status_code;
+ GetStruct()->get_sslstatus = navigation_entry_get_sslstatus;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefNavigationEntryCppToC::~CefNavigationEntryCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefNavigationEntry> CefCppToCRefCounted<
+ CefNavigationEntryCppToC,
+ CefNavigationEntry,
+ cef_navigation_entry_t>::UnwrapDerived(CefWrapperType type,
+ cef_navigation_entry_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefNavigationEntryCppToC,
+ CefNavigationEntry,
+ cef_navigation_entry_t>::kWrapperType =
+ WT_NAVIGATION_ENTRY;
diff --git a/libcef_dll/cpptoc/navigation_entry_cpptoc.h b/libcef_dll/cpptoc/navigation_entry_cpptoc.h
new file mode 100644
index 00000000..38285d81
--- /dev/null
+++ b/libcef_dll/cpptoc/navigation_entry_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=213e6404f2260e81c41b20a42ae7788af80710dc$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_NAVIGATION_ENTRY_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_NAVIGATION_ENTRY_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_navigation_entry_capi.h"
+#include "include/cef_navigation_entry.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefNavigationEntryCppToC
+ : public CefCppToCRefCounted<CefNavigationEntryCppToC,
+ CefNavigationEntry,
+ cef_navigation_entry_t> {
+ public:
+ CefNavigationEntryCppToC();
+ virtual ~CefNavigationEntryCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_NAVIGATION_ENTRY_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/navigation_entry_visitor_cpptoc.cc b/libcef_dll/cpptoc/navigation_entry_visitor_cpptoc.cc
new file mode 100644
index 00000000..6783792a
--- /dev/null
+++ b/libcef_dll/cpptoc/navigation_entry_visitor_cpptoc.cc
@@ -0,0 +1,81 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=addccca2d817966a80bf0f33aa17b4cc2bab968c$
+//
+
+#include "libcef_dll/cpptoc/navigation_entry_visitor_cpptoc.h"
+#include "libcef_dll/ctocpp/navigation_entry_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK
+navigation_entry_visitor_visit(struct _cef_navigation_entry_visitor_t* self,
+ struct _cef_navigation_entry_t* entry,
+ int current,
+ int index,
+ int total) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: entry; type: refptr_diff
+ DCHECK(entry);
+ if (!entry) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefNavigationEntryVisitorCppToC::Get(self)->Visit(
+ CefNavigationEntryCToCpp::Wrap(entry), current ? true : false, index,
+ total);
+
+ // Return type: bool
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefNavigationEntryVisitorCppToC::CefNavigationEntryVisitorCppToC() {
+ GetStruct()->visit = navigation_entry_visitor_visit;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefNavigationEntryVisitorCppToC::~CefNavigationEntryVisitorCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefNavigationEntryVisitor>
+CefCppToCRefCounted<CefNavigationEntryVisitorCppToC,
+ CefNavigationEntryVisitor,
+ cef_navigation_entry_visitor_t>::
+ UnwrapDerived(CefWrapperType type, cef_navigation_entry_visitor_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCppToCRefCounted<CefNavigationEntryVisitorCppToC,
+ CefNavigationEntryVisitor,
+ cef_navigation_entry_visitor_t>::kWrapperType =
+ WT_NAVIGATION_ENTRY_VISITOR;
diff --git a/libcef_dll/cpptoc/navigation_entry_visitor_cpptoc.h b/libcef_dll/cpptoc/navigation_entry_visitor_cpptoc.h
new file mode 100644
index 00000000..77bb1a68
--- /dev/null
+++ b/libcef_dll/cpptoc/navigation_entry_visitor_cpptoc.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=e2fe9b1846135732e7596c2ff7ab6efadbb5a519$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_NAVIGATION_ENTRY_VISITOR_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_NAVIGATION_ENTRY_VISITOR_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_browser_capi.h"
+#include "include/capi/cef_client_capi.h"
+#include "include/cef_browser.h"
+#include "include/cef_client.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefNavigationEntryVisitorCppToC
+ : public CefCppToCRefCounted<CefNavigationEntryVisitorCppToC,
+ CefNavigationEntryVisitor,
+ cef_navigation_entry_visitor_t> {
+ public:
+ CefNavigationEntryVisitorCppToC();
+ virtual ~CefNavigationEntryVisitorCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_NAVIGATION_ENTRY_VISITOR_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/pdf_print_callback_cpptoc.cc b/libcef_dll/cpptoc/pdf_print_callback_cpptoc.cc
new file mode 100644
index 00000000..78c57da1
--- /dev/null
+++ b/libcef_dll/cpptoc/pdf_print_callback_cpptoc.cc
@@ -0,0 +1,73 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=1df7a3d15f0578169d5f7ae564c15b4c2b852882$
+//
+
+#include "libcef_dll/cpptoc/pdf_print_callback_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK
+pdf_print_callback_on_pdf_print_finished(struct _cef_pdf_print_callback_t* self,
+ const cef_string_t* path,
+ int ok) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: path; type: string_byref_const
+ DCHECK(path);
+ if (!path) {
+ return;
+ }
+
+ // Execute
+ CefPdfPrintCallbackCppToC::Get(self)->OnPdfPrintFinished(CefString(path),
+ ok ? true : false);
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefPdfPrintCallbackCppToC::CefPdfPrintCallbackCppToC() {
+ GetStruct()->on_pdf_print_finished = pdf_print_callback_on_pdf_print_finished;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefPdfPrintCallbackCppToC::~CefPdfPrintCallbackCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefPdfPrintCallback> CefCppToCRefCounted<
+ CefPdfPrintCallbackCppToC,
+ CefPdfPrintCallback,
+ cef_pdf_print_callback_t>::UnwrapDerived(CefWrapperType type,
+ cef_pdf_print_callback_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefPdfPrintCallbackCppToC,
+ CefPdfPrintCallback,
+ cef_pdf_print_callback_t>::kWrapperType =
+ WT_PDF_PRINT_CALLBACK;
diff --git a/libcef_dll/cpptoc/pdf_print_callback_cpptoc.h b/libcef_dll/cpptoc/pdf_print_callback_cpptoc.h
new file mode 100644
index 00000000..79130c8d
--- /dev/null
+++ b/libcef_dll/cpptoc/pdf_print_callback_cpptoc.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=5e9c671740881e345231547607160ce167d37728$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_PDF_PRINT_CALLBACK_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_PDF_PRINT_CALLBACK_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_browser_capi.h"
+#include "include/capi/cef_client_capi.h"
+#include "include/cef_browser.h"
+#include "include/cef_client.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefPdfPrintCallbackCppToC
+ : public CefCppToCRefCounted<CefPdfPrintCallbackCppToC,
+ CefPdfPrintCallback,
+ cef_pdf_print_callback_t> {
+ public:
+ CefPdfPrintCallbackCppToC();
+ virtual ~CefPdfPrintCallbackCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_PDF_PRINT_CALLBACK_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/permission_handler_cpptoc.cc b/libcef_dll/cpptoc/permission_handler_cpptoc.cc
new file mode 100644
index 00000000..234fe5bb
--- /dev/null
+++ b/libcef_dll/cpptoc/permission_handler_cpptoc.cc
@@ -0,0 +1,170 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=ab9f07a4be312d0b6bc59f9ab94fdbaa34f5dc82$
+//
+
+#include "libcef_dll/cpptoc/permission_handler_cpptoc.h"
+#include "libcef_dll/ctocpp/browser_ctocpp.h"
+#include "libcef_dll/ctocpp/frame_ctocpp.h"
+#include "libcef_dll/ctocpp/media_access_callback_ctocpp.h"
+#include "libcef_dll/ctocpp/permission_prompt_callback_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK permission_handler_on_request_media_access_permission(
+ struct _cef_permission_handler_t* self,
+ cef_browser_t* browser,
+ cef_frame_t* frame,
+ const cef_string_t* requesting_origin,
+ uint32 requested_permissions,
+ cef_media_access_callback_t* callback) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return 0;
+ }
+ // Verify param: frame; type: refptr_diff
+ DCHECK(frame);
+ if (!frame) {
+ return 0;
+ }
+ // Verify param: requesting_origin; type: string_byref_const
+ DCHECK(requesting_origin);
+ if (!requesting_origin) {
+ return 0;
+ }
+ // Verify param: callback; type: refptr_diff
+ DCHECK(callback);
+ if (!callback) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefPermissionHandlerCppToC::Get(self)->OnRequestMediaAccessPermission(
+ CefBrowserCToCpp::Wrap(browser), CefFrameCToCpp::Wrap(frame),
+ CefString(requesting_origin), requested_permissions,
+ CefMediaAccessCallbackCToCpp::Wrap(callback));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK permission_handler_on_show_permission_prompt(
+ struct _cef_permission_handler_t* self,
+ cef_browser_t* browser,
+ uint64 prompt_id,
+ const cef_string_t* requesting_origin,
+ uint32 requested_permissions,
+ cef_permission_prompt_callback_t* callback) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return 0;
+ }
+ // Verify param: requesting_origin; type: string_byref_const
+ DCHECK(requesting_origin);
+ if (!requesting_origin) {
+ return 0;
+ }
+ // Verify param: callback; type: refptr_diff
+ DCHECK(callback);
+ if (!callback) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefPermissionHandlerCppToC::Get(self)->OnShowPermissionPrompt(
+ CefBrowserCToCpp::Wrap(browser), prompt_id, CefString(requesting_origin),
+ requested_permissions, CefPermissionPromptCallbackCToCpp::Wrap(callback));
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK permission_handler_on_dismiss_permission_prompt(
+ struct _cef_permission_handler_t* self,
+ cef_browser_t* browser,
+ uint64 prompt_id,
+ cef_permission_request_result_t result) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+
+ // Execute
+ CefPermissionHandlerCppToC::Get(self)->OnDismissPermissionPrompt(
+ CefBrowserCToCpp::Wrap(browser), prompt_id, result);
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefPermissionHandlerCppToC::CefPermissionHandlerCppToC() {
+ GetStruct()->on_request_media_access_permission =
+ permission_handler_on_request_media_access_permission;
+ GetStruct()->on_show_permission_prompt =
+ permission_handler_on_show_permission_prompt;
+ GetStruct()->on_dismiss_permission_prompt =
+ permission_handler_on_dismiss_permission_prompt;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefPermissionHandlerCppToC::~CefPermissionHandlerCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefPermissionHandler> CefCppToCRefCounted<
+ CefPermissionHandlerCppToC,
+ CefPermissionHandler,
+ cef_permission_handler_t>::UnwrapDerived(CefWrapperType type,
+ cef_permission_handler_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefPermissionHandlerCppToC,
+ CefPermissionHandler,
+ cef_permission_handler_t>::kWrapperType =
+ WT_PERMISSION_HANDLER;
diff --git a/libcef_dll/cpptoc/permission_handler_cpptoc.h b/libcef_dll/cpptoc/permission_handler_cpptoc.h
new file mode 100644
index 00000000..0ac7a851
--- /dev/null
+++ b/libcef_dll/cpptoc/permission_handler_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=85771f8c4169ad8465d7d53294a2da107ed1a03c$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_PERMISSION_HANDLER_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_PERMISSION_HANDLER_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_permission_handler_capi.h"
+#include "include/cef_permission_handler.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefPermissionHandlerCppToC
+ : public CefCppToCRefCounted<CefPermissionHandlerCppToC,
+ CefPermissionHandler,
+ cef_permission_handler_t> {
+ public:
+ CefPermissionHandlerCppToC();
+ virtual ~CefPermissionHandlerCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_PERMISSION_HANDLER_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/permission_prompt_callback_cpptoc.cc b/libcef_dll/cpptoc/permission_prompt_callback_cpptoc.cc
new file mode 100644
index 00000000..7edbeedd
--- /dev/null
+++ b/libcef_dll/cpptoc/permission_prompt_callback_cpptoc.cc
@@ -0,0 +1,67 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=37ab08ce3f3226d0d38ac05bb91dbf060e43a598$
+//
+
+#include "libcef_dll/cpptoc/permission_prompt_callback_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK
+permission_prompt_callback_cont(struct _cef_permission_prompt_callback_t* self,
+ cef_permission_request_result_t result) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefPermissionPromptCallbackCppToC::Get(self)->Continue(result);
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefPermissionPromptCallbackCppToC::CefPermissionPromptCallbackCppToC() {
+ GetStruct()->cont = permission_prompt_callback_cont;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefPermissionPromptCallbackCppToC::~CefPermissionPromptCallbackCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefPermissionPromptCallback>
+CefCppToCRefCounted<CefPermissionPromptCallbackCppToC,
+ CefPermissionPromptCallback,
+ cef_permission_prompt_callback_t>::
+ UnwrapDerived(CefWrapperType type, cef_permission_prompt_callback_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCppToCRefCounted<CefPermissionPromptCallbackCppToC,
+ CefPermissionPromptCallback,
+ cef_permission_prompt_callback_t>::kWrapperType =
+ WT_PERMISSION_PROMPT_CALLBACK;
diff --git a/libcef_dll/cpptoc/permission_prompt_callback_cpptoc.h b/libcef_dll/cpptoc/permission_prompt_callback_cpptoc.h
new file mode 100644
index 00000000..67797889
--- /dev/null
+++ b/libcef_dll/cpptoc/permission_prompt_callback_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=1fa140e60746b9a65c7ff9216577128cb1d2fb35$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_PERMISSION_PROMPT_CALLBACK_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_PERMISSION_PROMPT_CALLBACK_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_permission_handler_capi.h"
+#include "include/cef_permission_handler.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefPermissionPromptCallbackCppToC
+ : public CefCppToCRefCounted<CefPermissionPromptCallbackCppToC,
+ CefPermissionPromptCallback,
+ cef_permission_prompt_callback_t> {
+ public:
+ CefPermissionPromptCallbackCppToC();
+ virtual ~CefPermissionPromptCallbackCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_PERMISSION_PROMPT_CALLBACK_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/post_data_cpptoc.cc b/libcef_dll/cpptoc/post_data_cpptoc.cc
new file mode 100644
index 00000000..84230d82
--- /dev/null
+++ b/libcef_dll/cpptoc/post_data_cpptoc.cc
@@ -0,0 +1,207 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=5e90cf25cb72e84e91a1f8dde1ad722592424dcb$
+//
+
+#include "libcef_dll/cpptoc/post_data_cpptoc.h"
+#include <algorithm>
+#include "libcef_dll/cpptoc/post_data_element_cpptoc.h"
+
+// GLOBAL FUNCTIONS - Body may be edited by hand.
+
+CEF_EXPORT cef_post_data_t* cef_post_data_create() {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ CefRefPtr<CefPostData> _retval = CefPostData::Create();
+
+ // Return type: refptr_same
+ return CefPostDataCppToC::Wrap(_retval);
+}
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK post_data_is_read_only(struct _cef_post_data_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefPostDataCppToC::Get(self)->IsReadOnly();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+post_data_has_excluded_elements(struct _cef_post_data_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefPostDataCppToC::Get(self)->HasExcludedElements();
+
+ // Return type: bool
+ return _retval;
+}
+
+size_t CEF_CALLBACK post_data_get_element_count(struct _cef_post_data_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ size_t _retval = CefPostDataCppToC::Get(self)->GetElementCount();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK
+post_data_get_elements(struct _cef_post_data_t* self,
+ size_t* elementsCount,
+ struct _cef_post_data_element_t** elements) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: elements; type: refptr_vec_same_byref
+ DCHECK(elementsCount && (*elementsCount == 0 || elements));
+ if (!elementsCount || (*elementsCount > 0 && !elements)) {
+ return;
+ }
+
+ // Translate param: elements; type: refptr_vec_same_byref
+ std::vector<CefRefPtr<CefPostDataElement>> elementsList;
+ if (elementsCount && *elementsCount > 0 && elements) {
+ for (size_t i = 0; i < *elementsCount; ++i) {
+ elementsList.push_back(CefPostDataElementCppToC::Unwrap(elements[i]));
+ }
+ }
+
+ // Execute
+ CefPostDataCppToC::Get(self)->GetElements(elementsList);
+
+ // Restore param: elements; type: refptr_vec_same_byref
+ if (elementsCount && elements) {
+ *elementsCount = std::min(elementsList.size(), *elementsCount);
+ if (*elementsCount > 0) {
+ for (size_t i = 0; i < *elementsCount; ++i) {
+ elements[i] = CefPostDataElementCppToC::Wrap(elementsList[i]);
+ }
+ }
+ }
+}
+
+int CEF_CALLBACK
+post_data_remove_element(struct _cef_post_data_t* self,
+ struct _cef_post_data_element_t* element) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: element; type: refptr_same
+ DCHECK(element);
+ if (!element) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefPostDataCppToC::Get(self)->RemoveElement(
+ CefPostDataElementCppToC::Unwrap(element));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+post_data_add_element(struct _cef_post_data_t* self,
+ struct _cef_post_data_element_t* element) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: element; type: refptr_same
+ DCHECK(element);
+ if (!element) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefPostDataCppToC::Get(self)->AddElement(
+ CefPostDataElementCppToC::Unwrap(element));
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK post_data_remove_elements(struct _cef_post_data_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefPostDataCppToC::Get(self)->RemoveElements();
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefPostDataCppToC::CefPostDataCppToC() {
+ GetStruct()->is_read_only = post_data_is_read_only;
+ GetStruct()->has_excluded_elements = post_data_has_excluded_elements;
+ GetStruct()->get_element_count = post_data_get_element_count;
+ GetStruct()->get_elements = post_data_get_elements;
+ GetStruct()->remove_element = post_data_remove_element;
+ GetStruct()->add_element = post_data_add_element;
+ GetStruct()->remove_elements = post_data_remove_elements;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefPostDataCppToC::~CefPostDataCppToC() {}
+
+template <>
+CefRefPtr<CefPostData>
+CefCppToCRefCounted<CefPostDataCppToC, CefPostData, cef_post_data_t>::
+ UnwrapDerived(CefWrapperType type, cef_post_data_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefPostDataCppToC,
+ CefPostData,
+ cef_post_data_t>::kWrapperType =
+ WT_POST_DATA;
diff --git a/libcef_dll/cpptoc/post_data_cpptoc.h b/libcef_dll/cpptoc/post_data_cpptoc.h
new file mode 100644
index 00000000..59518a2b
--- /dev/null
+++ b/libcef_dll/cpptoc/post_data_cpptoc.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=784458fd59458b07ba3c6eacac3803b9901c354c$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_POST_DATA_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_POST_DATA_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_request_capi.h"
+#include "include/cef_request.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefPostDataCppToC : public CefCppToCRefCounted<CefPostDataCppToC,
+ CefPostData,
+ cef_post_data_t> {
+ public:
+ CefPostDataCppToC();
+ virtual ~CefPostDataCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_POST_DATA_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/post_data_element_cpptoc.cc b/libcef_dll/cpptoc/post_data_element_cpptoc.cc
new file mode 100644
index 00000000..0bde75e2
--- /dev/null
+++ b/libcef_dll/cpptoc/post_data_element_cpptoc.cc
@@ -0,0 +1,206 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=163df09395448195c38cd73e0cdff8e0018eed7a$
+//
+
+#include "libcef_dll/cpptoc/post_data_element_cpptoc.h"
+
+// GLOBAL FUNCTIONS - Body may be edited by hand.
+
+CEF_EXPORT cef_post_data_element_t* cef_post_data_element_create() {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ CefRefPtr<CefPostDataElement> _retval = CefPostDataElement::Create();
+
+ // Return type: refptr_same
+ return CefPostDataElementCppToC::Wrap(_retval);
+}
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK
+post_data_element_is_read_only(struct _cef_post_data_element_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefPostDataElementCppToC::Get(self)->IsReadOnly();
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK
+post_data_element_set_to_empty(struct _cef_post_data_element_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefPostDataElementCppToC::Get(self)->SetToEmpty();
+}
+
+void CEF_CALLBACK
+post_data_element_set_to_file(struct _cef_post_data_element_t* self,
+ const cef_string_t* fileName) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: fileName; type: string_byref_const
+ DCHECK(fileName);
+ if (!fileName) {
+ return;
+ }
+
+ // Execute
+ CefPostDataElementCppToC::Get(self)->SetToFile(CefString(fileName));
+}
+
+void CEF_CALLBACK
+post_data_element_set_to_bytes(struct _cef_post_data_element_t* self,
+ size_t size,
+ const void* bytes) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: bytes; type: simple_byaddr
+ DCHECK(bytes);
+ if (!bytes) {
+ return;
+ }
+
+ // Execute
+ CefPostDataElementCppToC::Get(self)->SetToBytes(size, bytes);
+}
+
+cef_postdataelement_type_t CEF_CALLBACK
+post_data_element_get_type(struct _cef_post_data_element_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return PDE_TYPE_EMPTY;
+ }
+
+ // Execute
+ cef_postdataelement_type_t _retval =
+ CefPostDataElementCppToC::Get(self)->GetType();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_string_userfree_t CEF_CALLBACK
+post_data_element_get_file(struct _cef_post_data_element_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefPostDataElementCppToC::Get(self)->GetFile();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+size_t CEF_CALLBACK
+post_data_element_get_bytes_count(struct _cef_post_data_element_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ size_t _retval = CefPostDataElementCppToC::Get(self)->GetBytesCount();
+
+ // Return type: simple
+ return _retval;
+}
+
+size_t CEF_CALLBACK
+post_data_element_get_bytes(struct _cef_post_data_element_t* self,
+ size_t size,
+ void* bytes) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: bytes; type: simple_byaddr
+ DCHECK(bytes);
+ if (!bytes) {
+ return 0;
+ }
+
+ // Execute
+ size_t _retval = CefPostDataElementCppToC::Get(self)->GetBytes(size, bytes);
+
+ // Return type: simple
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefPostDataElementCppToC::CefPostDataElementCppToC() {
+ GetStruct()->is_read_only = post_data_element_is_read_only;
+ GetStruct()->set_to_empty = post_data_element_set_to_empty;
+ GetStruct()->set_to_file = post_data_element_set_to_file;
+ GetStruct()->set_to_bytes = post_data_element_set_to_bytes;
+ GetStruct()->get_type = post_data_element_get_type;
+ GetStruct()->get_file = post_data_element_get_file;
+ GetStruct()->get_bytes_count = post_data_element_get_bytes_count;
+ GetStruct()->get_bytes = post_data_element_get_bytes;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefPostDataElementCppToC::~CefPostDataElementCppToC() {}
+
+template <>
+CefRefPtr<CefPostDataElement> CefCppToCRefCounted<
+ CefPostDataElementCppToC,
+ CefPostDataElement,
+ cef_post_data_element_t>::UnwrapDerived(CefWrapperType type,
+ cef_post_data_element_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefPostDataElementCppToC,
+ CefPostDataElement,
+ cef_post_data_element_t>::kWrapperType =
+ WT_POST_DATA_ELEMENT;
diff --git a/libcef_dll/cpptoc/post_data_element_cpptoc.h b/libcef_dll/cpptoc/post_data_element_cpptoc.h
new file mode 100644
index 00000000..5b57b204
--- /dev/null
+++ b/libcef_dll/cpptoc/post_data_element_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=6d48d5f01f5cebcdca0fcfa7ce2b39a049fdc9cd$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_POST_DATA_ELEMENT_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_POST_DATA_ELEMENT_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_request_capi.h"
+#include "include/cef_request.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefPostDataElementCppToC
+ : public CefCppToCRefCounted<CefPostDataElementCppToC,
+ CefPostDataElement,
+ cef_post_data_element_t> {
+ public:
+ CefPostDataElementCppToC();
+ virtual ~CefPostDataElementCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_POST_DATA_ELEMENT_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/preference_manager_cpptoc.cc b/libcef_dll/cpptoc/preference_manager_cpptoc.cc
new file mode 100644
index 00000000..5344de9a
--- /dev/null
+++ b/libcef_dll/cpptoc/preference_manager_cpptoc.cc
@@ -0,0 +1,193 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=03f2344ea74ba170a5756bb8636f56c32df787a1$
+//
+
+#include "libcef_dll/cpptoc/preference_manager_cpptoc.h"
+#include "libcef_dll/cpptoc/dictionary_value_cpptoc.h"
+#include "libcef_dll/cpptoc/request_context_cpptoc.h"
+#include "libcef_dll/cpptoc/value_cpptoc.h"
+
+// GLOBAL FUNCTIONS - Body may be edited by hand.
+
+CEF_EXPORT cef_preference_manager_t* cef_preference_manager_get_global() {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ CefRefPtr<CefPreferenceManager> _retval =
+ CefPreferenceManager::GetGlobalPreferenceManager();
+
+ // Return type: refptr_same
+ return CefPreferenceManagerCppToC::Wrap(_retval);
+}
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK
+preference_manager_has_preference(struct _cef_preference_manager_t* self,
+ const cef_string_t* name) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: name; type: string_byref_const
+ DCHECK(name);
+ if (!name) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefPreferenceManagerCppToC::Get(self)->HasPreference(CefString(name));
+
+ // Return type: bool
+ return _retval;
+}
+
+struct _cef_value_t* CEF_CALLBACK
+preference_manager_get_preference(struct _cef_preference_manager_t* self,
+ const cef_string_t* name) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+ // Verify param: name; type: string_byref_const
+ DCHECK(name);
+ if (!name) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefValue> _retval =
+ CefPreferenceManagerCppToC::Get(self)->GetPreference(CefString(name));
+
+ // Return type: refptr_same
+ return CefValueCppToC::Wrap(_retval);
+}
+
+struct _cef_dictionary_value_t* CEF_CALLBACK
+preference_manager_get_all_preferences(struct _cef_preference_manager_t* self,
+ int include_defaults) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefDictionaryValue> _retval =
+ CefPreferenceManagerCppToC::Get(self)->GetAllPreferences(
+ include_defaults ? true : false);
+
+ // Return type: refptr_same
+ return CefDictionaryValueCppToC::Wrap(_retval);
+}
+
+int CEF_CALLBACK
+preference_manager_can_set_preference(struct _cef_preference_manager_t* self,
+ const cef_string_t* name) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: name; type: string_byref_const
+ DCHECK(name);
+ if (!name) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefPreferenceManagerCppToC::Get(self)->CanSetPreference(CefString(name));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+preference_manager_set_preference(struct _cef_preference_manager_t* self,
+ const cef_string_t* name,
+ struct _cef_value_t* value,
+ cef_string_t* error) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: name; type: string_byref_const
+ DCHECK(name);
+ if (!name) {
+ return 0;
+ }
+ // Verify param: error; type: string_byref
+ DCHECK(error);
+ if (!error) {
+ return 0;
+ }
+ // Unverified params: value
+
+ // Translate param: error; type: string_byref
+ CefString errorStr(error);
+
+ // Execute
+ bool _retval = CefPreferenceManagerCppToC::Get(self)->SetPreference(
+ CefString(name), CefValueCppToC::Unwrap(value), errorStr);
+
+ // Return type: bool
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefPreferenceManagerCppToC::CefPreferenceManagerCppToC() {
+ GetStruct()->has_preference = preference_manager_has_preference;
+ GetStruct()->get_preference = preference_manager_get_preference;
+ GetStruct()->get_all_preferences = preference_manager_get_all_preferences;
+ GetStruct()->can_set_preference = preference_manager_can_set_preference;
+ GetStruct()->set_preference = preference_manager_set_preference;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefPreferenceManagerCppToC::~CefPreferenceManagerCppToC() {}
+
+template <>
+CefRefPtr<CefPreferenceManager> CefCppToCRefCounted<
+ CefPreferenceManagerCppToC,
+ CefPreferenceManager,
+ cef_preference_manager_t>::UnwrapDerived(CefWrapperType type,
+ cef_preference_manager_t* s) {
+ if (type == WT_REQUEST_CONTEXT) {
+ return CefRequestContextCppToC::Unwrap(
+ reinterpret_cast<cef_request_context_t*>(s));
+ }
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefPreferenceManagerCppToC,
+ CefPreferenceManager,
+ cef_preference_manager_t>::kWrapperType =
+ WT_PREFERENCE_MANAGER;
diff --git a/libcef_dll/cpptoc/preference_manager_cpptoc.h b/libcef_dll/cpptoc/preference_manager_cpptoc.h
new file mode 100644
index 00000000..8c0a6342
--- /dev/null
+++ b/libcef_dll/cpptoc/preference_manager_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=1a942f4b4935d0c3741ca58c3dc84c6c365827c6$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_PREFERENCE_MANAGER_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_PREFERENCE_MANAGER_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_preference_capi.h"
+#include "include/cef_preference.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefPreferenceManagerCppToC
+ : public CefCppToCRefCounted<CefPreferenceManagerCppToC,
+ CefPreferenceManager,
+ cef_preference_manager_t> {
+ public:
+ CefPreferenceManagerCppToC();
+ virtual ~CefPreferenceManagerCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_PREFERENCE_MANAGER_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/preference_registrar_cpptoc.cc b/libcef_dll/cpptoc/preference_registrar_cpptoc.cc
new file mode 100644
index 00000000..7b935c01
--- /dev/null
+++ b/libcef_dll/cpptoc/preference_registrar_cpptoc.cc
@@ -0,0 +1,85 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=341388d9df93e67401777e34989f0bd43f341c80$
+//
+
+#include "libcef_dll/cpptoc/preference_registrar_cpptoc.h"
+#include "libcef_dll/cpptoc/value_cpptoc.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK
+preference_registrar_add_preference(struct _cef_preference_registrar_t* self,
+ const cef_string_t* name,
+ struct _cef_value_t* default_value) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: name; type: string_byref_const
+ DCHECK(name);
+ if (!name) {
+ return 0;
+ }
+ // Verify param: default_value; type: refptr_same
+ DCHECK(default_value);
+ if (!default_value) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefPreferenceRegistrarCppToC::Get(self)->AddPreference(
+ CefString(name), CefValueCppToC::Unwrap(default_value));
+
+ // Return type: bool
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefPreferenceRegistrarCppToC::CefPreferenceRegistrarCppToC() {
+ GetStruct()->add_preference = preference_registrar_add_preference;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefPreferenceRegistrarCppToC::~CefPreferenceRegistrarCppToC() {}
+
+template <>
+CefOwnPtr<CefPreferenceRegistrar> CefCppToCScoped<CefPreferenceRegistrarCppToC,
+ CefPreferenceRegistrar,
+ cef_preference_registrar_t>::
+ UnwrapDerivedOwn(CefWrapperType type, cef_preference_registrar_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return CefOwnPtr<CefPreferenceRegistrar>();
+}
+
+template <>
+CefRawPtr<CefPreferenceRegistrar> CefCppToCScoped<CefPreferenceRegistrarCppToC,
+ CefPreferenceRegistrar,
+ cef_preference_registrar_t>::
+ UnwrapDerivedRaw(CefWrapperType type, cef_preference_registrar_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCScoped<CefPreferenceRegistrarCppToC,
+ CefPreferenceRegistrar,
+ cef_preference_registrar_t>::kWrapperType =
+ WT_PREFERENCE_REGISTRAR;
diff --git a/libcef_dll/cpptoc/preference_registrar_cpptoc.h b/libcef_dll/cpptoc/preference_registrar_cpptoc.h
new file mode 100644
index 00000000..897a1992
--- /dev/null
+++ b/libcef_dll/cpptoc/preference_registrar_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=a276311e31965315ceb5e7f293eaee8140a79acb$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_PREFERENCE_REGISTRAR_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_PREFERENCE_REGISTRAR_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_preference_capi.h"
+#include "include/cef_preference.h"
+#include "libcef_dll/cpptoc/cpptoc_scoped.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefPreferenceRegistrarCppToC
+ : public CefCppToCScoped<CefPreferenceRegistrarCppToC,
+ CefPreferenceRegistrar,
+ cef_preference_registrar_t> {
+ public:
+ CefPreferenceRegistrarCppToC();
+ virtual ~CefPreferenceRegistrarCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_PREFERENCE_REGISTRAR_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/print_dialog_callback_cpptoc.cc b/libcef_dll/cpptoc/print_dialog_callback_cpptoc.cc
new file mode 100644
index 00000000..efec9a53
--- /dev/null
+++ b/libcef_dll/cpptoc/print_dialog_callback_cpptoc.cc
@@ -0,0 +1,90 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=2440f3cedc982eed4d2f2c9f698a15b378d23a11$
+//
+
+#include "libcef_dll/cpptoc/print_dialog_callback_cpptoc.h"
+#include "libcef_dll/cpptoc/print_settings_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK
+print_dialog_callback_cont(struct _cef_print_dialog_callback_t* self,
+ struct _cef_print_settings_t* settings) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: settings; type: refptr_same
+ DCHECK(settings);
+ if (!settings) {
+ return;
+ }
+
+ // Execute
+ CefPrintDialogCallbackCppToC::Get(self)->Continue(
+ CefPrintSettingsCppToC::Unwrap(settings));
+}
+
+void CEF_CALLBACK
+print_dialog_callback_cancel(struct _cef_print_dialog_callback_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefPrintDialogCallbackCppToC::Get(self)->Cancel();
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefPrintDialogCallbackCppToC::CefPrintDialogCallbackCppToC() {
+ GetStruct()->cont = print_dialog_callback_cont;
+ GetStruct()->cancel = print_dialog_callback_cancel;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefPrintDialogCallbackCppToC::~CefPrintDialogCallbackCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefPrintDialogCallback> CefCppToCRefCounted<
+ CefPrintDialogCallbackCppToC,
+ CefPrintDialogCallback,
+ cef_print_dialog_callback_t>::UnwrapDerived(CefWrapperType type,
+ cef_print_dialog_callback_t*
+ s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefPrintDialogCallbackCppToC,
+ CefPrintDialogCallback,
+ cef_print_dialog_callback_t>::kWrapperType =
+ WT_PRINT_DIALOG_CALLBACK;
diff --git a/libcef_dll/cpptoc/print_dialog_callback_cpptoc.h b/libcef_dll/cpptoc/print_dialog_callback_cpptoc.h
new file mode 100644
index 00000000..281ef139
--- /dev/null
+++ b/libcef_dll/cpptoc/print_dialog_callback_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=ee6fd2ddae3899be82feca1e37cce919363bae99$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_PRINT_DIALOG_CALLBACK_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_PRINT_DIALOG_CALLBACK_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_print_handler_capi.h"
+#include "include/cef_print_handler.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefPrintDialogCallbackCppToC
+ : public CefCppToCRefCounted<CefPrintDialogCallbackCppToC,
+ CefPrintDialogCallback,
+ cef_print_dialog_callback_t> {
+ public:
+ CefPrintDialogCallbackCppToC();
+ virtual ~CefPrintDialogCallbackCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_PRINT_DIALOG_CALLBACK_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/print_handler_cpptoc.cc b/libcef_dll/cpptoc/print_handler_cpptoc.cc
new file mode 100644
index 00000000..bfccc3c2
--- /dev/null
+++ b/libcef_dll/cpptoc/print_handler_cpptoc.cc
@@ -0,0 +1,236 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=ddbbddf37b581bf4fc29bcc7ccff2e1129fb14ad$
+//
+
+#include "libcef_dll/cpptoc/print_handler_cpptoc.h"
+#include "libcef_dll/ctocpp/browser_ctocpp.h"
+#include "libcef_dll/ctocpp/print_dialog_callback_ctocpp.h"
+#include "libcef_dll/ctocpp/print_job_callback_ctocpp.h"
+#include "libcef_dll/ctocpp/print_settings_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK
+print_handler_on_print_start(struct _cef_print_handler_t* self,
+ cef_browser_t* browser) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+
+ // Execute
+ CefPrintHandlerCppToC::Get(self)->OnPrintStart(
+ CefBrowserCToCpp::Wrap(browser));
+}
+
+void CEF_CALLBACK
+print_handler_on_print_settings(struct _cef_print_handler_t* self,
+ cef_browser_t* browser,
+ struct _cef_print_settings_t* settings,
+ int get_defaults) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+ // Verify param: settings; type: refptr_diff
+ DCHECK(settings);
+ if (!settings) {
+ return;
+ }
+
+ // Execute
+ CefPrintHandlerCppToC::Get(self)->OnPrintSettings(
+ CefBrowserCToCpp::Wrap(browser), CefPrintSettingsCToCpp::Wrap(settings),
+ get_defaults ? true : false);
+}
+
+int CEF_CALLBACK
+print_handler_on_print_dialog(struct _cef_print_handler_t* self,
+ cef_browser_t* browser,
+ int has_selection,
+ cef_print_dialog_callback_t* callback) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return 0;
+ }
+ // Verify param: callback; type: refptr_diff
+ DCHECK(callback);
+ if (!callback) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefPrintHandlerCppToC::Get(self)->OnPrintDialog(
+ CefBrowserCToCpp::Wrap(browser), has_selection ? true : false,
+ CefPrintDialogCallbackCToCpp::Wrap(callback));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+print_handler_on_print_job(struct _cef_print_handler_t* self,
+ cef_browser_t* browser,
+ const cef_string_t* document_name,
+ const cef_string_t* pdf_file_path,
+ cef_print_job_callback_t* callback) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return 0;
+ }
+ // Verify param: document_name; type: string_byref_const
+ DCHECK(document_name);
+ if (!document_name) {
+ return 0;
+ }
+ // Verify param: pdf_file_path; type: string_byref_const
+ DCHECK(pdf_file_path);
+ if (!pdf_file_path) {
+ return 0;
+ }
+ // Verify param: callback; type: refptr_diff
+ DCHECK(callback);
+ if (!callback) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefPrintHandlerCppToC::Get(self)->OnPrintJob(
+ CefBrowserCToCpp::Wrap(browser), CefString(document_name),
+ CefString(pdf_file_path), CefPrintJobCallbackCToCpp::Wrap(callback));
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK
+print_handler_on_print_reset(struct _cef_print_handler_t* self,
+ cef_browser_t* browser) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+
+ // Execute
+ CefPrintHandlerCppToC::Get(self)->OnPrintReset(
+ CefBrowserCToCpp::Wrap(browser));
+}
+
+cef_size_t CEF_CALLBACK
+print_handler_get_pdf_paper_size(struct _cef_print_handler_t* self,
+ cef_browser_t* browser,
+ int device_units_per_inch) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval = CefPrintHandlerCppToC::Get(self)->GetPdfPaperSize(
+ CefBrowserCToCpp::Wrap(browser), device_units_per_inch);
+
+ // Return type: simple
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefPrintHandlerCppToC::CefPrintHandlerCppToC() {
+ GetStruct()->on_print_start = print_handler_on_print_start;
+ GetStruct()->on_print_settings = print_handler_on_print_settings;
+ GetStruct()->on_print_dialog = print_handler_on_print_dialog;
+ GetStruct()->on_print_job = print_handler_on_print_job;
+ GetStruct()->on_print_reset = print_handler_on_print_reset;
+ GetStruct()->get_pdf_paper_size = print_handler_get_pdf_paper_size;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefPrintHandlerCppToC::~CefPrintHandlerCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefPrintHandler> CefCppToCRefCounted<
+ CefPrintHandlerCppToC,
+ CefPrintHandler,
+ cef_print_handler_t>::UnwrapDerived(CefWrapperType type,
+ cef_print_handler_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefPrintHandlerCppToC,
+ CefPrintHandler,
+ cef_print_handler_t>::kWrapperType =
+ WT_PRINT_HANDLER;
diff --git a/libcef_dll/cpptoc/print_handler_cpptoc.h b/libcef_dll/cpptoc/print_handler_cpptoc.h
new file mode 100644
index 00000000..f2d71b3c
--- /dev/null
+++ b/libcef_dll/cpptoc/print_handler_cpptoc.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=cd0bb4e9c12f53896be544b28ae3c6f38b3504e2$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_PRINT_HANDLER_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_PRINT_HANDLER_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_print_handler_capi.h"
+#include "include/cef_print_handler.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefPrintHandlerCppToC : public CefCppToCRefCounted<CefPrintHandlerCppToC,
+ CefPrintHandler,
+ cef_print_handler_t> {
+ public:
+ CefPrintHandlerCppToC();
+ virtual ~CefPrintHandlerCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_PRINT_HANDLER_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/print_job_callback_cpptoc.cc b/libcef_dll/cpptoc/print_job_callback_cpptoc.cc
new file mode 100644
index 00000000..b60a3dfe
--- /dev/null
+++ b/libcef_dll/cpptoc/print_job_callback_cpptoc.cc
@@ -0,0 +1,65 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=4a96bcb2808507afe4d9e103373392e9bb936731$
+//
+
+#include "libcef_dll/cpptoc/print_job_callback_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK
+print_job_callback_cont(struct _cef_print_job_callback_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefPrintJobCallbackCppToC::Get(self)->Continue();
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefPrintJobCallbackCppToC::CefPrintJobCallbackCppToC() {
+ GetStruct()->cont = print_job_callback_cont;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefPrintJobCallbackCppToC::~CefPrintJobCallbackCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefPrintJobCallback> CefCppToCRefCounted<
+ CefPrintJobCallbackCppToC,
+ CefPrintJobCallback,
+ cef_print_job_callback_t>::UnwrapDerived(CefWrapperType type,
+ cef_print_job_callback_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefPrintJobCallbackCppToC,
+ CefPrintJobCallback,
+ cef_print_job_callback_t>::kWrapperType =
+ WT_PRINT_JOB_CALLBACK;
diff --git a/libcef_dll/cpptoc/print_job_callback_cpptoc.h b/libcef_dll/cpptoc/print_job_callback_cpptoc.h
new file mode 100644
index 00000000..cc590108
--- /dev/null
+++ b/libcef_dll/cpptoc/print_job_callback_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=54a355e9511b5d0956f1a7269ee21766fa7f8c87$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_PRINT_JOB_CALLBACK_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_PRINT_JOB_CALLBACK_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_print_handler_capi.h"
+#include "include/cef_print_handler.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefPrintJobCallbackCppToC
+ : public CefCppToCRefCounted<CefPrintJobCallbackCppToC,
+ CefPrintJobCallback,
+ cef_print_job_callback_t> {
+ public:
+ CefPrintJobCallbackCppToC();
+ virtual ~CefPrintJobCallbackCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_PRINT_JOB_CALLBACK_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/print_settings_cpptoc.cc b/libcef_dll/cpptoc/print_settings_cpptoc.cc
new file mode 100644
index 00000000..f4018257
--- /dev/null
+++ b/libcef_dll/cpptoc/print_settings_cpptoc.cc
@@ -0,0 +1,519 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=7de7cab1410567741db3c8b4afbb0d6fec1098eb$
+//
+
+#include "libcef_dll/cpptoc/print_settings_cpptoc.h"
+#include <algorithm>
+#include "libcef_dll/shutdown_checker.h"
+
+// GLOBAL FUNCTIONS - Body may be edited by hand.
+
+CEF_EXPORT cef_print_settings_t* cef_print_settings_create() {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ CefRefPtr<CefPrintSettings> _retval = CefPrintSettings::Create();
+
+ // Return type: refptr_same
+ return CefPrintSettingsCppToC::Wrap(_retval);
+}
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK print_settings_is_valid(struct _cef_print_settings_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefPrintSettingsCppToC::Get(self)->IsValid();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+print_settings_is_read_only(struct _cef_print_settings_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefPrintSettingsCppToC::Get(self)->IsReadOnly();
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK
+print_settings_set_orientation(struct _cef_print_settings_t* self,
+ int landscape) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefPrintSettingsCppToC::Get(self)->SetOrientation(landscape ? true : false);
+}
+
+int CEF_CALLBACK
+print_settings_is_landscape(struct _cef_print_settings_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefPrintSettingsCppToC::Get(self)->IsLandscape();
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK print_settings_set_printer_printable_area(
+ struct _cef_print_settings_t* self,
+ const cef_size_t* physical_size_device_units,
+ const cef_rect_t* printable_area_device_units,
+ int landscape_needs_flip) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: physical_size_device_units; type: simple_byref_const
+ DCHECK(physical_size_device_units);
+ if (!physical_size_device_units) {
+ return;
+ }
+ // Verify param: printable_area_device_units; type: simple_byref_const
+ DCHECK(printable_area_device_units);
+ if (!printable_area_device_units) {
+ return;
+ }
+
+ // Translate param: physical_size_device_units; type: simple_byref_const
+ CefSize physical_size_device_unitsVal =
+ physical_size_device_units ? *physical_size_device_units : CefSize();
+ // Translate param: printable_area_device_units; type: simple_byref_const
+ CefRect printable_area_device_unitsVal =
+ printable_area_device_units ? *printable_area_device_units : CefRect();
+
+ // Execute
+ CefPrintSettingsCppToC::Get(self)->SetPrinterPrintableArea(
+ physical_size_device_unitsVal, printable_area_device_unitsVal,
+ landscape_needs_flip ? true : false);
+}
+
+void CEF_CALLBACK
+print_settings_set_device_name(struct _cef_print_settings_t* self,
+ const cef_string_t* name) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Unverified params: name
+
+ // Execute
+ CefPrintSettingsCppToC::Get(self)->SetDeviceName(CefString(name));
+}
+
+cef_string_userfree_t CEF_CALLBACK
+print_settings_get_device_name(struct _cef_print_settings_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefPrintSettingsCppToC::Get(self)->GetDeviceName();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+void CEF_CALLBACK print_settings_set_dpi(struct _cef_print_settings_t* self,
+ int dpi) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefPrintSettingsCppToC::Get(self)->SetDPI(dpi);
+}
+
+int CEF_CALLBACK print_settings_get_dpi(struct _cef_print_settings_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefPrintSettingsCppToC::Get(self)->GetDPI();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK
+print_settings_set_page_ranges(struct _cef_print_settings_t* self,
+ size_t rangesCount,
+ cef_range_t const* ranges) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: ranges; type: simple_vec_byref_const
+ DCHECK(rangesCount == 0 || ranges);
+ if (rangesCount > 0 && !ranges) {
+ return;
+ }
+
+ // Translate param: ranges; type: simple_vec_byref_const
+ std::vector<CefRange> rangesList;
+ if (rangesCount > 0) {
+ for (size_t i = 0; i < rangesCount; ++i) {
+ CefRange rangesVal = ranges[i];
+ rangesList.push_back(rangesVal);
+ }
+ }
+
+ // Execute
+ CefPrintSettingsCppToC::Get(self)->SetPageRanges(rangesList);
+}
+
+size_t CEF_CALLBACK
+print_settings_get_page_ranges_count(struct _cef_print_settings_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ size_t _retval = CefPrintSettingsCppToC::Get(self)->GetPageRangesCount();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK
+print_settings_get_page_ranges(struct _cef_print_settings_t* self,
+ size_t* rangesCount,
+ cef_range_t* ranges) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: ranges; type: simple_vec_byref
+ DCHECK(rangesCount && (*rangesCount == 0 || ranges));
+ if (!rangesCount || (*rangesCount > 0 && !ranges)) {
+ return;
+ }
+
+ // Translate param: ranges; type: simple_vec_byref
+ std::vector<CefRange> rangesList;
+ if (rangesCount && *rangesCount > 0 && ranges) {
+ for (size_t i = 0; i < *rangesCount; ++i) {
+ rangesList.push_back(ranges[i]);
+ }
+ }
+
+ // Execute
+ CefPrintSettingsCppToC::Get(self)->GetPageRanges(rangesList);
+
+ // Restore param: ranges; type: simple_vec_byref
+ if (rangesCount && ranges) {
+ *rangesCount = std::min(rangesList.size(), *rangesCount);
+ if (*rangesCount > 0) {
+ for (size_t i = 0; i < *rangesCount; ++i) {
+ ranges[i] = rangesList[i];
+ }
+ }
+ }
+}
+
+void CEF_CALLBACK
+print_settings_set_selection_only(struct _cef_print_settings_t* self,
+ int selection_only) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefPrintSettingsCppToC::Get(self)->SetSelectionOnly(selection_only ? true
+ : false);
+}
+
+int CEF_CALLBACK
+print_settings_is_selection_only(struct _cef_print_settings_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefPrintSettingsCppToC::Get(self)->IsSelectionOnly();
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK print_settings_set_collate(struct _cef_print_settings_t* self,
+ int collate) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefPrintSettingsCppToC::Get(self)->SetCollate(collate ? true : false);
+}
+
+int CEF_CALLBACK
+print_settings_will_collate(struct _cef_print_settings_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefPrintSettingsCppToC::Get(self)->WillCollate();
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK
+print_settings_set_color_model(struct _cef_print_settings_t* self,
+ cef_color_model_t model) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefPrintSettingsCppToC::Get(self)->SetColorModel(model);
+}
+
+cef_color_model_t CEF_CALLBACK
+print_settings_get_color_model(struct _cef_print_settings_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return COLOR_MODEL_UNKNOWN;
+ }
+
+ // Execute
+ cef_color_model_t _retval =
+ CefPrintSettingsCppToC::Get(self)->GetColorModel();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK print_settings_set_copies(struct _cef_print_settings_t* self,
+ int copies) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefPrintSettingsCppToC::Get(self)->SetCopies(copies);
+}
+
+int CEF_CALLBACK print_settings_get_copies(struct _cef_print_settings_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefPrintSettingsCppToC::Get(self)->GetCopies();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK
+print_settings_set_duplex_mode(struct _cef_print_settings_t* self,
+ cef_duplex_mode_t mode) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefPrintSettingsCppToC::Get(self)->SetDuplexMode(mode);
+}
+
+cef_duplex_mode_t CEF_CALLBACK
+print_settings_get_duplex_mode(struct _cef_print_settings_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return DUPLEX_MODE_UNKNOWN;
+ }
+
+ // Execute
+ cef_duplex_mode_t _retval =
+ CefPrintSettingsCppToC::Get(self)->GetDuplexMode();
+
+ // Return type: simple
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefPrintSettingsCppToC::CefPrintSettingsCppToC() {
+ GetStruct()->is_valid = print_settings_is_valid;
+ GetStruct()->is_read_only = print_settings_is_read_only;
+ GetStruct()->set_orientation = print_settings_set_orientation;
+ GetStruct()->is_landscape = print_settings_is_landscape;
+ GetStruct()->set_printer_printable_area =
+ print_settings_set_printer_printable_area;
+ GetStruct()->set_device_name = print_settings_set_device_name;
+ GetStruct()->get_device_name = print_settings_get_device_name;
+ GetStruct()->set_dpi = print_settings_set_dpi;
+ GetStruct()->get_dpi = print_settings_get_dpi;
+ GetStruct()->set_page_ranges = print_settings_set_page_ranges;
+ GetStruct()->get_page_ranges_count = print_settings_get_page_ranges_count;
+ GetStruct()->get_page_ranges = print_settings_get_page_ranges;
+ GetStruct()->set_selection_only = print_settings_set_selection_only;
+ GetStruct()->is_selection_only = print_settings_is_selection_only;
+ GetStruct()->set_collate = print_settings_set_collate;
+ GetStruct()->will_collate = print_settings_will_collate;
+ GetStruct()->set_color_model = print_settings_set_color_model;
+ GetStruct()->get_color_model = print_settings_get_color_model;
+ GetStruct()->set_copies = print_settings_set_copies;
+ GetStruct()->get_copies = print_settings_get_copies;
+ GetStruct()->set_duplex_mode = print_settings_set_duplex_mode;
+ GetStruct()->get_duplex_mode = print_settings_get_duplex_mode;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefPrintSettingsCppToC::~CefPrintSettingsCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefPrintSettings> CefCppToCRefCounted<
+ CefPrintSettingsCppToC,
+ CefPrintSettings,
+ cef_print_settings_t>::UnwrapDerived(CefWrapperType type,
+ cef_print_settings_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefPrintSettingsCppToC,
+ CefPrintSettings,
+ cef_print_settings_t>::kWrapperType =
+ WT_PRINT_SETTINGS;
diff --git a/libcef_dll/cpptoc/print_settings_cpptoc.h b/libcef_dll/cpptoc/print_settings_cpptoc.h
new file mode 100644
index 00000000..c7ece392
--- /dev/null
+++ b/libcef_dll/cpptoc/print_settings_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=596144335f97b41394808d0de0908c2a69d04d7a$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_PRINT_SETTINGS_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_PRINT_SETTINGS_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_print_settings_capi.h"
+#include "include/cef_print_settings.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefPrintSettingsCppToC
+ : public CefCppToCRefCounted<CefPrintSettingsCppToC,
+ CefPrintSettings,
+ cef_print_settings_t> {
+ public:
+ CefPrintSettingsCppToC();
+ virtual ~CefPrintSettingsCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_PRINT_SETTINGS_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/process_message_cpptoc.cc b/libcef_dll/cpptoc/process_message_cpptoc.cc
new file mode 100644
index 00000000..538de7b9
--- /dev/null
+++ b/libcef_dll/cpptoc/process_message_cpptoc.cc
@@ -0,0 +1,190 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=80473999475a2327eca8289bd30d970c699abb21$
+//
+
+#include "libcef_dll/cpptoc/process_message_cpptoc.h"
+#include "libcef_dll/cpptoc/list_value_cpptoc.h"
+#include "libcef_dll/cpptoc/shared_memory_region_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// GLOBAL FUNCTIONS - Body may be edited by hand.
+
+CEF_EXPORT cef_process_message_t* cef_process_message_create(
+ const cef_string_t* name) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: name; type: string_byref_const
+ DCHECK(name);
+ if (!name) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefProcessMessage> _retval =
+ CefProcessMessage::Create(CefString(name));
+
+ // Return type: refptr_same
+ return CefProcessMessageCppToC::Wrap(_retval);
+}
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK process_message_is_valid(struct _cef_process_message_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefProcessMessageCppToC::Get(self)->IsValid();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+process_message_is_read_only(struct _cef_process_message_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefProcessMessageCppToC::Get(self)->IsReadOnly();
+
+ // Return type: bool
+ return _retval;
+}
+
+struct _cef_process_message_t* CEF_CALLBACK
+process_message_copy(struct _cef_process_message_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefProcessMessage> _retval =
+ CefProcessMessageCppToC::Get(self)->Copy();
+
+ // Return type: refptr_same
+ return CefProcessMessageCppToC::Wrap(_retval);
+}
+
+cef_string_userfree_t CEF_CALLBACK
+process_message_get_name(struct _cef_process_message_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefProcessMessageCppToC::Get(self)->GetName();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+struct _cef_list_value_t* CEF_CALLBACK
+process_message_get_argument_list(struct _cef_process_message_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefListValue> _retval =
+ CefProcessMessageCppToC::Get(self)->GetArgumentList();
+
+ // Return type: refptr_same
+ return CefListValueCppToC::Wrap(_retval);
+}
+
+struct _cef_shared_memory_region_t* CEF_CALLBACK
+process_message_get_shared_memory_region(struct _cef_process_message_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefSharedMemoryRegion> _retval =
+ CefProcessMessageCppToC::Get(self)->GetSharedMemoryRegion();
+
+ // Return type: refptr_same
+ return CefSharedMemoryRegionCppToC::Wrap(_retval);
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefProcessMessageCppToC::CefProcessMessageCppToC() {
+ GetStruct()->is_valid = process_message_is_valid;
+ GetStruct()->is_read_only = process_message_is_read_only;
+ GetStruct()->copy = process_message_copy;
+ GetStruct()->get_name = process_message_get_name;
+ GetStruct()->get_argument_list = process_message_get_argument_list;
+ GetStruct()->get_shared_memory_region =
+ process_message_get_shared_memory_region;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefProcessMessageCppToC::~CefProcessMessageCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefProcessMessage> CefCppToCRefCounted<
+ CefProcessMessageCppToC,
+ CefProcessMessage,
+ cef_process_message_t>::UnwrapDerived(CefWrapperType type,
+ cef_process_message_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefProcessMessageCppToC,
+ CefProcessMessage,
+ cef_process_message_t>::kWrapperType =
+ WT_PROCESS_MESSAGE;
diff --git a/libcef_dll/cpptoc/process_message_cpptoc.h b/libcef_dll/cpptoc/process_message_cpptoc.h
new file mode 100644
index 00000000..e3f24858
--- /dev/null
+++ b/libcef_dll/cpptoc/process_message_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=6d4c104d51d4d34c0ec8b767a13db58a6fb0fef8$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_PROCESS_MESSAGE_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_PROCESS_MESSAGE_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_process_message_capi.h"
+#include "include/cef_process_message.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefProcessMessageCppToC
+ : public CefCppToCRefCounted<CefProcessMessageCppToC,
+ CefProcessMessage,
+ cef_process_message_t> {
+ public:
+ CefProcessMessageCppToC();
+ virtual ~CefProcessMessageCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_PROCESS_MESSAGE_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/read_handler_cpptoc.cc b/libcef_dll/cpptoc/read_handler_cpptoc.cc
new file mode 100644
index 00000000..ba6aab8f
--- /dev/null
+++ b/libcef_dll/cpptoc/read_handler_cpptoc.cc
@@ -0,0 +1,147 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=808efb0b2702ab12ea55c67846d9159a45cc0bd7$
+//
+
+#include "libcef_dll/cpptoc/read_handler_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+size_t CEF_CALLBACK read_handler_read(struct _cef_read_handler_t* self,
+ void* ptr,
+ size_t size,
+ size_t n) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: ptr; type: simple_byaddr
+ DCHECK(ptr);
+ if (!ptr) {
+ return 0;
+ }
+
+ // Execute
+ size_t _retval = CefReadHandlerCppToC::Get(self)->Read(ptr, size, n);
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK read_handler_seek(struct _cef_read_handler_t* self,
+ int64 offset,
+ int whence) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefReadHandlerCppToC::Get(self)->Seek(offset, whence);
+
+ // Return type: simple
+ return _retval;
+}
+
+int64 CEF_CALLBACK read_handler_tell(struct _cef_read_handler_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int64 _retval = CefReadHandlerCppToC::Get(self)->Tell();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK read_handler_eof(struct _cef_read_handler_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefReadHandlerCppToC::Get(self)->Eof();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK read_handler_may_block(struct _cef_read_handler_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefReadHandlerCppToC::Get(self)->MayBlock();
+
+ // Return type: bool
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefReadHandlerCppToC::CefReadHandlerCppToC() {
+ GetStruct()->read = read_handler_read;
+ GetStruct()->seek = read_handler_seek;
+ GetStruct()->tell = read_handler_tell;
+ GetStruct()->eof = read_handler_eof;
+ GetStruct()->may_block = read_handler_may_block;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefReadHandlerCppToC::~CefReadHandlerCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefReadHandler>
+CefCppToCRefCounted<CefReadHandlerCppToC, CefReadHandler, cef_read_handler_t>::
+ UnwrapDerived(CefWrapperType type, cef_read_handler_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefReadHandlerCppToC,
+ CefReadHandler,
+ cef_read_handler_t>::kWrapperType =
+ WT_READ_HANDLER;
diff --git a/libcef_dll/cpptoc/read_handler_cpptoc.h b/libcef_dll/cpptoc/read_handler_cpptoc.h
new file mode 100644
index 00000000..4c4ddc6e
--- /dev/null
+++ b/libcef_dll/cpptoc/read_handler_cpptoc.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=8a5eb8ffc9a8857ac10a6586e954dc532d10618a$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_READ_HANDLER_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_READ_HANDLER_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_stream_capi.h"
+#include "include/cef_stream.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefReadHandlerCppToC : public CefCppToCRefCounted<CefReadHandlerCppToC,
+ CefReadHandler,
+ cef_read_handler_t> {
+ public:
+ CefReadHandlerCppToC();
+ virtual ~CefReadHandlerCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_READ_HANDLER_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/registration_cpptoc.cc b/libcef_dll/cpptoc/registration_cpptoc.cc
new file mode 100644
index 00000000..ab7f377f
--- /dev/null
+++ b/libcef_dll/cpptoc/registration_cpptoc.cc
@@ -0,0 +1,42 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=9256f12f40a70c8a2e6100882473516f80c097c4$
+//
+
+#include "libcef_dll/cpptoc/registration_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefRegistrationCppToC::CefRegistrationCppToC() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefRegistrationCppToC::~CefRegistrationCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefRegistration>
+CefCppToCRefCounted<CefRegistrationCppToC,
+ CefRegistration,
+ cef_registration_t>::UnwrapDerived(CefWrapperType type,
+ cef_registration_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefRegistrationCppToC,
+ CefRegistration,
+ cef_registration_t>::kWrapperType =
+ WT_REGISTRATION;
diff --git a/libcef_dll/cpptoc/registration_cpptoc.h b/libcef_dll/cpptoc/registration_cpptoc.h
new file mode 100644
index 00000000..8fd4ce15
--- /dev/null
+++ b/libcef_dll/cpptoc/registration_cpptoc.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=461d6b9297ebd61bf8d2df2e3960458a9a3705f6$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_REGISTRATION_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_REGISTRATION_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_registration_capi.h"
+#include "include/cef_registration.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefRegistrationCppToC : public CefCppToCRefCounted<CefRegistrationCppToC,
+ CefRegistration,
+ cef_registration_t> {
+ public:
+ CefRegistrationCppToC();
+ virtual ~CefRegistrationCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_REGISTRATION_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/render_handler_cpptoc.cc b/libcef_dll/cpptoc/render_handler_cpptoc.cc
new file mode 100644
index 00000000..8420b229
--- /dev/null
+++ b/libcef_dll/cpptoc/render_handler_cpptoc.cc
@@ -0,0 +1,655 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=46ea8d3dc2d9f2c1f430eb15fecc16768e6adb6a$
+//
+
+#include "libcef_dll/cpptoc/render_handler_cpptoc.h"
+#include "libcef_dll/cpptoc/accessibility_handler_cpptoc.h"
+#include "libcef_dll/ctocpp/browser_ctocpp.h"
+#include "libcef_dll/ctocpp/drag_data_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+cef_accessibility_handler_t* CEF_CALLBACK
+render_handler_get_accessibility_handler(struct _cef_render_handler_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefAccessibilityHandler> _retval =
+ CefRenderHandlerCppToC::Get(self)->GetAccessibilityHandler();
+
+ // Return type: refptr_same
+ return CefAccessibilityHandlerCppToC::Wrap(_retval);
+}
+
+int CEF_CALLBACK
+render_handler_get_root_screen_rect(struct _cef_render_handler_t* self,
+ cef_browser_t* browser,
+ cef_rect_t* rect) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return 0;
+ }
+ // Verify param: rect; type: simple_byref
+ DCHECK(rect);
+ if (!rect) {
+ return 0;
+ }
+
+ // Translate param: rect; type: simple_byref
+ CefRect rectVal = rect ? *rect : CefRect();
+
+ // Execute
+ bool _retval = CefRenderHandlerCppToC::Get(self)->GetRootScreenRect(
+ CefBrowserCToCpp::Wrap(browser), rectVal);
+
+ // Restore param: rect; type: simple_byref
+ if (rect) {
+ *rect = rectVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK
+render_handler_get_view_rect(struct _cef_render_handler_t* self,
+ cef_browser_t* browser,
+ cef_rect_t* rect) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+ // Verify param: rect; type: simple_byref
+ DCHECK(rect);
+ if (!rect) {
+ return;
+ }
+
+ // Translate param: rect; type: simple_byref
+ CefRect rectVal = rect ? *rect : CefRect();
+
+ // Execute
+ CefRenderHandlerCppToC::Get(self)->GetViewRect(
+ CefBrowserCToCpp::Wrap(browser), rectVal);
+
+ // Restore param: rect; type: simple_byref
+ if (rect) {
+ *rect = rectVal;
+ }
+}
+
+int CEF_CALLBACK
+render_handler_get_screen_point(struct _cef_render_handler_t* self,
+ cef_browser_t* browser,
+ int viewX,
+ int viewY,
+ int* screenX,
+ int* screenY) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return 0;
+ }
+ // Verify param: screenX; type: simple_byref
+ DCHECK(screenX);
+ if (!screenX) {
+ return 0;
+ }
+ // Verify param: screenY; type: simple_byref
+ DCHECK(screenY);
+ if (!screenY) {
+ return 0;
+ }
+
+ // Translate param: screenX; type: simple_byref
+ int screenXVal = screenX ? *screenX : 0;
+ // Translate param: screenY; type: simple_byref
+ int screenYVal = screenY ? *screenY : 0;
+
+ // Execute
+ bool _retval = CefRenderHandlerCppToC::Get(self)->GetScreenPoint(
+ CefBrowserCToCpp::Wrap(browser), viewX, viewY, screenXVal, screenYVal);
+
+ // Restore param: screenX; type: simple_byref
+ if (screenX) {
+ *screenX = screenXVal;
+ }
+ // Restore param: screenY; type: simple_byref
+ if (screenY) {
+ *screenY = screenYVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+render_handler_get_screen_info(struct _cef_render_handler_t* self,
+ cef_browser_t* browser,
+ cef_screen_info_t* screen_info) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return 0;
+ }
+ // Verify param: screen_info; type: simple_byref
+ DCHECK(screen_info);
+ if (!screen_info) {
+ return 0;
+ }
+
+ // Translate param: screen_info; type: simple_byref
+ CefScreenInfo screen_infoVal = screen_info ? *screen_info : CefScreenInfo();
+
+ // Execute
+ bool _retval = CefRenderHandlerCppToC::Get(self)->GetScreenInfo(
+ CefBrowserCToCpp::Wrap(browser), screen_infoVal);
+
+ // Restore param: screen_info; type: simple_byref
+ if (screen_info) {
+ *screen_info = screen_infoVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK
+render_handler_on_popup_show(struct _cef_render_handler_t* self,
+ cef_browser_t* browser,
+ int show) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+
+ // Execute
+ CefRenderHandlerCppToC::Get(self)->OnPopupShow(
+ CefBrowserCToCpp::Wrap(browser), show ? true : false);
+}
+
+void CEF_CALLBACK
+render_handler_on_popup_size(struct _cef_render_handler_t* self,
+ cef_browser_t* browser,
+ const cef_rect_t* rect) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+ // Verify param: rect; type: simple_byref_const
+ DCHECK(rect);
+ if (!rect) {
+ return;
+ }
+
+ // Translate param: rect; type: simple_byref_const
+ CefRect rectVal = rect ? *rect : CefRect();
+
+ // Execute
+ CefRenderHandlerCppToC::Get(self)->OnPopupSize(
+ CefBrowserCToCpp::Wrap(browser), rectVal);
+}
+
+void CEF_CALLBACK render_handler_on_paint(struct _cef_render_handler_t* self,
+ cef_browser_t* browser,
+ cef_paint_element_type_t type,
+ size_t dirtyRectsCount,
+ cef_rect_t const* dirtyRects,
+ const void* buffer,
+ int width,
+ int height) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+ // Verify param: dirtyRects; type: simple_vec_byref_const
+ DCHECK(dirtyRectsCount == 0 || dirtyRects);
+ if (dirtyRectsCount > 0 && !dirtyRects) {
+ return;
+ }
+ // Verify param: buffer; type: simple_byaddr
+ DCHECK(buffer);
+ if (!buffer) {
+ return;
+ }
+
+ // Translate param: dirtyRects; type: simple_vec_byref_const
+ std::vector<CefRect> dirtyRectsList;
+ if (dirtyRectsCount > 0) {
+ for (size_t i = 0; i < dirtyRectsCount; ++i) {
+ CefRect dirtyRectsVal = dirtyRects[i];
+ dirtyRectsList.push_back(dirtyRectsVal);
+ }
+ }
+
+ // Execute
+ CefRenderHandlerCppToC::Get(self)->OnPaint(CefBrowserCToCpp::Wrap(browser),
+ type, dirtyRectsList, buffer,
+ width, height);
+}
+
+void CEF_CALLBACK
+render_handler_on_accelerated_paint(struct _cef_render_handler_t* self,
+ cef_browser_t* browser,
+ cef_paint_element_type_t type,
+ size_t dirtyRectsCount,
+ cef_rect_t const* dirtyRects,
+ void* shared_handle) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+ // Verify param: dirtyRects; type: simple_vec_byref_const
+ DCHECK(dirtyRectsCount == 0 || dirtyRects);
+ if (dirtyRectsCount > 0 && !dirtyRects) {
+ return;
+ }
+ // Verify param: shared_handle; type: simple_byaddr
+ DCHECK(shared_handle);
+ if (!shared_handle) {
+ return;
+ }
+
+ // Translate param: dirtyRects; type: simple_vec_byref_const
+ std::vector<CefRect> dirtyRectsList;
+ if (dirtyRectsCount > 0) {
+ for (size_t i = 0; i < dirtyRectsCount; ++i) {
+ CefRect dirtyRectsVal = dirtyRects[i];
+ dirtyRectsList.push_back(dirtyRectsVal);
+ }
+ }
+
+ // Execute
+ CefRenderHandlerCppToC::Get(self)->OnAcceleratedPaint(
+ CefBrowserCToCpp::Wrap(browser), type, dirtyRectsList, shared_handle);
+}
+
+void CEF_CALLBACK
+render_handler_get_touch_handle_size(struct _cef_render_handler_t* self,
+ cef_browser_t* browser,
+ cef_horizontal_alignment_t orientation,
+ cef_size_t* size) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+ // Verify param: size; type: simple_byref
+ DCHECK(size);
+ if (!size) {
+ return;
+ }
+
+ // Translate param: size; type: simple_byref
+ CefSize sizeVal = size ? *size : CefSize();
+
+ // Execute
+ CefRenderHandlerCppToC::Get(self)->GetTouchHandleSize(
+ CefBrowserCToCpp::Wrap(browser), orientation, sizeVal);
+
+ // Restore param: size; type: simple_byref
+ if (size) {
+ *size = sizeVal;
+ }
+}
+
+void CEF_CALLBACK render_handler_on_touch_handle_state_changed(
+ struct _cef_render_handler_t* self,
+ cef_browser_t* browser,
+ const cef_touch_handle_state_t* state) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+ // Verify param: state; type: simple_byref_const
+ DCHECK(state);
+ if (!state) {
+ return;
+ }
+
+ // Translate param: state; type: simple_byref_const
+ CefTouchHandleState stateVal = state ? *state : CefTouchHandleState();
+
+ // Execute
+ CefRenderHandlerCppToC::Get(self)->OnTouchHandleStateChanged(
+ CefBrowserCToCpp::Wrap(browser), stateVal);
+}
+
+int CEF_CALLBACK
+render_handler_start_dragging(struct _cef_render_handler_t* self,
+ cef_browser_t* browser,
+ cef_drag_data_t* drag_data,
+ cef_drag_operations_mask_t allowed_ops,
+ int x,
+ int y) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return 0;
+ }
+ // Verify param: drag_data; type: refptr_diff
+ DCHECK(drag_data);
+ if (!drag_data) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefRenderHandlerCppToC::Get(self)->StartDragging(
+ CefBrowserCToCpp::Wrap(browser), CefDragDataCToCpp::Wrap(drag_data),
+ allowed_ops, x, y);
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK
+render_handler_update_drag_cursor(struct _cef_render_handler_t* self,
+ cef_browser_t* browser,
+ cef_drag_operations_mask_t operation) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+
+ // Execute
+ CefRenderHandlerCppToC::Get(self)->UpdateDragCursor(
+ CefBrowserCToCpp::Wrap(browser), operation);
+}
+
+void CEF_CALLBACK
+render_handler_on_scroll_offset_changed(struct _cef_render_handler_t* self,
+ cef_browser_t* browser,
+ double x,
+ double y) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+
+ // Execute
+ CefRenderHandlerCppToC::Get(self)->OnScrollOffsetChanged(
+ CefBrowserCToCpp::Wrap(browser), x, y);
+}
+
+void CEF_CALLBACK render_handler_on_ime_composition_range_changed(
+ struct _cef_render_handler_t* self,
+ cef_browser_t* browser,
+ const cef_range_t* selected_range,
+ size_t character_boundsCount,
+ cef_rect_t const* character_bounds) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+ // Verify param: selected_range; type: simple_byref_const
+ DCHECK(selected_range);
+ if (!selected_range) {
+ return;
+ }
+ // Verify param: character_bounds; type: simple_vec_byref_const
+ DCHECK(character_boundsCount == 0 || character_bounds);
+ if (character_boundsCount > 0 && !character_bounds) {
+ return;
+ }
+
+ // Translate param: selected_range; type: simple_byref_const
+ CefRange selected_rangeVal = selected_range ? *selected_range : CefRange();
+ // Translate param: character_bounds; type: simple_vec_byref_const
+ std::vector<CefRect> character_boundsList;
+ if (character_boundsCount > 0) {
+ for (size_t i = 0; i < character_boundsCount; ++i) {
+ CefRect character_boundsVal = character_bounds[i];
+ character_boundsList.push_back(character_boundsVal);
+ }
+ }
+
+ // Execute
+ CefRenderHandlerCppToC::Get(self)->OnImeCompositionRangeChanged(
+ CefBrowserCToCpp::Wrap(browser), selected_rangeVal, character_boundsList);
+}
+
+void CEF_CALLBACK
+render_handler_on_text_selection_changed(struct _cef_render_handler_t* self,
+ cef_browser_t* browser,
+ const cef_string_t* selected_text,
+ const cef_range_t* selected_range) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+ // Unverified params: selected_text, selected_range
+
+ // Translate param: selected_range; type: simple_byref_const
+ CefRange selected_rangeVal = selected_range ? *selected_range : CefRange();
+
+ // Execute
+ CefRenderHandlerCppToC::Get(self)->OnTextSelectionChanged(
+ CefBrowserCToCpp::Wrap(browser), CefString(selected_text),
+ selected_rangeVal);
+}
+
+void CEF_CALLBACK
+render_handler_on_virtual_keyboard_requested(struct _cef_render_handler_t* self,
+ cef_browser_t* browser,
+ cef_text_input_mode_t input_mode) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+
+ // Execute
+ CefRenderHandlerCppToC::Get(self)->OnVirtualKeyboardRequested(
+ CefBrowserCToCpp::Wrap(browser), input_mode);
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefRenderHandlerCppToC::CefRenderHandlerCppToC() {
+ GetStruct()->get_accessibility_handler =
+ render_handler_get_accessibility_handler;
+ GetStruct()->get_root_screen_rect = render_handler_get_root_screen_rect;
+ GetStruct()->get_view_rect = render_handler_get_view_rect;
+ GetStruct()->get_screen_point = render_handler_get_screen_point;
+ GetStruct()->get_screen_info = render_handler_get_screen_info;
+ GetStruct()->on_popup_show = render_handler_on_popup_show;
+ GetStruct()->on_popup_size = render_handler_on_popup_size;
+ GetStruct()->on_paint = render_handler_on_paint;
+ GetStruct()->on_accelerated_paint = render_handler_on_accelerated_paint;
+ GetStruct()->get_touch_handle_size = render_handler_get_touch_handle_size;
+ GetStruct()->on_touch_handle_state_changed =
+ render_handler_on_touch_handle_state_changed;
+ GetStruct()->start_dragging = render_handler_start_dragging;
+ GetStruct()->update_drag_cursor = render_handler_update_drag_cursor;
+ GetStruct()->on_scroll_offset_changed =
+ render_handler_on_scroll_offset_changed;
+ GetStruct()->on_ime_composition_range_changed =
+ render_handler_on_ime_composition_range_changed;
+ GetStruct()->on_text_selection_changed =
+ render_handler_on_text_selection_changed;
+ GetStruct()->on_virtual_keyboard_requested =
+ render_handler_on_virtual_keyboard_requested;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefRenderHandlerCppToC::~CefRenderHandlerCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefRenderHandler> CefCppToCRefCounted<
+ CefRenderHandlerCppToC,
+ CefRenderHandler,
+ cef_render_handler_t>::UnwrapDerived(CefWrapperType type,
+ cef_render_handler_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefRenderHandlerCppToC,
+ CefRenderHandler,
+ cef_render_handler_t>::kWrapperType =
+ WT_RENDER_HANDLER;
diff --git a/libcef_dll/cpptoc/render_handler_cpptoc.h b/libcef_dll/cpptoc/render_handler_cpptoc.h
new file mode 100644
index 00000000..f56251d7
--- /dev/null
+++ b/libcef_dll/cpptoc/render_handler_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=a0cdfb84f8b30f01dd01556ad3e1725e043641e0$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_RENDER_HANDLER_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_RENDER_HANDLER_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_render_handler_capi.h"
+#include "include/cef_render_handler.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefRenderHandlerCppToC
+ : public CefCppToCRefCounted<CefRenderHandlerCppToC,
+ CefRenderHandler,
+ cef_render_handler_t> {
+ public:
+ CefRenderHandlerCppToC();
+ virtual ~CefRenderHandlerCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_RENDER_HANDLER_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/render_process_handler_cpptoc.cc b/libcef_dll/cpptoc/render_process_handler_cpptoc.cc
new file mode 100644
index 00000000..40ee7bd1
--- /dev/null
+++ b/libcef_dll/cpptoc/render_process_handler_cpptoc.cc
@@ -0,0 +1,317 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=5737d6b536a99ac844904acaa8977c25476ed524$
+//
+
+#include "libcef_dll/cpptoc/render_process_handler_cpptoc.h"
+#include "libcef_dll/cpptoc/load_handler_cpptoc.h"
+#include "libcef_dll/ctocpp/browser_ctocpp.h"
+#include "libcef_dll/ctocpp/dictionary_value_ctocpp.h"
+#include "libcef_dll/ctocpp/domnode_ctocpp.h"
+#include "libcef_dll/ctocpp/frame_ctocpp.h"
+#include "libcef_dll/ctocpp/process_message_ctocpp.h"
+#include "libcef_dll/ctocpp/v8context_ctocpp.h"
+#include "libcef_dll/ctocpp/v8exception_ctocpp.h"
+#include "libcef_dll/ctocpp/v8stack_trace_ctocpp.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK render_process_handler_on_web_kit_initialized(
+ struct _cef_render_process_handler_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefRenderProcessHandlerCppToC::Get(self)->OnWebKitInitialized();
+}
+
+void CEF_CALLBACK render_process_handler_on_browser_created(
+ struct _cef_render_process_handler_t* self,
+ cef_browser_t* browser,
+ struct _cef_dictionary_value_t* extra_info) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+ // Unverified params: extra_info
+
+ // Execute
+ CefRenderProcessHandlerCppToC::Get(self)->OnBrowserCreated(
+ CefBrowserCToCpp::Wrap(browser),
+ CefDictionaryValueCToCpp::Wrap(extra_info));
+}
+
+void CEF_CALLBACK render_process_handler_on_browser_destroyed(
+ struct _cef_render_process_handler_t* self,
+ cef_browser_t* browser) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+
+ // Execute
+ CefRenderProcessHandlerCppToC::Get(self)->OnBrowserDestroyed(
+ CefBrowserCToCpp::Wrap(browser));
+}
+
+cef_load_handler_t* CEF_CALLBACK render_process_handler_get_load_handler(
+ struct _cef_render_process_handler_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefLoadHandler> _retval =
+ CefRenderProcessHandlerCppToC::Get(self)->GetLoadHandler();
+
+ // Return type: refptr_same
+ return CefLoadHandlerCppToC::Wrap(_retval);
+}
+
+void CEF_CALLBACK render_process_handler_on_context_created(
+ struct _cef_render_process_handler_t* self,
+ cef_browser_t* browser,
+ cef_frame_t* frame,
+ struct _cef_v8context_t* context) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+ // Verify param: frame; type: refptr_diff
+ DCHECK(frame);
+ if (!frame) {
+ return;
+ }
+ // Verify param: context; type: refptr_diff
+ DCHECK(context);
+ if (!context) {
+ return;
+ }
+
+ // Execute
+ CefRenderProcessHandlerCppToC::Get(self)->OnContextCreated(
+ CefBrowserCToCpp::Wrap(browser), CefFrameCToCpp::Wrap(frame),
+ CefV8ContextCToCpp::Wrap(context));
+}
+
+void CEF_CALLBACK render_process_handler_on_context_released(
+ struct _cef_render_process_handler_t* self,
+ cef_browser_t* browser,
+ cef_frame_t* frame,
+ struct _cef_v8context_t* context) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+ // Verify param: frame; type: refptr_diff
+ DCHECK(frame);
+ if (!frame) {
+ return;
+ }
+ // Verify param: context; type: refptr_diff
+ DCHECK(context);
+ if (!context) {
+ return;
+ }
+
+ // Execute
+ CefRenderProcessHandlerCppToC::Get(self)->OnContextReleased(
+ CefBrowserCToCpp::Wrap(browser), CefFrameCToCpp::Wrap(frame),
+ CefV8ContextCToCpp::Wrap(context));
+}
+
+void CEF_CALLBACK render_process_handler_on_uncaught_exception(
+ struct _cef_render_process_handler_t* self,
+ cef_browser_t* browser,
+ cef_frame_t* frame,
+ struct _cef_v8context_t* context,
+ struct _cef_v8exception_t* exception,
+ struct _cef_v8stack_trace_t* stackTrace) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+ // Verify param: frame; type: refptr_diff
+ DCHECK(frame);
+ if (!frame) {
+ return;
+ }
+ // Verify param: context; type: refptr_diff
+ DCHECK(context);
+ if (!context) {
+ return;
+ }
+ // Verify param: exception; type: refptr_diff
+ DCHECK(exception);
+ if (!exception) {
+ return;
+ }
+ // Verify param: stackTrace; type: refptr_diff
+ DCHECK(stackTrace);
+ if (!stackTrace) {
+ return;
+ }
+
+ // Execute
+ CefRenderProcessHandlerCppToC::Get(self)->OnUncaughtException(
+ CefBrowserCToCpp::Wrap(browser), CefFrameCToCpp::Wrap(frame),
+ CefV8ContextCToCpp::Wrap(context), CefV8ExceptionCToCpp::Wrap(exception),
+ CefV8StackTraceCToCpp::Wrap(stackTrace));
+}
+
+void CEF_CALLBACK render_process_handler_on_focused_node_changed(
+ struct _cef_render_process_handler_t* self,
+ cef_browser_t* browser,
+ cef_frame_t* frame,
+ cef_domnode_t* node) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+ // Unverified params: frame, node
+
+ // Execute
+ CefRenderProcessHandlerCppToC::Get(self)->OnFocusedNodeChanged(
+ CefBrowserCToCpp::Wrap(browser), CefFrameCToCpp::Wrap(frame),
+ CefDOMNodeCToCpp::Wrap(node));
+}
+
+int CEF_CALLBACK render_process_handler_on_process_message_received(
+ struct _cef_render_process_handler_t* self,
+ cef_browser_t* browser,
+ cef_frame_t* frame,
+ cef_process_id_t source_process,
+ cef_process_message_t* message) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return 0;
+ }
+ // Verify param: frame; type: refptr_diff
+ DCHECK(frame);
+ if (!frame) {
+ return 0;
+ }
+ // Verify param: message; type: refptr_diff
+ DCHECK(message);
+ if (!message) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefRenderProcessHandlerCppToC::Get(self)->OnProcessMessageReceived(
+ CefBrowserCToCpp::Wrap(browser), CefFrameCToCpp::Wrap(frame),
+ source_process, CefProcessMessageCToCpp::Wrap(message));
+
+ // Return type: bool
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefRenderProcessHandlerCppToC::CefRenderProcessHandlerCppToC() {
+ GetStruct()->on_web_kit_initialized =
+ render_process_handler_on_web_kit_initialized;
+ GetStruct()->on_browser_created = render_process_handler_on_browser_created;
+ GetStruct()->on_browser_destroyed =
+ render_process_handler_on_browser_destroyed;
+ GetStruct()->get_load_handler = render_process_handler_get_load_handler;
+ GetStruct()->on_context_created = render_process_handler_on_context_created;
+ GetStruct()->on_context_released = render_process_handler_on_context_released;
+ GetStruct()->on_uncaught_exception =
+ render_process_handler_on_uncaught_exception;
+ GetStruct()->on_focused_node_changed =
+ render_process_handler_on_focused_node_changed;
+ GetStruct()->on_process_message_received =
+ render_process_handler_on_process_message_received;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefRenderProcessHandlerCppToC::~CefRenderProcessHandlerCppToC() {}
+
+template <>
+CefRefPtr<CefRenderProcessHandler> CefCppToCRefCounted<
+ CefRenderProcessHandlerCppToC,
+ CefRenderProcessHandler,
+ cef_render_process_handler_t>::UnwrapDerived(CefWrapperType type,
+ cef_render_process_handler_t*
+ s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefRenderProcessHandlerCppToC,
+ CefRenderProcessHandler,
+ cef_render_process_handler_t>::kWrapperType =
+ WT_RENDER_PROCESS_HANDLER;
diff --git a/libcef_dll/cpptoc/render_process_handler_cpptoc.h b/libcef_dll/cpptoc/render_process_handler_cpptoc.h
new file mode 100644
index 00000000..124c4a50
--- /dev/null
+++ b/libcef_dll/cpptoc/render_process_handler_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=1686827d48e7c0d75a603a2b6b8ca05b4f158340$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_RENDER_PROCESS_HANDLER_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_RENDER_PROCESS_HANDLER_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_render_process_handler_capi.h"
+#include "include/cef_render_process_handler.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefRenderProcessHandlerCppToC
+ : public CefCppToCRefCounted<CefRenderProcessHandlerCppToC,
+ CefRenderProcessHandler,
+ cef_render_process_handler_t> {
+ public:
+ CefRenderProcessHandlerCppToC();
+ virtual ~CefRenderProcessHandlerCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_RENDER_PROCESS_HANDLER_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/request_context_cpptoc.cc b/libcef_dll/cpptoc/request_context_cpptoc.cc
new file mode 100644
index 00000000..f0bd72ed
--- /dev/null
+++ b/libcef_dll/cpptoc/request_context_cpptoc.cc
@@ -0,0 +1,654 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=e710aaf020af29d178d2668e24577c371ebf6d45$
+//
+
+#include "libcef_dll/cpptoc/request_context_cpptoc.h"
+#include "libcef_dll/cpptoc/cookie_manager_cpptoc.h"
+#include "libcef_dll/cpptoc/dictionary_value_cpptoc.h"
+#include "libcef_dll/cpptoc/extension_cpptoc.h"
+#include "libcef_dll/cpptoc/media_router_cpptoc.h"
+#include "libcef_dll/cpptoc/value_cpptoc.h"
+#include "libcef_dll/ctocpp/completion_callback_ctocpp.h"
+#include "libcef_dll/ctocpp/extension_handler_ctocpp.h"
+#include "libcef_dll/ctocpp/request_context_handler_ctocpp.h"
+#include "libcef_dll/ctocpp/resolve_callback_ctocpp.h"
+#include "libcef_dll/ctocpp/scheme_handler_factory_ctocpp.h"
+#include "libcef_dll/template_util.h"
+#include "libcef_dll/transfer_util.h"
+
+// GLOBAL FUNCTIONS - Body may be edited by hand.
+
+CEF_EXPORT cef_request_context_t* cef_request_context_get_global_context() {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ CefRefPtr<CefRequestContext> _retval = CefRequestContext::GetGlobalContext();
+
+ // Return type: refptr_same
+ return CefRequestContextCppToC::Wrap(_retval);
+}
+
+CEF_EXPORT cef_request_context_t* cef_request_context_create_context(
+ const struct _cef_request_context_settings_t* settings,
+ struct _cef_request_context_handler_t* handler) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: settings; type: struct_byref_const
+ DCHECK(settings);
+ if (!settings) {
+ return NULL;
+ }
+ if (!template_util::has_valid_size(settings)) {
+ NOTREACHED() << "invalid settings->[base.]size";
+ return NULL;
+ }
+ // Unverified params: handler
+
+ // Translate param: settings; type: struct_byref_const
+ CefRequestContextSettings settingsObj;
+ if (settings) {
+ settingsObj.Set(*settings, false);
+ }
+
+ // Execute
+ CefRefPtr<CefRequestContext> _retval = CefRequestContext::CreateContext(
+ settingsObj, CefRequestContextHandlerCToCpp::Wrap(handler));
+
+ // Return type: refptr_same
+ return CefRequestContextCppToC::Wrap(_retval);
+}
+
+CEF_EXPORT cef_request_context_t* cef_create_context_shared(
+ cef_request_context_t* other,
+ struct _cef_request_context_handler_t* handler) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: other; type: refptr_same
+ DCHECK(other);
+ if (!other) {
+ return NULL;
+ }
+ // Unverified params: handler
+
+ // Execute
+ CefRefPtr<CefRequestContext> _retval = CefRequestContext::CreateContext(
+ CefRequestContextCppToC::Unwrap(other),
+ CefRequestContextHandlerCToCpp::Wrap(handler));
+
+ // Return type: refptr_same
+ return CefRequestContextCppToC::Wrap(_retval);
+}
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK request_context_is_same(struct _cef_request_context_t* self,
+ struct _cef_request_context_t* other) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: other; type: refptr_same
+ DCHECK(other);
+ if (!other) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefRequestContextCppToC::Get(self)->IsSame(
+ CefRequestContextCppToC::Unwrap(other));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+request_context_is_sharing_with(struct _cef_request_context_t* self,
+ struct _cef_request_context_t* other) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: other; type: refptr_same
+ DCHECK(other);
+ if (!other) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefRequestContextCppToC::Get(self)->IsSharingWith(
+ CefRequestContextCppToC::Unwrap(other));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+request_context_is_global(struct _cef_request_context_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefRequestContextCppToC::Get(self)->IsGlobal();
+
+ // Return type: bool
+ return _retval;
+}
+
+struct _cef_request_context_handler_t* CEF_CALLBACK
+request_context_get_handler(struct _cef_request_context_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefRequestContextHandler> _retval =
+ CefRequestContextCppToC::Get(self)->GetHandler();
+
+ // Return type: refptr_diff
+ return CefRequestContextHandlerCToCpp::Unwrap(_retval);
+}
+
+cef_string_userfree_t CEF_CALLBACK
+request_context_get_cache_path(struct _cef_request_context_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefRequestContextCppToC::Get(self)->GetCachePath();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_cookie_manager_t* CEF_CALLBACK
+request_context_get_cookie_manager(struct _cef_request_context_t* self,
+ cef_completion_callback_t* callback) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+ // Unverified params: callback
+
+ // Execute
+ CefRefPtr<CefCookieManager> _retval =
+ CefRequestContextCppToC::Get(self)->GetCookieManager(
+ CefCompletionCallbackCToCpp::Wrap(callback));
+
+ // Return type: refptr_same
+ return CefCookieManagerCppToC::Wrap(_retval);
+}
+
+int CEF_CALLBACK request_context_register_scheme_handler_factory(
+ struct _cef_request_context_t* self,
+ const cef_string_t* scheme_name,
+ const cef_string_t* domain_name,
+ struct _cef_scheme_handler_factory_t* factory) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: scheme_name; type: string_byref_const
+ DCHECK(scheme_name);
+ if (!scheme_name) {
+ return 0;
+ }
+ // Unverified params: domain_name, factory
+
+ // Execute
+ bool _retval =
+ CefRequestContextCppToC::Get(self)->RegisterSchemeHandlerFactory(
+ CefString(scheme_name), CefString(domain_name),
+ CefSchemeHandlerFactoryCToCpp::Wrap(factory));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK request_context_clear_scheme_handler_factories(
+ struct _cef_request_context_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefRequestContextCppToC::Get(self)->ClearSchemeHandlerFactories();
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK request_context_clear_certificate_exceptions(
+ struct _cef_request_context_t* self,
+ cef_completion_callback_t* callback) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Unverified params: callback
+
+ // Execute
+ CefRequestContextCppToC::Get(self)->ClearCertificateExceptions(
+ CefCompletionCallbackCToCpp::Wrap(callback));
+}
+
+void CEF_CALLBACK request_context_clear_http_auth_credentials(
+ struct _cef_request_context_t* self,
+ cef_completion_callback_t* callback) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Unverified params: callback
+
+ // Execute
+ CefRequestContextCppToC::Get(self)->ClearHttpAuthCredentials(
+ CefCompletionCallbackCToCpp::Wrap(callback));
+}
+
+void CEF_CALLBACK
+request_context_close_all_connections(struct _cef_request_context_t* self,
+ cef_completion_callback_t* callback) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Unverified params: callback
+
+ // Execute
+ CefRequestContextCppToC::Get(self)->CloseAllConnections(
+ CefCompletionCallbackCToCpp::Wrap(callback));
+}
+
+void CEF_CALLBACK
+request_context_resolve_host(struct _cef_request_context_t* self,
+ const cef_string_t* origin,
+ cef_resolve_callback_t* callback) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: origin; type: string_byref_const
+ DCHECK(origin);
+ if (!origin) {
+ return;
+ }
+ // Verify param: callback; type: refptr_diff
+ DCHECK(callback);
+ if (!callback) {
+ return;
+ }
+
+ // Execute
+ CefRequestContextCppToC::Get(self)->ResolveHost(
+ CefString(origin), CefResolveCallbackCToCpp::Wrap(callback));
+}
+
+void CEF_CALLBACK
+request_context_load_extension(struct _cef_request_context_t* self,
+ const cef_string_t* root_directory,
+ struct _cef_dictionary_value_t* manifest,
+ cef_extension_handler_t* handler) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: root_directory; type: string_byref_const
+ DCHECK(root_directory);
+ if (!root_directory) {
+ return;
+ }
+ // Unverified params: manifest, handler
+
+ // Execute
+ CefRequestContextCppToC::Get(self)->LoadExtension(
+ CefString(root_directory), CefDictionaryValueCppToC::Unwrap(manifest),
+ CefExtensionHandlerCToCpp::Wrap(handler));
+}
+
+int CEF_CALLBACK
+request_context_did_load_extension(struct _cef_request_context_t* self,
+ const cef_string_t* extension_id) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: extension_id; type: string_byref_const
+ DCHECK(extension_id);
+ if (!extension_id) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefRequestContextCppToC::Get(self)->DidLoadExtension(
+ CefString(extension_id));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+request_context_has_extension(struct _cef_request_context_t* self,
+ const cef_string_t* extension_id) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: extension_id; type: string_byref_const
+ DCHECK(extension_id);
+ if (!extension_id) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefRequestContextCppToC::Get(self)->HasExtension(CefString(extension_id));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+request_context_get_extensions(struct _cef_request_context_t* self,
+ cef_string_list_t extension_ids) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: extension_ids; type: string_vec_byref
+ DCHECK(extension_ids);
+ if (!extension_ids) {
+ return 0;
+ }
+
+ // Translate param: extension_ids; type: string_vec_byref
+ std::vector<CefString> extension_idsList;
+ transfer_string_list_contents(extension_ids, extension_idsList);
+
+ // Execute
+ bool _retval =
+ CefRequestContextCppToC::Get(self)->GetExtensions(extension_idsList);
+
+ // Restore param: extension_ids; type: string_vec_byref
+ cef_string_list_clear(extension_ids);
+ transfer_string_list_contents(extension_idsList, extension_ids);
+
+ // Return type: bool
+ return _retval;
+}
+
+cef_extension_t* CEF_CALLBACK
+request_context_get_extension(struct _cef_request_context_t* self,
+ const cef_string_t* extension_id) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+ // Verify param: extension_id; type: string_byref_const
+ DCHECK(extension_id);
+ if (!extension_id) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefExtension> _retval =
+ CefRequestContextCppToC::Get(self)->GetExtension(CefString(extension_id));
+
+ // Return type: refptr_same
+ return CefExtensionCppToC::Wrap(_retval);
+}
+
+cef_media_router_t* CEF_CALLBACK
+request_context_get_media_router(struct _cef_request_context_t* self,
+ cef_completion_callback_t* callback) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+ // Unverified params: callback
+
+ // Execute
+ CefRefPtr<CefMediaRouter> _retval =
+ CefRequestContextCppToC::Get(self)->GetMediaRouter(
+ CefCompletionCallbackCToCpp::Wrap(callback));
+
+ // Return type: refptr_same
+ return CefMediaRouterCppToC::Wrap(_retval);
+}
+
+int CEF_CALLBACK
+request_context_has_preference(struct _cef_preference_manager_t* self,
+ const cef_string_t* name) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: name; type: string_byref_const
+ DCHECK(name);
+ if (!name) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefRequestContextCppToC::Get(
+ reinterpret_cast<cef_request_context_t*>(self))
+ ->HasPreference(CefString(name));
+
+ // Return type: bool
+ return _retval;
+}
+
+struct _cef_value_t* CEF_CALLBACK
+request_context_get_preference(struct _cef_preference_manager_t* self,
+ const cef_string_t* name) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+ // Verify param: name; type: string_byref_const
+ DCHECK(name);
+ if (!name) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefValue> _retval =
+ CefRequestContextCppToC::Get(
+ reinterpret_cast<cef_request_context_t*>(self))
+ ->GetPreference(CefString(name));
+
+ // Return type: refptr_same
+ return CefValueCppToC::Wrap(_retval);
+}
+
+struct _cef_dictionary_value_t* CEF_CALLBACK
+request_context_get_all_preferences(struct _cef_preference_manager_t* self,
+ int include_defaults) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefDictionaryValue> _retval =
+ CefRequestContextCppToC::Get(
+ reinterpret_cast<cef_request_context_t*>(self))
+ ->GetAllPreferences(include_defaults ? true : false);
+
+ // Return type: refptr_same
+ return CefDictionaryValueCppToC::Wrap(_retval);
+}
+
+int CEF_CALLBACK
+request_context_can_set_preference(struct _cef_preference_manager_t* self,
+ const cef_string_t* name) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: name; type: string_byref_const
+ DCHECK(name);
+ if (!name) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefRequestContextCppToC::Get(
+ reinterpret_cast<cef_request_context_t*>(self))
+ ->CanSetPreference(CefString(name));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+request_context_set_preference(struct _cef_preference_manager_t* self,
+ const cef_string_t* name,
+ struct _cef_value_t* value,
+ cef_string_t* error) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: name; type: string_byref_const
+ DCHECK(name);
+ if (!name) {
+ return 0;
+ }
+ // Verify param: error; type: string_byref
+ DCHECK(error);
+ if (!error) {
+ return 0;
+ }
+ // Unverified params: value
+
+ // Translate param: error; type: string_byref
+ CefString errorStr(error);
+
+ // Execute
+ bool _retval = CefRequestContextCppToC::Get(
+ reinterpret_cast<cef_request_context_t*>(self))
+ ->SetPreference(CefString(name),
+ CefValueCppToC::Unwrap(value), errorStr);
+
+ // Return type: bool
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefRequestContextCppToC::CefRequestContextCppToC() {
+ GetStruct()->is_same = request_context_is_same;
+ GetStruct()->is_sharing_with = request_context_is_sharing_with;
+ GetStruct()->is_global = request_context_is_global;
+ GetStruct()->get_handler = request_context_get_handler;
+ GetStruct()->get_cache_path = request_context_get_cache_path;
+ GetStruct()->get_cookie_manager = request_context_get_cookie_manager;
+ GetStruct()->register_scheme_handler_factory =
+ request_context_register_scheme_handler_factory;
+ GetStruct()->clear_scheme_handler_factories =
+ request_context_clear_scheme_handler_factories;
+ GetStruct()->clear_certificate_exceptions =
+ request_context_clear_certificate_exceptions;
+ GetStruct()->clear_http_auth_credentials =
+ request_context_clear_http_auth_credentials;
+ GetStruct()->close_all_connections = request_context_close_all_connections;
+ GetStruct()->resolve_host = request_context_resolve_host;
+ GetStruct()->load_extension = request_context_load_extension;
+ GetStruct()->did_load_extension = request_context_did_load_extension;
+ GetStruct()->has_extension = request_context_has_extension;
+ GetStruct()->get_extensions = request_context_get_extensions;
+ GetStruct()->get_extension = request_context_get_extension;
+ GetStruct()->get_media_router = request_context_get_media_router;
+ GetStruct()->base.has_preference = request_context_has_preference;
+ GetStruct()->base.get_preference = request_context_get_preference;
+ GetStruct()->base.get_all_preferences = request_context_get_all_preferences;
+ GetStruct()->base.can_set_preference = request_context_can_set_preference;
+ GetStruct()->base.set_preference = request_context_set_preference;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefRequestContextCppToC::~CefRequestContextCppToC() {}
+
+template <>
+CefRefPtr<CefRequestContext> CefCppToCRefCounted<
+ CefRequestContextCppToC,
+ CefRequestContext,
+ cef_request_context_t>::UnwrapDerived(CefWrapperType type,
+ cef_request_context_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefRequestContextCppToC,
+ CefRequestContext,
+ cef_request_context_t>::kWrapperType =
+ WT_REQUEST_CONTEXT;
diff --git a/libcef_dll/cpptoc/request_context_cpptoc.h b/libcef_dll/cpptoc/request_context_cpptoc.h
new file mode 100644
index 00000000..f798fefb
--- /dev/null
+++ b/libcef_dll/cpptoc/request_context_cpptoc.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=07ccff0f6993fe1634467a76d9996081fca0ec3a$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_REQUEST_CONTEXT_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_REQUEST_CONTEXT_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_request_context_capi.h"
+#include "include/capi/cef_request_context_handler_capi.h"
+#include "include/capi/cef_scheme_capi.h"
+#include "include/cef_request_context.h"
+#include "include/cef_request_context_handler.h"
+#include "include/cef_scheme.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefRequestContextCppToC
+ : public CefCppToCRefCounted<CefRequestContextCppToC,
+ CefRequestContext,
+ cef_request_context_t> {
+ public:
+ CefRequestContextCppToC();
+ virtual ~CefRequestContextCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_REQUEST_CONTEXT_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/request_context_handler_cpptoc.cc b/libcef_dll/cpptoc/request_context_handler_cpptoc.cc
new file mode 100644
index 00000000..70bc2c03
--- /dev/null
+++ b/libcef_dll/cpptoc/request_context_handler_cpptoc.cc
@@ -0,0 +1,126 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=ed44d7498b80c75957e24cc2baa879d9bda691f3$
+//
+
+#include "libcef_dll/cpptoc/request_context_handler_cpptoc.h"
+#include "libcef_dll/cpptoc/resource_request_handler_cpptoc.h"
+#include "libcef_dll/ctocpp/browser_ctocpp.h"
+#include "libcef_dll/ctocpp/frame_ctocpp.h"
+#include "libcef_dll/ctocpp/request_context_ctocpp.h"
+#include "libcef_dll/ctocpp/request_ctocpp.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK request_context_handler_on_request_context_initialized(
+ struct _cef_request_context_handler_t* self,
+ cef_request_context_t* request_context) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: request_context; type: refptr_diff
+ DCHECK(request_context);
+ if (!request_context) {
+ return;
+ }
+
+ // Execute
+ CefRequestContextHandlerCppToC::Get(self)->OnRequestContextInitialized(
+ CefRequestContextCToCpp::Wrap(request_context));
+}
+
+struct _cef_resource_request_handler_t* CEF_CALLBACK
+request_context_handler_get_resource_request_handler(
+ struct _cef_request_context_handler_t* self,
+ cef_browser_t* browser,
+ cef_frame_t* frame,
+ cef_request_t* request,
+ int is_navigation,
+ int is_download,
+ const cef_string_t* request_initiator,
+ int* disable_default_handling) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+ // Verify param: request; type: refptr_diff
+ DCHECK(request);
+ if (!request) {
+ return NULL;
+ }
+ // Verify param: disable_default_handling; type: bool_byref
+ DCHECK(disable_default_handling);
+ if (!disable_default_handling) {
+ return NULL;
+ }
+ // Unverified params: browser, frame, request_initiator
+
+ // Translate param: disable_default_handling; type: bool_byref
+ bool disable_default_handlingBool =
+ (disable_default_handling && *disable_default_handling) ? true : false;
+
+ // Execute
+ CefRefPtr<CefResourceRequestHandler> _retval =
+ CefRequestContextHandlerCppToC::Get(self)->GetResourceRequestHandler(
+ CefBrowserCToCpp::Wrap(browser), CefFrameCToCpp::Wrap(frame),
+ CefRequestCToCpp::Wrap(request), is_navigation ? true : false,
+ is_download ? true : false, CefString(request_initiator),
+ disable_default_handlingBool);
+
+ // Restore param: disable_default_handling; type: bool_byref
+ if (disable_default_handling) {
+ *disable_default_handling = disable_default_handlingBool ? true : false;
+ }
+
+ // Return type: refptr_same
+ return CefResourceRequestHandlerCppToC::Wrap(_retval);
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefRequestContextHandlerCppToC::CefRequestContextHandlerCppToC() {
+ GetStruct()->on_request_context_initialized =
+ request_context_handler_on_request_context_initialized;
+ GetStruct()->get_resource_request_handler =
+ request_context_handler_get_resource_request_handler;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefRequestContextHandlerCppToC::~CefRequestContextHandlerCppToC() {}
+
+template <>
+CefRefPtr<CefRequestContextHandler> CefCppToCRefCounted<
+ CefRequestContextHandlerCppToC,
+ CefRequestContextHandler,
+ cef_request_context_handler_t>::UnwrapDerived(CefWrapperType type,
+ cef_request_context_handler_t*
+ s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCppToCRefCounted<CefRequestContextHandlerCppToC,
+ CefRequestContextHandler,
+ cef_request_context_handler_t>::kWrapperType =
+ WT_REQUEST_CONTEXT_HANDLER;
diff --git a/libcef_dll/cpptoc/request_context_handler_cpptoc.h b/libcef_dll/cpptoc/request_context_handler_cpptoc.h
new file mode 100644
index 00000000..7a002b95
--- /dev/null
+++ b/libcef_dll/cpptoc/request_context_handler_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=0985ec29d8f7825abf5542f7bff3a0477431fc1a$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_REQUEST_CONTEXT_HANDLER_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_REQUEST_CONTEXT_HANDLER_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_request_context_handler_capi.h"
+#include "include/cef_request_context_handler.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefRequestContextHandlerCppToC
+ : public CefCppToCRefCounted<CefRequestContextHandlerCppToC,
+ CefRequestContextHandler,
+ cef_request_context_handler_t> {
+ public:
+ CefRequestContextHandlerCppToC();
+ virtual ~CefRequestContextHandlerCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_REQUEST_CONTEXT_HANDLER_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/request_cpptoc.cc b/libcef_dll/cpptoc/request_cpptoc.cc
new file mode 100644
index 00000000..aa91a8dd
--- /dev/null
+++ b/libcef_dll/cpptoc/request_cpptoc.cc
@@ -0,0 +1,484 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=64b21283c46b80ddd854c073ed2bc30e65b0d543$
+//
+
+#include "libcef_dll/cpptoc/request_cpptoc.h"
+#include "libcef_dll/cpptoc/post_data_cpptoc.h"
+#include "libcef_dll/transfer_util.h"
+
+// GLOBAL FUNCTIONS - Body may be edited by hand.
+
+CEF_EXPORT cef_request_t* cef_request_create() {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ CefRefPtr<CefRequest> _retval = CefRequest::Create();
+
+ // Return type: refptr_same
+ return CefRequestCppToC::Wrap(_retval);
+}
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK request_is_read_only(struct _cef_request_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefRequestCppToC::Get(self)->IsReadOnly();
+
+ // Return type: bool
+ return _retval;
+}
+
+cef_string_userfree_t CEF_CALLBACK
+request_get_url(struct _cef_request_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefRequestCppToC::Get(self)->GetURL();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+void CEF_CALLBACK request_set_url(struct _cef_request_t* self,
+ const cef_string_t* url) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: url; type: string_byref_const
+ DCHECK(url);
+ if (!url) {
+ return;
+ }
+
+ // Execute
+ CefRequestCppToC::Get(self)->SetURL(CefString(url));
+}
+
+cef_string_userfree_t CEF_CALLBACK
+request_get_method(struct _cef_request_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefRequestCppToC::Get(self)->GetMethod();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+void CEF_CALLBACK request_set_method(struct _cef_request_t* self,
+ const cef_string_t* method) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: method; type: string_byref_const
+ DCHECK(method);
+ if (!method) {
+ return;
+ }
+
+ // Execute
+ CefRequestCppToC::Get(self)->SetMethod(CefString(method));
+}
+
+void CEF_CALLBACK request_set_referrer(struct _cef_request_t* self,
+ const cef_string_t* referrer_url,
+ cef_referrer_policy_t policy) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Unverified params: referrer_url
+
+ // Execute
+ CefRequestCppToC::Get(self)->SetReferrer(CefString(referrer_url), policy);
+}
+
+cef_string_userfree_t CEF_CALLBACK
+request_get_referrer_url(struct _cef_request_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefRequestCppToC::Get(self)->GetReferrerURL();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_referrer_policy_t CEF_CALLBACK
+request_get_referrer_policy(struct _cef_request_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return REFERRER_POLICY_DEFAULT;
+ }
+
+ // Execute
+ cef_referrer_policy_t _retval =
+ CefRequestCppToC::Get(self)->GetReferrerPolicy();
+
+ // Return type: simple
+ return _retval;
+}
+
+struct _cef_post_data_t* CEF_CALLBACK
+request_get_post_data(struct _cef_request_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefPostData> _retval = CefRequestCppToC::Get(self)->GetPostData();
+
+ // Return type: refptr_same
+ return CefPostDataCppToC::Wrap(_retval);
+}
+
+void CEF_CALLBACK request_set_post_data(struct _cef_request_t* self,
+ struct _cef_post_data_t* postData) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: postData; type: refptr_same
+ DCHECK(postData);
+ if (!postData) {
+ return;
+ }
+
+ // Execute
+ CefRequestCppToC::Get(self)->SetPostData(CefPostDataCppToC::Unwrap(postData));
+}
+
+void CEF_CALLBACK request_get_header_map(struct _cef_request_t* self,
+ cef_string_multimap_t headerMap) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: headerMap; type: string_map_multi_byref
+ DCHECK(headerMap);
+ if (!headerMap) {
+ return;
+ }
+
+ // Translate param: headerMap; type: string_map_multi_byref
+ std::multimap<CefString, CefString> headerMapMultimap;
+ transfer_string_multimap_contents(headerMap, headerMapMultimap);
+
+ // Execute
+ CefRequestCppToC::Get(self)->GetHeaderMap(headerMapMultimap);
+
+ // Restore param: headerMap; type: string_map_multi_byref
+ cef_string_multimap_clear(headerMap);
+ transfer_string_multimap_contents(headerMapMultimap, headerMap);
+}
+
+void CEF_CALLBACK request_set_header_map(struct _cef_request_t* self,
+ cef_string_multimap_t headerMap) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: headerMap; type: string_map_multi_byref_const
+ DCHECK(headerMap);
+ if (!headerMap) {
+ return;
+ }
+
+ // Translate param: headerMap; type: string_map_multi_byref_const
+ std::multimap<CefString, CefString> headerMapMultimap;
+ transfer_string_multimap_contents(headerMap, headerMapMultimap);
+
+ // Execute
+ CefRequestCppToC::Get(self)->SetHeaderMap(headerMapMultimap);
+}
+
+cef_string_userfree_t CEF_CALLBACK
+request_get_header_by_name(struct _cef_request_t* self,
+ const cef_string_t* name) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+ // Verify param: name; type: string_byref_const
+ DCHECK(name);
+ if (!name) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval =
+ CefRequestCppToC::Get(self)->GetHeaderByName(CefString(name));
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+void CEF_CALLBACK request_set_header_by_name(struct _cef_request_t* self,
+ const cef_string_t* name,
+ const cef_string_t* value,
+ int overwrite) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: name; type: string_byref_const
+ DCHECK(name);
+ if (!name) {
+ return;
+ }
+ // Unverified params: value
+
+ // Execute
+ CefRequestCppToC::Get(self)->SetHeaderByName(
+ CefString(name), CefString(value), overwrite ? true : false);
+}
+
+void CEF_CALLBACK request_set(struct _cef_request_t* self,
+ const cef_string_t* url,
+ const cef_string_t* method,
+ struct _cef_post_data_t* postData,
+ cef_string_multimap_t headerMap) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: url; type: string_byref_const
+ DCHECK(url);
+ if (!url) {
+ return;
+ }
+ // Verify param: method; type: string_byref_const
+ DCHECK(method);
+ if (!method) {
+ return;
+ }
+ // Verify param: headerMap; type: string_map_multi_byref_const
+ DCHECK(headerMap);
+ if (!headerMap) {
+ return;
+ }
+ // Unverified params: postData
+
+ // Translate param: headerMap; type: string_map_multi_byref_const
+ std::multimap<CefString, CefString> headerMapMultimap;
+ transfer_string_multimap_contents(headerMap, headerMapMultimap);
+
+ // Execute
+ CefRequestCppToC::Get(self)->Set(CefString(url), CefString(method),
+ CefPostDataCppToC::Unwrap(postData),
+ headerMapMultimap);
+}
+
+int CEF_CALLBACK request_get_flags(struct _cef_request_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return UR_FLAG_NONE;
+ }
+
+ // Execute
+ int _retval = CefRequestCppToC::Get(self)->GetFlags();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK request_set_flags(struct _cef_request_t* self, int flags) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefRequestCppToC::Get(self)->SetFlags(flags);
+}
+
+cef_string_userfree_t CEF_CALLBACK
+request_get_first_party_for_cookies(struct _cef_request_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefRequestCppToC::Get(self)->GetFirstPartyForCookies();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+void CEF_CALLBACK
+request_set_first_party_for_cookies(struct _cef_request_t* self,
+ const cef_string_t* url) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Unverified params: url
+
+ // Execute
+ CefRequestCppToC::Get(self)->SetFirstPartyForCookies(CefString(url));
+}
+
+cef_resource_type_t CEF_CALLBACK
+request_get_resource_type(struct _cef_request_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return RT_SUB_RESOURCE;
+ }
+
+ // Execute
+ cef_resource_type_t _retval = CefRequestCppToC::Get(self)->GetResourceType();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_transition_type_t CEF_CALLBACK
+request_get_transition_type(struct _cef_request_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return TT_EXPLICIT;
+ }
+
+ // Execute
+ cef_transition_type_t _retval =
+ CefRequestCppToC::Get(self)->GetTransitionType();
+
+ // Return type: simple
+ return _retval;
+}
+
+uint64 CEF_CALLBACK request_get_identifier(struct _cef_request_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ uint64 _retval = CefRequestCppToC::Get(self)->GetIdentifier();
+
+ // Return type: simple
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefRequestCppToC::CefRequestCppToC() {
+ GetStruct()->is_read_only = request_is_read_only;
+ GetStruct()->get_url = request_get_url;
+ GetStruct()->set_url = request_set_url;
+ GetStruct()->get_method = request_get_method;
+ GetStruct()->set_method = request_set_method;
+ GetStruct()->set_referrer = request_set_referrer;
+ GetStruct()->get_referrer_url = request_get_referrer_url;
+ GetStruct()->get_referrer_policy = request_get_referrer_policy;
+ GetStruct()->get_post_data = request_get_post_data;
+ GetStruct()->set_post_data = request_set_post_data;
+ GetStruct()->get_header_map = request_get_header_map;
+ GetStruct()->set_header_map = request_set_header_map;
+ GetStruct()->get_header_by_name = request_get_header_by_name;
+ GetStruct()->set_header_by_name = request_set_header_by_name;
+ GetStruct()->set = request_set;
+ GetStruct()->get_flags = request_get_flags;
+ GetStruct()->set_flags = request_set_flags;
+ GetStruct()->get_first_party_for_cookies =
+ request_get_first_party_for_cookies;
+ GetStruct()->set_first_party_for_cookies =
+ request_set_first_party_for_cookies;
+ GetStruct()->get_resource_type = request_get_resource_type;
+ GetStruct()->get_transition_type = request_get_transition_type;
+ GetStruct()->get_identifier = request_get_identifier;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefRequestCppToC::~CefRequestCppToC() {}
+
+template <>
+CefRefPtr<CefRequest>
+CefCppToCRefCounted<CefRequestCppToC, CefRequest, cef_request_t>::UnwrapDerived(
+ CefWrapperType type,
+ cef_request_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefRequestCppToC,
+ CefRequest,
+ cef_request_t>::kWrapperType = WT_REQUEST;
diff --git a/libcef_dll/cpptoc/request_cpptoc.h b/libcef_dll/cpptoc/request_cpptoc.h
new file mode 100644
index 00000000..723e1dec
--- /dev/null
+++ b/libcef_dll/cpptoc/request_cpptoc.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=406c30cba514a450568bc341a7facf5495ab58a5$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_REQUEST_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_REQUEST_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_request_capi.h"
+#include "include/cef_request.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefRequestCppToC
+ : public CefCppToCRefCounted<CefRequestCppToC, CefRequest, cef_request_t> {
+ public:
+ CefRequestCppToC();
+ virtual ~CefRequestCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_REQUEST_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/request_handler_cpptoc.cc b/libcef_dll/cpptoc/request_handler_cpptoc.cc
new file mode 100644
index 00000000..a35e2186
--- /dev/null
+++ b/libcef_dll/cpptoc/request_handler_cpptoc.cc
@@ -0,0 +1,433 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=bb63cba306af7d795935851813985fb8467c1245$
+//
+
+#include "libcef_dll/cpptoc/request_handler_cpptoc.h"
+#include "libcef_dll/cpptoc/resource_request_handler_cpptoc.h"
+#include "libcef_dll/ctocpp/auth_callback_ctocpp.h"
+#include "libcef_dll/ctocpp/browser_ctocpp.h"
+#include "libcef_dll/ctocpp/callback_ctocpp.h"
+#include "libcef_dll/ctocpp/frame_ctocpp.h"
+#include "libcef_dll/ctocpp/request_ctocpp.h"
+#include "libcef_dll/ctocpp/select_client_certificate_callback_ctocpp.h"
+#include "libcef_dll/ctocpp/sslinfo_ctocpp.h"
+#include "libcef_dll/ctocpp/x509certificate_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK
+request_handler_on_before_browse(struct _cef_request_handler_t* self,
+ cef_browser_t* browser,
+ cef_frame_t* frame,
+ cef_request_t* request,
+ int user_gesture,
+ int is_redirect) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return 0;
+ }
+ // Verify param: frame; type: refptr_diff
+ DCHECK(frame);
+ if (!frame) {
+ return 0;
+ }
+ // Verify param: request; type: refptr_diff
+ DCHECK(request);
+ if (!request) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefRequestHandlerCppToC::Get(self)->OnBeforeBrowse(
+ CefBrowserCToCpp::Wrap(browser), CefFrameCToCpp::Wrap(frame),
+ CefRequestCToCpp::Wrap(request), user_gesture ? true : false,
+ is_redirect ? true : false);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK request_handler_on_open_urlfrom_tab(
+ struct _cef_request_handler_t* self,
+ cef_browser_t* browser,
+ cef_frame_t* frame,
+ const cef_string_t* target_url,
+ cef_window_open_disposition_t target_disposition,
+ int user_gesture) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return 0;
+ }
+ // Verify param: frame; type: refptr_diff
+ DCHECK(frame);
+ if (!frame) {
+ return 0;
+ }
+ // Verify param: target_url; type: string_byref_const
+ DCHECK(target_url);
+ if (!target_url) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefRequestHandlerCppToC::Get(self)->OnOpenURLFromTab(
+ CefBrowserCToCpp::Wrap(browser), CefFrameCToCpp::Wrap(frame),
+ CefString(target_url), target_disposition, user_gesture ? true : false);
+
+ // Return type: bool
+ return _retval;
+}
+
+struct _cef_resource_request_handler_t* CEF_CALLBACK
+request_handler_get_resource_request_handler(
+ struct _cef_request_handler_t* self,
+ cef_browser_t* browser,
+ cef_frame_t* frame,
+ cef_request_t* request,
+ int is_navigation,
+ int is_download,
+ const cef_string_t* request_initiator,
+ int* disable_default_handling) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return NULL;
+ }
+ // Verify param: frame; type: refptr_diff
+ DCHECK(frame);
+ if (!frame) {
+ return NULL;
+ }
+ // Verify param: request; type: refptr_diff
+ DCHECK(request);
+ if (!request) {
+ return NULL;
+ }
+ // Verify param: disable_default_handling; type: bool_byref
+ DCHECK(disable_default_handling);
+ if (!disable_default_handling) {
+ return NULL;
+ }
+ // Unverified params: request_initiator
+
+ // Translate param: disable_default_handling; type: bool_byref
+ bool disable_default_handlingBool =
+ (disable_default_handling && *disable_default_handling) ? true : false;
+
+ // Execute
+ CefRefPtr<CefResourceRequestHandler> _retval =
+ CefRequestHandlerCppToC::Get(self)->GetResourceRequestHandler(
+ CefBrowserCToCpp::Wrap(browser), CefFrameCToCpp::Wrap(frame),
+ CefRequestCToCpp::Wrap(request), is_navigation ? true : false,
+ is_download ? true : false, CefString(request_initiator),
+ disable_default_handlingBool);
+
+ // Restore param: disable_default_handling; type: bool_byref
+ if (disable_default_handling) {
+ *disable_default_handling = disable_default_handlingBool ? true : false;
+ }
+
+ // Return type: refptr_same
+ return CefResourceRequestHandlerCppToC::Wrap(_retval);
+}
+
+int CEF_CALLBACK
+request_handler_get_auth_credentials(struct _cef_request_handler_t* self,
+ cef_browser_t* browser,
+ const cef_string_t* origin_url,
+ int isProxy,
+ const cef_string_t* host,
+ int port,
+ const cef_string_t* realm,
+ const cef_string_t* scheme,
+ cef_auth_callback_t* callback) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return 0;
+ }
+ // Verify param: origin_url; type: string_byref_const
+ DCHECK(origin_url);
+ if (!origin_url) {
+ return 0;
+ }
+ // Verify param: host; type: string_byref_const
+ DCHECK(host);
+ if (!host) {
+ return 0;
+ }
+ // Verify param: callback; type: refptr_diff
+ DCHECK(callback);
+ if (!callback) {
+ return 0;
+ }
+ // Unverified params: realm, scheme
+
+ // Execute
+ bool _retval = CefRequestHandlerCppToC::Get(self)->GetAuthCredentials(
+ CefBrowserCToCpp::Wrap(browser), CefString(origin_url),
+ isProxy ? true : false, CefString(host), port, CefString(realm),
+ CefString(scheme), CefAuthCallbackCToCpp::Wrap(callback));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+request_handler_on_certificate_error(struct _cef_request_handler_t* self,
+ cef_browser_t* browser,
+ cef_errorcode_t cert_error,
+ const cef_string_t* request_url,
+ struct _cef_sslinfo_t* ssl_info,
+ cef_callback_t* callback) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return 0;
+ }
+ // Verify param: request_url; type: string_byref_const
+ DCHECK(request_url);
+ if (!request_url) {
+ return 0;
+ }
+ // Verify param: ssl_info; type: refptr_diff
+ DCHECK(ssl_info);
+ if (!ssl_info) {
+ return 0;
+ }
+ // Verify param: callback; type: refptr_diff
+ DCHECK(callback);
+ if (!callback) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefRequestHandlerCppToC::Get(self)->OnCertificateError(
+ CefBrowserCToCpp::Wrap(browser), cert_error, CefString(request_url),
+ CefSSLInfoCToCpp::Wrap(ssl_info), CefCallbackCToCpp::Wrap(callback));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK request_handler_on_select_client_certificate(
+ struct _cef_request_handler_t* self,
+ cef_browser_t* browser,
+ int isProxy,
+ const cef_string_t* host,
+ int port,
+ size_t certificatesCount,
+ struct _cef_x509certificate_t* const* certificates,
+ cef_select_client_certificate_callback_t* callback) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return 0;
+ }
+ // Verify param: host; type: string_byref_const
+ DCHECK(host);
+ if (!host) {
+ return 0;
+ }
+ // Verify param: certificates; type: refptr_vec_diff_byref_const
+ DCHECK(certificatesCount == 0 || certificates);
+ if (certificatesCount > 0 && !certificates) {
+ return 0;
+ }
+ // Verify param: callback; type: refptr_diff
+ DCHECK(callback);
+ if (!callback) {
+ return 0;
+ }
+
+ // Translate param: certificates; type: refptr_vec_diff_byref_const
+ std::vector<CefRefPtr<CefX509Certificate>> certificatesList;
+ if (certificatesCount > 0) {
+ for (size_t i = 0; i < certificatesCount; ++i) {
+ CefRefPtr<CefX509Certificate> certificatesVal =
+ CefX509CertificateCToCpp::Wrap(certificates[i]);
+ certificatesList.push_back(certificatesVal);
+ }
+ }
+
+ // Execute
+ bool _retval = CefRequestHandlerCppToC::Get(self)->OnSelectClientCertificate(
+ CefBrowserCToCpp::Wrap(browser), isProxy ? true : false, CefString(host),
+ port, certificatesList,
+ CefSelectClientCertificateCallbackCToCpp::Wrap(callback));
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK
+request_handler_on_render_view_ready(struct _cef_request_handler_t* self,
+ cef_browser_t* browser) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+
+ // Execute
+ CefRequestHandlerCppToC::Get(self)->OnRenderViewReady(
+ CefBrowserCToCpp::Wrap(browser));
+}
+
+void CEF_CALLBACK request_handler_on_render_process_terminated(
+ struct _cef_request_handler_t* self,
+ cef_browser_t* browser,
+ cef_termination_status_t status) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+
+ // Execute
+ CefRequestHandlerCppToC::Get(self)->OnRenderProcessTerminated(
+ CefBrowserCToCpp::Wrap(browser), status);
+}
+
+void CEF_CALLBACK request_handler_on_document_available_in_main_frame(
+ struct _cef_request_handler_t* self,
+ cef_browser_t* browser) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+
+ // Execute
+ CefRequestHandlerCppToC::Get(self)->OnDocumentAvailableInMainFrame(
+ CefBrowserCToCpp::Wrap(browser));
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefRequestHandlerCppToC::CefRequestHandlerCppToC() {
+ GetStruct()->on_before_browse = request_handler_on_before_browse;
+ GetStruct()->on_open_urlfrom_tab = request_handler_on_open_urlfrom_tab;
+ GetStruct()->get_resource_request_handler =
+ request_handler_get_resource_request_handler;
+ GetStruct()->get_auth_credentials = request_handler_get_auth_credentials;
+ GetStruct()->on_certificate_error = request_handler_on_certificate_error;
+ GetStruct()->on_select_client_certificate =
+ request_handler_on_select_client_certificate;
+ GetStruct()->on_render_view_ready = request_handler_on_render_view_ready;
+ GetStruct()->on_render_process_terminated =
+ request_handler_on_render_process_terminated;
+ GetStruct()->on_document_available_in_main_frame =
+ request_handler_on_document_available_in_main_frame;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefRequestHandlerCppToC::~CefRequestHandlerCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefRequestHandler> CefCppToCRefCounted<
+ CefRequestHandlerCppToC,
+ CefRequestHandler,
+ cef_request_handler_t>::UnwrapDerived(CefWrapperType type,
+ cef_request_handler_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefRequestHandlerCppToC,
+ CefRequestHandler,
+ cef_request_handler_t>::kWrapperType =
+ WT_REQUEST_HANDLER;
diff --git a/libcef_dll/cpptoc/request_handler_cpptoc.h b/libcef_dll/cpptoc/request_handler_cpptoc.h
new file mode 100644
index 00000000..73ff5d4c
--- /dev/null
+++ b/libcef_dll/cpptoc/request_handler_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=0167d427e72426d439b11b2655caac2b79a7b8de$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_REQUEST_HANDLER_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_REQUEST_HANDLER_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_request_handler_capi.h"
+#include "include/cef_request_handler.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefRequestHandlerCppToC
+ : public CefCppToCRefCounted<CefRequestHandlerCppToC,
+ CefRequestHandler,
+ cef_request_handler_t> {
+ public:
+ CefRequestHandlerCppToC();
+ virtual ~CefRequestHandlerCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_REQUEST_HANDLER_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/resolve_callback_cpptoc.cc b/libcef_dll/cpptoc/resolve_callback_cpptoc.cc
new file mode 100644
index 00000000..0db23f39
--- /dev/null
+++ b/libcef_dll/cpptoc/resolve_callback_cpptoc.cc
@@ -0,0 +1,74 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=b9b5047524de83c24a2911a83b1cb48fc472774a$
+//
+
+#include "libcef_dll/cpptoc/resolve_callback_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+#include "libcef_dll/transfer_util.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK
+resolve_callback_on_resolve_completed(struct _cef_resolve_callback_t* self,
+ cef_errorcode_t result,
+ cef_string_list_t resolved_ips) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Unverified params: resolved_ips
+
+ // Translate param: resolved_ips; type: string_vec_byref_const
+ std::vector<CefString> resolved_ipsList;
+ transfer_string_list_contents(resolved_ips, resolved_ipsList);
+
+ // Execute
+ CefResolveCallbackCppToC::Get(self)->OnResolveCompleted(result,
+ resolved_ipsList);
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefResolveCallbackCppToC::CefResolveCallbackCppToC() {
+ GetStruct()->on_resolve_completed = resolve_callback_on_resolve_completed;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefResolveCallbackCppToC::~CefResolveCallbackCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefResolveCallback> CefCppToCRefCounted<
+ CefResolveCallbackCppToC,
+ CefResolveCallback,
+ cef_resolve_callback_t>::UnwrapDerived(CefWrapperType type,
+ cef_resolve_callback_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefResolveCallbackCppToC,
+ CefResolveCallback,
+ cef_resolve_callback_t>::kWrapperType =
+ WT_RESOLVE_CALLBACK;
diff --git a/libcef_dll/cpptoc/resolve_callback_cpptoc.h b/libcef_dll/cpptoc/resolve_callback_cpptoc.h
new file mode 100644
index 00000000..cd35ce3d
--- /dev/null
+++ b/libcef_dll/cpptoc/resolve_callback_cpptoc.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=aea5c318f99d23b06478b765f81720890aa098b3$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_RESOLVE_CALLBACK_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_RESOLVE_CALLBACK_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_request_context_capi.h"
+#include "include/capi/cef_request_context_handler_capi.h"
+#include "include/capi/cef_scheme_capi.h"
+#include "include/cef_request_context.h"
+#include "include/cef_request_context_handler.h"
+#include "include/cef_scheme.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefResolveCallbackCppToC
+ : public CefCppToCRefCounted<CefResolveCallbackCppToC,
+ CefResolveCallback,
+ cef_resolve_callback_t> {
+ public:
+ CefResolveCallbackCppToC();
+ virtual ~CefResolveCallbackCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_RESOLVE_CALLBACK_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/resource_bundle_cpptoc.cc b/libcef_dll/cpptoc/resource_bundle_cpptoc.cc
new file mode 100644
index 00000000..bf2b0daa
--- /dev/null
+++ b/libcef_dll/cpptoc/resource_bundle_cpptoc.cc
@@ -0,0 +1,119 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=8ef82c13bcb073b2cd97ef38d79d47478d1eddec$
+//
+
+#include "libcef_dll/cpptoc/resource_bundle_cpptoc.h"
+#include "libcef_dll/cpptoc/binary_value_cpptoc.h"
+
+// GLOBAL FUNCTIONS - Body may be edited by hand.
+
+CEF_EXPORT cef_resource_bundle_t* cef_resource_bundle_get_global() {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ CefRefPtr<CefResourceBundle> _retval = CefResourceBundle::GetGlobal();
+
+ // Return type: refptr_same
+ return CefResourceBundleCppToC::Wrap(_retval);
+}
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+cef_string_userfree_t CEF_CALLBACK
+resource_bundle_get_localized_string(struct _cef_resource_bundle_t* self,
+ int string_id) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval =
+ CefResourceBundleCppToC::Get(self)->GetLocalizedString(string_id);
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+struct _cef_binary_value_t* CEF_CALLBACK
+resource_bundle_get_data_resource(struct _cef_resource_bundle_t* self,
+ int resource_id) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefBinaryValue> _retval =
+ CefResourceBundleCppToC::Get(self)->GetDataResource(resource_id);
+
+ // Return type: refptr_same
+ return CefBinaryValueCppToC::Wrap(_retval);
+}
+
+struct _cef_binary_value_t* CEF_CALLBACK
+resource_bundle_get_data_resource_for_scale(struct _cef_resource_bundle_t* self,
+ int resource_id,
+ cef_scale_factor_t scale_factor) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefBinaryValue> _retval =
+ CefResourceBundleCppToC::Get(self)->GetDataResourceForScale(resource_id,
+ scale_factor);
+
+ // Return type: refptr_same
+ return CefBinaryValueCppToC::Wrap(_retval);
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefResourceBundleCppToC::CefResourceBundleCppToC() {
+ GetStruct()->get_localized_string = resource_bundle_get_localized_string;
+ GetStruct()->get_data_resource = resource_bundle_get_data_resource;
+ GetStruct()->get_data_resource_for_scale =
+ resource_bundle_get_data_resource_for_scale;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefResourceBundleCppToC::~CefResourceBundleCppToC() {}
+
+template <>
+CefRefPtr<CefResourceBundle> CefCppToCRefCounted<
+ CefResourceBundleCppToC,
+ CefResourceBundle,
+ cef_resource_bundle_t>::UnwrapDerived(CefWrapperType type,
+ cef_resource_bundle_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefResourceBundleCppToC,
+ CefResourceBundle,
+ cef_resource_bundle_t>::kWrapperType =
+ WT_RESOURCE_BUNDLE;
diff --git a/libcef_dll/cpptoc/resource_bundle_cpptoc.h b/libcef_dll/cpptoc/resource_bundle_cpptoc.h
new file mode 100644
index 00000000..8102bff0
--- /dev/null
+++ b/libcef_dll/cpptoc/resource_bundle_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=c126e6379765b577e7251c418bd3fe4dbe392522$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_RESOURCE_BUNDLE_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_RESOURCE_BUNDLE_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_resource_bundle_capi.h"
+#include "include/cef_resource_bundle.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefResourceBundleCppToC
+ : public CefCppToCRefCounted<CefResourceBundleCppToC,
+ CefResourceBundle,
+ cef_resource_bundle_t> {
+ public:
+ CefResourceBundleCppToC();
+ virtual ~CefResourceBundleCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_RESOURCE_BUNDLE_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/resource_bundle_handler_cpptoc.cc b/libcef_dll/cpptoc/resource_bundle_handler_cpptoc.cc
new file mode 100644
index 00000000..8eb668d7
--- /dev/null
+++ b/libcef_dll/cpptoc/resource_bundle_handler_cpptoc.cc
@@ -0,0 +1,179 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=9fed784c5de6718569cc5c0828a1856831148146$
+//
+
+#include "libcef_dll/cpptoc/resource_bundle_handler_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK resource_bundle_handler_get_localized_string(
+ struct _cef_resource_bundle_handler_t* self,
+ int string_id,
+ cef_string_t* string) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: string; type: string_byref
+ DCHECK(string);
+ if (!string) {
+ return 0;
+ }
+
+ // Translate param: string; type: string_byref
+ CefString stringStr(string);
+
+ // Execute
+ bool _retval = CefResourceBundleHandlerCppToC::Get(self)->GetLocalizedString(
+ string_id, stringStr);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK resource_bundle_handler_get_data_resource(
+ struct _cef_resource_bundle_handler_t* self,
+ int resource_id,
+ void** data,
+ size_t* data_size) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: data; type: simple_byref
+ DCHECK(data);
+ if (!data) {
+ return 0;
+ }
+ // Verify param: data_size; type: simple_byref
+ DCHECK(data_size);
+ if (!data_size) {
+ return 0;
+ }
+
+ // Translate param: data; type: simple_byref
+ void* dataVal = data ? *data : NULL;
+ // Translate param: data_size; type: simple_byref
+ size_t data_sizeVal = data_size ? *data_size : 0;
+
+ // Execute
+ bool _retval = CefResourceBundleHandlerCppToC::Get(self)->GetDataResource(
+ resource_id, dataVal, data_sizeVal);
+
+ // Restore param: data; type: simple_byref
+ if (data) {
+ *data = dataVal;
+ }
+ // Restore param: data_size; type: simple_byref
+ if (data_size) {
+ *data_size = data_sizeVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK resource_bundle_handler_get_data_resource_for_scale(
+ struct _cef_resource_bundle_handler_t* self,
+ int resource_id,
+ cef_scale_factor_t scale_factor,
+ void** data,
+ size_t* data_size) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: data; type: simple_byref
+ DCHECK(data);
+ if (!data) {
+ return 0;
+ }
+ // Verify param: data_size; type: simple_byref
+ DCHECK(data_size);
+ if (!data_size) {
+ return 0;
+ }
+
+ // Translate param: data; type: simple_byref
+ void* dataVal = data ? *data : NULL;
+ // Translate param: data_size; type: simple_byref
+ size_t data_sizeVal = data_size ? *data_size : 0;
+
+ // Execute
+ bool _retval =
+ CefResourceBundleHandlerCppToC::Get(self)->GetDataResourceForScale(
+ resource_id, scale_factor, dataVal, data_sizeVal);
+
+ // Restore param: data; type: simple_byref
+ if (data) {
+ *data = dataVal;
+ }
+ // Restore param: data_size; type: simple_byref
+ if (data_size) {
+ *data_size = data_sizeVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefResourceBundleHandlerCppToC::CefResourceBundleHandlerCppToC() {
+ GetStruct()->get_localized_string =
+ resource_bundle_handler_get_localized_string;
+ GetStruct()->get_data_resource = resource_bundle_handler_get_data_resource;
+ GetStruct()->get_data_resource_for_scale =
+ resource_bundle_handler_get_data_resource_for_scale;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefResourceBundleHandlerCppToC::~CefResourceBundleHandlerCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefResourceBundleHandler> CefCppToCRefCounted<
+ CefResourceBundleHandlerCppToC,
+ CefResourceBundleHandler,
+ cef_resource_bundle_handler_t>::UnwrapDerived(CefWrapperType type,
+ cef_resource_bundle_handler_t*
+ s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCppToCRefCounted<CefResourceBundleHandlerCppToC,
+ CefResourceBundleHandler,
+ cef_resource_bundle_handler_t>::kWrapperType =
+ WT_RESOURCE_BUNDLE_HANDLER;
diff --git a/libcef_dll/cpptoc/resource_bundle_handler_cpptoc.h b/libcef_dll/cpptoc/resource_bundle_handler_cpptoc.h
new file mode 100644
index 00000000..3b74d914
--- /dev/null
+++ b/libcef_dll/cpptoc/resource_bundle_handler_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=f6e9e2a12912ea7b9ab5060481e323c180698725$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_RESOURCE_BUNDLE_HANDLER_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_RESOURCE_BUNDLE_HANDLER_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_resource_bundle_handler_capi.h"
+#include "include/cef_resource_bundle_handler.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefResourceBundleHandlerCppToC
+ : public CefCppToCRefCounted<CefResourceBundleHandlerCppToC,
+ CefResourceBundleHandler,
+ cef_resource_bundle_handler_t> {
+ public:
+ CefResourceBundleHandlerCppToC();
+ virtual ~CefResourceBundleHandlerCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_RESOURCE_BUNDLE_HANDLER_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/resource_handler_cpptoc.cc b/libcef_dll/cpptoc/resource_handler_cpptoc.cc
new file mode 100644
index 00000000..c0043ac5
--- /dev/null
+++ b/libcef_dll/cpptoc/resource_handler_cpptoc.cc
@@ -0,0 +1,329 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=5a00cba2b704ea26cf404ca0aab08be98ce08154$
+//
+
+#include "libcef_dll/cpptoc/resource_handler_cpptoc.h"
+#include "libcef_dll/ctocpp/callback_ctocpp.h"
+#include "libcef_dll/ctocpp/request_ctocpp.h"
+#include "libcef_dll/ctocpp/resource_read_callback_ctocpp.h"
+#include "libcef_dll/ctocpp/resource_skip_callback_ctocpp.h"
+#include "libcef_dll/ctocpp/response_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK resource_handler_open(struct _cef_resource_handler_t* self,
+ cef_request_t* request,
+ int* handle_request,
+ cef_callback_t* callback) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: request; type: refptr_diff
+ DCHECK(request);
+ if (!request) {
+ return 0;
+ }
+ // Verify param: handle_request; type: bool_byref
+ DCHECK(handle_request);
+ if (!handle_request) {
+ return 0;
+ }
+ // Verify param: callback; type: refptr_diff
+ DCHECK(callback);
+ if (!callback) {
+ return 0;
+ }
+
+ // Translate param: handle_request; type: bool_byref
+ bool handle_requestBool = (handle_request && *handle_request) ? true : false;
+
+ // Execute
+ bool _retval = CefResourceHandlerCppToC::Get(self)->Open(
+ CefRequestCToCpp::Wrap(request), handle_requestBool,
+ CefCallbackCToCpp::Wrap(callback));
+
+ // Restore param: handle_request; type: bool_byref
+ if (handle_request) {
+ *handle_request = handle_requestBool ? true : false;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+resource_handler_process_request(struct _cef_resource_handler_t* self,
+ cef_request_t* request,
+ cef_callback_t* callback) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: request; type: refptr_diff
+ DCHECK(request);
+ if (!request) {
+ return 0;
+ }
+ // Verify param: callback; type: refptr_diff
+ DCHECK(callback);
+ if (!callback) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefResourceHandlerCppToC::Get(self)->ProcessRequest(
+ CefRequestCToCpp::Wrap(request), CefCallbackCToCpp::Wrap(callback));
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK
+resource_handler_get_response_headers(struct _cef_resource_handler_t* self,
+ struct _cef_response_t* response,
+ int64* response_length,
+ cef_string_t* redirectUrl) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: response; type: refptr_diff
+ DCHECK(response);
+ if (!response) {
+ return;
+ }
+ // Verify param: response_length; type: simple_byref
+ DCHECK(response_length);
+ if (!response_length) {
+ return;
+ }
+ // Verify param: redirectUrl; type: string_byref
+ DCHECK(redirectUrl);
+ if (!redirectUrl) {
+ return;
+ }
+
+ // Translate param: response_length; type: simple_byref
+ int64 response_lengthVal = response_length ? *response_length : 0;
+ // Translate param: redirectUrl; type: string_byref
+ CefString redirectUrlStr(redirectUrl);
+
+ // Execute
+ CefResourceHandlerCppToC::Get(self)->GetResponseHeaders(
+ CefResponseCToCpp::Wrap(response), response_lengthVal, redirectUrlStr);
+
+ // Restore param: response_length; type: simple_byref
+ if (response_length) {
+ *response_length = response_lengthVal;
+ }
+}
+
+int CEF_CALLBACK resource_handler_skip(struct _cef_resource_handler_t* self,
+ int64 bytes_to_skip,
+ int64* bytes_skipped,
+ cef_resource_skip_callback_t* callback) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: bytes_skipped; type: simple_byref
+ DCHECK(bytes_skipped);
+ if (!bytes_skipped) {
+ return 0;
+ }
+ // Verify param: callback; type: refptr_diff
+ DCHECK(callback);
+ if (!callback) {
+ return 0;
+ }
+
+ // Translate param: bytes_skipped; type: simple_byref
+ int64 bytes_skippedVal = bytes_skipped ? *bytes_skipped : 0;
+
+ // Execute
+ bool _retval = CefResourceHandlerCppToC::Get(self)->Skip(
+ bytes_to_skip, bytes_skippedVal,
+ CefResourceSkipCallbackCToCpp::Wrap(callback));
+
+ // Restore param: bytes_skipped; type: simple_byref
+ if (bytes_skipped) {
+ *bytes_skipped = bytes_skippedVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK resource_handler_read(struct _cef_resource_handler_t* self,
+ void* data_out,
+ int bytes_to_read,
+ int* bytes_read,
+ cef_resource_read_callback_t* callback) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: data_out; type: simple_byaddr
+ DCHECK(data_out);
+ if (!data_out) {
+ return 0;
+ }
+ // Verify param: bytes_read; type: simple_byref
+ DCHECK(bytes_read);
+ if (!bytes_read) {
+ return 0;
+ }
+ // Verify param: callback; type: refptr_diff
+ DCHECK(callback);
+ if (!callback) {
+ return 0;
+ }
+
+ // Translate param: bytes_read; type: simple_byref
+ int bytes_readVal = bytes_read ? *bytes_read : 0;
+
+ // Execute
+ bool _retval = CefResourceHandlerCppToC::Get(self)->Read(
+ data_out, bytes_to_read, bytes_readVal,
+ CefResourceReadCallbackCToCpp::Wrap(callback));
+
+ // Restore param: bytes_read; type: simple_byref
+ if (bytes_read) {
+ *bytes_read = bytes_readVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+resource_handler_read_response(struct _cef_resource_handler_t* self,
+ void* data_out,
+ int bytes_to_read,
+ int* bytes_read,
+ cef_callback_t* callback) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: data_out; type: simple_byaddr
+ DCHECK(data_out);
+ if (!data_out) {
+ return 0;
+ }
+ // Verify param: bytes_read; type: simple_byref
+ DCHECK(bytes_read);
+ if (!bytes_read) {
+ return 0;
+ }
+ // Verify param: callback; type: refptr_diff
+ DCHECK(callback);
+ if (!callback) {
+ return 0;
+ }
+
+ // Translate param: bytes_read; type: simple_byref
+ int bytes_readVal = bytes_read ? *bytes_read : 0;
+
+ // Execute
+ bool _retval = CefResourceHandlerCppToC::Get(self)->ReadResponse(
+ data_out, bytes_to_read, bytes_readVal,
+ CefCallbackCToCpp::Wrap(callback));
+
+ // Restore param: bytes_read; type: simple_byref
+ if (bytes_read) {
+ *bytes_read = bytes_readVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK
+resource_handler_cancel(struct _cef_resource_handler_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefResourceHandlerCppToC::Get(self)->Cancel();
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefResourceHandlerCppToC::CefResourceHandlerCppToC() {
+ GetStruct()->open = resource_handler_open;
+ GetStruct()->process_request = resource_handler_process_request;
+ GetStruct()->get_response_headers = resource_handler_get_response_headers;
+ GetStruct()->skip = resource_handler_skip;
+ GetStruct()->read = resource_handler_read;
+ GetStruct()->read_response = resource_handler_read_response;
+ GetStruct()->cancel = resource_handler_cancel;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefResourceHandlerCppToC::~CefResourceHandlerCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefResourceHandler> CefCppToCRefCounted<
+ CefResourceHandlerCppToC,
+ CefResourceHandler,
+ cef_resource_handler_t>::UnwrapDerived(CefWrapperType type,
+ cef_resource_handler_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefResourceHandlerCppToC,
+ CefResourceHandler,
+ cef_resource_handler_t>::kWrapperType =
+ WT_RESOURCE_HANDLER;
diff --git a/libcef_dll/cpptoc/resource_handler_cpptoc.h b/libcef_dll/cpptoc/resource_handler_cpptoc.h
new file mode 100644
index 00000000..fc57f647
--- /dev/null
+++ b/libcef_dll/cpptoc/resource_handler_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=3853a8b89137fdd6c71bc86f801536517bde7c88$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_RESOURCE_HANDLER_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_RESOURCE_HANDLER_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_resource_handler_capi.h"
+#include "include/cef_resource_handler.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefResourceHandlerCppToC
+ : public CefCppToCRefCounted<CefResourceHandlerCppToC,
+ CefResourceHandler,
+ cef_resource_handler_t> {
+ public:
+ CefResourceHandlerCppToC();
+ virtual ~CefResourceHandlerCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_RESOURCE_HANDLER_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/resource_read_callback_cpptoc.cc b/libcef_dll/cpptoc/resource_read_callback_cpptoc.cc
new file mode 100644
index 00000000..c337b8c3
--- /dev/null
+++ b/libcef_dll/cpptoc/resource_read_callback_cpptoc.cc
@@ -0,0 +1,67 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=38393598812c88b7e4a94371a374be0af454713f$
+//
+
+#include "libcef_dll/cpptoc/resource_read_callback_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK
+resource_read_callback_cont(struct _cef_resource_read_callback_t* self,
+ int bytes_read) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefResourceReadCallbackCppToC::Get(self)->Continue(bytes_read);
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefResourceReadCallbackCppToC::CefResourceReadCallbackCppToC() {
+ GetStruct()->cont = resource_read_callback_cont;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefResourceReadCallbackCppToC::~CefResourceReadCallbackCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefResourceReadCallback> CefCppToCRefCounted<
+ CefResourceReadCallbackCppToC,
+ CefResourceReadCallback,
+ cef_resource_read_callback_t>::UnwrapDerived(CefWrapperType type,
+ cef_resource_read_callback_t*
+ s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefResourceReadCallbackCppToC,
+ CefResourceReadCallback,
+ cef_resource_read_callback_t>::kWrapperType =
+ WT_RESOURCE_READ_CALLBACK;
diff --git a/libcef_dll/cpptoc/resource_read_callback_cpptoc.h b/libcef_dll/cpptoc/resource_read_callback_cpptoc.h
new file mode 100644
index 00000000..f152b5d2
--- /dev/null
+++ b/libcef_dll/cpptoc/resource_read_callback_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=f5efbaafb5a54dfb9deb422cf31a0908c8a4cfc3$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_RESOURCE_READ_CALLBACK_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_RESOURCE_READ_CALLBACK_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_resource_handler_capi.h"
+#include "include/cef_resource_handler.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefResourceReadCallbackCppToC
+ : public CefCppToCRefCounted<CefResourceReadCallbackCppToC,
+ CefResourceReadCallback,
+ cef_resource_read_callback_t> {
+ public:
+ CefResourceReadCallbackCppToC();
+ virtual ~CefResourceReadCallbackCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_RESOURCE_READ_CALLBACK_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/resource_request_handler_cpptoc.cc b/libcef_dll/cpptoc/resource_request_handler_cpptoc.cc
new file mode 100644
index 00000000..b6f9a995
--- /dev/null
+++ b/libcef_dll/cpptoc/resource_request_handler_cpptoc.cc
@@ -0,0 +1,344 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=ae437028fb869b3a569bb45d150cf772a309a1f2$
+//
+
+#include "libcef_dll/cpptoc/resource_request_handler_cpptoc.h"
+#include "libcef_dll/cpptoc/cookie_access_filter_cpptoc.h"
+#include "libcef_dll/cpptoc/resource_handler_cpptoc.h"
+#include "libcef_dll/cpptoc/response_filter_cpptoc.h"
+#include "libcef_dll/ctocpp/browser_ctocpp.h"
+#include "libcef_dll/ctocpp/callback_ctocpp.h"
+#include "libcef_dll/ctocpp/frame_ctocpp.h"
+#include "libcef_dll/ctocpp/request_ctocpp.h"
+#include "libcef_dll/ctocpp/response_ctocpp.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+struct _cef_cookie_access_filter_t* CEF_CALLBACK
+resource_request_handler_get_cookie_access_filter(
+ struct _cef_resource_request_handler_t* self,
+ cef_browser_t* browser,
+ cef_frame_t* frame,
+ cef_request_t* request) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+ // Verify param: request; type: refptr_diff
+ DCHECK(request);
+ if (!request) {
+ return NULL;
+ }
+ // Unverified params: browser, frame
+
+ // Execute
+ CefRefPtr<CefCookieAccessFilter> _retval =
+ CefResourceRequestHandlerCppToC::Get(self)->GetCookieAccessFilter(
+ CefBrowserCToCpp::Wrap(browser), CefFrameCToCpp::Wrap(frame),
+ CefRequestCToCpp::Wrap(request));
+
+ // Return type: refptr_same
+ return CefCookieAccessFilterCppToC::Wrap(_retval);
+}
+
+cef_return_value_t CEF_CALLBACK
+resource_request_handler_on_before_resource_load(
+ struct _cef_resource_request_handler_t* self,
+ cef_browser_t* browser,
+ cef_frame_t* frame,
+ cef_request_t* request,
+ cef_callback_t* callback) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return RV_CONTINUE;
+ }
+ // Verify param: request; type: refptr_diff
+ DCHECK(request);
+ if (!request) {
+ return RV_CONTINUE;
+ }
+ // Verify param: callback; type: refptr_diff
+ DCHECK(callback);
+ if (!callback) {
+ return RV_CONTINUE;
+ }
+ // Unverified params: browser, frame
+
+ // Execute
+ cef_return_value_t _retval =
+ CefResourceRequestHandlerCppToC::Get(self)->OnBeforeResourceLoad(
+ CefBrowserCToCpp::Wrap(browser), CefFrameCToCpp::Wrap(frame),
+ CefRequestCToCpp::Wrap(request), CefCallbackCToCpp::Wrap(callback));
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_resource_handler_t* CEF_CALLBACK
+resource_request_handler_get_resource_handler(
+ struct _cef_resource_request_handler_t* self,
+ cef_browser_t* browser,
+ cef_frame_t* frame,
+ cef_request_t* request) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+ // Verify param: request; type: refptr_diff
+ DCHECK(request);
+ if (!request) {
+ return NULL;
+ }
+ // Unverified params: browser, frame
+
+ // Execute
+ CefRefPtr<CefResourceHandler> _retval =
+ CefResourceRequestHandlerCppToC::Get(self)->GetResourceHandler(
+ CefBrowserCToCpp::Wrap(browser), CefFrameCToCpp::Wrap(frame),
+ CefRequestCToCpp::Wrap(request));
+
+ // Return type: refptr_same
+ return CefResourceHandlerCppToC::Wrap(_retval);
+}
+
+void CEF_CALLBACK resource_request_handler_on_resource_redirect(
+ struct _cef_resource_request_handler_t* self,
+ cef_browser_t* browser,
+ cef_frame_t* frame,
+ cef_request_t* request,
+ struct _cef_response_t* response,
+ cef_string_t* new_url) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: request; type: refptr_diff
+ DCHECK(request);
+ if (!request) {
+ return;
+ }
+ // Verify param: response; type: refptr_diff
+ DCHECK(response);
+ if (!response) {
+ return;
+ }
+ // Verify param: new_url; type: string_byref
+ DCHECK(new_url);
+ if (!new_url) {
+ return;
+ }
+ // Unverified params: browser, frame
+
+ // Translate param: new_url; type: string_byref
+ CefString new_urlStr(new_url);
+
+ // Execute
+ CefResourceRequestHandlerCppToC::Get(self)->OnResourceRedirect(
+ CefBrowserCToCpp::Wrap(browser), CefFrameCToCpp::Wrap(frame),
+ CefRequestCToCpp::Wrap(request), CefResponseCToCpp::Wrap(response),
+ new_urlStr);
+}
+
+int CEF_CALLBACK resource_request_handler_on_resource_response(
+ struct _cef_resource_request_handler_t* self,
+ cef_browser_t* browser,
+ cef_frame_t* frame,
+ cef_request_t* request,
+ struct _cef_response_t* response) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: request; type: refptr_diff
+ DCHECK(request);
+ if (!request) {
+ return 0;
+ }
+ // Verify param: response; type: refptr_diff
+ DCHECK(response);
+ if (!response) {
+ return 0;
+ }
+ // Unverified params: browser, frame
+
+ // Execute
+ bool _retval = CefResourceRequestHandlerCppToC::Get(self)->OnResourceResponse(
+ CefBrowserCToCpp::Wrap(browser), CefFrameCToCpp::Wrap(frame),
+ CefRequestCToCpp::Wrap(request), CefResponseCToCpp::Wrap(response));
+
+ // Return type: bool
+ return _retval;
+}
+
+struct _cef_response_filter_t* CEF_CALLBACK
+resource_request_handler_get_resource_response_filter(
+ struct _cef_resource_request_handler_t* self,
+ cef_browser_t* browser,
+ cef_frame_t* frame,
+ cef_request_t* request,
+ struct _cef_response_t* response) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+ // Verify param: request; type: refptr_diff
+ DCHECK(request);
+ if (!request) {
+ return NULL;
+ }
+ // Verify param: response; type: refptr_diff
+ DCHECK(response);
+ if (!response) {
+ return NULL;
+ }
+ // Unverified params: browser, frame
+
+ // Execute
+ CefRefPtr<CefResponseFilter> _retval =
+ CefResourceRequestHandlerCppToC::Get(self)->GetResourceResponseFilter(
+ CefBrowserCToCpp::Wrap(browser), CefFrameCToCpp::Wrap(frame),
+ CefRequestCToCpp::Wrap(request), CefResponseCToCpp::Wrap(response));
+
+ // Return type: refptr_same
+ return CefResponseFilterCppToC::Wrap(_retval);
+}
+
+void CEF_CALLBACK resource_request_handler_on_resource_load_complete(
+ struct _cef_resource_request_handler_t* self,
+ cef_browser_t* browser,
+ cef_frame_t* frame,
+ cef_request_t* request,
+ struct _cef_response_t* response,
+ cef_urlrequest_status_t status,
+ int64 received_content_length) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: request; type: refptr_diff
+ DCHECK(request);
+ if (!request) {
+ return;
+ }
+ // Verify param: response; type: refptr_diff
+ DCHECK(response);
+ if (!response) {
+ return;
+ }
+ // Unverified params: browser, frame
+
+ // Execute
+ CefResourceRequestHandlerCppToC::Get(self)->OnResourceLoadComplete(
+ CefBrowserCToCpp::Wrap(browser), CefFrameCToCpp::Wrap(frame),
+ CefRequestCToCpp::Wrap(request), CefResponseCToCpp::Wrap(response),
+ status, received_content_length);
+}
+
+void CEF_CALLBACK resource_request_handler_on_protocol_execution(
+ struct _cef_resource_request_handler_t* self,
+ cef_browser_t* browser,
+ cef_frame_t* frame,
+ cef_request_t* request,
+ int* allow_os_execution) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: request; type: refptr_diff
+ DCHECK(request);
+ if (!request) {
+ return;
+ }
+ // Verify param: allow_os_execution; type: bool_byref
+ DCHECK(allow_os_execution);
+ if (!allow_os_execution) {
+ return;
+ }
+ // Unverified params: browser, frame
+
+ // Translate param: allow_os_execution; type: bool_byref
+ bool allow_os_executionBool =
+ (allow_os_execution && *allow_os_execution) ? true : false;
+
+ // Execute
+ CefResourceRequestHandlerCppToC::Get(self)->OnProtocolExecution(
+ CefBrowserCToCpp::Wrap(browser), CefFrameCToCpp::Wrap(frame),
+ CefRequestCToCpp::Wrap(request), allow_os_executionBool);
+
+ // Restore param: allow_os_execution; type: bool_byref
+ if (allow_os_execution) {
+ *allow_os_execution = allow_os_executionBool ? true : false;
+ }
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefResourceRequestHandlerCppToC::CefResourceRequestHandlerCppToC() {
+ GetStruct()->get_cookie_access_filter =
+ resource_request_handler_get_cookie_access_filter;
+ GetStruct()->on_before_resource_load =
+ resource_request_handler_on_before_resource_load;
+ GetStruct()->get_resource_handler =
+ resource_request_handler_get_resource_handler;
+ GetStruct()->on_resource_redirect =
+ resource_request_handler_on_resource_redirect;
+ GetStruct()->on_resource_response =
+ resource_request_handler_on_resource_response;
+ GetStruct()->get_resource_response_filter =
+ resource_request_handler_get_resource_response_filter;
+ GetStruct()->on_resource_load_complete =
+ resource_request_handler_on_resource_load_complete;
+ GetStruct()->on_protocol_execution =
+ resource_request_handler_on_protocol_execution;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefResourceRequestHandlerCppToC::~CefResourceRequestHandlerCppToC() {}
+
+template <>
+CefRefPtr<CefResourceRequestHandler>
+CefCppToCRefCounted<CefResourceRequestHandlerCppToC,
+ CefResourceRequestHandler,
+ cef_resource_request_handler_t>::
+ UnwrapDerived(CefWrapperType type, cef_resource_request_handler_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCppToCRefCounted<CefResourceRequestHandlerCppToC,
+ CefResourceRequestHandler,
+ cef_resource_request_handler_t>::kWrapperType =
+ WT_RESOURCE_REQUEST_HANDLER;
diff --git a/libcef_dll/cpptoc/resource_request_handler_cpptoc.h b/libcef_dll/cpptoc/resource_request_handler_cpptoc.h
new file mode 100644
index 00000000..70100017
--- /dev/null
+++ b/libcef_dll/cpptoc/resource_request_handler_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=0b8d614a76b9027970354dc850f7b491348a2941$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_RESOURCE_REQUEST_HANDLER_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_RESOURCE_REQUEST_HANDLER_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_resource_request_handler_capi.h"
+#include "include/cef_resource_request_handler.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefResourceRequestHandlerCppToC
+ : public CefCppToCRefCounted<CefResourceRequestHandlerCppToC,
+ CefResourceRequestHandler,
+ cef_resource_request_handler_t> {
+ public:
+ CefResourceRequestHandlerCppToC();
+ virtual ~CefResourceRequestHandlerCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_RESOURCE_REQUEST_HANDLER_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/resource_skip_callback_cpptoc.cc b/libcef_dll/cpptoc/resource_skip_callback_cpptoc.cc
new file mode 100644
index 00000000..5cb22bf3
--- /dev/null
+++ b/libcef_dll/cpptoc/resource_skip_callback_cpptoc.cc
@@ -0,0 +1,67 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=2a57133cdf0ebd14c4feb067f867f558b1403ae8$
+//
+
+#include "libcef_dll/cpptoc/resource_skip_callback_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK
+resource_skip_callback_cont(struct _cef_resource_skip_callback_t* self,
+ int64 bytes_skipped) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefResourceSkipCallbackCppToC::Get(self)->Continue(bytes_skipped);
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefResourceSkipCallbackCppToC::CefResourceSkipCallbackCppToC() {
+ GetStruct()->cont = resource_skip_callback_cont;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefResourceSkipCallbackCppToC::~CefResourceSkipCallbackCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefResourceSkipCallback> CefCppToCRefCounted<
+ CefResourceSkipCallbackCppToC,
+ CefResourceSkipCallback,
+ cef_resource_skip_callback_t>::UnwrapDerived(CefWrapperType type,
+ cef_resource_skip_callback_t*
+ s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefResourceSkipCallbackCppToC,
+ CefResourceSkipCallback,
+ cef_resource_skip_callback_t>::kWrapperType =
+ WT_RESOURCE_SKIP_CALLBACK;
diff --git a/libcef_dll/cpptoc/resource_skip_callback_cpptoc.h b/libcef_dll/cpptoc/resource_skip_callback_cpptoc.h
new file mode 100644
index 00000000..d7a82710
--- /dev/null
+++ b/libcef_dll/cpptoc/resource_skip_callback_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=5e756fb08a289333025a894573332555a1ab8e1f$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_RESOURCE_SKIP_CALLBACK_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_RESOURCE_SKIP_CALLBACK_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_resource_handler_capi.h"
+#include "include/cef_resource_handler.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefResourceSkipCallbackCppToC
+ : public CefCppToCRefCounted<CefResourceSkipCallbackCppToC,
+ CefResourceSkipCallback,
+ cef_resource_skip_callback_t> {
+ public:
+ CefResourceSkipCallbackCppToC();
+ virtual ~CefResourceSkipCallbackCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_RESOURCE_SKIP_CALLBACK_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/response_cpptoc.cc b/libcef_dll/cpptoc/response_cpptoc.cc
new file mode 100644
index 00000000..658890f8
--- /dev/null
+++ b/libcef_dll/cpptoc/response_cpptoc.cc
@@ -0,0 +1,357 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=91a122bd04945c350a947a565acf15419e055404$
+//
+
+#include "libcef_dll/cpptoc/response_cpptoc.h"
+#include "libcef_dll/transfer_util.h"
+
+// GLOBAL FUNCTIONS - Body may be edited by hand.
+
+CEF_EXPORT cef_response_t* cef_response_create() {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ CefRefPtr<CefResponse> _retval = CefResponse::Create();
+
+ // Return type: refptr_same
+ return CefResponseCppToC::Wrap(_retval);
+}
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK response_is_read_only(struct _cef_response_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefResponseCppToC::Get(self)->IsReadOnly();
+
+ // Return type: bool
+ return _retval;
+}
+
+cef_errorcode_t CEF_CALLBACK response_get_error(struct _cef_response_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return ERR_NONE;
+ }
+
+ // Execute
+ cef_errorcode_t _retval = CefResponseCppToC::Get(self)->GetError();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK response_set_error(struct _cef_response_t* self,
+ cef_errorcode_t error) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefResponseCppToC::Get(self)->SetError(error);
+}
+
+int CEF_CALLBACK response_get_status(struct _cef_response_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefResponseCppToC::Get(self)->GetStatus();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK response_set_status(struct _cef_response_t* self,
+ int status) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefResponseCppToC::Get(self)->SetStatus(status);
+}
+
+cef_string_userfree_t CEF_CALLBACK
+response_get_status_text(struct _cef_response_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefResponseCppToC::Get(self)->GetStatusText();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+void CEF_CALLBACK response_set_status_text(struct _cef_response_t* self,
+ const cef_string_t* statusText) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Unverified params: statusText
+
+ // Execute
+ CefResponseCppToC::Get(self)->SetStatusText(CefString(statusText));
+}
+
+cef_string_userfree_t CEF_CALLBACK
+response_get_mime_type(struct _cef_response_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefResponseCppToC::Get(self)->GetMimeType();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+void CEF_CALLBACK response_set_mime_type(struct _cef_response_t* self,
+ const cef_string_t* mimeType) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Unverified params: mimeType
+
+ // Execute
+ CefResponseCppToC::Get(self)->SetMimeType(CefString(mimeType));
+}
+
+cef_string_userfree_t CEF_CALLBACK
+response_get_charset(struct _cef_response_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefResponseCppToC::Get(self)->GetCharset();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+void CEF_CALLBACK response_set_charset(struct _cef_response_t* self,
+ const cef_string_t* charset) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Unverified params: charset
+
+ // Execute
+ CefResponseCppToC::Get(self)->SetCharset(CefString(charset));
+}
+
+cef_string_userfree_t CEF_CALLBACK
+response_get_header_by_name(struct _cef_response_t* self,
+ const cef_string_t* name) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+ // Verify param: name; type: string_byref_const
+ DCHECK(name);
+ if (!name) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval =
+ CefResponseCppToC::Get(self)->GetHeaderByName(CefString(name));
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+void CEF_CALLBACK response_set_header_by_name(struct _cef_response_t* self,
+ const cef_string_t* name,
+ const cef_string_t* value,
+ int overwrite) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: name; type: string_byref_const
+ DCHECK(name);
+ if (!name) {
+ return;
+ }
+ // Unverified params: value
+
+ // Execute
+ CefResponseCppToC::Get(self)->SetHeaderByName(
+ CefString(name), CefString(value), overwrite ? true : false);
+}
+
+void CEF_CALLBACK response_get_header_map(struct _cef_response_t* self,
+ cef_string_multimap_t headerMap) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: headerMap; type: string_map_multi_byref
+ DCHECK(headerMap);
+ if (!headerMap) {
+ return;
+ }
+
+ // Translate param: headerMap; type: string_map_multi_byref
+ std::multimap<CefString, CefString> headerMapMultimap;
+ transfer_string_multimap_contents(headerMap, headerMapMultimap);
+
+ // Execute
+ CefResponseCppToC::Get(self)->GetHeaderMap(headerMapMultimap);
+
+ // Restore param: headerMap; type: string_map_multi_byref
+ cef_string_multimap_clear(headerMap);
+ transfer_string_multimap_contents(headerMapMultimap, headerMap);
+}
+
+void CEF_CALLBACK response_set_header_map(struct _cef_response_t* self,
+ cef_string_multimap_t headerMap) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: headerMap; type: string_map_multi_byref_const
+ DCHECK(headerMap);
+ if (!headerMap) {
+ return;
+ }
+
+ // Translate param: headerMap; type: string_map_multi_byref_const
+ std::multimap<CefString, CefString> headerMapMultimap;
+ transfer_string_multimap_contents(headerMap, headerMapMultimap);
+
+ // Execute
+ CefResponseCppToC::Get(self)->SetHeaderMap(headerMapMultimap);
+}
+
+cef_string_userfree_t CEF_CALLBACK
+response_get_url(struct _cef_response_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefResponseCppToC::Get(self)->GetURL();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+void CEF_CALLBACK response_set_url(struct _cef_response_t* self,
+ const cef_string_t* url) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Unverified params: url
+
+ // Execute
+ CefResponseCppToC::Get(self)->SetURL(CefString(url));
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefResponseCppToC::CefResponseCppToC() {
+ GetStruct()->is_read_only = response_is_read_only;
+ GetStruct()->get_error = response_get_error;
+ GetStruct()->set_error = response_set_error;
+ GetStruct()->get_status = response_get_status;
+ GetStruct()->set_status = response_set_status;
+ GetStruct()->get_status_text = response_get_status_text;
+ GetStruct()->set_status_text = response_set_status_text;
+ GetStruct()->get_mime_type = response_get_mime_type;
+ GetStruct()->set_mime_type = response_set_mime_type;
+ GetStruct()->get_charset = response_get_charset;
+ GetStruct()->set_charset = response_set_charset;
+ GetStruct()->get_header_by_name = response_get_header_by_name;
+ GetStruct()->set_header_by_name = response_set_header_by_name;
+ GetStruct()->get_header_map = response_get_header_map;
+ GetStruct()->set_header_map = response_set_header_map;
+ GetStruct()->get_url = response_get_url;
+ GetStruct()->set_url = response_set_url;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefResponseCppToC::~CefResponseCppToC() {}
+
+template <>
+CefRefPtr<CefResponse>
+CefCppToCRefCounted<CefResponseCppToC, CefResponse, cef_response_t>::
+ UnwrapDerived(CefWrapperType type, cef_response_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefResponseCppToC,
+ CefResponse,
+ cef_response_t>::kWrapperType = WT_RESPONSE;
diff --git a/libcef_dll/cpptoc/response_cpptoc.h b/libcef_dll/cpptoc/response_cpptoc.h
new file mode 100644
index 00000000..b84c6990
--- /dev/null
+++ b/libcef_dll/cpptoc/response_cpptoc.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=624d1cb515a9f5f44d6e63574021689ccfe09b76$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_RESPONSE_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_RESPONSE_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_response_capi.h"
+#include "include/cef_response.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefResponseCppToC : public CefCppToCRefCounted<CefResponseCppToC,
+ CefResponse,
+ cef_response_t> {
+ public:
+ CefResponseCppToC();
+ virtual ~CefResponseCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_RESPONSE_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/response_filter_cpptoc.cc b/libcef_dll/cpptoc/response_filter_cpptoc.cc
new file mode 100644
index 00000000..055ba1b9
--- /dev/null
+++ b/libcef_dll/cpptoc/response_filter_cpptoc.cc
@@ -0,0 +1,126 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=67a86aa6e1d96bc5c9960dbee2b7e6786879a161$
+//
+
+#include "libcef_dll/cpptoc/response_filter_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK
+response_filter_init_filter(struct _cef_response_filter_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefResponseFilterCppToC::Get(self)->InitFilter();
+
+ // Return type: bool
+ return _retval;
+}
+
+cef_response_filter_status_t CEF_CALLBACK
+response_filter_filter(struct _cef_response_filter_t* self,
+ void* data_in,
+ size_t data_in_size,
+ size_t* data_in_read,
+ void* data_out,
+ size_t data_out_size,
+ size_t* data_out_written) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return RESPONSE_FILTER_ERROR;
+ }
+ // Verify param: data_in_read; type: simple_byref
+ DCHECK(data_in_read);
+ if (!data_in_read) {
+ return RESPONSE_FILTER_ERROR;
+ }
+ // Verify param: data_out; type: simple_byaddr
+ DCHECK(data_out);
+ if (!data_out) {
+ return RESPONSE_FILTER_ERROR;
+ }
+ // Verify param: data_out_written; type: simple_byref
+ DCHECK(data_out_written);
+ if (!data_out_written) {
+ return RESPONSE_FILTER_ERROR;
+ }
+ // Unverified params: data_in
+
+ // Translate param: data_in_read; type: simple_byref
+ size_t data_in_readVal = data_in_read ? *data_in_read : 0;
+ // Translate param: data_out_written; type: simple_byref
+ size_t data_out_writtenVal = data_out_written ? *data_out_written : 0;
+
+ // Execute
+ cef_response_filter_status_t _retval =
+ CefResponseFilterCppToC::Get(self)->Filter(
+ data_in, data_in_size, data_in_readVal, data_out, data_out_size,
+ data_out_writtenVal);
+
+ // Restore param: data_in_read; type: simple_byref
+ if (data_in_read) {
+ *data_in_read = data_in_readVal;
+ }
+ // Restore param: data_out_written; type: simple_byref
+ if (data_out_written) {
+ *data_out_written = data_out_writtenVal;
+ }
+
+ // Return type: simple
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefResponseFilterCppToC::CefResponseFilterCppToC() {
+ GetStruct()->init_filter = response_filter_init_filter;
+ GetStruct()->filter = response_filter_filter;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefResponseFilterCppToC::~CefResponseFilterCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefResponseFilter> CefCppToCRefCounted<
+ CefResponseFilterCppToC,
+ CefResponseFilter,
+ cef_response_filter_t>::UnwrapDerived(CefWrapperType type,
+ cef_response_filter_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefResponseFilterCppToC,
+ CefResponseFilter,
+ cef_response_filter_t>::kWrapperType =
+ WT_RESPONSE_FILTER;
diff --git a/libcef_dll/cpptoc/response_filter_cpptoc.h b/libcef_dll/cpptoc/response_filter_cpptoc.h
new file mode 100644
index 00000000..c17599dc
--- /dev/null
+++ b/libcef_dll/cpptoc/response_filter_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=55d4dc0a6467d6d084de5e1114be0fcd36ae89b9$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_RESPONSE_FILTER_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_RESPONSE_FILTER_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_response_filter_capi.h"
+#include "include/cef_response_filter.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefResponseFilterCppToC
+ : public CefCppToCRefCounted<CefResponseFilterCppToC,
+ CefResponseFilter,
+ cef_response_filter_t> {
+ public:
+ CefResponseFilterCppToC();
+ virtual ~CefResponseFilterCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_RESPONSE_FILTER_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/run_context_menu_callback_cpptoc.cc b/libcef_dll/cpptoc/run_context_menu_callback_cpptoc.cc
new file mode 100644
index 00000000..0ea5bdea
--- /dev/null
+++ b/libcef_dll/cpptoc/run_context_menu_callback_cpptoc.cc
@@ -0,0 +1,84 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=3d4a026e0e0c0f45b3bfbc6efaeeda3073b94196$
+//
+
+#include "libcef_dll/cpptoc/run_context_menu_callback_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK
+run_context_menu_callback_cont(struct _cef_run_context_menu_callback_t* self,
+ int command_id,
+ cef_event_flags_t event_flags) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefRunContextMenuCallbackCppToC::Get(self)->Continue(command_id, event_flags);
+}
+
+void CEF_CALLBACK run_context_menu_callback_cancel(
+ struct _cef_run_context_menu_callback_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefRunContextMenuCallbackCppToC::Get(self)->Cancel();
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefRunContextMenuCallbackCppToC::CefRunContextMenuCallbackCppToC() {
+ GetStruct()->cont = run_context_menu_callback_cont;
+ GetStruct()->cancel = run_context_menu_callback_cancel;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefRunContextMenuCallbackCppToC::~CefRunContextMenuCallbackCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefRunContextMenuCallback>
+CefCppToCRefCounted<CefRunContextMenuCallbackCppToC,
+ CefRunContextMenuCallback,
+ cef_run_context_menu_callback_t>::
+ UnwrapDerived(CefWrapperType type, cef_run_context_menu_callback_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCppToCRefCounted<CefRunContextMenuCallbackCppToC,
+ CefRunContextMenuCallback,
+ cef_run_context_menu_callback_t>::kWrapperType =
+ WT_RUN_CONTEXT_MENU_CALLBACK;
diff --git a/libcef_dll/cpptoc/run_context_menu_callback_cpptoc.h b/libcef_dll/cpptoc/run_context_menu_callback_cpptoc.h
new file mode 100644
index 00000000..954af278
--- /dev/null
+++ b/libcef_dll/cpptoc/run_context_menu_callback_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=a41928b718004e3e8cc92ba620b20f76ad9181b7$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_RUN_CONTEXT_MENU_CALLBACK_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_RUN_CONTEXT_MENU_CALLBACK_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_context_menu_handler_capi.h"
+#include "include/cef_context_menu_handler.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefRunContextMenuCallbackCppToC
+ : public CefCppToCRefCounted<CefRunContextMenuCallbackCppToC,
+ CefRunContextMenuCallback,
+ cef_run_context_menu_callback_t> {
+ public:
+ CefRunContextMenuCallbackCppToC();
+ virtual ~CefRunContextMenuCallbackCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_RUN_CONTEXT_MENU_CALLBACK_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/run_file_dialog_callback_cpptoc.cc b/libcef_dll/cpptoc/run_file_dialog_callback_cpptoc.cc
new file mode 100644
index 00000000..9589394f
--- /dev/null
+++ b/libcef_dll/cpptoc/run_file_dialog_callback_cpptoc.cc
@@ -0,0 +1,75 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=1377c3978cb878ce8fea606899c80b99f017fe48$
+//
+
+#include "libcef_dll/cpptoc/run_file_dialog_callback_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+#include "libcef_dll/transfer_util.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK run_file_dialog_callback_on_file_dialog_dismissed(
+ struct _cef_run_file_dialog_callback_t* self,
+ cef_string_list_t file_paths) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Unverified params: file_paths
+
+ // Translate param: file_paths; type: string_vec_byref_const
+ std::vector<CefString> file_pathsList;
+ transfer_string_list_contents(file_paths, file_pathsList);
+
+ // Execute
+ CefRunFileDialogCallbackCppToC::Get(self)->OnFileDialogDismissed(
+ file_pathsList);
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefRunFileDialogCallbackCppToC::CefRunFileDialogCallbackCppToC() {
+ GetStruct()->on_file_dialog_dismissed =
+ run_file_dialog_callback_on_file_dialog_dismissed;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefRunFileDialogCallbackCppToC::~CefRunFileDialogCallbackCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefRunFileDialogCallback>
+CefCppToCRefCounted<CefRunFileDialogCallbackCppToC,
+ CefRunFileDialogCallback,
+ cef_run_file_dialog_callback_t>::
+ UnwrapDerived(CefWrapperType type, cef_run_file_dialog_callback_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCppToCRefCounted<CefRunFileDialogCallbackCppToC,
+ CefRunFileDialogCallback,
+ cef_run_file_dialog_callback_t>::kWrapperType =
+ WT_RUN_FILE_DIALOG_CALLBACK;
diff --git a/libcef_dll/cpptoc/run_file_dialog_callback_cpptoc.h b/libcef_dll/cpptoc/run_file_dialog_callback_cpptoc.h
new file mode 100644
index 00000000..c5dac2e3
--- /dev/null
+++ b/libcef_dll/cpptoc/run_file_dialog_callback_cpptoc.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=7f45e5e5b3772e10b2eb6901c3e27e835a873163$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_RUN_FILE_DIALOG_CALLBACK_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_RUN_FILE_DIALOG_CALLBACK_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_browser_capi.h"
+#include "include/capi/cef_client_capi.h"
+#include "include/cef_browser.h"
+#include "include/cef_client.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefRunFileDialogCallbackCppToC
+ : public CefCppToCRefCounted<CefRunFileDialogCallbackCppToC,
+ CefRunFileDialogCallback,
+ cef_run_file_dialog_callback_t> {
+ public:
+ CefRunFileDialogCallbackCppToC();
+ virtual ~CefRunFileDialogCallbackCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_RUN_FILE_DIALOG_CALLBACK_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/run_quick_menu_callback_cpptoc.cc b/libcef_dll/cpptoc/run_quick_menu_callback_cpptoc.cc
new file mode 100644
index 00000000..900e0652
--- /dev/null
+++ b/libcef_dll/cpptoc/run_quick_menu_callback_cpptoc.cc
@@ -0,0 +1,85 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=eb693cdf087ac87c4fe8da576a41faa120f97cd1$
+//
+
+#include "libcef_dll/cpptoc/run_quick_menu_callback_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK
+run_quick_menu_callback_cont(struct _cef_run_quick_menu_callback_t* self,
+ int command_id,
+ cef_event_flags_t event_flags) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefRunQuickMenuCallbackCppToC::Get(self)->Continue(command_id, event_flags);
+}
+
+void CEF_CALLBACK
+run_quick_menu_callback_cancel(struct _cef_run_quick_menu_callback_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefRunQuickMenuCallbackCppToC::Get(self)->Cancel();
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefRunQuickMenuCallbackCppToC::CefRunQuickMenuCallbackCppToC() {
+ GetStruct()->cont = run_quick_menu_callback_cont;
+ GetStruct()->cancel = run_quick_menu_callback_cancel;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefRunQuickMenuCallbackCppToC::~CefRunQuickMenuCallbackCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefRunQuickMenuCallback> CefCppToCRefCounted<
+ CefRunQuickMenuCallbackCppToC,
+ CefRunQuickMenuCallback,
+ cef_run_quick_menu_callback_t>::UnwrapDerived(CefWrapperType type,
+ cef_run_quick_menu_callback_t*
+ s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCppToCRefCounted<CefRunQuickMenuCallbackCppToC,
+ CefRunQuickMenuCallback,
+ cef_run_quick_menu_callback_t>::kWrapperType =
+ WT_RUN_QUICK_MENU_CALLBACK;
diff --git a/libcef_dll/cpptoc/run_quick_menu_callback_cpptoc.h b/libcef_dll/cpptoc/run_quick_menu_callback_cpptoc.h
new file mode 100644
index 00000000..b8fa640f
--- /dev/null
+++ b/libcef_dll/cpptoc/run_quick_menu_callback_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=acc845289f80273062c7fde7d81e0c034a80f4e1$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_RUN_QUICK_MENU_CALLBACK_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_RUN_QUICK_MENU_CALLBACK_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_context_menu_handler_capi.h"
+#include "include/cef_context_menu_handler.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefRunQuickMenuCallbackCppToC
+ : public CefCppToCRefCounted<CefRunQuickMenuCallbackCppToC,
+ CefRunQuickMenuCallback,
+ cef_run_quick_menu_callback_t> {
+ public:
+ CefRunQuickMenuCallbackCppToC();
+ virtual ~CefRunQuickMenuCallbackCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_RUN_QUICK_MENU_CALLBACK_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/scheme_handler_factory_cpptoc.cc b/libcef_dll/cpptoc/scheme_handler_factory_cpptoc.cc
new file mode 100644
index 00000000..42d5fa81
--- /dev/null
+++ b/libcef_dll/cpptoc/scheme_handler_factory_cpptoc.cc
@@ -0,0 +1,86 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=bf6605b9c5545c7b739ee45b368b8b8d657c7961$
+//
+
+#include "libcef_dll/cpptoc/scheme_handler_factory_cpptoc.h"
+#include "libcef_dll/cpptoc/resource_handler_cpptoc.h"
+#include "libcef_dll/ctocpp/browser_ctocpp.h"
+#include "libcef_dll/ctocpp/frame_ctocpp.h"
+#include "libcef_dll/ctocpp/request_ctocpp.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+cef_resource_handler_t* CEF_CALLBACK
+scheme_handler_factory_create(struct _cef_scheme_handler_factory_t* self,
+ cef_browser_t* browser,
+ cef_frame_t* frame,
+ const cef_string_t* scheme_name,
+ cef_request_t* request) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+ // Verify param: scheme_name; type: string_byref_const
+ DCHECK(scheme_name);
+ if (!scheme_name) {
+ return NULL;
+ }
+ // Verify param: request; type: refptr_diff
+ DCHECK(request);
+ if (!request) {
+ return NULL;
+ }
+ // Unverified params: browser, frame
+
+ // Execute
+ CefRefPtr<CefResourceHandler> _retval =
+ CefSchemeHandlerFactoryCppToC::Get(self)->Create(
+ CefBrowserCToCpp::Wrap(browser), CefFrameCToCpp::Wrap(frame),
+ CefString(scheme_name), CefRequestCToCpp::Wrap(request));
+
+ // Return type: refptr_same
+ return CefResourceHandlerCppToC::Wrap(_retval);
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefSchemeHandlerFactoryCppToC::CefSchemeHandlerFactoryCppToC() {
+ GetStruct()->create = scheme_handler_factory_create;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefSchemeHandlerFactoryCppToC::~CefSchemeHandlerFactoryCppToC() {}
+
+template <>
+CefRefPtr<CefSchemeHandlerFactory> CefCppToCRefCounted<
+ CefSchemeHandlerFactoryCppToC,
+ CefSchemeHandlerFactory,
+ cef_scheme_handler_factory_t>::UnwrapDerived(CefWrapperType type,
+ cef_scheme_handler_factory_t*
+ s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefSchemeHandlerFactoryCppToC,
+ CefSchemeHandlerFactory,
+ cef_scheme_handler_factory_t>::kWrapperType =
+ WT_SCHEME_HANDLER_FACTORY;
diff --git a/libcef_dll/cpptoc/scheme_handler_factory_cpptoc.h b/libcef_dll/cpptoc/scheme_handler_factory_cpptoc.h
new file mode 100644
index 00000000..75daf7c1
--- /dev/null
+++ b/libcef_dll/cpptoc/scheme_handler_factory_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=746b9d06b417c9730fa98fa456a08e5c53e5475b$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_SCHEME_HANDLER_FACTORY_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_SCHEME_HANDLER_FACTORY_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_scheme_capi.h"
+#include "include/cef_scheme.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefSchemeHandlerFactoryCppToC
+ : public CefCppToCRefCounted<CefSchemeHandlerFactoryCppToC,
+ CefSchemeHandlerFactory,
+ cef_scheme_handler_factory_t> {
+ public:
+ CefSchemeHandlerFactoryCppToC();
+ virtual ~CefSchemeHandlerFactoryCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_SCHEME_HANDLER_FACTORY_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/scheme_registrar_cpptoc.cc b/libcef_dll/cpptoc/scheme_registrar_cpptoc.cc
new file mode 100644
index 00000000..6a0736dc
--- /dev/null
+++ b/libcef_dll/cpptoc/scheme_registrar_cpptoc.cc
@@ -0,0 +1,81 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=c8d002bda0c13dc943bc13dc03162e4caea2598d$
+//
+
+#include "libcef_dll/cpptoc/scheme_registrar_cpptoc.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK
+scheme_registrar_add_custom_scheme(struct _cef_scheme_registrar_t* self,
+ const cef_string_t* scheme_name,
+ int options) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: scheme_name; type: string_byref_const
+ DCHECK(scheme_name);
+ if (!scheme_name) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefSchemeRegistrarCppToC::Get(self)->AddCustomScheme(
+ CefString(scheme_name), options);
+
+ // Return type: bool
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefSchemeRegistrarCppToC::CefSchemeRegistrarCppToC() {
+ GetStruct()->add_custom_scheme = scheme_registrar_add_custom_scheme;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefSchemeRegistrarCppToC::~CefSchemeRegistrarCppToC() {}
+
+template <>
+CefOwnPtr<CefSchemeRegistrar> CefCppToCScoped<
+ CefSchemeRegistrarCppToC,
+ CefSchemeRegistrar,
+ cef_scheme_registrar_t>::UnwrapDerivedOwn(CefWrapperType type,
+ cef_scheme_registrar_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return CefOwnPtr<CefSchemeRegistrar>();
+}
+
+template <>
+CefRawPtr<CefSchemeRegistrar> CefCppToCScoped<
+ CefSchemeRegistrarCppToC,
+ CefSchemeRegistrar,
+ cef_scheme_registrar_t>::UnwrapDerivedRaw(CefWrapperType type,
+ cef_scheme_registrar_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCScoped<CefSchemeRegistrarCppToC,
+ CefSchemeRegistrar,
+ cef_scheme_registrar_t>::kWrapperType =
+ WT_SCHEME_REGISTRAR;
diff --git a/libcef_dll/cpptoc/scheme_registrar_cpptoc.h b/libcef_dll/cpptoc/scheme_registrar_cpptoc.h
new file mode 100644
index 00000000..3966e216
--- /dev/null
+++ b/libcef_dll/cpptoc/scheme_registrar_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=92c5fb1f7d14753510b029f71579a26970f0304c$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_SCHEME_REGISTRAR_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_SCHEME_REGISTRAR_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_scheme_capi.h"
+#include "include/cef_scheme.h"
+#include "libcef_dll/cpptoc/cpptoc_scoped.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefSchemeRegistrarCppToC
+ : public CefCppToCScoped<CefSchemeRegistrarCppToC,
+ CefSchemeRegistrar,
+ cef_scheme_registrar_t> {
+ public:
+ CefSchemeRegistrarCppToC();
+ virtual ~CefSchemeRegistrarCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_SCHEME_REGISTRAR_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/select_client_certificate_callback_cpptoc.cc b/libcef_dll/cpptoc/select_client_certificate_callback_cpptoc.cc
new file mode 100644
index 00000000..87f21f93
--- /dev/null
+++ b/libcef_dll/cpptoc/select_client_certificate_callback_cpptoc.cc
@@ -0,0 +1,73 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=c865766a570b4a0d355791d595f74f24fb7741b2$
+//
+
+#include "libcef_dll/cpptoc/select_client_certificate_callback_cpptoc.h"
+#include "libcef_dll/cpptoc/x509certificate_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK select_client_certificate_callback_select(
+ struct _cef_select_client_certificate_callback_t* self,
+ struct _cef_x509certificate_t* cert) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Unverified params: cert
+
+ // Execute
+ CefSelectClientCertificateCallbackCppToC::Get(self)->Select(
+ CefX509CertificateCppToC::Unwrap(cert));
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefSelectClientCertificateCallbackCppToC::
+ CefSelectClientCertificateCallbackCppToC() {
+ GetStruct()->select = select_client_certificate_callback_select;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefSelectClientCertificateCallbackCppToC::
+ ~CefSelectClientCertificateCallbackCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefSelectClientCertificateCallback>
+CefCppToCRefCounted<CefSelectClientCertificateCallbackCppToC,
+ CefSelectClientCertificateCallback,
+ cef_select_client_certificate_callback_t>::
+ UnwrapDerived(CefWrapperType type,
+ cef_select_client_certificate_callback_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<
+ CefSelectClientCertificateCallbackCppToC,
+ CefSelectClientCertificateCallback,
+ cef_select_client_certificate_callback_t>::kWrapperType =
+ WT_SELECT_CLIENT_CERTIFICATE_CALLBACK;
diff --git a/libcef_dll/cpptoc/select_client_certificate_callback_cpptoc.h b/libcef_dll/cpptoc/select_client_certificate_callback_cpptoc.h
new file mode 100644
index 00000000..1001cdca
--- /dev/null
+++ b/libcef_dll/cpptoc/select_client_certificate_callback_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=a8aaabd6df08000d4add9785980560b8427b9d68$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_SELECT_CLIENT_CERTIFICATE_CALLBACK_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_SELECT_CLIENT_CERTIFICATE_CALLBACK_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_request_handler_capi.h"
+#include "include/cef_request_handler.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefSelectClientCertificateCallbackCppToC
+ : public CefCppToCRefCounted<CefSelectClientCertificateCallbackCppToC,
+ CefSelectClientCertificateCallback,
+ cef_select_client_certificate_callback_t> {
+ public:
+ CefSelectClientCertificateCallbackCppToC();
+ virtual ~CefSelectClientCertificateCallbackCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_SELECT_CLIENT_CERTIFICATE_CALLBACK_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/server_cpptoc.cc b/libcef_dll/cpptoc/server_cpptoc.cc
new file mode 100644
index 00000000..ecdd00f4
--- /dev/null
+++ b/libcef_dll/cpptoc/server_cpptoc.cc
@@ -0,0 +1,350 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=64f33249acb07a3a3b27763d339e3bd41af6bc5d$
+//
+
+#include "libcef_dll/cpptoc/server_cpptoc.h"
+#include "libcef_dll/cpptoc/task_runner_cpptoc.h"
+#include "libcef_dll/ctocpp/server_handler_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+#include "libcef_dll/transfer_util.h"
+
+// GLOBAL FUNCTIONS - Body may be edited by hand.
+
+CEF_EXPORT void cef_server_create(const cef_string_t* address,
+ uint16 port,
+ int backlog,
+ struct _cef_server_handler_t* handler) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: address; type: string_byref_const
+ DCHECK(address);
+ if (!address) {
+ return;
+ }
+ // Verify param: handler; type: refptr_diff
+ DCHECK(handler);
+ if (!handler) {
+ return;
+ }
+
+ // Execute
+ CefServer::CreateServer(CefString(address), port, backlog,
+ CefServerHandlerCToCpp::Wrap(handler));
+}
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+struct _cef_task_runner_t* CEF_CALLBACK
+server_get_task_runner(struct _cef_server_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefTaskRunner> _retval =
+ CefServerCppToC::Get(self)->GetTaskRunner();
+
+ // Return type: refptr_same
+ return CefTaskRunnerCppToC::Wrap(_retval);
+}
+
+void CEF_CALLBACK server_shutdown(struct _cef_server_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefServerCppToC::Get(self)->Shutdown();
+}
+
+int CEF_CALLBACK server_is_running(struct _cef_server_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefServerCppToC::Get(self)->IsRunning();
+
+ // Return type: bool
+ return _retval;
+}
+
+cef_string_userfree_t CEF_CALLBACK
+server_get_address(struct _cef_server_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefServerCppToC::Get(self)->GetAddress();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+int CEF_CALLBACK server_has_connection(struct _cef_server_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefServerCppToC::Get(self)->HasConnection();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK server_is_valid_connection(struct _cef_server_t* self,
+ int connection_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefServerCppToC::Get(self)->IsValidConnection(connection_id);
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK server_send_http200response(struct _cef_server_t* self,
+ int connection_id,
+ const cef_string_t* content_type,
+ const void* data,
+ size_t data_size) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: content_type; type: string_byref_const
+ DCHECK(content_type);
+ if (!content_type) {
+ return;
+ }
+ // Verify param: data; type: simple_byaddr
+ DCHECK(data);
+ if (!data) {
+ return;
+ }
+
+ // Execute
+ CefServerCppToC::Get(self)->SendHttp200Response(
+ connection_id, CefString(content_type), data, data_size);
+}
+
+void CEF_CALLBACK server_send_http404response(struct _cef_server_t* self,
+ int connection_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefServerCppToC::Get(self)->SendHttp404Response(connection_id);
+}
+
+void CEF_CALLBACK
+server_send_http500response(struct _cef_server_t* self,
+ int connection_id,
+ const cef_string_t* error_message) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: error_message; type: string_byref_const
+ DCHECK(error_message);
+ if (!error_message) {
+ return;
+ }
+
+ // Execute
+ CefServerCppToC::Get(self)->SendHttp500Response(connection_id,
+ CefString(error_message));
+}
+
+void CEF_CALLBACK
+server_send_http_response(struct _cef_server_t* self,
+ int connection_id,
+ int response_code,
+ const cef_string_t* content_type,
+ int64 content_length,
+ cef_string_multimap_t extra_headers) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: content_type; type: string_byref_const
+ DCHECK(content_type);
+ if (!content_type) {
+ return;
+ }
+ // Unverified params: extra_headers
+
+ // Translate param: extra_headers; type: string_map_multi_byref_const
+ std::multimap<CefString, CefString> extra_headersMultimap;
+ transfer_string_multimap_contents(extra_headers, extra_headersMultimap);
+
+ // Execute
+ CefServerCppToC::Get(self)->SendHttpResponse(
+ connection_id, response_code, CefString(content_type), content_length,
+ extra_headersMultimap);
+}
+
+void CEF_CALLBACK server_send_raw_data(struct _cef_server_t* self,
+ int connection_id,
+ const void* data,
+ size_t data_size) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: data; type: simple_byaddr
+ DCHECK(data);
+ if (!data) {
+ return;
+ }
+
+ // Execute
+ CefServerCppToC::Get(self)->SendRawData(connection_id, data, data_size);
+}
+
+void CEF_CALLBACK server_close_connection(struct _cef_server_t* self,
+ int connection_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefServerCppToC::Get(self)->CloseConnection(connection_id);
+}
+
+void CEF_CALLBACK server_send_web_socket_message(struct _cef_server_t* self,
+ int connection_id,
+ const void* data,
+ size_t data_size) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: data; type: simple_byaddr
+ DCHECK(data);
+ if (!data) {
+ return;
+ }
+
+ // Execute
+ CefServerCppToC::Get(self)->SendWebSocketMessage(connection_id, data,
+ data_size);
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefServerCppToC::CefServerCppToC() {
+ GetStruct()->get_task_runner = server_get_task_runner;
+ GetStruct()->shutdown = server_shutdown;
+ GetStruct()->is_running = server_is_running;
+ GetStruct()->get_address = server_get_address;
+ GetStruct()->has_connection = server_has_connection;
+ GetStruct()->is_valid_connection = server_is_valid_connection;
+ GetStruct()->send_http200response = server_send_http200response;
+ GetStruct()->send_http404response = server_send_http404response;
+ GetStruct()->send_http500response = server_send_http500response;
+ GetStruct()->send_http_response = server_send_http_response;
+ GetStruct()->send_raw_data = server_send_raw_data;
+ GetStruct()->close_connection = server_close_connection;
+ GetStruct()->send_web_socket_message = server_send_web_socket_message;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefServerCppToC::~CefServerCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefServer>
+CefCppToCRefCounted<CefServerCppToC, CefServer, cef_server_t>::UnwrapDerived(
+ CefWrapperType type,
+ cef_server_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefServerCppToC, CefServer, cef_server_t>::
+ kWrapperType = WT_SERVER;
diff --git a/libcef_dll/cpptoc/server_cpptoc.h b/libcef_dll/cpptoc/server_cpptoc.h
new file mode 100644
index 00000000..fd191b03
--- /dev/null
+++ b/libcef_dll/cpptoc/server_cpptoc.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=edf9787173ef035101e1d1805f2926b6028530f8$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_SERVER_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_SERVER_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_server_capi.h"
+#include "include/cef_server.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefServerCppToC
+ : public CefCppToCRefCounted<CefServerCppToC, CefServer, cef_server_t> {
+ public:
+ CefServerCppToC();
+ virtual ~CefServerCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_SERVER_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/server_handler_cpptoc.cc b/libcef_dll/cpptoc/server_handler_cpptoc.cc
new file mode 100644
index 00000000..c9298484
--- /dev/null
+++ b/libcef_dll/cpptoc/server_handler_cpptoc.cc
@@ -0,0 +1,281 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=c97b6223ac1745adbc83abf78ccd3b7d401ccd20$
+//
+
+#include "libcef_dll/cpptoc/server_handler_cpptoc.h"
+#include "libcef_dll/ctocpp/callback_ctocpp.h"
+#include "libcef_dll/ctocpp/request_ctocpp.h"
+#include "libcef_dll/ctocpp/server_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK
+server_handler_on_server_created(struct _cef_server_handler_t* self,
+ cef_server_t* server) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: server; type: refptr_diff
+ DCHECK(server);
+ if (!server) {
+ return;
+ }
+
+ // Execute
+ CefServerHandlerCppToC::Get(self)->OnServerCreated(
+ CefServerCToCpp::Wrap(server));
+}
+
+void CEF_CALLBACK
+server_handler_on_server_destroyed(struct _cef_server_handler_t* self,
+ cef_server_t* server) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: server; type: refptr_diff
+ DCHECK(server);
+ if (!server) {
+ return;
+ }
+
+ // Execute
+ CefServerHandlerCppToC::Get(self)->OnServerDestroyed(
+ CefServerCToCpp::Wrap(server));
+}
+
+void CEF_CALLBACK
+server_handler_on_client_connected(struct _cef_server_handler_t* self,
+ cef_server_t* server,
+ int connection_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: server; type: refptr_diff
+ DCHECK(server);
+ if (!server) {
+ return;
+ }
+
+ // Execute
+ CefServerHandlerCppToC::Get(self)->OnClientConnected(
+ CefServerCToCpp::Wrap(server), connection_id);
+}
+
+void CEF_CALLBACK
+server_handler_on_client_disconnected(struct _cef_server_handler_t* self,
+ cef_server_t* server,
+ int connection_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: server; type: refptr_diff
+ DCHECK(server);
+ if (!server) {
+ return;
+ }
+
+ // Execute
+ CefServerHandlerCppToC::Get(self)->OnClientDisconnected(
+ CefServerCToCpp::Wrap(server), connection_id);
+}
+
+void CEF_CALLBACK
+server_handler_on_http_request(struct _cef_server_handler_t* self,
+ cef_server_t* server,
+ int connection_id,
+ const cef_string_t* client_address,
+ cef_request_t* request) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: server; type: refptr_diff
+ DCHECK(server);
+ if (!server) {
+ return;
+ }
+ // Verify param: client_address; type: string_byref_const
+ DCHECK(client_address);
+ if (!client_address) {
+ return;
+ }
+ // Verify param: request; type: refptr_diff
+ DCHECK(request);
+ if (!request) {
+ return;
+ }
+
+ // Execute
+ CefServerHandlerCppToC::Get(self)->OnHttpRequest(
+ CefServerCToCpp::Wrap(server), connection_id, CefString(client_address),
+ CefRequestCToCpp::Wrap(request));
+}
+
+void CEF_CALLBACK
+server_handler_on_web_socket_request(struct _cef_server_handler_t* self,
+ cef_server_t* server,
+ int connection_id,
+ const cef_string_t* client_address,
+ cef_request_t* request,
+ cef_callback_t* callback) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: server; type: refptr_diff
+ DCHECK(server);
+ if (!server) {
+ return;
+ }
+ // Verify param: client_address; type: string_byref_const
+ DCHECK(client_address);
+ if (!client_address) {
+ return;
+ }
+ // Verify param: request; type: refptr_diff
+ DCHECK(request);
+ if (!request) {
+ return;
+ }
+ // Verify param: callback; type: refptr_diff
+ DCHECK(callback);
+ if (!callback) {
+ return;
+ }
+
+ // Execute
+ CefServerHandlerCppToC::Get(self)->OnWebSocketRequest(
+ CefServerCToCpp::Wrap(server), connection_id, CefString(client_address),
+ CefRequestCToCpp::Wrap(request), CefCallbackCToCpp::Wrap(callback));
+}
+
+void CEF_CALLBACK
+server_handler_on_web_socket_connected(struct _cef_server_handler_t* self,
+ cef_server_t* server,
+ int connection_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: server; type: refptr_diff
+ DCHECK(server);
+ if (!server) {
+ return;
+ }
+
+ // Execute
+ CefServerHandlerCppToC::Get(self)->OnWebSocketConnected(
+ CefServerCToCpp::Wrap(server), connection_id);
+}
+
+void CEF_CALLBACK
+server_handler_on_web_socket_message(struct _cef_server_handler_t* self,
+ cef_server_t* server,
+ int connection_id,
+ const void* data,
+ size_t data_size) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: server; type: refptr_diff
+ DCHECK(server);
+ if (!server) {
+ return;
+ }
+ // Verify param: data; type: simple_byaddr
+ DCHECK(data);
+ if (!data) {
+ return;
+ }
+
+ // Execute
+ CefServerHandlerCppToC::Get(self)->OnWebSocketMessage(
+ CefServerCToCpp::Wrap(server), connection_id, data, data_size);
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefServerHandlerCppToC::CefServerHandlerCppToC() {
+ GetStruct()->on_server_created = server_handler_on_server_created;
+ GetStruct()->on_server_destroyed = server_handler_on_server_destroyed;
+ GetStruct()->on_client_connected = server_handler_on_client_connected;
+ GetStruct()->on_client_disconnected = server_handler_on_client_disconnected;
+ GetStruct()->on_http_request = server_handler_on_http_request;
+ GetStruct()->on_web_socket_request = server_handler_on_web_socket_request;
+ GetStruct()->on_web_socket_connected = server_handler_on_web_socket_connected;
+ GetStruct()->on_web_socket_message = server_handler_on_web_socket_message;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefServerHandlerCppToC::~CefServerHandlerCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefServerHandler> CefCppToCRefCounted<
+ CefServerHandlerCppToC,
+ CefServerHandler,
+ cef_server_handler_t>::UnwrapDerived(CefWrapperType type,
+ cef_server_handler_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefServerHandlerCppToC,
+ CefServerHandler,
+ cef_server_handler_t>::kWrapperType =
+ WT_SERVER_HANDLER;
diff --git a/libcef_dll/cpptoc/server_handler_cpptoc.h b/libcef_dll/cpptoc/server_handler_cpptoc.h
new file mode 100644
index 00000000..c452567a
--- /dev/null
+++ b/libcef_dll/cpptoc/server_handler_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=ba72a7b9571b7e2d9d490a02972855eca1ff987f$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_SERVER_HANDLER_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_SERVER_HANDLER_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_server_capi.h"
+#include "include/cef_server.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefServerHandlerCppToC
+ : public CefCppToCRefCounted<CefServerHandlerCppToC,
+ CefServerHandler,
+ cef_server_handler_t> {
+ public:
+ CefServerHandlerCppToC();
+ virtual ~CefServerHandlerCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_SERVER_HANDLER_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/set_cookie_callback_cpptoc.cc b/libcef_dll/cpptoc/set_cookie_callback_cpptoc.cc
new file mode 100644
index 00000000..27275eb1
--- /dev/null
+++ b/libcef_dll/cpptoc/set_cookie_callback_cpptoc.cc
@@ -0,0 +1,66 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=d199f58fbd9efb01b375935d0660f8e2f74e630f$
+//
+
+#include "libcef_dll/cpptoc/set_cookie_callback_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK
+set_cookie_callback_on_complete(struct _cef_set_cookie_callback_t* self,
+ int success) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefSetCookieCallbackCppToC::Get(self)->OnComplete(success ? true : false);
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefSetCookieCallbackCppToC::CefSetCookieCallbackCppToC() {
+ GetStruct()->on_complete = set_cookie_callback_on_complete;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefSetCookieCallbackCppToC::~CefSetCookieCallbackCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefSetCookieCallback> CefCppToCRefCounted<
+ CefSetCookieCallbackCppToC,
+ CefSetCookieCallback,
+ cef_set_cookie_callback_t>::UnwrapDerived(CefWrapperType type,
+ cef_set_cookie_callback_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefSetCookieCallbackCppToC,
+ CefSetCookieCallback,
+ cef_set_cookie_callback_t>::kWrapperType =
+ WT_SET_COOKIE_CALLBACK;
diff --git a/libcef_dll/cpptoc/set_cookie_callback_cpptoc.h b/libcef_dll/cpptoc/set_cookie_callback_cpptoc.h
new file mode 100644
index 00000000..85c34421
--- /dev/null
+++ b/libcef_dll/cpptoc/set_cookie_callback_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=886b832f912900c89787888566d4d5e803c91ebc$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_SET_COOKIE_CALLBACK_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_SET_COOKIE_CALLBACK_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_cookie_capi.h"
+#include "include/cef_cookie.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefSetCookieCallbackCppToC
+ : public CefCppToCRefCounted<CefSetCookieCallbackCppToC,
+ CefSetCookieCallback,
+ cef_set_cookie_callback_t> {
+ public:
+ CefSetCookieCallbackCppToC();
+ virtual ~CefSetCookieCallbackCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_SET_COOKIE_CALLBACK_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/shared_memory_region_cpptoc.cc b/libcef_dll/cpptoc/shared_memory_region_cpptoc.cc
new file mode 100644
index 00000000..0c5900fd
--- /dev/null
+++ b/libcef_dll/cpptoc/shared_memory_region_cpptoc.cc
@@ -0,0 +1,106 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=5b181bf741072399ceb3c21ad010ce2bed04aab3$
+//
+
+#include "libcef_dll/cpptoc/shared_memory_region_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK
+shared_memory_region_is_valid(struct _cef_shared_memory_region_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefSharedMemoryRegionCppToC::Get(self)->IsValid();
+
+ // Return type: bool
+ return _retval;
+}
+
+size_t CEF_CALLBACK
+shared_memory_region_size(struct _cef_shared_memory_region_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ size_t _retval = CefSharedMemoryRegionCppToC::Get(self)->Size();
+
+ // Return type: simple
+ return _retval;
+}
+
+const void* CEF_CALLBACK
+shared_memory_region_memory(struct _cef_shared_memory_region_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ const void* _retval = CefSharedMemoryRegionCppToC::Get(self)->Memory();
+
+ // Return type: simple
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefSharedMemoryRegionCppToC::CefSharedMemoryRegionCppToC() {
+ GetStruct()->is_valid = shared_memory_region_is_valid;
+ GetStruct()->size = shared_memory_region_size;
+ GetStruct()->memory = shared_memory_region_memory;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefSharedMemoryRegionCppToC::~CefSharedMemoryRegionCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefSharedMemoryRegion> CefCppToCRefCounted<
+ CefSharedMemoryRegionCppToC,
+ CefSharedMemoryRegion,
+ cef_shared_memory_region_t>::UnwrapDerived(CefWrapperType type,
+ cef_shared_memory_region_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefSharedMemoryRegionCppToC,
+ CefSharedMemoryRegion,
+ cef_shared_memory_region_t>::kWrapperType =
+ WT_SHARED_MEMORY_REGION;
diff --git a/libcef_dll/cpptoc/shared_memory_region_cpptoc.h b/libcef_dll/cpptoc/shared_memory_region_cpptoc.h
new file mode 100644
index 00000000..85fc6d5a
--- /dev/null
+++ b/libcef_dll/cpptoc/shared_memory_region_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=65f87b7ef4fffcdd5fb70969719b9bb8fa4c8a7b$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_SHARED_MEMORY_REGION_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_SHARED_MEMORY_REGION_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_shared_memory_region_capi.h"
+#include "include/cef_shared_memory_region.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefSharedMemoryRegionCppToC
+ : public CefCppToCRefCounted<CefSharedMemoryRegionCppToC,
+ CefSharedMemoryRegion,
+ cef_shared_memory_region_t> {
+ public:
+ CefSharedMemoryRegionCppToC();
+ virtual ~CefSharedMemoryRegionCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_SHARED_MEMORY_REGION_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/shared_process_message_builder_cpptoc.cc b/libcef_dll/cpptoc/shared_process_message_builder_cpptoc.cc
new file mode 100644
index 00000000..7fce3101
--- /dev/null
+++ b/libcef_dll/cpptoc/shared_process_message_builder_cpptoc.cc
@@ -0,0 +1,150 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=724a8df36edf93cbfa842226a4507891ec8df8e6$
+//
+
+#include "libcef_dll/cpptoc/shared_process_message_builder_cpptoc.h"
+#include "libcef_dll/cpptoc/process_message_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// GLOBAL FUNCTIONS - Body may be edited by hand.
+
+CEF_EXPORT cef_shared_process_message_builder_t*
+cef_shared_process_message_builder_create(const cef_string_t* name,
+ size_t byte_size) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: name; type: string_byref_const
+ DCHECK(name);
+ if (!name) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefSharedProcessMessageBuilder> _retval =
+ CefSharedProcessMessageBuilder::Create(CefString(name), byte_size);
+
+ // Return type: refptr_same
+ return CefSharedProcessMessageBuilderCppToC::Wrap(_retval);
+}
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK shared_process_message_builder_is_valid(
+ struct _cef_shared_process_message_builder_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefSharedProcessMessageBuilderCppToC::Get(self)->IsValid();
+
+ // Return type: bool
+ return _retval;
+}
+
+size_t CEF_CALLBACK shared_process_message_builder_size(
+ struct _cef_shared_process_message_builder_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ size_t _retval = CefSharedProcessMessageBuilderCppToC::Get(self)->Size();
+
+ // Return type: simple
+ return _retval;
+}
+
+void* CEF_CALLBACK shared_process_message_builder_memory(
+ struct _cef_shared_process_message_builder_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ void* _retval = CefSharedProcessMessageBuilderCppToC::Get(self)->Memory();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_process_message_t* CEF_CALLBACK shared_process_message_builder_build(
+ struct _cef_shared_process_message_builder_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefProcessMessage> _retval =
+ CefSharedProcessMessageBuilderCppToC::Get(self)->Build();
+
+ // Return type: refptr_same
+ return CefProcessMessageCppToC::Wrap(_retval);
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefSharedProcessMessageBuilderCppToC::CefSharedProcessMessageBuilderCppToC() {
+ GetStruct()->is_valid = shared_process_message_builder_is_valid;
+ GetStruct()->size = shared_process_message_builder_size;
+ GetStruct()->memory = shared_process_message_builder_memory;
+ GetStruct()->build = shared_process_message_builder_build;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefSharedProcessMessageBuilderCppToC::~CefSharedProcessMessageBuilderCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefSharedProcessMessageBuilder>
+CefCppToCRefCounted<CefSharedProcessMessageBuilderCppToC,
+ CefSharedProcessMessageBuilder,
+ cef_shared_process_message_builder_t>::
+ UnwrapDerived(CefWrapperType type,
+ cef_shared_process_message_builder_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCppToCRefCounted<CefSharedProcessMessageBuilderCppToC,
+ CefSharedProcessMessageBuilder,
+ cef_shared_process_message_builder_t>::kWrapperType =
+ WT_SHARED_PROCESS_MESSAGE_BUILDER;
diff --git a/libcef_dll/cpptoc/shared_process_message_builder_cpptoc.h b/libcef_dll/cpptoc/shared_process_message_builder_cpptoc.h
new file mode 100644
index 00000000..442e2e1a
--- /dev/null
+++ b/libcef_dll/cpptoc/shared_process_message_builder_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=da417f77c868bf40de0bff713b6eb935ffb845ea$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_SHARED_PROCESS_MESSAGE_BUILDER_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_SHARED_PROCESS_MESSAGE_BUILDER_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_shared_process_message_builder_capi.h"
+#include "include/cef_shared_process_message_builder.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefSharedProcessMessageBuilderCppToC
+ : public CefCppToCRefCounted<CefSharedProcessMessageBuilderCppToC,
+ CefSharedProcessMessageBuilder,
+ cef_shared_process_message_builder_t> {
+ public:
+ CefSharedProcessMessageBuilderCppToC();
+ virtual ~CefSharedProcessMessageBuilderCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_SHARED_PROCESS_MESSAGE_BUILDER_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/sslinfo_cpptoc.cc b/libcef_dll/cpptoc/sslinfo_cpptoc.cc
new file mode 100644
index 00000000..59e990c0
--- /dev/null
+++ b/libcef_dll/cpptoc/sslinfo_cpptoc.cc
@@ -0,0 +1,87 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=b4016d9e37c0be7b025cd7f0f3f880745eeb2da2$
+//
+
+#include "libcef_dll/cpptoc/sslinfo_cpptoc.h"
+#include "libcef_dll/cpptoc/x509certificate_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+cef_cert_status_t CEF_CALLBACK
+sslinfo_get_cert_status(struct _cef_sslinfo_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CERT_STATUS_NONE;
+ }
+
+ // Execute
+ cef_cert_status_t _retval = CefSSLInfoCppToC::Get(self)->GetCertStatus();
+
+ // Return type: simple
+ return _retval;
+}
+
+struct _cef_x509certificate_t* CEF_CALLBACK
+sslinfo_get_x509certificate(struct _cef_sslinfo_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefX509Certificate> _retval =
+ CefSSLInfoCppToC::Get(self)->GetX509Certificate();
+
+ // Return type: refptr_same
+ return CefX509CertificateCppToC::Wrap(_retval);
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefSSLInfoCppToC::CefSSLInfoCppToC() {
+ GetStruct()->get_cert_status = sslinfo_get_cert_status;
+ GetStruct()->get_x509certificate = sslinfo_get_x509certificate;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefSSLInfoCppToC::~CefSSLInfoCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefSSLInfo>
+CefCppToCRefCounted<CefSSLInfoCppToC, CefSSLInfo, cef_sslinfo_t>::UnwrapDerived(
+ CefWrapperType type,
+ cef_sslinfo_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefSSLInfoCppToC,
+ CefSSLInfo,
+ cef_sslinfo_t>::kWrapperType = WT_SSLINFO;
diff --git a/libcef_dll/cpptoc/sslinfo_cpptoc.h b/libcef_dll/cpptoc/sslinfo_cpptoc.h
new file mode 100644
index 00000000..bb957680
--- /dev/null
+++ b/libcef_dll/cpptoc/sslinfo_cpptoc.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=2eaaaeef70817cde9783efe192d0f57cb73ddfad$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_SSLINFO_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_SSLINFO_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_ssl_info_capi.h"
+#include "include/cef_ssl_info.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefSSLInfoCppToC
+ : public CefCppToCRefCounted<CefSSLInfoCppToC, CefSSLInfo, cef_sslinfo_t> {
+ public:
+ CefSSLInfoCppToC();
+ virtual ~CefSSLInfoCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_SSLINFO_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/sslstatus_cpptoc.cc b/libcef_dll/cpptoc/sslstatus_cpptoc.cc
new file mode 100644
index 00000000..70b8c9d9
--- /dev/null
+++ b/libcef_dll/cpptoc/sslstatus_cpptoc.cc
@@ -0,0 +1,144 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=645171054314f522ab1a56423d3ebab3346c6905$
+//
+
+#include "libcef_dll/cpptoc/sslstatus_cpptoc.h"
+#include "libcef_dll/cpptoc/x509certificate_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK sslstatus_is_secure_connection(struct _cef_sslstatus_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefSSLStatusCppToC::Get(self)->IsSecureConnection();
+
+ // Return type: bool
+ return _retval;
+}
+
+cef_cert_status_t CEF_CALLBACK
+sslstatus_get_cert_status(struct _cef_sslstatus_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CERT_STATUS_NONE;
+ }
+
+ // Execute
+ cef_cert_status_t _retval = CefSSLStatusCppToC::Get(self)->GetCertStatus();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_ssl_version_t CEF_CALLBACK
+sslstatus_get_sslversion(struct _cef_sslstatus_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return SSL_CONNECTION_VERSION_UNKNOWN;
+ }
+
+ // Execute
+ cef_ssl_version_t _retval = CefSSLStatusCppToC::Get(self)->GetSSLVersion();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_ssl_content_status_t CEF_CALLBACK
+sslstatus_get_content_status(struct _cef_sslstatus_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return SSL_CONTENT_NORMAL_CONTENT;
+ }
+
+ // Execute
+ cef_ssl_content_status_t _retval =
+ CefSSLStatusCppToC::Get(self)->GetContentStatus();
+
+ // Return type: simple
+ return _retval;
+}
+
+struct _cef_x509certificate_t* CEF_CALLBACK
+sslstatus_get_x509certificate(struct _cef_sslstatus_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefX509Certificate> _retval =
+ CefSSLStatusCppToC::Get(self)->GetX509Certificate();
+
+ // Return type: refptr_same
+ return CefX509CertificateCppToC::Wrap(_retval);
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefSSLStatusCppToC::CefSSLStatusCppToC() {
+ GetStruct()->is_secure_connection = sslstatus_is_secure_connection;
+ GetStruct()->get_cert_status = sslstatus_get_cert_status;
+ GetStruct()->get_sslversion = sslstatus_get_sslversion;
+ GetStruct()->get_content_status = sslstatus_get_content_status;
+ GetStruct()->get_x509certificate = sslstatus_get_x509certificate;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefSSLStatusCppToC::~CefSSLStatusCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefSSLStatus>
+CefCppToCRefCounted<CefSSLStatusCppToC, CefSSLStatus, cef_sslstatus_t>::
+ UnwrapDerived(CefWrapperType type, cef_sslstatus_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefSSLStatusCppToC,
+ CefSSLStatus,
+ cef_sslstatus_t>::kWrapperType =
+ WT_SSLSTATUS;
diff --git a/libcef_dll/cpptoc/sslstatus_cpptoc.h b/libcef_dll/cpptoc/sslstatus_cpptoc.h
new file mode 100644
index 00000000..4e5379fb
--- /dev/null
+++ b/libcef_dll/cpptoc/sslstatus_cpptoc.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=dba266754e189de39172bddaacf0dfa3fdd79351$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_SSLSTATUS_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_SSLSTATUS_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_ssl_status_capi.h"
+#include "include/cef_ssl_status.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefSSLStatusCppToC : public CefCppToCRefCounted<CefSSLStatusCppToC,
+ CefSSLStatus,
+ cef_sslstatus_t> {
+ public:
+ CefSSLStatusCppToC();
+ virtual ~CefSSLStatusCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_SSLSTATUS_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/stream_reader_cpptoc.cc b/libcef_dll/cpptoc/stream_reader_cpptoc.cc
new file mode 100644
index 00000000..1ff5728e
--- /dev/null
+++ b/libcef_dll/cpptoc/stream_reader_cpptoc.cc
@@ -0,0 +1,212 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=3835ba1790959a5287e49afe05089daa4e536a5d$
+//
+
+#include "libcef_dll/cpptoc/stream_reader_cpptoc.h"
+#include "libcef_dll/ctocpp/read_handler_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// GLOBAL FUNCTIONS - Body may be edited by hand.
+
+CEF_EXPORT cef_stream_reader_t* cef_stream_reader_create_for_file(
+ const cef_string_t* fileName) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: fileName; type: string_byref_const
+ DCHECK(fileName);
+ if (!fileName) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefStreamReader> _retval =
+ CefStreamReader::CreateForFile(CefString(fileName));
+
+ // Return type: refptr_same
+ return CefStreamReaderCppToC::Wrap(_retval);
+}
+
+CEF_EXPORT cef_stream_reader_t* cef_stream_reader_create_for_data(void* data,
+ size_t size) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: data; type: simple_byaddr
+ DCHECK(data);
+ if (!data) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefStreamReader> _retval =
+ CefStreamReader::CreateForData(data, size);
+
+ // Return type: refptr_same
+ return CefStreamReaderCppToC::Wrap(_retval);
+}
+
+CEF_EXPORT cef_stream_reader_t* cef_stream_reader_create_for_handler(
+ cef_read_handler_t* handler) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: handler; type: refptr_diff
+ DCHECK(handler);
+ if (!handler) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefStreamReader> _retval =
+ CefStreamReader::CreateForHandler(CefReadHandlerCToCpp::Wrap(handler));
+
+ // Return type: refptr_same
+ return CefStreamReaderCppToC::Wrap(_retval);
+}
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+size_t CEF_CALLBACK stream_reader_read(struct _cef_stream_reader_t* self,
+ void* ptr,
+ size_t size,
+ size_t n) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: ptr; type: simple_byaddr
+ DCHECK(ptr);
+ if (!ptr) {
+ return 0;
+ }
+
+ // Execute
+ size_t _retval = CefStreamReaderCppToC::Get(self)->Read(ptr, size, n);
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK stream_reader_seek(struct _cef_stream_reader_t* self,
+ int64 offset,
+ int whence) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefStreamReaderCppToC::Get(self)->Seek(offset, whence);
+
+ // Return type: simple
+ return _retval;
+}
+
+int64 CEF_CALLBACK stream_reader_tell(struct _cef_stream_reader_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int64 _retval = CefStreamReaderCppToC::Get(self)->Tell();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK stream_reader_eof(struct _cef_stream_reader_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefStreamReaderCppToC::Get(self)->Eof();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK stream_reader_may_block(struct _cef_stream_reader_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefStreamReaderCppToC::Get(self)->MayBlock();
+
+ // Return type: bool
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefStreamReaderCppToC::CefStreamReaderCppToC() {
+ GetStruct()->read = stream_reader_read;
+ GetStruct()->seek = stream_reader_seek;
+ GetStruct()->tell = stream_reader_tell;
+ GetStruct()->eof = stream_reader_eof;
+ GetStruct()->may_block = stream_reader_may_block;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefStreamReaderCppToC::~CefStreamReaderCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefStreamReader> CefCppToCRefCounted<
+ CefStreamReaderCppToC,
+ CefStreamReader,
+ cef_stream_reader_t>::UnwrapDerived(CefWrapperType type,
+ cef_stream_reader_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefStreamReaderCppToC,
+ CefStreamReader,
+ cef_stream_reader_t>::kWrapperType =
+ WT_STREAM_READER;
diff --git a/libcef_dll/cpptoc/stream_reader_cpptoc.h b/libcef_dll/cpptoc/stream_reader_cpptoc.h
new file mode 100644
index 00000000..d4d5dc5a
--- /dev/null
+++ b/libcef_dll/cpptoc/stream_reader_cpptoc.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=6482aca1d5d2c06d39d226f2d085580abc8eee99$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_STREAM_READER_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_STREAM_READER_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_stream_capi.h"
+#include "include/cef_stream.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefStreamReaderCppToC : public CefCppToCRefCounted<CefStreamReaderCppToC,
+ CefStreamReader,
+ cef_stream_reader_t> {
+ public:
+ CefStreamReaderCppToC();
+ virtual ~CefStreamReaderCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_STREAM_READER_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/stream_writer_cpptoc.cc b/libcef_dll/cpptoc/stream_writer_cpptoc.cc
new file mode 100644
index 00000000..b25a7f75
--- /dev/null
+++ b/libcef_dll/cpptoc/stream_writer_cpptoc.cc
@@ -0,0 +1,192 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=349c01655f473acda59d69d5884ef82bcb5a72a0$
+//
+
+#include "libcef_dll/cpptoc/stream_writer_cpptoc.h"
+#include "libcef_dll/ctocpp/write_handler_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// GLOBAL FUNCTIONS - Body may be edited by hand.
+
+CEF_EXPORT cef_stream_writer_t* cef_stream_writer_create_for_file(
+ const cef_string_t* fileName) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: fileName; type: string_byref_const
+ DCHECK(fileName);
+ if (!fileName) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefStreamWriter> _retval =
+ CefStreamWriter::CreateForFile(CefString(fileName));
+
+ // Return type: refptr_same
+ return CefStreamWriterCppToC::Wrap(_retval);
+}
+
+CEF_EXPORT cef_stream_writer_t* cef_stream_writer_create_for_handler(
+ cef_write_handler_t* handler) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: handler; type: refptr_diff
+ DCHECK(handler);
+ if (!handler) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefStreamWriter> _retval =
+ CefStreamWriter::CreateForHandler(CefWriteHandlerCToCpp::Wrap(handler));
+
+ // Return type: refptr_same
+ return CefStreamWriterCppToC::Wrap(_retval);
+}
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+size_t CEF_CALLBACK stream_writer_write(struct _cef_stream_writer_t* self,
+ const void* ptr,
+ size_t size,
+ size_t n) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: ptr; type: simple_byaddr
+ DCHECK(ptr);
+ if (!ptr) {
+ return 0;
+ }
+
+ // Execute
+ size_t _retval = CefStreamWriterCppToC::Get(self)->Write(ptr, size, n);
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK stream_writer_seek(struct _cef_stream_writer_t* self,
+ int64 offset,
+ int whence) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefStreamWriterCppToC::Get(self)->Seek(offset, whence);
+
+ // Return type: simple
+ return _retval;
+}
+
+int64 CEF_CALLBACK stream_writer_tell(struct _cef_stream_writer_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int64 _retval = CefStreamWriterCppToC::Get(self)->Tell();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK stream_writer_flush(struct _cef_stream_writer_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefStreamWriterCppToC::Get(self)->Flush();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK stream_writer_may_block(struct _cef_stream_writer_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefStreamWriterCppToC::Get(self)->MayBlock();
+
+ // Return type: bool
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefStreamWriterCppToC::CefStreamWriterCppToC() {
+ GetStruct()->write = stream_writer_write;
+ GetStruct()->seek = stream_writer_seek;
+ GetStruct()->tell = stream_writer_tell;
+ GetStruct()->flush = stream_writer_flush;
+ GetStruct()->may_block = stream_writer_may_block;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefStreamWriterCppToC::~CefStreamWriterCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefStreamWriter> CefCppToCRefCounted<
+ CefStreamWriterCppToC,
+ CefStreamWriter,
+ cef_stream_writer_t>::UnwrapDerived(CefWrapperType type,
+ cef_stream_writer_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefStreamWriterCppToC,
+ CefStreamWriter,
+ cef_stream_writer_t>::kWrapperType =
+ WT_STREAM_WRITER;
diff --git a/libcef_dll/cpptoc/stream_writer_cpptoc.h b/libcef_dll/cpptoc/stream_writer_cpptoc.h
new file mode 100644
index 00000000..0a5ed64e
--- /dev/null
+++ b/libcef_dll/cpptoc/stream_writer_cpptoc.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=7b95fc6bea4023038075ee6712eaceb6c0a153a8$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_STREAM_WRITER_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_STREAM_WRITER_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_stream_capi.h"
+#include "include/cef_stream.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefStreamWriterCppToC : public CefCppToCRefCounted<CefStreamWriterCppToC,
+ CefStreamWriter,
+ cef_stream_writer_t> {
+ public:
+ CefStreamWriterCppToC();
+ virtual ~CefStreamWriterCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_STREAM_WRITER_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/string_visitor_cpptoc.cc b/libcef_dll/cpptoc/string_visitor_cpptoc.cc
new file mode 100644
index 00000000..6b6fc514
--- /dev/null
+++ b/libcef_dll/cpptoc/string_visitor_cpptoc.cc
@@ -0,0 +1,66 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=fc666ba470e71976f9fffe58ada81b0c6fc2d95b$
+//
+
+#include "libcef_dll/cpptoc/string_visitor_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK string_visitor_visit(struct _cef_string_visitor_t* self,
+ const cef_string_t* string) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Unverified params: string
+
+ // Execute
+ CefStringVisitorCppToC::Get(self)->Visit(CefString(string));
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefStringVisitorCppToC::CefStringVisitorCppToC() {
+ GetStruct()->visit = string_visitor_visit;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefStringVisitorCppToC::~CefStringVisitorCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefStringVisitor> CefCppToCRefCounted<
+ CefStringVisitorCppToC,
+ CefStringVisitor,
+ cef_string_visitor_t>::UnwrapDerived(CefWrapperType type,
+ cef_string_visitor_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefStringVisitorCppToC,
+ CefStringVisitor,
+ cef_string_visitor_t>::kWrapperType =
+ WT_STRING_VISITOR;
diff --git a/libcef_dll/cpptoc/string_visitor_cpptoc.h b/libcef_dll/cpptoc/string_visitor_cpptoc.h
new file mode 100644
index 00000000..86a2b46f
--- /dev/null
+++ b/libcef_dll/cpptoc/string_visitor_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=8f717e4df178cef8f90d5af081094a4952fcc90e$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_STRING_VISITOR_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_STRING_VISITOR_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_string_visitor_capi.h"
+#include "include/cef_string_visitor.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefStringVisitorCppToC
+ : public CefCppToCRefCounted<CefStringVisitorCppToC,
+ CefStringVisitor,
+ cef_string_visitor_t> {
+ public:
+ CefStringVisitorCppToC();
+ virtual ~CefStringVisitorCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_STRING_VISITOR_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/task_cpptoc.cc b/libcef_dll/cpptoc/task_cpptoc.cc
new file mode 100644
index 00000000..346bb4c8
--- /dev/null
+++ b/libcef_dll/cpptoc/task_cpptoc.cc
@@ -0,0 +1,57 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=9555d03b779dde190621989b6c8a433392093e87$
+//
+
+#include "libcef_dll/cpptoc/task_cpptoc.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK task_execute(struct _cef_task_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefTaskCppToC::Get(self)->Execute();
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefTaskCppToC::CefTaskCppToC() {
+ GetStruct()->execute = task_execute;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefTaskCppToC::~CefTaskCppToC() {}
+
+template <>
+CefRefPtr<CefTask>
+CefCppToCRefCounted<CefTaskCppToC, CefTask, cef_task_t>::UnwrapDerived(
+ CefWrapperType type,
+ cef_task_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCppToCRefCounted<CefTaskCppToC, CefTask, cef_task_t>::kWrapperType =
+ WT_TASK;
diff --git a/libcef_dll/cpptoc/task_cpptoc.h b/libcef_dll/cpptoc/task_cpptoc.h
new file mode 100644
index 00000000..9a702d94
--- /dev/null
+++ b/libcef_dll/cpptoc/task_cpptoc.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=32859b75e638cd76a9319561b675fa3583818905$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_TASK_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_TASK_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_task_capi.h"
+#include "include/cef_task.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefTaskCppToC
+ : public CefCppToCRefCounted<CefTaskCppToC, CefTask, cef_task_t> {
+ public:
+ CefTaskCppToC();
+ virtual ~CefTaskCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_TASK_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/task_runner_cpptoc.cc b/libcef_dll/cpptoc/task_runner_cpptoc.cc
new file mode 100644
index 00000000..3d996fe8
--- /dev/null
+++ b/libcef_dll/cpptoc/task_runner_cpptoc.cc
@@ -0,0 +1,190 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=fe298b392c12586863032c597c4b2f9c3b264b1d$
+//
+
+#include "libcef_dll/cpptoc/task_runner_cpptoc.h"
+#include "libcef_dll/ctocpp/task_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// GLOBAL FUNCTIONS - Body may be edited by hand.
+
+CEF_EXPORT cef_task_runner_t* cef_task_runner_get_for_current_thread() {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ CefRefPtr<CefTaskRunner> _retval = CefTaskRunner::GetForCurrentThread();
+
+ // Return type: refptr_same
+ return CefTaskRunnerCppToC::Wrap(_retval);
+}
+
+CEF_EXPORT cef_task_runner_t* cef_task_runner_get_for_thread(
+ cef_thread_id_t threadId) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ CefRefPtr<CefTaskRunner> _retval = CefTaskRunner::GetForThread(threadId);
+
+ // Return type: refptr_same
+ return CefTaskRunnerCppToC::Wrap(_retval);
+}
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK task_runner_is_same(struct _cef_task_runner_t* self,
+ struct _cef_task_runner_t* that) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: that; type: refptr_same
+ DCHECK(that);
+ if (!that) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefTaskRunnerCppToC::Get(self)->IsSame(CefTaskRunnerCppToC::Unwrap(that));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+task_runner_belongs_to_current_thread(struct _cef_task_runner_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefTaskRunnerCppToC::Get(self)->BelongsToCurrentThread();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK task_runner_belongs_to_thread(struct _cef_task_runner_t* self,
+ cef_thread_id_t threadId) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefTaskRunnerCppToC::Get(self)->BelongsToThread(threadId);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK task_runner_post_task(struct _cef_task_runner_t* self,
+ cef_task_t* task) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: task; type: refptr_diff
+ DCHECK(task);
+ if (!task) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefTaskRunnerCppToC::Get(self)->PostTask(CefTaskCToCpp::Wrap(task));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK task_runner_post_delayed_task(struct _cef_task_runner_t* self,
+ cef_task_t* task,
+ int64 delay_ms) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: task; type: refptr_diff
+ DCHECK(task);
+ if (!task) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefTaskRunnerCppToC::Get(self)->PostDelayedTask(
+ CefTaskCToCpp::Wrap(task), delay_ms);
+
+ // Return type: bool
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefTaskRunnerCppToC::CefTaskRunnerCppToC() {
+ GetStruct()->is_same = task_runner_is_same;
+ GetStruct()->belongs_to_current_thread =
+ task_runner_belongs_to_current_thread;
+ GetStruct()->belongs_to_thread = task_runner_belongs_to_thread;
+ GetStruct()->post_task = task_runner_post_task;
+ GetStruct()->post_delayed_task = task_runner_post_delayed_task;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefTaskRunnerCppToC::~CefTaskRunnerCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefTaskRunner>
+CefCppToCRefCounted<CefTaskRunnerCppToC, CefTaskRunner, cef_task_runner_t>::
+ UnwrapDerived(CefWrapperType type, cef_task_runner_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefTaskRunnerCppToC,
+ CefTaskRunner,
+ cef_task_runner_t>::kWrapperType =
+ WT_TASK_RUNNER;
diff --git a/libcef_dll/cpptoc/task_runner_cpptoc.h b/libcef_dll/cpptoc/task_runner_cpptoc.h
new file mode 100644
index 00000000..d462c7e1
--- /dev/null
+++ b/libcef_dll/cpptoc/task_runner_cpptoc.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=66efea72ce623fbf542496f15d0b5fe33d426286$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_TASK_RUNNER_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_TASK_RUNNER_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_task_capi.h"
+#include "include/cef_task.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefTaskRunnerCppToC : public CefCppToCRefCounted<CefTaskRunnerCppToC,
+ CefTaskRunner,
+ cef_task_runner_t> {
+ public:
+ CefTaskRunnerCppToC();
+ virtual ~CefTaskRunnerCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_TASK_RUNNER_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/test/test_server_connection_cpptoc.cc b/libcef_dll/cpptoc/test/test_server_connection_cpptoc.cc
new file mode 100644
index 00000000..c38ae8c2
--- /dev/null
+++ b/libcef_dll/cpptoc/test/test_server_connection_cpptoc.cc
@@ -0,0 +1,161 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=461cf3d1954bafc2f291894ddf2b366b083bb773$
+//
+
+#include "libcef_dll/cpptoc/test/test_server_connection_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+#include "libcef_dll/transfer_util.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK test_server_connection_send_http200response(
+ struct _cef_test_server_connection_t* self,
+ const cef_string_t* content_type,
+ const void* data,
+ size_t data_size) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: content_type; type: string_byref_const
+ DCHECK(content_type);
+ if (!content_type) {
+ return;
+ }
+ // Verify param: data; type: simple_byaddr
+ DCHECK(data);
+ if (!data) {
+ return;
+ }
+
+ // Execute
+ CefTestServerConnectionCppToC::Get(self)->SendHttp200Response(
+ CefString(content_type), data, data_size);
+}
+
+void CEF_CALLBACK test_server_connection_send_http404response(
+ struct _cef_test_server_connection_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefTestServerConnectionCppToC::Get(self)->SendHttp404Response();
+}
+
+void CEF_CALLBACK test_server_connection_send_http500response(
+ struct _cef_test_server_connection_t* self,
+ const cef_string_t* error_message) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: error_message; type: string_byref_const
+ DCHECK(error_message);
+ if (!error_message) {
+ return;
+ }
+
+ // Execute
+ CefTestServerConnectionCppToC::Get(self)->SendHttp500Response(
+ CefString(error_message));
+}
+
+void CEF_CALLBACK test_server_connection_send_http_response(
+ struct _cef_test_server_connection_t* self,
+ int response_code,
+ const cef_string_t* content_type,
+ const void* data,
+ size_t data_size,
+ cef_string_multimap_t extra_headers) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: content_type; type: string_byref_const
+ DCHECK(content_type);
+ if (!content_type) {
+ return;
+ }
+ // Verify param: data; type: simple_byaddr
+ DCHECK(data);
+ if (!data) {
+ return;
+ }
+ // Unverified params: extra_headers
+
+ // Translate param: extra_headers; type: string_map_multi_byref_const
+ std::multimap<CefString, CefString> extra_headersMultimap;
+ transfer_string_multimap_contents(extra_headers, extra_headersMultimap);
+
+ // Execute
+ CefTestServerConnectionCppToC::Get(self)->SendHttpResponse(
+ response_code, CefString(content_type), data, data_size,
+ extra_headersMultimap);
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefTestServerConnectionCppToC::CefTestServerConnectionCppToC() {
+ GetStruct()->send_http200response =
+ test_server_connection_send_http200response;
+ GetStruct()->send_http404response =
+ test_server_connection_send_http404response;
+ GetStruct()->send_http500response =
+ test_server_connection_send_http500response;
+ GetStruct()->send_http_response = test_server_connection_send_http_response;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefTestServerConnectionCppToC::~CefTestServerConnectionCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefTestServerConnection> CefCppToCRefCounted<
+ CefTestServerConnectionCppToC,
+ CefTestServerConnection,
+ cef_test_server_connection_t>::UnwrapDerived(CefWrapperType type,
+ cef_test_server_connection_t*
+ s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefTestServerConnectionCppToC,
+ CefTestServerConnection,
+ cef_test_server_connection_t>::kWrapperType =
+ WT_TEST_SERVER_CONNECTION;
diff --git a/libcef_dll/cpptoc/test/test_server_connection_cpptoc.h b/libcef_dll/cpptoc/test/test_server_connection_cpptoc.h
new file mode 100644
index 00000000..92baadfa
--- /dev/null
+++ b/libcef_dll/cpptoc/test/test_server_connection_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=da4666f75e56bfc41483f5d5627e9db612364ffb$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_TEST_TEST_SERVER_CONNECTION_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_TEST_TEST_SERVER_CONNECTION_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/test/cef_test_server_capi.h"
+#include "include/test/cef_test_server.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefTestServerConnectionCppToC
+ : public CefCppToCRefCounted<CefTestServerConnectionCppToC,
+ CefTestServerConnection,
+ cef_test_server_connection_t> {
+ public:
+ CefTestServerConnectionCppToC();
+ virtual ~CefTestServerConnectionCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_TEST_TEST_SERVER_CONNECTION_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/test/test_server_cpptoc.cc b/libcef_dll/cpptoc/test/test_server_cpptoc.cc
new file mode 100644
index 00000000..445df72b
--- /dev/null
+++ b/libcef_dll/cpptoc/test/test_server_cpptoc.cc
@@ -0,0 +1,108 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=442e7f211c420aea2bc399024b947f67d83d3a6d$
+//
+
+#include "libcef_dll/cpptoc/test/test_server_cpptoc.h"
+#include "libcef_dll/ctocpp/test/test_server_handler_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// GLOBAL FUNCTIONS - Body may be edited by hand.
+
+CEF_EXPORT cef_test_server_t* cef_test_server_create_and_start(
+ uint16 port,
+ int https_server,
+ cef_test_cert_type_t https_cert_type,
+ struct _cef_test_server_handler_t* handler) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: handler; type: refptr_diff
+ DCHECK(handler);
+ if (!handler) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefTestServer> _retval = CefTestServer::CreateAndStart(
+ port, https_server ? true : false, https_cert_type,
+ CefTestServerHandlerCToCpp::Wrap(handler));
+
+ // Return type: refptr_same
+ return CefTestServerCppToC::Wrap(_retval);
+}
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK test_server_stop(struct _cef_test_server_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefTestServerCppToC::Get(self)->Stop();
+}
+
+cef_string_userfree_t CEF_CALLBACK
+test_server_get_origin(struct _cef_test_server_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefTestServerCppToC::Get(self)->GetOrigin();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefTestServerCppToC::CefTestServerCppToC() {
+ GetStruct()->stop = test_server_stop;
+ GetStruct()->get_origin = test_server_get_origin;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefTestServerCppToC::~CefTestServerCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefTestServer>
+CefCppToCRefCounted<CefTestServerCppToC, CefTestServer, cef_test_server_t>::
+ UnwrapDerived(CefWrapperType type, cef_test_server_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefTestServerCppToC,
+ CefTestServer,
+ cef_test_server_t>::kWrapperType =
+ WT_TEST_SERVER;
diff --git a/libcef_dll/cpptoc/test/test_server_cpptoc.h b/libcef_dll/cpptoc/test/test_server_cpptoc.h
new file mode 100644
index 00000000..0c3bed60
--- /dev/null
+++ b/libcef_dll/cpptoc/test/test_server_cpptoc.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=f6f3d0a111ecd4f978ed7a1c9493679d027367fd$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_TEST_TEST_SERVER_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_TEST_TEST_SERVER_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/test/cef_test_server_capi.h"
+#include "include/test/cef_test_server.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefTestServerCppToC : public CefCppToCRefCounted<CefTestServerCppToC,
+ CefTestServer,
+ cef_test_server_t> {
+ public:
+ CefTestServerCppToC();
+ virtual ~CefTestServerCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_TEST_TEST_SERVER_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/test/test_server_handler_cpptoc.cc b/libcef_dll/cpptoc/test/test_server_handler_cpptoc.cc
new file mode 100644
index 00000000..8e5c00bc
--- /dev/null
+++ b/libcef_dll/cpptoc/test/test_server_handler_cpptoc.cc
@@ -0,0 +1,92 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=d180fbc2710aeb96dc4db266168281c29cc43642$
+//
+
+#include "libcef_dll/cpptoc/test/test_server_handler_cpptoc.h"
+#include "libcef_dll/ctocpp/request_ctocpp.h"
+#include "libcef_dll/ctocpp/test/test_server_connection_ctocpp.h"
+#include "libcef_dll/ctocpp/test/test_server_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK test_server_handler_on_test_server_request(
+ struct _cef_test_server_handler_t* self,
+ cef_test_server_t* server,
+ cef_request_t* request,
+ struct _cef_test_server_connection_t* connection) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: server; type: refptr_diff
+ DCHECK(server);
+ if (!server) {
+ return 0;
+ }
+ // Verify param: request; type: refptr_diff
+ DCHECK(request);
+ if (!request) {
+ return 0;
+ }
+ // Verify param: connection; type: refptr_diff
+ DCHECK(connection);
+ if (!connection) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefTestServerHandlerCppToC::Get(self)->OnTestServerRequest(
+ CefTestServerCToCpp::Wrap(server), CefRequestCToCpp::Wrap(request),
+ CefTestServerConnectionCToCpp::Wrap(connection));
+
+ // Return type: bool
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefTestServerHandlerCppToC::CefTestServerHandlerCppToC() {
+ GetStruct()->on_test_server_request =
+ test_server_handler_on_test_server_request;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefTestServerHandlerCppToC::~CefTestServerHandlerCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefTestServerHandler> CefCppToCRefCounted<
+ CefTestServerHandlerCppToC,
+ CefTestServerHandler,
+ cef_test_server_handler_t>::UnwrapDerived(CefWrapperType type,
+ cef_test_server_handler_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefTestServerHandlerCppToC,
+ CefTestServerHandler,
+ cef_test_server_handler_t>::kWrapperType =
+ WT_TEST_SERVER_HANDLER;
diff --git a/libcef_dll/cpptoc/test/test_server_handler_cpptoc.h b/libcef_dll/cpptoc/test/test_server_handler_cpptoc.h
new file mode 100644
index 00000000..d844b6b7
--- /dev/null
+++ b/libcef_dll/cpptoc/test/test_server_handler_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=c52f8327259f74779b2bb7e16a84b5c245da482b$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_TEST_TEST_SERVER_HANDLER_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_TEST_TEST_SERVER_HANDLER_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/test/cef_test_server_capi.h"
+#include "include/test/cef_test_server.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefTestServerHandlerCppToC
+ : public CefCppToCRefCounted<CefTestServerHandlerCppToC,
+ CefTestServerHandler,
+ cef_test_server_handler_t> {
+ public:
+ CefTestServerHandlerCppToC();
+ virtual ~CefTestServerHandlerCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_TEST_TEST_SERVER_HANDLER_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/test/translator_test_cpptoc.cc b/libcef_dll/cpptoc/test/translator_test_cpptoc.cc
new file mode 100644
index 00000000..d10c506f
--- /dev/null
+++ b/libcef_dll/cpptoc/test/translator_test_cpptoc.cc
@@ -0,0 +1,1758 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=2b8d7a22d62b14176b5e7a9be38c7948544c71b6$
+//
+
+#include "libcef_dll/cpptoc/test/translator_test_cpptoc.h"
+#include <algorithm>
+#include "libcef_dll/cpptoc/test/translator_test_ref_ptr_library_child_cpptoc.h"
+#include "libcef_dll/cpptoc/test/translator_test_ref_ptr_library_cpptoc.h"
+#include "libcef_dll/cpptoc/test/translator_test_scoped_library_child_cpptoc.h"
+#include "libcef_dll/cpptoc/test/translator_test_scoped_library_cpptoc.h"
+#include "libcef_dll/ctocpp/test/translator_test_ref_ptr_client_child_ctocpp.h"
+#include "libcef_dll/ctocpp/test/translator_test_ref_ptr_client_ctocpp.h"
+#include "libcef_dll/ctocpp/test/translator_test_scoped_client_child_ctocpp.h"
+#include "libcef_dll/ctocpp/test/translator_test_scoped_client_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+#include "libcef_dll/transfer_util.h"
+
+// GLOBAL FUNCTIONS - Body may be edited by hand.
+
+CEF_EXPORT cef_translator_test_t* cef_translator_test_create() {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ CefRefPtr<CefTranslatorTest> _retval = CefTranslatorTest::Create();
+
+ // Return type: refptr_same
+ return CefTranslatorTestCppToC::Wrap(_retval);
+}
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK
+translator_test_get_void(struct _cef_translator_test_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefTranslatorTestCppToC::Get(self)->GetVoid();
+}
+
+int CEF_CALLBACK translator_test_get_bool(struct _cef_translator_test_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefTranslatorTestCppToC::Get(self)->GetBool();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK translator_test_get_int(struct _cef_translator_test_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefTranslatorTestCppToC::Get(self)->GetInt();
+
+ // Return type: simple
+ return _retval;
+}
+
+double CEF_CALLBACK
+translator_test_get_double(struct _cef_translator_test_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ double _retval = CefTranslatorTestCppToC::Get(self)->GetDouble();
+
+ // Return type: simple
+ return _retval;
+}
+
+long CEF_CALLBACK
+translator_test_get_long(struct _cef_translator_test_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ long _retval = CefTranslatorTestCppToC::Get(self)->GetLong();
+
+ // Return type: simple
+ return _retval;
+}
+
+size_t CEF_CALLBACK
+translator_test_get_sizet(struct _cef_translator_test_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ size_t _retval = CefTranslatorTestCppToC::Get(self)->GetSizet();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK translator_test_set_void(struct _cef_translator_test_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefTranslatorTestCppToC::Get(self)->SetVoid();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK translator_test_set_bool(struct _cef_translator_test_t* self,
+ int val) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefTranslatorTestCppToC::Get(self)->SetBool(val ? true : false);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK translator_test_set_int(struct _cef_translator_test_t* self,
+ int val) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefTranslatorTestCppToC::Get(self)->SetInt(val);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK translator_test_set_double(struct _cef_translator_test_t* self,
+ double val) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefTranslatorTestCppToC::Get(self)->SetDouble(val);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK translator_test_set_long(struct _cef_translator_test_t* self,
+ long val) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefTranslatorTestCppToC::Get(self)->SetLong(val);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK translator_test_set_sizet(struct _cef_translator_test_t* self,
+ size_t val) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefTranslatorTestCppToC::Get(self)->SetSizet(val);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+translator_test_set_int_list(struct _cef_translator_test_t* self,
+ size_t valCount,
+ int const* val) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: val; type: simple_vec_byref_const
+ DCHECK(valCount == 0 || val);
+ if (valCount > 0 && !val) {
+ return 0;
+ }
+
+ // Translate param: val; type: simple_vec_byref_const
+ std::vector<int> valList;
+ if (valCount > 0) {
+ for (size_t i = 0; i < valCount; ++i) {
+ int valVal = val[i];
+ valList.push_back(valVal);
+ }
+ }
+
+ // Execute
+ bool _retval = CefTranslatorTestCppToC::Get(self)->SetIntList(valList);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+translator_test_get_int_list_by_ref(struct _cef_translator_test_t* self,
+ size_t* valCount,
+ int* val) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: val; type: simple_vec_byref
+ DCHECK(valCount && (*valCount == 0 || val));
+ if (!valCount || (*valCount > 0 && !val)) {
+ return 0;
+ }
+
+ // Translate param: val; type: simple_vec_byref
+ std::vector<int> valList;
+ if (valCount && *valCount > 0 && val) {
+ for (size_t i = 0; i < *valCount; ++i) {
+ valList.push_back(val[i]);
+ }
+ }
+
+ // Execute
+ bool _retval = CefTranslatorTestCppToC::Get(self)->GetIntListByRef(valList);
+
+ // Restore param: val; type: simple_vec_byref
+ if (valCount && val) {
+ *valCount = std::min(valList.size(), *valCount);
+ if (*valCount > 0) {
+ for (size_t i = 0; i < *valCount; ++i) {
+ val[i] = valList[i];
+ }
+ }
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+size_t CEF_CALLBACK
+translator_test_get_int_list_size(struct _cef_translator_test_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ size_t _retval = CefTranslatorTestCppToC::Get(self)->GetIntListSize();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_string_userfree_t CEF_CALLBACK
+translator_test_get_string(struct _cef_translator_test_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefTranslatorTestCppToC::Get(self)->GetString();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+int CEF_CALLBACK translator_test_set_string(struct _cef_translator_test_t* self,
+ const cef_string_t* val) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: val; type: string_byref_const
+ DCHECK(val);
+ if (!val) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefTranslatorTestCppToC::Get(self)->SetString(CefString(val));
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK
+translator_test_get_string_by_ref(struct _cef_translator_test_t* self,
+ cef_string_t* val) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: val; type: string_byref
+ DCHECK(val);
+ if (!val) {
+ return;
+ }
+
+ // Translate param: val; type: string_byref
+ CefString valStr(val);
+
+ // Execute
+ CefTranslatorTestCppToC::Get(self)->GetStringByRef(valStr);
+}
+
+int CEF_CALLBACK
+translator_test_set_string_list(struct _cef_translator_test_t* self,
+ cef_string_list_t val) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: val; type: string_vec_byref_const
+ DCHECK(val);
+ if (!val) {
+ return 0;
+ }
+
+ // Translate param: val; type: string_vec_byref_const
+ std::vector<CefString> valList;
+ transfer_string_list_contents(val, valList);
+
+ // Execute
+ bool _retval = CefTranslatorTestCppToC::Get(self)->SetStringList(valList);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+translator_test_get_string_list_by_ref(struct _cef_translator_test_t* self,
+ cef_string_list_t val) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: val; type: string_vec_byref
+ DCHECK(val);
+ if (!val) {
+ return 0;
+ }
+
+ // Translate param: val; type: string_vec_byref
+ std::vector<CefString> valList;
+ transfer_string_list_contents(val, valList);
+
+ // Execute
+ bool _retval =
+ CefTranslatorTestCppToC::Get(self)->GetStringListByRef(valList);
+
+ // Restore param: val; type: string_vec_byref
+ cef_string_list_clear(val);
+ transfer_string_list_contents(valList, val);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+translator_test_set_string_map(struct _cef_translator_test_t* self,
+ cef_string_map_t val) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: val; type: string_map_single_byref_const
+ DCHECK(val);
+ if (!val) {
+ return 0;
+ }
+
+ // Translate param: val; type: string_map_single_byref_const
+ std::map<CefString, CefString> valMap;
+ transfer_string_map_contents(val, valMap);
+
+ // Execute
+ bool _retval = CefTranslatorTestCppToC::Get(self)->SetStringMap(valMap);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+translator_test_get_string_map_by_ref(struct _cef_translator_test_t* self,
+ cef_string_map_t val) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: val; type: string_map_single_byref
+ DCHECK(val);
+ if (!val) {
+ return 0;
+ }
+
+ // Translate param: val; type: string_map_single_byref
+ std::map<CefString, CefString> valMap;
+ transfer_string_map_contents(val, valMap);
+
+ // Execute
+ bool _retval = CefTranslatorTestCppToC::Get(self)->GetStringMapByRef(valMap);
+
+ // Restore param: val; type: string_map_single_byref
+ cef_string_map_clear(val);
+ transfer_string_map_contents(valMap, val);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+translator_test_set_string_multimap(struct _cef_translator_test_t* self,
+ cef_string_multimap_t val) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: val; type: string_map_multi_byref_const
+ DCHECK(val);
+ if (!val) {
+ return 0;
+ }
+
+ // Translate param: val; type: string_map_multi_byref_const
+ std::multimap<CefString, CefString> valMultimap;
+ transfer_string_multimap_contents(val, valMultimap);
+
+ // Execute
+ bool _retval =
+ CefTranslatorTestCppToC::Get(self)->SetStringMultimap(valMultimap);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+translator_test_get_string_multimap_by_ref(struct _cef_translator_test_t* self,
+ cef_string_multimap_t val) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: val; type: string_map_multi_byref
+ DCHECK(val);
+ if (!val) {
+ return 0;
+ }
+
+ // Translate param: val; type: string_map_multi_byref
+ std::multimap<CefString, CefString> valMultimap;
+ transfer_string_multimap_contents(val, valMultimap);
+
+ // Execute
+ bool _retval =
+ CefTranslatorTestCppToC::Get(self)->GetStringMultimapByRef(valMultimap);
+
+ // Restore param: val; type: string_map_multi_byref
+ cef_string_multimap_clear(val);
+ transfer_string_multimap_contents(valMultimap, val);
+
+ // Return type: bool
+ return _retval;
+}
+
+cef_point_t CEF_CALLBACK
+translator_test_get_point(struct _cef_translator_test_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefPoint();
+ }
+
+ // Execute
+ cef_point_t _retval = CefTranslatorTestCppToC::Get(self)->GetPoint();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK translator_test_set_point(struct _cef_translator_test_t* self,
+ const cef_point_t* val) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: val; type: simple_byref_const
+ DCHECK(val);
+ if (!val) {
+ return 0;
+ }
+
+ // Translate param: val; type: simple_byref_const
+ CefPoint valVal = val ? *val : CefPoint();
+
+ // Execute
+ bool _retval = CefTranslatorTestCppToC::Get(self)->SetPoint(valVal);
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK
+translator_test_get_point_by_ref(struct _cef_translator_test_t* self,
+ cef_point_t* val) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: val; type: simple_byref
+ DCHECK(val);
+ if (!val) {
+ return;
+ }
+
+ // Translate param: val; type: simple_byref
+ CefPoint valVal = val ? *val : CefPoint();
+
+ // Execute
+ CefTranslatorTestCppToC::Get(self)->GetPointByRef(valVal);
+
+ // Restore param: val; type: simple_byref
+ if (val) {
+ *val = valVal;
+ }
+}
+
+int CEF_CALLBACK
+translator_test_set_point_list(struct _cef_translator_test_t* self,
+ size_t valCount,
+ cef_point_t const* val) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: val; type: simple_vec_byref_const
+ DCHECK(valCount == 0 || val);
+ if (valCount > 0 && !val) {
+ return 0;
+ }
+
+ // Translate param: val; type: simple_vec_byref_const
+ std::vector<CefPoint> valList;
+ if (valCount > 0) {
+ for (size_t i = 0; i < valCount; ++i) {
+ CefPoint valVal = val[i];
+ valList.push_back(valVal);
+ }
+ }
+
+ // Execute
+ bool _retval = CefTranslatorTestCppToC::Get(self)->SetPointList(valList);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+translator_test_get_point_list_by_ref(struct _cef_translator_test_t* self,
+ size_t* valCount,
+ cef_point_t* val) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: val; type: simple_vec_byref
+ DCHECK(valCount && (*valCount == 0 || val));
+ if (!valCount || (*valCount > 0 && !val)) {
+ return 0;
+ }
+
+ // Translate param: val; type: simple_vec_byref
+ std::vector<CefPoint> valList;
+ if (valCount && *valCount > 0 && val) {
+ for (size_t i = 0; i < *valCount; ++i) {
+ valList.push_back(val[i]);
+ }
+ }
+
+ // Execute
+ bool _retval = CefTranslatorTestCppToC::Get(self)->GetPointListByRef(valList);
+
+ // Restore param: val; type: simple_vec_byref
+ if (valCount && val) {
+ *valCount = std::min(valList.size(), *valCount);
+ if (*valCount > 0) {
+ for (size_t i = 0; i < *valCount; ++i) {
+ val[i] = valList[i];
+ }
+ }
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+size_t CEF_CALLBACK
+translator_test_get_point_list_size(struct _cef_translator_test_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ size_t _retval = CefTranslatorTestCppToC::Get(self)->GetPointListSize();
+
+ // Return type: simple
+ return _retval;
+}
+
+struct _cef_translator_test_ref_ptr_library_t* CEF_CALLBACK
+translator_test_get_ref_ptr_library(struct _cef_translator_test_t* self,
+ int val) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefTranslatorTestRefPtrLibrary> _retval =
+ CefTranslatorTestCppToC::Get(self)->GetRefPtrLibrary(val);
+
+ // Return type: refptr_same
+ return CefTranslatorTestRefPtrLibraryCppToC::Wrap(_retval);
+}
+
+int CEF_CALLBACK translator_test_set_ref_ptr_library(
+ struct _cef_translator_test_t* self,
+ struct _cef_translator_test_ref_ptr_library_t* val) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: val; type: refptr_same
+ DCHECK(val);
+ if (!val) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefTranslatorTestCppToC::Get(self)->SetRefPtrLibrary(
+ CefTranslatorTestRefPtrLibraryCppToC::Unwrap(val));
+
+ // Return type: simple
+ return _retval;
+}
+
+struct _cef_translator_test_ref_ptr_library_t* CEF_CALLBACK
+translator_test_set_ref_ptr_library_and_return(
+ struct _cef_translator_test_t* self,
+ struct _cef_translator_test_ref_ptr_library_t* val) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+ // Verify param: val; type: refptr_same
+ DCHECK(val);
+ if (!val) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefTranslatorTestRefPtrLibrary> _retval =
+ CefTranslatorTestCppToC::Get(self)->SetRefPtrLibraryAndReturn(
+ CefTranslatorTestRefPtrLibraryCppToC::Unwrap(val));
+
+ // Return type: refptr_same
+ return CefTranslatorTestRefPtrLibraryCppToC::Wrap(_retval);
+}
+
+int CEF_CALLBACK translator_test_set_child_ref_ptr_library(
+ struct _cef_translator_test_t* self,
+ struct _cef_translator_test_ref_ptr_library_child_t* val) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: val; type: refptr_same
+ DCHECK(val);
+ if (!val) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefTranslatorTestCppToC::Get(self)->SetChildRefPtrLibrary(
+ CefTranslatorTestRefPtrLibraryChildCppToC::Unwrap(val));
+
+ // Return type: simple
+ return _retval;
+}
+
+struct _cef_translator_test_ref_ptr_library_t* CEF_CALLBACK
+translator_test_set_child_ref_ptr_library_and_return_parent(
+ struct _cef_translator_test_t* self,
+ struct _cef_translator_test_ref_ptr_library_child_t* val) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+ // Verify param: val; type: refptr_same
+ DCHECK(val);
+ if (!val) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefTranslatorTestRefPtrLibrary> _retval =
+ CefTranslatorTestCppToC::Get(self)->SetChildRefPtrLibraryAndReturnParent(
+ CefTranslatorTestRefPtrLibraryChildCppToC::Unwrap(val));
+
+ // Return type: refptr_same
+ return CefTranslatorTestRefPtrLibraryCppToC::Wrap(_retval);
+}
+
+int CEF_CALLBACK translator_test_set_ref_ptr_library_list(
+ struct _cef_translator_test_t* self,
+ size_t valCount,
+ struct _cef_translator_test_ref_ptr_library_t* const* val,
+ int val1,
+ int val2) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: val; type: refptr_vec_same_byref_const
+ DCHECK(valCount == 0 || val);
+ if (valCount > 0 && !val) {
+ return 0;
+ }
+
+ // Translate param: val; type: refptr_vec_same_byref_const
+ std::vector<CefRefPtr<CefTranslatorTestRefPtrLibrary>> valList;
+ if (valCount > 0) {
+ for (size_t i = 0; i < valCount; ++i) {
+ CefRefPtr<CefTranslatorTestRefPtrLibrary> valVal =
+ CefTranslatorTestRefPtrLibraryCppToC::Unwrap(val[i]);
+ valList.push_back(valVal);
+ }
+ }
+
+ // Execute
+ bool _retval = CefTranslatorTestCppToC::Get(self)->SetRefPtrLibraryList(
+ valList, val1, val2);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK translator_test_get_ref_ptr_library_list_by_ref(
+ struct _cef_translator_test_t* self,
+ size_t* valCount,
+ struct _cef_translator_test_ref_ptr_library_t** val,
+ int val1,
+ int val2) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: val; type: refptr_vec_same_byref
+ DCHECK(valCount && (*valCount == 0 || val));
+ if (!valCount || (*valCount > 0 && !val)) {
+ return 0;
+ }
+
+ // Translate param: val; type: refptr_vec_same_byref
+ std::vector<CefRefPtr<CefTranslatorTestRefPtrLibrary>> valList;
+ if (valCount && *valCount > 0 && val) {
+ for (size_t i = 0; i < *valCount; ++i) {
+ valList.push_back(CefTranslatorTestRefPtrLibraryCppToC::Unwrap(val[i]));
+ }
+ }
+
+ // Execute
+ bool _retval = CefTranslatorTestCppToC::Get(self)->GetRefPtrLibraryListByRef(
+ valList, val1, val2);
+
+ // Restore param: val; type: refptr_vec_same_byref
+ if (valCount && val) {
+ *valCount = std::min(valList.size(), *valCount);
+ if (*valCount > 0) {
+ for (size_t i = 0; i < *valCount; ++i) {
+ val[i] = CefTranslatorTestRefPtrLibraryCppToC::Wrap(valList[i]);
+ }
+ }
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+size_t CEF_CALLBACK translator_test_get_ref_ptr_library_list_size(
+ struct _cef_translator_test_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ size_t _retval =
+ CefTranslatorTestCppToC::Get(self)->GetRefPtrLibraryListSize();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK translator_test_set_ref_ptr_client(
+ struct _cef_translator_test_t* self,
+ struct _cef_translator_test_ref_ptr_client_t* val) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: val; type: refptr_diff
+ DCHECK(val);
+ if (!val) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefTranslatorTestCppToC::Get(self)->SetRefPtrClient(
+ CefTranslatorTestRefPtrClientCToCpp::Wrap(val));
+
+ // Return type: simple
+ return _retval;
+}
+
+struct _cef_translator_test_ref_ptr_client_t* CEF_CALLBACK
+translator_test_set_ref_ptr_client_and_return(
+ struct _cef_translator_test_t* self,
+ struct _cef_translator_test_ref_ptr_client_t* val) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+ // Verify param: val; type: refptr_diff
+ DCHECK(val);
+ if (!val) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefTranslatorTestRefPtrClient> _retval =
+ CefTranslatorTestCppToC::Get(self)->SetRefPtrClientAndReturn(
+ CefTranslatorTestRefPtrClientCToCpp::Wrap(val));
+
+ // Return type: refptr_diff
+ return CefTranslatorTestRefPtrClientCToCpp::Unwrap(_retval);
+}
+
+int CEF_CALLBACK translator_test_set_child_ref_ptr_client(
+ struct _cef_translator_test_t* self,
+ struct _cef_translator_test_ref_ptr_client_child_t* val) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: val; type: refptr_diff
+ DCHECK(val);
+ if (!val) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefTranslatorTestCppToC::Get(self)->SetChildRefPtrClient(
+ CefTranslatorTestRefPtrClientChildCToCpp::Wrap(val));
+
+ // Return type: simple
+ return _retval;
+}
+
+struct _cef_translator_test_ref_ptr_client_t* CEF_CALLBACK
+translator_test_set_child_ref_ptr_client_and_return_parent(
+ struct _cef_translator_test_t* self,
+ struct _cef_translator_test_ref_ptr_client_child_t* val) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+ // Verify param: val; type: refptr_diff
+ DCHECK(val);
+ if (!val) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefTranslatorTestRefPtrClient> _retval =
+ CefTranslatorTestCppToC::Get(self)->SetChildRefPtrClientAndReturnParent(
+ CefTranslatorTestRefPtrClientChildCToCpp::Wrap(val));
+
+ // Return type: refptr_diff
+ return CefTranslatorTestRefPtrClientCToCpp::Unwrap(_retval);
+}
+
+int CEF_CALLBACK translator_test_set_ref_ptr_client_list(
+ struct _cef_translator_test_t* self,
+ size_t valCount,
+ struct _cef_translator_test_ref_ptr_client_t* const* val,
+ int val1,
+ int val2) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: val; type: refptr_vec_diff_byref_const
+ DCHECK(valCount == 0 || val);
+ if (valCount > 0 && !val) {
+ return 0;
+ }
+
+ // Translate param: val; type: refptr_vec_diff_byref_const
+ std::vector<CefRefPtr<CefTranslatorTestRefPtrClient>> valList;
+ if (valCount > 0) {
+ for (size_t i = 0; i < valCount; ++i) {
+ CefRefPtr<CefTranslatorTestRefPtrClient> valVal =
+ CefTranslatorTestRefPtrClientCToCpp::Wrap(val[i]);
+ valList.push_back(valVal);
+ }
+ }
+
+ // Execute
+ bool _retval = CefTranslatorTestCppToC::Get(self)->SetRefPtrClientList(
+ valList, val1, val2);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK translator_test_get_ref_ptr_client_list_by_ref(
+ struct _cef_translator_test_t* self,
+ size_t* valCount,
+ struct _cef_translator_test_ref_ptr_client_t** val,
+ struct _cef_translator_test_ref_ptr_client_t* val1,
+ struct _cef_translator_test_ref_ptr_client_t* val2) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: val; type: refptr_vec_diff_byref
+ DCHECK(valCount && (*valCount == 0 || val));
+ if (!valCount || (*valCount > 0 && !val)) {
+ return 0;
+ }
+ // Verify param: val1; type: refptr_diff
+ DCHECK(val1);
+ if (!val1) {
+ return 0;
+ }
+ // Verify param: val2; type: refptr_diff
+ DCHECK(val2);
+ if (!val2) {
+ return 0;
+ }
+
+ // Translate param: val; type: refptr_vec_diff_byref
+ std::vector<CefRefPtr<CefTranslatorTestRefPtrClient>> valList;
+ if (valCount && *valCount > 0 && val) {
+ for (size_t i = 0; i < *valCount; ++i) {
+ valList.push_back(CefTranslatorTestRefPtrClientCToCpp::Wrap(val[i]));
+ }
+ }
+
+ // Execute
+ bool _retval = CefTranslatorTestCppToC::Get(self)->GetRefPtrClientListByRef(
+ valList, CefTranslatorTestRefPtrClientCToCpp::Wrap(val1),
+ CefTranslatorTestRefPtrClientCToCpp::Wrap(val2));
+
+ // Restore param: val; type: refptr_vec_diff_byref
+ if (valCount && val) {
+ *valCount = std::min(valList.size(), *valCount);
+ if (*valCount > 0) {
+ for (size_t i = 0; i < *valCount; ++i) {
+ val[i] = CefTranslatorTestRefPtrClientCToCpp::Unwrap(valList[i]);
+ }
+ }
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+size_t CEF_CALLBACK translator_test_get_ref_ptr_client_list_size(
+ struct _cef_translator_test_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ size_t _retval =
+ CefTranslatorTestCppToC::Get(self)->GetRefPtrClientListSize();
+
+ // Return type: simple
+ return _retval;
+}
+
+struct _cef_translator_test_scoped_library_t* CEF_CALLBACK
+translator_test_get_own_ptr_library(struct _cef_translator_test_t* self,
+ int val) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefOwnPtr<CefTranslatorTestScopedLibrary> _retval =
+ CefTranslatorTestCppToC::Get(self)->GetOwnPtrLibrary(val);
+
+ // Return type: ownptr_same
+ return CefTranslatorTestScopedLibraryCppToC::WrapOwn(std::move(_retval));
+}
+
+int CEF_CALLBACK translator_test_set_own_ptr_library(
+ struct _cef_translator_test_t* self,
+ struct _cef_translator_test_scoped_library_t* val) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: val; type: ownptr_same
+ DCHECK(val);
+ if (!val) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefTranslatorTestCppToC::Get(self)->SetOwnPtrLibrary(
+ CefTranslatorTestScopedLibraryCppToC::UnwrapOwn(val));
+
+ // Return type: simple
+ return _retval;
+}
+
+struct _cef_translator_test_scoped_library_t* CEF_CALLBACK
+translator_test_set_own_ptr_library_and_return(
+ struct _cef_translator_test_t* self,
+ struct _cef_translator_test_scoped_library_t* val) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+ // Verify param: val; type: ownptr_same
+ DCHECK(val);
+ if (!val) {
+ return NULL;
+ }
+
+ // Execute
+ CefOwnPtr<CefTranslatorTestScopedLibrary> _retval =
+ CefTranslatorTestCppToC::Get(self)->SetOwnPtrLibraryAndReturn(
+ CefTranslatorTestScopedLibraryCppToC::UnwrapOwn(val));
+
+ // Return type: ownptr_same
+ return CefTranslatorTestScopedLibraryCppToC::WrapOwn(std::move(_retval));
+}
+
+int CEF_CALLBACK translator_test_set_child_own_ptr_library(
+ struct _cef_translator_test_t* self,
+ struct _cef_translator_test_scoped_library_child_t* val) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: val; type: ownptr_same
+ DCHECK(val);
+ if (!val) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefTranslatorTestCppToC::Get(self)->SetChildOwnPtrLibrary(
+ CefTranslatorTestScopedLibraryChildCppToC::UnwrapOwn(val));
+
+ // Return type: simple
+ return _retval;
+}
+
+struct _cef_translator_test_scoped_library_t* CEF_CALLBACK
+translator_test_set_child_own_ptr_library_and_return_parent(
+ struct _cef_translator_test_t* self,
+ struct _cef_translator_test_scoped_library_child_t* val) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+ // Verify param: val; type: ownptr_same
+ DCHECK(val);
+ if (!val) {
+ return NULL;
+ }
+
+ // Execute
+ CefOwnPtr<CefTranslatorTestScopedLibrary> _retval =
+ CefTranslatorTestCppToC::Get(self)->SetChildOwnPtrLibraryAndReturnParent(
+ CefTranslatorTestScopedLibraryChildCppToC::UnwrapOwn(val));
+
+ // Return type: ownptr_same
+ return CefTranslatorTestScopedLibraryCppToC::WrapOwn(std::move(_retval));
+}
+
+int CEF_CALLBACK translator_test_set_own_ptr_client(
+ struct _cef_translator_test_t* self,
+ struct _cef_translator_test_scoped_client_t* val) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: val; type: ownptr_diff
+ DCHECK(val);
+ if (!val) {
+ return 0;
+ }
+
+ // Translate param: val; type: ownptr_diff
+ CefOwnPtr<CefTranslatorTestScopedClient> valPtr(
+ CefTranslatorTestScopedClientCToCpp::Wrap(val));
+
+ // Execute
+ int _retval =
+ CefTranslatorTestCppToC::Get(self)->SetOwnPtrClient(std::move(valPtr));
+
+ // Return type: simple
+ return _retval;
+}
+
+struct _cef_translator_test_scoped_client_t* CEF_CALLBACK
+translator_test_set_own_ptr_client_and_return(
+ struct _cef_translator_test_t* self,
+ struct _cef_translator_test_scoped_client_t* val) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+ // Verify param: val; type: ownptr_diff
+ DCHECK(val);
+ if (!val) {
+ return NULL;
+ }
+
+ // Translate param: val; type: ownptr_diff
+ CefOwnPtr<CefTranslatorTestScopedClient> valPtr(
+ CefTranslatorTestScopedClientCToCpp::Wrap(val));
+
+ // Execute
+ CefOwnPtr<CefTranslatorTestScopedClient> _retval =
+ CefTranslatorTestCppToC::Get(self)->SetOwnPtrClientAndReturn(
+ std::move(valPtr));
+
+ // Return type: ownptr_diff
+ return CefTranslatorTestScopedClientCToCpp::UnwrapOwn(std::move(_retval));
+}
+
+int CEF_CALLBACK translator_test_set_child_own_ptr_client(
+ struct _cef_translator_test_t* self,
+ struct _cef_translator_test_scoped_client_child_t* val) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: val; type: ownptr_diff
+ DCHECK(val);
+ if (!val) {
+ return 0;
+ }
+
+ // Translate param: val; type: ownptr_diff
+ CefOwnPtr<CefTranslatorTestScopedClientChild> valPtr(
+ CefTranslatorTestScopedClientChildCToCpp::Wrap(val));
+
+ // Execute
+ int _retval = CefTranslatorTestCppToC::Get(self)->SetChildOwnPtrClient(
+ std::move(valPtr));
+
+ // Return type: simple
+ return _retval;
+}
+
+struct _cef_translator_test_scoped_client_t* CEF_CALLBACK
+translator_test_set_child_own_ptr_client_and_return_parent(
+ struct _cef_translator_test_t* self,
+ struct _cef_translator_test_scoped_client_child_t* val) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+ // Verify param: val; type: ownptr_diff
+ DCHECK(val);
+ if (!val) {
+ return NULL;
+ }
+
+ // Translate param: val; type: ownptr_diff
+ CefOwnPtr<CefTranslatorTestScopedClientChild> valPtr(
+ CefTranslatorTestScopedClientChildCToCpp::Wrap(val));
+
+ // Execute
+ CefOwnPtr<CefTranslatorTestScopedClient> _retval =
+ CefTranslatorTestCppToC::Get(self)->SetChildOwnPtrClientAndReturnParent(
+ std::move(valPtr));
+
+ // Return type: ownptr_diff
+ return CefTranslatorTestScopedClientCToCpp::UnwrapOwn(std::move(_retval));
+}
+
+int CEF_CALLBACK translator_test_set_raw_ptr_library(
+ struct _cef_translator_test_t* self,
+ struct _cef_translator_test_scoped_library_t* val) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: val; type: rawptr_same
+ DCHECK(val);
+ if (!val) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefTranslatorTestCppToC::Get(self)->SetRawPtrLibrary(
+ CefTranslatorTestScopedLibraryCppToC::UnwrapRaw(val));
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK translator_test_set_child_raw_ptr_library(
+ struct _cef_translator_test_t* self,
+ struct _cef_translator_test_scoped_library_child_t* val) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: val; type: rawptr_same
+ DCHECK(val);
+ if (!val) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefTranslatorTestCppToC::Get(self)->SetChildRawPtrLibrary(
+ CefTranslatorTestScopedLibraryChildCppToC::UnwrapRaw(val));
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK translator_test_set_raw_ptr_library_list(
+ struct _cef_translator_test_t* self,
+ size_t valCount,
+ struct _cef_translator_test_scoped_library_t* const* val,
+ int val1,
+ int val2) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: val; type: rawptr_vec_same_byref_const
+ DCHECK(valCount == 0 || val);
+ if (valCount > 0 && !val) {
+ return 0;
+ }
+
+ // Translate param: val; type: rawptr_vec_same_byref_const
+ std::vector<CefRawPtr<CefTranslatorTestScopedLibrary>> valList;
+ if (valCount > 0) {
+ for (size_t i = 0; i < valCount; ++i) {
+ CefRawPtr<CefTranslatorTestScopedLibrary> valVal =
+ CefTranslatorTestScopedLibraryCppToC::UnwrapRaw(val[i]);
+ valList.push_back(valVal);
+ }
+ }
+
+ // Execute
+ bool _retval = CefTranslatorTestCppToC::Get(self)->SetRawPtrLibraryList(
+ valList, val1, val2);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK translator_test_set_raw_ptr_client(
+ struct _cef_translator_test_t* self,
+ struct _cef_translator_test_scoped_client_t* val) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: val; type: rawptr_diff
+ DCHECK(val);
+ if (!val) {
+ return 0;
+ }
+
+ // Translate param: val; type: rawptr_diff
+ CefOwnPtr<CefTranslatorTestScopedClient> valPtr(
+ CefTranslatorTestScopedClientCToCpp::Wrap(val));
+
+ // Execute
+ int _retval =
+ CefTranslatorTestCppToC::Get(self)->SetRawPtrClient(valPtr.get());
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK translator_test_set_child_raw_ptr_client(
+ struct _cef_translator_test_t* self,
+ struct _cef_translator_test_scoped_client_child_t* val) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: val; type: rawptr_diff
+ DCHECK(val);
+ if (!val) {
+ return 0;
+ }
+
+ // Translate param: val; type: rawptr_diff
+ CefOwnPtr<CefTranslatorTestScopedClientChild> valPtr(
+ CefTranslatorTestScopedClientChildCToCpp::Wrap(val));
+
+ // Execute
+ int _retval =
+ CefTranslatorTestCppToC::Get(self)->SetChildRawPtrClient(valPtr.get());
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK translator_test_set_raw_ptr_client_list(
+ struct _cef_translator_test_t* self,
+ size_t valCount,
+ struct _cef_translator_test_scoped_client_t* const* val,
+ int val1,
+ int val2) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: val; type: rawptr_vec_diff_byref_const
+ DCHECK(valCount == 0 || val);
+ if (valCount > 0 && !val) {
+ return 0;
+ }
+
+ // Translate param: val; type: rawptr_vec_diff_byref_const
+ std::vector<CefRawPtr<CefTranslatorTestScopedClient>> valList;
+ if (valCount > 0) {
+ for (size_t i = 0; i < valCount; ++i) {
+ CefRawPtr<CefTranslatorTestScopedClient> valVal =
+ CefTranslatorTestScopedClientCToCpp::Wrap(val[i]).release();
+ valList.push_back(valVal);
+ }
+ }
+
+ // Execute
+ bool _retval = CefTranslatorTestCppToC::Get(self)->SetRawPtrClientList(
+ valList, val1, val2);
+
+ // Restore param: val; type: rawptr_vec_diff_byref_const
+ if (valCount > 0) {
+ for (size_t i = 0; i < valCount; ++i) {
+ delete valList[i];
+ }
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefTranslatorTestCppToC::CefTranslatorTestCppToC() {
+ GetStruct()->get_void = translator_test_get_void;
+ GetStruct()->get_bool = translator_test_get_bool;
+ GetStruct()->get_int = translator_test_get_int;
+ GetStruct()->get_double = translator_test_get_double;
+ GetStruct()->get_long = translator_test_get_long;
+ GetStruct()->get_sizet = translator_test_get_sizet;
+ GetStruct()->set_void = translator_test_set_void;
+ GetStruct()->set_bool = translator_test_set_bool;
+ GetStruct()->set_int = translator_test_set_int;
+ GetStruct()->set_double = translator_test_set_double;
+ GetStruct()->set_long = translator_test_set_long;
+ GetStruct()->set_sizet = translator_test_set_sizet;
+ GetStruct()->set_int_list = translator_test_set_int_list;
+ GetStruct()->get_int_list_by_ref = translator_test_get_int_list_by_ref;
+ GetStruct()->get_int_list_size = translator_test_get_int_list_size;
+ GetStruct()->get_string = translator_test_get_string;
+ GetStruct()->set_string = translator_test_set_string;
+ GetStruct()->get_string_by_ref = translator_test_get_string_by_ref;
+ GetStruct()->set_string_list = translator_test_set_string_list;
+ GetStruct()->get_string_list_by_ref = translator_test_get_string_list_by_ref;
+ GetStruct()->set_string_map = translator_test_set_string_map;
+ GetStruct()->get_string_map_by_ref = translator_test_get_string_map_by_ref;
+ GetStruct()->set_string_multimap = translator_test_set_string_multimap;
+ GetStruct()->get_string_multimap_by_ref =
+ translator_test_get_string_multimap_by_ref;
+ GetStruct()->get_point = translator_test_get_point;
+ GetStruct()->set_point = translator_test_set_point;
+ GetStruct()->get_point_by_ref = translator_test_get_point_by_ref;
+ GetStruct()->set_point_list = translator_test_set_point_list;
+ GetStruct()->get_point_list_by_ref = translator_test_get_point_list_by_ref;
+ GetStruct()->get_point_list_size = translator_test_get_point_list_size;
+ GetStruct()->get_ref_ptr_library = translator_test_get_ref_ptr_library;
+ GetStruct()->set_ref_ptr_library = translator_test_set_ref_ptr_library;
+ GetStruct()->set_ref_ptr_library_and_return =
+ translator_test_set_ref_ptr_library_and_return;
+ GetStruct()->set_child_ref_ptr_library =
+ translator_test_set_child_ref_ptr_library;
+ GetStruct()->set_child_ref_ptr_library_and_return_parent =
+ translator_test_set_child_ref_ptr_library_and_return_parent;
+ GetStruct()->set_ref_ptr_library_list =
+ translator_test_set_ref_ptr_library_list;
+ GetStruct()->get_ref_ptr_library_list_by_ref =
+ translator_test_get_ref_ptr_library_list_by_ref;
+ GetStruct()->get_ref_ptr_library_list_size =
+ translator_test_get_ref_ptr_library_list_size;
+ GetStruct()->set_ref_ptr_client = translator_test_set_ref_ptr_client;
+ GetStruct()->set_ref_ptr_client_and_return =
+ translator_test_set_ref_ptr_client_and_return;
+ GetStruct()->set_child_ref_ptr_client =
+ translator_test_set_child_ref_ptr_client;
+ GetStruct()->set_child_ref_ptr_client_and_return_parent =
+ translator_test_set_child_ref_ptr_client_and_return_parent;
+ GetStruct()->set_ref_ptr_client_list =
+ translator_test_set_ref_ptr_client_list;
+ GetStruct()->get_ref_ptr_client_list_by_ref =
+ translator_test_get_ref_ptr_client_list_by_ref;
+ GetStruct()->get_ref_ptr_client_list_size =
+ translator_test_get_ref_ptr_client_list_size;
+ GetStruct()->get_own_ptr_library = translator_test_get_own_ptr_library;
+ GetStruct()->set_own_ptr_library = translator_test_set_own_ptr_library;
+ GetStruct()->set_own_ptr_library_and_return =
+ translator_test_set_own_ptr_library_and_return;
+ GetStruct()->set_child_own_ptr_library =
+ translator_test_set_child_own_ptr_library;
+ GetStruct()->set_child_own_ptr_library_and_return_parent =
+ translator_test_set_child_own_ptr_library_and_return_parent;
+ GetStruct()->set_own_ptr_client = translator_test_set_own_ptr_client;
+ GetStruct()->set_own_ptr_client_and_return =
+ translator_test_set_own_ptr_client_and_return;
+ GetStruct()->set_child_own_ptr_client =
+ translator_test_set_child_own_ptr_client;
+ GetStruct()->set_child_own_ptr_client_and_return_parent =
+ translator_test_set_child_own_ptr_client_and_return_parent;
+ GetStruct()->set_raw_ptr_library = translator_test_set_raw_ptr_library;
+ GetStruct()->set_child_raw_ptr_library =
+ translator_test_set_child_raw_ptr_library;
+ GetStruct()->set_raw_ptr_library_list =
+ translator_test_set_raw_ptr_library_list;
+ GetStruct()->set_raw_ptr_client = translator_test_set_raw_ptr_client;
+ GetStruct()->set_child_raw_ptr_client =
+ translator_test_set_child_raw_ptr_client;
+ GetStruct()->set_raw_ptr_client_list =
+ translator_test_set_raw_ptr_client_list;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefTranslatorTestCppToC::~CefTranslatorTestCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefTranslatorTest> CefCppToCRefCounted<
+ CefTranslatorTestCppToC,
+ CefTranslatorTest,
+ cef_translator_test_t>::UnwrapDerived(CefWrapperType type,
+ cef_translator_test_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefTranslatorTestCppToC,
+ CefTranslatorTest,
+ cef_translator_test_t>::kWrapperType =
+ WT_TRANSLATOR_TEST;
diff --git a/libcef_dll/cpptoc/test/translator_test_cpptoc.h b/libcef_dll/cpptoc/test/translator_test_cpptoc.h
new file mode 100644
index 00000000..c84b4700
--- /dev/null
+++ b/libcef_dll/cpptoc/test/translator_test_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=5f0f8e9729af10fb258c197facf57ae150969f1a$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_TEST_TRANSLATOR_TEST_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_TEST_TRANSLATOR_TEST_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/test/cef_translator_test_capi.h"
+#include "include/test/cef_translator_test.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefTranslatorTestCppToC
+ : public CefCppToCRefCounted<CefTranslatorTestCppToC,
+ CefTranslatorTest,
+ cef_translator_test_t> {
+ public:
+ CefTranslatorTestCppToC();
+ virtual ~CefTranslatorTestCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_TEST_TRANSLATOR_TEST_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/test/translator_test_ref_ptr_client_child_cpptoc.cc b/libcef_dll/cpptoc/test/translator_test_ref_ptr_client_child_cpptoc.cc
new file mode 100644
index 00000000..0a42640d
--- /dev/null
+++ b/libcef_dll/cpptoc/test/translator_test_ref_ptr_client_child_cpptoc.cc
@@ -0,0 +1,96 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=56384b27dfcbd43965ef7fd5bf521d56fb40766d$
+//
+
+#include "libcef_dll/cpptoc/test/translator_test_ref_ptr_client_child_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK translator_test_ref_ptr_client_child_get_other_value(
+ struct _cef_translator_test_ref_ptr_client_child_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval =
+ CefTranslatorTestRefPtrClientChildCppToC::Get(self)->GetOtherValue();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK translator_test_ref_ptr_client_child_get_value(
+ struct _cef_translator_test_ref_ptr_client_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval =
+ CefTranslatorTestRefPtrClientChildCppToC::Get(
+ reinterpret_cast<cef_translator_test_ref_ptr_client_child_t*>(self))
+ ->GetValue();
+
+ // Return type: simple
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefTranslatorTestRefPtrClientChildCppToC::
+ CefTranslatorTestRefPtrClientChildCppToC() {
+ GetStruct()->get_other_value =
+ translator_test_ref_ptr_client_child_get_other_value;
+ GetStruct()->base.get_value = translator_test_ref_ptr_client_child_get_value;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefTranslatorTestRefPtrClientChildCppToC::
+ ~CefTranslatorTestRefPtrClientChildCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefTranslatorTestRefPtrClientChild>
+CefCppToCRefCounted<CefTranslatorTestRefPtrClientChildCppToC,
+ CefTranslatorTestRefPtrClientChild,
+ cef_translator_test_ref_ptr_client_child_t>::
+ UnwrapDerived(CefWrapperType type,
+ cef_translator_test_ref_ptr_client_child_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<
+ CefTranslatorTestRefPtrClientChildCppToC,
+ CefTranslatorTestRefPtrClientChild,
+ cef_translator_test_ref_ptr_client_child_t>::kWrapperType =
+ WT_TRANSLATOR_TEST_REF_PTR_CLIENT_CHILD;
diff --git a/libcef_dll/cpptoc/test/translator_test_ref_ptr_client_child_cpptoc.h b/libcef_dll/cpptoc/test/translator_test_ref_ptr_client_child_cpptoc.h
new file mode 100644
index 00000000..71d3384f
--- /dev/null
+++ b/libcef_dll/cpptoc/test/translator_test_ref_ptr_client_child_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=b6731cceb5f02011f2bafe6afa336b95355a1bf0$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_TEST_TRANSLATOR_TEST_REF_PTR_CLIENT_CHILD_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_TEST_TRANSLATOR_TEST_REF_PTR_CLIENT_CHILD_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/test/cef_translator_test_capi.h"
+#include "include/test/cef_translator_test.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefTranslatorTestRefPtrClientChildCppToC
+ : public CefCppToCRefCounted<CefTranslatorTestRefPtrClientChildCppToC,
+ CefTranslatorTestRefPtrClientChild,
+ cef_translator_test_ref_ptr_client_child_t> {
+ public:
+ CefTranslatorTestRefPtrClientChildCppToC();
+ virtual ~CefTranslatorTestRefPtrClientChildCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_TEST_TRANSLATOR_TEST_REF_PTR_CLIENT_CHILD_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/test/translator_test_ref_ptr_client_cpptoc.cc b/libcef_dll/cpptoc/test/translator_test_ref_ptr_client_cpptoc.cc
new file mode 100644
index 00000000..398b8506
--- /dev/null
+++ b/libcef_dll/cpptoc/test/translator_test_ref_ptr_client_cpptoc.cc
@@ -0,0 +1,75 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=c1cde9099d0161a04f31e595bde4c6466b490d8b$
+//
+
+#include "libcef_dll/cpptoc/test/translator_test_ref_ptr_client_cpptoc.h"
+#include "libcef_dll/cpptoc/test/translator_test_ref_ptr_client_child_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK translator_test_ref_ptr_client_get_value(
+ struct _cef_translator_test_ref_ptr_client_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefTranslatorTestRefPtrClientCppToC::Get(self)->GetValue();
+
+ // Return type: simple
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefTranslatorTestRefPtrClientCppToC::CefTranslatorTestRefPtrClientCppToC() {
+ GetStruct()->get_value = translator_test_ref_ptr_client_get_value;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefTranslatorTestRefPtrClientCppToC::~CefTranslatorTestRefPtrClientCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefTranslatorTestRefPtrClient>
+CefCppToCRefCounted<CefTranslatorTestRefPtrClientCppToC,
+ CefTranslatorTestRefPtrClient,
+ cef_translator_test_ref_ptr_client_t>::
+ UnwrapDerived(CefWrapperType type,
+ cef_translator_test_ref_ptr_client_t* s) {
+ if (type == WT_TRANSLATOR_TEST_REF_PTR_CLIENT_CHILD) {
+ return CefTranslatorTestRefPtrClientChildCppToC::Unwrap(
+ reinterpret_cast<cef_translator_test_ref_ptr_client_child_t*>(s));
+ }
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCppToCRefCounted<CefTranslatorTestRefPtrClientCppToC,
+ CefTranslatorTestRefPtrClient,
+ cef_translator_test_ref_ptr_client_t>::kWrapperType =
+ WT_TRANSLATOR_TEST_REF_PTR_CLIENT;
diff --git a/libcef_dll/cpptoc/test/translator_test_ref_ptr_client_cpptoc.h b/libcef_dll/cpptoc/test/translator_test_ref_ptr_client_cpptoc.h
new file mode 100644
index 00000000..e8a53096
--- /dev/null
+++ b/libcef_dll/cpptoc/test/translator_test_ref_ptr_client_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=871a3626f0e6928f2b1094b6fd01175f2bc82a29$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_TEST_TRANSLATOR_TEST_REF_PTR_CLIENT_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_TEST_TRANSLATOR_TEST_REF_PTR_CLIENT_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/test/cef_translator_test_capi.h"
+#include "include/test/cef_translator_test.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefTranslatorTestRefPtrClientCppToC
+ : public CefCppToCRefCounted<CefTranslatorTestRefPtrClientCppToC,
+ CefTranslatorTestRefPtrClient,
+ cef_translator_test_ref_ptr_client_t> {
+ public:
+ CefTranslatorTestRefPtrClientCppToC();
+ virtual ~CefTranslatorTestRefPtrClientCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_TEST_TRANSLATOR_TEST_REF_PTR_CLIENT_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/test/translator_test_ref_ptr_library_child_child_cpptoc.cc b/libcef_dll/cpptoc/test/translator_test_ref_ptr_library_child_child_cpptoc.cc
new file mode 100644
index 00000000..f89d4e7c
--- /dev/null
+++ b/libcef_dll/cpptoc/test/translator_test_ref_ptr_library_child_child_cpptoc.cc
@@ -0,0 +1,204 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=178ed72ca63c4bceca77fbec9581f6d36e6dbaa3$
+//
+
+#include "libcef_dll/cpptoc/test/translator_test_ref_ptr_library_child_child_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// GLOBAL FUNCTIONS - Body may be edited by hand.
+
+CEF_EXPORT cef_translator_test_ref_ptr_library_child_child_t*
+cef_translator_test_ref_ptr_library_child_child_create(int value,
+ int other_value,
+ int other_other_value) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ CefRefPtr<CefTranslatorTestRefPtrLibraryChildChild> _retval =
+ CefTranslatorTestRefPtrLibraryChildChild::Create(value, other_value,
+ other_other_value);
+
+ // Return type: refptr_same
+ return CefTranslatorTestRefPtrLibraryChildChildCppToC::Wrap(_retval);
+}
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK
+translator_test_ref_ptr_library_child_child_get_other_other_value(
+ struct _cef_translator_test_ref_ptr_library_child_child_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefTranslatorTestRefPtrLibraryChildChildCppToC::Get(self)
+ ->GetOtherOtherValue();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK
+translator_test_ref_ptr_library_child_child_set_other_other_value(
+ struct _cef_translator_test_ref_ptr_library_child_child_t* self,
+ int value) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefTranslatorTestRefPtrLibraryChildChildCppToC::Get(self)->SetOtherOtherValue(
+ value);
+}
+
+int CEF_CALLBACK translator_test_ref_ptr_library_child_child_get_other_value(
+ struct _cef_translator_test_ref_ptr_library_child_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval =
+ CefTranslatorTestRefPtrLibraryChildChildCppToC::Get(
+ reinterpret_cast<cef_translator_test_ref_ptr_library_child_child_t*>(
+ self))
+ ->GetOtherValue();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK translator_test_ref_ptr_library_child_child_set_other_value(
+ struct _cef_translator_test_ref_ptr_library_child_t* self,
+ int value) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefTranslatorTestRefPtrLibraryChildChildCppToC::Get(
+ reinterpret_cast<cef_translator_test_ref_ptr_library_child_child_t*>(
+ self))
+ ->SetOtherValue(value);
+}
+
+int CEF_CALLBACK translator_test_ref_ptr_library_child_child_get_value(
+ struct _cef_translator_test_ref_ptr_library_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval =
+ CefTranslatorTestRefPtrLibraryChildChildCppToC::Get(
+ reinterpret_cast<cef_translator_test_ref_ptr_library_child_child_t*>(
+ self))
+ ->GetValue();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK translator_test_ref_ptr_library_child_child_set_value(
+ struct _cef_translator_test_ref_ptr_library_t* self,
+ int value) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefTranslatorTestRefPtrLibraryChildChildCppToC::Get(
+ reinterpret_cast<cef_translator_test_ref_ptr_library_child_child_t*>(
+ self))
+ ->SetValue(value);
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefTranslatorTestRefPtrLibraryChildChildCppToC::
+ CefTranslatorTestRefPtrLibraryChildChildCppToC() {
+ GetStruct()->get_other_other_value =
+ translator_test_ref_ptr_library_child_child_get_other_other_value;
+ GetStruct()->set_other_other_value =
+ translator_test_ref_ptr_library_child_child_set_other_other_value;
+ GetStruct()->base.get_other_value =
+ translator_test_ref_ptr_library_child_child_get_other_value;
+ GetStruct()->base.set_other_value =
+ translator_test_ref_ptr_library_child_child_set_other_value;
+ GetStruct()->base.base.get_value =
+ translator_test_ref_ptr_library_child_child_get_value;
+ GetStruct()->base.base.set_value =
+ translator_test_ref_ptr_library_child_child_set_value;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefTranslatorTestRefPtrLibraryChildChildCppToC::
+ ~CefTranslatorTestRefPtrLibraryChildChildCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefTranslatorTestRefPtrLibraryChildChild>
+CefCppToCRefCounted<CefTranslatorTestRefPtrLibraryChildChildCppToC,
+ CefTranslatorTestRefPtrLibraryChildChild,
+ cef_translator_test_ref_ptr_library_child_child_t>::
+ UnwrapDerived(CefWrapperType type,
+ cef_translator_test_ref_ptr_library_child_child_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<
+ CefTranslatorTestRefPtrLibraryChildChildCppToC,
+ CefTranslatorTestRefPtrLibraryChildChild,
+ cef_translator_test_ref_ptr_library_child_child_t>::kWrapperType =
+ WT_TRANSLATOR_TEST_REF_PTR_LIBRARY_CHILD_CHILD;
diff --git a/libcef_dll/cpptoc/test/translator_test_ref_ptr_library_child_child_cpptoc.h b/libcef_dll/cpptoc/test/translator_test_ref_ptr_library_child_child_cpptoc.h
new file mode 100644
index 00000000..c17f7181
--- /dev/null
+++ b/libcef_dll/cpptoc/test/translator_test_ref_ptr_library_child_child_cpptoc.h
@@ -0,0 +1,39 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=c578229af8491c038b4a036ca870c5dd268b9244$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_TEST_TRANSLATOR_TEST_REF_PTR_LIBRARY_CHILD_CHILD_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_TEST_TRANSLATOR_TEST_REF_PTR_LIBRARY_CHILD_CHILD_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/test/cef_translator_test_capi.h"
+#include "include/test/cef_translator_test.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefTranslatorTestRefPtrLibraryChildChildCppToC
+ : public CefCppToCRefCounted<
+ CefTranslatorTestRefPtrLibraryChildChildCppToC,
+ CefTranslatorTestRefPtrLibraryChildChild,
+ cef_translator_test_ref_ptr_library_child_child_t> {
+ public:
+ CefTranslatorTestRefPtrLibraryChildChildCppToC();
+ virtual ~CefTranslatorTestRefPtrLibraryChildChildCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_TEST_TRANSLATOR_TEST_REF_PTR_LIBRARY_CHILD_CHILD_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/test/translator_test_ref_ptr_library_child_cpptoc.cc b/libcef_dll/cpptoc/test/translator_test_ref_ptr_library_child_cpptoc.cc
new file mode 100644
index 00000000..c23025f2
--- /dev/null
+++ b/libcef_dll/cpptoc/test/translator_test_ref_ptr_library_child_cpptoc.cc
@@ -0,0 +1,155 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=f1156abd7d5a26d954f9c4de9f1666be7e2ab0ce$
+//
+
+#include "libcef_dll/cpptoc/test/translator_test_ref_ptr_library_child_cpptoc.h"
+#include "libcef_dll/cpptoc/test/translator_test_ref_ptr_library_child_child_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// GLOBAL FUNCTIONS - Body may be edited by hand.
+
+CEF_EXPORT cef_translator_test_ref_ptr_library_child_t*
+cef_translator_test_ref_ptr_library_child_create(int value, int other_value) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ CefRefPtr<CefTranslatorTestRefPtrLibraryChild> _retval =
+ CefTranslatorTestRefPtrLibraryChild::Create(value, other_value);
+
+ // Return type: refptr_same
+ return CefTranslatorTestRefPtrLibraryChildCppToC::Wrap(_retval);
+}
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK translator_test_ref_ptr_library_child_get_other_value(
+ struct _cef_translator_test_ref_ptr_library_child_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval =
+ CefTranslatorTestRefPtrLibraryChildCppToC::Get(self)->GetOtherValue();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK translator_test_ref_ptr_library_child_set_other_value(
+ struct _cef_translator_test_ref_ptr_library_child_t* self,
+ int value) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefTranslatorTestRefPtrLibraryChildCppToC::Get(self)->SetOtherValue(value);
+}
+
+int CEF_CALLBACK translator_test_ref_ptr_library_child_get_value(
+ struct _cef_translator_test_ref_ptr_library_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval =
+ CefTranslatorTestRefPtrLibraryChildCppToC::Get(
+ reinterpret_cast<cef_translator_test_ref_ptr_library_child_t*>(self))
+ ->GetValue();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK translator_test_ref_ptr_library_child_set_value(
+ struct _cef_translator_test_ref_ptr_library_t* self,
+ int value) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefTranslatorTestRefPtrLibraryChildCppToC::Get(
+ reinterpret_cast<cef_translator_test_ref_ptr_library_child_t*>(self))
+ ->SetValue(value);
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefTranslatorTestRefPtrLibraryChildCppToC::
+ CefTranslatorTestRefPtrLibraryChildCppToC() {
+ GetStruct()->get_other_value =
+ translator_test_ref_ptr_library_child_get_other_value;
+ GetStruct()->set_other_value =
+ translator_test_ref_ptr_library_child_set_other_value;
+ GetStruct()->base.get_value = translator_test_ref_ptr_library_child_get_value;
+ GetStruct()->base.set_value = translator_test_ref_ptr_library_child_set_value;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefTranslatorTestRefPtrLibraryChildCppToC::
+ ~CefTranslatorTestRefPtrLibraryChildCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefTranslatorTestRefPtrLibraryChild>
+CefCppToCRefCounted<CefTranslatorTestRefPtrLibraryChildCppToC,
+ CefTranslatorTestRefPtrLibraryChild,
+ cef_translator_test_ref_ptr_library_child_t>::
+ UnwrapDerived(CefWrapperType type,
+ cef_translator_test_ref_ptr_library_child_t* s) {
+ if (type == WT_TRANSLATOR_TEST_REF_PTR_LIBRARY_CHILD_CHILD) {
+ return CefTranslatorTestRefPtrLibraryChildChildCppToC::Unwrap(
+ reinterpret_cast<cef_translator_test_ref_ptr_library_child_child_t*>(
+ s));
+ }
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<
+ CefTranslatorTestRefPtrLibraryChildCppToC,
+ CefTranslatorTestRefPtrLibraryChild,
+ cef_translator_test_ref_ptr_library_child_t>::kWrapperType =
+ WT_TRANSLATOR_TEST_REF_PTR_LIBRARY_CHILD;
diff --git a/libcef_dll/cpptoc/test/translator_test_ref_ptr_library_child_cpptoc.h b/libcef_dll/cpptoc/test/translator_test_ref_ptr_library_child_cpptoc.h
new file mode 100644
index 00000000..0ed52386
--- /dev/null
+++ b/libcef_dll/cpptoc/test/translator_test_ref_ptr_library_child_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=f138313a94a2c2943926df60ee5293f5dc9f62b8$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_TEST_TRANSLATOR_TEST_REF_PTR_LIBRARY_CHILD_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_TEST_TRANSLATOR_TEST_REF_PTR_LIBRARY_CHILD_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/test/cef_translator_test_capi.h"
+#include "include/test/cef_translator_test.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefTranslatorTestRefPtrLibraryChildCppToC
+ : public CefCppToCRefCounted<CefTranslatorTestRefPtrLibraryChildCppToC,
+ CefTranslatorTestRefPtrLibraryChild,
+ cef_translator_test_ref_ptr_library_child_t> {
+ public:
+ CefTranslatorTestRefPtrLibraryChildCppToC();
+ virtual ~CefTranslatorTestRefPtrLibraryChildCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_TEST_TRANSLATOR_TEST_REF_PTR_LIBRARY_CHILD_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/test/translator_test_ref_ptr_library_cpptoc.cc b/libcef_dll/cpptoc/test/translator_test_ref_ptr_library_cpptoc.cc
new file mode 100644
index 00000000..287794d9
--- /dev/null
+++ b/libcef_dll/cpptoc/test/translator_test_ref_ptr_library_cpptoc.cc
@@ -0,0 +1,114 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=23a27436f99688bd141b939ef756cab4d47fe857$
+//
+
+#include "libcef_dll/cpptoc/test/translator_test_ref_ptr_library_cpptoc.h"
+#include "libcef_dll/cpptoc/test/translator_test_ref_ptr_library_child_child_cpptoc.h"
+#include "libcef_dll/cpptoc/test/translator_test_ref_ptr_library_child_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// GLOBAL FUNCTIONS - Body may be edited by hand.
+
+CEF_EXPORT cef_translator_test_ref_ptr_library_t*
+cef_translator_test_ref_ptr_library_create(int value) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ CefRefPtr<CefTranslatorTestRefPtrLibrary> _retval =
+ CefTranslatorTestRefPtrLibrary::Create(value);
+
+ // Return type: refptr_same
+ return CefTranslatorTestRefPtrLibraryCppToC::Wrap(_retval);
+}
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK translator_test_ref_ptr_library_get_value(
+ struct _cef_translator_test_ref_ptr_library_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefTranslatorTestRefPtrLibraryCppToC::Get(self)->GetValue();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK translator_test_ref_ptr_library_set_value(
+ struct _cef_translator_test_ref_ptr_library_t* self,
+ int value) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefTranslatorTestRefPtrLibraryCppToC::Get(self)->SetValue(value);
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefTranslatorTestRefPtrLibraryCppToC::CefTranslatorTestRefPtrLibraryCppToC() {
+ GetStruct()->get_value = translator_test_ref_ptr_library_get_value;
+ GetStruct()->set_value = translator_test_ref_ptr_library_set_value;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefTranslatorTestRefPtrLibraryCppToC::~CefTranslatorTestRefPtrLibraryCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefTranslatorTestRefPtrLibrary>
+CefCppToCRefCounted<CefTranslatorTestRefPtrLibraryCppToC,
+ CefTranslatorTestRefPtrLibrary,
+ cef_translator_test_ref_ptr_library_t>::
+ UnwrapDerived(CefWrapperType type,
+ cef_translator_test_ref_ptr_library_t* s) {
+ if (type == WT_TRANSLATOR_TEST_REF_PTR_LIBRARY_CHILD) {
+ return CefTranslatorTestRefPtrLibraryChildCppToC::Unwrap(
+ reinterpret_cast<cef_translator_test_ref_ptr_library_child_t*>(s));
+ }
+ if (type == WT_TRANSLATOR_TEST_REF_PTR_LIBRARY_CHILD_CHILD) {
+ return CefTranslatorTestRefPtrLibraryChildChildCppToC::Unwrap(
+ reinterpret_cast<cef_translator_test_ref_ptr_library_child_child_t*>(
+ s));
+ }
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCppToCRefCounted<CefTranslatorTestRefPtrLibraryCppToC,
+ CefTranslatorTestRefPtrLibrary,
+ cef_translator_test_ref_ptr_library_t>::kWrapperType =
+ WT_TRANSLATOR_TEST_REF_PTR_LIBRARY;
diff --git a/libcef_dll/cpptoc/test/translator_test_ref_ptr_library_cpptoc.h b/libcef_dll/cpptoc/test/translator_test_ref_ptr_library_cpptoc.h
new file mode 100644
index 00000000..e1420e8f
--- /dev/null
+++ b/libcef_dll/cpptoc/test/translator_test_ref_ptr_library_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=f431a7518ff642f5b307dbd716bfcd75c5bcb37a$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_TEST_TRANSLATOR_TEST_REF_PTR_LIBRARY_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_TEST_TRANSLATOR_TEST_REF_PTR_LIBRARY_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/test/cef_translator_test_capi.h"
+#include "include/test/cef_translator_test.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefTranslatorTestRefPtrLibraryCppToC
+ : public CefCppToCRefCounted<CefTranslatorTestRefPtrLibraryCppToC,
+ CefTranslatorTestRefPtrLibrary,
+ cef_translator_test_ref_ptr_library_t> {
+ public:
+ CefTranslatorTestRefPtrLibraryCppToC();
+ virtual ~CefTranslatorTestRefPtrLibraryCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_TEST_TRANSLATOR_TEST_REF_PTR_LIBRARY_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/test/translator_test_scoped_client_child_cpptoc.cc b/libcef_dll/cpptoc/test/translator_test_scoped_client_child_cpptoc.cc
new file mode 100644
index 00000000..90725708
--- /dev/null
+++ b/libcef_dll/cpptoc/test/translator_test_scoped_client_child_cpptoc.cc
@@ -0,0 +1,100 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=2444cafe9c59f007ea908c8e43a8f02376d57011$
+//
+
+#include "libcef_dll/cpptoc/test/translator_test_scoped_client_child_cpptoc.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK translator_test_scoped_client_child_get_other_value(
+ struct _cef_translator_test_scoped_client_child_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval =
+ CefTranslatorTestScopedClientChildCppToC::Get(self)->GetOtherValue();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK translator_test_scoped_client_child_get_value(
+ struct _cef_translator_test_scoped_client_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval =
+ CefTranslatorTestScopedClientChildCppToC::Get(
+ reinterpret_cast<cef_translator_test_scoped_client_child_t*>(self))
+ ->GetValue();
+
+ // Return type: simple
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefTranslatorTestScopedClientChildCppToC::
+ CefTranslatorTestScopedClientChildCppToC() {
+ GetStruct()->get_other_value =
+ translator_test_scoped_client_child_get_other_value;
+ GetStruct()->base.get_value = translator_test_scoped_client_child_get_value;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefTranslatorTestScopedClientChildCppToC::
+ ~CefTranslatorTestScopedClientChildCppToC() {}
+
+template <>
+CefOwnPtr<CefTranslatorTestScopedClientChild>
+CefCppToCScoped<CefTranslatorTestScopedClientChildCppToC,
+ CefTranslatorTestScopedClientChild,
+ cef_translator_test_scoped_client_child_t>::
+ UnwrapDerivedOwn(CefWrapperType type,
+ cef_translator_test_scoped_client_child_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return CefOwnPtr<CefTranslatorTestScopedClientChild>();
+}
+
+template <>
+CefRawPtr<CefTranslatorTestScopedClientChild>
+CefCppToCScoped<CefTranslatorTestScopedClientChildCppToC,
+ CefTranslatorTestScopedClientChild,
+ cef_translator_test_scoped_client_child_t>::
+ UnwrapDerivedRaw(CefWrapperType type,
+ cef_translator_test_scoped_client_child_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCppToCScoped<CefTranslatorTestScopedClientChildCppToC,
+ CefTranslatorTestScopedClientChild,
+ cef_translator_test_scoped_client_child_t>::kWrapperType =
+ WT_TRANSLATOR_TEST_SCOPED_CLIENT_CHILD;
diff --git a/libcef_dll/cpptoc/test/translator_test_scoped_client_child_cpptoc.h b/libcef_dll/cpptoc/test/translator_test_scoped_client_child_cpptoc.h
new file mode 100644
index 00000000..894345cc
--- /dev/null
+++ b/libcef_dll/cpptoc/test/translator_test_scoped_client_child_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=7a7900759a192fa0586d1ab7e2706c513ed9b715$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_TEST_TRANSLATOR_TEST_SCOPED_CLIENT_CHILD_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_TEST_TRANSLATOR_TEST_SCOPED_CLIENT_CHILD_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/test/cef_translator_test_capi.h"
+#include "include/test/cef_translator_test.h"
+#include "libcef_dll/cpptoc/cpptoc_scoped.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefTranslatorTestScopedClientChildCppToC
+ : public CefCppToCScoped<CefTranslatorTestScopedClientChildCppToC,
+ CefTranslatorTestScopedClientChild,
+ cef_translator_test_scoped_client_child_t> {
+ public:
+ CefTranslatorTestScopedClientChildCppToC();
+ virtual ~CefTranslatorTestScopedClientChildCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_TEST_TRANSLATOR_TEST_SCOPED_CLIENT_CHILD_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/test/translator_test_scoped_client_cpptoc.cc b/libcef_dll/cpptoc/test/translator_test_scoped_client_cpptoc.cc
new file mode 100644
index 00000000..a0187a03
--- /dev/null
+++ b/libcef_dll/cpptoc/test/translator_test_scoped_client_cpptoc.cc
@@ -0,0 +1,85 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=d19e196c418e6325718ada2866d37f6ee142d606$
+//
+
+#include "libcef_dll/cpptoc/test/translator_test_scoped_client_cpptoc.h"
+#include "libcef_dll/cpptoc/test/translator_test_scoped_client_child_cpptoc.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK translator_test_scoped_client_get_value(
+ struct _cef_translator_test_scoped_client_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefTranslatorTestScopedClientCppToC::Get(self)->GetValue();
+
+ // Return type: simple
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefTranslatorTestScopedClientCppToC::CefTranslatorTestScopedClientCppToC() {
+ GetStruct()->get_value = translator_test_scoped_client_get_value;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefTranslatorTestScopedClientCppToC::~CefTranslatorTestScopedClientCppToC() {}
+
+template <>
+CefOwnPtr<CefTranslatorTestScopedClient>
+CefCppToCScoped<CefTranslatorTestScopedClientCppToC,
+ CefTranslatorTestScopedClient,
+ cef_translator_test_scoped_client_t>::
+ UnwrapDerivedOwn(CefWrapperType type,
+ cef_translator_test_scoped_client_t* s) {
+ if (type == WT_TRANSLATOR_TEST_SCOPED_CLIENT_CHILD) {
+ return CefTranslatorTestScopedClientChildCppToC::UnwrapOwn(
+ reinterpret_cast<cef_translator_test_scoped_client_child_t*>(s));
+ }
+ NOTREACHED() << "Unexpected class type: " << type;
+ return CefOwnPtr<CefTranslatorTestScopedClient>();
+}
+
+template <>
+CefRawPtr<CefTranslatorTestScopedClient>
+CefCppToCScoped<CefTranslatorTestScopedClientCppToC,
+ CefTranslatorTestScopedClient,
+ cef_translator_test_scoped_client_t>::
+ UnwrapDerivedRaw(CefWrapperType type,
+ cef_translator_test_scoped_client_t* s) {
+ if (type == WT_TRANSLATOR_TEST_SCOPED_CLIENT_CHILD) {
+ return CefTranslatorTestScopedClientChildCppToC::UnwrapRaw(
+ reinterpret_cast<cef_translator_test_scoped_client_child_t*>(s));
+ }
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCppToCScoped<CefTranslatorTestScopedClientCppToC,
+ CefTranslatorTestScopedClient,
+ cef_translator_test_scoped_client_t>::kWrapperType =
+ WT_TRANSLATOR_TEST_SCOPED_CLIENT;
diff --git a/libcef_dll/cpptoc/test/translator_test_scoped_client_cpptoc.h b/libcef_dll/cpptoc/test/translator_test_scoped_client_cpptoc.h
new file mode 100644
index 00000000..d73036be
--- /dev/null
+++ b/libcef_dll/cpptoc/test/translator_test_scoped_client_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=bf705a17d41da4d434c122928b0f55c8760d3689$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_TEST_TRANSLATOR_TEST_SCOPED_CLIENT_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_TEST_TRANSLATOR_TEST_SCOPED_CLIENT_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/test/cef_translator_test_capi.h"
+#include "include/test/cef_translator_test.h"
+#include "libcef_dll/cpptoc/cpptoc_scoped.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefTranslatorTestScopedClientCppToC
+ : public CefCppToCScoped<CefTranslatorTestScopedClientCppToC,
+ CefTranslatorTestScopedClient,
+ cef_translator_test_scoped_client_t> {
+ public:
+ CefTranslatorTestScopedClientCppToC();
+ virtual ~CefTranslatorTestScopedClientCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_TEST_TRANSLATOR_TEST_SCOPED_CLIENT_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/test/translator_test_scoped_library_child_child_cpptoc.cc b/libcef_dll/cpptoc/test/translator_test_scoped_library_child_child_cpptoc.cc
new file mode 100644
index 00000000..8dffd875
--- /dev/null
+++ b/libcef_dll/cpptoc/test/translator_test_scoped_library_child_child_cpptoc.cc
@@ -0,0 +1,197 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=29014eb7cb86c46ed68a938cc862a1eed9335ee3$
+//
+
+#include "libcef_dll/cpptoc/test/translator_test_scoped_library_child_child_cpptoc.h"
+
+// GLOBAL FUNCTIONS - Body may be edited by hand.
+
+CEF_EXPORT cef_translator_test_scoped_library_child_child_t*
+cef_translator_test_scoped_library_child_child_create(int value,
+ int other_value,
+ int other_other_value) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ CefOwnPtr<CefTranslatorTestScopedLibraryChildChild> _retval =
+ CefTranslatorTestScopedLibraryChildChild::Create(value, other_value,
+ other_other_value);
+
+ // Return type: ownptr_same
+ return CefTranslatorTestScopedLibraryChildChildCppToC::WrapOwn(
+ std::move(_retval));
+}
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK
+translator_test_scoped_library_child_child_get_other_other_value(
+ struct _cef_translator_test_scoped_library_child_child_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefTranslatorTestScopedLibraryChildChildCppToC::Get(self)
+ ->GetOtherOtherValue();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK
+translator_test_scoped_library_child_child_set_other_other_value(
+ struct _cef_translator_test_scoped_library_child_child_t* self,
+ int value) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefTranslatorTestScopedLibraryChildChildCppToC::Get(self)->SetOtherOtherValue(
+ value);
+}
+
+int CEF_CALLBACK translator_test_scoped_library_child_child_get_other_value(
+ struct _cef_translator_test_scoped_library_child_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval =
+ CefTranslatorTestScopedLibraryChildChildCppToC::Get(
+ reinterpret_cast<cef_translator_test_scoped_library_child_child_t*>(
+ self))
+ ->GetOtherValue();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK translator_test_scoped_library_child_child_set_other_value(
+ struct _cef_translator_test_scoped_library_child_t* self,
+ int value) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefTranslatorTestScopedLibraryChildChildCppToC::Get(
+ reinterpret_cast<cef_translator_test_scoped_library_child_child_t*>(self))
+ ->SetOtherValue(value);
+}
+
+int CEF_CALLBACK translator_test_scoped_library_child_child_get_value(
+ struct _cef_translator_test_scoped_library_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval =
+ CefTranslatorTestScopedLibraryChildChildCppToC::Get(
+ reinterpret_cast<cef_translator_test_scoped_library_child_child_t*>(
+ self))
+ ->GetValue();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK translator_test_scoped_library_child_child_set_value(
+ struct _cef_translator_test_scoped_library_t* self,
+ int value) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefTranslatorTestScopedLibraryChildChildCppToC::Get(
+ reinterpret_cast<cef_translator_test_scoped_library_child_child_t*>(self))
+ ->SetValue(value);
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefTranslatorTestScopedLibraryChildChildCppToC::
+ CefTranslatorTestScopedLibraryChildChildCppToC() {
+ GetStruct()->get_other_other_value =
+ translator_test_scoped_library_child_child_get_other_other_value;
+ GetStruct()->set_other_other_value =
+ translator_test_scoped_library_child_child_set_other_other_value;
+ GetStruct()->base.get_other_value =
+ translator_test_scoped_library_child_child_get_other_value;
+ GetStruct()->base.set_other_value =
+ translator_test_scoped_library_child_child_set_other_value;
+ GetStruct()->base.base.get_value =
+ translator_test_scoped_library_child_child_get_value;
+ GetStruct()->base.base.set_value =
+ translator_test_scoped_library_child_child_set_value;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefTranslatorTestScopedLibraryChildChildCppToC::
+ ~CefTranslatorTestScopedLibraryChildChildCppToC() {}
+
+template <>
+CefOwnPtr<CefTranslatorTestScopedLibraryChildChild>
+CefCppToCScoped<CefTranslatorTestScopedLibraryChildChildCppToC,
+ CefTranslatorTestScopedLibraryChildChild,
+ cef_translator_test_scoped_library_child_child_t>::
+ UnwrapDerivedOwn(CefWrapperType type,
+ cef_translator_test_scoped_library_child_child_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return CefOwnPtr<CefTranslatorTestScopedLibraryChildChild>();
+}
+
+template <>
+CefRawPtr<CefTranslatorTestScopedLibraryChildChild>
+CefCppToCScoped<CefTranslatorTestScopedLibraryChildChildCppToC,
+ CefTranslatorTestScopedLibraryChildChild,
+ cef_translator_test_scoped_library_child_child_t>::
+ UnwrapDerivedRaw(CefWrapperType type,
+ cef_translator_test_scoped_library_child_child_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCScoped<
+ CefTranslatorTestScopedLibraryChildChildCppToC,
+ CefTranslatorTestScopedLibraryChildChild,
+ cef_translator_test_scoped_library_child_child_t>::kWrapperType =
+ WT_TRANSLATOR_TEST_SCOPED_LIBRARY_CHILD_CHILD;
diff --git a/libcef_dll/cpptoc/test/translator_test_scoped_library_child_child_cpptoc.h b/libcef_dll/cpptoc/test/translator_test_scoped_library_child_child_cpptoc.h
new file mode 100644
index 00000000..3602a4b0
--- /dev/null
+++ b/libcef_dll/cpptoc/test/translator_test_scoped_library_child_child_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=333a572bf8bb3cde5058ae36410b571d777cd157$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_TEST_TRANSLATOR_TEST_SCOPED_LIBRARY_CHILD_CHILD_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_TEST_TRANSLATOR_TEST_SCOPED_LIBRARY_CHILD_CHILD_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/test/cef_translator_test_capi.h"
+#include "include/test/cef_translator_test.h"
+#include "libcef_dll/cpptoc/cpptoc_scoped.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefTranslatorTestScopedLibraryChildChildCppToC
+ : public CefCppToCScoped<CefTranslatorTestScopedLibraryChildChildCppToC,
+ CefTranslatorTestScopedLibraryChildChild,
+ cef_translator_test_scoped_library_child_child_t> {
+ public:
+ CefTranslatorTestScopedLibraryChildChildCppToC();
+ virtual ~CefTranslatorTestScopedLibraryChildChildCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_TEST_TRANSLATOR_TEST_SCOPED_LIBRARY_CHILD_CHILD_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/test/translator_test_scoped_library_child_cpptoc.cc b/libcef_dll/cpptoc/test/translator_test_scoped_library_child_cpptoc.cc
new file mode 100644
index 00000000..1a665df2
--- /dev/null
+++ b/libcef_dll/cpptoc/test/translator_test_scoped_library_child_cpptoc.cc
@@ -0,0 +1,156 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=3fb60285776c7480d0909430c04b3fe5a0c257be$
+//
+
+#include "libcef_dll/cpptoc/test/translator_test_scoped_library_child_cpptoc.h"
+#include "libcef_dll/cpptoc/test/translator_test_scoped_library_child_child_cpptoc.h"
+
+// GLOBAL FUNCTIONS - Body may be edited by hand.
+
+CEF_EXPORT cef_translator_test_scoped_library_child_t*
+cef_translator_test_scoped_library_child_create(int value, int other_value) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ CefOwnPtr<CefTranslatorTestScopedLibraryChild> _retval =
+ CefTranslatorTestScopedLibraryChild::Create(value, other_value);
+
+ // Return type: ownptr_same
+ return CefTranslatorTestScopedLibraryChildCppToC::WrapOwn(std::move(_retval));
+}
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK translator_test_scoped_library_child_get_other_value(
+ struct _cef_translator_test_scoped_library_child_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval =
+ CefTranslatorTestScopedLibraryChildCppToC::Get(self)->GetOtherValue();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK translator_test_scoped_library_child_set_other_value(
+ struct _cef_translator_test_scoped_library_child_t* self,
+ int value) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefTranslatorTestScopedLibraryChildCppToC::Get(self)->SetOtherValue(value);
+}
+
+int CEF_CALLBACK translator_test_scoped_library_child_get_value(
+ struct _cef_translator_test_scoped_library_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval =
+ CefTranslatorTestScopedLibraryChildCppToC::Get(
+ reinterpret_cast<cef_translator_test_scoped_library_child_t*>(self))
+ ->GetValue();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK translator_test_scoped_library_child_set_value(
+ struct _cef_translator_test_scoped_library_t* self,
+ int value) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefTranslatorTestScopedLibraryChildCppToC::Get(
+ reinterpret_cast<cef_translator_test_scoped_library_child_t*>(self))
+ ->SetValue(value);
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefTranslatorTestScopedLibraryChildCppToC::
+ CefTranslatorTestScopedLibraryChildCppToC() {
+ GetStruct()->get_other_value =
+ translator_test_scoped_library_child_get_other_value;
+ GetStruct()->set_other_value =
+ translator_test_scoped_library_child_set_other_value;
+ GetStruct()->base.get_value = translator_test_scoped_library_child_get_value;
+ GetStruct()->base.set_value = translator_test_scoped_library_child_set_value;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefTranslatorTestScopedLibraryChildCppToC::
+ ~CefTranslatorTestScopedLibraryChildCppToC() {}
+
+template <>
+CefOwnPtr<CefTranslatorTestScopedLibraryChild>
+CefCppToCScoped<CefTranslatorTestScopedLibraryChildCppToC,
+ CefTranslatorTestScopedLibraryChild,
+ cef_translator_test_scoped_library_child_t>::
+ UnwrapDerivedOwn(CefWrapperType type,
+ cef_translator_test_scoped_library_child_t* s) {
+ if (type == WT_TRANSLATOR_TEST_SCOPED_LIBRARY_CHILD_CHILD) {
+ return CefTranslatorTestScopedLibraryChildChildCppToC::UnwrapOwn(
+ reinterpret_cast<cef_translator_test_scoped_library_child_child_t*>(s));
+ }
+ NOTREACHED() << "Unexpected class type: " << type;
+ return CefOwnPtr<CefTranslatorTestScopedLibraryChild>();
+}
+
+template <>
+CefRawPtr<CefTranslatorTestScopedLibraryChild>
+CefCppToCScoped<CefTranslatorTestScopedLibraryChildCppToC,
+ CefTranslatorTestScopedLibraryChild,
+ cef_translator_test_scoped_library_child_t>::
+ UnwrapDerivedRaw(CefWrapperType type,
+ cef_translator_test_scoped_library_child_t* s) {
+ if (type == WT_TRANSLATOR_TEST_SCOPED_LIBRARY_CHILD_CHILD) {
+ return CefTranslatorTestScopedLibraryChildChildCppToC::UnwrapRaw(
+ reinterpret_cast<cef_translator_test_scoped_library_child_child_t*>(s));
+ }
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCppToCScoped<CefTranslatorTestScopedLibraryChildCppToC,
+ CefTranslatorTestScopedLibraryChild,
+ cef_translator_test_scoped_library_child_t>::kWrapperType =
+ WT_TRANSLATOR_TEST_SCOPED_LIBRARY_CHILD;
diff --git a/libcef_dll/cpptoc/test/translator_test_scoped_library_child_cpptoc.h b/libcef_dll/cpptoc/test/translator_test_scoped_library_child_cpptoc.h
new file mode 100644
index 00000000..e1c516aa
--- /dev/null
+++ b/libcef_dll/cpptoc/test/translator_test_scoped_library_child_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=df48c52988d69bfd94bc4245d1c2069f45512f7a$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_TEST_TRANSLATOR_TEST_SCOPED_LIBRARY_CHILD_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_TEST_TRANSLATOR_TEST_SCOPED_LIBRARY_CHILD_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/test/cef_translator_test_capi.h"
+#include "include/test/cef_translator_test.h"
+#include "libcef_dll/cpptoc/cpptoc_scoped.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefTranslatorTestScopedLibraryChildCppToC
+ : public CefCppToCScoped<CefTranslatorTestScopedLibraryChildCppToC,
+ CefTranslatorTestScopedLibraryChild,
+ cef_translator_test_scoped_library_child_t> {
+ public:
+ CefTranslatorTestScopedLibraryChildCppToC();
+ virtual ~CefTranslatorTestScopedLibraryChildCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_TEST_TRANSLATOR_TEST_SCOPED_LIBRARY_CHILD_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/test/translator_test_scoped_library_cpptoc.cc b/libcef_dll/cpptoc/test/translator_test_scoped_library_cpptoc.cc
new file mode 100644
index 00000000..acb37c94
--- /dev/null
+++ b/libcef_dll/cpptoc/test/translator_test_scoped_library_cpptoc.cc
@@ -0,0 +1,123 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=9aeefcb3a387576c2a7ef206b9bcf57ac9c7f060$
+//
+
+#include "libcef_dll/cpptoc/test/translator_test_scoped_library_cpptoc.h"
+#include "libcef_dll/cpptoc/test/translator_test_scoped_library_child_child_cpptoc.h"
+#include "libcef_dll/cpptoc/test/translator_test_scoped_library_child_cpptoc.h"
+
+// GLOBAL FUNCTIONS - Body may be edited by hand.
+
+CEF_EXPORT cef_translator_test_scoped_library_t*
+cef_translator_test_scoped_library_create(int value) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ CefOwnPtr<CefTranslatorTestScopedLibrary> _retval =
+ CefTranslatorTestScopedLibrary::Create(value);
+
+ // Return type: ownptr_same
+ return CefTranslatorTestScopedLibraryCppToC::WrapOwn(std::move(_retval));
+}
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK translator_test_scoped_library_get_value(
+ struct _cef_translator_test_scoped_library_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefTranslatorTestScopedLibraryCppToC::Get(self)->GetValue();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK translator_test_scoped_library_set_value(
+ struct _cef_translator_test_scoped_library_t* self,
+ int value) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefTranslatorTestScopedLibraryCppToC::Get(self)->SetValue(value);
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefTranslatorTestScopedLibraryCppToC::CefTranslatorTestScopedLibraryCppToC() {
+ GetStruct()->get_value = translator_test_scoped_library_get_value;
+ GetStruct()->set_value = translator_test_scoped_library_set_value;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefTranslatorTestScopedLibraryCppToC::~CefTranslatorTestScopedLibraryCppToC() {}
+
+template <>
+CefOwnPtr<CefTranslatorTestScopedLibrary>
+CefCppToCScoped<CefTranslatorTestScopedLibraryCppToC,
+ CefTranslatorTestScopedLibrary,
+ cef_translator_test_scoped_library_t>::
+ UnwrapDerivedOwn(CefWrapperType type,
+ cef_translator_test_scoped_library_t* s) {
+ if (type == WT_TRANSLATOR_TEST_SCOPED_LIBRARY_CHILD) {
+ return CefTranslatorTestScopedLibraryChildCppToC::UnwrapOwn(
+ reinterpret_cast<cef_translator_test_scoped_library_child_t*>(s));
+ }
+ if (type == WT_TRANSLATOR_TEST_SCOPED_LIBRARY_CHILD_CHILD) {
+ return CefTranslatorTestScopedLibraryChildChildCppToC::UnwrapOwn(
+ reinterpret_cast<cef_translator_test_scoped_library_child_child_t*>(s));
+ }
+ NOTREACHED() << "Unexpected class type: " << type;
+ return CefOwnPtr<CefTranslatorTestScopedLibrary>();
+}
+
+template <>
+CefRawPtr<CefTranslatorTestScopedLibrary>
+CefCppToCScoped<CefTranslatorTestScopedLibraryCppToC,
+ CefTranslatorTestScopedLibrary,
+ cef_translator_test_scoped_library_t>::
+ UnwrapDerivedRaw(CefWrapperType type,
+ cef_translator_test_scoped_library_t* s) {
+ if (type == WT_TRANSLATOR_TEST_SCOPED_LIBRARY_CHILD) {
+ return CefTranslatorTestScopedLibraryChildCppToC::UnwrapRaw(
+ reinterpret_cast<cef_translator_test_scoped_library_child_t*>(s));
+ }
+ if (type == WT_TRANSLATOR_TEST_SCOPED_LIBRARY_CHILD_CHILD) {
+ return CefTranslatorTestScopedLibraryChildChildCppToC::UnwrapRaw(
+ reinterpret_cast<cef_translator_test_scoped_library_child_child_t*>(s));
+ }
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCppToCScoped<CefTranslatorTestScopedLibraryCppToC,
+ CefTranslatorTestScopedLibrary,
+ cef_translator_test_scoped_library_t>::kWrapperType =
+ WT_TRANSLATOR_TEST_SCOPED_LIBRARY;
diff --git a/libcef_dll/cpptoc/test/translator_test_scoped_library_cpptoc.h b/libcef_dll/cpptoc/test/translator_test_scoped_library_cpptoc.h
new file mode 100644
index 00000000..f0384061
--- /dev/null
+++ b/libcef_dll/cpptoc/test/translator_test_scoped_library_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=029af2aa3f312b751ca30b039f22e5c4fbd42295$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_TEST_TRANSLATOR_TEST_SCOPED_LIBRARY_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_TEST_TRANSLATOR_TEST_SCOPED_LIBRARY_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/test/cef_translator_test_capi.h"
+#include "include/test/cef_translator_test.h"
+#include "libcef_dll/cpptoc/cpptoc_scoped.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefTranslatorTestScopedLibraryCppToC
+ : public CefCppToCScoped<CefTranslatorTestScopedLibraryCppToC,
+ CefTranslatorTestScopedLibrary,
+ cef_translator_test_scoped_library_t> {
+ public:
+ CefTranslatorTestScopedLibraryCppToC();
+ virtual ~CefTranslatorTestScopedLibraryCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_TEST_TRANSLATOR_TEST_SCOPED_LIBRARY_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/thread_cpptoc.cc b/libcef_dll/cpptoc/thread_cpptoc.cc
new file mode 100644
index 00000000..d07c19fd
--- /dev/null
+++ b/libcef_dll/cpptoc/thread_cpptoc.cc
@@ -0,0 +1,143 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=ae28647ac7b24fd9581981aab2e1b27b9efca355$
+//
+
+#include "libcef_dll/cpptoc/thread_cpptoc.h"
+#include "libcef_dll/cpptoc/task_runner_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// GLOBAL FUNCTIONS - Body may be edited by hand.
+
+CEF_EXPORT cef_thread_t* cef_thread_create(
+ const cef_string_t* display_name,
+ cef_thread_priority_t priority,
+ cef_message_loop_type_t message_loop_type,
+ int stoppable,
+ cef_com_init_mode_t com_init_mode) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: display_name
+
+ // Execute
+ CefRefPtr<CefThread> _retval = CefThread::CreateThread(
+ CefString(display_name), priority, message_loop_type,
+ stoppable ? true : false, com_init_mode);
+
+ // Return type: refptr_same
+ return CefThreadCppToC::Wrap(_retval);
+}
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+cef_task_runner_t* CEF_CALLBACK
+thread_get_task_runner(struct _cef_thread_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefTaskRunner> _retval =
+ CefThreadCppToC::Get(self)->GetTaskRunner();
+
+ // Return type: refptr_same
+ return CefTaskRunnerCppToC::Wrap(_retval);
+}
+
+cef_platform_thread_id_t CEF_CALLBACK
+thread_get_platform_thread_id(struct _cef_thread_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return kInvalidPlatformThreadId;
+ }
+
+ // Execute
+ cef_platform_thread_id_t _retval =
+ CefThreadCppToC::Get(self)->GetPlatformThreadId();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK thread_stop(struct _cef_thread_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefThreadCppToC::Get(self)->Stop();
+}
+
+int CEF_CALLBACK thread_is_running(struct _cef_thread_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefThreadCppToC::Get(self)->IsRunning();
+
+ // Return type: bool
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefThreadCppToC::CefThreadCppToC() {
+ GetStruct()->get_task_runner = thread_get_task_runner;
+ GetStruct()->get_platform_thread_id = thread_get_platform_thread_id;
+ GetStruct()->stop = thread_stop;
+ GetStruct()->is_running = thread_is_running;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefThreadCppToC::~CefThreadCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefThread>
+CefCppToCRefCounted<CefThreadCppToC, CefThread, cef_thread_t>::UnwrapDerived(
+ CefWrapperType type,
+ cef_thread_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefThreadCppToC, CefThread, cef_thread_t>::
+ kWrapperType = WT_THREAD;
diff --git a/libcef_dll/cpptoc/thread_cpptoc.h b/libcef_dll/cpptoc/thread_cpptoc.h
new file mode 100644
index 00000000..37f0be30
--- /dev/null
+++ b/libcef_dll/cpptoc/thread_cpptoc.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=684bc72317e634d7357bdea53bf7dfe81d9d536b$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_THREAD_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_THREAD_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_thread_capi.h"
+#include "include/cef_thread.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefThreadCppToC
+ : public CefCppToCRefCounted<CefThreadCppToC, CefThread, cef_thread_t> {
+ public:
+ CefThreadCppToC();
+ virtual ~CefThreadCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_THREAD_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/urlrequest_client_cpptoc.cc b/libcef_dll/cpptoc/urlrequest_client_cpptoc.cc
new file mode 100644
index 00000000..0b72753a
--- /dev/null
+++ b/libcef_dll/cpptoc/urlrequest_client_cpptoc.cc
@@ -0,0 +1,197 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=c3a6ea0e93d96381917a52439f8ee86822bcfce2$
+//
+
+#include "libcef_dll/cpptoc/urlrequest_client_cpptoc.h"
+#include "libcef_dll/ctocpp/auth_callback_ctocpp.h"
+#include "libcef_dll/ctocpp/urlrequest_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK
+urlrequest_client_on_request_complete(struct _cef_urlrequest_client_t* self,
+ cef_urlrequest_t* request) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: request; type: refptr_diff
+ DCHECK(request);
+ if (!request) {
+ return;
+ }
+
+ // Execute
+ CefURLRequestClientCppToC::Get(self)->OnRequestComplete(
+ CefURLRequestCToCpp::Wrap(request));
+}
+
+void CEF_CALLBACK
+urlrequest_client_on_upload_progress(struct _cef_urlrequest_client_t* self,
+ cef_urlrequest_t* request,
+ int64 current,
+ int64 total) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: request; type: refptr_diff
+ DCHECK(request);
+ if (!request) {
+ return;
+ }
+
+ // Execute
+ CefURLRequestClientCppToC::Get(self)->OnUploadProgress(
+ CefURLRequestCToCpp::Wrap(request), current, total);
+}
+
+void CEF_CALLBACK
+urlrequest_client_on_download_progress(struct _cef_urlrequest_client_t* self,
+ cef_urlrequest_t* request,
+ int64 current,
+ int64 total) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: request; type: refptr_diff
+ DCHECK(request);
+ if (!request) {
+ return;
+ }
+
+ // Execute
+ CefURLRequestClientCppToC::Get(self)->OnDownloadProgress(
+ CefURLRequestCToCpp::Wrap(request), current, total);
+}
+
+void CEF_CALLBACK
+urlrequest_client_on_download_data(struct _cef_urlrequest_client_t* self,
+ cef_urlrequest_t* request,
+ const void* data,
+ size_t data_length) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: request; type: refptr_diff
+ DCHECK(request);
+ if (!request) {
+ return;
+ }
+ // Verify param: data; type: simple_byaddr
+ DCHECK(data);
+ if (!data) {
+ return;
+ }
+
+ // Execute
+ CefURLRequestClientCppToC::Get(self)->OnDownloadData(
+ CefURLRequestCToCpp::Wrap(request), data, data_length);
+}
+
+int CEF_CALLBACK
+urlrequest_client_get_auth_credentials(struct _cef_urlrequest_client_t* self,
+ int isProxy,
+ const cef_string_t* host,
+ int port,
+ const cef_string_t* realm,
+ const cef_string_t* scheme,
+ cef_auth_callback_t* callback) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: host; type: string_byref_const
+ DCHECK(host);
+ if (!host) {
+ return 0;
+ }
+ // Verify param: scheme; type: string_byref_const
+ DCHECK(scheme);
+ if (!scheme) {
+ return 0;
+ }
+ // Verify param: callback; type: refptr_diff
+ DCHECK(callback);
+ if (!callback) {
+ return 0;
+ }
+ // Unverified params: realm
+
+ // Execute
+ bool _retval = CefURLRequestClientCppToC::Get(self)->GetAuthCredentials(
+ isProxy ? true : false, CefString(host), port, CefString(realm),
+ CefString(scheme), CefAuthCallbackCToCpp::Wrap(callback));
+
+ // Return type: bool
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefURLRequestClientCppToC::CefURLRequestClientCppToC() {
+ GetStruct()->on_request_complete = urlrequest_client_on_request_complete;
+ GetStruct()->on_upload_progress = urlrequest_client_on_upload_progress;
+ GetStruct()->on_download_progress = urlrequest_client_on_download_progress;
+ GetStruct()->on_download_data = urlrequest_client_on_download_data;
+ GetStruct()->get_auth_credentials = urlrequest_client_get_auth_credentials;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefURLRequestClientCppToC::~CefURLRequestClientCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefURLRequestClient> CefCppToCRefCounted<
+ CefURLRequestClientCppToC,
+ CefURLRequestClient,
+ cef_urlrequest_client_t>::UnwrapDerived(CefWrapperType type,
+ cef_urlrequest_client_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefURLRequestClientCppToC,
+ CefURLRequestClient,
+ cef_urlrequest_client_t>::kWrapperType =
+ WT_URLREQUEST_CLIENT;
diff --git a/libcef_dll/cpptoc/urlrequest_client_cpptoc.h b/libcef_dll/cpptoc/urlrequest_client_cpptoc.h
new file mode 100644
index 00000000..551f69c5
--- /dev/null
+++ b/libcef_dll/cpptoc/urlrequest_client_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=da593bcc58bec4b7dc1159fdc2fd2b8f472a6c93$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_URLREQUEST_CLIENT_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_URLREQUEST_CLIENT_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_urlrequest_capi.h"
+#include "include/cef_urlrequest.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefURLRequestClientCppToC
+ : public CefCppToCRefCounted<CefURLRequestClientCppToC,
+ CefURLRequestClient,
+ cef_urlrequest_client_t> {
+ public:
+ CefURLRequestClientCppToC();
+ virtual ~CefURLRequestClientCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_URLREQUEST_CLIENT_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/urlrequest_cpptoc.cc b/libcef_dll/cpptoc/urlrequest_cpptoc.cc
new file mode 100644
index 00000000..d2ce15de
--- /dev/null
+++ b/libcef_dll/cpptoc/urlrequest_cpptoc.cc
@@ -0,0 +1,215 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=c9e932ea4980ef0d6ced8f891265bdd49ff4b806$
+//
+
+#include "libcef_dll/cpptoc/urlrequest_cpptoc.h"
+#include "libcef_dll/cpptoc/request_context_cpptoc.h"
+#include "libcef_dll/cpptoc/request_cpptoc.h"
+#include "libcef_dll/cpptoc/response_cpptoc.h"
+#include "libcef_dll/ctocpp/urlrequest_client_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// GLOBAL FUNCTIONS - Body may be edited by hand.
+
+CEF_EXPORT cef_urlrequest_t* cef_urlrequest_create(
+ cef_request_t* request,
+ struct _cef_urlrequest_client_t* client,
+ cef_request_context_t* request_context) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: request; type: refptr_same
+ DCHECK(request);
+ if (!request) {
+ return NULL;
+ }
+ // Verify param: client; type: refptr_diff
+ DCHECK(client);
+ if (!client) {
+ return NULL;
+ }
+ // Unverified params: request_context
+
+ // Execute
+ CefRefPtr<CefURLRequest> _retval =
+ CefURLRequest::Create(CefRequestCppToC::Unwrap(request),
+ CefURLRequestClientCToCpp::Wrap(client),
+ CefRequestContextCppToC::Unwrap(request_context));
+
+ // Return type: refptr_same
+ return CefURLRequestCppToC::Wrap(_retval);
+}
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+cef_request_t* CEF_CALLBACK
+urlrequest_get_request(struct _cef_urlrequest_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefRequest> _retval = CefURLRequestCppToC::Get(self)->GetRequest();
+
+ // Return type: refptr_same
+ return CefRequestCppToC::Wrap(_retval);
+}
+
+struct _cef_urlrequest_client_t* CEF_CALLBACK
+urlrequest_get_client(struct _cef_urlrequest_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefURLRequestClient> _retval =
+ CefURLRequestCppToC::Get(self)->GetClient();
+
+ // Return type: refptr_diff
+ return CefURLRequestClientCToCpp::Unwrap(_retval);
+}
+
+cef_urlrequest_status_t CEF_CALLBACK
+urlrequest_get_request_status(struct _cef_urlrequest_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return UR_UNKNOWN;
+ }
+
+ // Execute
+ cef_urlrequest_status_t _retval =
+ CefURLRequestCppToC::Get(self)->GetRequestStatus();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_errorcode_t CEF_CALLBACK
+urlrequest_get_request_error(struct _cef_urlrequest_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return ERR_NONE;
+ }
+
+ // Execute
+ cef_errorcode_t _retval = CefURLRequestCppToC::Get(self)->GetRequestError();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_response_t* CEF_CALLBACK
+urlrequest_get_response(struct _cef_urlrequest_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefResponse> _retval =
+ CefURLRequestCppToC::Get(self)->GetResponse();
+
+ // Return type: refptr_same
+ return CefResponseCppToC::Wrap(_retval);
+}
+
+int CEF_CALLBACK
+urlrequest_response_was_cached(struct _cef_urlrequest_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefURLRequestCppToC::Get(self)->ResponseWasCached();
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK urlrequest_cancel(struct _cef_urlrequest_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefURLRequestCppToC::Get(self)->Cancel();
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefURLRequestCppToC::CefURLRequestCppToC() {
+ GetStruct()->get_request = urlrequest_get_request;
+ GetStruct()->get_client = urlrequest_get_client;
+ GetStruct()->get_request_status = urlrequest_get_request_status;
+ GetStruct()->get_request_error = urlrequest_get_request_error;
+ GetStruct()->get_response = urlrequest_get_response;
+ GetStruct()->response_was_cached = urlrequest_response_was_cached;
+ GetStruct()->cancel = urlrequest_cancel;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefURLRequestCppToC::~CefURLRequestCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefURLRequest>
+CefCppToCRefCounted<CefURLRequestCppToC, CefURLRequest, cef_urlrequest_t>::
+ UnwrapDerived(CefWrapperType type, cef_urlrequest_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefURLRequestCppToC,
+ CefURLRequest,
+ cef_urlrequest_t>::kWrapperType =
+ WT_URLREQUEST;
diff --git a/libcef_dll/cpptoc/urlrequest_cpptoc.h b/libcef_dll/cpptoc/urlrequest_cpptoc.h
new file mode 100644
index 00000000..3ed15df7
--- /dev/null
+++ b/libcef_dll/cpptoc/urlrequest_cpptoc.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=f870036a626bd6ba126425b586b0a3116030c8d6$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_URLREQUEST_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_URLREQUEST_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_urlrequest_capi.h"
+#include "include/cef_urlrequest.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefURLRequestCppToC : public CefCppToCRefCounted<CefURLRequestCppToC,
+ CefURLRequest,
+ cef_urlrequest_t> {
+ public:
+ CefURLRequestCppToC();
+ virtual ~CefURLRequestCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_URLREQUEST_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/v8accessor_cpptoc.cc b/libcef_dll/cpptoc/v8accessor_cpptoc.cc
new file mode 100644
index 00000000..d762766f
--- /dev/null
+++ b/libcef_dll/cpptoc/v8accessor_cpptoc.cc
@@ -0,0 +1,151 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=f4164c6761097fed20cf8ef4a42784f193f141af$
+//
+
+#include "libcef_dll/cpptoc/v8accessor_cpptoc.h"
+#include "libcef_dll/ctocpp/v8value_ctocpp.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK v8accessor_get(struct _cef_v8accessor_t* self,
+ const cef_string_t* name,
+ struct _cef_v8value_t* object,
+ struct _cef_v8value_t** retval,
+ cef_string_t* exception) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: name; type: string_byref_const
+ DCHECK(name);
+ if (!name) {
+ return 0;
+ }
+ // Verify param: object; type: refptr_diff
+ DCHECK(object);
+ if (!object) {
+ return 0;
+ }
+ // Verify param: retval; type: refptr_diff_byref
+ DCHECK(retval);
+ if (!retval) {
+ return 0;
+ }
+ // Verify param: exception; type: string_byref
+ DCHECK(exception);
+ if (!exception) {
+ return 0;
+ }
+
+ // Translate param: retval; type: refptr_diff_byref
+ CefRefPtr<CefV8Value> retvalPtr;
+ if (retval && *retval) {
+ retvalPtr = CefV8ValueCToCpp::Wrap(*retval);
+ }
+ CefV8Value* retvalOrig = retvalPtr.get();
+ // Translate param: exception; type: string_byref
+ CefString exceptionStr(exception);
+
+ // Execute
+ bool _retval = CefV8AccessorCppToC::Get(self)->Get(
+ CefString(name), CefV8ValueCToCpp::Wrap(object), retvalPtr, exceptionStr);
+
+ // Restore param: retval; type: refptr_diff_byref
+ if (retval) {
+ if (retvalPtr.get()) {
+ if (retvalPtr.get() != retvalOrig) {
+ *retval = CefV8ValueCToCpp::Unwrap(retvalPtr);
+ }
+ } else {
+ *retval = nullptr;
+ }
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK v8accessor_set(struct _cef_v8accessor_t* self,
+ const cef_string_t* name,
+ struct _cef_v8value_t* object,
+ struct _cef_v8value_t* value,
+ cef_string_t* exception) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: name; type: string_byref_const
+ DCHECK(name);
+ if (!name) {
+ return 0;
+ }
+ // Verify param: object; type: refptr_diff
+ DCHECK(object);
+ if (!object) {
+ return 0;
+ }
+ // Verify param: value; type: refptr_diff
+ DCHECK(value);
+ if (!value) {
+ return 0;
+ }
+ // Verify param: exception; type: string_byref
+ DCHECK(exception);
+ if (!exception) {
+ return 0;
+ }
+
+ // Translate param: exception; type: string_byref
+ CefString exceptionStr(exception);
+
+ // Execute
+ bool _retval = CefV8AccessorCppToC::Get(self)->Set(
+ CefString(name), CefV8ValueCToCpp::Wrap(object),
+ CefV8ValueCToCpp::Wrap(value), exceptionStr);
+
+ // Return type: bool
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefV8AccessorCppToC::CefV8AccessorCppToC() {
+ GetStruct()->get = v8accessor_get;
+ GetStruct()->set = v8accessor_set;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefV8AccessorCppToC::~CefV8AccessorCppToC() {}
+
+template <>
+CefRefPtr<CefV8Accessor>
+CefCppToCRefCounted<CefV8AccessorCppToC, CefV8Accessor, cef_v8accessor_t>::
+ UnwrapDerived(CefWrapperType type, cef_v8accessor_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefV8AccessorCppToC,
+ CefV8Accessor,
+ cef_v8accessor_t>::kWrapperType =
+ WT_V8ACCESSOR;
diff --git a/libcef_dll/cpptoc/v8accessor_cpptoc.h b/libcef_dll/cpptoc/v8accessor_cpptoc.h
new file mode 100644
index 00000000..fb40f863
--- /dev/null
+++ b/libcef_dll/cpptoc/v8accessor_cpptoc.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=b8975b107d5912bdcc3e66229119fed6316d269c$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_V8ACCESSOR_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_V8ACCESSOR_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_v8_capi.h"
+#include "include/cef_v8.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefV8AccessorCppToC : public CefCppToCRefCounted<CefV8AccessorCppToC,
+ CefV8Accessor,
+ cef_v8accessor_t> {
+ public:
+ CefV8AccessorCppToC();
+ virtual ~CefV8AccessorCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_V8ACCESSOR_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/v8array_buffer_release_callback_cpptoc.cc b/libcef_dll/cpptoc/v8array_buffer_release_callback_cpptoc.cc
new file mode 100644
index 00000000..55cabaa3
--- /dev/null
+++ b/libcef_dll/cpptoc/v8array_buffer_release_callback_cpptoc.cc
@@ -0,0 +1,69 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=cba0c0be85a7b8de588f939e43c267dbfe5eaca7$
+//
+
+#include "libcef_dll/cpptoc/v8array_buffer_release_callback_cpptoc.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK v8array_buffer_release_callback_release_buffer(
+ struct _cef_v8array_buffer_release_callback_t* self,
+ void* buffer) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: buffer; type: simple_byaddr
+ DCHECK(buffer);
+ if (!buffer) {
+ return;
+ }
+
+ // Execute
+ CefV8ArrayBufferReleaseCallbackCppToC::Get(self)->ReleaseBuffer(buffer);
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefV8ArrayBufferReleaseCallbackCppToC::CefV8ArrayBufferReleaseCallbackCppToC() {
+ GetStruct()->release_buffer = v8array_buffer_release_callback_release_buffer;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefV8ArrayBufferReleaseCallbackCppToC::
+ ~CefV8ArrayBufferReleaseCallbackCppToC() {}
+
+template <>
+CefRefPtr<CefV8ArrayBufferReleaseCallback>
+CefCppToCRefCounted<CefV8ArrayBufferReleaseCallbackCppToC,
+ CefV8ArrayBufferReleaseCallback,
+ cef_v8array_buffer_release_callback_t>::
+ UnwrapDerived(CefWrapperType type,
+ cef_v8array_buffer_release_callback_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCppToCRefCounted<CefV8ArrayBufferReleaseCallbackCppToC,
+ CefV8ArrayBufferReleaseCallback,
+ cef_v8array_buffer_release_callback_t>::kWrapperType =
+ WT_V8ARRAY_BUFFER_RELEASE_CALLBACK;
diff --git a/libcef_dll/cpptoc/v8array_buffer_release_callback_cpptoc.h b/libcef_dll/cpptoc/v8array_buffer_release_callback_cpptoc.h
new file mode 100644
index 00000000..650881c3
--- /dev/null
+++ b/libcef_dll/cpptoc/v8array_buffer_release_callback_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=f3cb7f220bf24ad178eed9b14d8b6e3d1baed6d5$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_V8ARRAY_BUFFER_RELEASE_CALLBACK_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_V8ARRAY_BUFFER_RELEASE_CALLBACK_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_v8_capi.h"
+#include "include/cef_v8.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefV8ArrayBufferReleaseCallbackCppToC
+ : public CefCppToCRefCounted<CefV8ArrayBufferReleaseCallbackCppToC,
+ CefV8ArrayBufferReleaseCallback,
+ cef_v8array_buffer_release_callback_t> {
+ public:
+ CefV8ArrayBufferReleaseCallbackCppToC();
+ virtual ~CefV8ArrayBufferReleaseCallbackCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_V8ARRAY_BUFFER_RELEASE_CALLBACK_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/v8context_cpptoc.cc b/libcef_dll/cpptoc/v8context_cpptoc.cc
new file mode 100644
index 00000000..bdc403c4
--- /dev/null
+++ b/libcef_dll/cpptoc/v8context_cpptoc.cc
@@ -0,0 +1,293 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=41198a9138698a683a4d2d7e3fd8a6116cdd3923$
+//
+
+#include "libcef_dll/cpptoc/v8context_cpptoc.h"
+#include "libcef_dll/cpptoc/browser_cpptoc.h"
+#include "libcef_dll/cpptoc/frame_cpptoc.h"
+#include "libcef_dll/cpptoc/task_runner_cpptoc.h"
+#include "libcef_dll/cpptoc/v8exception_cpptoc.h"
+#include "libcef_dll/cpptoc/v8value_cpptoc.h"
+
+// GLOBAL FUNCTIONS - Body may be edited by hand.
+
+CEF_EXPORT cef_v8context_t* cef_v8context_get_current_context() {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ CefRefPtr<CefV8Context> _retval = CefV8Context::GetCurrentContext();
+
+ // Return type: refptr_same
+ return CefV8ContextCppToC::Wrap(_retval);
+}
+
+CEF_EXPORT cef_v8context_t* cef_v8context_get_entered_context() {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ CefRefPtr<CefV8Context> _retval = CefV8Context::GetEnteredContext();
+
+ // Return type: refptr_same
+ return CefV8ContextCppToC::Wrap(_retval);
+}
+
+CEF_EXPORT int cef_v8context_in_context() {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ bool _retval = CefV8Context::InContext();
+
+ // Return type: bool
+ return _retval;
+}
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+cef_task_runner_t* CEF_CALLBACK
+v8context_get_task_runner(struct _cef_v8context_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefTaskRunner> _retval =
+ CefV8ContextCppToC::Get(self)->GetTaskRunner();
+
+ // Return type: refptr_same
+ return CefTaskRunnerCppToC::Wrap(_retval);
+}
+
+int CEF_CALLBACK v8context_is_valid(struct _cef_v8context_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefV8ContextCppToC::Get(self)->IsValid();
+
+ // Return type: bool
+ return _retval;
+}
+
+cef_browser_t* CEF_CALLBACK
+v8context_get_browser(struct _cef_v8context_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefBrowser> _retval = CefV8ContextCppToC::Get(self)->GetBrowser();
+
+ // Return type: refptr_same
+ return CefBrowserCppToC::Wrap(_retval);
+}
+
+cef_frame_t* CEF_CALLBACK v8context_get_frame(struct _cef_v8context_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefFrame> _retval = CefV8ContextCppToC::Get(self)->GetFrame();
+
+ // Return type: refptr_same
+ return CefFrameCppToC::Wrap(_retval);
+}
+
+struct _cef_v8value_t* CEF_CALLBACK
+v8context_get_global(struct _cef_v8context_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefV8Value> _retval = CefV8ContextCppToC::Get(self)->GetGlobal();
+
+ // Return type: refptr_same
+ return CefV8ValueCppToC::Wrap(_retval);
+}
+
+int CEF_CALLBACK v8context_enter(struct _cef_v8context_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefV8ContextCppToC::Get(self)->Enter();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK v8context_exit(struct _cef_v8context_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefV8ContextCppToC::Get(self)->Exit();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK v8context_is_same(struct _cef_v8context_t* self,
+ struct _cef_v8context_t* that) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: that; type: refptr_same
+ DCHECK(that);
+ if (!that) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefV8ContextCppToC::Get(self)->IsSame(CefV8ContextCppToC::Unwrap(that));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK v8context_eval(struct _cef_v8context_t* self,
+ const cef_string_t* code,
+ const cef_string_t* script_url,
+ int start_line,
+ struct _cef_v8value_t** retval,
+ struct _cef_v8exception_t** exception) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: code; type: string_byref_const
+ DCHECK(code);
+ if (!code) {
+ return 0;
+ }
+ // Verify param: retval; type: refptr_same_byref
+ DCHECK(retval);
+ if (!retval) {
+ return 0;
+ }
+ // Verify param: exception; type: refptr_same_byref
+ DCHECK(exception);
+ if (!exception) {
+ return 0;
+ }
+ // Unverified params: script_url
+
+ // Translate param: retval; type: refptr_same_byref
+ CefRefPtr<CefV8Value> retvalPtr;
+ if (retval && *retval) {
+ retvalPtr = CefV8ValueCppToC::Unwrap(*retval);
+ }
+ CefV8Value* retvalOrig = retvalPtr.get();
+ // Translate param: exception; type: refptr_same_byref
+ CefRefPtr<CefV8Exception> exceptionPtr;
+ if (exception && *exception) {
+ exceptionPtr = CefV8ExceptionCppToC::Unwrap(*exception);
+ }
+ CefV8Exception* exceptionOrig = exceptionPtr.get();
+
+ // Execute
+ bool _retval = CefV8ContextCppToC::Get(self)->Eval(
+ CefString(code), CefString(script_url), start_line, retvalPtr,
+ exceptionPtr);
+
+ // Restore param: retval; type: refptr_same_byref
+ if (retval) {
+ if (retvalPtr.get()) {
+ if (retvalPtr.get() != retvalOrig) {
+ *retval = CefV8ValueCppToC::Wrap(retvalPtr);
+ }
+ } else {
+ *retval = nullptr;
+ }
+ }
+ // Restore param: exception; type: refptr_same_byref
+ if (exception) {
+ if (exceptionPtr.get()) {
+ if (exceptionPtr.get() != exceptionOrig) {
+ *exception = CefV8ExceptionCppToC::Wrap(exceptionPtr);
+ }
+ } else {
+ *exception = nullptr;
+ }
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefV8ContextCppToC::CefV8ContextCppToC() {
+ GetStruct()->get_task_runner = v8context_get_task_runner;
+ GetStruct()->is_valid = v8context_is_valid;
+ GetStruct()->get_browser = v8context_get_browser;
+ GetStruct()->get_frame = v8context_get_frame;
+ GetStruct()->get_global = v8context_get_global;
+ GetStruct()->enter = v8context_enter;
+ GetStruct()->exit = v8context_exit;
+ GetStruct()->is_same = v8context_is_same;
+ GetStruct()->eval = v8context_eval;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefV8ContextCppToC::~CefV8ContextCppToC() {}
+
+template <>
+CefRefPtr<CefV8Context>
+CefCppToCRefCounted<CefV8ContextCppToC, CefV8Context, cef_v8context_t>::
+ UnwrapDerived(CefWrapperType type, cef_v8context_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefV8ContextCppToC,
+ CefV8Context,
+ cef_v8context_t>::kWrapperType =
+ WT_V8CONTEXT;
diff --git a/libcef_dll/cpptoc/v8context_cpptoc.h b/libcef_dll/cpptoc/v8context_cpptoc.h
new file mode 100644
index 00000000..5b7746d2
--- /dev/null
+++ b/libcef_dll/cpptoc/v8context_cpptoc.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=251051522f71e61a56b0844596a6ca2d858915c8$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_V8CONTEXT_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_V8CONTEXT_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_v8_capi.h"
+#include "include/cef_v8.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefV8ContextCppToC : public CefCppToCRefCounted<CefV8ContextCppToC,
+ CefV8Context,
+ cef_v8context_t> {
+ public:
+ CefV8ContextCppToC();
+ virtual ~CefV8ContextCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_V8CONTEXT_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/v8exception_cpptoc.cc b/libcef_dll/cpptoc/v8exception_cpptoc.cc
new file mode 100644
index 00000000..e18ee5ca
--- /dev/null
+++ b/libcef_dll/cpptoc/v8exception_cpptoc.cc
@@ -0,0 +1,176 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=4870e3ecf7cc7455aeeb82cbc545f01a248b3306$
+//
+
+#include "libcef_dll/cpptoc/v8exception_cpptoc.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+cef_string_userfree_t CEF_CALLBACK
+v8exception_get_message(struct _cef_v8exception_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefV8ExceptionCppToC::Get(self)->GetMessage();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_string_userfree_t CEF_CALLBACK
+v8exception_get_source_line(struct _cef_v8exception_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefV8ExceptionCppToC::Get(self)->GetSourceLine();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_string_userfree_t CEF_CALLBACK
+v8exception_get_script_resource_name(struct _cef_v8exception_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefV8ExceptionCppToC::Get(self)->GetScriptResourceName();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+int CEF_CALLBACK v8exception_get_line_number(struct _cef_v8exception_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefV8ExceptionCppToC::Get(self)->GetLineNumber();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK
+v8exception_get_start_position(struct _cef_v8exception_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefV8ExceptionCppToC::Get(self)->GetStartPosition();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK v8exception_get_end_position(struct _cef_v8exception_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefV8ExceptionCppToC::Get(self)->GetEndPosition();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK v8exception_get_start_column(struct _cef_v8exception_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefV8ExceptionCppToC::Get(self)->GetStartColumn();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK v8exception_get_end_column(struct _cef_v8exception_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefV8ExceptionCppToC::Get(self)->GetEndColumn();
+
+ // Return type: simple
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefV8ExceptionCppToC::CefV8ExceptionCppToC() {
+ GetStruct()->get_message = v8exception_get_message;
+ GetStruct()->get_source_line = v8exception_get_source_line;
+ GetStruct()->get_script_resource_name = v8exception_get_script_resource_name;
+ GetStruct()->get_line_number = v8exception_get_line_number;
+ GetStruct()->get_start_position = v8exception_get_start_position;
+ GetStruct()->get_end_position = v8exception_get_end_position;
+ GetStruct()->get_start_column = v8exception_get_start_column;
+ GetStruct()->get_end_column = v8exception_get_end_column;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefV8ExceptionCppToC::~CefV8ExceptionCppToC() {}
+
+template <>
+CefRefPtr<CefV8Exception>
+CefCppToCRefCounted<CefV8ExceptionCppToC, CefV8Exception, cef_v8exception_t>::
+ UnwrapDerived(CefWrapperType type, cef_v8exception_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefV8ExceptionCppToC,
+ CefV8Exception,
+ cef_v8exception_t>::kWrapperType =
+ WT_V8EXCEPTION;
diff --git a/libcef_dll/cpptoc/v8exception_cpptoc.h b/libcef_dll/cpptoc/v8exception_cpptoc.h
new file mode 100644
index 00000000..d9f8725b
--- /dev/null
+++ b/libcef_dll/cpptoc/v8exception_cpptoc.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=438f4efa56776c515c7c42c6a7dae68937729fef$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_V8EXCEPTION_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_V8EXCEPTION_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_v8_capi.h"
+#include "include/cef_v8.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefV8ExceptionCppToC : public CefCppToCRefCounted<CefV8ExceptionCppToC,
+ CefV8Exception,
+ cef_v8exception_t> {
+ public:
+ CefV8ExceptionCppToC();
+ virtual ~CefV8ExceptionCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_V8EXCEPTION_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/v8handler_cpptoc.cc b/libcef_dll/cpptoc/v8handler_cpptoc.cc
new file mode 100644
index 00000000..3951e81b
--- /dev/null
+++ b/libcef_dll/cpptoc/v8handler_cpptoc.cc
@@ -0,0 +1,122 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=27cf2c55d79ea035daa2c3b595d6a6bbe4e36b86$
+//
+
+#include "libcef_dll/cpptoc/v8handler_cpptoc.h"
+#include "libcef_dll/ctocpp/v8value_ctocpp.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK v8handler_execute(struct _cef_v8handler_t* self,
+ const cef_string_t* name,
+ struct _cef_v8value_t* object,
+ size_t argumentsCount,
+ struct _cef_v8value_t* const* arguments,
+ struct _cef_v8value_t** retval,
+ cef_string_t* exception) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: name; type: string_byref_const
+ DCHECK(name);
+ if (!name) {
+ return 0;
+ }
+ // Verify param: object; type: refptr_diff
+ DCHECK(object);
+ if (!object) {
+ return 0;
+ }
+ // Verify param: arguments; type: refptr_vec_diff_byref_const
+ DCHECK(argumentsCount == 0 || arguments);
+ if (argumentsCount > 0 && !arguments) {
+ return 0;
+ }
+ // Verify param: retval; type: refptr_diff_byref
+ DCHECK(retval);
+ if (!retval) {
+ return 0;
+ }
+ // Verify param: exception; type: string_byref
+ DCHECK(exception);
+ if (!exception) {
+ return 0;
+ }
+
+ // Translate param: arguments; type: refptr_vec_diff_byref_const
+ std::vector<CefRefPtr<CefV8Value>> argumentsList;
+ if (argumentsCount > 0) {
+ for (size_t i = 0; i < argumentsCount; ++i) {
+ CefRefPtr<CefV8Value> argumentsVal = CefV8ValueCToCpp::Wrap(arguments[i]);
+ argumentsList.push_back(argumentsVal);
+ }
+ }
+ // Translate param: retval; type: refptr_diff_byref
+ CefRefPtr<CefV8Value> retvalPtr;
+ if (retval && *retval) {
+ retvalPtr = CefV8ValueCToCpp::Wrap(*retval);
+ }
+ CefV8Value* retvalOrig = retvalPtr.get();
+ // Translate param: exception; type: string_byref
+ CefString exceptionStr(exception);
+
+ // Execute
+ bool _retval = CefV8HandlerCppToC::Get(self)->Execute(
+ CefString(name), CefV8ValueCToCpp::Wrap(object), argumentsList, retvalPtr,
+ exceptionStr);
+
+ // Restore param: retval; type: refptr_diff_byref
+ if (retval) {
+ if (retvalPtr.get()) {
+ if (retvalPtr.get() != retvalOrig) {
+ *retval = CefV8ValueCToCpp::Unwrap(retvalPtr);
+ }
+ } else {
+ *retval = nullptr;
+ }
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefV8HandlerCppToC::CefV8HandlerCppToC() {
+ GetStruct()->execute = v8handler_execute;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefV8HandlerCppToC::~CefV8HandlerCppToC() {}
+
+template <>
+CefRefPtr<CefV8Handler>
+CefCppToCRefCounted<CefV8HandlerCppToC, CefV8Handler, cef_v8handler_t>::
+ UnwrapDerived(CefWrapperType type, cef_v8handler_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefV8HandlerCppToC,
+ CefV8Handler,
+ cef_v8handler_t>::kWrapperType =
+ WT_V8HANDLER;
diff --git a/libcef_dll/cpptoc/v8handler_cpptoc.h b/libcef_dll/cpptoc/v8handler_cpptoc.h
new file mode 100644
index 00000000..f3122ffc
--- /dev/null
+++ b/libcef_dll/cpptoc/v8handler_cpptoc.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=25ab4ee4f4c72c6be2e4df28dfaa8bbe5ec522d6$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_V8HANDLER_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_V8HANDLER_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_v8_capi.h"
+#include "include/cef_v8.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefV8HandlerCppToC : public CefCppToCRefCounted<CefV8HandlerCppToC,
+ CefV8Handler,
+ cef_v8handler_t> {
+ public:
+ CefV8HandlerCppToC();
+ virtual ~CefV8HandlerCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_V8HANDLER_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/v8interceptor_cpptoc.cc b/libcef_dll/cpptoc/v8interceptor_cpptoc.cc
new file mode 100644
index 00000000..bcd3743d
--- /dev/null
+++ b/libcef_dll/cpptoc/v8interceptor_cpptoc.cc
@@ -0,0 +1,259 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=c636c92ceb26daa758f12cb54a39277e69d721e6$
+//
+
+#include "libcef_dll/cpptoc/v8interceptor_cpptoc.h"
+#include "libcef_dll/ctocpp/v8value_ctocpp.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK v8interceptor_get_byname(struct _cef_v8interceptor_t* self,
+ const cef_string_t* name,
+ struct _cef_v8value_t* object,
+ struct _cef_v8value_t** retval,
+ cef_string_t* exception) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: name; type: string_byref_const
+ DCHECK(name);
+ if (!name) {
+ return 0;
+ }
+ // Verify param: object; type: refptr_diff
+ DCHECK(object);
+ if (!object) {
+ return 0;
+ }
+ // Verify param: retval; type: refptr_diff_byref
+ DCHECK(retval);
+ if (!retval) {
+ return 0;
+ }
+ // Verify param: exception; type: string_byref
+ DCHECK(exception);
+ if (!exception) {
+ return 0;
+ }
+
+ // Translate param: retval; type: refptr_diff_byref
+ CefRefPtr<CefV8Value> retvalPtr;
+ if (retval && *retval) {
+ retvalPtr = CefV8ValueCToCpp::Wrap(*retval);
+ }
+ CefV8Value* retvalOrig = retvalPtr.get();
+ // Translate param: exception; type: string_byref
+ CefString exceptionStr(exception);
+
+ // Execute
+ bool _retval = CefV8InterceptorCppToC::Get(self)->Get(
+ CefString(name), CefV8ValueCToCpp::Wrap(object), retvalPtr, exceptionStr);
+
+ // Restore param: retval; type: refptr_diff_byref
+ if (retval) {
+ if (retvalPtr.get()) {
+ if (retvalPtr.get() != retvalOrig) {
+ *retval = CefV8ValueCToCpp::Unwrap(retvalPtr);
+ }
+ } else {
+ *retval = nullptr;
+ }
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK v8interceptor_get_byindex(struct _cef_v8interceptor_t* self,
+ int index,
+ struct _cef_v8value_t* object,
+ struct _cef_v8value_t** retval,
+ cef_string_t* exception) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: index; type: simple_byval
+ DCHECK_GE(index, 0);
+ if (index < 0) {
+ return 0;
+ }
+ // Verify param: object; type: refptr_diff
+ DCHECK(object);
+ if (!object) {
+ return 0;
+ }
+ // Verify param: retval; type: refptr_diff_byref
+ DCHECK(retval);
+ if (!retval) {
+ return 0;
+ }
+ // Verify param: exception; type: string_byref
+ DCHECK(exception);
+ if (!exception) {
+ return 0;
+ }
+
+ // Translate param: retval; type: refptr_diff_byref
+ CefRefPtr<CefV8Value> retvalPtr;
+ if (retval && *retval) {
+ retvalPtr = CefV8ValueCToCpp::Wrap(*retval);
+ }
+ CefV8Value* retvalOrig = retvalPtr.get();
+ // Translate param: exception; type: string_byref
+ CefString exceptionStr(exception);
+
+ // Execute
+ bool _retval = CefV8InterceptorCppToC::Get(self)->Get(
+ index, CefV8ValueCToCpp::Wrap(object), retvalPtr, exceptionStr);
+
+ // Restore param: retval; type: refptr_diff_byref
+ if (retval) {
+ if (retvalPtr.get()) {
+ if (retvalPtr.get() != retvalOrig) {
+ *retval = CefV8ValueCToCpp::Unwrap(retvalPtr);
+ }
+ } else {
+ *retval = nullptr;
+ }
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK v8interceptor_set_byname(struct _cef_v8interceptor_t* self,
+ const cef_string_t* name,
+ struct _cef_v8value_t* object,
+ struct _cef_v8value_t* value,
+ cef_string_t* exception) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: name; type: string_byref_const
+ DCHECK(name);
+ if (!name) {
+ return 0;
+ }
+ // Verify param: object; type: refptr_diff
+ DCHECK(object);
+ if (!object) {
+ return 0;
+ }
+ // Verify param: value; type: refptr_diff
+ DCHECK(value);
+ if (!value) {
+ return 0;
+ }
+ // Verify param: exception; type: string_byref
+ DCHECK(exception);
+ if (!exception) {
+ return 0;
+ }
+
+ // Translate param: exception; type: string_byref
+ CefString exceptionStr(exception);
+
+ // Execute
+ bool _retval = CefV8InterceptorCppToC::Get(self)->Set(
+ CefString(name), CefV8ValueCToCpp::Wrap(object),
+ CefV8ValueCToCpp::Wrap(value), exceptionStr);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK v8interceptor_set_byindex(struct _cef_v8interceptor_t* self,
+ int index,
+ struct _cef_v8value_t* object,
+ struct _cef_v8value_t* value,
+ cef_string_t* exception) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: index; type: simple_byval
+ DCHECK_GE(index, 0);
+ if (index < 0) {
+ return 0;
+ }
+ // Verify param: object; type: refptr_diff
+ DCHECK(object);
+ if (!object) {
+ return 0;
+ }
+ // Verify param: value; type: refptr_diff
+ DCHECK(value);
+ if (!value) {
+ return 0;
+ }
+ // Verify param: exception; type: string_byref
+ DCHECK(exception);
+ if (!exception) {
+ return 0;
+ }
+
+ // Translate param: exception; type: string_byref
+ CefString exceptionStr(exception);
+
+ // Execute
+ bool _retval = CefV8InterceptorCppToC::Get(self)->Set(
+ index, CefV8ValueCToCpp::Wrap(object), CefV8ValueCToCpp::Wrap(value),
+ exceptionStr);
+
+ // Return type: bool
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefV8InterceptorCppToC::CefV8InterceptorCppToC() {
+ GetStruct()->get_byname = v8interceptor_get_byname;
+ GetStruct()->get_byindex = v8interceptor_get_byindex;
+ GetStruct()->set_byname = v8interceptor_set_byname;
+ GetStruct()->set_byindex = v8interceptor_set_byindex;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefV8InterceptorCppToC::~CefV8InterceptorCppToC() {}
+
+template <>
+CefRefPtr<CefV8Interceptor> CefCppToCRefCounted<
+ CefV8InterceptorCppToC,
+ CefV8Interceptor,
+ cef_v8interceptor_t>::UnwrapDerived(CefWrapperType type,
+ cef_v8interceptor_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefV8InterceptorCppToC,
+ CefV8Interceptor,
+ cef_v8interceptor_t>::kWrapperType =
+ WT_V8INTERCEPTOR;
diff --git a/libcef_dll/cpptoc/v8interceptor_cpptoc.h b/libcef_dll/cpptoc/v8interceptor_cpptoc.h
new file mode 100644
index 00000000..07f4a629
--- /dev/null
+++ b/libcef_dll/cpptoc/v8interceptor_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=17704763b12cf8c125a358d2db96037f13613b17$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_V8INTERCEPTOR_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_V8INTERCEPTOR_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_v8_capi.h"
+#include "include/cef_v8.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefV8InterceptorCppToC
+ : public CefCppToCRefCounted<CefV8InterceptorCppToC,
+ CefV8Interceptor,
+ cef_v8interceptor_t> {
+ public:
+ CefV8InterceptorCppToC();
+ virtual ~CefV8InterceptorCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_V8INTERCEPTOR_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/v8stack_frame_cpptoc.cc b/libcef_dll/cpptoc/v8stack_frame_cpptoc.cc
new file mode 100644
index 00000000..bd6d8435
--- /dev/null
+++ b/libcef_dll/cpptoc/v8stack_frame_cpptoc.cc
@@ -0,0 +1,181 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=9140f32115725c3fc0d7a0be0450c6dc5a47d315$
+//
+
+#include "libcef_dll/cpptoc/v8stack_frame_cpptoc.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK v8stack_frame_is_valid(struct _cef_v8stack_frame_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefV8StackFrameCppToC::Get(self)->IsValid();
+
+ // Return type: bool
+ return _retval;
+}
+
+cef_string_userfree_t CEF_CALLBACK
+v8stack_frame_get_script_name(struct _cef_v8stack_frame_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefV8StackFrameCppToC::Get(self)->GetScriptName();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_string_userfree_t CEF_CALLBACK
+v8stack_frame_get_script_name_or_source_url(struct _cef_v8stack_frame_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval =
+ CefV8StackFrameCppToC::Get(self)->GetScriptNameOrSourceURL();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_string_userfree_t CEF_CALLBACK
+v8stack_frame_get_function_name(struct _cef_v8stack_frame_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefV8StackFrameCppToC::Get(self)->GetFunctionName();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+int CEF_CALLBACK
+v8stack_frame_get_line_number(struct _cef_v8stack_frame_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefV8StackFrameCppToC::Get(self)->GetLineNumber();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK v8stack_frame_get_column(struct _cef_v8stack_frame_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefV8StackFrameCppToC::Get(self)->GetColumn();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK v8stack_frame_is_eval(struct _cef_v8stack_frame_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefV8StackFrameCppToC::Get(self)->IsEval();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+v8stack_frame_is_constructor(struct _cef_v8stack_frame_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefV8StackFrameCppToC::Get(self)->IsConstructor();
+
+ // Return type: bool
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefV8StackFrameCppToC::CefV8StackFrameCppToC() {
+ GetStruct()->is_valid = v8stack_frame_is_valid;
+ GetStruct()->get_script_name = v8stack_frame_get_script_name;
+ GetStruct()->get_script_name_or_source_url =
+ v8stack_frame_get_script_name_or_source_url;
+ GetStruct()->get_function_name = v8stack_frame_get_function_name;
+ GetStruct()->get_line_number = v8stack_frame_get_line_number;
+ GetStruct()->get_column = v8stack_frame_get_column;
+ GetStruct()->is_eval = v8stack_frame_is_eval;
+ GetStruct()->is_constructor = v8stack_frame_is_constructor;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefV8StackFrameCppToC::~CefV8StackFrameCppToC() {}
+
+template <>
+CefRefPtr<CefV8StackFrame> CefCppToCRefCounted<
+ CefV8StackFrameCppToC,
+ CefV8StackFrame,
+ cef_v8stack_frame_t>::UnwrapDerived(CefWrapperType type,
+ cef_v8stack_frame_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefV8StackFrameCppToC,
+ CefV8StackFrame,
+ cef_v8stack_frame_t>::kWrapperType =
+ WT_V8STACK_FRAME;
diff --git a/libcef_dll/cpptoc/v8stack_frame_cpptoc.h b/libcef_dll/cpptoc/v8stack_frame_cpptoc.h
new file mode 100644
index 00000000..fabdf222
--- /dev/null
+++ b/libcef_dll/cpptoc/v8stack_frame_cpptoc.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=a804ebb160de9a40b1e8ce65e1dfca67e5ffb658$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_V8STACK_FRAME_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_V8STACK_FRAME_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_v8_capi.h"
+#include "include/cef_v8.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefV8StackFrameCppToC : public CefCppToCRefCounted<CefV8StackFrameCppToC,
+ CefV8StackFrame,
+ cef_v8stack_frame_t> {
+ public:
+ CefV8StackFrameCppToC();
+ virtual ~CefV8StackFrameCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_V8STACK_FRAME_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/v8stack_trace_cpptoc.cc b/libcef_dll/cpptoc/v8stack_trace_cpptoc.cc
new file mode 100644
index 00000000..58a7005d
--- /dev/null
+++ b/libcef_dll/cpptoc/v8stack_trace_cpptoc.cc
@@ -0,0 +1,121 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=f2e03b1ebb215b895e8b74cf49816fbe6eeccf26$
+//
+
+#include "libcef_dll/cpptoc/v8stack_trace_cpptoc.h"
+#include "libcef_dll/cpptoc/v8stack_frame_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// GLOBAL FUNCTIONS - Body may be edited by hand.
+
+CEF_EXPORT cef_v8stack_trace_t* cef_v8stack_trace_get_current(int frame_limit) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ CefRefPtr<CefV8StackTrace> _retval = CefV8StackTrace::GetCurrent(frame_limit);
+
+ // Return type: refptr_same
+ return CefV8StackTraceCppToC::Wrap(_retval);
+}
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK v8stack_trace_is_valid(struct _cef_v8stack_trace_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefV8StackTraceCppToC::Get(self)->IsValid();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+v8stack_trace_get_frame_count(struct _cef_v8stack_trace_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefV8StackTraceCppToC::Get(self)->GetFrameCount();
+
+ // Return type: simple
+ return _retval;
+}
+
+struct _cef_v8stack_frame_t* CEF_CALLBACK
+v8stack_trace_get_frame(struct _cef_v8stack_trace_t* self, int index) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefV8StackFrame> _retval =
+ CefV8StackTraceCppToC::Get(self)->GetFrame(index);
+
+ // Return type: refptr_same
+ return CefV8StackFrameCppToC::Wrap(_retval);
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefV8StackTraceCppToC::CefV8StackTraceCppToC() {
+ GetStruct()->is_valid = v8stack_trace_is_valid;
+ GetStruct()->get_frame_count = v8stack_trace_get_frame_count;
+ GetStruct()->get_frame = v8stack_trace_get_frame;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefV8StackTraceCppToC::~CefV8StackTraceCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefV8StackTrace> CefCppToCRefCounted<
+ CefV8StackTraceCppToC,
+ CefV8StackTrace,
+ cef_v8stack_trace_t>::UnwrapDerived(CefWrapperType type,
+ cef_v8stack_trace_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefV8StackTraceCppToC,
+ CefV8StackTrace,
+ cef_v8stack_trace_t>::kWrapperType =
+ WT_V8STACK_TRACE;
diff --git a/libcef_dll/cpptoc/v8stack_trace_cpptoc.h b/libcef_dll/cpptoc/v8stack_trace_cpptoc.h
new file mode 100644
index 00000000..c0374479
--- /dev/null
+++ b/libcef_dll/cpptoc/v8stack_trace_cpptoc.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=7d064189557bf22631a1daf8a757128680743960$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_V8STACK_TRACE_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_V8STACK_TRACE_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_v8_capi.h"
+#include "include/cef_v8.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefV8StackTraceCppToC : public CefCppToCRefCounted<CefV8StackTraceCppToC,
+ CefV8StackTrace,
+ cef_v8stack_trace_t> {
+ public:
+ CefV8StackTraceCppToC();
+ virtual ~CefV8StackTraceCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_V8STACK_TRACE_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/v8value_cpptoc.cc b/libcef_dll/cpptoc/v8value_cpptoc.cc
new file mode 100644
index 00000000..b65a80eb
--- /dev/null
+++ b/libcef_dll/cpptoc/v8value_cpptoc.cc
@@ -0,0 +1,1181 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=288abf6f0b6298472cdaeca2fe21e6b6678626fe$
+//
+
+#include "libcef_dll/cpptoc/v8value_cpptoc.h"
+#include "libcef_dll/cpptoc/v8context_cpptoc.h"
+#include "libcef_dll/cpptoc/v8exception_cpptoc.h"
+#include "libcef_dll/ctocpp/base_ref_counted_ctocpp.h"
+#include "libcef_dll/ctocpp/v8accessor_ctocpp.h"
+#include "libcef_dll/ctocpp/v8array_buffer_release_callback_ctocpp.h"
+#include "libcef_dll/ctocpp/v8handler_ctocpp.h"
+#include "libcef_dll/ctocpp/v8interceptor_ctocpp.h"
+#include "libcef_dll/transfer_util.h"
+
+// GLOBAL FUNCTIONS - Body may be edited by hand.
+
+CEF_EXPORT cef_v8value_t* cef_v8value_create_undefined() {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ CefRefPtr<CefV8Value> _retval = CefV8Value::CreateUndefined();
+
+ // Return type: refptr_same
+ return CefV8ValueCppToC::Wrap(_retval);
+}
+
+CEF_EXPORT cef_v8value_t* cef_v8value_create_null() {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ CefRefPtr<CefV8Value> _retval = CefV8Value::CreateNull();
+
+ // Return type: refptr_same
+ return CefV8ValueCppToC::Wrap(_retval);
+}
+
+CEF_EXPORT cef_v8value_t* cef_v8value_create_bool(int value) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ CefRefPtr<CefV8Value> _retval = CefV8Value::CreateBool(value ? true : false);
+
+ // Return type: refptr_same
+ return CefV8ValueCppToC::Wrap(_retval);
+}
+
+CEF_EXPORT cef_v8value_t* cef_v8value_create_int(int32 value) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ CefRefPtr<CefV8Value> _retval = CefV8Value::CreateInt(value);
+
+ // Return type: refptr_same
+ return CefV8ValueCppToC::Wrap(_retval);
+}
+
+CEF_EXPORT cef_v8value_t* cef_v8value_create_uint(uint32 value) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ CefRefPtr<CefV8Value> _retval = CefV8Value::CreateUInt(value);
+
+ // Return type: refptr_same
+ return CefV8ValueCppToC::Wrap(_retval);
+}
+
+CEF_EXPORT cef_v8value_t* cef_v8value_create_double(double value) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ CefRefPtr<CefV8Value> _retval = CefV8Value::CreateDouble(value);
+
+ // Return type: refptr_same
+ return CefV8ValueCppToC::Wrap(_retval);
+}
+
+CEF_EXPORT cef_v8value_t* cef_v8value_create_date(cef_basetime_t date) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ CefRefPtr<CefV8Value> _retval = CefV8Value::CreateDate(date);
+
+ // Return type: refptr_same
+ return CefV8ValueCppToC::Wrap(_retval);
+}
+
+CEF_EXPORT cef_v8value_t* cef_v8value_create_string(const cef_string_t* value) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: value
+
+ // Execute
+ CefRefPtr<CefV8Value> _retval = CefV8Value::CreateString(CefString(value));
+
+ // Return type: refptr_same
+ return CefV8ValueCppToC::Wrap(_retval);
+}
+
+CEF_EXPORT cef_v8value_t* cef_v8value_create_object(
+ cef_v8accessor_t* accessor,
+ cef_v8interceptor_t* interceptor) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: accessor, interceptor
+
+ // Execute
+ CefRefPtr<CefV8Value> _retval =
+ CefV8Value::CreateObject(CefV8AccessorCToCpp::Wrap(accessor),
+ CefV8InterceptorCToCpp::Wrap(interceptor));
+
+ // Return type: refptr_same
+ return CefV8ValueCppToC::Wrap(_retval);
+}
+
+CEF_EXPORT cef_v8value_t* cef_v8value_create_array(int length) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ CefRefPtr<CefV8Value> _retval = CefV8Value::CreateArray(length);
+
+ // Return type: refptr_same
+ return CefV8ValueCppToC::Wrap(_retval);
+}
+
+CEF_EXPORT cef_v8value_t* cef_v8value_create_array_buffer(
+ void* buffer,
+ size_t length,
+ cef_v8array_buffer_release_callback_t* release_callback) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: buffer; type: simple_byaddr
+ DCHECK(buffer);
+ if (!buffer) {
+ return NULL;
+ }
+ // Verify param: release_callback; type: refptr_diff
+ DCHECK(release_callback);
+ if (!release_callback) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefV8Value> _retval = CefV8Value::CreateArrayBuffer(
+ buffer, length,
+ CefV8ArrayBufferReleaseCallbackCToCpp::Wrap(release_callback));
+
+ // Return type: refptr_same
+ return CefV8ValueCppToC::Wrap(_retval);
+}
+
+CEF_EXPORT cef_v8value_t* cef_v8value_create_function(
+ const cef_string_t* name,
+ cef_v8handler_t* handler) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: name; type: string_byref_const
+ DCHECK(name);
+ if (!name) {
+ return NULL;
+ }
+ // Verify param: handler; type: refptr_diff
+ DCHECK(handler);
+ if (!handler) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefV8Value> _retval = CefV8Value::CreateFunction(
+ CefString(name), CefV8HandlerCToCpp::Wrap(handler));
+
+ // Return type: refptr_same
+ return CefV8ValueCppToC::Wrap(_retval);
+}
+
+CEF_EXPORT cef_v8value_t* cef_v8value_create_promise() {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ CefRefPtr<CefV8Value> _retval = CefV8Value::CreatePromise();
+
+ // Return type: refptr_same
+ return CefV8ValueCppToC::Wrap(_retval);
+}
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK v8value_is_valid(struct _cef_v8value_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefV8ValueCppToC::Get(self)->IsValid();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK v8value_is_undefined(struct _cef_v8value_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefV8ValueCppToC::Get(self)->IsUndefined();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK v8value_is_null(struct _cef_v8value_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefV8ValueCppToC::Get(self)->IsNull();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK v8value_is_bool(struct _cef_v8value_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefV8ValueCppToC::Get(self)->IsBool();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK v8value_is_int(struct _cef_v8value_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefV8ValueCppToC::Get(self)->IsInt();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK v8value_is_uint(struct _cef_v8value_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefV8ValueCppToC::Get(self)->IsUInt();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK v8value_is_double(struct _cef_v8value_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefV8ValueCppToC::Get(self)->IsDouble();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK v8value_is_date(struct _cef_v8value_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefV8ValueCppToC::Get(self)->IsDate();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK v8value_is_string(struct _cef_v8value_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefV8ValueCppToC::Get(self)->IsString();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK v8value_is_object(struct _cef_v8value_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefV8ValueCppToC::Get(self)->IsObject();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK v8value_is_array(struct _cef_v8value_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefV8ValueCppToC::Get(self)->IsArray();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK v8value_is_array_buffer(struct _cef_v8value_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefV8ValueCppToC::Get(self)->IsArrayBuffer();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK v8value_is_function(struct _cef_v8value_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefV8ValueCppToC::Get(self)->IsFunction();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK v8value_is_promise(struct _cef_v8value_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefV8ValueCppToC::Get(self)->IsPromise();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK v8value_is_same(struct _cef_v8value_t* self,
+ struct _cef_v8value_t* that) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: that; type: refptr_same
+ DCHECK(that);
+ if (!that) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefV8ValueCppToC::Get(self)->IsSame(CefV8ValueCppToC::Unwrap(that));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK v8value_get_bool_value(struct _cef_v8value_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefV8ValueCppToC::Get(self)->GetBoolValue();
+
+ // Return type: bool
+ return _retval;
+}
+
+int32 CEF_CALLBACK v8value_get_int_value(struct _cef_v8value_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int32 _retval = CefV8ValueCppToC::Get(self)->GetIntValue();
+
+ // Return type: simple
+ return _retval;
+}
+
+uint32 CEF_CALLBACK v8value_get_uint_value(struct _cef_v8value_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ uint32 _retval = CefV8ValueCppToC::Get(self)->GetUIntValue();
+
+ // Return type: simple
+ return _retval;
+}
+
+double CEF_CALLBACK v8value_get_double_value(struct _cef_v8value_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ double _retval = CefV8ValueCppToC::Get(self)->GetDoubleValue();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_basetime_t CEF_CALLBACK
+v8value_get_date_value(struct _cef_v8value_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefBaseTime();
+ }
+
+ // Execute
+ cef_basetime_t _retval = CefV8ValueCppToC::Get(self)->GetDateValue();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_string_userfree_t CEF_CALLBACK
+v8value_get_string_value(struct _cef_v8value_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefV8ValueCppToC::Get(self)->GetStringValue();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+int CEF_CALLBACK v8value_is_user_created(struct _cef_v8value_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefV8ValueCppToC::Get(self)->IsUserCreated();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK v8value_has_exception(struct _cef_v8value_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefV8ValueCppToC::Get(self)->HasException();
+
+ // Return type: bool
+ return _retval;
+}
+
+cef_v8exception_t* CEF_CALLBACK
+v8value_get_exception(struct _cef_v8value_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefV8Exception> _retval =
+ CefV8ValueCppToC::Get(self)->GetException();
+
+ // Return type: refptr_same
+ return CefV8ExceptionCppToC::Wrap(_retval);
+}
+
+int CEF_CALLBACK v8value_clear_exception(struct _cef_v8value_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefV8ValueCppToC::Get(self)->ClearException();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK v8value_will_rethrow_exceptions(struct _cef_v8value_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefV8ValueCppToC::Get(self)->WillRethrowExceptions();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK v8value_set_rethrow_exceptions(struct _cef_v8value_t* self,
+ int rethrow) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefV8ValueCppToC::Get(self)->SetRethrowExceptions(rethrow ? true : false);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK v8value_has_value_bykey(struct _cef_v8value_t* self,
+ const cef_string_t* key) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Unverified params: key
+
+ // Execute
+ bool _retval = CefV8ValueCppToC::Get(self)->HasValue(CefString(key));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK v8value_has_value_byindex(struct _cef_v8value_t* self,
+ int index) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: index; type: simple_byval
+ DCHECK_GE(index, 0);
+ if (index < 0) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefV8ValueCppToC::Get(self)->HasValue(index);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK v8value_delete_value_bykey(struct _cef_v8value_t* self,
+ const cef_string_t* key) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Unverified params: key
+
+ // Execute
+ bool _retval = CefV8ValueCppToC::Get(self)->DeleteValue(CefString(key));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK v8value_delete_value_byindex(struct _cef_v8value_t* self,
+ int index) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: index; type: simple_byval
+ DCHECK_GE(index, 0);
+ if (index < 0) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefV8ValueCppToC::Get(self)->DeleteValue(index);
+
+ // Return type: bool
+ return _retval;
+}
+
+struct _cef_v8value_t* CEF_CALLBACK
+v8value_get_value_bykey(struct _cef_v8value_t* self, const cef_string_t* key) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+ // Unverified params: key
+
+ // Execute
+ CefRefPtr<CefV8Value> _retval =
+ CefV8ValueCppToC::Get(self)->GetValue(CefString(key));
+
+ // Return type: refptr_same
+ return CefV8ValueCppToC::Wrap(_retval);
+}
+
+struct _cef_v8value_t* CEF_CALLBACK
+v8value_get_value_byindex(struct _cef_v8value_t* self, int index) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+ // Verify param: index; type: simple_byval
+ DCHECK_GE(index, 0);
+ if (index < 0) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefV8Value> _retval = CefV8ValueCppToC::Get(self)->GetValue(index);
+
+ // Return type: refptr_same
+ return CefV8ValueCppToC::Wrap(_retval);
+}
+
+int CEF_CALLBACK v8value_set_value_bykey(struct _cef_v8value_t* self,
+ const cef_string_t* key,
+ struct _cef_v8value_t* value,
+ cef_v8_propertyattribute_t attribute) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: value; type: refptr_same
+ DCHECK(value);
+ if (!value) {
+ return 0;
+ }
+ // Unverified params: key
+
+ // Execute
+ bool _retval = CefV8ValueCppToC::Get(self)->SetValue(
+ CefString(key), CefV8ValueCppToC::Unwrap(value), attribute);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK v8value_set_value_byindex(struct _cef_v8value_t* self,
+ int index,
+ struct _cef_v8value_t* value) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: index; type: simple_byval
+ DCHECK_GE(index, 0);
+ if (index < 0) {
+ return 0;
+ }
+ // Verify param: value; type: refptr_same
+ DCHECK(value);
+ if (!value) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefV8ValueCppToC::Get(self)->SetValue(
+ index, CefV8ValueCppToC::Unwrap(value));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+v8value_set_value_byaccessor(struct _cef_v8value_t* self,
+ const cef_string_t* key,
+ cef_v8_accesscontrol_t settings,
+ cef_v8_propertyattribute_t attribute) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Unverified params: key
+
+ // Execute
+ bool _retval = CefV8ValueCppToC::Get(self)->SetValue(CefString(key), settings,
+ attribute);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK v8value_get_keys(struct _cef_v8value_t* self,
+ cef_string_list_t keys) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: keys; type: string_vec_byref
+ DCHECK(keys);
+ if (!keys) {
+ return 0;
+ }
+
+ // Translate param: keys; type: string_vec_byref
+ std::vector<CefString> keysList;
+ transfer_string_list_contents(keys, keysList);
+
+ // Execute
+ bool _retval = CefV8ValueCppToC::Get(self)->GetKeys(keysList);
+
+ // Restore param: keys; type: string_vec_byref
+ cef_string_list_clear(keys);
+ transfer_string_list_contents(keysList, keys);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK v8value_set_user_data(struct _cef_v8value_t* self,
+ cef_base_ref_counted_t* user_data) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Unverified params: user_data
+
+ // Execute
+ bool _retval = CefV8ValueCppToC::Get(self)->SetUserData(
+ CefBaseRefCountedCToCpp::Wrap(user_data));
+
+ // Return type: bool
+ return _retval;
+}
+
+cef_base_ref_counted_t* CEF_CALLBACK
+v8value_get_user_data(struct _cef_v8value_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefBaseRefCounted> _retval =
+ CefV8ValueCppToC::Get(self)->GetUserData();
+
+ // Return type: refptr_diff
+ return CefBaseRefCountedCToCpp::Unwrap(_retval);
+}
+
+int CEF_CALLBACK
+v8value_get_externally_allocated_memory(struct _cef_v8value_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefV8ValueCppToC::Get(self)->GetExternallyAllocatedMemory();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK
+v8value_adjust_externally_allocated_memory(struct _cef_v8value_t* self,
+ int change_in_bytes) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefV8ValueCppToC::Get(self)->AdjustExternallyAllocatedMemory(
+ change_in_bytes);
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK v8value_get_array_length(struct _cef_v8value_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefV8ValueCppToC::Get(self)->GetArrayLength();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_v8array_buffer_release_callback_t* CEF_CALLBACK
+v8value_get_array_buffer_release_callback(struct _cef_v8value_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefV8ArrayBufferReleaseCallback> _retval =
+ CefV8ValueCppToC::Get(self)->GetArrayBufferReleaseCallback();
+
+ // Return type: refptr_diff
+ return CefV8ArrayBufferReleaseCallbackCToCpp::Unwrap(_retval);
+}
+
+int CEF_CALLBACK v8value_neuter_array_buffer(struct _cef_v8value_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefV8ValueCppToC::Get(self)->NeuterArrayBuffer();
+
+ // Return type: bool
+ return _retval;
+}
+
+cef_string_userfree_t CEF_CALLBACK
+v8value_get_function_name(struct _cef_v8value_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefV8ValueCppToC::Get(self)->GetFunctionName();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_v8handler_t* CEF_CALLBACK
+v8value_get_function_handler(struct _cef_v8value_t* self) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefV8Handler> _retval =
+ CefV8ValueCppToC::Get(self)->GetFunctionHandler();
+
+ // Return type: refptr_diff
+ return CefV8HandlerCToCpp::Unwrap(_retval);
+}
+
+struct _cef_v8value_t* CEF_CALLBACK
+v8value_execute_function(struct _cef_v8value_t* self,
+ struct _cef_v8value_t* object,
+ size_t argumentsCount,
+ struct _cef_v8value_t* const* arguments) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+ // Verify param: arguments; type: refptr_vec_same_byref_const
+ DCHECK(argumentsCount == 0 || arguments);
+ if (argumentsCount > 0 && !arguments) {
+ return NULL;
+ }
+ // Unverified params: object
+
+ // Translate param: arguments; type: refptr_vec_same_byref_const
+ std::vector<CefRefPtr<CefV8Value>> argumentsList;
+ if (argumentsCount > 0) {
+ for (size_t i = 0; i < argumentsCount; ++i) {
+ CefRefPtr<CefV8Value> argumentsVal =
+ CefV8ValueCppToC::Unwrap(arguments[i]);
+ argumentsList.push_back(argumentsVal);
+ }
+ }
+
+ // Execute
+ CefRefPtr<CefV8Value> _retval = CefV8ValueCppToC::Get(self)->ExecuteFunction(
+ CefV8ValueCppToC::Unwrap(object), argumentsList);
+
+ // Return type: refptr_same
+ return CefV8ValueCppToC::Wrap(_retval);
+}
+
+struct _cef_v8value_t* CEF_CALLBACK
+v8value_execute_function_with_context(struct _cef_v8value_t* self,
+ cef_v8context_t* context,
+ struct _cef_v8value_t* object,
+ size_t argumentsCount,
+ struct _cef_v8value_t* const* arguments) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+ // Verify param: context; type: refptr_same
+ DCHECK(context);
+ if (!context) {
+ return NULL;
+ }
+ // Verify param: arguments; type: refptr_vec_same_byref_const
+ DCHECK(argumentsCount == 0 || arguments);
+ if (argumentsCount > 0 && !arguments) {
+ return NULL;
+ }
+ // Unverified params: object
+
+ // Translate param: arguments; type: refptr_vec_same_byref_const
+ std::vector<CefRefPtr<CefV8Value>> argumentsList;
+ if (argumentsCount > 0) {
+ for (size_t i = 0; i < argumentsCount; ++i) {
+ CefRefPtr<CefV8Value> argumentsVal =
+ CefV8ValueCppToC::Unwrap(arguments[i]);
+ argumentsList.push_back(argumentsVal);
+ }
+ }
+
+ // Execute
+ CefRefPtr<CefV8Value> _retval =
+ CefV8ValueCppToC::Get(self)->ExecuteFunctionWithContext(
+ CefV8ContextCppToC::Unwrap(context), CefV8ValueCppToC::Unwrap(object),
+ argumentsList);
+
+ // Return type: refptr_same
+ return CefV8ValueCppToC::Wrap(_retval);
+}
+
+int CEF_CALLBACK v8value_resolve_promise(struct _cef_v8value_t* self,
+ struct _cef_v8value_t* arg) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Unverified params: arg
+
+ // Execute
+ bool _retval = CefV8ValueCppToC::Get(self)->ResolvePromise(
+ CefV8ValueCppToC::Unwrap(arg));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK v8value_reject_promise(struct _cef_v8value_t* self,
+ const cef_string_t* errorMsg) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: errorMsg; type: string_byref_const
+ DCHECK(errorMsg);
+ if (!errorMsg) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefV8ValueCppToC::Get(self)->RejectPromise(CefString(errorMsg));
+
+ // Return type: bool
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefV8ValueCppToC::CefV8ValueCppToC() {
+ GetStruct()->is_valid = v8value_is_valid;
+ GetStruct()->is_undefined = v8value_is_undefined;
+ GetStruct()->is_null = v8value_is_null;
+ GetStruct()->is_bool = v8value_is_bool;
+ GetStruct()->is_int = v8value_is_int;
+ GetStruct()->is_uint = v8value_is_uint;
+ GetStruct()->is_double = v8value_is_double;
+ GetStruct()->is_date = v8value_is_date;
+ GetStruct()->is_string = v8value_is_string;
+ GetStruct()->is_object = v8value_is_object;
+ GetStruct()->is_array = v8value_is_array;
+ GetStruct()->is_array_buffer = v8value_is_array_buffer;
+ GetStruct()->is_function = v8value_is_function;
+ GetStruct()->is_promise = v8value_is_promise;
+ GetStruct()->is_same = v8value_is_same;
+ GetStruct()->get_bool_value = v8value_get_bool_value;
+ GetStruct()->get_int_value = v8value_get_int_value;
+ GetStruct()->get_uint_value = v8value_get_uint_value;
+ GetStruct()->get_double_value = v8value_get_double_value;
+ GetStruct()->get_date_value = v8value_get_date_value;
+ GetStruct()->get_string_value = v8value_get_string_value;
+ GetStruct()->is_user_created = v8value_is_user_created;
+ GetStruct()->has_exception = v8value_has_exception;
+ GetStruct()->get_exception = v8value_get_exception;
+ GetStruct()->clear_exception = v8value_clear_exception;
+ GetStruct()->will_rethrow_exceptions = v8value_will_rethrow_exceptions;
+ GetStruct()->set_rethrow_exceptions = v8value_set_rethrow_exceptions;
+ GetStruct()->has_value_bykey = v8value_has_value_bykey;
+ GetStruct()->has_value_byindex = v8value_has_value_byindex;
+ GetStruct()->delete_value_bykey = v8value_delete_value_bykey;
+ GetStruct()->delete_value_byindex = v8value_delete_value_byindex;
+ GetStruct()->get_value_bykey = v8value_get_value_bykey;
+ GetStruct()->get_value_byindex = v8value_get_value_byindex;
+ GetStruct()->set_value_bykey = v8value_set_value_bykey;
+ GetStruct()->set_value_byindex = v8value_set_value_byindex;
+ GetStruct()->set_value_byaccessor = v8value_set_value_byaccessor;
+ GetStruct()->get_keys = v8value_get_keys;
+ GetStruct()->set_user_data = v8value_set_user_data;
+ GetStruct()->get_user_data = v8value_get_user_data;
+ GetStruct()->get_externally_allocated_memory =
+ v8value_get_externally_allocated_memory;
+ GetStruct()->adjust_externally_allocated_memory =
+ v8value_adjust_externally_allocated_memory;
+ GetStruct()->get_array_length = v8value_get_array_length;
+ GetStruct()->get_array_buffer_release_callback =
+ v8value_get_array_buffer_release_callback;
+ GetStruct()->neuter_array_buffer = v8value_neuter_array_buffer;
+ GetStruct()->get_function_name = v8value_get_function_name;
+ GetStruct()->get_function_handler = v8value_get_function_handler;
+ GetStruct()->execute_function = v8value_execute_function;
+ GetStruct()->execute_function_with_context =
+ v8value_execute_function_with_context;
+ GetStruct()->resolve_promise = v8value_resolve_promise;
+ GetStruct()->reject_promise = v8value_reject_promise;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefV8ValueCppToC::~CefV8ValueCppToC() {}
+
+template <>
+CefRefPtr<CefV8Value>
+CefCppToCRefCounted<CefV8ValueCppToC, CefV8Value, cef_v8value_t>::UnwrapDerived(
+ CefWrapperType type,
+ cef_v8value_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefV8ValueCppToC,
+ CefV8Value,
+ cef_v8value_t>::kWrapperType = WT_V8VALUE;
diff --git a/libcef_dll/cpptoc/v8value_cpptoc.h b/libcef_dll/cpptoc/v8value_cpptoc.h
new file mode 100644
index 00000000..87862ae7
--- /dev/null
+++ b/libcef_dll/cpptoc/v8value_cpptoc.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=5b314dd35111aa303aa5d695e75839076f874c90$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_V8VALUE_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_V8VALUE_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_v8_capi.h"
+#include "include/cef_v8.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefV8ValueCppToC
+ : public CefCppToCRefCounted<CefV8ValueCppToC, CefV8Value, cef_v8value_t> {
+ public:
+ CefV8ValueCppToC();
+ virtual ~CefV8ValueCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_V8VALUE_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/value_cpptoc.cc b/libcef_dll/cpptoc/value_cpptoc.cc
new file mode 100644
index 00000000..6e374c48
--- /dev/null
+++ b/libcef_dll/cpptoc/value_cpptoc.cc
@@ -0,0 +1,501 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=ceba5d41469bb3acdd579f21d83d18ec38be4b99$
+//
+
+#include "libcef_dll/cpptoc/value_cpptoc.h"
+#include "libcef_dll/cpptoc/binary_value_cpptoc.h"
+#include "libcef_dll/cpptoc/dictionary_value_cpptoc.h"
+#include "libcef_dll/cpptoc/list_value_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// GLOBAL FUNCTIONS - Body may be edited by hand.
+
+CEF_EXPORT cef_value_t* cef_value_create() {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ CefRefPtr<CefValue> _retval = CefValue::Create();
+
+ // Return type: refptr_same
+ return CefValueCppToC::Wrap(_retval);
+}
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK value_is_valid(struct _cef_value_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefValueCppToC::Get(self)->IsValid();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK value_is_owned(struct _cef_value_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefValueCppToC::Get(self)->IsOwned();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK value_is_read_only(struct _cef_value_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefValueCppToC::Get(self)->IsReadOnly();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK value_is_same(struct _cef_value_t* self,
+ struct _cef_value_t* that) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: that; type: refptr_same
+ DCHECK(that);
+ if (!that) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefValueCppToC::Get(self)->IsSame(CefValueCppToC::Unwrap(that));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK value_is_equal(struct _cef_value_t* self,
+ struct _cef_value_t* that) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: that; type: refptr_same
+ DCHECK(that);
+ if (!that) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefValueCppToC::Get(self)->IsEqual(CefValueCppToC::Unwrap(that));
+
+ // Return type: bool
+ return _retval;
+}
+
+struct _cef_value_t* CEF_CALLBACK value_copy(struct _cef_value_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefValue> _retval = CefValueCppToC::Get(self)->Copy();
+
+ // Return type: refptr_same
+ return CefValueCppToC::Wrap(_retval);
+}
+
+cef_value_type_t CEF_CALLBACK value_get_type(struct _cef_value_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return VTYPE_INVALID;
+ }
+
+ // Execute
+ cef_value_type_t _retval = CefValueCppToC::Get(self)->GetType();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK value_get_bool(struct _cef_value_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefValueCppToC::Get(self)->GetBool();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK value_get_int(struct _cef_value_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefValueCppToC::Get(self)->GetInt();
+
+ // Return type: simple
+ return _retval;
+}
+
+double CEF_CALLBACK value_get_double(struct _cef_value_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ double _retval = CefValueCppToC::Get(self)->GetDouble();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_string_userfree_t CEF_CALLBACK value_get_string(struct _cef_value_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefValueCppToC::Get(self)->GetString();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+struct _cef_binary_value_t* CEF_CALLBACK
+value_get_binary(struct _cef_value_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefBinaryValue> _retval = CefValueCppToC::Get(self)->GetBinary();
+
+ // Return type: refptr_same
+ return CefBinaryValueCppToC::Wrap(_retval);
+}
+
+struct _cef_dictionary_value_t* CEF_CALLBACK
+value_get_dictionary(struct _cef_value_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefDictionaryValue> _retval =
+ CefValueCppToC::Get(self)->GetDictionary();
+
+ // Return type: refptr_same
+ return CefDictionaryValueCppToC::Wrap(_retval);
+}
+
+struct _cef_list_value_t* CEF_CALLBACK
+value_get_list(struct _cef_value_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefListValue> _retval = CefValueCppToC::Get(self)->GetList();
+
+ // Return type: refptr_same
+ return CefListValueCppToC::Wrap(_retval);
+}
+
+int CEF_CALLBACK value_set_null(struct _cef_value_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefValueCppToC::Get(self)->SetNull();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK value_set_bool(struct _cef_value_t* self, int value) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefValueCppToC::Get(self)->SetBool(value ? true : false);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK value_set_int(struct _cef_value_t* self, int value) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefValueCppToC::Get(self)->SetInt(value);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK value_set_double(struct _cef_value_t* self, double value) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefValueCppToC::Get(self)->SetDouble(value);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK value_set_string(struct _cef_value_t* self,
+ const cef_string_t* value) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Unverified params: value
+
+ // Execute
+ bool _retval = CefValueCppToC::Get(self)->SetString(CefString(value));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK value_set_binary(struct _cef_value_t* self,
+ struct _cef_binary_value_t* value) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: value; type: refptr_same
+ DCHECK(value);
+ if (!value) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefValueCppToC::Get(self)->SetBinary(CefBinaryValueCppToC::Unwrap(value));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK value_set_dictionary(struct _cef_value_t* self,
+ struct _cef_dictionary_value_t* value) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: value; type: refptr_same
+ DCHECK(value);
+ if (!value) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefValueCppToC::Get(self)->SetDictionary(
+ CefDictionaryValueCppToC::Unwrap(value));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK value_set_list(struct _cef_value_t* self,
+ struct _cef_list_value_t* value) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: value; type: refptr_same
+ DCHECK(value);
+ if (!value) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefValueCppToC::Get(self)->SetList(CefListValueCppToC::Unwrap(value));
+
+ // Return type: bool
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefValueCppToC::CefValueCppToC() {
+ GetStruct()->is_valid = value_is_valid;
+ GetStruct()->is_owned = value_is_owned;
+ GetStruct()->is_read_only = value_is_read_only;
+ GetStruct()->is_same = value_is_same;
+ GetStruct()->is_equal = value_is_equal;
+ GetStruct()->copy = value_copy;
+ GetStruct()->get_type = value_get_type;
+ GetStruct()->get_bool = value_get_bool;
+ GetStruct()->get_int = value_get_int;
+ GetStruct()->get_double = value_get_double;
+ GetStruct()->get_string = value_get_string;
+ GetStruct()->get_binary = value_get_binary;
+ GetStruct()->get_dictionary = value_get_dictionary;
+ GetStruct()->get_list = value_get_list;
+ GetStruct()->set_null = value_set_null;
+ GetStruct()->set_bool = value_set_bool;
+ GetStruct()->set_int = value_set_int;
+ GetStruct()->set_double = value_set_double;
+ GetStruct()->set_string = value_set_string;
+ GetStruct()->set_binary = value_set_binary;
+ GetStruct()->set_dictionary = value_set_dictionary;
+ GetStruct()->set_list = value_set_list;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefValueCppToC::~CefValueCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefValue>
+CefCppToCRefCounted<CefValueCppToC, CefValue, cef_value_t>::UnwrapDerived(
+ CefWrapperType type,
+ cef_value_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCppToCRefCounted<CefValueCppToC, CefValue, cef_value_t>::kWrapperType =
+ WT_VALUE;
diff --git a/libcef_dll/cpptoc/value_cpptoc.h b/libcef_dll/cpptoc/value_cpptoc.h
new file mode 100644
index 00000000..512155e5
--- /dev/null
+++ b/libcef_dll/cpptoc/value_cpptoc.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=19a491010366c91259449297ea4fb37414ae2a8e$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_VALUE_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_VALUE_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_values_capi.h"
+#include "include/cef_values.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefValueCppToC
+ : public CefCppToCRefCounted<CefValueCppToC, CefValue, cef_value_t> {
+ public:
+ CefValueCppToC();
+ virtual ~CefValueCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_VALUE_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/views/box_layout_cpptoc.cc b/libcef_dll/cpptoc/views/box_layout_cpptoc.cc
new file mode 100644
index 00000000..c8ad949f
--- /dev/null
+++ b/libcef_dll/cpptoc/views/box_layout_cpptoc.cc
@@ -0,0 +1,155 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=fd39feb52a9ace3fda3d5bfda54c4a240173f2ff$
+//
+
+#include "libcef_dll/cpptoc/views/box_layout_cpptoc.h"
+#include "libcef_dll/cpptoc/views/fill_layout_cpptoc.h"
+#include "libcef_dll/cpptoc/views/view_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK box_layout_set_flex_for_view(struct _cef_box_layout_t* self,
+ struct _cef_view_t* view,
+ int flex) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: view; type: refptr_same
+ DCHECK(view);
+ if (!view) {
+ return;
+ }
+
+ // Execute
+ CefBoxLayoutCppToC::Get(self)->SetFlexForView(CefViewCppToC::Unwrap(view),
+ flex);
+}
+
+void CEF_CALLBACK box_layout_clear_flex_for_view(struct _cef_box_layout_t* self,
+ struct _cef_view_t* view) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: view; type: refptr_same
+ DCHECK(view);
+ if (!view) {
+ return;
+ }
+
+ // Execute
+ CefBoxLayoutCppToC::Get(self)->ClearFlexForView(CefViewCppToC::Unwrap(view));
+}
+
+cef_box_layout_t* CEF_CALLBACK
+box_layout_as_box_layout(struct _cef_layout_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefBoxLayout> _retval =
+ CefBoxLayoutCppToC::Get(reinterpret_cast<cef_box_layout_t*>(self))
+ ->AsBoxLayout();
+
+ // Return type: refptr_same
+ return CefBoxLayoutCppToC::Wrap(_retval);
+}
+
+cef_fill_layout_t* CEF_CALLBACK
+box_layout_as_fill_layout(struct _cef_layout_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefFillLayout> _retval =
+ CefBoxLayoutCppToC::Get(reinterpret_cast<cef_box_layout_t*>(self))
+ ->AsFillLayout();
+
+ // Return type: refptr_same
+ return CefFillLayoutCppToC::Wrap(_retval);
+}
+
+int CEF_CALLBACK box_layout_is_valid(struct _cef_layout_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefBoxLayoutCppToC::Get(reinterpret_cast<cef_box_layout_t*>(self))
+ ->IsValid();
+
+ // Return type: bool
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefBoxLayoutCppToC::CefBoxLayoutCppToC() {
+ GetStruct()->set_flex_for_view = box_layout_set_flex_for_view;
+ GetStruct()->clear_flex_for_view = box_layout_clear_flex_for_view;
+ GetStruct()->base.as_box_layout = box_layout_as_box_layout;
+ GetStruct()->base.as_fill_layout = box_layout_as_fill_layout;
+ GetStruct()->base.is_valid = box_layout_is_valid;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefBoxLayoutCppToC::~CefBoxLayoutCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefBoxLayout>
+CefCppToCRefCounted<CefBoxLayoutCppToC, CefBoxLayout, cef_box_layout_t>::
+ UnwrapDerived(CefWrapperType type, cef_box_layout_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefBoxLayoutCppToC,
+ CefBoxLayout,
+ cef_box_layout_t>::kWrapperType =
+ WT_BOX_LAYOUT;
diff --git a/libcef_dll/cpptoc/views/box_layout_cpptoc.h b/libcef_dll/cpptoc/views/box_layout_cpptoc.h
new file mode 100644
index 00000000..fc41243e
--- /dev/null
+++ b/libcef_dll/cpptoc/views/box_layout_cpptoc.h
@@ -0,0 +1,39 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=3f9e4984c1e1eff7e51ab13f9f7fe2ab249657ec$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_VIEWS_BOX_LAYOUT_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_VIEWS_BOX_LAYOUT_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/views/cef_box_layout_capi.h"
+#include "include/capi/views/cef_view_capi.h"
+#include "include/views/cef_box_layout.h"
+#include "include/views/cef_view.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefBoxLayoutCppToC : public CefCppToCRefCounted<CefBoxLayoutCppToC,
+ CefBoxLayout,
+ cef_box_layout_t> {
+ public:
+ CefBoxLayoutCppToC();
+ virtual ~CefBoxLayoutCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_VIEWS_BOX_LAYOUT_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/views/browser_view_cpptoc.cc b/libcef_dll/cpptoc/views/browser_view_cpptoc.cc
new file mode 100644
index 00000000..058773fe
--- /dev/null
+++ b/libcef_dll/cpptoc/views/browser_view_cpptoc.cc
@@ -0,0 +1,1295 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=bb9fa0045c967777df8fd84c5b6c4223f7a84592$
+//
+
+#include "libcef_dll/cpptoc/views/browser_view_cpptoc.h"
+#include "libcef_dll/cpptoc/browser_cpptoc.h"
+#include "libcef_dll/cpptoc/dictionary_value_cpptoc.h"
+#include "libcef_dll/cpptoc/request_context_cpptoc.h"
+#include "libcef_dll/cpptoc/views/button_cpptoc.h"
+#include "libcef_dll/cpptoc/views/panel_cpptoc.h"
+#include "libcef_dll/cpptoc/views/scroll_view_cpptoc.h"
+#include "libcef_dll/cpptoc/views/textfield_cpptoc.h"
+#include "libcef_dll/cpptoc/views/view_cpptoc.h"
+#include "libcef_dll/cpptoc/views/window_cpptoc.h"
+#include "libcef_dll/ctocpp/client_ctocpp.h"
+#include "libcef_dll/ctocpp/views/browser_view_delegate_ctocpp.h"
+#include "libcef_dll/ctocpp/views/view_delegate_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+#include "libcef_dll/template_util.h"
+
+// GLOBAL FUNCTIONS - Body may be edited by hand.
+
+CEF_EXPORT cef_browser_view_t* cef_browser_view_create(
+ cef_client_t* client,
+ const cef_string_t* url,
+ const struct _cef_browser_settings_t* settings,
+ cef_dictionary_value_t* extra_info,
+ cef_request_context_t* request_context,
+ cef_browser_view_delegate_t* delegate) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: settings; type: struct_byref_const
+ DCHECK(settings);
+ if (!settings) {
+ return NULL;
+ }
+ if (!template_util::has_valid_size(settings)) {
+ NOTREACHED() << "invalid settings->[base.]size";
+ return NULL;
+ }
+ // Unverified params: client, url, extra_info, request_context, delegate
+
+ // Translate param: settings; type: struct_byref_const
+ CefBrowserSettings settingsObj;
+ if (settings) {
+ settingsObj.Set(*settings, false);
+ }
+
+ // Execute
+ CefRefPtr<CefBrowserView> _retval = CefBrowserView::CreateBrowserView(
+ CefClientCToCpp::Wrap(client), CefString(url), settingsObj,
+ CefDictionaryValueCppToC::Unwrap(extra_info),
+ CefRequestContextCppToC::Unwrap(request_context),
+ CefBrowserViewDelegateCToCpp::Wrap(delegate));
+
+ // Return type: refptr_same
+ return CefBrowserViewCppToC::Wrap(_retval);
+}
+
+CEF_EXPORT cef_browser_view_t* cef_browser_view_get_for_browser(
+ cef_browser_t* browser) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_same
+ DCHECK(browser);
+ if (!browser) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefBrowserView> _retval =
+ CefBrowserView::GetForBrowser(CefBrowserCppToC::Unwrap(browser));
+
+ // Return type: refptr_same
+ return CefBrowserViewCppToC::Wrap(_retval);
+}
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+cef_browser_t* CEF_CALLBACK
+browser_view_get_browser(struct _cef_browser_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefBrowser> _retval = CefBrowserViewCppToC::Get(self)->GetBrowser();
+
+ // Return type: refptr_same
+ return CefBrowserCppToC::Wrap(_retval);
+}
+
+struct _cef_view_t* CEF_CALLBACK
+browser_view_get_chrome_toolbar(struct _cef_browser_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefView> _retval =
+ CefBrowserViewCppToC::Get(self)->GetChromeToolbar();
+
+ // Return type: refptr_same
+ return CefViewCppToC::Wrap(_retval);
+}
+
+void CEF_CALLBACK
+browser_view_set_prefer_accelerators(struct _cef_browser_view_t* self,
+ int prefer_accelerators) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefBrowserViewCppToC::Get(self)->SetPreferAccelerators(
+ prefer_accelerators ? true : false);
+}
+
+cef_browser_view_t* CEF_CALLBACK
+browser_view_as_browser_view(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefBrowserView> _retval =
+ CefBrowserViewCppToC::Get(reinterpret_cast<cef_browser_view_t*>(self))
+ ->AsBrowserView();
+
+ // Return type: refptr_same
+ return CefBrowserViewCppToC::Wrap(_retval);
+}
+
+cef_button_t* CEF_CALLBACK browser_view_as_button(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefButton> _retval =
+ CefBrowserViewCppToC::Get(reinterpret_cast<cef_browser_view_t*>(self))
+ ->AsButton();
+
+ // Return type: refptr_same
+ return CefButtonCppToC::Wrap(_retval);
+}
+
+cef_panel_t* CEF_CALLBACK browser_view_as_panel(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefPanel> _retval =
+ CefBrowserViewCppToC::Get(reinterpret_cast<cef_browser_view_t*>(self))
+ ->AsPanel();
+
+ // Return type: refptr_same
+ return CefPanelCppToC::Wrap(_retval);
+}
+
+cef_scroll_view_t* CEF_CALLBACK
+browser_view_as_scroll_view(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefScrollView> _retval =
+ CefBrowserViewCppToC::Get(reinterpret_cast<cef_browser_view_t*>(self))
+ ->AsScrollView();
+
+ // Return type: refptr_same
+ return CefScrollViewCppToC::Wrap(_retval);
+}
+
+cef_textfield_t* CEF_CALLBACK
+browser_view_as_textfield(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefTextfield> _retval =
+ CefBrowserViewCppToC::Get(reinterpret_cast<cef_browser_view_t*>(self))
+ ->AsTextfield();
+
+ // Return type: refptr_same
+ return CefTextfieldCppToC::Wrap(_retval);
+}
+
+cef_string_userfree_t CEF_CALLBACK
+browser_view_get_type_string(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval =
+ CefBrowserViewCppToC::Get(reinterpret_cast<cef_browser_view_t*>(self))
+ ->GetTypeString();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_string_userfree_t CEF_CALLBACK
+browser_view_to_string(struct _cef_view_t* self, int include_children) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval =
+ CefBrowserViewCppToC::Get(reinterpret_cast<cef_browser_view_t*>(self))
+ ->ToString(include_children ? true : false);
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+int CEF_CALLBACK browser_view_is_valid(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefBrowserViewCppToC::Get(reinterpret_cast<cef_browser_view_t*>(self))
+ ->IsValid();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK browser_view_is_attached(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefBrowserViewCppToC::Get(reinterpret_cast<cef_browser_view_t*>(self))
+ ->IsAttached();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK browser_view_is_same(struct _cef_view_t* self,
+ struct _cef_view_t* that) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: that; type: refptr_same
+ DCHECK(that);
+ if (!that) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefBrowserViewCppToC::Get(reinterpret_cast<cef_browser_view_t*>(self))
+ ->IsSame(CefViewCppToC::Unwrap(that));
+
+ // Return type: bool
+ return _retval;
+}
+
+struct _cef_view_delegate_t* CEF_CALLBACK
+browser_view_get_delegate(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefViewDelegate> _retval =
+ CefBrowserViewCppToC::Get(reinterpret_cast<cef_browser_view_t*>(self))
+ ->GetDelegate();
+
+ // Return type: refptr_diff
+ return CefViewDelegateCToCpp::Unwrap(_retval);
+}
+
+struct _cef_window_t* CEF_CALLBACK
+browser_view_get_window(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefWindow> _retval =
+ CefBrowserViewCppToC::Get(reinterpret_cast<cef_browser_view_t*>(self))
+ ->GetWindow();
+
+ // Return type: refptr_same
+ return CefWindowCppToC::Wrap(_retval);
+}
+
+int CEF_CALLBACK browser_view_get_id(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval =
+ CefBrowserViewCppToC::Get(reinterpret_cast<cef_browser_view_t*>(self))
+ ->GetID();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK browser_view_set_id(struct _cef_view_t* self, int id) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefBrowserViewCppToC::Get(reinterpret_cast<cef_browser_view_t*>(self))
+ ->SetID(id);
+}
+
+int CEF_CALLBACK browser_view_get_group_id(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval =
+ CefBrowserViewCppToC::Get(reinterpret_cast<cef_browser_view_t*>(self))
+ ->GetGroupID();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK browser_view_set_group_id(struct _cef_view_t* self,
+ int group_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefBrowserViewCppToC::Get(reinterpret_cast<cef_browser_view_t*>(self))
+ ->SetGroupID(group_id);
+}
+
+struct _cef_view_t* CEF_CALLBACK
+browser_view_get_parent_view(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefView> _retval =
+ CefBrowserViewCppToC::Get(reinterpret_cast<cef_browser_view_t*>(self))
+ ->GetParentView();
+
+ // Return type: refptr_same
+ return CefViewCppToC::Wrap(_retval);
+}
+
+struct _cef_view_t* CEF_CALLBACK
+browser_view_get_view_for_id(struct _cef_view_t* self, int id) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefView> _retval =
+ CefBrowserViewCppToC::Get(reinterpret_cast<cef_browser_view_t*>(self))
+ ->GetViewForID(id);
+
+ // Return type: refptr_same
+ return CefViewCppToC::Wrap(_retval);
+}
+
+void CEF_CALLBACK browser_view_set_bounds(struct _cef_view_t* self,
+ const cef_rect_t* bounds) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: bounds; type: simple_byref_const
+ DCHECK(bounds);
+ if (!bounds) {
+ return;
+ }
+
+ // Translate param: bounds; type: simple_byref_const
+ CefRect boundsVal = bounds ? *bounds : CefRect();
+
+ // Execute
+ CefBrowserViewCppToC::Get(reinterpret_cast<cef_browser_view_t*>(self))
+ ->SetBounds(boundsVal);
+}
+
+cef_rect_t CEF_CALLBACK browser_view_get_bounds(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefRect();
+ }
+
+ // Execute
+ cef_rect_t _retval =
+ CefBrowserViewCppToC::Get(reinterpret_cast<cef_browser_view_t*>(self))
+ ->GetBounds();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_rect_t CEF_CALLBACK
+browser_view_get_bounds_in_screen(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefRect();
+ }
+
+ // Execute
+ cef_rect_t _retval =
+ CefBrowserViewCppToC::Get(reinterpret_cast<cef_browser_view_t*>(self))
+ ->GetBoundsInScreen();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK browser_view_set_size(struct _cef_view_t* self,
+ const cef_size_t* size) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: size; type: simple_byref_const
+ DCHECK(size);
+ if (!size) {
+ return;
+ }
+
+ // Translate param: size; type: simple_byref_const
+ CefSize sizeVal = size ? *size : CefSize();
+
+ // Execute
+ CefBrowserViewCppToC::Get(reinterpret_cast<cef_browser_view_t*>(self))
+ ->SetSize(sizeVal);
+}
+
+cef_size_t CEF_CALLBACK browser_view_get_size(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval =
+ CefBrowserViewCppToC::Get(reinterpret_cast<cef_browser_view_t*>(self))
+ ->GetSize();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK browser_view_set_position(struct _cef_view_t* self,
+ const cef_point_t* position) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: position; type: simple_byref_const
+ DCHECK(position);
+ if (!position) {
+ return;
+ }
+
+ // Translate param: position; type: simple_byref_const
+ CefPoint positionVal = position ? *position : CefPoint();
+
+ // Execute
+ CefBrowserViewCppToC::Get(reinterpret_cast<cef_browser_view_t*>(self))
+ ->SetPosition(positionVal);
+}
+
+cef_point_t CEF_CALLBACK browser_view_get_position(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefPoint();
+ }
+
+ // Execute
+ cef_point_t _retval =
+ CefBrowserViewCppToC::Get(reinterpret_cast<cef_browser_view_t*>(self))
+ ->GetPosition();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK browser_view_set_insets(struct _cef_view_t* self,
+ const cef_insets_t* insets) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: insets; type: simple_byref_const
+ DCHECK(insets);
+ if (!insets) {
+ return;
+ }
+
+ // Translate param: insets; type: simple_byref_const
+ CefInsets insetsVal = insets ? *insets : CefInsets();
+
+ // Execute
+ CefBrowserViewCppToC::Get(reinterpret_cast<cef_browser_view_t*>(self))
+ ->SetInsets(insetsVal);
+}
+
+cef_insets_t CEF_CALLBACK browser_view_get_insets(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefInsets();
+ }
+
+ // Execute
+ cef_insets_t _retval =
+ CefBrowserViewCppToC::Get(reinterpret_cast<cef_browser_view_t*>(self))
+ ->GetInsets();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_size_t CEF_CALLBACK
+browser_view_get_preferred_size(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval =
+ CefBrowserViewCppToC::Get(reinterpret_cast<cef_browser_view_t*>(self))
+ ->GetPreferredSize();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK
+browser_view_size_to_preferred_size(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefBrowserViewCppToC::Get(reinterpret_cast<cef_browser_view_t*>(self))
+ ->SizeToPreferredSize();
+}
+
+cef_size_t CEF_CALLBACK
+browser_view_get_minimum_size(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval =
+ CefBrowserViewCppToC::Get(reinterpret_cast<cef_browser_view_t*>(self))
+ ->GetMinimumSize();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_size_t CEF_CALLBACK
+browser_view_get_maximum_size(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval =
+ CefBrowserViewCppToC::Get(reinterpret_cast<cef_browser_view_t*>(self))
+ ->GetMaximumSize();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK browser_view_get_height_for_width(struct _cef_view_t* self,
+ int width) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval =
+ CefBrowserViewCppToC::Get(reinterpret_cast<cef_browser_view_t*>(self))
+ ->GetHeightForWidth(width);
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK browser_view_invalidate_layout(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefBrowserViewCppToC::Get(reinterpret_cast<cef_browser_view_t*>(self))
+ ->InvalidateLayout();
+}
+
+void CEF_CALLBACK browser_view_set_visible(struct _cef_view_t* self,
+ int visible) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefBrowserViewCppToC::Get(reinterpret_cast<cef_browser_view_t*>(self))
+ ->SetVisible(visible ? true : false);
+}
+
+int CEF_CALLBACK browser_view_is_visible(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefBrowserViewCppToC::Get(reinterpret_cast<cef_browser_view_t*>(self))
+ ->IsVisible();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK browser_view_is_drawn(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefBrowserViewCppToC::Get(reinterpret_cast<cef_browser_view_t*>(self))
+ ->IsDrawn();
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK browser_view_set_enabled(struct _cef_view_t* self,
+ int enabled) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefBrowserViewCppToC::Get(reinterpret_cast<cef_browser_view_t*>(self))
+ ->SetEnabled(enabled ? true : false);
+}
+
+int CEF_CALLBACK browser_view_is_enabled(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefBrowserViewCppToC::Get(reinterpret_cast<cef_browser_view_t*>(self))
+ ->IsEnabled();
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK browser_view_set_focusable(struct _cef_view_t* self,
+ int focusable) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefBrowserViewCppToC::Get(reinterpret_cast<cef_browser_view_t*>(self))
+ ->SetFocusable(focusable ? true : false);
+}
+
+int CEF_CALLBACK browser_view_is_focusable(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefBrowserViewCppToC::Get(reinterpret_cast<cef_browser_view_t*>(self))
+ ->IsFocusable();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+browser_view_is_accessibility_focusable(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefBrowserViewCppToC::Get(reinterpret_cast<cef_browser_view_t*>(self))
+ ->IsAccessibilityFocusable();
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK browser_view_request_focus(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefBrowserViewCppToC::Get(reinterpret_cast<cef_browser_view_t*>(self))
+ ->RequestFocus();
+}
+
+void CEF_CALLBACK browser_view_set_background_color(struct _cef_view_t* self,
+ cef_color_t color) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefBrowserViewCppToC::Get(reinterpret_cast<cef_browser_view_t*>(self))
+ ->SetBackgroundColor(color);
+}
+
+cef_color_t CEF_CALLBACK
+browser_view_get_background_color(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ cef_color_t _retval =
+ CefBrowserViewCppToC::Get(reinterpret_cast<cef_browser_view_t*>(self))
+ ->GetBackgroundColor();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK browser_view_convert_point_to_screen(struct _cef_view_t* self,
+ cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: point; type: simple_byref
+ DCHECK(point);
+ if (!point) {
+ return 0;
+ }
+
+ // Translate param: point; type: simple_byref
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ bool _retval =
+ CefBrowserViewCppToC::Get(reinterpret_cast<cef_browser_view_t*>(self))
+ ->ConvertPointToScreen(pointVal);
+
+ // Restore param: point; type: simple_byref
+ if (point) {
+ *point = pointVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+browser_view_convert_point_from_screen(struct _cef_view_t* self,
+ cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: point; type: simple_byref
+ DCHECK(point);
+ if (!point) {
+ return 0;
+ }
+
+ // Translate param: point; type: simple_byref
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ bool _retval =
+ CefBrowserViewCppToC::Get(reinterpret_cast<cef_browser_view_t*>(self))
+ ->ConvertPointFromScreen(pointVal);
+
+ // Restore param: point; type: simple_byref
+ if (point) {
+ *point = pointVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK browser_view_convert_point_to_window(struct _cef_view_t* self,
+ cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: point; type: simple_byref
+ DCHECK(point);
+ if (!point) {
+ return 0;
+ }
+
+ // Translate param: point; type: simple_byref
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ bool _retval =
+ CefBrowserViewCppToC::Get(reinterpret_cast<cef_browser_view_t*>(self))
+ ->ConvertPointToWindow(pointVal);
+
+ // Restore param: point; type: simple_byref
+ if (point) {
+ *point = pointVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+browser_view_convert_point_from_window(struct _cef_view_t* self,
+ cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: point; type: simple_byref
+ DCHECK(point);
+ if (!point) {
+ return 0;
+ }
+
+ // Translate param: point; type: simple_byref
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ bool _retval =
+ CefBrowserViewCppToC::Get(reinterpret_cast<cef_browser_view_t*>(self))
+ ->ConvertPointFromWindow(pointVal);
+
+ // Restore param: point; type: simple_byref
+ if (point) {
+ *point = pointVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK browser_view_convert_point_to_view(struct _cef_view_t* self,
+ struct _cef_view_t* view,
+ cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: view; type: refptr_same
+ DCHECK(view);
+ if (!view) {
+ return 0;
+ }
+ // Verify param: point; type: simple_byref
+ DCHECK(point);
+ if (!point) {
+ return 0;
+ }
+
+ // Translate param: point; type: simple_byref
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ bool _retval =
+ CefBrowserViewCppToC::Get(reinterpret_cast<cef_browser_view_t*>(self))
+ ->ConvertPointToView(CefViewCppToC::Unwrap(view), pointVal);
+
+ // Restore param: point; type: simple_byref
+ if (point) {
+ *point = pointVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK browser_view_convert_point_from_view(struct _cef_view_t* self,
+ struct _cef_view_t* view,
+ cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: view; type: refptr_same
+ DCHECK(view);
+ if (!view) {
+ return 0;
+ }
+ // Verify param: point; type: simple_byref
+ DCHECK(point);
+ if (!point) {
+ return 0;
+ }
+
+ // Translate param: point; type: simple_byref
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ bool _retval =
+ CefBrowserViewCppToC::Get(reinterpret_cast<cef_browser_view_t*>(self))
+ ->ConvertPointFromView(CefViewCppToC::Unwrap(view), pointVal);
+
+ // Restore param: point; type: simple_byref
+ if (point) {
+ *point = pointVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefBrowserViewCppToC::CefBrowserViewCppToC() {
+ GetStruct()->get_browser = browser_view_get_browser;
+ GetStruct()->get_chrome_toolbar = browser_view_get_chrome_toolbar;
+ GetStruct()->set_prefer_accelerators = browser_view_set_prefer_accelerators;
+ GetStruct()->base.as_browser_view = browser_view_as_browser_view;
+ GetStruct()->base.as_button = browser_view_as_button;
+ GetStruct()->base.as_panel = browser_view_as_panel;
+ GetStruct()->base.as_scroll_view = browser_view_as_scroll_view;
+ GetStruct()->base.as_textfield = browser_view_as_textfield;
+ GetStruct()->base.get_type_string = browser_view_get_type_string;
+ GetStruct()->base.to_string = browser_view_to_string;
+ GetStruct()->base.is_valid = browser_view_is_valid;
+ GetStruct()->base.is_attached = browser_view_is_attached;
+ GetStruct()->base.is_same = browser_view_is_same;
+ GetStruct()->base.get_delegate = browser_view_get_delegate;
+ GetStruct()->base.get_window = browser_view_get_window;
+ GetStruct()->base.get_id = browser_view_get_id;
+ GetStruct()->base.set_id = browser_view_set_id;
+ GetStruct()->base.get_group_id = browser_view_get_group_id;
+ GetStruct()->base.set_group_id = browser_view_set_group_id;
+ GetStruct()->base.get_parent_view = browser_view_get_parent_view;
+ GetStruct()->base.get_view_for_id = browser_view_get_view_for_id;
+ GetStruct()->base.set_bounds = browser_view_set_bounds;
+ GetStruct()->base.get_bounds = browser_view_get_bounds;
+ GetStruct()->base.get_bounds_in_screen = browser_view_get_bounds_in_screen;
+ GetStruct()->base.set_size = browser_view_set_size;
+ GetStruct()->base.get_size = browser_view_get_size;
+ GetStruct()->base.set_position = browser_view_set_position;
+ GetStruct()->base.get_position = browser_view_get_position;
+ GetStruct()->base.set_insets = browser_view_set_insets;
+ GetStruct()->base.get_insets = browser_view_get_insets;
+ GetStruct()->base.get_preferred_size = browser_view_get_preferred_size;
+ GetStruct()->base.size_to_preferred_size =
+ browser_view_size_to_preferred_size;
+ GetStruct()->base.get_minimum_size = browser_view_get_minimum_size;
+ GetStruct()->base.get_maximum_size = browser_view_get_maximum_size;
+ GetStruct()->base.get_height_for_width = browser_view_get_height_for_width;
+ GetStruct()->base.invalidate_layout = browser_view_invalidate_layout;
+ GetStruct()->base.set_visible = browser_view_set_visible;
+ GetStruct()->base.is_visible = browser_view_is_visible;
+ GetStruct()->base.is_drawn = browser_view_is_drawn;
+ GetStruct()->base.set_enabled = browser_view_set_enabled;
+ GetStruct()->base.is_enabled = browser_view_is_enabled;
+ GetStruct()->base.set_focusable = browser_view_set_focusable;
+ GetStruct()->base.is_focusable = browser_view_is_focusable;
+ GetStruct()->base.is_accessibility_focusable =
+ browser_view_is_accessibility_focusable;
+ GetStruct()->base.request_focus = browser_view_request_focus;
+ GetStruct()->base.set_background_color = browser_view_set_background_color;
+ GetStruct()->base.get_background_color = browser_view_get_background_color;
+ GetStruct()->base.convert_point_to_screen =
+ browser_view_convert_point_to_screen;
+ GetStruct()->base.convert_point_from_screen =
+ browser_view_convert_point_from_screen;
+ GetStruct()->base.convert_point_to_window =
+ browser_view_convert_point_to_window;
+ GetStruct()->base.convert_point_from_window =
+ browser_view_convert_point_from_window;
+ GetStruct()->base.convert_point_to_view = browser_view_convert_point_to_view;
+ GetStruct()->base.convert_point_from_view =
+ browser_view_convert_point_from_view;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefBrowserViewCppToC::~CefBrowserViewCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefBrowserView>
+CefCppToCRefCounted<CefBrowserViewCppToC, CefBrowserView, cef_browser_view_t>::
+ UnwrapDerived(CefWrapperType type, cef_browser_view_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefBrowserViewCppToC,
+ CefBrowserView,
+ cef_browser_view_t>::kWrapperType =
+ WT_BROWSER_VIEW;
diff --git a/libcef_dll/cpptoc/views/browser_view_cpptoc.h b/libcef_dll/cpptoc/views/browser_view_cpptoc.h
new file mode 100644
index 00000000..2f9fd838
--- /dev/null
+++ b/libcef_dll/cpptoc/views/browser_view_cpptoc.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=f981c5f7247ec57926549c145c47a7cdcbdd80a0$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_VIEWS_BROWSER_VIEW_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_VIEWS_BROWSER_VIEW_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/views/cef_browser_view_capi.h"
+#include "include/views/cef_browser_view.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefBrowserViewCppToC : public CefCppToCRefCounted<CefBrowserViewCppToC,
+ CefBrowserView,
+ cef_browser_view_t> {
+ public:
+ CefBrowserViewCppToC();
+ virtual ~CefBrowserViewCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_VIEWS_BROWSER_VIEW_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/views/browser_view_delegate_cpptoc.cc b/libcef_dll/cpptoc/views/browser_view_delegate_cpptoc.cc
new file mode 100644
index 00000000..8e7d9cb1
--- /dev/null
+++ b/libcef_dll/cpptoc/views/browser_view_delegate_cpptoc.cc
@@ -0,0 +1,507 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=8b92c198857b0ca5c3ddc9b2c8a82febe7ed8cde$
+//
+
+#include "libcef_dll/cpptoc/views/browser_view_delegate_cpptoc.h"
+#include "libcef_dll/cpptoc/client_cpptoc.h"
+#include "libcef_dll/ctocpp/browser_ctocpp.h"
+#include "libcef_dll/ctocpp/views/browser_view_ctocpp.h"
+#include "libcef_dll/ctocpp/views/view_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+#include "libcef_dll/template_util.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK browser_view_delegate_on_browser_created(
+ struct _cef_browser_view_delegate_t* self,
+ cef_browser_view_t* browser_view,
+ cef_browser_t* browser) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser_view; type: refptr_diff
+ DCHECK(browser_view);
+ if (!browser_view) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+
+ // Execute
+ CefBrowserViewDelegateCppToC::Get(self)->OnBrowserCreated(
+ CefBrowserViewCToCpp::Wrap(browser_view),
+ CefBrowserCToCpp::Wrap(browser));
+}
+
+void CEF_CALLBACK browser_view_delegate_on_browser_destroyed(
+ struct _cef_browser_view_delegate_t* self,
+ cef_browser_view_t* browser_view,
+ cef_browser_t* browser) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: browser_view; type: refptr_diff
+ DCHECK(browser_view);
+ if (!browser_view) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser);
+ if (!browser) {
+ return;
+ }
+
+ // Execute
+ CefBrowserViewDelegateCppToC::Get(self)->OnBrowserDestroyed(
+ CefBrowserViewCToCpp::Wrap(browser_view),
+ CefBrowserCToCpp::Wrap(browser));
+}
+
+cef_browser_view_delegate_t* CEF_CALLBACK
+browser_view_delegate_get_delegate_for_popup_browser_view(
+ struct _cef_browser_view_delegate_t* self,
+ cef_browser_view_t* browser_view,
+ const struct _cef_browser_settings_t* settings,
+ cef_client_t* client,
+ int is_devtools) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+ // Verify param: browser_view; type: refptr_diff
+ DCHECK(browser_view);
+ if (!browser_view) {
+ return NULL;
+ }
+ // Verify param: settings; type: struct_byref_const
+ DCHECK(settings);
+ if (!settings) {
+ return NULL;
+ }
+ if (!template_util::has_valid_size(settings)) {
+ NOTREACHED() << "invalid settings->[base.]size";
+ return NULL;
+ }
+ // Unverified params: client
+
+ // Translate param: settings; type: struct_byref_const
+ CefBrowserSettings settingsObj;
+ if (settings) {
+ settingsObj.Set(*settings, false);
+ }
+
+ // Execute
+ CefRefPtr<CefBrowserViewDelegate> _retval =
+ CefBrowserViewDelegateCppToC::Get(self)->GetDelegateForPopupBrowserView(
+ CefBrowserViewCToCpp::Wrap(browser_view), settingsObj,
+ CefClientCppToC::Unwrap(client), is_devtools ? true : false);
+
+ // Return type: refptr_same
+ return CefBrowserViewDelegateCppToC::Wrap(_retval);
+}
+
+int CEF_CALLBACK browser_view_delegate_on_popup_browser_view_created(
+ struct _cef_browser_view_delegate_t* self,
+ cef_browser_view_t* browser_view,
+ cef_browser_view_t* popup_browser_view,
+ int is_devtools) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: browser_view; type: refptr_diff
+ DCHECK(browser_view);
+ if (!browser_view) {
+ return 0;
+ }
+ // Verify param: popup_browser_view; type: refptr_diff
+ DCHECK(popup_browser_view);
+ if (!popup_browser_view) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefBrowserViewDelegateCppToC::Get(self)->OnPopupBrowserViewCreated(
+ CefBrowserViewCToCpp::Wrap(browser_view),
+ CefBrowserViewCToCpp::Wrap(popup_browser_view),
+ is_devtools ? true : false);
+
+ // Return type: bool
+ return _retval;
+}
+
+cef_chrome_toolbar_type_t CEF_CALLBACK
+browser_view_delegate_get_chrome_toolbar_type(
+ struct _cef_browser_view_delegate_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CEF_CTT_NONE;
+ }
+
+ // Execute
+ cef_chrome_toolbar_type_t _retval =
+ CefBrowserViewDelegateCppToC::Get(self)->GetChromeToolbarType();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_size_t CEF_CALLBACK
+browser_view_delegate_get_preferred_size(struct _cef_view_delegate_t* self,
+ cef_view_t* view) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval = CefBrowserViewDelegateCppToC::Get(
+ reinterpret_cast<cef_browser_view_delegate_t*>(self))
+ ->GetPreferredSize(CefViewCToCpp::Wrap(view));
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_size_t CEF_CALLBACK
+browser_view_delegate_get_minimum_size(struct _cef_view_delegate_t* self,
+ cef_view_t* view) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval = CefBrowserViewDelegateCppToC::Get(
+ reinterpret_cast<cef_browser_view_delegate_t*>(self))
+ ->GetMinimumSize(CefViewCToCpp::Wrap(view));
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_size_t CEF_CALLBACK
+browser_view_delegate_get_maximum_size(struct _cef_view_delegate_t* self,
+ cef_view_t* view) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval = CefBrowserViewDelegateCppToC::Get(
+ reinterpret_cast<cef_browser_view_delegate_t*>(self))
+ ->GetMaximumSize(CefViewCToCpp::Wrap(view));
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK
+browser_view_delegate_get_height_for_width(struct _cef_view_delegate_t* self,
+ cef_view_t* view,
+ int width) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefBrowserViewDelegateCppToC::Get(
+ reinterpret_cast<cef_browser_view_delegate_t*>(self))
+ ->GetHeightForWidth(CefViewCToCpp::Wrap(view), width);
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK
+browser_view_delegate_on_parent_view_changed(struct _cef_view_delegate_t* self,
+ cef_view_t* view,
+ int added,
+ cef_view_t* parent) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return;
+ }
+ // Verify param: parent; type: refptr_diff
+ DCHECK(parent);
+ if (!parent) {
+ return;
+ }
+
+ // Execute
+ CefBrowserViewDelegateCppToC::Get(
+ reinterpret_cast<cef_browser_view_delegate_t*>(self))
+ ->OnParentViewChanged(CefViewCToCpp::Wrap(view), added ? true : false,
+ CefViewCToCpp::Wrap(parent));
+}
+
+void CEF_CALLBACK
+browser_view_delegate_on_child_view_changed(struct _cef_view_delegate_t* self,
+ cef_view_t* view,
+ int added,
+ cef_view_t* child) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return;
+ }
+ // Verify param: child; type: refptr_diff
+ DCHECK(child);
+ if (!child) {
+ return;
+ }
+
+ // Execute
+ CefBrowserViewDelegateCppToC::Get(
+ reinterpret_cast<cef_browser_view_delegate_t*>(self))
+ ->OnChildViewChanged(CefViewCToCpp::Wrap(view), added ? true : false,
+ CefViewCToCpp::Wrap(child));
+}
+
+void CEF_CALLBACK
+browser_view_delegate_on_window_changed(struct _cef_view_delegate_t* self,
+ cef_view_t* view,
+ int added) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return;
+ }
+
+ // Execute
+ CefBrowserViewDelegateCppToC::Get(
+ reinterpret_cast<cef_browser_view_delegate_t*>(self))
+ ->OnWindowChanged(CefViewCToCpp::Wrap(view), added ? true : false);
+}
+
+void CEF_CALLBACK
+browser_view_delegate_on_layout_changed(struct _cef_view_delegate_t* self,
+ cef_view_t* view,
+ const cef_rect_t* new_bounds) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return;
+ }
+ // Verify param: new_bounds; type: simple_byref_const
+ DCHECK(new_bounds);
+ if (!new_bounds) {
+ return;
+ }
+
+ // Translate param: new_bounds; type: simple_byref_const
+ CefRect new_boundsVal = new_bounds ? *new_bounds : CefRect();
+
+ // Execute
+ CefBrowserViewDelegateCppToC::Get(
+ reinterpret_cast<cef_browser_view_delegate_t*>(self))
+ ->OnLayoutChanged(CefViewCToCpp::Wrap(view), new_boundsVal);
+}
+
+void CEF_CALLBACK
+browser_view_delegate_on_focus(struct _cef_view_delegate_t* self,
+ cef_view_t* view) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return;
+ }
+
+ // Execute
+ CefBrowserViewDelegateCppToC::Get(
+ reinterpret_cast<cef_browser_view_delegate_t*>(self))
+ ->OnFocus(CefViewCToCpp::Wrap(view));
+}
+
+void CEF_CALLBACK
+browser_view_delegate_on_blur(struct _cef_view_delegate_t* self,
+ cef_view_t* view) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return;
+ }
+
+ // Execute
+ CefBrowserViewDelegateCppToC::Get(
+ reinterpret_cast<cef_browser_view_delegate_t*>(self))
+ ->OnBlur(CefViewCToCpp::Wrap(view));
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefBrowserViewDelegateCppToC::CefBrowserViewDelegateCppToC() {
+ GetStruct()->on_browser_created = browser_view_delegate_on_browser_created;
+ GetStruct()->on_browser_destroyed =
+ browser_view_delegate_on_browser_destroyed;
+ GetStruct()->get_delegate_for_popup_browser_view =
+ browser_view_delegate_get_delegate_for_popup_browser_view;
+ GetStruct()->on_popup_browser_view_created =
+ browser_view_delegate_on_popup_browser_view_created;
+ GetStruct()->get_chrome_toolbar_type =
+ browser_view_delegate_get_chrome_toolbar_type;
+ GetStruct()->base.get_preferred_size =
+ browser_view_delegate_get_preferred_size;
+ GetStruct()->base.get_minimum_size = browser_view_delegate_get_minimum_size;
+ GetStruct()->base.get_maximum_size = browser_view_delegate_get_maximum_size;
+ GetStruct()->base.get_height_for_width =
+ browser_view_delegate_get_height_for_width;
+ GetStruct()->base.on_parent_view_changed =
+ browser_view_delegate_on_parent_view_changed;
+ GetStruct()->base.on_child_view_changed =
+ browser_view_delegate_on_child_view_changed;
+ GetStruct()->base.on_window_changed = browser_view_delegate_on_window_changed;
+ GetStruct()->base.on_layout_changed = browser_view_delegate_on_layout_changed;
+ GetStruct()->base.on_focus = browser_view_delegate_on_focus;
+ GetStruct()->base.on_blur = browser_view_delegate_on_blur;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefBrowserViewDelegateCppToC::~CefBrowserViewDelegateCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefBrowserViewDelegate> CefCppToCRefCounted<
+ CefBrowserViewDelegateCppToC,
+ CefBrowserViewDelegate,
+ cef_browser_view_delegate_t>::UnwrapDerived(CefWrapperType type,
+ cef_browser_view_delegate_t*
+ s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefBrowserViewDelegateCppToC,
+ CefBrowserViewDelegate,
+ cef_browser_view_delegate_t>::kWrapperType =
+ WT_BROWSER_VIEW_DELEGATE;
diff --git a/libcef_dll/cpptoc/views/browser_view_delegate_cpptoc.h b/libcef_dll/cpptoc/views/browser_view_delegate_cpptoc.h
new file mode 100644
index 00000000..f0761f3b
--- /dev/null
+++ b/libcef_dll/cpptoc/views/browser_view_delegate_cpptoc.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=b091e620040d148171ce5c99d5376cb00356eb37$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_VIEWS_BROWSER_VIEW_DELEGATE_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_VIEWS_BROWSER_VIEW_DELEGATE_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_browser_capi.h"
+#include "include/capi/views/cef_browser_view_capi.h"
+#include "include/capi/views/cef_browser_view_delegate_capi.h"
+#include "include/cef_browser.h"
+#include "include/views/cef_browser_view.h"
+#include "include/views/cef_browser_view_delegate.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefBrowserViewDelegateCppToC
+ : public CefCppToCRefCounted<CefBrowserViewDelegateCppToC,
+ CefBrowserViewDelegate,
+ cef_browser_view_delegate_t> {
+ public:
+ CefBrowserViewDelegateCppToC();
+ virtual ~CefBrowserViewDelegateCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_VIEWS_BROWSER_VIEW_DELEGATE_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/views/button_cpptoc.cc b/libcef_dll/cpptoc/views/button_cpptoc.cc
new file mode 100644
index 00000000..aa88780c
--- /dev/null
+++ b/libcef_dll/cpptoc/views/button_cpptoc.cc
@@ -0,0 +1,1249 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=5428bc6354709f7b7083f545fa0ed5c1af82470d$
+//
+
+#include "libcef_dll/cpptoc/views/button_cpptoc.h"
+#include "libcef_dll/cpptoc/views/browser_view_cpptoc.h"
+#include "libcef_dll/cpptoc/views/label_button_cpptoc.h"
+#include "libcef_dll/cpptoc/views/menu_button_cpptoc.h"
+#include "libcef_dll/cpptoc/views/panel_cpptoc.h"
+#include "libcef_dll/cpptoc/views/scroll_view_cpptoc.h"
+#include "libcef_dll/cpptoc/views/textfield_cpptoc.h"
+#include "libcef_dll/cpptoc/views/view_cpptoc.h"
+#include "libcef_dll/cpptoc/views/window_cpptoc.h"
+#include "libcef_dll/ctocpp/views/view_delegate_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+cef_label_button_t* CEF_CALLBACK
+button_as_label_button(struct _cef_button_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefLabelButton> _retval =
+ CefButtonCppToC::Get(self)->AsLabelButton();
+
+ // Return type: refptr_same
+ return CefLabelButtonCppToC::Wrap(_retval);
+}
+
+void CEF_CALLBACK button_set_state(struct _cef_button_t* self,
+ cef_button_state_t state) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefButtonCppToC::Get(self)->SetState(state);
+}
+
+cef_button_state_t CEF_CALLBACK button_get_state(struct _cef_button_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CEF_BUTTON_STATE_NORMAL;
+ }
+
+ // Execute
+ cef_button_state_t _retval = CefButtonCppToC::Get(self)->GetState();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK button_set_ink_drop_enabled(struct _cef_button_t* self,
+ int enabled) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefButtonCppToC::Get(self)->SetInkDropEnabled(enabled ? true : false);
+}
+
+void CEF_CALLBACK button_set_tooltip_text(struct _cef_button_t* self,
+ const cef_string_t* tooltip_text) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: tooltip_text; type: string_byref_const
+ DCHECK(tooltip_text);
+ if (!tooltip_text) {
+ return;
+ }
+
+ // Execute
+ CefButtonCppToC::Get(self)->SetTooltipText(CefString(tooltip_text));
+}
+
+void CEF_CALLBACK button_set_accessible_name(struct _cef_button_t* self,
+ const cef_string_t* name) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: name; type: string_byref_const
+ DCHECK(name);
+ if (!name) {
+ return;
+ }
+
+ // Execute
+ CefButtonCppToC::Get(self)->SetAccessibleName(CefString(name));
+}
+
+cef_browser_view_t* CEF_CALLBACK
+button_as_browser_view(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefBrowserView> _retval =
+ CefButtonCppToC::Get(reinterpret_cast<cef_button_t*>(self))
+ ->AsBrowserView();
+
+ // Return type: refptr_same
+ return CefBrowserViewCppToC::Wrap(_retval);
+}
+
+cef_button_t* CEF_CALLBACK button_as_button(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefButton> _retval =
+ CefButtonCppToC::Get(reinterpret_cast<cef_button_t*>(self))->AsButton();
+
+ // Return type: refptr_same
+ return CefButtonCppToC::Wrap(_retval);
+}
+
+cef_panel_t* CEF_CALLBACK button_as_panel(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefPanel> _retval =
+ CefButtonCppToC::Get(reinterpret_cast<cef_button_t*>(self))->AsPanel();
+
+ // Return type: refptr_same
+ return CefPanelCppToC::Wrap(_retval);
+}
+
+cef_scroll_view_t* CEF_CALLBACK
+button_as_scroll_view(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefScrollView> _retval =
+ CefButtonCppToC::Get(reinterpret_cast<cef_button_t*>(self))
+ ->AsScrollView();
+
+ // Return type: refptr_same
+ return CefScrollViewCppToC::Wrap(_retval);
+}
+
+cef_textfield_t* CEF_CALLBACK button_as_textfield(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefTextfield> _retval =
+ CefButtonCppToC::Get(reinterpret_cast<cef_button_t*>(self))
+ ->AsTextfield();
+
+ // Return type: refptr_same
+ return CefTextfieldCppToC::Wrap(_retval);
+}
+
+cef_string_userfree_t CEF_CALLBACK
+button_get_type_string(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval =
+ CefButtonCppToC::Get(reinterpret_cast<cef_button_t*>(self))
+ ->GetTypeString();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_string_userfree_t CEF_CALLBACK button_to_string(struct _cef_view_t* self,
+ int include_children) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval =
+ CefButtonCppToC::Get(reinterpret_cast<cef_button_t*>(self))
+ ->ToString(include_children ? true : false);
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+int CEF_CALLBACK button_is_valid(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefButtonCppToC::Get(reinterpret_cast<cef_button_t*>(self))->IsValid();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK button_is_attached(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefButtonCppToC::Get(reinterpret_cast<cef_button_t*>(self))->IsAttached();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK button_is_same(struct _cef_view_t* self,
+ struct _cef_view_t* that) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: that; type: refptr_same
+ DCHECK(that);
+ if (!that) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefButtonCppToC::Get(reinterpret_cast<cef_button_t*>(self))
+ ->IsSame(CefViewCppToC::Unwrap(that));
+
+ // Return type: bool
+ return _retval;
+}
+
+struct _cef_view_delegate_t* CEF_CALLBACK
+button_get_delegate(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefViewDelegate> _retval =
+ CefButtonCppToC::Get(reinterpret_cast<cef_button_t*>(self))
+ ->GetDelegate();
+
+ // Return type: refptr_diff
+ return CefViewDelegateCToCpp::Unwrap(_retval);
+}
+
+struct _cef_window_t* CEF_CALLBACK button_get_window(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefWindow> _retval =
+ CefButtonCppToC::Get(reinterpret_cast<cef_button_t*>(self))->GetWindow();
+
+ // Return type: refptr_same
+ return CefWindowCppToC::Wrap(_retval);
+}
+
+int CEF_CALLBACK button_get_id(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval =
+ CefButtonCppToC::Get(reinterpret_cast<cef_button_t*>(self))->GetID();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK button_set_id(struct _cef_view_t* self, int id) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefButtonCppToC::Get(reinterpret_cast<cef_button_t*>(self))->SetID(id);
+}
+
+int CEF_CALLBACK button_get_group_id(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval =
+ CefButtonCppToC::Get(reinterpret_cast<cef_button_t*>(self))->GetGroupID();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK button_set_group_id(struct _cef_view_t* self, int group_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefButtonCppToC::Get(reinterpret_cast<cef_button_t*>(self))
+ ->SetGroupID(group_id);
+}
+
+struct _cef_view_t* CEF_CALLBACK
+button_get_parent_view(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefView> _retval =
+ CefButtonCppToC::Get(reinterpret_cast<cef_button_t*>(self))
+ ->GetParentView();
+
+ // Return type: refptr_same
+ return CefViewCppToC::Wrap(_retval);
+}
+
+struct _cef_view_t* CEF_CALLBACK
+button_get_view_for_id(struct _cef_view_t* self, int id) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefView> _retval =
+ CefButtonCppToC::Get(reinterpret_cast<cef_button_t*>(self))
+ ->GetViewForID(id);
+
+ // Return type: refptr_same
+ return CefViewCppToC::Wrap(_retval);
+}
+
+void CEF_CALLBACK button_set_bounds(struct _cef_view_t* self,
+ const cef_rect_t* bounds) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: bounds; type: simple_byref_const
+ DCHECK(bounds);
+ if (!bounds) {
+ return;
+ }
+
+ // Translate param: bounds; type: simple_byref_const
+ CefRect boundsVal = bounds ? *bounds : CefRect();
+
+ // Execute
+ CefButtonCppToC::Get(reinterpret_cast<cef_button_t*>(self))
+ ->SetBounds(boundsVal);
+}
+
+cef_rect_t CEF_CALLBACK button_get_bounds(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefRect();
+ }
+
+ // Execute
+ cef_rect_t _retval =
+ CefButtonCppToC::Get(reinterpret_cast<cef_button_t*>(self))->GetBounds();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_rect_t CEF_CALLBACK button_get_bounds_in_screen(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefRect();
+ }
+
+ // Execute
+ cef_rect_t _retval =
+ CefButtonCppToC::Get(reinterpret_cast<cef_button_t*>(self))
+ ->GetBoundsInScreen();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK button_set_size(struct _cef_view_t* self,
+ const cef_size_t* size) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: size; type: simple_byref_const
+ DCHECK(size);
+ if (!size) {
+ return;
+ }
+
+ // Translate param: size; type: simple_byref_const
+ CefSize sizeVal = size ? *size : CefSize();
+
+ // Execute
+ CefButtonCppToC::Get(reinterpret_cast<cef_button_t*>(self))->SetSize(sizeVal);
+}
+
+cef_size_t CEF_CALLBACK button_get_size(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval =
+ CefButtonCppToC::Get(reinterpret_cast<cef_button_t*>(self))->GetSize();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK button_set_position(struct _cef_view_t* self,
+ const cef_point_t* position) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: position; type: simple_byref_const
+ DCHECK(position);
+ if (!position) {
+ return;
+ }
+
+ // Translate param: position; type: simple_byref_const
+ CefPoint positionVal = position ? *position : CefPoint();
+
+ // Execute
+ CefButtonCppToC::Get(reinterpret_cast<cef_button_t*>(self))
+ ->SetPosition(positionVal);
+}
+
+cef_point_t CEF_CALLBACK button_get_position(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefPoint();
+ }
+
+ // Execute
+ cef_point_t _retval =
+ CefButtonCppToC::Get(reinterpret_cast<cef_button_t*>(self))
+ ->GetPosition();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK button_set_insets(struct _cef_view_t* self,
+ const cef_insets_t* insets) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: insets; type: simple_byref_const
+ DCHECK(insets);
+ if (!insets) {
+ return;
+ }
+
+ // Translate param: insets; type: simple_byref_const
+ CefInsets insetsVal = insets ? *insets : CefInsets();
+
+ // Execute
+ CefButtonCppToC::Get(reinterpret_cast<cef_button_t*>(self))
+ ->SetInsets(insetsVal);
+}
+
+cef_insets_t CEF_CALLBACK button_get_insets(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefInsets();
+ }
+
+ // Execute
+ cef_insets_t _retval =
+ CefButtonCppToC::Get(reinterpret_cast<cef_button_t*>(self))->GetInsets();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_size_t CEF_CALLBACK button_get_preferred_size(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval =
+ CefButtonCppToC::Get(reinterpret_cast<cef_button_t*>(self))
+ ->GetPreferredSize();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK button_size_to_preferred_size(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefButtonCppToC::Get(reinterpret_cast<cef_button_t*>(self))
+ ->SizeToPreferredSize();
+}
+
+cef_size_t CEF_CALLBACK button_get_minimum_size(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval =
+ CefButtonCppToC::Get(reinterpret_cast<cef_button_t*>(self))
+ ->GetMinimumSize();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_size_t CEF_CALLBACK button_get_maximum_size(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval =
+ CefButtonCppToC::Get(reinterpret_cast<cef_button_t*>(self))
+ ->GetMaximumSize();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK button_get_height_for_width(struct _cef_view_t* self,
+ int width) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefButtonCppToC::Get(reinterpret_cast<cef_button_t*>(self))
+ ->GetHeightForWidth(width);
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK button_invalidate_layout(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefButtonCppToC::Get(reinterpret_cast<cef_button_t*>(self))
+ ->InvalidateLayout();
+}
+
+void CEF_CALLBACK button_set_visible(struct _cef_view_t* self, int visible) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefButtonCppToC::Get(reinterpret_cast<cef_button_t*>(self))
+ ->SetVisible(visible ? true : false);
+}
+
+int CEF_CALLBACK button_is_visible(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefButtonCppToC::Get(reinterpret_cast<cef_button_t*>(self))->IsVisible();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK button_is_drawn(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefButtonCppToC::Get(reinterpret_cast<cef_button_t*>(self))->IsDrawn();
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK button_set_enabled(struct _cef_view_t* self, int enabled) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefButtonCppToC::Get(reinterpret_cast<cef_button_t*>(self))
+ ->SetEnabled(enabled ? true : false);
+}
+
+int CEF_CALLBACK button_is_enabled(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefButtonCppToC::Get(reinterpret_cast<cef_button_t*>(self))->IsEnabled();
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK button_set_focusable(struct _cef_view_t* self,
+ int focusable) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefButtonCppToC::Get(reinterpret_cast<cef_button_t*>(self))
+ ->SetFocusable(focusable ? true : false);
+}
+
+int CEF_CALLBACK button_is_focusable(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefButtonCppToC::Get(reinterpret_cast<cef_button_t*>(self))
+ ->IsFocusable();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK button_is_accessibility_focusable(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefButtonCppToC::Get(reinterpret_cast<cef_button_t*>(self))
+ ->IsAccessibilityFocusable();
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK button_request_focus(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefButtonCppToC::Get(reinterpret_cast<cef_button_t*>(self))->RequestFocus();
+}
+
+void CEF_CALLBACK button_set_background_color(struct _cef_view_t* self,
+ cef_color_t color) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefButtonCppToC::Get(reinterpret_cast<cef_button_t*>(self))
+ ->SetBackgroundColor(color);
+}
+
+cef_color_t CEF_CALLBACK button_get_background_color(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ cef_color_t _retval =
+ CefButtonCppToC::Get(reinterpret_cast<cef_button_t*>(self))
+ ->GetBackgroundColor();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK button_convert_point_to_screen(struct _cef_view_t* self,
+ cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: point; type: simple_byref
+ DCHECK(point);
+ if (!point) {
+ return 0;
+ }
+
+ // Translate param: point; type: simple_byref
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ bool _retval = CefButtonCppToC::Get(reinterpret_cast<cef_button_t*>(self))
+ ->ConvertPointToScreen(pointVal);
+
+ // Restore param: point; type: simple_byref
+ if (point) {
+ *point = pointVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK button_convert_point_from_screen(struct _cef_view_t* self,
+ cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: point; type: simple_byref
+ DCHECK(point);
+ if (!point) {
+ return 0;
+ }
+
+ // Translate param: point; type: simple_byref
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ bool _retval = CefButtonCppToC::Get(reinterpret_cast<cef_button_t*>(self))
+ ->ConvertPointFromScreen(pointVal);
+
+ // Restore param: point; type: simple_byref
+ if (point) {
+ *point = pointVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK button_convert_point_to_window(struct _cef_view_t* self,
+ cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: point; type: simple_byref
+ DCHECK(point);
+ if (!point) {
+ return 0;
+ }
+
+ // Translate param: point; type: simple_byref
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ bool _retval = CefButtonCppToC::Get(reinterpret_cast<cef_button_t*>(self))
+ ->ConvertPointToWindow(pointVal);
+
+ // Restore param: point; type: simple_byref
+ if (point) {
+ *point = pointVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK button_convert_point_from_window(struct _cef_view_t* self,
+ cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: point; type: simple_byref
+ DCHECK(point);
+ if (!point) {
+ return 0;
+ }
+
+ // Translate param: point; type: simple_byref
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ bool _retval = CefButtonCppToC::Get(reinterpret_cast<cef_button_t*>(self))
+ ->ConvertPointFromWindow(pointVal);
+
+ // Restore param: point; type: simple_byref
+ if (point) {
+ *point = pointVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK button_convert_point_to_view(struct _cef_view_t* self,
+ struct _cef_view_t* view,
+ cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: view; type: refptr_same
+ DCHECK(view);
+ if (!view) {
+ return 0;
+ }
+ // Verify param: point; type: simple_byref
+ DCHECK(point);
+ if (!point) {
+ return 0;
+ }
+
+ // Translate param: point; type: simple_byref
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ bool _retval =
+ CefButtonCppToC::Get(reinterpret_cast<cef_button_t*>(self))
+ ->ConvertPointToView(CefViewCppToC::Unwrap(view), pointVal);
+
+ // Restore param: point; type: simple_byref
+ if (point) {
+ *point = pointVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK button_convert_point_from_view(struct _cef_view_t* self,
+ struct _cef_view_t* view,
+ cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: view; type: refptr_same
+ DCHECK(view);
+ if (!view) {
+ return 0;
+ }
+ // Verify param: point; type: simple_byref
+ DCHECK(point);
+ if (!point) {
+ return 0;
+ }
+
+ // Translate param: point; type: simple_byref
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ bool _retval =
+ CefButtonCppToC::Get(reinterpret_cast<cef_button_t*>(self))
+ ->ConvertPointFromView(CefViewCppToC::Unwrap(view), pointVal);
+
+ // Restore param: point; type: simple_byref
+ if (point) {
+ *point = pointVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefButtonCppToC::CefButtonCppToC() {
+ GetStruct()->as_label_button = button_as_label_button;
+ GetStruct()->set_state = button_set_state;
+ GetStruct()->get_state = button_get_state;
+ GetStruct()->set_ink_drop_enabled = button_set_ink_drop_enabled;
+ GetStruct()->set_tooltip_text = button_set_tooltip_text;
+ GetStruct()->set_accessible_name = button_set_accessible_name;
+ GetStruct()->base.as_browser_view = button_as_browser_view;
+ GetStruct()->base.as_button = button_as_button;
+ GetStruct()->base.as_panel = button_as_panel;
+ GetStruct()->base.as_scroll_view = button_as_scroll_view;
+ GetStruct()->base.as_textfield = button_as_textfield;
+ GetStruct()->base.get_type_string = button_get_type_string;
+ GetStruct()->base.to_string = button_to_string;
+ GetStruct()->base.is_valid = button_is_valid;
+ GetStruct()->base.is_attached = button_is_attached;
+ GetStruct()->base.is_same = button_is_same;
+ GetStruct()->base.get_delegate = button_get_delegate;
+ GetStruct()->base.get_window = button_get_window;
+ GetStruct()->base.get_id = button_get_id;
+ GetStruct()->base.set_id = button_set_id;
+ GetStruct()->base.get_group_id = button_get_group_id;
+ GetStruct()->base.set_group_id = button_set_group_id;
+ GetStruct()->base.get_parent_view = button_get_parent_view;
+ GetStruct()->base.get_view_for_id = button_get_view_for_id;
+ GetStruct()->base.set_bounds = button_set_bounds;
+ GetStruct()->base.get_bounds = button_get_bounds;
+ GetStruct()->base.get_bounds_in_screen = button_get_bounds_in_screen;
+ GetStruct()->base.set_size = button_set_size;
+ GetStruct()->base.get_size = button_get_size;
+ GetStruct()->base.set_position = button_set_position;
+ GetStruct()->base.get_position = button_get_position;
+ GetStruct()->base.set_insets = button_set_insets;
+ GetStruct()->base.get_insets = button_get_insets;
+ GetStruct()->base.get_preferred_size = button_get_preferred_size;
+ GetStruct()->base.size_to_preferred_size = button_size_to_preferred_size;
+ GetStruct()->base.get_minimum_size = button_get_minimum_size;
+ GetStruct()->base.get_maximum_size = button_get_maximum_size;
+ GetStruct()->base.get_height_for_width = button_get_height_for_width;
+ GetStruct()->base.invalidate_layout = button_invalidate_layout;
+ GetStruct()->base.set_visible = button_set_visible;
+ GetStruct()->base.is_visible = button_is_visible;
+ GetStruct()->base.is_drawn = button_is_drawn;
+ GetStruct()->base.set_enabled = button_set_enabled;
+ GetStruct()->base.is_enabled = button_is_enabled;
+ GetStruct()->base.set_focusable = button_set_focusable;
+ GetStruct()->base.is_focusable = button_is_focusable;
+ GetStruct()->base.is_accessibility_focusable =
+ button_is_accessibility_focusable;
+ GetStruct()->base.request_focus = button_request_focus;
+ GetStruct()->base.set_background_color = button_set_background_color;
+ GetStruct()->base.get_background_color = button_get_background_color;
+ GetStruct()->base.convert_point_to_screen = button_convert_point_to_screen;
+ GetStruct()->base.convert_point_from_screen =
+ button_convert_point_from_screen;
+ GetStruct()->base.convert_point_to_window = button_convert_point_to_window;
+ GetStruct()->base.convert_point_from_window =
+ button_convert_point_from_window;
+ GetStruct()->base.convert_point_to_view = button_convert_point_to_view;
+ GetStruct()->base.convert_point_from_view = button_convert_point_from_view;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefButtonCppToC::~CefButtonCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefButton>
+CefCppToCRefCounted<CefButtonCppToC, CefButton, cef_button_t>::UnwrapDerived(
+ CefWrapperType type,
+ cef_button_t* s) {
+ if (type == WT_LABEL_BUTTON) {
+ return CefLabelButtonCppToC::Unwrap(
+ reinterpret_cast<cef_label_button_t*>(s));
+ }
+ if (type == WT_MENU_BUTTON) {
+ return CefMenuButtonCppToC::Unwrap(reinterpret_cast<cef_menu_button_t*>(s));
+ }
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefButtonCppToC, CefButton, cef_button_t>::
+ kWrapperType = WT_BUTTON;
diff --git a/libcef_dll/cpptoc/views/button_cpptoc.h b/libcef_dll/cpptoc/views/button_cpptoc.h
new file mode 100644
index 00000000..ed70f485
--- /dev/null
+++ b/libcef_dll/cpptoc/views/button_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=3fc906cb8937c58418501c33ba81462806b26860$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_VIEWS_BUTTON_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_VIEWS_BUTTON_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/views/cef_button_capi.h"
+#include "include/capi/views/cef_label_button_capi.h"
+#include "include/views/cef_button.h"
+#include "include/views/cef_label_button.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefButtonCppToC
+ : public CefCppToCRefCounted<CefButtonCppToC, CefButton, cef_button_t> {
+ public:
+ CefButtonCppToC();
+ virtual ~CefButtonCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_VIEWS_BUTTON_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/views/button_delegate_cpptoc.cc b/libcef_dll/cpptoc/views/button_delegate_cpptoc.cc
new file mode 100644
index 00000000..a69a206f
--- /dev/null
+++ b/libcef_dll/cpptoc/views/button_delegate_cpptoc.cc
@@ -0,0 +1,376 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=87511af5e1a3eebefe2fa90759274ac14cdbda62$
+//
+
+#include "libcef_dll/cpptoc/views/button_delegate_cpptoc.h"
+#include "libcef_dll/cpptoc/views/menu_button_delegate_cpptoc.h"
+#include "libcef_dll/ctocpp/views/button_ctocpp.h"
+#include "libcef_dll/ctocpp/views/view_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK
+button_delegate_on_button_pressed(struct _cef_button_delegate_t* self,
+ cef_button_t* button) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: button; type: refptr_diff
+ DCHECK(button);
+ if (!button) {
+ return;
+ }
+
+ // Execute
+ CefButtonDelegateCppToC::Get(self)->OnButtonPressed(
+ CefButtonCToCpp::Wrap(button));
+}
+
+void CEF_CALLBACK
+button_delegate_on_button_state_changed(struct _cef_button_delegate_t* self,
+ cef_button_t* button) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: button; type: refptr_diff
+ DCHECK(button);
+ if (!button) {
+ return;
+ }
+
+ // Execute
+ CefButtonDelegateCppToC::Get(self)->OnButtonStateChanged(
+ CefButtonCToCpp::Wrap(button));
+}
+
+cef_size_t CEF_CALLBACK
+button_delegate_get_preferred_size(struct _cef_view_delegate_t* self,
+ cef_view_t* view) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval = CefButtonDelegateCppToC::Get(
+ reinterpret_cast<cef_button_delegate_t*>(self))
+ ->GetPreferredSize(CefViewCToCpp::Wrap(view));
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_size_t CEF_CALLBACK
+button_delegate_get_minimum_size(struct _cef_view_delegate_t* self,
+ cef_view_t* view) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval = CefButtonDelegateCppToC::Get(
+ reinterpret_cast<cef_button_delegate_t*>(self))
+ ->GetMinimumSize(CefViewCToCpp::Wrap(view));
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_size_t CEF_CALLBACK
+button_delegate_get_maximum_size(struct _cef_view_delegate_t* self,
+ cef_view_t* view) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval = CefButtonDelegateCppToC::Get(
+ reinterpret_cast<cef_button_delegate_t*>(self))
+ ->GetMaximumSize(CefViewCToCpp::Wrap(view));
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK
+button_delegate_get_height_for_width(struct _cef_view_delegate_t* self,
+ cef_view_t* view,
+ int width) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefButtonDelegateCppToC::Get(
+ reinterpret_cast<cef_button_delegate_t*>(self))
+ ->GetHeightForWidth(CefViewCToCpp::Wrap(view), width);
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK
+button_delegate_on_parent_view_changed(struct _cef_view_delegate_t* self,
+ cef_view_t* view,
+ int added,
+ cef_view_t* parent) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return;
+ }
+ // Verify param: parent; type: refptr_diff
+ DCHECK(parent);
+ if (!parent) {
+ return;
+ }
+
+ // Execute
+ CefButtonDelegateCppToC::Get(reinterpret_cast<cef_button_delegate_t*>(self))
+ ->OnParentViewChanged(CefViewCToCpp::Wrap(view), added ? true : false,
+ CefViewCToCpp::Wrap(parent));
+}
+
+void CEF_CALLBACK
+button_delegate_on_child_view_changed(struct _cef_view_delegate_t* self,
+ cef_view_t* view,
+ int added,
+ cef_view_t* child) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return;
+ }
+ // Verify param: child; type: refptr_diff
+ DCHECK(child);
+ if (!child) {
+ return;
+ }
+
+ // Execute
+ CefButtonDelegateCppToC::Get(reinterpret_cast<cef_button_delegate_t*>(self))
+ ->OnChildViewChanged(CefViewCToCpp::Wrap(view), added ? true : false,
+ CefViewCToCpp::Wrap(child));
+}
+
+void CEF_CALLBACK
+button_delegate_on_window_changed(struct _cef_view_delegate_t* self,
+ cef_view_t* view,
+ int added) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return;
+ }
+
+ // Execute
+ CefButtonDelegateCppToC::Get(reinterpret_cast<cef_button_delegate_t*>(self))
+ ->OnWindowChanged(CefViewCToCpp::Wrap(view), added ? true : false);
+}
+
+void CEF_CALLBACK
+button_delegate_on_layout_changed(struct _cef_view_delegate_t* self,
+ cef_view_t* view,
+ const cef_rect_t* new_bounds) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return;
+ }
+ // Verify param: new_bounds; type: simple_byref_const
+ DCHECK(new_bounds);
+ if (!new_bounds) {
+ return;
+ }
+
+ // Translate param: new_bounds; type: simple_byref_const
+ CefRect new_boundsVal = new_bounds ? *new_bounds : CefRect();
+
+ // Execute
+ CefButtonDelegateCppToC::Get(reinterpret_cast<cef_button_delegate_t*>(self))
+ ->OnLayoutChanged(CefViewCToCpp::Wrap(view), new_boundsVal);
+}
+
+void CEF_CALLBACK button_delegate_on_focus(struct _cef_view_delegate_t* self,
+ cef_view_t* view) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return;
+ }
+
+ // Execute
+ CefButtonDelegateCppToC::Get(reinterpret_cast<cef_button_delegate_t*>(self))
+ ->OnFocus(CefViewCToCpp::Wrap(view));
+}
+
+void CEF_CALLBACK button_delegate_on_blur(struct _cef_view_delegate_t* self,
+ cef_view_t* view) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return;
+ }
+
+ // Execute
+ CefButtonDelegateCppToC::Get(reinterpret_cast<cef_button_delegate_t*>(self))
+ ->OnBlur(CefViewCToCpp::Wrap(view));
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefButtonDelegateCppToC::CefButtonDelegateCppToC() {
+ GetStruct()->on_button_pressed = button_delegate_on_button_pressed;
+ GetStruct()->on_button_state_changed =
+ button_delegate_on_button_state_changed;
+ GetStruct()->base.get_preferred_size = button_delegate_get_preferred_size;
+ GetStruct()->base.get_minimum_size = button_delegate_get_minimum_size;
+ GetStruct()->base.get_maximum_size = button_delegate_get_maximum_size;
+ GetStruct()->base.get_height_for_width = button_delegate_get_height_for_width;
+ GetStruct()->base.on_parent_view_changed =
+ button_delegate_on_parent_view_changed;
+ GetStruct()->base.on_child_view_changed =
+ button_delegate_on_child_view_changed;
+ GetStruct()->base.on_window_changed = button_delegate_on_window_changed;
+ GetStruct()->base.on_layout_changed = button_delegate_on_layout_changed;
+ GetStruct()->base.on_focus = button_delegate_on_focus;
+ GetStruct()->base.on_blur = button_delegate_on_blur;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefButtonDelegateCppToC::~CefButtonDelegateCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefButtonDelegate> CefCppToCRefCounted<
+ CefButtonDelegateCppToC,
+ CefButtonDelegate,
+ cef_button_delegate_t>::UnwrapDerived(CefWrapperType type,
+ cef_button_delegate_t* s) {
+ if (type == WT_MENU_BUTTON_DELEGATE) {
+ return CefMenuButtonDelegateCppToC::Unwrap(
+ reinterpret_cast<cef_menu_button_delegate_t*>(s));
+ }
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefButtonDelegateCppToC,
+ CefButtonDelegate,
+ cef_button_delegate_t>::kWrapperType =
+ WT_BUTTON_DELEGATE;
diff --git a/libcef_dll/cpptoc/views/button_delegate_cpptoc.h b/libcef_dll/cpptoc/views/button_delegate_cpptoc.h
new file mode 100644
index 00000000..b342d8c5
--- /dev/null
+++ b/libcef_dll/cpptoc/views/button_delegate_cpptoc.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=455b4eb400cc642cfb4cf0089b12059b8be31af6$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_VIEWS_BUTTON_DELEGATE_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_VIEWS_BUTTON_DELEGATE_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/views/cef_button_capi.h"
+#include "include/capi/views/cef_button_delegate_capi.h"
+#include "include/views/cef_button.h"
+#include "include/views/cef_button_delegate.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefButtonDelegateCppToC
+ : public CefCppToCRefCounted<CefButtonDelegateCppToC,
+ CefButtonDelegate,
+ cef_button_delegate_t> {
+ public:
+ CefButtonDelegateCppToC();
+ virtual ~CefButtonDelegateCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_VIEWS_BUTTON_DELEGATE_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/views/display_cpptoc.cc b/libcef_dll/cpptoc/views/display_cpptoc.cc
new file mode 100644
index 00000000..c346e55e
--- /dev/null
+++ b/libcef_dll/cpptoc/views/display_cpptoc.cc
@@ -0,0 +1,393 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=c876a721fa14497054e1d3fd3bd95a09298cd774$
+//
+
+#include "libcef_dll/cpptoc/views/display_cpptoc.h"
+#include <algorithm>
+#include "libcef_dll/shutdown_checker.h"
+
+// GLOBAL FUNCTIONS - Body may be edited by hand.
+
+CEF_EXPORT cef_display_t* cef_display_get_primary() {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ CefRefPtr<CefDisplay> _retval = CefDisplay::GetPrimaryDisplay();
+
+ // Return type: refptr_same
+ return CefDisplayCppToC::Wrap(_retval);
+}
+
+CEF_EXPORT cef_display_t* cef_display_get_nearest_point(
+ const cef_point_t* point,
+ int input_pixel_coords) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: point; type: simple_byref_const
+ DCHECK(point);
+ if (!point) {
+ return NULL;
+ }
+
+ // Translate param: point; type: simple_byref_const
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ CefRefPtr<CefDisplay> _retval = CefDisplay::GetDisplayNearestPoint(
+ pointVal, input_pixel_coords ? true : false);
+
+ // Return type: refptr_same
+ return CefDisplayCppToC::Wrap(_retval);
+}
+
+CEF_EXPORT cef_display_t* cef_display_get_matching_bounds(
+ const cef_rect_t* bounds,
+ int input_pixel_coords) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: bounds; type: simple_byref_const
+ DCHECK(bounds);
+ if (!bounds) {
+ return NULL;
+ }
+
+ // Translate param: bounds; type: simple_byref_const
+ CefRect boundsVal = bounds ? *bounds : CefRect();
+
+ // Execute
+ CefRefPtr<CefDisplay> _retval = CefDisplay::GetDisplayMatchingBounds(
+ boundsVal, input_pixel_coords ? true : false);
+
+ // Return type: refptr_same
+ return CefDisplayCppToC::Wrap(_retval);
+}
+
+CEF_EXPORT size_t cef_display_get_count() {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ size_t _retval = CefDisplay::GetDisplayCount();
+
+ // Return type: simple
+ return _retval;
+}
+
+CEF_EXPORT void cef_display_get_alls(size_t* displaysCount,
+ cef_display_t** displays) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: displays; type: refptr_vec_same_byref
+ DCHECK(displaysCount && (*displaysCount == 0 || displays));
+ if (!displaysCount || (*displaysCount > 0 && !displays)) {
+ return;
+ }
+
+ // Translate param: displays; type: refptr_vec_same_byref
+ std::vector<CefRefPtr<CefDisplay>> displaysList;
+ if (displaysCount && *displaysCount > 0 && displays) {
+ for (size_t i = 0; i < *displaysCount; ++i) {
+ displaysList.push_back(CefDisplayCppToC::Unwrap(displays[i]));
+ }
+ }
+
+ // Execute
+ CefDisplay::GetAllDisplays(displaysList);
+
+ // Restore param: displays; type: refptr_vec_same_byref
+ if (displaysCount && displays) {
+ *displaysCount = std::min(displaysList.size(), *displaysCount);
+ if (*displaysCount > 0) {
+ for (size_t i = 0; i < *displaysCount; ++i) {
+ displays[i] = CefDisplayCppToC::Wrap(displaysList[i]);
+ }
+ }
+ }
+}
+
+CEF_EXPORT cef_point_t
+cef_display_convert_screen_point_to_pixels(const cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: point; type: simple_byref_const
+ DCHECK(point);
+ if (!point) {
+ return CefPoint();
+ }
+
+ // Translate param: point; type: simple_byref_const
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ cef_point_t _retval = CefDisplay::ConvertScreenPointToPixels(pointVal);
+
+ // Return type: simple
+ return _retval;
+}
+
+CEF_EXPORT cef_point_t
+cef_display_convert_screen_point_from_pixels(const cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: point; type: simple_byref_const
+ DCHECK(point);
+ if (!point) {
+ return CefPoint();
+ }
+
+ // Translate param: point; type: simple_byref_const
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ cef_point_t _retval = CefDisplay::ConvertScreenPointFromPixels(pointVal);
+
+ // Return type: simple
+ return _retval;
+}
+
+CEF_EXPORT cef_rect_t
+cef_display_convert_screen_rect_to_pixels(const cef_rect_t* rect) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: rect; type: simple_byref_const
+ DCHECK(rect);
+ if (!rect) {
+ return CefRect();
+ }
+
+ // Translate param: rect; type: simple_byref_const
+ CefRect rectVal = rect ? *rect : CefRect();
+
+ // Execute
+ cef_rect_t _retval = CefDisplay::ConvertScreenRectToPixels(rectVal);
+
+ // Return type: simple
+ return _retval;
+}
+
+CEF_EXPORT cef_rect_t
+cef_display_convert_screen_rect_from_pixels(const cef_rect_t* rect) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: rect; type: simple_byref_const
+ DCHECK(rect);
+ if (!rect) {
+ return CefRect();
+ }
+
+ // Translate param: rect; type: simple_byref_const
+ CefRect rectVal = rect ? *rect : CefRect();
+
+ // Execute
+ cef_rect_t _retval = CefDisplay::ConvertScreenRectFromPixels(rectVal);
+
+ // Return type: simple
+ return _retval;
+}
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int64 CEF_CALLBACK display_get_id(struct _cef_display_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int64 _retval = CefDisplayCppToC::Get(self)->GetID();
+
+ // Return type: simple
+ return _retval;
+}
+
+float CEF_CALLBACK
+display_get_device_scale_factor(struct _cef_display_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ float _retval = CefDisplayCppToC::Get(self)->GetDeviceScaleFactor();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK display_convert_point_to_pixels(struct _cef_display_t* self,
+ cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: point; type: simple_byref
+ DCHECK(point);
+ if (!point) {
+ return;
+ }
+
+ // Translate param: point; type: simple_byref
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ CefDisplayCppToC::Get(self)->ConvertPointToPixels(pointVal);
+
+ // Restore param: point; type: simple_byref
+ if (point) {
+ *point = pointVal;
+ }
+}
+
+void CEF_CALLBACK display_convert_point_from_pixels(struct _cef_display_t* self,
+ cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: point; type: simple_byref
+ DCHECK(point);
+ if (!point) {
+ return;
+ }
+
+ // Translate param: point; type: simple_byref
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ CefDisplayCppToC::Get(self)->ConvertPointFromPixels(pointVal);
+
+ // Restore param: point; type: simple_byref
+ if (point) {
+ *point = pointVal;
+ }
+}
+
+cef_rect_t CEF_CALLBACK display_get_bounds(struct _cef_display_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefRect();
+ }
+
+ // Execute
+ cef_rect_t _retval = CefDisplayCppToC::Get(self)->GetBounds();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_rect_t CEF_CALLBACK display_get_work_area(struct _cef_display_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefRect();
+ }
+
+ // Execute
+ cef_rect_t _retval = CefDisplayCppToC::Get(self)->GetWorkArea();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK display_get_rotation(struct _cef_display_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefDisplayCppToC::Get(self)->GetRotation();
+
+ // Return type: simple
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefDisplayCppToC::CefDisplayCppToC() {
+ GetStruct()->get_id = display_get_id;
+ GetStruct()->get_device_scale_factor = display_get_device_scale_factor;
+ GetStruct()->convert_point_to_pixels = display_convert_point_to_pixels;
+ GetStruct()->convert_point_from_pixels = display_convert_point_from_pixels;
+ GetStruct()->get_bounds = display_get_bounds;
+ GetStruct()->get_work_area = display_get_work_area;
+ GetStruct()->get_rotation = display_get_rotation;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefDisplayCppToC::~CefDisplayCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefDisplay>
+CefCppToCRefCounted<CefDisplayCppToC, CefDisplay, cef_display_t>::UnwrapDerived(
+ CefWrapperType type,
+ cef_display_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefDisplayCppToC,
+ CefDisplay,
+ cef_display_t>::kWrapperType = WT_DISPLAY;
diff --git a/libcef_dll/cpptoc/views/display_cpptoc.h b/libcef_dll/cpptoc/views/display_cpptoc.h
new file mode 100644
index 00000000..13eb6a65
--- /dev/null
+++ b/libcef_dll/cpptoc/views/display_cpptoc.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=73811073aeb490787e777b5e7f8e41ef34cd6369$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_VIEWS_DISPLAY_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_VIEWS_DISPLAY_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/views/cef_display_capi.h"
+#include "include/views/cef_display.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefDisplayCppToC
+ : public CefCppToCRefCounted<CefDisplayCppToC, CefDisplay, cef_display_t> {
+ public:
+ CefDisplayCppToC();
+ virtual ~CefDisplayCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_VIEWS_DISPLAY_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/views/fill_layout_cpptoc.cc b/libcef_dll/cpptoc/views/fill_layout_cpptoc.cc
new file mode 100644
index 00000000..e700440d
--- /dev/null
+++ b/libcef_dll/cpptoc/views/fill_layout_cpptoc.cc
@@ -0,0 +1,110 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=94b09cfcb27c860d91d5c36b80f84569e35c9147$
+//
+
+#include "libcef_dll/cpptoc/views/fill_layout_cpptoc.h"
+#include "libcef_dll/cpptoc/views/box_layout_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+cef_box_layout_t* CEF_CALLBACK
+fill_layout_as_box_layout(struct _cef_layout_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefBoxLayout> _retval =
+ CefFillLayoutCppToC::Get(reinterpret_cast<cef_fill_layout_t*>(self))
+ ->AsBoxLayout();
+
+ // Return type: refptr_same
+ return CefBoxLayoutCppToC::Wrap(_retval);
+}
+
+cef_fill_layout_t* CEF_CALLBACK
+fill_layout_as_fill_layout(struct _cef_layout_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefFillLayout> _retval =
+ CefFillLayoutCppToC::Get(reinterpret_cast<cef_fill_layout_t*>(self))
+ ->AsFillLayout();
+
+ // Return type: refptr_same
+ return CefFillLayoutCppToC::Wrap(_retval);
+}
+
+int CEF_CALLBACK fill_layout_is_valid(struct _cef_layout_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefFillLayoutCppToC::Get(reinterpret_cast<cef_fill_layout_t*>(self))
+ ->IsValid();
+
+ // Return type: bool
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefFillLayoutCppToC::CefFillLayoutCppToC() {
+ GetStruct()->base.as_box_layout = fill_layout_as_box_layout;
+ GetStruct()->base.as_fill_layout = fill_layout_as_fill_layout;
+ GetStruct()->base.is_valid = fill_layout_is_valid;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefFillLayoutCppToC::~CefFillLayoutCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefFillLayout>
+CefCppToCRefCounted<CefFillLayoutCppToC, CefFillLayout, cef_fill_layout_t>::
+ UnwrapDerived(CefWrapperType type, cef_fill_layout_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefFillLayoutCppToC,
+ CefFillLayout,
+ cef_fill_layout_t>::kWrapperType =
+ WT_FILL_LAYOUT;
diff --git a/libcef_dll/cpptoc/views/fill_layout_cpptoc.h b/libcef_dll/cpptoc/views/fill_layout_cpptoc.h
new file mode 100644
index 00000000..a6958422
--- /dev/null
+++ b/libcef_dll/cpptoc/views/fill_layout_cpptoc.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=88b95199af576610e6ce7e71603fb3c8b1426046$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_VIEWS_FILL_LAYOUT_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_VIEWS_FILL_LAYOUT_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/views/cef_fill_layout_capi.h"
+#include "include/views/cef_fill_layout.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefFillLayoutCppToC : public CefCppToCRefCounted<CefFillLayoutCppToC,
+ CefFillLayout,
+ cef_fill_layout_t> {
+ public:
+ CefFillLayoutCppToC();
+ virtual ~CefFillLayoutCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_VIEWS_FILL_LAYOUT_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/views/label_button_cpptoc.cc b/libcef_dll/cpptoc/views/label_button_cpptoc.cc
new file mode 100644
index 00000000..801e8753
--- /dev/null
+++ b/libcef_dll/cpptoc/views/label_button_cpptoc.cc
@@ -0,0 +1,1550 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=b82103e68fffd36a97aa8d9784a1f2def77a6fab$
+//
+
+#include "libcef_dll/cpptoc/views/label_button_cpptoc.h"
+#include "libcef_dll/cpptoc/image_cpptoc.h"
+#include "libcef_dll/cpptoc/views/browser_view_cpptoc.h"
+#include "libcef_dll/cpptoc/views/button_cpptoc.h"
+#include "libcef_dll/cpptoc/views/menu_button_cpptoc.h"
+#include "libcef_dll/cpptoc/views/panel_cpptoc.h"
+#include "libcef_dll/cpptoc/views/scroll_view_cpptoc.h"
+#include "libcef_dll/cpptoc/views/textfield_cpptoc.h"
+#include "libcef_dll/cpptoc/views/view_cpptoc.h"
+#include "libcef_dll/cpptoc/views/window_cpptoc.h"
+#include "libcef_dll/ctocpp/views/button_delegate_ctocpp.h"
+#include "libcef_dll/ctocpp/views/view_delegate_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// GLOBAL FUNCTIONS - Body may be edited by hand.
+
+CEF_EXPORT cef_label_button_t* cef_label_button_create(
+ cef_button_delegate_t* delegate,
+ const cef_string_t* text) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: delegate; type: refptr_diff
+ DCHECK(delegate);
+ if (!delegate) {
+ return NULL;
+ }
+ // Unverified params: text
+
+ // Execute
+ CefRefPtr<CefLabelButton> _retval = CefLabelButton::CreateLabelButton(
+ CefButtonDelegateCToCpp::Wrap(delegate), CefString(text));
+
+ // Return type: refptr_same
+ return CefLabelButtonCppToC::Wrap(_retval);
+}
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+cef_menu_button_t* CEF_CALLBACK
+label_button_as_menu_button(struct _cef_label_button_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefMenuButton> _retval =
+ CefLabelButtonCppToC::Get(self)->AsMenuButton();
+
+ // Return type: refptr_same
+ return CefMenuButtonCppToC::Wrap(_retval);
+}
+
+void CEF_CALLBACK label_button_set_text(struct _cef_label_button_t* self,
+ const cef_string_t* text) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: text; type: string_byref_const
+ DCHECK(text);
+ if (!text) {
+ return;
+ }
+
+ // Execute
+ CefLabelButtonCppToC::Get(self)->SetText(CefString(text));
+}
+
+cef_string_userfree_t CEF_CALLBACK
+label_button_get_text(struct _cef_label_button_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefLabelButtonCppToC::Get(self)->GetText();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+void CEF_CALLBACK label_button_set_image(struct _cef_label_button_t* self,
+ cef_button_state_t button_state,
+ cef_image_t* image) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Unverified params: image
+
+ // Execute
+ CefLabelButtonCppToC::Get(self)->SetImage(button_state,
+ CefImageCppToC::Unwrap(image));
+}
+
+cef_image_t* CEF_CALLBACK
+label_button_get_image(struct _cef_label_button_t* self,
+ cef_button_state_t button_state) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefImage> _retval =
+ CefLabelButtonCppToC::Get(self)->GetImage(button_state);
+
+ // Return type: refptr_same
+ return CefImageCppToC::Wrap(_retval);
+}
+
+void CEF_CALLBACK label_button_set_text_color(struct _cef_label_button_t* self,
+ cef_button_state_t for_state,
+ cef_color_t color) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefLabelButtonCppToC::Get(self)->SetTextColor(for_state, color);
+}
+
+void CEF_CALLBACK
+label_button_set_enabled_text_colors(struct _cef_label_button_t* self,
+ cef_color_t color) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefLabelButtonCppToC::Get(self)->SetEnabledTextColors(color);
+}
+
+void CEF_CALLBACK label_button_set_font_list(struct _cef_label_button_t* self,
+ const cef_string_t* font_list) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: font_list; type: string_byref_const
+ DCHECK(font_list);
+ if (!font_list) {
+ return;
+ }
+
+ // Execute
+ CefLabelButtonCppToC::Get(self)->SetFontList(CefString(font_list));
+}
+
+void CEF_CALLBACK
+label_button_set_horizontal_alignment(struct _cef_label_button_t* self,
+ cef_horizontal_alignment_t alignment) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefLabelButtonCppToC::Get(self)->SetHorizontalAlignment(alignment);
+}
+
+void CEF_CALLBACK
+label_button_set_minimum_size(struct _cef_label_button_t* self,
+ const cef_size_t* size) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: size; type: simple_byref_const
+ DCHECK(size);
+ if (!size) {
+ return;
+ }
+
+ // Translate param: size; type: simple_byref_const
+ CefSize sizeVal = size ? *size : CefSize();
+
+ // Execute
+ CefLabelButtonCppToC::Get(self)->SetMinimumSize(sizeVal);
+}
+
+void CEF_CALLBACK
+label_button_set_maximum_size(struct _cef_label_button_t* self,
+ const cef_size_t* size) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: size; type: simple_byref_const
+ DCHECK(size);
+ if (!size) {
+ return;
+ }
+
+ // Translate param: size; type: simple_byref_const
+ CefSize sizeVal = size ? *size : CefSize();
+
+ // Execute
+ CefLabelButtonCppToC::Get(self)->SetMaximumSize(sizeVal);
+}
+
+cef_label_button_t* CEF_CALLBACK
+label_button_as_label_button(struct _cef_button_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefLabelButton> _retval =
+ CefLabelButtonCppToC::Get(reinterpret_cast<cef_label_button_t*>(self))
+ ->AsLabelButton();
+
+ // Return type: refptr_same
+ return CefLabelButtonCppToC::Wrap(_retval);
+}
+
+void CEF_CALLBACK label_button_set_state(struct _cef_button_t* self,
+ cef_button_state_t state) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefLabelButtonCppToC::Get(reinterpret_cast<cef_label_button_t*>(self))
+ ->SetState(state);
+}
+
+cef_button_state_t CEF_CALLBACK
+label_button_get_state(struct _cef_button_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CEF_BUTTON_STATE_NORMAL;
+ }
+
+ // Execute
+ cef_button_state_t _retval =
+ CefLabelButtonCppToC::Get(reinterpret_cast<cef_label_button_t*>(self))
+ ->GetState();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK label_button_set_ink_drop_enabled(struct _cef_button_t* self,
+ int enabled) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefLabelButtonCppToC::Get(reinterpret_cast<cef_label_button_t*>(self))
+ ->SetInkDropEnabled(enabled ? true : false);
+}
+
+void CEF_CALLBACK
+label_button_set_tooltip_text(struct _cef_button_t* self,
+ const cef_string_t* tooltip_text) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: tooltip_text; type: string_byref_const
+ DCHECK(tooltip_text);
+ if (!tooltip_text) {
+ return;
+ }
+
+ // Execute
+ CefLabelButtonCppToC::Get(reinterpret_cast<cef_label_button_t*>(self))
+ ->SetTooltipText(CefString(tooltip_text));
+}
+
+void CEF_CALLBACK label_button_set_accessible_name(struct _cef_button_t* self,
+ const cef_string_t* name) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: name; type: string_byref_const
+ DCHECK(name);
+ if (!name) {
+ return;
+ }
+
+ // Execute
+ CefLabelButtonCppToC::Get(reinterpret_cast<cef_label_button_t*>(self))
+ ->SetAccessibleName(CefString(name));
+}
+
+cef_browser_view_t* CEF_CALLBACK
+label_button_as_browser_view(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefBrowserView> _retval =
+ CefLabelButtonCppToC::Get(reinterpret_cast<cef_label_button_t*>(self))
+ ->AsBrowserView();
+
+ // Return type: refptr_same
+ return CefBrowserViewCppToC::Wrap(_retval);
+}
+
+cef_button_t* CEF_CALLBACK label_button_as_button(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefButton> _retval =
+ CefLabelButtonCppToC::Get(reinterpret_cast<cef_label_button_t*>(self))
+ ->AsButton();
+
+ // Return type: refptr_same
+ return CefButtonCppToC::Wrap(_retval);
+}
+
+cef_panel_t* CEF_CALLBACK label_button_as_panel(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefPanel> _retval =
+ CefLabelButtonCppToC::Get(reinterpret_cast<cef_label_button_t*>(self))
+ ->AsPanel();
+
+ // Return type: refptr_same
+ return CefPanelCppToC::Wrap(_retval);
+}
+
+cef_scroll_view_t* CEF_CALLBACK
+label_button_as_scroll_view(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefScrollView> _retval =
+ CefLabelButtonCppToC::Get(reinterpret_cast<cef_label_button_t*>(self))
+ ->AsScrollView();
+
+ // Return type: refptr_same
+ return CefScrollViewCppToC::Wrap(_retval);
+}
+
+cef_textfield_t* CEF_CALLBACK
+label_button_as_textfield(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefTextfield> _retval =
+ CefLabelButtonCppToC::Get(reinterpret_cast<cef_label_button_t*>(self))
+ ->AsTextfield();
+
+ // Return type: refptr_same
+ return CefTextfieldCppToC::Wrap(_retval);
+}
+
+cef_string_userfree_t CEF_CALLBACK
+label_button_get_type_string(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval =
+ CefLabelButtonCppToC::Get(reinterpret_cast<cef_label_button_t*>(self))
+ ->GetTypeString();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_string_userfree_t CEF_CALLBACK
+label_button_to_string(struct _cef_view_t* self, int include_children) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval =
+ CefLabelButtonCppToC::Get(reinterpret_cast<cef_label_button_t*>(self))
+ ->ToString(include_children ? true : false);
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+int CEF_CALLBACK label_button_is_valid(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefLabelButtonCppToC::Get(reinterpret_cast<cef_label_button_t*>(self))
+ ->IsValid();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK label_button_is_attached(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefLabelButtonCppToC::Get(reinterpret_cast<cef_label_button_t*>(self))
+ ->IsAttached();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK label_button_is_same(struct _cef_view_t* self,
+ struct _cef_view_t* that) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: that; type: refptr_same
+ DCHECK(that);
+ if (!that) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefLabelButtonCppToC::Get(reinterpret_cast<cef_label_button_t*>(self))
+ ->IsSame(CefViewCppToC::Unwrap(that));
+
+ // Return type: bool
+ return _retval;
+}
+
+struct _cef_view_delegate_t* CEF_CALLBACK
+label_button_get_delegate(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefViewDelegate> _retval =
+ CefLabelButtonCppToC::Get(reinterpret_cast<cef_label_button_t*>(self))
+ ->GetDelegate();
+
+ // Return type: refptr_diff
+ return CefViewDelegateCToCpp::Unwrap(_retval);
+}
+
+struct _cef_window_t* CEF_CALLBACK
+label_button_get_window(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefWindow> _retval =
+ CefLabelButtonCppToC::Get(reinterpret_cast<cef_label_button_t*>(self))
+ ->GetWindow();
+
+ // Return type: refptr_same
+ return CefWindowCppToC::Wrap(_retval);
+}
+
+int CEF_CALLBACK label_button_get_id(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval =
+ CefLabelButtonCppToC::Get(reinterpret_cast<cef_label_button_t*>(self))
+ ->GetID();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK label_button_set_id(struct _cef_view_t* self, int id) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefLabelButtonCppToC::Get(reinterpret_cast<cef_label_button_t*>(self))
+ ->SetID(id);
+}
+
+int CEF_CALLBACK label_button_get_group_id(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval =
+ CefLabelButtonCppToC::Get(reinterpret_cast<cef_label_button_t*>(self))
+ ->GetGroupID();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK label_button_set_group_id(struct _cef_view_t* self,
+ int group_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefLabelButtonCppToC::Get(reinterpret_cast<cef_label_button_t*>(self))
+ ->SetGroupID(group_id);
+}
+
+struct _cef_view_t* CEF_CALLBACK
+label_button_get_parent_view(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefView> _retval =
+ CefLabelButtonCppToC::Get(reinterpret_cast<cef_label_button_t*>(self))
+ ->GetParentView();
+
+ // Return type: refptr_same
+ return CefViewCppToC::Wrap(_retval);
+}
+
+struct _cef_view_t* CEF_CALLBACK
+label_button_get_view_for_id(struct _cef_view_t* self, int id) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefView> _retval =
+ CefLabelButtonCppToC::Get(reinterpret_cast<cef_label_button_t*>(self))
+ ->GetViewForID(id);
+
+ // Return type: refptr_same
+ return CefViewCppToC::Wrap(_retval);
+}
+
+void CEF_CALLBACK label_button_set_bounds(struct _cef_view_t* self,
+ const cef_rect_t* bounds) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: bounds; type: simple_byref_const
+ DCHECK(bounds);
+ if (!bounds) {
+ return;
+ }
+
+ // Translate param: bounds; type: simple_byref_const
+ CefRect boundsVal = bounds ? *bounds : CefRect();
+
+ // Execute
+ CefLabelButtonCppToC::Get(reinterpret_cast<cef_label_button_t*>(self))
+ ->SetBounds(boundsVal);
+}
+
+cef_rect_t CEF_CALLBACK label_button_get_bounds(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefRect();
+ }
+
+ // Execute
+ cef_rect_t _retval =
+ CefLabelButtonCppToC::Get(reinterpret_cast<cef_label_button_t*>(self))
+ ->GetBounds();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_rect_t CEF_CALLBACK
+label_button_get_bounds_in_screen(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefRect();
+ }
+
+ // Execute
+ cef_rect_t _retval =
+ CefLabelButtonCppToC::Get(reinterpret_cast<cef_label_button_t*>(self))
+ ->GetBoundsInScreen();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK label_button_set_size(struct _cef_view_t* self,
+ const cef_size_t* size) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: size; type: simple_byref_const
+ DCHECK(size);
+ if (!size) {
+ return;
+ }
+
+ // Translate param: size; type: simple_byref_const
+ CefSize sizeVal = size ? *size : CefSize();
+
+ // Execute
+ CefLabelButtonCppToC::Get(reinterpret_cast<cef_label_button_t*>(self))
+ ->SetSize(sizeVal);
+}
+
+cef_size_t CEF_CALLBACK label_button_get_size(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval =
+ CefLabelButtonCppToC::Get(reinterpret_cast<cef_label_button_t*>(self))
+ ->GetSize();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK label_button_set_position(struct _cef_view_t* self,
+ const cef_point_t* position) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: position; type: simple_byref_const
+ DCHECK(position);
+ if (!position) {
+ return;
+ }
+
+ // Translate param: position; type: simple_byref_const
+ CefPoint positionVal = position ? *position : CefPoint();
+
+ // Execute
+ CefLabelButtonCppToC::Get(reinterpret_cast<cef_label_button_t*>(self))
+ ->SetPosition(positionVal);
+}
+
+cef_point_t CEF_CALLBACK label_button_get_position(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefPoint();
+ }
+
+ // Execute
+ cef_point_t _retval =
+ CefLabelButtonCppToC::Get(reinterpret_cast<cef_label_button_t*>(self))
+ ->GetPosition();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK label_button_set_insets(struct _cef_view_t* self,
+ const cef_insets_t* insets) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: insets; type: simple_byref_const
+ DCHECK(insets);
+ if (!insets) {
+ return;
+ }
+
+ // Translate param: insets; type: simple_byref_const
+ CefInsets insetsVal = insets ? *insets : CefInsets();
+
+ // Execute
+ CefLabelButtonCppToC::Get(reinterpret_cast<cef_label_button_t*>(self))
+ ->SetInsets(insetsVal);
+}
+
+cef_insets_t CEF_CALLBACK label_button_get_insets(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefInsets();
+ }
+
+ // Execute
+ cef_insets_t _retval =
+ CefLabelButtonCppToC::Get(reinterpret_cast<cef_label_button_t*>(self))
+ ->GetInsets();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_size_t CEF_CALLBACK
+label_button_get_preferred_size(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval =
+ CefLabelButtonCppToC::Get(reinterpret_cast<cef_label_button_t*>(self))
+ ->GetPreferredSize();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK
+label_button_size_to_preferred_size(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefLabelButtonCppToC::Get(reinterpret_cast<cef_label_button_t*>(self))
+ ->SizeToPreferredSize();
+}
+
+cef_size_t CEF_CALLBACK
+label_button_get_minimum_size(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval =
+ CefLabelButtonCppToC::Get(reinterpret_cast<cef_label_button_t*>(self))
+ ->GetMinimumSize();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_size_t CEF_CALLBACK
+label_button_get_maximum_size(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval =
+ CefLabelButtonCppToC::Get(reinterpret_cast<cef_label_button_t*>(self))
+ ->GetMaximumSize();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK label_button_get_height_for_width(struct _cef_view_t* self,
+ int width) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval =
+ CefLabelButtonCppToC::Get(reinterpret_cast<cef_label_button_t*>(self))
+ ->GetHeightForWidth(width);
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK label_button_invalidate_layout(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefLabelButtonCppToC::Get(reinterpret_cast<cef_label_button_t*>(self))
+ ->InvalidateLayout();
+}
+
+void CEF_CALLBACK label_button_set_visible(struct _cef_view_t* self,
+ int visible) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefLabelButtonCppToC::Get(reinterpret_cast<cef_label_button_t*>(self))
+ ->SetVisible(visible ? true : false);
+}
+
+int CEF_CALLBACK label_button_is_visible(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefLabelButtonCppToC::Get(reinterpret_cast<cef_label_button_t*>(self))
+ ->IsVisible();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK label_button_is_drawn(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefLabelButtonCppToC::Get(reinterpret_cast<cef_label_button_t*>(self))
+ ->IsDrawn();
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK label_button_set_enabled(struct _cef_view_t* self,
+ int enabled) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefLabelButtonCppToC::Get(reinterpret_cast<cef_label_button_t*>(self))
+ ->SetEnabled(enabled ? true : false);
+}
+
+int CEF_CALLBACK label_button_is_enabled(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefLabelButtonCppToC::Get(reinterpret_cast<cef_label_button_t*>(self))
+ ->IsEnabled();
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK label_button_set_focusable(struct _cef_view_t* self,
+ int focusable) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefLabelButtonCppToC::Get(reinterpret_cast<cef_label_button_t*>(self))
+ ->SetFocusable(focusable ? true : false);
+}
+
+int CEF_CALLBACK label_button_is_focusable(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefLabelButtonCppToC::Get(reinterpret_cast<cef_label_button_t*>(self))
+ ->IsFocusable();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+label_button_is_accessibility_focusable(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefLabelButtonCppToC::Get(reinterpret_cast<cef_label_button_t*>(self))
+ ->IsAccessibilityFocusable();
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK label_button_request_focus(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefLabelButtonCppToC::Get(reinterpret_cast<cef_label_button_t*>(self))
+ ->RequestFocus();
+}
+
+void CEF_CALLBACK label_button_set_background_color(struct _cef_view_t* self,
+ cef_color_t color) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefLabelButtonCppToC::Get(reinterpret_cast<cef_label_button_t*>(self))
+ ->SetBackgroundColor(color);
+}
+
+cef_color_t CEF_CALLBACK
+label_button_get_background_color(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ cef_color_t _retval =
+ CefLabelButtonCppToC::Get(reinterpret_cast<cef_label_button_t*>(self))
+ ->GetBackgroundColor();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK label_button_convert_point_to_screen(struct _cef_view_t* self,
+ cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: point; type: simple_byref
+ DCHECK(point);
+ if (!point) {
+ return 0;
+ }
+
+ // Translate param: point; type: simple_byref
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ bool _retval =
+ CefLabelButtonCppToC::Get(reinterpret_cast<cef_label_button_t*>(self))
+ ->ConvertPointToScreen(pointVal);
+
+ // Restore param: point; type: simple_byref
+ if (point) {
+ *point = pointVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+label_button_convert_point_from_screen(struct _cef_view_t* self,
+ cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: point; type: simple_byref
+ DCHECK(point);
+ if (!point) {
+ return 0;
+ }
+
+ // Translate param: point; type: simple_byref
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ bool _retval =
+ CefLabelButtonCppToC::Get(reinterpret_cast<cef_label_button_t*>(self))
+ ->ConvertPointFromScreen(pointVal);
+
+ // Restore param: point; type: simple_byref
+ if (point) {
+ *point = pointVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK label_button_convert_point_to_window(struct _cef_view_t* self,
+ cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: point; type: simple_byref
+ DCHECK(point);
+ if (!point) {
+ return 0;
+ }
+
+ // Translate param: point; type: simple_byref
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ bool _retval =
+ CefLabelButtonCppToC::Get(reinterpret_cast<cef_label_button_t*>(self))
+ ->ConvertPointToWindow(pointVal);
+
+ // Restore param: point; type: simple_byref
+ if (point) {
+ *point = pointVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+label_button_convert_point_from_window(struct _cef_view_t* self,
+ cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: point; type: simple_byref
+ DCHECK(point);
+ if (!point) {
+ return 0;
+ }
+
+ // Translate param: point; type: simple_byref
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ bool _retval =
+ CefLabelButtonCppToC::Get(reinterpret_cast<cef_label_button_t*>(self))
+ ->ConvertPointFromWindow(pointVal);
+
+ // Restore param: point; type: simple_byref
+ if (point) {
+ *point = pointVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK label_button_convert_point_to_view(struct _cef_view_t* self,
+ struct _cef_view_t* view,
+ cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: view; type: refptr_same
+ DCHECK(view);
+ if (!view) {
+ return 0;
+ }
+ // Verify param: point; type: simple_byref
+ DCHECK(point);
+ if (!point) {
+ return 0;
+ }
+
+ // Translate param: point; type: simple_byref
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ bool _retval =
+ CefLabelButtonCppToC::Get(reinterpret_cast<cef_label_button_t*>(self))
+ ->ConvertPointToView(CefViewCppToC::Unwrap(view), pointVal);
+
+ // Restore param: point; type: simple_byref
+ if (point) {
+ *point = pointVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK label_button_convert_point_from_view(struct _cef_view_t* self,
+ struct _cef_view_t* view,
+ cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: view; type: refptr_same
+ DCHECK(view);
+ if (!view) {
+ return 0;
+ }
+ // Verify param: point; type: simple_byref
+ DCHECK(point);
+ if (!point) {
+ return 0;
+ }
+
+ // Translate param: point; type: simple_byref
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ bool _retval =
+ CefLabelButtonCppToC::Get(reinterpret_cast<cef_label_button_t*>(self))
+ ->ConvertPointFromView(CefViewCppToC::Unwrap(view), pointVal);
+
+ // Restore param: point; type: simple_byref
+ if (point) {
+ *point = pointVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefLabelButtonCppToC::CefLabelButtonCppToC() {
+ GetStruct()->as_menu_button = label_button_as_menu_button;
+ GetStruct()->set_text = label_button_set_text;
+ GetStruct()->get_text = label_button_get_text;
+ GetStruct()->set_image = label_button_set_image;
+ GetStruct()->get_image = label_button_get_image;
+ GetStruct()->set_text_color = label_button_set_text_color;
+ GetStruct()->set_enabled_text_colors = label_button_set_enabled_text_colors;
+ GetStruct()->set_font_list = label_button_set_font_list;
+ GetStruct()->set_horizontal_alignment = label_button_set_horizontal_alignment;
+ GetStruct()->set_minimum_size = label_button_set_minimum_size;
+ GetStruct()->set_maximum_size = label_button_set_maximum_size;
+ GetStruct()->base.as_label_button = label_button_as_label_button;
+ GetStruct()->base.set_state = label_button_set_state;
+ GetStruct()->base.get_state = label_button_get_state;
+ GetStruct()->base.set_ink_drop_enabled = label_button_set_ink_drop_enabled;
+ GetStruct()->base.set_tooltip_text = label_button_set_tooltip_text;
+ GetStruct()->base.set_accessible_name = label_button_set_accessible_name;
+ GetStruct()->base.base.as_browser_view = label_button_as_browser_view;
+ GetStruct()->base.base.as_button = label_button_as_button;
+ GetStruct()->base.base.as_panel = label_button_as_panel;
+ GetStruct()->base.base.as_scroll_view = label_button_as_scroll_view;
+ GetStruct()->base.base.as_textfield = label_button_as_textfield;
+ GetStruct()->base.base.get_type_string = label_button_get_type_string;
+ GetStruct()->base.base.to_string = label_button_to_string;
+ GetStruct()->base.base.is_valid = label_button_is_valid;
+ GetStruct()->base.base.is_attached = label_button_is_attached;
+ GetStruct()->base.base.is_same = label_button_is_same;
+ GetStruct()->base.base.get_delegate = label_button_get_delegate;
+ GetStruct()->base.base.get_window = label_button_get_window;
+ GetStruct()->base.base.get_id = label_button_get_id;
+ GetStruct()->base.base.set_id = label_button_set_id;
+ GetStruct()->base.base.get_group_id = label_button_get_group_id;
+ GetStruct()->base.base.set_group_id = label_button_set_group_id;
+ GetStruct()->base.base.get_parent_view = label_button_get_parent_view;
+ GetStruct()->base.base.get_view_for_id = label_button_get_view_for_id;
+ GetStruct()->base.base.set_bounds = label_button_set_bounds;
+ GetStruct()->base.base.get_bounds = label_button_get_bounds;
+ GetStruct()->base.base.get_bounds_in_screen =
+ label_button_get_bounds_in_screen;
+ GetStruct()->base.base.set_size = label_button_set_size;
+ GetStruct()->base.base.get_size = label_button_get_size;
+ GetStruct()->base.base.set_position = label_button_set_position;
+ GetStruct()->base.base.get_position = label_button_get_position;
+ GetStruct()->base.base.set_insets = label_button_set_insets;
+ GetStruct()->base.base.get_insets = label_button_get_insets;
+ GetStruct()->base.base.get_preferred_size = label_button_get_preferred_size;
+ GetStruct()->base.base.size_to_preferred_size =
+ label_button_size_to_preferred_size;
+ GetStruct()->base.base.get_minimum_size = label_button_get_minimum_size;
+ GetStruct()->base.base.get_maximum_size = label_button_get_maximum_size;
+ GetStruct()->base.base.get_height_for_width =
+ label_button_get_height_for_width;
+ GetStruct()->base.base.invalidate_layout = label_button_invalidate_layout;
+ GetStruct()->base.base.set_visible = label_button_set_visible;
+ GetStruct()->base.base.is_visible = label_button_is_visible;
+ GetStruct()->base.base.is_drawn = label_button_is_drawn;
+ GetStruct()->base.base.set_enabled = label_button_set_enabled;
+ GetStruct()->base.base.is_enabled = label_button_is_enabled;
+ GetStruct()->base.base.set_focusable = label_button_set_focusable;
+ GetStruct()->base.base.is_focusable = label_button_is_focusable;
+ GetStruct()->base.base.is_accessibility_focusable =
+ label_button_is_accessibility_focusable;
+ GetStruct()->base.base.request_focus = label_button_request_focus;
+ GetStruct()->base.base.set_background_color =
+ label_button_set_background_color;
+ GetStruct()->base.base.get_background_color =
+ label_button_get_background_color;
+ GetStruct()->base.base.convert_point_to_screen =
+ label_button_convert_point_to_screen;
+ GetStruct()->base.base.convert_point_from_screen =
+ label_button_convert_point_from_screen;
+ GetStruct()->base.base.convert_point_to_window =
+ label_button_convert_point_to_window;
+ GetStruct()->base.base.convert_point_from_window =
+ label_button_convert_point_from_window;
+ GetStruct()->base.base.convert_point_to_view =
+ label_button_convert_point_to_view;
+ GetStruct()->base.base.convert_point_from_view =
+ label_button_convert_point_from_view;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefLabelButtonCppToC::~CefLabelButtonCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefLabelButton>
+CefCppToCRefCounted<CefLabelButtonCppToC, CefLabelButton, cef_label_button_t>::
+ UnwrapDerived(CefWrapperType type, cef_label_button_t* s) {
+ if (type == WT_MENU_BUTTON) {
+ return CefMenuButtonCppToC::Unwrap(reinterpret_cast<cef_menu_button_t*>(s));
+ }
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefLabelButtonCppToC,
+ CefLabelButton,
+ cef_label_button_t>::kWrapperType =
+ WT_LABEL_BUTTON;
diff --git a/libcef_dll/cpptoc/views/label_button_cpptoc.h b/libcef_dll/cpptoc/views/label_button_cpptoc.h
new file mode 100644
index 00000000..dad5d895
--- /dev/null
+++ b/libcef_dll/cpptoc/views/label_button_cpptoc.h
@@ -0,0 +1,39 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=8e86fa292ee6e5debd2525e71eaa3ae8e42c8e55$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_VIEWS_LABEL_BUTTON_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_VIEWS_LABEL_BUTTON_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/views/cef_label_button_capi.h"
+#include "include/capi/views/cef_menu_button_capi.h"
+#include "include/views/cef_label_button.h"
+#include "include/views/cef_menu_button.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefLabelButtonCppToC : public CefCppToCRefCounted<CefLabelButtonCppToC,
+ CefLabelButton,
+ cef_label_button_t> {
+ public:
+ CefLabelButtonCppToC();
+ virtual ~CefLabelButtonCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_VIEWS_LABEL_BUTTON_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/views/layout_cpptoc.cc b/libcef_dll/cpptoc/views/layout_cpptoc.cc
new file mode 100644
index 00000000..15f4a838
--- /dev/null
+++ b/libcef_dll/cpptoc/views/layout_cpptoc.cc
@@ -0,0 +1,110 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=e8d8216333b81676768e82762ec1da35a19e62f8$
+//
+
+#include "libcef_dll/cpptoc/views/layout_cpptoc.h"
+#include "libcef_dll/cpptoc/views/box_layout_cpptoc.h"
+#include "libcef_dll/cpptoc/views/fill_layout_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+cef_box_layout_t* CEF_CALLBACK
+layout_as_box_layout(struct _cef_layout_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefBoxLayout> _retval = CefLayoutCppToC::Get(self)->AsBoxLayout();
+
+ // Return type: refptr_same
+ return CefBoxLayoutCppToC::Wrap(_retval);
+}
+
+cef_fill_layout_t* CEF_CALLBACK
+layout_as_fill_layout(struct _cef_layout_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefFillLayout> _retval = CefLayoutCppToC::Get(self)->AsFillLayout();
+
+ // Return type: refptr_same
+ return CefFillLayoutCppToC::Wrap(_retval);
+}
+
+int CEF_CALLBACK layout_is_valid(struct _cef_layout_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefLayoutCppToC::Get(self)->IsValid();
+
+ // Return type: bool
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefLayoutCppToC::CefLayoutCppToC() {
+ GetStruct()->as_box_layout = layout_as_box_layout;
+ GetStruct()->as_fill_layout = layout_as_fill_layout;
+ GetStruct()->is_valid = layout_is_valid;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefLayoutCppToC::~CefLayoutCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefLayout>
+CefCppToCRefCounted<CefLayoutCppToC, CefLayout, cef_layout_t>::UnwrapDerived(
+ CefWrapperType type,
+ cef_layout_t* s) {
+ if (type == WT_BOX_LAYOUT) {
+ return CefBoxLayoutCppToC::Unwrap(reinterpret_cast<cef_box_layout_t*>(s));
+ }
+ if (type == WT_FILL_LAYOUT) {
+ return CefFillLayoutCppToC::Unwrap(reinterpret_cast<cef_fill_layout_t*>(s));
+ }
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefLayoutCppToC, CefLayout, cef_layout_t>::
+ kWrapperType = WT_LAYOUT;
diff --git a/libcef_dll/cpptoc/views/layout_cpptoc.h b/libcef_dll/cpptoc/views/layout_cpptoc.h
new file mode 100644
index 00000000..76c9930e
--- /dev/null
+++ b/libcef_dll/cpptoc/views/layout_cpptoc.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=d0adda3ed7bbb825b0c9959960f832d23f75ccdc$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_VIEWS_LAYOUT_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_VIEWS_LAYOUT_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/views/cef_box_layout_capi.h"
+#include "include/capi/views/cef_fill_layout_capi.h"
+#include "include/capi/views/cef_layout_capi.h"
+#include "include/views/cef_box_layout.h"
+#include "include/views/cef_fill_layout.h"
+#include "include/views/cef_layout.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefLayoutCppToC
+ : public CefCppToCRefCounted<CefLayoutCppToC, CefLayout, cef_layout_t> {
+ public:
+ CefLayoutCppToC();
+ virtual ~CefLayoutCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_VIEWS_LAYOUT_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/views/menu_button_cpptoc.cc b/libcef_dll/cpptoc/views/menu_button_cpptoc.cc
new file mode 100644
index 00000000..7c034a07
--- /dev/null
+++ b/libcef_dll/cpptoc/views/menu_button_cpptoc.cc
@@ -0,0 +1,1604 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=8a0e747873df46bb39ec65538eb0d6b4f1b04327$
+//
+
+#include "libcef_dll/cpptoc/views/menu_button_cpptoc.h"
+#include "libcef_dll/cpptoc/image_cpptoc.h"
+#include "libcef_dll/cpptoc/menu_model_cpptoc.h"
+#include "libcef_dll/cpptoc/views/browser_view_cpptoc.h"
+#include "libcef_dll/cpptoc/views/button_cpptoc.h"
+#include "libcef_dll/cpptoc/views/label_button_cpptoc.h"
+#include "libcef_dll/cpptoc/views/panel_cpptoc.h"
+#include "libcef_dll/cpptoc/views/scroll_view_cpptoc.h"
+#include "libcef_dll/cpptoc/views/textfield_cpptoc.h"
+#include "libcef_dll/cpptoc/views/view_cpptoc.h"
+#include "libcef_dll/cpptoc/views/window_cpptoc.h"
+#include "libcef_dll/ctocpp/views/menu_button_delegate_ctocpp.h"
+#include "libcef_dll/ctocpp/views/view_delegate_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// GLOBAL FUNCTIONS - Body may be edited by hand.
+
+CEF_EXPORT cef_menu_button_t* cef_menu_button_create(
+ cef_menu_button_delegate_t* delegate,
+ const cef_string_t* text) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: delegate; type: refptr_diff
+ DCHECK(delegate);
+ if (!delegate) {
+ return NULL;
+ }
+ // Unverified params: text
+
+ // Execute
+ CefRefPtr<CefMenuButton> _retval = CefMenuButton::CreateMenuButton(
+ CefMenuButtonDelegateCToCpp::Wrap(delegate), CefString(text));
+
+ // Return type: refptr_same
+ return CefMenuButtonCppToC::Wrap(_retval);
+}
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK
+menu_button_show_menu(struct _cef_menu_button_t* self,
+ cef_menu_model_t* menu_model,
+ const cef_point_t* screen_point,
+ cef_menu_anchor_position_t anchor_position) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: menu_model; type: refptr_same
+ DCHECK(menu_model);
+ if (!menu_model) {
+ return;
+ }
+ // Verify param: screen_point; type: simple_byref_const
+ DCHECK(screen_point);
+ if (!screen_point) {
+ return;
+ }
+
+ // Translate param: screen_point; type: simple_byref_const
+ CefPoint screen_pointVal = screen_point ? *screen_point : CefPoint();
+
+ // Execute
+ CefMenuButtonCppToC::Get(self)->ShowMenu(
+ CefMenuModelCppToC::Unwrap(menu_model), screen_pointVal, anchor_position);
+}
+
+void CEF_CALLBACK menu_button_trigger_menu(struct _cef_menu_button_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefMenuButtonCppToC::Get(self)->TriggerMenu();
+}
+
+cef_menu_button_t* CEF_CALLBACK
+menu_button_as_menu_button(struct _cef_label_button_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefMenuButton> _retval =
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->AsMenuButton();
+
+ // Return type: refptr_same
+ return CefMenuButtonCppToC::Wrap(_retval);
+}
+
+void CEF_CALLBACK menu_button_set_text(struct _cef_label_button_t* self,
+ const cef_string_t* text) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: text; type: string_byref_const
+ DCHECK(text);
+ if (!text) {
+ return;
+ }
+
+ // Execute
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->SetText(CefString(text));
+}
+
+cef_string_userfree_t CEF_CALLBACK
+menu_button_get_text(struct _cef_label_button_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval =
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->GetText();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+void CEF_CALLBACK menu_button_set_image(struct _cef_label_button_t* self,
+ cef_button_state_t button_state,
+ cef_image_t* image) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Unverified params: image
+
+ // Execute
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->SetImage(button_state, CefImageCppToC::Unwrap(image));
+}
+
+cef_image_t* CEF_CALLBACK
+menu_button_get_image(struct _cef_label_button_t* self,
+ cef_button_state_t button_state) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefImage> _retval =
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->GetImage(button_state);
+
+ // Return type: refptr_same
+ return CefImageCppToC::Wrap(_retval);
+}
+
+void CEF_CALLBACK menu_button_set_text_color(struct _cef_label_button_t* self,
+ cef_button_state_t for_state,
+ cef_color_t color) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->SetTextColor(for_state, color);
+}
+
+void CEF_CALLBACK
+menu_button_set_enabled_text_colors(struct _cef_label_button_t* self,
+ cef_color_t color) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->SetEnabledTextColors(color);
+}
+
+void CEF_CALLBACK menu_button_set_font_list(struct _cef_label_button_t* self,
+ const cef_string_t* font_list) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: font_list; type: string_byref_const
+ DCHECK(font_list);
+ if (!font_list) {
+ return;
+ }
+
+ // Execute
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->SetFontList(CefString(font_list));
+}
+
+void CEF_CALLBACK
+menu_button_set_horizontal_alignment(struct _cef_label_button_t* self,
+ cef_horizontal_alignment_t alignment) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->SetHorizontalAlignment(alignment);
+}
+
+void CEF_CALLBACK menu_button_set_minimum_size(struct _cef_label_button_t* self,
+ const cef_size_t* size) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: size; type: simple_byref_const
+ DCHECK(size);
+ if (!size) {
+ return;
+ }
+
+ // Translate param: size; type: simple_byref_const
+ CefSize sizeVal = size ? *size : CefSize();
+
+ // Execute
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->SetMinimumSize(sizeVal);
+}
+
+void CEF_CALLBACK menu_button_set_maximum_size(struct _cef_label_button_t* self,
+ const cef_size_t* size) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: size; type: simple_byref_const
+ DCHECK(size);
+ if (!size) {
+ return;
+ }
+
+ // Translate param: size; type: simple_byref_const
+ CefSize sizeVal = size ? *size : CefSize();
+
+ // Execute
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->SetMaximumSize(sizeVal);
+}
+
+cef_label_button_t* CEF_CALLBACK
+menu_button_as_label_button(struct _cef_button_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefLabelButton> _retval =
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->AsLabelButton();
+
+ // Return type: refptr_same
+ return CefLabelButtonCppToC::Wrap(_retval);
+}
+
+void CEF_CALLBACK menu_button_set_state(struct _cef_button_t* self,
+ cef_button_state_t state) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->SetState(state);
+}
+
+cef_button_state_t CEF_CALLBACK
+menu_button_get_state(struct _cef_button_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CEF_BUTTON_STATE_NORMAL;
+ }
+
+ // Execute
+ cef_button_state_t _retval =
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->GetState();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK menu_button_set_ink_drop_enabled(struct _cef_button_t* self,
+ int enabled) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->SetInkDropEnabled(enabled ? true : false);
+}
+
+void CEF_CALLBACK
+menu_button_set_tooltip_text(struct _cef_button_t* self,
+ const cef_string_t* tooltip_text) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: tooltip_text; type: string_byref_const
+ DCHECK(tooltip_text);
+ if (!tooltip_text) {
+ return;
+ }
+
+ // Execute
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->SetTooltipText(CefString(tooltip_text));
+}
+
+void CEF_CALLBACK menu_button_set_accessible_name(struct _cef_button_t* self,
+ const cef_string_t* name) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: name; type: string_byref_const
+ DCHECK(name);
+ if (!name) {
+ return;
+ }
+
+ // Execute
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->SetAccessibleName(CefString(name));
+}
+
+cef_browser_view_t* CEF_CALLBACK
+menu_button_as_browser_view(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefBrowserView> _retval =
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->AsBrowserView();
+
+ // Return type: refptr_same
+ return CefBrowserViewCppToC::Wrap(_retval);
+}
+
+cef_button_t* CEF_CALLBACK menu_button_as_button(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefButton> _retval =
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->AsButton();
+
+ // Return type: refptr_same
+ return CefButtonCppToC::Wrap(_retval);
+}
+
+cef_panel_t* CEF_CALLBACK menu_button_as_panel(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefPanel> _retval =
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->AsPanel();
+
+ // Return type: refptr_same
+ return CefPanelCppToC::Wrap(_retval);
+}
+
+cef_scroll_view_t* CEF_CALLBACK
+menu_button_as_scroll_view(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefScrollView> _retval =
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->AsScrollView();
+
+ // Return type: refptr_same
+ return CefScrollViewCppToC::Wrap(_retval);
+}
+
+cef_textfield_t* CEF_CALLBACK
+menu_button_as_textfield(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefTextfield> _retval =
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->AsTextfield();
+
+ // Return type: refptr_same
+ return CefTextfieldCppToC::Wrap(_retval);
+}
+
+cef_string_userfree_t CEF_CALLBACK
+menu_button_get_type_string(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval =
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->GetTypeString();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_string_userfree_t CEF_CALLBACK
+menu_button_to_string(struct _cef_view_t* self, int include_children) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval =
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->ToString(include_children ? true : false);
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+int CEF_CALLBACK menu_button_is_valid(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->IsValid();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK menu_button_is_attached(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->IsAttached();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK menu_button_is_same(struct _cef_view_t* self,
+ struct _cef_view_t* that) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: that; type: refptr_same
+ DCHECK(that);
+ if (!that) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->IsSame(CefViewCppToC::Unwrap(that));
+
+ // Return type: bool
+ return _retval;
+}
+
+struct _cef_view_delegate_t* CEF_CALLBACK
+menu_button_get_delegate(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefViewDelegate> _retval =
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->GetDelegate();
+
+ // Return type: refptr_diff
+ return CefViewDelegateCToCpp::Unwrap(_retval);
+}
+
+struct _cef_window_t* CEF_CALLBACK
+menu_button_get_window(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefWindow> _retval =
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->GetWindow();
+
+ // Return type: refptr_same
+ return CefWindowCppToC::Wrap(_retval);
+}
+
+int CEF_CALLBACK menu_button_get_id(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval =
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->GetID();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK menu_button_set_id(struct _cef_view_t* self, int id) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->SetID(id);
+}
+
+int CEF_CALLBACK menu_button_get_group_id(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval =
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->GetGroupID();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK menu_button_set_group_id(struct _cef_view_t* self,
+ int group_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->SetGroupID(group_id);
+}
+
+struct _cef_view_t* CEF_CALLBACK
+menu_button_get_parent_view(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefView> _retval =
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->GetParentView();
+
+ // Return type: refptr_same
+ return CefViewCppToC::Wrap(_retval);
+}
+
+struct _cef_view_t* CEF_CALLBACK
+menu_button_get_view_for_id(struct _cef_view_t* self, int id) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefView> _retval =
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->GetViewForID(id);
+
+ // Return type: refptr_same
+ return CefViewCppToC::Wrap(_retval);
+}
+
+void CEF_CALLBACK menu_button_set_bounds(struct _cef_view_t* self,
+ const cef_rect_t* bounds) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: bounds; type: simple_byref_const
+ DCHECK(bounds);
+ if (!bounds) {
+ return;
+ }
+
+ // Translate param: bounds; type: simple_byref_const
+ CefRect boundsVal = bounds ? *bounds : CefRect();
+
+ // Execute
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->SetBounds(boundsVal);
+}
+
+cef_rect_t CEF_CALLBACK menu_button_get_bounds(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefRect();
+ }
+
+ // Execute
+ cef_rect_t _retval =
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->GetBounds();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_rect_t CEF_CALLBACK
+menu_button_get_bounds_in_screen(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefRect();
+ }
+
+ // Execute
+ cef_rect_t _retval =
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->GetBoundsInScreen();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK menu_button_set_size(struct _cef_view_t* self,
+ const cef_size_t* size) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: size; type: simple_byref_const
+ DCHECK(size);
+ if (!size) {
+ return;
+ }
+
+ // Translate param: size; type: simple_byref_const
+ CefSize sizeVal = size ? *size : CefSize();
+
+ // Execute
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->SetSize(sizeVal);
+}
+
+cef_size_t CEF_CALLBACK menu_button_get_size(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval =
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->GetSize();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK menu_button_set_position(struct _cef_view_t* self,
+ const cef_point_t* position) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: position; type: simple_byref_const
+ DCHECK(position);
+ if (!position) {
+ return;
+ }
+
+ // Translate param: position; type: simple_byref_const
+ CefPoint positionVal = position ? *position : CefPoint();
+
+ // Execute
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->SetPosition(positionVal);
+}
+
+cef_point_t CEF_CALLBACK menu_button_get_position(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefPoint();
+ }
+
+ // Execute
+ cef_point_t _retval =
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->GetPosition();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK menu_button_set_insets(struct _cef_view_t* self,
+ const cef_insets_t* insets) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: insets; type: simple_byref_const
+ DCHECK(insets);
+ if (!insets) {
+ return;
+ }
+
+ // Translate param: insets; type: simple_byref_const
+ CefInsets insetsVal = insets ? *insets : CefInsets();
+
+ // Execute
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->SetInsets(insetsVal);
+}
+
+cef_insets_t CEF_CALLBACK menu_button_get_insets(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefInsets();
+ }
+
+ // Execute
+ cef_insets_t _retval =
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->GetInsets();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_size_t CEF_CALLBACK
+menu_button_get_preferred_size(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval =
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->GetPreferredSize();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK menu_button_size_to_preferred_size(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->SizeToPreferredSize();
+}
+
+cef_size_t CEF_CALLBACK menu_button_get_minimum_size(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval =
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->GetMinimumSize();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_size_t CEF_CALLBACK menu_button_get_maximum_size(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval =
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->GetMaximumSize();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK menu_button_get_height_for_width(struct _cef_view_t* self,
+ int width) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval =
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->GetHeightForWidth(width);
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK menu_button_invalidate_layout(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->InvalidateLayout();
+}
+
+void CEF_CALLBACK menu_button_set_visible(struct _cef_view_t* self,
+ int visible) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->SetVisible(visible ? true : false);
+}
+
+int CEF_CALLBACK menu_button_is_visible(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->IsVisible();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK menu_button_is_drawn(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->IsDrawn();
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK menu_button_set_enabled(struct _cef_view_t* self,
+ int enabled) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->SetEnabled(enabled ? true : false);
+}
+
+int CEF_CALLBACK menu_button_is_enabled(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->IsEnabled();
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK menu_button_set_focusable(struct _cef_view_t* self,
+ int focusable) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->SetFocusable(focusable ? true : false);
+}
+
+int CEF_CALLBACK menu_button_is_focusable(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->IsFocusable();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+menu_button_is_accessibility_focusable(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->IsAccessibilityFocusable();
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK menu_button_request_focus(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->RequestFocus();
+}
+
+void CEF_CALLBACK menu_button_set_background_color(struct _cef_view_t* self,
+ cef_color_t color) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->SetBackgroundColor(color);
+}
+
+cef_color_t CEF_CALLBACK
+menu_button_get_background_color(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ cef_color_t _retval =
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->GetBackgroundColor();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK menu_button_convert_point_to_screen(struct _cef_view_t* self,
+ cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: point; type: simple_byref
+ DCHECK(point);
+ if (!point) {
+ return 0;
+ }
+
+ // Translate param: point; type: simple_byref
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ bool _retval =
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->ConvertPointToScreen(pointVal);
+
+ // Restore param: point; type: simple_byref
+ if (point) {
+ *point = pointVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK menu_button_convert_point_from_screen(struct _cef_view_t* self,
+ cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: point; type: simple_byref
+ DCHECK(point);
+ if (!point) {
+ return 0;
+ }
+
+ // Translate param: point; type: simple_byref
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ bool _retval =
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->ConvertPointFromScreen(pointVal);
+
+ // Restore param: point; type: simple_byref
+ if (point) {
+ *point = pointVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK menu_button_convert_point_to_window(struct _cef_view_t* self,
+ cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: point; type: simple_byref
+ DCHECK(point);
+ if (!point) {
+ return 0;
+ }
+
+ // Translate param: point; type: simple_byref
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ bool _retval =
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->ConvertPointToWindow(pointVal);
+
+ // Restore param: point; type: simple_byref
+ if (point) {
+ *point = pointVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK menu_button_convert_point_from_window(struct _cef_view_t* self,
+ cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: point; type: simple_byref
+ DCHECK(point);
+ if (!point) {
+ return 0;
+ }
+
+ // Translate param: point; type: simple_byref
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ bool _retval =
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->ConvertPointFromWindow(pointVal);
+
+ // Restore param: point; type: simple_byref
+ if (point) {
+ *point = pointVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK menu_button_convert_point_to_view(struct _cef_view_t* self,
+ struct _cef_view_t* view,
+ cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: view; type: refptr_same
+ DCHECK(view);
+ if (!view) {
+ return 0;
+ }
+ // Verify param: point; type: simple_byref
+ DCHECK(point);
+ if (!point) {
+ return 0;
+ }
+
+ // Translate param: point; type: simple_byref
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ bool _retval =
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->ConvertPointToView(CefViewCppToC::Unwrap(view), pointVal);
+
+ // Restore param: point; type: simple_byref
+ if (point) {
+ *point = pointVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK menu_button_convert_point_from_view(struct _cef_view_t* self,
+ struct _cef_view_t* view,
+ cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: view; type: refptr_same
+ DCHECK(view);
+ if (!view) {
+ return 0;
+ }
+ // Verify param: point; type: simple_byref
+ DCHECK(point);
+ if (!point) {
+ return 0;
+ }
+
+ // Translate param: point; type: simple_byref
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ bool _retval =
+ CefMenuButtonCppToC::Get(reinterpret_cast<cef_menu_button_t*>(self))
+ ->ConvertPointFromView(CefViewCppToC::Unwrap(view), pointVal);
+
+ // Restore param: point; type: simple_byref
+ if (point) {
+ *point = pointVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefMenuButtonCppToC::CefMenuButtonCppToC() {
+ GetStruct()->show_menu = menu_button_show_menu;
+ GetStruct()->trigger_menu = menu_button_trigger_menu;
+ GetStruct()->base.as_menu_button = menu_button_as_menu_button;
+ GetStruct()->base.set_text = menu_button_set_text;
+ GetStruct()->base.get_text = menu_button_get_text;
+ GetStruct()->base.set_image = menu_button_set_image;
+ GetStruct()->base.get_image = menu_button_get_image;
+ GetStruct()->base.set_text_color = menu_button_set_text_color;
+ GetStruct()->base.set_enabled_text_colors =
+ menu_button_set_enabled_text_colors;
+ GetStruct()->base.set_font_list = menu_button_set_font_list;
+ GetStruct()->base.set_horizontal_alignment =
+ menu_button_set_horizontal_alignment;
+ GetStruct()->base.set_minimum_size = menu_button_set_minimum_size;
+ GetStruct()->base.set_maximum_size = menu_button_set_maximum_size;
+ GetStruct()->base.base.as_label_button = menu_button_as_label_button;
+ GetStruct()->base.base.set_state = menu_button_set_state;
+ GetStruct()->base.base.get_state = menu_button_get_state;
+ GetStruct()->base.base.set_ink_drop_enabled =
+ menu_button_set_ink_drop_enabled;
+ GetStruct()->base.base.set_tooltip_text = menu_button_set_tooltip_text;
+ GetStruct()->base.base.set_accessible_name = menu_button_set_accessible_name;
+ GetStruct()->base.base.base.as_browser_view = menu_button_as_browser_view;
+ GetStruct()->base.base.base.as_button = menu_button_as_button;
+ GetStruct()->base.base.base.as_panel = menu_button_as_panel;
+ GetStruct()->base.base.base.as_scroll_view = menu_button_as_scroll_view;
+ GetStruct()->base.base.base.as_textfield = menu_button_as_textfield;
+ GetStruct()->base.base.base.get_type_string = menu_button_get_type_string;
+ GetStruct()->base.base.base.to_string = menu_button_to_string;
+ GetStruct()->base.base.base.is_valid = menu_button_is_valid;
+ GetStruct()->base.base.base.is_attached = menu_button_is_attached;
+ GetStruct()->base.base.base.is_same = menu_button_is_same;
+ GetStruct()->base.base.base.get_delegate = menu_button_get_delegate;
+ GetStruct()->base.base.base.get_window = menu_button_get_window;
+ GetStruct()->base.base.base.get_id = menu_button_get_id;
+ GetStruct()->base.base.base.set_id = menu_button_set_id;
+ GetStruct()->base.base.base.get_group_id = menu_button_get_group_id;
+ GetStruct()->base.base.base.set_group_id = menu_button_set_group_id;
+ GetStruct()->base.base.base.get_parent_view = menu_button_get_parent_view;
+ GetStruct()->base.base.base.get_view_for_id = menu_button_get_view_for_id;
+ GetStruct()->base.base.base.set_bounds = menu_button_set_bounds;
+ GetStruct()->base.base.base.get_bounds = menu_button_get_bounds;
+ GetStruct()->base.base.base.get_bounds_in_screen =
+ menu_button_get_bounds_in_screen;
+ GetStruct()->base.base.base.set_size = menu_button_set_size;
+ GetStruct()->base.base.base.get_size = menu_button_get_size;
+ GetStruct()->base.base.base.set_position = menu_button_set_position;
+ GetStruct()->base.base.base.get_position = menu_button_get_position;
+ GetStruct()->base.base.base.set_insets = menu_button_set_insets;
+ GetStruct()->base.base.base.get_insets = menu_button_get_insets;
+ GetStruct()->base.base.base.get_preferred_size =
+ menu_button_get_preferred_size;
+ GetStruct()->base.base.base.size_to_preferred_size =
+ menu_button_size_to_preferred_size;
+ GetStruct()->base.base.base.get_minimum_size = menu_button_get_minimum_size;
+ GetStruct()->base.base.base.get_maximum_size = menu_button_get_maximum_size;
+ GetStruct()->base.base.base.get_height_for_width =
+ menu_button_get_height_for_width;
+ GetStruct()->base.base.base.invalidate_layout = menu_button_invalidate_layout;
+ GetStruct()->base.base.base.set_visible = menu_button_set_visible;
+ GetStruct()->base.base.base.is_visible = menu_button_is_visible;
+ GetStruct()->base.base.base.is_drawn = menu_button_is_drawn;
+ GetStruct()->base.base.base.set_enabled = menu_button_set_enabled;
+ GetStruct()->base.base.base.is_enabled = menu_button_is_enabled;
+ GetStruct()->base.base.base.set_focusable = menu_button_set_focusable;
+ GetStruct()->base.base.base.is_focusable = menu_button_is_focusable;
+ GetStruct()->base.base.base.is_accessibility_focusable =
+ menu_button_is_accessibility_focusable;
+ GetStruct()->base.base.base.request_focus = menu_button_request_focus;
+ GetStruct()->base.base.base.set_background_color =
+ menu_button_set_background_color;
+ GetStruct()->base.base.base.get_background_color =
+ menu_button_get_background_color;
+ GetStruct()->base.base.base.convert_point_to_screen =
+ menu_button_convert_point_to_screen;
+ GetStruct()->base.base.base.convert_point_from_screen =
+ menu_button_convert_point_from_screen;
+ GetStruct()->base.base.base.convert_point_to_window =
+ menu_button_convert_point_to_window;
+ GetStruct()->base.base.base.convert_point_from_window =
+ menu_button_convert_point_from_window;
+ GetStruct()->base.base.base.convert_point_to_view =
+ menu_button_convert_point_to_view;
+ GetStruct()->base.base.base.convert_point_from_view =
+ menu_button_convert_point_from_view;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefMenuButtonCppToC::~CefMenuButtonCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefMenuButton>
+CefCppToCRefCounted<CefMenuButtonCppToC, CefMenuButton, cef_menu_button_t>::
+ UnwrapDerived(CefWrapperType type, cef_menu_button_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefMenuButtonCppToC,
+ CefMenuButton,
+ cef_menu_button_t>::kWrapperType =
+ WT_MENU_BUTTON;
diff --git a/libcef_dll/cpptoc/views/menu_button_cpptoc.h b/libcef_dll/cpptoc/views/menu_button_cpptoc.h
new file mode 100644
index 00000000..52f93e09
--- /dev/null
+++ b/libcef_dll/cpptoc/views/menu_button_cpptoc.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=f2f44594e4cbcb3ef1ee3eb39d3d498f7a6cafbc$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_VIEWS_MENU_BUTTON_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_VIEWS_MENU_BUTTON_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/views/cef_menu_button_capi.h"
+#include "include/views/cef_menu_button.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefMenuButtonCppToC : public CefCppToCRefCounted<CefMenuButtonCppToC,
+ CefMenuButton,
+ cef_menu_button_t> {
+ public:
+ CefMenuButtonCppToC();
+ virtual ~CefMenuButtonCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_VIEWS_MENU_BUTTON_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/views/menu_button_delegate_cpptoc.cc b/libcef_dll/cpptoc/views/menu_button_delegate_cpptoc.cc
new file mode 100644
index 00000000..c2fbd62d
--- /dev/null
+++ b/libcef_dll/cpptoc/views/menu_button_delegate_cpptoc.cc
@@ -0,0 +1,429 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=9758823653e71b6f40a07d1ccf051dd10e92b5b5$
+//
+
+#include "libcef_dll/cpptoc/views/menu_button_delegate_cpptoc.h"
+#include "libcef_dll/ctocpp/views/button_ctocpp.h"
+#include "libcef_dll/ctocpp/views/menu_button_ctocpp.h"
+#include "libcef_dll/ctocpp/views/menu_button_pressed_lock_ctocpp.h"
+#include "libcef_dll/ctocpp/views/view_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK menu_button_delegate_on_menu_button_pressed(
+ struct _cef_menu_button_delegate_t* self,
+ cef_menu_button_t* menu_button,
+ const cef_point_t* screen_point,
+ cef_menu_button_pressed_lock_t* button_pressed_lock) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: menu_button; type: refptr_diff
+ DCHECK(menu_button);
+ if (!menu_button) {
+ return;
+ }
+ // Verify param: screen_point; type: simple_byref_const
+ DCHECK(screen_point);
+ if (!screen_point) {
+ return;
+ }
+ // Verify param: button_pressed_lock; type: refptr_diff
+ DCHECK(button_pressed_lock);
+ if (!button_pressed_lock) {
+ return;
+ }
+
+ // Translate param: screen_point; type: simple_byref_const
+ CefPoint screen_pointVal = screen_point ? *screen_point : CefPoint();
+
+ // Execute
+ CefMenuButtonDelegateCppToC::Get(self)->OnMenuButtonPressed(
+ CefMenuButtonCToCpp::Wrap(menu_button), screen_pointVal,
+ CefMenuButtonPressedLockCToCpp::Wrap(button_pressed_lock));
+}
+
+void CEF_CALLBACK
+menu_button_delegate_on_button_pressed(struct _cef_button_delegate_t* self,
+ cef_button_t* button) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: button; type: refptr_diff
+ DCHECK(button);
+ if (!button) {
+ return;
+ }
+
+ // Execute
+ CefMenuButtonDelegateCppToC::Get(
+ reinterpret_cast<cef_menu_button_delegate_t*>(self))
+ ->OnButtonPressed(CefButtonCToCpp::Wrap(button));
+}
+
+void CEF_CALLBACK menu_button_delegate_on_button_state_changed(
+ struct _cef_button_delegate_t* self,
+ cef_button_t* button) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: button; type: refptr_diff
+ DCHECK(button);
+ if (!button) {
+ return;
+ }
+
+ // Execute
+ CefMenuButtonDelegateCppToC::Get(
+ reinterpret_cast<cef_menu_button_delegate_t*>(self))
+ ->OnButtonStateChanged(CefButtonCToCpp::Wrap(button));
+}
+
+cef_size_t CEF_CALLBACK
+menu_button_delegate_get_preferred_size(struct _cef_view_delegate_t* self,
+ cef_view_t* view) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval = CefMenuButtonDelegateCppToC::Get(
+ reinterpret_cast<cef_menu_button_delegate_t*>(self))
+ ->GetPreferredSize(CefViewCToCpp::Wrap(view));
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_size_t CEF_CALLBACK
+menu_button_delegate_get_minimum_size(struct _cef_view_delegate_t* self,
+ cef_view_t* view) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval = CefMenuButtonDelegateCppToC::Get(
+ reinterpret_cast<cef_menu_button_delegate_t*>(self))
+ ->GetMinimumSize(CefViewCToCpp::Wrap(view));
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_size_t CEF_CALLBACK
+menu_button_delegate_get_maximum_size(struct _cef_view_delegate_t* self,
+ cef_view_t* view) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval = CefMenuButtonDelegateCppToC::Get(
+ reinterpret_cast<cef_menu_button_delegate_t*>(self))
+ ->GetMaximumSize(CefViewCToCpp::Wrap(view));
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK
+menu_button_delegate_get_height_for_width(struct _cef_view_delegate_t* self,
+ cef_view_t* view,
+ int width) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefMenuButtonDelegateCppToC::Get(
+ reinterpret_cast<cef_menu_button_delegate_t*>(self))
+ ->GetHeightForWidth(CefViewCToCpp::Wrap(view), width);
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK
+menu_button_delegate_on_parent_view_changed(struct _cef_view_delegate_t* self,
+ cef_view_t* view,
+ int added,
+ cef_view_t* parent) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return;
+ }
+ // Verify param: parent; type: refptr_diff
+ DCHECK(parent);
+ if (!parent) {
+ return;
+ }
+
+ // Execute
+ CefMenuButtonDelegateCppToC::Get(
+ reinterpret_cast<cef_menu_button_delegate_t*>(self))
+ ->OnParentViewChanged(CefViewCToCpp::Wrap(view), added ? true : false,
+ CefViewCToCpp::Wrap(parent));
+}
+
+void CEF_CALLBACK
+menu_button_delegate_on_child_view_changed(struct _cef_view_delegate_t* self,
+ cef_view_t* view,
+ int added,
+ cef_view_t* child) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return;
+ }
+ // Verify param: child; type: refptr_diff
+ DCHECK(child);
+ if (!child) {
+ return;
+ }
+
+ // Execute
+ CefMenuButtonDelegateCppToC::Get(
+ reinterpret_cast<cef_menu_button_delegate_t*>(self))
+ ->OnChildViewChanged(CefViewCToCpp::Wrap(view), added ? true : false,
+ CefViewCToCpp::Wrap(child));
+}
+
+void CEF_CALLBACK
+menu_button_delegate_on_window_changed(struct _cef_view_delegate_t* self,
+ cef_view_t* view,
+ int added) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return;
+ }
+
+ // Execute
+ CefMenuButtonDelegateCppToC::Get(
+ reinterpret_cast<cef_menu_button_delegate_t*>(self))
+ ->OnWindowChanged(CefViewCToCpp::Wrap(view), added ? true : false);
+}
+
+void CEF_CALLBACK
+menu_button_delegate_on_layout_changed(struct _cef_view_delegate_t* self,
+ cef_view_t* view,
+ const cef_rect_t* new_bounds) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return;
+ }
+ // Verify param: new_bounds; type: simple_byref_const
+ DCHECK(new_bounds);
+ if (!new_bounds) {
+ return;
+ }
+
+ // Translate param: new_bounds; type: simple_byref_const
+ CefRect new_boundsVal = new_bounds ? *new_bounds : CefRect();
+
+ // Execute
+ CefMenuButtonDelegateCppToC::Get(
+ reinterpret_cast<cef_menu_button_delegate_t*>(self))
+ ->OnLayoutChanged(CefViewCToCpp::Wrap(view), new_boundsVal);
+}
+
+void CEF_CALLBACK
+menu_button_delegate_on_focus(struct _cef_view_delegate_t* self,
+ cef_view_t* view) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return;
+ }
+
+ // Execute
+ CefMenuButtonDelegateCppToC::Get(
+ reinterpret_cast<cef_menu_button_delegate_t*>(self))
+ ->OnFocus(CefViewCToCpp::Wrap(view));
+}
+
+void CEF_CALLBACK
+menu_button_delegate_on_blur(struct _cef_view_delegate_t* self,
+ cef_view_t* view) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return;
+ }
+
+ // Execute
+ CefMenuButtonDelegateCppToC::Get(
+ reinterpret_cast<cef_menu_button_delegate_t*>(self))
+ ->OnBlur(CefViewCToCpp::Wrap(view));
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefMenuButtonDelegateCppToC::CefMenuButtonDelegateCppToC() {
+ GetStruct()->on_menu_button_pressed =
+ menu_button_delegate_on_menu_button_pressed;
+ GetStruct()->base.on_button_pressed = menu_button_delegate_on_button_pressed;
+ GetStruct()->base.on_button_state_changed =
+ menu_button_delegate_on_button_state_changed;
+ GetStruct()->base.base.get_preferred_size =
+ menu_button_delegate_get_preferred_size;
+ GetStruct()->base.base.get_minimum_size =
+ menu_button_delegate_get_minimum_size;
+ GetStruct()->base.base.get_maximum_size =
+ menu_button_delegate_get_maximum_size;
+ GetStruct()->base.base.get_height_for_width =
+ menu_button_delegate_get_height_for_width;
+ GetStruct()->base.base.on_parent_view_changed =
+ menu_button_delegate_on_parent_view_changed;
+ GetStruct()->base.base.on_child_view_changed =
+ menu_button_delegate_on_child_view_changed;
+ GetStruct()->base.base.on_window_changed =
+ menu_button_delegate_on_window_changed;
+ GetStruct()->base.base.on_layout_changed =
+ menu_button_delegate_on_layout_changed;
+ GetStruct()->base.base.on_focus = menu_button_delegate_on_focus;
+ GetStruct()->base.base.on_blur = menu_button_delegate_on_blur;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefMenuButtonDelegateCppToC::~CefMenuButtonDelegateCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefMenuButtonDelegate> CefCppToCRefCounted<
+ CefMenuButtonDelegateCppToC,
+ CefMenuButtonDelegate,
+ cef_menu_button_delegate_t>::UnwrapDerived(CefWrapperType type,
+ cef_menu_button_delegate_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefMenuButtonDelegateCppToC,
+ CefMenuButtonDelegate,
+ cef_menu_button_delegate_t>::kWrapperType =
+ WT_MENU_BUTTON_DELEGATE;
diff --git a/libcef_dll/cpptoc/views/menu_button_delegate_cpptoc.h b/libcef_dll/cpptoc/views/menu_button_delegate_cpptoc.h
new file mode 100644
index 00000000..5f70f5a4
--- /dev/null
+++ b/libcef_dll/cpptoc/views/menu_button_delegate_cpptoc.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=9178b58c1b03965fc20636f3efd97c2385618574$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_VIEWS_MENU_BUTTON_DELEGATE_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_VIEWS_MENU_BUTTON_DELEGATE_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/views/cef_menu_button_capi.h"
+#include "include/capi/views/cef_menu_button_delegate_capi.h"
+#include "include/views/cef_menu_button.h"
+#include "include/views/cef_menu_button_delegate.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefMenuButtonDelegateCppToC
+ : public CefCppToCRefCounted<CefMenuButtonDelegateCppToC,
+ CefMenuButtonDelegate,
+ cef_menu_button_delegate_t> {
+ public:
+ CefMenuButtonDelegateCppToC();
+ virtual ~CefMenuButtonDelegateCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_VIEWS_MENU_BUTTON_DELEGATE_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/views/menu_button_pressed_lock_cpptoc.cc b/libcef_dll/cpptoc/views/menu_button_pressed_lock_cpptoc.cc
new file mode 100644
index 00000000..c3d85d20
--- /dev/null
+++ b/libcef_dll/cpptoc/views/menu_button_pressed_lock_cpptoc.cc
@@ -0,0 +1,43 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=2dc6b6ba5f4b65f25877aa56083d0e6dea42e7ae$
+//
+
+#include "libcef_dll/cpptoc/views/menu_button_pressed_lock_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefMenuButtonPressedLockCppToC::CefMenuButtonPressedLockCppToC() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefMenuButtonPressedLockCppToC::~CefMenuButtonPressedLockCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefMenuButtonPressedLock>
+CefCppToCRefCounted<CefMenuButtonPressedLockCppToC,
+ CefMenuButtonPressedLock,
+ cef_menu_button_pressed_lock_t>::
+ UnwrapDerived(CefWrapperType type, cef_menu_button_pressed_lock_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCppToCRefCounted<CefMenuButtonPressedLockCppToC,
+ CefMenuButtonPressedLock,
+ cef_menu_button_pressed_lock_t>::kWrapperType =
+ WT_MENU_BUTTON_PRESSED_LOCK;
diff --git a/libcef_dll/cpptoc/views/menu_button_pressed_lock_cpptoc.h b/libcef_dll/cpptoc/views/menu_button_pressed_lock_cpptoc.h
new file mode 100644
index 00000000..79a8566e
--- /dev/null
+++ b/libcef_dll/cpptoc/views/menu_button_pressed_lock_cpptoc.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=5d7f30f1265294fc8617b444bd35bee3da172746$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_VIEWS_MENU_BUTTON_PRESSED_LOCK_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_VIEWS_MENU_BUTTON_PRESSED_LOCK_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/views/cef_menu_button_capi.h"
+#include "include/capi/views/cef_menu_button_delegate_capi.h"
+#include "include/views/cef_menu_button.h"
+#include "include/views/cef_menu_button_delegate.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefMenuButtonPressedLockCppToC
+ : public CefCppToCRefCounted<CefMenuButtonPressedLockCppToC,
+ CefMenuButtonPressedLock,
+ cef_menu_button_pressed_lock_t> {
+ public:
+ CefMenuButtonPressedLockCppToC();
+ virtual ~CefMenuButtonPressedLockCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_VIEWS_MENU_BUTTON_PRESSED_LOCK_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/views/overlay_controller_cpptoc.cc b/libcef_dll/cpptoc/views/overlay_controller_cpptoc.cc
new file mode 100644
index 00000000..2cedf76f
--- /dev/null
+++ b/libcef_dll/cpptoc/views/overlay_controller_cpptoc.cc
@@ -0,0 +1,440 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=8ebed0f097f98544037eeebfb9b2dbf21d579f03$
+//
+
+#include "libcef_dll/cpptoc/views/overlay_controller_cpptoc.h"
+#include "libcef_dll/cpptoc/views/view_cpptoc.h"
+#include "libcef_dll/cpptoc/views/window_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK
+overlay_controller_is_valid(struct _cef_overlay_controller_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefOverlayControllerCppToC::Get(self)->IsValid();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+overlay_controller_is_same(struct _cef_overlay_controller_t* self,
+ struct _cef_overlay_controller_t* that) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: that; type: refptr_same
+ DCHECK(that);
+ if (!that) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefOverlayControllerCppToC::Get(self)->IsSame(
+ CefOverlayControllerCppToC::Unwrap(that));
+
+ // Return type: bool
+ return _retval;
+}
+
+struct _cef_view_t* CEF_CALLBACK
+overlay_controller_get_contents_view(struct _cef_overlay_controller_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefView> _retval =
+ CefOverlayControllerCppToC::Get(self)->GetContentsView();
+
+ // Return type: refptr_same
+ return CefViewCppToC::Wrap(_retval);
+}
+
+struct _cef_window_t* CEF_CALLBACK
+overlay_controller_get_window(struct _cef_overlay_controller_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefWindow> _retval =
+ CefOverlayControllerCppToC::Get(self)->GetWindow();
+
+ // Return type: refptr_same
+ return CefWindowCppToC::Wrap(_retval);
+}
+
+cef_docking_mode_t CEF_CALLBACK
+overlay_controller_get_docking_mode(struct _cef_overlay_controller_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CEF_DOCKING_MODE_TOP_LEFT;
+ }
+
+ // Execute
+ cef_docking_mode_t _retval =
+ CefOverlayControllerCppToC::Get(self)->GetDockingMode();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK
+overlay_controller_destroy(struct _cef_overlay_controller_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefOverlayControllerCppToC::Get(self)->Destroy();
+}
+
+void CEF_CALLBACK
+overlay_controller_set_bounds(struct _cef_overlay_controller_t* self,
+ const cef_rect_t* bounds) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: bounds; type: simple_byref_const
+ DCHECK(bounds);
+ if (!bounds) {
+ return;
+ }
+
+ // Translate param: bounds; type: simple_byref_const
+ CefRect boundsVal = bounds ? *bounds : CefRect();
+
+ // Execute
+ CefOverlayControllerCppToC::Get(self)->SetBounds(boundsVal);
+}
+
+cef_rect_t CEF_CALLBACK
+overlay_controller_get_bounds(struct _cef_overlay_controller_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefRect();
+ }
+
+ // Execute
+ cef_rect_t _retval = CefOverlayControllerCppToC::Get(self)->GetBounds();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_rect_t CEF_CALLBACK overlay_controller_get_bounds_in_screen(
+ struct _cef_overlay_controller_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefRect();
+ }
+
+ // Execute
+ cef_rect_t _retval =
+ CefOverlayControllerCppToC::Get(self)->GetBoundsInScreen();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK
+overlay_controller_set_size(struct _cef_overlay_controller_t* self,
+ const cef_size_t* size) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: size; type: simple_byref_const
+ DCHECK(size);
+ if (!size) {
+ return;
+ }
+
+ // Translate param: size; type: simple_byref_const
+ CefSize sizeVal = size ? *size : CefSize();
+
+ // Execute
+ CefOverlayControllerCppToC::Get(self)->SetSize(sizeVal);
+}
+
+cef_size_t CEF_CALLBACK
+overlay_controller_get_size(struct _cef_overlay_controller_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval = CefOverlayControllerCppToC::Get(self)->GetSize();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK
+overlay_controller_set_position(struct _cef_overlay_controller_t* self,
+ const cef_point_t* position) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: position; type: simple_byref_const
+ DCHECK(position);
+ if (!position) {
+ return;
+ }
+
+ // Translate param: position; type: simple_byref_const
+ CefPoint positionVal = position ? *position : CefPoint();
+
+ // Execute
+ CefOverlayControllerCppToC::Get(self)->SetPosition(positionVal);
+}
+
+cef_point_t CEF_CALLBACK
+overlay_controller_get_position(struct _cef_overlay_controller_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefPoint();
+ }
+
+ // Execute
+ cef_point_t _retval = CefOverlayControllerCppToC::Get(self)->GetPosition();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK
+overlay_controller_set_insets(struct _cef_overlay_controller_t* self,
+ const cef_insets_t* insets) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: insets; type: simple_byref_const
+ DCHECK(insets);
+ if (!insets) {
+ return;
+ }
+
+ // Translate param: insets; type: simple_byref_const
+ CefInsets insetsVal = insets ? *insets : CefInsets();
+
+ // Execute
+ CefOverlayControllerCppToC::Get(self)->SetInsets(insetsVal);
+}
+
+cef_insets_t CEF_CALLBACK
+overlay_controller_get_insets(struct _cef_overlay_controller_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefInsets();
+ }
+
+ // Execute
+ cef_insets_t _retval = CefOverlayControllerCppToC::Get(self)->GetInsets();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK overlay_controller_size_to_preferred_size(
+ struct _cef_overlay_controller_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefOverlayControllerCppToC::Get(self)->SizeToPreferredSize();
+}
+
+void CEF_CALLBACK
+overlay_controller_set_visible(struct _cef_overlay_controller_t* self,
+ int visible) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefOverlayControllerCppToC::Get(self)->SetVisible(visible ? true : false);
+}
+
+int CEF_CALLBACK
+overlay_controller_is_visible(struct _cef_overlay_controller_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefOverlayControllerCppToC::Get(self)->IsVisible();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+overlay_controller_is_drawn(struct _cef_overlay_controller_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefOverlayControllerCppToC::Get(self)->IsDrawn();
+
+ // Return type: bool
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefOverlayControllerCppToC::CefOverlayControllerCppToC() {
+ GetStruct()->is_valid = overlay_controller_is_valid;
+ GetStruct()->is_same = overlay_controller_is_same;
+ GetStruct()->get_contents_view = overlay_controller_get_contents_view;
+ GetStruct()->get_window = overlay_controller_get_window;
+ GetStruct()->get_docking_mode = overlay_controller_get_docking_mode;
+ GetStruct()->destroy = overlay_controller_destroy;
+ GetStruct()->set_bounds = overlay_controller_set_bounds;
+ GetStruct()->get_bounds = overlay_controller_get_bounds;
+ GetStruct()->get_bounds_in_screen = overlay_controller_get_bounds_in_screen;
+ GetStruct()->set_size = overlay_controller_set_size;
+ GetStruct()->get_size = overlay_controller_get_size;
+ GetStruct()->set_position = overlay_controller_set_position;
+ GetStruct()->get_position = overlay_controller_get_position;
+ GetStruct()->set_insets = overlay_controller_set_insets;
+ GetStruct()->get_insets = overlay_controller_get_insets;
+ GetStruct()->size_to_preferred_size =
+ overlay_controller_size_to_preferred_size;
+ GetStruct()->set_visible = overlay_controller_set_visible;
+ GetStruct()->is_visible = overlay_controller_is_visible;
+ GetStruct()->is_drawn = overlay_controller_is_drawn;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefOverlayControllerCppToC::~CefOverlayControllerCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefOverlayController> CefCppToCRefCounted<
+ CefOverlayControllerCppToC,
+ CefOverlayController,
+ cef_overlay_controller_t>::UnwrapDerived(CefWrapperType type,
+ cef_overlay_controller_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefOverlayControllerCppToC,
+ CefOverlayController,
+ cef_overlay_controller_t>::kWrapperType =
+ WT_OVERLAY_CONTROLLER;
diff --git a/libcef_dll/cpptoc/views/overlay_controller_cpptoc.h b/libcef_dll/cpptoc/views/overlay_controller_cpptoc.h
new file mode 100644
index 00000000..b89f8b4b
--- /dev/null
+++ b/libcef_dll/cpptoc/views/overlay_controller_cpptoc.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=8d50609d2e79539752a8118f831e853b845892f4$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_VIEWS_OVERLAY_CONTROLLER_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_VIEWS_OVERLAY_CONTROLLER_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/views/cef_overlay_controller_capi.h"
+#include "include/capi/views/cef_view_capi.h"
+#include "include/capi/views/cef_window_capi.h"
+#include "include/views/cef_overlay_controller.h"
+#include "include/views/cef_view.h"
+#include "include/views/cef_window.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefOverlayControllerCppToC
+ : public CefCppToCRefCounted<CefOverlayControllerCppToC,
+ CefOverlayController,
+ cef_overlay_controller_t> {
+ public:
+ CefOverlayControllerCppToC();
+ virtual ~CefOverlayControllerCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_VIEWS_OVERLAY_CONTROLLER_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/views/panel_cpptoc.cc b/libcef_dll/cpptoc/views/panel_cpptoc.cc
new file mode 100644
index 00000000..0d744bae
--- /dev/null
+++ b/libcef_dll/cpptoc/views/panel_cpptoc.cc
@@ -0,0 +1,1388 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=bbcc06d178c7f86041c0b9f0887c67427a7381ff$
+//
+
+#include "libcef_dll/cpptoc/views/panel_cpptoc.h"
+#include "libcef_dll/cpptoc/views/box_layout_cpptoc.h"
+#include "libcef_dll/cpptoc/views/browser_view_cpptoc.h"
+#include "libcef_dll/cpptoc/views/button_cpptoc.h"
+#include "libcef_dll/cpptoc/views/fill_layout_cpptoc.h"
+#include "libcef_dll/cpptoc/views/layout_cpptoc.h"
+#include "libcef_dll/cpptoc/views/scroll_view_cpptoc.h"
+#include "libcef_dll/cpptoc/views/textfield_cpptoc.h"
+#include "libcef_dll/cpptoc/views/view_cpptoc.h"
+#include "libcef_dll/cpptoc/views/window_cpptoc.h"
+#include "libcef_dll/ctocpp/views/panel_delegate_ctocpp.h"
+#include "libcef_dll/ctocpp/views/view_delegate_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// GLOBAL FUNCTIONS - Body may be edited by hand.
+
+CEF_EXPORT cef_panel_t* cef_panel_create(cef_panel_delegate_t* delegate) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: delegate
+
+ // Execute
+ CefRefPtr<CefPanel> _retval =
+ CefPanel::CreatePanel(CefPanelDelegateCToCpp::Wrap(delegate));
+
+ // Return type: refptr_same
+ return CefPanelCppToC::Wrap(_retval);
+}
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+struct _cef_window_t* CEF_CALLBACK panel_as_window(struct _cef_panel_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefWindow> _retval = CefPanelCppToC::Get(self)->AsWindow();
+
+ // Return type: refptr_same
+ return CefWindowCppToC::Wrap(_retval);
+}
+
+cef_fill_layout_t* CEF_CALLBACK
+panel_set_to_fill_layout(struct _cef_panel_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefFillLayout> _retval =
+ CefPanelCppToC::Get(self)->SetToFillLayout();
+
+ // Return type: refptr_same
+ return CefFillLayoutCppToC::Wrap(_retval);
+}
+
+cef_box_layout_t* CEF_CALLBACK
+panel_set_to_box_layout(struct _cef_panel_t* self,
+ const cef_box_layout_settings_t* settings) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+ // Verify param: settings; type: simple_byref_const
+ DCHECK(settings);
+ if (!settings) {
+ return NULL;
+ }
+
+ // Translate param: settings; type: simple_byref_const
+ CefBoxLayoutSettings settingsVal =
+ settings ? *settings : CefBoxLayoutSettings();
+
+ // Execute
+ CefRefPtr<CefBoxLayout> _retval =
+ CefPanelCppToC::Get(self)->SetToBoxLayout(settingsVal);
+
+ // Return type: refptr_same
+ return CefBoxLayoutCppToC::Wrap(_retval);
+}
+
+cef_layout_t* CEF_CALLBACK panel_get_layout(struct _cef_panel_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefLayout> _retval = CefPanelCppToC::Get(self)->GetLayout();
+
+ // Return type: refptr_same
+ return CefLayoutCppToC::Wrap(_retval);
+}
+
+void CEF_CALLBACK panel_layout(struct _cef_panel_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefPanelCppToC::Get(self)->Layout();
+}
+
+void CEF_CALLBACK panel_add_child_view(struct _cef_panel_t* self,
+ struct _cef_view_t* view) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: view; type: refptr_same
+ DCHECK(view);
+ if (!view) {
+ return;
+ }
+
+ // Execute
+ CefPanelCppToC::Get(self)->AddChildView(CefViewCppToC::Unwrap(view));
+}
+
+void CEF_CALLBACK panel_add_child_view_at(struct _cef_panel_t* self,
+ struct _cef_view_t* view,
+ int index) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: view; type: refptr_same
+ DCHECK(view);
+ if (!view) {
+ return;
+ }
+ // Verify param: index; type: simple_byval
+ DCHECK_GE(index, 0);
+ if (index < 0) {
+ return;
+ }
+
+ // Execute
+ CefPanelCppToC::Get(self)->AddChildViewAt(CefViewCppToC::Unwrap(view), index);
+}
+
+void CEF_CALLBACK panel_reorder_child_view(struct _cef_panel_t* self,
+ struct _cef_view_t* view,
+ int index) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: view; type: refptr_same
+ DCHECK(view);
+ if (!view) {
+ return;
+ }
+
+ // Execute
+ CefPanelCppToC::Get(self)->ReorderChildView(CefViewCppToC::Unwrap(view),
+ index);
+}
+
+void CEF_CALLBACK panel_remove_child_view(struct _cef_panel_t* self,
+ struct _cef_view_t* view) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: view; type: refptr_same
+ DCHECK(view);
+ if (!view) {
+ return;
+ }
+
+ // Execute
+ CefPanelCppToC::Get(self)->RemoveChildView(CefViewCppToC::Unwrap(view));
+}
+
+void CEF_CALLBACK panel_remove_all_child_views(struct _cef_panel_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefPanelCppToC::Get(self)->RemoveAllChildViews();
+}
+
+size_t CEF_CALLBACK panel_get_child_view_count(struct _cef_panel_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ size_t _retval = CefPanelCppToC::Get(self)->GetChildViewCount();
+
+ // Return type: simple
+ return _retval;
+}
+
+struct _cef_view_t* CEF_CALLBACK
+panel_get_child_view_at(struct _cef_panel_t* self, int index) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+ // Verify param: index; type: simple_byval
+ DCHECK_GE(index, 0);
+ if (index < 0) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefView> _retval = CefPanelCppToC::Get(self)->GetChildViewAt(index);
+
+ // Return type: refptr_same
+ return CefViewCppToC::Wrap(_retval);
+}
+
+cef_browser_view_t* CEF_CALLBACK
+panel_as_browser_view(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefBrowserView> _retval =
+ CefPanelCppToC::Get(reinterpret_cast<cef_panel_t*>(self))
+ ->AsBrowserView();
+
+ // Return type: refptr_same
+ return CefBrowserViewCppToC::Wrap(_retval);
+}
+
+cef_button_t* CEF_CALLBACK panel_as_button(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefButton> _retval =
+ CefPanelCppToC::Get(reinterpret_cast<cef_panel_t*>(self))->AsButton();
+
+ // Return type: refptr_same
+ return CefButtonCppToC::Wrap(_retval);
+}
+
+cef_panel_t* CEF_CALLBACK panel_as_panel(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefPanel> _retval =
+ CefPanelCppToC::Get(reinterpret_cast<cef_panel_t*>(self))->AsPanel();
+
+ // Return type: refptr_same
+ return CefPanelCppToC::Wrap(_retval);
+}
+
+cef_scroll_view_t* CEF_CALLBACK panel_as_scroll_view(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefScrollView> _retval =
+ CefPanelCppToC::Get(reinterpret_cast<cef_panel_t*>(self))->AsScrollView();
+
+ // Return type: refptr_same
+ return CefScrollViewCppToC::Wrap(_retval);
+}
+
+cef_textfield_t* CEF_CALLBACK panel_as_textfield(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefTextfield> _retval =
+ CefPanelCppToC::Get(reinterpret_cast<cef_panel_t*>(self))->AsTextfield();
+
+ // Return type: refptr_same
+ return CefTextfieldCppToC::Wrap(_retval);
+}
+
+cef_string_userfree_t CEF_CALLBACK
+panel_get_type_string(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefPanelCppToC::Get(reinterpret_cast<cef_panel_t*>(self))
+ ->GetTypeString();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_string_userfree_t CEF_CALLBACK panel_to_string(struct _cef_view_t* self,
+ int include_children) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefPanelCppToC::Get(reinterpret_cast<cef_panel_t*>(self))
+ ->ToString(include_children ? true : false);
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+int CEF_CALLBACK panel_is_valid(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefPanelCppToC::Get(reinterpret_cast<cef_panel_t*>(self))->IsValid();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK panel_is_attached(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefPanelCppToC::Get(reinterpret_cast<cef_panel_t*>(self))->IsAttached();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK panel_is_same(struct _cef_view_t* self,
+ struct _cef_view_t* that) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: that; type: refptr_same
+ DCHECK(that);
+ if (!that) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefPanelCppToC::Get(reinterpret_cast<cef_panel_t*>(self))
+ ->IsSame(CefViewCppToC::Unwrap(that));
+
+ // Return type: bool
+ return _retval;
+}
+
+struct _cef_view_delegate_t* CEF_CALLBACK
+panel_get_delegate(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefViewDelegate> _retval =
+ CefPanelCppToC::Get(reinterpret_cast<cef_panel_t*>(self))->GetDelegate();
+
+ // Return type: refptr_diff
+ return CefViewDelegateCToCpp::Unwrap(_retval);
+}
+
+struct _cef_window_t* CEF_CALLBACK panel_get_window(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefWindow> _retval =
+ CefPanelCppToC::Get(reinterpret_cast<cef_panel_t*>(self))->GetWindow();
+
+ // Return type: refptr_same
+ return CefWindowCppToC::Wrap(_retval);
+}
+
+int CEF_CALLBACK panel_get_id(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval =
+ CefPanelCppToC::Get(reinterpret_cast<cef_panel_t*>(self))->GetID();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK panel_set_id(struct _cef_view_t* self, int id) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefPanelCppToC::Get(reinterpret_cast<cef_panel_t*>(self))->SetID(id);
+}
+
+int CEF_CALLBACK panel_get_group_id(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval =
+ CefPanelCppToC::Get(reinterpret_cast<cef_panel_t*>(self))->GetGroupID();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK panel_set_group_id(struct _cef_view_t* self, int group_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefPanelCppToC::Get(reinterpret_cast<cef_panel_t*>(self))
+ ->SetGroupID(group_id);
+}
+
+struct _cef_view_t* CEF_CALLBACK
+panel_get_parent_view(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefView> _retval =
+ CefPanelCppToC::Get(reinterpret_cast<cef_panel_t*>(self))
+ ->GetParentView();
+
+ // Return type: refptr_same
+ return CefViewCppToC::Wrap(_retval);
+}
+
+struct _cef_view_t* CEF_CALLBACK panel_get_view_for_id(struct _cef_view_t* self,
+ int id) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefView> _retval =
+ CefPanelCppToC::Get(reinterpret_cast<cef_panel_t*>(self))
+ ->GetViewForID(id);
+
+ // Return type: refptr_same
+ return CefViewCppToC::Wrap(_retval);
+}
+
+void CEF_CALLBACK panel_set_bounds(struct _cef_view_t* self,
+ const cef_rect_t* bounds) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: bounds; type: simple_byref_const
+ DCHECK(bounds);
+ if (!bounds) {
+ return;
+ }
+
+ // Translate param: bounds; type: simple_byref_const
+ CefRect boundsVal = bounds ? *bounds : CefRect();
+
+ // Execute
+ CefPanelCppToC::Get(reinterpret_cast<cef_panel_t*>(self))
+ ->SetBounds(boundsVal);
+}
+
+cef_rect_t CEF_CALLBACK panel_get_bounds(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefRect();
+ }
+
+ // Execute
+ cef_rect_t _retval =
+ CefPanelCppToC::Get(reinterpret_cast<cef_panel_t*>(self))->GetBounds();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_rect_t CEF_CALLBACK panel_get_bounds_in_screen(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefRect();
+ }
+
+ // Execute
+ cef_rect_t _retval = CefPanelCppToC::Get(reinterpret_cast<cef_panel_t*>(self))
+ ->GetBoundsInScreen();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK panel_set_size(struct _cef_view_t* self,
+ const cef_size_t* size) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: size; type: simple_byref_const
+ DCHECK(size);
+ if (!size) {
+ return;
+ }
+
+ // Translate param: size; type: simple_byref_const
+ CefSize sizeVal = size ? *size : CefSize();
+
+ // Execute
+ CefPanelCppToC::Get(reinterpret_cast<cef_panel_t*>(self))->SetSize(sizeVal);
+}
+
+cef_size_t CEF_CALLBACK panel_get_size(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval =
+ CefPanelCppToC::Get(reinterpret_cast<cef_panel_t*>(self))->GetSize();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK panel_set_position(struct _cef_view_t* self,
+ const cef_point_t* position) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: position; type: simple_byref_const
+ DCHECK(position);
+ if (!position) {
+ return;
+ }
+
+ // Translate param: position; type: simple_byref_const
+ CefPoint positionVal = position ? *position : CefPoint();
+
+ // Execute
+ CefPanelCppToC::Get(reinterpret_cast<cef_panel_t*>(self))
+ ->SetPosition(positionVal);
+}
+
+cef_point_t CEF_CALLBACK panel_get_position(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefPoint();
+ }
+
+ // Execute
+ cef_point_t _retval =
+ CefPanelCppToC::Get(reinterpret_cast<cef_panel_t*>(self))->GetPosition();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK panel_set_insets(struct _cef_view_t* self,
+ const cef_insets_t* insets) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: insets; type: simple_byref_const
+ DCHECK(insets);
+ if (!insets) {
+ return;
+ }
+
+ // Translate param: insets; type: simple_byref_const
+ CefInsets insetsVal = insets ? *insets : CefInsets();
+
+ // Execute
+ CefPanelCppToC::Get(reinterpret_cast<cef_panel_t*>(self))
+ ->SetInsets(insetsVal);
+}
+
+cef_insets_t CEF_CALLBACK panel_get_insets(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefInsets();
+ }
+
+ // Execute
+ cef_insets_t _retval =
+ CefPanelCppToC::Get(reinterpret_cast<cef_panel_t*>(self))->GetInsets();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_size_t CEF_CALLBACK panel_get_preferred_size(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval = CefPanelCppToC::Get(reinterpret_cast<cef_panel_t*>(self))
+ ->GetPreferredSize();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK panel_size_to_preferred_size(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefPanelCppToC::Get(reinterpret_cast<cef_panel_t*>(self))
+ ->SizeToPreferredSize();
+}
+
+cef_size_t CEF_CALLBACK panel_get_minimum_size(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval = CefPanelCppToC::Get(reinterpret_cast<cef_panel_t*>(self))
+ ->GetMinimumSize();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_size_t CEF_CALLBACK panel_get_maximum_size(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval = CefPanelCppToC::Get(reinterpret_cast<cef_panel_t*>(self))
+ ->GetMaximumSize();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK panel_get_height_for_width(struct _cef_view_t* self,
+ int width) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefPanelCppToC::Get(reinterpret_cast<cef_panel_t*>(self))
+ ->GetHeightForWidth(width);
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK panel_invalidate_layout(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefPanelCppToC::Get(reinterpret_cast<cef_panel_t*>(self))->InvalidateLayout();
+}
+
+void CEF_CALLBACK panel_set_visible(struct _cef_view_t* self, int visible) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefPanelCppToC::Get(reinterpret_cast<cef_panel_t*>(self))
+ ->SetVisible(visible ? true : false);
+}
+
+int CEF_CALLBACK panel_is_visible(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefPanelCppToC::Get(reinterpret_cast<cef_panel_t*>(self))->IsVisible();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK panel_is_drawn(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefPanelCppToC::Get(reinterpret_cast<cef_panel_t*>(self))->IsDrawn();
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK panel_set_enabled(struct _cef_view_t* self, int enabled) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefPanelCppToC::Get(reinterpret_cast<cef_panel_t*>(self))
+ ->SetEnabled(enabled ? true : false);
+}
+
+int CEF_CALLBACK panel_is_enabled(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefPanelCppToC::Get(reinterpret_cast<cef_panel_t*>(self))->IsEnabled();
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK panel_set_focusable(struct _cef_view_t* self, int focusable) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefPanelCppToC::Get(reinterpret_cast<cef_panel_t*>(self))
+ ->SetFocusable(focusable ? true : false);
+}
+
+int CEF_CALLBACK panel_is_focusable(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefPanelCppToC::Get(reinterpret_cast<cef_panel_t*>(self))->IsFocusable();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK panel_is_accessibility_focusable(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefPanelCppToC::Get(reinterpret_cast<cef_panel_t*>(self))
+ ->IsAccessibilityFocusable();
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK panel_request_focus(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefPanelCppToC::Get(reinterpret_cast<cef_panel_t*>(self))->RequestFocus();
+}
+
+void CEF_CALLBACK panel_set_background_color(struct _cef_view_t* self,
+ cef_color_t color) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefPanelCppToC::Get(reinterpret_cast<cef_panel_t*>(self))
+ ->SetBackgroundColor(color);
+}
+
+cef_color_t CEF_CALLBACK panel_get_background_color(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ cef_color_t _retval =
+ CefPanelCppToC::Get(reinterpret_cast<cef_panel_t*>(self))
+ ->GetBackgroundColor();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK panel_convert_point_to_screen(struct _cef_view_t* self,
+ cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: point; type: simple_byref
+ DCHECK(point);
+ if (!point) {
+ return 0;
+ }
+
+ // Translate param: point; type: simple_byref
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ bool _retval = CefPanelCppToC::Get(reinterpret_cast<cef_panel_t*>(self))
+ ->ConvertPointToScreen(pointVal);
+
+ // Restore param: point; type: simple_byref
+ if (point) {
+ *point = pointVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK panel_convert_point_from_screen(struct _cef_view_t* self,
+ cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: point; type: simple_byref
+ DCHECK(point);
+ if (!point) {
+ return 0;
+ }
+
+ // Translate param: point; type: simple_byref
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ bool _retval = CefPanelCppToC::Get(reinterpret_cast<cef_panel_t*>(self))
+ ->ConvertPointFromScreen(pointVal);
+
+ // Restore param: point; type: simple_byref
+ if (point) {
+ *point = pointVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK panel_convert_point_to_window(struct _cef_view_t* self,
+ cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: point; type: simple_byref
+ DCHECK(point);
+ if (!point) {
+ return 0;
+ }
+
+ // Translate param: point; type: simple_byref
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ bool _retval = CefPanelCppToC::Get(reinterpret_cast<cef_panel_t*>(self))
+ ->ConvertPointToWindow(pointVal);
+
+ // Restore param: point; type: simple_byref
+ if (point) {
+ *point = pointVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK panel_convert_point_from_window(struct _cef_view_t* self,
+ cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: point; type: simple_byref
+ DCHECK(point);
+ if (!point) {
+ return 0;
+ }
+
+ // Translate param: point; type: simple_byref
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ bool _retval = CefPanelCppToC::Get(reinterpret_cast<cef_panel_t*>(self))
+ ->ConvertPointFromWindow(pointVal);
+
+ // Restore param: point; type: simple_byref
+ if (point) {
+ *point = pointVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK panel_convert_point_to_view(struct _cef_view_t* self,
+ struct _cef_view_t* view,
+ cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: view; type: refptr_same
+ DCHECK(view);
+ if (!view) {
+ return 0;
+ }
+ // Verify param: point; type: simple_byref
+ DCHECK(point);
+ if (!point) {
+ return 0;
+ }
+
+ // Translate param: point; type: simple_byref
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ bool _retval =
+ CefPanelCppToC::Get(reinterpret_cast<cef_panel_t*>(self))
+ ->ConvertPointToView(CefViewCppToC::Unwrap(view), pointVal);
+
+ // Restore param: point; type: simple_byref
+ if (point) {
+ *point = pointVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK panel_convert_point_from_view(struct _cef_view_t* self,
+ struct _cef_view_t* view,
+ cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: view; type: refptr_same
+ DCHECK(view);
+ if (!view) {
+ return 0;
+ }
+ // Verify param: point; type: simple_byref
+ DCHECK(point);
+ if (!point) {
+ return 0;
+ }
+
+ // Translate param: point; type: simple_byref
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ bool _retval =
+ CefPanelCppToC::Get(reinterpret_cast<cef_panel_t*>(self))
+ ->ConvertPointFromView(CefViewCppToC::Unwrap(view), pointVal);
+
+ // Restore param: point; type: simple_byref
+ if (point) {
+ *point = pointVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefPanelCppToC::CefPanelCppToC() {
+ GetStruct()->as_window = panel_as_window;
+ GetStruct()->set_to_fill_layout = panel_set_to_fill_layout;
+ GetStruct()->set_to_box_layout = panel_set_to_box_layout;
+ GetStruct()->get_layout = panel_get_layout;
+ GetStruct()->layout = panel_layout;
+ GetStruct()->add_child_view = panel_add_child_view;
+ GetStruct()->add_child_view_at = panel_add_child_view_at;
+ GetStruct()->reorder_child_view = panel_reorder_child_view;
+ GetStruct()->remove_child_view = panel_remove_child_view;
+ GetStruct()->remove_all_child_views = panel_remove_all_child_views;
+ GetStruct()->get_child_view_count = panel_get_child_view_count;
+ GetStruct()->get_child_view_at = panel_get_child_view_at;
+ GetStruct()->base.as_browser_view = panel_as_browser_view;
+ GetStruct()->base.as_button = panel_as_button;
+ GetStruct()->base.as_panel = panel_as_panel;
+ GetStruct()->base.as_scroll_view = panel_as_scroll_view;
+ GetStruct()->base.as_textfield = panel_as_textfield;
+ GetStruct()->base.get_type_string = panel_get_type_string;
+ GetStruct()->base.to_string = panel_to_string;
+ GetStruct()->base.is_valid = panel_is_valid;
+ GetStruct()->base.is_attached = panel_is_attached;
+ GetStruct()->base.is_same = panel_is_same;
+ GetStruct()->base.get_delegate = panel_get_delegate;
+ GetStruct()->base.get_window = panel_get_window;
+ GetStruct()->base.get_id = panel_get_id;
+ GetStruct()->base.set_id = panel_set_id;
+ GetStruct()->base.get_group_id = panel_get_group_id;
+ GetStruct()->base.set_group_id = panel_set_group_id;
+ GetStruct()->base.get_parent_view = panel_get_parent_view;
+ GetStruct()->base.get_view_for_id = panel_get_view_for_id;
+ GetStruct()->base.set_bounds = panel_set_bounds;
+ GetStruct()->base.get_bounds = panel_get_bounds;
+ GetStruct()->base.get_bounds_in_screen = panel_get_bounds_in_screen;
+ GetStruct()->base.set_size = panel_set_size;
+ GetStruct()->base.get_size = panel_get_size;
+ GetStruct()->base.set_position = panel_set_position;
+ GetStruct()->base.get_position = panel_get_position;
+ GetStruct()->base.set_insets = panel_set_insets;
+ GetStruct()->base.get_insets = panel_get_insets;
+ GetStruct()->base.get_preferred_size = panel_get_preferred_size;
+ GetStruct()->base.size_to_preferred_size = panel_size_to_preferred_size;
+ GetStruct()->base.get_minimum_size = panel_get_minimum_size;
+ GetStruct()->base.get_maximum_size = panel_get_maximum_size;
+ GetStruct()->base.get_height_for_width = panel_get_height_for_width;
+ GetStruct()->base.invalidate_layout = panel_invalidate_layout;
+ GetStruct()->base.set_visible = panel_set_visible;
+ GetStruct()->base.is_visible = panel_is_visible;
+ GetStruct()->base.is_drawn = panel_is_drawn;
+ GetStruct()->base.set_enabled = panel_set_enabled;
+ GetStruct()->base.is_enabled = panel_is_enabled;
+ GetStruct()->base.set_focusable = panel_set_focusable;
+ GetStruct()->base.is_focusable = panel_is_focusable;
+ GetStruct()->base.is_accessibility_focusable =
+ panel_is_accessibility_focusable;
+ GetStruct()->base.request_focus = panel_request_focus;
+ GetStruct()->base.set_background_color = panel_set_background_color;
+ GetStruct()->base.get_background_color = panel_get_background_color;
+ GetStruct()->base.convert_point_to_screen = panel_convert_point_to_screen;
+ GetStruct()->base.convert_point_from_screen = panel_convert_point_from_screen;
+ GetStruct()->base.convert_point_to_window = panel_convert_point_to_window;
+ GetStruct()->base.convert_point_from_window = panel_convert_point_from_window;
+ GetStruct()->base.convert_point_to_view = panel_convert_point_to_view;
+ GetStruct()->base.convert_point_from_view = panel_convert_point_from_view;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefPanelCppToC::~CefPanelCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefPanel>
+CefCppToCRefCounted<CefPanelCppToC, CefPanel, cef_panel_t>::UnwrapDerived(
+ CefWrapperType type,
+ cef_panel_t* s) {
+ if (type == WT_WINDOW) {
+ return CefWindowCppToC::Unwrap(reinterpret_cast<cef_window_t*>(s));
+ }
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCppToCRefCounted<CefPanelCppToC, CefPanel, cef_panel_t>::kWrapperType =
+ WT_PANEL;
diff --git a/libcef_dll/cpptoc/views/panel_cpptoc.h b/libcef_dll/cpptoc/views/panel_cpptoc.h
new file mode 100644
index 00000000..7411c0d3
--- /dev/null
+++ b/libcef_dll/cpptoc/views/panel_cpptoc.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=2c4b5c88fc2a00039dc5eb01aaa90ecd7c2ea0ad$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_VIEWS_PANEL_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_VIEWS_PANEL_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/views/cef_box_layout_capi.h"
+#include "include/capi/views/cef_fill_layout_capi.h"
+#include "include/capi/views/cef_layout_capi.h"
+#include "include/capi/views/cef_panel_capi.h"
+#include "include/capi/views/cef_window_capi.h"
+#include "include/views/cef_box_layout.h"
+#include "include/views/cef_fill_layout.h"
+#include "include/views/cef_layout.h"
+#include "include/views/cef_panel.h"
+#include "include/views/cef_window.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefPanelCppToC
+ : public CefCppToCRefCounted<CefPanelCppToC, CefPanel, cef_panel_t> {
+ public:
+ CefPanelCppToC();
+ virtual ~CefPanelCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_VIEWS_PANEL_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/views/panel_delegate_cpptoc.cc b/libcef_dll/cpptoc/views/panel_delegate_cpptoc.cc
new file mode 100644
index 00000000..d5f084a9
--- /dev/null
+++ b/libcef_dll/cpptoc/views/panel_delegate_cpptoc.cc
@@ -0,0 +1,328 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=5738293c290214f784a22e3144475247cd4ee3b4$
+//
+
+#include "libcef_dll/cpptoc/views/panel_delegate_cpptoc.h"
+#include "libcef_dll/cpptoc/views/window_delegate_cpptoc.h"
+#include "libcef_dll/ctocpp/views/view_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+cef_size_t CEF_CALLBACK
+panel_delegate_get_preferred_size(struct _cef_view_delegate_t* self,
+ cef_view_t* view) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval =
+ CefPanelDelegateCppToC::Get(reinterpret_cast<cef_panel_delegate_t*>(self))
+ ->GetPreferredSize(CefViewCToCpp::Wrap(view));
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_size_t CEF_CALLBACK
+panel_delegate_get_minimum_size(struct _cef_view_delegate_t* self,
+ cef_view_t* view) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval =
+ CefPanelDelegateCppToC::Get(reinterpret_cast<cef_panel_delegate_t*>(self))
+ ->GetMinimumSize(CefViewCToCpp::Wrap(view));
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_size_t CEF_CALLBACK
+panel_delegate_get_maximum_size(struct _cef_view_delegate_t* self,
+ cef_view_t* view) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval =
+ CefPanelDelegateCppToC::Get(reinterpret_cast<cef_panel_delegate_t*>(self))
+ ->GetMaximumSize(CefViewCToCpp::Wrap(view));
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK
+panel_delegate_get_height_for_width(struct _cef_view_delegate_t* self,
+ cef_view_t* view,
+ int width) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return 0;
+ }
+
+ // Execute
+ int _retval =
+ CefPanelDelegateCppToC::Get(reinterpret_cast<cef_panel_delegate_t*>(self))
+ ->GetHeightForWidth(CefViewCToCpp::Wrap(view), width);
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK
+panel_delegate_on_parent_view_changed(struct _cef_view_delegate_t* self,
+ cef_view_t* view,
+ int added,
+ cef_view_t* parent) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return;
+ }
+ // Verify param: parent; type: refptr_diff
+ DCHECK(parent);
+ if (!parent) {
+ return;
+ }
+
+ // Execute
+ CefPanelDelegateCppToC::Get(reinterpret_cast<cef_panel_delegate_t*>(self))
+ ->OnParentViewChanged(CefViewCToCpp::Wrap(view), added ? true : false,
+ CefViewCToCpp::Wrap(parent));
+}
+
+void CEF_CALLBACK
+panel_delegate_on_child_view_changed(struct _cef_view_delegate_t* self,
+ cef_view_t* view,
+ int added,
+ cef_view_t* child) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return;
+ }
+ // Verify param: child; type: refptr_diff
+ DCHECK(child);
+ if (!child) {
+ return;
+ }
+
+ // Execute
+ CefPanelDelegateCppToC::Get(reinterpret_cast<cef_panel_delegate_t*>(self))
+ ->OnChildViewChanged(CefViewCToCpp::Wrap(view), added ? true : false,
+ CefViewCToCpp::Wrap(child));
+}
+
+void CEF_CALLBACK
+panel_delegate_on_window_changed(struct _cef_view_delegate_t* self,
+ cef_view_t* view,
+ int added) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return;
+ }
+
+ // Execute
+ CefPanelDelegateCppToC::Get(reinterpret_cast<cef_panel_delegate_t*>(self))
+ ->OnWindowChanged(CefViewCToCpp::Wrap(view), added ? true : false);
+}
+
+void CEF_CALLBACK
+panel_delegate_on_layout_changed(struct _cef_view_delegate_t* self,
+ cef_view_t* view,
+ const cef_rect_t* new_bounds) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return;
+ }
+ // Verify param: new_bounds; type: simple_byref_const
+ DCHECK(new_bounds);
+ if (!new_bounds) {
+ return;
+ }
+
+ // Translate param: new_bounds; type: simple_byref_const
+ CefRect new_boundsVal = new_bounds ? *new_bounds : CefRect();
+
+ // Execute
+ CefPanelDelegateCppToC::Get(reinterpret_cast<cef_panel_delegate_t*>(self))
+ ->OnLayoutChanged(CefViewCToCpp::Wrap(view), new_boundsVal);
+}
+
+void CEF_CALLBACK panel_delegate_on_focus(struct _cef_view_delegate_t* self,
+ cef_view_t* view) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return;
+ }
+
+ // Execute
+ CefPanelDelegateCppToC::Get(reinterpret_cast<cef_panel_delegate_t*>(self))
+ ->OnFocus(CefViewCToCpp::Wrap(view));
+}
+
+void CEF_CALLBACK panel_delegate_on_blur(struct _cef_view_delegate_t* self,
+ cef_view_t* view) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return;
+ }
+
+ // Execute
+ CefPanelDelegateCppToC::Get(reinterpret_cast<cef_panel_delegate_t*>(self))
+ ->OnBlur(CefViewCToCpp::Wrap(view));
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefPanelDelegateCppToC::CefPanelDelegateCppToC() {
+ GetStruct()->base.get_preferred_size = panel_delegate_get_preferred_size;
+ GetStruct()->base.get_minimum_size = panel_delegate_get_minimum_size;
+ GetStruct()->base.get_maximum_size = panel_delegate_get_maximum_size;
+ GetStruct()->base.get_height_for_width = panel_delegate_get_height_for_width;
+ GetStruct()->base.on_parent_view_changed =
+ panel_delegate_on_parent_view_changed;
+ GetStruct()->base.on_child_view_changed =
+ panel_delegate_on_child_view_changed;
+ GetStruct()->base.on_window_changed = panel_delegate_on_window_changed;
+ GetStruct()->base.on_layout_changed = panel_delegate_on_layout_changed;
+ GetStruct()->base.on_focus = panel_delegate_on_focus;
+ GetStruct()->base.on_blur = panel_delegate_on_blur;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefPanelDelegateCppToC::~CefPanelDelegateCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefPanelDelegate> CefCppToCRefCounted<
+ CefPanelDelegateCppToC,
+ CefPanelDelegate,
+ cef_panel_delegate_t>::UnwrapDerived(CefWrapperType type,
+ cef_panel_delegate_t* s) {
+ if (type == WT_WINDOW_DELEGATE) {
+ return CefWindowDelegateCppToC::Unwrap(
+ reinterpret_cast<cef_window_delegate_t*>(s));
+ }
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefPanelDelegateCppToC,
+ CefPanelDelegate,
+ cef_panel_delegate_t>::kWrapperType =
+ WT_PANEL_DELEGATE;
diff --git a/libcef_dll/cpptoc/views/panel_delegate_cpptoc.h b/libcef_dll/cpptoc/views/panel_delegate_cpptoc.h
new file mode 100644
index 00000000..578ce7c7
--- /dev/null
+++ b/libcef_dll/cpptoc/views/panel_delegate_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=1eedf21b5a9e1edb24e6c24de55c991388b50c7c$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_VIEWS_PANEL_DELEGATE_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_VIEWS_PANEL_DELEGATE_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/views/cef_panel_delegate_capi.h"
+#include "include/views/cef_panel_delegate.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefPanelDelegateCppToC
+ : public CefCppToCRefCounted<CefPanelDelegateCppToC,
+ CefPanelDelegate,
+ cef_panel_delegate_t> {
+ public:
+ CefPanelDelegateCppToC();
+ virtual ~CefPanelDelegateCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_VIEWS_PANEL_DELEGATE_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/views/scroll_view_cpptoc.cc b/libcef_dll/cpptoc/views/scroll_view_cpptoc.cc
new file mode 100644
index 00000000..06d2c16f
--- /dev/null
+++ b/libcef_dll/cpptoc/views/scroll_view_cpptoc.cc
@@ -0,0 +1,1320 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=6f6ba39e44e91b687fc1f4d0c2c1873664b5cf93$
+//
+
+#include "libcef_dll/cpptoc/views/scroll_view_cpptoc.h"
+#include "libcef_dll/cpptoc/views/browser_view_cpptoc.h"
+#include "libcef_dll/cpptoc/views/button_cpptoc.h"
+#include "libcef_dll/cpptoc/views/panel_cpptoc.h"
+#include "libcef_dll/cpptoc/views/textfield_cpptoc.h"
+#include "libcef_dll/cpptoc/views/view_cpptoc.h"
+#include "libcef_dll/cpptoc/views/window_cpptoc.h"
+#include "libcef_dll/ctocpp/views/view_delegate_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// GLOBAL FUNCTIONS - Body may be edited by hand.
+
+CEF_EXPORT cef_scroll_view_t* cef_scroll_view_create(
+ struct _cef_view_delegate_t* delegate) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: delegate
+
+ // Execute
+ CefRefPtr<CefScrollView> _retval =
+ CefScrollView::CreateScrollView(CefViewDelegateCToCpp::Wrap(delegate));
+
+ // Return type: refptr_same
+ return CefScrollViewCppToC::Wrap(_retval);
+}
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK scroll_view_set_content_view(struct _cef_scroll_view_t* self,
+ struct _cef_view_t* view) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: view; type: refptr_same
+ DCHECK(view);
+ if (!view) {
+ return;
+ }
+
+ // Execute
+ CefScrollViewCppToC::Get(self)->SetContentView(CefViewCppToC::Unwrap(view));
+}
+
+struct _cef_view_t* CEF_CALLBACK
+scroll_view_get_content_view(struct _cef_scroll_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefView> _retval = CefScrollViewCppToC::Get(self)->GetContentView();
+
+ // Return type: refptr_same
+ return CefViewCppToC::Wrap(_retval);
+}
+
+cef_rect_t CEF_CALLBACK
+scroll_view_get_visible_content_rect(struct _cef_scroll_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefRect();
+ }
+
+ // Execute
+ cef_rect_t _retval = CefScrollViewCppToC::Get(self)->GetVisibleContentRect();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK
+scroll_view_has_horizontal_scrollbar(struct _cef_scroll_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefScrollViewCppToC::Get(self)->HasHorizontalScrollbar();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+scroll_view_get_horizontal_scrollbar_height(struct _cef_scroll_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefScrollViewCppToC::Get(self)->GetHorizontalScrollbarHeight();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK
+scroll_view_has_vertical_scrollbar(struct _cef_scroll_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefScrollViewCppToC::Get(self)->HasVerticalScrollbar();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+scroll_view_get_vertical_scrollbar_width(struct _cef_scroll_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefScrollViewCppToC::Get(self)->GetVerticalScrollbarWidth();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_browser_view_t* CEF_CALLBACK
+scroll_view_as_browser_view(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefBrowserView> _retval =
+ CefScrollViewCppToC::Get(reinterpret_cast<cef_scroll_view_t*>(self))
+ ->AsBrowserView();
+
+ // Return type: refptr_same
+ return CefBrowserViewCppToC::Wrap(_retval);
+}
+
+cef_button_t* CEF_CALLBACK scroll_view_as_button(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefButton> _retval =
+ CefScrollViewCppToC::Get(reinterpret_cast<cef_scroll_view_t*>(self))
+ ->AsButton();
+
+ // Return type: refptr_same
+ return CefButtonCppToC::Wrap(_retval);
+}
+
+cef_panel_t* CEF_CALLBACK scroll_view_as_panel(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefPanel> _retval =
+ CefScrollViewCppToC::Get(reinterpret_cast<cef_scroll_view_t*>(self))
+ ->AsPanel();
+
+ // Return type: refptr_same
+ return CefPanelCppToC::Wrap(_retval);
+}
+
+cef_scroll_view_t* CEF_CALLBACK
+scroll_view_as_scroll_view(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefScrollView> _retval =
+ CefScrollViewCppToC::Get(reinterpret_cast<cef_scroll_view_t*>(self))
+ ->AsScrollView();
+
+ // Return type: refptr_same
+ return CefScrollViewCppToC::Wrap(_retval);
+}
+
+cef_textfield_t* CEF_CALLBACK
+scroll_view_as_textfield(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefTextfield> _retval =
+ CefScrollViewCppToC::Get(reinterpret_cast<cef_scroll_view_t*>(self))
+ ->AsTextfield();
+
+ // Return type: refptr_same
+ return CefTextfieldCppToC::Wrap(_retval);
+}
+
+cef_string_userfree_t CEF_CALLBACK
+scroll_view_get_type_string(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval =
+ CefScrollViewCppToC::Get(reinterpret_cast<cef_scroll_view_t*>(self))
+ ->GetTypeString();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_string_userfree_t CEF_CALLBACK
+scroll_view_to_string(struct _cef_view_t* self, int include_children) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval =
+ CefScrollViewCppToC::Get(reinterpret_cast<cef_scroll_view_t*>(self))
+ ->ToString(include_children ? true : false);
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+int CEF_CALLBACK scroll_view_is_valid(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefScrollViewCppToC::Get(reinterpret_cast<cef_scroll_view_t*>(self))
+ ->IsValid();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK scroll_view_is_attached(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefScrollViewCppToC::Get(reinterpret_cast<cef_scroll_view_t*>(self))
+ ->IsAttached();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK scroll_view_is_same(struct _cef_view_t* self,
+ struct _cef_view_t* that) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: that; type: refptr_same
+ DCHECK(that);
+ if (!that) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefScrollViewCppToC::Get(reinterpret_cast<cef_scroll_view_t*>(self))
+ ->IsSame(CefViewCppToC::Unwrap(that));
+
+ // Return type: bool
+ return _retval;
+}
+
+struct _cef_view_delegate_t* CEF_CALLBACK
+scroll_view_get_delegate(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefViewDelegate> _retval =
+ CefScrollViewCppToC::Get(reinterpret_cast<cef_scroll_view_t*>(self))
+ ->GetDelegate();
+
+ // Return type: refptr_diff
+ return CefViewDelegateCToCpp::Unwrap(_retval);
+}
+
+struct _cef_window_t* CEF_CALLBACK
+scroll_view_get_window(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefWindow> _retval =
+ CefScrollViewCppToC::Get(reinterpret_cast<cef_scroll_view_t*>(self))
+ ->GetWindow();
+
+ // Return type: refptr_same
+ return CefWindowCppToC::Wrap(_retval);
+}
+
+int CEF_CALLBACK scroll_view_get_id(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval =
+ CefScrollViewCppToC::Get(reinterpret_cast<cef_scroll_view_t*>(self))
+ ->GetID();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK scroll_view_set_id(struct _cef_view_t* self, int id) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefScrollViewCppToC::Get(reinterpret_cast<cef_scroll_view_t*>(self))
+ ->SetID(id);
+}
+
+int CEF_CALLBACK scroll_view_get_group_id(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval =
+ CefScrollViewCppToC::Get(reinterpret_cast<cef_scroll_view_t*>(self))
+ ->GetGroupID();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK scroll_view_set_group_id(struct _cef_view_t* self,
+ int group_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefScrollViewCppToC::Get(reinterpret_cast<cef_scroll_view_t*>(self))
+ ->SetGroupID(group_id);
+}
+
+struct _cef_view_t* CEF_CALLBACK
+scroll_view_get_parent_view(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefView> _retval =
+ CefScrollViewCppToC::Get(reinterpret_cast<cef_scroll_view_t*>(self))
+ ->GetParentView();
+
+ // Return type: refptr_same
+ return CefViewCppToC::Wrap(_retval);
+}
+
+struct _cef_view_t* CEF_CALLBACK
+scroll_view_get_view_for_id(struct _cef_view_t* self, int id) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefView> _retval =
+ CefScrollViewCppToC::Get(reinterpret_cast<cef_scroll_view_t*>(self))
+ ->GetViewForID(id);
+
+ // Return type: refptr_same
+ return CefViewCppToC::Wrap(_retval);
+}
+
+void CEF_CALLBACK scroll_view_set_bounds(struct _cef_view_t* self,
+ const cef_rect_t* bounds) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: bounds; type: simple_byref_const
+ DCHECK(bounds);
+ if (!bounds) {
+ return;
+ }
+
+ // Translate param: bounds; type: simple_byref_const
+ CefRect boundsVal = bounds ? *bounds : CefRect();
+
+ // Execute
+ CefScrollViewCppToC::Get(reinterpret_cast<cef_scroll_view_t*>(self))
+ ->SetBounds(boundsVal);
+}
+
+cef_rect_t CEF_CALLBACK scroll_view_get_bounds(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefRect();
+ }
+
+ // Execute
+ cef_rect_t _retval =
+ CefScrollViewCppToC::Get(reinterpret_cast<cef_scroll_view_t*>(self))
+ ->GetBounds();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_rect_t CEF_CALLBACK
+scroll_view_get_bounds_in_screen(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefRect();
+ }
+
+ // Execute
+ cef_rect_t _retval =
+ CefScrollViewCppToC::Get(reinterpret_cast<cef_scroll_view_t*>(self))
+ ->GetBoundsInScreen();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK scroll_view_set_size(struct _cef_view_t* self,
+ const cef_size_t* size) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: size; type: simple_byref_const
+ DCHECK(size);
+ if (!size) {
+ return;
+ }
+
+ // Translate param: size; type: simple_byref_const
+ CefSize sizeVal = size ? *size : CefSize();
+
+ // Execute
+ CefScrollViewCppToC::Get(reinterpret_cast<cef_scroll_view_t*>(self))
+ ->SetSize(sizeVal);
+}
+
+cef_size_t CEF_CALLBACK scroll_view_get_size(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval =
+ CefScrollViewCppToC::Get(reinterpret_cast<cef_scroll_view_t*>(self))
+ ->GetSize();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK scroll_view_set_position(struct _cef_view_t* self,
+ const cef_point_t* position) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: position; type: simple_byref_const
+ DCHECK(position);
+ if (!position) {
+ return;
+ }
+
+ // Translate param: position; type: simple_byref_const
+ CefPoint positionVal = position ? *position : CefPoint();
+
+ // Execute
+ CefScrollViewCppToC::Get(reinterpret_cast<cef_scroll_view_t*>(self))
+ ->SetPosition(positionVal);
+}
+
+cef_point_t CEF_CALLBACK scroll_view_get_position(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefPoint();
+ }
+
+ // Execute
+ cef_point_t _retval =
+ CefScrollViewCppToC::Get(reinterpret_cast<cef_scroll_view_t*>(self))
+ ->GetPosition();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK scroll_view_set_insets(struct _cef_view_t* self,
+ const cef_insets_t* insets) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: insets; type: simple_byref_const
+ DCHECK(insets);
+ if (!insets) {
+ return;
+ }
+
+ // Translate param: insets; type: simple_byref_const
+ CefInsets insetsVal = insets ? *insets : CefInsets();
+
+ // Execute
+ CefScrollViewCppToC::Get(reinterpret_cast<cef_scroll_view_t*>(self))
+ ->SetInsets(insetsVal);
+}
+
+cef_insets_t CEF_CALLBACK scroll_view_get_insets(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefInsets();
+ }
+
+ // Execute
+ cef_insets_t _retval =
+ CefScrollViewCppToC::Get(reinterpret_cast<cef_scroll_view_t*>(self))
+ ->GetInsets();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_size_t CEF_CALLBACK
+scroll_view_get_preferred_size(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval =
+ CefScrollViewCppToC::Get(reinterpret_cast<cef_scroll_view_t*>(self))
+ ->GetPreferredSize();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK scroll_view_size_to_preferred_size(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefScrollViewCppToC::Get(reinterpret_cast<cef_scroll_view_t*>(self))
+ ->SizeToPreferredSize();
+}
+
+cef_size_t CEF_CALLBACK scroll_view_get_minimum_size(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval =
+ CefScrollViewCppToC::Get(reinterpret_cast<cef_scroll_view_t*>(self))
+ ->GetMinimumSize();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_size_t CEF_CALLBACK scroll_view_get_maximum_size(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval =
+ CefScrollViewCppToC::Get(reinterpret_cast<cef_scroll_view_t*>(self))
+ ->GetMaximumSize();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK scroll_view_get_height_for_width(struct _cef_view_t* self,
+ int width) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval =
+ CefScrollViewCppToC::Get(reinterpret_cast<cef_scroll_view_t*>(self))
+ ->GetHeightForWidth(width);
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK scroll_view_invalidate_layout(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefScrollViewCppToC::Get(reinterpret_cast<cef_scroll_view_t*>(self))
+ ->InvalidateLayout();
+}
+
+void CEF_CALLBACK scroll_view_set_visible(struct _cef_view_t* self,
+ int visible) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefScrollViewCppToC::Get(reinterpret_cast<cef_scroll_view_t*>(self))
+ ->SetVisible(visible ? true : false);
+}
+
+int CEF_CALLBACK scroll_view_is_visible(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefScrollViewCppToC::Get(reinterpret_cast<cef_scroll_view_t*>(self))
+ ->IsVisible();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK scroll_view_is_drawn(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefScrollViewCppToC::Get(reinterpret_cast<cef_scroll_view_t*>(self))
+ ->IsDrawn();
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK scroll_view_set_enabled(struct _cef_view_t* self,
+ int enabled) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefScrollViewCppToC::Get(reinterpret_cast<cef_scroll_view_t*>(self))
+ ->SetEnabled(enabled ? true : false);
+}
+
+int CEF_CALLBACK scroll_view_is_enabled(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefScrollViewCppToC::Get(reinterpret_cast<cef_scroll_view_t*>(self))
+ ->IsEnabled();
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK scroll_view_set_focusable(struct _cef_view_t* self,
+ int focusable) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefScrollViewCppToC::Get(reinterpret_cast<cef_scroll_view_t*>(self))
+ ->SetFocusable(focusable ? true : false);
+}
+
+int CEF_CALLBACK scroll_view_is_focusable(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefScrollViewCppToC::Get(reinterpret_cast<cef_scroll_view_t*>(self))
+ ->IsFocusable();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+scroll_view_is_accessibility_focusable(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefScrollViewCppToC::Get(reinterpret_cast<cef_scroll_view_t*>(self))
+ ->IsAccessibilityFocusable();
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK scroll_view_request_focus(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefScrollViewCppToC::Get(reinterpret_cast<cef_scroll_view_t*>(self))
+ ->RequestFocus();
+}
+
+void CEF_CALLBACK scroll_view_set_background_color(struct _cef_view_t* self,
+ cef_color_t color) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefScrollViewCppToC::Get(reinterpret_cast<cef_scroll_view_t*>(self))
+ ->SetBackgroundColor(color);
+}
+
+cef_color_t CEF_CALLBACK
+scroll_view_get_background_color(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ cef_color_t _retval =
+ CefScrollViewCppToC::Get(reinterpret_cast<cef_scroll_view_t*>(self))
+ ->GetBackgroundColor();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK scroll_view_convert_point_to_screen(struct _cef_view_t* self,
+ cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: point; type: simple_byref
+ DCHECK(point);
+ if (!point) {
+ return 0;
+ }
+
+ // Translate param: point; type: simple_byref
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ bool _retval =
+ CefScrollViewCppToC::Get(reinterpret_cast<cef_scroll_view_t*>(self))
+ ->ConvertPointToScreen(pointVal);
+
+ // Restore param: point; type: simple_byref
+ if (point) {
+ *point = pointVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK scroll_view_convert_point_from_screen(struct _cef_view_t* self,
+ cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: point; type: simple_byref
+ DCHECK(point);
+ if (!point) {
+ return 0;
+ }
+
+ // Translate param: point; type: simple_byref
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ bool _retval =
+ CefScrollViewCppToC::Get(reinterpret_cast<cef_scroll_view_t*>(self))
+ ->ConvertPointFromScreen(pointVal);
+
+ // Restore param: point; type: simple_byref
+ if (point) {
+ *point = pointVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK scroll_view_convert_point_to_window(struct _cef_view_t* self,
+ cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: point; type: simple_byref
+ DCHECK(point);
+ if (!point) {
+ return 0;
+ }
+
+ // Translate param: point; type: simple_byref
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ bool _retval =
+ CefScrollViewCppToC::Get(reinterpret_cast<cef_scroll_view_t*>(self))
+ ->ConvertPointToWindow(pointVal);
+
+ // Restore param: point; type: simple_byref
+ if (point) {
+ *point = pointVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK scroll_view_convert_point_from_window(struct _cef_view_t* self,
+ cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: point; type: simple_byref
+ DCHECK(point);
+ if (!point) {
+ return 0;
+ }
+
+ // Translate param: point; type: simple_byref
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ bool _retval =
+ CefScrollViewCppToC::Get(reinterpret_cast<cef_scroll_view_t*>(self))
+ ->ConvertPointFromWindow(pointVal);
+
+ // Restore param: point; type: simple_byref
+ if (point) {
+ *point = pointVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK scroll_view_convert_point_to_view(struct _cef_view_t* self,
+ struct _cef_view_t* view,
+ cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: view; type: refptr_same
+ DCHECK(view);
+ if (!view) {
+ return 0;
+ }
+ // Verify param: point; type: simple_byref
+ DCHECK(point);
+ if (!point) {
+ return 0;
+ }
+
+ // Translate param: point; type: simple_byref
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ bool _retval =
+ CefScrollViewCppToC::Get(reinterpret_cast<cef_scroll_view_t*>(self))
+ ->ConvertPointToView(CefViewCppToC::Unwrap(view), pointVal);
+
+ // Restore param: point; type: simple_byref
+ if (point) {
+ *point = pointVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK scroll_view_convert_point_from_view(struct _cef_view_t* self,
+ struct _cef_view_t* view,
+ cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: view; type: refptr_same
+ DCHECK(view);
+ if (!view) {
+ return 0;
+ }
+ // Verify param: point; type: simple_byref
+ DCHECK(point);
+ if (!point) {
+ return 0;
+ }
+
+ // Translate param: point; type: simple_byref
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ bool _retval =
+ CefScrollViewCppToC::Get(reinterpret_cast<cef_scroll_view_t*>(self))
+ ->ConvertPointFromView(CefViewCppToC::Unwrap(view), pointVal);
+
+ // Restore param: point; type: simple_byref
+ if (point) {
+ *point = pointVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefScrollViewCppToC::CefScrollViewCppToC() {
+ GetStruct()->set_content_view = scroll_view_set_content_view;
+ GetStruct()->get_content_view = scroll_view_get_content_view;
+ GetStruct()->get_visible_content_rect = scroll_view_get_visible_content_rect;
+ GetStruct()->has_horizontal_scrollbar = scroll_view_has_horizontal_scrollbar;
+ GetStruct()->get_horizontal_scrollbar_height =
+ scroll_view_get_horizontal_scrollbar_height;
+ GetStruct()->has_vertical_scrollbar = scroll_view_has_vertical_scrollbar;
+ GetStruct()->get_vertical_scrollbar_width =
+ scroll_view_get_vertical_scrollbar_width;
+ GetStruct()->base.as_browser_view = scroll_view_as_browser_view;
+ GetStruct()->base.as_button = scroll_view_as_button;
+ GetStruct()->base.as_panel = scroll_view_as_panel;
+ GetStruct()->base.as_scroll_view = scroll_view_as_scroll_view;
+ GetStruct()->base.as_textfield = scroll_view_as_textfield;
+ GetStruct()->base.get_type_string = scroll_view_get_type_string;
+ GetStruct()->base.to_string = scroll_view_to_string;
+ GetStruct()->base.is_valid = scroll_view_is_valid;
+ GetStruct()->base.is_attached = scroll_view_is_attached;
+ GetStruct()->base.is_same = scroll_view_is_same;
+ GetStruct()->base.get_delegate = scroll_view_get_delegate;
+ GetStruct()->base.get_window = scroll_view_get_window;
+ GetStruct()->base.get_id = scroll_view_get_id;
+ GetStruct()->base.set_id = scroll_view_set_id;
+ GetStruct()->base.get_group_id = scroll_view_get_group_id;
+ GetStruct()->base.set_group_id = scroll_view_set_group_id;
+ GetStruct()->base.get_parent_view = scroll_view_get_parent_view;
+ GetStruct()->base.get_view_for_id = scroll_view_get_view_for_id;
+ GetStruct()->base.set_bounds = scroll_view_set_bounds;
+ GetStruct()->base.get_bounds = scroll_view_get_bounds;
+ GetStruct()->base.get_bounds_in_screen = scroll_view_get_bounds_in_screen;
+ GetStruct()->base.set_size = scroll_view_set_size;
+ GetStruct()->base.get_size = scroll_view_get_size;
+ GetStruct()->base.set_position = scroll_view_set_position;
+ GetStruct()->base.get_position = scroll_view_get_position;
+ GetStruct()->base.set_insets = scroll_view_set_insets;
+ GetStruct()->base.get_insets = scroll_view_get_insets;
+ GetStruct()->base.get_preferred_size = scroll_view_get_preferred_size;
+ GetStruct()->base.size_to_preferred_size = scroll_view_size_to_preferred_size;
+ GetStruct()->base.get_minimum_size = scroll_view_get_minimum_size;
+ GetStruct()->base.get_maximum_size = scroll_view_get_maximum_size;
+ GetStruct()->base.get_height_for_width = scroll_view_get_height_for_width;
+ GetStruct()->base.invalidate_layout = scroll_view_invalidate_layout;
+ GetStruct()->base.set_visible = scroll_view_set_visible;
+ GetStruct()->base.is_visible = scroll_view_is_visible;
+ GetStruct()->base.is_drawn = scroll_view_is_drawn;
+ GetStruct()->base.set_enabled = scroll_view_set_enabled;
+ GetStruct()->base.is_enabled = scroll_view_is_enabled;
+ GetStruct()->base.set_focusable = scroll_view_set_focusable;
+ GetStruct()->base.is_focusable = scroll_view_is_focusable;
+ GetStruct()->base.is_accessibility_focusable =
+ scroll_view_is_accessibility_focusable;
+ GetStruct()->base.request_focus = scroll_view_request_focus;
+ GetStruct()->base.set_background_color = scroll_view_set_background_color;
+ GetStruct()->base.get_background_color = scroll_view_get_background_color;
+ GetStruct()->base.convert_point_to_screen =
+ scroll_view_convert_point_to_screen;
+ GetStruct()->base.convert_point_from_screen =
+ scroll_view_convert_point_from_screen;
+ GetStruct()->base.convert_point_to_window =
+ scroll_view_convert_point_to_window;
+ GetStruct()->base.convert_point_from_window =
+ scroll_view_convert_point_from_window;
+ GetStruct()->base.convert_point_to_view = scroll_view_convert_point_to_view;
+ GetStruct()->base.convert_point_from_view =
+ scroll_view_convert_point_from_view;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefScrollViewCppToC::~CefScrollViewCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefScrollView>
+CefCppToCRefCounted<CefScrollViewCppToC, CefScrollView, cef_scroll_view_t>::
+ UnwrapDerived(CefWrapperType type, cef_scroll_view_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefScrollViewCppToC,
+ CefScrollView,
+ cef_scroll_view_t>::kWrapperType =
+ WT_SCROLL_VIEW;
diff --git a/libcef_dll/cpptoc/views/scroll_view_cpptoc.h b/libcef_dll/cpptoc/views/scroll_view_cpptoc.h
new file mode 100644
index 00000000..1861706c
--- /dev/null
+++ b/libcef_dll/cpptoc/views/scroll_view_cpptoc.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=f0b7e40e7ec1e3870dbc7f25430978c46eb1a51f$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_VIEWS_SCROLL_VIEW_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_VIEWS_SCROLL_VIEW_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/views/cef_scroll_view_capi.h"
+#include "include/views/cef_scroll_view.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefScrollViewCppToC : public CefCppToCRefCounted<CefScrollViewCppToC,
+ CefScrollView,
+ cef_scroll_view_t> {
+ public:
+ CefScrollViewCppToC();
+ virtual ~CefScrollViewCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_VIEWS_SCROLL_VIEW_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/views/textfield_cpptoc.cc b/libcef_dll/cpptoc/views/textfield_cpptoc.cc
new file mode 100644
index 00000000..af71c81d
--- /dev/null
+++ b/libcef_dll/cpptoc/views/textfield_cpptoc.cc
@@ -0,0 +1,1772 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=4b4c876c54c2ea2240d34c119cf2cdca6e307bde$
+//
+
+#include "libcef_dll/cpptoc/views/textfield_cpptoc.h"
+#include "libcef_dll/cpptoc/views/browser_view_cpptoc.h"
+#include "libcef_dll/cpptoc/views/button_cpptoc.h"
+#include "libcef_dll/cpptoc/views/panel_cpptoc.h"
+#include "libcef_dll/cpptoc/views/scroll_view_cpptoc.h"
+#include "libcef_dll/cpptoc/views/view_cpptoc.h"
+#include "libcef_dll/cpptoc/views/window_cpptoc.h"
+#include "libcef_dll/ctocpp/views/textfield_delegate_ctocpp.h"
+#include "libcef_dll/ctocpp/views/view_delegate_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// GLOBAL FUNCTIONS - Body may be edited by hand.
+
+CEF_EXPORT cef_textfield_t* cef_textfield_create(
+ cef_textfield_delegate_t* delegate) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: delegate
+
+ // Execute
+ CefRefPtr<CefTextfield> _retval =
+ CefTextfield::CreateTextfield(CefTextfieldDelegateCToCpp::Wrap(delegate));
+
+ // Return type: refptr_same
+ return CefTextfieldCppToC::Wrap(_retval);
+}
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK textfield_set_password_input(struct _cef_textfield_t* self,
+ int password_input) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefTextfieldCppToC::Get(self)->SetPasswordInput(password_input ? true
+ : false);
+}
+
+int CEF_CALLBACK textfield_is_password_input(struct _cef_textfield_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefTextfieldCppToC::Get(self)->IsPasswordInput();
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK textfield_set_read_only(struct _cef_textfield_t* self,
+ int read_only) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefTextfieldCppToC::Get(self)->SetReadOnly(read_only ? true : false);
+}
+
+int CEF_CALLBACK textfield_is_read_only(struct _cef_textfield_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefTextfieldCppToC::Get(self)->IsReadOnly();
+
+ // Return type: bool
+ return _retval;
+}
+
+cef_string_userfree_t CEF_CALLBACK
+textfield_get_text(struct _cef_textfield_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefTextfieldCppToC::Get(self)->GetText();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+void CEF_CALLBACK textfield_set_text(struct _cef_textfield_t* self,
+ const cef_string_t* text) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: text; type: string_byref_const
+ DCHECK(text);
+ if (!text) {
+ return;
+ }
+
+ // Execute
+ CefTextfieldCppToC::Get(self)->SetText(CefString(text));
+}
+
+void CEF_CALLBACK textfield_append_text(struct _cef_textfield_t* self,
+ const cef_string_t* text) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: text; type: string_byref_const
+ DCHECK(text);
+ if (!text) {
+ return;
+ }
+
+ // Execute
+ CefTextfieldCppToC::Get(self)->AppendText(CefString(text));
+}
+
+void CEF_CALLBACK
+textfield_insert_or_replace_text(struct _cef_textfield_t* self,
+ const cef_string_t* text) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: text; type: string_byref_const
+ DCHECK(text);
+ if (!text) {
+ return;
+ }
+
+ // Execute
+ CefTextfieldCppToC::Get(self)->InsertOrReplaceText(CefString(text));
+}
+
+int CEF_CALLBACK textfield_has_selection(struct _cef_textfield_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefTextfieldCppToC::Get(self)->HasSelection();
+
+ // Return type: bool
+ return _retval;
+}
+
+cef_string_userfree_t CEF_CALLBACK
+textfield_get_selected_text(struct _cef_textfield_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefTextfieldCppToC::Get(self)->GetSelectedText();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+void CEF_CALLBACK textfield_select_all(struct _cef_textfield_t* self,
+ int reversed) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefTextfieldCppToC::Get(self)->SelectAll(reversed ? true : false);
+}
+
+void CEF_CALLBACK textfield_clear_selection(struct _cef_textfield_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefTextfieldCppToC::Get(self)->ClearSelection();
+}
+
+cef_range_t CEF_CALLBACK
+textfield_get_selected_range(struct _cef_textfield_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefRange();
+ }
+
+ // Execute
+ cef_range_t _retval = CefTextfieldCppToC::Get(self)->GetSelectedRange();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK textfield_select_range(struct _cef_textfield_t* self,
+ const cef_range_t* range) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: range; type: simple_byref_const
+ DCHECK(range);
+ if (!range) {
+ return;
+ }
+
+ // Translate param: range; type: simple_byref_const
+ CefRange rangeVal = range ? *range : CefRange();
+
+ // Execute
+ CefTextfieldCppToC::Get(self)->SelectRange(rangeVal);
+}
+
+size_t CEF_CALLBACK
+textfield_get_cursor_position(struct _cef_textfield_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ size_t _retval = CefTextfieldCppToC::Get(self)->GetCursorPosition();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK textfield_set_text_color(struct _cef_textfield_t* self,
+ cef_color_t color) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefTextfieldCppToC::Get(self)->SetTextColor(color);
+}
+
+cef_color_t CEF_CALLBACK
+textfield_get_text_color(struct _cef_textfield_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ cef_color_t _retval = CefTextfieldCppToC::Get(self)->GetTextColor();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK
+textfield_set_selection_text_color(struct _cef_textfield_t* self,
+ cef_color_t color) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefTextfieldCppToC::Get(self)->SetSelectionTextColor(color);
+}
+
+cef_color_t CEF_CALLBACK
+textfield_get_selection_text_color(struct _cef_textfield_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ cef_color_t _retval = CefTextfieldCppToC::Get(self)->GetSelectionTextColor();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK
+textfield_set_selection_background_color(struct _cef_textfield_t* self,
+ cef_color_t color) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefTextfieldCppToC::Get(self)->SetSelectionBackgroundColor(color);
+}
+
+cef_color_t CEF_CALLBACK
+textfield_get_selection_background_color(struct _cef_textfield_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ cef_color_t _retval =
+ CefTextfieldCppToC::Get(self)->GetSelectionBackgroundColor();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK textfield_set_font_list(struct _cef_textfield_t* self,
+ const cef_string_t* font_list) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: font_list; type: string_byref_const
+ DCHECK(font_list);
+ if (!font_list) {
+ return;
+ }
+
+ // Execute
+ CefTextfieldCppToC::Get(self)->SetFontList(CefString(font_list));
+}
+
+void CEF_CALLBACK textfield_apply_text_color(struct _cef_textfield_t* self,
+ cef_color_t color,
+ const cef_range_t* range) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: range; type: simple_byref_const
+ DCHECK(range);
+ if (!range) {
+ return;
+ }
+
+ // Translate param: range; type: simple_byref_const
+ CefRange rangeVal = range ? *range : CefRange();
+
+ // Execute
+ CefTextfieldCppToC::Get(self)->ApplyTextColor(color, rangeVal);
+}
+
+void CEF_CALLBACK textfield_apply_text_style(struct _cef_textfield_t* self,
+ cef_text_style_t style,
+ int add,
+ const cef_range_t* range) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: range; type: simple_byref_const
+ DCHECK(range);
+ if (!range) {
+ return;
+ }
+
+ // Translate param: range; type: simple_byref_const
+ CefRange rangeVal = range ? *range : CefRange();
+
+ // Execute
+ CefTextfieldCppToC::Get(self)->ApplyTextStyle(style, add ? true : false,
+ rangeVal);
+}
+
+int CEF_CALLBACK
+textfield_is_command_enabled(struct _cef_textfield_t* self,
+ cef_text_field_commands_t command_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefTextfieldCppToC::Get(self)->IsCommandEnabled(command_id);
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK
+textfield_execute_command(struct _cef_textfield_t* self,
+ cef_text_field_commands_t command_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefTextfieldCppToC::Get(self)->ExecuteCommand(command_id);
+}
+
+void CEF_CALLBACK textfield_clear_edit_history(struct _cef_textfield_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefTextfieldCppToC::Get(self)->ClearEditHistory();
+}
+
+void CEF_CALLBACK textfield_set_placeholder_text(struct _cef_textfield_t* self,
+ const cef_string_t* text) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: text; type: string_byref_const
+ DCHECK(text);
+ if (!text) {
+ return;
+ }
+
+ // Execute
+ CefTextfieldCppToC::Get(self)->SetPlaceholderText(CefString(text));
+}
+
+cef_string_userfree_t CEF_CALLBACK
+textfield_get_placeholder_text(struct _cef_textfield_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefTextfieldCppToC::Get(self)->GetPlaceholderText();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+void CEF_CALLBACK
+textfield_set_placeholder_text_color(struct _cef_textfield_t* self,
+ cef_color_t color) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefTextfieldCppToC::Get(self)->SetPlaceholderTextColor(color);
+}
+
+void CEF_CALLBACK textfield_set_accessible_name(struct _cef_textfield_t* self,
+ const cef_string_t* name) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: name; type: string_byref_const
+ DCHECK(name);
+ if (!name) {
+ return;
+ }
+
+ // Execute
+ CefTextfieldCppToC::Get(self)->SetAccessibleName(CefString(name));
+}
+
+cef_browser_view_t* CEF_CALLBACK
+textfield_as_browser_view(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefBrowserView> _retval =
+ CefTextfieldCppToC::Get(reinterpret_cast<cef_textfield_t*>(self))
+ ->AsBrowserView();
+
+ // Return type: refptr_same
+ return CefBrowserViewCppToC::Wrap(_retval);
+}
+
+cef_button_t* CEF_CALLBACK textfield_as_button(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefButton> _retval =
+ CefTextfieldCppToC::Get(reinterpret_cast<cef_textfield_t*>(self))
+ ->AsButton();
+
+ // Return type: refptr_same
+ return CefButtonCppToC::Wrap(_retval);
+}
+
+cef_panel_t* CEF_CALLBACK textfield_as_panel(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefPanel> _retval =
+ CefTextfieldCppToC::Get(reinterpret_cast<cef_textfield_t*>(self))
+ ->AsPanel();
+
+ // Return type: refptr_same
+ return CefPanelCppToC::Wrap(_retval);
+}
+
+cef_scroll_view_t* CEF_CALLBACK
+textfield_as_scroll_view(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefScrollView> _retval =
+ CefTextfieldCppToC::Get(reinterpret_cast<cef_textfield_t*>(self))
+ ->AsScrollView();
+
+ // Return type: refptr_same
+ return CefScrollViewCppToC::Wrap(_retval);
+}
+
+cef_textfield_t* CEF_CALLBACK textfield_as_textfield(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefTextfield> _retval =
+ CefTextfieldCppToC::Get(reinterpret_cast<cef_textfield_t*>(self))
+ ->AsTextfield();
+
+ // Return type: refptr_same
+ return CefTextfieldCppToC::Wrap(_retval);
+}
+
+cef_string_userfree_t CEF_CALLBACK
+textfield_get_type_string(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval =
+ CefTextfieldCppToC::Get(reinterpret_cast<cef_textfield_t*>(self))
+ ->GetTypeString();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_string_userfree_t CEF_CALLBACK textfield_to_string(struct _cef_view_t* self,
+ int include_children) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval =
+ CefTextfieldCppToC::Get(reinterpret_cast<cef_textfield_t*>(self))
+ ->ToString(include_children ? true : false);
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+int CEF_CALLBACK textfield_is_valid(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefTextfieldCppToC::Get(reinterpret_cast<cef_textfield_t*>(self))
+ ->IsValid();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK textfield_is_attached(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefTextfieldCppToC::Get(reinterpret_cast<cef_textfield_t*>(self))
+ ->IsAttached();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK textfield_is_same(struct _cef_view_t* self,
+ struct _cef_view_t* that) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: that; type: refptr_same
+ DCHECK(that);
+ if (!that) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefTextfieldCppToC::Get(reinterpret_cast<cef_textfield_t*>(self))
+ ->IsSame(CefViewCppToC::Unwrap(that));
+
+ // Return type: bool
+ return _retval;
+}
+
+struct _cef_view_delegate_t* CEF_CALLBACK
+textfield_get_delegate(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefViewDelegate> _retval =
+ CefTextfieldCppToC::Get(reinterpret_cast<cef_textfield_t*>(self))
+ ->GetDelegate();
+
+ // Return type: refptr_diff
+ return CefViewDelegateCToCpp::Unwrap(_retval);
+}
+
+struct _cef_window_t* CEF_CALLBACK
+textfield_get_window(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefWindow> _retval =
+ CefTextfieldCppToC::Get(reinterpret_cast<cef_textfield_t*>(self))
+ ->GetWindow();
+
+ // Return type: refptr_same
+ return CefWindowCppToC::Wrap(_retval);
+}
+
+int CEF_CALLBACK textfield_get_id(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval =
+ CefTextfieldCppToC::Get(reinterpret_cast<cef_textfield_t*>(self))
+ ->GetID();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK textfield_set_id(struct _cef_view_t* self, int id) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefTextfieldCppToC::Get(reinterpret_cast<cef_textfield_t*>(self))->SetID(id);
+}
+
+int CEF_CALLBACK textfield_get_group_id(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval =
+ CefTextfieldCppToC::Get(reinterpret_cast<cef_textfield_t*>(self))
+ ->GetGroupID();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK textfield_set_group_id(struct _cef_view_t* self,
+ int group_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefTextfieldCppToC::Get(reinterpret_cast<cef_textfield_t*>(self))
+ ->SetGroupID(group_id);
+}
+
+struct _cef_view_t* CEF_CALLBACK
+textfield_get_parent_view(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefView> _retval =
+ CefTextfieldCppToC::Get(reinterpret_cast<cef_textfield_t*>(self))
+ ->GetParentView();
+
+ // Return type: refptr_same
+ return CefViewCppToC::Wrap(_retval);
+}
+
+struct _cef_view_t* CEF_CALLBACK
+textfield_get_view_for_id(struct _cef_view_t* self, int id) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefView> _retval =
+ CefTextfieldCppToC::Get(reinterpret_cast<cef_textfield_t*>(self))
+ ->GetViewForID(id);
+
+ // Return type: refptr_same
+ return CefViewCppToC::Wrap(_retval);
+}
+
+void CEF_CALLBACK textfield_set_bounds(struct _cef_view_t* self,
+ const cef_rect_t* bounds) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: bounds; type: simple_byref_const
+ DCHECK(bounds);
+ if (!bounds) {
+ return;
+ }
+
+ // Translate param: bounds; type: simple_byref_const
+ CefRect boundsVal = bounds ? *bounds : CefRect();
+
+ // Execute
+ CefTextfieldCppToC::Get(reinterpret_cast<cef_textfield_t*>(self))
+ ->SetBounds(boundsVal);
+}
+
+cef_rect_t CEF_CALLBACK textfield_get_bounds(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefRect();
+ }
+
+ // Execute
+ cef_rect_t _retval =
+ CefTextfieldCppToC::Get(reinterpret_cast<cef_textfield_t*>(self))
+ ->GetBounds();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_rect_t CEF_CALLBACK
+textfield_get_bounds_in_screen(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefRect();
+ }
+
+ // Execute
+ cef_rect_t _retval =
+ CefTextfieldCppToC::Get(reinterpret_cast<cef_textfield_t*>(self))
+ ->GetBoundsInScreen();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK textfield_set_size(struct _cef_view_t* self,
+ const cef_size_t* size) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: size; type: simple_byref_const
+ DCHECK(size);
+ if (!size) {
+ return;
+ }
+
+ // Translate param: size; type: simple_byref_const
+ CefSize sizeVal = size ? *size : CefSize();
+
+ // Execute
+ CefTextfieldCppToC::Get(reinterpret_cast<cef_textfield_t*>(self))
+ ->SetSize(sizeVal);
+}
+
+cef_size_t CEF_CALLBACK textfield_get_size(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval =
+ CefTextfieldCppToC::Get(reinterpret_cast<cef_textfield_t*>(self))
+ ->GetSize();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK textfield_set_position(struct _cef_view_t* self,
+ const cef_point_t* position) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: position; type: simple_byref_const
+ DCHECK(position);
+ if (!position) {
+ return;
+ }
+
+ // Translate param: position; type: simple_byref_const
+ CefPoint positionVal = position ? *position : CefPoint();
+
+ // Execute
+ CefTextfieldCppToC::Get(reinterpret_cast<cef_textfield_t*>(self))
+ ->SetPosition(positionVal);
+}
+
+cef_point_t CEF_CALLBACK textfield_get_position(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefPoint();
+ }
+
+ // Execute
+ cef_point_t _retval =
+ CefTextfieldCppToC::Get(reinterpret_cast<cef_textfield_t*>(self))
+ ->GetPosition();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK textfield_set_insets(struct _cef_view_t* self,
+ const cef_insets_t* insets) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: insets; type: simple_byref_const
+ DCHECK(insets);
+ if (!insets) {
+ return;
+ }
+
+ // Translate param: insets; type: simple_byref_const
+ CefInsets insetsVal = insets ? *insets : CefInsets();
+
+ // Execute
+ CefTextfieldCppToC::Get(reinterpret_cast<cef_textfield_t*>(self))
+ ->SetInsets(insetsVal);
+}
+
+cef_insets_t CEF_CALLBACK textfield_get_insets(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefInsets();
+ }
+
+ // Execute
+ cef_insets_t _retval =
+ CefTextfieldCppToC::Get(reinterpret_cast<cef_textfield_t*>(self))
+ ->GetInsets();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_size_t CEF_CALLBACK textfield_get_preferred_size(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval =
+ CefTextfieldCppToC::Get(reinterpret_cast<cef_textfield_t*>(self))
+ ->GetPreferredSize();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK textfield_size_to_preferred_size(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefTextfieldCppToC::Get(reinterpret_cast<cef_textfield_t*>(self))
+ ->SizeToPreferredSize();
+}
+
+cef_size_t CEF_CALLBACK textfield_get_minimum_size(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval =
+ CefTextfieldCppToC::Get(reinterpret_cast<cef_textfield_t*>(self))
+ ->GetMinimumSize();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_size_t CEF_CALLBACK textfield_get_maximum_size(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval =
+ CefTextfieldCppToC::Get(reinterpret_cast<cef_textfield_t*>(self))
+ ->GetMaximumSize();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK textfield_get_height_for_width(struct _cef_view_t* self,
+ int width) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval =
+ CefTextfieldCppToC::Get(reinterpret_cast<cef_textfield_t*>(self))
+ ->GetHeightForWidth(width);
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK textfield_invalidate_layout(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefTextfieldCppToC::Get(reinterpret_cast<cef_textfield_t*>(self))
+ ->InvalidateLayout();
+}
+
+void CEF_CALLBACK textfield_set_visible(struct _cef_view_t* self, int visible) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefTextfieldCppToC::Get(reinterpret_cast<cef_textfield_t*>(self))
+ ->SetVisible(visible ? true : false);
+}
+
+int CEF_CALLBACK textfield_is_visible(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefTextfieldCppToC::Get(reinterpret_cast<cef_textfield_t*>(self))
+ ->IsVisible();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK textfield_is_drawn(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefTextfieldCppToC::Get(reinterpret_cast<cef_textfield_t*>(self))
+ ->IsDrawn();
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK textfield_set_enabled(struct _cef_view_t* self, int enabled) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefTextfieldCppToC::Get(reinterpret_cast<cef_textfield_t*>(self))
+ ->SetEnabled(enabled ? true : false);
+}
+
+int CEF_CALLBACK textfield_is_enabled(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefTextfieldCppToC::Get(reinterpret_cast<cef_textfield_t*>(self))
+ ->IsEnabled();
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK textfield_set_focusable(struct _cef_view_t* self,
+ int focusable) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefTextfieldCppToC::Get(reinterpret_cast<cef_textfield_t*>(self))
+ ->SetFocusable(focusable ? true : false);
+}
+
+int CEF_CALLBACK textfield_is_focusable(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefTextfieldCppToC::Get(reinterpret_cast<cef_textfield_t*>(self))
+ ->IsFocusable();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+textfield_is_accessibility_focusable(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefTextfieldCppToC::Get(reinterpret_cast<cef_textfield_t*>(self))
+ ->IsAccessibilityFocusable();
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK textfield_request_focus(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefTextfieldCppToC::Get(reinterpret_cast<cef_textfield_t*>(self))
+ ->RequestFocus();
+}
+
+void CEF_CALLBACK textfield_set_background_color(struct _cef_view_t* self,
+ cef_color_t color) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefTextfieldCppToC::Get(reinterpret_cast<cef_textfield_t*>(self))
+ ->SetBackgroundColor(color);
+}
+
+cef_color_t CEF_CALLBACK
+textfield_get_background_color(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ cef_color_t _retval =
+ CefTextfieldCppToC::Get(reinterpret_cast<cef_textfield_t*>(self))
+ ->GetBackgroundColor();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK textfield_convert_point_to_screen(struct _cef_view_t* self,
+ cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: point; type: simple_byref
+ DCHECK(point);
+ if (!point) {
+ return 0;
+ }
+
+ // Translate param: point; type: simple_byref
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ bool _retval =
+ CefTextfieldCppToC::Get(reinterpret_cast<cef_textfield_t*>(self))
+ ->ConvertPointToScreen(pointVal);
+
+ // Restore param: point; type: simple_byref
+ if (point) {
+ *point = pointVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK textfield_convert_point_from_screen(struct _cef_view_t* self,
+ cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: point; type: simple_byref
+ DCHECK(point);
+ if (!point) {
+ return 0;
+ }
+
+ // Translate param: point; type: simple_byref
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ bool _retval =
+ CefTextfieldCppToC::Get(reinterpret_cast<cef_textfield_t*>(self))
+ ->ConvertPointFromScreen(pointVal);
+
+ // Restore param: point; type: simple_byref
+ if (point) {
+ *point = pointVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK textfield_convert_point_to_window(struct _cef_view_t* self,
+ cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: point; type: simple_byref
+ DCHECK(point);
+ if (!point) {
+ return 0;
+ }
+
+ // Translate param: point; type: simple_byref
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ bool _retval =
+ CefTextfieldCppToC::Get(reinterpret_cast<cef_textfield_t*>(self))
+ ->ConvertPointToWindow(pointVal);
+
+ // Restore param: point; type: simple_byref
+ if (point) {
+ *point = pointVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK textfield_convert_point_from_window(struct _cef_view_t* self,
+ cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: point; type: simple_byref
+ DCHECK(point);
+ if (!point) {
+ return 0;
+ }
+
+ // Translate param: point; type: simple_byref
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ bool _retval =
+ CefTextfieldCppToC::Get(reinterpret_cast<cef_textfield_t*>(self))
+ ->ConvertPointFromWindow(pointVal);
+
+ // Restore param: point; type: simple_byref
+ if (point) {
+ *point = pointVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK textfield_convert_point_to_view(struct _cef_view_t* self,
+ struct _cef_view_t* view,
+ cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: view; type: refptr_same
+ DCHECK(view);
+ if (!view) {
+ return 0;
+ }
+ // Verify param: point; type: simple_byref
+ DCHECK(point);
+ if (!point) {
+ return 0;
+ }
+
+ // Translate param: point; type: simple_byref
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ bool _retval =
+ CefTextfieldCppToC::Get(reinterpret_cast<cef_textfield_t*>(self))
+ ->ConvertPointToView(CefViewCppToC::Unwrap(view), pointVal);
+
+ // Restore param: point; type: simple_byref
+ if (point) {
+ *point = pointVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK textfield_convert_point_from_view(struct _cef_view_t* self,
+ struct _cef_view_t* view,
+ cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: view; type: refptr_same
+ DCHECK(view);
+ if (!view) {
+ return 0;
+ }
+ // Verify param: point; type: simple_byref
+ DCHECK(point);
+ if (!point) {
+ return 0;
+ }
+
+ // Translate param: point; type: simple_byref
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ bool _retval =
+ CefTextfieldCppToC::Get(reinterpret_cast<cef_textfield_t*>(self))
+ ->ConvertPointFromView(CefViewCppToC::Unwrap(view), pointVal);
+
+ // Restore param: point; type: simple_byref
+ if (point) {
+ *point = pointVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefTextfieldCppToC::CefTextfieldCppToC() {
+ GetStruct()->set_password_input = textfield_set_password_input;
+ GetStruct()->is_password_input = textfield_is_password_input;
+ GetStruct()->set_read_only = textfield_set_read_only;
+ GetStruct()->is_read_only = textfield_is_read_only;
+ GetStruct()->get_text = textfield_get_text;
+ GetStruct()->set_text = textfield_set_text;
+ GetStruct()->append_text = textfield_append_text;
+ GetStruct()->insert_or_replace_text = textfield_insert_or_replace_text;
+ GetStruct()->has_selection = textfield_has_selection;
+ GetStruct()->get_selected_text = textfield_get_selected_text;
+ GetStruct()->select_all = textfield_select_all;
+ GetStruct()->clear_selection = textfield_clear_selection;
+ GetStruct()->get_selected_range = textfield_get_selected_range;
+ GetStruct()->select_range = textfield_select_range;
+ GetStruct()->get_cursor_position = textfield_get_cursor_position;
+ GetStruct()->set_text_color = textfield_set_text_color;
+ GetStruct()->get_text_color = textfield_get_text_color;
+ GetStruct()->set_selection_text_color = textfield_set_selection_text_color;
+ GetStruct()->get_selection_text_color = textfield_get_selection_text_color;
+ GetStruct()->set_selection_background_color =
+ textfield_set_selection_background_color;
+ GetStruct()->get_selection_background_color =
+ textfield_get_selection_background_color;
+ GetStruct()->set_font_list = textfield_set_font_list;
+ GetStruct()->apply_text_color = textfield_apply_text_color;
+ GetStruct()->apply_text_style = textfield_apply_text_style;
+ GetStruct()->is_command_enabled = textfield_is_command_enabled;
+ GetStruct()->execute_command = textfield_execute_command;
+ GetStruct()->clear_edit_history = textfield_clear_edit_history;
+ GetStruct()->set_placeholder_text = textfield_set_placeholder_text;
+ GetStruct()->get_placeholder_text = textfield_get_placeholder_text;
+ GetStruct()->set_placeholder_text_color =
+ textfield_set_placeholder_text_color;
+ GetStruct()->set_accessible_name = textfield_set_accessible_name;
+ GetStruct()->base.as_browser_view = textfield_as_browser_view;
+ GetStruct()->base.as_button = textfield_as_button;
+ GetStruct()->base.as_panel = textfield_as_panel;
+ GetStruct()->base.as_scroll_view = textfield_as_scroll_view;
+ GetStruct()->base.as_textfield = textfield_as_textfield;
+ GetStruct()->base.get_type_string = textfield_get_type_string;
+ GetStruct()->base.to_string = textfield_to_string;
+ GetStruct()->base.is_valid = textfield_is_valid;
+ GetStruct()->base.is_attached = textfield_is_attached;
+ GetStruct()->base.is_same = textfield_is_same;
+ GetStruct()->base.get_delegate = textfield_get_delegate;
+ GetStruct()->base.get_window = textfield_get_window;
+ GetStruct()->base.get_id = textfield_get_id;
+ GetStruct()->base.set_id = textfield_set_id;
+ GetStruct()->base.get_group_id = textfield_get_group_id;
+ GetStruct()->base.set_group_id = textfield_set_group_id;
+ GetStruct()->base.get_parent_view = textfield_get_parent_view;
+ GetStruct()->base.get_view_for_id = textfield_get_view_for_id;
+ GetStruct()->base.set_bounds = textfield_set_bounds;
+ GetStruct()->base.get_bounds = textfield_get_bounds;
+ GetStruct()->base.get_bounds_in_screen = textfield_get_bounds_in_screen;
+ GetStruct()->base.set_size = textfield_set_size;
+ GetStruct()->base.get_size = textfield_get_size;
+ GetStruct()->base.set_position = textfield_set_position;
+ GetStruct()->base.get_position = textfield_get_position;
+ GetStruct()->base.set_insets = textfield_set_insets;
+ GetStruct()->base.get_insets = textfield_get_insets;
+ GetStruct()->base.get_preferred_size = textfield_get_preferred_size;
+ GetStruct()->base.size_to_preferred_size = textfield_size_to_preferred_size;
+ GetStruct()->base.get_minimum_size = textfield_get_minimum_size;
+ GetStruct()->base.get_maximum_size = textfield_get_maximum_size;
+ GetStruct()->base.get_height_for_width = textfield_get_height_for_width;
+ GetStruct()->base.invalidate_layout = textfield_invalidate_layout;
+ GetStruct()->base.set_visible = textfield_set_visible;
+ GetStruct()->base.is_visible = textfield_is_visible;
+ GetStruct()->base.is_drawn = textfield_is_drawn;
+ GetStruct()->base.set_enabled = textfield_set_enabled;
+ GetStruct()->base.is_enabled = textfield_is_enabled;
+ GetStruct()->base.set_focusable = textfield_set_focusable;
+ GetStruct()->base.is_focusable = textfield_is_focusable;
+ GetStruct()->base.is_accessibility_focusable =
+ textfield_is_accessibility_focusable;
+ GetStruct()->base.request_focus = textfield_request_focus;
+ GetStruct()->base.set_background_color = textfield_set_background_color;
+ GetStruct()->base.get_background_color = textfield_get_background_color;
+ GetStruct()->base.convert_point_to_screen = textfield_convert_point_to_screen;
+ GetStruct()->base.convert_point_from_screen =
+ textfield_convert_point_from_screen;
+ GetStruct()->base.convert_point_to_window = textfield_convert_point_to_window;
+ GetStruct()->base.convert_point_from_window =
+ textfield_convert_point_from_window;
+ GetStruct()->base.convert_point_to_view = textfield_convert_point_to_view;
+ GetStruct()->base.convert_point_from_view = textfield_convert_point_from_view;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefTextfieldCppToC::~CefTextfieldCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefTextfield>
+CefCppToCRefCounted<CefTextfieldCppToC, CefTextfield, cef_textfield_t>::
+ UnwrapDerived(CefWrapperType type, cef_textfield_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefTextfieldCppToC,
+ CefTextfield,
+ cef_textfield_t>::kWrapperType =
+ WT_TEXTFIELD;
diff --git a/libcef_dll/cpptoc/views/textfield_cpptoc.h b/libcef_dll/cpptoc/views/textfield_cpptoc.h
new file mode 100644
index 00000000..79083530
--- /dev/null
+++ b/libcef_dll/cpptoc/views/textfield_cpptoc.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=0b5018c0b9d42f4ee100098365c46e0ea723ea29$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_VIEWS_TEXTFIELD_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_VIEWS_TEXTFIELD_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/views/cef_textfield_capi.h"
+#include "include/views/cef_textfield.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefTextfieldCppToC : public CefCppToCRefCounted<CefTextfieldCppToC,
+ CefTextfield,
+ cef_textfield_t> {
+ public:
+ CefTextfieldCppToC();
+ virtual ~CefTextfieldCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_VIEWS_TEXTFIELD_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/views/textfield_delegate_cpptoc.cc b/libcef_dll/cpptoc/views/textfield_delegate_cpptoc.cc
new file mode 100644
index 00000000..7f644edc
--- /dev/null
+++ b/libcef_dll/cpptoc/views/textfield_delegate_cpptoc.cc
@@ -0,0 +1,389 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=00fd32a1d0bf034760f3afe3fb62ba58aba6a61b$
+//
+
+#include "libcef_dll/cpptoc/views/textfield_delegate_cpptoc.h"
+#include "libcef_dll/ctocpp/views/textfield_ctocpp.h"
+#include "libcef_dll/ctocpp/views/view_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK
+textfield_delegate_on_key_event(struct _cef_textfield_delegate_t* self,
+ cef_textfield_t* textfield,
+ const cef_key_event_t* event) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: textfield; type: refptr_diff
+ DCHECK(textfield);
+ if (!textfield) {
+ return 0;
+ }
+ // Verify param: event; type: simple_byref_const
+ DCHECK(event);
+ if (!event) {
+ return 0;
+ }
+
+ // Translate param: event; type: simple_byref_const
+ CefKeyEvent eventVal = event ? *event : CefKeyEvent();
+
+ // Execute
+ bool _retval = CefTextfieldDelegateCppToC::Get(self)->OnKeyEvent(
+ CefTextfieldCToCpp::Wrap(textfield), eventVal);
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK
+textfield_delegate_on_after_user_action(struct _cef_textfield_delegate_t* self,
+ cef_textfield_t* textfield) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: textfield; type: refptr_diff
+ DCHECK(textfield);
+ if (!textfield) {
+ return;
+ }
+
+ // Execute
+ CefTextfieldDelegateCppToC::Get(self)->OnAfterUserAction(
+ CefTextfieldCToCpp::Wrap(textfield));
+}
+
+cef_size_t CEF_CALLBACK
+textfield_delegate_get_preferred_size(struct _cef_view_delegate_t* self,
+ cef_view_t* view) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval = CefTextfieldDelegateCppToC::Get(
+ reinterpret_cast<cef_textfield_delegate_t*>(self))
+ ->GetPreferredSize(CefViewCToCpp::Wrap(view));
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_size_t CEF_CALLBACK
+textfield_delegate_get_minimum_size(struct _cef_view_delegate_t* self,
+ cef_view_t* view) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval = CefTextfieldDelegateCppToC::Get(
+ reinterpret_cast<cef_textfield_delegate_t*>(self))
+ ->GetMinimumSize(CefViewCToCpp::Wrap(view));
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_size_t CEF_CALLBACK
+textfield_delegate_get_maximum_size(struct _cef_view_delegate_t* self,
+ cef_view_t* view) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval = CefTextfieldDelegateCppToC::Get(
+ reinterpret_cast<cef_textfield_delegate_t*>(self))
+ ->GetMaximumSize(CefViewCToCpp::Wrap(view));
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK
+textfield_delegate_get_height_for_width(struct _cef_view_delegate_t* self,
+ cef_view_t* view,
+ int width) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefTextfieldDelegateCppToC::Get(
+ reinterpret_cast<cef_textfield_delegate_t*>(self))
+ ->GetHeightForWidth(CefViewCToCpp::Wrap(view), width);
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK
+textfield_delegate_on_parent_view_changed(struct _cef_view_delegate_t* self,
+ cef_view_t* view,
+ int added,
+ cef_view_t* parent) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return;
+ }
+ // Verify param: parent; type: refptr_diff
+ DCHECK(parent);
+ if (!parent) {
+ return;
+ }
+
+ // Execute
+ CefTextfieldDelegateCppToC::Get(
+ reinterpret_cast<cef_textfield_delegate_t*>(self))
+ ->OnParentViewChanged(CefViewCToCpp::Wrap(view), added ? true : false,
+ CefViewCToCpp::Wrap(parent));
+}
+
+void CEF_CALLBACK
+textfield_delegate_on_child_view_changed(struct _cef_view_delegate_t* self,
+ cef_view_t* view,
+ int added,
+ cef_view_t* child) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return;
+ }
+ // Verify param: child; type: refptr_diff
+ DCHECK(child);
+ if (!child) {
+ return;
+ }
+
+ // Execute
+ CefTextfieldDelegateCppToC::Get(
+ reinterpret_cast<cef_textfield_delegate_t*>(self))
+ ->OnChildViewChanged(CefViewCToCpp::Wrap(view), added ? true : false,
+ CefViewCToCpp::Wrap(child));
+}
+
+void CEF_CALLBACK
+textfield_delegate_on_window_changed(struct _cef_view_delegate_t* self,
+ cef_view_t* view,
+ int added) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return;
+ }
+
+ // Execute
+ CefTextfieldDelegateCppToC::Get(
+ reinterpret_cast<cef_textfield_delegate_t*>(self))
+ ->OnWindowChanged(CefViewCToCpp::Wrap(view), added ? true : false);
+}
+
+void CEF_CALLBACK
+textfield_delegate_on_layout_changed(struct _cef_view_delegate_t* self,
+ cef_view_t* view,
+ const cef_rect_t* new_bounds) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return;
+ }
+ // Verify param: new_bounds; type: simple_byref_const
+ DCHECK(new_bounds);
+ if (!new_bounds) {
+ return;
+ }
+
+ // Translate param: new_bounds; type: simple_byref_const
+ CefRect new_boundsVal = new_bounds ? *new_bounds : CefRect();
+
+ // Execute
+ CefTextfieldDelegateCppToC::Get(
+ reinterpret_cast<cef_textfield_delegate_t*>(self))
+ ->OnLayoutChanged(CefViewCToCpp::Wrap(view), new_boundsVal);
+}
+
+void CEF_CALLBACK textfield_delegate_on_focus(struct _cef_view_delegate_t* self,
+ cef_view_t* view) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return;
+ }
+
+ // Execute
+ CefTextfieldDelegateCppToC::Get(
+ reinterpret_cast<cef_textfield_delegate_t*>(self))
+ ->OnFocus(CefViewCToCpp::Wrap(view));
+}
+
+void CEF_CALLBACK textfield_delegate_on_blur(struct _cef_view_delegate_t* self,
+ cef_view_t* view) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return;
+ }
+
+ // Execute
+ CefTextfieldDelegateCppToC::Get(
+ reinterpret_cast<cef_textfield_delegate_t*>(self))
+ ->OnBlur(CefViewCToCpp::Wrap(view));
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefTextfieldDelegateCppToC::CefTextfieldDelegateCppToC() {
+ GetStruct()->on_key_event = textfield_delegate_on_key_event;
+ GetStruct()->on_after_user_action = textfield_delegate_on_after_user_action;
+ GetStruct()->base.get_preferred_size = textfield_delegate_get_preferred_size;
+ GetStruct()->base.get_minimum_size = textfield_delegate_get_minimum_size;
+ GetStruct()->base.get_maximum_size = textfield_delegate_get_maximum_size;
+ GetStruct()->base.get_height_for_width =
+ textfield_delegate_get_height_for_width;
+ GetStruct()->base.on_parent_view_changed =
+ textfield_delegate_on_parent_view_changed;
+ GetStruct()->base.on_child_view_changed =
+ textfield_delegate_on_child_view_changed;
+ GetStruct()->base.on_window_changed = textfield_delegate_on_window_changed;
+ GetStruct()->base.on_layout_changed = textfield_delegate_on_layout_changed;
+ GetStruct()->base.on_focus = textfield_delegate_on_focus;
+ GetStruct()->base.on_blur = textfield_delegate_on_blur;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefTextfieldDelegateCppToC::~CefTextfieldDelegateCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefTextfieldDelegate> CefCppToCRefCounted<
+ CefTextfieldDelegateCppToC,
+ CefTextfieldDelegate,
+ cef_textfield_delegate_t>::UnwrapDerived(CefWrapperType type,
+ cef_textfield_delegate_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefTextfieldDelegateCppToC,
+ CefTextfieldDelegate,
+ cef_textfield_delegate_t>::kWrapperType =
+ WT_TEXTFIELD_DELEGATE;
diff --git a/libcef_dll/cpptoc/views/textfield_delegate_cpptoc.h b/libcef_dll/cpptoc/views/textfield_delegate_cpptoc.h
new file mode 100644
index 00000000..2ad4735f
--- /dev/null
+++ b/libcef_dll/cpptoc/views/textfield_delegate_cpptoc.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=33ba2bd44c946bf204f2f7a929b8d208768ca3dd$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_VIEWS_TEXTFIELD_DELEGATE_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_VIEWS_TEXTFIELD_DELEGATE_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/views/cef_textfield_capi.h"
+#include "include/capi/views/cef_textfield_delegate_capi.h"
+#include "include/views/cef_textfield.h"
+#include "include/views/cef_textfield_delegate.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefTextfieldDelegateCppToC
+ : public CefCppToCRefCounted<CefTextfieldDelegateCppToC,
+ CefTextfieldDelegate,
+ cef_textfield_delegate_t> {
+ public:
+ CefTextfieldDelegateCppToC();
+ virtual ~CefTextfieldDelegateCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_VIEWS_TEXTFIELD_DELEGATE_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/views/view_cpptoc.cc b/libcef_dll/cpptoc/views/view_cpptoc.cc
new file mode 100644
index 00000000..60d9affc
--- /dev/null
+++ b/libcef_dll/cpptoc/views/view_cpptoc.cc
@@ -0,0 +1,1092 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=13c90ba22a371d972974229f18f87f407e552102$
+//
+
+#include "libcef_dll/cpptoc/views/view_cpptoc.h"
+#include "libcef_dll/cpptoc/views/browser_view_cpptoc.h"
+#include "libcef_dll/cpptoc/views/button_cpptoc.h"
+#include "libcef_dll/cpptoc/views/label_button_cpptoc.h"
+#include "libcef_dll/cpptoc/views/menu_button_cpptoc.h"
+#include "libcef_dll/cpptoc/views/panel_cpptoc.h"
+#include "libcef_dll/cpptoc/views/scroll_view_cpptoc.h"
+#include "libcef_dll/cpptoc/views/textfield_cpptoc.h"
+#include "libcef_dll/cpptoc/views/window_cpptoc.h"
+#include "libcef_dll/ctocpp/views/view_delegate_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+cef_browser_view_t* CEF_CALLBACK
+view_as_browser_view(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefBrowserView> _retval = CefViewCppToC::Get(self)->AsBrowserView();
+
+ // Return type: refptr_same
+ return CefBrowserViewCppToC::Wrap(_retval);
+}
+
+cef_button_t* CEF_CALLBACK view_as_button(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefButton> _retval = CefViewCppToC::Get(self)->AsButton();
+
+ // Return type: refptr_same
+ return CefButtonCppToC::Wrap(_retval);
+}
+
+cef_panel_t* CEF_CALLBACK view_as_panel(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefPanel> _retval = CefViewCppToC::Get(self)->AsPanel();
+
+ // Return type: refptr_same
+ return CefPanelCppToC::Wrap(_retval);
+}
+
+cef_scroll_view_t* CEF_CALLBACK view_as_scroll_view(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefScrollView> _retval = CefViewCppToC::Get(self)->AsScrollView();
+
+ // Return type: refptr_same
+ return CefScrollViewCppToC::Wrap(_retval);
+}
+
+cef_textfield_t* CEF_CALLBACK view_as_textfield(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefTextfield> _retval = CefViewCppToC::Get(self)->AsTextfield();
+
+ // Return type: refptr_same
+ return CefTextfieldCppToC::Wrap(_retval);
+}
+
+cef_string_userfree_t CEF_CALLBACK
+view_get_type_string(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefViewCppToC::Get(self)->GetTypeString();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_string_userfree_t CEF_CALLBACK view_to_string(struct _cef_view_t* self,
+ int include_children) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval =
+ CefViewCppToC::Get(self)->ToString(include_children ? true : false);
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+int CEF_CALLBACK view_is_valid(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefViewCppToC::Get(self)->IsValid();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK view_is_attached(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefViewCppToC::Get(self)->IsAttached();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK view_is_same(struct _cef_view_t* self,
+ struct _cef_view_t* that) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: that; type: refptr_same
+ DCHECK(that);
+ if (!that) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefViewCppToC::Get(self)->IsSame(CefViewCppToC::Unwrap(that));
+
+ // Return type: bool
+ return _retval;
+}
+
+struct _cef_view_delegate_t* CEF_CALLBACK
+view_get_delegate(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefViewDelegate> _retval = CefViewCppToC::Get(self)->GetDelegate();
+
+ // Return type: refptr_diff
+ return CefViewDelegateCToCpp::Unwrap(_retval);
+}
+
+struct _cef_window_t* CEF_CALLBACK view_get_window(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefWindow> _retval = CefViewCppToC::Get(self)->GetWindow();
+
+ // Return type: refptr_same
+ return CefWindowCppToC::Wrap(_retval);
+}
+
+int CEF_CALLBACK view_get_id(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefViewCppToC::Get(self)->GetID();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK view_set_id(struct _cef_view_t* self, int id) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefViewCppToC::Get(self)->SetID(id);
+}
+
+int CEF_CALLBACK view_get_group_id(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefViewCppToC::Get(self)->GetGroupID();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK view_set_group_id(struct _cef_view_t* self, int group_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefViewCppToC::Get(self)->SetGroupID(group_id);
+}
+
+struct _cef_view_t* CEF_CALLBACK
+view_get_parent_view(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefView> _retval = CefViewCppToC::Get(self)->GetParentView();
+
+ // Return type: refptr_same
+ return CefViewCppToC::Wrap(_retval);
+}
+
+struct _cef_view_t* CEF_CALLBACK view_get_view_for_id(struct _cef_view_t* self,
+ int id) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefView> _retval = CefViewCppToC::Get(self)->GetViewForID(id);
+
+ // Return type: refptr_same
+ return CefViewCppToC::Wrap(_retval);
+}
+
+void CEF_CALLBACK view_set_bounds(struct _cef_view_t* self,
+ const cef_rect_t* bounds) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: bounds; type: simple_byref_const
+ DCHECK(bounds);
+ if (!bounds) {
+ return;
+ }
+
+ // Translate param: bounds; type: simple_byref_const
+ CefRect boundsVal = bounds ? *bounds : CefRect();
+
+ // Execute
+ CefViewCppToC::Get(self)->SetBounds(boundsVal);
+}
+
+cef_rect_t CEF_CALLBACK view_get_bounds(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefRect();
+ }
+
+ // Execute
+ cef_rect_t _retval = CefViewCppToC::Get(self)->GetBounds();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_rect_t CEF_CALLBACK view_get_bounds_in_screen(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefRect();
+ }
+
+ // Execute
+ cef_rect_t _retval = CefViewCppToC::Get(self)->GetBoundsInScreen();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK view_set_size(struct _cef_view_t* self,
+ const cef_size_t* size) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: size; type: simple_byref_const
+ DCHECK(size);
+ if (!size) {
+ return;
+ }
+
+ // Translate param: size; type: simple_byref_const
+ CefSize sizeVal = size ? *size : CefSize();
+
+ // Execute
+ CefViewCppToC::Get(self)->SetSize(sizeVal);
+}
+
+cef_size_t CEF_CALLBACK view_get_size(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval = CefViewCppToC::Get(self)->GetSize();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK view_set_position(struct _cef_view_t* self,
+ const cef_point_t* position) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: position; type: simple_byref_const
+ DCHECK(position);
+ if (!position) {
+ return;
+ }
+
+ // Translate param: position; type: simple_byref_const
+ CefPoint positionVal = position ? *position : CefPoint();
+
+ // Execute
+ CefViewCppToC::Get(self)->SetPosition(positionVal);
+}
+
+cef_point_t CEF_CALLBACK view_get_position(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefPoint();
+ }
+
+ // Execute
+ cef_point_t _retval = CefViewCppToC::Get(self)->GetPosition();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK view_set_insets(struct _cef_view_t* self,
+ const cef_insets_t* insets) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: insets; type: simple_byref_const
+ DCHECK(insets);
+ if (!insets) {
+ return;
+ }
+
+ // Translate param: insets; type: simple_byref_const
+ CefInsets insetsVal = insets ? *insets : CefInsets();
+
+ // Execute
+ CefViewCppToC::Get(self)->SetInsets(insetsVal);
+}
+
+cef_insets_t CEF_CALLBACK view_get_insets(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefInsets();
+ }
+
+ // Execute
+ cef_insets_t _retval = CefViewCppToC::Get(self)->GetInsets();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_size_t CEF_CALLBACK view_get_preferred_size(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval = CefViewCppToC::Get(self)->GetPreferredSize();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK view_size_to_preferred_size(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefViewCppToC::Get(self)->SizeToPreferredSize();
+}
+
+cef_size_t CEF_CALLBACK view_get_minimum_size(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval = CefViewCppToC::Get(self)->GetMinimumSize();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_size_t CEF_CALLBACK view_get_maximum_size(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval = CefViewCppToC::Get(self)->GetMaximumSize();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK view_get_height_for_width(struct _cef_view_t* self,
+ int width) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefViewCppToC::Get(self)->GetHeightForWidth(width);
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK view_invalidate_layout(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefViewCppToC::Get(self)->InvalidateLayout();
+}
+
+void CEF_CALLBACK view_set_visible(struct _cef_view_t* self, int visible) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefViewCppToC::Get(self)->SetVisible(visible ? true : false);
+}
+
+int CEF_CALLBACK view_is_visible(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefViewCppToC::Get(self)->IsVisible();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK view_is_drawn(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefViewCppToC::Get(self)->IsDrawn();
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK view_set_enabled(struct _cef_view_t* self, int enabled) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefViewCppToC::Get(self)->SetEnabled(enabled ? true : false);
+}
+
+int CEF_CALLBACK view_is_enabled(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefViewCppToC::Get(self)->IsEnabled();
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK view_set_focusable(struct _cef_view_t* self, int focusable) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefViewCppToC::Get(self)->SetFocusable(focusable ? true : false);
+}
+
+int CEF_CALLBACK view_is_focusable(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefViewCppToC::Get(self)->IsFocusable();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK view_is_accessibility_focusable(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefViewCppToC::Get(self)->IsAccessibilityFocusable();
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK view_request_focus(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefViewCppToC::Get(self)->RequestFocus();
+}
+
+void CEF_CALLBACK view_set_background_color(struct _cef_view_t* self,
+ cef_color_t color) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefViewCppToC::Get(self)->SetBackgroundColor(color);
+}
+
+cef_color_t CEF_CALLBACK view_get_background_color(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ cef_color_t _retval = CefViewCppToC::Get(self)->GetBackgroundColor();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK view_convert_point_to_screen(struct _cef_view_t* self,
+ cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: point; type: simple_byref
+ DCHECK(point);
+ if (!point) {
+ return 0;
+ }
+
+ // Translate param: point; type: simple_byref
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ bool _retval = CefViewCppToC::Get(self)->ConvertPointToScreen(pointVal);
+
+ // Restore param: point; type: simple_byref
+ if (point) {
+ *point = pointVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK view_convert_point_from_screen(struct _cef_view_t* self,
+ cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: point; type: simple_byref
+ DCHECK(point);
+ if (!point) {
+ return 0;
+ }
+
+ // Translate param: point; type: simple_byref
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ bool _retval = CefViewCppToC::Get(self)->ConvertPointFromScreen(pointVal);
+
+ // Restore param: point; type: simple_byref
+ if (point) {
+ *point = pointVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK view_convert_point_to_window(struct _cef_view_t* self,
+ cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: point; type: simple_byref
+ DCHECK(point);
+ if (!point) {
+ return 0;
+ }
+
+ // Translate param: point; type: simple_byref
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ bool _retval = CefViewCppToC::Get(self)->ConvertPointToWindow(pointVal);
+
+ // Restore param: point; type: simple_byref
+ if (point) {
+ *point = pointVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK view_convert_point_from_window(struct _cef_view_t* self,
+ cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: point; type: simple_byref
+ DCHECK(point);
+ if (!point) {
+ return 0;
+ }
+
+ // Translate param: point; type: simple_byref
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ bool _retval = CefViewCppToC::Get(self)->ConvertPointFromWindow(pointVal);
+
+ // Restore param: point; type: simple_byref
+ if (point) {
+ *point = pointVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK view_convert_point_to_view(struct _cef_view_t* self,
+ struct _cef_view_t* view,
+ cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: view; type: refptr_same
+ DCHECK(view);
+ if (!view) {
+ return 0;
+ }
+ // Verify param: point; type: simple_byref
+ DCHECK(point);
+ if (!point) {
+ return 0;
+ }
+
+ // Translate param: point; type: simple_byref
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ bool _retval = CefViewCppToC::Get(self)->ConvertPointToView(
+ CefViewCppToC::Unwrap(view), pointVal);
+
+ // Restore param: point; type: simple_byref
+ if (point) {
+ *point = pointVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK view_convert_point_from_view(struct _cef_view_t* self,
+ struct _cef_view_t* view,
+ cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: view; type: refptr_same
+ DCHECK(view);
+ if (!view) {
+ return 0;
+ }
+ // Verify param: point; type: simple_byref
+ DCHECK(point);
+ if (!point) {
+ return 0;
+ }
+
+ // Translate param: point; type: simple_byref
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ bool _retval = CefViewCppToC::Get(self)->ConvertPointFromView(
+ CefViewCppToC::Unwrap(view), pointVal);
+
+ // Restore param: point; type: simple_byref
+ if (point) {
+ *point = pointVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefViewCppToC::CefViewCppToC() {
+ GetStruct()->as_browser_view = view_as_browser_view;
+ GetStruct()->as_button = view_as_button;
+ GetStruct()->as_panel = view_as_panel;
+ GetStruct()->as_scroll_view = view_as_scroll_view;
+ GetStruct()->as_textfield = view_as_textfield;
+ GetStruct()->get_type_string = view_get_type_string;
+ GetStruct()->to_string = view_to_string;
+ GetStruct()->is_valid = view_is_valid;
+ GetStruct()->is_attached = view_is_attached;
+ GetStruct()->is_same = view_is_same;
+ GetStruct()->get_delegate = view_get_delegate;
+ GetStruct()->get_window = view_get_window;
+ GetStruct()->get_id = view_get_id;
+ GetStruct()->set_id = view_set_id;
+ GetStruct()->get_group_id = view_get_group_id;
+ GetStruct()->set_group_id = view_set_group_id;
+ GetStruct()->get_parent_view = view_get_parent_view;
+ GetStruct()->get_view_for_id = view_get_view_for_id;
+ GetStruct()->set_bounds = view_set_bounds;
+ GetStruct()->get_bounds = view_get_bounds;
+ GetStruct()->get_bounds_in_screen = view_get_bounds_in_screen;
+ GetStruct()->set_size = view_set_size;
+ GetStruct()->get_size = view_get_size;
+ GetStruct()->set_position = view_set_position;
+ GetStruct()->get_position = view_get_position;
+ GetStruct()->set_insets = view_set_insets;
+ GetStruct()->get_insets = view_get_insets;
+ GetStruct()->get_preferred_size = view_get_preferred_size;
+ GetStruct()->size_to_preferred_size = view_size_to_preferred_size;
+ GetStruct()->get_minimum_size = view_get_minimum_size;
+ GetStruct()->get_maximum_size = view_get_maximum_size;
+ GetStruct()->get_height_for_width = view_get_height_for_width;
+ GetStruct()->invalidate_layout = view_invalidate_layout;
+ GetStruct()->set_visible = view_set_visible;
+ GetStruct()->is_visible = view_is_visible;
+ GetStruct()->is_drawn = view_is_drawn;
+ GetStruct()->set_enabled = view_set_enabled;
+ GetStruct()->is_enabled = view_is_enabled;
+ GetStruct()->set_focusable = view_set_focusable;
+ GetStruct()->is_focusable = view_is_focusable;
+ GetStruct()->is_accessibility_focusable = view_is_accessibility_focusable;
+ GetStruct()->request_focus = view_request_focus;
+ GetStruct()->set_background_color = view_set_background_color;
+ GetStruct()->get_background_color = view_get_background_color;
+ GetStruct()->convert_point_to_screen = view_convert_point_to_screen;
+ GetStruct()->convert_point_from_screen = view_convert_point_from_screen;
+ GetStruct()->convert_point_to_window = view_convert_point_to_window;
+ GetStruct()->convert_point_from_window = view_convert_point_from_window;
+ GetStruct()->convert_point_to_view = view_convert_point_to_view;
+ GetStruct()->convert_point_from_view = view_convert_point_from_view;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefViewCppToC::~CefViewCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefView>
+CefCppToCRefCounted<CefViewCppToC, CefView, cef_view_t>::UnwrapDerived(
+ CefWrapperType type,
+ cef_view_t* s) {
+ if (type == WT_BROWSER_VIEW) {
+ return CefBrowserViewCppToC::Unwrap(
+ reinterpret_cast<cef_browser_view_t*>(s));
+ }
+ if (type == WT_BUTTON) {
+ return CefButtonCppToC::Unwrap(reinterpret_cast<cef_button_t*>(s));
+ }
+ if (type == WT_LABEL_BUTTON) {
+ return CefLabelButtonCppToC::Unwrap(
+ reinterpret_cast<cef_label_button_t*>(s));
+ }
+ if (type == WT_MENU_BUTTON) {
+ return CefMenuButtonCppToC::Unwrap(reinterpret_cast<cef_menu_button_t*>(s));
+ }
+ if (type == WT_PANEL) {
+ return CefPanelCppToC::Unwrap(reinterpret_cast<cef_panel_t*>(s));
+ }
+ if (type == WT_SCROLL_VIEW) {
+ return CefScrollViewCppToC::Unwrap(reinterpret_cast<cef_scroll_view_t*>(s));
+ }
+ if (type == WT_TEXTFIELD) {
+ return CefTextfieldCppToC::Unwrap(reinterpret_cast<cef_textfield_t*>(s));
+ }
+ if (type == WT_WINDOW) {
+ return CefWindowCppToC::Unwrap(reinterpret_cast<cef_window_t*>(s));
+ }
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCppToCRefCounted<CefViewCppToC, CefView, cef_view_t>::kWrapperType =
+ WT_VIEW;
diff --git a/libcef_dll/cpptoc/views/view_cpptoc.h b/libcef_dll/cpptoc/views/view_cpptoc.h
new file mode 100644
index 00000000..efb59751
--- /dev/null
+++ b/libcef_dll/cpptoc/views/view_cpptoc.h
@@ -0,0 +1,48 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=0d24d12448e97907667f8347a38818e0a4d713ed$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_VIEWS_VIEW_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_VIEWS_VIEW_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/views/cef_browser_view_capi.h"
+#include "include/capi/views/cef_button_capi.h"
+#include "include/capi/views/cef_panel_capi.h"
+#include "include/capi/views/cef_scroll_view_capi.h"
+#include "include/capi/views/cef_textfield_capi.h"
+#include "include/capi/views/cef_view_capi.h"
+#include "include/capi/views/cef_window_capi.h"
+#include "include/views/cef_browser_view.h"
+#include "include/views/cef_button.h"
+#include "include/views/cef_panel.h"
+#include "include/views/cef_scroll_view.h"
+#include "include/views/cef_textfield.h"
+#include "include/views/cef_view.h"
+#include "include/views/cef_window.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefViewCppToC
+ : public CefCppToCRefCounted<CefViewCppToC, CefView, cef_view_t> {
+ public:
+ CefViewCppToC();
+ virtual ~CefViewCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_VIEWS_VIEW_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/views/view_delegate_cpptoc.cc b/libcef_dll/cpptoc/views/view_delegate_cpptoc.cc
new file mode 100644
index 00000000..074f10ce
--- /dev/null
+++ b/libcef_dll/cpptoc/views/view_delegate_cpptoc.cc
@@ -0,0 +1,345 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=7411dc1ef606336389a483ed2a95b14d70c8eb3e$
+//
+
+#include "libcef_dll/cpptoc/views/view_delegate_cpptoc.h"
+#include "libcef_dll/cpptoc/views/browser_view_delegate_cpptoc.h"
+#include "libcef_dll/cpptoc/views/button_delegate_cpptoc.h"
+#include "libcef_dll/cpptoc/views/menu_button_delegate_cpptoc.h"
+#include "libcef_dll/cpptoc/views/panel_delegate_cpptoc.h"
+#include "libcef_dll/cpptoc/views/textfield_delegate_cpptoc.h"
+#include "libcef_dll/cpptoc/views/window_delegate_cpptoc.h"
+#include "libcef_dll/ctocpp/views/view_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+cef_size_t CEF_CALLBACK
+view_delegate_get_preferred_size(struct _cef_view_delegate_t* self,
+ cef_view_t* view) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval = CefViewDelegateCppToC::Get(self)->GetPreferredSize(
+ CefViewCToCpp::Wrap(view));
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_size_t CEF_CALLBACK
+view_delegate_get_minimum_size(struct _cef_view_delegate_t* self,
+ cef_view_t* view) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval = CefViewDelegateCppToC::Get(self)->GetMinimumSize(
+ CefViewCToCpp::Wrap(view));
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_size_t CEF_CALLBACK
+view_delegate_get_maximum_size(struct _cef_view_delegate_t* self,
+ cef_view_t* view) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval = CefViewDelegateCppToC::Get(self)->GetMaximumSize(
+ CefViewCToCpp::Wrap(view));
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK
+view_delegate_get_height_for_width(struct _cef_view_delegate_t* self,
+ cef_view_t* view,
+ int width) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefViewDelegateCppToC::Get(self)->GetHeightForWidth(
+ CefViewCToCpp::Wrap(view), width);
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK
+view_delegate_on_parent_view_changed(struct _cef_view_delegate_t* self,
+ cef_view_t* view,
+ int added,
+ cef_view_t* parent) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return;
+ }
+ // Verify param: parent; type: refptr_diff
+ DCHECK(parent);
+ if (!parent) {
+ return;
+ }
+
+ // Execute
+ CefViewDelegateCppToC::Get(self)->OnParentViewChanged(
+ CefViewCToCpp::Wrap(view), added ? true : false,
+ CefViewCToCpp::Wrap(parent));
+}
+
+void CEF_CALLBACK
+view_delegate_on_child_view_changed(struct _cef_view_delegate_t* self,
+ cef_view_t* view,
+ int added,
+ cef_view_t* child) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return;
+ }
+ // Verify param: child; type: refptr_diff
+ DCHECK(child);
+ if (!child) {
+ return;
+ }
+
+ // Execute
+ CefViewDelegateCppToC::Get(self)->OnChildViewChanged(
+ CefViewCToCpp::Wrap(view), added ? true : false,
+ CefViewCToCpp::Wrap(child));
+}
+
+void CEF_CALLBACK
+view_delegate_on_window_changed(struct _cef_view_delegate_t* self,
+ cef_view_t* view,
+ int added) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return;
+ }
+
+ // Execute
+ CefViewDelegateCppToC::Get(self)->OnWindowChanged(CefViewCToCpp::Wrap(view),
+ added ? true : false);
+}
+
+void CEF_CALLBACK
+view_delegate_on_layout_changed(struct _cef_view_delegate_t* self,
+ cef_view_t* view,
+ const cef_rect_t* new_bounds) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return;
+ }
+ // Verify param: new_bounds; type: simple_byref_const
+ DCHECK(new_bounds);
+ if (!new_bounds) {
+ return;
+ }
+
+ // Translate param: new_bounds; type: simple_byref_const
+ CefRect new_boundsVal = new_bounds ? *new_bounds : CefRect();
+
+ // Execute
+ CefViewDelegateCppToC::Get(self)->OnLayoutChanged(CefViewCToCpp::Wrap(view),
+ new_boundsVal);
+}
+
+void CEF_CALLBACK view_delegate_on_focus(struct _cef_view_delegate_t* self,
+ cef_view_t* view) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return;
+ }
+
+ // Execute
+ CefViewDelegateCppToC::Get(self)->OnFocus(CefViewCToCpp::Wrap(view));
+}
+
+void CEF_CALLBACK view_delegate_on_blur(struct _cef_view_delegate_t* self,
+ cef_view_t* view) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return;
+ }
+
+ // Execute
+ CefViewDelegateCppToC::Get(self)->OnBlur(CefViewCToCpp::Wrap(view));
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefViewDelegateCppToC::CefViewDelegateCppToC() {
+ GetStruct()->get_preferred_size = view_delegate_get_preferred_size;
+ GetStruct()->get_minimum_size = view_delegate_get_minimum_size;
+ GetStruct()->get_maximum_size = view_delegate_get_maximum_size;
+ GetStruct()->get_height_for_width = view_delegate_get_height_for_width;
+ GetStruct()->on_parent_view_changed = view_delegate_on_parent_view_changed;
+ GetStruct()->on_child_view_changed = view_delegate_on_child_view_changed;
+ GetStruct()->on_window_changed = view_delegate_on_window_changed;
+ GetStruct()->on_layout_changed = view_delegate_on_layout_changed;
+ GetStruct()->on_focus = view_delegate_on_focus;
+ GetStruct()->on_blur = view_delegate_on_blur;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefViewDelegateCppToC::~CefViewDelegateCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefViewDelegate> CefCppToCRefCounted<
+ CefViewDelegateCppToC,
+ CefViewDelegate,
+ cef_view_delegate_t>::UnwrapDerived(CefWrapperType type,
+ cef_view_delegate_t* s) {
+ if (type == WT_BROWSER_VIEW_DELEGATE) {
+ return CefBrowserViewDelegateCppToC::Unwrap(
+ reinterpret_cast<cef_browser_view_delegate_t*>(s));
+ }
+ if (type == WT_BUTTON_DELEGATE) {
+ return CefButtonDelegateCppToC::Unwrap(
+ reinterpret_cast<cef_button_delegate_t*>(s));
+ }
+ if (type == WT_MENU_BUTTON_DELEGATE) {
+ return CefMenuButtonDelegateCppToC::Unwrap(
+ reinterpret_cast<cef_menu_button_delegate_t*>(s));
+ }
+ if (type == WT_PANEL_DELEGATE) {
+ return CefPanelDelegateCppToC::Unwrap(
+ reinterpret_cast<cef_panel_delegate_t*>(s));
+ }
+ if (type == WT_TEXTFIELD_DELEGATE) {
+ return CefTextfieldDelegateCppToC::Unwrap(
+ reinterpret_cast<cef_textfield_delegate_t*>(s));
+ }
+ if (type == WT_WINDOW_DELEGATE) {
+ return CefWindowDelegateCppToC::Unwrap(
+ reinterpret_cast<cef_window_delegate_t*>(s));
+ }
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefViewDelegateCppToC,
+ CefViewDelegate,
+ cef_view_delegate_t>::kWrapperType =
+ WT_VIEW_DELEGATE;
diff --git a/libcef_dll/cpptoc/views/view_delegate_cpptoc.h b/libcef_dll/cpptoc/views/view_delegate_cpptoc.h
new file mode 100644
index 00000000..a6903ef4
--- /dev/null
+++ b/libcef_dll/cpptoc/views/view_delegate_cpptoc.h
@@ -0,0 +1,39 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=384b7d1f2df446d35d6ba46e62d89976d88fef7c$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_VIEWS_VIEW_DELEGATE_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_VIEWS_VIEW_DELEGATE_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/views/cef_view_capi.h"
+#include "include/capi/views/cef_view_delegate_capi.h"
+#include "include/views/cef_view.h"
+#include "include/views/cef_view_delegate.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefViewDelegateCppToC : public CefCppToCRefCounted<CefViewDelegateCppToC,
+ CefViewDelegate,
+ cef_view_delegate_t> {
+ public:
+ CefViewDelegateCppToC();
+ virtual ~CefViewDelegateCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_VIEWS_VIEW_DELEGATE_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/views/window_cpptoc.cc b/libcef_dll/cpptoc/views/window_cpptoc.cc
new file mode 100644
index 00000000..767ce93a
--- /dev/null
+++ b/libcef_dll/cpptoc/views/window_cpptoc.cc
@@ -0,0 +1,2097 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=ead4e6a19c7e3ad881931b3cc0d4da81b64a24ea$
+//
+
+#include "libcef_dll/cpptoc/views/window_cpptoc.h"
+#include "libcef_dll/cpptoc/image_cpptoc.h"
+#include "libcef_dll/cpptoc/menu_model_cpptoc.h"
+#include "libcef_dll/cpptoc/views/box_layout_cpptoc.h"
+#include "libcef_dll/cpptoc/views/browser_view_cpptoc.h"
+#include "libcef_dll/cpptoc/views/button_cpptoc.h"
+#include "libcef_dll/cpptoc/views/display_cpptoc.h"
+#include "libcef_dll/cpptoc/views/fill_layout_cpptoc.h"
+#include "libcef_dll/cpptoc/views/layout_cpptoc.h"
+#include "libcef_dll/cpptoc/views/overlay_controller_cpptoc.h"
+#include "libcef_dll/cpptoc/views/panel_cpptoc.h"
+#include "libcef_dll/cpptoc/views/scroll_view_cpptoc.h"
+#include "libcef_dll/cpptoc/views/textfield_cpptoc.h"
+#include "libcef_dll/cpptoc/views/view_cpptoc.h"
+#include "libcef_dll/ctocpp/views/view_delegate_ctocpp.h"
+#include "libcef_dll/ctocpp/views/window_delegate_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// GLOBAL FUNCTIONS - Body may be edited by hand.
+
+CEF_EXPORT cef_window_t* cef_window_create_top_level(
+ struct _cef_window_delegate_t* delegate) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: delegate
+
+ // Execute
+ CefRefPtr<CefWindow> _retval =
+ CefWindow::CreateTopLevelWindow(CefWindowDelegateCToCpp::Wrap(delegate));
+
+ // Return type: refptr_same
+ return CefWindowCppToC::Wrap(_retval);
+}
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK window_show(struct _cef_window_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefWindowCppToC::Get(self)->Show();
+}
+
+void CEF_CALLBACK window_hide(struct _cef_window_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefWindowCppToC::Get(self)->Hide();
+}
+
+void CEF_CALLBACK window_center_window(struct _cef_window_t* self,
+ const cef_size_t* size) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: size; type: simple_byref_const
+ DCHECK(size);
+ if (!size) {
+ return;
+ }
+
+ // Translate param: size; type: simple_byref_const
+ CefSize sizeVal = size ? *size : CefSize();
+
+ // Execute
+ CefWindowCppToC::Get(self)->CenterWindow(sizeVal);
+}
+
+void CEF_CALLBACK window_close(struct _cef_window_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefWindowCppToC::Get(self)->Close();
+}
+
+int CEF_CALLBACK window_is_closed(struct _cef_window_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefWindowCppToC::Get(self)->IsClosed();
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK window_activate(struct _cef_window_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefWindowCppToC::Get(self)->Activate();
+}
+
+void CEF_CALLBACK window_deactivate(struct _cef_window_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefWindowCppToC::Get(self)->Deactivate();
+}
+
+int CEF_CALLBACK window_is_active(struct _cef_window_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefWindowCppToC::Get(self)->IsActive();
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK window_bring_to_top(struct _cef_window_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefWindowCppToC::Get(self)->BringToTop();
+}
+
+void CEF_CALLBACK window_set_always_on_top(struct _cef_window_t* self,
+ int on_top) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefWindowCppToC::Get(self)->SetAlwaysOnTop(on_top ? true : false);
+}
+
+int CEF_CALLBACK window_is_always_on_top(struct _cef_window_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefWindowCppToC::Get(self)->IsAlwaysOnTop();
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK window_maximize(struct _cef_window_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefWindowCppToC::Get(self)->Maximize();
+}
+
+void CEF_CALLBACK window_minimize(struct _cef_window_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefWindowCppToC::Get(self)->Minimize();
+}
+
+void CEF_CALLBACK window_restore(struct _cef_window_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefWindowCppToC::Get(self)->Restore();
+}
+
+void CEF_CALLBACK window_set_fullscreen(struct _cef_window_t* self,
+ int fullscreen) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefWindowCppToC::Get(self)->SetFullscreen(fullscreen ? true : false);
+}
+
+int CEF_CALLBACK window_is_maximized(struct _cef_window_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefWindowCppToC::Get(self)->IsMaximized();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK window_is_minimized(struct _cef_window_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefWindowCppToC::Get(self)->IsMinimized();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK window_is_fullscreen(struct _cef_window_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefWindowCppToC::Get(self)->IsFullscreen();
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK window_set_title(struct _cef_window_t* self,
+ const cef_string_t* title) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Unverified params: title
+
+ // Execute
+ CefWindowCppToC::Get(self)->SetTitle(CefString(title));
+}
+
+cef_string_userfree_t CEF_CALLBACK
+window_get_title(struct _cef_window_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefWindowCppToC::Get(self)->GetTitle();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+void CEF_CALLBACK window_set_window_icon(struct _cef_window_t* self,
+ cef_image_t* image) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: image; type: refptr_same
+ DCHECK(image);
+ if (!image) {
+ return;
+ }
+
+ // Execute
+ CefWindowCppToC::Get(self)->SetWindowIcon(CefImageCppToC::Unwrap(image));
+}
+
+cef_image_t* CEF_CALLBACK window_get_window_icon(struct _cef_window_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefImage> _retval = CefWindowCppToC::Get(self)->GetWindowIcon();
+
+ // Return type: refptr_same
+ return CefImageCppToC::Wrap(_retval);
+}
+
+void CEF_CALLBACK window_set_window_app_icon(struct _cef_window_t* self,
+ cef_image_t* image) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: image; type: refptr_same
+ DCHECK(image);
+ if (!image) {
+ return;
+ }
+
+ // Execute
+ CefWindowCppToC::Get(self)->SetWindowAppIcon(CefImageCppToC::Unwrap(image));
+}
+
+cef_image_t* CEF_CALLBACK
+window_get_window_app_icon(struct _cef_window_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefImage> _retval = CefWindowCppToC::Get(self)->GetWindowAppIcon();
+
+ // Return type: refptr_same
+ return CefImageCppToC::Wrap(_retval);
+}
+
+cef_overlay_controller_t* CEF_CALLBACK
+window_add_overlay_view(struct _cef_window_t* self,
+ cef_view_t* view,
+ cef_docking_mode_t docking_mode) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+ // Verify param: view; type: refptr_same
+ DCHECK(view);
+ if (!view) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefOverlayController> _retval =
+ CefWindowCppToC::Get(self)->AddOverlayView(CefViewCppToC::Unwrap(view),
+ docking_mode);
+
+ // Return type: refptr_same
+ return CefOverlayControllerCppToC::Wrap(_retval);
+}
+
+void CEF_CALLBACK window_show_menu(struct _cef_window_t* self,
+ cef_menu_model_t* menu_model,
+ const cef_point_t* screen_point,
+ cef_menu_anchor_position_t anchor_position) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: menu_model; type: refptr_same
+ DCHECK(menu_model);
+ if (!menu_model) {
+ return;
+ }
+ // Verify param: screen_point; type: simple_byref_const
+ DCHECK(screen_point);
+ if (!screen_point) {
+ return;
+ }
+
+ // Translate param: screen_point; type: simple_byref_const
+ CefPoint screen_pointVal = screen_point ? *screen_point : CefPoint();
+
+ // Execute
+ CefWindowCppToC::Get(self)->ShowMenu(CefMenuModelCppToC::Unwrap(menu_model),
+ screen_pointVal, anchor_position);
+}
+
+void CEF_CALLBACK window_cancel_menu(struct _cef_window_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefWindowCppToC::Get(self)->CancelMenu();
+}
+
+cef_display_t* CEF_CALLBACK window_get_display(struct _cef_window_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefDisplay> _retval = CefWindowCppToC::Get(self)->GetDisplay();
+
+ // Return type: refptr_same
+ return CefDisplayCppToC::Wrap(_retval);
+}
+
+cef_rect_t CEF_CALLBACK
+window_get_client_area_bounds_in_screen(struct _cef_window_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefRect();
+ }
+
+ // Execute
+ cef_rect_t _retval =
+ CefWindowCppToC::Get(self)->GetClientAreaBoundsInScreen();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK
+window_set_draggable_regions(struct _cef_window_t* self,
+ size_t regionsCount,
+ cef_draggable_region_t const* regions) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Unverified params: regions
+
+ // Translate param: regions; type: simple_vec_byref_const
+ std::vector<CefDraggableRegion> regionsList;
+ if (regionsCount > 0) {
+ for (size_t i = 0; i < regionsCount; ++i) {
+ CefDraggableRegion regionsVal = regions[i];
+ regionsList.push_back(regionsVal);
+ }
+ }
+
+ // Execute
+ CefWindowCppToC::Get(self)->SetDraggableRegions(regionsList);
+}
+
+cef_window_handle_t CEF_CALLBACK
+window_get_window_handle(struct _cef_window_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return kNullWindowHandle;
+ }
+
+ // Execute
+ cef_window_handle_t _retval = CefWindowCppToC::Get(self)->GetWindowHandle();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK window_send_key_press(struct _cef_window_t* self,
+ int key_code,
+ uint32 event_flags) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefWindowCppToC::Get(self)->SendKeyPress(key_code, event_flags);
+}
+
+void CEF_CALLBACK window_send_mouse_move(struct _cef_window_t* self,
+ int screen_x,
+ int screen_y) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefWindowCppToC::Get(self)->SendMouseMove(screen_x, screen_y);
+}
+
+void CEF_CALLBACK window_send_mouse_events(struct _cef_window_t* self,
+ cef_mouse_button_type_t button,
+ int mouse_down,
+ int mouse_up) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefWindowCppToC::Get(self)->SendMouseEvents(button, mouse_down ? true : false,
+ mouse_up ? true : false);
+}
+
+void CEF_CALLBACK window_set_accelerator(struct _cef_window_t* self,
+ int command_id,
+ int key_code,
+ int shift_pressed,
+ int ctrl_pressed,
+ int alt_pressed) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefWindowCppToC::Get(self)->SetAccelerator(
+ command_id, key_code, shift_pressed ? true : false,
+ ctrl_pressed ? true : false, alt_pressed ? true : false);
+}
+
+void CEF_CALLBACK window_remove_accelerator(struct _cef_window_t* self,
+ int command_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefWindowCppToC::Get(self)->RemoveAccelerator(command_id);
+}
+
+void CEF_CALLBACK window_remove_all_accelerators(struct _cef_window_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefWindowCppToC::Get(self)->RemoveAllAccelerators();
+}
+
+struct _cef_window_t* CEF_CALLBACK window_as_window(struct _cef_panel_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefWindow> _retval =
+ CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))->AsWindow();
+
+ // Return type: refptr_same
+ return CefWindowCppToC::Wrap(_retval);
+}
+
+cef_fill_layout_t* CEF_CALLBACK
+window_set_to_fill_layout(struct _cef_panel_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefFillLayout> _retval =
+ CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))
+ ->SetToFillLayout();
+
+ // Return type: refptr_same
+ return CefFillLayoutCppToC::Wrap(_retval);
+}
+
+cef_box_layout_t* CEF_CALLBACK
+window_set_to_box_layout(struct _cef_panel_t* self,
+ const cef_box_layout_settings_t* settings) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+ // Verify param: settings; type: simple_byref_const
+ DCHECK(settings);
+ if (!settings) {
+ return NULL;
+ }
+
+ // Translate param: settings; type: simple_byref_const
+ CefBoxLayoutSettings settingsVal =
+ settings ? *settings : CefBoxLayoutSettings();
+
+ // Execute
+ CefRefPtr<CefBoxLayout> _retval =
+ CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))
+ ->SetToBoxLayout(settingsVal);
+
+ // Return type: refptr_same
+ return CefBoxLayoutCppToC::Wrap(_retval);
+}
+
+cef_layout_t* CEF_CALLBACK window_get_layout(struct _cef_panel_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefLayout> _retval =
+ CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))->GetLayout();
+
+ // Return type: refptr_same
+ return CefLayoutCppToC::Wrap(_retval);
+}
+
+void CEF_CALLBACK window_layout(struct _cef_panel_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))->Layout();
+}
+
+void CEF_CALLBACK window_add_child_view(struct _cef_panel_t* self,
+ cef_view_t* view) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: view; type: refptr_same
+ DCHECK(view);
+ if (!view) {
+ return;
+ }
+
+ // Execute
+ CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))
+ ->AddChildView(CefViewCppToC::Unwrap(view));
+}
+
+void CEF_CALLBACK window_add_child_view_at(struct _cef_panel_t* self,
+ cef_view_t* view,
+ int index) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: view; type: refptr_same
+ DCHECK(view);
+ if (!view) {
+ return;
+ }
+ // Verify param: index; type: simple_byval
+ DCHECK_GE(index, 0);
+ if (index < 0) {
+ return;
+ }
+
+ // Execute
+ CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))
+ ->AddChildViewAt(CefViewCppToC::Unwrap(view), index);
+}
+
+void CEF_CALLBACK window_reorder_child_view(struct _cef_panel_t* self,
+ cef_view_t* view,
+ int index) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: view; type: refptr_same
+ DCHECK(view);
+ if (!view) {
+ return;
+ }
+
+ // Execute
+ CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))
+ ->ReorderChildView(CefViewCppToC::Unwrap(view), index);
+}
+
+void CEF_CALLBACK window_remove_child_view(struct _cef_panel_t* self,
+ cef_view_t* view) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: view; type: refptr_same
+ DCHECK(view);
+ if (!view) {
+ return;
+ }
+
+ // Execute
+ CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))
+ ->RemoveChildView(CefViewCppToC::Unwrap(view));
+}
+
+void CEF_CALLBACK window_remove_all_child_views(struct _cef_panel_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))
+ ->RemoveAllChildViews();
+}
+
+size_t CEF_CALLBACK window_get_child_view_count(struct _cef_panel_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ size_t _retval = CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))
+ ->GetChildViewCount();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_view_t* CEF_CALLBACK window_get_child_view_at(struct _cef_panel_t* self,
+ int index) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+ // Verify param: index; type: simple_byval
+ DCHECK_GE(index, 0);
+ if (index < 0) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefView> _retval =
+ CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))
+ ->GetChildViewAt(index);
+
+ // Return type: refptr_same
+ return CefViewCppToC::Wrap(_retval);
+}
+
+cef_browser_view_t* CEF_CALLBACK
+window_as_browser_view(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefBrowserView> _retval =
+ CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))
+ ->AsBrowserView();
+
+ // Return type: refptr_same
+ return CefBrowserViewCppToC::Wrap(_retval);
+}
+
+cef_button_t* CEF_CALLBACK window_as_button(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefButton> _retval =
+ CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))->AsButton();
+
+ // Return type: refptr_same
+ return CefButtonCppToC::Wrap(_retval);
+}
+
+cef_panel_t* CEF_CALLBACK window_as_panel(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefPanel> _retval =
+ CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))->AsPanel();
+
+ // Return type: refptr_same
+ return CefPanelCppToC::Wrap(_retval);
+}
+
+cef_scroll_view_t* CEF_CALLBACK
+window_as_scroll_view(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefScrollView> _retval =
+ CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))
+ ->AsScrollView();
+
+ // Return type: refptr_same
+ return CefScrollViewCppToC::Wrap(_retval);
+}
+
+cef_textfield_t* CEF_CALLBACK window_as_textfield(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefTextfield> _retval =
+ CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))
+ ->AsTextfield();
+
+ // Return type: refptr_same
+ return CefTextfieldCppToC::Wrap(_retval);
+}
+
+cef_string_userfree_t CEF_CALLBACK
+window_get_type_string(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval =
+ CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))
+ ->GetTypeString();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_string_userfree_t CEF_CALLBACK window_to_string(struct _cef_view_t* self,
+ int include_children) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval =
+ CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))
+ ->ToString(include_children ? true : false);
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+int CEF_CALLBACK window_is_valid(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))->IsValid();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK window_is_attached(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))->IsAttached();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK window_is_same(struct _cef_view_t* self, cef_view_t* that) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: that; type: refptr_same
+ DCHECK(that);
+ if (!that) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))
+ ->IsSame(CefViewCppToC::Unwrap(that));
+
+ // Return type: bool
+ return _retval;
+}
+
+cef_view_delegate_t* CEF_CALLBACK
+window_get_delegate(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefViewDelegate> _retval =
+ CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))
+ ->GetDelegate();
+
+ // Return type: refptr_diff
+ return CefViewDelegateCToCpp::Unwrap(_retval);
+}
+
+struct _cef_window_t* CEF_CALLBACK window_get_window(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefWindow> _retval =
+ CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))->GetWindow();
+
+ // Return type: refptr_same
+ return CefWindowCppToC::Wrap(_retval);
+}
+
+int CEF_CALLBACK window_get_id(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval =
+ CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))->GetID();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK window_set_id(struct _cef_view_t* self, int id) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))->SetID(id);
+}
+
+int CEF_CALLBACK window_get_group_id(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval =
+ CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))->GetGroupID();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK window_set_group_id(struct _cef_view_t* self, int group_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))
+ ->SetGroupID(group_id);
+}
+
+cef_view_t* CEF_CALLBACK window_get_parent_view(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefView> _retval =
+ CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))
+ ->GetParentView();
+
+ // Return type: refptr_same
+ return CefViewCppToC::Wrap(_retval);
+}
+
+cef_view_t* CEF_CALLBACK window_get_view_for_id(struct _cef_view_t* self,
+ int id) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefView> _retval =
+ CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))
+ ->GetViewForID(id);
+
+ // Return type: refptr_same
+ return CefViewCppToC::Wrap(_retval);
+}
+
+void CEF_CALLBACK window_set_bounds(struct _cef_view_t* self,
+ const cef_rect_t* bounds) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: bounds; type: simple_byref_const
+ DCHECK(bounds);
+ if (!bounds) {
+ return;
+ }
+
+ // Translate param: bounds; type: simple_byref_const
+ CefRect boundsVal = bounds ? *bounds : CefRect();
+
+ // Execute
+ CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))
+ ->SetBounds(boundsVal);
+}
+
+cef_rect_t CEF_CALLBACK window_get_bounds(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefRect();
+ }
+
+ // Execute
+ cef_rect_t _retval =
+ CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))->GetBounds();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_rect_t CEF_CALLBACK window_get_bounds_in_screen(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefRect();
+ }
+
+ // Execute
+ cef_rect_t _retval =
+ CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))
+ ->GetBoundsInScreen();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK window_set_size(struct _cef_view_t* self,
+ const cef_size_t* size) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: size; type: simple_byref_const
+ DCHECK(size);
+ if (!size) {
+ return;
+ }
+
+ // Translate param: size; type: simple_byref_const
+ CefSize sizeVal = size ? *size : CefSize();
+
+ // Execute
+ CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))->SetSize(sizeVal);
+}
+
+cef_size_t CEF_CALLBACK window_get_size(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval =
+ CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))->GetSize();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK window_set_position(struct _cef_view_t* self,
+ const cef_point_t* position) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: position; type: simple_byref_const
+ DCHECK(position);
+ if (!position) {
+ return;
+ }
+
+ // Translate param: position; type: simple_byref_const
+ CefPoint positionVal = position ? *position : CefPoint();
+
+ // Execute
+ CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))
+ ->SetPosition(positionVal);
+}
+
+cef_point_t CEF_CALLBACK window_get_position(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefPoint();
+ }
+
+ // Execute
+ cef_point_t _retval =
+ CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))
+ ->GetPosition();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK window_set_insets(struct _cef_view_t* self,
+ const cef_insets_t* insets) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: insets; type: simple_byref_const
+ DCHECK(insets);
+ if (!insets) {
+ return;
+ }
+
+ // Translate param: insets; type: simple_byref_const
+ CefInsets insetsVal = insets ? *insets : CefInsets();
+
+ // Execute
+ CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))
+ ->SetInsets(insetsVal);
+}
+
+cef_insets_t CEF_CALLBACK window_get_insets(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefInsets();
+ }
+
+ // Execute
+ cef_insets_t _retval =
+ CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))->GetInsets();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_size_t CEF_CALLBACK window_get_preferred_size(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval =
+ CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))
+ ->GetPreferredSize();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK window_size_to_preferred_size(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))
+ ->SizeToPreferredSize();
+}
+
+cef_size_t CEF_CALLBACK window_get_minimum_size(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval =
+ CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))
+ ->GetMinimumSize();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_size_t CEF_CALLBACK window_get_maximum_size(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval =
+ CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))
+ ->GetMaximumSize();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK window_get_height_for_width(struct _cef_view_t* self,
+ int width) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))
+ ->GetHeightForWidth(width);
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK window_invalidate_layout(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))
+ ->InvalidateLayout();
+}
+
+void CEF_CALLBACK window_set_visible(struct _cef_view_t* self, int visible) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))
+ ->SetVisible(visible ? true : false);
+}
+
+int CEF_CALLBACK window_is_visible(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))->IsVisible();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK window_is_drawn(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))->IsDrawn();
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK window_set_enabled(struct _cef_view_t* self, int enabled) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))
+ ->SetEnabled(enabled ? true : false);
+}
+
+int CEF_CALLBACK window_is_enabled(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))->IsEnabled();
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK window_set_focusable(struct _cef_view_t* self,
+ int focusable) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))
+ ->SetFocusable(focusable ? true : false);
+}
+
+int CEF_CALLBACK window_is_focusable(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))
+ ->IsFocusable();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK window_is_accessibility_focusable(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))
+ ->IsAccessibilityFocusable();
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK window_request_focus(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))->RequestFocus();
+}
+
+void CEF_CALLBACK window_set_background_color(struct _cef_view_t* self,
+ cef_color_t color) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))
+ ->SetBackgroundColor(color);
+}
+
+cef_color_t CEF_CALLBACK window_get_background_color(struct _cef_view_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ cef_color_t _retval =
+ CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))
+ ->GetBackgroundColor();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK window_convert_point_to_screen(struct _cef_view_t* self,
+ cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: point; type: simple_byref
+ DCHECK(point);
+ if (!point) {
+ return 0;
+ }
+
+ // Translate param: point; type: simple_byref
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ bool _retval = CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))
+ ->ConvertPointToScreen(pointVal);
+
+ // Restore param: point; type: simple_byref
+ if (point) {
+ *point = pointVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK window_convert_point_from_screen(struct _cef_view_t* self,
+ cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: point; type: simple_byref
+ DCHECK(point);
+ if (!point) {
+ return 0;
+ }
+
+ // Translate param: point; type: simple_byref
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ bool _retval = CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))
+ ->ConvertPointFromScreen(pointVal);
+
+ // Restore param: point; type: simple_byref
+ if (point) {
+ *point = pointVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK window_convert_point_to_window(struct _cef_view_t* self,
+ cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: point; type: simple_byref
+ DCHECK(point);
+ if (!point) {
+ return 0;
+ }
+
+ // Translate param: point; type: simple_byref
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ bool _retval = CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))
+ ->ConvertPointToWindow(pointVal);
+
+ // Restore param: point; type: simple_byref
+ if (point) {
+ *point = pointVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK window_convert_point_from_window(struct _cef_view_t* self,
+ cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: point; type: simple_byref
+ DCHECK(point);
+ if (!point) {
+ return 0;
+ }
+
+ // Translate param: point; type: simple_byref
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ bool _retval = CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))
+ ->ConvertPointFromWindow(pointVal);
+
+ // Restore param: point; type: simple_byref
+ if (point) {
+ *point = pointVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK window_convert_point_to_view(struct _cef_view_t* self,
+ cef_view_t* view,
+ cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: view; type: refptr_same
+ DCHECK(view);
+ if (!view) {
+ return 0;
+ }
+ // Verify param: point; type: simple_byref
+ DCHECK(point);
+ if (!point) {
+ return 0;
+ }
+
+ // Translate param: point; type: simple_byref
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ bool _retval =
+ CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))
+ ->ConvertPointToView(CefViewCppToC::Unwrap(view), pointVal);
+
+ // Restore param: point; type: simple_byref
+ if (point) {
+ *point = pointVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK window_convert_point_from_view(struct _cef_view_t* self,
+ cef_view_t* view,
+ cef_point_t* point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: view; type: refptr_same
+ DCHECK(view);
+ if (!view) {
+ return 0;
+ }
+ // Verify param: point; type: simple_byref
+ DCHECK(point);
+ if (!point) {
+ return 0;
+ }
+
+ // Translate param: point; type: simple_byref
+ CefPoint pointVal = point ? *point : CefPoint();
+
+ // Execute
+ bool _retval =
+ CefWindowCppToC::Get(reinterpret_cast<cef_window_t*>(self))
+ ->ConvertPointFromView(CefViewCppToC::Unwrap(view), pointVal);
+
+ // Restore param: point; type: simple_byref
+ if (point) {
+ *point = pointVal;
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefWindowCppToC::CefWindowCppToC() {
+ GetStruct()->show = window_show;
+ GetStruct()->hide = window_hide;
+ GetStruct()->center_window = window_center_window;
+ GetStruct()->close = window_close;
+ GetStruct()->is_closed = window_is_closed;
+ GetStruct()->activate = window_activate;
+ GetStruct()->deactivate = window_deactivate;
+ GetStruct()->is_active = window_is_active;
+ GetStruct()->bring_to_top = window_bring_to_top;
+ GetStruct()->set_always_on_top = window_set_always_on_top;
+ GetStruct()->is_always_on_top = window_is_always_on_top;
+ GetStruct()->maximize = window_maximize;
+ GetStruct()->minimize = window_minimize;
+ GetStruct()->restore = window_restore;
+ GetStruct()->set_fullscreen = window_set_fullscreen;
+ GetStruct()->is_maximized = window_is_maximized;
+ GetStruct()->is_minimized = window_is_minimized;
+ GetStruct()->is_fullscreen = window_is_fullscreen;
+ GetStruct()->set_title = window_set_title;
+ GetStruct()->get_title = window_get_title;
+ GetStruct()->set_window_icon = window_set_window_icon;
+ GetStruct()->get_window_icon = window_get_window_icon;
+ GetStruct()->set_window_app_icon = window_set_window_app_icon;
+ GetStruct()->get_window_app_icon = window_get_window_app_icon;
+ GetStruct()->add_overlay_view = window_add_overlay_view;
+ GetStruct()->show_menu = window_show_menu;
+ GetStruct()->cancel_menu = window_cancel_menu;
+ GetStruct()->get_display = window_get_display;
+ GetStruct()->get_client_area_bounds_in_screen =
+ window_get_client_area_bounds_in_screen;
+ GetStruct()->set_draggable_regions = window_set_draggable_regions;
+ GetStruct()->get_window_handle = window_get_window_handle;
+ GetStruct()->send_key_press = window_send_key_press;
+ GetStruct()->send_mouse_move = window_send_mouse_move;
+ GetStruct()->send_mouse_events = window_send_mouse_events;
+ GetStruct()->set_accelerator = window_set_accelerator;
+ GetStruct()->remove_accelerator = window_remove_accelerator;
+ GetStruct()->remove_all_accelerators = window_remove_all_accelerators;
+ GetStruct()->base.as_window = window_as_window;
+ GetStruct()->base.set_to_fill_layout = window_set_to_fill_layout;
+ GetStruct()->base.set_to_box_layout = window_set_to_box_layout;
+ GetStruct()->base.get_layout = window_get_layout;
+ GetStruct()->base.layout = window_layout;
+ GetStruct()->base.add_child_view = window_add_child_view;
+ GetStruct()->base.add_child_view_at = window_add_child_view_at;
+ GetStruct()->base.reorder_child_view = window_reorder_child_view;
+ GetStruct()->base.remove_child_view = window_remove_child_view;
+ GetStruct()->base.remove_all_child_views = window_remove_all_child_views;
+ GetStruct()->base.get_child_view_count = window_get_child_view_count;
+ GetStruct()->base.get_child_view_at = window_get_child_view_at;
+ GetStruct()->base.base.as_browser_view = window_as_browser_view;
+ GetStruct()->base.base.as_button = window_as_button;
+ GetStruct()->base.base.as_panel = window_as_panel;
+ GetStruct()->base.base.as_scroll_view = window_as_scroll_view;
+ GetStruct()->base.base.as_textfield = window_as_textfield;
+ GetStruct()->base.base.get_type_string = window_get_type_string;
+ GetStruct()->base.base.to_string = window_to_string;
+ GetStruct()->base.base.is_valid = window_is_valid;
+ GetStruct()->base.base.is_attached = window_is_attached;
+ GetStruct()->base.base.is_same = window_is_same;
+ GetStruct()->base.base.get_delegate = window_get_delegate;
+ GetStruct()->base.base.get_window = window_get_window;
+ GetStruct()->base.base.get_id = window_get_id;
+ GetStruct()->base.base.set_id = window_set_id;
+ GetStruct()->base.base.get_group_id = window_get_group_id;
+ GetStruct()->base.base.set_group_id = window_set_group_id;
+ GetStruct()->base.base.get_parent_view = window_get_parent_view;
+ GetStruct()->base.base.get_view_for_id = window_get_view_for_id;
+ GetStruct()->base.base.set_bounds = window_set_bounds;
+ GetStruct()->base.base.get_bounds = window_get_bounds;
+ GetStruct()->base.base.get_bounds_in_screen = window_get_bounds_in_screen;
+ GetStruct()->base.base.set_size = window_set_size;
+ GetStruct()->base.base.get_size = window_get_size;
+ GetStruct()->base.base.set_position = window_set_position;
+ GetStruct()->base.base.get_position = window_get_position;
+ GetStruct()->base.base.set_insets = window_set_insets;
+ GetStruct()->base.base.get_insets = window_get_insets;
+ GetStruct()->base.base.get_preferred_size = window_get_preferred_size;
+ GetStruct()->base.base.size_to_preferred_size = window_size_to_preferred_size;
+ GetStruct()->base.base.get_minimum_size = window_get_minimum_size;
+ GetStruct()->base.base.get_maximum_size = window_get_maximum_size;
+ GetStruct()->base.base.get_height_for_width = window_get_height_for_width;
+ GetStruct()->base.base.invalidate_layout = window_invalidate_layout;
+ GetStruct()->base.base.set_visible = window_set_visible;
+ GetStruct()->base.base.is_visible = window_is_visible;
+ GetStruct()->base.base.is_drawn = window_is_drawn;
+ GetStruct()->base.base.set_enabled = window_set_enabled;
+ GetStruct()->base.base.is_enabled = window_is_enabled;
+ GetStruct()->base.base.set_focusable = window_set_focusable;
+ GetStruct()->base.base.is_focusable = window_is_focusable;
+ GetStruct()->base.base.is_accessibility_focusable =
+ window_is_accessibility_focusable;
+ GetStruct()->base.base.request_focus = window_request_focus;
+ GetStruct()->base.base.set_background_color = window_set_background_color;
+ GetStruct()->base.base.get_background_color = window_get_background_color;
+ GetStruct()->base.base.convert_point_to_screen =
+ window_convert_point_to_screen;
+ GetStruct()->base.base.convert_point_from_screen =
+ window_convert_point_from_screen;
+ GetStruct()->base.base.convert_point_to_window =
+ window_convert_point_to_window;
+ GetStruct()->base.base.convert_point_from_window =
+ window_convert_point_from_window;
+ GetStruct()->base.base.convert_point_to_view = window_convert_point_to_view;
+ GetStruct()->base.base.convert_point_from_view =
+ window_convert_point_from_view;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefWindowCppToC::~CefWindowCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefWindow>
+CefCppToCRefCounted<CefWindowCppToC, CefWindow, cef_window_t>::UnwrapDerived(
+ CefWrapperType type,
+ cef_window_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefWindowCppToC, CefWindow, cef_window_t>::
+ kWrapperType = WT_WINDOW;
diff --git a/libcef_dll/cpptoc/views/window_cpptoc.h b/libcef_dll/cpptoc/views/window_cpptoc.h
new file mode 100644
index 00000000..e02be449
--- /dev/null
+++ b/libcef_dll/cpptoc/views/window_cpptoc.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=12ff3d7d14f9977ff1f62e9a35b04b153a135480$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_VIEWS_WINDOW_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_VIEWS_WINDOW_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/views/cef_window_capi.h"
+#include "include/views/cef_window.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefWindowCppToC
+ : public CefCppToCRefCounted<CefWindowCppToC, CefWindow, cef_window_t> {
+ public:
+ CefWindowCppToC();
+ virtual ~CefWindowCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_VIEWS_WINDOW_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/views/window_delegate_cpptoc.cc b/libcef_dll/cpptoc/views/window_delegate_cpptoc.cc
new file mode 100644
index 00000000..64c799e3
--- /dev/null
+++ b/libcef_dll/cpptoc/views/window_delegate_cpptoc.cc
@@ -0,0 +1,809 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=18f715de465689a4e8484bbced8ad92d9434438a$
+//
+
+#include "libcef_dll/cpptoc/views/window_delegate_cpptoc.h"
+#include "libcef_dll/ctocpp/views/view_ctocpp.h"
+#include "libcef_dll/ctocpp/views/window_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK
+window_delegate_on_window_created(struct _cef_window_delegate_t* self,
+ cef_window_t* window) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: window; type: refptr_diff
+ DCHECK(window);
+ if (!window) {
+ return;
+ }
+
+ // Execute
+ CefWindowDelegateCppToC::Get(self)->OnWindowCreated(
+ CefWindowCToCpp::Wrap(window));
+}
+
+void CEF_CALLBACK
+window_delegate_on_window_closing(struct _cef_window_delegate_t* self,
+ cef_window_t* window) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: window; type: refptr_diff
+ DCHECK(window);
+ if (!window) {
+ return;
+ }
+
+ // Execute
+ CefWindowDelegateCppToC::Get(self)->OnWindowClosing(
+ CefWindowCToCpp::Wrap(window));
+}
+
+void CEF_CALLBACK
+window_delegate_on_window_destroyed(struct _cef_window_delegate_t* self,
+ cef_window_t* window) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: window; type: refptr_diff
+ DCHECK(window);
+ if (!window) {
+ return;
+ }
+
+ // Execute
+ CefWindowDelegateCppToC::Get(self)->OnWindowDestroyed(
+ CefWindowCToCpp::Wrap(window));
+}
+
+void CEF_CALLBACK window_delegate_on_window_activation_changed(
+ struct _cef_window_delegate_t* self,
+ cef_window_t* window,
+ int active) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: window; type: refptr_diff
+ DCHECK(window);
+ if (!window) {
+ return;
+ }
+
+ // Execute
+ CefWindowDelegateCppToC::Get(self)->OnWindowActivationChanged(
+ CefWindowCToCpp::Wrap(window), active ? true : false);
+}
+
+void CEF_CALLBACK
+window_delegate_on_window_bounds_changed(struct _cef_window_delegate_t* self,
+ cef_window_t* window,
+ const cef_rect_t* new_bounds) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: window; type: refptr_diff
+ DCHECK(window);
+ if (!window) {
+ return;
+ }
+ // Verify param: new_bounds; type: simple_byref_const
+ DCHECK(new_bounds);
+ if (!new_bounds) {
+ return;
+ }
+
+ // Translate param: new_bounds; type: simple_byref_const
+ CefRect new_boundsVal = new_bounds ? *new_bounds : CefRect();
+
+ // Execute
+ CefWindowDelegateCppToC::Get(self)->OnWindowBoundsChanged(
+ CefWindowCToCpp::Wrap(window), new_boundsVal);
+}
+
+cef_window_t* CEF_CALLBACK
+window_delegate_get_parent_window(struct _cef_window_delegate_t* self,
+ cef_window_t* window,
+ int* is_menu,
+ int* can_activate_menu) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+ // Verify param: window; type: refptr_diff
+ DCHECK(window);
+ if (!window) {
+ return NULL;
+ }
+ // Verify param: is_menu; type: bool_byaddr
+ DCHECK(is_menu);
+ if (!is_menu) {
+ return NULL;
+ }
+ // Verify param: can_activate_menu; type: bool_byaddr
+ DCHECK(can_activate_menu);
+ if (!can_activate_menu) {
+ return NULL;
+ }
+
+ // Translate param: is_menu; type: bool_byaddr
+ bool is_menuBool = (is_menu && *is_menu) ? true : false;
+ // Translate param: can_activate_menu; type: bool_byaddr
+ bool can_activate_menuBool =
+ (can_activate_menu && *can_activate_menu) ? true : false;
+
+ // Execute
+ CefRefPtr<CefWindow> _retval =
+ CefWindowDelegateCppToC::Get(self)->GetParentWindow(
+ CefWindowCToCpp::Wrap(window), &is_menuBool, &can_activate_menuBool);
+
+ // Restore param: is_menu; type: bool_byaddr
+ if (is_menu) {
+ *is_menu = is_menuBool ? true : false;
+ }
+ // Restore param: can_activate_menu; type: bool_byaddr
+ if (can_activate_menu) {
+ *can_activate_menu = can_activate_menuBool ? true : false;
+ }
+
+ // Return type: refptr_diff
+ return CefWindowCToCpp::Unwrap(_retval);
+}
+
+cef_rect_t CEF_CALLBACK
+window_delegate_get_initial_bounds(struct _cef_window_delegate_t* self,
+ cef_window_t* window) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefRect();
+ }
+ // Verify param: window; type: refptr_diff
+ DCHECK(window);
+ if (!window) {
+ return CefRect();
+ }
+
+ // Execute
+ cef_rect_t _retval = CefWindowDelegateCppToC::Get(self)->GetInitialBounds(
+ CefWindowCToCpp::Wrap(window));
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_show_state_t CEF_CALLBACK
+window_delegate_get_initial_show_state(struct _cef_window_delegate_t* self,
+ cef_window_t* window) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CEF_SHOW_STATE_NORMAL;
+ }
+ // Verify param: window; type: refptr_diff
+ DCHECK(window);
+ if (!window) {
+ return CEF_SHOW_STATE_NORMAL;
+ }
+
+ // Execute
+ cef_show_state_t _retval =
+ CefWindowDelegateCppToC::Get(self)->GetInitialShowState(
+ CefWindowCToCpp::Wrap(window));
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK
+window_delegate_is_frameless(struct _cef_window_delegate_t* self,
+ cef_window_t* window) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: window; type: refptr_diff
+ DCHECK(window);
+ if (!window) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefWindowDelegateCppToC::Get(self)->IsFrameless(
+ CefWindowCToCpp::Wrap(window));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK window_delegate_with_standard_window_buttons(
+ struct _cef_window_delegate_t* self,
+ cef_window_t* window) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: window; type: refptr_diff
+ DCHECK(window);
+ if (!window) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefWindowDelegateCppToC::Get(self)->WithStandardWindowButtons(
+ CefWindowCToCpp::Wrap(window));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+window_delegate_get_titlebar_height(struct _cef_window_delegate_t* self,
+ cef_window_t* window,
+ float* titlebar_height) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: window; type: refptr_diff
+ DCHECK(window);
+ if (!window) {
+ return 0;
+ }
+ // Verify param: titlebar_height; type: simple_byaddr
+ DCHECK(titlebar_height);
+ if (!titlebar_height) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefWindowDelegateCppToC::Get(self)->GetTitlebarHeight(
+ CefWindowCToCpp::Wrap(window), titlebar_height);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK window_delegate_can_resize(struct _cef_window_delegate_t* self,
+ cef_window_t* window) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: window; type: refptr_diff
+ DCHECK(window);
+ if (!window) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefWindowDelegateCppToC::Get(self)->CanResize(
+ CefWindowCToCpp::Wrap(window));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+window_delegate_can_maximize(struct _cef_window_delegate_t* self,
+ cef_window_t* window) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: window; type: refptr_diff
+ DCHECK(window);
+ if (!window) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefWindowDelegateCppToC::Get(self)->CanMaximize(
+ CefWindowCToCpp::Wrap(window));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+window_delegate_can_minimize(struct _cef_window_delegate_t* self,
+ cef_window_t* window) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: window; type: refptr_diff
+ DCHECK(window);
+ if (!window) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefWindowDelegateCppToC::Get(self)->CanMinimize(
+ CefWindowCToCpp::Wrap(window));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK window_delegate_can_close(struct _cef_window_delegate_t* self,
+ cef_window_t* window) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: window; type: refptr_diff
+ DCHECK(window);
+ if (!window) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefWindowDelegateCppToC::Get(self)->CanClose(
+ CefWindowCToCpp::Wrap(window));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+window_delegate_on_accelerator(struct _cef_window_delegate_t* self,
+ cef_window_t* window,
+ int command_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: window; type: refptr_diff
+ DCHECK(window);
+ if (!window) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefWindowDelegateCppToC::Get(self)->OnAccelerator(
+ CefWindowCToCpp::Wrap(window), command_id);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+window_delegate_on_key_event(struct _cef_window_delegate_t* self,
+ cef_window_t* window,
+ const cef_key_event_t* event) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: window; type: refptr_diff
+ DCHECK(window);
+ if (!window) {
+ return 0;
+ }
+ // Verify param: event; type: simple_byref_const
+ DCHECK(event);
+ if (!event) {
+ return 0;
+ }
+
+ // Translate param: event; type: simple_byref_const
+ CefKeyEvent eventVal = event ? *event : CefKeyEvent();
+
+ // Execute
+ bool _retval = CefWindowDelegateCppToC::Get(self)->OnKeyEvent(
+ CefWindowCToCpp::Wrap(window), eventVal);
+
+ // Return type: bool
+ return _retval;
+}
+
+cef_size_t CEF_CALLBACK
+window_delegate_get_preferred_size(struct _cef_view_delegate_t* self,
+ cef_view_t* view) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval = CefWindowDelegateCppToC::Get(
+ reinterpret_cast<cef_window_delegate_t*>(self))
+ ->GetPreferredSize(CefViewCToCpp::Wrap(view));
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_size_t CEF_CALLBACK
+window_delegate_get_minimum_size(struct _cef_view_delegate_t* self,
+ cef_view_t* view) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval = CefWindowDelegateCppToC::Get(
+ reinterpret_cast<cef_window_delegate_t*>(self))
+ ->GetMinimumSize(CefViewCToCpp::Wrap(view));
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_size_t CEF_CALLBACK
+window_delegate_get_maximum_size(struct _cef_view_delegate_t* self,
+ cef_view_t* view) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefSize();
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval = CefWindowDelegateCppToC::Get(
+ reinterpret_cast<cef_window_delegate_t*>(self))
+ ->GetMaximumSize(CefViewCToCpp::Wrap(view));
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK
+window_delegate_get_height_for_width(struct _cef_view_delegate_t* self,
+ cef_view_t* view,
+ int width) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefWindowDelegateCppToC::Get(
+ reinterpret_cast<cef_window_delegate_t*>(self))
+ ->GetHeightForWidth(CefViewCToCpp::Wrap(view), width);
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK
+window_delegate_on_parent_view_changed(struct _cef_view_delegate_t* self,
+ cef_view_t* view,
+ int added,
+ cef_view_t* parent) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return;
+ }
+ // Verify param: parent; type: refptr_diff
+ DCHECK(parent);
+ if (!parent) {
+ return;
+ }
+
+ // Execute
+ CefWindowDelegateCppToC::Get(reinterpret_cast<cef_window_delegate_t*>(self))
+ ->OnParentViewChanged(CefViewCToCpp::Wrap(view), added ? true : false,
+ CefViewCToCpp::Wrap(parent));
+}
+
+void CEF_CALLBACK
+window_delegate_on_child_view_changed(struct _cef_view_delegate_t* self,
+ cef_view_t* view,
+ int added,
+ cef_view_t* child) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return;
+ }
+ // Verify param: child; type: refptr_diff
+ DCHECK(child);
+ if (!child) {
+ return;
+ }
+
+ // Execute
+ CefWindowDelegateCppToC::Get(reinterpret_cast<cef_window_delegate_t*>(self))
+ ->OnChildViewChanged(CefViewCToCpp::Wrap(view), added ? true : false,
+ CefViewCToCpp::Wrap(child));
+}
+
+void CEF_CALLBACK
+window_delegate_on_window_changed(struct _cef_view_delegate_t* self,
+ cef_view_t* view,
+ int added) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return;
+ }
+
+ // Execute
+ CefWindowDelegateCppToC::Get(reinterpret_cast<cef_window_delegate_t*>(self))
+ ->OnWindowChanged(CefViewCToCpp::Wrap(view), added ? true : false);
+}
+
+void CEF_CALLBACK
+window_delegate_on_layout_changed(struct _cef_view_delegate_t* self,
+ cef_view_t* view,
+ const cef_rect_t* new_bounds) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return;
+ }
+ // Verify param: new_bounds; type: simple_byref_const
+ DCHECK(new_bounds);
+ if (!new_bounds) {
+ return;
+ }
+
+ // Translate param: new_bounds; type: simple_byref_const
+ CefRect new_boundsVal = new_bounds ? *new_bounds : CefRect();
+
+ // Execute
+ CefWindowDelegateCppToC::Get(reinterpret_cast<cef_window_delegate_t*>(self))
+ ->OnLayoutChanged(CefViewCToCpp::Wrap(view), new_boundsVal);
+}
+
+void CEF_CALLBACK window_delegate_on_focus(struct _cef_view_delegate_t* self,
+ cef_view_t* view) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return;
+ }
+
+ // Execute
+ CefWindowDelegateCppToC::Get(reinterpret_cast<cef_window_delegate_t*>(self))
+ ->OnFocus(CefViewCToCpp::Wrap(view));
+}
+
+void CEF_CALLBACK window_delegate_on_blur(struct _cef_view_delegate_t* self,
+ cef_view_t* view) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: view; type: refptr_diff
+ DCHECK(view);
+ if (!view) {
+ return;
+ }
+
+ // Execute
+ CefWindowDelegateCppToC::Get(reinterpret_cast<cef_window_delegate_t*>(self))
+ ->OnBlur(CefViewCToCpp::Wrap(view));
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefWindowDelegateCppToC::CefWindowDelegateCppToC() {
+ GetStruct()->on_window_created = window_delegate_on_window_created;
+ GetStruct()->on_window_closing = window_delegate_on_window_closing;
+ GetStruct()->on_window_destroyed = window_delegate_on_window_destroyed;
+ GetStruct()->on_window_activation_changed =
+ window_delegate_on_window_activation_changed;
+ GetStruct()->on_window_bounds_changed =
+ window_delegate_on_window_bounds_changed;
+ GetStruct()->get_parent_window = window_delegate_get_parent_window;
+ GetStruct()->get_initial_bounds = window_delegate_get_initial_bounds;
+ GetStruct()->get_initial_show_state = window_delegate_get_initial_show_state;
+ GetStruct()->is_frameless = window_delegate_is_frameless;
+ GetStruct()->with_standard_window_buttons =
+ window_delegate_with_standard_window_buttons;
+ GetStruct()->get_titlebar_height = window_delegate_get_titlebar_height;
+ GetStruct()->can_resize = window_delegate_can_resize;
+ GetStruct()->can_maximize = window_delegate_can_maximize;
+ GetStruct()->can_minimize = window_delegate_can_minimize;
+ GetStruct()->can_close = window_delegate_can_close;
+ GetStruct()->on_accelerator = window_delegate_on_accelerator;
+ GetStruct()->on_key_event = window_delegate_on_key_event;
+ GetStruct()->base.base.get_preferred_size =
+ window_delegate_get_preferred_size;
+ GetStruct()->base.base.get_minimum_size = window_delegate_get_minimum_size;
+ GetStruct()->base.base.get_maximum_size = window_delegate_get_maximum_size;
+ GetStruct()->base.base.get_height_for_width =
+ window_delegate_get_height_for_width;
+ GetStruct()->base.base.on_parent_view_changed =
+ window_delegate_on_parent_view_changed;
+ GetStruct()->base.base.on_child_view_changed =
+ window_delegate_on_child_view_changed;
+ GetStruct()->base.base.on_window_changed = window_delegate_on_window_changed;
+ GetStruct()->base.base.on_layout_changed = window_delegate_on_layout_changed;
+ GetStruct()->base.base.on_focus = window_delegate_on_focus;
+ GetStruct()->base.base.on_blur = window_delegate_on_blur;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefWindowDelegateCppToC::~CefWindowDelegateCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefWindowDelegate> CefCppToCRefCounted<
+ CefWindowDelegateCppToC,
+ CefWindowDelegate,
+ cef_window_delegate_t>::UnwrapDerived(CefWrapperType type,
+ cef_window_delegate_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefWindowDelegateCppToC,
+ CefWindowDelegate,
+ cef_window_delegate_t>::kWrapperType =
+ WT_WINDOW_DELEGATE;
diff --git a/libcef_dll/cpptoc/views/window_delegate_cpptoc.h b/libcef_dll/cpptoc/views/window_delegate_cpptoc.h
new file mode 100644
index 00000000..441a2ca2
--- /dev/null
+++ b/libcef_dll/cpptoc/views/window_delegate_cpptoc.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=b4d82958ac79ac843f904c4aa8010a6909ca06fa$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_VIEWS_WINDOW_DELEGATE_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_VIEWS_WINDOW_DELEGATE_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/views/cef_window_capi.h"
+#include "include/capi/views/cef_window_delegate_capi.h"
+#include "include/views/cef_window.h"
+#include "include/views/cef_window_delegate.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefWindowDelegateCppToC
+ : public CefCppToCRefCounted<CefWindowDelegateCppToC,
+ CefWindowDelegate,
+ cef_window_delegate_t> {
+ public:
+ CefWindowDelegateCppToC();
+ virtual ~CefWindowDelegateCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_VIEWS_WINDOW_DELEGATE_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/waitable_event_cpptoc.cc b/libcef_dll/cpptoc/waitable_event_cpptoc.cc
new file mode 100644
index 00000000..5f5e854a
--- /dev/null
+++ b/libcef_dll/cpptoc/waitable_event_cpptoc.cc
@@ -0,0 +1,149 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=3a713f33f726dab21c7e477861c9160b080f9005$
+//
+
+#include "libcef_dll/cpptoc/waitable_event_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// GLOBAL FUNCTIONS - Body may be edited by hand.
+
+CEF_EXPORT cef_waitable_event_t* cef_waitable_event_create(
+ int automatic_reset,
+ int initially_signaled) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ CefRefPtr<CefWaitableEvent> _retval = CefWaitableEvent::CreateWaitableEvent(
+ automatic_reset ? true : false, initially_signaled ? true : false);
+
+ // Return type: refptr_same
+ return CefWaitableEventCppToC::Wrap(_retval);
+}
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+void CEF_CALLBACK waitable_event_reset(struct _cef_waitable_event_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefWaitableEventCppToC::Get(self)->Reset();
+}
+
+void CEF_CALLBACK waitable_event_signal(struct _cef_waitable_event_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefWaitableEventCppToC::Get(self)->Signal();
+}
+
+int CEF_CALLBACK
+waitable_event_is_signaled(struct _cef_waitable_event_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefWaitableEventCppToC::Get(self)->IsSignaled();
+
+ // Return type: bool
+ return _retval;
+}
+
+void CEF_CALLBACK waitable_event_wait(struct _cef_waitable_event_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+
+ // Execute
+ CefWaitableEventCppToC::Get(self)->Wait();
+}
+
+int CEF_CALLBACK waitable_event_timed_wait(struct _cef_waitable_event_t* self,
+ int64 max_ms) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefWaitableEventCppToC::Get(self)->TimedWait(max_ms);
+
+ // Return type: bool
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefWaitableEventCppToC::CefWaitableEventCppToC() {
+ GetStruct()->reset = waitable_event_reset;
+ GetStruct()->signal = waitable_event_signal;
+ GetStruct()->is_signaled = waitable_event_is_signaled;
+ GetStruct()->wait = waitable_event_wait;
+ GetStruct()->timed_wait = waitable_event_timed_wait;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefWaitableEventCppToC::~CefWaitableEventCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefWaitableEvent> CefCppToCRefCounted<
+ CefWaitableEventCppToC,
+ CefWaitableEvent,
+ cef_waitable_event_t>::UnwrapDerived(CefWrapperType type,
+ cef_waitable_event_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefWaitableEventCppToC,
+ CefWaitableEvent,
+ cef_waitable_event_t>::kWrapperType =
+ WT_WAITABLE_EVENT;
diff --git a/libcef_dll/cpptoc/waitable_event_cpptoc.h b/libcef_dll/cpptoc/waitable_event_cpptoc.h
new file mode 100644
index 00000000..1e1ba618
--- /dev/null
+++ b/libcef_dll/cpptoc/waitable_event_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=c3d08738052ecc67921493df15ea0df38c040314$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_WAITABLE_EVENT_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_WAITABLE_EVENT_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_waitable_event_capi.h"
+#include "include/cef_waitable_event.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefWaitableEventCppToC
+ : public CefCppToCRefCounted<CefWaitableEventCppToC,
+ CefWaitableEvent,
+ cef_waitable_event_t> {
+ public:
+ CefWaitableEventCppToC();
+ virtual ~CefWaitableEventCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_WAITABLE_EVENT_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/write_handler_cpptoc.cc b/libcef_dll/cpptoc/write_handler_cpptoc.cc
new file mode 100644
index 00000000..1bd13680
--- /dev/null
+++ b/libcef_dll/cpptoc/write_handler_cpptoc.cc
@@ -0,0 +1,149 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=a7d0c28420e88fe055cc18eda55d9cae1f3ee33f$
+//
+
+#include "libcef_dll/cpptoc/write_handler_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+size_t CEF_CALLBACK write_handler_write(struct _cef_write_handler_t* self,
+ const void* ptr,
+ size_t size,
+ size_t n) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: ptr; type: simple_byaddr
+ DCHECK(ptr);
+ if (!ptr) {
+ return 0;
+ }
+
+ // Execute
+ size_t _retval = CefWriteHandlerCppToC::Get(self)->Write(ptr, size, n);
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK write_handler_seek(struct _cef_write_handler_t* self,
+ int64 offset,
+ int whence) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefWriteHandlerCppToC::Get(self)->Seek(offset, whence);
+
+ // Return type: simple
+ return _retval;
+}
+
+int64 CEF_CALLBACK write_handler_tell(struct _cef_write_handler_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int64 _retval = CefWriteHandlerCppToC::Get(self)->Tell();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK write_handler_flush(struct _cef_write_handler_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefWriteHandlerCppToC::Get(self)->Flush();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK write_handler_may_block(struct _cef_write_handler_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefWriteHandlerCppToC::Get(self)->MayBlock();
+
+ // Return type: bool
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefWriteHandlerCppToC::CefWriteHandlerCppToC() {
+ GetStruct()->write = write_handler_write;
+ GetStruct()->seek = write_handler_seek;
+ GetStruct()->tell = write_handler_tell;
+ GetStruct()->flush = write_handler_flush;
+ GetStruct()->may_block = write_handler_may_block;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefWriteHandlerCppToC::~CefWriteHandlerCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefWriteHandler> CefCppToCRefCounted<
+ CefWriteHandlerCppToC,
+ CefWriteHandler,
+ cef_write_handler_t>::UnwrapDerived(CefWrapperType type,
+ cef_write_handler_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefWriteHandlerCppToC,
+ CefWriteHandler,
+ cef_write_handler_t>::kWrapperType =
+ WT_WRITE_HANDLER;
diff --git a/libcef_dll/cpptoc/write_handler_cpptoc.h b/libcef_dll/cpptoc/write_handler_cpptoc.h
new file mode 100644
index 00000000..60a0ba79
--- /dev/null
+++ b/libcef_dll/cpptoc/write_handler_cpptoc.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=94c67ea9a0a7a44b92ef2d322f7dd34490f5b8e6$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_WRITE_HANDLER_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_WRITE_HANDLER_CPPTOC_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_stream_capi.h"
+#include "include/cef_stream.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed wrapper-side only.
+class CefWriteHandlerCppToC : public CefCppToCRefCounted<CefWriteHandlerCppToC,
+ CefWriteHandler,
+ cef_write_handler_t> {
+ public:
+ CefWriteHandlerCppToC();
+ virtual ~CefWriteHandlerCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_WRITE_HANDLER_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/x509cert_principal_cpptoc.cc b/libcef_dll/cpptoc/x509cert_principal_cpptoc.cc
new file mode 100644
index 00000000..de54d90e
--- /dev/null
+++ b/libcef_dll/cpptoc/x509cert_principal_cpptoc.cc
@@ -0,0 +1,270 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=06fc26b84bc5dda324774ba87944b41e3669bfb7$
+//
+
+#include "libcef_dll/cpptoc/x509cert_principal_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+#include "libcef_dll/transfer_util.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+cef_string_userfree_t CEF_CALLBACK
+x509cert_principal_get_display_name(struct _cef_x509cert_principal_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefX509CertPrincipalCppToC::Get(self)->GetDisplayName();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_string_userfree_t CEF_CALLBACK
+x509cert_principal_get_common_name(struct _cef_x509cert_principal_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefX509CertPrincipalCppToC::Get(self)->GetCommonName();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_string_userfree_t CEF_CALLBACK
+x509cert_principal_get_locality_name(struct _cef_x509cert_principal_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefX509CertPrincipalCppToC::Get(self)->GetLocalityName();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_string_userfree_t CEF_CALLBACK
+x509cert_principal_get_state_or_province_name(
+ struct _cef_x509cert_principal_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval =
+ CefX509CertPrincipalCppToC::Get(self)->GetStateOrProvinceName();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_string_userfree_t CEF_CALLBACK
+x509cert_principal_get_country_name(struct _cef_x509cert_principal_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefX509CertPrincipalCppToC::Get(self)->GetCountryName();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+void CEF_CALLBACK
+x509cert_principal_get_street_addresses(struct _cef_x509cert_principal_t* self,
+ cef_string_list_t addresses) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: addresses; type: string_vec_byref
+ DCHECK(addresses);
+ if (!addresses) {
+ return;
+ }
+
+ // Translate param: addresses; type: string_vec_byref
+ std::vector<CefString> addressesList;
+ transfer_string_list_contents(addresses, addressesList);
+
+ // Execute
+ CefX509CertPrincipalCppToC::Get(self)->GetStreetAddresses(addressesList);
+
+ // Restore param: addresses; type: string_vec_byref
+ cef_string_list_clear(addresses);
+ transfer_string_list_contents(addressesList, addresses);
+}
+
+void CEF_CALLBACK x509cert_principal_get_organization_names(
+ struct _cef_x509cert_principal_t* self,
+ cef_string_list_t names) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: names; type: string_vec_byref
+ DCHECK(names);
+ if (!names) {
+ return;
+ }
+
+ // Translate param: names; type: string_vec_byref
+ std::vector<CefString> namesList;
+ transfer_string_list_contents(names, namesList);
+
+ // Execute
+ CefX509CertPrincipalCppToC::Get(self)->GetOrganizationNames(namesList);
+
+ // Restore param: names; type: string_vec_byref
+ cef_string_list_clear(names);
+ transfer_string_list_contents(namesList, names);
+}
+
+void CEF_CALLBACK x509cert_principal_get_organization_unit_names(
+ struct _cef_x509cert_principal_t* self,
+ cef_string_list_t names) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: names; type: string_vec_byref
+ DCHECK(names);
+ if (!names) {
+ return;
+ }
+
+ // Translate param: names; type: string_vec_byref
+ std::vector<CefString> namesList;
+ transfer_string_list_contents(names, namesList);
+
+ // Execute
+ CefX509CertPrincipalCppToC::Get(self)->GetOrganizationUnitNames(namesList);
+
+ // Restore param: names; type: string_vec_byref
+ cef_string_list_clear(names);
+ transfer_string_list_contents(namesList, names);
+}
+
+void CEF_CALLBACK
+x509cert_principal_get_domain_components(struct _cef_x509cert_principal_t* self,
+ cef_string_list_t components) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: components; type: string_vec_byref
+ DCHECK(components);
+ if (!components) {
+ return;
+ }
+
+ // Translate param: components; type: string_vec_byref
+ std::vector<CefString> componentsList;
+ transfer_string_list_contents(components, componentsList);
+
+ // Execute
+ CefX509CertPrincipalCppToC::Get(self)->GetDomainComponents(componentsList);
+
+ // Restore param: components; type: string_vec_byref
+ cef_string_list_clear(components);
+ transfer_string_list_contents(componentsList, components);
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefX509CertPrincipalCppToC::CefX509CertPrincipalCppToC() {
+ GetStruct()->get_display_name = x509cert_principal_get_display_name;
+ GetStruct()->get_common_name = x509cert_principal_get_common_name;
+ GetStruct()->get_locality_name = x509cert_principal_get_locality_name;
+ GetStruct()->get_state_or_province_name =
+ x509cert_principal_get_state_or_province_name;
+ GetStruct()->get_country_name = x509cert_principal_get_country_name;
+ GetStruct()->get_street_addresses = x509cert_principal_get_street_addresses;
+ GetStruct()->get_organization_names =
+ x509cert_principal_get_organization_names;
+ GetStruct()->get_organization_unit_names =
+ x509cert_principal_get_organization_unit_names;
+ GetStruct()->get_domain_components = x509cert_principal_get_domain_components;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefX509CertPrincipalCppToC::~CefX509CertPrincipalCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefX509CertPrincipal> CefCppToCRefCounted<
+ CefX509CertPrincipalCppToC,
+ CefX509CertPrincipal,
+ cef_x509cert_principal_t>::UnwrapDerived(CefWrapperType type,
+ cef_x509cert_principal_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefX509CertPrincipalCppToC,
+ CefX509CertPrincipal,
+ cef_x509cert_principal_t>::kWrapperType =
+ WT_X509CERT_PRINCIPAL;
diff --git a/libcef_dll/cpptoc/x509cert_principal_cpptoc.h b/libcef_dll/cpptoc/x509cert_principal_cpptoc.h
new file mode 100644
index 00000000..8aba2d61
--- /dev/null
+++ b/libcef_dll/cpptoc/x509cert_principal_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=6e97a51d6d111d04e88c67e98eff127d7ca09dc1$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_X509CERT_PRINCIPAL_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_X509CERT_PRINCIPAL_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_x509_certificate_capi.h"
+#include "include/cef_x509_certificate.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefX509CertPrincipalCppToC
+ : public CefCppToCRefCounted<CefX509CertPrincipalCppToC,
+ CefX509CertPrincipal,
+ cef_x509cert_principal_t> {
+ public:
+ CefX509CertPrincipalCppToC();
+ virtual ~CefX509CertPrincipalCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_X509CERT_PRINCIPAL_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/x509certificate_cpptoc.cc b/libcef_dll/cpptoc/x509certificate_cpptoc.cc
new file mode 100644
index 00000000..03c18b19
--- /dev/null
+++ b/libcef_dll/cpptoc/x509certificate_cpptoc.cc
@@ -0,0 +1,294 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=73f73c1f9dd6f55f2cdc78e66867aada8ad31a28$
+//
+
+#include "libcef_dll/cpptoc/x509certificate_cpptoc.h"
+#include <algorithm>
+#include "libcef_dll/cpptoc/binary_value_cpptoc.h"
+#include "libcef_dll/cpptoc/x509cert_principal_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+cef_x509cert_principal_t* CEF_CALLBACK
+x509certificate_get_subject(struct _cef_x509certificate_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefX509CertPrincipal> _retval =
+ CefX509CertificateCppToC::Get(self)->GetSubject();
+
+ // Return type: refptr_same
+ return CefX509CertPrincipalCppToC::Wrap(_retval);
+}
+
+cef_x509cert_principal_t* CEF_CALLBACK
+x509certificate_get_issuer(struct _cef_x509certificate_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefX509CertPrincipal> _retval =
+ CefX509CertificateCppToC::Get(self)->GetIssuer();
+
+ // Return type: refptr_same
+ return CefX509CertPrincipalCppToC::Wrap(_retval);
+}
+
+cef_binary_value_t* CEF_CALLBACK
+x509certificate_get_serial_number(struct _cef_x509certificate_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefBinaryValue> _retval =
+ CefX509CertificateCppToC::Get(self)->GetSerialNumber();
+
+ // Return type: refptr_same
+ return CefBinaryValueCppToC::Wrap(_retval);
+}
+
+cef_basetime_t CEF_CALLBACK
+x509certificate_get_valid_start(struct _cef_x509certificate_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefBaseTime();
+ }
+
+ // Execute
+ cef_basetime_t _retval = CefX509CertificateCppToC::Get(self)->GetValidStart();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_basetime_t CEF_CALLBACK
+x509certificate_get_valid_expiry(struct _cef_x509certificate_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefBaseTime();
+ }
+
+ // Execute
+ cef_basetime_t _retval =
+ CefX509CertificateCppToC::Get(self)->GetValidExpiry();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_binary_value_t* CEF_CALLBACK
+x509certificate_get_derencoded(struct _cef_x509certificate_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefBinaryValue> _retval =
+ CefX509CertificateCppToC::Get(self)->GetDEREncoded();
+
+ // Return type: refptr_same
+ return CefBinaryValueCppToC::Wrap(_retval);
+}
+
+cef_binary_value_t* CEF_CALLBACK
+x509certificate_get_pemencoded(struct _cef_x509certificate_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefBinaryValue> _retval =
+ CefX509CertificateCppToC::Get(self)->GetPEMEncoded();
+
+ // Return type: refptr_same
+ return CefBinaryValueCppToC::Wrap(_retval);
+}
+
+size_t CEF_CALLBACK
+x509certificate_get_issuer_chain_size(struct _cef_x509certificate_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ size_t _retval = CefX509CertificateCppToC::Get(self)->GetIssuerChainSize();
+
+ // Return type: simple
+ return _retval;
+}
+
+void CEF_CALLBACK
+x509certificate_get_derencoded_issuer_chain(struct _cef_x509certificate_t* self,
+ size_t* chainCount,
+ cef_binary_value_t** chain) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: chain; type: refptr_vec_same_byref
+ DCHECK(chainCount && (*chainCount == 0 || chain));
+ if (!chainCount || (*chainCount > 0 && !chain)) {
+ return;
+ }
+
+ // Translate param: chain; type: refptr_vec_same_byref
+ std::vector<CefRefPtr<CefBinaryValue>> chainList;
+ if (chainCount && *chainCount > 0 && chain) {
+ for (size_t i = 0; i < *chainCount; ++i) {
+ chainList.push_back(CefBinaryValueCppToC::Unwrap(chain[i]));
+ }
+ }
+
+ // Execute
+ CefX509CertificateCppToC::Get(self)->GetDEREncodedIssuerChain(chainList);
+
+ // Restore param: chain; type: refptr_vec_same_byref
+ if (chainCount && chain) {
+ *chainCount = std::min(chainList.size(), *chainCount);
+ if (*chainCount > 0) {
+ for (size_t i = 0; i < *chainCount; ++i) {
+ chain[i] = CefBinaryValueCppToC::Wrap(chainList[i]);
+ }
+ }
+ }
+}
+
+void CEF_CALLBACK
+x509certificate_get_pemencoded_issuer_chain(struct _cef_x509certificate_t* self,
+ size_t* chainCount,
+ cef_binary_value_t** chain) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return;
+ }
+ // Verify param: chain; type: refptr_vec_same_byref
+ DCHECK(chainCount && (*chainCount == 0 || chain));
+ if (!chainCount || (*chainCount > 0 && !chain)) {
+ return;
+ }
+
+ // Translate param: chain; type: refptr_vec_same_byref
+ std::vector<CefRefPtr<CefBinaryValue>> chainList;
+ if (chainCount && *chainCount > 0 && chain) {
+ for (size_t i = 0; i < *chainCount; ++i) {
+ chainList.push_back(CefBinaryValueCppToC::Unwrap(chain[i]));
+ }
+ }
+
+ // Execute
+ CefX509CertificateCppToC::Get(self)->GetPEMEncodedIssuerChain(chainList);
+
+ // Restore param: chain; type: refptr_vec_same_byref
+ if (chainCount && chain) {
+ *chainCount = std::min(chainList.size(), *chainCount);
+ if (*chainCount > 0) {
+ for (size_t i = 0; i < *chainCount; ++i) {
+ chain[i] = CefBinaryValueCppToC::Wrap(chainList[i]);
+ }
+ }
+ }
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefX509CertificateCppToC::CefX509CertificateCppToC() {
+ GetStruct()->get_subject = x509certificate_get_subject;
+ GetStruct()->get_issuer = x509certificate_get_issuer;
+ GetStruct()->get_serial_number = x509certificate_get_serial_number;
+ GetStruct()->get_valid_start = x509certificate_get_valid_start;
+ GetStruct()->get_valid_expiry = x509certificate_get_valid_expiry;
+ GetStruct()->get_derencoded = x509certificate_get_derencoded;
+ GetStruct()->get_pemencoded = x509certificate_get_pemencoded;
+ GetStruct()->get_issuer_chain_size = x509certificate_get_issuer_chain_size;
+ GetStruct()->get_derencoded_issuer_chain =
+ x509certificate_get_derencoded_issuer_chain;
+ GetStruct()->get_pemencoded_issuer_chain =
+ x509certificate_get_pemencoded_issuer_chain;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefX509CertificateCppToC::~CefX509CertificateCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefX509Certificate> CefCppToCRefCounted<
+ CefX509CertificateCppToC,
+ CefX509Certificate,
+ cef_x509certificate_t>::UnwrapDerived(CefWrapperType type,
+ cef_x509certificate_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefX509CertificateCppToC,
+ CefX509Certificate,
+ cef_x509certificate_t>::kWrapperType =
+ WT_X509CERTIFICATE;
diff --git a/libcef_dll/cpptoc/x509certificate_cpptoc.h b/libcef_dll/cpptoc/x509certificate_cpptoc.h
new file mode 100644
index 00000000..6ef90271
--- /dev/null
+++ b/libcef_dll/cpptoc/x509certificate_cpptoc.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=11090b23faf77d87bde0a603e74a0697be58fa7c$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_X509CERTIFICATE_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_X509CERTIFICATE_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_x509_certificate_capi.h"
+#include "include/cef_x509_certificate.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefX509CertificateCppToC
+ : public CefCppToCRefCounted<CefX509CertificateCppToC,
+ CefX509Certificate,
+ cef_x509certificate_t> {
+ public:
+ CefX509CertificateCppToC();
+ virtual ~CefX509CertificateCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_X509CERTIFICATE_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/xml_reader_cpptoc.cc b/libcef_dll/cpptoc/xml_reader_cpptoc.cc
new file mode 100644
index 00000000..b0de20f8
--- /dev/null
+++ b/libcef_dll/cpptoc/xml_reader_cpptoc.cc
@@ -0,0 +1,671 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=8a647c490d84ceb4828f633a3c95d741e9fb9d9f$
+//
+
+#include "libcef_dll/cpptoc/xml_reader_cpptoc.h"
+#include "libcef_dll/cpptoc/stream_reader_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// GLOBAL FUNCTIONS - Body may be edited by hand.
+
+CEF_EXPORT cef_xml_reader_t* cef_xml_reader_create(
+ cef_stream_reader_t* stream,
+ cef_xml_encoding_type_t encodingType,
+ const cef_string_t* URI) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: stream; type: refptr_same
+ DCHECK(stream);
+ if (!stream) {
+ return NULL;
+ }
+ // Verify param: URI; type: string_byref_const
+ DCHECK(URI);
+ if (!URI) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefXmlReader> _retval = CefXmlReader::Create(
+ CefStreamReaderCppToC::Unwrap(stream), encodingType, CefString(URI));
+
+ // Return type: refptr_same
+ return CefXmlReaderCppToC::Wrap(_retval);
+}
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK xml_reader_move_to_next_node(struct _cef_xml_reader_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefXmlReaderCppToC::Get(self)->MoveToNextNode();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK xml_reader_close(struct _cef_xml_reader_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefXmlReaderCppToC::Get(self)->Close();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK xml_reader_has_error(struct _cef_xml_reader_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefXmlReaderCppToC::Get(self)->HasError();
+
+ // Return type: bool
+ return _retval;
+}
+
+cef_string_userfree_t CEF_CALLBACK
+xml_reader_get_error(struct _cef_xml_reader_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefXmlReaderCppToC::Get(self)->GetError();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_xml_node_type_t CEF_CALLBACK
+xml_reader_get_type(struct _cef_xml_reader_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return XML_NODE_UNSUPPORTED;
+ }
+
+ // Execute
+ cef_xml_node_type_t _retval = CefXmlReaderCppToC::Get(self)->GetType();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK xml_reader_get_depth(struct _cef_xml_reader_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefXmlReaderCppToC::Get(self)->GetDepth();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_string_userfree_t CEF_CALLBACK
+xml_reader_get_local_name(struct _cef_xml_reader_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefXmlReaderCppToC::Get(self)->GetLocalName();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_string_userfree_t CEF_CALLBACK
+xml_reader_get_prefix(struct _cef_xml_reader_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefXmlReaderCppToC::Get(self)->GetPrefix();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_string_userfree_t CEF_CALLBACK
+xml_reader_get_qualified_name(struct _cef_xml_reader_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefXmlReaderCppToC::Get(self)->GetQualifiedName();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_string_userfree_t CEF_CALLBACK
+xml_reader_get_namespace_uri(struct _cef_xml_reader_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefXmlReaderCppToC::Get(self)->GetNamespaceURI();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_string_userfree_t CEF_CALLBACK
+xml_reader_get_base_uri(struct _cef_xml_reader_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefXmlReaderCppToC::Get(self)->GetBaseURI();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_string_userfree_t CEF_CALLBACK
+xml_reader_get_xml_lang(struct _cef_xml_reader_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefXmlReaderCppToC::Get(self)->GetXmlLang();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+int CEF_CALLBACK xml_reader_is_empty_element(struct _cef_xml_reader_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefXmlReaderCppToC::Get(self)->IsEmptyElement();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK xml_reader_has_value(struct _cef_xml_reader_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefXmlReaderCppToC::Get(self)->HasValue();
+
+ // Return type: bool
+ return _retval;
+}
+
+cef_string_userfree_t CEF_CALLBACK
+xml_reader_get_value(struct _cef_xml_reader_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefXmlReaderCppToC::Get(self)->GetValue();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+int CEF_CALLBACK xml_reader_has_attributes(struct _cef_xml_reader_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefXmlReaderCppToC::Get(self)->HasAttributes();
+
+ // Return type: bool
+ return _retval;
+}
+
+size_t CEF_CALLBACK
+xml_reader_get_attribute_count(struct _cef_xml_reader_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ size_t _retval = CefXmlReaderCppToC::Get(self)->GetAttributeCount();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_string_userfree_t CEF_CALLBACK
+xml_reader_get_attribute_byindex(struct _cef_xml_reader_t* self, int index) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+ // Verify param: index; type: simple_byval
+ DCHECK_GE(index, 0);
+ if (index < 0) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefXmlReaderCppToC::Get(self)->GetAttribute(index);
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_string_userfree_t CEF_CALLBACK
+xml_reader_get_attribute_byqname(struct _cef_xml_reader_t* self,
+ const cef_string_t* qualifiedName) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+ // Verify param: qualifiedName; type: string_byref_const
+ DCHECK(qualifiedName);
+ if (!qualifiedName) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval =
+ CefXmlReaderCppToC::Get(self)->GetAttribute(CefString(qualifiedName));
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_string_userfree_t CEF_CALLBACK
+xml_reader_get_attribute_bylname(struct _cef_xml_reader_t* self,
+ const cef_string_t* localName,
+ const cef_string_t* namespaceURI) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+ // Verify param: localName; type: string_byref_const
+ DCHECK(localName);
+ if (!localName) {
+ return NULL;
+ }
+ // Verify param: namespaceURI; type: string_byref_const
+ DCHECK(namespaceURI);
+ if (!namespaceURI) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefXmlReaderCppToC::Get(self)->GetAttribute(
+ CefString(localName), CefString(namespaceURI));
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_string_userfree_t CEF_CALLBACK
+xml_reader_get_inner_xml(struct _cef_xml_reader_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefXmlReaderCppToC::Get(self)->GetInnerXml();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+cef_string_userfree_t CEF_CALLBACK
+xml_reader_get_outer_xml(struct _cef_xml_reader_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefXmlReaderCppToC::Get(self)->GetOuterXml();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+int CEF_CALLBACK xml_reader_get_line_number(struct _cef_xml_reader_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefXmlReaderCppToC::Get(self)->GetLineNumber();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK
+xml_reader_move_to_attribute_byindex(struct _cef_xml_reader_t* self,
+ int index) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: index; type: simple_byval
+ DCHECK_GE(index, 0);
+ if (index < 0) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefXmlReaderCppToC::Get(self)->MoveToAttribute(index);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+xml_reader_move_to_attribute_byqname(struct _cef_xml_reader_t* self,
+ const cef_string_t* qualifiedName) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: qualifiedName; type: string_byref_const
+ DCHECK(qualifiedName);
+ if (!qualifiedName) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefXmlReaderCppToC::Get(self)->MoveToAttribute(CefString(qualifiedName));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+xml_reader_move_to_attribute_bylname(struct _cef_xml_reader_t* self,
+ const cef_string_t* localName,
+ const cef_string_t* namespaceURI) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: localName; type: string_byref_const
+ DCHECK(localName);
+ if (!localName) {
+ return 0;
+ }
+ // Verify param: namespaceURI; type: string_byref_const
+ DCHECK(namespaceURI);
+ if (!namespaceURI) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefXmlReaderCppToC::Get(self)->MoveToAttribute(
+ CefString(localName), CefString(namespaceURI));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+xml_reader_move_to_first_attribute(struct _cef_xml_reader_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefXmlReaderCppToC::Get(self)->MoveToFirstAttribute();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+xml_reader_move_to_next_attribute(struct _cef_xml_reader_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefXmlReaderCppToC::Get(self)->MoveToNextAttribute();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK
+xml_reader_move_to_carrying_element(struct _cef_xml_reader_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefXmlReaderCppToC::Get(self)->MoveToCarryingElement();
+
+ // Return type: bool
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefXmlReaderCppToC::CefXmlReaderCppToC() {
+ GetStruct()->move_to_next_node = xml_reader_move_to_next_node;
+ GetStruct()->close = xml_reader_close;
+ GetStruct()->has_error = xml_reader_has_error;
+ GetStruct()->get_error = xml_reader_get_error;
+ GetStruct()->get_type = xml_reader_get_type;
+ GetStruct()->get_depth = xml_reader_get_depth;
+ GetStruct()->get_local_name = xml_reader_get_local_name;
+ GetStruct()->get_prefix = xml_reader_get_prefix;
+ GetStruct()->get_qualified_name = xml_reader_get_qualified_name;
+ GetStruct()->get_namespace_uri = xml_reader_get_namespace_uri;
+ GetStruct()->get_base_uri = xml_reader_get_base_uri;
+ GetStruct()->get_xml_lang = xml_reader_get_xml_lang;
+ GetStruct()->is_empty_element = xml_reader_is_empty_element;
+ GetStruct()->has_value = xml_reader_has_value;
+ GetStruct()->get_value = xml_reader_get_value;
+ GetStruct()->has_attributes = xml_reader_has_attributes;
+ GetStruct()->get_attribute_count = xml_reader_get_attribute_count;
+ GetStruct()->get_attribute_byindex = xml_reader_get_attribute_byindex;
+ GetStruct()->get_attribute_byqname = xml_reader_get_attribute_byqname;
+ GetStruct()->get_attribute_bylname = xml_reader_get_attribute_bylname;
+ GetStruct()->get_inner_xml = xml_reader_get_inner_xml;
+ GetStruct()->get_outer_xml = xml_reader_get_outer_xml;
+ GetStruct()->get_line_number = xml_reader_get_line_number;
+ GetStruct()->move_to_attribute_byindex = xml_reader_move_to_attribute_byindex;
+ GetStruct()->move_to_attribute_byqname = xml_reader_move_to_attribute_byqname;
+ GetStruct()->move_to_attribute_bylname = xml_reader_move_to_attribute_bylname;
+ GetStruct()->move_to_first_attribute = xml_reader_move_to_first_attribute;
+ GetStruct()->move_to_next_attribute = xml_reader_move_to_next_attribute;
+ GetStruct()->move_to_carrying_element = xml_reader_move_to_carrying_element;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefXmlReaderCppToC::~CefXmlReaderCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefXmlReader>
+CefCppToCRefCounted<CefXmlReaderCppToC, CefXmlReader, cef_xml_reader_t>::
+ UnwrapDerived(CefWrapperType type, cef_xml_reader_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefXmlReaderCppToC,
+ CefXmlReader,
+ cef_xml_reader_t>::kWrapperType =
+ WT_XML_READER;
diff --git a/libcef_dll/cpptoc/xml_reader_cpptoc.h b/libcef_dll/cpptoc/xml_reader_cpptoc.h
new file mode 100644
index 00000000..0a69e23f
--- /dev/null
+++ b/libcef_dll/cpptoc/xml_reader_cpptoc.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=1305b95acf584a0a0e5fd412e948f195233f476b$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_XML_READER_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_XML_READER_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_xml_reader_capi.h"
+#include "include/cef_xml_reader.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefXmlReaderCppToC : public CefCppToCRefCounted<CefXmlReaderCppToC,
+ CefXmlReader,
+ cef_xml_reader_t> {
+ public:
+ CefXmlReaderCppToC();
+ virtual ~CefXmlReaderCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_XML_READER_CPPTOC_H_
diff --git a/libcef_dll/cpptoc/zip_reader_cpptoc.cc b/libcef_dll/cpptoc/zip_reader_cpptoc.cc
new file mode 100644
index 00000000..35451988
--- /dev/null
+++ b/libcef_dll/cpptoc/zip_reader_cpptoc.cc
@@ -0,0 +1,305 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=c794f92b885a3c50f229606dc1691502a7ab889b$
+//
+
+#include "libcef_dll/cpptoc/zip_reader_cpptoc.h"
+#include "libcef_dll/cpptoc/stream_reader_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// GLOBAL FUNCTIONS - Body may be edited by hand.
+
+CEF_EXPORT cef_zip_reader_t* cef_zip_reader_create(
+ cef_stream_reader_t* stream) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: stream; type: refptr_same
+ DCHECK(stream);
+ if (!stream) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefZipReader> _retval =
+ CefZipReader::Create(CefStreamReaderCppToC::Unwrap(stream));
+
+ // Return type: refptr_same
+ return CefZipReaderCppToC::Wrap(_retval);
+}
+
+namespace {
+
+// MEMBER FUNCTIONS - Body may be edited by hand.
+
+int CEF_CALLBACK zip_reader_move_to_first_file(struct _cef_zip_reader_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefZipReaderCppToC::Get(self)->MoveToFirstFile();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK zip_reader_move_to_next_file(struct _cef_zip_reader_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefZipReaderCppToC::Get(self)->MoveToNextFile();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK zip_reader_move_to_file(struct _cef_zip_reader_t* self,
+ const cef_string_t* fileName,
+ int caseSensitive) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: fileName; type: string_byref_const
+ DCHECK(fileName);
+ if (!fileName) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefZipReaderCppToC::Get(self)->MoveToFile(
+ CefString(fileName), caseSensitive ? true : false);
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK zip_reader_close(struct _cef_zip_reader_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefZipReaderCppToC::Get(self)->Close();
+
+ // Return type: bool
+ return _retval;
+}
+
+cef_string_userfree_t CEF_CALLBACK
+zip_reader_get_file_name(struct _cef_zip_reader_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefZipReaderCppToC::Get(self)->GetFileName();
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+int64 CEF_CALLBACK zip_reader_get_file_size(struct _cef_zip_reader_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int64 _retval = CefZipReaderCppToC::Get(self)->GetFileSize();
+
+ // Return type: simple
+ return _retval;
+}
+
+cef_basetime_t CEF_CALLBACK
+zip_reader_get_file_last_modified(struct _cef_zip_reader_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return CefBaseTime();
+ }
+
+ // Execute
+ cef_basetime_t _retval = CefZipReaderCppToC::Get(self)->GetFileLastModified();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK zip_reader_open_file(struct _cef_zip_reader_t* self,
+ const cef_string_t* password) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Unverified params: password
+
+ // Execute
+ bool _retval = CefZipReaderCppToC::Get(self)->OpenFile(CefString(password));
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK zip_reader_close_file(struct _cef_zip_reader_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefZipReaderCppToC::Get(self)->CloseFile();
+
+ // Return type: bool
+ return _retval;
+}
+
+int CEF_CALLBACK zip_reader_read_file(struct _cef_zip_reader_t* self,
+ void* buffer,
+ size_t bufferSize) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+ // Verify param: buffer; type: simple_byaddr
+ DCHECK(buffer);
+ if (!buffer) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = CefZipReaderCppToC::Get(self)->ReadFile(buffer, bufferSize);
+
+ // Return type: simple
+ return _retval;
+}
+
+int64 CEF_CALLBACK zip_reader_tell(struct _cef_zip_reader_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ int64 _retval = CefZipReaderCppToC::Get(self)->Tell();
+
+ // Return type: simple
+ return _retval;
+}
+
+int CEF_CALLBACK zip_reader_eof(struct _cef_zip_reader_t* self) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ DCHECK(self);
+ if (!self) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefZipReaderCppToC::Get(self)->Eof();
+
+ // Return type: bool
+ return _retval;
+}
+
+} // namespace
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefZipReaderCppToC::CefZipReaderCppToC() {
+ GetStruct()->move_to_first_file = zip_reader_move_to_first_file;
+ GetStruct()->move_to_next_file = zip_reader_move_to_next_file;
+ GetStruct()->move_to_file = zip_reader_move_to_file;
+ GetStruct()->close = zip_reader_close;
+ GetStruct()->get_file_name = zip_reader_get_file_name;
+ GetStruct()->get_file_size = zip_reader_get_file_size;
+ GetStruct()->get_file_last_modified = zip_reader_get_file_last_modified;
+ GetStruct()->open_file = zip_reader_open_file;
+ GetStruct()->close_file = zip_reader_close_file;
+ GetStruct()->read_file = zip_reader_read_file;
+ GetStruct()->tell = zip_reader_tell;
+ GetStruct()->eof = zip_reader_eof;
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefZipReaderCppToC::~CefZipReaderCppToC() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+CefRefPtr<CefZipReader>
+CefCppToCRefCounted<CefZipReaderCppToC, CefZipReader, cef_zip_reader_t>::
+ UnwrapDerived(CefWrapperType type, cef_zip_reader_t* s) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCppToCRefCounted<CefZipReaderCppToC,
+ CefZipReader,
+ cef_zip_reader_t>::kWrapperType =
+ WT_ZIP_READER;
diff --git a/libcef_dll/cpptoc/zip_reader_cpptoc.h b/libcef_dll/cpptoc/zip_reader_cpptoc.h
new file mode 100644
index 00000000..06233d39
--- /dev/null
+++ b/libcef_dll/cpptoc/zip_reader_cpptoc.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=488ca93df16ff22fdd9d397aab117990f01f3331$
+//
+
+#ifndef CEF_LIBCEF_DLL_CPPTOC_ZIP_READER_CPPTOC_H_
+#define CEF_LIBCEF_DLL_CPPTOC_ZIP_READER_CPPTOC_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_zip_reader_capi.h"
+#include "include/cef_zip_reader.h"
+#include "libcef_dll/cpptoc/cpptoc_ref_counted.h"
+
+// Wrap a C++ class with a C structure.
+// This class may be instantiated and accessed DLL-side only.
+class CefZipReaderCppToC : public CefCppToCRefCounted<CefZipReaderCppToC,
+ CefZipReader,
+ cef_zip_reader_t> {
+ public:
+ CefZipReaderCppToC();
+ virtual ~CefZipReaderCppToC();
+};
+
+#endif // CEF_LIBCEF_DLL_CPPTOC_ZIP_READER_CPPTOC_H_
diff --git a/libcef_dll/ctocpp/accessibility_handler_ctocpp.cc b/libcef_dll/ctocpp/accessibility_handler_ctocpp.cc
new file mode 100644
index 00000000..292038dc
--- /dev/null
+++ b/libcef_dll/ctocpp/accessibility_handler_ctocpp.cc
@@ -0,0 +1,90 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=236b528eccad839c6afca3c752c83868fe823fa8$
+//
+
+#include "libcef_dll/ctocpp/accessibility_handler_ctocpp.h"
+#include "libcef_dll/cpptoc/value_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+void CefAccessibilityHandlerCToCpp::OnAccessibilityTreeChange(
+ CefRefPtr<CefValue> value) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_accessibility_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_accessibility_tree_change)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: value; type: refptr_diff
+ DCHECK(value.get());
+ if (!value.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_accessibility_tree_change(_struct, CefValueCppToC::Wrap(value));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefAccessibilityHandlerCToCpp::OnAccessibilityLocationChange(
+ CefRefPtr<CefValue> value) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_accessibility_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_accessibility_location_change)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: value; type: refptr_diff
+ DCHECK(value.get());
+ if (!value.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_accessibility_location_change(_struct,
+ CefValueCppToC::Wrap(value));
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefAccessibilityHandlerCToCpp::CefAccessibilityHandlerCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefAccessibilityHandlerCToCpp::~CefAccessibilityHandlerCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_accessibility_handler_t* CefCToCppRefCounted<
+ CefAccessibilityHandlerCToCpp,
+ CefAccessibilityHandler,
+ cef_accessibility_handler_t>::UnwrapDerived(CefWrapperType type,
+ CefAccessibilityHandler* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefAccessibilityHandlerCToCpp,
+ CefAccessibilityHandler,
+ cef_accessibility_handler_t>::kWrapperType =
+ WT_ACCESSIBILITY_HANDLER;
diff --git a/libcef_dll/ctocpp/accessibility_handler_ctocpp.h b/libcef_dll/ctocpp/accessibility_handler_ctocpp.h
new file mode 100644
index 00000000..0a94e2ea
--- /dev/null
+++ b/libcef_dll/ctocpp/accessibility_handler_ctocpp.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=3bfebc6542251128247e89a55fba8cbb3bc7061d$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_ACCESSIBILITY_HANDLER_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_ACCESSIBILITY_HANDLER_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_accessibility_handler_capi.h"
+#include "include/cef_accessibility_handler.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefAccessibilityHandlerCToCpp
+ : public CefCToCppRefCounted<CefAccessibilityHandlerCToCpp,
+ CefAccessibilityHandler,
+ cef_accessibility_handler_t> {
+ public:
+ CefAccessibilityHandlerCToCpp();
+ virtual ~CefAccessibilityHandlerCToCpp();
+
+ // CefAccessibilityHandler methods.
+ void OnAccessibilityTreeChange(CefRefPtr<CefValue> value) override;
+ void OnAccessibilityLocationChange(CefRefPtr<CefValue> value) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_ACCESSIBILITY_HANDLER_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/app_ctocpp.cc b/libcef_dll/ctocpp/app_ctocpp.cc
new file mode 100644
index 00000000..030401dc
--- /dev/null
+++ b/libcef_dll/ctocpp/app_ctocpp.cc
@@ -0,0 +1,141 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=db849902d1f4a2d4e41103d76fe5985a078a413a$
+//
+
+#include "libcef_dll/ctocpp/app_ctocpp.h"
+#include "libcef_dll/cpptoc/command_line_cpptoc.h"
+#include "libcef_dll/cpptoc/scheme_registrar_cpptoc.h"
+#include "libcef_dll/ctocpp/browser_process_handler_ctocpp.h"
+#include "libcef_dll/ctocpp/render_process_handler_ctocpp.h"
+#include "libcef_dll/ctocpp/resource_bundle_handler_ctocpp.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+void CefAppCToCpp::OnBeforeCommandLineProcessing(
+ const CefString& process_type,
+ CefRefPtr<CefCommandLine> command_line) {
+ cef_app_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_before_command_line_processing)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: command_line; type: refptr_diff
+ DCHECK(command_line.get());
+ if (!command_line.get()) {
+ return;
+ }
+ // Unverified params: process_type
+
+ // Execute
+ _struct->on_before_command_line_processing(
+ _struct, process_type.GetStruct(),
+ CefCommandLineCppToC::Wrap(command_line));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefAppCToCpp::OnRegisterCustomSchemes(
+ CefRawPtr<CefSchemeRegistrar> registrar) {
+ cef_app_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_register_custom_schemes)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: registrar; type: rawptr_diff
+ DCHECK(registrar);
+ if (!registrar) {
+ return;
+ }
+
+ // Translate param: registrar; type: rawptr_diff
+ CefOwnPtr<CefSchemeRegistrarCppToC> registrarPtr(
+ CefSchemeRegistrarCppToC::WrapRaw(registrar));
+
+ // Execute
+ _struct->on_register_custom_schemes(_struct, registrarPtr->GetStruct());
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefResourceBundleHandler> CefAppCToCpp::GetResourceBundleHandler() {
+ cef_app_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_resource_bundle_handler)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_resource_bundle_handler_t* _retval =
+ _struct->get_resource_bundle_handler(_struct);
+
+ // Return type: refptr_same
+ return CefResourceBundleHandlerCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefBrowserProcessHandler> CefAppCToCpp::GetBrowserProcessHandler() {
+ cef_app_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_browser_process_handler)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_browser_process_handler_t* _retval =
+ _struct->get_browser_process_handler(_struct);
+
+ // Return type: refptr_same
+ return CefBrowserProcessHandlerCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefRenderProcessHandler> CefAppCToCpp::GetRenderProcessHandler() {
+ cef_app_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_render_process_handler)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_render_process_handler_t* _retval =
+ _struct->get_render_process_handler(_struct);
+
+ // Return type: refptr_same
+ return CefRenderProcessHandlerCToCpp::Wrap(_retval);
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefAppCToCpp::CefAppCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefAppCToCpp::~CefAppCToCpp() {}
+
+template <>
+cef_app_t* CefCToCppRefCounted<CefAppCToCpp, CefApp, cef_app_t>::UnwrapDerived(
+ CefWrapperType type,
+ CefApp* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCToCppRefCounted<CefAppCToCpp, CefApp, cef_app_t>::kWrapperType = WT_APP;
diff --git a/libcef_dll/ctocpp/app_ctocpp.h b/libcef_dll/ctocpp/app_ctocpp.h
new file mode 100644
index 00000000..80424a30
--- /dev/null
+++ b/libcef_dll/ctocpp/app_ctocpp.h
@@ -0,0 +1,46 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=ea433c4f09f9cc1c432e3406dacfe27ec81c20cb$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_APP_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_APP_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_app_capi.h"
+#include "include/cef_app.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefAppCToCpp
+ : public CefCToCppRefCounted<CefAppCToCpp, CefApp, cef_app_t> {
+ public:
+ CefAppCToCpp();
+ virtual ~CefAppCToCpp();
+
+ // CefApp methods.
+ void OnBeforeCommandLineProcessing(
+ const CefString& process_type,
+ CefRefPtr<CefCommandLine> command_line) override;
+ void OnRegisterCustomSchemes(
+ CefRawPtr<CefSchemeRegistrar> registrar) override;
+ CefRefPtr<CefResourceBundleHandler> GetResourceBundleHandler() override;
+ CefRefPtr<CefBrowserProcessHandler> GetBrowserProcessHandler() override;
+ CefRefPtr<CefRenderProcessHandler> GetRenderProcessHandler() override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_APP_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/audio_handler_ctocpp.cc b/libcef_dll/ctocpp/audio_handler_ctocpp.cc
new file mode 100644
index 00000000..57aeac3c
--- /dev/null
+++ b/libcef_dll/ctocpp/audio_handler_ctocpp.cc
@@ -0,0 +1,176 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=88d580fa35d32ce62d7a20a4febc193ffdaa45ee$
+//
+
+#include "libcef_dll/ctocpp/audio_handler_ctocpp.h"
+#include "libcef_dll/cpptoc/browser_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+bool CefAudioHandlerCToCpp::GetAudioParameters(CefRefPtr<CefBrowser> browser,
+ CefAudioParameters& params) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_audio_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_audio_parameters)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->get_audio_parameters(
+ _struct, CefBrowserCppToC::Wrap(browser), &params);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefAudioHandlerCToCpp::OnAudioStreamStarted(
+ CefRefPtr<CefBrowser> browser,
+ const CefAudioParameters& params,
+ int channels) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_audio_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_audio_stream_started)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_audio_stream_started(_struct, CefBrowserCppToC::Wrap(browser),
+ &params, channels);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefAudioHandlerCToCpp::OnAudioStreamPacket(CefRefPtr<CefBrowser> browser,
+ const float** data,
+ int frames,
+ int64 pts) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_audio_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_audio_stream_packet)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+ // Verify param: data; type: simple_byaddr
+ DCHECK(data);
+ if (!data) {
+ return;
+ }
+
+ // Execute
+ _struct->on_audio_stream_packet(_struct, CefBrowserCppToC::Wrap(browser),
+ data, frames, pts);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefAudioHandlerCToCpp::OnAudioStreamStopped(
+ CefRefPtr<CefBrowser> browser) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_audio_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_audio_stream_stopped)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_audio_stream_stopped(_struct, CefBrowserCppToC::Wrap(browser));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefAudioHandlerCToCpp::OnAudioStreamError(CefRefPtr<CefBrowser> browser,
+ const CefString& message) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_audio_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_audio_stream_error)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+ // Verify param: message; type: string_byref_const
+ DCHECK(!message.empty());
+ if (message.empty()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_audio_stream_error(_struct, CefBrowserCppToC::Wrap(browser),
+ message.GetStruct());
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefAudioHandlerCToCpp::CefAudioHandlerCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefAudioHandlerCToCpp::~CefAudioHandlerCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_audio_handler_t*
+CefCToCppRefCounted<CefAudioHandlerCToCpp,
+ CefAudioHandler,
+ cef_audio_handler_t>::UnwrapDerived(CefWrapperType type,
+ CefAudioHandler* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefAudioHandlerCToCpp,
+ CefAudioHandler,
+ cef_audio_handler_t>::kWrapperType =
+ WT_AUDIO_HANDLER;
diff --git a/libcef_dll/ctocpp/audio_handler_ctocpp.h b/libcef_dll/ctocpp/audio_handler_ctocpp.h
new file mode 100644
index 00000000..07bf46b6
--- /dev/null
+++ b/libcef_dll/ctocpp/audio_handler_ctocpp.h
@@ -0,0 +1,51 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=761b05f6a7cd2f0cfc1968a3902bd874060ad79b$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_AUDIO_HANDLER_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_AUDIO_HANDLER_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_audio_handler_capi.h"
+#include "include/cef_audio_handler.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefAudioHandlerCToCpp : public CefCToCppRefCounted<CefAudioHandlerCToCpp,
+ CefAudioHandler,
+ cef_audio_handler_t> {
+ public:
+ CefAudioHandlerCToCpp();
+ virtual ~CefAudioHandlerCToCpp();
+
+ // CefAudioHandler methods.
+ bool GetAudioParameters(CefRefPtr<CefBrowser> browser,
+ CefAudioParameters& params) override;
+ void OnAudioStreamStarted(CefRefPtr<CefBrowser> browser,
+ const CefAudioParameters& params,
+ int channels) override;
+ void OnAudioStreamPacket(CefRefPtr<CefBrowser> browser,
+ const float** data,
+ int frames,
+ int64 pts) override;
+ void OnAudioStreamStopped(CefRefPtr<CefBrowser> browser) override;
+ void OnAudioStreamError(CefRefPtr<CefBrowser> browser,
+ const CefString& message) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_AUDIO_HANDLER_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/auth_callback_ctocpp.cc b/libcef_dll/ctocpp/auth_callback_ctocpp.cc
new file mode 100644
index 00000000..bb4d6d3c
--- /dev/null
+++ b/libcef_dll/ctocpp/auth_callback_ctocpp.cc
@@ -0,0 +1,76 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=d43fde9a3c77573a0939afc7c7d2016c5b291a40$
+//
+
+#include "libcef_dll/ctocpp/auth_callback_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+void CefAuthCallbackCToCpp::Continue(const CefString& username,
+ const CefString& password) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_auth_callback_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, cont)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: username, password
+
+ // Execute
+ _struct->cont(_struct, username.GetStruct(), password.GetStruct());
+}
+
+NO_SANITIZE("cfi-icall") void CefAuthCallbackCToCpp::Cancel() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_auth_callback_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, cancel)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->cancel(_struct);
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefAuthCallbackCToCpp::CefAuthCallbackCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefAuthCallbackCToCpp::~CefAuthCallbackCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_auth_callback_t*
+CefCToCppRefCounted<CefAuthCallbackCToCpp,
+ CefAuthCallback,
+ cef_auth_callback_t>::UnwrapDerived(CefWrapperType type,
+ CefAuthCallback* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefAuthCallbackCToCpp,
+ CefAuthCallback,
+ cef_auth_callback_t>::kWrapperType =
+ WT_AUTH_CALLBACK;
diff --git a/libcef_dll/ctocpp/auth_callback_ctocpp.h b/libcef_dll/ctocpp/auth_callback_ctocpp.h
new file mode 100644
index 00000000..f6242bdc
--- /dev/null
+++ b/libcef_dll/ctocpp/auth_callback_ctocpp.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=60f444d40338eb245860b389d087e12af15cbf20$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_AUTH_CALLBACK_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_AUTH_CALLBACK_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_auth_callback_capi.h"
+#include "include/cef_auth_callback.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefAuthCallbackCToCpp : public CefCToCppRefCounted<CefAuthCallbackCToCpp,
+ CefAuthCallback,
+ cef_auth_callback_t> {
+ public:
+ CefAuthCallbackCToCpp();
+ virtual ~CefAuthCallbackCToCpp();
+
+ // CefAuthCallback methods.
+ void Continue(const CefString& username, const CefString& password) override;
+ void Cancel() override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_AUTH_CALLBACK_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/base_ref_counted_ctocpp.cc b/libcef_dll/ctocpp/base_ref_counted_ctocpp.cc
new file mode 100644
index 00000000..4b14e3fd
--- /dev/null
+++ b/libcef_dll/ctocpp/base_ref_counted_ctocpp.cc
@@ -0,0 +1,23 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "libcef_dll/ctocpp/base_ref_counted_ctocpp.h"
+
+CefBaseRefCountedCToCpp::CefBaseRefCountedCToCpp() {}
+
+template <>
+cef_base_ref_counted_t* CefCToCppRefCounted<
+ CefBaseRefCountedCToCpp,
+ CefBaseRefCounted,
+ cef_base_ref_counted_t>::UnwrapDerived(CefWrapperType type,
+ CefBaseRefCounted* c) {
+ NOTREACHED();
+ return NULL;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefBaseRefCountedCToCpp,
+ CefBaseRefCounted,
+ cef_base_ref_counted_t>::kWrapperType =
+ WT_BASE_REF_COUNTED;
diff --git a/libcef_dll/ctocpp/base_ref_counted_ctocpp.h b/libcef_dll/ctocpp/base_ref_counted_ctocpp.h
new file mode 100644
index 00000000..dfff39e2
--- /dev/null
+++ b/libcef_dll/ctocpp/base_ref_counted_ctocpp.h
@@ -0,0 +1,26 @@
+// Copyright (c) 2009 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_BASE_REF_COUNTED_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_BASE_REF_COUNTED_CTOCPP_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+#include "include/cef_base.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+// Wrap a C structure with a C++ class.
+class CefBaseRefCountedCToCpp
+ : public CefCToCppRefCounted<CefBaseRefCountedCToCpp,
+ CefBaseRefCounted,
+ cef_base_ref_counted_t> {
+ public:
+ CefBaseRefCountedCToCpp();
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_BASE_REF_COUNTED_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/base_scoped_ctocpp.cc b/libcef_dll/ctocpp/base_scoped_ctocpp.cc
new file mode 100644
index 00000000..40accb5a
--- /dev/null
+++ b/libcef_dll/ctocpp/base_scoped_ctocpp.cc
@@ -0,0 +1,29 @@
+// Copyright (c) 2017 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "libcef_dll/ctocpp/base_scoped_ctocpp.h"
+
+CefBaseScopedCToCpp::CefBaseScopedCToCpp() {}
+
+template <>
+cef_base_scoped_t*
+CefCToCppScoped<CefBaseScopedCToCpp, CefBaseScoped, cef_base_scoped_t>::
+ UnwrapDerivedOwn(CefWrapperType type, CefOwnPtr<CefBaseScoped> c) {
+ NOTREACHED();
+ return NULL;
+}
+
+template <>
+cef_base_scoped_t*
+CefCToCppScoped<CefBaseScopedCToCpp, CefBaseScoped, cef_base_scoped_t>::
+ UnwrapDerivedRaw(CefWrapperType type, CefRawPtr<CefBaseScoped> c) {
+ NOTREACHED();
+ return NULL;
+}
+
+template <>
+CefWrapperType CefCToCppScoped<CefBaseScopedCToCpp,
+ CefBaseScoped,
+ cef_base_scoped_t>::kWrapperType =
+ WT_BASE_SCOPED;
diff --git a/libcef_dll/ctocpp/base_scoped_ctocpp.h b/libcef_dll/ctocpp/base_scoped_ctocpp.h
new file mode 100644
index 00000000..6e7c0852
--- /dev/null
+++ b/libcef_dll/ctocpp/base_scoped_ctocpp.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2017 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_BASE_SCOPED_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_BASE_SCOPED_CTOCPP_H_
+#pragma once
+
+#include "include/capi/cef_base_capi.h"
+#include "include/cef_base.h"
+#include "libcef_dll/ctocpp/ctocpp_scoped.h"
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+// Wrap a C structure with a C++ class.
+class CefBaseScopedCToCpp : public CefCToCppScoped<CefBaseScopedCToCpp,
+ CefBaseScoped,
+ cef_base_scoped_t> {
+ public:
+ CefBaseScopedCToCpp();
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_BASE_SCOPED_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/before_download_callback_ctocpp.cc b/libcef_dll/ctocpp/before_download_callback_ctocpp.cc
new file mode 100644
index 00000000..b3767bb6
--- /dev/null
+++ b/libcef_dll/ctocpp/before_download_callback_ctocpp.cc
@@ -0,0 +1,64 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=720f0530ee0dff9014bc77e1475ba41de29fb890$
+//
+
+#include "libcef_dll/ctocpp/before_download_callback_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+void CefBeforeDownloadCallbackCToCpp::Continue(const CefString& download_path,
+ bool show_dialog) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_before_download_callback_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, cont)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: download_path
+
+ // Execute
+ _struct->cont(_struct, download_path.GetStruct(), show_dialog);
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefBeforeDownloadCallbackCToCpp::CefBeforeDownloadCallbackCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefBeforeDownloadCallbackCToCpp::~CefBeforeDownloadCallbackCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_before_download_callback_t* CefCToCppRefCounted<
+ CefBeforeDownloadCallbackCToCpp,
+ CefBeforeDownloadCallback,
+ cef_before_download_callback_t>::UnwrapDerived(CefWrapperType type,
+ CefBeforeDownloadCallback*
+ c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCToCppRefCounted<CefBeforeDownloadCallbackCToCpp,
+ CefBeforeDownloadCallback,
+ cef_before_download_callback_t>::kWrapperType =
+ WT_BEFORE_DOWNLOAD_CALLBACK;
diff --git a/libcef_dll/ctocpp/before_download_callback_ctocpp.h b/libcef_dll/ctocpp/before_download_callback_ctocpp.h
new file mode 100644
index 00000000..23739dd8
--- /dev/null
+++ b/libcef_dll/ctocpp/before_download_callback_ctocpp.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=743f5b5893055b96eb373b93368c727b3d36d3c6$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_BEFORE_DOWNLOAD_CALLBACK_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_BEFORE_DOWNLOAD_CALLBACK_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_download_handler_capi.h"
+#include "include/cef_download_handler.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefBeforeDownloadCallbackCToCpp
+ : public CefCToCppRefCounted<CefBeforeDownloadCallbackCToCpp,
+ CefBeforeDownloadCallback,
+ cef_before_download_callback_t> {
+ public:
+ CefBeforeDownloadCallbackCToCpp();
+ virtual ~CefBeforeDownloadCallbackCToCpp();
+
+ // CefBeforeDownloadCallback methods.
+ void Continue(const CefString& download_path, bool show_dialog) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_BEFORE_DOWNLOAD_CALLBACK_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/binary_value_ctocpp.cc b/libcef_dll/ctocpp/binary_value_ctocpp.cc
new file mode 100644
index 00000000..8d75247c
--- /dev/null
+++ b/libcef_dll/ctocpp/binary_value_ctocpp.cc
@@ -0,0 +1,207 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=b1bfb92cdbb050816ed3387ad596fa8af7327479$
+//
+
+#include "libcef_dll/ctocpp/binary_value_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// STATIC METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefBinaryValue> CefBinaryValue::Create(const void* data,
+ size_t data_size) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: data; type: simple_byaddr
+ DCHECK(data);
+ if (!data) {
+ return nullptr;
+ }
+
+ // Execute
+ cef_binary_value_t* _retval = cef_binary_value_create(data, data_size);
+
+ // Return type: refptr_same
+ return CefBinaryValueCToCpp::Wrap(_retval);
+}
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") bool CefBinaryValueCToCpp::IsValid() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_binary_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_valid)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_valid(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefBinaryValueCToCpp::IsOwned() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_binary_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_owned)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_owned(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefBinaryValueCToCpp::IsSame(CefRefPtr<CefBinaryValue> that) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_binary_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_same)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: that; type: refptr_same
+ DCHECK(that.get());
+ if (!that.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->is_same(_struct, CefBinaryValueCToCpp::Unwrap(that));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefBinaryValueCToCpp::IsEqual(CefRefPtr<CefBinaryValue> that) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_binary_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_equal)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: that; type: refptr_same
+ DCHECK(that.get());
+ if (!that.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->is_equal(_struct, CefBinaryValueCToCpp::Unwrap(that));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefBinaryValue> CefBinaryValueCToCpp::Copy() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_binary_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, copy)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_binary_value_t* _retval = _struct->copy(_struct);
+
+ // Return type: refptr_same
+ return CefBinaryValueCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") size_t CefBinaryValueCToCpp::GetSize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_binary_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_size)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ size_t _retval = _struct->get_size(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+size_t CefBinaryValueCToCpp::GetData(void* buffer,
+ size_t buffer_size,
+ size_t data_offset) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_binary_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_data)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: buffer; type: simple_byaddr
+ DCHECK(buffer);
+ if (!buffer) {
+ return 0;
+ }
+
+ // Execute
+ size_t _retval = _struct->get_data(_struct, buffer, buffer_size, data_offset);
+
+ // Return type: simple
+ return _retval;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefBinaryValueCToCpp::CefBinaryValueCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefBinaryValueCToCpp::~CefBinaryValueCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_binary_value_t*
+CefCToCppRefCounted<CefBinaryValueCToCpp, CefBinaryValue, cef_binary_value_t>::
+ UnwrapDerived(CefWrapperType type, CefBinaryValue* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefBinaryValueCToCpp,
+ CefBinaryValue,
+ cef_binary_value_t>::kWrapperType =
+ WT_BINARY_VALUE;
diff --git a/libcef_dll/ctocpp/binary_value_ctocpp.h b/libcef_dll/ctocpp/binary_value_ctocpp.h
new file mode 100644
index 00000000..414f7026
--- /dev/null
+++ b/libcef_dll/ctocpp/binary_value_ctocpp.h
@@ -0,0 +1,46 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=b6f011a6c26b4264084eb68dae0d63032c07013c$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_BINARY_VALUE_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_BINARY_VALUE_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_values_capi.h"
+#include "include/cef_values.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefBinaryValueCToCpp : public CefCToCppRefCounted<CefBinaryValueCToCpp,
+ CefBinaryValue,
+ cef_binary_value_t> {
+ public:
+ CefBinaryValueCToCpp();
+ virtual ~CefBinaryValueCToCpp();
+
+ // CefBinaryValue methods.
+ bool IsValid() override;
+ bool IsOwned() override;
+ bool IsSame(CefRefPtr<CefBinaryValue> that) override;
+ bool IsEqual(CefRefPtr<CefBinaryValue> that) override;
+ CefRefPtr<CefBinaryValue> Copy() override;
+ size_t GetSize() override;
+ size_t GetData(void* buffer, size_t buffer_size, size_t data_offset) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_BINARY_VALUE_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/browser_ctocpp.cc b/libcef_dll/ctocpp/browser_ctocpp.cc
new file mode 100644
index 00000000..3ffff4fa
--- /dev/null
+++ b/libcef_dll/ctocpp/browser_ctocpp.cc
@@ -0,0 +1,436 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=d81e2665aee6c13c537a443480bfff9b8bc6bd47$
+//
+
+#include "libcef_dll/ctocpp/browser_ctocpp.h"
+#include <algorithm>
+#include "libcef_dll/ctocpp/browser_host_ctocpp.h"
+#include "libcef_dll/ctocpp/frame_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+#include "libcef_dll/transfer_util.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") bool CefBrowserCToCpp::IsValid() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_valid)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_valid(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefBrowserHost> CefBrowserCToCpp::GetHost() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_host)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_browser_host_t* _retval = _struct->get_host(_struct);
+
+ // Return type: refptr_same
+ return CefBrowserHostCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") bool CefBrowserCToCpp::CanGoBack() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, can_go_back)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->can_go_back(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") void CefBrowserCToCpp::GoBack() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, go_back)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->go_back(_struct);
+}
+
+NO_SANITIZE("cfi-icall") bool CefBrowserCToCpp::CanGoForward() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, can_go_forward)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->can_go_forward(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") void CefBrowserCToCpp::GoForward() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, go_forward)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->go_forward(_struct);
+}
+
+NO_SANITIZE("cfi-icall") bool CefBrowserCToCpp::IsLoading() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_loading)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_loading(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") void CefBrowserCToCpp::Reload() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, reload)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->reload(_struct);
+}
+
+NO_SANITIZE("cfi-icall") void CefBrowserCToCpp::ReloadIgnoreCache() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, reload_ignore_cache)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->reload_ignore_cache(_struct);
+}
+
+NO_SANITIZE("cfi-icall") void CefBrowserCToCpp::StopLoad() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, stop_load)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->stop_load(_struct);
+}
+
+NO_SANITIZE("cfi-icall") int CefBrowserCToCpp::GetIdentifier() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_identifier)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_identifier(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefBrowserCToCpp::IsSame(CefRefPtr<CefBrowser> that) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_same)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: that; type: refptr_same
+ DCHECK(that.get());
+ if (!that.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->is_same(_struct, CefBrowserCToCpp::Unwrap(that));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefBrowserCToCpp::IsPopup() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_popup)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_popup(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefBrowserCToCpp::HasDocument() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, has_document)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->has_document(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefFrame> CefBrowserCToCpp::GetMainFrame() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_main_frame)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_frame_t* _retval = _struct->get_main_frame(_struct);
+
+ // Return type: refptr_same
+ return CefFrameCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefFrame> CefBrowserCToCpp::GetFocusedFrame() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_focused_frame)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_frame_t* _retval = _struct->get_focused_frame(_struct);
+
+ // Return type: refptr_same
+ return CefFrameCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefFrame> CefBrowserCToCpp::GetFrame(int64 identifier) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_frame_byident)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_frame_t* _retval = _struct->get_frame_byident(_struct, identifier);
+
+ // Return type: refptr_same
+ return CefFrameCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefFrame> CefBrowserCToCpp::GetFrame(const CefString& name) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_frame)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: name
+
+ // Execute
+ cef_frame_t* _retval = _struct->get_frame(_struct, name.GetStruct());
+
+ // Return type: refptr_same
+ return CefFrameCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") size_t CefBrowserCToCpp::GetFrameCount() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_frame_count)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ size_t _retval = _struct->get_frame_count(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefBrowserCToCpp::GetFrameIdentifiers(std::vector<int64>& identifiers) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_frame_identifiers)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Translate param: identifiers; type: simple_vec_byref
+ size_t identifiersSize = identifiers.size();
+ size_t identifiersCount = std::max(GetFrameCount(), identifiersSize);
+ int64* identifiersList = NULL;
+ if (identifiersCount > 0) {
+ identifiersList = new int64[identifiersCount];
+ DCHECK(identifiersList);
+ if (identifiersList) {
+ memset(identifiersList, 0, sizeof(int64) * identifiersCount);
+ }
+ if (identifiersList && identifiersSize > 0) {
+ for (size_t i = 0; i < identifiersSize; ++i) {
+ identifiersList[i] = identifiers[i];
+ }
+ }
+ }
+
+ // Execute
+ _struct->get_frame_identifiers(_struct, &identifiersCount, identifiersList);
+
+ // Restore param:identifiers; type: simple_vec_byref
+ identifiers.clear();
+ if (identifiersCount > 0 && identifiersList) {
+ for (size_t i = 0; i < identifiersCount; ++i) {
+ identifiers.push_back(identifiersList[i]);
+ }
+ delete[] identifiersList;
+ }
+}
+
+NO_SANITIZE("cfi-icall")
+void CefBrowserCToCpp::GetFrameNames(std::vector<CefString>& names) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_frame_names)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Translate param: names; type: string_vec_byref
+ cef_string_list_t namesList = cef_string_list_alloc();
+ DCHECK(namesList);
+ if (namesList) {
+ transfer_string_list_contents(names, namesList);
+ }
+
+ // Execute
+ _struct->get_frame_names(_struct, namesList);
+
+ // Restore param:names; type: string_vec_byref
+ if (namesList) {
+ names.clear();
+ transfer_string_list_contents(namesList, names);
+ cef_string_list_free(namesList);
+ }
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefBrowserCToCpp::CefBrowserCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefBrowserCToCpp::~CefBrowserCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_browser_t*
+CefCToCppRefCounted<CefBrowserCToCpp, CefBrowser, cef_browser_t>::UnwrapDerived(
+ CefWrapperType type,
+ CefBrowser* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefBrowserCToCpp,
+ CefBrowser,
+ cef_browser_t>::kWrapperType = WT_BROWSER;
diff --git a/libcef_dll/ctocpp/browser_ctocpp.h b/libcef_dll/ctocpp/browser_ctocpp.h
new file mode 100644
index 00000000..dcb1fb3a
--- /dev/null
+++ b/libcef_dll/ctocpp/browser_ctocpp.h
@@ -0,0 +1,62 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=675d288fbd8077e1a702308dd4a57e63aea00ba8$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_BROWSER_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_BROWSER_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include <vector>
+#include "include/capi/cef_browser_capi.h"
+#include "include/capi/cef_client_capi.h"
+#include "include/cef_browser.h"
+#include "include/cef_client.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefBrowserCToCpp
+ : public CefCToCppRefCounted<CefBrowserCToCpp, CefBrowser, cef_browser_t> {
+ public:
+ CefBrowserCToCpp();
+ virtual ~CefBrowserCToCpp();
+
+ // CefBrowser methods.
+ bool IsValid() override;
+ CefRefPtr<CefBrowserHost> GetHost() override;
+ bool CanGoBack() override;
+ void GoBack() override;
+ bool CanGoForward() override;
+ void GoForward() override;
+ bool IsLoading() override;
+ void Reload() override;
+ void ReloadIgnoreCache() override;
+ void StopLoad() override;
+ int GetIdentifier() override;
+ bool IsSame(CefRefPtr<CefBrowser> that) override;
+ bool IsPopup() override;
+ bool HasDocument() override;
+ CefRefPtr<CefFrame> GetMainFrame() override;
+ CefRefPtr<CefFrame> GetFocusedFrame() override;
+ CefRefPtr<CefFrame> GetFrame(int64 identifier) override;
+ CefRefPtr<CefFrame> GetFrame(const CefString& name) override;
+ size_t GetFrameCount() override;
+ void GetFrameIdentifiers(std::vector<int64>& identifiers) override;
+ void GetFrameNames(std::vector<CefString>& names) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_BROWSER_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/browser_host_ctocpp.cc b/libcef_dll/ctocpp/browser_host_ctocpp.cc
new file mode 100644
index 00000000..490caa71
--- /dev/null
+++ b/libcef_dll/ctocpp/browser_host_ctocpp.cc
@@ -0,0 +1,1204 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=aad33efa7cb9fe4904f1fcafecd960e2b3c86ab1$
+//
+
+#include "libcef_dll/ctocpp/browser_host_ctocpp.h"
+#include "libcef_dll/cpptoc/client_cpptoc.h"
+#include "libcef_dll/cpptoc/dev_tools_message_observer_cpptoc.h"
+#include "libcef_dll/cpptoc/download_image_callback_cpptoc.h"
+#include "libcef_dll/cpptoc/navigation_entry_visitor_cpptoc.h"
+#include "libcef_dll/cpptoc/pdf_print_callback_cpptoc.h"
+#include "libcef_dll/cpptoc/run_file_dialog_callback_cpptoc.h"
+#include "libcef_dll/ctocpp/browser_ctocpp.h"
+#include "libcef_dll/ctocpp/dictionary_value_ctocpp.h"
+#include "libcef_dll/ctocpp/drag_data_ctocpp.h"
+#include "libcef_dll/ctocpp/extension_ctocpp.h"
+#include "libcef_dll/ctocpp/navigation_entry_ctocpp.h"
+#include "libcef_dll/ctocpp/registration_ctocpp.h"
+#include "libcef_dll/ctocpp/request_context_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+#include "libcef_dll/transfer_util.h"
+
+// STATIC METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+bool CefBrowserHost::CreateBrowser(
+ const CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient> client,
+ const CefString& url,
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefDictionaryValue> extra_info,
+ CefRefPtr<CefRequestContext> request_context) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: client, url, extra_info, request_context
+
+ // Execute
+ int _retval = cef_browser_host_create_browser(
+ &windowInfo, CefClientCppToC::Wrap(client), url.GetStruct(), &settings,
+ CefDictionaryValueCToCpp::Unwrap(extra_info),
+ CefRequestContextCToCpp::Unwrap(request_context));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefBrowser> CefBrowserHost::CreateBrowserSync(
+ const CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient> client,
+ const CefString& url,
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefDictionaryValue> extra_info,
+ CefRefPtr<CefRequestContext> request_context) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: client, url, extra_info, request_context
+
+ // Execute
+ cef_browser_t* _retval = cef_browser_host_create_browser_sync(
+ &windowInfo, CefClientCppToC::Wrap(client), url.GetStruct(), &settings,
+ CefDictionaryValueCToCpp::Unwrap(extra_info),
+ CefRequestContextCToCpp::Unwrap(request_context));
+
+ // Return type: refptr_same
+ return CefBrowserCToCpp::Wrap(_retval);
+}
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefBrowser> CefBrowserHostCToCpp::GetBrowser() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_browser)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_browser_t* _retval = _struct->get_browser(_struct);
+
+ // Return type: refptr_same
+ return CefBrowserCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefBrowserHostCToCpp::CloseBrowser(bool force_close) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, close_browser)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->close_browser(_struct, force_close);
+}
+
+NO_SANITIZE("cfi-icall") bool CefBrowserHostCToCpp::TryCloseBrowser() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, try_close_browser)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->try_close_browser(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") void CefBrowserHostCToCpp::SetFocus(bool focus) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_focus)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_focus(_struct, focus);
+}
+
+NO_SANITIZE("cfi-icall")
+CefWindowHandle CefBrowserHostCToCpp::GetWindowHandle() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_window_handle)) {
+ return kNullWindowHandle;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_window_handle_t _retval = _struct->get_window_handle(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CefWindowHandle CefBrowserHostCToCpp::GetOpenerWindowHandle() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_opener_window_handle)) {
+ return kNullWindowHandle;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_window_handle_t _retval = _struct->get_opener_window_handle(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") bool CefBrowserHostCToCpp::HasView() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, has_view)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->has_view(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefClient> CefBrowserHostCToCpp::GetClient() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_client)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_client_t* _retval = _struct->get_client(_struct);
+
+ // Return type: refptr_diff
+ return CefClientCppToC::Unwrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefRequestContext> CefBrowserHostCToCpp::GetRequestContext() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_request_context)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_request_context_t* _retval = _struct->get_request_context(_struct);
+
+ // Return type: refptr_same
+ return CefRequestContextCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") double CefBrowserHostCToCpp::GetZoomLevel() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_zoom_level)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ double _retval = _struct->get_zoom_level(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefBrowserHostCToCpp::SetZoomLevel(double zoomLevel) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_zoom_level)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_zoom_level(_struct, zoomLevel);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefBrowserHostCToCpp::RunFileDialog(
+ FileDialogMode mode,
+ const CefString& title,
+ const CefString& default_file_path,
+ const std::vector<CefString>& accept_filters,
+ CefRefPtr<CefRunFileDialogCallback> callback) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, run_file_dialog)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: callback; type: refptr_diff
+ DCHECK(callback.get());
+ if (!callback.get()) {
+ return;
+ }
+ // Unverified params: title, default_file_path, accept_filters
+
+ // Translate param: accept_filters; type: string_vec_byref_const
+ cef_string_list_t accept_filtersList = cef_string_list_alloc();
+ DCHECK(accept_filtersList);
+ if (accept_filtersList) {
+ transfer_string_list_contents(accept_filters, accept_filtersList);
+ }
+
+ // Execute
+ _struct->run_file_dialog(_struct, mode, title.GetStruct(),
+ default_file_path.GetStruct(), accept_filtersList,
+ CefRunFileDialogCallbackCppToC::Wrap(callback));
+
+ // Restore param:accept_filters; type: string_vec_byref_const
+ if (accept_filtersList) {
+ cef_string_list_free(accept_filtersList);
+ }
+}
+
+NO_SANITIZE("cfi-icall")
+void CefBrowserHostCToCpp::StartDownload(const CefString& url) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, start_download)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: url; type: string_byref_const
+ DCHECK(!url.empty());
+ if (url.empty()) {
+ return;
+ }
+
+ // Execute
+ _struct->start_download(_struct, url.GetStruct());
+}
+
+NO_SANITIZE("cfi-icall")
+void CefBrowserHostCToCpp::DownloadImage(
+ const CefString& image_url,
+ bool is_favicon,
+ uint32 max_image_size,
+ bool bypass_cache,
+ CefRefPtr<CefDownloadImageCallback> callback) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, download_image)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: image_url; type: string_byref_const
+ DCHECK(!image_url.empty());
+ if (image_url.empty()) {
+ return;
+ }
+ // Verify param: callback; type: refptr_diff
+ DCHECK(callback.get());
+ if (!callback.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->download_image(_struct, image_url.GetStruct(), is_favicon,
+ max_image_size, bypass_cache,
+ CefDownloadImageCallbackCppToC::Wrap(callback));
+}
+
+NO_SANITIZE("cfi-icall") void CefBrowserHostCToCpp::Print() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, print)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->print(_struct);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefBrowserHostCToCpp::PrintToPDF(const CefString& path,
+ const CefPdfPrintSettings& settings,
+ CefRefPtr<CefPdfPrintCallback> callback) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, print_to_pdf)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: path; type: string_byref_const
+ DCHECK(!path.empty());
+ if (path.empty()) {
+ return;
+ }
+ // Unverified params: callback
+
+ // Execute
+ _struct->print_to_pdf(_struct, path.GetStruct(), &settings,
+ CefPdfPrintCallbackCppToC::Wrap(callback));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefBrowserHostCToCpp::Find(const CefString& searchText,
+ bool forward,
+ bool matchCase,
+ bool findNext) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, find)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: searchText; type: string_byref_const
+ DCHECK(!searchText.empty());
+ if (searchText.empty()) {
+ return;
+ }
+
+ // Execute
+ _struct->find(_struct, searchText.GetStruct(), forward, matchCase, findNext);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefBrowserHostCToCpp::StopFinding(bool clearSelection) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, stop_finding)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->stop_finding(_struct, clearSelection);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefBrowserHostCToCpp::ShowDevTools(const CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient> client,
+ const CefBrowserSettings& settings,
+ const CefPoint& inspect_element_at) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, show_dev_tools)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: windowInfo, client, settings, inspect_element_at
+
+ // Execute
+ _struct->show_dev_tools(_struct, &windowInfo, CefClientCppToC::Wrap(client),
+ &settings, &inspect_element_at);
+}
+
+NO_SANITIZE("cfi-icall") void CefBrowserHostCToCpp::CloseDevTools() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, close_dev_tools)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->close_dev_tools(_struct);
+}
+
+NO_SANITIZE("cfi-icall") bool CefBrowserHostCToCpp::HasDevTools() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, has_dev_tools)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->has_dev_tools(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefBrowserHostCToCpp::SendDevToolsMessage(const void* message,
+ size_t message_size) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, send_dev_tools_message)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: message; type: simple_byaddr
+ DCHECK(message);
+ if (!message) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->send_dev_tools_message(_struct, message, message_size);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+int CefBrowserHostCToCpp::ExecuteDevToolsMethod(
+ int message_id,
+ const CefString& method,
+ CefRefPtr<CefDictionaryValue> params) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, execute_dev_tools_method)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: method; type: string_byref_const
+ DCHECK(!method.empty());
+ if (method.empty()) {
+ return 0;
+ }
+ // Unverified params: params
+
+ // Execute
+ int _retval = _struct->execute_dev_tools_method(
+ _struct, message_id, method.GetStruct(),
+ CefDictionaryValueCToCpp::Unwrap(params));
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefRegistration> CefBrowserHostCToCpp::AddDevToolsMessageObserver(
+ CefRefPtr<CefDevToolsMessageObserver> observer) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, add_dev_tools_message_observer)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: observer; type: refptr_diff
+ DCHECK(observer.get());
+ if (!observer.get()) {
+ return nullptr;
+ }
+
+ // Execute
+ cef_registration_t* _retval = _struct->add_dev_tools_message_observer(
+ _struct, CefDevToolsMessageObserverCppToC::Wrap(observer));
+
+ // Return type: refptr_same
+ return CefRegistrationCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefBrowserHostCToCpp::GetNavigationEntries(
+ CefRefPtr<CefNavigationEntryVisitor> visitor,
+ bool current_only) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_navigation_entries)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: visitor; type: refptr_diff
+ DCHECK(visitor.get());
+ if (!visitor.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->get_navigation_entries(
+ _struct, CefNavigationEntryVisitorCppToC::Wrap(visitor), current_only);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefBrowserHostCToCpp::ReplaceMisspelling(const CefString& word) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, replace_misspelling)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: word; type: string_byref_const
+ DCHECK(!word.empty());
+ if (word.empty()) {
+ return;
+ }
+
+ // Execute
+ _struct->replace_misspelling(_struct, word.GetStruct());
+}
+
+NO_SANITIZE("cfi-icall")
+void CefBrowserHostCToCpp::AddWordToDictionary(const CefString& word) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, add_word_to_dictionary)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: word; type: string_byref_const
+ DCHECK(!word.empty());
+ if (word.empty()) {
+ return;
+ }
+
+ // Execute
+ _struct->add_word_to_dictionary(_struct, word.GetStruct());
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefBrowserHostCToCpp::IsWindowRenderingDisabled() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_window_rendering_disabled)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_window_rendering_disabled(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") void CefBrowserHostCToCpp::WasResized() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, was_resized)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->was_resized(_struct);
+}
+
+NO_SANITIZE("cfi-icall") void CefBrowserHostCToCpp::WasHidden(bool hidden) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, was_hidden)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->was_hidden(_struct, hidden);
+}
+
+NO_SANITIZE("cfi-icall") void CefBrowserHostCToCpp::NotifyScreenInfoChanged() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, notify_screen_info_changed)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->notify_screen_info_changed(_struct);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefBrowserHostCToCpp::Invalidate(PaintElementType type) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, invalidate)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->invalidate(_struct, type);
+}
+
+NO_SANITIZE("cfi-icall") void CefBrowserHostCToCpp::SendExternalBeginFrame() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, send_external_begin_frame)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->send_external_begin_frame(_struct);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefBrowserHostCToCpp::SendKeyEvent(const CefKeyEvent& event) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, send_key_event)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->send_key_event(_struct, &event);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefBrowserHostCToCpp::SendMouseClickEvent(const CefMouseEvent& event,
+ MouseButtonType type,
+ bool mouseUp,
+ int clickCount) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, send_mouse_click_event)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->send_mouse_click_event(_struct, &event, type, mouseUp, clickCount);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefBrowserHostCToCpp::SendMouseMoveEvent(const CefMouseEvent& event,
+ bool mouseLeave) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, send_mouse_move_event)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->send_mouse_move_event(_struct, &event, mouseLeave);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefBrowserHostCToCpp::SendMouseWheelEvent(const CefMouseEvent& event,
+ int deltaX,
+ int deltaY) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, send_mouse_wheel_event)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->send_mouse_wheel_event(_struct, &event, deltaX, deltaY);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefBrowserHostCToCpp::SendTouchEvent(const CefTouchEvent& event) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, send_touch_event)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->send_touch_event(_struct, &event);
+}
+
+NO_SANITIZE("cfi-icall") void CefBrowserHostCToCpp::SendCaptureLostEvent() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, send_capture_lost_event)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->send_capture_lost_event(_struct);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefBrowserHostCToCpp::NotifyMoveOrResizeStarted() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, notify_move_or_resize_started)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->notify_move_or_resize_started(_struct);
+}
+
+NO_SANITIZE("cfi-icall") int CefBrowserHostCToCpp::GetWindowlessFrameRate() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_windowless_frame_rate)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_windowless_frame_rate(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefBrowserHostCToCpp::SetWindowlessFrameRate(int frame_rate) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_windowless_frame_rate)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_windowless_frame_rate(_struct, frame_rate);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefBrowserHostCToCpp::ImeSetComposition(
+ const CefString& text,
+ const std::vector<CefCompositionUnderline>& underlines,
+ const CefRange& replacement_range,
+ const CefRange& selection_range) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, ime_set_composition)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: text, underlines
+
+ // Translate param: underlines; type: simple_vec_byref_const
+ const size_t underlinesCount = underlines.size();
+ cef_composition_underline_t* underlinesList = NULL;
+ if (underlinesCount > 0) {
+ underlinesList = new cef_composition_underline_t[underlinesCount];
+ DCHECK(underlinesList);
+ if (underlinesList) {
+ for (size_t i = 0; i < underlinesCount; ++i) {
+ underlinesList[i] = underlines[i];
+ }
+ }
+ }
+
+ // Execute
+ _struct->ime_set_composition(_struct, text.GetStruct(), underlinesCount,
+ underlinesList, &replacement_range,
+ &selection_range);
+
+ // Restore param:underlines; type: simple_vec_byref_const
+ if (underlinesList) {
+ delete[] underlinesList;
+ }
+}
+
+NO_SANITIZE("cfi-icall")
+void CefBrowserHostCToCpp::ImeCommitText(const CefString& text,
+ const CefRange& replacement_range,
+ int relative_cursor_pos) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, ime_commit_text)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: text
+
+ // Execute
+ _struct->ime_commit_text(_struct, text.GetStruct(), &replacement_range,
+ relative_cursor_pos);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefBrowserHostCToCpp::ImeFinishComposingText(bool keep_selection) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, ime_finish_composing_text)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->ime_finish_composing_text(_struct, keep_selection);
+}
+
+NO_SANITIZE("cfi-icall") void CefBrowserHostCToCpp::ImeCancelComposition() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, ime_cancel_composition)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->ime_cancel_composition(_struct);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefBrowserHostCToCpp::DragTargetDragEnter(CefRefPtr<CefDragData> drag_data,
+ const CefMouseEvent& event,
+ DragOperationsMask allowed_ops) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, drag_target_drag_enter)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: drag_data; type: refptr_same
+ DCHECK(drag_data.get());
+ if (!drag_data.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->drag_target_drag_enter(_struct, CefDragDataCToCpp::Unwrap(drag_data),
+ &event, allowed_ops);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefBrowserHostCToCpp::DragTargetDragOver(const CefMouseEvent& event,
+ DragOperationsMask allowed_ops) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, drag_target_drag_over)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->drag_target_drag_over(_struct, &event, allowed_ops);
+}
+
+NO_SANITIZE("cfi-icall") void CefBrowserHostCToCpp::DragTargetDragLeave() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, drag_target_drag_leave)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->drag_target_drag_leave(_struct);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefBrowserHostCToCpp::DragTargetDrop(const CefMouseEvent& event) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, drag_target_drop)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->drag_target_drop(_struct, &event);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefBrowserHostCToCpp::DragSourceEndedAt(int x,
+ int y,
+ DragOperationsMask op) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, drag_source_ended_at)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->drag_source_ended_at(_struct, x, y, op);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefBrowserHostCToCpp::DragSourceSystemDragEnded() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, drag_source_system_drag_ended)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->drag_source_system_drag_ended(_struct);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefNavigationEntry>
+CefBrowserHostCToCpp::GetVisibleNavigationEntry() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_visible_navigation_entry)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_navigation_entry_t* _retval =
+ _struct->get_visible_navigation_entry(_struct);
+
+ // Return type: refptr_same
+ return CefNavigationEntryCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefBrowserHostCToCpp::SetAccessibilityState(
+ cef_state_t accessibility_state) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_accessibility_state)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_accessibility_state(_struct, accessibility_state);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefBrowserHostCToCpp::SetAutoResizeEnabled(bool enabled,
+ const CefSize& min_size,
+ const CefSize& max_size) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_auto_resize_enabled)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_auto_resize_enabled(_struct, enabled, &min_size, &max_size);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefExtension> CefBrowserHostCToCpp::GetExtension() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_extension)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_extension_t* _retval = _struct->get_extension(_struct);
+
+ // Return type: refptr_same
+ return CefExtensionCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") bool CefBrowserHostCToCpp::IsBackgroundHost() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_background_host)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_background_host(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") void CefBrowserHostCToCpp::SetAudioMuted(bool mute) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_audio_muted)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_audio_muted(_struct, mute);
+}
+
+NO_SANITIZE("cfi-icall") bool CefBrowserHostCToCpp::IsAudioMuted() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_host_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_audio_muted)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_audio_muted(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefBrowserHostCToCpp::CefBrowserHostCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefBrowserHostCToCpp::~CefBrowserHostCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_browser_host_t*
+CefCToCppRefCounted<CefBrowserHostCToCpp, CefBrowserHost, cef_browser_host_t>::
+ UnwrapDerived(CefWrapperType type, CefBrowserHost* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefBrowserHostCToCpp,
+ CefBrowserHost,
+ cef_browser_host_t>::kWrapperType =
+ WT_BROWSER_HOST;
diff --git a/libcef_dll/ctocpp/browser_host_ctocpp.h b/libcef_dll/ctocpp/browser_host_ctocpp.h
new file mode 100644
index 00000000..b721a69b
--- /dev/null
+++ b/libcef_dll/ctocpp/browser_host_ctocpp.h
@@ -0,0 +1,136 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=95d1cd8a96633dc2338a636c3c4eda9a15442846$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_BROWSER_HOST_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_BROWSER_HOST_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include <vector>
+#include "include/capi/cef_browser_capi.h"
+#include "include/capi/cef_client_capi.h"
+#include "include/cef_browser.h"
+#include "include/cef_client.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefBrowserHostCToCpp : public CefCToCppRefCounted<CefBrowserHostCToCpp,
+ CefBrowserHost,
+ cef_browser_host_t> {
+ public:
+ CefBrowserHostCToCpp();
+ virtual ~CefBrowserHostCToCpp();
+
+ // CefBrowserHost methods.
+ CefRefPtr<CefBrowser> GetBrowser() override;
+ void CloseBrowser(bool force_close) override;
+ bool TryCloseBrowser() override;
+ void SetFocus(bool focus) override;
+ CefWindowHandle GetWindowHandle() override;
+ CefWindowHandle GetOpenerWindowHandle() override;
+ bool HasView() override;
+ CefRefPtr<CefClient> GetClient() override;
+ CefRefPtr<CefRequestContext> GetRequestContext() override;
+ double GetZoomLevel() override;
+ void SetZoomLevel(double zoomLevel) override;
+ void RunFileDialog(FileDialogMode mode,
+ const CefString& title,
+ const CefString& default_file_path,
+ const std::vector<CefString>& accept_filters,
+ CefRefPtr<CefRunFileDialogCallback> callback) override;
+ void StartDownload(const CefString& url) override;
+ void DownloadImage(const CefString& image_url,
+ bool is_favicon,
+ uint32 max_image_size,
+ bool bypass_cache,
+ CefRefPtr<CefDownloadImageCallback> callback) override;
+ void Print() override;
+ void PrintToPDF(const CefString& path,
+ const CefPdfPrintSettings& settings,
+ CefRefPtr<CefPdfPrintCallback> callback) override;
+ void Find(const CefString& searchText,
+ bool forward,
+ bool matchCase,
+ bool findNext) override;
+ void StopFinding(bool clearSelection) override;
+ void ShowDevTools(const CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient> client,
+ const CefBrowserSettings& settings,
+ const CefPoint& inspect_element_at) override;
+ void CloseDevTools() override;
+ bool HasDevTools() override;
+ bool SendDevToolsMessage(const void* message, size_t message_size) override;
+ int ExecuteDevToolsMethod(int message_id,
+ const CefString& method,
+ CefRefPtr<CefDictionaryValue> params) override;
+ CefRefPtr<CefRegistration> AddDevToolsMessageObserver(
+ CefRefPtr<CefDevToolsMessageObserver> observer) override;
+ void GetNavigationEntries(CefRefPtr<CefNavigationEntryVisitor> visitor,
+ bool current_only) override;
+ void ReplaceMisspelling(const CefString& word) override;
+ void AddWordToDictionary(const CefString& word) override;
+ bool IsWindowRenderingDisabled() override;
+ void WasResized() override;
+ void WasHidden(bool hidden) override;
+ void NotifyScreenInfoChanged() override;
+ void Invalidate(PaintElementType type) override;
+ void SendExternalBeginFrame() override;
+ void SendKeyEvent(const CefKeyEvent& event) override;
+ void SendMouseClickEvent(const CefMouseEvent& event,
+ MouseButtonType type,
+ bool mouseUp,
+ int clickCount) override;
+ void SendMouseMoveEvent(const CefMouseEvent& event, bool mouseLeave) override;
+ void SendMouseWheelEvent(const CefMouseEvent& event,
+ int deltaX,
+ int deltaY) override;
+ void SendTouchEvent(const CefTouchEvent& event) override;
+ void SendCaptureLostEvent() override;
+ void NotifyMoveOrResizeStarted() override;
+ int GetWindowlessFrameRate() override;
+ void SetWindowlessFrameRate(int frame_rate) override;
+ void ImeSetComposition(const CefString& text,
+ const std::vector<CefCompositionUnderline>& underlines,
+ const CefRange& replacement_range,
+ const CefRange& selection_range) override;
+ void ImeCommitText(const CefString& text,
+ const CefRange& replacement_range,
+ int relative_cursor_pos) override;
+ void ImeFinishComposingText(bool keep_selection) override;
+ void ImeCancelComposition() override;
+ void DragTargetDragEnter(CefRefPtr<CefDragData> drag_data,
+ const CefMouseEvent& event,
+ DragOperationsMask allowed_ops) override;
+ void DragTargetDragOver(const CefMouseEvent& event,
+ DragOperationsMask allowed_ops) override;
+ void DragTargetDragLeave() override;
+ void DragTargetDrop(const CefMouseEvent& event) override;
+ void DragSourceEndedAt(int x, int y, DragOperationsMask op) override;
+ void DragSourceSystemDragEnded() override;
+ CefRefPtr<CefNavigationEntry> GetVisibleNavigationEntry() override;
+ void SetAccessibilityState(cef_state_t accessibility_state) override;
+ void SetAutoResizeEnabled(bool enabled,
+ const CefSize& min_size,
+ const CefSize& max_size) override;
+ CefRefPtr<CefExtension> GetExtension() override;
+ bool IsBackgroundHost() override;
+ void SetAudioMuted(bool mute) override;
+ bool IsAudioMuted() override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_BROWSER_HOST_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/browser_process_handler_ctocpp.cc b/libcef_dll/ctocpp/browser_process_handler_ctocpp.cc
new file mode 100644
index 00000000..b87e9292
--- /dev/null
+++ b/libcef_dll/ctocpp/browser_process_handler_ctocpp.cc
@@ -0,0 +1,134 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=08bc3d3dc2179824d250c38c1d1165c642110e87$
+//
+
+#include "libcef_dll/ctocpp/browser_process_handler_ctocpp.h"
+#include "libcef_dll/cpptoc/command_line_cpptoc.h"
+#include "libcef_dll/cpptoc/preference_registrar_cpptoc.h"
+#include "libcef_dll/ctocpp/client_ctocpp.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+void CefBrowserProcessHandlerCToCpp::OnRegisterCustomPreferences(
+ cef_preferences_type_t type,
+ CefRawPtr<CefPreferenceRegistrar> registrar) {
+ cef_browser_process_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_register_custom_preferences)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: registrar; type: rawptr_diff
+ DCHECK(registrar);
+ if (!registrar) {
+ return;
+ }
+
+ // Translate param: registrar; type: rawptr_diff
+ CefOwnPtr<CefPreferenceRegistrarCppToC> registrarPtr(
+ CefPreferenceRegistrarCppToC::WrapRaw(registrar));
+
+ // Execute
+ _struct->on_register_custom_preferences(_struct, type,
+ registrarPtr->GetStruct());
+}
+
+NO_SANITIZE("cfi-icall")
+void CefBrowserProcessHandlerCToCpp::OnContextInitialized() {
+ cef_browser_process_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_context_initialized)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->on_context_initialized(_struct);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefBrowserProcessHandlerCToCpp::OnBeforeChildProcessLaunch(
+ CefRefPtr<CefCommandLine> command_line) {
+ cef_browser_process_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_before_child_process_launch)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: command_line; type: refptr_diff
+ DCHECK(command_line.get());
+ if (!command_line.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_before_child_process_launch(
+ _struct, CefCommandLineCppToC::Wrap(command_line));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefBrowserProcessHandlerCToCpp::OnScheduleMessagePumpWork(int64 delay_ms) {
+ cef_browser_process_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_schedule_message_pump_work)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->on_schedule_message_pump_work(_struct, delay_ms);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefClient> CefBrowserProcessHandlerCToCpp::GetDefaultClient() {
+ cef_browser_process_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_default_client)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_client_t* _retval = _struct->get_default_client(_struct);
+
+ // Return type: refptr_same
+ return CefClientCToCpp::Wrap(_retval);
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefBrowserProcessHandlerCToCpp::CefBrowserProcessHandlerCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefBrowserProcessHandlerCToCpp::~CefBrowserProcessHandlerCToCpp() {}
+
+template <>
+cef_browser_process_handler_t* CefCToCppRefCounted<
+ CefBrowserProcessHandlerCToCpp,
+ CefBrowserProcessHandler,
+ cef_browser_process_handler_t>::UnwrapDerived(CefWrapperType type,
+ CefBrowserProcessHandler* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCToCppRefCounted<CefBrowserProcessHandlerCToCpp,
+ CefBrowserProcessHandler,
+ cef_browser_process_handler_t>::kWrapperType =
+ WT_BROWSER_PROCESS_HANDLER;
diff --git a/libcef_dll/ctocpp/browser_process_handler_ctocpp.h b/libcef_dll/ctocpp/browser_process_handler_ctocpp.h
new file mode 100644
index 00000000..9b209521
--- /dev/null
+++ b/libcef_dll/ctocpp/browser_process_handler_ctocpp.h
@@ -0,0 +1,48 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=d86cc781b93a34ab7bc94f35b7c45ab9587aef10$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_BROWSER_PROCESS_HANDLER_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_BROWSER_PROCESS_HANDLER_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_browser_process_handler_capi.h"
+#include "include/cef_browser_process_handler.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefBrowserProcessHandlerCToCpp
+ : public CefCToCppRefCounted<CefBrowserProcessHandlerCToCpp,
+ CefBrowserProcessHandler,
+ cef_browser_process_handler_t> {
+ public:
+ CefBrowserProcessHandlerCToCpp();
+ virtual ~CefBrowserProcessHandlerCToCpp();
+
+ // CefBrowserProcessHandler methods.
+ void OnRegisterCustomPreferences(
+ cef_preferences_type_t type,
+ CefRawPtr<CefPreferenceRegistrar> registrar) override;
+ void OnContextInitialized() override;
+ void OnBeforeChildProcessLaunch(
+ CefRefPtr<CefCommandLine> command_line) override;
+ void OnScheduleMessagePumpWork(int64 delay_ms) override;
+ CefRefPtr<CefClient> GetDefaultClient() override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_BROWSER_PROCESS_HANDLER_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/callback_ctocpp.cc b/libcef_dll/ctocpp/callback_ctocpp.cc
new file mode 100644
index 00000000..06f40544
--- /dev/null
+++ b/libcef_dll/ctocpp/callback_ctocpp.cc
@@ -0,0 +1,69 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=46485b99f5f5805d9420da3af282d1279f80481c$
+//
+
+#include "libcef_dll/ctocpp/callback_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") void CefCallbackCToCpp::Continue() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_callback_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, cont)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->cont(_struct);
+}
+
+NO_SANITIZE("cfi-icall") void CefCallbackCToCpp::Cancel() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_callback_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, cancel)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->cancel(_struct);
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefCallbackCToCpp::CefCallbackCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefCallbackCToCpp::~CefCallbackCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_callback_t*
+CefCToCppRefCounted<CefCallbackCToCpp, CefCallback, cef_callback_t>::
+ UnwrapDerived(CefWrapperType type, CefCallback* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefCallbackCToCpp,
+ CefCallback,
+ cef_callback_t>::kWrapperType = WT_CALLBACK;
diff --git a/libcef_dll/ctocpp/callback_ctocpp.h b/libcef_dll/ctocpp/callback_ctocpp.h
new file mode 100644
index 00000000..1e596514
--- /dev/null
+++ b/libcef_dll/ctocpp/callback_ctocpp.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=33a36c40703e1a794c2d8365f0ed692bad529e4b$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_CALLBACK_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_CALLBACK_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_callback_capi.h"
+#include "include/cef_callback.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefCallbackCToCpp : public CefCToCppRefCounted<CefCallbackCToCpp,
+ CefCallback,
+ cef_callback_t> {
+ public:
+ CefCallbackCToCpp();
+ virtual ~CefCallbackCToCpp();
+
+ // CefCallback methods.
+ void Continue() override;
+ void Cancel() override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_CALLBACK_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/client_ctocpp.cc b/libcef_dll/ctocpp/client_ctocpp.cc
new file mode 100644
index 00000000..84df0330
--- /dev/null
+++ b/libcef_dll/ctocpp/client_ctocpp.cc
@@ -0,0 +1,386 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=b9ac525a8ecae9a1219679e5d08b9a05c03e769a$
+//
+
+#include "libcef_dll/ctocpp/client_ctocpp.h"
+#include "libcef_dll/cpptoc/browser_cpptoc.h"
+#include "libcef_dll/cpptoc/frame_cpptoc.h"
+#include "libcef_dll/cpptoc/process_message_cpptoc.h"
+#include "libcef_dll/ctocpp/audio_handler_ctocpp.h"
+#include "libcef_dll/ctocpp/command_handler_ctocpp.h"
+#include "libcef_dll/ctocpp/context_menu_handler_ctocpp.h"
+#include "libcef_dll/ctocpp/dialog_handler_ctocpp.h"
+#include "libcef_dll/ctocpp/display_handler_ctocpp.h"
+#include "libcef_dll/ctocpp/download_handler_ctocpp.h"
+#include "libcef_dll/ctocpp/drag_handler_ctocpp.h"
+#include "libcef_dll/ctocpp/find_handler_ctocpp.h"
+#include "libcef_dll/ctocpp/focus_handler_ctocpp.h"
+#include "libcef_dll/ctocpp/frame_handler_ctocpp.h"
+#include "libcef_dll/ctocpp/jsdialog_handler_ctocpp.h"
+#include "libcef_dll/ctocpp/keyboard_handler_ctocpp.h"
+#include "libcef_dll/ctocpp/life_span_handler_ctocpp.h"
+#include "libcef_dll/ctocpp/load_handler_ctocpp.h"
+#include "libcef_dll/ctocpp/permission_handler_ctocpp.h"
+#include "libcef_dll/ctocpp/print_handler_ctocpp.h"
+#include "libcef_dll/ctocpp/render_handler_ctocpp.h"
+#include "libcef_dll/ctocpp/request_handler_ctocpp.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefAudioHandler> CefClientCToCpp::GetAudioHandler() {
+ cef_client_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_audio_handler)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_audio_handler_t* _retval = _struct->get_audio_handler(_struct);
+
+ // Return type: refptr_same
+ return CefAudioHandlerCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefCommandHandler> CefClientCToCpp::GetCommandHandler() {
+ cef_client_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_command_handler)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_command_handler_t* _retval = _struct->get_command_handler(_struct);
+
+ // Return type: refptr_same
+ return CefCommandHandlerCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefContextMenuHandler> CefClientCToCpp::GetContextMenuHandler() {
+ cef_client_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_context_menu_handler)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_context_menu_handler_t* _retval =
+ _struct->get_context_menu_handler(_struct);
+
+ // Return type: refptr_same
+ return CefContextMenuHandlerCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefDialogHandler> CefClientCToCpp::GetDialogHandler() {
+ cef_client_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_dialog_handler)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_dialog_handler_t* _retval = _struct->get_dialog_handler(_struct);
+
+ // Return type: refptr_same
+ return CefDialogHandlerCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefDisplayHandler> CefClientCToCpp::GetDisplayHandler() {
+ cef_client_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_display_handler)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_display_handler_t* _retval = _struct->get_display_handler(_struct);
+
+ // Return type: refptr_same
+ return CefDisplayHandlerCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefDownloadHandler> CefClientCToCpp::GetDownloadHandler() {
+ cef_client_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_download_handler)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_download_handler_t* _retval = _struct->get_download_handler(_struct);
+
+ // Return type: refptr_same
+ return CefDownloadHandlerCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefDragHandler> CefClientCToCpp::GetDragHandler() {
+ cef_client_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_drag_handler)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_drag_handler_t* _retval = _struct->get_drag_handler(_struct);
+
+ // Return type: refptr_same
+ return CefDragHandlerCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefFindHandler> CefClientCToCpp::GetFindHandler() {
+ cef_client_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_find_handler)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_find_handler_t* _retval = _struct->get_find_handler(_struct);
+
+ // Return type: refptr_same
+ return CefFindHandlerCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefFocusHandler> CefClientCToCpp::GetFocusHandler() {
+ cef_client_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_focus_handler)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_focus_handler_t* _retval = _struct->get_focus_handler(_struct);
+
+ // Return type: refptr_same
+ return CefFocusHandlerCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefFrameHandler> CefClientCToCpp::GetFrameHandler() {
+ cef_client_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_frame_handler)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_frame_handler_t* _retval = _struct->get_frame_handler(_struct);
+
+ // Return type: refptr_same
+ return CefFrameHandlerCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefPermissionHandler> CefClientCToCpp::GetPermissionHandler() {
+ cef_client_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_permission_handler)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_permission_handler_t* _retval = _struct->get_permission_handler(_struct);
+
+ // Return type: refptr_same
+ return CefPermissionHandlerCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefJSDialogHandler> CefClientCToCpp::GetJSDialogHandler() {
+ cef_client_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_jsdialog_handler)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_jsdialog_handler_t* _retval = _struct->get_jsdialog_handler(_struct);
+
+ // Return type: refptr_same
+ return CefJSDialogHandlerCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefKeyboardHandler> CefClientCToCpp::GetKeyboardHandler() {
+ cef_client_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_keyboard_handler)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_keyboard_handler_t* _retval = _struct->get_keyboard_handler(_struct);
+
+ // Return type: refptr_same
+ return CefKeyboardHandlerCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefLifeSpanHandler> CefClientCToCpp::GetLifeSpanHandler() {
+ cef_client_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_life_span_handler)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_life_span_handler_t* _retval = _struct->get_life_span_handler(_struct);
+
+ // Return type: refptr_same
+ return CefLifeSpanHandlerCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefLoadHandler> CefClientCToCpp::GetLoadHandler() {
+ cef_client_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_load_handler)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_load_handler_t* _retval = _struct->get_load_handler(_struct);
+
+ // Return type: refptr_same
+ return CefLoadHandlerCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefPrintHandler> CefClientCToCpp::GetPrintHandler() {
+ cef_client_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_print_handler)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_print_handler_t* _retval = _struct->get_print_handler(_struct);
+
+ // Return type: refptr_same
+ return CefPrintHandlerCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefRenderHandler> CefClientCToCpp::GetRenderHandler() {
+ cef_client_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_render_handler)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_render_handler_t* _retval = _struct->get_render_handler(_struct);
+
+ // Return type: refptr_same
+ return CefRenderHandlerCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefRequestHandler> CefClientCToCpp::GetRequestHandler() {
+ cef_client_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_request_handler)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_request_handler_t* _retval = _struct->get_request_handler(_struct);
+
+ // Return type: refptr_same
+ return CefRequestHandlerCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefClientCToCpp::OnProcessMessageReceived(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefProcessId source_process,
+ CefRefPtr<CefProcessMessage> message) {
+ cef_client_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_process_message_received)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return false;
+ }
+ // Verify param: frame; type: refptr_diff
+ DCHECK(frame.get());
+ if (!frame.get()) {
+ return false;
+ }
+ // Verify param: message; type: refptr_diff
+ DCHECK(message.get());
+ if (!message.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->on_process_message_received(
+ _struct, CefBrowserCppToC::Wrap(browser), CefFrameCppToC::Wrap(frame),
+ source_process, CefProcessMessageCppToC::Wrap(message));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefClientCToCpp::CefClientCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefClientCToCpp::~CefClientCToCpp() {}
+
+template <>
+cef_client_t*
+CefCToCppRefCounted<CefClientCToCpp, CefClient, cef_client_t>::UnwrapDerived(
+ CefWrapperType type,
+ CefClient* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefClientCToCpp, CefClient, cef_client_t>::
+ kWrapperType = WT_CLIENT;
diff --git a/libcef_dll/ctocpp/client_ctocpp.h b/libcef_dll/ctocpp/client_ctocpp.h
new file mode 100644
index 00000000..f38dae9d
--- /dev/null
+++ b/libcef_dll/ctocpp/client_ctocpp.h
@@ -0,0 +1,60 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=28e1869fba61dd480e1194722393eb2b83ccba5e$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_CLIENT_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_CLIENT_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_client_capi.h"
+#include "include/cef_client.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefClientCToCpp
+ : public CefCToCppRefCounted<CefClientCToCpp, CefClient, cef_client_t> {
+ public:
+ CefClientCToCpp();
+ virtual ~CefClientCToCpp();
+
+ // CefClient methods.
+ CefRefPtr<CefAudioHandler> GetAudioHandler() override;
+ CefRefPtr<CefCommandHandler> GetCommandHandler() override;
+ CefRefPtr<CefContextMenuHandler> GetContextMenuHandler() override;
+ CefRefPtr<CefDialogHandler> GetDialogHandler() override;
+ CefRefPtr<CefDisplayHandler> GetDisplayHandler() override;
+ CefRefPtr<CefDownloadHandler> GetDownloadHandler() override;
+ CefRefPtr<CefDragHandler> GetDragHandler() override;
+ CefRefPtr<CefFindHandler> GetFindHandler() override;
+ CefRefPtr<CefFocusHandler> GetFocusHandler() override;
+ CefRefPtr<CefFrameHandler> GetFrameHandler() override;
+ CefRefPtr<CefPermissionHandler> GetPermissionHandler() override;
+ CefRefPtr<CefJSDialogHandler> GetJSDialogHandler() override;
+ CefRefPtr<CefKeyboardHandler> GetKeyboardHandler() override;
+ CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() override;
+ CefRefPtr<CefLoadHandler> GetLoadHandler() override;
+ CefRefPtr<CefPrintHandler> GetPrintHandler() override;
+ CefRefPtr<CefRenderHandler> GetRenderHandler() override;
+ CefRefPtr<CefRequestHandler> GetRequestHandler() override;
+ bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefProcessId source_process,
+ CefRefPtr<CefProcessMessage> message) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_CLIENT_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/command_handler_ctocpp.cc b/libcef_dll/ctocpp/command_handler_ctocpp.cc
new file mode 100644
index 00000000..bed629b2
--- /dev/null
+++ b/libcef_dll/ctocpp/command_handler_ctocpp.cc
@@ -0,0 +1,73 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=af3697f4c41762086c8edff7f63a794e8bf95b25$
+//
+
+#include "libcef_dll/ctocpp/command_handler_ctocpp.h"
+#include "libcef_dll/cpptoc/browser_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+bool CefCommandHandlerCToCpp::OnChromeCommand(
+ CefRefPtr<CefBrowser> browser,
+ int command_id,
+ cef_window_open_disposition_t disposition) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_command_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_chrome_command)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->on_chrome_command(
+ _struct, CefBrowserCppToC::Wrap(browser), command_id, disposition);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefCommandHandlerCToCpp::CefCommandHandlerCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefCommandHandlerCToCpp::~CefCommandHandlerCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_command_handler_t* CefCToCppRefCounted<
+ CefCommandHandlerCToCpp,
+ CefCommandHandler,
+ cef_command_handler_t>::UnwrapDerived(CefWrapperType type,
+ CefCommandHandler* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefCommandHandlerCToCpp,
+ CefCommandHandler,
+ cef_command_handler_t>::kWrapperType =
+ WT_COMMAND_HANDLER;
diff --git a/libcef_dll/ctocpp/command_handler_ctocpp.h b/libcef_dll/ctocpp/command_handler_ctocpp.h
new file mode 100644
index 00000000..986a92d2
--- /dev/null
+++ b/libcef_dll/ctocpp/command_handler_ctocpp.h
@@ -0,0 +1,43 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=1def18706fb8efd9d28a718b505905d366a0d057$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_COMMAND_HANDLER_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_COMMAND_HANDLER_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_command_handler_capi.h"
+#include "include/cef_command_handler.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefCommandHandlerCToCpp
+ : public CefCToCppRefCounted<CefCommandHandlerCToCpp,
+ CefCommandHandler,
+ cef_command_handler_t> {
+ public:
+ CefCommandHandlerCToCpp();
+ virtual ~CefCommandHandlerCToCpp();
+
+ // CefCommandHandler methods.
+ bool OnChromeCommand(CefRefPtr<CefBrowser> browser,
+ int command_id,
+ cef_window_open_disposition_t disposition) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_COMMAND_HANDLER_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/command_line_ctocpp.cc b/libcef_dll/ctocpp/command_line_ctocpp.cc
new file mode 100644
index 00000000..237c4f05
--- /dev/null
+++ b/libcef_dll/ctocpp/command_line_ctocpp.cc
@@ -0,0 +1,470 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=e641e3609e9b096e6be7edc589314d4d3e909ad1$
+//
+
+#include "libcef_dll/ctocpp/command_line_ctocpp.h"
+#include "include/cef_api_hash.h"
+#include "libcef_dll/transfer_util.h"
+
+// STATIC METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefCommandLine> CefCommandLine::CreateCommandLine() {
+ const char* api_hash = cef_api_hash(0);
+ if (strcmp(api_hash, CEF_API_HASH_PLATFORM)) {
+ // The libcef API hash does not match the current header API hash.
+ NOTREACHED();
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_command_line_t* _retval = cef_command_line_create();
+
+ // Return type: refptr_same
+ return CefCommandLineCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefCommandLine> CefCommandLine::GetGlobalCommandLine() {
+ const char* api_hash = cef_api_hash(0);
+ if (strcmp(api_hash, CEF_API_HASH_PLATFORM)) {
+ // The libcef API hash does not match the current header API hash.
+ NOTREACHED();
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_command_line_t* _retval = cef_command_line_get_global();
+
+ // Return type: refptr_same
+ return CefCommandLineCToCpp::Wrap(_retval);
+}
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") bool CefCommandLineCToCpp::IsValid() {
+ cef_command_line_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_valid)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_valid(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefCommandLineCToCpp::IsReadOnly() {
+ cef_command_line_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_read_only)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_read_only(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefCommandLine> CefCommandLineCToCpp::Copy() {
+ cef_command_line_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, copy)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_command_line_t* _retval = _struct->copy(_struct);
+
+ // Return type: refptr_same
+ return CefCommandLineCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefCommandLineCToCpp::InitFromArgv(int argc, const char* const* argv) {
+ cef_command_line_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, init_from_argv)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: argv; type: simple_byaddr
+ DCHECK(argv);
+ if (!argv) {
+ return;
+ }
+
+ // Execute
+ _struct->init_from_argv(_struct, argc, argv);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefCommandLineCToCpp::InitFromString(const CefString& command_line) {
+ cef_command_line_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, init_from_string)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: command_line; type: string_byref_const
+ DCHECK(!command_line.empty());
+ if (command_line.empty()) {
+ return;
+ }
+
+ // Execute
+ _struct->init_from_string(_struct, command_line.GetStruct());
+}
+
+NO_SANITIZE("cfi-icall") void CefCommandLineCToCpp::Reset() {
+ cef_command_line_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, reset)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->reset(_struct);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefCommandLineCToCpp::GetArgv(std::vector<CefString>& argv) {
+ cef_command_line_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_argv)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Translate param: argv; type: string_vec_byref
+ cef_string_list_t argvList = cef_string_list_alloc();
+ DCHECK(argvList);
+ if (argvList) {
+ transfer_string_list_contents(argv, argvList);
+ }
+
+ // Execute
+ _struct->get_argv(_struct, argvList);
+
+ // Restore param:argv; type: string_vec_byref
+ if (argvList) {
+ argv.clear();
+ transfer_string_list_contents(argvList, argv);
+ cef_string_list_free(argvList);
+ }
+}
+
+NO_SANITIZE("cfi-icall")
+CefString CefCommandLineCToCpp::GetCommandLineString() {
+ cef_command_line_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_command_line_string)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_command_line_string(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") CefString CefCommandLineCToCpp::GetProgram() {
+ cef_command_line_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_program)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_program(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefCommandLineCToCpp::SetProgram(const CefString& program) {
+ cef_command_line_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_program)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: program; type: string_byref_const
+ DCHECK(!program.empty());
+ if (program.empty()) {
+ return;
+ }
+
+ // Execute
+ _struct->set_program(_struct, program.GetStruct());
+}
+
+NO_SANITIZE("cfi-icall") bool CefCommandLineCToCpp::HasSwitches() {
+ cef_command_line_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, has_switches)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->has_switches(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefCommandLineCToCpp::HasSwitch(const CefString& name) {
+ cef_command_line_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, has_switch)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: name; type: string_byref_const
+ DCHECK(!name.empty());
+ if (name.empty()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->has_switch(_struct, name.GetStruct());
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CefString CefCommandLineCToCpp::GetSwitchValue(const CefString& name) {
+ cef_command_line_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_switch_value)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: name; type: string_byref_const
+ DCHECK(!name.empty());
+ if (name.empty()) {
+ return CefString();
+ }
+
+ // Execute
+ cef_string_userfree_t _retval =
+ _struct->get_switch_value(_struct, name.GetStruct());
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefCommandLineCToCpp::GetSwitches(SwitchMap& switches) {
+ cef_command_line_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_switches)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Translate param: switches; type: string_map_single_byref
+ cef_string_map_t switchesMap = cef_string_map_alloc();
+ DCHECK(switchesMap);
+ if (switchesMap) {
+ transfer_string_map_contents(switches, switchesMap);
+ }
+
+ // Execute
+ _struct->get_switches(_struct, switchesMap);
+
+ // Restore param:switches; type: string_map_single_byref
+ if (switchesMap) {
+ switches.clear();
+ transfer_string_map_contents(switchesMap, switches);
+ cef_string_map_free(switchesMap);
+ }
+}
+
+NO_SANITIZE("cfi-icall")
+void CefCommandLineCToCpp::AppendSwitch(const CefString& name) {
+ cef_command_line_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, append_switch)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: name; type: string_byref_const
+ DCHECK(!name.empty());
+ if (name.empty()) {
+ return;
+ }
+
+ // Execute
+ _struct->append_switch(_struct, name.GetStruct());
+}
+
+NO_SANITIZE("cfi-icall")
+void CefCommandLineCToCpp::AppendSwitchWithValue(const CefString& name,
+ const CefString& value) {
+ cef_command_line_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, append_switch_with_value)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: name; type: string_byref_const
+ DCHECK(!name.empty());
+ if (name.empty()) {
+ return;
+ }
+ // Verify param: value; type: string_byref_const
+ DCHECK(!value.empty());
+ if (value.empty()) {
+ return;
+ }
+
+ // Execute
+ _struct->append_switch_with_value(_struct, name.GetStruct(),
+ value.GetStruct());
+}
+
+NO_SANITIZE("cfi-icall") bool CefCommandLineCToCpp::HasArguments() {
+ cef_command_line_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, has_arguments)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->has_arguments(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefCommandLineCToCpp::GetArguments(ArgumentList& arguments) {
+ cef_command_line_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_arguments)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Translate param: arguments; type: string_vec_byref
+ cef_string_list_t argumentsList = cef_string_list_alloc();
+ DCHECK(argumentsList);
+ if (argumentsList) {
+ transfer_string_list_contents(arguments, argumentsList);
+ }
+
+ // Execute
+ _struct->get_arguments(_struct, argumentsList);
+
+ // Restore param:arguments; type: string_vec_byref
+ if (argumentsList) {
+ arguments.clear();
+ transfer_string_list_contents(argumentsList, arguments);
+ cef_string_list_free(argumentsList);
+ }
+}
+
+NO_SANITIZE("cfi-icall")
+void CefCommandLineCToCpp::AppendArgument(const CefString& argument) {
+ cef_command_line_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, append_argument)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: argument; type: string_byref_const
+ DCHECK(!argument.empty());
+ if (argument.empty()) {
+ return;
+ }
+
+ // Execute
+ _struct->append_argument(_struct, argument.GetStruct());
+}
+
+NO_SANITIZE("cfi-icall")
+void CefCommandLineCToCpp::PrependWrapper(const CefString& wrapper) {
+ cef_command_line_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, prepend_wrapper)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: wrapper; type: string_byref_const
+ DCHECK(!wrapper.empty());
+ if (wrapper.empty()) {
+ return;
+ }
+
+ // Execute
+ _struct->prepend_wrapper(_struct, wrapper.GetStruct());
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefCommandLineCToCpp::CefCommandLineCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefCommandLineCToCpp::~CefCommandLineCToCpp() {}
+
+template <>
+cef_command_line_t*
+CefCToCppRefCounted<CefCommandLineCToCpp, CefCommandLine, cef_command_line_t>::
+ UnwrapDerived(CefWrapperType type, CefCommandLine* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefCommandLineCToCpp,
+ CefCommandLine,
+ cef_command_line_t>::kWrapperType =
+ WT_COMMAND_LINE;
diff --git a/libcef_dll/ctocpp/command_line_ctocpp.h b/libcef_dll/ctocpp/command_line_ctocpp.h
new file mode 100644
index 00000000..7beaa99e
--- /dev/null
+++ b/libcef_dll/ctocpp/command_line_ctocpp.h
@@ -0,0 +1,61 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=c91f76be5a60016fa78afe2813b0d4df3bb422e7$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_COMMAND_LINE_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_COMMAND_LINE_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include <vector>
+#include "include/capi/cef_command_line_capi.h"
+#include "include/cef_command_line.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefCommandLineCToCpp : public CefCToCppRefCounted<CefCommandLineCToCpp,
+ CefCommandLine,
+ cef_command_line_t> {
+ public:
+ CefCommandLineCToCpp();
+ virtual ~CefCommandLineCToCpp();
+
+ // CefCommandLine methods.
+ bool IsValid() override;
+ bool IsReadOnly() override;
+ CefRefPtr<CefCommandLine> Copy() override;
+ void InitFromArgv(int argc, const char* const* argv) override;
+ void InitFromString(const CefString& command_line) override;
+ void Reset() override;
+ void GetArgv(std::vector<CefString>& argv) override;
+ CefString GetCommandLineString() override;
+ CefString GetProgram() override;
+ void SetProgram(const CefString& program) override;
+ bool HasSwitches() override;
+ bool HasSwitch(const CefString& name) override;
+ CefString GetSwitchValue(const CefString& name) override;
+ void GetSwitches(SwitchMap& switches) override;
+ void AppendSwitch(const CefString& name) override;
+ void AppendSwitchWithValue(const CefString& name,
+ const CefString& value) override;
+ bool HasArguments() override;
+ void GetArguments(ArgumentList& arguments) override;
+ void AppendArgument(const CefString& argument) override;
+ void PrependWrapper(const CefString& wrapper) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_COMMAND_LINE_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/completion_callback_ctocpp.cc b/libcef_dll/ctocpp/completion_callback_ctocpp.cc
new file mode 100644
index 00000000..4c161d1c
--- /dev/null
+++ b/libcef_dll/ctocpp/completion_callback_ctocpp.cc
@@ -0,0 +1,58 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=1e131bf890b71867e7bad0359099dcca3455726b$
+//
+
+#include "libcef_dll/ctocpp/completion_callback_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") void CefCompletionCallbackCToCpp::OnComplete() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_completion_callback_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_complete)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->on_complete(_struct);
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefCompletionCallbackCToCpp::CefCompletionCallbackCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefCompletionCallbackCToCpp::~CefCompletionCallbackCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_completion_callback_t* CefCToCppRefCounted<
+ CefCompletionCallbackCToCpp,
+ CefCompletionCallback,
+ cef_completion_callback_t>::UnwrapDerived(CefWrapperType type,
+ CefCompletionCallback* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefCompletionCallbackCToCpp,
+ CefCompletionCallback,
+ cef_completion_callback_t>::kWrapperType =
+ WT_COMPLETION_CALLBACK;
diff --git a/libcef_dll/ctocpp/completion_callback_ctocpp.h b/libcef_dll/ctocpp/completion_callback_ctocpp.h
new file mode 100644
index 00000000..37956aad
--- /dev/null
+++ b/libcef_dll/ctocpp/completion_callback_ctocpp.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=bbdf6c23d87122deb5d3100430547b2c608497a9$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_COMPLETION_CALLBACK_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_COMPLETION_CALLBACK_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_callback_capi.h"
+#include "include/cef_callback.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefCompletionCallbackCToCpp
+ : public CefCToCppRefCounted<CefCompletionCallbackCToCpp,
+ CefCompletionCallback,
+ cef_completion_callback_t> {
+ public:
+ CefCompletionCallbackCToCpp();
+ virtual ~CefCompletionCallbackCToCpp();
+
+ // CefCompletionCallback methods.
+ void OnComplete() override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_COMPLETION_CALLBACK_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/context_menu_handler_ctocpp.cc b/libcef_dll/ctocpp/context_menu_handler_ctocpp.cc
new file mode 100644
index 00000000..5636fb05
--- /dev/null
+++ b/libcef_dll/ctocpp/context_menu_handler_ctocpp.cc
@@ -0,0 +1,322 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=67b8663a4c699cbffeba193c1b581bce765d6d50$
+//
+
+#include "libcef_dll/ctocpp/context_menu_handler_ctocpp.h"
+#include "libcef_dll/cpptoc/browser_cpptoc.h"
+#include "libcef_dll/cpptoc/context_menu_params_cpptoc.h"
+#include "libcef_dll/cpptoc/frame_cpptoc.h"
+#include "libcef_dll/cpptoc/menu_model_cpptoc.h"
+#include "libcef_dll/cpptoc/run_context_menu_callback_cpptoc.h"
+#include "libcef_dll/cpptoc/run_quick_menu_callback_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+void CefContextMenuHandlerCToCpp::OnBeforeContextMenu(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefContextMenuParams> params,
+ CefRefPtr<CefMenuModel> model) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_context_menu_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_before_context_menu)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+ // Verify param: frame; type: refptr_diff
+ DCHECK(frame.get());
+ if (!frame.get()) {
+ return;
+ }
+ // Verify param: params; type: refptr_diff
+ DCHECK(params.get());
+ if (!params.get()) {
+ return;
+ }
+ // Verify param: model; type: refptr_diff
+ DCHECK(model.get());
+ if (!model.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_before_context_menu(_struct, CefBrowserCppToC::Wrap(browser),
+ CefFrameCppToC::Wrap(frame),
+ CefContextMenuParamsCppToC::Wrap(params),
+ CefMenuModelCppToC::Wrap(model));
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefContextMenuHandlerCToCpp::RunContextMenu(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefContextMenuParams> params,
+ CefRefPtr<CefMenuModel> model,
+ CefRefPtr<CefRunContextMenuCallback> callback) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_context_menu_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, run_context_menu)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return false;
+ }
+ // Verify param: frame; type: refptr_diff
+ DCHECK(frame.get());
+ if (!frame.get()) {
+ return false;
+ }
+ // Verify param: params; type: refptr_diff
+ DCHECK(params.get());
+ if (!params.get()) {
+ return false;
+ }
+ // Verify param: model; type: refptr_diff
+ DCHECK(model.get());
+ if (!model.get()) {
+ return false;
+ }
+ // Verify param: callback; type: refptr_diff
+ DCHECK(callback.get());
+ if (!callback.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->run_context_menu(
+ _struct, CefBrowserCppToC::Wrap(browser), CefFrameCppToC::Wrap(frame),
+ CefContextMenuParamsCppToC::Wrap(params), CefMenuModelCppToC::Wrap(model),
+ CefRunContextMenuCallbackCppToC::Wrap(callback));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefContextMenuHandlerCToCpp::OnContextMenuCommand(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefContextMenuParams> params,
+ int command_id,
+ EventFlags event_flags) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_context_menu_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_context_menu_command)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return false;
+ }
+ // Verify param: frame; type: refptr_diff
+ DCHECK(frame.get());
+ if (!frame.get()) {
+ return false;
+ }
+ // Verify param: params; type: refptr_diff
+ DCHECK(params.get());
+ if (!params.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->on_context_menu_command(
+ _struct, CefBrowserCppToC::Wrap(browser), CefFrameCppToC::Wrap(frame),
+ CefContextMenuParamsCppToC::Wrap(params), command_id, event_flags);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefContextMenuHandlerCToCpp::OnContextMenuDismissed(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_context_menu_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_context_menu_dismissed)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+ // Verify param: frame; type: refptr_diff
+ DCHECK(frame.get());
+ if (!frame.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_context_menu_dismissed(_struct, CefBrowserCppToC::Wrap(browser),
+ CefFrameCppToC::Wrap(frame));
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefContextMenuHandlerCToCpp::RunQuickMenu(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const CefPoint& location,
+ const CefSize& size,
+ QuickMenuEditStateFlags edit_state_flags,
+ CefRefPtr<CefRunQuickMenuCallback> callback) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_context_menu_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, run_quick_menu)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return false;
+ }
+ // Verify param: frame; type: refptr_diff
+ DCHECK(frame.get());
+ if (!frame.get()) {
+ return false;
+ }
+ // Verify param: callback; type: refptr_diff
+ DCHECK(callback.get());
+ if (!callback.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->run_quick_menu(
+ _struct, CefBrowserCppToC::Wrap(browser), CefFrameCppToC::Wrap(frame),
+ &location, &size, edit_state_flags,
+ CefRunQuickMenuCallbackCppToC::Wrap(callback));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefContextMenuHandlerCToCpp::OnQuickMenuCommand(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int command_id,
+ EventFlags event_flags) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_context_menu_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_quick_menu_command)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return false;
+ }
+ // Verify param: frame; type: refptr_diff
+ DCHECK(frame.get());
+ if (!frame.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->on_quick_menu_command(
+ _struct, CefBrowserCppToC::Wrap(browser), CefFrameCppToC::Wrap(frame),
+ command_id, event_flags);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefContextMenuHandlerCToCpp::OnQuickMenuDismissed(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_context_menu_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_quick_menu_dismissed)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+ // Verify param: frame; type: refptr_diff
+ DCHECK(frame.get());
+ if (!frame.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_quick_menu_dismissed(_struct, CefBrowserCppToC::Wrap(browser),
+ CefFrameCppToC::Wrap(frame));
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefContextMenuHandlerCToCpp::CefContextMenuHandlerCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefContextMenuHandlerCToCpp::~CefContextMenuHandlerCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_context_menu_handler_t* CefCToCppRefCounted<
+ CefContextMenuHandlerCToCpp,
+ CefContextMenuHandler,
+ cef_context_menu_handler_t>::UnwrapDerived(CefWrapperType type,
+ CefContextMenuHandler* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefContextMenuHandlerCToCpp,
+ CefContextMenuHandler,
+ cef_context_menu_handler_t>::kWrapperType =
+ WT_CONTEXT_MENU_HANDLER;
diff --git a/libcef_dll/ctocpp/context_menu_handler_ctocpp.h b/libcef_dll/ctocpp/context_menu_handler_ctocpp.h
new file mode 100644
index 00000000..852d36c9
--- /dev/null
+++ b/libcef_dll/ctocpp/context_menu_handler_ctocpp.h
@@ -0,0 +1,68 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=200acf8c2308059416e4f920d66bb98c6f234ffe$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_CONTEXT_MENU_HANDLER_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_CONTEXT_MENU_HANDLER_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_context_menu_handler_capi.h"
+#include "include/cef_context_menu_handler.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefContextMenuHandlerCToCpp
+ : public CefCToCppRefCounted<CefContextMenuHandlerCToCpp,
+ CefContextMenuHandler,
+ cef_context_menu_handler_t> {
+ public:
+ CefContextMenuHandlerCToCpp();
+ virtual ~CefContextMenuHandlerCToCpp();
+
+ // CefContextMenuHandler methods.
+ void OnBeforeContextMenu(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefContextMenuParams> params,
+ CefRefPtr<CefMenuModel> model) override;
+ bool RunContextMenu(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefContextMenuParams> params,
+ CefRefPtr<CefMenuModel> model,
+ CefRefPtr<CefRunContextMenuCallback> callback) override;
+ bool OnContextMenuCommand(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefContextMenuParams> params,
+ int command_id,
+ EventFlags event_flags) override;
+ void OnContextMenuDismissed(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) override;
+ bool RunQuickMenu(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const CefPoint& location,
+ const CefSize& size,
+ QuickMenuEditStateFlags edit_state_flags,
+ CefRefPtr<CefRunQuickMenuCallback> callback) override;
+ bool OnQuickMenuCommand(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int command_id,
+ EventFlags event_flags) override;
+ void OnQuickMenuDismissed(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_CONTEXT_MENU_HANDLER_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/context_menu_params_ctocpp.cc b/libcef_dll/ctocpp/context_menu_params_ctocpp.cc
new file mode 100644
index 00000000..92cc190f
--- /dev/null
+++ b/libcef_dll/ctocpp/context_menu_params_ctocpp.cc
@@ -0,0 +1,432 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=0653ced3fab7b668ced0862cdd5819c585706a1d$
+//
+
+#include "libcef_dll/ctocpp/context_menu_params_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+#include "libcef_dll/transfer_util.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") int CefContextMenuParamsCToCpp::GetXCoord() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_context_menu_params_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_xcoord)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_xcoord(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") int CefContextMenuParamsCToCpp::GetYCoord() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_context_menu_params_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_ycoord)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_ycoord(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CefContextMenuParams::TypeFlags CefContextMenuParamsCToCpp::GetTypeFlags() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_context_menu_params_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_type_flags)) {
+ return CM_TYPEFLAG_NONE;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_context_menu_type_flags_t _retval = _struct->get_type_flags(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") CefString CefContextMenuParamsCToCpp::GetLinkUrl() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_context_menu_params_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_link_url)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_link_url(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+CefString CefContextMenuParamsCToCpp::GetUnfilteredLinkUrl() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_context_menu_params_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_unfiltered_link_url)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_unfiltered_link_url(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") CefString CefContextMenuParamsCToCpp::GetSourceUrl() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_context_menu_params_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_source_url)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_source_url(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") bool CefContextMenuParamsCToCpp::HasImageContents() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_context_menu_params_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, has_image_contents)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->has_image_contents(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") CefString CefContextMenuParamsCToCpp::GetTitleText() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_context_menu_params_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_title_text)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_title_text(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") CefString CefContextMenuParamsCToCpp::GetPageUrl() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_context_menu_params_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_page_url)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_page_url(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") CefString CefContextMenuParamsCToCpp::GetFrameUrl() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_context_menu_params_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_frame_url)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_frame_url(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+CefString CefContextMenuParamsCToCpp::GetFrameCharset() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_context_menu_params_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_frame_charset)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_frame_charset(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+CefContextMenuParams::MediaType CefContextMenuParamsCToCpp::GetMediaType() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_context_menu_params_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_media_type)) {
+ return CM_MEDIATYPE_NONE;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_context_menu_media_type_t _retval = _struct->get_media_type(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CefContextMenuParams::MediaStateFlags
+CefContextMenuParamsCToCpp::GetMediaStateFlags() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_context_menu_params_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_media_state_flags)) {
+ return CM_MEDIAFLAG_NONE;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_context_menu_media_state_flags_t _retval =
+ _struct->get_media_state_flags(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CefString CefContextMenuParamsCToCpp::GetSelectionText() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_context_menu_params_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_selection_text)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_selection_text(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+CefString CefContextMenuParamsCToCpp::GetMisspelledWord() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_context_menu_params_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_misspelled_word)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_misspelled_word(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefContextMenuParamsCToCpp::GetDictionarySuggestions(
+ std::vector<CefString>& suggestions) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_context_menu_params_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_dictionary_suggestions)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Translate param: suggestions; type: string_vec_byref
+ cef_string_list_t suggestionsList = cef_string_list_alloc();
+ DCHECK(suggestionsList);
+ if (suggestionsList) {
+ transfer_string_list_contents(suggestions, suggestionsList);
+ }
+
+ // Execute
+ int _retval = _struct->get_dictionary_suggestions(_struct, suggestionsList);
+
+ // Restore param:suggestions; type: string_vec_byref
+ if (suggestionsList) {
+ suggestions.clear();
+ transfer_string_list_contents(suggestionsList, suggestions);
+ cef_string_list_free(suggestionsList);
+ }
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefContextMenuParamsCToCpp::IsEditable() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_context_menu_params_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_editable)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_editable(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefContextMenuParamsCToCpp::IsSpellCheckEnabled() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_context_menu_params_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_spell_check_enabled)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_spell_check_enabled(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CefContextMenuParams::EditStateFlags
+CefContextMenuParamsCToCpp::GetEditStateFlags() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_context_menu_params_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_edit_state_flags)) {
+ return CM_EDITFLAG_NONE;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_context_menu_edit_state_flags_t _retval =
+ _struct->get_edit_state_flags(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") bool CefContextMenuParamsCToCpp::IsCustomMenu() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_context_menu_params_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_custom_menu)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_custom_menu(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefContextMenuParamsCToCpp::CefContextMenuParamsCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefContextMenuParamsCToCpp::~CefContextMenuParamsCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_context_menu_params_t* CefCToCppRefCounted<
+ CefContextMenuParamsCToCpp,
+ CefContextMenuParams,
+ cef_context_menu_params_t>::UnwrapDerived(CefWrapperType type,
+ CefContextMenuParams* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefContextMenuParamsCToCpp,
+ CefContextMenuParams,
+ cef_context_menu_params_t>::kWrapperType =
+ WT_CONTEXT_MENU_PARAMS;
diff --git a/libcef_dll/ctocpp/context_menu_params_ctocpp.h b/libcef_dll/ctocpp/context_menu_params_ctocpp.h
new file mode 100644
index 00000000..e800861e
--- /dev/null
+++ b/libcef_dll/ctocpp/context_menu_params_ctocpp.h
@@ -0,0 +1,61 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=d4a3ee70f42b74bd849215f0f569d07164bf29a7$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_CONTEXT_MENU_PARAMS_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_CONTEXT_MENU_PARAMS_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include <vector>
+#include "include/capi/cef_context_menu_handler_capi.h"
+#include "include/cef_context_menu_handler.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefContextMenuParamsCToCpp
+ : public CefCToCppRefCounted<CefContextMenuParamsCToCpp,
+ CefContextMenuParams,
+ cef_context_menu_params_t> {
+ public:
+ CefContextMenuParamsCToCpp();
+ virtual ~CefContextMenuParamsCToCpp();
+
+ // CefContextMenuParams methods.
+ int GetXCoord() override;
+ int GetYCoord() override;
+ TypeFlags GetTypeFlags() override;
+ CefString GetLinkUrl() override;
+ CefString GetUnfilteredLinkUrl() override;
+ CefString GetSourceUrl() override;
+ bool HasImageContents() override;
+ CefString GetTitleText() override;
+ CefString GetPageUrl() override;
+ CefString GetFrameUrl() override;
+ CefString GetFrameCharset() override;
+ MediaType GetMediaType() override;
+ MediaStateFlags GetMediaStateFlags() override;
+ CefString GetSelectionText() override;
+ CefString GetMisspelledWord() override;
+ bool GetDictionarySuggestions(std::vector<CefString>& suggestions) override;
+ bool IsEditable() override;
+ bool IsSpellCheckEnabled() override;
+ EditStateFlags GetEditStateFlags() override;
+ bool IsCustomMenu() override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_CONTEXT_MENU_PARAMS_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/cookie_access_filter_ctocpp.cc b/libcef_dll/ctocpp/cookie_access_filter_ctocpp.cc
new file mode 100644
index 00000000..c74ee521
--- /dev/null
+++ b/libcef_dll/ctocpp/cookie_access_filter_ctocpp.cc
@@ -0,0 +1,108 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=f3dd306439e0d02bf7f68c7e93a1c746b2d25cb8$
+//
+
+#include "libcef_dll/ctocpp/cookie_access_filter_ctocpp.h"
+#include "libcef_dll/cpptoc/browser_cpptoc.h"
+#include "libcef_dll/cpptoc/frame_cpptoc.h"
+#include "libcef_dll/cpptoc/request_cpptoc.h"
+#include "libcef_dll/cpptoc/response_cpptoc.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+bool CefCookieAccessFilterCToCpp::CanSendCookie(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ const CefCookie& cookie) {
+ cef_cookie_access_filter_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, can_send_cookie)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: request; type: refptr_diff
+ DCHECK(request.get());
+ if (!request.get()) {
+ return false;
+ }
+ // Unverified params: browser, frame
+
+ // Execute
+ int _retval = _struct->can_send_cookie(
+ _struct, CefBrowserCppToC::Wrap(browser), CefFrameCppToC::Wrap(frame),
+ CefRequestCppToC::Wrap(request), &cookie);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefCookieAccessFilterCToCpp::CanSaveCookie(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response,
+ const CefCookie& cookie) {
+ cef_cookie_access_filter_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, can_save_cookie)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: request; type: refptr_diff
+ DCHECK(request.get());
+ if (!request.get()) {
+ return false;
+ }
+ // Verify param: response; type: refptr_diff
+ DCHECK(response.get());
+ if (!response.get()) {
+ return false;
+ }
+ // Unverified params: browser, frame
+
+ // Execute
+ int _retval = _struct->can_save_cookie(
+ _struct, CefBrowserCppToC::Wrap(browser), CefFrameCppToC::Wrap(frame),
+ CefRequestCppToC::Wrap(request), CefResponseCppToC::Wrap(response),
+ &cookie);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefCookieAccessFilterCToCpp::CefCookieAccessFilterCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefCookieAccessFilterCToCpp::~CefCookieAccessFilterCToCpp() {}
+
+template <>
+cef_cookie_access_filter_t* CefCToCppRefCounted<
+ CefCookieAccessFilterCToCpp,
+ CefCookieAccessFilter,
+ cef_cookie_access_filter_t>::UnwrapDerived(CefWrapperType type,
+ CefCookieAccessFilter* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefCookieAccessFilterCToCpp,
+ CefCookieAccessFilter,
+ cef_cookie_access_filter_t>::kWrapperType =
+ WT_COOKIE_ACCESS_FILTER;
diff --git a/libcef_dll/ctocpp/cookie_access_filter_ctocpp.h b/libcef_dll/ctocpp/cookie_access_filter_ctocpp.h
new file mode 100644
index 00000000..0da83121
--- /dev/null
+++ b/libcef_dll/ctocpp/cookie_access_filter_ctocpp.h
@@ -0,0 +1,49 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=b325a81a438e8e510eb826bc4e6acf5df04281c8$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_COOKIE_ACCESS_FILTER_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_COOKIE_ACCESS_FILTER_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_resource_request_handler_capi.h"
+#include "include/cef_resource_request_handler.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefCookieAccessFilterCToCpp
+ : public CefCToCppRefCounted<CefCookieAccessFilterCToCpp,
+ CefCookieAccessFilter,
+ cef_cookie_access_filter_t> {
+ public:
+ CefCookieAccessFilterCToCpp();
+ virtual ~CefCookieAccessFilterCToCpp();
+
+ // CefCookieAccessFilter methods.
+ bool CanSendCookie(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ const CefCookie& cookie) override;
+ bool CanSaveCookie(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response,
+ const CefCookie& cookie) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_COOKIE_ACCESS_FILTER_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/cookie_manager_ctocpp.cc b/libcef_dll/ctocpp/cookie_manager_ctocpp.cc
new file mode 100644
index 00000000..2f353e2d
--- /dev/null
+++ b/libcef_dll/ctocpp/cookie_manager_ctocpp.cc
@@ -0,0 +1,188 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=f620145f59aad5bc92c729dc876e9c094b06a541$
+//
+
+#include "libcef_dll/ctocpp/cookie_manager_ctocpp.h"
+#include "libcef_dll/cpptoc/completion_callback_cpptoc.h"
+#include "libcef_dll/cpptoc/cookie_visitor_cpptoc.h"
+#include "libcef_dll/cpptoc/delete_cookies_callback_cpptoc.h"
+#include "libcef_dll/cpptoc/set_cookie_callback_cpptoc.h"
+
+// STATIC METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefCookieManager> CefCookieManager::GetGlobalManager(
+ CefRefPtr<CefCompletionCallback> callback) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: callback
+
+ // Execute
+ cef_cookie_manager_t* _retval = cef_cookie_manager_get_global_manager(
+ CefCompletionCallbackCppToC::Wrap(callback));
+
+ // Return type: refptr_same
+ return CefCookieManagerCToCpp::Wrap(_retval);
+}
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+bool CefCookieManagerCToCpp::VisitAllCookies(
+ CefRefPtr<CefCookieVisitor> visitor) {
+ cef_cookie_manager_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, visit_all_cookies)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: visitor; type: refptr_diff
+ DCHECK(visitor.get());
+ if (!visitor.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->visit_all_cookies(
+ _struct, CefCookieVisitorCppToC::Wrap(visitor));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefCookieManagerCToCpp::VisitUrlCookies(
+ const CefString& url,
+ bool includeHttpOnly,
+ CefRefPtr<CefCookieVisitor> visitor) {
+ cef_cookie_manager_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, visit_url_cookies)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: url; type: string_byref_const
+ DCHECK(!url.empty());
+ if (url.empty()) {
+ return false;
+ }
+ // Verify param: visitor; type: refptr_diff
+ DCHECK(visitor.get());
+ if (!visitor.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval =
+ _struct->visit_url_cookies(_struct, url.GetStruct(), includeHttpOnly,
+ CefCookieVisitorCppToC::Wrap(visitor));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefCookieManagerCToCpp::SetCookie(
+ const CefString& url,
+ const CefCookie& cookie,
+ CefRefPtr<CefSetCookieCallback> callback) {
+ cef_cookie_manager_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_cookie)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: url; type: string_byref_const
+ DCHECK(!url.empty());
+ if (url.empty()) {
+ return false;
+ }
+ // Unverified params: callback
+
+ // Execute
+ int _retval = _struct->set_cookie(_struct, url.GetStruct(), &cookie,
+ CefSetCookieCallbackCppToC::Wrap(callback));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefCookieManagerCToCpp::DeleteCookies(
+ const CefString& url,
+ const CefString& cookie_name,
+ CefRefPtr<CefDeleteCookiesCallback> callback) {
+ cef_cookie_manager_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, delete_cookies)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: url, cookie_name, callback
+
+ // Execute
+ int _retval =
+ _struct->delete_cookies(_struct, url.GetStruct(), cookie_name.GetStruct(),
+ CefDeleteCookiesCallbackCppToC::Wrap(callback));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefCookieManagerCToCpp::FlushStore(
+ CefRefPtr<CefCompletionCallback> callback) {
+ cef_cookie_manager_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, flush_store)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: callback
+
+ // Execute
+ int _retval = _struct->flush_store(
+ _struct, CefCompletionCallbackCppToC::Wrap(callback));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefCookieManagerCToCpp::CefCookieManagerCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefCookieManagerCToCpp::~CefCookieManagerCToCpp() {}
+
+template <>
+cef_cookie_manager_t*
+CefCToCppRefCounted<CefCookieManagerCToCpp,
+ CefCookieManager,
+ cef_cookie_manager_t>::UnwrapDerived(CefWrapperType type,
+ CefCookieManager* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefCookieManagerCToCpp,
+ CefCookieManager,
+ cef_cookie_manager_t>::kWrapperType =
+ WT_COOKIE_MANAGER;
diff --git a/libcef_dll/ctocpp/cookie_manager_ctocpp.h b/libcef_dll/ctocpp/cookie_manager_ctocpp.h
new file mode 100644
index 00000000..418fd7dc
--- /dev/null
+++ b/libcef_dll/ctocpp/cookie_manager_ctocpp.h
@@ -0,0 +1,51 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=47bcf17fac9734852100b8e44bbead84b4ef78dc$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_COOKIE_MANAGER_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_COOKIE_MANAGER_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_cookie_capi.h"
+#include "include/cef_cookie.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefCookieManagerCToCpp
+ : public CefCToCppRefCounted<CefCookieManagerCToCpp,
+ CefCookieManager,
+ cef_cookie_manager_t> {
+ public:
+ CefCookieManagerCToCpp();
+ virtual ~CefCookieManagerCToCpp();
+
+ // CefCookieManager methods.
+ bool VisitAllCookies(CefRefPtr<CefCookieVisitor> visitor) override;
+ bool VisitUrlCookies(const CefString& url,
+ bool includeHttpOnly,
+ CefRefPtr<CefCookieVisitor> visitor) override;
+ bool SetCookie(const CefString& url,
+ const CefCookie& cookie,
+ CefRefPtr<CefSetCookieCallback> callback) override;
+ bool DeleteCookies(const CefString& url,
+ const CefString& cookie_name,
+ CefRefPtr<CefDeleteCookiesCallback> callback) override;
+ bool FlushStore(CefRefPtr<CefCompletionCallback> callback) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_COOKIE_MANAGER_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/cookie_visitor_ctocpp.cc b/libcef_dll/ctocpp/cookie_visitor_ctocpp.cc
new file mode 100644
index 00000000..ede3e738
--- /dev/null
+++ b/libcef_dll/ctocpp/cookie_visitor_ctocpp.cc
@@ -0,0 +1,72 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=01563cc1ee4d46340cf89b0b1602fe08b1b05109$
+//
+
+#include "libcef_dll/ctocpp/cookie_visitor_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+bool CefCookieVisitorCToCpp::Visit(const CefCookie& cookie,
+ int count,
+ int total,
+ bool& deleteCookie) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_cookie_visitor_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, visit)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Translate param: deleteCookie; type: bool_byref
+ int deleteCookieInt = deleteCookie;
+
+ // Execute
+ int _retval =
+ _struct->visit(_struct, &cookie, count, total, &deleteCookieInt);
+
+ // Restore param:deleteCookie; type: bool_byref
+ deleteCookie = deleteCookieInt ? true : false;
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefCookieVisitorCToCpp::CefCookieVisitorCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefCookieVisitorCToCpp::~CefCookieVisitorCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_cookie_visitor_t*
+CefCToCppRefCounted<CefCookieVisitorCToCpp,
+ CefCookieVisitor,
+ cef_cookie_visitor_t>::UnwrapDerived(CefWrapperType type,
+ CefCookieVisitor* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefCookieVisitorCToCpp,
+ CefCookieVisitor,
+ cef_cookie_visitor_t>::kWrapperType =
+ WT_COOKIE_VISITOR;
diff --git a/libcef_dll/ctocpp/cookie_visitor_ctocpp.h b/libcef_dll/ctocpp/cookie_visitor_ctocpp.h
new file mode 100644
index 00000000..cfc8498e
--- /dev/null
+++ b/libcef_dll/ctocpp/cookie_visitor_ctocpp.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=70fdf3c9319fd0ca0c0653ded314d645f8f39dfb$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_COOKIE_VISITOR_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_COOKIE_VISITOR_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_cookie_capi.h"
+#include "include/cef_cookie.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefCookieVisitorCToCpp
+ : public CefCToCppRefCounted<CefCookieVisitorCToCpp,
+ CefCookieVisitor,
+ cef_cookie_visitor_t> {
+ public:
+ CefCookieVisitorCToCpp();
+ virtual ~CefCookieVisitorCToCpp();
+
+ // CefCookieVisitor methods.
+ bool Visit(const CefCookie& cookie,
+ int count,
+ int total,
+ bool& deleteCookie) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_COOKIE_VISITOR_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/ctocpp_ref_counted.h b/libcef_dll/ctocpp/ctocpp_ref_counted.h
new file mode 100644
index 00000000..429d246a
--- /dev/null
+++ b/libcef_dll/ctocpp/ctocpp_ref_counted.h
@@ -0,0 +1,182 @@
+// Copyright (c) 2009 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_CTOCPP_REF_COUNTED_H_
+#define CEF_LIBCEF_DLL_CTOCPP_CTOCPP_REF_COUNTED_H_
+#pragma once
+
+#include "include/base/cef_logging.h"
+#include "include/capi/cef_base_capi.h"
+#include "include/cef_base.h"
+#include "libcef_dll/wrapper_types.h"
+
+// Wrap a C structure with a C++ class. This is used when the implementation
+// exists on the other side of the DLL boundary but will have methods called on
+// this side of the DLL boundary.
+template <class ClassName, class BaseName, class StructName>
+class CefCToCppRefCounted : public BaseName {
+ public:
+ CefCToCppRefCounted(const CefCToCppRefCounted&) = delete;
+ CefCToCppRefCounted& operator=(const CefCToCppRefCounted&) = delete;
+
+ // Create a new wrapper instance for a structure reference received from the
+ // other side.
+ static CefRefPtr<BaseName> Wrap(StructName* s);
+
+ // Retrieve the underlying structure reference from a wrapper instance for
+ // return back to the other side.
+ static StructName* Unwrap(CefRefPtr<BaseName> c);
+
+ // CefBaseRefCounted methods increment/decrement reference counts on both this
+ // object and the underlying wrapped structure.
+ void AddRef() const {
+ UnderlyingAddRef();
+ ref_count_.AddRef();
+ }
+ bool Release() const;
+ bool HasOneRef() const { return UnderlyingHasOneRef(); }
+ bool HasAtLeastOneRef() const { return UnderlyingHasAtLeastOneRef(); }
+
+ protected:
+ CefCToCppRefCounted() = default;
+ virtual ~CefCToCppRefCounted() = default;
+
+ // If returning the structure across the DLL boundary use Unwrap() instead.
+ StructName* GetStruct() const {
+ WrapperStruct* wrapperStruct = GetWrapperStruct(this);
+ // Verify that the wrapper offset was calculated correctly.
+ DCHECK_EQ(kWrapperType, wrapperStruct->type_);
+ return wrapperStruct->struct_;
+ }
+
+ private:
+ // Used to associate this wrapper object and the structure reference received
+ // from the other side.
+ struct WrapperStruct;
+
+ static WrapperStruct* GetWrapperStruct(const BaseName* obj);
+
+ // Unwrap as the derived type.
+ static StructName* UnwrapDerived(CefWrapperType type, BaseName* c);
+
+ // Increment/decrement reference counts on only the underlying class.
+ NO_SANITIZE("cfi-icall")
+ void UnderlyingAddRef() const {
+ cef_base_ref_counted_t* base =
+ reinterpret_cast<cef_base_ref_counted_t*>(GetStruct());
+ if (base->add_ref) {
+ base->add_ref(base);
+ }
+ }
+
+ NO_SANITIZE("cfi-icall")
+ bool UnderlyingRelease() const {
+ cef_base_ref_counted_t* base =
+ reinterpret_cast<cef_base_ref_counted_t*>(GetStruct());
+ if (!base->release) {
+ return false;
+ }
+ return base->release(base) ? true : false;
+ }
+
+ NO_SANITIZE("cfi-icall")
+ bool UnderlyingHasOneRef() const {
+ cef_base_ref_counted_t* base =
+ reinterpret_cast<cef_base_ref_counted_t*>(GetStruct());
+ if (!base->has_one_ref) {
+ return false;
+ }
+ return base->has_one_ref(base) ? true : false;
+ }
+
+ NO_SANITIZE("cfi-icall")
+ bool UnderlyingHasAtLeastOneRef() const {
+ cef_base_ref_counted_t* base =
+ reinterpret_cast<cef_base_ref_counted_t*>(GetStruct());
+ if (!base->has_at_least_one_ref) {
+ return false;
+ }
+ return base->has_at_least_one_ref(base) ? true : false;
+ }
+
+ CefRefCount ref_count_;
+
+ static CefWrapperType kWrapperType;
+};
+
+template <class ClassName, class BaseName, class StructName>
+struct CefCToCppRefCounted<ClassName, BaseName, StructName>::WrapperStruct {
+ CefWrapperType type_;
+ StructName* struct_;
+ ClassName wrapper_;
+};
+
+template <class ClassName, class BaseName, class StructName>
+CefRefPtr<BaseName> CefCToCppRefCounted<ClassName, BaseName, StructName>::Wrap(
+ StructName* s) {
+ if (!s) {
+ return nullptr;
+ }
+
+ // Wrap their structure with the CefCToCppRefCounted object.
+ WrapperStruct* wrapperStruct = new WrapperStruct;
+ wrapperStruct->type_ = kWrapperType;
+ wrapperStruct->struct_ = s;
+
+ // Put the wrapper object in a smart pointer.
+ CefRefPtr<BaseName> wrapperPtr(&wrapperStruct->wrapper_);
+ // Release the reference that was added to the CefCppToC wrapper object on
+ // the other side before their structure was passed to us.
+ wrapperStruct->wrapper_.UnderlyingRelease();
+ // Return the smart pointer.
+ return wrapperPtr;
+}
+
+template <class ClassName, class BaseName, class StructName>
+StructName* CefCToCppRefCounted<ClassName, BaseName, StructName>::Unwrap(
+ CefRefPtr<BaseName> c) {
+ if (!c.get()) {
+ return nullptr;
+ }
+
+ WrapperStruct* wrapperStruct = GetWrapperStruct(c.get());
+
+ // If the type does not match this object then we need to unwrap as the
+ // derived type.
+ if (wrapperStruct->type_ != kWrapperType) {
+ return UnwrapDerived(wrapperStruct->type_, c.get());
+ }
+
+ // Add a reference to the CefCppToC wrapper object on the other side that
+ // will be released once the structure is received.
+ wrapperStruct->wrapper_.UnderlyingAddRef();
+ // Return their original structure.
+ return wrapperStruct->struct_;
+}
+
+template <class ClassName, class BaseName, class StructName>
+bool CefCToCppRefCounted<ClassName, BaseName, StructName>::Release() const {
+ UnderlyingRelease();
+ if (ref_count_.Release()) {
+ WrapperStruct* wrapperStruct = GetWrapperStruct(this);
+ // Verify that the wrapper offset was calculated correctly.
+ DCHECK_EQ(kWrapperType, wrapperStruct->type_);
+ delete wrapperStruct;
+ return true;
+ }
+ return false;
+}
+
+template <class ClassName, class BaseName, class StructName>
+typename CefCToCppRefCounted<ClassName, BaseName, StructName>::WrapperStruct*
+CefCToCppRefCounted<ClassName, BaseName, StructName>::GetWrapperStruct(
+ const BaseName* obj) {
+ // Offset using the WrapperStruct size instead of individual member sizes to
+ // avoid problems due to platform/compiler differences in structure padding.
+ return reinterpret_cast<WrapperStruct*>(
+ reinterpret_cast<char*>(const_cast<BaseName*>(obj)) -
+ (sizeof(WrapperStruct) - sizeof(ClassName)));
+}
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_CTOCPP_REF_COUNTED_H_
diff --git a/libcef_dll/ctocpp/ctocpp_scoped.h b/libcef_dll/ctocpp/ctocpp_scoped.h
new file mode 100644
index 00000000..be1bb848
--- /dev/null
+++ b/libcef_dll/ctocpp/ctocpp_scoped.h
@@ -0,0 +1,205 @@
+// Copyright (c) 2017 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_CTOCPP_SCOPED_H_
+#define CEF_LIBCEF_DLL_CTOCPP_CTOCPP_SCOPED_H_
+#pragma once
+
+#include "include/base/cef_logging.h"
+#include "include/capi/cef_base_capi.h"
+#include "include/cef_base.h"
+#include "libcef_dll/wrapper_types.h"
+
+// Wrap a C structure with a C++ class. This is used when the implementation
+// exists on the other side of the DLL boundary but will have methods called on
+// this side of the DLL boundary.
+template <class ClassName, class BaseName, class StructName>
+class CefCToCppScoped : public BaseName {
+ public:
+ CefCToCppScoped(const CefCToCppScoped&) = delete;
+ CefCToCppScoped& operator=(const CefCToCppScoped&) = delete;
+
+ // Create a new wrapper instance for a structure reference received from the
+ // other side. The caller owns the CToCpp wrapper instance but not necessarily
+ // the underling object on the CppToC side (depends if s->del is non-NULL).
+ // The returned wrapper object can be used as either a scoped argument or to
+ // pass ownership. For example:
+ //
+ // void my_method(my_type1_t* struct1, my_type2_t* struct2) {
+ // // Passes ownership to MyMethod1().
+ // MyMethod1(MyType1CToCpp::Wrap(struct1));
+ //
+ // // Passes reference to MyMethod2().
+ // CefOwnPtr<MyType1> obj2 = MyType2CToCpp::Wrap(struct2);
+ // MyMethod2(obj2.get());
+ // // |obj2| is deleted when my_method() goes out of scope.
+ // }
+ //
+ // void MyMethod1(CefOwnPtr<MyType1> obj1) {
+ // // |obj1| is deleted when MyMethod1() goes out of scope.
+ // }
+ //
+ // void MyMethod2(CefRawPtr<MyType2> obj2) {
+ // }
+ static CefOwnPtr<BaseName> Wrap(StructName* s);
+
+ // Retrieve the underlying structure reference from a wrapper instance for
+ // return back to the other side. Ownership will be passed back to the other
+ // side and the wrapper will be deleted. For example:
+ //
+ // void MyMethod(CefOwnPtr<MyType> obj) {
+ // // Ownership of the underlying MyType object is passed to my_method().
+ // my_method(MyTypeCToCpp::UnwrapOwn(std::move(obj)));
+ // // |obj| is now NULL.
+ // }
+ static StructName* UnwrapOwn(CefOwnPtr<BaseName> c);
+
+ // Retrieve the underlying structure reference from a wrapper instance for
+ // return back to the other side. Ownership does not change. For example:
+ //
+ // void MyMethod(CefRawPtr<MyType> obj) {
+ // // A reference is passed to my_method(). Ownership does not change.
+ // my_method2(MyTypeCToCpp::UnwrapRaw(obj));
+ // }
+ static StructName* UnwrapRaw(CefRawPtr<BaseName> c);
+
+ // Override delete operator to properly delete the WrapperStruct.
+ // ~CefCToCppScoped will be called first followed by this method.
+ static void operator delete(void* ptr);
+
+ protected:
+ CefCToCppScoped() = default;
+ virtual ~CefCToCppScoped() = default;
+
+ // If returning the structure across the DLL boundary use Unwrap() instead.
+ StructName* GetStruct() const {
+ WrapperStruct* wrapperStruct = GetWrapperStruct(this);
+ // Verify that the wrapper offset was calculated correctly.
+ DCHECK_EQ(kWrapperType, wrapperStruct->type_);
+ return wrapperStruct->struct_;
+ }
+
+ private:
+ // Used to associate this wrapper object and the structure reference received
+ // from the other side.
+ struct WrapperStruct;
+
+ static WrapperStruct* GetWrapperStruct(const BaseName* obj);
+
+ // Unwrap as the derived type.
+ static StructName* UnwrapDerivedOwn(CefWrapperType type,
+ CefOwnPtr<BaseName> c);
+ static StructName* UnwrapDerivedRaw(CefWrapperType type,
+ CefRawPtr<BaseName> c);
+
+ static CefWrapperType kWrapperType;
+};
+
+template <class ClassName, class BaseName, class StructName>
+struct CefCToCppScoped<ClassName, BaseName, StructName>::WrapperStruct {
+ CefWrapperType type_;
+ StructName* struct_;
+ ClassName wrapper_;
+};
+
+template <class ClassName, class BaseName, class StructName>
+CefOwnPtr<BaseName> CefCToCppScoped<ClassName, BaseName, StructName>::Wrap(
+ StructName* s) {
+ if (!s) {
+ return CefOwnPtr<BaseName>();
+ }
+
+ // Wrap their structure with the CefCToCpp object.
+ WrapperStruct* wrapperStruct = new WrapperStruct;
+ wrapperStruct->type_ = kWrapperType;
+ wrapperStruct->struct_ = s;
+
+ return CefOwnPtr<BaseName>(&wrapperStruct->wrapper_);
+}
+
+template <class ClassName, class BaseName, class StructName>
+StructName* CefCToCppScoped<ClassName, BaseName, StructName>::UnwrapOwn(
+ CefOwnPtr<BaseName> c) {
+ if (!c.get()) {
+ return nullptr;
+ }
+
+ WrapperStruct* wrapperStruct = GetWrapperStruct(c.get());
+
+ // If the type does not match this object then we need to unwrap as the
+ // derived type.
+ if (wrapperStruct->type_ != kWrapperType) {
+ return UnwrapDerivedOwn(wrapperStruct->type_, std::move(c));
+ }
+
+ StructName* orig_struct = wrapperStruct->struct_;
+
+#if DCHECK_IS_ON()
+ // We should own the object currently.
+ cef_base_scoped_t* base = reinterpret_cast<cef_base_scoped_t*>(orig_struct);
+ DCHECK(base && base->del);
+#endif
+
+ // Don't delete the original object when the wrapper is deleted.
+ wrapperStruct->struct_ = nullptr;
+
+ // Return the original structure.
+ return orig_struct;
+ // The wrapper |c| is deleted when this method goes out of scope.
+}
+
+template <class ClassName, class BaseName, class StructName>
+StructName* CefCToCppScoped<ClassName, BaseName, StructName>::UnwrapRaw(
+ CefRawPtr<BaseName> c) {
+ if (!c) {
+ return nullptr;
+ }
+
+ WrapperStruct* wrapperStruct = GetWrapperStruct(c);
+
+ // If the type does not match this object then we need to unwrap as the
+ // derived type.
+ if (wrapperStruct->type_ != kWrapperType) {
+ return UnwrapDerivedRaw(wrapperStruct->type_, c);
+ }
+
+ // Return the original structure.
+ return wrapperStruct->struct_;
+}
+
+template <class ClassName, class BaseName, class StructName>
+NO_SANITIZE("cfi-icall")
+void CefCToCppScoped<ClassName, BaseName, StructName>::operator delete(
+ void* ptr) {
+ WrapperStruct* wrapperStruct = GetWrapperStruct(static_cast<BaseName*>(ptr));
+ // Verify that the wrapper offset was calculated correctly.
+ DCHECK_EQ(kWrapperType, wrapperStruct->type_);
+
+ // May be NULL if UnwrapOwn() was called.
+ cef_base_scoped_t* base =
+ reinterpret_cast<cef_base_scoped_t*>(wrapperStruct->struct_);
+
+ // If we own the object (base->del != NULL) then notify the other side that
+ // the object has been deleted.
+ if (base && base->del) {
+ base->del(base);
+ }
+
+ // Delete the wrapper structure without executing ~CefCToCppScoped() an
+ // additional time.
+ ::operator delete(wrapperStruct);
+}
+
+template <class ClassName, class BaseName, class StructName>
+typename CefCToCppScoped<ClassName, BaseName, StructName>::WrapperStruct*
+CefCToCppScoped<ClassName, BaseName, StructName>::GetWrapperStruct(
+ const BaseName* obj) {
+ // Offset using the WrapperStruct size instead of individual member sizes to
+ // avoid problems due to platform/compiler differences in structure padding.
+ return reinterpret_cast<WrapperStruct*>(
+ reinterpret_cast<char*>(const_cast<BaseName*>(obj)) -
+ (sizeof(WrapperStruct) - sizeof(ClassName)));
+}
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_CTOCPP_SCOPED_H_
diff --git a/libcef_dll/ctocpp/delete_cookies_callback_ctocpp.cc b/libcef_dll/ctocpp/delete_cookies_callback_ctocpp.cc
new file mode 100644
index 00000000..a56be1a2
--- /dev/null
+++ b/libcef_dll/ctocpp/delete_cookies_callback_ctocpp.cc
@@ -0,0 +1,60 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=7610357e3d387904c31686a66cfbe344dd80962f$
+//
+
+#include "libcef_dll/ctocpp/delete_cookies_callback_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+void CefDeleteCookiesCallbackCToCpp::OnComplete(int num_deleted) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_delete_cookies_callback_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_complete)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->on_complete(_struct, num_deleted);
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefDeleteCookiesCallbackCToCpp::CefDeleteCookiesCallbackCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefDeleteCookiesCallbackCToCpp::~CefDeleteCookiesCallbackCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_delete_cookies_callback_t* CefCToCppRefCounted<
+ CefDeleteCookiesCallbackCToCpp,
+ CefDeleteCookiesCallback,
+ cef_delete_cookies_callback_t>::UnwrapDerived(CefWrapperType type,
+ CefDeleteCookiesCallback* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCToCppRefCounted<CefDeleteCookiesCallbackCToCpp,
+ CefDeleteCookiesCallback,
+ cef_delete_cookies_callback_t>::kWrapperType =
+ WT_DELETE_COOKIES_CALLBACK;
diff --git a/libcef_dll/ctocpp/delete_cookies_callback_ctocpp.h b/libcef_dll/ctocpp/delete_cookies_callback_ctocpp.h
new file mode 100644
index 00000000..7e7bdaf3
--- /dev/null
+++ b/libcef_dll/ctocpp/delete_cookies_callback_ctocpp.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=e064baa776ef2fb9b70d51ec556613859a222067$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_DELETE_COOKIES_CALLBACK_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_DELETE_COOKIES_CALLBACK_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_cookie_capi.h"
+#include "include/cef_cookie.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefDeleteCookiesCallbackCToCpp
+ : public CefCToCppRefCounted<CefDeleteCookiesCallbackCToCpp,
+ CefDeleteCookiesCallback,
+ cef_delete_cookies_callback_t> {
+ public:
+ CefDeleteCookiesCallbackCToCpp();
+ virtual ~CefDeleteCookiesCallbackCToCpp();
+
+ // CefDeleteCookiesCallback methods.
+ void OnComplete(int num_deleted) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_DELETE_COOKIES_CALLBACK_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/dev_tools_message_observer_ctocpp.cc b/libcef_dll/ctocpp/dev_tools_message_observer_ctocpp.cc
new file mode 100644
index 00000000..6357f294
--- /dev/null
+++ b/libcef_dll/ctocpp/dev_tools_message_observer_ctocpp.cc
@@ -0,0 +1,186 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=0a0ea961456500b4545d5947422606918de83d6e$
+//
+
+#include "libcef_dll/ctocpp/dev_tools_message_observer_ctocpp.h"
+#include "libcef_dll/cpptoc/browser_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+bool CefDevToolsMessageObserverCToCpp::OnDevToolsMessage(
+ CefRefPtr<CefBrowser> browser,
+ const void* message,
+ size_t message_size) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_dev_tools_message_observer_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_dev_tools_message)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return false;
+ }
+ // Verify param: message; type: simple_byaddr
+ DCHECK(message);
+ if (!message) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->on_dev_tools_message(
+ _struct, CefBrowserCppToC::Wrap(browser), message, message_size);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefDevToolsMessageObserverCToCpp::OnDevToolsMethodResult(
+ CefRefPtr<CefBrowser> browser,
+ int message_id,
+ bool success,
+ const void* result,
+ size_t result_size) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_dev_tools_message_observer_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_dev_tools_method_result)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+ // Unverified params: result
+
+ // Execute
+ _struct->on_dev_tools_method_result(_struct, CefBrowserCppToC::Wrap(browser),
+ message_id, success, result, result_size);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefDevToolsMessageObserverCToCpp::OnDevToolsEvent(
+ CefRefPtr<CefBrowser> browser,
+ const CefString& method,
+ const void* params,
+ size_t params_size) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_dev_tools_message_observer_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_dev_tools_event)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+ // Verify param: method; type: string_byref_const
+ DCHECK(!method.empty());
+ if (method.empty()) {
+ return;
+ }
+ // Unverified params: params
+
+ // Execute
+ _struct->on_dev_tools_event(_struct, CefBrowserCppToC::Wrap(browser),
+ method.GetStruct(), params, params_size);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefDevToolsMessageObserverCToCpp::OnDevToolsAgentAttached(
+ CefRefPtr<CefBrowser> browser) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_dev_tools_message_observer_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_dev_tools_agent_attached)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_dev_tools_agent_attached(_struct,
+ CefBrowserCppToC::Wrap(browser));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefDevToolsMessageObserverCToCpp::OnDevToolsAgentDetached(
+ CefRefPtr<CefBrowser> browser) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_dev_tools_message_observer_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_dev_tools_agent_detached)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_dev_tools_agent_detached(_struct,
+ CefBrowserCppToC::Wrap(browser));
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefDevToolsMessageObserverCToCpp::CefDevToolsMessageObserverCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefDevToolsMessageObserverCToCpp::~CefDevToolsMessageObserverCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_dev_tools_message_observer_t* CefCToCppRefCounted<
+ CefDevToolsMessageObserverCToCpp,
+ CefDevToolsMessageObserver,
+ cef_dev_tools_message_observer_t>::UnwrapDerived(CefWrapperType type,
+ CefDevToolsMessageObserver*
+ c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCToCppRefCounted<CefDevToolsMessageObserverCToCpp,
+ CefDevToolsMessageObserver,
+ cef_dev_tools_message_observer_t>::kWrapperType =
+ WT_DEV_TOOLS_MESSAGE_OBSERVER;
diff --git a/libcef_dll/ctocpp/dev_tools_message_observer_ctocpp.h b/libcef_dll/ctocpp/dev_tools_message_observer_ctocpp.h
new file mode 100644
index 00000000..c328e21f
--- /dev/null
+++ b/libcef_dll/ctocpp/dev_tools_message_observer_ctocpp.h
@@ -0,0 +1,56 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=13f5ab113bea9ee958f3d92e1c10898fd182c14e$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_DEV_TOOLS_MESSAGE_OBSERVER_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_DEV_TOOLS_MESSAGE_OBSERVER_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_browser_capi.h"
+#include "include/capi/cef_devtools_message_observer_capi.h"
+#include "include/cef_browser.h"
+#include "include/cef_devtools_message_observer.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefDevToolsMessageObserverCToCpp
+ : public CefCToCppRefCounted<CefDevToolsMessageObserverCToCpp,
+ CefDevToolsMessageObserver,
+ cef_dev_tools_message_observer_t> {
+ public:
+ CefDevToolsMessageObserverCToCpp();
+ virtual ~CefDevToolsMessageObserverCToCpp();
+
+ // CefDevToolsMessageObserver methods.
+ bool OnDevToolsMessage(CefRefPtr<CefBrowser> browser,
+ const void* message,
+ size_t message_size) override;
+ void OnDevToolsMethodResult(CefRefPtr<CefBrowser> browser,
+ int message_id,
+ bool success,
+ const void* result,
+ size_t result_size) override;
+ void OnDevToolsEvent(CefRefPtr<CefBrowser> browser,
+ const CefString& method,
+ const void* params,
+ size_t params_size) override;
+ void OnDevToolsAgentAttached(CefRefPtr<CefBrowser> browser) override;
+ void OnDevToolsAgentDetached(CefRefPtr<CefBrowser> browser) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_DEV_TOOLS_MESSAGE_OBSERVER_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/dialog_handler_ctocpp.cc b/libcef_dll/ctocpp/dialog_handler_ctocpp.cc
new file mode 100644
index 00000000..8b043376
--- /dev/null
+++ b/libcef_dll/ctocpp/dialog_handler_ctocpp.cc
@@ -0,0 +1,98 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=d3e14a8c5fc34064be3a20f386a11b1d7962163e$
+//
+
+#include "libcef_dll/ctocpp/dialog_handler_ctocpp.h"
+#include "libcef_dll/cpptoc/browser_cpptoc.h"
+#include "libcef_dll/cpptoc/file_dialog_callback_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+#include "libcef_dll/transfer_util.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+bool CefDialogHandlerCToCpp::OnFileDialog(
+ CefRefPtr<CefBrowser> browser,
+ FileDialogMode mode,
+ const CefString& title,
+ const CefString& default_file_path,
+ const std::vector<CefString>& accept_filters,
+ CefRefPtr<CefFileDialogCallback> callback) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_dialog_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_file_dialog)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return false;
+ }
+ // Verify param: callback; type: refptr_diff
+ DCHECK(callback.get());
+ if (!callback.get()) {
+ return false;
+ }
+ // Unverified params: title, default_file_path, accept_filters
+
+ // Translate param: accept_filters; type: string_vec_byref_const
+ cef_string_list_t accept_filtersList = cef_string_list_alloc();
+ DCHECK(accept_filtersList);
+ if (accept_filtersList) {
+ transfer_string_list_contents(accept_filters, accept_filtersList);
+ }
+
+ // Execute
+ int _retval = _struct->on_file_dialog(
+ _struct, CefBrowserCppToC::Wrap(browser), mode, title.GetStruct(),
+ default_file_path.GetStruct(), accept_filtersList,
+ CefFileDialogCallbackCppToC::Wrap(callback));
+
+ // Restore param:accept_filters; type: string_vec_byref_const
+ if (accept_filtersList) {
+ cef_string_list_free(accept_filtersList);
+ }
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefDialogHandlerCToCpp::CefDialogHandlerCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefDialogHandlerCToCpp::~CefDialogHandlerCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_dialog_handler_t*
+CefCToCppRefCounted<CefDialogHandlerCToCpp,
+ CefDialogHandler,
+ cef_dialog_handler_t>::UnwrapDerived(CefWrapperType type,
+ CefDialogHandler* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefDialogHandlerCToCpp,
+ CefDialogHandler,
+ cef_dialog_handler_t>::kWrapperType =
+ WT_DIALOG_HANDLER;
diff --git a/libcef_dll/ctocpp/dialog_handler_ctocpp.h b/libcef_dll/ctocpp/dialog_handler_ctocpp.h
new file mode 100644
index 00000000..32be4bcf
--- /dev/null
+++ b/libcef_dll/ctocpp/dialog_handler_ctocpp.h
@@ -0,0 +1,47 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=32bf297fed4117e7a49ec5286fa05a51b2bf106b$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_DIALOG_HANDLER_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_DIALOG_HANDLER_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include <vector>
+#include "include/capi/cef_dialog_handler_capi.h"
+#include "include/cef_dialog_handler.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefDialogHandlerCToCpp
+ : public CefCToCppRefCounted<CefDialogHandlerCToCpp,
+ CefDialogHandler,
+ cef_dialog_handler_t> {
+ public:
+ CefDialogHandlerCToCpp();
+ virtual ~CefDialogHandlerCToCpp();
+
+ // CefDialogHandler methods.
+ bool OnFileDialog(CefRefPtr<CefBrowser> browser,
+ FileDialogMode mode,
+ const CefString& title,
+ const CefString& default_file_path,
+ const std::vector<CefString>& accept_filters,
+ CefRefPtr<CefFileDialogCallback> callback) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_DIALOG_HANDLER_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/dictionary_value_ctocpp.cc b/libcef_dll/ctocpp/dictionary_value_ctocpp.cc
new file mode 100644
index 00000000..f3b2f752
--- /dev/null
+++ b/libcef_dll/ctocpp/dictionary_value_ctocpp.cc
@@ -0,0 +1,767 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=1ff8df1cf72415529b26fe90318d43bfe07939f1$
+//
+
+#include "libcef_dll/ctocpp/dictionary_value_ctocpp.h"
+#include "libcef_dll/ctocpp/binary_value_ctocpp.h"
+#include "libcef_dll/ctocpp/list_value_ctocpp.h"
+#include "libcef_dll/ctocpp/value_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+#include "libcef_dll/transfer_util.h"
+
+// STATIC METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefDictionaryValue> CefDictionaryValue::Create() {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_dictionary_value_t* _retval = cef_dictionary_value_create();
+
+ // Return type: refptr_same
+ return CefDictionaryValueCToCpp::Wrap(_retval);
+}
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") bool CefDictionaryValueCToCpp::IsValid() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_dictionary_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_valid)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_valid(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefDictionaryValueCToCpp::IsOwned() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_dictionary_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_owned)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_owned(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefDictionaryValueCToCpp::IsReadOnly() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_dictionary_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_read_only)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_read_only(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefDictionaryValueCToCpp::IsSame(CefRefPtr<CefDictionaryValue> that) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_dictionary_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_same)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: that; type: refptr_same
+ DCHECK(that.get());
+ if (!that.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval =
+ _struct->is_same(_struct, CefDictionaryValueCToCpp::Unwrap(that));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefDictionaryValueCToCpp::IsEqual(CefRefPtr<CefDictionaryValue> that) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_dictionary_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_equal)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: that; type: refptr_same
+ DCHECK(that.get());
+ if (!that.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval =
+ _struct->is_equal(_struct, CefDictionaryValueCToCpp::Unwrap(that));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefDictionaryValue> CefDictionaryValueCToCpp::Copy(
+ bool exclude_empty_children) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_dictionary_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, copy)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_dictionary_value_t* _retval =
+ _struct->copy(_struct, exclude_empty_children);
+
+ // Return type: refptr_same
+ return CefDictionaryValueCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") size_t CefDictionaryValueCToCpp::GetSize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_dictionary_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_size)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ size_t _retval = _struct->get_size(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") bool CefDictionaryValueCToCpp::Clear() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_dictionary_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, clear)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->clear(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefDictionaryValueCToCpp::HasKey(const CefString& key) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_dictionary_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, has_key)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: key; type: string_byref_const
+ DCHECK(!key.empty());
+ if (key.empty()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->has_key(_struct, key.GetStruct());
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefDictionaryValueCToCpp::GetKeys(KeyList& keys) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_dictionary_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_keys)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Translate param: keys; type: string_vec_byref
+ cef_string_list_t keysList = cef_string_list_alloc();
+ DCHECK(keysList);
+ if (keysList) {
+ transfer_string_list_contents(keys, keysList);
+ }
+
+ // Execute
+ int _retval = _struct->get_keys(_struct, keysList);
+
+ // Restore param:keys; type: string_vec_byref
+ if (keysList) {
+ keys.clear();
+ transfer_string_list_contents(keysList, keys);
+ cef_string_list_free(keysList);
+ }
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefDictionaryValueCToCpp::Remove(const CefString& key) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_dictionary_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, remove)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: key; type: string_byref_const
+ DCHECK(!key.empty());
+ if (key.empty()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->remove(_struct, key.GetStruct());
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CefValueType CefDictionaryValueCToCpp::GetType(const CefString& key) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_dictionary_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_type)) {
+ return VTYPE_INVALID;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: key; type: string_byref_const
+ DCHECK(!key.empty());
+ if (key.empty()) {
+ return VTYPE_INVALID;
+ }
+
+ // Execute
+ cef_value_type_t _retval = _struct->get_type(_struct, key.GetStruct());
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefValue> CefDictionaryValueCToCpp::GetValue(const CefString& key) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_dictionary_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_value)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: key; type: string_byref_const
+ DCHECK(!key.empty());
+ if (key.empty()) {
+ return nullptr;
+ }
+
+ // Execute
+ cef_value_t* _retval = _struct->get_value(_struct, key.GetStruct());
+
+ // Return type: refptr_same
+ return CefValueCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefDictionaryValueCToCpp::GetBool(const CefString& key) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_dictionary_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_bool)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: key; type: string_byref_const
+ DCHECK(!key.empty());
+ if (key.empty()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->get_bool(_struct, key.GetStruct());
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+int CefDictionaryValueCToCpp::GetInt(const CefString& key) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_dictionary_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_int)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: key; type: string_byref_const
+ DCHECK(!key.empty());
+ if (key.empty()) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = _struct->get_int(_struct, key.GetStruct());
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+double CefDictionaryValueCToCpp::GetDouble(const CefString& key) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_dictionary_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_double)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: key; type: string_byref_const
+ DCHECK(!key.empty());
+ if (key.empty()) {
+ return 0;
+ }
+
+ // Execute
+ double _retval = _struct->get_double(_struct, key.GetStruct());
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CefString CefDictionaryValueCToCpp::GetString(const CefString& key) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_dictionary_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_string)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: key; type: string_byref_const
+ DCHECK(!key.empty());
+ if (key.empty()) {
+ return CefString();
+ }
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_string(_struct, key.GetStruct());
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefBinaryValue> CefDictionaryValueCToCpp::GetBinary(
+ const CefString& key) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_dictionary_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_binary)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: key; type: string_byref_const
+ DCHECK(!key.empty());
+ if (key.empty()) {
+ return nullptr;
+ }
+
+ // Execute
+ cef_binary_value_t* _retval = _struct->get_binary(_struct, key.GetStruct());
+
+ // Return type: refptr_same
+ return CefBinaryValueCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefDictionaryValue> CefDictionaryValueCToCpp::GetDictionary(
+ const CefString& key) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_dictionary_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_dictionary)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: key; type: string_byref_const
+ DCHECK(!key.empty());
+ if (key.empty()) {
+ return nullptr;
+ }
+
+ // Execute
+ cef_dictionary_value_t* _retval =
+ _struct->get_dictionary(_struct, key.GetStruct());
+
+ // Return type: refptr_same
+ return CefDictionaryValueCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefListValue> CefDictionaryValueCToCpp::GetList(
+ const CefString& key) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_dictionary_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_list)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: key; type: string_byref_const
+ DCHECK(!key.empty());
+ if (key.empty()) {
+ return nullptr;
+ }
+
+ // Execute
+ cef_list_value_t* _retval = _struct->get_list(_struct, key.GetStruct());
+
+ // Return type: refptr_same
+ return CefListValueCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefDictionaryValueCToCpp::SetValue(const CefString& key,
+ CefRefPtr<CefValue> value) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_dictionary_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_value)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: key; type: string_byref_const
+ DCHECK(!key.empty());
+ if (key.empty()) {
+ return false;
+ }
+ // Verify param: value; type: refptr_same
+ DCHECK(value.get());
+ if (!value.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->set_value(_struct, key.GetStruct(),
+ CefValueCToCpp::Unwrap(value));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefDictionaryValueCToCpp::SetNull(const CefString& key) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_dictionary_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_null)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: key; type: string_byref_const
+ DCHECK(!key.empty());
+ if (key.empty()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->set_null(_struct, key.GetStruct());
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefDictionaryValueCToCpp::SetBool(const CefString& key, bool value) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_dictionary_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_bool)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: key; type: string_byref_const
+ DCHECK(!key.empty());
+ if (key.empty()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->set_bool(_struct, key.GetStruct(), value);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefDictionaryValueCToCpp::SetInt(const CefString& key, int value) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_dictionary_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_int)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: key; type: string_byref_const
+ DCHECK(!key.empty());
+ if (key.empty()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->set_int(_struct, key.GetStruct(), value);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefDictionaryValueCToCpp::SetDouble(const CefString& key, double value) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_dictionary_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_double)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: key; type: string_byref_const
+ DCHECK(!key.empty());
+ if (key.empty()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->set_double(_struct, key.GetStruct(), value);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefDictionaryValueCToCpp::SetString(const CefString& key,
+ const CefString& value) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_dictionary_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_string)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: key; type: string_byref_const
+ DCHECK(!key.empty());
+ if (key.empty()) {
+ return false;
+ }
+ // Unverified params: value
+
+ // Execute
+ int _retval =
+ _struct->set_string(_struct, key.GetStruct(), value.GetStruct());
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefDictionaryValueCToCpp::SetBinary(const CefString& key,
+ CefRefPtr<CefBinaryValue> value) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_dictionary_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_binary)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: key; type: string_byref_const
+ DCHECK(!key.empty());
+ if (key.empty()) {
+ return false;
+ }
+ // Verify param: value; type: refptr_same
+ DCHECK(value.get());
+ if (!value.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->set_binary(_struct, key.GetStruct(),
+ CefBinaryValueCToCpp::Unwrap(value));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefDictionaryValueCToCpp::SetDictionary(
+ const CefString& key,
+ CefRefPtr<CefDictionaryValue> value) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_dictionary_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_dictionary)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: key; type: string_byref_const
+ DCHECK(!key.empty());
+ if (key.empty()) {
+ return false;
+ }
+ // Verify param: value; type: refptr_same
+ DCHECK(value.get());
+ if (!value.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->set_dictionary(
+ _struct, key.GetStruct(), CefDictionaryValueCToCpp::Unwrap(value));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefDictionaryValueCToCpp::SetList(const CefString& key,
+ CefRefPtr<CefListValue> value) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_dictionary_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_list)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: key; type: string_byref_const
+ DCHECK(!key.empty());
+ if (key.empty()) {
+ return false;
+ }
+ // Verify param: value; type: refptr_same
+ DCHECK(value.get());
+ if (!value.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->set_list(_struct, key.GetStruct(),
+ CefListValueCToCpp::Unwrap(value));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefDictionaryValueCToCpp::CefDictionaryValueCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefDictionaryValueCToCpp::~CefDictionaryValueCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_dictionary_value_t* CefCToCppRefCounted<
+ CefDictionaryValueCToCpp,
+ CefDictionaryValue,
+ cef_dictionary_value_t>::UnwrapDerived(CefWrapperType type,
+ CefDictionaryValue* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefDictionaryValueCToCpp,
+ CefDictionaryValue,
+ cef_dictionary_value_t>::kWrapperType =
+ WT_DICTIONARY_VALUE;
diff --git a/libcef_dll/ctocpp/dictionary_value_ctocpp.h b/libcef_dll/ctocpp/dictionary_value_ctocpp.h
new file mode 100644
index 00000000..ba9843f8
--- /dev/null
+++ b/libcef_dll/ctocpp/dictionary_value_ctocpp.h
@@ -0,0 +1,71 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=68a7aff9f01e57edaeaa53bfbbc4c6121ebb3a1b$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_DICTIONARY_VALUE_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_DICTIONARY_VALUE_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_values_capi.h"
+#include "include/cef_values.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefDictionaryValueCToCpp
+ : public CefCToCppRefCounted<CefDictionaryValueCToCpp,
+ CefDictionaryValue,
+ cef_dictionary_value_t> {
+ public:
+ CefDictionaryValueCToCpp();
+ virtual ~CefDictionaryValueCToCpp();
+
+ // CefDictionaryValue methods.
+ bool IsValid() override;
+ bool IsOwned() override;
+ bool IsReadOnly() override;
+ bool IsSame(CefRefPtr<CefDictionaryValue> that) override;
+ bool IsEqual(CefRefPtr<CefDictionaryValue> that) override;
+ CefRefPtr<CefDictionaryValue> Copy(bool exclude_empty_children) override;
+ size_t GetSize() override;
+ bool Clear() override;
+ bool HasKey(const CefString& key) override;
+ bool GetKeys(KeyList& keys) override;
+ bool Remove(const CefString& key) override;
+ CefValueType GetType(const CefString& key) override;
+ CefRefPtr<CefValue> GetValue(const CefString& key) override;
+ bool GetBool(const CefString& key) override;
+ int GetInt(const CefString& key) override;
+ double GetDouble(const CefString& key) override;
+ CefString GetString(const CefString& key) override;
+ CefRefPtr<CefBinaryValue> GetBinary(const CefString& key) override;
+ CefRefPtr<CefDictionaryValue> GetDictionary(const CefString& key) override;
+ CefRefPtr<CefListValue> GetList(const CefString& key) override;
+ bool SetValue(const CefString& key, CefRefPtr<CefValue> value) override;
+ bool SetNull(const CefString& key) override;
+ bool SetBool(const CefString& key, bool value) override;
+ bool SetInt(const CefString& key, int value) override;
+ bool SetDouble(const CefString& key, double value) override;
+ bool SetString(const CefString& key, const CefString& value) override;
+ bool SetBinary(const CefString& key,
+ CefRefPtr<CefBinaryValue> value) override;
+ bool SetDictionary(const CefString& key,
+ CefRefPtr<CefDictionaryValue> value) override;
+ bool SetList(const CefString& key, CefRefPtr<CefListValue> value) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_DICTIONARY_VALUE_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/display_handler_ctocpp.cc b/libcef_dll/ctocpp/display_handler_ctocpp.cc
new file mode 100644
index 00000000..461f0ec9
--- /dev/null
+++ b/libcef_dll/ctocpp/display_handler_ctocpp.cc
@@ -0,0 +1,352 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=1a8b2156636547df981ea07ef3a017f661f1e419$
+//
+
+#include "libcef_dll/ctocpp/display_handler_ctocpp.h"
+#include "libcef_dll/cpptoc/browser_cpptoc.h"
+#include "libcef_dll/cpptoc/frame_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+#include "libcef_dll/transfer_util.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+void CefDisplayHandlerCToCpp::OnAddressChange(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const CefString& url) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_display_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_address_change)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+ // Verify param: frame; type: refptr_diff
+ DCHECK(frame.get());
+ if (!frame.get()) {
+ return;
+ }
+ // Verify param: url; type: string_byref_const
+ DCHECK(!url.empty());
+ if (url.empty()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_address_change(_struct, CefBrowserCppToC::Wrap(browser),
+ CefFrameCppToC::Wrap(frame), url.GetStruct());
+}
+
+NO_SANITIZE("cfi-icall")
+void CefDisplayHandlerCToCpp::OnTitleChange(CefRefPtr<CefBrowser> browser,
+ const CefString& title) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_display_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_title_change)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+ // Unverified params: title
+
+ // Execute
+ _struct->on_title_change(_struct, CefBrowserCppToC::Wrap(browser),
+ title.GetStruct());
+}
+
+NO_SANITIZE("cfi-icall")
+void CefDisplayHandlerCToCpp::OnFaviconURLChange(
+ CefRefPtr<CefBrowser> browser,
+ const std::vector<CefString>& icon_urls) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_display_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_favicon_urlchange)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+ // Unverified params: icon_urls
+
+ // Translate param: icon_urls; type: string_vec_byref_const
+ cef_string_list_t icon_urlsList = cef_string_list_alloc();
+ DCHECK(icon_urlsList);
+ if (icon_urlsList) {
+ transfer_string_list_contents(icon_urls, icon_urlsList);
+ }
+
+ // Execute
+ _struct->on_favicon_urlchange(_struct, CefBrowserCppToC::Wrap(browser),
+ icon_urlsList);
+
+ // Restore param:icon_urls; type: string_vec_byref_const
+ if (icon_urlsList) {
+ cef_string_list_free(icon_urlsList);
+ }
+}
+
+NO_SANITIZE("cfi-icall")
+void CefDisplayHandlerCToCpp::OnFullscreenModeChange(
+ CefRefPtr<CefBrowser> browser,
+ bool fullscreen) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_display_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_fullscreen_mode_change)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_fullscreen_mode_change(_struct, CefBrowserCppToC::Wrap(browser),
+ fullscreen);
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefDisplayHandlerCToCpp::OnTooltip(CefRefPtr<CefBrowser> browser,
+ CefString& text) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_display_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_tooltip)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return false;
+ }
+ // Unverified params: text
+
+ // Execute
+ int _retval = _struct->on_tooltip(_struct, CefBrowserCppToC::Wrap(browser),
+ text.GetWritableStruct());
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefDisplayHandlerCToCpp::OnStatusMessage(CefRefPtr<CefBrowser> browser,
+ const CefString& value) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_display_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_status_message)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+ // Unverified params: value
+
+ // Execute
+ _struct->on_status_message(_struct, CefBrowserCppToC::Wrap(browser),
+ value.GetStruct());
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefDisplayHandlerCToCpp::OnConsoleMessage(CefRefPtr<CefBrowser> browser,
+ cef_log_severity_t level,
+ const CefString& message,
+ const CefString& source,
+ int line) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_display_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_console_message)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return false;
+ }
+ // Unverified params: message, source
+
+ // Execute
+ int _retval = _struct->on_console_message(
+ _struct, CefBrowserCppToC::Wrap(browser), level, message.GetStruct(),
+ source.GetStruct(), line);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefDisplayHandlerCToCpp::OnAutoResize(CefRefPtr<CefBrowser> browser,
+ const CefSize& new_size) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_display_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_auto_resize)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->on_auto_resize(
+ _struct, CefBrowserCppToC::Wrap(browser), &new_size);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefDisplayHandlerCToCpp::OnLoadingProgressChange(
+ CefRefPtr<CefBrowser> browser,
+ double progress) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_display_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_loading_progress_change)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_loading_progress_change(_struct, CefBrowserCppToC::Wrap(browser),
+ progress);
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefDisplayHandlerCToCpp::OnCursorChange(
+ CefRefPtr<CefBrowser> browser,
+ CefCursorHandle cursor,
+ cef_cursor_type_t type,
+ const CefCursorInfo& custom_cursor_info) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_display_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_cursor_change)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval =
+ _struct->on_cursor_change(_struct, CefBrowserCppToC::Wrap(browser),
+ cursor, type, &custom_cursor_info);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefDisplayHandlerCToCpp::OnMediaAccessChange(CefRefPtr<CefBrowser> browser,
+ bool has_video_access,
+ bool has_audio_access) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_display_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_media_access_change)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_media_access_change(_struct, CefBrowserCppToC::Wrap(browser),
+ has_video_access, has_audio_access);
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefDisplayHandlerCToCpp::CefDisplayHandlerCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefDisplayHandlerCToCpp::~CefDisplayHandlerCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_display_handler_t* CefCToCppRefCounted<
+ CefDisplayHandlerCToCpp,
+ CefDisplayHandler,
+ cef_display_handler_t>::UnwrapDerived(CefWrapperType type,
+ CefDisplayHandler* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefDisplayHandlerCToCpp,
+ CefDisplayHandler,
+ cef_display_handler_t>::kWrapperType =
+ WT_DISPLAY_HANDLER;
diff --git a/libcef_dll/ctocpp/display_handler_ctocpp.h b/libcef_dll/ctocpp/display_handler_ctocpp.h
new file mode 100644
index 00000000..e8964991
--- /dev/null
+++ b/libcef_dll/ctocpp/display_handler_ctocpp.h
@@ -0,0 +1,69 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=d45cff7bbeeb6398470dfb56e3e0f4258add36a2$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_DISPLAY_HANDLER_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_DISPLAY_HANDLER_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include <vector>
+#include "include/capi/cef_display_handler_capi.h"
+#include "include/cef_display_handler.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefDisplayHandlerCToCpp
+ : public CefCToCppRefCounted<CefDisplayHandlerCToCpp,
+ CefDisplayHandler,
+ cef_display_handler_t> {
+ public:
+ CefDisplayHandlerCToCpp();
+ virtual ~CefDisplayHandlerCToCpp();
+
+ // CefDisplayHandler methods.
+ void OnAddressChange(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const CefString& url) override;
+ void OnTitleChange(CefRefPtr<CefBrowser> browser,
+ const CefString& title) override;
+ void OnFaviconURLChange(CefRefPtr<CefBrowser> browser,
+ const std::vector<CefString>& icon_urls) override;
+ void OnFullscreenModeChange(CefRefPtr<CefBrowser> browser,
+ bool fullscreen) override;
+ bool OnTooltip(CefRefPtr<CefBrowser> browser, CefString& text) override;
+ void OnStatusMessage(CefRefPtr<CefBrowser> browser,
+ const CefString& value) override;
+ bool OnConsoleMessage(CefRefPtr<CefBrowser> browser,
+ cef_log_severity_t level,
+ const CefString& message,
+ const CefString& source,
+ int line) override;
+ bool OnAutoResize(CefRefPtr<CefBrowser> browser,
+ const CefSize& new_size) override;
+ void OnLoadingProgressChange(CefRefPtr<CefBrowser> browser,
+ double progress) override;
+ bool OnCursorChange(CefRefPtr<CefBrowser> browser,
+ CefCursorHandle cursor,
+ cef_cursor_type_t type,
+ const CefCursorInfo& custom_cursor_info) override;
+ void OnMediaAccessChange(CefRefPtr<CefBrowser> browser,
+ bool has_video_access,
+ bool has_audio_access) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_DISPLAY_HANDLER_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/domdocument_ctocpp.cc b/libcef_dll/ctocpp/domdocument_ctocpp.cc
new file mode 100644
index 00000000..45655303
--- /dev/null
+++ b/libcef_dll/ctocpp/domdocument_ctocpp.cc
@@ -0,0 +1,310 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=3029a85a03d6d8d68350bea5ad3448e0b142bce0$
+//
+
+#include "libcef_dll/ctocpp/domdocument_ctocpp.h"
+#include "libcef_dll/ctocpp/domnode_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") CefDOMDocument::Type CefDOMDocumentCToCpp::GetType() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_domdocument_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_type)) {
+ return DOM_DOCUMENT_TYPE_UNKNOWN;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_dom_document_type_t _retval = _struct->get_type(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefDOMNode> CefDOMDocumentCToCpp::GetDocument() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_domdocument_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_document)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_domnode_t* _retval = _struct->get_document(_struct);
+
+ // Return type: refptr_same
+ return CefDOMNodeCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefDOMNode> CefDOMDocumentCToCpp::GetBody() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_domdocument_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_body)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_domnode_t* _retval = _struct->get_body(_struct);
+
+ // Return type: refptr_same
+ return CefDOMNodeCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefDOMNode> CefDOMDocumentCToCpp::GetHead() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_domdocument_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_head)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_domnode_t* _retval = _struct->get_head(_struct);
+
+ // Return type: refptr_same
+ return CefDOMNodeCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") CefString CefDOMDocumentCToCpp::GetTitle() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_domdocument_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_title)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_title(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefDOMNode> CefDOMDocumentCToCpp::GetElementById(
+ const CefString& id) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_domdocument_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_element_by_id)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: id; type: string_byref_const
+ DCHECK(!id.empty());
+ if (id.empty()) {
+ return nullptr;
+ }
+
+ // Execute
+ cef_domnode_t* _retval = _struct->get_element_by_id(_struct, id.GetStruct());
+
+ // Return type: refptr_same
+ return CefDOMNodeCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefDOMNode> CefDOMDocumentCToCpp::GetFocusedNode() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_domdocument_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_focused_node)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_domnode_t* _retval = _struct->get_focused_node(_struct);
+
+ // Return type: refptr_same
+ return CefDOMNodeCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") bool CefDOMDocumentCToCpp::HasSelection() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_domdocument_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, has_selection)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->has_selection(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") int CefDOMDocumentCToCpp::GetSelectionStartOffset() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_domdocument_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_selection_start_offset)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_selection_start_offset(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") int CefDOMDocumentCToCpp::GetSelectionEndOffset() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_domdocument_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_selection_end_offset)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_selection_end_offset(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CefString CefDOMDocumentCToCpp::GetSelectionAsMarkup() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_domdocument_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_selection_as_markup)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_selection_as_markup(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") CefString CefDOMDocumentCToCpp::GetSelectionAsText() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_domdocument_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_selection_as_text)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_selection_as_text(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") CefString CefDOMDocumentCToCpp::GetBaseURL() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_domdocument_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_base_url)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_base_url(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+CefString CefDOMDocumentCToCpp::GetCompleteURL(const CefString& partialURL) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_domdocument_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_complete_url)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: partialURL; type: string_byref_const
+ DCHECK(!partialURL.empty());
+ if (partialURL.empty()) {
+ return CefString();
+ }
+
+ // Execute
+ cef_string_userfree_t _retval =
+ _struct->get_complete_url(_struct, partialURL.GetStruct());
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefDOMDocumentCToCpp::CefDOMDocumentCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefDOMDocumentCToCpp::~CefDOMDocumentCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_domdocument_t*
+CefCToCppRefCounted<CefDOMDocumentCToCpp, CefDOMDocument, cef_domdocument_t>::
+ UnwrapDerived(CefWrapperType type, CefDOMDocument* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefDOMDocumentCToCpp,
+ CefDOMDocument,
+ cef_domdocument_t>::kWrapperType =
+ WT_DOMDOCUMENT;
diff --git a/libcef_dll/ctocpp/domdocument_ctocpp.h b/libcef_dll/ctocpp/domdocument_ctocpp.h
new file mode 100644
index 00000000..29fe326f
--- /dev/null
+++ b/libcef_dll/ctocpp/domdocument_ctocpp.h
@@ -0,0 +1,53 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=987816a9b106341068d08f3cd9254c98cf77f6ad$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_DOMDOCUMENT_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_DOMDOCUMENT_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_dom_capi.h"
+#include "include/cef_dom.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefDOMDocumentCToCpp : public CefCToCppRefCounted<CefDOMDocumentCToCpp,
+ CefDOMDocument,
+ cef_domdocument_t> {
+ public:
+ CefDOMDocumentCToCpp();
+ virtual ~CefDOMDocumentCToCpp();
+
+ // CefDOMDocument methods.
+ Type GetType() override;
+ CefRefPtr<CefDOMNode> GetDocument() override;
+ CefRefPtr<CefDOMNode> GetBody() override;
+ CefRefPtr<CefDOMNode> GetHead() override;
+ CefString GetTitle() override;
+ CefRefPtr<CefDOMNode> GetElementById(const CefString& id) override;
+ CefRefPtr<CefDOMNode> GetFocusedNode() override;
+ bool HasSelection() override;
+ int GetSelectionStartOffset() override;
+ int GetSelectionEndOffset() override;
+ CefString GetSelectionAsMarkup() override;
+ CefString GetSelectionAsText() override;
+ CefString GetBaseURL() override;
+ CefString GetCompleteURL(const CefString& partialURL) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_DOMDOCUMENT_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/domnode_ctocpp.cc b/libcef_dll/ctocpp/domnode_ctocpp.cc
new file mode 100644
index 00000000..11f62e28
--- /dev/null
+++ b/libcef_dll/ctocpp/domnode_ctocpp.cc
@@ -0,0 +1,562 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=c55b3c940044e1ba8614366bc005404fb34f6cb1$
+//
+
+#include "libcef_dll/ctocpp/domnode_ctocpp.h"
+#include "libcef_dll/ctocpp/domdocument_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+#include "libcef_dll/transfer_util.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") CefDOMNode::Type CefDOMNodeCToCpp::GetType() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_domnode_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_type)) {
+ return DOM_NODE_TYPE_UNSUPPORTED;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_dom_node_type_t _retval = _struct->get_type(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") bool CefDOMNodeCToCpp::IsText() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_domnode_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_text)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_text(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefDOMNodeCToCpp::IsElement() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_domnode_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_element)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_element(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefDOMNodeCToCpp::IsEditable() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_domnode_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_editable)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_editable(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefDOMNodeCToCpp::IsFormControlElement() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_domnode_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_form_control_element)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_form_control_element(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CefString CefDOMNodeCToCpp::GetFormControlElementType() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_domnode_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_form_control_element_type)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval =
+ _struct->get_form_control_element_type(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefDOMNodeCToCpp::IsSame(CefRefPtr<CefDOMNode> that) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_domnode_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_same)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: that; type: refptr_same
+ DCHECK(that.get());
+ if (!that.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->is_same(_struct, CefDOMNodeCToCpp::Unwrap(that));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") CefString CefDOMNodeCToCpp::GetName() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_domnode_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_name)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_name(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") CefString CefDOMNodeCToCpp::GetValue() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_domnode_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_value)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_value(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefDOMNodeCToCpp::SetValue(const CefString& value) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_domnode_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_value)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: value; type: string_byref_const
+ DCHECK(!value.empty());
+ if (value.empty()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->set_value(_struct, value.GetStruct());
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") CefString CefDOMNodeCToCpp::GetAsMarkup() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_domnode_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_as_markup)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_as_markup(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefDOMDocument> CefDOMNodeCToCpp::GetDocument() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_domnode_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_document)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_domdocument_t* _retval = _struct->get_document(_struct);
+
+ // Return type: refptr_same
+ return CefDOMDocumentCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefDOMNode> CefDOMNodeCToCpp::GetParent() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_domnode_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_parent)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_domnode_t* _retval = _struct->get_parent(_struct);
+
+ // Return type: refptr_same
+ return CefDOMNodeCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefDOMNode> CefDOMNodeCToCpp::GetPreviousSibling() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_domnode_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_previous_sibling)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_domnode_t* _retval = _struct->get_previous_sibling(_struct);
+
+ // Return type: refptr_same
+ return CefDOMNodeCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefDOMNode> CefDOMNodeCToCpp::GetNextSibling() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_domnode_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_next_sibling)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_domnode_t* _retval = _struct->get_next_sibling(_struct);
+
+ // Return type: refptr_same
+ return CefDOMNodeCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") bool CefDOMNodeCToCpp::HasChildren() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_domnode_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, has_children)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->has_children(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefDOMNode> CefDOMNodeCToCpp::GetFirstChild() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_domnode_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_first_child)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_domnode_t* _retval = _struct->get_first_child(_struct);
+
+ // Return type: refptr_same
+ return CefDOMNodeCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefDOMNode> CefDOMNodeCToCpp::GetLastChild() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_domnode_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_last_child)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_domnode_t* _retval = _struct->get_last_child(_struct);
+
+ // Return type: refptr_same
+ return CefDOMNodeCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") CefString CefDOMNodeCToCpp::GetElementTagName() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_domnode_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_element_tag_name)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_element_tag_name(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") bool CefDOMNodeCToCpp::HasElementAttributes() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_domnode_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, has_element_attributes)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->has_element_attributes(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefDOMNodeCToCpp::HasElementAttribute(const CefString& attrName) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_domnode_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, has_element_attribute)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: attrName; type: string_byref_const
+ DCHECK(!attrName.empty());
+ if (attrName.empty()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->has_element_attribute(_struct, attrName.GetStruct());
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CefString CefDOMNodeCToCpp::GetElementAttribute(const CefString& attrName) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_domnode_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_element_attribute)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: attrName; type: string_byref_const
+ DCHECK(!attrName.empty());
+ if (attrName.empty()) {
+ return CefString();
+ }
+
+ // Execute
+ cef_string_userfree_t _retval =
+ _struct->get_element_attribute(_struct, attrName.GetStruct());
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefDOMNodeCToCpp::GetElementAttributes(AttributeMap& attrMap) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_domnode_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_element_attributes)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Translate param: attrMap; type: string_map_single_byref
+ cef_string_map_t attrMapMap = cef_string_map_alloc();
+ DCHECK(attrMapMap);
+ if (attrMapMap) {
+ transfer_string_map_contents(attrMap, attrMapMap);
+ }
+
+ // Execute
+ _struct->get_element_attributes(_struct, attrMapMap);
+
+ // Restore param:attrMap; type: string_map_single_byref
+ if (attrMapMap) {
+ attrMap.clear();
+ transfer_string_map_contents(attrMapMap, attrMap);
+ cef_string_map_free(attrMapMap);
+ }
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefDOMNodeCToCpp::SetElementAttribute(const CefString& attrName,
+ const CefString& value) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_domnode_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_element_attribute)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: attrName; type: string_byref_const
+ DCHECK(!attrName.empty());
+ if (attrName.empty()) {
+ return false;
+ }
+ // Verify param: value; type: string_byref_const
+ DCHECK(!value.empty());
+ if (value.empty()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->set_element_attribute(_struct, attrName.GetStruct(),
+ value.GetStruct());
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") CefString CefDOMNodeCToCpp::GetElementInnerText() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_domnode_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_element_inner_text)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_element_inner_text(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") CefRect CefDOMNodeCToCpp::GetElementBounds() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_domnode_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_element_bounds)) {
+ return CefRect();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_rect_t _retval = _struct->get_element_bounds(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefDOMNodeCToCpp::CefDOMNodeCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefDOMNodeCToCpp::~CefDOMNodeCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_domnode_t*
+CefCToCppRefCounted<CefDOMNodeCToCpp, CefDOMNode, cef_domnode_t>::UnwrapDerived(
+ CefWrapperType type,
+ CefDOMNode* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefDOMNodeCToCpp,
+ CefDOMNode,
+ cef_domnode_t>::kWrapperType = WT_DOMNODE;
diff --git a/libcef_dll/ctocpp/domnode_ctocpp.h b/libcef_dll/ctocpp/domnode_ctocpp.h
new file mode 100644
index 00000000..a16b3109
--- /dev/null
+++ b/libcef_dll/ctocpp/domnode_ctocpp.h
@@ -0,0 +1,65 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=343a5f84d09a6933f005c3915582c73c43bda406$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_DOMNODE_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_DOMNODE_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_dom_capi.h"
+#include "include/cef_dom.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefDOMNodeCToCpp
+ : public CefCToCppRefCounted<CefDOMNodeCToCpp, CefDOMNode, cef_domnode_t> {
+ public:
+ CefDOMNodeCToCpp();
+ virtual ~CefDOMNodeCToCpp();
+
+ // CefDOMNode methods.
+ Type GetType() override;
+ bool IsText() override;
+ bool IsElement() override;
+ bool IsEditable() override;
+ bool IsFormControlElement() override;
+ CefString GetFormControlElementType() override;
+ bool IsSame(CefRefPtr<CefDOMNode> that) override;
+ CefString GetName() override;
+ CefString GetValue() override;
+ bool SetValue(const CefString& value) override;
+ CefString GetAsMarkup() override;
+ CefRefPtr<CefDOMDocument> GetDocument() override;
+ CefRefPtr<CefDOMNode> GetParent() override;
+ CefRefPtr<CefDOMNode> GetPreviousSibling() override;
+ CefRefPtr<CefDOMNode> GetNextSibling() override;
+ bool HasChildren() override;
+ CefRefPtr<CefDOMNode> GetFirstChild() override;
+ CefRefPtr<CefDOMNode> GetLastChild() override;
+ CefString GetElementTagName() override;
+ bool HasElementAttributes() override;
+ bool HasElementAttribute(const CefString& attrName) override;
+ CefString GetElementAttribute(const CefString& attrName) override;
+ void GetElementAttributes(AttributeMap& attrMap) override;
+ bool SetElementAttribute(const CefString& attrName,
+ const CefString& value) override;
+ CefString GetElementInnerText() override;
+ CefRect GetElementBounds() override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_DOMNODE_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/domvisitor_ctocpp.cc b/libcef_dll/ctocpp/domvisitor_ctocpp.cc
new file mode 100644
index 00000000..bcec99d9
--- /dev/null
+++ b/libcef_dll/ctocpp/domvisitor_ctocpp.cc
@@ -0,0 +1,64 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=faf6f8643d2c54f410b3c140ffc9b6bad2a57b4a$
+//
+
+#include "libcef_dll/ctocpp/domvisitor_ctocpp.h"
+#include "libcef_dll/cpptoc/domdocument_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+void CefDOMVisitorCToCpp::Visit(CefRefPtr<CefDOMDocument> document) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_domvisitor_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, visit)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: document; type: refptr_diff
+ DCHECK(document.get());
+ if (!document.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->visit(_struct, CefDOMDocumentCppToC::Wrap(document));
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefDOMVisitorCToCpp::CefDOMVisitorCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefDOMVisitorCToCpp::~CefDOMVisitorCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_domvisitor_t*
+CefCToCppRefCounted<CefDOMVisitorCToCpp, CefDOMVisitor, cef_domvisitor_t>::
+ UnwrapDerived(CefWrapperType type, CefDOMVisitor* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefDOMVisitorCToCpp,
+ CefDOMVisitor,
+ cef_domvisitor_t>::kWrapperType =
+ WT_DOMVISITOR;
diff --git a/libcef_dll/ctocpp/domvisitor_ctocpp.h b/libcef_dll/ctocpp/domvisitor_ctocpp.h
new file mode 100644
index 00000000..0504b522
--- /dev/null
+++ b/libcef_dll/ctocpp/domvisitor_ctocpp.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=9f8a534b9feef5b972259d972bf30ad838e1a788$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_DOMVISITOR_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_DOMVISITOR_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_dom_capi.h"
+#include "include/cef_dom.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefDOMVisitorCToCpp : public CefCToCppRefCounted<CefDOMVisitorCToCpp,
+ CefDOMVisitor,
+ cef_domvisitor_t> {
+ public:
+ CefDOMVisitorCToCpp();
+ virtual ~CefDOMVisitorCToCpp();
+
+ // CefDOMVisitor methods.
+ void Visit(CefRefPtr<CefDOMDocument> document) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_DOMVISITOR_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/download_handler_ctocpp.cc b/libcef_dll/ctocpp/download_handler_ctocpp.cc
new file mode 100644
index 00000000..5ac64731
--- /dev/null
+++ b/libcef_dll/ctocpp/download_handler_ctocpp.cc
@@ -0,0 +1,165 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=c6c8482357711189540cbb82ae40bf9bd78b404b$
+//
+
+#include "libcef_dll/ctocpp/download_handler_ctocpp.h"
+#include "libcef_dll/cpptoc/before_download_callback_cpptoc.h"
+#include "libcef_dll/cpptoc/browser_cpptoc.h"
+#include "libcef_dll/cpptoc/download_item_callback_cpptoc.h"
+#include "libcef_dll/cpptoc/download_item_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+bool CefDownloadHandlerCToCpp::CanDownload(CefRefPtr<CefBrowser> browser,
+ const CefString& url,
+ const CefString& request_method) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_download_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, can_download)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return false;
+ }
+ // Verify param: url; type: string_byref_const
+ DCHECK(!url.empty());
+ if (url.empty()) {
+ return false;
+ }
+ // Verify param: request_method; type: string_byref_const
+ DCHECK(!request_method.empty());
+ if (request_method.empty()) {
+ return false;
+ }
+
+ // Execute
+ int _retval =
+ _struct->can_download(_struct, CefBrowserCppToC::Wrap(browser),
+ url.GetStruct(), request_method.GetStruct());
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefDownloadHandlerCToCpp::OnBeforeDownload(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefDownloadItem> download_item,
+ const CefString& suggested_name,
+ CefRefPtr<CefBeforeDownloadCallback> callback) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_download_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_before_download)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+ // Verify param: download_item; type: refptr_diff
+ DCHECK(download_item.get());
+ if (!download_item.get()) {
+ return;
+ }
+ // Verify param: suggested_name; type: string_byref_const
+ DCHECK(!suggested_name.empty());
+ if (suggested_name.empty()) {
+ return;
+ }
+ // Verify param: callback; type: refptr_diff
+ DCHECK(callback.get());
+ if (!callback.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_before_download(_struct, CefBrowserCppToC::Wrap(browser),
+ CefDownloadItemCppToC::Wrap(download_item),
+ suggested_name.GetStruct(),
+ CefBeforeDownloadCallbackCppToC::Wrap(callback));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefDownloadHandlerCToCpp::OnDownloadUpdated(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefDownloadItem> download_item,
+ CefRefPtr<CefDownloadItemCallback> callback) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_download_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_download_updated)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+ // Verify param: download_item; type: refptr_diff
+ DCHECK(download_item.get());
+ if (!download_item.get()) {
+ return;
+ }
+ // Verify param: callback; type: refptr_diff
+ DCHECK(callback.get());
+ if (!callback.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_download_updated(_struct, CefBrowserCppToC::Wrap(browser),
+ CefDownloadItemCppToC::Wrap(download_item),
+ CefDownloadItemCallbackCppToC::Wrap(callback));
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefDownloadHandlerCToCpp::CefDownloadHandlerCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefDownloadHandlerCToCpp::~CefDownloadHandlerCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_download_handler_t* CefCToCppRefCounted<
+ CefDownloadHandlerCToCpp,
+ CefDownloadHandler,
+ cef_download_handler_t>::UnwrapDerived(CefWrapperType type,
+ CefDownloadHandler* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefDownloadHandlerCToCpp,
+ CefDownloadHandler,
+ cef_download_handler_t>::kWrapperType =
+ WT_DOWNLOAD_HANDLER;
diff --git a/libcef_dll/ctocpp/download_handler_ctocpp.h b/libcef_dll/ctocpp/download_handler_ctocpp.h
new file mode 100644
index 00000000..d8253204
--- /dev/null
+++ b/libcef_dll/ctocpp/download_handler_ctocpp.h
@@ -0,0 +1,50 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=486d31ad20241c84c224f0b8c90fe0c0f915ad18$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_DOWNLOAD_HANDLER_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_DOWNLOAD_HANDLER_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_download_handler_capi.h"
+#include "include/cef_download_handler.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefDownloadHandlerCToCpp
+ : public CefCToCppRefCounted<CefDownloadHandlerCToCpp,
+ CefDownloadHandler,
+ cef_download_handler_t> {
+ public:
+ CefDownloadHandlerCToCpp();
+ virtual ~CefDownloadHandlerCToCpp();
+
+ // CefDownloadHandler methods.
+ bool CanDownload(CefRefPtr<CefBrowser> browser,
+ const CefString& url,
+ const CefString& request_method) override;
+ void OnBeforeDownload(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefDownloadItem> download_item,
+ const CefString& suggested_name,
+ CefRefPtr<CefBeforeDownloadCallback> callback) override;
+ void OnDownloadUpdated(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefDownloadItem> download_item,
+ CefRefPtr<CefDownloadItemCallback> callback) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_DOWNLOAD_HANDLER_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/download_image_callback_ctocpp.cc b/libcef_dll/ctocpp/download_image_callback_ctocpp.cc
new file mode 100644
index 00000000..87663865
--- /dev/null
+++ b/libcef_dll/ctocpp/download_image_callback_ctocpp.cc
@@ -0,0 +1,73 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=c6c7ffb21714d5d9beee716a1cce07e1b91525c5$
+//
+
+#include "libcef_dll/ctocpp/download_image_callback_ctocpp.h"
+#include "libcef_dll/cpptoc/image_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+void CefDownloadImageCallbackCToCpp::OnDownloadImageFinished(
+ const CefString& image_url,
+ int http_status_code,
+ CefRefPtr<CefImage> image) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_download_image_callback_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_download_image_finished)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: image_url; type: string_byref_const
+ DCHECK(!image_url.empty());
+ if (image_url.empty()) {
+ return;
+ }
+ // Unverified params: image
+
+ // Execute
+ _struct->on_download_image_finished(_struct, image_url.GetStruct(),
+ http_status_code,
+ CefImageCppToC::Wrap(image));
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefDownloadImageCallbackCToCpp::CefDownloadImageCallbackCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefDownloadImageCallbackCToCpp::~CefDownloadImageCallbackCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_download_image_callback_t* CefCToCppRefCounted<
+ CefDownloadImageCallbackCToCpp,
+ CefDownloadImageCallback,
+ cef_download_image_callback_t>::UnwrapDerived(CefWrapperType type,
+ CefDownloadImageCallback* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCToCppRefCounted<CefDownloadImageCallbackCToCpp,
+ CefDownloadImageCallback,
+ cef_download_image_callback_t>::kWrapperType =
+ WT_DOWNLOAD_IMAGE_CALLBACK;
diff --git a/libcef_dll/ctocpp/download_image_callback_ctocpp.h b/libcef_dll/ctocpp/download_image_callback_ctocpp.h
new file mode 100644
index 00000000..5c7b7ccb
--- /dev/null
+++ b/libcef_dll/ctocpp/download_image_callback_ctocpp.h
@@ -0,0 +1,45 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=c281c09951a9b4f85556d0a9008b2524326254dd$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_DOWNLOAD_IMAGE_CALLBACK_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_DOWNLOAD_IMAGE_CALLBACK_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_browser_capi.h"
+#include "include/capi/cef_client_capi.h"
+#include "include/cef_browser.h"
+#include "include/cef_client.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefDownloadImageCallbackCToCpp
+ : public CefCToCppRefCounted<CefDownloadImageCallbackCToCpp,
+ CefDownloadImageCallback,
+ cef_download_image_callback_t> {
+ public:
+ CefDownloadImageCallbackCToCpp();
+ virtual ~CefDownloadImageCallbackCToCpp();
+
+ // CefDownloadImageCallback methods.
+ void OnDownloadImageFinished(const CefString& image_url,
+ int http_status_code,
+ CefRefPtr<CefImage> image) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_DOWNLOAD_IMAGE_CALLBACK_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/download_item_callback_ctocpp.cc b/libcef_dll/ctocpp/download_item_callback_ctocpp.cc
new file mode 100644
index 00000000..f306fbb5
--- /dev/null
+++ b/libcef_dll/ctocpp/download_item_callback_ctocpp.cc
@@ -0,0 +1,86 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=464ef9eb17442065860808d28cd96a5736ac118c$
+//
+
+#include "libcef_dll/ctocpp/download_item_callback_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") void CefDownloadItemCallbackCToCpp::Cancel() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_download_item_callback_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, cancel)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->cancel(_struct);
+}
+
+NO_SANITIZE("cfi-icall") void CefDownloadItemCallbackCToCpp::Pause() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_download_item_callback_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, pause)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->pause(_struct);
+}
+
+NO_SANITIZE("cfi-icall") void CefDownloadItemCallbackCToCpp::Resume() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_download_item_callback_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, resume)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->resume(_struct);
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefDownloadItemCallbackCToCpp::CefDownloadItemCallbackCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefDownloadItemCallbackCToCpp::~CefDownloadItemCallbackCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_download_item_callback_t* CefCToCppRefCounted<
+ CefDownloadItemCallbackCToCpp,
+ CefDownloadItemCallback,
+ cef_download_item_callback_t>::UnwrapDerived(CefWrapperType type,
+ CefDownloadItemCallback* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefDownloadItemCallbackCToCpp,
+ CefDownloadItemCallback,
+ cef_download_item_callback_t>::kWrapperType =
+ WT_DOWNLOAD_ITEM_CALLBACK;
diff --git a/libcef_dll/ctocpp/download_item_callback_ctocpp.h b/libcef_dll/ctocpp/download_item_callback_ctocpp.h
new file mode 100644
index 00000000..0f52a412
--- /dev/null
+++ b/libcef_dll/ctocpp/download_item_callback_ctocpp.h
@@ -0,0 +1,43 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=013ef6edbf734cdf4e6d00ba5b8be6c46284e2ca$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_DOWNLOAD_ITEM_CALLBACK_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_DOWNLOAD_ITEM_CALLBACK_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_download_handler_capi.h"
+#include "include/cef_download_handler.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefDownloadItemCallbackCToCpp
+ : public CefCToCppRefCounted<CefDownloadItemCallbackCToCpp,
+ CefDownloadItemCallback,
+ cef_download_item_callback_t> {
+ public:
+ CefDownloadItemCallbackCToCpp();
+ virtual ~CefDownloadItemCallbackCToCpp();
+
+ // CefDownloadItemCallback methods.
+ void Cancel() override;
+ void Pause() override;
+ void Resume() override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_DOWNLOAD_ITEM_CALLBACK_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/download_item_ctocpp.cc b/libcef_dll/ctocpp/download_item_ctocpp.cc
new file mode 100644
index 00000000..752c5aac
--- /dev/null
+++ b/libcef_dll/ctocpp/download_item_ctocpp.cc
@@ -0,0 +1,347 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=4ce3ee0a560c692db5902828ffd856ac1a3f4b19$
+//
+
+#include "libcef_dll/ctocpp/download_item_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") bool CefDownloadItemCToCpp::IsValid() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_download_item_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_valid)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_valid(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefDownloadItemCToCpp::IsInProgress() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_download_item_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_in_progress)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_in_progress(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefDownloadItemCToCpp::IsComplete() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_download_item_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_complete)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_complete(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefDownloadItemCToCpp::IsCanceled() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_download_item_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_canceled)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_canceled(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") int64 CefDownloadItemCToCpp::GetCurrentSpeed() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_download_item_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_current_speed)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int64 _retval = _struct->get_current_speed(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") int CefDownloadItemCToCpp::GetPercentComplete() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_download_item_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_percent_complete)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_percent_complete(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") int64 CefDownloadItemCToCpp::GetTotalBytes() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_download_item_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_total_bytes)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int64 _retval = _struct->get_total_bytes(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") int64 CefDownloadItemCToCpp::GetReceivedBytes() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_download_item_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_received_bytes)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int64 _retval = _struct->get_received_bytes(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") CefBaseTime CefDownloadItemCToCpp::GetStartTime() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_download_item_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_start_time)) {
+ return CefBaseTime();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_basetime_t _retval = _struct->get_start_time(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") CefBaseTime CefDownloadItemCToCpp::GetEndTime() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_download_item_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_end_time)) {
+ return CefBaseTime();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_basetime_t _retval = _struct->get_end_time(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") CefString CefDownloadItemCToCpp::GetFullPath() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_download_item_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_full_path)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_full_path(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") uint32 CefDownloadItemCToCpp::GetId() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_download_item_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_id)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ uint32 _retval = _struct->get_id(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") CefString CefDownloadItemCToCpp::GetURL() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_download_item_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_url)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_url(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") CefString CefDownloadItemCToCpp::GetOriginalUrl() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_download_item_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_original_url)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_original_url(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+CefString CefDownloadItemCToCpp::GetSuggestedFileName() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_download_item_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_suggested_file_name)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_suggested_file_name(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+CefString CefDownloadItemCToCpp::GetContentDisposition() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_download_item_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_content_disposition)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_content_disposition(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") CefString CefDownloadItemCToCpp::GetMimeType() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_download_item_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_mime_type)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_mime_type(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefDownloadItemCToCpp::CefDownloadItemCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefDownloadItemCToCpp::~CefDownloadItemCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_download_item_t*
+CefCToCppRefCounted<CefDownloadItemCToCpp,
+ CefDownloadItem,
+ cef_download_item_t>::UnwrapDerived(CefWrapperType type,
+ CefDownloadItem* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefDownloadItemCToCpp,
+ CefDownloadItem,
+ cef_download_item_t>::kWrapperType =
+ WT_DOWNLOAD_ITEM;
diff --git a/libcef_dll/ctocpp/download_item_ctocpp.h b/libcef_dll/ctocpp/download_item_ctocpp.h
new file mode 100644
index 00000000..8c93039e
--- /dev/null
+++ b/libcef_dll/ctocpp/download_item_ctocpp.h
@@ -0,0 +1,56 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=d0295aa7dbc39993e62486a20a1ef8123d0648b2$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_DOWNLOAD_ITEM_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_DOWNLOAD_ITEM_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_download_item_capi.h"
+#include "include/cef_download_item.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefDownloadItemCToCpp : public CefCToCppRefCounted<CefDownloadItemCToCpp,
+ CefDownloadItem,
+ cef_download_item_t> {
+ public:
+ CefDownloadItemCToCpp();
+ virtual ~CefDownloadItemCToCpp();
+
+ // CefDownloadItem methods.
+ bool IsValid() override;
+ bool IsInProgress() override;
+ bool IsComplete() override;
+ bool IsCanceled() override;
+ int64 GetCurrentSpeed() override;
+ int GetPercentComplete() override;
+ int64 GetTotalBytes() override;
+ int64 GetReceivedBytes() override;
+ CefBaseTime GetStartTime() override;
+ CefBaseTime GetEndTime() override;
+ CefString GetFullPath() override;
+ uint32 GetId() override;
+ CefString GetURL() override;
+ CefString GetOriginalUrl() override;
+ CefString GetSuggestedFileName() override;
+ CefString GetContentDisposition() override;
+ CefString GetMimeType() override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_DOWNLOAD_ITEM_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/drag_data_ctocpp.cc b/libcef_dll/ctocpp/drag_data_ctocpp.cc
new file mode 100644
index 00000000..7d7b4aad
--- /dev/null
+++ b/libcef_dll/ctocpp/drag_data_ctocpp.cc
@@ -0,0 +1,534 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=c4cce4949cab252b568fc4dd34755b0b0908636b$
+//
+
+#include "libcef_dll/ctocpp/drag_data_ctocpp.h"
+#include "libcef_dll/ctocpp/image_ctocpp.h"
+#include "libcef_dll/ctocpp/stream_writer_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+#include "libcef_dll/transfer_util.h"
+
+// STATIC METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefDragData> CefDragData::Create() {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_drag_data_t* _retval = cef_drag_data_create();
+
+ // Return type: refptr_same
+ return CefDragDataCToCpp::Wrap(_retval);
+}
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefDragData> CefDragDataCToCpp::Clone() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_drag_data_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, clone)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_drag_data_t* _retval = _struct->clone(_struct);
+
+ // Return type: refptr_same
+ return CefDragDataCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") bool CefDragDataCToCpp::IsReadOnly() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_drag_data_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_read_only)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_read_only(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefDragDataCToCpp::IsLink() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_drag_data_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_link)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_link(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefDragDataCToCpp::IsFragment() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_drag_data_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_fragment)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_fragment(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefDragDataCToCpp::IsFile() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_drag_data_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_file)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_file(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") CefString CefDragDataCToCpp::GetLinkURL() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_drag_data_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_link_url)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_link_url(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") CefString CefDragDataCToCpp::GetLinkTitle() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_drag_data_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_link_title)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_link_title(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") CefString CefDragDataCToCpp::GetLinkMetadata() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_drag_data_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_link_metadata)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_link_metadata(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") CefString CefDragDataCToCpp::GetFragmentText() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_drag_data_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_fragment_text)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_fragment_text(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") CefString CefDragDataCToCpp::GetFragmentHtml() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_drag_data_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_fragment_html)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_fragment_html(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") CefString CefDragDataCToCpp::GetFragmentBaseURL() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_drag_data_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_fragment_base_url)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_fragment_base_url(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") CefString CefDragDataCToCpp::GetFileName() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_drag_data_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_file_name)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_file_name(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+size_t CefDragDataCToCpp::GetFileContents(CefRefPtr<CefStreamWriter> writer) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_drag_data_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_file_contents)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: writer
+
+ // Execute
+ size_t _retval = _struct->get_file_contents(
+ _struct, CefStreamWriterCToCpp::Unwrap(writer));
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefDragDataCToCpp::GetFileNames(std::vector<CefString>& names) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_drag_data_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_file_names)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Translate param: names; type: string_vec_byref
+ cef_string_list_t namesList = cef_string_list_alloc();
+ DCHECK(namesList);
+ if (namesList) {
+ transfer_string_list_contents(names, namesList);
+ }
+
+ // Execute
+ int _retval = _struct->get_file_names(_struct, namesList);
+
+ // Restore param:names; type: string_vec_byref
+ if (namesList) {
+ names.clear();
+ transfer_string_list_contents(namesList, names);
+ cef_string_list_free(namesList);
+ }
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefDragDataCToCpp::SetLinkURL(const CefString& url) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_drag_data_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_link_url)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: url
+
+ // Execute
+ _struct->set_link_url(_struct, url.GetStruct());
+}
+
+NO_SANITIZE("cfi-icall")
+void CefDragDataCToCpp::SetLinkTitle(const CefString& title) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_drag_data_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_link_title)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: title
+
+ // Execute
+ _struct->set_link_title(_struct, title.GetStruct());
+}
+
+NO_SANITIZE("cfi-icall")
+void CefDragDataCToCpp::SetLinkMetadata(const CefString& data) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_drag_data_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_link_metadata)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: data
+
+ // Execute
+ _struct->set_link_metadata(_struct, data.GetStruct());
+}
+
+NO_SANITIZE("cfi-icall")
+void CefDragDataCToCpp::SetFragmentText(const CefString& text) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_drag_data_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_fragment_text)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: text
+
+ // Execute
+ _struct->set_fragment_text(_struct, text.GetStruct());
+}
+
+NO_SANITIZE("cfi-icall")
+void CefDragDataCToCpp::SetFragmentHtml(const CefString& html) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_drag_data_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_fragment_html)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: html
+
+ // Execute
+ _struct->set_fragment_html(_struct, html.GetStruct());
+}
+
+NO_SANITIZE("cfi-icall")
+void CefDragDataCToCpp::SetFragmentBaseURL(const CefString& base_url) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_drag_data_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_fragment_base_url)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: base_url
+
+ // Execute
+ _struct->set_fragment_base_url(_struct, base_url.GetStruct());
+}
+
+NO_SANITIZE("cfi-icall") void CefDragDataCToCpp::ResetFileContents() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_drag_data_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, reset_file_contents)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->reset_file_contents(_struct);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefDragDataCToCpp::AddFile(const CefString& path,
+ const CefString& display_name) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_drag_data_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, add_file)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: path; type: string_byref_const
+ DCHECK(!path.empty());
+ if (path.empty()) {
+ return;
+ }
+ // Unverified params: display_name
+
+ // Execute
+ _struct->add_file(_struct, path.GetStruct(), display_name.GetStruct());
+}
+
+NO_SANITIZE("cfi-icall") void CefDragDataCToCpp::ClearFilenames() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_drag_data_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, clear_filenames)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->clear_filenames(_struct);
+}
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefImage> CefDragDataCToCpp::GetImage() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_drag_data_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_image)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_image_t* _retval = _struct->get_image(_struct);
+
+ // Return type: refptr_same
+ return CefImageCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") CefPoint CefDragDataCToCpp::GetImageHotspot() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_drag_data_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_image_hotspot)) {
+ return CefPoint();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_point_t _retval = _struct->get_image_hotspot(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") bool CefDragDataCToCpp::HasImage() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_drag_data_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, has_image)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->has_image(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefDragDataCToCpp::CefDragDataCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefDragDataCToCpp::~CefDragDataCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_drag_data_t*
+CefCToCppRefCounted<CefDragDataCToCpp, CefDragData, cef_drag_data_t>::
+ UnwrapDerived(CefWrapperType type, CefDragData* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefDragDataCToCpp,
+ CefDragData,
+ cef_drag_data_t>::kWrapperType =
+ WT_DRAG_DATA;
diff --git a/libcef_dll/ctocpp/drag_data_ctocpp.h b/libcef_dll/ctocpp/drag_data_ctocpp.h
new file mode 100644
index 00000000..b9a79bd3
--- /dev/null
+++ b/libcef_dll/ctocpp/drag_data_ctocpp.h
@@ -0,0 +1,66 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=7a8ec7b7c1010725596b1a64eb325b0e75ea34b7$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_DRAG_DATA_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_DRAG_DATA_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include <vector>
+#include "include/capi/cef_drag_data_capi.h"
+#include "include/cef_drag_data.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefDragDataCToCpp : public CefCToCppRefCounted<CefDragDataCToCpp,
+ CefDragData,
+ cef_drag_data_t> {
+ public:
+ CefDragDataCToCpp();
+ virtual ~CefDragDataCToCpp();
+
+ // CefDragData methods.
+ CefRefPtr<CefDragData> Clone() override;
+ bool IsReadOnly() override;
+ bool IsLink() override;
+ bool IsFragment() override;
+ bool IsFile() override;
+ CefString GetLinkURL() override;
+ CefString GetLinkTitle() override;
+ CefString GetLinkMetadata() override;
+ CefString GetFragmentText() override;
+ CefString GetFragmentHtml() override;
+ CefString GetFragmentBaseURL() override;
+ CefString GetFileName() override;
+ size_t GetFileContents(CefRefPtr<CefStreamWriter> writer) override;
+ bool GetFileNames(std::vector<CefString>& names) override;
+ void SetLinkURL(const CefString& url) override;
+ void SetLinkTitle(const CefString& title) override;
+ void SetLinkMetadata(const CefString& data) override;
+ void SetFragmentText(const CefString& text) override;
+ void SetFragmentHtml(const CefString& html) override;
+ void SetFragmentBaseURL(const CefString& base_url) override;
+ void ResetFileContents() override;
+ void AddFile(const CefString& path, const CefString& display_name) override;
+ void ClearFilenames() override;
+ CefRefPtr<CefImage> GetImage() override;
+ CefPoint GetImageHotspot() override;
+ bool HasImage() override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_DRAG_DATA_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/drag_handler_ctocpp.cc b/libcef_dll/ctocpp/drag_handler_ctocpp.cc
new file mode 100644
index 00000000..9da254c1
--- /dev/null
+++ b/libcef_dll/ctocpp/drag_handler_ctocpp.cc
@@ -0,0 +1,126 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=5675b51fb9ff6ac85f60c3696b9f4155421d5ef3$
+//
+
+#include "libcef_dll/ctocpp/drag_handler_ctocpp.h"
+#include "libcef_dll/cpptoc/browser_cpptoc.h"
+#include "libcef_dll/cpptoc/drag_data_cpptoc.h"
+#include "libcef_dll/cpptoc/frame_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+bool CefDragHandlerCToCpp::OnDragEnter(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefDragData> dragData,
+ DragOperationsMask mask) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_drag_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_drag_enter)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return false;
+ }
+ // Verify param: dragData; type: refptr_diff
+ DCHECK(dragData.get());
+ if (!dragData.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->on_drag_enter(_struct, CefBrowserCppToC::Wrap(browser),
+ CefDragDataCppToC::Wrap(dragData), mask);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefDragHandlerCToCpp::OnDraggableRegionsChanged(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const std::vector<CefDraggableRegion>& regions) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_drag_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_draggable_regions_changed)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+ // Verify param: frame; type: refptr_diff
+ DCHECK(frame.get());
+ if (!frame.get()) {
+ return;
+ }
+
+ // Translate param: regions; type: simple_vec_byref_const
+ const size_t regionsCount = regions.size();
+ cef_draggable_region_t* regionsList = NULL;
+ if (regionsCount > 0) {
+ regionsList = new cef_draggable_region_t[regionsCount];
+ DCHECK(regionsList);
+ if (regionsList) {
+ for (size_t i = 0; i < regionsCount; ++i) {
+ regionsList[i] = regions[i];
+ }
+ }
+ }
+
+ // Execute
+ _struct->on_draggable_regions_changed(
+ _struct, CefBrowserCppToC::Wrap(browser), CefFrameCppToC::Wrap(frame),
+ regionsCount, regionsList);
+
+ // Restore param:regions; type: simple_vec_byref_const
+ if (regionsList) {
+ delete[] regionsList;
+ }
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefDragHandlerCToCpp::CefDragHandlerCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefDragHandlerCToCpp::~CefDragHandlerCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_drag_handler_t*
+CefCToCppRefCounted<CefDragHandlerCToCpp, CefDragHandler, cef_drag_handler_t>::
+ UnwrapDerived(CefWrapperType type, CefDragHandler* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefDragHandlerCToCpp,
+ CefDragHandler,
+ cef_drag_handler_t>::kWrapperType =
+ WT_DRAG_HANDLER;
diff --git a/libcef_dll/ctocpp/drag_handler_ctocpp.h b/libcef_dll/ctocpp/drag_handler_ctocpp.h
new file mode 100644
index 00000000..153cf498
--- /dev/null
+++ b/libcef_dll/ctocpp/drag_handler_ctocpp.h
@@ -0,0 +1,47 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=a8523e82439b30828b0774d2eff240ea215b96d6$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_DRAG_HANDLER_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_DRAG_HANDLER_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include <vector>
+#include "include/capi/cef_drag_handler_capi.h"
+#include "include/cef_drag_handler.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefDragHandlerCToCpp : public CefCToCppRefCounted<CefDragHandlerCToCpp,
+ CefDragHandler,
+ cef_drag_handler_t> {
+ public:
+ CefDragHandlerCToCpp();
+ virtual ~CefDragHandlerCToCpp();
+
+ // CefDragHandler methods.
+ bool OnDragEnter(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefDragData> dragData,
+ DragOperationsMask mask) override;
+ void OnDraggableRegionsChanged(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const std::vector<CefDraggableRegion>& regions) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_DRAG_HANDLER_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/end_tracing_callback_ctocpp.cc b/libcef_dll/ctocpp/end_tracing_callback_ctocpp.cc
new file mode 100644
index 00000000..4a0d8fea
--- /dev/null
+++ b/libcef_dll/ctocpp/end_tracing_callback_ctocpp.cc
@@ -0,0 +1,66 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=d62144c01e5efa6355c635ada089496a0fef4ec5$
+//
+
+#include "libcef_dll/ctocpp/end_tracing_callback_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+void CefEndTracingCallbackCToCpp::OnEndTracingComplete(
+ const CefString& tracing_file) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_end_tracing_callback_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_end_tracing_complete)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: tracing_file; type: string_byref_const
+ DCHECK(!tracing_file.empty());
+ if (tracing_file.empty()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_end_tracing_complete(_struct, tracing_file.GetStruct());
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefEndTracingCallbackCToCpp::CefEndTracingCallbackCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefEndTracingCallbackCToCpp::~CefEndTracingCallbackCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_end_tracing_callback_t* CefCToCppRefCounted<
+ CefEndTracingCallbackCToCpp,
+ CefEndTracingCallback,
+ cef_end_tracing_callback_t>::UnwrapDerived(CefWrapperType type,
+ CefEndTracingCallback* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefEndTracingCallbackCToCpp,
+ CefEndTracingCallback,
+ cef_end_tracing_callback_t>::kWrapperType =
+ WT_END_TRACING_CALLBACK;
diff --git a/libcef_dll/ctocpp/end_tracing_callback_ctocpp.h b/libcef_dll/ctocpp/end_tracing_callback_ctocpp.h
new file mode 100644
index 00000000..c915803e
--- /dev/null
+++ b/libcef_dll/ctocpp/end_tracing_callback_ctocpp.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=d798b3255a8ad2aea9d4afbe3492eaad538d8d0a$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_END_TRACING_CALLBACK_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_END_TRACING_CALLBACK_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_trace_capi.h"
+#include "include/cef_trace.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefEndTracingCallbackCToCpp
+ : public CefCToCppRefCounted<CefEndTracingCallbackCToCpp,
+ CefEndTracingCallback,
+ cef_end_tracing_callback_t> {
+ public:
+ CefEndTracingCallbackCToCpp();
+ virtual ~CefEndTracingCallbackCToCpp();
+
+ // CefEndTracingCallback methods.
+ void OnEndTracingComplete(const CefString& tracing_file) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_END_TRACING_CALLBACK_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/extension_ctocpp.cc b/libcef_dll/ctocpp/extension_ctocpp.cc
new file mode 100644
index 00000000..001c939c
--- /dev/null
+++ b/libcef_dll/ctocpp/extension_ctocpp.cc
@@ -0,0 +1,192 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=93f4af6f3591fb4bd50275d518b176b890b7d901$
+//
+
+#include "libcef_dll/ctocpp/extension_ctocpp.h"
+#include "libcef_dll/cpptoc/extension_handler_cpptoc.h"
+#include "libcef_dll/ctocpp/dictionary_value_ctocpp.h"
+#include "libcef_dll/ctocpp/request_context_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") CefString CefExtensionCToCpp::GetIdentifier() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_extension_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_identifier)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_identifier(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") CefString CefExtensionCToCpp::GetPath() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_extension_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_path)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_path(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefDictionaryValue> CefExtensionCToCpp::GetManifest() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_extension_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_manifest)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_dictionary_value_t* _retval = _struct->get_manifest(_struct);
+
+ // Return type: refptr_same
+ return CefDictionaryValueCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefExtensionCToCpp::IsSame(CefRefPtr<CefExtension> that) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_extension_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_same)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: that; type: refptr_same
+ DCHECK(that.get());
+ if (!that.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->is_same(_struct, CefExtensionCToCpp::Unwrap(that));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefExtensionHandler> CefExtensionCToCpp::GetHandler() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_extension_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_handler)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_extension_handler_t* _retval = _struct->get_handler(_struct);
+
+ // Return type: refptr_diff
+ return CefExtensionHandlerCppToC::Unwrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefRequestContext> CefExtensionCToCpp::GetLoaderContext() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_extension_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_loader_context)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_request_context_t* _retval = _struct->get_loader_context(_struct);
+
+ // Return type: refptr_same
+ return CefRequestContextCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") bool CefExtensionCToCpp::IsLoaded() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_extension_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_loaded)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_loaded(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") void CefExtensionCToCpp::Unload() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_extension_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, unload)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->unload(_struct);
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefExtensionCToCpp::CefExtensionCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefExtensionCToCpp::~CefExtensionCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_extension_t*
+CefCToCppRefCounted<CefExtensionCToCpp, CefExtension, cef_extension_t>::
+ UnwrapDerived(CefWrapperType type, CefExtension* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefExtensionCToCpp,
+ CefExtension,
+ cef_extension_t>::kWrapperType =
+ WT_EXTENSION;
diff --git a/libcef_dll/ctocpp/extension_ctocpp.h b/libcef_dll/ctocpp/extension_ctocpp.h
new file mode 100644
index 00000000..b1868108
--- /dev/null
+++ b/libcef_dll/ctocpp/extension_ctocpp.h
@@ -0,0 +1,51 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=07a08b9dd260059e77dfb433f43686cbc5569bea$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_EXTENSION_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_EXTENSION_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_extension_capi.h"
+#include "include/capi/cef_extension_handler_capi.h"
+#include "include/capi/cef_request_context_capi.h"
+#include "include/cef_extension.h"
+#include "include/cef_extension_handler.h"
+#include "include/cef_request_context.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefExtensionCToCpp : public CefCToCppRefCounted<CefExtensionCToCpp,
+ CefExtension,
+ cef_extension_t> {
+ public:
+ CefExtensionCToCpp();
+ virtual ~CefExtensionCToCpp();
+
+ // CefExtension methods.
+ CefString GetIdentifier() override;
+ CefString GetPath() override;
+ CefRefPtr<CefDictionaryValue> GetManifest() override;
+ bool IsSame(CefRefPtr<CefExtension> that) override;
+ CefRefPtr<CefExtensionHandler> GetHandler() override;
+ CefRefPtr<CefRequestContext> GetLoaderContext() override;
+ bool IsLoaded() override;
+ void Unload() override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_EXTENSION_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/extension_handler_ctocpp.cc b/libcef_dll/ctocpp/extension_handler_ctocpp.cc
new file mode 100644
index 00000000..527da887
--- /dev/null
+++ b/libcef_dll/ctocpp/extension_handler_ctocpp.cc
@@ -0,0 +1,346 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=aefea006b8e7eaaa44359ef0a29d8dc181b2ae8d$
+//
+
+#include "libcef_dll/ctocpp/extension_handler_ctocpp.h"
+#include "libcef_dll/cpptoc/browser_cpptoc.h"
+#include "libcef_dll/cpptoc/extension_cpptoc.h"
+#include "libcef_dll/cpptoc/get_extension_resource_callback_cpptoc.h"
+#include "libcef_dll/ctocpp/client_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+void CefExtensionHandlerCToCpp::OnExtensionLoadFailed(cef_errorcode_t result) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_extension_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_extension_load_failed)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->on_extension_load_failed(_struct, result);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefExtensionHandlerCToCpp::OnExtensionLoaded(
+ CefRefPtr<CefExtension> extension) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_extension_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_extension_loaded)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: extension; type: refptr_diff
+ DCHECK(extension.get());
+ if (!extension.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_extension_loaded(_struct, CefExtensionCppToC::Wrap(extension));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefExtensionHandlerCToCpp::OnExtensionUnloaded(
+ CefRefPtr<CefExtension> extension) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_extension_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_extension_unloaded)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: extension; type: refptr_diff
+ DCHECK(extension.get());
+ if (!extension.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_extension_unloaded(_struct, CefExtensionCppToC::Wrap(extension));
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefExtensionHandlerCToCpp::OnBeforeBackgroundBrowser(
+ CefRefPtr<CefExtension> extension,
+ const CefString& url,
+ CefRefPtr<CefClient>& client,
+ CefBrowserSettings& settings) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_extension_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_before_background_browser)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: extension; type: refptr_diff
+ DCHECK(extension.get());
+ if (!extension.get()) {
+ return false;
+ }
+ // Verify param: url; type: string_byref_const
+ DCHECK(!url.empty());
+ if (url.empty()) {
+ return false;
+ }
+
+ // Translate param: client; type: refptr_same_byref
+ cef_client_t* clientStruct = NULL;
+ if (client.get()) {
+ clientStruct = CefClientCToCpp::Unwrap(client);
+ }
+ cef_client_t* clientOrig = clientStruct;
+
+ // Execute
+ int _retval = _struct->on_before_background_browser(
+ _struct, CefExtensionCppToC::Wrap(extension), url.GetStruct(),
+ &clientStruct, &settings);
+
+ // Restore param:client; type: refptr_same_byref
+ if (clientStruct) {
+ if (clientStruct != clientOrig) {
+ client = CefClientCToCpp::Wrap(clientStruct);
+ }
+ } else {
+ client = nullptr;
+ }
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefExtensionHandlerCToCpp::OnBeforeBrowser(
+ CefRefPtr<CefExtension> extension,
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefBrowser> active_browser,
+ int index,
+ const CefString& url,
+ bool active,
+ CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient>& client,
+ CefBrowserSettings& settings) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_extension_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_before_browser)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: extension; type: refptr_diff
+ DCHECK(extension.get());
+ if (!extension.get()) {
+ return false;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return false;
+ }
+ // Verify param: active_browser; type: refptr_diff
+ DCHECK(active_browser.get());
+ if (!active_browser.get()) {
+ return false;
+ }
+ // Verify param: url; type: string_byref_const
+ DCHECK(!url.empty());
+ if (url.empty()) {
+ return false;
+ }
+
+ // Translate param: client; type: refptr_same_byref
+ cef_client_t* clientStruct = NULL;
+ if (client.get()) {
+ clientStruct = CefClientCToCpp::Unwrap(client);
+ }
+ cef_client_t* clientOrig = clientStruct;
+
+ // Execute
+ int _retval = _struct->on_before_browser(
+ _struct, CefExtensionCppToC::Wrap(extension),
+ CefBrowserCppToC::Wrap(browser), CefBrowserCppToC::Wrap(active_browser),
+ index, url.GetStruct(), active, &windowInfo, &clientStruct, &settings);
+
+ // Restore param:client; type: refptr_same_byref
+ if (clientStruct) {
+ if (clientStruct != clientOrig) {
+ client = CefClientCToCpp::Wrap(clientStruct);
+ }
+ } else {
+ client = nullptr;
+ }
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefBrowser> CefExtensionHandlerCToCpp::GetActiveBrowser(
+ CefRefPtr<CefExtension> extension,
+ CefRefPtr<CefBrowser> browser,
+ bool include_incognito) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_extension_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_active_browser)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: extension; type: refptr_diff
+ DCHECK(extension.get());
+ if (!extension.get()) {
+ return nullptr;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return nullptr;
+ }
+
+ // Execute
+ cef_browser_t* _retval = _struct->get_active_browser(
+ _struct, CefExtensionCppToC::Wrap(extension),
+ CefBrowserCppToC::Wrap(browser), include_incognito);
+
+ // Return type: refptr_diff
+ return CefBrowserCppToC::Unwrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefExtensionHandlerCToCpp::CanAccessBrowser(
+ CefRefPtr<CefExtension> extension,
+ CefRefPtr<CefBrowser> browser,
+ bool include_incognito,
+ CefRefPtr<CefBrowser> target_browser) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_extension_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, can_access_browser)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: extension; type: refptr_diff
+ DCHECK(extension.get());
+ if (!extension.get()) {
+ return false;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return false;
+ }
+ // Verify param: target_browser; type: refptr_diff
+ DCHECK(target_browser.get());
+ if (!target_browser.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->can_access_browser(
+ _struct, CefExtensionCppToC::Wrap(extension),
+ CefBrowserCppToC::Wrap(browser), include_incognito,
+ CefBrowserCppToC::Wrap(target_browser));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefExtensionHandlerCToCpp::GetExtensionResource(
+ CefRefPtr<CefExtension> extension,
+ CefRefPtr<CefBrowser> browser,
+ const CefString& file,
+ CefRefPtr<CefGetExtensionResourceCallback> callback) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_extension_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_extension_resource)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: extension; type: refptr_diff
+ DCHECK(extension.get());
+ if (!extension.get()) {
+ return false;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return false;
+ }
+ // Verify param: file; type: string_byref_const
+ DCHECK(!file.empty());
+ if (file.empty()) {
+ return false;
+ }
+ // Verify param: callback; type: refptr_diff
+ DCHECK(callback.get());
+ if (!callback.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->get_extension_resource(
+ _struct, CefExtensionCppToC::Wrap(extension),
+ CefBrowserCppToC::Wrap(browser), file.GetStruct(),
+ CefGetExtensionResourceCallbackCppToC::Wrap(callback));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefExtensionHandlerCToCpp::CefExtensionHandlerCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefExtensionHandlerCToCpp::~CefExtensionHandlerCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_extension_handler_t* CefCToCppRefCounted<
+ CefExtensionHandlerCToCpp,
+ CefExtensionHandler,
+ cef_extension_handler_t>::UnwrapDerived(CefWrapperType type,
+ CefExtensionHandler* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefExtensionHandlerCToCpp,
+ CefExtensionHandler,
+ cef_extension_handler_t>::kWrapperType =
+ WT_EXTENSION_HANDLER;
diff --git a/libcef_dll/ctocpp/extension_handler_ctocpp.h b/libcef_dll/ctocpp/extension_handler_ctocpp.h
new file mode 100644
index 00000000..eab84e7d
--- /dev/null
+++ b/libcef_dll/ctocpp/extension_handler_ctocpp.h
@@ -0,0 +1,70 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=5e432e7dd8e10b681b96bad3694ba2d0bf79fad6$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_EXTENSION_HANDLER_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_EXTENSION_HANDLER_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_client_capi.h"
+#include "include/capi/cef_extension_handler_capi.h"
+#include "include/cef_client.h"
+#include "include/cef_extension_handler.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefExtensionHandlerCToCpp
+ : public CefCToCppRefCounted<CefExtensionHandlerCToCpp,
+ CefExtensionHandler,
+ cef_extension_handler_t> {
+ public:
+ CefExtensionHandlerCToCpp();
+ virtual ~CefExtensionHandlerCToCpp();
+
+ // CefExtensionHandler methods.
+ void OnExtensionLoadFailed(cef_errorcode_t result) override;
+ void OnExtensionLoaded(CefRefPtr<CefExtension> extension) override;
+ void OnExtensionUnloaded(CefRefPtr<CefExtension> extension) override;
+ bool OnBeforeBackgroundBrowser(CefRefPtr<CefExtension> extension,
+ const CefString& url,
+ CefRefPtr<CefClient>& client,
+ CefBrowserSettings& settings) override;
+ bool OnBeforeBrowser(CefRefPtr<CefExtension> extension,
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefBrowser> active_browser,
+ int index,
+ const CefString& url,
+ bool active,
+ CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient>& client,
+ CefBrowserSettings& settings) override;
+ CefRefPtr<CefBrowser> GetActiveBrowser(CefRefPtr<CefExtension> extension,
+ CefRefPtr<CefBrowser> browser,
+ bool include_incognito) override;
+ bool CanAccessBrowser(CefRefPtr<CefExtension> extension,
+ CefRefPtr<CefBrowser> browser,
+ bool include_incognito,
+ CefRefPtr<CefBrowser> target_browser) override;
+ bool GetExtensionResource(
+ CefRefPtr<CefExtension> extension,
+ CefRefPtr<CefBrowser> browser,
+ const CefString& file,
+ CefRefPtr<CefGetExtensionResourceCallback> callback) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_EXTENSION_HANDLER_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/file_dialog_callback_ctocpp.cc b/libcef_dll/ctocpp/file_dialog_callback_ctocpp.cc
new file mode 100644
index 00000000..8fdd7637
--- /dev/null
+++ b/libcef_dll/ctocpp/file_dialog_callback_ctocpp.cc
@@ -0,0 +1,89 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=49a9c2dc0a50b5afa3de2fa4e78606597227f175$
+//
+
+#include "libcef_dll/ctocpp/file_dialog_callback_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+#include "libcef_dll/transfer_util.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+void CefFileDialogCallbackCToCpp::Continue(
+ const std::vector<CefString>& file_paths) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_file_dialog_callback_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, cont)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: file_paths
+
+ // Translate param: file_paths; type: string_vec_byref_const
+ cef_string_list_t file_pathsList = cef_string_list_alloc();
+ DCHECK(file_pathsList);
+ if (file_pathsList) {
+ transfer_string_list_contents(file_paths, file_pathsList);
+ }
+
+ // Execute
+ _struct->cont(_struct, file_pathsList);
+
+ // Restore param:file_paths; type: string_vec_byref_const
+ if (file_pathsList) {
+ cef_string_list_free(file_pathsList);
+ }
+}
+
+NO_SANITIZE("cfi-icall") void CefFileDialogCallbackCToCpp::Cancel() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_file_dialog_callback_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, cancel)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->cancel(_struct);
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefFileDialogCallbackCToCpp::CefFileDialogCallbackCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefFileDialogCallbackCToCpp::~CefFileDialogCallbackCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_file_dialog_callback_t* CefCToCppRefCounted<
+ CefFileDialogCallbackCToCpp,
+ CefFileDialogCallback,
+ cef_file_dialog_callback_t>::UnwrapDerived(CefWrapperType type,
+ CefFileDialogCallback* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefFileDialogCallbackCToCpp,
+ CefFileDialogCallback,
+ cef_file_dialog_callback_t>::kWrapperType =
+ WT_FILE_DIALOG_CALLBACK;
diff --git a/libcef_dll/ctocpp/file_dialog_callback_ctocpp.h b/libcef_dll/ctocpp/file_dialog_callback_ctocpp.h
new file mode 100644
index 00000000..266a8b7c
--- /dev/null
+++ b/libcef_dll/ctocpp/file_dialog_callback_ctocpp.h
@@ -0,0 +1,43 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=75544d28b1d0f0cdfc2f8cb1bd3f521cfe676bce$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_FILE_DIALOG_CALLBACK_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_FILE_DIALOG_CALLBACK_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include <vector>
+#include "include/capi/cef_dialog_handler_capi.h"
+#include "include/cef_dialog_handler.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefFileDialogCallbackCToCpp
+ : public CefCToCppRefCounted<CefFileDialogCallbackCToCpp,
+ CefFileDialogCallback,
+ cef_file_dialog_callback_t> {
+ public:
+ CefFileDialogCallbackCToCpp();
+ virtual ~CefFileDialogCallbackCToCpp();
+
+ // CefFileDialogCallback methods.
+ void Continue(const std::vector<CefString>& file_paths) override;
+ void Cancel() override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_FILE_DIALOG_CALLBACK_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/find_handler_ctocpp.cc b/libcef_dll/ctocpp/find_handler_ctocpp.cc
new file mode 100644
index 00000000..cc4cd2c9
--- /dev/null
+++ b/libcef_dll/ctocpp/find_handler_ctocpp.cc
@@ -0,0 +1,71 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=7436e1945600e337c6cbc3f25cc2d0d871515a0f$
+//
+
+#include "libcef_dll/ctocpp/find_handler_ctocpp.h"
+#include "libcef_dll/cpptoc/browser_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+void CefFindHandlerCToCpp::OnFindResult(CefRefPtr<CefBrowser> browser,
+ int identifier,
+ int count,
+ const CefRect& selectionRect,
+ int activeMatchOrdinal,
+ bool finalUpdate) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_find_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_find_result)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_find_result(_struct, CefBrowserCppToC::Wrap(browser), identifier,
+ count, &selectionRect, activeMatchOrdinal,
+ finalUpdate);
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefFindHandlerCToCpp::CefFindHandlerCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefFindHandlerCToCpp::~CefFindHandlerCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_find_handler_t*
+CefCToCppRefCounted<CefFindHandlerCToCpp, CefFindHandler, cef_find_handler_t>::
+ UnwrapDerived(CefWrapperType type, CefFindHandler* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefFindHandlerCToCpp,
+ CefFindHandler,
+ cef_find_handler_t>::kWrapperType =
+ WT_FIND_HANDLER;
diff --git a/libcef_dll/ctocpp/find_handler_ctocpp.h b/libcef_dll/ctocpp/find_handler_ctocpp.h
new file mode 100644
index 00000000..98f75b2d
--- /dev/null
+++ b/libcef_dll/ctocpp/find_handler_ctocpp.h
@@ -0,0 +1,45 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=8b86bd425ab5e9283d8fc8ac96b54740bf495cbb$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_FIND_HANDLER_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_FIND_HANDLER_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_find_handler_capi.h"
+#include "include/cef_find_handler.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefFindHandlerCToCpp : public CefCToCppRefCounted<CefFindHandlerCToCpp,
+ CefFindHandler,
+ cef_find_handler_t> {
+ public:
+ CefFindHandlerCToCpp();
+ virtual ~CefFindHandlerCToCpp();
+
+ // CefFindHandler methods.
+ void OnFindResult(CefRefPtr<CefBrowser> browser,
+ int identifier,
+ int count,
+ const CefRect& selectionRect,
+ int activeMatchOrdinal,
+ bool finalUpdate) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_FIND_HANDLER_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/focus_handler_ctocpp.cc b/libcef_dll/ctocpp/focus_handler_ctocpp.cc
new file mode 100644
index 00000000..00261d6d
--- /dev/null
+++ b/libcef_dll/ctocpp/focus_handler_ctocpp.cc
@@ -0,0 +1,114 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=84b98dacc31cb8f0ba37eb08757fda14267a2407$
+//
+
+#include "libcef_dll/ctocpp/focus_handler_ctocpp.h"
+#include "libcef_dll/cpptoc/browser_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+void CefFocusHandlerCToCpp::OnTakeFocus(CefRefPtr<CefBrowser> browser,
+ bool next) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_focus_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_take_focus)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_take_focus(_struct, CefBrowserCppToC::Wrap(browser), next);
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefFocusHandlerCToCpp::OnSetFocus(CefRefPtr<CefBrowser> browser,
+ FocusSource source) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_focus_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_set_focus)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval =
+ _struct->on_set_focus(_struct, CefBrowserCppToC::Wrap(browser), source);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefFocusHandlerCToCpp::OnGotFocus(CefRefPtr<CefBrowser> browser) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_focus_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_got_focus)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_got_focus(_struct, CefBrowserCppToC::Wrap(browser));
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefFocusHandlerCToCpp::CefFocusHandlerCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefFocusHandlerCToCpp::~CefFocusHandlerCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_focus_handler_t*
+CefCToCppRefCounted<CefFocusHandlerCToCpp,
+ CefFocusHandler,
+ cef_focus_handler_t>::UnwrapDerived(CefWrapperType type,
+ CefFocusHandler* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefFocusHandlerCToCpp,
+ CefFocusHandler,
+ cef_focus_handler_t>::kWrapperType =
+ WT_FOCUS_HANDLER;
diff --git a/libcef_dll/ctocpp/focus_handler_ctocpp.h b/libcef_dll/ctocpp/focus_handler_ctocpp.h
new file mode 100644
index 00000000..6c0f9220
--- /dev/null
+++ b/libcef_dll/ctocpp/focus_handler_ctocpp.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=6a454cd9846e772380a72c5429d114f73cc3c1f5$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_FOCUS_HANDLER_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_FOCUS_HANDLER_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_focus_handler_capi.h"
+#include "include/cef_focus_handler.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefFocusHandlerCToCpp : public CefCToCppRefCounted<CefFocusHandlerCToCpp,
+ CefFocusHandler,
+ cef_focus_handler_t> {
+ public:
+ CefFocusHandlerCToCpp();
+ virtual ~CefFocusHandlerCToCpp();
+
+ // CefFocusHandler methods.
+ void OnTakeFocus(CefRefPtr<CefBrowser> browser, bool next) override;
+ bool OnSetFocus(CefRefPtr<CefBrowser> browser, FocusSource source) override;
+ void OnGotFocus(CefRefPtr<CefBrowser> browser) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_FOCUS_HANDLER_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/frame_ctocpp.cc b/libcef_dll/ctocpp/frame_ctocpp.cc
new file mode 100644
index 00000000..933705ac
--- /dev/null
+++ b/libcef_dll/ctocpp/frame_ctocpp.cc
@@ -0,0 +1,505 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=dccd8985bad895305a64d49d4cc690d51ec75f8a$
+//
+
+#include "libcef_dll/ctocpp/frame_ctocpp.h"
+#include "libcef_dll/cpptoc/domvisitor_cpptoc.h"
+#include "libcef_dll/cpptoc/string_visitor_cpptoc.h"
+#include "libcef_dll/cpptoc/urlrequest_client_cpptoc.h"
+#include "libcef_dll/ctocpp/browser_ctocpp.h"
+#include "libcef_dll/ctocpp/process_message_ctocpp.h"
+#include "libcef_dll/ctocpp/request_ctocpp.h"
+#include "libcef_dll/ctocpp/urlrequest_ctocpp.h"
+#include "libcef_dll/ctocpp/v8context_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") bool CefFrameCToCpp::IsValid() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_frame_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_valid)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_valid(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") void CefFrameCToCpp::Undo() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_frame_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, undo)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->undo(_struct);
+}
+
+NO_SANITIZE("cfi-icall") void CefFrameCToCpp::Redo() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_frame_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, redo)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->redo(_struct);
+}
+
+NO_SANITIZE("cfi-icall") void CefFrameCToCpp::Cut() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_frame_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, cut)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->cut(_struct);
+}
+
+NO_SANITIZE("cfi-icall") void CefFrameCToCpp::Copy() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_frame_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, copy)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->copy(_struct);
+}
+
+NO_SANITIZE("cfi-icall") void CefFrameCToCpp::Paste() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_frame_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, paste)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->paste(_struct);
+}
+
+NO_SANITIZE("cfi-icall") void CefFrameCToCpp::Delete() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_frame_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, del)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->del(_struct);
+}
+
+NO_SANITIZE("cfi-icall") void CefFrameCToCpp::SelectAll() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_frame_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, select_all)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->select_all(_struct);
+}
+
+NO_SANITIZE("cfi-icall") void CefFrameCToCpp::ViewSource() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_frame_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, view_source)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->view_source(_struct);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefFrameCToCpp::GetSource(CefRefPtr<CefStringVisitor> visitor) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_frame_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_source)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: visitor; type: refptr_diff
+ DCHECK(visitor.get());
+ if (!visitor.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->get_source(_struct, CefStringVisitorCppToC::Wrap(visitor));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefFrameCToCpp::GetText(CefRefPtr<CefStringVisitor> visitor) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_frame_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_text)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: visitor; type: refptr_diff
+ DCHECK(visitor.get());
+ if (!visitor.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->get_text(_struct, CefStringVisitorCppToC::Wrap(visitor));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefFrameCToCpp::LoadRequest(CefRefPtr<CefRequest> request) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_frame_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, load_request)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: request; type: refptr_same
+ DCHECK(request.get());
+ if (!request.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->load_request(_struct, CefRequestCToCpp::Unwrap(request));
+}
+
+NO_SANITIZE("cfi-icall") void CefFrameCToCpp::LoadURL(const CefString& url) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_frame_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, load_url)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: url; type: string_byref_const
+ DCHECK(!url.empty());
+ if (url.empty()) {
+ return;
+ }
+
+ // Execute
+ _struct->load_url(_struct, url.GetStruct());
+}
+
+NO_SANITIZE("cfi-icall")
+void CefFrameCToCpp::ExecuteJavaScript(const CefString& code,
+ const CefString& script_url,
+ int start_line) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_frame_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, execute_java_script)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: code; type: string_byref_const
+ DCHECK(!code.empty());
+ if (code.empty()) {
+ return;
+ }
+ // Unverified params: script_url
+
+ // Execute
+ _struct->execute_java_script(_struct, code.GetStruct(),
+ script_url.GetStruct(), start_line);
+}
+
+NO_SANITIZE("cfi-icall") bool CefFrameCToCpp::IsMain() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_frame_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_main)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_main(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefFrameCToCpp::IsFocused() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_frame_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_focused)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_focused(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") CefString CefFrameCToCpp::GetName() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_frame_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_name)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_name(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") int64 CefFrameCToCpp::GetIdentifier() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_frame_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_identifier)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int64 _retval = _struct->get_identifier(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefFrame> CefFrameCToCpp::GetParent() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_frame_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_parent)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_frame_t* _retval = _struct->get_parent(_struct);
+
+ // Return type: refptr_same
+ return CefFrameCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") CefString CefFrameCToCpp::GetURL() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_frame_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_url)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_url(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefBrowser> CefFrameCToCpp::GetBrowser() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_frame_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_browser)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_browser_t* _retval = _struct->get_browser(_struct);
+
+ // Return type: refptr_same
+ return CefBrowserCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefV8Context> CefFrameCToCpp::GetV8Context() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_frame_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_v8context)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_v8context_t* _retval = _struct->get_v8context(_struct);
+
+ // Return type: refptr_same
+ return CefV8ContextCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefFrameCToCpp::VisitDOM(CefRefPtr<CefDOMVisitor> visitor) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_frame_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, visit_dom)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: visitor; type: refptr_diff
+ DCHECK(visitor.get());
+ if (!visitor.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->visit_dom(_struct, CefDOMVisitorCppToC::Wrap(visitor));
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefURLRequest> CefFrameCToCpp::CreateURLRequest(
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefURLRequestClient> client) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_frame_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, create_urlrequest)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: request; type: refptr_same
+ DCHECK(request.get());
+ if (!request.get()) {
+ return nullptr;
+ }
+ // Verify param: client; type: refptr_diff
+ DCHECK(client.get());
+ if (!client.get()) {
+ return nullptr;
+ }
+
+ // Execute
+ cef_urlrequest_t* _retval =
+ _struct->create_urlrequest(_struct, CefRequestCToCpp::Unwrap(request),
+ CefURLRequestClientCppToC::Wrap(client));
+
+ // Return type: refptr_same
+ return CefURLRequestCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefFrameCToCpp::SendProcessMessage(CefProcessId target_process,
+ CefRefPtr<CefProcessMessage> message) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_frame_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, send_process_message)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: message; type: refptr_same
+ DCHECK(message.get());
+ if (!message.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->send_process_message(_struct, target_process,
+ CefProcessMessageCToCpp::Unwrap(message));
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefFrameCToCpp::CefFrameCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefFrameCToCpp::~CefFrameCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_frame_t*
+CefCToCppRefCounted<CefFrameCToCpp, CefFrame, cef_frame_t>::UnwrapDerived(
+ CefWrapperType type,
+ CefFrame* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCToCppRefCounted<CefFrameCToCpp, CefFrame, cef_frame_t>::kWrapperType =
+ WT_FRAME;
diff --git a/libcef_dll/ctocpp/frame_ctocpp.h b/libcef_dll/ctocpp/frame_ctocpp.h
new file mode 100644
index 00000000..1dcabfbd
--- /dev/null
+++ b/libcef_dll/ctocpp/frame_ctocpp.h
@@ -0,0 +1,74 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=6b1e5c1fa56a6561a054d35866e1c598c7e64368$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_FRAME_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_FRAME_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_browser_capi.h"
+#include "include/capi/cef_frame_capi.h"
+#include "include/capi/cef_urlrequest_capi.h"
+#include "include/capi/cef_v8_capi.h"
+#include "include/cef_browser.h"
+#include "include/cef_frame.h"
+#include "include/cef_urlrequest.h"
+#include "include/cef_v8.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefFrameCToCpp
+ : public CefCToCppRefCounted<CefFrameCToCpp, CefFrame, cef_frame_t> {
+ public:
+ CefFrameCToCpp();
+ virtual ~CefFrameCToCpp();
+
+ // CefFrame methods.
+ bool IsValid() override;
+ void Undo() override;
+ void Redo() override;
+ void Cut() override;
+ void Copy() override;
+ void Paste() override;
+ void Delete() override;
+ void SelectAll() override;
+ void ViewSource() override;
+ void GetSource(CefRefPtr<CefStringVisitor> visitor) override;
+ void GetText(CefRefPtr<CefStringVisitor> visitor) override;
+ void LoadRequest(CefRefPtr<CefRequest> request) override;
+ void LoadURL(const CefString& url) override;
+ void ExecuteJavaScript(const CefString& code,
+ const CefString& script_url,
+ int start_line) override;
+ bool IsMain() override;
+ bool IsFocused() override;
+ CefString GetName() override;
+ int64 GetIdentifier() override;
+ CefRefPtr<CefFrame> GetParent() override;
+ CefString GetURL() override;
+ CefRefPtr<CefBrowser> GetBrowser() override;
+ CefRefPtr<CefV8Context> GetV8Context() override;
+ void VisitDOM(CefRefPtr<CefDOMVisitor> visitor) override;
+ CefRefPtr<CefURLRequest> CreateURLRequest(
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefURLRequestClient> client) override;
+ void SendProcessMessage(CefProcessId target_process,
+ CefRefPtr<CefProcessMessage> message) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_FRAME_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/frame_handler_ctocpp.cc b/libcef_dll/ctocpp/frame_handler_ctocpp.cc
new file mode 100644
index 00000000..e4f30345
--- /dev/null
+++ b/libcef_dll/ctocpp/frame_handler_ctocpp.cc
@@ -0,0 +1,157 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=499afac754e20ab09693803a14a047a576ed1eb2$
+//
+
+#include "libcef_dll/ctocpp/frame_handler_ctocpp.h"
+#include "libcef_dll/cpptoc/browser_cpptoc.h"
+#include "libcef_dll/cpptoc/frame_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+void CefFrameHandlerCToCpp::OnFrameCreated(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_frame_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_frame_created)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+ // Verify param: frame; type: refptr_diff
+ DCHECK(frame.get());
+ if (!frame.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_frame_created(_struct, CefBrowserCppToC::Wrap(browser),
+ CefFrameCppToC::Wrap(frame));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefFrameHandlerCToCpp::OnFrameAttached(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ bool reattached) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_frame_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_frame_attached)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+ // Verify param: frame; type: refptr_diff
+ DCHECK(frame.get());
+ if (!frame.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_frame_attached(_struct, CefBrowserCppToC::Wrap(browser),
+ CefFrameCppToC::Wrap(frame), reattached);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefFrameHandlerCToCpp::OnFrameDetached(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_frame_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_frame_detached)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+ // Verify param: frame; type: refptr_diff
+ DCHECK(frame.get());
+ if (!frame.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_frame_detached(_struct, CefBrowserCppToC::Wrap(browser),
+ CefFrameCppToC::Wrap(frame));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefFrameHandlerCToCpp::OnMainFrameChanged(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> old_frame,
+ CefRefPtr<CefFrame> new_frame) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_frame_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_main_frame_changed)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+ // Unverified params: old_frame, new_frame
+
+ // Execute
+ _struct->on_main_frame_changed(_struct, CefBrowserCppToC::Wrap(browser),
+ CefFrameCppToC::Wrap(old_frame),
+ CefFrameCppToC::Wrap(new_frame));
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefFrameHandlerCToCpp::CefFrameHandlerCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefFrameHandlerCToCpp::~CefFrameHandlerCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_frame_handler_t*
+CefCToCppRefCounted<CefFrameHandlerCToCpp,
+ CefFrameHandler,
+ cef_frame_handler_t>::UnwrapDerived(CefWrapperType type,
+ CefFrameHandler* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefFrameHandlerCToCpp,
+ CefFrameHandler,
+ cef_frame_handler_t>::kWrapperType =
+ WT_FRAME_HANDLER;
diff --git a/libcef_dll/ctocpp/frame_handler_ctocpp.h b/libcef_dll/ctocpp/frame_handler_ctocpp.h
new file mode 100644
index 00000000..be28fb88
--- /dev/null
+++ b/libcef_dll/ctocpp/frame_handler_ctocpp.h
@@ -0,0 +1,49 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=a1366f78329888eadf9121d7df819687d82a40c7$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_FRAME_HANDLER_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_FRAME_HANDLER_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_frame_handler_capi.h"
+#include "include/cef_frame_handler.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefFrameHandlerCToCpp : public CefCToCppRefCounted<CefFrameHandlerCToCpp,
+ CefFrameHandler,
+ cef_frame_handler_t> {
+ public:
+ CefFrameHandlerCToCpp();
+ virtual ~CefFrameHandlerCToCpp();
+
+ // CefFrameHandler methods.
+ void OnFrameCreated(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) override;
+ void OnFrameAttached(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ bool reattached) override;
+ void OnFrameDetached(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) override;
+ void OnMainFrameChanged(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> old_frame,
+ CefRefPtr<CefFrame> new_frame) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_FRAME_HANDLER_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/get_extension_resource_callback_ctocpp.cc b/libcef_dll/ctocpp/get_extension_resource_callback_ctocpp.cc
new file mode 100644
index 00000000..c6d869c2
--- /dev/null
+++ b/libcef_dll/ctocpp/get_extension_resource_callback_ctocpp.cc
@@ -0,0 +1,80 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=5a1986090e786d2d1c14f839cb9e18b97e1080b5$
+//
+
+#include "libcef_dll/ctocpp/get_extension_resource_callback_ctocpp.h"
+#include "libcef_dll/ctocpp/stream_reader_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+void CefGetExtensionResourceCallbackCToCpp::Continue(
+ CefRefPtr<CefStreamReader> stream) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_get_extension_resource_callback_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, cont)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: stream
+
+ // Execute
+ _struct->cont(_struct, CefStreamReaderCToCpp::Unwrap(stream));
+}
+
+NO_SANITIZE("cfi-icall") void CefGetExtensionResourceCallbackCToCpp::Cancel() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_get_extension_resource_callback_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, cancel)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->cancel(_struct);
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefGetExtensionResourceCallbackCToCpp::CefGetExtensionResourceCallbackCToCpp() {
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefGetExtensionResourceCallbackCToCpp::
+ ~CefGetExtensionResourceCallbackCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_get_extension_resource_callback_t*
+CefCToCppRefCounted<CefGetExtensionResourceCallbackCToCpp,
+ CefGetExtensionResourceCallback,
+ cef_get_extension_resource_callback_t>::
+ UnwrapDerived(CefWrapperType type, CefGetExtensionResourceCallback* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCToCppRefCounted<CefGetExtensionResourceCallbackCToCpp,
+ CefGetExtensionResourceCallback,
+ cef_get_extension_resource_callback_t>::kWrapperType =
+ WT_GET_EXTENSION_RESOURCE_CALLBACK;
diff --git a/libcef_dll/ctocpp/get_extension_resource_callback_ctocpp.h b/libcef_dll/ctocpp/get_extension_resource_callback_ctocpp.h
new file mode 100644
index 00000000..afebabd4
--- /dev/null
+++ b/libcef_dll/ctocpp/get_extension_resource_callback_ctocpp.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=fd92d3650c1f3f04b84d9a0847631463b9e9ca2c$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_GET_EXTENSION_RESOURCE_CALLBACK_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_GET_EXTENSION_RESOURCE_CALLBACK_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_client_capi.h"
+#include "include/capi/cef_extension_handler_capi.h"
+#include "include/cef_client.h"
+#include "include/cef_extension_handler.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefGetExtensionResourceCallbackCToCpp
+ : public CefCToCppRefCounted<CefGetExtensionResourceCallbackCToCpp,
+ CefGetExtensionResourceCallback,
+ cef_get_extension_resource_callback_t> {
+ public:
+ CefGetExtensionResourceCallbackCToCpp();
+ virtual ~CefGetExtensionResourceCallbackCToCpp();
+
+ // CefGetExtensionResourceCallback methods.
+ void Continue(CefRefPtr<CefStreamReader> stream) override;
+ void Cancel() override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_GET_EXTENSION_RESOURCE_CALLBACK_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/image_ctocpp.cc b/libcef_dll/ctocpp/image_ctocpp.cc
new file mode 100644
index 00000000..153b15b2
--- /dev/null
+++ b/libcef_dll/ctocpp/image_ctocpp.cc
@@ -0,0 +1,344 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=d679c42dea71a6b726ac967998a9a0cb1571d2b9$
+//
+
+#include "libcef_dll/ctocpp/image_ctocpp.h"
+#include "libcef_dll/ctocpp/binary_value_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// STATIC METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefImage> CefImage::CreateImage() {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_image_t* _retval = cef_image_create();
+
+ // Return type: refptr_same
+ return CefImageCToCpp::Wrap(_retval);
+}
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") bool CefImageCToCpp::IsEmpty() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_image_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_empty)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_empty(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefImageCToCpp::IsSame(CefRefPtr<CefImage> that) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_image_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_same)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: that; type: refptr_same
+ DCHECK(that.get());
+ if (!that.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->is_same(_struct, CefImageCToCpp::Unwrap(that));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefImageCToCpp::AddBitmap(float scale_factor,
+ int pixel_width,
+ int pixel_height,
+ cef_color_type_t color_type,
+ cef_alpha_type_t alpha_type,
+ const void* pixel_data,
+ size_t pixel_data_size) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_image_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, add_bitmap)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: pixel_data; type: simple_byaddr
+ DCHECK(pixel_data);
+ if (!pixel_data) {
+ return false;
+ }
+
+ // Execute
+ int _retval =
+ _struct->add_bitmap(_struct, scale_factor, pixel_width, pixel_height,
+ color_type, alpha_type, pixel_data, pixel_data_size);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefImageCToCpp::AddPNG(float scale_factor,
+ const void* png_data,
+ size_t png_data_size) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_image_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, add_png)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: png_data; type: simple_byaddr
+ DCHECK(png_data);
+ if (!png_data) {
+ return false;
+ }
+
+ // Execute
+ int _retval =
+ _struct->add_png(_struct, scale_factor, png_data, png_data_size);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefImageCToCpp::AddJPEG(float scale_factor,
+ const void* jpeg_data,
+ size_t jpeg_data_size) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_image_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, add_jpeg)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: jpeg_data; type: simple_byaddr
+ DCHECK(jpeg_data);
+ if (!jpeg_data) {
+ return false;
+ }
+
+ // Execute
+ int _retval =
+ _struct->add_jpeg(_struct, scale_factor, jpeg_data, jpeg_data_size);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") size_t CefImageCToCpp::GetWidth() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_image_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_width)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ size_t _retval = _struct->get_width(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") size_t CefImageCToCpp::GetHeight() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_image_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_height)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ size_t _retval = _struct->get_height(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefImageCToCpp::HasRepresentation(float scale_factor) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_image_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, has_representation)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->has_representation(_struct, scale_factor);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefImageCToCpp::RemoveRepresentation(float scale_factor) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_image_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, remove_representation)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->remove_representation(_struct, scale_factor);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefImageCToCpp::GetRepresentationInfo(float scale_factor,
+ float& actual_scale_factor,
+ int& pixel_width,
+ int& pixel_height) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_image_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_representation_info)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_representation_info(
+ _struct, scale_factor, &actual_scale_factor, &pixel_width, &pixel_height);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefBinaryValue> CefImageCToCpp::GetAsBitmap(
+ float scale_factor,
+ cef_color_type_t color_type,
+ cef_alpha_type_t alpha_type,
+ int& pixel_width,
+ int& pixel_height) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_image_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_as_bitmap)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_binary_value_t* _retval =
+ _struct->get_as_bitmap(_struct, scale_factor, color_type, alpha_type,
+ &pixel_width, &pixel_height);
+
+ // Return type: refptr_same
+ return CefBinaryValueCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefBinaryValue> CefImageCToCpp::GetAsPNG(float scale_factor,
+ bool with_transparency,
+ int& pixel_width,
+ int& pixel_height) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_image_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_as_png)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_binary_value_t* _retval = _struct->get_as_png(
+ _struct, scale_factor, with_transparency, &pixel_width, &pixel_height);
+
+ // Return type: refptr_same
+ return CefBinaryValueCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefBinaryValue> CefImageCToCpp::GetAsJPEG(float scale_factor,
+ int quality,
+ int& pixel_width,
+ int& pixel_height) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_image_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_as_jpeg)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_binary_value_t* _retval = _struct->get_as_jpeg(
+ _struct, scale_factor, quality, &pixel_width, &pixel_height);
+
+ // Return type: refptr_same
+ return CefBinaryValueCToCpp::Wrap(_retval);
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefImageCToCpp::CefImageCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefImageCToCpp::~CefImageCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_image_t*
+CefCToCppRefCounted<CefImageCToCpp, CefImage, cef_image_t>::UnwrapDerived(
+ CefWrapperType type,
+ CefImage* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCToCppRefCounted<CefImageCToCpp, CefImage, cef_image_t>::kWrapperType =
+ WT_IMAGE;
diff --git a/libcef_dll/ctocpp/image_ctocpp.h b/libcef_dll/ctocpp/image_ctocpp.h
new file mode 100644
index 00000000..8d635fdd
--- /dev/null
+++ b/libcef_dll/ctocpp/image_ctocpp.h
@@ -0,0 +1,74 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=13afe421110fa07e94c1724d21302b018a71a633$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_IMAGE_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_IMAGE_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_image_capi.h"
+#include "include/cef_image.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefImageCToCpp
+ : public CefCToCppRefCounted<CefImageCToCpp, CefImage, cef_image_t> {
+ public:
+ CefImageCToCpp();
+ virtual ~CefImageCToCpp();
+
+ // CefImage methods.
+ bool IsEmpty() override;
+ bool IsSame(CefRefPtr<CefImage> that) override;
+ bool AddBitmap(float scale_factor,
+ int pixel_width,
+ int pixel_height,
+ cef_color_type_t color_type,
+ cef_alpha_type_t alpha_type,
+ const void* pixel_data,
+ size_t pixel_data_size) override;
+ bool AddPNG(float scale_factor,
+ const void* png_data,
+ size_t png_data_size) override;
+ bool AddJPEG(float scale_factor,
+ const void* jpeg_data,
+ size_t jpeg_data_size) override;
+ size_t GetWidth() override;
+ size_t GetHeight() override;
+ bool HasRepresentation(float scale_factor) override;
+ bool RemoveRepresentation(float scale_factor) override;
+ bool GetRepresentationInfo(float scale_factor,
+ float& actual_scale_factor,
+ int& pixel_width,
+ int& pixel_height) override;
+ CefRefPtr<CefBinaryValue> GetAsBitmap(float scale_factor,
+ cef_color_type_t color_type,
+ cef_alpha_type_t alpha_type,
+ int& pixel_width,
+ int& pixel_height) override;
+ CefRefPtr<CefBinaryValue> GetAsPNG(float scale_factor,
+ bool with_transparency,
+ int& pixel_width,
+ int& pixel_height) override;
+ CefRefPtr<CefBinaryValue> GetAsJPEG(float scale_factor,
+ int quality,
+ int& pixel_width,
+ int& pixel_height) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_IMAGE_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/jsdialog_callback_ctocpp.cc b/libcef_dll/ctocpp/jsdialog_callback_ctocpp.cc
new file mode 100644
index 00000000..9fae4cb0
--- /dev/null
+++ b/libcef_dll/ctocpp/jsdialog_callback_ctocpp.cc
@@ -0,0 +1,62 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=eff3cd2d25f42a1155319d6eee8ea770e16c7ba7$
+//
+
+#include "libcef_dll/ctocpp/jsdialog_callback_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+void CefJSDialogCallbackCToCpp::Continue(bool success,
+ const CefString& user_input) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_jsdialog_callback_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, cont)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: user_input
+
+ // Execute
+ _struct->cont(_struct, success, user_input.GetStruct());
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefJSDialogCallbackCToCpp::CefJSDialogCallbackCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefJSDialogCallbackCToCpp::~CefJSDialogCallbackCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_jsdialog_callback_t* CefCToCppRefCounted<
+ CefJSDialogCallbackCToCpp,
+ CefJSDialogCallback,
+ cef_jsdialog_callback_t>::UnwrapDerived(CefWrapperType type,
+ CefJSDialogCallback* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefJSDialogCallbackCToCpp,
+ CefJSDialogCallback,
+ cef_jsdialog_callback_t>::kWrapperType =
+ WT_JSDIALOG_CALLBACK;
diff --git a/libcef_dll/ctocpp/jsdialog_callback_ctocpp.h b/libcef_dll/ctocpp/jsdialog_callback_ctocpp.h
new file mode 100644
index 00000000..a73df8ad
--- /dev/null
+++ b/libcef_dll/ctocpp/jsdialog_callback_ctocpp.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=5e91e201bc50f771d1ded89088fffcb0da8d34d7$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_JSDIALOG_CALLBACK_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_JSDIALOG_CALLBACK_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_jsdialog_handler_capi.h"
+#include "include/cef_jsdialog_handler.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefJSDialogCallbackCToCpp
+ : public CefCToCppRefCounted<CefJSDialogCallbackCToCpp,
+ CefJSDialogCallback,
+ cef_jsdialog_callback_t> {
+ public:
+ CefJSDialogCallbackCToCpp();
+ virtual ~CefJSDialogCallbackCToCpp();
+
+ // CefJSDialogCallback methods.
+ void Continue(bool success, const CefString& user_input) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_JSDIALOG_CALLBACK_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/jsdialog_handler_ctocpp.cc b/libcef_dll/ctocpp/jsdialog_handler_ctocpp.cc
new file mode 100644
index 00000000..c7df99a5
--- /dev/null
+++ b/libcef_dll/ctocpp/jsdialog_handler_ctocpp.cc
@@ -0,0 +1,171 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=022f9cc79a1aade870e9f1f7a77f8604c6a9c36b$
+//
+
+#include "libcef_dll/ctocpp/jsdialog_handler_ctocpp.h"
+#include "libcef_dll/cpptoc/browser_cpptoc.h"
+#include "libcef_dll/cpptoc/jsdialog_callback_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+bool CefJSDialogHandlerCToCpp::OnJSDialog(
+ CefRefPtr<CefBrowser> browser,
+ const CefString& origin_url,
+ JSDialogType dialog_type,
+ const CefString& message_text,
+ const CefString& default_prompt_text,
+ CefRefPtr<CefJSDialogCallback> callback,
+ bool& suppress_message) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_jsdialog_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_jsdialog)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return false;
+ }
+ // Verify param: callback; type: refptr_diff
+ DCHECK(callback.get());
+ if (!callback.get()) {
+ return false;
+ }
+ // Unverified params: origin_url, message_text, default_prompt_text
+
+ // Translate param: suppress_message; type: bool_byref
+ int suppress_messageInt = suppress_message;
+
+ // Execute
+ int _retval = _struct->on_jsdialog(
+ _struct, CefBrowserCppToC::Wrap(browser), origin_url.GetStruct(),
+ dialog_type, message_text.GetStruct(), default_prompt_text.GetStruct(),
+ CefJSDialogCallbackCppToC::Wrap(callback), &suppress_messageInt);
+
+ // Restore param:suppress_message; type: bool_byref
+ suppress_message = suppress_messageInt ? true : false;
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefJSDialogHandlerCToCpp::OnBeforeUnloadDialog(
+ CefRefPtr<CefBrowser> browser,
+ const CefString& message_text,
+ bool is_reload,
+ CefRefPtr<CefJSDialogCallback> callback) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_jsdialog_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_before_unload_dialog)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return false;
+ }
+ // Verify param: callback; type: refptr_diff
+ DCHECK(callback.get());
+ if (!callback.get()) {
+ return false;
+ }
+ // Unverified params: message_text
+
+ // Execute
+ int _retval = _struct->on_before_unload_dialog(
+ _struct, CefBrowserCppToC::Wrap(browser), message_text.GetStruct(),
+ is_reload, CefJSDialogCallbackCppToC::Wrap(callback));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefJSDialogHandlerCToCpp::OnResetDialogState(
+ CefRefPtr<CefBrowser> browser) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_jsdialog_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_reset_dialog_state)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_reset_dialog_state(_struct, CefBrowserCppToC::Wrap(browser));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefJSDialogHandlerCToCpp::OnDialogClosed(CefRefPtr<CefBrowser> browser) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_jsdialog_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_dialog_closed)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_dialog_closed(_struct, CefBrowserCppToC::Wrap(browser));
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefJSDialogHandlerCToCpp::CefJSDialogHandlerCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefJSDialogHandlerCToCpp::~CefJSDialogHandlerCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_jsdialog_handler_t* CefCToCppRefCounted<
+ CefJSDialogHandlerCToCpp,
+ CefJSDialogHandler,
+ cef_jsdialog_handler_t>::UnwrapDerived(CefWrapperType type,
+ CefJSDialogHandler* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefJSDialogHandlerCToCpp,
+ CefJSDialogHandler,
+ cef_jsdialog_handler_t>::kWrapperType =
+ WT_JSDIALOG_HANDLER;
diff --git a/libcef_dll/ctocpp/jsdialog_handler_ctocpp.h b/libcef_dll/ctocpp/jsdialog_handler_ctocpp.h
new file mode 100644
index 00000000..740330b3
--- /dev/null
+++ b/libcef_dll/ctocpp/jsdialog_handler_ctocpp.h
@@ -0,0 +1,53 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=55b3bcb925cfaf44f79c0e03fc55878d748f55ce$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_JSDIALOG_HANDLER_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_JSDIALOG_HANDLER_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_jsdialog_handler_capi.h"
+#include "include/cef_jsdialog_handler.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefJSDialogHandlerCToCpp
+ : public CefCToCppRefCounted<CefJSDialogHandlerCToCpp,
+ CefJSDialogHandler,
+ cef_jsdialog_handler_t> {
+ public:
+ CefJSDialogHandlerCToCpp();
+ virtual ~CefJSDialogHandlerCToCpp();
+
+ // CefJSDialogHandler methods.
+ bool OnJSDialog(CefRefPtr<CefBrowser> browser,
+ const CefString& origin_url,
+ JSDialogType dialog_type,
+ const CefString& message_text,
+ const CefString& default_prompt_text,
+ CefRefPtr<CefJSDialogCallback> callback,
+ bool& suppress_message) override;
+ bool OnBeforeUnloadDialog(CefRefPtr<CefBrowser> browser,
+ const CefString& message_text,
+ bool is_reload,
+ CefRefPtr<CefJSDialogCallback> callback) override;
+ void OnResetDialogState(CefRefPtr<CefBrowser> browser) override;
+ void OnDialogClosed(CefRefPtr<CefBrowser> browser) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_JSDIALOG_HANDLER_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/keyboard_handler_ctocpp.cc b/libcef_dll/ctocpp/keyboard_handler_ctocpp.cc
new file mode 100644
index 00000000..423f7537
--- /dev/null
+++ b/libcef_dll/ctocpp/keyboard_handler_ctocpp.cc
@@ -0,0 +1,115 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=a581ca5b863ea4d1c6c94f9eef37b676ab370e77$
+//
+
+#include "libcef_dll/ctocpp/keyboard_handler_ctocpp.h"
+#include "libcef_dll/cpptoc/browser_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+bool CefKeyboardHandlerCToCpp::OnPreKeyEvent(CefRefPtr<CefBrowser> browser,
+ const CefKeyEvent& event,
+ CefEventHandle os_event,
+ bool* is_keyboard_shortcut) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_keyboard_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_pre_key_event)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return false;
+ }
+ // Verify param: is_keyboard_shortcut; type: bool_byaddr
+ DCHECK(is_keyboard_shortcut);
+ if (!is_keyboard_shortcut) {
+ return false;
+ }
+
+ // Translate param: is_keyboard_shortcut; type: bool_byaddr
+ int is_keyboard_shortcutInt =
+ is_keyboard_shortcut ? *is_keyboard_shortcut : 0;
+
+ // Execute
+ int _retval =
+ _struct->on_pre_key_event(_struct, CefBrowserCppToC::Wrap(browser),
+ &event, os_event, &is_keyboard_shortcutInt);
+
+ // Restore param:is_keyboard_shortcut; type: bool_byaddr
+ if (is_keyboard_shortcut) {
+ *is_keyboard_shortcut = is_keyboard_shortcutInt ? true : false;
+ }
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefKeyboardHandlerCToCpp::OnKeyEvent(CefRefPtr<CefBrowser> browser,
+ const CefKeyEvent& event,
+ CefEventHandle os_event) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_keyboard_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_key_event)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->on_key_event(_struct, CefBrowserCppToC::Wrap(browser),
+ &event, os_event);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefKeyboardHandlerCToCpp::CefKeyboardHandlerCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefKeyboardHandlerCToCpp::~CefKeyboardHandlerCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_keyboard_handler_t* CefCToCppRefCounted<
+ CefKeyboardHandlerCToCpp,
+ CefKeyboardHandler,
+ cef_keyboard_handler_t>::UnwrapDerived(CefWrapperType type,
+ CefKeyboardHandler* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefKeyboardHandlerCToCpp,
+ CefKeyboardHandler,
+ cef_keyboard_handler_t>::kWrapperType =
+ WT_KEYBOARD_HANDLER;
diff --git a/libcef_dll/ctocpp/keyboard_handler_ctocpp.h b/libcef_dll/ctocpp/keyboard_handler_ctocpp.h
new file mode 100644
index 00000000..65c681eb
--- /dev/null
+++ b/libcef_dll/ctocpp/keyboard_handler_ctocpp.h
@@ -0,0 +1,47 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=a25080ecb1a098b748d8384bc5af591ea773deff$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_KEYBOARD_HANDLER_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_KEYBOARD_HANDLER_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_keyboard_handler_capi.h"
+#include "include/cef_keyboard_handler.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefKeyboardHandlerCToCpp
+ : public CefCToCppRefCounted<CefKeyboardHandlerCToCpp,
+ CefKeyboardHandler,
+ cef_keyboard_handler_t> {
+ public:
+ CefKeyboardHandlerCToCpp();
+ virtual ~CefKeyboardHandlerCToCpp();
+
+ // CefKeyboardHandler methods.
+ bool OnPreKeyEvent(CefRefPtr<CefBrowser> browser,
+ const CefKeyEvent& event,
+ CefEventHandle os_event,
+ bool* is_keyboard_shortcut) override;
+ bool OnKeyEvent(CefRefPtr<CefBrowser> browser,
+ const CefKeyEvent& event,
+ CefEventHandle os_event) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_KEYBOARD_HANDLER_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/life_span_handler_ctocpp.cc b/libcef_dll/ctocpp/life_span_handler_ctocpp.cc
new file mode 100644
index 00000000..eda350ed
--- /dev/null
+++ b/libcef_dll/ctocpp/life_span_handler_ctocpp.cc
@@ -0,0 +1,202 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=55296997cc48bab5c04548fa063f0692bfad12c5$
+//
+
+#include "libcef_dll/ctocpp/life_span_handler_ctocpp.h"
+#include "libcef_dll/cpptoc/browser_cpptoc.h"
+#include "libcef_dll/cpptoc/dictionary_value_cpptoc.h"
+#include "libcef_dll/cpptoc/frame_cpptoc.h"
+#include "libcef_dll/ctocpp/client_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+bool CefLifeSpanHandlerCToCpp::OnBeforePopup(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const CefString& target_url,
+ const CefString& target_frame_name,
+ WindowOpenDisposition target_disposition,
+ bool user_gesture,
+ const CefPopupFeatures& popupFeatures,
+ CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient>& client,
+ CefBrowserSettings& settings,
+ CefRefPtr<CefDictionaryValue>& extra_info,
+ bool* no_javascript_access) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_life_span_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_before_popup)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return false;
+ }
+ // Verify param: frame; type: refptr_diff
+ DCHECK(frame.get());
+ if (!frame.get()) {
+ return false;
+ }
+ // Verify param: no_javascript_access; type: bool_byaddr
+ DCHECK(no_javascript_access);
+ if (!no_javascript_access) {
+ return false;
+ }
+ // Unverified params: target_url, target_frame_name
+
+ // Translate param: client; type: refptr_same_byref
+ cef_client_t* clientStruct = NULL;
+ if (client.get()) {
+ clientStruct = CefClientCToCpp::Unwrap(client);
+ }
+ cef_client_t* clientOrig = clientStruct;
+ // Translate param: extra_info; type: refptr_diff_byref
+ cef_dictionary_value_t* extra_infoStruct = NULL;
+ if (extra_info.get()) {
+ extra_infoStruct = CefDictionaryValueCppToC::Wrap(extra_info);
+ }
+ cef_dictionary_value_t* extra_infoOrig = extra_infoStruct;
+ // Translate param: no_javascript_access; type: bool_byaddr
+ int no_javascript_accessInt =
+ no_javascript_access ? *no_javascript_access : 0;
+
+ // Execute
+ int _retval = _struct->on_before_popup(
+ _struct, CefBrowserCppToC::Wrap(browser), CefFrameCppToC::Wrap(frame),
+ target_url.GetStruct(), target_frame_name.GetStruct(), target_disposition,
+ user_gesture, &popupFeatures, &windowInfo, &clientStruct, &settings,
+ &extra_infoStruct, &no_javascript_accessInt);
+
+ // Restore param:client; type: refptr_same_byref
+ if (clientStruct) {
+ if (clientStruct != clientOrig) {
+ client = CefClientCToCpp::Wrap(clientStruct);
+ }
+ } else {
+ client = nullptr;
+ }
+ // Restore param:extra_info; type: refptr_diff_byref
+ if (extra_infoStruct) {
+ if (extra_infoStruct != extra_infoOrig) {
+ extra_info = CefDictionaryValueCppToC::Unwrap(extra_infoStruct);
+ }
+ } else {
+ extra_info = nullptr;
+ }
+ // Restore param:no_javascript_access; type: bool_byaddr
+ if (no_javascript_access) {
+ *no_javascript_access = no_javascript_accessInt ? true : false;
+ }
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefLifeSpanHandlerCToCpp::OnAfterCreated(CefRefPtr<CefBrowser> browser) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_life_span_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_after_created)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_after_created(_struct, CefBrowserCppToC::Wrap(browser));
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefLifeSpanHandlerCToCpp::DoClose(CefRefPtr<CefBrowser> browser) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_life_span_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, do_close)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->do_close(_struct, CefBrowserCppToC::Wrap(browser));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefLifeSpanHandlerCToCpp::OnBeforeClose(CefRefPtr<CefBrowser> browser) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_life_span_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_before_close)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_before_close(_struct, CefBrowserCppToC::Wrap(browser));
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefLifeSpanHandlerCToCpp::CefLifeSpanHandlerCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefLifeSpanHandlerCToCpp::~CefLifeSpanHandlerCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_life_span_handler_t* CefCToCppRefCounted<
+ CefLifeSpanHandlerCToCpp,
+ CefLifeSpanHandler,
+ cef_life_span_handler_t>::UnwrapDerived(CefWrapperType type,
+ CefLifeSpanHandler* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefLifeSpanHandlerCToCpp,
+ CefLifeSpanHandler,
+ cef_life_span_handler_t>::kWrapperType =
+ WT_LIFE_SPAN_HANDLER;
diff --git a/libcef_dll/ctocpp/life_span_handler_ctocpp.h b/libcef_dll/ctocpp/life_span_handler_ctocpp.h
new file mode 100644
index 00000000..542c5328
--- /dev/null
+++ b/libcef_dll/ctocpp/life_span_handler_ctocpp.h
@@ -0,0 +1,57 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=229117f1ecb1cc27b5ab5eebd79e64c30d73a855$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_LIFE_SPAN_HANDLER_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_LIFE_SPAN_HANDLER_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_client_capi.h"
+#include "include/capi/cef_life_span_handler_capi.h"
+#include "include/cef_client.h"
+#include "include/cef_life_span_handler.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefLifeSpanHandlerCToCpp
+ : public CefCToCppRefCounted<CefLifeSpanHandlerCToCpp,
+ CefLifeSpanHandler,
+ cef_life_span_handler_t> {
+ public:
+ CefLifeSpanHandlerCToCpp();
+ virtual ~CefLifeSpanHandlerCToCpp();
+
+ // CefLifeSpanHandler methods.
+ bool OnBeforePopup(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const CefString& target_url,
+ const CefString& target_frame_name,
+ WindowOpenDisposition target_disposition,
+ bool user_gesture,
+ const CefPopupFeatures& popupFeatures,
+ CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient>& client,
+ CefBrowserSettings& settings,
+ CefRefPtr<CefDictionaryValue>& extra_info,
+ bool* no_javascript_access) override;
+ void OnAfterCreated(CefRefPtr<CefBrowser> browser) override;
+ bool DoClose(CefRefPtr<CefBrowser> browser) override;
+ void OnBeforeClose(CefRefPtr<CefBrowser> browser) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_LIFE_SPAN_HANDLER_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/list_value_ctocpp.cc b/libcef_dll/ctocpp/list_value_ctocpp.cc
new file mode 100644
index 00000000..76ef3746
--- /dev/null
+++ b/libcef_dll/ctocpp/list_value_ctocpp.cc
@@ -0,0 +1,596 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=84d7a315d04726c8f80067ea2207618d7dfdd798$
+//
+
+#include "libcef_dll/ctocpp/list_value_ctocpp.h"
+#include "libcef_dll/ctocpp/binary_value_ctocpp.h"
+#include "libcef_dll/ctocpp/dictionary_value_ctocpp.h"
+#include "libcef_dll/ctocpp/value_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// STATIC METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefListValue> CefListValue::Create() {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_list_value_t* _retval = cef_list_value_create();
+
+ // Return type: refptr_same
+ return CefListValueCToCpp::Wrap(_retval);
+}
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") bool CefListValueCToCpp::IsValid() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_list_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_valid)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_valid(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefListValueCToCpp::IsOwned() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_list_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_owned)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_owned(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefListValueCToCpp::IsReadOnly() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_list_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_read_only)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_read_only(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefListValueCToCpp::IsSame(CefRefPtr<CefListValue> that) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_list_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_same)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: that; type: refptr_same
+ DCHECK(that.get());
+ if (!that.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->is_same(_struct, CefListValueCToCpp::Unwrap(that));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefListValueCToCpp::IsEqual(CefRefPtr<CefListValue> that) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_list_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_equal)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: that; type: refptr_same
+ DCHECK(that.get());
+ if (!that.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->is_equal(_struct, CefListValueCToCpp::Unwrap(that));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefListValue> CefListValueCToCpp::Copy() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_list_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, copy)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_list_value_t* _retval = _struct->copy(_struct);
+
+ // Return type: refptr_same
+ return CefListValueCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") bool CefListValueCToCpp::SetSize(size_t size) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_list_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_size)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->set_size(_struct, size);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") size_t CefListValueCToCpp::GetSize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_list_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_size)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ size_t _retval = _struct->get_size(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") bool CefListValueCToCpp::Clear() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_list_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, clear)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->clear(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefListValueCToCpp::Remove(size_t index) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_list_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, remove)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->remove(_struct, index);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CefValueType CefListValueCToCpp::GetType(size_t index) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_list_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_type)) {
+ return VTYPE_INVALID;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_value_type_t _retval = _struct->get_type(_struct, index);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefValue> CefListValueCToCpp::GetValue(size_t index) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_list_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_value)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_value_t* _retval = _struct->get_value(_struct, index);
+
+ // Return type: refptr_same
+ return CefValueCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") bool CefListValueCToCpp::GetBool(size_t index) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_list_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_bool)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_bool(_struct, index);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") int CefListValueCToCpp::GetInt(size_t index) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_list_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_int)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_int(_struct, index);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") double CefListValueCToCpp::GetDouble(size_t index) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_list_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_double)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ double _retval = _struct->get_double(_struct, index);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") CefString CefListValueCToCpp::GetString(size_t index) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_list_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_string)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_string(_struct, index);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefBinaryValue> CefListValueCToCpp::GetBinary(size_t index) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_list_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_binary)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_binary_value_t* _retval = _struct->get_binary(_struct, index);
+
+ // Return type: refptr_same
+ return CefBinaryValueCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefDictionaryValue> CefListValueCToCpp::GetDictionary(size_t index) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_list_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_dictionary)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_dictionary_value_t* _retval = _struct->get_dictionary(_struct, index);
+
+ // Return type: refptr_same
+ return CefDictionaryValueCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefListValue> CefListValueCToCpp::GetList(size_t index) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_list_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_list)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_list_value_t* _retval = _struct->get_list(_struct, index);
+
+ // Return type: refptr_same
+ return CefListValueCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefListValueCToCpp::SetValue(size_t index, CefRefPtr<CefValue> value) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_list_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_value)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: value; type: refptr_same
+ DCHECK(value.get());
+ if (!value.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval =
+ _struct->set_value(_struct, index, CefValueCToCpp::Unwrap(value));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefListValueCToCpp::SetNull(size_t index) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_list_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_null)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->set_null(_struct, index);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefListValueCToCpp::SetBool(size_t index, bool value) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_list_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_bool)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->set_bool(_struct, index, value);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefListValueCToCpp::SetInt(size_t index, int value) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_list_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_int)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->set_int(_struct, index, value);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefListValueCToCpp::SetDouble(size_t index, double value) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_list_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_double)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->set_double(_struct, index, value);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefListValueCToCpp::SetString(size_t index, const CefString& value) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_list_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_string)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: value
+
+ // Execute
+ int _retval = _struct->set_string(_struct, index, value.GetStruct());
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefListValueCToCpp::SetBinary(size_t index,
+ CefRefPtr<CefBinaryValue> value) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_list_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_binary)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: value; type: refptr_same
+ DCHECK(value.get());
+ if (!value.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval =
+ _struct->set_binary(_struct, index, CefBinaryValueCToCpp::Unwrap(value));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefListValueCToCpp::SetDictionary(size_t index,
+ CefRefPtr<CefDictionaryValue> value) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_list_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_dictionary)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: value; type: refptr_same
+ DCHECK(value.get());
+ if (!value.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->set_dictionary(
+ _struct, index, CefDictionaryValueCToCpp::Unwrap(value));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefListValueCToCpp::SetList(size_t index, CefRefPtr<CefListValue> value) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_list_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_list)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: value; type: refptr_same
+ DCHECK(value.get());
+ if (!value.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval =
+ _struct->set_list(_struct, index, CefListValueCToCpp::Unwrap(value));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefListValueCToCpp::CefListValueCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefListValueCToCpp::~CefListValueCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_list_value_t*
+CefCToCppRefCounted<CefListValueCToCpp, CefListValue, cef_list_value_t>::
+ UnwrapDerived(CefWrapperType type, CefListValue* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefListValueCToCpp,
+ CefListValue,
+ cef_list_value_t>::kWrapperType =
+ WT_LIST_VALUE;
diff --git a/libcef_dll/ctocpp/list_value_ctocpp.h b/libcef_dll/ctocpp/list_value_ctocpp.h
new file mode 100644
index 00000000..d09dfb95
--- /dev/null
+++ b/libcef_dll/ctocpp/list_value_ctocpp.h
@@ -0,0 +1,68 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=99b478c698261aa2aaf566b283fc938aacf3b2bf$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_LIST_VALUE_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_LIST_VALUE_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_values_capi.h"
+#include "include/cef_values.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefListValueCToCpp : public CefCToCppRefCounted<CefListValueCToCpp,
+ CefListValue,
+ cef_list_value_t> {
+ public:
+ CefListValueCToCpp();
+ virtual ~CefListValueCToCpp();
+
+ // CefListValue methods.
+ bool IsValid() override;
+ bool IsOwned() override;
+ bool IsReadOnly() override;
+ bool IsSame(CefRefPtr<CefListValue> that) override;
+ bool IsEqual(CefRefPtr<CefListValue> that) override;
+ CefRefPtr<CefListValue> Copy() override;
+ bool SetSize(size_t size) override;
+ size_t GetSize() override;
+ bool Clear() override;
+ bool Remove(size_t index) override;
+ CefValueType GetType(size_t index) override;
+ CefRefPtr<CefValue> GetValue(size_t index) override;
+ bool GetBool(size_t index) override;
+ int GetInt(size_t index) override;
+ double GetDouble(size_t index) override;
+ CefString GetString(size_t index) override;
+ CefRefPtr<CefBinaryValue> GetBinary(size_t index) override;
+ CefRefPtr<CefDictionaryValue> GetDictionary(size_t index) override;
+ CefRefPtr<CefListValue> GetList(size_t index) override;
+ bool SetValue(size_t index, CefRefPtr<CefValue> value) override;
+ bool SetNull(size_t index) override;
+ bool SetBool(size_t index, bool value) override;
+ bool SetInt(size_t index, int value) override;
+ bool SetDouble(size_t index, double value) override;
+ bool SetString(size_t index, const CefString& value) override;
+ bool SetBinary(size_t index, CefRefPtr<CefBinaryValue> value) override;
+ bool SetDictionary(size_t index,
+ CefRefPtr<CefDictionaryValue> value) override;
+ bool SetList(size_t index, CefRefPtr<CefListValue> value) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_LIST_VALUE_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/load_handler_ctocpp.cc b/libcef_dll/ctocpp/load_handler_ctocpp.cc
new file mode 100644
index 00000000..67fd9054
--- /dev/null
+++ b/libcef_dll/ctocpp/load_handler_ctocpp.cc
@@ -0,0 +1,165 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=383c19c3c8f95deb40ca6eac2860b34f52b0a421$
+//
+
+#include "libcef_dll/ctocpp/load_handler_ctocpp.h"
+#include "libcef_dll/cpptoc/browser_cpptoc.h"
+#include "libcef_dll/cpptoc/frame_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+void CefLoadHandlerCToCpp::OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
+ bool isLoading,
+ bool canGoBack,
+ bool canGoForward) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_load_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_loading_state_change)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_loading_state_change(_struct, CefBrowserCppToC::Wrap(browser),
+ isLoading, canGoBack, canGoForward);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefLoadHandlerCToCpp::OnLoadStart(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ TransitionType transition_type) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_load_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_load_start)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+ // Verify param: frame; type: refptr_diff
+ DCHECK(frame.get());
+ if (!frame.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_load_start(_struct, CefBrowserCppToC::Wrap(browser),
+ CefFrameCppToC::Wrap(frame), transition_type);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefLoadHandlerCToCpp::OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int httpStatusCode) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_load_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_load_end)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+ // Verify param: frame; type: refptr_diff
+ DCHECK(frame.get());
+ if (!frame.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_load_end(_struct, CefBrowserCppToC::Wrap(browser),
+ CefFrameCppToC::Wrap(frame), httpStatusCode);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefLoadHandlerCToCpp::OnLoadError(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ ErrorCode errorCode,
+ const CefString& errorText,
+ const CefString& failedUrl) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_load_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_load_error)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+ // Verify param: frame; type: refptr_diff
+ DCHECK(frame.get());
+ if (!frame.get()) {
+ return;
+ }
+ // Verify param: failedUrl; type: string_byref_const
+ DCHECK(!failedUrl.empty());
+ if (failedUrl.empty()) {
+ return;
+ }
+ // Unverified params: errorText
+
+ // Execute
+ _struct->on_load_error(_struct, CefBrowserCppToC::Wrap(browser),
+ CefFrameCppToC::Wrap(frame), errorCode,
+ errorText.GetStruct(), failedUrl.GetStruct());
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefLoadHandlerCToCpp::CefLoadHandlerCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefLoadHandlerCToCpp::~CefLoadHandlerCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_load_handler_t*
+CefCToCppRefCounted<CefLoadHandlerCToCpp, CefLoadHandler, cef_load_handler_t>::
+ UnwrapDerived(CefWrapperType type, CefLoadHandler* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefLoadHandlerCToCpp,
+ CefLoadHandler,
+ cef_load_handler_t>::kWrapperType =
+ WT_LOAD_HANDLER;
diff --git a/libcef_dll/ctocpp/load_handler_ctocpp.h b/libcef_dll/ctocpp/load_handler_ctocpp.h
new file mode 100644
index 00000000..8a6bbff8
--- /dev/null
+++ b/libcef_dll/ctocpp/load_handler_ctocpp.h
@@ -0,0 +1,54 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=d05ba1799ed6cc227ab5d314ce8a96187b7a3069$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_LOAD_HANDLER_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_LOAD_HANDLER_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_load_handler_capi.h"
+#include "include/cef_load_handler.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefLoadHandlerCToCpp : public CefCToCppRefCounted<CefLoadHandlerCToCpp,
+ CefLoadHandler,
+ cef_load_handler_t> {
+ public:
+ CefLoadHandlerCToCpp();
+ virtual ~CefLoadHandlerCToCpp();
+
+ // CefLoadHandler methods.
+ void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
+ bool isLoading,
+ bool canGoBack,
+ bool canGoForward) override;
+ void OnLoadStart(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ TransitionType transition_type) override;
+ void OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int httpStatusCode) override;
+ void OnLoadError(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ ErrorCode errorCode,
+ const CefString& errorText,
+ const CefString& failedUrl) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_LOAD_HANDLER_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/media_access_callback_ctocpp.cc b/libcef_dll/ctocpp/media_access_callback_ctocpp.cc
new file mode 100644
index 00000000..1909dff7
--- /dev/null
+++ b/libcef_dll/ctocpp/media_access_callback_ctocpp.cc
@@ -0,0 +1,73 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=081d829156aaa2d8fbf4dd77c359c6be60f2daf8$
+//
+
+#include "libcef_dll/ctocpp/media_access_callback_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+void CefMediaAccessCallbackCToCpp::Continue(uint32 allowed_permissions) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_media_access_callback_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, cont)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->cont(_struct, allowed_permissions);
+}
+
+NO_SANITIZE("cfi-icall") void CefMediaAccessCallbackCToCpp::Cancel() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_media_access_callback_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, cancel)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->cancel(_struct);
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefMediaAccessCallbackCToCpp::CefMediaAccessCallbackCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefMediaAccessCallbackCToCpp::~CefMediaAccessCallbackCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_media_access_callback_t* CefCToCppRefCounted<
+ CefMediaAccessCallbackCToCpp,
+ CefMediaAccessCallback,
+ cef_media_access_callback_t>::UnwrapDerived(CefWrapperType type,
+ CefMediaAccessCallback* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefMediaAccessCallbackCToCpp,
+ CefMediaAccessCallback,
+ cef_media_access_callback_t>::kWrapperType =
+ WT_MEDIA_ACCESS_CALLBACK;
diff --git a/libcef_dll/ctocpp/media_access_callback_ctocpp.h b/libcef_dll/ctocpp/media_access_callback_ctocpp.h
new file mode 100644
index 00000000..730c3621
--- /dev/null
+++ b/libcef_dll/ctocpp/media_access_callback_ctocpp.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=44c5b964bd7f3953354c90ce10979b8612b05ae8$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_MEDIA_ACCESS_CALLBACK_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_MEDIA_ACCESS_CALLBACK_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_permission_handler_capi.h"
+#include "include/cef_permission_handler.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefMediaAccessCallbackCToCpp
+ : public CefCToCppRefCounted<CefMediaAccessCallbackCToCpp,
+ CefMediaAccessCallback,
+ cef_media_access_callback_t> {
+ public:
+ CefMediaAccessCallbackCToCpp();
+ virtual ~CefMediaAccessCallbackCToCpp();
+
+ // CefMediaAccessCallback methods.
+ void Continue(uint32 allowed_permissions) override;
+ void Cancel() override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_MEDIA_ACCESS_CALLBACK_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/media_observer_ctocpp.cc b/libcef_dll/ctocpp/media_observer_ctocpp.cc
new file mode 100644
index 00000000..da269362
--- /dev/null
+++ b/libcef_dll/ctocpp/media_observer_ctocpp.cc
@@ -0,0 +1,167 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=b3e6ce9639724749d0077dbc8f6702afba83f561$
+//
+
+#include "libcef_dll/ctocpp/media_observer_ctocpp.h"
+#include "libcef_dll/cpptoc/media_route_cpptoc.h"
+#include "libcef_dll/cpptoc/media_sink_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+void CefMediaObserverCToCpp::OnSinks(
+ const std::vector<CefRefPtr<CefMediaSink>>& sinks) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_media_observer_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_sinks)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Translate param: sinks; type: refptr_vec_diff_byref_const
+ const size_t sinksCount = sinks.size();
+ cef_media_sink_t** sinksList = NULL;
+ if (sinksCount > 0) {
+ sinksList = new cef_media_sink_t*[sinksCount];
+ DCHECK(sinksList);
+ if (sinksList) {
+ for (size_t i = 0; i < sinksCount; ++i) {
+ sinksList[i] = CefMediaSinkCppToC::Wrap(sinks[i]);
+ }
+ }
+ }
+
+ // Execute
+ _struct->on_sinks(_struct, sinksCount, sinksList);
+
+ // Restore param:sinks; type: refptr_vec_diff_byref_const
+ if (sinksList) {
+ delete[] sinksList;
+ }
+}
+
+NO_SANITIZE("cfi-icall")
+void CefMediaObserverCToCpp::OnRoutes(
+ const std::vector<CefRefPtr<CefMediaRoute>>& routes) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_media_observer_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_routes)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Translate param: routes; type: refptr_vec_diff_byref_const
+ const size_t routesCount = routes.size();
+ cef_media_route_t** routesList = NULL;
+ if (routesCount > 0) {
+ routesList = new cef_media_route_t*[routesCount];
+ DCHECK(routesList);
+ if (routesList) {
+ for (size_t i = 0; i < routesCount; ++i) {
+ routesList[i] = CefMediaRouteCppToC::Wrap(routes[i]);
+ }
+ }
+ }
+
+ // Execute
+ _struct->on_routes(_struct, routesCount, routesList);
+
+ // Restore param:routes; type: refptr_vec_diff_byref_const
+ if (routesList) {
+ delete[] routesList;
+ }
+}
+
+NO_SANITIZE("cfi-icall")
+void CefMediaObserverCToCpp::OnRouteStateChanged(CefRefPtr<CefMediaRoute> route,
+ ConnectionState state) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_media_observer_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_route_state_changed)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: route; type: refptr_diff
+ DCHECK(route.get());
+ if (!route.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_route_state_changed(_struct, CefMediaRouteCppToC::Wrap(route),
+ state);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefMediaObserverCToCpp::OnRouteMessageReceived(
+ CefRefPtr<CefMediaRoute> route,
+ const void* message,
+ size_t message_size) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_media_observer_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_route_message_received)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: route; type: refptr_diff
+ DCHECK(route.get());
+ if (!route.get()) {
+ return;
+ }
+ // Verify param: message; type: simple_byaddr
+ DCHECK(message);
+ if (!message) {
+ return;
+ }
+
+ // Execute
+ _struct->on_route_message_received(_struct, CefMediaRouteCppToC::Wrap(route),
+ message, message_size);
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefMediaObserverCToCpp::CefMediaObserverCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefMediaObserverCToCpp::~CefMediaObserverCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_media_observer_t*
+CefCToCppRefCounted<CefMediaObserverCToCpp,
+ CefMediaObserver,
+ cef_media_observer_t>::UnwrapDerived(CefWrapperType type,
+ CefMediaObserver* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefMediaObserverCToCpp,
+ CefMediaObserver,
+ cef_media_observer_t>::kWrapperType =
+ WT_MEDIA_OBSERVER;
diff --git a/libcef_dll/ctocpp/media_observer_ctocpp.h b/libcef_dll/ctocpp/media_observer_ctocpp.h
new file mode 100644
index 00000000..45ded099
--- /dev/null
+++ b/libcef_dll/ctocpp/media_observer_ctocpp.h
@@ -0,0 +1,48 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=af2c09e08b7a2c8c89fdbe314c074fe0d7f825cf$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_MEDIA_OBSERVER_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_MEDIA_OBSERVER_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include <vector>
+#include "include/capi/cef_media_router_capi.h"
+#include "include/cef_media_router.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefMediaObserverCToCpp
+ : public CefCToCppRefCounted<CefMediaObserverCToCpp,
+ CefMediaObserver,
+ cef_media_observer_t> {
+ public:
+ CefMediaObserverCToCpp();
+ virtual ~CefMediaObserverCToCpp();
+
+ // CefMediaObserver methods.
+ void OnSinks(const std::vector<CefRefPtr<CefMediaSink>>& sinks) override;
+ void OnRoutes(const std::vector<CefRefPtr<CefMediaRoute>>& routes) override;
+ void OnRouteStateChanged(CefRefPtr<CefMediaRoute> route,
+ ConnectionState state) override;
+ void OnRouteMessageReceived(CefRefPtr<CefMediaRoute> route,
+ const void* message,
+ size_t message_size) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_MEDIA_OBSERVER_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/media_route_create_callback_ctocpp.cc b/libcef_dll/ctocpp/media_route_create_callback_ctocpp.cc
new file mode 100644
index 00000000..6eb5d160
--- /dev/null
+++ b/libcef_dll/ctocpp/media_route_create_callback_ctocpp.cc
@@ -0,0 +1,67 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=f422501ac723c377df6b2ff14c8f0452de3ea055$
+//
+
+#include "libcef_dll/ctocpp/media_route_create_callback_ctocpp.h"
+#include "libcef_dll/cpptoc/media_route_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+void CefMediaRouteCreateCallbackCToCpp::OnMediaRouteCreateFinished(
+ RouteCreateResult result,
+ const CefString& error,
+ CefRefPtr<CefMediaRoute> route) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_media_route_create_callback_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_media_route_create_finished)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: error, route
+
+ // Execute
+ _struct->on_media_route_create_finished(_struct, result, error.GetStruct(),
+ CefMediaRouteCppToC::Wrap(route));
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefMediaRouteCreateCallbackCToCpp::CefMediaRouteCreateCallbackCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefMediaRouteCreateCallbackCToCpp::~CefMediaRouteCreateCallbackCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_media_route_create_callback_t*
+CefCToCppRefCounted<CefMediaRouteCreateCallbackCToCpp,
+ CefMediaRouteCreateCallback,
+ cef_media_route_create_callback_t>::
+ UnwrapDerived(CefWrapperType type, CefMediaRouteCreateCallback* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCToCppRefCounted<CefMediaRouteCreateCallbackCToCpp,
+ CefMediaRouteCreateCallback,
+ cef_media_route_create_callback_t>::kWrapperType =
+ WT_MEDIA_ROUTE_CREATE_CALLBACK;
diff --git a/libcef_dll/ctocpp/media_route_create_callback_ctocpp.h b/libcef_dll/ctocpp/media_route_create_callback_ctocpp.h
new file mode 100644
index 00000000..d590439d
--- /dev/null
+++ b/libcef_dll/ctocpp/media_route_create_callback_ctocpp.h
@@ -0,0 +1,43 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=ecf8319d38a7ef9e5b5730c55ca299b3a8056018$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_MEDIA_ROUTE_CREATE_CALLBACK_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_MEDIA_ROUTE_CREATE_CALLBACK_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_media_router_capi.h"
+#include "include/cef_media_router.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefMediaRouteCreateCallbackCToCpp
+ : public CefCToCppRefCounted<CefMediaRouteCreateCallbackCToCpp,
+ CefMediaRouteCreateCallback,
+ cef_media_route_create_callback_t> {
+ public:
+ CefMediaRouteCreateCallbackCToCpp();
+ virtual ~CefMediaRouteCreateCallbackCToCpp();
+
+ // CefMediaRouteCreateCallback methods.
+ void OnMediaRouteCreateFinished(RouteCreateResult result,
+ const CefString& error,
+ CefRefPtr<CefMediaRoute> route) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_MEDIA_ROUTE_CREATE_CALLBACK_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/media_route_ctocpp.cc b/libcef_dll/ctocpp/media_route_ctocpp.cc
new file mode 100644
index 00000000..3b8b9d50
--- /dev/null
+++ b/libcef_dll/ctocpp/media_route_ctocpp.cc
@@ -0,0 +1,135 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=d46a5856b98d5c55d4eb2eb6caf9d793b2519f02$
+//
+
+#include "libcef_dll/ctocpp/media_route_ctocpp.h"
+#include "libcef_dll/ctocpp/media_sink_ctocpp.h"
+#include "libcef_dll/ctocpp/media_source_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") CefString CefMediaRouteCToCpp::GetId() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_media_route_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_id)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_id(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefMediaSource> CefMediaRouteCToCpp::GetSource() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_media_route_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_source)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_media_source_t* _retval = _struct->get_source(_struct);
+
+ // Return type: refptr_same
+ return CefMediaSourceCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefMediaSink> CefMediaRouteCToCpp::GetSink() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_media_route_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_sink)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_media_sink_t* _retval = _struct->get_sink(_struct);
+
+ // Return type: refptr_same
+ return CefMediaSinkCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefMediaRouteCToCpp::SendRouteMessage(const void* message,
+ size_t message_size) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_media_route_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, send_route_message)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: message; type: simple_byaddr
+ DCHECK(message);
+ if (!message) {
+ return;
+ }
+
+ // Execute
+ _struct->send_route_message(_struct, message, message_size);
+}
+
+NO_SANITIZE("cfi-icall") void CefMediaRouteCToCpp::Terminate() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_media_route_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, terminate)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->terminate(_struct);
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefMediaRouteCToCpp::CefMediaRouteCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefMediaRouteCToCpp::~CefMediaRouteCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_media_route_t*
+CefCToCppRefCounted<CefMediaRouteCToCpp, CefMediaRoute, cef_media_route_t>::
+ UnwrapDerived(CefWrapperType type, CefMediaRoute* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefMediaRouteCToCpp,
+ CefMediaRoute,
+ cef_media_route_t>::kWrapperType =
+ WT_MEDIA_ROUTE;
diff --git a/libcef_dll/ctocpp/media_route_ctocpp.h b/libcef_dll/ctocpp/media_route_ctocpp.h
new file mode 100644
index 00000000..a5742664
--- /dev/null
+++ b/libcef_dll/ctocpp/media_route_ctocpp.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=c8f6db85d4b577c287a587a72aa11d6e10f55d78$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_MEDIA_ROUTE_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_MEDIA_ROUTE_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_media_router_capi.h"
+#include "include/cef_media_router.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefMediaRouteCToCpp : public CefCToCppRefCounted<CefMediaRouteCToCpp,
+ CefMediaRoute,
+ cef_media_route_t> {
+ public:
+ CefMediaRouteCToCpp();
+ virtual ~CefMediaRouteCToCpp();
+
+ // CefMediaRoute methods.
+ CefString GetId() override;
+ CefRefPtr<CefMediaSource> GetSource() override;
+ CefRefPtr<CefMediaSink> GetSink() override;
+ void SendRouteMessage(const void* message, size_t message_size) override;
+ void Terminate() override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_MEDIA_ROUTE_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/media_router_ctocpp.cc b/libcef_dll/ctocpp/media_router_ctocpp.cc
new file mode 100644
index 00000000..a3907ee2
--- /dev/null
+++ b/libcef_dll/ctocpp/media_router_ctocpp.cc
@@ -0,0 +1,182 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=3c1bf66c510b9f2d4a63bb400b37b93e9f555349$
+//
+
+#include "libcef_dll/ctocpp/media_router_ctocpp.h"
+#include "libcef_dll/cpptoc/completion_callback_cpptoc.h"
+#include "libcef_dll/cpptoc/media_observer_cpptoc.h"
+#include "libcef_dll/cpptoc/media_route_create_callback_cpptoc.h"
+#include "libcef_dll/ctocpp/media_sink_ctocpp.h"
+#include "libcef_dll/ctocpp/media_source_ctocpp.h"
+#include "libcef_dll/ctocpp/registration_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// STATIC METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefMediaRouter> CefMediaRouter::GetGlobalMediaRouter(
+ CefRefPtr<CefCompletionCallback> callback) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: callback
+
+ // Execute
+ cef_media_router_t* _retval =
+ cef_media_router_get_global(CefCompletionCallbackCppToC::Wrap(callback));
+
+ // Return type: refptr_same
+ return CefMediaRouterCToCpp::Wrap(_retval);
+}
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefRegistration> CefMediaRouterCToCpp::AddObserver(
+ CefRefPtr<CefMediaObserver> observer) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_media_router_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, add_observer)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: observer; type: refptr_diff
+ DCHECK(observer.get());
+ if (!observer.get()) {
+ return nullptr;
+ }
+
+ // Execute
+ cef_registration_t* _retval =
+ _struct->add_observer(_struct, CefMediaObserverCppToC::Wrap(observer));
+
+ // Return type: refptr_same
+ return CefRegistrationCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefMediaSource> CefMediaRouterCToCpp::GetSource(
+ const CefString& urn) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_media_router_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_source)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: urn; type: string_byref_const
+ DCHECK(!urn.empty());
+ if (urn.empty()) {
+ return nullptr;
+ }
+
+ // Execute
+ cef_media_source_t* _retval = _struct->get_source(_struct, urn.GetStruct());
+
+ // Return type: refptr_same
+ return CefMediaSourceCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") void CefMediaRouterCToCpp::NotifyCurrentSinks() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_media_router_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, notify_current_sinks)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->notify_current_sinks(_struct);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefMediaRouterCToCpp::CreateRoute(
+ CefRefPtr<CefMediaSource> source,
+ CefRefPtr<CefMediaSink> sink,
+ CefRefPtr<CefMediaRouteCreateCallback> callback) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_media_router_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, create_route)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: source; type: refptr_same
+ DCHECK(source.get());
+ if (!source.get()) {
+ return;
+ }
+ // Verify param: sink; type: refptr_same
+ DCHECK(sink.get());
+ if (!sink.get()) {
+ return;
+ }
+ // Verify param: callback; type: refptr_diff
+ DCHECK(callback.get());
+ if (!callback.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->create_route(_struct, CefMediaSourceCToCpp::Unwrap(source),
+ CefMediaSinkCToCpp::Unwrap(sink),
+ CefMediaRouteCreateCallbackCppToC::Wrap(callback));
+}
+
+NO_SANITIZE("cfi-icall") void CefMediaRouterCToCpp::NotifyCurrentRoutes() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_media_router_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, notify_current_routes)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->notify_current_routes(_struct);
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefMediaRouterCToCpp::CefMediaRouterCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefMediaRouterCToCpp::~CefMediaRouterCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_media_router_t*
+CefCToCppRefCounted<CefMediaRouterCToCpp, CefMediaRouter, cef_media_router_t>::
+ UnwrapDerived(CefWrapperType type, CefMediaRouter* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefMediaRouterCToCpp,
+ CefMediaRouter,
+ cef_media_router_t>::kWrapperType =
+ WT_MEDIA_ROUTER;
diff --git a/libcef_dll/ctocpp/media_router_ctocpp.h b/libcef_dll/ctocpp/media_router_ctocpp.h
new file mode 100644
index 00000000..c48028da
--- /dev/null
+++ b/libcef_dll/ctocpp/media_router_ctocpp.h
@@ -0,0 +1,47 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=ef079450730cdf1b8720a84d83b361c6423a091a$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_MEDIA_ROUTER_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_MEDIA_ROUTER_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_media_router_capi.h"
+#include "include/cef_media_router.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefMediaRouterCToCpp : public CefCToCppRefCounted<CefMediaRouterCToCpp,
+ CefMediaRouter,
+ cef_media_router_t> {
+ public:
+ CefMediaRouterCToCpp();
+ virtual ~CefMediaRouterCToCpp();
+
+ // CefMediaRouter methods.
+ CefRefPtr<CefRegistration> AddObserver(
+ CefRefPtr<CefMediaObserver> observer) override;
+ CefRefPtr<CefMediaSource> GetSource(const CefString& urn) override;
+ void NotifyCurrentSinks() override;
+ void CreateRoute(CefRefPtr<CefMediaSource> source,
+ CefRefPtr<CefMediaSink> sink,
+ CefRefPtr<CefMediaRouteCreateCallback> callback) override;
+ void NotifyCurrentRoutes() override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_MEDIA_ROUTER_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/media_sink_ctocpp.cc b/libcef_dll/ctocpp/media_sink_ctocpp.cc
new file mode 100644
index 00000000..6fb9833f
--- /dev/null
+++ b/libcef_dll/ctocpp/media_sink_ctocpp.cc
@@ -0,0 +1,182 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=6a7b7f88d045e2827c989a39368741a8d6064da4$
+//
+
+#include "libcef_dll/ctocpp/media_sink_ctocpp.h"
+#include "libcef_dll/cpptoc/media_sink_device_info_callback_cpptoc.h"
+#include "libcef_dll/ctocpp/media_source_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") CefString CefMediaSinkCToCpp::GetId() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_media_sink_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_id)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_id(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") CefString CefMediaSinkCToCpp::GetName() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_media_sink_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_name)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_name(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+CefMediaSink::IconType CefMediaSinkCToCpp::GetIconType() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_media_sink_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_icon_type)) {
+ return CEF_MSIT_GENERIC;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_media_sink_icon_type_t _retval = _struct->get_icon_type(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefMediaSinkCToCpp::GetDeviceInfo(
+ CefRefPtr<CefMediaSinkDeviceInfoCallback> callback) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_media_sink_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_device_info)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: callback; type: refptr_diff
+ DCHECK(callback.get());
+ if (!callback.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->get_device_info(
+ _struct, CefMediaSinkDeviceInfoCallbackCppToC::Wrap(callback));
+}
+
+NO_SANITIZE("cfi-icall") bool CefMediaSinkCToCpp::IsCastSink() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_media_sink_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_cast_sink)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_cast_sink(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefMediaSinkCToCpp::IsDialSink() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_media_sink_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_dial_sink)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_dial_sink(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefMediaSinkCToCpp::IsCompatibleWith(CefRefPtr<CefMediaSource> source) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_media_sink_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_compatible_with)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: source; type: refptr_same
+ DCHECK(source.get());
+ if (!source.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->is_compatible_with(
+ _struct, CefMediaSourceCToCpp::Unwrap(source));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefMediaSinkCToCpp::CefMediaSinkCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefMediaSinkCToCpp::~CefMediaSinkCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_media_sink_t*
+CefCToCppRefCounted<CefMediaSinkCToCpp, CefMediaSink, cef_media_sink_t>::
+ UnwrapDerived(CefWrapperType type, CefMediaSink* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefMediaSinkCToCpp,
+ CefMediaSink,
+ cef_media_sink_t>::kWrapperType =
+ WT_MEDIA_SINK;
diff --git a/libcef_dll/ctocpp/media_sink_ctocpp.h b/libcef_dll/ctocpp/media_sink_ctocpp.h
new file mode 100644
index 00000000..80e03936
--- /dev/null
+++ b/libcef_dll/ctocpp/media_sink_ctocpp.h
@@ -0,0 +1,47 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=f1a192a4341ed6fe0d4b6f8b065b372401e0f055$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_MEDIA_SINK_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_MEDIA_SINK_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_media_router_capi.h"
+#include "include/cef_media_router.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefMediaSinkCToCpp : public CefCToCppRefCounted<CefMediaSinkCToCpp,
+ CefMediaSink,
+ cef_media_sink_t> {
+ public:
+ CefMediaSinkCToCpp();
+ virtual ~CefMediaSinkCToCpp();
+
+ // CefMediaSink methods.
+ CefString GetId() override;
+ CefString GetName() override;
+ IconType GetIconType() override;
+ void GetDeviceInfo(
+ CefRefPtr<CefMediaSinkDeviceInfoCallback> callback) override;
+ bool IsCastSink() override;
+ bool IsDialSink() override;
+ bool IsCompatibleWith(CefRefPtr<CefMediaSource> source) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_MEDIA_SINK_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/media_sink_device_info_callback_ctocpp.cc b/libcef_dll/ctocpp/media_sink_device_info_callback_ctocpp.cc
new file mode 100644
index 00000000..8b625028
--- /dev/null
+++ b/libcef_dll/ctocpp/media_sink_device_info_callback_ctocpp.cc
@@ -0,0 +1,61 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=20d3c82d71ea1ba068d4b86487b9f24ae0bdaa29$
+//
+
+#include "libcef_dll/ctocpp/media_sink_device_info_callback_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+void CefMediaSinkDeviceInfoCallbackCToCpp::OnMediaSinkDeviceInfo(
+ const CefMediaSinkDeviceInfo& device_info) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_media_sink_device_info_callback_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_media_sink_device_info)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->on_media_sink_device_info(_struct, &device_info);
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefMediaSinkDeviceInfoCallbackCToCpp::CefMediaSinkDeviceInfoCallbackCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefMediaSinkDeviceInfoCallbackCToCpp::~CefMediaSinkDeviceInfoCallbackCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_media_sink_device_info_callback_t*
+CefCToCppRefCounted<CefMediaSinkDeviceInfoCallbackCToCpp,
+ CefMediaSinkDeviceInfoCallback,
+ cef_media_sink_device_info_callback_t>::
+ UnwrapDerived(CefWrapperType type, CefMediaSinkDeviceInfoCallback* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCToCppRefCounted<CefMediaSinkDeviceInfoCallbackCToCpp,
+ CefMediaSinkDeviceInfoCallback,
+ cef_media_sink_device_info_callback_t>::kWrapperType =
+ WT_MEDIA_SINK_DEVICE_INFO_CALLBACK;
diff --git a/libcef_dll/ctocpp/media_sink_device_info_callback_ctocpp.h b/libcef_dll/ctocpp/media_sink_device_info_callback_ctocpp.h
new file mode 100644
index 00000000..06395235
--- /dev/null
+++ b/libcef_dll/ctocpp/media_sink_device_info_callback_ctocpp.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=4f2660ef656d3041a8b0905855d0149b299d3c7c$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_MEDIA_SINK_DEVICE_INFO_CALLBACK_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_MEDIA_SINK_DEVICE_INFO_CALLBACK_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_media_router_capi.h"
+#include "include/cef_media_router.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefMediaSinkDeviceInfoCallbackCToCpp
+ : public CefCToCppRefCounted<CefMediaSinkDeviceInfoCallbackCToCpp,
+ CefMediaSinkDeviceInfoCallback,
+ cef_media_sink_device_info_callback_t> {
+ public:
+ CefMediaSinkDeviceInfoCallbackCToCpp();
+ virtual ~CefMediaSinkDeviceInfoCallbackCToCpp();
+
+ // CefMediaSinkDeviceInfoCallback methods.
+ void OnMediaSinkDeviceInfo(
+ const CefMediaSinkDeviceInfo& device_info) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_MEDIA_SINK_DEVICE_INFO_CALLBACK_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/media_source_ctocpp.cc b/libcef_dll/ctocpp/media_source_ctocpp.cc
new file mode 100644
index 00000000..0e2b44f4
--- /dev/null
+++ b/libcef_dll/ctocpp/media_source_ctocpp.cc
@@ -0,0 +1,95 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=4ef592680d7650fb636a997f127d3c8e54d6c450$
+//
+
+#include "libcef_dll/ctocpp/media_source_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") CefString CefMediaSourceCToCpp::GetId() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_media_source_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_id)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_id(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") bool CefMediaSourceCToCpp::IsCastSource() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_media_source_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_cast_source)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_cast_source(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefMediaSourceCToCpp::IsDialSource() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_media_source_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_dial_source)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_dial_source(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefMediaSourceCToCpp::CefMediaSourceCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefMediaSourceCToCpp::~CefMediaSourceCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_media_source_t*
+CefCToCppRefCounted<CefMediaSourceCToCpp, CefMediaSource, cef_media_source_t>::
+ UnwrapDerived(CefWrapperType type, CefMediaSource* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefMediaSourceCToCpp,
+ CefMediaSource,
+ cef_media_source_t>::kWrapperType =
+ WT_MEDIA_SOURCE;
diff --git a/libcef_dll/ctocpp/media_source_ctocpp.h b/libcef_dll/ctocpp/media_source_ctocpp.h
new file mode 100644
index 00000000..743c8131
--- /dev/null
+++ b/libcef_dll/ctocpp/media_source_ctocpp.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=36c26e21479231ade66738aee8f10c01f9d0cd22$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_MEDIA_SOURCE_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_MEDIA_SOURCE_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_media_router_capi.h"
+#include "include/cef_media_router.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefMediaSourceCToCpp : public CefCToCppRefCounted<CefMediaSourceCToCpp,
+ CefMediaSource,
+ cef_media_source_t> {
+ public:
+ CefMediaSourceCToCpp();
+ virtual ~CefMediaSourceCToCpp();
+
+ // CefMediaSource methods.
+ CefString GetId() override;
+ bool IsCastSource() override;
+ bool IsDialSource() override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_MEDIA_SOURCE_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/menu_model_ctocpp.cc b/libcef_dll/ctocpp/menu_model_ctocpp.cc
new file mode 100644
index 00000000..13beebbd
--- /dev/null
+++ b/libcef_dll/ctocpp/menu_model_ctocpp.cc
@@ -0,0 +1,1206 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=04b75e77074493307543f443a11d0b3ffade1ff8$
+//
+
+#include "libcef_dll/ctocpp/menu_model_ctocpp.h"
+#include "libcef_dll/cpptoc/menu_model_delegate_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// STATIC METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefMenuModel> CefMenuModel::CreateMenuModel(
+ CefRefPtr<CefMenuModelDelegate> delegate) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: delegate; type: refptr_diff
+ DCHECK(delegate.get());
+ if (!delegate.get()) {
+ return nullptr;
+ }
+
+ // Execute
+ cef_menu_model_t* _retval =
+ cef_menu_model_create(CefMenuModelDelegateCppToC::Wrap(delegate));
+
+ // Return type: refptr_same
+ return CefMenuModelCToCpp::Wrap(_retval);
+}
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") bool CefMenuModelCToCpp::IsSubMenu() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_sub_menu)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_sub_menu(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefMenuModelCToCpp::Clear() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, clear)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->clear(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") size_t CefMenuModelCToCpp::GetCount() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_count)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ size_t _retval = _struct->get_count(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") bool CefMenuModelCToCpp::AddSeparator() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, add_separator)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->add_separator(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefMenuModelCToCpp::AddItem(int command_id, const CefString& label) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, add_item)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: label; type: string_byref_const
+ DCHECK(!label.empty());
+ if (label.empty()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->add_item(_struct, command_id, label.GetStruct());
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefMenuModelCToCpp::AddCheckItem(int command_id, const CefString& label) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, add_check_item)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: label; type: string_byref_const
+ DCHECK(!label.empty());
+ if (label.empty()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->add_check_item(_struct, command_id, label.GetStruct());
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefMenuModelCToCpp::AddRadioItem(int command_id,
+ const CefString& label,
+ int group_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, add_radio_item)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: label; type: string_byref_const
+ DCHECK(!label.empty());
+ if (label.empty()) {
+ return false;
+ }
+
+ // Execute
+ int _retval =
+ _struct->add_radio_item(_struct, command_id, label.GetStruct(), group_id);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefMenuModel> CefMenuModelCToCpp::AddSubMenu(int command_id,
+ const CefString& label) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, add_sub_menu)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: label; type: string_byref_const
+ DCHECK(!label.empty());
+ if (label.empty()) {
+ return nullptr;
+ }
+
+ // Execute
+ cef_menu_model_t* _retval =
+ _struct->add_sub_menu(_struct, command_id, label.GetStruct());
+
+ // Return type: refptr_same
+ return CefMenuModelCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefMenuModelCToCpp::InsertSeparatorAt(size_t index) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, insert_separator_at)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->insert_separator_at(_struct, index);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefMenuModelCToCpp::InsertItemAt(size_t index,
+ int command_id,
+ const CefString& label) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, insert_item_at)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: label; type: string_byref_const
+ DCHECK(!label.empty());
+ if (label.empty()) {
+ return false;
+ }
+
+ // Execute
+ int _retval =
+ _struct->insert_item_at(_struct, index, command_id, label.GetStruct());
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefMenuModelCToCpp::InsertCheckItemAt(size_t index,
+ int command_id,
+ const CefString& label) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, insert_check_item_at)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: label; type: string_byref_const
+ DCHECK(!label.empty());
+ if (label.empty()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->insert_check_item_at(_struct, index, command_id,
+ label.GetStruct());
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefMenuModelCToCpp::InsertRadioItemAt(size_t index,
+ int command_id,
+ const CefString& label,
+ int group_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, insert_radio_item_at)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: label; type: string_byref_const
+ DCHECK(!label.empty());
+ if (label.empty()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->insert_radio_item_at(_struct, index, command_id,
+ label.GetStruct(), group_id);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefMenuModel> CefMenuModelCToCpp::InsertSubMenuAt(
+ size_t index,
+ int command_id,
+ const CefString& label) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, insert_sub_menu_at)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: label; type: string_byref_const
+ DCHECK(!label.empty());
+ if (label.empty()) {
+ return nullptr;
+ }
+
+ // Execute
+ cef_menu_model_t* _retval = _struct->insert_sub_menu_at(
+ _struct, index, command_id, label.GetStruct());
+
+ // Return type: refptr_same
+ return CefMenuModelCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") bool CefMenuModelCToCpp::Remove(int command_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, remove)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->remove(_struct, command_id);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefMenuModelCToCpp::RemoveAt(size_t index) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, remove_at)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->remove_at(_struct, index);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") int CefMenuModelCToCpp::GetIndexOf(int command_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_index_of)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_index_of(_struct, command_id);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") int CefMenuModelCToCpp::GetCommandIdAt(size_t index) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_command_id_at)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_command_id_at(_struct, index);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefMenuModelCToCpp::SetCommandIdAt(size_t index, int command_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_command_id_at)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->set_command_id_at(_struct, index, command_id);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CefString CefMenuModelCToCpp::GetLabel(int command_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_label)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_label(_struct, command_id);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+CefString CefMenuModelCToCpp::GetLabelAt(size_t index) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_label_at)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_label_at(_struct, index);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefMenuModelCToCpp::SetLabel(int command_id, const CefString& label) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_label)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: label; type: string_byref_const
+ DCHECK(!label.empty());
+ if (label.empty()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->set_label(_struct, command_id, label.GetStruct());
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefMenuModelCToCpp::SetLabelAt(size_t index, const CefString& label) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_label_at)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: label; type: string_byref_const
+ DCHECK(!label.empty());
+ if (label.empty()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->set_label_at(_struct, index, label.GetStruct());
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CefMenuModel::MenuItemType CefMenuModelCToCpp::GetType(int command_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_type)) {
+ return MENUITEMTYPE_NONE;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_menu_item_type_t _retval = _struct->get_type(_struct, command_id);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CefMenuModel::MenuItemType CefMenuModelCToCpp::GetTypeAt(size_t index) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_type_at)) {
+ return MENUITEMTYPE_NONE;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_menu_item_type_t _retval = _struct->get_type_at(_struct, index);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") int CefMenuModelCToCpp::GetGroupId(int command_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_group_id)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_group_id(_struct, command_id);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") int CefMenuModelCToCpp::GetGroupIdAt(size_t index) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_group_id_at)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_group_id_at(_struct, index);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefMenuModelCToCpp::SetGroupId(int command_id, int group_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_group_id)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->set_group_id(_struct, command_id, group_id);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefMenuModelCToCpp::SetGroupIdAt(size_t index, int group_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_group_id_at)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->set_group_id_at(_struct, index, group_id);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefMenuModel> CefMenuModelCToCpp::GetSubMenu(int command_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_sub_menu)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_menu_model_t* _retval = _struct->get_sub_menu(_struct, command_id);
+
+ // Return type: refptr_same
+ return CefMenuModelCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefMenuModel> CefMenuModelCToCpp::GetSubMenuAt(size_t index) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_sub_menu_at)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_menu_model_t* _retval = _struct->get_sub_menu_at(_struct, index);
+
+ // Return type: refptr_same
+ return CefMenuModelCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") bool CefMenuModelCToCpp::IsVisible(int command_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_visible)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_visible(_struct, command_id);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefMenuModelCToCpp::IsVisibleAt(size_t index) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_visible_at)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_visible_at(_struct, index);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefMenuModelCToCpp::SetVisible(int command_id, bool visible) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_visible)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->set_visible(_struct, command_id, visible);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefMenuModelCToCpp::SetVisibleAt(size_t index, bool visible) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_visible_at)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->set_visible_at(_struct, index, visible);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefMenuModelCToCpp::IsEnabled(int command_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_enabled)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_enabled(_struct, command_id);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefMenuModelCToCpp::IsEnabledAt(size_t index) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_enabled_at)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_enabled_at(_struct, index);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefMenuModelCToCpp::SetEnabled(int command_id, bool enabled) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_enabled)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->set_enabled(_struct, command_id, enabled);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefMenuModelCToCpp::SetEnabledAt(size_t index, bool enabled) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_enabled_at)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->set_enabled_at(_struct, index, enabled);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefMenuModelCToCpp::IsChecked(int command_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_checked)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_checked(_struct, command_id);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefMenuModelCToCpp::IsCheckedAt(size_t index) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_checked_at)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_checked_at(_struct, index);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefMenuModelCToCpp::SetChecked(int command_id, bool checked) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_checked)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->set_checked(_struct, command_id, checked);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefMenuModelCToCpp::SetCheckedAt(size_t index, bool checked) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_checked_at)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->set_checked_at(_struct, index, checked);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefMenuModelCToCpp::HasAccelerator(int command_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, has_accelerator)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->has_accelerator(_struct, command_id);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefMenuModelCToCpp::HasAcceleratorAt(size_t index) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, has_accelerator_at)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->has_accelerator_at(_struct, index);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefMenuModelCToCpp::SetAccelerator(int command_id,
+ int key_code,
+ bool shift_pressed,
+ bool ctrl_pressed,
+ bool alt_pressed) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_accelerator)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->set_accelerator(
+ _struct, command_id, key_code, shift_pressed, ctrl_pressed, alt_pressed);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefMenuModelCToCpp::SetAcceleratorAt(size_t index,
+ int key_code,
+ bool shift_pressed,
+ bool ctrl_pressed,
+ bool alt_pressed) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_accelerator_at)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->set_accelerator_at(
+ _struct, index, key_code, shift_pressed, ctrl_pressed, alt_pressed);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefMenuModelCToCpp::RemoveAccelerator(int command_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, remove_accelerator)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->remove_accelerator(_struct, command_id);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefMenuModelCToCpp::RemoveAcceleratorAt(size_t index) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, remove_accelerator_at)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->remove_accelerator_at(_struct, index);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefMenuModelCToCpp::GetAccelerator(int command_id,
+ int& key_code,
+ bool& shift_pressed,
+ bool& ctrl_pressed,
+ bool& alt_pressed) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_accelerator)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Translate param: shift_pressed; type: bool_byref
+ int shift_pressedInt = shift_pressed;
+ // Translate param: ctrl_pressed; type: bool_byref
+ int ctrl_pressedInt = ctrl_pressed;
+ // Translate param: alt_pressed; type: bool_byref
+ int alt_pressedInt = alt_pressed;
+
+ // Execute
+ int _retval = _struct->get_accelerator(_struct, command_id, &key_code,
+ &shift_pressedInt, &ctrl_pressedInt,
+ &alt_pressedInt);
+
+ // Restore param:shift_pressed; type: bool_byref
+ shift_pressed = shift_pressedInt ? true : false;
+ // Restore param:ctrl_pressed; type: bool_byref
+ ctrl_pressed = ctrl_pressedInt ? true : false;
+ // Restore param:alt_pressed; type: bool_byref
+ alt_pressed = alt_pressedInt ? true : false;
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefMenuModelCToCpp::GetAcceleratorAt(size_t index,
+ int& key_code,
+ bool& shift_pressed,
+ bool& ctrl_pressed,
+ bool& alt_pressed) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_accelerator_at)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Translate param: shift_pressed; type: bool_byref
+ int shift_pressedInt = shift_pressed;
+ // Translate param: ctrl_pressed; type: bool_byref
+ int ctrl_pressedInt = ctrl_pressed;
+ // Translate param: alt_pressed; type: bool_byref
+ int alt_pressedInt = alt_pressed;
+
+ // Execute
+ int _retval =
+ _struct->get_accelerator_at(_struct, index, &key_code, &shift_pressedInt,
+ &ctrl_pressedInt, &alt_pressedInt);
+
+ // Restore param:shift_pressed; type: bool_byref
+ shift_pressed = shift_pressedInt ? true : false;
+ // Restore param:ctrl_pressed; type: bool_byref
+ ctrl_pressed = ctrl_pressedInt ? true : false;
+ // Restore param:alt_pressed; type: bool_byref
+ alt_pressed = alt_pressedInt ? true : false;
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefMenuModelCToCpp::SetColor(int command_id,
+ cef_menu_color_type_t color_type,
+ cef_color_t color) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_color)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->set_color(_struct, command_id, color_type, color);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefMenuModelCToCpp::SetColorAt(int index,
+ cef_menu_color_type_t color_type,
+ cef_color_t color) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_color_at)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->set_color_at(_struct, index, color_type, color);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefMenuModelCToCpp::GetColor(int command_id,
+ cef_menu_color_type_t color_type,
+ cef_color_t& color) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_color)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_color(_struct, command_id, color_type, &color);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefMenuModelCToCpp::GetColorAt(int index,
+ cef_menu_color_type_t color_type,
+ cef_color_t& color) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_color_at)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_color_at(_struct, index, color_type, &color);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefMenuModelCToCpp::SetFontList(int command_id,
+ const CefString& font_list) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_font_list)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: font_list
+
+ // Execute
+ int _retval =
+ _struct->set_font_list(_struct, command_id, font_list.GetStruct());
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefMenuModelCToCpp::SetFontListAt(int index, const CefString& font_list) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_font_list_at)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: font_list
+
+ // Execute
+ int _retval =
+ _struct->set_font_list_at(_struct, index, font_list.GetStruct());
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefMenuModelCToCpp::CefMenuModelCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefMenuModelCToCpp::~CefMenuModelCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_menu_model_t*
+CefCToCppRefCounted<CefMenuModelCToCpp, CefMenuModel, cef_menu_model_t>::
+ UnwrapDerived(CefWrapperType type, CefMenuModel* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefMenuModelCToCpp,
+ CefMenuModel,
+ cef_menu_model_t>::kWrapperType =
+ WT_MENU_MODEL;
diff --git a/libcef_dll/ctocpp/menu_model_ctocpp.h b/libcef_dll/ctocpp/menu_model_ctocpp.h
new file mode 100644
index 00000000..d6ed8d0c
--- /dev/null
+++ b/libcef_dll/ctocpp/menu_model_ctocpp.h
@@ -0,0 +1,131 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=1b1c5e3e3cca0da704d30c6577a0c083c3fb389b$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_MENU_MODEL_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_MENU_MODEL_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_menu_model_capi.h"
+#include "include/cef_menu_model.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefMenuModelCToCpp : public CefCToCppRefCounted<CefMenuModelCToCpp,
+ CefMenuModel,
+ cef_menu_model_t> {
+ public:
+ CefMenuModelCToCpp();
+ virtual ~CefMenuModelCToCpp();
+
+ // CefMenuModel methods.
+ bool IsSubMenu() override;
+ bool Clear() override;
+ size_t GetCount() override;
+ bool AddSeparator() override;
+ bool AddItem(int command_id, const CefString& label) override;
+ bool AddCheckItem(int command_id, const CefString& label) override;
+ bool AddRadioItem(int command_id,
+ const CefString& label,
+ int group_id) override;
+ CefRefPtr<CefMenuModel> AddSubMenu(int command_id,
+ const CefString& label) override;
+ bool InsertSeparatorAt(size_t index) override;
+ bool InsertItemAt(size_t index,
+ int command_id,
+ const CefString& label) override;
+ bool InsertCheckItemAt(size_t index,
+ int command_id,
+ const CefString& label) override;
+ bool InsertRadioItemAt(size_t index,
+ int command_id,
+ const CefString& label,
+ int group_id) override;
+ CefRefPtr<CefMenuModel> InsertSubMenuAt(size_t index,
+ int command_id,
+ const CefString& label) override;
+ bool Remove(int command_id) override;
+ bool RemoveAt(size_t index) override;
+ int GetIndexOf(int command_id) override;
+ int GetCommandIdAt(size_t index) override;
+ bool SetCommandIdAt(size_t index, int command_id) override;
+ CefString GetLabel(int command_id) override;
+ CefString GetLabelAt(size_t index) override;
+ bool SetLabel(int command_id, const CefString& label) override;
+ bool SetLabelAt(size_t index, const CefString& label) override;
+ MenuItemType GetType(int command_id) override;
+ MenuItemType GetTypeAt(size_t index) override;
+ int GetGroupId(int command_id) override;
+ int GetGroupIdAt(size_t index) override;
+ bool SetGroupId(int command_id, int group_id) override;
+ bool SetGroupIdAt(size_t index, int group_id) override;
+ CefRefPtr<CefMenuModel> GetSubMenu(int command_id) override;
+ CefRefPtr<CefMenuModel> GetSubMenuAt(size_t index) override;
+ bool IsVisible(int command_id) override;
+ bool IsVisibleAt(size_t index) override;
+ bool SetVisible(int command_id, bool visible) override;
+ bool SetVisibleAt(size_t index, bool visible) override;
+ bool IsEnabled(int command_id) override;
+ bool IsEnabledAt(size_t index) override;
+ bool SetEnabled(int command_id, bool enabled) override;
+ bool SetEnabledAt(size_t index, bool enabled) override;
+ bool IsChecked(int command_id) override;
+ bool IsCheckedAt(size_t index) override;
+ bool SetChecked(int command_id, bool checked) override;
+ bool SetCheckedAt(size_t index, bool checked) override;
+ bool HasAccelerator(int command_id) override;
+ bool HasAcceleratorAt(size_t index) override;
+ bool SetAccelerator(int command_id,
+ int key_code,
+ bool shift_pressed,
+ bool ctrl_pressed,
+ bool alt_pressed) override;
+ bool SetAcceleratorAt(size_t index,
+ int key_code,
+ bool shift_pressed,
+ bool ctrl_pressed,
+ bool alt_pressed) override;
+ bool RemoveAccelerator(int command_id) override;
+ bool RemoveAcceleratorAt(size_t index) override;
+ bool GetAccelerator(int command_id,
+ int& key_code,
+ bool& shift_pressed,
+ bool& ctrl_pressed,
+ bool& alt_pressed) override;
+ bool GetAcceleratorAt(size_t index,
+ int& key_code,
+ bool& shift_pressed,
+ bool& ctrl_pressed,
+ bool& alt_pressed) override;
+ bool SetColor(int command_id,
+ cef_menu_color_type_t color_type,
+ cef_color_t color) override;
+ bool SetColorAt(int index,
+ cef_menu_color_type_t color_type,
+ cef_color_t color) override;
+ bool GetColor(int command_id,
+ cef_menu_color_type_t color_type,
+ cef_color_t& color) override;
+ bool GetColorAt(int index,
+ cef_menu_color_type_t color_type,
+ cef_color_t& color) override;
+ bool SetFontList(int command_id, const CefString& font_list) override;
+ bool SetFontListAt(int index, const CefString& font_list) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_MENU_MODEL_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/menu_model_delegate_ctocpp.cc b/libcef_dll/ctocpp/menu_model_delegate_ctocpp.cc
new file mode 100644
index 00000000..6d35ac34
--- /dev/null
+++ b/libcef_dll/ctocpp/menu_model_delegate_ctocpp.cc
@@ -0,0 +1,212 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=c979acd0dbde40884fedcfba613491006226accb$
+//
+
+#include "libcef_dll/ctocpp/menu_model_delegate_ctocpp.h"
+#include "libcef_dll/cpptoc/menu_model_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+void CefMenuModelDelegateCToCpp::ExecuteCommand(
+ CefRefPtr<CefMenuModel> menu_model,
+ int command_id,
+ cef_event_flags_t event_flags) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_delegate_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, execute_command)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: menu_model; type: refptr_diff
+ DCHECK(menu_model.get());
+ if (!menu_model.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->execute_command(_struct, CefMenuModelCppToC::Wrap(menu_model),
+ command_id, event_flags);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefMenuModelDelegateCToCpp::MouseOutsideMenu(
+ CefRefPtr<CefMenuModel> menu_model,
+ const CefPoint& screen_point) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_delegate_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, mouse_outside_menu)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: menu_model; type: refptr_diff
+ DCHECK(menu_model.get());
+ if (!menu_model.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->mouse_outside_menu(_struct, CefMenuModelCppToC::Wrap(menu_model),
+ &screen_point);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefMenuModelDelegateCToCpp::UnhandledOpenSubmenu(
+ CefRefPtr<CefMenuModel> menu_model,
+ bool is_rtl) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_delegate_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, unhandled_open_submenu)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: menu_model; type: refptr_diff
+ DCHECK(menu_model.get());
+ if (!menu_model.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->unhandled_open_submenu(_struct, CefMenuModelCppToC::Wrap(menu_model),
+ is_rtl);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefMenuModelDelegateCToCpp::UnhandledCloseSubmenu(
+ CefRefPtr<CefMenuModel> menu_model,
+ bool is_rtl) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_delegate_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, unhandled_close_submenu)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: menu_model; type: refptr_diff
+ DCHECK(menu_model.get());
+ if (!menu_model.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->unhandled_close_submenu(
+ _struct, CefMenuModelCppToC::Wrap(menu_model), is_rtl);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefMenuModelDelegateCToCpp::MenuWillShow(
+ CefRefPtr<CefMenuModel> menu_model) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_delegate_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, menu_will_show)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: menu_model; type: refptr_diff
+ DCHECK(menu_model.get());
+ if (!menu_model.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->menu_will_show(_struct, CefMenuModelCppToC::Wrap(menu_model));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefMenuModelDelegateCToCpp::MenuClosed(
+ CefRefPtr<CefMenuModel> menu_model) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_delegate_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, menu_closed)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: menu_model; type: refptr_diff
+ DCHECK(menu_model.get());
+ if (!menu_model.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->menu_closed(_struct, CefMenuModelCppToC::Wrap(menu_model));
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefMenuModelDelegateCToCpp::FormatLabel(CefRefPtr<CefMenuModel> menu_model,
+ CefString& label) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_model_delegate_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, format_label)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: menu_model; type: refptr_diff
+ DCHECK(menu_model.get());
+ if (!menu_model.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->format_label(
+ _struct, CefMenuModelCppToC::Wrap(menu_model), label.GetWritableStruct());
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefMenuModelDelegateCToCpp::CefMenuModelDelegateCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefMenuModelDelegateCToCpp::~CefMenuModelDelegateCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_menu_model_delegate_t* CefCToCppRefCounted<
+ CefMenuModelDelegateCToCpp,
+ CefMenuModelDelegate,
+ cef_menu_model_delegate_t>::UnwrapDerived(CefWrapperType type,
+ CefMenuModelDelegate* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefMenuModelDelegateCToCpp,
+ CefMenuModelDelegate,
+ cef_menu_model_delegate_t>::kWrapperType =
+ WT_MENU_MODEL_DELEGATE;
diff --git a/libcef_dll/ctocpp/menu_model_delegate_ctocpp.h b/libcef_dll/ctocpp/menu_model_delegate_ctocpp.h
new file mode 100644
index 00000000..7762f4e8
--- /dev/null
+++ b/libcef_dll/ctocpp/menu_model_delegate_ctocpp.h
@@ -0,0 +1,55 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=6ac8a9990cf50850d8f8716096094d1180215be9$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_MENU_MODEL_DELEGATE_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_MENU_MODEL_DELEGATE_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_menu_model_capi.h"
+#include "include/capi/cef_menu_model_delegate_capi.h"
+#include "include/cef_menu_model.h"
+#include "include/cef_menu_model_delegate.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefMenuModelDelegateCToCpp
+ : public CefCToCppRefCounted<CefMenuModelDelegateCToCpp,
+ CefMenuModelDelegate,
+ cef_menu_model_delegate_t> {
+ public:
+ CefMenuModelDelegateCToCpp();
+ virtual ~CefMenuModelDelegateCToCpp();
+
+ // CefMenuModelDelegate methods.
+ void ExecuteCommand(CefRefPtr<CefMenuModel> menu_model,
+ int command_id,
+ cef_event_flags_t event_flags) override;
+ void MouseOutsideMenu(CefRefPtr<CefMenuModel> menu_model,
+ const CefPoint& screen_point) override;
+ void UnhandledOpenSubmenu(CefRefPtr<CefMenuModel> menu_model,
+ bool is_rtl) override;
+ void UnhandledCloseSubmenu(CefRefPtr<CefMenuModel> menu_model,
+ bool is_rtl) override;
+ void MenuWillShow(CefRefPtr<CefMenuModel> menu_model) override;
+ void MenuClosed(CefRefPtr<CefMenuModel> menu_model) override;
+ bool FormatLabel(CefRefPtr<CefMenuModel> menu_model,
+ CefString& label) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_MENU_MODEL_DELEGATE_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/navigation_entry_ctocpp.cc b/libcef_dll/ctocpp/navigation_entry_ctocpp.cc
new file mode 100644
index 00000000..6c4e15bc
--- /dev/null
+++ b/libcef_dll/ctocpp/navigation_entry_ctocpp.cc
@@ -0,0 +1,227 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=a832a32c3a3d5c43676c7bc76bafbe77a964a5f1$
+//
+
+#include "libcef_dll/ctocpp/navigation_entry_ctocpp.h"
+#include "libcef_dll/ctocpp/sslstatus_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") bool CefNavigationEntryCToCpp::IsValid() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_navigation_entry_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_valid)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_valid(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") CefString CefNavigationEntryCToCpp::GetURL() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_navigation_entry_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_url)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_url(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") CefString CefNavigationEntryCToCpp::GetDisplayURL() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_navigation_entry_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_display_url)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_display_url(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") CefString CefNavigationEntryCToCpp::GetOriginalURL() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_navigation_entry_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_original_url)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_original_url(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") CefString CefNavigationEntryCToCpp::GetTitle() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_navigation_entry_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_title)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_title(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+CefNavigationEntry::TransitionType
+CefNavigationEntryCToCpp::GetTransitionType() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_navigation_entry_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_transition_type)) {
+ return TT_EXPLICIT;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_transition_type_t _retval = _struct->get_transition_type(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") bool CefNavigationEntryCToCpp::HasPostData() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_navigation_entry_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, has_post_data)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->has_post_data(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CefBaseTime CefNavigationEntryCToCpp::GetCompletionTime() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_navigation_entry_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_completion_time)) {
+ return CefBaseTime();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_basetime_t _retval = _struct->get_completion_time(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") int CefNavigationEntryCToCpp::GetHttpStatusCode() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_navigation_entry_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_http_status_code)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_http_status_code(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefSSLStatus> CefNavigationEntryCToCpp::GetSSLStatus() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_navigation_entry_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_sslstatus)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_sslstatus_t* _retval = _struct->get_sslstatus(_struct);
+
+ // Return type: refptr_same
+ return CefSSLStatusCToCpp::Wrap(_retval);
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefNavigationEntryCToCpp::CefNavigationEntryCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefNavigationEntryCToCpp::~CefNavigationEntryCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_navigation_entry_t* CefCToCppRefCounted<
+ CefNavigationEntryCToCpp,
+ CefNavigationEntry,
+ cef_navigation_entry_t>::UnwrapDerived(CefWrapperType type,
+ CefNavigationEntry* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefNavigationEntryCToCpp,
+ CefNavigationEntry,
+ cef_navigation_entry_t>::kWrapperType =
+ WT_NAVIGATION_ENTRY;
diff --git a/libcef_dll/ctocpp/navigation_entry_ctocpp.h b/libcef_dll/ctocpp/navigation_entry_ctocpp.h
new file mode 100644
index 00000000..35513787
--- /dev/null
+++ b/libcef_dll/ctocpp/navigation_entry_ctocpp.h
@@ -0,0 +1,50 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=09c6bbd82ec82943b6f310c5ffb347bfbef2654c$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_NAVIGATION_ENTRY_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_NAVIGATION_ENTRY_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_navigation_entry_capi.h"
+#include "include/cef_navigation_entry.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefNavigationEntryCToCpp
+ : public CefCToCppRefCounted<CefNavigationEntryCToCpp,
+ CefNavigationEntry,
+ cef_navigation_entry_t> {
+ public:
+ CefNavigationEntryCToCpp();
+ virtual ~CefNavigationEntryCToCpp();
+
+ // CefNavigationEntry methods.
+ bool IsValid() override;
+ CefString GetURL() override;
+ CefString GetDisplayURL() override;
+ CefString GetOriginalURL() override;
+ CefString GetTitle() override;
+ TransitionType GetTransitionType() override;
+ bool HasPostData() override;
+ CefBaseTime GetCompletionTime() override;
+ int GetHttpStatusCode() override;
+ CefRefPtr<CefSSLStatus> GetSSLStatus() override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_NAVIGATION_ENTRY_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/navigation_entry_visitor_ctocpp.cc b/libcef_dll/ctocpp/navigation_entry_visitor_ctocpp.cc
new file mode 100644
index 00000000..90683d0b
--- /dev/null
+++ b/libcef_dll/ctocpp/navigation_entry_visitor_ctocpp.cc
@@ -0,0 +1,75 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=48281bb0de6e38b45f5dbc60bf7609b476241d76$
+//
+
+#include "libcef_dll/ctocpp/navigation_entry_visitor_ctocpp.h"
+#include "libcef_dll/cpptoc/navigation_entry_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+bool CefNavigationEntryVisitorCToCpp::Visit(CefRefPtr<CefNavigationEntry> entry,
+ bool current,
+ int index,
+ int total) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_navigation_entry_visitor_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, visit)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: entry; type: refptr_diff
+ DCHECK(entry.get());
+ if (!entry.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->visit(_struct, CefNavigationEntryCppToC::Wrap(entry),
+ current, index, total);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefNavigationEntryVisitorCToCpp::CefNavigationEntryVisitorCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefNavigationEntryVisitorCToCpp::~CefNavigationEntryVisitorCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_navigation_entry_visitor_t* CefCToCppRefCounted<
+ CefNavigationEntryVisitorCToCpp,
+ CefNavigationEntryVisitor,
+ cef_navigation_entry_visitor_t>::UnwrapDerived(CefWrapperType type,
+ CefNavigationEntryVisitor*
+ c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCToCppRefCounted<CefNavigationEntryVisitorCToCpp,
+ CefNavigationEntryVisitor,
+ cef_navigation_entry_visitor_t>::kWrapperType =
+ WT_NAVIGATION_ENTRY_VISITOR;
diff --git a/libcef_dll/ctocpp/navigation_entry_visitor_ctocpp.h b/libcef_dll/ctocpp/navigation_entry_visitor_ctocpp.h
new file mode 100644
index 00000000..bcaa2c93
--- /dev/null
+++ b/libcef_dll/ctocpp/navigation_entry_visitor_ctocpp.h
@@ -0,0 +1,46 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=3dbe29abccbfa1d1cc7014630bbe312d9de42ac8$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_NAVIGATION_ENTRY_VISITOR_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_NAVIGATION_ENTRY_VISITOR_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_browser_capi.h"
+#include "include/capi/cef_client_capi.h"
+#include "include/cef_browser.h"
+#include "include/cef_client.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefNavigationEntryVisitorCToCpp
+ : public CefCToCppRefCounted<CefNavigationEntryVisitorCToCpp,
+ CefNavigationEntryVisitor,
+ cef_navigation_entry_visitor_t> {
+ public:
+ CefNavigationEntryVisitorCToCpp();
+ virtual ~CefNavigationEntryVisitorCToCpp();
+
+ // CefNavigationEntryVisitor methods.
+ bool Visit(CefRefPtr<CefNavigationEntry> entry,
+ bool current,
+ int index,
+ int total) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_NAVIGATION_ENTRY_VISITOR_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/pdf_print_callback_ctocpp.cc b/libcef_dll/ctocpp/pdf_print_callback_ctocpp.cc
new file mode 100644
index 00000000..ac4ab49f
--- /dev/null
+++ b/libcef_dll/ctocpp/pdf_print_callback_ctocpp.cc
@@ -0,0 +1,66 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=f3a80bf42c989064d862e16f34e4ac045b922c0d$
+//
+
+#include "libcef_dll/ctocpp/pdf_print_callback_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+void CefPdfPrintCallbackCToCpp::OnPdfPrintFinished(const CefString& path,
+ bool ok) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_pdf_print_callback_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_pdf_print_finished)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: path; type: string_byref_const
+ DCHECK(!path.empty());
+ if (path.empty()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_pdf_print_finished(_struct, path.GetStruct(), ok);
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefPdfPrintCallbackCToCpp::CefPdfPrintCallbackCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefPdfPrintCallbackCToCpp::~CefPdfPrintCallbackCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_pdf_print_callback_t* CefCToCppRefCounted<
+ CefPdfPrintCallbackCToCpp,
+ CefPdfPrintCallback,
+ cef_pdf_print_callback_t>::UnwrapDerived(CefWrapperType type,
+ CefPdfPrintCallback* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefPdfPrintCallbackCToCpp,
+ CefPdfPrintCallback,
+ cef_pdf_print_callback_t>::kWrapperType =
+ WT_PDF_PRINT_CALLBACK;
diff --git a/libcef_dll/ctocpp/pdf_print_callback_ctocpp.h b/libcef_dll/ctocpp/pdf_print_callback_ctocpp.h
new file mode 100644
index 00000000..7abf1c11
--- /dev/null
+++ b/libcef_dll/ctocpp/pdf_print_callback_ctocpp.h
@@ -0,0 +1,43 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=0387fbd8f6ad59dac67959eeded82630a2bba935$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_PDF_PRINT_CALLBACK_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_PDF_PRINT_CALLBACK_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_browser_capi.h"
+#include "include/capi/cef_client_capi.h"
+#include "include/cef_browser.h"
+#include "include/cef_client.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefPdfPrintCallbackCToCpp
+ : public CefCToCppRefCounted<CefPdfPrintCallbackCToCpp,
+ CefPdfPrintCallback,
+ cef_pdf_print_callback_t> {
+ public:
+ CefPdfPrintCallbackCToCpp();
+ virtual ~CefPdfPrintCallbackCToCpp();
+
+ // CefPdfPrintCallback methods.
+ void OnPdfPrintFinished(const CefString& path, bool ok) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_PDF_PRINT_CALLBACK_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/permission_handler_ctocpp.cc b/libcef_dll/ctocpp/permission_handler_ctocpp.cc
new file mode 100644
index 00000000..56b8a3b2
--- /dev/null
+++ b/libcef_dll/ctocpp/permission_handler_ctocpp.cc
@@ -0,0 +1,162 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=2ff01ee1ca831e910dcd7b1767a0e9d251aa9747$
+//
+
+#include "libcef_dll/ctocpp/permission_handler_ctocpp.h"
+#include "libcef_dll/cpptoc/browser_cpptoc.h"
+#include "libcef_dll/cpptoc/frame_cpptoc.h"
+#include "libcef_dll/cpptoc/media_access_callback_cpptoc.h"
+#include "libcef_dll/cpptoc/permission_prompt_callback_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+bool CefPermissionHandlerCToCpp::OnRequestMediaAccessPermission(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const CefString& requesting_origin,
+ uint32 requested_permissions,
+ CefRefPtr<CefMediaAccessCallback> callback) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_permission_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_request_media_access_permission)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return false;
+ }
+ // Verify param: frame; type: refptr_diff
+ DCHECK(frame.get());
+ if (!frame.get()) {
+ return false;
+ }
+ // Verify param: requesting_origin; type: string_byref_const
+ DCHECK(!requesting_origin.empty());
+ if (requesting_origin.empty()) {
+ return false;
+ }
+ // Verify param: callback; type: refptr_diff
+ DCHECK(callback.get());
+ if (!callback.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->on_request_media_access_permission(
+ _struct, CefBrowserCppToC::Wrap(browser), CefFrameCppToC::Wrap(frame),
+ requesting_origin.GetStruct(), requested_permissions,
+ CefMediaAccessCallbackCppToC::Wrap(callback));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefPermissionHandlerCToCpp::OnShowPermissionPrompt(
+ CefRefPtr<CefBrowser> browser,
+ uint64 prompt_id,
+ const CefString& requesting_origin,
+ uint32 requested_permissions,
+ CefRefPtr<CefPermissionPromptCallback> callback) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_permission_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_show_permission_prompt)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return false;
+ }
+ // Verify param: requesting_origin; type: string_byref_const
+ DCHECK(!requesting_origin.empty());
+ if (requesting_origin.empty()) {
+ return false;
+ }
+ // Verify param: callback; type: refptr_diff
+ DCHECK(callback.get());
+ if (!callback.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->on_show_permission_prompt(
+ _struct, CefBrowserCppToC::Wrap(browser), prompt_id,
+ requesting_origin.GetStruct(), requested_permissions,
+ CefPermissionPromptCallbackCppToC::Wrap(callback));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefPermissionHandlerCToCpp::OnDismissPermissionPrompt(
+ CefRefPtr<CefBrowser> browser,
+ uint64 prompt_id,
+ cef_permission_request_result_t result) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_permission_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_dismiss_permission_prompt)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_dismiss_permission_prompt(
+ _struct, CefBrowserCppToC::Wrap(browser), prompt_id, result);
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefPermissionHandlerCToCpp::CefPermissionHandlerCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefPermissionHandlerCToCpp::~CefPermissionHandlerCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_permission_handler_t* CefCToCppRefCounted<
+ CefPermissionHandlerCToCpp,
+ CefPermissionHandler,
+ cef_permission_handler_t>::UnwrapDerived(CefWrapperType type,
+ CefPermissionHandler* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefPermissionHandlerCToCpp,
+ CefPermissionHandler,
+ cef_permission_handler_t>::kWrapperType =
+ WT_PERMISSION_HANDLER;
diff --git a/libcef_dll/ctocpp/permission_handler_ctocpp.h b/libcef_dll/ctocpp/permission_handler_ctocpp.h
new file mode 100644
index 00000000..20a9cea1
--- /dev/null
+++ b/libcef_dll/ctocpp/permission_handler_ctocpp.h
@@ -0,0 +1,56 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=d04848217552f94ca2bd3647ce973b92a0e62a01$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_PERMISSION_HANDLER_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_PERMISSION_HANDLER_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_permission_handler_capi.h"
+#include "include/cef_permission_handler.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefPermissionHandlerCToCpp
+ : public CefCToCppRefCounted<CefPermissionHandlerCToCpp,
+ CefPermissionHandler,
+ cef_permission_handler_t> {
+ public:
+ CefPermissionHandlerCToCpp();
+ virtual ~CefPermissionHandlerCToCpp();
+
+ // CefPermissionHandler methods.
+ bool OnRequestMediaAccessPermission(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const CefString& requesting_origin,
+ uint32 requested_permissions,
+ CefRefPtr<CefMediaAccessCallback> callback) override;
+ bool OnShowPermissionPrompt(
+ CefRefPtr<CefBrowser> browser,
+ uint64 prompt_id,
+ const CefString& requesting_origin,
+ uint32 requested_permissions,
+ CefRefPtr<CefPermissionPromptCallback> callback) override;
+ void OnDismissPermissionPrompt(
+ CefRefPtr<CefBrowser> browser,
+ uint64 prompt_id,
+ cef_permission_request_result_t result) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_PERMISSION_HANDLER_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/permission_prompt_callback_ctocpp.cc b/libcef_dll/ctocpp/permission_prompt_callback_ctocpp.cc
new file mode 100644
index 00000000..588ada58
--- /dev/null
+++ b/libcef_dll/ctocpp/permission_prompt_callback_ctocpp.cc
@@ -0,0 +1,61 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=9262abf05b3c8486a7b8bb0488d8b59a667d6b44$
+//
+
+#include "libcef_dll/ctocpp/permission_prompt_callback_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+void CefPermissionPromptCallbackCToCpp::Continue(
+ cef_permission_request_result_t result) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_permission_prompt_callback_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, cont)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->cont(_struct, result);
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefPermissionPromptCallbackCToCpp::CefPermissionPromptCallbackCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefPermissionPromptCallbackCToCpp::~CefPermissionPromptCallbackCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_permission_prompt_callback_t*
+CefCToCppRefCounted<CefPermissionPromptCallbackCToCpp,
+ CefPermissionPromptCallback,
+ cef_permission_prompt_callback_t>::
+ UnwrapDerived(CefWrapperType type, CefPermissionPromptCallback* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCToCppRefCounted<CefPermissionPromptCallbackCToCpp,
+ CefPermissionPromptCallback,
+ cef_permission_prompt_callback_t>::kWrapperType =
+ WT_PERMISSION_PROMPT_CALLBACK;
diff --git a/libcef_dll/ctocpp/permission_prompt_callback_ctocpp.h b/libcef_dll/ctocpp/permission_prompt_callback_ctocpp.h
new file mode 100644
index 00000000..be82ab76
--- /dev/null
+++ b/libcef_dll/ctocpp/permission_prompt_callback_ctocpp.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=8b2ed4405822451f9bae6ae35d589611b6c8e0f3$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_PERMISSION_PROMPT_CALLBACK_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_PERMISSION_PROMPT_CALLBACK_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_permission_handler_capi.h"
+#include "include/cef_permission_handler.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefPermissionPromptCallbackCToCpp
+ : public CefCToCppRefCounted<CefPermissionPromptCallbackCToCpp,
+ CefPermissionPromptCallback,
+ cef_permission_prompt_callback_t> {
+ public:
+ CefPermissionPromptCallbackCToCpp();
+ virtual ~CefPermissionPromptCallbackCToCpp();
+
+ // CefPermissionPromptCallback methods.
+ void Continue(cef_permission_request_result_t result) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_PERMISSION_PROMPT_CALLBACK_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/post_data_ctocpp.cc b/libcef_dll/ctocpp/post_data_ctocpp.cc
new file mode 100644
index 00000000..33390317
--- /dev/null
+++ b/libcef_dll/ctocpp/post_data_ctocpp.cc
@@ -0,0 +1,195 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=b8f7072a18170af6fff845c7b911c9e9cb845658$
+//
+
+#include "libcef_dll/ctocpp/post_data_ctocpp.h"
+#include <algorithm>
+#include "libcef_dll/ctocpp/post_data_element_ctocpp.h"
+
+// STATIC METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefPostData> CefPostData::Create() {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_post_data_t* _retval = cef_post_data_create();
+
+ // Return type: refptr_same
+ return CefPostDataCToCpp::Wrap(_retval);
+}
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") bool CefPostDataCToCpp::IsReadOnly() {
+ cef_post_data_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_read_only)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_read_only(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefPostDataCToCpp::HasExcludedElements() {
+ cef_post_data_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, has_excluded_elements)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->has_excluded_elements(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") size_t CefPostDataCToCpp::GetElementCount() {
+ cef_post_data_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_element_count)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ size_t _retval = _struct->get_element_count(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefPostDataCToCpp::GetElements(ElementVector& elements) {
+ cef_post_data_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_elements)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Translate param: elements; type: refptr_vec_same_byref
+ size_t elementsSize = elements.size();
+ size_t elementsCount = std::max(GetElementCount(), elementsSize);
+ cef_post_data_element_t** elementsList = NULL;
+ if (elementsCount > 0) {
+ elementsList = new cef_post_data_element_t*[elementsCount];
+ DCHECK(elementsList);
+ if (elementsList) {
+ memset(elementsList, 0, sizeof(cef_post_data_element_t*) * elementsCount);
+ }
+ if (elementsList && elementsSize > 0) {
+ for (size_t i = 0; i < elementsSize; ++i) {
+ elementsList[i] = CefPostDataElementCToCpp::Unwrap(elements[i]);
+ }
+ }
+ }
+
+ // Execute
+ _struct->get_elements(_struct, &elementsCount, elementsList);
+
+ // Restore param:elements; type: refptr_vec_same_byref
+ elements.clear();
+ if (elementsCount > 0 && elementsList) {
+ for (size_t i = 0; i < elementsCount; ++i) {
+ elements.push_back(CefPostDataElementCToCpp::Wrap(elementsList[i]));
+ }
+ delete[] elementsList;
+ }
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefPostDataCToCpp::RemoveElement(CefRefPtr<CefPostDataElement> element) {
+ cef_post_data_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, remove_element)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: element; type: refptr_same
+ DCHECK(element.get());
+ if (!element.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->remove_element(
+ _struct, CefPostDataElementCToCpp::Unwrap(element));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefPostDataCToCpp::AddElement(CefRefPtr<CefPostDataElement> element) {
+ cef_post_data_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, add_element)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: element; type: refptr_same
+ DCHECK(element.get());
+ if (!element.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval =
+ _struct->add_element(_struct, CefPostDataElementCToCpp::Unwrap(element));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") void CefPostDataCToCpp::RemoveElements() {
+ cef_post_data_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, remove_elements)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->remove_elements(_struct);
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefPostDataCToCpp::CefPostDataCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefPostDataCToCpp::~CefPostDataCToCpp() {}
+
+template <>
+cef_post_data_t*
+CefCToCppRefCounted<CefPostDataCToCpp, CefPostData, cef_post_data_t>::
+ UnwrapDerived(CefWrapperType type, CefPostData* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefPostDataCToCpp,
+ CefPostData,
+ cef_post_data_t>::kWrapperType =
+ WT_POST_DATA;
diff --git a/libcef_dll/ctocpp/post_data_ctocpp.h b/libcef_dll/ctocpp/post_data_ctocpp.h
new file mode 100644
index 00000000..7666035c
--- /dev/null
+++ b/libcef_dll/ctocpp/post_data_ctocpp.h
@@ -0,0 +1,46 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=e70d58d7c779528d03b49ead50c162ebf0eb0ca7$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_POST_DATA_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_POST_DATA_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_request_capi.h"
+#include "include/cef_request.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefPostDataCToCpp : public CefCToCppRefCounted<CefPostDataCToCpp,
+ CefPostData,
+ cef_post_data_t> {
+ public:
+ CefPostDataCToCpp();
+ virtual ~CefPostDataCToCpp();
+
+ // CefPostData methods.
+ bool IsReadOnly() override;
+ bool HasExcludedElements() override;
+ size_t GetElementCount() override;
+ void GetElements(ElementVector& elements) override;
+ bool RemoveElement(CefRefPtr<CefPostDataElement> element) override;
+ bool AddElement(CefRefPtr<CefPostDataElement> element) override;
+ void RemoveElements() override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_POST_DATA_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/post_data_element_ctocpp.cc b/libcef_dll/ctocpp/post_data_element_ctocpp.cc
new file mode 100644
index 00000000..041b4b5a
--- /dev/null
+++ b/libcef_dll/ctocpp/post_data_element_ctocpp.cc
@@ -0,0 +1,189 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=46e4cc8924d3070e56735a5b2b0746ae82d25b2b$
+//
+
+#include "libcef_dll/ctocpp/post_data_element_ctocpp.h"
+
+// STATIC METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefPostDataElement> CefPostDataElement::Create() {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_post_data_element_t* _retval = cef_post_data_element_create();
+
+ // Return type: refptr_same
+ return CefPostDataElementCToCpp::Wrap(_retval);
+}
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") bool CefPostDataElementCToCpp::IsReadOnly() {
+ cef_post_data_element_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_read_only)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_read_only(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") void CefPostDataElementCToCpp::SetToEmpty() {
+ cef_post_data_element_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_to_empty)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_to_empty(_struct);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefPostDataElementCToCpp::SetToFile(const CefString& fileName) {
+ cef_post_data_element_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_to_file)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: fileName; type: string_byref_const
+ DCHECK(!fileName.empty());
+ if (fileName.empty()) {
+ return;
+ }
+
+ // Execute
+ _struct->set_to_file(_struct, fileName.GetStruct());
+}
+
+NO_SANITIZE("cfi-icall")
+void CefPostDataElementCToCpp::SetToBytes(size_t size, const void* bytes) {
+ cef_post_data_element_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_to_bytes)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: bytes; type: simple_byaddr
+ DCHECK(bytes);
+ if (!bytes) {
+ return;
+ }
+
+ // Execute
+ _struct->set_to_bytes(_struct, size, bytes);
+}
+
+NO_SANITIZE("cfi-icall")
+CefPostDataElement::Type CefPostDataElementCToCpp::GetType() {
+ cef_post_data_element_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_type)) {
+ return PDE_TYPE_EMPTY;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_postdataelement_type_t _retval = _struct->get_type(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") CefString CefPostDataElementCToCpp::GetFile() {
+ cef_post_data_element_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_file)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_file(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") size_t CefPostDataElementCToCpp::GetBytesCount() {
+ cef_post_data_element_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_bytes_count)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ size_t _retval = _struct->get_bytes_count(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+size_t CefPostDataElementCToCpp::GetBytes(size_t size, void* bytes) {
+ cef_post_data_element_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_bytes)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: bytes; type: simple_byaddr
+ DCHECK(bytes);
+ if (!bytes) {
+ return 0;
+ }
+
+ // Execute
+ size_t _retval = _struct->get_bytes(_struct, size, bytes);
+
+ // Return type: simple
+ return _retval;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefPostDataElementCToCpp::CefPostDataElementCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefPostDataElementCToCpp::~CefPostDataElementCToCpp() {}
+
+template <>
+cef_post_data_element_t* CefCToCppRefCounted<
+ CefPostDataElementCToCpp,
+ CefPostDataElement,
+ cef_post_data_element_t>::UnwrapDerived(CefWrapperType type,
+ CefPostDataElement* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefPostDataElementCToCpp,
+ CefPostDataElement,
+ cef_post_data_element_t>::kWrapperType =
+ WT_POST_DATA_ELEMENT;
diff --git a/libcef_dll/ctocpp/post_data_element_ctocpp.h b/libcef_dll/ctocpp/post_data_element_ctocpp.h
new file mode 100644
index 00000000..e422be54
--- /dev/null
+++ b/libcef_dll/ctocpp/post_data_element_ctocpp.h
@@ -0,0 +1,48 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=a81732545889a9d401edb7f5540e0762bb787526$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_POST_DATA_ELEMENT_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_POST_DATA_ELEMENT_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_request_capi.h"
+#include "include/cef_request.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefPostDataElementCToCpp
+ : public CefCToCppRefCounted<CefPostDataElementCToCpp,
+ CefPostDataElement,
+ cef_post_data_element_t> {
+ public:
+ CefPostDataElementCToCpp();
+ virtual ~CefPostDataElementCToCpp();
+
+ // CefPostDataElement methods.
+ bool IsReadOnly() override;
+ void SetToEmpty() override;
+ void SetToFile(const CefString& fileName) override;
+ void SetToBytes(size_t size, const void* bytes) override;
+ Type GetType() override;
+ CefString GetFile() override;
+ size_t GetBytesCount() override;
+ size_t GetBytes(size_t size, void* bytes) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_POST_DATA_ELEMENT_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/preference_manager_ctocpp.cc b/libcef_dll/ctocpp/preference_manager_ctocpp.cc
new file mode 100644
index 00000000..dd2c3b19
--- /dev/null
+++ b/libcef_dll/ctocpp/preference_manager_ctocpp.cc
@@ -0,0 +1,175 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=e1ea194c8ef69a57ee4bee0b1729798128eb8754$
+//
+
+#include "libcef_dll/ctocpp/preference_manager_ctocpp.h"
+#include "libcef_dll/ctocpp/dictionary_value_ctocpp.h"
+#include "libcef_dll/ctocpp/request_context_ctocpp.h"
+#include "libcef_dll/ctocpp/value_ctocpp.h"
+
+// STATIC METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefPreferenceManager>
+CefPreferenceManager::GetGlobalPreferenceManager() {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_preference_manager_t* _retval = cef_preference_manager_get_global();
+
+ // Return type: refptr_same
+ return CefPreferenceManagerCToCpp::Wrap(_retval);
+}
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+bool CefPreferenceManagerCToCpp::HasPreference(const CefString& name) {
+ cef_preference_manager_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, has_preference)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: name; type: string_byref_const
+ DCHECK(!name.empty());
+ if (name.empty()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->has_preference(_struct, name.GetStruct());
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefValue> CefPreferenceManagerCToCpp::GetPreference(
+ const CefString& name) {
+ cef_preference_manager_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_preference)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: name; type: string_byref_const
+ DCHECK(!name.empty());
+ if (name.empty()) {
+ return nullptr;
+ }
+
+ // Execute
+ cef_value_t* _retval = _struct->get_preference(_struct, name.GetStruct());
+
+ // Return type: refptr_same
+ return CefValueCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefDictionaryValue> CefPreferenceManagerCToCpp::GetAllPreferences(
+ bool include_defaults) {
+ cef_preference_manager_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_all_preferences)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_dictionary_value_t* _retval =
+ _struct->get_all_preferences(_struct, include_defaults);
+
+ // Return type: refptr_same
+ return CefDictionaryValueCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefPreferenceManagerCToCpp::CanSetPreference(const CefString& name) {
+ cef_preference_manager_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, can_set_preference)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: name; type: string_byref_const
+ DCHECK(!name.empty());
+ if (name.empty()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->can_set_preference(_struct, name.GetStruct());
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefPreferenceManagerCToCpp::SetPreference(const CefString& name,
+ CefRefPtr<CefValue> value,
+ CefString& error) {
+ cef_preference_manager_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_preference)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: name; type: string_byref_const
+ DCHECK(!name.empty());
+ if (name.empty()) {
+ return false;
+ }
+ // Unverified params: value
+
+ // Execute
+ int _retval = _struct->set_preference(_struct, name.GetStruct(),
+ CefValueCToCpp::Unwrap(value),
+ error.GetWritableStruct());
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefPreferenceManagerCToCpp::CefPreferenceManagerCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefPreferenceManagerCToCpp::~CefPreferenceManagerCToCpp() {}
+
+template <>
+cef_preference_manager_t* CefCToCppRefCounted<
+ CefPreferenceManagerCToCpp,
+ CefPreferenceManager,
+ cef_preference_manager_t>::UnwrapDerived(CefWrapperType type,
+ CefPreferenceManager* c) {
+ if (type == WT_REQUEST_CONTEXT) {
+ return reinterpret_cast<cef_preference_manager_t*>(
+ CefRequestContextCToCpp::Unwrap(
+ reinterpret_cast<CefRequestContext*>(c)));
+ }
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefPreferenceManagerCToCpp,
+ CefPreferenceManager,
+ cef_preference_manager_t>::kWrapperType =
+ WT_PREFERENCE_MANAGER;
diff --git a/libcef_dll/ctocpp/preference_manager_ctocpp.h b/libcef_dll/ctocpp/preference_manager_ctocpp.h
new file mode 100644
index 00000000..585a1be8
--- /dev/null
+++ b/libcef_dll/ctocpp/preference_manager_ctocpp.h
@@ -0,0 +1,48 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=89ee6916279697654c516137ee56f5cbef07e4c0$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_PREFERENCE_MANAGER_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_PREFERENCE_MANAGER_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_preference_capi.h"
+#include "include/cef_preference.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefPreferenceManagerCToCpp
+ : public CefCToCppRefCounted<CefPreferenceManagerCToCpp,
+ CefPreferenceManager,
+ cef_preference_manager_t> {
+ public:
+ CefPreferenceManagerCToCpp();
+ virtual ~CefPreferenceManagerCToCpp();
+
+ // CefPreferenceManager methods.
+ bool HasPreference(const CefString& name) override;
+ CefRefPtr<CefValue> GetPreference(const CefString& name) override;
+ CefRefPtr<CefDictionaryValue> GetAllPreferences(
+ bool include_defaults) override;
+ bool CanSetPreference(const CefString& name) override;
+ bool SetPreference(const CefString& name,
+ CefRefPtr<CefValue> value,
+ CefString& error) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_PREFERENCE_MANAGER_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/preference_registrar_ctocpp.cc b/libcef_dll/ctocpp/preference_registrar_ctocpp.cc
new file mode 100644
index 00000000..97cae6a8
--- /dev/null
+++ b/libcef_dll/ctocpp/preference_registrar_ctocpp.cc
@@ -0,0 +1,80 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=952c6b775c3954a28e87a4c15625dcfa14829ec4$
+//
+
+#include "libcef_dll/ctocpp/preference_registrar_ctocpp.h"
+#include "libcef_dll/ctocpp/value_ctocpp.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+bool CefPreferenceRegistrarCToCpp::AddPreference(
+ const CefString& name,
+ CefRefPtr<CefValue> default_value) {
+ cef_preference_registrar_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, add_preference)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: name; type: string_byref_const
+ DCHECK(!name.empty());
+ if (name.empty()) {
+ return false;
+ }
+ // Verify param: default_value; type: refptr_same
+ DCHECK(default_value.get());
+ if (!default_value.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->add_preference(_struct, name.GetStruct(),
+ CefValueCToCpp::Unwrap(default_value));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefPreferenceRegistrarCToCpp::CefPreferenceRegistrarCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefPreferenceRegistrarCToCpp::~CefPreferenceRegistrarCToCpp() {}
+
+template <>
+cef_preference_registrar_t* CefCToCppScoped<CefPreferenceRegistrarCToCpp,
+ CefPreferenceRegistrar,
+ cef_preference_registrar_t>::
+ UnwrapDerivedOwn(CefWrapperType type, CefOwnPtr<CefPreferenceRegistrar> c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+cef_preference_registrar_t* CefCToCppScoped<CefPreferenceRegistrarCToCpp,
+ CefPreferenceRegistrar,
+ cef_preference_registrar_t>::
+ UnwrapDerivedRaw(CefWrapperType type, CefRawPtr<CefPreferenceRegistrar> c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppScoped<CefPreferenceRegistrarCToCpp,
+ CefPreferenceRegistrar,
+ cef_preference_registrar_t>::kWrapperType =
+ WT_PREFERENCE_REGISTRAR;
diff --git a/libcef_dll/ctocpp/preference_registrar_ctocpp.h b/libcef_dll/ctocpp/preference_registrar_ctocpp.h
new file mode 100644
index 00000000..b6b10d32
--- /dev/null
+++ b/libcef_dll/ctocpp/preference_registrar_ctocpp.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=bcd7981d2a8feae116d3c658f430f9753c11612d$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_PREFERENCE_REGISTRAR_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_PREFERENCE_REGISTRAR_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_preference_capi.h"
+#include "include/cef_preference.h"
+#include "libcef_dll/ctocpp/ctocpp_scoped.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefPreferenceRegistrarCToCpp
+ : public CefCToCppScoped<CefPreferenceRegistrarCToCpp,
+ CefPreferenceRegistrar,
+ cef_preference_registrar_t> {
+ public:
+ CefPreferenceRegistrarCToCpp();
+ virtual ~CefPreferenceRegistrarCToCpp();
+
+ // CefPreferenceRegistrar methods.
+ bool AddPreference(const CefString& name,
+ CefRefPtr<CefValue> default_value) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_PREFERENCE_REGISTRAR_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/print_dialog_callback_ctocpp.cc b/libcef_dll/ctocpp/print_dialog_callback_ctocpp.cc
new file mode 100644
index 00000000..4327b459
--- /dev/null
+++ b/libcef_dll/ctocpp/print_dialog_callback_ctocpp.cc
@@ -0,0 +1,81 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=93f9d3b5ef4e7f4746529d2d1e0ee61952e56be0$
+//
+
+#include "libcef_dll/ctocpp/print_dialog_callback_ctocpp.h"
+#include "libcef_dll/ctocpp/print_settings_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+void CefPrintDialogCallbackCToCpp::Continue(
+ CefRefPtr<CefPrintSettings> settings) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_print_dialog_callback_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, cont)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: settings; type: refptr_same
+ DCHECK(settings.get());
+ if (!settings.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->cont(_struct, CefPrintSettingsCToCpp::Unwrap(settings));
+}
+
+NO_SANITIZE("cfi-icall") void CefPrintDialogCallbackCToCpp::Cancel() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_print_dialog_callback_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, cancel)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->cancel(_struct);
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefPrintDialogCallbackCToCpp::CefPrintDialogCallbackCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefPrintDialogCallbackCToCpp::~CefPrintDialogCallbackCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_print_dialog_callback_t* CefCToCppRefCounted<
+ CefPrintDialogCallbackCToCpp,
+ CefPrintDialogCallback,
+ cef_print_dialog_callback_t>::UnwrapDerived(CefWrapperType type,
+ CefPrintDialogCallback* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefPrintDialogCallbackCToCpp,
+ CefPrintDialogCallback,
+ cef_print_dialog_callback_t>::kWrapperType =
+ WT_PRINT_DIALOG_CALLBACK;
diff --git a/libcef_dll/ctocpp/print_dialog_callback_ctocpp.h b/libcef_dll/ctocpp/print_dialog_callback_ctocpp.h
new file mode 100644
index 00000000..cf5e9cbe
--- /dev/null
+++ b/libcef_dll/ctocpp/print_dialog_callback_ctocpp.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=7c49e07c9ba8bfc8f7620952b19140828a3bf011$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_PRINT_DIALOG_CALLBACK_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_PRINT_DIALOG_CALLBACK_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_print_handler_capi.h"
+#include "include/cef_print_handler.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefPrintDialogCallbackCToCpp
+ : public CefCToCppRefCounted<CefPrintDialogCallbackCToCpp,
+ CefPrintDialogCallback,
+ cef_print_dialog_callback_t> {
+ public:
+ CefPrintDialogCallbackCToCpp();
+ virtual ~CefPrintDialogCallbackCToCpp();
+
+ // CefPrintDialogCallback methods.
+ void Continue(CefRefPtr<CefPrintSettings> settings) override;
+ void Cancel() override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_PRINT_DIALOG_CALLBACK_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/print_handler_ctocpp.cc b/libcef_dll/ctocpp/print_handler_ctocpp.cc
new file mode 100644
index 00000000..948dbffc
--- /dev/null
+++ b/libcef_dll/ctocpp/print_handler_ctocpp.cc
@@ -0,0 +1,226 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=6b8fc1fd1fff48712c77d9402a0a1d747e14b5a1$
+//
+
+#include "libcef_dll/ctocpp/print_handler_ctocpp.h"
+#include "libcef_dll/cpptoc/browser_cpptoc.h"
+#include "libcef_dll/cpptoc/print_dialog_callback_cpptoc.h"
+#include "libcef_dll/cpptoc/print_job_callback_cpptoc.h"
+#include "libcef_dll/cpptoc/print_settings_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+void CefPrintHandlerCToCpp::OnPrintStart(CefRefPtr<CefBrowser> browser) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_print_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_print_start)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_print_start(_struct, CefBrowserCppToC::Wrap(browser));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefPrintHandlerCToCpp::OnPrintSettings(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefPrintSettings> settings,
+ bool get_defaults) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_print_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_print_settings)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+ // Verify param: settings; type: refptr_diff
+ DCHECK(settings.get());
+ if (!settings.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_print_settings(_struct, CefBrowserCppToC::Wrap(browser),
+ CefPrintSettingsCppToC::Wrap(settings),
+ get_defaults);
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefPrintHandlerCToCpp::OnPrintDialog(
+ CefRefPtr<CefBrowser> browser,
+ bool has_selection,
+ CefRefPtr<CefPrintDialogCallback> callback) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_print_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_print_dialog)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return false;
+ }
+ // Verify param: callback; type: refptr_diff
+ DCHECK(callback.get());
+ if (!callback.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->on_print_dialog(
+ _struct, CefBrowserCppToC::Wrap(browser), has_selection,
+ CefPrintDialogCallbackCppToC::Wrap(callback));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefPrintHandlerCToCpp::OnPrintJob(
+ CefRefPtr<CefBrowser> browser,
+ const CefString& document_name,
+ const CefString& pdf_file_path,
+ CefRefPtr<CefPrintJobCallback> callback) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_print_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_print_job)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return false;
+ }
+ // Verify param: document_name; type: string_byref_const
+ DCHECK(!document_name.empty());
+ if (document_name.empty()) {
+ return false;
+ }
+ // Verify param: pdf_file_path; type: string_byref_const
+ DCHECK(!pdf_file_path.empty());
+ if (pdf_file_path.empty()) {
+ return false;
+ }
+ // Verify param: callback; type: refptr_diff
+ DCHECK(callback.get());
+ if (!callback.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->on_print_job(
+ _struct, CefBrowserCppToC::Wrap(browser), document_name.GetStruct(),
+ pdf_file_path.GetStruct(), CefPrintJobCallbackCppToC::Wrap(callback));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefPrintHandlerCToCpp::OnPrintReset(CefRefPtr<CefBrowser> browser) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_print_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_print_reset)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_print_reset(_struct, CefBrowserCppToC::Wrap(browser));
+}
+
+NO_SANITIZE("cfi-icall")
+CefSize CefPrintHandlerCToCpp::GetPdfPaperSize(CefRefPtr<CefBrowser> browser,
+ int device_units_per_inch) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_print_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_pdf_paper_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval = _struct->get_pdf_paper_size(
+ _struct, CefBrowserCppToC::Wrap(browser), device_units_per_inch);
+
+ // Return type: simple
+ return _retval;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefPrintHandlerCToCpp::CefPrintHandlerCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefPrintHandlerCToCpp::~CefPrintHandlerCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_print_handler_t*
+CefCToCppRefCounted<CefPrintHandlerCToCpp,
+ CefPrintHandler,
+ cef_print_handler_t>::UnwrapDerived(CefWrapperType type,
+ CefPrintHandler* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefPrintHandlerCToCpp,
+ CefPrintHandler,
+ cef_print_handler_t>::kWrapperType =
+ WT_PRINT_HANDLER;
diff --git a/libcef_dll/ctocpp/print_handler_ctocpp.h b/libcef_dll/ctocpp/print_handler_ctocpp.h
new file mode 100644
index 00000000..5e7722f2
--- /dev/null
+++ b/libcef_dll/ctocpp/print_handler_ctocpp.h
@@ -0,0 +1,53 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=b1d082ab9bea88f46372a371b68b9b4c25a96ca2$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_PRINT_HANDLER_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_PRINT_HANDLER_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_print_handler_capi.h"
+#include "include/cef_print_handler.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefPrintHandlerCToCpp : public CefCToCppRefCounted<CefPrintHandlerCToCpp,
+ CefPrintHandler,
+ cef_print_handler_t> {
+ public:
+ CefPrintHandlerCToCpp();
+ virtual ~CefPrintHandlerCToCpp();
+
+ // CefPrintHandler methods.
+ void OnPrintStart(CefRefPtr<CefBrowser> browser) override;
+ void OnPrintSettings(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefPrintSettings> settings,
+ bool get_defaults) override;
+ bool OnPrintDialog(CefRefPtr<CefBrowser> browser,
+ bool has_selection,
+ CefRefPtr<CefPrintDialogCallback> callback) override;
+ bool OnPrintJob(CefRefPtr<CefBrowser> browser,
+ const CefString& document_name,
+ const CefString& pdf_file_path,
+ CefRefPtr<CefPrintJobCallback> callback) override;
+ void OnPrintReset(CefRefPtr<CefBrowser> browser) override;
+ CefSize GetPdfPaperSize(CefRefPtr<CefBrowser> browser,
+ int device_units_per_inch) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_PRINT_HANDLER_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/print_job_callback_ctocpp.cc b/libcef_dll/ctocpp/print_job_callback_ctocpp.cc
new file mode 100644
index 00000000..471dbd10
--- /dev/null
+++ b/libcef_dll/ctocpp/print_job_callback_ctocpp.cc
@@ -0,0 +1,58 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=6d7e2581786609dd5b472dd72dae47f26c1e7e7d$
+//
+
+#include "libcef_dll/ctocpp/print_job_callback_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") void CefPrintJobCallbackCToCpp::Continue() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_print_job_callback_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, cont)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->cont(_struct);
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefPrintJobCallbackCToCpp::CefPrintJobCallbackCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefPrintJobCallbackCToCpp::~CefPrintJobCallbackCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_print_job_callback_t* CefCToCppRefCounted<
+ CefPrintJobCallbackCToCpp,
+ CefPrintJobCallback,
+ cef_print_job_callback_t>::UnwrapDerived(CefWrapperType type,
+ CefPrintJobCallback* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefPrintJobCallbackCToCpp,
+ CefPrintJobCallback,
+ cef_print_job_callback_t>::kWrapperType =
+ WT_PRINT_JOB_CALLBACK;
diff --git a/libcef_dll/ctocpp/print_job_callback_ctocpp.h b/libcef_dll/ctocpp/print_job_callback_ctocpp.h
new file mode 100644
index 00000000..6f7710e1
--- /dev/null
+++ b/libcef_dll/ctocpp/print_job_callback_ctocpp.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=6ac2e8d5475582b66e40e297b192bdbdc8acbeed$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_PRINT_JOB_CALLBACK_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_PRINT_JOB_CALLBACK_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_print_handler_capi.h"
+#include "include/cef_print_handler.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefPrintJobCallbackCToCpp
+ : public CefCToCppRefCounted<CefPrintJobCallbackCToCpp,
+ CefPrintJobCallback,
+ cef_print_job_callback_t> {
+ public:
+ CefPrintJobCallbackCToCpp();
+ virtual ~CefPrintJobCallbackCToCpp();
+
+ // CefPrintJobCallback methods.
+ void Continue() override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_PRINT_JOB_CALLBACK_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/print_settings_ctocpp.cc b/libcef_dll/ctocpp/print_settings_ctocpp.cc
new file mode 100644
index 00000000..199948a0
--- /dev/null
+++ b/libcef_dll/ctocpp/print_settings_ctocpp.cc
@@ -0,0 +1,464 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=479c82d8c72edba5bc48bdd8e32677ebe0bc720e$
+//
+
+#include "libcef_dll/ctocpp/print_settings_ctocpp.h"
+#include <algorithm>
+#include "libcef_dll/shutdown_checker.h"
+
+// STATIC METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefPrintSettings> CefPrintSettings::Create() {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_print_settings_t* _retval = cef_print_settings_create();
+
+ // Return type: refptr_same
+ return CefPrintSettingsCToCpp::Wrap(_retval);
+}
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") bool CefPrintSettingsCToCpp::IsValid() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_print_settings_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_valid)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_valid(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefPrintSettingsCToCpp::IsReadOnly() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_print_settings_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_read_only)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_read_only(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefPrintSettingsCToCpp::SetOrientation(bool landscape) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_print_settings_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_orientation)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_orientation(_struct, landscape);
+}
+
+NO_SANITIZE("cfi-icall") bool CefPrintSettingsCToCpp::IsLandscape() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_print_settings_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_landscape)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_landscape(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefPrintSettingsCToCpp::SetPrinterPrintableArea(
+ const CefSize& physical_size_device_units,
+ const CefRect& printable_area_device_units,
+ bool landscape_needs_flip) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_print_settings_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_printer_printable_area)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_printer_printable_area(_struct, &physical_size_device_units,
+ &printable_area_device_units,
+ landscape_needs_flip);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefPrintSettingsCToCpp::SetDeviceName(const CefString& name) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_print_settings_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_device_name)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: name
+
+ // Execute
+ _struct->set_device_name(_struct, name.GetStruct());
+}
+
+NO_SANITIZE("cfi-icall") CefString CefPrintSettingsCToCpp::GetDeviceName() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_print_settings_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_device_name)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_device_name(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") void CefPrintSettingsCToCpp::SetDPI(int dpi) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_print_settings_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_dpi)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_dpi(_struct, dpi);
+}
+
+NO_SANITIZE("cfi-icall") int CefPrintSettingsCToCpp::GetDPI() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_print_settings_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_dpi)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_dpi(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefPrintSettingsCToCpp::SetPageRanges(const PageRangeList& ranges) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_print_settings_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_page_ranges)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Translate param: ranges; type: simple_vec_byref_const
+ const size_t rangesCount = ranges.size();
+ cef_range_t* rangesList = NULL;
+ if (rangesCount > 0) {
+ rangesList = new cef_range_t[rangesCount];
+ DCHECK(rangesList);
+ if (rangesList) {
+ for (size_t i = 0; i < rangesCount; ++i) {
+ rangesList[i] = ranges[i];
+ }
+ }
+ }
+
+ // Execute
+ _struct->set_page_ranges(_struct, rangesCount, rangesList);
+
+ // Restore param:ranges; type: simple_vec_byref_const
+ if (rangesList) {
+ delete[] rangesList;
+ }
+}
+
+NO_SANITIZE("cfi-icall") size_t CefPrintSettingsCToCpp::GetPageRangesCount() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_print_settings_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_page_ranges_count)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ size_t _retval = _struct->get_page_ranges_count(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefPrintSettingsCToCpp::GetPageRanges(PageRangeList& ranges) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_print_settings_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_page_ranges)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Translate param: ranges; type: simple_vec_byref
+ size_t rangesSize = ranges.size();
+ size_t rangesCount = std::max(GetPageRangesCount(), rangesSize);
+ cef_range_t* rangesList = NULL;
+ if (rangesCount > 0) {
+ rangesList = new cef_range_t[rangesCount];
+ DCHECK(rangesList);
+ if (rangesList) {
+ memset(rangesList, 0, sizeof(cef_range_t) * rangesCount);
+ }
+ if (rangesList && rangesSize > 0) {
+ for (size_t i = 0; i < rangesSize; ++i) {
+ rangesList[i] = ranges[i];
+ }
+ }
+ }
+
+ // Execute
+ _struct->get_page_ranges(_struct, &rangesCount, rangesList);
+
+ // Restore param:ranges; type: simple_vec_byref
+ ranges.clear();
+ if (rangesCount > 0 && rangesList) {
+ for (size_t i = 0; i < rangesCount; ++i) {
+ ranges.push_back(rangesList[i]);
+ }
+ delete[] rangesList;
+ }
+}
+
+NO_SANITIZE("cfi-icall")
+void CefPrintSettingsCToCpp::SetSelectionOnly(bool selection_only) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_print_settings_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_selection_only)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_selection_only(_struct, selection_only);
+}
+
+NO_SANITIZE("cfi-icall") bool CefPrintSettingsCToCpp::IsSelectionOnly() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_print_settings_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_selection_only)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_selection_only(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") void CefPrintSettingsCToCpp::SetCollate(bool collate) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_print_settings_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_collate)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_collate(_struct, collate);
+}
+
+NO_SANITIZE("cfi-icall") bool CefPrintSettingsCToCpp::WillCollate() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_print_settings_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, will_collate)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->will_collate(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefPrintSettingsCToCpp::SetColorModel(ColorModel model) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_print_settings_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_color_model)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_color_model(_struct, model);
+}
+
+NO_SANITIZE("cfi-icall")
+CefPrintSettings::ColorModel CefPrintSettingsCToCpp::GetColorModel() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_print_settings_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_color_model)) {
+ return COLOR_MODEL_UNKNOWN;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_color_model_t _retval = _struct->get_color_model(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") void CefPrintSettingsCToCpp::SetCopies(int copies) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_print_settings_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_copies)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_copies(_struct, copies);
+}
+
+NO_SANITIZE("cfi-icall") int CefPrintSettingsCToCpp::GetCopies() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_print_settings_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_copies)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_copies(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefPrintSettingsCToCpp::SetDuplexMode(DuplexMode mode) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_print_settings_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_duplex_mode)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_duplex_mode(_struct, mode);
+}
+
+NO_SANITIZE("cfi-icall")
+CefPrintSettings::DuplexMode CefPrintSettingsCToCpp::GetDuplexMode() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_print_settings_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_duplex_mode)) {
+ return DUPLEX_MODE_UNKNOWN;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_duplex_mode_t _retval = _struct->get_duplex_mode(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefPrintSettingsCToCpp::CefPrintSettingsCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefPrintSettingsCToCpp::~CefPrintSettingsCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_print_settings_t*
+CefCToCppRefCounted<CefPrintSettingsCToCpp,
+ CefPrintSettings,
+ cef_print_settings_t>::UnwrapDerived(CefWrapperType type,
+ CefPrintSettings* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefPrintSettingsCToCpp,
+ CefPrintSettings,
+ cef_print_settings_t>::kWrapperType =
+ WT_PRINT_SETTINGS;
diff --git a/libcef_dll/ctocpp/print_settings_ctocpp.h b/libcef_dll/ctocpp/print_settings_ctocpp.h
new file mode 100644
index 00000000..3c23fc18
--- /dev/null
+++ b/libcef_dll/ctocpp/print_settings_ctocpp.h
@@ -0,0 +1,64 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=75238f577e768438cead970fa7362e4b04856894$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_PRINT_SETTINGS_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_PRINT_SETTINGS_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_print_settings_capi.h"
+#include "include/cef_print_settings.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefPrintSettingsCToCpp
+ : public CefCToCppRefCounted<CefPrintSettingsCToCpp,
+ CefPrintSettings,
+ cef_print_settings_t> {
+ public:
+ CefPrintSettingsCToCpp();
+ virtual ~CefPrintSettingsCToCpp();
+
+ // CefPrintSettings methods.
+ bool IsValid() override;
+ bool IsReadOnly() override;
+ void SetOrientation(bool landscape) override;
+ bool IsLandscape() override;
+ void SetPrinterPrintableArea(const CefSize& physical_size_device_units,
+ const CefRect& printable_area_device_units,
+ bool landscape_needs_flip) override;
+ void SetDeviceName(const CefString& name) override;
+ CefString GetDeviceName() override;
+ void SetDPI(int dpi) override;
+ int GetDPI() override;
+ void SetPageRanges(const PageRangeList& ranges) override;
+ size_t GetPageRangesCount() override;
+ void GetPageRanges(PageRangeList& ranges) override;
+ void SetSelectionOnly(bool selection_only) override;
+ bool IsSelectionOnly() override;
+ void SetCollate(bool collate) override;
+ bool WillCollate() override;
+ void SetColorModel(ColorModel model) override;
+ ColorModel GetColorModel() override;
+ void SetCopies(int copies) override;
+ int GetCopies() override;
+ void SetDuplexMode(DuplexMode mode) override;
+ DuplexMode GetDuplexMode() override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_PRINT_SETTINGS_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/process_message_ctocpp.cc b/libcef_dll/ctocpp/process_message_ctocpp.cc
new file mode 100644
index 00000000..6c58c16b
--- /dev/null
+++ b/libcef_dll/ctocpp/process_message_ctocpp.cc
@@ -0,0 +1,176 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=ac50966059a1ba14d20824a27bcc19e9c0c0d910$
+//
+
+#include "libcef_dll/ctocpp/process_message_ctocpp.h"
+#include "libcef_dll/ctocpp/list_value_ctocpp.h"
+#include "libcef_dll/ctocpp/shared_memory_region_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// STATIC METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefProcessMessage> CefProcessMessage::Create(const CefString& name) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: name; type: string_byref_const
+ DCHECK(!name.empty());
+ if (name.empty()) {
+ return nullptr;
+ }
+
+ // Execute
+ cef_process_message_t* _retval = cef_process_message_create(name.GetStruct());
+
+ // Return type: refptr_same
+ return CefProcessMessageCToCpp::Wrap(_retval);
+}
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") bool CefProcessMessageCToCpp::IsValid() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_process_message_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_valid)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_valid(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefProcessMessageCToCpp::IsReadOnly() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_process_message_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_read_only)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_read_only(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefProcessMessage> CefProcessMessageCToCpp::Copy() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_process_message_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, copy)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_process_message_t* _retval = _struct->copy(_struct);
+
+ // Return type: refptr_same
+ return CefProcessMessageCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") CefString CefProcessMessageCToCpp::GetName() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_process_message_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_name)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_name(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefListValue> CefProcessMessageCToCpp::GetArgumentList() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_process_message_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_argument_list)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_list_value_t* _retval = _struct->get_argument_list(_struct);
+
+ // Return type: refptr_same
+ return CefListValueCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefSharedMemoryRegion>
+CefProcessMessageCToCpp::GetSharedMemoryRegion() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_process_message_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_shared_memory_region)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_shared_memory_region_t* _retval =
+ _struct->get_shared_memory_region(_struct);
+
+ // Return type: refptr_same
+ return CefSharedMemoryRegionCToCpp::Wrap(_retval);
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefProcessMessageCToCpp::CefProcessMessageCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefProcessMessageCToCpp::~CefProcessMessageCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_process_message_t* CefCToCppRefCounted<
+ CefProcessMessageCToCpp,
+ CefProcessMessage,
+ cef_process_message_t>::UnwrapDerived(CefWrapperType type,
+ CefProcessMessage* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefProcessMessageCToCpp,
+ CefProcessMessage,
+ cef_process_message_t>::kWrapperType =
+ WT_PROCESS_MESSAGE;
diff --git a/libcef_dll/ctocpp/process_message_ctocpp.h b/libcef_dll/ctocpp/process_message_ctocpp.h
new file mode 100644
index 00000000..87b569c2
--- /dev/null
+++ b/libcef_dll/ctocpp/process_message_ctocpp.h
@@ -0,0 +1,46 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=cf099f71fe1c451ca650912e7ba34ef54f2aa61b$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_PROCESS_MESSAGE_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_PROCESS_MESSAGE_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_process_message_capi.h"
+#include "include/cef_process_message.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefProcessMessageCToCpp
+ : public CefCToCppRefCounted<CefProcessMessageCToCpp,
+ CefProcessMessage,
+ cef_process_message_t> {
+ public:
+ CefProcessMessageCToCpp();
+ virtual ~CefProcessMessageCToCpp();
+
+ // CefProcessMessage methods.
+ bool IsValid() override;
+ bool IsReadOnly() override;
+ CefRefPtr<CefProcessMessage> Copy() override;
+ CefString GetName() override;
+ CefRefPtr<CefListValue> GetArgumentList() override;
+ CefRefPtr<CefSharedMemoryRegion> GetSharedMemoryRegion() override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_PROCESS_MESSAGE_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/read_handler_ctocpp.cc b/libcef_dll/ctocpp/read_handler_ctocpp.cc
new file mode 100644
index 00000000..0def1174
--- /dev/null
+++ b/libcef_dll/ctocpp/read_handler_ctocpp.cc
@@ -0,0 +1,135 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=ce1b7280f3a73296607a5f4440bffad40c73d5ad$
+//
+
+#include "libcef_dll/ctocpp/read_handler_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+size_t CefReadHandlerCToCpp::Read(void* ptr, size_t size, size_t n) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_read_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, read)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: ptr; type: simple_byaddr
+ DCHECK(ptr);
+ if (!ptr) {
+ return 0;
+ }
+
+ // Execute
+ size_t _retval = _struct->read(_struct, ptr, size, n);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+int CefReadHandlerCToCpp::Seek(int64 offset, int whence) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_read_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, seek)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->seek(_struct, offset, whence);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") int64 CefReadHandlerCToCpp::Tell() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_read_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, tell)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int64 _retval = _struct->tell(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") int CefReadHandlerCToCpp::Eof() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_read_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, eof)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->eof(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") bool CefReadHandlerCToCpp::MayBlock() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_read_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, may_block)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->may_block(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefReadHandlerCToCpp::CefReadHandlerCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefReadHandlerCToCpp::~CefReadHandlerCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_read_handler_t*
+CefCToCppRefCounted<CefReadHandlerCToCpp, CefReadHandler, cef_read_handler_t>::
+ UnwrapDerived(CefWrapperType type, CefReadHandler* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefReadHandlerCToCpp,
+ CefReadHandler,
+ cef_read_handler_t>::kWrapperType =
+ WT_READ_HANDLER;
diff --git a/libcef_dll/ctocpp/read_handler_ctocpp.h b/libcef_dll/ctocpp/read_handler_ctocpp.h
new file mode 100644
index 00000000..546462a4
--- /dev/null
+++ b/libcef_dll/ctocpp/read_handler_ctocpp.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=d4b05ef2f8edd18da8b5ed9c5d4afe8162f81069$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_READ_HANDLER_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_READ_HANDLER_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_stream_capi.h"
+#include "include/cef_stream.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefReadHandlerCToCpp : public CefCToCppRefCounted<CefReadHandlerCToCpp,
+ CefReadHandler,
+ cef_read_handler_t> {
+ public:
+ CefReadHandlerCToCpp();
+ virtual ~CefReadHandlerCToCpp();
+
+ // CefReadHandler methods.
+ size_t Read(void* ptr, size_t size, size_t n) override;
+ int Seek(int64 offset, int whence) override;
+ int64 Tell() override;
+ int Eof() override;
+ bool MayBlock() override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_READ_HANDLER_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/registration_ctocpp.cc b/libcef_dll/ctocpp/registration_ctocpp.cc
new file mode 100644
index 00000000..a0b5a00b
--- /dev/null
+++ b/libcef_dll/ctocpp/registration_ctocpp.cc
@@ -0,0 +1,42 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=e1eade4ceaefc7079366e8b0d29d499590273e8c$
+//
+
+#include "libcef_dll/ctocpp/registration_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefRegistrationCToCpp::CefRegistrationCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefRegistrationCToCpp::~CefRegistrationCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_registration_t*
+CefCToCppRefCounted<CefRegistrationCToCpp,
+ CefRegistration,
+ cef_registration_t>::UnwrapDerived(CefWrapperType type,
+ CefRegistration* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefRegistrationCToCpp,
+ CefRegistration,
+ cef_registration_t>::kWrapperType =
+ WT_REGISTRATION;
diff --git a/libcef_dll/ctocpp/registration_ctocpp.h b/libcef_dll/ctocpp/registration_ctocpp.h
new file mode 100644
index 00000000..b60a76fd
--- /dev/null
+++ b/libcef_dll/ctocpp/registration_ctocpp.h
@@ -0,0 +1,39 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=8b9f37f2e0d395e737bc158d7d4bfb5f5e85e5c4$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_REGISTRATION_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_REGISTRATION_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_registration_capi.h"
+#include "include/cef_registration.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefRegistrationCToCpp : public CefCToCppRefCounted<CefRegistrationCToCpp,
+ CefRegistration,
+ cef_registration_t> {
+ public:
+ CefRegistrationCToCpp();
+ virtual ~CefRegistrationCToCpp();
+
+ // CefRegistration methods.
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_REGISTRATION_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/render_handler_ctocpp.cc b/libcef_dll/ctocpp/render_handler_ctocpp.cc
new file mode 100644
index 00000000..73cd5bde
--- /dev/null
+++ b/libcef_dll/ctocpp/render_handler_ctocpp.cc
@@ -0,0 +1,540 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=65a8e5baeed8773ac21f0decf0f0b82c16754aef$
+//
+
+#include "libcef_dll/ctocpp/render_handler_ctocpp.h"
+#include "libcef_dll/cpptoc/browser_cpptoc.h"
+#include "libcef_dll/cpptoc/drag_data_cpptoc.h"
+#include "libcef_dll/ctocpp/accessibility_handler_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefAccessibilityHandler>
+CefRenderHandlerCToCpp::GetAccessibilityHandler() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_render_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_accessibility_handler)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_accessibility_handler_t* _retval =
+ _struct->get_accessibility_handler(_struct);
+
+ // Return type: refptr_same
+ return CefAccessibilityHandlerCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefRenderHandlerCToCpp::GetRootScreenRect(CefRefPtr<CefBrowser> browser,
+ CefRect& rect) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_render_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_root_screen_rect)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->get_root_screen_rect(
+ _struct, CefBrowserCppToC::Wrap(browser), &rect);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefRenderHandlerCToCpp::GetViewRect(CefRefPtr<CefBrowser> browser,
+ CefRect& rect) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_render_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_view_rect)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->get_view_rect(_struct, CefBrowserCppToC::Wrap(browser), &rect);
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefRenderHandlerCToCpp::GetScreenPoint(CefRefPtr<CefBrowser> browser,
+ int viewX,
+ int viewY,
+ int& screenX,
+ int& screenY) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_render_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_screen_point)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval =
+ _struct->get_screen_point(_struct, CefBrowserCppToC::Wrap(browser), viewX,
+ viewY, &screenX, &screenY);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefRenderHandlerCToCpp::GetScreenInfo(CefRefPtr<CefBrowser> browser,
+ CefScreenInfo& screen_info) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_render_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_screen_info)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->get_screen_info(
+ _struct, CefBrowserCppToC::Wrap(browser), &screen_info);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefRenderHandlerCToCpp::OnPopupShow(CefRefPtr<CefBrowser> browser,
+ bool show) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_render_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_popup_show)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_popup_show(_struct, CefBrowserCppToC::Wrap(browser), show);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefRenderHandlerCToCpp::OnPopupSize(CefRefPtr<CefBrowser> browser,
+ const CefRect& rect) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_render_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_popup_size)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_popup_size(_struct, CefBrowserCppToC::Wrap(browser), &rect);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefRenderHandlerCToCpp::OnPaint(CefRefPtr<CefBrowser> browser,
+ PaintElementType type,
+ const RectList& dirtyRects,
+ const void* buffer,
+ int width,
+ int height) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_render_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_paint)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+ // Verify param: buffer; type: simple_byaddr
+ DCHECK(buffer);
+ if (!buffer) {
+ return;
+ }
+
+ // Translate param: dirtyRects; type: simple_vec_byref_const
+ const size_t dirtyRectsCount = dirtyRects.size();
+ cef_rect_t* dirtyRectsList = NULL;
+ if (dirtyRectsCount > 0) {
+ dirtyRectsList = new cef_rect_t[dirtyRectsCount];
+ DCHECK(dirtyRectsList);
+ if (dirtyRectsList) {
+ for (size_t i = 0; i < dirtyRectsCount; ++i) {
+ dirtyRectsList[i] = dirtyRects[i];
+ }
+ }
+ }
+
+ // Execute
+ _struct->on_paint(_struct, CefBrowserCppToC::Wrap(browser), type,
+ dirtyRectsCount, dirtyRectsList, buffer, width, height);
+
+ // Restore param:dirtyRects; type: simple_vec_byref_const
+ if (dirtyRectsList) {
+ delete[] dirtyRectsList;
+ }
+}
+
+NO_SANITIZE("cfi-icall")
+void CefRenderHandlerCToCpp::OnAcceleratedPaint(CefRefPtr<CefBrowser> browser,
+ PaintElementType type,
+ const RectList& dirtyRects,
+ void* shared_handle) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_render_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_accelerated_paint)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+ // Verify param: shared_handle; type: simple_byaddr
+ DCHECK(shared_handle);
+ if (!shared_handle) {
+ return;
+ }
+
+ // Translate param: dirtyRects; type: simple_vec_byref_const
+ const size_t dirtyRectsCount = dirtyRects.size();
+ cef_rect_t* dirtyRectsList = NULL;
+ if (dirtyRectsCount > 0) {
+ dirtyRectsList = new cef_rect_t[dirtyRectsCount];
+ DCHECK(dirtyRectsList);
+ if (dirtyRectsList) {
+ for (size_t i = 0; i < dirtyRectsCount; ++i) {
+ dirtyRectsList[i] = dirtyRects[i];
+ }
+ }
+ }
+
+ // Execute
+ _struct->on_accelerated_paint(_struct, CefBrowserCppToC::Wrap(browser), type,
+ dirtyRectsCount, dirtyRectsList, shared_handle);
+
+ // Restore param:dirtyRects; type: simple_vec_byref_const
+ if (dirtyRectsList) {
+ delete[] dirtyRectsList;
+ }
+}
+
+NO_SANITIZE("cfi-icall")
+void CefRenderHandlerCToCpp::GetTouchHandleSize(
+ CefRefPtr<CefBrowser> browser,
+ cef_horizontal_alignment_t orientation,
+ CefSize& size) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_render_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_touch_handle_size)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->get_touch_handle_size(_struct, CefBrowserCppToC::Wrap(browser),
+ orientation, &size);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefRenderHandlerCToCpp::OnTouchHandleStateChanged(
+ CefRefPtr<CefBrowser> browser,
+ const CefTouchHandleState& state) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_render_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_touch_handle_state_changed)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_touch_handle_state_changed(
+ _struct, CefBrowserCppToC::Wrap(browser), &state);
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefRenderHandlerCToCpp::StartDragging(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefDragData> drag_data,
+ DragOperationsMask allowed_ops,
+ int x,
+ int y) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_render_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, start_dragging)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return false;
+ }
+ // Verify param: drag_data; type: refptr_diff
+ DCHECK(drag_data.get());
+ if (!drag_data.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->start_dragging(
+ _struct, CefBrowserCppToC::Wrap(browser),
+ CefDragDataCppToC::Wrap(drag_data), allowed_ops, x, y);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefRenderHandlerCToCpp::UpdateDragCursor(CefRefPtr<CefBrowser> browser,
+ DragOperation operation) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_render_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, update_drag_cursor)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->update_drag_cursor(_struct, CefBrowserCppToC::Wrap(browser),
+ operation);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefRenderHandlerCToCpp::OnScrollOffsetChanged(
+ CefRefPtr<CefBrowser> browser,
+ double x,
+ double y) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_render_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_scroll_offset_changed)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_scroll_offset_changed(_struct, CefBrowserCppToC::Wrap(browser), x,
+ y);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefRenderHandlerCToCpp::OnImeCompositionRangeChanged(
+ CefRefPtr<CefBrowser> browser,
+ const CefRange& selected_range,
+ const RectList& character_bounds) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_render_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_ime_composition_range_changed)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+
+ // Translate param: character_bounds; type: simple_vec_byref_const
+ const size_t character_boundsCount = character_bounds.size();
+ cef_rect_t* character_boundsList = NULL;
+ if (character_boundsCount > 0) {
+ character_boundsList = new cef_rect_t[character_boundsCount];
+ DCHECK(character_boundsList);
+ if (character_boundsList) {
+ for (size_t i = 0; i < character_boundsCount; ++i) {
+ character_boundsList[i] = character_bounds[i];
+ }
+ }
+ }
+
+ // Execute
+ _struct->on_ime_composition_range_changed(
+ _struct, CefBrowserCppToC::Wrap(browser), &selected_range,
+ character_boundsCount, character_boundsList);
+
+ // Restore param:character_bounds; type: simple_vec_byref_const
+ if (character_boundsList) {
+ delete[] character_boundsList;
+ }
+}
+
+NO_SANITIZE("cfi-icall")
+void CefRenderHandlerCToCpp::OnTextSelectionChanged(
+ CefRefPtr<CefBrowser> browser,
+ const CefString& selected_text,
+ const CefRange& selected_range) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_render_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_text_selection_changed)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+ // Unverified params: selected_text, selected_range
+
+ // Execute
+ _struct->on_text_selection_changed(_struct, CefBrowserCppToC::Wrap(browser),
+ selected_text.GetStruct(),
+ &selected_range);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefRenderHandlerCToCpp::OnVirtualKeyboardRequested(
+ CefRefPtr<CefBrowser> browser,
+ TextInputMode input_mode) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_render_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_virtual_keyboard_requested)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_virtual_keyboard_requested(
+ _struct, CefBrowserCppToC::Wrap(browser), input_mode);
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefRenderHandlerCToCpp::CefRenderHandlerCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefRenderHandlerCToCpp::~CefRenderHandlerCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_render_handler_t*
+CefCToCppRefCounted<CefRenderHandlerCToCpp,
+ CefRenderHandler,
+ cef_render_handler_t>::UnwrapDerived(CefWrapperType type,
+ CefRenderHandler* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefRenderHandlerCToCpp,
+ CefRenderHandler,
+ cef_render_handler_t>::kWrapperType =
+ WT_RENDER_HANDLER;
diff --git a/libcef_dll/ctocpp/render_handler_ctocpp.h b/libcef_dll/ctocpp/render_handler_ctocpp.h
new file mode 100644
index 00000000..bd21445d
--- /dev/null
+++ b/libcef_dll/ctocpp/render_handler_ctocpp.h
@@ -0,0 +1,85 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=e10b3b9a07b4b6929a4168ad657c0046200c1d75$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_RENDER_HANDLER_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_RENDER_HANDLER_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_render_handler_capi.h"
+#include "include/cef_render_handler.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefRenderHandlerCToCpp
+ : public CefCToCppRefCounted<CefRenderHandlerCToCpp,
+ CefRenderHandler,
+ cef_render_handler_t> {
+ public:
+ CefRenderHandlerCToCpp();
+ virtual ~CefRenderHandlerCToCpp();
+
+ // CefRenderHandler methods.
+ CefRefPtr<CefAccessibilityHandler> GetAccessibilityHandler() override;
+ bool GetRootScreenRect(CefRefPtr<CefBrowser> browser, CefRect& rect) override;
+ void GetViewRect(CefRefPtr<CefBrowser> browser, CefRect& rect) override;
+ bool GetScreenPoint(CefRefPtr<CefBrowser> browser,
+ int viewX,
+ int viewY,
+ int& screenX,
+ int& screenY) override;
+ bool GetScreenInfo(CefRefPtr<CefBrowser> browser,
+ CefScreenInfo& screen_info) override;
+ void OnPopupShow(CefRefPtr<CefBrowser> browser, bool show) override;
+ void OnPopupSize(CefRefPtr<CefBrowser> browser, const CefRect& rect) override;
+ void OnPaint(CefRefPtr<CefBrowser> browser,
+ PaintElementType type,
+ const RectList& dirtyRects,
+ const void* buffer,
+ int width,
+ int height) override;
+ void OnAcceleratedPaint(CefRefPtr<CefBrowser> browser,
+ PaintElementType type,
+ const RectList& dirtyRects,
+ void* shared_handle) override;
+ void GetTouchHandleSize(CefRefPtr<CefBrowser> browser,
+ cef_horizontal_alignment_t orientation,
+ CefSize& size) override;
+ void OnTouchHandleStateChanged(CefRefPtr<CefBrowser> browser,
+ const CefTouchHandleState& state) override;
+ bool StartDragging(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefDragData> drag_data,
+ DragOperationsMask allowed_ops,
+ int x,
+ int y) override;
+ void UpdateDragCursor(CefRefPtr<CefBrowser> browser,
+ DragOperation operation) override;
+ void OnScrollOffsetChanged(CefRefPtr<CefBrowser> browser,
+ double x,
+ double y) override;
+ void OnImeCompositionRangeChanged(CefRefPtr<CefBrowser> browser,
+ const CefRange& selected_range,
+ const RectList& character_bounds) override;
+ void OnTextSelectionChanged(CefRefPtr<CefBrowser> browser,
+ const CefString& selected_text,
+ const CefRange& selected_range) override;
+ void OnVirtualKeyboardRequested(CefRefPtr<CefBrowser> browser,
+ TextInputMode input_mode) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_RENDER_HANDLER_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/render_process_handler_ctocpp.cc b/libcef_dll/ctocpp/render_process_handler_ctocpp.cc
new file mode 100644
index 00000000..53a42fd3
--- /dev/null
+++ b/libcef_dll/ctocpp/render_process_handler_ctocpp.cc
@@ -0,0 +1,300 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=a6f27ab9f9842ab192ea253a5e66aea4e37466f8$
+//
+
+#include "libcef_dll/ctocpp/render_process_handler_ctocpp.h"
+#include "libcef_dll/cpptoc/browser_cpptoc.h"
+#include "libcef_dll/cpptoc/dictionary_value_cpptoc.h"
+#include "libcef_dll/cpptoc/domnode_cpptoc.h"
+#include "libcef_dll/cpptoc/frame_cpptoc.h"
+#include "libcef_dll/cpptoc/process_message_cpptoc.h"
+#include "libcef_dll/cpptoc/v8context_cpptoc.h"
+#include "libcef_dll/cpptoc/v8exception_cpptoc.h"
+#include "libcef_dll/cpptoc/v8stack_trace_cpptoc.h"
+#include "libcef_dll/ctocpp/load_handler_ctocpp.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+void CefRenderProcessHandlerCToCpp::OnWebKitInitialized() {
+ cef_render_process_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_web_kit_initialized)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->on_web_kit_initialized(_struct);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefRenderProcessHandlerCToCpp::OnBrowserCreated(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefDictionaryValue> extra_info) {
+ cef_render_process_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_browser_created)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+ // Unverified params: extra_info
+
+ // Execute
+ _struct->on_browser_created(_struct, CefBrowserCppToC::Wrap(browser),
+ CefDictionaryValueCppToC::Wrap(extra_info));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefRenderProcessHandlerCToCpp::OnBrowserDestroyed(
+ CefRefPtr<CefBrowser> browser) {
+ cef_render_process_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_browser_destroyed)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_browser_destroyed(_struct, CefBrowserCppToC::Wrap(browser));
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefLoadHandler> CefRenderProcessHandlerCToCpp::GetLoadHandler() {
+ cef_render_process_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_load_handler)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_load_handler_t* _retval = _struct->get_load_handler(_struct);
+
+ // Return type: refptr_same
+ return CefLoadHandlerCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefRenderProcessHandlerCToCpp::OnContextCreated(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefV8Context> context) {
+ cef_render_process_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_context_created)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+ // Verify param: frame; type: refptr_diff
+ DCHECK(frame.get());
+ if (!frame.get()) {
+ return;
+ }
+ // Verify param: context; type: refptr_diff
+ DCHECK(context.get());
+ if (!context.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_context_created(_struct, CefBrowserCppToC::Wrap(browser),
+ CefFrameCppToC::Wrap(frame),
+ CefV8ContextCppToC::Wrap(context));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefRenderProcessHandlerCToCpp::OnContextReleased(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefV8Context> context) {
+ cef_render_process_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_context_released)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+ // Verify param: frame; type: refptr_diff
+ DCHECK(frame.get());
+ if (!frame.get()) {
+ return;
+ }
+ // Verify param: context; type: refptr_diff
+ DCHECK(context.get());
+ if (!context.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_context_released(_struct, CefBrowserCppToC::Wrap(browser),
+ CefFrameCppToC::Wrap(frame),
+ CefV8ContextCppToC::Wrap(context));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefRenderProcessHandlerCToCpp::OnUncaughtException(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefV8Context> context,
+ CefRefPtr<CefV8Exception> exception,
+ CefRefPtr<CefV8StackTrace> stackTrace) {
+ cef_render_process_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_uncaught_exception)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+ // Verify param: frame; type: refptr_diff
+ DCHECK(frame.get());
+ if (!frame.get()) {
+ return;
+ }
+ // Verify param: context; type: refptr_diff
+ DCHECK(context.get());
+ if (!context.get()) {
+ return;
+ }
+ // Verify param: exception; type: refptr_diff
+ DCHECK(exception.get());
+ if (!exception.get()) {
+ return;
+ }
+ // Verify param: stackTrace; type: refptr_diff
+ DCHECK(stackTrace.get());
+ if (!stackTrace.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_uncaught_exception(
+ _struct, CefBrowserCppToC::Wrap(browser), CefFrameCppToC::Wrap(frame),
+ CefV8ContextCppToC::Wrap(context), CefV8ExceptionCppToC::Wrap(exception),
+ CefV8StackTraceCppToC::Wrap(stackTrace));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefRenderProcessHandlerCToCpp::OnFocusedNodeChanged(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefDOMNode> node) {
+ cef_render_process_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_focused_node_changed)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+ // Unverified params: frame, node
+
+ // Execute
+ _struct->on_focused_node_changed(_struct, CefBrowserCppToC::Wrap(browser),
+ CefFrameCppToC::Wrap(frame),
+ CefDOMNodeCppToC::Wrap(node));
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefRenderProcessHandlerCToCpp::OnProcessMessageReceived(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefProcessId source_process,
+ CefRefPtr<CefProcessMessage> message) {
+ cef_render_process_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_process_message_received)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return false;
+ }
+ // Verify param: frame; type: refptr_diff
+ DCHECK(frame.get());
+ if (!frame.get()) {
+ return false;
+ }
+ // Verify param: message; type: refptr_diff
+ DCHECK(message.get());
+ if (!message.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->on_process_message_received(
+ _struct, CefBrowserCppToC::Wrap(browser), CefFrameCppToC::Wrap(frame),
+ source_process, CefProcessMessageCppToC::Wrap(message));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefRenderProcessHandlerCToCpp::CefRenderProcessHandlerCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefRenderProcessHandlerCToCpp::~CefRenderProcessHandlerCToCpp() {}
+
+template <>
+cef_render_process_handler_t* CefCToCppRefCounted<
+ CefRenderProcessHandlerCToCpp,
+ CefRenderProcessHandler,
+ cef_render_process_handler_t>::UnwrapDerived(CefWrapperType type,
+ CefRenderProcessHandler* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefRenderProcessHandlerCToCpp,
+ CefRenderProcessHandler,
+ cef_render_process_handler_t>::kWrapperType =
+ WT_RENDER_PROCESS_HANDLER;
diff --git a/libcef_dll/ctocpp/render_process_handler_ctocpp.h b/libcef_dll/ctocpp/render_process_handler_ctocpp.h
new file mode 100644
index 00000000..dcf49a67
--- /dev/null
+++ b/libcef_dll/ctocpp/render_process_handler_ctocpp.h
@@ -0,0 +1,63 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=1e5030658a4775df8e1eb8bbd54c43cdacf4572a$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_RENDER_PROCESS_HANDLER_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_RENDER_PROCESS_HANDLER_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_render_process_handler_capi.h"
+#include "include/cef_render_process_handler.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefRenderProcessHandlerCToCpp
+ : public CefCToCppRefCounted<CefRenderProcessHandlerCToCpp,
+ CefRenderProcessHandler,
+ cef_render_process_handler_t> {
+ public:
+ CefRenderProcessHandlerCToCpp();
+ virtual ~CefRenderProcessHandlerCToCpp();
+
+ // CefRenderProcessHandler methods.
+ void OnWebKitInitialized() override;
+ void OnBrowserCreated(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefDictionaryValue> extra_info) override;
+ void OnBrowserDestroyed(CefRefPtr<CefBrowser> browser) override;
+ CefRefPtr<CefLoadHandler> GetLoadHandler() override;
+ void OnContextCreated(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefV8Context> context) override;
+ void OnContextReleased(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefV8Context> context) override;
+ void OnUncaughtException(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefV8Context> context,
+ CefRefPtr<CefV8Exception> exception,
+ CefRefPtr<CefV8StackTrace> stackTrace) override;
+ void OnFocusedNodeChanged(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefDOMNode> node) override;
+ bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefProcessId source_process,
+ CefRefPtr<CefProcessMessage> message) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_RENDER_PROCESS_HANDLER_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/request_context_ctocpp.cc b/libcef_dll/ctocpp/request_context_ctocpp.cc
new file mode 100644
index 00000000..5806155e
--- /dev/null
+++ b/libcef_dll/ctocpp/request_context_ctocpp.cc
@@ -0,0 +1,601 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=ebc2c4b31cdbde186263ed5eccbb6cc3e7da1d30$
+//
+
+#include "libcef_dll/ctocpp/request_context_ctocpp.h"
+#include "libcef_dll/cpptoc/completion_callback_cpptoc.h"
+#include "libcef_dll/cpptoc/extension_handler_cpptoc.h"
+#include "libcef_dll/cpptoc/request_context_handler_cpptoc.h"
+#include "libcef_dll/cpptoc/resolve_callback_cpptoc.h"
+#include "libcef_dll/cpptoc/scheme_handler_factory_cpptoc.h"
+#include "libcef_dll/ctocpp/cookie_manager_ctocpp.h"
+#include "libcef_dll/ctocpp/dictionary_value_ctocpp.h"
+#include "libcef_dll/ctocpp/extension_ctocpp.h"
+#include "libcef_dll/ctocpp/media_router_ctocpp.h"
+#include "libcef_dll/ctocpp/value_ctocpp.h"
+#include "libcef_dll/transfer_util.h"
+
+// STATIC METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefRequestContext> CefRequestContext::GetGlobalContext() {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_request_context_t* _retval = cef_request_context_get_global_context();
+
+ // Return type: refptr_same
+ return CefRequestContextCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefRequestContext> CefRequestContext::CreateContext(
+ const CefRequestContextSettings& settings,
+ CefRefPtr<CefRequestContextHandler> handler) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: handler
+
+ // Execute
+ cef_request_context_t* _retval = cef_request_context_create_context(
+ &settings, CefRequestContextHandlerCppToC::Wrap(handler));
+
+ // Return type: refptr_same
+ return CefRequestContextCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefRequestContext> CefRequestContext::CreateContext(
+ CefRefPtr<CefRequestContext> other,
+ CefRefPtr<CefRequestContextHandler> handler) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: other; type: refptr_same
+ DCHECK(other.get());
+ if (!other.get()) {
+ return nullptr;
+ }
+ // Unverified params: handler
+
+ // Execute
+ cef_request_context_t* _retval =
+ cef_create_context_shared(CefRequestContextCToCpp::Unwrap(other),
+ CefRequestContextHandlerCppToC::Wrap(handler));
+
+ // Return type: refptr_same
+ return CefRequestContextCToCpp::Wrap(_retval);
+}
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+bool CefRequestContextCToCpp::IsSame(CefRefPtr<CefRequestContext> other) {
+ cef_request_context_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_same)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: other; type: refptr_same
+ DCHECK(other.get());
+ if (!other.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval =
+ _struct->is_same(_struct, CefRequestContextCToCpp::Unwrap(other));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefRequestContextCToCpp::IsSharingWith(
+ CefRefPtr<CefRequestContext> other) {
+ cef_request_context_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_sharing_with)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: other; type: refptr_same
+ DCHECK(other.get());
+ if (!other.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval =
+ _struct->is_sharing_with(_struct, CefRequestContextCToCpp::Unwrap(other));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefRequestContextCToCpp::IsGlobal() {
+ cef_request_context_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_global)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_global(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefRequestContextHandler> CefRequestContextCToCpp::GetHandler() {
+ cef_request_context_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_handler)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_request_context_handler_t* _retval = _struct->get_handler(_struct);
+
+ // Return type: refptr_diff
+ return CefRequestContextHandlerCppToC::Unwrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") CefString CefRequestContextCToCpp::GetCachePath() {
+ cef_request_context_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_cache_path)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_cache_path(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefCookieManager> CefRequestContextCToCpp::GetCookieManager(
+ CefRefPtr<CefCompletionCallback> callback) {
+ cef_request_context_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_cookie_manager)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: callback
+
+ // Execute
+ cef_cookie_manager_t* _retval = _struct->get_cookie_manager(
+ _struct, CefCompletionCallbackCppToC::Wrap(callback));
+
+ // Return type: refptr_same
+ return CefCookieManagerCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefRequestContextCToCpp::RegisterSchemeHandlerFactory(
+ const CefString& scheme_name,
+ const CefString& domain_name,
+ CefRefPtr<CefSchemeHandlerFactory> factory) {
+ cef_request_context_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, register_scheme_handler_factory)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: scheme_name; type: string_byref_const
+ DCHECK(!scheme_name.empty());
+ if (scheme_name.empty()) {
+ return false;
+ }
+ // Unverified params: domain_name, factory
+
+ // Execute
+ int _retval = _struct->register_scheme_handler_factory(
+ _struct, scheme_name.GetStruct(), domain_name.GetStruct(),
+ CefSchemeHandlerFactoryCppToC::Wrap(factory));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefRequestContextCToCpp::ClearSchemeHandlerFactories() {
+ cef_request_context_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, clear_scheme_handler_factories)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->clear_scheme_handler_factories(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefRequestContextCToCpp::ClearCertificateExceptions(
+ CefRefPtr<CefCompletionCallback> callback) {
+ cef_request_context_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, clear_certificate_exceptions)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: callback
+
+ // Execute
+ _struct->clear_certificate_exceptions(
+ _struct, CefCompletionCallbackCppToC::Wrap(callback));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefRequestContextCToCpp::ClearHttpAuthCredentials(
+ CefRefPtr<CefCompletionCallback> callback) {
+ cef_request_context_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, clear_http_auth_credentials)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: callback
+
+ // Execute
+ _struct->clear_http_auth_credentials(
+ _struct, CefCompletionCallbackCppToC::Wrap(callback));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefRequestContextCToCpp::CloseAllConnections(
+ CefRefPtr<CefCompletionCallback> callback) {
+ cef_request_context_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, close_all_connections)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: callback
+
+ // Execute
+ _struct->close_all_connections(_struct,
+ CefCompletionCallbackCppToC::Wrap(callback));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefRequestContextCToCpp::ResolveHost(
+ const CefString& origin,
+ CefRefPtr<CefResolveCallback> callback) {
+ cef_request_context_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, resolve_host)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: origin; type: string_byref_const
+ DCHECK(!origin.empty());
+ if (origin.empty()) {
+ return;
+ }
+ // Verify param: callback; type: refptr_diff
+ DCHECK(callback.get());
+ if (!callback.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->resolve_host(_struct, origin.GetStruct(),
+ CefResolveCallbackCppToC::Wrap(callback));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefRequestContextCToCpp::LoadExtension(
+ const CefString& root_directory,
+ CefRefPtr<CefDictionaryValue> manifest,
+ CefRefPtr<CefExtensionHandler> handler) {
+ cef_request_context_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, load_extension)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: root_directory; type: string_byref_const
+ DCHECK(!root_directory.empty());
+ if (root_directory.empty()) {
+ return;
+ }
+ // Unverified params: manifest, handler
+
+ // Execute
+ _struct->load_extension(_struct, root_directory.GetStruct(),
+ CefDictionaryValueCToCpp::Unwrap(manifest),
+ CefExtensionHandlerCppToC::Wrap(handler));
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefRequestContextCToCpp::DidLoadExtension(const CefString& extension_id) {
+ cef_request_context_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, did_load_extension)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: extension_id; type: string_byref_const
+ DCHECK(!extension_id.empty());
+ if (extension_id.empty()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->did_load_extension(_struct, extension_id.GetStruct());
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefRequestContextCToCpp::HasExtension(const CefString& extension_id) {
+ cef_request_context_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, has_extension)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: extension_id; type: string_byref_const
+ DCHECK(!extension_id.empty());
+ if (extension_id.empty()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->has_extension(_struct, extension_id.GetStruct());
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefRequestContextCToCpp::GetExtensions(
+ std::vector<CefString>& extension_ids) {
+ cef_request_context_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_extensions)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Translate param: extension_ids; type: string_vec_byref
+ cef_string_list_t extension_idsList = cef_string_list_alloc();
+ DCHECK(extension_idsList);
+ if (extension_idsList) {
+ transfer_string_list_contents(extension_ids, extension_idsList);
+ }
+
+ // Execute
+ int _retval = _struct->get_extensions(_struct, extension_idsList);
+
+ // Restore param:extension_ids; type: string_vec_byref
+ if (extension_idsList) {
+ extension_ids.clear();
+ transfer_string_list_contents(extension_idsList, extension_ids);
+ cef_string_list_free(extension_idsList);
+ }
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefExtension> CefRequestContextCToCpp::GetExtension(
+ const CefString& extension_id) {
+ cef_request_context_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_extension)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: extension_id; type: string_byref_const
+ DCHECK(!extension_id.empty());
+ if (extension_id.empty()) {
+ return nullptr;
+ }
+
+ // Execute
+ cef_extension_t* _retval =
+ _struct->get_extension(_struct, extension_id.GetStruct());
+
+ // Return type: refptr_same
+ return CefExtensionCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefMediaRouter> CefRequestContextCToCpp::GetMediaRouter(
+ CefRefPtr<CefCompletionCallback> callback) {
+ cef_request_context_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_media_router)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: callback
+
+ // Execute
+ cef_media_router_t* _retval = _struct->get_media_router(
+ _struct, CefCompletionCallbackCppToC::Wrap(callback));
+
+ // Return type: refptr_same
+ return CefMediaRouterCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefRequestContextCToCpp::HasPreference(const CefString& name) {
+ cef_preference_manager_t* _struct =
+ reinterpret_cast<cef_preference_manager_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, has_preference)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: name; type: string_byref_const
+ DCHECK(!name.empty());
+ if (name.empty()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->has_preference(_struct, name.GetStruct());
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefValue> CefRequestContextCToCpp::GetPreference(
+ const CefString& name) {
+ cef_preference_manager_t* _struct =
+ reinterpret_cast<cef_preference_manager_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_preference)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: name; type: string_byref_const
+ DCHECK(!name.empty());
+ if (name.empty()) {
+ return nullptr;
+ }
+
+ // Execute
+ cef_value_t* _retval = _struct->get_preference(_struct, name.GetStruct());
+
+ // Return type: refptr_same
+ return CefValueCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefDictionaryValue> CefRequestContextCToCpp::GetAllPreferences(
+ bool include_defaults) {
+ cef_preference_manager_t* _struct =
+ reinterpret_cast<cef_preference_manager_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_all_preferences)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_dictionary_value_t* _retval =
+ _struct->get_all_preferences(_struct, include_defaults);
+
+ // Return type: refptr_same
+ return CefDictionaryValueCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefRequestContextCToCpp::CanSetPreference(const CefString& name) {
+ cef_preference_manager_t* _struct =
+ reinterpret_cast<cef_preference_manager_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, can_set_preference)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: name; type: string_byref_const
+ DCHECK(!name.empty());
+ if (name.empty()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->can_set_preference(_struct, name.GetStruct());
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefRequestContextCToCpp::SetPreference(const CefString& name,
+ CefRefPtr<CefValue> value,
+ CefString& error) {
+ cef_preference_manager_t* _struct =
+ reinterpret_cast<cef_preference_manager_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_preference)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: name; type: string_byref_const
+ DCHECK(!name.empty());
+ if (name.empty()) {
+ return false;
+ }
+ // Unverified params: value
+
+ // Execute
+ int _retval = _struct->set_preference(_struct, name.GetStruct(),
+ CefValueCToCpp::Unwrap(value),
+ error.GetWritableStruct());
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefRequestContextCToCpp::CefRequestContextCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefRequestContextCToCpp::~CefRequestContextCToCpp() {}
+
+template <>
+cef_request_context_t* CefCToCppRefCounted<
+ CefRequestContextCToCpp,
+ CefRequestContext,
+ cef_request_context_t>::UnwrapDerived(CefWrapperType type,
+ CefRequestContext* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefRequestContextCToCpp,
+ CefRequestContext,
+ cef_request_context_t>::kWrapperType =
+ WT_REQUEST_CONTEXT;
diff --git a/libcef_dll/ctocpp/request_context_ctocpp.h b/libcef_dll/ctocpp/request_context_ctocpp.h
new file mode 100644
index 00000000..ac5422bd
--- /dev/null
+++ b/libcef_dll/ctocpp/request_context_ctocpp.h
@@ -0,0 +1,83 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=4a05f4583cacc076519f6505f8f8952c5e471a49$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_REQUEST_CONTEXT_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_REQUEST_CONTEXT_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include <vector>
+#include "include/capi/cef_request_context_capi.h"
+#include "include/capi/cef_request_context_handler_capi.h"
+#include "include/capi/cef_scheme_capi.h"
+#include "include/cef_request_context.h"
+#include "include/cef_request_context_handler.h"
+#include "include/cef_scheme.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefRequestContextCToCpp
+ : public CefCToCppRefCounted<CefRequestContextCToCpp,
+ CefRequestContext,
+ cef_request_context_t> {
+ public:
+ CefRequestContextCToCpp();
+ virtual ~CefRequestContextCToCpp();
+
+ // CefRequestContext methods.
+ bool IsSame(CefRefPtr<CefRequestContext> other) override;
+ bool IsSharingWith(CefRefPtr<CefRequestContext> other) override;
+ bool IsGlobal() override;
+ CefRefPtr<CefRequestContextHandler> GetHandler() override;
+ CefString GetCachePath() override;
+ CefRefPtr<CefCookieManager> GetCookieManager(
+ CefRefPtr<CefCompletionCallback> callback) override;
+ bool RegisterSchemeHandlerFactory(
+ const CefString& scheme_name,
+ const CefString& domain_name,
+ CefRefPtr<CefSchemeHandlerFactory> factory) override;
+ bool ClearSchemeHandlerFactories() override;
+ void ClearCertificateExceptions(
+ CefRefPtr<CefCompletionCallback> callback) override;
+ void ClearHttpAuthCredentials(
+ CefRefPtr<CefCompletionCallback> callback) override;
+ void CloseAllConnections(CefRefPtr<CefCompletionCallback> callback) override;
+ void ResolveHost(const CefString& origin,
+ CefRefPtr<CefResolveCallback> callback) override;
+ void LoadExtension(const CefString& root_directory,
+ CefRefPtr<CefDictionaryValue> manifest,
+ CefRefPtr<CefExtensionHandler> handler) override;
+ bool DidLoadExtension(const CefString& extension_id) override;
+ bool HasExtension(const CefString& extension_id) override;
+ bool GetExtensions(std::vector<CefString>& extension_ids) override;
+ CefRefPtr<CefExtension> GetExtension(const CefString& extension_id) override;
+ CefRefPtr<CefMediaRouter> GetMediaRouter(
+ CefRefPtr<CefCompletionCallback> callback) override;
+
+ // CefPreferenceManager methods.
+ bool HasPreference(const CefString& name) override;
+ CefRefPtr<CefValue> GetPreference(const CefString& name) override;
+ CefRefPtr<CefDictionaryValue> GetAllPreferences(
+ bool include_defaults) override;
+ bool CanSetPreference(const CefString& name) override;
+ bool SetPreference(const CefString& name,
+ CefRefPtr<CefValue> value,
+ CefString& error) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_REQUEST_CONTEXT_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/request_context_handler_ctocpp.cc b/libcef_dll/ctocpp/request_context_handler_ctocpp.cc
new file mode 100644
index 00000000..7c6d51ed
--- /dev/null
+++ b/libcef_dll/ctocpp/request_context_handler_ctocpp.cc
@@ -0,0 +1,109 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=9125fa607d69db95c303e9c73448e854c44d15cc$
+//
+
+#include "libcef_dll/ctocpp/request_context_handler_ctocpp.h"
+#include "libcef_dll/cpptoc/browser_cpptoc.h"
+#include "libcef_dll/cpptoc/frame_cpptoc.h"
+#include "libcef_dll/cpptoc/request_context_cpptoc.h"
+#include "libcef_dll/cpptoc/request_cpptoc.h"
+#include "libcef_dll/ctocpp/resource_request_handler_ctocpp.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+void CefRequestContextHandlerCToCpp::OnRequestContextInitialized(
+ CefRefPtr<CefRequestContext> request_context) {
+ cef_request_context_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_request_context_initialized)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: request_context; type: refptr_diff
+ DCHECK(request_context.get());
+ if (!request_context.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_request_context_initialized(
+ _struct, CefRequestContextCppToC::Wrap(request_context));
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefResourceRequestHandler>
+CefRequestContextHandlerCToCpp::GetResourceRequestHandler(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ bool is_navigation,
+ bool is_download,
+ const CefString& request_initiator,
+ bool& disable_default_handling) {
+ cef_request_context_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_resource_request_handler)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: request; type: refptr_diff
+ DCHECK(request.get());
+ if (!request.get()) {
+ return nullptr;
+ }
+ // Unverified params: browser, frame, request_initiator
+
+ // Translate param: disable_default_handling; type: bool_byref
+ int disable_default_handlingInt = disable_default_handling;
+
+ // Execute
+ cef_resource_request_handler_t* _retval =
+ _struct->get_resource_request_handler(
+ _struct, CefBrowserCppToC::Wrap(browser), CefFrameCppToC::Wrap(frame),
+ CefRequestCppToC::Wrap(request), is_navigation, is_download,
+ request_initiator.GetStruct(), &disable_default_handlingInt);
+
+ // Restore param:disable_default_handling; type: bool_byref
+ disable_default_handling = disable_default_handlingInt ? true : false;
+
+ // Return type: refptr_same
+ return CefResourceRequestHandlerCToCpp::Wrap(_retval);
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefRequestContextHandlerCToCpp::CefRequestContextHandlerCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefRequestContextHandlerCToCpp::~CefRequestContextHandlerCToCpp() {}
+
+template <>
+cef_request_context_handler_t* CefCToCppRefCounted<
+ CefRequestContextHandlerCToCpp,
+ CefRequestContextHandler,
+ cef_request_context_handler_t>::UnwrapDerived(CefWrapperType type,
+ CefRequestContextHandler* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCToCppRefCounted<CefRequestContextHandlerCToCpp,
+ CefRequestContextHandler,
+ cef_request_context_handler_t>::kWrapperType =
+ WT_REQUEST_CONTEXT_HANDLER;
diff --git a/libcef_dll/ctocpp/request_context_handler_ctocpp.h b/libcef_dll/ctocpp/request_context_handler_ctocpp.h
new file mode 100644
index 00000000..004f130a
--- /dev/null
+++ b/libcef_dll/ctocpp/request_context_handler_ctocpp.h
@@ -0,0 +1,50 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=8f4c9ab7910a1497890d9bb3bc7aef80e23b7306$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_REQUEST_CONTEXT_HANDLER_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_REQUEST_CONTEXT_HANDLER_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_request_context_handler_capi.h"
+#include "include/cef_request_context_handler.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefRequestContextHandlerCToCpp
+ : public CefCToCppRefCounted<CefRequestContextHandlerCToCpp,
+ CefRequestContextHandler,
+ cef_request_context_handler_t> {
+ public:
+ CefRequestContextHandlerCToCpp();
+ virtual ~CefRequestContextHandlerCToCpp();
+
+ // CefRequestContextHandler methods.
+ void OnRequestContextInitialized(
+ CefRefPtr<CefRequestContext> request_context) override;
+ CefRefPtr<CefResourceRequestHandler> GetResourceRequestHandler(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ bool is_navigation,
+ bool is_download,
+ const CefString& request_initiator,
+ bool& disable_default_handling) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_REQUEST_CONTEXT_HANDLER_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/request_ctocpp.cc b/libcef_dll/ctocpp/request_ctocpp.cc
new file mode 100644
index 00000000..33b3d93e
--- /dev/null
+++ b/libcef_dll/ctocpp/request_ctocpp.cc
@@ -0,0 +1,470 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=3454ad8f0a09ee48d7376f8e3eabcf967959de82$
+//
+
+#include "libcef_dll/ctocpp/request_ctocpp.h"
+#include "libcef_dll/ctocpp/post_data_ctocpp.h"
+#include "libcef_dll/transfer_util.h"
+
+// STATIC METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefRequest> CefRequest::Create() {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_request_t* _retval = cef_request_create();
+
+ // Return type: refptr_same
+ return CefRequestCToCpp::Wrap(_retval);
+}
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") bool CefRequestCToCpp::IsReadOnly() {
+ cef_request_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_read_only)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_read_only(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") CefString CefRequestCToCpp::GetURL() {
+ cef_request_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_url)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_url(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") void CefRequestCToCpp::SetURL(const CefString& url) {
+ cef_request_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_url)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: url; type: string_byref_const
+ DCHECK(!url.empty());
+ if (url.empty()) {
+ return;
+ }
+
+ // Execute
+ _struct->set_url(_struct, url.GetStruct());
+}
+
+NO_SANITIZE("cfi-icall") CefString CefRequestCToCpp::GetMethod() {
+ cef_request_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_method)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_method(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefRequestCToCpp::SetMethod(const CefString& method) {
+ cef_request_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_method)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: method; type: string_byref_const
+ DCHECK(!method.empty());
+ if (method.empty()) {
+ return;
+ }
+
+ // Execute
+ _struct->set_method(_struct, method.GetStruct());
+}
+
+NO_SANITIZE("cfi-icall")
+void CefRequestCToCpp::SetReferrer(const CefString& referrer_url,
+ ReferrerPolicy policy) {
+ cef_request_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_referrer)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: referrer_url
+
+ // Execute
+ _struct->set_referrer(_struct, referrer_url.GetStruct(), policy);
+}
+
+NO_SANITIZE("cfi-icall") CefString CefRequestCToCpp::GetReferrerURL() {
+ cef_request_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_referrer_url)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_referrer_url(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRequest::ReferrerPolicy CefRequestCToCpp::GetReferrerPolicy() {
+ cef_request_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_referrer_policy)) {
+ return REFERRER_POLICY_DEFAULT;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_referrer_policy_t _retval = _struct->get_referrer_policy(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefPostData> CefRequestCToCpp::GetPostData() {
+ cef_request_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_post_data)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_post_data_t* _retval = _struct->get_post_data(_struct);
+
+ // Return type: refptr_same
+ return CefPostDataCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefRequestCToCpp::SetPostData(CefRefPtr<CefPostData> postData) {
+ cef_request_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_post_data)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: postData; type: refptr_same
+ DCHECK(postData.get());
+ if (!postData.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->set_post_data(_struct, CefPostDataCToCpp::Unwrap(postData));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefRequestCToCpp::GetHeaderMap(HeaderMap& headerMap) {
+ cef_request_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_header_map)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Translate param: headerMap; type: string_map_multi_byref
+ cef_string_multimap_t headerMapMultimap = cef_string_multimap_alloc();
+ DCHECK(headerMapMultimap);
+ if (headerMapMultimap) {
+ transfer_string_multimap_contents(headerMap, headerMapMultimap);
+ }
+
+ // Execute
+ _struct->get_header_map(_struct, headerMapMultimap);
+
+ // Restore param:headerMap; type: string_map_multi_byref
+ if (headerMapMultimap) {
+ headerMap.clear();
+ transfer_string_multimap_contents(headerMapMultimap, headerMap);
+ cef_string_multimap_free(headerMapMultimap);
+ }
+}
+
+NO_SANITIZE("cfi-icall")
+void CefRequestCToCpp::SetHeaderMap(const HeaderMap& headerMap) {
+ cef_request_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_header_map)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Translate param: headerMap; type: string_map_multi_byref_const
+ cef_string_multimap_t headerMapMultimap = cef_string_multimap_alloc();
+ DCHECK(headerMapMultimap);
+ if (headerMapMultimap) {
+ transfer_string_multimap_contents(headerMap, headerMapMultimap);
+ }
+
+ // Execute
+ _struct->set_header_map(_struct, headerMapMultimap);
+
+ // Restore param:headerMap; type: string_map_multi_byref_const
+ if (headerMapMultimap) {
+ cef_string_multimap_free(headerMapMultimap);
+ }
+}
+
+NO_SANITIZE("cfi-icall")
+CefString CefRequestCToCpp::GetHeaderByName(const CefString& name) {
+ cef_request_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_header_by_name)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: name; type: string_byref_const
+ DCHECK(!name.empty());
+ if (name.empty()) {
+ return CefString();
+ }
+
+ // Execute
+ cef_string_userfree_t _retval =
+ _struct->get_header_by_name(_struct, name.GetStruct());
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefRequestCToCpp::SetHeaderByName(const CefString& name,
+ const CefString& value,
+ bool overwrite) {
+ cef_request_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_header_by_name)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: name; type: string_byref_const
+ DCHECK(!name.empty());
+ if (name.empty()) {
+ return;
+ }
+ // Unverified params: value
+
+ // Execute
+ _struct->set_header_by_name(_struct, name.GetStruct(), value.GetStruct(),
+ overwrite);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefRequestCToCpp::Set(const CefString& url,
+ const CefString& method,
+ CefRefPtr<CefPostData> postData,
+ const HeaderMap& headerMap) {
+ cef_request_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: url; type: string_byref_const
+ DCHECK(!url.empty());
+ if (url.empty()) {
+ return;
+ }
+ // Verify param: method; type: string_byref_const
+ DCHECK(!method.empty());
+ if (method.empty()) {
+ return;
+ }
+ // Unverified params: postData
+
+ // Translate param: headerMap; type: string_map_multi_byref_const
+ cef_string_multimap_t headerMapMultimap = cef_string_multimap_alloc();
+ DCHECK(headerMapMultimap);
+ if (headerMapMultimap) {
+ transfer_string_multimap_contents(headerMap, headerMapMultimap);
+ }
+
+ // Execute
+ _struct->set(_struct, url.GetStruct(), method.GetStruct(),
+ CefPostDataCToCpp::Unwrap(postData), headerMapMultimap);
+
+ // Restore param:headerMap; type: string_map_multi_byref_const
+ if (headerMapMultimap) {
+ cef_string_multimap_free(headerMapMultimap);
+ }
+}
+
+NO_SANITIZE("cfi-icall") int CefRequestCToCpp::GetFlags() {
+ cef_request_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_flags)) {
+ return UR_FLAG_NONE;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_flags(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") void CefRequestCToCpp::SetFlags(int flags) {
+ cef_request_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_flags)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_flags(_struct, flags);
+}
+
+NO_SANITIZE("cfi-icall") CefString CefRequestCToCpp::GetFirstPartyForCookies() {
+ cef_request_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_first_party_for_cookies)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_first_party_for_cookies(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefRequestCToCpp::SetFirstPartyForCookies(const CefString& url) {
+ cef_request_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_first_party_for_cookies)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: url
+
+ // Execute
+ _struct->set_first_party_for_cookies(_struct, url.GetStruct());
+}
+
+NO_SANITIZE("cfi-icall")
+CefRequest::ResourceType CefRequestCToCpp::GetResourceType() {
+ cef_request_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_resource_type)) {
+ return RT_SUB_RESOURCE;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_resource_type_t _retval = _struct->get_resource_type(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRequest::TransitionType CefRequestCToCpp::GetTransitionType() {
+ cef_request_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_transition_type)) {
+ return TT_EXPLICIT;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_transition_type_t _retval = _struct->get_transition_type(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") uint64 CefRequestCToCpp::GetIdentifier() {
+ cef_request_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_identifier)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ uint64 _retval = _struct->get_identifier(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefRequestCToCpp::CefRequestCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefRequestCToCpp::~CefRequestCToCpp() {}
+
+template <>
+cef_request_t*
+CefCToCppRefCounted<CefRequestCToCpp, CefRequest, cef_request_t>::UnwrapDerived(
+ CefWrapperType type,
+ CefRequest* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefRequestCToCpp,
+ CefRequest,
+ cef_request_t>::kWrapperType = WT_REQUEST;
diff --git a/libcef_dll/ctocpp/request_ctocpp.h b/libcef_dll/ctocpp/request_ctocpp.h
new file mode 100644
index 00000000..7b3b6654
--- /dev/null
+++ b/libcef_dll/ctocpp/request_ctocpp.h
@@ -0,0 +1,66 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=7e87acb36c494058615248f36c7536368d3d5fb5$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_REQUEST_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_REQUEST_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_request_capi.h"
+#include "include/cef_request.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefRequestCToCpp
+ : public CefCToCppRefCounted<CefRequestCToCpp, CefRequest, cef_request_t> {
+ public:
+ CefRequestCToCpp();
+ virtual ~CefRequestCToCpp();
+
+ // CefRequest methods.
+ bool IsReadOnly() override;
+ CefString GetURL() override;
+ void SetURL(const CefString& url) override;
+ CefString GetMethod() override;
+ void SetMethod(const CefString& method) override;
+ void SetReferrer(const CefString& referrer_url,
+ ReferrerPolicy policy) override;
+ CefString GetReferrerURL() override;
+ ReferrerPolicy GetReferrerPolicy() override;
+ CefRefPtr<CefPostData> GetPostData() override;
+ void SetPostData(CefRefPtr<CefPostData> postData) override;
+ void GetHeaderMap(HeaderMap& headerMap) override;
+ void SetHeaderMap(const HeaderMap& headerMap) override;
+ CefString GetHeaderByName(const CefString& name) override;
+ void SetHeaderByName(const CefString& name,
+ const CefString& value,
+ bool overwrite) override;
+ void Set(const CefString& url,
+ const CefString& method,
+ CefRefPtr<CefPostData> postData,
+ const HeaderMap& headerMap) override;
+ int GetFlags() override;
+ void SetFlags(int flags) override;
+ CefString GetFirstPartyForCookies() override;
+ void SetFirstPartyForCookies(const CefString& url) override;
+ ResourceType GetResourceType() override;
+ TransitionType GetTransitionType() override;
+ uint64 GetIdentifier() override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_REQUEST_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/request_handler_ctocpp.cc b/libcef_dll/ctocpp/request_handler_ctocpp.cc
new file mode 100644
index 00000000..358e1259
--- /dev/null
+++ b/libcef_dll/ctocpp/request_handler_ctocpp.cc
@@ -0,0 +1,414 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=75c5c934d39c9d12cd7731203c3ac941cdbc52a3$
+//
+
+#include "libcef_dll/ctocpp/request_handler_ctocpp.h"
+#include "libcef_dll/cpptoc/auth_callback_cpptoc.h"
+#include "libcef_dll/cpptoc/browser_cpptoc.h"
+#include "libcef_dll/cpptoc/callback_cpptoc.h"
+#include "libcef_dll/cpptoc/frame_cpptoc.h"
+#include "libcef_dll/cpptoc/request_cpptoc.h"
+#include "libcef_dll/cpptoc/select_client_certificate_callback_cpptoc.h"
+#include "libcef_dll/cpptoc/sslinfo_cpptoc.h"
+#include "libcef_dll/cpptoc/x509certificate_cpptoc.h"
+#include "libcef_dll/ctocpp/resource_request_handler_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+bool CefRequestHandlerCToCpp::OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ bool user_gesture,
+ bool is_redirect) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_request_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_before_browse)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return false;
+ }
+ // Verify param: frame; type: refptr_diff
+ DCHECK(frame.get());
+ if (!frame.get()) {
+ return false;
+ }
+ // Verify param: request; type: refptr_diff
+ DCHECK(request.get());
+ if (!request.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->on_before_browse(
+ _struct, CefBrowserCppToC::Wrap(browser), CefFrameCppToC::Wrap(frame),
+ CefRequestCppToC::Wrap(request), user_gesture, is_redirect);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefRequestHandlerCToCpp::OnOpenURLFromTab(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const CefString& target_url,
+ WindowOpenDisposition target_disposition,
+ bool user_gesture) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_request_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_open_urlfrom_tab)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return false;
+ }
+ // Verify param: frame; type: refptr_diff
+ DCHECK(frame.get());
+ if (!frame.get()) {
+ return false;
+ }
+ // Verify param: target_url; type: string_byref_const
+ DCHECK(!target_url.empty());
+ if (target_url.empty()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->on_open_urlfrom_tab(
+ _struct, CefBrowserCppToC::Wrap(browser), CefFrameCppToC::Wrap(frame),
+ target_url.GetStruct(), target_disposition, user_gesture);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefResourceRequestHandler>
+CefRequestHandlerCToCpp::GetResourceRequestHandler(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ bool is_navigation,
+ bool is_download,
+ const CefString& request_initiator,
+ bool& disable_default_handling) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_request_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_resource_request_handler)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return nullptr;
+ }
+ // Verify param: frame; type: refptr_diff
+ DCHECK(frame.get());
+ if (!frame.get()) {
+ return nullptr;
+ }
+ // Verify param: request; type: refptr_diff
+ DCHECK(request.get());
+ if (!request.get()) {
+ return nullptr;
+ }
+ // Unverified params: request_initiator
+
+ // Translate param: disable_default_handling; type: bool_byref
+ int disable_default_handlingInt = disable_default_handling;
+
+ // Execute
+ cef_resource_request_handler_t* _retval =
+ _struct->get_resource_request_handler(
+ _struct, CefBrowserCppToC::Wrap(browser), CefFrameCppToC::Wrap(frame),
+ CefRequestCppToC::Wrap(request), is_navigation, is_download,
+ request_initiator.GetStruct(), &disable_default_handlingInt);
+
+ // Restore param:disable_default_handling; type: bool_byref
+ disable_default_handling = disable_default_handlingInt ? true : false;
+
+ // Return type: refptr_same
+ return CefResourceRequestHandlerCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefRequestHandlerCToCpp::GetAuthCredentials(
+ CefRefPtr<CefBrowser> browser,
+ const CefString& origin_url,
+ bool isProxy,
+ const CefString& host,
+ int port,
+ const CefString& realm,
+ const CefString& scheme,
+ CefRefPtr<CefAuthCallback> callback) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_request_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_auth_credentials)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return false;
+ }
+ // Verify param: origin_url; type: string_byref_const
+ DCHECK(!origin_url.empty());
+ if (origin_url.empty()) {
+ return false;
+ }
+ // Verify param: host; type: string_byref_const
+ DCHECK(!host.empty());
+ if (host.empty()) {
+ return false;
+ }
+ // Verify param: callback; type: refptr_diff
+ DCHECK(callback.get());
+ if (!callback.get()) {
+ return false;
+ }
+ // Unverified params: realm, scheme
+
+ // Execute
+ int _retval = _struct->get_auth_credentials(
+ _struct, CefBrowserCppToC::Wrap(browser), origin_url.GetStruct(), isProxy,
+ host.GetStruct(), port, realm.GetStruct(), scheme.GetStruct(),
+ CefAuthCallbackCppToC::Wrap(callback));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefRequestHandlerCToCpp::OnCertificateError(
+ CefRefPtr<CefBrowser> browser,
+ cef_errorcode_t cert_error,
+ const CefString& request_url,
+ CefRefPtr<CefSSLInfo> ssl_info,
+ CefRefPtr<CefCallback> callback) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_request_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_certificate_error)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return false;
+ }
+ // Verify param: request_url; type: string_byref_const
+ DCHECK(!request_url.empty());
+ if (request_url.empty()) {
+ return false;
+ }
+ // Verify param: ssl_info; type: refptr_diff
+ DCHECK(ssl_info.get());
+ if (!ssl_info.get()) {
+ return false;
+ }
+ // Verify param: callback; type: refptr_diff
+ DCHECK(callback.get());
+ if (!callback.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->on_certificate_error(
+ _struct, CefBrowserCppToC::Wrap(browser), cert_error,
+ request_url.GetStruct(), CefSSLInfoCppToC::Wrap(ssl_info),
+ CefCallbackCppToC::Wrap(callback));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefRequestHandlerCToCpp::OnSelectClientCertificate(
+ CefRefPtr<CefBrowser> browser,
+ bool isProxy,
+ const CefString& host,
+ int port,
+ const X509CertificateList& certificates,
+ CefRefPtr<CefSelectClientCertificateCallback> callback) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_request_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_select_client_certificate)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return false;
+ }
+ // Verify param: host; type: string_byref_const
+ DCHECK(!host.empty());
+ if (host.empty()) {
+ return false;
+ }
+ // Verify param: callback; type: refptr_diff
+ DCHECK(callback.get());
+ if (!callback.get()) {
+ return false;
+ }
+
+ // Translate param: certificates; type: refptr_vec_diff_byref_const
+ const size_t certificatesCount = certificates.size();
+ cef_x509certificate_t** certificatesList = NULL;
+ if (certificatesCount > 0) {
+ certificatesList = new cef_x509certificate_t*[certificatesCount];
+ DCHECK(certificatesList);
+ if (certificatesList) {
+ for (size_t i = 0; i < certificatesCount; ++i) {
+ certificatesList[i] = CefX509CertificateCppToC::Wrap(certificates[i]);
+ }
+ }
+ }
+
+ // Execute
+ int _retval = _struct->on_select_client_certificate(
+ _struct, CefBrowserCppToC::Wrap(browser), isProxy, host.GetStruct(), port,
+ certificatesCount, certificatesList,
+ CefSelectClientCertificateCallbackCppToC::Wrap(callback));
+
+ // Restore param:certificates; type: refptr_vec_diff_byref_const
+ if (certificatesList) {
+ delete[] certificatesList;
+ }
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefRequestHandlerCToCpp::OnRenderViewReady(CefRefPtr<CefBrowser> browser) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_request_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_render_view_ready)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_render_view_ready(_struct, CefBrowserCppToC::Wrap(browser));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefRequestHandlerCToCpp::OnRenderProcessTerminated(
+ CefRefPtr<CefBrowser> browser,
+ TerminationStatus status) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_request_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_render_process_terminated)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_render_process_terminated(
+ _struct, CefBrowserCppToC::Wrap(browser), status);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefRequestHandlerCToCpp::OnDocumentAvailableInMainFrame(
+ CefRefPtr<CefBrowser> browser) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_request_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_document_available_in_main_frame)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_document_available_in_main_frame(_struct,
+ CefBrowserCppToC::Wrap(browser));
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefRequestHandlerCToCpp::CefRequestHandlerCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefRequestHandlerCToCpp::~CefRequestHandlerCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_request_handler_t* CefCToCppRefCounted<
+ CefRequestHandlerCToCpp,
+ CefRequestHandler,
+ cef_request_handler_t>::UnwrapDerived(CefWrapperType type,
+ CefRequestHandler* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefRequestHandlerCToCpp,
+ CefRequestHandler,
+ cef_request_handler_t>::kWrapperType =
+ WT_REQUEST_HANDLER;
diff --git a/libcef_dll/ctocpp/request_handler_ctocpp.h b/libcef_dll/ctocpp/request_handler_ctocpp.h
new file mode 100644
index 00000000..38ef594d
--- /dev/null
+++ b/libcef_dll/ctocpp/request_handler_ctocpp.h
@@ -0,0 +1,82 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=4f8f1876fa5ee304f9e4481212df662fa05da02d$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_REQUEST_HANDLER_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_REQUEST_HANDLER_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_request_handler_capi.h"
+#include "include/cef_request_handler.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefRequestHandlerCToCpp
+ : public CefCToCppRefCounted<CefRequestHandlerCToCpp,
+ CefRequestHandler,
+ cef_request_handler_t> {
+ public:
+ CefRequestHandlerCToCpp();
+ virtual ~CefRequestHandlerCToCpp();
+
+ // CefRequestHandler methods.
+ bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ bool user_gesture,
+ bool is_redirect) override;
+ bool OnOpenURLFromTab(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const CefString& target_url,
+ WindowOpenDisposition target_disposition,
+ bool user_gesture) override;
+ CefRefPtr<CefResourceRequestHandler> GetResourceRequestHandler(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ bool is_navigation,
+ bool is_download,
+ const CefString& request_initiator,
+ bool& disable_default_handling) override;
+ bool GetAuthCredentials(CefRefPtr<CefBrowser> browser,
+ const CefString& origin_url,
+ bool isProxy,
+ const CefString& host,
+ int port,
+ const CefString& realm,
+ const CefString& scheme,
+ CefRefPtr<CefAuthCallback> callback) override;
+ bool OnCertificateError(CefRefPtr<CefBrowser> browser,
+ cef_errorcode_t cert_error,
+ const CefString& request_url,
+ CefRefPtr<CefSSLInfo> ssl_info,
+ CefRefPtr<CefCallback> callback) override;
+ bool OnSelectClientCertificate(
+ CefRefPtr<CefBrowser> browser,
+ bool isProxy,
+ const CefString& host,
+ int port,
+ const X509CertificateList& certificates,
+ CefRefPtr<CefSelectClientCertificateCallback> callback) override;
+ void OnRenderViewReady(CefRefPtr<CefBrowser> browser) override;
+ void OnRenderProcessTerminated(CefRefPtr<CefBrowser> browser,
+ TerminationStatus status) override;
+ void OnDocumentAvailableInMainFrame(CefRefPtr<CefBrowser> browser) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_REQUEST_HANDLER_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/resolve_callback_ctocpp.cc b/libcef_dll/ctocpp/resolve_callback_ctocpp.cc
new file mode 100644
index 00000000..27e5df45
--- /dev/null
+++ b/libcef_dll/ctocpp/resolve_callback_ctocpp.cc
@@ -0,0 +1,76 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=93f0764aabe8525c1a3473c9e345b926403fa78b$
+//
+
+#include "libcef_dll/ctocpp/resolve_callback_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+#include "libcef_dll/transfer_util.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+void CefResolveCallbackCToCpp::OnResolveCompleted(
+ cef_errorcode_t result,
+ const std::vector<CefString>& resolved_ips) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_resolve_callback_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_resolve_completed)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: resolved_ips
+
+ // Translate param: resolved_ips; type: string_vec_byref_const
+ cef_string_list_t resolved_ipsList = cef_string_list_alloc();
+ DCHECK(resolved_ipsList);
+ if (resolved_ipsList) {
+ transfer_string_list_contents(resolved_ips, resolved_ipsList);
+ }
+
+ // Execute
+ _struct->on_resolve_completed(_struct, result, resolved_ipsList);
+
+ // Restore param:resolved_ips; type: string_vec_byref_const
+ if (resolved_ipsList) {
+ cef_string_list_free(resolved_ipsList);
+ }
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefResolveCallbackCToCpp::CefResolveCallbackCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefResolveCallbackCToCpp::~CefResolveCallbackCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_resolve_callback_t* CefCToCppRefCounted<
+ CefResolveCallbackCToCpp,
+ CefResolveCallback,
+ cef_resolve_callback_t>::UnwrapDerived(CefWrapperType type,
+ CefResolveCallback* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefResolveCallbackCToCpp,
+ CefResolveCallback,
+ cef_resolve_callback_t>::kWrapperType =
+ WT_RESOLVE_CALLBACK;
diff --git a/libcef_dll/ctocpp/resolve_callback_ctocpp.h b/libcef_dll/ctocpp/resolve_callback_ctocpp.h
new file mode 100644
index 00000000..f9e115e7
--- /dev/null
+++ b/libcef_dll/ctocpp/resolve_callback_ctocpp.h
@@ -0,0 +1,47 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=648f3d66272798ab00f7a97d33126aef193d5fa5$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_RESOLVE_CALLBACK_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_RESOLVE_CALLBACK_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include <vector>
+#include "include/capi/cef_request_context_capi.h"
+#include "include/capi/cef_request_context_handler_capi.h"
+#include "include/capi/cef_scheme_capi.h"
+#include "include/cef_request_context.h"
+#include "include/cef_request_context_handler.h"
+#include "include/cef_scheme.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefResolveCallbackCToCpp
+ : public CefCToCppRefCounted<CefResolveCallbackCToCpp,
+ CefResolveCallback,
+ cef_resolve_callback_t> {
+ public:
+ CefResolveCallbackCToCpp();
+ virtual ~CefResolveCallbackCToCpp();
+
+ // CefResolveCallback methods.
+ void OnResolveCompleted(cef_errorcode_t result,
+ const std::vector<CefString>& resolved_ips) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_RESOLVE_CALLBACK_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/resource_bundle_ctocpp.cc b/libcef_dll/ctocpp/resource_bundle_ctocpp.cc
new file mode 100644
index 00000000..54cdd416
--- /dev/null
+++ b/libcef_dll/ctocpp/resource_bundle_ctocpp.cc
@@ -0,0 +1,111 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=6c8e563997f192706a1cddfc1d785bffebdd8174$
+//
+
+#include "libcef_dll/ctocpp/resource_bundle_ctocpp.h"
+#include "libcef_dll/ctocpp/binary_value_ctocpp.h"
+
+// STATIC METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefResourceBundle> CefResourceBundle::GetGlobal() {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_resource_bundle_t* _retval = cef_resource_bundle_get_global();
+
+ // Return type: refptr_same
+ return CefResourceBundleCToCpp::Wrap(_retval);
+}
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefString CefResourceBundleCToCpp::GetLocalizedString(int string_id) {
+ cef_resource_bundle_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_localized_string)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval =
+ _struct->get_localized_string(_struct, string_id);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefBinaryValue> CefResourceBundleCToCpp::GetDataResource(
+ int resource_id) {
+ cef_resource_bundle_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_data_resource)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_binary_value_t* _retval =
+ _struct->get_data_resource(_struct, resource_id);
+
+ // Return type: refptr_same
+ return CefBinaryValueCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefBinaryValue> CefResourceBundleCToCpp::GetDataResourceForScale(
+ int resource_id,
+ ScaleFactor scale_factor) {
+ cef_resource_bundle_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_data_resource_for_scale)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_binary_value_t* _retval =
+ _struct->get_data_resource_for_scale(_struct, resource_id, scale_factor);
+
+ // Return type: refptr_same
+ return CefBinaryValueCToCpp::Wrap(_retval);
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefResourceBundleCToCpp::CefResourceBundleCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefResourceBundleCToCpp::~CefResourceBundleCToCpp() {}
+
+template <>
+cef_resource_bundle_t* CefCToCppRefCounted<
+ CefResourceBundleCToCpp,
+ CefResourceBundle,
+ cef_resource_bundle_t>::UnwrapDerived(CefWrapperType type,
+ CefResourceBundle* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefResourceBundleCToCpp,
+ CefResourceBundle,
+ cef_resource_bundle_t>::kWrapperType =
+ WT_RESOURCE_BUNDLE;
diff --git a/libcef_dll/ctocpp/resource_bundle_ctocpp.h b/libcef_dll/ctocpp/resource_bundle_ctocpp.h
new file mode 100644
index 00000000..9d0444e6
--- /dev/null
+++ b/libcef_dll/ctocpp/resource_bundle_ctocpp.h
@@ -0,0 +1,45 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=e18e48353500f27c27160812032cadc398fe00f9$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_RESOURCE_BUNDLE_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_RESOURCE_BUNDLE_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_resource_bundle_capi.h"
+#include "include/cef_resource_bundle.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefResourceBundleCToCpp
+ : public CefCToCppRefCounted<CefResourceBundleCToCpp,
+ CefResourceBundle,
+ cef_resource_bundle_t> {
+ public:
+ CefResourceBundleCToCpp();
+ virtual ~CefResourceBundleCToCpp();
+
+ // CefResourceBundle methods.
+ CefString GetLocalizedString(int string_id) override;
+ CefRefPtr<CefBinaryValue> GetDataResource(int resource_id) override;
+ CefRefPtr<CefBinaryValue> GetDataResourceForScale(
+ int resource_id,
+ ScaleFactor scale_factor) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_RESOURCE_BUNDLE_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/resource_bundle_handler_ctocpp.cc b/libcef_dll/ctocpp/resource_bundle_handler_ctocpp.cc
new file mode 100644
index 00000000..46f5c08b
--- /dev/null
+++ b/libcef_dll/ctocpp/resource_bundle_handler_ctocpp.cc
@@ -0,0 +1,109 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=4d903123dd75fca6eec9810c797a4b58b06a9b03$
+//
+
+#include "libcef_dll/ctocpp/resource_bundle_handler_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+bool CefResourceBundleHandlerCToCpp::GetLocalizedString(int string_id,
+ CefString& string) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_resource_bundle_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_localized_string)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_localized_string(_struct, string_id,
+ string.GetWritableStruct());
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefResourceBundleHandlerCToCpp::GetDataResource(int resource_id,
+ void*& data,
+ size_t& data_size) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_resource_bundle_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_data_resource)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval =
+ _struct->get_data_resource(_struct, resource_id, &data, &data_size);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefResourceBundleHandlerCToCpp::GetDataResourceForScale(
+ int resource_id,
+ ScaleFactor scale_factor,
+ void*& data,
+ size_t& data_size) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_resource_bundle_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_data_resource_for_scale)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_data_resource_for_scale(
+ _struct, resource_id, scale_factor, &data, &data_size);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefResourceBundleHandlerCToCpp::CefResourceBundleHandlerCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefResourceBundleHandlerCToCpp::~CefResourceBundleHandlerCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_resource_bundle_handler_t* CefCToCppRefCounted<
+ CefResourceBundleHandlerCToCpp,
+ CefResourceBundleHandler,
+ cef_resource_bundle_handler_t>::UnwrapDerived(CefWrapperType type,
+ CefResourceBundleHandler* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCToCppRefCounted<CefResourceBundleHandlerCToCpp,
+ CefResourceBundleHandler,
+ cef_resource_bundle_handler_t>::kWrapperType =
+ WT_RESOURCE_BUNDLE_HANDLER;
diff --git a/libcef_dll/ctocpp/resource_bundle_handler_ctocpp.h b/libcef_dll/ctocpp/resource_bundle_handler_ctocpp.h
new file mode 100644
index 00000000..0b427b1f
--- /dev/null
+++ b/libcef_dll/ctocpp/resource_bundle_handler_ctocpp.h
@@ -0,0 +1,48 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=52b1821c0ed82e859eddbb113d4a73ba2b178548$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_RESOURCE_BUNDLE_HANDLER_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_RESOURCE_BUNDLE_HANDLER_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_resource_bundle_handler_capi.h"
+#include "include/cef_resource_bundle_handler.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefResourceBundleHandlerCToCpp
+ : public CefCToCppRefCounted<CefResourceBundleHandlerCToCpp,
+ CefResourceBundleHandler,
+ cef_resource_bundle_handler_t> {
+ public:
+ CefResourceBundleHandlerCToCpp();
+ virtual ~CefResourceBundleHandlerCToCpp();
+
+ // CefResourceBundleHandler methods.
+ bool GetLocalizedString(int string_id, CefString& string) override;
+ bool GetDataResource(int resource_id,
+ void*& data,
+ size_t& data_size) override;
+ bool GetDataResourceForScale(int resource_id,
+ ScaleFactor scale_factor,
+ void*& data,
+ size_t& data_size) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_RESOURCE_BUNDLE_HANDLER_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/resource_handler_ctocpp.cc b/libcef_dll/ctocpp/resource_handler_ctocpp.cc
new file mode 100644
index 00000000..0a50df77
--- /dev/null
+++ b/libcef_dll/ctocpp/resource_handler_ctocpp.cc
@@ -0,0 +1,256 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=35588cfd8c8eb4000eb3de5edec70d361897c760$
+//
+
+#include "libcef_dll/ctocpp/resource_handler_ctocpp.h"
+#include "libcef_dll/cpptoc/callback_cpptoc.h"
+#include "libcef_dll/cpptoc/request_cpptoc.h"
+#include "libcef_dll/cpptoc/resource_read_callback_cpptoc.h"
+#include "libcef_dll/cpptoc/resource_skip_callback_cpptoc.h"
+#include "libcef_dll/cpptoc/response_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+bool CefResourceHandlerCToCpp::Open(CefRefPtr<CefRequest> request,
+ bool& handle_request,
+ CefRefPtr<CefCallback> callback) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_resource_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, open)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: request; type: refptr_diff
+ DCHECK(request.get());
+ if (!request.get()) {
+ return false;
+ }
+ // Verify param: callback; type: refptr_diff
+ DCHECK(callback.get());
+ if (!callback.get()) {
+ return false;
+ }
+
+ // Translate param: handle_request; type: bool_byref
+ int handle_requestInt = handle_request;
+
+ // Execute
+ int _retval =
+ _struct->open(_struct, CefRequestCppToC::Wrap(request),
+ &handle_requestInt, CefCallbackCppToC::Wrap(callback));
+
+ // Restore param:handle_request; type: bool_byref
+ handle_request = handle_requestInt ? true : false;
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefResourceHandlerCToCpp::ProcessRequest(CefRefPtr<CefRequest> request,
+ CefRefPtr<CefCallback> callback) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_resource_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, process_request)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: request; type: refptr_diff
+ DCHECK(request.get());
+ if (!request.get()) {
+ return false;
+ }
+ // Verify param: callback; type: refptr_diff
+ DCHECK(callback.get());
+ if (!callback.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval =
+ _struct->process_request(_struct, CefRequestCppToC::Wrap(request),
+ CefCallbackCppToC::Wrap(callback));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefResourceHandlerCToCpp::GetResponseHeaders(
+ CefRefPtr<CefResponse> response,
+ int64& response_length,
+ CefString& redirectUrl) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_resource_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_response_headers)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: response; type: refptr_diff
+ DCHECK(response.get());
+ if (!response.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->get_response_headers(_struct, CefResponseCppToC::Wrap(response),
+ &response_length,
+ redirectUrl.GetWritableStruct());
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefResourceHandlerCToCpp::Skip(
+ int64 bytes_to_skip,
+ int64& bytes_skipped,
+ CefRefPtr<CefResourceSkipCallback> callback) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_resource_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, skip)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: callback; type: refptr_diff
+ DCHECK(callback.get());
+ if (!callback.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->skip(_struct, bytes_to_skip, &bytes_skipped,
+ CefResourceSkipCallbackCppToC::Wrap(callback));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefResourceHandlerCToCpp::Read(
+ void* data_out,
+ int bytes_to_read,
+ int& bytes_read,
+ CefRefPtr<CefResourceReadCallback> callback) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_resource_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, read)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: data_out; type: simple_byaddr
+ DCHECK(data_out);
+ if (!data_out) {
+ return false;
+ }
+ // Verify param: callback; type: refptr_diff
+ DCHECK(callback.get());
+ if (!callback.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->read(_struct, data_out, bytes_to_read, &bytes_read,
+ CefResourceReadCallbackCppToC::Wrap(callback));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefResourceHandlerCToCpp::ReadResponse(void* data_out,
+ int bytes_to_read,
+ int& bytes_read,
+ CefRefPtr<CefCallback> callback) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_resource_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, read_response)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: data_out; type: simple_byaddr
+ DCHECK(data_out);
+ if (!data_out) {
+ return false;
+ }
+ // Verify param: callback; type: refptr_diff
+ DCHECK(callback.get());
+ if (!callback.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval =
+ _struct->read_response(_struct, data_out, bytes_to_read, &bytes_read,
+ CefCallbackCppToC::Wrap(callback));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") void CefResourceHandlerCToCpp::Cancel() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_resource_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, cancel)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->cancel(_struct);
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefResourceHandlerCToCpp::CefResourceHandlerCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefResourceHandlerCToCpp::~CefResourceHandlerCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_resource_handler_t* CefCToCppRefCounted<
+ CefResourceHandlerCToCpp,
+ CefResourceHandler,
+ cef_resource_handler_t>::UnwrapDerived(CefWrapperType type,
+ CefResourceHandler* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefResourceHandlerCToCpp,
+ CefResourceHandler,
+ cef_resource_handler_t>::kWrapperType =
+ WT_RESOURCE_HANDLER;
diff --git a/libcef_dll/ctocpp/resource_handler_ctocpp.h b/libcef_dll/ctocpp/resource_handler_ctocpp.h
new file mode 100644
index 00000000..da05687c
--- /dev/null
+++ b/libcef_dll/ctocpp/resource_handler_ctocpp.h
@@ -0,0 +1,60 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=8cf5fea5fc1d33f8268a4608417a75ef6ee9bf51$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_RESOURCE_HANDLER_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_RESOURCE_HANDLER_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_resource_handler_capi.h"
+#include "include/cef_resource_handler.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefResourceHandlerCToCpp
+ : public CefCToCppRefCounted<CefResourceHandlerCToCpp,
+ CefResourceHandler,
+ cef_resource_handler_t> {
+ public:
+ CefResourceHandlerCToCpp();
+ virtual ~CefResourceHandlerCToCpp();
+
+ // CefResourceHandler methods.
+ bool Open(CefRefPtr<CefRequest> request,
+ bool& handle_request,
+ CefRefPtr<CefCallback> callback) override;
+ bool ProcessRequest(CefRefPtr<CefRequest> request,
+ CefRefPtr<CefCallback> callback) override;
+ void GetResponseHeaders(CefRefPtr<CefResponse> response,
+ int64& response_length,
+ CefString& redirectUrl) override;
+ bool Skip(int64 bytes_to_skip,
+ int64& bytes_skipped,
+ CefRefPtr<CefResourceSkipCallback> callback) override;
+ bool Read(void* data_out,
+ int bytes_to_read,
+ int& bytes_read,
+ CefRefPtr<CefResourceReadCallback> callback) override;
+ bool ReadResponse(void* data_out,
+ int bytes_to_read,
+ int& bytes_read,
+ CefRefPtr<CefCallback> callback) override;
+ void Cancel() override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_RESOURCE_HANDLER_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/resource_read_callback_ctocpp.cc b/libcef_dll/ctocpp/resource_read_callback_ctocpp.cc
new file mode 100644
index 00000000..8257abd3
--- /dev/null
+++ b/libcef_dll/ctocpp/resource_read_callback_ctocpp.cc
@@ -0,0 +1,59 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=27162e0430742e5c8ccf73dc8fca20572132a530$
+//
+
+#include "libcef_dll/ctocpp/resource_read_callback_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+void CefResourceReadCallbackCToCpp::Continue(int bytes_read) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_resource_read_callback_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, cont)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->cont(_struct, bytes_read);
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefResourceReadCallbackCToCpp::CefResourceReadCallbackCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefResourceReadCallbackCToCpp::~CefResourceReadCallbackCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_resource_read_callback_t* CefCToCppRefCounted<
+ CefResourceReadCallbackCToCpp,
+ CefResourceReadCallback,
+ cef_resource_read_callback_t>::UnwrapDerived(CefWrapperType type,
+ CefResourceReadCallback* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefResourceReadCallbackCToCpp,
+ CefResourceReadCallback,
+ cef_resource_read_callback_t>::kWrapperType =
+ WT_RESOURCE_READ_CALLBACK;
diff --git a/libcef_dll/ctocpp/resource_read_callback_ctocpp.h b/libcef_dll/ctocpp/resource_read_callback_ctocpp.h
new file mode 100644
index 00000000..37b79c96
--- /dev/null
+++ b/libcef_dll/ctocpp/resource_read_callback_ctocpp.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=aeb2eaecc30bb2498b709af0ec45dd6b5dc9b392$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_RESOURCE_READ_CALLBACK_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_RESOURCE_READ_CALLBACK_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_resource_handler_capi.h"
+#include "include/cef_resource_handler.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefResourceReadCallbackCToCpp
+ : public CefCToCppRefCounted<CefResourceReadCallbackCToCpp,
+ CefResourceReadCallback,
+ cef_resource_read_callback_t> {
+ public:
+ CefResourceReadCallbackCToCpp();
+ virtual ~CefResourceReadCallbackCToCpp();
+
+ // CefResourceReadCallback methods.
+ void Continue(int bytes_read) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_RESOURCE_READ_CALLBACK_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/resource_request_handler_ctocpp.cc b/libcef_dll/ctocpp/resource_request_handler_ctocpp.cc
new file mode 100644
index 00000000..916671ec
--- /dev/null
+++ b/libcef_dll/ctocpp/resource_request_handler_ctocpp.cc
@@ -0,0 +1,312 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=9735af448f1beaad6ba7b71805aecc8b8f55d830$
+//
+
+#include "libcef_dll/ctocpp/resource_request_handler_ctocpp.h"
+#include "libcef_dll/cpptoc/browser_cpptoc.h"
+#include "libcef_dll/cpptoc/callback_cpptoc.h"
+#include "libcef_dll/cpptoc/frame_cpptoc.h"
+#include "libcef_dll/cpptoc/request_cpptoc.h"
+#include "libcef_dll/cpptoc/response_cpptoc.h"
+#include "libcef_dll/ctocpp/cookie_access_filter_ctocpp.h"
+#include "libcef_dll/ctocpp/resource_handler_ctocpp.h"
+#include "libcef_dll/ctocpp/response_filter_ctocpp.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefCookieAccessFilter>
+CefResourceRequestHandlerCToCpp::GetCookieAccessFilter(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request) {
+ cef_resource_request_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_cookie_access_filter)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: request; type: refptr_diff
+ DCHECK(request.get());
+ if (!request.get()) {
+ return nullptr;
+ }
+ // Unverified params: browser, frame
+
+ // Execute
+ cef_cookie_access_filter_t* _retval = _struct->get_cookie_access_filter(
+ _struct, CefBrowserCppToC::Wrap(browser), CefFrameCppToC::Wrap(frame),
+ CefRequestCppToC::Wrap(request));
+
+ // Return type: refptr_same
+ return CefCookieAccessFilterCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefResourceRequestHandler::ReturnValue
+CefResourceRequestHandlerCToCpp::OnBeforeResourceLoad(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefCallback> callback) {
+ cef_resource_request_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_before_resource_load)) {
+ return RV_CONTINUE;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: request; type: refptr_diff
+ DCHECK(request.get());
+ if (!request.get()) {
+ return RV_CONTINUE;
+ }
+ // Verify param: callback; type: refptr_diff
+ DCHECK(callback.get());
+ if (!callback.get()) {
+ return RV_CONTINUE;
+ }
+ // Unverified params: browser, frame
+
+ // Execute
+ cef_return_value_t _retval = _struct->on_before_resource_load(
+ _struct, CefBrowserCppToC::Wrap(browser), CefFrameCppToC::Wrap(frame),
+ CefRequestCppToC::Wrap(request), CefCallbackCppToC::Wrap(callback));
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefResourceHandler>
+CefResourceRequestHandlerCToCpp::GetResourceHandler(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request) {
+ cef_resource_request_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_resource_handler)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: request; type: refptr_diff
+ DCHECK(request.get());
+ if (!request.get()) {
+ return nullptr;
+ }
+ // Unverified params: browser, frame
+
+ // Execute
+ cef_resource_handler_t* _retval = _struct->get_resource_handler(
+ _struct, CefBrowserCppToC::Wrap(browser), CefFrameCppToC::Wrap(frame),
+ CefRequestCppToC::Wrap(request));
+
+ // Return type: refptr_same
+ return CefResourceHandlerCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefResourceRequestHandlerCToCpp::OnResourceRedirect(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response,
+ CefString& new_url) {
+ cef_resource_request_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_resource_redirect)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: request; type: refptr_diff
+ DCHECK(request.get());
+ if (!request.get()) {
+ return;
+ }
+ // Verify param: response; type: refptr_diff
+ DCHECK(response.get());
+ if (!response.get()) {
+ return;
+ }
+ // Unverified params: browser, frame
+
+ // Execute
+ _struct->on_resource_redirect(
+ _struct, CefBrowserCppToC::Wrap(browser), CefFrameCppToC::Wrap(frame),
+ CefRequestCppToC::Wrap(request), CefResponseCppToC::Wrap(response),
+ new_url.GetWritableStruct());
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefResourceRequestHandlerCToCpp::OnResourceResponse(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response) {
+ cef_resource_request_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_resource_response)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: request; type: refptr_diff
+ DCHECK(request.get());
+ if (!request.get()) {
+ return false;
+ }
+ // Verify param: response; type: refptr_diff
+ DCHECK(response.get());
+ if (!response.get()) {
+ return false;
+ }
+ // Unverified params: browser, frame
+
+ // Execute
+ int _retval = _struct->on_resource_response(
+ _struct, CefBrowserCppToC::Wrap(browser), CefFrameCppToC::Wrap(frame),
+ CefRequestCppToC::Wrap(request), CefResponseCppToC::Wrap(response));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefResponseFilter>
+CefResourceRequestHandlerCToCpp::GetResourceResponseFilter(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response) {
+ cef_resource_request_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_resource_response_filter)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: request; type: refptr_diff
+ DCHECK(request.get());
+ if (!request.get()) {
+ return nullptr;
+ }
+ // Verify param: response; type: refptr_diff
+ DCHECK(response.get());
+ if (!response.get()) {
+ return nullptr;
+ }
+ // Unverified params: browser, frame
+
+ // Execute
+ cef_response_filter_t* _retval = _struct->get_resource_response_filter(
+ _struct, CefBrowserCppToC::Wrap(browser), CefFrameCppToC::Wrap(frame),
+ CefRequestCppToC::Wrap(request), CefResponseCppToC::Wrap(response));
+
+ // Return type: refptr_same
+ return CefResponseFilterCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefResourceRequestHandlerCToCpp::OnResourceLoadComplete(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response,
+ URLRequestStatus status,
+ int64 received_content_length) {
+ cef_resource_request_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_resource_load_complete)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: request; type: refptr_diff
+ DCHECK(request.get());
+ if (!request.get()) {
+ return;
+ }
+ // Verify param: response; type: refptr_diff
+ DCHECK(response.get());
+ if (!response.get()) {
+ return;
+ }
+ // Unverified params: browser, frame
+
+ // Execute
+ _struct->on_resource_load_complete(
+ _struct, CefBrowserCppToC::Wrap(browser), CefFrameCppToC::Wrap(frame),
+ CefRequestCppToC::Wrap(request), CefResponseCppToC::Wrap(response),
+ status, received_content_length);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefResourceRequestHandlerCToCpp::OnProtocolExecution(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ bool& allow_os_execution) {
+ cef_resource_request_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_protocol_execution)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: request; type: refptr_diff
+ DCHECK(request.get());
+ if (!request.get()) {
+ return;
+ }
+ // Unverified params: browser, frame
+
+ // Translate param: allow_os_execution; type: bool_byref
+ int allow_os_executionInt = allow_os_execution;
+
+ // Execute
+ _struct->on_protocol_execution(
+ _struct, CefBrowserCppToC::Wrap(browser), CefFrameCppToC::Wrap(frame),
+ CefRequestCppToC::Wrap(request), &allow_os_executionInt);
+
+ // Restore param:allow_os_execution; type: bool_byref
+ allow_os_execution = allow_os_executionInt ? true : false;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefResourceRequestHandlerCToCpp::CefResourceRequestHandlerCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefResourceRequestHandlerCToCpp::~CefResourceRequestHandlerCToCpp() {}
+
+template <>
+cef_resource_request_handler_t* CefCToCppRefCounted<
+ CefResourceRequestHandlerCToCpp,
+ CefResourceRequestHandler,
+ cef_resource_request_handler_t>::UnwrapDerived(CefWrapperType type,
+ CefResourceRequestHandler*
+ c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCToCppRefCounted<CefResourceRequestHandlerCToCpp,
+ CefResourceRequestHandler,
+ cef_resource_request_handler_t>::kWrapperType =
+ WT_RESOURCE_REQUEST_HANDLER;
diff --git a/libcef_dll/ctocpp/resource_request_handler_ctocpp.h b/libcef_dll/ctocpp/resource_request_handler_ctocpp.h
new file mode 100644
index 00000000..4d2c5cd3
--- /dev/null
+++ b/libcef_dll/ctocpp/resource_request_handler_ctocpp.h
@@ -0,0 +1,76 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=4564ea5efd8c4be32e2df7c98fd70a645eb9f696$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_RESOURCE_REQUEST_HANDLER_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_RESOURCE_REQUEST_HANDLER_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_resource_request_handler_capi.h"
+#include "include/cef_resource_request_handler.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefResourceRequestHandlerCToCpp
+ : public CefCToCppRefCounted<CefResourceRequestHandlerCToCpp,
+ CefResourceRequestHandler,
+ cef_resource_request_handler_t> {
+ public:
+ CefResourceRequestHandlerCToCpp();
+ virtual ~CefResourceRequestHandlerCToCpp();
+
+ // CefResourceRequestHandler methods.
+ CefRefPtr<CefCookieAccessFilter> GetCookieAccessFilter(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request) override;
+ ReturnValue OnBeforeResourceLoad(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefCallback> callback) override;
+ CefRefPtr<CefResourceHandler> GetResourceHandler(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request) override;
+ void OnResourceRedirect(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response,
+ CefString& new_url) override;
+ bool OnResourceResponse(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response) override;
+ CefRefPtr<CefResponseFilter> GetResourceResponseFilter(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response) override;
+ void OnResourceLoadComplete(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response,
+ URLRequestStatus status,
+ int64 received_content_length) override;
+ void OnProtocolExecution(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ bool& allow_os_execution) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_RESOURCE_REQUEST_HANDLER_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/resource_skip_callback_ctocpp.cc b/libcef_dll/ctocpp/resource_skip_callback_ctocpp.cc
new file mode 100644
index 00000000..a89cb3e2
--- /dev/null
+++ b/libcef_dll/ctocpp/resource_skip_callback_ctocpp.cc
@@ -0,0 +1,59 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=b6351a3c3dc209334aa1371934d5eb846ed2f378$
+//
+
+#include "libcef_dll/ctocpp/resource_skip_callback_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+void CefResourceSkipCallbackCToCpp::Continue(int64 bytes_skipped) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_resource_skip_callback_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, cont)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->cont(_struct, bytes_skipped);
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefResourceSkipCallbackCToCpp::CefResourceSkipCallbackCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefResourceSkipCallbackCToCpp::~CefResourceSkipCallbackCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_resource_skip_callback_t* CefCToCppRefCounted<
+ CefResourceSkipCallbackCToCpp,
+ CefResourceSkipCallback,
+ cef_resource_skip_callback_t>::UnwrapDerived(CefWrapperType type,
+ CefResourceSkipCallback* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefResourceSkipCallbackCToCpp,
+ CefResourceSkipCallback,
+ cef_resource_skip_callback_t>::kWrapperType =
+ WT_RESOURCE_SKIP_CALLBACK;
diff --git a/libcef_dll/ctocpp/resource_skip_callback_ctocpp.h b/libcef_dll/ctocpp/resource_skip_callback_ctocpp.h
new file mode 100644
index 00000000..5d8a347b
--- /dev/null
+++ b/libcef_dll/ctocpp/resource_skip_callback_ctocpp.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=ace627f34f6c16512fb0d7a9a4ebb96e9c00c78d$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_RESOURCE_SKIP_CALLBACK_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_RESOURCE_SKIP_CALLBACK_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_resource_handler_capi.h"
+#include "include/cef_resource_handler.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefResourceSkipCallbackCToCpp
+ : public CefCToCppRefCounted<CefResourceSkipCallbackCToCpp,
+ CefResourceSkipCallback,
+ cef_resource_skip_callback_t> {
+ public:
+ CefResourceSkipCallbackCToCpp();
+ virtual ~CefResourceSkipCallbackCToCpp();
+
+ // CefResourceSkipCallback methods.
+ void Continue(int64 bytes_skipped) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_RESOURCE_SKIP_CALLBACK_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/response_ctocpp.cc b/libcef_dll/ctocpp/response_ctocpp.cc
new file mode 100644
index 00000000..06ffd968
--- /dev/null
+++ b/libcef_dll/ctocpp/response_ctocpp.cc
@@ -0,0 +1,348 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=7907e6e61d139645840b49fb291d761c085b77eb$
+//
+
+#include "libcef_dll/ctocpp/response_ctocpp.h"
+#include "libcef_dll/transfer_util.h"
+
+// STATIC METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefResponse> CefResponse::Create() {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_response_t* _retval = cef_response_create();
+
+ // Return type: refptr_same
+ return CefResponseCToCpp::Wrap(_retval);
+}
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") bool CefResponseCToCpp::IsReadOnly() {
+ cef_response_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_read_only)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_read_only(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") cef_errorcode_t CefResponseCToCpp::GetError() {
+ cef_response_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_error)) {
+ return ERR_NONE;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_errorcode_t _retval = _struct->get_error(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefResponseCToCpp::SetError(cef_errorcode_t error) {
+ cef_response_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_error)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_error(_struct, error);
+}
+
+NO_SANITIZE("cfi-icall") int CefResponseCToCpp::GetStatus() {
+ cef_response_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_status)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_status(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") void CefResponseCToCpp::SetStatus(int status) {
+ cef_response_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_status)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_status(_struct, status);
+}
+
+NO_SANITIZE("cfi-icall") CefString CefResponseCToCpp::GetStatusText() {
+ cef_response_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_status_text)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_status_text(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefResponseCToCpp::SetStatusText(const CefString& statusText) {
+ cef_response_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_status_text)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: statusText
+
+ // Execute
+ _struct->set_status_text(_struct, statusText.GetStruct());
+}
+
+NO_SANITIZE("cfi-icall") CefString CefResponseCToCpp::GetMimeType() {
+ cef_response_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_mime_type)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_mime_type(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefResponseCToCpp::SetMimeType(const CefString& mimeType) {
+ cef_response_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_mime_type)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: mimeType
+
+ // Execute
+ _struct->set_mime_type(_struct, mimeType.GetStruct());
+}
+
+NO_SANITIZE("cfi-icall") CefString CefResponseCToCpp::GetCharset() {
+ cef_response_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_charset)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_charset(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefResponseCToCpp::SetCharset(const CefString& charset) {
+ cef_response_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_charset)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: charset
+
+ // Execute
+ _struct->set_charset(_struct, charset.GetStruct());
+}
+
+NO_SANITIZE("cfi-icall")
+CefString CefResponseCToCpp::GetHeaderByName(const CefString& name) {
+ cef_response_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_header_by_name)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: name; type: string_byref_const
+ DCHECK(!name.empty());
+ if (name.empty()) {
+ return CefString();
+ }
+
+ // Execute
+ cef_string_userfree_t _retval =
+ _struct->get_header_by_name(_struct, name.GetStruct());
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefResponseCToCpp::SetHeaderByName(const CefString& name,
+ const CefString& value,
+ bool overwrite) {
+ cef_response_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_header_by_name)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: name; type: string_byref_const
+ DCHECK(!name.empty());
+ if (name.empty()) {
+ return;
+ }
+ // Unverified params: value
+
+ // Execute
+ _struct->set_header_by_name(_struct, name.GetStruct(), value.GetStruct(),
+ overwrite);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefResponseCToCpp::GetHeaderMap(HeaderMap& headerMap) {
+ cef_response_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_header_map)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Translate param: headerMap; type: string_map_multi_byref
+ cef_string_multimap_t headerMapMultimap = cef_string_multimap_alloc();
+ DCHECK(headerMapMultimap);
+ if (headerMapMultimap) {
+ transfer_string_multimap_contents(headerMap, headerMapMultimap);
+ }
+
+ // Execute
+ _struct->get_header_map(_struct, headerMapMultimap);
+
+ // Restore param:headerMap; type: string_map_multi_byref
+ if (headerMapMultimap) {
+ headerMap.clear();
+ transfer_string_multimap_contents(headerMapMultimap, headerMap);
+ cef_string_multimap_free(headerMapMultimap);
+ }
+}
+
+NO_SANITIZE("cfi-icall")
+void CefResponseCToCpp::SetHeaderMap(const HeaderMap& headerMap) {
+ cef_response_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_header_map)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Translate param: headerMap; type: string_map_multi_byref_const
+ cef_string_multimap_t headerMapMultimap = cef_string_multimap_alloc();
+ DCHECK(headerMapMultimap);
+ if (headerMapMultimap) {
+ transfer_string_multimap_contents(headerMap, headerMapMultimap);
+ }
+
+ // Execute
+ _struct->set_header_map(_struct, headerMapMultimap);
+
+ // Restore param:headerMap; type: string_map_multi_byref_const
+ if (headerMapMultimap) {
+ cef_string_multimap_free(headerMapMultimap);
+ }
+}
+
+NO_SANITIZE("cfi-icall") CefString CefResponseCToCpp::GetURL() {
+ cef_response_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_url)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_url(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") void CefResponseCToCpp::SetURL(const CefString& url) {
+ cef_response_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_url)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: url
+
+ // Execute
+ _struct->set_url(_struct, url.GetStruct());
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefResponseCToCpp::CefResponseCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefResponseCToCpp::~CefResponseCToCpp() {}
+
+template <>
+cef_response_t*
+CefCToCppRefCounted<CefResponseCToCpp, CefResponse, cef_response_t>::
+ UnwrapDerived(CefWrapperType type, CefResponse* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefResponseCToCpp,
+ CefResponse,
+ cef_response_t>::kWrapperType = WT_RESPONSE;
diff --git a/libcef_dll/ctocpp/response_ctocpp.h b/libcef_dll/ctocpp/response_ctocpp.h
new file mode 100644
index 00000000..00a12792
--- /dev/null
+++ b/libcef_dll/ctocpp/response_ctocpp.h
@@ -0,0 +1,58 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=3ec4c709bcd18d24997d554134b1b01e17bbd0fb$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_RESPONSE_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_RESPONSE_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_response_capi.h"
+#include "include/cef_response.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefResponseCToCpp : public CefCToCppRefCounted<CefResponseCToCpp,
+ CefResponse,
+ cef_response_t> {
+ public:
+ CefResponseCToCpp();
+ virtual ~CefResponseCToCpp();
+
+ // CefResponse methods.
+ bool IsReadOnly() override;
+ cef_errorcode_t GetError() override;
+ void SetError(cef_errorcode_t error) override;
+ int GetStatus() override;
+ void SetStatus(int status) override;
+ CefString GetStatusText() override;
+ void SetStatusText(const CefString& statusText) override;
+ CefString GetMimeType() override;
+ void SetMimeType(const CefString& mimeType) override;
+ CefString GetCharset() override;
+ void SetCharset(const CefString& charset) override;
+ CefString GetHeaderByName(const CefString& name) override;
+ void SetHeaderByName(const CefString& name,
+ const CefString& value,
+ bool overwrite) override;
+ void GetHeaderMap(HeaderMap& headerMap) override;
+ void SetHeaderMap(const HeaderMap& headerMap) override;
+ CefString GetURL() override;
+ void SetURL(const CefString& url) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_RESPONSE_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/response_filter_ctocpp.cc b/libcef_dll/ctocpp/response_filter_ctocpp.cc
new file mode 100644
index 00000000..ce4030e5
--- /dev/null
+++ b/libcef_dll/ctocpp/response_filter_ctocpp.cc
@@ -0,0 +1,94 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=024aa882f5db1793297f5634152de31edf552559$
+//
+
+#include "libcef_dll/ctocpp/response_filter_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") bool CefResponseFilterCToCpp::InitFilter() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_response_filter_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, init_filter)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->init_filter(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CefResponseFilter::FilterStatus CefResponseFilterCToCpp::Filter(
+ void* data_in,
+ size_t data_in_size,
+ size_t& data_in_read,
+ void* data_out,
+ size_t data_out_size,
+ size_t& data_out_written) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_response_filter_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, filter)) {
+ return RESPONSE_FILTER_ERROR;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: data_out; type: simple_byaddr
+ DCHECK(data_out);
+ if (!data_out) {
+ return RESPONSE_FILTER_ERROR;
+ }
+ // Unverified params: data_in
+
+ // Execute
+ cef_response_filter_status_t _retval =
+ _struct->filter(_struct, data_in, data_in_size, &data_in_read, data_out,
+ data_out_size, &data_out_written);
+
+ // Return type: simple
+ return _retval;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefResponseFilterCToCpp::CefResponseFilterCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefResponseFilterCToCpp::~CefResponseFilterCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_response_filter_t* CefCToCppRefCounted<
+ CefResponseFilterCToCpp,
+ CefResponseFilter,
+ cef_response_filter_t>::UnwrapDerived(CefWrapperType type,
+ CefResponseFilter* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefResponseFilterCToCpp,
+ CefResponseFilter,
+ cef_response_filter_t>::kWrapperType =
+ WT_RESPONSE_FILTER;
diff --git a/libcef_dll/ctocpp/response_filter_ctocpp.h b/libcef_dll/ctocpp/response_filter_ctocpp.h
new file mode 100644
index 00000000..a15d97ff
--- /dev/null
+++ b/libcef_dll/ctocpp/response_filter_ctocpp.h
@@ -0,0 +1,47 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=b9ca51a2ee848580b14c1a06b49b2b9e048ab798$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_RESPONSE_FILTER_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_RESPONSE_FILTER_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_response_filter_capi.h"
+#include "include/cef_response_filter.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefResponseFilterCToCpp
+ : public CefCToCppRefCounted<CefResponseFilterCToCpp,
+ CefResponseFilter,
+ cef_response_filter_t> {
+ public:
+ CefResponseFilterCToCpp();
+ virtual ~CefResponseFilterCToCpp();
+
+ // CefResponseFilter methods.
+ bool InitFilter() override;
+ FilterStatus Filter(void* data_in,
+ size_t data_in_size,
+ size_t& data_in_read,
+ void* data_out,
+ size_t data_out_size,
+ size_t& data_out_written) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_RESPONSE_FILTER_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/run_context_menu_callback_ctocpp.cc b/libcef_dll/ctocpp/run_context_menu_callback_ctocpp.cc
new file mode 100644
index 00000000..8d02dd57
--- /dev/null
+++ b/libcef_dll/ctocpp/run_context_menu_callback_ctocpp.cc
@@ -0,0 +1,76 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=23cebc9bbfaeb250f98ce8357a5a473ce964db3b$
+//
+
+#include "libcef_dll/ctocpp/run_context_menu_callback_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+void CefRunContextMenuCallbackCToCpp::Continue(int command_id,
+ cef_event_flags_t event_flags) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_run_context_menu_callback_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, cont)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->cont(_struct, command_id, event_flags);
+}
+
+NO_SANITIZE("cfi-icall") void CefRunContextMenuCallbackCToCpp::Cancel() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_run_context_menu_callback_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, cancel)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->cancel(_struct);
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefRunContextMenuCallbackCToCpp::CefRunContextMenuCallbackCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefRunContextMenuCallbackCToCpp::~CefRunContextMenuCallbackCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_run_context_menu_callback_t* CefCToCppRefCounted<
+ CefRunContextMenuCallbackCToCpp,
+ CefRunContextMenuCallback,
+ cef_run_context_menu_callback_t>::UnwrapDerived(CefWrapperType type,
+ CefRunContextMenuCallback*
+ c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCToCppRefCounted<CefRunContextMenuCallbackCToCpp,
+ CefRunContextMenuCallback,
+ cef_run_context_menu_callback_t>::kWrapperType =
+ WT_RUN_CONTEXT_MENU_CALLBACK;
diff --git a/libcef_dll/ctocpp/run_context_menu_callback_ctocpp.h b/libcef_dll/ctocpp/run_context_menu_callback_ctocpp.h
new file mode 100644
index 00000000..90d9cd66
--- /dev/null
+++ b/libcef_dll/ctocpp/run_context_menu_callback_ctocpp.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=7663b13ecb057bba0158685bc34783f37ef2f030$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_RUN_CONTEXT_MENU_CALLBACK_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_RUN_CONTEXT_MENU_CALLBACK_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_context_menu_handler_capi.h"
+#include "include/cef_context_menu_handler.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefRunContextMenuCallbackCToCpp
+ : public CefCToCppRefCounted<CefRunContextMenuCallbackCToCpp,
+ CefRunContextMenuCallback,
+ cef_run_context_menu_callback_t> {
+ public:
+ CefRunContextMenuCallbackCToCpp();
+ virtual ~CefRunContextMenuCallbackCToCpp();
+
+ // CefRunContextMenuCallback methods.
+ void Continue(int command_id, cef_event_flags_t event_flags) override;
+ void Cancel() override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_RUN_CONTEXT_MENU_CALLBACK_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/run_file_dialog_callback_ctocpp.cc b/libcef_dll/ctocpp/run_file_dialog_callback_ctocpp.cc
new file mode 100644
index 00000000..34ee4be5
--- /dev/null
+++ b/libcef_dll/ctocpp/run_file_dialog_callback_ctocpp.cc
@@ -0,0 +1,77 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=875b4e63f320e3ee1c1802fe28e8a842e4b89fdc$
+//
+
+#include "libcef_dll/ctocpp/run_file_dialog_callback_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+#include "libcef_dll/transfer_util.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+void CefRunFileDialogCallbackCToCpp::OnFileDialogDismissed(
+ const std::vector<CefString>& file_paths) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_run_file_dialog_callback_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_file_dialog_dismissed)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: file_paths
+
+ // Translate param: file_paths; type: string_vec_byref_const
+ cef_string_list_t file_pathsList = cef_string_list_alloc();
+ DCHECK(file_pathsList);
+ if (file_pathsList) {
+ transfer_string_list_contents(file_paths, file_pathsList);
+ }
+
+ // Execute
+ _struct->on_file_dialog_dismissed(_struct, file_pathsList);
+
+ // Restore param:file_paths; type: string_vec_byref_const
+ if (file_pathsList) {
+ cef_string_list_free(file_pathsList);
+ }
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefRunFileDialogCallbackCToCpp::CefRunFileDialogCallbackCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefRunFileDialogCallbackCToCpp::~CefRunFileDialogCallbackCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_run_file_dialog_callback_t* CefCToCppRefCounted<
+ CefRunFileDialogCallbackCToCpp,
+ CefRunFileDialogCallback,
+ cef_run_file_dialog_callback_t>::UnwrapDerived(CefWrapperType type,
+ CefRunFileDialogCallback*
+ c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCToCppRefCounted<CefRunFileDialogCallbackCToCpp,
+ CefRunFileDialogCallback,
+ cef_run_file_dialog_callback_t>::kWrapperType =
+ WT_RUN_FILE_DIALOG_CALLBACK;
diff --git a/libcef_dll/ctocpp/run_file_dialog_callback_ctocpp.h b/libcef_dll/ctocpp/run_file_dialog_callback_ctocpp.h
new file mode 100644
index 00000000..e109d0d5
--- /dev/null
+++ b/libcef_dll/ctocpp/run_file_dialog_callback_ctocpp.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=5793fe937c3f7fb75ee7d79ab6bd6e93411bd954$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_RUN_FILE_DIALOG_CALLBACK_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_RUN_FILE_DIALOG_CALLBACK_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include <vector>
+#include "include/capi/cef_browser_capi.h"
+#include "include/capi/cef_client_capi.h"
+#include "include/cef_browser.h"
+#include "include/cef_client.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefRunFileDialogCallbackCToCpp
+ : public CefCToCppRefCounted<CefRunFileDialogCallbackCToCpp,
+ CefRunFileDialogCallback,
+ cef_run_file_dialog_callback_t> {
+ public:
+ CefRunFileDialogCallbackCToCpp();
+ virtual ~CefRunFileDialogCallbackCToCpp();
+
+ // CefRunFileDialogCallback methods.
+ void OnFileDialogDismissed(const std::vector<CefString>& file_paths) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_RUN_FILE_DIALOG_CALLBACK_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/run_quick_menu_callback_ctocpp.cc b/libcef_dll/ctocpp/run_quick_menu_callback_ctocpp.cc
new file mode 100644
index 00000000..bf3caf8d
--- /dev/null
+++ b/libcef_dll/ctocpp/run_quick_menu_callback_ctocpp.cc
@@ -0,0 +1,75 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=f5141438ba9687494eb24e71c67d59b57eba60ef$
+//
+
+#include "libcef_dll/ctocpp/run_quick_menu_callback_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+void CefRunQuickMenuCallbackCToCpp::Continue(int command_id,
+ cef_event_flags_t event_flags) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_run_quick_menu_callback_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, cont)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->cont(_struct, command_id, event_flags);
+}
+
+NO_SANITIZE("cfi-icall") void CefRunQuickMenuCallbackCToCpp::Cancel() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_run_quick_menu_callback_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, cancel)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->cancel(_struct);
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefRunQuickMenuCallbackCToCpp::CefRunQuickMenuCallbackCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefRunQuickMenuCallbackCToCpp::~CefRunQuickMenuCallbackCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_run_quick_menu_callback_t* CefCToCppRefCounted<
+ CefRunQuickMenuCallbackCToCpp,
+ CefRunQuickMenuCallback,
+ cef_run_quick_menu_callback_t>::UnwrapDerived(CefWrapperType type,
+ CefRunQuickMenuCallback* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCToCppRefCounted<CefRunQuickMenuCallbackCToCpp,
+ CefRunQuickMenuCallback,
+ cef_run_quick_menu_callback_t>::kWrapperType =
+ WT_RUN_QUICK_MENU_CALLBACK;
diff --git a/libcef_dll/ctocpp/run_quick_menu_callback_ctocpp.h b/libcef_dll/ctocpp/run_quick_menu_callback_ctocpp.h
new file mode 100644
index 00000000..155b0b93
--- /dev/null
+++ b/libcef_dll/ctocpp/run_quick_menu_callback_ctocpp.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=c079137f43167df4c21e63f38cdd8c33f4423445$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_RUN_QUICK_MENU_CALLBACK_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_RUN_QUICK_MENU_CALLBACK_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_context_menu_handler_capi.h"
+#include "include/cef_context_menu_handler.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefRunQuickMenuCallbackCToCpp
+ : public CefCToCppRefCounted<CefRunQuickMenuCallbackCToCpp,
+ CefRunQuickMenuCallback,
+ cef_run_quick_menu_callback_t> {
+ public:
+ CefRunQuickMenuCallbackCToCpp();
+ virtual ~CefRunQuickMenuCallbackCToCpp();
+
+ // CefRunQuickMenuCallback methods.
+ void Continue(int command_id, cef_event_flags_t event_flags) override;
+ void Cancel() override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_RUN_QUICK_MENU_CALLBACK_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/scheme_handler_factory_ctocpp.cc b/libcef_dll/ctocpp/scheme_handler_factory_ctocpp.cc
new file mode 100644
index 00000000..f89c71bf
--- /dev/null
+++ b/libcef_dll/ctocpp/scheme_handler_factory_ctocpp.cc
@@ -0,0 +1,79 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=3a371669a10c2618d3b9f6386bb8e6d2f704398f$
+//
+
+#include "libcef_dll/ctocpp/scheme_handler_factory_ctocpp.h"
+#include "libcef_dll/cpptoc/browser_cpptoc.h"
+#include "libcef_dll/cpptoc/frame_cpptoc.h"
+#include "libcef_dll/cpptoc/request_cpptoc.h"
+#include "libcef_dll/ctocpp/resource_handler_ctocpp.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefResourceHandler> CefSchemeHandlerFactoryCToCpp::Create(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const CefString& scheme_name,
+ CefRefPtr<CefRequest> request) {
+ cef_scheme_handler_factory_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, create)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: scheme_name; type: string_byref_const
+ DCHECK(!scheme_name.empty());
+ if (scheme_name.empty()) {
+ return nullptr;
+ }
+ // Verify param: request; type: refptr_diff
+ DCHECK(request.get());
+ if (!request.get()) {
+ return nullptr;
+ }
+ // Unverified params: browser, frame
+
+ // Execute
+ cef_resource_handler_t* _retval = _struct->create(
+ _struct, CefBrowserCppToC::Wrap(browser), CefFrameCppToC::Wrap(frame),
+ scheme_name.GetStruct(), CefRequestCppToC::Wrap(request));
+
+ // Return type: refptr_same
+ return CefResourceHandlerCToCpp::Wrap(_retval);
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefSchemeHandlerFactoryCToCpp::CefSchemeHandlerFactoryCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefSchemeHandlerFactoryCToCpp::~CefSchemeHandlerFactoryCToCpp() {}
+
+template <>
+cef_scheme_handler_factory_t* CefCToCppRefCounted<
+ CefSchemeHandlerFactoryCToCpp,
+ CefSchemeHandlerFactory,
+ cef_scheme_handler_factory_t>::UnwrapDerived(CefWrapperType type,
+ CefSchemeHandlerFactory* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefSchemeHandlerFactoryCToCpp,
+ CefSchemeHandlerFactory,
+ cef_scheme_handler_factory_t>::kWrapperType =
+ WT_SCHEME_HANDLER_FACTORY;
diff --git a/libcef_dll/ctocpp/scheme_handler_factory_ctocpp.h b/libcef_dll/ctocpp/scheme_handler_factory_ctocpp.h
new file mode 100644
index 00000000..6e20d97d
--- /dev/null
+++ b/libcef_dll/ctocpp/scheme_handler_factory_ctocpp.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=8553de031f140b9c850e487863fc91b97633314b$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_SCHEME_HANDLER_FACTORY_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_SCHEME_HANDLER_FACTORY_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_scheme_capi.h"
+#include "include/cef_scheme.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefSchemeHandlerFactoryCToCpp
+ : public CefCToCppRefCounted<CefSchemeHandlerFactoryCToCpp,
+ CefSchemeHandlerFactory,
+ cef_scheme_handler_factory_t> {
+ public:
+ CefSchemeHandlerFactoryCToCpp();
+ virtual ~CefSchemeHandlerFactoryCToCpp();
+
+ // CefSchemeHandlerFactory methods.
+ CefRefPtr<CefResourceHandler> Create(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const CefString& scheme_name,
+ CefRefPtr<CefRequest> request) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_SCHEME_HANDLER_FACTORY_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/scheme_registrar_ctocpp.cc b/libcef_dll/ctocpp/scheme_registrar_ctocpp.cc
new file mode 100644
index 00000000..98ac0e91
--- /dev/null
+++ b/libcef_dll/ctocpp/scheme_registrar_ctocpp.cc
@@ -0,0 +1,75 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=1790a3bb7eb1f77332e52acce06b7b8de24d4f9c$
+//
+
+#include "libcef_dll/ctocpp/scheme_registrar_ctocpp.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+bool CefSchemeRegistrarCToCpp::AddCustomScheme(const CefString& scheme_name,
+ int options) {
+ cef_scheme_registrar_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, add_custom_scheme)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: scheme_name; type: string_byref_const
+ DCHECK(!scheme_name.empty());
+ if (scheme_name.empty()) {
+ return false;
+ }
+
+ // Execute
+ int _retval =
+ _struct->add_custom_scheme(_struct, scheme_name.GetStruct(), options);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefSchemeRegistrarCToCpp::CefSchemeRegistrarCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefSchemeRegistrarCToCpp::~CefSchemeRegistrarCToCpp() {}
+
+template <>
+cef_scheme_registrar_t* CefCToCppScoped<
+ CefSchemeRegistrarCToCpp,
+ CefSchemeRegistrar,
+ cef_scheme_registrar_t>::UnwrapDerivedOwn(CefWrapperType type,
+ CefOwnPtr<CefSchemeRegistrar> c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+cef_scheme_registrar_t* CefCToCppScoped<
+ CefSchemeRegistrarCToCpp,
+ CefSchemeRegistrar,
+ cef_scheme_registrar_t>::UnwrapDerivedRaw(CefWrapperType type,
+ CefRawPtr<CefSchemeRegistrar> c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppScoped<CefSchemeRegistrarCToCpp,
+ CefSchemeRegistrar,
+ cef_scheme_registrar_t>::kWrapperType =
+ WT_SCHEME_REGISTRAR;
diff --git a/libcef_dll/ctocpp/scheme_registrar_ctocpp.h b/libcef_dll/ctocpp/scheme_registrar_ctocpp.h
new file mode 100644
index 00000000..8ac7075b
--- /dev/null
+++ b/libcef_dll/ctocpp/scheme_registrar_ctocpp.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=a30e0b019ab6b34998563c8bf46f7b0c8089c3ba$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_SCHEME_REGISTRAR_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_SCHEME_REGISTRAR_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_scheme_capi.h"
+#include "include/cef_scheme.h"
+#include "libcef_dll/ctocpp/ctocpp_scoped.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefSchemeRegistrarCToCpp
+ : public CefCToCppScoped<CefSchemeRegistrarCToCpp,
+ CefSchemeRegistrar,
+ cef_scheme_registrar_t> {
+ public:
+ CefSchemeRegistrarCToCpp();
+ virtual ~CefSchemeRegistrarCToCpp();
+
+ // CefSchemeRegistrar methods.
+ bool AddCustomScheme(const CefString& scheme_name, int options) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_SCHEME_REGISTRAR_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/select_client_certificate_callback_ctocpp.cc b/libcef_dll/ctocpp/select_client_certificate_callback_ctocpp.cc
new file mode 100644
index 00000000..bdf0fc79
--- /dev/null
+++ b/libcef_dll/ctocpp/select_client_certificate_callback_ctocpp.cc
@@ -0,0 +1,66 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=6949f8943b86edf4d444adbb8e20b8cff183eadb$
+//
+
+#include "libcef_dll/ctocpp/select_client_certificate_callback_ctocpp.h"
+#include "libcef_dll/ctocpp/x509certificate_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+void CefSelectClientCertificateCallbackCToCpp::Select(
+ CefRefPtr<CefX509Certificate> cert) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_select_client_certificate_callback_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, select)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: cert
+
+ // Execute
+ _struct->select(_struct, CefX509CertificateCToCpp::Unwrap(cert));
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefSelectClientCertificateCallbackCToCpp::
+ CefSelectClientCertificateCallbackCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefSelectClientCertificateCallbackCToCpp::
+ ~CefSelectClientCertificateCallbackCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_select_client_certificate_callback_t*
+CefCToCppRefCounted<CefSelectClientCertificateCallbackCToCpp,
+ CefSelectClientCertificateCallback,
+ cef_select_client_certificate_callback_t>::
+ UnwrapDerived(CefWrapperType type, CefSelectClientCertificateCallback* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<
+ CefSelectClientCertificateCallbackCToCpp,
+ CefSelectClientCertificateCallback,
+ cef_select_client_certificate_callback_t>::kWrapperType =
+ WT_SELECT_CLIENT_CERTIFICATE_CALLBACK;
diff --git a/libcef_dll/ctocpp/select_client_certificate_callback_ctocpp.h b/libcef_dll/ctocpp/select_client_certificate_callback_ctocpp.h
new file mode 100644
index 00000000..4b621654
--- /dev/null
+++ b/libcef_dll/ctocpp/select_client_certificate_callback_ctocpp.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=49b4af5d293d5d88b27bea26aca6c410f86c6e59$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_SELECT_CLIENT_CERTIFICATE_CALLBACK_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_SELECT_CLIENT_CERTIFICATE_CALLBACK_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_request_handler_capi.h"
+#include "include/cef_request_handler.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefSelectClientCertificateCallbackCToCpp
+ : public CefCToCppRefCounted<CefSelectClientCertificateCallbackCToCpp,
+ CefSelectClientCertificateCallback,
+ cef_select_client_certificate_callback_t> {
+ public:
+ CefSelectClientCertificateCallbackCToCpp();
+ virtual ~CefSelectClientCertificateCallbackCToCpp();
+
+ // CefSelectClientCertificateCallback methods.
+ void Select(CefRefPtr<CefX509Certificate> cert) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_SELECT_CLIENT_CERTIFICATE_CALLBACK_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/server_ctocpp.cc b/libcef_dll/ctocpp/server_ctocpp.cc
new file mode 100644
index 00000000..75aaeb02
--- /dev/null
+++ b/libcef_dll/ctocpp/server_ctocpp.cc
@@ -0,0 +1,343 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=ac37df1c5a9a759393e0c7b33e60af3477ec8ce8$
+//
+
+#include "libcef_dll/ctocpp/server_ctocpp.h"
+#include "libcef_dll/cpptoc/server_handler_cpptoc.h"
+#include "libcef_dll/ctocpp/task_runner_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+#include "libcef_dll/transfer_util.h"
+
+// STATIC METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+void CefServer::CreateServer(const CefString& address,
+ uint16 port,
+ int backlog,
+ CefRefPtr<CefServerHandler> handler) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: address; type: string_byref_const
+ DCHECK(!address.empty());
+ if (address.empty()) {
+ return;
+ }
+ // Verify param: handler; type: refptr_diff
+ DCHECK(handler.get());
+ if (!handler.get()) {
+ return;
+ }
+
+ // Execute
+ cef_server_create(address.GetStruct(), port, backlog,
+ CefServerHandlerCppToC::Wrap(handler));
+}
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefTaskRunner> CefServerCToCpp::GetTaskRunner() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_server_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_task_runner)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_task_runner_t* _retval = _struct->get_task_runner(_struct);
+
+ // Return type: refptr_same
+ return CefTaskRunnerCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") void CefServerCToCpp::Shutdown() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_server_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, shutdown)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->shutdown(_struct);
+}
+
+NO_SANITIZE("cfi-icall") bool CefServerCToCpp::IsRunning() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_server_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_running)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_running(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") CefString CefServerCToCpp::GetAddress() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_server_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_address)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_address(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") bool CefServerCToCpp::HasConnection() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_server_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, has_connection)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->has_connection(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefServerCToCpp::IsValidConnection(int connection_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_server_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_valid_connection)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_valid_connection(_struct, connection_id);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefServerCToCpp::SendHttp200Response(int connection_id,
+ const CefString& content_type,
+ const void* data,
+ size_t data_size) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_server_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, send_http200response)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: content_type; type: string_byref_const
+ DCHECK(!content_type.empty());
+ if (content_type.empty()) {
+ return;
+ }
+ // Verify param: data; type: simple_byaddr
+ DCHECK(data);
+ if (!data) {
+ return;
+ }
+
+ // Execute
+ _struct->send_http200response(_struct, connection_id,
+ content_type.GetStruct(), data, data_size);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefServerCToCpp::SendHttp404Response(int connection_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_server_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, send_http404response)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->send_http404response(_struct, connection_id);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefServerCToCpp::SendHttp500Response(int connection_id,
+ const CefString& error_message) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_server_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, send_http500response)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: error_message; type: string_byref_const
+ DCHECK(!error_message.empty());
+ if (error_message.empty()) {
+ return;
+ }
+
+ // Execute
+ _struct->send_http500response(_struct, connection_id,
+ error_message.GetStruct());
+}
+
+NO_SANITIZE("cfi-icall")
+void CefServerCToCpp::SendHttpResponse(int connection_id,
+ int response_code,
+ const CefString& content_type,
+ int64 content_length,
+ const HeaderMap& extra_headers) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_server_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, send_http_response)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: content_type; type: string_byref_const
+ DCHECK(!content_type.empty());
+ if (content_type.empty()) {
+ return;
+ }
+ // Unverified params: extra_headers
+
+ // Translate param: extra_headers; type: string_map_multi_byref_const
+ cef_string_multimap_t extra_headersMultimap = cef_string_multimap_alloc();
+ DCHECK(extra_headersMultimap);
+ if (extra_headersMultimap) {
+ transfer_string_multimap_contents(extra_headers, extra_headersMultimap);
+ }
+
+ // Execute
+ _struct->send_http_response(_struct, connection_id, response_code,
+ content_type.GetStruct(), content_length,
+ extra_headersMultimap);
+
+ // Restore param:extra_headers; type: string_map_multi_byref_const
+ if (extra_headersMultimap) {
+ cef_string_multimap_free(extra_headersMultimap);
+ }
+}
+
+NO_SANITIZE("cfi-icall")
+void CefServerCToCpp::SendRawData(int connection_id,
+ const void* data,
+ size_t data_size) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_server_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, send_raw_data)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: data; type: simple_byaddr
+ DCHECK(data);
+ if (!data) {
+ return;
+ }
+
+ // Execute
+ _struct->send_raw_data(_struct, connection_id, data, data_size);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefServerCToCpp::CloseConnection(int connection_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_server_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, close_connection)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->close_connection(_struct, connection_id);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefServerCToCpp::SendWebSocketMessage(int connection_id,
+ const void* data,
+ size_t data_size) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_server_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, send_web_socket_message)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: data; type: simple_byaddr
+ DCHECK(data);
+ if (!data) {
+ return;
+ }
+
+ // Execute
+ _struct->send_web_socket_message(_struct, connection_id, data, data_size);
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefServerCToCpp::CefServerCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefServerCToCpp::~CefServerCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_server_t*
+CefCToCppRefCounted<CefServerCToCpp, CefServer, cef_server_t>::UnwrapDerived(
+ CefWrapperType type,
+ CefServer* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefServerCToCpp, CefServer, cef_server_t>::
+ kWrapperType = WT_SERVER;
diff --git a/libcef_dll/ctocpp/server_ctocpp.h b/libcef_dll/ctocpp/server_ctocpp.h
new file mode 100644
index 00000000..b9a038e2
--- /dev/null
+++ b/libcef_dll/ctocpp/server_ctocpp.h
@@ -0,0 +1,63 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=efb9652f9e2a17079ff20457264e8b0ecfd19499$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_SERVER_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_SERVER_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_server_capi.h"
+#include "include/cef_server.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefServerCToCpp
+ : public CefCToCppRefCounted<CefServerCToCpp, CefServer, cef_server_t> {
+ public:
+ CefServerCToCpp();
+ virtual ~CefServerCToCpp();
+
+ // CefServer methods.
+ CefRefPtr<CefTaskRunner> GetTaskRunner() override;
+ void Shutdown() override;
+ bool IsRunning() override;
+ CefString GetAddress() override;
+ bool HasConnection() override;
+ bool IsValidConnection(int connection_id) override;
+ void SendHttp200Response(int connection_id,
+ const CefString& content_type,
+ const void* data,
+ size_t data_size) override;
+ void SendHttp404Response(int connection_id) override;
+ void SendHttp500Response(int connection_id,
+ const CefString& error_message) override;
+ void SendHttpResponse(int connection_id,
+ int response_code,
+ const CefString& content_type,
+ int64 content_length,
+ const HeaderMap& extra_headers) override;
+ void SendRawData(int connection_id,
+ const void* data,
+ size_t data_size) override;
+ void CloseConnection(int connection_id) override;
+ void SendWebSocketMessage(int connection_id,
+ const void* data,
+ size_t data_size) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_SERVER_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/server_handler_ctocpp.cc b/libcef_dll/ctocpp/server_handler_ctocpp.cc
new file mode 100644
index 00000000..ad304aeb
--- /dev/null
+++ b/libcef_dll/ctocpp/server_handler_ctocpp.cc
@@ -0,0 +1,268 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=74bf4d64d8bff289328a21b486d9848e39307f19$
+//
+
+#include "libcef_dll/ctocpp/server_handler_ctocpp.h"
+#include "libcef_dll/cpptoc/callback_cpptoc.h"
+#include "libcef_dll/cpptoc/request_cpptoc.h"
+#include "libcef_dll/cpptoc/server_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+void CefServerHandlerCToCpp::OnServerCreated(CefRefPtr<CefServer> server) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_server_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_server_created)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: server; type: refptr_diff
+ DCHECK(server.get());
+ if (!server.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_server_created(_struct, CefServerCppToC::Wrap(server));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefServerHandlerCToCpp::OnServerDestroyed(CefRefPtr<CefServer> server) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_server_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_server_destroyed)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: server; type: refptr_diff
+ DCHECK(server.get());
+ if (!server.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_server_destroyed(_struct, CefServerCppToC::Wrap(server));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefServerHandlerCToCpp::OnClientConnected(CefRefPtr<CefServer> server,
+ int connection_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_server_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_client_connected)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: server; type: refptr_diff
+ DCHECK(server.get());
+ if (!server.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_client_connected(_struct, CefServerCppToC::Wrap(server),
+ connection_id);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefServerHandlerCToCpp::OnClientDisconnected(CefRefPtr<CefServer> server,
+ int connection_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_server_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_client_disconnected)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: server; type: refptr_diff
+ DCHECK(server.get());
+ if (!server.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_client_disconnected(_struct, CefServerCppToC::Wrap(server),
+ connection_id);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefServerHandlerCToCpp::OnHttpRequest(CefRefPtr<CefServer> server,
+ int connection_id,
+ const CefString& client_address,
+ CefRefPtr<CefRequest> request) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_server_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_http_request)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: server; type: refptr_diff
+ DCHECK(server.get());
+ if (!server.get()) {
+ return;
+ }
+ // Verify param: client_address; type: string_byref_const
+ DCHECK(!client_address.empty());
+ if (client_address.empty()) {
+ return;
+ }
+ // Verify param: request; type: refptr_diff
+ DCHECK(request.get());
+ if (!request.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_http_request(_struct, CefServerCppToC::Wrap(server),
+ connection_id, client_address.GetStruct(),
+ CefRequestCppToC::Wrap(request));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefServerHandlerCToCpp::OnWebSocketRequest(
+ CefRefPtr<CefServer> server,
+ int connection_id,
+ const CefString& client_address,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefCallback> callback) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_server_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_web_socket_request)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: server; type: refptr_diff
+ DCHECK(server.get());
+ if (!server.get()) {
+ return;
+ }
+ // Verify param: client_address; type: string_byref_const
+ DCHECK(!client_address.empty());
+ if (client_address.empty()) {
+ return;
+ }
+ // Verify param: request; type: refptr_diff
+ DCHECK(request.get());
+ if (!request.get()) {
+ return;
+ }
+ // Verify param: callback; type: refptr_diff
+ DCHECK(callback.get());
+ if (!callback.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_web_socket_request(_struct, CefServerCppToC::Wrap(server),
+ connection_id, client_address.GetStruct(),
+ CefRequestCppToC::Wrap(request),
+ CefCallbackCppToC::Wrap(callback));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefServerHandlerCToCpp::OnWebSocketConnected(CefRefPtr<CefServer> server,
+ int connection_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_server_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_web_socket_connected)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: server; type: refptr_diff
+ DCHECK(server.get());
+ if (!server.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_web_socket_connected(_struct, CefServerCppToC::Wrap(server),
+ connection_id);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefServerHandlerCToCpp::OnWebSocketMessage(CefRefPtr<CefServer> server,
+ int connection_id,
+ const void* data,
+ size_t data_size) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_server_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_web_socket_message)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: server; type: refptr_diff
+ DCHECK(server.get());
+ if (!server.get()) {
+ return;
+ }
+ // Verify param: data; type: simple_byaddr
+ DCHECK(data);
+ if (!data) {
+ return;
+ }
+
+ // Execute
+ _struct->on_web_socket_message(_struct, CefServerCppToC::Wrap(server),
+ connection_id, data, data_size);
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefServerHandlerCToCpp::CefServerHandlerCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefServerHandlerCToCpp::~CefServerHandlerCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_server_handler_t*
+CefCToCppRefCounted<CefServerHandlerCToCpp,
+ CefServerHandler,
+ cef_server_handler_t>::UnwrapDerived(CefWrapperType type,
+ CefServerHandler* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefServerHandlerCToCpp,
+ CefServerHandler,
+ cef_server_handler_t>::kWrapperType =
+ WT_SERVER_HANDLER;
diff --git a/libcef_dll/ctocpp/server_handler_ctocpp.h b/libcef_dll/ctocpp/server_handler_ctocpp.h
new file mode 100644
index 00000000..fbb9d761
--- /dev/null
+++ b/libcef_dll/ctocpp/server_handler_ctocpp.h
@@ -0,0 +1,61 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=0bed1f616f1ae42a7eb755dba59b329cd600abff$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_SERVER_HANDLER_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_SERVER_HANDLER_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_server_capi.h"
+#include "include/cef_server.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefServerHandlerCToCpp
+ : public CefCToCppRefCounted<CefServerHandlerCToCpp,
+ CefServerHandler,
+ cef_server_handler_t> {
+ public:
+ CefServerHandlerCToCpp();
+ virtual ~CefServerHandlerCToCpp();
+
+ // CefServerHandler methods.
+ void OnServerCreated(CefRefPtr<CefServer> server) override;
+ void OnServerDestroyed(CefRefPtr<CefServer> server) override;
+ void OnClientConnected(CefRefPtr<CefServer> server,
+ int connection_id) override;
+ void OnClientDisconnected(CefRefPtr<CefServer> server,
+ int connection_id) override;
+ void OnHttpRequest(CefRefPtr<CefServer> server,
+ int connection_id,
+ const CefString& client_address,
+ CefRefPtr<CefRequest> request) override;
+ void OnWebSocketRequest(CefRefPtr<CefServer> server,
+ int connection_id,
+ const CefString& client_address,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefCallback> callback) override;
+ void OnWebSocketConnected(CefRefPtr<CefServer> server,
+ int connection_id) override;
+ void OnWebSocketMessage(CefRefPtr<CefServer> server,
+ int connection_id,
+ const void* data,
+ size_t data_size) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_SERVER_HANDLER_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/set_cookie_callback_ctocpp.cc b/libcef_dll/ctocpp/set_cookie_callback_ctocpp.cc
new file mode 100644
index 00000000..a33873f2
--- /dev/null
+++ b/libcef_dll/ctocpp/set_cookie_callback_ctocpp.cc
@@ -0,0 +1,59 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=b6872491fd6b64121984c0b979ef252d09003194$
+//
+
+#include "libcef_dll/ctocpp/set_cookie_callback_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+void CefSetCookieCallbackCToCpp::OnComplete(bool success) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_set_cookie_callback_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_complete)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->on_complete(_struct, success);
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefSetCookieCallbackCToCpp::CefSetCookieCallbackCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefSetCookieCallbackCToCpp::~CefSetCookieCallbackCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_set_cookie_callback_t* CefCToCppRefCounted<
+ CefSetCookieCallbackCToCpp,
+ CefSetCookieCallback,
+ cef_set_cookie_callback_t>::UnwrapDerived(CefWrapperType type,
+ CefSetCookieCallback* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefSetCookieCallbackCToCpp,
+ CefSetCookieCallback,
+ cef_set_cookie_callback_t>::kWrapperType =
+ WT_SET_COOKIE_CALLBACK;
diff --git a/libcef_dll/ctocpp/set_cookie_callback_ctocpp.h b/libcef_dll/ctocpp/set_cookie_callback_ctocpp.h
new file mode 100644
index 00000000..06780716
--- /dev/null
+++ b/libcef_dll/ctocpp/set_cookie_callback_ctocpp.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=26be0ed7d7165630ee23b480419768f1fd9b95fe$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_SET_COOKIE_CALLBACK_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_SET_COOKIE_CALLBACK_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_cookie_capi.h"
+#include "include/cef_cookie.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefSetCookieCallbackCToCpp
+ : public CefCToCppRefCounted<CefSetCookieCallbackCToCpp,
+ CefSetCookieCallback,
+ cef_set_cookie_callback_t> {
+ public:
+ CefSetCookieCallbackCToCpp();
+ virtual ~CefSetCookieCallbackCToCpp();
+
+ // CefSetCookieCallback methods.
+ void OnComplete(bool success) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_SET_COOKIE_CALLBACK_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/shared_memory_region_ctocpp.cc b/libcef_dll/ctocpp/shared_memory_region_ctocpp.cc
new file mode 100644
index 00000000..cd335878
--- /dev/null
+++ b/libcef_dll/ctocpp/shared_memory_region_ctocpp.cc
@@ -0,0 +1,95 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=488fdead59657c8bdb17e6d3d6a970f6b65e970e$
+//
+
+#include "libcef_dll/ctocpp/shared_memory_region_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") bool CefSharedMemoryRegionCToCpp::IsValid() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_shared_memory_region_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_valid)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_valid(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") size_t CefSharedMemoryRegionCToCpp::Size() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_shared_memory_region_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, size)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ size_t _retval = _struct->size(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") const void* CefSharedMemoryRegionCToCpp::Memory() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_shared_memory_region_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, memory)) {
+ return NULL;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ const void* _retval = _struct->memory(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefSharedMemoryRegionCToCpp::CefSharedMemoryRegionCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefSharedMemoryRegionCToCpp::~CefSharedMemoryRegionCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_shared_memory_region_t* CefCToCppRefCounted<
+ CefSharedMemoryRegionCToCpp,
+ CefSharedMemoryRegion,
+ cef_shared_memory_region_t>::UnwrapDerived(CefWrapperType type,
+ CefSharedMemoryRegion* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefSharedMemoryRegionCToCpp,
+ CefSharedMemoryRegion,
+ cef_shared_memory_region_t>::kWrapperType =
+ WT_SHARED_MEMORY_REGION;
diff --git a/libcef_dll/ctocpp/shared_memory_region_ctocpp.h b/libcef_dll/ctocpp/shared_memory_region_ctocpp.h
new file mode 100644
index 00000000..45da99d9
--- /dev/null
+++ b/libcef_dll/ctocpp/shared_memory_region_ctocpp.h
@@ -0,0 +1,43 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=f5d0285d28412c40b8e04953025294c5f0779ecd$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_SHARED_MEMORY_REGION_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_SHARED_MEMORY_REGION_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_shared_memory_region_capi.h"
+#include "include/cef_shared_memory_region.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefSharedMemoryRegionCToCpp
+ : public CefCToCppRefCounted<CefSharedMemoryRegionCToCpp,
+ CefSharedMemoryRegion,
+ cef_shared_memory_region_t> {
+ public:
+ CefSharedMemoryRegionCToCpp();
+ virtual ~CefSharedMemoryRegionCToCpp();
+
+ // CefSharedMemoryRegion methods.
+ bool IsValid() override;
+ size_t Size() override;
+ const void* Memory() override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_SHARED_MEMORY_REGION_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/shared_process_message_builder_ctocpp.cc b/libcef_dll/ctocpp/shared_process_message_builder_ctocpp.cc
new file mode 100644
index 00000000..4cba99a8
--- /dev/null
+++ b/libcef_dll/ctocpp/shared_process_message_builder_ctocpp.cc
@@ -0,0 +1,137 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=78817cc08a00cfafed41724327295d5437d922e9$
+//
+
+#include "libcef_dll/ctocpp/shared_process_message_builder_ctocpp.h"
+#include "libcef_dll/ctocpp/process_message_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// STATIC METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefSharedProcessMessageBuilder>
+CefSharedProcessMessageBuilder::Create(const CefString& name,
+ size_t byte_size) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: name; type: string_byref_const
+ DCHECK(!name.empty());
+ if (name.empty()) {
+ return nullptr;
+ }
+
+ // Execute
+ cef_shared_process_message_builder_t* _retval =
+ cef_shared_process_message_builder_create(name.GetStruct(), byte_size);
+
+ // Return type: refptr_same
+ return CefSharedProcessMessageBuilderCToCpp::Wrap(_retval);
+}
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") bool CefSharedProcessMessageBuilderCToCpp::IsValid() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_shared_process_message_builder_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_valid)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_valid(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") size_t CefSharedProcessMessageBuilderCToCpp::Size() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_shared_process_message_builder_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, size)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ size_t _retval = _struct->size(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") void* CefSharedProcessMessageBuilderCToCpp::Memory() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_shared_process_message_builder_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, memory)) {
+ return NULL;
+ }
+
+ // Execute
+ void* _retval = _struct->memory(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefProcessMessage> CefSharedProcessMessageBuilderCToCpp::Build() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_shared_process_message_builder_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, build)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_process_message_t* _retval = _struct->build(_struct);
+
+ // Return type: refptr_same
+ return CefProcessMessageCToCpp::Wrap(_retval);
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefSharedProcessMessageBuilderCToCpp::CefSharedProcessMessageBuilderCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefSharedProcessMessageBuilderCToCpp::~CefSharedProcessMessageBuilderCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_shared_process_message_builder_t*
+CefCToCppRefCounted<CefSharedProcessMessageBuilderCToCpp,
+ CefSharedProcessMessageBuilder,
+ cef_shared_process_message_builder_t>::
+ UnwrapDerived(CefWrapperType type, CefSharedProcessMessageBuilder* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCToCppRefCounted<CefSharedProcessMessageBuilderCToCpp,
+ CefSharedProcessMessageBuilder,
+ cef_shared_process_message_builder_t>::kWrapperType =
+ WT_SHARED_PROCESS_MESSAGE_BUILDER;
diff --git a/libcef_dll/ctocpp/shared_process_message_builder_ctocpp.h b/libcef_dll/ctocpp/shared_process_message_builder_ctocpp.h
new file mode 100644
index 00000000..ea4f038b
--- /dev/null
+++ b/libcef_dll/ctocpp/shared_process_message_builder_ctocpp.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=de0791f744ddb7e9e9256bb120f233cb64826188$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_SHARED_PROCESS_MESSAGE_BUILDER_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_SHARED_PROCESS_MESSAGE_BUILDER_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_shared_process_message_builder_capi.h"
+#include "include/cef_shared_process_message_builder.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefSharedProcessMessageBuilderCToCpp
+ : public CefCToCppRefCounted<CefSharedProcessMessageBuilderCToCpp,
+ CefSharedProcessMessageBuilder,
+ cef_shared_process_message_builder_t> {
+ public:
+ CefSharedProcessMessageBuilderCToCpp();
+ virtual ~CefSharedProcessMessageBuilderCToCpp();
+
+ // CefSharedProcessMessageBuilder methods.
+ bool IsValid() override;
+ size_t Size() override;
+ void* Memory() override;
+ CefRefPtr<CefProcessMessage> Build() override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_SHARED_PROCESS_MESSAGE_BUILDER_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/sslinfo_ctocpp.cc b/libcef_dll/ctocpp/sslinfo_ctocpp.cc
new file mode 100644
index 00000000..fbe0c5cd
--- /dev/null
+++ b/libcef_dll/ctocpp/sslinfo_ctocpp.cc
@@ -0,0 +1,78 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=33a406dea5c7b19a173f32c3d77a14574b120df7$
+//
+
+#include "libcef_dll/ctocpp/sslinfo_ctocpp.h"
+#include "libcef_dll/ctocpp/x509certificate_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") cef_cert_status_t CefSSLInfoCToCpp::GetCertStatus() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_sslinfo_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_cert_status)) {
+ return CERT_STATUS_NONE;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_cert_status_t _retval = _struct->get_cert_status(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefX509Certificate> CefSSLInfoCToCpp::GetX509Certificate() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_sslinfo_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_x509certificate)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_x509certificate_t* _retval = _struct->get_x509certificate(_struct);
+
+ // Return type: refptr_same
+ return CefX509CertificateCToCpp::Wrap(_retval);
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefSSLInfoCToCpp::CefSSLInfoCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefSSLInfoCToCpp::~CefSSLInfoCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_sslinfo_t*
+CefCToCppRefCounted<CefSSLInfoCToCpp, CefSSLInfo, cef_sslinfo_t>::UnwrapDerived(
+ CefWrapperType type,
+ CefSSLInfo* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefSSLInfoCToCpp,
+ CefSSLInfo,
+ cef_sslinfo_t>::kWrapperType = WT_SSLINFO;
diff --git a/libcef_dll/ctocpp/sslinfo_ctocpp.h b/libcef_dll/ctocpp/sslinfo_ctocpp.h
new file mode 100644
index 00000000..80ed6f17
--- /dev/null
+++ b/libcef_dll/ctocpp/sslinfo_ctocpp.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=d08212eed1df4078ed5bb72dd7fc6d478f476ecb$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_SSLINFO_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_SSLINFO_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_ssl_info_capi.h"
+#include "include/cef_ssl_info.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefSSLInfoCToCpp
+ : public CefCToCppRefCounted<CefSSLInfoCToCpp, CefSSLInfo, cef_sslinfo_t> {
+ public:
+ CefSSLInfoCToCpp();
+ virtual ~CefSSLInfoCToCpp();
+
+ // CefSSLInfo methods.
+ cef_cert_status_t GetCertStatus() override;
+ CefRefPtr<CefX509Certificate> GetX509Certificate() override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_SSLINFO_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/sslstatus_ctocpp.cc b/libcef_dll/ctocpp/sslstatus_ctocpp.cc
new file mode 100644
index 00000000..0b847974
--- /dev/null
+++ b/libcef_dll/ctocpp/sslstatus_ctocpp.cc
@@ -0,0 +1,130 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=367c7e71f4d0e57f08b1c2fc63d54dcb475ee59e$
+//
+
+#include "libcef_dll/ctocpp/sslstatus_ctocpp.h"
+#include "libcef_dll/ctocpp/x509certificate_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") bool CefSSLStatusCToCpp::IsSecureConnection() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_sslstatus_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_secure_connection)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_secure_connection(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") cef_cert_status_t CefSSLStatusCToCpp::GetCertStatus() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_sslstatus_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_cert_status)) {
+ return CERT_STATUS_NONE;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_cert_status_t _retval = _struct->get_cert_status(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") cef_ssl_version_t CefSSLStatusCToCpp::GetSSLVersion() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_sslstatus_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_sslversion)) {
+ return SSL_CONNECTION_VERSION_UNKNOWN;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_ssl_version_t _retval = _struct->get_sslversion(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+cef_ssl_content_status_t CefSSLStatusCToCpp::GetContentStatus() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_sslstatus_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_content_status)) {
+ return SSL_CONTENT_NORMAL_CONTENT;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_ssl_content_status_t _retval = _struct->get_content_status(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefX509Certificate> CefSSLStatusCToCpp::GetX509Certificate() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_sslstatus_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_x509certificate)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_x509certificate_t* _retval = _struct->get_x509certificate(_struct);
+
+ // Return type: refptr_same
+ return CefX509CertificateCToCpp::Wrap(_retval);
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefSSLStatusCToCpp::CefSSLStatusCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefSSLStatusCToCpp::~CefSSLStatusCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_sslstatus_t*
+CefCToCppRefCounted<CefSSLStatusCToCpp, CefSSLStatus, cef_sslstatus_t>::
+ UnwrapDerived(CefWrapperType type, CefSSLStatus* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefSSLStatusCToCpp,
+ CefSSLStatus,
+ cef_sslstatus_t>::kWrapperType =
+ WT_SSLSTATUS;
diff --git a/libcef_dll/ctocpp/sslstatus_ctocpp.h b/libcef_dll/ctocpp/sslstatus_ctocpp.h
new file mode 100644
index 00000000..c36c5254
--- /dev/null
+++ b/libcef_dll/ctocpp/sslstatus_ctocpp.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=af612f99d0ccc287b152a20b3e9956af223f82e0$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_SSLSTATUS_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_SSLSTATUS_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_ssl_status_capi.h"
+#include "include/cef_ssl_status.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefSSLStatusCToCpp : public CefCToCppRefCounted<CefSSLStatusCToCpp,
+ CefSSLStatus,
+ cef_sslstatus_t> {
+ public:
+ CefSSLStatusCToCpp();
+ virtual ~CefSSLStatusCToCpp();
+
+ // CefSSLStatus methods.
+ bool IsSecureConnection() override;
+ cef_cert_status_t GetCertStatus() override;
+ cef_ssl_version_t GetSSLVersion() override;
+ cef_ssl_content_status_t GetContentStatus() override;
+ CefRefPtr<CefX509Certificate> GetX509Certificate() override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_SSLSTATUS_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/stream_reader_ctocpp.cc b/libcef_dll/ctocpp/stream_reader_ctocpp.cc
new file mode 100644
index 00000000..867479f3
--- /dev/null
+++ b/libcef_dll/ctocpp/stream_reader_ctocpp.cc
@@ -0,0 +1,202 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=dff1919433cb60a9fff1f115f26cbda5fefe3eed$
+//
+
+#include "libcef_dll/ctocpp/stream_reader_ctocpp.h"
+#include "libcef_dll/cpptoc/read_handler_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// STATIC METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefStreamReader> CefStreamReader::CreateForFile(
+ const CefString& fileName) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: fileName; type: string_byref_const
+ DCHECK(!fileName.empty());
+ if (fileName.empty()) {
+ return nullptr;
+ }
+
+ // Execute
+ cef_stream_reader_t* _retval =
+ cef_stream_reader_create_for_file(fileName.GetStruct());
+
+ // Return type: refptr_same
+ return CefStreamReaderCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefStreamReader> CefStreamReader::CreateForData(void* data,
+ size_t size) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: data; type: simple_byaddr
+ DCHECK(data);
+ if (!data) {
+ return nullptr;
+ }
+
+ // Execute
+ cef_stream_reader_t* _retval = cef_stream_reader_create_for_data(data, size);
+
+ // Return type: refptr_same
+ return CefStreamReaderCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefStreamReader> CefStreamReader::CreateForHandler(
+ CefRefPtr<CefReadHandler> handler) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: handler; type: refptr_diff
+ DCHECK(handler.get());
+ if (!handler.get()) {
+ return nullptr;
+ }
+
+ // Execute
+ cef_stream_reader_t* _retval =
+ cef_stream_reader_create_for_handler(CefReadHandlerCppToC::Wrap(handler));
+
+ // Return type: refptr_same
+ return CefStreamReaderCToCpp::Wrap(_retval);
+}
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+size_t CefStreamReaderCToCpp::Read(void* ptr, size_t size, size_t n) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_stream_reader_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, read)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: ptr; type: simple_byaddr
+ DCHECK(ptr);
+ if (!ptr) {
+ return 0;
+ }
+
+ // Execute
+ size_t _retval = _struct->read(_struct, ptr, size, n);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+int CefStreamReaderCToCpp::Seek(int64 offset, int whence) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_stream_reader_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, seek)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->seek(_struct, offset, whence);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") int64 CefStreamReaderCToCpp::Tell() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_stream_reader_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, tell)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int64 _retval = _struct->tell(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") int CefStreamReaderCToCpp::Eof() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_stream_reader_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, eof)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->eof(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") bool CefStreamReaderCToCpp::MayBlock() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_stream_reader_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, may_block)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->may_block(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefStreamReaderCToCpp::CefStreamReaderCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefStreamReaderCToCpp::~CefStreamReaderCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_stream_reader_t*
+CefCToCppRefCounted<CefStreamReaderCToCpp,
+ CefStreamReader,
+ cef_stream_reader_t>::UnwrapDerived(CefWrapperType type,
+ CefStreamReader* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefStreamReaderCToCpp,
+ CefStreamReader,
+ cef_stream_reader_t>::kWrapperType =
+ WT_STREAM_READER;
diff --git a/libcef_dll/ctocpp/stream_reader_ctocpp.h b/libcef_dll/ctocpp/stream_reader_ctocpp.h
new file mode 100644
index 00000000..1376f714
--- /dev/null
+++ b/libcef_dll/ctocpp/stream_reader_ctocpp.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=8a1cd61b67d54a528ac936415fa11ff1936cd628$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_STREAM_READER_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_STREAM_READER_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_stream_capi.h"
+#include "include/cef_stream.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefStreamReaderCToCpp : public CefCToCppRefCounted<CefStreamReaderCToCpp,
+ CefStreamReader,
+ cef_stream_reader_t> {
+ public:
+ CefStreamReaderCToCpp();
+ virtual ~CefStreamReaderCToCpp();
+
+ // CefStreamReader methods.
+ size_t Read(void* ptr, size_t size, size_t n) override;
+ int Seek(int64 offset, int whence) override;
+ int64 Tell() override;
+ int Eof() override;
+ bool MayBlock() override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_STREAM_READER_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/stream_writer_ctocpp.cc b/libcef_dll/ctocpp/stream_writer_ctocpp.cc
new file mode 100644
index 00000000..6fd312ea
--- /dev/null
+++ b/libcef_dll/ctocpp/stream_writer_ctocpp.cc
@@ -0,0 +1,182 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=8db930f01e1f9ea8f170d55c5a9a6b0961f2a40e$
+//
+
+#include "libcef_dll/ctocpp/stream_writer_ctocpp.h"
+#include "libcef_dll/cpptoc/write_handler_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// STATIC METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefStreamWriter> CefStreamWriter::CreateForFile(
+ const CefString& fileName) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: fileName; type: string_byref_const
+ DCHECK(!fileName.empty());
+ if (fileName.empty()) {
+ return nullptr;
+ }
+
+ // Execute
+ cef_stream_writer_t* _retval =
+ cef_stream_writer_create_for_file(fileName.GetStruct());
+
+ // Return type: refptr_same
+ return CefStreamWriterCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefStreamWriter> CefStreamWriter::CreateForHandler(
+ CefRefPtr<CefWriteHandler> handler) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: handler; type: refptr_diff
+ DCHECK(handler.get());
+ if (!handler.get()) {
+ return nullptr;
+ }
+
+ // Execute
+ cef_stream_writer_t* _retval = cef_stream_writer_create_for_handler(
+ CefWriteHandlerCppToC::Wrap(handler));
+
+ // Return type: refptr_same
+ return CefStreamWriterCToCpp::Wrap(_retval);
+}
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+size_t CefStreamWriterCToCpp::Write(const void* ptr, size_t size, size_t n) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_stream_writer_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, write)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: ptr; type: simple_byaddr
+ DCHECK(ptr);
+ if (!ptr) {
+ return 0;
+ }
+
+ // Execute
+ size_t _retval = _struct->write(_struct, ptr, size, n);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+int CefStreamWriterCToCpp::Seek(int64 offset, int whence) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_stream_writer_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, seek)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->seek(_struct, offset, whence);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") int64 CefStreamWriterCToCpp::Tell() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_stream_writer_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, tell)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int64 _retval = _struct->tell(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") int CefStreamWriterCToCpp::Flush() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_stream_writer_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, flush)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->flush(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") bool CefStreamWriterCToCpp::MayBlock() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_stream_writer_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, may_block)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->may_block(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefStreamWriterCToCpp::CefStreamWriterCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefStreamWriterCToCpp::~CefStreamWriterCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_stream_writer_t*
+CefCToCppRefCounted<CefStreamWriterCToCpp,
+ CefStreamWriter,
+ cef_stream_writer_t>::UnwrapDerived(CefWrapperType type,
+ CefStreamWriter* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefStreamWriterCToCpp,
+ CefStreamWriter,
+ cef_stream_writer_t>::kWrapperType =
+ WT_STREAM_WRITER;
diff --git a/libcef_dll/ctocpp/stream_writer_ctocpp.h b/libcef_dll/ctocpp/stream_writer_ctocpp.h
new file mode 100644
index 00000000..eceb31ac
--- /dev/null
+++ b/libcef_dll/ctocpp/stream_writer_ctocpp.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=f1156f9657858024d8d0dc20af0b5f53e82b5d74$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_STREAM_WRITER_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_STREAM_WRITER_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_stream_capi.h"
+#include "include/cef_stream.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefStreamWriterCToCpp : public CefCToCppRefCounted<CefStreamWriterCToCpp,
+ CefStreamWriter,
+ cef_stream_writer_t> {
+ public:
+ CefStreamWriterCToCpp();
+ virtual ~CefStreamWriterCToCpp();
+
+ // CefStreamWriter methods.
+ size_t Write(const void* ptr, size_t size, size_t n) override;
+ int Seek(int64 offset, int whence) override;
+ int64 Tell() override;
+ int Flush() override;
+ bool MayBlock() override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_STREAM_WRITER_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/string_visitor_ctocpp.cc b/libcef_dll/ctocpp/string_visitor_ctocpp.cc
new file mode 100644
index 00000000..b3657a84
--- /dev/null
+++ b/libcef_dll/ctocpp/string_visitor_ctocpp.cc
@@ -0,0 +1,61 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=bcde08bca60cd45a802fdeb684da6b0c41c7a540$
+//
+
+#include "libcef_dll/ctocpp/string_visitor_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+void CefStringVisitorCToCpp::Visit(const CefString& string) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_string_visitor_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, visit)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: string
+
+ // Execute
+ _struct->visit(_struct, string.GetStruct());
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefStringVisitorCToCpp::CefStringVisitorCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefStringVisitorCToCpp::~CefStringVisitorCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_string_visitor_t*
+CefCToCppRefCounted<CefStringVisitorCToCpp,
+ CefStringVisitor,
+ cef_string_visitor_t>::UnwrapDerived(CefWrapperType type,
+ CefStringVisitor* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefStringVisitorCToCpp,
+ CefStringVisitor,
+ cef_string_visitor_t>::kWrapperType =
+ WT_STRING_VISITOR;
diff --git a/libcef_dll/ctocpp/string_visitor_ctocpp.h b/libcef_dll/ctocpp/string_visitor_ctocpp.h
new file mode 100644
index 00000000..53e15edc
--- /dev/null
+++ b/libcef_dll/ctocpp/string_visitor_ctocpp.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=6e693b6dd1a72803aa7243d7cd5de54354338c37$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_STRING_VISITOR_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_STRING_VISITOR_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_string_visitor_capi.h"
+#include "include/cef_string_visitor.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefStringVisitorCToCpp
+ : public CefCToCppRefCounted<CefStringVisitorCToCpp,
+ CefStringVisitor,
+ cef_string_visitor_t> {
+ public:
+ CefStringVisitorCToCpp();
+ virtual ~CefStringVisitorCToCpp();
+
+ // CefStringVisitor methods.
+ void Visit(const CefString& string) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_STRING_VISITOR_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/task_ctocpp.cc b/libcef_dll/ctocpp/task_ctocpp.cc
new file mode 100644
index 00000000..dd4b25dd
--- /dev/null
+++ b/libcef_dll/ctocpp/task_ctocpp.cc
@@ -0,0 +1,51 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=33c1231863fe21b1c37ddba6900c4e75cbe25421$
+//
+
+#include "libcef_dll/ctocpp/task_ctocpp.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") void CefTaskCToCpp::Execute() {
+ cef_task_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, execute)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->execute(_struct);
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefTaskCToCpp::CefTaskCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefTaskCToCpp::~CefTaskCToCpp() {}
+
+template <>
+cef_task_t*
+CefCToCppRefCounted<CefTaskCToCpp, CefTask, cef_task_t>::UnwrapDerived(
+ CefWrapperType type,
+ CefTask* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCToCppRefCounted<CefTaskCToCpp, CefTask, cef_task_t>::kWrapperType =
+ WT_TASK;
diff --git a/libcef_dll/ctocpp/task_ctocpp.h b/libcef_dll/ctocpp/task_ctocpp.h
new file mode 100644
index 00000000..ccd90edb
--- /dev/null
+++ b/libcef_dll/ctocpp/task_ctocpp.h
@@ -0,0 +1,39 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=e722a5b9ae2bb6e3d3236a199930600dc3b5e0f8$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_TASK_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_TASK_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_task_capi.h"
+#include "include/cef_task.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefTaskCToCpp
+ : public CefCToCppRefCounted<CefTaskCToCpp, CefTask, cef_task_t> {
+ public:
+ CefTaskCToCpp();
+ virtual ~CefTaskCToCpp();
+
+ // CefTask methods.
+ void Execute() override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_TASK_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/task_runner_ctocpp.cc b/libcef_dll/ctocpp/task_runner_ctocpp.cc
new file mode 100644
index 00000000..bcbdf66c
--- /dev/null
+++ b/libcef_dll/ctocpp/task_runner_ctocpp.cc
@@ -0,0 +1,180 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=5a082e5b08a31d4c92fda51b26e07b291258e9e9$
+//
+
+#include "libcef_dll/ctocpp/task_runner_ctocpp.h"
+#include "libcef_dll/cpptoc/task_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// STATIC METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefTaskRunner> CefTaskRunner::GetForCurrentThread() {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_task_runner_t* _retval = cef_task_runner_get_for_current_thread();
+
+ // Return type: refptr_same
+ return CefTaskRunnerCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefTaskRunner> CefTaskRunner::GetForThread(CefThreadId threadId) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_task_runner_t* _retval = cef_task_runner_get_for_thread(threadId);
+
+ // Return type: refptr_same
+ return CefTaskRunnerCToCpp::Wrap(_retval);
+}
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+bool CefTaskRunnerCToCpp::IsSame(CefRefPtr<CefTaskRunner> that) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_task_runner_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_same)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: that; type: refptr_same
+ DCHECK(that.get());
+ if (!that.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->is_same(_struct, CefTaskRunnerCToCpp::Unwrap(that));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefTaskRunnerCToCpp::BelongsToCurrentThread() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_task_runner_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, belongs_to_current_thread)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->belongs_to_current_thread(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefTaskRunnerCToCpp::BelongsToThread(CefThreadId threadId) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_task_runner_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, belongs_to_thread)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->belongs_to_thread(_struct, threadId);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefTaskRunnerCToCpp::PostTask(CefRefPtr<CefTask> task) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_task_runner_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, post_task)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: task; type: refptr_diff
+ DCHECK(task.get());
+ if (!task.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->post_task(_struct, CefTaskCppToC::Wrap(task));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefTaskRunnerCToCpp::PostDelayedTask(CefRefPtr<CefTask> task,
+ int64 delay_ms) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_task_runner_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, post_delayed_task)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: task; type: refptr_diff
+ DCHECK(task.get());
+ if (!task.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval =
+ _struct->post_delayed_task(_struct, CefTaskCppToC::Wrap(task), delay_ms);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefTaskRunnerCToCpp::CefTaskRunnerCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefTaskRunnerCToCpp::~CefTaskRunnerCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_task_runner_t*
+CefCToCppRefCounted<CefTaskRunnerCToCpp, CefTaskRunner, cef_task_runner_t>::
+ UnwrapDerived(CefWrapperType type, CefTaskRunner* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefTaskRunnerCToCpp,
+ CefTaskRunner,
+ cef_task_runner_t>::kWrapperType =
+ WT_TASK_RUNNER;
diff --git a/libcef_dll/ctocpp/task_runner_ctocpp.h b/libcef_dll/ctocpp/task_runner_ctocpp.h
new file mode 100644
index 00000000..2f33aaff
--- /dev/null
+++ b/libcef_dll/ctocpp/task_runner_ctocpp.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=372cc40047bb36d78f80f4d1edbbba30faad2c7f$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_TASK_RUNNER_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_TASK_RUNNER_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_task_capi.h"
+#include "include/cef_task.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefTaskRunnerCToCpp : public CefCToCppRefCounted<CefTaskRunnerCToCpp,
+ CefTaskRunner,
+ cef_task_runner_t> {
+ public:
+ CefTaskRunnerCToCpp();
+ virtual ~CefTaskRunnerCToCpp();
+
+ // CefTaskRunner methods.
+ bool IsSame(CefRefPtr<CefTaskRunner> that) override;
+ bool BelongsToCurrentThread() override;
+ bool BelongsToThread(CefThreadId threadId) override;
+ bool PostTask(CefRefPtr<CefTask> task) override;
+ bool PostDelayedTask(CefRefPtr<CefTask> task, int64 delay_ms) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_TASK_RUNNER_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/test/test_server_connection_ctocpp.cc b/libcef_dll/ctocpp/test/test_server_connection_ctocpp.cc
new file mode 100644
index 00000000..ce3424c3
--- /dev/null
+++ b/libcef_dll/ctocpp/test/test_server_connection_ctocpp.cc
@@ -0,0 +1,157 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=8192d1e40fa6b42502907094351c3deeefb4db08$
+//
+
+#include "libcef_dll/ctocpp/test/test_server_connection_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+#include "libcef_dll/transfer_util.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+void CefTestServerConnectionCToCpp::SendHttp200Response(
+ const CefString& content_type,
+ const void* data,
+ size_t data_size) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_test_server_connection_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, send_http200response)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: content_type; type: string_byref_const
+ DCHECK(!content_type.empty());
+ if (content_type.empty()) {
+ return;
+ }
+ // Verify param: data; type: simple_byaddr
+ DCHECK(data);
+ if (!data) {
+ return;
+ }
+
+ // Execute
+ _struct->send_http200response(_struct, content_type.GetStruct(), data,
+ data_size);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefTestServerConnectionCToCpp::SendHttp404Response() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_test_server_connection_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, send_http404response)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->send_http404response(_struct);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefTestServerConnectionCToCpp::SendHttp500Response(
+ const CefString& error_message) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_test_server_connection_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, send_http500response)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: error_message; type: string_byref_const
+ DCHECK(!error_message.empty());
+ if (error_message.empty()) {
+ return;
+ }
+
+ // Execute
+ _struct->send_http500response(_struct, error_message.GetStruct());
+}
+
+NO_SANITIZE("cfi-icall")
+void CefTestServerConnectionCToCpp::SendHttpResponse(
+ int response_code,
+ const CefString& content_type,
+ const void* data,
+ size_t data_size,
+ const HeaderMap& extra_headers) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_test_server_connection_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, send_http_response)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: content_type; type: string_byref_const
+ DCHECK(!content_type.empty());
+ if (content_type.empty()) {
+ return;
+ }
+ // Verify param: data; type: simple_byaddr
+ DCHECK(data);
+ if (!data) {
+ return;
+ }
+ // Unverified params: extra_headers
+
+ // Translate param: extra_headers; type: string_map_multi_byref_const
+ cef_string_multimap_t extra_headersMultimap = cef_string_multimap_alloc();
+ DCHECK(extra_headersMultimap);
+ if (extra_headersMultimap) {
+ transfer_string_multimap_contents(extra_headers, extra_headersMultimap);
+ }
+
+ // Execute
+ _struct->send_http_response(_struct, response_code, content_type.GetStruct(),
+ data, data_size, extra_headersMultimap);
+
+ // Restore param:extra_headers; type: string_map_multi_byref_const
+ if (extra_headersMultimap) {
+ cef_string_multimap_free(extra_headersMultimap);
+ }
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefTestServerConnectionCToCpp::CefTestServerConnectionCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefTestServerConnectionCToCpp::~CefTestServerConnectionCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_test_server_connection_t* CefCToCppRefCounted<
+ CefTestServerConnectionCToCpp,
+ CefTestServerConnection,
+ cef_test_server_connection_t>::UnwrapDerived(CefWrapperType type,
+ CefTestServerConnection* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefTestServerConnectionCToCpp,
+ CefTestServerConnection,
+ cef_test_server_connection_t>::kWrapperType =
+ WT_TEST_SERVER_CONNECTION;
diff --git a/libcef_dll/ctocpp/test/test_server_connection_ctocpp.h b/libcef_dll/ctocpp/test/test_server_connection_ctocpp.h
new file mode 100644
index 00000000..0c2788d9
--- /dev/null
+++ b/libcef_dll/ctocpp/test/test_server_connection_ctocpp.h
@@ -0,0 +1,50 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=99b84d1e02eeeaa485722c9d685bfed90a8bd356$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_TEST_TEST_SERVER_CONNECTION_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_TEST_TEST_SERVER_CONNECTION_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/test/cef_test_server_capi.h"
+#include "include/test/cef_test_server.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefTestServerConnectionCToCpp
+ : public CefCToCppRefCounted<CefTestServerConnectionCToCpp,
+ CefTestServerConnection,
+ cef_test_server_connection_t> {
+ public:
+ CefTestServerConnectionCToCpp();
+ virtual ~CefTestServerConnectionCToCpp();
+
+ // CefTestServerConnection methods.
+ void SendHttp200Response(const CefString& content_type,
+ const void* data,
+ size_t data_size) override;
+ void SendHttp404Response() override;
+ void SendHttp500Response(const CefString& error_message) override;
+ void SendHttpResponse(int response_code,
+ const CefString& content_type,
+ const void* data,
+ size_t data_size,
+ const HeaderMap& extra_headers) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_TEST_TEST_SERVER_CONNECTION_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/test/test_server_ctocpp.cc b/libcef_dll/ctocpp/test/test_server_ctocpp.cc
new file mode 100644
index 00000000..132f7117
--- /dev/null
+++ b/libcef_dll/ctocpp/test/test_server_ctocpp.cc
@@ -0,0 +1,103 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=c28a94226a89e94a765d19e7d59bfa8a50efe295$
+//
+
+#include "libcef_dll/ctocpp/test/test_server_ctocpp.h"
+#include "libcef_dll/cpptoc/test/test_server_handler_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// STATIC METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefTestServer> CefTestServer::CreateAndStart(
+ uint16 port,
+ bool https_server,
+ cef_test_cert_type_t https_cert_type,
+ CefRefPtr<CefTestServerHandler> handler) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: handler; type: refptr_diff
+ DCHECK(handler.get());
+ if (!handler.get()) {
+ return nullptr;
+ }
+
+ // Execute
+ cef_test_server_t* _retval = cef_test_server_create_and_start(
+ port, https_server, https_cert_type,
+ CefTestServerHandlerCppToC::Wrap(handler));
+
+ // Return type: refptr_same
+ return CefTestServerCToCpp::Wrap(_retval);
+}
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") void CefTestServerCToCpp::Stop() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_test_server_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, stop)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->stop(_struct);
+}
+
+NO_SANITIZE("cfi-icall") CefString CefTestServerCToCpp::GetOrigin() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_test_server_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_origin)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_origin(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefTestServerCToCpp::CefTestServerCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefTestServerCToCpp::~CefTestServerCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_test_server_t*
+CefCToCppRefCounted<CefTestServerCToCpp, CefTestServer, cef_test_server_t>::
+ UnwrapDerived(CefWrapperType type, CefTestServer* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefTestServerCToCpp,
+ CefTestServer,
+ cef_test_server_t>::kWrapperType =
+ WT_TEST_SERVER;
diff --git a/libcef_dll/ctocpp/test/test_server_ctocpp.h b/libcef_dll/ctocpp/test/test_server_ctocpp.h
new file mode 100644
index 00000000..1d95f6b4
--- /dev/null
+++ b/libcef_dll/ctocpp/test/test_server_ctocpp.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=06d5fbd145898540f060616efbd6f81e1bee7498$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_TEST_TEST_SERVER_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_TEST_TEST_SERVER_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/test/cef_test_server_capi.h"
+#include "include/test/cef_test_server.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefTestServerCToCpp : public CefCToCppRefCounted<CefTestServerCToCpp,
+ CefTestServer,
+ cef_test_server_t> {
+ public:
+ CefTestServerCToCpp();
+ virtual ~CefTestServerCToCpp();
+
+ // CefTestServer methods.
+ void Stop() override;
+ CefString GetOrigin() override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_TEST_TEST_SERVER_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/test/test_server_handler_ctocpp.cc b/libcef_dll/ctocpp/test/test_server_handler_ctocpp.cc
new file mode 100644
index 00000000..365c921f
--- /dev/null
+++ b/libcef_dll/ctocpp/test/test_server_handler_ctocpp.cc
@@ -0,0 +1,87 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=150f0433fb541e23edad54baa1af9f870f4c7a84$
+//
+
+#include "libcef_dll/ctocpp/test/test_server_handler_ctocpp.h"
+#include "libcef_dll/cpptoc/request_cpptoc.h"
+#include "libcef_dll/cpptoc/test/test_server_connection_cpptoc.h"
+#include "libcef_dll/cpptoc/test/test_server_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+bool CefTestServerHandlerCToCpp::OnTestServerRequest(
+ CefRefPtr<CefTestServer> server,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefTestServerConnection> connection) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_test_server_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_test_server_request)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: server; type: refptr_diff
+ DCHECK(server.get());
+ if (!server.get()) {
+ return false;
+ }
+ // Verify param: request; type: refptr_diff
+ DCHECK(request.get());
+ if (!request.get()) {
+ return false;
+ }
+ // Verify param: connection; type: refptr_diff
+ DCHECK(connection.get());
+ if (!connection.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->on_test_server_request(
+ _struct, CefTestServerCppToC::Wrap(server),
+ CefRequestCppToC::Wrap(request),
+ CefTestServerConnectionCppToC::Wrap(connection));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefTestServerHandlerCToCpp::CefTestServerHandlerCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefTestServerHandlerCToCpp::~CefTestServerHandlerCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_test_server_handler_t* CefCToCppRefCounted<
+ CefTestServerHandlerCToCpp,
+ CefTestServerHandler,
+ cef_test_server_handler_t>::UnwrapDerived(CefWrapperType type,
+ CefTestServerHandler* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefTestServerHandlerCToCpp,
+ CefTestServerHandler,
+ cef_test_server_handler_t>::kWrapperType =
+ WT_TEST_SERVER_HANDLER;
diff --git a/libcef_dll/ctocpp/test/test_server_handler_ctocpp.h b/libcef_dll/ctocpp/test/test_server_handler_ctocpp.h
new file mode 100644
index 00000000..b390bf7c
--- /dev/null
+++ b/libcef_dll/ctocpp/test/test_server_handler_ctocpp.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=c0a7d6e6596314771567fafa185ac777bdc61a65$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_TEST_TEST_SERVER_HANDLER_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_TEST_TEST_SERVER_HANDLER_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/test/cef_test_server_capi.h"
+#include "include/test/cef_test_server.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefTestServerHandlerCToCpp
+ : public CefCToCppRefCounted<CefTestServerHandlerCToCpp,
+ CefTestServerHandler,
+ cef_test_server_handler_t> {
+ public:
+ CefTestServerHandlerCToCpp();
+ virtual ~CefTestServerHandlerCToCpp();
+
+ // CefTestServerHandler methods.
+ bool OnTestServerRequest(
+ CefRefPtr<CefTestServer> server,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefTestServerConnection> connection) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_TEST_TEST_SERVER_HANDLER_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/test/translator_test_ctocpp.cc b/libcef_dll/ctocpp/test/translator_test_ctocpp.cc
new file mode 100644
index 00000000..da331e4d
--- /dev/null
+++ b/libcef_dll/ctocpp/test/translator_test_ctocpp.cc
@@ -0,0 +1,1663 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=af7948baa27d1ea9ad277f294014affb8bf3ba49$
+//
+
+#include "libcef_dll/ctocpp/test/translator_test_ctocpp.h"
+#include <algorithm>
+#include "libcef_dll/cpptoc/test/translator_test_ref_ptr_client_child_cpptoc.h"
+#include "libcef_dll/cpptoc/test/translator_test_ref_ptr_client_cpptoc.h"
+#include "libcef_dll/cpptoc/test/translator_test_scoped_client_child_cpptoc.h"
+#include "libcef_dll/cpptoc/test/translator_test_scoped_client_cpptoc.h"
+#include "libcef_dll/ctocpp/test/translator_test_ref_ptr_library_child_ctocpp.h"
+#include "libcef_dll/ctocpp/test/translator_test_ref_ptr_library_ctocpp.h"
+#include "libcef_dll/ctocpp/test/translator_test_scoped_library_child_ctocpp.h"
+#include "libcef_dll/ctocpp/test/translator_test_scoped_library_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+#include "libcef_dll/transfer_util.h"
+
+// STATIC METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefTranslatorTest> CefTranslatorTest::Create() {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_translator_test_t* _retval = cef_translator_test_create();
+
+ // Return type: refptr_same
+ return CefTranslatorTestCToCpp::Wrap(_retval);
+}
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") void CefTranslatorTestCToCpp::GetVoid() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_void)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->get_void(_struct);
+}
+
+NO_SANITIZE("cfi-icall") bool CefTranslatorTestCToCpp::GetBool() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_bool)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_bool(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") int CefTranslatorTestCToCpp::GetInt() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_int)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_int(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") double CefTranslatorTestCToCpp::GetDouble() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_double)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ double _retval = _struct->get_double(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") long CefTranslatorTestCToCpp::GetLong() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_long)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ long _retval = _struct->get_long(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") size_t CefTranslatorTestCToCpp::GetSizet() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_sizet)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ size_t _retval = _struct->get_sizet(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") bool CefTranslatorTestCToCpp::SetVoid() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_void)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->set_void(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefTranslatorTestCToCpp::SetBool(bool val) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_bool)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->set_bool(_struct, val);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefTranslatorTestCToCpp::SetInt(int val) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_int)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->set_int(_struct, val);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefTranslatorTestCToCpp::SetDouble(double val) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_double)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->set_double(_struct, val);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefTranslatorTestCToCpp::SetLong(long val) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_long)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->set_long(_struct, val);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefTranslatorTestCToCpp::SetSizet(size_t val) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_sizet)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->set_sizet(_struct, val);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefTranslatorTestCToCpp::SetIntList(const std::vector<int>& val) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_int_list)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Translate param: val; type: simple_vec_byref_const
+ const size_t valCount = val.size();
+ int* valList = NULL;
+ if (valCount > 0) {
+ valList = new int[valCount];
+ DCHECK(valList);
+ if (valList) {
+ for (size_t i = 0; i < valCount; ++i) {
+ valList[i] = val[i];
+ }
+ }
+ }
+
+ // Execute
+ int _retval = _struct->set_int_list(_struct, valCount, valList);
+
+ // Restore param:val; type: simple_vec_byref_const
+ if (valList) {
+ delete[] valList;
+ }
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefTranslatorTestCToCpp::GetIntListByRef(IntList& val) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_int_list_by_ref)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Translate param: val; type: simple_vec_byref
+ size_t valSize = val.size();
+ size_t valCount = std::max(GetIntListSize(), valSize);
+ int* valList = NULL;
+ if (valCount > 0) {
+ valList = new int[valCount];
+ DCHECK(valList);
+ if (valList) {
+ memset(valList, 0, sizeof(int) * valCount);
+ }
+ if (valList && valSize > 0) {
+ for (size_t i = 0; i < valSize; ++i) {
+ valList[i] = val[i];
+ }
+ }
+ }
+
+ // Execute
+ int _retval = _struct->get_int_list_by_ref(_struct, &valCount, valList);
+
+ // Restore param:val; type: simple_vec_byref
+ val.clear();
+ if (valCount > 0 && valList) {
+ for (size_t i = 0; i < valCount; ++i) {
+ val.push_back(valList[i]);
+ }
+ delete[] valList;
+ }
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") size_t CefTranslatorTestCToCpp::GetIntListSize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_int_list_size)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ size_t _retval = _struct->get_int_list_size(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") CefString CefTranslatorTestCToCpp::GetString() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_string)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_string(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefTranslatorTestCToCpp::SetString(const CefString& val) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_string)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: val; type: string_byref_const
+ DCHECK(!val.empty());
+ if (val.empty()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->set_string(_struct, val.GetStruct());
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefTranslatorTestCToCpp::GetStringByRef(CefString& val) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_string_by_ref)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->get_string_by_ref(_struct, val.GetWritableStruct());
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefTranslatorTestCToCpp::SetStringList(const std::vector<CefString>& val) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_string_list)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Translate param: val; type: string_vec_byref_const
+ cef_string_list_t valList = cef_string_list_alloc();
+ DCHECK(valList);
+ if (valList) {
+ transfer_string_list_contents(val, valList);
+ }
+
+ // Execute
+ int _retval = _struct->set_string_list(_struct, valList);
+
+ // Restore param:val; type: string_vec_byref_const
+ if (valList) {
+ cef_string_list_free(valList);
+ }
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefTranslatorTestCToCpp::GetStringListByRef(StringList& val) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_string_list_by_ref)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Translate param: val; type: string_vec_byref
+ cef_string_list_t valList = cef_string_list_alloc();
+ DCHECK(valList);
+ if (valList) {
+ transfer_string_list_contents(val, valList);
+ }
+
+ // Execute
+ int _retval = _struct->get_string_list_by_ref(_struct, valList);
+
+ // Restore param:val; type: string_vec_byref
+ if (valList) {
+ val.clear();
+ transfer_string_list_contents(valList, val);
+ cef_string_list_free(valList);
+ }
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefTranslatorTestCToCpp::SetStringMap(const StringMap& val) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_string_map)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Translate param: val; type: string_map_single_byref_const
+ cef_string_map_t valMap = cef_string_map_alloc();
+ DCHECK(valMap);
+ if (valMap) {
+ transfer_string_map_contents(val, valMap);
+ }
+
+ // Execute
+ int _retval = _struct->set_string_map(_struct, valMap);
+
+ // Restore param:val; type: string_map_single_byref_const
+ if (valMap) {
+ cef_string_map_free(valMap);
+ }
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefTranslatorTestCToCpp::GetStringMapByRef(
+ std::map<CefString, CefString>& val) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_string_map_by_ref)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Translate param: val; type: string_map_single_byref
+ cef_string_map_t valMap = cef_string_map_alloc();
+ DCHECK(valMap);
+ if (valMap) {
+ transfer_string_map_contents(val, valMap);
+ }
+
+ // Execute
+ int _retval = _struct->get_string_map_by_ref(_struct, valMap);
+
+ // Restore param:val; type: string_map_single_byref
+ if (valMap) {
+ val.clear();
+ transfer_string_map_contents(valMap, val);
+ cef_string_map_free(valMap);
+ }
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefTranslatorTestCToCpp::SetStringMultimap(
+ const std::multimap<CefString, CefString>& val) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_string_multimap)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Translate param: val; type: string_map_multi_byref_const
+ cef_string_multimap_t valMultimap = cef_string_multimap_alloc();
+ DCHECK(valMultimap);
+ if (valMultimap) {
+ transfer_string_multimap_contents(val, valMultimap);
+ }
+
+ // Execute
+ int _retval = _struct->set_string_multimap(_struct, valMultimap);
+
+ // Restore param:val; type: string_map_multi_byref_const
+ if (valMultimap) {
+ cef_string_multimap_free(valMultimap);
+ }
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefTranslatorTestCToCpp::GetStringMultimapByRef(StringMultimap& val) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_string_multimap_by_ref)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Translate param: val; type: string_map_multi_byref
+ cef_string_multimap_t valMultimap = cef_string_multimap_alloc();
+ DCHECK(valMultimap);
+ if (valMultimap) {
+ transfer_string_multimap_contents(val, valMultimap);
+ }
+
+ // Execute
+ int _retval = _struct->get_string_multimap_by_ref(_struct, valMultimap);
+
+ // Restore param:val; type: string_map_multi_byref
+ if (valMultimap) {
+ val.clear();
+ transfer_string_multimap_contents(valMultimap, val);
+ cef_string_multimap_free(valMultimap);
+ }
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") CefPoint CefTranslatorTestCToCpp::GetPoint() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_point)) {
+ return CefPoint();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_point_t _retval = _struct->get_point(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefTranslatorTestCToCpp::SetPoint(const CefPoint& val) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_point)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->set_point(_struct, &val);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefTranslatorTestCToCpp::GetPointByRef(CefPoint& val) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_point_by_ref)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->get_point_by_ref(_struct, &val);
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefTranslatorTestCToCpp::SetPointList(const std::vector<CefPoint>& val) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_point_list)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Translate param: val; type: simple_vec_byref_const
+ const size_t valCount = val.size();
+ cef_point_t* valList = NULL;
+ if (valCount > 0) {
+ valList = new cef_point_t[valCount];
+ DCHECK(valList);
+ if (valList) {
+ for (size_t i = 0; i < valCount; ++i) {
+ valList[i] = val[i];
+ }
+ }
+ }
+
+ // Execute
+ int _retval = _struct->set_point_list(_struct, valCount, valList);
+
+ // Restore param:val; type: simple_vec_byref_const
+ if (valList) {
+ delete[] valList;
+ }
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefTranslatorTestCToCpp::GetPointListByRef(PointList& val) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_point_list_by_ref)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Translate param: val; type: simple_vec_byref
+ size_t valSize = val.size();
+ size_t valCount = std::max(GetPointListSize(), valSize);
+ cef_point_t* valList = NULL;
+ if (valCount > 0) {
+ valList = new cef_point_t[valCount];
+ DCHECK(valList);
+ if (valList) {
+ memset(valList, 0, sizeof(cef_point_t) * valCount);
+ }
+ if (valList && valSize > 0) {
+ for (size_t i = 0; i < valSize; ++i) {
+ valList[i] = val[i];
+ }
+ }
+ }
+
+ // Execute
+ int _retval = _struct->get_point_list_by_ref(_struct, &valCount, valList);
+
+ // Restore param:val; type: simple_vec_byref
+ val.clear();
+ if (valCount > 0 && valList) {
+ for (size_t i = 0; i < valCount; ++i) {
+ val.push_back(valList[i]);
+ }
+ delete[] valList;
+ }
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") size_t CefTranslatorTestCToCpp::GetPointListSize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_point_list_size)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ size_t _retval = _struct->get_point_list_size(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefTranslatorTestRefPtrLibrary>
+CefTranslatorTestCToCpp::GetRefPtrLibrary(int val) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_ref_ptr_library)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_translator_test_ref_ptr_library_t* _retval =
+ _struct->get_ref_ptr_library(_struct, val);
+
+ // Return type: refptr_same
+ return CefTranslatorTestRefPtrLibraryCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+int CefTranslatorTestCToCpp::SetRefPtrLibrary(
+ CefRefPtr<CefTranslatorTestRefPtrLibrary> val) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_ref_ptr_library)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: val; type: refptr_same
+ DCHECK(val.get());
+ if (!val.get()) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = _struct->set_ref_ptr_library(
+ _struct, CefTranslatorTestRefPtrLibraryCToCpp::Unwrap(val));
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefTranslatorTestRefPtrLibrary>
+CefTranslatorTestCToCpp::SetRefPtrLibraryAndReturn(
+ CefRefPtr<CefTranslatorTestRefPtrLibrary> val) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_ref_ptr_library_and_return)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: val; type: refptr_same
+ DCHECK(val.get());
+ if (!val.get()) {
+ return nullptr;
+ }
+
+ // Execute
+ cef_translator_test_ref_ptr_library_t* _retval =
+ _struct->set_ref_ptr_library_and_return(
+ _struct, CefTranslatorTestRefPtrLibraryCToCpp::Unwrap(val));
+
+ // Return type: refptr_same
+ return CefTranslatorTestRefPtrLibraryCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+int CefTranslatorTestCToCpp::SetChildRefPtrLibrary(
+ CefRefPtr<CefTranslatorTestRefPtrLibraryChild> val) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_child_ref_ptr_library)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: val; type: refptr_same
+ DCHECK(val.get());
+ if (!val.get()) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = _struct->set_child_ref_ptr_library(
+ _struct, CefTranslatorTestRefPtrLibraryChildCToCpp::Unwrap(val));
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefTranslatorTestRefPtrLibrary>
+CefTranslatorTestCToCpp::SetChildRefPtrLibraryAndReturnParent(
+ CefRefPtr<CefTranslatorTestRefPtrLibraryChild> val) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct,
+ set_child_ref_ptr_library_and_return_parent)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: val; type: refptr_same
+ DCHECK(val.get());
+ if (!val.get()) {
+ return nullptr;
+ }
+
+ // Execute
+ cef_translator_test_ref_ptr_library_t* _retval =
+ _struct->set_child_ref_ptr_library_and_return_parent(
+ _struct, CefTranslatorTestRefPtrLibraryChildCToCpp::Unwrap(val));
+
+ // Return type: refptr_same
+ return CefTranslatorTestRefPtrLibraryCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefTranslatorTestCToCpp::SetRefPtrLibraryList(
+ const std::vector<CefRefPtr<CefTranslatorTestRefPtrLibrary>>& val,
+ int val1,
+ int val2) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_ref_ptr_library_list)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Translate param: val; type: refptr_vec_same_byref_const
+ const size_t valCount = val.size();
+ cef_translator_test_ref_ptr_library_t** valList = NULL;
+ if (valCount > 0) {
+ valList = new cef_translator_test_ref_ptr_library_t*[valCount];
+ DCHECK(valList);
+ if (valList) {
+ for (size_t i = 0; i < valCount; ++i) {
+ valList[i] = CefTranslatorTestRefPtrLibraryCToCpp::Unwrap(val[i]);
+ }
+ }
+ }
+
+ // Execute
+ int _retval =
+ _struct->set_ref_ptr_library_list(_struct, valCount, valList, val1, val2);
+
+ // Restore param:val; type: refptr_vec_same_byref_const
+ if (valList) {
+ delete[] valList;
+ }
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefTranslatorTestCToCpp::GetRefPtrLibraryListByRef(RefPtrLibraryList& val,
+ int val1,
+ int val2) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_ref_ptr_library_list_by_ref)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Translate param: val; type: refptr_vec_same_byref
+ size_t valSize = val.size();
+ size_t valCount = std::max(GetRefPtrLibraryListSize(), valSize);
+ cef_translator_test_ref_ptr_library_t** valList = NULL;
+ if (valCount > 0) {
+ valList = new cef_translator_test_ref_ptr_library_t*[valCount];
+ DCHECK(valList);
+ if (valList) {
+ memset(valList, 0,
+ sizeof(cef_translator_test_ref_ptr_library_t*) * valCount);
+ }
+ if (valList && valSize > 0) {
+ for (size_t i = 0; i < valSize; ++i) {
+ valList[i] = CefTranslatorTestRefPtrLibraryCToCpp::Unwrap(val[i]);
+ }
+ }
+ }
+
+ // Execute
+ int _retval = _struct->get_ref_ptr_library_list_by_ref(_struct, &valCount,
+ valList, val1, val2);
+
+ // Restore param:val; type: refptr_vec_same_byref
+ val.clear();
+ if (valCount > 0 && valList) {
+ for (size_t i = 0; i < valCount; ++i) {
+ val.push_back(CefTranslatorTestRefPtrLibraryCToCpp::Wrap(valList[i]));
+ }
+ delete[] valList;
+ }
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+size_t CefTranslatorTestCToCpp::GetRefPtrLibraryListSize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_ref_ptr_library_list_size)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ size_t _retval = _struct->get_ref_ptr_library_list_size(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+int CefTranslatorTestCToCpp::SetRefPtrClient(
+ CefRefPtr<CefTranslatorTestRefPtrClient> val) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_ref_ptr_client)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: val; type: refptr_diff
+ DCHECK(val.get());
+ if (!val.get()) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = _struct->set_ref_ptr_client(
+ _struct, CefTranslatorTestRefPtrClientCppToC::Wrap(val));
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefTranslatorTestRefPtrClient>
+CefTranslatorTestCToCpp::SetRefPtrClientAndReturn(
+ CefRefPtr<CefTranslatorTestRefPtrClient> val) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_ref_ptr_client_and_return)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: val; type: refptr_diff
+ DCHECK(val.get());
+ if (!val.get()) {
+ return nullptr;
+ }
+
+ // Execute
+ cef_translator_test_ref_ptr_client_t* _retval =
+ _struct->set_ref_ptr_client_and_return(
+ _struct, CefTranslatorTestRefPtrClientCppToC::Wrap(val));
+
+ // Return type: refptr_diff
+ return CefTranslatorTestRefPtrClientCppToC::Unwrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+int CefTranslatorTestCToCpp::SetChildRefPtrClient(
+ CefRefPtr<CefTranslatorTestRefPtrClientChild> val) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_child_ref_ptr_client)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: val; type: refptr_diff
+ DCHECK(val.get());
+ if (!val.get()) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = _struct->set_child_ref_ptr_client(
+ _struct, CefTranslatorTestRefPtrClientChildCppToC::Wrap(val));
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefTranslatorTestRefPtrClient>
+CefTranslatorTestCToCpp::SetChildRefPtrClientAndReturnParent(
+ CefRefPtr<CefTranslatorTestRefPtrClientChild> val) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_child_ref_ptr_client_and_return_parent)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: val; type: refptr_diff
+ DCHECK(val.get());
+ if (!val.get()) {
+ return nullptr;
+ }
+
+ // Execute
+ cef_translator_test_ref_ptr_client_t* _retval =
+ _struct->set_child_ref_ptr_client_and_return_parent(
+ _struct, CefTranslatorTestRefPtrClientChildCppToC::Wrap(val));
+
+ // Return type: refptr_diff
+ return CefTranslatorTestRefPtrClientCppToC::Unwrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefTranslatorTestCToCpp::SetRefPtrClientList(
+ const std::vector<CefRefPtr<CefTranslatorTestRefPtrClient>>& val,
+ int val1,
+ int val2) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_ref_ptr_client_list)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Translate param: val; type: refptr_vec_diff_byref_const
+ const size_t valCount = val.size();
+ cef_translator_test_ref_ptr_client_t** valList = NULL;
+ if (valCount > 0) {
+ valList = new cef_translator_test_ref_ptr_client_t*[valCount];
+ DCHECK(valList);
+ if (valList) {
+ for (size_t i = 0; i < valCount; ++i) {
+ valList[i] = CefTranslatorTestRefPtrClientCppToC::Wrap(val[i]);
+ }
+ }
+ }
+
+ // Execute
+ int _retval =
+ _struct->set_ref_ptr_client_list(_struct, valCount, valList, val1, val2);
+
+ // Restore param:val; type: refptr_vec_diff_byref_const
+ if (valList) {
+ delete[] valList;
+ }
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefTranslatorTestCToCpp::GetRefPtrClientListByRef(
+ RefPtrClientList& val,
+ CefRefPtr<CefTranslatorTestRefPtrClient> val1,
+ CefRefPtr<CefTranslatorTestRefPtrClient> val2) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_ref_ptr_client_list_by_ref)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: val1; type: refptr_diff
+ DCHECK(val1.get());
+ if (!val1.get()) {
+ return false;
+ }
+ // Verify param: val2; type: refptr_diff
+ DCHECK(val2.get());
+ if (!val2.get()) {
+ return false;
+ }
+
+ // Translate param: val; type: refptr_vec_diff_byref
+ size_t valSize = val.size();
+ size_t valCount = std::max(GetRefPtrLibraryListSize(), valSize);
+ cef_translator_test_ref_ptr_client_t** valList = NULL;
+ if (valCount > 0) {
+ valList = new cef_translator_test_ref_ptr_client_t*[valCount];
+ DCHECK(valList);
+ if (valList) {
+ memset(valList, 0,
+ sizeof(cef_translator_test_ref_ptr_client_t*) * valCount);
+ }
+ if (valList && valSize > 0) {
+ for (size_t i = 0; i < valSize; ++i) {
+ valList[i] = CefTranslatorTestRefPtrClientCppToC::Wrap(val[i]);
+ }
+ }
+ }
+
+ // Execute
+ int _retval = _struct->get_ref_ptr_client_list_by_ref(
+ _struct, &valCount, valList,
+ CefTranslatorTestRefPtrClientCppToC::Wrap(val1),
+ CefTranslatorTestRefPtrClientCppToC::Wrap(val2));
+
+ // Restore param:val; type: refptr_vec_diff_byref
+ val.clear();
+ if (valCount > 0 && valList) {
+ for (size_t i = 0; i < valCount; ++i) {
+ val.push_back(CefTranslatorTestRefPtrClientCppToC::Unwrap(valList[i]));
+ }
+ delete[] valList;
+ }
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+size_t CefTranslatorTestCToCpp::GetRefPtrClientListSize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_ref_ptr_client_list_size)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ size_t _retval = _struct->get_ref_ptr_client_list_size(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CefOwnPtr<CefTranslatorTestScopedLibrary>
+CefTranslatorTestCToCpp::GetOwnPtrLibrary(int val) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_own_ptr_library)) {
+ return CefOwnPtr<CefTranslatorTestScopedLibrary>();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_translator_test_scoped_library_t* _retval =
+ _struct->get_own_ptr_library(_struct, val);
+
+ // Return type: ownptr_same
+ return CefTranslatorTestScopedLibraryCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+int CefTranslatorTestCToCpp::SetOwnPtrLibrary(
+ CefOwnPtr<CefTranslatorTestScopedLibrary> val) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_own_ptr_library)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: val; type: ownptr_same
+ DCHECK(val.get());
+ if (!val.get()) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = _struct->set_own_ptr_library(
+ _struct, CefTranslatorTestScopedLibraryCToCpp::UnwrapOwn(std::move(val)));
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CefOwnPtr<CefTranslatorTestScopedLibrary>
+CefTranslatorTestCToCpp::SetOwnPtrLibraryAndReturn(
+ CefOwnPtr<CefTranslatorTestScopedLibrary> val) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_own_ptr_library_and_return)) {
+ return CefOwnPtr<CefTranslatorTestScopedLibrary>();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: val; type: ownptr_same
+ DCHECK(val.get());
+ if (!val.get()) {
+ return CefOwnPtr<CefTranslatorTestScopedLibrary>();
+ }
+
+ // Execute
+ cef_translator_test_scoped_library_t* _retval =
+ _struct->set_own_ptr_library_and_return(
+ _struct,
+ CefTranslatorTestScopedLibraryCToCpp::UnwrapOwn(std::move(val)));
+
+ // Return type: ownptr_same
+ return CefTranslatorTestScopedLibraryCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+int CefTranslatorTestCToCpp::SetChildOwnPtrLibrary(
+ CefOwnPtr<CefTranslatorTestScopedLibraryChild> val) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_child_own_ptr_library)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: val; type: ownptr_same
+ DCHECK(val.get());
+ if (!val.get()) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = _struct->set_child_own_ptr_library(
+ _struct,
+ CefTranslatorTestScopedLibraryChildCToCpp::UnwrapOwn(std::move(val)));
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CefOwnPtr<CefTranslatorTestScopedLibrary>
+CefTranslatorTestCToCpp::SetChildOwnPtrLibraryAndReturnParent(
+ CefOwnPtr<CefTranslatorTestScopedLibraryChild> val) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct,
+ set_child_own_ptr_library_and_return_parent)) {
+ return CefOwnPtr<CefTranslatorTestScopedLibrary>();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: val; type: ownptr_same
+ DCHECK(val.get());
+ if (!val.get()) {
+ return CefOwnPtr<CefTranslatorTestScopedLibrary>();
+ }
+
+ // Execute
+ cef_translator_test_scoped_library_t* _retval =
+ _struct->set_child_own_ptr_library_and_return_parent(
+ _struct,
+ CefTranslatorTestScopedLibraryChildCToCpp::UnwrapOwn(std::move(val)));
+
+ // Return type: ownptr_same
+ return CefTranslatorTestScopedLibraryCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+int CefTranslatorTestCToCpp::SetOwnPtrClient(
+ CefOwnPtr<CefTranslatorTestScopedClient> val) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_own_ptr_client)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: val; type: ownptr_diff
+ DCHECK(val.get());
+ if (!val.get()) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = _struct->set_own_ptr_client(
+ _struct, CefTranslatorTestScopedClientCppToC::WrapOwn(std::move(val)));
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CefOwnPtr<CefTranslatorTestScopedClient>
+CefTranslatorTestCToCpp::SetOwnPtrClientAndReturn(
+ CefOwnPtr<CefTranslatorTestScopedClient> val) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_own_ptr_client_and_return)) {
+ return CefOwnPtr<CefTranslatorTestScopedClient>();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: val; type: ownptr_diff
+ DCHECK(val.get());
+ if (!val.get()) {
+ return CefOwnPtr<CefTranslatorTestScopedClient>();
+ }
+
+ // Execute
+ cef_translator_test_scoped_client_t* _retval =
+ _struct->set_own_ptr_client_and_return(
+ _struct,
+ CefTranslatorTestScopedClientCppToC::WrapOwn(std::move(val)));
+
+ // Return type: ownptr_diff
+ return CefTranslatorTestScopedClientCppToC::UnwrapOwn(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+int CefTranslatorTestCToCpp::SetChildOwnPtrClient(
+ CefOwnPtr<CefTranslatorTestScopedClientChild> val) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_child_own_ptr_client)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: val; type: ownptr_diff
+ DCHECK(val.get());
+ if (!val.get()) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = _struct->set_child_own_ptr_client(
+ _struct,
+ CefTranslatorTestScopedClientChildCppToC::WrapOwn(std::move(val)));
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CefOwnPtr<CefTranslatorTestScopedClient>
+CefTranslatorTestCToCpp::SetChildOwnPtrClientAndReturnParent(
+ CefOwnPtr<CefTranslatorTestScopedClientChild> val) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_child_own_ptr_client_and_return_parent)) {
+ return CefOwnPtr<CefTranslatorTestScopedClient>();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: val; type: ownptr_diff
+ DCHECK(val.get());
+ if (!val.get()) {
+ return CefOwnPtr<CefTranslatorTestScopedClient>();
+ }
+
+ // Execute
+ cef_translator_test_scoped_client_t* _retval =
+ _struct->set_child_own_ptr_client_and_return_parent(
+ _struct,
+ CefTranslatorTestScopedClientChildCppToC::WrapOwn(std::move(val)));
+
+ // Return type: ownptr_diff
+ return CefTranslatorTestScopedClientCppToC::UnwrapOwn(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+int CefTranslatorTestCToCpp::SetRawPtrLibrary(
+ CefRawPtr<CefTranslatorTestScopedLibrary> val) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_raw_ptr_library)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: val; type: rawptr_same
+ DCHECK(val);
+ if (!val) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = _struct->set_raw_ptr_library(
+ _struct, CefTranslatorTestScopedLibraryCToCpp::UnwrapRaw(val));
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+int CefTranslatorTestCToCpp::SetChildRawPtrLibrary(
+ CefRawPtr<CefTranslatorTestScopedLibraryChild> val) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_child_raw_ptr_library)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: val; type: rawptr_same
+ DCHECK(val);
+ if (!val) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = _struct->set_child_raw_ptr_library(
+ _struct, CefTranslatorTestScopedLibraryChildCToCpp::UnwrapRaw(val));
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefTranslatorTestCToCpp::SetRawPtrLibraryList(
+ const std::vector<CefRawPtr<CefTranslatorTestScopedLibrary>>& val,
+ int val1,
+ int val2) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_raw_ptr_library_list)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Translate param: val; type: rawptr_vec_same_byref_const
+ const size_t valCount = val.size();
+ cef_translator_test_scoped_library_t** valList = NULL;
+ if (valCount > 0) {
+ valList = new cef_translator_test_scoped_library_t*[valCount];
+ DCHECK(valList);
+ if (valList) {
+ for (size_t i = 0; i < valCount; ++i) {
+ valList[i] = CefTranslatorTestScopedLibraryCToCpp::UnwrapRaw(val[i]);
+ }
+ }
+ }
+
+ // Execute
+ int _retval =
+ _struct->set_raw_ptr_library_list(_struct, valCount, valList, val1, val2);
+
+ // Restore param:val; type: rawptr_vec_same_byref_const
+ if (valList) {
+ delete[] valList;
+ }
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+int CefTranslatorTestCToCpp::SetRawPtrClient(
+ CefRawPtr<CefTranslatorTestScopedClient> val) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_raw_ptr_client)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: val; type: rawptr_diff
+ DCHECK(val);
+ if (!val) {
+ return 0;
+ }
+
+ // Translate param: val; type: rawptr_diff
+ CefOwnPtr<CefTranslatorTestScopedClientCppToC> valPtr(
+ CefTranslatorTestScopedClientCppToC::WrapRaw(val));
+
+ // Execute
+ int _retval = _struct->set_raw_ptr_client(_struct, valPtr->GetStruct());
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+int CefTranslatorTestCToCpp::SetChildRawPtrClient(
+ CefRawPtr<CefTranslatorTestScopedClientChild> val) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_child_raw_ptr_client)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: val; type: rawptr_diff
+ DCHECK(val);
+ if (!val) {
+ return 0;
+ }
+
+ // Translate param: val; type: rawptr_diff
+ CefOwnPtr<CefTranslatorTestScopedClientChildCppToC> valPtr(
+ CefTranslatorTestScopedClientChildCppToC::WrapRaw(val));
+
+ // Execute
+ int _retval = _struct->set_child_raw_ptr_client(_struct, valPtr->GetStruct());
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefTranslatorTestCToCpp::SetRawPtrClientList(
+ const std::vector<CefRawPtr<CefTranslatorTestScopedClient>>& val,
+ int val1,
+ int val2) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_raw_ptr_client_list)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Translate param: val; type: rawptr_vec_diff_byref_const
+ const size_t valCount = val.size();
+ cef_translator_test_scoped_client_t** valList = NULL;
+ if (valCount > 0) {
+ valList = new cef_translator_test_scoped_client_t*[valCount];
+ DCHECK(valList);
+ if (valList) {
+ for (size_t i = 0; i < valCount; ++i) {
+ valList[i] = CefTranslatorTestScopedClientCppToC::WrapRaw(val[i])
+ .release()
+ ->GetStruct();
+ }
+ }
+ }
+
+ // Execute
+ int _retval =
+ _struct->set_raw_ptr_client_list(_struct, valCount, valList, val1, val2);
+
+ // Restore param:val; type: rawptr_vec_diff_byref_const
+ if (valCount > 0) {
+ for (size_t i = 0; i < valCount; ++i) {
+ delete CefTranslatorTestScopedClientCppToC::GetWrapper(valList[i]);
+ }
+ }
+ if (valList) {
+ delete[] valList;
+ }
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefTranslatorTestCToCpp::CefTranslatorTestCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefTranslatorTestCToCpp::~CefTranslatorTestCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_translator_test_t* CefCToCppRefCounted<
+ CefTranslatorTestCToCpp,
+ CefTranslatorTest,
+ cef_translator_test_t>::UnwrapDerived(CefWrapperType type,
+ CefTranslatorTest* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefTranslatorTestCToCpp,
+ CefTranslatorTest,
+ cef_translator_test_t>::kWrapperType =
+ WT_TRANSLATOR_TEST;
diff --git a/libcef_dll/ctocpp/test/translator_test_ctocpp.h b/libcef_dll/ctocpp/test/translator_test_ctocpp.h
new file mode 100644
index 00000000..8384cefe
--- /dev/null
+++ b/libcef_dll/ctocpp/test/translator_test_ctocpp.h
@@ -0,0 +1,136 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=915917340262b6243b06022fe96cc1e96625cac9$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_TEST_TRANSLATOR_TEST_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_TEST_TRANSLATOR_TEST_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include <map>
+#include <vector>
+#include "include/capi/test/cef_translator_test_capi.h"
+#include "include/test/cef_translator_test.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefTranslatorTestCToCpp
+ : public CefCToCppRefCounted<CefTranslatorTestCToCpp,
+ CefTranslatorTest,
+ cef_translator_test_t> {
+ public:
+ CefTranslatorTestCToCpp();
+ virtual ~CefTranslatorTestCToCpp();
+
+ // CefTranslatorTest methods.
+ void GetVoid() override;
+ bool GetBool() override;
+ int GetInt() override;
+ double GetDouble() override;
+ long GetLong() override;
+ size_t GetSizet() override;
+ bool SetVoid() override;
+ bool SetBool(bool val) override;
+ bool SetInt(int val) override;
+ bool SetDouble(double val) override;
+ bool SetLong(long val) override;
+ bool SetSizet(size_t val) override;
+ bool SetIntList(const std::vector<int>& val) override;
+ bool GetIntListByRef(IntList& val) override;
+ size_t GetIntListSize() override;
+ CefString GetString() override;
+ bool SetString(const CefString& val) override;
+ void GetStringByRef(CefString& val) override;
+ bool SetStringList(const std::vector<CefString>& val) override;
+ bool GetStringListByRef(StringList& val) override;
+ bool SetStringMap(const StringMap& val) override;
+ bool GetStringMapByRef(std::map<CefString, CefString>& val) override;
+ bool SetStringMultimap(
+ const std::multimap<CefString, CefString>& val) override;
+ bool GetStringMultimapByRef(StringMultimap& val) override;
+ CefPoint GetPoint() override;
+ bool SetPoint(const CefPoint& val) override;
+ void GetPointByRef(CefPoint& val) override;
+ bool SetPointList(const std::vector<CefPoint>& val) override;
+ bool GetPointListByRef(PointList& val) override;
+ size_t GetPointListSize() override;
+ CefRefPtr<CefTranslatorTestRefPtrLibrary> GetRefPtrLibrary(int val) override;
+ int SetRefPtrLibrary(CefRefPtr<CefTranslatorTestRefPtrLibrary> val) override;
+ CefRefPtr<CefTranslatorTestRefPtrLibrary> SetRefPtrLibraryAndReturn(
+ CefRefPtr<CefTranslatorTestRefPtrLibrary> val) override;
+ int SetChildRefPtrLibrary(
+ CefRefPtr<CefTranslatorTestRefPtrLibraryChild> val) override;
+ CefRefPtr<CefTranslatorTestRefPtrLibrary>
+ SetChildRefPtrLibraryAndReturnParent(
+ CefRefPtr<CefTranslatorTestRefPtrLibraryChild> val) override;
+ bool SetRefPtrLibraryList(
+ const std::vector<CefRefPtr<CefTranslatorTestRefPtrLibrary>>& val,
+ int val1,
+ int val2) override;
+ bool GetRefPtrLibraryListByRef(RefPtrLibraryList& val,
+ int val1,
+ int val2) override;
+ size_t GetRefPtrLibraryListSize() override;
+ int SetRefPtrClient(CefRefPtr<CefTranslatorTestRefPtrClient> val) override;
+ CefRefPtr<CefTranslatorTestRefPtrClient> SetRefPtrClientAndReturn(
+ CefRefPtr<CefTranslatorTestRefPtrClient> val) override;
+ int SetChildRefPtrClient(
+ CefRefPtr<CefTranslatorTestRefPtrClientChild> val) override;
+ CefRefPtr<CefTranslatorTestRefPtrClient> SetChildRefPtrClientAndReturnParent(
+ CefRefPtr<CefTranslatorTestRefPtrClientChild> val) override;
+ bool SetRefPtrClientList(
+ const std::vector<CefRefPtr<CefTranslatorTestRefPtrClient>>& val,
+ int val1,
+ int val2) override;
+ bool GetRefPtrClientListByRef(
+ RefPtrClientList& val,
+ CefRefPtr<CefTranslatorTestRefPtrClient> val1,
+ CefRefPtr<CefTranslatorTestRefPtrClient> val2) override;
+ size_t GetRefPtrClientListSize() override;
+ CefOwnPtr<CefTranslatorTestScopedLibrary> GetOwnPtrLibrary(int val) override;
+ int SetOwnPtrLibrary(CefOwnPtr<CefTranslatorTestScopedLibrary> val) override;
+ CefOwnPtr<CefTranslatorTestScopedLibrary> SetOwnPtrLibraryAndReturn(
+ CefOwnPtr<CefTranslatorTestScopedLibrary> val) override;
+ int SetChildOwnPtrLibrary(
+ CefOwnPtr<CefTranslatorTestScopedLibraryChild> val) override;
+ CefOwnPtr<CefTranslatorTestScopedLibrary>
+ SetChildOwnPtrLibraryAndReturnParent(
+ CefOwnPtr<CefTranslatorTestScopedLibraryChild> val) override;
+ int SetOwnPtrClient(CefOwnPtr<CefTranslatorTestScopedClient> val) override;
+ CefOwnPtr<CefTranslatorTestScopedClient> SetOwnPtrClientAndReturn(
+ CefOwnPtr<CefTranslatorTestScopedClient> val) override;
+ int SetChildOwnPtrClient(
+ CefOwnPtr<CefTranslatorTestScopedClientChild> val) override;
+ CefOwnPtr<CefTranslatorTestScopedClient> SetChildOwnPtrClientAndReturnParent(
+ CefOwnPtr<CefTranslatorTestScopedClientChild> val) override;
+ int SetRawPtrLibrary(CefRawPtr<CefTranslatorTestScopedLibrary> val) override;
+ int SetChildRawPtrLibrary(
+ CefRawPtr<CefTranslatorTestScopedLibraryChild> val) override;
+ bool SetRawPtrLibraryList(
+ const std::vector<CefRawPtr<CefTranslatorTestScopedLibrary>>& val,
+ int val1,
+ int val2) override;
+ int SetRawPtrClient(CefRawPtr<CefTranslatorTestScopedClient> val) override;
+ int SetChildRawPtrClient(
+ CefRawPtr<CefTranslatorTestScopedClientChild> val) override;
+ bool SetRawPtrClientList(
+ const std::vector<CefRawPtr<CefTranslatorTestScopedClient>>& val,
+ int val1,
+ int val2) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_TEST_TRANSLATOR_TEST_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/test/translator_test_ref_ptr_client_child_ctocpp.cc b/libcef_dll/ctocpp/test/translator_test_ref_ptr_client_child_ctocpp.cc
new file mode 100644
index 00000000..776db860
--- /dev/null
+++ b/libcef_dll/ctocpp/test/translator_test_ref_ptr_client_child_ctocpp.cc
@@ -0,0 +1,84 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=5f0147c0fd3225a764d914be4cfbe05f3145f59a$
+//
+
+#include "libcef_dll/ctocpp/test/translator_test_ref_ptr_client_child_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+int CefTranslatorTestRefPtrClientChildCToCpp::GetOtherValue() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_ref_ptr_client_child_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_other_value)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_other_value(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+int CefTranslatorTestRefPtrClientChildCToCpp::GetValue() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_ref_ptr_client_t* _struct =
+ reinterpret_cast<cef_translator_test_ref_ptr_client_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_value)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_value(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefTranslatorTestRefPtrClientChildCToCpp::
+ CefTranslatorTestRefPtrClientChildCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefTranslatorTestRefPtrClientChildCToCpp::
+ ~CefTranslatorTestRefPtrClientChildCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_translator_test_ref_ptr_client_child_t*
+CefCToCppRefCounted<CefTranslatorTestRefPtrClientChildCToCpp,
+ CefTranslatorTestRefPtrClientChild,
+ cef_translator_test_ref_ptr_client_child_t>::
+ UnwrapDerived(CefWrapperType type, CefTranslatorTestRefPtrClientChild* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<
+ CefTranslatorTestRefPtrClientChildCToCpp,
+ CefTranslatorTestRefPtrClientChild,
+ cef_translator_test_ref_ptr_client_child_t>::kWrapperType =
+ WT_TRANSLATOR_TEST_REF_PTR_CLIENT_CHILD;
diff --git a/libcef_dll/ctocpp/test/translator_test_ref_ptr_client_child_ctocpp.h b/libcef_dll/ctocpp/test/translator_test_ref_ptr_client_child_ctocpp.h
new file mode 100644
index 00000000..d59c50cf
--- /dev/null
+++ b/libcef_dll/ctocpp/test/translator_test_ref_ptr_client_child_ctocpp.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=971a30d8a2814ecdddb08763016621ce94b9da92$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_TEST_TRANSLATOR_TEST_REF_PTR_CLIENT_CHILD_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_TEST_TRANSLATOR_TEST_REF_PTR_CLIENT_CHILD_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/test/cef_translator_test_capi.h"
+#include "include/test/cef_translator_test.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefTranslatorTestRefPtrClientChildCToCpp
+ : public CefCToCppRefCounted<CefTranslatorTestRefPtrClientChildCToCpp,
+ CefTranslatorTestRefPtrClientChild,
+ cef_translator_test_ref_ptr_client_child_t> {
+ public:
+ CefTranslatorTestRefPtrClientChildCToCpp();
+ virtual ~CefTranslatorTestRefPtrClientChildCToCpp();
+
+ // CefTranslatorTestRefPtrClientChild methods.
+ int GetOtherValue() override;
+
+ // CefTranslatorTestRefPtrClient methods.
+ int GetValue() override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_TEST_TRANSLATOR_TEST_REF_PTR_CLIENT_CHILD_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/test/translator_test_ref_ptr_client_ctocpp.cc b/libcef_dll/ctocpp/test/translator_test_ref_ptr_client_ctocpp.cc
new file mode 100644
index 00000000..898e674e
--- /dev/null
+++ b/libcef_dll/ctocpp/test/translator_test_ref_ptr_client_ctocpp.cc
@@ -0,0 +1,68 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=8466641105f3c19fce94947eff086aeb1ccc526b$
+//
+
+#include "libcef_dll/ctocpp/test/translator_test_ref_ptr_client_ctocpp.h"
+#include "libcef_dll/ctocpp/test/translator_test_ref_ptr_client_child_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") int CefTranslatorTestRefPtrClientCToCpp::GetValue() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_ref_ptr_client_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_value)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_value(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefTranslatorTestRefPtrClientCToCpp::CefTranslatorTestRefPtrClientCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefTranslatorTestRefPtrClientCToCpp::~CefTranslatorTestRefPtrClientCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_translator_test_ref_ptr_client_t*
+CefCToCppRefCounted<CefTranslatorTestRefPtrClientCToCpp,
+ CefTranslatorTestRefPtrClient,
+ cef_translator_test_ref_ptr_client_t>::
+ UnwrapDerived(CefWrapperType type, CefTranslatorTestRefPtrClient* c) {
+ if (type == WT_TRANSLATOR_TEST_REF_PTR_CLIENT_CHILD) {
+ return reinterpret_cast<cef_translator_test_ref_ptr_client_t*>(
+ CefTranslatorTestRefPtrClientChildCToCpp::Unwrap(
+ reinterpret_cast<CefTranslatorTestRefPtrClientChild*>(c)));
+ }
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCToCppRefCounted<CefTranslatorTestRefPtrClientCToCpp,
+ CefTranslatorTestRefPtrClient,
+ cef_translator_test_ref_ptr_client_t>::kWrapperType =
+ WT_TRANSLATOR_TEST_REF_PTR_CLIENT;
diff --git a/libcef_dll/ctocpp/test/translator_test_ref_ptr_client_ctocpp.h b/libcef_dll/ctocpp/test/translator_test_ref_ptr_client_ctocpp.h
new file mode 100644
index 00000000..968847f2
--- /dev/null
+++ b/libcef_dll/ctocpp/test/translator_test_ref_ptr_client_ctocpp.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=a083f0198c6c93ee0fccdb262dce8dc567abbf9c$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_TEST_TRANSLATOR_TEST_REF_PTR_CLIENT_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_TEST_TRANSLATOR_TEST_REF_PTR_CLIENT_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/test/cef_translator_test_capi.h"
+#include "include/test/cef_translator_test.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefTranslatorTestRefPtrClientCToCpp
+ : public CefCToCppRefCounted<CefTranslatorTestRefPtrClientCToCpp,
+ CefTranslatorTestRefPtrClient,
+ cef_translator_test_ref_ptr_client_t> {
+ public:
+ CefTranslatorTestRefPtrClientCToCpp();
+ virtual ~CefTranslatorTestRefPtrClientCToCpp();
+
+ // CefTranslatorTestRefPtrClient methods.
+ int GetValue() override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_TEST_TRANSLATOR_TEST_REF_PTR_CLIENT_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/test/translator_test_ref_ptr_library_child_child_ctocpp.cc b/libcef_dll/ctocpp/test/translator_test_ref_ptr_library_child_child_ctocpp.cc
new file mode 100644
index 00000000..420f7192
--- /dev/null
+++ b/libcef_dll/ctocpp/test/translator_test_ref_ptr_library_child_child_ctocpp.cc
@@ -0,0 +1,174 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=cc5546fc8b0b06121d59d367472b7d42f25f12f3$
+//
+
+#include "libcef_dll/ctocpp/test/translator_test_ref_ptr_library_child_child_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// STATIC METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefTranslatorTestRefPtrLibraryChildChild>
+CefTranslatorTestRefPtrLibraryChildChild::Create(int value,
+ int other_value,
+ int other_other_value) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_translator_test_ref_ptr_library_child_child_t* _retval =
+ cef_translator_test_ref_ptr_library_child_child_create(value, other_value,
+ other_other_value);
+
+ // Return type: refptr_same
+ return CefTranslatorTestRefPtrLibraryChildChildCToCpp::Wrap(_retval);
+}
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+int CefTranslatorTestRefPtrLibraryChildChildCToCpp::GetOtherOtherValue() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_ref_ptr_library_child_child_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_other_other_value)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_other_other_value(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefTranslatorTestRefPtrLibraryChildChildCToCpp::SetOtherOtherValue(
+ int value) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_ref_ptr_library_child_child_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_other_other_value)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_other_other_value(_struct, value);
+}
+
+NO_SANITIZE("cfi-icall")
+int CefTranslatorTestRefPtrLibraryChildChildCToCpp::GetOtherValue() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_ref_ptr_library_child_t* _struct =
+ reinterpret_cast<cef_translator_test_ref_ptr_library_child_t*>(
+ GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_other_value)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_other_value(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefTranslatorTestRefPtrLibraryChildChildCToCpp::SetOtherValue(int value) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_ref_ptr_library_child_t* _struct =
+ reinterpret_cast<cef_translator_test_ref_ptr_library_child_t*>(
+ GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_other_value)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_other_value(_struct, value);
+}
+
+NO_SANITIZE("cfi-icall")
+int CefTranslatorTestRefPtrLibraryChildChildCToCpp::GetValue() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_ref_ptr_library_t* _struct =
+ reinterpret_cast<cef_translator_test_ref_ptr_library_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_value)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_value(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefTranslatorTestRefPtrLibraryChildChildCToCpp::SetValue(int value) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_ref_ptr_library_t* _struct =
+ reinterpret_cast<cef_translator_test_ref_ptr_library_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_value)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_value(_struct, value);
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefTranslatorTestRefPtrLibraryChildChildCToCpp::
+ CefTranslatorTestRefPtrLibraryChildChildCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefTranslatorTestRefPtrLibraryChildChildCToCpp::
+ ~CefTranslatorTestRefPtrLibraryChildChildCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_translator_test_ref_ptr_library_child_child_t*
+CefCToCppRefCounted<CefTranslatorTestRefPtrLibraryChildChildCToCpp,
+ CefTranslatorTestRefPtrLibraryChildChild,
+ cef_translator_test_ref_ptr_library_child_child_t>::
+ UnwrapDerived(CefWrapperType type,
+ CefTranslatorTestRefPtrLibraryChildChild* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<
+ CefTranslatorTestRefPtrLibraryChildChildCToCpp,
+ CefTranslatorTestRefPtrLibraryChildChild,
+ cef_translator_test_ref_ptr_library_child_child_t>::kWrapperType =
+ WT_TRANSLATOR_TEST_REF_PTR_LIBRARY_CHILD_CHILD;
diff --git a/libcef_dll/ctocpp/test/translator_test_ref_ptr_library_child_child_ctocpp.h b/libcef_dll/ctocpp/test/translator_test_ref_ptr_library_child_child_ctocpp.h
new file mode 100644
index 00000000..f6a503a2
--- /dev/null
+++ b/libcef_dll/ctocpp/test/translator_test_ref_ptr_library_child_child_ctocpp.h
@@ -0,0 +1,51 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=49af27e043172c178c3ef4f37805069e6af739e6$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_TEST_TRANSLATOR_TEST_REF_PTR_LIBRARY_CHILD_CHILD_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_TEST_TRANSLATOR_TEST_REF_PTR_LIBRARY_CHILD_CHILD_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/test/cef_translator_test_capi.h"
+#include "include/test/cef_translator_test.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefTranslatorTestRefPtrLibraryChildChildCToCpp
+ : public CefCToCppRefCounted<
+ CefTranslatorTestRefPtrLibraryChildChildCToCpp,
+ CefTranslatorTestRefPtrLibraryChildChild,
+ cef_translator_test_ref_ptr_library_child_child_t> {
+ public:
+ CefTranslatorTestRefPtrLibraryChildChildCToCpp();
+ virtual ~CefTranslatorTestRefPtrLibraryChildChildCToCpp();
+
+ // CefTranslatorTestRefPtrLibraryChildChild methods.
+ int GetOtherOtherValue() override;
+ void SetOtherOtherValue(int value) override;
+
+ // CefTranslatorTestRefPtrLibraryChild methods.
+ int GetOtherValue() override;
+ void SetOtherValue(int value) override;
+
+ // CefTranslatorTestRefPtrLibrary methods.
+ int GetValue() override;
+ void SetValue(int value) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_TEST_TRANSLATOR_TEST_REF_PTR_LIBRARY_CHILD_CHILD_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/test/translator_test_ref_ptr_library_child_ctocpp.cc b/libcef_dll/ctocpp/test/translator_test_ref_ptr_library_child_ctocpp.cc
new file mode 100644
index 00000000..5074691b
--- /dev/null
+++ b/libcef_dll/ctocpp/test/translator_test_ref_ptr_library_child_ctocpp.cc
@@ -0,0 +1,138 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=8a2d1836475451990a27eb757fc9396fe249daf0$
+//
+
+#include "libcef_dll/ctocpp/test/translator_test_ref_ptr_library_child_ctocpp.h"
+#include "libcef_dll/ctocpp/test/translator_test_ref_ptr_library_child_child_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// STATIC METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefTranslatorTestRefPtrLibraryChild>
+CefTranslatorTestRefPtrLibraryChild::Create(int value, int other_value) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_translator_test_ref_ptr_library_child_t* _retval =
+ cef_translator_test_ref_ptr_library_child_create(value, other_value);
+
+ // Return type: refptr_same
+ return CefTranslatorTestRefPtrLibraryChildCToCpp::Wrap(_retval);
+}
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+int CefTranslatorTestRefPtrLibraryChildCToCpp::GetOtherValue() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_ref_ptr_library_child_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_other_value)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_other_value(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefTranslatorTestRefPtrLibraryChildCToCpp::SetOtherValue(int value) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_ref_ptr_library_child_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_other_value)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_other_value(_struct, value);
+}
+
+NO_SANITIZE("cfi-icall")
+int CefTranslatorTestRefPtrLibraryChildCToCpp::GetValue() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_ref_ptr_library_t* _struct =
+ reinterpret_cast<cef_translator_test_ref_ptr_library_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_value)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_value(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefTranslatorTestRefPtrLibraryChildCToCpp::SetValue(int value) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_ref_ptr_library_t* _struct =
+ reinterpret_cast<cef_translator_test_ref_ptr_library_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_value)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_value(_struct, value);
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefTranslatorTestRefPtrLibraryChildCToCpp::
+ CefTranslatorTestRefPtrLibraryChildCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefTranslatorTestRefPtrLibraryChildCToCpp::
+ ~CefTranslatorTestRefPtrLibraryChildCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_translator_test_ref_ptr_library_child_t*
+CefCToCppRefCounted<CefTranslatorTestRefPtrLibraryChildCToCpp,
+ CefTranslatorTestRefPtrLibraryChild,
+ cef_translator_test_ref_ptr_library_child_t>::
+ UnwrapDerived(CefWrapperType type, CefTranslatorTestRefPtrLibraryChild* c) {
+ if (type == WT_TRANSLATOR_TEST_REF_PTR_LIBRARY_CHILD_CHILD) {
+ return reinterpret_cast<cef_translator_test_ref_ptr_library_child_t*>(
+ CefTranslatorTestRefPtrLibraryChildChildCToCpp::Unwrap(
+ reinterpret_cast<CefTranslatorTestRefPtrLibraryChildChild*>(c)));
+ }
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<
+ CefTranslatorTestRefPtrLibraryChildCToCpp,
+ CefTranslatorTestRefPtrLibraryChild,
+ cef_translator_test_ref_ptr_library_child_t>::kWrapperType =
+ WT_TRANSLATOR_TEST_REF_PTR_LIBRARY_CHILD;
diff --git a/libcef_dll/ctocpp/test/translator_test_ref_ptr_library_child_ctocpp.h b/libcef_dll/ctocpp/test/translator_test_ref_ptr_library_child_ctocpp.h
new file mode 100644
index 00000000..a5e5b711
--- /dev/null
+++ b/libcef_dll/ctocpp/test/translator_test_ref_ptr_library_child_ctocpp.h
@@ -0,0 +1,46 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=ef77c876031b14fdee487305c5cfded6a9cb910f$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_TEST_TRANSLATOR_TEST_REF_PTR_LIBRARY_CHILD_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_TEST_TRANSLATOR_TEST_REF_PTR_LIBRARY_CHILD_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/test/cef_translator_test_capi.h"
+#include "include/test/cef_translator_test.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefTranslatorTestRefPtrLibraryChildCToCpp
+ : public CefCToCppRefCounted<CefTranslatorTestRefPtrLibraryChildCToCpp,
+ CefTranslatorTestRefPtrLibraryChild,
+ cef_translator_test_ref_ptr_library_child_t> {
+ public:
+ CefTranslatorTestRefPtrLibraryChildCToCpp();
+ virtual ~CefTranslatorTestRefPtrLibraryChildCToCpp();
+
+ // CefTranslatorTestRefPtrLibraryChild methods.
+ int GetOtherValue() override;
+ void SetOtherValue(int value) override;
+
+ // CefTranslatorTestRefPtrLibrary methods.
+ int GetValue() override;
+ void SetValue(int value) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_TEST_TRANSLATOR_TEST_REF_PTR_LIBRARY_CHILD_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/test/translator_test_ref_ptr_library_ctocpp.cc b/libcef_dll/ctocpp/test/translator_test_ref_ptr_library_ctocpp.cc
new file mode 100644
index 00000000..98e11d29
--- /dev/null
+++ b/libcef_dll/ctocpp/test/translator_test_ref_ptr_library_ctocpp.cc
@@ -0,0 +1,106 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=b921e7e7ea0d88e5d0cd2f8e7f089926c8b1f1b6$
+//
+
+#include "libcef_dll/ctocpp/test/translator_test_ref_ptr_library_ctocpp.h"
+#include "libcef_dll/ctocpp/test/translator_test_ref_ptr_library_child_child_ctocpp.h"
+#include "libcef_dll/ctocpp/test/translator_test_ref_ptr_library_child_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// STATIC METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefTranslatorTestRefPtrLibrary>
+CefTranslatorTestRefPtrLibrary::Create(int value) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_translator_test_ref_ptr_library_t* _retval =
+ cef_translator_test_ref_ptr_library_create(value);
+
+ // Return type: refptr_same
+ return CefTranslatorTestRefPtrLibraryCToCpp::Wrap(_retval);
+}
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") int CefTranslatorTestRefPtrLibraryCToCpp::GetValue() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_ref_ptr_library_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_value)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_value(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefTranslatorTestRefPtrLibraryCToCpp::SetValue(int value) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_translator_test_ref_ptr_library_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_value)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_value(_struct, value);
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefTranslatorTestRefPtrLibraryCToCpp::CefTranslatorTestRefPtrLibraryCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefTranslatorTestRefPtrLibraryCToCpp::~CefTranslatorTestRefPtrLibraryCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_translator_test_ref_ptr_library_t*
+CefCToCppRefCounted<CefTranslatorTestRefPtrLibraryCToCpp,
+ CefTranslatorTestRefPtrLibrary,
+ cef_translator_test_ref_ptr_library_t>::
+ UnwrapDerived(CefWrapperType type, CefTranslatorTestRefPtrLibrary* c) {
+ if (type == WT_TRANSLATOR_TEST_REF_PTR_LIBRARY_CHILD) {
+ return reinterpret_cast<cef_translator_test_ref_ptr_library_t*>(
+ CefTranslatorTestRefPtrLibraryChildCToCpp::Unwrap(
+ reinterpret_cast<CefTranslatorTestRefPtrLibraryChild*>(c)));
+ }
+ if (type == WT_TRANSLATOR_TEST_REF_PTR_LIBRARY_CHILD_CHILD) {
+ return reinterpret_cast<cef_translator_test_ref_ptr_library_t*>(
+ CefTranslatorTestRefPtrLibraryChildChildCToCpp::Unwrap(
+ reinterpret_cast<CefTranslatorTestRefPtrLibraryChildChild*>(c)));
+ }
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCToCppRefCounted<CefTranslatorTestRefPtrLibraryCToCpp,
+ CefTranslatorTestRefPtrLibrary,
+ cef_translator_test_ref_ptr_library_t>::kWrapperType =
+ WT_TRANSLATOR_TEST_REF_PTR_LIBRARY;
diff --git a/libcef_dll/ctocpp/test/translator_test_ref_ptr_library_ctocpp.h b/libcef_dll/ctocpp/test/translator_test_ref_ptr_library_ctocpp.h
new file mode 100644
index 00000000..94ff9da7
--- /dev/null
+++ b/libcef_dll/ctocpp/test/translator_test_ref_ptr_library_ctocpp.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=9fa8897ee5081b7cd95a6cb791fb69871f61406e$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_TEST_TRANSLATOR_TEST_REF_PTR_LIBRARY_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_TEST_TRANSLATOR_TEST_REF_PTR_LIBRARY_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/test/cef_translator_test_capi.h"
+#include "include/test/cef_translator_test.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefTranslatorTestRefPtrLibraryCToCpp
+ : public CefCToCppRefCounted<CefTranslatorTestRefPtrLibraryCToCpp,
+ CefTranslatorTestRefPtrLibrary,
+ cef_translator_test_ref_ptr_library_t> {
+ public:
+ CefTranslatorTestRefPtrLibraryCToCpp();
+ virtual ~CefTranslatorTestRefPtrLibraryCToCpp();
+
+ // CefTranslatorTestRefPtrLibrary methods.
+ int GetValue() override;
+ void SetValue(int value) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_TEST_TRANSLATOR_TEST_REF_PTR_LIBRARY_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/test/translator_test_scoped_client_child_ctocpp.cc b/libcef_dll/ctocpp/test/translator_test_scoped_client_child_ctocpp.cc
new file mode 100644
index 00000000..7e628838
--- /dev/null
+++ b/libcef_dll/ctocpp/test/translator_test_scoped_client_child_ctocpp.cc
@@ -0,0 +1,89 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=cdb4ca04fa51dad19a502395e551f155d7f7670e$
+//
+
+#include "libcef_dll/ctocpp/test/translator_test_scoped_client_child_ctocpp.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+int CefTranslatorTestScopedClientChildCToCpp::GetOtherValue() {
+ cef_translator_test_scoped_client_child_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_other_value)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_other_value(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+int CefTranslatorTestScopedClientChildCToCpp::GetValue() {
+ cef_translator_test_scoped_client_t* _struct =
+ reinterpret_cast<cef_translator_test_scoped_client_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_value)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_value(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefTranslatorTestScopedClientChildCToCpp::
+ CefTranslatorTestScopedClientChildCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefTranslatorTestScopedClientChildCToCpp::
+ ~CefTranslatorTestScopedClientChildCToCpp() {}
+
+template <>
+cef_translator_test_scoped_client_child_t*
+CefCToCppScoped<CefTranslatorTestScopedClientChildCToCpp,
+ CefTranslatorTestScopedClientChild,
+ cef_translator_test_scoped_client_child_t>::
+ UnwrapDerivedOwn(CefWrapperType type,
+ CefOwnPtr<CefTranslatorTestScopedClientChild> c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+cef_translator_test_scoped_client_child_t*
+CefCToCppScoped<CefTranslatorTestScopedClientChildCToCpp,
+ CefTranslatorTestScopedClientChild,
+ cef_translator_test_scoped_client_child_t>::
+ UnwrapDerivedRaw(CefWrapperType type,
+ CefRawPtr<CefTranslatorTestScopedClientChild> c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCToCppScoped<CefTranslatorTestScopedClientChildCToCpp,
+ CefTranslatorTestScopedClientChild,
+ cef_translator_test_scoped_client_child_t>::kWrapperType =
+ WT_TRANSLATOR_TEST_SCOPED_CLIENT_CHILD;
diff --git a/libcef_dll/ctocpp/test/translator_test_scoped_client_child_ctocpp.h b/libcef_dll/ctocpp/test/translator_test_scoped_client_child_ctocpp.h
new file mode 100644
index 00000000..36339c17
--- /dev/null
+++ b/libcef_dll/ctocpp/test/translator_test_scoped_client_child_ctocpp.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=ec4bff6137c66581b34dc2ef11beb02276de163a$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_TEST_TRANSLATOR_TEST_SCOPED_CLIENT_CHILD_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_TEST_TRANSLATOR_TEST_SCOPED_CLIENT_CHILD_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/test/cef_translator_test_capi.h"
+#include "include/test/cef_translator_test.h"
+#include "libcef_dll/ctocpp/ctocpp_scoped.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefTranslatorTestScopedClientChildCToCpp
+ : public CefCToCppScoped<CefTranslatorTestScopedClientChildCToCpp,
+ CefTranslatorTestScopedClientChild,
+ cef_translator_test_scoped_client_child_t> {
+ public:
+ CefTranslatorTestScopedClientChildCToCpp();
+ virtual ~CefTranslatorTestScopedClientChildCToCpp();
+
+ // CefTranslatorTestScopedClientChild methods.
+ int GetOtherValue() override;
+
+ // CefTranslatorTestScopedClient methods.
+ int GetValue() override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_TEST_TRANSLATOR_TEST_SCOPED_CLIENT_CHILD_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/test/translator_test_scoped_client_ctocpp.cc b/libcef_dll/ctocpp/test/translator_test_scoped_client_ctocpp.cc
new file mode 100644
index 00000000..66a48597
--- /dev/null
+++ b/libcef_dll/ctocpp/test/translator_test_scoped_client_ctocpp.cc
@@ -0,0 +1,83 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=d16a979d1fd6b2e58a40bd49da0071e03c7b1b13$
+//
+
+#include "libcef_dll/ctocpp/test/translator_test_scoped_client_ctocpp.h"
+#include "libcef_dll/ctocpp/test/translator_test_scoped_client_child_ctocpp.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") int CefTranslatorTestScopedClientCToCpp::GetValue() {
+ cef_translator_test_scoped_client_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_value)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_value(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefTranslatorTestScopedClientCToCpp::CefTranslatorTestScopedClientCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefTranslatorTestScopedClientCToCpp::~CefTranslatorTestScopedClientCToCpp() {}
+
+template <>
+cef_translator_test_scoped_client_t*
+CefCToCppScoped<CefTranslatorTestScopedClientCToCpp,
+ CefTranslatorTestScopedClient,
+ cef_translator_test_scoped_client_t>::
+ UnwrapDerivedOwn(CefWrapperType type,
+ CefOwnPtr<CefTranslatorTestScopedClient> c) {
+ if (type == WT_TRANSLATOR_TEST_SCOPED_CLIENT_CHILD) {
+ return reinterpret_cast<cef_translator_test_scoped_client_t*>(
+ CefTranslatorTestScopedClientChildCToCpp::UnwrapOwn(
+ CefOwnPtr<CefTranslatorTestScopedClientChild>(
+ reinterpret_cast<CefTranslatorTestScopedClientChild*>(
+ c.release()))));
+ }
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+cef_translator_test_scoped_client_t*
+CefCToCppScoped<CefTranslatorTestScopedClientCToCpp,
+ CefTranslatorTestScopedClient,
+ cef_translator_test_scoped_client_t>::
+ UnwrapDerivedRaw(CefWrapperType type,
+ CefRawPtr<CefTranslatorTestScopedClient> c) {
+ if (type == WT_TRANSLATOR_TEST_SCOPED_CLIENT_CHILD) {
+ return reinterpret_cast<cef_translator_test_scoped_client_t*>(
+ CefTranslatorTestScopedClientChildCToCpp::UnwrapRaw(
+ CefRawPtr<CefTranslatorTestScopedClientChild>(
+ reinterpret_cast<CefTranslatorTestScopedClientChild*>(c))));
+ }
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCToCppScoped<CefTranslatorTestScopedClientCToCpp,
+ CefTranslatorTestScopedClient,
+ cef_translator_test_scoped_client_t>::kWrapperType =
+ WT_TRANSLATOR_TEST_SCOPED_CLIENT;
diff --git a/libcef_dll/ctocpp/test/translator_test_scoped_client_ctocpp.h b/libcef_dll/ctocpp/test/translator_test_scoped_client_ctocpp.h
new file mode 100644
index 00000000..caeaf694
--- /dev/null
+++ b/libcef_dll/ctocpp/test/translator_test_scoped_client_ctocpp.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=d511f3a8273e4d9c6acff3d183b7bfa84e1385e3$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_TEST_TRANSLATOR_TEST_SCOPED_CLIENT_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_TEST_TRANSLATOR_TEST_SCOPED_CLIENT_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/test/cef_translator_test_capi.h"
+#include "include/test/cef_translator_test.h"
+#include "libcef_dll/ctocpp/ctocpp_scoped.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefTranslatorTestScopedClientCToCpp
+ : public CefCToCppScoped<CefTranslatorTestScopedClientCToCpp,
+ CefTranslatorTestScopedClient,
+ cef_translator_test_scoped_client_t> {
+ public:
+ CefTranslatorTestScopedClientCToCpp();
+ virtual ~CefTranslatorTestScopedClientCToCpp();
+
+ // CefTranslatorTestScopedClient methods.
+ int GetValue() override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_TEST_TRANSLATOR_TEST_SCOPED_CLIENT_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/test/translator_test_scoped_library_child_child_ctocpp.cc b/libcef_dll/ctocpp/test/translator_test_scoped_library_child_child_ctocpp.cc
new file mode 100644
index 00000000..99eb7297
--- /dev/null
+++ b/libcef_dll/ctocpp/test/translator_test_scoped_library_child_child_ctocpp.cc
@@ -0,0 +1,168 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=62c1f23411e35b3e4ec97748f4cb1c070d9ef763$
+//
+
+#include "libcef_dll/ctocpp/test/translator_test_scoped_library_child_child_ctocpp.h"
+
+// STATIC METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefOwnPtr<CefTranslatorTestScopedLibraryChildChild>
+CefTranslatorTestScopedLibraryChildChild::Create(int value,
+ int other_value,
+ int other_other_value) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_translator_test_scoped_library_child_child_t* _retval =
+ cef_translator_test_scoped_library_child_child_create(value, other_value,
+ other_other_value);
+
+ // Return type: ownptr_same
+ return CefTranslatorTestScopedLibraryChildChildCToCpp::Wrap(_retval);
+}
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+int CefTranslatorTestScopedLibraryChildChildCToCpp::GetOtherOtherValue() {
+ cef_translator_test_scoped_library_child_child_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_other_other_value)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_other_other_value(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefTranslatorTestScopedLibraryChildChildCToCpp::SetOtherOtherValue(
+ int value) {
+ cef_translator_test_scoped_library_child_child_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_other_other_value)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_other_other_value(_struct, value);
+}
+
+NO_SANITIZE("cfi-icall")
+int CefTranslatorTestScopedLibraryChildChildCToCpp::GetOtherValue() {
+ cef_translator_test_scoped_library_child_t* _struct =
+ reinterpret_cast<cef_translator_test_scoped_library_child_t*>(
+ GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_other_value)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_other_value(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefTranslatorTestScopedLibraryChildChildCToCpp::SetOtherValue(int value) {
+ cef_translator_test_scoped_library_child_t* _struct =
+ reinterpret_cast<cef_translator_test_scoped_library_child_t*>(
+ GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_other_value)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_other_value(_struct, value);
+}
+
+NO_SANITIZE("cfi-icall")
+int CefTranslatorTestScopedLibraryChildChildCToCpp::GetValue() {
+ cef_translator_test_scoped_library_t* _struct =
+ reinterpret_cast<cef_translator_test_scoped_library_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_value)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_value(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefTranslatorTestScopedLibraryChildChildCToCpp::SetValue(int value) {
+ cef_translator_test_scoped_library_t* _struct =
+ reinterpret_cast<cef_translator_test_scoped_library_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_value)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_value(_struct, value);
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefTranslatorTestScopedLibraryChildChildCToCpp::
+ CefTranslatorTestScopedLibraryChildChildCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefTranslatorTestScopedLibraryChildChildCToCpp::
+ ~CefTranslatorTestScopedLibraryChildChildCToCpp() {}
+
+template <>
+cef_translator_test_scoped_library_child_child_t*
+CefCToCppScoped<CefTranslatorTestScopedLibraryChildChildCToCpp,
+ CefTranslatorTestScopedLibraryChildChild,
+ cef_translator_test_scoped_library_child_child_t>::
+ UnwrapDerivedOwn(CefWrapperType type,
+ CefOwnPtr<CefTranslatorTestScopedLibraryChildChild> c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+cef_translator_test_scoped_library_child_child_t*
+CefCToCppScoped<CefTranslatorTestScopedLibraryChildChildCToCpp,
+ CefTranslatorTestScopedLibraryChildChild,
+ cef_translator_test_scoped_library_child_child_t>::
+ UnwrapDerivedRaw(CefWrapperType type,
+ CefRawPtr<CefTranslatorTestScopedLibraryChildChild> c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppScoped<
+ CefTranslatorTestScopedLibraryChildChildCToCpp,
+ CefTranslatorTestScopedLibraryChildChild,
+ cef_translator_test_scoped_library_child_child_t>::kWrapperType =
+ WT_TRANSLATOR_TEST_SCOPED_LIBRARY_CHILD_CHILD;
diff --git a/libcef_dll/ctocpp/test/translator_test_scoped_library_child_child_ctocpp.h b/libcef_dll/ctocpp/test/translator_test_scoped_library_child_child_ctocpp.h
new file mode 100644
index 00000000..8b3fd348
--- /dev/null
+++ b/libcef_dll/ctocpp/test/translator_test_scoped_library_child_child_ctocpp.h
@@ -0,0 +1,50 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=b6fc182f3444ce3926bff6d2b30d14aeca4cb9ba$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_TEST_TRANSLATOR_TEST_SCOPED_LIBRARY_CHILD_CHILD_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_TEST_TRANSLATOR_TEST_SCOPED_LIBRARY_CHILD_CHILD_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/test/cef_translator_test_capi.h"
+#include "include/test/cef_translator_test.h"
+#include "libcef_dll/ctocpp/ctocpp_scoped.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefTranslatorTestScopedLibraryChildChildCToCpp
+ : public CefCToCppScoped<CefTranslatorTestScopedLibraryChildChildCToCpp,
+ CefTranslatorTestScopedLibraryChildChild,
+ cef_translator_test_scoped_library_child_child_t> {
+ public:
+ CefTranslatorTestScopedLibraryChildChildCToCpp();
+ virtual ~CefTranslatorTestScopedLibraryChildChildCToCpp();
+
+ // CefTranslatorTestScopedLibraryChildChild methods.
+ int GetOtherOtherValue() override;
+ void SetOtherOtherValue(int value) override;
+
+ // CefTranslatorTestScopedLibraryChild methods.
+ int GetOtherValue() override;
+ void SetOtherValue(int value) override;
+
+ // CefTranslatorTestScopedLibrary methods.
+ int GetValue() override;
+ void SetValue(int value) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_TEST_TRANSLATOR_TEST_SCOPED_LIBRARY_CHILD_CHILD_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/test/translator_test_scoped_library_child_ctocpp.cc b/libcef_dll/ctocpp/test/translator_test_scoped_library_child_ctocpp.cc
new file mode 100644
index 00000000..e616f946
--- /dev/null
+++ b/libcef_dll/ctocpp/test/translator_test_scoped_library_child_ctocpp.cc
@@ -0,0 +1,146 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=ba28121d699be43841a82405922a22ef280bcaad$
+//
+
+#include "libcef_dll/ctocpp/test/translator_test_scoped_library_child_ctocpp.h"
+#include "libcef_dll/ctocpp/test/translator_test_scoped_library_child_child_ctocpp.h"
+
+// STATIC METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefOwnPtr<CefTranslatorTestScopedLibraryChild>
+CefTranslatorTestScopedLibraryChild::Create(int value, int other_value) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_translator_test_scoped_library_child_t* _retval =
+ cef_translator_test_scoped_library_child_create(value, other_value);
+
+ // Return type: ownptr_same
+ return CefTranslatorTestScopedLibraryChildCToCpp::Wrap(_retval);
+}
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+int CefTranslatorTestScopedLibraryChildCToCpp::GetOtherValue() {
+ cef_translator_test_scoped_library_child_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_other_value)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_other_value(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefTranslatorTestScopedLibraryChildCToCpp::SetOtherValue(int value) {
+ cef_translator_test_scoped_library_child_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_other_value)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_other_value(_struct, value);
+}
+
+NO_SANITIZE("cfi-icall")
+int CefTranslatorTestScopedLibraryChildCToCpp::GetValue() {
+ cef_translator_test_scoped_library_t* _struct =
+ reinterpret_cast<cef_translator_test_scoped_library_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_value)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_value(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefTranslatorTestScopedLibraryChildCToCpp::SetValue(int value) {
+ cef_translator_test_scoped_library_t* _struct =
+ reinterpret_cast<cef_translator_test_scoped_library_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_value)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_value(_struct, value);
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefTranslatorTestScopedLibraryChildCToCpp::
+ CefTranslatorTestScopedLibraryChildCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefTranslatorTestScopedLibraryChildCToCpp::
+ ~CefTranslatorTestScopedLibraryChildCToCpp() {}
+
+template <>
+cef_translator_test_scoped_library_child_t*
+CefCToCppScoped<CefTranslatorTestScopedLibraryChildCToCpp,
+ CefTranslatorTestScopedLibraryChild,
+ cef_translator_test_scoped_library_child_t>::
+ UnwrapDerivedOwn(CefWrapperType type,
+ CefOwnPtr<CefTranslatorTestScopedLibraryChild> c) {
+ if (type == WT_TRANSLATOR_TEST_SCOPED_LIBRARY_CHILD_CHILD) {
+ return reinterpret_cast<cef_translator_test_scoped_library_child_t*>(
+ CefTranslatorTestScopedLibraryChildChildCToCpp::UnwrapOwn(
+ CefOwnPtr<CefTranslatorTestScopedLibraryChildChild>(
+ reinterpret_cast<CefTranslatorTestScopedLibraryChildChild*>(
+ c.release()))));
+ }
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+cef_translator_test_scoped_library_child_t*
+CefCToCppScoped<CefTranslatorTestScopedLibraryChildCToCpp,
+ CefTranslatorTestScopedLibraryChild,
+ cef_translator_test_scoped_library_child_t>::
+ UnwrapDerivedRaw(CefWrapperType type,
+ CefRawPtr<CefTranslatorTestScopedLibraryChild> c) {
+ if (type == WT_TRANSLATOR_TEST_SCOPED_LIBRARY_CHILD_CHILD) {
+ return reinterpret_cast<cef_translator_test_scoped_library_child_t*>(
+ CefTranslatorTestScopedLibraryChildChildCToCpp::UnwrapRaw(
+ CefRawPtr<CefTranslatorTestScopedLibraryChildChild>(
+ reinterpret_cast<CefTranslatorTestScopedLibraryChildChild*>(
+ c))));
+ }
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCToCppScoped<CefTranslatorTestScopedLibraryChildCToCpp,
+ CefTranslatorTestScopedLibraryChild,
+ cef_translator_test_scoped_library_child_t>::kWrapperType =
+ WT_TRANSLATOR_TEST_SCOPED_LIBRARY_CHILD;
diff --git a/libcef_dll/ctocpp/test/translator_test_scoped_library_child_ctocpp.h b/libcef_dll/ctocpp/test/translator_test_scoped_library_child_ctocpp.h
new file mode 100644
index 00000000..e4ab2f9e
--- /dev/null
+++ b/libcef_dll/ctocpp/test/translator_test_scoped_library_child_ctocpp.h
@@ -0,0 +1,46 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=954fc390e3b474eedcf0bbb3df41e717c00449d3$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_TEST_TRANSLATOR_TEST_SCOPED_LIBRARY_CHILD_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_TEST_TRANSLATOR_TEST_SCOPED_LIBRARY_CHILD_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/test/cef_translator_test_capi.h"
+#include "include/test/cef_translator_test.h"
+#include "libcef_dll/ctocpp/ctocpp_scoped.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefTranslatorTestScopedLibraryChildCToCpp
+ : public CefCToCppScoped<CefTranslatorTestScopedLibraryChildCToCpp,
+ CefTranslatorTestScopedLibraryChild,
+ cef_translator_test_scoped_library_child_t> {
+ public:
+ CefTranslatorTestScopedLibraryChildCToCpp();
+ virtual ~CefTranslatorTestScopedLibraryChildCToCpp();
+
+ // CefTranslatorTestScopedLibraryChild methods.
+ int GetOtherValue() override;
+ void SetOtherValue(int value) override;
+
+ // CefTranslatorTestScopedLibrary methods.
+ int GetValue() override;
+ void SetValue(int value) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_TEST_TRANSLATOR_TEST_SCOPED_LIBRARY_CHILD_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/test/translator_test_scoped_library_ctocpp.cc b/libcef_dll/ctocpp/test/translator_test_scoped_library_ctocpp.cc
new file mode 100644
index 00000000..fc4121cd
--- /dev/null
+++ b/libcef_dll/ctocpp/test/translator_test_scoped_library_ctocpp.cc
@@ -0,0 +1,126 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=a7e1fb6e675934a1628d956cc7017cf67a405df6$
+//
+
+#include "libcef_dll/ctocpp/test/translator_test_scoped_library_ctocpp.h"
+#include "libcef_dll/ctocpp/test/translator_test_scoped_library_child_child_ctocpp.h"
+#include "libcef_dll/ctocpp/test/translator_test_scoped_library_child_ctocpp.h"
+
+// STATIC METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefOwnPtr<CefTranslatorTestScopedLibrary>
+CefTranslatorTestScopedLibrary::Create(int value) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_translator_test_scoped_library_t* _retval =
+ cef_translator_test_scoped_library_create(value);
+
+ // Return type: ownptr_same
+ return CefTranslatorTestScopedLibraryCToCpp::Wrap(_retval);
+}
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") int CefTranslatorTestScopedLibraryCToCpp::GetValue() {
+ cef_translator_test_scoped_library_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_value)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_value(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefTranslatorTestScopedLibraryCToCpp::SetValue(int value) {
+ cef_translator_test_scoped_library_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_value)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_value(_struct, value);
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefTranslatorTestScopedLibraryCToCpp::CefTranslatorTestScopedLibraryCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefTranslatorTestScopedLibraryCToCpp::~CefTranslatorTestScopedLibraryCToCpp() {}
+
+template <>
+cef_translator_test_scoped_library_t*
+CefCToCppScoped<CefTranslatorTestScopedLibraryCToCpp,
+ CefTranslatorTestScopedLibrary,
+ cef_translator_test_scoped_library_t>::
+ UnwrapDerivedOwn(CefWrapperType type,
+ CefOwnPtr<CefTranslatorTestScopedLibrary> c) {
+ if (type == WT_TRANSLATOR_TEST_SCOPED_LIBRARY_CHILD) {
+ return reinterpret_cast<cef_translator_test_scoped_library_t*>(
+ CefTranslatorTestScopedLibraryChildCToCpp::UnwrapOwn(
+ CefOwnPtr<CefTranslatorTestScopedLibraryChild>(
+ reinterpret_cast<CefTranslatorTestScopedLibraryChild*>(
+ c.release()))));
+ }
+ if (type == WT_TRANSLATOR_TEST_SCOPED_LIBRARY_CHILD_CHILD) {
+ return reinterpret_cast<cef_translator_test_scoped_library_t*>(
+ CefTranslatorTestScopedLibraryChildChildCToCpp::UnwrapOwn(
+ CefOwnPtr<CefTranslatorTestScopedLibraryChildChild>(
+ reinterpret_cast<CefTranslatorTestScopedLibraryChildChild*>(
+ c.release()))));
+ }
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+cef_translator_test_scoped_library_t*
+CefCToCppScoped<CefTranslatorTestScopedLibraryCToCpp,
+ CefTranslatorTestScopedLibrary,
+ cef_translator_test_scoped_library_t>::
+ UnwrapDerivedRaw(CefWrapperType type,
+ CefRawPtr<CefTranslatorTestScopedLibrary> c) {
+ if (type == WT_TRANSLATOR_TEST_SCOPED_LIBRARY_CHILD) {
+ return reinterpret_cast<cef_translator_test_scoped_library_t*>(
+ CefTranslatorTestScopedLibraryChildCToCpp::UnwrapRaw(
+ CefRawPtr<CefTranslatorTestScopedLibraryChild>(
+ reinterpret_cast<CefTranslatorTestScopedLibraryChild*>(c))));
+ }
+ if (type == WT_TRANSLATOR_TEST_SCOPED_LIBRARY_CHILD_CHILD) {
+ return reinterpret_cast<cef_translator_test_scoped_library_t*>(
+ CefTranslatorTestScopedLibraryChildChildCToCpp::UnwrapRaw(
+ CefRawPtr<CefTranslatorTestScopedLibraryChildChild>(
+ reinterpret_cast<CefTranslatorTestScopedLibraryChildChild*>(
+ c))));
+ }
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCToCppScoped<CefTranslatorTestScopedLibraryCToCpp,
+ CefTranslatorTestScopedLibrary,
+ cef_translator_test_scoped_library_t>::kWrapperType =
+ WT_TRANSLATOR_TEST_SCOPED_LIBRARY;
diff --git a/libcef_dll/ctocpp/test/translator_test_scoped_library_ctocpp.h b/libcef_dll/ctocpp/test/translator_test_scoped_library_ctocpp.h
new file mode 100644
index 00000000..c40e19ef
--- /dev/null
+++ b/libcef_dll/ctocpp/test/translator_test_scoped_library_ctocpp.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=5fafb4986f557d448f6f234fd49ea899eac81af1$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_TEST_TRANSLATOR_TEST_SCOPED_LIBRARY_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_TEST_TRANSLATOR_TEST_SCOPED_LIBRARY_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/test/cef_translator_test_capi.h"
+#include "include/test/cef_translator_test.h"
+#include "libcef_dll/ctocpp/ctocpp_scoped.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefTranslatorTestScopedLibraryCToCpp
+ : public CefCToCppScoped<CefTranslatorTestScopedLibraryCToCpp,
+ CefTranslatorTestScopedLibrary,
+ cef_translator_test_scoped_library_t> {
+ public:
+ CefTranslatorTestScopedLibraryCToCpp();
+ virtual ~CefTranslatorTestScopedLibraryCToCpp();
+
+ // CefTranslatorTestScopedLibrary methods.
+ int GetValue() override;
+ void SetValue(int value) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_TEST_TRANSLATOR_TEST_SCOPED_LIBRARY_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/thread_ctocpp.cc b/libcef_dll/ctocpp/thread_ctocpp.cc
new file mode 100644
index 00000000..98446f3a
--- /dev/null
+++ b/libcef_dll/ctocpp/thread_ctocpp.cc
@@ -0,0 +1,133 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=1f351fed26d9a331d9924c893d8b3d52064a1ecf$
+//
+
+#include "libcef_dll/ctocpp/thread_ctocpp.h"
+#include "libcef_dll/ctocpp/task_runner_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// STATIC METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefThread> CefThread::CreateThread(
+ const CefString& display_name,
+ cef_thread_priority_t priority,
+ cef_message_loop_type_t message_loop_type,
+ bool stoppable,
+ cef_com_init_mode_t com_init_mode) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: display_name
+
+ // Execute
+ cef_thread_t* _retval =
+ cef_thread_create(display_name.GetStruct(), priority, message_loop_type,
+ stoppable, com_init_mode);
+
+ // Return type: refptr_same
+ return CefThreadCToCpp::Wrap(_retval);
+}
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefTaskRunner> CefThreadCToCpp::GetTaskRunner() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_thread_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_task_runner)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_task_runner_t* _retval = _struct->get_task_runner(_struct);
+
+ // Return type: refptr_same
+ return CefTaskRunnerCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+cef_platform_thread_id_t CefThreadCToCpp::GetPlatformThreadId() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_thread_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_platform_thread_id)) {
+ return kInvalidPlatformThreadId;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_platform_thread_id_t _retval = _struct->get_platform_thread_id(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") void CefThreadCToCpp::Stop() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_thread_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, stop)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->stop(_struct);
+}
+
+NO_SANITIZE("cfi-icall") bool CefThreadCToCpp::IsRunning() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_thread_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_running)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_running(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefThreadCToCpp::CefThreadCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefThreadCToCpp::~CefThreadCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_thread_t*
+CefCToCppRefCounted<CefThreadCToCpp, CefThread, cef_thread_t>::UnwrapDerived(
+ CefWrapperType type,
+ CefThread* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefThreadCToCpp, CefThread, cef_thread_t>::
+ kWrapperType = WT_THREAD;
diff --git a/libcef_dll/ctocpp/thread_ctocpp.h b/libcef_dll/ctocpp/thread_ctocpp.h
new file mode 100644
index 00000000..5bdc3574
--- /dev/null
+++ b/libcef_dll/ctocpp/thread_ctocpp.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=63729fa2f06672498bde63eaa8151b20db9e6fd8$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_THREAD_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_THREAD_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_thread_capi.h"
+#include "include/cef_thread.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefThreadCToCpp
+ : public CefCToCppRefCounted<CefThreadCToCpp, CefThread, cef_thread_t> {
+ public:
+ CefThreadCToCpp();
+ virtual ~CefThreadCToCpp();
+
+ // CefThread methods.
+ CefRefPtr<CefTaskRunner> GetTaskRunner() override;
+ cef_platform_thread_id_t GetPlatformThreadId() override;
+ void Stop() override;
+ bool IsRunning() override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_THREAD_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/urlrequest_client_ctocpp.cc b/libcef_dll/ctocpp/urlrequest_client_ctocpp.cc
new file mode 100644
index 00000000..3552e93f
--- /dev/null
+++ b/libcef_dll/ctocpp/urlrequest_client_ctocpp.cc
@@ -0,0 +1,190 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=956da62e09f176547af7d7ff7696bf7374ac1f2f$
+//
+
+#include "libcef_dll/ctocpp/urlrequest_client_ctocpp.h"
+#include "libcef_dll/cpptoc/auth_callback_cpptoc.h"
+#include "libcef_dll/cpptoc/urlrequest_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+void CefURLRequestClientCToCpp::OnRequestComplete(
+ CefRefPtr<CefURLRequest> request) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_urlrequest_client_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_request_complete)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: request; type: refptr_diff
+ DCHECK(request.get());
+ if (!request.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_request_complete(_struct, CefURLRequestCppToC::Wrap(request));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefURLRequestClientCToCpp::OnUploadProgress(
+ CefRefPtr<CefURLRequest> request,
+ int64 current,
+ int64 total) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_urlrequest_client_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_upload_progress)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: request; type: refptr_diff
+ DCHECK(request.get());
+ if (!request.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_upload_progress(_struct, CefURLRequestCppToC::Wrap(request),
+ current, total);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefURLRequestClientCToCpp::OnDownloadProgress(
+ CefRefPtr<CefURLRequest> request,
+ int64 current,
+ int64 total) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_urlrequest_client_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_download_progress)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: request; type: refptr_diff
+ DCHECK(request.get());
+ if (!request.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_download_progress(_struct, CefURLRequestCppToC::Wrap(request),
+ current, total);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefURLRequestClientCToCpp::OnDownloadData(CefRefPtr<CefURLRequest> request,
+ const void* data,
+ size_t data_length) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_urlrequest_client_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_download_data)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: request; type: refptr_diff
+ DCHECK(request.get());
+ if (!request.get()) {
+ return;
+ }
+ // Verify param: data; type: simple_byaddr
+ DCHECK(data);
+ if (!data) {
+ return;
+ }
+
+ // Execute
+ _struct->on_download_data(_struct, CefURLRequestCppToC::Wrap(request), data,
+ data_length);
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefURLRequestClientCToCpp::GetAuthCredentials(
+ bool isProxy,
+ const CefString& host,
+ int port,
+ const CefString& realm,
+ const CefString& scheme,
+ CefRefPtr<CefAuthCallback> callback) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_urlrequest_client_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_auth_credentials)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: host; type: string_byref_const
+ DCHECK(!host.empty());
+ if (host.empty()) {
+ return false;
+ }
+ // Verify param: scheme; type: string_byref_const
+ DCHECK(!scheme.empty());
+ if (scheme.empty()) {
+ return false;
+ }
+ // Verify param: callback; type: refptr_diff
+ DCHECK(callback.get());
+ if (!callback.get()) {
+ return false;
+ }
+ // Unverified params: realm
+
+ // Execute
+ int _retval = _struct->get_auth_credentials(
+ _struct, isProxy, host.GetStruct(), port, realm.GetStruct(),
+ scheme.GetStruct(), CefAuthCallbackCppToC::Wrap(callback));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefURLRequestClientCToCpp::CefURLRequestClientCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefURLRequestClientCToCpp::~CefURLRequestClientCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_urlrequest_client_t* CefCToCppRefCounted<
+ CefURLRequestClientCToCpp,
+ CefURLRequestClient,
+ cef_urlrequest_client_t>::UnwrapDerived(CefWrapperType type,
+ CefURLRequestClient* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefURLRequestClientCToCpp,
+ CefURLRequestClient,
+ cef_urlrequest_client_t>::kWrapperType =
+ WT_URLREQUEST_CLIENT;
diff --git a/libcef_dll/ctocpp/urlrequest_client_ctocpp.h b/libcef_dll/ctocpp/urlrequest_client_ctocpp.h
new file mode 100644
index 00000000..dd081f9c
--- /dev/null
+++ b/libcef_dll/ctocpp/urlrequest_client_ctocpp.h
@@ -0,0 +1,56 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=50740eddae0ae234cf24d2b73eadcfdb16fcf0f0$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_URLREQUEST_CLIENT_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_URLREQUEST_CLIENT_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_urlrequest_capi.h"
+#include "include/cef_urlrequest.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefURLRequestClientCToCpp
+ : public CefCToCppRefCounted<CefURLRequestClientCToCpp,
+ CefURLRequestClient,
+ cef_urlrequest_client_t> {
+ public:
+ CefURLRequestClientCToCpp();
+ virtual ~CefURLRequestClientCToCpp();
+
+ // CefURLRequestClient methods.
+ void OnRequestComplete(CefRefPtr<CefURLRequest> request) override;
+ void OnUploadProgress(CefRefPtr<CefURLRequest> request,
+ int64 current,
+ int64 total) override;
+ void OnDownloadProgress(CefRefPtr<CefURLRequest> request,
+ int64 current,
+ int64 total) override;
+ void OnDownloadData(CefRefPtr<CefURLRequest> request,
+ const void* data,
+ size_t data_length) override;
+ bool GetAuthCredentials(bool isProxy,
+ const CefString& host,
+ int port,
+ const CefString& realm,
+ const CefString& scheme,
+ CefRefPtr<CefAuthCallback> callback) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_URLREQUEST_CLIENT_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/urlrequest_ctocpp.cc b/libcef_dll/ctocpp/urlrequest_ctocpp.cc
new file mode 100644
index 00000000..81136153
--- /dev/null
+++ b/libcef_dll/ctocpp/urlrequest_ctocpp.cc
@@ -0,0 +1,200 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=23d4bdc22e978bf6682f73801b11acc9c602c715$
+//
+
+#include "libcef_dll/ctocpp/urlrequest_ctocpp.h"
+#include "libcef_dll/cpptoc/urlrequest_client_cpptoc.h"
+#include "libcef_dll/ctocpp/request_context_ctocpp.h"
+#include "libcef_dll/ctocpp/request_ctocpp.h"
+#include "libcef_dll/ctocpp/response_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// STATIC METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefURLRequest> CefURLRequest::Create(
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefURLRequestClient> client,
+ CefRefPtr<CefRequestContext> request_context) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: request; type: refptr_same
+ DCHECK(request.get());
+ if (!request.get()) {
+ return nullptr;
+ }
+ // Verify param: client; type: refptr_diff
+ DCHECK(client.get());
+ if (!client.get()) {
+ return nullptr;
+ }
+ // Unverified params: request_context
+
+ // Execute
+ cef_urlrequest_t* _retval =
+ cef_urlrequest_create(CefRequestCToCpp::Unwrap(request),
+ CefURLRequestClientCppToC::Wrap(client),
+ CefRequestContextCToCpp::Unwrap(request_context));
+
+ // Return type: refptr_same
+ return CefURLRequestCToCpp::Wrap(_retval);
+}
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefRequest> CefURLRequestCToCpp::GetRequest() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_urlrequest_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_request)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_request_t* _retval = _struct->get_request(_struct);
+
+ // Return type: refptr_same
+ return CefRequestCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefURLRequestClient> CefURLRequestCToCpp::GetClient() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_urlrequest_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_client)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_urlrequest_client_t* _retval = _struct->get_client(_struct);
+
+ // Return type: refptr_diff
+ return CefURLRequestClientCppToC::Unwrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefURLRequest::Status CefURLRequestCToCpp::GetRequestStatus() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_urlrequest_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_request_status)) {
+ return UR_UNKNOWN;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_urlrequest_status_t _retval = _struct->get_request_status(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CefURLRequest::ErrorCode CefURLRequestCToCpp::GetRequestError() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_urlrequest_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_request_error)) {
+ return ERR_NONE;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_errorcode_t _retval = _struct->get_request_error(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefResponse> CefURLRequestCToCpp::GetResponse() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_urlrequest_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_response)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_response_t* _retval = _struct->get_response(_struct);
+
+ // Return type: refptr_same
+ return CefResponseCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") bool CefURLRequestCToCpp::ResponseWasCached() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_urlrequest_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, response_was_cached)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->response_was_cached(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") void CefURLRequestCToCpp::Cancel() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_urlrequest_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, cancel)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->cancel(_struct);
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefURLRequestCToCpp::CefURLRequestCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefURLRequestCToCpp::~CefURLRequestCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_urlrequest_t*
+CefCToCppRefCounted<CefURLRequestCToCpp, CefURLRequest, cef_urlrequest_t>::
+ UnwrapDerived(CefWrapperType type, CefURLRequest* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefURLRequestCToCpp,
+ CefURLRequest,
+ cef_urlrequest_t>::kWrapperType =
+ WT_URLREQUEST;
diff --git a/libcef_dll/ctocpp/urlrequest_ctocpp.h b/libcef_dll/ctocpp/urlrequest_ctocpp.h
new file mode 100644
index 00000000..7a2bff5e
--- /dev/null
+++ b/libcef_dll/ctocpp/urlrequest_ctocpp.h
@@ -0,0 +1,46 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=8c953a3dd5cdec5cba6160e848884c2f7c9b3ac6$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_URLREQUEST_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_URLREQUEST_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_urlrequest_capi.h"
+#include "include/cef_urlrequest.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefURLRequestCToCpp : public CefCToCppRefCounted<CefURLRequestCToCpp,
+ CefURLRequest,
+ cef_urlrequest_t> {
+ public:
+ CefURLRequestCToCpp();
+ virtual ~CefURLRequestCToCpp();
+
+ // CefURLRequest methods.
+ CefRefPtr<CefRequest> GetRequest() override;
+ CefRefPtr<CefURLRequestClient> GetClient() override;
+ Status GetRequestStatus() override;
+ ErrorCode GetRequestError() override;
+ CefRefPtr<CefResponse> GetResponse() override;
+ bool ResponseWasCached() override;
+ void Cancel() override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_URLREQUEST_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/v8accessor_ctocpp.cc b/libcef_dll/ctocpp/v8accessor_ctocpp.cc
new file mode 100644
index 00000000..739551ec
--- /dev/null
+++ b/libcef_dll/ctocpp/v8accessor_ctocpp.cc
@@ -0,0 +1,125 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=20c409219d3b1a4db83f506807a3f4401e2dffb4$
+//
+
+#include "libcef_dll/ctocpp/v8accessor_ctocpp.h"
+#include "libcef_dll/cpptoc/v8value_cpptoc.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+bool CefV8AccessorCToCpp::Get(const CefString& name,
+ const CefRefPtr<CefV8Value> object,
+ CefRefPtr<CefV8Value>& retval,
+ CefString& exception) {
+ cef_v8accessor_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: name; type: string_byref_const
+ DCHECK(!name.empty());
+ if (name.empty()) {
+ return false;
+ }
+ // Verify param: object; type: refptr_diff
+ DCHECK(object.get());
+ if (!object.get()) {
+ return false;
+ }
+
+ // Translate param: retval; type: refptr_diff_byref
+ cef_v8value_t* retvalStruct = NULL;
+ if (retval.get()) {
+ retvalStruct = CefV8ValueCppToC::Wrap(retval);
+ }
+ cef_v8value_t* retvalOrig = retvalStruct;
+
+ // Execute
+ int _retval =
+ _struct->get(_struct, name.GetStruct(), CefV8ValueCppToC::Wrap(object),
+ &retvalStruct, exception.GetWritableStruct());
+
+ // Restore param:retval; type: refptr_diff_byref
+ if (retvalStruct) {
+ if (retvalStruct != retvalOrig) {
+ retval = CefV8ValueCppToC::Unwrap(retvalStruct);
+ }
+ } else {
+ retval = nullptr;
+ }
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefV8AccessorCToCpp::Set(const CefString& name,
+ const CefRefPtr<CefV8Value> object,
+ const CefRefPtr<CefV8Value> value,
+ CefString& exception) {
+ cef_v8accessor_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: name; type: string_byref_const
+ DCHECK(!name.empty());
+ if (name.empty()) {
+ return false;
+ }
+ // Verify param: object; type: refptr_diff
+ DCHECK(object.get());
+ if (!object.get()) {
+ return false;
+ }
+ // Verify param: value; type: refptr_diff
+ DCHECK(value.get());
+ if (!value.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->set(
+ _struct, name.GetStruct(), CefV8ValueCppToC::Wrap(object),
+ CefV8ValueCppToC::Wrap(value), exception.GetWritableStruct());
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefV8AccessorCToCpp::CefV8AccessorCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefV8AccessorCToCpp::~CefV8AccessorCToCpp() {}
+
+template <>
+cef_v8accessor_t*
+CefCToCppRefCounted<CefV8AccessorCToCpp, CefV8Accessor, cef_v8accessor_t>::
+ UnwrapDerived(CefWrapperType type, CefV8Accessor* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefV8AccessorCToCpp,
+ CefV8Accessor,
+ cef_v8accessor_t>::kWrapperType =
+ WT_V8ACCESSOR;
diff --git a/libcef_dll/ctocpp/v8accessor_ctocpp.h b/libcef_dll/ctocpp/v8accessor_ctocpp.h
new file mode 100644
index 00000000..45c4de9f
--- /dev/null
+++ b/libcef_dll/ctocpp/v8accessor_ctocpp.h
@@ -0,0 +1,47 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=1d8a3afd0e6a0344a9c5f6e301b517e5f906c186$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_V8ACCESSOR_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_V8ACCESSOR_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_v8_capi.h"
+#include "include/cef_v8.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefV8AccessorCToCpp : public CefCToCppRefCounted<CefV8AccessorCToCpp,
+ CefV8Accessor,
+ cef_v8accessor_t> {
+ public:
+ CefV8AccessorCToCpp();
+ virtual ~CefV8AccessorCToCpp();
+
+ // CefV8Accessor methods.
+ bool Get(const CefString& name,
+ const CefRefPtr<CefV8Value> object,
+ CefRefPtr<CefV8Value>& retval,
+ CefString& exception) override;
+ bool Set(const CefString& name,
+ const CefRefPtr<CefV8Value> object,
+ const CefRefPtr<CefV8Value> value,
+ CefString& exception) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_V8ACCESSOR_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/v8array_buffer_release_callback_ctocpp.cc b/libcef_dll/ctocpp/v8array_buffer_release_callback_ctocpp.cc
new file mode 100644
index 00000000..1564ec61
--- /dev/null
+++ b/libcef_dll/ctocpp/v8array_buffer_release_callback_ctocpp.cc
@@ -0,0 +1,63 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=a8e1be23deec15c2443d4adfefa81ed924a15985$
+//
+
+#include "libcef_dll/ctocpp/v8array_buffer_release_callback_ctocpp.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+void CefV8ArrayBufferReleaseCallbackCToCpp::ReleaseBuffer(void* buffer) {
+ cef_v8array_buffer_release_callback_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, release_buffer)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: buffer; type: simple_byaddr
+ DCHECK(buffer);
+ if (!buffer) {
+ return;
+ }
+
+ // Execute
+ _struct->release_buffer(_struct, buffer);
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefV8ArrayBufferReleaseCallbackCToCpp::CefV8ArrayBufferReleaseCallbackCToCpp() {
+}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefV8ArrayBufferReleaseCallbackCToCpp::
+ ~CefV8ArrayBufferReleaseCallbackCToCpp() {}
+
+template <>
+cef_v8array_buffer_release_callback_t*
+CefCToCppRefCounted<CefV8ArrayBufferReleaseCallbackCToCpp,
+ CefV8ArrayBufferReleaseCallback,
+ cef_v8array_buffer_release_callback_t>::
+ UnwrapDerived(CefWrapperType type, CefV8ArrayBufferReleaseCallback* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCToCppRefCounted<CefV8ArrayBufferReleaseCallbackCToCpp,
+ CefV8ArrayBufferReleaseCallback,
+ cef_v8array_buffer_release_callback_t>::kWrapperType =
+ WT_V8ARRAY_BUFFER_RELEASE_CALLBACK;
diff --git a/libcef_dll/ctocpp/v8array_buffer_release_callback_ctocpp.h b/libcef_dll/ctocpp/v8array_buffer_release_callback_ctocpp.h
new file mode 100644
index 00000000..4a529253
--- /dev/null
+++ b/libcef_dll/ctocpp/v8array_buffer_release_callback_ctocpp.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=4f9c4bb702d2824ee94dd334244cd9ba14609025$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_V8ARRAY_BUFFER_RELEASE_CALLBACK_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_V8ARRAY_BUFFER_RELEASE_CALLBACK_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_v8_capi.h"
+#include "include/cef_v8.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefV8ArrayBufferReleaseCallbackCToCpp
+ : public CefCToCppRefCounted<CefV8ArrayBufferReleaseCallbackCToCpp,
+ CefV8ArrayBufferReleaseCallback,
+ cef_v8array_buffer_release_callback_t> {
+ public:
+ CefV8ArrayBufferReleaseCallbackCToCpp();
+ virtual ~CefV8ArrayBufferReleaseCallbackCToCpp();
+
+ // CefV8ArrayBufferReleaseCallback methods.
+ void ReleaseBuffer(void* buffer) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_V8ARRAY_BUFFER_RELEASE_CALLBACK_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/v8context_ctocpp.cc b/libcef_dll/ctocpp/v8context_ctocpp.cc
new file mode 100644
index 00000000..1866a747
--- /dev/null
+++ b/libcef_dll/ctocpp/v8context_ctocpp.cc
@@ -0,0 +1,265 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=af5dfb61e2e3f14c482c861af5a271adca93439a$
+//
+
+#include "libcef_dll/ctocpp/v8context_ctocpp.h"
+#include "libcef_dll/ctocpp/browser_ctocpp.h"
+#include "libcef_dll/ctocpp/frame_ctocpp.h"
+#include "libcef_dll/ctocpp/task_runner_ctocpp.h"
+#include "libcef_dll/ctocpp/v8exception_ctocpp.h"
+#include "libcef_dll/ctocpp/v8value_ctocpp.h"
+
+// STATIC METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefV8Context> CefV8Context::GetCurrentContext() {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_v8context_t* _retval = cef_v8context_get_current_context();
+
+ // Return type: refptr_same
+ return CefV8ContextCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefV8Context> CefV8Context::GetEnteredContext() {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_v8context_t* _retval = cef_v8context_get_entered_context();
+
+ // Return type: refptr_same
+ return CefV8ContextCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") bool CefV8Context::InContext() {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = cef_v8context_in_context();
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefTaskRunner> CefV8ContextCToCpp::GetTaskRunner() {
+ cef_v8context_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_task_runner)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_task_runner_t* _retval = _struct->get_task_runner(_struct);
+
+ // Return type: refptr_same
+ return CefTaskRunnerCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") bool CefV8ContextCToCpp::IsValid() {
+ cef_v8context_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_valid)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_valid(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefBrowser> CefV8ContextCToCpp::GetBrowser() {
+ cef_v8context_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_browser)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_browser_t* _retval = _struct->get_browser(_struct);
+
+ // Return type: refptr_same
+ return CefBrowserCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefFrame> CefV8ContextCToCpp::GetFrame() {
+ cef_v8context_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_frame)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_frame_t* _retval = _struct->get_frame(_struct);
+
+ // Return type: refptr_same
+ return CefFrameCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefV8Value> CefV8ContextCToCpp::GetGlobal() {
+ cef_v8context_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_global)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_v8value_t* _retval = _struct->get_global(_struct);
+
+ // Return type: refptr_same
+ return CefV8ValueCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") bool CefV8ContextCToCpp::Enter() {
+ cef_v8context_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, enter)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->enter(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefV8ContextCToCpp::Exit() {
+ cef_v8context_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, exit)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->exit(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefV8ContextCToCpp::IsSame(CefRefPtr<CefV8Context> that) {
+ cef_v8context_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_same)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: that; type: refptr_same
+ DCHECK(that.get());
+ if (!that.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->is_same(_struct, CefV8ContextCToCpp::Unwrap(that));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefV8ContextCToCpp::Eval(const CefString& code,
+ const CefString& script_url,
+ int start_line,
+ CefRefPtr<CefV8Value>& retval,
+ CefRefPtr<CefV8Exception>& exception) {
+ cef_v8context_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, eval)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: code; type: string_byref_const
+ DCHECK(!code.empty());
+ if (code.empty()) {
+ return false;
+ }
+ // Unverified params: script_url
+
+ // Translate param: retval; type: refptr_same_byref
+ cef_v8value_t* retvalStruct = NULL;
+ if (retval.get()) {
+ retvalStruct = CefV8ValueCToCpp::Unwrap(retval);
+ }
+ cef_v8value_t* retvalOrig = retvalStruct;
+ // Translate param: exception; type: refptr_same_byref
+ cef_v8exception_t* exceptionStruct = NULL;
+ if (exception.get()) {
+ exceptionStruct = CefV8ExceptionCToCpp::Unwrap(exception);
+ }
+ cef_v8exception_t* exceptionOrig = exceptionStruct;
+
+ // Execute
+ int _retval = _struct->eval(_struct, code.GetStruct(), script_url.GetStruct(),
+ start_line, &retvalStruct, &exceptionStruct);
+
+ // Restore param:retval; type: refptr_same_byref
+ if (retvalStruct) {
+ if (retvalStruct != retvalOrig) {
+ retval = CefV8ValueCToCpp::Wrap(retvalStruct);
+ }
+ } else {
+ retval = nullptr;
+ }
+ // Restore param:exception; type: refptr_same_byref
+ if (exceptionStruct) {
+ if (exceptionStruct != exceptionOrig) {
+ exception = CefV8ExceptionCToCpp::Wrap(exceptionStruct);
+ }
+ } else {
+ exception = nullptr;
+ }
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefV8ContextCToCpp::CefV8ContextCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefV8ContextCToCpp::~CefV8ContextCToCpp() {}
+
+template <>
+cef_v8context_t*
+CefCToCppRefCounted<CefV8ContextCToCpp, CefV8Context, cef_v8context_t>::
+ UnwrapDerived(CefWrapperType type, CefV8Context* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefV8ContextCToCpp,
+ CefV8Context,
+ cef_v8context_t>::kWrapperType =
+ WT_V8CONTEXT;
diff --git a/libcef_dll/ctocpp/v8context_ctocpp.h b/libcef_dll/ctocpp/v8context_ctocpp.h
new file mode 100644
index 00000000..7ab4e0bc
--- /dev/null
+++ b/libcef_dll/ctocpp/v8context_ctocpp.h
@@ -0,0 +1,52 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=c5159f67aa8d77aca23153cf6c35468af27dba14$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_V8CONTEXT_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_V8CONTEXT_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_v8_capi.h"
+#include "include/cef_v8.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefV8ContextCToCpp : public CefCToCppRefCounted<CefV8ContextCToCpp,
+ CefV8Context,
+ cef_v8context_t> {
+ public:
+ CefV8ContextCToCpp();
+ virtual ~CefV8ContextCToCpp();
+
+ // CefV8Context methods.
+ CefRefPtr<CefTaskRunner> GetTaskRunner() override;
+ bool IsValid() override;
+ CefRefPtr<CefBrowser> GetBrowser() override;
+ CefRefPtr<CefFrame> GetFrame() override;
+ CefRefPtr<CefV8Value> GetGlobal() override;
+ bool Enter() override;
+ bool Exit() override;
+ bool IsSame(CefRefPtr<CefV8Context> that) override;
+ bool Eval(const CefString& code,
+ const CefString& script_url,
+ int start_line,
+ CefRefPtr<CefV8Value>& retval,
+ CefRefPtr<CefV8Exception>& exception) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_V8CONTEXT_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/v8exception_ctocpp.cc b/libcef_dll/ctocpp/v8exception_ctocpp.cc
new file mode 100644
index 00000000..0a13756c
--- /dev/null
+++ b/libcef_dll/ctocpp/v8exception_ctocpp.cc
@@ -0,0 +1,166 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=b3ea08250be63ea366897aac9eb85868711f27da$
+//
+
+#include "libcef_dll/ctocpp/v8exception_ctocpp.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") CefString CefV8ExceptionCToCpp::GetMessage() {
+ cef_v8exception_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_message)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_message(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") CefString CefV8ExceptionCToCpp::GetSourceLine() {
+ cef_v8exception_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_source_line)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_source_line(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+CefString CefV8ExceptionCToCpp::GetScriptResourceName() {
+ cef_v8exception_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_script_resource_name)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_script_resource_name(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") int CefV8ExceptionCToCpp::GetLineNumber() {
+ cef_v8exception_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_line_number)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_line_number(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") int CefV8ExceptionCToCpp::GetStartPosition() {
+ cef_v8exception_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_start_position)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_start_position(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") int CefV8ExceptionCToCpp::GetEndPosition() {
+ cef_v8exception_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_end_position)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_end_position(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") int CefV8ExceptionCToCpp::GetStartColumn() {
+ cef_v8exception_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_start_column)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_start_column(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") int CefV8ExceptionCToCpp::GetEndColumn() {
+ cef_v8exception_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_end_column)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_end_column(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefV8ExceptionCToCpp::CefV8ExceptionCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefV8ExceptionCToCpp::~CefV8ExceptionCToCpp() {}
+
+template <>
+cef_v8exception_t*
+CefCToCppRefCounted<CefV8ExceptionCToCpp, CefV8Exception, cef_v8exception_t>::
+ UnwrapDerived(CefWrapperType type, CefV8Exception* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefV8ExceptionCToCpp,
+ CefV8Exception,
+ cef_v8exception_t>::kWrapperType =
+ WT_V8EXCEPTION;
diff --git a/libcef_dll/ctocpp/v8exception_ctocpp.h b/libcef_dll/ctocpp/v8exception_ctocpp.h
new file mode 100644
index 00000000..0256b62f
--- /dev/null
+++ b/libcef_dll/ctocpp/v8exception_ctocpp.h
@@ -0,0 +1,47 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=ed15db160fa19964fe5c9902c279fa1b44bd0dbe$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_V8EXCEPTION_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_V8EXCEPTION_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_v8_capi.h"
+#include "include/cef_v8.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefV8ExceptionCToCpp : public CefCToCppRefCounted<CefV8ExceptionCToCpp,
+ CefV8Exception,
+ cef_v8exception_t> {
+ public:
+ CefV8ExceptionCToCpp();
+ virtual ~CefV8ExceptionCToCpp();
+
+ // CefV8Exception methods.
+ CefString GetMessage() override;
+ CefString GetSourceLine() override;
+ CefString GetScriptResourceName() override;
+ int GetLineNumber() override;
+ int GetStartPosition() override;
+ int GetEndPosition() override;
+ int GetStartColumn() override;
+ int GetEndColumn() override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_V8EXCEPTION_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/v8handler_ctocpp.cc b/libcef_dll/ctocpp/v8handler_ctocpp.cc
new file mode 100644
index 00000000..20f8637d
--- /dev/null
+++ b/libcef_dll/ctocpp/v8handler_ctocpp.cc
@@ -0,0 +1,105 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=3bed822df5b626633e7f1fd8dcc328d8eb0446fb$
+//
+
+#include "libcef_dll/ctocpp/v8handler_ctocpp.h"
+#include "libcef_dll/cpptoc/v8value_cpptoc.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+bool CefV8HandlerCToCpp::Execute(const CefString& name,
+ CefRefPtr<CefV8Value> object,
+ const CefV8ValueList& arguments,
+ CefRefPtr<CefV8Value>& retval,
+ CefString& exception) {
+ cef_v8handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, execute)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: name; type: string_byref_const
+ DCHECK(!name.empty());
+ if (name.empty()) {
+ return false;
+ }
+ // Verify param: object; type: refptr_diff
+ DCHECK(object.get());
+ if (!object.get()) {
+ return false;
+ }
+
+ // Translate param: arguments; type: refptr_vec_diff_byref_const
+ const size_t argumentsCount = arguments.size();
+ cef_v8value_t** argumentsList = NULL;
+ if (argumentsCount > 0) {
+ argumentsList = new cef_v8value_t*[argumentsCount];
+ DCHECK(argumentsList);
+ if (argumentsList) {
+ for (size_t i = 0; i < argumentsCount; ++i) {
+ argumentsList[i] = CefV8ValueCppToC::Wrap(arguments[i]);
+ }
+ }
+ }
+ // Translate param: retval; type: refptr_diff_byref
+ cef_v8value_t* retvalStruct = NULL;
+ if (retval.get()) {
+ retvalStruct = CefV8ValueCppToC::Wrap(retval);
+ }
+ cef_v8value_t* retvalOrig = retvalStruct;
+
+ // Execute
+ int _retval = _struct->execute(
+ _struct, name.GetStruct(), CefV8ValueCppToC::Wrap(object), argumentsCount,
+ argumentsList, &retvalStruct, exception.GetWritableStruct());
+
+ // Restore param:arguments; type: refptr_vec_diff_byref_const
+ if (argumentsList) {
+ delete[] argumentsList;
+ }
+ // Restore param:retval; type: refptr_diff_byref
+ if (retvalStruct) {
+ if (retvalStruct != retvalOrig) {
+ retval = CefV8ValueCppToC::Unwrap(retvalStruct);
+ }
+ } else {
+ retval = nullptr;
+ }
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefV8HandlerCToCpp::CefV8HandlerCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefV8HandlerCToCpp::~CefV8HandlerCToCpp() {}
+
+template <>
+cef_v8handler_t*
+CefCToCppRefCounted<CefV8HandlerCToCpp, CefV8Handler, cef_v8handler_t>::
+ UnwrapDerived(CefWrapperType type, CefV8Handler* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefV8HandlerCToCpp,
+ CefV8Handler,
+ cef_v8handler_t>::kWrapperType =
+ WT_V8HANDLER;
diff --git a/libcef_dll/ctocpp/v8handler_ctocpp.h b/libcef_dll/ctocpp/v8handler_ctocpp.h
new file mode 100644
index 00000000..cd5a0e42
--- /dev/null
+++ b/libcef_dll/ctocpp/v8handler_ctocpp.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=442444a8b361b3ce3f599181fe8057d175e1cc20$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_V8HANDLER_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_V8HANDLER_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_v8_capi.h"
+#include "include/cef_v8.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefV8HandlerCToCpp : public CefCToCppRefCounted<CefV8HandlerCToCpp,
+ CefV8Handler,
+ cef_v8handler_t> {
+ public:
+ CefV8HandlerCToCpp();
+ virtual ~CefV8HandlerCToCpp();
+
+ // CefV8Handler methods.
+ bool Execute(const CefString& name,
+ CefRefPtr<CefV8Value> object,
+ const CefV8ValueList& arguments,
+ CefRefPtr<CefV8Value>& retval,
+ CefString& exception) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_V8HANDLER_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/v8interceptor_ctocpp.cc b/libcef_dll/ctocpp/v8interceptor_ctocpp.cc
new file mode 100644
index 00000000..628ba3a0
--- /dev/null
+++ b/libcef_dll/ctocpp/v8interceptor_ctocpp.cc
@@ -0,0 +1,212 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=edbd66283dfde3f7129c189c7ca51c1d45dc804d$
+//
+
+#include "libcef_dll/ctocpp/v8interceptor_ctocpp.h"
+#include "libcef_dll/cpptoc/v8value_cpptoc.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+bool CefV8InterceptorCToCpp::Get(const CefString& name,
+ const CefRefPtr<CefV8Value> object,
+ CefRefPtr<CefV8Value>& retval,
+ CefString& exception) {
+ cef_v8interceptor_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_byname)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: name; type: string_byref_const
+ DCHECK(!name.empty());
+ if (name.empty()) {
+ return false;
+ }
+ // Verify param: object; type: refptr_diff
+ DCHECK(object.get());
+ if (!object.get()) {
+ return false;
+ }
+
+ // Translate param: retval; type: refptr_diff_byref
+ cef_v8value_t* retvalStruct = NULL;
+ if (retval.get()) {
+ retvalStruct = CefV8ValueCppToC::Wrap(retval);
+ }
+ cef_v8value_t* retvalOrig = retvalStruct;
+
+ // Execute
+ int _retval = _struct->get_byname(
+ _struct, name.GetStruct(), CefV8ValueCppToC::Wrap(object), &retvalStruct,
+ exception.GetWritableStruct());
+
+ // Restore param:retval; type: refptr_diff_byref
+ if (retvalStruct) {
+ if (retvalStruct != retvalOrig) {
+ retval = CefV8ValueCppToC::Unwrap(retvalStruct);
+ }
+ } else {
+ retval = nullptr;
+ }
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefV8InterceptorCToCpp::Get(int index,
+ const CefRefPtr<CefV8Value> object,
+ CefRefPtr<CefV8Value>& retval,
+ CefString& exception) {
+ cef_v8interceptor_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_byindex)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: index; type: simple_byval
+ DCHECK_GE(index, 0);
+ if (index < 0) {
+ return false;
+ }
+ // Verify param: object; type: refptr_diff
+ DCHECK(object.get());
+ if (!object.get()) {
+ return false;
+ }
+
+ // Translate param: retval; type: refptr_diff_byref
+ cef_v8value_t* retvalStruct = NULL;
+ if (retval.get()) {
+ retvalStruct = CefV8ValueCppToC::Wrap(retval);
+ }
+ cef_v8value_t* retvalOrig = retvalStruct;
+
+ // Execute
+ int _retval =
+ _struct->get_byindex(_struct, index, CefV8ValueCppToC::Wrap(object),
+ &retvalStruct, exception.GetWritableStruct());
+
+ // Restore param:retval; type: refptr_diff_byref
+ if (retvalStruct) {
+ if (retvalStruct != retvalOrig) {
+ retval = CefV8ValueCppToC::Unwrap(retvalStruct);
+ }
+ } else {
+ retval = nullptr;
+ }
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefV8InterceptorCToCpp::Set(const CefString& name,
+ const CefRefPtr<CefV8Value> object,
+ const CefRefPtr<CefV8Value> value,
+ CefString& exception) {
+ cef_v8interceptor_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_byname)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: name; type: string_byref_const
+ DCHECK(!name.empty());
+ if (name.empty()) {
+ return false;
+ }
+ // Verify param: object; type: refptr_diff
+ DCHECK(object.get());
+ if (!object.get()) {
+ return false;
+ }
+ // Verify param: value; type: refptr_diff
+ DCHECK(value.get());
+ if (!value.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->set_byname(
+ _struct, name.GetStruct(), CefV8ValueCppToC::Wrap(object),
+ CefV8ValueCppToC::Wrap(value), exception.GetWritableStruct());
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefV8InterceptorCToCpp::Set(int index,
+ const CefRefPtr<CefV8Value> object,
+ const CefRefPtr<CefV8Value> value,
+ CefString& exception) {
+ cef_v8interceptor_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_byindex)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: index; type: simple_byval
+ DCHECK_GE(index, 0);
+ if (index < 0) {
+ return false;
+ }
+ // Verify param: object; type: refptr_diff
+ DCHECK(object.get());
+ if (!object.get()) {
+ return false;
+ }
+ // Verify param: value; type: refptr_diff
+ DCHECK(value.get());
+ if (!value.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->set_byindex(
+ _struct, index, CefV8ValueCppToC::Wrap(object),
+ CefV8ValueCppToC::Wrap(value), exception.GetWritableStruct());
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefV8InterceptorCToCpp::CefV8InterceptorCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefV8InterceptorCToCpp::~CefV8InterceptorCToCpp() {}
+
+template <>
+cef_v8interceptor_t*
+CefCToCppRefCounted<CefV8InterceptorCToCpp,
+ CefV8Interceptor,
+ cef_v8interceptor_t>::UnwrapDerived(CefWrapperType type,
+ CefV8Interceptor* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefV8InterceptorCToCpp,
+ CefV8Interceptor,
+ cef_v8interceptor_t>::kWrapperType =
+ WT_V8INTERCEPTOR;
diff --git a/libcef_dll/ctocpp/v8interceptor_ctocpp.h b/libcef_dll/ctocpp/v8interceptor_ctocpp.h
new file mode 100644
index 00000000..de862c1d
--- /dev/null
+++ b/libcef_dll/ctocpp/v8interceptor_ctocpp.h
@@ -0,0 +1,56 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=11fbbb5b1de3f96d332ec3653780826677ffcdf2$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_V8INTERCEPTOR_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_V8INTERCEPTOR_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_v8_capi.h"
+#include "include/cef_v8.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefV8InterceptorCToCpp
+ : public CefCToCppRefCounted<CefV8InterceptorCToCpp,
+ CefV8Interceptor,
+ cef_v8interceptor_t> {
+ public:
+ CefV8InterceptorCToCpp();
+ virtual ~CefV8InterceptorCToCpp();
+
+ // CefV8Interceptor methods.
+ bool Get(const CefString& name,
+ const CefRefPtr<CefV8Value> object,
+ CefRefPtr<CefV8Value>& retval,
+ CefString& exception) override;
+ bool Get(int index,
+ const CefRefPtr<CefV8Value> object,
+ CefRefPtr<CefV8Value>& retval,
+ CefString& exception) override;
+ bool Set(const CefString& name,
+ const CefRefPtr<CefV8Value> object,
+ const CefRefPtr<CefV8Value> value,
+ CefString& exception) override;
+ bool Set(int index,
+ const CefRefPtr<CefV8Value> object,
+ const CefRefPtr<CefV8Value> value,
+ CefString& exception) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_V8INTERCEPTOR_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/v8stack_frame_ctocpp.cc b/libcef_dll/ctocpp/v8stack_frame_ctocpp.cc
new file mode 100644
index 00000000..56d68fde
--- /dev/null
+++ b/libcef_dll/ctocpp/v8stack_frame_ctocpp.cc
@@ -0,0 +1,169 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=e62b4e0bc37726652674fb026a548dc1de6e54ca$
+//
+
+#include "libcef_dll/ctocpp/v8stack_frame_ctocpp.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") bool CefV8StackFrameCToCpp::IsValid() {
+ cef_v8stack_frame_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_valid)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_valid(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") CefString CefV8StackFrameCToCpp::GetScriptName() {
+ cef_v8stack_frame_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_script_name)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_script_name(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+CefString CefV8StackFrameCToCpp::GetScriptNameOrSourceURL() {
+ cef_v8stack_frame_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_script_name_or_source_url)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval =
+ _struct->get_script_name_or_source_url(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") CefString CefV8StackFrameCToCpp::GetFunctionName() {
+ cef_v8stack_frame_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_function_name)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_function_name(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") int CefV8StackFrameCToCpp::GetLineNumber() {
+ cef_v8stack_frame_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_line_number)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_line_number(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") int CefV8StackFrameCToCpp::GetColumn() {
+ cef_v8stack_frame_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_column)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_column(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") bool CefV8StackFrameCToCpp::IsEval() {
+ cef_v8stack_frame_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_eval)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_eval(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefV8StackFrameCToCpp::IsConstructor() {
+ cef_v8stack_frame_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_constructor)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_constructor(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefV8StackFrameCToCpp::CefV8StackFrameCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefV8StackFrameCToCpp::~CefV8StackFrameCToCpp() {}
+
+template <>
+cef_v8stack_frame_t*
+CefCToCppRefCounted<CefV8StackFrameCToCpp,
+ CefV8StackFrame,
+ cef_v8stack_frame_t>::UnwrapDerived(CefWrapperType type,
+ CefV8StackFrame* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefV8StackFrameCToCpp,
+ CefV8StackFrame,
+ cef_v8stack_frame_t>::kWrapperType =
+ WT_V8STACK_FRAME;
diff --git a/libcef_dll/ctocpp/v8stack_frame_ctocpp.h b/libcef_dll/ctocpp/v8stack_frame_ctocpp.h
new file mode 100644
index 00000000..474cd1ad
--- /dev/null
+++ b/libcef_dll/ctocpp/v8stack_frame_ctocpp.h
@@ -0,0 +1,47 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=366d110fdfaf3d241c26e9ec276f7c363ecd313f$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_V8STACK_FRAME_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_V8STACK_FRAME_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_v8_capi.h"
+#include "include/cef_v8.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefV8StackFrameCToCpp : public CefCToCppRefCounted<CefV8StackFrameCToCpp,
+ CefV8StackFrame,
+ cef_v8stack_frame_t> {
+ public:
+ CefV8StackFrameCToCpp();
+ virtual ~CefV8StackFrameCToCpp();
+
+ // CefV8StackFrame methods.
+ bool IsValid() override;
+ CefString GetScriptName() override;
+ CefString GetScriptNameOrSourceURL() override;
+ CefString GetFunctionName() override;
+ int GetLineNumber() override;
+ int GetColumn() override;
+ bool IsEval() override;
+ bool IsConstructor() override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_V8STACK_FRAME_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/v8stack_trace_ctocpp.cc b/libcef_dll/ctocpp/v8stack_trace_ctocpp.cc
new file mode 100644
index 00000000..7d2fb0ba
--- /dev/null
+++ b/libcef_dll/ctocpp/v8stack_trace_ctocpp.cc
@@ -0,0 +1,112 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=baa09d0933e7754969e1503dd06c2f4d4b52e16c$
+//
+
+#include "libcef_dll/ctocpp/v8stack_trace_ctocpp.h"
+#include "libcef_dll/ctocpp/v8stack_frame_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// STATIC METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefV8StackTrace> CefV8StackTrace::GetCurrent(int frame_limit) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_v8stack_trace_t* _retval = cef_v8stack_trace_get_current(frame_limit);
+
+ // Return type: refptr_same
+ return CefV8StackTraceCToCpp::Wrap(_retval);
+}
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") bool CefV8StackTraceCToCpp::IsValid() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_v8stack_trace_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_valid)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_valid(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") int CefV8StackTraceCToCpp::GetFrameCount() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_v8stack_trace_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_frame_count)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_frame_count(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefV8StackFrame> CefV8StackTraceCToCpp::GetFrame(int index) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_v8stack_trace_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_frame)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_v8stack_frame_t* _retval = _struct->get_frame(_struct, index);
+
+ // Return type: refptr_same
+ return CefV8StackFrameCToCpp::Wrap(_retval);
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefV8StackTraceCToCpp::CefV8StackTraceCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefV8StackTraceCToCpp::~CefV8StackTraceCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_v8stack_trace_t*
+CefCToCppRefCounted<CefV8StackTraceCToCpp,
+ CefV8StackTrace,
+ cef_v8stack_trace_t>::UnwrapDerived(CefWrapperType type,
+ CefV8StackTrace* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefV8StackTraceCToCpp,
+ CefV8StackTrace,
+ cef_v8stack_trace_t>::kWrapperType =
+ WT_V8STACK_TRACE;
diff --git a/libcef_dll/ctocpp/v8stack_trace_ctocpp.h b/libcef_dll/ctocpp/v8stack_trace_ctocpp.h
new file mode 100644
index 00000000..1e076ac1
--- /dev/null
+++ b/libcef_dll/ctocpp/v8stack_trace_ctocpp.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=361eefa5a258faf92d09e28787293fa29bbed742$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_V8STACK_TRACE_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_V8STACK_TRACE_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_v8_capi.h"
+#include "include/cef_v8.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefV8StackTraceCToCpp : public CefCToCppRefCounted<CefV8StackTraceCToCpp,
+ CefV8StackTrace,
+ cef_v8stack_trace_t> {
+ public:
+ CefV8StackTraceCToCpp();
+ virtual ~CefV8StackTraceCToCpp();
+
+ // CefV8StackTrace methods.
+ bool IsValid() override;
+ int GetFrameCount() override;
+ CefRefPtr<CefV8StackFrame> GetFrame(int index) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_V8STACK_TRACE_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/v8value_ctocpp.cc b/libcef_dll/ctocpp/v8value_ctocpp.cc
new file mode 100644
index 00000000..c133362a
--- /dev/null
+++ b/libcef_dll/ctocpp/v8value_ctocpp.cc
@@ -0,0 +1,1139 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=f60bd8d4d46c4b8ae247f9a0e0b9827f450635d3$
+//
+
+#include "libcef_dll/ctocpp/v8value_ctocpp.h"
+#include "libcef_dll/cpptoc/base_ref_counted_cpptoc.h"
+#include "libcef_dll/cpptoc/v8accessor_cpptoc.h"
+#include "libcef_dll/cpptoc/v8array_buffer_release_callback_cpptoc.h"
+#include "libcef_dll/cpptoc/v8handler_cpptoc.h"
+#include "libcef_dll/cpptoc/v8interceptor_cpptoc.h"
+#include "libcef_dll/ctocpp/v8context_ctocpp.h"
+#include "libcef_dll/ctocpp/v8exception_ctocpp.h"
+#include "libcef_dll/transfer_util.h"
+
+// STATIC METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefV8Value> CefV8Value::CreateUndefined() {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_v8value_t* _retval = cef_v8value_create_undefined();
+
+ // Return type: refptr_same
+ return CefV8ValueCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefV8Value> CefV8Value::CreateNull() {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_v8value_t* _retval = cef_v8value_create_null();
+
+ // Return type: refptr_same
+ return CefV8ValueCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefV8Value> CefV8Value::CreateBool(bool value) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_v8value_t* _retval = cef_v8value_create_bool(value);
+
+ // Return type: refptr_same
+ return CefV8ValueCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefV8Value> CefV8Value::CreateInt(int32 value) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_v8value_t* _retval = cef_v8value_create_int(value);
+
+ // Return type: refptr_same
+ return CefV8ValueCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefV8Value> CefV8Value::CreateUInt(uint32 value) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_v8value_t* _retval = cef_v8value_create_uint(value);
+
+ // Return type: refptr_same
+ return CefV8ValueCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefV8Value> CefV8Value::CreateDouble(double value) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_v8value_t* _retval = cef_v8value_create_double(value);
+
+ // Return type: refptr_same
+ return CefV8ValueCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefV8Value> CefV8Value::CreateDate(CefBaseTime date) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_v8value_t* _retval = cef_v8value_create_date(date);
+
+ // Return type: refptr_same
+ return CefV8ValueCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefV8Value> CefV8Value::CreateString(const CefString& value) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: value
+
+ // Execute
+ cef_v8value_t* _retval = cef_v8value_create_string(value.GetStruct());
+
+ // Return type: refptr_same
+ return CefV8ValueCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefV8Value> CefV8Value::CreateObject(
+ CefRefPtr<CefV8Accessor> accessor,
+ CefRefPtr<CefV8Interceptor> interceptor) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: accessor, interceptor
+
+ // Execute
+ cef_v8value_t* _retval =
+ cef_v8value_create_object(CefV8AccessorCppToC::Wrap(accessor),
+ CefV8InterceptorCppToC::Wrap(interceptor));
+
+ // Return type: refptr_same
+ return CefV8ValueCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefV8Value> CefV8Value::CreateArray(int length) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_v8value_t* _retval = cef_v8value_create_array(length);
+
+ // Return type: refptr_same
+ return CefV8ValueCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefV8Value> CefV8Value::CreateArrayBuffer(
+ void* buffer,
+ size_t length,
+ CefRefPtr<CefV8ArrayBufferReleaseCallback> release_callback) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: buffer; type: simple_byaddr
+ DCHECK(buffer);
+ if (!buffer) {
+ return nullptr;
+ }
+ // Verify param: release_callback; type: refptr_diff
+ DCHECK(release_callback.get());
+ if (!release_callback.get()) {
+ return nullptr;
+ }
+
+ // Execute
+ cef_v8value_t* _retval = cef_v8value_create_array_buffer(
+ buffer, length,
+ CefV8ArrayBufferReleaseCallbackCppToC::Wrap(release_callback));
+
+ // Return type: refptr_same
+ return CefV8ValueCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefV8Value> CefV8Value::CreateFunction(
+ const CefString& name,
+ CefRefPtr<CefV8Handler> handler) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: name; type: string_byref_const
+ DCHECK(!name.empty());
+ if (name.empty()) {
+ return nullptr;
+ }
+ // Verify param: handler; type: refptr_diff
+ DCHECK(handler.get());
+ if (!handler.get()) {
+ return nullptr;
+ }
+
+ // Execute
+ cef_v8value_t* _retval = cef_v8value_create_function(
+ name.GetStruct(), CefV8HandlerCppToC::Wrap(handler));
+
+ // Return type: refptr_same
+ return CefV8ValueCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefV8Value> CefV8Value::CreatePromise() {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_v8value_t* _retval = cef_v8value_create_promise();
+
+ // Return type: refptr_same
+ return CefV8ValueCToCpp::Wrap(_retval);
+}
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") bool CefV8ValueCToCpp::IsValid() {
+ cef_v8value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_valid)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_valid(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefV8ValueCToCpp::IsUndefined() {
+ cef_v8value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_undefined)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_undefined(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefV8ValueCToCpp::IsNull() {
+ cef_v8value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_null)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_null(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefV8ValueCToCpp::IsBool() {
+ cef_v8value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_bool)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_bool(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefV8ValueCToCpp::IsInt() {
+ cef_v8value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_int)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_int(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefV8ValueCToCpp::IsUInt() {
+ cef_v8value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_uint)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_uint(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefV8ValueCToCpp::IsDouble() {
+ cef_v8value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_double)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_double(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefV8ValueCToCpp::IsDate() {
+ cef_v8value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_date)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_date(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefV8ValueCToCpp::IsString() {
+ cef_v8value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_string)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_string(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefV8ValueCToCpp::IsObject() {
+ cef_v8value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_object)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_object(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefV8ValueCToCpp::IsArray() {
+ cef_v8value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_array)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_array(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefV8ValueCToCpp::IsArrayBuffer() {
+ cef_v8value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_array_buffer)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_array_buffer(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefV8ValueCToCpp::IsFunction() {
+ cef_v8value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_function)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_function(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefV8ValueCToCpp::IsPromise() {
+ cef_v8value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_promise)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_promise(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefV8ValueCToCpp::IsSame(CefRefPtr<CefV8Value> that) {
+ cef_v8value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_same)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: that; type: refptr_same
+ DCHECK(that.get());
+ if (!that.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->is_same(_struct, CefV8ValueCToCpp::Unwrap(that));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefV8ValueCToCpp::GetBoolValue() {
+ cef_v8value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_bool_value)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_bool_value(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") int32 CefV8ValueCToCpp::GetIntValue() {
+ cef_v8value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_int_value)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int32 _retval = _struct->get_int_value(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") uint32 CefV8ValueCToCpp::GetUIntValue() {
+ cef_v8value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_uint_value)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ uint32 _retval = _struct->get_uint_value(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") double CefV8ValueCToCpp::GetDoubleValue() {
+ cef_v8value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_double_value)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ double _retval = _struct->get_double_value(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") CefBaseTime CefV8ValueCToCpp::GetDateValue() {
+ cef_v8value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_date_value)) {
+ return CefBaseTime();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_basetime_t _retval = _struct->get_date_value(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") CefString CefV8ValueCToCpp::GetStringValue() {
+ cef_v8value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_string_value)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_string_value(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") bool CefV8ValueCToCpp::IsUserCreated() {
+ cef_v8value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_user_created)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_user_created(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefV8ValueCToCpp::HasException() {
+ cef_v8value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, has_exception)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->has_exception(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefV8Exception> CefV8ValueCToCpp::GetException() {
+ cef_v8value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_exception)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_v8exception_t* _retval = _struct->get_exception(_struct);
+
+ // Return type: refptr_same
+ return CefV8ExceptionCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") bool CefV8ValueCToCpp::ClearException() {
+ cef_v8value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, clear_exception)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->clear_exception(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefV8ValueCToCpp::WillRethrowExceptions() {
+ cef_v8value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, will_rethrow_exceptions)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->will_rethrow_exceptions(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefV8ValueCToCpp::SetRethrowExceptions(bool rethrow) {
+ cef_v8value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_rethrow_exceptions)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->set_rethrow_exceptions(_struct, rethrow);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefV8ValueCToCpp::HasValue(const CefString& key) {
+ cef_v8value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, has_value_bykey)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: key
+
+ // Execute
+ int _retval = _struct->has_value_bykey(_struct, key.GetStruct());
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefV8ValueCToCpp::HasValue(int index) {
+ cef_v8value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, has_value_byindex)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: index; type: simple_byval
+ DCHECK_GE(index, 0);
+ if (index < 0) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->has_value_byindex(_struct, index);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefV8ValueCToCpp::DeleteValue(const CefString& key) {
+ cef_v8value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, delete_value_bykey)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: key
+
+ // Execute
+ int _retval = _struct->delete_value_bykey(_struct, key.GetStruct());
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefV8ValueCToCpp::DeleteValue(int index) {
+ cef_v8value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, delete_value_byindex)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: index; type: simple_byval
+ DCHECK_GE(index, 0);
+ if (index < 0) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->delete_value_byindex(_struct, index);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefV8Value> CefV8ValueCToCpp::GetValue(const CefString& key) {
+ cef_v8value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_value_bykey)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: key
+
+ // Execute
+ cef_v8value_t* _retval = _struct->get_value_bykey(_struct, key.GetStruct());
+
+ // Return type: refptr_same
+ return CefV8ValueCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefV8Value> CefV8ValueCToCpp::GetValue(int index) {
+ cef_v8value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_value_byindex)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: index; type: simple_byval
+ DCHECK_GE(index, 0);
+ if (index < 0) {
+ return nullptr;
+ }
+
+ // Execute
+ cef_v8value_t* _retval = _struct->get_value_byindex(_struct, index);
+
+ // Return type: refptr_same
+ return CefV8ValueCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefV8ValueCToCpp::SetValue(const CefString& key,
+ CefRefPtr<CefV8Value> value,
+ PropertyAttribute attribute) {
+ cef_v8value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_value_bykey)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: value; type: refptr_same
+ DCHECK(value.get());
+ if (!value.get()) {
+ return false;
+ }
+ // Unverified params: key
+
+ // Execute
+ int _retval = _struct->set_value_bykey(
+ _struct, key.GetStruct(), CefV8ValueCToCpp::Unwrap(value), attribute);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefV8ValueCToCpp::SetValue(int index, CefRefPtr<CefV8Value> value) {
+ cef_v8value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_value_byindex)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: index; type: simple_byval
+ DCHECK_GE(index, 0);
+ if (index < 0) {
+ return false;
+ }
+ // Verify param: value; type: refptr_same
+ DCHECK(value.get());
+ if (!value.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->set_value_byindex(_struct, index,
+ CefV8ValueCToCpp::Unwrap(value));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefV8ValueCToCpp::SetValue(const CefString& key,
+ AccessControl settings,
+ PropertyAttribute attribute) {
+ cef_v8value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_value_byaccessor)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: key
+
+ // Execute
+ int _retval = _struct->set_value_byaccessor(_struct, key.GetStruct(),
+ settings, attribute);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefV8ValueCToCpp::GetKeys(std::vector<CefString>& keys) {
+ cef_v8value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_keys)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Translate param: keys; type: string_vec_byref
+ cef_string_list_t keysList = cef_string_list_alloc();
+ DCHECK(keysList);
+ if (keysList) {
+ transfer_string_list_contents(keys, keysList);
+ }
+
+ // Execute
+ int _retval = _struct->get_keys(_struct, keysList);
+
+ // Restore param:keys; type: string_vec_byref
+ if (keysList) {
+ keys.clear();
+ transfer_string_list_contents(keysList, keys);
+ cef_string_list_free(keysList);
+ }
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefV8ValueCToCpp::SetUserData(CefRefPtr<CefBaseRefCounted> user_data) {
+ cef_v8value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_user_data)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: user_data
+
+ // Execute
+ int _retval =
+ _struct->set_user_data(_struct, CefBaseRefCountedCppToC::Wrap(user_data));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefBaseRefCounted> CefV8ValueCToCpp::GetUserData() {
+ cef_v8value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_user_data)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_base_ref_counted_t* _retval = _struct->get_user_data(_struct);
+
+ // Return type: refptr_diff
+ return CefBaseRefCountedCppToC::Unwrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") int CefV8ValueCToCpp::GetExternallyAllocatedMemory() {
+ cef_v8value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_externally_allocated_memory)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_externally_allocated_memory(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+int CefV8ValueCToCpp::AdjustExternallyAllocatedMemory(int change_in_bytes) {
+ cef_v8value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, adjust_externally_allocated_memory)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval =
+ _struct->adjust_externally_allocated_memory(_struct, change_in_bytes);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") int CefV8ValueCToCpp::GetArrayLength() {
+ cef_v8value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_array_length)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_array_length(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefV8ArrayBufferReleaseCallback>
+CefV8ValueCToCpp::GetArrayBufferReleaseCallback() {
+ cef_v8value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_array_buffer_release_callback)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_v8array_buffer_release_callback_t* _retval =
+ _struct->get_array_buffer_release_callback(_struct);
+
+ // Return type: refptr_diff
+ return CefV8ArrayBufferReleaseCallbackCppToC::Unwrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") bool CefV8ValueCToCpp::NeuterArrayBuffer() {
+ cef_v8value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, neuter_array_buffer)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->neuter_array_buffer(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") CefString CefV8ValueCToCpp::GetFunctionName() {
+ cef_v8value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_function_name)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_function_name(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefV8Handler> CefV8ValueCToCpp::GetFunctionHandler() {
+ cef_v8value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_function_handler)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_v8handler_t* _retval = _struct->get_function_handler(_struct);
+
+ // Return type: refptr_diff
+ return CefV8HandlerCppToC::Unwrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefV8Value> CefV8ValueCToCpp::ExecuteFunction(
+ CefRefPtr<CefV8Value> object,
+ const CefV8ValueList& arguments) {
+ cef_v8value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, execute_function)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: object
+
+ // Translate param: arguments; type: refptr_vec_same_byref_const
+ const size_t argumentsCount = arguments.size();
+ cef_v8value_t** argumentsList = NULL;
+ if (argumentsCount > 0) {
+ argumentsList = new cef_v8value_t*[argumentsCount];
+ DCHECK(argumentsList);
+ if (argumentsList) {
+ for (size_t i = 0; i < argumentsCount; ++i) {
+ argumentsList[i] = CefV8ValueCToCpp::Unwrap(arguments[i]);
+ }
+ }
+ }
+
+ // Execute
+ cef_v8value_t* _retval = _struct->execute_function(
+ _struct, CefV8ValueCToCpp::Unwrap(object), argumentsCount, argumentsList);
+
+ // Restore param:arguments; type: refptr_vec_same_byref_const
+ if (argumentsList) {
+ delete[] argumentsList;
+ }
+
+ // Return type: refptr_same
+ return CefV8ValueCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefV8Value> CefV8ValueCToCpp::ExecuteFunctionWithContext(
+ CefRefPtr<CefV8Context> context,
+ CefRefPtr<CefV8Value> object,
+ const CefV8ValueList& arguments) {
+ cef_v8value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, execute_function_with_context)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: context; type: refptr_same
+ DCHECK(context.get());
+ if (!context.get()) {
+ return nullptr;
+ }
+ // Unverified params: object
+
+ // Translate param: arguments; type: refptr_vec_same_byref_const
+ const size_t argumentsCount = arguments.size();
+ cef_v8value_t** argumentsList = NULL;
+ if (argumentsCount > 0) {
+ argumentsList = new cef_v8value_t*[argumentsCount];
+ DCHECK(argumentsList);
+ if (argumentsList) {
+ for (size_t i = 0; i < argumentsCount; ++i) {
+ argumentsList[i] = CefV8ValueCToCpp::Unwrap(arguments[i]);
+ }
+ }
+ }
+
+ // Execute
+ cef_v8value_t* _retval = _struct->execute_function_with_context(
+ _struct, CefV8ContextCToCpp::Unwrap(context),
+ CefV8ValueCToCpp::Unwrap(object), argumentsCount, argumentsList);
+
+ // Restore param:arguments; type: refptr_vec_same_byref_const
+ if (argumentsList) {
+ delete[] argumentsList;
+ }
+
+ // Return type: refptr_same
+ return CefV8ValueCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefV8ValueCToCpp::ResolvePromise(CefRefPtr<CefV8Value> arg) {
+ cef_v8value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, resolve_promise)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: arg
+
+ // Execute
+ int _retval =
+ _struct->resolve_promise(_struct, CefV8ValueCToCpp::Unwrap(arg));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefV8ValueCToCpp::RejectPromise(const CefString& errorMsg) {
+ cef_v8value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, reject_promise)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: errorMsg; type: string_byref_const
+ DCHECK(!errorMsg.empty());
+ if (errorMsg.empty()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->reject_promise(_struct, errorMsg.GetStruct());
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefV8ValueCToCpp::CefV8ValueCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefV8ValueCToCpp::~CefV8ValueCToCpp() {}
+
+template <>
+cef_v8value_t*
+CefCToCppRefCounted<CefV8ValueCToCpp, CefV8Value, cef_v8value_t>::UnwrapDerived(
+ CefWrapperType type,
+ CefV8Value* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefV8ValueCToCpp,
+ CefV8Value,
+ cef_v8value_t>::kWrapperType = WT_V8VALUE;
diff --git a/libcef_dll/ctocpp/v8value_ctocpp.h b/libcef_dll/ctocpp/v8value_ctocpp.h
new file mode 100644
index 00000000..b9137cc2
--- /dev/null
+++ b/libcef_dll/ctocpp/v8value_ctocpp.h
@@ -0,0 +1,99 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=ec4b3cb221b3fcfb0f8f5e35aa351d3696cb78bb$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_V8VALUE_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_V8VALUE_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include <vector>
+#include "include/capi/cef_v8_capi.h"
+#include "include/cef_v8.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefV8ValueCToCpp
+ : public CefCToCppRefCounted<CefV8ValueCToCpp, CefV8Value, cef_v8value_t> {
+ public:
+ CefV8ValueCToCpp();
+ virtual ~CefV8ValueCToCpp();
+
+ // CefV8Value methods.
+ bool IsValid() override;
+ bool IsUndefined() override;
+ bool IsNull() override;
+ bool IsBool() override;
+ bool IsInt() override;
+ bool IsUInt() override;
+ bool IsDouble() override;
+ bool IsDate() override;
+ bool IsString() override;
+ bool IsObject() override;
+ bool IsArray() override;
+ bool IsArrayBuffer() override;
+ bool IsFunction() override;
+ bool IsPromise() override;
+ bool IsSame(CefRefPtr<CefV8Value> that) override;
+ bool GetBoolValue() override;
+ int32 GetIntValue() override;
+ uint32 GetUIntValue() override;
+ double GetDoubleValue() override;
+ CefBaseTime GetDateValue() override;
+ CefString GetStringValue() override;
+ bool IsUserCreated() override;
+ bool HasException() override;
+ CefRefPtr<CefV8Exception> GetException() override;
+ bool ClearException() override;
+ bool WillRethrowExceptions() override;
+ bool SetRethrowExceptions(bool rethrow) override;
+ bool HasValue(const CefString& key) override;
+ bool HasValue(int index) override;
+ bool DeleteValue(const CefString& key) override;
+ bool DeleteValue(int index) override;
+ CefRefPtr<CefV8Value> GetValue(const CefString& key) override;
+ CefRefPtr<CefV8Value> GetValue(int index) override;
+ bool SetValue(const CefString& key,
+ CefRefPtr<CefV8Value> value,
+ PropertyAttribute attribute) override;
+ bool SetValue(int index, CefRefPtr<CefV8Value> value) override;
+ bool SetValue(const CefString& key,
+ AccessControl settings,
+ PropertyAttribute attribute) override;
+ bool GetKeys(std::vector<CefString>& keys) override;
+ bool SetUserData(CefRefPtr<CefBaseRefCounted> user_data) override;
+ CefRefPtr<CefBaseRefCounted> GetUserData() override;
+ int GetExternallyAllocatedMemory() override;
+ int AdjustExternallyAllocatedMemory(int change_in_bytes) override;
+ int GetArrayLength() override;
+ CefRefPtr<CefV8ArrayBufferReleaseCallback> GetArrayBufferReleaseCallback()
+ override;
+ bool NeuterArrayBuffer() override;
+ CefString GetFunctionName() override;
+ CefRefPtr<CefV8Handler> GetFunctionHandler() override;
+ CefRefPtr<CefV8Value> ExecuteFunction(
+ CefRefPtr<CefV8Value> object,
+ const CefV8ValueList& arguments) override;
+ CefRefPtr<CefV8Value> ExecuteFunctionWithContext(
+ CefRefPtr<CefV8Context> context,
+ CefRefPtr<CefV8Value> object,
+ const CefV8ValueList& arguments) override;
+ bool ResolvePromise(CefRefPtr<CefV8Value> arg) override;
+ bool RejectPromise(const CefString& errorMsg) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_V8VALUE_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/value_ctocpp.cc b/libcef_dll/ctocpp/value_ctocpp.cc
new file mode 100644
index 00000000..b55cce5e
--- /dev/null
+++ b/libcef_dll/ctocpp/value_ctocpp.cc
@@ -0,0 +1,475 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=44707a75bb7e703e880eb1f3da22e1724c32d1d3$
+//
+
+#include "libcef_dll/ctocpp/value_ctocpp.h"
+#include "libcef_dll/ctocpp/binary_value_ctocpp.h"
+#include "libcef_dll/ctocpp/dictionary_value_ctocpp.h"
+#include "libcef_dll/ctocpp/list_value_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// STATIC METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefValue> CefValue::Create() {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_value_t* _retval = cef_value_create();
+
+ // Return type: refptr_same
+ return CefValueCToCpp::Wrap(_retval);
+}
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") bool CefValueCToCpp::IsValid() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_valid)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_valid(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefValueCToCpp::IsOwned() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_owned)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_owned(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefValueCToCpp::IsReadOnly() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_read_only)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_read_only(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefValueCToCpp::IsSame(CefRefPtr<CefValue> that) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_same)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: that; type: refptr_same
+ DCHECK(that.get());
+ if (!that.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->is_same(_struct, CefValueCToCpp::Unwrap(that));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefValueCToCpp::IsEqual(CefRefPtr<CefValue> that) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_equal)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: that; type: refptr_same
+ DCHECK(that.get());
+ if (!that.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->is_equal(_struct, CefValueCToCpp::Unwrap(that));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefValue> CefValueCToCpp::Copy() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, copy)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_value_t* _retval = _struct->copy(_struct);
+
+ // Return type: refptr_same
+ return CefValueCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") CefValueType CefValueCToCpp::GetType() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_type)) {
+ return VTYPE_INVALID;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_value_type_t _retval = _struct->get_type(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") bool CefValueCToCpp::GetBool() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_bool)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_bool(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") int CefValueCToCpp::GetInt() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_int)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_int(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") double CefValueCToCpp::GetDouble() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_double)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ double _retval = _struct->get_double(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") CefString CefValueCToCpp::GetString() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_string)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_string(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefBinaryValue> CefValueCToCpp::GetBinary() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_binary)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_binary_value_t* _retval = _struct->get_binary(_struct);
+
+ // Return type: refptr_same
+ return CefBinaryValueCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefDictionaryValue> CefValueCToCpp::GetDictionary() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_dictionary)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_dictionary_value_t* _retval = _struct->get_dictionary(_struct);
+
+ // Return type: refptr_same
+ return CefDictionaryValueCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefListValue> CefValueCToCpp::GetList() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_list)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_list_value_t* _retval = _struct->get_list(_struct);
+
+ // Return type: refptr_same
+ return CefListValueCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") bool CefValueCToCpp::SetNull() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_null)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->set_null(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefValueCToCpp::SetBool(bool value) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_bool)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->set_bool(_struct, value);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefValueCToCpp::SetInt(int value) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_int)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->set_int(_struct, value);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefValueCToCpp::SetDouble(double value) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_double)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->set_double(_struct, value);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefValueCToCpp::SetString(const CefString& value) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_string)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: value
+
+ // Execute
+ int _retval = _struct->set_string(_struct, value.GetStruct());
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefValueCToCpp::SetBinary(CefRefPtr<CefBinaryValue> value) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_binary)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: value; type: refptr_same
+ DCHECK(value.get());
+ if (!value.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval =
+ _struct->set_binary(_struct, CefBinaryValueCToCpp::Unwrap(value));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefValueCToCpp::SetDictionary(CefRefPtr<CefDictionaryValue> value) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_dictionary)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: value; type: refptr_same
+ DCHECK(value.get());
+ if (!value.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval =
+ _struct->set_dictionary(_struct, CefDictionaryValueCToCpp::Unwrap(value));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefValueCToCpp::SetList(CefRefPtr<CefListValue> value) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_value_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_list)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: value; type: refptr_same
+ DCHECK(value.get());
+ if (!value.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->set_list(_struct, CefListValueCToCpp::Unwrap(value));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefValueCToCpp::CefValueCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefValueCToCpp::~CefValueCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_value_t*
+CefCToCppRefCounted<CefValueCToCpp, CefValue, cef_value_t>::UnwrapDerived(
+ CefWrapperType type,
+ CefValue* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCToCppRefCounted<CefValueCToCpp, CefValue, cef_value_t>::kWrapperType =
+ WT_VALUE;
diff --git a/libcef_dll/ctocpp/value_ctocpp.h b/libcef_dll/ctocpp/value_ctocpp.h
new file mode 100644
index 00000000..9b31150c
--- /dev/null
+++ b/libcef_dll/ctocpp/value_ctocpp.h
@@ -0,0 +1,60 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=80621c9fcd1e112984ddb490da40034e9731d530$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_VALUE_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_VALUE_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_values_capi.h"
+#include "include/cef_values.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefValueCToCpp
+ : public CefCToCppRefCounted<CefValueCToCpp, CefValue, cef_value_t> {
+ public:
+ CefValueCToCpp();
+ virtual ~CefValueCToCpp();
+
+ // CefValue methods.
+ bool IsValid() override;
+ bool IsOwned() override;
+ bool IsReadOnly() override;
+ bool IsSame(CefRefPtr<CefValue> that) override;
+ bool IsEqual(CefRefPtr<CefValue> that) override;
+ CefRefPtr<CefValue> Copy() override;
+ CefValueType GetType() override;
+ bool GetBool() override;
+ int GetInt() override;
+ double GetDouble() override;
+ CefString GetString() override;
+ CefRefPtr<CefBinaryValue> GetBinary() override;
+ CefRefPtr<CefDictionaryValue> GetDictionary() override;
+ CefRefPtr<CefListValue> GetList() override;
+ bool SetNull() override;
+ bool SetBool(bool value) override;
+ bool SetInt(int value) override;
+ bool SetDouble(double value) override;
+ bool SetString(const CefString& value) override;
+ bool SetBinary(CefRefPtr<CefBinaryValue> value) override;
+ bool SetDictionary(CefRefPtr<CefDictionaryValue> value) override;
+ bool SetList(CefRefPtr<CefListValue> value) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_VALUE_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/views/box_layout_ctocpp.cc b/libcef_dll/ctocpp/views/box_layout_ctocpp.cc
new file mode 100644
index 00000000..20f09142
--- /dev/null
+++ b/libcef_dll/ctocpp/views/box_layout_ctocpp.cc
@@ -0,0 +1,139 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=375ba9e9a373da9833cd7a549cdad0b0ee0c203c$
+//
+
+#include "libcef_dll/ctocpp/views/box_layout_ctocpp.h"
+#include "libcef_dll/ctocpp/views/fill_layout_ctocpp.h"
+#include "libcef_dll/ctocpp/views/view_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+void CefBoxLayoutCToCpp::SetFlexForView(CefRefPtr<CefView> view, int flex) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_box_layout_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_flex_for_view)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_same
+ DCHECK(view.get());
+ if (!view.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->set_flex_for_view(_struct, CefViewCToCpp::Unwrap(view), flex);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefBoxLayoutCToCpp::ClearFlexForView(CefRefPtr<CefView> view) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_box_layout_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, clear_flex_for_view)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_same
+ DCHECK(view.get());
+ if (!view.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->clear_flex_for_view(_struct, CefViewCToCpp::Unwrap(view));
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefBoxLayout> CefBoxLayoutCToCpp::AsBoxLayout() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_layout_t* _struct = reinterpret_cast<cef_layout_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, as_box_layout)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_box_layout_t* _retval = _struct->as_box_layout(_struct);
+
+ // Return type: refptr_same
+ return CefBoxLayoutCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefFillLayout> CefBoxLayoutCToCpp::AsFillLayout() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_layout_t* _struct = reinterpret_cast<cef_layout_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, as_fill_layout)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_fill_layout_t* _retval = _struct->as_fill_layout(_struct);
+
+ // Return type: refptr_same
+ return CefFillLayoutCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") bool CefBoxLayoutCToCpp::IsValid() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_layout_t* _struct = reinterpret_cast<cef_layout_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_valid)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_valid(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefBoxLayoutCToCpp::CefBoxLayoutCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefBoxLayoutCToCpp::~CefBoxLayoutCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_box_layout_t*
+CefCToCppRefCounted<CefBoxLayoutCToCpp, CefBoxLayout, cef_box_layout_t>::
+ UnwrapDerived(CefWrapperType type, CefBoxLayout* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefBoxLayoutCToCpp,
+ CefBoxLayout,
+ cef_box_layout_t>::kWrapperType =
+ WT_BOX_LAYOUT;
diff --git a/libcef_dll/ctocpp/views/box_layout_ctocpp.h b/libcef_dll/ctocpp/views/box_layout_ctocpp.h
new file mode 100644
index 00000000..6639e642
--- /dev/null
+++ b/libcef_dll/ctocpp/views/box_layout_ctocpp.h
@@ -0,0 +1,48 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=c14b6372ec4705cdcbcebc6d7367fe0c3c544001$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_VIEWS_BOX_LAYOUT_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_VIEWS_BOX_LAYOUT_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/views/cef_box_layout_capi.h"
+#include "include/capi/views/cef_view_capi.h"
+#include "include/views/cef_box_layout.h"
+#include "include/views/cef_view.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefBoxLayoutCToCpp : public CefCToCppRefCounted<CefBoxLayoutCToCpp,
+ CefBoxLayout,
+ cef_box_layout_t> {
+ public:
+ CefBoxLayoutCToCpp();
+ virtual ~CefBoxLayoutCToCpp();
+
+ // CefBoxLayout methods.
+ void SetFlexForView(CefRefPtr<CefView> view, int flex) override;
+ void ClearFlexForView(CefRefPtr<CefView> view) override;
+
+ // CefLayout methods.
+ CefRefPtr<CefBoxLayout> AsBoxLayout() override;
+ CefRefPtr<CefFillLayout> AsFillLayout() override;
+ bool IsValid() override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_VIEWS_BOX_LAYOUT_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/views/browser_view_ctocpp.cc b/libcef_dll/ctocpp/views/browser_view_ctocpp.cc
new file mode 100644
index 00000000..5b42d619
--- /dev/null
+++ b/libcef_dll/ctocpp/views/browser_view_ctocpp.cc
@@ -0,0 +1,1013 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=e9970bfc276e4a6a7fc99f0d8c2eccd8bb60903e$
+//
+
+#include "libcef_dll/ctocpp/views/browser_view_ctocpp.h"
+#include "libcef_dll/cpptoc/client_cpptoc.h"
+#include "libcef_dll/cpptoc/views/browser_view_delegate_cpptoc.h"
+#include "libcef_dll/cpptoc/views/view_delegate_cpptoc.h"
+#include "libcef_dll/ctocpp/browser_ctocpp.h"
+#include "libcef_dll/ctocpp/dictionary_value_ctocpp.h"
+#include "libcef_dll/ctocpp/request_context_ctocpp.h"
+#include "libcef_dll/ctocpp/views/button_ctocpp.h"
+#include "libcef_dll/ctocpp/views/panel_ctocpp.h"
+#include "libcef_dll/ctocpp/views/scroll_view_ctocpp.h"
+#include "libcef_dll/ctocpp/views/textfield_ctocpp.h"
+#include "libcef_dll/ctocpp/views/view_ctocpp.h"
+#include "libcef_dll/ctocpp/views/window_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// STATIC METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefBrowserView> CefBrowserView::CreateBrowserView(
+ CefRefPtr<CefClient> client,
+ const CefString& url,
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefDictionaryValue> extra_info,
+ CefRefPtr<CefRequestContext> request_context,
+ CefRefPtr<CefBrowserViewDelegate> delegate) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: client, url, extra_info, request_context, delegate
+
+ // Execute
+ cef_browser_view_t* _retval = cef_browser_view_create(
+ CefClientCppToC::Wrap(client), url.GetStruct(), &settings,
+ CefDictionaryValueCToCpp::Unwrap(extra_info),
+ CefRequestContextCToCpp::Unwrap(request_context),
+ CefBrowserViewDelegateCppToC::Wrap(delegate));
+
+ // Return type: refptr_same
+ return CefBrowserViewCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefBrowserView> CefBrowserView::GetForBrowser(
+ CefRefPtr<CefBrowser> browser) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser; type: refptr_same
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return nullptr;
+ }
+
+ // Execute
+ cef_browser_view_t* _retval =
+ cef_browser_view_get_for_browser(CefBrowserCToCpp::Unwrap(browser));
+
+ // Return type: refptr_same
+ return CefBrowserViewCToCpp::Wrap(_retval);
+}
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefBrowser> CefBrowserViewCToCpp::GetBrowser() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_browser)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_browser_t* _retval = _struct->get_browser(_struct);
+
+ // Return type: refptr_same
+ return CefBrowserCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefView> CefBrowserViewCToCpp::GetChromeToolbar() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_chrome_toolbar)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_view_t* _retval = _struct->get_chrome_toolbar(_struct);
+
+ // Return type: refptr_same
+ return CefViewCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefBrowserViewCToCpp::SetPreferAccelerators(bool prefer_accelerators) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_prefer_accelerators)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_prefer_accelerators(_struct, prefer_accelerators);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefBrowserView> CefBrowserViewCToCpp::AsBrowserView() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, as_browser_view)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_browser_view_t* _retval = _struct->as_browser_view(_struct);
+
+ // Return type: refptr_same
+ return CefBrowserViewCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefButton> CefBrowserViewCToCpp::AsButton() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, as_button)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_button_t* _retval = _struct->as_button(_struct);
+
+ // Return type: refptr_same
+ return CefButtonCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefPanel> CefBrowserViewCToCpp::AsPanel() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, as_panel)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_panel_t* _retval = _struct->as_panel(_struct);
+
+ // Return type: refptr_same
+ return CefPanelCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefScrollView> CefBrowserViewCToCpp::AsScrollView() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, as_scroll_view)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_scroll_view_t* _retval = _struct->as_scroll_view(_struct);
+
+ // Return type: refptr_same
+ return CefScrollViewCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefTextfield> CefBrowserViewCToCpp::AsTextfield() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, as_textfield)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_textfield_t* _retval = _struct->as_textfield(_struct);
+
+ // Return type: refptr_same
+ return CefTextfieldCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") CefString CefBrowserViewCToCpp::GetTypeString() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_type_string)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_type_string(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+CefString CefBrowserViewCToCpp::ToString(bool include_children) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, to_string)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->to_string(_struct, include_children);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") bool CefBrowserViewCToCpp::IsValid() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_valid)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_valid(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefBrowserViewCToCpp::IsAttached() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_attached)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_attached(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefBrowserViewCToCpp::IsSame(CefRefPtr<CefView> that) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_same)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: that; type: refptr_same
+ DCHECK(that.get());
+ if (!that.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->is_same(_struct, CefViewCToCpp::Unwrap(that));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefViewDelegate> CefBrowserViewCToCpp::GetDelegate() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_delegate)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_view_delegate_t* _retval = _struct->get_delegate(_struct);
+
+ // Return type: refptr_diff
+ return CefViewDelegateCppToC::Unwrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefWindow> CefBrowserViewCToCpp::GetWindow() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_window)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_window_t* _retval = _struct->get_window(_struct);
+
+ // Return type: refptr_same
+ return CefWindowCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") int CefBrowserViewCToCpp::GetID() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_id)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_id(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") void CefBrowserViewCToCpp::SetID(int id) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_id)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_id(_struct, id);
+}
+
+NO_SANITIZE("cfi-icall") int CefBrowserViewCToCpp::GetGroupID() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_group_id)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_group_id(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") void CefBrowserViewCToCpp::SetGroupID(int group_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_group_id)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_group_id(_struct, group_id);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefView> CefBrowserViewCToCpp::GetParentView() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_parent_view)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_view_t* _retval = _struct->get_parent_view(_struct);
+
+ // Return type: refptr_same
+ return CefViewCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefView> CefBrowserViewCToCpp::GetViewForID(int id) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_view_for_id)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_view_t* _retval = _struct->get_view_for_id(_struct, id);
+
+ // Return type: refptr_same
+ return CefViewCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefBrowserViewCToCpp::SetBounds(const CefRect& bounds) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_bounds)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_bounds(_struct, &bounds);
+}
+
+NO_SANITIZE("cfi-icall") CefRect CefBrowserViewCToCpp::GetBounds() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_bounds)) {
+ return CefRect();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_rect_t _retval = _struct->get_bounds(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") CefRect CefBrowserViewCToCpp::GetBoundsInScreen() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_bounds_in_screen)) {
+ return CefRect();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_rect_t _retval = _struct->get_bounds_in_screen(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefBrowserViewCToCpp::SetSize(const CefSize& size) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_size)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_size(_struct, &size);
+}
+
+NO_SANITIZE("cfi-icall") CefSize CefBrowserViewCToCpp::GetSize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_size_t _retval = _struct->get_size(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefBrowserViewCToCpp::SetPosition(const CefPoint& position) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_position)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_position(_struct, &position);
+}
+
+NO_SANITIZE("cfi-icall") CefPoint CefBrowserViewCToCpp::GetPosition() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_position)) {
+ return CefPoint();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_point_t _retval = _struct->get_position(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefBrowserViewCToCpp::SetInsets(const CefInsets& insets) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_insets)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_insets(_struct, &insets);
+}
+
+NO_SANITIZE("cfi-icall") CefInsets CefBrowserViewCToCpp::GetInsets() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_insets)) {
+ return CefInsets();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_insets_t _retval = _struct->get_insets(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") CefSize CefBrowserViewCToCpp::GetPreferredSize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_preferred_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_size_t _retval = _struct->get_preferred_size(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") void CefBrowserViewCToCpp::SizeToPreferredSize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, size_to_preferred_size)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->size_to_preferred_size(_struct);
+}
+
+NO_SANITIZE("cfi-icall") CefSize CefBrowserViewCToCpp::GetMinimumSize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_minimum_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_size_t _retval = _struct->get_minimum_size(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") CefSize CefBrowserViewCToCpp::GetMaximumSize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_maximum_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_size_t _retval = _struct->get_maximum_size(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+int CefBrowserViewCToCpp::GetHeightForWidth(int width) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_height_for_width)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_height_for_width(_struct, width);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") void CefBrowserViewCToCpp::InvalidateLayout() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, invalidate_layout)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->invalidate_layout(_struct);
+}
+
+NO_SANITIZE("cfi-icall") void CefBrowserViewCToCpp::SetVisible(bool visible) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_visible)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_visible(_struct, visible);
+}
+
+NO_SANITIZE("cfi-icall") bool CefBrowserViewCToCpp::IsVisible() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_visible)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_visible(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefBrowserViewCToCpp::IsDrawn() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_drawn)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_drawn(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") void CefBrowserViewCToCpp::SetEnabled(bool enabled) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_enabled)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_enabled(_struct, enabled);
+}
+
+NO_SANITIZE("cfi-icall") bool CefBrowserViewCToCpp::IsEnabled() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_enabled)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_enabled(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefBrowserViewCToCpp::SetFocusable(bool focusable) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_focusable)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_focusable(_struct, focusable);
+}
+
+NO_SANITIZE("cfi-icall") bool CefBrowserViewCToCpp::IsFocusable() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_focusable)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_focusable(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefBrowserViewCToCpp::IsAccessibilityFocusable() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_accessibility_focusable)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_accessibility_focusable(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") void CefBrowserViewCToCpp::RequestFocus() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, request_focus)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->request_focus(_struct);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefBrowserViewCToCpp::SetBackgroundColor(cef_color_t color) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_background_color)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_background_color(_struct, color);
+}
+
+NO_SANITIZE("cfi-icall")
+cef_color_t CefBrowserViewCToCpp::GetBackgroundColor() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_background_color)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_color_t _retval = _struct->get_background_color(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefBrowserViewCToCpp::ConvertPointToScreen(CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, convert_point_to_screen)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->convert_point_to_screen(_struct, &point);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefBrowserViewCToCpp::ConvertPointFromScreen(CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, convert_point_from_screen)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->convert_point_from_screen(_struct, &point);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefBrowserViewCToCpp::ConvertPointToWindow(CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, convert_point_to_window)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->convert_point_to_window(_struct, &point);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefBrowserViewCToCpp::ConvertPointFromWindow(CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, convert_point_from_window)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->convert_point_from_window(_struct, &point);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefBrowserViewCToCpp::ConvertPointToView(CefRefPtr<CefView> view,
+ CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, convert_point_to_view)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_same
+ DCHECK(view.get());
+ if (!view.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->convert_point_to_view(
+ _struct, CefViewCToCpp::Unwrap(view), &point);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefBrowserViewCToCpp::ConvertPointFromView(CefRefPtr<CefView> view,
+ CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, convert_point_from_view)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_same
+ DCHECK(view.get());
+ if (!view.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->convert_point_from_view(
+ _struct, CefViewCToCpp::Unwrap(view), &point);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefBrowserViewCToCpp::CefBrowserViewCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefBrowserViewCToCpp::~CefBrowserViewCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_browser_view_t*
+CefCToCppRefCounted<CefBrowserViewCToCpp, CefBrowserView, cef_browser_view_t>::
+ UnwrapDerived(CefWrapperType type, CefBrowserView* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefBrowserViewCToCpp,
+ CefBrowserView,
+ cef_browser_view_t>::kWrapperType =
+ WT_BROWSER_VIEW;
diff --git a/libcef_dll/ctocpp/views/browser_view_ctocpp.h b/libcef_dll/ctocpp/views/browser_view_ctocpp.h
new file mode 100644
index 00000000..526b63fd
--- /dev/null
+++ b/libcef_dll/ctocpp/views/browser_view_ctocpp.h
@@ -0,0 +1,94 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=3369ae36dfebd0283661566cf91fa57dbfec29e4$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_VIEWS_BROWSER_VIEW_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_VIEWS_BROWSER_VIEW_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/views/cef_browser_view_capi.h"
+#include "include/views/cef_browser_view.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefBrowserViewCToCpp : public CefCToCppRefCounted<CefBrowserViewCToCpp,
+ CefBrowserView,
+ cef_browser_view_t> {
+ public:
+ CefBrowserViewCToCpp();
+ virtual ~CefBrowserViewCToCpp();
+
+ // CefBrowserView methods.
+ CefRefPtr<CefBrowser> GetBrowser() override;
+ CefRefPtr<CefView> GetChromeToolbar() override;
+ void SetPreferAccelerators(bool prefer_accelerators) override;
+
+ // CefView methods.
+ CefRefPtr<CefBrowserView> AsBrowserView() override;
+ CefRefPtr<CefButton> AsButton() override;
+ CefRefPtr<CefPanel> AsPanel() override;
+ CefRefPtr<CefScrollView> AsScrollView() override;
+ CefRefPtr<CefTextfield> AsTextfield() override;
+ CefString GetTypeString() override;
+ CefString ToString(bool include_children) override;
+ bool IsValid() override;
+ bool IsAttached() override;
+ bool IsSame(CefRefPtr<CefView> that) override;
+ CefRefPtr<CefViewDelegate> GetDelegate() override;
+ CefRefPtr<CefWindow> GetWindow() override;
+ int GetID() override;
+ void SetID(int id) override;
+ int GetGroupID() override;
+ void SetGroupID(int group_id) override;
+ CefRefPtr<CefView> GetParentView() override;
+ CefRefPtr<CefView> GetViewForID(int id) override;
+ void SetBounds(const CefRect& bounds) override;
+ CefRect GetBounds() override;
+ CefRect GetBoundsInScreen() override;
+ void SetSize(const CefSize& size) override;
+ CefSize GetSize() override;
+ void SetPosition(const CefPoint& position) override;
+ CefPoint GetPosition() override;
+ void SetInsets(const CefInsets& insets) override;
+ CefInsets GetInsets() override;
+ CefSize GetPreferredSize() override;
+ void SizeToPreferredSize() override;
+ CefSize GetMinimumSize() override;
+ CefSize GetMaximumSize() override;
+ int GetHeightForWidth(int width) override;
+ void InvalidateLayout() override;
+ void SetVisible(bool visible) override;
+ bool IsVisible() override;
+ bool IsDrawn() override;
+ void SetEnabled(bool enabled) override;
+ bool IsEnabled() override;
+ void SetFocusable(bool focusable) override;
+ bool IsFocusable() override;
+ bool IsAccessibilityFocusable() override;
+ void RequestFocus() override;
+ void SetBackgroundColor(cef_color_t color) override;
+ cef_color_t GetBackgroundColor() override;
+ bool ConvertPointToScreen(CefPoint& point) override;
+ bool ConvertPointFromScreen(CefPoint& point) override;
+ bool ConvertPointToWindow(CefPoint& point) override;
+ bool ConvertPointFromWindow(CefPoint& point) override;
+ bool ConvertPointToView(CefRefPtr<CefView> view, CefPoint& point) override;
+ bool ConvertPointFromView(CefRefPtr<CefView> view, CefPoint& point) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_VIEWS_BROWSER_VIEW_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/views/browser_view_delegate_ctocpp.cc b/libcef_dll/ctocpp/views/browser_view_delegate_ctocpp.cc
new file mode 100644
index 00000000..a98dc7e9
--- /dev/null
+++ b/libcef_dll/ctocpp/views/browser_view_delegate_ctocpp.cc
@@ -0,0 +1,451 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=7301ce9c063a7ff4ab88b6382f6441ba314b20c0$
+//
+
+#include "libcef_dll/ctocpp/views/browser_view_delegate_ctocpp.h"
+#include "libcef_dll/cpptoc/browser_cpptoc.h"
+#include "libcef_dll/cpptoc/views/browser_view_cpptoc.h"
+#include "libcef_dll/cpptoc/views/view_cpptoc.h"
+#include "libcef_dll/ctocpp/client_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+void CefBrowserViewDelegateCToCpp::OnBrowserCreated(
+ CefRefPtr<CefBrowserView> browser_view,
+ CefRefPtr<CefBrowser> browser) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_view_delegate_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_browser_created)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser_view; type: refptr_diff
+ DCHECK(browser_view.get());
+ if (!browser_view.get()) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_browser_created(_struct, CefBrowserViewCppToC::Wrap(browser_view),
+ CefBrowserCppToC::Wrap(browser));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefBrowserViewDelegateCToCpp::OnBrowserDestroyed(
+ CefRefPtr<CefBrowserView> browser_view,
+ CefRefPtr<CefBrowser> browser) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_view_delegate_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_browser_destroyed)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser_view; type: refptr_diff
+ DCHECK(browser_view.get());
+ if (!browser_view.get()) {
+ return;
+ }
+ // Verify param: browser; type: refptr_diff
+ DCHECK(browser.get());
+ if (!browser.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_browser_destroyed(_struct,
+ CefBrowserViewCppToC::Wrap(browser_view),
+ CefBrowserCppToC::Wrap(browser));
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefBrowserViewDelegate>
+CefBrowserViewDelegateCToCpp::GetDelegateForPopupBrowserView(
+ CefRefPtr<CefBrowserView> browser_view,
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefClient> client,
+ bool is_devtools) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_view_delegate_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_delegate_for_popup_browser_view)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser_view; type: refptr_diff
+ DCHECK(browser_view.get());
+ if (!browser_view.get()) {
+ return nullptr;
+ }
+ // Unverified params: client
+
+ // Execute
+ cef_browser_view_delegate_t* _retval =
+ _struct->get_delegate_for_popup_browser_view(
+ _struct, CefBrowserViewCppToC::Wrap(browser_view), &settings,
+ CefClientCToCpp::Unwrap(client), is_devtools);
+
+ // Return type: refptr_same
+ return CefBrowserViewDelegateCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefBrowserViewDelegateCToCpp::OnPopupBrowserViewCreated(
+ CefRefPtr<CefBrowserView> browser_view,
+ CefRefPtr<CefBrowserView> popup_browser_view,
+ bool is_devtools) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_view_delegate_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_popup_browser_view_created)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: browser_view; type: refptr_diff
+ DCHECK(browser_view.get());
+ if (!browser_view.get()) {
+ return false;
+ }
+ // Verify param: popup_browser_view; type: refptr_diff
+ DCHECK(popup_browser_view.get());
+ if (!popup_browser_view.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->on_popup_browser_view_created(
+ _struct, CefBrowserViewCppToC::Wrap(browser_view),
+ CefBrowserViewCppToC::Wrap(popup_browser_view), is_devtools);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CefBrowserViewDelegate::ChromeToolbarType
+CefBrowserViewDelegateCToCpp::GetChromeToolbarType() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_browser_view_delegate_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_chrome_toolbar_type)) {
+ return CEF_CTT_NONE;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_chrome_toolbar_type_t _retval = _struct->get_chrome_toolbar_type(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CefSize CefBrowserViewDelegateCToCpp::GetPreferredSize(
+ CefRefPtr<CefView> view) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_preferred_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval =
+ _struct->get_preferred_size(_struct, CefViewCppToC::Wrap(view));
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CefSize CefBrowserViewDelegateCToCpp::GetMinimumSize(CefRefPtr<CefView> view) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_minimum_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval =
+ _struct->get_minimum_size(_struct, CefViewCppToC::Wrap(view));
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CefSize CefBrowserViewDelegateCToCpp::GetMaximumSize(CefRefPtr<CefView> view) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_maximum_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval =
+ _struct->get_maximum_size(_struct, CefViewCppToC::Wrap(view));
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+int CefBrowserViewDelegateCToCpp::GetHeightForWidth(CefRefPtr<CefView> view,
+ int width) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_height_for_width)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return 0;
+ }
+
+ // Execute
+ int _retval =
+ _struct->get_height_for_width(_struct, CefViewCppToC::Wrap(view), width);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefBrowserViewDelegateCToCpp::OnParentViewChanged(
+ CefRefPtr<CefView> view,
+ bool added,
+ CefRefPtr<CefView> parent) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, on_parent_view_changed)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return;
+ }
+ // Verify param: parent; type: refptr_diff
+ DCHECK(parent.get());
+ if (!parent.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_parent_view_changed(_struct, CefViewCppToC::Wrap(view), added,
+ CefViewCppToC::Wrap(parent));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefBrowserViewDelegateCToCpp::OnChildViewChanged(
+ CefRefPtr<CefView> view,
+ bool added,
+ CefRefPtr<CefView> child) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, on_child_view_changed)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return;
+ }
+ // Verify param: child; type: refptr_diff
+ DCHECK(child.get());
+ if (!child.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_child_view_changed(_struct, CefViewCppToC::Wrap(view), added,
+ CefViewCppToC::Wrap(child));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefBrowserViewDelegateCToCpp::OnWindowChanged(CefRefPtr<CefView> view,
+ bool added) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, on_window_changed)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_window_changed(_struct, CefViewCppToC::Wrap(view), added);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefBrowserViewDelegateCToCpp::OnLayoutChanged(CefRefPtr<CefView> view,
+ const CefRect& new_bounds) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, on_layout_changed)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_layout_changed(_struct, CefViewCppToC::Wrap(view), &new_bounds);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefBrowserViewDelegateCToCpp::OnFocus(CefRefPtr<CefView> view) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, on_focus)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_focus(_struct, CefViewCppToC::Wrap(view));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefBrowserViewDelegateCToCpp::OnBlur(CefRefPtr<CefView> view) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, on_blur)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_blur(_struct, CefViewCppToC::Wrap(view));
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefBrowserViewDelegateCToCpp::CefBrowserViewDelegateCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefBrowserViewDelegateCToCpp::~CefBrowserViewDelegateCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_browser_view_delegate_t* CefCToCppRefCounted<
+ CefBrowserViewDelegateCToCpp,
+ CefBrowserViewDelegate,
+ cef_browser_view_delegate_t>::UnwrapDerived(CefWrapperType type,
+ CefBrowserViewDelegate* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefBrowserViewDelegateCToCpp,
+ CefBrowserViewDelegate,
+ cef_browser_view_delegate_t>::kWrapperType =
+ WT_BROWSER_VIEW_DELEGATE;
diff --git a/libcef_dll/ctocpp/views/browser_view_delegate_ctocpp.h b/libcef_dll/ctocpp/views/browser_view_delegate_ctocpp.h
new file mode 100644
index 00000000..bc1abf58
--- /dev/null
+++ b/libcef_dll/ctocpp/views/browser_view_delegate_ctocpp.h
@@ -0,0 +1,74 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=ae219b09b69d7a49f48878a5d2f94b25c9b4150b$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_VIEWS_BROWSER_VIEW_DELEGATE_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_VIEWS_BROWSER_VIEW_DELEGATE_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_browser_capi.h"
+#include "include/capi/views/cef_browser_view_capi.h"
+#include "include/capi/views/cef_browser_view_delegate_capi.h"
+#include "include/cef_browser.h"
+#include "include/views/cef_browser_view.h"
+#include "include/views/cef_browser_view_delegate.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefBrowserViewDelegateCToCpp
+ : public CefCToCppRefCounted<CefBrowserViewDelegateCToCpp,
+ CefBrowserViewDelegate,
+ cef_browser_view_delegate_t> {
+ public:
+ CefBrowserViewDelegateCToCpp();
+ virtual ~CefBrowserViewDelegateCToCpp();
+
+ // CefBrowserViewDelegate methods.
+ void OnBrowserCreated(CefRefPtr<CefBrowserView> browser_view,
+ CefRefPtr<CefBrowser> browser) override;
+ void OnBrowserDestroyed(CefRefPtr<CefBrowserView> browser_view,
+ CefRefPtr<CefBrowser> browser) override;
+ CefRefPtr<CefBrowserViewDelegate> GetDelegateForPopupBrowserView(
+ CefRefPtr<CefBrowserView> browser_view,
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefClient> client,
+ bool is_devtools) override;
+ bool OnPopupBrowserViewCreated(CefRefPtr<CefBrowserView> browser_view,
+ CefRefPtr<CefBrowserView> popup_browser_view,
+ bool is_devtools) override;
+ ChromeToolbarType GetChromeToolbarType() override;
+
+ // CefViewDelegate methods.
+ CefSize GetPreferredSize(CefRefPtr<CefView> view) override;
+ CefSize GetMinimumSize(CefRefPtr<CefView> view) override;
+ CefSize GetMaximumSize(CefRefPtr<CefView> view) override;
+ int GetHeightForWidth(CefRefPtr<CefView> view, int width) override;
+ void OnParentViewChanged(CefRefPtr<CefView> view,
+ bool added,
+ CefRefPtr<CefView> parent) override;
+ void OnChildViewChanged(CefRefPtr<CefView> view,
+ bool added,
+ CefRefPtr<CefView> child) override;
+ void OnWindowChanged(CefRefPtr<CefView> view, bool added) override;
+ void OnLayoutChanged(CefRefPtr<CefView> view,
+ const CefRect& new_bounds) override;
+ void OnFocus(CefRefPtr<CefView> view) override;
+ void OnBlur(CefRefPtr<CefView> view) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_VIEWS_BROWSER_VIEW_DELEGATE_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/views/button_ctocpp.cc b/libcef_dll/ctocpp/views/button_ctocpp.cc
new file mode 100644
index 00000000..5c54ec59
--- /dev/null
+++ b/libcef_dll/ctocpp/views/button_ctocpp.cc
@@ -0,0 +1,1017 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=21ad12e2611fc02420e4105826b5e38fed399c1c$
+//
+
+#include "libcef_dll/ctocpp/views/button_ctocpp.h"
+#include "libcef_dll/cpptoc/views/view_delegate_cpptoc.h"
+#include "libcef_dll/ctocpp/views/browser_view_ctocpp.h"
+#include "libcef_dll/ctocpp/views/label_button_ctocpp.h"
+#include "libcef_dll/ctocpp/views/menu_button_ctocpp.h"
+#include "libcef_dll/ctocpp/views/panel_ctocpp.h"
+#include "libcef_dll/ctocpp/views/scroll_view_ctocpp.h"
+#include "libcef_dll/ctocpp/views/textfield_ctocpp.h"
+#include "libcef_dll/ctocpp/views/view_ctocpp.h"
+#include "libcef_dll/ctocpp/views/window_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefLabelButton> CefButtonCToCpp::AsLabelButton() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_button_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, as_label_button)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_label_button_t* _retval = _struct->as_label_button(_struct);
+
+ // Return type: refptr_same
+ return CefLabelButtonCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefButtonCToCpp::SetState(cef_button_state_t state) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_button_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_state)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_state(_struct, state);
+}
+
+NO_SANITIZE("cfi-icall") cef_button_state_t CefButtonCToCpp::GetState() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_button_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_state)) {
+ return CEF_BUTTON_STATE_NORMAL;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_button_state_t _retval = _struct->get_state(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") void CefButtonCToCpp::SetInkDropEnabled(bool enabled) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_button_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_ink_drop_enabled)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_ink_drop_enabled(_struct, enabled);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefButtonCToCpp::SetTooltipText(const CefString& tooltip_text) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_button_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_tooltip_text)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: tooltip_text; type: string_byref_const
+ DCHECK(!tooltip_text.empty());
+ if (tooltip_text.empty()) {
+ return;
+ }
+
+ // Execute
+ _struct->set_tooltip_text(_struct, tooltip_text.GetStruct());
+}
+
+NO_SANITIZE("cfi-icall")
+void CefButtonCToCpp::SetAccessibleName(const CefString& name) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_button_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_accessible_name)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: name; type: string_byref_const
+ DCHECK(!name.empty());
+ if (name.empty()) {
+ return;
+ }
+
+ // Execute
+ _struct->set_accessible_name(_struct, name.GetStruct());
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefBrowserView> CefButtonCToCpp::AsBrowserView() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, as_browser_view)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_browser_view_t* _retval = _struct->as_browser_view(_struct);
+
+ // Return type: refptr_same
+ return CefBrowserViewCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefButton> CefButtonCToCpp::AsButton() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, as_button)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_button_t* _retval = _struct->as_button(_struct);
+
+ // Return type: refptr_same
+ return CefButtonCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefPanel> CefButtonCToCpp::AsPanel() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, as_panel)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_panel_t* _retval = _struct->as_panel(_struct);
+
+ // Return type: refptr_same
+ return CefPanelCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefScrollView> CefButtonCToCpp::AsScrollView() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, as_scroll_view)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_scroll_view_t* _retval = _struct->as_scroll_view(_struct);
+
+ // Return type: refptr_same
+ return CefScrollViewCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefTextfield> CefButtonCToCpp::AsTextfield() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, as_textfield)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_textfield_t* _retval = _struct->as_textfield(_struct);
+
+ // Return type: refptr_same
+ return CefTextfieldCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") CefString CefButtonCToCpp::GetTypeString() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_type_string)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_type_string(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+CefString CefButtonCToCpp::ToString(bool include_children) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, to_string)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->to_string(_struct, include_children);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") bool CefButtonCToCpp::IsValid() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_valid)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_valid(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefButtonCToCpp::IsAttached() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_attached)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_attached(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefButtonCToCpp::IsSame(CefRefPtr<CefView> that) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_same)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: that; type: refptr_same
+ DCHECK(that.get());
+ if (!that.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->is_same(_struct, CefViewCToCpp::Unwrap(that));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefViewDelegate> CefButtonCToCpp::GetDelegate() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_delegate)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_view_delegate_t* _retval = _struct->get_delegate(_struct);
+
+ // Return type: refptr_diff
+ return CefViewDelegateCppToC::Unwrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefWindow> CefButtonCToCpp::GetWindow() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_window)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_window_t* _retval = _struct->get_window(_struct);
+
+ // Return type: refptr_same
+ return CefWindowCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") int CefButtonCToCpp::GetID() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_id)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_id(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") void CefButtonCToCpp::SetID(int id) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_id)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_id(_struct, id);
+}
+
+NO_SANITIZE("cfi-icall") int CefButtonCToCpp::GetGroupID() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_group_id)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_group_id(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") void CefButtonCToCpp::SetGroupID(int group_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_group_id)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_group_id(_struct, group_id);
+}
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefView> CefButtonCToCpp::GetParentView() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_parent_view)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_view_t* _retval = _struct->get_parent_view(_struct);
+
+ // Return type: refptr_same
+ return CefViewCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefView> CefButtonCToCpp::GetViewForID(int id) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_view_for_id)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_view_t* _retval = _struct->get_view_for_id(_struct, id);
+
+ // Return type: refptr_same
+ return CefViewCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefButtonCToCpp::SetBounds(const CefRect& bounds) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_bounds)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_bounds(_struct, &bounds);
+}
+
+NO_SANITIZE("cfi-icall") CefRect CefButtonCToCpp::GetBounds() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_bounds)) {
+ return CefRect();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_rect_t _retval = _struct->get_bounds(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") CefRect CefButtonCToCpp::GetBoundsInScreen() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_bounds_in_screen)) {
+ return CefRect();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_rect_t _retval = _struct->get_bounds_in_screen(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") void CefButtonCToCpp::SetSize(const CefSize& size) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_size)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_size(_struct, &size);
+}
+
+NO_SANITIZE("cfi-icall") CefSize CefButtonCToCpp::GetSize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_size_t _retval = _struct->get_size(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefButtonCToCpp::SetPosition(const CefPoint& position) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_position)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_position(_struct, &position);
+}
+
+NO_SANITIZE("cfi-icall") CefPoint CefButtonCToCpp::GetPosition() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_position)) {
+ return CefPoint();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_point_t _retval = _struct->get_position(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefButtonCToCpp::SetInsets(const CefInsets& insets) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_insets)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_insets(_struct, &insets);
+}
+
+NO_SANITIZE("cfi-icall") CefInsets CefButtonCToCpp::GetInsets() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_insets)) {
+ return CefInsets();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_insets_t _retval = _struct->get_insets(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") CefSize CefButtonCToCpp::GetPreferredSize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_preferred_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_size_t _retval = _struct->get_preferred_size(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") void CefButtonCToCpp::SizeToPreferredSize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, size_to_preferred_size)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->size_to_preferred_size(_struct);
+}
+
+NO_SANITIZE("cfi-icall") CefSize CefButtonCToCpp::GetMinimumSize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_minimum_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_size_t _retval = _struct->get_minimum_size(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") CefSize CefButtonCToCpp::GetMaximumSize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_maximum_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_size_t _retval = _struct->get_maximum_size(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") int CefButtonCToCpp::GetHeightForWidth(int width) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_height_for_width)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_height_for_width(_struct, width);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") void CefButtonCToCpp::InvalidateLayout() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, invalidate_layout)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->invalidate_layout(_struct);
+}
+
+NO_SANITIZE("cfi-icall") void CefButtonCToCpp::SetVisible(bool visible) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_visible)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_visible(_struct, visible);
+}
+
+NO_SANITIZE("cfi-icall") bool CefButtonCToCpp::IsVisible() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_visible)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_visible(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefButtonCToCpp::IsDrawn() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_drawn)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_drawn(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") void CefButtonCToCpp::SetEnabled(bool enabled) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_enabled)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_enabled(_struct, enabled);
+}
+
+NO_SANITIZE("cfi-icall") bool CefButtonCToCpp::IsEnabled() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_enabled)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_enabled(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") void CefButtonCToCpp::SetFocusable(bool focusable) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_focusable)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_focusable(_struct, focusable);
+}
+
+NO_SANITIZE("cfi-icall") bool CefButtonCToCpp::IsFocusable() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_focusable)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_focusable(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefButtonCToCpp::IsAccessibilityFocusable() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_accessibility_focusable)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_accessibility_focusable(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") void CefButtonCToCpp::RequestFocus() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, request_focus)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->request_focus(_struct);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefButtonCToCpp::SetBackgroundColor(cef_color_t color) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_background_color)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_background_color(_struct, color);
+}
+
+NO_SANITIZE("cfi-icall") cef_color_t CefButtonCToCpp::GetBackgroundColor() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_background_color)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_color_t _retval = _struct->get_background_color(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefButtonCToCpp::ConvertPointToScreen(CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, convert_point_to_screen)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->convert_point_to_screen(_struct, &point);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefButtonCToCpp::ConvertPointFromScreen(CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, convert_point_from_screen)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->convert_point_from_screen(_struct, &point);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefButtonCToCpp::ConvertPointToWindow(CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, convert_point_to_window)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->convert_point_to_window(_struct, &point);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefButtonCToCpp::ConvertPointFromWindow(CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, convert_point_from_window)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->convert_point_from_window(_struct, &point);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefButtonCToCpp::ConvertPointToView(CefRefPtr<CefView> view,
+ CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, convert_point_to_view)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_same
+ DCHECK(view.get());
+ if (!view.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->convert_point_to_view(
+ _struct, CefViewCToCpp::Unwrap(view), &point);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefButtonCToCpp::ConvertPointFromView(CefRefPtr<CefView> view,
+ CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, convert_point_from_view)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_same
+ DCHECK(view.get());
+ if (!view.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->convert_point_from_view(
+ _struct, CefViewCToCpp::Unwrap(view), &point);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefButtonCToCpp::CefButtonCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefButtonCToCpp::~CefButtonCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_button_t*
+CefCToCppRefCounted<CefButtonCToCpp, CefButton, cef_button_t>::UnwrapDerived(
+ CefWrapperType type,
+ CefButton* c) {
+ if (type == WT_LABEL_BUTTON) {
+ return reinterpret_cast<cef_button_t*>(
+ CefLabelButtonCToCpp::Unwrap(reinterpret_cast<CefLabelButton*>(c)));
+ }
+ if (type == WT_MENU_BUTTON) {
+ return reinterpret_cast<cef_button_t*>(
+ CefMenuButtonCToCpp::Unwrap(reinterpret_cast<CefMenuButton*>(c)));
+ }
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefButtonCToCpp, CefButton, cef_button_t>::
+ kWrapperType = WT_BUTTON;
diff --git a/libcef_dll/ctocpp/views/button_ctocpp.h b/libcef_dll/ctocpp/views/button_ctocpp.h
new file mode 100644
index 00000000..4f4362ee
--- /dev/null
+++ b/libcef_dll/ctocpp/views/button_ctocpp.h
@@ -0,0 +1,98 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=d6be48f8326ec9e541ace36d0b467cf6b1fbc065$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_VIEWS_BUTTON_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_VIEWS_BUTTON_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/views/cef_button_capi.h"
+#include "include/capi/views/cef_label_button_capi.h"
+#include "include/views/cef_button.h"
+#include "include/views/cef_label_button.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefButtonCToCpp
+ : public CefCToCppRefCounted<CefButtonCToCpp, CefButton, cef_button_t> {
+ public:
+ CefButtonCToCpp();
+ virtual ~CefButtonCToCpp();
+
+ // CefButton methods.
+ CefRefPtr<CefLabelButton> AsLabelButton() override;
+ void SetState(cef_button_state_t state) override;
+ cef_button_state_t GetState() override;
+ void SetInkDropEnabled(bool enabled) override;
+ void SetTooltipText(const CefString& tooltip_text) override;
+ void SetAccessibleName(const CefString& name) override;
+
+ // CefView methods.
+ CefRefPtr<CefBrowserView> AsBrowserView() override;
+ CefRefPtr<CefButton> AsButton() override;
+ CefRefPtr<CefPanel> AsPanel() override;
+ CefRefPtr<CefScrollView> AsScrollView() override;
+ CefRefPtr<CefTextfield> AsTextfield() override;
+ CefString GetTypeString() override;
+ CefString ToString(bool include_children) override;
+ bool IsValid() override;
+ bool IsAttached() override;
+ bool IsSame(CefRefPtr<CefView> that) override;
+ CefRefPtr<CefViewDelegate> GetDelegate() override;
+ CefRefPtr<CefWindow> GetWindow() override;
+ int GetID() override;
+ void SetID(int id) override;
+ int GetGroupID() override;
+ void SetGroupID(int group_id) override;
+ CefRefPtr<CefView> GetParentView() override;
+ CefRefPtr<CefView> GetViewForID(int id) override;
+ void SetBounds(const CefRect& bounds) override;
+ CefRect GetBounds() override;
+ CefRect GetBoundsInScreen() override;
+ void SetSize(const CefSize& size) override;
+ CefSize GetSize() override;
+ void SetPosition(const CefPoint& position) override;
+ CefPoint GetPosition() override;
+ void SetInsets(const CefInsets& insets) override;
+ CefInsets GetInsets() override;
+ CefSize GetPreferredSize() override;
+ void SizeToPreferredSize() override;
+ CefSize GetMinimumSize() override;
+ CefSize GetMaximumSize() override;
+ int GetHeightForWidth(int width) override;
+ void InvalidateLayout() override;
+ void SetVisible(bool visible) override;
+ bool IsVisible() override;
+ bool IsDrawn() override;
+ void SetEnabled(bool enabled) override;
+ bool IsEnabled() override;
+ void SetFocusable(bool focusable) override;
+ bool IsFocusable() override;
+ bool IsAccessibilityFocusable() override;
+ void RequestFocus() override;
+ void SetBackgroundColor(cef_color_t color) override;
+ cef_color_t GetBackgroundColor() override;
+ bool ConvertPointToScreen(CefPoint& point) override;
+ bool ConvertPointFromScreen(CefPoint& point) override;
+ bool ConvertPointToWindow(CefPoint& point) override;
+ bool ConvertPointFromWindow(CefPoint& point) override;
+ bool ConvertPointToView(CefRefPtr<CefView> view, CefPoint& point) override;
+ bool ConvertPointFromView(CefRefPtr<CefView> view, CefPoint& point) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_VIEWS_BUTTON_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/views/button_delegate_ctocpp.cc b/libcef_dll/ctocpp/views/button_delegate_ctocpp.cc
new file mode 100644
index 00000000..9f738f91
--- /dev/null
+++ b/libcef_dll/ctocpp/views/button_delegate_ctocpp.cc
@@ -0,0 +1,350 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=29415424384da3b4a596ce3419826ee54ab73669$
+//
+
+#include "libcef_dll/ctocpp/views/button_delegate_ctocpp.h"
+#include "libcef_dll/cpptoc/views/button_cpptoc.h"
+#include "libcef_dll/cpptoc/views/view_cpptoc.h"
+#include "libcef_dll/ctocpp/views/menu_button_delegate_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+void CefButtonDelegateCToCpp::OnButtonPressed(CefRefPtr<CefButton> button) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_button_delegate_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_button_pressed)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: button; type: refptr_diff
+ DCHECK(button.get());
+ if (!button.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_button_pressed(_struct, CefButtonCppToC::Wrap(button));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefButtonDelegateCToCpp::OnButtonStateChanged(
+ CefRefPtr<CefButton> button) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_button_delegate_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_button_state_changed)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: button; type: refptr_diff
+ DCHECK(button.get());
+ if (!button.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_button_state_changed(_struct, CefButtonCppToC::Wrap(button));
+}
+
+NO_SANITIZE("cfi-icall")
+CefSize CefButtonDelegateCToCpp::GetPreferredSize(CefRefPtr<CefView> view) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_preferred_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval =
+ _struct->get_preferred_size(_struct, CefViewCppToC::Wrap(view));
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CefSize CefButtonDelegateCToCpp::GetMinimumSize(CefRefPtr<CefView> view) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_minimum_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval =
+ _struct->get_minimum_size(_struct, CefViewCppToC::Wrap(view));
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CefSize CefButtonDelegateCToCpp::GetMaximumSize(CefRefPtr<CefView> view) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_maximum_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval =
+ _struct->get_maximum_size(_struct, CefViewCppToC::Wrap(view));
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+int CefButtonDelegateCToCpp::GetHeightForWidth(CefRefPtr<CefView> view,
+ int width) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_height_for_width)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return 0;
+ }
+
+ // Execute
+ int _retval =
+ _struct->get_height_for_width(_struct, CefViewCppToC::Wrap(view), width);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefButtonDelegateCToCpp::OnParentViewChanged(CefRefPtr<CefView> view,
+ bool added,
+ CefRefPtr<CefView> parent) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, on_parent_view_changed)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return;
+ }
+ // Verify param: parent; type: refptr_diff
+ DCHECK(parent.get());
+ if (!parent.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_parent_view_changed(_struct, CefViewCppToC::Wrap(view), added,
+ CefViewCppToC::Wrap(parent));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefButtonDelegateCToCpp::OnChildViewChanged(CefRefPtr<CefView> view,
+ bool added,
+ CefRefPtr<CefView> child) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, on_child_view_changed)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return;
+ }
+ // Verify param: child; type: refptr_diff
+ DCHECK(child.get());
+ if (!child.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_child_view_changed(_struct, CefViewCppToC::Wrap(view), added,
+ CefViewCppToC::Wrap(child));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefButtonDelegateCToCpp::OnWindowChanged(CefRefPtr<CefView> view,
+ bool added) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, on_window_changed)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_window_changed(_struct, CefViewCppToC::Wrap(view), added);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefButtonDelegateCToCpp::OnLayoutChanged(CefRefPtr<CefView> view,
+ const CefRect& new_bounds) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, on_layout_changed)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_layout_changed(_struct, CefViewCppToC::Wrap(view), &new_bounds);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefButtonDelegateCToCpp::OnFocus(CefRefPtr<CefView> view) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, on_focus)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_focus(_struct, CefViewCppToC::Wrap(view));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefButtonDelegateCToCpp::OnBlur(CefRefPtr<CefView> view) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, on_blur)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_blur(_struct, CefViewCppToC::Wrap(view));
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefButtonDelegateCToCpp::CefButtonDelegateCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefButtonDelegateCToCpp::~CefButtonDelegateCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_button_delegate_t* CefCToCppRefCounted<
+ CefButtonDelegateCToCpp,
+ CefButtonDelegate,
+ cef_button_delegate_t>::UnwrapDerived(CefWrapperType type,
+ CefButtonDelegate* c) {
+ if (type == WT_MENU_BUTTON_DELEGATE) {
+ return reinterpret_cast<cef_button_delegate_t*>(
+ CefMenuButtonDelegateCToCpp::Unwrap(
+ reinterpret_cast<CefMenuButtonDelegate*>(c)));
+ }
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefButtonDelegateCToCpp,
+ CefButtonDelegate,
+ cef_button_delegate_t>::kWrapperType =
+ WT_BUTTON_DELEGATE;
diff --git a/libcef_dll/ctocpp/views/button_delegate_ctocpp.h b/libcef_dll/ctocpp/views/button_delegate_ctocpp.h
new file mode 100644
index 00000000..a01a96bd
--- /dev/null
+++ b/libcef_dll/ctocpp/views/button_delegate_ctocpp.h
@@ -0,0 +1,61 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=13140a32b465eaf52f13693cd244a9b47eda5068$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_VIEWS_BUTTON_DELEGATE_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_VIEWS_BUTTON_DELEGATE_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/views/cef_button_capi.h"
+#include "include/capi/views/cef_button_delegate_capi.h"
+#include "include/views/cef_button.h"
+#include "include/views/cef_button_delegate.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefButtonDelegateCToCpp
+ : public CefCToCppRefCounted<CefButtonDelegateCToCpp,
+ CefButtonDelegate,
+ cef_button_delegate_t> {
+ public:
+ CefButtonDelegateCToCpp();
+ virtual ~CefButtonDelegateCToCpp();
+
+ // CefButtonDelegate methods.
+ void OnButtonPressed(CefRefPtr<CefButton> button) override;
+ void OnButtonStateChanged(CefRefPtr<CefButton> button) override;
+
+ // CefViewDelegate methods.
+ CefSize GetPreferredSize(CefRefPtr<CefView> view) override;
+ CefSize GetMinimumSize(CefRefPtr<CefView> view) override;
+ CefSize GetMaximumSize(CefRefPtr<CefView> view) override;
+ int GetHeightForWidth(CefRefPtr<CefView> view, int width) override;
+ void OnParentViewChanged(CefRefPtr<CefView> view,
+ bool added,
+ CefRefPtr<CefView> parent) override;
+ void OnChildViewChanged(CefRefPtr<CefView> view,
+ bool added,
+ CefRefPtr<CefView> child) override;
+ void OnWindowChanged(CefRefPtr<CefView> view, bool added) override;
+ void OnLayoutChanged(CefRefPtr<CefView> view,
+ const CefRect& new_bounds) override;
+ void OnFocus(CefRefPtr<CefView> view) override;
+ void OnBlur(CefRefPtr<CefView> view) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_VIEWS_BUTTON_DELEGATE_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/views/display_ctocpp.cc b/libcef_dll/ctocpp/views/display_ctocpp.cc
new file mode 100644
index 00000000..907b8a0a
--- /dev/null
+++ b/libcef_dll/ctocpp/views/display_ctocpp.cc
@@ -0,0 +1,304 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=ce835458848e642bc1f9a8231a7d6996f4db85ee$
+//
+
+#include "libcef_dll/ctocpp/views/display_ctocpp.h"
+#include <algorithm>
+#include "libcef_dll/shutdown_checker.h"
+
+// STATIC METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefDisplay> CefDisplay::GetPrimaryDisplay() {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_display_t* _retval = cef_display_get_primary();
+
+ // Return type: refptr_same
+ return CefDisplayCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefDisplay> CefDisplay::GetDisplayNearestPoint(
+ const CefPoint& point,
+ bool input_pixel_coords) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_display_t* _retval =
+ cef_display_get_nearest_point(&point, input_pixel_coords);
+
+ // Return type: refptr_same
+ return CefDisplayCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefDisplay> CefDisplay::GetDisplayMatchingBounds(
+ const CefRect& bounds,
+ bool input_pixel_coords) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_display_t* _retval =
+ cef_display_get_matching_bounds(&bounds, input_pixel_coords);
+
+ // Return type: refptr_same
+ return CefDisplayCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") size_t CefDisplay::GetDisplayCount() {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ size_t _retval = cef_display_get_count();
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefDisplay::GetAllDisplays(std::vector<CefRefPtr<CefDisplay>>& displays) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Translate param: displays; type: refptr_vec_same_byref
+ size_t displaysSize = displays.size();
+ size_t displaysCount = std::max(GetDisplayCount(), displaysSize);
+ cef_display_t** displaysList = NULL;
+ if (displaysCount > 0) {
+ displaysList = new cef_display_t*[displaysCount];
+ DCHECK(displaysList);
+ if (displaysList) {
+ memset(displaysList, 0, sizeof(cef_display_t*) * displaysCount);
+ }
+ if (displaysList && displaysSize > 0) {
+ for (size_t i = 0; i < displaysSize; ++i) {
+ displaysList[i] = CefDisplayCToCpp::Unwrap(displays[i]);
+ }
+ }
+ }
+
+ // Execute
+ cef_display_get_alls(&displaysCount, displaysList);
+
+ // Restore param:displays; type: refptr_vec_same_byref
+ displays.clear();
+ if (displaysCount > 0 && displaysList) {
+ for (size_t i = 0; i < displaysCount; ++i) {
+ displays.push_back(CefDisplayCToCpp::Wrap(displaysList[i]));
+ }
+ delete[] displaysList;
+ }
+}
+
+NO_SANITIZE("cfi-icall")
+CefPoint CefDisplay::ConvertScreenPointToPixels(const CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_point_t _retval = cef_display_convert_screen_point_to_pixels(&point);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CefPoint CefDisplay::ConvertScreenPointFromPixels(const CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_point_t _retval = cef_display_convert_screen_point_from_pixels(&point);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRect CefDisplay::ConvertScreenRectToPixels(const CefRect& rect) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_rect_t _retval = cef_display_convert_screen_rect_to_pixels(&rect);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRect CefDisplay::ConvertScreenRectFromPixels(const CefRect& rect) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_rect_t _retval = cef_display_convert_screen_rect_from_pixels(&rect);
+
+ // Return type: simple
+ return _retval;
+}
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") int64 CefDisplayCToCpp::GetID() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_display_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_id)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int64 _retval = _struct->get_id(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") float CefDisplayCToCpp::GetDeviceScaleFactor() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_display_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_device_scale_factor)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ float _retval = _struct->get_device_scale_factor(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefDisplayCToCpp::ConvertPointToPixels(CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_display_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, convert_point_to_pixels)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->convert_point_to_pixels(_struct, &point);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefDisplayCToCpp::ConvertPointFromPixels(CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_display_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, convert_point_from_pixels)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->convert_point_from_pixels(_struct, &point);
+}
+
+NO_SANITIZE("cfi-icall") CefRect CefDisplayCToCpp::GetBounds() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_display_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_bounds)) {
+ return CefRect();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_rect_t _retval = _struct->get_bounds(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") CefRect CefDisplayCToCpp::GetWorkArea() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_display_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_work_area)) {
+ return CefRect();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_rect_t _retval = _struct->get_work_area(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") int CefDisplayCToCpp::GetRotation() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_display_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_rotation)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_rotation(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefDisplayCToCpp::CefDisplayCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefDisplayCToCpp::~CefDisplayCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_display_t*
+CefCToCppRefCounted<CefDisplayCToCpp, CefDisplay, cef_display_t>::UnwrapDerived(
+ CefWrapperType type,
+ CefDisplay* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefDisplayCToCpp,
+ CefDisplay,
+ cef_display_t>::kWrapperType = WT_DISPLAY;
diff --git a/libcef_dll/ctocpp/views/display_ctocpp.h b/libcef_dll/ctocpp/views/display_ctocpp.h
new file mode 100644
index 00000000..5d12545d
--- /dev/null
+++ b/libcef_dll/ctocpp/views/display_ctocpp.h
@@ -0,0 +1,45 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=a05d5f989630c0c031cbe9cc04150a6e1e54c4d4$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_VIEWS_DISPLAY_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_VIEWS_DISPLAY_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/views/cef_display_capi.h"
+#include "include/views/cef_display.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefDisplayCToCpp
+ : public CefCToCppRefCounted<CefDisplayCToCpp, CefDisplay, cef_display_t> {
+ public:
+ CefDisplayCToCpp();
+ virtual ~CefDisplayCToCpp();
+
+ // CefDisplay methods.
+ int64 GetID() override;
+ float GetDeviceScaleFactor() override;
+ void ConvertPointToPixels(CefPoint& point) override;
+ void ConvertPointFromPixels(CefPoint& point) override;
+ CefRect GetBounds() override;
+ CefRect GetWorkArea() override;
+ int GetRotation() override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_VIEWS_DISPLAY_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/views/fill_layout_ctocpp.cc b/libcef_dll/ctocpp/views/fill_layout_ctocpp.cc
new file mode 100644
index 00000000..8de26b49
--- /dev/null
+++ b/libcef_dll/ctocpp/views/fill_layout_ctocpp.cc
@@ -0,0 +1,96 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=67fefa404548bb01592c170a58bcfb9e79a3a9c5$
+//
+
+#include "libcef_dll/ctocpp/views/fill_layout_ctocpp.h"
+#include "libcef_dll/ctocpp/views/box_layout_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefBoxLayout> CefFillLayoutCToCpp::AsBoxLayout() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_layout_t* _struct = reinterpret_cast<cef_layout_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, as_box_layout)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_box_layout_t* _retval = _struct->as_box_layout(_struct);
+
+ // Return type: refptr_same
+ return CefBoxLayoutCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefFillLayout> CefFillLayoutCToCpp::AsFillLayout() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_layout_t* _struct = reinterpret_cast<cef_layout_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, as_fill_layout)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_fill_layout_t* _retval = _struct->as_fill_layout(_struct);
+
+ // Return type: refptr_same
+ return CefFillLayoutCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") bool CefFillLayoutCToCpp::IsValid() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_layout_t* _struct = reinterpret_cast<cef_layout_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_valid)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_valid(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefFillLayoutCToCpp::CefFillLayoutCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefFillLayoutCToCpp::~CefFillLayoutCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_fill_layout_t*
+CefCToCppRefCounted<CefFillLayoutCToCpp, CefFillLayout, cef_fill_layout_t>::
+ UnwrapDerived(CefWrapperType type, CefFillLayout* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefFillLayoutCToCpp,
+ CefFillLayout,
+ cef_fill_layout_t>::kWrapperType =
+ WT_FILL_LAYOUT;
diff --git a/libcef_dll/ctocpp/views/fill_layout_ctocpp.h b/libcef_dll/ctocpp/views/fill_layout_ctocpp.h
new file mode 100644
index 00000000..06b0380c
--- /dev/null
+++ b/libcef_dll/ctocpp/views/fill_layout_ctocpp.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=5d52b0af136f7ac008cb89a29ce65942932b9f64$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_VIEWS_FILL_LAYOUT_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_VIEWS_FILL_LAYOUT_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/views/cef_fill_layout_capi.h"
+#include "include/views/cef_fill_layout.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefFillLayoutCToCpp : public CefCToCppRefCounted<CefFillLayoutCToCpp,
+ CefFillLayout,
+ cef_fill_layout_t> {
+ public:
+ CefFillLayoutCToCpp();
+ virtual ~CefFillLayoutCToCpp();
+
+ // CefFillLayout methods.
+
+ // CefLayout methods.
+ CefRefPtr<CefBoxLayout> AsBoxLayout() override;
+ CefRefPtr<CefFillLayout> AsFillLayout() override;
+ bool IsValid() override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_VIEWS_FILL_LAYOUT_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/views/label_button_ctocpp.cc b/libcef_dll/ctocpp/views/label_button_ctocpp.cc
new file mode 100644
index 00000000..ac114c30
--- /dev/null
+++ b/libcef_dll/ctocpp/views/label_button_ctocpp.cc
@@ -0,0 +1,1242 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=2b5dc6a8e2cea55a4a2d6f2e66dcfd5c08550d7b$
+//
+
+#include "libcef_dll/ctocpp/views/label_button_ctocpp.h"
+#include "libcef_dll/cpptoc/views/button_delegate_cpptoc.h"
+#include "libcef_dll/cpptoc/views/view_delegate_cpptoc.h"
+#include "libcef_dll/ctocpp/image_ctocpp.h"
+#include "libcef_dll/ctocpp/views/browser_view_ctocpp.h"
+#include "libcef_dll/ctocpp/views/button_ctocpp.h"
+#include "libcef_dll/ctocpp/views/menu_button_ctocpp.h"
+#include "libcef_dll/ctocpp/views/panel_ctocpp.h"
+#include "libcef_dll/ctocpp/views/scroll_view_ctocpp.h"
+#include "libcef_dll/ctocpp/views/textfield_ctocpp.h"
+#include "libcef_dll/ctocpp/views/view_ctocpp.h"
+#include "libcef_dll/ctocpp/views/window_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// STATIC METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefLabelButton> CefLabelButton::CreateLabelButton(
+ CefRefPtr<CefButtonDelegate> delegate,
+ const CefString& text) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: delegate; type: refptr_diff
+ DCHECK(delegate.get());
+ if (!delegate.get()) {
+ return nullptr;
+ }
+ // Unverified params: text
+
+ // Execute
+ cef_label_button_t* _retval = cef_label_button_create(
+ CefButtonDelegateCppToC::Wrap(delegate), text.GetStruct());
+
+ // Return type: refptr_same
+ return CefLabelButtonCToCpp::Wrap(_retval);
+}
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefMenuButton> CefLabelButtonCToCpp::AsMenuButton() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_label_button_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, as_menu_button)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_menu_button_t* _retval = _struct->as_menu_button(_struct);
+
+ // Return type: refptr_same
+ return CefMenuButtonCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefLabelButtonCToCpp::SetText(const CefString& text) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_label_button_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_text)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: text; type: string_byref_const
+ DCHECK(!text.empty());
+ if (text.empty()) {
+ return;
+ }
+
+ // Execute
+ _struct->set_text(_struct, text.GetStruct());
+}
+
+NO_SANITIZE("cfi-icall") CefString CefLabelButtonCToCpp::GetText() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_label_button_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_text)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_text(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefLabelButtonCToCpp::SetImage(cef_button_state_t button_state,
+ CefRefPtr<CefImage> image) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_label_button_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_image)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: image
+
+ // Execute
+ _struct->set_image(_struct, button_state, CefImageCToCpp::Unwrap(image));
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefImage> CefLabelButtonCToCpp::GetImage(
+ cef_button_state_t button_state) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_label_button_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_image)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_image_t* _retval = _struct->get_image(_struct, button_state);
+
+ // Return type: refptr_same
+ return CefImageCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefLabelButtonCToCpp::SetTextColor(cef_button_state_t for_state,
+ cef_color_t color) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_label_button_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_text_color)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_text_color(_struct, for_state, color);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefLabelButtonCToCpp::SetEnabledTextColors(cef_color_t color) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_label_button_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_enabled_text_colors)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_enabled_text_colors(_struct, color);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefLabelButtonCToCpp::SetFontList(const CefString& font_list) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_label_button_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_font_list)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: font_list; type: string_byref_const
+ DCHECK(!font_list.empty());
+ if (font_list.empty()) {
+ return;
+ }
+
+ // Execute
+ _struct->set_font_list(_struct, font_list.GetStruct());
+}
+
+NO_SANITIZE("cfi-icall")
+void CefLabelButtonCToCpp::SetHorizontalAlignment(
+ cef_horizontal_alignment_t alignment) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_label_button_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_horizontal_alignment)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_horizontal_alignment(_struct, alignment);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefLabelButtonCToCpp::SetMinimumSize(const CefSize& size) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_label_button_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_minimum_size)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_minimum_size(_struct, &size);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefLabelButtonCToCpp::SetMaximumSize(const CefSize& size) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_label_button_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_maximum_size)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_maximum_size(_struct, &size);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefLabelButton> CefLabelButtonCToCpp::AsLabelButton() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_button_t* _struct = reinterpret_cast<cef_button_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, as_label_button)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_label_button_t* _retval = _struct->as_label_button(_struct);
+
+ // Return type: refptr_same
+ return CefLabelButtonCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefLabelButtonCToCpp::SetState(cef_button_state_t state) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_button_t* _struct = reinterpret_cast<cef_button_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_state)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_state(_struct, state);
+}
+
+NO_SANITIZE("cfi-icall") cef_button_state_t CefLabelButtonCToCpp::GetState() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_button_t* _struct = reinterpret_cast<cef_button_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_state)) {
+ return CEF_BUTTON_STATE_NORMAL;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_button_state_t _retval = _struct->get_state(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefLabelButtonCToCpp::SetInkDropEnabled(bool enabled) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_button_t* _struct = reinterpret_cast<cef_button_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_ink_drop_enabled)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_ink_drop_enabled(_struct, enabled);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefLabelButtonCToCpp::SetTooltipText(const CefString& tooltip_text) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_button_t* _struct = reinterpret_cast<cef_button_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_tooltip_text)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: tooltip_text; type: string_byref_const
+ DCHECK(!tooltip_text.empty());
+ if (tooltip_text.empty()) {
+ return;
+ }
+
+ // Execute
+ _struct->set_tooltip_text(_struct, tooltip_text.GetStruct());
+}
+
+NO_SANITIZE("cfi-icall")
+void CefLabelButtonCToCpp::SetAccessibleName(const CefString& name) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_button_t* _struct = reinterpret_cast<cef_button_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_accessible_name)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: name; type: string_byref_const
+ DCHECK(!name.empty());
+ if (name.empty()) {
+ return;
+ }
+
+ // Execute
+ _struct->set_accessible_name(_struct, name.GetStruct());
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefBrowserView> CefLabelButtonCToCpp::AsBrowserView() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, as_browser_view)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_browser_view_t* _retval = _struct->as_browser_view(_struct);
+
+ // Return type: refptr_same
+ return CefBrowserViewCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefButton> CefLabelButtonCToCpp::AsButton() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, as_button)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_button_t* _retval = _struct->as_button(_struct);
+
+ // Return type: refptr_same
+ return CefButtonCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefPanel> CefLabelButtonCToCpp::AsPanel() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, as_panel)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_panel_t* _retval = _struct->as_panel(_struct);
+
+ // Return type: refptr_same
+ return CefPanelCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefScrollView> CefLabelButtonCToCpp::AsScrollView() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, as_scroll_view)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_scroll_view_t* _retval = _struct->as_scroll_view(_struct);
+
+ // Return type: refptr_same
+ return CefScrollViewCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefTextfield> CefLabelButtonCToCpp::AsTextfield() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, as_textfield)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_textfield_t* _retval = _struct->as_textfield(_struct);
+
+ // Return type: refptr_same
+ return CefTextfieldCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") CefString CefLabelButtonCToCpp::GetTypeString() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_type_string)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_type_string(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+CefString CefLabelButtonCToCpp::ToString(bool include_children) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, to_string)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->to_string(_struct, include_children);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") bool CefLabelButtonCToCpp::IsValid() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_valid)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_valid(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefLabelButtonCToCpp::IsAttached() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_attached)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_attached(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefLabelButtonCToCpp::IsSame(CefRefPtr<CefView> that) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_same)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: that; type: refptr_same
+ DCHECK(that.get());
+ if (!that.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->is_same(_struct, CefViewCToCpp::Unwrap(that));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefViewDelegate> CefLabelButtonCToCpp::GetDelegate() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_delegate)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_view_delegate_t* _retval = _struct->get_delegate(_struct);
+
+ // Return type: refptr_diff
+ return CefViewDelegateCppToC::Unwrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefWindow> CefLabelButtonCToCpp::GetWindow() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_window)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_window_t* _retval = _struct->get_window(_struct);
+
+ // Return type: refptr_same
+ return CefWindowCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") int CefLabelButtonCToCpp::GetID() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_id)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_id(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") void CefLabelButtonCToCpp::SetID(int id) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_id)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_id(_struct, id);
+}
+
+NO_SANITIZE("cfi-icall") int CefLabelButtonCToCpp::GetGroupID() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_group_id)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_group_id(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") void CefLabelButtonCToCpp::SetGroupID(int group_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_group_id)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_group_id(_struct, group_id);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefView> CefLabelButtonCToCpp::GetParentView() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_parent_view)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_view_t* _retval = _struct->get_parent_view(_struct);
+
+ // Return type: refptr_same
+ return CefViewCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefView> CefLabelButtonCToCpp::GetViewForID(int id) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_view_for_id)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_view_t* _retval = _struct->get_view_for_id(_struct, id);
+
+ // Return type: refptr_same
+ return CefViewCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefLabelButtonCToCpp::SetBounds(const CefRect& bounds) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_bounds)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_bounds(_struct, &bounds);
+}
+
+NO_SANITIZE("cfi-icall") CefRect CefLabelButtonCToCpp::GetBounds() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_bounds)) {
+ return CefRect();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_rect_t _retval = _struct->get_bounds(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") CefRect CefLabelButtonCToCpp::GetBoundsInScreen() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_bounds_in_screen)) {
+ return CefRect();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_rect_t _retval = _struct->get_bounds_in_screen(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefLabelButtonCToCpp::SetSize(const CefSize& size) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_size)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_size(_struct, &size);
+}
+
+NO_SANITIZE("cfi-icall") CefSize CefLabelButtonCToCpp::GetSize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_size_t _retval = _struct->get_size(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefLabelButtonCToCpp::SetPosition(const CefPoint& position) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_position)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_position(_struct, &position);
+}
+
+NO_SANITIZE("cfi-icall") CefPoint CefLabelButtonCToCpp::GetPosition() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_position)) {
+ return CefPoint();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_point_t _retval = _struct->get_position(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefLabelButtonCToCpp::SetInsets(const CefInsets& insets) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_insets)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_insets(_struct, &insets);
+}
+
+NO_SANITIZE("cfi-icall") CefInsets CefLabelButtonCToCpp::GetInsets() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_insets)) {
+ return CefInsets();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_insets_t _retval = _struct->get_insets(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") CefSize CefLabelButtonCToCpp::GetPreferredSize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_preferred_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_size_t _retval = _struct->get_preferred_size(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") void CefLabelButtonCToCpp::SizeToPreferredSize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, size_to_preferred_size)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->size_to_preferred_size(_struct);
+}
+
+NO_SANITIZE("cfi-icall") CefSize CefLabelButtonCToCpp::GetMinimumSize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_minimum_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_size_t _retval = _struct->get_minimum_size(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") CefSize CefLabelButtonCToCpp::GetMaximumSize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_maximum_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_size_t _retval = _struct->get_maximum_size(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+int CefLabelButtonCToCpp::GetHeightForWidth(int width) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_height_for_width)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_height_for_width(_struct, width);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") void CefLabelButtonCToCpp::InvalidateLayout() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, invalidate_layout)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->invalidate_layout(_struct);
+}
+
+NO_SANITIZE("cfi-icall") void CefLabelButtonCToCpp::SetVisible(bool visible) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_visible)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_visible(_struct, visible);
+}
+
+NO_SANITIZE("cfi-icall") bool CefLabelButtonCToCpp::IsVisible() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_visible)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_visible(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefLabelButtonCToCpp::IsDrawn() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_drawn)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_drawn(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") void CefLabelButtonCToCpp::SetEnabled(bool enabled) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_enabled)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_enabled(_struct, enabled);
+}
+
+NO_SANITIZE("cfi-icall") bool CefLabelButtonCToCpp::IsEnabled() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_enabled)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_enabled(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefLabelButtonCToCpp::SetFocusable(bool focusable) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_focusable)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_focusable(_struct, focusable);
+}
+
+NO_SANITIZE("cfi-icall") bool CefLabelButtonCToCpp::IsFocusable() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_focusable)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_focusable(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefLabelButtonCToCpp::IsAccessibilityFocusable() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_accessibility_focusable)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_accessibility_focusable(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") void CefLabelButtonCToCpp::RequestFocus() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, request_focus)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->request_focus(_struct);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefLabelButtonCToCpp::SetBackgroundColor(cef_color_t color) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_background_color)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_background_color(_struct, color);
+}
+
+NO_SANITIZE("cfi-icall")
+cef_color_t CefLabelButtonCToCpp::GetBackgroundColor() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_background_color)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_color_t _retval = _struct->get_background_color(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefLabelButtonCToCpp::ConvertPointToScreen(CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, convert_point_to_screen)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->convert_point_to_screen(_struct, &point);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefLabelButtonCToCpp::ConvertPointFromScreen(CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, convert_point_from_screen)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->convert_point_from_screen(_struct, &point);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefLabelButtonCToCpp::ConvertPointToWindow(CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, convert_point_to_window)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->convert_point_to_window(_struct, &point);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefLabelButtonCToCpp::ConvertPointFromWindow(CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, convert_point_from_window)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->convert_point_from_window(_struct, &point);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefLabelButtonCToCpp::ConvertPointToView(CefRefPtr<CefView> view,
+ CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, convert_point_to_view)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_same
+ DCHECK(view.get());
+ if (!view.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->convert_point_to_view(
+ _struct, CefViewCToCpp::Unwrap(view), &point);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefLabelButtonCToCpp::ConvertPointFromView(CefRefPtr<CefView> view,
+ CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, convert_point_from_view)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_same
+ DCHECK(view.get());
+ if (!view.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->convert_point_from_view(
+ _struct, CefViewCToCpp::Unwrap(view), &point);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefLabelButtonCToCpp::CefLabelButtonCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefLabelButtonCToCpp::~CefLabelButtonCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_label_button_t*
+CefCToCppRefCounted<CefLabelButtonCToCpp, CefLabelButton, cef_label_button_t>::
+ UnwrapDerived(CefWrapperType type, CefLabelButton* c) {
+ if (type == WT_MENU_BUTTON) {
+ return reinterpret_cast<cef_label_button_t*>(
+ CefMenuButtonCToCpp::Unwrap(reinterpret_cast<CefMenuButton*>(c)));
+ }
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefLabelButtonCToCpp,
+ CefLabelButton,
+ cef_label_button_t>::kWrapperType =
+ WT_LABEL_BUTTON;
diff --git a/libcef_dll/ctocpp/views/label_button_ctocpp.h b/libcef_dll/ctocpp/views/label_button_ctocpp.h
new file mode 100644
index 00000000..d7f20dcd
--- /dev/null
+++ b/libcef_dll/ctocpp/views/label_button_ctocpp.h
@@ -0,0 +1,113 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=e54619e16a7a8f21cdeeb4ddfcedf3504c258d35$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_VIEWS_LABEL_BUTTON_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_VIEWS_LABEL_BUTTON_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/views/cef_label_button_capi.h"
+#include "include/capi/views/cef_menu_button_capi.h"
+#include "include/views/cef_label_button.h"
+#include "include/views/cef_menu_button.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefLabelButtonCToCpp : public CefCToCppRefCounted<CefLabelButtonCToCpp,
+ CefLabelButton,
+ cef_label_button_t> {
+ public:
+ CefLabelButtonCToCpp();
+ virtual ~CefLabelButtonCToCpp();
+
+ // CefLabelButton methods.
+ CefRefPtr<CefMenuButton> AsMenuButton() override;
+ void SetText(const CefString& text) override;
+ CefString GetText() override;
+ void SetImage(cef_button_state_t button_state,
+ CefRefPtr<CefImage> image) override;
+ CefRefPtr<CefImage> GetImage(cef_button_state_t button_state) override;
+ void SetTextColor(cef_button_state_t for_state, cef_color_t color) override;
+ void SetEnabledTextColors(cef_color_t color) override;
+ void SetFontList(const CefString& font_list) override;
+ void SetHorizontalAlignment(cef_horizontal_alignment_t alignment) override;
+ void SetMinimumSize(const CefSize& size) override;
+ void SetMaximumSize(const CefSize& size) override;
+
+ // CefButton methods.
+ CefRefPtr<CefLabelButton> AsLabelButton() override;
+ void SetState(cef_button_state_t state) override;
+ cef_button_state_t GetState() override;
+ void SetInkDropEnabled(bool enabled) override;
+ void SetTooltipText(const CefString& tooltip_text) override;
+ void SetAccessibleName(const CefString& name) override;
+
+ // CefView methods.
+ CefRefPtr<CefBrowserView> AsBrowserView() override;
+ CefRefPtr<CefButton> AsButton() override;
+ CefRefPtr<CefPanel> AsPanel() override;
+ CefRefPtr<CefScrollView> AsScrollView() override;
+ CefRefPtr<CefTextfield> AsTextfield() override;
+ CefString GetTypeString() override;
+ CefString ToString(bool include_children) override;
+ bool IsValid() override;
+ bool IsAttached() override;
+ bool IsSame(CefRefPtr<CefView> that) override;
+ CefRefPtr<CefViewDelegate> GetDelegate() override;
+ CefRefPtr<CefWindow> GetWindow() override;
+ int GetID() override;
+ void SetID(int id) override;
+ int GetGroupID() override;
+ void SetGroupID(int group_id) override;
+ CefRefPtr<CefView> GetParentView() override;
+ CefRefPtr<CefView> GetViewForID(int id) override;
+ void SetBounds(const CefRect& bounds) override;
+ CefRect GetBounds() override;
+ CefRect GetBoundsInScreen() override;
+ void SetSize(const CefSize& size) override;
+ CefSize GetSize() override;
+ void SetPosition(const CefPoint& position) override;
+ CefPoint GetPosition() override;
+ void SetInsets(const CefInsets& insets) override;
+ CefInsets GetInsets() override;
+ CefSize GetPreferredSize() override;
+ void SizeToPreferredSize() override;
+ CefSize GetMinimumSize() override;
+ CefSize GetMaximumSize() override;
+ int GetHeightForWidth(int width) override;
+ void InvalidateLayout() override;
+ void SetVisible(bool visible) override;
+ bool IsVisible() override;
+ bool IsDrawn() override;
+ void SetEnabled(bool enabled) override;
+ bool IsEnabled() override;
+ void SetFocusable(bool focusable) override;
+ bool IsFocusable() override;
+ bool IsAccessibilityFocusable() override;
+ void RequestFocus() override;
+ void SetBackgroundColor(cef_color_t color) override;
+ cef_color_t GetBackgroundColor() override;
+ bool ConvertPointToScreen(CefPoint& point) override;
+ bool ConvertPointFromScreen(CefPoint& point) override;
+ bool ConvertPointToWindow(CefPoint& point) override;
+ bool ConvertPointFromWindow(CefPoint& point) override;
+ bool ConvertPointToView(CefRefPtr<CefView> view, CefPoint& point) override;
+ bool ConvertPointFromView(CefRefPtr<CefView> view, CefPoint& point) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_VIEWS_LABEL_BUTTON_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/views/layout_ctocpp.cc b/libcef_dll/ctocpp/views/layout_ctocpp.cc
new file mode 100644
index 00000000..280adf89
--- /dev/null
+++ b/libcef_dll/ctocpp/views/layout_ctocpp.cc
@@ -0,0 +1,104 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=312e5c15b26db94513fe213fbcfba6d1c43e39b7$
+//
+
+#include "libcef_dll/ctocpp/views/layout_ctocpp.h"
+#include "libcef_dll/ctocpp/views/box_layout_ctocpp.h"
+#include "libcef_dll/ctocpp/views/fill_layout_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefBoxLayout> CefLayoutCToCpp::AsBoxLayout() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_layout_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, as_box_layout)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_box_layout_t* _retval = _struct->as_box_layout(_struct);
+
+ // Return type: refptr_same
+ return CefBoxLayoutCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefFillLayout> CefLayoutCToCpp::AsFillLayout() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_layout_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, as_fill_layout)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_fill_layout_t* _retval = _struct->as_fill_layout(_struct);
+
+ // Return type: refptr_same
+ return CefFillLayoutCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") bool CefLayoutCToCpp::IsValid() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_layout_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_valid)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_valid(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefLayoutCToCpp::CefLayoutCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefLayoutCToCpp::~CefLayoutCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_layout_t*
+CefCToCppRefCounted<CefLayoutCToCpp, CefLayout, cef_layout_t>::UnwrapDerived(
+ CefWrapperType type,
+ CefLayout* c) {
+ if (type == WT_BOX_LAYOUT) {
+ return reinterpret_cast<cef_layout_t*>(
+ CefBoxLayoutCToCpp::Unwrap(reinterpret_cast<CefBoxLayout*>(c)));
+ }
+ if (type == WT_FILL_LAYOUT) {
+ return reinterpret_cast<cef_layout_t*>(
+ CefFillLayoutCToCpp::Unwrap(reinterpret_cast<CefFillLayout*>(c)));
+ }
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefLayoutCToCpp, CefLayout, cef_layout_t>::
+ kWrapperType = WT_LAYOUT;
diff --git a/libcef_dll/ctocpp/views/layout_ctocpp.h b/libcef_dll/ctocpp/views/layout_ctocpp.h
new file mode 100644
index 00000000..6ffa76d3
--- /dev/null
+++ b/libcef_dll/ctocpp/views/layout_ctocpp.h
@@ -0,0 +1,45 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=f50cae9c7f44f282497cff43e8b89fc76f60e51b$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_VIEWS_LAYOUT_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_VIEWS_LAYOUT_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/views/cef_box_layout_capi.h"
+#include "include/capi/views/cef_fill_layout_capi.h"
+#include "include/capi/views/cef_layout_capi.h"
+#include "include/views/cef_box_layout.h"
+#include "include/views/cef_fill_layout.h"
+#include "include/views/cef_layout.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefLayoutCToCpp
+ : public CefCToCppRefCounted<CefLayoutCToCpp, CefLayout, cef_layout_t> {
+ public:
+ CefLayoutCToCpp();
+ virtual ~CefLayoutCToCpp();
+
+ // CefLayout methods.
+ CefRefPtr<CefBoxLayout> AsBoxLayout() override;
+ CefRefPtr<CefFillLayout> AsFillLayout() override;
+ bool IsValid() override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_VIEWS_LAYOUT_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/views/menu_button_ctocpp.cc b/libcef_dll/ctocpp/views/menu_button_ctocpp.cc
new file mode 100644
index 00000000..cffaf96b
--- /dev/null
+++ b/libcef_dll/ctocpp/views/menu_button_ctocpp.cc
@@ -0,0 +1,1285 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=2ecf87822e0901130b8738a0e6b0d663129404a2$
+//
+
+#include "libcef_dll/ctocpp/views/menu_button_ctocpp.h"
+#include "libcef_dll/cpptoc/views/menu_button_delegate_cpptoc.h"
+#include "libcef_dll/cpptoc/views/view_delegate_cpptoc.h"
+#include "libcef_dll/ctocpp/image_ctocpp.h"
+#include "libcef_dll/ctocpp/menu_model_ctocpp.h"
+#include "libcef_dll/ctocpp/views/browser_view_ctocpp.h"
+#include "libcef_dll/ctocpp/views/button_ctocpp.h"
+#include "libcef_dll/ctocpp/views/label_button_ctocpp.h"
+#include "libcef_dll/ctocpp/views/panel_ctocpp.h"
+#include "libcef_dll/ctocpp/views/scroll_view_ctocpp.h"
+#include "libcef_dll/ctocpp/views/textfield_ctocpp.h"
+#include "libcef_dll/ctocpp/views/view_ctocpp.h"
+#include "libcef_dll/ctocpp/views/window_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// STATIC METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefMenuButton> CefMenuButton::CreateMenuButton(
+ CefRefPtr<CefMenuButtonDelegate> delegate,
+ const CefString& text) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: delegate; type: refptr_diff
+ DCHECK(delegate.get());
+ if (!delegate.get()) {
+ return nullptr;
+ }
+ // Unverified params: text
+
+ // Execute
+ cef_menu_button_t* _retval = cef_menu_button_create(
+ CefMenuButtonDelegateCppToC::Wrap(delegate), text.GetStruct());
+
+ // Return type: refptr_same
+ return CefMenuButtonCToCpp::Wrap(_retval);
+}
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+void CefMenuButtonCToCpp::ShowMenu(CefRefPtr<CefMenuModel> menu_model,
+ const CefPoint& screen_point,
+ cef_menu_anchor_position_t anchor_position) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_button_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, show_menu)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: menu_model; type: refptr_same
+ DCHECK(menu_model.get());
+ if (!menu_model.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->show_menu(_struct, CefMenuModelCToCpp::Unwrap(menu_model),
+ &screen_point, anchor_position);
+}
+
+NO_SANITIZE("cfi-icall") void CefMenuButtonCToCpp::TriggerMenu() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_button_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, trigger_menu)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->trigger_menu(_struct);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefMenuButton> CefMenuButtonCToCpp::AsMenuButton() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_label_button_t* _struct =
+ reinterpret_cast<cef_label_button_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, as_menu_button)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_menu_button_t* _retval = _struct->as_menu_button(_struct);
+
+ // Return type: refptr_same
+ return CefMenuButtonCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefMenuButtonCToCpp::SetText(const CefString& text) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_label_button_t* _struct =
+ reinterpret_cast<cef_label_button_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_text)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: text; type: string_byref_const
+ DCHECK(!text.empty());
+ if (text.empty()) {
+ return;
+ }
+
+ // Execute
+ _struct->set_text(_struct, text.GetStruct());
+}
+
+NO_SANITIZE("cfi-icall") CefString CefMenuButtonCToCpp::GetText() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_label_button_t* _struct =
+ reinterpret_cast<cef_label_button_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_text)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_text(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefMenuButtonCToCpp::SetImage(cef_button_state_t button_state,
+ CefRefPtr<CefImage> image) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_label_button_t* _struct =
+ reinterpret_cast<cef_label_button_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_image)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: image
+
+ // Execute
+ _struct->set_image(_struct, button_state, CefImageCToCpp::Unwrap(image));
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefImage> CefMenuButtonCToCpp::GetImage(
+ cef_button_state_t button_state) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_label_button_t* _struct =
+ reinterpret_cast<cef_label_button_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_image)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_image_t* _retval = _struct->get_image(_struct, button_state);
+
+ // Return type: refptr_same
+ return CefImageCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefMenuButtonCToCpp::SetTextColor(cef_button_state_t for_state,
+ cef_color_t color) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_label_button_t* _struct =
+ reinterpret_cast<cef_label_button_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_text_color)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_text_color(_struct, for_state, color);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefMenuButtonCToCpp::SetEnabledTextColors(cef_color_t color) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_label_button_t* _struct =
+ reinterpret_cast<cef_label_button_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_enabled_text_colors)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_enabled_text_colors(_struct, color);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefMenuButtonCToCpp::SetFontList(const CefString& font_list) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_label_button_t* _struct =
+ reinterpret_cast<cef_label_button_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_font_list)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: font_list; type: string_byref_const
+ DCHECK(!font_list.empty());
+ if (font_list.empty()) {
+ return;
+ }
+
+ // Execute
+ _struct->set_font_list(_struct, font_list.GetStruct());
+}
+
+NO_SANITIZE("cfi-icall")
+void CefMenuButtonCToCpp::SetHorizontalAlignment(
+ cef_horizontal_alignment_t alignment) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_label_button_t* _struct =
+ reinterpret_cast<cef_label_button_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_horizontal_alignment)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_horizontal_alignment(_struct, alignment);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefMenuButtonCToCpp::SetMinimumSize(const CefSize& size) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_label_button_t* _struct =
+ reinterpret_cast<cef_label_button_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_minimum_size)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_minimum_size(_struct, &size);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefMenuButtonCToCpp::SetMaximumSize(const CefSize& size) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_label_button_t* _struct =
+ reinterpret_cast<cef_label_button_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_maximum_size)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_maximum_size(_struct, &size);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefLabelButton> CefMenuButtonCToCpp::AsLabelButton() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_button_t* _struct = reinterpret_cast<cef_button_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, as_label_button)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_label_button_t* _retval = _struct->as_label_button(_struct);
+
+ // Return type: refptr_same
+ return CefLabelButtonCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefMenuButtonCToCpp::SetState(cef_button_state_t state) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_button_t* _struct = reinterpret_cast<cef_button_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_state)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_state(_struct, state);
+}
+
+NO_SANITIZE("cfi-icall") cef_button_state_t CefMenuButtonCToCpp::GetState() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_button_t* _struct = reinterpret_cast<cef_button_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_state)) {
+ return CEF_BUTTON_STATE_NORMAL;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_button_state_t _retval = _struct->get_state(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefMenuButtonCToCpp::SetInkDropEnabled(bool enabled) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_button_t* _struct = reinterpret_cast<cef_button_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_ink_drop_enabled)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_ink_drop_enabled(_struct, enabled);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefMenuButtonCToCpp::SetTooltipText(const CefString& tooltip_text) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_button_t* _struct = reinterpret_cast<cef_button_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_tooltip_text)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: tooltip_text; type: string_byref_const
+ DCHECK(!tooltip_text.empty());
+ if (tooltip_text.empty()) {
+ return;
+ }
+
+ // Execute
+ _struct->set_tooltip_text(_struct, tooltip_text.GetStruct());
+}
+
+NO_SANITIZE("cfi-icall")
+void CefMenuButtonCToCpp::SetAccessibleName(const CefString& name) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_button_t* _struct = reinterpret_cast<cef_button_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_accessible_name)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: name; type: string_byref_const
+ DCHECK(!name.empty());
+ if (name.empty()) {
+ return;
+ }
+
+ // Execute
+ _struct->set_accessible_name(_struct, name.GetStruct());
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefBrowserView> CefMenuButtonCToCpp::AsBrowserView() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, as_browser_view)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_browser_view_t* _retval = _struct->as_browser_view(_struct);
+
+ // Return type: refptr_same
+ return CefBrowserViewCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefButton> CefMenuButtonCToCpp::AsButton() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, as_button)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_button_t* _retval = _struct->as_button(_struct);
+
+ // Return type: refptr_same
+ return CefButtonCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefPanel> CefMenuButtonCToCpp::AsPanel() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, as_panel)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_panel_t* _retval = _struct->as_panel(_struct);
+
+ // Return type: refptr_same
+ return CefPanelCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefScrollView> CefMenuButtonCToCpp::AsScrollView() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, as_scroll_view)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_scroll_view_t* _retval = _struct->as_scroll_view(_struct);
+
+ // Return type: refptr_same
+ return CefScrollViewCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefTextfield> CefMenuButtonCToCpp::AsTextfield() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, as_textfield)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_textfield_t* _retval = _struct->as_textfield(_struct);
+
+ // Return type: refptr_same
+ return CefTextfieldCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") CefString CefMenuButtonCToCpp::GetTypeString() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_type_string)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_type_string(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+CefString CefMenuButtonCToCpp::ToString(bool include_children) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, to_string)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->to_string(_struct, include_children);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") bool CefMenuButtonCToCpp::IsValid() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_valid)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_valid(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefMenuButtonCToCpp::IsAttached() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_attached)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_attached(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefMenuButtonCToCpp::IsSame(CefRefPtr<CefView> that) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_same)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: that; type: refptr_same
+ DCHECK(that.get());
+ if (!that.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->is_same(_struct, CefViewCToCpp::Unwrap(that));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefViewDelegate> CefMenuButtonCToCpp::GetDelegate() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_delegate)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_view_delegate_t* _retval = _struct->get_delegate(_struct);
+
+ // Return type: refptr_diff
+ return CefViewDelegateCppToC::Unwrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefWindow> CefMenuButtonCToCpp::GetWindow() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_window)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_window_t* _retval = _struct->get_window(_struct);
+
+ // Return type: refptr_same
+ return CefWindowCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") int CefMenuButtonCToCpp::GetID() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_id)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_id(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") void CefMenuButtonCToCpp::SetID(int id) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_id)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_id(_struct, id);
+}
+
+NO_SANITIZE("cfi-icall") int CefMenuButtonCToCpp::GetGroupID() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_group_id)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_group_id(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") void CefMenuButtonCToCpp::SetGroupID(int group_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_group_id)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_group_id(_struct, group_id);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefView> CefMenuButtonCToCpp::GetParentView() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_parent_view)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_view_t* _retval = _struct->get_parent_view(_struct);
+
+ // Return type: refptr_same
+ return CefViewCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefView> CefMenuButtonCToCpp::GetViewForID(int id) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_view_for_id)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_view_t* _retval = _struct->get_view_for_id(_struct, id);
+
+ // Return type: refptr_same
+ return CefViewCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefMenuButtonCToCpp::SetBounds(const CefRect& bounds) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_bounds)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_bounds(_struct, &bounds);
+}
+
+NO_SANITIZE("cfi-icall") CefRect CefMenuButtonCToCpp::GetBounds() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_bounds)) {
+ return CefRect();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_rect_t _retval = _struct->get_bounds(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") CefRect CefMenuButtonCToCpp::GetBoundsInScreen() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_bounds_in_screen)) {
+ return CefRect();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_rect_t _retval = _struct->get_bounds_in_screen(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefMenuButtonCToCpp::SetSize(const CefSize& size) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_size)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_size(_struct, &size);
+}
+
+NO_SANITIZE("cfi-icall") CefSize CefMenuButtonCToCpp::GetSize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_size_t _retval = _struct->get_size(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefMenuButtonCToCpp::SetPosition(const CefPoint& position) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_position)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_position(_struct, &position);
+}
+
+NO_SANITIZE("cfi-icall") CefPoint CefMenuButtonCToCpp::GetPosition() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_position)) {
+ return CefPoint();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_point_t _retval = _struct->get_position(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefMenuButtonCToCpp::SetInsets(const CefInsets& insets) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_insets)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_insets(_struct, &insets);
+}
+
+NO_SANITIZE("cfi-icall") CefInsets CefMenuButtonCToCpp::GetInsets() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_insets)) {
+ return CefInsets();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_insets_t _retval = _struct->get_insets(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") CefSize CefMenuButtonCToCpp::GetPreferredSize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_preferred_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_size_t _retval = _struct->get_preferred_size(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") void CefMenuButtonCToCpp::SizeToPreferredSize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, size_to_preferred_size)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->size_to_preferred_size(_struct);
+}
+
+NO_SANITIZE("cfi-icall") CefSize CefMenuButtonCToCpp::GetMinimumSize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_minimum_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_size_t _retval = _struct->get_minimum_size(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") CefSize CefMenuButtonCToCpp::GetMaximumSize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_maximum_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_size_t _retval = _struct->get_maximum_size(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") int CefMenuButtonCToCpp::GetHeightForWidth(int width) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_height_for_width)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_height_for_width(_struct, width);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") void CefMenuButtonCToCpp::InvalidateLayout() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, invalidate_layout)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->invalidate_layout(_struct);
+}
+
+NO_SANITIZE("cfi-icall") void CefMenuButtonCToCpp::SetVisible(bool visible) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_visible)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_visible(_struct, visible);
+}
+
+NO_SANITIZE("cfi-icall") bool CefMenuButtonCToCpp::IsVisible() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_visible)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_visible(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefMenuButtonCToCpp::IsDrawn() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_drawn)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_drawn(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") void CefMenuButtonCToCpp::SetEnabled(bool enabled) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_enabled)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_enabled(_struct, enabled);
+}
+
+NO_SANITIZE("cfi-icall") bool CefMenuButtonCToCpp::IsEnabled() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_enabled)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_enabled(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefMenuButtonCToCpp::SetFocusable(bool focusable) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_focusable)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_focusable(_struct, focusable);
+}
+
+NO_SANITIZE("cfi-icall") bool CefMenuButtonCToCpp::IsFocusable() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_focusable)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_focusable(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefMenuButtonCToCpp::IsAccessibilityFocusable() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_accessibility_focusable)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_accessibility_focusable(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") void CefMenuButtonCToCpp::RequestFocus() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, request_focus)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->request_focus(_struct);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefMenuButtonCToCpp::SetBackgroundColor(cef_color_t color) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_background_color)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_background_color(_struct, color);
+}
+
+NO_SANITIZE("cfi-icall") cef_color_t CefMenuButtonCToCpp::GetBackgroundColor() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_background_color)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_color_t _retval = _struct->get_background_color(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefMenuButtonCToCpp::ConvertPointToScreen(CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, convert_point_to_screen)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->convert_point_to_screen(_struct, &point);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefMenuButtonCToCpp::ConvertPointFromScreen(CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, convert_point_from_screen)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->convert_point_from_screen(_struct, &point);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefMenuButtonCToCpp::ConvertPointToWindow(CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, convert_point_to_window)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->convert_point_to_window(_struct, &point);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefMenuButtonCToCpp::ConvertPointFromWindow(CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, convert_point_from_window)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->convert_point_from_window(_struct, &point);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefMenuButtonCToCpp::ConvertPointToView(CefRefPtr<CefView> view,
+ CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, convert_point_to_view)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_same
+ DCHECK(view.get());
+ if (!view.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->convert_point_to_view(
+ _struct, CefViewCToCpp::Unwrap(view), &point);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefMenuButtonCToCpp::ConvertPointFromView(CefRefPtr<CefView> view,
+ CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, convert_point_from_view)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_same
+ DCHECK(view.get());
+ if (!view.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->convert_point_from_view(
+ _struct, CefViewCToCpp::Unwrap(view), &point);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefMenuButtonCToCpp::CefMenuButtonCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefMenuButtonCToCpp::~CefMenuButtonCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_menu_button_t*
+CefCToCppRefCounted<CefMenuButtonCToCpp, CefMenuButton, cef_menu_button_t>::
+ UnwrapDerived(CefWrapperType type, CefMenuButton* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefMenuButtonCToCpp,
+ CefMenuButton,
+ cef_menu_button_t>::kWrapperType =
+ WT_MENU_BUTTON;
diff --git a/libcef_dll/ctocpp/views/menu_button_ctocpp.h b/libcef_dll/ctocpp/views/menu_button_ctocpp.h
new file mode 100644
index 00000000..77293750
--- /dev/null
+++ b/libcef_dll/ctocpp/views/menu_button_ctocpp.h
@@ -0,0 +1,117 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=0323c84d6099ab582a71a40f8065013cecc126cd$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_VIEWS_MENU_BUTTON_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_VIEWS_MENU_BUTTON_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/views/cef_menu_button_capi.h"
+#include "include/views/cef_menu_button.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefMenuButtonCToCpp : public CefCToCppRefCounted<CefMenuButtonCToCpp,
+ CefMenuButton,
+ cef_menu_button_t> {
+ public:
+ CefMenuButtonCToCpp();
+ virtual ~CefMenuButtonCToCpp();
+
+ // CefMenuButton methods.
+ void ShowMenu(CefRefPtr<CefMenuModel> menu_model,
+ const CefPoint& screen_point,
+ cef_menu_anchor_position_t anchor_position) override;
+ void TriggerMenu() override;
+
+ // CefLabelButton methods.
+ CefRefPtr<CefMenuButton> AsMenuButton() override;
+ void SetText(const CefString& text) override;
+ CefString GetText() override;
+ void SetImage(cef_button_state_t button_state,
+ CefRefPtr<CefImage> image) override;
+ CefRefPtr<CefImage> GetImage(cef_button_state_t button_state) override;
+ void SetTextColor(cef_button_state_t for_state, cef_color_t color) override;
+ void SetEnabledTextColors(cef_color_t color) override;
+ void SetFontList(const CefString& font_list) override;
+ void SetHorizontalAlignment(cef_horizontal_alignment_t alignment) override;
+ void SetMinimumSize(const CefSize& size) override;
+ void SetMaximumSize(const CefSize& size) override;
+
+ // CefButton methods.
+ CefRefPtr<CefLabelButton> AsLabelButton() override;
+ void SetState(cef_button_state_t state) override;
+ cef_button_state_t GetState() override;
+ void SetInkDropEnabled(bool enabled) override;
+ void SetTooltipText(const CefString& tooltip_text) override;
+ void SetAccessibleName(const CefString& name) override;
+
+ // CefView methods.
+ CefRefPtr<CefBrowserView> AsBrowserView() override;
+ CefRefPtr<CefButton> AsButton() override;
+ CefRefPtr<CefPanel> AsPanel() override;
+ CefRefPtr<CefScrollView> AsScrollView() override;
+ CefRefPtr<CefTextfield> AsTextfield() override;
+ CefString GetTypeString() override;
+ CefString ToString(bool include_children) override;
+ bool IsValid() override;
+ bool IsAttached() override;
+ bool IsSame(CefRefPtr<CefView> that) override;
+ CefRefPtr<CefViewDelegate> GetDelegate() override;
+ CefRefPtr<CefWindow> GetWindow() override;
+ int GetID() override;
+ void SetID(int id) override;
+ int GetGroupID() override;
+ void SetGroupID(int group_id) override;
+ CefRefPtr<CefView> GetParentView() override;
+ CefRefPtr<CefView> GetViewForID(int id) override;
+ void SetBounds(const CefRect& bounds) override;
+ CefRect GetBounds() override;
+ CefRect GetBoundsInScreen() override;
+ void SetSize(const CefSize& size) override;
+ CefSize GetSize() override;
+ void SetPosition(const CefPoint& position) override;
+ CefPoint GetPosition() override;
+ void SetInsets(const CefInsets& insets) override;
+ CefInsets GetInsets() override;
+ CefSize GetPreferredSize() override;
+ void SizeToPreferredSize() override;
+ CefSize GetMinimumSize() override;
+ CefSize GetMaximumSize() override;
+ int GetHeightForWidth(int width) override;
+ void InvalidateLayout() override;
+ void SetVisible(bool visible) override;
+ bool IsVisible() override;
+ bool IsDrawn() override;
+ void SetEnabled(bool enabled) override;
+ bool IsEnabled() override;
+ void SetFocusable(bool focusable) override;
+ bool IsFocusable() override;
+ bool IsAccessibilityFocusable() override;
+ void RequestFocus() override;
+ void SetBackgroundColor(cef_color_t color) override;
+ cef_color_t GetBackgroundColor() override;
+ bool ConvertPointToScreen(CefPoint& point) override;
+ bool ConvertPointFromScreen(CefPoint& point) override;
+ bool ConvertPointToWindow(CefPoint& point) override;
+ bool ConvertPointFromWindow(CefPoint& point) override;
+ bool ConvertPointToView(CefRefPtr<CefView> view, CefPoint& point) override;
+ bool ConvertPointFromView(CefRefPtr<CefView> view, CefPoint& point) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_VIEWS_MENU_BUTTON_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/views/menu_button_delegate_ctocpp.cc b/libcef_dll/ctocpp/views/menu_button_delegate_ctocpp.cc
new file mode 100644
index 00000000..f732521f
--- /dev/null
+++ b/libcef_dll/ctocpp/views/menu_button_delegate_ctocpp.cc
@@ -0,0 +1,380 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=4a75c3d8ec4015821d89489f6ea97151c900ac75$
+//
+
+#include "libcef_dll/ctocpp/views/menu_button_delegate_ctocpp.h"
+#include "libcef_dll/cpptoc/views/button_cpptoc.h"
+#include "libcef_dll/cpptoc/views/menu_button_cpptoc.h"
+#include "libcef_dll/cpptoc/views/menu_button_pressed_lock_cpptoc.h"
+#include "libcef_dll/cpptoc/views/view_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+void CefMenuButtonDelegateCToCpp::OnMenuButtonPressed(
+ CefRefPtr<CefMenuButton> menu_button,
+ const CefPoint& screen_point,
+ CefRefPtr<CefMenuButtonPressedLock> button_pressed_lock) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_menu_button_delegate_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_menu_button_pressed)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: menu_button; type: refptr_diff
+ DCHECK(menu_button.get());
+ if (!menu_button.get()) {
+ return;
+ }
+ // Verify param: button_pressed_lock; type: refptr_diff
+ DCHECK(button_pressed_lock.get());
+ if (!button_pressed_lock.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_menu_button_pressed(
+ _struct, CefMenuButtonCppToC::Wrap(menu_button), &screen_point,
+ CefMenuButtonPressedLockCppToC::Wrap(button_pressed_lock));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefMenuButtonDelegateCToCpp::OnButtonPressed(CefRefPtr<CefButton> button) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_button_delegate_t* _struct =
+ reinterpret_cast<cef_button_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, on_button_pressed)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: button; type: refptr_diff
+ DCHECK(button.get());
+ if (!button.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_button_pressed(_struct, CefButtonCppToC::Wrap(button));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefMenuButtonDelegateCToCpp::OnButtonStateChanged(
+ CefRefPtr<CefButton> button) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_button_delegate_t* _struct =
+ reinterpret_cast<cef_button_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, on_button_state_changed)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: button; type: refptr_diff
+ DCHECK(button.get());
+ if (!button.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_button_state_changed(_struct, CefButtonCppToC::Wrap(button));
+}
+
+NO_SANITIZE("cfi-icall")
+CefSize CefMenuButtonDelegateCToCpp::GetPreferredSize(CefRefPtr<CefView> view) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_preferred_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval =
+ _struct->get_preferred_size(_struct, CefViewCppToC::Wrap(view));
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CefSize CefMenuButtonDelegateCToCpp::GetMinimumSize(CefRefPtr<CefView> view) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_minimum_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval =
+ _struct->get_minimum_size(_struct, CefViewCppToC::Wrap(view));
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CefSize CefMenuButtonDelegateCToCpp::GetMaximumSize(CefRefPtr<CefView> view) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_maximum_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval =
+ _struct->get_maximum_size(_struct, CefViewCppToC::Wrap(view));
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+int CefMenuButtonDelegateCToCpp::GetHeightForWidth(CefRefPtr<CefView> view,
+ int width) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_height_for_width)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return 0;
+ }
+
+ // Execute
+ int _retval =
+ _struct->get_height_for_width(_struct, CefViewCppToC::Wrap(view), width);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefMenuButtonDelegateCToCpp::OnParentViewChanged(
+ CefRefPtr<CefView> view,
+ bool added,
+ CefRefPtr<CefView> parent) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, on_parent_view_changed)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return;
+ }
+ // Verify param: parent; type: refptr_diff
+ DCHECK(parent.get());
+ if (!parent.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_parent_view_changed(_struct, CefViewCppToC::Wrap(view), added,
+ CefViewCppToC::Wrap(parent));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefMenuButtonDelegateCToCpp::OnChildViewChanged(CefRefPtr<CefView> view,
+ bool added,
+ CefRefPtr<CefView> child) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, on_child_view_changed)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return;
+ }
+ // Verify param: child; type: refptr_diff
+ DCHECK(child.get());
+ if (!child.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_child_view_changed(_struct, CefViewCppToC::Wrap(view), added,
+ CefViewCppToC::Wrap(child));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefMenuButtonDelegateCToCpp::OnWindowChanged(CefRefPtr<CefView> view,
+ bool added) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, on_window_changed)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_window_changed(_struct, CefViewCppToC::Wrap(view), added);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefMenuButtonDelegateCToCpp::OnLayoutChanged(CefRefPtr<CefView> view,
+ const CefRect& new_bounds) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, on_layout_changed)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_layout_changed(_struct, CefViewCppToC::Wrap(view), &new_bounds);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefMenuButtonDelegateCToCpp::OnFocus(CefRefPtr<CefView> view) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, on_focus)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_focus(_struct, CefViewCppToC::Wrap(view));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefMenuButtonDelegateCToCpp::OnBlur(CefRefPtr<CefView> view) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, on_blur)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_blur(_struct, CefViewCppToC::Wrap(view));
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefMenuButtonDelegateCToCpp::CefMenuButtonDelegateCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefMenuButtonDelegateCToCpp::~CefMenuButtonDelegateCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_menu_button_delegate_t* CefCToCppRefCounted<
+ CefMenuButtonDelegateCToCpp,
+ CefMenuButtonDelegate,
+ cef_menu_button_delegate_t>::UnwrapDerived(CefWrapperType type,
+ CefMenuButtonDelegate* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefMenuButtonDelegateCToCpp,
+ CefMenuButtonDelegate,
+ cef_menu_button_delegate_t>::kWrapperType =
+ WT_MENU_BUTTON_DELEGATE;
diff --git a/libcef_dll/ctocpp/views/menu_button_delegate_ctocpp.h b/libcef_dll/ctocpp/views/menu_button_delegate_ctocpp.h
new file mode 100644
index 00000000..f8906291
--- /dev/null
+++ b/libcef_dll/ctocpp/views/menu_button_delegate_ctocpp.h
@@ -0,0 +1,67 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=962c2d2bc800670d19838fa2a34ab4faa8203531$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_VIEWS_MENU_BUTTON_DELEGATE_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_VIEWS_MENU_BUTTON_DELEGATE_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/views/cef_menu_button_capi.h"
+#include "include/capi/views/cef_menu_button_delegate_capi.h"
+#include "include/views/cef_menu_button.h"
+#include "include/views/cef_menu_button_delegate.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefMenuButtonDelegateCToCpp
+ : public CefCToCppRefCounted<CefMenuButtonDelegateCToCpp,
+ CefMenuButtonDelegate,
+ cef_menu_button_delegate_t> {
+ public:
+ CefMenuButtonDelegateCToCpp();
+ virtual ~CefMenuButtonDelegateCToCpp();
+
+ // CefMenuButtonDelegate methods.
+ void OnMenuButtonPressed(
+ CefRefPtr<CefMenuButton> menu_button,
+ const CefPoint& screen_point,
+ CefRefPtr<CefMenuButtonPressedLock> button_pressed_lock) override;
+
+ // CefButtonDelegate methods.
+ void OnButtonPressed(CefRefPtr<CefButton> button) override;
+ void OnButtonStateChanged(CefRefPtr<CefButton> button) override;
+
+ // CefViewDelegate methods.
+ CefSize GetPreferredSize(CefRefPtr<CefView> view) override;
+ CefSize GetMinimumSize(CefRefPtr<CefView> view) override;
+ CefSize GetMaximumSize(CefRefPtr<CefView> view) override;
+ int GetHeightForWidth(CefRefPtr<CefView> view, int width) override;
+ void OnParentViewChanged(CefRefPtr<CefView> view,
+ bool added,
+ CefRefPtr<CefView> parent) override;
+ void OnChildViewChanged(CefRefPtr<CefView> view,
+ bool added,
+ CefRefPtr<CefView> child) override;
+ void OnWindowChanged(CefRefPtr<CefView> view, bool added) override;
+ void OnLayoutChanged(CefRefPtr<CefView> view,
+ const CefRect& new_bounds) override;
+ void OnFocus(CefRefPtr<CefView> view) override;
+ void OnBlur(CefRefPtr<CefView> view) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_VIEWS_MENU_BUTTON_DELEGATE_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/views/menu_button_pressed_lock_ctocpp.cc b/libcef_dll/ctocpp/views/menu_button_pressed_lock_ctocpp.cc
new file mode 100644
index 00000000..313832fd
--- /dev/null
+++ b/libcef_dll/ctocpp/views/menu_button_pressed_lock_ctocpp.cc
@@ -0,0 +1,44 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=52df98f1359e9a8e231ec9e2555bc883e1fa84b5$
+//
+
+#include "libcef_dll/ctocpp/views/menu_button_pressed_lock_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefMenuButtonPressedLockCToCpp::CefMenuButtonPressedLockCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefMenuButtonPressedLockCToCpp::~CefMenuButtonPressedLockCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_menu_button_pressed_lock_t* CefCToCppRefCounted<
+ CefMenuButtonPressedLockCToCpp,
+ CefMenuButtonPressedLock,
+ cef_menu_button_pressed_lock_t>::UnwrapDerived(CefWrapperType type,
+ CefMenuButtonPressedLock*
+ c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCToCppRefCounted<CefMenuButtonPressedLockCToCpp,
+ CefMenuButtonPressedLock,
+ cef_menu_button_pressed_lock_t>::kWrapperType =
+ WT_MENU_BUTTON_PRESSED_LOCK;
diff --git a/libcef_dll/ctocpp/views/menu_button_pressed_lock_ctocpp.h b/libcef_dll/ctocpp/views/menu_button_pressed_lock_ctocpp.h
new file mode 100644
index 00000000..3a2ce082
--- /dev/null
+++ b/libcef_dll/ctocpp/views/menu_button_pressed_lock_ctocpp.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=8c0bc19bcd5b9f53b0ee556fb0117e9a6115eb7f$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_VIEWS_MENU_BUTTON_PRESSED_LOCK_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_VIEWS_MENU_BUTTON_PRESSED_LOCK_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/views/cef_menu_button_capi.h"
+#include "include/capi/views/cef_menu_button_delegate_capi.h"
+#include "include/views/cef_menu_button.h"
+#include "include/views/cef_menu_button_delegate.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefMenuButtonPressedLockCToCpp
+ : public CefCToCppRefCounted<CefMenuButtonPressedLockCToCpp,
+ CefMenuButtonPressedLock,
+ cef_menu_button_pressed_lock_t> {
+ public:
+ CefMenuButtonPressedLockCToCpp();
+ virtual ~CefMenuButtonPressedLockCToCpp();
+
+ // CefMenuButtonPressedLock methods.
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_VIEWS_MENU_BUTTON_PRESSED_LOCK_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/views/overlay_controller_ctocpp.cc b/libcef_dll/ctocpp/views/overlay_controller_ctocpp.cc
new file mode 100644
index 00000000..ec46e9f9
--- /dev/null
+++ b/libcef_dll/ctocpp/views/overlay_controller_ctocpp.cc
@@ -0,0 +1,366 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=f104fb8a49bd3ad2cfc7f638995bbd04e1bbbd5b$
+//
+
+#include "libcef_dll/ctocpp/views/overlay_controller_ctocpp.h"
+#include "libcef_dll/ctocpp/views/view_ctocpp.h"
+#include "libcef_dll/ctocpp/views/window_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") bool CefOverlayControllerCToCpp::IsValid() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_overlay_controller_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_valid)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_valid(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefOverlayControllerCToCpp::IsSame(CefRefPtr<CefOverlayController> that) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_overlay_controller_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_same)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: that; type: refptr_same
+ DCHECK(that.get());
+ if (!that.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval =
+ _struct->is_same(_struct, CefOverlayControllerCToCpp::Unwrap(that));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefView> CefOverlayControllerCToCpp::GetContentsView() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_overlay_controller_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_contents_view)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_view_t* _retval = _struct->get_contents_view(_struct);
+
+ // Return type: refptr_same
+ return CefViewCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefWindow> CefOverlayControllerCToCpp::GetWindow() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_overlay_controller_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_window)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_window_t* _retval = _struct->get_window(_struct);
+
+ // Return type: refptr_same
+ return CefWindowCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+cef_docking_mode_t CefOverlayControllerCToCpp::GetDockingMode() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_overlay_controller_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_docking_mode)) {
+ return CEF_DOCKING_MODE_TOP_LEFT;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_docking_mode_t _retval = _struct->get_docking_mode(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") void CefOverlayControllerCToCpp::Destroy() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_overlay_controller_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, destroy)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->destroy(_struct);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefOverlayControllerCToCpp::SetBounds(const CefRect& bounds) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_overlay_controller_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_bounds)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_bounds(_struct, &bounds);
+}
+
+NO_SANITIZE("cfi-icall") CefRect CefOverlayControllerCToCpp::GetBounds() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_overlay_controller_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_bounds)) {
+ return CefRect();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_rect_t _retval = _struct->get_bounds(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRect CefOverlayControllerCToCpp::GetBoundsInScreen() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_overlay_controller_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_bounds_in_screen)) {
+ return CefRect();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_rect_t _retval = _struct->get_bounds_in_screen(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefOverlayControllerCToCpp::SetSize(const CefSize& size) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_overlay_controller_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_size)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_size(_struct, &size);
+}
+
+NO_SANITIZE("cfi-icall") CefSize CefOverlayControllerCToCpp::GetSize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_overlay_controller_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_size_t _retval = _struct->get_size(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefOverlayControllerCToCpp::SetPosition(const CefPoint& position) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_overlay_controller_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_position)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_position(_struct, &position);
+}
+
+NO_SANITIZE("cfi-icall") CefPoint CefOverlayControllerCToCpp::GetPosition() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_overlay_controller_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_position)) {
+ return CefPoint();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_point_t _retval = _struct->get_position(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefOverlayControllerCToCpp::SetInsets(const CefInsets& insets) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_overlay_controller_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_insets)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_insets(_struct, &insets);
+}
+
+NO_SANITIZE("cfi-icall") CefInsets CefOverlayControllerCToCpp::GetInsets() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_overlay_controller_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_insets)) {
+ return CefInsets();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_insets_t _retval = _struct->get_insets(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefOverlayControllerCToCpp::SizeToPreferredSize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_overlay_controller_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, size_to_preferred_size)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->size_to_preferred_size(_struct);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefOverlayControllerCToCpp::SetVisible(bool visible) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_overlay_controller_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_visible)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_visible(_struct, visible);
+}
+
+NO_SANITIZE("cfi-icall") bool CefOverlayControllerCToCpp::IsVisible() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_overlay_controller_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_visible)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_visible(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefOverlayControllerCToCpp::IsDrawn() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_overlay_controller_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_drawn)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_drawn(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefOverlayControllerCToCpp::CefOverlayControllerCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefOverlayControllerCToCpp::~CefOverlayControllerCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_overlay_controller_t* CefCToCppRefCounted<
+ CefOverlayControllerCToCpp,
+ CefOverlayController,
+ cef_overlay_controller_t>::UnwrapDerived(CefWrapperType type,
+ CefOverlayController* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefOverlayControllerCToCpp,
+ CefOverlayController,
+ cef_overlay_controller_t>::kWrapperType =
+ WT_OVERLAY_CONTROLLER;
diff --git a/libcef_dll/ctocpp/views/overlay_controller_ctocpp.h b/libcef_dll/ctocpp/views/overlay_controller_ctocpp.h
new file mode 100644
index 00000000..e8c47e0c
--- /dev/null
+++ b/libcef_dll/ctocpp/views/overlay_controller_ctocpp.h
@@ -0,0 +1,63 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=a8dd9d8eb796f499231143866c2d8f45e9b25d0c$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_VIEWS_OVERLAY_CONTROLLER_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_VIEWS_OVERLAY_CONTROLLER_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/views/cef_overlay_controller_capi.h"
+#include "include/capi/views/cef_view_capi.h"
+#include "include/capi/views/cef_window_capi.h"
+#include "include/views/cef_overlay_controller.h"
+#include "include/views/cef_view.h"
+#include "include/views/cef_window.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefOverlayControllerCToCpp
+ : public CefCToCppRefCounted<CefOverlayControllerCToCpp,
+ CefOverlayController,
+ cef_overlay_controller_t> {
+ public:
+ CefOverlayControllerCToCpp();
+ virtual ~CefOverlayControllerCToCpp();
+
+ // CefOverlayController methods.
+ bool IsValid() override;
+ bool IsSame(CefRefPtr<CefOverlayController> that) override;
+ CefRefPtr<CefView> GetContentsView() override;
+ CefRefPtr<CefWindow> GetWindow() override;
+ cef_docking_mode_t GetDockingMode() override;
+ void Destroy() override;
+ void SetBounds(const CefRect& bounds) override;
+ CefRect GetBounds() override;
+ CefRect GetBoundsInScreen() override;
+ void SetSize(const CefSize& size) override;
+ CefSize GetSize() override;
+ void SetPosition(const CefPoint& position) override;
+ CefPoint GetPosition() override;
+ void SetInsets(const CefInsets& insets) override;
+ CefInsets GetInsets() override;
+ void SizeToPreferredSize() override;
+ void SetVisible(bool visible) override;
+ bool IsVisible() override;
+ bool IsDrawn() override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_VIEWS_OVERLAY_CONTROLLER_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/views/panel_ctocpp.cc b/libcef_dll/ctocpp/views/panel_ctocpp.cc
new file mode 100644
index 00000000..1ff2b728
--- /dev/null
+++ b/libcef_dll/ctocpp/views/panel_ctocpp.cc
@@ -0,0 +1,1156 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=28af26c5e97ef246985cfb0828d5f13e325824b4$
+//
+
+#include "libcef_dll/ctocpp/views/panel_ctocpp.h"
+#include "libcef_dll/cpptoc/views/panel_delegate_cpptoc.h"
+#include "libcef_dll/cpptoc/views/view_delegate_cpptoc.h"
+#include "libcef_dll/ctocpp/views/box_layout_ctocpp.h"
+#include "libcef_dll/ctocpp/views/browser_view_ctocpp.h"
+#include "libcef_dll/ctocpp/views/button_ctocpp.h"
+#include "libcef_dll/ctocpp/views/fill_layout_ctocpp.h"
+#include "libcef_dll/ctocpp/views/layout_ctocpp.h"
+#include "libcef_dll/ctocpp/views/scroll_view_ctocpp.h"
+#include "libcef_dll/ctocpp/views/textfield_ctocpp.h"
+#include "libcef_dll/ctocpp/views/view_ctocpp.h"
+#include "libcef_dll/ctocpp/views/window_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// STATIC METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefPanel> CefPanel::CreatePanel(
+ CefRefPtr<CefPanelDelegate> delegate) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: delegate
+
+ // Execute
+ cef_panel_t* _retval =
+ cef_panel_create(CefPanelDelegateCppToC::Wrap(delegate));
+
+ // Return type: refptr_same
+ return CefPanelCToCpp::Wrap(_retval);
+}
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefWindow> CefPanelCToCpp::AsWindow() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_panel_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, as_window)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_window_t* _retval = _struct->as_window(_struct);
+
+ // Return type: refptr_same
+ return CefWindowCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefFillLayout> CefPanelCToCpp::SetToFillLayout() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_panel_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_to_fill_layout)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_fill_layout_t* _retval = _struct->set_to_fill_layout(_struct);
+
+ // Return type: refptr_same
+ return CefFillLayoutCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefBoxLayout> CefPanelCToCpp::SetToBoxLayout(
+ const CefBoxLayoutSettings& settings) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_panel_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_to_box_layout)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_box_layout_t* _retval = _struct->set_to_box_layout(_struct, &settings);
+
+ // Return type: refptr_same
+ return CefBoxLayoutCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefLayout> CefPanelCToCpp::GetLayout() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_panel_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_layout)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_layout_t* _retval = _struct->get_layout(_struct);
+
+ // Return type: refptr_same
+ return CefLayoutCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") void CefPanelCToCpp::Layout() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_panel_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, layout)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->layout(_struct);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefPanelCToCpp::AddChildView(CefRefPtr<CefView> view) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_panel_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, add_child_view)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_same
+ DCHECK(view.get());
+ if (!view.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->add_child_view(_struct, CefViewCToCpp::Unwrap(view));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefPanelCToCpp::AddChildViewAt(CefRefPtr<CefView> view, int index) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_panel_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, add_child_view_at)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_same
+ DCHECK(view.get());
+ if (!view.get()) {
+ return;
+ }
+ // Verify param: index; type: simple_byval
+ DCHECK_GE(index, 0);
+ if (index < 0) {
+ return;
+ }
+
+ // Execute
+ _struct->add_child_view_at(_struct, CefViewCToCpp::Unwrap(view), index);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefPanelCToCpp::ReorderChildView(CefRefPtr<CefView> view, int index) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_panel_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, reorder_child_view)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_same
+ DCHECK(view.get());
+ if (!view.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->reorder_child_view(_struct, CefViewCToCpp::Unwrap(view), index);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefPanelCToCpp::RemoveChildView(CefRefPtr<CefView> view) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_panel_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, remove_child_view)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_same
+ DCHECK(view.get());
+ if (!view.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->remove_child_view(_struct, CefViewCToCpp::Unwrap(view));
+}
+
+NO_SANITIZE("cfi-icall") void CefPanelCToCpp::RemoveAllChildViews() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_panel_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, remove_all_child_views)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->remove_all_child_views(_struct);
+}
+
+NO_SANITIZE("cfi-icall") size_t CefPanelCToCpp::GetChildViewCount() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_panel_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_child_view_count)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ size_t _retval = _struct->get_child_view_count(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefView> CefPanelCToCpp::GetChildViewAt(int index) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_panel_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_child_view_at)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: index; type: simple_byval
+ DCHECK_GE(index, 0);
+ if (index < 0) {
+ return nullptr;
+ }
+
+ // Execute
+ cef_view_t* _retval = _struct->get_child_view_at(_struct, index);
+
+ // Return type: refptr_same
+ return CefViewCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefBrowserView> CefPanelCToCpp::AsBrowserView() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, as_browser_view)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_browser_view_t* _retval = _struct->as_browser_view(_struct);
+
+ // Return type: refptr_same
+ return CefBrowserViewCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefButton> CefPanelCToCpp::AsButton() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, as_button)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_button_t* _retval = _struct->as_button(_struct);
+
+ // Return type: refptr_same
+ return CefButtonCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefPanel> CefPanelCToCpp::AsPanel() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, as_panel)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_panel_t* _retval = _struct->as_panel(_struct);
+
+ // Return type: refptr_same
+ return CefPanelCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefScrollView> CefPanelCToCpp::AsScrollView() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, as_scroll_view)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_scroll_view_t* _retval = _struct->as_scroll_view(_struct);
+
+ // Return type: refptr_same
+ return CefScrollViewCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefTextfield> CefPanelCToCpp::AsTextfield() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, as_textfield)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_textfield_t* _retval = _struct->as_textfield(_struct);
+
+ // Return type: refptr_same
+ return CefTextfieldCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") CefString CefPanelCToCpp::GetTypeString() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_type_string)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_type_string(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+CefString CefPanelCToCpp::ToString(bool include_children) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, to_string)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->to_string(_struct, include_children);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") bool CefPanelCToCpp::IsValid() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_valid)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_valid(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefPanelCToCpp::IsAttached() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_attached)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_attached(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefPanelCToCpp::IsSame(CefRefPtr<CefView> that) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_same)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: that; type: refptr_same
+ DCHECK(that.get());
+ if (!that.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->is_same(_struct, CefViewCToCpp::Unwrap(that));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefViewDelegate> CefPanelCToCpp::GetDelegate() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_delegate)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_view_delegate_t* _retval = _struct->get_delegate(_struct);
+
+ // Return type: refptr_diff
+ return CefViewDelegateCppToC::Unwrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefWindow> CefPanelCToCpp::GetWindow() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_window)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_window_t* _retval = _struct->get_window(_struct);
+
+ // Return type: refptr_same
+ return CefWindowCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") int CefPanelCToCpp::GetID() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_id)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_id(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") void CefPanelCToCpp::SetID(int id) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_id)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_id(_struct, id);
+}
+
+NO_SANITIZE("cfi-icall") int CefPanelCToCpp::GetGroupID() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_group_id)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_group_id(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") void CefPanelCToCpp::SetGroupID(int group_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_group_id)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_group_id(_struct, group_id);
+}
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefView> CefPanelCToCpp::GetParentView() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_parent_view)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_view_t* _retval = _struct->get_parent_view(_struct);
+
+ // Return type: refptr_same
+ return CefViewCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefView> CefPanelCToCpp::GetViewForID(int id) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_view_for_id)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_view_t* _retval = _struct->get_view_for_id(_struct, id);
+
+ // Return type: refptr_same
+ return CefViewCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") void CefPanelCToCpp::SetBounds(const CefRect& bounds) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_bounds)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_bounds(_struct, &bounds);
+}
+
+NO_SANITIZE("cfi-icall") CefRect CefPanelCToCpp::GetBounds() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_bounds)) {
+ return CefRect();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_rect_t _retval = _struct->get_bounds(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") CefRect CefPanelCToCpp::GetBoundsInScreen() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_bounds_in_screen)) {
+ return CefRect();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_rect_t _retval = _struct->get_bounds_in_screen(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") void CefPanelCToCpp::SetSize(const CefSize& size) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_size)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_size(_struct, &size);
+}
+
+NO_SANITIZE("cfi-icall") CefSize CefPanelCToCpp::GetSize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_size_t _retval = _struct->get_size(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefPanelCToCpp::SetPosition(const CefPoint& position) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_position)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_position(_struct, &position);
+}
+
+NO_SANITIZE("cfi-icall") CefPoint CefPanelCToCpp::GetPosition() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_position)) {
+ return CefPoint();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_point_t _retval = _struct->get_position(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefPanelCToCpp::SetInsets(const CefInsets& insets) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_insets)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_insets(_struct, &insets);
+}
+
+NO_SANITIZE("cfi-icall") CefInsets CefPanelCToCpp::GetInsets() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_insets)) {
+ return CefInsets();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_insets_t _retval = _struct->get_insets(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") CefSize CefPanelCToCpp::GetPreferredSize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_preferred_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_size_t _retval = _struct->get_preferred_size(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") void CefPanelCToCpp::SizeToPreferredSize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, size_to_preferred_size)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->size_to_preferred_size(_struct);
+}
+
+NO_SANITIZE("cfi-icall") CefSize CefPanelCToCpp::GetMinimumSize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_minimum_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_size_t _retval = _struct->get_minimum_size(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") CefSize CefPanelCToCpp::GetMaximumSize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_maximum_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_size_t _retval = _struct->get_maximum_size(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") int CefPanelCToCpp::GetHeightForWidth(int width) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_height_for_width)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_height_for_width(_struct, width);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") void CefPanelCToCpp::InvalidateLayout() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, invalidate_layout)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->invalidate_layout(_struct);
+}
+
+NO_SANITIZE("cfi-icall") void CefPanelCToCpp::SetVisible(bool visible) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_visible)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_visible(_struct, visible);
+}
+
+NO_SANITIZE("cfi-icall") bool CefPanelCToCpp::IsVisible() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_visible)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_visible(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefPanelCToCpp::IsDrawn() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_drawn)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_drawn(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") void CefPanelCToCpp::SetEnabled(bool enabled) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_enabled)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_enabled(_struct, enabled);
+}
+
+NO_SANITIZE("cfi-icall") bool CefPanelCToCpp::IsEnabled() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_enabled)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_enabled(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") void CefPanelCToCpp::SetFocusable(bool focusable) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_focusable)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_focusable(_struct, focusable);
+}
+
+NO_SANITIZE("cfi-icall") bool CefPanelCToCpp::IsFocusable() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_focusable)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_focusable(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefPanelCToCpp::IsAccessibilityFocusable() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_accessibility_focusable)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_accessibility_focusable(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") void CefPanelCToCpp::RequestFocus() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, request_focus)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->request_focus(_struct);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefPanelCToCpp::SetBackgroundColor(cef_color_t color) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_background_color)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_background_color(_struct, color);
+}
+
+NO_SANITIZE("cfi-icall") cef_color_t CefPanelCToCpp::GetBackgroundColor() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_background_color)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_color_t _retval = _struct->get_background_color(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefPanelCToCpp::ConvertPointToScreen(CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, convert_point_to_screen)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->convert_point_to_screen(_struct, &point);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefPanelCToCpp::ConvertPointFromScreen(CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, convert_point_from_screen)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->convert_point_from_screen(_struct, &point);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefPanelCToCpp::ConvertPointToWindow(CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, convert_point_to_window)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->convert_point_to_window(_struct, &point);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefPanelCToCpp::ConvertPointFromWindow(CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, convert_point_from_window)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->convert_point_from_window(_struct, &point);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefPanelCToCpp::ConvertPointToView(CefRefPtr<CefView> view,
+ CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, convert_point_to_view)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_same
+ DCHECK(view.get());
+ if (!view.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->convert_point_to_view(
+ _struct, CefViewCToCpp::Unwrap(view), &point);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefPanelCToCpp::ConvertPointFromView(CefRefPtr<CefView> view,
+ CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, convert_point_from_view)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_same
+ DCHECK(view.get());
+ if (!view.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->convert_point_from_view(
+ _struct, CefViewCToCpp::Unwrap(view), &point);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefPanelCToCpp::CefPanelCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefPanelCToCpp::~CefPanelCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_panel_t*
+CefCToCppRefCounted<CefPanelCToCpp, CefPanel, cef_panel_t>::UnwrapDerived(
+ CefWrapperType type,
+ CefPanel* c) {
+ if (type == WT_WINDOW) {
+ return reinterpret_cast<cef_panel_t*>(
+ CefWindowCToCpp::Unwrap(reinterpret_cast<CefWindow*>(c)));
+ }
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCToCppRefCounted<CefPanelCToCpp, CefPanel, cef_panel_t>::kWrapperType =
+ WT_PANEL;
diff --git a/libcef_dll/ctocpp/views/panel_ctocpp.h b/libcef_dll/ctocpp/views/panel_ctocpp.h
new file mode 100644
index 00000000..ee6410be
--- /dev/null
+++ b/libcef_dll/ctocpp/views/panel_ctocpp.h
@@ -0,0 +1,111 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=c0c4823d1084bd1ea4f2065e93b51a56718bed87$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_VIEWS_PANEL_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_VIEWS_PANEL_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/views/cef_box_layout_capi.h"
+#include "include/capi/views/cef_fill_layout_capi.h"
+#include "include/capi/views/cef_layout_capi.h"
+#include "include/capi/views/cef_panel_capi.h"
+#include "include/capi/views/cef_window_capi.h"
+#include "include/views/cef_box_layout.h"
+#include "include/views/cef_fill_layout.h"
+#include "include/views/cef_layout.h"
+#include "include/views/cef_panel.h"
+#include "include/views/cef_window.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefPanelCToCpp
+ : public CefCToCppRefCounted<CefPanelCToCpp, CefPanel, cef_panel_t> {
+ public:
+ CefPanelCToCpp();
+ virtual ~CefPanelCToCpp();
+
+ // CefPanel methods.
+ CefRefPtr<CefWindow> AsWindow() override;
+ CefRefPtr<CefFillLayout> SetToFillLayout() override;
+ CefRefPtr<CefBoxLayout> SetToBoxLayout(
+ const CefBoxLayoutSettings& settings) override;
+ CefRefPtr<CefLayout> GetLayout() override;
+ void Layout() override;
+ void AddChildView(CefRefPtr<CefView> view) override;
+ void AddChildViewAt(CefRefPtr<CefView> view, int index) override;
+ void ReorderChildView(CefRefPtr<CefView> view, int index) override;
+ void RemoveChildView(CefRefPtr<CefView> view) override;
+ void RemoveAllChildViews() override;
+ size_t GetChildViewCount() override;
+ CefRefPtr<CefView> GetChildViewAt(int index) override;
+
+ // CefView methods.
+ CefRefPtr<CefBrowserView> AsBrowserView() override;
+ CefRefPtr<CefButton> AsButton() override;
+ CefRefPtr<CefPanel> AsPanel() override;
+ CefRefPtr<CefScrollView> AsScrollView() override;
+ CefRefPtr<CefTextfield> AsTextfield() override;
+ CefString GetTypeString() override;
+ CefString ToString(bool include_children) override;
+ bool IsValid() override;
+ bool IsAttached() override;
+ bool IsSame(CefRefPtr<CefView> that) override;
+ CefRefPtr<CefViewDelegate> GetDelegate() override;
+ CefRefPtr<CefWindow> GetWindow() override;
+ int GetID() override;
+ void SetID(int id) override;
+ int GetGroupID() override;
+ void SetGroupID(int group_id) override;
+ CefRefPtr<CefView> GetParentView() override;
+ CefRefPtr<CefView> GetViewForID(int id) override;
+ void SetBounds(const CefRect& bounds) override;
+ CefRect GetBounds() override;
+ CefRect GetBoundsInScreen() override;
+ void SetSize(const CefSize& size) override;
+ CefSize GetSize() override;
+ void SetPosition(const CefPoint& position) override;
+ CefPoint GetPosition() override;
+ void SetInsets(const CefInsets& insets) override;
+ CefInsets GetInsets() override;
+ CefSize GetPreferredSize() override;
+ void SizeToPreferredSize() override;
+ CefSize GetMinimumSize() override;
+ CefSize GetMaximumSize() override;
+ int GetHeightForWidth(int width) override;
+ void InvalidateLayout() override;
+ void SetVisible(bool visible) override;
+ bool IsVisible() override;
+ bool IsDrawn() override;
+ void SetEnabled(bool enabled) override;
+ bool IsEnabled() override;
+ void SetFocusable(bool focusable) override;
+ bool IsFocusable() override;
+ bool IsAccessibilityFocusable() override;
+ void RequestFocus() override;
+ void SetBackgroundColor(cef_color_t color) override;
+ cef_color_t GetBackgroundColor() override;
+ bool ConvertPointToScreen(CefPoint& point) override;
+ bool ConvertPointFromScreen(CefPoint& point) override;
+ bool ConvertPointToWindow(CefPoint& point) override;
+ bool ConvertPointFromWindow(CefPoint& point) override;
+ bool ConvertPointToView(CefRefPtr<CefView> view, CefPoint& point) override;
+ bool ConvertPointFromView(CefRefPtr<CefView> view, CefPoint& point) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_VIEWS_PANEL_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/views/panel_delegate_ctocpp.cc b/libcef_dll/ctocpp/views/panel_delegate_ctocpp.cc
new file mode 100644
index 00000000..f2fe959c
--- /dev/null
+++ b/libcef_dll/ctocpp/views/panel_delegate_ctocpp.cc
@@ -0,0 +1,306 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=405f351887cd4d64177534dd1a362f1027126b0d$
+//
+
+#include "libcef_dll/ctocpp/views/panel_delegate_ctocpp.h"
+#include "libcef_dll/cpptoc/views/view_cpptoc.h"
+#include "libcef_dll/ctocpp/views/window_delegate_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefSize CefPanelDelegateCToCpp::GetPreferredSize(CefRefPtr<CefView> view) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_preferred_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval =
+ _struct->get_preferred_size(_struct, CefViewCppToC::Wrap(view));
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CefSize CefPanelDelegateCToCpp::GetMinimumSize(CefRefPtr<CefView> view) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_minimum_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval =
+ _struct->get_minimum_size(_struct, CefViewCppToC::Wrap(view));
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CefSize CefPanelDelegateCToCpp::GetMaximumSize(CefRefPtr<CefView> view) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_maximum_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval =
+ _struct->get_maximum_size(_struct, CefViewCppToC::Wrap(view));
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+int CefPanelDelegateCToCpp::GetHeightForWidth(CefRefPtr<CefView> view,
+ int width) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_height_for_width)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return 0;
+ }
+
+ // Execute
+ int _retval =
+ _struct->get_height_for_width(_struct, CefViewCppToC::Wrap(view), width);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefPanelDelegateCToCpp::OnParentViewChanged(CefRefPtr<CefView> view,
+ bool added,
+ CefRefPtr<CefView> parent) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, on_parent_view_changed)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return;
+ }
+ // Verify param: parent; type: refptr_diff
+ DCHECK(parent.get());
+ if (!parent.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_parent_view_changed(_struct, CefViewCppToC::Wrap(view), added,
+ CefViewCppToC::Wrap(parent));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefPanelDelegateCToCpp::OnChildViewChanged(CefRefPtr<CefView> view,
+ bool added,
+ CefRefPtr<CefView> child) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, on_child_view_changed)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return;
+ }
+ // Verify param: child; type: refptr_diff
+ DCHECK(child.get());
+ if (!child.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_child_view_changed(_struct, CefViewCppToC::Wrap(view), added,
+ CefViewCppToC::Wrap(child));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefPanelDelegateCToCpp::OnWindowChanged(CefRefPtr<CefView> view,
+ bool added) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, on_window_changed)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_window_changed(_struct, CefViewCppToC::Wrap(view), added);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefPanelDelegateCToCpp::OnLayoutChanged(CefRefPtr<CefView> view,
+ const CefRect& new_bounds) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, on_layout_changed)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_layout_changed(_struct, CefViewCppToC::Wrap(view), &new_bounds);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefPanelDelegateCToCpp::OnFocus(CefRefPtr<CefView> view) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, on_focus)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_focus(_struct, CefViewCppToC::Wrap(view));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefPanelDelegateCToCpp::OnBlur(CefRefPtr<CefView> view) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, on_blur)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_blur(_struct, CefViewCppToC::Wrap(view));
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefPanelDelegateCToCpp::CefPanelDelegateCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefPanelDelegateCToCpp::~CefPanelDelegateCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_panel_delegate_t*
+CefCToCppRefCounted<CefPanelDelegateCToCpp,
+ CefPanelDelegate,
+ cef_panel_delegate_t>::UnwrapDerived(CefWrapperType type,
+ CefPanelDelegate* c) {
+ if (type == WT_WINDOW_DELEGATE) {
+ return reinterpret_cast<cef_panel_delegate_t*>(
+ CefWindowDelegateCToCpp::Unwrap(
+ reinterpret_cast<CefWindowDelegate*>(c)));
+ }
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefPanelDelegateCToCpp,
+ CefPanelDelegate,
+ cef_panel_delegate_t>::kWrapperType =
+ WT_PANEL_DELEGATE;
diff --git a/libcef_dll/ctocpp/views/panel_delegate_ctocpp.h b/libcef_dll/ctocpp/views/panel_delegate_ctocpp.h
new file mode 100644
index 00000000..62fd16d8
--- /dev/null
+++ b/libcef_dll/ctocpp/views/panel_delegate_ctocpp.h
@@ -0,0 +1,57 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=dcad633b9f91da4e5b08cfa8be122b6797211b46$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_VIEWS_PANEL_DELEGATE_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_VIEWS_PANEL_DELEGATE_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/views/cef_panel_delegate_capi.h"
+#include "include/views/cef_panel_delegate.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefPanelDelegateCToCpp
+ : public CefCToCppRefCounted<CefPanelDelegateCToCpp,
+ CefPanelDelegate,
+ cef_panel_delegate_t> {
+ public:
+ CefPanelDelegateCToCpp();
+ virtual ~CefPanelDelegateCToCpp();
+
+ // CefPanelDelegate methods.
+
+ // CefViewDelegate methods.
+ CefSize GetPreferredSize(CefRefPtr<CefView> view) override;
+ CefSize GetMinimumSize(CefRefPtr<CefView> view) override;
+ CefSize GetMaximumSize(CefRefPtr<CefView> view) override;
+ int GetHeightForWidth(CefRefPtr<CefView> view, int width) override;
+ void OnParentViewChanged(CefRefPtr<CefView> view,
+ bool added,
+ CefRefPtr<CefView> parent) override;
+ void OnChildViewChanged(CefRefPtr<CefView> view,
+ bool added,
+ CefRefPtr<CefView> child) override;
+ void OnWindowChanged(CefRefPtr<CefView> view, bool added) override;
+ void OnLayoutChanged(CefRefPtr<CefView> view,
+ const CefRect& new_bounds) override;
+ void OnFocus(CefRefPtr<CefView> view) override;
+ void OnBlur(CefRefPtr<CefView> view) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_VIEWS_PANEL_DELEGATE_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/views/scroll_view_ctocpp.cc b/libcef_dll/ctocpp/views/scroll_view_ctocpp.cc
new file mode 100644
index 00000000..9a20708a
--- /dev/null
+++ b/libcef_dll/ctocpp/views/scroll_view_ctocpp.cc
@@ -0,0 +1,1050 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=2f144e9072f0e1ab8e47a32192fe993b1b71c40a$
+//
+
+#include "libcef_dll/ctocpp/views/scroll_view_ctocpp.h"
+#include "libcef_dll/cpptoc/views/view_delegate_cpptoc.h"
+#include "libcef_dll/ctocpp/views/browser_view_ctocpp.h"
+#include "libcef_dll/ctocpp/views/button_ctocpp.h"
+#include "libcef_dll/ctocpp/views/panel_ctocpp.h"
+#include "libcef_dll/ctocpp/views/textfield_ctocpp.h"
+#include "libcef_dll/ctocpp/views/view_ctocpp.h"
+#include "libcef_dll/ctocpp/views/window_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// STATIC METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefScrollView> CefScrollView::CreateScrollView(
+ CefRefPtr<CefViewDelegate> delegate) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: delegate
+
+ // Execute
+ cef_scroll_view_t* _retval =
+ cef_scroll_view_create(CefViewDelegateCppToC::Wrap(delegate));
+
+ // Return type: refptr_same
+ return CefScrollViewCToCpp::Wrap(_retval);
+}
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+void CefScrollViewCToCpp::SetContentView(CefRefPtr<CefView> view) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_scroll_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_content_view)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_same
+ DCHECK(view.get());
+ if (!view.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->set_content_view(_struct, CefViewCToCpp::Unwrap(view));
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefView> CefScrollViewCToCpp::GetContentView() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_scroll_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_content_view)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_view_t* _retval = _struct->get_content_view(_struct);
+
+ // Return type: refptr_same
+ return CefViewCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") CefRect CefScrollViewCToCpp::GetVisibleContentRect() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_scroll_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_visible_content_rect)) {
+ return CefRect();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_rect_t _retval = _struct->get_visible_content_rect(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") bool CefScrollViewCToCpp::HasHorizontalScrollbar() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_scroll_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, has_horizontal_scrollbar)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->has_horizontal_scrollbar(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+int CefScrollViewCToCpp::GetHorizontalScrollbarHeight() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_scroll_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_horizontal_scrollbar_height)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_horizontal_scrollbar_height(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") bool CefScrollViewCToCpp::HasVerticalScrollbar() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_scroll_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, has_vertical_scrollbar)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->has_vertical_scrollbar(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") int CefScrollViewCToCpp::GetVerticalScrollbarWidth() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_scroll_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_vertical_scrollbar_width)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_vertical_scrollbar_width(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefBrowserView> CefScrollViewCToCpp::AsBrowserView() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, as_browser_view)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_browser_view_t* _retval = _struct->as_browser_view(_struct);
+
+ // Return type: refptr_same
+ return CefBrowserViewCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefButton> CefScrollViewCToCpp::AsButton() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, as_button)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_button_t* _retval = _struct->as_button(_struct);
+
+ // Return type: refptr_same
+ return CefButtonCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefPanel> CefScrollViewCToCpp::AsPanel() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, as_panel)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_panel_t* _retval = _struct->as_panel(_struct);
+
+ // Return type: refptr_same
+ return CefPanelCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefScrollView> CefScrollViewCToCpp::AsScrollView() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, as_scroll_view)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_scroll_view_t* _retval = _struct->as_scroll_view(_struct);
+
+ // Return type: refptr_same
+ return CefScrollViewCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefTextfield> CefScrollViewCToCpp::AsTextfield() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, as_textfield)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_textfield_t* _retval = _struct->as_textfield(_struct);
+
+ // Return type: refptr_same
+ return CefTextfieldCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") CefString CefScrollViewCToCpp::GetTypeString() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_type_string)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_type_string(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+CefString CefScrollViewCToCpp::ToString(bool include_children) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, to_string)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->to_string(_struct, include_children);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") bool CefScrollViewCToCpp::IsValid() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_valid)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_valid(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefScrollViewCToCpp::IsAttached() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_attached)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_attached(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefScrollViewCToCpp::IsSame(CefRefPtr<CefView> that) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_same)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: that; type: refptr_same
+ DCHECK(that.get());
+ if (!that.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->is_same(_struct, CefViewCToCpp::Unwrap(that));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefViewDelegate> CefScrollViewCToCpp::GetDelegate() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_delegate)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_view_delegate_t* _retval = _struct->get_delegate(_struct);
+
+ // Return type: refptr_diff
+ return CefViewDelegateCppToC::Unwrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefWindow> CefScrollViewCToCpp::GetWindow() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_window)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_window_t* _retval = _struct->get_window(_struct);
+
+ // Return type: refptr_same
+ return CefWindowCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") int CefScrollViewCToCpp::GetID() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_id)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_id(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") void CefScrollViewCToCpp::SetID(int id) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_id)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_id(_struct, id);
+}
+
+NO_SANITIZE("cfi-icall") int CefScrollViewCToCpp::GetGroupID() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_group_id)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_group_id(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") void CefScrollViewCToCpp::SetGroupID(int group_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_group_id)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_group_id(_struct, group_id);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefView> CefScrollViewCToCpp::GetParentView() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_parent_view)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_view_t* _retval = _struct->get_parent_view(_struct);
+
+ // Return type: refptr_same
+ return CefViewCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefView> CefScrollViewCToCpp::GetViewForID(int id) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_view_for_id)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_view_t* _retval = _struct->get_view_for_id(_struct, id);
+
+ // Return type: refptr_same
+ return CefViewCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefScrollViewCToCpp::SetBounds(const CefRect& bounds) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_bounds)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_bounds(_struct, &bounds);
+}
+
+NO_SANITIZE("cfi-icall") CefRect CefScrollViewCToCpp::GetBounds() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_bounds)) {
+ return CefRect();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_rect_t _retval = _struct->get_bounds(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") CefRect CefScrollViewCToCpp::GetBoundsInScreen() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_bounds_in_screen)) {
+ return CefRect();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_rect_t _retval = _struct->get_bounds_in_screen(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefScrollViewCToCpp::SetSize(const CefSize& size) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_size)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_size(_struct, &size);
+}
+
+NO_SANITIZE("cfi-icall") CefSize CefScrollViewCToCpp::GetSize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_size_t _retval = _struct->get_size(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefScrollViewCToCpp::SetPosition(const CefPoint& position) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_position)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_position(_struct, &position);
+}
+
+NO_SANITIZE("cfi-icall") CefPoint CefScrollViewCToCpp::GetPosition() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_position)) {
+ return CefPoint();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_point_t _retval = _struct->get_position(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefScrollViewCToCpp::SetInsets(const CefInsets& insets) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_insets)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_insets(_struct, &insets);
+}
+
+NO_SANITIZE("cfi-icall") CefInsets CefScrollViewCToCpp::GetInsets() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_insets)) {
+ return CefInsets();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_insets_t _retval = _struct->get_insets(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") CefSize CefScrollViewCToCpp::GetPreferredSize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_preferred_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_size_t _retval = _struct->get_preferred_size(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") void CefScrollViewCToCpp::SizeToPreferredSize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, size_to_preferred_size)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->size_to_preferred_size(_struct);
+}
+
+NO_SANITIZE("cfi-icall") CefSize CefScrollViewCToCpp::GetMinimumSize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_minimum_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_size_t _retval = _struct->get_minimum_size(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") CefSize CefScrollViewCToCpp::GetMaximumSize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_maximum_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_size_t _retval = _struct->get_maximum_size(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") int CefScrollViewCToCpp::GetHeightForWidth(int width) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_height_for_width)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_height_for_width(_struct, width);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") void CefScrollViewCToCpp::InvalidateLayout() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, invalidate_layout)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->invalidate_layout(_struct);
+}
+
+NO_SANITIZE("cfi-icall") void CefScrollViewCToCpp::SetVisible(bool visible) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_visible)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_visible(_struct, visible);
+}
+
+NO_SANITIZE("cfi-icall") bool CefScrollViewCToCpp::IsVisible() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_visible)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_visible(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefScrollViewCToCpp::IsDrawn() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_drawn)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_drawn(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") void CefScrollViewCToCpp::SetEnabled(bool enabled) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_enabled)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_enabled(_struct, enabled);
+}
+
+NO_SANITIZE("cfi-icall") bool CefScrollViewCToCpp::IsEnabled() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_enabled)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_enabled(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefScrollViewCToCpp::SetFocusable(bool focusable) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_focusable)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_focusable(_struct, focusable);
+}
+
+NO_SANITIZE("cfi-icall") bool CefScrollViewCToCpp::IsFocusable() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_focusable)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_focusable(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefScrollViewCToCpp::IsAccessibilityFocusable() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_accessibility_focusable)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_accessibility_focusable(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") void CefScrollViewCToCpp::RequestFocus() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, request_focus)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->request_focus(_struct);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefScrollViewCToCpp::SetBackgroundColor(cef_color_t color) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_background_color)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_background_color(_struct, color);
+}
+
+NO_SANITIZE("cfi-icall") cef_color_t CefScrollViewCToCpp::GetBackgroundColor() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_background_color)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_color_t _retval = _struct->get_background_color(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefScrollViewCToCpp::ConvertPointToScreen(CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, convert_point_to_screen)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->convert_point_to_screen(_struct, &point);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefScrollViewCToCpp::ConvertPointFromScreen(CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, convert_point_from_screen)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->convert_point_from_screen(_struct, &point);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefScrollViewCToCpp::ConvertPointToWindow(CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, convert_point_to_window)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->convert_point_to_window(_struct, &point);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefScrollViewCToCpp::ConvertPointFromWindow(CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, convert_point_from_window)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->convert_point_from_window(_struct, &point);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefScrollViewCToCpp::ConvertPointToView(CefRefPtr<CefView> view,
+ CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, convert_point_to_view)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_same
+ DCHECK(view.get());
+ if (!view.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->convert_point_to_view(
+ _struct, CefViewCToCpp::Unwrap(view), &point);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefScrollViewCToCpp::ConvertPointFromView(CefRefPtr<CefView> view,
+ CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, convert_point_from_view)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_same
+ DCHECK(view.get());
+ if (!view.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->convert_point_from_view(
+ _struct, CefViewCToCpp::Unwrap(view), &point);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefScrollViewCToCpp::CefScrollViewCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefScrollViewCToCpp::~CefScrollViewCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_scroll_view_t*
+CefCToCppRefCounted<CefScrollViewCToCpp, CefScrollView, cef_scroll_view_t>::
+ UnwrapDerived(CefWrapperType type, CefScrollView* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefScrollViewCToCpp,
+ CefScrollView,
+ cef_scroll_view_t>::kWrapperType =
+ WT_SCROLL_VIEW;
diff --git a/libcef_dll/ctocpp/views/scroll_view_ctocpp.h b/libcef_dll/ctocpp/views/scroll_view_ctocpp.h
new file mode 100644
index 00000000..5ceb93da
--- /dev/null
+++ b/libcef_dll/ctocpp/views/scroll_view_ctocpp.h
@@ -0,0 +1,98 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=3a3c2eee1765f8a1d86044eadc75eca9c6fae25f$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_VIEWS_SCROLL_VIEW_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_VIEWS_SCROLL_VIEW_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/views/cef_scroll_view_capi.h"
+#include "include/views/cef_scroll_view.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefScrollViewCToCpp : public CefCToCppRefCounted<CefScrollViewCToCpp,
+ CefScrollView,
+ cef_scroll_view_t> {
+ public:
+ CefScrollViewCToCpp();
+ virtual ~CefScrollViewCToCpp();
+
+ // CefScrollView methods.
+ void SetContentView(CefRefPtr<CefView> view) override;
+ CefRefPtr<CefView> GetContentView() override;
+ CefRect GetVisibleContentRect() override;
+ bool HasHorizontalScrollbar() override;
+ int GetHorizontalScrollbarHeight() override;
+ bool HasVerticalScrollbar() override;
+ int GetVerticalScrollbarWidth() override;
+
+ // CefView methods.
+ CefRefPtr<CefBrowserView> AsBrowserView() override;
+ CefRefPtr<CefButton> AsButton() override;
+ CefRefPtr<CefPanel> AsPanel() override;
+ CefRefPtr<CefScrollView> AsScrollView() override;
+ CefRefPtr<CefTextfield> AsTextfield() override;
+ CefString GetTypeString() override;
+ CefString ToString(bool include_children) override;
+ bool IsValid() override;
+ bool IsAttached() override;
+ bool IsSame(CefRefPtr<CefView> that) override;
+ CefRefPtr<CefViewDelegate> GetDelegate() override;
+ CefRefPtr<CefWindow> GetWindow() override;
+ int GetID() override;
+ void SetID(int id) override;
+ int GetGroupID() override;
+ void SetGroupID(int group_id) override;
+ CefRefPtr<CefView> GetParentView() override;
+ CefRefPtr<CefView> GetViewForID(int id) override;
+ void SetBounds(const CefRect& bounds) override;
+ CefRect GetBounds() override;
+ CefRect GetBoundsInScreen() override;
+ void SetSize(const CefSize& size) override;
+ CefSize GetSize() override;
+ void SetPosition(const CefPoint& position) override;
+ CefPoint GetPosition() override;
+ void SetInsets(const CefInsets& insets) override;
+ CefInsets GetInsets() override;
+ CefSize GetPreferredSize() override;
+ void SizeToPreferredSize() override;
+ CefSize GetMinimumSize() override;
+ CefSize GetMaximumSize() override;
+ int GetHeightForWidth(int width) override;
+ void InvalidateLayout() override;
+ void SetVisible(bool visible) override;
+ bool IsVisible() override;
+ bool IsDrawn() override;
+ void SetEnabled(bool enabled) override;
+ bool IsEnabled() override;
+ void SetFocusable(bool focusable) override;
+ bool IsFocusable() override;
+ bool IsAccessibilityFocusable() override;
+ void RequestFocus() override;
+ void SetBackgroundColor(cef_color_t color) override;
+ cef_color_t GetBackgroundColor() override;
+ bool ConvertPointToScreen(CefPoint& point) override;
+ bool ConvertPointFromScreen(CefPoint& point) override;
+ bool ConvertPointToWindow(CefPoint& point) override;
+ bool ConvertPointFromWindow(CefPoint& point) override;
+ bool ConvertPointToView(CefRefPtr<CefView> view, CefPoint& point) override;
+ bool ConvertPointFromView(CefRefPtr<CefView> view, CefPoint& point) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_VIEWS_SCROLL_VIEW_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/views/textfield_ctocpp.cc b/libcef_dll/ctocpp/views/textfield_ctocpp.cc
new file mode 100644
index 00000000..6ca9f56a
--- /dev/null
+++ b/libcef_dll/ctocpp/views/textfield_ctocpp.cc
@@ -0,0 +1,1458 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=dc4a2a8439531603f9bcaeeaa807a955f3846430$
+//
+
+#include "libcef_dll/ctocpp/views/textfield_ctocpp.h"
+#include "libcef_dll/cpptoc/views/textfield_delegate_cpptoc.h"
+#include "libcef_dll/cpptoc/views/view_delegate_cpptoc.h"
+#include "libcef_dll/ctocpp/views/browser_view_ctocpp.h"
+#include "libcef_dll/ctocpp/views/button_ctocpp.h"
+#include "libcef_dll/ctocpp/views/panel_ctocpp.h"
+#include "libcef_dll/ctocpp/views/scroll_view_ctocpp.h"
+#include "libcef_dll/ctocpp/views/view_ctocpp.h"
+#include "libcef_dll/ctocpp/views/window_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// STATIC METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefTextfield> CefTextfield::CreateTextfield(
+ CefRefPtr<CefTextfieldDelegate> delegate) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: delegate
+
+ // Execute
+ cef_textfield_t* _retval =
+ cef_textfield_create(CefTextfieldDelegateCppToC::Wrap(delegate));
+
+ // Return type: refptr_same
+ return CefTextfieldCToCpp::Wrap(_retval);
+}
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+void CefTextfieldCToCpp::SetPasswordInput(bool password_input) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_textfield_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_password_input)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_password_input(_struct, password_input);
+}
+
+NO_SANITIZE("cfi-icall") bool CefTextfieldCToCpp::IsPasswordInput() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_textfield_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_password_input)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_password_input(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") void CefTextfieldCToCpp::SetReadOnly(bool read_only) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_textfield_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_read_only)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_read_only(_struct, read_only);
+}
+
+NO_SANITIZE("cfi-icall") bool CefTextfieldCToCpp::IsReadOnly() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_textfield_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_read_only)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_read_only(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") CefString CefTextfieldCToCpp::GetText() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_textfield_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_text)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_text(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefTextfieldCToCpp::SetText(const CefString& text) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_textfield_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_text)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: text; type: string_byref_const
+ DCHECK(!text.empty());
+ if (text.empty()) {
+ return;
+ }
+
+ // Execute
+ _struct->set_text(_struct, text.GetStruct());
+}
+
+NO_SANITIZE("cfi-icall")
+void CefTextfieldCToCpp::AppendText(const CefString& text) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_textfield_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, append_text)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: text; type: string_byref_const
+ DCHECK(!text.empty());
+ if (text.empty()) {
+ return;
+ }
+
+ // Execute
+ _struct->append_text(_struct, text.GetStruct());
+}
+
+NO_SANITIZE("cfi-icall")
+void CefTextfieldCToCpp::InsertOrReplaceText(const CefString& text) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_textfield_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, insert_or_replace_text)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: text; type: string_byref_const
+ DCHECK(!text.empty());
+ if (text.empty()) {
+ return;
+ }
+
+ // Execute
+ _struct->insert_or_replace_text(_struct, text.GetStruct());
+}
+
+NO_SANITIZE("cfi-icall") bool CefTextfieldCToCpp::HasSelection() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_textfield_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, has_selection)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->has_selection(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") CefString CefTextfieldCToCpp::GetSelectedText() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_textfield_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_selected_text)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_selected_text(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") void CefTextfieldCToCpp::SelectAll(bool reversed) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_textfield_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, select_all)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->select_all(_struct, reversed);
+}
+
+NO_SANITIZE("cfi-icall") void CefTextfieldCToCpp::ClearSelection() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_textfield_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, clear_selection)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->clear_selection(_struct);
+}
+
+NO_SANITIZE("cfi-icall") CefRange CefTextfieldCToCpp::GetSelectedRange() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_textfield_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_selected_range)) {
+ return CefRange();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_range_t _retval = _struct->get_selected_range(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefTextfieldCToCpp::SelectRange(const CefRange& range) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_textfield_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, select_range)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->select_range(_struct, &range);
+}
+
+NO_SANITIZE("cfi-icall") size_t CefTextfieldCToCpp::GetCursorPosition() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_textfield_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_cursor_position)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ size_t _retval = _struct->get_cursor_position(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefTextfieldCToCpp::SetTextColor(cef_color_t color) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_textfield_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_text_color)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_text_color(_struct, color);
+}
+
+NO_SANITIZE("cfi-icall") cef_color_t CefTextfieldCToCpp::GetTextColor() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_textfield_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_text_color)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_color_t _retval = _struct->get_text_color(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefTextfieldCToCpp::SetSelectionTextColor(cef_color_t color) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_textfield_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_selection_text_color)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_selection_text_color(_struct, color);
+}
+
+NO_SANITIZE("cfi-icall")
+cef_color_t CefTextfieldCToCpp::GetSelectionTextColor() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_textfield_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_selection_text_color)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_color_t _retval = _struct->get_selection_text_color(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefTextfieldCToCpp::SetSelectionBackgroundColor(cef_color_t color) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_textfield_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_selection_background_color)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_selection_background_color(_struct, color);
+}
+
+NO_SANITIZE("cfi-icall")
+cef_color_t CefTextfieldCToCpp::GetSelectionBackgroundColor() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_textfield_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_selection_background_color)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_color_t _retval = _struct->get_selection_background_color(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefTextfieldCToCpp::SetFontList(const CefString& font_list) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_textfield_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_font_list)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: font_list; type: string_byref_const
+ DCHECK(!font_list.empty());
+ if (font_list.empty()) {
+ return;
+ }
+
+ // Execute
+ _struct->set_font_list(_struct, font_list.GetStruct());
+}
+
+NO_SANITIZE("cfi-icall")
+void CefTextfieldCToCpp::ApplyTextColor(cef_color_t color,
+ const CefRange& range) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_textfield_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, apply_text_color)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->apply_text_color(_struct, color, &range);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefTextfieldCToCpp::ApplyTextStyle(cef_text_style_t style,
+ bool add,
+ const CefRange& range) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_textfield_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, apply_text_style)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->apply_text_style(_struct, style, add, &range);
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefTextfieldCToCpp::IsCommandEnabled(
+ cef_text_field_commands_t command_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_textfield_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_command_enabled)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_command_enabled(_struct, command_id);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefTextfieldCToCpp::ExecuteCommand(cef_text_field_commands_t command_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_textfield_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, execute_command)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->execute_command(_struct, command_id);
+}
+
+NO_SANITIZE("cfi-icall") void CefTextfieldCToCpp::ClearEditHistory() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_textfield_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, clear_edit_history)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->clear_edit_history(_struct);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefTextfieldCToCpp::SetPlaceholderText(const CefString& text) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_textfield_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_placeholder_text)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: text; type: string_byref_const
+ DCHECK(!text.empty());
+ if (text.empty()) {
+ return;
+ }
+
+ // Execute
+ _struct->set_placeholder_text(_struct, text.GetStruct());
+}
+
+NO_SANITIZE("cfi-icall") CefString CefTextfieldCToCpp::GetPlaceholderText() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_textfield_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_placeholder_text)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_placeholder_text(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefTextfieldCToCpp::SetPlaceholderTextColor(cef_color_t color) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_textfield_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_placeholder_text_color)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_placeholder_text_color(_struct, color);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefTextfieldCToCpp::SetAccessibleName(const CefString& name) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_textfield_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_accessible_name)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: name; type: string_byref_const
+ DCHECK(!name.empty());
+ if (name.empty()) {
+ return;
+ }
+
+ // Execute
+ _struct->set_accessible_name(_struct, name.GetStruct());
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefBrowserView> CefTextfieldCToCpp::AsBrowserView() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, as_browser_view)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_browser_view_t* _retval = _struct->as_browser_view(_struct);
+
+ // Return type: refptr_same
+ return CefBrowserViewCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefButton> CefTextfieldCToCpp::AsButton() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, as_button)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_button_t* _retval = _struct->as_button(_struct);
+
+ // Return type: refptr_same
+ return CefButtonCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefPanel> CefTextfieldCToCpp::AsPanel() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, as_panel)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_panel_t* _retval = _struct->as_panel(_struct);
+
+ // Return type: refptr_same
+ return CefPanelCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefScrollView> CefTextfieldCToCpp::AsScrollView() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, as_scroll_view)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_scroll_view_t* _retval = _struct->as_scroll_view(_struct);
+
+ // Return type: refptr_same
+ return CefScrollViewCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefTextfield> CefTextfieldCToCpp::AsTextfield() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, as_textfield)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_textfield_t* _retval = _struct->as_textfield(_struct);
+
+ // Return type: refptr_same
+ return CefTextfieldCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") CefString CefTextfieldCToCpp::GetTypeString() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_type_string)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_type_string(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+CefString CefTextfieldCToCpp::ToString(bool include_children) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, to_string)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->to_string(_struct, include_children);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") bool CefTextfieldCToCpp::IsValid() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_valid)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_valid(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefTextfieldCToCpp::IsAttached() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_attached)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_attached(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefTextfieldCToCpp::IsSame(CefRefPtr<CefView> that) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_same)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: that; type: refptr_same
+ DCHECK(that.get());
+ if (!that.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->is_same(_struct, CefViewCToCpp::Unwrap(that));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefViewDelegate> CefTextfieldCToCpp::GetDelegate() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_delegate)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_view_delegate_t* _retval = _struct->get_delegate(_struct);
+
+ // Return type: refptr_diff
+ return CefViewDelegateCppToC::Unwrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefWindow> CefTextfieldCToCpp::GetWindow() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_window)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_window_t* _retval = _struct->get_window(_struct);
+
+ // Return type: refptr_same
+ return CefWindowCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") int CefTextfieldCToCpp::GetID() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_id)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_id(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") void CefTextfieldCToCpp::SetID(int id) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_id)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_id(_struct, id);
+}
+
+NO_SANITIZE("cfi-icall") int CefTextfieldCToCpp::GetGroupID() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_group_id)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_group_id(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") void CefTextfieldCToCpp::SetGroupID(int group_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_group_id)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_group_id(_struct, group_id);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefView> CefTextfieldCToCpp::GetParentView() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_parent_view)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_view_t* _retval = _struct->get_parent_view(_struct);
+
+ // Return type: refptr_same
+ return CefViewCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefView> CefTextfieldCToCpp::GetViewForID(int id) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_view_for_id)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_view_t* _retval = _struct->get_view_for_id(_struct, id);
+
+ // Return type: refptr_same
+ return CefViewCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefTextfieldCToCpp::SetBounds(const CefRect& bounds) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_bounds)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_bounds(_struct, &bounds);
+}
+
+NO_SANITIZE("cfi-icall") CefRect CefTextfieldCToCpp::GetBounds() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_bounds)) {
+ return CefRect();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_rect_t _retval = _struct->get_bounds(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") CefRect CefTextfieldCToCpp::GetBoundsInScreen() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_bounds_in_screen)) {
+ return CefRect();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_rect_t _retval = _struct->get_bounds_in_screen(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") void CefTextfieldCToCpp::SetSize(const CefSize& size) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_size)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_size(_struct, &size);
+}
+
+NO_SANITIZE("cfi-icall") CefSize CefTextfieldCToCpp::GetSize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_size_t _retval = _struct->get_size(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefTextfieldCToCpp::SetPosition(const CefPoint& position) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_position)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_position(_struct, &position);
+}
+
+NO_SANITIZE("cfi-icall") CefPoint CefTextfieldCToCpp::GetPosition() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_position)) {
+ return CefPoint();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_point_t _retval = _struct->get_position(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefTextfieldCToCpp::SetInsets(const CefInsets& insets) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_insets)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_insets(_struct, &insets);
+}
+
+NO_SANITIZE("cfi-icall") CefInsets CefTextfieldCToCpp::GetInsets() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_insets)) {
+ return CefInsets();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_insets_t _retval = _struct->get_insets(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") CefSize CefTextfieldCToCpp::GetPreferredSize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_preferred_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_size_t _retval = _struct->get_preferred_size(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") void CefTextfieldCToCpp::SizeToPreferredSize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, size_to_preferred_size)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->size_to_preferred_size(_struct);
+}
+
+NO_SANITIZE("cfi-icall") CefSize CefTextfieldCToCpp::GetMinimumSize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_minimum_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_size_t _retval = _struct->get_minimum_size(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") CefSize CefTextfieldCToCpp::GetMaximumSize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_maximum_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_size_t _retval = _struct->get_maximum_size(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") int CefTextfieldCToCpp::GetHeightForWidth(int width) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_height_for_width)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_height_for_width(_struct, width);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") void CefTextfieldCToCpp::InvalidateLayout() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, invalidate_layout)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->invalidate_layout(_struct);
+}
+
+NO_SANITIZE("cfi-icall") void CefTextfieldCToCpp::SetVisible(bool visible) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_visible)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_visible(_struct, visible);
+}
+
+NO_SANITIZE("cfi-icall") bool CefTextfieldCToCpp::IsVisible() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_visible)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_visible(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefTextfieldCToCpp::IsDrawn() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_drawn)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_drawn(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") void CefTextfieldCToCpp::SetEnabled(bool enabled) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_enabled)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_enabled(_struct, enabled);
+}
+
+NO_SANITIZE("cfi-icall") bool CefTextfieldCToCpp::IsEnabled() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_enabled)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_enabled(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") void CefTextfieldCToCpp::SetFocusable(bool focusable) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_focusable)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_focusable(_struct, focusable);
+}
+
+NO_SANITIZE("cfi-icall") bool CefTextfieldCToCpp::IsFocusable() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_focusable)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_focusable(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefTextfieldCToCpp::IsAccessibilityFocusable() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_accessibility_focusable)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_accessibility_focusable(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") void CefTextfieldCToCpp::RequestFocus() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, request_focus)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->request_focus(_struct);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefTextfieldCToCpp::SetBackgroundColor(cef_color_t color) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_background_color)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_background_color(_struct, color);
+}
+
+NO_SANITIZE("cfi-icall") cef_color_t CefTextfieldCToCpp::GetBackgroundColor() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_background_color)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_color_t _retval = _struct->get_background_color(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefTextfieldCToCpp::ConvertPointToScreen(CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, convert_point_to_screen)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->convert_point_to_screen(_struct, &point);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefTextfieldCToCpp::ConvertPointFromScreen(CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, convert_point_from_screen)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->convert_point_from_screen(_struct, &point);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefTextfieldCToCpp::ConvertPointToWindow(CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, convert_point_to_window)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->convert_point_to_window(_struct, &point);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefTextfieldCToCpp::ConvertPointFromWindow(CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, convert_point_from_window)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->convert_point_from_window(_struct, &point);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefTextfieldCToCpp::ConvertPointToView(CefRefPtr<CefView> view,
+ CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, convert_point_to_view)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_same
+ DCHECK(view.get());
+ if (!view.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->convert_point_to_view(
+ _struct, CefViewCToCpp::Unwrap(view), &point);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefTextfieldCToCpp::ConvertPointFromView(CefRefPtr<CefView> view,
+ CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, convert_point_from_view)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_same
+ DCHECK(view.get());
+ if (!view.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->convert_point_from_view(
+ _struct, CefViewCToCpp::Unwrap(view), &point);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefTextfieldCToCpp::CefTextfieldCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefTextfieldCToCpp::~CefTextfieldCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_textfield_t*
+CefCToCppRefCounted<CefTextfieldCToCpp, CefTextfield, cef_textfield_t>::
+ UnwrapDerived(CefWrapperType type, CefTextfield* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefTextfieldCToCpp,
+ CefTextfield,
+ cef_textfield_t>::kWrapperType =
+ WT_TEXTFIELD;
diff --git a/libcef_dll/ctocpp/views/textfield_ctocpp.h b/libcef_dll/ctocpp/views/textfield_ctocpp.h
new file mode 100644
index 00000000..3325a22a
--- /dev/null
+++ b/libcef_dll/ctocpp/views/textfield_ctocpp.h
@@ -0,0 +1,124 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=cdc3237fbd889409f8e9aa2116689a3e1c1229c7$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_VIEWS_TEXTFIELD_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_VIEWS_TEXTFIELD_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/views/cef_textfield_capi.h"
+#include "include/views/cef_textfield.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefTextfieldCToCpp : public CefCToCppRefCounted<CefTextfieldCToCpp,
+ CefTextfield,
+ cef_textfield_t> {
+ public:
+ CefTextfieldCToCpp();
+ virtual ~CefTextfieldCToCpp();
+
+ // CefTextfield methods.
+ void SetPasswordInput(bool password_input) override;
+ bool IsPasswordInput() override;
+ void SetReadOnly(bool read_only) override;
+ bool IsReadOnly() override;
+ CefString GetText() override;
+ void SetText(const CefString& text) override;
+ void AppendText(const CefString& text) override;
+ void InsertOrReplaceText(const CefString& text) override;
+ bool HasSelection() override;
+ CefString GetSelectedText() override;
+ void SelectAll(bool reversed) override;
+ void ClearSelection() override;
+ CefRange GetSelectedRange() override;
+ void SelectRange(const CefRange& range) override;
+ size_t GetCursorPosition() override;
+ void SetTextColor(cef_color_t color) override;
+ cef_color_t GetTextColor() override;
+ void SetSelectionTextColor(cef_color_t color) override;
+ cef_color_t GetSelectionTextColor() override;
+ void SetSelectionBackgroundColor(cef_color_t color) override;
+ cef_color_t GetSelectionBackgroundColor() override;
+ void SetFontList(const CefString& font_list) override;
+ void ApplyTextColor(cef_color_t color, const CefRange& range) override;
+ void ApplyTextStyle(cef_text_style_t style,
+ bool add,
+ const CefRange& range) override;
+ bool IsCommandEnabled(cef_text_field_commands_t command_id) override;
+ void ExecuteCommand(cef_text_field_commands_t command_id) override;
+ void ClearEditHistory() override;
+ void SetPlaceholderText(const CefString& text) override;
+ CefString GetPlaceholderText() override;
+ void SetPlaceholderTextColor(cef_color_t color) override;
+ void SetAccessibleName(const CefString& name) override;
+
+ // CefView methods.
+ CefRefPtr<CefBrowserView> AsBrowserView() override;
+ CefRefPtr<CefButton> AsButton() override;
+ CefRefPtr<CefPanel> AsPanel() override;
+ CefRefPtr<CefScrollView> AsScrollView() override;
+ CefRefPtr<CefTextfield> AsTextfield() override;
+ CefString GetTypeString() override;
+ CefString ToString(bool include_children) override;
+ bool IsValid() override;
+ bool IsAttached() override;
+ bool IsSame(CefRefPtr<CefView> that) override;
+ CefRefPtr<CefViewDelegate> GetDelegate() override;
+ CefRefPtr<CefWindow> GetWindow() override;
+ int GetID() override;
+ void SetID(int id) override;
+ int GetGroupID() override;
+ void SetGroupID(int group_id) override;
+ CefRefPtr<CefView> GetParentView() override;
+ CefRefPtr<CefView> GetViewForID(int id) override;
+ void SetBounds(const CefRect& bounds) override;
+ CefRect GetBounds() override;
+ CefRect GetBoundsInScreen() override;
+ void SetSize(const CefSize& size) override;
+ CefSize GetSize() override;
+ void SetPosition(const CefPoint& position) override;
+ CefPoint GetPosition() override;
+ void SetInsets(const CefInsets& insets) override;
+ CefInsets GetInsets() override;
+ CefSize GetPreferredSize() override;
+ void SizeToPreferredSize() override;
+ CefSize GetMinimumSize() override;
+ CefSize GetMaximumSize() override;
+ int GetHeightForWidth(int width) override;
+ void InvalidateLayout() override;
+ void SetVisible(bool visible) override;
+ bool IsVisible() override;
+ bool IsDrawn() override;
+ void SetEnabled(bool enabled) override;
+ bool IsEnabled() override;
+ void SetFocusable(bool focusable) override;
+ bool IsFocusable() override;
+ bool IsAccessibilityFocusable() override;
+ void RequestFocus() override;
+ void SetBackgroundColor(cef_color_t color) override;
+ cef_color_t GetBackgroundColor() override;
+ bool ConvertPointToScreen(CefPoint& point) override;
+ bool ConvertPointFromScreen(CefPoint& point) override;
+ bool ConvertPointToWindow(CefPoint& point) override;
+ bool ConvertPointFromWindow(CefPoint& point) override;
+ bool ConvertPointToView(CefRefPtr<CefView> view, CefPoint& point) override;
+ bool ConvertPointFromView(CefRefPtr<CefView> view, CefPoint& point) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_VIEWS_TEXTFIELD_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/views/textfield_delegate_ctocpp.cc b/libcef_dll/ctocpp/views/textfield_delegate_ctocpp.cc
new file mode 100644
index 00000000..b5452d6e
--- /dev/null
+++ b/libcef_dll/ctocpp/views/textfield_delegate_ctocpp.cc
@@ -0,0 +1,350 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=7b605cbe624fc1d82b3b74000a03a7941fba7eba$
+//
+
+#include "libcef_dll/ctocpp/views/textfield_delegate_ctocpp.h"
+#include "libcef_dll/cpptoc/views/textfield_cpptoc.h"
+#include "libcef_dll/cpptoc/views/view_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+bool CefTextfieldDelegateCToCpp::OnKeyEvent(CefRefPtr<CefTextfield> textfield,
+ const CefKeyEvent& event) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_textfield_delegate_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_key_event)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: textfield; type: refptr_diff
+ DCHECK(textfield.get());
+ if (!textfield.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->on_key_event(
+ _struct, CefTextfieldCppToC::Wrap(textfield), &event);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefTextfieldDelegateCToCpp::OnAfterUserAction(
+ CefRefPtr<CefTextfield> textfield) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_textfield_delegate_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_after_user_action)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: textfield; type: refptr_diff
+ DCHECK(textfield.get());
+ if (!textfield.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_after_user_action(_struct, CefTextfieldCppToC::Wrap(textfield));
+}
+
+NO_SANITIZE("cfi-icall")
+CefSize CefTextfieldDelegateCToCpp::GetPreferredSize(CefRefPtr<CefView> view) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_preferred_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval =
+ _struct->get_preferred_size(_struct, CefViewCppToC::Wrap(view));
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CefSize CefTextfieldDelegateCToCpp::GetMinimumSize(CefRefPtr<CefView> view) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_minimum_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval =
+ _struct->get_minimum_size(_struct, CefViewCppToC::Wrap(view));
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CefSize CefTextfieldDelegateCToCpp::GetMaximumSize(CefRefPtr<CefView> view) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_maximum_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval =
+ _struct->get_maximum_size(_struct, CefViewCppToC::Wrap(view));
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+int CefTextfieldDelegateCToCpp::GetHeightForWidth(CefRefPtr<CefView> view,
+ int width) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_height_for_width)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return 0;
+ }
+
+ // Execute
+ int _retval =
+ _struct->get_height_for_width(_struct, CefViewCppToC::Wrap(view), width);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefTextfieldDelegateCToCpp::OnParentViewChanged(
+ CefRefPtr<CefView> view,
+ bool added,
+ CefRefPtr<CefView> parent) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, on_parent_view_changed)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return;
+ }
+ // Verify param: parent; type: refptr_diff
+ DCHECK(parent.get());
+ if (!parent.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_parent_view_changed(_struct, CefViewCppToC::Wrap(view), added,
+ CefViewCppToC::Wrap(parent));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefTextfieldDelegateCToCpp::OnChildViewChanged(CefRefPtr<CefView> view,
+ bool added,
+ CefRefPtr<CefView> child) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, on_child_view_changed)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return;
+ }
+ // Verify param: child; type: refptr_diff
+ DCHECK(child.get());
+ if (!child.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_child_view_changed(_struct, CefViewCppToC::Wrap(view), added,
+ CefViewCppToC::Wrap(child));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefTextfieldDelegateCToCpp::OnWindowChanged(CefRefPtr<CefView> view,
+ bool added) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, on_window_changed)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_window_changed(_struct, CefViewCppToC::Wrap(view), added);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefTextfieldDelegateCToCpp::OnLayoutChanged(CefRefPtr<CefView> view,
+ const CefRect& new_bounds) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, on_layout_changed)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_layout_changed(_struct, CefViewCppToC::Wrap(view), &new_bounds);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefTextfieldDelegateCToCpp::OnFocus(CefRefPtr<CefView> view) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, on_focus)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_focus(_struct, CefViewCppToC::Wrap(view));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefTextfieldDelegateCToCpp::OnBlur(CefRefPtr<CefView> view) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, on_blur)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_blur(_struct, CefViewCppToC::Wrap(view));
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefTextfieldDelegateCToCpp::CefTextfieldDelegateCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefTextfieldDelegateCToCpp::~CefTextfieldDelegateCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_textfield_delegate_t* CefCToCppRefCounted<
+ CefTextfieldDelegateCToCpp,
+ CefTextfieldDelegate,
+ cef_textfield_delegate_t>::UnwrapDerived(CefWrapperType type,
+ CefTextfieldDelegate* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefTextfieldDelegateCToCpp,
+ CefTextfieldDelegate,
+ cef_textfield_delegate_t>::kWrapperType =
+ WT_TEXTFIELD_DELEGATE;
diff --git a/libcef_dll/ctocpp/views/textfield_delegate_ctocpp.h b/libcef_dll/ctocpp/views/textfield_delegate_ctocpp.h
new file mode 100644
index 00000000..76d15eee
--- /dev/null
+++ b/libcef_dll/ctocpp/views/textfield_delegate_ctocpp.h
@@ -0,0 +1,62 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=65dedd950d154a0125b094bb1488e787726545cb$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_VIEWS_TEXTFIELD_DELEGATE_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_VIEWS_TEXTFIELD_DELEGATE_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/views/cef_textfield_capi.h"
+#include "include/capi/views/cef_textfield_delegate_capi.h"
+#include "include/views/cef_textfield.h"
+#include "include/views/cef_textfield_delegate.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefTextfieldDelegateCToCpp
+ : public CefCToCppRefCounted<CefTextfieldDelegateCToCpp,
+ CefTextfieldDelegate,
+ cef_textfield_delegate_t> {
+ public:
+ CefTextfieldDelegateCToCpp();
+ virtual ~CefTextfieldDelegateCToCpp();
+
+ // CefTextfieldDelegate methods.
+ bool OnKeyEvent(CefRefPtr<CefTextfield> textfield,
+ const CefKeyEvent& event) override;
+ void OnAfterUserAction(CefRefPtr<CefTextfield> textfield) override;
+
+ // CefViewDelegate methods.
+ CefSize GetPreferredSize(CefRefPtr<CefView> view) override;
+ CefSize GetMinimumSize(CefRefPtr<CefView> view) override;
+ CefSize GetMaximumSize(CefRefPtr<CefView> view) override;
+ int GetHeightForWidth(CefRefPtr<CefView> view, int width) override;
+ void OnParentViewChanged(CefRefPtr<CefView> view,
+ bool added,
+ CefRefPtr<CefView> parent) override;
+ void OnChildViewChanged(CefRefPtr<CefView> view,
+ bool added,
+ CefRefPtr<CefView> child) override;
+ void OnWindowChanged(CefRefPtr<CefView> view, bool added) override;
+ void OnLayoutChanged(CefRefPtr<CefView> view,
+ const CefRect& new_bounds) override;
+ void OnFocus(CefRefPtr<CefView> view) override;
+ void OnBlur(CefRefPtr<CefView> view) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_VIEWS_TEXTFIELD_DELEGATE_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/views/view_ctocpp.cc b/libcef_dll/ctocpp/views/view_ctocpp.cc
new file mode 100644
index 00000000..237db02d
--- /dev/null
+++ b/libcef_dll/ctocpp/views/view_ctocpp.cc
@@ -0,0 +1,934 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=44f883b688d3032e56569aa1f1f2ac9b7d5d6bc4$
+//
+
+#include "libcef_dll/ctocpp/views/view_ctocpp.h"
+#include "libcef_dll/cpptoc/views/view_delegate_cpptoc.h"
+#include "libcef_dll/ctocpp/views/browser_view_ctocpp.h"
+#include "libcef_dll/ctocpp/views/button_ctocpp.h"
+#include "libcef_dll/ctocpp/views/label_button_ctocpp.h"
+#include "libcef_dll/ctocpp/views/menu_button_ctocpp.h"
+#include "libcef_dll/ctocpp/views/panel_ctocpp.h"
+#include "libcef_dll/ctocpp/views/scroll_view_ctocpp.h"
+#include "libcef_dll/ctocpp/views/textfield_ctocpp.h"
+#include "libcef_dll/ctocpp/views/window_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefBrowserView> CefViewCToCpp::AsBrowserView() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, as_browser_view)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_browser_view_t* _retval = _struct->as_browser_view(_struct);
+
+ // Return type: refptr_same
+ return CefBrowserViewCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefButton> CefViewCToCpp::AsButton() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, as_button)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_button_t* _retval = _struct->as_button(_struct);
+
+ // Return type: refptr_same
+ return CefButtonCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefPanel> CefViewCToCpp::AsPanel() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, as_panel)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_panel_t* _retval = _struct->as_panel(_struct);
+
+ // Return type: refptr_same
+ return CefPanelCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefScrollView> CefViewCToCpp::AsScrollView() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, as_scroll_view)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_scroll_view_t* _retval = _struct->as_scroll_view(_struct);
+
+ // Return type: refptr_same
+ return CefScrollViewCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefTextfield> CefViewCToCpp::AsTextfield() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, as_textfield)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_textfield_t* _retval = _struct->as_textfield(_struct);
+
+ // Return type: refptr_same
+ return CefTextfieldCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") CefString CefViewCToCpp::GetTypeString() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_type_string)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_type_string(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+CefString CefViewCToCpp::ToString(bool include_children) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, to_string)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->to_string(_struct, include_children);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") bool CefViewCToCpp::IsValid() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_valid)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_valid(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefViewCToCpp::IsAttached() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_attached)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_attached(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefViewCToCpp::IsSame(CefRefPtr<CefView> that) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_same)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: that; type: refptr_same
+ DCHECK(that.get());
+ if (!that.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->is_same(_struct, CefViewCToCpp::Unwrap(that));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefViewDelegate> CefViewCToCpp::GetDelegate() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_delegate)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_view_delegate_t* _retval = _struct->get_delegate(_struct);
+
+ // Return type: refptr_diff
+ return CefViewDelegateCppToC::Unwrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefWindow> CefViewCToCpp::GetWindow() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_window)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_window_t* _retval = _struct->get_window(_struct);
+
+ // Return type: refptr_same
+ return CefWindowCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") int CefViewCToCpp::GetID() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_id)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_id(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") void CefViewCToCpp::SetID(int id) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_id)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_id(_struct, id);
+}
+
+NO_SANITIZE("cfi-icall") int CefViewCToCpp::GetGroupID() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_group_id)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_group_id(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") void CefViewCToCpp::SetGroupID(int group_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_group_id)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_group_id(_struct, group_id);
+}
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefView> CefViewCToCpp::GetParentView() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_parent_view)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_view_t* _retval = _struct->get_parent_view(_struct);
+
+ // Return type: refptr_same
+ return CefViewCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefView> CefViewCToCpp::GetViewForID(int id) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_view_for_id)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_view_t* _retval = _struct->get_view_for_id(_struct, id);
+
+ // Return type: refptr_same
+ return CefViewCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") void CefViewCToCpp::SetBounds(const CefRect& bounds) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_bounds)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_bounds(_struct, &bounds);
+}
+
+NO_SANITIZE("cfi-icall") CefRect CefViewCToCpp::GetBounds() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_bounds)) {
+ return CefRect();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_rect_t _retval = _struct->get_bounds(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") CefRect CefViewCToCpp::GetBoundsInScreen() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_bounds_in_screen)) {
+ return CefRect();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_rect_t _retval = _struct->get_bounds_in_screen(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") void CefViewCToCpp::SetSize(const CefSize& size) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_size)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_size(_struct, &size);
+}
+
+NO_SANITIZE("cfi-icall") CefSize CefViewCToCpp::GetSize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_size_t _retval = _struct->get_size(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefViewCToCpp::SetPosition(const CefPoint& position) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_position)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_position(_struct, &position);
+}
+
+NO_SANITIZE("cfi-icall") CefPoint CefViewCToCpp::GetPosition() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_position)) {
+ return CefPoint();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_point_t _retval = _struct->get_position(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefViewCToCpp::SetInsets(const CefInsets& insets) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_insets)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_insets(_struct, &insets);
+}
+
+NO_SANITIZE("cfi-icall") CefInsets CefViewCToCpp::GetInsets() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_insets)) {
+ return CefInsets();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_insets_t _retval = _struct->get_insets(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") CefSize CefViewCToCpp::GetPreferredSize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_preferred_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_size_t _retval = _struct->get_preferred_size(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") void CefViewCToCpp::SizeToPreferredSize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, size_to_preferred_size)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->size_to_preferred_size(_struct);
+}
+
+NO_SANITIZE("cfi-icall") CefSize CefViewCToCpp::GetMinimumSize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_minimum_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_size_t _retval = _struct->get_minimum_size(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") CefSize CefViewCToCpp::GetMaximumSize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_maximum_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_size_t _retval = _struct->get_maximum_size(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") int CefViewCToCpp::GetHeightForWidth(int width) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_height_for_width)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_height_for_width(_struct, width);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") void CefViewCToCpp::InvalidateLayout() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, invalidate_layout)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->invalidate_layout(_struct);
+}
+
+NO_SANITIZE("cfi-icall") void CefViewCToCpp::SetVisible(bool visible) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_visible)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_visible(_struct, visible);
+}
+
+NO_SANITIZE("cfi-icall") bool CefViewCToCpp::IsVisible() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_visible)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_visible(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefViewCToCpp::IsDrawn() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_drawn)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_drawn(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") void CefViewCToCpp::SetEnabled(bool enabled) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_enabled)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_enabled(_struct, enabled);
+}
+
+NO_SANITIZE("cfi-icall") bool CefViewCToCpp::IsEnabled() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_enabled)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_enabled(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") void CefViewCToCpp::SetFocusable(bool focusable) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_focusable)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_focusable(_struct, focusable);
+}
+
+NO_SANITIZE("cfi-icall") bool CefViewCToCpp::IsFocusable() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_focusable)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_focusable(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefViewCToCpp::IsAccessibilityFocusable() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_accessibility_focusable)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_accessibility_focusable(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") void CefViewCToCpp::RequestFocus() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, request_focus)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->request_focus(_struct);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefViewCToCpp::SetBackgroundColor(cef_color_t color) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_background_color)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_background_color(_struct, color);
+}
+
+NO_SANITIZE("cfi-icall") cef_color_t CefViewCToCpp::GetBackgroundColor() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_background_color)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_color_t _retval = _struct->get_background_color(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefViewCToCpp::ConvertPointToScreen(CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, convert_point_to_screen)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->convert_point_to_screen(_struct, &point);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefViewCToCpp::ConvertPointFromScreen(CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, convert_point_from_screen)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->convert_point_from_screen(_struct, &point);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefViewCToCpp::ConvertPointToWindow(CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, convert_point_to_window)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->convert_point_to_window(_struct, &point);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefViewCToCpp::ConvertPointFromWindow(CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, convert_point_from_window)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->convert_point_from_window(_struct, &point);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefViewCToCpp::ConvertPointToView(CefRefPtr<CefView> view,
+ CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, convert_point_to_view)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_same
+ DCHECK(view.get());
+ if (!view.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->convert_point_to_view(
+ _struct, CefViewCToCpp::Unwrap(view), &point);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefViewCToCpp::ConvertPointFromView(CefRefPtr<CefView> view,
+ CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, convert_point_from_view)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_same
+ DCHECK(view.get());
+ if (!view.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->convert_point_from_view(
+ _struct, CefViewCToCpp::Unwrap(view), &point);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefViewCToCpp::CefViewCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefViewCToCpp::~CefViewCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_view_t*
+CefCToCppRefCounted<CefViewCToCpp, CefView, cef_view_t>::UnwrapDerived(
+ CefWrapperType type,
+ CefView* c) {
+ if (type == WT_BROWSER_VIEW) {
+ return reinterpret_cast<cef_view_t*>(
+ CefBrowserViewCToCpp::Unwrap(reinterpret_cast<CefBrowserView*>(c)));
+ }
+ if (type == WT_BUTTON) {
+ return reinterpret_cast<cef_view_t*>(
+ CefButtonCToCpp::Unwrap(reinterpret_cast<CefButton*>(c)));
+ }
+ if (type == WT_LABEL_BUTTON) {
+ return reinterpret_cast<cef_view_t*>(
+ CefLabelButtonCToCpp::Unwrap(reinterpret_cast<CefLabelButton*>(c)));
+ }
+ if (type == WT_MENU_BUTTON) {
+ return reinterpret_cast<cef_view_t*>(
+ CefMenuButtonCToCpp::Unwrap(reinterpret_cast<CefMenuButton*>(c)));
+ }
+ if (type == WT_PANEL) {
+ return reinterpret_cast<cef_view_t*>(
+ CefPanelCToCpp::Unwrap(reinterpret_cast<CefPanel*>(c)));
+ }
+ if (type == WT_SCROLL_VIEW) {
+ return reinterpret_cast<cef_view_t*>(
+ CefScrollViewCToCpp::Unwrap(reinterpret_cast<CefScrollView*>(c)));
+ }
+ if (type == WT_TEXTFIELD) {
+ return reinterpret_cast<cef_view_t*>(
+ CefTextfieldCToCpp::Unwrap(reinterpret_cast<CefTextfield*>(c)));
+ }
+ if (type == WT_WINDOW) {
+ return reinterpret_cast<cef_view_t*>(
+ CefWindowCToCpp::Unwrap(reinterpret_cast<CefWindow*>(c)));
+ }
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType
+ CefCToCppRefCounted<CefViewCToCpp, CefView, cef_view_t>::kWrapperType =
+ WT_VIEW;
diff --git a/libcef_dll/ctocpp/views/view_ctocpp.h b/libcef_dll/ctocpp/views/view_ctocpp.h
new file mode 100644
index 00000000..65b2cc07
--- /dev/null
+++ b/libcef_dll/ctocpp/views/view_ctocpp.h
@@ -0,0 +1,100 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=5af9a065bd30e46fad816250442dd6b3d31834fd$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_VIEWS_VIEW_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_VIEWS_VIEW_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/views/cef_browser_view_capi.h"
+#include "include/capi/views/cef_button_capi.h"
+#include "include/capi/views/cef_panel_capi.h"
+#include "include/capi/views/cef_scroll_view_capi.h"
+#include "include/capi/views/cef_textfield_capi.h"
+#include "include/capi/views/cef_view_capi.h"
+#include "include/capi/views/cef_window_capi.h"
+#include "include/views/cef_browser_view.h"
+#include "include/views/cef_button.h"
+#include "include/views/cef_panel.h"
+#include "include/views/cef_scroll_view.h"
+#include "include/views/cef_textfield.h"
+#include "include/views/cef_view.h"
+#include "include/views/cef_window.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefViewCToCpp
+ : public CefCToCppRefCounted<CefViewCToCpp, CefView, cef_view_t> {
+ public:
+ CefViewCToCpp();
+ virtual ~CefViewCToCpp();
+
+ // CefView methods.
+ CefRefPtr<CefBrowserView> AsBrowserView() override;
+ CefRefPtr<CefButton> AsButton() override;
+ CefRefPtr<CefPanel> AsPanel() override;
+ CefRefPtr<CefScrollView> AsScrollView() override;
+ CefRefPtr<CefTextfield> AsTextfield() override;
+ CefString GetTypeString() override;
+ CefString ToString(bool include_children) override;
+ bool IsValid() override;
+ bool IsAttached() override;
+ bool IsSame(CefRefPtr<CefView> that) override;
+ CefRefPtr<CefViewDelegate> GetDelegate() override;
+ CefRefPtr<CefWindow> GetWindow() override;
+ int GetID() override;
+ void SetID(int id) override;
+ int GetGroupID() override;
+ void SetGroupID(int group_id) override;
+ CefRefPtr<CefView> GetParentView() override;
+ CefRefPtr<CefView> GetViewForID(int id) override;
+ void SetBounds(const CefRect& bounds) override;
+ CefRect GetBounds() override;
+ CefRect GetBoundsInScreen() override;
+ void SetSize(const CefSize& size) override;
+ CefSize GetSize() override;
+ void SetPosition(const CefPoint& position) override;
+ CefPoint GetPosition() override;
+ void SetInsets(const CefInsets& insets) override;
+ CefInsets GetInsets() override;
+ CefSize GetPreferredSize() override;
+ void SizeToPreferredSize() override;
+ CefSize GetMinimumSize() override;
+ CefSize GetMaximumSize() override;
+ int GetHeightForWidth(int width) override;
+ void InvalidateLayout() override;
+ void SetVisible(bool visible) override;
+ bool IsVisible() override;
+ bool IsDrawn() override;
+ void SetEnabled(bool enabled) override;
+ bool IsEnabled() override;
+ void SetFocusable(bool focusable) override;
+ bool IsFocusable() override;
+ bool IsAccessibilityFocusable() override;
+ void RequestFocus() override;
+ void SetBackgroundColor(cef_color_t color) override;
+ cef_color_t GetBackgroundColor() override;
+ bool ConvertPointToScreen(CefPoint& point) override;
+ bool ConvertPointFromScreen(CefPoint& point) override;
+ bool ConvertPointToWindow(CefPoint& point) override;
+ bool ConvertPointFromWindow(CefPoint& point) override;
+ bool ConvertPointToView(CefRefPtr<CefView> view, CefPoint& point) override;
+ bool ConvertPointFromView(CefRefPtr<CefView> view, CefPoint& point) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_VIEWS_VIEW_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/views/view_delegate_ctocpp.cc b/libcef_dll/ctocpp/views/view_delegate_ctocpp.cc
new file mode 100644
index 00000000..65e300a4
--- /dev/null
+++ b/libcef_dll/ctocpp/views/view_delegate_ctocpp.cc
@@ -0,0 +1,325 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=8d041a69343f5af9338dd705701acbe7f94f425f$
+//
+
+#include "libcef_dll/ctocpp/views/view_delegate_ctocpp.h"
+#include "libcef_dll/cpptoc/views/view_cpptoc.h"
+#include "libcef_dll/ctocpp/views/browser_view_delegate_ctocpp.h"
+#include "libcef_dll/ctocpp/views/button_delegate_ctocpp.h"
+#include "libcef_dll/ctocpp/views/menu_button_delegate_ctocpp.h"
+#include "libcef_dll/ctocpp/views/panel_delegate_ctocpp.h"
+#include "libcef_dll/ctocpp/views/textfield_delegate_ctocpp.h"
+#include "libcef_dll/ctocpp/views/window_delegate_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefSize CefViewDelegateCToCpp::GetPreferredSize(CefRefPtr<CefView> view) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_preferred_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval =
+ _struct->get_preferred_size(_struct, CefViewCppToC::Wrap(view));
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CefSize CefViewDelegateCToCpp::GetMinimumSize(CefRefPtr<CefView> view) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_minimum_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval =
+ _struct->get_minimum_size(_struct, CefViewCppToC::Wrap(view));
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CefSize CefViewDelegateCToCpp::GetMaximumSize(CefRefPtr<CefView> view) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_maximum_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval =
+ _struct->get_maximum_size(_struct, CefViewCppToC::Wrap(view));
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+int CefViewDelegateCToCpp::GetHeightForWidth(CefRefPtr<CefView> view,
+ int width) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_height_for_width)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return 0;
+ }
+
+ // Execute
+ int _retval =
+ _struct->get_height_for_width(_struct, CefViewCppToC::Wrap(view), width);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefViewDelegateCToCpp::OnParentViewChanged(CefRefPtr<CefView> view,
+ bool added,
+ CefRefPtr<CefView> parent) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_parent_view_changed)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return;
+ }
+ // Verify param: parent; type: refptr_diff
+ DCHECK(parent.get());
+ if (!parent.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_parent_view_changed(_struct, CefViewCppToC::Wrap(view), added,
+ CefViewCppToC::Wrap(parent));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefViewDelegateCToCpp::OnChildViewChanged(CefRefPtr<CefView> view,
+ bool added,
+ CefRefPtr<CefView> child) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_child_view_changed)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return;
+ }
+ // Verify param: child; type: refptr_diff
+ DCHECK(child.get());
+ if (!child.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_child_view_changed(_struct, CefViewCppToC::Wrap(view), added,
+ CefViewCppToC::Wrap(child));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefViewDelegateCToCpp::OnWindowChanged(CefRefPtr<CefView> view,
+ bool added) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_window_changed)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_window_changed(_struct, CefViewCppToC::Wrap(view), added);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefViewDelegateCToCpp::OnLayoutChanged(CefRefPtr<CefView> view,
+ const CefRect& new_bounds) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_layout_changed)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_layout_changed(_struct, CefViewCppToC::Wrap(view), &new_bounds);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefViewDelegateCToCpp::OnFocus(CefRefPtr<CefView> view) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_focus)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_focus(_struct, CefViewCppToC::Wrap(view));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefViewDelegateCToCpp::OnBlur(CefRefPtr<CefView> view) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_blur)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_blur(_struct, CefViewCppToC::Wrap(view));
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefViewDelegateCToCpp::CefViewDelegateCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefViewDelegateCToCpp::~CefViewDelegateCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_view_delegate_t*
+CefCToCppRefCounted<CefViewDelegateCToCpp,
+ CefViewDelegate,
+ cef_view_delegate_t>::UnwrapDerived(CefWrapperType type,
+ CefViewDelegate* c) {
+ if (type == WT_BROWSER_VIEW_DELEGATE) {
+ return reinterpret_cast<cef_view_delegate_t*>(
+ CefBrowserViewDelegateCToCpp::Unwrap(
+ reinterpret_cast<CefBrowserViewDelegate*>(c)));
+ }
+ if (type == WT_BUTTON_DELEGATE) {
+ return reinterpret_cast<cef_view_delegate_t*>(
+ CefButtonDelegateCToCpp::Unwrap(
+ reinterpret_cast<CefButtonDelegate*>(c)));
+ }
+ if (type == WT_MENU_BUTTON_DELEGATE) {
+ return reinterpret_cast<cef_view_delegate_t*>(
+ CefMenuButtonDelegateCToCpp::Unwrap(
+ reinterpret_cast<CefMenuButtonDelegate*>(c)));
+ }
+ if (type == WT_PANEL_DELEGATE) {
+ return reinterpret_cast<cef_view_delegate_t*>(
+ CefPanelDelegateCToCpp::Unwrap(reinterpret_cast<CefPanelDelegate*>(c)));
+ }
+ if (type == WT_TEXTFIELD_DELEGATE) {
+ return reinterpret_cast<cef_view_delegate_t*>(
+ CefTextfieldDelegateCToCpp::Unwrap(
+ reinterpret_cast<CefTextfieldDelegate*>(c)));
+ }
+ if (type == WT_WINDOW_DELEGATE) {
+ return reinterpret_cast<cef_view_delegate_t*>(
+ CefWindowDelegateCToCpp::Unwrap(
+ reinterpret_cast<CefWindowDelegate*>(c)));
+ }
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefViewDelegateCToCpp,
+ CefViewDelegate,
+ cef_view_delegate_t>::kWrapperType =
+ WT_VIEW_DELEGATE;
diff --git a/libcef_dll/ctocpp/views/view_delegate_ctocpp.h b/libcef_dll/ctocpp/views/view_delegate_ctocpp.h
new file mode 100644
index 00000000..2a8024bf
--- /dev/null
+++ b/libcef_dll/ctocpp/views/view_delegate_ctocpp.h
@@ -0,0 +1,56 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=c433d8e9462e7a948338bfe9192f247fdc253614$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_VIEWS_VIEW_DELEGATE_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_VIEWS_VIEW_DELEGATE_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/views/cef_view_capi.h"
+#include "include/capi/views/cef_view_delegate_capi.h"
+#include "include/views/cef_view.h"
+#include "include/views/cef_view_delegate.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefViewDelegateCToCpp : public CefCToCppRefCounted<CefViewDelegateCToCpp,
+ CefViewDelegate,
+ cef_view_delegate_t> {
+ public:
+ CefViewDelegateCToCpp();
+ virtual ~CefViewDelegateCToCpp();
+
+ // CefViewDelegate methods.
+ CefSize GetPreferredSize(CefRefPtr<CefView> view) override;
+ CefSize GetMinimumSize(CefRefPtr<CefView> view) override;
+ CefSize GetMaximumSize(CefRefPtr<CefView> view) override;
+ int GetHeightForWidth(CefRefPtr<CefView> view, int width) override;
+ void OnParentViewChanged(CefRefPtr<CefView> view,
+ bool added,
+ CefRefPtr<CefView> parent) override;
+ void OnChildViewChanged(CefRefPtr<CefView> view,
+ bool added,
+ CefRefPtr<CefView> child) override;
+ void OnWindowChanged(CefRefPtr<CefView> view, bool added) override;
+ void OnLayoutChanged(CefRefPtr<CefView> view,
+ const CefRect& new_bounds) override;
+ void OnFocus(CefRefPtr<CefView> view) override;
+ void OnBlur(CefRefPtr<CefView> view) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_VIEWS_VIEW_DELEGATE_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/views/window_ctocpp.cc b/libcef_dll/ctocpp/views/window_ctocpp.cc
new file mode 100644
index 00000000..0b5eb558
--- /dev/null
+++ b/libcef_dll/ctocpp/views/window_ctocpp.cc
@@ -0,0 +1,1790 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=9cb7b2760f04201aaf79feceb2db8c0d3036892c$
+//
+
+#include "libcef_dll/ctocpp/views/window_ctocpp.h"
+#include "libcef_dll/cpptoc/views/view_delegate_cpptoc.h"
+#include "libcef_dll/cpptoc/views/window_delegate_cpptoc.h"
+#include "libcef_dll/ctocpp/image_ctocpp.h"
+#include "libcef_dll/ctocpp/menu_model_ctocpp.h"
+#include "libcef_dll/ctocpp/views/box_layout_ctocpp.h"
+#include "libcef_dll/ctocpp/views/browser_view_ctocpp.h"
+#include "libcef_dll/ctocpp/views/button_ctocpp.h"
+#include "libcef_dll/ctocpp/views/display_ctocpp.h"
+#include "libcef_dll/ctocpp/views/fill_layout_ctocpp.h"
+#include "libcef_dll/ctocpp/views/layout_ctocpp.h"
+#include "libcef_dll/ctocpp/views/overlay_controller_ctocpp.h"
+#include "libcef_dll/ctocpp/views/panel_ctocpp.h"
+#include "libcef_dll/ctocpp/views/scroll_view_ctocpp.h"
+#include "libcef_dll/ctocpp/views/textfield_ctocpp.h"
+#include "libcef_dll/ctocpp/views/view_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// STATIC METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefWindow> CefWindow::CreateTopLevelWindow(
+ CefRefPtr<CefWindowDelegate> delegate) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: delegate
+
+ // Execute
+ cef_window_t* _retval =
+ cef_window_create_top_level(CefWindowDelegateCppToC::Wrap(delegate));
+
+ // Return type: refptr_same
+ return CefWindowCToCpp::Wrap(_retval);
+}
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") void CefWindowCToCpp::Show() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_window_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, show)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->show(_struct);
+}
+
+NO_SANITIZE("cfi-icall") void CefWindowCToCpp::Hide() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_window_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, hide)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->hide(_struct);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefWindowCToCpp::CenterWindow(const CefSize& size) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_window_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, center_window)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->center_window(_struct, &size);
+}
+
+NO_SANITIZE("cfi-icall") void CefWindowCToCpp::Close() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_window_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, close)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->close(_struct);
+}
+
+NO_SANITIZE("cfi-icall") bool CefWindowCToCpp::IsClosed() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_window_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_closed)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_closed(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") void CefWindowCToCpp::Activate() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_window_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, activate)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->activate(_struct);
+}
+
+NO_SANITIZE("cfi-icall") void CefWindowCToCpp::Deactivate() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_window_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, deactivate)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->deactivate(_struct);
+}
+
+NO_SANITIZE("cfi-icall") bool CefWindowCToCpp::IsActive() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_window_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_active)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_active(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") void CefWindowCToCpp::BringToTop() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_window_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, bring_to_top)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->bring_to_top(_struct);
+}
+
+NO_SANITIZE("cfi-icall") void CefWindowCToCpp::SetAlwaysOnTop(bool on_top) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_window_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_always_on_top)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_always_on_top(_struct, on_top);
+}
+
+NO_SANITIZE("cfi-icall") bool CefWindowCToCpp::IsAlwaysOnTop() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_window_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_always_on_top)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_always_on_top(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") void CefWindowCToCpp::Maximize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_window_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, maximize)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->maximize(_struct);
+}
+
+NO_SANITIZE("cfi-icall") void CefWindowCToCpp::Minimize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_window_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, minimize)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->minimize(_struct);
+}
+
+NO_SANITIZE("cfi-icall") void CefWindowCToCpp::Restore() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_window_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, restore)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->restore(_struct);
+}
+
+NO_SANITIZE("cfi-icall") void CefWindowCToCpp::SetFullscreen(bool fullscreen) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_window_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_fullscreen)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_fullscreen(_struct, fullscreen);
+}
+
+NO_SANITIZE("cfi-icall") bool CefWindowCToCpp::IsMaximized() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_window_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_maximized)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_maximized(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefWindowCToCpp::IsMinimized() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_window_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_minimized)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_minimized(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefWindowCToCpp::IsFullscreen() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_window_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_fullscreen)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_fullscreen(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefWindowCToCpp::SetTitle(const CefString& title) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_window_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_title)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: title
+
+ // Execute
+ _struct->set_title(_struct, title.GetStruct());
+}
+
+NO_SANITIZE("cfi-icall") CefString CefWindowCToCpp::GetTitle() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_window_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_title)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_title(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefWindowCToCpp::SetWindowIcon(CefRefPtr<CefImage> image) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_window_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_window_icon)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: image; type: refptr_same
+ DCHECK(image.get());
+ if (!image.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->set_window_icon(_struct, CefImageCToCpp::Unwrap(image));
+}
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefImage> CefWindowCToCpp::GetWindowIcon() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_window_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_window_icon)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_image_t* _retval = _struct->get_window_icon(_struct);
+
+ // Return type: refptr_same
+ return CefImageCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefWindowCToCpp::SetWindowAppIcon(CefRefPtr<CefImage> image) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_window_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_window_app_icon)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: image; type: refptr_same
+ DCHECK(image.get());
+ if (!image.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->set_window_app_icon(_struct, CefImageCToCpp::Unwrap(image));
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefImage> CefWindowCToCpp::GetWindowAppIcon() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_window_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_window_app_icon)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_image_t* _retval = _struct->get_window_app_icon(_struct);
+
+ // Return type: refptr_same
+ return CefImageCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefOverlayController> CefWindowCToCpp::AddOverlayView(
+ CefRefPtr<CefView> view,
+ cef_docking_mode_t docking_mode) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_window_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, add_overlay_view)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_same
+ DCHECK(view.get());
+ if (!view.get()) {
+ return nullptr;
+ }
+
+ // Execute
+ cef_overlay_controller_t* _retval = _struct->add_overlay_view(
+ _struct, CefViewCToCpp::Unwrap(view), docking_mode);
+
+ // Return type: refptr_same
+ return CefOverlayControllerCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefWindowCToCpp::ShowMenu(CefRefPtr<CefMenuModel> menu_model,
+ const CefPoint& screen_point,
+ cef_menu_anchor_position_t anchor_position) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_window_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, show_menu)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: menu_model; type: refptr_same
+ DCHECK(menu_model.get());
+ if (!menu_model.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->show_menu(_struct, CefMenuModelCToCpp::Unwrap(menu_model),
+ &screen_point, anchor_position);
+}
+
+NO_SANITIZE("cfi-icall") void CefWindowCToCpp::CancelMenu() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_window_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, cancel_menu)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->cancel_menu(_struct);
+}
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefDisplay> CefWindowCToCpp::GetDisplay() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_window_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_display)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_display_t* _retval = _struct->get_display(_struct);
+
+ // Return type: refptr_same
+ return CefDisplayCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRect CefWindowCToCpp::GetClientAreaBoundsInScreen() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_window_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_client_area_bounds_in_screen)) {
+ return CefRect();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_rect_t _retval = _struct->get_client_area_bounds_in_screen(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefWindowCToCpp::SetDraggableRegions(
+ const std::vector<CefDraggableRegion>& regions) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_window_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_draggable_regions)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: regions
+
+ // Translate param: regions; type: simple_vec_byref_const
+ const size_t regionsCount = regions.size();
+ cef_draggable_region_t* regionsList = NULL;
+ if (regionsCount > 0) {
+ regionsList = new cef_draggable_region_t[regionsCount];
+ DCHECK(regionsList);
+ if (regionsList) {
+ for (size_t i = 0; i < regionsCount; ++i) {
+ regionsList[i] = regions[i];
+ }
+ }
+ }
+
+ // Execute
+ _struct->set_draggable_regions(_struct, regionsCount, regionsList);
+
+ // Restore param:regions; type: simple_vec_byref_const
+ if (regionsList) {
+ delete[] regionsList;
+ }
+}
+
+NO_SANITIZE("cfi-icall") CefWindowHandle CefWindowCToCpp::GetWindowHandle() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_window_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_window_handle)) {
+ return kNullWindowHandle;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_window_handle_t _retval = _struct->get_window_handle(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefWindowCToCpp::SendKeyPress(int key_code, uint32 event_flags) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_window_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, send_key_press)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->send_key_press(_struct, key_code, event_flags);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefWindowCToCpp::SendMouseMove(int screen_x, int screen_y) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_window_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, send_mouse_move)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->send_mouse_move(_struct, screen_x, screen_y);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefWindowCToCpp::SendMouseEvents(cef_mouse_button_type_t button,
+ bool mouse_down,
+ bool mouse_up) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_window_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, send_mouse_events)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->send_mouse_events(_struct, button, mouse_down, mouse_up);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefWindowCToCpp::SetAccelerator(int command_id,
+ int key_code,
+ bool shift_pressed,
+ bool ctrl_pressed,
+ bool alt_pressed) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_window_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, set_accelerator)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_accelerator(_struct, command_id, key_code, shift_pressed,
+ ctrl_pressed, alt_pressed);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefWindowCToCpp::RemoveAccelerator(int command_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_window_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, remove_accelerator)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->remove_accelerator(_struct, command_id);
+}
+
+NO_SANITIZE("cfi-icall") void CefWindowCToCpp::RemoveAllAccelerators() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_window_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, remove_all_accelerators)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->remove_all_accelerators(_struct);
+}
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefWindow> CefWindowCToCpp::AsWindow() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_panel_t* _struct = reinterpret_cast<cef_panel_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, as_window)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_window_t* _retval = _struct->as_window(_struct);
+
+ // Return type: refptr_same
+ return CefWindowCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefFillLayout> CefWindowCToCpp::SetToFillLayout() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_panel_t* _struct = reinterpret_cast<cef_panel_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_to_fill_layout)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_fill_layout_t* _retval = _struct->set_to_fill_layout(_struct);
+
+ // Return type: refptr_same
+ return CefFillLayoutCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefBoxLayout> CefWindowCToCpp::SetToBoxLayout(
+ const CefBoxLayoutSettings& settings) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_panel_t* _struct = reinterpret_cast<cef_panel_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_to_box_layout)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_box_layout_t* _retval = _struct->set_to_box_layout(_struct, &settings);
+
+ // Return type: refptr_same
+ return CefBoxLayoutCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefLayout> CefWindowCToCpp::GetLayout() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_panel_t* _struct = reinterpret_cast<cef_panel_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_layout)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_layout_t* _retval = _struct->get_layout(_struct);
+
+ // Return type: refptr_same
+ return CefLayoutCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") void CefWindowCToCpp::Layout() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_panel_t* _struct = reinterpret_cast<cef_panel_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, layout)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->layout(_struct);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefWindowCToCpp::AddChildView(CefRefPtr<CefView> view) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_panel_t* _struct = reinterpret_cast<cef_panel_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, add_child_view)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_same
+ DCHECK(view.get());
+ if (!view.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->add_child_view(_struct, CefViewCToCpp::Unwrap(view));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefWindowCToCpp::AddChildViewAt(CefRefPtr<CefView> view, int index) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_panel_t* _struct = reinterpret_cast<cef_panel_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, add_child_view_at)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_same
+ DCHECK(view.get());
+ if (!view.get()) {
+ return;
+ }
+ // Verify param: index; type: simple_byval
+ DCHECK_GE(index, 0);
+ if (index < 0) {
+ return;
+ }
+
+ // Execute
+ _struct->add_child_view_at(_struct, CefViewCToCpp::Unwrap(view), index);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefWindowCToCpp::ReorderChildView(CefRefPtr<CefView> view, int index) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_panel_t* _struct = reinterpret_cast<cef_panel_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, reorder_child_view)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_same
+ DCHECK(view.get());
+ if (!view.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->reorder_child_view(_struct, CefViewCToCpp::Unwrap(view), index);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefWindowCToCpp::RemoveChildView(CefRefPtr<CefView> view) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_panel_t* _struct = reinterpret_cast<cef_panel_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, remove_child_view)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_same
+ DCHECK(view.get());
+ if (!view.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->remove_child_view(_struct, CefViewCToCpp::Unwrap(view));
+}
+
+NO_SANITIZE("cfi-icall") void CefWindowCToCpp::RemoveAllChildViews() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_panel_t* _struct = reinterpret_cast<cef_panel_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, remove_all_child_views)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->remove_all_child_views(_struct);
+}
+
+NO_SANITIZE("cfi-icall") size_t CefWindowCToCpp::GetChildViewCount() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_panel_t* _struct = reinterpret_cast<cef_panel_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_child_view_count)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ size_t _retval = _struct->get_child_view_count(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefView> CefWindowCToCpp::GetChildViewAt(int index) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_panel_t* _struct = reinterpret_cast<cef_panel_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_child_view_at)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: index; type: simple_byval
+ DCHECK_GE(index, 0);
+ if (index < 0) {
+ return nullptr;
+ }
+
+ // Execute
+ cef_view_t* _retval = _struct->get_child_view_at(_struct, index);
+
+ // Return type: refptr_same
+ return CefViewCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefBrowserView> CefWindowCToCpp::AsBrowserView() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, as_browser_view)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_browser_view_t* _retval = _struct->as_browser_view(_struct);
+
+ // Return type: refptr_same
+ return CefBrowserViewCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefButton> CefWindowCToCpp::AsButton() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, as_button)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_button_t* _retval = _struct->as_button(_struct);
+
+ // Return type: refptr_same
+ return CefButtonCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefPanel> CefWindowCToCpp::AsPanel() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, as_panel)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_panel_t* _retval = _struct->as_panel(_struct);
+
+ // Return type: refptr_same
+ return CefPanelCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefScrollView> CefWindowCToCpp::AsScrollView() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, as_scroll_view)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_scroll_view_t* _retval = _struct->as_scroll_view(_struct);
+
+ // Return type: refptr_same
+ return CefScrollViewCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefTextfield> CefWindowCToCpp::AsTextfield() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, as_textfield)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_textfield_t* _retval = _struct->as_textfield(_struct);
+
+ // Return type: refptr_same
+ return CefTextfieldCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") CefString CefWindowCToCpp::GetTypeString() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_type_string)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_type_string(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+CefString CefWindowCToCpp::ToString(bool include_children) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, to_string)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->to_string(_struct, include_children);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") bool CefWindowCToCpp::IsValid() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_valid)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_valid(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefWindowCToCpp::IsAttached() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_attached)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_attached(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefWindowCToCpp::IsSame(CefRefPtr<CefView> that) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_same)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: that; type: refptr_same
+ DCHECK(that.get());
+ if (!that.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->is_same(_struct, CefViewCToCpp::Unwrap(that));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefViewDelegate> CefWindowCToCpp::GetDelegate() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_delegate)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_view_delegate_t* _retval = _struct->get_delegate(_struct);
+
+ // Return type: refptr_diff
+ return CefViewDelegateCppToC::Unwrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefWindow> CefWindowCToCpp::GetWindow() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_window)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_window_t* _retval = _struct->get_window(_struct);
+
+ // Return type: refptr_same
+ return CefWindowCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") int CefWindowCToCpp::GetID() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_id)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_id(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") void CefWindowCToCpp::SetID(int id) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_id)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_id(_struct, id);
+}
+
+NO_SANITIZE("cfi-icall") int CefWindowCToCpp::GetGroupID() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_group_id)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_group_id(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") void CefWindowCToCpp::SetGroupID(int group_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_group_id)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_group_id(_struct, group_id);
+}
+
+NO_SANITIZE("cfi-icall") CefRefPtr<CefView> CefWindowCToCpp::GetParentView() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_parent_view)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_view_t* _retval = _struct->get_parent_view(_struct);
+
+ // Return type: refptr_same
+ return CefViewCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefView> CefWindowCToCpp::GetViewForID(int id) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_view_for_id)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_view_t* _retval = _struct->get_view_for_id(_struct, id);
+
+ // Return type: refptr_same
+ return CefViewCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefWindowCToCpp::SetBounds(const CefRect& bounds) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_bounds)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_bounds(_struct, &bounds);
+}
+
+NO_SANITIZE("cfi-icall") CefRect CefWindowCToCpp::GetBounds() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_bounds)) {
+ return CefRect();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_rect_t _retval = _struct->get_bounds(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") CefRect CefWindowCToCpp::GetBoundsInScreen() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_bounds_in_screen)) {
+ return CefRect();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_rect_t _retval = _struct->get_bounds_in_screen(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") void CefWindowCToCpp::SetSize(const CefSize& size) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_size)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_size(_struct, &size);
+}
+
+NO_SANITIZE("cfi-icall") CefSize CefWindowCToCpp::GetSize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_size_t _retval = _struct->get_size(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefWindowCToCpp::SetPosition(const CefPoint& position) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_position)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_position(_struct, &position);
+}
+
+NO_SANITIZE("cfi-icall") CefPoint CefWindowCToCpp::GetPosition() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_position)) {
+ return CefPoint();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_point_t _retval = _struct->get_position(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefWindowCToCpp::SetInsets(const CefInsets& insets) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_insets)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_insets(_struct, &insets);
+}
+
+NO_SANITIZE("cfi-icall") CefInsets CefWindowCToCpp::GetInsets() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_insets)) {
+ return CefInsets();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_insets_t _retval = _struct->get_insets(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") CefSize CefWindowCToCpp::GetPreferredSize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_preferred_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_size_t _retval = _struct->get_preferred_size(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") void CefWindowCToCpp::SizeToPreferredSize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, size_to_preferred_size)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->size_to_preferred_size(_struct);
+}
+
+NO_SANITIZE("cfi-icall") CefSize CefWindowCToCpp::GetMinimumSize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_minimum_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_size_t _retval = _struct->get_minimum_size(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") CefSize CefWindowCToCpp::GetMaximumSize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_maximum_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_size_t _retval = _struct->get_maximum_size(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") int CefWindowCToCpp::GetHeightForWidth(int width) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_height_for_width)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_height_for_width(_struct, width);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") void CefWindowCToCpp::InvalidateLayout() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, invalidate_layout)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->invalidate_layout(_struct);
+}
+
+NO_SANITIZE("cfi-icall") void CefWindowCToCpp::SetVisible(bool visible) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_visible)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_visible(_struct, visible);
+}
+
+NO_SANITIZE("cfi-icall") bool CefWindowCToCpp::IsVisible() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_visible)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_visible(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefWindowCToCpp::IsDrawn() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_drawn)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_drawn(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") void CefWindowCToCpp::SetEnabled(bool enabled) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_enabled)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_enabled(_struct, enabled);
+}
+
+NO_SANITIZE("cfi-icall") bool CefWindowCToCpp::IsEnabled() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_enabled)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_enabled(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") void CefWindowCToCpp::SetFocusable(bool focusable) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_focusable)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_focusable(_struct, focusable);
+}
+
+NO_SANITIZE("cfi-icall") bool CefWindowCToCpp::IsFocusable() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_focusable)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_focusable(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefWindowCToCpp::IsAccessibilityFocusable() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, is_accessibility_focusable)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_accessibility_focusable(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") void CefWindowCToCpp::RequestFocus() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, request_focus)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->request_focus(_struct);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefWindowCToCpp::SetBackgroundColor(cef_color_t color) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, set_background_color)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->set_background_color(_struct, color);
+}
+
+NO_SANITIZE("cfi-icall") cef_color_t CefWindowCToCpp::GetBackgroundColor() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_background_color)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_color_t _retval = _struct->get_background_color(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefWindowCToCpp::ConvertPointToScreen(CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, convert_point_to_screen)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->convert_point_to_screen(_struct, &point);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefWindowCToCpp::ConvertPointFromScreen(CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, convert_point_from_screen)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->convert_point_from_screen(_struct, &point);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefWindowCToCpp::ConvertPointToWindow(CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, convert_point_to_window)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->convert_point_to_window(_struct, &point);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefWindowCToCpp::ConvertPointFromWindow(CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, convert_point_from_window)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->convert_point_from_window(_struct, &point);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefWindowCToCpp::ConvertPointToView(CefRefPtr<CefView> view,
+ CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, convert_point_to_view)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_same
+ DCHECK(view.get());
+ if (!view.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->convert_point_to_view(
+ _struct, CefViewCToCpp::Unwrap(view), &point);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefWindowCToCpp::ConvertPointFromView(CefRefPtr<CefView> view,
+ CefPoint& point) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, convert_point_from_view)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_same
+ DCHECK(view.get());
+ if (!view.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->convert_point_from_view(
+ _struct, CefViewCToCpp::Unwrap(view), &point);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefWindowCToCpp::CefWindowCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefWindowCToCpp::~CefWindowCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_window_t*
+CefCToCppRefCounted<CefWindowCToCpp, CefWindow, cef_window_t>::UnwrapDerived(
+ CefWrapperType type,
+ CefWindow* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefWindowCToCpp, CefWindow, cef_window_t>::
+ kWrapperType = WT_WINDOW;
diff --git a/libcef_dll/ctocpp/views/window_ctocpp.h b/libcef_dll/ctocpp/views/window_ctocpp.h
new file mode 100644
index 00000000..58fd19e3
--- /dev/null
+++ b/libcef_dll/ctocpp/views/window_ctocpp.h
@@ -0,0 +1,154 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=a16d73107ffbbcdb06153c0bfcc5e4ac43bbadb0$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_VIEWS_WINDOW_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_VIEWS_WINDOW_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include <vector>
+#include "include/capi/views/cef_window_capi.h"
+#include "include/views/cef_window.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefWindowCToCpp
+ : public CefCToCppRefCounted<CefWindowCToCpp, CefWindow, cef_window_t> {
+ public:
+ CefWindowCToCpp();
+ virtual ~CefWindowCToCpp();
+
+ // CefWindow methods.
+ void Show() override;
+ void Hide() override;
+ void CenterWindow(const CefSize& size) override;
+ void Close() override;
+ bool IsClosed() override;
+ void Activate() override;
+ void Deactivate() override;
+ bool IsActive() override;
+ void BringToTop() override;
+ void SetAlwaysOnTop(bool on_top) override;
+ bool IsAlwaysOnTop() override;
+ void Maximize() override;
+ void Minimize() override;
+ void Restore() override;
+ void SetFullscreen(bool fullscreen) override;
+ bool IsMaximized() override;
+ bool IsMinimized() override;
+ bool IsFullscreen() override;
+ void SetTitle(const CefString& title) override;
+ CefString GetTitle() override;
+ void SetWindowIcon(CefRefPtr<CefImage> image) override;
+ CefRefPtr<CefImage> GetWindowIcon() override;
+ void SetWindowAppIcon(CefRefPtr<CefImage> image) override;
+ CefRefPtr<CefImage> GetWindowAppIcon() override;
+ CefRefPtr<CefOverlayController> AddOverlayView(
+ CefRefPtr<CefView> view,
+ cef_docking_mode_t docking_mode) override;
+ void ShowMenu(CefRefPtr<CefMenuModel> menu_model,
+ const CefPoint& screen_point,
+ cef_menu_anchor_position_t anchor_position) override;
+ void CancelMenu() override;
+ CefRefPtr<CefDisplay> GetDisplay() override;
+ CefRect GetClientAreaBoundsInScreen() override;
+ void SetDraggableRegions(
+ const std::vector<CefDraggableRegion>& regions) override;
+ CefWindowHandle GetWindowHandle() override;
+ void SendKeyPress(int key_code, uint32 event_flags) override;
+ void SendMouseMove(int screen_x, int screen_y) override;
+ void SendMouseEvents(cef_mouse_button_type_t button,
+ bool mouse_down,
+ bool mouse_up) override;
+ void SetAccelerator(int command_id,
+ int key_code,
+ bool shift_pressed,
+ bool ctrl_pressed,
+ bool alt_pressed) override;
+ void RemoveAccelerator(int command_id) override;
+ void RemoveAllAccelerators() override;
+
+ // CefPanel methods.
+ CefRefPtr<CefWindow> AsWindow() override;
+ CefRefPtr<CefFillLayout> SetToFillLayout() override;
+ CefRefPtr<CefBoxLayout> SetToBoxLayout(
+ const CefBoxLayoutSettings& settings) override;
+ CefRefPtr<CefLayout> GetLayout() override;
+ void Layout() override;
+ void AddChildView(CefRefPtr<CefView> view) override;
+ void AddChildViewAt(CefRefPtr<CefView> view, int index) override;
+ void ReorderChildView(CefRefPtr<CefView> view, int index) override;
+ void RemoveChildView(CefRefPtr<CefView> view) override;
+ void RemoveAllChildViews() override;
+ size_t GetChildViewCount() override;
+ CefRefPtr<CefView> GetChildViewAt(int index) override;
+
+ // CefView methods.
+ CefRefPtr<CefBrowserView> AsBrowserView() override;
+ CefRefPtr<CefButton> AsButton() override;
+ CefRefPtr<CefPanel> AsPanel() override;
+ CefRefPtr<CefScrollView> AsScrollView() override;
+ CefRefPtr<CefTextfield> AsTextfield() override;
+ CefString GetTypeString() override;
+ CefString ToString(bool include_children) override;
+ bool IsValid() override;
+ bool IsAttached() override;
+ bool IsSame(CefRefPtr<CefView> that) override;
+ CefRefPtr<CefViewDelegate> GetDelegate() override;
+ CefRefPtr<CefWindow> GetWindow() override;
+ int GetID() override;
+ void SetID(int id) override;
+ int GetGroupID() override;
+ void SetGroupID(int group_id) override;
+ CefRefPtr<CefView> GetParentView() override;
+ CefRefPtr<CefView> GetViewForID(int id) override;
+ void SetBounds(const CefRect& bounds) override;
+ CefRect GetBounds() override;
+ CefRect GetBoundsInScreen() override;
+ void SetSize(const CefSize& size) override;
+ CefSize GetSize() override;
+ void SetPosition(const CefPoint& position) override;
+ CefPoint GetPosition() override;
+ void SetInsets(const CefInsets& insets) override;
+ CefInsets GetInsets() override;
+ CefSize GetPreferredSize() override;
+ void SizeToPreferredSize() override;
+ CefSize GetMinimumSize() override;
+ CefSize GetMaximumSize() override;
+ int GetHeightForWidth(int width) override;
+ void InvalidateLayout() override;
+ void SetVisible(bool visible) override;
+ bool IsVisible() override;
+ bool IsDrawn() override;
+ void SetEnabled(bool enabled) override;
+ bool IsEnabled() override;
+ void SetFocusable(bool focusable) override;
+ bool IsFocusable() override;
+ bool IsAccessibilityFocusable() override;
+ void RequestFocus() override;
+ void SetBackgroundColor(cef_color_t color) override;
+ cef_color_t GetBackgroundColor() override;
+ bool ConvertPointToScreen(CefPoint& point) override;
+ bool ConvertPointFromScreen(CefPoint& point) override;
+ bool ConvertPointToWindow(CefPoint& point) override;
+ bool ConvertPointFromWindow(CefPoint& point) override;
+ bool ConvertPointToView(CefRefPtr<CefView> view, CefPoint& point) override;
+ bool ConvertPointFromView(CefRefPtr<CefView> view, CefPoint& point) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_VIEWS_WINDOW_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/views/window_delegate_ctocpp.cc b/libcef_dll/ctocpp/views/window_delegate_ctocpp.cc
new file mode 100644
index 00000000..206d9532
--- /dev/null
+++ b/libcef_dll/ctocpp/views/window_delegate_ctocpp.cc
@@ -0,0 +1,744 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=40aea12873a3c8803c9d2d6c06a0270197ead58e$
+//
+
+#include "libcef_dll/ctocpp/views/window_delegate_ctocpp.h"
+#include "libcef_dll/cpptoc/views/view_cpptoc.h"
+#include "libcef_dll/cpptoc/views/window_cpptoc.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+void CefWindowDelegateCToCpp::OnWindowCreated(CefRefPtr<CefWindow> window) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_window_delegate_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_window_created)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: window; type: refptr_diff
+ DCHECK(window.get());
+ if (!window.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_window_created(_struct, CefWindowCppToC::Wrap(window));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefWindowDelegateCToCpp::OnWindowClosing(CefRefPtr<CefWindow> window) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_window_delegate_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_window_closing)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: window; type: refptr_diff
+ DCHECK(window.get());
+ if (!window.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_window_closing(_struct, CefWindowCppToC::Wrap(window));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefWindowDelegateCToCpp::OnWindowDestroyed(CefRefPtr<CefWindow> window) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_window_delegate_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_window_destroyed)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: window; type: refptr_diff
+ DCHECK(window.get());
+ if (!window.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_window_destroyed(_struct, CefWindowCppToC::Wrap(window));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefWindowDelegateCToCpp::OnWindowActivationChanged(
+ CefRefPtr<CefWindow> window,
+ bool active) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_window_delegate_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_window_activation_changed)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: window; type: refptr_diff
+ DCHECK(window.get());
+ if (!window.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_window_activation_changed(_struct, CefWindowCppToC::Wrap(window),
+ active);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefWindowDelegateCToCpp::OnWindowBoundsChanged(CefRefPtr<CefWindow> window,
+ const CefRect& new_bounds) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_window_delegate_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_window_bounds_changed)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: window; type: refptr_diff
+ DCHECK(window.get());
+ if (!window.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_window_bounds_changed(_struct, CefWindowCppToC::Wrap(window),
+ &new_bounds);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefWindow> CefWindowDelegateCToCpp::GetParentWindow(
+ CefRefPtr<CefWindow> window,
+ bool* is_menu,
+ bool* can_activate_menu) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_window_delegate_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_parent_window)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: window; type: refptr_diff
+ DCHECK(window.get());
+ if (!window.get()) {
+ return nullptr;
+ }
+ // Verify param: is_menu; type: bool_byaddr
+ DCHECK(is_menu);
+ if (!is_menu) {
+ return nullptr;
+ }
+ // Verify param: can_activate_menu; type: bool_byaddr
+ DCHECK(can_activate_menu);
+ if (!can_activate_menu) {
+ return nullptr;
+ }
+
+ // Translate param: is_menu; type: bool_byaddr
+ int is_menuInt = is_menu ? *is_menu : 0;
+ // Translate param: can_activate_menu; type: bool_byaddr
+ int can_activate_menuInt = can_activate_menu ? *can_activate_menu : 0;
+
+ // Execute
+ cef_window_t* _retval =
+ _struct->get_parent_window(_struct, CefWindowCppToC::Wrap(window),
+ &is_menuInt, &can_activate_menuInt);
+
+ // Restore param:is_menu; type: bool_byaddr
+ if (is_menu) {
+ *is_menu = is_menuInt ? true : false;
+ }
+ // Restore param:can_activate_menu; type: bool_byaddr
+ if (can_activate_menu) {
+ *can_activate_menu = can_activate_menuInt ? true : false;
+ }
+
+ // Return type: refptr_diff
+ return CefWindowCppToC::Unwrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRect CefWindowDelegateCToCpp::GetInitialBounds(CefRefPtr<CefWindow> window) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_window_delegate_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_initial_bounds)) {
+ return CefRect();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: window; type: refptr_diff
+ DCHECK(window.get());
+ if (!window.get()) {
+ return CefRect();
+ }
+
+ // Execute
+ cef_rect_t _retval =
+ _struct->get_initial_bounds(_struct, CefWindowCppToC::Wrap(window));
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+cef_show_state_t CefWindowDelegateCToCpp::GetInitialShowState(
+ CefRefPtr<CefWindow> window) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_window_delegate_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_initial_show_state)) {
+ return CEF_SHOW_STATE_NORMAL;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: window; type: refptr_diff
+ DCHECK(window.get());
+ if (!window.get()) {
+ return CEF_SHOW_STATE_NORMAL;
+ }
+
+ // Execute
+ cef_show_state_t _retval =
+ _struct->get_initial_show_state(_struct, CefWindowCppToC::Wrap(window));
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefWindowDelegateCToCpp::IsFrameless(CefRefPtr<CefWindow> window) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_window_delegate_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_frameless)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: window; type: refptr_diff
+ DCHECK(window.get());
+ if (!window.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->is_frameless(_struct, CefWindowCppToC::Wrap(window));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefWindowDelegateCToCpp::WithStandardWindowButtons(
+ CefRefPtr<CefWindow> window) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_window_delegate_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, with_standard_window_buttons)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: window; type: refptr_diff
+ DCHECK(window.get());
+ if (!window.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->with_standard_window_buttons(
+ _struct, CefWindowCppToC::Wrap(window));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefWindowDelegateCToCpp::GetTitlebarHeight(CefRefPtr<CefWindow> window,
+ float* titlebar_height) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_window_delegate_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_titlebar_height)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: window; type: refptr_diff
+ DCHECK(window.get());
+ if (!window.get()) {
+ return false;
+ }
+ // Verify param: titlebar_height; type: simple_byaddr
+ DCHECK(titlebar_height);
+ if (!titlebar_height) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->get_titlebar_height(
+ _struct, CefWindowCppToC::Wrap(window), titlebar_height);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefWindowDelegateCToCpp::CanResize(CefRefPtr<CefWindow> window) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_window_delegate_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, can_resize)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: window; type: refptr_diff
+ DCHECK(window.get());
+ if (!window.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->can_resize(_struct, CefWindowCppToC::Wrap(window));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefWindowDelegateCToCpp::CanMaximize(CefRefPtr<CefWindow> window) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_window_delegate_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, can_maximize)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: window; type: refptr_diff
+ DCHECK(window.get());
+ if (!window.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->can_maximize(_struct, CefWindowCppToC::Wrap(window));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefWindowDelegateCToCpp::CanMinimize(CefRefPtr<CefWindow> window) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_window_delegate_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, can_minimize)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: window; type: refptr_diff
+ DCHECK(window.get());
+ if (!window.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->can_minimize(_struct, CefWindowCppToC::Wrap(window));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefWindowDelegateCToCpp::CanClose(CefRefPtr<CefWindow> window) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_window_delegate_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, can_close)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: window; type: refptr_diff
+ DCHECK(window.get());
+ if (!window.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->can_close(_struct, CefWindowCppToC::Wrap(window));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefWindowDelegateCToCpp::OnAccelerator(CefRefPtr<CefWindow> window,
+ int command_id) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_window_delegate_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_accelerator)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: window; type: refptr_diff
+ DCHECK(window.get());
+ if (!window.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->on_accelerator(_struct, CefWindowCppToC::Wrap(window),
+ command_id);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefWindowDelegateCToCpp::OnKeyEvent(CefRefPtr<CefWindow> window,
+ const CefKeyEvent& event) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_window_delegate_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, on_key_event)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: window; type: refptr_diff
+ DCHECK(window.get());
+ if (!window.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval =
+ _struct->on_key_event(_struct, CefWindowCppToC::Wrap(window), &event);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CefSize CefWindowDelegateCToCpp::GetPreferredSize(CefRefPtr<CefView> view) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_preferred_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval =
+ _struct->get_preferred_size(_struct, CefViewCppToC::Wrap(view));
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CefSize CefWindowDelegateCToCpp::GetMinimumSize(CefRefPtr<CefView> view) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_minimum_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval =
+ _struct->get_minimum_size(_struct, CefViewCppToC::Wrap(view));
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CefSize CefWindowDelegateCToCpp::GetMaximumSize(CefRefPtr<CefView> view) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_maximum_size)) {
+ return CefSize();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return CefSize();
+ }
+
+ // Execute
+ cef_size_t _retval =
+ _struct->get_maximum_size(_struct, CefViewCppToC::Wrap(view));
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+int CefWindowDelegateCToCpp::GetHeightForWidth(CefRefPtr<CefView> view,
+ int width) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, get_height_for_width)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return 0;
+ }
+
+ // Execute
+ int _retval =
+ _struct->get_height_for_width(_struct, CefViewCppToC::Wrap(view), width);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefWindowDelegateCToCpp::OnParentViewChanged(CefRefPtr<CefView> view,
+ bool added,
+ CefRefPtr<CefView> parent) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, on_parent_view_changed)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return;
+ }
+ // Verify param: parent; type: refptr_diff
+ DCHECK(parent.get());
+ if (!parent.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_parent_view_changed(_struct, CefViewCppToC::Wrap(view), added,
+ CefViewCppToC::Wrap(parent));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefWindowDelegateCToCpp::OnChildViewChanged(CefRefPtr<CefView> view,
+ bool added,
+ CefRefPtr<CefView> child) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, on_child_view_changed)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return;
+ }
+ // Verify param: child; type: refptr_diff
+ DCHECK(child.get());
+ if (!child.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_child_view_changed(_struct, CefViewCppToC::Wrap(view), added,
+ CefViewCppToC::Wrap(child));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefWindowDelegateCToCpp::OnWindowChanged(CefRefPtr<CefView> view,
+ bool added) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, on_window_changed)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_window_changed(_struct, CefViewCppToC::Wrap(view), added);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefWindowDelegateCToCpp::OnLayoutChanged(CefRefPtr<CefView> view,
+ const CefRect& new_bounds) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, on_layout_changed)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_layout_changed(_struct, CefViewCppToC::Wrap(view), &new_bounds);
+}
+
+NO_SANITIZE("cfi-icall")
+void CefWindowDelegateCToCpp::OnFocus(CefRefPtr<CefView> view) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, on_focus)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_focus(_struct, CefViewCppToC::Wrap(view));
+}
+
+NO_SANITIZE("cfi-icall")
+void CefWindowDelegateCToCpp::OnBlur(CefRefPtr<CefView> view) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_view_delegate_t* _struct =
+ reinterpret_cast<cef_view_delegate_t*>(GetStruct());
+ if (CEF_MEMBER_MISSING(_struct, on_blur)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: view; type: refptr_diff
+ DCHECK(view.get());
+ if (!view.get()) {
+ return;
+ }
+
+ // Execute
+ _struct->on_blur(_struct, CefViewCppToC::Wrap(view));
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefWindowDelegateCToCpp::CefWindowDelegateCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefWindowDelegateCToCpp::~CefWindowDelegateCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_window_delegate_t* CefCToCppRefCounted<
+ CefWindowDelegateCToCpp,
+ CefWindowDelegate,
+ cef_window_delegate_t>::UnwrapDerived(CefWrapperType type,
+ CefWindowDelegate* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefWindowDelegateCToCpp,
+ CefWindowDelegate,
+ cef_window_delegate_t>::kWrapperType =
+ WT_WINDOW_DELEGATE;
diff --git a/libcef_dll/ctocpp/views/window_delegate_ctocpp.h b/libcef_dll/ctocpp/views/window_delegate_ctocpp.h
new file mode 100644
index 00000000..def8dd49
--- /dev/null
+++ b/libcef_dll/ctocpp/views/window_delegate_ctocpp.h
@@ -0,0 +1,84 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=d100d8866a7eab2a163d4ddb3cacd00141f65757$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_VIEWS_WINDOW_DELEGATE_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_VIEWS_WINDOW_DELEGATE_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/views/cef_window_capi.h"
+#include "include/capi/views/cef_window_delegate_capi.h"
+#include "include/views/cef_window.h"
+#include "include/views/cef_window_delegate.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefWindowDelegateCToCpp
+ : public CefCToCppRefCounted<CefWindowDelegateCToCpp,
+ CefWindowDelegate,
+ cef_window_delegate_t> {
+ public:
+ CefWindowDelegateCToCpp();
+ virtual ~CefWindowDelegateCToCpp();
+
+ // CefWindowDelegate methods.
+ void OnWindowCreated(CefRefPtr<CefWindow> window) override;
+ void OnWindowClosing(CefRefPtr<CefWindow> window) override;
+ void OnWindowDestroyed(CefRefPtr<CefWindow> window) override;
+ void OnWindowActivationChanged(CefRefPtr<CefWindow> window,
+ bool active) override;
+ void OnWindowBoundsChanged(CefRefPtr<CefWindow> window,
+ const CefRect& new_bounds) override;
+ CefRefPtr<CefWindow> GetParentWindow(CefRefPtr<CefWindow> window,
+ bool* is_menu,
+ bool* can_activate_menu) override;
+ CefRect GetInitialBounds(CefRefPtr<CefWindow> window) override;
+ cef_show_state_t GetInitialShowState(CefRefPtr<CefWindow> window) override;
+ bool IsFrameless(CefRefPtr<CefWindow> window) override;
+ bool WithStandardWindowButtons(CefRefPtr<CefWindow> window) override;
+ bool GetTitlebarHeight(CefRefPtr<CefWindow> window,
+ float* titlebar_height) override;
+ bool CanResize(CefRefPtr<CefWindow> window) override;
+ bool CanMaximize(CefRefPtr<CefWindow> window) override;
+ bool CanMinimize(CefRefPtr<CefWindow> window) override;
+ bool CanClose(CefRefPtr<CefWindow> window) override;
+ bool OnAccelerator(CefRefPtr<CefWindow> window, int command_id) override;
+ bool OnKeyEvent(CefRefPtr<CefWindow> window,
+ const CefKeyEvent& event) override;
+
+ // CefPanelDelegate methods.
+
+ // CefViewDelegate methods.
+ CefSize GetPreferredSize(CefRefPtr<CefView> view) override;
+ CefSize GetMinimumSize(CefRefPtr<CefView> view) override;
+ CefSize GetMaximumSize(CefRefPtr<CefView> view) override;
+ int GetHeightForWidth(CefRefPtr<CefView> view, int width) override;
+ void OnParentViewChanged(CefRefPtr<CefView> view,
+ bool added,
+ CefRefPtr<CefView> parent) override;
+ void OnChildViewChanged(CefRefPtr<CefView> view,
+ bool added,
+ CefRefPtr<CefView> child) override;
+ void OnWindowChanged(CefRefPtr<CefView> view, bool added) override;
+ void OnLayoutChanged(CefRefPtr<CefView> view,
+ const CefRect& new_bounds) override;
+ void OnFocus(CefRefPtr<CefView> view) override;
+ void OnBlur(CefRefPtr<CefView> view) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_VIEWS_WINDOW_DELEGATE_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/waitable_event_ctocpp.cc b/libcef_dll/ctocpp/waitable_event_ctocpp.cc
new file mode 100644
index 00000000..eeb5fcd5
--- /dev/null
+++ b/libcef_dll/ctocpp/waitable_event_ctocpp.cc
@@ -0,0 +1,138 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=185ce5e8dabe003ad884d6ad9dca1947c9c6e27a$
+//
+
+#include "libcef_dll/ctocpp/waitable_event_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// STATIC METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefWaitableEvent> CefWaitableEvent::CreateWaitableEvent(
+ bool automatic_reset,
+ bool initially_signaled) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_waitable_event_t* _retval =
+ cef_waitable_event_create(automatic_reset, initially_signaled);
+
+ // Return type: refptr_same
+ return CefWaitableEventCToCpp::Wrap(_retval);
+}
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") void CefWaitableEventCToCpp::Reset() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_waitable_event_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, reset)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->reset(_struct);
+}
+
+NO_SANITIZE("cfi-icall") void CefWaitableEventCToCpp::Signal() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_waitable_event_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, signal)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->signal(_struct);
+}
+
+NO_SANITIZE("cfi-icall") bool CefWaitableEventCToCpp::IsSignaled() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_waitable_event_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_signaled)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_signaled(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") void CefWaitableEventCToCpp::Wait() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_waitable_event_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, wait)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ _struct->wait(_struct);
+}
+
+NO_SANITIZE("cfi-icall") bool CefWaitableEventCToCpp::TimedWait(int64 max_ms) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_waitable_event_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, timed_wait)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->timed_wait(_struct, max_ms);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefWaitableEventCToCpp::CefWaitableEventCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefWaitableEventCToCpp::~CefWaitableEventCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_waitable_event_t*
+CefCToCppRefCounted<CefWaitableEventCToCpp,
+ CefWaitableEvent,
+ cef_waitable_event_t>::UnwrapDerived(CefWrapperType type,
+ CefWaitableEvent* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefWaitableEventCToCpp,
+ CefWaitableEvent,
+ cef_waitable_event_t>::kWrapperType =
+ WT_WAITABLE_EVENT;
diff --git a/libcef_dll/ctocpp/waitable_event_ctocpp.h b/libcef_dll/ctocpp/waitable_event_ctocpp.h
new file mode 100644
index 00000000..7cd6e03c
--- /dev/null
+++ b/libcef_dll/ctocpp/waitable_event_ctocpp.h
@@ -0,0 +1,45 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=ea92b8c5871694e9c32c29a5d554774afe7aa3dd$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_WAITABLE_EVENT_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_WAITABLE_EVENT_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_waitable_event_capi.h"
+#include "include/cef_waitable_event.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefWaitableEventCToCpp
+ : public CefCToCppRefCounted<CefWaitableEventCToCpp,
+ CefWaitableEvent,
+ cef_waitable_event_t> {
+ public:
+ CefWaitableEventCToCpp();
+ virtual ~CefWaitableEventCToCpp();
+
+ // CefWaitableEvent methods.
+ void Reset() override;
+ void Signal() override;
+ bool IsSignaled() override;
+ void Wait() override;
+ bool TimedWait(int64 max_ms) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_WAITABLE_EVENT_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/write_handler_ctocpp.cc b/libcef_dll/ctocpp/write_handler_ctocpp.cc
new file mode 100644
index 00000000..a6d707a3
--- /dev/null
+++ b/libcef_dll/ctocpp/write_handler_ctocpp.cc
@@ -0,0 +1,137 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=4bbe58d52a3098f3bc77f202fe28f914c15b26e1$
+//
+
+#include "libcef_dll/ctocpp/write_handler_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+size_t CefWriteHandlerCToCpp::Write(const void* ptr, size_t size, size_t n) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_write_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, write)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: ptr; type: simple_byaddr
+ DCHECK(ptr);
+ if (!ptr) {
+ return 0;
+ }
+
+ // Execute
+ size_t _retval = _struct->write(_struct, ptr, size, n);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+int CefWriteHandlerCToCpp::Seek(int64 offset, int whence) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_write_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, seek)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->seek(_struct, offset, whence);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") int64 CefWriteHandlerCToCpp::Tell() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_write_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, tell)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int64 _retval = _struct->tell(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") int CefWriteHandlerCToCpp::Flush() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_write_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, flush)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->flush(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") bool CefWriteHandlerCToCpp::MayBlock() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_write_handler_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, may_block)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->may_block(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefWriteHandlerCToCpp::CefWriteHandlerCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefWriteHandlerCToCpp::~CefWriteHandlerCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_write_handler_t*
+CefCToCppRefCounted<CefWriteHandlerCToCpp,
+ CefWriteHandler,
+ cef_write_handler_t>::UnwrapDerived(CefWrapperType type,
+ CefWriteHandler* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefWriteHandlerCToCpp,
+ CefWriteHandler,
+ cef_write_handler_t>::kWrapperType =
+ WT_WRITE_HANDLER;
diff --git a/libcef_dll/ctocpp/write_handler_ctocpp.h b/libcef_dll/ctocpp/write_handler_ctocpp.h
new file mode 100644
index 00000000..8d959831
--- /dev/null
+++ b/libcef_dll/ctocpp/write_handler_ctocpp.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=56728a12a3e14ab71d1dee991a7912d5d3c111f6$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_WRITE_HANDLER_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_WRITE_HANDLER_CTOCPP_H_
+#pragma once
+
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+
+#include "include/capi/cef_stream_capi.h"
+#include "include/cef_stream.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed DLL-side only.
+class CefWriteHandlerCToCpp : public CefCToCppRefCounted<CefWriteHandlerCToCpp,
+ CefWriteHandler,
+ cef_write_handler_t> {
+ public:
+ CefWriteHandlerCToCpp();
+ virtual ~CefWriteHandlerCToCpp();
+
+ // CefWriteHandler methods.
+ size_t Write(const void* ptr, size_t size, size_t n) override;
+ int Seek(int64 offset, int whence) override;
+ int64 Tell() override;
+ int Flush() override;
+ bool MayBlock() override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_WRITE_HANDLER_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/x509cert_principal_ctocpp.cc b/libcef_dll/ctocpp/x509cert_principal_ctocpp.cc
new file mode 100644
index 00000000..7fcdd812
--- /dev/null
+++ b/libcef_dll/ctocpp/x509cert_principal_ctocpp.cc
@@ -0,0 +1,264 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=b1619ca8f166708708f74e0734efde3516546f9a$
+//
+
+#include "libcef_dll/ctocpp/x509cert_principal_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+#include "libcef_dll/transfer_util.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefString CefX509CertPrincipalCToCpp::GetDisplayName() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_x509cert_principal_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_display_name)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_display_name(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") CefString CefX509CertPrincipalCToCpp::GetCommonName() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_x509cert_principal_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_common_name)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_common_name(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+CefString CefX509CertPrincipalCToCpp::GetLocalityName() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_x509cert_principal_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_locality_name)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_locality_name(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+CefString CefX509CertPrincipalCToCpp::GetStateOrProvinceName() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_x509cert_principal_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_state_or_province_name)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_state_or_province_name(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+CefString CefX509CertPrincipalCToCpp::GetCountryName() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_x509cert_principal_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_country_name)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_country_name(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefX509CertPrincipalCToCpp::GetStreetAddresses(
+ std::vector<CefString>& addresses) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_x509cert_principal_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_street_addresses)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Translate param: addresses; type: string_vec_byref
+ cef_string_list_t addressesList = cef_string_list_alloc();
+ DCHECK(addressesList);
+ if (addressesList) {
+ transfer_string_list_contents(addresses, addressesList);
+ }
+
+ // Execute
+ _struct->get_street_addresses(_struct, addressesList);
+
+ // Restore param:addresses; type: string_vec_byref
+ if (addressesList) {
+ addresses.clear();
+ transfer_string_list_contents(addressesList, addresses);
+ cef_string_list_free(addressesList);
+ }
+}
+
+NO_SANITIZE("cfi-icall")
+void CefX509CertPrincipalCToCpp::GetOrganizationNames(
+ std::vector<CefString>& names) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_x509cert_principal_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_organization_names)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Translate param: names; type: string_vec_byref
+ cef_string_list_t namesList = cef_string_list_alloc();
+ DCHECK(namesList);
+ if (namesList) {
+ transfer_string_list_contents(names, namesList);
+ }
+
+ // Execute
+ _struct->get_organization_names(_struct, namesList);
+
+ // Restore param:names; type: string_vec_byref
+ if (namesList) {
+ names.clear();
+ transfer_string_list_contents(namesList, names);
+ cef_string_list_free(namesList);
+ }
+}
+
+NO_SANITIZE("cfi-icall")
+void CefX509CertPrincipalCToCpp::GetOrganizationUnitNames(
+ std::vector<CefString>& names) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_x509cert_principal_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_organization_unit_names)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Translate param: names; type: string_vec_byref
+ cef_string_list_t namesList = cef_string_list_alloc();
+ DCHECK(namesList);
+ if (namesList) {
+ transfer_string_list_contents(names, namesList);
+ }
+
+ // Execute
+ _struct->get_organization_unit_names(_struct, namesList);
+
+ // Restore param:names; type: string_vec_byref
+ if (namesList) {
+ names.clear();
+ transfer_string_list_contents(namesList, names);
+ cef_string_list_free(namesList);
+ }
+}
+
+NO_SANITIZE("cfi-icall")
+void CefX509CertPrincipalCToCpp::GetDomainComponents(
+ std::vector<CefString>& components) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_x509cert_principal_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_domain_components)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Translate param: components; type: string_vec_byref
+ cef_string_list_t componentsList = cef_string_list_alloc();
+ DCHECK(componentsList);
+ if (componentsList) {
+ transfer_string_list_contents(components, componentsList);
+ }
+
+ // Execute
+ _struct->get_domain_components(_struct, componentsList);
+
+ // Restore param:components; type: string_vec_byref
+ if (componentsList) {
+ components.clear();
+ transfer_string_list_contents(componentsList, components);
+ cef_string_list_free(componentsList);
+ }
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefX509CertPrincipalCToCpp::CefX509CertPrincipalCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefX509CertPrincipalCToCpp::~CefX509CertPrincipalCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_x509cert_principal_t* CefCToCppRefCounted<
+ CefX509CertPrincipalCToCpp,
+ CefX509CertPrincipal,
+ cef_x509cert_principal_t>::UnwrapDerived(CefWrapperType type,
+ CefX509CertPrincipal* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefX509CertPrincipalCToCpp,
+ CefX509CertPrincipal,
+ cef_x509cert_principal_t>::kWrapperType =
+ WT_X509CERT_PRINCIPAL;
diff --git a/libcef_dll/ctocpp/x509cert_principal_ctocpp.h b/libcef_dll/ctocpp/x509cert_principal_ctocpp.h
new file mode 100644
index 00000000..ff05ec5f
--- /dev/null
+++ b/libcef_dll/ctocpp/x509cert_principal_ctocpp.h
@@ -0,0 +1,50 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=26c06425ee3d75470177631cff1348e5dc26f946$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_X509CERT_PRINCIPAL_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_X509CERT_PRINCIPAL_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include <vector>
+#include "include/capi/cef_x509_certificate_capi.h"
+#include "include/cef_x509_certificate.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefX509CertPrincipalCToCpp
+ : public CefCToCppRefCounted<CefX509CertPrincipalCToCpp,
+ CefX509CertPrincipal,
+ cef_x509cert_principal_t> {
+ public:
+ CefX509CertPrincipalCToCpp();
+ virtual ~CefX509CertPrincipalCToCpp();
+
+ // CefX509CertPrincipal methods.
+ CefString GetDisplayName() override;
+ CefString GetCommonName() override;
+ CefString GetLocalityName() override;
+ CefString GetStateOrProvinceName() override;
+ CefString GetCountryName() override;
+ void GetStreetAddresses(std::vector<CefString>& addresses) override;
+ void GetOrganizationNames(std::vector<CefString>& names) override;
+ void GetOrganizationUnitNames(std::vector<CefString>& names) override;
+ void GetDomainComponents(std::vector<CefString>& components) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_X509CERT_PRINCIPAL_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/x509certificate_ctocpp.cc b/libcef_dll/ctocpp/x509certificate_ctocpp.cc
new file mode 100644
index 00000000..49f77cdf
--- /dev/null
+++ b/libcef_dll/ctocpp/x509certificate_ctocpp.cc
@@ -0,0 +1,273 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=e8e755f72056f698bbe9edfc4250fb288718e10d$
+//
+
+#include "libcef_dll/ctocpp/x509certificate_ctocpp.h"
+#include <algorithm>
+#include "libcef_dll/ctocpp/binary_value_ctocpp.h"
+#include "libcef_dll/ctocpp/x509cert_principal_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefX509CertPrincipal> CefX509CertificateCToCpp::GetSubject() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_x509certificate_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_subject)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_x509cert_principal_t* _retval = _struct->get_subject(_struct);
+
+ // Return type: refptr_same
+ return CefX509CertPrincipalCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefX509CertPrincipal> CefX509CertificateCToCpp::GetIssuer() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_x509certificate_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_issuer)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_x509cert_principal_t* _retval = _struct->get_issuer(_struct);
+
+ // Return type: refptr_same
+ return CefX509CertPrincipalCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefBinaryValue> CefX509CertificateCToCpp::GetSerialNumber() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_x509certificate_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_serial_number)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_binary_value_t* _retval = _struct->get_serial_number(_struct);
+
+ // Return type: refptr_same
+ return CefBinaryValueCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") CefBaseTime CefX509CertificateCToCpp::GetValidStart() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_x509certificate_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_valid_start)) {
+ return CefBaseTime();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_basetime_t _retval = _struct->get_valid_start(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CefBaseTime CefX509CertificateCToCpp::GetValidExpiry() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_x509certificate_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_valid_expiry)) {
+ return CefBaseTime();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_basetime_t _retval = _struct->get_valid_expiry(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefBinaryValue> CefX509CertificateCToCpp::GetDEREncoded() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_x509certificate_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_derencoded)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_binary_value_t* _retval = _struct->get_derencoded(_struct);
+
+ // Return type: refptr_same
+ return CefBinaryValueCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefBinaryValue> CefX509CertificateCToCpp::GetPEMEncoded() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_x509certificate_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_pemencoded)) {
+ return nullptr;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_binary_value_t* _retval = _struct->get_pemencoded(_struct);
+
+ // Return type: refptr_same
+ return CefBinaryValueCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall") size_t CefX509CertificateCToCpp::GetIssuerChainSize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_x509certificate_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_issuer_chain_size)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ size_t _retval = _struct->get_issuer_chain_size(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+void CefX509CertificateCToCpp::GetDEREncodedIssuerChain(
+ IssuerChainBinaryList& chain) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_x509certificate_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_derencoded_issuer_chain)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Translate param: chain; type: refptr_vec_same_byref
+ size_t chainSize = chain.size();
+ size_t chainCount = std::max(GetIssuerChainSize(), chainSize);
+ cef_binary_value_t** chainList = NULL;
+ if (chainCount > 0) {
+ chainList = new cef_binary_value_t*[chainCount];
+ DCHECK(chainList);
+ if (chainList) {
+ memset(chainList, 0, sizeof(cef_binary_value_t*) * chainCount);
+ }
+ if (chainList && chainSize > 0) {
+ for (size_t i = 0; i < chainSize; ++i) {
+ chainList[i] = CefBinaryValueCToCpp::Unwrap(chain[i]);
+ }
+ }
+ }
+
+ // Execute
+ _struct->get_derencoded_issuer_chain(_struct, &chainCount, chainList);
+
+ // Restore param:chain; type: refptr_vec_same_byref
+ chain.clear();
+ if (chainCount > 0 && chainList) {
+ for (size_t i = 0; i < chainCount; ++i) {
+ chain.push_back(CefBinaryValueCToCpp::Wrap(chainList[i]));
+ }
+ delete[] chainList;
+ }
+}
+
+NO_SANITIZE("cfi-icall")
+void CefX509CertificateCToCpp::GetPEMEncodedIssuerChain(
+ IssuerChainBinaryList& chain) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_x509certificate_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_pemencoded_issuer_chain)) {
+ return;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Translate param: chain; type: refptr_vec_same_byref
+ size_t chainSize = chain.size();
+ size_t chainCount = std::max(GetIssuerChainSize(), chainSize);
+ cef_binary_value_t** chainList = NULL;
+ if (chainCount > 0) {
+ chainList = new cef_binary_value_t*[chainCount];
+ DCHECK(chainList);
+ if (chainList) {
+ memset(chainList, 0, sizeof(cef_binary_value_t*) * chainCount);
+ }
+ if (chainList && chainSize > 0) {
+ for (size_t i = 0; i < chainSize; ++i) {
+ chainList[i] = CefBinaryValueCToCpp::Unwrap(chain[i]);
+ }
+ }
+ }
+
+ // Execute
+ _struct->get_pemencoded_issuer_chain(_struct, &chainCount, chainList);
+
+ // Restore param:chain; type: refptr_vec_same_byref
+ chain.clear();
+ if (chainCount > 0 && chainList) {
+ for (size_t i = 0; i < chainCount; ++i) {
+ chain.push_back(CefBinaryValueCToCpp::Wrap(chainList[i]));
+ }
+ delete[] chainList;
+ }
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefX509CertificateCToCpp::CefX509CertificateCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefX509CertificateCToCpp::~CefX509CertificateCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_x509certificate_t* CefCToCppRefCounted<
+ CefX509CertificateCToCpp,
+ CefX509Certificate,
+ cef_x509certificate_t>::UnwrapDerived(CefWrapperType type,
+ CefX509Certificate* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefX509CertificateCToCpp,
+ CefX509Certificate,
+ cef_x509certificate_t>::kWrapperType =
+ WT_X509CERTIFICATE;
diff --git a/libcef_dll/ctocpp/x509certificate_ctocpp.h b/libcef_dll/ctocpp/x509certificate_ctocpp.h
new file mode 100644
index 00000000..721b4999
--- /dev/null
+++ b/libcef_dll/ctocpp/x509certificate_ctocpp.h
@@ -0,0 +1,50 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=39cb5dd7488f7035a1b52e50b48e3bffee27dba6$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_X509CERTIFICATE_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_X509CERTIFICATE_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_x509_certificate_capi.h"
+#include "include/cef_x509_certificate.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefX509CertificateCToCpp
+ : public CefCToCppRefCounted<CefX509CertificateCToCpp,
+ CefX509Certificate,
+ cef_x509certificate_t> {
+ public:
+ CefX509CertificateCToCpp();
+ virtual ~CefX509CertificateCToCpp();
+
+ // CefX509Certificate methods.
+ CefRefPtr<CefX509CertPrincipal> GetSubject() override;
+ CefRefPtr<CefX509CertPrincipal> GetIssuer() override;
+ CefRefPtr<CefBinaryValue> GetSerialNumber() override;
+ CefBaseTime GetValidStart() override;
+ CefBaseTime GetValidExpiry() override;
+ CefRefPtr<CefBinaryValue> GetDEREncoded() override;
+ CefRefPtr<CefBinaryValue> GetPEMEncoded() override;
+ size_t GetIssuerChainSize() override;
+ void GetDEREncodedIssuerChain(IssuerChainBinaryList& chain) override;
+ void GetPEMEncodedIssuerChain(IssuerChainBinaryList& chain) override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_X509CERTIFICATE_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/xml_reader_ctocpp.cc b/libcef_dll/ctocpp/xml_reader_ctocpp.cc
new file mode 100644
index 00000000..56e38c25
--- /dev/null
+++ b/libcef_dll/ctocpp/xml_reader_ctocpp.cc
@@ -0,0 +1,648 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=4c42535d9b888851a5d46b587e67df2aeb7199ca$
+//
+
+#include "libcef_dll/ctocpp/xml_reader_ctocpp.h"
+#include "libcef_dll/ctocpp/stream_reader_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// STATIC METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefXmlReader> CefXmlReader::Create(CefRefPtr<CefStreamReader> stream,
+ EncodingType encodingType,
+ const CefString& URI) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: stream; type: refptr_same
+ DCHECK(stream.get());
+ if (!stream.get()) {
+ return nullptr;
+ }
+ // Verify param: URI; type: string_byref_const
+ DCHECK(!URI.empty());
+ if (URI.empty()) {
+ return nullptr;
+ }
+
+ // Execute
+ cef_xml_reader_t* _retval = cef_xml_reader_create(
+ CefStreamReaderCToCpp::Unwrap(stream), encodingType, URI.GetStruct());
+
+ // Return type: refptr_same
+ return CefXmlReaderCToCpp::Wrap(_retval);
+}
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") bool CefXmlReaderCToCpp::MoveToNextNode() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_xml_reader_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, move_to_next_node)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->move_to_next_node(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefXmlReaderCToCpp::Close() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_xml_reader_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, close)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->close(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefXmlReaderCToCpp::HasError() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_xml_reader_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, has_error)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->has_error(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") CefString CefXmlReaderCToCpp::GetError() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_xml_reader_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_error)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_error(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") CefXmlReader::NodeType CefXmlReaderCToCpp::GetType() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_xml_reader_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_type)) {
+ return XML_NODE_UNSUPPORTED;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_xml_node_type_t _retval = _struct->get_type(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") int CefXmlReaderCToCpp::GetDepth() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_xml_reader_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_depth)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_depth(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") CefString CefXmlReaderCToCpp::GetLocalName() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_xml_reader_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_local_name)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_local_name(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") CefString CefXmlReaderCToCpp::GetPrefix() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_xml_reader_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_prefix)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_prefix(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") CefString CefXmlReaderCToCpp::GetQualifiedName() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_xml_reader_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_qualified_name)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_qualified_name(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") CefString CefXmlReaderCToCpp::GetNamespaceURI() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_xml_reader_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_namespace_uri)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_namespace_uri(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") CefString CefXmlReaderCToCpp::GetBaseURI() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_xml_reader_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_base_uri)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_base_uri(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") CefString CefXmlReaderCToCpp::GetXmlLang() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_xml_reader_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_xml_lang)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_xml_lang(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") bool CefXmlReaderCToCpp::IsEmptyElement() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_xml_reader_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, is_empty_element)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->is_empty_element(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefXmlReaderCToCpp::HasValue() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_xml_reader_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, has_value)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->has_value(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") CefString CefXmlReaderCToCpp::GetValue() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_xml_reader_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_value)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_value(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") bool CefXmlReaderCToCpp::HasAttributes() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_xml_reader_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, has_attributes)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->has_attributes(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") size_t CefXmlReaderCToCpp::GetAttributeCount() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_xml_reader_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_attribute_count)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ size_t _retval = _struct->get_attribute_count(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") CefString CefXmlReaderCToCpp::GetAttribute(int index) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_xml_reader_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_attribute_byindex)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: index; type: simple_byval
+ DCHECK_GE(index, 0);
+ if (index < 0) {
+ return CefString();
+ }
+
+ // Execute
+ cef_string_userfree_t _retval =
+ _struct->get_attribute_byindex(_struct, index);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+CefString CefXmlReaderCToCpp::GetAttribute(const CefString& qualifiedName) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_xml_reader_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_attribute_byqname)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: qualifiedName; type: string_byref_const
+ DCHECK(!qualifiedName.empty());
+ if (qualifiedName.empty()) {
+ return CefString();
+ }
+
+ // Execute
+ cef_string_userfree_t _retval =
+ _struct->get_attribute_byqname(_struct, qualifiedName.GetStruct());
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+CefString CefXmlReaderCToCpp::GetAttribute(const CefString& localName,
+ const CefString& namespaceURI) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_xml_reader_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_attribute_bylname)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: localName; type: string_byref_const
+ DCHECK(!localName.empty());
+ if (localName.empty()) {
+ return CefString();
+ }
+ // Verify param: namespaceURI; type: string_byref_const
+ DCHECK(!namespaceURI.empty());
+ if (namespaceURI.empty()) {
+ return CefString();
+ }
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_attribute_bylname(
+ _struct, localName.GetStruct(), namespaceURI.GetStruct());
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") CefString CefXmlReaderCToCpp::GetInnerXml() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_xml_reader_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_inner_xml)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_inner_xml(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") CefString CefXmlReaderCToCpp::GetOuterXml() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_xml_reader_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_outer_xml)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_outer_xml(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") int CefXmlReaderCToCpp::GetLineNumber() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_xml_reader_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_line_number)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->get_line_number(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") bool CefXmlReaderCToCpp::MoveToAttribute(int index) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_xml_reader_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, move_to_attribute_byindex)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: index; type: simple_byval
+ DCHECK_GE(index, 0);
+ if (index < 0) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->move_to_attribute_byindex(_struct, index);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefXmlReaderCToCpp::MoveToAttribute(const CefString& qualifiedName) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_xml_reader_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, move_to_attribute_byqname)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: qualifiedName; type: string_byref_const
+ DCHECK(!qualifiedName.empty());
+ if (qualifiedName.empty()) {
+ return false;
+ }
+
+ // Execute
+ int _retval =
+ _struct->move_to_attribute_byqname(_struct, qualifiedName.GetStruct());
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefXmlReaderCToCpp::MoveToAttribute(const CefString& localName,
+ const CefString& namespaceURI) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_xml_reader_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, move_to_attribute_bylname)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: localName; type: string_byref_const
+ DCHECK(!localName.empty());
+ if (localName.empty()) {
+ return false;
+ }
+ // Verify param: namespaceURI; type: string_byref_const
+ DCHECK(!namespaceURI.empty());
+ if (namespaceURI.empty()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = _struct->move_to_attribute_bylname(
+ _struct, localName.GetStruct(), namespaceURI.GetStruct());
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefXmlReaderCToCpp::MoveToFirstAttribute() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_xml_reader_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, move_to_first_attribute)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->move_to_first_attribute(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefXmlReaderCToCpp::MoveToNextAttribute() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_xml_reader_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, move_to_next_attribute)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->move_to_next_attribute(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefXmlReaderCToCpp::MoveToCarryingElement() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_xml_reader_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, move_to_carrying_element)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->move_to_carrying_element(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefXmlReaderCToCpp::CefXmlReaderCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefXmlReaderCToCpp::~CefXmlReaderCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_xml_reader_t*
+CefCToCppRefCounted<CefXmlReaderCToCpp, CefXmlReader, cef_xml_reader_t>::
+ UnwrapDerived(CefWrapperType type, CefXmlReader* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefXmlReaderCToCpp,
+ CefXmlReader,
+ cef_xml_reader_t>::kWrapperType =
+ WT_XML_READER;
diff --git a/libcef_dll/ctocpp/xml_reader_ctocpp.h b/libcef_dll/ctocpp/xml_reader_ctocpp.h
new file mode 100644
index 00000000..28101860
--- /dev/null
+++ b/libcef_dll/ctocpp/xml_reader_ctocpp.h
@@ -0,0 +1,70 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=5f87c82093a6a16e03df00673d2ff20a9f0490d5$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_XML_READER_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_XML_READER_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_xml_reader_capi.h"
+#include "include/cef_xml_reader.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefXmlReaderCToCpp : public CefCToCppRefCounted<CefXmlReaderCToCpp,
+ CefXmlReader,
+ cef_xml_reader_t> {
+ public:
+ CefXmlReaderCToCpp();
+ virtual ~CefXmlReaderCToCpp();
+
+ // CefXmlReader methods.
+ bool MoveToNextNode() override;
+ bool Close() override;
+ bool HasError() override;
+ CefString GetError() override;
+ NodeType GetType() override;
+ int GetDepth() override;
+ CefString GetLocalName() override;
+ CefString GetPrefix() override;
+ CefString GetQualifiedName() override;
+ CefString GetNamespaceURI() override;
+ CefString GetBaseURI() override;
+ CefString GetXmlLang() override;
+ bool IsEmptyElement() override;
+ bool HasValue() override;
+ CefString GetValue() override;
+ bool HasAttributes() override;
+ size_t GetAttributeCount() override;
+ CefString GetAttribute(int index) override;
+ CefString GetAttribute(const CefString& qualifiedName) override;
+ CefString GetAttribute(const CefString& localName,
+ const CefString& namespaceURI) override;
+ CefString GetInnerXml() override;
+ CefString GetOuterXml() override;
+ int GetLineNumber() override;
+ bool MoveToAttribute(int index) override;
+ bool MoveToAttribute(const CefString& qualifiedName) override;
+ bool MoveToAttribute(const CefString& localName,
+ const CefString& namespaceURI) override;
+ bool MoveToFirstAttribute() override;
+ bool MoveToNextAttribute() override;
+ bool MoveToCarryingElement() override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_XML_READER_CTOCPP_H_
diff --git a/libcef_dll/ctocpp/zip_reader_ctocpp.cc b/libcef_dll/ctocpp/zip_reader_ctocpp.cc
new file mode 100644
index 00000000..8f658531
--- /dev/null
+++ b/libcef_dll/ctocpp/zip_reader_ctocpp.cc
@@ -0,0 +1,291 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=08d37db545a632813585805e01cdd6b1e1705fe3$
+//
+
+#include "libcef_dll/ctocpp/zip_reader_ctocpp.h"
+#include "libcef_dll/ctocpp/stream_reader_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+
+// STATIC METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CefRefPtr<CefZipReader> CefZipReader::Create(
+ CefRefPtr<CefStreamReader> stream) {
+ shutdown_checker::AssertNotShutdown();
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: stream; type: refptr_same
+ DCHECK(stream.get());
+ if (!stream.get()) {
+ return nullptr;
+ }
+
+ // Execute
+ cef_zip_reader_t* _retval =
+ cef_zip_reader_create(CefStreamReaderCToCpp::Unwrap(stream));
+
+ // Return type: refptr_same
+ return CefZipReaderCToCpp::Wrap(_retval);
+}
+
+// VIRTUAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall") bool CefZipReaderCToCpp::MoveToFirstFile() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_zip_reader_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, move_to_first_file)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->move_to_first_file(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefZipReaderCToCpp::MoveToNextFile() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_zip_reader_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, move_to_next_file)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->move_to_next_file(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefZipReaderCToCpp::MoveToFile(const CefString& fileName,
+ bool caseSensitive) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_zip_reader_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, move_to_file)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: fileName; type: string_byref_const
+ DCHECK(!fileName.empty());
+ if (fileName.empty()) {
+ return false;
+ }
+
+ // Execute
+ int _retval =
+ _struct->move_to_file(_struct, fileName.GetStruct(), caseSensitive);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefZipReaderCToCpp::Close() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_zip_reader_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, close)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->close(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") CefString CefZipReaderCToCpp::GetFileName() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_zip_reader_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_file_name)) {
+ return CefString();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_string_userfree_t _retval = _struct->get_file_name(_struct);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall") int64 CefZipReaderCToCpp::GetFileSize() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_zip_reader_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_file_size)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int64 _retval = _struct->get_file_size(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") CefBaseTime CefZipReaderCToCpp::GetFileLastModified() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_zip_reader_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, get_file_last_modified)) {
+ return CefBaseTime();
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_basetime_t _retval = _struct->get_file_last_modified(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+bool CefZipReaderCToCpp::OpenFile(const CefString& password) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_zip_reader_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, open_file)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: password
+
+ // Execute
+ int _retval = _struct->open_file(_struct, password.GetStruct());
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") bool CefZipReaderCToCpp::CloseFile() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_zip_reader_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, close_file)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->close_file(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+int CefZipReaderCToCpp::ReadFile(void* buffer, size_t bufferSize) {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_zip_reader_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, read_file)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: buffer; type: simple_byaddr
+ DCHECK(buffer);
+ if (!buffer) {
+ return 0;
+ }
+
+ // Execute
+ int _retval = _struct->read_file(_struct, buffer, bufferSize);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") int64 CefZipReaderCToCpp::Tell() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_zip_reader_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, tell)) {
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int64 _retval = _struct->tell(_struct);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall") bool CefZipReaderCToCpp::Eof() {
+ shutdown_checker::AssertNotShutdown();
+
+ cef_zip_reader_t* _struct = GetStruct();
+ if (CEF_MEMBER_MISSING(_struct, eof)) {
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = _struct->eof(_struct);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+// CONSTRUCTOR - Do not edit by hand.
+
+CefZipReaderCToCpp::CefZipReaderCToCpp() {}
+
+// DESTRUCTOR - Do not edit by hand.
+
+CefZipReaderCToCpp::~CefZipReaderCToCpp() {
+ shutdown_checker::AssertNotShutdown();
+}
+
+template <>
+cef_zip_reader_t*
+CefCToCppRefCounted<CefZipReaderCToCpp, CefZipReader, cef_zip_reader_t>::
+ UnwrapDerived(CefWrapperType type, CefZipReader* c) {
+ NOTREACHED() << "Unexpected class type: " << type;
+ return nullptr;
+}
+
+template <>
+CefWrapperType CefCToCppRefCounted<CefZipReaderCToCpp,
+ CefZipReader,
+ cef_zip_reader_t>::kWrapperType =
+ WT_ZIP_READER;
diff --git a/libcef_dll/ctocpp/zip_reader_ctocpp.h b/libcef_dll/ctocpp/zip_reader_ctocpp.h
new file mode 100644
index 00000000..3c1e7744
--- /dev/null
+++ b/libcef_dll/ctocpp/zip_reader_ctocpp.h
@@ -0,0 +1,51 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=607dfcaa8f19f7510fc4f87fc31a8754369fdc3a$
+//
+
+#ifndef CEF_LIBCEF_DLL_CTOCPP_ZIP_READER_CTOCPP_H_
+#define CEF_LIBCEF_DLL_CTOCPP_ZIP_READER_CTOCPP_H_
+#pragma once
+
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+
+#include "include/capi/cef_zip_reader_capi.h"
+#include "include/cef_zip_reader.h"
+#include "libcef_dll/ctocpp/ctocpp_ref_counted.h"
+
+// Wrap a C structure with a C++ class.
+// This class may be instantiated and accessed wrapper-side only.
+class CefZipReaderCToCpp : public CefCToCppRefCounted<CefZipReaderCToCpp,
+ CefZipReader,
+ cef_zip_reader_t> {
+ public:
+ CefZipReaderCToCpp();
+ virtual ~CefZipReaderCToCpp();
+
+ // CefZipReader methods.
+ bool MoveToFirstFile() override;
+ bool MoveToNextFile() override;
+ bool MoveToFile(const CefString& fileName, bool caseSensitive) override;
+ bool Close() override;
+ CefString GetFileName() override;
+ int64 GetFileSize() override;
+ CefBaseTime GetFileLastModified() override;
+ bool OpenFile(const CefString& password) override;
+ bool CloseFile() override;
+ int ReadFile(void* buffer, size_t bufferSize) override;
+ int64 Tell() override;
+ bool Eof() override;
+};
+
+#endif // CEF_LIBCEF_DLL_CTOCPP_ZIP_READER_CTOCPP_H_
diff --git a/libcef_dll/libcef.dll.manifest b/libcef_dll/libcef.dll.manifest
new file mode 100644
index 00000000..76c63808
--- /dev/null
+++ b/libcef_dll/libcef.dll.manifest
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+ <dependency>
+ <dependentAssembly>
+ <assemblyIdentity type="Win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"></assemblyIdentity>
+ </dependentAssembly>
+ </dependency>
+</assembly>
diff --git a/libcef_dll/libcef.lst b/libcef_dll/libcef.lst
new file mode 100644
index 00000000..e236ea99
--- /dev/null
+++ b/libcef_dll/libcef.lst
@@ -0,0 +1,9 @@
+# Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ /* Only export necessary symbols from libcef.so. */
+ global: cef_*;
+ local: *;
+};
diff --git a/libcef_dll/libcef_dll.cc b/libcef_dll/libcef_dll.cc
new file mode 100644
index 00000000..d4840c94
--- /dev/null
+++ b/libcef_dll/libcef_dll.cc
@@ -0,0 +1,940 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=f0c6529941194dc0bbbb1ac75268b6653653dbbb$
+//
+
+#include "include/capi/cef_app_capi.h"
+#include "include/capi/cef_crash_util_capi.h"
+#include "include/capi/cef_file_util_capi.h"
+#include "include/capi/cef_i18n_util_capi.h"
+#include "include/capi/cef_origin_whitelist_capi.h"
+#include "include/capi/cef_parser_capi.h"
+#include "include/capi/cef_path_util_capi.h"
+#include "include/capi/cef_process_util_capi.h"
+#include "include/capi/cef_scheme_capi.h"
+#include "include/capi/cef_ssl_info_capi.h"
+#include "include/capi/cef_task_capi.h"
+#include "include/capi/cef_trace_capi.h"
+#include "include/capi/cef_v8_capi.h"
+#include "include/capi/test/cef_test_helpers_capi.h"
+#include "include/cef_app.h"
+#include "include/cef_crash_util.h"
+#include "include/cef_file_util.h"
+#include "include/cef_i18n_util.h"
+#include "include/cef_origin_whitelist.h"
+#include "include/cef_parser.h"
+#include "include/cef_path_util.h"
+#include "include/cef_process_util.h"
+#include "include/cef_scheme.h"
+#include "include/cef_ssl_info.h"
+#include "include/cef_task.h"
+#include "include/cef_trace.h"
+#include "include/cef_v8.h"
+#include "include/test/cef_test_helpers.h"
+#include "libcef_dll/cpptoc/binary_value_cpptoc.h"
+#include "libcef_dll/cpptoc/command_line_cpptoc.h"
+#include "libcef_dll/cpptoc/frame_cpptoc.h"
+#include "libcef_dll/cpptoc/value_cpptoc.h"
+#include "libcef_dll/ctocpp/app_ctocpp.h"
+#include "libcef_dll/ctocpp/completion_callback_ctocpp.h"
+#include "libcef_dll/ctocpp/end_tracing_callback_ctocpp.h"
+#include "libcef_dll/ctocpp/scheme_handler_factory_ctocpp.h"
+#include "libcef_dll/ctocpp/task_ctocpp.h"
+#include "libcef_dll/ctocpp/v8handler_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+#include "libcef_dll/template_util.h"
+#include "libcef_dll/transfer_util.h"
+
+// GLOBAL FUNCTIONS - Body may be edited by hand.
+
+CEF_EXPORT int cef_execute_process(const cef_main_args_t* args,
+ struct _cef_app_t* application,
+ void* windows_sandbox_info) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: args; type: simple_byref_const
+ DCHECK(args);
+ if (!args) {
+ return 0;
+ }
+ // Unverified params: application, windows_sandbox_info
+
+ // Translate param: args; type: simple_byref_const
+ CefMainArgs argsVal = args ? *args : CefMainArgs();
+
+ // Execute
+ int _retval = CefExecuteProcess(argsVal, CefAppCToCpp::Wrap(application),
+ windows_sandbox_info);
+
+ // Return type: simple
+ return _retval;
+}
+
+CEF_EXPORT int cef_initialize(const cef_main_args_t* args,
+ const struct _cef_settings_t* settings,
+ struct _cef_app_t* application,
+ void* windows_sandbox_info) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: args; type: simple_byref_const
+ DCHECK(args);
+ if (!args) {
+ return 0;
+ }
+ // Verify param: settings; type: struct_byref_const
+ DCHECK(settings);
+ if (!settings) {
+ return 0;
+ }
+ if (!template_util::has_valid_size(settings)) {
+ NOTREACHED() << "invalid settings->[base.]size";
+ return 0;
+ }
+ // Unverified params: application, windows_sandbox_info
+
+ // Translate param: args; type: simple_byref_const
+ CefMainArgs argsVal = args ? *args : CefMainArgs();
+ // Translate param: settings; type: struct_byref_const
+ CefSettings settingsObj;
+ if (settings) {
+ settingsObj.Set(*settings, false);
+ }
+
+ // Execute
+ bool _retval =
+ CefInitialize(argsVal, settingsObj, CefAppCToCpp::Wrap(application),
+ windows_sandbox_info);
+
+ // Return type: bool
+ return _retval;
+}
+
+CEF_EXPORT void cef_shutdown() {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+#if DCHECK_IS_ON()
+ shutdown_checker::SetIsShutdown();
+#endif
+
+ // Execute
+ CefShutdown();
+}
+
+CEF_EXPORT void cef_do_message_loop_work() {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ CefDoMessageLoopWork();
+}
+
+CEF_EXPORT void cef_run_message_loop() {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ CefRunMessageLoop();
+}
+
+CEF_EXPORT void cef_quit_message_loop() {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ CefQuitMessageLoop();
+}
+
+CEF_EXPORT int cef_crash_reporting_enabled() {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ bool _retval = CefCrashReportingEnabled();
+
+ // Return type: bool
+ return _retval;
+}
+
+CEF_EXPORT void cef_set_crash_key_value(const cef_string_t* key,
+ const cef_string_t* value) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: key; type: string_byref_const
+ DCHECK(key);
+ if (!key) {
+ return;
+ }
+ // Unverified params: value
+
+ // Execute
+ CefSetCrashKeyValue(CefString(key), CefString(value));
+}
+
+CEF_EXPORT int cef_create_directory(const cef_string_t* full_path) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: full_path; type: string_byref_const
+ DCHECK(full_path);
+ if (!full_path) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefCreateDirectory(CefString(full_path));
+
+ // Return type: bool
+ return _retval;
+}
+
+CEF_EXPORT int cef_get_temp_directory(cef_string_t* temp_dir) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: temp_dir; type: string_byref
+ DCHECK(temp_dir);
+ if (!temp_dir) {
+ return 0;
+ }
+
+ // Translate param: temp_dir; type: string_byref
+ CefString temp_dirStr(temp_dir);
+
+ // Execute
+ bool _retval = CefGetTempDirectory(temp_dirStr);
+
+ // Return type: bool
+ return _retval;
+}
+
+CEF_EXPORT int cef_create_new_temp_directory(const cef_string_t* prefix,
+ cef_string_t* new_temp_path) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: new_temp_path; type: string_byref
+ DCHECK(new_temp_path);
+ if (!new_temp_path) {
+ return 0;
+ }
+ // Unverified params: prefix
+
+ // Translate param: new_temp_path; type: string_byref
+ CefString new_temp_pathStr(new_temp_path);
+
+ // Execute
+ bool _retval = CefCreateNewTempDirectory(CefString(prefix), new_temp_pathStr);
+
+ // Return type: bool
+ return _retval;
+}
+
+CEF_EXPORT int cef_create_temp_directory_in_directory(
+ const cef_string_t* base_dir,
+ const cef_string_t* prefix,
+ cef_string_t* new_dir) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: base_dir; type: string_byref_const
+ DCHECK(base_dir);
+ if (!base_dir) {
+ return 0;
+ }
+ // Verify param: new_dir; type: string_byref
+ DCHECK(new_dir);
+ if (!new_dir) {
+ return 0;
+ }
+ // Unverified params: prefix
+
+ // Translate param: new_dir; type: string_byref
+ CefString new_dirStr(new_dir);
+
+ // Execute
+ bool _retval = CefCreateTempDirectoryInDirectory(
+ CefString(base_dir), CefString(prefix), new_dirStr);
+
+ // Return type: bool
+ return _retval;
+}
+
+CEF_EXPORT int cef_directory_exists(const cef_string_t* path) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: path; type: string_byref_const
+ DCHECK(path);
+ if (!path) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefDirectoryExists(CefString(path));
+
+ // Return type: bool
+ return _retval;
+}
+
+CEF_EXPORT int cef_delete_file(const cef_string_t* path, int recursive) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: path; type: string_byref_const
+ DCHECK(path);
+ if (!path) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefDeleteFile(CefString(path), recursive ? true : false);
+
+ // Return type: bool
+ return _retval;
+}
+
+CEF_EXPORT int cef_zip_directory(const cef_string_t* src_dir,
+ const cef_string_t* dest_file,
+ int include_hidden_files) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: src_dir; type: string_byref_const
+ DCHECK(src_dir);
+ if (!src_dir) {
+ return 0;
+ }
+ // Verify param: dest_file; type: string_byref_const
+ DCHECK(dest_file);
+ if (!dest_file) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefZipDirectory(CefString(src_dir), CefString(dest_file),
+ include_hidden_files ? true : false);
+
+ // Return type: bool
+ return _retval;
+}
+
+CEF_EXPORT void cef_load_crlsets_file(const cef_string_t* path) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: path; type: string_byref_const
+ DCHECK(path);
+ if (!path) {
+ return;
+ }
+
+ // Execute
+ CefLoadCRLSetsFile(CefString(path));
+}
+
+CEF_EXPORT int cef_is_rtl() {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ bool _retval = CefIsRTL();
+
+ // Return type: bool
+ return _retval;
+}
+
+CEF_EXPORT int cef_add_cross_origin_whitelist_entry(
+ const cef_string_t* source_origin,
+ const cef_string_t* target_protocol,
+ const cef_string_t* target_domain,
+ int allow_target_subdomains) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: source_origin; type: string_byref_const
+ DCHECK(source_origin);
+ if (!source_origin) {
+ return 0;
+ }
+ // Verify param: target_protocol; type: string_byref_const
+ DCHECK(target_protocol);
+ if (!target_protocol) {
+ return 0;
+ }
+ // Unverified params: target_domain
+
+ // Execute
+ bool _retval = CefAddCrossOriginWhitelistEntry(
+ CefString(source_origin), CefString(target_protocol),
+ CefString(target_domain), allow_target_subdomains ? true : false);
+
+ // Return type: bool
+ return _retval;
+}
+
+CEF_EXPORT int cef_remove_cross_origin_whitelist_entry(
+ const cef_string_t* source_origin,
+ const cef_string_t* target_protocol,
+ const cef_string_t* target_domain,
+ int allow_target_subdomains) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: source_origin; type: string_byref_const
+ DCHECK(source_origin);
+ if (!source_origin) {
+ return 0;
+ }
+ // Verify param: target_protocol; type: string_byref_const
+ DCHECK(target_protocol);
+ if (!target_protocol) {
+ return 0;
+ }
+ // Unverified params: target_domain
+
+ // Execute
+ bool _retval = CefRemoveCrossOriginWhitelistEntry(
+ CefString(source_origin), CefString(target_protocol),
+ CefString(target_domain), allow_target_subdomains ? true : false);
+
+ // Return type: bool
+ return _retval;
+}
+
+CEF_EXPORT int cef_clear_cross_origin_whitelist() {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ bool _retval = CefClearCrossOriginWhitelist();
+
+ // Return type: bool
+ return _retval;
+}
+
+CEF_EXPORT int cef_resolve_url(const cef_string_t* base_url,
+ const cef_string_t* relative_url,
+ cef_string_t* resolved_url) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: base_url; type: string_byref_const
+ DCHECK(base_url);
+ if (!base_url) {
+ return 0;
+ }
+ // Verify param: relative_url; type: string_byref_const
+ DCHECK(relative_url);
+ if (!relative_url) {
+ return 0;
+ }
+ // Verify param: resolved_url; type: string_byref
+ DCHECK(resolved_url);
+ if (!resolved_url) {
+ return 0;
+ }
+
+ // Translate param: resolved_url; type: string_byref
+ CefString resolved_urlStr(resolved_url);
+
+ // Execute
+ bool _retval = CefResolveURL(CefString(base_url), CefString(relative_url),
+ resolved_urlStr);
+
+ // Return type: bool
+ return _retval;
+}
+
+CEF_EXPORT int cef_parse_url(const cef_string_t* url,
+ struct _cef_urlparts_t* parts) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: url; type: string_byref_const
+ DCHECK(url);
+ if (!url) {
+ return 0;
+ }
+ // Verify param: parts; type: struct_byref
+ DCHECK(parts);
+ if (!parts) {
+ return 0;
+ }
+ if (!template_util::has_valid_size(parts)) {
+ NOTREACHED() << "invalid parts->[base.]size";
+ return 0;
+ }
+
+ // Translate param: parts; type: struct_byref
+ CefURLParts partsObj;
+ if (parts) {
+ partsObj.AttachTo(*parts);
+ }
+
+ // Execute
+ bool _retval = CefParseURL(CefString(url), partsObj);
+
+ // Restore param: parts; type: struct_byref
+ if (parts) {
+ partsObj.DetachTo(*parts);
+ }
+
+ // Return type: bool
+ return _retval;
+}
+
+CEF_EXPORT int cef_create_url(const struct _cef_urlparts_t* parts,
+ cef_string_t* url) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: parts; type: struct_byref_const
+ DCHECK(parts);
+ if (!parts) {
+ return 0;
+ }
+ if (!template_util::has_valid_size(parts)) {
+ NOTREACHED() << "invalid parts->[base.]size";
+ return 0;
+ }
+ // Verify param: url; type: string_byref
+ DCHECK(url);
+ if (!url) {
+ return 0;
+ }
+
+ // Translate param: parts; type: struct_byref_const
+ CefURLParts partsObj;
+ if (parts) {
+ partsObj.Set(*parts, false);
+ }
+ // Translate param: url; type: string_byref
+ CefString urlStr(url);
+
+ // Execute
+ bool _retval = CefCreateURL(partsObj, urlStr);
+
+ // Return type: bool
+ return _retval;
+}
+
+CEF_EXPORT cef_string_userfree_t
+cef_format_url_for_security_display(const cef_string_t* origin_url) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: origin_url; type: string_byref_const
+ DCHECK(origin_url);
+ if (!origin_url) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefFormatUrlForSecurityDisplay(CefString(origin_url));
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+CEF_EXPORT cef_string_userfree_t
+cef_get_mime_type(const cef_string_t* extension) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: extension; type: string_byref_const
+ DCHECK(extension);
+ if (!extension) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefGetMimeType(CefString(extension));
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+CEF_EXPORT void cef_get_extensions_for_mime_type(const cef_string_t* mime_type,
+ cef_string_list_t extensions) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: mime_type; type: string_byref_const
+ DCHECK(mime_type);
+ if (!mime_type) {
+ return;
+ }
+ // Verify param: extensions; type: string_vec_byref
+ DCHECK(extensions);
+ if (!extensions) {
+ return;
+ }
+
+ // Translate param: extensions; type: string_vec_byref
+ std::vector<CefString> extensionsList;
+ transfer_string_list_contents(extensions, extensionsList);
+
+ // Execute
+ CefGetExtensionsForMimeType(CefString(mime_type), extensionsList);
+
+ // Restore param: extensions; type: string_vec_byref
+ cef_string_list_clear(extensions);
+ transfer_string_list_contents(extensionsList, extensions);
+}
+
+CEF_EXPORT cef_string_userfree_t cef_base64encode(const void* data,
+ size_t data_size) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: data; type: simple_byaddr
+ DCHECK(data);
+ if (!data) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefBase64Encode(data, data_size);
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+CEF_EXPORT struct _cef_binary_value_t* cef_base64decode(
+ const cef_string_t* data) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: data; type: string_byref_const
+ DCHECK(data);
+ if (!data) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefBinaryValue> _retval = CefBase64Decode(CefString(data));
+
+ // Return type: refptr_same
+ return CefBinaryValueCppToC::Wrap(_retval);
+}
+
+CEF_EXPORT cef_string_userfree_t cef_uriencode(const cef_string_t* text,
+ int use_plus) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: text; type: string_byref_const
+ DCHECK(text);
+ if (!text) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefURIEncode(CefString(text), use_plus ? true : false);
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+CEF_EXPORT cef_string_userfree_t
+cef_uridecode(const cef_string_t* text,
+ int convert_to_utf8,
+ cef_uri_unescape_rule_t unescape_rule) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: text; type: string_byref_const
+ DCHECK(text);
+ if (!text) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefURIDecode(
+ CefString(text), convert_to_utf8 ? true : false, unescape_rule);
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+CEF_EXPORT struct _cef_value_t* cef_parse_json(
+ const cef_string_t* json_string,
+ cef_json_parser_options_t options) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: json_string; type: string_byref_const
+ DCHECK(json_string);
+ if (!json_string) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefValue> _retval = CefParseJSON(CefString(json_string), options);
+
+ // Return type: refptr_same
+ return CefValueCppToC::Wrap(_retval);
+}
+
+CEF_EXPORT struct _cef_value_t* cef_parse_json_buffer(
+ const void* json,
+ size_t json_size,
+ cef_json_parser_options_t options) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: json; type: simple_byaddr
+ DCHECK(json);
+ if (!json) {
+ return NULL;
+ }
+
+ // Execute
+ CefRefPtr<CefValue> _retval = CefParseJSON(json, json_size, options);
+
+ // Return type: refptr_same
+ return CefValueCppToC::Wrap(_retval);
+}
+
+CEF_EXPORT struct _cef_value_t* cef_parse_jsonand_return_error(
+ const cef_string_t* json_string,
+ cef_json_parser_options_t options,
+ cef_string_t* error_msg_out) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: json_string; type: string_byref_const
+ DCHECK(json_string);
+ if (!json_string) {
+ return NULL;
+ }
+ // Verify param: error_msg_out; type: string_byref
+ DCHECK(error_msg_out);
+ if (!error_msg_out) {
+ return NULL;
+ }
+
+ // Translate param: error_msg_out; type: string_byref
+ CefString error_msg_outStr(error_msg_out);
+
+ // Execute
+ CefRefPtr<CefValue> _retval = CefParseJSONAndReturnError(
+ CefString(json_string), options, error_msg_outStr);
+
+ // Return type: refptr_same
+ return CefValueCppToC::Wrap(_retval);
+}
+
+CEF_EXPORT cef_string_userfree_t
+cef_write_json(struct _cef_value_t* node, cef_json_writer_options_t options) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: node; type: refptr_same
+ DCHECK(node);
+ if (!node) {
+ return NULL;
+ }
+
+ // Execute
+ CefString _retval = CefWriteJSON(CefValueCppToC::Unwrap(node), options);
+
+ // Return type: string
+ return _retval.DetachToUserFree();
+}
+
+CEF_EXPORT int cef_get_path(cef_path_key_t key, cef_string_t* path) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: path; type: string_byref
+ DCHECK(path);
+ if (!path) {
+ return 0;
+ }
+
+ // Translate param: path; type: string_byref
+ CefString pathStr(path);
+
+ // Execute
+ bool _retval = CefGetPath(key, pathStr);
+
+ // Return type: bool
+ return _retval;
+}
+
+CEF_EXPORT int cef_launch_process(struct _cef_command_line_t* command_line) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: command_line; type: refptr_same
+ DCHECK(command_line);
+ if (!command_line) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefLaunchProcess(CefCommandLineCppToC::Unwrap(command_line));
+
+ // Return type: bool
+ return _retval;
+}
+
+CEF_EXPORT int cef_register_scheme_handler_factory(
+ const cef_string_t* scheme_name,
+ const cef_string_t* domain_name,
+ struct _cef_scheme_handler_factory_t* factory) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: scheme_name; type: string_byref_const
+ DCHECK(scheme_name);
+ if (!scheme_name) {
+ return 0;
+ }
+ // Unverified params: domain_name, factory
+
+ // Execute
+ bool _retval = CefRegisterSchemeHandlerFactory(
+ CefString(scheme_name), CefString(domain_name),
+ CefSchemeHandlerFactoryCToCpp::Wrap(factory));
+
+ // Return type: bool
+ return _retval;
+}
+
+CEF_EXPORT int cef_clear_scheme_handler_factories() {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ bool _retval = CefClearSchemeHandlerFactories();
+
+ // Return type: bool
+ return _retval;
+}
+
+CEF_EXPORT int cef_is_cert_status_error(cef_cert_status_t status) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ bool _retval = CefIsCertStatusError(status);
+
+ // Return type: bool
+ return _retval;
+}
+
+CEF_EXPORT int cef_currently_on(cef_thread_id_t threadId) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ bool _retval = CefCurrentlyOn(threadId);
+
+ // Return type: bool
+ return _retval;
+}
+
+CEF_EXPORT int cef_post_task(cef_thread_id_t threadId,
+ struct _cef_task_t* task) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: task; type: refptr_diff
+ DCHECK(task);
+ if (!task) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval = CefPostTask(threadId, CefTaskCToCpp::Wrap(task));
+
+ // Return type: bool
+ return _retval;
+}
+
+CEF_EXPORT int cef_post_delayed_task(cef_thread_id_t threadId,
+ struct _cef_task_t* task,
+ int64 delay_ms) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: task; type: refptr_diff
+ DCHECK(task);
+ if (!task) {
+ return 0;
+ }
+
+ // Execute
+ bool _retval =
+ CefPostDelayedTask(threadId, CefTaskCToCpp::Wrap(task), delay_ms);
+
+ // Return type: bool
+ return _retval;
+}
+
+CEF_EXPORT int cef_begin_tracing(const cef_string_t* categories,
+ struct _cef_completion_callback_t* callback) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: categories, callback
+
+ // Execute
+ bool _retval = CefBeginTracing(CefString(categories),
+ CefCompletionCallbackCToCpp::Wrap(callback));
+
+ // Return type: bool
+ return _retval;
+}
+
+CEF_EXPORT int cef_end_tracing(const cef_string_t* tracing_file,
+ struct _cef_end_tracing_callback_t* callback) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: tracing_file, callback
+
+ // Execute
+ bool _retval = CefEndTracing(CefString(tracing_file),
+ CefEndTracingCallbackCToCpp::Wrap(callback));
+
+ // Return type: bool
+ return _retval;
+}
+
+CEF_EXPORT int64 cef_now_from_system_trace_time() {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int64 _retval = CefNowFromSystemTraceTime();
+
+ // Return type: simple
+ return _retval;
+}
+
+CEF_EXPORT int cef_register_extension(const cef_string_t* extension_name,
+ const cef_string_t* javascript_code,
+ struct _cef_v8handler_t* handler) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: extension_name; type: string_byref_const
+ DCHECK(extension_name);
+ if (!extension_name) {
+ return 0;
+ }
+ // Verify param: javascript_code; type: string_byref_const
+ DCHECK(javascript_code);
+ if (!javascript_code) {
+ return 0;
+ }
+ // Unverified params: handler
+
+ // Execute
+ bool _retval = CefRegisterExtension(CefString(extension_name),
+ CefString(javascript_code),
+ CefV8HandlerCToCpp::Wrap(handler));
+
+ // Return type: bool
+ return _retval;
+}
+
+CEF_EXPORT void cef_execute_java_script_with_user_gesture_for_tests(
+ struct _cef_frame_t* frame,
+ const cef_string_t* javascript) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: frame; type: refptr_same
+ DCHECK(frame);
+ if (!frame) {
+ return;
+ }
+ // Unverified params: javascript
+
+ // Execute
+ CefExecuteJavaScriptWithUserGestureForTests(CefFrameCppToC::Unwrap(frame),
+ CefString(javascript));
+}
+
+CEF_EXPORT void cef_set_data_directory_for_tests(const cef_string_t* dir) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: dir; type: string_byref_const
+ DCHECK(dir);
+ if (!dir) {
+ return;
+ }
+
+ // Execute
+ CefSetDataDirectoryForTests(CefString(dir));
+}
diff --git a/libcef_dll/libcef_dll.rc b/libcef_dll/libcef_dll.rc
new file mode 100644
index 00000000..f01d627b
--- /dev/null
+++ b/libcef_dll/libcef_dll.rc
@@ -0,0 +1,143 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#define APSTUDIO_HIDDEN_SYMBOLS
+#include "windows.h"
+#include "include/cef_version.h"
+#undef APSTUDIO_HIDDEN_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#define APSTUDIO_HIDDEN_SYMBOLS\r\n"
+ "#include ""windows.h""\r\n"
+ "#include ""include/version.h""\r\n"
+ "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_ALERT DIALOGEX 0, 0, 241, 76
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "JavaScript Alert"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,184,55,50,14
+ LTEXT "",IDC_DIALOGTEXT,16,17,210,30
+END
+
+IDD_CONFIRM DIALOGEX 0, 0, 241, 76
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "JavaScript Confirm"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ PUSHBUTTON "Cancel",IDCANCEL,184,55,50,14
+ DEFPUSHBUTTON "OK",IDOK,131,55,50,14
+ LTEXT "",IDC_DIALOGTEXT,16,17,210,30
+END
+
+IDD_PROMPT DIALOGEX 0, 0, 241, 76
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "JavaScript Prompt"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,131,55,50,14
+ LTEXT "",IDC_DIALOGTEXT,16,17,210,18
+ PUSHBUTTON "Cancel",IDCANCEL,184,55,50,14
+ EDITTEXT IDC_PROMPTEDIT,15,33,210,14,ES_AUTOHSCROLL
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION CEF_VERSION_MAJOR,CEF_VERSION_MINOR,CEF_VERSION_PATCH,0
+ PRODUCTVERSION CEF_VERSION_MAJOR,CEF_VERSION_MINOR,CEF_VERSION_PATCH,0
+ FILEFLAGSMASK 0x17L
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "FileDescription", "Chromium Embedded Framework (CEF) Dynamic Link Library"
+ VALUE "FileVersion", CEF_VERSION
+ VALUE "InternalName", "libcef"
+ VALUE "LegalCopyright", "Copyright (C) " MAKE_STRING(COPYRIGHT_YEAR) " The Chromium Embedded Framework Authors"
+ VALUE "OriginalFilename", "libcef.dll"
+ VALUE "ProductName", "Chromium Embedded Framework (CEF) Dynamic Link Library"
+ VALUE "ProductVersion", CEF_VERSION
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/libcef_dll/libcef_dll2.cc b/libcef_dll/libcef_dll2.cc
new file mode 100644
index 00000000..cdf6ebe7
--- /dev/null
+++ b/libcef_dll/libcef_dll2.cc
@@ -0,0 +1,78 @@
+// Copyright (c) 2011 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+
+#include <cstddef>
+
+#include "include/base/cef_build.h"
+#include "include/cef_api_hash.h"
+#include "include/cef_version.h"
+
+#if defined(OS_WIN)
+#include "include/internal/cef_win.h"
+#endif
+
+CEF_EXPORT int cef_version_info(int entry) {
+ switch (entry) {
+ case 0:
+ return CEF_VERSION_MAJOR;
+ case 1:
+ return CEF_VERSION_MINOR;
+ case 2:
+ return CEF_VERSION_PATCH;
+ case 3:
+ return CEF_COMMIT_NUMBER;
+ case 4:
+ return CHROME_VERSION_MAJOR;
+ case 5:
+ return CHROME_VERSION_MINOR;
+ case 6:
+ return CHROME_VERSION_BUILD;
+ case 7:
+ return CHROME_VERSION_PATCH;
+ default:
+ return 0;
+ }
+}
+
+CEF_EXPORT const char* cef_api_hash(int entry) {
+ switch (entry) {
+ case 0:
+ return CEF_API_HASH_PLATFORM;
+ case 1:
+ return CEF_API_HASH_UNIVERSAL;
+ case 2:
+ return CEF_COMMIT_HASH;
+ default:
+ return NULL;
+ }
+}
+
+#if defined(OS_WIN)
+
+#if defined(ARCH_CPU_32_BITS)
+CEF_EXPORT int cef_run_winmain_with_preferred_stack_size(wWinMainPtr wWinMain,
+ HINSTANCE hInstance,
+ LPWSTR lpCmdLine,
+ int nCmdShow) {
+ return CefRunWinMainWithPreferredStackSize(wWinMain, hInstance, lpCmdLine,
+ nCmdShow);
+}
+
+CEF_EXPORT int cef_run_main_with_preferred_stack_size(mainPtr main,
+ int argc,
+ char* argv[]) {
+ return CefRunMainWithPreferredStackSize(main, argc, argv);
+}
+#endif // defined(ARCH_CPU_32_BITS)
+
+CEF_EXPORT void cef_enable_highdpi_support() {
+ CefEnableHighDPISupport();
+}
+
+CEF_EXPORT void cef_set_osmodal_loop(int osModalLoop) {
+ CefSetOSModalLoop(osModalLoop ? true : false);
+}
+
+#endif // defined(OS_WIN)
diff --git a/libcef_dll/resource.h b/libcef_dll/resource.h
new file mode 100644
index 00000000..a4a58891
--- /dev/null
+++ b/libcef_dll/resource.h
@@ -0,0 +1,25 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by libcef_dll.rc
+//
+
+// Avoid files associated with MacOS
+#define _X86_
+
+#define IDD_ALERT 130
+#define IDD_CONFIRM 131
+#define IDD_PROMPT 132
+#define IDC_PROMPTEDIT 1000
+#define IDC_DIALOGTEXT 1001
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NO_MFC 1
+#define _APS_NEXT_RESOURCE_VALUE 130
+#define _APS_NEXT_COMMAND_VALUE 32000
+#define _APS_NEXT_CONTROL_VALUE 1000
+#define _APS_NEXT_SYMED_VALUE 110
+#endif
+#endif
diff --git a/libcef_dll/sandbox/sandbox_mac.mm b/libcef_dll/sandbox/sandbox_mac.mm
new file mode 100644
index 00000000..f3afaff3
--- /dev/null
+++ b/libcef_dll/sandbox/sandbox_mac.mm
@@ -0,0 +1,66 @@
+// Copyright 2018 The Chromium Embedded Framework Authors. Portions Copyright
+// 2018 the Chromium Authors. All rights reserved. Use of this source code is
+// governed by a BSD-style license that can be found in the LICENSE file.
+
+#include <mach-o/dyld.h>
+#include <stdio.h>
+
+#include <memory>
+
+#include "sandbox/mac/seatbelt_exec.h"
+
+#include "include/cef_sandbox_mac.h"
+
+void* cef_sandbox_initialize(int argc, char** argv) {
+ uint32_t exec_path_size = 0;
+ int rv = _NSGetExecutablePath(NULL, &exec_path_size);
+ if (rv != -1) {
+ return NULL;
+ }
+
+ std::unique_ptr<char[]> exec_path(new char[exec_path_size]);
+ rv = _NSGetExecutablePath(exec_path.get(), &exec_path_size);
+ if (rv != 0) {
+ return NULL;
+ }
+
+ sandbox::SeatbeltExecServer::CreateFromArgumentsResult seatbelt =
+ sandbox::SeatbeltExecServer::CreateFromArguments(exec_path.get(), argc,
+ argv);
+ if (seatbelt.sandbox_required) {
+ if (!seatbelt.server) {
+ fprintf(stderr, "Failed to create the seatbelt sandbox server.\n");
+ return NULL;
+ }
+ if (!seatbelt.server->InitializeSandbox()) {
+ fprintf(stderr, "Failed to initialize the sandbox.\n");
+ return NULL;
+ }
+ }
+
+ auto* copy = new sandbox::SeatbeltExecServer::CreateFromArgumentsResult();
+ copy->sandbox_required = seatbelt.sandbox_required;
+ copy->server.swap(seatbelt.server);
+ return copy;
+}
+
+void cef_sandbox_destroy(void* sandbox_context) {
+ delete static_cast<sandbox::SeatbeltExecServer::CreateFromArgumentsResult*>(
+ sandbox_context);
+}
+
+CefScopedSandboxContext::CefScopedSandboxContext() : sandbox_context_(NULL) {}
+
+CefScopedSandboxContext::~CefScopedSandboxContext() {
+ if (sandbox_context_) {
+ cef_sandbox_destroy(sandbox_context_);
+ }
+}
+
+bool CefScopedSandboxContext::Initialize(int argc, char** argv) {
+ if (sandbox_context_) {
+ return false;
+ }
+ sandbox_context_ = cef_sandbox_initialize(argc, argv);
+ return !!sandbox_context_;
+}
diff --git a/libcef_dll/sandbox/sandbox_win.cc b/libcef_dll/sandbox/sandbox_win.cc
new file mode 100644
index 00000000..bb5c77c5
--- /dev/null
+++ b/libcef_dll/sandbox/sandbox_win.cc
@@ -0,0 +1,57 @@
+// Copyright 2013 The Chromium Embedded Framework Authors. Portions Copyright
+// 2011 the Chromium Authors. All rights reserved. Use of this source code is
+// governed by a BSD-style license that can be found in the LICENSE file.
+
+#include "base/notreached.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/sandbox_factory.h"
+
+#include "cef/libcef/features/features.h"
+#include "include/cef_sandbox_win.h"
+
+namespace {
+
+// From content/app/sandbox_helper_win.cc:
+void InitializeSandboxInfo(sandbox::SandboxInterfaceInfo* info) {
+ info->broker_services = sandbox::SandboxFactory::GetBrokerServices();
+ if (info->broker_services) {
+ // Ensure the proper mitigations are enforced for the browser process.
+ info->broker_services->RatchetDownSecurityMitigations(
+ sandbox::MITIGATION_DEP | sandbox::MITIGATION_DEP_NO_ATL_THUNK |
+ sandbox::MITIGATION_HARDEN_TOKEN_IL_POLICY);
+ // Note: these mitigations are "post-startup". Some mitigations that need
+ // to be enabled sooner (e.g. MITIGATION_EXTENSION_POINT_DISABLE) are done
+ // so in Chrome_ELF.
+ } else {
+ info->target_services = sandbox::SandboxFactory::GetTargetServices();
+ }
+}
+
+} // namespace
+
+void* cef_sandbox_info_create() {
+ sandbox::SandboxInterfaceInfo* info = new sandbox::SandboxInterfaceInfo();
+ memset(info, 0, sizeof(sandbox::SandboxInterfaceInfo));
+ InitializeSandboxInfo(info);
+ return info;
+}
+
+void cef_sandbox_info_destroy(void* sandbox_info) {
+ delete static_cast<sandbox::SandboxInterfaceInfo*>(sandbox_info);
+}
+
+#if BUILDFLAG(IS_CEF_SANDBOX_BUILD)
+
+// Avoid bringing in partition_alloc dependencies.
+namespace partition_alloc {
+bool ReleaseReservation() {
+ NOTREACHED();
+ return false;
+}
+
+void TerminateBecauseOutOfMemory(size_t size) {
+ NOTREACHED();
+}
+} // namespace partition_alloc
+
+#endif // BUILDFLAG(IS_CEF_SANDBOX_BUILD)
diff --git a/libcef_dll/shutdown_checker.cc b/libcef_dll/shutdown_checker.cc
new file mode 100644
index 00000000..e5646a7e
--- /dev/null
+++ b/libcef_dll/shutdown_checker.cc
@@ -0,0 +1,45 @@
+// Copyright (c) 2019 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "libcef_dll/shutdown_checker.h"
+
+#include <atomic>
+
+#include "include/base/cef_logging.h"
+
+namespace shutdown_checker {
+
+#if DCHECK_IS_ON()
+
+namespace {
+
+std::atomic_bool g_cef_shutdown{false};
+
+bool IsCefShutdown() {
+ return g_cef_shutdown.load();
+}
+
+void SetCefShutdown() {
+ g_cef_shutdown.store(true);
+}
+
+} // namespace
+
+void AssertNotShutdown() {
+ DCHECK(!IsCefShutdown())
+ << "Object reference incorrectly held at CefShutdown";
+}
+
+void SetIsShutdown() {
+ DCHECK(!IsCefShutdown());
+ SetCefShutdown();
+}
+
+#else // !DCHECK_IS_ON()
+
+void AssertNotShutdown() {}
+
+#endif // !DCHECK_IS_ON()
+
+} // namespace shutdown_checker
diff --git a/libcef_dll/shutdown_checker.h b/libcef_dll/shutdown_checker.h
new file mode 100644
index 00000000..9d447881
--- /dev/null
+++ b/libcef_dll/shutdown_checker.h
@@ -0,0 +1,19 @@
+// Copyright (c) 2019 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_DLL_SHUTDOWN_CHECKER_H_
+#define CEF_LIBCEF_DLL_SHUTDOWN_CHECKER_H_
+#pragma once
+
+namespace shutdown_checker {
+
+// Check that CEF objects are not held at CefShutdown.
+void AssertNotShutdown();
+
+// Called from libcef_dll.cc and libcef_dll_wrapper.cc.
+void SetIsShutdown();
+
+} // namespace shutdown_checker
+
+#endif // CEF_LIBCEF_DLL_SHUTDOWN_CHECKER_H_
diff --git a/libcef_dll/template_util.h b/libcef_dll/template_util.h
new file mode 100644
index 00000000..4749f2c5
--- /dev/null
+++ b/libcef_dll/template_util.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_DLL_TEMPLATE_UTIL_H_
+#define CEF_LIBCEF_DLL_TEMPLATE_UTIL_H_
+#pragma once
+
+#include <type_traits>
+
+namespace template_util {
+
+// Used to detect whether the given C struct has a size_t size field or has a
+// base field and a base field has a size field.
+template <typename T, typename = void>
+struct HasValidSize {
+ bool operator()(const T*) { return true; }
+};
+template <typename T>
+struct HasValidSize<
+ T,
+ typename std::enable_if_t<std::is_same<decltype(T::size), size_t>::value>> {
+ bool operator()(const T* s) { return s->size == sizeof(*s); }
+};
+template <typename T>
+struct HasValidSize<T, decltype(void(T::base.size))> {
+ bool operator()(const T* s) { return s->base.size == sizeof(*s); }
+};
+
+template <typename T>
+inline bool has_valid_size(const T* s) {
+ return HasValidSize<T>()(s);
+}
+
+} // namespace template_util
+
+#endif // CEF_LIBCEF_DLL_TEMPLATE_UTIL_H_
diff --git a/libcef_dll/transfer_util.cc b/libcef_dll/transfer_util.cc
new file mode 100644
index 00000000..47ad1359
--- /dev/null
+++ b/libcef_dll/transfer_util.cc
@@ -0,0 +1,66 @@
+// Copyright (c) 2009 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "libcef_dll/transfer_util.h"
+
+void transfer_string_list_contents(cef_string_list_t fromList,
+ StringList& toList) {
+ size_t size = cef_string_list_size(fromList);
+ CefString value;
+
+ for (size_t i = 0; i < size; i++) {
+ cef_string_list_value(fromList, i, value.GetWritableStruct());
+ toList.push_back(value);
+ }
+}
+
+void transfer_string_list_contents(const StringList& fromList,
+ cef_string_list_t toList) {
+ size_t size = fromList.size();
+ for (size_t i = 0; i < size; ++i) {
+ cef_string_list_append(toList, fromList[i].GetStruct());
+ }
+}
+
+void transfer_string_map_contents(cef_string_map_t fromMap, StringMap& toMap) {
+ size_t size = cef_string_map_size(fromMap);
+ CefString key, value;
+
+ for (size_t i = 0; i < size; ++i) {
+ cef_string_map_key(fromMap, i, key.GetWritableStruct());
+ cef_string_map_value(fromMap, i, value.GetWritableStruct());
+
+ toMap.insert(std::make_pair(key, value));
+ }
+}
+
+void transfer_string_map_contents(const StringMap& fromMap,
+ cef_string_map_t toMap) {
+ StringMap::const_iterator it = fromMap.begin();
+ for (; it != fromMap.end(); ++it) {
+ cef_string_map_append(toMap, it->first.GetStruct(), it->second.GetStruct());
+ }
+}
+
+void transfer_string_multimap_contents(cef_string_multimap_t fromMap,
+ StringMultimap& toMap) {
+ size_t size = cef_string_multimap_size(fromMap);
+ CefString key, value;
+
+ for (size_t i = 0; i < size; ++i) {
+ cef_string_multimap_key(fromMap, i, key.GetWritableStruct());
+ cef_string_multimap_value(fromMap, i, value.GetWritableStruct());
+
+ toMap.insert(std::make_pair(key, value));
+ }
+}
+
+void transfer_string_multimap_contents(const StringMultimap& fromMap,
+ cef_string_multimap_t toMap) {
+ StringMultimap::const_iterator it = fromMap.begin();
+ for (; it != fromMap.end(); ++it) {
+ cef_string_multimap_append(toMap, it->first.GetStruct(),
+ it->second.GetStruct());
+ }
+}
diff --git a/libcef_dll/transfer_util.h b/libcef_dll/transfer_util.h
new file mode 100644
index 00000000..6da9ae15
--- /dev/null
+++ b/libcef_dll/transfer_util.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2009 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_DLL_TRANSFER_UTIL_H_
+#define CEF_LIBCEF_DLL_TRANSFER_UTIL_H_
+#pragma once
+
+#include <map>
+#include <vector>
+
+#include "include/internal/cef_string_list.h"
+#include "include/internal/cef_string_map.h"
+#include "include/internal/cef_string_multimap.h"
+
+// Copy contents from one list type to another.
+using StringList = std::vector<CefString>;
+void transfer_string_list_contents(cef_string_list_t fromList,
+ StringList& toList);
+void transfer_string_list_contents(const StringList& fromList,
+ cef_string_list_t toList);
+
+// Copy contents from one map type to another.
+using StringMap = std::map<CefString, CefString>;
+void transfer_string_map_contents(cef_string_map_t fromMap, StringMap& toMap);
+void transfer_string_map_contents(const StringMap& fromMap,
+ cef_string_map_t toMap);
+
+// Copy contents from one map type to another.
+using StringMultimap = std::multimap<CefString, CefString>;
+void transfer_string_multimap_contents(cef_string_multimap_t fromMap,
+ StringMultimap& toMap);
+void transfer_string_multimap_contents(const StringMultimap& fromMap,
+ cef_string_multimap_t toMap);
+
+#endif // CEF_LIBCEF_DLL_TRANSFER_UTIL_H_
diff --git a/libcef_dll/wrapper/cef_browser_info_map.h b/libcef_dll/wrapper/cef_browser_info_map.h
new file mode 100644
index 00000000..24459ce7
--- /dev/null
+++ b/libcef_dll/wrapper/cef_browser_info_map.h
@@ -0,0 +1,281 @@
+// Copyright (c) 2014 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_LIBCEF_DLL_WRAPPER_CEF_BROWSER_INFO_MAP_H_
+#define CEF_LIBCEF_DLL_WRAPPER_CEF_BROWSER_INFO_MAP_H_
+#pragma once
+
+#include <map>
+
+#include "include/base/cef_logging.h"
+
+// Default traits for CefBrowserInfoMap. Override to provide different object
+// destruction behavior.
+template <typename ObjectType>
+struct DefaultCefBrowserInfoMapTraits {
+ static void Destruct(ObjectType info) { delete info; }
+};
+
+// Maps an arbitrary IdType to an arbitrary ObjectType on a per-browser basis.
+template <typename IdType,
+ typename ObjectType,
+ typename Traits = DefaultCefBrowserInfoMapTraits<ObjectType>>
+class CefBrowserInfoMap {
+ public:
+ // Implement this interface to visit and optionally delete objects in the map.
+ class Visitor {
+ public:
+ using InfoIdType = IdType;
+ using InfoObjectType = ObjectType;
+
+ // Called once for each info object. Set |remove| to true to remove the
+ // object from the map. It is safe to destruct removed objects in this
+ // callback. Return true to continue iterating or false to stop iterating.
+ virtual bool OnNextInfo(int browser_id,
+ InfoIdType info_id,
+ InfoObjectType info,
+ bool* remove) = 0;
+
+ protected:
+ virtual ~Visitor() {}
+ };
+
+ CefBrowserInfoMap() = default;
+
+ CefBrowserInfoMap(const CefBrowserInfoMap&) = delete;
+ CefBrowserInfoMap& operator=(const CefBrowserInfoMap&) = delete;
+
+ ~CefBrowserInfoMap() { clear(); }
+
+ // Add an object associated with the specified ID values.
+ void Add(int browser_id, IdType info_id, ObjectType info) {
+ InfoMap* info_map = nullptr;
+ typename BrowserInfoMap::const_iterator it_browser =
+ browser_info_map_.find(browser_id);
+ if (it_browser == browser_info_map_.end()) {
+ // No InfoMap exists for the browser ID so create it.
+ info_map = new InfoMap;
+ browser_info_map_.insert(std::make_pair(browser_id, info_map));
+ } else {
+ info_map = it_browser->second;
+ // The specified ID should not already exist in the map.
+ DCHECK(info_map->find(info_id) == info_map->end());
+ }
+
+ info_map->insert(std::make_pair(info_id, info));
+ }
+
+ // Find the object with the specified ID values. |visitor| can optionally be
+ // used to evaluate or remove the object at the same time. If the object is
+ // removed using the Visitor the caller is responsible for destroying it.
+ ObjectType Find(int browser_id, IdType info_id, Visitor* vistor) {
+ if (browser_info_map_.empty()) {
+ return ObjectType();
+ }
+
+ typename BrowserInfoMap::iterator it_browser =
+ browser_info_map_.find(browser_id);
+ if (it_browser == browser_info_map_.end()) {
+ return ObjectType();
+ }
+
+ InfoMap* info_map = it_browser->second;
+ typename InfoMap::iterator it_info = info_map->find(info_id);
+ if (it_info == info_map->end()) {
+ return ObjectType();
+ }
+
+ ObjectType info = it_info->second;
+
+ bool remove = false;
+ if (vistor) {
+ vistor->OnNextInfo(browser_id, it_info->first, info, &remove);
+ }
+ if (remove) {
+ info_map->erase(it_info);
+
+ if (info_map->empty()) {
+ // No more entries in the InfoMap so remove it.
+ browser_info_map_.erase(it_browser);
+ delete info_map;
+ }
+ }
+
+ return info;
+ }
+
+ // Find all objects. If any objects are removed using the Visitor the caller
+ // is responsible for destroying them.
+ void FindAll(Visitor* visitor) {
+ DCHECK(visitor);
+
+ if (browser_info_map_.empty()) {
+ return;
+ }
+
+ bool remove, keepgoing = true;
+
+ typename BrowserInfoMap::iterator it_browser = browser_info_map_.begin();
+ while (it_browser != browser_info_map_.end()) {
+ InfoMap* info_map = it_browser->second;
+
+ typename InfoMap::iterator it_info = info_map->begin();
+ while (it_info != info_map->end()) {
+ remove = false;
+ keepgoing = visitor->OnNextInfo(it_browser->first, it_info->first,
+ it_info->second, &remove);
+
+ if (remove) {
+ info_map->erase(it_info++);
+ } else {
+ ++it_info;
+ }
+
+ if (!keepgoing) {
+ break;
+ }
+ }
+
+ if (info_map->empty()) {
+ // No more entries in the InfoMap so remove it.
+ browser_info_map_.erase(it_browser++);
+ delete info_map;
+ } else {
+ ++it_browser;
+ }
+
+ if (!keepgoing) {
+ break;
+ }
+ }
+ }
+
+ // Find all objects associated with the specified browser. If any objects are
+ // removed using the Visitor the caller is responsible for destroying them.
+ void FindAll(int browser_id, Visitor* visitor) {
+ DCHECK(visitor);
+
+ if (browser_info_map_.empty()) {
+ return;
+ }
+
+ typename BrowserInfoMap::iterator it_browser =
+ browser_info_map_.find(browser_id);
+ if (it_browser == browser_info_map_.end()) {
+ return;
+ }
+
+ InfoMap* info_map = it_browser->second;
+ bool remove, keepgoing;
+
+ typename InfoMap::iterator it_info = info_map->begin();
+ while (it_info != info_map->end()) {
+ remove = false;
+ keepgoing = visitor->OnNextInfo(browser_id, it_info->first,
+ it_info->second, &remove);
+
+ if (remove) {
+ info_map->erase(it_info++);
+ } else {
+ ++it_info;
+ }
+
+ if (!keepgoing) {
+ break;
+ }
+ }
+
+ if (info_map->empty()) {
+ // No more entries in the InfoMap so remove it.
+ browser_info_map_.erase(it_browser);
+ delete info_map;
+ }
+ }
+
+ // Returns true if the map is empty.
+ bool empty() const { return browser_info_map_.empty(); }
+
+ // Returns the number of objects in the map.
+ size_t size() const {
+ if (browser_info_map_.empty()) {
+ return 0;
+ }
+
+ size_t size = 0;
+ typename BrowserInfoMap::const_iterator it_browser =
+ browser_info_map_.begin();
+ for (; it_browser != browser_info_map_.end(); ++it_browser) {
+ size += it_browser->second->size();
+ }
+ return size;
+ }
+
+ // Returns the number of objects in the map that are associated with the
+ // specified browser.
+ size_t size(int browser_id) const {
+ if (browser_info_map_.empty()) {
+ return 0;
+ }
+
+ typename BrowserInfoMap::const_iterator it_browser =
+ browser_info_map_.find(browser_id);
+ if (it_browser != browser_info_map_.end()) {
+ return it_browser->second->size();
+ }
+
+ return 0;
+ }
+
+ // Remove all objects from the map. The objects will be destructed.
+ void clear() {
+ if (browser_info_map_.empty()) {
+ return;
+ }
+
+ typename BrowserInfoMap::const_iterator it_browser =
+ browser_info_map_.begin();
+ for (; it_browser != browser_info_map_.end(); ++it_browser) {
+ InfoMap* info_map = it_browser->second;
+ typename InfoMap::const_iterator it_info = info_map->begin();
+ for (; it_info != info_map->end(); ++it_info) {
+ Traits::Destruct(it_info->second);
+ }
+ delete info_map;
+ }
+ browser_info_map_.clear();
+ }
+
+ // Remove all objects from the map that are associated with the specified
+ // browser. The objects will be destructed.
+ void clear(int browser_id) {
+ if (browser_info_map_.empty()) {
+ return;
+ }
+
+ typename BrowserInfoMap::iterator it_browser =
+ browser_info_map_.find(browser_id);
+ if (it_browser == browser_info_map_.end()) {
+ return;
+ }
+
+ InfoMap* info_map = it_browser->second;
+ typename InfoMap::const_iterator it_info = info_map->begin();
+ for (; it_info != info_map->end(); ++it_info) {
+ Traits::Destruct(it_info->second);
+ }
+
+ browser_info_map_.erase(it_browser);
+ delete info_map;
+ }
+
+ private:
+ // Map IdType to ObjectType instance.
+ using InfoMap = std::map<IdType, ObjectType>;
+ // Map browser ID to InfoMap instance.
+ using BrowserInfoMap = std::map<int, InfoMap*>;
+
+ BrowserInfoMap browser_info_map_;
+};
+
+#endif // CEF_LIBCEF_DLL_WRAPPER_CEF_BROWSER_INFO_MAP_H_
diff --git a/libcef_dll/wrapper/cef_byte_read_handler.cc b/libcef_dll/wrapper/cef_byte_read_handler.cc
new file mode 100644
index 00000000..c1690e68
--- /dev/null
+++ b/libcef_dll/wrapper/cef_byte_read_handler.cc
@@ -0,0 +1,69 @@
+// Copyright (c) 2010 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "include/wrapper/cef_byte_read_handler.h"
+
+#include <algorithm>
+#include <cstdio>
+#include <cstdlib>
+
+CefByteReadHandler::CefByteReadHandler(const unsigned char* bytes,
+ size_t size,
+ CefRefPtr<CefBaseRefCounted> source)
+ : bytes_(bytes), size_(size), offset_(0), source_(source) {}
+
+size_t CefByteReadHandler::Read(void* ptr, size_t size, size_t n) {
+ base::AutoLock lock_scope(lock_);
+ size_t s = static_cast<size_t>(size_ - offset_) / size;
+ size_t ret = std::min(n, s);
+ memcpy(ptr, bytes_ + offset_, ret * size);
+ offset_ += ret * size;
+ return ret;
+}
+
+int CefByteReadHandler::Seek(int64 offset, int whence) {
+ int rv = -1L;
+ base::AutoLock lock_scope(lock_);
+ switch (whence) {
+ case SEEK_CUR:
+ if (offset_ + offset > size_ || offset_ + offset < 0) {
+ break;
+ }
+ offset_ += offset;
+ rv = 0;
+ break;
+ case SEEK_END: {
+#if defined(OS_WIN)
+ int64 offset_abs = _abs64(offset);
+#else
+ int64 offset_abs = std::abs(offset);
+#endif
+ if (offset_abs > size_) {
+ break;
+ }
+ offset_ = size_ - offset_abs;
+ rv = 0;
+ break;
+ }
+ case SEEK_SET:
+ if (offset > size_ || offset < 0) {
+ break;
+ }
+ offset_ = offset;
+ rv = 0;
+ break;
+ }
+
+ return rv;
+}
+
+int64 CefByteReadHandler::Tell() {
+ base::AutoLock lock_scope(lock_);
+ return offset_;
+}
+
+int CefByteReadHandler::Eof() {
+ base::AutoLock lock_scope(lock_);
+ return (offset_ >= size_);
+}
diff --git a/libcef_dll/wrapper/cef_closure_task.cc b/libcef_dll/wrapper/cef_closure_task.cc
new file mode 100644
index 00000000..aa8c6482
--- /dev/null
+++ b/libcef_dll/wrapper/cef_closure_task.cc
@@ -0,0 +1,80 @@
+// Copyright (c) 2014 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "include/wrapper/cef_closure_task.h"
+
+#include <memory>
+
+#include "include/base/cef_callback.h"
+
+namespace {
+
+class CefOnceClosureTask : public CefTask {
+ public:
+ explicit CefOnceClosureTask(base::OnceClosure closure)
+ : closure_(std::move(closure)) {}
+
+ CefOnceClosureTask(const CefOnceClosureTask&) = delete;
+ CefOnceClosureTask& operator=(const CefOnceClosureTask&) = delete;
+
+ // CefTask method
+ void Execute() override { std::move(closure_).Run(); }
+
+ private:
+ base::OnceClosure closure_;
+
+ IMPLEMENT_REFCOUNTING(CefOnceClosureTask);
+};
+
+class CefRepeatingClosureTask : public CefTask {
+ public:
+ explicit CefRepeatingClosureTask(const base::RepeatingClosure& closure)
+ : closure_(closure) {}
+
+ CefRepeatingClosureTask(const CefRepeatingClosureTask&) = delete;
+ CefRepeatingClosureTask& operator=(const CefRepeatingClosureTask&) = delete;
+
+ // CefTask method
+ void Execute() override {
+ closure_.Run();
+ closure_.Reset();
+ }
+
+ private:
+ base::RepeatingClosure closure_;
+
+ IMPLEMENT_REFCOUNTING(CefRepeatingClosureTask);
+};
+
+} // namespace
+
+CefRefPtr<CefTask> CefCreateClosureTask(base::OnceClosure closure) {
+ return new CefOnceClosureTask(std::move(closure));
+}
+
+CefRefPtr<CefTask> CefCreateClosureTask(const base::RepeatingClosure& closure) {
+ return new CefRepeatingClosureTask(closure);
+}
+
+bool CefPostTask(CefThreadId threadId, base::OnceClosure closure) {
+ return CefPostTask(threadId, new CefOnceClosureTask(std::move(closure)));
+}
+
+bool CefPostTask(CefThreadId threadId, const base::RepeatingClosure& closure) {
+ return CefPostTask(threadId, new CefRepeatingClosureTask(closure));
+}
+
+bool CefPostDelayedTask(CefThreadId threadId,
+ base::OnceClosure closure,
+ int64 delay_ms) {
+ return CefPostDelayedTask(
+ threadId, new CefOnceClosureTask(std::move(closure)), delay_ms);
+}
+
+bool CefPostDelayedTask(CefThreadId threadId,
+ const base::RepeatingClosure& closure,
+ int64 delay_ms) {
+ return CefPostDelayedTask(threadId, new CefRepeatingClosureTask(closure),
+ delay_ms);
+}
diff --git a/libcef_dll/wrapper/cef_library_loader_mac.mm b/libcef_dll/wrapper/cef_library_loader_mac.mm
new file mode 100644
index 00000000..046f46b0
--- /dev/null
+++ b/libcef_dll/wrapper/cef_library_loader_mac.mm
@@ -0,0 +1,77 @@
+// Copyright (c) 2018 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "include/wrapper/cef_library_loader.h"
+
+#include <libgen.h>
+#include <mach-o/dyld.h>
+#include <stdio.h>
+
+#include <memory>
+#include <sstream>
+
+namespace {
+
+const char kFrameworkPath[] =
+ "Chromium Embedded Framework.framework/Chromium Embedded Framework";
+const char kPathFromHelperExe[] = "../../..";
+const char kPathFromMainExe[] = "../Frameworks";
+
+std::string GetFrameworkPath(bool helper) {
+ uint32_t exec_path_size = 0;
+ int rv = _NSGetExecutablePath(NULL, &exec_path_size);
+ if (rv != -1) {
+ return std::string();
+ }
+
+ std::unique_ptr<char[]> exec_path(new char[exec_path_size]);
+ rv = _NSGetExecutablePath(exec_path.get(), &exec_path_size);
+ if (rv != 0) {
+ return std::string();
+ }
+
+ // Get the directory path of the executable.
+ const char* parent_dir = dirname(exec_path.get());
+ if (!parent_dir) {
+ return std::string();
+ }
+
+ // Append the relative path to the framework.
+ std::stringstream ss;
+ ss << parent_dir << "/" << (helper ? kPathFromHelperExe : kPathFromMainExe)
+ << "/" << kFrameworkPath;
+ return ss.str();
+}
+
+} // namespace
+
+CefScopedLibraryLoader::CefScopedLibraryLoader() : loaded_(false) {}
+
+bool CefScopedLibraryLoader::Load(bool helper) {
+ if (loaded_) {
+ return false;
+ }
+
+ const std::string& framework_path = GetFrameworkPath(helper);
+ if (framework_path.empty()) {
+ fprintf(stderr, "App does not have the expected bundle structure.\n");
+ return false;
+ }
+
+ // Load the CEF framework library.
+ if (!cef_load_library(framework_path.c_str())) {
+ fprintf(stderr, "Failed to load the CEF framework.\n");
+ return false;
+ }
+
+ loaded_ = true;
+ return true;
+}
+
+CefScopedLibraryLoader::~CefScopedLibraryLoader() {
+ if (loaded_) {
+ // Unload the CEF framework library.
+ cef_unload_library();
+ }
+}
diff --git a/libcef_dll/wrapper/cef_message_router.cc b/libcef_dll/wrapper/cef_message_router.cc
new file mode 100644
index 00000000..13fd31b9
--- /dev/null
+++ b/libcef_dll/wrapper/cef_message_router.cc
@@ -0,0 +1,1270 @@
+// Copyright (c) 2014 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "include/wrapper/cef_message_router.h"
+
+#include <map>
+#include <set>
+
+#include "include/base/cef_callback.h"
+#include "include/cef_shared_process_message_builder.h"
+#include "include/cef_task.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "include/wrapper/cef_helpers.h"
+#include "libcef_dll/wrapper/cef_browser_info_map.h"
+
+namespace {
+
+// ID value reserved for internal use.
+const int kReservedId = 0;
+
+// Appended to the JS function name for related IPC messages.
+const char kMessageSuffix[] = "Msg";
+
+// JS object member argument names for cefQuery.
+const char kMemberRequest[] = "request";
+const char kMemberOnSuccess[] = "onSuccess";
+const char kMemberOnFailure[] = "onFailure";
+const char kMemberPersistent[] = "persistent";
+
+// Default error information when a query is canceled.
+const int kCanceledErrorCode = -1;
+const char kCanceledErrorMessage[] = "The query has been canceled";
+
+// Value of 16KB is chosen as a result of performance tests available at
+// http://tests/ipc_performance
+constexpr size_t kResponseSizeThreshold = 16384;
+
+// Validate configuration settings.
+bool ValidateConfig(CefMessageRouterConfig& config) {
+ // Must specify function names.
+ if (config.js_cancel_function.empty() || config.js_query_function.empty()) {
+ return false;
+ }
+
+ return true;
+}
+
+struct MessageHeader {
+ int context_id;
+ int request_id;
+ bool is_success;
+};
+
+struct ParsedMessage {
+ int context_id;
+ int request_id;
+ bool success;
+ int error_code;
+ CefString message;
+};
+
+size_t GetMessageSize(const CefString& response) {
+ return sizeof(MessageHeader) +
+ (response.size() * sizeof(CefString::char_type));
+}
+
+void CopyResponseIntoMemory(void* memory, const CefString& response) {
+ const size_t bytes = response.size() * sizeof(CefString::char_type);
+ void* dest = static_cast<uint8_t*>(memory) + sizeof(MessageHeader);
+ memcpy(dest, response.c_str(), bytes);
+}
+
+CefString GetStringFromMemory(const void* memory, size_t size) {
+ const size_t bytes = size - sizeof(MessageHeader);
+ const size_t string_len = bytes / sizeof(CefString::char_type);
+ const CefString::char_type* src =
+ reinterpret_cast<const CefString::char_type*>(
+ static_cast<const uint8_t*>(memory) + sizeof(MessageHeader));
+ constexpr bool copy = true;
+ CefString result;
+ result.FromString(src, string_len, copy);
+ return result;
+}
+
+CefRefPtr<CefProcessMessage> BuildListMessage(const std::string& message_name,
+ int context_id,
+ int request_id,
+ const CefString& response) {
+ auto message = CefProcessMessage::Create(message_name);
+ CefRefPtr<CefListValue> args = message->GetArgumentList();
+ args->SetInt(0, context_id);
+ args->SetInt(1, request_id);
+ args->SetBool(2, true); // Indicates a success result.
+ args->SetString(3, response);
+ return message;
+}
+
+CefRefPtr<CefProcessMessage> BuildBinaryMessage(const std::string& message_name,
+ int context_id,
+ int request_id,
+ const CefString& response) {
+ const size_t message_size = GetMessageSize(response);
+ auto builder =
+ CefSharedProcessMessageBuilder::Create(message_name, message_size);
+ if (!builder->IsValid()) {
+ LOG(ERROR) << "Failed to allocate shared memory region of size "
+ << message_size;
+ // Use list message as a fallback
+ return BuildListMessage(message_name, context_id, request_id, response);
+ }
+
+ auto header = static_cast<MessageHeader*>(builder->Memory());
+ header->context_id = context_id;
+ header->request_id = request_id;
+ header->is_success = true;
+
+ CopyResponseIntoMemory(builder->Memory(), response);
+
+ return builder->Build();
+}
+
+CefRefPtr<CefProcessMessage> BuildMessage(size_t threshold,
+ const std::string& message_name,
+ int context_id,
+ int request_id,
+ const CefString& response) {
+ if (response.size() <= threshold) {
+ return BuildListMessage(message_name, context_id, request_id, response);
+ } else {
+ return BuildBinaryMessage(message_name, context_id, request_id, response);
+ }
+}
+
+ParsedMessage ParseMessage(const CefRefPtr<CefProcessMessage>& message) {
+ if (auto args = message->GetArgumentList()) {
+ DCHECK_GT(args->GetSize(), 3U);
+
+ const int context_id = args->GetInt(0);
+ const int request_id = args->GetInt(1);
+ const bool is_success = args->GetBool(2);
+
+ if (is_success) {
+ return ParsedMessage{context_id, request_id, is_success, 0,
+ args->GetString(3)};
+ }
+
+ DCHECK_EQ(args->GetSize(), 5U);
+ return ParsedMessage{context_id, request_id, is_success, args->GetInt(3),
+ args->GetString(4)};
+ }
+
+ if (const auto region = message->GetSharedMemoryRegion()) {
+ if (region->IsValid()) {
+ DCHECK_GE(region->Size(), sizeof(MessageHeader));
+ auto header = static_cast<const MessageHeader*>(region->Memory());
+ DCHECK(header->is_success);
+ return ParsedMessage{
+ header->context_id, header->request_id, header->is_success, 0,
+ GetStringFromMemory(region->Memory(), region->Size())};
+ }
+ }
+
+ return ParsedMessage{};
+}
+
+// Helper template for generated ID values.
+template <typename T>
+class IdGenerator {
+ public:
+ IdGenerator() : next_id_(kReservedId) {}
+
+ IdGenerator(const IdGenerator&) = delete;
+ IdGenerator& operator=(const IdGenerator&) = delete;
+
+ T GetNextId() {
+ T id = ++next_id_;
+ if (id == kReservedId) { // In case the integer value wraps.
+ id = ++next_id_;
+ }
+ return id;
+ }
+
+ private:
+ T next_id_;
+};
+
+// Browser-side router implementation.
+class CefMessageRouterBrowserSideImpl : public CefMessageRouterBrowserSide {
+ public:
+ // Implementation of the Callback interface.
+ class CallbackImpl : public CefMessageRouterBrowserSide::Callback {
+ public:
+ CallbackImpl(CefRefPtr<CefMessageRouterBrowserSideImpl> router,
+ int browser_id,
+ int64 query_id,
+ bool persistent)
+ : router_(router),
+ browser_id_(browser_id),
+ query_id_(query_id),
+ persistent_(persistent) {}
+
+ CallbackImpl(const CallbackImpl&) = delete;
+ CallbackImpl& operator=(const CallbackImpl&) = delete;
+
+ virtual ~CallbackImpl() {
+ // Hitting this DCHECK means that you didn't call Success or Failure
+ // on the Callback after returning true from Handler::OnQuery. You must
+ // call Failure to terminate persistent queries.
+ DCHECK(!router_);
+ }
+
+ void Success(const CefString& response) override {
+ if (!CefCurrentlyOn(TID_UI)) {
+ // Must execute on the UI thread to access member variables.
+ CefPostTask(TID_UI,
+ base::BindOnce(&CallbackImpl::Success, this, response));
+ return;
+ }
+
+ if (router_) {
+ CefPostTask(
+ TID_UI,
+ base::BindOnce(&CefMessageRouterBrowserSideImpl::OnCallbackSuccess,
+ router_.get(), browser_id_, query_id_, response));
+
+ if (!persistent_) {
+ // Non-persistent callbacks are only good for a single use.
+ router_ = nullptr;
+ }
+ }
+ }
+
+ void Failure(int error_code, const CefString& error_message) override {
+ if (!CefCurrentlyOn(TID_UI)) {
+ // Must execute on the UI thread to access member variables.
+ CefPostTask(TID_UI, base::BindOnce(&CallbackImpl::Failure, this,
+ error_code, error_message));
+ return;
+ }
+
+ if (router_) {
+ CefPostTask(
+ TID_UI,
+ base::BindOnce(&CefMessageRouterBrowserSideImpl::OnCallbackFailure,
+ router_.get(), browser_id_, query_id_, error_code,
+ error_message));
+
+ // Failure always invalidates the callback.
+ router_ = nullptr;
+ }
+ }
+
+ void Detach() {
+ CEF_REQUIRE_UI_THREAD();
+ router_ = nullptr;
+ }
+
+ private:
+ CefRefPtr<CefMessageRouterBrowserSideImpl> router_;
+ const int browser_id_;
+ const int64 query_id_;
+ const bool persistent_;
+
+ IMPLEMENT_REFCOUNTING(CallbackImpl);
+ };
+
+ explicit CefMessageRouterBrowserSideImpl(const CefMessageRouterConfig& config)
+ : config_(config),
+ query_message_name_(config.js_query_function.ToString() +
+ kMessageSuffix),
+ cancel_message_name_(config.js_cancel_function.ToString() +
+ kMessageSuffix) {}
+
+ CefMessageRouterBrowserSideImpl(const CefMessageRouterBrowserSideImpl&) =
+ delete;
+ CefMessageRouterBrowserSideImpl& operator=(
+ const CefMessageRouterBrowserSideImpl&) = delete;
+
+ virtual ~CefMessageRouterBrowserSideImpl() {
+ // There should be no pending queries when the router is deleted.
+ DCHECK(browser_query_info_map_.empty());
+ }
+
+ bool AddHandler(Handler* handler, bool first) override {
+ CEF_REQUIRE_UI_THREAD();
+ if (handler_set_.find(handler) == handler_set_.end()) {
+ handler_set_.insert(first ? handler_set_.begin() : handler_set_.end(),
+ handler);
+ return true;
+ }
+ return false;
+ }
+
+ bool RemoveHandler(Handler* handler) override {
+ CEF_REQUIRE_UI_THREAD();
+ if (handler_set_.erase(handler) > 0) {
+ CancelPendingFor(nullptr, handler, true);
+ return true;
+ }
+ return false;
+ }
+
+ void CancelPending(CefRefPtr<CefBrowser> browser, Handler* handler) override {
+ CancelPendingFor(browser, handler, true);
+ }
+
+ int GetPendingCount(CefRefPtr<CefBrowser> browser,
+ Handler* handler) override {
+ CEF_REQUIRE_UI_THREAD();
+
+ if (browser_query_info_map_.empty()) {
+ return 0;
+ }
+
+ if (handler) {
+ // Need to iterate over each QueryInfo object to test the handler.
+ class Visitor : public BrowserQueryInfoMap::Visitor {
+ public:
+ explicit Visitor(Handler* handler) : handler_(handler), count_(0) {}
+
+ bool OnNextInfo(int browser_id,
+ InfoIdType info_id,
+ InfoObjectType info,
+ bool* remove) override {
+ if (info->handler == handler_) {
+ count_++;
+ }
+ return true;
+ }
+
+ int count() const { return count_; }
+
+ private:
+ Handler* handler_;
+ int count_;
+ };
+
+ Visitor visitor(handler);
+
+ if (browser.get()) {
+ // Count queries associated with the specified browser.
+ browser_query_info_map_.FindAll(browser->GetIdentifier(), &visitor);
+ } else {
+ // Count all queries for all browsers.
+ browser_query_info_map_.FindAll(&visitor);
+ }
+
+ return visitor.count();
+ } else if (browser.get()) {
+ return static_cast<int>(
+ browser_query_info_map_.size(browser->GetIdentifier()));
+ }
+
+ return static_cast<int>(browser_query_info_map_.size());
+ }
+
+ void OnBeforeClose(CefRefPtr<CefBrowser> browser) override {
+ CancelPendingFor(browser, nullptr, false);
+ }
+
+ void OnRenderProcessTerminated(CefRefPtr<CefBrowser> browser) override {
+ CancelPendingFor(browser, nullptr, false);
+ }
+
+ void OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) override {
+ if (frame->IsMain()) {
+ CancelPendingFor(browser, nullptr, false);
+ }
+ }
+
+ bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefProcessId source_process,
+ CefRefPtr<CefProcessMessage> message) override {
+ CEF_REQUIRE_UI_THREAD();
+
+ const std::string& message_name = message->GetName();
+ if (message_name == query_message_name_) {
+ CefRefPtr<CefListValue> args = message->GetArgumentList();
+ DCHECK_EQ(args->GetSize(), 4U);
+
+ const int context_id = args->GetInt(0);
+ const int request_id = args->GetInt(1);
+ const CefString& request = args->GetString(2);
+ const bool persistent = args->GetBool(3);
+
+ if (handler_set_.empty()) {
+ // No handlers so cancel the query.
+ CancelUnhandledQuery(browser, frame, context_id, request_id);
+ return true;
+ }
+
+ const int browser_id = browser->GetIdentifier();
+ const int64 query_id = query_id_generator_.GetNextId();
+
+ CefRefPtr<CallbackImpl> callback(
+ new CallbackImpl(this, browser_id, query_id, persistent));
+
+ // Make a copy of the handler list in case the user adds or removes a
+ // handler while we're iterating.
+ HandlerSet handler_set = handler_set_;
+
+ bool handled = false;
+ HandlerSet::const_iterator it_handler = handler_set.begin();
+ for (; it_handler != handler_set.end(); ++it_handler) {
+ handled = (*it_handler)
+ ->OnQuery(browser, frame, query_id, request, persistent,
+ callback.get());
+ if (handled) {
+ break;
+ }
+ }
+
+ // If the query isn't handled nothing should be keeping a reference to
+ // the callback.
+ DCHECK(handled || callback->HasOneRef());
+
+ if (handled) {
+ // Persist the query information until the callback executes.
+ // It's safe to do this here because the callback will execute
+ // asynchronously.
+ QueryInfo* info = new QueryInfo;
+ info->browser = browser;
+ info->frame = frame;
+ info->context_id = context_id;
+ info->request_id = request_id;
+ info->persistent = persistent;
+ info->callback = callback;
+ info->handler = *(it_handler);
+ browser_query_info_map_.Add(browser_id, query_id, info);
+ } else {
+ // Invalidate the callback.
+ callback->Detach();
+
+ // No one chose to handle the query so cancel it.
+ CancelUnhandledQuery(browser, frame, context_id, request_id);
+ }
+
+ return true;
+ } else if (message_name == cancel_message_name_) {
+ CefRefPtr<CefListValue> args = message->GetArgumentList();
+ DCHECK_EQ(args->GetSize(), 2U);
+
+ const int browser_id = browser->GetIdentifier();
+ const int context_id = args->GetInt(0);
+ const int request_id = args->GetInt(1);
+
+ CancelPendingRequest(browser_id, context_id, request_id);
+ return true;
+ }
+
+ return false;
+ }
+
+ private:
+ // Structure representing a pending query.
+ struct QueryInfo {
+ // Browser and frame originated the query.
+ CefRefPtr<CefBrowser> browser;
+ CefRefPtr<CefFrame> frame;
+
+ // IDs that uniquely identify the query in the renderer process. These
+ // values are opaque to the browser process but must be returned with the
+ // response.
+ int context_id;
+ int request_id;
+
+ // True if the query is persistent.
+ bool persistent;
+
+ // Callback associated with the query that must be detached when the query
+ // is canceled.
+ CefRefPtr<CallbackImpl> callback;
+
+ // Handler that should be notified if the query is automatically canceled.
+ Handler* handler;
+ };
+
+ // Retrieve a QueryInfo object from the map based on the browser-side query
+ // ID. If |always_remove| is true then the QueryInfo object will always be
+ // removed from the map. Othewise, the QueryInfo object will only be removed
+ // if the query is non-persistent. If |removed| is true the caller is
+ // responsible for deleting the returned QueryInfo object.
+ QueryInfo* GetQueryInfo(int browser_id,
+ int64 query_id,
+ bool always_remove,
+ bool* removed) {
+ class Visitor : public BrowserQueryInfoMap::Visitor {
+ public:
+ explicit Visitor(bool always_remove)
+ : always_remove_(always_remove), removed_(false) {}
+
+ bool OnNextInfo(int browser_id,
+ InfoIdType info_id,
+ InfoObjectType info,
+ bool* remove) override {
+ *remove = removed_ = (always_remove_ || !info->persistent);
+ return true;
+ }
+
+ bool removed() const { return removed_; }
+
+ private:
+ const bool always_remove_;
+ bool removed_;
+ };
+
+ Visitor visitor(always_remove);
+ QueryInfo* info =
+ browser_query_info_map_.Find(browser_id, query_id, &visitor);
+ if (info) {
+ *removed = visitor.removed();
+ }
+ return info;
+ }
+
+ // Called by CallbackImpl on success.
+ void OnCallbackSuccess(int browser_id,
+ int64 query_id,
+ const CefString& response) {
+ CEF_REQUIRE_UI_THREAD();
+
+ bool removed;
+ QueryInfo* info = GetQueryInfo(browser_id, query_id, false, &removed);
+ if (info) {
+ SendQuerySuccess(info, response);
+ if (removed) {
+ delete info;
+ }
+ }
+ }
+
+ // Called by CallbackImpl on failure.
+ void OnCallbackFailure(int browser_id,
+ int64 query_id,
+ int error_code,
+ const CefString& error_message) {
+ CEF_REQUIRE_UI_THREAD();
+
+ bool removed;
+ QueryInfo* info = GetQueryInfo(browser_id, query_id, true, &removed);
+ if (info) {
+ SendQueryFailure(info, error_code, error_message);
+ DCHECK(removed);
+ delete info;
+ }
+ }
+
+ void SendQuerySuccess(QueryInfo* info, const CefString& response) {
+ SendQuerySuccess(info->browser, info->frame, info->context_id,
+ info->request_id, response);
+ }
+
+ void SendQuerySuccess(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int context_id,
+ int request_id,
+ const CefString& response) {
+ if (auto message =
+ BuildMessage(config_.message_size_threshold, query_message_name_,
+ context_id, request_id, response)) {
+ frame->SendProcessMessage(PID_RENDERER, message);
+ }
+ }
+
+ void SendQueryFailure(QueryInfo* info,
+ int error_code,
+ const CefString& error_message) {
+ SendQueryFailure(info->browser, info->frame, info->context_id,
+ info->request_id, error_code, error_message);
+ }
+
+ void SendQueryFailure(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int context_id,
+ int request_id,
+ int error_code,
+ const CefString& error_message) {
+ CefRefPtr<CefProcessMessage> message =
+ CefProcessMessage::Create(query_message_name_);
+ CefRefPtr<CefListValue> args = message->GetArgumentList();
+ args->SetInt(0, context_id);
+ args->SetInt(1, request_id);
+ args->SetBool(2, false); // Indicates a failure result.
+ args->SetInt(3, error_code);
+ args->SetString(4, error_message);
+ frame->SendProcessMessage(PID_RENDERER, message);
+ }
+
+ // Cancel a query that has not been sent to a handler.
+ void CancelUnhandledQuery(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int context_id,
+ int request_id) {
+ SendQueryFailure(browser, frame, context_id, request_id, kCanceledErrorCode,
+ kCanceledErrorMessage);
+ }
+
+ // Cancel a query that has already been sent to a handler.
+ void CancelQuery(int64 query_id, QueryInfo* info, bool notify_renderer) {
+ if (notify_renderer) {
+ SendQueryFailure(info, kCanceledErrorCode, kCanceledErrorMessage);
+ }
+
+ info->handler->OnQueryCanceled(info->browser, info->frame, query_id);
+
+ // Invalidate the callback.
+ info->callback->Detach();
+ }
+
+ // Cancel all pending queries associated with either |browser| or |handler|.
+ // If both |browser| and |handler| are NULL all pending queries will be
+ // canceled. Set |notify_renderer| to true if the renderer should be notified.
+ void CancelPendingFor(CefRefPtr<CefBrowser> browser,
+ Handler* handler,
+ bool notify_renderer) {
+ if (!CefCurrentlyOn(TID_UI)) {
+ // Must execute on the UI thread.
+ CefPostTask(
+ TID_UI,
+ base::BindOnce(&CefMessageRouterBrowserSideImpl::CancelPendingFor,
+ this, browser, handler, notify_renderer));
+ return;
+ }
+
+ if (browser_query_info_map_.empty()) {
+ return;
+ }
+
+ class Visitor : public BrowserQueryInfoMap::Visitor {
+ public:
+ Visitor(CefMessageRouterBrowserSideImpl* router,
+ Handler* handler,
+ bool notify_renderer)
+ : router_(router),
+ handler_(handler),
+ notify_renderer_(notify_renderer) {}
+
+ bool OnNextInfo(int browser_id,
+ InfoIdType info_id,
+ InfoObjectType info,
+ bool* remove) override {
+ if (!handler_ || info->handler == handler_) {
+ *remove = true;
+ router_->CancelQuery(info_id, info, notify_renderer_);
+ delete info;
+ }
+ return true;
+ }
+
+ private:
+ CefMessageRouterBrowserSideImpl* router_;
+ Handler* handler_;
+ const bool notify_renderer_;
+ };
+
+ Visitor visitor(this, handler, notify_renderer);
+
+ if (browser.get()) {
+ // Cancel all queries associated with the specified browser.
+ browser_query_info_map_.FindAll(browser->GetIdentifier(), &visitor);
+ } else {
+ // Cancel all queries for all browsers.
+ browser_query_info_map_.FindAll(&visitor);
+ }
+ }
+
+ // Cancel a query based on the renderer-side IDs. If |request_id| is
+ // kReservedId all requests associated with |context_id| will be canceled.
+ void CancelPendingRequest(int browser_id, int context_id, int request_id) {
+ class Visitor : public BrowserQueryInfoMap::Visitor {
+ public:
+ Visitor(CefMessageRouterBrowserSideImpl* router,
+ int context_id,
+ int request_id)
+ : router_(router), context_id_(context_id), request_id_(request_id) {}
+
+ bool OnNextInfo(int browser_id,
+ InfoIdType info_id,
+ InfoObjectType info,
+ bool* remove) override {
+ if (info->context_id == context_id_ &&
+ (request_id_ == kReservedId || info->request_id == request_id_)) {
+ *remove = true;
+ router_->CancelQuery(info_id, info, false);
+ delete info;
+
+ // Stop iterating if only canceling a single request.
+ return (request_id_ == kReservedId);
+ }
+ return true;
+ }
+
+ private:
+ CefMessageRouterBrowserSideImpl* router_;
+ const int context_id_;
+ const int request_id_;
+ };
+
+ Visitor visitor(this, context_id, request_id);
+ browser_query_info_map_.FindAll(browser_id, &visitor);
+ }
+
+ const CefMessageRouterConfig config_;
+ const std::string query_message_name_;
+ const std::string cancel_message_name_;
+
+ IdGenerator<int64> query_id_generator_;
+
+ // Set of currently registered handlers. An entry is added when a handler is
+ // registered and removed when a handler is unregistered.
+ using HandlerSet = std::set<Handler*>;
+ HandlerSet handler_set_;
+
+ // Map of query ID to QueryInfo instance. An entry is added when a Handler
+ // indicates that it will handle the query and removed when either the query
+ // is completed via the Callback, the query is explicitly canceled from the
+ // renderer process, or the associated context is (or will be) released.
+ using BrowserQueryInfoMap = CefBrowserInfoMap<int64, QueryInfo*>;
+ BrowserQueryInfoMap browser_query_info_map_;
+};
+
+// Renderer-side router implementation.
+class CefMessageRouterRendererSideImpl : public CefMessageRouterRendererSide {
+ public:
+ class V8HandlerImpl : public CefV8Handler {
+ public:
+ V8HandlerImpl(CefRefPtr<CefMessageRouterRendererSideImpl> router,
+ const CefMessageRouterConfig& config)
+ : router_(router), config_(config), context_id_(kReservedId) {}
+
+ V8HandlerImpl(const V8HandlerImpl&) = delete;
+ V8HandlerImpl& operator=(const V8HandlerImpl&) = delete;
+
+ bool Execute(const CefString& name,
+ CefRefPtr<CefV8Value> object,
+ const CefV8ValueList& arguments,
+ CefRefPtr<CefV8Value>& retval,
+ CefString& exception) override {
+ if (name == config_.js_query_function) {
+ if (arguments.size() != 1 || !arguments[0]->IsObject()) {
+ exception = "Invalid arguments; expecting a single object";
+ return true;
+ }
+
+ CefRefPtr<CefV8Value> arg = arguments[0];
+
+ CefRefPtr<CefV8Value> requestVal = arg->GetValue(kMemberRequest);
+ if (!requestVal.get() || !requestVal->IsString()) {
+ exception = "Invalid arguments; object member '" +
+ std::string(kMemberRequest) +
+ "' is required and must have type string";
+ return true;
+ }
+
+ CefRefPtr<CefV8Value> successVal = nullptr;
+ if (arg->HasValue(kMemberOnSuccess)) {
+ successVal = arg->GetValue(kMemberOnSuccess);
+ if (!successVal->IsFunction()) {
+ exception = "Invalid arguments; object member '" +
+ std::string(kMemberOnSuccess) +
+ "' must have type function";
+ return true;
+ }
+ }
+
+ CefRefPtr<CefV8Value> failureVal = nullptr;
+ if (arg->HasValue(kMemberOnFailure)) {
+ failureVal = arg->GetValue(kMemberOnFailure);
+ if (!failureVal->IsFunction()) {
+ exception = "Invalid arguments; object member '" +
+ std::string(kMemberOnFailure) +
+ "' must have type function";
+ return true;
+ }
+ }
+
+ CefRefPtr<CefV8Value> persistentVal = nullptr;
+ if (arg->HasValue(kMemberPersistent)) {
+ persistentVal = arg->GetValue(kMemberPersistent);
+ if (!persistentVal->IsBool()) {
+ exception = "Invalid arguments; object member '" +
+ std::string(kMemberPersistent) +
+ "' must have type boolean";
+ return true;
+ }
+ }
+
+ CefRefPtr<CefV8Context> context = CefV8Context::GetCurrentContext();
+ const int context_id = GetIDForContext(context);
+ const bool persistent =
+ (persistentVal.get() && persistentVal->GetBoolValue());
+
+ const int request_id = router_->SendQuery(
+ context->GetBrowser(), context->GetFrame(), context_id,
+ requestVal->GetStringValue(), persistent, successVal, failureVal);
+ retval = CefV8Value::CreateInt(request_id);
+ return true;
+ } else if (name == config_.js_cancel_function) {
+ if (arguments.size() != 1 || !arguments[0]->IsInt()) {
+ exception = "Invalid arguments; expecting a single integer";
+ return true;
+ }
+
+ bool result = false;
+ const int request_id = arguments[0]->GetIntValue();
+ if (request_id != kReservedId) {
+ CefRefPtr<CefV8Context> context = CefV8Context::GetCurrentContext();
+ const int context_id = GetIDForContext(context);
+ result =
+ router_->SendCancel(context->GetBrowser(), context->GetFrame(),
+ context_id, request_id);
+ }
+ retval = CefV8Value::CreateBool(result);
+ return true;
+ }
+
+ return false;
+ }
+
+ private:
+ // Don't create the context ID until it's actually needed.
+ int GetIDForContext(CefRefPtr<CefV8Context> context) {
+ if (context_id_ == kReservedId) {
+ context_id_ = router_->CreateIDForContext(context);
+ }
+ return context_id_;
+ }
+
+ CefRefPtr<CefMessageRouterRendererSideImpl> router_;
+ const CefMessageRouterConfig config_;
+ int context_id_;
+
+ IMPLEMENT_REFCOUNTING(V8HandlerImpl);
+ };
+
+ explicit CefMessageRouterRendererSideImpl(
+ const CefMessageRouterConfig& config)
+ : config_(config),
+ query_message_name_(config.js_query_function.ToString() +
+ kMessageSuffix),
+ cancel_message_name_(config.js_cancel_function.ToString() +
+ kMessageSuffix) {}
+
+ CefMessageRouterRendererSideImpl(const CefMessageRouterRendererSideImpl&) =
+ delete;
+ CefMessageRouterRendererSideImpl& operator=(
+ const CefMessageRouterRendererSideImpl&) = delete;
+
+ int GetPendingCount(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefV8Context> context) override {
+ CEF_REQUIRE_RENDERER_THREAD();
+
+ if (browser_request_info_map_.empty()) {
+ return 0;
+ }
+
+ if (context.get()) {
+ const int context_id = GetIDForContext(context, false);
+ if (context_id == kReservedId) {
+ return 0; // Nothing associated with the specified context.
+ }
+
+ // Need to iterate over each RequestInfo object to test the context.
+ class Visitor : public BrowserRequestInfoMap::Visitor {
+ public:
+ explicit Visitor(int context_id) : context_id_(context_id), count_(0) {}
+
+ bool OnNextInfo(int browser_id,
+ InfoIdType info_id,
+ InfoObjectType info,
+ bool* remove) override {
+ if (info_id.first == context_id_) {
+ count_++;
+ }
+ return true;
+ }
+
+ int count() const { return count_; }
+
+ private:
+ int context_id_;
+ int count_;
+ };
+
+ Visitor visitor(context_id);
+
+ if (browser.get()) {
+ // Count requests associated with the specified browser.
+ browser_request_info_map_.FindAll(browser->GetIdentifier(), &visitor);
+ } else {
+ // Count all requests for all browsers.
+ browser_request_info_map_.FindAll(&visitor);
+ }
+
+ return visitor.count();
+ } else if (browser.get()) {
+ return static_cast<int>(
+ browser_request_info_map_.size(browser->GetIdentifier()));
+ }
+
+ return static_cast<int>(browser_request_info_map_.size());
+ }
+
+ void OnContextCreated(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefV8Context> context) override {
+ CEF_REQUIRE_RENDERER_THREAD();
+
+ // Register function handlers with the 'window' object.
+ CefRefPtr<CefV8Value> window = context->GetGlobal();
+
+ CefRefPtr<V8HandlerImpl> handler = new V8HandlerImpl(this, config_);
+ CefV8Value::PropertyAttribute attributes =
+ static_cast<CefV8Value::PropertyAttribute>(
+ V8_PROPERTY_ATTRIBUTE_READONLY | V8_PROPERTY_ATTRIBUTE_DONTENUM |
+ V8_PROPERTY_ATTRIBUTE_DONTDELETE);
+
+ // Add the query function.
+ CefRefPtr<CefV8Value> query_func =
+ CefV8Value::CreateFunction(config_.js_query_function, handler.get());
+ window->SetValue(config_.js_query_function, query_func, attributes);
+
+ // Add the cancel function.
+ CefRefPtr<CefV8Value> cancel_func =
+ CefV8Value::CreateFunction(config_.js_cancel_function, handler.get());
+ window->SetValue(config_.js_cancel_function, cancel_func, attributes);
+ }
+
+ void OnContextReleased(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefV8Context> context) override {
+ CEF_REQUIRE_RENDERER_THREAD();
+
+ // Get the context ID and remove the context from the map.
+ const int context_id = GetIDForContext(context, true);
+ if (context_id != kReservedId) {
+ // Cancel all pending requests for the context.
+ SendCancel(browser, frame, context_id, kReservedId);
+ }
+ }
+
+ bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefProcessId source_process,
+ CefRefPtr<CefProcessMessage> message) override {
+ CEF_REQUIRE_RENDERER_THREAD();
+
+ const std::string& message_name = message->GetName();
+ if (message_name == query_message_name_) {
+ auto content = ParseMessage(message);
+ if (content.success) {
+ CefPostTask(
+ TID_RENDERER,
+ base::BindOnce(
+ &CefMessageRouterRendererSideImpl::ExecuteSuccessCallback, this,
+ browser->GetIdentifier(), content.context_id,
+ content.request_id, content.message));
+ } else {
+ CefPostTask(
+ TID_RENDERER,
+ base::BindOnce(
+ &CefMessageRouterRendererSideImpl::ExecuteFailureCallback, this,
+ browser->GetIdentifier(), content.context_id,
+ content.request_id, content.error_code, content.message));
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ private:
+ // Structure representing a pending request.
+ struct RequestInfo {
+ // True if the request is persistent.
+ bool persistent;
+
+ // Success callback function. May be NULL.
+ CefRefPtr<CefV8Value> success_callback;
+
+ // Failure callback function. May be NULL.
+ CefRefPtr<CefV8Value> failure_callback;
+ };
+
+ // Retrieve a RequestInfo object from the map based on the renderer-side
+ // IDs. If |always_remove| is true then the RequestInfo object will always be
+ // removed from the map. Othewise, the RequestInfo object will only be removed
+ // if the query is non-persistent. If |removed| is true the caller is
+ // responsible for deleting the returned QueryInfo object.
+ RequestInfo* GetRequestInfo(int browser_id,
+ int context_id,
+ int request_id,
+ bool always_remove,
+ bool* removed) {
+ class Visitor : public BrowserRequestInfoMap::Visitor {
+ public:
+ explicit Visitor(bool always_remove)
+ : always_remove_(always_remove), removed_(false) {}
+
+ bool OnNextInfo(int browser_id,
+ InfoIdType info_id,
+ InfoObjectType info,
+ bool* remove) override {
+ *remove = removed_ = (always_remove_ || !info->persistent);
+ return true;
+ }
+
+ bool removed() const { return removed_; }
+
+ private:
+ const bool always_remove_;
+ bool removed_;
+ };
+
+ Visitor visitor(always_remove);
+ RequestInfo* info = browser_request_info_map_.Find(
+ browser_id, std::make_pair(context_id, request_id), &visitor);
+ if (info) {
+ *removed = visitor.removed();
+ }
+ return info;
+ }
+
+ // Returns the new request ID.
+ int SendQuery(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int context_id,
+ const CefString& request,
+ bool persistent,
+ CefRefPtr<CefV8Value> success_callback,
+ CefRefPtr<CefV8Value> failure_callback) {
+ CEF_REQUIRE_RENDERER_THREAD();
+
+ const int request_id = request_id_generator_.GetNextId();
+
+ auto* info =
+ new RequestInfo{persistent, success_callback, failure_callback};
+
+ browser_request_info_map_.Add(browser->GetIdentifier(),
+ std::make_pair(context_id, request_id), info);
+
+ CefRefPtr<CefProcessMessage> message =
+ CefProcessMessage::Create(query_message_name_);
+
+ CefRefPtr<CefListValue> args = message->GetArgumentList();
+ args->SetInt(0, context_id);
+ args->SetInt(1, request_id);
+ args->SetString(2, request);
+ args->SetBool(3, persistent);
+
+ frame->SendProcessMessage(PID_BROWSER, message);
+
+ return request_id;
+ }
+
+ // If |request_id| is kReservedId all requests associated with |context_id|
+ // will be canceled, otherwise only the specified |request_id| will be
+ // canceled. Returns true if any request was canceled.
+ bool SendCancel(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int context_id,
+ int request_id) {
+ CEF_REQUIRE_RENDERER_THREAD();
+
+ const int browser_id = browser->GetIdentifier();
+
+ int cancel_count = 0;
+ if (request_id != kReservedId) {
+ // Cancel a single request.
+ bool removed;
+ RequestInfo* info =
+ GetRequestInfo(browser_id, context_id, request_id, true, &removed);
+ if (info) {
+ DCHECK(removed);
+ delete info;
+ cancel_count = 1;
+ }
+ } else {
+ // Cancel all requests with the specified context ID.
+ class Visitor : public BrowserRequestInfoMap::Visitor {
+ public:
+ explicit Visitor(int context_id)
+ : context_id_(context_id), cancel_count_(0) {}
+
+ bool OnNextInfo(int browser_id,
+ InfoIdType info_id,
+ InfoObjectType info,
+ bool* remove) override {
+ if (info_id.first == context_id_) {
+ *remove = true;
+ delete info;
+ cancel_count_++;
+ }
+ return true;
+ }
+
+ int cancel_count() const { return cancel_count_; }
+
+ private:
+ const int context_id_;
+ int cancel_count_;
+ };
+
+ Visitor visitor(context_id);
+ browser_request_info_map_.FindAll(browser_id, &visitor);
+ cancel_count = visitor.cancel_count();
+ }
+
+ if (cancel_count > 0) {
+ CefRefPtr<CefProcessMessage> message =
+ CefProcessMessage::Create(cancel_message_name_);
+
+ CefRefPtr<CefListValue> args = message->GetArgumentList();
+ args->SetInt(0, context_id);
+ args->SetInt(1, request_id);
+
+ frame->SendProcessMessage(PID_BROWSER, message);
+ return true;
+ }
+
+ return false;
+ }
+
+ // Execute the onSuccess JavaScript callback.
+ void ExecuteSuccessCallback(int browser_id,
+ int context_id,
+ int request_id,
+ const CefString& response) {
+ CEF_REQUIRE_RENDERER_THREAD();
+
+ bool removed;
+ RequestInfo* info =
+ GetRequestInfo(browser_id, context_id, request_id, false, &removed);
+ if (!info) {
+ return;
+ }
+
+ CefRefPtr<CefV8Context> context = GetContextByID(context_id);
+ if (context && info->success_callback) {
+ CefV8ValueList args;
+ args.push_back(CefV8Value::CreateString(response));
+ info->success_callback->ExecuteFunctionWithContext(context, nullptr,
+ args);
+ }
+
+ if (removed) {
+ delete info;
+ }
+ }
+
+ // Execute the onFailure JavaScript callback.
+ void ExecuteFailureCallback(int browser_id,
+ int context_id,
+ int request_id,
+ int error_code,
+ const CefString& error_message) {
+ CEF_REQUIRE_RENDERER_THREAD();
+
+ bool removed;
+ RequestInfo* info =
+ GetRequestInfo(browser_id, context_id, request_id, true, &removed);
+ if (!info) {
+ return;
+ }
+
+ CefRefPtr<CefV8Context> context = GetContextByID(context_id);
+ if (context && info->failure_callback) {
+ CefV8ValueList args;
+ args.push_back(CefV8Value::CreateInt(error_code));
+ args.push_back(CefV8Value::CreateString(error_message));
+ info->failure_callback->ExecuteFunctionWithContext(context, nullptr,
+ args);
+ }
+
+ DCHECK(removed);
+ delete info;
+ }
+
+ int CreateIDForContext(CefRefPtr<CefV8Context> context) {
+ CEF_REQUIRE_RENDERER_THREAD();
+
+ // The context should not already have an associated ID.
+ DCHECK_EQ(GetIDForContext(context, false), kReservedId);
+
+ const int context_id = context_id_generator_.GetNextId();
+ context_map_.insert(std::make_pair(context_id, context));
+ return context_id;
+ }
+
+ // Retrieves the existing ID value associated with the specified |context|.
+ // If |remove| is true the context will also be removed from the map.
+ int GetIDForContext(CefRefPtr<CefV8Context> context, bool remove) {
+ CEF_REQUIRE_RENDERER_THREAD();
+
+ ContextMap::iterator it = context_map_.begin();
+ for (; it != context_map_.end(); ++it) {
+ if (it->second->IsSame(context)) {
+ int context_id = it->first;
+ if (remove) {
+ context_map_.erase(it);
+ }
+ return context_id;
+ }
+ }
+
+ return kReservedId;
+ }
+
+ CefRefPtr<CefV8Context> GetContextByID(int context_id) {
+ CEF_REQUIRE_RENDERER_THREAD();
+
+ ContextMap::const_iterator it = context_map_.find(context_id);
+ if (it != context_map_.end()) {
+ return it->second;
+ }
+ return nullptr;
+ }
+
+ const CefMessageRouterConfig config_;
+ const std::string query_message_name_;
+ const std::string cancel_message_name_;
+
+ IdGenerator<int> context_id_generator_;
+ IdGenerator<int> request_id_generator_;
+
+ // Map of (request ID, context ID) to RequestInfo for pending queries. An
+ // entry is added when a request is initiated via the bound function and
+ // removed when either the request completes, is canceled via the bound
+ // function, or the associated context is released.
+ using BrowserRequestInfoMap =
+ CefBrowserInfoMap<std::pair<int, int>, RequestInfo*>;
+ BrowserRequestInfoMap browser_request_info_map_;
+
+ // Map of context ID to CefV8Context for existing contexts. An entry is added
+ // when a bound function is executed for the first time in the context and
+ // removed when the context is released.
+ using ContextMap = std::map<int, CefRefPtr<CefV8Context>>;
+ ContextMap context_map_;
+};
+
+} // namespace
+
+CefMessageRouterConfig::CefMessageRouterConfig()
+ : js_query_function("cefQuery"),
+ js_cancel_function("cefQueryCancel"),
+ message_size_threshold(kResponseSizeThreshold) {}
+
+// static
+CefRefPtr<CefMessageRouterBrowserSide> CefMessageRouterBrowserSide::Create(
+ const CefMessageRouterConfig& config) {
+ CefMessageRouterConfig validated_config = config;
+ if (!ValidateConfig(validated_config)) {
+ return nullptr;
+ }
+ return new CefMessageRouterBrowserSideImpl(validated_config);
+}
+
+// static
+CefRefPtr<CefMessageRouterRendererSide> CefMessageRouterRendererSide::Create(
+ const CefMessageRouterConfig& config) {
+ CefMessageRouterConfig validated_config = config;
+ if (!ValidateConfig(validated_config)) {
+ return nullptr;
+ }
+ return new CefMessageRouterRendererSideImpl(validated_config);
+}
diff --git a/libcef_dll/wrapper/cef_resource_manager.cc b/libcef_dll/wrapper/cef_resource_manager.cc
new file mode 100644
index 00000000..1df8aeb9
--- /dev/null
+++ b/libcef_dll/wrapper/cef_resource_manager.cc
@@ -0,0 +1,784 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "include/wrapper/cef_resource_manager.h"
+
+#include <algorithm>
+#include <vector>
+
+#include "include/base/cef_callback.h"
+#include "include/base/cef_weak_ptr.h"
+#include "include/cef_parser.h"
+#include "include/wrapper/cef_stream_resource_handler.h"
+#include "include/wrapper/cef_zip_archive.h"
+
+namespace {
+
+#if defined(OS_WIN)
+#define PATH_SEP '\\'
+#else
+#define PATH_SEP '/'
+#endif
+
+// Returns |url| without the query or fragment components, if any.
+std::string GetUrlWithoutQueryOrFragment(const std::string& url) {
+ // Find the first instance of '?' or '#'.
+ const size_t pos = std::min(url.find('?'), url.find('#'));
+ if (pos != std::string::npos) {
+ return url.substr(0, pos);
+ }
+
+ return url;
+}
+
+// Determine the mime type based on the |url| file extension.
+std::string GetMimeType(const std::string& url) {
+ std::string mime_type;
+ const std::string& url_without_query = GetUrlWithoutQueryOrFragment(url);
+ size_t sep = url_without_query.find_last_of(".");
+ if (sep != std::string::npos) {
+ mime_type = CefGetMimeType(url_without_query.substr(sep + 1));
+ if (!mime_type.empty()) {
+ return mime_type;
+ }
+ }
+ return "text/html";
+}
+
+// Default no-op filter.
+std::string GetFilteredUrl(const std::string& url) {
+ return url;
+}
+
+// Provider of fixed contents.
+class ContentProvider : public CefResourceManager::Provider {
+ public:
+ ContentProvider(const std::string& url,
+ const std::string& content,
+ const std::string& mime_type)
+ : url_(url), content_(content), mime_type_(mime_type) {
+ DCHECK(!url.empty());
+ DCHECK(!content.empty());
+ }
+
+ ContentProvider(const ContentProvider&) = delete;
+ ContentProvider& operator=(const ContentProvider&) = delete;
+
+ bool OnRequest(scoped_refptr<CefResourceManager::Request> request) override {
+ CEF_REQUIRE_IO_THREAD();
+
+ const std::string& url = request->url();
+ if (url != url_) {
+ // Not handled by this provider.
+ return false;
+ }
+
+ CefRefPtr<CefStreamReader> stream = CefStreamReader::CreateForData(
+ static_cast<void*>(const_cast<char*>(content_.data())),
+ content_.length());
+
+ // Determine the mime type a single time if it isn't already set.
+ if (mime_type_.empty()) {
+ mime_type_ = request->mime_type_resolver().Run(url);
+ }
+
+ request->Continue(new CefStreamResourceHandler(mime_type_, stream));
+ return true;
+ }
+
+ private:
+ std::string url_;
+ std::string content_;
+ std::string mime_type_;
+};
+
+// Provider of contents loaded from a directory on the file system.
+class DirectoryProvider : public CefResourceManager::Provider {
+ public:
+ DirectoryProvider(const std::string& url_path,
+ const std::string& directory_path)
+ : url_path_(url_path), directory_path_(directory_path) {
+ DCHECK(!url_path_.empty());
+ DCHECK(!directory_path_.empty());
+
+ // Normalize the path values.
+ if (url_path_[url_path_.size() - 1] != '/') {
+ url_path_ += '/';
+ }
+ if (directory_path_[directory_path_.size() - 1] != PATH_SEP) {
+ directory_path_ += PATH_SEP;
+ }
+ }
+
+ DirectoryProvider(const DirectoryProvider&) = delete;
+ DirectoryProvider& operator=(const DirectoryProvider&) = delete;
+
+ bool OnRequest(scoped_refptr<CefResourceManager::Request> request) override {
+ CEF_REQUIRE_IO_THREAD();
+
+ const std::string& url = request->url();
+ if (url.find(url_path_) != 0U) {
+ return false;
+ }
+
+ const std::string& file_path = GetFilePath(url);
+
+ // Open |file_path| on the FILE thread.
+ CefPostTask(TID_FILE_USER_BLOCKING,
+ base::BindOnce(&DirectoryProvider::OpenOnFileThread, file_path,
+ request));
+
+ return true;
+ }
+
+ private:
+ std::string GetFilePath(const std::string& url) {
+ std::string path_part = url.substr(url_path_.length());
+#if defined(OS_WIN)
+ std::replace(path_part.begin(), path_part.end(), '/', '\\');
+#endif
+ return directory_path_ + path_part;
+ }
+
+ static void OpenOnFileThread(
+ const std::string& file_path,
+ scoped_refptr<CefResourceManager::Request> request) {
+ CEF_REQUIRE_FILE_USER_BLOCKING_THREAD();
+
+ CefRefPtr<CefStreamReader> stream =
+ CefStreamReader::CreateForFile(file_path);
+
+ // Continue loading on the IO thread.
+ CefPostTask(TID_IO,
+ base::BindOnce(&DirectoryProvider::ContinueOpenOnIOThread,
+ request, stream));
+ }
+
+ static void ContinueOpenOnIOThread(
+ scoped_refptr<CefResourceManager::Request> request,
+ CefRefPtr<CefStreamReader> stream) {
+ CEF_REQUIRE_IO_THREAD();
+
+ CefRefPtr<CefStreamResourceHandler> handler;
+ if (stream.get()) {
+ handler = new CefStreamResourceHandler(
+ request->mime_type_resolver().Run(request->url()), stream);
+ }
+ request->Continue(handler);
+ }
+
+ std::string url_path_;
+ std::string directory_path_;
+};
+
+// Provider of contents loaded from an archive file.
+class ArchiveProvider : public CefResourceManager::Provider {
+ public:
+ ArchiveProvider(const std::string& url_path,
+ const std::string& archive_path,
+ const std::string& password)
+ : url_path_(url_path),
+ archive_path_(archive_path),
+ password_(password),
+ archive_load_started_(false),
+ archive_load_ended_(false),
+ weak_ptr_factory_(this) {
+ DCHECK(!url_path_.empty());
+ DCHECK(!archive_path_.empty());
+
+ // Normalize the path values.
+ if (url_path_[url_path_.size() - 1] != '/') {
+ url_path_ += '/';
+ }
+ }
+
+ ArchiveProvider(const ArchiveProvider&) = delete;
+ ArchiveProvider& operator=(const ArchiveProvider&) = delete;
+
+ bool OnRequest(scoped_refptr<CefResourceManager::Request> request) override {
+ CEF_REQUIRE_IO_THREAD();
+
+ const std::string& url = request->url();
+ if (url.find(url_path_) != 0U) {
+ // Not handled by this provider.
+ return false;
+ }
+
+ if (!archive_load_started_) {
+ // Initiate archive loading and queue the pending request.
+ archive_load_started_ = true;
+ pending_requests_.push_back(request);
+
+ // Load the archive file on the FILE thread.
+ CefPostTask(TID_FILE_USER_BLOCKING,
+ base::BindOnce(&ArchiveProvider::LoadOnFileThread,
+ weak_ptr_factory_.GetWeakPtr(), archive_path_,
+ password_));
+ return true;
+ }
+
+ if (archive_load_started_ && !archive_load_ended_) {
+ // The archive load has already started. Queue the pending request.
+ pending_requests_.push_back(request);
+ return true;
+ }
+
+ // Archive loading is done.
+ return ContinueRequest(request);
+ }
+
+ private:
+ static void LoadOnFileThread(base::WeakPtr<ArchiveProvider> ptr,
+ const std::string& archive_path,
+ const std::string& password) {
+ CEF_REQUIRE_FILE_USER_BLOCKING_THREAD();
+
+ CefRefPtr<CefZipArchive> archive;
+
+ CefRefPtr<CefStreamReader> stream =
+ CefStreamReader::CreateForFile(archive_path);
+ if (stream.get()) {
+ archive = new CefZipArchive;
+ if (archive->Load(stream, password, true) == 0) {
+ DLOG(WARNING) << "Empty archive file: " << archive_path;
+ archive = nullptr;
+ }
+ } else {
+ DLOG(WARNING) << "Failed to load archive file: " << archive_path;
+ }
+
+ CefPostTask(TID_IO, base::BindOnce(&ArchiveProvider::ContinueOnIOThread,
+ ptr, archive));
+ }
+
+ void ContinueOnIOThread(CefRefPtr<CefZipArchive> archive) {
+ CEF_REQUIRE_IO_THREAD();
+
+ archive_load_ended_ = true;
+ archive_ = archive;
+
+ if (!pending_requests_.empty()) {
+ // Continue all pending requests.
+ PendingRequests::const_iterator it = pending_requests_.begin();
+ for (; it != pending_requests_.end(); ++it) {
+ ContinueRequest(*it);
+ }
+ pending_requests_.clear();
+ }
+ }
+
+ bool ContinueRequest(scoped_refptr<CefResourceManager::Request> request) {
+ CefRefPtr<CefResourceHandler> handler;
+
+ // |archive_| will be NULL if the archive file failed to load or was empty.
+ if (archive_.get()) {
+ const std::string& url = request->url();
+ const std::string& relative_path = url.substr(url_path_.length());
+ CefRefPtr<CefZipArchive::File> file = archive_->GetFile(relative_path);
+ if (file.get()) {
+ handler = new CefStreamResourceHandler(
+ request->mime_type_resolver().Run(url), file->GetStreamReader());
+ }
+ }
+
+ if (!handler.get()) {
+ return false;
+ }
+
+ request->Continue(handler);
+ return true;
+ }
+
+ std::string url_path_;
+ std::string archive_path_;
+ std::string password_;
+
+ bool archive_load_started_;
+ bool archive_load_ended_;
+ CefRefPtr<CefZipArchive> archive_;
+
+ // List of requests that are pending while the archive is being loaded.
+ using PendingRequests =
+ std::vector<scoped_refptr<CefResourceManager::Request>>;
+ PendingRequests pending_requests_;
+
+ // Must be the last member.
+ base::WeakPtrFactory<ArchiveProvider> weak_ptr_factory_;
+};
+
+} // namespace
+
+// CefResourceManager::ProviderEntry implementation.
+
+struct CefResourceManager::ProviderEntry {
+ ProviderEntry(Provider* provider, int order, const std::string& identifier)
+ : provider_(provider),
+ order_(order),
+ identifier_(identifier),
+ deletion_pending_(false) {}
+
+ std::unique_ptr<Provider> provider_;
+ int order_;
+ std::string identifier_;
+
+ // List of pending requests currently associated with this provider.
+ RequestList pending_requests_;
+
+ // True if deletion of this provider is pending.
+ bool deletion_pending_;
+};
+
+// CefResourceManager::RequestState implementation.
+
+CefResourceManager::RequestState::~RequestState() {
+ // Always execute the callback.
+ if (callback_.get()) {
+ callback_->Continue();
+ }
+}
+
+// CefResourceManager::Request implementation.
+
+void CefResourceManager::Request::Continue(
+ CefRefPtr<CefResourceHandler> handler) {
+ if (!CefCurrentlyOn(TID_IO)) {
+ CefPostTask(TID_IO, base::BindOnce(&CefResourceManager::Request::Continue,
+ this, handler));
+ return;
+ }
+
+ if (!state_.get()) {
+ return;
+ }
+
+ // Disassociate |state_| immediately so that Provider::OnRequestCanceled is
+ // not called unexpectedly if Provider::OnRequest calls this method and then
+ // calls CefResourceManager::Remove*.
+ CefPostTask(TID_IO,
+ base::BindOnce(&CefResourceManager::Request::ContinueOnIOThread,
+ std::move(state_), handler));
+}
+
+void CefResourceManager::Request::Stop() {
+ if (!CefCurrentlyOn(TID_IO)) {
+ CefPostTask(TID_IO,
+ base::BindOnce(&CefResourceManager::Request::Stop, this));
+ return;
+ }
+
+ if (!state_.get()) {
+ return;
+ }
+
+ // Disassociate |state_| immediately so that Provider::OnRequestCanceled is
+ // not called unexpectedly if Provider::OnRequest calls this method and then
+ // calls CefResourceManager::Remove*.
+ CefPostTask(TID_IO,
+ base::BindOnce(&CefResourceManager::Request::StopOnIOThread,
+ std::move(state_)));
+}
+
+CefResourceManager::Request::Request(std::unique_ptr<RequestState> state)
+ : state_(std::move(state)), params_(state_->params_) {
+ CEF_REQUIRE_IO_THREAD();
+
+ ProviderEntry* entry = *(state_->current_entry_pos_);
+ // Should not be on a deleted entry.
+ DCHECK(!entry->deletion_pending_);
+
+ // Add this request to the entry's pending request list.
+ entry->pending_requests_.push_back(this);
+ state_->current_request_pos_ = --entry->pending_requests_.end();
+}
+
+// Detaches and returns |state_| if the provider indicates that it will not
+// handle the request. Note that |state_| may already be NULL if OnRequest
+// executes a callback before returning, in which case execution will continue
+// asynchronously in any case.
+std::unique_ptr<CefResourceManager::RequestState>
+CefResourceManager::Request::SendRequest() {
+ CEF_REQUIRE_IO_THREAD();
+ Provider* provider = (*state_->current_entry_pos_)->provider_.get();
+ if (!provider->OnRequest(this)) {
+ return std::move(state_);
+ }
+ return std::unique_ptr<RequestState>();
+}
+
+bool CefResourceManager::Request::HasState() {
+ CEF_REQUIRE_IO_THREAD();
+ return (state_.get() != nullptr);
+}
+
+// static
+void CefResourceManager::Request::ContinueOnIOThread(
+ std::unique_ptr<RequestState> state,
+ CefRefPtr<CefResourceHandler> handler) {
+ CEF_REQUIRE_IO_THREAD();
+ // The manager may already have been deleted.
+ base::WeakPtr<CefResourceManager> manager = state->manager_;
+ if (manager) {
+ manager->ContinueRequest(std::move(state), handler);
+ }
+}
+
+// static
+void CefResourceManager::Request::StopOnIOThread(
+ std::unique_ptr<RequestState> state) {
+ CEF_REQUIRE_IO_THREAD();
+ // The manager may already have been deleted.
+ base::WeakPtr<CefResourceManager> manager = state->manager_;
+ if (manager) {
+ manager->StopRequest(std::move(state));
+ }
+}
+
+// CefResourceManager implementation.
+
+CefResourceManager::CefResourceManager()
+ : url_filter_(base::BindRepeating(GetFilteredUrl)),
+ mime_type_resolver_(base::BindRepeating(GetMimeType)) {}
+
+CefResourceManager::~CefResourceManager() {
+ CEF_REQUIRE_IO_THREAD();
+ RemoveAllProviders();
+
+ // Delete all entryies now. Requests may still be pending but they will not
+ // call back into this manager due to the use of WeakPtr.
+ if (!providers_.empty()) {
+ ProviderEntryList::iterator it = providers_.begin();
+ for (; it != providers_.end(); ++it) {
+ delete *it;
+ }
+ providers_.clear();
+ }
+}
+
+void CefResourceManager::AddContentProvider(const std::string& url,
+ const std::string& content,
+ const std::string& mime_type,
+ int order,
+ const std::string& identifier) {
+ AddProvider(new ContentProvider(url, content, mime_type), order, identifier);
+}
+
+void CefResourceManager::AddDirectoryProvider(const std::string& url_path,
+ const std::string& directory_path,
+ int order,
+ const std::string& identifier) {
+ AddProvider(new DirectoryProvider(url_path, directory_path), order,
+ identifier);
+}
+
+void CefResourceManager::AddArchiveProvider(const std::string& url_path,
+ const std::string& archive_path,
+ const std::string& password,
+ int order,
+ const std::string& identifier) {
+ AddProvider(new ArchiveProvider(url_path, archive_path, password), order,
+ identifier);
+}
+
+void CefResourceManager::AddProvider(Provider* provider,
+ int order,
+ const std::string& identifier) {
+ DCHECK(provider);
+ if (!provider) {
+ return;
+ }
+
+ if (!CefCurrentlyOn(TID_IO)) {
+ CefPostTask(TID_IO, base::BindOnce(&CefResourceManager::AddProvider, this,
+ provider, order, identifier));
+ return;
+ }
+
+ std::unique_ptr<ProviderEntry> new_entry(
+ new ProviderEntry(provider, order, identifier));
+
+ if (providers_.empty()) {
+ providers_.push_back(new_entry.release());
+ return;
+ }
+
+ // Insert before the first entry with a higher |order| value.
+ ProviderEntryList::iterator it = providers_.begin();
+ for (; it != providers_.end(); ++it) {
+ if ((*it)->order_ > order) {
+ break;
+ }
+ }
+
+ providers_.insert(it, new_entry.release());
+}
+
+void CefResourceManager::RemoveProviders(const std::string& identifier) {
+ if (!CefCurrentlyOn(TID_IO)) {
+ CefPostTask(TID_IO, base::BindOnce(&CefResourceManager::RemoveProviders,
+ this, identifier));
+ return;
+ }
+
+ if (providers_.empty()) {
+ return;
+ }
+
+ ProviderEntryList::iterator it = providers_.begin();
+ while (it != providers_.end()) {
+ if ((*it)->identifier_ == identifier) {
+ DeleteProvider(it, false);
+ } else {
+ ++it;
+ }
+ }
+}
+
+void CefResourceManager::RemoveAllProviders() {
+ if (!CefCurrentlyOn(TID_IO)) {
+ CefPostTask(TID_IO,
+ base::BindOnce(&CefResourceManager::RemoveAllProviders, this));
+ return;
+ }
+
+ if (providers_.empty()) {
+ return;
+ }
+
+ ProviderEntryList::iterator it = providers_.begin();
+ while (it != providers_.end()) {
+ DeleteProvider(it, true);
+ }
+}
+
+void CefResourceManager::SetMimeTypeResolver(const MimeTypeResolver& resolver) {
+ if (!CefCurrentlyOn(TID_IO)) {
+ CefPostTask(TID_IO, base::BindOnce(&CefResourceManager::SetMimeTypeResolver,
+ this, resolver));
+ return;
+ }
+
+ if (!resolver.is_null()) {
+ mime_type_resolver_ = resolver;
+ } else {
+ mime_type_resolver_ = base::BindRepeating(GetMimeType);
+ }
+}
+
+void CefResourceManager::SetUrlFilter(const UrlFilter& filter) {
+ if (!CefCurrentlyOn(TID_IO)) {
+ CefPostTask(TID_IO, base::BindOnce(&CefResourceManager::SetUrlFilter, this,
+ filter));
+ return;
+ }
+
+ if (!filter.is_null()) {
+ url_filter_ = filter;
+ } else {
+ url_filter_ = base::BindRepeating(GetFilteredUrl);
+ }
+}
+
+cef_return_value_t CefResourceManager::OnBeforeResourceLoad(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefCallback> callback) {
+ CEF_REQUIRE_IO_THREAD();
+
+ // Find the first provider that is not pending deletion.
+ ProviderEntryList::iterator current_entry_pos = providers_.begin();
+ GetNextValidProvider(current_entry_pos);
+
+ if (current_entry_pos == providers_.end()) {
+ // No providers so continue the request immediately.
+ return RV_CONTINUE;
+ }
+
+ std::unique_ptr<RequestState> state(new RequestState);
+
+ if (!weak_ptr_factory_.get()) {
+ // WeakPtrFactory instances need to be created and destroyed on the same
+ // thread. This object performs most of its work on the IO thread and will
+ // be destroyed on the IO thread so, now that we're on the IO thread,
+ // properly initialize the WeakPtrFactory.
+ weak_ptr_factory_.reset(new base::WeakPtrFactory<CefResourceManager>(this));
+ }
+
+ state->manager_ = weak_ptr_factory_->GetWeakPtr();
+ state->callback_ = callback;
+
+ state->params_.url_ =
+ GetUrlWithoutQueryOrFragment(url_filter_.Run(request->GetURL()));
+ state->params_.browser_ = browser;
+ state->params_.frame_ = frame;
+ state->params_.request_ = request;
+ state->params_.url_filter_ = url_filter_;
+ state->params_.mime_type_resolver_ = mime_type_resolver_;
+
+ state->current_entry_pos_ = current_entry_pos;
+
+ // If the request is potentially handled we need to continue asynchronously.
+ return SendRequest(std::move(state)) ? RV_CONTINUE_ASYNC : RV_CONTINUE;
+}
+
+CefRefPtr<CefResourceHandler> CefResourceManager::GetResourceHandler(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request) {
+ CEF_REQUIRE_IO_THREAD();
+
+ if (pending_handlers_.empty()) {
+ return nullptr;
+ }
+
+ CefRefPtr<CefResourceHandler> handler;
+
+ PendingHandlersMap::iterator it =
+ pending_handlers_.find(request->GetIdentifier());
+ if (it != pending_handlers_.end()) {
+ handler = it->second;
+ pending_handlers_.erase(it);
+ }
+
+ return handler;
+}
+
+// Send the request to providers in order until one potentially handles it or we
+// run out of providers. Returns true if the request is potentially handled.
+bool CefResourceManager::SendRequest(std::unique_ptr<RequestState> state) {
+ bool potentially_handled = false;
+
+ do {
+ // Should not be on the last provider entry.
+ DCHECK(state->current_entry_pos_ != providers_.end());
+ scoped_refptr<Request> request = new Request(std::move(state));
+
+ // Give the provider an opportunity to handle the request.
+ state = request->SendRequest();
+ if (state.get()) {
+ // The provider will not handle the request. Move to the next provider if
+ // any.
+ if (!IncrementProvider(state.get())) {
+ StopRequest(std::move(state));
+ }
+ } else {
+ potentially_handled = true;
+ }
+ } while (state.get());
+
+ return potentially_handled;
+}
+
+void CefResourceManager::ContinueRequest(
+ std::unique_ptr<RequestState> state,
+ CefRefPtr<CefResourceHandler> handler) {
+ CEF_REQUIRE_IO_THREAD();
+
+ if (handler.get()) {
+ // The request has been handled. Associate the request ID with the handler.
+ pending_handlers_.insert(
+ std::make_pair(state->params_.request_->GetIdentifier(), handler));
+ StopRequest(std::move(state));
+ } else {
+ // Move to the next provider if any.
+ if (IncrementProvider(state.get())) {
+ SendRequest(std::move(state));
+ } else {
+ StopRequest(std::move(state));
+ }
+ }
+}
+
+void CefResourceManager::StopRequest(std::unique_ptr<RequestState> state) {
+ CEF_REQUIRE_IO_THREAD();
+
+ // Detach from the current provider.
+ DetachRequestFromProvider(state.get());
+
+ // Delete the state object and execute the callback.
+ state.reset();
+}
+
+// Move state to the next provider if any and return true if there are more
+// providers.
+bool CefResourceManager::IncrementProvider(RequestState* state) {
+ // Identify the next provider.
+ ProviderEntryList::iterator next_entry_pos = state->current_entry_pos_;
+ GetNextValidProvider(++next_entry_pos);
+
+ // Detach from the current provider.
+ DetachRequestFromProvider(state);
+
+ if (next_entry_pos != providers_.end()) {
+ // Update the state to reference the new provider entry.
+ state->current_entry_pos_ = next_entry_pos;
+ return true;
+ }
+
+ return false;
+}
+
+// The new provider, if any, should be determined before calling this method.
+void CefResourceManager::DetachRequestFromProvider(RequestState* state) {
+ if (state->current_entry_pos_ != providers_.end()) {
+ // Remove the association from the current provider entry.
+ ProviderEntryList::iterator current_entry_pos = state->current_entry_pos_;
+ ProviderEntry* current_entry = *(current_entry_pos);
+ current_entry->pending_requests_.erase(state->current_request_pos_);
+
+ if (current_entry->deletion_pending_ &&
+ current_entry->pending_requests_.empty()) {
+ // Delete the current provider entry now.
+ providers_.erase(current_entry_pos);
+ delete current_entry;
+ }
+
+ // Set to the end for error checking purposes.
+ state->current_entry_pos_ = providers_.end();
+ }
+}
+
+// Move to the next provider that is not pending deletion.
+void CefResourceManager::GetNextValidProvider(
+ ProviderEntryList::iterator& iterator) {
+ while (iterator != providers_.end() && (*iterator)->deletion_pending_) {
+ ++iterator;
+ }
+}
+
+void CefResourceManager::DeleteProvider(ProviderEntryList::iterator& iterator,
+ bool stop) {
+ CEF_REQUIRE_IO_THREAD();
+
+ ProviderEntry* current_entry = *(iterator);
+
+ if (current_entry->deletion_pending_) {
+ return;
+ }
+
+ if (!current_entry->pending_requests_.empty()) {
+ // Don't delete the provider entry until all pending requests have cleared.
+ current_entry->deletion_pending_ = true;
+
+ // Continue pending requests immediately.
+ RequestList::iterator it = current_entry->pending_requests_.begin();
+ for (; it != current_entry->pending_requests_.end(); ++it) {
+ const scoped_refptr<Request>& request = *it;
+ if (request->HasState()) {
+ if (stop) {
+ request->Stop();
+ } else {
+ request->Continue(nullptr);
+ }
+ current_entry->provider_->OnRequestCanceled(request);
+ }
+ }
+
+ ++iterator;
+ } else {
+ // Delete the provider entry now.
+ iterator = providers_.erase(iterator);
+ delete current_entry;
+ }
+}
diff --git a/libcef_dll/wrapper/cef_scoped_temp_dir.cc b/libcef_dll/wrapper/cef_scoped_temp_dir.cc
new file mode 100644
index 00000000..c1318933
--- /dev/null
+++ b/libcef_dll/wrapper/cef_scoped_temp_dir.cc
@@ -0,0 +1,95 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. Portions copyright
+// 2011 The Chromium Authors. All rights reserved. Use of this source code is
+// governed by a BSD-style license that can be found in the LICENSE file.
+
+#include "include/wrapper/cef_scoped_temp_dir.h"
+
+#include "include/base/cef_logging.h"
+#include "include/cef_file_util.h"
+
+CefScopedTempDir::CefScopedTempDir() {}
+
+CefScopedTempDir::~CefScopedTempDir() {
+ if (!path_.empty() && !Delete()) {
+ DLOG(WARNING) << "Could not delete temp dir in dtor.";
+ }
+}
+
+bool CefScopedTempDir::CreateUniqueTempDir() {
+ if (!path_.empty()) {
+ return false;
+ }
+
+ // This "scoped_dir" prefix is only used on Windows and serves as a template
+ // for the unique name.
+ if (!CefCreateNewTempDirectory("scoped_dir", path_)) {
+ return false;
+ }
+
+ return true;
+}
+
+bool CefScopedTempDir::CreateUniqueTempDirUnderPath(
+ const CefString& base_path) {
+ if (!path_.empty()) {
+ return false;
+ }
+
+ // If |base_path| does not exist, create it.
+ if (!CefCreateDirectory(base_path)) {
+ return false;
+ }
+
+ // Create a new, uniquely named directory under |base_path|.
+ if (!CefCreateTempDirectoryInDirectory(base_path, "scoped_dir_", path_)) {
+ return false;
+ }
+
+ return true;
+}
+
+bool CefScopedTempDir::Set(const CefString& path) {
+ if (!path_.empty()) {
+ return false;
+ }
+
+ if (!CefDirectoryExists(path) && !CefCreateDirectory(path)) {
+ return false;
+ }
+
+ path_ = path;
+ return true;
+}
+
+bool CefScopedTempDir::Delete() {
+ if (path_.empty()) {
+ return false;
+ }
+
+ bool ret = CefDeleteFile(path_, true);
+ if (ret) {
+ // We only clear the path if deleted the directory.
+ path_.clear();
+ }
+
+ return ret;
+}
+
+CefString CefScopedTempDir::Take() {
+ CefString ret = path_;
+ path_.clear();
+ return ret;
+}
+
+const CefString& CefScopedTempDir::GetPath() const {
+ DCHECK(!path_.empty()) << "Did you call CreateUniqueTempDir* before?";
+ return path_;
+}
+
+bool CefScopedTempDir::IsEmpty() const {
+ return path_.empty();
+}
+
+bool CefScopedTempDir::IsValid() const {
+ return !path_.empty() && CefDirectoryExists(path_);
+}
diff --git a/libcef_dll/wrapper/cef_stream_resource_handler.cc b/libcef_dll/wrapper/cef_stream_resource_handler.cc
new file mode 100644
index 00000000..730398f8
--- /dev/null
+++ b/libcef_dll/wrapper/cef_stream_resource_handler.cc
@@ -0,0 +1,87 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "include/wrapper/cef_stream_resource_handler.h"
+
+#include <algorithm>
+
+#include "include/base/cef_logging.h"
+#include "include/cef_task.h"
+#include "include/wrapper/cef_helpers.h"
+
+CefStreamResourceHandler::CefStreamResourceHandler(
+ const CefString& mime_type,
+ CefRefPtr<CefStreamReader> stream)
+ : status_code_(200),
+ status_text_("OK"),
+ mime_type_(mime_type),
+ stream_(stream) {
+ DCHECK(!mime_type_.empty());
+}
+
+CefStreamResourceHandler::CefStreamResourceHandler(
+ int status_code,
+ const CefString& status_text,
+ const CefString& mime_type,
+ CefResponse::HeaderMap header_map,
+ CefRefPtr<CefStreamReader> stream)
+ : status_code_(status_code),
+ status_text_(status_text),
+ mime_type_(mime_type),
+ header_map_(header_map),
+ stream_(stream) {
+ DCHECK(!mime_type_.empty());
+}
+
+bool CefStreamResourceHandler::Open(CefRefPtr<CefRequest> request,
+ bool& handle_request,
+ CefRefPtr<CefCallback> callback) {
+ DCHECK(!CefCurrentlyOn(TID_UI) && !CefCurrentlyOn(TID_IO));
+
+ // Continue the request immediately.
+ handle_request = true;
+ return true;
+}
+
+void CefStreamResourceHandler::GetResponseHeaders(
+ CefRefPtr<CefResponse> response,
+ int64& response_length,
+ CefString& redirectUrl) {
+ CEF_REQUIRE_IO_THREAD();
+
+ response->SetStatus(status_code_);
+ response->SetStatusText(status_text_);
+ response->SetMimeType(mime_type_);
+
+ if (!header_map_.empty()) {
+ response->SetHeaderMap(header_map_);
+ }
+
+ response_length = stream_ ? -1 : 0;
+}
+
+bool CefStreamResourceHandler::Read(
+ void* data_out,
+ int bytes_to_read,
+ int& bytes_read,
+ CefRefPtr<CefResourceReadCallback> callback) {
+ DCHECK(!CefCurrentlyOn(TID_UI) && !CefCurrentlyOn(TID_IO));
+ DCHECK_GT(bytes_to_read, 0);
+ DCHECK(stream_);
+
+ // Read until the buffer is full or until Read() returns 0 to indicate no
+ // more data.
+ bytes_read = 0;
+ int read = 0;
+ do {
+ read = static_cast<int>(
+ stream_->Read(static_cast<char*>(data_out) + bytes_read, 1,
+ bytes_to_read - bytes_read));
+ bytes_read += read;
+ } while (read != 0 && bytes_read < bytes_to_read);
+
+ return (bytes_read > 0);
+}
+
+void CefStreamResourceHandler::Cancel() {}
diff --git a/libcef_dll/wrapper/cef_xml_object.cc b/libcef_dll/wrapper/cef_xml_object.cc
new file mode 100644
index 00000000..3cdccfb3
--- /dev/null
+++ b/libcef_dll/wrapper/cef_xml_object.cc
@@ -0,0 +1,467 @@
+// Copyright (c) 2010 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "include/wrapper/cef_xml_object.h"
+
+#include <sstream>
+
+#include "include/base/cef_logging.h"
+#include "include/cef_stream.h"
+
+namespace {
+
+class CefXmlObjectLoader {
+ public:
+ explicit CefXmlObjectLoader(CefRefPtr<CefXmlObject> root_object)
+ : root_object_(root_object) {}
+
+ CefXmlObjectLoader(const CefXmlObjectLoader&) = delete;
+ CefXmlObjectLoader& operator=(const CefXmlObjectLoader&) = delete;
+
+ bool Load(CefRefPtr<CefStreamReader> stream,
+ CefXmlReader::EncodingType encodingType,
+ const CefString& URI) {
+ CefRefPtr<CefXmlReader> reader(
+ CefXmlReader::Create(stream, encodingType, URI));
+ if (!reader.get()) {
+ return false;
+ }
+
+ bool ret = reader->MoveToNextNode();
+ if (ret) {
+ CefRefPtr<CefXmlObject> cur_object(root_object_), new_object;
+ CefXmlObject::ObjectVector queue;
+ int cur_depth, value_depth = -1;
+ CefXmlReader::NodeType cur_type;
+ std::stringstream cur_value;
+ bool last_has_ns = false;
+
+ queue.push_back(root_object_);
+
+ do {
+ cur_depth = reader->GetDepth();
+ if (value_depth >= 0 && cur_depth > value_depth) {
+ // The current node has already been parsed as part of a value.
+ continue;
+ }
+
+ cur_type = reader->GetType();
+ if (cur_type == XML_NODE_ELEMENT_START) {
+ if (cur_depth == value_depth) {
+ // Add to the current value.
+ cur_value << std::string(reader->GetOuterXml());
+ continue;
+ } else if (last_has_ns && reader->GetPrefix().empty()) {
+ if (!cur_object->HasChildren()) {
+ // Start a new value because the last element has a namespace and
+ // this element does not.
+ value_depth = cur_depth;
+ cur_value << std::string(reader->GetOuterXml());
+ } else {
+ // Value following a child element is not allowed.
+ std::stringstream ss;
+ ss << "Value following child element, line "
+ << reader->GetLineNumber();
+ load_error_ = ss.str();
+ ret = false;
+ break;
+ }
+ } else {
+ // Start a new element.
+ new_object = new CefXmlObject(reader->GetQualifiedName());
+ cur_object->AddChild(new_object);
+ last_has_ns = !reader->GetPrefix().empty();
+
+ if (!reader->IsEmptyElement()) {
+ // The new element potentially has a value and/or children, so
+ // set the current object and add the object to the queue.
+ cur_object = new_object;
+ queue.push_back(cur_object);
+ }
+
+ if (reader->HasAttributes() && reader->MoveToFirstAttribute()) {
+ // Read all object attributes.
+ do {
+ new_object->SetAttributeValue(reader->GetQualifiedName(),
+ reader->GetValue());
+ } while (reader->MoveToNextAttribute());
+ reader->MoveToCarryingElement();
+ }
+ }
+ } else if (cur_type == XML_NODE_ELEMENT_END) {
+ if (cur_depth == value_depth) {
+ // Ending an element that is already in the value.
+ continue;
+ } else if (cur_depth < value_depth) {
+ // Done with parsing the value portion of the current element.
+ cur_object->SetValue(cur_value.str());
+ cur_value.str("");
+ value_depth = -1;
+ }
+
+ // Pop the current element from the queue.
+ queue.pop_back();
+
+ if (queue.empty() ||
+ cur_object->GetName() != reader->GetQualifiedName()) {
+ // Open tag without close tag or close tag without open tag should
+ // never occur (the parser catches this error).
+ NOTREACHED();
+ std::stringstream ss;
+ ss << "Mismatched end tag for "
+ << std::string(cur_object->GetName()) << ", line "
+ << reader->GetLineNumber();
+ load_error_ = ss.str();
+ ret = false;
+ break;
+ }
+
+ // Set the current object to the previous object in the queue.
+ cur_object = queue.back().get();
+ } else if (cur_type == XML_NODE_TEXT || cur_type == XML_NODE_CDATA ||
+ cur_type == XML_NODE_ENTITY_REFERENCE) {
+ if (cur_depth == value_depth) {
+ // Add to the current value.
+ cur_value << std::string(reader->GetValue());
+ } else if (!cur_object->HasChildren()) {
+ // Start a new value.
+ value_depth = cur_depth;
+ cur_value << std::string(reader->GetValue());
+ } else {
+ // Value following a child element is not allowed.
+ std::stringstream ss;
+ ss << "Value following child element, line "
+ << reader->GetLineNumber();
+ load_error_ = ss.str();
+ ret = false;
+ break;
+ }
+ }
+ } while (reader->MoveToNextNode());
+ }
+
+ if (reader->HasError()) {
+ load_error_ = reader->GetError();
+ return false;
+ }
+
+ return ret;
+ }
+
+ CefString GetLoadError() { return load_error_; }
+
+ private:
+ CefString load_error_;
+ CefRefPtr<CefXmlObject> root_object_;
+};
+
+} // namespace
+
+CefXmlObject::CefXmlObject(const CefString& name)
+ : name_(name), parent_(nullptr) {}
+
+CefXmlObject::~CefXmlObject() {}
+
+bool CefXmlObject::Load(CefRefPtr<CefStreamReader> stream,
+ CefXmlReader::EncodingType encodingType,
+ const CefString& URI,
+ CefString* loadError) {
+ Clear();
+
+ CefXmlObjectLoader loader(this);
+ if (!loader.Load(stream, encodingType, URI)) {
+ if (loadError) {
+ *loadError = loader.GetLoadError();
+ }
+ return false;
+ }
+ return true;
+}
+
+void CefXmlObject::Set(CefRefPtr<CefXmlObject> object) {
+ DCHECK(object.get());
+
+ Clear();
+
+ name_ = object->GetName();
+ Append(object, true);
+}
+
+void CefXmlObject::Append(CefRefPtr<CefXmlObject> object,
+ bool overwriteAttributes) {
+ DCHECK(object.get());
+
+ if (object->HasChildren()) {
+ ObjectVector children;
+ object->GetChildren(children);
+ ObjectVector::const_iterator it = children.begin();
+ for (; it != children.end(); ++it) {
+ AddChild((*it)->Duplicate());
+ }
+ }
+
+ if (object->HasAttributes()) {
+ AttributeMap attributes;
+ object->GetAttributes(attributes);
+ AttributeMap::const_iterator it = attributes.begin();
+ for (; it != attributes.end(); ++it) {
+ if (overwriteAttributes || !HasAttribute(it->first)) {
+ SetAttributeValue(it->first, it->second);
+ }
+ }
+ }
+}
+
+CefRefPtr<CefXmlObject> CefXmlObject::Duplicate() {
+ CefRefPtr<CefXmlObject> new_obj;
+ {
+ base::AutoLock lock_scope(lock_);
+ new_obj = new CefXmlObject(name_);
+ new_obj->Append(this, true);
+ }
+ return new_obj;
+}
+
+void CefXmlObject::Clear() {
+ ClearChildren();
+ ClearAttributes();
+}
+
+CefString CefXmlObject::GetName() {
+ CefString name;
+ {
+ base::AutoLock lock_scope(lock_);
+ name = name_;
+ }
+ return name;
+}
+
+bool CefXmlObject::SetName(const CefString& name) {
+ DCHECK(!name.empty());
+ if (name.empty()) {
+ return false;
+ }
+
+ base::AutoLock lock_scope(lock_);
+ name_ = name;
+ return true;
+}
+
+bool CefXmlObject::HasParent() {
+ base::AutoLock lock_scope(lock_);
+ return (parent_ != nullptr);
+}
+
+CefRefPtr<CefXmlObject> CefXmlObject::GetParent() {
+ CefRefPtr<CefXmlObject> parent;
+ {
+ base::AutoLock lock_scope(lock_);
+ parent = parent_;
+ }
+ return parent;
+}
+
+bool CefXmlObject::HasValue() {
+ base::AutoLock lock_scope(lock_);
+ return !value_.empty();
+}
+
+CefString CefXmlObject::GetValue() {
+ CefString value;
+ {
+ base::AutoLock lock_scope(lock_);
+ value = value_;
+ }
+ return value;
+}
+
+bool CefXmlObject::SetValue(const CefString& value) {
+ base::AutoLock lock_scope(lock_);
+ DCHECK(children_.empty());
+ if (!children_.empty()) {
+ return false;
+ }
+ value_ = value;
+ return true;
+}
+
+bool CefXmlObject::HasAttributes() {
+ base::AutoLock lock_scope(lock_);
+ return !attributes_.empty();
+}
+
+size_t CefXmlObject::GetAttributeCount() {
+ base::AutoLock lock_scope(lock_);
+ return attributes_.size();
+}
+
+bool CefXmlObject::HasAttribute(const CefString& name) {
+ if (name.empty()) {
+ return false;
+ }
+
+ base::AutoLock lock_scope(lock_);
+ AttributeMap::const_iterator it = attributes_.find(name);
+ return (it != attributes_.end());
+}
+
+CefString CefXmlObject::GetAttributeValue(const CefString& name) {
+ DCHECK(!name.empty());
+ CefString value;
+ if (!name.empty()) {
+ base::AutoLock lock_scope(lock_);
+ AttributeMap::const_iterator it = attributes_.find(name);
+ if (it != attributes_.end()) {
+ value = it->second;
+ }
+ }
+ return value;
+}
+
+bool CefXmlObject::SetAttributeValue(const CefString& name,
+ const CefString& value) {
+ DCHECK(!name.empty());
+ if (name.empty()) {
+ return false;
+ }
+
+ base::AutoLock lock_scope(lock_);
+ AttributeMap::iterator it = attributes_.find(name);
+ if (it != attributes_.end()) {
+ it->second = value;
+ } else {
+ attributes_.insert(std::make_pair(name, value));
+ }
+ return true;
+}
+
+size_t CefXmlObject::GetAttributes(AttributeMap& attributes) {
+ base::AutoLock lock_scope(lock_);
+ attributes = attributes_;
+ return attributes_.size();
+}
+
+void CefXmlObject::ClearAttributes() {
+ base::AutoLock lock_scope(lock_);
+ attributes_.clear();
+}
+
+bool CefXmlObject::HasChildren() {
+ base::AutoLock lock_scope(lock_);
+ return !children_.empty();
+}
+
+size_t CefXmlObject::GetChildCount() {
+ base::AutoLock lock_scope(lock_);
+ return children_.size();
+}
+
+bool CefXmlObject::HasChild(CefRefPtr<CefXmlObject> child) {
+ DCHECK(child.get());
+
+ base::AutoLock lock_scope(lock_);
+ ObjectVector::const_iterator it = children_.begin();
+ for (; it != children_.end(); ++it) {
+ if ((*it).get() == child.get()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool CefXmlObject::AddChild(CefRefPtr<CefXmlObject> child) {
+ DCHECK(child.get());
+ if (!child.get()) {
+ return false;
+ }
+
+ CefRefPtr<CefXmlObject> parent = child->GetParent();
+ DCHECK(!parent);
+ if (parent) {
+ return false;
+ }
+
+ base::AutoLock lock_scope(lock_);
+
+ children_.push_back(child);
+ child->SetParent(this);
+ return true;
+}
+
+bool CefXmlObject::RemoveChild(CefRefPtr<CefXmlObject> child) {
+ DCHECK(child.get());
+
+ base::AutoLock lock_scope(lock_);
+ ObjectVector::iterator it = children_.begin();
+ for (; it != children_.end(); ++it) {
+ if ((*it).get() == child.get()) {
+ children_.erase(it);
+ child->SetParent(nullptr);
+ return true;
+ }
+ }
+ return false;
+}
+
+size_t CefXmlObject::GetChildren(ObjectVector& children) {
+ base::AutoLock lock_scope(lock_);
+ children = children_;
+ return children_.size();
+}
+
+void CefXmlObject::ClearChildren() {
+ base::AutoLock lock_scope(lock_);
+ ObjectVector::iterator it = children_.begin();
+ for (; it != children_.end(); ++it) {
+ (*it)->SetParent(nullptr);
+ }
+ children_.clear();
+}
+
+CefRefPtr<CefXmlObject> CefXmlObject::FindChild(const CefString& name) {
+ DCHECK(!name.empty());
+ if (name.empty()) {
+ return nullptr;
+ }
+
+ base::AutoLock lock_scope(lock_);
+ ObjectVector::const_iterator it = children_.begin();
+ for (; it != children_.end(); ++it) {
+ if ((*it)->GetName() == name) {
+ return (*it);
+ }
+ }
+ return nullptr;
+}
+
+size_t CefXmlObject::FindChildren(const CefString& name,
+ ObjectVector& children) {
+ DCHECK(!name.empty());
+ if (name.empty()) {
+ return 0;
+ }
+
+ size_t ct = 0;
+
+ base::AutoLock lock_scope(lock_);
+ ObjectVector::const_iterator it = children_.begin();
+ for (; it != children_.end(); ++it) {
+ if ((*it)->GetName() == name) {
+ children.push_back(*it);
+ ct++;
+ }
+ }
+ return ct;
+}
+
+void CefXmlObject::SetParent(CefXmlObject* parent) {
+ base::AutoLock lock_scope(lock_);
+ if (parent) {
+ DCHECK(parent_ == nullptr);
+ parent_ = parent;
+ } else {
+ DCHECK(parent_ != nullptr);
+ parent_ = nullptr;
+ }
+}
diff --git a/libcef_dll/wrapper/cef_zip_archive.cc b/libcef_dll/wrapper/cef_zip_archive.cc
new file mode 100644
index 00000000..3ebff15b
--- /dev/null
+++ b/libcef_dll/wrapper/cef_zip_archive.cc
@@ -0,0 +1,177 @@
+// Copyright (c) 2010 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "include/wrapper/cef_zip_archive.h"
+
+#include <algorithm>
+#include <memory>
+
+#include "include/base/cef_logging.h"
+#include "include/cef_stream.h"
+#include "include/cef_zip_reader.h"
+#include "include/wrapper/cef_byte_read_handler.h"
+
+#if defined(OS_LINUX)
+#include <wctype.h>
+#endif
+
+namespace {
+
+// Convert |str| to lowercase in a Unicode-friendly manner.
+CefString ToLower(const CefString& str) {
+ std::wstring wstr = str;
+ std::transform(wstr.begin(), wstr.end(), wstr.begin(), towlower);
+ return wstr;
+}
+
+class CefZipFile : public CefZipArchive::File {
+ public:
+ CefZipFile() : data_size_(0) {}
+
+ CefZipFile(const CefZipFile&) = delete;
+ CefZipFile& operator=(const CefZipFile&) = delete;
+
+ bool Initialize(size_t data_size) {
+ data_.reset(new (std::nothrow) unsigned char[data_size]);
+ if (data_) {
+ data_size_ = data_size;
+ return true;
+ } else {
+ DLOG(ERROR) << "Failed to allocate " << data_size << " bytes of memory";
+ data_size_ = 0;
+ return false;
+ }
+ }
+
+ virtual const unsigned char* GetData() const override { return data_.get(); }
+
+ virtual size_t GetDataSize() const override { return data_size_; }
+
+ virtual CefRefPtr<CefStreamReader> GetStreamReader() const override {
+ CefRefPtr<CefReadHandler> handler(new CefByteReadHandler(
+ data_.get(), data_size_, const_cast<CefZipFile*>(this)));
+ return CefStreamReader::CreateForHandler(handler);
+ }
+
+ unsigned char* data() { return data_.get(); }
+
+ private:
+ size_t data_size_;
+ std::unique_ptr<unsigned char[]> data_;
+
+ IMPLEMENT_REFCOUNTING(CefZipFile);
+};
+
+} // namespace
+
+// CefZipArchive implementation
+
+CefZipArchive::CefZipArchive() {}
+
+CefZipArchive::~CefZipArchive() {}
+
+size_t CefZipArchive::Load(CefRefPtr<CefStreamReader> stream,
+ const CefString& password,
+ bool overwriteExisting) {
+ base::AutoLock lock_scope(lock_);
+
+ CefRefPtr<CefZipReader> reader(CefZipReader::Create(stream));
+ if (!reader.get()) {
+ return 0;
+ }
+
+ if (!reader->MoveToFirstFile()) {
+ return 0;
+ }
+
+ FileMap::iterator it;
+ size_t count = 0;
+
+ do {
+ const size_t size = static_cast<size_t>(reader->GetFileSize());
+ if (size == 0) {
+ // Skip directories and empty files.
+ continue;
+ }
+
+ if (!reader->OpenFile(password)) {
+ break;
+ }
+
+ const CefString& name = ToLower(reader->GetFileName());
+
+ it = contents_.find(name);
+ if (it != contents_.end()) {
+ if (overwriteExisting) {
+ contents_.erase(it);
+ } else { // Skip files that already exist.
+ continue;
+ }
+ }
+
+ CefRefPtr<CefZipFile> contents = new CefZipFile();
+ if (!contents->Initialize(size)) {
+ continue;
+ }
+ unsigned char* data = contents->data();
+ size_t offset = 0;
+
+ // Read the file contents.
+ do {
+ offset += reader->ReadFile(data + offset, size - offset);
+ } while (offset < size && !reader->Eof());
+
+ DCHECK(offset == size);
+
+ reader->CloseFile();
+ count++;
+
+ // Add the file to the map.
+ contents_.insert(std::make_pair(name, contents.get()));
+ } while (reader->MoveToNextFile());
+
+ return count;
+}
+
+void CefZipArchive::Clear() {
+ base::AutoLock lock_scope(lock_);
+ contents_.clear();
+}
+
+size_t CefZipArchive::GetFileCount() const {
+ base::AutoLock lock_scope(lock_);
+ return contents_.size();
+}
+
+bool CefZipArchive::HasFile(const CefString& fileName) const {
+ base::AutoLock lock_scope(lock_);
+ FileMap::const_iterator it = contents_.find(ToLower(fileName));
+ return (it != contents_.end());
+}
+
+CefRefPtr<CefZipArchive::File> CefZipArchive::GetFile(
+ const CefString& fileName) const {
+ base::AutoLock lock_scope(lock_);
+ FileMap::const_iterator it = contents_.find(ToLower(fileName));
+ if (it != contents_.end()) {
+ return it->second;
+ }
+ return nullptr;
+}
+
+bool CefZipArchive::RemoveFile(const CefString& fileName) {
+ base::AutoLock lock_scope(lock_);
+ FileMap::iterator it = contents_.find(ToLower(fileName));
+ if (it != contents_.end()) {
+ contents_.erase(it);
+ return true;
+ }
+ return false;
+}
+
+size_t CefZipArchive::GetFiles(FileMap& map) const {
+ base::AutoLock lock_scope(lock_);
+ map = contents_;
+ return contents_.size();
+}
diff --git a/libcef_dll/wrapper/libcef_dll_dylib.cc b/libcef_dll/wrapper/libcef_dll_dylib.cc
new file mode 100644
index 00000000..6c2219bc
--- /dev/null
+++ b/libcef_dll/wrapper/libcef_dll_dylib.cc
@@ -0,0 +1,1816 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=c3d95d65039cab3684964b164afe772d8a614f82$
+//
+
+#include <dlfcn.h>
+#include <stdio.h>
+
+#include "include/base/cef_compiler_specific.h"
+#include "include/capi/cef_app_capi.h"
+#include "include/capi/cef_browser_capi.h"
+#include "include/capi/cef_command_line_capi.h"
+#include "include/capi/cef_cookie_capi.h"
+#include "include/capi/cef_crash_util_capi.h"
+#include "include/capi/cef_drag_data_capi.h"
+#include "include/capi/cef_file_util_capi.h"
+#include "include/capi/cef_i18n_util_capi.h"
+#include "include/capi/cef_image_capi.h"
+#include "include/capi/cef_media_router_capi.h"
+#include "include/capi/cef_menu_model_capi.h"
+#include "include/capi/cef_origin_whitelist_capi.h"
+#include "include/capi/cef_parser_capi.h"
+#include "include/capi/cef_path_util_capi.h"
+#include "include/capi/cef_preference_capi.h"
+#include "include/capi/cef_print_settings_capi.h"
+#include "include/capi/cef_process_message_capi.h"
+#include "include/capi/cef_process_util_capi.h"
+#include "include/capi/cef_request_capi.h"
+#include "include/capi/cef_request_context_capi.h"
+#include "include/capi/cef_resource_bundle_capi.h"
+#include "include/capi/cef_response_capi.h"
+#include "include/capi/cef_scheme_capi.h"
+#include "include/capi/cef_server_capi.h"
+#include "include/capi/cef_shared_process_message_builder_capi.h"
+#include "include/capi/cef_ssl_info_capi.h"
+#include "include/capi/cef_stream_capi.h"
+#include "include/capi/cef_task_capi.h"
+#include "include/capi/cef_thread_capi.h"
+#include "include/capi/cef_trace_capi.h"
+#include "include/capi/cef_urlrequest_capi.h"
+#include "include/capi/cef_v8_capi.h"
+#include "include/capi/cef_values_capi.h"
+#include "include/capi/cef_waitable_event_capi.h"
+#include "include/capi/cef_xml_reader_capi.h"
+#include "include/capi/cef_zip_reader_capi.h"
+#include "include/capi/test/cef_test_helpers_capi.h"
+#include "include/capi/test/cef_test_server_capi.h"
+#include "include/capi/test/cef_translator_test_capi.h"
+#include "include/capi/views/cef_browser_view_capi.h"
+#include "include/capi/views/cef_display_capi.h"
+#include "include/capi/views/cef_label_button_capi.h"
+#include "include/capi/views/cef_menu_button_capi.h"
+#include "include/capi/views/cef_panel_capi.h"
+#include "include/capi/views/cef_scroll_view_capi.h"
+#include "include/capi/views/cef_textfield_capi.h"
+#include "include/capi/views/cef_window_capi.h"
+#include "include/cef_api_hash.h"
+#include "include/cef_version.h"
+#include "include/internal/cef_logging_internal.h"
+#include "include/internal/cef_string_list.h"
+#include "include/internal/cef_string_map.h"
+#include "include/internal/cef_string_multimap.h"
+#include "include/internal/cef_string_types.h"
+#include "include/internal/cef_thread_internal.h"
+#include "include/internal/cef_time.h"
+#include "include/internal/cef_trace_event_internal.h"
+#include "include/wrapper/cef_library_loader.h"
+
+// GLOBAL WRAPPER FUNCTIONS - Do not edit by hand.
+
+namespace {
+
+void* g_libcef_handle = nullptr;
+
+void* libcef_get_ptr(const char* path, const char* name) {
+ void* ptr = dlsym(g_libcef_handle, name);
+ if (!ptr) {
+ fprintf(stderr, "dlsym %s: %s\n", path, dlerror());
+ }
+ return ptr;
+}
+
+struct libcef_pointers {
+ decltype(&cef_execute_process) cef_execute_process;
+ decltype(&cef_initialize) cef_initialize;
+ decltype(&cef_shutdown) cef_shutdown;
+ decltype(&cef_do_message_loop_work) cef_do_message_loop_work;
+ decltype(&cef_run_message_loop) cef_run_message_loop;
+ decltype(&cef_quit_message_loop) cef_quit_message_loop;
+ decltype(&cef_crash_reporting_enabled) cef_crash_reporting_enabled;
+ decltype(&cef_set_crash_key_value) cef_set_crash_key_value;
+ decltype(&cef_create_directory) cef_create_directory;
+ decltype(&cef_get_temp_directory) cef_get_temp_directory;
+ decltype(&cef_create_new_temp_directory) cef_create_new_temp_directory;
+ decltype(&cef_create_temp_directory_in_directory)
+ cef_create_temp_directory_in_directory;
+ decltype(&cef_directory_exists) cef_directory_exists;
+ decltype(&cef_delete_file) cef_delete_file;
+ decltype(&cef_zip_directory) cef_zip_directory;
+ decltype(&cef_load_crlsets_file) cef_load_crlsets_file;
+ decltype(&cef_is_rtl) cef_is_rtl;
+ decltype(&cef_add_cross_origin_whitelist_entry)
+ cef_add_cross_origin_whitelist_entry;
+ decltype(&cef_remove_cross_origin_whitelist_entry)
+ cef_remove_cross_origin_whitelist_entry;
+ decltype(&cef_clear_cross_origin_whitelist) cef_clear_cross_origin_whitelist;
+ decltype(&cef_resolve_url) cef_resolve_url;
+ decltype(&cef_parse_url) cef_parse_url;
+ decltype(&cef_create_url) cef_create_url;
+ decltype(&cef_format_url_for_security_display)
+ cef_format_url_for_security_display;
+ decltype(&cef_get_mime_type) cef_get_mime_type;
+ decltype(&cef_get_extensions_for_mime_type) cef_get_extensions_for_mime_type;
+ decltype(&cef_base64encode) cef_base64encode;
+ decltype(&cef_base64decode) cef_base64decode;
+ decltype(&cef_uriencode) cef_uriencode;
+ decltype(&cef_uridecode) cef_uridecode;
+ decltype(&cef_parse_json) cef_parse_json;
+ decltype(&cef_parse_json_buffer) cef_parse_json_buffer;
+ decltype(&cef_parse_jsonand_return_error) cef_parse_jsonand_return_error;
+ decltype(&cef_write_json) cef_write_json;
+ decltype(&cef_get_path) cef_get_path;
+ decltype(&cef_launch_process) cef_launch_process;
+ decltype(&cef_register_scheme_handler_factory)
+ cef_register_scheme_handler_factory;
+ decltype(&cef_clear_scheme_handler_factories)
+ cef_clear_scheme_handler_factories;
+ decltype(&cef_is_cert_status_error) cef_is_cert_status_error;
+ decltype(&cef_currently_on) cef_currently_on;
+ decltype(&cef_post_task) cef_post_task;
+ decltype(&cef_post_delayed_task) cef_post_delayed_task;
+ decltype(&cef_begin_tracing) cef_begin_tracing;
+ decltype(&cef_end_tracing) cef_end_tracing;
+ decltype(&cef_now_from_system_trace_time) cef_now_from_system_trace_time;
+ decltype(&cef_register_extension) cef_register_extension;
+ decltype(&cef_execute_java_script_with_user_gesture_for_tests)
+ cef_execute_java_script_with_user_gesture_for_tests;
+ decltype(&cef_set_data_directory_for_tests) cef_set_data_directory_for_tests;
+ decltype(&cef_browser_host_create_browser) cef_browser_host_create_browser;
+ decltype(&cef_browser_host_create_browser_sync)
+ cef_browser_host_create_browser_sync;
+ decltype(&cef_command_line_create) cef_command_line_create;
+ decltype(&cef_command_line_get_global) cef_command_line_get_global;
+ decltype(&cef_cookie_manager_get_global_manager)
+ cef_cookie_manager_get_global_manager;
+ decltype(&cef_drag_data_create) cef_drag_data_create;
+ decltype(&cef_image_create) cef_image_create;
+ decltype(&cef_media_router_get_global) cef_media_router_get_global;
+ decltype(&cef_menu_model_create) cef_menu_model_create;
+ decltype(&cef_preference_manager_get_global)
+ cef_preference_manager_get_global;
+ decltype(&cef_print_settings_create) cef_print_settings_create;
+ decltype(&cef_process_message_create) cef_process_message_create;
+ decltype(&cef_request_create) cef_request_create;
+ decltype(&cef_post_data_create) cef_post_data_create;
+ decltype(&cef_post_data_element_create) cef_post_data_element_create;
+ decltype(&cef_request_context_get_global_context)
+ cef_request_context_get_global_context;
+ decltype(&cef_request_context_create_context)
+ cef_request_context_create_context;
+ decltype(&cef_create_context_shared) cef_create_context_shared;
+ decltype(&cef_resource_bundle_get_global) cef_resource_bundle_get_global;
+ decltype(&cef_response_create) cef_response_create;
+ decltype(&cef_server_create) cef_server_create;
+ decltype(&cef_shared_process_message_builder_create)
+ cef_shared_process_message_builder_create;
+ decltype(&cef_stream_reader_create_for_file)
+ cef_stream_reader_create_for_file;
+ decltype(&cef_stream_reader_create_for_data)
+ cef_stream_reader_create_for_data;
+ decltype(&cef_stream_reader_create_for_handler)
+ cef_stream_reader_create_for_handler;
+ decltype(&cef_stream_writer_create_for_file)
+ cef_stream_writer_create_for_file;
+ decltype(&cef_stream_writer_create_for_handler)
+ cef_stream_writer_create_for_handler;
+ decltype(&cef_task_runner_get_for_current_thread)
+ cef_task_runner_get_for_current_thread;
+ decltype(&cef_task_runner_get_for_thread) cef_task_runner_get_for_thread;
+ decltype(&cef_thread_create) cef_thread_create;
+ decltype(&cef_urlrequest_create) cef_urlrequest_create;
+ decltype(&cef_v8context_get_current_context)
+ cef_v8context_get_current_context;
+ decltype(&cef_v8context_get_entered_context)
+ cef_v8context_get_entered_context;
+ decltype(&cef_v8context_in_context) cef_v8context_in_context;
+ decltype(&cef_v8value_create_undefined) cef_v8value_create_undefined;
+ decltype(&cef_v8value_create_null) cef_v8value_create_null;
+ decltype(&cef_v8value_create_bool) cef_v8value_create_bool;
+ decltype(&cef_v8value_create_int) cef_v8value_create_int;
+ decltype(&cef_v8value_create_uint) cef_v8value_create_uint;
+ decltype(&cef_v8value_create_double) cef_v8value_create_double;
+ decltype(&cef_v8value_create_date) cef_v8value_create_date;
+ decltype(&cef_v8value_create_string) cef_v8value_create_string;
+ decltype(&cef_v8value_create_object) cef_v8value_create_object;
+ decltype(&cef_v8value_create_array) cef_v8value_create_array;
+ decltype(&cef_v8value_create_array_buffer) cef_v8value_create_array_buffer;
+ decltype(&cef_v8value_create_function) cef_v8value_create_function;
+ decltype(&cef_v8value_create_promise) cef_v8value_create_promise;
+ decltype(&cef_v8stack_trace_get_current) cef_v8stack_trace_get_current;
+ decltype(&cef_value_create) cef_value_create;
+ decltype(&cef_binary_value_create) cef_binary_value_create;
+ decltype(&cef_dictionary_value_create) cef_dictionary_value_create;
+ decltype(&cef_list_value_create) cef_list_value_create;
+ decltype(&cef_waitable_event_create) cef_waitable_event_create;
+ decltype(&cef_xml_reader_create) cef_xml_reader_create;
+ decltype(&cef_zip_reader_create) cef_zip_reader_create;
+ decltype(&cef_test_server_create_and_start) cef_test_server_create_and_start;
+ decltype(&cef_translator_test_create) cef_translator_test_create;
+ decltype(&cef_translator_test_ref_ptr_library_create)
+ cef_translator_test_ref_ptr_library_create;
+ decltype(&cef_translator_test_ref_ptr_library_child_create)
+ cef_translator_test_ref_ptr_library_child_create;
+ decltype(&cef_translator_test_ref_ptr_library_child_child_create)
+ cef_translator_test_ref_ptr_library_child_child_create;
+ decltype(&cef_translator_test_scoped_library_create)
+ cef_translator_test_scoped_library_create;
+ decltype(&cef_translator_test_scoped_library_child_create)
+ cef_translator_test_scoped_library_child_create;
+ decltype(&cef_translator_test_scoped_library_child_child_create)
+ cef_translator_test_scoped_library_child_child_create;
+ decltype(&cef_browser_view_create) cef_browser_view_create;
+ decltype(&cef_browser_view_get_for_browser) cef_browser_view_get_for_browser;
+ decltype(&cef_display_get_primary) cef_display_get_primary;
+ decltype(&cef_display_get_nearest_point) cef_display_get_nearest_point;
+ decltype(&cef_display_get_matching_bounds) cef_display_get_matching_bounds;
+ decltype(&cef_display_get_count) cef_display_get_count;
+ decltype(&cef_display_get_alls) cef_display_get_alls;
+ decltype(&cef_display_convert_screen_point_to_pixels)
+ cef_display_convert_screen_point_to_pixels;
+ decltype(&cef_display_convert_screen_point_from_pixels)
+ cef_display_convert_screen_point_from_pixels;
+ decltype(&cef_display_convert_screen_rect_to_pixels)
+ cef_display_convert_screen_rect_to_pixels;
+ decltype(&cef_display_convert_screen_rect_from_pixels)
+ cef_display_convert_screen_rect_from_pixels;
+ decltype(&cef_label_button_create) cef_label_button_create;
+ decltype(&cef_menu_button_create) cef_menu_button_create;
+ decltype(&cef_panel_create) cef_panel_create;
+ decltype(&cef_scroll_view_create) cef_scroll_view_create;
+ decltype(&cef_textfield_create) cef_textfield_create;
+ decltype(&cef_window_create_top_level) cef_window_create_top_level;
+ decltype(&cef_api_hash) cef_api_hash;
+ decltype(&cef_version_info) cef_version_info;
+ decltype(&cef_get_min_log_level) cef_get_min_log_level;
+ decltype(&cef_get_vlog_level) cef_get_vlog_level;
+ decltype(&cef_log) cef_log;
+ decltype(&cef_string_list_alloc) cef_string_list_alloc;
+ decltype(&cef_string_list_size) cef_string_list_size;
+ decltype(&cef_string_list_value) cef_string_list_value;
+ decltype(&cef_string_list_append) cef_string_list_append;
+ decltype(&cef_string_list_clear) cef_string_list_clear;
+ decltype(&cef_string_list_free) cef_string_list_free;
+ decltype(&cef_string_list_copy) cef_string_list_copy;
+ decltype(&cef_string_map_alloc) cef_string_map_alloc;
+ decltype(&cef_string_map_size) cef_string_map_size;
+ decltype(&cef_string_map_find) cef_string_map_find;
+ decltype(&cef_string_map_key) cef_string_map_key;
+ decltype(&cef_string_map_value) cef_string_map_value;
+ decltype(&cef_string_map_append) cef_string_map_append;
+ decltype(&cef_string_map_clear) cef_string_map_clear;
+ decltype(&cef_string_map_free) cef_string_map_free;
+ decltype(&cef_string_multimap_alloc) cef_string_multimap_alloc;
+ decltype(&cef_string_multimap_size) cef_string_multimap_size;
+ decltype(&cef_string_multimap_find_count) cef_string_multimap_find_count;
+ decltype(&cef_string_multimap_enumerate) cef_string_multimap_enumerate;
+ decltype(&cef_string_multimap_key) cef_string_multimap_key;
+ decltype(&cef_string_multimap_value) cef_string_multimap_value;
+ decltype(&cef_string_multimap_append) cef_string_multimap_append;
+ decltype(&cef_string_multimap_clear) cef_string_multimap_clear;
+ decltype(&cef_string_multimap_free) cef_string_multimap_free;
+ decltype(&cef_string_wide_set) cef_string_wide_set;
+ decltype(&cef_string_utf8_set) cef_string_utf8_set;
+ decltype(&cef_string_utf16_set) cef_string_utf16_set;
+ decltype(&cef_string_wide_clear) cef_string_wide_clear;
+ decltype(&cef_string_utf8_clear) cef_string_utf8_clear;
+ decltype(&cef_string_utf16_clear) cef_string_utf16_clear;
+ decltype(&cef_string_wide_cmp) cef_string_wide_cmp;
+ decltype(&cef_string_utf8_cmp) cef_string_utf8_cmp;
+ decltype(&cef_string_utf16_cmp) cef_string_utf16_cmp;
+ decltype(&cef_string_wide_to_utf8) cef_string_wide_to_utf8;
+ decltype(&cef_string_utf8_to_wide) cef_string_utf8_to_wide;
+ decltype(&cef_string_wide_to_utf16) cef_string_wide_to_utf16;
+ decltype(&cef_string_utf16_to_wide) cef_string_utf16_to_wide;
+ decltype(&cef_string_utf8_to_utf16) cef_string_utf8_to_utf16;
+ decltype(&cef_string_utf16_to_utf8) cef_string_utf16_to_utf8;
+ decltype(&cef_string_ascii_to_wide) cef_string_ascii_to_wide;
+ decltype(&cef_string_ascii_to_utf16) cef_string_ascii_to_utf16;
+ decltype(&cef_string_userfree_wide_alloc) cef_string_userfree_wide_alloc;
+ decltype(&cef_string_userfree_utf8_alloc) cef_string_userfree_utf8_alloc;
+ decltype(&cef_string_userfree_utf16_alloc) cef_string_userfree_utf16_alloc;
+ decltype(&cef_string_userfree_wide_free) cef_string_userfree_wide_free;
+ decltype(&cef_string_userfree_utf8_free) cef_string_userfree_utf8_free;
+ decltype(&cef_string_userfree_utf16_free) cef_string_userfree_utf16_free;
+ decltype(&cef_string_utf16_to_lower) cef_string_utf16_to_lower;
+ decltype(&cef_string_utf16_to_upper) cef_string_utf16_to_upper;
+ decltype(&cef_get_current_platform_thread_id)
+ cef_get_current_platform_thread_id;
+ decltype(&cef_get_current_platform_thread_handle)
+ cef_get_current_platform_thread_handle;
+ decltype(&cef_time_to_timet) cef_time_to_timet;
+ decltype(&cef_time_from_timet) cef_time_from_timet;
+ decltype(&cef_time_to_doublet) cef_time_to_doublet;
+ decltype(&cef_time_from_doublet) cef_time_from_doublet;
+ decltype(&cef_time_now) cef_time_now;
+ decltype(&cef_basetime_now) cef_basetime_now;
+ decltype(&cef_time_delta) cef_time_delta;
+ decltype(&cef_time_to_basetime) cef_time_to_basetime;
+ decltype(&cef_time_from_basetime) cef_time_from_basetime;
+ decltype(&cef_trace_event_instant) cef_trace_event_instant;
+ decltype(&cef_trace_event_begin) cef_trace_event_begin;
+ decltype(&cef_trace_event_end) cef_trace_event_end;
+ decltype(&cef_trace_counter) cef_trace_counter;
+ decltype(&cef_trace_counter_id) cef_trace_counter_id;
+ decltype(&cef_trace_event_async_begin) cef_trace_event_async_begin;
+ decltype(&cef_trace_event_async_step_into) cef_trace_event_async_step_into;
+ decltype(&cef_trace_event_async_step_past) cef_trace_event_async_step_past;
+ decltype(&cef_trace_event_async_end) cef_trace_event_async_end;
+
+} g_libcef_pointers = {0};
+
+#define INIT_ENTRY(name) \
+ g_libcef_pointers.name = (decltype(&name))libcef_get_ptr(path, #name); \
+ if (!g_libcef_pointers.name) { \
+ return 0; \
+ }
+
+int libcef_init_pointers(const char* path) {
+ INIT_ENTRY(cef_execute_process);
+ INIT_ENTRY(cef_initialize);
+ INIT_ENTRY(cef_shutdown);
+ INIT_ENTRY(cef_do_message_loop_work);
+ INIT_ENTRY(cef_run_message_loop);
+ INIT_ENTRY(cef_quit_message_loop);
+ INIT_ENTRY(cef_crash_reporting_enabled);
+ INIT_ENTRY(cef_set_crash_key_value);
+ INIT_ENTRY(cef_create_directory);
+ INIT_ENTRY(cef_get_temp_directory);
+ INIT_ENTRY(cef_create_new_temp_directory);
+ INIT_ENTRY(cef_create_temp_directory_in_directory);
+ INIT_ENTRY(cef_directory_exists);
+ INIT_ENTRY(cef_delete_file);
+ INIT_ENTRY(cef_zip_directory);
+ INIT_ENTRY(cef_load_crlsets_file);
+ INIT_ENTRY(cef_is_rtl);
+ INIT_ENTRY(cef_add_cross_origin_whitelist_entry);
+ INIT_ENTRY(cef_remove_cross_origin_whitelist_entry);
+ INIT_ENTRY(cef_clear_cross_origin_whitelist);
+ INIT_ENTRY(cef_resolve_url);
+ INIT_ENTRY(cef_parse_url);
+ INIT_ENTRY(cef_create_url);
+ INIT_ENTRY(cef_format_url_for_security_display);
+ INIT_ENTRY(cef_get_mime_type);
+ INIT_ENTRY(cef_get_extensions_for_mime_type);
+ INIT_ENTRY(cef_base64encode);
+ INIT_ENTRY(cef_base64decode);
+ INIT_ENTRY(cef_uriencode);
+ INIT_ENTRY(cef_uridecode);
+ INIT_ENTRY(cef_parse_json);
+ INIT_ENTRY(cef_parse_json_buffer);
+ INIT_ENTRY(cef_parse_jsonand_return_error);
+ INIT_ENTRY(cef_write_json);
+ INIT_ENTRY(cef_get_path);
+ INIT_ENTRY(cef_launch_process);
+ INIT_ENTRY(cef_register_scheme_handler_factory);
+ INIT_ENTRY(cef_clear_scheme_handler_factories);
+ INIT_ENTRY(cef_is_cert_status_error);
+ INIT_ENTRY(cef_currently_on);
+ INIT_ENTRY(cef_post_task);
+ INIT_ENTRY(cef_post_delayed_task);
+ INIT_ENTRY(cef_begin_tracing);
+ INIT_ENTRY(cef_end_tracing);
+ INIT_ENTRY(cef_now_from_system_trace_time);
+ INIT_ENTRY(cef_register_extension);
+ INIT_ENTRY(cef_execute_java_script_with_user_gesture_for_tests);
+ INIT_ENTRY(cef_set_data_directory_for_tests);
+ INIT_ENTRY(cef_browser_host_create_browser);
+ INIT_ENTRY(cef_browser_host_create_browser_sync);
+ INIT_ENTRY(cef_command_line_create);
+ INIT_ENTRY(cef_command_line_get_global);
+ INIT_ENTRY(cef_cookie_manager_get_global_manager);
+ INIT_ENTRY(cef_drag_data_create);
+ INIT_ENTRY(cef_image_create);
+ INIT_ENTRY(cef_media_router_get_global);
+ INIT_ENTRY(cef_menu_model_create);
+ INIT_ENTRY(cef_preference_manager_get_global);
+ INIT_ENTRY(cef_print_settings_create);
+ INIT_ENTRY(cef_process_message_create);
+ INIT_ENTRY(cef_request_create);
+ INIT_ENTRY(cef_post_data_create);
+ INIT_ENTRY(cef_post_data_element_create);
+ INIT_ENTRY(cef_request_context_get_global_context);
+ INIT_ENTRY(cef_request_context_create_context);
+ INIT_ENTRY(cef_create_context_shared);
+ INIT_ENTRY(cef_resource_bundle_get_global);
+ INIT_ENTRY(cef_response_create);
+ INIT_ENTRY(cef_server_create);
+ INIT_ENTRY(cef_shared_process_message_builder_create);
+ INIT_ENTRY(cef_stream_reader_create_for_file);
+ INIT_ENTRY(cef_stream_reader_create_for_data);
+ INIT_ENTRY(cef_stream_reader_create_for_handler);
+ INIT_ENTRY(cef_stream_writer_create_for_file);
+ INIT_ENTRY(cef_stream_writer_create_for_handler);
+ INIT_ENTRY(cef_task_runner_get_for_current_thread);
+ INIT_ENTRY(cef_task_runner_get_for_thread);
+ INIT_ENTRY(cef_thread_create);
+ INIT_ENTRY(cef_urlrequest_create);
+ INIT_ENTRY(cef_v8context_get_current_context);
+ INIT_ENTRY(cef_v8context_get_entered_context);
+ INIT_ENTRY(cef_v8context_in_context);
+ INIT_ENTRY(cef_v8value_create_undefined);
+ INIT_ENTRY(cef_v8value_create_null);
+ INIT_ENTRY(cef_v8value_create_bool);
+ INIT_ENTRY(cef_v8value_create_int);
+ INIT_ENTRY(cef_v8value_create_uint);
+ INIT_ENTRY(cef_v8value_create_double);
+ INIT_ENTRY(cef_v8value_create_date);
+ INIT_ENTRY(cef_v8value_create_string);
+ INIT_ENTRY(cef_v8value_create_object);
+ INIT_ENTRY(cef_v8value_create_array);
+ INIT_ENTRY(cef_v8value_create_array_buffer);
+ INIT_ENTRY(cef_v8value_create_function);
+ INIT_ENTRY(cef_v8value_create_promise);
+ INIT_ENTRY(cef_v8stack_trace_get_current);
+ INIT_ENTRY(cef_value_create);
+ INIT_ENTRY(cef_binary_value_create);
+ INIT_ENTRY(cef_dictionary_value_create);
+ INIT_ENTRY(cef_list_value_create);
+ INIT_ENTRY(cef_waitable_event_create);
+ INIT_ENTRY(cef_xml_reader_create);
+ INIT_ENTRY(cef_zip_reader_create);
+ INIT_ENTRY(cef_test_server_create_and_start);
+ INIT_ENTRY(cef_translator_test_create);
+ INIT_ENTRY(cef_translator_test_ref_ptr_library_create);
+ INIT_ENTRY(cef_translator_test_ref_ptr_library_child_create);
+ INIT_ENTRY(cef_translator_test_ref_ptr_library_child_child_create);
+ INIT_ENTRY(cef_translator_test_scoped_library_create);
+ INIT_ENTRY(cef_translator_test_scoped_library_child_create);
+ INIT_ENTRY(cef_translator_test_scoped_library_child_child_create);
+ INIT_ENTRY(cef_browser_view_create);
+ INIT_ENTRY(cef_browser_view_get_for_browser);
+ INIT_ENTRY(cef_display_get_primary);
+ INIT_ENTRY(cef_display_get_nearest_point);
+ INIT_ENTRY(cef_display_get_matching_bounds);
+ INIT_ENTRY(cef_display_get_count);
+ INIT_ENTRY(cef_display_get_alls);
+ INIT_ENTRY(cef_display_convert_screen_point_to_pixels);
+ INIT_ENTRY(cef_display_convert_screen_point_from_pixels);
+ INIT_ENTRY(cef_display_convert_screen_rect_to_pixels);
+ INIT_ENTRY(cef_display_convert_screen_rect_from_pixels);
+ INIT_ENTRY(cef_label_button_create);
+ INIT_ENTRY(cef_menu_button_create);
+ INIT_ENTRY(cef_panel_create);
+ INIT_ENTRY(cef_scroll_view_create);
+ INIT_ENTRY(cef_textfield_create);
+ INIT_ENTRY(cef_window_create_top_level);
+ INIT_ENTRY(cef_api_hash);
+ INIT_ENTRY(cef_version_info);
+ INIT_ENTRY(cef_get_min_log_level);
+ INIT_ENTRY(cef_get_vlog_level);
+ INIT_ENTRY(cef_log);
+ INIT_ENTRY(cef_string_list_alloc);
+ INIT_ENTRY(cef_string_list_size);
+ INIT_ENTRY(cef_string_list_value);
+ INIT_ENTRY(cef_string_list_append);
+ INIT_ENTRY(cef_string_list_clear);
+ INIT_ENTRY(cef_string_list_free);
+ INIT_ENTRY(cef_string_list_copy);
+ INIT_ENTRY(cef_string_map_alloc);
+ INIT_ENTRY(cef_string_map_size);
+ INIT_ENTRY(cef_string_map_find);
+ INIT_ENTRY(cef_string_map_key);
+ INIT_ENTRY(cef_string_map_value);
+ INIT_ENTRY(cef_string_map_append);
+ INIT_ENTRY(cef_string_map_clear);
+ INIT_ENTRY(cef_string_map_free);
+ INIT_ENTRY(cef_string_multimap_alloc);
+ INIT_ENTRY(cef_string_multimap_size);
+ INIT_ENTRY(cef_string_multimap_find_count);
+ INIT_ENTRY(cef_string_multimap_enumerate);
+ INIT_ENTRY(cef_string_multimap_key);
+ INIT_ENTRY(cef_string_multimap_value);
+ INIT_ENTRY(cef_string_multimap_append);
+ INIT_ENTRY(cef_string_multimap_clear);
+ INIT_ENTRY(cef_string_multimap_free);
+ INIT_ENTRY(cef_string_wide_set);
+ INIT_ENTRY(cef_string_utf8_set);
+ INIT_ENTRY(cef_string_utf16_set);
+ INIT_ENTRY(cef_string_wide_clear);
+ INIT_ENTRY(cef_string_utf8_clear);
+ INIT_ENTRY(cef_string_utf16_clear);
+ INIT_ENTRY(cef_string_wide_cmp);
+ INIT_ENTRY(cef_string_utf8_cmp);
+ INIT_ENTRY(cef_string_utf16_cmp);
+ INIT_ENTRY(cef_string_wide_to_utf8);
+ INIT_ENTRY(cef_string_utf8_to_wide);
+ INIT_ENTRY(cef_string_wide_to_utf16);
+ INIT_ENTRY(cef_string_utf16_to_wide);
+ INIT_ENTRY(cef_string_utf8_to_utf16);
+ INIT_ENTRY(cef_string_utf16_to_utf8);
+ INIT_ENTRY(cef_string_ascii_to_wide);
+ INIT_ENTRY(cef_string_ascii_to_utf16);
+ INIT_ENTRY(cef_string_userfree_wide_alloc);
+ INIT_ENTRY(cef_string_userfree_utf8_alloc);
+ INIT_ENTRY(cef_string_userfree_utf16_alloc);
+ INIT_ENTRY(cef_string_userfree_wide_free);
+ INIT_ENTRY(cef_string_userfree_utf8_free);
+ INIT_ENTRY(cef_string_userfree_utf16_free);
+ INIT_ENTRY(cef_string_utf16_to_lower);
+ INIT_ENTRY(cef_string_utf16_to_upper);
+ INIT_ENTRY(cef_get_current_platform_thread_id);
+ INIT_ENTRY(cef_get_current_platform_thread_handle);
+ INIT_ENTRY(cef_time_to_timet);
+ INIT_ENTRY(cef_time_from_timet);
+ INIT_ENTRY(cef_time_to_doublet);
+ INIT_ENTRY(cef_time_from_doublet);
+ INIT_ENTRY(cef_time_now);
+ INIT_ENTRY(cef_basetime_now);
+ INIT_ENTRY(cef_time_delta);
+ INIT_ENTRY(cef_time_to_basetime);
+ INIT_ENTRY(cef_time_from_basetime);
+ INIT_ENTRY(cef_trace_event_instant);
+ INIT_ENTRY(cef_trace_event_begin);
+ INIT_ENTRY(cef_trace_event_end);
+ INIT_ENTRY(cef_trace_counter);
+ INIT_ENTRY(cef_trace_counter_id);
+ INIT_ENTRY(cef_trace_event_async_begin);
+ INIT_ENTRY(cef_trace_event_async_step_into);
+ INIT_ENTRY(cef_trace_event_async_step_past);
+ INIT_ENTRY(cef_trace_event_async_end);
+ return 1;
+}
+
+} // namespace
+
+int cef_load_library(const char* path) {
+ if (g_libcef_handle) {
+ return 0;
+ }
+
+ g_libcef_handle = dlopen(path, RTLD_LAZY | RTLD_LOCAL | RTLD_FIRST);
+ if (!g_libcef_handle) {
+ fprintf(stderr, "dlopen %s: %s\n", path, dlerror());
+ return 0;
+ }
+
+ if (!libcef_init_pointers(path)) {
+ cef_unload_library();
+ return 0;
+ }
+
+ return 1;
+}
+
+int cef_unload_library() {
+ int result = 0;
+ if (g_libcef_handle) {
+ result = !dlclose(g_libcef_handle);
+ if (!result) {
+ fprintf(stderr, "dlclose: %s\n", dlerror());
+ }
+ g_libcef_handle = nullptr;
+ }
+ return result;
+}
+
+NO_SANITIZE("cfi-icall")
+int cef_execute_process(const cef_main_args_t* args,
+ struct _cef_app_t* application,
+ void* windows_sandbox_info) {
+ return g_libcef_pointers.cef_execute_process(args, application,
+ windows_sandbox_info);
+}
+
+NO_SANITIZE("cfi-icall")
+int cef_initialize(const cef_main_args_t* args,
+ const struct _cef_settings_t* settings,
+ struct _cef_app_t* application,
+ void* windows_sandbox_info) {
+ return g_libcef_pointers.cef_initialize(args, settings, application,
+ windows_sandbox_info);
+}
+
+NO_SANITIZE("cfi-icall") void cef_shutdown() {
+ g_libcef_pointers.cef_shutdown();
+}
+
+NO_SANITIZE("cfi-icall") void cef_do_message_loop_work() {
+ g_libcef_pointers.cef_do_message_loop_work();
+}
+
+NO_SANITIZE("cfi-icall") void cef_run_message_loop() {
+ g_libcef_pointers.cef_run_message_loop();
+}
+
+NO_SANITIZE("cfi-icall") void cef_quit_message_loop() {
+ g_libcef_pointers.cef_quit_message_loop();
+}
+
+NO_SANITIZE("cfi-icall") int cef_crash_reporting_enabled() {
+ return g_libcef_pointers.cef_crash_reporting_enabled();
+}
+
+NO_SANITIZE("cfi-icall")
+void cef_set_crash_key_value(const cef_string_t* key,
+ const cef_string_t* value) {
+ g_libcef_pointers.cef_set_crash_key_value(key, value);
+}
+
+NO_SANITIZE("cfi-icall")
+int cef_create_directory(const cef_string_t* full_path) {
+ return g_libcef_pointers.cef_create_directory(full_path);
+}
+
+NO_SANITIZE("cfi-icall") int cef_get_temp_directory(cef_string_t* temp_dir) {
+ return g_libcef_pointers.cef_get_temp_directory(temp_dir);
+}
+
+NO_SANITIZE("cfi-icall")
+int cef_create_new_temp_directory(const cef_string_t* prefix,
+ cef_string_t* new_temp_path) {
+ return g_libcef_pointers.cef_create_new_temp_directory(prefix, new_temp_path);
+}
+
+NO_SANITIZE("cfi-icall")
+int cef_create_temp_directory_in_directory(const cef_string_t* base_dir,
+ const cef_string_t* prefix,
+ cef_string_t* new_dir) {
+ return g_libcef_pointers.cef_create_temp_directory_in_directory(
+ base_dir, prefix, new_dir);
+}
+
+NO_SANITIZE("cfi-icall") int cef_directory_exists(const cef_string_t* path) {
+ return g_libcef_pointers.cef_directory_exists(path);
+}
+
+NO_SANITIZE("cfi-icall")
+int cef_delete_file(const cef_string_t* path, int recursive) {
+ return g_libcef_pointers.cef_delete_file(path, recursive);
+}
+
+NO_SANITIZE("cfi-icall")
+int cef_zip_directory(const cef_string_t* src_dir,
+ const cef_string_t* dest_file,
+ int include_hidden_files) {
+ return g_libcef_pointers.cef_zip_directory(src_dir, dest_file,
+ include_hidden_files);
+}
+
+NO_SANITIZE("cfi-icall") void cef_load_crlsets_file(const cef_string_t* path) {
+ g_libcef_pointers.cef_load_crlsets_file(path);
+}
+
+NO_SANITIZE("cfi-icall") int cef_is_rtl() {
+ return g_libcef_pointers.cef_is_rtl();
+}
+
+NO_SANITIZE("cfi-icall")
+int cef_add_cross_origin_whitelist_entry(const cef_string_t* source_origin,
+ const cef_string_t* target_protocol,
+ const cef_string_t* target_domain,
+ int allow_target_subdomains) {
+ return g_libcef_pointers.cef_add_cross_origin_whitelist_entry(
+ source_origin, target_protocol, target_domain, allow_target_subdomains);
+}
+
+NO_SANITIZE("cfi-icall")
+int cef_remove_cross_origin_whitelist_entry(const cef_string_t* source_origin,
+ const cef_string_t* target_protocol,
+ const cef_string_t* target_domain,
+ int allow_target_subdomains) {
+ return g_libcef_pointers.cef_remove_cross_origin_whitelist_entry(
+ source_origin, target_protocol, target_domain, allow_target_subdomains);
+}
+
+NO_SANITIZE("cfi-icall") int cef_clear_cross_origin_whitelist() {
+ return g_libcef_pointers.cef_clear_cross_origin_whitelist();
+}
+
+NO_SANITIZE("cfi-icall")
+int cef_resolve_url(const cef_string_t* base_url,
+ const cef_string_t* relative_url,
+ cef_string_t* resolved_url) {
+ return g_libcef_pointers.cef_resolve_url(base_url, relative_url,
+ resolved_url);
+}
+
+NO_SANITIZE("cfi-icall")
+int cef_parse_url(const cef_string_t* url, struct _cef_urlparts_t* parts) {
+ return g_libcef_pointers.cef_parse_url(url, parts);
+}
+
+NO_SANITIZE("cfi-icall")
+int cef_create_url(const struct _cef_urlparts_t* parts, cef_string_t* url) {
+ return g_libcef_pointers.cef_create_url(parts, url);
+}
+
+NO_SANITIZE("cfi-icall")
+cef_string_userfree_t cef_format_url_for_security_display(
+ const cef_string_t* origin_url) {
+ return g_libcef_pointers.cef_format_url_for_security_display(origin_url);
+}
+
+NO_SANITIZE("cfi-icall")
+cef_string_userfree_t cef_get_mime_type(const cef_string_t* extension) {
+ return g_libcef_pointers.cef_get_mime_type(extension);
+}
+
+NO_SANITIZE("cfi-icall")
+void cef_get_extensions_for_mime_type(const cef_string_t* mime_type,
+ cef_string_list_t extensions) {
+ g_libcef_pointers.cef_get_extensions_for_mime_type(mime_type, extensions);
+}
+
+NO_SANITIZE("cfi-icall")
+cef_string_userfree_t cef_base64encode(const void* data, size_t data_size) {
+ return g_libcef_pointers.cef_base64encode(data, data_size);
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_binary_value_t* cef_base64decode(const cef_string_t* data) {
+ return g_libcef_pointers.cef_base64decode(data);
+}
+
+NO_SANITIZE("cfi-icall")
+cef_string_userfree_t cef_uriencode(const cef_string_t* text, int use_plus) {
+ return g_libcef_pointers.cef_uriencode(text, use_plus);
+}
+
+NO_SANITIZE("cfi-icall")
+cef_string_userfree_t cef_uridecode(const cef_string_t* text,
+ int convert_to_utf8,
+ cef_uri_unescape_rule_t unescape_rule) {
+ return g_libcef_pointers.cef_uridecode(text, convert_to_utf8, unescape_rule);
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_value_t* cef_parse_json(const cef_string_t* json_string,
+ cef_json_parser_options_t options) {
+ return g_libcef_pointers.cef_parse_json(json_string, options);
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_value_t* cef_parse_json_buffer(const void* json,
+ size_t json_size,
+ cef_json_parser_options_t options) {
+ return g_libcef_pointers.cef_parse_json_buffer(json, json_size, options);
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_value_t* cef_parse_jsonand_return_error(
+ const cef_string_t* json_string,
+ cef_json_parser_options_t options,
+ cef_string_t* error_msg_out) {
+ return g_libcef_pointers.cef_parse_jsonand_return_error(json_string, options,
+ error_msg_out);
+}
+
+NO_SANITIZE("cfi-icall")
+cef_string_userfree_t cef_write_json(struct _cef_value_t* node,
+ cef_json_writer_options_t options) {
+ return g_libcef_pointers.cef_write_json(node, options);
+}
+
+NO_SANITIZE("cfi-icall")
+int cef_get_path(cef_path_key_t key, cef_string_t* path) {
+ return g_libcef_pointers.cef_get_path(key, path);
+}
+
+NO_SANITIZE("cfi-icall")
+int cef_launch_process(struct _cef_command_line_t* command_line) {
+ return g_libcef_pointers.cef_launch_process(command_line);
+}
+
+NO_SANITIZE("cfi-icall")
+int cef_register_scheme_handler_factory(
+ const cef_string_t* scheme_name,
+ const cef_string_t* domain_name,
+ struct _cef_scheme_handler_factory_t* factory) {
+ return g_libcef_pointers.cef_register_scheme_handler_factory(
+ scheme_name, domain_name, factory);
+}
+
+NO_SANITIZE("cfi-icall") int cef_clear_scheme_handler_factories() {
+ return g_libcef_pointers.cef_clear_scheme_handler_factories();
+}
+
+NO_SANITIZE("cfi-icall")
+int cef_is_cert_status_error(cef_cert_status_t status) {
+ return g_libcef_pointers.cef_is_cert_status_error(status);
+}
+
+NO_SANITIZE("cfi-icall") int cef_currently_on(cef_thread_id_t threadId) {
+ return g_libcef_pointers.cef_currently_on(threadId);
+}
+
+NO_SANITIZE("cfi-icall")
+int cef_post_task(cef_thread_id_t threadId, struct _cef_task_t* task) {
+ return g_libcef_pointers.cef_post_task(threadId, task);
+}
+
+NO_SANITIZE("cfi-icall")
+int cef_post_delayed_task(cef_thread_id_t threadId,
+ struct _cef_task_t* task,
+ int64 delay_ms) {
+ return g_libcef_pointers.cef_post_delayed_task(threadId, task, delay_ms);
+}
+
+NO_SANITIZE("cfi-icall")
+int cef_begin_tracing(const cef_string_t* categories,
+ struct _cef_completion_callback_t* callback) {
+ return g_libcef_pointers.cef_begin_tracing(categories, callback);
+}
+
+NO_SANITIZE("cfi-icall")
+int cef_end_tracing(const cef_string_t* tracing_file,
+ struct _cef_end_tracing_callback_t* callback) {
+ return g_libcef_pointers.cef_end_tracing(tracing_file, callback);
+}
+
+NO_SANITIZE("cfi-icall") int64 cef_now_from_system_trace_time() {
+ return g_libcef_pointers.cef_now_from_system_trace_time();
+}
+
+NO_SANITIZE("cfi-icall")
+int cef_register_extension(const cef_string_t* extension_name,
+ const cef_string_t* javascript_code,
+ struct _cef_v8handler_t* handler) {
+ return g_libcef_pointers.cef_register_extension(extension_name,
+ javascript_code, handler);
+}
+
+NO_SANITIZE("cfi-icall")
+void cef_execute_java_script_with_user_gesture_for_tests(
+ struct _cef_frame_t* frame,
+ const cef_string_t* javascript) {
+ g_libcef_pointers.cef_execute_java_script_with_user_gesture_for_tests(
+ frame, javascript);
+}
+
+NO_SANITIZE("cfi-icall")
+void cef_set_data_directory_for_tests(const cef_string_t* dir) {
+ g_libcef_pointers.cef_set_data_directory_for_tests(dir);
+}
+
+NO_SANITIZE("cfi-icall")
+int cef_browser_host_create_browser(
+ const struct _cef_window_info_t* windowInfo,
+ struct _cef_client_t* client,
+ const cef_string_t* url,
+ const struct _cef_browser_settings_t* settings,
+ struct _cef_dictionary_value_t* extra_info,
+ struct _cef_request_context_t* request_context) {
+ return g_libcef_pointers.cef_browser_host_create_browser(
+ windowInfo, client, url, settings, extra_info, request_context);
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_browser_t* cef_browser_host_create_browser_sync(
+ const struct _cef_window_info_t* windowInfo,
+ struct _cef_client_t* client,
+ const cef_string_t* url,
+ const struct _cef_browser_settings_t* settings,
+ struct _cef_dictionary_value_t* extra_info,
+ struct _cef_request_context_t* request_context) {
+ return g_libcef_pointers.cef_browser_host_create_browser_sync(
+ windowInfo, client, url, settings, extra_info, request_context);
+}
+
+NO_SANITIZE("cfi-icall") struct _cef_command_line_t* cef_command_line_create() {
+ return g_libcef_pointers.cef_command_line_create();
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_command_line_t* cef_command_line_get_global() {
+ return g_libcef_pointers.cef_command_line_get_global();
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_cookie_manager_t* cef_cookie_manager_get_global_manager(
+ struct _cef_completion_callback_t* callback) {
+ return g_libcef_pointers.cef_cookie_manager_get_global_manager(callback);
+}
+
+NO_SANITIZE("cfi-icall") struct _cef_drag_data_t* cef_drag_data_create() {
+ return g_libcef_pointers.cef_drag_data_create();
+}
+
+NO_SANITIZE("cfi-icall") struct _cef_image_t* cef_image_create() {
+ return g_libcef_pointers.cef_image_create();
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_media_router_t* cef_media_router_get_global(
+ struct _cef_completion_callback_t* callback) {
+ return g_libcef_pointers.cef_media_router_get_global(callback);
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_menu_model_t* cef_menu_model_create(
+ struct _cef_menu_model_delegate_t* delegate) {
+ return g_libcef_pointers.cef_menu_model_create(delegate);
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_preference_manager_t* cef_preference_manager_get_global() {
+ return g_libcef_pointers.cef_preference_manager_get_global();
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_print_settings_t* cef_print_settings_create() {
+ return g_libcef_pointers.cef_print_settings_create();
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_process_message_t* cef_process_message_create(
+ const cef_string_t* name) {
+ return g_libcef_pointers.cef_process_message_create(name);
+}
+
+NO_SANITIZE("cfi-icall") struct _cef_request_t* cef_request_create() {
+ return g_libcef_pointers.cef_request_create();
+}
+
+NO_SANITIZE("cfi-icall") struct _cef_post_data_t* cef_post_data_create() {
+ return g_libcef_pointers.cef_post_data_create();
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_post_data_element_t* cef_post_data_element_create() {
+ return g_libcef_pointers.cef_post_data_element_create();
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_request_context_t* cef_request_context_get_global_context() {
+ return g_libcef_pointers.cef_request_context_get_global_context();
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_request_context_t* cef_request_context_create_context(
+ const struct _cef_request_context_settings_t* settings,
+ struct _cef_request_context_handler_t* handler) {
+ return g_libcef_pointers.cef_request_context_create_context(settings,
+ handler);
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_request_context_t* cef_create_context_shared(
+ struct _cef_request_context_t* other,
+ struct _cef_request_context_handler_t* handler) {
+ return g_libcef_pointers.cef_create_context_shared(other, handler);
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_resource_bundle_t* cef_resource_bundle_get_global() {
+ return g_libcef_pointers.cef_resource_bundle_get_global();
+}
+
+NO_SANITIZE("cfi-icall") struct _cef_response_t* cef_response_create() {
+ return g_libcef_pointers.cef_response_create();
+}
+
+NO_SANITIZE("cfi-icall")
+void cef_server_create(const cef_string_t* address,
+ uint16 port,
+ int backlog,
+ struct _cef_server_handler_t* handler) {
+ g_libcef_pointers.cef_server_create(address, port, backlog, handler);
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_shared_process_message_builder_t*
+cef_shared_process_message_builder_create(const cef_string_t* name,
+ size_t byte_size) {
+ return g_libcef_pointers.cef_shared_process_message_builder_create(name,
+ byte_size);
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_stream_reader_t* cef_stream_reader_create_for_file(
+ const cef_string_t* fileName) {
+ return g_libcef_pointers.cef_stream_reader_create_for_file(fileName);
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_stream_reader_t* cef_stream_reader_create_for_data(void* data,
+ size_t size) {
+ return g_libcef_pointers.cef_stream_reader_create_for_data(data, size);
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_stream_reader_t* cef_stream_reader_create_for_handler(
+ struct _cef_read_handler_t* handler) {
+ return g_libcef_pointers.cef_stream_reader_create_for_handler(handler);
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_stream_writer_t* cef_stream_writer_create_for_file(
+ const cef_string_t* fileName) {
+ return g_libcef_pointers.cef_stream_writer_create_for_file(fileName);
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_stream_writer_t* cef_stream_writer_create_for_handler(
+ struct _cef_write_handler_t* handler) {
+ return g_libcef_pointers.cef_stream_writer_create_for_handler(handler);
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_task_runner_t* cef_task_runner_get_for_current_thread() {
+ return g_libcef_pointers.cef_task_runner_get_for_current_thread();
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_task_runner_t* cef_task_runner_get_for_thread(
+ cef_thread_id_t threadId) {
+ return g_libcef_pointers.cef_task_runner_get_for_thread(threadId);
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_thread_t* cef_thread_create(
+ const cef_string_t* display_name,
+ cef_thread_priority_t priority,
+ cef_message_loop_type_t message_loop_type,
+ int stoppable,
+ cef_com_init_mode_t com_init_mode) {
+ return g_libcef_pointers.cef_thread_create(
+ display_name, priority, message_loop_type, stoppable, com_init_mode);
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_urlrequest_t* cef_urlrequest_create(
+ struct _cef_request_t* request,
+ struct _cef_urlrequest_client_t* client,
+ struct _cef_request_context_t* request_context) {
+ return g_libcef_pointers.cef_urlrequest_create(request, client,
+ request_context);
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_v8context_t* cef_v8context_get_current_context() {
+ return g_libcef_pointers.cef_v8context_get_current_context();
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_v8context_t* cef_v8context_get_entered_context() {
+ return g_libcef_pointers.cef_v8context_get_entered_context();
+}
+
+NO_SANITIZE("cfi-icall") int cef_v8context_in_context() {
+ return g_libcef_pointers.cef_v8context_in_context();
+}
+
+NO_SANITIZE("cfi-icall") struct _cef_v8value_t* cef_v8value_create_undefined() {
+ return g_libcef_pointers.cef_v8value_create_undefined();
+}
+
+NO_SANITIZE("cfi-icall") struct _cef_v8value_t* cef_v8value_create_null() {
+ return g_libcef_pointers.cef_v8value_create_null();
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_v8value_t* cef_v8value_create_bool(int value) {
+ return g_libcef_pointers.cef_v8value_create_bool(value);
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_v8value_t* cef_v8value_create_int(int32 value) {
+ return g_libcef_pointers.cef_v8value_create_int(value);
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_v8value_t* cef_v8value_create_uint(uint32 value) {
+ return g_libcef_pointers.cef_v8value_create_uint(value);
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_v8value_t* cef_v8value_create_double(double value) {
+ return g_libcef_pointers.cef_v8value_create_double(value);
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_v8value_t* cef_v8value_create_date(cef_basetime_t date) {
+ return g_libcef_pointers.cef_v8value_create_date(date);
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_v8value_t* cef_v8value_create_string(const cef_string_t* value) {
+ return g_libcef_pointers.cef_v8value_create_string(value);
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_v8value_t* cef_v8value_create_object(
+ struct _cef_v8accessor_t* accessor,
+ struct _cef_v8interceptor_t* interceptor) {
+ return g_libcef_pointers.cef_v8value_create_object(accessor, interceptor);
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_v8value_t* cef_v8value_create_array(int length) {
+ return g_libcef_pointers.cef_v8value_create_array(length);
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_v8value_t* cef_v8value_create_array_buffer(
+ void* buffer,
+ size_t length,
+ struct _cef_v8array_buffer_release_callback_t* release_callback) {
+ return g_libcef_pointers.cef_v8value_create_array_buffer(buffer, length,
+ release_callback);
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_v8value_t* cef_v8value_create_function(
+ const cef_string_t* name,
+ struct _cef_v8handler_t* handler) {
+ return g_libcef_pointers.cef_v8value_create_function(name, handler);
+}
+
+NO_SANITIZE("cfi-icall") struct _cef_v8value_t* cef_v8value_create_promise() {
+ return g_libcef_pointers.cef_v8value_create_promise();
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_v8stack_trace_t* cef_v8stack_trace_get_current(int frame_limit) {
+ return g_libcef_pointers.cef_v8stack_trace_get_current(frame_limit);
+}
+
+NO_SANITIZE("cfi-icall") struct _cef_value_t* cef_value_create() {
+ return g_libcef_pointers.cef_value_create();
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_binary_value_t* cef_binary_value_create(const void* data,
+ size_t data_size) {
+ return g_libcef_pointers.cef_binary_value_create(data, data_size);
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_dictionary_value_t* cef_dictionary_value_create() {
+ return g_libcef_pointers.cef_dictionary_value_create();
+}
+
+NO_SANITIZE("cfi-icall") struct _cef_list_value_t* cef_list_value_create() {
+ return g_libcef_pointers.cef_list_value_create();
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_waitable_event_t* cef_waitable_event_create(
+ int automatic_reset,
+ int initially_signaled) {
+ return g_libcef_pointers.cef_waitable_event_create(automatic_reset,
+ initially_signaled);
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_xml_reader_t* cef_xml_reader_create(
+ struct _cef_stream_reader_t* stream,
+ cef_xml_encoding_type_t encodingType,
+ const cef_string_t* URI) {
+ return g_libcef_pointers.cef_xml_reader_create(stream, encodingType, URI);
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_zip_reader_t* cef_zip_reader_create(
+ struct _cef_stream_reader_t* stream) {
+ return g_libcef_pointers.cef_zip_reader_create(stream);
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_test_server_t* cef_test_server_create_and_start(
+ uint16 port,
+ int https_server,
+ cef_test_cert_type_t https_cert_type,
+ struct _cef_test_server_handler_t* handler) {
+ return g_libcef_pointers.cef_test_server_create_and_start(
+ port, https_server, https_cert_type, handler);
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_translator_test_t* cef_translator_test_create() {
+ return g_libcef_pointers.cef_translator_test_create();
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_translator_test_ref_ptr_library_t*
+cef_translator_test_ref_ptr_library_create(int value) {
+ return g_libcef_pointers.cef_translator_test_ref_ptr_library_create(value);
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_translator_test_ref_ptr_library_child_t*
+cef_translator_test_ref_ptr_library_child_create(int value, int other_value) {
+ return g_libcef_pointers.cef_translator_test_ref_ptr_library_child_create(
+ value, other_value);
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_translator_test_ref_ptr_library_child_child_t*
+cef_translator_test_ref_ptr_library_child_child_create(int value,
+ int other_value,
+ int other_other_value) {
+ return g_libcef_pointers
+ .cef_translator_test_ref_ptr_library_child_child_create(
+ value, other_value, other_other_value);
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_translator_test_scoped_library_t*
+cef_translator_test_scoped_library_create(int value) {
+ return g_libcef_pointers.cef_translator_test_scoped_library_create(value);
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_translator_test_scoped_library_child_t*
+cef_translator_test_scoped_library_child_create(int value, int other_value) {
+ return g_libcef_pointers.cef_translator_test_scoped_library_child_create(
+ value, other_value);
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_translator_test_scoped_library_child_child_t*
+cef_translator_test_scoped_library_child_child_create(int value,
+ int other_value,
+ int other_other_value) {
+ return g_libcef_pointers
+ .cef_translator_test_scoped_library_child_child_create(value, other_value,
+ other_other_value);
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_browser_view_t* cef_browser_view_create(
+ struct _cef_client_t* client,
+ const cef_string_t* url,
+ const struct _cef_browser_settings_t* settings,
+ struct _cef_dictionary_value_t* extra_info,
+ struct _cef_request_context_t* request_context,
+ struct _cef_browser_view_delegate_t* delegate) {
+ return g_libcef_pointers.cef_browser_view_create(
+ client, url, settings, extra_info, request_context, delegate);
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_browser_view_t* cef_browser_view_get_for_browser(
+ struct _cef_browser_t* browser) {
+ return g_libcef_pointers.cef_browser_view_get_for_browser(browser);
+}
+
+NO_SANITIZE("cfi-icall") struct _cef_display_t* cef_display_get_primary() {
+ return g_libcef_pointers.cef_display_get_primary();
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_display_t* cef_display_get_nearest_point(const cef_point_t* point,
+ int input_pixel_coords) {
+ return g_libcef_pointers.cef_display_get_nearest_point(point,
+ input_pixel_coords);
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_display_t* cef_display_get_matching_bounds(const cef_rect_t* bounds,
+ int input_pixel_coords) {
+ return g_libcef_pointers.cef_display_get_matching_bounds(bounds,
+ input_pixel_coords);
+}
+
+NO_SANITIZE("cfi-icall") size_t cef_display_get_count() {
+ return g_libcef_pointers.cef_display_get_count();
+}
+
+NO_SANITIZE("cfi-icall")
+void cef_display_get_alls(size_t* displaysCount,
+ struct _cef_display_t** displays) {
+ g_libcef_pointers.cef_display_get_alls(displaysCount, displays);
+}
+
+NO_SANITIZE("cfi-icall")
+cef_point_t cef_display_convert_screen_point_to_pixels(
+ const cef_point_t* point) {
+ return g_libcef_pointers.cef_display_convert_screen_point_to_pixels(point);
+}
+
+NO_SANITIZE("cfi-icall")
+cef_point_t cef_display_convert_screen_point_from_pixels(
+ const cef_point_t* point) {
+ return g_libcef_pointers.cef_display_convert_screen_point_from_pixels(point);
+}
+
+NO_SANITIZE("cfi-icall")
+cef_rect_t cef_display_convert_screen_rect_to_pixels(const cef_rect_t* rect) {
+ return g_libcef_pointers.cef_display_convert_screen_rect_to_pixels(rect);
+}
+
+NO_SANITIZE("cfi-icall")
+cef_rect_t cef_display_convert_screen_rect_from_pixels(const cef_rect_t* rect) {
+ return g_libcef_pointers.cef_display_convert_screen_rect_from_pixels(rect);
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_label_button_t* cef_label_button_create(
+ struct _cef_button_delegate_t* delegate,
+ const cef_string_t* text) {
+ return g_libcef_pointers.cef_label_button_create(delegate, text);
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_menu_button_t* cef_menu_button_create(
+ struct _cef_menu_button_delegate_t* delegate,
+ const cef_string_t* text) {
+ return g_libcef_pointers.cef_menu_button_create(delegate, text);
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_panel_t* cef_panel_create(struct _cef_panel_delegate_t* delegate) {
+ return g_libcef_pointers.cef_panel_create(delegate);
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_scroll_view_t* cef_scroll_view_create(
+ struct _cef_view_delegate_t* delegate) {
+ return g_libcef_pointers.cef_scroll_view_create(delegate);
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_textfield_t* cef_textfield_create(
+ struct _cef_textfield_delegate_t* delegate) {
+ return g_libcef_pointers.cef_textfield_create(delegate);
+}
+
+NO_SANITIZE("cfi-icall")
+struct _cef_window_t* cef_window_create_top_level(
+ struct _cef_window_delegate_t* delegate) {
+ return g_libcef_pointers.cef_window_create_top_level(delegate);
+}
+
+NO_SANITIZE("cfi-icall") const char* cef_api_hash(int entry) {
+ return g_libcef_pointers.cef_api_hash(entry);
+}
+
+NO_SANITIZE("cfi-icall") int cef_version_info(int entry) {
+ return g_libcef_pointers.cef_version_info(entry);
+}
+
+NO_SANITIZE("cfi-icall") int cef_get_min_log_level() {
+ return g_libcef_pointers.cef_get_min_log_level();
+}
+
+NO_SANITIZE("cfi-icall")
+int cef_get_vlog_level(const char* file_start, size_t N) {
+ return g_libcef_pointers.cef_get_vlog_level(file_start, N);
+}
+
+NO_SANITIZE("cfi-icall")
+void cef_log(const char* file, int line, int severity, const char* message) {
+ g_libcef_pointers.cef_log(file, line, severity, message);
+}
+
+NO_SANITIZE("cfi-icall") cef_string_list_t cef_string_list_alloc() {
+ return g_libcef_pointers.cef_string_list_alloc();
+}
+
+NO_SANITIZE("cfi-icall") size_t cef_string_list_size(cef_string_list_t list) {
+ return g_libcef_pointers.cef_string_list_size(list);
+}
+
+NO_SANITIZE("cfi-icall")
+int cef_string_list_value(cef_string_list_t list,
+ size_t index,
+ cef_string_t* value) {
+ return g_libcef_pointers.cef_string_list_value(list, index, value);
+}
+
+NO_SANITIZE("cfi-icall")
+void cef_string_list_append(cef_string_list_t list, const cef_string_t* value) {
+ g_libcef_pointers.cef_string_list_append(list, value);
+}
+
+NO_SANITIZE("cfi-icall") void cef_string_list_clear(cef_string_list_t list) {
+ g_libcef_pointers.cef_string_list_clear(list);
+}
+
+NO_SANITIZE("cfi-icall") void cef_string_list_free(cef_string_list_t list) {
+ g_libcef_pointers.cef_string_list_free(list);
+}
+
+NO_SANITIZE("cfi-icall")
+cef_string_list_t cef_string_list_copy(cef_string_list_t list) {
+ return g_libcef_pointers.cef_string_list_copy(list);
+}
+
+NO_SANITIZE("cfi-icall") cef_string_map_t cef_string_map_alloc() {
+ return g_libcef_pointers.cef_string_map_alloc();
+}
+
+NO_SANITIZE("cfi-icall") size_t cef_string_map_size(cef_string_map_t map) {
+ return g_libcef_pointers.cef_string_map_size(map);
+}
+
+NO_SANITIZE("cfi-icall")
+int cef_string_map_find(cef_string_map_t map,
+ const cef_string_t* key,
+ cef_string_t* value) {
+ return g_libcef_pointers.cef_string_map_find(map, key, value);
+}
+
+NO_SANITIZE("cfi-icall")
+int cef_string_map_key(cef_string_map_t map, size_t index, cef_string_t* key) {
+ return g_libcef_pointers.cef_string_map_key(map, index, key);
+}
+
+NO_SANITIZE("cfi-icall")
+int cef_string_map_value(cef_string_map_t map,
+ size_t index,
+ cef_string_t* value) {
+ return g_libcef_pointers.cef_string_map_value(map, index, value);
+}
+
+NO_SANITIZE("cfi-icall")
+int cef_string_map_append(cef_string_map_t map,
+ const cef_string_t* key,
+ const cef_string_t* value) {
+ return g_libcef_pointers.cef_string_map_append(map, key, value);
+}
+
+NO_SANITIZE("cfi-icall") void cef_string_map_clear(cef_string_map_t map) {
+ g_libcef_pointers.cef_string_map_clear(map);
+}
+
+NO_SANITIZE("cfi-icall") void cef_string_map_free(cef_string_map_t map) {
+ g_libcef_pointers.cef_string_map_free(map);
+}
+
+NO_SANITIZE("cfi-icall") cef_string_multimap_t cef_string_multimap_alloc() {
+ return g_libcef_pointers.cef_string_multimap_alloc();
+}
+
+NO_SANITIZE("cfi-icall")
+size_t cef_string_multimap_size(cef_string_multimap_t map) {
+ return g_libcef_pointers.cef_string_multimap_size(map);
+}
+
+NO_SANITIZE("cfi-icall")
+size_t cef_string_multimap_find_count(cef_string_multimap_t map,
+ const cef_string_t* key) {
+ return g_libcef_pointers.cef_string_multimap_find_count(map, key);
+}
+
+NO_SANITIZE("cfi-icall")
+int cef_string_multimap_enumerate(cef_string_multimap_t map,
+ const cef_string_t* key,
+ size_t value_index,
+ cef_string_t* value) {
+ return g_libcef_pointers.cef_string_multimap_enumerate(map, key, value_index,
+ value);
+}
+
+NO_SANITIZE("cfi-icall")
+int cef_string_multimap_key(cef_string_multimap_t map,
+ size_t index,
+ cef_string_t* key) {
+ return g_libcef_pointers.cef_string_multimap_key(map, index, key);
+}
+
+NO_SANITIZE("cfi-icall")
+int cef_string_multimap_value(cef_string_multimap_t map,
+ size_t index,
+ cef_string_t* value) {
+ return g_libcef_pointers.cef_string_multimap_value(map, index, value);
+}
+
+NO_SANITIZE("cfi-icall")
+int cef_string_multimap_append(cef_string_multimap_t map,
+ const cef_string_t* key,
+ const cef_string_t* value) {
+ return g_libcef_pointers.cef_string_multimap_append(map, key, value);
+}
+
+NO_SANITIZE("cfi-icall")
+void cef_string_multimap_clear(cef_string_multimap_t map) {
+ g_libcef_pointers.cef_string_multimap_clear(map);
+}
+
+NO_SANITIZE("cfi-icall")
+void cef_string_multimap_free(cef_string_multimap_t map) {
+ g_libcef_pointers.cef_string_multimap_free(map);
+}
+
+NO_SANITIZE("cfi-icall")
+int cef_string_wide_set(const wchar_t* src,
+ size_t src_len,
+ cef_string_wide_t* output,
+ int copy) {
+ return g_libcef_pointers.cef_string_wide_set(src, src_len, output, copy);
+}
+
+NO_SANITIZE("cfi-icall")
+int cef_string_utf8_set(const char* src,
+ size_t src_len,
+ cef_string_utf8_t* output,
+ int copy) {
+ return g_libcef_pointers.cef_string_utf8_set(src, src_len, output, copy);
+}
+
+NO_SANITIZE("cfi-icall")
+int cef_string_utf16_set(const char16* src,
+ size_t src_len,
+ cef_string_utf16_t* output,
+ int copy) {
+ return g_libcef_pointers.cef_string_utf16_set(src, src_len, output, copy);
+}
+
+NO_SANITIZE("cfi-icall") void cef_string_wide_clear(cef_string_wide_t* str) {
+ g_libcef_pointers.cef_string_wide_clear(str);
+}
+
+NO_SANITIZE("cfi-icall") void cef_string_utf8_clear(cef_string_utf8_t* str) {
+ g_libcef_pointers.cef_string_utf8_clear(str);
+}
+
+NO_SANITIZE("cfi-icall") void cef_string_utf16_clear(cef_string_utf16_t* str) {
+ g_libcef_pointers.cef_string_utf16_clear(str);
+}
+
+NO_SANITIZE("cfi-icall")
+int cef_string_wide_cmp(const cef_string_wide_t* str1,
+ const cef_string_wide_t* str2) {
+ return g_libcef_pointers.cef_string_wide_cmp(str1, str2);
+}
+
+NO_SANITIZE("cfi-icall")
+int cef_string_utf8_cmp(const cef_string_utf8_t* str1,
+ const cef_string_utf8_t* str2) {
+ return g_libcef_pointers.cef_string_utf8_cmp(str1, str2);
+}
+
+NO_SANITIZE("cfi-icall")
+int cef_string_utf16_cmp(const cef_string_utf16_t* str1,
+ const cef_string_utf16_t* str2) {
+ return g_libcef_pointers.cef_string_utf16_cmp(str1, str2);
+}
+
+NO_SANITIZE("cfi-icall")
+int cef_string_wide_to_utf8(const wchar_t* src,
+ size_t src_len,
+ cef_string_utf8_t* output) {
+ return g_libcef_pointers.cef_string_wide_to_utf8(src, src_len, output);
+}
+
+NO_SANITIZE("cfi-icall")
+int cef_string_utf8_to_wide(const char* src,
+ size_t src_len,
+ cef_string_wide_t* output) {
+ return g_libcef_pointers.cef_string_utf8_to_wide(src, src_len, output);
+}
+
+NO_SANITIZE("cfi-icall")
+int cef_string_wide_to_utf16(const wchar_t* src,
+ size_t src_len,
+ cef_string_utf16_t* output) {
+ return g_libcef_pointers.cef_string_wide_to_utf16(src, src_len, output);
+}
+
+NO_SANITIZE("cfi-icall")
+int cef_string_utf16_to_wide(const char16* src,
+ size_t src_len,
+ cef_string_wide_t* output) {
+ return g_libcef_pointers.cef_string_utf16_to_wide(src, src_len, output);
+}
+
+NO_SANITIZE("cfi-icall")
+int cef_string_utf8_to_utf16(const char* src,
+ size_t src_len,
+ cef_string_utf16_t* output) {
+ return g_libcef_pointers.cef_string_utf8_to_utf16(src, src_len, output);
+}
+
+NO_SANITIZE("cfi-icall")
+int cef_string_utf16_to_utf8(const char16* src,
+ size_t src_len,
+ cef_string_utf8_t* output) {
+ return g_libcef_pointers.cef_string_utf16_to_utf8(src, src_len, output);
+}
+
+NO_SANITIZE("cfi-icall")
+int cef_string_ascii_to_wide(const char* src,
+ size_t src_len,
+ cef_string_wide_t* output) {
+ return g_libcef_pointers.cef_string_ascii_to_wide(src, src_len, output);
+}
+
+NO_SANITIZE("cfi-icall")
+int cef_string_ascii_to_utf16(const char* src,
+ size_t src_len,
+ cef_string_utf16_t* output) {
+ return g_libcef_pointers.cef_string_ascii_to_utf16(src, src_len, output);
+}
+
+NO_SANITIZE("cfi-icall")
+cef_string_userfree_wide_t cef_string_userfree_wide_alloc() {
+ return g_libcef_pointers.cef_string_userfree_wide_alloc();
+}
+
+NO_SANITIZE("cfi-icall")
+cef_string_userfree_utf8_t cef_string_userfree_utf8_alloc() {
+ return g_libcef_pointers.cef_string_userfree_utf8_alloc();
+}
+
+NO_SANITIZE("cfi-icall")
+cef_string_userfree_utf16_t cef_string_userfree_utf16_alloc() {
+ return g_libcef_pointers.cef_string_userfree_utf16_alloc();
+}
+
+NO_SANITIZE("cfi-icall")
+void cef_string_userfree_wide_free(cef_string_userfree_wide_t str) {
+ g_libcef_pointers.cef_string_userfree_wide_free(str);
+}
+
+NO_SANITIZE("cfi-icall")
+void cef_string_userfree_utf8_free(cef_string_userfree_utf8_t str) {
+ g_libcef_pointers.cef_string_userfree_utf8_free(str);
+}
+
+NO_SANITIZE("cfi-icall")
+void cef_string_userfree_utf16_free(cef_string_userfree_utf16_t str) {
+ g_libcef_pointers.cef_string_userfree_utf16_free(str);
+}
+
+NO_SANITIZE("cfi-icall")
+int cef_string_utf16_to_lower(const char16* src,
+ size_t src_len,
+ cef_string_utf16_t* output) {
+ return g_libcef_pointers.cef_string_utf16_to_lower(src, src_len, output);
+}
+
+NO_SANITIZE("cfi-icall")
+int cef_string_utf16_to_upper(const char16* src,
+ size_t src_len,
+ cef_string_utf16_t* output) {
+ return g_libcef_pointers.cef_string_utf16_to_upper(src, src_len, output);
+}
+
+NO_SANITIZE("cfi-icall")
+cef_platform_thread_id_t cef_get_current_platform_thread_id() {
+ return g_libcef_pointers.cef_get_current_platform_thread_id();
+}
+
+NO_SANITIZE("cfi-icall")
+cef_platform_thread_handle_t cef_get_current_platform_thread_handle() {
+ return g_libcef_pointers.cef_get_current_platform_thread_handle();
+}
+
+NO_SANITIZE("cfi-icall")
+int cef_time_to_timet(const cef_time_t* cef_time, time_t* time) {
+ return g_libcef_pointers.cef_time_to_timet(cef_time, time);
+}
+
+NO_SANITIZE("cfi-icall")
+int cef_time_from_timet(time_t time, cef_time_t* cef_time) {
+ return g_libcef_pointers.cef_time_from_timet(time, cef_time);
+}
+
+NO_SANITIZE("cfi-icall")
+int cef_time_to_doublet(const cef_time_t* cef_time, double* time) {
+ return g_libcef_pointers.cef_time_to_doublet(cef_time, time);
+}
+
+NO_SANITIZE("cfi-icall")
+int cef_time_from_doublet(double time, cef_time_t* cef_time) {
+ return g_libcef_pointers.cef_time_from_doublet(time, cef_time);
+}
+
+NO_SANITIZE("cfi-icall") int cef_time_now(cef_time_t* cef_time) {
+ return g_libcef_pointers.cef_time_now(cef_time);
+}
+
+NO_SANITIZE("cfi-icall") cef_basetime_t cef_basetime_now() {
+ return g_libcef_pointers.cef_basetime_now();
+}
+
+NO_SANITIZE("cfi-icall")
+int cef_time_delta(const cef_time_t* cef_time1,
+ const cef_time_t* cef_time2,
+ long long* delta) {
+ return g_libcef_pointers.cef_time_delta(cef_time1, cef_time2, delta);
+}
+
+NO_SANITIZE("cfi-icall")
+int cef_time_to_basetime(const cef_time_t* from, cef_basetime_t* to) {
+ return g_libcef_pointers.cef_time_to_basetime(from, to);
+}
+
+NO_SANITIZE("cfi-icall")
+int cef_time_from_basetime(const cef_basetime_t from, cef_time_t* to) {
+ return g_libcef_pointers.cef_time_from_basetime(from, to);
+}
+
+NO_SANITIZE("cfi-icall")
+void cef_trace_event_instant(const char* category,
+ const char* name,
+ const char* arg1_name,
+ uint64 arg1_val,
+ const char* arg2_name,
+ uint64 arg2_val,
+ int copy) {
+ g_libcef_pointers.cef_trace_event_instant(category, name, arg1_name, arg1_val,
+ arg2_name, arg2_val, copy);
+}
+
+NO_SANITIZE("cfi-icall")
+void cef_trace_event_begin(const char* category,
+ const char* name,
+ const char* arg1_name,
+ uint64 arg1_val,
+ const char* arg2_name,
+ uint64 arg2_val,
+ int copy) {
+ g_libcef_pointers.cef_trace_event_begin(category, name, arg1_name, arg1_val,
+ arg2_name, arg2_val, copy);
+}
+
+NO_SANITIZE("cfi-icall")
+void cef_trace_event_end(const char* category,
+ const char* name,
+ const char* arg1_name,
+ uint64 arg1_val,
+ const char* arg2_name,
+ uint64 arg2_val,
+ int copy) {
+ g_libcef_pointers.cef_trace_event_end(category, name, arg1_name, arg1_val,
+ arg2_name, arg2_val, copy);
+}
+
+NO_SANITIZE("cfi-icall")
+void cef_trace_counter(const char* category,
+ const char* name,
+ const char* value1_name,
+ uint64 value1_val,
+ const char* value2_name,
+ uint64 value2_val,
+ int copy) {
+ g_libcef_pointers.cef_trace_counter(category, name, value1_name, value1_val,
+ value2_name, value2_val, copy);
+}
+
+NO_SANITIZE("cfi-icall")
+void cef_trace_counter_id(const char* category,
+ const char* name,
+ uint64 id,
+ const char* value1_name,
+ uint64 value1_val,
+ const char* value2_name,
+ uint64 value2_val,
+ int copy) {
+ g_libcef_pointers.cef_trace_counter_id(category, name, id, value1_name,
+ value1_val, value2_name, value2_val,
+ copy);
+}
+
+NO_SANITIZE("cfi-icall")
+void cef_trace_event_async_begin(const char* category,
+ const char* name,
+ uint64 id,
+ const char* arg1_name,
+ uint64 arg1_val,
+ const char* arg2_name,
+ uint64 arg2_val,
+ int copy) {
+ g_libcef_pointers.cef_trace_event_async_begin(
+ category, name, id, arg1_name, arg1_val, arg2_name, arg2_val, copy);
+}
+
+NO_SANITIZE("cfi-icall")
+void cef_trace_event_async_step_into(const char* category,
+ const char* name,
+ uint64 id,
+ uint64 step,
+ const char* arg1_name,
+ uint64 arg1_val,
+ int copy) {
+ g_libcef_pointers.cef_trace_event_async_step_into(category, name, id, step,
+ arg1_name, arg1_val, copy);
+}
+
+NO_SANITIZE("cfi-icall")
+void cef_trace_event_async_step_past(const char* category,
+ const char* name,
+ uint64 id,
+ uint64 step,
+ const char* arg1_name,
+ uint64 arg1_val,
+ int copy) {
+ g_libcef_pointers.cef_trace_event_async_step_past(category, name, id, step,
+ arg1_name, arg1_val, copy);
+}
+
+NO_SANITIZE("cfi-icall")
+void cef_trace_event_async_end(const char* category,
+ const char* name,
+ uint64 id,
+ const char* arg1_name,
+ uint64 arg1_val,
+ const char* arg2_name,
+ uint64 arg2_val,
+ int copy) {
+ g_libcef_pointers.cef_trace_event_async_end(
+ category, name, id, arg1_name, arg1_val, arg2_name, arg2_val, copy);
+}
diff --git a/libcef_dll/wrapper/libcef_dll_wrapper.cc b/libcef_dll/wrapper/libcef_dll_wrapper.cc
new file mode 100644
index 00000000..08b642d2
--- /dev/null
+++ b/libcef_dll/wrapper/libcef_dll_wrapper.cc
@@ -0,0 +1,877 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=60bb1af4e6451440a44e3469e69e34fd6f711d62$
+//
+
+#include "include/capi/cef_app_capi.h"
+#include "include/capi/cef_crash_util_capi.h"
+#include "include/capi/cef_file_util_capi.h"
+#include "include/capi/cef_i18n_util_capi.h"
+#include "include/capi/cef_origin_whitelist_capi.h"
+#include "include/capi/cef_parser_capi.h"
+#include "include/capi/cef_path_util_capi.h"
+#include "include/capi/cef_process_util_capi.h"
+#include "include/capi/cef_scheme_capi.h"
+#include "include/capi/cef_ssl_info_capi.h"
+#include "include/capi/cef_task_capi.h"
+#include "include/capi/cef_trace_capi.h"
+#include "include/capi/cef_v8_capi.h"
+#include "include/capi/test/cef_test_helpers_capi.h"
+#include "include/cef_api_hash.h"
+#include "include/cef_app.h"
+#include "include/cef_crash_util.h"
+#include "include/cef_file_util.h"
+#include "include/cef_i18n_util.h"
+#include "include/cef_origin_whitelist.h"
+#include "include/cef_parser.h"
+#include "include/cef_path_util.h"
+#include "include/cef_process_util.h"
+#include "include/cef_scheme.h"
+#include "include/cef_ssl_info.h"
+#include "include/cef_task.h"
+#include "include/cef_trace.h"
+#include "include/cef_v8.h"
+#include "include/test/cef_test_helpers.h"
+#include "libcef_dll/cpptoc/app_cpptoc.h"
+#include "libcef_dll/cpptoc/completion_callback_cpptoc.h"
+#include "libcef_dll/cpptoc/end_tracing_callback_cpptoc.h"
+#include "libcef_dll/cpptoc/scheme_handler_factory_cpptoc.h"
+#include "libcef_dll/cpptoc/task_cpptoc.h"
+#include "libcef_dll/cpptoc/v8handler_cpptoc.h"
+#include "libcef_dll/ctocpp/binary_value_ctocpp.h"
+#include "libcef_dll/ctocpp/command_line_ctocpp.h"
+#include "libcef_dll/ctocpp/frame_ctocpp.h"
+#include "libcef_dll/ctocpp/value_ctocpp.h"
+#include "libcef_dll/shutdown_checker.h"
+#include "libcef_dll/transfer_util.h"
+
+// Define used to facilitate parsing.
+#define CEF_GLOBAL
+
+// GLOBAL METHODS - Body may be edited by hand.
+
+NO_SANITIZE("cfi-icall")
+CEF_GLOBAL int CefExecuteProcess(const CefMainArgs& args,
+ CefRefPtr<CefApp> application,
+ void* windows_sandbox_info) {
+ const char* api_hash = cef_api_hash(0);
+ if (strcmp(api_hash, CEF_API_HASH_PLATFORM)) {
+ // The libcef API hash does not match the current header API hash.
+ NOTREACHED();
+ return 0;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: application, windows_sandbox_info
+
+ // Execute
+ int _retval = cef_execute_process(&args, CefAppCppToC::Wrap(application),
+ windows_sandbox_info);
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CEF_GLOBAL bool CefInitialize(const CefMainArgs& args,
+ const CefSettings& settings,
+ CefRefPtr<CefApp> application,
+ void* windows_sandbox_info) {
+ const char* api_hash = cef_api_hash(0);
+ if (strcmp(api_hash, CEF_API_HASH_PLATFORM)) {
+ // The libcef API hash does not match the current header API hash.
+ NOTREACHED();
+ return false;
+ }
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: application, windows_sandbox_info
+
+ // Execute
+ int _retval = cef_initialize(
+ &args, &settings, CefAppCppToC::Wrap(application), windows_sandbox_info);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") CEF_GLOBAL void CefShutdown() {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+#if DCHECK_IS_ON()
+ shutdown_checker::SetIsShutdown();
+#endif
+
+ // Execute
+ cef_shutdown();
+}
+
+NO_SANITIZE("cfi-icall") CEF_GLOBAL void CefDoMessageLoopWork() {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_do_message_loop_work();
+}
+
+NO_SANITIZE("cfi-icall") CEF_GLOBAL void CefRunMessageLoop() {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_run_message_loop();
+}
+
+NO_SANITIZE("cfi-icall") CEF_GLOBAL void CefQuitMessageLoop() {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ cef_quit_message_loop();
+}
+
+NO_SANITIZE("cfi-icall") CEF_GLOBAL bool CefCrashReportingEnabled() {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = cef_crash_reporting_enabled();
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CEF_GLOBAL
+void CefSetCrashKeyValue(const CefString& key, const CefString& value) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: key; type: string_byref_const
+ DCHECK(!key.empty());
+ if (key.empty()) {
+ return;
+ }
+ // Unverified params: value
+
+ // Execute
+ cef_set_crash_key_value(key.GetStruct(), value.GetStruct());
+}
+
+NO_SANITIZE("cfi-icall")
+CEF_GLOBAL bool CefCreateDirectory(const CefString& full_path) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: full_path; type: string_byref_const
+ DCHECK(!full_path.empty());
+ if (full_path.empty()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = cef_create_directory(full_path.GetStruct());
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CEF_GLOBAL bool CefGetTempDirectory(CefString& temp_dir) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = cef_get_temp_directory(temp_dir.GetWritableStruct());
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CEF_GLOBAL bool CefCreateNewTempDirectory(const CefString& prefix,
+ CefString& new_temp_path) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: prefix
+
+ // Execute
+ int _retval = cef_create_new_temp_directory(
+ prefix.GetStruct(), new_temp_path.GetWritableStruct());
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CEF_GLOBAL bool CefCreateTempDirectoryInDirectory(const CefString& base_dir,
+ const CefString& prefix,
+ CefString& new_dir) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: base_dir; type: string_byref_const
+ DCHECK(!base_dir.empty());
+ if (base_dir.empty()) {
+ return false;
+ }
+ // Unverified params: prefix
+
+ // Execute
+ int _retval = cef_create_temp_directory_in_directory(
+ base_dir.GetStruct(), prefix.GetStruct(), new_dir.GetWritableStruct());
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CEF_GLOBAL bool CefDirectoryExists(const CefString& path) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: path; type: string_byref_const
+ DCHECK(!path.empty());
+ if (path.empty()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = cef_directory_exists(path.GetStruct());
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CEF_GLOBAL bool CefDeleteFile(const CefString& path, bool recursive) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: path; type: string_byref_const
+ DCHECK(!path.empty());
+ if (path.empty()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = cef_delete_file(path.GetStruct(), recursive);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CEF_GLOBAL bool CefZipDirectory(const CefString& src_dir,
+ const CefString& dest_file,
+ bool include_hidden_files) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: src_dir; type: string_byref_const
+ DCHECK(!src_dir.empty());
+ if (src_dir.empty()) {
+ return false;
+ }
+ // Verify param: dest_file; type: string_byref_const
+ DCHECK(!dest_file.empty());
+ if (dest_file.empty()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = cef_zip_directory(src_dir.GetStruct(), dest_file.GetStruct(),
+ include_hidden_files);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CEF_GLOBAL void CefLoadCRLSetsFile(const CefString& path) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: path; type: string_byref_const
+ DCHECK(!path.empty());
+ if (path.empty()) {
+ return;
+ }
+
+ // Execute
+ cef_load_crlsets_file(path.GetStruct());
+}
+
+NO_SANITIZE("cfi-icall") CEF_GLOBAL bool CefIsRTL() {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = cef_is_rtl();
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CEF_GLOBAL
+bool CefAddCrossOriginWhitelistEntry(const CefString& source_origin,
+ const CefString& target_protocol,
+ const CefString& target_domain,
+ bool allow_target_subdomains) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: source_origin; type: string_byref_const
+ DCHECK(!source_origin.empty());
+ if (source_origin.empty()) {
+ return false;
+ }
+ // Verify param: target_protocol; type: string_byref_const
+ DCHECK(!target_protocol.empty());
+ if (target_protocol.empty()) {
+ return false;
+ }
+ // Unverified params: target_domain
+
+ // Execute
+ int _retval = cef_add_cross_origin_whitelist_entry(
+ source_origin.GetStruct(), target_protocol.GetStruct(),
+ target_domain.GetStruct(), allow_target_subdomains);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CEF_GLOBAL
+bool CefRemoveCrossOriginWhitelistEntry(const CefString& source_origin,
+ const CefString& target_protocol,
+ const CefString& target_domain,
+ bool allow_target_subdomains) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: source_origin; type: string_byref_const
+ DCHECK(!source_origin.empty());
+ if (source_origin.empty()) {
+ return false;
+ }
+ // Verify param: target_protocol; type: string_byref_const
+ DCHECK(!target_protocol.empty());
+ if (target_protocol.empty()) {
+ return false;
+ }
+ // Unverified params: target_domain
+
+ // Execute
+ int _retval = cef_remove_cross_origin_whitelist_entry(
+ source_origin.GetStruct(), target_protocol.GetStruct(),
+ target_domain.GetStruct(), allow_target_subdomains);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") CEF_GLOBAL bool CefClearCrossOriginWhitelist() {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = cef_clear_cross_origin_whitelist();
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CEF_GLOBAL bool CefResolveURL(const CefString& base_url,
+ const CefString& relative_url,
+ CefString& resolved_url) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: base_url; type: string_byref_const
+ DCHECK(!base_url.empty());
+ if (base_url.empty()) {
+ return false;
+ }
+ // Verify param: relative_url; type: string_byref_const
+ DCHECK(!relative_url.empty());
+ if (relative_url.empty()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = cef_resolve_url(base_url.GetStruct(), relative_url.GetStruct(),
+ resolved_url.GetWritableStruct());
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CEF_GLOBAL bool CefParseURL(const CefString& url, CefURLParts& parts) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: url; type: string_byref_const
+ DCHECK(!url.empty());
+ if (url.empty()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = cef_parse_url(url.GetStruct(), &parts);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CEF_GLOBAL bool CefCreateURL(const CefURLParts& parts, CefString& url) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = cef_create_url(&parts, url.GetWritableStruct());
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CEF_GLOBAL CefString
+CefFormatUrlForSecurityDisplay(const CefString& origin_url) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: origin_url; type: string_byref_const
+ DCHECK(!origin_url.empty());
+ if (origin_url.empty()) {
+ return CefString();
+ }
+
+ // Execute
+ cef_string_userfree_t _retval =
+ cef_format_url_for_security_display(origin_url.GetStruct());
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+CEF_GLOBAL CefString CefGetMimeType(const CefString& extension) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: extension; type: string_byref_const
+ DCHECK(!extension.empty());
+ if (extension.empty()) {
+ return CefString();
+ }
+
+ // Execute
+ cef_string_userfree_t _retval = cef_get_mime_type(extension.GetStruct());
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+CEF_GLOBAL
+void CefGetExtensionsForMimeType(const CefString& mime_type,
+ std::vector<CefString>& extensions) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: mime_type; type: string_byref_const
+ DCHECK(!mime_type.empty());
+ if (mime_type.empty()) {
+ return;
+ }
+
+ // Translate param: extensions; type: string_vec_byref
+ cef_string_list_t extensionsList = cef_string_list_alloc();
+ DCHECK(extensionsList);
+ if (extensionsList) {
+ transfer_string_list_contents(extensions, extensionsList);
+ }
+
+ // Execute
+ cef_get_extensions_for_mime_type(mime_type.GetStruct(), extensionsList);
+
+ // Restore param:extensions; type: string_vec_byref
+ if (extensionsList) {
+ extensions.clear();
+ transfer_string_list_contents(extensionsList, extensions);
+ cef_string_list_free(extensionsList);
+ }
+}
+
+NO_SANITIZE("cfi-icall")
+CEF_GLOBAL CefString CefBase64Encode(const void* data, size_t data_size) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: data; type: simple_byaddr
+ DCHECK(data);
+ if (!data) {
+ return CefString();
+ }
+
+ // Execute
+ cef_string_userfree_t _retval = cef_base64encode(data, data_size);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+CEF_GLOBAL CefRefPtr<CefBinaryValue> CefBase64Decode(const CefString& data) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: data; type: string_byref_const
+ DCHECK(!data.empty());
+ if (data.empty()) {
+ return nullptr;
+ }
+
+ // Execute
+ cef_binary_value_t* _retval = cef_base64decode(data.GetStruct());
+
+ // Return type: refptr_same
+ return CefBinaryValueCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CEF_GLOBAL CefString CefURIEncode(const CefString& text, bool use_plus) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: text; type: string_byref_const
+ DCHECK(!text.empty());
+ if (text.empty()) {
+ return CefString();
+ }
+
+ // Execute
+ cef_string_userfree_t _retval = cef_uriencode(text.GetStruct(), use_plus);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+CEF_GLOBAL CefString CefURIDecode(const CefString& text,
+ bool convert_to_utf8,
+ cef_uri_unescape_rule_t unescape_rule) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: text; type: string_byref_const
+ DCHECK(!text.empty());
+ if (text.empty()) {
+ return CefString();
+ }
+
+ // Execute
+ cef_string_userfree_t _retval =
+ cef_uridecode(text.GetStruct(), convert_to_utf8, unescape_rule);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+CEF_GLOBAL CefRefPtr<CefValue> CefParseJSON(const CefString& json_string,
+ cef_json_parser_options_t options) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: json_string; type: string_byref_const
+ DCHECK(!json_string.empty());
+ if (json_string.empty()) {
+ return nullptr;
+ }
+
+ // Execute
+ cef_value_t* _retval = cef_parse_json(json_string.GetStruct(), options);
+
+ // Return type: refptr_same
+ return CefValueCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CEF_GLOBAL CefRefPtr<CefValue> CefParseJSON(const void* json,
+ size_t json_size,
+ cef_json_parser_options_t options) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: json; type: simple_byaddr
+ DCHECK(json);
+ if (!json) {
+ return nullptr;
+ }
+
+ // Execute
+ cef_value_t* _retval = cef_parse_json_buffer(json, json_size, options);
+
+ // Return type: refptr_same
+ return CefValueCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CEF_GLOBAL CefRefPtr<CefValue> CefParseJSONAndReturnError(
+ const CefString& json_string,
+ cef_json_parser_options_t options,
+ CefString& error_msg_out) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: json_string; type: string_byref_const
+ DCHECK(!json_string.empty());
+ if (json_string.empty()) {
+ return nullptr;
+ }
+
+ // Execute
+ cef_value_t* _retval = cef_parse_jsonand_return_error(
+ json_string.GetStruct(), options, error_msg_out.GetWritableStruct());
+
+ // Return type: refptr_same
+ return CefValueCToCpp::Wrap(_retval);
+}
+
+NO_SANITIZE("cfi-icall")
+CEF_GLOBAL CefString CefWriteJSON(CefRefPtr<CefValue> node,
+ cef_json_writer_options_t options) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: node; type: refptr_same
+ DCHECK(node.get());
+ if (!node.get()) {
+ return CefString();
+ }
+
+ // Execute
+ cef_string_userfree_t _retval =
+ cef_write_json(CefValueCToCpp::Unwrap(node), options);
+
+ // Return type: string
+ CefString _retvalStr;
+ _retvalStr.AttachToUserFree(_retval);
+ return _retvalStr;
+}
+
+NO_SANITIZE("cfi-icall")
+CEF_GLOBAL bool CefGetPath(PathKey key, CefString& path) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = cef_get_path(key, path.GetWritableStruct());
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CEF_GLOBAL bool CefLaunchProcess(CefRefPtr<CefCommandLine> command_line) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: command_line; type: refptr_same
+ DCHECK(command_line.get());
+ if (!command_line.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = cef_launch_process(CefCommandLineCToCpp::Unwrap(command_line));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CEF_GLOBAL bool CefRegisterSchemeHandlerFactory(
+ const CefString& scheme_name,
+ const CefString& domain_name,
+ CefRefPtr<CefSchemeHandlerFactory> factory) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: scheme_name; type: string_byref_const
+ DCHECK(!scheme_name.empty());
+ if (scheme_name.empty()) {
+ return false;
+ }
+ // Unverified params: domain_name, factory
+
+ // Execute
+ int _retval = cef_register_scheme_handler_factory(
+ scheme_name.GetStruct(), domain_name.GetStruct(),
+ CefSchemeHandlerFactoryCppToC::Wrap(factory));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") CEF_GLOBAL bool CefClearSchemeHandlerFactories() {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = cef_clear_scheme_handler_factories();
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CEF_GLOBAL bool CefIsCertStatusError(cef_cert_status_t status) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = cef_is_cert_status_error(status);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") CEF_GLOBAL bool CefCurrentlyOn(CefThreadId threadId) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int _retval = cef_currently_on(threadId);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CEF_GLOBAL bool CefPostTask(CefThreadId threadId, CefRefPtr<CefTask> task) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: task; type: refptr_diff
+ DCHECK(task.get());
+ if (!task.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval = cef_post_task(threadId, CefTaskCppToC::Wrap(task));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CEF_GLOBAL bool CefPostDelayedTask(CefThreadId threadId,
+ CefRefPtr<CefTask> task,
+ int64 delay_ms) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: task; type: refptr_diff
+ DCHECK(task.get());
+ if (!task.get()) {
+ return false;
+ }
+
+ // Execute
+ int _retval =
+ cef_post_delayed_task(threadId, CefTaskCppToC::Wrap(task), delay_ms);
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CEF_GLOBAL bool CefBeginTracing(const CefString& categories,
+ CefRefPtr<CefCompletionCallback> callback) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: categories, callback
+
+ // Execute
+ int _retval = cef_begin_tracing(categories.GetStruct(),
+ CefCompletionCallbackCppToC::Wrap(callback));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CEF_GLOBAL bool CefEndTracing(const CefString& tracing_file,
+ CefRefPtr<CefEndTracingCallback> callback) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Unverified params: tracing_file, callback
+
+ // Execute
+ int _retval = cef_end_tracing(tracing_file.GetStruct(),
+ CefEndTracingCallbackCppToC::Wrap(callback));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall") CEF_GLOBAL int64 CefNowFromSystemTraceTime() {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Execute
+ int64 _retval = cef_now_from_system_trace_time();
+
+ // Return type: simple
+ return _retval;
+}
+
+NO_SANITIZE("cfi-icall")
+CEF_GLOBAL bool CefRegisterExtension(const CefString& extension_name,
+ const CefString& javascript_code,
+ CefRefPtr<CefV8Handler> handler) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: extension_name; type: string_byref_const
+ DCHECK(!extension_name.empty());
+ if (extension_name.empty()) {
+ return false;
+ }
+ // Verify param: javascript_code; type: string_byref_const
+ DCHECK(!javascript_code.empty());
+ if (javascript_code.empty()) {
+ return false;
+ }
+ // Unverified params: handler
+
+ // Execute
+ int _retval = cef_register_extension(extension_name.GetStruct(),
+ javascript_code.GetStruct(),
+ CefV8HandlerCppToC::Wrap(handler));
+
+ // Return type: bool
+ return _retval ? true : false;
+}
+
+NO_SANITIZE("cfi-icall")
+CEF_GLOBAL void CefExecuteJavaScriptWithUserGestureForTests(
+ CefRefPtr<CefFrame> frame,
+ const CefString& javascript) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: frame; type: refptr_same
+ DCHECK(frame.get());
+ if (!frame.get()) {
+ return;
+ }
+ // Unverified params: javascript
+
+ // Execute
+ cef_execute_java_script_with_user_gesture_for_tests(
+ CefFrameCToCpp::Unwrap(frame), javascript.GetStruct());
+}
+
+NO_SANITIZE("cfi-icall")
+CEF_GLOBAL void CefSetDataDirectoryForTests(const CefString& dir) {
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+ // Verify param: dir; type: string_byref_const
+ DCHECK(!dir.empty());
+ if (dir.empty()) {
+ return;
+ }
+
+ // Execute
+ cef_set_data_directory_for_tests(dir.GetStruct());
+}
diff --git a/libcef_dll/wrapper/libcef_dll_wrapper2.cc b/libcef_dll/wrapper/libcef_dll_wrapper2.cc
new file mode 100644
index 00000000..02b1f854
--- /dev/null
+++ b/libcef_dll/wrapper/libcef_dll_wrapper2.cc
@@ -0,0 +1,62 @@
+// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "include/base/cef_build.h"
+
+#if defined(OS_WIN)
+
+#include "include/base/cef_compiler_specific.h"
+#include "include/base/cef_logging.h"
+#include "include/cef_api_hash.h"
+#include "include/internal/cef_win.h"
+
+#if defined(ARCH_CPU_32_BITS)
+NO_SANITIZE("cfi-icall")
+int CefRunWinMainWithPreferredStackSize(wWinMainPtr wWinMain,
+ HINSTANCE hInstance,
+ LPWSTR lpCmdLine,
+ int nCmdShow) {
+ CHECK(wWinMain && hInstance);
+
+ const char* api_hash = cef_api_hash(0);
+ if (strcmp(api_hash, CEF_API_HASH_PLATFORM)) {
+ // The libcef API hash does not match the current header API hash.
+ NOTREACHED();
+ return 0;
+ }
+
+ return cef_run_winmain_with_preferred_stack_size(wWinMain, hInstance,
+ lpCmdLine, nCmdShow);
+}
+
+int CefRunMainWithPreferredStackSize(mainPtr main, int argc, char* argv[]) {
+ CHECK(main);
+
+ const char* api_hash = cef_api_hash(0);
+ if (strcmp(api_hash, CEF_API_HASH_PLATFORM)) {
+ // The libcef API hash does not match the current header API hash.
+ NOTREACHED();
+ return 0;
+ }
+
+ return cef_run_main_with_preferred_stack_size(main, argc, argv);
+}
+#endif // defined(ARCH_CPU_32_BITS)
+
+NO_SANITIZE("cfi-icall") void CefEnableHighDPISupport() {
+ const char* api_hash = cef_api_hash(0);
+ if (strcmp(api_hash, CEF_API_HASH_PLATFORM)) {
+ // The libcef API hash does not match the current header API hash.
+ NOTREACHED();
+ return;
+ }
+
+ cef_enable_highdpi_support();
+}
+
+NO_SANITIZE("cfi-icall") void CefSetOSModalLoop(bool osModalLoop) {
+ cef_set_osmodal_loop(osModalLoop);
+}
+
+#endif // defined(OS_WIN)
diff --git a/libcef_dll/wrapper_types.h b/libcef_dll/wrapper_types.h
new file mode 100644
index 00000000..eddb3ec9
--- /dev/null
+++ b/libcef_dll/wrapper_types.h
@@ -0,0 +1,189 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=220cf66311a9b87b0edfadf9617138d7cf3273f8$
+//
+
+#ifndef CEF_LIBCEF_DLL_WRAPPER_TYPES_H_
+#define CEF_LIBCEF_DLL_WRAPPER_TYPES_H_
+#pragma once
+
+enum CefWrapperType {
+ WT_BASE_REF_COUNTED = 1,
+ WT_BASE_SCOPED,
+ WT_ACCESSIBILITY_HANDLER,
+ WT_APP,
+ WT_AUDIO_HANDLER,
+ WT_AUTH_CALLBACK,
+ WT_BEFORE_DOWNLOAD_CALLBACK,
+ WT_BINARY_VALUE,
+ WT_BOX_LAYOUT,
+ WT_BROWSER,
+ WT_BROWSER_HOST,
+ WT_BROWSER_PROCESS_HANDLER,
+ WT_BROWSER_VIEW,
+ WT_BROWSER_VIEW_DELEGATE,
+ WT_BUTTON,
+ WT_BUTTON_DELEGATE,
+ WT_CALLBACK,
+ WT_CLIENT,
+ WT_COMMAND_HANDLER,
+ WT_COMMAND_LINE,
+ WT_COMPLETION_CALLBACK,
+ WT_CONTEXT_MENU_HANDLER,
+ WT_CONTEXT_MENU_PARAMS,
+ WT_COOKIE_ACCESS_FILTER,
+ WT_COOKIE_MANAGER,
+ WT_COOKIE_VISITOR,
+ WT_DOMDOCUMENT,
+ WT_DOMNODE,
+ WT_DOMVISITOR,
+ WT_DELETE_COOKIES_CALLBACK,
+ WT_DEV_TOOLS_MESSAGE_OBSERVER,
+ WT_DIALOG_HANDLER,
+ WT_DICTIONARY_VALUE,
+ WT_DISPLAY,
+ WT_DISPLAY_HANDLER,
+ WT_DOWNLOAD_HANDLER,
+ WT_DOWNLOAD_IMAGE_CALLBACK,
+ WT_DOWNLOAD_ITEM,
+ WT_DOWNLOAD_ITEM_CALLBACK,
+ WT_DRAG_DATA,
+ WT_DRAG_HANDLER,
+ WT_END_TRACING_CALLBACK,
+ WT_EXTENSION,
+ WT_EXTENSION_HANDLER,
+ WT_FILE_DIALOG_CALLBACK,
+ WT_FILL_LAYOUT,
+ WT_FIND_HANDLER,
+ WT_FOCUS_HANDLER,
+ WT_FRAME,
+ WT_FRAME_HANDLER,
+ WT_GET_EXTENSION_RESOURCE_CALLBACK,
+ WT_IMAGE,
+ WT_JSDIALOG_CALLBACK,
+ WT_JSDIALOG_HANDLER,
+ WT_KEYBOARD_HANDLER,
+ WT_LABEL_BUTTON,
+ WT_LAYOUT,
+ WT_LIFE_SPAN_HANDLER,
+ WT_LIST_VALUE,
+ WT_LOAD_HANDLER,
+ WT_MEDIA_ACCESS_CALLBACK,
+ WT_MEDIA_OBSERVER,
+ WT_MEDIA_ROUTE,
+ WT_MEDIA_ROUTE_CREATE_CALLBACK,
+ WT_MEDIA_ROUTER,
+ WT_MEDIA_SINK,
+ WT_MEDIA_SINK_DEVICE_INFO_CALLBACK,
+ WT_MEDIA_SOURCE,
+ WT_MENU_BUTTON,
+ WT_MENU_BUTTON_DELEGATE,
+ WT_MENU_BUTTON_PRESSED_LOCK,
+ WT_MENU_MODEL,
+ WT_MENU_MODEL_DELEGATE,
+ WT_NAVIGATION_ENTRY,
+ WT_NAVIGATION_ENTRY_VISITOR,
+ WT_OVERLAY_CONTROLLER,
+ WT_PANEL,
+ WT_PANEL_DELEGATE,
+ WT_PDF_PRINT_CALLBACK,
+ WT_PERMISSION_HANDLER,
+ WT_PERMISSION_PROMPT_CALLBACK,
+ WT_POST_DATA,
+ WT_POST_DATA_ELEMENT,
+ WT_PREFERENCE_MANAGER,
+ WT_PREFERENCE_REGISTRAR,
+ WT_PRINT_DIALOG_CALLBACK,
+ WT_PRINT_HANDLER,
+ WT_PRINT_JOB_CALLBACK,
+ WT_PRINT_SETTINGS,
+ WT_PROCESS_MESSAGE,
+ WT_READ_HANDLER,
+ WT_REGISTRATION,
+ WT_RENDER_HANDLER,
+ WT_RENDER_PROCESS_HANDLER,
+ WT_REQUEST,
+ WT_REQUEST_CONTEXT,
+ WT_REQUEST_CONTEXT_HANDLER,
+ WT_REQUEST_HANDLER,
+ WT_RESOLVE_CALLBACK,
+ WT_RESOURCE_BUNDLE,
+ WT_RESOURCE_BUNDLE_HANDLER,
+ WT_RESOURCE_HANDLER,
+ WT_RESOURCE_READ_CALLBACK,
+ WT_RESOURCE_REQUEST_HANDLER,
+ WT_RESOURCE_SKIP_CALLBACK,
+ WT_RESPONSE,
+ WT_RESPONSE_FILTER,
+ WT_RUN_CONTEXT_MENU_CALLBACK,
+ WT_RUN_FILE_DIALOG_CALLBACK,
+ WT_RUN_QUICK_MENU_CALLBACK,
+ WT_SSLINFO,
+ WT_SSLSTATUS,
+ WT_SCHEME_HANDLER_FACTORY,
+ WT_SCHEME_REGISTRAR,
+ WT_SCROLL_VIEW,
+ WT_SELECT_CLIENT_CERTIFICATE_CALLBACK,
+ WT_SERVER,
+ WT_SERVER_HANDLER,
+ WT_SET_COOKIE_CALLBACK,
+ WT_SHARED_MEMORY_REGION,
+ WT_SHARED_PROCESS_MESSAGE_BUILDER,
+ WT_STREAM_READER,
+ WT_STREAM_WRITER,
+ WT_STRING_VISITOR,
+ WT_TASK,
+ WT_TASK_RUNNER,
+ WT_TEST_SERVER,
+ WT_TEST_SERVER_CONNECTION,
+ WT_TEST_SERVER_HANDLER,
+ WT_TEXTFIELD,
+ WT_TEXTFIELD_DELEGATE,
+ WT_THREAD,
+ WT_TRANSLATOR_TEST,
+ WT_TRANSLATOR_TEST_REF_PTR_CLIENT,
+ WT_TRANSLATOR_TEST_REF_PTR_CLIENT_CHILD,
+ WT_TRANSLATOR_TEST_REF_PTR_LIBRARY,
+ WT_TRANSLATOR_TEST_REF_PTR_LIBRARY_CHILD,
+ WT_TRANSLATOR_TEST_REF_PTR_LIBRARY_CHILD_CHILD,
+ WT_TRANSLATOR_TEST_SCOPED_CLIENT,
+ WT_TRANSLATOR_TEST_SCOPED_CLIENT_CHILD,
+ WT_TRANSLATOR_TEST_SCOPED_LIBRARY,
+ WT_TRANSLATOR_TEST_SCOPED_LIBRARY_CHILD,
+ WT_TRANSLATOR_TEST_SCOPED_LIBRARY_CHILD_CHILD,
+ WT_URLREQUEST,
+ WT_URLREQUEST_CLIENT,
+ WT_V8ACCESSOR,
+ WT_V8ARRAY_BUFFER_RELEASE_CALLBACK,
+ WT_V8CONTEXT,
+ WT_V8EXCEPTION,
+ WT_V8HANDLER,
+ WT_V8INTERCEPTOR,
+ WT_V8STACK_FRAME,
+ WT_V8STACK_TRACE,
+ WT_V8VALUE,
+ WT_VALUE,
+ WT_VIEW,
+ WT_VIEW_DELEGATE,
+ WT_WAITABLE_EVENT,
+ WT_WINDOW,
+ WT_WINDOW_DELEGATE,
+ WT_WRITE_HANDLER,
+ WT_X509CERT_PRINCIPAL,
+ WT_X509CERTIFICATE,
+ WT_XML_READER,
+ WT_ZIP_READER,
+
+ WT_LAST
+};
+
+#endif // CEF_LIBCEF_DLL_WRAPPER_TYPES_H_
diff --git a/patch/README.txt b/patch/README.txt
new file mode 100644
index 00000000..7ea3ccbf
--- /dev/null
+++ b/patch/README.txt
@@ -0,0 +1,15 @@
+There may be instances where CEF requires changes to the source code for
+Chromium, Blink or third-party projects that are either not desired by those
+projects or that have not yet been merged into the source code versions of those
+projects used by CEF. To address this situation the CEF project adds a patch
+capability as part of cef_create_projects[.bat|sh] build step. This patch
+capability works as follows:
+
+1. The CEF developer creates one or more patch files containing all required
+ code changes and places those patch files in the "patches" subdirectory.
+2. The CEF developer adds an entry for each patch file in the "patch.cfg" file.
+3. When building CEF from source code the patch files are applied by the
+ patcher.py tool via the cef_create_projects[.bat|sh] build step
+4. When updating Chromium the patch_updater.py tool is used to update all patch
+ files. See https://bitbucket.org/chromiumembedded/cef/wiki/ChromiumUpdate.md
+ for more information about the update process.
diff --git a/patch/patch.cfg b/patch/patch.cfg
new file mode 100644
index 00000000..2652be90
--- /dev/null
+++ b/patch/patch.cfg
@@ -0,0 +1,628 @@
+# Patch configuration file. See the README.txt file in the patch directory for
+# information on how this configuration is used.
+#
+# Each dictionary entry in the "patches" map represents a single patch file.
+# Supported key/value pairs are as follows:
+#
+# - 'name' Required. The name of the patch file without the .patch
+# extension that will be read from the patches subdirectory.
+# - 'path' Optional. The repository root for the patch file. Defaults to
+# the Chromium "src" root. All patch file contents must be
+# relative to this repository root.
+# - 'condition' Optional. The patch file will only be applied if an environment
+# variable with this name exists.
+#
+# Each entry should also include a comment linking to the code review or bug
+# report that the patch relates to.
+
+patches = [
+ {
+ # Necessary for grit integration.
+ 'name': 'gritsettings',
+ },
+ {
+ # Necessary for GN integration.
+ #
+ # Exclude the //chrome:packed_resources_locales target from the CEF build
+ # due to conflicting outputs with the //cef:repack_locales_pack target.
+ #
+ # Write environment.* files with the correct SDK version on Windows.
+ # https://bugs.chromium.org/p/chromium/issues/detail?id=634788
+ #
+ # Windows: Add cc_wrapper support for sccache builds.
+ # https://github.com/chromiumembedded/cef/issues/2432
+ 'name': 'gn_config',
+ },
+ {
+ # Patches that must be applied after `gclient sync --nohooks` and before
+ # `gclient runhooks`.
+ #
+ # Support custom VS toolchain on Windows.
+ # https://bugs.chromium.org/p/chromium/issues/detail?id=623342
+ #
+ # Don't copy dbghelp.dll/dbgcore.dll from the Windows SDK.
+ # https://github.com/chromiumembedded/cef/issues/3356
+ 'name': 'runhooks',
+ },
+ {
+ # Support component builds (GN is_component_build=true).
+ # https://github.com/chromiumembedded/cef/issues/1617
+ 'name': 'component_build',
+ },
+ {
+ # Revert change on Windows that removes MessageLoop::os_modal_loop().
+ # https://codereview.chromium.org/1992243003
+ #
+ # Revert change that removes MessageLoopForUI constructor.
+ # https://chromium-review.googlesource.com/751322
+ #
+ # Add MessageLoop::ReleasePump to fix crashes during shutdown with multi-
+ # threaded message loop mode.
+ # https://github.com/chromiumembedded/cef/issues/2362
+ 'name': 'message_loop',
+ },
+ {
+ # Add builtin trace event categories for CEF.
+ # Required due to https://crrev.com/331266377d.
+ 'name': 'trace_event',
+ },
+ {
+ # Enable popups in offscreen rendering on MacOS.
+ 'name': 'webkit_popups',
+ },
+ {
+ # Give AlloyContentRendererClient access to protected
+ # RuntimeEnabledFeatures methods.
+ 'name': 'webkit_runtime_enabled_features',
+ },
+ {
+ # Fix export of UnderlayOpenGLHostingWindow for 64-bit MacOS builds.
+ # https://github.com/chromiumembedded/cef/issues/1051
+ 'name': 'underlay_1051',
+ },
+ {
+ # Allow specification of a parent window handle for Widget creation.
+ # https://github.com/chromiumembedded/cef/issues/180
+ #
+ # Fix multiple handling of WM_MOUSEWHEEL messages on Windows.
+ # https://github.com/chromiumembedded/cef/issues/1481
+ #
+ # Support custom RenderWidgetHostViewOSR for BrowserPluginGuest.
+ # https://github.com/chromiumembedded/cef/issues/1565
+ #
+ # Fix focus/activation handling and keyboard input on Windows and Linux.
+ # https://github.com/chromiumembedded/cef/issues/1677
+ # https://github.com/chromiumembedded/cef/issues/1679
+ # https://github.com/chromiumembedded/cef/issues/1700
+ # https://github.com/chromiumembedded/cef/issues/3316
+ #
+ # Support creation of captionless windows with resizable borders.
+ # https://github.com/chromiumembedded/cef/issues/1749
+ #
+ # Windows: When |params.remove_standard_frame| is true remove WS_CAPTION
+ # and WS_SYSMENU styles. Otherwise Windows 10 enforces a minimum window
+ # width of ~116 units that cannot be overridden.
+ # Linux: Allow creation of activatable menu windows.
+ # Linux: Support CefWindowDelegate::CanResize restriction by specifying
+ # min/max Widget size values.
+ # https://github.com/chromiumembedded/cef/issues/1947
+ #
+ # Support configuration of RWHVGuest device scale factor.
+ # https://github.com/chromiumembedded/cef/issues/2078
+ #
+ # Windows: Fix focus assignment when clicking WebView with external parent.
+ # https://github.com/chromiumembedded/cef/issues/3031
+ #
+ # Fix minimize & fullscreen behavior on initial Widget creation.
+ #
+ # Allow override of RWHVBase::GetNewScreenInfosForUpdate() which is now
+ # required due to https://crrev.com/96938eb36e in order to use
+ # RWHVBase::UpdateScreenInfo() with OSR.
+ #
+ # Windows: Fix incorrect DIPToScreenRect usage in DesktopWindowTreeHostWin
+ # when |has_external_parent_| is true.
+ # https://github.com/chromiumembedded/cef/issues/3359
+ 'name': 'views_widget',
+ },
+ {
+ # Allow specification of a custom WebContentsView.
+ # https://github.com/chromiumembedded/cef/issues/1257
+ #
+ # Support custom RenderWidgetHostViewOSR for BrowserPluginGuest.
+ # https://github.com/chromiumembedded/cef/issues/1565
+ #
+ # Add WebContentsObserver::OnFrameFocused.
+ #
+ # Add WebContentsObserver::RenderWidgetCreated.
+ # https://github.com/chromiumembedded/cef/issues/3308
+ 'name': 'web_contents_1257_1565',
+ },
+ {
+ # Support custom RenderWidgetHostViewOSR for MimeHandlerViewGuest and
+ # expose OnGuestAttached/Detached notifications.
+ # https://github.com/chromiumembedded/cef/issues/1565
+ # https://github.com/chromiumembedded/cef/issues/2727
+ 'name': 'mime_handler_view_guest_1565_2727',
+ },
+ {
+ # Fix drag&drop of combined text and URL data on Linux/Aura.
+ # https://codereview.chromium.org/208313009
+ 'name': 'ui_dragdrop_355390',
+ },
+ {
+ # Split content::ContentMain into the separate steps required by CEF.
+ # https://bugs.chromium.org/p/chromium/issues/detail?id=654986#c17
+ #
+ # Remove DCHECK on Linux when initialized CEF from a non-main thread.
+ # https://github.com/chromiumembedded/cef/issues/1639
+ #
+ # Fix DiscardableSharedMemoryManager crash on shutdown with multi-threaded
+ # message loop.
+ # https://github.com/chromiumembedded/cef/issues/2798
+ 'name': 'content_main_654986',
+ },
+ {
+ # Expose the FontFamilyCache UserData key.
+ # https://github.com/chromiumembedded/cef/issues/1501
+ 'name': 'font_family_cache_1501',
+ },
+ {
+ # Modify views::View to extend SupportsUserData.
+ # https://github.com/chromiumembedded/cef/issues/1749
+ #
+ # Don't add TestDesktopScreenOzone dependency on Linux.
+ # Reverts ui_controls_factory_desktop_aurax11.cc (now
+ # ui_controls_factory_desktop_aura_ozone.cc) changes from
+ # https://codereview.chromium.org/2327623002
+ #
+ # Add InkDropHostView::ink_drop_mode method.
+ # Reverts ink_drop_host_view.h changes from
+ # https://codereview.chromium.org/2723843002
+ #
+ # Add LabelButton::SetFontList method.
+ # Reverts label_button.[cc|h] changes from
+ # https://codereview.chromium.org/2801583002
+ #
+ # Expose callbacks for mouse/keyboard events that trigger menu switching.
+ # Add accelerator display support to Label.
+ # https://github.com/chromiumembedded/cef/issues/2102
+ #
+ # Route |parent_widget| to MenuHost for OSR context menu Widget creation.
+ # https://github.com/chromiumembedded/cef/issues/3330
+ 'name': 'views_1749_2102_3330',
+ },
+ {
+ # Support CEF changes in chrome/browser.
+ #
+ # Fix duplicate symbols for enterprise_connectors::ContentAnalysisSdkManager
+ # https://bugs.chromium.org/p/chromium/issues/detail?id=1368633
+ 'name': 'chrome_browser',
+ },
+ {
+ # Support CEF changes in chrome/renderer.
+ 'name': 'chrome_renderer',
+ },
+ {
+ # Changes to support the Chrome runtime in CEF.
+ # https://github.com/chromiumembedded/cef/issues/2969
+ 'name': 'chrome_runtime',
+ },
+ {
+ # Changes to support Chrome runtime integration with CEF Views.
+ # See related documentation in
+ # libcef/browser/chrome/views/chrome_browser_frame.h.
+ # https://github.com/chromiumembedded/cef/issues/2969
+ 'name': 'chrome_runtime_views',
+ },
+ {
+ # Changes to support the Chrome runtime in CEF.
+ # https://github.com/chromiumembedded/cef/issues/2969
+ #
+ # Fix fatal error: 'components/printing/common/print.mojom.h' file not found
+ # From chrome/browser/ui/browser_commands.cc via
+ # chrome/browser/printing/print_view_manager_common.h
+ 'name': 'chrome_browser_browser',
+ },
+ {
+ # Don't initialize ExtensionSystemFactory when extensions are disabled.
+ # https://github.com/chromiumembedded/cef/issues/2359
+ #
+ # Remove NOTREACHED() in GetContentSettingFromRulesImpl triggered by
+ # NavigationTest.LoadCrossOriginLoadURL with the chrome runtime.
+ 'name': 'chrome_browser_content_settings',
+ },
+ {
+ # chrome: Support custom handling of context menus.
+ # https://github.com/chromiumembedded/cef/issues/2969
+ 'name': 'chrome_browser_context_menus',
+ },
+ {
+ # Support use of chrome native dialogs with CEF runtimes.
+ # - Adds support for FileSelectHelper and SelectFileDialog interception.
+ # - Adds additional type filters for dialogs created via FileSelectHelper.
+ # - Adds support for chaining PrintingContextLinux callbacks.
+ # https://github.com/chromiumembedded/cef/issues/3314
+ 'name': 'chrome_browser_dialogs_native',
+ },
+ {
+ # Support use of chrome Widget dialogs with CEF runtimes.
+ # - Add gfx::AcceleratedWidget dialog parent argument to
+ # DialogDelegate::CreateDialogWidget for CEF windowless rendering.
+ # - Support nullptr gfx::NativeWindow/gfx::NativeView dialog parent for CEF
+ # windowless rendering.
+ # https://github.com/chromiumembedded/cef/issues/3316
+ 'name': 'chrome_browser_dialogs_widget',
+ },
+ {
+ # chrome: Support override of ChromeMimeHandlerViewGuestDelegate.
+ # https://github.com/chromiumembedded/cef/issues/2969
+ 'name': 'chrome_browser_extensions',
+ },
+ {
+ # alloy: Disable ProxyErrorClient callbacks when extensions are disabled.
+ # https://github.com/chromiumembedded/cef/issues/2830
+ 'name': 'chrome_browser_net_proxy',
+ },
+ {
+ # Support override of CreatePermissionPrompt.
+ # https://github.com/chromiumembedded/cef/issues/3352
+ 'name': 'chrome_browser_permission_prompt',
+ },
+ {
+ # alloy: Don't initialize ExtensionSystemFactory when extensions are
+ # disabled.
+ # https://github.com/chromiumembedded/cef/issues/2852
+ 'name': 'chrome_browser_themes',
+ },
+ {
+ # Make some methods of ProfileManager virtual.
+ #
+ # Don't create IdentityManager in RendererUpdater.
+ # https://github.com/chromiumembedded/cef/issues/1917
+ #
+ # chrome: Support CEF incognito Profiles that allow Browser creation.
+ # chrome: Allow CEF to delay OffTheRecordProfileImpl initialization.
+ # https://github.com/chromiumembedded/cef/issues/2969
+ 'name': 'chrome_browser_profiles',
+ },
+ {
+ # chrome: Fix assertion when clicking the incognito profile button.
+ # https://github.com/chromiumembedded/cef/issues/2969
+ 'name': 'chrome_browser_profile_menu',
+ },
+ {
+ # alloy: Don't require heap profiler for utility processes.
+ # Avoids a DCHECK added in https://crrev.com/c21e9f71d1f2e
+ 'name': 'chrome_utility_client',
+ },
+ {
+ # Support override of the User-Agent product component when NetworkService
+ # is enabled.
+ # https://github.com/chromiumembedded/cef/issues/2622
+ 'name': 'embedder_product_override',
+ },
+ {
+ # Fix Jumbo/component build dependency issue.
+ 'name': 'chrome_browser_safe_browsing',
+ },
+ {
+ # Allow CEF to share Chrome plugin loading code.
+ #
+ # Add BrowserPluginGuest::owner_web_contents() method.
+ 'name': 'chrome_plugins',
+ },
+ {
+ # Don't create databases, blob_storage or VideoDecodeStats directories when
+ # cache_path is empty.
+ # https://github.com/chromiumembedded/cef/issues/2289
+ 'name': 'storage_incognito_2289',
+ },
+ {
+ # Support WebUI by removing dependency on non-NULL IOThread* object.
+ # https://github.com/chromiumembedded/cef/issues/2037
+ 'name': 'webui_2037',
+ },
+ {
+ # Implement breakpad/crashpad customization required by CEF.
+ # https://github.com/chromiumembedded/cef/issues/1995
+ 'name': 'crashpad_1995',
+ },
+ {
+ # Support customization of crash report pruning limits.
+ # https://bugs.chromium.org/p/crashpad/issues/detail?id=142
+ #
+ # Implement better rate-limiting/retry logic.
+ # https://bugs.chromium.org/p/crashpad/issues/detail?id=23
+ 'name': 'crashpad_tp_1995',
+ },
+ {
+ # Fix white flash during browser creation.
+ # https://github.com/chromiumembedded/cef/issues/1984
+ #
+ # Windows: Fix crash during window creation.
+ # https://bugs.chromium.org/p/chromium/issues/detail?id=761389
+ 'name': 'rwh_background_color_1984',
+ },
+ {
+ # Expose RFH via NavigationHandle for retrieval in DidFinishNavigation on
+ # network error.
+ # https://groups.google.com/a/chromium.org/d/msg/chromium-dev/6iAQPx_hwh8/gaTR5f1GAQAJ
+ #
+ # Add ContentRendererClient::RenderThreadConnected to fix sync IPC issue.
+ # https://bugs.chromium.org/p/chromium/issues/detail?id=728195
+ #
+ # Add ContentRendererClient::DevToolsAgent[Attached|Detached] methods.
+ #
+ # Always return the Chrome product value for DevTools.
+ # https://github.com/chromiumembedded/cef/issues/2300
+ #
+ # Add new ContentBrowserClient::HandleExternalProtocol variant for use with
+ # the NetworkService.
+ # https://github.com/chromiumembedded/cef/issues/2622
+ #
+ # Change ContentBrowserClient::ConfigureNetworkContextParams return type to
+ # bool to support cancellation of NetworkContext creation during shutdown.
+ # https://github.com/chromiumembedded/cef/issues/2985
+ 'name': 'content_2015',
+ },
+ {
+ # Add ContentRendererClient::DevToolsAgent[Attached|Detached] methods.
+ 'name': 'webkit_plugin_info_2015',
+ },
+ {
+ # Linux: Attach routing IDs to PrintingContext.
+ # https://github.com/chromiumembedded/cef/issues/2196
+ 'name': 'printing_context_2196',
+ },
+ {
+ # Windows: Remove llvmlibthin as the combine_libs.py can't handle those.
+ # https://github.com/chromiumembedded/cef/issues/2470
+ 'name': 'build',
+ },
+ {
+ # Changes necessary to support chrome extensions. Add a new
+ # ExtensionHost constructor that allows CEF to create the WebContents.
+ # https://github.com/chromiumembedded/cef/issues/1947
+ #
+ # Don't initialize PrerenderContents object in StreamsPrivateAPI.
+ #
+ # Return nullptr from ExtensionsClient::Get and ExtensionRegistry::Get
+ # when extensions are disabled.
+ 'name': 'extensions_1947',
+ },
+ {
+ # macOS: Fix undesirable switch to discrete GPU during startup.
+ # https://github.com/chromiumembedded/cef/issues/2398
+ #
+ # macOS: Rely on symlinks to find the Libraries directory.
+ # https://bugs.chromium.org/p/chromium/issues/detail?id=757974#c23
+ 'name': 'mac_gpu',
+ },
+ {
+ # macOS: Make the NativeEventProcessor protocol dependency optional.
+ # https://github.com/chromiumembedded/cef/issues/2539
+ 'name': 'mac_event_observer_2539',
+ },
+ {
+ # macOS: Fix crash when scrolling in OSR mode.
+ # https://github.com/chromiumembedded/cef/issues/2540
+ 'name': 'mac_fling_scheduler_2540',
+ },
+ {
+ # Allow ResourceBundle creation/destruction on the main thread and usage on
+ # the UI thread.
+ # https://github.com/chromiumembedded/cef/issues/2398
+ 'name': 'resource_bundle_2512',
+ },
+ {
+ # macOS: Fix crash when showing a select popup with CefDoMessageLoopWork.
+ # https://github.com/chromiumembedded/cef/issues/2495
+ 'name': 'message_pump_mac_2495',
+ },
+ {
+ # Linux: Load binaries from DIR_ASSETS.
+ # https://github.com/chromiumembedded/cef/issues/1936
+ 'name': 'linux_assets_path_1936',
+ },
+ {
+ # Linux: Fix ld.lld: error: relocation R_X86_64_TPOFF32 against
+ # blink::g_thread_specific_ cannot be used with -shared
+ # https://groups.google.com/a/chromium.org/g/blink-dev/c/wx0gZFCY3p4/m/iLBHRi0ZAQAJ
+ 'name': 'linux_blink_thread_local',
+ },
+ {
+ # Linux: Avoid usage of chrome::FILE_COMPONENT_WIDEVINE_CDM_HINT.
+ # https://github.com/chromiumembedded/cef/issues/3149
+ 'name': 'linux_chrome_widevine_3149',
+ },
+ {
+ # Enhancements to NetworkService:
+ # - Add support for calling CookieMonster::SetCookieableSchemes.
+ # - Fix cache directory structure ("C:\temp\cache\cache\Cache" should be
+ # "C:\temp\cache\Cache").
+ # https://github.com/chromiumembedded/cef/issues/2622
+ #
+ # alloy: Avoid initialization of privacy sandbox and identity manager.
+ # https://github.com/chromiumembedded/cef/issues/3434
+ 'name': 'services_network_2622',
+ },
+ {
+ # Enhancements to NetworkService:
+ # - Remove the non-nullptr WebContents requirement from
+ # NetworkServiceClient::OnAuthRequired.
+ # https://github.com/chromiumembedded/cef/issues/2718
+ #
+ # Change ContentBrowserClient::ConfigureNetworkContextParams return type to
+ # bool to support cancellation of NetworkContext creation during shutdown.
+ # https://github.com/chromiumembedded/cef/issues/2985
+ #
+ # Compute correct default quota when cache_path is unspecified.
+ 'name': 'services_network_2718',
+ },
+ {
+ # Restore the net::LOAD_DO_NOT_SEND_COOKIES flag to support disabling of
+ # cookie load/save on a per-request basis.
+ # Partially reverts the changes from
+ # https://chromium.googlesource.com/chromium/src/+/25eaa43022
+ 'name': 'net_cookie_flags',
+ },
+ {
+ # Restore WebView::SetResizeBackgroundColor() that was removed.
+ # http://crrev.com/3955c9f9eb
+ 'name': 'set_resize_background_color',
+ },
+ {
+ # Restore WebUrlLoader Cancel method.
+ # https://chromium-review.googlesource.com/c/chromium/src/+/1617042
+ 'name': 'web_url_loader_cancel_1617042',
+ },
+ {
+ # Avoid a shutdown crash with multi-threaded message loop caused by
+ # |g_browser_task_executor->browser_ui_thread_scheduler_| being null when
+ # BrowserTaskExecutor::Shutdown is called via CefContext::FinalizeShutdown.
+ # This crash was introduced by https://crrev.com/5f6212babf.
+ 'name': 'browser_scheduler',
+ },
+ {
+ # Restore access to WebUIControllerFactory::UnregisterFactoryForTesting
+ # which was removed in https://crrev.com/5f183d6636. We can't use
+ # ScopedWebUIControllerFactoryRegistration because it pulls in GTest
+ # dependencies.
+ #
+ # Add accessor for WebUIConfigMap::webui_controller_factory_.
+ 'name': 'browser_web_ui_controller_factory',
+ },
+ {
+ # Avoid a shutdown crash caused by PrefWatcher holding a reference to
+ # |g_browser_process->local_state()|, and the local_state being deleted
+ # before the PrefWatcher object (which is associated with a Profile).
+ # PrefWatcher::Shutdown will now be called from ChromeBrowserProcessStub::
+ # Shutdown for all Profiles before local_state deletion.
+ # This crash was introduced by https://crrev.com/7d032b378c.
+ 'name': 'chrome_pref_watcher',
+ },
+ {
+ # Add support for OSR rendering with Viz.
+ # https://github.com/chromiumembedded/cef/issues/2575
+ 'name': 'viz_osr_2575',
+ },
+ {
+ # Changes for print preview support:
+ # - Don't attach unnecessary Chrome-related handlers to constrained window.
+ # - Create file dialogs using the CEF code path.
+ # - Remove unsupported print preview UI options.
+ # - macOS: Fix error: no member named 'kCloudPrinterHandler' in namespace
+ # 'printing::features',
+ # https://github.com/chromiumembedded/cef/issues/123
+ 'name': 'print_preview_123',
+ },
+ {
+ # Store command-line switch names as lower-case ASCII on all platforms.
+ # https://github.com/chromiumembedded/cef/issues/1872
+ 'name': 'base_command_line_1872',
+ },
+ {
+ # Remove cef_sandbox dependency on boringssl functions.
+ # https://github.com/chromiumembedded/cef/issues/2743
+ #
+ # Enable the VS 2015 Update 2 fix when building with the MSVC standard
+ # library.
+ #
+ # Avoid usage of std::atomic_flag::test() added in C++20.
+ # https://github.com/llvm/llvm-project/issues/57364
+ #
+ # Avoid usage of PartitionAlloc assertions (PA_BASE_CHECK) in raw_ptr.h.
+ 'name': 'base_sandbox_2743',
+ },
+ {
+ # Add RenderWidgetHostImpl::SetCompositorForFlingScheduler to fix fling
+ # scrolling in OSR mode.
+ # https://github.com/chromiumembedded/cef/issues/2745
+ 'name': 'osr_fling_2745',
+ },
+ {
+ # Windows: Build targets as C++17 to avoid export of std::is_integral
+ # templates in cef_sandbox that should be inlined.
+ # https://github.com/chromiumembedded/cef/issues/2819
+ 'name': 'win_cpp17_msvc_sandbox_2819',
+ },
+ {
+ # libxml access is now limited to targets audited by the Security Team.
+ # https://chromium-review.googlesource.com/c/chromium/src/+/1884750
+ 'name': 'libxml_visibility',
+ },
+ {
+ # Fix unbound AssociatedRemote error in SetBackgroundOpaque.
+ # https://bugs.chromium.org/p/chromium/issues/detail?id=1070713
+ 'name': 'renderer_host_1070713',
+ },
+ {
+ # Allow the loading of non-standard non-local WebSafe custom schemes in
+ # iframes.
+ # https://bugs.chromium.org/p/chromium/issues/detail?id=1081397#c9
+ #
+ # Fix crash in NavigationRequest::GetOriginForURLLoaderFactory() when
+ # navigating to an unregistered (e.g. non-standard) scheme.
+ # https://github.com/chromiumembedded/cef/issues/3105
+ 'name': 'browser_security_policy_1081397',
+ },
+ {
+ # Fix build errors with enable_background_mode=false.
+ # https://bugs.chromium.org/p/chromium/issues/detail?id=1100085
+ #
+ # Changes to support the Chrome runtime in CEF (app_controller_mac.mm).
+ # https://github.com/chromiumembedded/cef/issues/2969
+ 'name': 'chrome_browser_background_mode_1100085',
+ },
+ {
+ # Linux: Fix ATK assertion error when generating ARM build config.
+ # https://bugs.chromium.org/p/chromium/issues/detail?id=1123214
+ 'name': 'linux_atk_1123214',
+ },
+ {
+ # Windows: Fix crash when |sandbox_info| parameter is nullptr.
+ # https://github.com/chromiumembedded/cef/issues/3210
+ 'name': 'win_sandbox_3210',
+ },
+ {
+ # Windows: Always use the root window as the owner for shell dialogs.
+ # https://github.com/chromiumembedded/cef/issues/3294
+ 'name': 'win_shell_dialogs_3294',
+ },
+ {
+ # Linux: Fix duplicate symbol error due to bluez/metrics_recorder.cc.
+ # https://bugs.chromium.org/p/chromium/issues/detail?id=1319006
+ 'name': 'linux_bluetooth_1319006',
+ },
+ {
+ # Linux: Support chaining of PrintingContextLinux callbacks.
+ # https://github.com/chromiumembedded/cef/issues/3314
+ # Also reverts the changes from https://crrev.com/db245883e1
+ 'name': 'linux_printing_context',
+ },
+ {
+ # Fix deadlock in EmbeddedTestServer::ShutdownAndWaitUntilComplete.
+ # https://chromium-review.googlesource.com/c/chromium/src/+/3798752
+ 'name': 'net_test_server_3798752'
+ },
+ {
+ # Linux: Fix "error: use of result of assignment to object of volatile-
+ # qualified type 'volatile gsize' (aka 'volatile unsigned long') is
+ # deprecated [-Werror,-Wdeprecated-volatile]" when building with
+ # use_sysroot=false on Ubuntu 18.04.
+ # https://chromium-review.googlesource.com/c/chromium/src/+/3960017
+ 'name': 'linux_glib_deprecated_volatile'
+ },
+ {
+ # Specify an output name for the pdfium build component to fix PDF
+ # loading with component build.
+ # https://pdfium-review.googlesource.com/c/pdfium/+/103501
+ 'name': 'pdfium_103501',
+ 'path': 'third_party/pdfium'
+ },
+ {
+ # Windows: Fix cef_sandbox compile error related to unsafe narrowing.
+ # https://chromium-review.googlesource.com/c/chromium/src/+/4219163
+ 'name': 'win_power_monitor_4219163'
+ }
+]
diff --git a/patch/patches/base_command_line_1872.patch b/patch/patches/base_command_line_1872.patch
new file mode 100644
index 00000000..3532b8d1
--- /dev/null
+++ b/patch/patches/base_command_line_1872.patch
@@ -0,0 +1,17 @@
+diff --git base/command_line.cc base/command_line.cc
+index ae845dcf3972a..a6fc08d159b74 100644
+--- base/command_line.cc
++++ base/command_line.cc
+@@ -339,11 +339,10 @@ void CommandLine::AppendSwitchPath(StringPiece switch_string,
+
+ void CommandLine::AppendSwitchNative(StringPiece switch_string,
+ CommandLine::StringPieceType value) {
+-#if BUILDFLAG(IS_WIN)
+ const std::string switch_key = ToLowerASCII(switch_string);
++#if BUILDFLAG(IS_WIN)
+ StringType combined_switch_string(UTF8ToWide(switch_key));
+ #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
+- StringPiece switch_key = switch_string;
+ StringType combined_switch_string(switch_key);
+ #endif
+ size_t prefix_length = GetSwitchPrefixLength(combined_switch_string);
diff --git a/patch/patches/base_sandbox_2743.patch b/patch/patches/base_sandbox_2743.patch
new file mode 100644
index 00000000..d58b3134
--- /dev/null
+++ b/patch/patches/base_sandbox_2743.patch
@@ -0,0 +1,229 @@
+diff --git base/BUILD.gn base/BUILD.gn
+index 1f0e5cc5f0fae..6f2003a67c9ce 100644
+--- base/BUILD.gn
++++ base/BUILD.gn
+@@ -39,6 +39,7 @@ import("//build/config/ui.gni")
+ import("//build/nocompile.gni")
+ import("//build/timestamp.gni")
+ import("//build_overrides/build.gni")
++import("//cef/libcef/features/features.gni")
+ import("//testing/libfuzzer/fuzzer_test.gni")
+ import("//testing/test.gni")
+
+@@ -1960,7 +1961,11 @@ component("base") {
+ "hash/md5_constexpr_internal.h",
+ "hash/sha1.h",
+ ]
+- if (is_nacl) {
++ deps += [ "//cef/libcef/features" ]
++ if (enable_cef) {
++ configs += [ "//cef/libcef/features:config" ]
++ }
++ if (is_nacl || is_cef_sandbox_build) {
+ sources += [
+ "hash/md5_nacl.cc",
+ "hash/md5_nacl.h",
+@@ -2104,6 +2109,12 @@ component("base") {
+ defines += [ "COM_INIT_CHECK_HOOK_DISABLED" ]
+ }
+
++ if (!use_custom_libcxx) {
++ # Enable the VS 2015 Update 2 fix when building with the MSVC standard
++ # library.
++ defines += [ "_ENABLE_ATOMIC_ALIGNMENT_FIX" ]
++ }
++
+ libs += [
+ "cfgmgr32.lib",
+ "powrprof.lib",
+diff --git base/allocator/dispatcher/dispatcher.cc base/allocator/dispatcher/dispatcher.cc
+index fd6e8a1696c94..df996398c1e78 100644
+--- base/allocator/dispatcher/dispatcher.cc
++++ base/allocator/dispatcher/dispatcher.cc
+@@ -13,6 +13,7 @@
+ #include "base/dcheck_is_on.h"
+ #include "base/no_destructor.h"
+ #include "base/sampling_heap_profiler/poisson_allocation_sampler.h"
++#include "cef/libcef/features/features.h"
+
+ #if DCHECK_IS_ON()
+ #include <atomic>
+@@ -259,7 +260,7 @@ struct Dispatcher::Impl {
+ }
+
+ void Reset() {
+-#if DCHECK_IS_ON()
++#if DCHECK_IS_ON() && !BUILDFLAG(IS_CEF_SANDBOX_BUILD)
+ DCHECK([&]() {
+ auto const was_set = is_initialized_check_flag_.test_and_set();
+ is_initialized_check_flag_.clear();
+diff --git base/hash/md5.h base/hash/md5.h
+index aa889f350e8f7..50acac8a69225 100644
+--- base/hash/md5.h
++++ base/hash/md5.h
+@@ -10,8 +10,9 @@
+ #include "base/base_export.h"
+ #include "base/strings/string_piece.h"
+ #include "build/build_config.h"
++#include "cef/libcef/features/features.h"
+
+-#if BUILDFLAG(IS_NACL)
++#if BUILDFLAG(IS_NACL) || BUILDFLAG(IS_CEF_SANDBOX_BUILD)
+ #include "base/hash/md5_nacl.h"
+ #else
+ #include "base/hash/md5_boringssl.h"
+diff --git base/hash/sha1.h base/hash/sha1.h
+index 29626e5853c6e..2fb1c61504c5d 100644
+--- base/hash/sha1.h
++++ base/hash/sha1.h
+@@ -14,7 +14,9 @@
+ #include "base/containers/span.h"
+ #include "base/strings/string_piece.h"
+ #include "build/build_config.h"
+-#if BUILDFLAG(IS_NACL)
++#include "cef/libcef/features/features.h"
++
++#if BUILDFLAG(IS_NACL) || BUILDFLAG(IS_CEF_SANDBOX_BUILD)
+ #include "base/hash/sha1_nacl.h"
+ #else
+ #include "base/hash/sha1_boringssl.h"
+diff --git base/rand_util.h base/rand_util.h
+index 04024537ee698..59864cb084559 100644
+--- base/rand_util.h
++++ base/rand_util.h
+@@ -15,8 +15,9 @@
+ #include "base/compiler_specific.h"
+ #include "base/gtest_prod_util.h"
+ #include "build/build_config.h"
++#include "cef/libcef/features/features.h"
+
+-#if !BUILDFLAG(IS_NACL)
++#if !BUILDFLAG(IS_NACL) && !BUILDFLAG(IS_CEF_SANDBOX_BUILD)
+ #include "third_party/boringssl/src/include/openssl/rand.h"
+ #endif
+
+@@ -93,7 +94,7 @@ class RandomBitGenerator {
+ ~RandomBitGenerator() = default;
+ };
+
+-#if !BUILDFLAG(IS_NACL)
++#if !BUILDFLAG(IS_NACL) && !BUILDFLAG(IS_CEF_SANDBOX_BUILD)
+ class NonAllocatingRandomBitGenerator {
+ public:
+ using result_type = uint64_t;
+diff --git base/rand_util_win.cc base/rand_util_win.cc
+index 2d9a1633b564f..d304c204c43ff 100644
+--- base/rand_util_win.cc
++++ base/rand_util_win.cc
+@@ -21,14 +21,19 @@
+ #include <limits>
+
+ #include "base/check.h"
++#include "cef/libcef/features/features.h"
++
++#if !BUILDFLAG(IS_CEF_SANDBOX_BUILD)
+ #include "base/feature_list.h"
+ #include "third_party/boringssl/src/include/openssl/crypto.h"
+ #include "third_party/boringssl/src/include/openssl/rand.h"
++#endif
+
+ namespace base {
+
+ namespace internal {
+
++#if !BUILDFLAG(IS_CEF_SANDBOX_BUILD)
+ namespace {
+
+ // The BoringSSl helpers are duplicated in rand_util_fuchsia.cc and
+@@ -50,11 +55,16 @@ bool UseBoringSSLForRandBytes() {
+ return g_use_boringssl.load(std::memory_order_relaxed);
+ }
+
++#else // !BUILDFLAG(IS_CEF_SANDBOX_BUILD)
++void ConfigureBoringSSLBackedRandBytesFieldTrial() {}
++#endif
++
+ } // namespace internal
+
+ namespace {
+
+ void RandBytes(void* output, size_t output_length, bool avoid_allocation) {
++#if !BUILDFLAG(IS_CEF_SANDBOX_BUILD)
+ if (!avoid_allocation && internal::UseBoringSSLForRandBytes()) {
+ // Ensure BoringSSL is initialized so it can use things like RDRAND.
+ CRYPTO_library_init();
+@@ -62,6 +72,7 @@ void RandBytes(void* output, size_t output_length, bool avoid_allocation) {
+ (void)RAND_bytes(static_cast<uint8_t*>(output), output_length);
+ return;
+ }
++#endif // !BUILDFLAG(IS_CEF_SANDBOX_BUILD)
+
+ char* output_ptr = static_cast<char*>(output);
+ while (output_length > 0) {
+diff --git base/unguessable_token.cc base/unguessable_token.cc
+index aa7423f88d278..1b2c7d3e3c4a0 100644
+--- base/unguessable_token.cc
++++ base/unguessable_token.cc
+@@ -10,8 +10,9 @@
+ #include "base/format_macros.h"
+ #include "base/rand_util.h"
+ #include "build/build_config.h"
++#include "cef/libcef/features/features.h"
+
+-#if !BUILDFLAG(IS_NACL)
++#if !BUILDFLAG(IS_NACL) && !BUILDFLAG(IS_CEF_SANDBOX_BUILD)
+ #include "third_party/boringssl/src/include/openssl/mem.h"
+ #endif
+
+@@ -46,7 +47,7 @@ absl::optional<UnguessableToken> UnguessableToken::Deserialize(uint64_t high,
+ }
+
+ bool UnguessableToken::operator==(const UnguessableToken& other) const {
+-#if BUILDFLAG(IS_NACL)
++#if BUILDFLAG(IS_NACL) || BUILDFLAG(IS_CEF_SANDBOX_BUILD)
+ // BoringSSL is unavailable for NaCl builds so it remains timing dependent.
+ return token_ == other.token_;
+ #else
+diff --git base/win/sid.cc base/win/sid.cc
+index 50a120166f08a..dc7da1949b6b1 100644
+--- base/win/sid.cc
++++ base/win/sid.cc
+@@ -16,14 +16,19 @@
+ #include <utility>
+
+ #include "base/check.h"
++#include "base/notreached.h"
+ #include "base/no_destructor.h"
+ #include "base/rand_util.h"
+ #include "base/strings/string_util_win.h"
+ #include "base/win/scoped_handle.h"
+ #include "base/win/scoped_localalloc.h"
+ #include "base/win/windows_version.h"
++#include "cef/libcef/features/features.h"
++
++#if !BUILDFLAG(IS_CEF_SANDBOX_BUILD)
+ #include "third_party/boringssl/src/include/openssl/crypto.h"
+ #include "third_party/boringssl/src/include/openssl/sha.h"
++#endif
+
+ namespace base::win {
+
+@@ -124,6 +129,7 @@ Sid Sid::FromNamedCapability(const std::wstring& capability_name) {
+ if (known_cap != known_capabilities->end()) {
+ return FromKnownCapability(known_cap->second);
+ }
++#if !BUILDFLAG(IS_CEF_SANDBOX_BUILD)
+ CRYPTO_library_init();
+ static_assert((SHA256_DIGEST_LENGTH / sizeof(DWORD)) ==
+ SECURITY_APP_PACKAGE_RID_COUNT);
+@@ -136,6 +142,10 @@ Sid Sid::FromNamedCapability(const std::wstring& capability_name) {
+ reinterpret_cast<uint8_t*>(&rids[2]));
+ return FromSubAuthorities(SECURITY_APP_PACKAGE_AUTHORITY, std::size(rids),
+ rids);
++#else
++ NOTREACHED();
++ return Sid(WellKnownSid::kNull);
++#endif
+ }
+
+ Sid Sid::FromKnownSid(WellKnownSid type) {
diff --git a/patch/patches/browser_scheduler.patch b/patch/patches/browser_scheduler.patch
new file mode 100644
index 00000000..9208ee61
--- /dev/null
+++ b/patch/patches/browser_scheduler.patch
@@ -0,0 +1,13 @@
+diff --git content/browser/scheduler/browser_task_executor.cc content/browser/scheduler/browser_task_executor.cc
+index 6006db1791a2a..81e7667183280 100644
+--- content/browser/scheduler/browser_task_executor.cc
++++ content/browser/scheduler/browser_task_executor.cc
+@@ -273,7 +273,7 @@ BrowserTaskExecutor::OnUserInputStart() {
+
+ // static
+ void BrowserTaskExecutor::Shutdown() {
+- if (!g_browser_task_executor)
++ if (!g_browser_task_executor || !g_browser_task_executor->ui_thread_executor_)
+ return;
+
+ DCHECK(Get()->ui_thread_executor_);
diff --git a/patch/patches/browser_security_policy_1081397.patch b/patch/patches/browser_security_policy_1081397.patch
new file mode 100644
index 00000000..e52f2c45
--- /dev/null
+++ b/patch/patches/browser_security_policy_1081397.patch
@@ -0,0 +1,65 @@
+diff --git content/browser/child_process_security_policy_impl.cc content/browser/child_process_security_policy_impl.cc
+index 4dbf8a2811c9e..917b6a2e7b56f 100644
+--- content/browser/child_process_security_policy_impl.cc
++++ content/browser/child_process_security_policy_impl.cc
+@@ -1800,6 +1800,16 @@ bool ChildProcessSecurityPolicyImpl::CanAccessDataForMaybeOpaqueOrigin(
+ // DeclarativeApiTest.PersistRules.
+ if (actual_process_lock.matches_scheme(url::kDataScheme))
+ return true;
++
++ // Allow other schemes that are non-standard, non-local and WebSafe.
++ if (lock_url.is_valid() &&
++ !lock_url.IsStandard() &&
++ !base::Contains(url::GetLocalSchemes(),
++ lock_url.scheme_piece()) &&
++ base::Contains(schemes_okay_to_request_in_any_process_,
++ lock_url.scheme())) {
++ return true;
++ }
+ }
+
+ // Make an exception to allow most visited tiles to commit in
+diff --git content/browser/renderer_host/navigation_request.cc content/browser/renderer_host/navigation_request.cc
+index 4b552797303b8..0e39c982b5803 100644
+--- content/browser/renderer_host/navigation_request.cc
++++ content/browser/renderer_host/navigation_request.cc
+@@ -6942,10 +6942,22 @@ NavigationRequest::GetOriginForURLLoaderFactoryBeforeResponseWithDebugInfo(
+ bool use_opaque_origin =
+ (sandbox_flags & network::mojom::WebSandboxFlags::kOrigin) ==
+ network::mojom::WebSandboxFlags::kOrigin;
++ if (use_opaque_origin) {
++ origin_and_debug_info.second += ", sandbox_flags";
++ }
++
++ if (!origin_and_debug_info.first.GetURL().IsStandard()) {
++ // Always return an opaque origin for non-standard URLs. Otherwise, the
++ // CanAccessDataForOrigin() check may fail for unregistered custom scheme
++ // requests in CEF.
++ use_opaque_origin = true;
++ origin_and_debug_info.second += ", cef_nonstandard";
++ }
++
+ if (use_opaque_origin) {
+ origin_and_debug_info =
+ std::make_pair(origin_and_debug_info.first.DeriveNewOpaqueOrigin(),
+- origin_and_debug_info.second + ", sandbox_flags");
++ origin_and_debug_info.second);
+ }
+
+ return origin_and_debug_info;
+@@ -6975,6 +6987,15 @@ NavigationRequest::GetOriginForURLLoaderFactoryAfterResponseWithDebugInfo() {
+ GetOriginForURLLoaderFactoryBeforeResponseWithDebugInfo(
+ SandboxFlagsToCommit());
+
++ if (origin_with_debug_info.first.opaque() &&
++ origin_with_debug_info.second.find("cef_nonstandard") !=
++ std::string::npos) {
++ // Always return an opaque origin for non-standard URLs. Otherwise, the
++ // below CanAccessDataForOrigin() check may fail for unregistered custom
++ // scheme requests in CEF.
++ return origin_with_debug_info;
++ }
++
+ // MHTML documents should commit as an opaque origin. They should not be able
+ // to make network request on behalf of the real origin.
+ DCHECK(!IsMhtmlOrSubframe() || origin_with_debug_info.first.opaque());
diff --git a/patch/patches/browser_web_ui_controller_factory.patch b/patch/patches/browser_web_ui_controller_factory.patch
new file mode 100644
index 00000000..7a5ca060
--- /dev/null
+++ b/patch/patches/browser_web_ui_controller_factory.patch
@@ -0,0 +1,29 @@
+diff --git content/public/browser/web_ui_controller_factory.h content/public/browser/web_ui_controller_factory.h
+index 9d9c17ffd6474..4eb79c65369af 100644
+--- content/public/browser/web_ui_controller_factory.h
++++ content/public/browser/web_ui_controller_factory.h
+@@ -47,9 +47,6 @@ class CONTENT_EXPORT WebUIControllerFactory {
+ virtual bool UseWebUIForURL(BrowserContext* browser_context,
+ const GURL& url) = 0;
+
+- private:
+- friend class ScopedWebUIControllerFactoryRegistration;
+-
+ static void UnregisterFactoryForTesting(WebUIControllerFactory* factory);
+ };
+
+diff --git content/public/browser/webui_config_map.h content/public/browser/webui_config_map.h
+index 19777632921fc..a22db4c49fd84 100644
+--- content/public/browser/webui_config_map.h
++++ content/public/browser/webui_config_map.h
+@@ -60,6 +60,10 @@ class CONTENT_EXPORT WebUIConfigMap {
+ // Returns the size of the map, i.e. how many WebUIConfigs are registered.
+ size_t GetSizeForTesting() { return configs_map_.size(); }
+
++ WebUIControllerFactory* controller_factory() const {
++ return webui_controller_factory_.get();
++ }
++
+ private:
+ void AddWebUIConfigImpl(std::unique_ptr<WebUIConfig> config);
+
diff --git a/patch/patches/build.patch b/patch/patches/build.patch
new file mode 100644
index 00000000..21191d2f
--- /dev/null
+++ b/patch/patches/build.patch
@@ -0,0 +1,13 @@
+diff --git build/config/compiler/BUILD.gn build/config/compiler/BUILD.gn
+index ef3285ae74e1b..c669380332eb9 100644
+--- build/config/compiler/BUILD.gn
++++ build/config/compiler/BUILD.gn
+@@ -1911,8 +1911,6 @@ config("thin_archive") {
+ # confuses lldb.
+ if ((is_posix && !is_nacl && !is_apple) || is_fuchsia) {
+ arflags = [ "-T" ]
+- } else if (is_win && use_lld) {
+- arflags = [ "/llvmlibthin" ]
+ }
+ }
+
diff --git a/patch/patches/chrome_browser.patch b/patch/patches/chrome_browser.patch
new file mode 100644
index 00000000..4f55eac9
--- /dev/null
+++ b/patch/patches/chrome_browser.patch
@@ -0,0 +1,40 @@
+diff --git chrome/browser/BUILD.gn chrome/browser/BUILD.gn
+index 42712ea4134e1..eee57ad898aa9 100644
+--- chrome/browser/BUILD.gn
++++ chrome/browser/BUILD.gn
+@@ -11,6 +11,7 @@ import("//build/config/compiler/pgo/pgo.gni")
+ import("//build/config/features.gni")
+ import("//build/config/python.gni")
+ import("//build/config/ui.gni")
++import("//cef/libcef/features/features.gni")
+ import("//chrome/browser/buildflags.gni")
+ import("//chrome/browser/downgrade/buildflags.gni")
+ import("//chrome/common/features.gni")
+@@ -1974,6 +1975,7 @@ static_library("browser") {
+ "//build/config/chromebox_for_meetings:buildflags",
+ "//build/config/compiler:compiler_buildflags",
+ "//cc",
++ "//cef/libcef/features",
+ "//chrome:extra_resources",
+ "//chrome:resources",
+ "//chrome:strings",
+@@ -2537,6 +2539,10 @@ static_library("browser") {
+ ]
+ }
+
++ if (enable_cef) {
++ configs += [ "//cef/libcef/features:config" ]
++ }
++
+ if (is_android) {
+ sources += [
+ "after_startup_task_utils_android.cc",
+@@ -6076,8 +6082,6 @@ static_library("browser") {
+ sources += [
+ "enterprise/chrome_browser_main_extra_parts_enterprise.cc",
+ "enterprise/chrome_browser_main_extra_parts_enterprise.h",
+- "enterprise/connectors/analysis/content_analysis_sdk_manager.cc",
+- "enterprise/connectors/analysis/content_analysis_sdk_manager.h",
+ "enterprise/connectors/analysis/local_binary_upload_service.cc",
+ "enterprise/connectors/analysis/local_binary_upload_service.h",
+ "enterprise/connectors/analysis/local_binary_upload_service_factory.cc",
diff --git a/patch/patches/chrome_browser_background_mode_1100085.patch b/patch/patches/chrome_browser_background_mode_1100085.patch
new file mode 100644
index 00000000..e5401222
--- /dev/null
+++ b/patch/patches/chrome_browser_background_mode_1100085.patch
@@ -0,0 +1,72 @@
+diff --git chrome/browser/browser_process.h chrome/browser/browser_process.h
+index fa9472796576e..3e6a71e1e9697 100644
+--- chrome/browser/browser_process.h
++++ chrome/browser/browser_process.h
+@@ -199,9 +199,9 @@ class BrowserProcess {
+ virtual DownloadStatusUpdater* download_status_updater() = 0;
+ virtual DownloadRequestLimiter* download_request_limiter() = 0;
+
++#if BUILDFLAG(ENABLE_BACKGROUND_MODE)
+ // Returns the object that manages background applications.
+ virtual BackgroundModeManager* background_mode_manager() = 0;
+-#if BUILDFLAG(ENABLE_BACKGROUND_MODE)
+ virtual void set_background_mode_manager_for_test(
+ std::unique_ptr<BackgroundModeManager> manager) = 0;
+ #endif
+diff --git chrome/browser/browser_process_impl.cc chrome/browser/browser_process_impl.cc
+index c559c9dee4da0..facb6dc88e2e1 100644
+--- chrome/browser/browser_process_impl.cc
++++ chrome/browser/browser_process_impl.cc
+@@ -1037,18 +1037,14 @@ DownloadRequestLimiter* BrowserProcessImpl::download_request_limiter() {
+ return download_request_limiter_.get();
+ }
+
+-BackgroundModeManager* BrowserProcessImpl::background_mode_manager() {
+ #if BUILDFLAG(ENABLE_BACKGROUND_MODE)
++BackgroundModeManager* BrowserProcessImpl::background_mode_manager() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ if (!background_mode_manager_)
+ CreateBackgroundModeManager();
+ return background_mode_manager_.get();
+-#else
+- return nullptr;
+-#endif
+ }
+
+-#if BUILDFLAG(ENABLE_BACKGROUND_MODE)
+ void BrowserProcessImpl::set_background_mode_manager_for_test(
+ std::unique_ptr<BackgroundModeManager> manager) {
+ background_mode_manager_ = std::move(manager);
+diff --git chrome/browser/browser_process_impl.h chrome/browser/browser_process_impl.h
+index c7fab534552b2..075f2e9cfdb66 100644
+--- chrome/browser/browser_process_impl.h
++++ chrome/browser/browser_process_impl.h
+@@ -174,8 +174,8 @@ class BrowserProcessImpl : public BrowserProcess,
+ void SetApplicationLocale(const std::string& actual_locale) override;
+ DownloadStatusUpdater* download_status_updater() override;
+ DownloadRequestLimiter* download_request_limiter() override;
+- BackgroundModeManager* background_mode_manager() override;
+ #if BUILDFLAG(ENABLE_BACKGROUND_MODE)
++ BackgroundModeManager* background_mode_manager() override;
+ void set_background_mode_manager_for_test(
+ std::unique_ptr<BackgroundModeManager> manager) override;
+ #endif
+diff --git chrome/browser/lifetime/browser_close_manager.cc chrome/browser/lifetime/browser_close_manager.cc
+index ac79a59ef056b..cac2b4d97271c 100644
+--- chrome/browser/lifetime/browser_close_manager.cc
++++ chrome/browser/lifetime/browser_close_manager.cc
+@@ -158,12 +158,14 @@ void BrowserCloseManager::CloseBrowsers() {
+ // exit can restore all browsers open before exiting.
+ ProfileManager::ShutdownSessionServices();
+ #endif
++#if BUILDFLAG(ENABLE_BACKGROUND_MODE)
+ if (!browser_shutdown::IsTryingToQuit()) {
+ BackgroundModeManager* background_mode_manager =
+ g_browser_process->background_mode_manager();
+ if (background_mode_manager)
+ background_mode_manager->SuspendBackgroundMode();
+ }
++#endif
+
+ // Make a copy of the BrowserList to simplify the case where we need to
+ // destroy a Browser during the loop.
diff --git a/patch/patches/chrome_browser_browser.patch b/patch/patches/chrome_browser_browser.patch
new file mode 100644
index 00000000..3b6ada53
--- /dev/null
+++ b/patch/patches/chrome_browser_browser.patch
@@ -0,0 +1,465 @@
+diff --git chrome/browser/browser_about_handler.cc chrome/browser/browser_about_handler.cc
+index 370d6ab102471..fe1e4111780ed 100644
+--- chrome/browser/browser_about_handler.cc
++++ chrome/browser/browser_about_handler.cc
+@@ -69,6 +69,9 @@ bool HandleNonNavigationAboutURL(const GURL& url) {
+ FROM_HERE, base::BindOnce(&chrome::AttemptExit));
+ return true;
+ }
++ if (base::EqualsCaseInsensitiveASCII(spec, "chrome://ignore/")) {
++ return true;
++ }
+
+ return false;
+ }
+diff --git chrome/browser/ui/BUILD.gn chrome/browser/ui/BUILD.gn
+index 03a6d3a2ee5e8..a19224279243c 100644
+--- chrome/browser/ui/BUILD.gn
++++ chrome/browser/ui/BUILD.gn
+@@ -9,6 +9,7 @@ import("//build/config/compiler/compiler.gni")
+ import("//build/config/features.gni")
+ import("//build/config/ozone.gni")
+ import("//build/config/ui.gni")
++import("//cef/libcef/features/features.gni")
+ import("//chrome/browser/buildflags.gni")
+ import("//chrome/common/features.gni")
+ import("//chromeos/ash/components/assistant/assistant.gni")
+@@ -361,6 +362,10 @@ static_library("ui") {
+ "//build/config/compiler:wexit_time_destructors",
+ ]
+
++ if (enable_cef) {
++ configs += [ "//cef/libcef/features:config" ]
++ }
++
+ # Since browser and browser_ui actually depend on each other,
+ # we must omit the dependency from browser_ui to browser.
+ # However, this means browser_ui and browser should more or less
+@@ -385,6 +390,7 @@ static_library("ui") {
+ "//build:chromeos_buildflags",
+ "//build/config/chromebox_for_meetings:buildflags",
+ "//cc/paint",
++ "//cef/libcef/features",
+ "//chrome:extra_resources",
+ "//chrome:resources",
+ "//chrome:strings",
+@@ -2527,6 +2533,8 @@ static_library("ui") {
+ "views/apps/app_dialog/app_block_dialog_view.h",
+ "views/apps/app_dialog/app_pause_dialog_view.cc",
+ "views/apps/app_dialog/app_pause_dialog_view.h",
++ "views/apps/app_dialog/app_uninstall_dialog_view.cc",
++ "views/apps/app_dialog/app_uninstall_dialog_view.h",
+ "views/apps/app_info_dialog/arc_app_info_links_panel.cc",
+ "views/apps/app_info_dialog/arc_app_info_links_panel.h",
+ "views/apps/chrome_app_window_client_views_chromeos.cc",
+@@ -4292,8 +4300,6 @@ static_library("ui") {
+ "views/accessibility/theme_tracking_non_accessible_image_view.h",
+ "views/apps/app_dialog/app_dialog_view.cc",
+ "views/apps/app_dialog/app_dialog_view.h",
+- "views/apps/app_dialog/app_uninstall_dialog_view.cc",
+- "views/apps/app_dialog/app_uninstall_dialog_view.h",
+ "views/apps/app_info_dialog/app_info_dialog_container.cc",
+ "views/apps/app_info_dialog/app_info_dialog_container.h",
+ "views/apps/app_info_dialog/app_info_dialog_views.cc",
+@@ -5799,6 +5805,7 @@ static_library("ui") {
+ if (enable_printing) {
+ deps += [
+ "//components/printing/browser",
++ "//components/printing/common:mojo_interfaces",
+ "//printing",
+ ]
+ }
+diff --git chrome/browser/ui/browser.cc chrome/browser/ui/browser.cc
+index 13a07ce16ad4f..66ae1d0afba7d 100644
+--- chrome/browser/ui/browser.cc
++++ chrome/browser/ui/browser.cc
+@@ -264,6 +264,25 @@
+ #include "components/captive_portal/content/captive_portal_tab_helper.h"
+ #endif
+
++#if BUILDFLAG(ENABLE_CEF)
++#define CALL_CEF_DELEGATE(name, ...) \
++ if (cef_browser_delegate_) { \
++ cef_browser_delegate_->name(__VA_ARGS__); \
++ }
++#define CALL_CEF_DELEGATE_RETURN(name, ...) \
++ if (cef_browser_delegate_) { \
++ return cef_browser_delegate_->name(__VA_ARGS__); \
++ }
++#define CALL_CEF_DELEGATE_RESULT(name, result, ...) \
++ if (cef_browser_delegate_) { \
++ result = cef_browser_delegate_->name(__VA_ARGS__); \
++ }
++#else // !BUILDFLAG(ENABLE_CEF)
++#define CALL_CEF_DELEGATE(name, ...)
++#define CALL_CEF_DELEGATE_RETURN(name, ...)
++#define CALL_CEF_DELEGATE_RESULT(name, result, ...)
++#endif
++
+ #if BUILDFLAG(ENABLE_EXTENSIONS)
+ #include "chrome/browser/extensions/extension_browser_window_helper.h"
+ #endif
+@@ -510,6 +529,13 @@ Browser::Browser(const CreateParams& params)
+
+ tab_strip_model_->AddObserver(this);
+
++#if BUILDFLAG(ENABLE_CEF)
++ if (cef::IsChromeRuntimeEnabled()) {
++ cef_browser_delegate_ =
++ cef::BrowserDelegate::Create(this, params.cef_params);
++ }
++#endif
++
+ location_bar_model_ = std::make_unique<LocationBarModelImpl>(
+ location_bar_model_delegate_.get(), content::kMaxURLDisplayChars);
+
+@@ -649,6 +675,12 @@ Browser::~Browser() {
+ // away so they don't try and call back to us.
+ if (select_file_dialog_.get())
+ select_file_dialog_->ListenerDestroyed();
++
++ // Clean up any objects attached via UserData before implicit destruction
++ // of CreateParams. Destruction of those objects may call into something
++ // (ProfileImpl, PrefService, etc) that will be destroyed when the last
++ // CefRequestContextImpl reference (held by CreateParams) is released.
++ ClearAllUserData();
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////
+@@ -1358,6 +1390,14 @@ content::KeyboardEventProcessingResult Browser::PreHandleKeyboardEvent(
+ if (exclusive_access_manager_->HandleUserKeyEvent(event))
+ return content::KeyboardEventProcessingResult::HANDLED;
+
++#if BUILDFLAG(ENABLE_CEF)
++ if (cef_browser_delegate_) {
++ auto result = cef_browser_delegate_->PreHandleKeyboardEvent(source, event);
++ if (result != content::KeyboardEventProcessingResult::NOT_HANDLED)
++ return result;
++ }
++#endif
++
+ return window()->PreHandleKeyboardEvent(event);
+ }
+
+@@ -1365,8 +1405,18 @@ bool Browser::HandleKeyboardEvent(content::WebContents* source,
+ const NativeWebKeyboardEvent& event) {
+ DevToolsWindow* devtools_window =
+ DevToolsWindow::GetInstanceForInspectedWebContents(source);
+- return (devtools_window && devtools_window->ForwardKeyboardEvent(event)) ||
+- window()->HandleKeyboardEvent(event);
++ if (devtools_window && devtools_window->ForwardKeyboardEvent(event)) {
++ return true;
++ }
++
++#if BUILDFLAG(ENABLE_CEF)
++ if (cef_browser_delegate_ &&
++ cef_browser_delegate_->HandleKeyboardEvent(source, event)) {
++ return true;
++ }
++#endif
++
++ return window()->HandleKeyboardEvent(event);
+ }
+
+ bool Browser::TabsNeedBeforeUnloadFired() {
+@@ -1574,6 +1624,14 @@ WebContents* Browser::OpenURLFromTab(WebContents* source,
+ return window->OpenURLFromTab(source, params);
+ }
+
++#if BUILDFLAG(ENABLE_CEF)
++ if (cef_browser_delegate_) {
++ auto web_contents = cef_browser_delegate_->OpenURLFromTab(source, params);
++ if (!web_contents)
++ return nullptr;
++ }
++#endif
++
+ NavigateParams nav_params(this, params.url, params.transition);
+ nav_params.FillNavigateParamsFromOpenURLParams(params);
+ nav_params.source_contents = source;
+@@ -1729,6 +1787,8 @@ void Browser::LoadingStateChanged(WebContents* source,
+ bool should_show_loading_ui) {
+ ScheduleUIUpdate(source, content::INVALIDATE_TYPE_LOAD);
+ UpdateWindowForLoadingStateChanged(source, should_show_loading_ui);
++
++ CALL_CEF_DELEGATE(LoadingStateChanged, source, should_show_loading_ui);
+ }
+
+ void Browser::CloseContents(WebContents* source) {
+@@ -1756,6 +1816,8 @@ void Browser::SetContentsBounds(WebContents* source, const gfx::Rect& bounds) {
+ }
+
+ void Browser::UpdateTargetURL(WebContents* source, const GURL& url) {
++ CALL_CEF_DELEGATE(UpdateTargetURL, source, url);
++
+ if (!GetStatusBubble())
+ return;
+
+@@ -1763,6 +1825,17 @@ void Browser::UpdateTargetURL(WebContents* source, const GURL& url) {
+ GetStatusBubble()->SetURL(url);
+ }
+
++bool Browser::DidAddMessageToConsole(
++ content::WebContents* source,
++ blink::mojom::ConsoleMessageLevel log_level,
++ const std::u16string& message,
++ int32_t line_no,
++ const std::u16string& source_id) {
++ CALL_CEF_DELEGATE_RETURN(DidAddMessageToConsole, source, log_level, message,
++ line_no, source_id);
++ return false;
++}
++
+ void Browser::ContentsMouseEvent(WebContents* source,
+ bool motion,
+ bool exited) {
+@@ -1787,6 +1860,19 @@ bool Browser::TakeFocus(content::WebContents* source, bool reverse) {
+ return false;
+ }
+
++void Browser::CanDownload(const GURL& url,
++ const std::string& request_method,
++ base::OnceCallback<void(bool)> callback) {
++#if BUILDFLAG(ENABLE_CEF)
++ if (cef_browser_delegate_) {
++ cef_browser_delegate_->CanDownload(url, request_method,
++ std::move(callback));
++ return;
++ }
++#endif
++ std::move(callback).Run(true);
++}
++
+ void Browser::BeforeUnloadFired(WebContents* web_contents,
+ bool proceed,
+ bool* proceed_to_fire_unload) {
+@@ -1879,6 +1965,10 @@ void Browser::WebContentsCreated(WebContents* source_contents,
+
+ // Make the tab show up in the task manager.
+ task_manager::WebContentsTags::CreateForTabContents(new_contents);
++
++ CALL_CEF_DELEGATE(WebContentsCreated, source_contents,
++ opener_render_process_id, opener_render_frame_id,
++ frame_name, target_url, new_contents);
+ }
+
+ void Browser::PortalWebContentsCreated(WebContents* portal_web_contents) {
+@@ -1990,11 +2080,15 @@ void Browser::EnterFullscreenModeForTab(
+ const blink::mojom::FullscreenOptions& options) {
+ exclusive_access_manager_->fullscreen_controller()->EnterFullscreenModeForTab(
+ requesting_frame, options.display_id);
++
++ CALL_CEF_DELEGATE(EnterFullscreenModeForTab, requesting_frame, options);
+ }
+
+ void Browser::ExitFullscreenModeForTab(WebContents* web_contents) {
+ exclusive_access_manager_->fullscreen_controller()->ExitFullscreenModeForTab(
+ web_contents);
++
++ CALL_CEF_DELEGATE(ExitFullscreenModeForTab, web_contents);
+ }
+
+ bool Browser::IsFullscreenForTabOrPending(const WebContents* web_contents) {
+@@ -2188,6 +2282,15 @@ void Browser::RequestMediaAccessPermission(
+ content::WebContents* web_contents,
+ const content::MediaStreamRequest& request,
+ content::MediaResponseCallback callback) {
++#if BUILDFLAG(ENABLE_CEF)
++ if (cef_browser_delegate_) {
++ callback = cef_browser_delegate_->RequestMediaAccessPermissionEx(
++ web_contents, request, std::move(callback));
++ if (callback.is_null())
++ return;
++ }
++#endif
++
+ const extensions::Extension* extension =
+ GetExtensionForOrigin(profile_, request.security_origin);
+ MediaCaptureDevicesDispatcher::GetInstance()->ProcessMediaAccessRequest(
+@@ -2724,13 +2827,20 @@ void Browser::RemoveScheduledUpdatesFor(WebContents* contents) {
+ // Browser, Getters for UI (private):
+
+ StatusBubble* Browser::GetStatusBubble() {
++ bool show_by_default = true;
++
+ // In web apps, and in kiosk and exclusive app mode we want to always hide the
+ // status bubble.
+ if (chrome::IsRunningInAppMode() ||
+ web_app::AppBrowserController::IsWebApp(this)) {
+- return nullptr;
++ show_by_default = false;
+ }
+
++ bool show = show_by_default;
++ CALL_CEF_DELEGATE_RESULT(ShowStatusBubble, show, show_by_default);
++ if (!show)
++ return nullptr;
++
+ return window_ ? window_->GetStatusBubble() : nullptr;
+ }
+
+@@ -2862,6 +2972,8 @@ void Browser::SetAsDelegate(WebContents* web_contents, bool set_delegate) {
+ BookmarkTabHelper::FromWebContents(web_contents)->RemoveObserver(this);
+ web_contents_collection_.StopObserving(web_contents);
+ }
++
++ CALL_CEF_DELEGATE(SetAsDelegate, web_contents, set_delegate);
+ }
+
+ void Browser::TabDetachedAtImpl(content::WebContents* contents,
+diff --git chrome/browser/ui/browser.h chrome/browser/ui/browser.h
+index 10105dd979aa4..9277cd507ae8e 100644
+--- chrome/browser/ui/browser.h
++++ chrome/browser/ui/browser.h
+@@ -22,6 +22,7 @@
+ #include "base/timer/elapsed_timer.h"
+ #include "build/build_config.h"
+ #include "build/chromeos_buildflags.h"
++#include "cef/libcef/features/runtime.h"
+ #include "chrome/browser/tab_contents/web_contents_collection.h"
+ #include "chrome/browser/themes/theme_service_observer.h"
+ #include "chrome/browser/ui/bookmarks/bookmark_bar.h"
+@@ -48,6 +49,10 @@
+ #include "ui/gfx/geometry/rect.h"
+ #include "ui/shell_dialogs/select_file_dialog.h"
+
++#if BUILDFLAG(ENABLE_CEF)
++#include "cef/libcef/browser/chrome/browser_delegate.h"
++#endif
++
+ #if BUILDFLAG(IS_ANDROID)
+ #error This file should only be included on desktop.
+ #endif
+@@ -315,6 +320,11 @@ class Browser : public TabStripModelObserver,
+ double initial_aspect_ratio = 1.0;
+ bool lock_aspect_ratio = false;
+
++#if BUILDFLAG(ENABLE_CEF)
++ // Opaque CEF-specific configuration. Will be propagated to new Browsers.
++ scoped_refptr<cef::BrowserDelegate::CreateParams> cef_params;
++#endif
++
+ private:
+ friend class Browser;
+ friend class WindowSizerChromeOSTest;
+@@ -390,6 +400,13 @@ class Browser : public TabStripModelObserver,
+ force_skip_warning_user_on_close_ = force_skip_warning_user_on_close;
+ }
+
++ // Return true if CEF will expose the toolbar to the client. This value is
++ // used to selectively enable toolbar behaviors such as command processing
++ // and omnibox focus without also including the toolbar in BrowserView layout
++ // calculations.
++ void set_toolbar_overridden(bool val) { toolbar_overridden_ = val; }
++ bool toolbar_overridden() const { return toolbar_overridden_; }
++
+ // Accessors ////////////////////////////////////////////////////////////////
+
+ const CreateParams& create_params() const { return create_params_; }
+@@ -463,6 +480,12 @@ class Browser : public TabStripModelObserver,
+
+ base::WeakPtr<Browser> AsWeakPtr();
+
++#if BUILDFLAG(ENABLE_CEF)
++ cef::BrowserDelegate* cef_delegate() const {
++ return cef_browser_delegate_.get();
++ }
++#endif
++
+ // Get the FindBarController for this browser, creating it if it does not
+ // yet exist.
+ FindBarController* GetFindBarController();
+@@ -839,11 +862,19 @@ class Browser : public TabStripModelObserver,
+ void SetContentsBounds(content::WebContents* source,
+ const gfx::Rect& bounds) override;
+ void UpdateTargetURL(content::WebContents* source, const GURL& url) override;
++ bool DidAddMessageToConsole(content::WebContents* source,
++ blink::mojom::ConsoleMessageLevel log_level,
++ const std::u16string& message,
++ int32_t line_no,
++ const std::u16string& source_id) override;
+ void ContentsMouseEvent(content::WebContents* source,
+ bool motion,
+ bool exited) override;
+ void ContentsZoomChange(bool zoom_in) override;
+ bool TakeFocus(content::WebContents* source, bool reverse) override;
++ void CanDownload(const GURL& url,
++ const std::string& request_method,
++ base::OnceCallback<void(bool)> callback) override;
+ void BeforeUnloadFired(content::WebContents* source,
+ bool proceed,
+ bool* proceed_to_fire_unload) override;
+@@ -1248,6 +1279,8 @@ class Browser : public TabStripModelObserver,
+ const std::string initial_workspace_;
+ bool initial_visible_on_all_workspaces_state_;
+
++ bool toolbar_overridden_ = false;
++
+ CreationSource creation_source_ = CreationSource::kUnknown;
+
+ UnloadController unload_controller_;
+@@ -1312,6 +1345,10 @@ class Browser : public TabStripModelObserver,
+ extension_browser_window_helper_;
+ #endif
+
++#if BUILDFLAG(ENABLE_CEF)
++ std::unique_ptr<cef::BrowserDelegate> cef_browser_delegate_;
++#endif
++
+ const base::ElapsedTimer creation_timer_;
+
+ // The opener browser of the document picture-in-picture browser. Null if the
+diff --git chrome/browser/ui/browser_navigator.cc chrome/browser/ui/browser_navigator.cc
+index dda3f5ba7f9a3..67b0eaaddfd3b 100644
+--- chrome/browser/ui/browser_navigator.cc
++++ chrome/browser/ui/browser_navigator.cc
+@@ -534,6 +534,13 @@ std::unique_ptr<content::WebContents> CreateTargetContents(
+ std::unique_ptr<WebContents> target_contents =
+ WebContents::Create(create_params);
+
++#if BUILDFLAG(ENABLE_CEF)
++ auto cef_delegate = params.browser->cef_delegate();
++ if (cef_delegate) {
++ cef_delegate->OnWebContentsCreated(target_contents.get());
++ }
++#endif
++
+ // New tabs can have WebUI URLs that will make calls back to arbitrary
+ // tab helpers, so the entire set of tab helpers needs to be set up
+ // immediately.
+diff --git chrome/browser/ui/browser_tabstrip.cc chrome/browser/ui/browser_tabstrip.cc
+index a3dbf97b6f943..799a64e17fca5 100644
+--- chrome/browser/ui/browser_tabstrip.cc
++++ chrome/browser/ui/browser_tabstrip.cc
+@@ -33,9 +33,13 @@ void AddTabAt(Browser* browser,
+ // Time new tab page creation time. We keep track of the timing data in
+ // WebContents, but we want to include the time it takes to create the
+ // WebContents object too.
++ // For CEF use a PageTransition that matches
++ // CefFrameHostImpl::kPageTransitionExplicit.
+ base::TimeTicks new_tab_start_time = base::TimeTicks::Now();
+ NavigateParams params(browser, url.is_empty() ? browser->GetNewTabURL() : url,
+- ui::PAGE_TRANSITION_TYPED);
++ static_cast<ui::PageTransition>(
++ ui::PAGE_TRANSITION_TYPED |
++ ui::PAGE_TRANSITION_FROM_ADDRESS_BAR));
+ params.disposition = foreground ? WindowOpenDisposition::NEW_FOREGROUND_TAB
+ : WindowOpenDisposition::NEW_BACKGROUND_TAB;
+ params.tabstrip_index = idx;
+@@ -71,6 +75,16 @@ void AddWebContents(Browser* browser,
+ // Can't create a new contents for the current tab - invalid case.
+ DCHECK(disposition != WindowOpenDisposition::CURRENT_TAB);
+
++#if BUILDFLAG(ENABLE_CEF)
++ if (browser && browser->cef_delegate() && new_contents) {
++ new_contents = browser->cef_delegate()->AddWebContents(
++ std::move(new_contents));
++ if (!new_contents) {
++ return;
++ }
++ }
++#endif
++
+ NavigateParams params(browser, std::move(new_contents));
+ params.source_contents = source_contents;
+ params.url = target_url;
diff --git a/patch/patches/chrome_browser_content_settings.patch b/patch/patches/chrome_browser_content_settings.patch
new file mode 100644
index 00000000..d401611f
--- /dev/null
+++ b/patch/patches/chrome_browser_content_settings.patch
@@ -0,0 +1,70 @@
+diff --git chrome/browser/content_settings/host_content_settings_map_factory.cc chrome/browser/content_settings/host_content_settings_map_factory.cc
+index c8a0156b69cc3..6a6fac072143d 100644
+--- chrome/browser/content_settings/host_content_settings_map_factory.cc
++++ chrome/browser/content_settings/host_content_settings_map_factory.cc
+@@ -9,6 +9,7 @@
+ #include "base/feature_list.h"
+ #include "build/build_config.h"
+ #include "build/buildflag.h"
++#include "cef/libcef/features/runtime.h"
+ #include "chrome/browser/content_settings/one_time_geolocation_permission_provider.h"
+ #include "chrome/browser/permissions/last_tab_standing_tracker_factory.h"
+ #include "chrome/browser/profiles/off_the_record_profile_impl.h"
+@@ -22,6 +23,10 @@
+ #include "extensions/buildflags/buildflags.h"
+ #include "ui/webui/webui_allowlist_provider.h"
+
++#if BUILDFLAG(ENABLE_CEF)
++#include "cef/libcef/common/extensions/extensions_util.h"
++#endif
++
+ #if BUILDFLAG(ENABLE_EXTENSIONS)
+ #include "base/trace_event/trace_event.h"
+ #include "extensions/browser/api/content_settings/content_settings_custom_extension_provider.h"
+@@ -61,7 +66,13 @@ HostContentSettingsMapFactory::HostContentSettingsMapFactory()
+ DependsOn(TemplateURLServiceFactory::GetInstance());
+ #endif
+ #if BUILDFLAG(ENABLE_EXTENSIONS)
++#if BUILDFLAG(ENABLE_CEF)
++ if (!cef::IsAlloyRuntimeEnabled() || extensions::ExtensionsEnabled()) {
++#endif
+ DependsOn(extensions::ContentSettingsService::GetFactoryInstance());
++#if BUILDFLAG(ENABLE_CEF)
++ }
++#endif
+ #endif
+ // Used by way of ShouldRestoreOldSessionCookies().
+ #if BUILDFLAG(ENABLE_SESSION_SERVICE)
+@@ -135,6 +146,9 @@ scoped_refptr<RefcountedKeyedService>
+ }
+
+ #if BUILDFLAG(ENABLE_EXTENSIONS)
++#if BUILDFLAG(ENABLE_CEF)
++ if (!cef::IsAlloyRuntimeEnabled() || extensions::ExtensionsEnabled()) {
++#endif
+ // These must be registered before before the HostSettings are passed over to
+ // the IOThread. Simplest to do this on construction.
+ settings_map->RegisterProvider(
+@@ -147,6 +161,9 @@ scoped_refptr<RefcountedKeyedService>
+ // the case where profile->IsOffTheRecord() is true? And what is the
+ // interaction with profile->IsGuestSession()?
+ false));
++#if BUILDFLAG(ENABLE_CEF)
++ }
++#endif
+ #endif // BUILDFLAG(ENABLE_EXTENSIONS)
+ #if BUILDFLAG(ENABLE_SUPERVISED_USERS)
+ SupervisedUserSettingsService* supervised_service =
+diff --git components/content_settings/renderer/content_settings_agent_impl.cc components/content_settings/renderer/content_settings_agent_impl.cc
+index c65b17d8ee9e2..1c6e91858ba9e 100644
+--- components/content_settings/renderer/content_settings_agent_impl.cc
++++ components/content_settings/renderer/content_settings_agent_impl.cc
+@@ -144,7 +144,7 @@ ContentSetting GetContentSettingFromRules(
+ return rule.GetContentSetting();
+ }
+ }
+- NOTREACHED();
++ // NOTREACHED();
+ return CONTENT_SETTING_DEFAULT;
+ }
+ } // namespace
diff --git a/patch/patches/chrome_browser_context_menus.patch b/patch/patches/chrome_browser_context_menus.patch
new file mode 100644
index 00000000..352f9627
--- /dev/null
+++ b/patch/patches/chrome_browser_context_menus.patch
@@ -0,0 +1,194 @@
+diff --git chrome/browser/renderer_context_menu/render_view_context_menu.cc chrome/browser/renderer_context_menu/render_view_context_menu.cc
+index 320f0cbcd14f9..b199f7a33e6d1 100644
+--- chrome/browser/renderer_context_menu/render_view_context_menu.cc
++++ chrome/browser/renderer_context_menu/render_view_context_menu.cc
+@@ -313,6 +313,13 @@ base::OnceCallback<void(RenderViewContextMenu*)>* GetMenuShownCallback() {
+ return callback.get();
+ }
+
++
++RenderViewContextMenu::MenuCreatedCallback* GetMenuCreatedCallback() {
++ static base::NoDestructor<RenderViewContextMenu::MenuCreatedCallback>
++ callback;
++ return callback.get();
++}
++
+ enum class UmaEnumIdLookupType {
+ GeneralEnumId,
+ ContextSpecificEnumId,
+@@ -555,6 +562,10 @@ int FindUMAEnumValueForCommand(int id, UmaEnumIdLookupType type) {
+ if (ContextMenuMatcher::IsExtensionsCustomCommandId(id))
+ return 1;
+
++ // Match the MENU_ID_USER_FIRST to MENU_ID_USER_LAST range from cef_types.h.
++ if (id >= 26500 && id <= 28500)
++ return 1;
++
+ id = CollapseCommandsForUMA(id);
+ const auto& map = GetIdcToUmaMap(type);
+ auto it = map.find(id);
+@@ -756,6 +767,14 @@ RenderViewContextMenu::RenderViewContextMenu(
+ #if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
+ pdf_ocr_submenu_model_ = std::make_unique<ui::SimpleMenuModel>(this);
+ #endif // BUILDFLAG(ENABLE_SCREEN_AI_SERVICE)
++
++ auto* cb = GetMenuCreatedCallback();
++ if (!cb->is_null()) {
++ first_observer_ = cb->Run(this);
++ if (first_observer_) {
++ observers_.AddObserver(first_observer_.get());
++ }
++ }
+ }
+
+ RenderViewContextMenu::~RenderViewContextMenu() = default;
+@@ -1170,6 +1189,12 @@ void RenderViewContextMenu::InitMenu() {
+ // menu, meaning that each menu item added/removed in this function will cause
+ // it to visibly jump on the screen (see b/173569669).
+ AppendQuickAnswersItems();
++
++ if (first_observer_) {
++ // Do this last so that the observer can optionally modify previously
++ // created items.
++ first_observer_->InitMenu(params_);
++ }
+ }
+
+ Profile* RenderViewContextMenu::GetProfile() const {
+@@ -3050,6 +3075,12 @@ void RenderViewContextMenu::RegisterExecutePluginActionCallbackForTesting(
+ execute_plugin_action_callback_ = std::move(cb);
+ }
+
++// static
++void RenderViewContextMenu::RegisterMenuCreatedCallback(
++ MenuCreatedCallback cb) {
++ *GetMenuCreatedCallback() = cb;
++}
++
+ custom_handlers::ProtocolHandlerRegistry::ProtocolHandlerList
+ RenderViewContextMenu::GetHandlersForLinkUrl() {
+ custom_handlers::ProtocolHandlerRegistry::ProtocolHandlerList handlers =
+diff --git chrome/browser/renderer_context_menu/render_view_context_menu.h chrome/browser/renderer_context_menu/render_view_context_menu.h
+index f0c2e640e7373..5bf9f35335878 100644
+--- chrome/browser/renderer_context_menu/render_view_context_menu.h
++++ chrome/browser/renderer_context_menu/render_view_context_menu.h
+@@ -139,6 +139,12 @@ class RenderViewContextMenu
+ }
+ #endif
+
++ // Registers a callback that will be called each time a context menu is
++ // created.
++ using MenuCreatedCallback = base::RepeatingCallback<
++ std::unique_ptr<RenderViewContextMenuObserver>(RenderViewContextMenu*)>;
++ static void RegisterMenuCreatedCallback(MenuCreatedCallback cb);
++
+ protected:
+ Profile* GetProfile() const;
+
+@@ -386,6 +392,9 @@ class RenderViewContextMenu
+ // built.
+ bool is_protocol_submenu_valid_ = false;
+
++ // An observer returned via MenuCreatedCallback that will be called first.
++ std::unique_ptr<RenderViewContextMenuObserver> first_observer_;
++
+ // An observer that handles spelling suggestions, "Add to dictionary", and
+ // "Use enhanced spell check" items.
+ std::unique_ptr<SpellingMenuObserver> spelling_suggestions_menu_observer_;
+diff --git chrome/browser/ui/views/renderer_context_menu/render_view_context_menu_views.cc chrome/browser/ui/views/renderer_context_menu/render_view_context_menu_views.cc
+index ab018dd1ce675..1d80631a0c2ec 100644
+--- chrome/browser/ui/views/renderer_context_menu/render_view_context_menu_views.cc
++++ chrome/browser/ui/views/renderer_context_menu/render_view_context_menu_views.cc
+@@ -149,6 +149,9 @@ void RenderViewContextMenuViews::RunMenuAt(views::Widget* parent,
+ bool RenderViewContextMenuViews::GetAcceleratorForCommandId(
+ int command_id,
+ ui::Accelerator* accel) const {
++ if (RenderViewContextMenu::GetAcceleratorForCommandId(command_id, accel))
++ return true;
++
+ // There are no formally defined accelerators we can query so we assume
+ // that Ctrl+C, Ctrl+V, Ctrl+X, Ctrl-A, etc do what they normally do.
+ switch (command_id) {
+diff --git components/renderer_context_menu/render_view_context_menu_base.cc components/renderer_context_menu/render_view_context_menu_base.cc
+index 62142213ca3e9..f2187cadb6cdf 100644
+--- components/renderer_context_menu/render_view_context_menu_base.cc
++++ components/renderer_context_menu/render_view_context_menu_base.cc
+@@ -382,6 +382,17 @@ bool RenderViewContextMenuBase::IsCommandIdChecked(int id) const {
+ return false;
+ }
+
++bool RenderViewContextMenuBase::GetAcceleratorForCommandId(
++ int id,
++ ui::Accelerator* accelerator) const {
++ for (auto& observer : observers_) {
++ if (observer.IsCommandIdSupported(id))
++ return observer.GetAccelerator(id, accelerator);
++ }
++
++ return false;
++}
++
+ void RenderViewContextMenuBase::ExecuteCommand(int id, int event_flags) {
+ command_executed_ = true;
+ RecordUsedItem(id);
+diff --git components/renderer_context_menu/render_view_context_menu_base.h components/renderer_context_menu/render_view_context_menu_base.h
+index 8a555391c8712..3c54143ba61c3 100644
+--- components/renderer_context_menu/render_view_context_menu_base.h
++++ components/renderer_context_menu/render_view_context_menu_base.h
+@@ -86,6 +86,9 @@ class RenderViewContextMenuBase : public ui::SimpleMenuModel::Delegate,
+
+ const ui::SimpleMenuModel& menu_model() const { return menu_model_; }
+ const content::ContextMenuParams& params() const { return params_; }
++ content::WebContents* source_web_contents() const {
++ return source_web_contents_;
++ }
+
+ // Returns true if the specified command id is known and valid for
+ // this menu. If the command is known |enabled| is set to indicate
+@@ -94,6 +97,9 @@ class RenderViewContextMenuBase : public ui::SimpleMenuModel::Delegate,
+
+ // SimpleMenuModel::Delegate implementation.
+ bool IsCommandIdChecked(int command_id) const override;
++ bool GetAcceleratorForCommandId(
++ int command_id,
++ ui::Accelerator* accelerator) const override;
+ void ExecuteCommand(int command_id, int event_flags) override;
+ void OnMenuWillShow(ui::SimpleMenuModel* source) override;
+ void MenuClosed(ui::SimpleMenuModel* source) override;
+diff --git components/renderer_context_menu/render_view_context_menu_observer.cc components/renderer_context_menu/render_view_context_menu_observer.cc
+index 9fdda1636003d..538bd05a41296 100644
+--- components/renderer_context_menu/render_view_context_menu_observer.cc
++++ components/renderer_context_menu/render_view_context_menu_observer.cc
+@@ -15,3 +15,8 @@ bool RenderViewContextMenuObserver::IsCommandIdChecked(int command_id) {
+ bool RenderViewContextMenuObserver::IsCommandIdEnabled(int command_id) {
+ return false;
+ }
++
++bool RenderViewContextMenuObserver::GetAccelerator(int command_id,
++ ui::Accelerator* accel) {
++ return false;
++}
+diff --git components/renderer_context_menu/render_view_context_menu_observer.h components/renderer_context_menu/render_view_context_menu_observer.h
+index 0527c57abd51c..70bebcbb50461 100644
+--- components/renderer_context_menu/render_view_context_menu_observer.h
++++ components/renderer_context_menu/render_view_context_menu_observer.h
+@@ -11,6 +11,10 @@ namespace content {
+ struct ContextMenuParams;
+ }
+
++namespace ui {
++class Accelerator;
++}
++
+ // The interface used for implementing context-menu items. The following
+ // instruction describe how to implement a context-menu item with this
+ // interface.
+@@ -100,6 +104,8 @@ class RenderViewContextMenuObserver {
+ virtual bool IsCommandIdChecked(int command_id);
+ virtual bool IsCommandIdEnabled(int command_id);
+
++ virtual bool GetAccelerator(int command_id, ui::Accelerator* accel);
++
+ // Called when a user selects the specified context-menu item. This is
+ // only called when the observer returns true for IsCommandIdSupported()
+ // for that |command_id|.
diff --git a/patch/patches/chrome_browser_dialogs_native.patch b/patch/patches/chrome_browser_dialogs_native.patch
new file mode 100644
index 00000000..311c1f0e
--- /dev/null
+++ b/patch/patches/chrome_browser_dialogs_native.patch
@@ -0,0 +1,352 @@
+diff --git chrome/browser/file_select_helper.cc chrome/browser/file_select_helper.cc
+index 24b1b799392ce..be2d605ab8907 100644
+--- chrome/browser/file_select_helper.cc
++++ chrome/browser/file_select_helper.cc
+@@ -20,6 +20,7 @@
+ #include "base/threading/hang_watcher.h"
+ #include "build/build_config.h"
+ #include "build/chromeos_buildflags.h"
++#include "cef/libcef/features/runtime.h"
+ #include "chrome/browser/browser_process.h"
+ #include "chrome/browser/chromeos/policy/dlp/dlp_rules_manager.h"
+ #include "chrome/browser/chromeos/policy/dlp/dlp_rules_manager_factory.h"
+@@ -257,6 +258,13 @@ void FileSelectHelper::OnListFile(
+ void FileSelectHelper::LaunchConfirmationDialog(
+ const base::FilePath& path,
+ std::vector<ui::SelectedFileInfo> selected_files) {
++ if (cef::IsAlloyRuntimeEnabled() || run_from_cef_) {
++ // Don't show the upload confirmation dialog with the Alloy runtime, or
++ // when triggered via CEF (initially or recursively).
++ ConvertToFileChooserFileInfoList(selected_files);
++ return;
++ }
++
+ ShowFolderUploadConfirmationDialog(
+ path,
+ base::BindOnce(&FileSelectHelper::ConvertToFileChooserFileInfoList, this),
+@@ -341,6 +349,12 @@ void FileSelectHelper::PerformContentAnalysisIfNeeded(
+ if (AbortIfWebContentsDestroyed())
+ return;
+
++ // Don't trigger creation of a AccountConsistencyModeManager (see issue #3401)
++ if (cef::IsAlloyRuntimeEnabled()) {
++ NotifyListenerAndEnd(std::move(list));
++ return;
++ }
++
+ #if BUILDFLAG(FULL_SAFE_BROWSING)
+ enterprise_connectors::ContentAnalysisDelegate::Data data;
+ if (enterprise_connectors::ContentAnalysisDelegate::IsEnabled(
+@@ -529,7 +543,8 @@ bool FileSelectHelper::IsDirectoryEnumerationStartedForTesting() {
+
+ std::unique_ptr<ui::SelectFileDialog::FileTypeInfo>
+ FileSelectHelper::GetFileTypesFromAcceptType(
+- const std::vector<std::u16string>& accept_types) {
++ const std::vector<std::u16string>& accept_types,
++ bool run_from_cef) {
+ auto base_file_type = std::make_unique<ui::SelectFileDialog::FileTypeInfo>();
+ if (accept_types.empty())
+ return base_file_type;
+@@ -542,17 +557,24 @@ FileSelectHelper::GetFileTypesFromAcceptType(
+ std::vector<base::FilePath::StringType>* extensions =
+ &file_type->extensions.back();
+
++ // Create individual filters for each accept type.
++ std::vector<std::vector<base::FilePath::StringType>> all_extensions;
++ std::vector<std::u16string> all_overrides;
++
+ // Find the corresponding extensions.
+ int valid_type_count = 0;
+ int description_id = 0;
+ for (const auto& accept_type : accept_types) {
++ std::vector<base::FilePath::StringType> current_extensions;
++ description_id = 0;
++
+ size_t old_extension_size = extensions->size();
+ if (accept_type[0] == '.') {
+ // If the type starts with a period it is assumed to be a file extension
+ // so we just have to add it to the list.
+ base::FilePath::StringType ext =
+ base::FilePath::FromUTF16Unsafe(accept_type).value();
+- extensions->push_back(ext.substr(1));
++ current_extensions.push_back(ext.substr(1));
+ } else {
+ if (!base::IsStringASCII(accept_type))
+ continue;
+@@ -563,10 +585,18 @@ FileSelectHelper::GetFileTypesFromAcceptType(
+ description_id = IDS_AUDIO_FILES;
+ else if (ascii_type == "video/*")
+ description_id = IDS_VIDEO_FILES;
+-
+- net::GetExtensionsForMimeType(ascii_type, extensions);
++ net::GetExtensionsForMimeType(ascii_type, &current_extensions);
+ }
+
++ if (!current_extensions.empty()) {
++ all_extensions.push_back(current_extensions);
++ all_overrides.push_back(description_id != 0 ?
++ l10n_util::GetStringUTF16(description_id) :
++ std::u16string());
++
++ extensions->insert(extensions->end(), current_extensions.begin(),
++ current_extensions.end());
++ }
+ if (extensions->size() > old_extension_size)
+ valid_type_count++;
+ }
+@@ -591,6 +621,15 @@ FileSelectHelper::GetFileTypesFromAcceptType(
+ l10n_util::GetStringUTF16(description_id));
+ }
+
++ if (run_from_cef && all_extensions.size() > 1) {
++ // Insert filters for the specific accept types at the beginning.
++ file_type->extensions.insert(file_type->extensions.begin(),
++ all_extensions.begin(), all_extensions.end());
++ file_type->extension_description_overrides.insert(
++ file_type->extension_description_overrides.begin(),
++ all_overrides.begin(), all_overrides.end());
++ }
++
+ return file_type;
+ }
+
+@@ -598,7 +637,8 @@ FileSelectHelper::GetFileTypesFromAcceptType(
+ void FileSelectHelper::RunFileChooser(
+ content::RenderFrameHost* render_frame_host,
+ scoped_refptr<content::FileSelectListener> listener,
+- const FileChooserParams& params) {
++ const FileChooserParams& params,
++ bool run_from_cef) {
+ Profile* profile = Profile::FromBrowserContext(
+ render_frame_host->GetProcess()->GetBrowserContext());
+
+@@ -617,6 +657,7 @@ void FileSelectHelper::RunFileChooser(
+ // message.
+ scoped_refptr<FileSelectHelper> file_select_helper(
+ new FileSelectHelper(profile));
++ file_select_helper->run_from_cef_ = run_from_cef;
+ file_select_helper->RunFileChooser(render_frame_host, std::move(listener),
+ params.Clone());
+ }
+@@ -670,7 +711,8 @@ void FileSelectHelper::RunFileChooser(
+ }
+
+ void FileSelectHelper::GetFileTypesInThreadPool(FileChooserParamsPtr params) {
+- select_file_types_ = GetFileTypesFromAcceptType(params->accept_types);
++ select_file_types_ = GetFileTypesFromAcceptType(params->accept_types,
++ run_from_cef_);
+ select_file_types_->allowed_paths =
+ params->need_local_path ? ui::SelectFileDialog::FileTypeInfo::NATIVE_PATH
+ : ui::SelectFileDialog::FileTypeInfo::ANY_PATH;
+diff --git chrome/browser/file_select_helper.h chrome/browser/file_select_helper.h
+index d4b49202f61ce..4813ec70d9b1b 100644
+--- chrome/browser/file_select_helper.h
++++ chrome/browser/file_select_helper.h
+@@ -65,7 +65,8 @@ class FileSelectHelper : public base::RefCountedThreadSafe<
+ static void RunFileChooser(
+ content::RenderFrameHost* render_frame_host,
+ scoped_refptr<content::FileSelectListener> listener,
+- const blink::mojom::FileChooserParams& params);
++ const blink::mojom::FileChooserParams& params,
++ bool run_from_cef = false);
+
+ // Enumerates all the files in directory.
+ static void EnumerateDirectory(
+@@ -296,7 +297,8 @@ class FileSelectHelper : public base::RefCountedThreadSafe<
+ // |accept_types| contains only valid lowercased MIME types or file extensions
+ // beginning with a period (.).
+ static std::unique_ptr<ui::SelectFileDialog::FileTypeInfo>
+- GetFileTypesFromAcceptType(const std::vector<std::u16string>& accept_types);
++ GetFileTypesFromAcceptType(const std::vector<std::u16string>& accept_types,
++ bool run_from_cef);
+
+ // Check the accept type is valid. It is expected to be all lower case with
+ // no whitespace.
+@@ -361,6 +363,9 @@ class FileSelectHelper : public base::RefCountedThreadSafe<
+ // Set to false in unit tests since there is no WebContents.
+ bool abort_on_missing_web_contents_in_tests_ = true;
+
++ // Set to true if this dialog was triggered via CEF.
++ bool run_from_cef_ = false;
++
+ #if BUILDFLAG(IS_CHROMEOS_ASH)
+ base::WeakPtrFactory<FileSelectHelper> weak_ptr_factory_{this};
+ #endif // BUILDFLAG(IS_CHROMEOS_ASH)
+diff --git chrome/browser/ui/chrome_select_file_policy.h chrome/browser/ui/chrome_select_file_policy.h
+index 026f8ae631697..45b324fd3ae25 100644
+--- chrome/browser/ui/chrome_select_file_policy.h
++++ chrome/browser/ui/chrome_select_file_policy.h
+@@ -30,6 +30,8 @@ class ChromeSelectFilePolicy : public ui::SelectFilePolicy {
+ // Returns true if local state allows showing file pickers.
+ static bool FileSelectDialogsAllowed();
+
++ content::WebContents* source_contents() const { return source_contents_; }
++
+ private:
+ raw_ptr<content::WebContents, DanglingUntriaged> source_contents_;
+ };
+diff --git ui/shell_dialogs/execute_select_file_win.cc ui/shell_dialogs/execute_select_file_win.cc
+index 101e91826023b..35456ffad43f3 100644
+--- ui/shell_dialogs/execute_select_file_win.cc
++++ ui/shell_dialogs/execute_select_file_win.cc
+@@ -297,9 +297,7 @@ bool ExecuteSelectSingleFile(HWND owner,
+ const std::vector<FileFilterSpec>& filter,
+ int* filter_index,
+ std::vector<base::FilePath>* paths) {
+- // Note: The title is not passed down for historical reasons.
+- // TODO(pmonette): Figure out if it's a worthwhile improvement.
+- return RunOpenFileDialog(owner, std::u16string(), std::u16string(),
++ return RunOpenFileDialog(owner, title, std::u16string(),
+ default_path, filter, 0, filter_index, paths);
+ }
+
+@@ -311,14 +309,13 @@ bool ExecuteSelectMultipleFile(HWND owner,
+ std::vector<base::FilePath>* paths) {
+ DWORD dialog_options = FOS_ALLOWMULTISELECT;
+
+- // Note: The title is not passed down for historical reasons.
+- // TODO(pmonette): Figure out if it's a worthwhile improvement.
+- return RunOpenFileDialog(owner, std::u16string(), std::u16string(),
++ return RunOpenFileDialog(owner, title, std::u16string(),
+ default_path, filter, dialog_options, filter_index,
+ paths);
+ }
+
+ bool ExecuteSaveFile(HWND owner,
++ const std::u16string& title,
+ const base::FilePath& default_path,
+ const std::vector<FileFilterSpec>& filter,
+ const std::wstring& def_ext,
+@@ -331,9 +328,7 @@ bool ExecuteSaveFile(HWND owner,
+
+ DWORD dialog_options = FOS_OVERWRITEPROMPT;
+
+- // Note: The title is not passed down for historical reasons.
+- // TODO(pmonette): Figure out if it's a worthwhile improvement.
+- return RunSaveFileDialog(owner, std::u16string(), default_path, filter,
++ return RunSaveFileDialog(owner, title, default_path, filter,
+ dialog_options, def_ext, filter_index, path);
+ }
+
+@@ -358,7 +353,7 @@ void ExecuteSelectFile(
+ break;
+ case SelectFileDialog::SELECT_SAVEAS_FILE: {
+ base::FilePath path;
+- if (ExecuteSaveFile(owner, default_path, filter, default_extension,
++ if (ExecuteSaveFile(owner, title, default_path, filter, default_extension,
+ &file_type_index, &path)) {
+ paths.push_back(std::move(path));
+ }
+diff --git ui/shell_dialogs/select_file_dialog.cc ui/shell_dialogs/select_file_dialog.cc
+index 4a67edd5e5ea0..dfbfd166fc33a 100644
+--- ui/shell_dialogs/select_file_dialog.cc
++++ ui/shell_dialogs/select_file_dialog.cc
+@@ -87,8 +87,10 @@ void SelectFileDialog::SetFactory(ui::SelectFileDialogFactory* factory) {
+ // static
+ scoped_refptr<SelectFileDialog> SelectFileDialog::Create(
+ Listener* listener,
+- std::unique_ptr<ui::SelectFilePolicy> policy) {
+- if (dialog_factory_)
++ std::unique_ptr<ui::SelectFilePolicy> policy,
++ bool run_from_cef) {
++ // Avoid reentrancy of the CEF factory.
++ if (dialog_factory_ && (!run_from_cef || !dialog_factory_->IsCefFactory()))
+ return dialog_factory_->Create(listener, std::move(policy));
+ return CreateSelectFileDialog(listener, std::move(policy));
+ }
+diff --git ui/shell_dialogs/select_file_dialog.h ui/shell_dialogs/select_file_dialog.h
+index ab71dd6c559ef..71899846eab4e 100644
+--- ui/shell_dialogs/select_file_dialog.h
++++ ui/shell_dialogs/select_file_dialog.h
+@@ -113,7 +113,8 @@ class SHELL_DIALOGS_EXPORT SelectFileDialog
+ // is refcounted and uses a background thread.
+ static scoped_refptr<SelectFileDialog> Create(
+ Listener* listener,
+- std::unique_ptr<SelectFilePolicy> policy);
++ std::unique_ptr<SelectFilePolicy> policy,
++ bool run_from_cef = false);
+
+ SelectFileDialog(const SelectFileDialog&) = delete;
+ SelectFileDialog& operator=(const SelectFileDialog&) = delete;
+@@ -210,6 +211,19 @@ class SHELL_DIALOGS_EXPORT SelectFileDialog
+ const GURL* caller = nullptr);
+ bool HasMultipleFileTypeChoices();
+
++ // Match the types used by CefWindowHandle.
++#if BUILDFLAG(IS_MAC)
++ using WidgetType = void*;
++ static constexpr WidgetType kNullWidget = nullptr;
++#else
++ using WidgetType = gfx::AcceleratedWidget;
++ static constexpr WidgetType kNullWidget = gfx::kNullAcceleratedWidget;
++#endif
++
++ void set_owning_widget(WidgetType widget) {
++ owning_widget_ = widget;
++ }
++
+ protected:
+ friend class base::RefCountedThreadSafe<SelectFileDialog>;
+
+@@ -235,6 +249,11 @@ class SHELL_DIALOGS_EXPORT SelectFileDialog
+ // The listener to be notified of selection completion.
+ raw_ptr<Listener, DanglingUntriaged> listener_;
+
++ std::unique_ptr<SelectFilePolicy> select_file_policy_;
++
++ // Support override of the |owning_window| value.
++ WidgetType owning_widget_ = kNullWidget;
++
+ private:
+ // Tests if the file selection dialog can be displayed by
+ // testing if the AllowFileSelectionDialogs-Policy is
+@@ -247,8 +266,6 @@ class SHELL_DIALOGS_EXPORT SelectFileDialog
+
+ // Returns true if the dialog has multiple file type choices.
+ virtual bool HasMultipleFileTypeChoicesImpl() = 0;
+-
+- std::unique_ptr<SelectFilePolicy> select_file_policy_;
+ };
+
+ SelectFileDialog* CreateSelectFileDialog(
+diff --git ui/shell_dialogs/select_file_dialog_factory.h ui/shell_dialogs/select_file_dialog_factory.h
+index c7acd9b05fbb8..3e95e4125fa24 100644
+--- ui/shell_dialogs/select_file_dialog_factory.h
++++ ui/shell_dialogs/select_file_dialog_factory.h
+@@ -24,6 +24,8 @@ class SHELL_DIALOGS_EXPORT SelectFileDialogFactory {
+ virtual SelectFileDialog* Create(
+ ui::SelectFileDialog::Listener* listener,
+ std::unique_ptr<ui::SelectFilePolicy> policy) = 0;
++
++ virtual bool IsCefFactory() const { return false; }
+ };
+
+ } // namespace ui
+diff --git ui/shell_dialogs/select_file_dialog_mac.mm ui/shell_dialogs/select_file_dialog_mac.mm
+index 0b8aaa3c0e4f0..fe01d3db2eabe 100644
+--- ui/shell_dialogs/select_file_dialog_mac.mm
++++ ui/shell_dialogs/select_file_dialog_mac.mm
+@@ -102,6 +102,10 @@ void SelectFileDialogImpl::SelectFileImpl(
+ mojo_window->CreateSelectFileDialog(std::move(receiver));
+ } else {
+ NSWindow* ns_window = gfx_window.GetNativeNSWindow();
++ if (!ns_window && owning_widget_) {
++ NSView* view = ((__bridge NSView*)owning_widget_);
++ ns_window = [view window];
++ }
+ mojo::MakeSelfOwnedReceiver(
+ std::make_unique<remote_cocoa::SelectFileDialogBridge>(ns_window),
+ std::move(receiver));
+diff --git ui/shell_dialogs/select_file_dialog_win.cc ui/shell_dialogs/select_file_dialog_win.cc
+index 04aa920d91675..93ea4988839cf 100644
+--- ui/shell_dialogs/select_file_dialog_win.cc
++++ ui/shell_dialogs/select_file_dialog_win.cc
+@@ -252,6 +252,8 @@ void SelectFileDialogImpl::SelectFileImpl(
+ HWND owner = owning_window && owning_window->GetRootWindow()
+ ? owning_window->GetHost()->GetAcceleratedWidget()
+ : nullptr;
++ if (!owner)
++ owner = owning_widget_;
+
+ std::unique_ptr<RunState> run_state = BeginRun(owner);
+
diff --git a/patch/patches/chrome_browser_dialogs_widget.patch b/patch/patches/chrome_browser_dialogs_widget.patch
new file mode 100644
index 00000000..629f0765
--- /dev/null
+++ b/patch/patches/chrome_browser_dialogs_widget.patch
@@ -0,0 +1,219 @@
+diff --git chrome/browser/ui/views/chrome_javascript_app_modal_view_factory_views.cc chrome/browser/ui/views/chrome_javascript_app_modal_view_factory_views.cc
+index d62e9fa67d534..e7bdaeb7b5e19 100644
+--- chrome/browser/ui/views/chrome_javascript_app_modal_view_factory_views.cc
++++ chrome/browser/ui/views/chrome_javascript_app_modal_view_factory_views.cc
+@@ -97,7 +97,7 @@ javascript_dialogs::AppModalDialogView* CreateViewsJavaScriptDialog(
+ gfx::NativeWindow parent_window =
+ controller->web_contents()->GetTopLevelNativeWindow();
+ #if defined(USE_AURA)
+- if (!parent_window->GetRootWindow()) {
++ if (parent_window && !parent_window->GetRootWindow()) {
+ // When we are part of a WebContents that isn't actually being displayed
+ // on the screen, we can't actually attach to it.
+ parent_window = nullptr;
+diff --git components/constrained_window/constrained_window_views.cc components/constrained_window/constrained_window_views.cc
+index 3b41c7d676b35..e76c13cd8d122 100644
+--- components/constrained_window/constrained_window_views.cc
++++ components/constrained_window/constrained_window_views.cc
+@@ -101,15 +101,24 @@ void UpdateModalDialogPosition(views::Widget* widget,
+ if (widget->HasCapture())
+ return;
+
++ // |host_view| will be nullptr with CEF windowless rendering.
++ auto host_view = dialog_host->GetHostView();
+ views::Widget* host_widget =
+- views::Widget::GetWidgetForNativeView(dialog_host->GetHostView());
++ host_view ? views::Widget::GetWidgetForNativeView(host_view) : nullptr;
+
+ // If the host view is not backed by a Views::Widget, just update the widget
+ // size. This can happen on MacViews under the Cocoa browser where the window
+ // modal dialogs are displayed as sheets, and their position is managed by a
+ // ConstrainedWindowSheetController instance.
+ if (!host_widget) {
++#if BUILDFLAG(IS_MAC)
+ widget->SetSize(size);
++#elif BUILDFLAG(IS_POSIX)
++ // Set the bounds here instead of relying on the default behavior of
++ // DesktopWindowTreeHostPlatform::CenterWindow which incorrectly centers
++ // the window on the screen.
++ widget->SetBounds(gfx::Rect(dialog_host->GetDialogPosition(size), size));
++#endif
+ return;
+ }
+
+@@ -215,7 +224,8 @@ views::Widget* CreateWebModalDialogViews(views::WidgetDelegate* dialog,
+
+ return views::DialogDelegate::CreateDialogWidget(
+ dialog, nullptr,
+- manager->delegate()->GetWebContentsModalDialogHost()->GetHostView());
++ manager->delegate()->GetWebContentsModalDialogHost()->GetHostView(),
++ manager->delegate()->GetWebContentsModalDialogHost()->GetHostWidget());
+ }
+
+ views::Widget* CreateBrowserModalDialogViews(
+@@ -232,8 +242,13 @@ views::Widget* CreateBrowserModalDialogViews(views::DialogDelegate* dialog,
+
+ gfx::NativeView parent_view =
+ parent ? CurrentClient()->GetDialogHostView(parent) : nullptr;
++ // Use with CEF windowless rendering.
++ gfx::AcceleratedWidget parent_widget =
++ parent ? gfx::kNullAcceleratedWidget :
++ CurrentClient()->GetModalDialogHost(parent)->GetHostWidget();
+ views::Widget* widget =
+- views::DialogDelegate::CreateDialogWidget(dialog, nullptr, parent_view);
++ views::DialogDelegate::CreateDialogWidget(dialog, nullptr, parent_view,
++ parent_widget);
+
+ bool requires_positioning = dialog->use_custom_frame();
+
+@@ -246,8 +261,7 @@ views::Widget* CreateBrowserModalDialogViews(views::DialogDelegate* dialog,
+ if (!requires_positioning)
+ return widget;
+
+- ModalDialogHost* host =
+- parent ? CurrentClient()->GetModalDialogHost(parent) : nullptr;
++ ModalDialogHost* host = CurrentClient()->GetModalDialogHost(parent);
+ if (host) {
+ DCHECK_EQ(parent_view, host->GetHostView());
+ ModalDialogHostObserver* dialog_host_observer =
+diff --git components/constrained_window/native_web_contents_modal_dialog_manager_views.cc components/constrained_window/native_web_contents_modal_dialog_manager_views.cc
+index 647391095306e..02aea9b01f59b 100644
+--- components/constrained_window/native_web_contents_modal_dialog_manager_views.cc
++++ components/constrained_window/native_web_contents_modal_dialog_manager_views.cc
+@@ -184,9 +184,12 @@ void NativeWebContentsModalDialogManagerViews::HostChanged(
+ if (host_) {
+ host_->AddObserver(this);
+
+- for (auto* widget : observed_widgets_) {
+- views::Widget::ReparentNativeView(widget->GetNativeView(),
+- host_->GetHostView());
++ // |host_view| will be nullptr with CEF windowless rendering.
++ if (auto host_view = host_->GetHostView()) {
++ for (auto* widget : observed_widgets_) {
++ views::Widget::ReparentNativeView(widget->GetNativeView(),
++ host_view);
++ }
+ }
+
+ OnPositionRequiresUpdate();
+diff --git components/web_modal/modal_dialog_host.h components/web_modal/modal_dialog_host.h
+index 51ed6bcf6b540..9ae4737e0737e 100644
+--- components/web_modal/modal_dialog_host.h
++++ components/web_modal/modal_dialog_host.h
+@@ -34,6 +34,10 @@ class WEB_MODAL_EXPORT ModalDialogHost {
+
+ // Returns the view against which the dialog is positioned and parented.
+ virtual gfx::NativeView GetHostView() const = 0;
++ // Returns the widget against which the dialog is positioned and parented.
++ // Used with CEF windowless rendering.
++ virtual gfx::AcceleratedWidget GetHostWidget() const {
++ return gfx::kNullAcceleratedWidget; }
+ // Gets the position for the dialog in coordinates relative to the host view.
+ virtual gfx::Point GetDialogPosition(const gfx::Size& size) = 0;
+ // Returns whether a dialog currently about to be shown should be activated.
+diff --git ui/views/window/dialog_delegate.cc ui/views/window/dialog_delegate.cc
+index fca1500246f01..e0c719b90f5da 100644
+--- ui/views/window/dialog_delegate.cc
++++ ui/views/window/dialog_delegate.cc
+@@ -54,10 +54,12 @@ DialogDelegate::DialogDelegate() {
+ // static
+ Widget* DialogDelegate::CreateDialogWidget(WidgetDelegate* delegate,
+ gfx::NativeWindow context,
+- gfx::NativeView parent) {
++ gfx::NativeView parent,
++ gfx::AcceleratedWidget parent_widget) {
+ views::Widget* widget = new views::Widget;
+ views::Widget::InitParams params =
+- GetDialogWidgetInitParams(delegate, context, parent, gfx::Rect());
++ GetDialogWidgetInitParams(delegate, context, parent, gfx::Rect(),
++ parent_widget);
+ widget->Init(std::move(params));
+ return widget;
+ }
+@@ -66,17 +68,19 @@ Widget* DialogDelegate::CreateDialogWidget(WidgetDelegate* delegate,
+ Widget* DialogDelegate::CreateDialogWidget(
+ std::unique_ptr<WidgetDelegate> delegate,
+ gfx::NativeWindow context,
+- gfx::NativeView parent) {
++ gfx::NativeView parent,
++ gfx::AcceleratedWidget parent_widget) {
+ DCHECK(delegate->owned_by_widget());
+- return CreateDialogWidget(delegate.release(), context, parent);
++ return CreateDialogWidget(delegate.release(), context, parent, parent_widget);
+ }
+
+ // static
+-bool DialogDelegate::CanSupportCustomFrame(gfx::NativeView parent) {
++bool DialogDelegate::CanSupportCustomFrame(gfx::NativeView parent,
++ gfx::AcceleratedWidget parent_widget) {
+ #if (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)) && \
+ BUILDFLAG(ENABLE_DESKTOP_AURA)
+ // The new style doesn't support unparented dialogs on Linux desktop.
+- return parent != nullptr;
++ return parent != nullptr || parent_widget != gfx::kNullAcceleratedWidget;
+ #else
+ return true;
+ #endif
+@@ -87,14 +91,15 @@ Widget::InitParams DialogDelegate::GetDialogWidgetInitParams(
+ WidgetDelegate* delegate,
+ gfx::NativeWindow context,
+ gfx::NativeView parent,
+- const gfx::Rect& bounds) {
++ const gfx::Rect& bounds,
++ gfx::AcceleratedWidget parent_widget) {
+ views::Widget::InitParams params;
+ params.delegate = delegate;
+ params.bounds = bounds;
+ DialogDelegate* dialog = delegate->AsDialogDelegate();
+
+ if (dialog)
+- dialog->params_.custom_frame &= CanSupportCustomFrame(parent);
++ dialog->params_.custom_frame &= CanSupportCustomFrame(parent, parent_widget);
+
+ if (!dialog || dialog->use_custom_frame()) {
+ params.opacity = Widget::InitParams::WindowOpacity::kTranslucent;
+@@ -107,6 +112,7 @@ Widget::InitParams DialogDelegate::GetDialogWidgetInitParams(
+ }
+ params.context = context;
+ params.parent = parent;
++ params.parent_widget = parent_widget;
+ #if !BUILDFLAG(IS_APPLE)
+ // Web-modal (ui::MODAL_TYPE_CHILD) dialogs with parents are marked as child
+ // widgets to prevent top-level window behavior (independent movement, etc).
+diff --git ui/views/window/dialog_delegate.h ui/views/window/dialog_delegate.h
+index 0b660d38eeb03..4f402ee8ddbd4 100644
+--- ui/views/window/dialog_delegate.h
++++ ui/views/window/dialog_delegate.h
+@@ -94,13 +94,18 @@ class VIEWS_EXPORT DialogDelegate : public WidgetDelegate {
+ // your use case.
+ static Widget* CreateDialogWidget(std::unique_ptr<WidgetDelegate> delegate,
+ gfx::NativeWindow context,
+- gfx::NativeView parent);
++ gfx::NativeView parent,
++ gfx::AcceleratedWidget parent_widget =
++ gfx::kNullAcceleratedWidget);
+ static Widget* CreateDialogWidget(WidgetDelegate* delegate,
+ gfx::NativeWindow context,
+- gfx::NativeView parent);
++ gfx::NativeView parent,
++ gfx::AcceleratedWidget parent_widget =
++ gfx::kNullAcceleratedWidget);
+
+ // Whether using custom dialog frame is supported for this dialog.
+- static bool CanSupportCustomFrame(gfx::NativeView parent);
++ static bool CanSupportCustomFrame(gfx::NativeView parent,
++ gfx::AcceleratedWidget parent_widget);
+
+ // Returns the dialog widget InitParams for a given |context| or |parent|.
+ // If |bounds| is not empty, used to initially place the dialog, otherwise
+@@ -108,7 +113,9 @@ class VIEWS_EXPORT DialogDelegate : public WidgetDelegate {
+ static Widget::InitParams GetDialogWidgetInitParams(WidgetDelegate* delegate,
+ gfx::NativeWindow context,
+ gfx::NativeView parent,
+- const gfx::Rect& bounds);
++ const gfx::Rect& bounds,
++ gfx::AcceleratedWidget parent_widget =
++ gfx::kNullAcceleratedWidget);
+
+ // Returns a mask specifying which of the available DialogButtons are visible
+ // for the dialog.
diff --git a/patch/patches/chrome_browser_extensions.patch b/patch/patches/chrome_browser_extensions.patch
new file mode 100644
index 00000000..f6249c2e
--- /dev/null
+++ b/patch/patches/chrome_browser_extensions.patch
@@ -0,0 +1,35 @@
+diff --git chrome/browser/extensions/api/chrome_extensions_api_client.cc chrome/browser/extensions/api/chrome_extensions_api_client.cc
+index e49e111d2e867..83f3c9221fa1e 100644
+--- chrome/browser/extensions/api/chrome_extensions_api_client.cc
++++ chrome/browser/extensions/api/chrome_extensions_api_client.cc
+@@ -13,6 +13,7 @@
+ #include "base/strings/string_util.h"
+ #include "build/build_config.h"
+ #include "build/chromeos_buildflags.h"
++#include "cef/libcef/features/runtime.h"
+ #include "chrome/browser/extensions/api/automation_internal/chrome_automation_internal_api_delegate.h"
+ #include "chrome/browser/extensions/api/chrome_device_permissions_prompt.h"
+ #include "chrome/browser/extensions/api/declarative_content/chrome_content_rules_registry.h"
+@@ -83,6 +84,10 @@
+ #include "chrome/browser/extensions/clipboard_extension_helper_chromeos.h"
+ #endif
+
++#if BUILDFLAG(ENABLE_CEF)
++#include "cef/libcef/browser/chrome/extensions/chrome_mime_handler_view_guest_delegate_cef.h"
++#endif
++
+ #if BUILDFLAG(ENABLE_PDF)
+ #include "chrome/browser/ui/pdf/chrome_pdf_web_contents_helper_client.h"
+ #include "components/pdf/browser/pdf_web_contents_helper.h"
+@@ -305,6 +310,11 @@ ChromeExtensionsAPIClient::CreateGuestViewManagerDelegate(
+ std::unique_ptr<MimeHandlerViewGuestDelegate>
+ ChromeExtensionsAPIClient::CreateMimeHandlerViewGuestDelegate(
+ MimeHandlerViewGuest* guest) const {
++#if BUILDFLAG(ENABLE_CEF)
++ if (cef::IsChromeRuntimeEnabled()) {
++ return std::make_unique<ChromeMimeHandlerViewGuestDelegateCef>(guest);
++ }
++#endif
+ return std::make_unique<ChromeMimeHandlerViewGuestDelegate>();
+ }
+
diff --git a/patch/patches/chrome_browser_net_proxy.patch b/patch/patches/chrome_browser_net_proxy.patch
new file mode 100644
index 00000000..59968315
--- /dev/null
+++ b/patch/patches/chrome_browser_net_proxy.patch
@@ -0,0 +1,33 @@
+diff --git chrome/browser/net/proxy_config_monitor.cc chrome/browser/net/proxy_config_monitor.cc
+index 34584b4400276..809b175ff26de 100644
+--- chrome/browser/net/proxy_config_monitor.cc
++++ chrome/browser/net/proxy_config_monitor.cc
+@@ -9,6 +9,7 @@
+ #include "base/strings/utf_string_conversions.h"
+ #include "build/build_config.h"
+ #include "build/chromeos_buildflags.h"
++#include "cef/libcef/features/runtime.h"
+ #include "chrome/browser/browser_process.h"
+ #include "chrome/browser/net/proxy_service_factory.h"
+ #include "chrome/browser/profiles/profile.h"
+@@ -21,6 +22,10 @@
+ #include "chrome/browser/ash/profiles/profile_helper.h"
+ #endif // BUILDFLAG(IS_CHROMEOS_ASH)
+
++#if BUILDFLAG(ENABLE_CEF)
++#include "cef/libcef/common/extensions/extensions_util.h"
++#endif
++
+ #if BUILDFLAG(ENABLE_EXTENSIONS)
+ #include "chrome/browser/extensions/api/proxy/proxy_api.h"
+ #endif
+@@ -90,6 +95,9 @@ void ProxyConfigMonitor::AddToNetworkContextParams(
+ .InitWithNewPipeAndPassReceiver());
+
+ #if BUILDFLAG(ENABLE_EXTENSIONS)
++#if BUILDFLAG(ENABLE_CEF)
++ if (!cef::IsAlloyRuntimeEnabled() || extensions::ExtensionsEnabled())
++#endif
+ error_receiver_set_.Add(this, network_context_params->proxy_error_client
+ .InitWithNewPipeAndPassReceiver());
+ #endif
diff --git a/patch/patches/chrome_browser_permission_prompt.patch b/patch/patches/chrome_browser_permission_prompt.patch
new file mode 100644
index 00000000..3adf2a07
--- /dev/null
+++ b/patch/patches/chrome_browser_permission_prompt.patch
@@ -0,0 +1,206 @@
+diff --git chrome/browser/background_fetch/background_fetch_permission_context.cc chrome/browser/background_fetch/background_fetch_permission_context.cc
+index 0a5aef10879ac..1b122c8848c97 100644
+--- chrome/browser/background_fetch/background_fetch_permission_context.cc
++++ chrome/browser/background_fetch/background_fetch_permission_context.cc
+@@ -4,6 +4,7 @@
+
+ #include "chrome/browser/background_fetch/background_fetch_permission_context.h"
+
++#include "cef/libcef/features/runtime.h"
+ #include "chrome/browser/browser_process.h"
+ #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
+ #include "chrome/browser/download/download_request_limiter.h"
+@@ -25,7 +26,8 @@ ContentSetting BackgroundFetchPermissionContext::GetPermissionStatusInternal(
+ const GURL& embedding_origin) const {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+- if (render_frame_host && !render_frame_host->GetParent()) {
++ if (!cef::IsAlloyRuntimeEnabled() &&
++ render_frame_host && !render_frame_host->GetParent()) {
+ DownloadRequestLimiter* limiter =
+ g_browser_process->download_request_limiter();
+ DCHECK(limiter);
+diff --git chrome/browser/background_sync/periodic_background_sync_permission_context.cc chrome/browser/background_sync/periodic_background_sync_permission_context.cc
+index 16107572d4d0d..409e9ea870482 100644
+--- chrome/browser/background_sync/periodic_background_sync_permission_context.cc
++++ chrome/browser/background_sync/periodic_background_sync_permission_context.cc
+@@ -6,6 +6,7 @@
+
+ #include "base/feature_list.h"
+ #include "build/build_config.h"
++#include "cef/libcef/features/runtime.h"
+ #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
+ #include "chrome/browser/installable/installable_utils.h"
+ #include "chrome/browser/profiles/profile.h"
+@@ -89,6 +90,10 @@ PeriodicBackgroundSyncPermissionContext::GetPermissionStatusInternal(
+ return CONTENT_SETTING_ALLOW;
+ #endif
+
++ if (cef::IsAlloyRuntimeEnabled()) {
++ return CONTENT_SETTING_BLOCK;
++ }
++
+ bool can_bypass_install_requirement =
+ base::FeatureList::IsEnabled(
+ features::kPeriodicSyncPermissionForDefaultSearchEngine) &&
+diff --git chrome/browser/permissions/chrome_permissions_client.cc chrome/browser/permissions/chrome_permissions_client.cc
+index d0d4fd4f7925b..0755927b00e2c 100644
+--- chrome/browser/permissions/chrome_permissions_client.cc
++++ chrome/browser/permissions/chrome_permissions_client.cc
+@@ -14,6 +14,7 @@
+ #include "base/time/time.h"
+ #include "build/build_config.h"
+ #include "build/chromeos_buildflags.h"
++#include "cef/libcef/features/runtime.h"
+ #include "chrome/browser/bluetooth/bluetooth_chooser_context_factory.h"
+ #include "chrome/browser/content_settings/cookie_settings_factory.h"
+ #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
+@@ -174,6 +175,9 @@ ChromePermissionsClient::GetPermissionDecisionAutoBlocker(
+ double ChromePermissionsClient::GetSiteEngagementScore(
+ content::BrowserContext* browser_context,
+ const GURL& origin) {
++ // No SiteEngagementService with the Alloy runtime.
++ if (cef::IsAlloyRuntimeEnabled())
++ return 0.0;
+ return site_engagement::SiteEngagementService::Get(
+ Profile::FromBrowserContext(browser_context))
+ ->GetScore(origin);
+@@ -321,8 +325,10 @@ ChromePermissionsClient::CreatePermissionUiSelectors(
+ std::make_unique<ContextualNotificationPermissionUiSelector>());
+ selectors.emplace_back(std::make_unique<PrefNotificationPermissionUiSelector>(
+ Profile::FromBrowserContext(browser_context)));
++ if (!cef::IsAlloyRuntimeEnabled()) {
+ selectors.emplace_back(std::make_unique<PredictionBasedPermissionUiSelector>(
+ Profile::FromBrowserContext(browser_context)));
++ }
+ return selectors;
+ }
+
+diff --git chrome/browser/permissions/permission_manager_factory.cc chrome/browser/permissions/permission_manager_factory.cc
+index 5e3e2bd6f1e69..4594213db914f 100644
+--- chrome/browser/permissions/permission_manager_factory.cc
++++ chrome/browser/permissions/permission_manager_factory.cc
+@@ -6,6 +6,7 @@
+
+ #include "build/build_config.h"
+ #include "build/chromeos_buildflags.h"
++#include "cef/libcef/features/runtime.h"
+ #include "chrome/browser/background_fetch/background_fetch_permission_context.h"
+ #include "chrome/browser/background_sync/periodic_background_sync_permission_context.h"
+ #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
+@@ -60,8 +61,10 @@ permissions::PermissionManager::PermissionContextMap CreatePermissionContexts(
+ std::make_unique<GeolocationPermissionContextDelegate>(profile);
+ #endif // BUILDFLAG(IS_ANDROID)
+ #if BUILDFLAG(IS_MAC)
++ if (!cef::IsAlloyRuntimeEnabled()) {
+ delegates.geolocation_manager =
+ g_browser_process->platform_part()->geolocation_manager();
++ }
+ #endif // BUILDFLAG(IS_MAC)
+ delegates.media_stream_device_enumerator =
+ MediaCaptureDevicesDispatcher::GetInstance();
+diff --git chrome/browser/storage/durable_storage_permission_context.cc chrome/browser/storage/durable_storage_permission_context.cc
+index 9836207f50e5b..09d8f5549820c 100644
+--- chrome/browser/storage/durable_storage_permission_context.cc
++++ chrome/browser/storage/durable_storage_permission_context.cc
+@@ -8,6 +8,7 @@
+
+ #include "base/check_op.h"
+ #include "base/containers/contains.h"
++#include "cef/libcef/features/runtime.h"
+ #include "chrome/browser/bookmarks/bookmark_model_factory.h"
+ #include "chrome/browser/content_settings/cookie_settings_factory.h"
+ #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
+@@ -55,7 +56,9 @@ void DurableStoragePermissionContext::DecidePermission(
+
+ // Durable is only allowed to be granted to the top-level origin. Embedding
+ // origin is the last committed navigation origin to the web contents.
+- if (requesting_origin != embedding_origin) {
++ // Permission depends on PWA and site engagement subsystems which are not
++ // supported by the Alloy runtime (see issue #3379).
++ if (cef::IsAlloyRuntimeEnabled() || requesting_origin != embedding_origin) {
+ NotifyPermissionSet(id, requesting_origin, embedding_origin,
+ std::move(callback), /*persist=*/false,
+ CONTENT_SETTING_DEFAULT, /*is_one_time=*/false,
+diff --git chrome/browser/ui/permission_bubble/permission_prompt.h chrome/browser/ui/permission_bubble/permission_prompt.h
+index fbce13c16ad10..0512b2f09937e 100644
+--- chrome/browser/ui/permission_bubble/permission_prompt.h
++++ chrome/browser/ui/permission_bubble/permission_prompt.h
+@@ -11,6 +11,13 @@ namespace content {
+ class WebContents;
+ }
+
++using CreatePermissionPromptFunctionPtr =
++ std::unique_ptr<permissions::PermissionPrompt> (*)(
++ content::WebContents* web_contents,
++ permissions::PermissionPrompt::Delegate* delegate,
++ bool* default_handling);
++void SetCreatePermissionPromptFunction(CreatePermissionPromptFunctionPtr);
++
+ // Factory function to create permission prompts for chrome.
+ std::unique_ptr<permissions::PermissionPrompt> CreatePermissionPrompt(
+ content::WebContents* web_contents,
+diff --git chrome/browser/ui/views/permissions/permission_prompt_factory.cc chrome/browser/ui/views/permissions/permission_prompt_factory.cc
+index 82a50b7e22dfe..c4ba55ec6bd54 100644
+--- chrome/browser/ui/views/permissions/permission_prompt_factory.cc
++++ chrome/browser/ui/views/permissions/permission_prompt_factory.cc
+@@ -158,11 +158,28 @@ std::unique_ptr<permissions::PermissionPrompt> CreateQuietPrompt(
+ }
+ }
+
++CreatePermissionPromptFunctionPtr g_create_permission_prompt_ptr = nullptr;
++
+ } // namespace
+
++void SetCreatePermissionPromptFunction(
++ CreatePermissionPromptFunctionPtr ptr) {
++ g_create_permission_prompt_ptr = ptr;
++}
++
+ std::unique_ptr<permissions::PermissionPrompt> CreatePermissionPrompt(
+ content::WebContents* web_contents,
+ permissions::PermissionPrompt::Delegate* delegate) {
++ if (g_create_permission_prompt_ptr) {
++ bool default_handling = true;
++ auto prompt = g_create_permission_prompt_ptr(web_contents, delegate,
++ &default_handling);
++ if (prompt)
++ return prompt;
++ if (!default_handling)
++ return nullptr;
++ }
++
+ Browser* browser = chrome::FindBrowserWithWebContents(web_contents);
+ if (!browser) {
+ DLOG(WARNING) << "Permission prompt suppressed because the WebContents is "
+diff --git components/embedder_support/permission_context_utils.cc components/embedder_support/permission_context_utils.cc
+index c3b99f8e21b1c..8abca05c7c482 100644
+--- components/embedder_support/permission_context_utils.cc
++++ components/embedder_support/permission_context_utils.cc
+@@ -5,6 +5,7 @@
+ #include "components/embedder_support/permission_context_utils.h"
+
+ #include "build/build_config.h"
++#include "cef/libcef/features/runtime.h"
+ #include "components/background_sync/background_sync_permission_context.h"
+ #include "components/permissions/contexts/accessibility_permission_context.h"
+ #include "components/permissions/contexts/camera_pan_tilt_zoom_permission_context.h"
+@@ -78,11 +79,18 @@ CreateDefaultPermissionContexts(content::BrowserContext* browser_context,
+ browser_context,
+ std::move(delegates.geolocation_permission_context_delegate));
+ #elif BUILDFLAG(IS_MAC)
++ if (cef::IsAlloyRuntimeEnabled()) {
++ permission_contexts[ContentSettingsType::GEOLOCATION] =
++ std::make_unique<permissions::GeolocationPermissionContext>(
++ browser_context,
++ std::move(delegates.geolocation_permission_context_delegate));
++ } else {
+ permission_contexts[ContentSettingsType::GEOLOCATION] =
+ std::make_unique<permissions::GeolocationPermissionContextMac>(
+ browser_context,
+ std::move(delegates.geolocation_permission_context_delegate),
+ delegates.geolocation_manager);
++ }
+ #else
+ permission_contexts[ContentSettingsType::GEOLOCATION] =
+ std::make_unique<permissions::GeolocationPermissionContext>(
diff --git a/patch/patches/chrome_browser_privacy_1119417.patch b/patch/patches/chrome_browser_privacy_1119417.patch
new file mode 100644
index 00000000..48aea7d3
--- /dev/null
+++ b/patch/patches/chrome_browser_privacy_1119417.patch
@@ -0,0 +1,59 @@
+diff --git chrome/browser/privacy/BUILD.gn chrome/browser/privacy/BUILD.gn
+index cd1f57e009f50..f93721e39e559 100644
+--- chrome/browser/privacy/BUILD.gn
++++ chrome/browser/privacy/BUILD.gn
+@@ -93,11 +93,15 @@ if (is_win || is_linux) {
+ ]
+ proto_deps = [ "//components/policy:full_runtime_code_generate" ]
+ proto_out_dir = "/chrome/browser/privacy"
++ generate_cc = false
++ generate_library = false
+ }
+
+ proto_library("traffic_annotation_proto") {
+ sources = [ "traffic_annotation.proto" ]
+ proto_deps = [ ":chrome_settings_full_runtime" ]
+ import_dirs = [ "$root_gen_dir" + "/components/policy/proto" ]
++ generate_cc = false
++ generate_library = false
+ }
+ }
+diff --git third_party/protobuf/proto_library.gni third_party/protobuf/proto_library.gni
+index a6943f5896cba..1561a868ccef9 100644
+--- third_party/protobuf/proto_library.gni
++++ third_party/protobuf/proto_library.gni
+@@ -28,6 +28,9 @@
+ # generate_javascript (optional, default false)
+ # Generate Javascript protobuf stubs.
+ #
++# generate_library (optional, default true)
++# Generate a "static_library" target for linking with the generated code.
++#
+ # cc_generator_options (optional)
+ # List of extra flags passed to the protocol compiler. If you need to
+ # add an EXPORT macro to a protobuf's C++ header, set the
+@@ -266,14 +269,21 @@ template("proto_library") {
+ protogens_cc = []
+ protogens_js = []
+
++ # Whether source code bindings should be generated.
++ generate_sources = generate_cc || generate_python || generate_with_plugin ||
++ generate_javascript
++
+ # Whether library should be generated.
+ # Library is not needed when proto_library is used to generate binary descriptor, in which case
+ # corresponding library target should be omitted entirely.
+- generate_library = generate_cc || generate_python || generate_with_plugin ||
+- generate_javascript
++ if (defined(invoker.generate_library)) {
++ generate_library = invoker.generate_library
++ } else {
++ generate_library = generate_sources
++ }
+
+ # List output files.
+- if (generate_library) {
++ if (generate_sources) {
+ foreach(proto, protos) {
+ proto_dir = get_path_info(proto, "dir")
+ proto_name = get_path_info(proto, "name")
diff --git a/patch/patches/chrome_browser_profile_menu.patch b/patch/patches/chrome_browser_profile_menu.patch
new file mode 100644
index 00000000..5377a418
--- /dev/null
+++ b/patch/patches/chrome_browser_profile_menu.patch
@@ -0,0 +1,75 @@
+diff --git chrome/browser/ui/bookmarks/bookmark_stats.cc chrome/browser/ui/bookmarks/bookmark_stats.cc
+index 45f661faa6e0b..777a1f6c333b6 100644
+--- chrome/browser/ui/bookmarks/bookmark_stats.cc
++++ chrome/browser/ui/bookmarks/bookmark_stats.cc
+@@ -21,7 +21,9 @@ bool IsBookmarkBarLocation(BookmarkLaunchLocation location) {
+
+ auto GetMetricProfile(const Profile* profile) {
+ DCHECK(profile);
+- DCHECK(profile->IsRegularProfile() || profile->IsIncognitoProfile());
++ DCHECK(profile->IsRegularProfile() || profile->IsIncognitoProfile() ||
++ (profile->IsOffTheRecord() &&
++ profile->GetOTRProfileID().IsUniqueForCEF()));
+ return profile->IsRegularProfile()
+ ? profile_metrics::BrowserProfileType::kRegular
+ : profile_metrics::BrowserProfileType::kIncognito;
+diff --git chrome/browser/ui/views/incognito_clear_browsing_data_dialog.cc chrome/browser/ui/views/incognito_clear_browsing_data_dialog.cc
+index f3a5093abe7ca..f2bcc7b3c1f4c 100644
+--- chrome/browser/ui/views/incognito_clear_browsing_data_dialog.cc
++++ chrome/browser/ui/views/incognito_clear_browsing_data_dialog.cc
+@@ -30,7 +30,9 @@ IncognitoClearBrowsingDataDialog::IncognitoClearBrowsingDataDialog(
+ dialog_type_(type),
+ incognito_profile_(incognito_profile) {
+ DCHECK(incognito_profile_);
+- DCHECK(incognito_profile_->IsIncognitoProfile());
++ DCHECK(incognito_profile_->IsIncognitoProfile() ||
++ (incognito_profile_->IsOffTheRecord() &&
++ incognito_profile_->GetOTRProfileID().IsUniqueForCEF()));
+ SetButtons(ui::DIALOG_BUTTON_NONE);
+ SetShowCloseButton(true);
+
+diff --git chrome/browser/ui/views/incognito_clear_browsing_data_dialog_coordinator.cc chrome/browser/ui/views/incognito_clear_browsing_data_dialog_coordinator.cc
+index caa20ec03434a..2a3ca921445c1 100644
+--- chrome/browser/ui/views/incognito_clear_browsing_data_dialog_coordinator.cc
++++ chrome/browser/ui/views/incognito_clear_browsing_data_dialog_coordinator.cc
+@@ -26,6 +26,10 @@ void IncognitoClearBrowsingDataDialogCoordinator::Show(
+ ->toolbar_button_provider()
+ ->GetAvatarToolbarButton();
+
++ // The full toolbar may not be visible.
++ if (!avatar_toolbar_button)
++ return;
++
+ auto bubble = std::make_unique<IncognitoClearBrowsingDataDialog>(
+ avatar_toolbar_button, GetBrowser().profile(), type);
+ DCHECK_EQ(nullptr, bubble_tracker_.view());
+diff --git chrome/browser/ui/views/profiles/incognito_menu_view.cc chrome/browser/ui/views/profiles/incognito_menu_view.cc
+index 723920ef96f9a..cb3cbbd18a957 100644
+--- chrome/browser/ui/views/profiles/incognito_menu_view.cc
++++ chrome/browser/ui/views/profiles/incognito_menu_view.cc
+@@ -37,7 +37,9 @@
+ IncognitoMenuView::IncognitoMenuView(views::Button* anchor_button,
+ Browser* browser)
+ : ProfileMenuViewBase(anchor_button, browser) {
+- DCHECK(browser->profile()->IsIncognitoProfile());
++ DCHECK(browser->profile()->IsIncognitoProfile() ||
++ (browser->profile()->IsOffTheRecord() &&
++ browser->profile()->GetOTRProfileID().IsUniqueForCEF()));
+ GetViewAccessibility().OverrideName(GetAccessibleWindowTitle());
+
+ base::RecordAction(base::UserMetricsAction("IncognitoMenu_Show"));
+diff --git chrome/browser/ui/views/profiles/profile_menu_coordinator.cc chrome/browser/ui/views/profiles/profile_menu_coordinator.cc
+index 41546d7dce559..dce0122a85933 100644
+--- chrome/browser/ui/views/profiles/profile_menu_coordinator.cc
++++ chrome/browser/ui/views/profiles/profile_menu_coordinator.cc
+@@ -45,7 +45,9 @@ void ProfileMenuCoordinator::Show(bool is_source_accelerator) {
+ feature_engagement::kIPHProfileSwitchFeature);
+
+ std::unique_ptr<ProfileMenuViewBase> bubble;
+- if (browser.profile()->IsIncognitoProfile()) {
++ if (browser.profile()->IsIncognitoProfile() ||
++ (browser.profile()->IsOffTheRecord() &&
++ browser.profile()->GetOTRProfileID().IsUniqueForCEF())) {
+ bubble =
+ std::make_unique<IncognitoMenuView>(avatar_toolbar_button, &browser);
+ } else {
diff --git a/patch/patches/chrome_browser_profiles.patch b/patch/patches/chrome_browser_profiles.patch
new file mode 100644
index 00000000..8f488c57
--- /dev/null
+++ b/patch/patches/chrome_browser_profiles.patch
@@ -0,0 +1,158 @@
+diff --git chrome/browser/profiles/off_the_record_profile_impl.cc chrome/browser/profiles/off_the_record_profile_impl.cc
+index 45357cf77c472..c5a4104a3414f 100644
+--- chrome/browser/profiles/off_the_record_profile_impl.cc
++++ chrome/browser/profiles/off_the_record_profile_impl.cc
+@@ -656,7 +656,9 @@ std::unique_ptr<Profile> Profile::CreateOffTheRecordProfile(
+ #endif
+ if (!profile)
+ profile = std::make_unique<OffTheRecordProfileImpl>(parent, otr_profile_id);
+- profile->Init();
++ // With CEF we want to delay initialization.
++ if (!otr_profile_id.IsUniqueForCEF())
++ profile->Init();
+ return std::move(profile);
+ }
+
+diff --git chrome/browser/profiles/profile.cc chrome/browser/profiles/profile.cc
+index d035eb9f2bea7..0ff6726604022 100644
+--- chrome/browser/profiles/profile.cc
++++ chrome/browser/profiles/profile.cc
+@@ -84,6 +84,7 @@ base::LazyInstance<std::set<content::BrowserContext*>>::Leaky
+
+ namespace {
+
++const char kCEFOTRProfileIDPrefix[] = "CEF::BrowserContext";
+ const char kDevToolsOTRProfileIDPrefix[] = "Devtools::BrowserContext";
+ const char kMediaRouterOTRProfileIDPrefix[] = "MediaRouter::Presentation";
+ const char kTestOTRProfileIDPrefix[] = "Test::OTR";
+@@ -104,6 +105,8 @@ bool Profile::OTRProfileID::AllowsBrowserWindows() const {
+ // DevTools::BrowserContext, MediaRouter::Presentation, and
+ // CaptivePortal::Signin are exceptions to this ban.
+ if (*this == PrimaryID() ||
++ base::StartsWith(profile_id_, kCEFOTRProfileIDPrefix,
++ base::CompareCase::SENSITIVE) ||
+ base::StartsWith(profile_id_, kDevToolsOTRProfileIDPrefix,
+ base::CompareCase::SENSITIVE) ||
+ base::StartsWith(profile_id_, kMediaRouterOTRProfileIDPrefix,
+@@ -141,6 +144,16 @@ Profile::OTRProfileID Profile::OTRProfileID::CreateUnique(
+ base::GUID::GenerateRandomV4().AsLowercaseString().c_str()));
+ }
+
++// static
++Profile::OTRProfileID Profile::OTRProfileID::CreateUniqueForCEF() {
++ return CreateUnique(kCEFOTRProfileIDPrefix);
++}
++
++bool Profile::OTRProfileID::IsUniqueForCEF() const {
++ return base::StartsWith(profile_id_, kCEFOTRProfileIDPrefix,
++ base::CompareCase::SENSITIVE);
++}
++
+ // static
+ Profile::OTRProfileID Profile::OTRProfileID::CreateUniqueForDevTools() {
+ return CreateUnique(kDevToolsOTRProfileIDPrefix);
+diff --git chrome/browser/profiles/profile.h chrome/browser/profiles/profile.h
+index 1e6a22d95a53f..6ec4182bfc5e7 100644
+--- chrome/browser/profiles/profile.h
++++ chrome/browser/profiles/profile.h
+@@ -99,6 +99,10 @@ class Profile : public content::BrowserContext {
+ // be applicable to run. Please see crbug.com/1098697#c3 for more details.
+ static OTRProfileID CreateUnique(const std::string& profile_id_prefix);
+
++ // Creates a unique OTR profile id to be used for CEF browser contexts.
++ static OTRProfileID CreateUniqueForCEF();
++ bool IsUniqueForCEF() const;
++
+ // Creates a unique OTR profile id to be used for DevTools browser contexts.
+ static OTRProfileID CreateUniqueForDevTools();
+
+@@ -494,6 +498,8 @@ class Profile : public content::BrowserContext {
+
+ base::WeakPtr<Profile> GetWeakPtr();
+
++ void NotifyOffTheRecordProfileCreated(Profile* off_the_record);
++
+ protected:
+ // Creates an OffTheRecordProfile which points to this Profile.
+ static std::unique_ptr<Profile> CreateOffTheRecordProfile(
+@@ -505,7 +511,6 @@ class Profile : public content::BrowserContext {
+ static PrefStore* CreateExtensionPrefStore(Profile*,
+ bool incognito_pref_store);
+
+- void NotifyOffTheRecordProfileCreated(Profile* off_the_record);
+ void NotifyProfileInitializationComplete();
+
+ // Returns whether the user has signed in this profile to an account.
+diff --git chrome/browser/profiles/profile_impl.cc chrome/browser/profiles/profile_impl.cc
+index 1340e751c0381..a0875155ddad2 100644
+--- chrome/browser/profiles/profile_impl.cc
++++ chrome/browser/profiles/profile_impl.cc
+@@ -1013,7 +1013,9 @@ Profile* ProfileImpl::GetOffTheRecordProfile(const OTRProfileID& otr_profile_id,
+
+ otr_profiles_[otr_profile_id] = std::move(otr_profile);
+
+- NotifyOffTheRecordProfileCreated(raw_otr_profile);
++ // With CEF we want to delay initialization.
++ if (!otr_profile_id.IsUniqueForCEF())
++ NotifyOffTheRecordProfileCreated(raw_otr_profile);
+
+ return raw_otr_profile;
+ }
+diff --git chrome/browser/profiles/profile_manager.cc chrome/browser/profiles/profile_manager.cc
+index 4f6dd066df3de..4d04f0ad554df 100644
+--- chrome/browser/profiles/profile_manager.cc
++++ chrome/browser/profiles/profile_manager.cc
+@@ -381,7 +381,7 @@ ProfileManager::ProfileManager(const base::FilePath& user_data_dir)
+ base::Unretained(this)));
+ #endif
+
+- if (ProfileShortcutManager::IsFeatureEnabled() && !user_data_dir_.empty())
++ if (!user_data_dir_.empty() && ProfileShortcutManager::IsFeatureEnabled())
+ profile_shortcut_manager_ = ProfileShortcutManager::Create(this);
+
+ zombie_metrics_timer_.Start(FROM_HERE, base::Minutes(30), this,
+diff --git chrome/browser/profiles/profile_manager.h chrome/browser/profiles/profile_manager.h
+index 54502d1b44a82..8134c87824687 100644
+--- chrome/browser/profiles/profile_manager.h
++++ chrome/browser/profiles/profile_manager.h
+@@ -130,7 +130,7 @@ class ProfileManager : public Profile::Delegate {
+ // acceptable. Returns nullptr if loading the new profile fails.
+ // TODO(bauerb): Migrate calls from other code to `GetProfileByPath()`, then
+ // make this method private.
+- Profile* GetProfile(const base::FilePath& profile_dir);
++ virtual Profile* GetProfile(const base::FilePath& profile_dir);
+
+ // Returns regular or off-the-record profile given its profile key.
+ static Profile* GetProfileFromProfileKey(ProfileKey* profile_key);
+@@ -171,7 +171,7 @@ class ProfileManager : public Profile::Delegate {
+
+ // Returns true if the profile pointer is known to point to an existing
+ // profile.
+- bool IsValidProfile(const void* profile);
++ virtual bool IsValidProfile(const void* profile);
+
+ // Returns the directory where the first created profile is stored,
+ // relative to the user data directory currently in use.
+diff --git chrome/browser/profiles/renderer_updater.cc chrome/browser/profiles/renderer_updater.cc
+index 43082afabf4bb..fa87aae9cbc93 100644
+--- chrome/browser/profiles/renderer_updater.cc
++++ chrome/browser/profiles/renderer_updater.cc
+@@ -8,6 +8,7 @@
+
+ #include "base/functional/bind.h"
+ #include "build/chromeos_buildflags.h"
++#include "cef/libcef/features/runtime.h"
+ #include "chrome/browser/content_settings/content_settings_manager_delegate.h"
+ #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
+ #include "chrome/browser/profiles/profile.h"
+@@ -35,8 +36,10 @@ RendererUpdater::RendererUpdater(Profile* profile)
+ : profile_(profile),
+ is_off_the_record_(profile_->IsOffTheRecord()),
+ original_profile_(profile->GetOriginalProfile()) {
++ if (!cef::IsAlloyRuntimeEnabled()) {
+ identity_manager_observation_.Observe(
+ IdentityManagerFactory::GetForProfile(original_profile_));
++ }
+
+ #if BUILDFLAG(IS_CHROMEOS_ASH)
+ oauth2_login_manager_ =
diff --git a/patch/patches/chrome_browser_safe_browsing.patch b/patch/patches/chrome_browser_safe_browsing.patch
new file mode 100644
index 00000000..82c9c3f1
--- /dev/null
+++ b/patch/patches/chrome_browser_safe_browsing.patch
@@ -0,0 +1,12 @@
+diff --git chrome/browser/safe_browsing/BUILD.gn chrome/browser/safe_browsing/BUILD.gn
+index da80c70f42a61..31441ecc1ee83 100644
+--- chrome/browser/safe_browsing/BUILD.gn
++++ chrome/browser/safe_browsing/BUILD.gn
+@@ -30,6 +30,7 @@ static_library("safe_browsing") {
+ "//components/browser_sync",
+ "//components/enterprise:enterprise",
+ "//components/enterprise/common:strings",
++ "//components/gcm_driver:gcm_buildflags",
+ "//components/keyed_service/content",
+ "//components/language/core/browser",
+ "//components/no_state_prefetch/browser",
diff --git a/patch/patches/chrome_browser_themes.patch b/patch/patches/chrome_browser_themes.patch
new file mode 100644
index 00000000..c1551ed9
--- /dev/null
+++ b/patch/patches/chrome_browser_themes.patch
@@ -0,0 +1,82 @@
+diff --git chrome/browser/themes/theme_service.cc chrome/browser/themes/theme_service.cc
+index 851cacf36cb21..217c38335903d 100644
+--- chrome/browser/themes/theme_service.cc
++++ chrome/browser/themes/theme_service.cc
+@@ -30,6 +30,7 @@
+ #include "base/task/thread_pool.h"
+ #include "base/trace_event/trace_event.h"
+ #include "build/build_config.h"
++#include "cef/libcef/features/runtime.h"
+ #include "chrome/browser/browser_features.h"
+ #include "chrome/browser/extensions/extension_service.h"
+ #include "chrome/browser/extensions/theme_installed_infobar_delegate.h"
+@@ -66,6 +67,10 @@
+ #include "ui/color/color_provider.h"
+ #include "ui/native_theme/native_theme.h"
+
++#if BUILDFLAG(ENABLE_CEF)
++#include "cef/libcef/common/extensions/extensions_util.h"
++#endif
++
+ #if BUILDFLAG(ENABLE_EXTENSIONS)
+ #include "base/scoped_observation.h"
+ #include "extensions/browser/extension_registry_observer.h"
+@@ -268,11 +273,19 @@ void ThemeService::Init() {
+ // OnExtensionServiceReady. Otherwise, the ThemeObserver won't be
+ // constructed in time to observe the corresponding events.
+ #if BUILDFLAG(ENABLE_EXTENSIONS)
++#if BUILDFLAG(ENABLE_CEF)
++ const bool extensions_disabled = cef::IsAlloyRuntimeEnabled() &&
++ !extensions::ExtensionsEnabled();
++#else
++ const bool extensions_disabled = false;
++#endif
++ if (!extensions_disabled) {
+ theme_observer_ = std::make_unique<ThemeObserver>(this);
+
+ extensions::ExtensionSystem::Get(profile_)->ready().Post(
+ FROM_HERE, base::BindOnce(&ThemeService::OnExtensionServiceReady,
+ weak_ptr_factory_.GetWeakPtr()));
++ }
+ #endif
+ theme_syncable_service_ =
+ std::make_unique<ThemeSyncableService>(profile_, this);
+diff --git chrome/browser/themes/theme_service_factory.cc chrome/browser/themes/theme_service_factory.cc
+index e3a7101326eee..c6592c0d5a1ba 100644
+--- chrome/browser/themes/theme_service_factory.cc
++++ chrome/browser/themes/theme_service_factory.cc
+@@ -7,6 +7,7 @@
+ #include "base/no_destructor.h"
+ #include "build/build_config.h"
+ #include "build/chromeos_buildflags.h"
++#include "cef/libcef/features/runtime.h"
+ #include "chrome/browser/extensions/extension_system_factory.h"
+ #include "chrome/browser/profiles/profile.h"
+ #include "chrome/browser/themes/theme_service.h"
+@@ -31,6 +32,10 @@
+ #include "ui/linux/linux_ui_factory.h"
+ #endif
+
++#if BUILDFLAG(ENABLE_CEF)
++#include "cef/libcef/common/extensions/extensions_util.h"
++#endif
++
+ namespace {
+
+ const ThemeHelper& GetThemeHelper() {
+@@ -74,7 +79,15 @@ ThemeServiceFactory::ThemeServiceFactory()
+ ProfileSelections::BuildRedirectedInIncognito()) {
+ DependsOn(extensions::ExtensionRegistryFactory::GetInstance());
+ DependsOn(extensions::ExtensionPrefsFactory::GetInstance());
++#if BUILDFLAG(ENABLE_CEF)
++ const bool extensions_disabled = cef::IsAlloyRuntimeEnabled() &&
++ !extensions::ExtensionsEnabled();
++#else
++ const bool extensions_disabled = false;
++#endif
++ if (!extensions_disabled) {
+ DependsOn(extensions::ExtensionSystemFactory::GetInstance());
++ }
+ }
+
+ ThemeServiceFactory::~ThemeServiceFactory() = default;
diff --git a/patch/patches/chrome_plugins.patch b/patch/patches/chrome_plugins.patch
new file mode 100644
index 00000000..b66fe9be
--- /dev/null
+++ b/patch/patches/chrome_plugins.patch
@@ -0,0 +1,141 @@
+diff --git chrome/browser/plugins/plugin_info_host_impl.cc chrome/browser/plugins/plugin_info_host_impl.cc
+index f59ecb8fa3246..bb55ea9d91a73 100644
+--- chrome/browser/plugins/plugin_info_host_impl.cc
++++ chrome/browser/plugins/plugin_info_host_impl.cc
+@@ -142,6 +142,10 @@ bool IsPluginLoadingAccessibleResourceInWebView(
+ extensions::ExtensionRegistry* extension_registry,
+ int process_id,
+ const GURL& resource) {
++ // May be nullptr if using CEF Alloy with extensions disabled.
++ if (!extension_registry)
++ return false;
++
+ extensions::WebViewRendererState* renderer_state =
+ extensions::WebViewRendererState::GetInstance();
+ std::string partition_id;
+diff --git chrome/browser/plugins/plugin_utils.cc chrome/browser/plugins/plugin_utils.cc
+index 8b3f569882aeb..afc8007a6228b 100644
+--- chrome/browser/plugins/plugin_utils.cc
++++ chrome/browser/plugins/plugin_utils.cc
+@@ -70,6 +70,13 @@ PluginUtils::GetMimeTypeToExtensionIdMap(
+ content::BrowserContext* browser_context) {
+ base::flat_map<std::string, std::string> mime_type_to_extension_id_map;
+ #if BUILDFLAG(ENABLE_EXTENSIONS)
++ // May be nullptr if using CEF Alloy with extensions disabled.
++ extensions::ExtensionRegistry* registry =
++ extensions::ExtensionRegistry::Get(browser_context);
++ if (!registry) {
++ return mime_type_to_extension_id_map;
++ }
++
+ Profile* profile = Profile::FromBrowserContext(browser_context);
+ if (extensions::ChromeContentBrowserClientExtensionsPart::
+ AreExtensionsDisabledForProfile(profile)) {
+@@ -80,9 +87,6 @@ PluginUtils::GetMimeTypeToExtensionIdMap(
+ MimeTypesHandler::GetMIMETypeAllowlist();
+ // Go through the allowed extensions and try to use them to intercept
+ // the URL request.
+- extensions::ExtensionRegistry* registry =
+- extensions::ExtensionRegistry::Get(browser_context);
+- DCHECK(registry);
+ for (const std::string& extension_id : allowlist) {
+ const extensions::Extension* extension =
+ registry->enabled_extensions().GetByID(extension_id);
+diff --git chrome/renderer/chrome_content_renderer_client.cc chrome/renderer/chrome_content_renderer_client.cc
+index eab276d6ebe23..aa6ca12d1b8bc 100644
+--- chrome/renderer/chrome_content_renderer_client.cc
++++ chrome/renderer/chrome_content_renderer_client.cc
+@@ -971,6 +971,7 @@ WebPlugin* ChromeContentRendererClient::CreatePlugin(
+
+ if ((status == chrome::mojom::PluginStatus::kUnauthorized ||
+ status == chrome::mojom::PluginStatus::kBlocked) &&
++ content_settings_agent_delegate &&
+ content_settings_agent_delegate->IsPluginTemporarilyAllowed(
+ identifier)) {
+ status = chrome::mojom::PluginStatus::kAllowed;
+@@ -1138,7 +1139,8 @@ WebPlugin* ChromeContentRendererClient::CreatePlugin(
+ render_frame->GetRemoteAssociatedInterfaces()->GetInterface(
+ plugin_auth_host.BindNewEndpointAndPassReceiver());
+ plugin_auth_host->BlockedUnauthorizedPlugin(group_name, identifier);
+- content_settings_agent->DidBlockContentType(content_type);
++ if (content_settings_agent)
++ content_settings_agent->DidBlockContentType(content_type);
+ break;
+ }
+ case chrome::mojom::PluginStatus::kBlocked: {
+@@ -1147,7 +1149,8 @@ WebPlugin* ChromeContentRendererClient::CreatePlugin(
+ l10n_util::GetStringFUTF16(IDS_PLUGIN_BLOCKED, group_name));
+ placeholder->AllowLoading();
+ RenderThread::Get()->RecordAction(UserMetricsAction("Plugin_Blocked"));
+- content_settings_agent->DidBlockContentType(content_type);
++ if (content_settings_agent)
++ content_settings_agent->DidBlockContentType(content_type);
+ break;
+ }
+ case chrome::mojom::PluginStatus::kBlockedByPolicy: {
+@@ -1157,7 +1160,8 @@ WebPlugin* ChromeContentRendererClient::CreatePlugin(
+ group_name));
+ RenderThread::Get()->RecordAction(
+ UserMetricsAction("Plugin_BlockedByPolicy"));
+- content_settings_agent->DidBlockContentType(content_type);
++ if (content_settings_agent)
++ content_settings_agent->DidBlockContentType(content_type);
+ break;
+ }
+ }
+diff --git content/browser/browser_plugin/browser_plugin_embedder.h content/browser/browser_plugin/browser_plugin_embedder.h
+index ad5f1925735fd..a871f4a7792a7 100644
+--- content/browser/browser_plugin/browser_plugin_embedder.h
++++ content/browser/browser_plugin/browser_plugin_embedder.h
+@@ -15,6 +15,7 @@
+ #define CONTENT_BROWSER_BROWSER_PLUGIN_BROWSER_PLUGIN_EMBEDDER_H_
+
+ #include "base/memory/raw_ptr.h"
++#include "content/common/content_export.h"
+
+ namespace content {
+
+@@ -26,7 +27,7 @@ struct NativeWebKeyboardEvent;
+
+ // TODO(wjmaclean): Get rid of "BrowserPlugin" in the name of this class.
+ // Perhaps "WebContentsEmbedderDelegate" would be better?
+-class BrowserPluginEmbedder {
++class CONTENT_EXPORT BrowserPluginEmbedder {
+ public:
+ BrowserPluginEmbedder(const BrowserPluginEmbedder&) = delete;
+ BrowserPluginEmbedder& operator=(const BrowserPluginEmbedder&) = delete;
+diff --git content/browser/browser_plugin/browser_plugin_guest.cc content/browser/browser_plugin/browser_plugin_guest.cc
+index a731c5ef5b714..99e313b92c242 100644
+--- content/browser/browser_plugin/browser_plugin_guest.cc
++++ content/browser/browser_plugin/browser_plugin_guest.cc
+@@ -80,6 +80,8 @@ void BrowserPluginGuest::InitInternal(WebContentsImpl* owner_web_contents) {
+ GetWebContents()->GetOrCreateWebPreferences();
+ prefs.navigate_on_drag_drop = false;
+ GetWebContents()->SetWebPreferences(prefs);
++
++ owner_web_contents_ = owner_web_contents;
+ }
+
+ BrowserPluginGuest::~BrowserPluginGuest() = default;
+diff --git content/browser/browser_plugin/browser_plugin_guest.h content/browser/browser_plugin/browser_plugin_guest.h
+index aec6a0eb9cbd0..286e7de6887a7 100644
+--- content/browser/browser_plugin/browser_plugin_guest.h
++++ content/browser/browser_plugin/browser_plugin_guest.h
+@@ -68,6 +68,8 @@ class BrowserPluginGuest : public WebContentsObserver {
+
+ WebContentsImpl* GetWebContents() const;
+
++ WebContentsImpl* owner_web_contents() const { return owner_web_contents_; }
++
+ private:
+ // BrowserPluginGuest is a WebContentsObserver of |web_contents| and
+ // |web_contents| has to stay valid for the lifetime of BrowserPluginGuest.
+@@ -77,6 +79,8 @@ class BrowserPluginGuest : public WebContentsObserver {
+ void InitInternal(WebContentsImpl* owner_web_contents);
+
+ const raw_ptr<BrowserPluginGuestDelegate, DanglingUntriaged> delegate_;
++
++ raw_ptr<WebContentsImpl> owner_web_contents_ = nullptr;
+ };
+
+ } // namespace content
diff --git a/patch/patches/chrome_pref_watcher.patch b/patch/patches/chrome_pref_watcher.patch
new file mode 100644
index 00000000..17c3c3a3
--- /dev/null
+++ b/patch/patches/chrome_pref_watcher.patch
@@ -0,0 +1,16 @@
+diff --git chrome/browser/ui/prefs/pref_watcher.h chrome/browser/ui/prefs/pref_watcher.h
+index 1027b73890375..4e310087dffce 100644
+--- chrome/browser/ui/prefs/pref_watcher.h
++++ chrome/browser/ui/prefs/pref_watcher.h
+@@ -30,10 +30,10 @@ class PrefWatcher : public KeyedService {
+ void RegisterRendererPreferenceWatcher(
+ mojo::PendingRemote<blink::mojom::RendererPreferenceWatcher> watcher);
+
+- private:
+ // KeyedService overrides:
+ void Shutdown() override;
+
++ private:
+ void UpdateRendererPreferences();
+ void OnWebPrefChanged(const std::string& pref_name);
+ void OnLiveCaptionEnabledPrefChanged(const std::string& pref_name);
diff --git a/patch/patches/chrome_renderer.patch b/patch/patches/chrome_renderer.patch
new file mode 100644
index 00000000..5979b2da
--- /dev/null
+++ b/patch/patches/chrome_renderer.patch
@@ -0,0 +1,31 @@
+diff --git chrome/renderer/BUILD.gn chrome/renderer/BUILD.gn
+index 6a646ba3e1975..8849ea7e53996 100644
+--- chrome/renderer/BUILD.gn
++++ chrome/renderer/BUILD.gn
+@@ -5,6 +5,7 @@
+ import("//build/config/buildflags_paint_preview.gni")
+ import("//build/config/chromeos/ui_mode.gni")
+ import("//build/config/features.gni")
++import("//cef/libcef/features/features.gni")
+ import("//chrome/common/features.gni")
+ import("//components/nacl/features.gni")
+ import("//components/offline_pages/buildflags/features.gni")
+@@ -124,6 +125,7 @@ static_library("renderer") {
+ deps = [
+ "//base/allocator:buildflags",
+ "//build:chromeos_buildflags",
++ "//cef/libcef/features",
+ "//chrome:resources",
+ "//chrome:strings",
+ "//chrome/common",
+@@ -221,6 +223,10 @@ static_library("renderer") {
+
+ configs += [ "//build/config/compiler:wexit_time_destructors" ]
+
++ if (enable_cef) {
++ configs += [ "//cef/libcef/features:config" ]
++ }
++
+ if (enable_nacl) {
+ deps += [ "//components/nacl/renderer" ]
+
diff --git a/patch/patches/chrome_runtime.patch b/patch/patches/chrome_runtime.patch
new file mode 100644
index 00000000..b2350c92
--- /dev/null
+++ b/patch/patches/chrome_runtime.patch
@@ -0,0 +1,384 @@
+diff --git chrome/app/chrome_main_delegate.cc chrome/app/chrome_main_delegate.cc
+index 6ecb3aeadd6e3..cdeca82d8bfe6 100644
+--- chrome/app/chrome_main_delegate.cc
++++ chrome/app/chrome_main_delegate.cc
+@@ -39,6 +39,7 @@
+ #include "base/trace_event/trace_event_impl.h"
+ #include "build/build_config.h"
+ #include "build/chromeos_buildflags.h"
++#include "cef/libcef/features/runtime.h"
+ #include "chrome/browser/chrome_content_browser_client.h"
+ #include "chrome/browser/chrome_resource_bundle_helper.h"
+ #include "chrome/browser/defaults.h"
+@@ -527,6 +528,8 @@ struct MainFunction {
+
+ // Initializes the user data dir. Must be called before InitializeLocalState().
+ void InitializeUserDataDir(base::CommandLine* command_line) {
++ if (cef::IsChromeRuntimeEnabled())
++ return;
+ #if BUILDFLAG(IS_WIN)
+ // Reach out to chrome_elf for the truth on the user data directory.
+ // Note that in tests, this links to chrome_elf_test_stubs.
+@@ -676,6 +679,10 @@ ChromeMainDelegate::~ChromeMainDelegate() {
+ ChromeMainDelegate::~ChromeMainDelegate() = default;
+ #endif // !BUILDFLAG(IS_ANDROID)
+
++void ChromeMainDelegate::CleanupOnUIThread() {
++ heap_profiler_controller_.reset();
++}
++
+ absl::optional<int> ChromeMainDelegate::PostEarlyInitialization(
+ InvokedIn invoked_in) {
+ DCHECK(base::ThreadPoolInstance::Get());
+@@ -959,7 +966,9 @@ void ChromeMainDelegate::CommonEarlyInitialization() {
+ }
+
+ #if BUILDFLAG(IS_WIN)
++ if (!cef::IsChromeRuntimeEnabled()) {
+ SetUpExtendedCrashReporting(is_browser_process);
++ }
+ base::sequence_manager::internal::ThreadControllerPowerMonitor::
+ InitializeOnMainThread();
+ base::InitializePlatformThreadFeatures();
+@@ -1324,6 +1333,7 @@ void ChromeMainDelegate::PreSandboxStartup() {
+ std::string process_type =
+ command_line.GetSwitchValueASCII(switches::kProcessType);
+
++ if (!cef::IsChromeRuntimeEnabled()) {
+ crash_reporter::InitializeCrashKeys();
+
+ #if BUILDFLAG(IS_POSIX)
+@@ -1334,6 +1344,7 @@ void ChromeMainDelegate::PreSandboxStartup() {
+ InitMacCrashReporter(command_line, process_type);
+ SetUpInstallerPreferences(command_line);
+ #endif
++ } // !cef::IsChromeRuntimeEnabled()
+
+ #if BUILDFLAG(IS_WIN)
+ child_process_logging::Init();
+@@ -1528,6 +1539,7 @@ void ChromeMainDelegate::PreSandboxStartup() {
+ CHECK(!loaded_locale.empty()) << "Locale could not be found for " << locale;
+ }
+
++ if (!cef::IsChromeRuntimeEnabled()) {
+ #if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC)
+ // Zygote needs to call InitCrashReporter() in RunZygote().
+ if (process_type != switches::kZygoteProcess) {
+@@ -1571,6 +1583,7 @@ void ChromeMainDelegate::PreSandboxStartup() {
+ // After all the platform Breakpads have been initialized, store the command
+ // line for crash reporting.
+ crash_keys::SetCrashKeysFromCommandLine(command_line);
++ } // !cef::IsChromeRuntimeEnabled()
+
+ #if BUILDFLAG(ENABLE_PDF)
+ MaybePatchGdiGetFontData();
+@@ -1672,6 +1685,7 @@ void ChromeMainDelegate::ZygoteForked() {
+ SetUpProfilingShutdownHandler();
+ }
+
++ if (!cef::IsChromeRuntimeEnabled()) {
+ // Needs to be called after we have chrome::DIR_USER_DATA. BrowserMain sets
+ // this up for the browser process in a different manner.
+ const base::CommandLine* command_line =
+@@ -1694,6 +1708,7 @@ void ChromeMainDelegate::ZygoteForked() {
+
+ // Reset the command line for the newly spawned process.
+ crash_keys::SetCrashKeysFromCommandLine(*command_line);
++ } // !cef::IsChromeRuntimeEnabled()
+ }
+
+ #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+diff --git chrome/app/chrome_main_delegate.h chrome/app/chrome_main_delegate.h
+index bfafb0a895b0f..f42ebc52d4a1a 100644
+--- chrome/app/chrome_main_delegate.h
++++ chrome/app/chrome_main_delegate.h
+@@ -52,6 +52,8 @@ class ChromeMainDelegate : public content::ContentMainDelegate {
+
+ ~ChromeMainDelegate() override;
+
++ virtual void CleanupOnUIThread();
++
+ protected:
+ // content::ContentMainDelegate:
+ absl::optional<int> BasicStartupComplete() override;
+diff --git chrome/browser/chrome_browser_main.cc chrome/browser/chrome_browser_main.cc
+index a09033cda2e09..df8f48d6d0403 100644
+--- chrome/browser/chrome_browser_main.cc
++++ chrome/browser/chrome_browser_main.cc
+@@ -51,6 +51,7 @@
+ #include "build/build_config.h"
+ #include "build/chromeos_buildflags.h"
+ #include "cc/base/switches.h"
++#include "cef/libcef/features/runtime.h"
+ #include "chrome/browser/about_flags.h"
+ #include "chrome/browser/active_use_util.h"
+ #include "chrome/browser/after_startup_task_utils.h"
+@@ -1473,7 +1474,7 @@ int ChromeBrowserMainParts::PreMainMessageLoopRunImpl() {
+ }
+ #endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_ASH)
+
+-#if BUILDFLAG(ENABLE_PROCESS_SINGLETON)
++#if BUILDFLAG(ENABLE_PROCESS_SINGLETON) && !BUILDFLAG(ENABLE_CEF)
+ // Handle special early return paths (which couldn't be processed even earlier
+ // as they require the process singleton to be held) first.
+
+@@ -1520,7 +1521,7 @@ int ChromeBrowserMainParts::PreMainMessageLoopRunImpl() {
+ return content::RESULT_CODE_NORMAL_EXIT;
+ #endif // BUILDFLAG(IS_WIN)
+ }
+-#endif // BUILDFLAG(ENABLE_PROCESS_SINGLETON)
++#endif // BUILDFLAG(ENABLE_PROCESS_SINGLETON) && !BUILDFLAG(ENABLE_CEF)
+
+ #if BUILDFLAG(IS_WIN)
+ // Check if there is any machine level Chrome installed on the current
+@@ -1573,12 +1574,14 @@ int ChromeBrowserMainParts::PreMainMessageLoopRunImpl() {
+ browser_process_->local_state());
+ }
+
++#if !BUILDFLAG(ENABLE_CEF)
+ // Needs to be done before PostProfileInit, since login manager on CrOS is
+ // called inside PostProfileInit.
+ content::WebUIControllerFactory::RegisterFactory(
+ ChromeWebUIControllerFactory::GetInstance());
+ RegisterChromeWebUIConfigs();
+ RegisterChromeUntrustedWebUIConfigs();
++#endif
+
+ #if BUILDFLAG(IS_ANDROID)
+ page_info::SetPageInfoClient(new ChromePageInfoClient());
+@@ -1727,6 +1730,10 @@ int ChromeBrowserMainParts::PreMainMessageLoopRunImpl() {
+ }
+ #endif // BUILDFLAG(IS_CHROMEOS_ASH)
+
++ // Bypass StartupBrowserCreator and RunLoop creation with CEF.
++ // CEF with the Chrome runtime will create and manage its own RunLoop.
++#if !BUILDFLAG(ENABLE_CEF)
++
+ // This step is costly and is already measured in
+ // Startup.StartupBrowserCreator_Start.
+ // See the comment above for an explanation of |process_command_line|.
+@@ -1765,11 +1772,14 @@ int ChromeBrowserMainParts::PreMainMessageLoopRunImpl() {
+
+ // Create the RunLoop for MainMessageLoopRun() to use and transfer
+ // ownership of the browser's lifetime to the BrowserProcess.
++ // CEF with the Chrome runtime will create and manage its own RunLoop.
+ DCHECK(!GetMainRunLoopInstance());
+ GetMainRunLoopInstance() = std::make_unique<base::RunLoop>();
+ browser_process_->SetQuitClosure(
+ GetMainRunLoopInstance()->QuitWhenIdleClosure());
+ }
++#endif // !BUILDFLAG(ENABLE_CEF)
++
+ browser_creator_.reset();
+ #endif // !BUILDFLAG(IS_ANDROID)
+
+diff --git chrome/browser/chrome_browser_main_mac.mm chrome/browser/chrome_browser_main_mac.mm
+index 194833d0bae43..21564d96466c0 100644
+--- chrome/browser/chrome_browser_main_mac.mm
++++ chrome/browser/chrome_browser_main_mac.mm
+@@ -17,6 +17,7 @@
+ #include "base/path_service.h"
+ #include "base/strings/sys_string_conversions.h"
+ #include "build/branding_buildflags.h"
++#include "cef/libcef/features/features.h"
+ #import "chrome/browser/app_controller_mac.h"
+ #include "chrome/browser/apps/app_shim/app_shim_listener.h"
+ #include "chrome/browser/browser_process.h"
+@@ -114,6 +115,7 @@ void ChromeBrowserMainPartsMac::PreCreateMainMessageLoop() {
+ }
+ #endif // !BUILDFLAG(CHROME_FOR_TESTING)
+
++#if !BUILDFLAG(ENABLE_CEF)
+ // Create the app delegate. This object is intentionally leaked as a global
+ // singleton. It is accessed through -[NSApp delegate].
+ AppController* app_controller = [[AppController alloc] init];
+@@ -122,6 +124,7 @@ void ChromeBrowserMainPartsMac::PreCreateMainMessageLoop() {
+ chrome::BuildMainMenu(NSApp, app_controller,
+ l10n_util::GetStringUTF16(IDS_PRODUCT_NAME), false);
+ [app_controller mainMenuCreated];
++#endif // BUILDFLAG(ENABLE_CEF)
+
+ ui::WarmScreenCapture();
+
+@@ -180,7 +183,9 @@ void ChromeBrowserMainPartsMac::PostProfileInit(Profile* profile,
+ }
+
+ void ChromeBrowserMainPartsMac::DidEndMainMessageLoop() {
++#if !BUILDFLAG(ENABLE_CEF)
+ AppController* appController =
+ base::mac::ObjCCastStrict<AppController>([NSApp delegate]);
+ [appController didEndMainMessageLoop];
++#endif
+ }
+diff --git chrome/browser/chrome_content_browser_client.cc chrome/browser/chrome_content_browser_client.cc
+index 6170a5656eb83..8d4ae07b4fd58 100644
+--- chrome/browser/chrome_content_browser_client.cc
++++ chrome/browser/chrome_content_browser_client.cc
+@@ -36,6 +36,7 @@
+ #include "base/values.h"
+ #include "build/build_config.h"
+ #include "build/chromeos_buildflags.h"
++#include "cef/libcef/features/features.h"
+ #include "chrome/browser/accessibility/accessibility_labels_service.h"
+ #include "chrome/browser/accessibility/accessibility_labels_service_factory.h"
+ #include "chrome/browser/after_startup_task_utils.h"
+@@ -1515,6 +1516,8 @@ void HandleStringData(
+ } // namespace
+
+ ChromeContentBrowserClient::ChromeContentBrowserClient() {
++ keepalive_timer_.reset(new base::OneShotTimer());
++
+ #if BUILDFLAG(ENABLE_PLUGINS)
+ extra_parts_.push_back(new ChromeContentBrowserClientPluginsPart);
+ #endif
+@@ -1540,6 +1543,11 @@ ChromeContentBrowserClient::~ChromeContentBrowserClient() {
+ extra_parts_.clear();
+ }
+
++void ChromeContentBrowserClient::CleanupOnUIThread() {
++ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
++ keepalive_timer_.reset();
++}
++
+ // static
+ void ChromeContentBrowserClient::RegisterLocalStatePrefs(
+ PrefRegistrySimple* registry) {
+@@ -4280,9 +4288,11 @@ void ChromeContentBrowserClient::BrowserURLHandlerCreated(
+ &search::HandleNewTabURLReverseRewrite);
+ #endif // BUILDFLAG(IS_ANDROID)
+
++#if !BUILDFLAG(ENABLE_CEF)
+ // chrome: & friends.
+ handler->AddHandlerPair(&ChromeContentBrowserClient::HandleWebUI,
+ &ChromeContentBrowserClient::HandleWebUIReverse);
++#endif
+ }
+
+ base::FilePath ChromeContentBrowserClient::GetDefaultDownloadDirectory() {
+@@ -6159,7 +6169,7 @@ void ChromeContentBrowserClient::OnNetworkServiceCreated(
+ network_service);
+ }
+
+-void ChromeContentBrowserClient::ConfigureNetworkContextParams(
++bool ChromeContentBrowserClient::ConfigureNetworkContextParams(
+ content::BrowserContext* context,
+ bool in_memory,
+ const base::FilePath& relative_partition_path,
+@@ -6177,6 +6187,8 @@ void ChromeContentBrowserClient::ConfigureNetworkContextParams(
+ network_context_params->user_agent = GetUserAgentBasedOnPolicy(context);
+ network_context_params->accept_language = GetApplicationLocale();
+ }
++
++ return true;
+ }
+
+ std::vector<base::FilePath>
+@@ -7083,10 +7095,10 @@ void ChromeContentBrowserClient::OnKeepaliveRequestStarted(
+ const auto now = base::TimeTicks::Now();
+ const auto timeout = GetKeepaliveTimerTimeout(context);
+ keepalive_deadline_ = std::max(keepalive_deadline_, now + timeout);
+- if (keepalive_deadline_ > now && !keepalive_timer_.IsRunning()) {
++ if (keepalive_deadline_ > now && !keepalive_timer_->IsRunning()) {
+ DVLOG(1) << "Starting a keepalive timer(" << timeout.InSecondsF()
+ << " seconds)";
+- keepalive_timer_.Start(
++ keepalive_timer_->Start(
+ FROM_HERE, keepalive_deadline_ - now,
+ base::BindOnce(
+ &ChromeContentBrowserClient::OnKeepaliveTimerFired,
+@@ -7105,7 +7117,8 @@ void ChromeContentBrowserClient::OnKeepaliveRequestFinished() {
+ --num_keepalive_requests_;
+ if (num_keepalive_requests_ == 0) {
+ DVLOG(1) << "Stopping the keepalive timer";
+- keepalive_timer_.Stop();
++ if (keepalive_timer_)
++ keepalive_timer_->Stop();
+ // This deletes the keep alive handle attached to the timer function and
+ // unblock the shutdown sequence.
+ }
+@@ -7241,7 +7254,7 @@ void ChromeContentBrowserClient::OnKeepaliveTimerFired(
+ const auto now = base::TimeTicks::Now();
+ const auto then = keepalive_deadline_;
+ if (now < then) {
+- keepalive_timer_.Start(
++ keepalive_timer_->Start(
+ FROM_HERE, then - now,
+ base::BindOnce(&ChromeContentBrowserClient::OnKeepaliveTimerFired,
+ weak_factory_.GetWeakPtr(),
+diff --git chrome/browser/chrome_content_browser_client.h chrome/browser/chrome_content_browser_client.h
+index 071a3dd11e61b..7b15b6f4abb24 100644
+--- chrome/browser/chrome_content_browser_client.h
++++ chrome/browser/chrome_content_browser_client.h
+@@ -121,6 +121,8 @@ class ChromeContentBrowserClient : public content::ContentBrowserClient {
+
+ ~ChromeContentBrowserClient() override;
+
++ virtual void CleanupOnUIThread();
++
+ // TODO(https://crbug.com/787567): This file is about calls from content/ out
+ // to chrome/ to get values or notify about events, but both of these
+ // functions are from chrome/ to chrome/ and don't involve content/ at all.
+@@ -601,7 +603,7 @@ class ChromeContentBrowserClient : public content::ContentBrowserClient {
+ override;
+ void OnNetworkServiceCreated(
+ network::mojom::NetworkService* network_service) override;
+- void ConfigureNetworkContextParams(
++ bool ConfigureNetworkContextParams(
+ content::BrowserContext* context,
+ bool in_memory,
+ const base::FilePath& relative_partition_path,
+@@ -962,7 +964,7 @@ class ChromeContentBrowserClient : public content::ContentBrowserClient {
+
+ #if !BUILDFLAG(IS_ANDROID)
+ uint64_t num_keepalive_requests_ = 0;
+- base::OneShotTimer keepalive_timer_;
++ std::unique_ptr<base::OneShotTimer> keepalive_timer_;
+ base::TimeTicks keepalive_deadline_;
+ #endif
+
+diff --git chrome/browser/prefs/browser_prefs.cc chrome/browser/prefs/browser_prefs.cc
+index 193d174d20d45..9b8d8a6b4a051 100644
+--- chrome/browser/prefs/browser_prefs.cc
++++ chrome/browser/prefs/browser_prefs.cc
+@@ -11,6 +11,7 @@
+ #include "build/build_config.h"
+ #include "build/chromecast_buildflags.h"
+ #include "build/chromeos_buildflags.h"
++#include "cef/libcef/features/features.h"
+ #include "chrome/browser/about_flags.h"
+ #include "chrome/browser/accessibility/accessibility_labels_service.h"
+ #include "chrome/browser/accessibility/accessibility_ui.h"
+@@ -172,6 +173,10 @@
+ #include "chrome/browser/background/background_mode_manager.h"
+ #endif
+
++#if BUILDFLAG(ENABLE_CEF)
++#include "cef/libcef/browser/prefs/browser_prefs.h"
++#endif
++
+ #if BUILDFLAG(ENABLE_EXTENSIONS)
+ #include "chrome/browser/accessibility/animation_policy_prefs.h"
+ #include "chrome/browser/apps/platform_apps/shortcut_manager.h"
+@@ -1366,6 +1371,11 @@ void RegisterLocalState(PrefRegistrySimple* registry) {
+
+ // This is intentionally last.
+ RegisterLocalStatePrefsForMigration(registry);
++
++#if BUILDFLAG(ENABLE_CEF)
++ // Always call this last.
++ browser_prefs::RegisterLocalStatePrefs(registry);
++#endif
+ }
+
+ // Register prefs applicable to all profiles.
+@@ -1761,6 +1771,10 @@ void RegisterUserProfilePrefs(user_prefs::PrefRegistrySyncable* registry,
+ const std::string& locale) {
+ RegisterProfilePrefs(registry, locale);
+
++#if BUILDFLAG(ENABLE_CEF)
++ browser_prefs::RegisterProfilePrefs(registry);
++#endif
++
+ #if BUILDFLAG(IS_ANDROID)
+ ::android::RegisterUserProfilePrefs(registry);
+ #endif
diff --git a/patch/patches/chrome_runtime_views.patch b/patch/patches/chrome_runtime_views.patch
new file mode 100644
index 00000000..a86a40f3
--- /dev/null
+++ b/patch/patches/chrome_runtime_views.patch
@@ -0,0 +1,515 @@
+diff --git chrome/browser/ui/browser_command_controller.cc chrome/browser/ui/browser_command_controller.cc
+index 100baefb933be..4e1501387aa6c 100644
+--- chrome/browser/ui/browser_command_controller.cc
++++ chrome/browser/ui/browser_command_controller.cc
+@@ -390,6 +390,7 @@ bool BrowserCommandController::ExecuteCommandWithDisposition(
+ // choose to not implement CommandUpdaterDelegate inside this class and
+ // therefore command_updater_ doesn't have the delegate set).
+ if (!SupportsCommand(id) || !IsCommandEnabled(id)) {
++ LOG(WARNING) << "Invalid/disabled command " << id;
+ return false;
+ }
+
+@@ -406,6 +407,13 @@ bool BrowserCommandController::ExecuteCommandWithDisposition(
+ DCHECK(command_updater_.IsCommandEnabled(id))
+ << "Invalid/disabled command " << id;
+
++#if BUILDFLAG(ENABLE_CEF)
++ if (browser_->cef_delegate() &&
++ browser_->cef_delegate()->HandleCommand(id, disposition)) {
++ return true;
++ }
++#endif
++
+ // The order of commands in this switch statement must match the function
+ // declaration order in browser.h!
+ switch (id) {
+@@ -1040,11 +1048,13 @@ void BrowserCommandController::TabRestoreServiceLoaded(
+ // BrowserCommandController, private:
+
+ bool BrowserCommandController::IsShowingMainUI() {
+- return browser_->SupportsWindowFeature(Browser::FEATURE_TABSTRIP);
++ return browser_->SupportsWindowFeature(Browser::FEATURE_TABSTRIP) ||
++ browser_->toolbar_overridden();
+ }
+
+ bool BrowserCommandController::IsShowingLocationBar() {
+- return browser_->SupportsWindowFeature(Browser::FEATURE_LOCATIONBAR);
++ return browser_->SupportsWindowFeature(Browser::FEATURE_LOCATIONBAR) ||
++ browser_->toolbar_overridden();
+ }
+
+ bool BrowserCommandController::IsWebAppOrCustomTab() const {
+diff --git chrome/browser/ui/views/frame/browser_frame.cc chrome/browser/ui/views/frame/browser_frame.cc
+index 1b8cd7a3ff295..b837a9379bd04 100644
+--- chrome/browser/ui/views/frame/browser_frame.cc
++++ chrome/browser/ui/views/frame/browser_frame.cc
+@@ -67,15 +67,23 @@ bool IsUsingLinuxSystemTheme(Profile* profile) {
+ ////////////////////////////////////////////////////////////////////////////////
+ // BrowserFrame, public:
+
++BrowserFrame::BrowserFrame() : BrowserFrame(nullptr) {}
++
+ BrowserFrame::BrowserFrame(BrowserView* browser_view)
+ : native_browser_frame_(nullptr),
+ root_view_(nullptr),
+ browser_frame_view_(nullptr),
+- browser_view_(browser_view) {
+- browser_view_->set_frame(this);
++ browser_view_(nullptr) {
+ set_is_secondary_widget(false);
+ // Don't focus anything on creation, selecting a tab will set the focus.
+ set_focus_on_creation(false);
++ if (browser_view)
++ InitBrowserView(browser_view);
++}
++
++void BrowserFrame::InitBrowserView(BrowserView* browser_view) {
++ browser_view_ = browser_view;
++ browser_view_->set_frame(this);
+ }
+
+ BrowserFrame::~BrowserFrame() {}
+@@ -147,6 +155,12 @@ gfx::Rect BrowserFrame::GetBoundsForTabStripRegion(
+ }
+
+ int BrowserFrame::GetTopInset() const {
++ if (!browser_frame_view_) {
++ // With CEF the browser may already be part of a larger Views layout. Zero
++ // out the adjustment in BrowserView::GetTopInsetInBrowserView() so that
++ // the browser isn't shifted to the top of the window.
++ return browser_view_->y();
++ }
+ return browser_frame_view_->GetTopInset(false);
+ }
+
+@@ -163,6 +177,8 @@ BrowserNonClientFrameView* BrowserFrame::GetFrameView() const {
+ }
+
+ bool BrowserFrame::UseCustomFrame() const {
++ if (!native_browser_frame_)
++ return true;
+ return native_browser_frame_->UseCustomFrame();
+ }
+
+@@ -176,20 +192,30 @@ bool BrowserFrame::ShouldDrawFrameHeader() const {
+
+ void BrowserFrame::GetWindowPlacement(gfx::Rect* bounds,
+ ui::WindowShowState* show_state) const {
++ if (!native_browser_frame_) {
++ *show_state = ui::SHOW_STATE_DEFAULT;
++ return;
++ }
+ return native_browser_frame_->GetWindowPlacement(bounds, show_state);
+ }
+
+ content::KeyboardEventProcessingResult BrowserFrame::PreHandleKeyboardEvent(
+ const content::NativeWebKeyboardEvent& event) {
++ if (!native_browser_frame_)
++ return content::KeyboardEventProcessingResult::NOT_HANDLED;
+ return native_browser_frame_->PreHandleKeyboardEvent(event);
+ }
+
+ bool BrowserFrame::HandleKeyboardEvent(
+ const content::NativeWebKeyboardEvent& event) {
++ if (!native_browser_frame_)
++ return false;
+ return native_browser_frame_->HandleKeyboardEvent(event);
+ }
+
+ void BrowserFrame::OnBrowserViewInitViewsComplete() {
++ if (!browser_frame_view_)
++ return;
+ browser_frame_view_->OnBrowserViewInitViewsComplete();
+ }
+
+@@ -251,7 +277,7 @@ const ui::ThemeProvider* BrowserFrame::GetThemeProvider() const {
+ ui::ColorProviderManager::ThemeInitializerSupplier*
+ BrowserFrame::GetCustomTheme() const {
+ // Do not return any custom theme if the browser has to use the dark theme.
+- if (ShouldUseDarkTheme())
++ if (ShouldUseDarkTheme() || !browser_view_)
+ return nullptr;
+
+ Browser* browser = browser_view_->browser();
+@@ -268,6 +294,8 @@ BrowserFrame::GetCustomTheme() const {
+ }
+
+ void BrowserFrame::OnNativeWidgetWorkspaceChanged() {
++ if (!browser_view_)
++ return;
+ chrome::SaveWindowWorkspace(browser_view_->browser(), GetWorkspace());
+ chrome::SaveWindowVisibleOnAllWorkspaces(browser_view_->browser(),
+ IsVisibleOnAllWorkspaces());
+@@ -355,6 +383,8 @@ void BrowserFrame::SetTabDragKind(TabDragKind tab_drag_kind) {
+
+ ui::ColorProviderManager::Key BrowserFrame::GetColorProviderKey() const {
+ auto key = Widget::GetColorProviderKey();
++ if (!browser_view_)
++ return key;
+ key.frame_type = UseCustomFrame()
+ ? ui::ColorProviderManager::FrameType::kChromium
+ : ui::ColorProviderManager::FrameType::kNative;
+@@ -441,5 +471,7 @@ bool BrowserFrame::RegenerateFrameOnThemeChange(
+ }
+
+ bool BrowserFrame::ShouldUseDarkTheme() const {
++ if (!browser_view_)
++ return false;
+ return browser_view_->browser()->profile()->IsIncognitoProfile();
+ }
+diff --git chrome/browser/ui/views/frame/browser_frame.h chrome/browser/ui/views/frame/browser_frame.h
+index 28085aa32d7d8..312911b8a4564 100644
+--- chrome/browser/ui/views/frame/browser_frame.h
++++ chrome/browser/ui/views/frame/browser_frame.h
+@@ -56,7 +56,9 @@ enum class TabDragKind {
+ // This is a virtual interface that allows system specific browser frames.
+ class BrowserFrame : public views::Widget, public views::ContextMenuController {
+ public:
++ BrowserFrame();
+ explicit BrowserFrame(BrowserView* browser_view);
++ void InitBrowserView(BrowserView* browser_view);
+
+ BrowserFrame(const BrowserFrame&) = delete;
+ BrowserFrame& operator=(const BrowserFrame&) = delete;
+diff --git chrome/browser/ui/views/frame/browser_view.cc chrome/browser/ui/views/frame/browser_view.cc
+index 8d1be7ef7470a..0a38b76e20597 100644
+--- chrome/browser/ui/views/frame/browser_view.cc
++++ chrome/browser/ui/views/frame/browser_view.cc
+@@ -307,11 +307,10 @@ using content::NativeWebKeyboardEvent;
+ using content::WebContents;
+ using web_modal::WebContentsModalDialogHost;
+
+-namespace {
++// static
++const char BrowserView::kBrowserViewKey[] = "__BROWSER_VIEW__";
+
+-// The name of a key to store on the window handle so that other code can
+-// locate this object using just the handle.
+-const char* const kBrowserViewKey = "__BROWSER_VIEW__";
++namespace {
+
+ #if BUILDFLAG(IS_CHROMEOS_ASH)
+ // UMA histograms that record animation smoothness for tab loading animation.
+@@ -826,11 +825,22 @@ class BrowserView::SidePanelVisibilityController : public views::ViewObserver {
+ ///////////////////////////////////////////////////////////////////////////////
+ // BrowserView, public:
+
++BrowserView::BrowserView() : BrowserView(nullptr) {}
++
+ BrowserView::BrowserView(std::unique_ptr<Browser> browser)
+ : views::ClientView(nullptr, nullptr),
+- browser_(std::move(browser)),
+ accessibility_mode_observer_(
+ std::make_unique<AccessibilityModeObserver>(this)) {
++ if (browser)
++ InitBrowser(std::move(browser));
++}
++
++void BrowserView::InitBrowser(std::unique_ptr<Browser> browser) {
++ DCHECK(!browser_);
++ browser_ = std::move(browser);
++
++ immersive_mode_controller_ = chrome::CreateImmersiveModeController(this);
++
+ SetShowIcon(
+ ::ShouldShowWindowIcon(browser_.get(), AppUsesWindowControlsOverlay()));
+
+@@ -874,7 +884,6 @@ BrowserView::BrowserView(std::unique_ptr<Browser> browser)
+ }
+
+ browser_->tab_strip_model()->AddObserver(this);
+- immersive_mode_controller_ = chrome::CreateImmersiveModeController(this);
+
+ // Top container holds tab strip region and toolbar and lives at the front of
+ // the view hierarchy.
+@@ -920,8 +929,15 @@ BrowserView::BrowserView(std::unique_ptr<Browser> browser)
+ contents_container->SetLayoutManager(std::make_unique<ContentsLayoutManager>(
+ devtools_web_view_, contents_web_view_));
+
+- toolbar_ = top_container_->AddChildView(
+- std::make_unique<ToolbarView>(browser_.get(), this));
++ toolbar_ = OverrideCreateToolbar(browser_.get(), this);
++ if (!toolbar_) {
++ toolbar_ = new ToolbarView(browser_.get(), this, absl::nullopt);
++ } else {
++ browser_->set_toolbar_overridden(true);
++ // Update state that depends on the above flag.
++ browser_->command_controller()->FullscreenStateChanged();
++ }
++ top_container_->AddChildView(base::WrapUnique(toolbar_.get()));
+
+ contents_separator_ =
+ top_container_->AddChildView(std::make_unique<ContentsSeparator>());
+@@ -1841,6 +1857,8 @@ bool BrowserView::ShouldHideUIForFullscreen() const {
+ if (immersive_mode_controller_->IsEnabled())
+ return false;
+
++ if (!frame_->GetFrameView())
++ return false;
+ return frame_->GetFrameView()->ShouldHideTopUIForFullscreen();
+ }
+
+@@ -2736,7 +2754,8 @@ DownloadShelf* BrowserView::GetDownloadShelf() {
+ }
+
+ DownloadBubbleUIController* BrowserView::GetDownloadBubbleUIController() {
+- DCHECK(toolbar_button_provider_);
++ if (!toolbar_button_provider_)
++ return nullptr;
+ if (auto* download_button = toolbar_button_provider_->GetDownloadButton())
+ return download_button->bubble_controller();
+ return nullptr;
+@@ -3228,7 +3247,8 @@ void BrowserView::ReparentTopContainerForEndOfImmersive() {
+ if (top_container()->parent() == this)
+ return;
+
+- overlay_view_->SetVisible(false);
++ if (overlay_view_)
++ overlay_view_->SetVisible(false);
+ top_container()->DestroyLayer();
+ AddChildViewAt(top_container(), 0);
+ EnsureFocusOrder();
+@@ -3767,8 +3787,10 @@ void BrowserView::Layout() {
+
+ // TODO(jamescook): Why was this in the middle of layout code?
+ toolbar_->location_bar()->omnibox_view()->SetFocusBehavior(
+- IsToolbarVisible() ? FocusBehavior::ALWAYS : FocusBehavior::NEVER);
+- frame()->GetFrameView()->UpdateMinimumSize();
++ (IsToolbarVisible() || browser_->toolbar_overridden()) ?
++ FocusBehavior::ALWAYS : FocusBehavior::NEVER);
++ if (frame()->GetFrameView())
++ frame()->GetFrameView()->UpdateMinimumSize();
+
+ // Some of the situations when the BrowserView is laid out are:
+ // - Enter/exit immersive fullscreen mode.
+@@ -3834,6 +3856,11 @@ void BrowserView::AddedToWidget() {
+ SetThemeProfileForWindow(GetNativeWindow(), browser_->profile());
+ #endif
+
++ // This browser view may already have a custom button provider set (e.g the
++ // hosted app frame).
++ if (!toolbar_button_provider_)
++ SetToolbarButtonProvider(toolbar_);
++
+ toolbar_->Init();
+
+ // TODO(pbos): Manage this either inside SidePanel or the corresponding button
+@@ -3889,13 +3916,9 @@ void BrowserView::AddedToWidget() {
+
+ EnsureFocusOrder();
+
+- // This browser view may already have a custom button provider set (e.g the
+- // hosted app frame).
+- if (!toolbar_button_provider_)
+- SetToolbarButtonProvider(toolbar_);
+-
+ frame_->OnBrowserViewInitViewsComplete();
+- frame_->GetFrameView()->UpdateMinimumSize();
++ if (frame_->GetFrameView())
++ frame_->GetFrameView()->UpdateMinimumSize();
+ using_native_frame_ = frame_->ShouldUseNativeFrame();
+
+ MaybeInitializeWebUITabStrip();
+@@ -4304,7 +4327,8 @@ void BrowserView::ProcessFullscreen(bool fullscreen,
+ // Undo our anti-jankiness hacks and force a re-layout.
+ in_process_fullscreen_ = false;
+ ToolbarSizeChanged(false);
+- frame_->GetFrameView()->OnFullscreenStateChanged();
++ if (frame_->GetFrameView())
++ frame_->GetFrameView()->OnFullscreenStateChanged();
+ }
+
+ bool BrowserView::ShouldUseImmersiveFullscreenForUrl(const GURL& url) const {
+@@ -4652,6 +4676,8 @@ Profile* BrowserView::GetProfile() {
+ }
+
+ void BrowserView::UpdateUIForTabFullscreen() {
++ if (!frame_->GetFrameView())
++ return;
+ frame()->GetFrameView()->UpdateFullscreenTopUI();
+ }
+
+@@ -4674,6 +4700,8 @@ void BrowserView::HideDownloadShelf() {
+ }
+
+ bool BrowserView::CanUserExitFullscreen() const {
++ if (!frame_->GetFrameView())
++ return true;
+ return frame_->GetFrameView()->CanUserExitFullscreen();
+ }
+
+diff --git chrome/browser/ui/views/frame/browser_view.h chrome/browser/ui/views/frame/browser_view.h
+index 673e626f60cd4..1444e9db81cfc 100644
+--- chrome/browser/ui/views/frame/browser_view.h
++++ chrome/browser/ui/views/frame/browser_view.h
+@@ -124,11 +124,16 @@ class BrowserView : public BrowserWindow,
+ public webapps::AppBannerManager::Observer {
+ public:
+ METADATA_HEADER(BrowserView);
++ BrowserView();
+ explicit BrowserView(std::unique_ptr<Browser> browser);
++ void InitBrowser(std::unique_ptr<Browser> browser);
+ BrowserView(const BrowserView&) = delete;
+ BrowserView& operator=(const BrowserView&) = delete;
+ ~BrowserView() override;
+
++ // Key used to bind BrowserView to the Widget with which it is associated.
++ static const char kBrowserViewKey[];
++
+ void set_frame(BrowserFrame* frame) {
+ frame_ = frame;
+ paint_as_active_subscription_ =
+@@ -777,6 +782,12 @@ class BrowserView : public BrowserWindow,
+ void SetLoadingAnimationStateChangeClosureForTesting(
+ base::OnceClosure closure);
+
++ protected:
++ virtual ToolbarView* OverrideCreateToolbar(Browser* browser,
++ BrowserView* browser_view) {
++ return nullptr;
++ }
++
+ private:
+ // Do not friend BrowserViewLayout. Use the BrowserViewLayoutDelegate
+ // interface to keep these two classes decoupled and testable.
+diff --git chrome/browser/ui/views/frame/browser_view_layout.cc chrome/browser/ui/views/frame/browser_view_layout.cc
+index 991e095456a35..2373048a30123 100644
+--- chrome/browser/ui/views/frame/browser_view_layout.cc
++++ chrome/browser/ui/views/frame/browser_view_layout.cc
+@@ -46,6 +46,10 @@
+ #include "ui/views/widget/widget.h"
+ #include "ui/views/window/client_view.h"
+
++#if BUILDFLAG(ENABLE_CEF)
++#include "cef/libcef/browser/chrome/views/chrome_views_util.h"
++#endif
++
+ using views::View;
+ using web_modal::ModalDialogHostObserver;
+ using web_modal::WebContentsModalDialogHost;
+@@ -466,6 +470,13 @@ int BrowserViewLayout::LayoutWebUITabStrip(int top) {
+
+ int BrowserViewLayout::LayoutToolbar(int top) {
+ TRACE_EVENT0("ui", "BrowserViewLayout::LayoutToolbar");
++#if BUILDFLAG(ENABLE_CEF)
++ if (cef::IsCefView(toolbar_)) {
++ // CEF may take ownership of the toolbar. Early exit to avoid the DCHECK
++ // in LayoutManager::SetViewVisibility().
++ return top;
++ }
++#endif
+ int browser_view_width = vertical_layout_rect_.width();
+ bool toolbar_visible = delegate_->IsToolbarVisible();
+ int height = toolbar_visible ? toolbar_->GetPreferredSize().height() : 0;
+diff --git chrome/browser/ui/views/frame/contents_web_view.cc chrome/browser/ui/views/frame/contents_web_view.cc
+index 5e059b9878fc2..c1f6fbcd40ec4 100644
+--- chrome/browser/ui/views/frame/contents_web_view.cc
++++ chrome/browser/ui/views/frame/contents_web_view.cc
+@@ -26,6 +26,11 @@
+ ContentsWebView::ContentsWebView(content::BrowserContext* browser_context)
+ : views::WebView(browser_context),
+ status_bubble_(nullptr) {
++ // Mouse events on draggable regions will not be handled by the WebView.
++ // Avoid the resulting DCHECK in NativeViewHost::OnMousePressed by
++ // configuring the NativeViewHost not to process events via the view
++ // hierarchy.
++ holder()->SetCanProcessEventsWithinSubtree(false);
+ }
+
+ ContentsWebView::~ContentsWebView() {
+diff --git chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
+index 4f04525fafb8e..eea2013607200 100644
+--- chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
++++ chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
+@@ -564,33 +564,47 @@ gfx::Range BrowserTabStripController::ListTabsInGroup(
+ }
+
+ bool BrowserTabStripController::IsFrameCondensed() const {
++ if (!GetFrameView())
++ return false;
+ return GetFrameView()->IsFrameCondensed();
+ }
+
+ bool BrowserTabStripController::HasVisibleBackgroundTabShapes() const {
++ if (!GetFrameView())
++ return false;
+ return GetFrameView()->HasVisibleBackgroundTabShapes(
+ BrowserFrameActiveState::kUseCurrent);
+ }
+
+ bool BrowserTabStripController::EverHasVisibleBackgroundTabShapes() const {
++ if (!GetFrameView())
++ return false;
+ return GetFrameView()->EverHasVisibleBackgroundTabShapes();
+ }
+
+ bool BrowserTabStripController::ShouldPaintAsActiveFrame() const {
++ if (!GetFrameView())
++ return false;
+ return GetFrameView()->ShouldPaintAsActive();
+ }
+
+ bool BrowserTabStripController::CanDrawStrokes() const {
++ if (!GetFrameView())
++ return false;
+ return GetFrameView()->CanDrawStrokes();
+ }
+
+ SkColor BrowserTabStripController::GetFrameColor(
+ BrowserFrameActiveState active_state) const {
++ if (!GetFrameView())
++ return SK_ColorWHITE;
+ return GetFrameView()->GetFrameColor(active_state);
+ }
+
+ absl::optional<int> BrowserTabStripController::GetCustomBackgroundId(
+ BrowserFrameActiveState active_state) const {
++ if (!GetFrameView())
++ return absl::nullopt;
+ return GetFrameView()->GetCustomBackgroundId(active_state);
+ }
+
+diff --git chrome/browser/ui/views/toolbar/toolbar_view.cc chrome/browser/ui/views/toolbar/toolbar_view.cc
+index 46ce747cfdec8..99a718aaffe01 100644
+--- chrome/browser/ui/views/toolbar/toolbar_view.cc
++++ chrome/browser/ui/views/toolbar/toolbar_view.cc
+@@ -164,12 +164,13 @@ auto& GetViewCommandMap() {
+ ////////////////////////////////////////////////////////////////////////////////
+ // ToolbarView, public:
+
+-ToolbarView::ToolbarView(Browser* browser, BrowserView* browser_view)
++ToolbarView::ToolbarView(Browser* browser, BrowserView* browser_view,
++ absl::optional<DisplayMode> display_mode)
+ : AnimationDelegateViews(this),
+ browser_(browser),
+ browser_view_(browser_view),
+ app_menu_icon_controller_(browser->profile(), this),
+- display_mode_(GetDisplayMode(browser)) {
++ display_mode_(display_mode ? *display_mode : GetDisplayMode(browser)) {
+ SetID(VIEW_ID_TOOLBAR);
+
+ if (display_mode_ == DisplayMode::NORMAL) {
+@@ -200,7 +201,7 @@ void ToolbarView::Init() {
+ #endif
+ auto location_bar = std::make_unique<LocationBarView>(
+ browser_, browser_->profile(), browser_->command_controller(), this,
+- display_mode_ != DisplayMode::NORMAL);
++ display_mode_ != DisplayMode::NORMAL && !browser_->toolbar_overridden());
+ // Make sure the toolbar shows by default.
+ size_animation_.Reset(1);
+
+diff --git chrome/browser/ui/views/toolbar/toolbar_view.h chrome/browser/ui/views/toolbar/toolbar_view.h
+index 8c2ea74023637..a24cab7c58f93 100644
+--- chrome/browser/ui/views/toolbar/toolbar_view.h
++++ chrome/browser/ui/views/toolbar/toolbar_view.h
+@@ -92,7 +92,8 @@ class ToolbarView : public views::AccessiblePaneView,
+ // needs to be displayed.
+ };
+
+- ToolbarView(Browser* browser, BrowserView* browser_view);
++ ToolbarView(Browser* browser, BrowserView* browser_view,
++ absl::optional<DisplayMode> display_mode);
+ ToolbarView(const ToolbarView&) = delete;
+ ToolbarView& operator=(const ToolbarView&) = delete;
+ ~ToolbarView() override;
diff --git a/patch/patches/chrome_utility_client.patch b/patch/patches/chrome_utility_client.patch
new file mode 100644
index 00000000..0612c600
--- /dev/null
+++ b/patch/patches/chrome_utility_client.patch
@@ -0,0 +1,22 @@
+diff --git chrome/utility/chrome_content_utility_client.cc chrome/utility/chrome_content_utility_client.cc
+index 6413d01cb4b41..b38eb084d8508 100644
+--- chrome/utility/chrome_content_utility_client.cc
++++ chrome/utility/chrome_content_utility_client.cc
+@@ -13,6 +13,7 @@
+ #include "base/path_service.h"
+ #include "base/task/single_thread_task_runner.h"
+ #include "build/build_config.h"
++#include "cef/libcef/features/runtime.h"
+ #include "chrome/common/chrome_paths.h"
+ #include "chrome/common/profiler/thread_profiler.h"
+ #include "chrome/common/profiler/thread_profiler_configuration.h"
+@@ -57,7 +58,8 @@ void ChromeContentUtilityClient::UtilityThreadStarted() {
+ command_line->GetSwitchValueASCII(switches::kProcessType);
+ // An in-process utility thread may run in other processes, only set up
+ // collector in a utility process.
+- if (process_type == switches::kUtilityProcess) {
++ if (process_type == switches::kUtilityProcess &&
++ !cef::IsAlloyRuntimeEnabled()) {
+ // The HeapProfilerController should have been created in
+ // ChromeMainDelegate::PostEarlyInitialization.
+ using HeapProfilerController = heap_profiling::HeapProfilerController;
diff --git a/patch/patches/component_build.patch b/patch/patches/component_build.patch
new file mode 100644
index 00000000..6e8b363a
--- /dev/null
+++ b/patch/patches/component_build.patch
@@ -0,0 +1,124 @@
+diff --git content/browser/devtools/devtools_instrumentation.h content/browser/devtools/devtools_instrumentation.h
+index 7ea19dc8d32eb..f592668272a41 100644
+--- content/browser/devtools/devtools_instrumentation.h
++++ content/browser/devtools/devtools_instrumentation.h
+@@ -102,7 +102,7 @@ bool ApplyUserAgentMetadataOverrides(
+ FrameTreeNode* frame_tree_node,
+ absl::optional<blink::UserAgentMetadata>* override_out);
+
+-bool WillCreateURLLoaderFactory(
++CONTENT_EXPORT bool WillCreateURLLoaderFactory(
+ RenderFrameHostImpl* rfh,
+ bool is_navigation,
+ bool is_download,
+diff --git content/browser/renderer_host/input/mouse_wheel_phase_handler.h content/browser/renderer_host/input/mouse_wheel_phase_handler.h
+index d69f9d4641613..e88aaf8617c52 100644
+--- content/browser/renderer_host/input/mouse_wheel_phase_handler.h
++++ content/browser/renderer_host/input/mouse_wheel_phase_handler.h
+@@ -9,6 +9,7 @@
+ #include "base/time/time.h"
+ #include "base/timer/timer.h"
+ #include "content/browser/renderer_host/render_widget_host_delegate.h"
++#include "content/common/content_export.h"
+ #include "third_party/blink/public/common/input/web_mouse_wheel_event.h"
+ #include "third_party/blink/public/mojom/input/input_event_result.mojom-shared.h"
+
+@@ -51,7 +52,7 @@ enum class FirstScrollUpdateAckState {
+ // The MouseWheelPhaseHandler is responsible for adding the proper phase to
+ // wheel events. Phase information is necessary for wheel scrolling since it
+ // shows the start and end of a scrolling sequence.
+-class MouseWheelPhaseHandler {
++class CONTENT_EXPORT MouseWheelPhaseHandler {
+ public:
+ MouseWheelPhaseHandler(RenderWidgetHostViewBase* const host_view);
+
+diff --git content/browser/renderer_host/input/synthetic_gesture_target_base.h content/browser/renderer_host/input/synthetic_gesture_target_base.h
+index 95ce91508908e..94042da4b46bf 100644
+--- content/browser/renderer_host/input/synthetic_gesture_target_base.h
++++ content/browser/renderer_host/input/synthetic_gesture_target_base.h
+@@ -9,6 +9,7 @@
+ #include "base/memory/raw_ptr.h"
+ #include "base/time/time.h"
+ #include "content/browser/renderer_host/input/synthetic_gesture_target.h"
++#include "content/common/content_export.h"
+ #include "ui/gfx/geometry/point_f.h"
+
+ namespace ui {
+@@ -26,7 +27,8 @@ namespace content {
+
+ class RenderWidgetHostImpl;
+
+-class SyntheticGestureTargetBase : public SyntheticGestureTarget {
++class CONTENT_EXPORT SyntheticGestureTargetBase :
++ public SyntheticGestureTarget {
+ public:
+ explicit SyntheticGestureTargetBase(RenderWidgetHostImpl* host);
+
+diff --git content/common/content_switches_internal.h content/common/content_switches_internal.h
+index 97c7dc7c25000..63c42610bfd9c 100644
+--- content/common/content_switches_internal.h
++++ content/common/content_switches_internal.h
+@@ -17,7 +17,7 @@ namespace content {
+
+ extern const char kFirstRendererProcess[];
+
+-bool IsPinchToZoomEnabled();
++CONTENT_EXPORT bool IsPinchToZoomEnabled();
+
+ blink::mojom::V8CacheOptions GetV8CacheOptions();
+
+diff --git third_party/blink/renderer/controller/BUILD.gn third_party/blink/renderer/controller/BUILD.gn
+index 2cf3784f871e2..df32d4ea7e027 100644
+--- third_party/blink/renderer/controller/BUILD.gn
++++ third_party/blink/renderer/controller/BUILD.gn
+@@ -32,6 +32,7 @@ component("controller") {
+
+ configs += [
+ "//build/config/compiler:wexit_time_destructors",
++ "//cef/libcef/features:config",
+ "//third_party/blink/renderer:config",
+ "//third_party/blink/renderer:inside_blink",
+ "//third_party/blink/renderer:non_test_config",
+@@ -57,6 +58,8 @@ component("controller") {
+ "performance_manager/v8_detailed_memory_reporter_impl.h",
+ "performance_manager/v8_worker_memory_reporter.cc",
+ "performance_manager/v8_worker_memory_reporter.h",
++ "//cef/libcef/renderer/blink_glue.cc",
++ "//cef/libcef/renderer/blink_glue.h",
+ ]
+
+ if (is_linux || is_chromeos) {
+diff --git ui/events/keycodes/BUILD.gn ui/events/keycodes/BUILD.gn
+index 9cdd599f0d739..23d1ff5cc30fc 100644
+--- ui/events/keycodes/BUILD.gn
++++ ui/events/keycodes/BUILD.gn
+@@ -19,6 +19,8 @@ source_set("xkb") {
+ "//ui/gfx/x/keysyms",
+ ]
+
++ defines = [ "KEYCODES_X_IMPLEMENTATION" ]
++
+ deps = [
+ "//base",
+ "//build:chromeos_buildflags",
+diff --git ui/events/keycodes/keyboard_code_conversion_xkb.h ui/events/keycodes/keyboard_code_conversion_xkb.h
+index 5693e3a1c4bc4..88c0cc6d59098 100644
+--- ui/events/keycodes/keyboard_code_conversion_xkb.h
++++ ui/events/keycodes/keyboard_code_conversion_xkb.h
+@@ -9,6 +9,7 @@
+
+
+ #include "ui/events/keycodes/dom/dom_key.h"
++#include "ui/events/keycodes/keycodes_x_export.h"
+ #include "ui/events/keycodes/xkb_keysym.h"
+
+ namespace ui {
+@@ -24,7 +25,7 @@ DomKey NonPrintableXKeySymToDomKey(xkb_keysym_t keysym);
+ // char16_t DeadXKeySymToCombiningCharacter(xkb_keysym_t keysym);
+
+ // Return the DomKey determined by the XKB layout result (keysym, character).
+-DomKey XKeySymToDomKey(xkb_keysym_t keysym, char16_t character);
++KEYCODES_X_EXPORT DomKey XKeySymToDomKey(xkb_keysym_t keysym, char16_t character);
+
+ } // namespace ui
+
diff --git a/patch/patches/content_2015.patch b/patch/patches/content_2015.patch
new file mode 100644
index 00000000..28491615
--- /dev/null
+++ b/patch/patches/content_2015.patch
@@ -0,0 +1,214 @@
+diff --git content/browser/devtools/devtools_http_handler.cc content/browser/devtools/devtools_http_handler.cc
+index a6e355d835004..9087d3cc485ea 100644
+--- content/browser/devtools/devtools_http_handler.cc
++++ content/browser/devtools/devtools_http_handler.cc
+@@ -589,7 +589,7 @@ void DevToolsHttpHandler::OnJsonRequest(
+ base::Value::Dict version;
+ version.Set("Protocol-Version", DevToolsAgentHost::GetProtocolVersion());
+ version.Set("WebKit-Version", GetWebKitVersion());
+- version.Set("Browser", GetContentClient()->browser()->GetProduct());
++ version.Set("Browser", GetContentClient()->browser()->GetChromeProduct());
+ version.Set("User-Agent", GetContentClient()->browser()->GetUserAgent());
+ version.Set("V8-Version", V8_VERSION_STRING);
+ std::string host = info.GetHeaderValue("host");
+diff --git content/browser/loader/navigation_url_loader_impl.cc content/browser/loader/navigation_url_loader_impl.cc
+index 059dca9146bde..ef5537248308f 100644
+--- content/browser/loader/navigation_url_loader_impl.cc
++++ content/browser/loader/navigation_url_loader_impl.cc
+@@ -712,6 +712,17 @@ NavigationURLLoaderImpl::PrepareForNonInterceptedRequest() {
+ resource_request_->has_user_gesture, initiating_origin,
+ initiator_document_.AsRenderFrameHostIfValid(), &loader_factory);
+
++ if (!handled) {
++ handled = GetContentClient()->browser()->HandleExternalProtocol(
++ web_contents_getter_, frame_tree_node_id_,
++ navigation_ui_data_.get(), request_info_->is_primary_main_frame,
++ FrameTreeNode::GloballyFindByID(frame_tree_node_id_)
++ ->IsInFencedFrameTree(),
++ request_info_->sandbox_flags,
++ *resource_request_, initiating_origin,
++ initiator_document_.AsRenderFrameHostIfValid(), &loader_factory);
++ }
++
+ if (loader_factory) {
+ factory = base::MakeRefCounted<network::WrapperSharedURLLoaderFactory>(
+ std::move(loader_factory));
+diff --git content/public/browser/content_browser_client.cc content/public/browser/content_browser_client.cc
+index 75dbea1be3e60..3c9d427c9b790 100644
+--- content/public/browser/content_browser_client.cc
++++ content/public/browser/content_browser_client.cc
+@@ -965,7 +965,7 @@ ContentBrowserClient::CreateURLLoaderHandlerForServiceWorkerNavigationPreload(
+ void ContentBrowserClient::OnNetworkServiceCreated(
+ network::mojom::NetworkService* network_service) {}
+
+-void ContentBrowserClient::ConfigureNetworkContextParams(
++bool ContentBrowserClient::ConfigureNetworkContextParams(
+ BrowserContext* context,
+ bool in_memory,
+ const base::FilePath& relative_partition_path,
+@@ -974,6 +974,7 @@ void ContentBrowserClient::ConfigureNetworkContextParams(
+ cert_verifier_creation_params) {
+ network_context_params->user_agent = GetUserAgentBasedOnPolicy(context);
+ network_context_params->accept_language = "en-us,en";
++ return true;
+ }
+
+ std::vector<base::FilePath>
+diff --git content/public/browser/content_browser_client.h content/public/browser/content_browser_client.h
+index 868dd480c66e3..4c788029e9c52 100644
+--- content/public/browser/content_browser_client.h
++++ content/public/browser/content_browser_client.h
+@@ -35,6 +35,7 @@
+ #include "content/public/browser/login_delegate.h"
+ #include "content/public/browser/mojo_binder_policy_map.h"
+ #include "content/public/browser/storage_partition_config.h"
++#include "content/public/browser/web_contents.h"
+ #include "content/public/common/alternative_error_page_override_info.mojom-forward.h"
+ #include "content/public/common/page_visibility_state.h"
+ #include "content/public/common/window_container_type.mojom-forward.h"
+@@ -1775,7 +1776,7 @@ class CONTENT_EXPORT ContentBrowserClient {
+ //
+ // If |relative_partition_path| is the empty string, it means this needs to
+ // create the default NetworkContext for the BrowserContext.
+- virtual void ConfigureNetworkContextParams(
++ virtual bool ConfigureNetworkContextParams(
+ BrowserContext* context,
+ bool in_memory,
+ const base::FilePath& relative_partition_path,
+@@ -1978,6 +1979,19 @@ class CONTENT_EXPORT ContentBrowserClient {
+ RenderFrameHost* initiator_document,
+ mojo::PendingRemote<network::mojom::URLLoaderFactory>* out_factory);
+
++ // Same as above, but exposing the whole ResourceRequest object.
++ virtual bool HandleExternalProtocol(
++ WebContents::Getter web_contents_getter,
++ int frame_tree_node_id,
++ NavigationUIData* navigation_data,
++ bool is_primary_main_frame,
++ bool is_in_fenced_frame_tree,
++ network::mojom::WebSandboxFlags sandbox_flags,
++ const network::ResourceRequest& request,
++ const absl::optional<url::Origin>& initiating_origin,
++ RenderFrameHost* initiator_document,
++ mojo::PendingRemote<network::mojom::URLLoaderFactory>* out_factory) { return false; }
++
+ // Creates an OverlayWindow to be used for video or Picture-in-Picture.
+ // This window will house the content shown when in Picture-in-Picture mode.
+ // This will return a new OverlayWindow.
+@@ -2034,6 +2048,10 @@ class CONTENT_EXPORT ContentBrowserClient {
+ // Used as part of the user agent string.
+ virtual std::string GetProduct();
+
++ // Returns the Chrome-specific product string. This is used for compatibility
++ // purposes with external tools like Selenium.
++ virtual std::string GetChromeProduct() { return GetProduct(); }
++
+ // Returns the user agent. This can also return the reduced user agent, based
+ // on blink::features::kUserAgentReduction. Content may cache this value.
+ virtual std::string GetUserAgent();
+diff --git content/public/renderer/content_renderer_client.h content/public/renderer/content_renderer_client.h
+index 77f2c4fbf8c88..ddbacedde912a 100644
+--- content/public/renderer/content_renderer_client.h
++++ content/public/renderer/content_renderer_client.h
+@@ -96,6 +96,9 @@ class CONTENT_EXPORT ContentRendererClient {
+ // binding requests from RenderProcessHost::BindReceiver().
+ virtual void ExposeInterfacesToBrowser(mojo::BinderMap* binders) {}
+
++ // Notifies that the RenderThread can now send sync IPC messages.
++ virtual void RenderThreadConnected() {}
++
+ // Notifies that a new RenderFrame has been created.
+ virtual void RenderFrameCreated(RenderFrame* render_frame) {}
+
+@@ -315,6 +318,10 @@ class CONTENT_EXPORT ContentRendererClient {
+ // This method may invalidate the frame.
+ virtual void RunScriptsAtDocumentIdle(RenderFrame* render_frame) {}
+
++ // Notifies that a DevTools agent has attached or detached.
++ virtual void DevToolsAgentAttached() {}
++ virtual void DevToolsAgentDetached() {}
++
+ // Allows subclasses to enable some runtime features before Blink has
+ // started.
+ virtual void SetRuntimeFeaturesDefaultsBeforeBlinkInitialization() {}
+diff --git content/renderer/render_thread_impl.cc content/renderer/render_thread_impl.cc
+index 2fb8a5e9b9f18..12a07a0619514 100644
+--- content/renderer/render_thread_impl.cc
++++ content/renderer/render_thread_impl.cc
+@@ -620,6 +620,8 @@ void RenderThreadImpl::Init() {
+ GetContentClient()->renderer()->CreateURLLoaderThrottleProvider(
+ blink::URLLoaderThrottleProviderType::kFrame);
+
++ GetContentClient()->renderer()->RenderThreadConnected();
++
+ GetAssociatedInterfaceRegistry()->AddInterface<mojom::Renderer>(
+ base::BindRepeating(&RenderThreadImpl::OnRendererInterfaceReceiver,
+ base::Unretained(this)));
+diff --git content/renderer/renderer_blink_platform_impl.cc content/renderer/renderer_blink_platform_impl.cc
+index a0811daead7bc..2beb0d03cd671 100644
+--- content/renderer/renderer_blink_platform_impl.cc
++++ content/renderer/renderer_blink_platform_impl.cc
+@@ -1001,6 +1001,15 @@ SkBitmap* RendererBlinkPlatformImpl::GetSadPageBitmap() {
+
+ //------------------------------------------------------------------------------
+
++void RendererBlinkPlatformImpl::DevToolsAgentAttached() {
++ GetContentClient()->renderer()->DevToolsAgentAttached();
++}
++void RendererBlinkPlatformImpl::DevToolsAgentDetached() {
++ GetContentClient()->renderer()->DevToolsAgentDetached();
++}
++
++//------------------------------------------------------------------------------
++
+ std::unique_ptr<blink::WebV8ValueConverter>
+ RendererBlinkPlatformImpl::CreateWebV8ValueConverter() {
+ return std::make_unique<V8ValueConverterImpl>();
+diff --git content/renderer/renderer_blink_platform_impl.h content/renderer/renderer_blink_platform_impl.h
+index f9b61ff32e3e7..ea649425e7b34 100644
+--- content/renderer/renderer_blink_platform_impl.h
++++ content/renderer/renderer_blink_platform_impl.h
+@@ -235,6 +235,9 @@ class CONTENT_EXPORT RendererBlinkPlatformImpl : public BlinkPlatformImpl {
+ uint64_t private_memory_footprint_bytes) override;
+ #endif
+
++ void DevToolsAgentAttached() override;
++ void DevToolsAgentDetached() override;
++
+ // Tells this platform that the renderer is locked to a site (i.e., a scheme
+ // plus eTLD+1, such as https://google.com), or to a more specific origin.
+ void SetIsLockedToSite();
+diff --git headless/lib/browser/headless_content_browser_client.cc headless/lib/browser/headless_content_browser_client.cc
+index 5c1f3a069c00b..db5f4250330ad 100644
+--- headless/lib/browser/headless_content_browser_client.cc
++++ headless/lib/browser/headless_content_browser_client.cc
+@@ -284,7 +284,7 @@ bool HeadlessContentBrowserClient::ShouldEnableStrictSiteIsolation() {
+ return false;
+ }
+
+-void HeadlessContentBrowserClient::ConfigureNetworkContextParams(
++bool HeadlessContentBrowserClient::ConfigureNetworkContextParams(
+ content::BrowserContext* context,
+ bool in_memory,
+ const base::FilePath& relative_partition_path,
+@@ -294,6 +294,7 @@ void HeadlessContentBrowserClient::ConfigureNetworkContextParams(
+ HeadlessBrowserContextImpl::From(context)->ConfigureNetworkContextParams(
+ in_memory, relative_partition_path, network_context_params,
+ cert_verifier_creation_params);
++ return true;
+ }
+
+ std::string HeadlessContentBrowserClient::GetProduct() {
+diff --git headless/lib/browser/headless_content_browser_client.h headless/lib/browser/headless_content_browser_client.h
+index c96642d57f5cd..bfcf88fa2559d 100644
+--- headless/lib/browser/headless_content_browser_client.h
++++ headless/lib/browser/headless_content_browser_client.h
+@@ -71,7 +71,7 @@ class HeadlessContentBrowserClient : public content::ContentBrowserClient {
+ std::unique_ptr<content::ClientCertificateDelegate> delegate) override;
+ bool ShouldEnableStrictSiteIsolation() override;
+
+- void ConfigureNetworkContextParams(
++ bool ConfigureNetworkContextParams(
+ content::BrowserContext* context,
+ bool in_memory,
+ const base::FilePath& relative_partition_path,
diff --git a/patch/patches/content_main_654986.patch b/patch/patches/content_main_654986.patch
new file mode 100644
index 00000000..5ef86220
--- /dev/null
+++ b/patch/patches/content_main_654986.patch
@@ -0,0 +1,184 @@
+diff --git content/app/content_main.cc content/app/content_main.cc
+index f646abaa56f8b..59d4a1f0817e6 100644
+--- content/app/content_main.cc
++++ content/app/content_main.cc
+@@ -172,11 +172,8 @@ ContentMainParams::~ContentMainParams() = default;
+ ContentMainParams::ContentMainParams(ContentMainParams&&) = default;
+ ContentMainParams& ContentMainParams::operator=(ContentMainParams&&) = default;
+
+-// This function must be marked with NO_STACK_PROTECTOR or it may crash on
+-// return, see the --change-stack-guard-on-fork command line flag.
+-int NO_STACK_PROTECTOR
+-RunContentProcess(ContentMainParams params,
+- ContentMainRunner* content_main_runner) {
++int ContentMainInitialize(ContentMainParams params,
++ ContentMainRunner* content_main_runner) {
+ base::FeatureList::FailOnFeatureAccessWithoutFeatureList();
+ #if BUILDFLAG(IS_CHROMEOS_LACROS)
+ // Lacros is launched with inherited priority. Revert to normal priority
+@@ -185,9 +182,6 @@ RunContentProcess(ContentMainParams params,
+ #endif
+ int exit_code = -1;
+ base::debug::GlobalActivityTracker* tracker = nullptr;
+-#if BUILDFLAG(IS_MAC)
+- std::unique_ptr<base::mac::ScopedNSAutoreleasePool> autorelease_pool;
+-#endif
+
+ // A flag to indicate whether Main() has been called before. On Android, we
+ // may re-run Main() without restarting the browser process. This flag
+@@ -273,12 +267,6 @@ RunContentProcess(ContentMainParams params,
+ #endif
+
+ #if BUILDFLAG(IS_MAC)
+- // We need this pool for all the objects created before we get to the event
+- // loop, but we don't want to leave them hanging around until the app quits.
+- // Each "main" needs to flush this pool right before it goes into its main
+- // event loop to get rid of the cruft.
+- autorelease_pool = std::make_unique<base::mac::ScopedNSAutoreleasePool>();
+- params.autorelease_pool = autorelease_pool.get();
+ InitializeMac();
+ #endif
+
+@@ -318,8 +306,18 @@ RunContentProcess(ContentMainParams params,
+
+ if (IsSubprocess())
+ CommonSubprocessInit();
+- exit_code = content_main_runner->Run();
+
++ return exit_code;
++}
++
++// This function must be marked with NO_STACK_PROTECTOR or it may crash on
++// return, see the --change-stack-guard-on-fork command line flag.
++int NO_STACK_PROTECTOR
++ContentMainRun(ContentMainRunner* content_main_runner) {
++ int exit_code = content_main_runner->Run();
++
++ base::debug::GlobalActivityTracker* tracker =
++ base::debug::GlobalActivityTracker::Get();
+ if (tracker) {
+ if (exit_code == 0) {
+ tracker->SetProcessPhaseIfEnabled(
+@@ -331,14 +329,41 @@ RunContentProcess(ContentMainParams params,
+ }
+ }
+
+-#if BUILDFLAG(IS_MAC)
+- autorelease_pool.reset();
+-#endif
++ return exit_code;
++}
+
++void ContentMainShutdown(ContentMainRunner* content_main_runner) {
+ #if !BUILDFLAG(IS_ANDROID)
+ content_main_runner->Shutdown();
+ #endif
++}
++
++// This function must be marked with NO_STACK_PROTECTOR or it may crash on
++// return, see the --change-stack-guard-on-fork command line flag.
++int NO_STACK_PROTECTOR
++RunContentProcess(ContentMainParams params,
++ ContentMainRunner* content_main_runner) {
++#if BUILDFLAG(IS_MAC)
++ // We need this pool for all the objects created before we get to the event
++ // loop, but we don't want to leave them hanging around until the app quits.
++ // Each "main" needs to flush this pool right before it goes into its main
++ // event loop to get rid of the cruft.
++ std::unique_ptr<base::mac::ScopedNSAutoreleasePool> autorelease_pool =
++ std::make_unique<base::mac::ScopedNSAutoreleasePool>();
++ params.autorelease_pool = autorelease_pool.get();
++#endif
++
++ int exit_code = ContentMainInitialize(std::move(params), content_main_runner);
++ if (exit_code >= 0)
++ return exit_code;
++ exit_code = ContentMainRun(content_main_runner);
++
++#if BUILDFLAG(IS_MAC)
++ params.autorelease_pool = nullptr;
++ autorelease_pool.reset();
++#endif
+
++ ContentMainShutdown(content_main_runner);
+ return exit_code;
+ }
+
+diff --git content/app/content_main_runner_impl.cc content/app/content_main_runner_impl.cc
+index 5029cbe44e4bd..fc6616da947eb 100644
+--- content/app/content_main_runner_impl.cc
++++ content/app/content_main_runner_impl.cc
+@@ -46,6 +46,7 @@
+ #include "base/task/thread_pool/thread_pool_instance.h"
+ #include "base/threading/hang_watcher.h"
+ #include "base/threading/platform_thread.h"
++#include "base/threading/thread_restrictions.h"
+ #include "base/time/time.h"
+ #include "base/trace_event/trace_event.h"
+ #include "build/build_config.h"
+@@ -1290,6 +1291,12 @@ void ContentMainRunnerImpl::Shutdown() {
+ is_shutdown_ = true;
+ }
+
++void ContentMainRunnerImpl::ShutdownOnUIThread() {
++ base::ScopedAllowBaseSyncPrimitivesForTesting allow_wait;
++ unregister_thread_closure_.RunAndReset();
++ discardable_shared_memory_manager_.reset();
++}
++
+ // static
+ std::unique_ptr<ContentMainRunner> ContentMainRunner::Create() {
+ return ContentMainRunnerImpl::Create();
+diff --git content/app/content_main_runner_impl.h content/app/content_main_runner_impl.h
+index ea9b5233820cd..aba62b3384134 100644
+--- content/app/content_main_runner_impl.h
++++ content/app/content_main_runner_impl.h
+@@ -27,7 +27,7 @@ class DiscardableSharedMemoryManager;
+ namespace content {
+ class MojoIpcSupport;
+
+-class ContentMainRunnerImpl : public ContentMainRunner {
++class CONTENT_EXPORT ContentMainRunnerImpl : public ContentMainRunner {
+ public:
+ static std::unique_ptr<ContentMainRunnerImpl> Create();
+
+@@ -46,6 +46,8 @@ class ContentMainRunnerImpl : public ContentMainRunner {
+ int Run() override;
+ void Shutdown() override;
+
++ void ShutdownOnUIThread();
++
+ private:
+ int RunBrowser(MainFunctionParams main_function_params,
+ bool start_minimal_browser);
+diff --git content/common/set_process_title.cc content/common/set_process_title.cc
+index 04a08015aaff6..694f5c43a29e1 100644
+--- content/common/set_process_title.cc
++++ content/common/set_process_title.cc
+@@ -54,7 +54,7 @@ void SetProcessTitleFromCommandLine(const char** main_argv) {
+ bool have_argv0 = false;
+
+ #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+- DCHECK_EQ(base::PlatformThread::CurrentId(), getpid());
++ // DCHECK_EQ(base::PlatformThread::CurrentId(), getpid());
+
+ if (main_argv)
+ setproctitle_init(main_argv);
+diff --git content/public/app/content_main.h content/public/app/content_main.h
+index 16e8c657ad61f..62d58b8dcccf5 100644
+--- content/public/app/content_main.h
++++ content/public/app/content_main.h
+@@ -93,6 +93,13 @@ struct CONTENT_EXPORT ContentMainParams {
+ }
+ };
+
++// Split RunContentProcess() into separate stages.
++CONTENT_EXPORT int ContentMainInitialize(
++ ContentMainParams params,
++ ContentMainRunner* content_main_runner);
++CONTENT_EXPORT int ContentMainRun(ContentMainRunner* content_main_runner);
++CONTENT_EXPORT void ContentMainShutdown(ContentMainRunner* content_main_runner);
++
+ CONTENT_EXPORT int RunContentProcess(ContentMainParams params,
+ ContentMainRunner* content_main_runner);
+
diff --git a/patch/patches/crashpad_1995.patch b/patch/patches/crashpad_1995.patch
new file mode 100644
index 00000000..d51d8d3b
--- /dev/null
+++ b/patch/patches/crashpad_1995.patch
@@ -0,0 +1,540 @@
+diff --git chrome/chrome_elf/BUILD.gn chrome/chrome_elf/BUILD.gn
+index e2cb049c1ce6c..8c2b6242894b3 100644
+--- chrome/chrome_elf/BUILD.gn
++++ chrome/chrome_elf/BUILD.gn
+@@ -7,6 +7,7 @@
+
+ import("//build/config/compiler/compiler.gni")
+ import("//build/config/win/manifest.gni")
++import("//cef/libcef/features/features.gni")
+ import("//chrome/process_version_rc_template.gni")
+ import("//testing/test.gni")
+
+@@ -106,9 +107,6 @@ source_set("constants") {
+
+ static_library("crash") {
+ sources = [
+- "../app/chrome_crash_reporter_client_win.cc",
+- "../app/chrome_crash_reporter_client_win.h",
+- "../common/chrome_result_codes.h",
+ "crash/crash_helper.cc",
+ "crash/crash_helper.h",
+ ]
+@@ -117,6 +115,7 @@ static_library("crash") {
+ ":hook_util",
+ "//base", # This needs to go. DEP of app, crash_keys, client.
+ "//base:base_static", # pe_image
++ "//cef/libcef/features",
+ "//chrome/install_static:install_static_util",
+ "//components/crash/core/app",
+ "//components/crash/core/common", # crash_keys
+@@ -124,6 +123,17 @@ static_library("crash") {
+ "//content/public/common:result_codes",
+ "//third_party/crashpad/crashpad/client", # DumpWithoutCrash
+ ]
++
++ if (enable_cef) {
++ deps += [ "//cef:chrome_elf_set" ]
++ include_dirs = [ "//cef" ]
++ } else {
++ sources += [
++ "//chrome/app/chrome_crash_reporter_client_win.cc",
++ "//chrome/app/chrome_crash_reporter_client_win.h",
++ "//chrome/common/chrome_result_codes.h",
++ ]
++ }
+ }
+
+ source_set("dll_hash") {
+diff --git chrome/chrome_elf/crash/crash_helper.cc chrome/chrome_elf/crash/crash_helper.cc
+index 27a803784eb9e..a8b033f475cb4 100644
+--- chrome/chrome_elf/crash/crash_helper.cc
++++ chrome/chrome_elf/crash/crash_helper.cc
+@@ -11,12 +11,17 @@
+ #include <string>
+ #include <vector>
+
++#include "cef/libcef/features/features.h"
+ #include "chrome/app/chrome_crash_reporter_client_win.h"
+ #include "chrome/chrome_elf/hook_util/hook_util.h"
+ #include "components/crash/core/app/crashpad.h"
+ #include "components/crash/core/common/crash_keys.h"
+ #include "third_party/crashpad/crashpad/client/crashpad_client.h"
+
++#if BUILDFLAG(ENABLE_CEF)
++#include "cef/libcef/common/crash_reporter_client.h"
++#endif
++
+ namespace {
+
+ // Crash handling from elf is only enabled for the chrome.exe process.
+@@ -77,7 +82,11 @@ bool InitializeCrashReporting() {
+ g_crash_reports = new std::vector<crash_reporter::Report>;
+ g_set_unhandled_exception_filter = new elf_hook::IATHook();
+
++#if BUILDFLAG(ENABLE_CEF)
++ CefCrashReporterClient::InitializeCrashReportingForProcess();
++#else
+ ChromeCrashReporterClient::InitializeCrashReportingForProcess();
++#endif
+
+ g_crash_helper_enabled = true;
+ return true;
+diff --git chrome/common/crash_keys.cc chrome/common/crash_keys.cc
+index f748d2dd47946..98371cf551a75 100644
+--- chrome/common/crash_keys.cc
++++ chrome/common/crash_keys.cc
+@@ -6,6 +6,8 @@
+
+ #include <deque>
+
++#include <iterator>
++
+ #include "base/base_switches.h"
+ #include "base/command_line.h"
+ #include "base/format_macros.h"
+@@ -93,8 +95,10 @@ void HandleEnableDisableFeatures(const base::CommandLine& command_line) {
+ }
+ #endif
+
++} // namespace
++
+ // Return true if we DON'T want to upload this flag to the crash server.
+-bool IsBoringSwitch(const std::string& flag) {
++bool IsBoringChromeSwitch(const std::string& flag) {
+ static const char* const kIgnoreSwitches[] = {
+ switches::kEnableLogging,
+ switches::kFlagSwitchesBegin,
+@@ -154,13 +158,11 @@ bool IsBoringSwitch(const std::string& flag) {
+ return false;
+ }
+
+-} // namespace
+-
+ void SetCrashKeysFromCommandLine(const base::CommandLine& command_line) {
+ #if BUILDFLAG(IS_CHROMEOS)
+ HandleEnableDisableFeatures(command_line);
+ #endif
+- SetSwitchesFromCommandLine(command_line, &IsBoringSwitch);
++ SetSwitchesFromCommandLine(command_line, &IsBoringChromeSwitch);
+ }
+
+ void SetActiveExtensions(const std::set<std::string>& extensions) {
+diff --git chrome/common/crash_keys.h chrome/common/crash_keys.h
+index d802db81c88ef..f78029680e366 100644
+--- chrome/common/crash_keys.h
++++ chrome/common/crash_keys.h
+@@ -16,6 +16,10 @@ class CommandLine;
+
+ namespace crash_keys {
+
++// Returns true if the specified command-line flag should be excluded from
++// crash reporting.
++bool IsBoringChromeSwitch(const std::string& flag);
++
+ // Sets the kNumSwitches key and the set of keys named using kSwitchFormat based
+ // on the given |command_line|.
+ void SetCrashKeysFromCommandLine(const base::CommandLine& command_line);
+diff --git components/crash/core/app/crash_reporter_client.cc components/crash/core/app/crash_reporter_client.cc
+index 284dd099122df..c09c614c11283 100644
+--- components/crash/core/app/crash_reporter_client.cc
++++ components/crash/core/app/crash_reporter_client.cc
+@@ -93,7 +93,7 @@ bool CrashReporterClient::GetShouldDumpLargerDumps() {
+ }
+ #endif
+
+-#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC)
++#if BUILDFLAG(IS_POSIX)
+ void CrashReporterClient::GetProductNameAndVersion(const char** product_name,
+ const char** version) {
+ }
+@@ -102,6 +102,7 @@ void CrashReporterClient::GetProductNameAndVersion(std::string* product_name,
+ std::string* version,
+ std::string* channel) {}
+
++#if !BUILDFLAG(IS_MAC)
+ base::FilePath CrashReporterClient::GetReporterLogFilename() {
+ return base::FilePath();
+ }
+@@ -111,6 +112,7 @@ bool CrashReporterClient::HandleCrashDump(const char* crashdump_filename,
+ return false;
+ }
+ #endif
++#endif
+
+ #if BUILDFLAG(IS_WIN)
+ bool CrashReporterClient::GetCrashDumpLocation(std::wstring* crash_dir) {
+@@ -145,6 +147,28 @@ bool CrashReporterClient::ReportingIsEnforcedByPolicy(bool* breakpad_enabled) {
+ return false;
+ }
+
++bool CrashReporterClient::EnableBreakpadForProcess(
++ const std::string& process_type) {
++ return false;
++}
++
++void CrashReporterClient::GetCrashOptionalArguments(
++ std::vector<std::string>* arguments) {
++}
++
++#if BUILDFLAG(IS_WIN)
++std::wstring CrashReporterClient::GetCrashExternalHandler(
++ const std::wstring& exe_dir) {
++ return exe_dir + L"\\crashpad_handler.exe";
++}
++#endif
++
++#if BUILDFLAG(IS_MAC)
++bool CrashReporterClient::EnableBrowserCrashForwarding() {
++ return true;
++}
++#endif
++
+ #if BUILDFLAG(IS_ANDROID)
+ unsigned int CrashReporterClient::GetCrashDumpPercentage() {
+ return 100;
+@@ -207,9 +231,4 @@ bool CrashReporterClient::ShouldMonitorCrashHandlerExpensively() {
+ return false;
+ }
+
+-bool CrashReporterClient::EnableBreakpadForProcess(
+- const std::string& process_type) {
+- return false;
+-}
+-
+ } // namespace crash_reporter
+diff --git components/crash/core/app/crash_reporter_client.h components/crash/core/app/crash_reporter_client.h
+index 9f8f20dfa6506..5d42f6fc1b003 100644
+--- components/crash/core/app/crash_reporter_client.h
++++ components/crash/core/app/crash_reporter_client.h
+@@ -5,7 +5,9 @@
+ #ifndef COMPONENTS_CRASH_CORE_APP_CRASH_REPORTER_CLIENT_H_
+ #define COMPONENTS_CRASH_CORE_APP_CRASH_REPORTER_CLIENT_H_
+
++#include <map>
+ #include <string>
++#include <vector>
+
+ #include "build/build_config.h"
+
+@@ -94,7 +96,7 @@ class CrashReporterClient {
+ virtual bool GetShouldDumpLargerDumps();
+ #endif
+
+-#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC)
++#if BUILDFLAG(IS_POSIX)
+ // Returns a textual description of the product type and version to include
+ // in the crash report. Neither out parameter should be set to NULL.
+ // TODO(jperaza): Remove the 2-parameter overload of this method once all
+@@ -105,6 +107,7 @@ class CrashReporterClient {
+ std::string* version,
+ std::string* channel);
+
++#if !BUILDFLAG(IS_MAC)
+ virtual base::FilePath GetReporterLogFilename();
+
+ // Custom crash minidump handler after the minidump is generated.
+@@ -114,6 +117,7 @@ class CrashReporterClient {
+ // libc nor allocate memory normally.
+ virtual bool HandleCrashDump(const char* crashdump_filename,
+ uint64_t crash_pid);
++#endif
+ #endif
+
+ // The location where minidump files should be written. Returns true if
+@@ -211,6 +215,20 @@ class CrashReporterClient {
+
+ // Returns true if breakpad should run in the given process type.
+ virtual bool EnableBreakpadForProcess(const std::string& process_type);
++
++ // Populate |arguments| with additional optional arguments.
++ virtual void GetCrashOptionalArguments(std::vector<std::string>* arguments);
++
++#if BUILDFLAG(IS_WIN)
++ // Returns the absolute path to the external crash handler exe.
++ virtual std::wstring GetCrashExternalHandler(const std::wstring& exe_dir);
++#endif
++
++#if BUILDFLAG(IS_MAC)
++ // Returns true if forwarding of crashes to the system crash reporter is
++ // enabled for the browser process.
++ virtual bool EnableBrowserCrashForwarding();
++#endif
+ };
+
+ } // namespace crash_reporter
+diff --git components/crash/core/app/crashpad.cc components/crash/core/app/crashpad.cc
+index 55ae5145e81a4..81daed959d336 100644
+--- components/crash/core/app/crashpad.cc
++++ components/crash/core/app/crashpad.cc
+@@ -130,7 +130,8 @@ bool InitializeCrashpadImpl(bool initial_client,
+ // fallback. Forwarding is turned off for debug-mode builds even for the
+ // browser process, because the system's crash reporter can take a very long
+ // time to chew on symbols.
+- if (!browser_process || is_debug_build) {
++ if (!browser_process || is_debug_build ||
++ !GetCrashReporterClient()->EnableBrowserCrashForwarding()) {
+ crashpad::CrashpadInfo::GetCrashpadInfo()
+ ->set_system_crash_reporter_forwarding(crashpad::TriState::kDisabled);
+ }
+diff --git components/crash/core/app/crashpad_linux.cc components/crash/core/app/crashpad_linux.cc
+index 99efa6b245b99..008eb397332c2 100644
+--- components/crash/core/app/crashpad_linux.cc
++++ components/crash/core/app/crashpad_linux.cc
+@@ -23,6 +23,7 @@
+ #include "components/crash/core/app/crash_reporter_client.h"
+ #include "components/crash/core/app/crash_switches.h"
+ #include "content/public/common/content_descriptors.h"
++#include "content/public/common/content_paths.h"
+ #include "sandbox/linux/services/namespace_sandbox.h"
+ #include "third_party/crashpad/crashpad/client/crashpad_client.h"
+ #include "third_party/crashpad/crashpad/client/crashpad_info.h"
+@@ -107,11 +108,10 @@ bool PlatformCrashpadInitialization(
+ crash_reporter_client->GetCrashDumpLocation(database_path);
+ crash_reporter_client->GetCrashMetricsLocation(&metrics_path);
+
++ // Use the same main (default) or subprocess helper exe.
+ base::FilePath handler_path;
+- if (!base::PathService::Get(base::DIR_EXE, &handler_path)) {
+- return false;
+- }
+- handler_path = handler_path.Append("chrome_crashpad_handler");
++ base::PathService::Get(content::CHILD_PROCESS_EXE, &handler_path);
++ DCHECK(!handler_path.empty());
+
+ // When --use-cros-crash-reporter is set (below), the handler passes dumps
+ // to ChromeOS's /sbin/crash_reporter which in turn passes the dump to
+@@ -128,8 +128,8 @@ bool PlatformCrashpadInitialization(
+ &product_version, &channel);
+
+ std::map<std::string, std::string> annotations;
+- annotations["prod"] = product_name;
+- annotations["ver"] = product_version;
++ annotations["product"] = product_name;
++ annotations["version"] = product_version;
+
+ #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
+ // Empty means stable.
+@@ -146,7 +146,20 @@ bool PlatformCrashpadInitialization(
+ annotations["channel"] = channel;
+ }
+
+- annotations["plat"] = std::string("Linux");
++#if defined(ARCH_CPU_ARM_FAMILY)
++#if defined(ARCH_CPU_32_BITS)
++ const char* platform = "linuxarm";
++#elif defined(ARCH_CPU_64_BITS)
++ const char* platform = "linuxarm64";
++#endif
++#else
++#if defined(ARCH_CPU_32_BITS)
++ const char* platform = "linux32";
++#elif defined(ARCH_CPU_64_BITS)
++ const char* platform = "linux64";
++#endif
++#endif // defined(ARCH_CPU_ARM_FAMILY)
++ annotations["platform"] = platform;
+
+ #if BUILDFLAG(IS_CHROMEOS_LACROS)
+ // "build_time_millis" is used on LaCros chrome to determine when to stop
+@@ -191,6 +204,12 @@ bool PlatformCrashpadInitialization(
+ }
+ #endif
+
++ // Since we're using the same main or subprocess helper exe we must specify
++ // the process type.
++ arguments.push_back(std::string("--type=") + switches::kCrashpadHandler);
++
++ crash_reporter_client->GetCrashOptionalArguments(&arguments);
++
+ CHECK(client.StartHandler(handler_path, *database_path, metrics_path, url,
+ annotations, arguments, false, false));
+ } else {
+diff --git components/crash/core/app/crashpad_mac.mm components/crash/core/app/crashpad_mac.mm
+index cab2c95eee53e..06e6f61ebccb1 100644
+--- components/crash/core/app/crashpad_mac.mm
++++ components/crash/core/app/crashpad_mac.mm
+@@ -16,11 +16,14 @@
+ #include "base/files/file_path.h"
+ #include "base/mac/bundle_locations.h"
+ #include "base/mac/foundation_util.h"
++#include "base/path_service.h"
+ #include "base/strings/string_number_conversions.h"
+ #include "base/strings/string_piece.h"
+ #include "base/strings/sys_string_conversions.h"
+ #include "build/branding_buildflags.h"
+ #include "components/crash/core/app/crash_reporter_client.h"
++#include "components/crash/core/app/crash_switches.h"
++#include "content/public/common/content_paths.h"
+ #include "third_party/crashpad/crashpad/client/crash_report_database.h"
+ #include "third_party/crashpad/crashpad/client/crashpad_client.h"
+ #include "third_party/crashpad/crashpad/client/crashpad_info.h"
+@@ -38,14 +41,24 @@ std::map<std::string, std::string> GetProcessSimpleAnnotations() {
+ std::map<std::string, std::string> process_annotations;
+ @autoreleasepool {
+ NSBundle* outer_bundle = base::mac::OuterBundle();
++ CrashReporterClient* crash_reporter_client = GetCrashReporterClient();
++ const char* product_name = "";
++ const char* product_version = "";
++ crash_reporter_client->GetProductNameAndVersion(&product_name,
++ &product_version);
++
++ if (strlen(product_name) == 0) {
+ #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
+- process_annotations["prod"] = "Chrome_Mac";
++ process_annotations["product"] = "Chrome_Mac";
+ #else
+- NSString* product = base::mac::ObjCCast<NSString>([outer_bundle
+- objectForInfoDictionaryKey:base::mac::CFToNSCast(kCFBundleNameKey)]);
+- process_annotations["prod"] =
+- base::SysNSStringToUTF8(product).append("_Mac");
++ NSString* product = base::mac::ObjCCast<NSString>([outer_bundle
++ objectForInfoDictionaryKey:base::mac::CFToNSCast(kCFBundleNameKey)]);
++ process_annotations["product"] =
++ base::SysNSStringToUTF8(product).append("_Mac");
+ #endif
++ } else {
++ process_annotations["product"] = product_name;
++ }
+
+ #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
+ // Empty means stable.
+@@ -76,12 +89,20 @@ std::map<std::string, std::string> GetProcessSimpleAnnotations() {
+ }
+ }
+
+- NSString* version =
+- base::mac::ObjCCast<NSString>([base::mac::FrameworkBundle()
+- objectForInfoDictionaryKey:@"CFBundleShortVersionString"]);
+- process_annotations["ver"] = base::SysNSStringToUTF8(version);
++ if (strlen(product_version) == 0) {
++ NSString* version =
++ base::mac::ObjCCast<NSString>([base::mac::FrameworkBundle()
++ objectForInfoDictionaryKey:@"CFBundleShortVersionString"]);
++ process_annotations["version"] = base::SysNSStringToUTF8(version);
++ } else {
++ process_annotations["version"] = product_version;
++ }
+
+- process_annotations["plat"] = std::string("OS X");
++#if defined(ARCH_CPU_ARM64)
++ process_annotations["platform"] = std::string("macosarm64");
++#else
++ process_annotations["platform"] = std::string("macos");
++#endif
+ } // @autoreleasepool
+ return process_annotations;
+ }();
+@@ -141,10 +162,10 @@ bool PlatformCrashpadInitialization(
+
+ if (initial_client) {
+ @autoreleasepool {
+- base::FilePath framework_bundle_path = base::mac::FrameworkBundlePath();
+- base::FilePath handler_path =
+- framework_bundle_path.Append("Helpers").Append(
+- "chrome_crashpad_handler");
++ // Use the same subprocess helper exe.
++ base::FilePath handler_path;
++ base::PathService::Get(content::CHILD_PROCESS_EXE, &handler_path);
++ DCHECK(!handler_path.empty());
+
+ // Is there a way to recover if this fails?
+ CrashReporterClient* crash_reporter_client = GetCrashReporterClient();
+@@ -173,6 +194,12 @@ bool PlatformCrashpadInitialization(
+ "--reset-own-crash-exception-port-to-system-default");
+ }
+
++ // Since we're using the same subprocess helper exe we must specify the
++ // process type.
++ arguments.push_back(std::string("--type=") + switches::kCrashpadHandler);
++
++ crash_reporter_client->GetCrashOptionalArguments(&arguments);
++
+ bool result = GetCrashpadClient().StartHandler(
+ handler_path, *database_path, metrics_path, url,
+ GetProcessSimpleAnnotations(), arguments, true, false);
+diff --git components/crash/core/app/crashpad_win.cc components/crash/core/app/crashpad_win.cc
+index 9ab5fb1c82275..740014c1119bd 100644
+--- components/crash/core/app/crashpad_win.cc
++++ components/crash/core/app/crashpad_win.cc
+@@ -36,8 +36,8 @@ void GetPlatformCrashpadAnnotations(
+ std::wstring product_name, version, special_build, channel_name;
+ crash_reporter_client->GetProductNameAndVersion(
+ exe_file, &product_name, &version, &special_build, &channel_name);
+- (*annotations)["prod"] = base::WideToUTF8(product_name);
+- (*annotations)["ver"] = base::WideToUTF8(version);
++ (*annotations)["product"] = base::WideToUTF8(product_name);
++ (*annotations)["version"] = base::WideToUTF8(version);
+ #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
+ // Empty means stable.
+ const bool allow_empty_channel = true;
+@@ -54,9 +54,11 @@ void GetPlatformCrashpadAnnotations(
+ if (!special_build.empty())
+ (*annotations)["special"] = base::WideToUTF8(special_build);
+ #if defined(ARCH_CPU_X86)
+- (*annotations)["plat"] = std::string("Win32");
++ (*annotations)["platform"] = std::string("win32");
+ #elif defined(ARCH_CPU_X86_64)
+- (*annotations)["plat"] = std::string("Win64");
++ (*annotations)["platform"] = std::string("win64");
++#elif defined(ARCH_CPU_ARM64)
++ (*annotations)["platform"] = std::string("winarm64");
+ #endif
+ }
+
+@@ -71,7 +73,9 @@ bool PlatformCrashpadInitialization(
+ base::FilePath metrics_path; // Only valid in the browser process.
+
+ const char kPipeNameVar[] = "CHROME_CRASHPAD_PIPE_NAME";
++#if defined(GOOGLE_CHROME_BUILD)
+ const char kServerUrlVar[] = "CHROME_CRASHPAD_SERVER_URL";
++#endif
+ std::unique_ptr<base::Environment> env(base::Environment::Create());
+
+ CrashReporterClient* crash_reporter_client = GetCrashReporterClient();
+@@ -94,9 +98,11 @@ bool PlatformCrashpadInitialization(
+
+ std::string url = crash_reporter_client->GetUploadUrl();
+
++#if defined(GOOGLE_CHROME_BUILD)
+ // Allow the crash server to be overridden for testing. If the variable
+ // isn't present in the environment then the default URL will remain.
+ env->GetVar(kServerUrlVar, &url);
++#endif
+
+ base::FilePath exe_file(exe_path);
+ if (exe_file.empty()) {
+@@ -107,13 +113,14 @@ bool PlatformCrashpadInitialization(
+ exe_file = base::FilePath(exe_file_path);
+ }
+
+- // If the handler is embedded in the binary (e.g. chrome, setup), we
+- // reinvoke it with --type=crashpad-handler. Otherwise, we use the
+- // standalone crashpad_handler.exe (for tests, etc.).
+ std::vector<std::string> start_arguments(initial_arguments);
++
++ // Always add --type=crashpad-handler because the value is expected by
++ // CefExecuteProcess.
++ start_arguments.push_back(
++ std::string("--type=") + switches::kCrashpadHandler);
++
+ if (embedded_handler) {
+- start_arguments.push_back(std::string("--type=") +
+- switches::kCrashpadHandler);
+ if (!user_data_dir.empty()) {
+ start_arguments.push_back(std::string("--user-data-dir=") +
+ user_data_dir);
+@@ -124,9 +131,12 @@ bool PlatformCrashpadInitialization(
+ start_arguments.push_back("/prefetch:7");
+ } else {
+ base::FilePath exe_dir = exe_file.DirName();
+- exe_file = exe_dir.Append(FILE_PATH_LITERAL("crashpad_handler.exe"));
++ exe_file = base::FilePath(
++ crash_reporter_client->GetCrashExternalHandler(exe_dir.value()));
+ }
+
++ crash_reporter_client->GetCrashOptionalArguments(&start_arguments);
++
+ std::vector<std::string> arguments(start_arguments);
+
+ if (crash_reporter_client->ShouldMonitorCrashHandlerExpensively()) {
diff --git a/patch/patches/crashpad_tp_1995.patch b/patch/patches/crashpad_tp_1995.patch
new file mode 100644
index 00000000..e06f801b
--- /dev/null
+++ b/patch/patches/crashpad_tp_1995.patch
@@ -0,0 +1,361 @@
+diff --git third_party/crashpad/crashpad/client/prune_crash_reports.cc third_party/crashpad/crashpad/client/prune_crash_reports.cc
+index 077694f541d57..928a520485414 100644
+--- third_party/crashpad/crashpad/client/prune_crash_reports.cc
++++ third_party/crashpad/crashpad/client/prune_crash_reports.cc
+@@ -75,13 +75,19 @@ size_t PruneCrashReportDatabase(CrashReportDatabase* database,
+ }
+
+ // static
+-std::unique_ptr<PruneCondition> PruneCondition::GetDefault() {
++std::unique_ptr<PruneCondition> PruneCondition::GetDefault(
++ int max_size_in_mb,
++ int max_age_in_days) {
+ // DatabaseSizePruneCondition must be the LHS so that it is always evaluated,
+ // due to the short-circuting behavior of BinaryPruneCondition.
++ if (max_size_in_mb <= 0)
++ max_size_in_mb = 128;
++ if (max_age_in_days <= 0)
++ max_age_in_days = 365;
+ return std::make_unique<BinaryPruneCondition>(
+ BinaryPruneCondition::OR,
+- new DatabaseSizePruneCondition(1024 * 128),
+- new AgePruneCondition(365));
++ new DatabaseSizePruneCondition(1024 * max_size_in_mb),
++ new AgePruneCondition(max_age_in_days));
+ }
+
+ static const time_t kSecondsInDay = 60 * 60 * 24;
+diff --git third_party/crashpad/crashpad/client/prune_crash_reports.h third_party/crashpad/crashpad/client/prune_crash_reports.h
+index b362e0aadbadd..1588232a6e4d4 100644
+--- third_party/crashpad/crashpad/client/prune_crash_reports.h
++++ third_party/crashpad/crashpad/client/prune_crash_reports.h
+@@ -58,7 +58,8 @@ class PruneCondition {
+ //! of 128 MB.
+ //!
+ //! \return A PruneCondition for use with PruneCrashReportDatabase().
+- static std::unique_ptr<PruneCondition> GetDefault();
++ static std::unique_ptr<PruneCondition> GetDefault(int max_size_in_mb,
++ int max_age_in_days);
+
+ virtual ~PruneCondition() {}
+
+diff --git third_party/crashpad/crashpad/client/settings.cc third_party/crashpad/crashpad/client/settings.cc
+index 5e4119e2175c7..e66600089be04 100644
+--- third_party/crashpad/crashpad/client/settings.cc
++++ third_party/crashpad/crashpad/client/settings.cc
+@@ -117,7 +117,7 @@ void ScopedLockedFileHandleTraits::Free(FileHandle handle) {
+
+ struct Settings::Data {
+ static constexpr uint32_t kSettingsMagic = 'CPds';
+- static constexpr uint32_t kSettingsVersion = 1;
++ static constexpr uint32_t kSettingsVersion = 2;
+
+ enum Options : uint32_t {
+ kUploadsEnabled = 1 << 0,
+@@ -128,6 +128,9 @@ struct Settings::Data {
+ options(0),
+ padding_0(0),
+ last_upload_attempt_time(0),
++ next_upload_attempt_time(0),
++ backoff_step(0),
++ padding_1(0),
+ client_id() {}
+
+ uint32_t magic;
+@@ -135,6 +138,9 @@ struct Settings::Data {
+ uint32_t options;
+ uint32_t padding_0;
+ int64_t last_upload_attempt_time; // time_t
++ int64_t next_upload_attempt_time; // time_t
++ uint32_t backoff_step;
++ uint32_t padding_1;
+ UUID client_id;
+ };
+
+@@ -234,6 +240,56 @@ bool Settings::IsLockExpired(const base::FilePath& file_path,
+ }
+ #endif // !CRASHPAD_FLOCK_ALWAYS_SUPPORTED
+
++bool Settings::GetNextUploadAttemptTime(time_t* time) {
++ DCHECK(initialized_.is_valid());
++
++ Data settings;
++ if (!OpenAndReadSettings(&settings))
++ return false;
++
++ *time = InRangeCast<time_t>(settings.next_upload_attempt_time,
++ std::numeric_limits<time_t>::max());
++ return true;
++}
++
++bool Settings::SetNextUploadAttemptTime(time_t time) {
++ DCHECK(initialized_.is_valid());
++
++ Data settings;
++ ScopedLockedFileHandle handle = OpenForWritingAndReadSettings(&settings);
++ if (!handle.is_valid())
++ return false;
++
++ settings.next_upload_attempt_time = InRangeCast<int64_t>(time, 0);
++
++ return WriteSettings(handle.get(), settings);
++}
++
++bool Settings::GetBackoffStep(int* step) {
++ DCHECK(initialized_.is_valid());
++
++ Data settings;
++ if (!OpenAndReadSettings(&settings))
++ return false;
++
++ *step = InRangeCast<int>(settings.backoff_step,
++ std::numeric_limits<int>::max());
++ return true;
++}
++
++bool Settings::SetBackoffStep(int step) {
++ DCHECK(initialized_.is_valid());
++
++ Data settings;
++ ScopedLockedFileHandle handle = OpenForWritingAndReadSettings(&settings);
++ if (!handle.is_valid())
++ return false;
++
++ settings.backoff_step = InRangeCast<uint32_t>(step, 0);
++
++ return WriteSettings(handle.get(), settings);
++}
++
+ // static
+ Settings::ScopedLockedFileHandle Settings::MakeScopedLockedFileHandle(
+ const internal::MakeScopedLockedFileHandleOptions& options,
+diff --git third_party/crashpad/crashpad/client/settings.h third_party/crashpad/crashpad/client/settings.h
+index 39b2de869d225..5a4e621c650ee 100644
+--- third_party/crashpad/crashpad/client/settings.h
++++ third_party/crashpad/crashpad/client/settings.h
+@@ -156,6 +156,11 @@ class Settings {
+ time_t lockfile_ttl);
+ #endif // !CRASHPAD_FLOCK_ALWAYS_SUPPORTED
+
++ bool GetNextUploadAttemptTime(time_t* time);
++ bool SetNextUploadAttemptTime(time_t time);
++ bool GetBackoffStep(int* step);
++ bool SetBackoffStep(int step);
++
+ private:
+ struct Data;
+
+diff --git third_party/crashpad/crashpad/handler/BUILD.gn third_party/crashpad/crashpad/handler/BUILD.gn
+index e5d488e26c170..08d7c35b7cc5c 100644
+--- third_party/crashpad/crashpad/handler/BUILD.gn
++++ third_party/crashpad/crashpad/handler/BUILD.gn
+@@ -12,6 +12,7 @@
+ # See the License for the specific language governing permissions and
+ # limitations under the License.
+
++import("//cef/libcef/features/features.gni")
+ import("../build/crashpad_buildconfig.gni")
+
+ static_library("handler") {
+@@ -58,6 +59,17 @@ static_library("handler") {
+ ]
+ }
+
++ if (enable_cef) {
++ sources += [
++ "//cef/libcef/common/cef_crash_report_upload_thread.cc",
++ "//cef/libcef/common/cef_crash_report_upload_thread.h",
++ "//cef/libcef/common/cef_crash_report_utils.cc",
++ "//cef/libcef/common/cef_crash_report_utils.h",
++ ]
++
++ configs += [ "//cef/libcef/features:config" ]
++ }
++
+ public_configs = [ "..:crashpad_config" ]
+
+ public_deps = [
+@@ -73,6 +85,7 @@ static_library("handler") {
+ "../snapshot",
+ "../third_party/mini_chromium:chromeos_buildflags",
+ "../tools:tool_support",
++ "//cef/libcef/features",
+ ]
+
+ if (crashpad_is_win) {
+diff --git third_party/crashpad/crashpad/handler/crash_report_upload_thread.cc third_party/crashpad/crashpad/handler/crash_report_upload_thread.cc
+index 5bd2889eda975..bf3ff4bfcf5c8 100644
+--- third_party/crashpad/crashpad/handler/crash_report_upload_thread.cc
++++ third_party/crashpad/crashpad/handler/crash_report_upload_thread.cc
+@@ -297,6 +297,8 @@ CrashReportUploadThread::UploadResult CrashReportUploadThread::UploadReport(
+ if (minidump_process_snapshot.Initialize(reader)) {
+ parameters =
+ BreakpadHTTPFormParametersFromMinidump(&minidump_process_snapshot);
++ if (!parameters.empty())
++ parameters = FilterParameters(parameters);
+ }
+
+ if (!reader->SeekSet(start_offset)) {
+diff --git third_party/crashpad/crashpad/handler/crash_report_upload_thread.h third_party/crashpad/crashpad/handler/crash_report_upload_thread.h
+index 22bb26e31893b..87c80604e5f7a 100644
+--- third_party/crashpad/crashpad/handler/crash_report_upload_thread.h
++++ third_party/crashpad/crashpad/handler/crash_report_upload_thread.h
+@@ -16,6 +16,7 @@
+ #define CRASHPAD_HANDLER_CRASH_REPORT_UPLOAD_THREAD_H_
+
+ #include <functional>
++#include <map>
+ #include <memory>
+ #include <string>
+ #include <unordered_map>
+@@ -128,7 +129,7 @@ class CrashReportUploadThread : public WorkerThread::Delegate,
+ //! \return `true` if the thread is running, `false` if it is not.
+ bool is_running() const { return thread_.is_running(); }
+
+- private:
++ protected:
+ //! \brief The result code from UploadReport().
+ enum class UploadResult {
+ //! \brief The crash report was uploaded successfully.
+@@ -156,7 +157,7 @@ class CrashReportUploadThread : public WorkerThread::Delegate,
+ //! object was constructed with \a watch_pending_reports, it will also scan
+ //! the crash report database for other pending reports, and process those as
+ //! well.
+- void ProcessPendingReports();
++ virtual void ProcessPendingReports();
+
+ //! \brief Processes a single pending report from the database.
+ //!
+@@ -170,7 +171,7 @@ class CrashReportUploadThread : public WorkerThread::Delegate,
+ //! remain in the “pending” state. If the upload fails and no more retries are
+ //! desired, or report upload is disabled, it will be marked as “completed” in
+ //! the database without ever having been uploaded.
+- void ProcessPendingReport(const CrashReportDatabase::Report& report);
++ virtual void ProcessPendingReport(const CrashReportDatabase::Report& report);
+
+ //! \brief Attempts to upload a crash report.
+ //!
+@@ -187,6 +188,11 @@ class CrashReportUploadThread : public WorkerThread::Delegate,
+ UploadResult UploadReport(const CrashReportDatabase::UploadReport* report,
+ std::string* response_body);
+
++ using ParameterMap = std::map<std::string, std::string>;
++ virtual ParameterMap FilterParameters(const ParameterMap& parameters) {
++ return parameters;
++ }
++
+ // WorkerThread::Delegate:
+ //! \brief Calls ProcessPendingReports() in response to ReportPending() having
+ //! been called on any thread, as well as periodically on a timer.
+diff --git third_party/crashpad/crashpad/handler/handler_main.cc third_party/crashpad/crashpad/handler/handler_main.cc
+index b7ba6b14bb9b3..0567343c99325 100644
+--- third_party/crashpad/crashpad/handler/handler_main.cc
++++ third_party/crashpad/crashpad/handler/handler_main.cc
+@@ -39,6 +39,7 @@
+ #include "base/strings/utf_string_conversions.h"
+ #include "build/build_config.h"
+ #include "build/chromeos_buildflags.h"
++#include "cef/libcef/features/features.h"
+ #include "client/crash_report_database.h"
+ #include "client/crashpad_client.h"
+ #include "client/crashpad_info.h"
+@@ -89,6 +90,10 @@
+ #include "util/win/session_end_watcher.h"
+ #endif // BUILDFLAG(IS_APPLE)
+
++#if BUILDFLAG(ENABLE_CEF)
++#include "cef/libcef/common/cef_crash_report_upload_thread.h"
++#endif
++
+ namespace crashpad {
+
+ namespace {
+@@ -248,6 +253,9 @@ struct Options {
+ bool periodic_tasks;
+ bool rate_limit;
+ bool upload_gzip;
++ int max_uploads;
++ int max_database_size;
++ int max_database_age;
+ #if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
+ bool use_cros_crash_reporter = false;
+ base::FilePath minidump_dir_for_tests;
+@@ -622,6 +630,9 @@ int HandlerMain(int argc,
+ kOptionTraceParentWithException,
+ #endif
+ kOptionURL,
++ kOptionMaxUploads,
++ kOptionMaxDatabaseSize,
++ kOptionMaxDatabaseAge,
+ #if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
+ kOptionUseCrosCrashReporter,
+ kOptionMinidumpDirForTests,
+@@ -722,6 +733,9 @@ int HandlerMain(int argc,
+ #endif // BUILDFLAG(IS_ANDROID)
+ {"help", no_argument, nullptr, kOptionHelp},
+ {"version", no_argument, nullptr, kOptionVersion},
++ {"max-uploads", required_argument, nullptr, kOptionMaxUploads},
++ {"max-db-size", required_argument, nullptr, kOptionMaxDatabaseSize},
++ {"max-db-age", required_argument, nullptr, kOptionMaxDatabaseAge},
+ {nullptr, 0, nullptr, 0},
+ };
+
+@@ -879,6 +893,27 @@ int HandlerMain(int argc,
+ options.url = optarg;
+ break;
+ }
++ case kOptionMaxUploads: {
++ if (base::StringToInt(optarg, &options.max_uploads)) {
++ if (options.max_uploads < 0)
++ options.max_uploads = 0;
++ }
++ break;
++ }
++ case kOptionMaxDatabaseSize: {
++ if (base::StringToInt(optarg, &options.max_database_size)) {
++ if (options.max_database_size < 0)
++ options.max_database_size = 0;
++ }
++ break;
++ }
++ case kOptionMaxDatabaseAge: {
++ if (base::StringToInt(optarg, &options.max_database_age)) {
++ if (options.max_database_age < 0)
++ options.max_database_age = 0;
++ }
++ break;
++ }
+ #if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
+ case kOptionUseCrosCrashReporter: {
+ options.use_cros_crash_reporter = true;
+@@ -1028,11 +1063,20 @@ int HandlerMain(int argc,
+ upload_thread_options.upload_gzip = options.upload_gzip;
+ upload_thread_options.watch_pending_reports = options.periodic_tasks;
+
++#if BUILDFLAG(ENABLE_CEF)
++ upload_thread.Reset(new CefCrashReportUploadThread(
++ database.get(),
++ options.url,
++ upload_thread_options,
++ CrashReportUploadThread::ProcessPendingReportsObservationCallback(),
++ options.max_uploads));
++#else
+ upload_thread.Reset(new CrashReportUploadThread(
+ database.get(),
+ options.url,
+ upload_thread_options,
+ CrashReportUploadThread::ProcessPendingReportsObservationCallback()));
++#endif
+ upload_thread.Get()->Start();
+ }
+
+@@ -1103,7 +1147,8 @@ int HandlerMain(int argc,
+ ScopedStoppable prune_thread;
+ if (options.periodic_tasks) {
+ prune_thread.Reset(new PruneCrashReportThread(
+- database.get(), PruneCondition::GetDefault()));
++ database.get(), PruneCondition::GetDefault(options.max_database_size,
++ options.max_database_age)));
+ prune_thread.Get()->Start();
+ }
+
diff --git a/patch/patches/embedder_product_override.patch b/patch/patches/embedder_product_override.patch
new file mode 100644
index 00000000..b6993e47
--- /dev/null
+++ b/patch/patches/embedder_product_override.patch
@@ -0,0 +1,38 @@
+diff --git components/embedder_support/user_agent_utils.cc components/embedder_support/user_agent_utils.cc
+index e7fe1c565aac5..45980ceed2c50 100644
+--- components/embedder_support/user_agent_utils.cc
++++ components/embedder_support/user_agent_utils.cc
+@@ -17,6 +17,7 @@
+ #include "base/version.h"
+ #include "build/branding_buildflags.h"
+ #include "build/build_config.h"
++#include "cef/libcef/features/features.h"
+ #include "components/embedder_support/pref_names.h"
+ #include "components/embedder_support/switches.h"
+ #include "components/policy/core/common/policy_pref_names.h"
+@@ -37,6 +38,10 @@
+ #include "base/win/windows_version.h"
+ #endif // BUILDFLAG(IS_WIN)
+
++#if BUILDFLAG(ENABLE_CEF)
++#include "cef/libcef/common/cef_switches.h"
++#endif
++
+ namespace embedder_support {
+
+ namespace {
+@@ -339,6 +344,14 @@ std::string GetMajorVersionForUserAgentString(
+ std::string GetProductAndVersion(
+ ForceMajorVersionToMinorPosition force_major_to_minor,
+ UserAgentReductionEnterprisePolicyState user_agent_reduction) {
++#if BUILDFLAG(ENABLE_CEF)
++ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
++ if (command_line->HasSwitch(switches::kUserAgentProductAndVersion)) {
++ return command_line->GetSwitchValueASCII(
++ switches::kUserAgentProductAndVersion);
++ }
++#endif
++
+ if (ShouldForceMajorVersionToMinorPosition(force_major_to_minor)) {
+ // Force major version to 99 and major version to minor version position.
+ if (ShouldReduceUserAgentMinorVersion(user_agent_reduction)) {
diff --git a/patch/patches/extensions_1947.patch b/patch/patches/extensions_1947.patch
new file mode 100644
index 00000000..f8e1e128
--- /dev/null
+++ b/patch/patches/extensions_1947.patch
@@ -0,0 +1,264 @@
+diff --git chrome/browser/extensions/api/streams_private/streams_private_api.cc chrome/browser/extensions/api/streams_private/streams_private_api.cc
+index cead7cfa14bae..24142c2e4896f 100644
+--- chrome/browser/extensions/api/streams_private/streams_private_api.cc
++++ chrome/browser/extensions/api/streams_private/streams_private_api.cc
+@@ -6,6 +6,7 @@
+
+ #include <utility>
+
++#include "cef/libcef/features/runtime.h"
+ #include "chrome/browser/extensions/extension_tab_util.h"
+ #include "chrome/browser/preloading/prefetch/no_state_prefetch/chrome_no_state_prefetch_contents_delegate.h"
+ #include "components/no_state_prefetch/browser/no_state_prefetch_contents.h"
+@@ -18,6 +19,10 @@
+ #include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h"
+ #include "extensions/common/manifest_handlers/mime_types_handler.h"
+
++#if BUILDFLAG(ENABLE_CEF)
++#include "cef/libcef/browser/extensions/alloy_extensions_util.h"
++#endif
++
+ namespace extensions {
+
+ void StreamsPrivateAPI::SendExecuteMimeTypeHandlerEvent(
+@@ -34,6 +39,7 @@ void StreamsPrivateAPI::SendExecuteMimeTypeHandlerEvent(
+ if (!web_contents)
+ return;
+
++ if (!cef::IsAlloyRuntimeEnabled()) {
+ // If the request was for NoStatePrefetch, abort the prefetcher and do not
+ // continue. This is because plugins cancel NoStatePrefetch, see
+ // http://crbug.com/343590.
+@@ -44,6 +50,7 @@ void StreamsPrivateAPI::SendExecuteMimeTypeHandlerEvent(
+ no_state_prefetch_contents->Destroy(prerender::FINAL_STATUS_DOWNLOAD);
+ return;
+ }
++ }
+
+ auto* browser_context = web_contents->GetBrowserContext();
+
+@@ -70,9 +77,18 @@ void StreamsPrivateAPI::SendExecuteMimeTypeHandlerEvent(
+ // forms of zooming won't work).
+ // TODO(1042323): Present a coherent representation of a tab id for portal
+ // contents.
+- int tab_id = web_contents->GetOuterWebContents()
+- ? SessionID::InvalidValue().id()
+- : ExtensionTabUtil::GetTabId(web_contents);
++ int tab_id;
++ if (web_contents->GetOuterWebContents()) {
++ tab_id = SessionID::InvalidValue().id();
++ } else
++#if BUILDFLAG(ENABLE_CEF)
++ if (cef::IsAlloyRuntimeEnabled()) {
++ tab_id = alloy::GetTabIdForWebContents(web_contents);
++ } else
++#endif // BUILDFLAG(ENABLE_CEF)
++ {
++ tab_id = ExtensionTabUtil::GetTabId(web_contents);
++ }
+
+ std::unique_ptr<StreamContainer> stream_container(
+ new StreamContainer(tab_id, embedded, handler_url, extension_id,
+diff --git extensions/browser/extension_host.cc extensions/browser/extension_host.cc
+index 4d29671429220..e0f287f785668 100644
+--- extensions/browser/extension_host.cc
++++ extensions/browser/extension_host.cc
+@@ -62,11 +62,12 @@ ExtensionHost::ExtensionHost(const Extension* extension,
+ host_type == mojom::ViewType::kExtensionDialog ||
+ host_type == mojom::ViewType::kExtensionPopup ||
+ host_type == mojom::ViewType::kExtensionSidePanel);
+- host_contents_ = WebContents::Create(
++ host_contents_owned_ = WebContents::Create(
+ WebContents::CreateParams(browser_context_, site_instance)),
+- content::WebContentsObserver::Observe(host_contents_.get());
++ host_contents_ = host_contents_owned_.get();
++ content::WebContentsObserver::Observe(host_contents_);
+ host_contents_->SetDelegate(this);
+- SetViewType(host_contents_.get(), host_type);
++ SetViewType(host_contents_, host_type);
+ main_frame_host_ = host_contents_->GetPrimaryMainFrame();
+
+ // Listen for when an extension is unloaded from the same profile, as it may
+@@ -81,6 +82,44 @@ ExtensionHost::ExtensionHost(const Extension* extension,
+ ExtensionHostRegistry::Get(browser_context_)->ExtensionHostCreated(this);
+ }
+
++ExtensionHost::ExtensionHost(ExtensionHostDelegate* delegate,
++ const Extension* extension,
++ content::BrowserContext* browser_context,
++ content::WebContents* host_contents,
++ const GURL& url,
++ mojom::ViewType host_type)
++ : delegate_(delegate),
++ extension_(extension),
++ extension_id_(extension->id()),
++ browser_context_(browser_context),
++ host_contents_(host_contents),
++ initial_url_(url),
++ extension_host_type_(host_type) {
++ DCHECK(delegate);
++ DCHECK(browser_context);
++ DCHECK(host_contents);
++
++ // Not used for panels, see PanelHost.
++ DCHECK(host_type == mojom::ViewType::kExtensionBackgroundPage ||
++ host_type == mojom::ViewType::kExtensionDialog ||
++ host_type == mojom::ViewType::kExtensionPopup);
++
++ content::WebContentsObserver::Observe(host_contents_);
++ SetViewType(host_contents_, host_type);
++
++ main_frame_host_ = host_contents_->GetPrimaryMainFrame();
++
++ // Listen for when an extension is unloaded from the same profile, as it may
++ // be the same extension that this points to.
++ ExtensionRegistry::Get(browser_context_)->AddObserver(this);
++
++ // Set up web contents observers and pref observers.
++ delegate_->OnExtensionHostCreated(host_contents_);
++
++ ExtensionWebContentsObserver::GetForWebContents(host_contents_)->
++ dispatcher()->set_delegate(this);
++}
++
+ ExtensionHost::~ExtensionHost() {
+ ExtensionRegistry::Get(browser_context_)->RemoveObserver(this);
+
+diff --git extensions/browser/extension_host.h extensions/browser/extension_host.h
+index 9ba85048d1fcf..f3a5b8bc9bda0 100644
+--- extensions/browser/extension_host.h
++++ extensions/browser/extension_host.h
+@@ -59,6 +59,12 @@ class ExtensionHost : public DeferredStartRenderHost,
+ content::SiteInstance* site_instance,
+ const GURL& url,
+ mojom::ViewType host_type);
++ ExtensionHost(ExtensionHostDelegate* delegate,
++ const Extension* extension,
++ content::BrowserContext* browser_context,
++ content::WebContents* host_contents,
++ const GURL& url,
++ mojom::ViewType host_type);
+
+ ExtensionHost(const ExtensionHost&) = delete;
+ ExtensionHost& operator=(const ExtensionHost&) = delete;
+@@ -69,7 +75,7 @@ class ExtensionHost : public DeferredStartRenderHost,
+ const Extension* extension() const { return extension_; }
+
+ const std::string& extension_id() const { return extension_id_; }
+- content::WebContents* host_contents() const { return host_contents_.get(); }
++ content::WebContents* host_contents() const { return host_contents_; }
+ content::RenderFrameHost* main_frame_host() const { return main_frame_host_; }
+ content::RenderProcessHost* render_process_host() const;
+ bool has_loaded_once() const { return has_loaded_once_; }
+@@ -205,7 +211,8 @@ class ExtensionHost : public DeferredStartRenderHost,
+ raw_ptr<content::BrowserContext> browser_context_;
+
+ // The host for our HTML content.
+- std::unique_ptr<content::WebContents> host_contents_;
++ std::unique_ptr<content::WebContents> host_contents_owned_;
++ content::WebContents* host_contents_;
+
+ // A pointer to the current or speculative main frame in `host_contents_`. We
+ // can't access this frame through the `host_contents_` directly as it does
+diff --git extensions/browser/extension_registry.cc extensions/browser/extension_registry.cc
+index 10d751cceab73..128af05925e07 100644
+--- extensions/browser/extension_registry.cc
++++ extensions/browser/extension_registry.cc
+@@ -6,9 +6,14 @@
+
+ #include "base/observer_list.h"
+ #include "base/strings/string_util.h"
++#include "cef/libcef/features/runtime.h"
+ #include "extensions/browser/extension_registry_factory.h"
+ #include "extensions/browser/extension_registry_observer.h"
+
++#if BUILDFLAG(ENABLE_CEF)
++#include "cef/libcef/common/extensions/extensions_util.h"
++#endif
++
+ namespace extensions {
+
+ ExtensionRegistry::ExtensionRegistry(content::BrowserContext* browser_context)
+@@ -17,6 +22,11 @@ ExtensionRegistry::~ExtensionRegistry() {}
+
+ // static
+ ExtensionRegistry* ExtensionRegistry::Get(content::BrowserContext* context) {
++#if BUILDFLAG(ENABLE_CEF)
++ if (cef::IsAlloyRuntimeEnabled() && !extensions::ExtensionsEnabled()) {
++ return nullptr;
++ }
++#endif
+ return ExtensionRegistryFactory::GetForBrowserContext(context);
+ }
+
+diff --git extensions/browser/extensions_browser_client.h extensions/browser/extensions_browser_client.h
+index bb7a1c1860f7f..25f9d0c47e5ab 100644
+--- extensions/browser/extensions_browser_client.h
++++ extensions/browser/extensions_browser_client.h
+@@ -31,6 +31,7 @@
+ #include "url/gurl.h"
+
+ class ExtensionFunctionRegistry;
++class GURL;
+ class PrefService;
+
+ namespace base {
+@@ -73,6 +74,7 @@ class ComponentExtensionResourceManager;
+ class Extension;
+ class ExtensionCache;
+ class ExtensionError;
++class ExtensionHost;
+ class ExtensionHostDelegate;
+ class ExtensionSet;
+ class ExtensionSystem;
+@@ -248,6 +250,14 @@ class ExtensionsBrowserClient {
+ virtual std::unique_ptr<ExtensionHostDelegate>
+ CreateExtensionHostDelegate() = 0;
+
++ // CEF creates a custom ExtensionHost for background pages. If the return
++ // value is true and |host| is NULL then fail the background host creation.
++ virtual bool CreateBackgroundExtensionHost(
++ const Extension* extension,
++ content::BrowserContext* browser_context,
++ const GURL& url,
++ ExtensionHost** host) { return false; }
++
+ // Returns true if the client version has updated since the last run. Called
+ // once each time the extensions system is loaded per browser_context. The
+ // implementation may wish to use the BrowserContext to record the current
+diff --git extensions/browser/process_manager.cc extensions/browser/process_manager.cc
+index 0a9fa13f82250..2d0ed7c2396c4 100644
+--- extensions/browser/process_manager.cc
++++ extensions/browser/process_manager.cc
+@@ -380,9 +380,17 @@ bool ProcessManager::CreateBackgroundHost(const Extension* extension,
+ return true; // TODO(kalman): return false here? It might break things...
+
+ DVLOG(1) << "CreateBackgroundHost " << extension->id();
+- ExtensionHost* host =
++ ExtensionHost* host = nullptr;
++ if (ExtensionsBrowserClient::Get()->CreateBackgroundExtensionHost(
++ extension, browser_context_, url, &host) && !host) {
++ // Explicitly fail if the client can't create the host.
++ return false;
++ }
++ if (!host) {
++ host =
+ new ExtensionHost(extension, GetSiteInstanceForURL(url).get(), url,
+ mojom::ViewType::kExtensionBackgroundPage);
++ }
+ host->SetCloseHandler(
+ base::BindOnce(&ProcessManager::HandleCloseExtensionHost,
+ weak_ptr_factory_.GetWeakPtr()));
+diff --git extensions/common/extensions_client.cc extensions/common/extensions_client.cc
+index 53ad0736cfbdf..c252591fa646d 100644
+--- extensions/common/extensions_client.cc
++++ extensions/common/extensions_client.cc
+@@ -23,7 +23,7 @@ ExtensionsClient* g_client = nullptr;
+ } // namespace
+
+ ExtensionsClient* ExtensionsClient::Get() {
+- DCHECK(g_client);
++ // May be nullptr if using CEF Alloy with extensions disabled.
+ return g_client;
+ }
+
diff --git a/patch/patches/font_family_cache_1501.patch b/patch/patches/font_family_cache_1501.patch
new file mode 100644
index 00000000..f4df0ba3
--- /dev/null
+++ b/patch/patches/font_family_cache_1501.patch
@@ -0,0 +1,13 @@
+diff --git chrome/browser/font_family_cache.h chrome/browser/font_family_cache.h
+index 459a25956e6e3..ef9148bf69e9b 100644
+--- chrome/browser/font_family_cache.h
++++ chrome/browser/font_family_cache.h
+@@ -19,6 +19,8 @@ class Profile;
+
+ FORWARD_DECLARE_TEST(FontFamilyCacheTest, Caching);
+
++extern const char kFontFamilyCacheKey[];
++
+ // Caches font family preferences associated with a PrefService. This class
+ // relies on the assumption that each concatenation of map_name + '.' + script
+ // is a unique string. It also relies on the assumption that the (const char*)
diff --git a/patch/patches/gn_config.patch b/patch/patches/gn_config.patch
new file mode 100644
index 00000000..effff6a9
--- /dev/null
+++ b/patch/patches/gn_config.patch
@@ -0,0 +1,175 @@
+diff --git .gn .gn
+index a9b0a5a827fc8..9a0fd388756f3 100644
+--- .gn
++++ .gn
+@@ -151,6 +151,8 @@ exec_script_whitelist =
+ "//chrome/android/webapk/shell_apk/prepare_upload_dir/BUILD.gn",
+ "//chrome/version.gni",
+
++ "//cef/BUILD.gn",
++
+ # TODO(dgn): Layer violation but breaks the build otherwise, see
+ # https://crbug.com/474506.
+ "//clank/java/BUILD.gn",
+diff --git BUILD.gn BUILD.gn
+index 7cfadb4724141..e59835c875ec6 100644
+--- BUILD.gn
++++ BUILD.gn
+@@ -18,6 +18,7 @@ import("//build/config/sanitizers/sanitizers.gni")
+ import("//build/config/ui.gni")
+ import("//build/gn_logs.gni")
+ import("//build/util/generate_wrapper.gni")
++import("//cef/libcef/features/features.gni")
+ import("//chrome/browser/buildflags.gni")
+ import("//components/nacl/features.gni")
+ import("//device/vr/buildflags/buildflags.gni")
+@@ -274,6 +275,10 @@ group("gn_all") {
+
+ deps += root_extra_deps
+
++ if (enable_cef) {
++ deps += [ "//cef" ]
++ }
++
+ if (enable_printing) {
+ deps += [ "//printing:printing_unittests" ]
+ }
+diff --git build/config/win/visual_studio_version.gni build/config/win/visual_studio_version.gni
+index d9024468296e7..11bfae65b7b02 100644
+--- build/config/win/visual_studio_version.gni
++++ build/config/win/visual_studio_version.gni
+@@ -12,9 +12,8 @@ declare_args() {
+ # Currently always "2015".
+ visual_studio_version = ""
+
+- # Directory of the Windows driver kit. If visual_studio_path is empty, this
+- # will be auto-filled.
+- wdk_path = ""
++ # Path to Visual Studio runtime libraries.
++ visual_studio_runtime_dirs = ""
+
+ # Full path to the Windows SDK, not including a backslash at the end.
+ # This value is the default location, override if you have a different
+@@ -28,12 +27,11 @@ if (visual_studio_path == "") {
+ visual_studio_path = toolchain_data.vs_path
+ windows_sdk_path = toolchain_data.sdk_path
+ visual_studio_version = toolchain_data.vs_version
+- wdk_path = toolchain_data.wdk_dir
+ visual_studio_runtime_dirs = toolchain_data.runtime_dirs
+ } else {
+ assert(visual_studio_version != "",
+ "You must set the visual_studio_version if you set the path")
+- assert(wdk_path != "",
+- "You must set the wdk_path if you set the visual studio path")
+- visual_studio_runtime_dirs = []
++ assert(visual_studio_runtime_dirs != "",
++ "You must set the visual_studio_runtime_dirs if you set the visual " +
++ "studio path")
+ }
+diff --git chrome/app/framework.order chrome/app/framework.order
+index 60f573a736ba5..90dd6d0b37314 100644
+--- chrome/app/framework.order
++++ chrome/app/framework.order
+@@ -28,3 +28,8 @@ _ChromeMain
+ _lprofDirMode
+ ___llvm_profile_filename
+ ___llvm_profile_raw_version
++
++# Symbols exported for CEF.
++_OBJC_CLASS_$_UnderlayOpenGLHostingWindow
++_OBJC_METACLASS_$_UnderlayOpenGLHostingWindow
++
+diff --git chrome/chrome_paks.gni chrome/chrome_paks.gni
+index a16658689a69e..36515332da633 100644
+--- chrome/chrome_paks.gni
++++ chrome/chrome_paks.gni
+@@ -6,6 +6,7 @@ import("//ash/ambient/resources/resources.gni")
+ import("//build/config/chromebox_for_meetings/buildflags.gni")
+ import("//build/config/chromeos/ui_mode.gni")
+ import("//build/config/locales.gni")
++import("//cef/libcef/features/features.gni")
+ import("//chrome/browser/buildflags.gni")
+ import("//chrome/common/features.gni")
+ import("//extensions/buildflags/buildflags.gni")
+@@ -73,6 +74,10 @@ template("chrome_repack_percent") {
+ "//ui/chromeos/resources",
+ ]
+ }
++ if (enable_cef) {
++ sources += [ "$root_gen_dir/cef/cef_resources.pak" ]
++ deps += [ "//cef:cef_resources" ]
++ }
+ if (enable_extensions) {
+ sources += [ "$root_gen_dir/extensions/extensions_browser_resources_${percent}_percent.pak" ]
+ deps += [ "//extensions:extensions_browser_resources" ]
+diff --git chrome/chrome_repack_locales.gni chrome/chrome_repack_locales.gni
+index adc881122cb9c..cafa71386fad6 100644
+--- chrome/chrome_repack_locales.gni
++++ chrome/chrome_repack_locales.gni
+@@ -6,6 +6,7 @@ import("//build/config/chrome_build.gni")
+ import("//build/config/chromeos/ui_mode.gni")
+ import("//build/config/features.gni")
+ import("//build/config/ui.gni")
++import("//cef/libcef/features/features.gni")
+ import("//extensions/buildflags/buildflags.gni")
+ import("//tools/grit/repack.gni")
+
+@@ -91,6 +92,10 @@ template("chrome_repack_locales") {
+ [ "${root_gen_dir}/chromeos/strings/chromeos_strings_" ]
+ deps += [ "//chromeos/strings" ]
+ }
++ if (enable_cef) {
++ source_patterns += [ "${root_gen_dir}/cef/cef_strings_" ]
++ deps += [ "//cef:cef_strings" ]
++ }
+ if (enable_extensions) {
+ source_patterns +=
+ [ "${root_gen_dir}/extensions/strings/extensions_strings_" ]
+diff --git chrome/installer/mini_installer/BUILD.gn chrome/installer/mini_installer/BUILD.gn
+index 4e6af9a522de5..b1851bc764355 100644
+--- chrome/installer/mini_installer/BUILD.gn
++++ chrome/installer/mini_installer/BUILD.gn
+@@ -6,6 +6,7 @@ import("//build/config/compiler/compiler.gni")
+ import("//build/config/features.gni")
+ import("//build/config/python.gni")
+ import("//build/config/ui.gni")
++import("//cef/libcef/features/features.gni")
+ import("//chrome/process_version_rc_template.gni")
+ import("//components/nacl/features.gni")
+ import("//third_party/ffmpeg/ffmpeg_options.gni")
+@@ -121,11 +122,13 @@ action("mini_installer_archive") {
+ inputs = [
+ "$root_out_dir/chrome.dll",
+ "$root_out_dir/chrome.exe",
+- "$root_out_dir/locales/en-US.pak",
+ "$root_out_dir/setup.exe",
+ "//chrome/tools/build/win/makecab.py",
+ release_file,
+ ]
++ if (!enable_cef) {
++ inputs += [ "$root_out_dir/locales/en-US.pak" ]
++ }
+
+ outputs = [
+ "$root_out_dir/chrome.7z",
+diff --git tools/grit/grit_args.gni tools/grit/grit_args.gni
+index 77f1be6116d0c..6bc41416af551 100644
+--- tools/grit/grit_args.gni
++++ tools/grit/grit_args.gni
+@@ -5,6 +5,7 @@
+ import("//build/config/chrome_build.gni")
+ import("//build/config/chromeos/ui_mode.gni")
+ import("//build/config/devtools.gni")
++import("//build/config/locales.gni")
+ import("//build/config/ui.gni")
+
+ shared_intermediate_dir = rebase_path(root_gen_dir, root_build_dir)
+@@ -36,6 +37,8 @@ _grit_defines = [
+
+ # Mac and iOS want Title Case strings.
+ "use_titlecase=${is_apple}",
++
++ "enable_pseudolocales=${enable_pseudolocales}",
+ ]
+
+ # Must match `enable_hidpi` in ui/base/ui_features.gni.
diff --git a/patch/patches/gritsettings.patch b/patch/patches/gritsettings.patch
new file mode 100644
index 00000000..5230061b
--- /dev/null
+++ b/patch/patches/gritsettings.patch
@@ -0,0 +1,20 @@
+diff --git tools/gritsettings/resource_ids.spec tools/gritsettings/resource_ids.spec
+index 15e77b25cc0b1..96d70a5ba039f 100644
+--- tools/gritsettings/resource_ids.spec
++++ tools/gritsettings/resource_ids.spec
+@@ -1110,6 +1110,15 @@
+ # END "everything else" section.
+ # Everything but chrome/, components/, content/, and ios/
+
++ "cef/libcef/resources/cef_resources.grd": {
++ "META": {"align": 31500},
++ "includes": [31500],
++ },
++ "cef/libcef/resources/cef_strings.grd": {
++ "META": {"align": 32000},
++ "messages": [32000],
++ },
++
+ # Thinking about appending to the end?
+ # Please read the header and find the right section above instead.
+ }
diff --git a/patch/patches/libxml_visibility.patch b/patch/patches/libxml_visibility.patch
new file mode 100644
index 00000000..06c567d9
--- /dev/null
+++ b/patch/patches/libxml_visibility.patch
@@ -0,0 +1,12 @@
+diff --git third_party/libxml/BUILD.gn third_party/libxml/BUILD.gn
+index 48840f40a3d19..c6a172fded049 100644
+--- third_party/libxml/BUILD.gn
++++ third_party/libxml/BUILD.gn
+@@ -140,6 +140,7 @@ static_library("libxml") {
+ ":libxml_utils",
+ ":xml_reader",
+ ":xml_writer",
++ "//cef:*",
+ "//chromecast/internal",
+ "//testing/libfuzzer/*",
+ "//third_party/blink/renderer/*",
diff --git a/patch/patches/linux_assets_path_1936.patch b/patch/patches/linux_assets_path_1936.patch
new file mode 100644
index 00000000..8cb1ce24
--- /dev/null
+++ b/patch/patches/linux_assets_path_1936.patch
@@ -0,0 +1,39 @@
+diff --git content/browser/child_process_launcher_helper_linux.cc content/browser/child_process_launcher_helper_linux.cc
+index b7f21237e87fa..11e4c166ab8a6 100644
+--- content/browser/child_process_launcher_helper_linux.cc
++++ content/browser/child_process_launcher_helper_linux.cc
+@@ -183,7 +183,7 @@ ZygoteCommunication* ChildProcessLauncherHelper::GetZygoteForLaunch() {
+ base::File OpenFileToShare(const base::FilePath& path,
+ base::MemoryMappedFile::Region* region) {
+ base::FilePath exe_dir;
+- bool result = base::PathService::Get(base::BasePathKey::DIR_EXE, &exe_dir);
++ bool result = base::PathService::Get(base::BasePathKey::DIR_ASSETS, &exe_dir);
+ DCHECK(result);
+ base::File file(exe_dir.Append(path),
+ base::File::FLAG_OPEN | base::File::FLAG_READ);
+diff --git sandbox/linux/suid/client/setuid_sandbox_host.cc sandbox/linux/suid/client/setuid_sandbox_host.cc
+index 84fd365da0283..88f3adf813eca 100644
+--- sandbox/linux/suid/client/setuid_sandbox_host.cc
++++ sandbox/linux/suid/client/setuid_sandbox_host.cc
+@@ -120,7 +120,7 @@ bool SetuidSandboxHost::IsDisabledViaEnvironment() {
+ base::FilePath SetuidSandboxHost::GetSandboxBinaryPath() {
+ base::FilePath sandbox_binary;
+ base::FilePath exe_dir;
+- if (base::PathService::Get(base::DIR_EXE, &exe_dir)) {
++ if (base::PathService::Get(base::DIR_ASSETS, &exe_dir)) {
+ base::FilePath sandbox_candidate = exe_dir.AppendASCII("chrome-sandbox");
+ if (base::PathExists(sandbox_candidate))
+ sandbox_binary = sandbox_candidate;
+diff --git ui/ozone/common/egl_util.cc ui/ozone/common/egl_util.cc
+index 021bcad8c3084..a37406d408718 100644
+--- ui/ozone/common/egl_util.cc
++++ ui/ozone/common/egl_util.cc
+@@ -127,7 +127,7 @@ bool LoadDefaultEGLGLES2Bindings(
+ if (implementation.gl == gl::kGLImplementationEGLANGLE) {
+ base::FilePath module_path;
+ #if !BUILDFLAG(IS_FUCHSIA)
+- if (!base::PathService::Get(base::DIR_MODULE, &module_path))
++ if (!base::PathService::Get(base::DIR_ASSETS, &module_path))
+ return false;
+ #endif
+
diff --git a/patch/patches/linux_atk_1123214.patch b/patch/patches/linux_atk_1123214.patch
new file mode 100644
index 00000000..a973758e
--- /dev/null
+++ b/patch/patches/linux_atk_1123214.patch
@@ -0,0 +1,26 @@
+diff --git build/config/linux/atk/BUILD.gn build/config/linux/atk/BUILD.gn
+index 239c3870a149a..9f5a34fc846bd 100644
+--- build/config/linux/atk/BUILD.gn
++++ build/config/linux/atk/BUILD.gn
+@@ -11,7 +11,7 @@ import("//build/config/ui.gni")
+ assert(!is_chromeos)
+
+ # These packages should _only_ be expected when building for a target.
+-assert(current_toolchain == default_toolchain)
++# assert(current_toolchain == default_toolchain)
+
+ if (use_atk) {
+ assert(use_glib, "use_atk=true requires that use_glib=true")
+diff --git build/config/linux/atspi2/BUILD.gn build/config/linux/atspi2/BUILD.gn
+index 51b6d33aab3c2..970d454e6b539 100644
+--- build/config/linux/atspi2/BUILD.gn
++++ build/config/linux/atspi2/BUILD.gn
+@@ -6,7 +6,7 @@ import("//build/config/linux/pkg_config.gni")
+ import("//build/config/ui.gni")
+
+ # These packages should _only_ be expected when building for a target.
+-assert(current_toolchain == default_toolchain)
++# assert(current_toolchain == default_toolchain)
+
+ if (use_atk) {
+ pkg_config("atspi2") {
diff --git a/patch/patches/linux_blink_thread_local.patch b/patch/patches/linux_blink_thread_local.patch
new file mode 100644
index 00000000..b4134f16
--- /dev/null
+++ b/patch/patches/linux_blink_thread_local.patch
@@ -0,0 +1,13 @@
+diff --git third_party/blink/renderer/platform/heap/thread_local.h third_party/blink/renderer/platform/heap/thread_local.h
+index 6993877c6c3ad..bf4f1626fa332 100644
+--- third_party/blink/renderer/platform/heap/thread_local.h
++++ third_party/blink/renderer/platform/heap/thread_local.h
+@@ -36,7 +36,7 @@
+ #if BLINK_HEAP_HIDE_THREAD_LOCAL_IN_LIBRARY
+ #define BLINK_HEAP_THREAD_LOCAL_MODEL "local-dynamic"
+ #else
+-#if BUILDFLAG(IS_WIN)
++#if BUILDFLAG(IS_WIN) || (BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_MAC))
+ #define BLINK_HEAP_THREAD_LOCAL_MODEL "initial-exec"
+ #elif BUILDFLAG(IS_ANDROID)
+ #define BLINK_HEAP_THREAD_LOCAL_MODEL "local-dynamic"
diff --git a/patch/patches/linux_bluetooth_1319006.patch b/patch/patches/linux_bluetooth_1319006.patch
new file mode 100644
index 00000000..8e9cb406
--- /dev/null
+++ b/patch/patches/linux_bluetooth_1319006.patch
@@ -0,0 +1,21 @@
+diff --git device/bluetooth/BUILD.gn device/bluetooth/BUILD.gn
+index 0b526044dcc7c..349ffa6a6ceca 100644
+--- device/bluetooth/BUILD.gn
++++ device/bluetooth/BUILD.gn
+@@ -46,10 +46,12 @@ source_set("deprecated_experimental_mojo") {
+ ]
+
+ if (is_chromeos || is_linux) {
+- sources += [
+- "bluez/metrics_recorder.cc",
+- "bluez/metrics_recorder.h",
+- ]
++ if (is_component_build) {
++ sources += [
++ "bluez/metrics_recorder.cc",
++ "bluez/metrics_recorder.h",
++ ]
++ }
+ }
+
+ deps = [
diff --git a/patch/patches/linux_chrome_widevine_3149.patch b/patch/patches/linux_chrome_widevine_3149.patch
new file mode 100644
index 00000000..33b7d8ee
--- /dev/null
+++ b/patch/patches/linux_chrome_widevine_3149.patch
@@ -0,0 +1,58 @@
+diff --git chrome/common/media/component_widevine_cdm_hint_file_linux.cc chrome/common/media/component_widevine_cdm_hint_file_linux.cc
+index 85a55fdd22a4f..0b935334136cb 100644
+--- chrome/common/media/component_widevine_cdm_hint_file_linux.cc
++++ chrome/common/media/component_widevine_cdm_hint_file_linux.cc
+@@ -16,6 +16,7 @@
+ #include "base/path_service.h"
+ #include "base/values.h"
+ #include "chrome/common/chrome_paths.h"
++#include "third_party/widevine/cdm/widevine_cdm_common.h"
+
+ namespace {
+
+@@ -37,14 +38,33 @@ base::FilePath GetPath(const base::Value& dict) {
+ return path;
+ }
+
++// On Linux the Widevine CDM is loaded into the zygote at startup. When the
++// component updater runs sometime later and finds a newer version of the
++// Widevine CDM, don't register it as the newer version can't be used. Instead,
++// save the path to the new Widevine CDM in this file. Next time at startup this
++// file will be checked, and if it references a usable Widevine CDM, use this
++// version instead of the old (potentially bundled) CDM.
++// Add this method instead of using chrome::FILE_COMPONENT_WIDEVINE_CDM_HINT
++// because only directories (not files) can be configured via
++// base::PathService::Override.
++bool GetHintFilePath(base::FilePath* hint_file_path) {
++ base::FilePath user_data_dir;
++ if (!base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir))
++ return false;
++ // Match the file name in chrome/common/chrome_paths.cc
++ *hint_file_path = user_data_dir
++ .AppendASCII(kWidevineCdmBaseDirectory)
++ .Append(FILE_PATH_LITERAL("latest-component-updated-widevine-cdm"));
++ return true;
++}
++
+ } // namespace
+
+ bool UpdateWidevineCdmHintFile(const base::FilePath& cdm_base_path) {
+ DCHECK(!cdm_base_path.empty());
+
+ base::FilePath hint_file_path;
+- CHECK(base::PathService::Get(chrome::FILE_COMPONENT_WIDEVINE_CDM_HINT,
+- &hint_file_path));
++ CHECK(GetHintFilePath(&hint_file_path));
+
+ base::Value dict(base::Value::Type::DICTIONARY);
+ dict.SetStringPath(kPath, cdm_base_path.value());
+@@ -62,8 +82,7 @@ bool UpdateWidevineCdmHintFile(const base::FilePath& cdm_base_path) {
+
+ base::FilePath GetLatestComponentUpdatedWidevineCdmDirectory() {
+ base::FilePath hint_file_path;
+- CHECK(base::PathService::Get(chrome::FILE_COMPONENT_WIDEVINE_CDM_HINT,
+- &hint_file_path));
++ CHECK(GetHintFilePath(&hint_file_path));
+
+ if (!base::PathExists(hint_file_path)) {
+ DVLOG(2) << "CDM hint file at " << hint_file_path << " does not exist.";
diff --git a/patch/patches/linux_glib_deprecated_volatile.patch b/patch/patches/linux_glib_deprecated_volatile.patch
new file mode 100644
index 00000000..f0b6b9a9
--- /dev/null
+++ b/patch/patches/linux_glib_deprecated_volatile.patch
@@ -0,0 +1,28 @@
+diff --git ui/accessibility/platform/BUILD.gn ui/accessibility/platform/BUILD.gn
+index 3bec9f0f7d46f..59c527bdd29cd 100644
+--- ui/accessibility/platform/BUILD.gn
++++ ui/accessibility/platform/BUILD.gn
+@@ -285,6 +285,10 @@ component("platform") {
+ if (use_gio) {
+ configs += [ "//build/linux:gio_config" ]
+ }
++
++ if (is_clang) {
++ cflags = [ "-Wno-deprecated-volatile" ]
++ }
+ }
+ }
+ }
+diff --git ui/gtk/BUILD.gn ui/gtk/BUILD.gn
+index 4fc6b6d617832..77f17ecf4caf0 100644
+--- ui/gtk/BUILD.gn
++++ ui/gtk/BUILD.gn
+@@ -176,4 +176,8 @@ component("gtk") {
+
+ # TODO: This should be removed.
+ deps += [ "//ui/ozone" ]
++
++ if (is_clang) {
++ cflags = [ "-Wno-deprecated-volatile" ]
++ }
+ }
diff --git a/patch/patches/linux_printing_context.patch b/patch/patches/linux_printing_context.patch
new file mode 100644
index 00000000..909a36af
--- /dev/null
+++ b/patch/patches/linux_printing_context.patch
@@ -0,0 +1,136 @@
+diff --git printing/printing_context_linux.cc printing/printing_context_linux.cc
+index 5520e15c232c8..2648037fcf37e 100644
+--- printing/printing_context_linux.cc
++++ printing/printing_context_linux.cc
+@@ -69,11 +69,11 @@ mojom::ResultCode PrintingContextLinux::UseDefaultSettings() {
+ ResetSettings();
+
+ #if BUILDFLAG(IS_LINUX)
+- if (!ui::LinuxUi::instance())
++ if (!ui::PrintingContextLinuxDelegate::instance())
+ return mojom::ResultCode::kSuccess;
+
+ if (!print_dialog_)
+- print_dialog_ = ui::LinuxUi::instance()->CreatePrintDialog(this);
++ print_dialog_ = ui::PrintingContextLinuxDelegate::instance()->CreatePrintDialog(this);
+ print_dialog_->UseDefaultSettings();
+ #endif
+
+@@ -82,8 +82,8 @@ mojom::ResultCode PrintingContextLinux::UseDefaultSettings() {
+
+ gfx::Size PrintingContextLinux::GetPdfPaperSizeDeviceUnits() {
+ #if BUILDFLAG(IS_LINUX)
+- if (ui::LinuxUi::instance())
+- return ui::LinuxUi::instance()->GetPdfPaperSize(this);
++ if (ui::PrintingContextLinuxDelegate::instance())
++ return ui::PrintingContextLinuxDelegate::instance()->GetPdfPaperSize(this);
+ #endif
+
+ return gfx::Size();
+@@ -95,11 +95,11 @@ mojom::ResultCode PrintingContextLinux::UpdatePrinterSettings(
+ DCHECK(!in_print_job_);
+
+ #if BUILDFLAG(IS_LINUX)
+- if (!ui::LinuxUi::instance())
++ if (!ui::PrintingContextLinuxDelegate::instance())
+ return mojom::ResultCode::kSuccess;
+
+ if (!print_dialog_)
+- print_dialog_ = ui::LinuxUi::instance()->CreatePrintDialog(this);
++ print_dialog_ = ui::PrintingContextLinuxDelegate::instance()->CreatePrintDialog(this);
+
+ // PrintDialogGtk::UpdateSettings() calls InitWithSettings() so settings_ will
+ // remain non-null after this line.
+diff --git ui/linux/linux_ui.cc ui/linux/linux_ui.cc
+index 29db798e8b171..f8b9546b90321 100644
+--- ui/linux/linux_ui.cc
++++ ui/linux/linux_ui.cc
+@@ -18,11 +18,29 @@ namespace ui {
+ namespace {
+
+ LinuxUi* g_linux_ui = nullptr;
++static PrintingContextLinuxDelegate* g_delegate = nullptr;
+
+ } // namespace
+
++// static
++PrintingContextLinuxDelegate* PrintingContextLinuxDelegate::SetInstance(
++ PrintingContextLinuxDelegate* delegate) {
++ auto old_delegate = g_delegate;
++ g_delegate = delegate;
++ return old_delegate;
++}
++
++// static
++PrintingContextLinuxDelegate* PrintingContextLinuxDelegate::instance() {
++ return g_delegate;
++}
++
+ // static
+ LinuxUi* LinuxUi::SetInstance(LinuxUi* instance) {
++#if BUILDFLAG(IS_LINUX) && BUILDFLAG(ENABLE_PRINTING)
++ PrintingContextLinuxDelegate::SetInstance(instance);
++#endif
++
+ return std::exchange(g_linux_ui, instance);
+ }
+
+diff --git ui/linux/linux_ui.h ui/linux/linux_ui.h
+index b5fd57741d2f4..eaab5f1bd2b0b 100644
+--- ui/linux/linux_ui.h
++++ ui/linux/linux_ui.h
+@@ -18,6 +18,10 @@
+ #include "build/chromecast_buildflags.h"
+ #include "printing/buildflags/buildflags.h"
+
++#if BUILDFLAG(ENABLE_PRINTING)
++#include "printing/printing_context_linux.h" // nogncheck
++#endif
++
+ // The main entrypoint into Linux toolkit specific code. GTK/QT code should only
+ // be executed behind this interface.
+
+@@ -60,9 +64,27 @@ class TextEditCommandAuraLinux;
+ class WindowButtonOrderObserver;
+ class WindowFrameProvider;
+
++class COMPONENT_EXPORT(LINUX_UI) PrintingContextLinuxDelegate {
++ public:
++ virtual ~PrintingContextLinuxDelegate() = default;
++
++ virtual printing::PrintDialogLinuxInterface* CreatePrintDialog(
++ printing::PrintingContextLinux* context) = 0;
++
++ virtual gfx::Size GetPdfPaperSize(printing::PrintingContextLinux* context) = 0;
++
++ static PrintingContextLinuxDelegate* SetInstance(
++ PrintingContextLinuxDelegate* delegate);
++ static PrintingContextLinuxDelegate* instance();
++};
++
+ // Adapter class with targets to render like different toolkits. Set by any
+ // project that wants to do linux desktop native rendering.
+-class COMPONENT_EXPORT(LINUX_UI) LinuxUi {
++class COMPONENT_EXPORT(LINUX_UI) LinuxUi
++#if BUILDFLAG(ENABLE_PRINTING)
++ : public PrintingContextLinuxDelegate
++#endif
++ {
+ public:
+ // Describes the window management actions that could be taken in response to
+ // a middle click in the non client area.
+@@ -129,14 +151,6 @@ class COMPONENT_EXPORT(LINUX_UI) LinuxUi {
+ // Returns a map of KeyboardEvent code to KeyboardEvent key values.
+ virtual base::flat_map<std::string, std::string> GetKeyboardLayoutMap() = 0;
+
+-#if BUILDFLAG(ENABLE_PRINTING)
+- virtual printing::PrintDialogLinuxInterface* CreatePrintDialog(
+- printing::PrintingContextLinux* context) = 0;
+-
+- virtual gfx::Size GetPdfPaperSize(
+- printing::PrintingContextLinux* context) = 0;
+-#endif
+-
+ // Returns a native file selection dialog. `listener` is of type
+ // SelectFileDialog::Listener. TODO(thomasanderson): Move
+ // SelectFileDialog::Listener to SelectFileDialogListener so that it can be
diff --git a/patch/patches/mac_event_observer_2539.patch b/patch/patches/mac_event_observer_2539.patch
new file mode 100644
index 00000000..14dfb9f9
--- /dev/null
+++ b/patch/patches/mac_event_observer_2539.patch
@@ -0,0 +1,22 @@
+diff --git content/browser/scheduler/responsiveness/native_event_observer_mac.mm content/browser/scheduler/responsiveness/native_event_observer_mac.mm
+index 4aecdd08b7de4..4f5e588a37865 100644
+--- content/browser/scheduler/responsiveness/native_event_observer_mac.mm
++++ content/browser/scheduler/responsiveness/native_event_observer_mac.mm
+@@ -12,13 +12,15 @@ namespace content {
+ namespace responsiveness {
+
+ void NativeEventObserver::RegisterObserver() {
+- DCHECK([NSApp conformsToProtocol:@protocol(NativeEventProcessor)]);
++ if (![NSApp conformsToProtocol:@protocol(NativeEventProcessor)])
++ return;
+ id<NativeEventProcessor> processor =
+ static_cast<id<NativeEventProcessor>>(NSApp);
+ [processor addNativeEventProcessorObserver:this];
+ }
+ void NativeEventObserver::DeregisterObserver() {
+- DCHECK([NSApp conformsToProtocol:@protocol(NativeEventProcessor)]);
++ if (![NSApp conformsToProtocol:@protocol(NativeEventProcessor)])
++ return;
+ id<NativeEventProcessor> processor =
+ static_cast<id<NativeEventProcessor>>(NSApp);
+ [processor removeNativeEventProcessorObserver:this];
diff --git a/patch/patches/mac_fling_scheduler_2540.patch b/patch/patches/mac_fling_scheduler_2540.patch
new file mode 100644
index 00000000..fa98a94b
--- /dev/null
+++ b/patch/patches/mac_fling_scheduler_2540.patch
@@ -0,0 +1,15 @@
+diff --git content/browser/renderer_host/input/fling_scheduler_mac.mm content/browser/renderer_host/input/fling_scheduler_mac.mm
+index 50ed39df38044..7839bdaf7b7e5 100644
+--- content/browser/renderer_host/input/fling_scheduler_mac.mm
++++ content/browser/renderer_host/input/fling_scheduler_mac.mm
+@@ -26,6 +26,10 @@ ui::Compositor* FlingSchedulerMac::GetCompositor() {
+ return nullptr;
+ }
+
++ // For CEF this will always be false when running in OSR mode.
++ if (!view->GetNativeView())
++ return nullptr;
++
+ RenderWidgetHostViewMac* mac_view =
+ static_cast<RenderWidgetHostViewMac*>(view);
+ if (mac_view->BrowserCompositor())
diff --git a/patch/patches/mac_gpu.patch b/patch/patches/mac_gpu.patch
new file mode 100644
index 00000000..95aa8d37
--- /dev/null
+++ b/patch/patches/mac_gpu.patch
@@ -0,0 +1,18 @@
+diff --git ui/gl/init/gl_initializer_mac.cc ui/gl/init/gl_initializer_mac.cc
+index e7bf81292b0f4..e700608f9b9d7 100644
+--- ui/gl/init/gl_initializer_mac.cc
++++ ui/gl/init/gl_initializer_mac.cc
+@@ -47,11 +47,8 @@ bool InitializeOneOffForSandbox() {
+ // GPU-related stuff is very slow without this, probably because
+ // the sandbox prevents loading graphics drivers or some such.
+ std::vector<CGLPixelFormatAttribute> attribs;
+- if (GLContext::SwitchableGPUsSupported()) {
+- // Avoid switching to the discrete GPU just for this pixel
+- // format selection.
+- attribs.push_back(kCGLPFAAllowOfflineRenderers);
+- }
++ // Avoid switching to the discrete GPU just for this pixel format selection.
++ attribs.push_back(kCGLPFAAllowOfflineRenderers);
+ attribs.push_back(static_cast<CGLPixelFormatAttribute>(0));
+
+ CGLPixelFormatObj format;
diff --git a/patch/patches/message_loop.patch b/patch/patches/message_loop.patch
new file mode 100644
index 00000000..958da699
--- /dev/null
+++ b/patch/patches/message_loop.patch
@@ -0,0 +1,75 @@
+diff --git base/message_loop/message_pump_win.cc base/message_loop/message_pump_win.cc
+index e0969d4ad3087..267ac89aab806 100644
+--- base/message_loop/message_pump_win.cc
++++ base/message_loop/message_pump_win.cc
+@@ -2,6 +2,7 @@
+ // Use of this source code is governed by a BSD-style license that can be
+ // found in the LICENSE file.
+
++#include "base/task/current_thread.h"
+ #include "base/message_loop/message_pump_win.h"
+
+ #include <algorithm>
+@@ -491,7 +492,17 @@ bool MessagePumpForUI::ProcessNextWindowsMessage() {
+ ctx.event()->set_chrome_message_pump();
+ msg_pump_data->set_sent_messages_in_queue(more_work_is_plausible);
+ });
+- has_msg = ::PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE) != FALSE;
++
++ // We should not process all window messages if we are in the context of an
++ // OS modal loop, i.e. in the context of a windows API call like MessageBox.
++ // This is to ensure that these messages are peeked out by the OS modal loop.
++ if (CurrentThread::Get()->os_modal_loop()) {
++ // We only peek out WM_PAINT and WM_TIMER here for reasons mentioned above.
++ has_msg = PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_REMOVE) ||
++ PeekMessage(&msg, NULL, WM_TIMER, WM_TIMER, PM_REMOVE);
++ } else {
++ has_msg = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) != FALSE;
++ }
+ }
+ }
+ if (has_msg)
+diff --git base/task/current_thread.cc base/task/current_thread.cc
+index 05daff869644c..ccd19eade21ed 100644
+--- base/task/current_thread.cc
++++ base/task/current_thread.cc
+@@ -48,6 +48,8 @@ void CurrentThread::AddDestructionObserver(
+
+ void CurrentThread::RemoveDestructionObserver(
+ DestructionObserver* destruction_observer) {
++ if (!current_)
++ return;
+ DCHECK(current_->IsBoundToCurrentThread());
+ current_->RemoveDestructionObserver(destruction_observer);
+ }
+diff --git base/task/current_thread.h base/task/current_thread.h
+index 6e5aea5de684f..22019f157eabd 100644
+--- base/task/current_thread.h
++++ base/task/current_thread.h
+@@ -132,6 +132,12 @@ class BASE_EXPORT CurrentThread {
+ // with a null callback to clear any potentially pending callbacks.
+ void RegisterOnNextIdleCallback(OnceClosure on_next_idle_callback);
+
++#if BUILDFLAG(IS_WIN)
++ void set_os_modal_loop(bool os_modal_loop) { os_modal_loop_ = os_modal_loop; }
++
++ bool os_modal_loop() const { return os_modal_loop_; }
++#endif // OS_WIN
++
+ // Enables nested task processing in scope of an upcoming native message loop.
+ // Some unwanted message loops may occur when using common controls or printer
+ // functions. Hence, nested task processing is disabled by default to avoid
+@@ -196,6 +202,13 @@ class BASE_EXPORT CurrentThread {
+ friend class web::WebTaskEnvironment;
+
+ raw_ptr<sequence_manager::internal::SequenceManagerImpl> current_;
++
++#if BUILDFLAG(IS_WIN)
++ private:
++ // Should be set to true before calling Windows APIs like TrackPopupMenu, etc.
++ // which enter a modal message loop.
++ bool os_modal_loop_ = false;
++#endif
+ };
+
+ #if !BUILDFLAG(IS_NACL)
diff --git a/patch/patches/message_pump_mac_2495.patch b/patch/patches/message_pump_mac_2495.patch
new file mode 100644
index 00000000..c492d304
--- /dev/null
+++ b/patch/patches/message_pump_mac_2495.patch
@@ -0,0 +1,24 @@
+diff --git base/message_loop/message_pump_mac.mm base/message_loop/message_pump_mac.mm
+index 25ee65396cfb7..3c9b433cb31bb 100644
+--- base/message_loop/message_pump_mac.mm
++++ base/message_loop/message_pump_mac.mm
+@@ -813,7 +813,8 @@ void MessagePumpUIApplication::Detach() {
+ #else
+
+ ScopedPumpMessagesInPrivateModes::ScopedPumpMessagesInPrivateModes() {
+- DCHECK(g_app_pump);
++ if (!g_app_pump)
++ return;
+ DCHECK_EQ(kNSApplicationModalSafeModeMask, g_app_pump->GetModeMask());
+ // Pumping events in private runloop modes is known to interact badly with
+ // app modal windows like NSAlert.
+@@ -823,7 +824,8 @@ ScopedPumpMessagesInPrivateModes::ScopedPumpMessagesInPrivateModes() {
+ }
+
+ ScopedPumpMessagesInPrivateModes::~ScopedPumpMessagesInPrivateModes() {
+- DCHECK(g_app_pump);
++ if (!g_app_pump)
++ return;
+ g_app_pump->SetModeMask(kNSApplicationModalSafeModeMask);
+ }
+
diff --git a/patch/patches/mime_handler_view_guest_1565_2727.patch b/patch/patches/mime_handler_view_guest_1565_2727.patch
new file mode 100644
index 00000000..e36eda82
--- /dev/null
+++ b/patch/patches/mime_handler_view_guest_1565_2727.patch
@@ -0,0 +1,100 @@
+diff --git content/browser/web_contents/web_contents_view.h content/browser/web_contents/web_contents_view.h
+index ddf25382e49fc..fe64fa31a7a85 100644
+--- content/browser/web_contents/web_contents_view.h
++++ content/browser/web_contents/web_contents_view.h
+@@ -25,7 +25,7 @@ struct DropData;
+ // The `WebContentsView` is an interface that is implemented by the platform-
+ // dependent web contents views. The `WebContents` uses this interface to talk
+ // to them.
+-class WebContentsView {
++class CONTENT_EXPORT WebContentsView {
+ public:
+ virtual ~WebContentsView() = default;
+
+diff --git extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.cc extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.cc
+index ec5521a6e2005..a9f3f55ffd176 100644
+--- extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.cc
++++ extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.cc
+@@ -228,6 +228,8 @@ void MimeHandlerViewGuest::CreateWebContents(
+ WebContents::CreateParams params(browser_context(),
+ guest_site_instance.get());
+ params.guest_delegate = this;
++ if (delegate_)
++ delegate_->OverrideWebContentsCreateParams(&params);
+ std::move(callback).Run(std::move(owned_this),
+ WebContents::CreateWithSessionStorage(
+ params, owner_web_contents()
+@@ -236,6 +238,10 @@ void MimeHandlerViewGuest::CreateWebContents(
+ }
+
+ void MimeHandlerViewGuest::DidAttachToEmbedder() {
++ is_guest_attached_ = true;
++ if (delegate_)
++ delegate_->OnGuestAttached();
++
+ DCHECK(stream_->handler_url().SchemeIs(extensions::kExtensionScheme));
+ GetController().LoadURL(stream_->handler_url(), content::Referrer(),
+ ui::PAGE_TRANSITION_AUTO_TOPLEVEL, std::string());
+@@ -493,6 +499,14 @@ void MimeHandlerViewGuest::DidFinishNavigation(
+ }
+ }
+
++void MimeHandlerViewGuest::WebContentsDestroyed() {
++ if (is_guest_attached_ && delegate_)
++ delegate_->OnGuestDetached();
++
++ // May delete |this|.
++ GuestView<MimeHandlerViewGuest>::WebContentsDestroyed();
++}
++
+ void MimeHandlerViewGuest::FuseBeforeUnloadControl(
+ mojo::PendingReceiver<mime_handler::BeforeUnloadControl> receiver) {
+ if (!pending_before_unload_control_)
+diff --git extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h
+index 810289b11cba7..714b7c64c9ba2 100644
+--- extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h
++++ extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h
+@@ -193,6 +193,7 @@ class MimeHandlerViewGuest
+ void ReadyToCommitNavigation(
+ content::NavigationHandle* navigation_handle) final;
+ void DidFinishNavigation(content::NavigationHandle* navigation_handle) final;
++ void WebContentsDestroyed() override;
+
+ std::unique_ptr<MimeHandlerViewGuestDelegate> delegate_;
+ std::unique_ptr<StreamContainer> stream_;
+@@ -201,6 +202,7 @@ class MimeHandlerViewGuest
+ content::ChildProcessHost::kInvalidUniqueID, MSG_ROUTING_NONE};
+ int embedder_widget_routing_id_ = MSG_ROUTING_NONE;
+
++ bool is_guest_attached_ = false;
+ bool is_guest_fullscreen_ = false;
+ bool is_embedder_fullscreen_ = false;
+ bool plugin_can_save_ = false;
+diff --git extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest_delegate.h extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest_delegate.h
+index 7f59e7925084e..777b8a3cf103a 100644
+--- extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest_delegate.h
++++ extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest_delegate.h
+@@ -7,6 +7,8 @@
+
+ #include <string>
+
++#include "content/public/browser/web_contents.h"
++
+ namespace content {
+ class RenderFrameHost;
+ struct ContextMenuParams;
+@@ -25,6 +27,14 @@ class MimeHandlerViewGuestDelegate {
+
+ virtual ~MimeHandlerViewGuestDelegate() {}
+
++ // Provides an opportunity to supply a custom view implementation.
++ virtual void OverrideWebContentsCreateParams(
++ content::WebContents::CreateParams* params) {}
++
++ // Called when a guest is attached or detached.
++ virtual void OnGuestAttached() {}
++ virtual void OnGuestDetached() {}
++
+ // Handles context menu, or returns false if unhandled.
+ //
+ // The `render_frame_host` represents the frame that requests the context menu
diff --git a/patch/patches/net_cookie_flags.patch b/patch/patches/net_cookie_flags.patch
new file mode 100644
index 00000000..61ef2cef
--- /dev/null
+++ b/patch/patches/net_cookie_flags.patch
@@ -0,0 +1,39 @@
+diff --git net/base/load_flags_list.h net/base/load_flags_list.h
+index f936d951fe272..90a3165172dce 100644
+--- net/base/load_flags_list.h
++++ net/base/load_flags_list.h
+@@ -103,3 +103,6 @@ LOAD_FLAG(RESTRICTED_PREFETCH, 1 << 15)
+ // is considered privileged, and therefore this flag must only be set from a
+ // trusted process.
+ LOAD_FLAG(CAN_USE_RESTRICTED_PREFETCH, 1 << 16)
++
++// This load will not send any cookies. For CEF usage.
++LOAD_FLAG(DO_NOT_SEND_COOKIES, 1 << 17)
+diff --git net/url_request/url_request_http_job.cc net/url_request/url_request_http_job.cc
+index 31b8af59f7b5e..162d54de19abf 100644
+--- net/url_request/url_request_http_job.cc
++++ net/url_request/url_request_http_job.cc
+@@ -1705,7 +1705,8 @@ bool URLRequestHttpJob::ShouldAddCookieHeader() const {
+ // Read cookies whenever allow_credentials() is true, even if the PrivacyMode
+ // is being overridden by NetworkDelegate and will eventually block them, as
+ // blocked cookies still need to be logged in that case.
+- return request_->context()->cookie_store() && request_->allow_credentials();
++ return request_->context()->cookie_store() && request_->allow_credentials() &&
++ !(request_info_.load_flags & LOAD_DO_NOT_SEND_COOKIES);
+ }
+
+ bool URLRequestHttpJob::IsPartitionedCookiesEnabled() const {
+diff --git services/network/public/cpp/resource_request.cc services/network/public/cpp/resource_request.cc
+index 6d42ae691a2c4..27c98529f7881 100644
+--- services/network/public/cpp/resource_request.cc
++++ services/network/public/cpp/resource_request.cc
+@@ -285,7 +285,8 @@ bool ResourceRequest::EqualsForTesting(const ResourceRequest& request) const {
+ }
+
+ bool ResourceRequest::SendsCookies() const {
+- return credentials_mode == network::mojom::CredentialsMode::kInclude;
++ return credentials_mode == network::mojom::CredentialsMode::kInclude &&
++ !(load_flags & net::LOAD_DO_NOT_SEND_COOKIES);
+ }
+
+ bool ResourceRequest::SavesCookies() const {
diff --git a/patch/patches/net_test_server_3798752.patch b/patch/patches/net_test_server_3798752.patch
new file mode 100644
index 00000000..3e9a618b
--- /dev/null
+++ b/patch/patches/net_test_server_3798752.patch
@@ -0,0 +1,22 @@
+diff --git net/test/embedded_test_server/embedded_test_server.cc net/test/embedded_test_server/embedded_test_server.cc
+index d112bec7c7dce..ca88a6df95e5d 100644
+--- net/test/embedded_test_server/embedded_test_server.cc
++++ net/test/embedded_test_server/embedded_test_server.cc
+@@ -982,7 +982,7 @@ bool EmbeddedTestServer::PostTaskToIOThreadAndWait(base::OnceClosure closure) {
+ if (!base::CurrentThread::Get())
+ temporary_loop = std::make_unique<base::SingleThreadTaskExecutor>();
+
+- base::RunLoop run_loop;
++ base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
+ if (!io_thread_->task_runner()->PostTaskAndReply(
+ FROM_HERE, std::move(closure), run_loop.QuitClosure())) {
+ return false;
+@@ -1009,7 +1009,7 @@ bool EmbeddedTestServer::PostTaskToIOThreadAndWaitWithResult(
+ if (!base::CurrentThread::Get())
+ temporary_loop = std::make_unique<base::SingleThreadTaskExecutor>();
+
+- base::RunLoop run_loop;
++ base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
+ bool task_result = false;
+ if (!io_thread_->task_runner()->PostTaskAndReplyWithResult(
+ FROM_HERE, std::move(task),
diff --git a/patch/patches/osr_fling_2745.patch b/patch/patches/osr_fling_2745.patch
new file mode 100644
index 00000000..292d7ddd
--- /dev/null
+++ b/patch/patches/osr_fling_2745.patch
@@ -0,0 +1,70 @@
+diff --git content/browser/renderer_host/input/fling_scheduler.cc content/browser/renderer_host/input/fling_scheduler.cc
+index 84e5d2a493556..160478790e261 100644
+--- content/browser/renderer_host/input/fling_scheduler.cc
++++ content/browser/renderer_host/input/fling_scheduler.cc
+@@ -68,6 +68,9 @@ void FlingScheduler::ProgressFlingOnBeginFrameIfneeded(
+ }
+
+ ui::Compositor* FlingScheduler::GetCompositor() {
++ if (compositor_) {
++ return compositor_;
++ }
+ #if defined(USE_AURA)
+ if (host_->GetView() && host_->GetView()->GetNativeView() &&
+ host_->GetView()->GetNativeView()->GetHost() &&
+diff --git content/browser/renderer_host/input/fling_scheduler_base.h content/browser/renderer_host/input/fling_scheduler_base.h
+index afefe3cd83dee..6668463247644 100644
+--- content/browser/renderer_host/input/fling_scheduler_base.h
++++ content/browser/renderer_host/input/fling_scheduler_base.h
+@@ -7,12 +7,23 @@
+
+ #include "content/browser/renderer_host/input/fling_controller.h"
+
++namespace ui {
++class Compositor;
++}
++
+ namespace content {
+
+ class FlingSchedulerBase : public FlingControllerSchedulerClient {
+ public:
+ virtual void ProgressFlingOnBeginFrameIfneeded(
+ base::TimeTicks current_time) = 0;
++
++ void SetCompositor(ui::Compositor* compositor) {
++ compositor_ = compositor;
++ }
++
++protected:
++ ui::Compositor* compositor_ = nullptr;
+ };
+
+ } // namespace content
+diff --git content/browser/renderer_host/render_widget_host_impl.cc content/browser/renderer_host/render_widget_host_impl.cc
+index a689c6e60b5d5..5a1204c01f04a 100644
+--- content/browser/renderer_host/render_widget_host_impl.cc
++++ content/browser/renderer_host/render_widget_host_impl.cc
+@@ -3144,6 +3144,11 @@ void RenderWidgetHostImpl::OnInvalidInputEventSource() {
+ GetProcess(), bad_message::INPUT_ROUTER_INVALID_EVENT_SOURCE);
+ }
+
++void RenderWidgetHostImpl::SetCompositorForFlingScheduler(ui::Compositor* compositor)
++{
++ fling_scheduler_->SetCompositor(compositor);
++}
++
+ void RenderWidgetHostImpl::AddPendingUserActivation(
+ const WebInputEvent& event) {
+ if ((base::FeatureList::IsEnabled(
+diff --git content/browser/renderer_host/render_widget_host_impl.h content/browser/renderer_host/render_widget_host_impl.h
+index 3910d3a1642ab..8738df72afced 100644
+--- content/browser/renderer_host/render_widget_host_impl.h
++++ content/browser/renderer_host/render_widget_host_impl.h
+@@ -791,6 +791,7 @@ class CONTENT_EXPORT RenderWidgetHostImpl
+
+ void ProgressFlingIfNeeded(base::TimeTicks current_time);
+ void StopFling();
++ void SetCompositorForFlingScheduler(ui::Compositor* compositor);
+
+ // The RenderWidgetHostImpl will keep showing the old page (for a while) after
+ // navigation until the first frame of the new page arrives. This reduces
diff --git a/patch/patches/pdfium_103501.patch b/patch/patches/pdfium_103501.patch
new file mode 100644
index 00000000..1d36d587
--- /dev/null
+++ b/patch/patches/pdfium_103501.patch
@@ -0,0 +1,12 @@
+diff --git BUILD.gn BUILD.gn
+index a8532128d..f5a098afa 100644
+--- BUILD.gn
++++ BUILD.gn
+@@ -338,6 +338,7 @@ group("pdfium_public_headers") {
+ }
+
+ component("pdfium") {
++ output_name = "pdfium"
+ libs = []
+ configs += [ ":pdfium_strict_config" ]
+ public_configs = [ ":pdfium_public_config" ]
diff --git a/patch/patches/print_preview_123.patch b/patch/patches/print_preview_123.patch
new file mode 100644
index 00000000..4f238287
--- /dev/null
+++ b/patch/patches/print_preview_123.patch
@@ -0,0 +1,140 @@
+diff --git chrome/browser/download/download_prefs.cc chrome/browser/download/download_prefs.cc
+index 35c194b2d8dc4..8b9cc3095906c 100644
+--- chrome/browser/download/download_prefs.cc
++++ chrome/browser/download/download_prefs.cc
+@@ -24,6 +24,7 @@
+ #include "base/strings/utf_string_conversions.h"
+ #include "build/build_config.h"
+ #include "build/chromeos_buildflags.h"
++#include "cef/libcef/features/runtime.h"
+ #include "chrome/browser/download/chrome_download_manager_delegate.h"
+ #include "chrome/browser/download/download_core_service_factory.h"
+ #include "chrome/browser/download/download_core_service_impl.h"
+@@ -61,6 +62,10 @@
+ #include "chrome/browser/ui/pdf/adobe_reader_info_win.h"
+ #endif
+
++#if BUILDFLAG(ENABLE_CEF)
++#include "cef/libcef/browser/alloy/alloy_download_util.h"
++#endif
++
+ using content::BrowserContext;
+ using content::BrowserThread;
+ using content::DownloadManager;
+@@ -348,6 +353,11 @@ DownloadPrefs* DownloadPrefs::FromDownloadManager(
+ // static
+ DownloadPrefs* DownloadPrefs::FromBrowserContext(
+ content::BrowserContext* context) {
++#if BUILDFLAG(ENABLE_CEF)
++ if (cef::IsAlloyRuntimeEnabled()) {
++ return alloy::GetDownloadPrefsFromBrowserContext(context);
++ }
++#endif
+ return FromDownloadManager(context->GetDownloadManager());
+ }
+
+diff --git chrome/browser/printing/print_preview_dialog_controller.cc chrome/browser/printing/print_preview_dialog_controller.cc
+index b848ee0d185ec..c3ddbc8932f66 100644
+--- chrome/browser/printing/print_preview_dialog_controller.cc
++++ chrome/browser/printing/print_preview_dialog_controller.cc
+@@ -15,6 +15,7 @@
+ #include "build/branding_buildflags.h"
+ #include "build/build_config.h"
+ #include "build/chromeos_buildflags.h"
++#include "cef/libcef/features/features.h"
+ #include "chrome/browser/browser_process.h"
+ #include "chrome/browser/printing/print_view_manager.h"
+ #include "chrome/browser/task_manager/web_contents_tags.h"
+diff --git chrome/browser/printing/print_view_manager_base.cc chrome/browser/printing/print_view_manager_base.cc
+index 34d6001efd674..d8c99f9f01e3c 100644
+--- chrome/browser/printing/print_view_manager_base.cc
++++ chrome/browser/printing/print_view_manager_base.cc
+@@ -610,13 +610,14 @@ void PrintViewManagerBase::UpdatePrintSettings(
+ job_settings.Set(kSettingRasterizePdfDpi, value);
+ }
+
++ content::RenderFrameHost* render_frame_host = GetCurrentTargetFrame();
+ auto callback_wrapper =
+ base::BindOnce(&PrintViewManagerBase::UpdatePrintSettingsReply,
+ weak_ptr_factory_.GetWeakPtr(), std::move(callback));
+ std::unique_ptr<PrinterQuery> printer_query = queue_->PopPrinterQuery(cookie);
+ if (!printer_query) {
+ printer_query =
+- queue_->CreatePrinterQuery(content::GlobalRenderFrameHostId());
++ queue_->CreatePrinterQuery(render_frame_host->GetGlobalId());
+ }
+ auto* printer_query_ptr = printer_query.get();
+ printer_query_ptr->SetSettings(
+diff --git chrome/browser/resources/print_preview/ui/destination_dialog.html chrome/browser/resources/print_preview/ui/destination_dialog.html
+index 5d1658999d5bb..d1b7b7288c946 100644
+--- chrome/browser/resources/print_preview/ui/destination_dialog.html
++++ chrome/browser/resources/print_preview/ui/destination_dialog.html
+@@ -15,10 +15,7 @@
+ </print-preview-destination-list>
+ </div>
+ <div slot="button-container">
+- <cr-button on-click="onManageButtonClick_">
+- $i18n{manage}
+- <iron-icon icon="cr:open-in-new" id="manageIcon"></iron-icon>
+- </cr-button>
++ <div></div>
+ <cr-button class="cancel-button" on-click="onCancelButtonClick_">
+ $i18n{cancel}
+ </cr-button>
+diff --git chrome/browser/ui/webui/constrained_web_dialog_ui.cc chrome/browser/ui/webui/constrained_web_dialog_ui.cc
+index d5767fe27db0d..5778847a68208 100644
+--- chrome/browser/ui/webui/constrained_web_dialog_ui.cc
++++ chrome/browser/ui/webui/constrained_web_dialog_ui.cc
+@@ -13,6 +13,7 @@
+ #include "base/memory/ptr_util.h"
+ #include "base/memory/raw_ptr.h"
+ #include "base/values.h"
++#include "cef/libcef/features/runtime.h"
+ #include "content/public/browser/notification_service.h"
+ #include "content/public/browser/render_frame_host.h"
+ #include "content/public/browser/web_contents.h"
+@@ -57,7 +58,9 @@ class ConstrainedWebDialogDelegateUserData
+ ConstrainedWebDialogUI::ConstrainedWebDialogUI(content::WebUI* web_ui)
+ : WebUIController(web_ui) {
+ #if BUILDFLAG(ENABLE_EXTENSIONS)
++ if (!cef::IsAlloyRuntimeEnabled()) {
+ extensions::TabHelper::CreateForWebContents(web_ui->GetWebContents());
++ }
+ #endif
+ }
+
+diff --git chrome/browser/ui/webui/print_preview/print_preview_ui.cc chrome/browser/ui/webui/print_preview/print_preview_ui.cc
+index 2680a3e16f53f..a925307664c15 100644
+--- chrome/browser/ui/webui/print_preview/print_preview_ui.cc
++++ chrome/browser/ui/webui/print_preview/print_preview_ui.cc
+@@ -23,6 +23,7 @@
+ #include "base/values.h"
+ #include "build/build_config.h"
+ #include "build/chromeos_buildflags.h"
++#include "cef/libcef/features/runtime.h"
+ #include "chrome/browser/browser_process.h"
+ #include "chrome/browser/pdf/pdf_extension_util.h"
+ #include "chrome/browser/policy/management_utils.h"
+@@ -101,6 +102,13 @@ const char16_t kBasicPrintShortcut[] = u"\u0028\u21e7\u2318\u0050\u0029";
+ const char16_t kBasicPrintShortcut[] = u"(Ctrl+Shift+P)";
+ #endif
+
++const char16_t* GetBasicPrintShortcut() {
++ if (cef::IsAlloyRuntimeEnabled()) {
++ return u"";
++ }
++ return kBasicPrintShortcut;
++}
++
+ constexpr char kInvalidArgsForDidStartPreview[] =
+ "Invalid arguments for DidStartPreview";
+ constexpr char kInvalidPageNumberForDidPreviewPage[] =
+@@ -329,7 +337,7 @@ void AddPrintPreviewStrings(content::WebUIDataSource* source) {
+ source->AddLocalizedStrings(kLocalizedStrings);
+
+ #if !BUILDFLAG(IS_CHROMEOS)
+- const std::u16string shortcut_text(kBasicPrintShortcut);
++ const std::u16string shortcut_text(GetBasicPrintShortcut());
+ source->AddString("systemDialogOption",
+ l10n_util::GetStringFUTF16(
+ IDS_PRINT_PREVIEW_SYSTEM_DIALOG_OPTION, shortcut_text));
diff --git a/patch/patches/printing_context_2196.patch b/patch/patches/printing_context_2196.patch
new file mode 100644
index 00000000..f74721c8
--- /dev/null
+++ b/patch/patches/printing_context_2196.patch
@@ -0,0 +1,41 @@
+diff --git chrome/browser/printing/printer_query.cc chrome/browser/printing/printer_query.cc
+index d01d616c3b1ea..580fa043bdc79 100644
+--- chrome/browser/printing/printer_query.cc
++++ chrome/browser/printing/printer_query.cc
+@@ -115,6 +115,7 @@ PrinterQuery::PrinterQuery(content::GlobalRenderFrameHostId rfh_id)
+ rfh_id_(rfh_id),
+ cookie_(PrintSettings::NewCookie()) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
++ printing_context_->set_render_ids(rfh_id.child_id, rfh_id.frame_routing_id);
+ }
+
+ PrinterQuery::~PrinterQuery() {
+diff --git printing/printing_context.h printing/printing_context.h
+index 7582c73418e74..f5b477c18c65a 100644
+--- printing/printing_context.h
++++ printing/printing_context.h
+@@ -173,6 +173,13 @@ class COMPONENT_EXPORT(PRINTING) PrintingContext {
+
+ int job_id() const { return job_id_; }
+
++ void set_render_ids(int render_process_id, int render_frame_id) {
++ render_process_id_ = render_process_id;
++ render_frame_id_ = render_frame_id;
++ }
++ int render_process_id() const { return render_process_id_; }
++ int render_frame_id() const { return render_frame_id_; }
++
+ protected:
+ explicit PrintingContext(Delegate* delegate);
+
+@@ -219,6 +226,10 @@ class COMPONENT_EXPORT(PRINTING) PrintingContext {
+ // The job id for the current job. The value is 0 if no jobs are active.
+ int job_id_;
+
++ // Routing IDs for the frame that owns this object.
++ int render_process_id_ = 0;
++ int render_frame_id_ = 0;
++
+ private:
+ #if BUILDFLAG(ENABLE_OOP_PRINTING)
+ // If this instance of PrintingContext should skip making any system calls
diff --git a/patch/patches/renderer_host_1070713.patch b/patch/patches/renderer_host_1070713.patch
new file mode 100644
index 00000000..daee8064
--- /dev/null
+++ b/patch/patches/renderer_host_1070713.patch
@@ -0,0 +1,13 @@
+diff --git content/browser/renderer_host/render_view_host_impl.cc content/browser/renderer_host/render_view_host_impl.cc
+index 39bd6ef7be6ec..a6ce95a1c8557 100644
+--- content/browser/renderer_host/render_view_host_impl.cc
++++ content/browser/renderer_host/render_view_host_impl.cc
+@@ -686,6 +686,8 @@ bool RenderViewHostImpl::IsRenderViewLive() const {
+ }
+
+ void RenderViewHostImpl::SetBackgroundOpaque(bool opaque) {
++ if (!GetWidget()->GetAssociatedFrameWidget().is_bound())
++ return;
+ GetWidget()->GetAssociatedFrameWidget()->SetBackgroundOpaque(opaque);
+ }
+
diff --git a/patch/patches/resource_bundle_2512.patch b/patch/patches/resource_bundle_2512.patch
new file mode 100644
index 00000000..58750163
--- /dev/null
+++ b/patch/patches/resource_bundle_2512.patch
@@ -0,0 +1,45 @@
+diff --git ui/base/resource/resource_bundle.cc ui/base/resource/resource_bundle.cc
+index a013ab393c6b0..1187c26bb65f8 100644
+--- ui/base/resource/resource_bundle.cc
++++ ui/base/resource/resource_bundle.cc
+@@ -909,6 +909,12 @@ ResourceBundle::ResourceBundle(Delegate* delegate)
+ : delegate_(delegate),
+ locale_resources_data_lock_(new base::Lock),
+ max_scale_factor_(k100Percent) {
++ // With CEF's multi-threaded mode the ResourceBundle may be created on the
++ // main thread and then accessed on the UI thread. Allow the SequenceChecker
++ // to re-bind on the UI thread when CalledOnValidSequence() is called for the
++ // first time.
++ DETACH_FROM_SEQUENCE(sequence_checker_);
++
+ mangle_localized_strings_ = base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kMangleLocalizedStrings);
+ }
+@@ -918,6 +924,11 @@ ResourceBundle::~ResourceBundle() {
+ UnloadLocaleResources();
+ }
+
++void ResourceBundle::CleanupOnUIThread() {
++ FreeImages();
++ font_cache_.clear();
++}
++
+ // static
+ void ResourceBundle::InitSharedInstance(Delegate* delegate) {
+ DCHECK(g_shared_instance_ == nullptr) << "ResourceBundle initialized twice";
+diff --git ui/base/resource/resource_bundle.h ui/base/resource/resource_bundle.h
+index 1ea959098a63a..82afff58caf65 100644
+--- ui/base/resource/resource_bundle.h
++++ ui/base/resource/resource_bundle.h
+@@ -216,6 +216,11 @@ class COMPONENT_EXPORT(UI_BASE) ResourceBundle {
+ ResourceBundle(const ResourceBundle&) = delete;
+ ResourceBundle& operator=(const ResourceBundle&) = delete;
+
++ // With CEF's multi-threaded mode the ResourceBundle may be created/destroyed
++ // on the main thread but accessed on the UI thread. Call this method on the
++ // UI thread to clean up resources before destruction.
++ void CleanupOnUIThread();
++
+ // Loads a secondary locale data pack using the given file region.
+ void LoadSecondaryLocaleDataWithPakFileRegion(
+ base::File pak_file,
diff --git a/patch/patches/runhooks.patch b/patch/patches/runhooks.patch
new file mode 100644
index 00000000..a14de55e
--- /dev/null
+++ b/patch/patches/runhooks.patch
@@ -0,0 +1,68 @@
+diff --git build/toolchain/win/setup_toolchain.py build/toolchain/win/setup_toolchain.py
+index 026bcc96c3439..cbc827b27a0ba 100644
+--- build/toolchain/win/setup_toolchain.py
++++ build/toolchain/win/setup_toolchain.py
+@@ -165,13 +165,17 @@ def _LoadToolchainEnv(cpu, toolchain_root, sdk_dir, target_store):
+ del os.environ['LIB']
+ if 'LIBPATH' in os.environ:
+ del os.environ['LIBPATH']
+- other_path = os.path.normpath(os.path.join(
++ script_path = os.path.normpath(os.path.join(
+ os.environ['GYP_MSVS_OVERRIDE_PATH'],
+ 'VC/Auxiliary/Build/vcvarsall.bat'))
+- if not os.path.exists(other_path):
+- raise Exception('%s is missing - make sure VC++ tools are installed.' %
+- script_path)
+- script_path = other_path
++ if not os.path.exists(script_path):
++ # Compiler environment variables must already be specified.
++ variables = []
++ for k in sorted(os.environ.keys()):
++ variables.append('%s=%s' % (str(k), str(os.environ[k])))
++ variables = '\n'.join(variables)
++ return _ExtractImportantEnvironment(variables)
++
+ cpu_arg = "amd64"
+ if (cpu != 'x64'):
+ # x64 is default target CPU thus any other CPU requires a target set
+diff --git build/vs_toolchain.py build/vs_toolchain.py
+index 6ca0be49fe8ed..28e134716c116 100755
+--- build/vs_toolchain.py
++++ build/vs_toolchain.py
+@@ -106,9 +106,16 @@ def SetEnvironmentAndGetRuntimeDllDirs():
+ runtime_path = os.path.pathsep.join(vs_runtime_dll_dirs)
+ os.environ['PATH'] = runtime_path + os.path.pathsep + os.environ['PATH']
+ elif sys.platform == 'win32' and not depot_tools_win_toolchain:
++ has_override_path = True
+ if not 'GYP_MSVS_OVERRIDE_PATH' in os.environ:
++ has_override_path = False
+ os.environ['GYP_MSVS_OVERRIDE_PATH'] = DetectVisualStudioPath()
+
++ if has_override_path:
++ # Don't attempt to copy DLLs when using a custom toolchain.
++ # The DLLs should already be discoverable via the PATH env variable.
++ return None
++
+ # When using an installed toolchain these files aren't needed in the output
+ # directory in order to run binaries locally, but they are needed in order
+ # to create isolates or the mini_installer. Copying them to the output
+@@ -157,6 +164,10 @@ def _RegistryGetValue(key, value):
+ def GetVisualStudioVersion():
+ """Return best available version of Visual Studio.
+ """
++ # Return the explicitly requested version, if any.
++ if 'GYP_MSVS_VERSION' in os.environ:
++ return os.environ['GYP_MSVS_VERSION']
++
+ supported_versions = list(MSVS_VERSIONS.keys())
+
+ # VS installed in depot_tools for Googlers
+@@ -430,7 +441,7 @@ def _CopyDebugger(target_dir, target_cpu):
+
+ # List of debug files that should be copied, the first element of the tuple is
+ # the name of the file and the second indicates if it's optional.
+- debug_files = [('dbghelp.dll', False), ('dbgcore.dll', True)]
++ debug_files = []
+ # The UCRT is not a redistributable component on arm64.
+ if target_cpu != 'arm64':
+ debug_files.extend([('api-ms-win-downlevel-kernel32-l2-1-0.dll', False),
diff --git a/patch/patches/rwh_background_color_1984.patch b/patch/patches/rwh_background_color_1984.patch
new file mode 100644
index 00000000..5ded6a7a
--- /dev/null
+++ b/patch/patches/rwh_background_color_1984.patch
@@ -0,0 +1,46 @@
+diff --git content/browser/renderer_host/render_widget_host_view_aura.cc content/browser/renderer_host/render_widget_host_view_aura.cc
+index 65daab4054860..14c44d8bd5512 100644
+--- content/browser/renderer_host/render_widget_host_view_aura.cc
++++ content/browser/renderer_host/render_widget_host_view_aura.cc
+@@ -6,6 +6,7 @@
+
+ #include <limits>
+ #include <memory>
++#include <tuple>
+ #include <set>
+ #include <utility>
+
+@@ -724,10 +725,12 @@ gfx::Rect RenderWidgetHostViewAura::GetViewBounds() {
+ void RenderWidgetHostViewAura::UpdateBackgroundColor() {
+ DCHECK(GetBackgroundColor());
+
+- SkColor color = *GetBackgroundColor();
+- bool opaque = SkColorGetA(color) == SK_AlphaOPAQUE;
+- window_->layer()->SetFillsBoundsOpaquely(opaque);
+- window_->layer()->SetColor(color);
++ if (window_) {
++ SkColor color = *GetBackgroundColor();
++ bool opaque = SkColorGetA(color) == SK_AlphaOPAQUE;
++ window_->layer()->SetFillsBoundsOpaquely(opaque);
++ window_->layer()->SetColor(color);
++ }
+ }
+
+ absl::optional<DisplayFeature> RenderWidgetHostViewAura::GetDisplayFeature() {
+@@ -2240,6 +2243,16 @@ void RenderWidgetHostViewAura::CreateAuraWindow(aura::client::WindowType type) {
+ // This needs to happen only after |window_| has been initialized using
+ // Init(), because it needs to have the layer.
+ window_->SetEmbedFrameSinkId(frame_sink_id_);
++
++ // Do this after |window_| is created to avoid crashes on Win10.
++ // See https://crbug.com/761389.
++ auto web_contents =
++ WebContents::FromRenderViewHost(RenderViewHost::From(host_));
++ if (web_contents) {
++ // TODO(mostynb): actually use prefs. Landing this as a separate CL
++ // first to rebaseline some unreliable layout tests.
++ std::ignore = web_contents->GetOrCreateWebPreferences();
++ }
+ }
+
+ void RenderWidgetHostViewAura::CreateDelegatedFrameHostClient() {
diff --git a/patch/patches/services_network_2622.patch b/patch/patches/services_network_2622.patch
new file mode 100644
index 00000000..198ad3bb
--- /dev/null
+++ b/patch/patches/services_network_2622.patch
@@ -0,0 +1,244 @@
+diff --git chrome/browser/enterprise/connectors/analysis/content_analysis_delegate.cc chrome/browser/enterprise/connectors/analysis/content_analysis_delegate.cc
+index 53383355d6646..d7a713017e16d 100644
+--- chrome/browser/enterprise/connectors/analysis/content_analysis_delegate.cc
++++ chrome/browser/enterprise/connectors/analysis/content_analysis_delegate.cc
+@@ -23,6 +23,7 @@
+ #include "base/strings/utf_string_conversions.h"
+ #include "base/time/time.h"
+ #include "build/build_config.h"
++#include "cef/libcef/features/runtime.h"
+ #include "chrome/browser/browser_process.h"
+ #include "chrome/browser/enterprise/connectors/analysis/analysis_settings.h"
+ #include "chrome/browser/enterprise/connectors/analysis/content_analysis_dialog.h"
+@@ -232,6 +233,9 @@ bool ContentAnalysisDelegate::IsEnabled(
+ GURL url,
+ Data* data,
+ enterprise_connectors::AnalysisConnector connector) {
++ if (cef::IsAlloyRuntimeEnabled())
++ return false;
++
+ auto* service =
+ enterprise_connectors::ConnectorsServiceFactory::GetForBrowserContext(
+ profile);
+diff --git chrome/browser/net/profile_network_context_service.cc chrome/browser/net/profile_network_context_service.cc
+index 99fb0211efd6b..5f4a4c2d7c977 100644
+--- chrome/browser/net/profile_network_context_service.cc
++++ chrome/browser/net/profile_network_context_service.cc
+@@ -22,6 +22,7 @@
+ #include "base/trace_event/trace_event.h"
+ #include "build/build_config.h"
+ #include "build/chromeos_buildflags.h"
++#include "cef/libcef/features/runtime.h"
+ #include "chrome/browser/browser_features.h"
+ #include "chrome/browser/browser_process.h"
+ #include "chrome/browser/chrome_content_browser_client.h"
+@@ -283,8 +284,10 @@ ProfileNetworkContextService::ProfileNetworkContextService(Profile* profile)
+ base::Unretained(this)));
+ cookie_settings_ = CookieSettingsFactory::GetForProfile(profile);
+ cookie_settings_observation_.Observe(cookie_settings_.get());
+- privacy_sandbox_settings_observer_.Observe(
+- PrivacySandboxSettingsFactory::GetForProfile(profile));
++ if (!cef::IsAlloyRuntimeEnabled()) {
++ privacy_sandbox_settings_observer_.Observe(
++ PrivacySandboxSettingsFactory::GetForProfile(profile));
++ }
+
+ DisableQuicIfNotAllowed();
+
+@@ -324,7 +327,9 @@ ProfileNetworkContextService::ProfileNetworkContextService(Profile* profile)
+ base::Unretained(this)));
+
+ #if BUILDFLAG(ENABLE_EXTENSIONS)
+- registry_observation_.Observe(extensions::ExtensionRegistry::Get(profile_));
++ if (auto extension_registry = extensions::ExtensionRegistry::Get(profile_)) {
++ registry_observation_.Observe(extension_registry);
++ }
+ #endif
+ }
+
+@@ -828,7 +833,19 @@ void ProfileNetworkContextService::ConfigureNetworkContextParamsInternal(
+
+ // Configure on-disk storage for non-OTR profiles. OTR profiles just use
+ // default behavior (in memory storage, default sizes).
+- if (!in_memory) {
++ if (!in_memory && cef::IsAlloyRuntimeEnabled()) {
++ PrefService* prefs = profile_->GetPrefs();
++ // Configure the HTTP cache path and size.
++ const base::FilePath& base_cache_path =
++ prefs->GetFilePath(prefs::kDiskCacheDir);
++ DCHECK(!base_cache_path.empty());
++ network_context_params->http_cache_directory =
++ base_cache_path.Append(chrome::kCacheDirname);
++ network_context_params->http_cache_max_size =
++ prefs->GetInteger(prefs::kDiskCacheSize);
++ }
++
++ if (!in_memory && !cef::IsAlloyRuntimeEnabled()) {
+ PrefService* local_state = g_browser_process->local_state();
+ // Configure the HTTP cache path and size.
+ base::FilePath base_cache_path;
+@@ -841,7 +858,9 @@ void ProfileNetworkContextService::ConfigureNetworkContextParamsInternal(
+ base_cache_path.Append(chrome::kCacheDirname);
+ network_context_params->http_cache_max_size =
+ local_state->GetInteger(prefs::kDiskCacheSize);
++ }
+
++ if (!in_memory) {
+ network_context_params->file_paths =
+ ::network::mojom::NetworkContextFilePaths::New();
+
+@@ -1039,6 +1058,7 @@ void ProfileNetworkContextService::ConfigureNetworkContextParamsInternal(
+ network_context_params->require_network_isolation_key = true;
+
+ network_context_params->block_trust_tokens =
++ cef::IsAlloyRuntimeEnabled() ||
+ !PrivacySandboxSettingsFactory::GetForProfile(profile_)
+ ->IsTrustTokensAllowed();
+
+diff --git chrome/browser/signin/identity_manager_factory.cc chrome/browser/signin/identity_manager_factory.cc
+index 0f92e4682eee9..ea6e6ed6f1e05 100644
+--- chrome/browser/signin/identity_manager_factory.cc
++++ chrome/browser/signin/identity_manager_factory.cc
+@@ -11,6 +11,7 @@
+ #include "base/observer_list.h"
+ #include "build/build_config.h"
+ #include "build/chromeos_buildflags.h"
++#include "cef/libcef/features/runtime.h"
+ #include "chrome/browser/browser_process.h"
+ #include "chrome/browser/image_fetcher/image_decoder_impl.h"
+ #include "chrome/browser/profiles/profile.h"
+@@ -82,6 +83,7 @@ IdentityManagerFactory::~IdentityManagerFactory() {
+ // static
+ signin::IdentityManager* IdentityManagerFactory::GetForProfile(
+ Profile* profile) {
++ DCHECK(!cef::IsAlloyRuntimeEnabled());
+ return static_cast<signin::IdentityManager*>(
+ GetInstance()->GetServiceForBrowserContext(profile, true));
+ }
+diff --git net/cookies/cookie_monster.cc net/cookies/cookie_monster.cc
+index 44f52e0c14355..6b380a5bfe3c8 100644
+--- net/cookies/cookie_monster.cc
++++ net/cookies/cookie_monster.cc
+@@ -554,6 +554,25 @@ void CookieMonster::SetCookieableSchemes(
+ MaybeRunCookieCallback(std::move(callback), true);
+ }
+
++void CookieMonster::AddCookieableSchemes(
++ const std::vector<std::string>& schemes,
++ SetCookieableSchemesCallback callback) {
++ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
++
++ // Calls to this method will have no effect if made after a WebView or
++ // CookieManager instance has been created.
++ if (initialized_) {
++ MaybeRunCookieCallback(std::move(callback), false);
++ return;
++ }
++
++ if (!schemes.empty()) {
++ cookieable_schemes_.insert(cookieable_schemes_.begin(), schemes.begin(),
++ schemes.end());
++ }
++ MaybeRunCookieCallback(std::move(callback), true);
++}
++
+ // This function must be called before the CookieMonster is used.
+ void CookieMonster::SetPersistSessionCookies(bool persist_session_cookies) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+diff --git net/cookies/cookie_monster.h net/cookies/cookie_monster.h
+index 8a896a86b58b0..08077ffeebc3e 100644
+--- net/cookies/cookie_monster.h
++++ net/cookies/cookie_monster.h
+@@ -208,6 +208,8 @@ class NET_EXPORT CookieMonster : public CookieStore {
+ CookieChangeDispatcher& GetChangeDispatcher() override;
+ void SetCookieableSchemes(const std::vector<std::string>& schemes,
+ SetCookieableSchemesCallback callback) override;
++ void AddCookieableSchemes(const std::vector<std::string>& schemes,
++ SetCookieableSchemesCallback callback) override;
+ absl::optional<bool> SiteHasCookieInOtherPartition(
+ const net::SchemefulSite& site,
+ const absl::optional<CookiePartitionKey>& partition_key) const override;
+diff --git net/cookies/cookie_store.h net/cookies/cookie_store.h
+index 61fd008fc067e..73909be088278 100644
+--- net/cookies/cookie_store.h
++++ net/cookies/cookie_store.h
+@@ -163,6 +163,11 @@ class NET_EXPORT CookieStore {
+ // Transfer ownership of a CookieAccessDelegate.
+ void SetCookieAccessDelegate(std::unique_ptr<CookieAccessDelegate> delegate);
+
++ // Adds to the list of cookieable schemes. Does nothing if called after first
++ // use of the instance (i.e. after the instance initialization process).
++ virtual void AddCookieableSchemes(const std::vector<std::string>& schemes,
++ SetCookieableSchemesCallback callback) = 0;
++
+ // This may be null if no delegate has been set yet, or the delegate has been
+ // reset to null.
+ const CookieAccessDelegate* cookie_access_delegate() const {
+diff --git services/network/cookie_manager.cc services/network/cookie_manager.cc
+index 5b4fe64a4374a..780c9726a03d3 100644
+--- services/network/cookie_manager.cc
++++ services/network/cookie_manager.cc
+@@ -283,14 +283,9 @@ void CookieManager::FlushCookieStore(FlushCookieStoreCallback callback) {
+ void CookieManager::AllowFileSchemeCookies(
+ bool allow,
+ AllowFileSchemeCookiesCallback callback) {
+- std::vector<std::string> cookieable_schemes(
+- net::CookieMonster::kDefaultCookieableSchemes,
+- net::CookieMonster::kDefaultCookieableSchemes +
+- net::CookieMonster::kDefaultCookieableSchemesCount);
+- if (allow) {
+- cookieable_schemes.push_back(url::kFileScheme);
+- }
+- cookie_store_->SetCookieableSchemes(cookieable_schemes, std::move(callback));
++ if (!allow)
++ return;
++ cookie_store_->AddCookieableSchemes({url::kFileScheme}, std::move(callback));
+ }
+
+ void CookieManager::SetForceKeepSessionState() {
+diff --git services/network/network_context.cc services/network/network_context.cc
+index 47bba434b56d8..92060d40e0a84 100644
+--- services/network/network_context.cc
++++ services/network/network_context.cc
+@@ -2252,16 +2252,20 @@ URLRequestContextOwner NetworkContext::MakeURLRequestContext(
+ network_service_->network_quality_estimator());
+ }
+
+- if (session_cleanup_cookie_store) {
+- std::unique_ptr<net::CookieMonster> cookie_store =
+- std::make_unique<net::CookieMonster>(session_cleanup_cookie_store.get(),
+- net_log);
+- if (params_->persist_session_cookies)
+- cookie_store->SetPersistSessionCookies(true);
++ std::unique_ptr<net::CookieMonster> cookie_store =
++ std::make_unique<net::CookieMonster>(session_cleanup_cookie_store.get(),
++ net_log);
++ if (session_cleanup_cookie_store && params_->persist_session_cookies)
++ cookie_store->SetPersistSessionCookies(true);
+
+- builder.SetCookieStore(std::move(cookie_store));
++ if (params_->cookieable_schemes.has_value()) {
++ cookie_store->SetCookieableSchemes(
++ *params_->cookieable_schemes,
++ net::CookieStore::SetCookieableSchemesCallback());
+ }
+
++ builder.SetCookieStore(std::move(cookie_store));
++
+ if (base::FeatureList::IsEnabled(features::kPrivateStateTokens)) {
+ trust_token_store_ = std::make_unique<PendingTrustTokenStore>();
+
+diff --git services/network/public/mojom/network_context.mojom services/network/public/mojom/network_context.mojom
+index b2254b765c313..9d7da9a963f40 100644
+--- services/network/public/mojom/network_context.mojom
++++ services/network/public/mojom/network_context.mojom
+@@ -347,6 +347,9 @@ struct NetworkContextParams {
+ // cookies. Otherwise it should be false.
+ bool persist_session_cookies = false;
+
++ // Schemes that will be passed to CookieMonster::SetCookieableSchemes.
++ array<string>? cookieable_schemes;
++
+ // True if an HTTP cache should be used.
+ bool http_cache_enabled = true;
+ // Maximum size of the HTTP cache. 0 means to use the default size.
diff --git a/patch/patches/services_network_2718.patch b/patch/patches/services_network_2718.patch
new file mode 100644
index 00000000..ac2ef9fd
--- /dev/null
+++ b/patch/patches/services_network_2718.patch
@@ -0,0 +1,57 @@
+diff --git content/browser/storage_partition_impl.cc content/browser/storage_partition_impl.cc
+index a0aa623d7f673..2d60f2a4d40e5 100644
+--- content/browser/storage_partition_impl.cc
++++ content/browser/storage_partition_impl.cc
+@@ -494,10 +494,6 @@ class LoginHandlerDelegate {
+ }
+
+ WebContents* web_contents = web_contents_getter_.Run();
+- if (!web_contents) {
+- OnAuthCredentials(absl::nullopt);
+- return;
+- }
+
+ // WeakPtr is not strictly necessary here due to OnRequestCancelled.
+ creating_login_delegate_ = true;
+@@ -549,12 +545,6 @@ void OnAuthRequiredContinuation(
+ mojo::PendingRemote<network::mojom::AuthChallengeResponder>
+ auth_challenge_responder,
+ base::RepeatingCallback<WebContents*(void)> web_contents_getter) {
+- if (!web_contents_getter || !web_contents_getter.Run()) {
+- mojo::Remote<network::mojom::AuthChallengeResponder>
+- auth_challenge_responder_remote(std::move(auth_challenge_responder));
+- auth_challenge_responder_remote->OnAuthCredentials(absl::nullopt);
+- return;
+- }
+ new LoginHandlerDelegate(
+ std::move(auth_challenge_responder), std::move(web_contents_getter),
+ auth_info, is_request_for_primary_main_frame, process_id, request_id, url,
+@@ -2939,8 +2929,12 @@ void StoragePartitionImpl::GetQuotaSettings(
+ return;
+ }
+
++ // CEF always returns false for IsOffTheRecord(), so also check the path.
++ const bool is_incognito = browser_context_->IsOffTheRecord() ||
++ browser_context_->GetPath().empty();
++
+ storage::GetNominalDynamicSettings(
+- GetPath(), browser_context_->IsOffTheRecord(),
++ GetPath(), is_incognito,
+ storage::GetDefaultDeviceInfoHelper(), std::move(callback));
+ }
+
+@@ -2950,9 +2944,12 @@ void StoragePartitionImpl::InitNetworkContext() {
+ cert_verifier::mojom::CertVerifierCreationParamsPtr
+ cert_verifier_creation_params =
+ cert_verifier::mojom::CertVerifierCreationParams::New();
+- GetContentClient()->browser()->ConfigureNetworkContextParams(
++ if (!GetContentClient()->browser()->ConfigureNetworkContextParams(
+ browser_context_, is_in_memory(), relative_partition_path_,
+- context_params.get(), cert_verifier_creation_params.get());
++ context_params.get(), cert_verifier_creation_params.get())) {
++ // Don't re-initialize the network context during shutdown.
++ return;
++ }
+ // Should be initialized with existing per-profile CORS access lists.
+ DCHECK(context_params->cors_origin_access_list.empty())
+ << "NetworkContextParams::cors_origin_access_list should be populated "
diff --git a/patch/patches/set_resize_background_color.patch b/patch/patches/set_resize_background_color.patch
new file mode 100644
index 00000000..11f63c3f
--- /dev/null
+++ b/patch/patches/set_resize_background_color.patch
@@ -0,0 +1,30 @@
+diff --git ui/views/controls/webview/webview.cc ui/views/controls/webview/webview.cc
+index fd325017d2347..84ab42c78c1fd 100644
+--- ui/views/controls/webview/webview.cc
++++ ui/views/controls/webview/webview.cc
+@@ -143,6 +143,10 @@ void WebView::EnableSizingFromWebContents(const gfx::Size& min_size,
+ MaybeEnableAutoResize(web_contents()->GetPrimaryMainFrame());
+ }
+
++void WebView::SetResizeBackgroundColor(SkColor resize_background_color) {
++ holder_->SetBackgroundColorWhenClipped(resize_background_color);
++}
++
+ void WebView::SetCrashedOverlayView(View* crashed_overlay_view) {
+ if (crashed_overlay_view_ == crashed_overlay_view)
+ return;
+diff --git ui/views/controls/webview/webview.h ui/views/controls/webview/webview.h
+index 33e93fd257574..b25e00d6b4f48 100644
+--- ui/views/controls/webview/webview.h
++++ ui/views/controls/webview/webview.h
+@@ -85,6 +85,10 @@ class WEBVIEW_EXPORT WebView : public View,
+ void EnableSizingFromWebContents(const gfx::Size& min_size,
+ const gfx::Size& max_size);
+
++ // Set the background color to use while resizing with a clip. This is white
++ // by default.
++ void SetResizeBackgroundColor(SkColor resize_background_color);
++
+ // If provided, this View will be shown in place of the web contents
+ // when the web contents is in a crashed state. This is cleared automatically
+ // if the web contents is changed.
diff --git a/patch/patches/storage_incognito_2289.patch b/patch/patches/storage_incognito_2289.patch
new file mode 100644
index 00000000..163f96f5
--- /dev/null
+++ b/patch/patches/storage_incognito_2289.patch
@@ -0,0 +1,72 @@
+diff --git content/browser/blob_storage/chrome_blob_storage_context.cc content/browser/blob_storage/chrome_blob_storage_context.cc
+index 3bfd99c004c55..e95bb2a6d78c2 100644
+--- content/browser/blob_storage/chrome_blob_storage_context.cc
++++ content/browser/blob_storage/chrome_blob_storage_context.cc
+@@ -122,7 +122,8 @@ ChromeBlobStorageContext* ChromeBlobStorageContext::GetFor(
+
+ // If we're not incognito mode, schedule all of our file tasks to enable
+ // disk on the storage context.
+- if (!context->IsOffTheRecord() && io_thread_valid) {
++ if (!context->GetPath().empty() && !context->IsOffTheRecord() &&
++ io_thread_valid) {
+ file_task_runner = base::ThreadPool::CreateTaskRunner(
+ {base::MayBlock(), base::TaskPriority::USER_VISIBLE,
+ base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN});
+diff --git content/browser/browser_context.cc content/browser/browser_context.cc
+index fe0f45376b729..2120ae8ef7665 100644
+--- content/browser/browser_context.cc
++++ content/browser/browser_context.cc
+@@ -130,7 +130,7 @@ StoragePartition* BrowserContext::GetStoragePartition(
+ StoragePartition* BrowserContext::GetStoragePartition(
+ const StoragePartitionConfig& storage_partition_config,
+ bool can_create) {
+- if (IsOffTheRecord()) {
++ if (IsOffTheRecord() || GetPath().empty()) {
+ // An off the record profile MUST only use in memory storage partitions.
+ CHECK(storage_partition_config.in_memory());
+ }
+@@ -365,7 +365,8 @@ BrowserContext::CreateVideoDecodePerfHistory() {
+ const bool kUseInMemoryDBDefault = false;
+ bool use_in_memory_db = base::GetFieldTrialParamByFeatureAsBool(
+ media::kMediaCapabilitiesWithParameters, kUseInMemoryDBParamName,
+- kUseInMemoryDBDefault);
++ kUseInMemoryDBDefault) ||
++ GetPath().empty();
+
+ std::unique_ptr<media::VideoDecodeStatsDB> stats_db;
+ if (use_in_memory_db) {
+diff --git content/public/browser/storage_partition_config.cc content/public/browser/storage_partition_config.cc
+index 81013d6eb993a..89abfbe7fec6c 100644
+--- content/public/browser/storage_partition_config.cc
++++ content/public/browser/storage_partition_config.cc
+@@ -7,6 +7,7 @@
+ #include <sstream>
+
+ #include "base/check.h"
++#include "base/files/file_path.h"
+ #include "base/strings/string_number_conversions.h"
+ #include "content/public/browser/browser_context.h"
+ #include "url/gurl.h"
+@@ -22,7 +23,8 @@ StoragePartitionConfig& StoragePartitionConfig::operator=(
+ // static
+ StoragePartitionConfig StoragePartitionConfig::CreateDefault(
+ BrowserContext* browser_context) {
+- return StoragePartitionConfig("", "", browser_context->IsOffTheRecord());
++ return StoragePartitionConfig("", "", browser_context->IsOffTheRecord() ||
++ browser_context->GetPath().empty());
+ }
+
+ // static
+diff --git storage/browser/database/database_tracker.cc storage/browser/database/database_tracker.cc
+index 27861ffd3321e..6983995e38815 100644
+--- storage/browser/database/database_tracker.cc
++++ storage/browser/database/database_tracker.cc
+@@ -568,7 +568,7 @@ bool DatabaseTracker::LazyInit() {
+ databases_table_ = std::make_unique<DatabasesTable>(db_.get());
+ meta_table_ = std::make_unique<sql::MetaTable>();
+
+- is_initialized_ = base::CreateDirectory(db_dir_) &&
++ is_initialized_ = (is_incognito_ ? true : base::CreateDirectory(db_dir_)) &&
+ (db_->is_open() ||
+ (is_incognito_ ? db_->OpenInMemory()
+ : db_->Open(kTrackerDatabaseFullPath))) &&
diff --git a/patch/patches/trace_event.patch b/patch/patches/trace_event.patch
new file mode 100644
index 00000000..2f83e144
--- /dev/null
+++ b/patch/patches/trace_event.patch
@@ -0,0 +1,13 @@
+diff --git base/trace_event/builtin_categories.h base/trace_event/builtin_categories.h
+index 686b0af1442fb..859c7ad4c64aa 100644
+--- base/trace_event/builtin_categories.h
++++ base/trace_event/builtin_categories.h
+@@ -64,6 +64,8 @@
+ X("cc") \
+ X("cc.debug") \
+ X("cdp.perf") \
++ X("cef") \
++ X("cef.client") \
+ X("chromeos") \
+ X("cma") \
+ X("compositor") \
diff --git a/patch/patches/ui_dragdrop_355390.patch b/patch/patches/ui_dragdrop_355390.patch
new file mode 100644
index 00000000..dda0787e
--- /dev/null
+++ b/patch/patches/ui_dragdrop_355390.patch
@@ -0,0 +1,14 @@
+diff --git ui/base/x/x11_os_exchange_data_provider.cc ui/base/x/x11_os_exchange_data_provider.cc
+index 50f6783cda7a0..a8f781375c719 100644
+--- ui/base/x/x11_os_exchange_data_provider.cc
++++ ui/base/x/x11_os_exchange_data_provider.cc
+@@ -139,7 +139,8 @@ void XOSExchangeDataProvider::SetURL(const GURL& url,
+ format_map_.Insert(x11::GetAtom(kMimeTypeMozillaURL), mem);
+
+ // Set a string fallback as well.
+- SetString(spec);
++ if (!HasString())
++ SetString(spec);
+
+ // Return early if this drag already contains file contents (this implies
+ // that file contents must be populated before URLs). Nautilus (and possibly
diff --git a/patch/patches/underlay_1051.patch b/patch/patches/underlay_1051.patch
new file mode 100644
index 00000000..6087d8e6
--- /dev/null
+++ b/patch/patches/underlay_1051.patch
@@ -0,0 +1,13 @@
+diff --git ui/base/cocoa/underlay_opengl_hosting_window.h ui/base/cocoa/underlay_opengl_hosting_window.h
+index a0e5f803e62b2..d59122c483920 100644
+--- ui/base/cocoa/underlay_opengl_hosting_window.h
++++ ui/base/cocoa/underlay_opengl_hosting_window.h
+@@ -12,7 +12,7 @@
+ // Common base class for windows that host a OpenGL surface that renders under
+ // the window. Previously contained methods related to hole punching, now just
+ // contains common asserts.
+-COMPONENT_EXPORT(UI_BASE)
++__attribute__((visibility("default")))
+ @interface UnderlayOpenGLHostingWindow : NSWindow
+ @end
+
diff --git a/patch/patches/views_1749_2102_3330.patch b/patch/patches/views_1749_2102_3330.patch
new file mode 100644
index 00000000..33c1ff38
--- /dev/null
+++ b/patch/patches/views_1749_2102_3330.patch
@@ -0,0 +1,739 @@
+diff --git ui/base/models/menu_model.h ui/base/models/menu_model.h
+index f1f8f33165a4a..8b07817c654e8 100644
+--- ui/base/models/menu_model.h
++++ ui/base/models/menu_model.h
+@@ -15,8 +15,11 @@
+ #include "ui/base/models/menu_separator_types.h"
+ #include "ui/gfx/native_widget_types.h"
+
++#include "third_party/skia/include/core/SkColor.h"
++
+ namespace gfx {
+ class FontList;
++class Point;
+ }
+
+ namespace ui {
+@@ -147,6 +150,27 @@ class COMPONENT_EXPORT(UI_BASE) MenuModel
+ // |event_flags| is a bit mask of ui::EventFlags.
+ virtual void ActivatedAt(size_t index, int event_flags);
+
++ // Called when the user moves the mouse outside the menu and over the owning
++ // window.
++ virtual void MouseOutsideMenu(const gfx::Point& screen_point) {}
++
++ // Called on unhandled open/close submenu keyboard commands. |is_rtl| will be
++ // true if the menu is displaying a right-to-left language.
++ virtual void UnhandledOpenSubmenu(bool is_rtl) {}
++ virtual void UnhandledCloseSubmenu(bool is_rtl) {}
++
++ // Override the text/background color of a given menu item dependent on the
++ // |index| and its |is_hovered| state. |is_minor| will be true for accelerator
++ // text. Returns true if it chooses to override the color.
++ virtual bool GetTextColor(size_t index,
++ bool is_minor,
++ bool is_hovered,
++ SkColor* override_color) const { return false; }
++ virtual bool GetBackgroundColor(size_t index,
++ bool is_hovered,
++ SkColor* override_color) const
++ { return false; }
++
+ // Called when the menu is about to be shown.
+ virtual void MenuWillShow() {}
+
+diff --git ui/gfx/render_text.cc ui/gfx/render_text.cc
+index 68a3c1f68f6c1..721bc530f8690 100644
+--- ui/gfx/render_text.cc
++++ ui/gfx/render_text.cc
+@@ -665,6 +665,14 @@ void RenderText::SetWhitespaceElision(absl::optional<bool> whitespace_elision) {
+ }
+ }
+
++void RenderText::SetDrawStringsFlags(int flags) {
++ if (draw_strings_flags_ == flags)
++ return;
++ draw_strings_flags_ = flags;
++ cached_bounds_and_offset_valid_ = false;
++ OnTextAttributeChanged();
++}
++
+ void RenderText::SetDisplayRect(const Rect& r) {
+ if (r != display_rect_) {
+ display_rect_ = r;
+@@ -1994,6 +2002,19 @@ void RenderText::OnTextAttributeChanged() {
+
+ layout_text_up_to_date_ = false;
+
++ if (draw_strings_flags_ != 0) {
++ // Compute layout size with the mnemonic character underlined since it might
++ // be larger than with the underline hidden.
++ int char_pos = -1;
++ int char_span = 0;
++ layout_text_ =
++ gfx::LocateAndRemoveAcceleratorChar(layout_text_, &char_pos, &char_span);
++ if (char_pos != -1) {
++ gfx::Range range(char_pos, char_pos + char_span);
++ styles_[TEXT_STYLE_UNDERLINE].ApplyValue(true, range);
++ }
++ }
++
+ OnLayoutTextAttributeChanged(true);
+ }
+
+diff --git ui/gfx/render_text.h ui/gfx/render_text.h
+index 5d9aaef31ecea..a6b47cd468270 100644
+--- ui/gfx/render_text.h
++++ ui/gfx/render_text.h
+@@ -347,6 +347,10 @@ class GFX_EXPORT RenderText {
+ return whitespace_elision_;
+ }
+
++ // Get or set the flags that control display of accelerator characters.
++ void SetDrawStringsFlags(int flags);
++ int draw_strings_flags() const { return draw_strings_flags_; }
++
+ const Rect& display_rect() const { return display_rect_; }
+ void SetDisplayRect(const Rect& r);
+
+@@ -1050,6 +1054,8 @@ class GFX_EXPORT RenderText {
+
+ // Tell whether or not the |layout_text_| needs an update or is up to date.
+ mutable bool layout_text_up_to_date_ = false;
++
++ int draw_strings_flags_ = 0;
+ };
+
+ } // namespace gfx
+diff --git ui/views/animation/ink_drop_host.h ui/views/animation/ink_drop_host.h
+index 427aed77cff26..415d8a4b22460 100644
+--- ui/views/animation/ink_drop_host.h
++++ ui/views/animation/ink_drop_host.h
+@@ -179,6 +179,8 @@ class VIEWS_EXPORT InkDropHost {
+ View* host_view() { return host_view_; }
+ const View* host_view() const { return host_view_; }
+
++ InkDropMode ink_drop_mode() const { return ink_drop_mode_; }
++
+ private:
+ friend class test::InkDropHostTestApi;
+
+diff --git ui/views/controls/button/label_button.cc ui/views/controls/button/label_button.cc
+index 5f48fe806d0ca..6253c7e880106 100644
+--- ui/views/controls/button/label_button.cc
++++ ui/views/controls/button/label_button.cc
+@@ -538,6 +538,12 @@ void LabelButton::OnThemeChanged() {
+ SchedulePaint();
+ }
+
++void LabelButton::SetFontList(const gfx::FontList& font_list) {
++ cached_normal_font_list_ = font_list;
++ cached_default_button_font_list_ = font_list;
++ label_->SetFontList(cached_normal_font_list_);
++}
++
+ void LabelButton::StateChanged(ButtonState old_state) {
+ Button::StateChanged(old_state);
+ ResetLabelEnabledColor();
+diff --git ui/views/controls/button/label_button.h ui/views/controls/button/label_button.h
+index 2da2766eeb055..0a8fbf3c51c13 100644
+--- ui/views/controls/button/label_button.h
++++ ui/views/controls/button/label_button.h
+@@ -141,6 +141,9 @@ class VIEWS_EXPORT LabelButton : public Button, public NativeThemeDelegate {
+ ui::NativeTheme::State GetForegroundThemeState(
+ ui::NativeTheme::ExtraParams* params) const override;
+
++ // Sets the font list used by this button.
++ void SetFontList(const gfx::FontList& font_list);
++
+ protected:
+ ImageView* image() const { return image_; }
+ Label* label() const { return label_; }
+diff --git ui/views/controls/label.cc ui/views/controls/label.cc
+index b544876cabea1..51efa38cda76e 100644
+--- ui/views/controls/label.cc
++++ ui/views/controls/label.cc
+@@ -52,12 +52,29 @@ enum LabelPropertyKey {
+ kLabelLineHeight,
+ kLabelObscured,
+ kLabelAllowCharacterBreak,
++ kLabelDrawStringsFlags,
+ };
+
+ bool IsOpaque(SkColor color) {
+ return SkColorGetA(color) == SK_AlphaOPAQUE;
+ }
+
++// Strips accelerator character prefixes in |text| if needed, based on |flags|.
++// Returns a range in |text| to underline or Range::InvalidRange() if
++// underlining is not needed.
++gfx::Range StripAcceleratorChars(int flags, std::u16string* text) {
++ if (flags & (gfx::Canvas::SHOW_PREFIX | gfx::Canvas::HIDE_PREFIX)) {
++ int char_pos = -1;
++ int char_span = 0;
++ *text = gfx::LocateAndRemoveAcceleratorChar(*text, &char_pos, &char_span);
++ if ((flags & gfx::Canvas::SHOW_PREFIX) && char_pos != -1) {
++ return gfx::Range(static_cast<size_t>(char_pos),
++ static_cast<size_t>(char_pos + char_span));
++ }
++ }
++ return gfx::Range::InvalidRange();
++}
++
+ } // namespace
+
+ namespace views {
+@@ -448,6 +465,15 @@ void Label::SetElideBehavior(gfx::ElideBehavior elide_behavior) {
+ OnPropertyChanged(&elide_behavior_, kPropertyEffectsPreferredSizeChanged);
+ }
+
++void Label::SetDrawStringsFlags(int flags) {
++ if (draw_strings_flags_ == flags)
++ return;
++ draw_strings_flags_ = flags;
++ full_text_->SetDrawStringsFlags(draw_strings_flags_);
++ OnPropertyChanged(&full_text_ + kLabelDrawStringsFlags,
++ kPropertyEffectsPreferredSizeChanged);
++}
++
+ std::u16string Label::GetTooltipText() const {
+ return tooltip_text_;
+ }
+@@ -753,6 +779,16 @@ std::unique_ptr<gfx::RenderText> Label::CreateRenderText() const {
+ render_text->SelectRange(stored_selection_range_);
+ }
+
++ if (draw_strings_flags_ != 0) {
++ auto text_str = GetText();
++ gfx::Range range = StripAcceleratorChars(draw_strings_flags_, &text_str);
++ render_text->SetText(text_str);
++ if (range.IsValid()) {
++ render_text->SetDisplayRect(bounds());
++ render_text->ApplyStyle(gfx::TEXT_STYLE_UNDERLINE, true, range);
++ }
++ }
++
+ return render_text;
+ }
+
+diff --git ui/views/controls/label.h ui/views/controls/label.h
+index 78bf64d40a649..16b889859d358 100644
+--- ui/views/controls/label.h
++++ ui/views/controls/label.h
+@@ -237,6 +237,10 @@ class VIEWS_EXPORT Label : public View,
+ gfx::ElideBehavior GetElideBehavior() const;
+ void SetElideBehavior(gfx::ElideBehavior elide_behavior);
+
++ // Get or set the flags that control display of accelerator characters.
++ void SetDrawStringsFlags(int flags);
++ int GetDrawStringsFlags() const { return draw_strings_flags_; }
++
+ // Gets/Sets the tooltip text. Default behavior for a label (single-line) is
+ // to show the full text if it is wider than its bounds. Calling this
+ // overrides the default behavior and lets you set a custom tooltip. To
+@@ -497,6 +501,7 @@ class VIEWS_EXPORT Label : public View,
+ int max_width_ = 0;
+ // This is used in single-line mode.
+ int max_width_single_line_ = 0;
++ int draw_strings_flags_ = 0;
+
+ std::unique_ptr<SelectionController> selection_controller_;
+
+diff --git ui/views/controls/menu/menu_controller.cc ui/views/controls/menu/menu_controller.cc
+index 64229eeead5f9..d3a13d1c0ab27 100644
+--- ui/views/controls/menu/menu_controller.cc
++++ ui/views/controls/menu/menu_controller.cc
+@@ -471,7 +471,8 @@ void MenuController::Run(Widget* parent,
+ MenuAnchorPosition position,
+ bool context_menu,
+ bool is_nested_drag,
+- gfx::NativeView native_view_for_gestures) {
++ gfx::NativeView native_view_for_gestures,
++ gfx::AcceleratedWidget parent_widget) {
+ exit_type_ = ExitType::kNone;
+ possible_drag_ = false;
+ drag_in_progress_ = false;
+@@ -518,6 +519,7 @@ void MenuController::Run(Widget* parent,
+ owner_->AddObserver(this);
+
+ native_view_for_gestures_ = native_view_for_gestures;
++ parent_widget_ = parent_widget;
+
+ // Only create a MenuPreTargetHandler for non-nested menus. Nested menus
+ // will use the existing one.
+@@ -2199,6 +2201,7 @@ void MenuController::OpenMenuImpl(MenuItemView* item, bool show) {
+ params.do_capture = do_capture;
+ params.native_view_for_gestures = native_view_for_gestures_;
+ params.owned_window_anchor = anchor;
++ params.parent_widget = parent_widget_;
+
+ if (item->GetParentMenuItem()) {
+ params.context = state_.item->GetWidget();
+@@ -2899,8 +2902,13 @@ MenuItemView* MenuController::FindInitialSelectableMenuItem(
+
+ void MenuController::OpenSubmenuChangeSelectionIfCan() {
+ MenuItemView* item = pending_state_.item;
+- if (!item->HasSubmenu() || !item->GetEnabled())
++ if (!item->HasSubmenu() || !item->GetEnabled() || !item->GetParentMenuItem()) {
++ MenuItemView* submenu_item =
++ item->GetParentMenuItem() ? item->GetParentMenuItem() : item;
++ submenu_item->GetDelegate()->OnUnhandledOpenSubmenu(submenu_item,
++ base::i18n::IsRTL());
+ return;
++ }
+ MenuItemView* to_select = nullptr;
+ if (!item->GetSubmenu()->GetMenuItems().empty())
+ to_select = FindInitialSelectableMenuItem(item, INCREMENT_SELECTION_DOWN);
+@@ -2919,8 +2927,10 @@ void MenuController::OpenSubmenuChangeSelectionIfCan() {
+ void MenuController::CloseSubmenu() {
+ MenuItemView* item = state_.item;
+ DCHECK(item);
+- if (!item->GetParentMenuItem())
++ if (!item->GetParentMenuItem()) {
++ item->GetDelegate()->OnUnhandledCloseSubmenu(item, base::i18n::IsRTL());
+ return;
++ }
+ if (item->SubmenuIsShowing())
+ SetSelection(item, SELECTION_UPDATE_IMMEDIATELY);
+ else if (item->GetParentMenuItem()->GetParentMenuItem())
+diff --git ui/views/controls/menu/menu_controller.h ui/views/controls/menu/menu_controller.h
+index ddc2dc5a381bb..c27f38c5e785e 100644
+--- ui/views/controls/menu/menu_controller.h
++++ ui/views/controls/menu/menu_controller.h
+@@ -113,7 +113,9 @@ class VIEWS_EXPORT MenuController
+ MenuAnchorPosition position,
+ bool context_menu,
+ bool is_nested_drag,
+- gfx::NativeView native_view_for_gestures = nullptr);
++ gfx::NativeView native_view_for_gestures = nullptr,
++ gfx::AcceleratedWidget parent_widget =
++ gfx::kNullAcceleratedWidget);
+
+ bool for_drop() const { return for_drop_; }
+
+@@ -730,6 +732,8 @@ class VIEWS_EXPORT MenuController
+ // RunType::SEND_GESTURE_EVENTS_TO_OWNER is set.
+ gfx::NativeView native_view_for_gestures_ = nullptr;
+
++ gfx::AcceleratedWidget parent_widget_ = gfx::kNullAcceleratedWidget;
++
+ // Indicates a possible drag operation.
+ bool possible_drag_ = false;
+
+diff --git ui/views/controls/menu/menu_delegate.h ui/views/controls/menu/menu_delegate.h
+index b8fa1c116ebcd..015f15ed72385 100644
+--- ui/views/controls/menu/menu_delegate.h
++++ ui/views/controls/menu/menu_delegate.h
+@@ -73,6 +73,22 @@ class VIEWS_EXPORT MenuDelegate {
+ virtual const gfx::FontList* GetLabelFontList(int id) const;
+ virtual absl::optional<SkColor> GetLabelColor(int id) const;
+
++ // Override the text color of a given menu item dependent on the |command_id|
++ // and its |is_hovered| state. |is_minor| will be true for accelerator text.
++ // Returns true if it chooses to override the color.
++ virtual bool GetTextColor(int command_id,
++ bool is_minor,
++ bool is_hovered,
++ SkColor* override_color) const { return false; }
++
++ // Override the background color of a given menu item dependent on the
++ // |command_id| and its |is_hovered| state. Returns true if it chooses to
++ // override the color.
++ virtual bool GetBackgroundColor(int command_id,
++ bool is_hovered,
++ SkColor* override_color) const
++ { return false; }
++
+ // The tooltip shown for the menu item. This is invoked when the user
+ // hovers over the item, and no tooltip text has been set for that item.
+ virtual std::u16string GetTooltipText(int id,
+@@ -201,6 +217,11 @@ class VIEWS_EXPORT MenuDelegate {
+ bool* has_mnemonics,
+ MenuButton** button);
+
++ // Called on unhandled open/close submenu keyboard commands. |is_rtl| will be
++ // true if the menu is displaying a right-to-left language.
++ virtual void OnUnhandledOpenSubmenu(MenuItemView* menu, bool is_rtl) {}
++ virtual void OnUnhandledCloseSubmenu(MenuItemView* menu, bool is_rtl) {}
++
+ // Returns the max width menus can grow to be.
+ virtual int GetMaxWidthForMenu(MenuItemView* menu);
+
+diff --git ui/views/controls/menu/menu_host.cc ui/views/controls/menu/menu_host.cc
+index 821826daa9e9a..626b8b540fd00 100644
+--- ui/views/controls/menu/menu_host.cc
++++ ui/views/controls/menu/menu_host.cc
+@@ -143,6 +143,8 @@ void MenuHost::InitMenuHost(const InitParams& init_params) {
+ : gfx::kNullNativeWindow;
+ params.bounds = init_params.bounds;
+
++ params.parent_widget = init_params.parent_widget;
++
+ #if defined(USE_AURA)
+ // TODO(msisov): remove kMenutype once positioning of anchored windows
+ // finally migrates to a new path.
+@@ -154,7 +156,8 @@ void MenuHost::InitMenuHost(const InitParams& init_params) {
+ // If MenuHost has no parent widget, it needs to be marked
+ // Activatable, so that calling Show in ShowMenuHost will
+ // get keyboard focus.
+- if (init_params.parent == nullptr)
++ if (init_params.parent == nullptr &&
++ init_params.parent_widget == gfx::kNullAcceleratedWidget)
+ params.activatable = Widget::InitParams::Activatable::kYes;
+
+ #if BUILDFLAG(IS_WIN)
+diff --git ui/views/controls/menu/menu_host.h ui/views/controls/menu/menu_host.h
+index 67cdb883886f8..4ca7d632ad7f9 100644
+--- ui/views/controls/menu/menu_host.h
++++ ui/views/controls/menu/menu_host.h
+@@ -55,6 +55,8 @@ class MenuHost : public Widget, public WidgetObserver {
+ // Additional information that helps to position anchored windows in such
+ // backends as Wayland.
+ ui::OwnedWindowAnchor owned_window_anchor;
++
++ gfx::AcceleratedWidget parent_widget = gfx::kNullAcceleratedWidget;
+ };
+
+ explicit MenuHost(SubmenuView* submenu);
+diff --git ui/views/controls/menu/menu_item_view.cc ui/views/controls/menu/menu_item_view.cc
+index 5cef5b698b9db..0e07b10be1744 100644
+--- ui/views/controls/menu/menu_item_view.cc
++++ ui/views/controls/menu/menu_item_view.cc
+@@ -1095,6 +1095,15 @@ void MenuItemView::PaintBackground(gfx::Canvas* canvas,
+ spilling_rect.set_y(spilling_rect.y() - corner_radius_);
+ spilling_rect.set_height(spilling_rect.height() + corner_radius_);
+ canvas->DrawRoundRect(spilling_rect, corner_radius_, flags);
++ return;
++ }
++
++ MenuDelegate *delegate = GetDelegate();
++ SkColor override_color;
++ if (delegate && delegate->GetBackgroundColor(GetCommand(),
++ paint_as_selected,
++ &override_color)) {
++ canvas->DrawColor(override_color);
+ } else if (paint_as_selected) {
+ gfx::Rect item_bounds = GetLocalBounds();
+ if (type_ == Type::kActionableSubMenu) {
+@@ -1161,6 +1170,13 @@ void MenuItemView::PaintMinorIconAndText(gfx::Canvas* canvas, SkColor color) {
+ }
+
+ SkColor MenuItemView::GetTextColor(bool minor, bool paint_as_selected) const {
++ SkColor text_color;
++ const MenuDelegate *delegate = GetDelegate();
++ if (delegate && delegate->GetTextColor(GetCommand(), minor, paint_as_selected,
++ &text_color)) {
++ return text_color;
++ }
++
+ style::TextContext context =
+ GetMenuController() && GetMenuController()->use_ash_system_ui_layout()
+ ? style::CONTEXT_TOUCH_MENU
+diff --git ui/views/controls/menu/menu_model_adapter.cc ui/views/controls/menu/menu_model_adapter.cc
+index 944a82d709df8..08aaf00b0208e 100644
+--- ui/views/controls/menu/menu_model_adapter.cc
++++ ui/views/controls/menu/menu_model_adapter.cc
+@@ -4,6 +4,7 @@
+
+ #include "ui/views/controls/menu/menu_model_adapter.h"
+
++#include <limits>
+ #include <list>
+ #include <memory>
+ #include <utility>
+@@ -243,6 +244,76 @@ bool MenuModelAdapter::IsItemChecked(int id) const {
+ return false;
+ }
+
++MenuItemView* MenuModelAdapter::GetSiblingMenu(MenuItemView* menu,
++ const gfx::Point& screen_point,
++ MenuAnchorPosition* anchor,
++ bool* has_mnemonics,
++ MenuButton** button) {
++ // Look up the menu model for this menu.
++ const std::map<MenuItemView*, ui::MenuModel*>::const_iterator map_iterator =
++ menu_map_.find(menu);
++ if (map_iterator != menu_map_.end()) {
++ map_iterator->second->MouseOutsideMenu(screen_point);
++ return nullptr;
++ }
++
++ NOTREACHED();
++ return nullptr;
++}
++
++void MenuModelAdapter::OnUnhandledOpenSubmenu(MenuItemView* menu,
++ bool is_rtl) {
++ // Look up the menu model for this menu.
++ const std::map<MenuItemView*, ui::MenuModel*>::const_iterator map_iterator =
++ menu_map_.find(menu);
++ if (map_iterator != menu_map_.end()) {
++ map_iterator->second->UnhandledOpenSubmenu(is_rtl);
++ return;
++ }
++
++ NOTREACHED();
++}
++
++void MenuModelAdapter::OnUnhandledCloseSubmenu(MenuItemView* menu,
++ bool is_rtl) {
++ // Look up the menu model for this menu.
++ const std::map<MenuItemView*, ui::MenuModel*>::const_iterator map_iterator =
++ menu_map_.find(menu);
++ if (map_iterator != menu_map_.end()) {
++ map_iterator->second->UnhandledCloseSubmenu(is_rtl);
++ return;
++ }
++
++ NOTREACHED();
++}
++
++bool MenuModelAdapter::GetTextColor(int command_id,
++ bool is_minor,
++ bool is_hovered,
++ SkColor* override_color) const {
++ ui::MenuModel* model = menu_model_;
++ size_t index = 0;
++ if (ui::MenuModel::GetModelAndIndexForCommandId(command_id, &model, &index))
++ return model->GetTextColor(index, is_minor, is_hovered, override_color);
++
++ // Return the default color.
++ return menu_model_->GetBackgroundColor(std::numeric_limits<size_t>::max(),
++ is_hovered, override_color);
++}
++
++bool MenuModelAdapter::GetBackgroundColor(int command_id,
++ bool is_hovered,
++ SkColor* override_color) const {
++ ui::MenuModel* model = menu_model_;
++ size_t index = 0;
++ if (ui::MenuModel::GetModelAndIndexForCommandId(command_id, &model, &index))
++ return model->GetBackgroundColor(index, is_hovered, override_color);
++
++ // Return the default color.
++ return menu_model_->GetBackgroundColor(std::numeric_limits<size_t>::max(),
++ is_hovered, override_color);
++}
++
+ void MenuModelAdapter::WillShowMenu(MenuItemView* menu) {
+ // Look up the menu model for this menu.
+ const std::map<MenuItemView*, ui::MenuModel*>::const_iterator map_iterator =
+diff --git ui/views/controls/menu/menu_model_adapter.h ui/views/controls/menu/menu_model_adapter.h
+index eaae7fd7a3607..bfc69d7fc86e1 100644
+--- ui/views/controls/menu/menu_model_adapter.h
++++ ui/views/controls/menu/menu_model_adapter.h
+@@ -88,6 +88,20 @@ class VIEWS_EXPORT MenuModelAdapter : public MenuDelegate,
+ bool IsCommandEnabled(int id) const override;
+ bool IsCommandVisible(int id) const override;
+ bool IsItemChecked(int id) const override;
++ MenuItemView* GetSiblingMenu(MenuItemView* menu,
++ const gfx::Point& screen_point,
++ MenuAnchorPosition* anchor,
++ bool* has_mnemonics,
++ MenuButton** button) override;
++ void OnUnhandledOpenSubmenu(MenuItemView* menu, bool is_rtl) override;
++ void OnUnhandledCloseSubmenu(MenuItemView* menu, bool is_rtl) override;
++ bool GetTextColor(int command_id,
++ bool is_minor,
++ bool is_hovered,
++ SkColor* override_color) const override;
++ bool GetBackgroundColor(int command_id,
++ bool is_hovered,
++ SkColor* override_color) const override;
+ void WillShowMenu(MenuItemView* menu) override;
+ void WillHideMenu(MenuItemView* menu) override;
+ void OnMenuClosed(MenuItemView* menu) override;
+diff --git ui/views/controls/menu/menu_runner.cc ui/views/controls/menu/menu_runner.cc
+index adb22671b94fa..59cc421e82e1b 100644
+--- ui/views/controls/menu/menu_runner.cc
++++ ui/views/controls/menu/menu_runner.cc
+@@ -36,6 +36,7 @@ void MenuRunner::RunMenuAt(Widget* parent,
+ MenuAnchorPosition anchor,
+ ui::MenuSourceType source_type,
+ gfx::NativeView native_view_for_gestures,
++ gfx::AcceleratedWidget parent_widget,
+ absl::optional<gfx::RoundedCornersF> corners) {
+ // Do not attempt to show the menu if the application is currently shutting
+ // down. MenuDelegate::OnMenuClosed would not be called.
+@@ -82,7 +83,7 @@ void MenuRunner::RunMenuAt(Widget* parent,
+ }
+
+ impl_->RunMenuAt(parent, button_controller, bounds, anchor, run_types_,
+- native_view_for_gestures, corners);
++ native_view_for_gestures, parent_widget, corners);
+ }
+
+ bool MenuRunner::IsRunning() const {
+diff --git ui/views/controls/menu/menu_runner.h ui/views/controls/menu/menu_runner.h
+index 9d51c2e38b893..7fbe67198a1e5 100644
+--- ui/views/controls/menu/menu_runner.h
++++ ui/views/controls/menu/menu_runner.h
+@@ -152,6 +152,8 @@ class VIEWS_EXPORT MenuRunner {
+ MenuAnchorPosition anchor,
+ ui::MenuSourceType source_type,
+ gfx::NativeView native_view_for_gestures = nullptr,
++ gfx::AcceleratedWidget parent_widget =
++ gfx::kNullAcceleratedWidget,
+ absl::optional<gfx::RoundedCornersF> corners = absl::nullopt);
+
+ // Returns true if we're in a nested run loop running the menu.
+diff --git ui/views/controls/menu/menu_runner_impl.cc ui/views/controls/menu/menu_runner_impl.cc
+index c2513d2889a2b..5dfef1af49685 100644
+--- ui/views/controls/menu/menu_runner_impl.cc
++++ ui/views/controls/menu/menu_runner_impl.cc
+@@ -117,6 +117,7 @@ void MenuRunnerImpl::RunMenuAt(Widget* parent,
+ MenuAnchorPosition anchor,
+ int32_t run_types,
+ gfx::NativeView native_view_for_gestures,
++ gfx::AcceleratedWidget parent_widget,
+ absl::optional<gfx::RoundedCornersF> corners) {
+ closing_event_time_ = base::TimeTicks();
+ if (running_) {
+@@ -184,7 +185,7 @@ void MenuRunnerImpl::RunMenuAt(Widget* parent,
+ controller->Run(parent, button_controller, menu_, bounds, anchor,
+ (run_types & MenuRunner::CONTEXT_MENU) != 0,
+ (run_types & MenuRunner::NESTED_DRAG) != 0,
+- native_view_for_gestures);
++ native_view_for_gestures, parent_widget);
+ }
+
+ void MenuRunnerImpl::Cancel() {
+diff --git ui/views/controls/menu/menu_runner_impl.h ui/views/controls/menu/menu_runner_impl.h
+index 4d2909b5094ab..245e1a24dd810 100644
+--- ui/views/controls/menu/menu_runner_impl.h
++++ ui/views/controls/menu/menu_runner_impl.h
+@@ -53,6 +53,7 @@ class VIEWS_EXPORT MenuRunnerImpl : public MenuRunnerImplInterface,
+ MenuAnchorPosition anchor,
+ int32_t run_types,
+ gfx::NativeView native_view_for_gestures,
++ gfx::AcceleratedWidget parent_widget,
+ absl::optional<gfx::RoundedCornersF> corners = absl::nullopt) override;
+ void Cancel() override;
+ base::TimeTicks GetClosingEventTime() const override;
+diff --git ui/views/controls/menu/menu_runner_impl_adapter.cc ui/views/controls/menu/menu_runner_impl_adapter.cc
+index b6c680063889b..a1efa677a43a5 100644
+--- ui/views/controls/menu/menu_runner_impl_adapter.cc
++++ ui/views/controls/menu/menu_runner_impl_adapter.cc
+@@ -34,9 +34,10 @@ void MenuRunnerImplAdapter::RunMenuAt(
+ MenuAnchorPosition anchor,
+ int32_t types,
+ gfx::NativeView native_view_for_gestures,
++ gfx::AcceleratedWidget parent_widget,
+ absl::optional<gfx::RoundedCornersF> corners) {
+ impl_->RunMenuAt(parent, button_controller, bounds, anchor, types,
+- native_view_for_gestures);
++ native_view_for_gestures, parent_widget);
+ }
+
+ void MenuRunnerImplAdapter::Cancel() {
+diff --git ui/views/controls/menu/menu_runner_impl_adapter.h ui/views/controls/menu/menu_runner_impl_adapter.h
+index e6587d2208a13..c2c72f7edb89c 100644
+--- ui/views/controls/menu/menu_runner_impl_adapter.h
++++ ui/views/controls/menu/menu_runner_impl_adapter.h
+@@ -44,6 +44,7 @@ class VIEWS_EXPORT MenuRunnerImplAdapter : public MenuRunnerImplInterface {
+ MenuAnchorPosition anchor,
+ int32_t types,
+ gfx::NativeView native_view_for_gestures,
++ gfx::AcceleratedWidget parent_widget,
+ absl::optional<gfx::RoundedCornersF> corners = absl::nullopt) override;
+ void Cancel() override;
+ base::TimeTicks GetClosingEventTime() const override;
+diff --git ui/views/controls/menu/menu_runner_impl_cocoa.h ui/views/controls/menu/menu_runner_impl_cocoa.h
+index 50291eb07440a..9716791a463aa 100644
+--- ui/views/controls/menu/menu_runner_impl_cocoa.h
++++ ui/views/controls/menu/menu_runner_impl_cocoa.h
+@@ -43,6 +43,7 @@ class VIEWS_EXPORT MenuRunnerImplCocoa : public MenuRunnerImplInterface {
+ MenuAnchorPosition anchor,
+ int32_t run_types,
+ gfx::NativeView native_view_for_gestures,
++ gfx::AcceleratedWidget parent_widget,
+ absl::optional<gfx::RoundedCornersF> corners = absl::nullopt) override;
+ void Cancel() override;
+ base::TimeTicks GetClosingEventTime() const override;
+diff --git ui/views/controls/menu/menu_runner_impl_cocoa.mm ui/views/controls/menu/menu_runner_impl_cocoa.mm
+index 9ad468f10e9df..ccbaaad5b78bd 100644
+--- ui/views/controls/menu/menu_runner_impl_cocoa.mm
++++ ui/views/controls/menu/menu_runner_impl_cocoa.mm
+@@ -195,6 +195,7 @@ void MenuRunnerImplCocoa::RunMenuAt(
+ MenuAnchorPosition anchor,
+ int32_t run_types,
+ gfx::NativeView native_view_for_gestures,
++ gfx::AcceleratedWidget /*parent_widget*/,
+ absl::optional<gfx::RoundedCornersF> corners) {
+ DCHECK(!IsRunning());
+ DCHECK(parent);
+diff --git ui/views/controls/menu/menu_runner_impl_interface.h ui/views/controls/menu/menu_runner_impl_interface.h
+index cf696fbcf0714..5c48fd7410b88 100644
+--- ui/views/controls/menu/menu_runner_impl_interface.h
++++ ui/views/controls/menu/menu_runner_impl_interface.h
+@@ -46,6 +46,8 @@ class MenuRunnerImplInterface {
+ MenuAnchorPosition anchor,
+ int32_t run_types,
+ gfx::NativeView native_view_for_gestures,
++ gfx::AcceleratedWidget parent_widget =
++ gfx::kNullAcceleratedWidget,
+ absl::optional<gfx::RoundedCornersF> corners = absl::nullopt) = 0;
+
+ // Hides and cancels the menu.
+diff --git ui/views/controls/menu/menu_scroll_view_container.cc ui/views/controls/menu/menu_scroll_view_container.cc
+index e9102acc407c8..46a0cfb8bf436 100644
+--- ui/views/controls/menu/menu_scroll_view_container.cc
++++ ui/views/controls/menu/menu_scroll_view_container.cc
+@@ -263,6 +263,11 @@ MenuScrollViewContainer::MenuScrollViewContainer(SubmenuView* content_view)
+ scroll_down_button_ = background_view_->AddChildView(
+ std::make_unique<MenuScrollButton>(content_view, false));
+
++ SkColor override_color;
++ MenuDelegate* delegate = content_view_->GetMenuItem()->GetDelegate();
++ if (delegate && delegate->GetBackgroundColor(-1, false, &override_color))
++ SetBackground(views::CreateSolidBackground(override_color));
++
+ arrow_ = BubbleBorderTypeFromAnchor(
+ content_view_->GetMenuItem()->GetMenuController()->GetAnchorPosition());
+
+diff --git ui/views/test/ui_controls_factory_desktop_aura_ozone.cc ui/views/test/ui_controls_factory_desktop_aura_ozone.cc
+index da9cefb9dffc1..6900756b3822d 100644
+--- ui/views/test/ui_controls_factory_desktop_aura_ozone.cc
++++ ui/views/test/ui_controls_factory_desktop_aura_ozone.cc
+@@ -16,6 +16,7 @@
+ #include "base/task/single_thread_task_runner.h"
+ #include "build/build_config.h"
+ #include "build/chromeos_buildflags.h"
++#include "cef/libcef/features/features.h"
+ #include "ui/aura/client/screen_position_client.h"
+ #include "ui/aura/env.h"
+ #include "ui/aura/test/aura_test_utils.h"
+@@ -106,9 +107,11 @@ class UIControlsDesktopOzone : public UIControlsAura {
+ aura::test::QueryLatestMousePositionRequestInHost(host);
+ host->ConvertPixelsToDIP(&root_current_location);
+
++#if !BUILDFLAG(ENABLE_CEF)
+ auto* screen = views::test::TestDesktopScreenOzone::GetInstance();
+ DCHECK_EQ(screen, display::Screen::GetScreen());
+ screen->set_cursor_screen_point(gfx::Point(screen_x, screen_y));
++#endif
+
+ #if !BUILDFLAG(IS_CHROMEOS_LACROS)
+ if (root_location != root_current_location &&
+diff --git ui/views/view.h ui/views/view.h
+index 43b50bfdc3cb6..3d23059131467 100644
+--- ui/views/view.h
++++ ui/views/view.h
+@@ -21,6 +21,7 @@
+ #include "base/memory/raw_ptr.h"
+ #include "base/observer_list.h"
+ #include "base/strings/string_piece.h"
++#include "base/supports_user_data.h"
+ #include "build/build_config.h"
+ #include "third_party/abseil-cpp/absl/types/optional.h"
+ #include "third_party/skia/include/core/SkPath.h"
+@@ -271,7 +272,8 @@ class VIEWS_EXPORT View : public ui::LayerDelegate,
+ public ui::EventTarget,
+ public ui::EventHandler,
+ public ui::PropertyHandler,
+- public ui::metadata::MetaDataProvider {
++ public ui::metadata::MetaDataProvider,
++ public base::SupportsUserData {
+ public:
+ using Views = std::vector<View*>;
+
diff --git a/patch/patches/views_widget.patch b/patch/patches/views_widget.patch
new file mode 100644
index 00000000..94a2f34c
--- /dev/null
+++ b/patch/patches/views_widget.patch
@@ -0,0 +1,491 @@
+diff --git content/browser/renderer_host/render_widget_host_view_base.cc content/browser/renderer_host/render_widget_host_view_base.cc
+index 9a942b2b4dd39..fe77b3fa468e3 100644
+--- content/browser/renderer_host/render_widget_host_view_base.cc
++++ content/browser/renderer_host/render_widget_host_view_base.cc
+@@ -656,6 +656,14 @@ float RenderWidgetHostViewBase::GetScaleOverrideForCapture() const {
+ return scale_override_for_capture_;
+ }
+
++void RenderWidgetHostViewBase::SetHasExternalParent(bool val) {
++ has_external_parent_ = val;
++}
++
++bool RenderWidgetHostViewBase::HasExternalParent() const {
++ return has_external_parent_;
++}
++
+ void RenderWidgetHostViewBase::OnAutoscrollStart() {
+ if (!GetMouseWheelPhaseHandler())
+ return;
+diff --git content/browser/renderer_host/render_widget_host_view_base.h content/browser/renderer_host/render_widget_host_view_base.h
+index 1425fc2e82e48..312114d238da2 100644
+--- content/browser/renderer_host/render_widget_host_view_base.h
++++ content/browser/renderer_host/render_widget_host_view_base.h
+@@ -71,6 +71,7 @@ class CursorManager;
+ class MouseWheelPhaseHandler;
+ class RenderWidgetHostImpl;
+ class RenderWidgetHostViewBaseObserver;
++class RenderWidgetHostViewGuest;
+ class SyntheticGestureTarget;
+ class TextInputManager;
+ class TouchSelectionControllerClientManager;
+@@ -141,6 +142,8 @@ class CONTENT_EXPORT RenderWidgetHostViewBase : public RenderWidgetHostView {
+ const gfx::Size& max_size) override;
+ void DisableAutoResize(const gfx::Size& new_size) override;
+ float GetDeviceScaleFactor() const final;
++ void SetHasExternalParent(bool val) override;
++ bool HasExternalParent() const override;
+ TouchSelectionControllerClientManager*
+ GetTouchSelectionControllerClientManager() override;
+ ui::mojom::VirtualKeyboardMode GetVirtualKeyboardMode() override;
+@@ -177,6 +180,10 @@ class CONTENT_EXPORT RenderWidgetHostViewBase : public RenderWidgetHostView {
+ // Called when screen information or native widget bounds change.
+ virtual void UpdateScreenInfo();
+
++ // Generates the most current set of ScreenInfos from the current set of
++ // displays in the system for use in UpdateScreenInfo.
++ virtual display::ScreenInfos GetNewScreenInfosForUpdate();
++
+ // Called by the TextInputManager to notify the view about being removed from
+ // the list of registered views, i.e., TextInputManager is no longer tracking
+ // TextInputState from this view. The RWHV should reset |text_input_manager_|
+@@ -430,6 +437,12 @@ class CONTENT_EXPORT RenderWidgetHostViewBase : public RenderWidgetHostView {
+ const gfx::Rect& bounds,
+ const gfx::Rect& anchor_rect) = 0;
+
++ // Perform all the initialization steps necessary for this object to represent
++ // the platform widget owned by |guest_view| and embedded in
++ // |parent_host_view|.
++ virtual void InitAsGuest(RenderWidgetHostView* parent_host_view,
++ RenderWidgetHostViewGuest* guest_view) {}
++
+ // Sets the cursor for this view to the one specified.
+ virtual void UpdateCursor(const ui::Cursor& cursor) = 0;
+
+@@ -675,6 +688,10 @@ class CONTENT_EXPORT RenderWidgetHostViewBase : public RenderWidgetHostView {
+ // to all displays.
+ gfx::Size system_cursor_size_;
+
++ // True if the widget has a external parent view/window outside of the
++ // Chromium-controlled view/window hierarchy.
++ bool has_external_parent_ = false;
++
+ private:
+ FRIEND_TEST_ALL_PREFIXES(
+ BrowserSideFlingBrowserTest,
+@@ -696,10 +713,6 @@ class CONTENT_EXPORT RenderWidgetHostViewBase : public RenderWidgetHostView {
+
+ void SynchronizeVisualProperties();
+
+- // Generates the most current set of ScreenInfos from the current set of
+- // displays in the system for use in UpdateScreenInfo.
+- display::ScreenInfos GetNewScreenInfosForUpdate();
+-
+ // Called when display properties that need to be synchronized with the
+ // renderer process changes. This method is called before notifying
+ // RenderWidgetHostImpl in order to allow the view to allocate a new
+diff --git content/browser/renderer_host/render_widget_host_view_event_handler.cc content/browser/renderer_host/render_widget_host_view_event_handler.cc
+index fe52808643114..58197f52e19e5 100644
+--- content/browser/renderer_host/render_widget_host_view_event_handler.cc
++++ content/browser/renderer_host/render_widget_host_view_event_handler.cc
+@@ -52,6 +52,10 @@ namespace {
+ // of the border area, in percentage of the corresponding dimension.
+ const int kMouseLockBorderPercentage = 15;
+
++#if BUILDFLAG(IS_LINUX)
++#include "ui/aura/window_tree_host.h"
++#endif
++
+ #if BUILDFLAG(IS_WIN)
+ // A callback function for EnumThreadWindows to enumerate and dismiss
+ // any owned popup windows.
+@@ -833,6 +837,14 @@ void RenderWidgetHostViewEventHandler::MoveCursorToCenter(
+ }
+ return;
+ }
++#endif
++#if BUILDFLAG(IS_LINUX)
++ if (host_view_->HasExternalParent() &&
++ window_ && window_->delegate()->CanFocus()) {
++ aura::WindowTreeHost* host = window_->GetHost();
++ if (host)
++ host->Show();
++ }
+ #endif
+ synthetic_move_position_ = center_in_screen;
+ }
+@@ -862,6 +874,17 @@ bool RenderWidgetHostViewEventHandler::MatchesSynthesizedMovePosition(
+ }
+
+ void RenderWidgetHostViewEventHandler::SetKeyboardFocus() {
++#if BUILDFLAG(IS_WIN)
++ if (host_view_->HasExternalParent() &&
++ window_ && window_->delegate()->CanFocus()) {
++ aura::WindowTreeHost* host = window_->GetHost();
++ if (host) {
++ gfx::AcceleratedWidget hwnd = host->GetAcceleratedWidget();
++ if (!(::GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_NOACTIVATE))
++ ::SetFocus(hwnd);
++ }
++ }
++#endif
+ // TODO(wjmaclean): can host_ ever be null?
+ if (host_ && set_focus_on_mouse_down_or_key_event_) {
+ set_focus_on_mouse_down_or_key_event_ = false;
+diff --git content/public/browser/render_widget_host_view.h content/public/browser/render_widget_host_view.h
+index c4cb1c13fc35c..a9371d66f3f9c 100644
+--- content/public/browser/render_widget_host_view.h
++++ content/public/browser/render_widget_host_view.h
+@@ -255,6 +255,14 @@ class CONTENT_EXPORT RenderWidgetHostView {
+ // This must always return the same device scale factor as GetScreenInfo.
+ virtual float GetDeviceScaleFactor() const = 0;
+
++ // Set whether the widget has a external parent view/window outside of the
++ // Chromium-controlled view/window hierarchy.
++ virtual void SetHasExternalParent(bool val) = 0;
++
++ // Returns true if the widget has a external parent view/window outside of the
++ // Chromium-controlled view/window hierarchy.
++ virtual bool HasExternalParent() const = 0;
++
+ #if BUILDFLAG(IS_MAC)
+ // Set the view's active state (i.e., tint state of controls).
+ virtual void SetActive(bool active) = 0;
+diff --git ui/ozone/platform/x11/x11_window.cc ui/ozone/platform/x11/x11_window.cc
+index cbf300db6ec3a..0e41c846397c7 100644
+--- ui/ozone/platform/x11/x11_window.cc
++++ ui/ozone/platform/x11/x11_window.cc
+@@ -1796,7 +1796,8 @@ void X11Window::CreateXWindow(const PlatformWindowInitProperties& properties) {
+ req.border_pixel = 0;
+
+ bounds_in_pixels_ = SanitizeBounds(bounds);
+- req.parent = x_root_window_;
++ req.parent = properties.parent_widget == gfx::kNullAcceleratedWidget ?
++ x_root_window_ : static_cast<x11::Window>(properties.parent_widget);
+ req.x = bounds_in_pixels_.x();
+ req.y = bounds_in_pixels_.y();
+ req.width = bounds_in_pixels_.width();
+diff --git ui/views/widget/desktop_aura/desktop_screen_win.cc ui/views/widget/desktop_aura/desktop_screen_win.cc
+index 4d15a5c0937e6..9db89f2ac8d91 100644
+--- ui/views/widget/desktop_aura/desktop_screen_win.cc
++++ ui/views/widget/desktop_aura/desktop_screen_win.cc
+@@ -23,6 +23,8 @@ DesktopScreenWin::~DesktopScreenWin() {
+ }
+
+ HWND DesktopScreenWin::GetHWNDFromNativeWindow(gfx::NativeWindow window) const {
++ if (!window)
++ return nullptr;
+ aura::WindowTreeHost* host = window->GetHost();
+ return host ? host->GetAcceleratedWidget() : nullptr;
+ }
+diff --git ui/views/widget/desktop_aura/desktop_window_tree_host_linux.cc ui/views/widget/desktop_aura/desktop_window_tree_host_linux.cc
+index 19e84689c878f..a8943c34699c5 100644
+--- ui/views/widget/desktop_aura/desktop_window_tree_host_linux.cc
++++ ui/views/widget/desktop_aura/desktop_window_tree_host_linux.cc
+@@ -165,6 +165,18 @@ Widget::MoveLoopResult DesktopWindowTreeHostLinux::RunMoveLoop(
+ return result;
+ }
+
++gfx::Rect DesktopWindowTreeHostLinux::GetWindowBoundsInScreen() const {
++ if (!screen_bounds_.IsEmpty())
++ return screen_bounds_;
++ return DesktopWindowTreeHostPlatform::GetWindowBoundsInScreen();
++}
++
++gfx::Point DesktopWindowTreeHostLinux::GetLocationOnScreenInPixels() const {
++ if (!screen_bounds_.IsEmpty())
++ return screen_bounds_.origin();
++ return DesktopWindowTreeHostPlatform::GetLocationOnScreenInPixels();
++}
++
+ void DesktopWindowTreeHostLinux::DispatchEvent(ui::Event* event) {
+ // In Windows, the native events sent to chrome are separated into client
+ // and non-client versions of events, which we record on our LocatedEvent
+@@ -288,6 +300,8 @@ void DesktopWindowTreeHostLinux::AddAdditionalInitProperties(
+
+ properties->wayland_app_id = params.wayland_app_id;
+
++ properties->parent_widget = params.parent_widget;
++
+ DCHECK(!properties->x11_extension_delegate);
+ properties->x11_extension_delegate = this;
+ }
+diff --git ui/views/widget/desktop_aura/desktop_window_tree_host_linux.h ui/views/widget/desktop_aura/desktop_window_tree_host_linux.h
+index 01d4ffe408a84..fbe41fefbb2bd 100644
+--- ui/views/widget/desktop_aura/desktop_window_tree_host_linux.h
++++ ui/views/widget/desktop_aura/desktop_window_tree_host_linux.h
+@@ -57,6 +57,8 @@ class VIEWS_EXPORT DesktopWindowTreeHostLinux
+ // Disables event listening to make |dialog| modal.
+ base::OnceClosure DisableEventListening();
+
++ void set_screen_bounds(const gfx::Rect& bounds) { screen_bounds_ = bounds; }
++
+ protected:
+ // Overridden from DesktopWindowTreeHost:
+ void Init(const Widget::InitParams& params) override;
+@@ -66,6 +68,8 @@ class VIEWS_EXPORT DesktopWindowTreeHostLinux
+ const gfx::Vector2d& drag_offset,
+ Widget::MoveLoopSource source,
+ Widget::MoveLoopEscapeBehavior escape_behavior) override;
++ gfx::Rect GetWindowBoundsInScreen() const override;
++ gfx::Point GetLocationOnScreenInPixels() const override;
+
+ // PlatformWindowDelegate:
+ void DispatchEvent(ui::Event* event) override;
+@@ -114,6 +118,9 @@ class VIEWS_EXPORT DesktopWindowTreeHostLinux
+
+ uint32_t modal_dialog_counter_ = 0;
+
++ // Override the screen bounds when the host is a child window.
++ gfx::Rect screen_bounds_;
++
+ // The display and the native X window hosting the root window.
+ base::WeakPtrFactory<DesktopWindowTreeHostLinux> weak_factory_{this};
+ };
+diff --git ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
+index 113fcb91360fb..8d82b545b51bb 100644
+--- ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
++++ ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
+@@ -275,8 +275,8 @@ void DesktopWindowTreeHostPlatform::Init(const Widget::InitParams& params) {
+ if (properties.parent_widget) {
+ window_parent_ = DesktopWindowTreeHostPlatform::GetHostForWidget(
+ properties.parent_widget);
+- DCHECK(window_parent_);
+- window_parent_->window_children_.insert(this);
++ if (window_parent_)
++ window_parent_->window_children_.insert(this);
+ }
+
+ // Calculate initial bounds.
+diff --git ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc
+index 0be1688818063..b627453be9f8b 100644
+--- ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc
++++ ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc
+@@ -180,16 +180,28 @@ void DesktopWindowTreeHostWin::Init(const Widget::InitParams& params) {
+ native_widget_delegate_.get());
+
+ HWND parent_hwnd = nullptr;
+- if (params.parent && params.parent->GetHost())
++ if (params.parent_widget) {
++ parent_hwnd = params.parent_widget;
++ has_external_parent_ = true;
++ } else if (params.parent && params.parent->GetHost()) {
+ parent_hwnd = params.parent->GetHost()->GetAcceleratedWidget();
++ }
+
+ remove_standard_frame_ = params.remove_standard_frame;
+ has_non_client_view_ = Widget::RequiresNonClientView(params.type);
+ z_order_ = params.EffectiveZOrderLevel();
+
+- // We don't have an HWND yet, so scale relative to the nearest screen.
+- gfx::Rect pixel_bounds =
+- display::win::ScreenWin::DIPToScreenRect(nullptr, params.bounds);
++ gfx::Rect pixel_bounds;
++ if (has_external_parent_ && params.type != Widget::InitParams::TYPE_MENU) {
++ // Scale relative to the screen that contains the parent window.
++ // Child windows always have origin (0,0).
++ pixel_bounds.set_size(display::win::ScreenWin::DIPToScreenSize(
++ parent_hwnd, params.bounds.size()));
++ } else {
++ // We don't have an HWND yet, so scale relative to the nearest screen.
++ pixel_bounds =
++ display::win::ScreenWin::DIPToScreenRect(nullptr, params.bounds);
++ }
+ message_handler_->Init(parent_hwnd, pixel_bounds, params.headless_mode);
+ CreateCompositor(params.force_software_compositing);
+ OnAcceleratedWidgetAvailable();
+@@ -1030,11 +1042,15 @@ void DesktopWindowTreeHostWin::HandleFrameChanged() {
+ }
+
+ void DesktopWindowTreeHostWin::HandleNativeFocus(HWND last_focused_window) {
+- // TODO(beng): inform the native_widget_delegate_.
++ // See comments in CefBrowserPlatformDelegateNativeWin::SetFocus.
++ if (has_external_parent_ && CanActivate())
++ HandleActivationChanged(true);
+ }
+
+ void DesktopWindowTreeHostWin::HandleNativeBlur(HWND focused_window) {
+- // TODO(beng): inform the native_widget_delegate_.
++ // See comments in CefBrowserPlatformDelegateNativeWin::SetFocus.
++ if (has_external_parent_ && CanActivate())
++ HandleActivationChanged(false);
+ }
+
+ bool DesktopWindowTreeHostWin::HandleMouseEvent(ui::MouseEvent* event) {
+@@ -1042,6 +1058,12 @@ bool DesktopWindowTreeHostWin::HandleMouseEvent(ui::MouseEvent* event) {
+ if (ui::PlatformEventSource::ShouldIgnoreNativePlatformEvents())
+ return true;
+
++ // See comments in CefBrowserPlatformDelegateNativeWin::SetFocus.
++ if (has_external_parent_ && CanActivate() && event->IsAnyButton() &&
++ ::GetFocus() != GetHWND()) {
++ ::SetFocus(GetHWND());
++ }
++
+ SendEventToSink(event);
+ return event->handled();
+ }
+@@ -1215,8 +1237,16 @@ void DesktopWindowTreeHostWin::SetBoundsInDIP(const gfx::Rect& bounds) {
+ // positions in variable-DPI situations. See https://crbug.com/1224715 for
+ // details.
+ aura::Window* root = nullptr;
+- const gfx::Rect bounds_in_pixels =
++ if (has_external_parent_) {
++ // Scale relative to the screen that contains the parent window.
++ root = AsWindowTreeHost()->window();
++ }
++ gfx::Rect bounds_in_pixels =
+ display::Screen::GetScreen()->DIPToScreenRectInWindow(root, bounds);
++ if (has_external_parent_) {
++ // Child windows always have origin (0,0).
++ bounds_in_pixels.set_origin(gfx::Point(0, 0));
++ }
+ AsWindowTreeHost()->SetBoundsInPixels(bounds_in_pixels);
+ }
+
+diff --git ui/views/widget/desktop_aura/desktop_window_tree_host_win.h ui/views/widget/desktop_aura/desktop_window_tree_host_win.h
+index b23ba1bf3a49f..f85ff1bef75e4 100644
+--- ui/views/widget/desktop_aura/desktop_window_tree_host_win.h
++++ ui/views/widget/desktop_aura/desktop_window_tree_host_win.h
+@@ -319,6 +319,10 @@ class VIEWS_EXPORT DesktopWindowTreeHostWin
+ // True if the window should have the frame removed.
+ bool remove_standard_frame_;
+
++ // True if the widget has a external parent view/window outside of the
++ // Chromium-controlled view/window hierarchy.
++ bool has_external_parent_ = false;
++
+ // Visibility of the cursor. On Windows we can have multiple root windows and
+ // the implementation of ::ShowCursor() is based on a counter, so making this
+ // member static ensures that ::ShowCursor() is always called exactly once
+diff --git ui/views/widget/widget.cc ui/views/widget/widget.cc
+index 13d32438918d0..e5152c6e467c2 100644
+--- ui/views/widget/widget.cc
++++ ui/views/widget/widget.cc
+@@ -366,7 +366,8 @@ void Widget::Init(InitParams params) {
+ }
+
+ params.child |= (params.type == InitParams::TYPE_CONTROL);
+- is_top_level_ = !params.child;
++ is_top_level_ = !params.child ||
++ params.parent_widget != gfx::kNullAcceleratedWidget;
+
+ if (params.opacity == views::Widget::InitParams::WindowOpacity::kInferred &&
+ params.type != views::Widget::InitParams::TYPE_WINDOW) {
+@@ -466,13 +467,21 @@ void Widget::Init(InitParams params) {
+
+ if (show_state == ui::SHOW_STATE_MAXIMIZED) {
+ Maximize();
++ saved_show_state_ = ui::SHOW_STATE_MAXIMIZED;
+ } else if (show_state == ui::SHOW_STATE_MINIMIZED) {
+ Minimize();
+ saved_show_state_ = ui::SHOW_STATE_MINIMIZED;
++ } else if (show_state == ui::SHOW_STATE_FULLSCREEN) {
++ SetFullscreen(true);
+ }
+ } else if (delegate) {
+ SetContentsView(delegate->TransferOwnershipOfContentsView());
+- SetInitialBoundsForFramelessWindow(bounds);
++ if (params.parent_widget != gfx::kNullAcceleratedWidget) {
++ // Set the bounds directly instead of applying an inset.
++ SetBounds(bounds);
++ } else {
++ SetInitialBoundsForFramelessWindow(bounds);
++ }
+ }
+
+ if (base::FeatureList::IsEnabled(features::kWidgetLayering)) {
+@@ -1592,10 +1601,16 @@ void Widget::OnNativeWidgetParentChanged(gfx::NativeView parent) {
+ }
+
+ gfx::Size Widget::GetMinimumSize() const {
++ gfx::Size size;
++ if (widget_delegate_->MaybeGetMinimumSize(&size))
++ return size;
+ return non_client_view_ ? non_client_view_->GetMinimumSize() : gfx::Size();
+ }
+
+ gfx::Size Widget::GetMaximumSize() const {
++ gfx::Size size;
++ if (widget_delegate_->MaybeGetMaximumSize(&size))
++ return size;
+ return non_client_view_ ? non_client_view_->GetMaximumSize() : gfx::Size();
+ }
+
+diff --git ui/views/widget/widget.h ui/views/widget/widget.h
+index c179c718d0255..967a87c07d026 100644
+--- ui/views/widget/widget.h
++++ ui/views/widget/widget.h
+@@ -351,6 +351,8 @@ class VIEWS_EXPORT Widget : public internal::NativeWidgetDelegate,
+ // the concept with bubble anchoring a la BubbleDialogDelegateView.
+ gfx::NativeView parent = nullptr;
+
++ gfx::AcceleratedWidget parent_widget = gfx::kNullAcceleratedWidget;
++
+ // Specifies the initial bounds of the Widget. Default is empty, which means
+ // the NativeWidget may specify a default size. If the parent is specified,
+ // |bounds| is in the parent's coordinate system. If the parent is not
+diff --git ui/views/widget/widget_delegate.h ui/views/widget/widget_delegate.h
+index 56c992edca67a..21cee8b517edd 100644
+--- ui/views/widget/widget_delegate.h
++++ ui/views/widget/widget_delegate.h
+@@ -375,6 +375,10 @@ class VIEWS_EXPORT WidgetDelegate
+ // Returns true if the title text should be centered.
+ bool ShouldCenterWindowTitleText() const;
+
++ // CEF supports override of min/max size values.
++ virtual bool MaybeGetMinimumSize(gfx::Size* size) const { return false; }
++ virtual bool MaybeGetMaximumSize(gfx::Size* size) const { return false; }
++
+ bool focus_traverses_out() const { return params_.focus_traverses_out; }
+ bool enable_arrow_key_traversal() const {
+ return params_.enable_arrow_key_traversal;
+diff --git ui/views/widget/widget_hwnd_utils.cc ui/views/widget/widget_hwnd_utils.cc
+index b162f426dbceb..017eb2562f6eb 100644
+--- ui/views/widget/widget_hwnd_utils.cc
++++ ui/views/widget/widget_hwnd_utils.cc
+@@ -63,7 +63,8 @@ void CalculateWindowStylesFromInitParams(
+ if (!widget_delegate->CanResize())
+ *style &= static_cast<DWORD>(~(WS_THICKFRAME | WS_MAXIMIZEBOX));
+ if (params.remove_standard_frame)
+- *style &= static_cast<DWORD>(~(WS_MINIMIZEBOX | WS_MAXIMIZEBOX));
++ *style &= static_cast<DWORD>(~(WS_MINIMIZEBOX | WS_MAXIMIZEBOX |
++ WS_CAPTION | WS_SYSMENU));
+
+ if (native_widget_delegate->IsDialogBox()) {
+ *style |= DS_MODALFRAME;
+diff --git ui/views/win/hwnd_message_handler.cc ui/views/win/hwnd_message_handler.cc
+index 22bb24f2afcef..9d63bf4013775 100644
+--- ui/views/win/hwnd_message_handler.cc
++++ ui/views/win/hwnd_message_handler.cc
+@@ -826,7 +826,11 @@ bool HWNDMessageHandler::IsVisible() const {
+ }
+
+ bool HWNDMessageHandler::IsActive() const {
+- return GetActiveWindow() == hwnd();
++ // This active state is checked via FocusManager::SetFocusedViewWithReason.
++ // With CEF external parent hwnd() may be a child window, whereas
++ // GetActiveWindow() will return the root window, so make sure that we always
++ // compare root windows.
++ return GetActiveWindow() == GetAncestor(hwnd(), GA_ROOT);
+ }
+
+ bool HWNDMessageHandler::IsMinimized() const {
+@@ -3187,10 +3191,13 @@ LRESULT HWNDMessageHandler::HandleMouseEventInternal(UINT message,
+ } else if (event.type() == ui::ET_MOUSEWHEEL) {
+ ui::MouseWheelEvent mouse_wheel_event(msg);
+ // Reroute the mouse wheel to the window under the pointer if applicable.
+- return (ui::RerouteMouseWheel(hwnd(), w_param, l_param) ||
+- delegate_->HandleMouseEvent(&mouse_wheel_event))
+- ? 0
+- : 1;
++ if (ui::RerouteMouseWheel(hwnd(), w_param, l_param) ||
++ delegate_->HandleMouseEvent(&mouse_wheel_event)) {
++ SetMsgHandled(TRUE);
++ return 0;
++ } else {
++ return 1;
++ }
+ }
+
+ // Suppress |ET_MOUSE_MOVED| and |ET_MOUSE_DRAGGED| events from WM_MOUSE*
diff --git a/patch/patches/viz_osr_2575.patch b/patch/patches/viz_osr_2575.patch
new file mode 100644
index 00000000..ed656cf1
--- /dev/null
+++ b/patch/patches/viz_osr_2575.patch
@@ -0,0 +1,271 @@
+diff --git components/viz/host/host_display_client.cc components/viz/host/host_display_client.cc
+index 0c63e0d59b6b0..bdbac6fceb1df 100644
+--- components/viz/host/host_display_client.cc
++++ components/viz/host/host_display_client.cc
+@@ -48,9 +48,14 @@ void HostDisplayClient::OnDisplayReceivedCALayerParams(
+ }
+ #endif
+
+-#if BUILDFLAG(IS_WIN)
++void HostDisplayClient::UseProxyOutputDevice(
++ UseProxyOutputDeviceCallback callback) {
++ std::move(callback).Run(false);
++}
++
+ void HostDisplayClient::CreateLayeredWindowUpdater(
+ mojo::PendingReceiver<mojom::LayeredWindowUpdater> receiver) {
++#if BUILDFLAG(IS_WIN)
+ if (!NeedsToUseLayerWindow(widget_)) {
+ DLOG(ERROR) << "HWND shouldn't be using a layered window";
+ return;
+@@ -58,7 +63,10 @@ void HostDisplayClient::CreateLayeredWindowUpdater(
+
+ layered_window_updater_ =
+ std::make_unique<LayeredWindowUpdaterImpl>(widget_, std::move(receiver));
++#endif
+ }
++
++#if BUILDFLAG(IS_WIN)
+ void HostDisplayClient::AddChildWindowToBrowser(
+ gpu::SurfaceHandle child_window) {
+ NOTREACHED();
+diff --git components/viz/host/host_display_client.h components/viz/host/host_display_client.h
+index 5eeaadec9773f..93a716decfbb9 100644
+--- components/viz/host/host_display_client.h
++++ components/viz/host/host_display_client.h
+@@ -39,16 +39,17 @@ class VIZ_HOST_EXPORT HostDisplayClient : public mojom::DisplayClient {
+ gfx::AcceleratedWidget widget() const { return widget_; }
+ #endif
+
+- private:
+ // mojom::DisplayClient implementation:
++ void UseProxyOutputDevice(UseProxyOutputDeviceCallback callback) override;
++
+ #if BUILDFLAG(IS_APPLE)
+ void OnDisplayReceivedCALayerParams(
+ const gfx::CALayerParams& ca_layer_params) override;
+ #endif
+
+-#if BUILDFLAG(IS_WIN)
+ void CreateLayeredWindowUpdater(
+ mojo::PendingReceiver<mojom::LayeredWindowUpdater> receiver) override;
++#if BUILDFLAG(IS_WIN)
+ void AddChildWindowToBrowser(gpu::SurfaceHandle child_window) override;
+ #endif
+
+diff --git components/viz/host/layered_window_updater_impl.cc components/viz/host/layered_window_updater_impl.cc
+index 271486b45dcc8..a62210d8ca3c8 100644
+--- components/viz/host/layered_window_updater_impl.cc
++++ components/viz/host/layered_window_updater_impl.cc
+@@ -44,7 +44,7 @@ void LayeredWindowUpdaterImpl::OnAllocatedSharedMemory(
+ // |region|'s handle will close when it goes out of scope.
+ }
+
+-void LayeredWindowUpdaterImpl::Draw(DrawCallback draw_callback) {
++void LayeredWindowUpdaterImpl::Draw(const gfx::Rect& damage_rect, DrawCallback draw_callback) {
+ TRACE_EVENT0("viz", "LayeredWindowUpdaterImpl::Draw");
+
+ if (!canvas_) {
+diff --git components/viz/host/layered_window_updater_impl.h components/viz/host/layered_window_updater_impl.h
+index 8af69cac78b74..9f74e511c263d 100644
+--- components/viz/host/layered_window_updater_impl.h
++++ components/viz/host/layered_window_updater_impl.h
+@@ -38,7 +38,7 @@ class VIZ_HOST_EXPORT LayeredWindowUpdaterImpl
+ // mojom::LayeredWindowUpdater implementation.
+ void OnAllocatedSharedMemory(const gfx::Size& pixel_size,
+ base::UnsafeSharedMemoryRegion region) override;
+- void Draw(DrawCallback draw_callback) override;
++ void Draw(const gfx::Rect& damage_rect, DrawCallback draw_callback) override;
+
+ private:
+ const HWND hwnd_;
+diff --git components/viz/service/BUILD.gn components/viz/service/BUILD.gn
+index 77fc13c924dd1..3046733922148 100644
+--- components/viz/service/BUILD.gn
++++ components/viz/service/BUILD.gn
+@@ -220,6 +220,8 @@ viz_component("service") {
+ "transitions/transferable_resource_tracker.cc",
+ "transitions/transferable_resource_tracker.h",
+ "viz_service_export.h",
++ "//cef/libcef/browser/osr/software_output_device_proxy.cc",
++ "//cef/libcef/browser/osr/software_output_device_proxy.h",
+ ]
+
+ defines = [ "VIZ_SERVICE_IMPLEMENTATION" ]
+diff --git components/viz/service/display_embedder/output_surface_provider_impl.cc components/viz/service/display_embedder/output_surface_provider_impl.cc
+index ec7cc3404b5d6..01898ac0cef5b 100644
+--- components/viz/service/display_embedder/output_surface_provider_impl.cc
++++ components/viz/service/display_embedder/output_surface_provider_impl.cc
+@@ -17,6 +17,7 @@
+ #include "build/chromecast_buildflags.h"
+ #include "build/chromeos_buildflags.h"
+ #include "cc/base/switches.h"
++#include "cef/libcef/browser/osr/software_output_device_proxy.h"
+ #include "components/viz/common/display/renderer_settings.h"
+ #include "components/viz/common/frame_sinks/begin_frame_source.h"
+ #include "components/viz/service/display/display_compositor_memory_and_task_controller.h"
+@@ -29,6 +30,7 @@
+ #include "gpu/command_buffer/service/scheduler_sequence.h"
+ #include "gpu/config/gpu_finch_features.h"
+ #include "gpu/ipc/common/surface_handle.h"
++#include "mojo/public/cpp/bindings/sync_call_restrictions.h"
+ #include "ui/base/ui_base_switches.h"
+
+ #if BUILDFLAG(IS_WIN)
+@@ -141,6 +143,20 @@ OutputSurfaceProviderImpl::CreateSoftwareOutputDeviceForPlatform(
+ if (headless_)
+ return std::make_unique<SoftwareOutputDevice>();
+
++ {
++ mojo::ScopedAllowSyncCallForTesting allow_sync;
++ DCHECK(display_client);
++ bool use_proxy_output_device = false;
++ if (display_client->UseProxyOutputDevice(&use_proxy_output_device) &&
++ use_proxy_output_device) {
++ mojo::PendingRemote<mojom::LayeredWindowUpdater> layered_window_updater;
++ display_client->CreateLayeredWindowUpdater(
++ layered_window_updater.InitWithNewPipeAndPassReceiver());
++ return std::make_unique<SoftwareOutputDeviceProxy>(
++ std::move(layered_window_updater));
++ }
++ }
++
+ #if BUILDFLAG(IS_WIN)
+ return CreateSoftwareOutputDeviceWin(surface_handle, &output_device_backing_,
+ display_client);
+diff --git components/viz/service/display_embedder/software_output_device_win.cc components/viz/service/display_embedder/software_output_device_win.cc
+index d4d4c1444e7a1..d62a3939a31fa 100644
+--- components/viz/service/display_embedder/software_output_device_win.cc
++++ components/viz/service/display_embedder/software_output_device_win.cc
+@@ -192,8 +192,9 @@ void SoftwareOutputDeviceWinProxy::EndPaintDelegated(
+ if (!canvas_)
+ return;
+
+- layered_window_updater_->Draw(base::BindOnce(
+- &SoftwareOutputDeviceWinProxy::DrawAck, base::Unretained(this)));
++ layered_window_updater_->Draw(
++ damage_rect, base::BindOnce(&SoftwareOutputDeviceWinProxy::DrawAck,
++ base::Unretained(this)));
+ waiting_on_draw_ack_ = true;
+
+ TRACE_EVENT_ASYNC_BEGIN0("viz", "SoftwareOutputDeviceWinProxy::Draw", this);
+diff --git content/browser/compositor/viz_process_transport_factory.cc content/browser/compositor/viz_process_transport_factory.cc
+index d4c0be621ecd9..8b6052c4bd807 100644
+--- content/browser/compositor/viz_process_transport_factory.cc
++++ content/browser/compositor/viz_process_transport_factory.cc
+@@ -397,8 +397,13 @@ void VizProcessTransportFactory::OnEstablishedGpuChannel(
+ mojo::AssociatedRemote<viz::mojom::DisplayPrivate> display_private;
+ root_params->display_private =
+ display_private.BindNewEndpointAndPassReceiver();
+- compositor_data.display_client =
+- std::make_unique<HostDisplayClient>(compositor);
++ if (compositor->delegate()) {
++ compositor_data.display_client =
++ compositor->delegate()->CreateHostDisplayClient();
++ } else {
++ compositor_data.display_client =
++ std::make_unique<HostDisplayClient>(compositor);
++ }
+ root_params->display_client =
+ compositor_data.display_client->GetBoundRemote(resize_task_runner_);
+ mojo::AssociatedRemote<viz::mojom::ExternalBeginFrameController>
+diff --git mojo/public/cpp/bindings/sync_call_restrictions.h mojo/public/cpp/bindings/sync_call_restrictions.h
+index d63ec55ae38d6..ff86831efd68b 100644
+--- mojo/public/cpp/bindings/sync_call_restrictions.h
++++ mojo/public/cpp/bindings/sync_call_restrictions.h
+@@ -42,6 +42,7 @@ class Compositor;
+ } // namespace ui
+
+ namespace viz {
++class GpuDisplayProvider;
+ class GpuHostImpl;
+ class HostFrameSinkManager;
+ class HostGpuMemoryBufferManager;
+@@ -118,6 +119,8 @@ class COMPONENT_EXPORT(MOJO_CPP_BINDINGS) SyncCallRestrictions {
+ // For preventing frame swaps of wrong size during resize on Windows.
+ // (https://crbug.com/811945)
+ friend class ui::Compositor;
++ // For query of whether to use SoftwareOutputDevice or not.
++ friend class viz::GpuDisplayProvider;
+ // For calling sync mojo API to get cdm origin. The service and the client are
+ // running in the same process, so it won't block anything.
+ // TODO(159346933) Remove once the origin isolation logic is moved outside of
+diff --git services/viz/privileged/mojom/compositing/display_private.mojom services/viz/privileged/mojom/compositing/display_private.mojom
+index 83c153d99c1e2..7396a87b56a94 100644
+--- services/viz/privileged/mojom/compositing/display_private.mojom
++++ services/viz/privileged/mojom/compositing/display_private.mojom
+@@ -102,12 +102,14 @@ interface DisplayPrivate {
+ };
+
+ interface DisplayClient {
++ [Sync]
++ UseProxyOutputDevice() => (bool success);
++
+ [EnableIf=is_mac]
+ OnDisplayReceivedCALayerParams(gfx.mojom.CALayerParams ca_layer_params);
+
+ // Creates a LayeredWindowUpdater implementation to draw into a layered
+ // window.
+- [EnableIf=is_win]
+ CreateLayeredWindowUpdater(pending_receiver<LayeredWindowUpdater> receiver);
+
+ // Sends the created child window to the browser process so that it can be
+diff --git services/viz/privileged/mojom/compositing/layered_window_updater.mojom services/viz/privileged/mojom/compositing/layered_window_updater.mojom
+index 2f462f0deb5fc..695869b83cefa 100644
+--- services/viz/privileged/mojom/compositing/layered_window_updater.mojom
++++ services/viz/privileged/mojom/compositing/layered_window_updater.mojom
+@@ -26,5 +26,5 @@ interface LayeredWindowUpdater {
+ // Draws to the HWND by copying pixels from shared memory. Callback must be
+ // called after draw operation is complete to signal shared memory can be
+ // modified.
+- Draw() => ();
++ Draw(gfx.mojom.Rect damage_rect) => ();
+ };
+diff --git ui/compositor/compositor.h ui/compositor/compositor.h
+index 2d296b025ec17..a45c73aaa09b8 100644
+--- ui/compositor/compositor.h
++++ ui/compositor/compositor.h
+@@ -33,7 +33,9 @@
+ #include "components/viz/common/frame_sinks/begin_frame_args.h"
+ #include "components/viz/common/surfaces/frame_sink_id.h"
+ #include "components/viz/common/surfaces/subtree_capture_id.h"
++#include "components/viz/host/host_display_client.h"
+ #include "components/viz/host/host_frame_sink_client.h"
++#include "components/viz/service/display/software_output_device.h"
+ #include "mojo/public/cpp/bindings/associated_remote.h"
+ #include "mojo/public/cpp/bindings/pending_remote.h"
+ #include "services/viz/privileged/mojom/compositing/display_private.mojom.h"
+@@ -145,6 +147,14 @@ class COMPOSITOR_EXPORT ContextFactory {
+ virtual viz::HostFrameSinkManager* GetHostFrameSinkManager() = 0;
+ };
+
++class COMPOSITOR_EXPORT CompositorDelegate {
++ public:
++ virtual std::unique_ptr<viz::HostDisplayClient> CreateHostDisplayClient() = 0;
++
++ protected:
++ virtual ~CompositorDelegate() {}
++};
++
+ // Compositor object to take care of GPU painting.
+ // A Browser compositor object is responsible for generating the final
+ // displayable form of pixels comprising a single widget's contents. It draws an
+@@ -188,6 +198,9 @@ class COMPOSITOR_EXPORT Compositor : public base::PowerSuspendObserver,
+ // Schedules a redraw of the layer tree associated with this compositor.
+ void ScheduleDraw();
+
++ CompositorDelegate* delegate() const { return delegate_; }
++ void SetDelegate(CompositorDelegate* delegate) { delegate_ = delegate; }
++
+ // Sets the root of the layer tree drawn by this Compositor. The root layer
+ // must have no parent. The compositor's root layer is reset if the root layer
+ // is destroyed. NULL can be passed to reset the root layer, in which case the
+@@ -513,6 +526,8 @@ class COMPOSITOR_EXPORT Compositor : public base::PowerSuspendObserver,
+
+ std::unique_ptr<PendingBeginFrameArgs> pending_begin_frame_args_;
+
++ CompositorDelegate* delegate_ = nullptr;
++
+ // The root of the Layer tree drawn by this compositor.
+ raw_ptr<Layer> root_layer_ = nullptr;
+
diff --git a/patch/patches/web_contents_1257_1565.patch b/patch/patches/web_contents_1257_1565.patch
new file mode 100644
index 00000000..ed0809b1
--- /dev/null
+++ b/patch/patches/web_contents_1257_1565.patch
@@ -0,0 +1,145 @@
+diff --git content/browser/web_contents/web_contents_impl.cc content/browser/web_contents/web_contents_impl.cc
+index aea2d122faef0..df8c1858b6387 100644
+--- content/browser/web_contents/web_contents_impl.cc
++++ content/browser/web_contents/web_contents_impl.cc
+@@ -3174,6 +3174,12 @@ void WebContentsImpl::Init(const WebContents::CreateParams& params,
+ params.main_frame_name, GetOpener(), primary_main_frame_policy,
+ base::UnguessableToken::Create());
+
++ if (params.view && params.delegate_view) {
++ view_.reset(params.view);
++ render_view_host_delegate_view_ = params.delegate_view;
++ }
++
++ if (!view_) {
+ std::unique_ptr<WebContentsViewDelegate> delegate =
+ GetContentClient()->browser()->GetWebContentsViewDelegate(this);
+
+@@ -3184,6 +3190,7 @@ void WebContentsImpl::Init(const WebContents::CreateParams& params,
+ view_ = CreateWebContentsView(this, std::move(delegate),
+ &render_view_host_delegate_view_);
+ }
++ }
+ CHECK(render_view_host_delegate_view_);
+ CHECK(view_.get());
+
+@@ -3364,6 +3371,9 @@ void WebContentsImpl::RenderWidgetCreated(
+ OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::RenderWidgetCreated",
+ "render_widget_host", render_widget_host);
+ created_widgets_.insert(render_widget_host);
++
++ observers_.NotifyObservers(
++ &WebContentsObserver::RenderWidgetCreated, render_widget_host);
+ }
+
+ void WebContentsImpl::RenderWidgetDeleted(
+@@ -4095,6 +4105,15 @@ FrameTree* WebContentsImpl::CreateNewWindow(
+ create_params.picture_in_picture_options = *(params.pip_options);
+ }
+
++ if (delegate_) {
++ delegate_->GetCustomWebContentsView(this,
++ params.target_url,
++ render_process_id,
++ opener->GetRoutingID(),
++ &create_params.view,
++ &create_params.delegate_view);
++ }
++
+ // Check whether there is an available prerendered page for this navigation if
+ // this is not for guest. If it exists, take WebContents pre-created for
+ // hosting the prerendered page instead of creating new WebContents.
+@@ -7995,6 +8014,9 @@ void WebContentsImpl::SetFocusedFrame(FrameTreeNode* node,
+ // frames).
+ SetFocusedFrameTree(&node->frame_tree());
+ }
++
++ observers_.NotifyObservers(&WebContentsObserver::OnFrameFocused,
++ node->current_frame_host());
+ }
+
+ void WebContentsImpl::DidCallFocus() {
+diff --git content/public/browser/web_contents.h content/public/browser/web_contents.h
+index 5644b0efa9a3e..da63511c87213 100644
+--- content/public/browser/web_contents.h
++++ content/public/browser/web_contents.h
+@@ -95,10 +95,12 @@ class BrowserContext;
+ class BrowserPluginGuestDelegate;
+ class RenderFrameHost;
+ class RenderViewHost;
++class RenderViewHostDelegateView;
+ class RenderWidgetHostView;
+ class ScreenOrientationDelegate;
+ class SiteInstance;
+ class WebContentsDelegate;
++class WebContentsView;
+ class WebUI;
+ struct DropData;
+ struct MHTMLGenerationParams;
+@@ -241,6 +243,10 @@ class WebContents : public PageNavigator,
+ network::mojom::WebSandboxFlags starting_sandbox_flags =
+ network::mojom::WebSandboxFlags::kNone;
+
++ // Optionally specify the view and delegate view.
++ content::WebContentsView* view = nullptr;
++ content::RenderViewHostDelegateView* delegate_view = nullptr;
++
+ // Value used to set the last time the WebContents was made active, this is
+ // the value that'll be returned by GetLastActiveTime(). If this is left
+ // default initialized then the value is not passed on to the WebContents
+diff --git content/public/browser/web_contents_delegate.h content/public/browser/web_contents_delegate.h
+index 2717fd39b99c6..604d3b75160a4 100644
+--- content/public/browser/web_contents_delegate.h
++++ content/public/browser/web_contents_delegate.h
+@@ -58,9 +58,11 @@ class EyeDropperListener;
+ class FileSelectListener;
+ class JavaScriptDialogManager;
+ class RenderFrameHost;
++class RenderViewHostDelegateView;
+ class RenderWidgetHost;
+ class SessionStorageNamespace;
+ class SiteInstance;
++class WebContentsView;
+ struct ContextMenuParams;
+ struct DropData;
+ struct MediaPlayerWatchTime;
+@@ -342,6 +344,14 @@ class CONTENT_EXPORT WebContentsDelegate {
+ const StoragePartitionConfig& partition_config,
+ SessionStorageNamespace* session_storage_namespace);
+
++ virtual void GetCustomWebContentsView(
++ WebContents* web_contents,
++ const GURL& target_url,
++ int opener_render_process_id,
++ int opener_render_frame_id,
++ content::WebContentsView** view,
++ content::RenderViewHostDelegateView** delegate_view) {}
++
+ // Notifies the delegate about the creation of a new WebContents. This
+ // typically happens when popups are created.
+ virtual void WebContentsCreated(WebContents* source_contents,
+diff --git content/public/browser/web_contents_observer.h content/public/browser/web_contents_observer.h
+index d89d18e8d2509..9d7df1f8e7bbc 100644
+--- content/public/browser/web_contents_observer.h
++++ content/public/browser/web_contents_observer.h
+@@ -219,6 +219,9 @@ class CONTENT_EXPORT WebContentsObserver {
+ virtual void OnCaptureHandleConfigUpdate(
+ const blink::mojom::CaptureHandleConfig& config) {}
+
++ // This method is invoked when a RenderWidget is created.
++ virtual void RenderWidgetCreated(RenderWidgetHost* render_widget_host) {}
++
+ // This method is invoked when the `blink::WebView` of the current
+ // RenderViewHost is ready, e.g. because we recreated it after a crash.
+ virtual void RenderViewReady() {}
+@@ -800,6 +803,10 @@ class CONTENT_EXPORT WebContentsObserver {
+ // WebContents has gained/lost focus.
+ virtual void OnFocusChangedInPage(FocusedNodeDetails* details) {}
+
++ // Notification that |render_frame_host| for this WebContents has gained
++ // focus.
++ virtual void OnFrameFocused(RenderFrameHost* render_frame_host) {}
++
+ // Notifies that the manifest URL for the main frame changed to
+ // |manifest_url|. This will be invoked when a document with a manifest loads
+ // or when the manifest URL changes (possibly to nothing). It is not invoked
diff --git a/patch/patches/web_url_loader_cancel_1617042.patch b/patch/patches/web_url_loader_cancel_1617042.patch
new file mode 100644
index 00000000..e41f0b6d
--- /dev/null
+++ b/patch/patches/web_url_loader_cancel_1617042.patch
@@ -0,0 +1,21 @@
+diff --git third_party/blink/public/platform/web_url_loader.h third_party/blink/public/platform/web_url_loader.h
+index 31054cf2795a4..d5082be28ea54 100644
+--- third_party/blink/public/platform/web_url_loader.h
++++ third_party/blink/public/platform/web_url_loader.h
+@@ -143,12 +143,14 @@ class BLINK_PLATFORM_EXPORT WebURLLoader {
+ void SetResourceRequestSenderForTesting(
+ std::unique_ptr<WebResourceRequestSender> resource_request_sender);
+
++ // Cancels an asynchronous load. This will appear as a load error to
++ // the client.
++ void Cancel();
++
+ private:
+ class Context;
+ class RequestPeerImpl;
+
+- void Cancel();
+-
+ scoped_refptr<Context> context_;
+ };
+
diff --git a/patch/patches/webkit_plugin_info_2015.patch b/patch/patches/webkit_plugin_info_2015.patch
new file mode 100644
index 00000000..c56ca685
--- /dev/null
+++ b/patch/patches/webkit_plugin_info_2015.patch
@@ -0,0 +1,44 @@
+diff --git third_party/blink/public/platform/platform.h third_party/blink/public/platform/platform.h
+index b2de9ae25b7ac..06b34b5a120cf 100644
+--- third_party/blink/public/platform/platform.h
++++ third_party/blink/public/platform/platform.h
+@@ -799,6 +799,11 @@ class BLINK_PLATFORM_EXPORT Platform {
+ uint64_t private_memory_footprint_bytes) {}
+ #endif
+
++ // DevTools ------------------------------------------------------------
++
++ virtual void DevToolsAgentAttached() {}
++ virtual void DevToolsAgentDetached() {}
++
+ private:
+ static void InitializeMainThreadCommon(
+ Platform* platform,
+diff --git third_party/blink/renderer/core/inspector/devtools_session.cc third_party/blink/renderer/core/inspector/devtools_session.cc
+index 01c2f360adbb0..92ea44b41820e 100644
+--- third_party/blink/renderer/core/inspector/devtools_session.cc
++++ third_party/blink/renderer/core/inspector/devtools_session.cc
+@@ -10,6 +10,7 @@
+
+ #include "base/task/sequenced_task_runner.h"
+ #include "base/task/single_thread_task_runner.h"
++#include "third_party/blink/public/platform/platform.h"
+ #include "third_party/blink/renderer/bindings/core/v8/script_controller.h"
+ #include "third_party/blink/renderer/core/frame/local_frame.h"
+ #include "third_party/blink/renderer/core/inspector/devtools_agent.h"
+@@ -165,6 +166,7 @@ DevToolsSession::DevToolsSession(
+ for (wtf_size_t i = 0; i < agents_.size(); i++)
+ agents_[i]->Restore();
+ }
++ Platform::Current()->DevToolsAgentAttached();
+ }
+
+ DevToolsSession::~DevToolsSession() {
+@@ -210,6 +212,7 @@ void DevToolsSession::Detach() {
+ agents_.clear();
+ v8_session_.reset();
+ agent_->client_->DebuggerTaskFinished();
++ Platform::Current()->DevToolsAgentDetached();
+ }
+
+ void DevToolsSession::DetachFromV8() {
diff --git a/patch/patches/webkit_popups.patch b/patch/patches/webkit_popups.patch
new file mode 100644
index 00000000..32fe6777
--- /dev/null
+++ b/patch/patches/webkit_popups.patch
@@ -0,0 +1,76 @@
+diff --git third_party/blink/public/web/web_view.h third_party/blink/public/web/web_view.h
+index c8655d9270b81..d11450d22123a 100644
+--- third_party/blink/public/web/web_view.h
++++ third_party/blink/public/web/web_view.h
+@@ -340,6 +340,7 @@ class BLINK_EXPORT WebView {
+
+ // Sets whether select popup menus should be rendered by the browser.
+ static void SetUseExternalPopupMenus(bool);
++ virtual void SetUseExternalPopupMenusThisInstance(bool) = 0;
+
+ // Cancels and hides the current popup (datetime, select...) if any.
+ virtual void CancelPagePopup() = 0;
+diff --git third_party/blink/renderer/core/exported/web_view_impl.cc third_party/blink/renderer/core/exported/web_view_impl.cc
+index 9ce7b0b20d0e9..52b7713d3d250 100644
+--- third_party/blink/renderer/core/exported/web_view_impl.cc
++++ third_party/blink/renderer/core/exported/web_view_impl.cc
+@@ -249,8 +249,13 @@ void WebView::SetUseExternalPopupMenus(bool use_external_popup_menus) {
+ g_should_use_external_popup_menus = use_external_popup_menus;
+ }
+
+-bool WebViewImpl::UseExternalPopupMenus() {
+- return g_should_use_external_popup_menus;
++void WebViewImpl::SetUseExternalPopupMenusThisInstance(
++ bool use_external_popup_menus) {
++ should_use_external_popup_menus_ = use_external_popup_menus;
++}
++
++bool WebViewImpl::UseExternalPopupMenus() const {
++ return should_use_external_popup_menus_;
+ }
+
+ namespace {
+@@ -563,6 +568,7 @@ WebViewImpl::WebViewImpl(
+ chrome_client_(MakeGarbageCollected<ChromeClientImpl>(this)),
+ minimum_zoom_level_(PageZoomFactorToZoomLevel(kMinimumPageZoomFactor)),
+ maximum_zoom_level_(PageZoomFactorToZoomLevel(kMaximumPageZoomFactor)),
++ should_use_external_popup_menus_(g_should_use_external_popup_menus),
+ does_composite_(does_composite),
+ fullscreen_controller_(std::make_unique<FullscreenController>(this)),
+ page_base_background_color_(
+diff --git third_party/blink/renderer/core/exported/web_view_impl.h third_party/blink/renderer/core/exported/web_view_impl.h
+index ac623b8bd6c06..3e0bd1dd8ce3b 100644
+--- third_party/blink/renderer/core/exported/web_view_impl.h
++++ third_party/blink/renderer/core/exported/web_view_impl.h
+@@ -134,7 +134,8 @@ class CORE_EXPORT WebViewImpl final : public WebView,
+ static HashSet<WebViewImpl*>& AllInstances();
+ // Returns true if popup menus should be rendered by the browser, false if
+ // they should be rendered by WebKit (which is the default).
+- static bool UseExternalPopupMenus();
++ void SetUseExternalPopupMenusThisInstance(bool) override;
++ bool UseExternalPopupMenus() const;
+
+ // Returns whether frames under this WebView are backed by a compositor.
+ bool does_composite() const { return does_composite_; }
+@@ -840,6 +841,8 @@ class CORE_EXPORT WebViewImpl final : public WebView,
+ float fake_page_scale_animation_page_scale_factor_ = 0.f;
+ bool fake_page_scale_animation_use_anchor_ = false;
+
++ bool should_use_external_popup_menus_;
++
+ float compositor_device_scale_factor_override_ = 0.f;
+ gfx::Transform device_emulation_transform_;
+
+diff --git third_party/blink/renderer/core/page/chrome_client_impl.cc third_party/blink/renderer/core/page/chrome_client_impl.cc
+index 77260f7c32736..3958ea3f812c2 100644
+--- third_party/blink/renderer/core/page/chrome_client_impl.cc
++++ third_party/blink/renderer/core/page/chrome_client_impl.cc
+@@ -913,7 +913,7 @@ bool ChromeClientImpl::HasOpenedPopup() const {
+ PopupMenu* ChromeClientImpl::OpenPopupMenu(LocalFrame& frame,
+ HTMLSelectElement& select) {
+ NotifyPopupOpeningObservers();
+- if (WebViewImpl::UseExternalPopupMenus())
++ if (web_view_->UseExternalPopupMenus())
+ return MakeGarbageCollected<ExternalPopupMenu>(frame, select);
+
+ DCHECK(RuntimeEnabledFeatures::PagePopupEnabled());
diff --git a/patch/patches/webkit_runtime_enabled_features.patch b/patch/patches/webkit_runtime_enabled_features.patch
new file mode 100644
index 00000000..33e7cc6e
--- /dev/null
+++ b/patch/patches/webkit_runtime_enabled_features.patch
@@ -0,0 +1,21 @@
+diff --git third_party/blink/renderer/build/scripts/templates/runtime_enabled_features.h.tmpl third_party/blink/renderer/build/scripts/templates/runtime_enabled_features.h.tmpl
+index 32ca8183f6501..fb38785835fa0 100644
+--- third_party/blink/renderer/build/scripts/templates/runtime_enabled_features.h.tmpl
++++ third_party/blink/renderer/build/scripts/templates/runtime_enabled_features.h.tmpl
+@@ -13,6 +13,8 @@
+ #include "third_party/blink/renderer/platform/platform_export.h"
+ #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+
++class AlloyContentRendererClient;
++
+ #define ASSERT_ORIGIN_TRIAL(feature) \
+ static_assert(std::is_same<decltype(::blink::RuntimeEnabledFeatures:: \
+ feature##EnabledByRuntimeFlag()), \
+@@ -117,6 +119,7 @@ class PLATFORM_EXPORT RuntimeEnabledFeatures : public RuntimeEnabledFeaturesBase
+ // protected section of RuntimeEnabledFeaturesBase. Normally, unit tests
+ // should use the ScopedFeatureNameForTest classes defined in
+ // platform/testing/runtime_enabled_features_test_helpers.h.
++ friend class ::AlloyContentRendererClient;
+ friend class DevToolsEmulator;
+ friend class InternalRuntimeFlags;
+ friend class V8ContextSnapshotImpl;
diff --git a/patch/patches/webui_2037.patch b/patch/patches/webui_2037.patch
new file mode 100644
index 00000000..610bebe9
--- /dev/null
+++ b/patch/patches/webui_2037.patch
@@ -0,0 +1,76 @@
+diff --git chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.cc chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.cc
+index 22bf50617329b..40dfc6cc75df0 100644
+--- chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.cc
++++ chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.cc
+@@ -19,10 +19,12 @@
+ #include "base/strings/stringprintf.h"
+ #include "base/system/sys_info.h"
+ #include "base/task/thread_pool.h"
++#include "base/threading/thread_restrictions.h"
+ #include "base/time/time.h"
+ #include "build/branding_buildflags.h"
+ #include "build/build_config.h"
+ #include "build/chromeos_buildflags.h"
++#include "cef/libcef/features/runtime.h"
+ #include "chrome/browser/browser_process.h"
+ #include "chrome/browser/extensions/chrome_content_browser_client_extensions_part.h"
+ #include "chrome/browser/google/google_brand.h"
+@@ -398,7 +400,11 @@ void ChromeInternalLogSource::Fetch(SysLogsSourceCallback callback) {
+ response->emplace(kOsVersionTag, os_version);
+ #endif
+
+- PopulateSyncLogs(response.get());
++ if (!cef::IsAlloyRuntimeEnabled()) {
++ // Avoid loading ProfileSyncServiceFactory which depends on a lot of
++ // unnecessary Chrome-specific factories.
++ PopulateSyncLogs(response.get());
++ }
+ PopulateExtensionInfoLogs(response.get());
+ PopulatePowerApiLogs(response.get());
+ #if BUILDFLAG(IS_WIN)
+@@ -472,8 +478,12 @@ void ChromeInternalLogSource::PopulateExtensionInfoLogs(
+ if (!profile)
+ return;
+
++ // May be nullptr if using CEF Alloy with extensions disabled.
+ extensions::ExtensionRegistry* extension_registry =
+ extensions::ExtensionRegistry::Get(profile);
++ if (!extension_registry)
++ return;
++
+ std::string extensions_list;
+ for (const scoped_refptr<const extensions::Extension>& extension :
+ extension_registry->enabled_extensions()) {
+@@ -577,6 +587,8 @@ void ChromeInternalLogSource::PopulateOnboardingTime(
+ #if BUILDFLAG(IS_WIN)
+ void ChromeInternalLogSource::PopulateUsbKeyboardDetected(
+ SystemLogsResponse* response) {
++ // The below call may result in some DLLs being loaded.
++ base::ScopedAllowBlockingForTesting allow_blocking;
+ std::string reason;
+ bool result =
+ base::win::IsKeyboardPresentOnSlate(ui::GetHiddenWindow(), &reason);
+diff --git chrome/browser/memory_details.cc chrome/browser/memory_details.cc
+index 2565fae8b1433..9ca16abf99c92 100644
+--- chrome/browser/memory_details.cc
++++ chrome/browser/memory_details.cc
+@@ -294,8 +294,11 @@ void MemoryDetails::CollectChildInfoOnUIThread() {
+ if (render_process_host) {
+ content::BrowserContext* context =
+ render_process_host->GetBrowserContext();
++
++ // May be nullptr if using CEF Alloy with extensions disabled.
+ extensions::ExtensionRegistry* extension_registry =
+ extensions::ExtensionRegistry::Get(context);
++ if (extension_registry) {
+ extension_set = &extension_registry->enabled_extensions();
+ extensions::ProcessMap* process_map =
+ extensions::ProcessMap::Get(context);
+@@ -311,6 +314,7 @@ void MemoryDetails::CollectChildInfoOnUIThread() {
+ break;
+ }
+ }
++ }
+ }
+ #endif
+
diff --git a/patch/patches/win_cpp17_msvc_sandbox_2819.patch b/patch/patches/win_cpp17_msvc_sandbox_2819.patch
new file mode 100644
index 00000000..6361d3f7
--- /dev/null
+++ b/patch/patches/win_cpp17_msvc_sandbox_2819.patch
@@ -0,0 +1,28 @@
+diff --git base/third_party/double_conversion/BUILD.gn base/third_party/double_conversion/BUILD.gn
+index 8380f58d995bc..c0755bf9870b4 100644
+--- base/third_party/double_conversion/BUILD.gn
++++ base/third_party/double_conversion/BUILD.gn
+@@ -9,6 +9,11 @@ config("config") {
+ "-Wno-unused-const-variable",
+ "-Wno-unused-function",
+ ]
++
++ # Build as C++17 to avoid export of templates that should be inlined.
++ if (is_win) {
++ cflags_cc = [ "/std:c++17" ]
++ }
+ }
+
+ static_library("double_conversion") {
+diff --git base/win/BUILD.gn base/win/BUILD.gn
+index d915a9320750c..5661652c9b2da 100644
+--- base/win/BUILD.gn
++++ base/win/BUILD.gn
+@@ -33,4 +33,7 @@ static_library("pe_image") {
+ "pe_image.cc",
+ "pe_image.h",
+ ]
++
++ # Build as C++17 to avoid export of templates that should be inlined.
++ cflags_cc = [ "/std:c++17" ]
+ }
diff --git a/patch/patches/win_power_monitor_4219163.patch b/patch/patches/win_power_monitor_4219163.patch
new file mode 100644
index 00000000..c48a35a8
--- /dev/null
+++ b/patch/patches/win_power_monitor_4219163.patch
@@ -0,0 +1,22 @@
+diff --git base/power_monitor/battery_level_provider_win.cc base/power_monitor/battery_level_provider_win.cc
+index 1e9f88154adc7..3c3a4ee7cd511 100644
+--- base/power_monitor/battery_level_provider_win.cc
++++ base/power_monitor/battery_level_provider_win.cc
+@@ -18,6 +18,7 @@
+
+ #include "base/memory/weak_ptr.h"
+ #include "base/metrics/histogram_macros.h"
++#include "base/numerics/safe_conversions.h"
+ #include "base/task/sequenced_task_runner.h"
+ #include "base/task/task_traits.h"
+ #include "base/task/thread_pool.h"
+@@ -134,7 +135,8 @@ absl::optional<uint32_t> GetBatteryBatteryDischargeGranularity(
+ if (!success)
+ return absl::nullopt;
+
+- size_t nb_elements = bytes_returned / sizeof(BATTERY_REPORTING_SCALE);
++ ptrdiff_t nb_elements = base::checked_cast<ptrdiff_t>(
++ bytes_returned / sizeof(BATTERY_REPORTING_SCALE));
+ if (!nb_elements)
+ return absl::nullopt;
+
diff --git a/patch/patches/win_sandbox_3210.patch b/patch/patches/win_sandbox_3210.patch
new file mode 100644
index 00000000..705428d7
--- /dev/null
+++ b/patch/patches/win_sandbox_3210.patch
@@ -0,0 +1,18 @@
+diff --git sandbox/policy/win/sandbox_win.cc sandbox/policy/win/sandbox_win.cc
+index cf16e2e25fec6..541d3eca56b92 100644
+--- sandbox/policy/win/sandbox_win.cc
++++ sandbox/policy/win/sandbox_win.cc
+@@ -1017,6 +1017,13 @@ ResultCode SandboxWin::StartSandboxedProcess(
+ const base::HandlesToInheritVector& handles_to_inherit,
+ SandboxDelegate* delegate,
+ base::Process* process) {
++ // Will be nullptr if SandboxInterfaceInfo was not initialized by the CEF
++ // client, meaning that the sandbox is implicitly disabled.
++ if (!g_broker_services) {
++ return LaunchWithoutSandbox(cmd_line, handles_to_inherit, delegate,
++ process);
++ }
++
+ const base::ElapsedTimer timer;
+
+ // Avoid making a policy if we won't use it.
diff --git a/patch/patches/win_shell_dialogs_3294.patch b/patch/patches/win_shell_dialogs_3294.patch
new file mode 100644
index 00000000..236c0f59
--- /dev/null
+++ b/patch/patches/win_shell_dialogs_3294.patch
@@ -0,0 +1,29 @@
+diff --git ui/shell_dialogs/base_shell_dialog_win.cc ui/shell_dialogs/base_shell_dialog_win.cc
+index 138167d4c0105..81562ffdd2162 100644
+--- ui/shell_dialogs/base_shell_dialog_win.cc
++++ ui/shell_dialogs/base_shell_dialog_win.cc
+@@ -59,11 +59,15 @@ BaseShellDialogImpl::Owners& BaseShellDialogImpl::GetOwners() {
+
+ // static
+ void BaseShellDialogImpl::DisableOwner(HWND owner) {
++ if (owner)
++ owner = GetAncestor(owner, GA_ROOT);
+ SetOwnerEnabled(owner, false);
+ }
+
+ std::unique_ptr<BaseShellDialogImpl::RunState> BaseShellDialogImpl::BeginRun(
+ HWND owner) {
++ if (owner)
++ owner = GetAncestor(owner, GA_ROOT);
+ // Cannot run a modal shell dialog if one is already running for this owner.
+ DCHECK(!IsRunningDialogForOwner(owner));
+ // The owner must be a top level window, otherwise we could end up with two
+@@ -89,6 +93,8 @@ void BaseShellDialogImpl::EndRun(std::unique_ptr<RunState> run_state) {
+ }
+
+ bool BaseShellDialogImpl::IsRunningDialogForOwner(HWND owner) const {
++ if (owner)
++ owner = GetAncestor(owner, GA_ROOT);
+ return (owner && GetOwners().find(owner) != GetOwners().end());
+ }
+
diff --git a/tests/cefclient/CMakeLists.txt.in b/tests/cefclient/CMakeLists.txt.in
new file mode 100644
index 00000000..84396999
--- /dev/null
+++ b/tests/cefclient/CMakeLists.txt.in
@@ -0,0 +1,318 @@
+# Copyright (c) 2014 The Chromium Embedded Framework Authors. All rights
+# reserved. Use of this source code is governed by a BSD-style license that
+# can be found in the LICENSE file.
+
+#
+# Source files.
+#
+
+# cefclient browser sources.
+{{
+ 'prefix': 'cefclient_browser',
+ 'set': 'CEFCLIENT_BROWSER_SRCS',
+ 'includes': [
+ 'shared_sources_browser',
+ 'cefclient_sources_browser',
+ ],
+}}
+
+# cefclient common sources.
+{{
+ 'prefix': 'cefclient_common',
+ 'set': 'CEFCLIENT_COMMON_SRCS',
+ 'includes': [
+ 'shared_sources_common',
+ 'cefclient_sources_common',
+ ],
+}}
+
+# cefclient renderer sources.
+{{
+ 'prefix': 'cefclient_renderer',
+ 'set': 'CEFCLIENT_RENDERER_SRCS',
+ 'includes': [
+ 'shared_sources_renderer',
+ 'cefclient_sources_renderer',
+ ],
+}}
+
+#cefclient Linux sources
+{{
+ 'prefix': 'cefclient_linux',
+ 'set': 'CEFCLIENT_LINUX_SRCS',
+ 'includes': [
+ 'shared_sources_linux',
+ 'cefclient_sources_linux',
+ ],
+}}
+
+#cefclient Mac OS X sources
+{{
+ 'prefix': 'cefclient_macosx',
+ 'set': 'CEFCLIENT_MAC_SRCS',
+ 'includes': [
+ 'shared_sources_mac',
+ 'cefclient_sources_mac',
+ ],
+}}
+
+# cefclient Mac OS X helper sources.
+{{
+ 'prefix': 'cefclient_helper',
+ 'set': 'CEFCLIENT_MAC_HELPER_SRCS',
+ 'includes': [
+ 'shared_sources_mac_helper',
+ ],
+}}
+
+#cefclient Windows sources
+{{
+ 'prefix': 'cefclient_windows',
+ 'set': 'CEFCLIENT_WINDOWS_SRCS',
+ 'includes': [
+ 'shared_sources_win',
+ 'cefclient_sources_win',
+ ],
+}}
+
+# cefclient resources.
+{{
+ 'prefix': 'cefclient_resources',
+ 'set': 'CEFCLIENT_RESOURCES_SRCS',
+ 'includes': [
+ 'shared_sources_resources',
+ 'cefclient_bundle_resources_mac:MAC',
+ 'cefclient_sources_resources',
+ 'cefclient_sources_resources_extensions_set_page_color',
+ ],
+}}
+
+
+#
+# Shared configuration.
+#
+
+# Target executable names.
+set(CEF_TARGET "cefclient")
+if(OS_MAC)
+ set(CEF_HELPER_TARGET "cefclient_Helper")
+ set(CEF_HELPER_OUTPUT_NAME "cefclient Helper")
+else()
+ # Logical target used to link the libcef library.
+ ADD_LOGICAL_TARGET("libcef_lib" "${CEF_LIB_DEBUG}" "${CEF_LIB_RELEASE}")
+endif()
+
+# Determine the target output directory.
+SET_CEF_TARGET_OUT_DIR()
+
+
+#
+# Linux configuration.
+#
+
+if(OS_LINUX)
+ # All sources required by the "cefclient" target. Generates an executable that
+ # is used for all processes.
+ set(CEFCLIENT_SRCS
+ ${CEFCLIENT_BROWSER_SRCS}
+ ${CEFCLIENT_COMMON_SRCS}
+ ${CEFCLIENT_RENDERER_SRCS}
+ ${CEFCLIENT_RESOURCES_SRCS}
+ ${CEFCLIENT_LINUX_SRCS}
+ )
+
+ # Find required libraries and update compiler/linker variables.
+ FIND_LINUX_LIBRARIES("gmodule-2.0 gtk+-3.0 gthread-2.0 gtk+-unix-print-3.0 xi")
+
+ # Executable target.
+ add_executable(${CEF_TARGET} ${CEFCLIENT_SRCS})
+ SET_EXECUTABLE_TARGET_PROPERTIES(${CEF_TARGET})
+ add_dependencies(${CEF_TARGET} libcef_dll_wrapper)
+ target_link_libraries(${CEF_TARGET} libcef_lib libcef_dll_wrapper "GL" ${CEF_STANDARD_LIBS})
+
+ # Set rpath so that libraries can be placed next to the executable.
+ set_target_properties(${CEF_TARGET} PROPERTIES INSTALL_RPATH "$ORIGIN")
+ set_target_properties(${CEF_TARGET} PROPERTIES BUILD_WITH_INSTALL_RPATH TRUE)
+ set_target_properties(${CEF_TARGET} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CEF_TARGET_OUT_DIR})
+
+ # We don't call deprecated GTK functions, and they can cause build failures, so disable them.
+ add_definitions("-DGTK_DISABLE_DEPRECATED")
+
+ # Copy CEF binary and resource files to the target output directory.
+ COPY_FILES("${CEF_TARGET}" "${CEF_BINARY_FILES}" "${CEF_BINARY_DIR}" "${CEF_TARGET_OUT_DIR}")
+ COPY_FILES("${CEF_TARGET}" "${CEF_RESOURCE_FILES}" "${CEF_RESOURCE_DIR}" "${CEF_TARGET_OUT_DIR}")
+
+ # Copy cefclient resource files to the target output directory.
+ COPY_FILES("${CEF_TARGET}" "${CEFCLIENT_RESOURCES_SRCS}" "${CMAKE_CURRENT_SOURCE_DIR}" "${CEF_TARGET_OUT_DIR}/cefclient_files")
+
+ # Set SUID permissions on the chrome-sandbox target.
+ SET_LINUX_SUID_PERMISSIONS("${CEF_TARGET}" "${CEF_TARGET_OUT_DIR}/chrome-sandbox")
+endif()
+
+
+#
+# Mac OS X configuration.
+#
+
+if(OS_MAC)
+ option(OPTION_USE_ARC "Build with ARC (automatic Reference Counting) on macOS." ON)
+ if(OPTION_USE_ARC)
+ list(APPEND CEF_COMPILER_FLAGS
+ -fobjc-arc
+ )
+ set_target_properties(${target} PROPERTIES
+ CLANG_ENABLE_OBJC_ARC "YES"
+ )
+ endif()
+
+ # All sources required by the "cefclient" target. Generates an app bundle that
+ # is used only for the browser process.
+ set(CEFCLIENT_SRCS
+ ${CEFCLIENT_BROWSER_SRCS}
+ ${CEFCLIENT_COMMON_SRCS}
+ ${CEFCLIENT_RESOURCES_SRCS}
+ ${CEFCLIENT_MAC_SRCS}
+ )
+
+ # All sources required by the "cefclient Helper" target. Generates an app
+ # bundle that is used only for non-browser processes.
+ set(CEFCLIENT_HELPER_SRCS
+ ${CEFCLIENT_COMMON_SRCS}
+ ${CEFCLIENT_RENDERER_SRCS}
+ ${CEFCLIENT_MAC_HELPER_SRCS}
+ )
+
+ # Output path for the main app bundle.
+ set(CEF_APP "${CEF_TARGET_OUT_DIR}/${CEF_TARGET}.app")
+
+ # Variables referenced from the main Info.plist file.
+ set(EXECUTABLE_NAME "${CEF_TARGET}")
+ set(PRODUCT_NAME "${CEF_TARGET}")
+
+ if(USE_SANDBOX)
+ # Logical target used to link the cef_sandbox library.
+ ADD_LOGICAL_TARGET("cef_sandbox_lib" "${CEF_SANDBOX_LIB_DEBUG}" "${CEF_SANDBOX_LIB_RELEASE}")
+ endif()
+
+ # Main app bundle target.
+ add_executable(${CEF_TARGET} MACOSX_BUNDLE ${CEFCLIENT_RESOURCES_SRCS} ${CEFCLIENT_SRCS})
+ SET_EXECUTABLE_TARGET_PROPERTIES(${CEF_TARGET})
+ add_dependencies(${CEF_TARGET} libcef_dll_wrapper)
+ target_link_libraries(${CEF_TARGET} libcef_dll_wrapper ${CEF_STANDARD_LIBS} "-framework OpenGL")
+ set_target_properties(${CEF_TARGET} PROPERTIES
+ MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/resources/mac/Info.plist
+ )
+
+ # Copy the CEF framework into the Frameworks directory.
+ add_custom_command(
+ TARGET ${CEF_TARGET}
+ POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy_directory
+ "${CEF_BINARY_DIR}/Chromium Embedded Framework.framework"
+ "${CEF_APP}/Contents/Frameworks/Chromium Embedded Framework.framework"
+ VERBATIM
+ )
+
+ # Create the multiple Helper app bundle targets.
+ foreach(_suffix_list ${CEF_HELPER_APP_SUFFIXES})
+ # Convert to a list and extract the suffix values.
+ string(REPLACE ":" ";" _suffix_list ${_suffix_list})
+ list(GET _suffix_list 0 _name_suffix)
+ list(GET _suffix_list 1 _target_suffix)
+ list(GET _suffix_list 2 _plist_suffix)
+
+ # Define Helper target and output names.
+ set(_helper_target "${CEF_HELPER_TARGET}${_target_suffix}")
+ set(_helper_output_name "${CEF_HELPER_OUTPUT_NAME}${_name_suffix}")
+
+ # Create Helper-specific variants of the helper-Info.plist file. Do this
+ # manually because the configure_file command (which is executed as part of
+ # MACOSX_BUNDLE_INFO_PLIST) uses global env variables and would insert the
+ # wrong values with multiple targets.
+ set(_helper_info_plist "${CMAKE_CURRENT_BINARY_DIR}/helper-Info${_target_suffix}.plist")
+ file(READ "${CMAKE_CURRENT_SOURCE_DIR}/resources/mac/helper-Info.plist" _plist_contents)
+ string(REPLACE "\${EXECUTABLE_NAME}" "${_helper_output_name}" _plist_contents ${_plist_contents})
+ string(REPLACE "\${PRODUCT_NAME}" "${_helper_output_name}" _plist_contents ${_plist_contents})
+ string(REPLACE "\${BUNDLE_ID_SUFFIX}" "${_plist_suffix}" _plist_contents ${_plist_contents})
+ file(WRITE ${_helper_info_plist} ${_plist_contents})
+
+ # Create Helper executable target.
+ add_executable(${_helper_target} MACOSX_BUNDLE ${CEFCLIENT_HELPER_SRCS})
+ SET_EXECUTABLE_TARGET_PROPERTIES(${_helper_target})
+ add_dependencies(${_helper_target} libcef_dll_wrapper)
+ target_link_libraries(${_helper_target} libcef_dll_wrapper ${CEF_STANDARD_LIBS})
+ set_target_properties(${_helper_target} PROPERTIES
+ MACOSX_BUNDLE_INFO_PLIST ${_helper_info_plist}
+ OUTPUT_NAME ${_helper_output_name}
+ )
+
+ if(USE_SANDBOX)
+ target_link_libraries(${_helper_target} cef_sandbox_lib)
+ endif()
+
+ # Add the Helper as a dependency of the main executable target.
+ add_dependencies(${CEF_TARGET} "${_helper_target}")
+
+ # Copy the Helper app bundle into the Frameworks directory.
+ add_custom_command(
+ TARGET ${CEF_TARGET}
+ POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy_directory
+ "${CEF_TARGET_OUT_DIR}/${_helper_output_name}.app"
+ "${CEF_APP}/Contents/Frameworks/${_helper_output_name}.app"
+ VERBATIM
+ )
+ endforeach()
+
+ # Manually process and copy over resource files.
+ # The Xcode generator can support this via the set_target_properties RESOURCE
+ # directive but that doesn't properly handle nested resource directories.
+ # Remove these prefixes from input file paths.
+ set(PREFIXES
+ "resources/mac/"
+ "resources/"
+ "../shared/resources/"
+ )
+ COPY_MAC_RESOURCES("${CEFCLIENT_RESOURCES_SRCS}" "${PREFIXES}" "${CEF_TARGET}" "${CMAKE_CURRENT_SOURCE_DIR}" "${CEF_APP}")
+endif()
+
+
+#
+# Windows configuration.
+#
+
+if(OS_WINDOWS)
+ # All sources required by the "cefclient" target. Generates an executable that
+ # is used for all processes.
+ set(CEFCLIENT_SRCS
+ ${CEFCLIENT_BROWSER_SRCS}
+ ${CEFCLIENT_COMMON_SRCS}
+ ${CEFCLIENT_RENDERER_SRCS}
+ ${CEFCLIENT_RESOURCES_SRCS}
+ ${CEFCLIENT_WINDOWS_SRCS}
+ )
+
+ # Executable target.
+ add_executable(${CEF_TARGET} WIN32 ${CEFCLIENT_SRCS})
+ SET_EXECUTABLE_TARGET_PROPERTIES(${CEF_TARGET})
+ add_dependencies(${CEF_TARGET} libcef_dll_wrapper)
+ target_link_libraries(${CEF_TARGET} libcef_lib libcef_dll_wrapper ${CEF_STANDARD_LIBS} d3d11.lib glu32.lib imm32.lib opengl32.lib)
+
+ if(USE_ATL)
+ # Required by VS2013 to link accessibility API functions.
+ target_link_libraries(${CEF_TARGET} oleacc.lib)
+ endif()
+
+ if(USE_SANDBOX)
+ # Logical target used to link the cef_sandbox library.
+ ADD_LOGICAL_TARGET("cef_sandbox_lib" "${CEF_SANDBOX_LIB_DEBUG}" "${CEF_SANDBOX_LIB_RELEASE}")
+ target_link_libraries(${CEF_TARGET} cef_sandbox_lib ${CEF_SANDBOX_STANDARD_LIBS})
+ endif()
+
+ # Add the custom manifest files to the executable.
+ ADD_WINDOWS_MANIFEST("${CMAKE_CURRENT_SOURCE_DIR}/resources/win" "${CEF_TARGET}" "exe")
+
+ # Copy CEF binary and resource files to the target output directory.
+ COPY_FILES("${CEF_TARGET}" "${CEF_BINARY_FILES}" "${CEF_BINARY_DIR}" "${CEF_TARGET_OUT_DIR}")
+ COPY_FILES("${CEF_TARGET}" "${CEF_RESOURCE_FILES}" "${CEF_RESOURCE_DIR}" "${CEF_TARGET_OUT_DIR}")
+endif()
diff --git a/tests/cefclient/browser/binding_test.cc b/tests/cefclient/browser/binding_test.cc
new file mode 100644
index 00000000..0dfdc775
--- /dev/null
+++ b/tests/cefclient/browser/binding_test.cc
@@ -0,0 +1,58 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/binding_test.h"
+
+#include <algorithm>
+#include <string>
+
+#include "tests/cefclient/browser/test_runner.h"
+
+namespace client {
+namespace binding_test {
+
+namespace {
+
+const char kTestUrlPath[] = "/binding";
+const char kTestMessageName[] = "BindingTest";
+
+// Handle messages in the browser process.
+class Handler : public CefMessageRouterBrowserSide::Handler {
+ public:
+ Handler() {}
+
+ // Called due to cefQuery execution in binding.html.
+ virtual bool OnQuery(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int64 query_id,
+ const CefString& request,
+ bool persistent,
+ CefRefPtr<Callback> callback) override {
+ // Only handle messages from the test URL.
+ const std::string& url = frame->GetURL();
+ if (!test_runner::IsTestURL(url, kTestUrlPath)) {
+ return false;
+ }
+
+ const std::string& message_name = request;
+ if (message_name.find(kTestMessageName) == 0) {
+ // Reverse the string and return.
+ std::string result = message_name.substr(sizeof(kTestMessageName));
+ std::reverse(result.begin(), result.end());
+ callback->Success(result);
+ return true;
+ }
+
+ return false;
+ }
+};
+
+} // namespace
+
+void CreateMessageHandlers(test_runner::MessageHandlerSet& handlers) {
+ handlers.insert(new Handler());
+}
+
+} // namespace binding_test
+} // namespace client
diff --git a/tests/cefclient/browser/binding_test.h b/tests/cefclient/browser/binding_test.h
new file mode 100644
index 00000000..96926945
--- /dev/null
+++ b/tests/cefclient/browser/binding_test.h
@@ -0,0 +1,20 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_BINDING_TEST_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_BINDING_TEST_H_
+#pragma once
+
+#include "tests/cefclient/browser/test_runner.h"
+
+namespace client {
+namespace binding_test {
+
+// Create message handlers. Called from test_runner.cc.
+void CreateMessageHandlers(test_runner::MessageHandlerSet& handlers);
+
+} // namespace binding_test
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_BINDING_TEST_H_
diff --git a/tests/cefclient/browser/browser_window.cc b/tests/cefclient/browser/browser_window.cc
new file mode 100644
index 00000000..355620c3
--- /dev/null
+++ b/tests/cefclient/browser/browser_window.cc
@@ -0,0 +1,96 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/browser_window.h"
+
+#include "include/base/cef_callback.h"
+#include "tests/shared/browser/main_message_loop.h"
+
+namespace client {
+
+BrowserWindow::BrowserWindow(Delegate* delegate)
+ : delegate_(delegate), is_closing_(false) {
+ DCHECK(delegate_);
+}
+
+void BrowserWindow::SetDeviceScaleFactor(float device_scale_factor) {}
+
+float BrowserWindow::GetDeviceScaleFactor() const {
+ return 1.0f;
+}
+
+CefRefPtr<CefBrowser> BrowserWindow::GetBrowser() const {
+ REQUIRE_MAIN_THREAD();
+ return browser_;
+}
+
+bool BrowserWindow::IsClosing() const {
+ REQUIRE_MAIN_THREAD();
+ return is_closing_;
+}
+
+void BrowserWindow::OnBrowserCreated(CefRefPtr<CefBrowser> browser) {
+ REQUIRE_MAIN_THREAD();
+ DCHECK(!browser_);
+ browser_ = browser;
+
+ delegate_->OnBrowserCreated(browser);
+}
+
+void BrowserWindow::OnBrowserClosing(CefRefPtr<CefBrowser> browser) {
+ REQUIRE_MAIN_THREAD();
+ DCHECK_EQ(browser->GetIdentifier(), browser_->GetIdentifier());
+ is_closing_ = true;
+
+ delegate_->OnBrowserWindowClosing();
+}
+
+void BrowserWindow::OnBrowserClosed(CefRefPtr<CefBrowser> browser) {
+ REQUIRE_MAIN_THREAD();
+ if (browser_.get()) {
+ DCHECK_EQ(browser->GetIdentifier(), browser_->GetIdentifier());
+ browser_ = nullptr;
+ }
+
+ client_handler_->DetachDelegate();
+ client_handler_ = nullptr;
+
+ // |this| may be deleted.
+ delegate_->OnBrowserWindowDestroyed();
+}
+
+void BrowserWindow::OnSetAddress(const std::string& url) {
+ REQUIRE_MAIN_THREAD();
+ delegate_->OnSetAddress(url);
+}
+
+void BrowserWindow::OnSetTitle(const std::string& title) {
+ REQUIRE_MAIN_THREAD();
+ delegate_->OnSetTitle(title);
+}
+
+void BrowserWindow::OnSetFullscreen(bool fullscreen) {
+ REQUIRE_MAIN_THREAD();
+ delegate_->OnSetFullscreen(fullscreen);
+}
+
+void BrowserWindow::OnAutoResize(const CefSize& new_size) {
+ REQUIRE_MAIN_THREAD();
+ delegate_->OnAutoResize(new_size);
+}
+
+void BrowserWindow::OnSetLoadingState(bool isLoading,
+ bool canGoBack,
+ bool canGoForward) {
+ REQUIRE_MAIN_THREAD();
+ delegate_->OnSetLoadingState(isLoading, canGoBack, canGoForward);
+}
+
+void BrowserWindow::OnSetDraggableRegions(
+ const std::vector<CefDraggableRegion>& regions) {
+ REQUIRE_MAIN_THREAD();
+ delegate_->OnSetDraggableRegions(regions);
+}
+
+} // namespace client
diff --git a/tests/cefclient/browser/browser_window.h b/tests/cefclient/browser/browser_window.h
new file mode 100644
index 00000000..314ba1f3
--- /dev/null
+++ b/tests/cefclient/browser/browser_window.h
@@ -0,0 +1,146 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_BROWSER_WINDOW_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_BROWSER_WINDOW_H_
+#pragma once
+
+#include <memory>
+
+#include "include/cef_browser.h"
+#include "tests/cefclient/browser/client_handler.h"
+#include "tests/cefclient/browser/client_types.h"
+
+namespace client {
+
+// Represents a native child window hosting a single browser instance. The
+// methods of this class must be called on the main thread unless otherwise
+// indicated.
+class BrowserWindow : public ClientHandler::Delegate {
+ public:
+ // This interface is implemented by the owner of the BrowserWindow. The
+ // methods of this class will be called on the main thread.
+ class Delegate {
+ public:
+ // Called when the browser has been created.
+ virtual void OnBrowserCreated(CefRefPtr<CefBrowser> browser) = 0;
+
+ // Called when the BrowserWindow is closing.
+ virtual void OnBrowserWindowClosing() {}
+
+ // Called when the BrowserWindow has been destroyed.
+ virtual void OnBrowserWindowDestroyed() = 0;
+
+ // Set the window URL address.
+ virtual void OnSetAddress(const std::string& url) = 0;
+
+ // Set the window title.
+ virtual void OnSetTitle(const std::string& title) = 0;
+
+ // Set fullscreen mode.
+ virtual void OnSetFullscreen(bool fullscreen) = 0;
+
+ // Auto-resize contents.
+ virtual void OnAutoResize(const CefSize& new_size) = 0;
+
+ // Set the loading state.
+ virtual void OnSetLoadingState(bool isLoading,
+ bool canGoBack,
+ bool canGoForward) = 0;
+
+ // Set the draggable regions.
+ virtual void OnSetDraggableRegions(
+ const std::vector<CefDraggableRegion>& regions) = 0;
+
+ protected:
+ virtual ~Delegate() {}
+ };
+
+ // Create a new browser and native window.
+ virtual void CreateBrowser(ClientWindowHandle parent_handle,
+ const CefRect& rect,
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefDictionaryValue> extra_info,
+ CefRefPtr<CefRequestContext> request_context) = 0;
+
+ // Retrieve the configuration that will be used when creating a popup window.
+ // The popup browser will initially be parented to |temp_handle| which should
+ // be a pre-existing hidden window. The native window will be created later
+ // after the browser has been created. This method will be called on the
+ // browser process UI thread.
+ virtual void GetPopupConfig(CefWindowHandle temp_handle,
+ CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient>& client,
+ CefBrowserSettings& settings) = 0;
+
+ // Show the popup window with correct parent and bounds in parent coordinates.
+ virtual void ShowPopup(ClientWindowHandle parent_handle,
+ int x,
+ int y,
+ size_t width,
+ size_t height) = 0;
+
+ // Show the window.
+ virtual void Show() = 0;
+
+ // Hide the window.
+ virtual void Hide() = 0;
+
+ // Set the window bounds in parent coordinates.
+ virtual void SetBounds(int x, int y, size_t width, size_t height) = 0;
+
+ // Set focus to the window.
+ virtual void SetFocus(bool focus) = 0;
+
+ // Set the device scale factor. Only used in combination with off-screen
+ // rendering.
+ virtual void SetDeviceScaleFactor(float device_scale_factor);
+
+ // Returns the device scale factor. Only used in combination with off-screen
+ // rendering.
+ virtual float GetDeviceScaleFactor() const;
+
+ // Returns the window handle.
+ virtual ClientWindowHandle GetWindowHandle() const = 0;
+
+ // Returns the browser owned by the window.
+ CefRefPtr<CefBrowser> GetBrowser() const;
+
+ // Returns true if the browser is closing.
+ bool IsClosing() const;
+
+ protected:
+ // Allow deletion via std::unique_ptr only.
+ friend std::default_delete<BrowserWindow>;
+
+ // Constructor may be called on any thread.
+ // |delegate| must outlive this object.
+ explicit BrowserWindow(Delegate* delegate);
+
+ // ClientHandler::Delegate methods.
+ void OnBrowserCreated(CefRefPtr<CefBrowser> browser) override;
+ void OnBrowserClosing(CefRefPtr<CefBrowser> browser) override;
+ void OnBrowserClosed(CefRefPtr<CefBrowser> browser) override;
+ void OnSetAddress(const std::string& url) override;
+ void OnSetTitle(const std::string& title) override;
+ void OnSetFullscreen(bool fullscreen) override;
+ void OnAutoResize(const CefSize& new_size) override;
+ void OnSetLoadingState(bool isLoading,
+ bool canGoBack,
+ bool canGoForward) override;
+ void OnSetDraggableRegions(
+ const std::vector<CefDraggableRegion>& regions) override;
+
+ Delegate* delegate_;
+ CefRefPtr<CefBrowser> browser_;
+ CefRefPtr<ClientHandler> client_handler_;
+ bool is_closing_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BrowserWindow);
+};
+
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_BROWSER_WINDOW_H_
diff --git a/tests/cefclient/browser/browser_window_osr_gtk.cc b/tests/cefclient/browser/browser_window_osr_gtk.cc
new file mode 100644
index 00000000..db5ce52f
--- /dev/null
+++ b/tests/cefclient/browser/browser_window_osr_gtk.cc
@@ -0,0 +1,2099 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/browser_window_osr_gtk.h"
+
+#include <GL/gl.h>
+#include <gdk/gdk.h>
+#include <gdk/gdkkeysyms-compat.h>
+#include <gdk/gdkx.h>
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+#define XK_3270 // for XK_3270_BackTab
+#include <X11/XF86keysym.h>
+#include <X11/Xcursor/Xcursor.h>
+#include <X11/keysym.h>
+
+#include <algorithm>
+
+#include "include/base/cef_logging.h"
+#include "include/base/cef_macros.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "tests/cefclient/browser/util_gtk.h"
+#include "tests/shared/browser/geometry_util.h"
+#include "tests/shared/browser/main_message_loop.h"
+
+namespace client {
+
+namespace {
+
+// Static BrowserWindowOsrGtk::EventFilter needs to forward touch events
+// to correct browser, so we maintain a vector of all windows.
+std::vector<BrowserWindowOsrGtk*> g_browser_windows;
+
+int GetCefStateModifiers(guint state) {
+ int modifiers = 0;
+ if (state & GDK_SHIFT_MASK) {
+ modifiers |= EVENTFLAG_SHIFT_DOWN;
+ }
+ if (state & GDK_LOCK_MASK) {
+ modifiers |= EVENTFLAG_CAPS_LOCK_ON;
+ }
+ if (state & GDK_CONTROL_MASK) {
+ modifiers |= EVENTFLAG_CONTROL_DOWN;
+ }
+ if (state & GDK_MOD1_MASK) {
+ modifiers |= EVENTFLAG_ALT_DOWN;
+ }
+ if (state & GDK_BUTTON1_MASK) {
+ modifiers |= EVENTFLAG_LEFT_MOUSE_BUTTON;
+ }
+ if (state & GDK_BUTTON2_MASK) {
+ modifiers |= EVENTFLAG_MIDDLE_MOUSE_BUTTON;
+ }
+ if (state & GDK_BUTTON3_MASK) {
+ modifiers |= EVENTFLAG_RIGHT_MOUSE_BUTTON;
+ }
+ return modifiers;
+}
+
+// From ui/events/keycodes/keyboard_codes_posix.h.
+enum KeyboardCode {
+ VKEY_BACK = 0x08,
+ VKEY_TAB = 0x09,
+ VKEY_BACKTAB = 0x0A,
+ VKEY_CLEAR = 0x0C,
+ VKEY_RETURN = 0x0D,
+ VKEY_SHIFT = 0x10,
+ VKEY_CONTROL = 0x11,
+ VKEY_MENU = 0x12,
+ VKEY_PAUSE = 0x13,
+ VKEY_CAPITAL = 0x14,
+ VKEY_KANA = 0x15,
+ VKEY_HANGUL = 0x15,
+ VKEY_JUNJA = 0x17,
+ VKEY_FINAL = 0x18,
+ VKEY_HANJA = 0x19,
+ VKEY_KANJI = 0x19,
+ VKEY_ESCAPE = 0x1B,
+ VKEY_CONVERT = 0x1C,
+ VKEY_NONCONVERT = 0x1D,
+ VKEY_ACCEPT = 0x1E,
+ VKEY_MODECHANGE = 0x1F,
+ VKEY_SPACE = 0x20,
+ VKEY_PRIOR = 0x21,
+ VKEY_NEXT = 0x22,
+ VKEY_END = 0x23,
+ VKEY_HOME = 0x24,
+ VKEY_LEFT = 0x25,
+ VKEY_UP = 0x26,
+ VKEY_RIGHT = 0x27,
+ VKEY_DOWN = 0x28,
+ VKEY_SELECT = 0x29,
+ VKEY_PRINT = 0x2A,
+ VKEY_EXECUTE = 0x2B,
+ VKEY_SNAPSHOT = 0x2C,
+ VKEY_INSERT = 0x2D,
+ VKEY_DELETE = 0x2E,
+ VKEY_HELP = 0x2F,
+ VKEY_0 = 0x30,
+ VKEY_1 = 0x31,
+ VKEY_2 = 0x32,
+ VKEY_3 = 0x33,
+ VKEY_4 = 0x34,
+ VKEY_5 = 0x35,
+ VKEY_6 = 0x36,
+ VKEY_7 = 0x37,
+ VKEY_8 = 0x38,
+ VKEY_9 = 0x39,
+ VKEY_A = 0x41,
+ VKEY_B = 0x42,
+ VKEY_C = 0x43,
+ VKEY_D = 0x44,
+ VKEY_E = 0x45,
+ VKEY_F = 0x46,
+ VKEY_G = 0x47,
+ VKEY_H = 0x48,
+ VKEY_I = 0x49,
+ VKEY_J = 0x4A,
+ VKEY_K = 0x4B,
+ VKEY_L = 0x4C,
+ VKEY_M = 0x4D,
+ VKEY_N = 0x4E,
+ VKEY_O = 0x4F,
+ VKEY_P = 0x50,
+ VKEY_Q = 0x51,
+ VKEY_R = 0x52,
+ VKEY_S = 0x53,
+ VKEY_T = 0x54,
+ VKEY_U = 0x55,
+ VKEY_V = 0x56,
+ VKEY_W = 0x57,
+ VKEY_X = 0x58,
+ VKEY_Y = 0x59,
+ VKEY_Z = 0x5A,
+ VKEY_LWIN = 0x5B,
+ VKEY_COMMAND = VKEY_LWIN, // Provide the Mac name for convenience.
+ VKEY_RWIN = 0x5C,
+ VKEY_APPS = 0x5D,
+ VKEY_SLEEP = 0x5F,
+ VKEY_NUMPAD0 = 0x60,
+ VKEY_NUMPAD1 = 0x61,
+ VKEY_NUMPAD2 = 0x62,
+ VKEY_NUMPAD3 = 0x63,
+ VKEY_NUMPAD4 = 0x64,
+ VKEY_NUMPAD5 = 0x65,
+ VKEY_NUMPAD6 = 0x66,
+ VKEY_NUMPAD7 = 0x67,
+ VKEY_NUMPAD8 = 0x68,
+ VKEY_NUMPAD9 = 0x69,
+ VKEY_MULTIPLY = 0x6A,
+ VKEY_ADD = 0x6B,
+ VKEY_SEPARATOR = 0x6C,
+ VKEY_SUBTRACT = 0x6D,
+ VKEY_DECIMAL = 0x6E,
+ VKEY_DIVIDE = 0x6F,
+ VKEY_F1 = 0x70,
+ VKEY_F2 = 0x71,
+ VKEY_F3 = 0x72,
+ VKEY_F4 = 0x73,
+ VKEY_F5 = 0x74,
+ VKEY_F6 = 0x75,
+ VKEY_F7 = 0x76,
+ VKEY_F8 = 0x77,
+ VKEY_F9 = 0x78,
+ VKEY_F10 = 0x79,
+ VKEY_F11 = 0x7A,
+ VKEY_F12 = 0x7B,
+ VKEY_F13 = 0x7C,
+ VKEY_F14 = 0x7D,
+ VKEY_F15 = 0x7E,
+ VKEY_F16 = 0x7F,
+ VKEY_F17 = 0x80,
+ VKEY_F18 = 0x81,
+ VKEY_F19 = 0x82,
+ VKEY_F20 = 0x83,
+ VKEY_F21 = 0x84,
+ VKEY_F22 = 0x85,
+ VKEY_F23 = 0x86,
+ VKEY_F24 = 0x87,
+ VKEY_NUMLOCK = 0x90,
+ VKEY_SCROLL = 0x91,
+ VKEY_LSHIFT = 0xA0,
+ VKEY_RSHIFT = 0xA1,
+ VKEY_LCONTROL = 0xA2,
+ VKEY_RCONTROL = 0xA3,
+ VKEY_LMENU = 0xA4,
+ VKEY_RMENU = 0xA5,
+ VKEY_BROWSER_BACK = 0xA6,
+ VKEY_BROWSER_FORWARD = 0xA7,
+ VKEY_BROWSER_REFRESH = 0xA8,
+ VKEY_BROWSER_STOP = 0xA9,
+ VKEY_BROWSER_SEARCH = 0xAA,
+ VKEY_BROWSER_FAVORITES = 0xAB,
+ VKEY_BROWSER_HOME = 0xAC,
+ VKEY_VOLUME_MUTE = 0xAD,
+ VKEY_VOLUME_DOWN = 0xAE,
+ VKEY_VOLUME_UP = 0xAF,
+ VKEY_MEDIA_NEXT_TRACK = 0xB0,
+ VKEY_MEDIA_PREV_TRACK = 0xB1,
+ VKEY_MEDIA_STOP = 0xB2,
+ VKEY_MEDIA_PLAY_PAUSE = 0xB3,
+ VKEY_MEDIA_LAUNCH_MAIL = 0xB4,
+ VKEY_MEDIA_LAUNCH_MEDIA_SELECT = 0xB5,
+ VKEY_MEDIA_LAUNCH_APP1 = 0xB6,
+ VKEY_MEDIA_LAUNCH_APP2 = 0xB7,
+ VKEY_OEM_1 = 0xBA,
+ VKEY_OEM_PLUS = 0xBB,
+ VKEY_OEM_COMMA = 0xBC,
+ VKEY_OEM_MINUS = 0xBD,
+ VKEY_OEM_PERIOD = 0xBE,
+ VKEY_OEM_2 = 0xBF,
+ VKEY_OEM_3 = 0xC0,
+ VKEY_OEM_4 = 0xDB,
+ VKEY_OEM_5 = 0xDC,
+ VKEY_OEM_6 = 0xDD,
+ VKEY_OEM_7 = 0xDE,
+ VKEY_OEM_8 = 0xDF,
+ VKEY_OEM_102 = 0xE2,
+ VKEY_OEM_103 = 0xE3, // GTV KEYCODE_MEDIA_REWIND
+ VKEY_OEM_104 = 0xE4, // GTV KEYCODE_MEDIA_FAST_FORWARD
+ VKEY_PROCESSKEY = 0xE5,
+ VKEY_PACKET = 0xE7,
+ VKEY_DBE_SBCSCHAR = 0xF3,
+ VKEY_DBE_DBCSCHAR = 0xF4,
+ VKEY_ATTN = 0xF6,
+ VKEY_CRSEL = 0xF7,
+ VKEY_EXSEL = 0xF8,
+ VKEY_EREOF = 0xF9,
+ VKEY_PLAY = 0xFA,
+ VKEY_ZOOM = 0xFB,
+ VKEY_NONAME = 0xFC,
+ VKEY_PA1 = 0xFD,
+ VKEY_OEM_CLEAR = 0xFE,
+ VKEY_UNKNOWN = 0,
+
+ // POSIX specific VKEYs. Note that as of Windows SDK 7.1, 0x97-9F, 0xD8-DA,
+ // and 0xE8 are unassigned.
+ VKEY_WLAN = 0x97,
+ VKEY_POWER = 0x98,
+ VKEY_BRIGHTNESS_DOWN = 0xD8,
+ VKEY_BRIGHTNESS_UP = 0xD9,
+ VKEY_KBD_BRIGHTNESS_DOWN = 0xDA,
+ VKEY_KBD_BRIGHTNESS_UP = 0xE8,
+
+ // Windows does not have a specific key code for AltGr. We use the unused 0xE1
+ // (VK_OEM_AX) code to represent AltGr, matching the behaviour of Firefox on
+ // Linux.
+ VKEY_ALTGR = 0xE1,
+ // Windows does not have a specific key code for Compose. We use the unused
+ // 0xE6 (VK_ICO_CLEAR) code to represent Compose.
+ VKEY_COMPOSE = 0xE6,
+};
+
+// From ui/events/keycodes/keyboard_code_conversion_x.cc.
+// Gdk key codes (e.g. GDK_BackSpace) and X keysyms (e.g. XK_BackSpace) share
+// the same values.
+KeyboardCode KeyboardCodeFromXKeysym(unsigned int keysym) {
+ switch (keysym) {
+ case XK_BackSpace:
+ return VKEY_BACK;
+ case XK_Delete:
+ case XK_KP_Delete:
+ return VKEY_DELETE;
+ case XK_Tab:
+ case XK_KP_Tab:
+ case XK_ISO_Left_Tab:
+ case XK_3270_BackTab:
+ return VKEY_TAB;
+ case XK_Linefeed:
+ case XK_Return:
+ case XK_KP_Enter:
+ case XK_ISO_Enter:
+ return VKEY_RETURN;
+ case XK_Clear:
+ case XK_KP_Begin: // NumPad 5 without Num Lock, for crosbug.com/29169.
+ return VKEY_CLEAR;
+ case XK_KP_Space:
+ case XK_space:
+ return VKEY_SPACE;
+ case XK_Home:
+ case XK_KP_Home:
+ return VKEY_HOME;
+ case XK_End:
+ case XK_KP_End:
+ return VKEY_END;
+ case XK_Page_Up:
+ case XK_KP_Page_Up: // aka XK_KP_Prior
+ return VKEY_PRIOR;
+ case XK_Page_Down:
+ case XK_KP_Page_Down: // aka XK_KP_Next
+ return VKEY_NEXT;
+ case XK_Left:
+ case XK_KP_Left:
+ return VKEY_LEFT;
+ case XK_Right:
+ case XK_KP_Right:
+ return VKEY_RIGHT;
+ case XK_Down:
+ case XK_KP_Down:
+ return VKEY_DOWN;
+ case XK_Up:
+ case XK_KP_Up:
+ return VKEY_UP;
+ case XK_Escape:
+ return VKEY_ESCAPE;
+ case XK_Kana_Lock:
+ case XK_Kana_Shift:
+ return VKEY_KANA;
+ case XK_Hangul:
+ return VKEY_HANGUL;
+ case XK_Hangul_Hanja:
+ return VKEY_HANJA;
+ case XK_Kanji:
+ return VKEY_KANJI;
+ case XK_Henkan:
+ return VKEY_CONVERT;
+ case XK_Muhenkan:
+ return VKEY_NONCONVERT;
+ case XK_Zenkaku_Hankaku:
+ return VKEY_DBE_DBCSCHAR;
+ case XK_A:
+ case XK_a:
+ return VKEY_A;
+ case XK_B:
+ case XK_b:
+ return VKEY_B;
+ case XK_C:
+ case XK_c:
+ return VKEY_C;
+ case XK_D:
+ case XK_d:
+ return VKEY_D;
+ case XK_E:
+ case XK_e:
+ return VKEY_E;
+ case XK_F:
+ case XK_f:
+ return VKEY_F;
+ case XK_G:
+ case XK_g:
+ return VKEY_G;
+ case XK_H:
+ case XK_h:
+ return VKEY_H;
+ case XK_I:
+ case XK_i:
+ return VKEY_I;
+ case XK_J:
+ case XK_j:
+ return VKEY_J;
+ case XK_K:
+ case XK_k:
+ return VKEY_K;
+ case XK_L:
+ case XK_l:
+ return VKEY_L;
+ case XK_M:
+ case XK_m:
+ return VKEY_M;
+ case XK_N:
+ case XK_n:
+ return VKEY_N;
+ case XK_O:
+ case XK_o:
+ return VKEY_O;
+ case XK_P:
+ case XK_p:
+ return VKEY_P;
+ case XK_Q:
+ case XK_q:
+ return VKEY_Q;
+ case XK_R:
+ case XK_r:
+ return VKEY_R;
+ case XK_S:
+ case XK_s:
+ return VKEY_S;
+ case XK_T:
+ case XK_t:
+ return VKEY_T;
+ case XK_U:
+ case XK_u:
+ return VKEY_U;
+ case XK_V:
+ case XK_v:
+ return VKEY_V;
+ case XK_W:
+ case XK_w:
+ return VKEY_W;
+ case XK_X:
+ case XK_x:
+ return VKEY_X;
+ case XK_Y:
+ case XK_y:
+ return VKEY_Y;
+ case XK_Z:
+ case XK_z:
+ return VKEY_Z;
+
+ case XK_0:
+ case XK_1:
+ case XK_2:
+ case XK_3:
+ case XK_4:
+ case XK_5:
+ case XK_6:
+ case XK_7:
+ case XK_8:
+ case XK_9:
+ return static_cast<KeyboardCode>(VKEY_0 + (keysym - XK_0));
+
+ case XK_parenright:
+ return VKEY_0;
+ case XK_exclam:
+ return VKEY_1;
+ case XK_at:
+ return VKEY_2;
+ case XK_numbersign:
+ return VKEY_3;
+ case XK_dollar:
+ return VKEY_4;
+ case XK_percent:
+ return VKEY_5;
+ case XK_asciicircum:
+ return VKEY_6;
+ case XK_ampersand:
+ return VKEY_7;
+ case XK_asterisk:
+ return VKEY_8;
+ case XK_parenleft:
+ return VKEY_9;
+
+ case XK_KP_0:
+ case XK_KP_1:
+ case XK_KP_2:
+ case XK_KP_3:
+ case XK_KP_4:
+ case XK_KP_5:
+ case XK_KP_6:
+ case XK_KP_7:
+ case XK_KP_8:
+ case XK_KP_9:
+ return static_cast<KeyboardCode>(VKEY_NUMPAD0 + (keysym - XK_KP_0));
+
+ case XK_multiply:
+ case XK_KP_Multiply:
+ return VKEY_MULTIPLY;
+ case XK_KP_Add:
+ return VKEY_ADD;
+ case XK_KP_Separator:
+ return VKEY_SEPARATOR;
+ case XK_KP_Subtract:
+ return VKEY_SUBTRACT;
+ case XK_KP_Decimal:
+ return VKEY_DECIMAL;
+ case XK_KP_Divide:
+ return VKEY_DIVIDE;
+ case XK_KP_Equal:
+ case XK_equal:
+ case XK_plus:
+ return VKEY_OEM_PLUS;
+ case XK_comma:
+ case XK_less:
+ return VKEY_OEM_COMMA;
+ case XK_minus:
+ case XK_underscore:
+ return VKEY_OEM_MINUS;
+ case XK_greater:
+ case XK_period:
+ return VKEY_OEM_PERIOD;
+ case XK_colon:
+ case XK_semicolon:
+ return VKEY_OEM_1;
+ case XK_question:
+ case XK_slash:
+ return VKEY_OEM_2;
+ case XK_asciitilde:
+ case XK_quoteleft:
+ return VKEY_OEM_3;
+ case XK_bracketleft:
+ case XK_braceleft:
+ return VKEY_OEM_4;
+ case XK_backslash:
+ case XK_bar:
+ return VKEY_OEM_5;
+ case XK_bracketright:
+ case XK_braceright:
+ return VKEY_OEM_6;
+ case XK_quoteright:
+ case XK_quotedbl:
+ return VKEY_OEM_7;
+ case XK_ISO_Level5_Shift:
+ return VKEY_OEM_8;
+ case XK_Shift_L:
+ case XK_Shift_R:
+ return VKEY_SHIFT;
+ case XK_Control_L:
+ case XK_Control_R:
+ return VKEY_CONTROL;
+ case XK_Meta_L:
+ case XK_Meta_R:
+ case XK_Alt_L:
+ case XK_Alt_R:
+ return VKEY_MENU;
+ case XK_ISO_Level3_Shift:
+ return VKEY_ALTGR;
+ case XK_Multi_key:
+ return VKEY_COMPOSE;
+ case XK_Pause:
+ return VKEY_PAUSE;
+ case XK_Caps_Lock:
+ return VKEY_CAPITAL;
+ case XK_Num_Lock:
+ return VKEY_NUMLOCK;
+ case XK_Scroll_Lock:
+ return VKEY_SCROLL;
+ case XK_Select:
+ return VKEY_SELECT;
+ case XK_Print:
+ return VKEY_PRINT;
+ case XK_Execute:
+ return VKEY_EXECUTE;
+ case XK_Insert:
+ case XK_KP_Insert:
+ return VKEY_INSERT;
+ case XK_Help:
+ return VKEY_HELP;
+ case XK_Super_L:
+ return VKEY_LWIN;
+ case XK_Super_R:
+ return VKEY_RWIN;
+ case XK_Menu:
+ return VKEY_APPS;
+ case XK_F1:
+ case XK_F2:
+ case XK_F3:
+ case XK_F4:
+ case XK_F5:
+ case XK_F6:
+ case XK_F7:
+ case XK_F8:
+ case XK_F9:
+ case XK_F10:
+ case XK_F11:
+ case XK_F12:
+ case XK_F13:
+ case XK_F14:
+ case XK_F15:
+ case XK_F16:
+ case XK_F17:
+ case XK_F18:
+ case XK_F19:
+ case XK_F20:
+ case XK_F21:
+ case XK_F22:
+ case XK_F23:
+ case XK_F24:
+ return static_cast<KeyboardCode>(VKEY_F1 + (keysym - XK_F1));
+ case XK_KP_F1:
+ case XK_KP_F2:
+ case XK_KP_F3:
+ case XK_KP_F4:
+ return static_cast<KeyboardCode>(VKEY_F1 + (keysym - XK_KP_F1));
+
+ case XK_guillemotleft:
+ case XK_guillemotright:
+ case XK_degree:
+ // In the case of canadian multilingual keyboard layout, VKEY_OEM_102 is
+ // assigned to ugrave key.
+ case XK_ugrave:
+ case XK_Ugrave:
+ case XK_brokenbar:
+ return VKEY_OEM_102; // international backslash key in 102 keyboard.
+
+ // When evdev is in use, /usr/share/X11/xkb/symbols/inet maps F13-18 keys
+ // to the special XF86XK symbols to support Microsoft Ergonomic keyboards:
+ // https://bugs.freedesktop.org/show_bug.cgi?id=5783
+ // In Chrome, we map these X key symbols back to F13-18 since we don't have
+ // VKEYs for these XF86XK symbols.
+ case XF86XK_Tools:
+ return VKEY_F13;
+ case XF86XK_Launch5:
+ return VKEY_F14;
+ case XF86XK_Launch6:
+ return VKEY_F15;
+ case XF86XK_Launch7:
+ return VKEY_F16;
+ case XF86XK_Launch8:
+ return VKEY_F17;
+ case XF86XK_Launch9:
+ return VKEY_F18;
+ case XF86XK_Refresh:
+ case XF86XK_History:
+ case XF86XK_OpenURL:
+ case XF86XK_AddFavorite:
+ case XF86XK_Go:
+ case XF86XK_ZoomIn:
+ case XF86XK_ZoomOut:
+ // ui::AcceleratorGtk tries to convert the XF86XK_ keysyms on Chrome
+ // startup. It's safe to return VKEY_UNKNOWN here since ui::AcceleratorGtk
+ // also checks a Gdk keysym. http://crbug.com/109843
+ return VKEY_UNKNOWN;
+ // For supporting multimedia buttons on a USB keyboard.
+ case XF86XK_Back:
+ return VKEY_BROWSER_BACK;
+ case XF86XK_Forward:
+ return VKEY_BROWSER_FORWARD;
+ case XF86XK_Reload:
+ return VKEY_BROWSER_REFRESH;
+ case XF86XK_Stop:
+ return VKEY_BROWSER_STOP;
+ case XF86XK_Search:
+ return VKEY_BROWSER_SEARCH;
+ case XF86XK_Favorites:
+ return VKEY_BROWSER_FAVORITES;
+ case XF86XK_HomePage:
+ return VKEY_BROWSER_HOME;
+ case XF86XK_AudioMute:
+ return VKEY_VOLUME_MUTE;
+ case XF86XK_AudioLowerVolume:
+ return VKEY_VOLUME_DOWN;
+ case XF86XK_AudioRaiseVolume:
+ return VKEY_VOLUME_UP;
+ case XF86XK_AudioNext:
+ return VKEY_MEDIA_NEXT_TRACK;
+ case XF86XK_AudioPrev:
+ return VKEY_MEDIA_PREV_TRACK;
+ case XF86XK_AudioStop:
+ return VKEY_MEDIA_STOP;
+ case XF86XK_AudioPlay:
+ return VKEY_MEDIA_PLAY_PAUSE;
+ case XF86XK_Mail:
+ return VKEY_MEDIA_LAUNCH_MAIL;
+ case XF86XK_LaunchA: // F3 on an Apple keyboard.
+ return VKEY_MEDIA_LAUNCH_APP1;
+ case XF86XK_LaunchB: // F4 on an Apple keyboard.
+ case XF86XK_Calculator:
+ return VKEY_MEDIA_LAUNCH_APP2;
+ case XF86XK_WLAN:
+ return VKEY_WLAN;
+ case XF86XK_PowerOff:
+ return VKEY_POWER;
+ case XF86XK_MonBrightnessDown:
+ return VKEY_BRIGHTNESS_DOWN;
+ case XF86XK_MonBrightnessUp:
+ return VKEY_BRIGHTNESS_UP;
+ case XF86XK_KbdBrightnessDown:
+ return VKEY_KBD_BRIGHTNESS_DOWN;
+ case XF86XK_KbdBrightnessUp:
+ return VKEY_KBD_BRIGHTNESS_UP;
+
+ // TODO(sad): some keycodes are still missing.
+ }
+ return VKEY_UNKNOWN;
+}
+
+// From content/browser/renderer_host/input/web_input_event_util_posix.cc.
+KeyboardCode GdkEventToWindowsKeyCode(const GdkEventKey* event) {
+ static const unsigned int kHardwareCodeToGDKKeyval[] = {
+ 0, // 0x00:
+ 0, // 0x01:
+ 0, // 0x02:
+ 0, // 0x03:
+ 0, // 0x04:
+ 0, // 0x05:
+ 0, // 0x06:
+ 0, // 0x07:
+ 0, // 0x08:
+ 0, // 0x09: GDK_Escape
+ GDK_1, // 0x0A: GDK_1
+ GDK_2, // 0x0B: GDK_2
+ GDK_3, // 0x0C: GDK_3
+ GDK_4, // 0x0D: GDK_4
+ GDK_5, // 0x0E: GDK_5
+ GDK_6, // 0x0F: GDK_6
+ GDK_7, // 0x10: GDK_7
+ GDK_8, // 0x11: GDK_8
+ GDK_9, // 0x12: GDK_9
+ GDK_0, // 0x13: GDK_0
+ GDK_minus, // 0x14: GDK_minus
+ GDK_equal, // 0x15: GDK_equal
+ 0, // 0x16: GDK_BackSpace
+ 0, // 0x17: GDK_Tab
+ GDK_q, // 0x18: GDK_q
+ GDK_w, // 0x19: GDK_w
+ GDK_e, // 0x1A: GDK_e
+ GDK_r, // 0x1B: GDK_r
+ GDK_t, // 0x1C: GDK_t
+ GDK_y, // 0x1D: GDK_y
+ GDK_u, // 0x1E: GDK_u
+ GDK_i, // 0x1F: GDK_i
+ GDK_o, // 0x20: GDK_o
+ GDK_p, // 0x21: GDK_p
+ GDK_bracketleft, // 0x22: GDK_bracketleft
+ GDK_bracketright, // 0x23: GDK_bracketright
+ 0, // 0x24: GDK_Return
+ 0, // 0x25: GDK_Control_L
+ GDK_a, // 0x26: GDK_a
+ GDK_s, // 0x27: GDK_s
+ GDK_d, // 0x28: GDK_d
+ GDK_f, // 0x29: GDK_f
+ GDK_g, // 0x2A: GDK_g
+ GDK_h, // 0x2B: GDK_h
+ GDK_j, // 0x2C: GDK_j
+ GDK_k, // 0x2D: GDK_k
+ GDK_l, // 0x2E: GDK_l
+ GDK_semicolon, // 0x2F: GDK_semicolon
+ GDK_apostrophe, // 0x30: GDK_apostrophe
+ GDK_grave, // 0x31: GDK_grave
+ 0, // 0x32: GDK_Shift_L
+ GDK_backslash, // 0x33: GDK_backslash
+ GDK_z, // 0x34: GDK_z
+ GDK_x, // 0x35: GDK_x
+ GDK_c, // 0x36: GDK_c
+ GDK_v, // 0x37: GDK_v
+ GDK_b, // 0x38: GDK_b
+ GDK_n, // 0x39: GDK_n
+ GDK_m, // 0x3A: GDK_m
+ GDK_comma, // 0x3B: GDK_comma
+ GDK_period, // 0x3C: GDK_period
+ GDK_slash, // 0x3D: GDK_slash
+ 0, // 0x3E: GDK_Shift_R
+ 0, // 0x3F:
+ 0, // 0x40:
+ 0, // 0x41:
+ 0, // 0x42:
+ 0, // 0x43:
+ 0, // 0x44:
+ 0, // 0x45:
+ 0, // 0x46:
+ 0, // 0x47:
+ 0, // 0x48:
+ 0, // 0x49:
+ 0, // 0x4A:
+ 0, // 0x4B:
+ 0, // 0x4C:
+ 0, // 0x4D:
+ 0, // 0x4E:
+ 0, // 0x4F:
+ 0, // 0x50:
+ 0, // 0x51:
+ 0, // 0x52:
+ 0, // 0x53:
+ 0, // 0x54:
+ 0, // 0x55:
+ 0, // 0x56:
+ 0, // 0x57:
+ 0, // 0x58:
+ 0, // 0x59:
+ 0, // 0x5A:
+ 0, // 0x5B:
+ 0, // 0x5C:
+ 0, // 0x5D:
+ 0, // 0x5E:
+ 0, // 0x5F:
+ 0, // 0x60:
+ 0, // 0x61:
+ 0, // 0x62:
+ 0, // 0x63:
+ 0, // 0x64:
+ 0, // 0x65:
+ 0, // 0x66:
+ 0, // 0x67:
+ 0, // 0x68:
+ 0, // 0x69:
+ 0, // 0x6A:
+ 0, // 0x6B:
+ 0, // 0x6C:
+ 0, // 0x6D:
+ 0, // 0x6E:
+ 0, // 0x6F:
+ 0, // 0x70:
+ 0, // 0x71:
+ 0, // 0x72:
+ GDK_Super_L, // 0x73: GDK_Super_L
+ GDK_Super_R, // 0x74: GDK_Super_R
+ };
+
+ // |windows_key_code| has to include a valid virtual-key code even when we
+ // use non-US layouts, e.g. even when we type an 'A' key of a US keyboard
+ // on the Hebrew layout, |windows_key_code| should be VK_A.
+ // On the other hand, |event->keyval| value depends on the current
+ // GdkKeymap object, i.e. when we type an 'A' key of a US keyboard on
+ // the Hebrew layout, |event->keyval| becomes GDK_hebrew_shin and this
+ // KeyboardCodeFromXKeysym() call returns 0.
+ // To improve compatibilty with Windows, we use |event->hardware_keycode|
+ // for retrieving its Windows key-code for the keys when the
+ // WebCore::windows_key_codeForEvent() call returns 0.
+ // We shouldn't use |event->hardware_keycode| for keys that GdkKeymap
+ // objects cannot change because |event->hardware_keycode| doesn't change
+ // even when we change the layout options, e.g. when we swap a control
+ // key and a caps-lock key, GTK doesn't swap their
+ // |event->hardware_keycode| values but swap their |event->keyval| values.
+ KeyboardCode windows_key_code = KeyboardCodeFromXKeysym(event->keyval);
+ if (windows_key_code) {
+ return windows_key_code;
+ }
+
+ if (event->hardware_keycode < std::size(kHardwareCodeToGDKKeyval)) {
+ int keyval = kHardwareCodeToGDKKeyval[event->hardware_keycode];
+ if (keyval) {
+ return KeyboardCodeFromXKeysym(keyval);
+ }
+ }
+
+ // This key is one that keyboard-layout drivers cannot change.
+ // Use |event->keyval| to retrieve its |windows_key_code| value.
+ return KeyboardCodeFromXKeysym(event->keyval);
+}
+
+// From content/browser/renderer_host/input/web_input_event_util_posix.cc.
+KeyboardCode GetWindowsKeyCodeWithoutLocation(KeyboardCode key_code) {
+ switch (key_code) {
+ case VKEY_LCONTROL:
+ case VKEY_RCONTROL:
+ return VKEY_CONTROL;
+ case VKEY_LSHIFT:
+ case VKEY_RSHIFT:
+ return VKEY_SHIFT;
+ case VKEY_LMENU:
+ case VKEY_RMENU:
+ return VKEY_MENU;
+ default:
+ return key_code;
+ }
+}
+
+// From content/browser/renderer_host/input/web_input_event_builders_gtk.cc.
+// Gets the corresponding control character of a specified key code. See:
+// http://en.wikipedia.org/wiki/Control_characters
+// We emulate Windows behavior here.
+int GetControlCharacter(KeyboardCode windows_key_code, bool shift) {
+ if (windows_key_code >= VKEY_A && windows_key_code <= VKEY_Z) {
+ // ctrl-A ~ ctrl-Z map to \x01 ~ \x1A
+ return windows_key_code - VKEY_A + 1;
+ }
+ if (shift) {
+ // following graphics chars require shift key to input.
+ switch (windows_key_code) {
+ // ctrl-@ maps to \x00 (Null byte)
+ case VKEY_2:
+ return 0;
+ // ctrl-^ maps to \x1E (Record separator, Information separator two)
+ case VKEY_6:
+ return 0x1E;
+ // ctrl-_ maps to \x1F (Unit separator, Information separator one)
+ case VKEY_OEM_MINUS:
+ return 0x1F;
+ // Returns 0 for all other keys to avoid inputting unexpected chars.
+ default:
+ return 0;
+ }
+ } else {
+ switch (windows_key_code) {
+ // ctrl-[ maps to \x1B (Escape)
+ case VKEY_OEM_4:
+ return 0x1B;
+ // ctrl-\ maps to \x1C (File separator, Information separator four)
+ case VKEY_OEM_5:
+ return 0x1C;
+ // ctrl-] maps to \x1D (Group separator, Information separator three)
+ case VKEY_OEM_6:
+ return 0x1D;
+ // ctrl-Enter maps to \x0A (Line feed)
+ case VKEY_RETURN:
+ return 0x0A;
+ // Returns 0 for all other keys to avoid inputting unexpected chars.
+ default:
+ return 0;
+ }
+ }
+}
+
+CefBrowserHost::DragOperationsMask GetDragOperationsMask(
+ GdkDragContext* drag_context) {
+ int allowed_ops = DRAG_OPERATION_NONE;
+ GdkDragAction drag_action = gdk_drag_context_get_actions(drag_context);
+ if (drag_action & GDK_ACTION_COPY) {
+ allowed_ops |= DRAG_OPERATION_COPY;
+ }
+ if (drag_action & GDK_ACTION_MOVE) {
+ allowed_ops |= DRAG_OPERATION_MOVE;
+ }
+ if (drag_action & GDK_ACTION_LINK) {
+ allowed_ops |= DRAG_OPERATION_LINK;
+ }
+ if (drag_action & GDK_ACTION_PRIVATE) {
+ allowed_ops |= DRAG_OPERATION_PRIVATE;
+ }
+ return static_cast<CefBrowserHost::DragOperationsMask>(allowed_ops);
+}
+
+class ScopedGLContext {
+ public:
+ ScopedGLContext(GtkWidget* widget, bool swap_buffers)
+ : swap_buffers_(swap_buffers), widget_(widget) {
+ gtk_gl_area_make_current(GTK_GL_AREA(widget));
+ is_valid_ = gtk_gl_area_get_error(GTK_GL_AREA(widget)) == nullptr;
+ if (swap_buffers_ && is_valid_) {
+ gtk_gl_area_queue_render(GTK_GL_AREA(widget_));
+ gtk_gl_area_attach_buffers(GTK_GL_AREA(widget));
+ }
+ }
+
+ virtual ~ScopedGLContext() {
+ if (swap_buffers_ && is_valid_) {
+ glFlush();
+ }
+ }
+
+ bool IsValid() const { return is_valid_; }
+
+ private:
+ bool swap_buffers_;
+ GtkWidget* const widget_;
+ bool is_valid_;
+ ScopedGdkThreadsEnter scoped_gdk_threads_;
+};
+
+} // namespace
+
+BrowserWindowOsrGtk::BrowserWindowOsrGtk(BrowserWindow::Delegate* delegate,
+ bool with_controls,
+ const std::string& startup_url,
+ const OsrRendererSettings& settings)
+ : BrowserWindow(delegate),
+ xdisplay_(nullptr),
+ renderer_(settings),
+ gl_enabled_(false),
+ painting_popup_(false),
+ hidden_(false),
+ glarea_(nullptr),
+ drag_trigger_event_(nullptr),
+ drag_data_(nullptr),
+ drag_operation_(DRAG_OPERATION_NONE),
+ drag_context_(nullptr),
+ drag_targets_(gtk_target_list_new(nullptr, 0)),
+ drag_leave_(false),
+ drag_drop_(false),
+ device_scale_factor_(1.0f) {
+ client_handler_ =
+ new ClientHandlerOsr(this, this, with_controls, startup_url);
+ g_browser_windows.push_back(this);
+}
+
+BrowserWindowOsrGtk::~BrowserWindowOsrGtk() {
+ g_browser_windows.erase(
+ std::find(g_browser_windows.begin(), g_browser_windows.end(), this));
+ ScopedGdkThreadsEnter scoped_gdk_threads;
+
+ if (drag_trigger_event_) {
+ gdk_event_free(drag_trigger_event_);
+ }
+ if (drag_context_) {
+ g_object_unref(drag_context_);
+ }
+ gtk_target_list_unref(drag_targets_);
+}
+
+void BrowserWindowOsrGtk::set_xdisplay(XDisplay* xdisplay) {
+ REQUIRE_MAIN_THREAD();
+ DCHECK(!xdisplay_);
+ xdisplay_ = xdisplay;
+}
+
+void BrowserWindowOsrGtk::CreateBrowser(
+ ClientWindowHandle parent_handle,
+ const CefRect& rect,
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefDictionaryValue> extra_info,
+ CefRefPtr<CefRequestContext> request_context) {
+ REQUIRE_MAIN_THREAD();
+
+ // Create the native window.
+ Create(parent_handle);
+
+ ScopedGdkThreadsEnter scoped_gdk_threads;
+
+ // Retrieve the X11 Window ID for the GTK parent window.
+ GtkWidget* window =
+ gtk_widget_get_ancestor(GTK_WIDGET(parent_handle), GTK_TYPE_WINDOW);
+ CefWindowHandle handle = GDK_WINDOW_XID(gtk_widget_get_window(window));
+ DCHECK(handle);
+
+ CefWindowInfo window_info;
+ window_info.SetAsWindowless(handle);
+
+ // Create the browser asynchronously.
+ CefBrowserHost::CreateBrowser(window_info, client_handler_,
+ client_handler_->startup_url(), settings,
+ extra_info, request_context);
+}
+
+void BrowserWindowOsrGtk::GetPopupConfig(CefWindowHandle temp_handle,
+ CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient>& client,
+ CefBrowserSettings& settings) {
+ CEF_REQUIRE_UI_THREAD();
+
+ windowInfo.SetAsWindowless(temp_handle);
+ client = client_handler_;
+}
+
+void BrowserWindowOsrGtk::ShowPopup(ClientWindowHandle parent_handle,
+ int x,
+ int y,
+ size_t width,
+ size_t height) {
+ REQUIRE_MAIN_THREAD();
+ DCHECK(browser_.get());
+
+ // Create the native window.
+ Create(parent_handle);
+
+ // Send resize notification so the compositor is assigned the correct
+ // viewport size and begins rendering.
+ browser_->GetHost()->WasResized();
+
+ Show();
+}
+
+void BrowserWindowOsrGtk::Show() {
+ REQUIRE_MAIN_THREAD();
+
+ if (hidden_) {
+ // Set the browser as visible.
+ browser_->GetHost()->WasHidden(false);
+ hidden_ = false;
+ }
+
+ // Give focus to the browser.
+ browser_->GetHost()->SetFocus(true);
+}
+
+void BrowserWindowOsrGtk::Hide() {
+ REQUIRE_MAIN_THREAD();
+
+ if (!browser_) {
+ return;
+ }
+
+ // Remove focus from the browser.
+ browser_->GetHost()->SetFocus(false);
+
+ if (!hidden_) {
+ // Set the browser as hidden.
+ browser_->GetHost()->WasHidden(true);
+ hidden_ = true;
+ }
+}
+
+void BrowserWindowOsrGtk::SetBounds(int x, int y, size_t width, size_t height) {
+ REQUIRE_MAIN_THREAD();
+ // Nothing to do here. GTK will take care of positioning in the container.
+}
+
+void BrowserWindowOsrGtk::SetFocus(bool focus) {
+ REQUIRE_MAIN_THREAD();
+ if (glarea_ && focus) {
+ gtk_widget_grab_focus(glarea_);
+ }
+}
+
+void BrowserWindowOsrGtk::SetDeviceScaleFactor(float device_scale_factor) {
+ REQUIRE_MAIN_THREAD();
+ {
+ base::AutoLock lock_scope(lock_);
+ if (device_scale_factor == device_scale_factor_) {
+ return;
+ }
+
+ // Apply some sanity checks.
+ if (device_scale_factor < 1.0f || device_scale_factor > 4.0f) {
+ return;
+ }
+
+ device_scale_factor_ = device_scale_factor;
+ }
+
+ if (browser_) {
+ browser_->GetHost()->NotifyScreenInfoChanged();
+ browser_->GetHost()->WasResized();
+ }
+}
+
+float BrowserWindowOsrGtk::GetDeviceScaleFactor() const {
+ REQUIRE_MAIN_THREAD();
+ base::AutoLock lock_scope(lock_);
+ return device_scale_factor_;
+}
+
+ClientWindowHandle BrowserWindowOsrGtk::GetWindowHandle() const {
+ REQUIRE_MAIN_THREAD();
+ return glarea_;
+}
+
+void BrowserWindowOsrGtk::OnAfterCreated(CefRefPtr<CefBrowser> browser) {
+ CEF_REQUIRE_UI_THREAD();
+}
+
+void BrowserWindowOsrGtk::OnBeforeClose(CefRefPtr<CefBrowser> browser) {
+ CEF_REQUIRE_UI_THREAD();
+
+ // Detach |this| from the ClientHandlerOsr.
+ static_cast<ClientHandlerOsr*>(client_handler_.get())->DetachOsrDelegate();
+
+ ScopedGdkThreadsEnter scoped_gdk_threads;
+
+ UnregisterDragDrop();
+
+ // Disconnect all signal handlers that reference |this|.
+ g_signal_handlers_disconnect_matched(glarea_, G_SIGNAL_MATCH_DATA, 0, 0,
+ nullptr, nullptr, this);
+
+ DisableGL();
+}
+
+bool BrowserWindowOsrGtk::GetRootScreenRect(CefRefPtr<CefBrowser> browser,
+ CefRect& rect) {
+ CEF_REQUIRE_UI_THREAD();
+ return false;
+}
+
+void BrowserWindowOsrGtk::GetViewRect(CefRefPtr<CefBrowser> browser,
+ CefRect& rect) {
+ CEF_REQUIRE_UI_THREAD();
+
+ rect.x = rect.y = 0;
+
+ if (!glarea_) {
+ // Never return an empty rectangle.
+ rect.width = rect.height = 1;
+ return;
+ }
+
+ float device_scale_factor;
+ {
+ base::AutoLock lock_scope(lock_);
+ device_scale_factor = device_scale_factor_;
+ }
+
+ // The simulated screen and view rectangle are the same. This is necessary
+ // for popup menus to be located and sized inside the view.
+ GtkAllocation allocation;
+ gtk_widget_get_allocation(glarea_, &allocation);
+ rect.width = DeviceToLogical(allocation.width, device_scale_factor);
+ if (rect.width == 0) {
+ rect.width = 1;
+ }
+ rect.height = DeviceToLogical(allocation.height, device_scale_factor);
+ if (rect.height == 0) {
+ rect.height = 1;
+ }
+}
+
+bool BrowserWindowOsrGtk::GetScreenPoint(CefRefPtr<CefBrowser> browser,
+ int viewX,
+ int viewY,
+ int& screenX,
+ int& screenY) {
+ CEF_REQUIRE_UI_THREAD();
+
+ float device_scale_factor;
+ {
+ base::AutoLock lock_scope(lock_);
+ device_scale_factor = device_scale_factor_;
+ }
+
+ // Get the widget position in the window.
+ GtkAllocation allocation;
+ gtk_widget_get_allocation(glarea_, &allocation);
+
+ // Convert from view DIP coordinates to window (pixel) coordinates.
+ screenX = allocation.x + LogicalToDevice(viewX, device_scale_factor);
+ screenY = allocation.y + LogicalToDevice(viewY, device_scale_factor);
+ return true;
+}
+
+bool BrowserWindowOsrGtk::GetScreenInfo(CefRefPtr<CefBrowser> browser,
+ CefScreenInfo& screen_info) {
+ CEF_REQUIRE_UI_THREAD();
+
+ CefRect view_rect;
+ GetViewRect(browser, view_rect);
+
+ float device_scale_factor;
+ {
+ base::AutoLock lock_scope(lock_);
+ device_scale_factor = device_scale_factor_;
+ }
+
+ screen_info.device_scale_factor = device_scale_factor;
+
+ // The screen info rectangles are used by the renderer to create and position
+ // popups. Keep popups inside the view rectangle.
+ screen_info.rect = view_rect;
+ screen_info.available_rect = view_rect;
+ return true;
+}
+
+void BrowserWindowOsrGtk::OnPopupShow(CefRefPtr<CefBrowser> browser,
+ bool show) {
+ CEF_REQUIRE_UI_THREAD();
+
+ if (!show) {
+ renderer_.ClearPopupRects();
+ browser->GetHost()->Invalidate(PET_VIEW);
+ }
+ renderer_.OnPopupShow(browser, show);
+}
+
+void BrowserWindowOsrGtk::OnPopupSize(CefRefPtr<CefBrowser> browser,
+ const CefRect& rect) {
+ CEF_REQUIRE_UI_THREAD();
+
+ float device_scale_factor;
+ {
+ base::AutoLock lock_scope(lock_);
+ device_scale_factor = device_scale_factor_;
+ }
+
+ renderer_.OnPopupSize(browser, LogicalToDevice(rect, device_scale_factor));
+}
+
+void BrowserWindowOsrGtk::OnPaint(CefRefPtr<CefBrowser> browser,
+ CefRenderHandler::PaintElementType type,
+ const CefRenderHandler::RectList& dirtyRects,
+ const void* buffer,
+ int width,
+ int height) {
+ CEF_REQUIRE_UI_THREAD();
+
+ if (width <= 2 && height <= 2) {
+ // Ignore really small buffer sizes while the widget is starting up.
+ return;
+ }
+
+ if (painting_popup_) {
+ renderer_.OnPaint(browser, type, dirtyRects, buffer, width, height);
+ return;
+ }
+
+ if (!gl_enabled_) {
+ EnableGL();
+ }
+
+ ScopedGLContext scoped_gl_context(glarea_, true);
+ if (!scoped_gl_context.IsValid()) {
+ return;
+ }
+
+ renderer_.OnPaint(browser, type, dirtyRects, buffer, width, height);
+ if (type == PET_VIEW && !renderer_.popup_rect().IsEmpty()) {
+ painting_popup_ = true;
+ browser->GetHost()->Invalidate(PET_POPUP);
+ painting_popup_ = false;
+ }
+ renderer_.Render();
+}
+
+void BrowserWindowOsrGtk::OnCursorChange(
+ CefRefPtr<CefBrowser> browser,
+ CefCursorHandle cursor,
+ cef_cursor_type_t type,
+ const CefCursorInfo& custom_cursor_info) {
+ CEF_REQUIRE_UI_THREAD();
+
+ // Retrieve the X11 display shared with Chromium.
+ CHECK(xdisplay_ != 0);
+
+ ScopedGdkThreadsEnter scoped_gdk_threads;
+
+ // Retrieve the X11 window handle for the GTK widget.
+ ::Window xwindow = GDK_WINDOW_XID(gtk_widget_get_window(glarea_));
+
+ // Set the cursor.
+ XDefineCursor(xdisplay_, xwindow, cursor);
+}
+
+bool BrowserWindowOsrGtk::StartDragging(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefDragData> drag_data,
+ CefRenderHandler::DragOperationsMask allowed_ops,
+ int x,
+ int y) {
+ CEF_REQUIRE_UI_THREAD();
+
+ if (!drag_data->HasImage()) {
+ LOG(ERROR) << "Drag image representation not available";
+ return false;
+ }
+
+ ScopedGdkThreadsEnter scoped_gdk_threads;
+
+ DragReset();
+ drag_data_ = drag_data;
+
+ // Begin drag.
+ if (drag_trigger_event_) {
+ LOG(ERROR) << "Dragging started, but last mouse event is missing";
+ DragReset();
+ return false;
+ }
+ drag_context_ = gtk_drag_begin(glarea_, drag_targets_, GDK_ACTION_COPY,
+ 1, // left mouse button
+ drag_trigger_event_);
+ if (!drag_context_) {
+ LOG(ERROR) << "GTK drag begin failed";
+ DragReset();
+ return false;
+ }
+ g_object_ref(drag_context_);
+
+ // Send drag enter event.
+ CefMouseEvent ev;
+ ev.x = x;
+ ev.y = y;
+ ev.modifiers = EVENTFLAG_LEFT_MOUSE_BUTTON;
+ browser->GetHost()->DragTargetDragEnter(drag_data, ev, allowed_ops);
+
+ return true;
+}
+
+void BrowserWindowOsrGtk::UpdateDragCursor(
+ CefRefPtr<CefBrowser> browser,
+ CefRenderHandler::DragOperation operation) {
+ CEF_REQUIRE_UI_THREAD();
+ drag_operation_ = operation;
+}
+
+void BrowserWindowOsrGtk::OnImeCompositionRangeChanged(
+ CefRefPtr<CefBrowser> browser,
+ const CefRange& selection_range,
+ const CefRenderHandler::RectList& character_bounds) {
+ CEF_REQUIRE_UI_THREAD();
+}
+
+void BrowserWindowOsrGtk::UpdateAccessibilityTree(CefRefPtr<CefValue> value) {
+ CEF_REQUIRE_UI_THREAD();
+}
+
+void BrowserWindowOsrGtk::UpdateAccessibilityLocation(
+ CefRefPtr<CefValue> value) {
+ CEF_REQUIRE_UI_THREAD();
+}
+
+void BrowserWindowOsrGtk::Create(ClientWindowHandle parent_handle) {
+ REQUIRE_MAIN_THREAD();
+ DCHECK(!glarea_);
+
+ ScopedGdkThreadsEnter scoped_gdk_threads;
+
+ glarea_ = gtk_gl_area_new();
+ DCHECK(glarea_);
+
+ gtk_widget_set_can_focus(glarea_, TRUE);
+
+ gtk_gl_area_set_auto_render(GTK_GL_AREA(glarea_), FALSE);
+
+ g_signal_connect(G_OBJECT(glarea_), "size_allocate",
+ G_CALLBACK(&BrowserWindowOsrGtk::SizeAllocation), this);
+
+ gtk_widget_set_events(
+ glarea_, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
+ GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK |
+ GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
+ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK |
+ GDK_SCROLL_MASK | GDK_FOCUS_CHANGE_MASK);
+ g_signal_connect(G_OBJECT(glarea_), "button_press_event",
+ G_CALLBACK(&BrowserWindowOsrGtk::ClickEvent), this);
+ g_signal_connect(G_OBJECT(glarea_), "button_release_event",
+ G_CALLBACK(&BrowserWindowOsrGtk::ClickEvent), this);
+ g_signal_connect(G_OBJECT(glarea_), "key_press_event",
+ G_CALLBACK(&BrowserWindowOsrGtk::KeyEvent), this);
+ g_signal_connect(G_OBJECT(glarea_), "key_release_event",
+ G_CALLBACK(&BrowserWindowOsrGtk::KeyEvent), this);
+ g_signal_connect(G_OBJECT(glarea_), "enter_notify_event",
+ G_CALLBACK(&BrowserWindowOsrGtk::MoveEvent), this);
+ g_signal_connect(G_OBJECT(glarea_), "leave_notify_event",
+ G_CALLBACK(&BrowserWindowOsrGtk::MoveEvent), this);
+ g_signal_connect(G_OBJECT(glarea_), "motion_notify_event",
+ G_CALLBACK(&BrowserWindowOsrGtk::MoveEvent), this);
+ g_signal_connect(G_OBJECT(glarea_), "scroll_event",
+ G_CALLBACK(&BrowserWindowOsrGtk::ScrollEvent), this);
+ g_signal_connect(G_OBJECT(glarea_), "focus_in_event",
+ G_CALLBACK(&BrowserWindowOsrGtk::FocusEvent), this);
+ g_signal_connect(G_OBJECT(glarea_), "focus_out_event",
+ G_CALLBACK(&BrowserWindowOsrGtk::FocusEvent), this);
+ g_signal_connect(G_OBJECT(glarea_), "touch-event",
+ G_CALLBACK(&BrowserWindowOsrGtk::TouchEvent), this);
+
+ RegisterDragDrop();
+
+ gtk_widget_set_vexpand(glarea_, TRUE);
+ gtk_grid_attach(GTK_GRID(parent_handle), glarea_, 0, 3, 1, 1);
+
+ // Make the GlArea visible in the parent container.
+ gtk_widget_show_all(parent_handle);
+}
+
+// static
+gint BrowserWindowOsrGtk::SizeAllocation(GtkWidget* widget,
+ GtkAllocation* allocation,
+ BrowserWindowOsrGtk* self) {
+ REQUIRE_MAIN_THREAD();
+ if (self->browser_.get()) {
+ // Results in a call to GetViewRect().
+ self->browser_->GetHost()->WasResized();
+ }
+ return TRUE;
+}
+
+// static
+gint BrowserWindowOsrGtk::ClickEvent(GtkWidget* widget,
+ GdkEventButton* event,
+ BrowserWindowOsrGtk* self) {
+ REQUIRE_MAIN_THREAD();
+
+ if (!self->browser_.get()) {
+ return TRUE;
+ }
+
+ CefRefPtr<CefBrowserHost> host = self->browser_->GetHost();
+
+ CefBrowserHost::MouseButtonType button_type = MBT_LEFT;
+ switch (event->button) {
+ case 1:
+ break;
+ case 2:
+ button_type = MBT_MIDDLE;
+ break;
+ case 3:
+ button_type = MBT_RIGHT;
+ break;
+ default:
+ // Other mouse buttons are not handled here.
+ return FALSE;
+ }
+
+ float device_scale_factor;
+ {
+ base::AutoLock lock_scope(self->lock_);
+ device_scale_factor = self->device_scale_factor_;
+ }
+
+ CefMouseEvent mouse_event;
+ mouse_event.x = event->x;
+ mouse_event.y = event->y;
+ self->ApplyPopupOffset(mouse_event.x, mouse_event.y);
+ DeviceToLogical(mouse_event, device_scale_factor);
+ mouse_event.modifiers = GetCefStateModifiers(event->state);
+
+ bool mouse_up = (event->type == GDK_BUTTON_RELEASE);
+ if (!mouse_up) {
+ gtk_widget_grab_focus(widget);
+ }
+
+ int click_count = 1;
+ switch (event->type) {
+ case GDK_2BUTTON_PRESS:
+ click_count = 2;
+ break;
+ case GDK_3BUTTON_PRESS:
+ click_count = 3;
+ break;
+ default:
+ break;
+ }
+
+ host->SendMouseClickEvent(mouse_event, button_type, mouse_up, click_count);
+
+ // Save mouse event that can be a possible trigger for drag.
+ if (!self->drag_context_ && button_type == MBT_LEFT) {
+ if (self->drag_trigger_event_) {
+ gdk_event_free(self->drag_trigger_event_);
+ }
+ self->drag_trigger_event_ =
+ gdk_event_copy(reinterpret_cast<GdkEvent*>(event));
+ }
+
+ return TRUE;
+}
+
+// static
+gint BrowserWindowOsrGtk::KeyEvent(GtkWidget* widget,
+ GdkEventKey* event,
+ BrowserWindowOsrGtk* self) {
+ REQUIRE_MAIN_THREAD();
+
+ if (!self->browser_.get()) {
+ return TRUE;
+ }
+
+ CefRefPtr<CefBrowserHost> host = self->browser_->GetHost();
+
+ // Based on WebKeyboardEventBuilder::Build from
+ // content/browser/renderer_host/input/web_input_event_builders_gtk.cc.
+ CefKeyEvent key_event;
+ KeyboardCode windows_key_code = GdkEventToWindowsKeyCode(event);
+ key_event.windows_key_code =
+ GetWindowsKeyCodeWithoutLocation(windows_key_code);
+ key_event.native_key_code = event->hardware_keycode;
+
+ key_event.modifiers = GetCefStateModifiers(event->state);
+ if (event->keyval >= GDK_KP_Space && event->keyval <= GDK_KP_9) {
+ key_event.modifiers |= EVENTFLAG_IS_KEY_PAD;
+ }
+ if (key_event.modifiers & EVENTFLAG_ALT_DOWN) {
+ key_event.is_system_key = true;
+ }
+
+ if (windows_key_code == VKEY_RETURN) {
+ // We need to treat the enter key as a key press of character \r. This
+ // is apparently just how webkit handles it and what it expects.
+ key_event.unmodified_character = '\r';
+ } else {
+ // FIXME: fix for non BMP chars
+ key_event.unmodified_character =
+ static_cast<int>(gdk_keyval_to_unicode(event->keyval));
+ }
+
+ // If ctrl key is pressed down, then control character shall be input.
+ if (key_event.modifiers & EVENTFLAG_CONTROL_DOWN) {
+ key_event.character = GetControlCharacter(
+ windows_key_code, key_event.modifiers & EVENTFLAG_SHIFT_DOWN);
+ } else {
+ key_event.character = key_event.unmodified_character;
+ }
+
+ if (event->type == GDK_KEY_PRESS) {
+ key_event.type = KEYEVENT_RAWKEYDOWN;
+ host->SendKeyEvent(key_event);
+ key_event.type = KEYEVENT_CHAR;
+ host->SendKeyEvent(key_event);
+ } else {
+ key_event.type = KEYEVENT_KEYUP;
+ host->SendKeyEvent(key_event);
+ }
+
+ return TRUE;
+}
+
+// static
+gint BrowserWindowOsrGtk::MoveEvent(GtkWidget* widget,
+ GdkEventMotion* event,
+ BrowserWindowOsrGtk* self) {
+ if (!self->browser_.get()) {
+ return TRUE;
+ }
+
+ CefRefPtr<CefBrowserHost> host = self->browser_->GetHost();
+
+ gint x, y;
+ GdkModifierType state;
+
+ if (event->is_hint) {
+ gdk_window_get_pointer(event->window, &x, &y, &state);
+ } else {
+ x = (gint)event->x;
+ y = (gint)event->y;
+ state = (GdkModifierType)event->state;
+ if (x == 0 && y == 0) {
+ // Invalid coordinates of (0,0) appear from time to time in
+ // enter-notify-event and leave-notify-event events. Sending them may
+ // cause StartDragging to never get called, so just ignore these.
+ return TRUE;
+ }
+ }
+
+ float device_scale_factor;
+ {
+ base::AutoLock lock_scope(self->lock_);
+ device_scale_factor = self->device_scale_factor_;
+ }
+
+ CefMouseEvent mouse_event;
+ mouse_event.x = x;
+ mouse_event.y = y;
+ self->ApplyPopupOffset(mouse_event.x, mouse_event.y);
+ DeviceToLogical(mouse_event, device_scale_factor);
+ mouse_event.modifiers = GetCefStateModifiers(state);
+
+ bool mouse_leave = (event->type == GDK_LEAVE_NOTIFY);
+ host->SendMouseMoveEvent(mouse_event, mouse_leave);
+
+ // Save mouse event that can be a possible trigger for drag.
+ if (!self->drag_context_ &&
+ (mouse_event.modifiers & EVENTFLAG_LEFT_MOUSE_BUTTON)) {
+ if (self->drag_trigger_event_) {
+ gdk_event_free(self->drag_trigger_event_);
+ }
+ self->drag_trigger_event_ =
+ gdk_event_copy(reinterpret_cast<GdkEvent*>(event));
+ }
+
+ return TRUE;
+}
+
+// static
+gint BrowserWindowOsrGtk::ScrollEvent(GtkWidget* widget,
+ GdkEventScroll* event,
+ BrowserWindowOsrGtk* self) {
+ REQUIRE_MAIN_THREAD();
+
+ if (!self->browser_.get()) {
+ return TRUE;
+ }
+
+ CefRefPtr<CefBrowserHost> host = self->browser_->GetHost();
+
+ float device_scale_factor;
+ {
+ base::AutoLock lock_scope(self->lock_);
+ device_scale_factor = self->device_scale_factor_;
+ }
+
+ CefMouseEvent mouse_event;
+ mouse_event.x = event->x;
+ mouse_event.y = event->y;
+ self->ApplyPopupOffset(mouse_event.x, mouse_event.y);
+ DeviceToLogical(mouse_event, device_scale_factor);
+ mouse_event.modifiers = GetCefStateModifiers(event->state);
+
+ static const int scrollbarPixelsPerGtkTick = 40;
+ int deltaX = 0;
+ int deltaY = 0;
+ switch (event->direction) {
+ case GDK_SCROLL_UP:
+ deltaY = scrollbarPixelsPerGtkTick;
+ break;
+ case GDK_SCROLL_DOWN:
+ deltaY = -scrollbarPixelsPerGtkTick;
+ break;
+ case GDK_SCROLL_LEFT:
+ deltaX = scrollbarPixelsPerGtkTick;
+ break;
+ case GDK_SCROLL_RIGHT:
+ deltaX = -scrollbarPixelsPerGtkTick;
+ break;
+ case GDK_SCROLL_SMOOTH:
+ NOTIMPLEMENTED();
+ break;
+ }
+
+ host->SendMouseWheelEvent(mouse_event, deltaX, deltaY);
+ return TRUE;
+}
+
+// static
+gint BrowserWindowOsrGtk::FocusEvent(GtkWidget* widget,
+ GdkEventFocus* event,
+ BrowserWindowOsrGtk* self) {
+ // May be called on the main thread and the UI thread.
+ if (self->browser_.get()) {
+ self->browser_->GetHost()->SetFocus(event->in == TRUE);
+ }
+ return TRUE;
+}
+
+// static
+gboolean BrowserWindowOsrGtk::TouchEvent(GtkWidget* widget,
+ GdkEventTouch* event,
+ BrowserWindowOsrGtk* self) {
+ REQUIRE_MAIN_THREAD();
+
+ if (!self->browser_.get()) {
+ return TRUE;
+ }
+
+ CefRefPtr<CefBrowserHost> host = self->browser_->GetHost();
+
+ float device_scale_factor;
+ {
+ base::AutoLock lock_scope(self->lock_);
+ device_scale_factor = self->device_scale_factor_;
+ }
+
+ CefTouchEvent touch_event;
+ switch (event->type) {
+ case GDK_TOUCH_BEGIN:
+ touch_event.type = CEF_TET_PRESSED;
+ break;
+ case GDK_TOUCH_UPDATE:
+ touch_event.type = CEF_TET_MOVED;
+ break;
+ case GDK_TOUCH_END:
+ touch_event.type = CEF_TET_RELEASED;
+ break;
+ default:
+ return TRUE;
+ }
+
+ touch_event.x = event->x;
+ touch_event.y = event->y;
+ touch_event.radius_x = 0;
+ touch_event.radius_y = 0;
+ touch_event.rotation_angle = 0;
+ touch_event.pressure = 0;
+ DeviceToLogical(touch_event, device_scale_factor);
+ touch_event.modifiers = GetCefStateModifiers(event->state);
+
+ host->SendTouchEvent(touch_event);
+ return TRUE;
+}
+
+bool BrowserWindowOsrGtk::IsOverPopupWidget(int x, int y) const {
+ const CefRect& rc = renderer_.popup_rect();
+ int popup_right = rc.x + rc.width;
+ int popup_bottom = rc.y + rc.height;
+ return (x >= rc.x) && (x < popup_right) && (y >= rc.y) && (y < popup_bottom);
+}
+
+int BrowserWindowOsrGtk::GetPopupXOffset() const {
+ return renderer_.original_popup_rect().x - renderer_.popup_rect().x;
+}
+
+int BrowserWindowOsrGtk::GetPopupYOffset() const {
+ return renderer_.original_popup_rect().y - renderer_.popup_rect().y;
+}
+
+void BrowserWindowOsrGtk::ApplyPopupOffset(int& x, int& y) const {
+ if (IsOverPopupWidget(x, y)) {
+ x += GetPopupXOffset();
+ y += GetPopupYOffset();
+ }
+}
+
+void BrowserWindowOsrGtk::EnableGL() {
+ CEF_REQUIRE_UI_THREAD();
+
+ if (gl_enabled_) {
+ return;
+ }
+
+ ScopedGLContext scoped_gl_context(glarea_, false);
+ if (!scoped_gl_context.IsValid()) {
+ return;
+ }
+
+ renderer_.Initialize();
+
+ gl_enabled_ = true;
+}
+
+void BrowserWindowOsrGtk::DisableGL() {
+ CEF_REQUIRE_UI_THREAD();
+
+ if (!gl_enabled_) {
+ return;
+ }
+
+ ScopedGLContext scoped_gl_context(glarea_, false);
+ if (!scoped_gl_context.IsValid()) {
+ return;
+ }
+
+ renderer_.Cleanup();
+
+ gl_enabled_ = false;
+}
+
+void BrowserWindowOsrGtk::RegisterDragDrop() {
+ REQUIRE_MAIN_THREAD();
+
+ ScopedGdkThreadsEnter scoped_gdk_threads;
+
+ // Succession of CEF d&d calls:
+ // 1. DragTargetDragEnter
+ // 2. DragTargetDragOver
+ // 3. DragTargetDragLeave - optional
+ // 4. DragSourceSystemDragEnded - optional, to cancel dragging
+ // 5. DragTargetDrop
+ // 6. DragSourceEndedAt
+ // 7. DragSourceSystemDragEnded
+
+ // Succession of GTK d&d events:
+ // 1. drag-begin-event, drag-data-get
+ // 2. drag-motion
+ // 3. drag-leave
+ // 4. drag-failed
+ // 5. drag-drop, drag-data-received
+ // 6. 7. drag-end-event
+
+ // Using gtk_drag_begin in StartDragging instead of calling
+ // gtk_drag_source_set here. Doing so because when using gtk_drag_source_set
+ // then StartDragging is being called very late, about ten DragMotion events
+ // after DragBegin, and drag icon can be set only when beginning drag.
+ // Default values for drag threshold are set to 8 pixels in both GTK and
+ // Chromium, but doesn't work as expected.
+ // --OFF--
+ // gtk_drag_source_set(glarea_, GDK_BUTTON1_MASK, nullptr, 0,
+ // GDK_ACTION_COPY);
+
+ // Source widget events.
+ g_signal_connect(G_OBJECT(glarea_), "drag_begin",
+ G_CALLBACK(&BrowserWindowOsrGtk::DragBegin), this);
+ g_signal_connect(G_OBJECT(glarea_), "drag_data_get",
+ G_CALLBACK(&BrowserWindowOsrGtk::DragDataGet), this);
+ g_signal_connect(G_OBJECT(glarea_), "drag_end",
+ G_CALLBACK(&BrowserWindowOsrGtk::DragEnd), this);
+
+ // Destination widget and its events.
+ gtk_drag_dest_set(glarea_, (GtkDestDefaults)0, (GtkTargetEntry*)nullptr, 0,
+ (GdkDragAction)GDK_ACTION_COPY);
+ g_signal_connect(G_OBJECT(glarea_), "drag_motion",
+ G_CALLBACK(&BrowserWindowOsrGtk::DragMotion), this);
+ g_signal_connect(G_OBJECT(glarea_), "drag_leave",
+ G_CALLBACK(&BrowserWindowOsrGtk::DragLeave), this);
+ g_signal_connect(G_OBJECT(glarea_), "drag_failed",
+ G_CALLBACK(&BrowserWindowOsrGtk::DragFailed), this);
+ g_signal_connect(G_OBJECT(glarea_), "drag_drop",
+ G_CALLBACK(&BrowserWindowOsrGtk::DragDrop), this);
+ g_signal_connect(G_OBJECT(glarea_), "drag_data_received",
+ G_CALLBACK(&BrowserWindowOsrGtk::DragDataReceived), this);
+}
+
+void BrowserWindowOsrGtk::UnregisterDragDrop() {
+ ScopedGdkThreadsEnter scoped_gdk_threads;
+ gtk_drag_dest_unset(glarea_);
+ // Drag events are unregistered in OnBeforeClose by calling
+ // g_signal_handlers_disconnect_matched.
+}
+
+void BrowserWindowOsrGtk::DragReset() {
+ if (drag_trigger_event_) {
+ gdk_event_free(drag_trigger_event_);
+ drag_trigger_event_ = nullptr;
+ }
+ drag_data_ = nullptr;
+ drag_operation_ = DRAG_OPERATION_NONE;
+ if (drag_context_) {
+ g_object_unref(drag_context_);
+ drag_context_ = nullptr;
+ }
+ drag_leave_ = false;
+ drag_drop_ = false;
+}
+
+// static
+void BrowserWindowOsrGtk::DragBegin(GtkWidget* widget,
+ GdkDragContext* drag_context,
+ BrowserWindowOsrGtk* self) {
+ // Load drag icon.
+ if (!self->drag_data_->HasImage()) {
+ LOG(ERROR) << "Failed to set drag icon, drag image not available";
+ return;
+ }
+
+ float device_scale_factor;
+ {
+ base::AutoLock lock_scope(self->lock_);
+ device_scale_factor = self->device_scale_factor_;
+ }
+
+ int pixel_width = 0;
+ int pixel_height = 0;
+ CefRefPtr<CefBinaryValue> image_binary =
+ self->drag_data_->GetImage()->GetAsPNG(device_scale_factor, true,
+ pixel_width, pixel_height);
+ if (!image_binary) {
+ LOG(ERROR) << "Failed to set drag icon, drag image error";
+ return;
+ }
+
+ ScopedGdkThreadsEnter scoped_gdk_threads;
+
+ size_t image_size = image_binary->GetSize();
+ guint8* image_buffer = (guint8*)malloc(image_size); // must free
+ image_binary->GetData((void*)image_buffer, image_size, 0);
+ GdkPixbufLoader* loader = nullptr; // must unref
+ GError* error = nullptr; // must free
+ GdkPixbuf* pixbuf = nullptr; // owned by loader
+ gboolean success = FALSE;
+ loader = gdk_pixbuf_loader_new_with_type("png", &error);
+ if (error == nullptr && loader) {
+ success =
+ gdk_pixbuf_loader_write(loader, image_buffer, image_size, nullptr);
+ if (success) {
+ success = gdk_pixbuf_loader_close(loader, nullptr);
+ if (success) {
+ pixbuf = gdk_pixbuf_loader_get_pixbuf(loader);
+ if (pixbuf) {
+ CefPoint image_hotspot = self->drag_data_->GetImageHotspot();
+ int hotspot_x = image_hotspot.x;
+ int hotspot_y = image_hotspot.y;
+ gtk_drag_set_icon_pixbuf(drag_context, pixbuf, hotspot_x, hotspot_y);
+ } else {
+ LOG(ERROR) << "Failed to set drag icon, pixbuf error";
+ }
+ } else {
+ LOG(ERROR) << "Failed to set drag icon, loader close error";
+ }
+ } else {
+ LOG(ERROR) << "Failed to set drag icon, loader write error";
+ }
+ } else {
+ LOG(ERROR) << "Failed to set drag icon, loader creation error";
+ }
+ if (loader) {
+ g_object_unref(loader); // unref
+ }
+ if (error) {
+ g_error_free(error); // free
+ }
+ free(image_buffer); // free
+}
+
+// static
+void BrowserWindowOsrGtk::DragDataGet(GtkWidget* widget,
+ GdkDragContext* drag_context,
+ GtkSelectionData* data,
+ guint info,
+ guint time,
+ BrowserWindowOsrGtk* self) {
+ REQUIRE_MAIN_THREAD();
+ // No drag targets are set so this callback is never called.
+}
+
+// static
+void BrowserWindowOsrGtk::DragEnd(GtkWidget* widget,
+ GdkDragContext* drag_context,
+ BrowserWindowOsrGtk* self) {
+ REQUIRE_MAIN_THREAD();
+
+ if (self->browser_) {
+ // Sometimes there is DragEnd event generated without prior DragDrop.
+ // Maybe related to drag-leave bug described in comments in DragLeave.
+ if (!self->drag_drop_) {
+ // Real coordinates not available.
+ self->browser_->GetHost()->DragSourceEndedAt(-1, -1,
+ self->drag_operation_);
+ }
+ self->browser_->GetHost()->DragSourceSystemDragEnded();
+ }
+
+ self->DragReset();
+}
+
+// static
+gboolean BrowserWindowOsrGtk::DragMotion(GtkWidget* widget,
+ GdkDragContext* drag_context,
+ gint x,
+ gint y,
+ guint time,
+ BrowserWindowOsrGtk* self) {
+ REQUIRE_MAIN_THREAD();
+
+ float device_scale_factor;
+ {
+ base::AutoLock lock_scope(self->lock_);
+ device_scale_factor = self->device_scale_factor_;
+ }
+
+ // MoveEvent is never called during drag & drop, so must call
+ // SendMouseMoveEvent here.
+ CefMouseEvent mouse_event;
+ mouse_event.x = x;
+ mouse_event.y = y;
+ mouse_event.modifiers = EVENTFLAG_LEFT_MOUSE_BUTTON;
+ self->ApplyPopupOffset(mouse_event.x, mouse_event.y);
+ DeviceToLogical(mouse_event, device_scale_factor);
+ if (self->browser_) {
+ bool mouse_leave = self->drag_leave_;
+ self->browser_->GetHost()->SendMouseMoveEvent(mouse_event, mouse_leave);
+ }
+
+ // Mouse event.
+ CefMouseEvent ev;
+ ev.x = x;
+ ev.y = y;
+ ev.modifiers = EVENTFLAG_LEFT_MOUSE_BUTTON;
+
+ CefBrowserHost::DragOperationsMask allowed_ops =
+ GetDragOperationsMask(drag_context);
+
+ // Send drag enter event if needed.
+ if (self->drag_leave_ && self->browser_) {
+ self->browser_->GetHost()->DragTargetDragEnter(self->drag_data_, ev,
+ allowed_ops);
+ }
+
+ // Send drag over event.
+ if (self->browser_) {
+ self->browser_->GetHost()->DragTargetDragOver(ev, allowed_ops);
+ }
+
+ // Update GTK drag status.
+ if (widget == self->glarea_) {
+ gdk_drag_status(drag_context, GDK_ACTION_COPY, time);
+ if (self->drag_leave_) {
+ self->drag_leave_ = false;
+ }
+ return TRUE;
+ } else {
+ LOG(WARNING) << "Invalid drag destination widget";
+ gdk_drag_status(drag_context, (GdkDragAction)0, time);
+ return FALSE;
+ }
+}
+
+// static
+void BrowserWindowOsrGtk::DragLeave(GtkWidget* widget,
+ GdkDragContext* drag_context,
+ guint time,
+ BrowserWindowOsrGtk* self) {
+ REQUIRE_MAIN_THREAD();
+
+ // There is no drag-enter event in GTK. The first drag-motion event
+ // after drag-leave will be a drag-enter event.
+
+ // There seems to be a bug during GTK drop, drag-leave event is generated
+ // just before drag-drop. A solution is to call DragTargetDragEnter
+ // and DragTargetDragOver in DragDrop when drag_leave_ is true.
+
+ // Send drag leave event.
+ if (self->browser_) {
+ self->browser_->GetHost()->DragTargetDragLeave();
+ }
+
+ self->drag_leave_ = true;
+}
+
+// static
+gboolean BrowserWindowOsrGtk::DragFailed(GtkWidget* widget,
+ GdkDragContext* drag_context,
+ GtkDragResult result,
+ BrowserWindowOsrGtk* self) {
+ REQUIRE_MAIN_THREAD();
+
+ // Send drag end coordinates and system drag ended event.
+ if (self->browser_) {
+ // Real coordinates not available.
+ self->browser_->GetHost()->DragSourceEndedAt(-1, -1, self->drag_operation_);
+ self->browser_->GetHost()->DragSourceSystemDragEnded();
+ }
+
+ self->DragReset();
+ return TRUE;
+}
+
+// static
+gboolean BrowserWindowOsrGtk::DragDrop(GtkWidget* widget,
+ GdkDragContext* drag_context,
+ gint x,
+ gint y,
+ guint time,
+ BrowserWindowOsrGtk* self) {
+ REQUIRE_MAIN_THREAD();
+
+ // Finish GTK drag.
+ gtk_drag_finish(drag_context, TRUE, FALSE, time);
+
+ // Mouse event.
+ CefMouseEvent ev;
+ ev.x = x;
+ ev.y = y;
+ ev.modifiers = EVENTFLAG_LEFT_MOUSE_BUTTON;
+
+ CefBrowserHost::DragOperationsMask allowed_ops =
+ GetDragOperationsMask(drag_context);
+
+ // Send drag enter/over events if needed (read comment in DragLeave).
+ if (self->drag_leave_ && self->browser_) {
+ self->browser_->GetHost()->DragTargetDragEnter(self->drag_data_, ev,
+ allowed_ops);
+ self->browser_->GetHost()->DragTargetDragOver(ev, allowed_ops);
+ }
+
+ // Send drag drop event.
+ if (self->browser_) {
+ self->browser_->GetHost()->DragTargetDrop(ev);
+ }
+
+ // Send drag end coordinates.
+ if (self->browser_) {
+ self->browser_->GetHost()->DragSourceEndedAt(x, y, self->drag_operation_);
+ }
+
+ self->drag_drop_ = true;
+ return TRUE;
+}
+
+// static
+void BrowserWindowOsrGtk::DragDataReceived(GtkWidget* widget,
+ GdkDragContext* drag_context,
+ gint x,
+ gint y,
+ GtkSelectionData* data,
+ guint info,
+ guint time,
+ BrowserWindowOsrGtk* self) {
+ REQUIRE_MAIN_THREAD();
+ // This callback is never called because DragDrop does not call
+ // gtk_drag_get_data, as only dragging inside web view is supported.
+}
+
+} // namespace client
diff --git a/tests/cefclient/browser/browser_window_osr_gtk.h b/tests/cefclient/browser/browser_window_osr_gtk.h
new file mode 100644
index 00000000..18bd3805
--- /dev/null
+++ b/tests/cefclient/browser/browser_window_osr_gtk.h
@@ -0,0 +1,215 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_BROWSER_WINDOW_OSR_GTK_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_BROWSER_WINDOW_OSR_GTK_H_
+#pragma once
+
+#include "include/base/cef_lock.h"
+
+#include "tests/cefclient/browser/browser_window.h"
+#include "tests/cefclient/browser/client_handler_osr.h"
+#include "tests/cefclient/browser/osr_renderer.h"
+
+namespace client {
+
+// Represents a native child window hosting a single off-screen browser
+// instance. The methods of this class must be called on the main thread unless
+// otherwise indicated.
+class BrowserWindowOsrGtk : public BrowserWindow,
+ public ClientHandlerOsr::OsrDelegate {
+ public:
+ typedef void* CefXIDeviceEvent;
+
+ // Constructor may be called on any thread.
+ // |delegate| must outlive this object.
+ BrowserWindowOsrGtk(BrowserWindow::Delegate* delegate,
+ bool with_controls,
+ const std::string& startup_url,
+ const OsrRendererSettings& settings);
+
+ // Called from RootWindowGtk::CreateRootWindow before CreateBrowser.
+ void set_xdisplay(XDisplay* xdisplay);
+
+ // BrowserWindow methods.
+ void CreateBrowser(ClientWindowHandle parent_handle,
+ const CefRect& rect,
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefDictionaryValue> extra_info,
+ CefRefPtr<CefRequestContext> request_context) override;
+ void GetPopupConfig(CefWindowHandle temp_handle,
+ CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient>& client,
+ CefBrowserSettings& settings) override;
+ void ShowPopup(ClientWindowHandle parent_handle,
+ int x,
+ int y,
+ size_t width,
+ size_t height) override;
+ void Show() override;
+ void Hide() override;
+ void SetBounds(int x, int y, size_t width, size_t height) override;
+ void SetFocus(bool focus) override;
+ void SetDeviceScaleFactor(float device_scale_factor) override;
+ float GetDeviceScaleFactor() const override;
+ ClientWindowHandle GetWindowHandle() const override;
+
+ // ClientHandlerOsr::OsrDelegate methods.
+ void OnAfterCreated(CefRefPtr<CefBrowser> browser) override;
+ void OnBeforeClose(CefRefPtr<CefBrowser> browser) override;
+ bool GetRootScreenRect(CefRefPtr<CefBrowser> browser, CefRect& rect) override;
+ void GetViewRect(CefRefPtr<CefBrowser> browser, CefRect& rect) override;
+ bool GetScreenPoint(CefRefPtr<CefBrowser> browser,
+ int viewX,
+ int viewY,
+ int& screenX,
+ int& screenY) override;
+ bool GetScreenInfo(CefRefPtr<CefBrowser> browser,
+ CefScreenInfo& screen_info) override;
+ void OnPopupShow(CefRefPtr<CefBrowser> browser, bool show) override;
+ void OnPopupSize(CefRefPtr<CefBrowser> browser, const CefRect& rect) override;
+ void OnPaint(CefRefPtr<CefBrowser> browser,
+ CefRenderHandler::PaintElementType type,
+ const CefRenderHandler::RectList& dirtyRects,
+ const void* buffer,
+ int width,
+ int height) override;
+ void OnCursorChange(CefRefPtr<CefBrowser> browser,
+ CefCursorHandle cursor,
+ cef_cursor_type_t type,
+ const CefCursorInfo& custom_cursor_info) override;
+ bool StartDragging(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefDragData> drag_data,
+ CefRenderHandler::DragOperationsMask allowed_ops,
+ int x,
+ int y) override;
+ void UpdateDragCursor(CefRefPtr<CefBrowser> browser,
+ CefRenderHandler::DragOperation operation) override;
+ void OnImeCompositionRangeChanged(
+ CefRefPtr<CefBrowser> browser,
+ const CefRange& selection_range,
+ const CefRenderHandler::RectList& character_bounds) override;
+ void UpdateAccessibilityTree(CefRefPtr<CefValue> value) override;
+ void UpdateAccessibilityLocation(CefRefPtr<CefValue> value) override;
+
+ private:
+ ~BrowserWindowOsrGtk();
+
+ // Create the GTK GlArea.
+ void Create(ClientWindowHandle parent_handle);
+
+ // Signal handlers for the GTK GlArea.
+ static gint SizeAllocation(GtkWidget* widget,
+ GtkAllocation* allocation,
+ BrowserWindowOsrGtk* self);
+ static gint ClickEvent(GtkWidget* widget,
+ GdkEventButton* event,
+ BrowserWindowOsrGtk* self);
+ static gint KeyEvent(GtkWidget* widget,
+ GdkEventKey* event,
+ BrowserWindowOsrGtk* self);
+ static gint MoveEvent(GtkWidget* widget,
+ GdkEventMotion* event,
+ BrowserWindowOsrGtk* self);
+ static gint ScrollEvent(GtkWidget* widget,
+ GdkEventScroll* event,
+ BrowserWindowOsrGtk* self);
+ static gint FocusEvent(GtkWidget* widget,
+ GdkEventFocus* event,
+ BrowserWindowOsrGtk* self);
+ static gboolean TouchEvent(GtkWidget* widget,
+ GdkEventTouch* event,
+ BrowserWindowOsrGtk* self);
+
+ void RegisterTouch();
+
+ bool IsOverPopupWidget(int x, int y) const;
+ int GetPopupXOffset() const;
+ int GetPopupYOffset() const;
+ void ApplyPopupOffset(int& x, int& y) const;
+
+ void EnableGL();
+ void DisableGL();
+
+ // Drag & drop
+ void RegisterDragDrop();
+ void UnregisterDragDrop();
+ void DragReset();
+ static void DragBegin(GtkWidget* widget,
+ GdkDragContext* drag_context,
+ BrowserWindowOsrGtk* self);
+ static void DragDataGet(GtkWidget* widget,
+ GdkDragContext* drag_context,
+ GtkSelectionData* data,
+ guint info,
+ guint time,
+ BrowserWindowOsrGtk* self);
+ static void DragEnd(GtkWidget* widget,
+ GdkDragContext* drag_context,
+ BrowserWindowOsrGtk* self);
+ static gboolean DragMotion(GtkWidget* widget,
+ GdkDragContext* drag_context,
+ gint x,
+ gint y,
+ guint time,
+ BrowserWindowOsrGtk* self);
+ static void DragLeave(GtkWidget* widget,
+ GdkDragContext* drag_context,
+ guint time,
+ BrowserWindowOsrGtk* self);
+ static gboolean DragFailed(GtkWidget* widget,
+ GdkDragContext* drag_context,
+ GtkDragResult result,
+ BrowserWindowOsrGtk* self);
+ static gboolean DragDrop(GtkWidget* widget,
+ GdkDragContext* drag_context,
+ gint x,
+ gint y,
+ guint time,
+ BrowserWindowOsrGtk* self);
+ static void DragDataReceived(GtkWidget* widget,
+ GdkDragContext* drag_context,
+ gint x,
+ gint y,
+ GtkSelectionData* data,
+ guint info,
+ guint time,
+ BrowserWindowOsrGtk* self);
+ static GdkFilterReturn EventFilter(GdkXEvent* gdk_xevent,
+ GdkEvent* event,
+ gpointer data);
+
+ XDisplay* xdisplay_;
+
+ // Members only accessed on the UI thread.
+ OsrRenderer renderer_;
+ bool gl_enabled_;
+ bool painting_popup_;
+
+ // Members only accessed on the main thread.
+ bool hidden_;
+
+ // Members protected by the GDK global lock.
+ ClientWindowHandle glarea_;
+
+ // Drag & drop
+ GdkEvent* drag_trigger_event_; // mouse event, a possible trigger for drag
+ CefRefPtr<CefDragData> drag_data_;
+ CefRenderHandler::DragOperation drag_operation_;
+ GdkDragContext* drag_context_;
+ GtkTargetList* drag_targets_;
+ bool drag_leave_;
+ bool drag_drop_;
+
+ mutable base::Lock lock_;
+
+ // Access to these members must be protected by |lock_|.
+ float device_scale_factor_;
+
+ DISALLOW_COPY_AND_ASSIGN(BrowserWindowOsrGtk);
+};
+
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_BROWSER_WINDOW_OSR_GTK_H_
diff --git a/tests/cefclient/browser/browser_window_osr_mac.h b/tests/cefclient/browser/browser_window_osr_mac.h
new file mode 100644
index 00000000..130a77c1
--- /dev/null
+++ b/tests/cefclient/browser/browser_window_osr_mac.h
@@ -0,0 +1,104 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_BROWSER_WINDOW_OSR_MAC_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_BROWSER_WINDOW_OSR_MAC_H_
+#pragma once
+
+#include "tests/cefclient/browser/browser_window.h"
+#include "tests/cefclient/browser/client_handler_osr.h"
+#include "tests/cefclient/browser/osr_renderer.h"
+#include "tests/cefclient/browser/text_input_client_osr_mac.h"
+
+namespace client {
+
+class BrowserWindowOsrMacImpl;
+
+// Represents a native child window hosting a single off-screen browser
+// instance. The methods of this class must be called on the main thread unless
+// otherwise indicated.
+class BrowserWindowOsrMac : public BrowserWindow,
+ public ClientHandlerOsr::OsrDelegate {
+ public:
+ // Constructor may be called on any thread.
+ // |delegate| must outlive this object.
+ BrowserWindowOsrMac(BrowserWindow::Delegate* delegate,
+ bool with_controls,
+ const std::string& startup_url,
+ const OsrRendererSettings& settings);
+ ~BrowserWindowOsrMac();
+
+ // BrowserWindow methods.
+ void CreateBrowser(ClientWindowHandle parent_handle,
+ const CefRect& rect,
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefDictionaryValue> extra_info,
+ CefRefPtr<CefRequestContext> request_context) override;
+ void GetPopupConfig(CefWindowHandle temp_handle,
+ CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient>& client,
+ CefBrowserSettings& settings) override;
+ void ShowPopup(ClientWindowHandle parent_handle,
+ int x,
+ int y,
+ size_t width,
+ size_t height) override;
+ void Show() override;
+ void Hide() override;
+ void SetBounds(int x, int y, size_t width, size_t height) override;
+ void SetFocus(bool focus) override;
+ void SetDeviceScaleFactor(float device_scale_factor) override;
+ float GetDeviceScaleFactor() const override;
+ ClientWindowHandle GetWindowHandle() const override;
+
+ // ClientHandlerOsr::OsrDelegate methods.
+ void OnAfterCreated(CefRefPtr<CefBrowser> browser) override;
+ void OnBeforeClose(CefRefPtr<CefBrowser> browser) override;
+ bool GetRootScreenRect(CefRefPtr<CefBrowser> browser, CefRect& rect) override;
+ void GetViewRect(CefRefPtr<CefBrowser> browser, CefRect& rect) override;
+ bool GetScreenPoint(CefRefPtr<CefBrowser> browser,
+ int viewX,
+ int viewY,
+ int& screenX,
+ int& screenY) override;
+ bool GetScreenInfo(CefRefPtr<CefBrowser> browser,
+ CefScreenInfo& screen_info) override;
+ void OnPopupShow(CefRefPtr<CefBrowser> browser, bool show) override;
+ void OnPopupSize(CefRefPtr<CefBrowser> browser, const CefRect& rect) override;
+ void OnPaint(CefRefPtr<CefBrowser> browser,
+ CefRenderHandler::PaintElementType type,
+ const CefRenderHandler::RectList& dirtyRects,
+ const void* buffer,
+ int width,
+ int height) override;
+ void OnCursorChange(CefRefPtr<CefBrowser> browser,
+ CefCursorHandle cursor,
+ cef_cursor_type_t type,
+ const CefCursorInfo& custom_cursor_info) override;
+ bool StartDragging(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefDragData> drag_data,
+ CefRenderHandler::DragOperationsMask allowed_ops,
+ int x,
+ int y) override;
+ void UpdateDragCursor(CefRefPtr<CefBrowser> browser,
+ CefRenderHandler::DragOperation operation) override;
+ void OnImeCompositionRangeChanged(
+ CefRefPtr<CefBrowser> browser,
+ const CefRange& selection_range,
+ const CefRenderHandler::RectList& character_bounds) override;
+
+ void UpdateAccessibilityTree(CefRefPtr<CefValue> value) override;
+ void UpdateAccessibilityLocation(CefRefPtr<CefValue> value) override;
+
+ private:
+ std::unique_ptr<BrowserWindowOsrMacImpl> impl_;
+
+ DISALLOW_COPY_AND_ASSIGN(BrowserWindowOsrMac);
+
+ friend class BrowserWindowOsrMacImpl;
+};
+
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_BROWSER_WINDOW_OSR_MAC_H_
diff --git a/tests/cefclient/browser/browser_window_osr_mac.mm b/tests/cefclient/browser/browser_window_osr_mac.mm
new file mode 100644
index 00000000..d72f0a9f
--- /dev/null
+++ b/tests/cefclient/browser/browser_window_osr_mac.mm
@@ -0,0 +1,1986 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/browser_window_osr_mac.h"
+
+#include <Cocoa/Cocoa.h>
+#include <OpenGL/gl.h>
+#import <objc/runtime.h>
+
+#include "include/base/cef_logging.h"
+#include "include/cef_parser.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "tests/cefclient/browser/bytes_write_handler.h"
+#include "tests/cefclient/browser/main_context.h"
+#include "tests/cefclient/browser/osr_accessibility_helper.h"
+#include "tests/cefclient/browser/osr_accessibility_node.h"
+#include "tests/cefclient/browser/text_input_client_osr_mac.h"
+#include "tests/shared/browser/geometry_util.h"
+#include "tests/shared/browser/main_message_loop.h"
+
+#import <AppKit/NSAccessibility.h>
+
+@interface BrowserOpenGLView
+ : NSOpenGLView <NSDraggingSource, NSDraggingDestination, NSAccessibility> {
+ @private
+ NSTrackingArea* tracking_area_;
+ client::BrowserWindowOsrMac* browser_window_;
+ client::OsrRenderer* renderer_;
+ NSPoint last_mouse_pos_;
+ NSPoint cur_mouse_pos_;
+ bool rotating_;
+
+ bool was_last_mouse_down_on_view_;
+
+ float device_scale_factor_;
+
+ // Drag and drop.
+ CefRefPtr<CefDragData> current_drag_data_;
+ NSDragOperation current_drag_op_;
+ NSDragOperation current_allowed_ops_;
+ NSPasteboard* pasteboard_;
+ NSString* fileUTI_;
+
+ // For intreacting with IME.
+ NSTextInputContext* text_input_context_osr_mac_;
+ CefTextInputClientOSRMac* text_input_client_;
+
+ // Manages Accessibility Tree
+ client::OsrAccessibilityHelper* accessibility_helper_;
+
+ // Event monitor for scroll wheel end event.
+ id endWheelMonitor_;
+}
+
+@end // @interface BrowserOpenGLView
+
+namespace {
+
+NSString* const kCEFDragDummyPboardType = @"org.CEF.drag-dummy-type";
+NSString* const kNSURLTitlePboardType = @"public.url-name";
+
+class ScopedGLContext {
+ public:
+ ScopedGLContext(BrowserOpenGLView* view, bool swap_buffers)
+ : swap_buffers_(swap_buffers) {
+ context_ = [view openGLContext];
+ [context_ makeCurrentContext];
+ }
+ ~ScopedGLContext() {
+ [NSOpenGLContext clearCurrentContext];
+ if (swap_buffers_) {
+ [context_ flushBuffer];
+ }
+ }
+
+ private:
+ NSOpenGLContext* context_;
+ const bool swap_buffers_;
+};
+
+NSPoint ConvertPointFromWindowToScreen(NSWindow* window, NSPoint point) {
+ NSRect point_rect = NSMakeRect(point.x, point.y, 0, 0);
+ return [window convertRectToScreen:point_rect].origin;
+}
+
+} // namespace
+
+@implementation BrowserOpenGLView
+
+- (id)initWithFrame:(NSRect)frame
+ andBrowserWindow:(client::BrowserWindowOsrMac*)browser_window
+ andRenderer:(client::OsrRenderer*)renderer {
+ NSOpenGLPixelFormat* pixelFormat = [[NSOpenGLPixelFormat alloc]
+ initWithAttributes:(NSOpenGLPixelFormatAttribute[]){
+ NSOpenGLPFADoubleBuffer, NSOpenGLPFADepthSize, 32,
+ 0}];
+#if !__has_feature(objc_arc)
+ [pixelFormat autorelease];
+#endif // !__has_feature(objc_arc)
+
+ if (self = [super initWithFrame:frame pixelFormat:pixelFormat]) {
+ browser_window_ = browser_window;
+ renderer_ = renderer;
+ rotating_ = false;
+ endWheelMonitor_ = nil;
+ device_scale_factor_ = 1.0f;
+
+ tracking_area_ = [[NSTrackingArea alloc]
+ initWithRect:frame
+ options:NSTrackingMouseMoved | NSTrackingActiveInActiveApp |
+ NSTrackingInVisibleRect
+ owner:self
+ userInfo:nil];
+ [self addTrackingArea:tracking_area_];
+
+ // enable HiDPI buffer
+ [self setWantsBestResolutionOpenGLSurface:YES];
+
+ [self resetDragDrop];
+
+ NSArray* types = [NSArray
+ arrayWithObjects:kCEFDragDummyPboardType, NSStringPboardType,
+ NSFilenamesPboardType, NSPasteboardTypeString, nil];
+ [self registerForDraggedTypes:types];
+ }
+
+ return self;
+}
+
+- (void)dealloc {
+ [[NSNotificationCenter defaultCenter]
+ removeObserver:self
+ name:NSWindowDidChangeBackingPropertiesNotification
+ object:nil];
+#if !__has_feature(objc_arc)
+ if (text_input_context_osr_mac_) {
+ [text_input_client_ release];
+ [text_input_context_osr_mac_ release];
+ }
+ [super dealloc];
+#endif // !__has_feature(objc_arc)
+}
+
+- (void)detach {
+ renderer_ = nullptr;
+ browser_window_ = nullptr;
+ if (text_input_client_) {
+ [text_input_client_ detach];
+ }
+}
+
+- (CefRefPtr<CefBrowser>)getBrowser {
+ if (browser_window_) {
+ return browser_window_->GetBrowser();
+ }
+ return nullptr;
+}
+
+- (void)setFrame:(NSRect)frameRect {
+ CefRefPtr<CefBrowser> browser = [self getBrowser];
+ if (!browser.get()) {
+ return;
+ }
+
+ [super setFrame:frameRect];
+ browser->GetHost()->WasResized();
+}
+
+- (void)sendMouseClick:(NSEvent*)event
+ button:(CefBrowserHost::MouseButtonType)type
+ isUp:(bool)isUp {
+ CefRefPtr<CefBrowser> browser = [self getBrowser];
+ if (!browser.get()) {
+ return;
+ }
+
+ CefMouseEvent mouseEvent;
+ [self getMouseEvent:mouseEvent forEvent:event];
+
+ // |point| is in OS X view coordinates.
+ NSPoint point = [self getClickPointForEvent:event];
+
+ // Convert to device coordinates.
+ point = [self convertPointToBackingInternal:point];
+
+ if (!isUp) {
+ was_last_mouse_down_on_view_ = ![self isOverPopupWidgetX:point.x
+ andY:point.y];
+ } else if (was_last_mouse_down_on_view_ &&
+ [self isOverPopupWidgetX:point.x andY:point.y] &&
+ ([self getPopupXOffset] || [self getPopupYOffset])) {
+ return;
+ }
+
+ browser->GetHost()->SendMouseClickEvent(mouseEvent, type, isUp,
+ static_cast<int>([event clickCount]));
+}
+
+- (void)mouseDown:(NSEvent*)event {
+ [self sendMouseClick:event button:MBT_LEFT isUp:false];
+}
+
+- (void)rightMouseDown:(NSEvent*)event {
+ if ([event modifierFlags] & NSEventModifierFlagShift) {
+ // Start rotation effect.
+ last_mouse_pos_ = cur_mouse_pos_ = [self getClickPointForEvent:event];
+ rotating_ = true;
+ return;
+ }
+
+ [self sendMouseClick:event button:MBT_RIGHT isUp:false];
+}
+
+- (void)otherMouseDown:(NSEvent*)event {
+ [self sendMouseClick:event button:MBT_MIDDLE isUp:false];
+}
+
+- (void)mouseUp:(NSEvent*)event {
+ [self sendMouseClick:event button:MBT_LEFT isUp:true];
+}
+
+- (void)rightMouseUp:(NSEvent*)event {
+ if (rotating_) {
+ // End rotation effect.
+ renderer_->SetSpin(0, 0);
+ rotating_ = false;
+ [self setNeedsDisplay:YES];
+ return;
+ }
+ [self sendMouseClick:event button:MBT_RIGHT isUp:true];
+}
+
+- (void)otherMouseUp:(NSEvent*)event {
+ [self sendMouseClick:event button:MBT_MIDDLE isUp:true];
+}
+
+- (void)mouseMoved:(NSEvent*)event {
+ CefRefPtr<CefBrowser> browser = [self getBrowser];
+ if (!browser.get()) {
+ return;
+ }
+
+ if (rotating_) {
+ // Apply rotation effect.
+ cur_mouse_pos_ = [self getClickPointForEvent:event];
+ ;
+ renderer_->IncrementSpin((cur_mouse_pos_.x - last_mouse_pos_.x),
+ (cur_mouse_pos_.y - last_mouse_pos_.y));
+ last_mouse_pos_ = cur_mouse_pos_;
+ [self setNeedsDisplay:YES];
+ return;
+ }
+
+ CefMouseEvent mouseEvent;
+ [self getMouseEvent:mouseEvent forEvent:event];
+
+ browser->GetHost()->SendMouseMoveEvent(mouseEvent, false);
+}
+
+- (void)mouseDragged:(NSEvent*)event {
+ [self mouseMoved:event];
+}
+
+- (void)rightMouseDragged:(NSEvent*)event {
+ [self mouseMoved:event];
+}
+
+- (void)otherMouseDragged:(NSEvent*)event {
+ [self mouseMoved:event];
+}
+
+- (void)mouseEntered:(NSEvent*)event {
+ [self mouseMoved:event];
+}
+
+- (void)mouseExited:(NSEvent*)event {
+ CefRefPtr<CefBrowser> browser = [self getBrowser];
+ if (!browser.get()) {
+ return;
+ }
+
+ CefMouseEvent mouseEvent;
+ [self getMouseEvent:mouseEvent forEvent:event];
+
+ browser->GetHost()->SendMouseMoveEvent(mouseEvent, true);
+}
+
+- (void)keyDown:(NSEvent*)event {
+ CefRefPtr<CefBrowser> browser = [self getBrowser];
+ if (!browser.get() || !text_input_context_osr_mac_) {
+ return;
+ }
+
+ if ([event type] != NSEventTypeFlagsChanged) {
+ if (text_input_client_) {
+ [text_input_client_ HandleKeyEventBeforeTextInputClient:event];
+
+ // The return value of this method seems to always be set to YES, thus we
+ // ignore it and ask the host view whether IME is active or not.
+ [text_input_context_osr_mac_ handleEvent:event];
+
+ CefKeyEvent keyEvent;
+ [self getKeyEvent:keyEvent forEvent:event];
+
+ [text_input_client_ HandleKeyEventAfterTextInputClient:keyEvent];
+ }
+ }
+
+ // Check for Caps lock and Toggle Touch Emulation
+ if (client::MainContext::Get()->TouchEventsEnabled()) {
+ [self toggleTouchEmulation:event];
+ }
+}
+
+// OSX does not have touch screens, so we emulate it by mapping multitouch
+// events on TrackPad to Touch Events on Screen. To ensure it does not
+// interfere with other Trackpad events, this mapping is only enabled if
+// touch-events=enabled commandline is passed and caps lock key is on.
+- (void)toggleTouchEmulation:(NSEvent*)event {
+ if ([event type] == NSEventTypeFlagsChanged && [event keyCode] == 0x39) {
+ NSUInteger flags = [event modifierFlags];
+ BOOL touch_enabled = flags & NSEventModifierFlagCapsLock ? YES : NO;
+ if (touch_enabled) {
+ self.allowedTouchTypes |= NSTouchTypeMaskDirect;
+ } else {
+ self.allowedTouchTypes &= ~NSTouchTypeMaskDirect;
+ }
+ }
+}
+
+- (cef_touch_event_type_t)getTouchPhase:(NSTouchPhase)phase {
+ cef_touch_event_type_t event_type = CEF_TET_RELEASED;
+ switch (phase) {
+ case NSTouchPhaseBegan:
+ event_type = CEF_TET_PRESSED;
+ break;
+ case NSTouchPhaseMoved:
+ event_type = CEF_TET_MOVED;
+ break;
+ case NSTouchPhaseEnded:
+ event_type = CEF_TET_RELEASED;
+ break;
+ case NSTouchPhaseCancelled:
+ event_type = CEF_TET_CANCELLED;
+ break;
+ default:
+ break;
+ }
+ return event_type;
+}
+
+// Translate NSTouch events to CefTouchEvents and send to browser.
+- (void)sendTouchEvent:(NSEvent*)event touchPhase:(NSTouchPhase)phase {
+ int modifiers = [self getModifiersForEvent:event];
+ CefRefPtr<CefBrowser> browser = [self getBrowser];
+
+ NSSet* touches = [event touchesMatchingPhase:phase inView:self];
+
+ for (NSTouch* touch in touches) {
+ // Convert NSTouch to CefTouchEvent.
+ CefTouchEvent touch_event;
+
+ // NSTouch.identity is unique during the life of the touch
+ touch_event.id = static_cast<int>(touch.identity.hash);
+ touch_event.type = [self getTouchPhase:phase];
+
+ NSPoint scaled_pos = [touch normalizedPosition];
+ NSSize view_size = [self bounds].size;
+
+ // Map point on Touch Device to View coordinates.
+ NSPoint touch_point = NSMakePoint(scaled_pos.x * view_size.width,
+ scaled_pos.y * view_size.height);
+
+ NSPoint contentLocal = [self convertPoint:touch_point fromView:nil];
+ NSPoint point;
+ point.x = contentLocal.x;
+ point.y = [self frame].size.height - contentLocal.y; // Flip y.
+
+ // Convert to device coordinates.
+ point = [self convertPointToBackingInternal:point];
+
+ int device_x = point.x;
+ int device_y = point.y;
+
+ const float device_scale_factor = [self getDeviceScaleFactor];
+ // Convert to browser view coordinates.
+ touch_event.x = client::DeviceToLogical(device_x, device_scale_factor);
+ touch_event.y = client::DeviceToLogical(device_y, device_scale_factor);
+
+ touch_event.radius_x = 0;
+ touch_event.radius_y = 0;
+
+ touch_event.rotation_angle = 0;
+ touch_event.pressure = 0;
+
+ touch_event.modifiers = modifiers;
+
+ // Notify the browser of touch event.
+ browser->GetHost()->SendTouchEvent(touch_event);
+ }
+}
+
+- (void)touchesBeganWithEvent:(NSEvent*)event {
+ [self sendTouchEvent:event touchPhase:NSTouchPhaseBegan];
+}
+
+- (void)touchesMovedWithEvent:(NSEvent*)event {
+ [self sendTouchEvent:event touchPhase:NSTouchPhaseMoved];
+}
+
+- (void)touchesEndedWithEvent:(NSEvent*)event {
+ [self sendTouchEvent:event touchPhase:NSTouchPhaseEnded];
+}
+
+- (void)touchesCancelledWithEvent:(NSEvent*)event {
+ [self sendTouchEvent:event touchPhase:NSTouchPhaseCancelled];
+}
+
+- (void)keyUp:(NSEvent*)event {
+ CefRefPtr<CefBrowser> browser = [self getBrowser];
+ if (!browser.get()) {
+ return;
+ }
+
+ CefKeyEvent keyEvent;
+ [self getKeyEvent:keyEvent forEvent:event];
+
+ keyEvent.type = KEYEVENT_KEYUP;
+ browser->GetHost()->SendKeyEvent(keyEvent);
+}
+
+- (void)flagsChanged:(NSEvent*)event {
+ if ([self isKeyUpEvent:event]) {
+ [self keyUp:event];
+ } else {
+ [self keyDown:event];
+ }
+}
+
+- (void)shortCircuitScrollWheelEvent:(NSEvent*)event {
+ if ([event phase] != NSEventPhaseEnded &&
+ [event phase] != NSEventPhaseCancelled) {
+ return;
+ }
+
+ [self sendScrollWheelEvet:event];
+
+ if (endWheelMonitor_) {
+ [NSEvent removeMonitor:endWheelMonitor_];
+ endWheelMonitor_ = nil;
+ }
+}
+
+- (void)scrollWheel:(NSEvent*)event {
+ // Use an NSEvent monitor to listen for the wheel-end end. This ensures that
+ // the event is received even when the mouse cursor is no longer over the
+ // view when the scrolling ends. Also it avoids sending duplicate scroll
+ // events to the renderer.
+ if ([event phase] == NSEventPhaseBegan && !endWheelMonitor_) {
+ endWheelMonitor_ = [NSEvent
+ addLocalMonitorForEventsMatchingMask:NSEventMaskScrollWheel
+ handler:^(NSEvent* blockEvent) {
+ [self shortCircuitScrollWheelEvent:
+ blockEvent];
+ return blockEvent;
+ }];
+ }
+
+ [self sendScrollWheelEvet:event];
+}
+
+- (void)sendScrollWheelEvet:(NSEvent*)event {
+ CefRefPtr<CefBrowser> browser = [self getBrowser];
+ if (!browser.get()) {
+ return;
+ }
+
+ CGEventRef cgEvent = [event CGEvent];
+ DCHECK(cgEvent);
+
+ int deltaX = static_cast<int>(
+ CGEventGetIntegerValueField(cgEvent, kCGScrollWheelEventPointDeltaAxis2));
+ int deltaY = static_cast<int>(
+ CGEventGetIntegerValueField(cgEvent, kCGScrollWheelEventPointDeltaAxis1));
+
+ CefMouseEvent mouseEvent;
+ [self getMouseEvent:mouseEvent forEvent:event];
+
+ browser->GetHost()->SendMouseWheelEvent(mouseEvent, deltaX, deltaY);
+}
+
+- (BOOL)canBecomeKeyView {
+ CefRefPtr<CefBrowser> browser = [self getBrowser];
+ return (browser.get() != nullptr);
+}
+
+- (BOOL)acceptsFirstResponder {
+ CefRefPtr<CefBrowser> browser = [self getBrowser];
+ return (browser.get() != nullptr);
+}
+
+- (BOOL)becomeFirstResponder {
+ CefRefPtr<CefBrowser> browser = [self getBrowser];
+ if (browser.get()) {
+ browser->GetHost()->SetFocus(true);
+ return [super becomeFirstResponder];
+ }
+
+ return NO;
+}
+
+- (BOOL)resignFirstResponder {
+ CefRefPtr<CefBrowser> browser = [self getBrowser];
+ if (browser.get()) {
+ browser->GetHost()->SetFocus(false);
+ return [super resignFirstResponder];
+ }
+
+ return NO;
+}
+
+- (void)undo:(id)sender {
+ CefRefPtr<CefBrowser> browser = [self getBrowser];
+ if (browser.get()) {
+ browser->GetFocusedFrame()->Undo();
+ }
+}
+
+- (void)redo:(id)sender {
+ CefRefPtr<CefBrowser> browser = [self getBrowser];
+ if (browser.get()) {
+ browser->GetFocusedFrame()->Redo();
+ }
+}
+
+- (void)cut:(id)sender {
+ CefRefPtr<CefBrowser> browser = [self getBrowser];
+ if (browser.get()) {
+ browser->GetFocusedFrame()->Cut();
+ }
+}
+
+- (void)copy:(id)sender {
+ CefRefPtr<CefBrowser> browser = [self getBrowser];
+ if (browser.get()) {
+ browser->GetFocusedFrame()->Copy();
+ }
+}
+
+- (void)paste:(id)sender {
+ CefRefPtr<CefBrowser> browser = [self getBrowser];
+ if (browser.get()) {
+ browser->GetFocusedFrame()->Paste();
+ }
+}
+
+- (void)delete:(id)sender {
+ CefRefPtr<CefBrowser> browser = [self getBrowser];
+ if (browser.get()) {
+ browser->GetFocusedFrame()->Delete();
+ }
+}
+
+- (void)selectAll:(id)sender {
+ CefRefPtr<CefBrowser> browser = [self getBrowser];
+ if (browser.get()) {
+ browser->GetFocusedFrame()->SelectAll();
+ }
+}
+
+- (NSPoint)getClickPointForEvent:(NSEvent*)event {
+ NSPoint windowLocal = [event locationInWindow];
+ NSPoint contentLocal = [self convertPoint:windowLocal fromView:nil];
+
+ NSPoint point;
+ point.x = contentLocal.x;
+ point.y = [self frame].size.height - contentLocal.y; // Flip y.
+ return point;
+}
+
+- (void)getKeyEvent:(CefKeyEvent&)keyEvent forEvent:(NSEvent*)event {
+ if ([event type] == NSEventTypeKeyDown || [event type] == NSEventTypeKeyUp) {
+ NSString* s = [event characters];
+ if ([s length] > 0) {
+ keyEvent.character = [s characterAtIndex:0];
+ }
+
+ s = [event charactersIgnoringModifiers];
+ if ([s length] > 0) {
+ keyEvent.unmodified_character = [s characterAtIndex:0];
+ }
+ }
+
+ if ([event type] == NSEventTypeFlagsChanged) {
+ keyEvent.character = 0;
+ keyEvent.unmodified_character = 0;
+ }
+
+ keyEvent.native_key_code = [event keyCode];
+
+ keyEvent.modifiers = [self getModifiersForEvent:event];
+}
+
+- (NSTextInputContext*)inputContext {
+ if (!text_input_context_osr_mac_) {
+ text_input_client_ =
+ [[CefTextInputClientOSRMac alloc] initWithBrowser:[self getBrowser]];
+ text_input_context_osr_mac_ =
+ [[NSTextInputContext alloc] initWithClient:text_input_client_];
+#if !__has_feature(objc_arc)
+ [text_input_client_ retain];
+ [text_input_context_osr_mac_ retain];
+#endif // !__has_feature(objc_arc)
+ }
+
+ return text_input_context_osr_mac_;
+}
+
+- (void)getMouseEvent:(CefMouseEvent&)mouseEvent forEvent:(NSEvent*)event {
+ const float device_scale_factor = [self getDeviceScaleFactor];
+
+ // |point| is in OS X view coordinates.
+ NSPoint point = [self getClickPointForEvent:event];
+
+ // Convert to device coordinates.
+ point = [self convertPointToBackingInternal:point];
+
+ int device_x = point.x;
+ int device_y = point.y;
+ if ([self isOverPopupWidgetX:device_x andY:device_y]) {
+ [self applyPopupOffsetToX:device_x andY:device_y];
+ }
+
+ // Convert to browser view coordinates.
+ mouseEvent.x = client::DeviceToLogical(device_x, device_scale_factor);
+ mouseEvent.y = client::DeviceToLogical(device_y, device_scale_factor);
+
+ mouseEvent.modifiers = [self getModifiersForEvent:event];
+}
+
+- (void)getMouseEvent:(CefMouseEvent&)mouseEvent
+ forDragInfo:(id<NSDraggingInfo>)info {
+ const float device_scale_factor = [self getDeviceScaleFactor];
+
+ // |point| is in OS X view coordinates.
+ NSPoint windowPoint = [info draggingLocation];
+ NSPoint point = [self flipWindowPointToView:windowPoint];
+
+ // Convert to device coordinates.
+ point = [self convertPointToBackingInternal:point];
+
+ // Convert to browser view coordinates.
+ mouseEvent.x = client::DeviceToLogical(point.x, device_scale_factor);
+ mouseEvent.y = client::DeviceToLogical(point.y, device_scale_factor);
+
+ mouseEvent.modifiers = static_cast<uint32>([NSEvent modifierFlags]);
+}
+
+- (int)getModifiersForEvent:(NSEvent*)event {
+ int modifiers = 0;
+
+ if ([event modifierFlags] & NSEventModifierFlagControl) {
+ modifiers |= EVENTFLAG_CONTROL_DOWN;
+ }
+ if ([event modifierFlags] & NSEventModifierFlagShift) {
+ modifiers |= EVENTFLAG_SHIFT_DOWN;
+ }
+ if ([event modifierFlags] & NSEventModifierFlagOption) {
+ modifiers |= EVENTFLAG_ALT_DOWN;
+ }
+ if ([event modifierFlags] & NSEventModifierFlagCommand) {
+ modifiers |= EVENTFLAG_COMMAND_DOWN;
+ }
+ if ([event modifierFlags] & NSEventModifierFlagCapsLock) {
+ modifiers |= EVENTFLAG_CAPS_LOCK_ON;
+ }
+
+ if ([event type] == NSEventTypeKeyUp || [event type] == NSEventTypeKeyDown ||
+ [event type] == NSEventTypeFlagsChanged) {
+ // Only perform this check for key events
+ if ([self isKeyPadEvent:event]) {
+ modifiers |= EVENTFLAG_IS_KEY_PAD;
+ }
+ }
+
+ // OS X does not have a modifier for NumLock, so I'm not entirely sure how to
+ // set EVENTFLAG_NUM_LOCK_ON;
+ //
+ // There is no EVENTFLAG for the function key either.
+
+ // Mouse buttons
+ switch ([event type]) {
+ case NSEventTypeLeftMouseDragged:
+ case NSEventTypeLeftMouseDown:
+ case NSEventTypeLeftMouseUp:
+ modifiers |= EVENTFLAG_LEFT_MOUSE_BUTTON;
+ break;
+ case NSEventTypeRightMouseDragged:
+ case NSEventTypeRightMouseDown:
+ case NSEventTypeRightMouseUp:
+ modifiers |= EVENTFLAG_RIGHT_MOUSE_BUTTON;
+ break;
+ case NSEventTypeOtherMouseDragged:
+ case NSEventTypeOtherMouseDown:
+ case NSEventTypeOtherMouseUp:
+ modifiers |= EVENTFLAG_MIDDLE_MOUSE_BUTTON;
+ break;
+ default:
+ break;
+ }
+
+ return modifiers;
+}
+
+- (BOOL)isKeyUpEvent:(NSEvent*)event {
+ if ([event type] != NSEventTypeFlagsChanged) {
+ return [event type] == NSEventTypeKeyUp;
+ }
+
+ // FIXME: This logic fails if the user presses both Shift keys at once, for
+ // example: we treat releasing one of them as keyDown.
+ switch ([event keyCode]) {
+ case 54: // Right Command
+ case 55: // Left Command
+ return ([event modifierFlags] & NSEventModifierFlagCommand) == 0;
+
+ case 57: // Capslock
+ return ([event modifierFlags] & NSEventModifierFlagCapsLock) == 0;
+
+ case 56: // Left Shift
+ case 60: // Right Shift
+ return ([event modifierFlags] & NSEventModifierFlagShift) == 0;
+
+ case 58: // Left Alt
+ case 61: // Right Alt
+ return ([event modifierFlags] & NSEventModifierFlagOption) == 0;
+
+ case 59: // Left Ctrl
+ case 62: // Right Ctrl
+ return ([event modifierFlags] & NSEventModifierFlagControl) == 0;
+
+ case 63: // Function
+ return ([event modifierFlags] & NSEventModifierFlagFunction) == 0;
+ }
+ return false;
+}
+
+- (BOOL)isKeyPadEvent:(NSEvent*)event {
+ if ([event modifierFlags] & NSEventModifierFlagNumericPad) {
+ return true;
+ }
+
+ switch ([event keyCode]) {
+ case 71: // Clear
+ case 81: // =
+ case 75: // /
+ case 67: // *
+ case 78: // -
+ case 69: // +
+ case 76: // Enter
+ case 65: // .
+ case 82: // 0
+ case 83: // 1
+ case 84: // 2
+ case 85: // 3
+ case 86: // 4
+ case 87: // 5
+ case 88: // 6
+ case 89: // 7
+ case 91: // 8
+ case 92: // 9
+ return true;
+ }
+
+ return false;
+}
+
+- (void)windowDidChangeBackingProperties:(NSNotification*)notification {
+ // This delegate method is only called on 10.7 and later, so don't worry about
+ // other backing changes calling it on 10.6 or earlier
+ [self resetDeviceScaleFactor];
+}
+
+- (void)drawRect:(NSRect)dirtyRect {
+ CefRefPtr<CefBrowser> browser = [self getBrowser];
+ if ([self inLiveResize] || !browser.get()) {
+ // Fill with the background color.
+ const cef_color_t background_color =
+ client::MainContext::Get()->GetBackgroundColor();
+ NSColor* color = [NSColor
+ colorWithCalibratedRed:float(CefColorGetR(background_color)) / 255.0f
+ green:float(CefColorGetG(background_color)) / 255.0f
+ blue:float(CefColorGetB(background_color)) / 255.0f
+ alpha:1.f];
+ [color setFill];
+ NSRectFill(dirtyRect);
+ }
+
+ // The Invalidate below fixes flicker when resizing.
+ if ([self inLiveResize] && browser.get()) {
+ browser->GetHost()->Invalidate(PET_VIEW);
+ }
+}
+
+// Drag and drop
+
+- (BOOL)startDragging:(CefRefPtr<CefDragData>)drag_data
+ allowedOps:(NSDragOperation)ops
+ point:(NSPoint)position {
+ DCHECK(!pasteboard_);
+ DCHECK(!fileUTI_);
+ DCHECK(!current_drag_data_.get());
+
+ [self resetDragDrop];
+
+ current_allowed_ops_ = ops;
+ current_drag_data_ = drag_data;
+
+ [self fillPasteboard];
+
+ NSEvent* currentEvent = [[NSApplication sharedApplication] currentEvent];
+ NSWindow* window = [self window];
+ NSTimeInterval eventTime = [currentEvent timestamp];
+
+ NSEvent* dragEvent = [NSEvent mouseEventWithType:NSEventTypeLeftMouseDragged
+ location:position
+ modifierFlags:NSEventMaskLeftMouseDragged
+ timestamp:eventTime
+ windowNumber:[window windowNumber]
+ context:nil
+ eventNumber:0
+ clickCount:1
+ pressure:1.0];
+
+ // TODO(cef): Pass a non-nil value to dragImage (see issue #1715). For now
+ // work around the "callee requires a non-null argument" error that occurs
+ // when building with the 10.11 SDK.
+ id nilArg = nil;
+ [window dragImage:nilArg
+ at:position
+ offset:NSZeroSize
+ event:dragEvent
+ pasteboard:pasteboard_
+ source:self
+ slideBack:YES];
+ return YES;
+}
+
+- (void)setCurrentDragOp:(NSDragOperation)op {
+ current_drag_op_ = op;
+}
+
+// NSDraggingSource Protocol
+
+- (NSDragOperation)draggingSession:(NSDraggingSession*)session
+ sourceOperationMaskForDraggingContext:(NSDraggingContext)context {
+ switch (context) {
+ case NSDraggingContextOutsideApplication:
+ return current_allowed_ops_;
+
+ case NSDraggingContextWithinApplication:
+ default:
+ return current_allowed_ops_;
+ }
+}
+
+- (NSArray*)namesOfPromisedFilesDroppedAtDestination:(NSURL*)dropDest {
+ if (![dropDest isFileURL]) {
+ return nil;
+ }
+
+ if (!current_drag_data_) {
+ return nil;
+ }
+
+ size_t expected_size = current_drag_data_->GetFileContents(nullptr);
+ if (expected_size == 0) {
+ return nil;
+ }
+
+ std::string path = [[dropDest path] UTF8String];
+ path.append("/");
+ path.append(current_drag_data_->GetFileName().ToString());
+
+ CefRefPtr<CefStreamWriter> writer = CefStreamWriter::CreateForFile(path);
+ if (!writer) {
+ return nil;
+ }
+
+ if (current_drag_data_->GetFileContents(writer) != expected_size) {
+ return nil;
+ }
+
+ return @[ [NSString stringWithUTF8String:path.c_str()] ];
+}
+
+- (void)draggedImage:(NSImage*)anImage
+ endedAt:(NSPoint)screenPoint
+ operation:(NSDragOperation)operation {
+ CefRefPtr<CefBrowser> browser = [self getBrowser];
+ if (!browser.get()) {
+ return;
+ }
+
+ if (operation == (NSDragOperationMove | NSDragOperationCopy)) {
+ operation &= ~NSDragOperationMove;
+ }
+
+ NSPoint windowPoint = [[self window] convertScreenToBase:screenPoint];
+ NSPoint pt = [self flipWindowPointToView:windowPoint];
+ CefRenderHandler::DragOperation op =
+ static_cast<CefRenderHandler::DragOperation>(operation);
+ browser->GetHost()->DragSourceEndedAt(pt.x, pt.y, op);
+ browser->GetHost()->DragSourceSystemDragEnded();
+ [self resetDragDrop];
+}
+
+// NSDraggingDestination Protocol
+
+- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)info {
+ CefRefPtr<CefBrowser> browser = [self getBrowser];
+ if (!browser.get()) {
+ return NSDragOperationNone;
+ }
+
+ CefRefPtr<CefDragData> drag_data;
+ if (!current_drag_data_) {
+ drag_data = CefDragData::Create();
+ [self populateDropData:drag_data fromPasteboard:[info draggingPasteboard]];
+ } else {
+ drag_data = current_drag_data_->Clone();
+ drag_data->ResetFileContents();
+ }
+
+ CefMouseEvent mouseEvent;
+ [self getMouseEvent:mouseEvent forDragInfo:info];
+
+ NSDragOperation mask = [info draggingSourceOperationMask];
+ CefBrowserHost::DragOperationsMask allowed_ops =
+ static_cast<CefBrowserHost::DragOperationsMask>(mask);
+
+ browser->GetHost()->DragTargetDragEnter(drag_data, mouseEvent, allowed_ops);
+ browser->GetHost()->DragTargetDragOver(mouseEvent, allowed_ops);
+
+ current_drag_op_ = NSDragOperationCopy;
+ return current_drag_op_;
+}
+
+- (void)draggingExited:(id<NSDraggingInfo>)sender {
+ CefRefPtr<CefBrowser> browser = [self getBrowser];
+ if (browser.get()) {
+ browser->GetHost()->DragTargetDragLeave();
+ }
+}
+
+- (BOOL)prepareForDragOperation:(id<NSDraggingInfo>)info {
+ return YES;
+}
+
+- (BOOL)performDragOperation:(id<NSDraggingInfo>)info {
+ CefRefPtr<CefBrowser> browser = [self getBrowser];
+ if (!browser.get()) {
+ return NO;
+ }
+
+ CefMouseEvent mouseEvent;
+ [self getMouseEvent:mouseEvent forDragInfo:info];
+
+ browser->GetHost()->DragTargetDrop(mouseEvent);
+
+ return YES;
+}
+
+- (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)info {
+ CefRefPtr<CefBrowser> browser = [self getBrowser];
+ if (!browser.get()) {
+ return NSDragOperationNone;
+ }
+
+ CefMouseEvent mouseEvent;
+ [self getMouseEvent:mouseEvent forDragInfo:info];
+
+ NSDragOperation mask = [info draggingSourceOperationMask];
+ CefBrowserHost::DragOperationsMask allowed_ops =
+ static_cast<CefBrowserHost::DragOperationsMask>(mask);
+
+ browser->GetHost()->DragTargetDragOver(mouseEvent, allowed_ops);
+
+ return current_drag_op_;
+}
+
+// NSPasteboardOwner Protocol
+
+- (void)pasteboard:(NSPasteboard*)pboard provideDataForType:(NSString*)type {
+ if (!current_drag_data_) {
+ return;
+ }
+
+ // URL.
+ if ([type isEqualToString:NSURLPboardType]) {
+ DCHECK(current_drag_data_->IsLink());
+ NSString* strUrl =
+ [NSString stringWithUTF8String:current_drag_data_->GetLinkURL()
+ .ToString()
+ .c_str()];
+ NSURL* url = [NSURL URLWithString:strUrl];
+ [url writeToPasteboard:pboard];
+ // URL title.
+ } else if ([type isEqualToString:kNSURLTitlePboardType]) {
+ NSString* strTitle =
+ [NSString stringWithUTF8String:current_drag_data_->GetLinkTitle()
+ .ToString()
+ .c_str()];
+ [pboard setString:strTitle forType:kNSURLTitlePboardType];
+
+ // File contents.
+ } else if ([type isEqualToString:fileUTI_]) {
+ size_t size = current_drag_data_->GetFileContents(nullptr);
+ DCHECK_GT(size, 0U);
+ CefRefPtr<client::BytesWriteHandler> handler =
+ new client::BytesWriteHandler(size);
+ CefRefPtr<CefStreamWriter> writer =
+ CefStreamWriter::CreateForHandler(handler.get());
+ current_drag_data_->GetFileContents(writer);
+ DCHECK_EQ(handler->GetDataSize(), static_cast<int64>(size));
+
+ [pboard setData:[NSData dataWithBytes:handler->GetData()
+ length:handler->GetDataSize()]
+ forType:fileUTI_];
+
+ // Plain text.
+ } else if ([type isEqualToString:NSStringPboardType]) {
+ NSString* strTitle =
+ [NSString stringWithUTF8String:current_drag_data_->GetFragmentText()
+ .ToString()
+ .c_str()];
+ [pboard setString:strTitle forType:NSStringPboardType];
+
+ } else if ([type isEqualToString:kCEFDragDummyPboardType]) {
+ // The dummy type _was_ promised and someone decided to call the bluff.
+ [pboard setData:[NSData data] forType:kCEFDragDummyPboardType];
+ }
+}
+
+// NSAccessibility Protocol implementation.
+- (BOOL)accessibilityIsIgnored {
+ if (!accessibility_helper_) {
+ return YES;
+ } else {
+ return NO;
+ }
+}
+
+- (id)accessibilityAttributeValue:(NSString*)attribute {
+ if (!accessibility_helper_) {
+ return [super accessibilityAttributeValue:attribute];
+ }
+ if ([attribute isEqualToString:NSAccessibilityRoleAttribute]) {
+ return NSAccessibilityGroupRole;
+ } else if ([attribute isEqualToString:NSAccessibilityDescriptionAttribute]) {
+ client::OsrAXNode* node = accessibility_helper_->GetRootNode();
+ std::string desc = node ? node->AxDescription() : "";
+ return [NSString stringWithUTF8String:desc.c_str()];
+ } else if ([attribute isEqualToString:NSAccessibilityValueAttribute]) {
+ client::OsrAXNode* node = accessibility_helper_->GetRootNode();
+ std::string desc = node ? node->AxValue() : "";
+ return [NSString stringWithUTF8String:desc.c_str()];
+ } else if ([attribute
+ isEqualToString:NSAccessibilityRoleDescriptionAttribute]) {
+ return NSAccessibilityRoleDescriptionForUIElement(self);
+ } else if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) {
+ client::OsrAXNode* node = accessibility_helper_->GetRootNode();
+ // Add Root as first Kid
+ NSMutableArray* kids = [NSMutableArray arrayWithCapacity:1];
+ NSObject* child = CAST_CEF_NATIVE_ACCESSIBLE_TO_NSOBJECT(
+ node->GetNativeAccessibleObject(nullptr));
+ [kids addObject:child];
+ return NSAccessibilityUnignoredChildren(kids);
+ } else {
+ return [super accessibilityAttributeValue:attribute];
+ }
+}
+
+- (id)accessibilityFocusedUIElement {
+ if (accessibility_helper_) {
+ client::OsrAXNode* node = accessibility_helper_->GetFocusedNode();
+ return node ? CAST_CEF_NATIVE_ACCESSIBLE_TO_NSOBJECT(
+ node->GetNativeAccessibleObject(nullptr))
+ : nil;
+ }
+ return nil;
+}
+
+// Utility methods.
+- (void)resetDragDrop {
+ current_drag_op_ = NSDragOperationNone;
+ current_allowed_ops_ = NSDragOperationNone;
+ current_drag_data_ = nullptr;
+ if (fileUTI_) {
+#if !__has_feature(objc_arc)
+ [fileUTI_ release];
+#endif // !__has_feature(objc_arc)
+ fileUTI_ = nil;
+ }
+ if (pasteboard_) {
+#if !__has_feature(objc_arc)
+ [pasteboard_ release];
+#endif // !__has_feature(objc_arc)
+ pasteboard_ = nil;
+ }
+}
+
+- (void)fillPasteboard {
+ DCHECK(!pasteboard_);
+ pasteboard_ = [NSPasteboard pasteboardWithName:NSPasteboardNameDrag];
+#if !__has_feature(objc_arc)
+ [pasteboard_ retain];
+#endif // !__has_feature(objc_arc)
+
+ [pasteboard_ declareTypes:@[ kCEFDragDummyPboardType ] owner:self];
+
+ // URL (and title).
+ if (current_drag_data_->IsLink()) {
+ [pasteboard_ addTypes:@[ NSURLPboardType, kNSURLTitlePboardType ]
+ owner:self];
+ }
+
+ // MIME type.
+ CefString mimeType;
+ size_t contents_size = current_drag_data_->GetFileContents(nullptr);
+ CefString download_metadata = current_drag_data_->GetLinkMetadata();
+
+ // File.
+ if (contents_size > 0) {
+ std::string file_name = current_drag_data_->GetFileName().ToString();
+ size_t sep = file_name.find_last_of(".");
+ CefString extension = file_name.substr(sep + 1);
+
+ mimeType = CefGetMimeType(extension);
+
+ if (!mimeType.empty()) {
+ CFStringRef mimeTypeCF;
+ mimeTypeCF = CFStringCreateWithCString(kCFAllocatorDefault,
+ mimeType.ToString().c_str(),
+ kCFStringEncodingUTF8);
+ fileUTI_ = (__bridge NSString*)UTTypeCreatePreferredIdentifierForTag(
+ kUTTagClassMIMEType, mimeTypeCF, nullptr);
+ CFRelease(mimeTypeCF);
+ // File (HFS) promise.
+ NSArray* fileUTIList = @[ fileUTI_ ];
+ [pasteboard_ addTypes:@[ NSFilesPromisePboardType ] owner:self];
+ [pasteboard_ setPropertyList:fileUTIList
+ forType:NSFilesPromisePboardType];
+
+ [pasteboard_ addTypes:fileUTIList owner:self];
+ }
+ }
+
+ // Plain text.
+ if (!current_drag_data_->GetFragmentText().empty()) {
+ [pasteboard_ addTypes:@[ NSStringPboardType ] owner:self];
+ }
+}
+
+- (void)populateDropData:(CefRefPtr<CefDragData>)data
+ fromPasteboard:(NSPasteboard*)pboard {
+ DCHECK(data);
+ DCHECK(pboard);
+ DCHECK(data && !data->IsReadOnly());
+ NSArray* types = [pboard types];
+
+ // Get plain text.
+ if ([types containsObject:NSStringPboardType]) {
+ data->SetFragmentText(
+ [[pboard stringForType:NSStringPboardType] UTF8String]);
+ }
+
+ // Get files.
+ if ([types containsObject:NSFilenamesPboardType]) {
+ NSArray* files = [pboard propertyListForType:NSFilenamesPboardType];
+ if ([files isKindOfClass:[NSArray class]] && [files count]) {
+ for (NSUInteger i = 0; i < [files count]; i++) {
+ NSString* filename = [files objectAtIndex:i];
+ BOOL exists =
+ [[NSFileManager defaultManager] fileExistsAtPath:filename];
+ if (exists) {
+ data->AddFile([filename UTF8String], CefString());
+ }
+ }
+ }
+ }
+}
+
+- (NSPoint)flipWindowPointToView:(const NSPoint&)windowPoint {
+ NSPoint viewPoint = [self convertPoint:windowPoint fromView:nil];
+ NSRect viewFrame = [self frame];
+ viewPoint.y = viewFrame.size.height - viewPoint.y;
+ return viewPoint;
+}
+
+- (void)resetDeviceScaleFactor {
+ float device_scale_factor = 1.0f;
+ NSWindow* window = [self window];
+ if (window) {
+ device_scale_factor = [window backingScaleFactor];
+ }
+ [self setDeviceScaleFactor:device_scale_factor];
+}
+
+- (void)setDeviceScaleFactor:(float)device_scale_factor {
+ if (device_scale_factor == device_scale_factor_) {
+ return;
+ }
+
+ // Apply some sanity checks.
+ if (device_scale_factor < 1.0f || device_scale_factor > 4.0f) {
+ return;
+ }
+
+ device_scale_factor_ = device_scale_factor;
+
+ CefRefPtr<CefBrowser> browser = [self getBrowser];
+ if (browser) {
+ browser->GetHost()->NotifyScreenInfoChanged();
+ browser->GetHost()->WasResized();
+ }
+}
+
+- (float)getDeviceScaleFactor {
+ return device_scale_factor_;
+}
+
+- (void)viewDidChangeBackingProperties {
+ [super viewDidChangeBackingProperties];
+ const CGFloat device_scale_factor = [self getDeviceScaleFactor];
+
+ if (device_scale_factor == device_scale_factor_) {
+ return;
+ }
+
+ CefRefPtr<CefBrowser> browser = [self getBrowser];
+ if (browser) {
+ browser->GetHost()->NotifyScreenInfoChanged();
+ browser->GetHost()->WasResized();
+ }
+}
+
+- (bool)isOverPopupWidgetX:(int)x andY:(int)y {
+ CefRect rc = renderer_->popup_rect();
+ int popup_right = rc.x + rc.width;
+ int popup_bottom = rc.y + rc.height;
+ return (x >= rc.x) && (x < popup_right) && (y >= rc.y) && (y < popup_bottom);
+}
+
+- (int)getPopupXOffset {
+ return renderer_->original_popup_rect().x - renderer_->popup_rect().x;
+}
+
+- (int)getPopupYOffset {
+ return renderer_->original_popup_rect().y - renderer_->popup_rect().y;
+}
+
+- (void)applyPopupOffsetToX:(int&)x andY:(int&)y {
+ if ([self isOverPopupWidgetX:x andY:y]) {
+ x += [self getPopupXOffset];
+ y += [self getPopupYOffset];
+ }
+}
+
+// Convert from scaled coordinates to view coordinates.
+- (NSPoint)convertPointFromBackingInternal:(NSPoint)aPoint {
+ return [self convertPointFromBacking:aPoint];
+}
+
+// Convert from view coordinates to scaled coordinates.
+- (NSPoint)convertPointToBackingInternal:(NSPoint)aPoint {
+ return [self convertPointToBacking:aPoint];
+}
+
+// Convert from scaled coordinates to view coordinates.
+- (NSRect)convertRectFromBackingInternal:(NSRect)aRect {
+ return [self convertRectFromBacking:aRect];
+}
+
+// Convert from view coordinates to scaled coordinates.
+- (NSRect)convertRectToBackingInternal:(NSRect)aRect {
+ return [self convertRectToBacking:aRect];
+}
+
+- (void)ChangeCompositionRange:(CefRange)range
+ character_bounds:(const CefRenderHandler::RectList&)bounds {
+ if (text_input_client_) {
+ [text_input_client_ ChangeCompositionRange:range character_bounds:bounds];
+ }
+}
+
+- (void)UpdateAccessibilityTree:(CefRefPtr<CefValue>)value {
+ if (!accessibility_helper_) {
+ accessibility_helper_ =
+ new client::OsrAccessibilityHelper(value, [self getBrowser]);
+ } else {
+ accessibility_helper_->UpdateAccessibilityTree(value);
+ }
+
+ if (accessibility_helper_) {
+ NSAccessibilityPostNotification(self,
+ NSAccessibilityValueChangedNotification);
+ }
+ return;
+}
+
+- (void)UpdateAccessibilityLocation:(CefRefPtr<CefValue>)value {
+ if (accessibility_helper_) {
+ accessibility_helper_->UpdateAccessibilityLocation(value);
+ }
+
+ if (accessibility_helper_) {
+ NSAccessibilityPostNotification(self,
+ NSAccessibilityValueChangedNotification);
+ }
+ return;
+}
+@end
+
+namespace client {
+
+class BrowserWindowOsrMacImpl {
+ public:
+ BrowserWindowOsrMacImpl(BrowserWindow::Delegate* delegate,
+ const std::string& startup_url,
+ const OsrRendererSettings& settings,
+ BrowserWindowOsrMac& browser_window);
+ ~BrowserWindowOsrMacImpl();
+
+ // BrowserWindow methods.
+ void CreateBrowser(ClientWindowHandle parent_handle,
+ const CefRect& rect,
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefDictionaryValue> extra_info,
+ CefRefPtr<CefRequestContext> request_context);
+ void GetPopupConfig(CefWindowHandle temp_handle,
+ CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient>& client,
+ CefBrowserSettings& settings);
+ void ShowPopup(ClientWindowHandle parent_handle,
+ int x,
+ int y,
+ size_t width,
+ size_t height);
+ void Show();
+ void Hide();
+ void SetBounds(int x, int y, size_t width, size_t height);
+ void SetFocus(bool focus);
+ void SetDeviceScaleFactor(float device_scale_factor);
+ float GetDeviceScaleFactor() const;
+ ClientWindowHandle GetWindowHandle() const;
+
+ // ClientHandlerOsr::OsrDelegate methods.
+ void OnAfterCreated(CefRefPtr<CefBrowser> browser);
+ void OnBeforeClose(CefRefPtr<CefBrowser> browser);
+ bool GetRootScreenRect(CefRefPtr<CefBrowser> browser, CefRect& rect);
+ void GetViewRect(CefRefPtr<CefBrowser> browser, CefRect& rect);
+ bool GetScreenPoint(CefRefPtr<CefBrowser> browser,
+ int viewX,
+ int viewY,
+ int& screenX,
+ int& screenY);
+ bool GetScreenInfo(CefRefPtr<CefBrowser> browser, CefScreenInfo& screen_info);
+ void OnPopupShow(CefRefPtr<CefBrowser> browser, bool show);
+ void OnPopupSize(CefRefPtr<CefBrowser> browser, const CefRect& rect);
+ void OnPaint(CefRefPtr<CefBrowser> browser,
+ CefRenderHandler::PaintElementType type,
+ const CefRenderHandler::RectList& dirtyRects,
+ const void* buffer,
+ int width,
+ int height);
+ void OnCursorChange(CefRefPtr<CefBrowser> browser,
+ CefCursorHandle cursor,
+ cef_cursor_type_t type,
+ const CefCursorInfo& custom_cursor_info);
+ bool StartDragging(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefDragData> drag_data,
+ CefRenderHandler::DragOperationsMask allowed_ops,
+ int x,
+ int y);
+ void UpdateDragCursor(CefRefPtr<CefBrowser> browser,
+ CefRenderHandler::DragOperation operation);
+ void OnImeCompositionRangeChanged(
+ CefRefPtr<CefBrowser> browser,
+ const CefRange& selection_range,
+ const CefRenderHandler::RectList& character_bounds);
+
+ void UpdateAccessibilityTree(CefRefPtr<CefValue> value);
+ void UpdateAccessibilityLocation(CefRefPtr<CefValue> value);
+
+ private:
+ // Create the NSView.
+ void Create(ClientWindowHandle parent_handle, const CefRect& rect);
+
+ BrowserWindowOsrMac& browser_window_;
+ // The below members will only be accessed on the main thread which should be
+ // the same as the CEF UI thread.
+ OsrRenderer renderer_;
+ BrowserOpenGLView* native_browser_view_;
+ bool hidden_;
+ bool painting_popup_;
+};
+
+BrowserWindowOsrMacImpl::BrowserWindowOsrMacImpl(
+ BrowserWindow::Delegate* delegate,
+ const std::string& startup_url,
+ const OsrRendererSettings& settings,
+ BrowserWindowOsrMac& browser_window)
+ : browser_window_(browser_window),
+ renderer_(settings),
+ native_browser_view_(nil),
+ hidden_(false),
+ painting_popup_(false) {}
+
+BrowserWindowOsrMacImpl::~BrowserWindowOsrMacImpl() {
+ if (native_browser_view_) {
+ // Disassociate the view with |this|.
+ [native_browser_view_ detach];
+ }
+}
+
+void BrowserWindowOsrMacImpl::CreateBrowser(
+ ClientWindowHandle parent_handle,
+ const CefRect& rect,
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefDictionaryValue> extra_info,
+ CefRefPtr<CefRequestContext> request_context) {
+ REQUIRE_MAIN_THREAD();
+
+ // Create the native NSView.
+ Create(parent_handle, rect);
+
+ CefWindowInfo window_info;
+ window_info.SetAsWindowless(
+ CAST_NSVIEW_TO_CEF_WINDOW_HANDLE(native_browser_view_));
+
+ // Create the browser asynchronously.
+ CefBrowserHost::CreateBrowser(window_info, browser_window_.client_handler_,
+ browser_window_.client_handler_->startup_url(),
+ settings, extra_info, request_context);
+}
+
+void BrowserWindowOsrMacImpl::GetPopupConfig(CefWindowHandle temp_handle,
+ CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient>& client,
+ CefBrowserSettings& settings) {
+ CEF_REQUIRE_UI_THREAD();
+
+ windowInfo.SetAsWindowless(temp_handle);
+ client = browser_window_.client_handler_;
+}
+
+void BrowserWindowOsrMacImpl::ShowPopup(ClientWindowHandle parent_handle,
+ int x,
+ int y,
+ size_t width,
+ size_t height) {
+ REQUIRE_MAIN_THREAD();
+ DCHECK(browser_window_.browser_.get());
+
+ // Create the native NSView.
+ Create(parent_handle,
+ CefRect(x, y, static_cast<int>(width), static_cast<int>(height)));
+
+ // Send resize notification so the compositor is assigned the correct
+ // viewport size and begins rendering.
+ browser_window_.browser_->GetHost()->WasResized();
+
+ Show();
+}
+
+void BrowserWindowOsrMacImpl::Show() {
+ REQUIRE_MAIN_THREAD();
+
+ if (hidden_) {
+ // Set the browser as visible.
+ browser_window_.browser_->GetHost()->WasHidden(false);
+ hidden_ = false;
+ }
+
+ // Give focus to the browser.
+ browser_window_.browser_->GetHost()->SetFocus(true);
+}
+
+void BrowserWindowOsrMacImpl::Hide() {
+ REQUIRE_MAIN_THREAD();
+
+ if (!browser_window_.browser_.get()) {
+ return;
+ }
+
+ // Remove focus from the browser.
+ browser_window_.browser_->GetHost()->SetFocus(false);
+
+ if (!hidden_) {
+ // Set the browser as hidden.
+ browser_window_.browser_->GetHost()->WasHidden(true);
+ hidden_ = true;
+ }
+}
+
+void BrowserWindowOsrMacImpl::SetBounds(int x,
+ int y,
+ size_t width,
+ size_t height) {
+ REQUIRE_MAIN_THREAD();
+ // Nothing to do here. GTK will take care of positioning in the container.
+}
+
+void BrowserWindowOsrMacImpl::SetFocus(bool focus) {
+ REQUIRE_MAIN_THREAD();
+ if (native_browser_view_) {
+ [native_browser_view_.window makeFirstResponder:native_browser_view_];
+ }
+}
+
+void BrowserWindowOsrMacImpl::SetDeviceScaleFactor(float device_scale_factor) {
+ REQUIRE_MAIN_THREAD();
+ if (native_browser_view_) {
+ [native_browser_view_ setDeviceScaleFactor:device_scale_factor];
+ }
+}
+
+float BrowserWindowOsrMacImpl::GetDeviceScaleFactor() const {
+ REQUIRE_MAIN_THREAD();
+ if (native_browser_view_) {
+ return [native_browser_view_ getDeviceScaleFactor];
+ }
+ return 1.0f;
+}
+
+ClientWindowHandle BrowserWindowOsrMacImpl::GetWindowHandle() const {
+ REQUIRE_MAIN_THREAD();
+ return CAST_NSVIEW_TO_CEF_WINDOW_HANDLE(native_browser_view_);
+}
+
+void BrowserWindowOsrMacImpl::OnAfterCreated(CefRefPtr<CefBrowser> browser) {
+ CEF_REQUIRE_UI_THREAD();
+}
+
+void BrowserWindowOsrMacImpl::OnBeforeClose(CefRefPtr<CefBrowser> browser) {
+ CEF_REQUIRE_UI_THREAD();
+ REQUIRE_MAIN_THREAD();
+
+ // Detach |this| from the ClientHandlerOsr.
+ static_cast<ClientHandlerOsr*>(browser_window_.client_handler_.get())
+ ->DetachOsrDelegate();
+}
+
+bool BrowserWindowOsrMacImpl::GetRootScreenRect(CefRefPtr<CefBrowser> browser,
+ CefRect& rect) {
+ CEF_REQUIRE_UI_THREAD();
+ return false;
+}
+
+void BrowserWindowOsrMacImpl::GetViewRect(CefRefPtr<CefBrowser> browser,
+ CefRect& rect) {
+ CEF_REQUIRE_UI_THREAD();
+ REQUIRE_MAIN_THREAD();
+
+ rect.x = rect.y = 0;
+
+ if (!native_browser_view_) {
+ // Never return an empty rectangle.
+ rect.width = rect.height = 1;
+ return;
+ }
+
+ const float device_scale_factor = [native_browser_view_ getDeviceScaleFactor];
+
+ // |bounds| is in OS X view coordinates.
+ NSRect bounds = native_browser_view_.bounds;
+
+ // Convert to device coordinates.
+ bounds = [native_browser_view_ convertRectToBackingInternal:bounds];
+
+ // Convert to browser view coordinates.
+ rect.width = DeviceToLogical(bounds.size.width, device_scale_factor);
+ if (rect.width == 0) {
+ rect.width = 1;
+ }
+ rect.height = DeviceToLogical(bounds.size.height, device_scale_factor);
+ if (rect.height == 0) {
+ rect.height = 1;
+ }
+}
+
+bool BrowserWindowOsrMacImpl::GetScreenPoint(CefRefPtr<CefBrowser> browser,
+ int viewX,
+ int viewY,
+ int& screenX,
+ int& screenY) {
+ CEF_REQUIRE_UI_THREAD();
+ REQUIRE_MAIN_THREAD();
+
+ if (!native_browser_view_) {
+ return false;
+ }
+
+ const float device_scale_factor = [native_browser_view_ getDeviceScaleFactor];
+
+ // (viewX, viewX) is in browser view coordinates.
+ // Convert to device coordinates.
+ NSPoint view_pt = NSMakePoint(LogicalToDevice(viewX, device_scale_factor),
+ LogicalToDevice(viewY, device_scale_factor));
+
+ // Convert to OS X view coordinates.
+ view_pt = [native_browser_view_ convertPointFromBackingInternal:view_pt];
+
+ // Reverse the Y component.
+ const NSRect bounds = native_browser_view_.bounds;
+ view_pt.y = bounds.size.height - view_pt.y;
+
+ // Convert to screen coordinates.
+ NSPoint window_pt = [native_browser_view_ convertPoint:view_pt toView:nil];
+ NSPoint screen_pt =
+ ConvertPointFromWindowToScreen(native_browser_view_.window, window_pt);
+
+ screenX = screen_pt.x;
+ screenY = screen_pt.y;
+ return true;
+}
+
+bool BrowserWindowOsrMacImpl::GetScreenInfo(CefRefPtr<CefBrowser> browser,
+ CefScreenInfo& screen_info) {
+ CEF_REQUIRE_UI_THREAD();
+ REQUIRE_MAIN_THREAD();
+
+ if (!native_browser_view_) {
+ return false;
+ }
+
+ CefRect view_rect;
+ GetViewRect(browser, view_rect);
+
+ screen_info.device_scale_factor = [native_browser_view_ getDeviceScaleFactor];
+
+ // The screen info rectangles are used by the renderer to create and position
+ // popups. Keep popups inside the view rectangle.
+ screen_info.rect = view_rect;
+ screen_info.available_rect = view_rect;
+
+ return true;
+}
+
+void BrowserWindowOsrMacImpl::OnPopupShow(CefRefPtr<CefBrowser> browser,
+ bool show) {
+ CEF_REQUIRE_UI_THREAD();
+ REQUIRE_MAIN_THREAD();
+
+ if (!native_browser_view_) {
+ return;
+ }
+
+ if (!show) {
+ renderer_.ClearPopupRects();
+ browser->GetHost()->Invalidate(PET_VIEW);
+ }
+ renderer_.OnPopupShow(browser, show);
+}
+
+void BrowserWindowOsrMacImpl::OnPopupSize(CefRefPtr<CefBrowser> browser,
+ const CefRect& rect) {
+ CEF_REQUIRE_UI_THREAD();
+ REQUIRE_MAIN_THREAD();
+
+ if (!native_browser_view_) {
+ return;
+ }
+
+ const float device_scale_factor = [native_browser_view_ getDeviceScaleFactor];
+
+ // |rect| is in browser view coordinates. Convert to device coordinates.
+ CefRect device_rect = LogicalToDevice(rect, device_scale_factor);
+
+ renderer_.OnPopupSize(browser, device_rect);
+}
+
+void BrowserWindowOsrMacImpl::OnPaint(
+ CefRefPtr<CefBrowser> browser,
+ CefRenderHandler::PaintElementType type,
+ const CefRenderHandler::RectList& dirtyRects,
+ const void* buffer,
+ int width,
+ int height) {
+ CEF_REQUIRE_UI_THREAD();
+ REQUIRE_MAIN_THREAD();
+
+ if (!native_browser_view_) {
+ return;
+ }
+
+ if (width <= 2 && height <= 2) {
+ // Ignore really small buffer sizes while the widget is starting up.
+ return;
+ }
+
+ if (painting_popup_) {
+ renderer_.OnPaint(browser, type, dirtyRects, buffer, width, height);
+ return;
+ }
+
+ ScopedGLContext scoped_gl_context(native_browser_view_, true);
+
+ renderer_.OnPaint(browser, type, dirtyRects, buffer, width, height);
+ if (type == PET_VIEW && !renderer_.popup_rect().IsEmpty()) {
+ painting_popup_ = true;
+ browser->GetHost()->Invalidate(PET_POPUP);
+ painting_popup_ = false;
+ }
+ renderer_.Render();
+}
+
+void BrowserWindowOsrMacImpl::OnCursorChange(
+ CefRefPtr<CefBrowser> browser,
+ CefCursorHandle cursor,
+ cef_cursor_type_t type,
+ const CefCursorInfo& custom_cursor_info) {
+ CEF_REQUIRE_UI_THREAD();
+ REQUIRE_MAIN_THREAD();
+
+ [CAST_CEF_CURSOR_HANDLE_TO_NSCURSOR(cursor) set];
+}
+
+bool BrowserWindowOsrMacImpl::StartDragging(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefDragData> drag_data,
+ CefRenderHandler::DragOperationsMask allowed_ops,
+ int x,
+ int y) {
+ CEF_REQUIRE_UI_THREAD();
+ REQUIRE_MAIN_THREAD();
+
+ if (!native_browser_view_) {
+ return false;
+ }
+
+ static float device_scale_factor =
+ [native_browser_view_ getDeviceScaleFactor];
+
+ // |point| is in browser view coordinates.
+ NSPoint point = NSMakePoint(x, y);
+
+ // Convert to device coordinates.
+ point.x = LogicalToDevice(point.x, device_scale_factor);
+ point.y = LogicalToDevice(point.y, device_scale_factor);
+
+ // Convert to OS X view coordinates.
+ point = [native_browser_view_ convertPointFromBackingInternal:point];
+
+ return [native_browser_view_
+ startDragging:drag_data
+ allowedOps:static_cast<NSDragOperation>(allowed_ops)
+ point:point];
+}
+
+void BrowserWindowOsrMacImpl::UpdateDragCursor(
+ CefRefPtr<CefBrowser> browser,
+ CefRenderHandler::DragOperation operation) {
+ CEF_REQUIRE_UI_THREAD();
+ REQUIRE_MAIN_THREAD();
+
+ if (native_browser_view_) {
+ [native_browser_view_ setCurrentDragOp:operation];
+ }
+}
+
+void BrowserWindowOsrMacImpl::OnImeCompositionRangeChanged(
+ CefRefPtr<CefBrowser> browser,
+ const CefRange& selection_range,
+ const CefRenderHandler::RectList& bounds) {
+ CEF_REQUIRE_UI_THREAD();
+
+ if (native_browser_view_) {
+ [native_browser_view_ ChangeCompositionRange:selection_range
+ character_bounds:bounds];
+ }
+}
+
+void BrowserWindowOsrMacImpl::UpdateAccessibilityTree(
+ CefRefPtr<CefValue> value) {
+ CEF_REQUIRE_UI_THREAD();
+
+ if (native_browser_view_) {
+ [native_browser_view_ UpdateAccessibilityTree:value];
+ }
+}
+
+void BrowserWindowOsrMacImpl::UpdateAccessibilityLocation(
+ CefRefPtr<CefValue> value) {
+ CEF_REQUIRE_UI_THREAD();
+
+ if (native_browser_view_) {
+ [native_browser_view_ UpdateAccessibilityLocation:value];
+ }
+}
+
+void BrowserWindowOsrMacImpl::Create(ClientWindowHandle parent_handle,
+ const CefRect& rect) {
+ REQUIRE_MAIN_THREAD();
+ DCHECK(!native_browser_view_);
+
+ NSRect window_rect = NSMakeRect(rect.x, rect.y, rect.width, rect.height);
+ native_browser_view_ =
+ [[BrowserOpenGLView alloc] initWithFrame:window_rect
+ andBrowserWindow:&browser_window_
+ andRenderer:&renderer_];
+ native_browser_view_.autoresizingMask =
+ (NSViewWidthSizable | NSViewHeightSizable);
+ native_browser_view_.autoresizesSubviews = YES;
+ [CAST_CEF_WINDOW_HANDLE_TO_NSVIEW(parent_handle)
+ addSubview:native_browser_view_];
+
+ // Determine the default scale factor.
+ [native_browser_view_ resetDeviceScaleFactor];
+
+ [[NSNotificationCenter defaultCenter]
+ addObserver:native_browser_view_
+ selector:@selector(windowDidChangeBackingProperties:)
+ name:NSWindowDidChangeBackingPropertiesNotification
+ object:native_browser_view_.window];
+}
+
+BrowserWindowOsrMac::BrowserWindowOsrMac(BrowserWindow::Delegate* delegate,
+ bool with_controls,
+ const std::string& startup_url,
+ const OsrRendererSettings& settings)
+ : BrowserWindow(delegate) {
+ client_handler_ =
+ new ClientHandlerOsr(this, this, with_controls, startup_url);
+ impl_.reset(
+ new BrowserWindowOsrMacImpl(delegate, startup_url, settings, *this));
+}
+
+BrowserWindowOsrMac::~BrowserWindowOsrMac() {}
+
+void BrowserWindowOsrMac::CreateBrowser(
+ ClientWindowHandle parent_handle,
+ const CefRect& rect,
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefDictionaryValue> extra_info,
+ CefRefPtr<CefRequestContext> request_context) {
+ impl_->CreateBrowser(parent_handle, rect, settings, extra_info,
+ request_context);
+}
+
+void BrowserWindowOsrMac::GetPopupConfig(CefWindowHandle temp_handle,
+ CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient>& client,
+ CefBrowserSettings& settings) {
+ impl_->GetPopupConfig(temp_handle, windowInfo, client, settings);
+}
+
+void BrowserWindowOsrMac::ShowPopup(ClientWindowHandle parent_handle,
+ int x,
+ int y,
+ size_t width,
+ size_t height) {
+ impl_->ShowPopup(parent_handle, x, y, width, height);
+}
+
+void BrowserWindowOsrMac::Show() {
+ impl_->Show();
+}
+
+void BrowserWindowOsrMac::Hide() {
+ impl_->Hide();
+}
+
+void BrowserWindowOsrMac::SetBounds(int x, int y, size_t width, size_t height) {
+ impl_->SetBounds(x, y, width, height);
+}
+
+void BrowserWindowOsrMac::SetFocus(bool focus) {
+ impl_->SetFocus(focus);
+}
+
+void BrowserWindowOsrMac::SetDeviceScaleFactor(float device_scale_factor) {
+ impl_->SetDeviceScaleFactor(device_scale_factor);
+}
+
+float BrowserWindowOsrMac::GetDeviceScaleFactor() const {
+ return impl_->GetDeviceScaleFactor();
+}
+
+ClientWindowHandle BrowserWindowOsrMac::GetWindowHandle() const {
+ return impl_->GetWindowHandle();
+}
+
+void BrowserWindowOsrMac::OnAfterCreated(CefRefPtr<CefBrowser> browser) {
+ impl_->OnAfterCreated(browser);
+}
+
+void BrowserWindowOsrMac::OnBeforeClose(CefRefPtr<CefBrowser> browser) {
+ impl_->OnBeforeClose(browser);
+}
+
+bool BrowserWindowOsrMac::GetRootScreenRect(CefRefPtr<CefBrowser> browser,
+ CefRect& rect) {
+ return impl_->GetRootScreenRect(browser, rect);
+}
+
+void BrowserWindowOsrMac::GetViewRect(CefRefPtr<CefBrowser> browser,
+ CefRect& rect) {
+ impl_->GetViewRect(browser, rect);
+}
+
+bool BrowserWindowOsrMac::GetScreenPoint(CefRefPtr<CefBrowser> browser,
+ int viewX,
+ int viewY,
+ int& screenX,
+ int& screenY) {
+ return impl_->GetScreenPoint(browser, viewX, viewY, screenX, screenY);
+}
+
+bool BrowserWindowOsrMac::GetScreenInfo(CefRefPtr<CefBrowser> browser,
+ CefScreenInfo& screen_info) {
+ return impl_->GetScreenInfo(browser, screen_info);
+}
+
+void BrowserWindowOsrMac::OnPopupShow(CefRefPtr<CefBrowser> browser,
+ bool show) {
+ impl_->OnPopupShow(browser, show);
+}
+
+void BrowserWindowOsrMac::OnPopupSize(CefRefPtr<CefBrowser> browser,
+ const CefRect& rect) {
+ impl_->OnPopupSize(browser, rect);
+}
+
+void BrowserWindowOsrMac::OnPaint(CefRefPtr<CefBrowser> browser,
+ CefRenderHandler::PaintElementType type,
+ const CefRenderHandler::RectList& dirtyRects,
+ const void* buffer,
+ int width,
+ int height) {
+ impl_->OnPaint(browser, type, dirtyRects, buffer, width, height);
+}
+
+void BrowserWindowOsrMac::OnCursorChange(
+ CefRefPtr<CefBrowser> browser,
+ CefCursorHandle cursor,
+ cef_cursor_type_t type,
+ const CefCursorInfo& custom_cursor_info) {
+ impl_->OnCursorChange(browser, cursor, type, custom_cursor_info);
+}
+
+bool BrowserWindowOsrMac::StartDragging(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefDragData> drag_data,
+ CefRenderHandler::DragOperationsMask allowed_ops,
+ int x,
+ int y) {
+ return impl_->StartDragging(browser, drag_data, allowed_ops, x, y);
+}
+
+void BrowserWindowOsrMac::UpdateDragCursor(
+ CefRefPtr<CefBrowser> browser,
+ CefRenderHandler::DragOperation operation) {
+ impl_->UpdateDragCursor(browser, operation);
+}
+
+void BrowserWindowOsrMac::OnImeCompositionRangeChanged(
+ CefRefPtr<CefBrowser> browser,
+ const CefRange& selection_range,
+ const CefRenderHandler::RectList& character_bounds) {
+ impl_->OnImeCompositionRangeChanged(browser, selection_range,
+ character_bounds);
+}
+
+void BrowserWindowOsrMac::UpdateAccessibilityTree(CefRefPtr<CefValue> value) {
+ impl_->UpdateAccessibilityTree(value);
+}
+
+void BrowserWindowOsrMac::UpdateAccessibilityLocation(
+ CefRefPtr<CefValue> value) {
+ impl_->UpdateAccessibilityLocation(value);
+}
+
+} // namespace client
diff --git a/tests/cefclient/browser/browser_window_osr_win.cc b/tests/cefclient/browser/browser_window_osr_win.cc
new file mode 100644
index 00000000..3a9e3c63
--- /dev/null
+++ b/tests/cefclient/browser/browser_window_osr_win.cc
@@ -0,0 +1,136 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/browser_window_osr_win.h"
+
+#include "tests/shared/browser/main_message_loop.h"
+
+namespace client {
+
+BrowserWindowOsrWin::BrowserWindowOsrWin(BrowserWindow::Delegate* delegate,
+ bool with_controls,
+ const std::string& startup_url,
+ const OsrRendererSettings& settings)
+ : BrowserWindow(delegate), osr_hwnd_(nullptr), device_scale_factor_(0) {
+ osr_window_ = new OsrWindowWin(this, settings);
+ client_handler_ =
+ new ClientHandlerOsr(this, osr_window_.get(), with_controls, startup_url);
+}
+
+void BrowserWindowOsrWin::CreateBrowser(
+ ClientWindowHandle parent_handle,
+ const CefRect& rect,
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefDictionaryValue> extra_info,
+ CefRefPtr<CefRequestContext> request_context) {
+ REQUIRE_MAIN_THREAD();
+
+ // Create the new browser and native window on the UI thread.
+ RECT wnd_rect = {rect.x, rect.y, rect.x + rect.width, rect.y + rect.height};
+ osr_window_->CreateBrowser(parent_handle, wnd_rect, client_handler_, settings,
+ extra_info, request_context,
+ client_handler_->startup_url());
+}
+
+void BrowserWindowOsrWin::GetPopupConfig(CefWindowHandle temp_handle,
+ CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient>& client,
+ CefBrowserSettings& settings) {
+ CEF_REQUIRE_UI_THREAD();
+
+ windowInfo.SetAsWindowless(temp_handle);
+ windowInfo.shared_texture_enabled =
+ osr_window_->settings().shared_texture_enabled;
+ windowInfo.external_begin_frame_enabled =
+ osr_window_->settings().external_begin_frame_enabled;
+
+ // Don't activate the hidden browser on creation.
+ windowInfo.ex_style |= WS_EX_NOACTIVATE;
+
+ client = client_handler_;
+}
+
+void BrowserWindowOsrWin::ShowPopup(ClientWindowHandle parent_handle,
+ int x,
+ int y,
+ size_t width,
+ size_t height) {
+ REQUIRE_MAIN_THREAD();
+ if (osr_window_) {
+ osr_window_->ShowPopup(parent_handle, x, y, width, height);
+ }
+}
+
+void BrowserWindowOsrWin::Show() {
+ REQUIRE_MAIN_THREAD();
+ if (osr_window_) {
+ osr_window_->Show();
+ }
+}
+
+void BrowserWindowOsrWin::Hide() {
+ REQUIRE_MAIN_THREAD();
+ if (osr_window_) {
+ osr_window_->Hide();
+ }
+}
+
+void BrowserWindowOsrWin::SetBounds(int x, int y, size_t width, size_t height) {
+ REQUIRE_MAIN_THREAD();
+ if (osr_window_) {
+ osr_window_->SetBounds(x, y, width, height);
+ }
+}
+
+void BrowserWindowOsrWin::SetFocus(bool focus) {
+ REQUIRE_MAIN_THREAD();
+ if (osr_window_ && focus) {
+ osr_window_->SetFocus();
+ }
+}
+
+void BrowserWindowOsrWin::SetDeviceScaleFactor(float device_scale_factor) {
+ REQUIRE_MAIN_THREAD();
+ if (device_scale_factor == device_scale_factor_) {
+ return;
+ }
+
+ // Apply some sanity checks.
+ if (device_scale_factor < 1.0f || device_scale_factor > 4.0f) {
+ return;
+ }
+
+ device_scale_factor_ = device_scale_factor;
+ if (osr_window_) {
+ osr_window_->SetDeviceScaleFactor(device_scale_factor);
+ }
+}
+
+float BrowserWindowOsrWin::GetDeviceScaleFactor() const {
+ REQUIRE_MAIN_THREAD();
+ DCHECK_GT(device_scale_factor_, 0);
+ return device_scale_factor_;
+}
+
+ClientWindowHandle BrowserWindowOsrWin::GetWindowHandle() const {
+ REQUIRE_MAIN_THREAD();
+ return osr_hwnd_;
+}
+
+void BrowserWindowOsrWin::OnBrowserClosed(CefRefPtr<CefBrowser> browser) {
+ REQUIRE_MAIN_THREAD();
+
+ // Release the OSR window reference. It will be deleted on the UI thread.
+ osr_window_ = nullptr;
+
+ BrowserWindow::OnBrowserClosed(browser);
+}
+
+void BrowserWindowOsrWin::OnOsrNativeWindowCreated(HWND hwnd) {
+ REQUIRE_MAIN_THREAD();
+ DCHECK(!osr_hwnd_);
+ osr_hwnd_ = hwnd;
+}
+
+} // namespace client
diff --git a/tests/cefclient/browser/browser_window_osr_win.h b/tests/cefclient/browser/browser_window_osr_win.h
new file mode 100644
index 00000000..e8caf718
--- /dev/null
+++ b/tests/cefclient/browser/browser_window_osr_win.h
@@ -0,0 +1,68 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_BROWSER_WINDOW_OSR_WIN_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_BROWSER_WINDOW_OSR_WIN_H_
+#pragma once
+
+#include "tests/cefclient/browser/browser_window.h"
+#include "tests/cefclient/browser/osr_window_win.h"
+
+namespace client {
+
+// Represents a native child window hosting a single off-screen browser
+// instance. The methods of this class must be called on the main thread unless
+// otherwise indicated.
+class BrowserWindowOsrWin : public BrowserWindow,
+ public OsrWindowWin::Delegate {
+ public:
+ // Constructor may be called on any thread.
+ // |delegate| must outlive this object.
+ BrowserWindowOsrWin(BrowserWindow::Delegate* delegate,
+ bool with_controls,
+ const std::string& startup_url,
+ const OsrRendererSettings& settings);
+
+ // BrowserWindow methods.
+ void CreateBrowser(ClientWindowHandle parent_handle,
+ const CefRect& rect,
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefDictionaryValue> extra_info,
+ CefRefPtr<CefRequestContext> request_context) override;
+ void GetPopupConfig(CefWindowHandle temp_handle,
+ CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient>& client,
+ CefBrowserSettings& settings) override;
+ void ShowPopup(ClientWindowHandle parent_handle,
+ int x,
+ int y,
+ size_t width,
+ size_t height) override;
+ void Show() override;
+ void Hide() override;
+ void SetBounds(int x, int y, size_t width, size_t height) override;
+ void SetFocus(bool focus) override;
+ void SetDeviceScaleFactor(float device_scale_factor) override;
+ float GetDeviceScaleFactor() const override;
+ ClientWindowHandle GetWindowHandle() const override;
+
+ private:
+ // ClienHandler::Delegate methods.
+ void OnBrowserClosed(CefRefPtr<CefBrowser> browser) override;
+
+ // OsrWindowWin::Delegate methods.
+ void OnOsrNativeWindowCreated(HWND hwnd) override;
+
+ // The below members are only accessed on the main thread.
+ scoped_refptr<OsrWindowWin> osr_window_;
+ HWND osr_hwnd_;
+
+ float device_scale_factor_;
+
+ DISALLOW_COPY_AND_ASSIGN(BrowserWindowOsrWin);
+};
+
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_BROWSER_WINDOW_OSR_WIN_H_
diff --git a/tests/cefclient/browser/browser_window_std_gtk.cc b/tests/cefclient/browser/browser_window_std_gtk.cc
new file mode 100644
index 00000000..8d4bd577
--- /dev/null
+++ b/tests/cefclient/browser/browser_window_std_gtk.cc
@@ -0,0 +1,191 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/browser_window_std_gtk.h"
+
+#include <gdk/gdk.h>
+#include <gdk/gdkx.h>
+#include <gtk/gtk.h>
+
+#include <X11/Xlib.h>
+#undef Success // Definition conflicts with cef_message_router.h
+#undef RootWindow // Definition conflicts with root_window.h
+
+#include "include/base/cef_logging.h"
+#include "tests/cefclient/browser/client_handler_std.h"
+#include "tests/cefclient/browser/util_gtk.h"
+#include "tests/shared/browser/main_message_loop.h"
+
+namespace client {
+
+namespace {
+
+::Window GetXWindowForWidget(GtkWidget* widget) {
+ ScopedGdkThreadsEnter scoped_gdk_threads;
+
+ // The GTK window must be visible before we can retrieve the XID.
+ ::Window xwindow = GDK_WINDOW_XID(gtk_widget_get_window(widget));
+ DCHECK(xwindow);
+ return xwindow;
+}
+
+void SetXWindowVisible(XDisplay* xdisplay, ::Window xwindow, bool visible) {
+ CHECK(xdisplay != 0);
+
+ // Retrieve the atoms required by the below XChangeProperty call.
+ const char* kAtoms[] = {"_NET_WM_STATE", "ATOM", "_NET_WM_STATE_HIDDEN"};
+ Atom atoms[3];
+ int result =
+ XInternAtoms(xdisplay, const_cast<char**>(kAtoms), 3, false, atoms);
+ if (!result) {
+ NOTREACHED();
+ }
+
+ if (!visible) {
+ // Set the hidden property state value.
+ std::unique_ptr<Atom[]> data(new Atom[1]);
+ data[0] = atoms[2];
+
+ XChangeProperty(xdisplay, xwindow,
+ atoms[0], // name
+ atoms[1], // type
+ 32, // size in bits of items in 'value'
+ PropModeReplace,
+ reinterpret_cast<const unsigned char*>(data.get()),
+ 1); // num items
+ } else {
+ // Set an empty array of property state values.
+ XChangeProperty(xdisplay, xwindow,
+ atoms[0], // name
+ atoms[1], // type
+ 32, // size in bits of items in 'value'
+ PropModeReplace, nullptr,
+ 0); // num items
+ }
+}
+
+void SetXWindowBounds(XDisplay* xdisplay,
+ ::Window xwindow,
+ int x,
+ int y,
+ size_t width,
+ size_t height) {
+ CHECK(xdisplay != 0);
+ XWindowChanges changes = {0};
+ changes.x = x;
+ changes.y = y;
+ changes.width = static_cast<int>(width);
+ changes.height = static_cast<int>(height);
+ XConfigureWindow(xdisplay, xwindow, CWX | CWY | CWHeight | CWWidth, &changes);
+}
+
+} // namespace
+
+BrowserWindowStdGtk::BrowserWindowStdGtk(Delegate* delegate,
+ bool with_controls,
+ const std::string& startup_url)
+ : BrowserWindow(delegate), xdisplay_(nullptr) {
+ client_handler_ = new ClientHandlerStd(this, with_controls, startup_url);
+}
+
+void BrowserWindowStdGtk::set_xdisplay(XDisplay* xdisplay) {
+ REQUIRE_MAIN_THREAD();
+ DCHECK(!xdisplay_);
+ xdisplay_ = xdisplay;
+}
+
+void BrowserWindowStdGtk::CreateBrowser(
+ ClientWindowHandle parent_handle,
+ const CefRect& rect,
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefDictionaryValue> extra_info,
+ CefRefPtr<CefRequestContext> request_context) {
+ REQUIRE_MAIN_THREAD();
+
+ CefWindowInfo window_info;
+ window_info.SetAsChild(GetXWindowForWidget(parent_handle), rect);
+
+ CefBrowserHost::CreateBrowser(window_info, client_handler_,
+ client_handler_->startup_url(), settings,
+ extra_info, request_context);
+}
+
+void BrowserWindowStdGtk::GetPopupConfig(CefWindowHandle temp_handle,
+ CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient>& client,
+ CefBrowserSettings& settings) {
+ CEF_REQUIRE_UI_THREAD();
+
+ // The window will be properly sized after the browser is created.
+ windowInfo.SetAsChild(temp_handle, CefRect());
+ client = client_handler_;
+}
+
+void BrowserWindowStdGtk::ShowPopup(ClientWindowHandle parent_handle,
+ int x,
+ int y,
+ size_t width,
+ size_t height) {
+ REQUIRE_MAIN_THREAD();
+
+ if (browser_) {
+ ::Window parent_xwindow = GetXWindowForWidget(parent_handle);
+ CHECK(xdisplay_ != 0);
+ ::Window xwindow = browser_->GetHost()->GetWindowHandle();
+ DCHECK(xwindow);
+
+ XReparentWindow(xdisplay_, xwindow, parent_xwindow, x, y);
+
+ SetXWindowBounds(xdisplay_, xwindow, x, y, width, height);
+ SetXWindowVisible(xdisplay_, xwindow, true);
+ }
+}
+
+void BrowserWindowStdGtk::Show() {
+ REQUIRE_MAIN_THREAD();
+
+ if (browser_) {
+ ::Window xwindow = browser_->GetHost()->GetWindowHandle();
+ DCHECK(xwindow);
+ SetXWindowVisible(xdisplay_, xwindow, true);
+ }
+}
+
+void BrowserWindowStdGtk::Hide() {
+ REQUIRE_MAIN_THREAD();
+
+ if (browser_) {
+ ::Window xwindow = browser_->GetHost()->GetWindowHandle();
+ DCHECK(xwindow);
+ SetXWindowVisible(xdisplay_, xwindow, false);
+ }
+}
+
+void BrowserWindowStdGtk::SetBounds(int x, int y, size_t width, size_t height) {
+ REQUIRE_MAIN_THREAD();
+
+ if (xdisplay_ && browser_) {
+ ::Window xwindow = browser_->GetHost()->GetWindowHandle();
+ DCHECK(xwindow);
+ SetXWindowBounds(xdisplay_, xwindow, x, y, width, height);
+ }
+}
+
+void BrowserWindowStdGtk::SetFocus(bool focus) {
+ REQUIRE_MAIN_THREAD();
+
+ if (browser_) {
+ browser_->GetHost()->SetFocus(focus);
+ }
+}
+
+ClientWindowHandle BrowserWindowStdGtk::GetWindowHandle() const {
+ REQUIRE_MAIN_THREAD();
+
+ // There is no GtkWidget* representation of this object.
+ NOTREACHED();
+ return nullptr;
+}
+
+} // namespace client
diff --git a/tests/cefclient/browser/browser_window_std_gtk.h b/tests/cefclient/browser/browser_window_std_gtk.h
new file mode 100644
index 00000000..28d50780
--- /dev/null
+++ b/tests/cefclient/browser/browser_window_std_gtk.h
@@ -0,0 +1,56 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_BROWSER_WINDOW_STD_GTK_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_BROWSER_WINDOW_STD_GTK_H_
+#pragma once
+
+#include "tests/cefclient/browser/browser_window.h"
+
+namespace client {
+
+// Represents a native child window hosting a single windowed browser instance.
+// The methods of this class must be called on the main thread unless otherwise
+// indicated.
+class BrowserWindowStdGtk : public BrowserWindow {
+ public:
+ // Constructor may be called on any thread.
+ // |delegate| must outlive this object.
+ BrowserWindowStdGtk(Delegate* delegate,
+ bool with_controls,
+ const std::string& startup_url);
+
+ // Called from RootWindowGtk::CreateRootWindow before CreateBrowser.
+ void set_xdisplay(XDisplay* xdisplay);
+
+ // BrowserWindow methods.
+ void CreateBrowser(ClientWindowHandle parent_handle,
+ const CefRect& rect,
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefDictionaryValue> extra_info,
+ CefRefPtr<CefRequestContext> request_context) override;
+ void GetPopupConfig(CefWindowHandle temp_handle,
+ CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient>& client,
+ CefBrowserSettings& settings) override;
+ void ShowPopup(ClientWindowHandle parent_handle,
+ int x,
+ int y,
+ size_t width,
+ size_t height) override;
+ void Show() override;
+ void Hide() override;
+ void SetBounds(int x, int y, size_t width, size_t height) override;
+ void SetFocus(bool focus) override;
+ ClientWindowHandle GetWindowHandle() const override;
+
+ private:
+ XDisplay* xdisplay_;
+
+ DISALLOW_COPY_AND_ASSIGN(BrowserWindowStdGtk);
+};
+
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_BROWSER_WINDOW_STD_GTK_H_
diff --git a/tests/cefclient/browser/browser_window_std_mac.h b/tests/cefclient/browser/browser_window_std_mac.h
new file mode 100644
index 00000000..8a91d8d1
--- /dev/null
+++ b/tests/cefclient/browser/browser_window_std_mac.h
@@ -0,0 +1,51 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_BROWSER_WINDOW_STD_MAC_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_BROWSER_WINDOW_STD_MAC_H_
+#pragma once
+
+#include "tests/cefclient/browser/browser_window.h"
+
+namespace client {
+
+// Represents a native child window hosting a single windowed browser instance.
+// The methods of this class must be called on the main thread unless otherwise
+// indicated.
+class BrowserWindowStdMac : public BrowserWindow {
+ public:
+ // Constructor may be called on any thread.
+ // |delegate| must outlive this object.
+ BrowserWindowStdMac(Delegate* delegate,
+ bool with_controls,
+ const std::string& startup_url);
+
+ // BrowserWindow methods.
+ void CreateBrowser(ClientWindowHandle parent_handle,
+ const CefRect& rect,
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefDictionaryValue> extra_info,
+ CefRefPtr<CefRequestContext> request_context) override;
+ void GetPopupConfig(CefWindowHandle temp_handle,
+ CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient>& client,
+ CefBrowserSettings& settings) override;
+ void ShowPopup(ClientWindowHandle parent_handle,
+ int x,
+ int y,
+ size_t width,
+ size_t height) override;
+ void Show() override;
+ void Hide() override;
+ void SetBounds(int x, int y, size_t width, size_t height) override;
+ void SetFocus(bool focus) override;
+ ClientWindowHandle GetWindowHandle() const override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BrowserWindowStdMac);
+};
+
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_BROWSER_WINDOW_STD_MAC_H_
diff --git a/tests/cefclient/browser/browser_window_std_mac.mm b/tests/cefclient/browser/browser_window_std_mac.mm
new file mode 100644
index 00000000..17ebc8ff
--- /dev/null
+++ b/tests/cefclient/browser/browser_window_std_mac.mm
@@ -0,0 +1,95 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/browser_window_std_mac.h"
+
+#include <Cocoa/Cocoa.h>
+
+#include "include/base/cef_logging.h"
+#include "tests/cefclient/browser/client_handler_std.h"
+#include "tests/shared/browser/main_message_loop.h"
+
+namespace client {
+
+BrowserWindowStdMac::BrowserWindowStdMac(Delegate* delegate,
+ bool with_controls,
+ const std::string& startup_url)
+ : BrowserWindow(delegate) {
+ client_handler_ = new ClientHandlerStd(this, with_controls, startup_url);
+}
+
+void BrowserWindowStdMac::CreateBrowser(
+ ClientWindowHandle parent_handle,
+ const CefRect& rect,
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefDictionaryValue> extra_info,
+ CefRefPtr<CefRequestContext> request_context) {
+ REQUIRE_MAIN_THREAD();
+
+ CefWindowInfo window_info;
+ window_info.SetAsChild(parent_handle, rect);
+
+ CefBrowserHost::CreateBrowser(window_info, client_handler_,
+ client_handler_->startup_url(), settings,
+ extra_info, request_context);
+}
+
+void BrowserWindowStdMac::GetPopupConfig(CefWindowHandle temp_handle,
+ CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient>& client,
+ CefBrowserSettings& settings) {
+ CEF_REQUIRE_UI_THREAD();
+
+ // The window will be properly sized after the browser is created.
+ windowInfo.SetAsChild(temp_handle, CefRect());
+ client = client_handler_;
+}
+
+void BrowserWindowStdMac::ShowPopup(ClientWindowHandle parent_handle,
+ int x,
+ int y,
+ size_t width,
+ size_t height) {
+ REQUIRE_MAIN_THREAD();
+
+ NSView* browser_view = CAST_CEF_WINDOW_HANDLE_TO_NSVIEW(GetWindowHandle());
+
+ // Re-parent |browser_view| to |parent_handle|.
+ [browser_view removeFromSuperview];
+ [CAST_CEF_WINDOW_HANDLE_TO_NSVIEW(parent_handle) addSubview:browser_view];
+
+ NSSize size = NSMakeSize(static_cast<int>(width), static_cast<int>(height));
+ [browser_view setFrameSize:size];
+}
+
+void BrowserWindowStdMac::Show() {
+ REQUIRE_MAIN_THREAD();
+ // Nothing to do here. Chromium internally handles window show/hide.
+}
+
+void BrowserWindowStdMac::Hide() {
+ REQUIRE_MAIN_THREAD();
+ // Nothing to do here. Chromium internally handles window show/hide.
+}
+
+void BrowserWindowStdMac::SetBounds(int x, int y, size_t width, size_t height) {
+ REQUIRE_MAIN_THREAD();
+ // Nothing to do here. Cocoa will size the browser for us.
+}
+
+void BrowserWindowStdMac::SetFocus(bool focus) {
+ REQUIRE_MAIN_THREAD();
+ // Nothing to do here. Chromium internally handles window focus assignment.
+}
+
+ClientWindowHandle BrowserWindowStdMac::GetWindowHandle() const {
+ REQUIRE_MAIN_THREAD();
+
+ if (browser_) {
+ return browser_->GetHost()->GetWindowHandle();
+ }
+ return nullptr;
+}
+
+} // namespace client
diff --git a/tests/cefclient/browser/browser_window_std_win.cc b/tests/cefclient/browser/browser_window_std_win.cc
new file mode 100644
index 00000000..d363377d
--- /dev/null
+++ b/tests/cefclient/browser/browser_window_std_win.cc
@@ -0,0 +1,123 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/browser_window_std_win.h"
+
+#include "tests/cefclient/browser/client_handler_std.h"
+#include "tests/shared/browser/main_message_loop.h"
+
+namespace client {
+
+BrowserWindowStdWin::BrowserWindowStdWin(Delegate* delegate,
+ bool with_controls,
+ const std::string& startup_url)
+ : BrowserWindow(delegate) {
+ client_handler_ = new ClientHandlerStd(this, with_controls, startup_url);
+}
+
+void BrowserWindowStdWin::CreateBrowser(
+ ClientWindowHandle parent_handle,
+ const CefRect& rect,
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefDictionaryValue> extra_info,
+ CefRefPtr<CefRequestContext> request_context) {
+ REQUIRE_MAIN_THREAD();
+
+ CefWindowInfo window_info;
+ window_info.SetAsChild(parent_handle, rect);
+
+ if (GetWindowLongPtr(parent_handle, GWL_EXSTYLE) & WS_EX_NOACTIVATE) {
+ // Don't activate the browser window on creation.
+ window_info.ex_style |= WS_EX_NOACTIVATE;
+ }
+
+ CefBrowserHost::CreateBrowser(window_info, client_handler_,
+ client_handler_->startup_url(), settings,
+ extra_info, request_context);
+}
+
+void BrowserWindowStdWin::GetPopupConfig(CefWindowHandle temp_handle,
+ CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient>& client,
+ CefBrowserSettings& settings) {
+ CEF_REQUIRE_UI_THREAD();
+
+ // The window will be properly sized after the browser is created.
+ windowInfo.SetAsChild(temp_handle, CefRect());
+
+ // Don't activate the hidden browser window on creation.
+ windowInfo.ex_style |= WS_EX_NOACTIVATE;
+
+ client = client_handler_;
+}
+
+void BrowserWindowStdWin::ShowPopup(ClientWindowHandle parent_handle,
+ int x,
+ int y,
+ size_t width,
+ size_t height) {
+ REQUIRE_MAIN_THREAD();
+
+ HWND hwnd = GetWindowHandle();
+ if (hwnd) {
+ SetParent(hwnd, parent_handle);
+ SetWindowPos(hwnd, nullptr, x, y, static_cast<int>(width),
+ static_cast<int>(height), SWP_NOZORDER | SWP_NOACTIVATE);
+
+ const bool no_activate =
+ GetWindowLongPtr(parent_handle, GWL_EXSTYLE) & WS_EX_NOACTIVATE;
+ ShowWindow(hwnd, no_activate ? SW_SHOWNOACTIVATE : SW_SHOW);
+ }
+}
+
+void BrowserWindowStdWin::Show() {
+ REQUIRE_MAIN_THREAD();
+
+ HWND hwnd = GetWindowHandle();
+ if (hwnd && !::IsWindowVisible(hwnd)) {
+ ShowWindow(hwnd, SW_SHOW);
+ }
+}
+
+void BrowserWindowStdWin::Hide() {
+ REQUIRE_MAIN_THREAD();
+
+ HWND hwnd = GetWindowHandle();
+ if (hwnd) {
+ // When the frame window is minimized set the browser window size to 0x0 to
+ // reduce resource usage.
+ SetWindowPos(hwnd, nullptr, 0, 0, 0, 0,
+ SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
+ }
+}
+
+void BrowserWindowStdWin::SetBounds(int x, int y, size_t width, size_t height) {
+ REQUIRE_MAIN_THREAD();
+
+ HWND hwnd = GetWindowHandle();
+ if (hwnd) {
+ // Set the browser window bounds.
+ SetWindowPos(hwnd, nullptr, x, y, static_cast<int>(width),
+ static_cast<int>(height), SWP_NOZORDER);
+ }
+}
+
+void BrowserWindowStdWin::SetFocus(bool focus) {
+ REQUIRE_MAIN_THREAD();
+
+ if (browser_) {
+ browser_->GetHost()->SetFocus(focus);
+ }
+}
+
+ClientWindowHandle BrowserWindowStdWin::GetWindowHandle() const {
+ REQUIRE_MAIN_THREAD();
+
+ if (browser_) {
+ return browser_->GetHost()->GetWindowHandle();
+ }
+ return nullptr;
+}
+
+} // namespace client
diff --git a/tests/cefclient/browser/browser_window_std_win.h b/tests/cefclient/browser/browser_window_std_win.h
new file mode 100644
index 00000000..5a7ee2a7
--- /dev/null
+++ b/tests/cefclient/browser/browser_window_std_win.h
@@ -0,0 +1,51 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_BROWSER_WINDOW_STD_WIN_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_BROWSER_WINDOW_STD_WIN_H_
+#pragma once
+
+#include "tests/cefclient/browser/browser_window.h"
+
+namespace client {
+
+// Represents a native child window hosting a single windowed browser instance.
+// The methods of this class must be called on the main thread unless otherwise
+// indicated.
+class BrowserWindowStdWin : public BrowserWindow {
+ public:
+ // Constructor may be called on any thread.
+ // |delegate| must outlive this object.
+ BrowserWindowStdWin(Delegate* delegate,
+ bool with_controls,
+ const std::string& startup_url);
+
+ // BrowserWindow methods.
+ void CreateBrowser(ClientWindowHandle parent_handle,
+ const CefRect& rect,
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefDictionaryValue> extra_info,
+ CefRefPtr<CefRequestContext> request_context) override;
+ void GetPopupConfig(CefWindowHandle temp_handle,
+ CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient>& client,
+ CefBrowserSettings& settings) override;
+ void ShowPopup(ClientWindowHandle parent_handle,
+ int x,
+ int y,
+ size_t width,
+ size_t height) override;
+ void Show() override;
+ void Hide() override;
+ void SetBounds(int x, int y, size_t width, size_t height) override;
+ void SetFocus(bool focus) override;
+ ClientWindowHandle GetWindowHandle() const override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BrowserWindowStdWin);
+};
+
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_BROWSER_WINDOW_STD_WIN_H_
diff --git a/tests/cefclient/browser/bytes_write_handler.cc b/tests/cefclient/browser/bytes_write_handler.cc
new file mode 100644
index 00000000..b05d6934
--- /dev/null
+++ b/tests/cefclient/browser/bytes_write_handler.cc
@@ -0,0 +1,100 @@
+// Copyright (c) 2014 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/bytes_write_handler.h"
+
+#include <cstdio>
+#include <cstdlib>
+
+#include "include/wrapper/cef_helpers.h"
+
+namespace client {
+
+BytesWriteHandler::BytesWriteHandler(size_t grow)
+ : grow_(grow), datasize_(grow), offset_(0) {
+ DCHECK_GT(grow, 0U);
+ data_ = malloc(grow);
+ DCHECK(data_ != nullptr);
+}
+
+BytesWriteHandler::~BytesWriteHandler() {
+ if (data_) {
+ free(data_);
+ }
+}
+
+size_t BytesWriteHandler::Write(const void* ptr, size_t size, size_t n) {
+ base::AutoLock lock_scope(lock_);
+ size_t rv;
+ if (offset_ + static_cast<int64>(size * n) >= datasize_ &&
+ Grow(size * n) == 0) {
+ rv = 0;
+ } else {
+ memcpy(reinterpret_cast<char*>(data_) + offset_, ptr, size * n);
+ offset_ += size * n;
+ rv = n;
+ }
+
+ return rv;
+}
+
+int BytesWriteHandler::Seek(int64 offset, int whence) {
+ int rv = -1L;
+ base::AutoLock lock_scope(lock_);
+ switch (whence) {
+ case SEEK_CUR:
+ if (offset_ + offset > datasize_ || offset_ + offset < 0) {
+ break;
+ }
+ offset_ += offset;
+ rv = 0;
+ break;
+ case SEEK_END: {
+ int64 offset_abs = std::abs(offset);
+ if (offset_abs > datasize_) {
+ break;
+ }
+ offset_ = datasize_ - offset_abs;
+ rv = 0;
+ break;
+ }
+ case SEEK_SET:
+ if (offset > datasize_ || offset < 0) {
+ break;
+ }
+ offset_ = offset;
+ rv = 0;
+ break;
+ }
+
+ return rv;
+}
+
+int64 BytesWriteHandler::Tell() {
+ base::AutoLock lock_scope(lock_);
+ return offset_;
+}
+
+int BytesWriteHandler::Flush() {
+ return 0;
+}
+
+size_t BytesWriteHandler::Grow(size_t size) {
+ lock_.AssertAcquired();
+ size_t rv;
+ size_t s = (size > grow_ ? size : grow_);
+ void* tmp = realloc(data_, datasize_ + s);
+ DCHECK(tmp != nullptr);
+ if (tmp) {
+ data_ = tmp;
+ datasize_ += s;
+ rv = datasize_;
+ } else {
+ rv = 0;
+ }
+
+ return rv;
+}
+
+} // namespace client
diff --git a/tests/cefclient/browser/bytes_write_handler.h b/tests/cefclient/browser/bytes_write_handler.h
new file mode 100644
index 00000000..6907675a
--- /dev/null
+++ b/tests/cefclient/browser/bytes_write_handler.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2014 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_BYTES_WRITE_HANDLER_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_BYTES_WRITE_HANDLER_H_
+#pragma once
+
+#include "include/base/cef_lock.h"
+#include "include/cef_stream.h"
+
+namespace client {
+
+class BytesWriteHandler : public CefWriteHandler {
+ public:
+ explicit BytesWriteHandler(size_t grow);
+ ~BytesWriteHandler();
+
+ size_t Write(const void* ptr, size_t size, size_t n) override;
+ int Seek(int64 offset, int whence) override;
+ int64 Tell() override;
+ int Flush() override;
+ bool MayBlock() override { return false; }
+
+ void* GetData() { return data_; }
+ int64 GetDataSize() { return offset_; }
+
+ private:
+ size_t Grow(size_t size);
+
+ size_t grow_;
+ void* data_;
+ int64 datasize_;
+ int64 offset_;
+
+ base::Lock lock_;
+
+ IMPLEMENT_REFCOUNTING(BytesWriteHandler);
+ DISALLOW_COPY_AND_ASSIGN(BytesWriteHandler);
+};
+
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_BYTES_WRITE_HANDLER_H_
diff --git a/tests/cefclient/browser/client_app_delegates_browser.cc b/tests/cefclient/browser/client_app_delegates_browser.cc
new file mode 100644
index 00000000..2d6fc64d
--- /dev/null
+++ b/tests/cefclient/browser/client_app_delegates_browser.cc
@@ -0,0 +1,20 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/shared/browser/client_app_browser.h"
+
+#include "tests/cefclient/browser/client_browser.h"
+
+namespace client {
+
+// static
+void ClientAppBrowser::RegisterCookieableSchemes(
+ std::vector<std::string>& cookieable_schemes) {}
+
+// static
+void ClientAppBrowser::CreateDelegates(DelegateSet& delegates) {
+ browser::CreateDelegates(delegates);
+}
+
+} // namespace client
diff --git a/tests/cefclient/browser/client_browser.cc b/tests/cefclient/browser/client_browser.cc
new file mode 100644
index 00000000..fd1561ca
--- /dev/null
+++ b/tests/cefclient/browser/client_browser.cc
@@ -0,0 +1,85 @@
+// Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/client_browser.h"
+#include "tests/cefclient/browser/main_context.h"
+
+#include "include/base/cef_logging.h"
+#include "include/cef_command_line.h"
+#include "include/cef_crash_util.h"
+#include "include/cef_file_util.h"
+#include "tests/cefclient/browser/client_prefs.h"
+#include "tests/cefclient/browser/default_client_handler.h"
+#include "tests/shared/common/client_switches.h"
+
+namespace client {
+namespace browser {
+
+namespace {
+
+class ClientBrowserDelegate : public ClientAppBrowser::Delegate {
+ public:
+ ClientBrowserDelegate() {}
+
+ void OnRegisterCustomPreferences(
+ CefRefPtr<client::ClientAppBrowser> app,
+ cef_preferences_type_t type,
+ CefRawPtr<CefPreferenceRegistrar> registrar) override {
+ if (type == CEF_PREFERENCES_TYPE_GLOBAL) {
+ // Register global preferences with default values.
+ prefs::RegisterGlobalPreferences(registrar);
+ }
+ }
+
+ void OnContextInitialized(CefRefPtr<ClientAppBrowser> app) override {
+ if (CefCrashReportingEnabled()) {
+ // Set some crash keys for testing purposes. Keys must be defined in the
+ // "crash_reporter.cfg" file. See cef_crash_util.h for details.
+ CefSetCrashKeyValue("testkey_small1", "value1_small_browser");
+ CefSetCrashKeyValue("testkey_small2", "value2_small_browser");
+ CefSetCrashKeyValue("testkey_medium1", "value1_medium_browser");
+ CefSetCrashKeyValue("testkey_medium2", "value2_medium_browser");
+ CefSetCrashKeyValue("testkey_large1", "value1_large_browser");
+ CefSetCrashKeyValue("testkey_large2", "value2_large_browser");
+ }
+
+ const std::string& crl_sets_path =
+ CefCommandLine::GetGlobalCommandLine()->GetSwitchValue(
+ switches::kCRLSetsPath);
+ if (!crl_sets_path.empty()) {
+ // Load the CRLSets file from the specified path.
+ CefLoadCRLSetsFile(crl_sets_path);
+ }
+ }
+
+ void OnBeforeCommandLineProcessing(
+ CefRefPtr<ClientAppBrowser> app,
+ CefRefPtr<CefCommandLine> command_line) override {
+ // Append Chromium command line parameters if touch events are enabled
+ if (client::MainContext::Get()->TouchEventsEnabled()) {
+ command_line->AppendSwitchWithValue("touch-events", "enabled");
+ }
+ }
+
+ CefRefPtr<CefClient> GetDefaultClient(
+ CefRefPtr<ClientAppBrowser> app) override {
+ // Default client handler for unmanaged browser windows. Used with the
+ // Chrome runtime only.
+ LOG(INFO) << "Creating a chrome browser with the default client";
+ return new DefaultClientHandler();
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ClientBrowserDelegate);
+ IMPLEMENT_REFCOUNTING(ClientBrowserDelegate);
+};
+
+} // namespace
+
+void CreateDelegates(ClientAppBrowser::DelegateSet& delegates) {
+ delegates.insert(new ClientBrowserDelegate);
+}
+
+} // namespace browser
+} // namespace client
diff --git a/tests/cefclient/browser/client_browser.h b/tests/cefclient/browser/client_browser.h
new file mode 100644
index 00000000..ac09e422
--- /dev/null
+++ b/tests/cefclient/browser/client_browser.h
@@ -0,0 +1,21 @@
+// Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_CLIENT_BROWSER_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_CLIENT_BROWSER_H_
+#pragma once
+
+#include "include/cef_base.h"
+#include "tests/shared/browser/client_app_browser.h"
+
+namespace client {
+namespace browser {
+
+// Create the browser delegate. Called from client_app_delegates_browser.cc.
+void CreateDelegates(ClientAppBrowser::DelegateSet& delegates);
+
+} // namespace browser
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_CLIENT_BROWSER_H_
diff --git a/tests/cefclient/browser/client_handler.cc b/tests/cefclient/browser/client_handler.cc
new file mode 100644
index 00000000..bfebba64
--- /dev/null
+++ b/tests/cefclient/browser/client_handler.cc
@@ -0,0 +1,1498 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/client_handler.h"
+
+#include <stdio.h>
+#include <algorithm>
+#include <iomanip>
+#include <sstream>
+#include <string>
+
+#include "include/base/cef_callback.h"
+#include "include/cef_browser.h"
+#include "include/cef_command_ids.h"
+#include "include/cef_frame.h"
+#include "include/cef_parser.h"
+#include "include/cef_shared_process_message_builder.h"
+#include "include/cef_ssl_status.h"
+#include "include/cef_x509_certificate.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "tests/cefclient/browser/main_context.h"
+#include "tests/cefclient/browser/root_window_manager.h"
+#include "tests/cefclient/browser/test_runner.h"
+#include "tests/shared/browser/extension_util.h"
+#include "tests/shared/browser/resource_util.h"
+#include "tests/shared/common/binary_value_utils.h"
+#include "tests/shared/common/client_switches.h"
+#include "tests/shared/common/string_util.h"
+
+namespace client {
+
+#if defined(OS_WIN)
+#define NEWLINE "\r\n"
+#else
+#define NEWLINE "\n"
+#endif
+
+namespace {
+
+// Custom menu command Ids.
+enum client_menu_ids {
+ CLIENT_ID_SHOW_DEVTOOLS = MENU_ID_USER_FIRST,
+ CLIENT_ID_CLOSE_DEVTOOLS,
+ CLIENT_ID_INSPECT_ELEMENT,
+ CLIENT_ID_SHOW_SSL_INFO,
+ CLIENT_ID_CURSOR_CHANGE_DISABLED,
+ CLIENT_ID_MEDIA_HANDLING_DISABLED,
+ CLIENT_ID_OFFLINE,
+ CLIENT_ID_TESTMENU_SUBMENU,
+ CLIENT_ID_TESTMENU_CHECKITEM,
+ CLIENT_ID_TESTMENU_RADIOITEM1,
+ CLIENT_ID_TESTMENU_RADIOITEM2,
+ CLIENT_ID_TESTMENU_RADIOITEM3,
+};
+
+// Must match the value in client_renderer.cc.
+const char kFocusedNodeChangedMessage[] = "ClientRenderer.FocusedNodeChanged";
+
+std::string GetTimeString(const CefTime& value) {
+ if (value.GetTimeT() == 0) {
+ return "Unspecified";
+ }
+
+ static const char* kMonths[] = {
+ "January", "February", "March", "April", "May", "June",
+ "July", "August", "September", "October", "November", "December"};
+ std::string month;
+ if (value.month >= 1 && value.month <= 12) {
+ month = kMonths[value.month - 1];
+ } else {
+ month = "Invalid";
+ }
+
+ std::stringstream ss;
+ ss << month << " " << value.day_of_month << ", " << value.year << " "
+ << std::setfill('0') << std::setw(2) << value.hour << ":"
+ << std::setfill('0') << std::setw(2) << value.minute << ":"
+ << std::setfill('0') << std::setw(2) << value.second;
+ return ss.str();
+}
+
+std::string GetTimeString(const CefBaseTime& value) {
+ CefTime time;
+ if (cef_time_from_basetime(value, &time)) {
+ return GetTimeString(time);
+ } else {
+ return "Invalid";
+ }
+}
+
+std::string GetBinaryString(CefRefPtr<CefBinaryValue> value) {
+ if (!value.get()) {
+ return "&nbsp;";
+ }
+
+ // Retrieve the value.
+ const size_t size = value->GetSize();
+ std::string src;
+ src.resize(size);
+ value->GetData(const_cast<char*>(src.data()), size, 0);
+
+ // Encode the value.
+ return CefBase64Encode(src.data(), src.size());
+}
+
+#define FLAG(flag) \
+ if (status & flag) { \
+ result += std::string(#flag) + "<br/>"; \
+ }
+
+#define VALUE(val, def) \
+ if (val == def) { \
+ return std::string(#def); \
+ }
+
+std::string GetCertStatusString(cef_cert_status_t status) {
+ std::string result;
+
+ FLAG(CERT_STATUS_COMMON_NAME_INVALID);
+ FLAG(CERT_STATUS_DATE_INVALID);
+ FLAG(CERT_STATUS_AUTHORITY_INVALID);
+ FLAG(CERT_STATUS_NO_REVOCATION_MECHANISM);
+ FLAG(CERT_STATUS_UNABLE_TO_CHECK_REVOCATION);
+ FLAG(CERT_STATUS_REVOKED);
+ FLAG(CERT_STATUS_INVALID);
+ FLAG(CERT_STATUS_WEAK_SIGNATURE_ALGORITHM);
+ FLAG(CERT_STATUS_NON_UNIQUE_NAME);
+ FLAG(CERT_STATUS_WEAK_KEY);
+ FLAG(CERT_STATUS_PINNED_KEY_MISSING);
+ FLAG(CERT_STATUS_NAME_CONSTRAINT_VIOLATION);
+ FLAG(CERT_STATUS_VALIDITY_TOO_LONG);
+ FLAG(CERT_STATUS_IS_EV);
+ FLAG(CERT_STATUS_REV_CHECKING_ENABLED);
+ FLAG(CERT_STATUS_SHA1_SIGNATURE_PRESENT);
+ FLAG(CERT_STATUS_CT_COMPLIANCE_FAILED);
+
+ if (result.empty()) {
+ return "&nbsp;";
+ }
+ return result;
+}
+
+std::string GetSSLVersionString(cef_ssl_version_t version) {
+ VALUE(version, SSL_CONNECTION_VERSION_UNKNOWN);
+ VALUE(version, SSL_CONNECTION_VERSION_SSL2);
+ VALUE(version, SSL_CONNECTION_VERSION_SSL3);
+ VALUE(version, SSL_CONNECTION_VERSION_TLS1);
+ VALUE(version, SSL_CONNECTION_VERSION_TLS1_1);
+ VALUE(version, SSL_CONNECTION_VERSION_TLS1_2);
+ VALUE(version, SSL_CONNECTION_VERSION_TLS1_3);
+ VALUE(version, SSL_CONNECTION_VERSION_QUIC);
+ return std::string();
+}
+
+std::string GetContentStatusString(cef_ssl_content_status_t status) {
+ std::string result;
+
+ VALUE(status, SSL_CONTENT_NORMAL_CONTENT);
+ FLAG(SSL_CONTENT_DISPLAYED_INSECURE_CONTENT);
+ FLAG(SSL_CONTENT_RAN_INSECURE_CONTENT);
+
+ if (result.empty()) {
+ return "&nbsp;";
+ }
+ return result;
+}
+
+// Load a data: URI containing the error message.
+void LoadErrorPage(CefRefPtr<CefFrame> frame,
+ const std::string& failed_url,
+ cef_errorcode_t error_code,
+ const std::string& other_info) {
+ std::stringstream ss;
+ ss << "<html><head><title>Page failed to load</title></head>"
+ "<body bgcolor=\"white\">"
+ "<h3>Page failed to load.</h3>"
+ "URL: <a href=\""
+ << failed_url << "\">" << failed_url
+ << "</a><br/>Error: " << test_runner::GetErrorString(error_code) << " ("
+ << error_code << ")";
+
+ if (!other_info.empty()) {
+ ss << "<br/>" << other_info;
+ }
+
+ ss << "</body></html>";
+ frame->LoadURL(test_runner::GetDataURI(ss.str(), "text/html"));
+}
+
+// Return HTML string with information about a certificate.
+std::string GetCertificateInformation(CefRefPtr<CefX509Certificate> cert,
+ cef_cert_status_t certstatus) {
+ CefRefPtr<CefX509CertPrincipal> subject = cert->GetSubject();
+ CefRefPtr<CefX509CertPrincipal> issuer = cert->GetIssuer();
+
+ // Build a table showing certificate information. Various types of invalid
+ // certificates can be tested using https://badssl.com/.
+ std::stringstream ss;
+ ss << "<h3>X.509 Certificate Information:</h3>"
+ "<table border=1><tr><th>Field</th><th>Value</th></tr>";
+
+ if (certstatus != CERT_STATUS_NONE) {
+ ss << "<tr><td>Status</td><td>" << GetCertStatusString(certstatus)
+ << "</td></tr>";
+ }
+
+ ss << "<tr><td>Subject</td><td>"
+ << (subject.get() ? subject->GetDisplayName().ToString() : "&nbsp;")
+ << "</td></tr>"
+ "<tr><td>Issuer</td><td>"
+ << (issuer.get() ? issuer->GetDisplayName().ToString() : "&nbsp;")
+ << "</td></tr>"
+ "<tr><td>Serial #*</td><td>"
+ << GetBinaryString(cert->GetSerialNumber()) << "</td></tr>"
+ << "<tr><td>Valid Start</td><td>" << GetTimeString(cert->GetValidStart())
+ << "</td></tr>"
+ "<tr><td>Valid Expiry</td><td>"
+ << GetTimeString(cert->GetValidExpiry()) << "</td></tr>";
+
+ CefX509Certificate::IssuerChainBinaryList der_chain_list;
+ CefX509Certificate::IssuerChainBinaryList pem_chain_list;
+ cert->GetDEREncodedIssuerChain(der_chain_list);
+ cert->GetPEMEncodedIssuerChain(pem_chain_list);
+ DCHECK_EQ(der_chain_list.size(), pem_chain_list.size());
+
+ der_chain_list.insert(der_chain_list.begin(), cert->GetDEREncoded());
+ pem_chain_list.insert(pem_chain_list.begin(), cert->GetPEMEncoded());
+
+ for (size_t i = 0U; i < der_chain_list.size(); ++i) {
+ ss << "<tr><td>DER Encoded*</td>"
+ "<td style=\"max-width:800px;overflow:scroll;\">"
+ << GetBinaryString(der_chain_list[i])
+ << "</td></tr>"
+ "<tr><td>PEM Encoded*</td>"
+ "<td style=\"max-width:800px;overflow:scroll;\">"
+ << GetBinaryString(pem_chain_list[i]) << "</td></tr>";
+ }
+
+ ss << "</table> * Displayed value is base64 encoded.";
+ return ss.str();
+}
+
+void OnTestProcessMessageReceived(
+ const CefRefPtr<CefFrame>& frame,
+ const CefRefPtr<CefProcessMessage>& process_message,
+ const bv_utils::TimePoint& finish_time) {
+ DCHECK(process_message->IsValid());
+
+ CefRefPtr<CefListValue> input_args = process_message->GetArgumentList();
+ DCHECK_EQ(input_args->GetSize(), 1U);
+
+ const auto renderer_msg =
+ bv_utils::GetRendererMsgFromBinary(input_args->GetBinary(0));
+
+ CefRefPtr<CefProcessMessage> response =
+ CefProcessMessage::Create(bv_utils::kTestSendProcessMessage);
+ CefRefPtr<CefListValue> args = response->GetArgumentList();
+
+ const auto message_size = std::max(input_args->GetBinary(0)->GetSize(),
+ sizeof(bv_utils::BrowserMessage));
+ std::vector<uint8_t> data(message_size);
+
+ const auto browser_msg =
+ reinterpret_cast<bv_utils::BrowserMessage*>(data.data());
+ browser_msg->test_id = renderer_msg.test_id;
+ browser_msg->duration = finish_time - renderer_msg.start_time;
+ browser_msg->start_time = bv_utils::Now();
+
+ args->SetBinary(0, bv_utils::CreateCefBinaryValue(data));
+ frame->SendProcessMessage(PID_RENDERER, response);
+}
+
+void OnTestSMRProcessMessageReceived(
+ const CefRefPtr<CefFrame>& frame,
+ const CefRefPtr<CefProcessMessage>& process_message,
+ const bv_utils::TimePoint& finish_time) {
+ DCHECK(process_message->IsValid());
+
+ CefRefPtr<CefSharedMemoryRegion> region =
+ process_message->GetSharedMemoryRegion();
+ DCHECK_GE(region->Size(), sizeof(bv_utils::RendererMessage));
+
+ const auto renderer_msg =
+ static_cast<const bv_utils::RendererMessage*>(region->Memory());
+ const auto message_size =
+ std::max(region->Size(), sizeof(bv_utils::BrowserMessage));
+ const auto renderer_time = renderer_msg->start_time;
+ const auto duration = finish_time - renderer_time;
+ const auto start_time = bv_utils::Now();
+
+ auto builder = CefSharedProcessMessageBuilder::Create(
+ bv_utils::kTestSendSMRProcessMessage, message_size);
+
+ const auto browser_msg =
+ static_cast<bv_utils::BrowserMessage*>(builder->Memory());
+ browser_msg->test_id = renderer_msg->test_id;
+ browser_msg->duration = duration;
+ browser_msg->start_time = start_time;
+
+ frame->SendProcessMessage(PID_RENDERER, builder->Build());
+}
+
+} // namespace
+
+class ClientDownloadImageCallback : public CefDownloadImageCallback {
+ public:
+ explicit ClientDownloadImageCallback(CefRefPtr<ClientHandler> client_handler)
+ : client_handler_(client_handler) {}
+
+ void OnDownloadImageFinished(const CefString& image_url,
+ int http_status_code,
+ CefRefPtr<CefImage> image) override {
+ if (image) {
+ client_handler_->NotifyFavicon(image);
+ }
+ }
+
+ private:
+ CefRefPtr<ClientHandler> client_handler_;
+
+ IMPLEMENT_REFCOUNTING(ClientDownloadImageCallback);
+ DISALLOW_COPY_AND_ASSIGN(ClientDownloadImageCallback);
+};
+
+ClientHandler::ClientHandler(Delegate* delegate,
+ bool is_osr,
+ bool with_controls,
+ const std::string& startup_url)
+ : is_osr_(is_osr),
+ with_controls_(with_controls),
+ startup_url_(startup_url),
+ delegate_(delegate),
+ console_log_file_(MainContext::Get()->GetConsoleLogPath()) {
+ DCHECK(!console_log_file_.empty());
+
+ resource_manager_ = new CefResourceManager();
+ test_runner::SetupResourceManager(resource_manager_, &string_resource_map_);
+
+ // Read command line settings.
+ CefRefPtr<CefCommandLine> command_line =
+ CefCommandLine::GetGlobalCommandLine();
+ mouse_cursor_change_disabled_ =
+ command_line->HasSwitch(switches::kMouseCursorChangeDisabled);
+ offline_ = command_line->HasSwitch(switches::kOffline);
+
+#if defined(OS_LINUX)
+ // Optionally use the client-provided GTK dialogs.
+ const bool use_client_dialogs =
+ command_line->HasSwitch(switches::kUseClientDialogs);
+
+ // Determine if the client-provided GTK dialogs can/should be used.
+ bool require_client_dialogs = false;
+ bool support_client_dialogs = true;
+
+ if (command_line->HasSwitch(switches::kMultiThreadedMessageLoop)) {
+ // Default/internal GTK dialogs are not supported in combination with
+ // multi-threaded-message-loop because Chromium doesn't support GDK threads.
+ // This does not apply to the JS dialogs which use Views instead of GTK.
+ if (!use_client_dialogs) {
+ LOG(WARNING) << "Client dialogs must be used in combination with "
+ "multi-threaded-message-loop.";
+ }
+ require_client_dialogs = true;
+ }
+
+ if (MainContext::Get()->UseViews()) {
+ // Client-provided GTK dialogs cannot be used in combination with Views
+ // because the implementation of ClientDialogHandlerGtk requires a top-level
+ // GtkWindow.
+ if (use_client_dialogs) {
+ LOG(ERROR) << "Client dialogs cannot be used in combination with Views.";
+ }
+ support_client_dialogs = false;
+ }
+
+ if (support_client_dialogs) {
+ if (use_client_dialogs) {
+ js_dialog_handler_ = new ClientDialogHandlerGtk();
+ }
+ if (use_client_dialogs || require_client_dialogs) {
+ file_dialog_handler_ = js_dialog_handler_ ? js_dialog_handler_
+ : new ClientDialogHandlerGtk();
+ print_handler_ = new ClientPrintHandlerGtk();
+ }
+ }
+#endif // defined(OS_LINUX)
+}
+
+void ClientHandler::DetachDelegate() {
+ if (!CURRENTLY_ON_MAIN_THREAD()) {
+ // Execute this method on the main thread.
+ MAIN_POST_CLOSURE(base::BindOnce(&ClientHandler::DetachDelegate, this));
+ return;
+ }
+
+ DCHECK(delegate_);
+ delegate_ = nullptr;
+}
+
+bool ClientHandler::OnProcessMessageReceived(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefProcessId source_process,
+ CefRefPtr<CefProcessMessage> message) {
+ CEF_REQUIRE_UI_THREAD();
+
+ const auto finish_time = bv_utils::Now();
+
+ if (message_router_->OnProcessMessageReceived(browser, frame, source_process,
+ message)) {
+ return true;
+ }
+
+ // Check for messages from the client renderer.
+ const std::string& message_name = message->GetName();
+ if (message_name == kFocusedNodeChangedMessage) {
+ // A message is sent from ClientRenderDelegate to tell us whether the
+ // currently focused DOM node is editable. Use of |focus_on_editable_field_|
+ // is redundant with CefKeyEvent.focus_on_editable_field in OnPreKeyEvent
+ // but is useful for demonstration purposes.
+ focus_on_editable_field_ = message->GetArgumentList()->GetBool(0);
+ return true;
+ }
+
+ if (message_name == bv_utils::kTestSendProcessMessage) {
+ OnTestProcessMessageReceived(frame, message, finish_time);
+ return true;
+ }
+
+ if (message_name == bv_utils::kTestSendSMRProcessMessage) {
+ OnTestSMRProcessMessageReceived(frame, message, finish_time);
+ return true;
+ }
+
+ return false;
+}
+
+bool ClientHandler::OnChromeCommand(CefRefPtr<CefBrowser> browser,
+ int command_id,
+ cef_window_open_disposition_t disposition) {
+ CEF_REQUIRE_UI_THREAD();
+ DCHECK(MainContext::Get()->UseChromeRuntime());
+
+ if (!with_controls_ &&
+ (disposition != WOD_CURRENT_TAB || !IsAllowedCommandId(command_id))) {
+ // Block everything that doesn't target the current tab or isn't an
+ // allowed command ID.
+ LOG(INFO) << "Blocking command " << command_id << " with disposition "
+ << disposition;
+ return true;
+ }
+
+ // Default handling.
+ return false;
+}
+
+void ClientHandler::OnBeforeContextMenu(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefContextMenuParams> params,
+ CefRefPtr<CefMenuModel> model) {
+ CEF_REQUIRE_UI_THREAD();
+
+ const bool use_chrome_runtime = MainContext::Get()->UseChromeRuntime();
+ if (use_chrome_runtime && !with_controls_) {
+ // Remove all disallowed menu items.
+ FilterMenuModel(model);
+ }
+
+ if ((params->GetTypeFlags() & (CM_TYPEFLAG_PAGE | CM_TYPEFLAG_FRAME)) != 0) {
+ // Add a separator if the menu already has items.
+ if (model->GetCount() > 0) {
+ model->AddSeparator();
+ }
+
+ if (!use_chrome_runtime) {
+ // TODO(chrome-runtime): Add support for this.
+ // Add DevTools items to all context menus.
+ model->AddItem(CLIENT_ID_SHOW_DEVTOOLS, "&Show DevTools");
+ model->AddItem(CLIENT_ID_CLOSE_DEVTOOLS, "Close DevTools");
+ model->AddSeparator();
+ model->AddItem(CLIENT_ID_INSPECT_ELEMENT, "Inspect Element");
+ }
+
+ if (HasSSLInformation(browser)) {
+ model->AddSeparator();
+ model->AddItem(CLIENT_ID_SHOW_SSL_INFO, "Show SSL information");
+ }
+
+ if (!use_chrome_runtime) {
+ // TODO(chrome-runtime): Add support for this.
+ model->AddSeparator();
+ model->AddCheckItem(CLIENT_ID_CURSOR_CHANGE_DISABLED,
+ "Cursor change disabled");
+ if (mouse_cursor_change_disabled_) {
+ model->SetChecked(CLIENT_ID_CURSOR_CHANGE_DISABLED, true);
+ }
+
+ model->AddSeparator();
+ model->AddCheckItem(CLIENT_ID_MEDIA_HANDLING_DISABLED,
+ "Media handling disabled");
+ if (media_handling_disabled_) {
+ model->SetChecked(CLIENT_ID_MEDIA_HANDLING_DISABLED, true);
+ }
+ }
+
+ model->AddSeparator();
+ model->AddCheckItem(CLIENT_ID_OFFLINE, "Offline mode");
+ if (offline_) {
+ model->SetChecked(CLIENT_ID_OFFLINE, true);
+ }
+
+ // Test context menu features.
+ BuildTestMenu(model);
+ }
+
+ if (delegate_) {
+ delegate_->OnBeforeContextMenu(model);
+ }
+}
+
+bool ClientHandler::OnContextMenuCommand(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefContextMenuParams> params,
+ int command_id,
+ EventFlags event_flags) {
+ CEF_REQUIRE_UI_THREAD();
+
+ switch (command_id) {
+ case CLIENT_ID_SHOW_DEVTOOLS:
+ ShowDevTools(browser, CefPoint());
+ return true;
+ case CLIENT_ID_CLOSE_DEVTOOLS:
+ CloseDevTools(browser);
+ return true;
+ case CLIENT_ID_INSPECT_ELEMENT:
+ ShowDevTools(browser, CefPoint(params->GetXCoord(), params->GetYCoord()));
+ return true;
+ case CLIENT_ID_SHOW_SSL_INFO:
+ ShowSSLInformation(browser);
+ return true;
+ case CLIENT_ID_CURSOR_CHANGE_DISABLED:
+ mouse_cursor_change_disabled_ = !mouse_cursor_change_disabled_;
+ return true;
+ case CLIENT_ID_MEDIA_HANDLING_DISABLED:
+ media_handling_disabled_ = !media_handling_disabled_;
+ return true;
+ case CLIENT_ID_OFFLINE:
+ offline_ = !offline_;
+ SetOfflineState(browser, offline_);
+ return true;
+ default: // Allow default handling, if any.
+ return ExecuteTestMenu(command_id);
+ }
+}
+
+void ClientHandler::OnAddressChange(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const CefString& url) {
+ CEF_REQUIRE_UI_THREAD();
+
+ // Only update the address for the main (top-level) frame.
+ if (frame->IsMain()) {
+ NotifyAddress(url);
+ }
+}
+
+void ClientHandler::OnTitleChange(CefRefPtr<CefBrowser> browser,
+ const CefString& title) {
+ CEF_REQUIRE_UI_THREAD();
+
+ NotifyTitle(title);
+}
+
+void ClientHandler::OnFaviconURLChange(
+ CefRefPtr<CefBrowser> browser,
+ const std::vector<CefString>& icon_urls) {
+ CEF_REQUIRE_UI_THREAD();
+
+ if (!icon_urls.empty() && download_favicon_images_) {
+ browser->GetHost()->DownloadImage(icon_urls[0], true, 16, false,
+ new ClientDownloadImageCallback(this));
+ }
+}
+
+void ClientHandler::OnFullscreenModeChange(CefRefPtr<CefBrowser> browser,
+ bool fullscreen) {
+ CEF_REQUIRE_UI_THREAD();
+
+ NotifyFullscreen(fullscreen);
+}
+
+bool ClientHandler::OnConsoleMessage(CefRefPtr<CefBrowser> browser,
+ cef_log_severity_t level,
+ const CefString& message,
+ const CefString& source,
+ int line) {
+ CEF_REQUIRE_UI_THREAD();
+
+ FILE* file = fopen(console_log_file_.c_str(), "a");
+ if (file) {
+ std::stringstream ss;
+ ss << "Level: ";
+ switch (level) {
+ case LOGSEVERITY_DEBUG:
+ ss << "Debug" << NEWLINE;
+ break;
+ case LOGSEVERITY_INFO:
+ ss << "Info" << NEWLINE;
+ break;
+ case LOGSEVERITY_WARNING:
+ ss << "Warn" << NEWLINE;
+ break;
+ case LOGSEVERITY_ERROR:
+ ss << "Error" << NEWLINE;
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+ ss << "Message: " << message.ToString() << NEWLINE
+ << "Source: " << source.ToString() << NEWLINE << "Line: " << line
+ << NEWLINE << "-----------------------" << NEWLINE;
+ fputs(ss.str().c_str(), file);
+ fclose(file);
+ }
+
+ return false;
+}
+
+bool ClientHandler::OnAutoResize(CefRefPtr<CefBrowser> browser,
+ const CefSize& new_size) {
+ CEF_REQUIRE_UI_THREAD();
+
+ NotifyAutoResize(new_size);
+ return true;
+}
+
+bool ClientHandler::OnCursorChange(CefRefPtr<CefBrowser> browser,
+ CefCursorHandle cursor,
+ cef_cursor_type_t type,
+ const CefCursorInfo& custom_cursor_info) {
+ CEF_REQUIRE_UI_THREAD();
+
+ // Return true to disable default handling of cursor changes.
+ return mouse_cursor_change_disabled_;
+}
+
+bool ClientHandler::CanDownload(CefRefPtr<CefBrowser> browser,
+ const CefString& url,
+ const CefString& request_method) {
+ CEF_REQUIRE_UI_THREAD();
+
+ if (!with_controls_) {
+ // Block the download.
+ LOG(INFO) << "Blocking download";
+ return false;
+ }
+
+ // Allow the download.
+ return true;
+}
+
+void ClientHandler::OnBeforeDownload(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefDownloadItem> download_item,
+ const CefString& suggested_name,
+ CefRefPtr<CefBeforeDownloadCallback> callback) {
+ CEF_REQUIRE_UI_THREAD();
+
+ // Continue the download and show the "Save As" dialog.
+ callback->Continue(MainContext::Get()->GetDownloadPath(suggested_name), true);
+}
+
+void ClientHandler::OnDownloadUpdated(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefDownloadItem> download_item,
+ CefRefPtr<CefDownloadItemCallback> callback) {
+ CEF_REQUIRE_UI_THREAD();
+
+ if (download_item->IsComplete()) {
+ test_runner::Alert(browser, "File \"" +
+ download_item->GetFullPath().ToString() +
+ "\" downloaded successfully.");
+ }
+}
+
+bool ClientHandler::OnDragEnter(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefDragData> dragData,
+ CefDragHandler::DragOperationsMask mask) {
+ CEF_REQUIRE_UI_THREAD();
+
+ // Forbid dragging of URLs and files.
+ if ((mask & DRAG_OPERATION_LINK) && !dragData->IsFragment()) {
+ test_runner::Alert(browser, "cefclient blocks dragging of URLs and files");
+ return true;
+ }
+
+ return false;
+}
+
+void ClientHandler::OnDraggableRegionsChanged(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const std::vector<CefDraggableRegion>& regions) {
+ CEF_REQUIRE_UI_THREAD();
+
+ NotifyDraggableRegions(regions);
+}
+
+void ClientHandler::OnTakeFocus(CefRefPtr<CefBrowser> browser, bool next) {
+ CEF_REQUIRE_UI_THREAD();
+
+ NotifyTakeFocus(next);
+}
+
+bool ClientHandler::OnSetFocus(CefRefPtr<CefBrowser> browser,
+ FocusSource source) {
+ CEF_REQUIRE_UI_THREAD();
+
+ if (initial_navigation_) {
+ CefRefPtr<CefCommandLine> command_line =
+ CefCommandLine::GetGlobalCommandLine();
+ if (command_line->HasSwitch(switches::kNoActivate)) {
+ // Don't give focus to the browser on creation.
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool ClientHandler::OnPreKeyEvent(CefRefPtr<CefBrowser> browser,
+ const CefKeyEvent& event,
+ CefEventHandle os_event,
+ bool* is_keyboard_shortcut) {
+ CEF_REQUIRE_UI_THREAD();
+
+ /*
+ if (!event.focus_on_editable_field && event.windows_key_code == 0x20) {
+ // Special handling for the space character when an input element does not
+ // have focus. Handling the event in OnPreKeyEvent() keeps the event from
+ // being processed in the renderer. If we instead handled the event in the
+ // OnKeyEvent() method the space key would cause the window to scroll in
+ // addition to showing the alert box.
+ if (event.type == KEYEVENT_RAWKEYDOWN)
+ test_runner::Alert(browser, "You pressed the space bar!");
+ return true;
+ }
+ */
+
+ return false;
+}
+
+bool ClientHandler::OnBeforePopup(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const CefString& target_url,
+ const CefString& target_frame_name,
+ CefLifeSpanHandler::WindowOpenDisposition target_disposition,
+ bool user_gesture,
+ const CefPopupFeatures& popupFeatures,
+ CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient>& client,
+ CefBrowserSettings& settings,
+ CefRefPtr<CefDictionaryValue>& extra_info,
+ bool* no_javascript_access) {
+ CEF_REQUIRE_UI_THREAD();
+
+ if (target_disposition == WOD_NEW_PICTURE_IN_PICTURE) {
+ // Use default handling for document picture-in-picture popups.
+ client = nullptr;
+ return false;
+ }
+
+ // Return true to cancel the popup window.
+ return !CreatePopupWindow(browser, false, popupFeatures, windowInfo, client,
+ settings);
+}
+
+void ClientHandler::OnAfterCreated(CefRefPtr<CefBrowser> browser) {
+ CEF_REQUIRE_UI_THREAD();
+
+ browser_count_++;
+
+ if (!message_router_) {
+ // Create the browser-side router for query handling.
+ CefMessageRouterConfig config;
+ message_router_ = CefMessageRouterBrowserSide::Create(config);
+
+ // Register handlers with the router.
+ test_runner::CreateMessageHandlers(message_handler_set_);
+ MessageHandlerSet::const_iterator it = message_handler_set_.begin();
+ for (; it != message_handler_set_.end(); ++it) {
+ message_router_->AddHandler(*(it), false);
+ }
+ }
+
+ // Set offline mode if requested via the command-line flag.
+ if (offline_) {
+ SetOfflineState(browser, true);
+ }
+
+ if (browser->GetHost()->GetExtension()) {
+ // Browsers hosting extension apps should auto-resize.
+ browser->GetHost()->SetAutoResizeEnabled(true, CefSize(20, 20),
+ CefSize(1000, 1000));
+
+ CefRefPtr<CefExtension> extension = browser->GetHost()->GetExtension();
+ if (extension_util::IsInternalExtension(extension->GetPath())) {
+ // Register the internal handler for extension resources.
+ extension_util::AddInternalExtensionToResourceManager(extension,
+ resource_manager_);
+ }
+ }
+
+ NotifyBrowserCreated(browser);
+}
+
+bool ClientHandler::DoClose(CefRefPtr<CefBrowser> browser) {
+ CEF_REQUIRE_UI_THREAD();
+
+ NotifyBrowserClosing(browser);
+
+ // Allow the close. For windowed browsers this will result in the OS close
+ // event being sent.
+ return false;
+}
+
+void ClientHandler::OnBeforeClose(CefRefPtr<CefBrowser> browser) {
+ CEF_REQUIRE_UI_THREAD();
+
+ if (--browser_count_ == 0) {
+ // Remove and delete message router handlers.
+ MessageHandlerSet::const_iterator it = message_handler_set_.begin();
+ for (; it != message_handler_set_.end(); ++it) {
+ message_router_->RemoveHandler(*(it));
+ delete *(it);
+ }
+ message_handler_set_.clear();
+ message_router_ = nullptr;
+ }
+
+ NotifyBrowserClosed(browser);
+}
+
+void ClientHandler::OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
+ bool isLoading,
+ bool canGoBack,
+ bool canGoForward) {
+ CEF_REQUIRE_UI_THREAD();
+
+ if (!isLoading && initial_navigation_) {
+ initial_navigation_ = false;
+ }
+
+ NotifyLoadingState(isLoading, canGoBack, canGoForward);
+}
+
+void ClientHandler::OnLoadError(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ ErrorCode errorCode,
+ const CefString& errorText,
+ const CefString& failedUrl) {
+ CEF_REQUIRE_UI_THREAD();
+
+ // Don't display an error for downloaded files.
+ if (errorCode == ERR_ABORTED) {
+ return;
+ }
+
+ // Don't display an error for external protocols that we allow the OS to
+ // handle. See OnProtocolExecution().
+ if (errorCode == ERR_UNKNOWN_URL_SCHEME) {
+ std::string urlStr = frame->GetURL();
+ if (urlStr.find("spotify:") == 0) {
+ return;
+ }
+ }
+
+ // Load the error page.
+ LoadErrorPage(frame, failedUrl, errorCode, errorText);
+}
+
+bool ClientHandler::OnRequestMediaAccessPermission(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const CefString& requesting_origin,
+ uint32 requested_permissions,
+ CefRefPtr<CefMediaAccessCallback> callback) {
+ callback->Continue(media_handling_disabled_ ? CEF_MEDIA_PERMISSION_NONE
+ : requested_permissions);
+ return true;
+}
+
+bool ClientHandler::OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ bool user_gesture,
+ bool is_redirect) {
+ CEF_REQUIRE_UI_THREAD();
+
+ message_router_->OnBeforeBrowse(browser, frame);
+ return false;
+}
+
+bool ClientHandler::OnOpenURLFromTab(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const CefString& target_url,
+ CefRequestHandler::WindowOpenDisposition target_disposition,
+ bool user_gesture) {
+ if (target_disposition == WOD_NEW_BACKGROUND_TAB ||
+ target_disposition == WOD_NEW_FOREGROUND_TAB) {
+ // Handle middle-click and ctrl + left-click by opening the URL in a new
+ // browser window.
+ auto config = std::make_unique<RootWindowConfig>();
+ config->with_controls = with_controls_;
+ config->with_osr = is_osr_;
+ config->url = target_url;
+ MainContext::Get()->GetRootWindowManager()->CreateRootWindow(
+ std::move(config));
+ return true;
+ }
+
+ // Open the URL in the current browser window.
+ return false;
+}
+
+CefRefPtr<CefResourceRequestHandler> ClientHandler::GetResourceRequestHandler(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ bool is_navigation,
+ bool is_download,
+ const CefString& request_initiator,
+ bool& disable_default_handling) {
+ CEF_REQUIRE_IO_THREAD();
+ return this;
+}
+
+bool ClientHandler::GetAuthCredentials(CefRefPtr<CefBrowser> browser,
+ const CefString& origin_url,
+ bool isProxy,
+ const CefString& host,
+ int port,
+ const CefString& realm,
+ const CefString& scheme,
+ CefRefPtr<CefAuthCallback> callback) {
+ CEF_REQUIRE_IO_THREAD();
+
+ // Used for testing authentication with a proxy server.
+ // For example, CCProxy on Windows.
+ if (isProxy) {
+ callback->Continue("guest", "guest");
+ return true;
+ }
+
+ // Used for testing authentication with https://jigsaw.w3.org/HTTP/.
+ if (host == "jigsaw.w3.org") {
+ callback->Continue("guest", "guest");
+ return true;
+ }
+
+ return false;
+}
+
+bool ClientHandler::OnCertificateError(CefRefPtr<CefBrowser> browser,
+ ErrorCode cert_error,
+ const CefString& request_url,
+ CefRefPtr<CefSSLInfo> ssl_info,
+ CefRefPtr<CefCallback> callback) {
+ CEF_REQUIRE_UI_THREAD();
+
+ if (cert_error == ERR_CERT_COMMON_NAME_INVALID &&
+ request_url.ToString().find("https://www.magpcss.com/") == 0U) {
+ // Allow magpcss.com to load despite having a certificate common name of
+ // magpcss.org.
+ callback->Continue();
+ return true;
+ }
+
+ CefRefPtr<CefX509Certificate> cert = ssl_info->GetX509Certificate();
+ if (cert.get()) {
+ // Load the error page.
+ LoadErrorPage(browser->GetMainFrame(), request_url, cert_error,
+ GetCertificateInformation(cert, ssl_info->GetCertStatus()));
+ }
+
+ return false; // Cancel the request.
+}
+
+bool ClientHandler::OnSelectClientCertificate(
+ CefRefPtr<CefBrowser> browser,
+ bool isProxy,
+ const CefString& host,
+ int port,
+ const X509CertificateList& certificates,
+ CefRefPtr<CefSelectClientCertificateCallback> callback) {
+ CEF_REQUIRE_UI_THREAD();
+
+ CefRefPtr<CefCommandLine> command_line =
+ CefCommandLine::GetGlobalCommandLine();
+ if (!command_line->HasSwitch(switches::kSslClientCertificate)) {
+ return false;
+ }
+
+ const std::string& cert_name =
+ command_line->GetSwitchValue(switches::kSslClientCertificate);
+
+ if (cert_name.empty()) {
+ callback->Select(nullptr);
+ return true;
+ }
+
+ std::vector<CefRefPtr<CefX509Certificate>>::const_iterator it =
+ certificates.begin();
+ for (; it != certificates.end(); ++it) {
+ CefString subject((*it)->GetSubject()->GetDisplayName());
+ if (subject == cert_name) {
+ callback->Select(*it);
+ return true;
+ }
+ }
+
+ return true;
+}
+
+void ClientHandler::OnRenderProcessTerminated(CefRefPtr<CefBrowser> browser,
+ TerminationStatus status) {
+ CEF_REQUIRE_UI_THREAD();
+
+ message_router_->OnRenderProcessTerminated(browser);
+
+ // Don't reload if there's no start URL, or if the crash URL was specified.
+ if (startup_url_.empty() || startup_url_ == "chrome://crash") {
+ return;
+ }
+
+ CefRefPtr<CefFrame> frame = browser->GetMainFrame();
+ std::string url = frame->GetURL();
+
+ // Don't reload if the termination occurred before any URL had successfully
+ // loaded.
+ if (url.empty()) {
+ return;
+ }
+
+ // Convert URLs to lowercase for easier comparison.
+ url = AsciiStrToLower(url);
+ const std::string& start_url = AsciiStrToLower(startup_url_);
+
+ // Don't reload the URL that just resulted in termination.
+ if (url.find(start_url) == 0) {
+ return;
+ }
+
+ frame->LoadURL(startup_url_);
+}
+
+void ClientHandler::OnDocumentAvailableInMainFrame(
+ CefRefPtr<CefBrowser> browser) {
+ CEF_REQUIRE_UI_THREAD();
+
+ // Restore offline mode after main frame navigation. Otherwise, offline state
+ // (e.g. `navigator.onLine`) might be wrong in the renderer process.
+ if (offline_) {
+ SetOfflineState(browser, true);
+ }
+}
+
+cef_return_value_t ClientHandler::OnBeforeResourceLoad(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefCallback> callback) {
+ CEF_REQUIRE_IO_THREAD();
+
+ return resource_manager_->OnBeforeResourceLoad(browser, frame, request,
+ callback);
+}
+
+CefRefPtr<CefResourceHandler> ClientHandler::GetResourceHandler(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request) {
+ CEF_REQUIRE_IO_THREAD();
+
+ return resource_manager_->GetResourceHandler(browser, frame, request);
+}
+
+CefRefPtr<CefResponseFilter> ClientHandler::GetResourceResponseFilter(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response) {
+ CEF_REQUIRE_IO_THREAD();
+
+ return test_runner::GetResourceResponseFilter(browser, frame, request,
+ response);
+}
+
+void ClientHandler::OnProtocolExecution(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ bool& allow_os_execution) {
+ CEF_REQUIRE_IO_THREAD();
+
+ std::string urlStr = request->GetURL();
+
+ // Allow OS execution of Spotify URIs.
+ if (urlStr.find("spotify:") == 0) {
+ allow_os_execution = true;
+ }
+}
+
+int ClientHandler::GetBrowserCount() const {
+ CEF_REQUIRE_UI_THREAD();
+ return browser_count_;
+}
+
+void ClientHandler::ShowDevTools(CefRefPtr<CefBrowser> browser,
+ const CefPoint& inspect_element_at) {
+ if (!CefCurrentlyOn(TID_UI)) {
+ // Execute this method on the UI thread.
+ CefPostTask(TID_UI, base::BindOnce(&ClientHandler::ShowDevTools, this,
+ browser, inspect_element_at));
+ return;
+ }
+
+ CefWindowInfo windowInfo;
+ CefRefPtr<CefClient> client;
+ CefBrowserSettings settings;
+
+ MainContext::Get()->PopulateBrowserSettings(&settings);
+
+ CefRefPtr<CefBrowserHost> host = browser->GetHost();
+
+ // Test if the DevTools browser already exists.
+ bool has_devtools = host->HasDevTools();
+ if (!has_devtools) {
+ // Create a new RootWindow for the DevTools browser that will be created
+ // by ShowDevTools().
+ has_devtools = CreatePopupWindow(browser, true, CefPopupFeatures(),
+ windowInfo, client, settings);
+ }
+
+ if (has_devtools) {
+ // Create the DevTools browser if it doesn't already exist.
+ // Otherwise, focus the existing DevTools browser and inspect the element
+ // at |inspect_element_at| if non-empty.
+ host->ShowDevTools(windowInfo, client, settings, inspect_element_at);
+ }
+}
+
+void ClientHandler::CloseDevTools(CefRefPtr<CefBrowser> browser) {
+ browser->GetHost()->CloseDevTools();
+}
+
+bool ClientHandler::HasSSLInformation(CefRefPtr<CefBrowser> browser) {
+ CefRefPtr<CefNavigationEntry> nav =
+ browser->GetHost()->GetVisibleNavigationEntry();
+
+ return (nav && nav->GetSSLStatus() &&
+ nav->GetSSLStatus()->IsSecureConnection());
+}
+
+void ClientHandler::ShowSSLInformation(CefRefPtr<CefBrowser> browser) {
+ std::stringstream ss;
+ CefRefPtr<CefNavigationEntry> nav =
+ browser->GetHost()->GetVisibleNavigationEntry();
+ if (!nav) {
+ return;
+ }
+
+ CefRefPtr<CefSSLStatus> ssl = nav->GetSSLStatus();
+ if (!ssl) {
+ return;
+ }
+
+ ss << "<html><head><title>SSL Information</title></head>"
+ "<body bgcolor=\"white\">"
+ "<h3>SSL Connection</h3>"
+ << "<table border=1><tr><th>Field</th><th>Value</th></tr>";
+
+ CefURLParts urlparts;
+ if (CefParseURL(nav->GetURL(), urlparts)) {
+ CefString port(&urlparts.port);
+ ss << "<tr><td>Server</td><td>" << CefString(&urlparts.host).ToString();
+ if (!port.empty()) {
+ ss << ":" << port.ToString();
+ }
+ ss << "</td></tr>";
+ }
+
+ ss << "<tr><td>SSL Version</td><td>"
+ << GetSSLVersionString(ssl->GetSSLVersion()) << "</td></tr>";
+ ss << "<tr><td>Content Status</td><td>"
+ << GetContentStatusString(ssl->GetContentStatus()) << "</td></tr>";
+
+ ss << "</table>";
+
+ CefRefPtr<CefX509Certificate> cert = ssl->GetX509Certificate();
+ if (cert.get()) {
+ ss << GetCertificateInformation(cert, ssl->GetCertStatus());
+ }
+
+ ss << "</body></html>";
+
+ auto config = std::make_unique<RootWindowConfig>();
+ config->with_controls = false;
+ config->with_osr = is_osr_;
+ config->url = test_runner::GetDataURI(ss.str(), "text/html");
+ MainContext::Get()->GetRootWindowManager()->CreateRootWindow(
+ std::move(config));
+}
+
+void ClientHandler::SetStringResource(const std::string& page,
+ const std::string& data) {
+ if (!CefCurrentlyOn(TID_IO)) {
+ CefPostTask(TID_IO, base::BindOnce(&ClientHandler::SetStringResource, this,
+ page, data));
+ return;
+ }
+
+ string_resource_map_[page] = data;
+}
+
+bool ClientHandler::CreatePopupWindow(CefRefPtr<CefBrowser> browser,
+ bool is_devtools,
+ const CefPopupFeatures& popupFeatures,
+ CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient>& client,
+ CefBrowserSettings& settings) {
+ CEF_REQUIRE_UI_THREAD();
+
+ // The popup browser will be parented to a new native window.
+ // Don't show URL bar and navigation buttons on DevTools windows.
+ MainContext::Get()->GetRootWindowManager()->CreateRootWindowAsPopup(
+ with_controls_ && !is_devtools, is_osr_, popupFeatures, windowInfo,
+ client, settings);
+
+ return true;
+}
+
+void ClientHandler::NotifyBrowserCreated(CefRefPtr<CefBrowser> browser) {
+ if (!CURRENTLY_ON_MAIN_THREAD()) {
+ // Execute this method on the main thread.
+ MAIN_POST_CLOSURE(
+ base::BindOnce(&ClientHandler::NotifyBrowserCreated, this, browser));
+ return;
+ }
+
+ if (delegate_) {
+ delegate_->OnBrowserCreated(browser);
+ }
+}
+
+void ClientHandler::NotifyBrowserClosing(CefRefPtr<CefBrowser> browser) {
+ if (!CURRENTLY_ON_MAIN_THREAD()) {
+ // Execute this method on the main thread.
+ MAIN_POST_CLOSURE(
+ base::BindOnce(&ClientHandler::NotifyBrowserClosing, this, browser));
+ return;
+ }
+
+ if (delegate_) {
+ delegate_->OnBrowserClosing(browser);
+ }
+}
+
+void ClientHandler::NotifyBrowserClosed(CefRefPtr<CefBrowser> browser) {
+ if (!CURRENTLY_ON_MAIN_THREAD()) {
+ // Execute this method on the main thread.
+ MAIN_POST_CLOSURE(
+ base::BindOnce(&ClientHandler::NotifyBrowserClosed, this, browser));
+ return;
+ }
+
+ if (delegate_) {
+ delegate_->OnBrowserClosed(browser);
+ }
+}
+
+void ClientHandler::NotifyAddress(const CefString& url) {
+ if (!CURRENTLY_ON_MAIN_THREAD()) {
+ // Execute this method on the main thread.
+ MAIN_POST_CLOSURE(base::BindOnce(&ClientHandler::NotifyAddress, this, url));
+ return;
+ }
+
+ if (delegate_) {
+ delegate_->OnSetAddress(url);
+ }
+}
+
+void ClientHandler::NotifyTitle(const CefString& title) {
+ if (!CURRENTLY_ON_MAIN_THREAD()) {
+ // Execute this method on the main thread.
+ MAIN_POST_CLOSURE(base::BindOnce(&ClientHandler::NotifyTitle, this, title));
+ return;
+ }
+
+ if (delegate_) {
+ delegate_->OnSetTitle(title);
+ }
+}
+
+void ClientHandler::NotifyFavicon(CefRefPtr<CefImage> image) {
+ if (!CURRENTLY_ON_MAIN_THREAD()) {
+ // Execute this method on the main thread.
+ MAIN_POST_CLOSURE(
+ base::BindOnce(&ClientHandler::NotifyFavicon, this, image));
+ return;
+ }
+
+ if (delegate_) {
+ delegate_->OnSetFavicon(image);
+ }
+}
+
+void ClientHandler::NotifyFullscreen(bool fullscreen) {
+ if (!CURRENTLY_ON_MAIN_THREAD()) {
+ // Execute this method on the main thread.
+ MAIN_POST_CLOSURE(
+ base::BindOnce(&ClientHandler::NotifyFullscreen, this, fullscreen));
+ return;
+ }
+
+ if (delegate_) {
+ delegate_->OnSetFullscreen(fullscreen);
+ }
+}
+
+void ClientHandler::NotifyAutoResize(const CefSize& new_size) {
+ if (!CURRENTLY_ON_MAIN_THREAD()) {
+ // Execute this method on the main thread.
+ MAIN_POST_CLOSURE(
+ base::BindOnce(&ClientHandler::NotifyAutoResize, this, new_size));
+ return;
+ }
+
+ if (delegate_) {
+ delegate_->OnAutoResize(new_size);
+ }
+}
+
+void ClientHandler::NotifyLoadingState(bool isLoading,
+ bool canGoBack,
+ bool canGoForward) {
+ if (!CURRENTLY_ON_MAIN_THREAD()) {
+ // Execute this method on the main thread.
+ MAIN_POST_CLOSURE(base::BindOnce(&ClientHandler::NotifyLoadingState, this,
+ isLoading, canGoBack, canGoForward));
+ return;
+ }
+
+ if (delegate_) {
+ delegate_->OnSetLoadingState(isLoading, canGoBack, canGoForward);
+ }
+}
+
+void ClientHandler::NotifyDraggableRegions(
+ const std::vector<CefDraggableRegion>& regions) {
+ if (!CURRENTLY_ON_MAIN_THREAD()) {
+ // Execute this method on the main thread.
+ MAIN_POST_CLOSURE(
+ base::BindOnce(&ClientHandler::NotifyDraggableRegions, this, regions));
+ return;
+ }
+
+ if (delegate_) {
+ delegate_->OnSetDraggableRegions(regions);
+ }
+}
+
+void ClientHandler::NotifyTakeFocus(bool next) {
+ if (!CURRENTLY_ON_MAIN_THREAD()) {
+ // Execute this method on the main thread.
+ MAIN_POST_CLOSURE(
+ base::BindOnce(&ClientHandler::NotifyTakeFocus, this, next));
+ return;
+ }
+
+ if (delegate_) {
+ delegate_->OnTakeFocus(next);
+ }
+}
+
+void ClientHandler::BuildTestMenu(CefRefPtr<CefMenuModel> model) {
+ if (model->GetCount() > 0) {
+ model->AddSeparator();
+ }
+
+ // Build the sub menu.
+ CefRefPtr<CefMenuModel> submenu =
+ model->AddSubMenu(CLIENT_ID_TESTMENU_SUBMENU, "Context Menu Test");
+ submenu->AddCheckItem(CLIENT_ID_TESTMENU_CHECKITEM, "Check Item");
+ submenu->AddRadioItem(CLIENT_ID_TESTMENU_RADIOITEM1, "Radio Item 1", 0);
+ submenu->AddRadioItem(CLIENT_ID_TESTMENU_RADIOITEM2, "Radio Item 2", 0);
+ submenu->AddRadioItem(CLIENT_ID_TESTMENU_RADIOITEM3, "Radio Item 3", 0);
+
+ // Check the check item.
+ if (test_menu_state_.check_item) {
+ submenu->SetChecked(CLIENT_ID_TESTMENU_CHECKITEM, true);
+ }
+
+ // Check the selected radio item.
+ submenu->SetChecked(
+ CLIENT_ID_TESTMENU_RADIOITEM1 + test_menu_state_.radio_item, true);
+}
+
+bool ClientHandler::ExecuteTestMenu(int command_id) {
+ if (command_id == CLIENT_ID_TESTMENU_CHECKITEM) {
+ // Toggle the check item.
+ test_menu_state_.check_item ^= 1;
+ return true;
+ } else if (command_id >= CLIENT_ID_TESTMENU_RADIOITEM1 &&
+ command_id <= CLIENT_ID_TESTMENU_RADIOITEM3) {
+ // Store the selected radio item.
+ test_menu_state_.radio_item = (command_id - CLIENT_ID_TESTMENU_RADIOITEM1);
+ return true;
+ }
+
+ // Allow default handling to proceed.
+ return false;
+}
+
+void ClientHandler::SetOfflineState(CefRefPtr<CefBrowser> browser,
+ bool offline) {
+ // See DevTools protocol docs for message format specification.
+ CefRefPtr<CefDictionaryValue> params = CefDictionaryValue::Create();
+ params->SetBool("offline", offline);
+ params->SetDouble("latency", 0);
+ params->SetDouble("downloadThroughput", 0);
+ params->SetDouble("uploadThroughput", 0);
+ browser->GetHost()->ExecuteDevToolsMethod(
+ /*message_id=*/0, "Network.emulateNetworkConditions", params);
+}
+
+void ClientHandler::FilterMenuModel(CefRefPtr<CefMenuModel> model) {
+ // Evaluate from the bottom to the top because we'll be removing menu items.
+ for (size_t x = model->GetCount(); x > 0; --x) {
+ const auto i = x - 1;
+ const auto type = model->GetTypeAt(i);
+ if (type == MENUITEMTYPE_SUBMENU) {
+ // Filter sub-menu and remove if empty.
+ auto sub_model = model->GetSubMenuAt(i);
+ FilterMenuModel(sub_model);
+ if (sub_model->GetCount() == 0) {
+ model->RemoveAt(i);
+ }
+ } else if (type == MENUITEMTYPE_SEPARATOR) {
+ // A separator shouldn't be the first or last element in the menu, and
+ // there shouldn't be multiple in a row.
+ if (i == 0 || i == model->GetCount() - 1 ||
+ model->GetTypeAt(i + 1) == MENUITEMTYPE_SEPARATOR) {
+ model->RemoveAt(i);
+ }
+ } else if (!IsAllowedCommandId(model->GetCommandIdAt(i))) {
+ model->RemoveAt(i);
+ }
+ }
+}
+
+bool ClientHandler::IsAllowedCommandId(int command_id) {
+ // Only the commands in this array will be allowed.
+ static const int kAllowedCommandIds[] = {
+ // Page navigation.
+ IDC_BACK,
+ IDC_FORWARD,
+ IDC_RELOAD,
+ IDC_RELOAD_BYPASSING_CACHE,
+ IDC_RELOAD_CLEARING_CACHE,
+ IDC_STOP,
+
+ // Printing.
+ IDC_PRINT,
+
+ // Edit controls.
+ IDC_CONTENT_CONTEXT_CUT,
+ IDC_CONTENT_CONTEXT_COPY,
+ IDC_CONTENT_CONTEXT_PASTE,
+ IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE,
+ IDC_CONTENT_CONTEXT_DELETE,
+ IDC_CONTENT_CONTEXT_SELECTALL,
+ IDC_CONTENT_CONTEXT_UNDO,
+ IDC_CONTENT_CONTEXT_REDO,
+ };
+ for (size_t i = 0; i < std::size(kAllowedCommandIds); ++i) {
+ if (command_id == kAllowedCommandIds[i]) {
+ return true;
+ }
+ }
+ return false;
+}
+
+} // namespace client
diff --git a/tests/cefclient/browser/client_handler.h b/tests/cefclient/browser/client_handler.h
new file mode 100644
index 00000000..aa4d07e2
--- /dev/null
+++ b/tests/cefclient/browser/client_handler.h
@@ -0,0 +1,457 @@
+// Copyright (c) 2011 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_CLIENT_HANDLER_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_CLIENT_HANDLER_H_
+#pragma once
+
+#include <set>
+#include <string>
+
+#include "include/cef_client.h"
+#include "include/wrapper/cef_helpers.h"
+#include "include/wrapper/cef_message_router.h"
+#include "include/wrapper/cef_resource_manager.h"
+#include "tests/cefclient/browser/client_types.h"
+#include "tests/cefclient/browser/test_runner.h"
+
+#if defined(OS_LINUX)
+#include "tests/cefclient/browser/dialog_handler_gtk.h"
+#include "tests/cefclient/browser/print_handler_gtk.h"
+#endif
+
+namespace client {
+
+class ClientDownloadImageCallback;
+
+// Client handler abstract base class. Provides common functionality shared by
+// all concrete client handler implementations.
+class ClientHandler : public CefClient,
+ public CefCommandHandler,
+ public CefContextMenuHandler,
+ public CefDisplayHandler,
+ public CefDownloadHandler,
+ public CefDragHandler,
+ public CefFocusHandler,
+ public CefKeyboardHandler,
+ public CefLifeSpanHandler,
+ public CefLoadHandler,
+ public CefPermissionHandler,
+ public CefRequestHandler,
+ public CefResourceRequestHandler {
+ public:
+ // Implement this interface to receive notification of ClientHandler
+ // events. The methods of this class will be called on the main thread unless
+ // otherwise indicated.
+ class Delegate {
+ public:
+ // Called when the browser is created.
+ virtual void OnBrowserCreated(CefRefPtr<CefBrowser> browser) = 0;
+
+ // Called when the browser is closing.
+ virtual void OnBrowserClosing(CefRefPtr<CefBrowser> browser) = 0;
+
+ // Called when the browser has been closed.
+ virtual void OnBrowserClosed(CefRefPtr<CefBrowser> browser) = 0;
+
+ // Set the window URL address.
+ virtual void OnSetAddress(const std::string& url) = 0;
+
+ // Set the window title.
+ virtual void OnSetTitle(const std::string& title) = 0;
+
+ // Set the Favicon image.
+ virtual void OnSetFavicon(CefRefPtr<CefImage> image) {}
+
+ // Set fullscreen mode.
+ virtual void OnSetFullscreen(bool fullscreen) = 0;
+
+ // Auto-resize contents.
+ virtual void OnAutoResize(const CefSize& new_size) = 0;
+
+ // Set the loading state.
+ virtual void OnSetLoadingState(bool isLoading,
+ bool canGoBack,
+ bool canGoForward) = 0;
+
+ // Set the draggable regions.
+ virtual void OnSetDraggableRegions(
+ const std::vector<CefDraggableRegion>& regions) = 0;
+
+ // Set focus to the next/previous control.
+ virtual void OnTakeFocus(bool next) {}
+
+ // Called on the UI thread before a context menu is displayed.
+ virtual void OnBeforeContextMenu(CefRefPtr<CefMenuModel> model) {}
+
+ protected:
+ virtual ~Delegate() {}
+ };
+
+ typedef std::set<CefMessageRouterBrowserSide::Handler*> MessageHandlerSet;
+
+ // Constructor may be called on any thread.
+ // |delegate| must outlive this object or DetachDelegate() must be called.
+ ClientHandler(Delegate* delegate,
+ bool is_osr,
+ bool with_controls,
+ const std::string& startup_url);
+
+ // This object may outlive the Delegate object so it's necessary for the
+ // Delegate to detach itself before destruction.
+ void DetachDelegate();
+
+ // CefClient methods
+ CefRefPtr<CefCommandHandler> GetCommandHandler() override { return this; }
+ CefRefPtr<CefContextMenuHandler> GetContextMenuHandler() override {
+ return this;
+ }
+ CefRefPtr<CefDisplayHandler> GetDisplayHandler() override { return this; }
+ CefRefPtr<CefDownloadHandler> GetDownloadHandler() override { return this; }
+ CefRefPtr<CefDragHandler> GetDragHandler() override { return this; }
+ CefRefPtr<CefFocusHandler> GetFocusHandler() override { return this; }
+ CefRefPtr<CefKeyboardHandler> GetKeyboardHandler() override { return this; }
+ CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() override { return this; }
+ CefRefPtr<CefLoadHandler> GetLoadHandler() override { return this; }
+ CefRefPtr<CefRequestHandler> GetRequestHandler() override { return this; }
+ CefRefPtr<CefPermissionHandler> GetPermissionHandler() override {
+ return this;
+ }
+ bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefProcessId source_process,
+ CefRefPtr<CefProcessMessage> message) override;
+
+#if defined(OS_LINUX)
+ CefRefPtr<CefDialogHandler> GetDialogHandler() override {
+ return file_dialog_handler_;
+ }
+ CefRefPtr<CefJSDialogHandler> GetJSDialogHandler() override {
+ return js_dialog_handler_;
+ }
+ CefRefPtr<CefPrintHandler> GetPrintHandler() override {
+ return print_handler_;
+ }
+#endif
+
+ // CefCommandHandler methods
+ bool OnChromeCommand(CefRefPtr<CefBrowser> browser,
+ int command_id,
+ cef_window_open_disposition_t disposition) override;
+
+ // CefContextMenuHandler methods
+ void OnBeforeContextMenu(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefContextMenuParams> params,
+ CefRefPtr<CefMenuModel> model) override;
+ bool OnContextMenuCommand(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefContextMenuParams> params,
+ int command_id,
+ EventFlags event_flags) override;
+
+ // CefDisplayHandler methods
+ void OnAddressChange(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const CefString& url) override;
+ void OnTitleChange(CefRefPtr<CefBrowser> browser,
+ const CefString& title) override;
+ void OnFaviconURLChange(CefRefPtr<CefBrowser> browser,
+ const std::vector<CefString>& icon_urls) override;
+ void OnFullscreenModeChange(CefRefPtr<CefBrowser> browser,
+ bool fullscreen) override;
+ bool OnConsoleMessage(CefRefPtr<CefBrowser> browser,
+ cef_log_severity_t level,
+ const CefString& message,
+ const CefString& source,
+ int line) override;
+ bool OnAutoResize(CefRefPtr<CefBrowser> browser,
+ const CefSize& new_size) override;
+ bool OnCursorChange(CefRefPtr<CefBrowser> browser,
+ CefCursorHandle cursor,
+ cef_cursor_type_t type,
+ const CefCursorInfo& custom_cursor_info) override;
+
+ // CefDownloadHandler methods
+ bool CanDownload(CefRefPtr<CefBrowser> browser,
+ const CefString& url,
+ const CefString& request_method) override;
+ void OnBeforeDownload(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefDownloadItem> download_item,
+ const CefString& suggested_name,
+ CefRefPtr<CefBeforeDownloadCallback> callback) override;
+ void OnDownloadUpdated(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefDownloadItem> download_item,
+ CefRefPtr<CefDownloadItemCallback> callback) override;
+
+ // CefDragHandler methods
+ bool OnDragEnter(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefDragData> dragData,
+ CefDragHandler::DragOperationsMask mask) override;
+ void OnDraggableRegionsChanged(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const std::vector<CefDraggableRegion>& regions) override;
+
+ // CefFocusHandler methods
+ void OnTakeFocus(CefRefPtr<CefBrowser> browser, bool next) override;
+ bool OnSetFocus(CefRefPtr<CefBrowser> browser, FocusSource source) override;
+
+ // CefKeyboardHandler methods
+ bool OnPreKeyEvent(CefRefPtr<CefBrowser> browser,
+ const CefKeyEvent& event,
+ CefEventHandle os_event,
+ bool* is_keyboard_shortcut) override;
+
+ // CefLifeSpanHandler methods
+ bool OnBeforePopup(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const CefString& target_url,
+ const CefString& target_frame_name,
+ CefLifeSpanHandler::WindowOpenDisposition target_disposition,
+ bool user_gesture,
+ const CefPopupFeatures& popupFeatures,
+ CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient>& client,
+ CefBrowserSettings& settings,
+ CefRefPtr<CefDictionaryValue>& extra_info,
+ bool* no_javascript_access) override;
+ void OnAfterCreated(CefRefPtr<CefBrowser> browser) override;
+ bool DoClose(CefRefPtr<CefBrowser> browser) override;
+ void OnBeforeClose(CefRefPtr<CefBrowser> browser) override;
+
+ // CefLoadHandler methods
+ void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
+ bool isLoading,
+ bool canGoBack,
+ bool canGoForward) override;
+ void OnLoadError(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ ErrorCode errorCode,
+ const CefString& errorText,
+ const CefString& failedUrl) override;
+
+ // CefPermissionHandler methods
+ bool OnRequestMediaAccessPermission(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const CefString& requesting_origin,
+ uint32 requested_permissions,
+ CefRefPtr<CefMediaAccessCallback> callback) override;
+
+ // CefRequestHandler methods
+ bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ bool user_gesture,
+ bool is_redirect) override;
+ bool OnOpenURLFromTab(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const CefString& target_url,
+ CefRequestHandler::WindowOpenDisposition target_disposition,
+ bool user_gesture) override;
+ CefRefPtr<CefResourceRequestHandler> GetResourceRequestHandler(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ bool is_navigation,
+ bool is_download,
+ const CefString& request_initiator,
+ bool& disable_default_handling) override;
+ bool GetAuthCredentials(CefRefPtr<CefBrowser> browser,
+ const CefString& origin_url,
+ bool isProxy,
+ const CefString& host,
+ int port,
+ const CefString& realm,
+ const CefString& scheme,
+ CefRefPtr<CefAuthCallback> callback) override;
+ bool OnCertificateError(CefRefPtr<CefBrowser> browser,
+ ErrorCode cert_error,
+ const CefString& request_url,
+ CefRefPtr<CefSSLInfo> ssl_info,
+ CefRefPtr<CefCallback> callback) override;
+ bool OnSelectClientCertificate(
+ CefRefPtr<CefBrowser> browser,
+ bool isProxy,
+ const CefString& host,
+ int port,
+ const X509CertificateList& certificates,
+ CefRefPtr<CefSelectClientCertificateCallback> callback) override;
+ void OnRenderProcessTerminated(CefRefPtr<CefBrowser> browser,
+ TerminationStatus status) override;
+ void OnDocumentAvailableInMainFrame(CefRefPtr<CefBrowser> browser) override;
+
+ // CefResourceRequestHandler methods
+ cef_return_value_t OnBeforeResourceLoad(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefCallback> callback) override;
+ CefRefPtr<CefResourceHandler> GetResourceHandler(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request) override;
+ CefRefPtr<CefResponseFilter> GetResourceResponseFilter(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response) override;
+ void OnProtocolExecution(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ bool& allow_os_execution) override;
+
+ // Returns the number of browsers currently using this handler. Can only be
+ // called on the CEF UI thread.
+ int GetBrowserCount() const;
+
+ // Show a new DevTools popup window.
+ void ShowDevTools(CefRefPtr<CefBrowser> browser,
+ const CefPoint& inspect_element_at);
+
+ // Close the existing DevTools popup window, if any.
+ void CloseDevTools(CefRefPtr<CefBrowser> browser);
+
+ // Test if the current site has SSL information available.
+ bool HasSSLInformation(CefRefPtr<CefBrowser> browser);
+
+ // Show SSL information for the current site.
+ void ShowSSLInformation(CefRefPtr<CefBrowser> browser);
+
+ // Set a string resource for loading via StringResourceProvider.
+ void SetStringResource(const std::string& page, const std::string& data);
+
+ // Returns the Delegate.
+ Delegate* delegate() const { return delegate_; }
+
+ // Returns the startup URL.
+ std::string startup_url() const { return startup_url_; }
+
+ // Set/get whether the client should download favicon images. Only safe to
+ // call immediately after client creation or on the browser process UI thread.
+ bool download_favicon_images() const { return download_favicon_images_; }
+ void set_download_favicon_images(bool allow) {
+ download_favicon_images_ = allow;
+ }
+
+ private:
+ friend class ClientDownloadImageCallback;
+
+ // Create a new popup window using the specified information. |is_devtools|
+ // will be true if the window will be used for DevTools. Return true to
+ // proceed with popup browser creation or false to cancel the popup browser.
+ // May be called on any thead.
+ bool CreatePopupWindow(CefRefPtr<CefBrowser> browser,
+ bool is_devtools,
+ const CefPopupFeatures& popupFeatures,
+ CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient>& client,
+ CefBrowserSettings& settings);
+
+ // Execute Delegate notifications on the main thread.
+ void NotifyBrowserCreated(CefRefPtr<CefBrowser> browser);
+ void NotifyBrowserClosing(CefRefPtr<CefBrowser> browser);
+ void NotifyBrowserClosed(CefRefPtr<CefBrowser> browser);
+ void NotifyAddress(const CefString& url);
+ void NotifyTitle(const CefString& title);
+ void NotifyFavicon(CefRefPtr<CefImage> image);
+ void NotifyFullscreen(bool fullscreen);
+ void NotifyAutoResize(const CefSize& new_size);
+ void NotifyLoadingState(bool isLoading, bool canGoBack, bool canGoForward);
+ void NotifyDraggableRegions(const std::vector<CefDraggableRegion>& regions);
+ void NotifyTakeFocus(bool next);
+
+ // Test context menu creation.
+ void BuildTestMenu(CefRefPtr<CefMenuModel> model);
+ bool ExecuteTestMenu(int command_id);
+
+ void SetOfflineState(CefRefPtr<CefBrowser> browser, bool offline);
+
+ // Filter menu and keyboard shortcut commands.
+ void FilterMenuModel(CefRefPtr<CefMenuModel> model);
+ bool IsAllowedCommandId(int command_id);
+
+ // THREAD SAFE MEMBERS
+ // The following members may be accessed from any thread.
+
+ // True if this handler uses off-screen rendering.
+ const bool is_osr_;
+
+ // True if this handler shows controls.
+ const bool with_controls_;
+
+ // The startup URL.
+ const std::string startup_url_;
+
+ // True if mouse cursor change is disabled.
+ bool mouse_cursor_change_disabled_;
+
+ // True if media handling is disabled.
+ bool media_handling_disabled_ = true;
+
+ // True if the browser is currently offline.
+ bool offline_;
+
+ // True if Favicon images should be downloaded.
+ bool download_favicon_images_ = false;
+
+#if defined(OS_LINUX)
+ // Custom dialog handlers for GTK.
+ CefRefPtr<ClientDialogHandlerGtk> file_dialog_handler_;
+ CefRefPtr<ClientDialogHandlerGtk> js_dialog_handler_;
+ CefRefPtr<ClientPrintHandlerGtk> print_handler_;
+#endif
+
+ // Handles the browser side of query routing. The renderer side is handled
+ // in client_renderer.cc.
+ CefRefPtr<CefMessageRouterBrowserSide> message_router_;
+
+ // Manages the registration and delivery of resources.
+ CefRefPtr<CefResourceManager> resource_manager_;
+
+ // Used to manage string resources in combination with StringResourceProvider.
+ // Only accessed on the IO thread.
+ test_runner::StringResourceMap string_resource_map_;
+
+ // MAIN THREAD MEMBERS
+ // The following members will only be accessed on the main thread. This will
+ // be the same as the CEF UI thread except when using multi-threaded message
+ // loop mode on Windows.
+
+ Delegate* delegate_;
+
+ // UI THREAD MEMBERS
+ // The following members will only be accessed on the CEF UI thread.
+
+ // Track state information for the text context menu.
+ struct TestMenuState {
+ TestMenuState() : check_item(true), radio_item(0) {}
+ bool check_item;
+ int radio_item;
+ } test_menu_state_;
+
+ // The current number of browsers using this handler.
+ int browser_count_ = 0;
+
+ // Console logging state.
+ const std::string console_log_file_;
+
+ // True if an editable field currently has focus.
+ bool focus_on_editable_field_ = false;
+
+ // True for the initial navigation after browser creation.
+ bool initial_navigation_ = true;
+
+ // Set of Handlers registered with the message router.
+ MessageHandlerSet message_handler_set_;
+
+ DISALLOW_COPY_AND_ASSIGN(ClientHandler);
+};
+
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_CLIENT_HANDLER_H_
diff --git a/tests/cefclient/browser/client_handler_osr.cc b/tests/cefclient/browser/client_handler_osr.cc
new file mode 100644
index 00000000..2f36af9b
--- /dev/null
+++ b/tests/cefclient/browser/client_handler_osr.cc
@@ -0,0 +1,200 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/client_handler_osr.h"
+
+#include "include/base/cef_callback.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "include/wrapper/cef_helpers.h"
+
+namespace client {
+
+ClientHandlerOsr::ClientHandlerOsr(Delegate* delegate,
+ OsrDelegate* osr_delegate,
+ bool with_controls,
+ const std::string& startup_url)
+ : ClientHandler(delegate, /*is_osr=*/true, with_controls, startup_url),
+ osr_delegate_(osr_delegate) {
+ DCHECK(osr_delegate_);
+}
+
+void ClientHandlerOsr::DetachOsrDelegate() {
+ if (!CefCurrentlyOn(TID_UI)) {
+ // Execute this method on the UI thread.
+ CefPostTask(TID_UI,
+ base::BindOnce(&ClientHandlerOsr::DetachOsrDelegate, this));
+ return;
+ }
+
+ DCHECK(osr_delegate_);
+ osr_delegate_ = nullptr;
+}
+
+void ClientHandlerOsr::OnAfterCreated(CefRefPtr<CefBrowser> browser) {
+ CEF_REQUIRE_UI_THREAD();
+ if (osr_delegate_) {
+ osr_delegate_->OnAfterCreated(browser);
+ }
+ ClientHandler::OnAfterCreated(browser);
+}
+
+void ClientHandlerOsr::OnBeforeClose(CefRefPtr<CefBrowser> browser) {
+ CEF_REQUIRE_UI_THREAD();
+ if (osr_delegate_) {
+ osr_delegate_->OnBeforeClose(browser);
+ }
+ ClientHandler::OnBeforeClose(browser);
+}
+
+bool ClientHandlerOsr::GetRootScreenRect(CefRefPtr<CefBrowser> browser,
+ CefRect& rect) {
+ CEF_REQUIRE_UI_THREAD();
+ if (!osr_delegate_) {
+ return false;
+ }
+ return osr_delegate_->GetRootScreenRect(browser, rect);
+}
+
+void ClientHandlerOsr::GetViewRect(CefRefPtr<CefBrowser> browser,
+ CefRect& rect) {
+ CEF_REQUIRE_UI_THREAD();
+ if (!osr_delegate_) {
+ // Never return an empty rectangle.
+ rect.width = rect.height = 1;
+ return;
+ }
+ osr_delegate_->GetViewRect(browser, rect);
+}
+
+bool ClientHandlerOsr::GetScreenPoint(CefRefPtr<CefBrowser> browser,
+ int viewX,
+ int viewY,
+ int& screenX,
+ int& screenY) {
+ CEF_REQUIRE_UI_THREAD();
+ if (!osr_delegate_) {
+ return false;
+ }
+ return osr_delegate_->GetScreenPoint(browser, viewX, viewY, screenX, screenY);
+}
+
+bool ClientHandlerOsr::GetScreenInfo(CefRefPtr<CefBrowser> browser,
+ CefScreenInfo& screen_info) {
+ CEF_REQUIRE_UI_THREAD();
+ if (!osr_delegate_) {
+ return false;
+ }
+ return osr_delegate_->GetScreenInfo(browser, screen_info);
+}
+
+void ClientHandlerOsr::OnPopupShow(CefRefPtr<CefBrowser> browser, bool show) {
+ CEF_REQUIRE_UI_THREAD();
+ if (!osr_delegate_) {
+ return;
+ }
+ return osr_delegate_->OnPopupShow(browser, show);
+}
+
+void ClientHandlerOsr::OnPopupSize(CefRefPtr<CefBrowser> browser,
+ const CefRect& rect) {
+ CEF_REQUIRE_UI_THREAD();
+ if (!osr_delegate_) {
+ return;
+ }
+ return osr_delegate_->OnPopupSize(browser, rect);
+}
+
+void ClientHandlerOsr::OnPaint(CefRefPtr<CefBrowser> browser,
+ PaintElementType type,
+ const RectList& dirtyRects,
+ const void* buffer,
+ int width,
+ int height) {
+ CEF_REQUIRE_UI_THREAD();
+ if (!osr_delegate_) {
+ return;
+ }
+ osr_delegate_->OnPaint(browser, type, dirtyRects, buffer, width, height);
+}
+
+void ClientHandlerOsr::OnAcceleratedPaint(
+ CefRefPtr<CefBrowser> browser,
+ CefRenderHandler::PaintElementType type,
+ const CefRenderHandler::RectList& dirtyRects,
+ void* share_handle) {
+ CEF_REQUIRE_UI_THREAD();
+ if (!osr_delegate_) {
+ return;
+ }
+ osr_delegate_->OnAcceleratedPaint(browser, type, dirtyRects, share_handle);
+}
+
+bool ClientHandlerOsr::StartDragging(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefDragData> drag_data,
+ CefRenderHandler::DragOperationsMask allowed_ops,
+ int x,
+ int y) {
+ CEF_REQUIRE_UI_THREAD();
+ if (!osr_delegate_) {
+ return false;
+ }
+ return osr_delegate_->StartDragging(browser, drag_data, allowed_ops, x, y);
+}
+
+void ClientHandlerOsr::UpdateDragCursor(
+ CefRefPtr<CefBrowser> browser,
+ CefRenderHandler::DragOperation operation) {
+ CEF_REQUIRE_UI_THREAD();
+ if (!osr_delegate_) {
+ return;
+ }
+ osr_delegate_->UpdateDragCursor(browser, operation);
+}
+
+void ClientHandlerOsr::OnImeCompositionRangeChanged(
+ CefRefPtr<CefBrowser> browser,
+ const CefRange& selection_range,
+ const CefRenderHandler::RectList& character_bounds) {
+ CEF_REQUIRE_UI_THREAD();
+ if (!osr_delegate_) {
+ return;
+ }
+ osr_delegate_->OnImeCompositionRangeChanged(browser, selection_range,
+ character_bounds);
+}
+
+void ClientHandlerOsr::OnAccessibilityTreeChange(CefRefPtr<CefValue> value) {
+ CEF_REQUIRE_UI_THREAD();
+ if (!osr_delegate_) {
+ return;
+ }
+ osr_delegate_->UpdateAccessibilityTree(value);
+}
+
+bool ClientHandlerOsr::OnCursorChange(CefRefPtr<CefBrowser> browser,
+ CefCursorHandle cursor,
+ cef_cursor_type_t type,
+ const CefCursorInfo& custom_cursor_info) {
+ CEF_REQUIRE_UI_THREAD();
+ if (ClientHandler::OnCursorChange(browser, cursor, type,
+ custom_cursor_info)) {
+ return true;
+ }
+ if (osr_delegate_) {
+ osr_delegate_->OnCursorChange(browser, cursor, type, custom_cursor_info);
+ }
+ return true;
+}
+
+void ClientHandlerOsr::OnAccessibilityLocationChange(
+ CefRefPtr<CefValue> value) {
+ CEF_REQUIRE_UI_THREAD();
+ if (!osr_delegate_) {
+ return;
+ }
+ osr_delegate_->UpdateAccessibilityLocation(value);
+}
+
+} // namespace client
diff --git a/tests/cefclient/browser/client_handler_osr.h b/tests/cefclient/browser/client_handler_osr.h
new file mode 100644
index 00000000..1fe247ea
--- /dev/null
+++ b/tests/cefclient/browser/client_handler_osr.h
@@ -0,0 +1,152 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_CLIENT_HANDLER_OSR_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_CLIENT_HANDLER_OSR_H_
+#pragma once
+
+#include "tests/cefclient/browser/client_handler.h"
+
+namespace client {
+
+// Client handler implementation for windowless browsers. There will only ever
+// be one browser per handler instance.
+class ClientHandlerOsr : public ClientHandler,
+ public CefAccessibilityHandler,
+ public CefRenderHandler {
+ public:
+ // Implement this interface to receive notification of ClientHandlerOsr
+ // events. The methods of this class will be called on the CEF UI thread.
+ class OsrDelegate {
+ public:
+ // These methods match the CefLifeSpanHandler interface.
+ virtual void OnAfterCreated(CefRefPtr<CefBrowser> browser) = 0;
+ virtual void OnBeforeClose(CefRefPtr<CefBrowser> browser) = 0;
+
+ // These methods match the CefRenderHandler interface.
+ virtual bool GetRootScreenRect(CefRefPtr<CefBrowser> browser,
+ CefRect& rect) = 0;
+ virtual void GetViewRect(CefRefPtr<CefBrowser> browser, CefRect& rect) = 0;
+ virtual bool GetScreenPoint(CefRefPtr<CefBrowser> browser,
+ int viewX,
+ int viewY,
+ int& screenX,
+ int& screenY) = 0;
+ virtual bool GetScreenInfo(CefRefPtr<CefBrowser> browser,
+ CefScreenInfo& screen_info) = 0;
+ virtual void OnPopupShow(CefRefPtr<CefBrowser> browser, bool show) = 0;
+ virtual void OnPopupSize(CefRefPtr<CefBrowser> browser,
+ const CefRect& rect) = 0;
+ virtual void OnPaint(CefRefPtr<CefBrowser> browser,
+ CefRenderHandler::PaintElementType type,
+ const CefRenderHandler::RectList& dirtyRects,
+ const void* buffer,
+ int width,
+ int height) = 0;
+ virtual void OnAcceleratedPaint(
+ CefRefPtr<CefBrowser> browser,
+ CefRenderHandler::PaintElementType type,
+ const CefRenderHandler::RectList& dirtyRects,
+ void* share_handle) {}
+ virtual bool StartDragging(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefDragData> drag_data,
+ CefRenderHandler::DragOperationsMask allowed_ops,
+ int x,
+ int y) = 0;
+ virtual void UpdateDragCursor(
+ CefRefPtr<CefBrowser> browser,
+ CefRenderHandler::DragOperation operation) = 0;
+ virtual void OnImeCompositionRangeChanged(
+ CefRefPtr<CefBrowser> browser,
+ const CefRange& selection_range,
+ const CefRenderHandler::RectList& character_bounds) = 0;
+
+ // These methods match the CefDisplayHandler interface.
+ virtual void OnCursorChange(CefRefPtr<CefBrowser> browser,
+ CefCursorHandle cursor,
+ cef_cursor_type_t type,
+ const CefCursorInfo& custom_cursor_info) = 0;
+
+ virtual void UpdateAccessibilityTree(CefRefPtr<CefValue> value) = 0;
+ virtual void UpdateAccessibilityLocation(CefRefPtr<CefValue> value) = 0;
+
+ protected:
+ virtual ~OsrDelegate() {}
+ };
+
+ ClientHandlerOsr(Delegate* delegate,
+ OsrDelegate* osr_delegate,
+ bool with_controls,
+ const std::string& startup_url);
+
+ // This object may outlive the OsrDelegate object so it's necessary for the
+ // OsrDelegate to detach itself before destruction.
+ void DetachOsrDelegate();
+
+ // CefClient methods.
+ CefRefPtr<CefRenderHandler> GetRenderHandler() override { return this; }
+ CefRefPtr<CefAccessibilityHandler> GetAccessibilityHandler() override {
+ return this;
+ }
+
+ // CefLifeSpanHandler methods.
+ void OnAfterCreated(CefRefPtr<CefBrowser> browser) override;
+ void OnBeforeClose(CefRefPtr<CefBrowser> browser) override;
+
+ // CefRenderHandler methods.
+ bool GetRootScreenRect(CefRefPtr<CefBrowser> browser, CefRect& rect) override;
+ void GetViewRect(CefRefPtr<CefBrowser> browser, CefRect& rect) override;
+ bool GetScreenPoint(CefRefPtr<CefBrowser> browser,
+ int viewX,
+ int viewY,
+ int& screenX,
+ int& screenY) override;
+ bool GetScreenInfo(CefRefPtr<CefBrowser> browser,
+ CefScreenInfo& screen_info) override;
+ void OnPopupShow(CefRefPtr<CefBrowser> browser, bool show) override;
+ void OnPopupSize(CefRefPtr<CefBrowser> browser, const CefRect& rect) override;
+ void OnPaint(CefRefPtr<CefBrowser> browser,
+ CefRenderHandler::PaintElementType type,
+ const CefRenderHandler::RectList& dirtyRects,
+ const void* buffer,
+ int width,
+ int height) override;
+ void OnAcceleratedPaint(CefRefPtr<CefBrowser> browser,
+ CefRenderHandler::PaintElementType type,
+ const CefRenderHandler::RectList& dirtyRects,
+ void* share_handle) override;
+ bool StartDragging(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefDragData> drag_data,
+ CefRenderHandler::DragOperationsMask allowed_ops,
+ int x,
+ int y) override;
+ void UpdateDragCursor(CefRefPtr<CefBrowser> browser,
+ CefRenderHandler::DragOperation operation) override;
+ void OnImeCompositionRangeChanged(
+ CefRefPtr<CefBrowser> browser,
+ const CefRange& selection_range,
+ const CefRenderHandler::RectList& character_bounds) override;
+
+ // CefDisplayHandler methods.
+ bool OnCursorChange(CefRefPtr<CefBrowser> browser,
+ CefCursorHandle cursor,
+ cef_cursor_type_t type,
+ const CefCursorInfo& custom_cursor_info) override;
+
+ // CefAccessibilityHandler methods.
+ void OnAccessibilityTreeChange(CefRefPtr<CefValue> value) override;
+ void OnAccessibilityLocationChange(CefRefPtr<CefValue> value) override;
+
+ private:
+ // Only accessed on the UI thread.
+ OsrDelegate* osr_delegate_;
+
+ // Include the default reference counting implementation.
+ IMPLEMENT_REFCOUNTING(ClientHandlerOsr);
+ DISALLOW_COPY_AND_ASSIGN(ClientHandlerOsr);
+};
+
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_CLIENT_HANDLER_OSR_H_
diff --git a/tests/cefclient/browser/client_handler_std.cc b/tests/cefclient/browser/client_handler_std.cc
new file mode 100644
index 00000000..e78166d9
--- /dev/null
+++ b/tests/cefclient/browser/client_handler_std.cc
@@ -0,0 +1,14 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/client_handler_std.h"
+
+namespace client {
+
+ClientHandlerStd::ClientHandlerStd(Delegate* delegate,
+ bool with_controls,
+ const std::string& startup_url)
+ : ClientHandler(delegate, /*is_osr=*/false, with_controls, startup_url) {}
+
+} // namespace client
diff --git a/tests/cefclient/browser/client_handler_std.h b/tests/cefclient/browser/client_handler_std.h
new file mode 100644
index 00000000..02aa7476
--- /dev/null
+++ b/tests/cefclient/browser/client_handler_std.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_CLIENT_HANDLER_STD_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_CLIENT_HANDLER_STD_H_
+#pragma once
+
+#include "tests/cefclient/browser/client_handler.h"
+
+namespace client {
+
+// Client handler implementation for windowed browsers. There will only ever be
+// one browser per handler instance.
+class ClientHandlerStd : public ClientHandler {
+ public:
+ ClientHandlerStd(Delegate* delegate,
+ bool with_controls,
+ const std::string& startup_url);
+
+ private:
+ // Include the default reference counting implementation.
+ IMPLEMENT_REFCOUNTING(ClientHandlerStd);
+ DISALLOW_COPY_AND_ASSIGN(ClientHandlerStd);
+};
+
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_CLIENT_HANDLER_STD_H_
diff --git a/tests/cefclient/browser/client_prefs.cc b/tests/cefclient/browser/client_prefs.cc
new file mode 100644
index 00000000..e64a1de6
--- /dev/null
+++ b/tests/cefclient/browser/client_prefs.cc
@@ -0,0 +1,206 @@
+// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/client_prefs.h"
+
+#include <memory>
+
+#include "include/base/cef_logging.h"
+#include "include/cef_command_line.h"
+#include "include/cef_preference.h"
+#include "include/cef_values.h"
+#include "include/views/cef_display.h"
+#include "include/wrapper/cef_helpers.h"
+#include "tests/shared/common/client_switches.h"
+#include "tests/shared/common/string_util.h"
+
+namespace client {
+namespace prefs {
+
+namespace {
+
+constexpr char kPrefWindowRestore[] = "cefclient.window_restore";
+
+constexpr char kWindowRestoreStateKey[] = "state";
+constexpr char kWindowRestoreBoundsKey[] = "bounds";
+constexpr char kWindowRestoreBoundsKey_X[] = "x";
+constexpr char kWindowRestoreBoundsKey_Y[] = "y";
+constexpr char kWindowRestoreBoundsKey_W[] = "w";
+constexpr char kWindowRestoreBoundsKey_H[] = "h";
+
+static struct {
+ const char* str;
+ cef_show_state_t state;
+} const kWindowRestoreStateValueMap[] = {
+ {"normal", CEF_SHOW_STATE_NORMAL},
+ {"minimized", CEF_SHOW_STATE_MINIMIZED},
+ {"maximized", CEF_SHOW_STATE_MAXIMIZED},
+ {"fullscreen", CEF_SHOW_STATE_FULLSCREEN},
+};
+
+std::optional<cef_show_state_t> ShowStateFromString(const std::string& str) {
+ const auto strLower = AsciiStrToLower(str);
+ for (size_t i = 0; i < std::size(kWindowRestoreStateValueMap); ++i) {
+ if (strLower == kWindowRestoreStateValueMap[i].str) {
+ return kWindowRestoreStateValueMap[i].state;
+ }
+ }
+ return std::nullopt;
+}
+
+const char* ShowStateToString(cef_show_state_t show_state) {
+ for (size_t i = 0; i < std::size(kWindowRestoreStateValueMap); ++i) {
+ if (show_state == kWindowRestoreStateValueMap[i].state) {
+ return kWindowRestoreStateValueMap[i].str;
+ }
+ }
+ NOTREACHED();
+ return nullptr;
+}
+
+// Create the CefValue representation that will be stored in preferences.
+CefRefPtr<CefValue> CreateWindowRestoreValue(
+ cef_show_state_t show_state,
+ std::optional<CefRect> dip_bounds) {
+ auto dict = CefDictionaryValue::Create();
+
+ // Show state is required.
+ dict->SetString(kWindowRestoreStateKey, ShowStateToString(show_state));
+
+ // Bounds is optional.
+ if (dip_bounds) {
+ auto bounds_dict = CefDictionaryValue::Create();
+ bounds_dict->SetInt(kWindowRestoreBoundsKey_X, dip_bounds->x);
+ bounds_dict->SetInt(kWindowRestoreBoundsKey_Y, dip_bounds->y);
+ bounds_dict->SetInt(kWindowRestoreBoundsKey_W, dip_bounds->width);
+ bounds_dict->SetInt(kWindowRestoreBoundsKey_H, dip_bounds->height);
+ dict->SetDictionary(kWindowRestoreBoundsKey, bounds_dict);
+ }
+
+ auto value = CefValue::Create();
+ value->SetDictionary(dict);
+ return value;
+}
+
+CefRefPtr<CefValue> CreateDefaultWindowRestoreValue() {
+ return CreateWindowRestoreValue(CEF_SHOW_STATE_NORMAL, std::nullopt);
+}
+
+// Parse the CefValue representation that was stored in preferences.
+bool ParseWindowRestoreValue(CefRefPtr<CefValue> value,
+ cef_show_state_t& show_state,
+ std::optional<CefRect>& dip_bounds) {
+ if (!value || value->GetType() != VTYPE_DICTIONARY) {
+ return false;
+ }
+
+ auto dict = value->GetDictionary();
+
+ bool has_state = false;
+
+ // Show state is required.
+ if (dict->GetType(kWindowRestoreStateKey) == VTYPE_STRING) {
+ auto result = ShowStateFromString(dict->GetString(kWindowRestoreStateKey));
+ if (result) {
+ show_state = *result;
+ has_state = true;
+ }
+ }
+
+ // Bounds is optional.
+ if (has_state && dict->GetType(kWindowRestoreBoundsKey) == VTYPE_DICTIONARY) {
+ auto bounds_dict = dict->GetDictionary(kWindowRestoreBoundsKey);
+ if (bounds_dict->GetType(kWindowRestoreBoundsKey_X) == VTYPE_INT &&
+ bounds_dict->GetType(kWindowRestoreBoundsKey_Y) == VTYPE_INT &&
+ bounds_dict->GetType(kWindowRestoreBoundsKey_W) == VTYPE_INT &&
+ bounds_dict->GetType(kWindowRestoreBoundsKey_H) == VTYPE_INT) {
+ dip_bounds = CefRect(bounds_dict->GetInt(kWindowRestoreBoundsKey_X),
+ bounds_dict->GetInt(kWindowRestoreBoundsKey_Y),
+ bounds_dict->GetInt(kWindowRestoreBoundsKey_W),
+ bounds_dict->GetInt(kWindowRestoreBoundsKey_H));
+ }
+ }
+
+ return has_state;
+}
+
+// Keep the bounds inside the closest display work area.
+CefRect ClampBoundsToDisplay(const CefRect& dip_bounds) {
+ auto display = CefDisplay::GetDisplayMatchingBounds(
+ dip_bounds, /*input_pixel_coords=*/false);
+ const auto work_area = display->GetWorkArea();
+
+ CefRect bounds = dip_bounds;
+
+ if (bounds.width > work_area.width) {
+ bounds.width = work_area.width;
+ }
+ if (bounds.height > work_area.height) {
+ bounds.height = work_area.height;
+ }
+
+ if (bounds.x < work_area.x) {
+ bounds.x = work_area.x;
+ } else if (bounds.x + bounds.width >= work_area.x + work_area.width) {
+ bounds.x = work_area.x + work_area.width - bounds.width;
+ }
+
+ if (bounds.y < work_area.y) {
+ bounds.y = work_area.y;
+ } else if (bounds.y + bounds.height >= work_area.y + work_area.height) {
+ bounds.y = work_area.y + work_area.height - bounds.height;
+ }
+
+ return bounds;
+}
+
+} // namespace
+
+void RegisterGlobalPreferences(CefRawPtr<CefPreferenceRegistrar> registrar) {
+ registrar->AddPreference(kPrefWindowRestore,
+ CreateDefaultWindowRestoreValue());
+}
+
+bool LoadWindowRestorePreferences(cef_show_state_t& show_state,
+ std::optional<CefRect>& dip_bounds) {
+ CEF_REQUIRE_UI_THREAD();
+
+ // Check if show state was specified on the command-line.
+ auto command_line = CefCommandLine::GetGlobalCommandLine();
+ if (command_line->HasSwitch(switches::kInitialShowState)) {
+ auto result = ShowStateFromString(
+ command_line->GetSwitchValue(switches::kInitialShowState));
+ if (result) {
+ show_state = *result;
+ return true;
+ }
+ }
+
+ // Check if show state was saved in global preferences.
+ auto manager = CefPreferenceManager::GetGlobalPreferenceManager();
+ if (ParseWindowRestoreValue(manager->GetPreference(kPrefWindowRestore),
+ show_state, dip_bounds)) {
+ if (dip_bounds) {
+ // Keep the bounds inside the closest display.
+ dip_bounds = ClampBoundsToDisplay(*dip_bounds);
+ }
+ return true;
+ }
+
+ return false;
+}
+
+bool SaveWindowRestorePreferences(cef_show_state_t show_state,
+ std::optional<CefRect> dip_bounds) {
+ CEF_REQUIRE_UI_THREAD();
+ auto manager = CefPreferenceManager::GetGlobalPreferenceManager();
+
+ CefString error;
+ return manager->SetPreference(
+ kPrefWindowRestore, CreateWindowRestoreValue(show_state, dip_bounds),
+ error);
+}
+
+} // namespace prefs
+} // namespace client
diff --git a/tests/cefclient/browser/client_prefs.h b/tests/cefclient/browser/client_prefs.h
new file mode 100644
index 00000000..577290d0
--- /dev/null
+++ b/tests/cefclient/browser/client_prefs.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_CLIENT_PREFS_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_CLIENT_PREFS_H_
+#pragma once
+
+#include <optional>
+
+#include "include/cef_base.h"
+#include "include/cef_preference.h"
+
+namespace client {
+namespace prefs {
+
+// Register global preferences with default values.
+void RegisterGlobalPreferences(CefRawPtr<CefPreferenceRegistrar> registrar);
+
+// Load/save window restore info.
+bool LoadWindowRestorePreferences(cef_show_state_t& show_state,
+ std::optional<CefRect>& dip_bounds);
+bool SaveWindowRestorePreferences(cef_show_state_t show_state,
+ std::optional<CefRect> dip_bounds);
+
+} // namespace prefs
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_CLIENT_PREFS_H_
diff --git a/tests/cefclient/browser/client_types.h b/tests/cefclient/browser/client_types.h
new file mode 100644
index 00000000..092c7112
--- /dev/null
+++ b/tests/cefclient/browser/client_types.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_CLIENT_TYPES_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_CLIENT_TYPES_H_
+#pragma once
+
+#include "include/cef_base.h"
+
+#if defined(OS_LINUX)
+#include <gtk/gtk.h>
+
+// The Linux client uses GTK instead of the underlying platform type (X11).
+#define ClientWindowHandle GtkWidget*
+#else
+#define ClientWindowHandle CefWindowHandle
+#endif
+
+#if defined(OS_MAC)
+#define ClientNativeMacWindow void*
+#ifdef __OBJC__
+#define CAST_CLIENT_NATIVE_MAC_WINDOW_TO_NSWINDOW(native) \
+ (__bridge NSWindow*)native
+#define CAST_NSWINDOW_TO_CLIENT_NATIVE_MAC_WINDOW(window) (__bridge void*)window
+#endif // __OBJC__
+#endif // defined OS_MAC
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_CLIENT_TYPES_H_
diff --git a/tests/cefclient/browser/default_client_handler.cc b/tests/cefclient/browser/default_client_handler.cc
new file mode 100644
index 00000000..d42f32a8
--- /dev/null
+++ b/tests/cefclient/browser/default_client_handler.cc
@@ -0,0 +1,60 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/default_client_handler.h"
+
+#include "tests/cefclient/browser/test_runner.h"
+
+namespace client {
+
+DefaultClientHandler::DefaultClientHandler() {
+ resource_manager_ = new CefResourceManager();
+ test_runner::SetupResourceManager(resource_manager_, nullptr);
+}
+
+CefRefPtr<CefResourceRequestHandler>
+DefaultClientHandler::GetResourceRequestHandler(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ bool is_navigation,
+ bool is_download,
+ const CefString& request_initiator,
+ bool& disable_default_handling) {
+ CEF_REQUIRE_IO_THREAD();
+ return this;
+}
+
+cef_return_value_t DefaultClientHandler::OnBeforeResourceLoad(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefCallback> callback) {
+ CEF_REQUIRE_IO_THREAD();
+
+ return resource_manager_->OnBeforeResourceLoad(browser, frame, request,
+ callback);
+}
+
+CefRefPtr<CefResourceHandler> DefaultClientHandler::GetResourceHandler(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request) {
+ CEF_REQUIRE_IO_THREAD();
+
+ return resource_manager_->GetResourceHandler(browser, frame, request);
+}
+
+CefRefPtr<CefResponseFilter> DefaultClientHandler::GetResourceResponseFilter(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response) {
+ CEF_REQUIRE_IO_THREAD();
+
+ return test_runner::GetResourceResponseFilter(browser, frame, request,
+ response);
+}
+
+} // namespace client
diff --git a/tests/cefclient/browser/default_client_handler.h b/tests/cefclient/browser/default_client_handler.h
new file mode 100644
index 00000000..6970d4ce
--- /dev/null
+++ b/tests/cefclient/browser/default_client_handler.h
@@ -0,0 +1,61 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_DEFAULT_CLIENT_HANDLER_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_DEFAULT_CLIENT_HANDLER_H_
+#pragma once
+
+#include "include/cef_client.h"
+#include "include/wrapper/cef_resource_manager.h"
+
+namespace client {
+
+// Default client handler for unmanaged browser windows. Used with the Chrome
+// runtime only.
+class DefaultClientHandler : public CefClient,
+ public CefRequestHandler,
+ public CefResourceRequestHandler {
+ public:
+ DefaultClientHandler();
+
+ // CefClient methods
+ CefRefPtr<CefRequestHandler> GetRequestHandler() override { return this; }
+
+ // CefRequestHandler methods
+ CefRefPtr<CefResourceRequestHandler> GetResourceRequestHandler(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ bool is_navigation,
+ bool is_download,
+ const CefString& request_initiator,
+ bool& disable_default_handling) override;
+
+ // CefResourceRequestHandler methods
+ cef_return_value_t OnBeforeResourceLoad(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefCallback> callback) override;
+ CefRefPtr<CefResourceHandler> GetResourceHandler(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request) override;
+ CefRefPtr<CefResponseFilter> GetResourceResponseFilter(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response) override;
+
+ private:
+ // Manages the registration and delivery of resources.
+ CefRefPtr<CefResourceManager> resource_manager_;
+
+ IMPLEMENT_REFCOUNTING(DefaultClientHandler);
+ DISALLOW_COPY_AND_ASSIGN(DefaultClientHandler);
+};
+
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_DEFAULT_CLIENT_HANDLER_H_
diff --git a/tests/cefclient/browser/dialog_handler_gtk.cc b/tests/cefclient/browser/dialog_handler_gtk.cc
new file mode 100644
index 00000000..33e687bb
--- /dev/null
+++ b/tests/cefclient/browser/dialog_handler_gtk.cc
@@ -0,0 +1,456 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/dialog_handler_gtk.h"
+
+#include <libgen.h>
+#include <sys/stat.h>
+
+#include "include/cef_browser.h"
+#include "include/cef_parser.h"
+#include "include/wrapper/cef_helpers.h"
+#include "tests/cefclient/browser/root_window.h"
+#include "tests/cefclient/browser/util_gtk.h"
+
+namespace client {
+
+namespace {
+
+const char kPromptTextId[] = "cef_prompt_text";
+
+// If there's a text entry in the dialog, get the text from the first one and
+// return it.
+std::string GetPromptText(GtkDialog* dialog) {
+ GtkWidget* widget = static_cast<GtkWidget*>(
+ g_object_get_data(G_OBJECT(dialog), kPromptTextId));
+ if (widget) {
+ return gtk_entry_get_text(GTK_ENTRY(widget));
+ }
+ return std::string();
+}
+
+std::string GetDescriptionFromMimeType(const std::string& mime_type) {
+ // Check for wild card mime types and return an appropriate description.
+ static const struct {
+ const char* mime_type;
+ const char* label;
+ } kWildCardMimeTypes[] = {
+ {"audio", "Audio Files"},
+ {"image", "Image Files"},
+ {"text", "Text Files"},
+ {"video", "Video Files"},
+ };
+
+ for (size_t i = 0;
+ i < sizeof(kWildCardMimeTypes) / sizeof(kWildCardMimeTypes[0]); ++i) {
+ if (mime_type == std::string(kWildCardMimeTypes[i].mime_type) + "/*") {
+ return std::string(kWildCardMimeTypes[i].label);
+ }
+ }
+
+ return std::string();
+}
+
+void AddFilters(GtkFileChooser* chooser,
+ const std::vector<CefString>& accept_filters,
+ bool include_all_files,
+ std::vector<GtkFileFilter*>* filters) {
+ bool has_filter = false;
+
+ for (size_t j = 0; j < accept_filters.size(); ++j) {
+ const std::string& filter = accept_filters[j];
+ if (filter.empty()) {
+ continue;
+ }
+
+ std::vector<std::string> extensions;
+ std::string description;
+
+ size_t sep_index = filter.find('|');
+ if (sep_index != std::string::npos) {
+ // Treat as a filter of the form "Filter Name|.ext1;.ext2;.ext3".
+ description = filter.substr(0, sep_index);
+
+ const std::string& exts = filter.substr(sep_index + 1);
+ size_t last = 0;
+ size_t size = exts.size();
+ for (size_t i = 0; i <= size; ++i) {
+ if (i == size || exts[i] == ';') {
+ std::string ext(exts, last, i - last);
+ if (!ext.empty() && ext[0] == '.') {
+ extensions.push_back(ext);
+ }
+ last = i + 1;
+ }
+ }
+ } else if (filter[0] == '.') {
+ // Treat as an extension beginning with the '.' character.
+ extensions.push_back(filter);
+ } else {
+ // Otherwise convert mime type to one or more extensions.
+ description = GetDescriptionFromMimeType(filter);
+
+ std::vector<CefString> ext;
+ CefGetExtensionsForMimeType(filter, ext);
+ for (size_t x = 0; x < ext.size(); ++x) {
+ extensions.push_back("." + ext[x].ToString());
+ }
+ }
+
+ if (extensions.empty()) {
+ continue;
+ }
+
+ GtkFileFilter* gtk_filter = gtk_file_filter_new();
+
+ std::string ext_str;
+ for (size_t x = 0; x < extensions.size(); ++x) {
+ const std::string& pattern = "*" + extensions[x];
+ if (x != 0) {
+ ext_str += ";";
+ }
+ ext_str += pattern;
+ gtk_file_filter_add_pattern(gtk_filter, pattern.c_str());
+ }
+
+ if (description.empty()) {
+ description = ext_str;
+ } else {
+ description += " (" + ext_str + ")";
+ }
+
+ gtk_file_filter_set_name(gtk_filter, description.c_str());
+ gtk_file_chooser_add_filter(chooser, gtk_filter);
+ if (!has_filter) {
+ has_filter = true;
+ }
+
+ filters->push_back(gtk_filter);
+ }
+
+ // Add the *.* filter, but only if we have added other filters (otherwise it
+ // is implied).
+ if (include_all_files && has_filter) {
+ GtkFileFilter* filter = gtk_file_filter_new();
+ gtk_file_filter_add_pattern(filter, "*");
+ gtk_file_filter_set_name(filter, "All Files (*)");
+ gtk_file_chooser_add_filter(chooser, filter);
+ }
+}
+
+GtkWindow* GetWindow(CefRefPtr<CefBrowser> browser) {
+ REQUIRE_MAIN_THREAD();
+ scoped_refptr<RootWindow> root_window =
+ RootWindow::GetForBrowser(browser->GetIdentifier());
+ if (root_window) {
+ GtkWidget* window = root_window->GetWindowHandle();
+ DCHECK(window);
+ if (!window) {
+ LOG(ERROR) << "No GtkWindow for browser";
+ }
+ return GTK_WINDOW(window);
+ }
+ return nullptr;
+}
+
+} // namespace
+
+ClientDialogHandlerGtk::ClientDialogHandlerGtk() : gtk_dialog_(nullptr) {}
+
+bool ClientDialogHandlerGtk::OnFileDialog(
+ CefRefPtr<CefBrowser> browser,
+ FileDialogMode mode,
+ const CefString& title,
+ const CefString& default_file_path,
+ const std::vector<CefString>& accept_filters,
+ CefRefPtr<CefFileDialogCallback> callback) {
+ CEF_REQUIRE_UI_THREAD();
+
+ OnFileDialogParams params;
+ params.browser = browser;
+ params.mode = mode;
+ params.title = title;
+ params.default_file_path = default_file_path;
+ params.accept_filters = accept_filters;
+ params.callback = callback;
+
+ GetWindowAndContinue(
+ browser, base::BindOnce(&ClientDialogHandlerGtk::OnFileDialogContinue,
+ this, params));
+ return true;
+}
+
+bool ClientDialogHandlerGtk::OnJSDialog(CefRefPtr<CefBrowser> browser,
+ const CefString& origin_url,
+ JSDialogType dialog_type,
+ const CefString& message_text,
+ const CefString& default_prompt_text,
+ CefRefPtr<CefJSDialogCallback> callback,
+ bool& suppress_message) {
+ CEF_REQUIRE_UI_THREAD();
+
+ OnJSDialogParams params;
+ params.browser = browser;
+ params.origin_url = origin_url;
+ params.dialog_type = dialog_type;
+ params.message_text = message_text;
+ params.default_prompt_text = default_prompt_text;
+ params.callback = callback;
+
+ GetWindowAndContinue(
+ browser, base::BindOnce(&ClientDialogHandlerGtk::OnJSDialogContinue, this,
+ params));
+ return true;
+}
+
+bool ClientDialogHandlerGtk::OnBeforeUnloadDialog(
+ CefRefPtr<CefBrowser> browser,
+ const CefString& message_text,
+ bool is_reload,
+ CefRefPtr<CefJSDialogCallback> callback) {
+ CEF_REQUIRE_UI_THREAD();
+
+ const std::string& new_message_text =
+ message_text.ToString() + "\n\nIs it OK to leave/reload this page?";
+ bool suppress_message = false;
+
+ return OnJSDialog(browser, CefString(), JSDIALOGTYPE_CONFIRM,
+ new_message_text, CefString(), callback, suppress_message);
+}
+
+void ClientDialogHandlerGtk::OnResetDialogState(CefRefPtr<CefBrowser> browser) {
+ CEF_REQUIRE_UI_THREAD();
+
+ if (!gtk_dialog_) {
+ return;
+ }
+
+ gtk_widget_destroy(gtk_dialog_);
+ gtk_dialog_ = nullptr;
+ js_dialog_callback_ = nullptr;
+}
+
+void ClientDialogHandlerGtk::OnFileDialogContinue(
+ const OnFileDialogParams& params,
+ GtkWindow* window) {
+ REQUIRE_MAIN_THREAD();
+
+ ScopedGdkThreadsEnter scoped_gdk_threads;
+
+ std::vector<CefString> files;
+
+ GtkFileChooserAction action;
+ const gchar* accept_button;
+
+ if (params.mode == FILE_DIALOG_OPEN ||
+ params.mode == FILE_DIALOG_OPEN_MULTIPLE) {
+ action = GTK_FILE_CHOOSER_ACTION_OPEN;
+ accept_button = "_Open";
+ } else if (params.mode == FILE_DIALOG_OPEN_FOLDER) {
+ action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
+ accept_button = "_Open";
+ } else if (params.mode == FILE_DIALOG_SAVE) {
+ action = GTK_FILE_CHOOSER_ACTION_SAVE;
+ accept_button = "_Save";
+ } else {
+ NOTREACHED();
+ params.callback->Cancel();
+ return;
+ }
+
+ std::string title_str;
+ if (!params.title.empty()) {
+ title_str = params.title;
+ } else {
+ switch (params.mode) {
+ case FILE_DIALOG_OPEN:
+ title_str = "Open File";
+ break;
+ case FILE_DIALOG_OPEN_MULTIPLE:
+ title_str = "Open Files";
+ break;
+ case FILE_DIALOG_OPEN_FOLDER:
+ title_str = "Open Folder";
+ break;
+ case FILE_DIALOG_SAVE:
+ title_str = "Save File";
+ break;
+ default:
+ break;
+ }
+ }
+
+ GtkWidget* dialog = gtk_file_chooser_dialog_new(
+ title_str.c_str(), GTK_WINDOW(window), action, "_Cancel",
+ GTK_RESPONSE_CANCEL, accept_button, GTK_RESPONSE_ACCEPT, nullptr);
+
+ if (params.mode == FILE_DIALOG_OPEN_MULTIPLE) {
+ gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), TRUE);
+ }
+
+ if (!params.default_file_path.empty() && params.mode == FILE_DIALOG_SAVE) {
+ const std::string& file_path = params.default_file_path;
+ bool exists = false;
+
+ struct stat sb;
+ if (stat(file_path.c_str(), &sb) == 0 && S_ISREG(sb.st_mode)) {
+ // Use the directory and name of the existing file.
+ gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), file_path.data());
+ exists = true;
+ }
+
+ if (!exists) {
+ // Set the current file name but let the user choose the directory.
+ std::string file_name_str = file_path;
+ const char* file_name = basename(const_cast<char*>(file_name_str.data()));
+ gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), file_name);
+ }
+ }
+
+ std::vector<GtkFileFilter*> filters;
+ AddFilters(GTK_FILE_CHOOSER(dialog), params.accept_filters, true, &filters);
+
+ bool success = false;
+
+ if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
+ if (params.mode == FILE_DIALOG_OPEN ||
+ params.mode == FILE_DIALOG_OPEN_FOLDER ||
+ params.mode == FILE_DIALOG_SAVE) {
+ char* filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
+ files.push_back(std::string(filename));
+ success = true;
+ } else if (params.mode == FILE_DIALOG_OPEN_MULTIPLE) {
+ GSList* filenames =
+ gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog));
+ if (filenames) {
+ for (GSList* iter = filenames; iter != nullptr;
+ iter = g_slist_next(iter)) {
+ std::string path(static_cast<char*>(iter->data));
+ g_free(iter->data);
+ files.push_back(path);
+ }
+ g_slist_free(filenames);
+ success = true;
+ }
+ }
+ }
+
+ gtk_widget_destroy(dialog);
+
+ if (success) {
+ params.callback->Continue(files);
+ } else {
+ params.callback->Cancel();
+ }
+}
+
+void ClientDialogHandlerGtk::OnJSDialogContinue(const OnJSDialogParams& params,
+ GtkWindow* window) {
+ REQUIRE_MAIN_THREAD();
+
+ ScopedGdkThreadsEnter scoped_gdk_threads;
+
+ GtkButtonsType buttons = GTK_BUTTONS_NONE;
+ GtkMessageType gtk_message_type = GTK_MESSAGE_OTHER;
+ std::string title;
+
+ switch (params.dialog_type) {
+ case JSDIALOGTYPE_ALERT:
+ buttons = GTK_BUTTONS_NONE;
+ gtk_message_type = GTK_MESSAGE_WARNING;
+ title = "JavaScript Alert";
+ break;
+
+ case JSDIALOGTYPE_CONFIRM:
+ buttons = GTK_BUTTONS_CANCEL;
+ gtk_message_type = GTK_MESSAGE_QUESTION;
+ title = "JavaScript Confirm";
+ break;
+
+ case JSDIALOGTYPE_PROMPT:
+ buttons = GTK_BUTTONS_CANCEL;
+ gtk_message_type = GTK_MESSAGE_QUESTION;
+ title = "JavaScript Prompt";
+ break;
+ }
+
+ js_dialog_callback_ = params.callback;
+
+ if (!params.origin_url.empty()) {
+ title += " - ";
+ title += CefFormatUrlForSecurityDisplay(params.origin_url).ToString();
+ }
+
+ gtk_dialog_ = gtk_message_dialog_new(GTK_WINDOW(window), GTK_DIALOG_MODAL,
+ gtk_message_type, buttons, "%s",
+ params.message_text.ToString().c_str());
+ g_signal_connect(gtk_dialog_, "delete-event",
+ G_CALLBACK(gtk_widget_hide_on_delete), nullptr);
+
+ gtk_window_set_title(GTK_WINDOW(gtk_dialog_), title.c_str());
+
+ GtkWidget* ok_button =
+ gtk_dialog_add_button(GTK_DIALOG(gtk_dialog_), "_OK", GTK_RESPONSE_OK);
+
+ if (params.dialog_type != JSDIALOGTYPE_PROMPT) {
+ gtk_widget_grab_focus(ok_button);
+ }
+
+ if (params.dialog_type == JSDIALOGTYPE_PROMPT) {
+ GtkWidget* content_area =
+ gtk_dialog_get_content_area(GTK_DIALOG(gtk_dialog_));
+ GtkWidget* text_box = gtk_entry_new();
+ gtk_entry_set_text(GTK_ENTRY(text_box),
+ params.default_prompt_text.ToString().c_str());
+ gtk_box_pack_start(GTK_BOX(content_area), text_box, TRUE, TRUE, 0);
+ g_object_set_data(G_OBJECT(gtk_dialog_), kPromptTextId, text_box);
+ gtk_entry_set_activates_default(GTK_ENTRY(text_box), TRUE);
+ }
+
+ gtk_dialog_set_default_response(GTK_DIALOG(gtk_dialog_), GTK_RESPONSE_OK);
+ g_signal_connect(gtk_dialog_, "response", G_CALLBACK(OnDialogResponse), this);
+ gtk_widget_show_all(GTK_WIDGET(gtk_dialog_));
+}
+
+void ClientDialogHandlerGtk::GetWindowAndContinue(
+ CefRefPtr<CefBrowser> browser,
+ base::OnceCallback<void(GtkWindow*)> callback) {
+ if (!CURRENTLY_ON_MAIN_THREAD()) {
+ MAIN_POST_CLOSURE(
+ base::BindOnce(&ClientDialogHandlerGtk::GetWindowAndContinue, this,
+ browser, std::move(callback)));
+ return;
+ }
+
+ GtkWindow* window = GetWindow(browser);
+ if (window) {
+ std::move(callback).Run(window);
+ }
+}
+
+// static
+void ClientDialogHandlerGtk::OnDialogResponse(GtkDialog* dialog,
+ gint response_id,
+ ClientDialogHandlerGtk* handler) {
+ REQUIRE_MAIN_THREAD();
+
+ DCHECK_EQ(dialog, GTK_DIALOG(handler->gtk_dialog_));
+ switch (response_id) {
+ case GTK_RESPONSE_OK:
+ handler->js_dialog_callback_->Continue(true, GetPromptText(dialog));
+ break;
+ case GTK_RESPONSE_CANCEL:
+ case GTK_RESPONSE_DELETE_EVENT:
+ handler->js_dialog_callback_->Continue(false, CefString());
+ break;
+ default:
+ NOTREACHED();
+ }
+
+ CefPostTask(TID_UI,
+ base::BindOnce(&ClientDialogHandlerGtk::OnResetDialogState,
+ handler, nullptr));
+}
+
+} // namespace client
diff --git a/tests/cefclient/browser/dialog_handler_gtk.h b/tests/cefclient/browser/dialog_handler_gtk.h
new file mode 100644
index 00000000..1ad96715
--- /dev/null
+++ b/tests/cefclient/browser/dialog_handler_gtk.h
@@ -0,0 +1,82 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_DIALOG_HANDLER_GTK_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_DIALOG_HANDLER_GTK_H_
+#pragma once
+
+#include <gtk/gtk.h>
+
+#include "include/base/cef_callback_forward.h"
+#include "include/cef_dialog_handler.h"
+#include "include/cef_jsdialog_handler.h"
+
+namespace client {
+
+class ClientDialogHandlerGtk : public CefDialogHandler,
+ public CefJSDialogHandler {
+ public:
+ ClientDialogHandlerGtk();
+
+ // CefDialogHandler methods.
+ bool OnFileDialog(CefRefPtr<CefBrowser> browser,
+ FileDialogMode mode,
+ const CefString& title,
+ const CefString& default_file_path,
+ const std::vector<CefString>& accept_filters,
+ CefRefPtr<CefFileDialogCallback> callback) override;
+
+ // CefJSDialogHandler methods.
+ bool OnJSDialog(CefRefPtr<CefBrowser> browser,
+ const CefString& origin_url,
+ JSDialogType dialog_type,
+ const CefString& message_text,
+ const CefString& default_prompt_text,
+ CefRefPtr<CefJSDialogCallback> callback,
+ bool& suppress_message) override;
+ bool OnBeforeUnloadDialog(CefRefPtr<CefBrowser> browser,
+ const CefString& message_text,
+ bool is_reload,
+ CefRefPtr<CefJSDialogCallback> callback) override;
+ void OnResetDialogState(CefRefPtr<CefBrowser> browser) override;
+
+ private:
+ struct OnFileDialogParams {
+ CefRefPtr<CefBrowser> browser;
+ FileDialogMode mode;
+ CefString title;
+ CefString default_file_path;
+ std::vector<CefString> accept_filters;
+ CefRefPtr<CefFileDialogCallback> callback;
+ };
+ void OnFileDialogContinue(const OnFileDialogParams& params,
+ GtkWindow* window);
+
+ struct OnJSDialogParams {
+ CefRefPtr<CefBrowser> browser;
+ CefString origin_url;
+ JSDialogType dialog_type;
+ CefString message_text;
+ CefString default_prompt_text;
+ CefRefPtr<CefJSDialogCallback> callback;
+ };
+ void OnJSDialogContinue(const OnJSDialogParams& params, GtkWindow* window);
+
+ void GetWindowAndContinue(CefRefPtr<CefBrowser> browser,
+ base::OnceCallback<void(GtkWindow*)> callback);
+
+ static void OnDialogResponse(GtkDialog* dialog,
+ gint response_id,
+ ClientDialogHandlerGtk* handler);
+
+ GtkWidget* gtk_dialog_;
+ CefRefPtr<CefJSDialogCallback> js_dialog_callback_;
+
+ IMPLEMENT_REFCOUNTING(ClientDialogHandlerGtk);
+ DISALLOW_COPY_AND_ASSIGN(ClientDialogHandlerGtk);
+};
+
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_DIALOG_HANDLER_GTK_H_
diff --git a/tests/cefclient/browser/dialog_test.cc b/tests/cefclient/browser/dialog_test.cc
new file mode 100644
index 00000000..78d23d83
--- /dev/null
+++ b/tests/cefclient/browser/dialog_test.cc
@@ -0,0 +1,178 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/dialog_test.h"
+
+#include <string>
+
+#include "include/cef_browser.h"
+#include "include/wrapper/cef_helpers.h"
+#include "tests/cefclient/browser/test_runner.h"
+#include "tests/shared/browser/file_util.h"
+
+namespace client {
+namespace dialog_test {
+
+namespace {
+
+const char kTestUrlPath[] = "/dialogs";
+const char kFileOpenPngMessageName[] = "DialogTest.FileOpenPng";
+const char kFileOpenImageMessageName[] = "DialogTest.FileOpenImage";
+const char kFileOpenMultipleMessageName[] = "DialogTest.FileOpenMultiple";
+const char kFileOpenFolderMessageName[] = "DialogTest.FileOpenFolder";
+const char kFileSaveMessageName[] = "DialogTest.FileSave";
+
+// Store persistent dialog state information.
+class DialogState : public base::RefCountedThreadSafe<DialogState> {
+ public:
+ DialogState() : mode_(FILE_DIALOG_OPEN), pending_(false) {}
+
+ cef_file_dialog_mode_t mode_;
+ CefString last_file_;
+ bool pending_;
+
+ DISALLOW_COPY_AND_ASSIGN(DialogState);
+};
+
+// Callback executed when the file dialog is dismissed.
+class DialogCallback : public CefRunFileDialogCallback {
+ public:
+ DialogCallback(
+ CefRefPtr<CefMessageRouterBrowserSide::Callback> router_callback,
+ scoped_refptr<DialogState> dialog_state)
+ : router_callback_(router_callback), dialog_state_(dialog_state) {}
+
+ virtual void OnFileDialogDismissed(
+ const std::vector<CefString>& file_paths) override {
+ CEF_REQUIRE_UI_THREAD();
+ DCHECK(dialog_state_->pending_);
+
+ if (!file_paths.empty()) {
+ dialog_state_->last_file_ = file_paths[0];
+ if (dialog_state_->mode_ == FILE_DIALOG_OPEN_FOLDER) {
+ std::string last_file = dialog_state_->last_file_;
+ if (last_file[last_file.length() - 1] != file_util::kPathSep) {
+ // Add a trailing slash so we know it's a directory. Otherwise, file
+ // dialogs will think the last path component is a file name.
+ last_file += file_util::kPathSep;
+ dialog_state_->last_file_ = last_file;
+ }
+ }
+ }
+
+ // Send a message back to the render process with the list of file paths.
+ std::string response;
+ for (int i = 0; i < static_cast<int>(file_paths.size()); ++i) {
+ if (!response.empty()) {
+ response += "|"; // Use a delimiter disallowed in file paths.
+ }
+ response += file_paths[i];
+ }
+
+ router_callback_->Success(response);
+ router_callback_ = nullptr;
+
+ dialog_state_->pending_ = false;
+ dialog_state_ = nullptr;
+ }
+
+ private:
+ CefRefPtr<CefMessageRouterBrowserSide::Callback> router_callback_;
+ scoped_refptr<DialogState> dialog_state_;
+
+ IMPLEMENT_REFCOUNTING(DialogCallback);
+ DISALLOW_COPY_AND_ASSIGN(DialogCallback);
+};
+
+// Handle messages in the browser process.
+class Handler : public CefMessageRouterBrowserSide::Handler {
+ public:
+ Handler() {}
+
+ // Called due to cefQuery execution in dialogs.html.
+ virtual bool OnQuery(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int64 query_id,
+ const CefString& request,
+ bool persistent,
+ CefRefPtr<Callback> callback) override {
+ CEF_REQUIRE_UI_THREAD();
+
+ // Only handle messages from the test URL.
+ const std::string& url = frame->GetURL();
+ if (!test_runner::IsTestURL(url, kTestUrlPath)) {
+ return false;
+ }
+
+ if (!dialog_state_.get()) {
+ dialog_state_ = new DialogState;
+ }
+
+ // Make sure we're only running one dialog at a time.
+ DCHECK(!dialog_state_->pending_);
+
+ std::vector<CefString> accept_filters;
+ std::string title;
+
+ const std::string& message_name = request;
+ if (message_name == kFileOpenPngMessageName) {
+ dialog_state_->mode_ = FILE_DIALOG_OPEN;
+ title = "My Open PNG Dialog";
+ accept_filters.push_back(".png");
+ } else if (message_name == kFileOpenImageMessageName) {
+ dialog_state_->mode_ = FILE_DIALOG_OPEN;
+ title = "My Open Image Dialog";
+ accept_filters.push_back("image/*");
+ } else if (message_name == kFileOpenMultipleMessageName) {
+ dialog_state_->mode_ = FILE_DIALOG_OPEN_MULTIPLE;
+ title = "My Open MultiType Dialog";
+ } else if (message_name == kFileOpenFolderMessageName) {
+ dialog_state_->mode_ = FILE_DIALOG_OPEN_FOLDER;
+ title = "My Open Folder Dialog";
+ } else if (message_name == kFileSaveMessageName) {
+ dialog_state_->mode_ = FILE_DIALOG_SAVE;
+ title = "My Save Dialog";
+ } else {
+ NOTREACHED();
+ return true;
+ }
+
+ if (accept_filters.empty() &&
+ dialog_state_->mode_ != FILE_DIALOG_OPEN_FOLDER) {
+ // Build filters based on mime time.
+ accept_filters.push_back("text/*");
+
+ // Build filters based on file extension.
+ accept_filters.push_back(".log");
+ accept_filters.push_back(".patch");
+
+ // Add specific filters as-is.
+ accept_filters.push_back("Document Files|.doc;.odt");
+ accept_filters.push_back("Image Files|.png;.jpg;.gif");
+ accept_filters.push_back("PDF Files|.pdf");
+ }
+
+ dialog_state_->pending_ = true;
+
+ browser->GetHost()->RunFileDialog(
+ dialog_state_->mode_, title, dialog_state_->last_file_, accept_filters,
+ new DialogCallback(callback, dialog_state_));
+
+ return true;
+ }
+
+ private:
+ scoped_refptr<DialogState> dialog_state_;
+
+ DISALLOW_COPY_AND_ASSIGN(Handler);
+};
+
+} // namespace
+
+void CreateMessageHandlers(test_runner::MessageHandlerSet& handlers) {
+ handlers.insert(new Handler());
+}
+
+} // namespace dialog_test
+} // namespace client
diff --git a/tests/cefclient/browser/dialog_test.h b/tests/cefclient/browser/dialog_test.h
new file mode 100644
index 00000000..2044594f
--- /dev/null
+++ b/tests/cefclient/browser/dialog_test.h
@@ -0,0 +1,20 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_DIALOG_TEST_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_DIALOG_TEST_H_
+#pragma once
+
+#include "tests/cefclient/browser/test_runner.h"
+
+namespace client {
+namespace dialog_test {
+
+// Create message handlers. Called from test_runner.cc.
+void CreateMessageHandlers(test_runner::MessageHandlerSet& handlers);
+
+} // namespace dialog_test
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_DIALOG_TEST_H_
diff --git a/tests/cefclient/browser/image_cache.cc b/tests/cefclient/browser/image_cache.cc
new file mode 100644
index 00000000..21645938
--- /dev/null
+++ b/tests/cefclient/browser/image_cache.cc
@@ -0,0 +1,319 @@
+// Copyright (c) 2017 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/image_cache.h"
+
+#include <algorithm>
+
+#include "tests/shared/browser/file_util.h"
+#include "tests/shared/browser/resource_util.h"
+#include "tests/shared/common/string_util.h"
+
+namespace client {
+
+namespace {
+
+const char kEmptyId[] = "__empty";
+
+} // namespace
+
+ImageCache::ImageCache() {}
+
+ImageCache::~ImageCache() {
+ CEF_REQUIRE_UI_THREAD();
+}
+
+ImageCache::ImageRep::ImageRep(const std::string& path, float scale_factor)
+ : path_(path), scale_factor_(scale_factor) {
+ DCHECK(!path_.empty());
+ DCHECK_GT(scale_factor_, 0.0f);
+}
+
+ImageCache::ImageInfo::ImageInfo(const std::string& id,
+ const ImageRepSet& reps,
+ bool internal,
+ bool force_reload)
+ : id_(id), reps_(reps), internal_(internal), force_reload_(force_reload) {
+#ifndef NDEBUG
+ DCHECK(!id_.empty());
+ if (id_ != kEmptyId) {
+ DCHECK(!reps_.empty());
+ }
+#endif
+}
+
+// static
+ImageCache::ImageInfo ImageCache::ImageInfo::Empty() {
+ return ImageInfo(kEmptyId, ImageRepSet(), true, false);
+}
+
+// static
+ImageCache::ImageInfo ImageCache::ImageInfo::Create1x(
+ const std::string& id,
+ const std::string& path_1x,
+ bool internal) {
+ ImageRepSet reps;
+ reps.push_back(ImageRep(path_1x, 1.0f));
+ return ImageInfo(id, reps, internal, false);
+}
+
+// static
+ImageCache::ImageInfo ImageCache::ImageInfo::Create2x(
+ const std::string& id,
+ const std::string& path_1x,
+ const std::string& path_2x,
+ bool internal) {
+ ImageRepSet reps;
+ reps.push_back(ImageRep(path_1x, 1.0f));
+ reps.push_back(ImageRep(path_2x, 2.0f));
+ return ImageInfo(id, reps, internal, false);
+}
+
+// static
+ImageCache::ImageInfo ImageCache::ImageInfo::Create2x(const std::string& id) {
+ return Create2x(id, id + ".1x.png", id + ".2x.png", true);
+}
+
+struct ImageCache::ImageContent {
+ ImageContent() {}
+
+ struct RepContent {
+ RepContent(ImageType type, float scale_factor, const std::string& contents)
+ : type_(type), scale_factor_(scale_factor), contents_(contents) {}
+
+ ImageType type_;
+ float scale_factor_;
+ std::string contents_;
+ };
+ typedef std::vector<RepContent> RepContentSet;
+ RepContentSet contents_;
+
+ CefRefPtr<CefImage> image_;
+};
+
+void ImageCache::LoadImages(const ImageInfoSet& image_info,
+ LoadImagesCallback callback) {
+ DCHECK(!image_info.empty());
+ DCHECK(!callback.is_null());
+
+ if (!CefCurrentlyOn(TID_UI)) {
+ CefPostTask(TID_UI, base::BindOnce(&ImageCache::LoadImages, this,
+ image_info, std::move(callback)));
+ return;
+ }
+
+ ImageSet images;
+ bool missing_images = false;
+
+ ImageInfoSet::const_iterator it = image_info.begin();
+ for (; it != image_info.end(); ++it) {
+ const ImageInfo& info = *it;
+
+ if (info.id_ == kEmptyId) {
+ // Image intentionally left empty.
+ images.push_back(nullptr);
+ continue;
+ }
+
+ ImageMap::iterator it2 = image_map_.find(info.id_);
+ if (it2 != image_map_.end()) {
+ if (!info.force_reload_) {
+ // Image already exists.
+ images.push_back(it2->second);
+ continue;
+ }
+
+ // Remove the existing image from the map.
+ image_map_.erase(it2);
+ }
+
+ // Load the image.
+ images.push_back(nullptr);
+ if (!missing_images) {
+ missing_images = true;
+ }
+ }
+
+ if (missing_images) {
+ CefPostTask(TID_FILE_USER_BLOCKING,
+ base::BindOnce(&ImageCache::LoadMissing, this, image_info,
+ images, std::move(callback)));
+ } else {
+ std::move(callback).Run(images);
+ }
+}
+
+CefRefPtr<CefImage> ImageCache::GetCachedImage(const std::string& image_id) {
+ CEF_REQUIRE_UI_THREAD();
+ DCHECK(!image_id.empty());
+
+ ImageMap::const_iterator it = image_map_.find(image_id);
+ if (it != image_map_.end()) {
+ return it->second;
+ }
+
+ return nullptr;
+}
+
+// static
+ImageCache::ImageType ImageCache::GetImageType(const std::string& path) {
+ std::string ext = file_util::GetFileExtension(path);
+ if (ext.empty()) {
+ return TYPE_NONE;
+ }
+
+ ext = AsciiStrToLower(ext);
+ if (ext == "png") {
+ return TYPE_PNG;
+ }
+ if (ext == "jpg" || ext == "jpeg") {
+ return TYPE_JPEG;
+ }
+
+ return TYPE_NONE;
+}
+
+void ImageCache::LoadMissing(const ImageInfoSet& image_info,
+ const ImageSet& images,
+ LoadImagesCallback callback) {
+ CEF_REQUIRE_FILE_USER_BLOCKING_THREAD();
+
+ DCHECK_EQ(image_info.size(), images.size());
+
+ ImageContentSet contents;
+
+ ImageInfoSet::const_iterator it1 = image_info.begin();
+ ImageSet::const_iterator it2 = images.begin();
+ for (; it1 != image_info.end() && it2 != images.end(); ++it1, ++it2) {
+ const ImageInfo& info = *it1;
+ ImageContent content;
+ if (*it2 || info.id_ == kEmptyId) {
+ // Image already exists or is intentionally empty.
+ content.image_ = *it2;
+ } else {
+ LoadImageContents(info, &content);
+ }
+ contents.push_back(content);
+ }
+
+ CefPostTask(TID_UI, base::BindOnce(&ImageCache::UpdateCache, this, image_info,
+ contents, std::move(callback)));
+}
+
+// static
+bool ImageCache::LoadImageContents(const ImageInfo& info,
+ ImageContent* content) {
+ CEF_REQUIRE_FILE_USER_BLOCKING_THREAD();
+
+ ImageRepSet::const_iterator it = info.reps_.begin();
+ for (; it != info.reps_.end(); ++it) {
+ const ImageRep& rep = *it;
+ ImageType rep_type;
+ std::string rep_contents;
+ if (!LoadImageContents(rep.path_, info.internal_, &rep_type,
+ &rep_contents)) {
+ LOG(ERROR) << "Failed to load image " << info.id_ << " from path "
+ << rep.path_;
+ return false;
+ }
+ content->contents_.push_back(
+ ImageContent::RepContent(rep_type, rep.scale_factor_, rep_contents));
+ }
+
+ return true;
+}
+
+// static
+bool ImageCache::LoadImageContents(const std::string& path,
+ bool internal,
+ ImageType* type,
+ std::string* contents) {
+ CEF_REQUIRE_FILE_USER_BLOCKING_THREAD();
+
+ *type = GetImageType(path);
+ if (*type == TYPE_NONE) {
+ return false;
+ }
+
+ if (internal) {
+ if (!LoadBinaryResource(path.c_str(), *contents)) {
+ return false;
+ }
+ } else if (!file_util::ReadFileToString(path, contents)) {
+ return false;
+ }
+
+ return !contents->empty();
+}
+
+void ImageCache::UpdateCache(const ImageInfoSet& image_info,
+ const ImageContentSet& contents,
+ LoadImagesCallback callback) {
+ CEF_REQUIRE_UI_THREAD();
+
+ DCHECK_EQ(image_info.size(), contents.size());
+
+ ImageSet images;
+
+ ImageInfoSet::const_iterator it1 = image_info.begin();
+ ImageContentSet::const_iterator it2 = contents.begin();
+ for (; it1 != image_info.end() && it2 != contents.end(); ++it1, ++it2) {
+ const ImageInfo& info = *it1;
+ const ImageContent& content = *it2;
+ if (content.image_ || info.id_ == kEmptyId) {
+ // Image already exists or is intentionally empty.
+ images.push_back(content.image_);
+ } else {
+ CefRefPtr<CefImage> image = CreateImage(info.id_, content);
+ images.push_back(image);
+
+ // Add the image to the map.
+ image_map_.insert(std::make_pair(info.id_, image));
+ }
+ }
+
+ std::move(callback).Run(images);
+}
+
+// static
+CefRefPtr<CefImage> ImageCache::CreateImage(const std::string& image_id,
+ const ImageContent& content) {
+ CEF_REQUIRE_UI_THREAD();
+
+ // Shouldn't be creating an image if one already exists.
+ DCHECK(!content.image_);
+
+ if (content.contents_.empty()) {
+ return nullptr;
+ }
+
+ CefRefPtr<CefImage> image = CefImage::CreateImage();
+
+ ImageContent::RepContentSet::const_iterator it = content.contents_.begin();
+ for (; it != content.contents_.end(); ++it) {
+ const ImageContent::RepContent& rep = *it;
+ if (rep.type_ == TYPE_PNG) {
+ if (!image->AddPNG(rep.scale_factor_, rep.contents_.c_str(),
+ rep.contents_.size())) {
+ LOG(ERROR) << "Failed to create image " << image_id << " for PNG@"
+ << rep.scale_factor_;
+ return nullptr;
+ }
+ } else if (rep.type_ == TYPE_JPEG) {
+ if (!image->AddJPEG(rep.scale_factor_, rep.contents_.c_str(),
+ rep.contents_.size())) {
+ LOG(ERROR) << "Failed to create image " << image_id << " for JPG@"
+ << rep.scale_factor_;
+ return nullptr;
+ }
+ } else {
+ NOTREACHED();
+ return nullptr;
+ }
+ }
+
+ return image;
+}
+
+} // namespace client
diff --git a/tests/cefclient/browser/image_cache.h b/tests/cefclient/browser/image_cache.h
new file mode 100644
index 00000000..42146728
--- /dev/null
+++ b/tests/cefclient/browser/image_cache.h
@@ -0,0 +1,127 @@
+// Copyright (c) 2017 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_IMAGE_CACHE_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_IMAGE_CACHE_H_
+#pragma once
+
+#include <map>
+#include <vector>
+
+#include "include/base/cef_callback.h"
+#include "include/base/cef_ref_counted.h"
+#include "include/cef_image.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "include/wrapper/cef_helpers.h"
+
+namespace client {
+
+// Simple image caching implementation.
+class ImageCache
+ : public base::RefCountedThreadSafe<ImageCache, CefDeleteOnUIThread> {
+ public:
+ ImageCache();
+
+ // Image representation at a specific scale factor.
+ struct ImageRep {
+ ImageRep(const std::string& path, float scale_factor);
+
+ // Full file system path.
+ std::string path_;
+
+ // Image scale factor (usually 1.0f or 2.0f).
+ float scale_factor_;
+ };
+ using ImageRepSet = std::vector<ImageRep>;
+
+ // Unique image that may have multiple representations.
+ struct ImageInfo {
+ ImageInfo(const std::string& id,
+ const ImageRepSet& reps,
+ bool internal,
+ bool force_reload);
+
+ // Helper for returning an empty image.
+ static ImageInfo Empty();
+
+ // Helpers for creating common representations.
+ static ImageInfo Create1x(const std::string& id,
+ const std::string& path_1x,
+ bool internal);
+ static ImageInfo Create2x(const std::string& id,
+ const std::string& path_1x,
+ const std::string& path_2x,
+ bool internal);
+ static ImageInfo Create2x(const std::string& id);
+
+ // Image unique ID.
+ std::string id_;
+
+ // Image representations to load.
+ ImageRepSet reps_;
+
+ // True if the image is internal (loaded via LoadBinaryResource).
+ bool internal_;
+
+ // True to force reload.
+ bool force_reload_;
+ };
+ using ImageInfoSet = std::vector<ImageInfo>;
+
+ using ImageSet = std::vector<CefRefPtr<CefImage>>;
+
+ using LoadImagesCallback =
+ base::OnceCallback<void(const ImageSet& /*images*/)>;
+
+ // Loads the images represented by |image_info|. Executes |callback|
+ // either synchronously or asychronously on the UI thread after completion.
+ void LoadImages(const ImageInfoSet& image_info, LoadImagesCallback callback);
+
+ // Returns an image that has already been cached. Must be called on the
+ // UI thread.
+ CefRefPtr<CefImage> GetCachedImage(const std::string& image_id);
+
+ private:
+ // Only allow deletion via scoped_refptr.
+ friend struct CefDeleteOnThread<TID_UI>;
+ friend class base::RefCountedThreadSafe<ImageCache, CefDeleteOnUIThread>;
+
+ ~ImageCache();
+
+ enum ImageType {
+ TYPE_NONE,
+ TYPE_PNG,
+ TYPE_JPEG,
+ };
+
+ static ImageType GetImageType(const std::string& path);
+
+ struct ImageContent;
+ using ImageContentSet = std::vector<ImageContent>;
+
+ // Load missing image contents on the FILE thread.
+ void LoadMissing(const ImageInfoSet& image_info,
+ const ImageSet& images,
+ LoadImagesCallback callback);
+ static bool LoadImageContents(const ImageInfo& info, ImageContent* content);
+ static bool LoadImageContents(const std::string& path,
+ bool internal,
+ ImageType* type,
+ std::string* contents);
+
+ // Create missing CefImage representations on the UI thread.
+ void UpdateCache(const ImageInfoSet& image_info,
+ const ImageContentSet& contents,
+ LoadImagesCallback callback);
+ static CefRefPtr<CefImage> CreateImage(const std::string& image_id,
+ const ImageContent& content);
+
+ // Map image ID to image representation. Only accessed on the UI thread.
+ using ImageMap = std::map<std::string, CefRefPtr<CefImage>>;
+ ImageMap image_map_;
+};
+
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_IMAGE_CACHE_H_
diff --git a/tests/cefclient/browser/main_context.cc b/tests/cefclient/browser/main_context.cc
new file mode 100644
index 00000000..11c455c6
--- /dev/null
+++ b/tests/cefclient/browser/main_context.cc
@@ -0,0 +1,32 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/main_context.h"
+
+#include "include/base/cef_logging.h"
+
+namespace client {
+
+namespace {
+
+MainContext* g_main_context = nullptr;
+
+} // namespace
+
+// static
+MainContext* MainContext::Get() {
+ DCHECK(g_main_context);
+ return g_main_context;
+}
+
+MainContext::MainContext() {
+ DCHECK(!g_main_context);
+ g_main_context = this;
+}
+
+MainContext::~MainContext() {
+ g_main_context = nullptr;
+}
+
+} // namespace client
diff --git a/tests/cefclient/browser/main_context.h b/tests/cefclient/browser/main_context.h
new file mode 100644
index 00000000..67d3e357
--- /dev/null
+++ b/tests/cefclient/browser/main_context.h
@@ -0,0 +1,75 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_MAIN_CONTEXT_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_MAIN_CONTEXT_H_
+#pragma once
+
+#include <string>
+
+#include "include/base/cef_macros.h"
+#include "include/base/cef_ref_counted.h"
+#include "include/internal/cef_types_wrappers.h"
+#include "tests/cefclient/browser/osr_renderer_settings.h"
+
+namespace client {
+
+class RootWindowManager;
+
+// Used to store global context in the browser process. The methods of this
+// class are thread-safe unless otherwise indicated.
+class MainContext {
+ public:
+ // Returns the singleton instance of this object.
+ static MainContext* Get();
+
+ // Returns the full path to the console log file.
+ virtual std::string GetConsoleLogPath() = 0;
+
+ // Returns the full path to |file_name|.
+ virtual std::string GetDownloadPath(const std::string& file_name) = 0;
+
+ // Returns the app working directory including trailing path separator.
+ virtual std::string GetAppWorkingDirectory() = 0;
+
+ // Returns the main application URL.
+ virtual std::string GetMainURL() = 0;
+
+ // Returns the background color.
+ virtual cef_color_t GetBackgroundColor() = 0;
+
+ // Returns true if the Chrome runtime will be used.
+ virtual bool UseChromeRuntime() = 0;
+
+ // Returns true if the Views framework will be used.
+ virtual bool UseViews() = 0;
+
+ // Returns true if windowless (off-screen) rendering will be used.
+ virtual bool UseWindowlessRendering() = 0;
+
+ // Returns true if touch events are enabled.
+ virtual bool TouchEventsEnabled() = 0;
+
+ // Returns true if the default popup implementation should be used.
+ virtual bool UseDefaultPopup() = 0;
+
+ // Populate |settings| based on command-line arguments.
+ virtual void PopulateSettings(CefSettings* settings) = 0;
+ virtual void PopulateBrowserSettings(CefBrowserSettings* settings) = 0;
+ virtual void PopulateOsrSettings(OsrRendererSettings* settings) = 0;
+
+ // Returns the object used to create/manage RootWindow instances.
+ virtual RootWindowManager* GetRootWindowManager() = 0;
+
+ protected:
+ MainContext();
+ virtual ~MainContext();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MainContext);
+};
+
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_MAIN_CONTEXT_H_
diff --git a/tests/cefclient/browser/main_context_impl.cc b/tests/cefclient/browser/main_context_impl.cc
new file mode 100644
index 00000000..46d2db94
--- /dev/null
+++ b/tests/cefclient/browser/main_context_impl.cc
@@ -0,0 +1,282 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/main_context_impl.h"
+
+#include <algorithm>
+
+#include "include/cef_parser.h"
+#include "tests/shared/browser/client_app_browser.h"
+#include "tests/shared/common/client_switches.h"
+#include "tests/shared/common/string_util.h"
+
+namespace client {
+
+namespace {
+
+// The default URL to load in a browser window.
+const char kDefaultUrl[] = "https://www.google.com";
+
+// Returns the ARGB value for |color|.
+cef_color_t ParseColor(const std::string& color) {
+ const std::string& colorToLower = AsciiStrToLower(color);
+ if (colorToLower == "black") {
+ return CefColorSetARGB(255, 0, 0, 0);
+ } else if (colorToLower == "blue") {
+ return CefColorSetARGB(255, 0, 0, 255);
+ } else if (colorToLower == "green") {
+ return CefColorSetARGB(255, 0, 255, 0);
+ } else if (colorToLower == "red") {
+ return CefColorSetARGB(255, 255, 0, 0);
+ } else if (colorToLower == "white") {
+ return CefColorSetARGB(255, 255, 255, 255);
+ }
+
+ // Use the default color.
+ return 0;
+}
+
+} // namespace
+
+MainContextImpl::MainContextImpl(CefRefPtr<CefCommandLine> command_line,
+ bool terminate_when_all_windows_closed)
+ : command_line_(command_line),
+ terminate_when_all_windows_closed_(terminate_when_all_windows_closed) {
+ DCHECK(command_line_.get());
+
+ // Set the main URL.
+ if (command_line_->HasSwitch(switches::kUrl)) {
+ main_url_ = command_line_->GetSwitchValue(switches::kUrl);
+ }
+ if (main_url_.empty()) {
+ main_url_ = kDefaultUrl;
+ }
+
+ // Whether windowless (off-screen) rendering will be used.
+ use_windowless_rendering_ =
+ command_line_->HasSwitch(switches::kOffScreenRenderingEnabled);
+
+ if (use_windowless_rendering_ &&
+ command_line_->HasSwitch(switches::kOffScreenFrameRate)) {
+ windowless_frame_rate_ =
+ atoi(command_line_->GetSwitchValue(switches::kOffScreenFrameRate)
+ .ToString()
+ .c_str());
+ }
+
+ // Whether transparent painting is used with windowless rendering.
+ const bool use_transparent_painting =
+ use_windowless_rendering_ &&
+ command_line_->HasSwitch(switches::kTransparentPaintingEnabled);
+
+#if defined(OS_WIN)
+ // Shared texture is only supported on Windows.
+ shared_texture_enabled_ =
+ use_windowless_rendering_ &&
+ command_line_->HasSwitch(switches::kSharedTextureEnabled);
+#endif
+
+ external_begin_frame_enabled_ =
+ use_windowless_rendering_ &&
+ command_line_->HasSwitch(switches::kExternalBeginFrameEnabled);
+
+ if (windowless_frame_rate_ <= 0) {
+// Choose a reasonable default rate based on the OSR mode.
+#if defined(OS_WIN)
+ windowless_frame_rate_ = shared_texture_enabled_ ? 60 : 30;
+#else
+ windowless_frame_rate_ = 30;
+#endif
+ }
+
+ // Enable experimental Chrome runtime. See issue #2969 for details.
+ use_chrome_runtime_ =
+ command_line_->HasSwitch(switches::kEnableChromeRuntime);
+
+ if (use_windowless_rendering_ && use_chrome_runtime_) {
+ LOG(ERROR)
+ << "Windowless rendering is not supported with the Chrome runtime.";
+ use_chrome_runtime_ = false;
+ }
+
+ // Whether the Views framework will be used.
+ use_views_ = command_line_->HasSwitch(switches::kUseViews);
+
+ if (use_windowless_rendering_ && use_views_) {
+ LOG(ERROR)
+ << "Windowless rendering is not supported by the Views framework.";
+ use_views_ = false;
+ }
+
+#if defined(OS_WIN) || defined(OS_LINUX)
+ if (use_chrome_runtime_ && !use_views_ &&
+ !command_line->HasSwitch(switches::kUseNative)) {
+ LOG(WARNING) << "Chrome runtime defaults to the Views framework.";
+ use_views_ = true;
+ }
+#else // !(defined(OS_WIN) || defined(OS_LINUX))
+ if (use_chrome_runtime_ && !use_views_) {
+ // TODO(chrome): Add support for this runtime configuration (e.g. a fully
+ // styled Chrome window with cefclient menu customizations). In the mean
+ // time this can be demo'd with "cefsimple --enable-chrome-runtime".
+ LOG(WARNING) << "Chrome runtime requires the Views framework.";
+ use_views_ = true;
+ }
+#endif // !(defined(OS_WIN) || defined(OS_LINUX))
+
+ if (use_views_ && command_line->HasSwitch(switches::kHideFrame) &&
+ !command_line_->HasSwitch(switches::kUrl)) {
+ // Use the draggable regions test as the default URL for frameless windows.
+ main_url_ = "http://tests/draggable";
+ }
+
+ if (command_line_->HasSwitch(switches::kBackgroundColor)) {
+ // Parse the background color value.
+ background_color_ =
+ ParseColor(command_line_->GetSwitchValue(switches::kBackgroundColor));
+ }
+
+ if (background_color_ == 0 && !use_views_) {
+ // Set an explicit background color.
+ background_color_ = CefColorSetARGB(255, 255, 255, 255);
+ }
+
+ // |browser_background_color_| should remain 0 to enable transparent painting.
+ if (!use_transparent_painting) {
+ browser_background_color_ = background_color_;
+ }
+}
+
+MainContextImpl::~MainContextImpl() {
+ // The context must either not have been initialized, or it must have also
+ // been shut down.
+ DCHECK(!initialized_ || shutdown_);
+}
+
+std::string MainContextImpl::GetConsoleLogPath() {
+ return GetAppWorkingDirectory() + "console.log";
+}
+
+std::string MainContextImpl::GetMainURL() {
+ return main_url_;
+}
+
+cef_color_t MainContextImpl::GetBackgroundColor() {
+ return background_color_;
+}
+
+bool MainContextImpl::UseChromeRuntime() {
+ return use_chrome_runtime_;
+}
+
+bool MainContextImpl::UseViews() {
+ return use_views_;
+}
+
+bool MainContextImpl::UseWindowlessRendering() {
+ return use_windowless_rendering_;
+}
+
+bool MainContextImpl::TouchEventsEnabled() {
+ return command_line_->GetSwitchValue("touch-events") == "enabled";
+}
+
+bool MainContextImpl::UseDefaultPopup() {
+ return !use_windowless_rendering_ &&
+ command_line_->HasSwitch(switches::kUseDefaultPopup);
+}
+
+void MainContextImpl::PopulateSettings(CefSettings* settings) {
+ client::ClientAppBrowser::PopulateSettings(command_line_, *settings);
+
+ if (use_chrome_runtime_) {
+ settings->chrome_runtime = true;
+ }
+
+ CefString(&settings->cache_path) =
+ command_line_->GetSwitchValue(switches::kCachePath);
+
+ if (use_windowless_rendering_) {
+ settings->windowless_rendering_enabled = true;
+ }
+
+ if (browser_background_color_ != 0) {
+ settings->background_color = browser_background_color_;
+ }
+
+ if (command_line_->HasSwitch("lang")) {
+ // Use the same locale for the Accept-Language HTTP request header.
+ CefString(&settings->accept_language_list) =
+ command_line_->GetSwitchValue("lang");
+ }
+}
+
+void MainContextImpl::PopulateBrowserSettings(CefBrowserSettings* settings) {
+ settings->windowless_frame_rate = windowless_frame_rate_;
+
+ if (browser_background_color_ != 0) {
+ settings->background_color = browser_background_color_;
+ }
+
+ if (use_chrome_runtime_ &&
+ command_line_->HasSwitch(switches::kHideChromeStatusBubble)) {
+ settings->chrome_status_bubble = STATE_DISABLED;
+ }
+}
+
+void MainContextImpl::PopulateOsrSettings(OsrRendererSettings* settings) {
+ settings->show_update_rect =
+ command_line_->HasSwitch(switches::kShowUpdateRect);
+
+#if defined(OS_WIN)
+ settings->shared_texture_enabled = shared_texture_enabled_;
+#endif
+ settings->external_begin_frame_enabled = external_begin_frame_enabled_;
+ settings->begin_frame_rate = windowless_frame_rate_;
+
+ if (browser_background_color_ != 0) {
+ settings->background_color = browser_background_color_;
+ }
+}
+
+RootWindowManager* MainContextImpl::GetRootWindowManager() {
+ DCHECK(InValidState());
+ return root_window_manager_.get();
+}
+
+bool MainContextImpl::Initialize(const CefMainArgs& args,
+ const CefSettings& settings,
+ CefRefPtr<CefApp> application,
+ void* windows_sandbox_info) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(!initialized_);
+ DCHECK(!shutdown_);
+
+ if (!CefInitialize(args, settings, application, windows_sandbox_info)) {
+ return false;
+ }
+
+ // Need to create the RootWindowManager after calling CefInitialize because
+ // TempWindowX11 uses cef_get_xdisplay().
+ root_window_manager_.reset(
+ new RootWindowManager(terminate_when_all_windows_closed_));
+
+ initialized_ = true;
+
+ return true;
+}
+
+void MainContextImpl::Shutdown() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(initialized_);
+ DCHECK(!shutdown_);
+
+ root_window_manager_.reset();
+
+ CefShutdown();
+
+ shutdown_ = true;
+}
+
+} // namespace client
diff --git a/tests/cefclient/browser/main_context_impl.h b/tests/cefclient/browser/main_context_impl.h
new file mode 100644
index 00000000..d07bc088
--- /dev/null
+++ b/tests/cefclient/browser/main_context_impl.h
@@ -0,0 +1,95 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_MAIN_CONTEXT_IMPL_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_MAIN_CONTEXT_IMPL_H_
+#pragma once
+
+#include <memory>
+
+#include "include/base/cef_thread_checker.h"
+#include "include/cef_app.h"
+#include "include/cef_command_line.h"
+#include "tests/cefclient/browser/main_context.h"
+#include "tests/cefclient/browser/root_window_manager.h"
+
+namespace client {
+
+// Used to store global context in the browser process.
+class MainContextImpl : public MainContext {
+ public:
+ MainContextImpl(CefRefPtr<CefCommandLine> command_line,
+ bool terminate_when_all_windows_closed);
+
+ // MainContext members.
+ std::string GetConsoleLogPath() override;
+ std::string GetDownloadPath(const std::string& file_name) override;
+ std::string GetAppWorkingDirectory() override;
+ std::string GetMainURL() override;
+ cef_color_t GetBackgroundColor() override;
+ bool UseChromeRuntime() override;
+ bool UseViews() override;
+ bool UseWindowlessRendering() override;
+ bool TouchEventsEnabled() override;
+ bool UseDefaultPopup() override;
+ void PopulateSettings(CefSettings* settings) override;
+ void PopulateBrowserSettings(CefBrowserSettings* settings) override;
+ void PopulateOsrSettings(OsrRendererSettings* settings) override;
+ RootWindowManager* GetRootWindowManager() override;
+
+ // Initialize CEF and associated main context state. This method must be
+ // called on the same thread that created this object.
+ bool Initialize(const CefMainArgs& args,
+ const CefSettings& settings,
+ CefRefPtr<CefApp> application,
+ void* windows_sandbox_info);
+
+ // Shut down CEF and associated context state. This method must be called on
+ // the same thread that created this object.
+ void Shutdown();
+
+ private:
+ // Allow deletion via std::unique_ptr only.
+ friend std::default_delete<MainContextImpl>;
+
+ ~MainContextImpl();
+
+ // Returns true if the context is in a valid state (initialized and not yet
+ // shut down).
+ bool InValidState() const { return initialized_ && !shutdown_; }
+
+ CefRefPtr<CefCommandLine> command_line_;
+ const bool terminate_when_all_windows_closed_;
+
+ // Track context state. Accessing these variables from multiple threads is
+ // safe because only a single thread will exist at the time that they're set
+ // (during context initialization and shutdown).
+ bool initialized_ = false;
+ bool shutdown_ = false;
+
+ std::string main_url_;
+ cef_color_t background_color_ = 0;
+ cef_color_t browser_background_color_ = 0;
+ bool use_windowless_rendering_;
+ int windowless_frame_rate_ = 0;
+ bool use_chrome_runtime_;
+ bool use_views_;
+
+ std::unique_ptr<RootWindowManager> root_window_manager_;
+
+#if defined(OS_WIN)
+ bool shared_texture_enabled_;
+#endif
+
+ bool external_begin_frame_enabled_;
+
+ // Used to verify that methods are called on the correct thread.
+ base::ThreadChecker thread_checker_;
+
+ DISALLOW_COPY_AND_ASSIGN(MainContextImpl);
+};
+
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_MAIN_CONTEXT_IMPL_H_
diff --git a/tests/cefclient/browser/main_context_impl_posix.cc b/tests/cefclient/browser/main_context_impl_posix.cc
new file mode 100644
index 00000000..8a13b330
--- /dev/null
+++ b/tests/cefclient/browser/main_context_impl_posix.cc
@@ -0,0 +1,28 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/main_context_impl.h"
+
+#include <unistd.h>
+
+namespace client {
+
+std::string MainContextImpl::GetDownloadPath(const std::string& file_name) {
+ return std::string();
+}
+
+std::string MainContextImpl::GetAppWorkingDirectory() {
+ char szWorkingDir[256];
+ if (getcwd(szWorkingDir, sizeof(szWorkingDir) - 1) == nullptr) {
+ szWorkingDir[0] = 0;
+ } else {
+ // Add trailing path separator.
+ size_t len = strlen(szWorkingDir);
+ szWorkingDir[len] = '/';
+ szWorkingDir[len + 1] = 0;
+ }
+ return szWorkingDir;
+}
+
+} // namespace client
diff --git a/tests/cefclient/browser/main_context_impl_win.cc b/tests/cefclient/browser/main_context_impl_win.cc
new file mode 100644
index 00000000..d85c6e9a
--- /dev/null
+++ b/tests/cefclient/browser/main_context_impl_win.cc
@@ -0,0 +1,39 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/main_context_impl.h"
+
+#include <direct.h>
+#include <shlobj.h>
+
+namespace client {
+
+std::string MainContextImpl::GetDownloadPath(const std::string& file_name) {
+ TCHAR szFolderPath[MAX_PATH];
+ std::string path;
+
+ // Save the file in the user's "My Documents" folder.
+ if (SUCCEEDED(SHGetFolderPath(nullptr, CSIDL_PERSONAL | CSIDL_FLAG_CREATE,
+ nullptr, 0, szFolderPath))) {
+ path = CefString(szFolderPath);
+ path += "\\" + file_name;
+ }
+
+ return path;
+}
+
+std::string MainContextImpl::GetAppWorkingDirectory() {
+ char szWorkingDir[MAX_PATH + 1];
+ if (_getcwd(szWorkingDir, MAX_PATH) == nullptr) {
+ szWorkingDir[0] = 0;
+ } else {
+ // Add trailing path separator.
+ size_t len = strlen(szWorkingDir);
+ szWorkingDir[len] = '\\';
+ szWorkingDir[len + 1] = 0;
+ }
+ return szWorkingDir;
+}
+
+} // namespace client
diff --git a/tests/cefclient/browser/main_message_loop_multithreaded_gtk.cc b/tests/cefclient/browser/main_message_loop_multithreaded_gtk.cc
new file mode 100644
index 00000000..736a106d
--- /dev/null
+++ b/tests/cefclient/browser/main_message_loop_multithreaded_gtk.cc
@@ -0,0 +1,152 @@
+// Copyright (c) 2018 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/main_message_loop_multithreaded_gtk.h"
+
+#include <X11/Xlib.h>
+#include <gtk/gtk.h>
+
+#include "include/base/cef_callback.h"
+#include "include/base/cef_logging.h"
+#include "include/wrapper/cef_closure_task.h"
+
+namespace client {
+
+namespace {
+
+base::Lock g_global_lock;
+base::PlatformThreadId g_global_lock_thread = kInvalidPlatformThreadId;
+
+void lock_enter() {
+ // The GDK lock is not reentrant, so check that we're using it correctly.
+ // See comments on ScopedGdkThreadsEnter.
+ base::PlatformThreadId current_thread = base::PlatformThread::CurrentId();
+ CHECK(current_thread != g_global_lock_thread);
+
+ g_global_lock.Acquire();
+ g_global_lock_thread = current_thread;
+}
+
+void lock_leave() {
+ g_global_lock_thread = kInvalidPlatformThreadId;
+ g_global_lock.Release();
+}
+
+// Same as g_idle_add() but specifying the GMainContext.
+guint idle_add(GMainContext* main_context,
+ GSourceFunc function,
+ gpointer data) {
+ GSource* source = g_idle_source_new();
+ g_source_set_callback(source, function, data, nullptr);
+ guint id = g_source_attach(source, main_context);
+ g_source_unref(source);
+ return id;
+}
+
+// Same as g_timeout_add() but specifying the GMainContext.
+guint timeout_add(GMainContext* main_context,
+ guint interval,
+ GSourceFunc function,
+ gpointer data) {
+ GSource* source = g_timeout_source_new(interval);
+ g_source_set_callback(source, function, data, nullptr);
+ guint id = g_source_attach(source, main_context);
+ g_source_unref(source);
+ return id;
+}
+
+} // namespace
+
+MainMessageLoopMultithreadedGtk::MainMessageLoopMultithreadedGtk()
+ : thread_id_(base::PlatformThread::CurrentId()) {
+ // Initialize Xlib support for concurrent threads. This function must be the
+ // first Xlib function a multi-threaded program calls, and it must complete
+ // before any other Xlib call is made.
+ CHECK(XInitThreads() != 0);
+
+ // Initialize GDK thread support. See comments on ScopedGdkThreadsEnter.
+ gdk_threads_set_lock_functions(lock_enter, lock_leave);
+ gdk_threads_init();
+}
+
+MainMessageLoopMultithreadedGtk::~MainMessageLoopMultithreadedGtk() {
+ DCHECK(RunsTasksOnCurrentThread());
+ DCHECK(queued_tasks_.empty());
+}
+
+int MainMessageLoopMultithreadedGtk::Run() {
+ DCHECK(RunsTasksOnCurrentThread());
+
+ // We use the default Glib context and Chromium creates its own context in
+ // MessagePumpGlib (starting in M86).
+ main_context_ = g_main_context_default();
+
+ main_loop_ = g_main_loop_new(main_context_, TRUE);
+
+ // Check the queue when GTK is idle, or at least every 100ms.
+ // TODO(cef): It might be more efficient to use input functions
+ // (gdk_input_add) and trigger by writing to an fd.
+ idle_add(main_context_, MainMessageLoopMultithreadedGtk::TriggerRunTasks,
+ this);
+ timeout_add(main_context_, 100,
+ MainMessageLoopMultithreadedGtk::TriggerRunTasks, this);
+
+ // Block until g_main_loop_quit().
+ g_main_loop_run(main_loop_);
+
+ // Release GLib resources.
+ g_main_loop_unref(main_loop_);
+ main_loop_ = nullptr;
+
+ main_context_ = nullptr;
+
+ return 0;
+}
+
+void MainMessageLoopMultithreadedGtk::Quit() {
+ PostTask(CefCreateClosureTask(base::BindOnce(
+ &MainMessageLoopMultithreadedGtk::DoQuit, base::Unretained(this))));
+}
+
+void MainMessageLoopMultithreadedGtk::PostTask(CefRefPtr<CefTask> task) {
+ base::AutoLock lock_scope(lock_);
+
+ // Queue the task.
+ queued_tasks_.push(task);
+}
+
+bool MainMessageLoopMultithreadedGtk::RunsTasksOnCurrentThread() const {
+ return (thread_id_ == base::PlatformThread::CurrentId());
+}
+
+// static
+int MainMessageLoopMultithreadedGtk::TriggerRunTasks(void* self) {
+ static_cast<MainMessageLoopMultithreadedGtk*>(self)->RunTasks();
+ return G_SOURCE_CONTINUE;
+}
+
+void MainMessageLoopMultithreadedGtk::RunTasks() {
+ DCHECK(RunsTasksOnCurrentThread());
+
+ std::queue<CefRefPtr<CefTask>> tasks;
+
+ {
+ base::AutoLock lock_scope(lock_);
+ tasks.swap(queued_tasks_);
+ }
+
+ // Execute all queued tasks.
+ while (!tasks.empty()) {
+ CefRefPtr<CefTask> task = tasks.front();
+ tasks.pop();
+ task->Execute();
+ }
+}
+
+void MainMessageLoopMultithreadedGtk::DoQuit() {
+ DCHECK(RunsTasksOnCurrentThread());
+ g_main_loop_quit(main_loop_);
+}
+
+} // namespace client
diff --git a/tests/cefclient/browser/main_message_loop_multithreaded_gtk.h b/tests/cefclient/browser/main_message_loop_multithreaded_gtk.h
new file mode 100644
index 00000000..7fbeaf89
--- /dev/null
+++ b/tests/cefclient/browser/main_message_loop_multithreaded_gtk.h
@@ -0,0 +1,54 @@
+// Copyright (c) 2018 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_MAIN_MESSAGE_LOOP_MULTITHREADED_GTK_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_MAIN_MESSAGE_LOOP_MULTITHREADED_GTK_H_
+#pragma once
+
+#include <queue>
+
+#include <gdk/gdk.h>
+
+#include "include/base/cef_lock.h"
+#include "include/base/cef_platform_thread.h"
+#include "tests/shared/browser/main_message_loop.h"
+
+namespace client {
+
+// Represents the main message loop in the browser process when using multi-
+// threaded message loop mode on Linux. In this mode there is no Chromium
+// message loop running on the main application thread. Instead, this
+// implementation utilizes a Glib context for running tasks.
+class MainMessageLoopMultithreadedGtk : public MainMessageLoop {
+ public:
+ MainMessageLoopMultithreadedGtk();
+ ~MainMessageLoopMultithreadedGtk();
+
+ // MainMessageLoop methods.
+ int Run() override;
+ void Quit() override;
+ void PostTask(CefRefPtr<CefTask> task) override;
+ bool RunsTasksOnCurrentThread() const override;
+
+ private:
+ static int TriggerRunTasks(void* self);
+ void RunTasks();
+ void DoQuit();
+
+ base::PlatformThreadId thread_id_;
+
+ GMainContext* main_context_;
+ GMainLoop* main_loop_;
+
+ base::Lock lock_;
+
+ // Must be protected by |lock_|.
+ std::queue<CefRefPtr<CefTask>> queued_tasks_;
+
+ DISALLOW_COPY_AND_ASSIGN(MainMessageLoopMultithreadedGtk);
+};
+
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_MAIN_MESSAGE_LOOP_MULTITHREADED_GTK_H_
diff --git a/tests/cefclient/browser/main_message_loop_multithreaded_win.cc b/tests/cefclient/browser/main_message_loop_multithreaded_win.cc
new file mode 100644
index 00000000..156cd3e4
--- /dev/null
+++ b/tests/cefclient/browser/main_message_loop_multithreaded_win.cc
@@ -0,0 +1,172 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/main_message_loop_multithreaded_win.h"
+
+#include "include/base/cef_callback.h"
+#include "include/base/cef_logging.h"
+#include "include/cef_app.h"
+#include "tests/cefclient/browser/resource.h"
+#include "tests/shared/browser/util_win.h"
+
+namespace client {
+
+namespace {
+
+const wchar_t kWndClass[] = L"Client_MessageWindow";
+const wchar_t kTaskMessageName[] = L"Client_CustomTask";
+
+} // namespace
+
+MainMessageLoopMultithreadedWin::MainMessageLoopMultithreadedWin()
+ : thread_id_(base::PlatformThread::CurrentId()),
+ task_message_id_(RegisterWindowMessage(kTaskMessageName)),
+ dialog_hwnd_(nullptr),
+ message_hwnd_(nullptr) {}
+
+MainMessageLoopMultithreadedWin::~MainMessageLoopMultithreadedWin() {
+ DCHECK(RunsTasksOnCurrentThread());
+ DCHECK(!message_hwnd_);
+ DCHECK(queued_tasks_.empty());
+}
+
+int MainMessageLoopMultithreadedWin::Run() {
+ DCHECK(RunsTasksOnCurrentThread());
+
+ HINSTANCE hInstance = ::GetModuleHandle(nullptr);
+
+ {
+ base::AutoLock lock_scope(lock_);
+
+ // Create the hidden window for message processing.
+ message_hwnd_ = CreateMessageWindow(hInstance);
+ CHECK(message_hwnd_);
+
+ // Store a pointer to |this| in the window's user data.
+ SetUserDataPtr(message_hwnd_, this);
+
+ // Execute any tasks that are currently queued.
+ while (!queued_tasks_.empty()) {
+ PostTaskInternal(queued_tasks_.front());
+ queued_tasks_.pop();
+ }
+ }
+
+ HACCEL hAccelTable =
+ LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_CEFCLIENT));
+
+ MSG msg;
+
+ // Run the application message loop.
+ while (GetMessage(&msg, nullptr, 0, 0)) {
+ // Allow processing of dialog messages.
+ if (dialog_hwnd_ && IsDialogMessage(dialog_hwnd_, &msg)) {
+ continue;
+ }
+
+ if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+
+ {
+ base::AutoLock lock_scope(lock_);
+
+ // Destroy the message window.
+ DestroyWindow(message_hwnd_);
+ message_hwnd_ = nullptr;
+ }
+
+ return static_cast<int>(msg.wParam);
+}
+
+void MainMessageLoopMultithreadedWin::Quit() {
+ // Execute PostQuitMessage(0) on the main thread.
+ PostClosure(base::BindOnce(::PostQuitMessage, 0));
+}
+
+void MainMessageLoopMultithreadedWin::PostTask(CefRefPtr<CefTask> task) {
+ base::AutoLock lock_scope(lock_);
+ PostTaskInternal(task);
+}
+
+bool MainMessageLoopMultithreadedWin::RunsTasksOnCurrentThread() const {
+ return (thread_id_ == base::PlatformThread::CurrentId());
+}
+
+void MainMessageLoopMultithreadedWin::SetCurrentModelessDialog(
+ HWND hWndDialog) {
+ DCHECK(RunsTasksOnCurrentThread());
+
+#if DCHECK_IS_ON()
+ if (hWndDialog) {
+ // A new dialog reference should not be set while one is currently set.
+ DCHECK(!dialog_hwnd_);
+ }
+#endif
+ dialog_hwnd_ = hWndDialog;
+}
+
+// static
+HWND MainMessageLoopMultithreadedWin::CreateMessageWindow(HINSTANCE hInstance) {
+ WNDCLASSEX wc = {0};
+ wc.cbSize = sizeof(wc);
+ wc.lpfnWndProc = MessageWndProc;
+ wc.hInstance = hInstance;
+ wc.lpszClassName = kWndClass;
+ RegisterClassEx(&wc);
+
+ return CreateWindow(kWndClass, 0, 0, 0, 0, 0, 0, HWND_MESSAGE, 0, hInstance,
+ 0);
+}
+
+// static
+LRESULT CALLBACK
+MainMessageLoopMultithreadedWin::MessageWndProc(HWND hWnd,
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam) {
+ MainMessageLoopMultithreadedWin* self =
+ GetUserDataPtr<MainMessageLoopMultithreadedWin*>(hWnd);
+
+ if (self && message == self->task_message_id_) {
+ // Execute the task.
+ CefTask* task = reinterpret_cast<CefTask*>(wParam);
+ task->Execute();
+
+ // Release the reference added in PostTaskInternal. This will likely result
+ // in |task| being deleted.
+ task->Release();
+ } else {
+ switch (message) {
+ case WM_NCDESTROY:
+ // Clear the reference to |self|.
+ SetUserDataPtr(hWnd, nullptr);
+ break;
+ }
+ }
+
+ return DefWindowProc(hWnd, message, wParam, lParam);
+}
+
+void MainMessageLoopMultithreadedWin::PostTaskInternal(
+ CefRefPtr<CefTask> task) {
+ lock_.AssertAcquired();
+
+ if (!message_hwnd_) {
+ // Queue the task until the message loop starts running.
+ queued_tasks_.push(task);
+ return;
+ }
+
+ // Add a reference that will be released in MessageWndProc.
+ task->AddRef();
+
+ // Post the task for execution by the message window.
+ PostMessage(message_hwnd_, task_message_id_,
+ reinterpret_cast<WPARAM>(task.get()), 0);
+}
+
+} // namespace client
diff --git a/tests/cefclient/browser/main_message_loop_multithreaded_win.h b/tests/cefclient/browser/main_message_loop_multithreaded_win.h
new file mode 100644
index 00000000..61151060
--- /dev/null
+++ b/tests/cefclient/browser/main_message_loop_multithreaded_win.h
@@ -0,0 +1,63 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_MAIN_MESSAGE_LOOP_MULTITHREADED_WIN_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_MAIN_MESSAGE_LOOP_MULTITHREADED_WIN_H_
+#pragma once
+
+#include <windows.h>
+#include <queue>
+
+#include "include/base/cef_lock.h"
+#include "include/base/cef_platform_thread.h"
+#include "tests/shared/browser/main_message_loop.h"
+
+namespace client {
+
+// Represents the main message loop in the browser process when using multi-
+// threaded message loop mode on Windows. In this mode there is no Chromium
+// message loop running on the main application thread. Instead, this
+// implementation utilizes a hidden message window for running tasks.
+class MainMessageLoopMultithreadedWin : public MainMessageLoop {
+ public:
+ MainMessageLoopMultithreadedWin();
+ ~MainMessageLoopMultithreadedWin();
+
+ // MainMessageLoop methods.
+ int Run() override;
+ void Quit() override;
+ void PostTask(CefRefPtr<CefTask> task) override;
+ bool RunsTasksOnCurrentThread() const override;
+ void SetCurrentModelessDialog(HWND hWndDialog) override;
+
+ private:
+ // Create the message window.
+ static HWND CreateMessageWindow(HINSTANCE hInstance);
+
+ // Window procedure for the message window.
+ static LRESULT CALLBACK MessageWndProc(HWND hWnd,
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam);
+
+ void PostTaskInternal(CefRefPtr<CefTask> task);
+
+ base::PlatformThreadId thread_id_;
+ UINT task_message_id_;
+
+ // Only accessed on the main thread.
+ HWND dialog_hwnd_;
+
+ base::Lock lock_;
+
+ // Must be protected by |lock_|.
+ HWND message_hwnd_;
+ std::queue<CefRefPtr<CefTask>> queued_tasks_;
+
+ DISALLOW_COPY_AND_ASSIGN(MainMessageLoopMultithreadedWin);
+};
+
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_MAIN_MESSAGE_LOOP_MULTITHREADED_WIN_H_
diff --git a/tests/cefclient/browser/media_router_test.cc b/tests/cefclient/browser/media_router_test.cc
new file mode 100644
index 00000000..94b39441
--- /dev/null
+++ b/tests/cefclient/browser/media_router_test.cc
@@ -0,0 +1,602 @@
+// Copyright (c) 2020 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/media_router_test.h"
+
+#include <string>
+#include <vector>
+
+#include "include/base/cef_logging.h"
+#include "include/cef_media_router.h"
+#include "include/cef_parser.h"
+#include "tests/cefclient/browser/test_runner.h"
+
+namespace client {
+namespace media_router_test {
+
+namespace {
+
+const char kTestUrlPath[] = "/media_router";
+
+// Application-specific error codes.
+const int kMessageFormatError = 1;
+const int kRequestFailedError = 2;
+
+// Message strings.
+const char kNameKey[] = "name";
+const char kNameValueSubscribe[] = "subscribe";
+const char kNameValueCreateRoute[] = "createRoute";
+const char kNameValueTerminateRoute[] = "terminateRoute";
+const char kNameValueSendMessage[] = "sendMessage";
+const char kSourceKey[] = "source_urn";
+const char kSinkKey[] = "sink_id";
+const char kRouteKey[] = "route_id";
+const char kMessageKey[] = "message";
+const char kSuccessKey[] = "success";
+const char kPayloadKey[] = "payload";
+
+// Convert a dictionary value to a JSON string.
+CefString GetJSON(CefRefPtr<CefDictionaryValue> dictionary) {
+ CefRefPtr<CefValue> value = CefValue::Create();
+ value->SetDictionary(dictionary);
+ return CefWriteJSON(value, JSON_WRITER_DEFAULT);
+}
+
+typedef CefMessageRouterBrowserSide::Callback CallbackType;
+
+void SendSuccess(CefRefPtr<CallbackType> callback,
+ CefRefPtr<CefDictionaryValue> result) {
+ callback->Success(GetJSON(result));
+}
+
+void SendFailure(CefRefPtr<CallbackType> callback,
+ int error_code,
+ const std::string& error_message) {
+ callback->Failure(error_code, error_message);
+}
+
+// Callback for CefMediaRouter::CreateRoute.
+class MediaRouteCreateCallback : public CefMediaRouteCreateCallback {
+ public:
+ explicit MediaRouteCreateCallback(CefRefPtr<CallbackType> create_callback)
+ : create_callback_(create_callback) {}
+
+ // CefMediaRouteCreateCallback method:
+ void OnMediaRouteCreateFinished(RouteCreateResult result,
+ const CefString& error,
+ CefRefPtr<CefMediaRoute> route) override {
+ CEF_REQUIRE_UI_THREAD();
+ if (result == CEF_MRCR_OK) {
+ CefRefPtr<CefDictionaryValue> dict = CefDictionaryValue::Create();
+ dict->SetString(kRouteKey, route->GetId());
+ SendSuccess(create_callback_, dict);
+ } else {
+ SendFailure(create_callback_, kRequestFailedError + result, error);
+ }
+ create_callback_ = nullptr;
+ }
+
+ private:
+ CefRefPtr<CallbackType> create_callback_;
+
+ IMPLEMENT_REFCOUNTING(MediaRouteCreateCallback);
+ DISALLOW_COPY_AND_ASSIGN(MediaRouteCreateCallback);
+};
+
+// Observes MediaRouter events. Only accessed on the UI thread.
+class MediaObserver : public CefMediaObserver {
+ public:
+ typedef std::vector<CefRefPtr<CefMediaRoute>> MediaRouteVector;
+ typedef std::vector<CefRefPtr<CefMediaSink>> MediaSinkVector;
+
+ MediaObserver(CefRefPtr<CefMediaRouter> media_router,
+ CefRefPtr<CallbackType> subscription_callback)
+ : media_router_(media_router),
+ subscription_callback_(subscription_callback),
+ next_sink_query_id_(0),
+ pending_sink_query_id_(-1),
+ pending_sink_callbacks_(0U) {}
+
+ ~MediaObserver() override { ClearSinkInfoMap(); }
+
+ bool CreateRoute(const std::string& source_urn,
+ const std::string& sink_id,
+ CefRefPtr<CallbackType> callback,
+ std::string& error) {
+ CefRefPtr<CefMediaSource> source = GetSource(source_urn);
+ if (!source) {
+ error = "Invalid source: " + source_urn;
+ return false;
+ }
+
+ CefRefPtr<CefMediaSink> sink = GetSink(sink_id);
+ if (!sink) {
+ error = "Invalid sink: " + sink_id;
+ return false;
+ }
+
+ media_router_->CreateRoute(source, sink,
+ new MediaRouteCreateCallback(callback));
+ return true;
+ }
+
+ bool TerminateRoute(const std::string& route_id, std::string& error) {
+ CefRefPtr<CefMediaRoute> route = GetRoute(route_id);
+ if (!route) {
+ error = "Invalid route: " + route_id;
+ return false;
+ }
+
+ route->Terminate();
+ return true;
+ }
+
+ bool SendRouteMessage(const std::string& route_id,
+ const std::string& message,
+ std::string& error) {
+ CefRefPtr<CefMediaRoute> route = GetRoute(route_id);
+ if (!route) {
+ error = "Invalid route: " + route_id;
+ return false;
+ }
+
+ route->SendRouteMessage(message.c_str(), message.size());
+ return true;
+ }
+
+ protected:
+ class DeviceInfoCallback : public CefMediaSinkDeviceInfoCallback {
+ public:
+ // Callback to be executed when the device info is available.
+ using CallbackType =
+ base::OnceCallback<void(const std::string& sink_id,
+ const CefMediaSinkDeviceInfo& device_info)>;
+
+ DeviceInfoCallback(const std::string& sink_id, CallbackType callback)
+ : sink_id_(sink_id), callback_(std::move(callback)) {}
+
+ void OnMediaSinkDeviceInfo(
+ const CefMediaSinkDeviceInfo& device_info) override {
+ CEF_REQUIRE_UI_THREAD();
+ std::move(callback_).Run(sink_id_, device_info);
+ }
+
+ private:
+ const std::string sink_id_;
+ CallbackType callback_;
+
+ IMPLEMENT_REFCOUNTING(DeviceInfoCallback);
+ DISALLOW_COPY_AND_ASSIGN(DeviceInfoCallback);
+ };
+
+ // CefMediaObserver methods:
+ void OnSinks(const MediaSinkVector& sinks) override {
+ CEF_REQUIRE_UI_THREAD();
+
+ ClearSinkInfoMap();
+
+ // Reset pending sink state.
+ pending_sink_callbacks_ = sinks.size();
+ pending_sink_query_id_ = ++next_sink_query_id_;
+
+ if (sinks.empty()) {
+ // No sinks, send the response immediately.
+ SendSinksResponse();
+ return;
+ }
+
+ MediaSinkVector::const_iterator it = sinks.begin();
+ for (size_t idx = 0; it != sinks.end(); ++it, ++idx) {
+ CefRefPtr<CefMediaSink> sink = *it;
+ const std::string& sink_id = sink->GetId();
+ SinkInfo* info = new SinkInfo;
+ info->sink = sink;
+ sink_info_map_.insert(std::make_pair(sink_id, info));
+
+ // Request the device info asynchronously. Send the response once all
+ // callbacks have executed.
+ auto callback = base::BindOnce(&MediaObserver::OnSinkDeviceInfo, this,
+ pending_sink_query_id_);
+ sink->GetDeviceInfo(new DeviceInfoCallback(sink_id, std::move(callback)));
+ }
+ }
+
+ void OnRoutes(const MediaRouteVector& routes) override {
+ CEF_REQUIRE_UI_THREAD();
+
+ route_map_.clear();
+
+ CefRefPtr<CefDictionaryValue> payload = CefDictionaryValue::Create();
+ CefRefPtr<CefListValue> routes_list = CefListValue::Create();
+ routes_list->SetSize(routes.size());
+
+ MediaRouteVector::const_iterator it = routes.begin();
+ for (size_t idx = 0; it != routes.end(); ++it, ++idx) {
+ CefRefPtr<CefMediaRoute> route = *it;
+ const std::string& route_id = route->GetId();
+ route_map_.insert(std::make_pair(route_id, route));
+
+ CefRefPtr<CefDictionaryValue> route_dict = CefDictionaryValue::Create();
+ route_dict->SetString("id", route_id);
+ route_dict->SetString(kSourceKey, route->GetSource()->GetId());
+ route_dict->SetString(kSinkKey, route->GetSink()->GetId());
+ routes_list->SetDictionary(idx, route_dict);
+ }
+
+ payload->SetList("routes_list", routes_list);
+ SendResponse("onRoutes", payload);
+ }
+
+ void OnRouteStateChanged(CefRefPtr<CefMediaRoute> route,
+ ConnectionState state) override {
+ CEF_REQUIRE_UI_THREAD();
+
+ CefRefPtr<CefDictionaryValue> payload = CefDictionaryValue::Create();
+ payload->SetString(kRouteKey, route->GetId());
+ payload->SetInt("connection_state", state);
+ SendResponse("onRouteStateChanged", payload);
+ }
+
+ void OnRouteMessageReceived(CefRefPtr<CefMediaRoute> route,
+ const void* message,
+ size_t message_size) override {
+ CEF_REQUIRE_UI_THREAD();
+
+ std::string message_str(static_cast<const char*>(message), message_size);
+
+ CefRefPtr<CefDictionaryValue> payload = CefDictionaryValue::Create();
+ payload->SetString(kRouteKey, route->GetId());
+ payload->SetString(kMessageKey, message_str);
+ SendResponse("onRouteMessageReceived", payload);
+ }
+
+ private:
+ CefRefPtr<CefMediaSource> GetSource(const std::string& source_urn) {
+ CefRefPtr<CefMediaSource> source = media_router_->GetSource(source_urn);
+ if (!source) {
+ return nullptr;
+ }
+ return source;
+ }
+
+ CefRefPtr<CefMediaSink> GetSink(const std::string& sink_id) {
+ SinkInfoMap::const_iterator it = sink_info_map_.find(sink_id);
+ if (it != sink_info_map_.end()) {
+ return it->second->sink;
+ }
+ return nullptr;
+ }
+
+ void ClearSinkInfoMap() {
+ SinkInfoMap::const_iterator it = sink_info_map_.begin();
+ for (; it != sink_info_map_.end(); ++it) {
+ delete it->second;
+ }
+ sink_info_map_.clear();
+ }
+
+ void OnSinkDeviceInfo(int sink_query_id,
+ const std::string& sink_id,
+ const CefMediaSinkDeviceInfo& device_info) {
+ // Discard callbacks that arrive after a new call to OnSinks().
+ if (sink_query_id != pending_sink_query_id_) {
+ return;
+ }
+
+ SinkInfoMap::const_iterator it = sink_info_map_.find(sink_id);
+ if (it != sink_info_map_.end()) {
+ it->second->device_info = device_info;
+ }
+
+ // Send the response once we've received all expected callbacks.
+ DCHECK_GT(pending_sink_callbacks_, 0U);
+ if (--pending_sink_callbacks_ == 0U) {
+ SendSinksResponse();
+ }
+ }
+
+ CefRefPtr<CefMediaRoute> GetRoute(const std::string& route_id) {
+ RouteMap::const_iterator it = route_map_.find(route_id);
+ if (it != route_map_.end()) {
+ return it->second;
+ }
+ return nullptr;
+ }
+
+ void SendResponse(const std::string& name,
+ CefRefPtr<CefDictionaryValue> payload) {
+ CefRefPtr<CefDictionaryValue> result = CefDictionaryValue::Create();
+ result->SetString(kNameKey, name);
+ result->SetDictionary(kPayloadKey, payload);
+ SendSuccess(subscription_callback_, result);
+ }
+
+ void SendSinksResponse() {
+ CefRefPtr<CefDictionaryValue> payload = CefDictionaryValue::Create();
+ CefRefPtr<CefListValue> sinks_list = CefListValue::Create();
+ sinks_list->SetSize(sink_info_map_.size());
+
+ SinkInfoMap::const_iterator it = sink_info_map_.begin();
+ for (size_t idx = 0; it != sink_info_map_.end(); ++it, ++idx) {
+ const SinkInfo* info = it->second;
+
+ CefRefPtr<CefDictionaryValue> sink_dict = CefDictionaryValue::Create();
+ sink_dict->SetString("id", it->first);
+ sink_dict->SetString("name", info->sink->GetName());
+ sink_dict->SetInt("icon", info->sink->GetIconType());
+ sink_dict->SetString("ip_address",
+ CefString(&info->device_info.ip_address));
+ sink_dict->SetInt("port", info->device_info.port);
+ sink_dict->SetString("model_name",
+ CefString(&info->device_info.model_name));
+ sink_dict->SetString("type", info->sink->IsCastSink() ? "cast"
+ : info->sink->IsDialSink() ? "dial"
+ : "unknown");
+ sinks_list->SetDictionary(idx, sink_dict);
+ }
+
+ payload->SetList("sinks_list", sinks_list);
+ SendResponse("onSinks", payload);
+ }
+
+ CefRefPtr<CefMediaRouter> media_router_;
+ CefRefPtr<CallbackType> subscription_callback_;
+
+ struct SinkInfo {
+ CefRefPtr<CefMediaSink> sink;
+ CefMediaSinkDeviceInfo device_info;
+ };
+ typedef std::map<std::string, SinkInfo*> SinkInfoMap;
+
+ // Used to uniquely identify a call to OnSinks(), for the purpose of
+ // associating OnMediaSinkDeviceInfo() callbacks.
+ int next_sink_query_id_;
+
+ // State from the most recent call to OnSinks().
+ SinkInfoMap sink_info_map_;
+ int pending_sink_query_id_;
+ size_t pending_sink_callbacks_;
+
+ // State from the most recent call to OnRoutes().
+ typedef std::map<std::string, CefRefPtr<CefMediaRoute>> RouteMap;
+ RouteMap route_map_;
+
+ IMPLEMENT_REFCOUNTING(MediaObserver);
+ DISALLOW_COPY_AND_ASSIGN(MediaObserver);
+};
+
+// Handle messages in the browser process. Only accessed on the UI thread.
+class Handler : public CefMessageRouterBrowserSide::Handler {
+ public:
+ typedef std::vector<std::string> NameVector;
+
+ Handler() { CEF_REQUIRE_UI_THREAD(); }
+
+ virtual ~Handler() {
+ SubscriptionStateMap::iterator it = subscription_state_map_.begin();
+ for (; it != subscription_state_map_.end(); ++it) {
+ delete it->second;
+ }
+ }
+
+ // Called due to cefQuery execution in media_router.html.
+ bool OnQuery(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int64 query_id,
+ const CefString& request,
+ bool persistent,
+ CefRefPtr<Callback> callback) override {
+ CEF_REQUIRE_UI_THREAD();
+
+ // Only handle messages from the test URL.
+ const std::string& url = frame->GetURL();
+ if (!test_runner::IsTestURL(url, kTestUrlPath)) {
+ return false;
+ }
+
+ // Parse |request| as a JSON dictionary.
+ CefRefPtr<CefDictionaryValue> request_dict = ParseJSON(request);
+ if (!request_dict) {
+ SendFailure(callback, kMessageFormatError, "Incorrect message format");
+ return true;
+ }
+
+ // Verify the "name" key.
+ if (!VerifyKey(request_dict, kNameKey, VTYPE_STRING, callback)) {
+ return true;
+ }
+
+ const std::string& message_name = request_dict->GetString(kNameKey);
+ if (message_name == kNameValueSubscribe) {
+ // Subscribe to notifications from the media router.
+
+ if (!persistent) {
+ SendFailure(callback, kMessageFormatError,
+ "Subscriptions must be persistent");
+ return true;
+ }
+
+ if (!CreateSubscription(browser, query_id, callback)) {
+ SendFailure(callback, kRequestFailedError,
+ "Browser is already subscribed");
+ }
+ return true;
+ }
+
+ // All other messages require a current subscription.
+ CefRefPtr<MediaObserver> media_observer =
+ GetMediaObserver(browser->GetIdentifier());
+ if (!media_observer) {
+ SendFailure(callback, kRequestFailedError,
+ "Browser is not currently subscribed");
+ }
+
+ if (message_name == kNameValueCreateRoute) {
+ // Create a new route.
+
+ // Verify the "source_urn" key.
+ if (!VerifyKey(request_dict, kSourceKey, VTYPE_STRING, callback)) {
+ return true;
+ }
+ // Verify the "sink_id" key.
+ if (!VerifyKey(request_dict, kSinkKey, VTYPE_STRING, callback)) {
+ return true;
+ }
+
+ const std::string& source_urn = request_dict->GetString(kSourceKey);
+ const std::string& sink_id = request_dict->GetString(kSinkKey);
+
+ // |callback| will be executed once the route is created.
+ std::string error;
+ if (!media_observer->CreateRoute(source_urn, sink_id, callback, error)) {
+ SendFailure(callback, kRequestFailedError, error);
+ }
+ return true;
+ } else if (message_name == kNameValueTerminateRoute) {
+ // Terminate an existing route.
+
+ // Verify the "route" key.
+ if (!VerifyKey(request_dict, kRouteKey, VTYPE_STRING, callback)) {
+ return true;
+ }
+
+ const std::string& route_id = request_dict->GetString(kRouteKey);
+ std::string error;
+ if (!media_observer->TerminateRoute(route_id, error)) {
+ SendFailure(callback, kRequestFailedError, error);
+ } else {
+ SendSuccessACK(callback);
+ }
+ return true;
+ } else if (message_name == kNameValueSendMessage) {
+ // Send a route message.
+
+ // Verify the "route_id" key.
+ if (!VerifyKey(request_dict, kRouteKey, VTYPE_STRING, callback)) {
+ return true;
+ }
+ // Verify the "message" key.
+ if (!VerifyKey(request_dict, kMessageKey, VTYPE_STRING, callback)) {
+ return true;
+ }
+
+ const std::string& route_id = request_dict->GetString(kRouteKey);
+ const std::string& message = request_dict->GetString(kMessageKey);
+ std::string error;
+ if (!media_observer->SendRouteMessage(route_id, message, error)) {
+ SendFailure(callback, kRequestFailedError, error);
+ } else {
+ SendSuccessACK(callback);
+ }
+ return true;
+ }
+
+ return false;
+ }
+
+ void OnQueryCanceled(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int64 query_id) override {
+ CEF_REQUIRE_UI_THREAD();
+ RemoveSubscription(browser->GetIdentifier(), query_id);
+ }
+
+ private:
+ static void SendSuccessACK(CefRefPtr<Callback> callback) {
+ CefRefPtr<CefDictionaryValue> result = CefDictionaryValue::Create();
+ result->SetBool(kSuccessKey, true);
+ SendSuccess(callback, result);
+ }
+
+ // Convert a JSON string to a dictionary value.
+ static CefRefPtr<CefDictionaryValue> ParseJSON(const CefString& string) {
+ CefRefPtr<CefValue> value = CefParseJSON(string, JSON_PARSER_RFC);
+ if (value.get() && value->GetType() == VTYPE_DICTIONARY) {
+ return value->GetDictionary();
+ }
+ return nullptr;
+ }
+
+ // Verify that |key| exists in |dictionary| and has type |value_type|. Fails
+ // |callback| and returns false on failure.
+ static bool VerifyKey(CefRefPtr<CefDictionaryValue> dictionary,
+ const char* key,
+ cef_value_type_t value_type,
+ CefRefPtr<Callback> callback) {
+ if (!dictionary->HasKey(key) || dictionary->GetType(key) != value_type) {
+ SendFailure(
+ callback, kMessageFormatError,
+ "Missing or incorrectly formatted message key: " + std::string(key));
+ return false;
+ }
+ return true;
+ }
+
+ // Subscription state associated with a single browser.
+ struct SubscriptionState {
+ int64 query_id;
+ CefRefPtr<MediaObserver> observer;
+ CefRefPtr<CefRegistration> registration;
+ };
+
+ bool CreateSubscription(CefRefPtr<CefBrowser> browser,
+ int64 query_id,
+ CefRefPtr<Callback> callback) {
+ const int browser_id = browser->GetIdentifier();
+ if (subscription_state_map_.find(browser_id) !=
+ subscription_state_map_.end()) {
+ // An subscription already exists for this browser.
+ return false;
+ }
+
+ CefRefPtr<CefMediaRouter> media_router =
+ browser->GetHost()->GetRequestContext()->GetMediaRouter(nullptr);
+
+ SubscriptionState* state = new SubscriptionState();
+ state->query_id = query_id;
+ state->observer = new MediaObserver(media_router, callback);
+ state->registration = media_router->AddObserver(state->observer);
+ subscription_state_map_.insert(std::make_pair(browser_id, state));
+
+ // Trigger sink and route callbacks.
+ media_router->NotifyCurrentSinks();
+ media_router->NotifyCurrentRoutes();
+
+ return true;
+ }
+
+ void RemoveSubscription(int browser_id, int64 query_id) {
+ SubscriptionStateMap::iterator it =
+ subscription_state_map_.find(browser_id);
+ if (it != subscription_state_map_.end() &&
+ it->second->query_id == query_id) {
+ delete it->second;
+ subscription_state_map_.erase(it);
+ }
+ }
+
+ CefRefPtr<MediaObserver> GetMediaObserver(int browser_id) {
+ SubscriptionStateMap::const_iterator it =
+ subscription_state_map_.find(browser_id);
+ if (it != subscription_state_map_.end()) {
+ return it->second->observer;
+ }
+ return nullptr;
+ }
+
+ // Map of browser ID to SubscriptionState object.
+ typedef std::map<int, SubscriptionState*> SubscriptionStateMap;
+ SubscriptionStateMap subscription_state_map_;
+
+ DISALLOW_COPY_AND_ASSIGN(Handler);
+};
+
+} // namespace
+
+void CreateMessageHandlers(test_runner::MessageHandlerSet& handlers) {
+ handlers.insert(new Handler());
+}
+
+} // namespace media_router_test
+} // namespace client
diff --git a/tests/cefclient/browser/media_router_test.h b/tests/cefclient/browser/media_router_test.h
new file mode 100644
index 00000000..1671ff02
--- /dev/null
+++ b/tests/cefclient/browser/media_router_test.h
@@ -0,0 +1,20 @@
+// Copyright (c) 2020 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_MEDIA_ROUTER_TEST_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_MEDIA_ROUTER_TEST_H_
+#pragma once
+
+#include "tests/cefclient/browser/test_runner.h"
+
+namespace client {
+namespace media_router_test {
+
+// Create message handlers. Called from test_runner.cc.
+void CreateMessageHandlers(test_runner::MessageHandlerSet& handlers);
+
+} // namespace media_router_test
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_MEDIA_ROUTER_TEST_H_
diff --git a/tests/cefclient/browser/osr_accessibility_helper.cc b/tests/cefclient/browser/osr_accessibility_helper.cc
new file mode 100644
index 00000000..caf3796d
--- /dev/null
+++ b/tests/cefclient/browser/osr_accessibility_helper.cc
@@ -0,0 +1,269 @@
+// Copyright 2017 The Chromium Embedded Framework Authors. Portions copyright
+// 2013 The Chromium Authors. All rights reserved. Use of this source code is
+// governed by a BSD-style license that can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/osr_accessibility_helper.h"
+#include "tests/cefclient/browser/osr_accessibility_node.h"
+
+namespace client {
+
+OsrAXTree::OsrAXTree() : root_node_id_(-1) {}
+
+OsrAXNode* OsrAXTree::GetNode(int nodeId) const {
+ auto result = node_map_.find(nodeId);
+ if (result != node_map_.end()) {
+ return result->second;
+ }
+ return nullptr;
+}
+
+void OsrAXTree::EraseNode(int nodeId) {
+ node_map_.erase(nodeId);
+}
+
+void OsrAXTree::AddNode(OsrAXNode* node) {
+ node_map_[node->OsrAXNodeId()] = node;
+}
+
+void OsrAXTree::UpdateTreeData(CefRefPtr<CefDictionaryValue> value) {
+ if (value->HasKey("parent_tree_id")) {
+ parent_tree_id_ = value->GetString("parent_tree_id");
+ } else {
+ parent_tree_id_ = "";
+ }
+
+ // may also update following:
+ // doctype, title, url, mimetype
+}
+
+OsrAccessibilityHelper::OsrAccessibilityHelper(CefRefPtr<CefValue> value,
+ CefRefPtr<CefBrowser> browser)
+ : focused_node_id_(-1), browser_(browser) {
+ UpdateAccessibilityTree(value);
+}
+
+int OsrAccessibilityHelper::CastToInt(CefRefPtr<CefValue> value) {
+ if (value->GetType() == VTYPE_STRING) {
+ const std::string& str = value->GetString();
+ return atoi(str.c_str());
+ } else {
+ return value->GetInt();
+ }
+}
+
+void OsrAccessibilityHelper::UpdateAccessibilityLocation(
+ CefRefPtr<CefValue> value) {
+ if (!value || value->GetType() != VTYPE_LIST) {
+ return;
+ }
+
+ CefRefPtr<CefListValue> locationChangeList = value->GetList();
+ size_t locationChangeCount = locationChangeList->GetSize();
+ if (locationChangeCount == 0) {
+ return;
+ }
+
+ for (size_t i = 0; i < locationChangeCount; i++) {
+ CefRefPtr<CefDictionaryValue> locationChangeDict =
+ locationChangeList->GetDictionary(i);
+ if (!locationChangeDict->HasKey("ax_tree_id") ||
+ !locationChangeDict->HasKey("new_location") ||
+ !locationChangeDict->HasKey("id")) {
+ continue;
+ }
+ CefString treeId = locationChangeDict->GetString("ax_tree_id");
+ int nodeId = CastToInt(locationChangeDict->GetValue("id"));
+
+ CefRefPtr<CefDictionaryValue> newLocationDict =
+ locationChangeDict->GetDictionary("new_location");
+ if (!newLocationDict) {
+ continue;
+ }
+
+ OsrAXNode* node = GetNode(treeId, nodeId);
+ if (!node) {
+ continue;
+ }
+ node->UpdateLocation(newLocationDict);
+ }
+}
+
+void OsrAccessibilityHelper::UpdateAccessibilityTree(
+ CefRefPtr<CefValue> value) {
+ if (!value || value->GetType() != VTYPE_DICTIONARY) {
+ return;
+ }
+
+ CefRefPtr<CefDictionaryValue> mainDict = value->GetDictionary();
+ if (!mainDict->HasKey("ax_tree_id") || !mainDict->HasKey("updates")) {
+ return;
+ }
+
+ CefString treeId = mainDict->GetString("ax_tree_id");
+ CefRefPtr<CefListValue> updatesList = mainDict->GetList("updates");
+
+ size_t updatesCount = updatesList->GetSize();
+ if (updatesCount == 0) {
+ return;
+ }
+
+ for (size_t i = 0; i < updatesCount; i++) {
+ CefRefPtr<CefDictionaryValue> updateDict = updatesList->GetDictionary(i);
+ UpdateLayout(treeId, updateDict);
+ }
+}
+
+OsrAXNode* OsrAccessibilityHelper::GetRootNode() const {
+ return GetTreeRootNode(root_tree_id_);
+}
+
+OsrAXNode* OsrAccessibilityHelper::GetFocusedNode() const {
+ auto tree = accessibility_node_map_.find(focused_tree_id_);
+ if (tree != accessibility_node_map_.end()) {
+ return tree->second.GetNode(focused_node_id_);
+ }
+
+ return nullptr;
+}
+
+OsrAXNode* OsrAccessibilityHelper::GetTreeRootNode(
+ const CefString& treeId) const {
+ auto tree = accessibility_node_map_.find(treeId);
+ if (tree != accessibility_node_map_.end()) {
+ return tree->second.GetNode(tree->second.GetRootNodeId());
+ }
+
+ return nullptr;
+}
+
+void OsrAccessibilityHelper::UpdateLayout(
+ const CefString& treeId,
+ CefRefPtr<CefDictionaryValue> update) {
+ if (!update) {
+ return;
+ }
+
+ // If a node is to be cleared
+ if (update->HasKey("node_id_to_clear")) {
+ int nodeId = CastToInt(update->GetValue("node_id_to_clear"));
+
+ // reset root node if that is to be cleared
+ auto tree = accessibility_node_map_.find(treeId);
+ if (tree != accessibility_node_map_.end()) {
+ if (tree->second.GetRootNodeId() == nodeId) {
+ root_tree_id_ = "";
+ tree->second.SetRootNodeId(-1);
+ }
+ }
+ if ((focused_tree_id_ == treeId) && (focused_node_id_ == nodeId)) {
+ UpdateFocusedNode("", -1);
+ }
+ OsrAXNode* node = GetNode(treeId, nodeId);
+ DestroyNode(node);
+ }
+
+ // get tree data
+ if (update->HasKey("tree_data") && update->HasKey("has_tree_data") &&
+ update->GetBool("has_tree_data")) {
+ CefRefPtr<CefDictionaryValue> tree_data =
+ update->GetDictionary("tree_data");
+ auto& tree = accessibility_node_map_[treeId];
+ tree.UpdateTreeData(tree_data);
+ if (tree.GetParentTreeId().empty()) {
+ root_tree_id_ = treeId;
+ }
+ if (tree_data->HasKey("focus_id") && tree_data->HasKey("focused_tree_id")) {
+ UpdateFocusedNode(tree_data->GetString("focused_tree_id"),
+ CastToInt(tree_data->GetValue("focus_id")));
+ }
+ }
+
+ // Now initialize/update the node data.
+ if (update->HasKey("nodes")) {
+ CefRefPtr<CefListValue> nodes = update->GetList("nodes");
+
+ for (size_t index = 0; index < nodes->GetSize(); index++) {
+ CefRefPtr<CefDictionaryValue> node = nodes->GetDictionary(index);
+ if (node) {
+ auto& tree = accessibility_node_map_[treeId];
+ int nodeId = CastToInt(node->GetValue("id"));
+ OsrAXNode* axNode = tree.GetNode(nodeId);
+ // Create if it is a new one
+ if (axNode) {
+ axNode->UpdateValue(node);
+ } else {
+ axNode = OsrAXNode::CreateNode(treeId, nodeId, node, this);
+ tree.AddNode(axNode);
+ }
+ }
+ }
+ }
+
+ if (update->HasKey("root_id")) {
+ int nodeId = CastToInt(update->GetValue("root_id"));
+ OsrAXNode* node = GetNode(treeId, nodeId);
+ if (node != nullptr) {
+ auto& tree = accessibility_node_map_[treeId];
+ tree.SetRootNodeId(nodeId);
+ }
+ }
+}
+
+void OsrAccessibilityHelper::UpdateFocusedNode(const CefString& treeId,
+ int nodeId) {
+ if ((focused_tree_id_ == treeId) && (focused_node_id_ == nodeId)) {
+ return;
+ }
+ focused_tree_id_ = treeId;
+ focused_node_id_ = nodeId;
+
+ // Now Notify Screen Reader
+ OsrAXNode* axNode = GetFocusedNode();
+ if (axNode) {
+ axNode->NotifyAccessibilityEvent("focus");
+ }
+}
+
+void OsrAccessibilityHelper::Reset() {
+ accessibility_node_map_.clear();
+ root_tree_id_ = "";
+ focused_tree_id_ = "";
+ focused_node_id_ = -1;
+}
+
+void OsrAccessibilityHelper::DestroyNode(OsrAXNode* node) {
+ if (node) {
+ CefString treeId = node->OsrAXTreeId();
+ int numChilds = node->GetChildCount();
+ if (numChilds > 0) {
+ for (int i = 0; i < numChilds; i++) {
+ OsrAXNode* childNode = node->ChildAtIndex(i);
+ if (!childNode) {
+ continue;
+ }
+ childNode->SetParent(nullptr);
+ if (childNode->OsrAXTreeId() == treeId) {
+ DestroyNode(childNode);
+ }
+ }
+ }
+ auto tree = accessibility_node_map_.find(treeId);
+ if (tree != accessibility_node_map_.end()) {
+ tree->second.EraseNode(node->OsrAXNodeId());
+ }
+
+ node->Destroy();
+ }
+}
+
+OsrAXNode* OsrAccessibilityHelper::GetNode(const CefString& treeId,
+ int nodeId) const {
+ auto tree = accessibility_node_map_.find(treeId);
+ if (tree != accessibility_node_map_.end()) {
+ return tree->second.GetNode(nodeId);
+ }
+
+ return nullptr;
+}
+
+} // namespace client
diff --git a/tests/cefclient/browser/osr_accessibility_helper.h b/tests/cefclient/browser/osr_accessibility_helper.h
new file mode 100644
index 00000000..83f271e4
--- /dev/null
+++ b/tests/cefclient/browser/osr_accessibility_helper.h
@@ -0,0 +1,81 @@
+// Copyright 2017 The Chromium Embedded Framework Authors. Portions copyright
+// 2013 The Chromium Authors. All rights reserved. Use of this source code is
+// governed by a BSD-style license that can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_OSR_ACCESSIBILITY_HELPER_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_OSR_ACCESSIBILITY_HELPER_H_
+
+#include <map>
+
+#include "include/cef_browser.h"
+
+namespace client {
+
+class OsrAXNode;
+class OsrAccessibilityHelper;
+
+class OsrAXTree {
+ public:
+ OsrAXTree();
+ OsrAXNode* GetNode(int nodeId) const;
+ void EraseNode(int nodeId);
+ void UpdateTreeData(CefRefPtr<CefDictionaryValue> value);
+ void AddNode(OsrAXNode* node);
+ const CefString& GetParentTreeId() const { return parent_tree_id_; }
+ int GetRootNodeId() const { return root_node_id_; }
+ void SetRootNodeId(int nodeId) { root_node_id_ = nodeId; }
+
+ private:
+ CefString parent_tree_id_;
+ int root_node_id_;
+ std::map<int, OsrAXNode*> node_map_;
+};
+
+// Helper class that abstracts Renderer Accessibility tree and provides a
+// uniform interface to be consumed by IAccessible interface on Windows and
+// NSAccessibility implementation on Mac in CefClient.
+class OsrAccessibilityHelper {
+ public:
+ OsrAccessibilityHelper(CefRefPtr<CefValue> value,
+ CefRefPtr<CefBrowser> browser);
+
+ void UpdateAccessibilityTree(CefRefPtr<CefValue> value);
+
+ void UpdateAccessibilityLocation(CefRefPtr<CefValue> value);
+
+ OsrAXNode* GetRootNode() const;
+
+ OsrAXNode* GetFocusedNode() const;
+
+ CefWindowHandle GetWindowHandle() const {
+ return browser_->GetHost()->GetWindowHandle();
+ }
+
+ CefRefPtr<CefBrowser> GetBrowser() const { return browser_; }
+
+ OsrAXNode* GetNode(const CefString& treeId, int nodeId) const;
+
+ OsrAXNode* GetTreeRootNode(const CefString& treeId) const;
+
+ static int CastToInt(CefRefPtr<CefValue> value);
+
+ private:
+ void Reset();
+
+ void UpdateLayout(const CefString& treeId,
+ CefRefPtr<CefDictionaryValue> update);
+
+ void UpdateFocusedNode(const CefString& treeId, int nodeId);
+
+ // Destroy the node and remove from Map
+ void DestroyNode(OsrAXNode* node);
+ CefString root_tree_id_;
+ CefString focused_tree_id_;
+ int focused_node_id_;
+ CefRefPtr<CefBrowser> browser_;
+ std::map<CefString, OsrAXTree> accessibility_node_map_;
+};
+
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_OSR_ACCESSIBILITY_HELPER_H_
diff --git a/tests/cefclient/browser/osr_accessibility_node.cc b/tests/cefclient/browser/osr_accessibility_node.cc
new file mode 100644
index 00000000..648d50a9
--- /dev/null
+++ b/tests/cefclient/browser/osr_accessibility_node.cc
@@ -0,0 +1,181 @@
+// Copyright 2017 The Chromium Embedded Framework Authors. Portions copyright
+// 2013 The Chromium Authors. All rights reserved. Use of this source code is
+// governed by a BSD-style license that can be found in the LICENSE file.
+
+// Base class implementation for CEF Acccessibility node. This is subclassed and
+// used by both IAccessible/NSAccessibility protocol implementation.
+
+#include "tests/cefclient/browser/osr_accessibility_node.h"
+
+#include "tests/cefclient/browser/osr_accessibility_helper.h"
+
+namespace client {
+
+OsrAXNode::OsrAXNode(const CefString& treeId,
+ int nodeId,
+ CefRefPtr<CefDictionaryValue> value,
+ OsrAccessibilityHelper* helper)
+ : tree_id_(treeId),
+ node_id_(nodeId),
+ platform_accessibility_(nullptr),
+ parent_(nullptr),
+ offset_container_id_(-1),
+ accessibility_helper_(helper) {
+ UpdateValue(value);
+}
+
+void OsrAXNode::UpdateLocation(CefRefPtr<CefDictionaryValue> value) {
+ // Update Bounds
+ if (value->HasKey("bounds")) {
+ CefRefPtr<CefDictionaryValue> loc = value->GetDictionary("bounds");
+ if (loc) {
+ location_ = CefRect(loc->GetDouble("x"), loc->GetDouble("y"),
+ loc->GetDouble("width"), loc->GetDouble("height"));
+ }
+ }
+ // Update offsets
+ if (value->HasKey("offset_container_id")) {
+ offset_container_id_ = OsrAccessibilityHelper::CastToInt(
+ value->GetValue("offset_container_id"));
+ }
+}
+
+void OsrAXNode::UpdateValue(CefRefPtr<CefDictionaryValue> value) {
+ if (value->HasKey("role")) {
+ role_ = value->GetString("role");
+ }
+
+ if (value->HasKey("child_ids")) {
+ CefRefPtr<CefListValue> childs = value->GetList("child_ids");
+ // Reset child Ids
+ child_ids_.clear();
+ for (size_t idx = 0; idx < childs->GetSize(); idx++) {
+ child_ids_.push_back(
+ OsrAccessibilityHelper::CastToInt(childs->GetValue(idx)));
+ }
+ }
+ // Update Location
+ if (value->HasKey("location")) {
+ CefRefPtr<CefDictionaryValue> loc = value->GetDictionary("location");
+ if (loc) {
+ location_ = CefRect(loc->GetDouble("x"), loc->GetDouble("y"),
+ loc->GetDouble("width"), loc->GetDouble("height"));
+ }
+ }
+ // Update offsets
+ if (value->HasKey("offset_container_id")) {
+ offset_container_id_ = OsrAccessibilityHelper::CastToInt(
+ value->GetValue("offset_container_id"));
+ }
+ // Update attributes
+ if (value->HasKey("attributes")) {
+ child_tree_id_ = "";
+
+ attributes_ = value->GetDictionary("attributes");
+
+ if (attributes_) {
+ scroll_.x = attributes_->HasKey("scrollX")
+ ? OsrAccessibilityHelper::CastToInt(
+ attributes_->GetValue("scrollX"))
+ : 0;
+ scroll_.y = attributes_->HasKey("scrollY")
+ ? OsrAccessibilityHelper::CastToInt(
+ attributes_->GetValue("scrollY"))
+ : 0;
+ }
+
+ if (attributes_ && attributes_->HasKey("childTreeId")) {
+ child_tree_id_ = attributes_->GetString("childTreeId");
+ }
+ if (attributes_ && attributes_->HasKey("name")) {
+ name_ = attributes_->GetString("name");
+ }
+ if (attributes_ && attributes_->HasKey("value")) {
+ value_ = attributes_->GetString("value");
+ }
+ if (attributes_ && attributes_->HasKey("description")) {
+ description_ = attributes_->GetString("description");
+ }
+ }
+}
+
+CefWindowHandle OsrAXNode::GetWindowHandle() const {
+ if (accessibility_helper_) {
+ return accessibility_helper_->GetWindowHandle();
+ }
+ return nullptr;
+}
+
+CefRefPtr<CefBrowser> OsrAXNode::GetBrowser() const {
+ if (accessibility_helper_) {
+ return accessibility_helper_->GetBrowser();
+ }
+ return nullptr;
+}
+
+void OsrAXNode::SetParent(OsrAXNode* parent) {
+ parent_ = parent;
+}
+
+CefRect OsrAXNode::AxLocation() const {
+ CefRect loc = location_;
+ loc.x -= scroll_.x;
+ loc.y -= scroll_.y;
+ OsrAXNode* offsetNode =
+ accessibility_helper_->GetNode(OsrAXTreeId(), offset_container_id_);
+ if (!offsetNode) {
+ OsrAXNode* p = parent_;
+ while (p) {
+ if (p->OsrAXTreeId() != OsrAXTreeId()) {
+ offsetNode = p;
+ break;
+ }
+ p = p->parent_;
+ }
+ }
+ // Add offset from parent Location
+ if (offsetNode) {
+ CefRect offset = offsetNode->AxLocation();
+ loc.x += offset.x;
+ loc.y += offset.y;
+ }
+ return loc;
+}
+
+int OsrAXNode::GetChildCount() const {
+ int count = static_cast<int>(child_ids_.size());
+ if (!child_tree_id_.empty()) {
+ OsrAXNode* childTreeRootNode =
+ accessibility_helper_->GetTreeRootNode(child_tree_id_);
+ if (childTreeRootNode) {
+ count++;
+ }
+ }
+ return count;
+}
+
+OsrAXNode* OsrAXNode::ChildAtIndex(int index) const {
+ int count = static_cast<int>(child_ids_.size());
+ if (index < count) {
+ return accessibility_helper_->GetNode(OsrAXTreeId(), child_ids_[index]);
+ }
+ if ((index == count) && (!child_tree_id_.empty())) {
+ OsrAXNode* childTreeRootNode =
+ accessibility_helper_->GetTreeRootNode(child_tree_id_);
+ if (childTreeRootNode) {
+ return childTreeRootNode;
+ }
+ }
+
+ return nullptr;
+}
+
+// Create and return the platform specific OsrAXNode Object
+OsrAXNode* OsrAXNode::CreateNode(const CefString& treeId,
+ int nodeId,
+ CefRefPtr<CefDictionaryValue> value,
+ OsrAccessibilityHelper* helper) {
+ return new OsrAXNode(treeId, nodeId, value, helper);
+}
+
+} // namespace client
diff --git a/tests/cefclient/browser/osr_accessibility_node.h b/tests/cefclient/browser/osr_accessibility_node.h
new file mode 100644
index 00000000..ab888191
--- /dev/null
+++ b/tests/cefclient/browser/osr_accessibility_node.h
@@ -0,0 +1,123 @@
+// Copyright 2017 The Chromium Embedded Framework Authors. Portions copyright
+// 2013 The Chromium Authors. All rights reserved. Use of this source code is
+// governed by a BSD-style license that can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_OSR_ACCESSIBILITY_NODE_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_OSR_ACCESSIBILITY_NODE_H_
+#pragma once
+
+#include <vector>
+
+#include "include/cef_browser.h"
+
+#if defined(OS_MAC)
+typedef void CefNativeAccessible;
+#if __OBJC__
+#if __has_feature(objc_arc)
+#define CAST_CEF_NATIVE_ACCESSIBLE_TO_NSOBJECT(accessible) \
+ (__bridge NSObject*)accessible
+#define CAST_NSOBJECT_TO_CEF_NATIVE_ACCESSIBLE(object) \
+ (__bridge CefNativeAccessible*)object
+#else // __has_feature(objc_arc)
+#define CAST_CEF_NATIVE_ACCESSIBLE_TO_NSOBJECT(accessible) (NSObject*)accessible
+#define CAST_NSOBJECT_TO_CEF_NATIVE_ACCESSIBLE(object) \
+ (__bridge CefNativeAccessible*)object
+#endif // __has_feature(objc_arc)
+#endif // __OBJC__
+#elif defined(OS_WIN)
+struct IAccessible;
+typedef IAccessible CefNativeAccessible;
+#else
+#error "Unsupported platform"
+#endif
+
+namespace client {
+
+class OsrAccessibilityHelper;
+
+// OsrAXNode is the base class for implementation for the NSAccessibility
+// protocol for interacting with VoiceOver and other accessibility clients.
+class OsrAXNode {
+ public:
+ // Create and return the platform specific OsrAXNode Object.
+ static OsrAXNode* CreateNode(const CefString& treeId,
+ int nodeId,
+ CefRefPtr<CefDictionaryValue> value,
+ OsrAccessibilityHelper* helper);
+
+ // Update Value.
+ void UpdateValue(CefRefPtr<CefDictionaryValue> value);
+
+ // UpdateLocation
+ void UpdateLocation(CefRefPtr<CefDictionaryValue> value);
+
+ // Fire a platform-specific notification that an event has occurred on
+ // this object.
+ void NotifyAccessibilityEvent(std::string event_type) const;
+
+ // Call Destroy rather than deleting this, because the subclass may
+ // use reference counting.
+ void Destroy();
+
+ // Return NSAccessibility Object for Mac/ IAccessible for Windows
+ CefNativeAccessible* GetNativeAccessibleObject(OsrAXNode* parent);
+
+ CefNativeAccessible* GetParentAccessibleObject() const {
+ return parent_ ? parent_->platform_accessibility_ : nullptr;
+ }
+
+ OsrAccessibilityHelper* GetAccessibilityHelper() const {
+ return accessibility_helper_;
+ }
+
+ int GetChildCount() const;
+
+ // Return the Child at the specified index
+ OsrAXNode* ChildAtIndex(int index) const;
+
+ const CefString& AxRole() const { return role_; }
+
+ const CefString& OsrAXTreeId() const { return tree_id_; }
+
+ int OsrAXNodeId() const { return node_id_; }
+
+ const CefString& AxValue() const { return value_; }
+
+ const CefString& AxName() const { return name_; }
+
+ const CefString& AxDescription() const { return description_; }
+
+ CefRect AxLocation() const;
+
+ CefWindowHandle GetWindowHandle() const;
+
+ CefRefPtr<CefBrowser> GetBrowser() const;
+
+ void SetParent(OsrAXNode* parent);
+
+ protected:
+ OsrAXNode(const CefString& treeId,
+ int nodeId,
+ CefRefPtr<CefDictionaryValue> value,
+ OsrAccessibilityHelper* helper);
+
+ CefString tree_id_;
+ int node_id_;
+ CefString child_tree_id_;
+ CefString role_;
+ CefString value_;
+ CefString name_;
+ CefString description_;
+ CefRect location_;
+ CefPoint scroll_;
+ std::vector<int> child_ids_;
+ CefNativeAccessible* platform_accessibility_;
+ OsrAXNode* parent_;
+ int offset_container_id_;
+ OsrAccessibilityHelper* accessibility_helper_;
+ CefRefPtr<CefDictionaryValue> attributes_;
+};
+
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_OSR_ACCESSIBILITY_NODE_H_
diff --git a/tests/cefclient/browser/osr_accessibility_node_mac.mm b/tests/cefclient/browser/osr_accessibility_node_mac.mm
new file mode 100644
index 00000000..b5d5c381
--- /dev/null
+++ b/tests/cefclient/browser/osr_accessibility_node_mac.mm
@@ -0,0 +1,612 @@
+// Copyright 2017 The Chromium Embedded Framework Authors. Portions copyright
+// 2013 The Chromium Authors. All rights reserved. Use of this source code is
+// governed by a BSD-style license that can be found in the LICENSE file.
+
+// Sample implementation for the NSAccessibility protocol for interacting with
+// VoiceOver and other accessibility clients.
+
+#include "tests/cefclient/browser/osr_accessibility_node.h"
+
+#import <AppKit/NSAccessibility.h>
+#import <Cocoa/Cocoa.h>
+
+#include "tests/cefclient/browser/osr_accessibility_helper.h"
+
+namespace {
+
+NSString* AxRoleToNSAxRole(const std::string& role_string) {
+ if (role_string == "abbr") {
+ return NSAccessibilityGroupRole;
+ }
+ if (role_string == "alertDialog") {
+ return NSAccessibilityGroupRole;
+ }
+ if (role_string == "alert") {
+ return NSAccessibilityGroupRole;
+ }
+ if (role_string == "annotation") {
+ return NSAccessibilityUnknownRole;
+ }
+ if (role_string == "application") {
+ return NSAccessibilityGroupRole;
+ }
+ if (role_string == "article") {
+ return NSAccessibilityGroupRole;
+ }
+ if (role_string == "audio") {
+ return NSAccessibilityGroupRole;
+ }
+ if (role_string == "banner") {
+ return NSAccessibilityGroupRole;
+ }
+ if (role_string == "blockquote") {
+ return NSAccessibilityGroupRole;
+ }
+ if (role_string == "busyIndicator") {
+ return NSAccessibilityBusyIndicatorRole;
+ }
+ if (role_string == "button") {
+ return NSAccessibilityButtonRole;
+ }
+ if (role_string == "buttonDropDown") {
+ return NSAccessibilityButtonRole;
+ }
+ if (role_string == "canvas") {
+ return NSAccessibilityImageRole;
+ }
+ if (role_string == "caption") {
+ return NSAccessibilityGroupRole;
+ }
+ if (role_string == "checkBox") {
+ return NSAccessibilityCheckBoxRole;
+ }
+ if (role_string == "colorWell") {
+ return NSAccessibilityColorWellRole;
+ }
+ if (role_string == "column") {
+ return NSAccessibilityColumnRole;
+ }
+ if (role_string == "comboBox") {
+ return NSAccessibilityComboBoxRole;
+ }
+ if (role_string == "complementary") {
+ return NSAccessibilityGroupRole;
+ }
+ if (role_string == "contentInfo") {
+ return NSAccessibilityGroupRole;
+ }
+ if (role_string == "definition") {
+ return NSAccessibilityGroupRole;
+ }
+ if (role_string == "descriptionListDetail") {
+ return NSAccessibilityGroupRole;
+ }
+ if (role_string == "descriptionList") {
+ return NSAccessibilityListRole;
+ }
+ if (role_string == "descriptionListTerm") {
+ return NSAccessibilityGroupRole;
+ }
+ if (role_string == "details") {
+ return NSAccessibilityGroupRole;
+ }
+ if (role_string == "dialog") {
+ return NSAccessibilityGroupRole;
+ }
+ if (role_string == "directory") {
+ return NSAccessibilityListRole;
+ }
+ if (role_string == "disclosureTriangle") {
+ return NSAccessibilityDisclosureTriangleRole;
+ }
+ if (role_string == "div") {
+ return NSAccessibilityGroupRole;
+ }
+ if (role_string == "document") {
+ return NSAccessibilityGroupRole;
+ }
+ if (role_string == "embeddedObject") {
+ return NSAccessibilityGroupRole;
+ }
+ if (role_string == "figcaption") {
+ return NSAccessibilityGroupRole;
+ }
+ if (role_string == "figure") {
+ return NSAccessibilityGroupRole;
+ }
+ if (role_string == "footer") {
+ return NSAccessibilityGroupRole;
+ }
+ if (role_string == "form") {
+ return NSAccessibilityGroupRole;
+ }
+ if (role_string == "genericContainer") {
+ return NSAccessibilityGroupRole;
+ }
+ if (role_string == "grid") {
+ return NSAccessibilityGroupRole;
+ }
+ if (role_string == "group") {
+ return NSAccessibilityGroupRole;
+ }
+ if (role_string == "iframe") {
+ return NSAccessibilityGroupRole;
+ }
+ if (role_string == "iframePresentational") {
+ return NSAccessibilityGroupRole;
+ }
+ if (role_string == "ignored") {
+ return NSAccessibilityUnknownRole;
+ }
+ if (role_string == "imageMapLink") {
+ return NSAccessibilityLinkRole;
+ }
+ if (role_string == "imageMap") {
+ return NSAccessibilityGroupRole;
+ }
+ if (role_string == "image") {
+ return NSAccessibilityImageRole;
+ }
+ if (role_string == "labelText") {
+ return NSAccessibilityGroupRole;
+ }
+ if (role_string == "legend") {
+ return NSAccessibilityGroupRole;
+ }
+ if (role_string == "link") {
+ return NSAccessibilityLinkRole;
+ }
+ if (role_string == "listBoxOption") {
+ return NSAccessibilityStaticTextRole;
+ }
+ if (role_string == "listBox") {
+ return NSAccessibilityListRole;
+ }
+ if (role_string == "listItem") {
+ return NSAccessibilityGroupRole;
+ }
+ if (role_string == "list") {
+ return NSAccessibilityListRole;
+ }
+ if (role_string == "log") {
+ return NSAccessibilityGroupRole;
+ }
+ if (role_string == "main") {
+ return NSAccessibilityGroupRole;
+ }
+ if (role_string == "mark") {
+ return NSAccessibilityGroupRole;
+ }
+ if (role_string == "marquee") {
+ return NSAccessibilityGroupRole;
+ }
+ if (role_string == "math") {
+ return NSAccessibilityGroupRole;
+ }
+ if (role_string == "menu") {
+ return NSAccessibilityMenuRole;
+ }
+ if (role_string == "menuBar") {
+ return NSAccessibilityMenuBarRole;
+ }
+ if (role_string == "menuButton") {
+ return NSAccessibilityButtonRole;
+ }
+ if (role_string == "menuItem") {
+ return NSAccessibilityMenuItemRole;
+ }
+ if (role_string == "menuItemCheckBox") {
+ return NSAccessibilityMenuItemRole;
+ }
+ if (role_string == "menuItemRadio") {
+ return NSAccessibilityMenuItemRole;
+ }
+ if (role_string == "menuListOption") {
+ return NSAccessibilityMenuItemRole;
+ }
+ if (role_string == "menuListPopup") {
+ return NSAccessibilityUnknownRole;
+ }
+ if (role_string == "meter") {
+ return NSAccessibilityProgressIndicatorRole;
+ }
+ if (role_string == "navigation") {
+ return NSAccessibilityGroupRole;
+ }
+ if (role_string == "note") {
+ return NSAccessibilityGroupRole;
+ }
+ if (role_string == "outline") {
+ return NSAccessibilityOutlineRole;
+ }
+ if (role_string == "paragraph") {
+ return NSAccessibilityGroupRole;
+ }
+ if (role_string == "popUpButton") {
+ return NSAccessibilityPopUpButtonRole;
+ }
+ if (role_string == "pre") {
+ return NSAccessibilityGroupRole;
+ }
+ if (role_string == "presentational") {
+ return NSAccessibilityGroupRole;
+ }
+ if (role_string == "progressIndicator") {
+ return NSAccessibilityProgressIndicatorRole;
+ }
+ if (role_string == "radioButton") {
+ return NSAccessibilityRadioButtonRole;
+ }
+ if (role_string == "radioGroup") {
+ return NSAccessibilityRadioGroupRole;
+ }
+ if (role_string == "region") {
+ return NSAccessibilityGroupRole;
+ }
+ if (role_string == "row") {
+ return NSAccessibilityRowRole;
+ }
+ if (role_string == "ruler") {
+ return NSAccessibilityRulerRole;
+ }
+ if (role_string == "scrollBar") {
+ return NSAccessibilityScrollBarRole;
+ }
+ if (role_string == "search") {
+ return NSAccessibilityGroupRole;
+ }
+ if (role_string == "searchBox") {
+ return NSAccessibilityTextFieldRole;
+ }
+ if (role_string == "slider") {
+ return NSAccessibilitySliderRole;
+ }
+ if (role_string == "sliderThumb") {
+ return NSAccessibilityValueIndicatorRole;
+ }
+ if (role_string == "spinButton") {
+ return NSAccessibilityIncrementorRole;
+ }
+ if (role_string == "splitter") {
+ return NSAccessibilitySplitterRole;
+ }
+ if (role_string == "staticText") {
+ return NSAccessibilityStaticTextRole;
+ }
+ if (role_string == "status") {
+ return NSAccessibilityGroupRole;
+ }
+ if (role_string == "svgRoot") {
+ return NSAccessibilityGroupRole;
+ }
+ if (role_string == "switch") {
+ return NSAccessibilityCheckBoxRole;
+ }
+ if (role_string == "tabGroup") {
+ return NSAccessibilityTabGroupRole;
+ }
+ if (role_string == "tabList") {
+ return NSAccessibilityTabGroupRole;
+ }
+ if (role_string == "tabPanel") {
+ return NSAccessibilityGroupRole;
+ }
+ if (role_string == "tab") {
+ return NSAccessibilityRadioButtonRole;
+ }
+ if (role_string == "tableHeaderContainer") {
+ return NSAccessibilityGroupRole;
+ }
+ if (role_string == "table") {
+ return NSAccessibilityTableRole;
+ }
+ if (role_string == "textField") {
+ return NSAccessibilityTextFieldRole;
+ }
+ if (role_string == "time") {
+ return NSAccessibilityGroupRole;
+ }
+ if (role_string == "timer") {
+ return NSAccessibilityGroupRole;
+ }
+ if (role_string == "toggleButton") {
+ return NSAccessibilityCheckBoxRole;
+ }
+ if (role_string == "toolbar") {
+ return NSAccessibilityToolbarRole;
+ }
+ if (role_string == "treeGrid") {
+ return NSAccessibilityTableRole;
+ }
+ if (role_string == "treeItem") {
+ return NSAccessibilityRowRole;
+ }
+ if (role_string == "tree") {
+ return NSAccessibilityOutlineRole;
+ }
+ if (role_string == "unknown") {
+ return NSAccessibilityUnknownRole;
+ }
+ if (role_string == "tooltip") {
+ return NSAccessibilityGroupRole;
+ }
+ if (role_string == "video") {
+ return NSAccessibilityGroupRole;
+ }
+ if (role_string == "window") {
+ return NSAccessibilityWindowRole;
+ }
+ return [NSString stringWithUTF8String:role_string.c_str()];
+}
+
+inline int MiddleX(const CefRect& rect) {
+ return rect.x + rect.width / 2;
+}
+
+inline int MiddleY(const CefRect& rect) {
+ return rect.y + rect.height / 2;
+}
+
+} // namespace
+
+// OsrAXNodeObject is sample implementation for the NSAccessibility protocol
+// for interacting with VoiceOver and other accessibility clients.
+@interface OsrAXNodeObject : NSObject {
+ // OsrAXNode* proxy object
+ client::OsrAXNode* node_;
+ CefNativeAccessible* parent_;
+}
+
+- (id)init:(client::OsrAXNode*)node;
++ (OsrAXNodeObject*)elementWithNode:(client::OsrAXNode*)node;
+@end
+
+@implementation OsrAXNodeObject
+- (id)init:(client::OsrAXNode*)node {
+ node_ = node;
+ parent_ = node_->GetParentAccessibleObject();
+ if (!parent_) {
+ parent_ = node_->GetWindowHandle();
+ }
+ return self;
+}
+
++ (OsrAXNodeObject*)elementWithNode:(client::OsrAXNode*)node {
+ // We manage the release ourself
+ return [[OsrAXNodeObject alloc] init:node];
+}
+
+- (BOOL)isEqual:(id)object {
+ if ([object isKindOfClass:[OsrAXNodeObject self]]) {
+ OsrAXNodeObject* other = object;
+ return (node_ == other->node_);
+ } else {
+ return NO;
+ }
+}
+
+// Utility methods to map AX information received from renderer
+// to platform properties
+- (NSString*)axRole {
+ // Get the Role from CefAccessibilityHelper and Map to NSRole
+ return AxRoleToNSAxRole(node_->AxRole());
+}
+
+- (NSString*)axDescription {
+ std::string desc = node_->AxDescription();
+ return [NSString stringWithUTF8String:desc.c_str()];
+}
+
+- (NSString*)axName {
+ std::string desc = node_->AxName();
+ return [NSString stringWithUTF8String:desc.c_str()];
+}
+
+- (NSString*)axValue {
+ std::string desc = node_->AxValue();
+ return [NSString stringWithUTF8String:desc.c_str()];
+}
+
+- (void)doMouseClick:(cef_mouse_button_type_t)type {
+ CefRefPtr<CefBrowser> browser = node_->GetBrowser();
+ if (browser) {
+ CefMouseEvent mouse_event;
+ const CefRect& rect = node_->AxLocation();
+ mouse_event.x = MiddleX(rect);
+ mouse_event.y = MiddleY(rect);
+
+ mouse_event.modifiers = 0;
+ browser->GetHost()->SendMouseClickEvent(mouse_event, type, false, 1);
+ browser->GetHost()->SendMouseClickEvent(mouse_event, type, true, 1);
+ }
+}
+
+- (NSMutableArray*)getKids {
+ int numChilds = node_->GetChildCount();
+ if (numChilds > 0) {
+ NSMutableArray* kids = [NSMutableArray arrayWithCapacity:numChilds];
+ for (int index = 0; index < numChilds; index++) {
+ client::OsrAXNode* child = node_->ChildAtIndex(index);
+ [kids addObject:child ? CAST_CEF_NATIVE_ACCESSIBLE_TO_NSOBJECT(
+ child->GetNativeAccessibleObject(node_))
+ : nil];
+ }
+ return kids;
+ }
+ return nil;
+}
+
+- (NSPoint)position {
+ CefRect cef_rect = node_->AxLocation();
+ NSPoint origin = NSMakePoint(cef_rect.x, cef_rect.y);
+ NSSize size = NSMakeSize(cef_rect.width, cef_rect.height);
+
+ NSView* view = CAST_CEF_WINDOW_HANDLE_TO_NSVIEW(node_->GetWindowHandle());
+ origin.y = NSHeight([view bounds]) - origin.y;
+ NSPoint originInWindow = [view convertPoint:origin toView:nil];
+
+ NSRect point_rect = NSMakeRect(originInWindow.x, originInWindow.y, 0, 0);
+ NSPoint originInScreen =
+ [[view window] convertRectToScreen:point_rect].origin;
+
+ originInScreen.y = originInScreen.y - size.height;
+ return originInScreen;
+}
+
+- (NSSize)size {
+ CefRect cef_rect = node_->AxLocation();
+ NSRect rect =
+ NSMakeRect(cef_rect.x, cef_rect.y, cef_rect.width, cef_rect.height);
+ NSView* view = CAST_CEF_WINDOW_HANDLE_TO_NSVIEW(node_->GetWindowHandle());
+ rect = [[view window] convertRectToScreen:rect];
+ return rect.size;
+}
+
+//
+// accessibility protocol
+//
+
+// attributes
+
+- (BOOL)accessibilityIsIgnored {
+ return NO;
+}
+
+- (NSArray*)accessibilityAttributeNames {
+ static NSArray* attributes = nil;
+ if (attributes == nil) {
+ attributes = [[NSArray alloc]
+ initWithObjects:NSAccessibilityRoleAttribute,
+ NSAccessibilityRoleDescriptionAttribute,
+ NSAccessibilityChildrenAttribute,
+ NSAccessibilityValueAttribute,
+ NSAccessibilityTitleAttribute,
+ NSAccessibilityDescriptionAttribute,
+ NSAccessibilityFocusedAttribute,
+ NSAccessibilityParentAttribute,
+ NSAccessibilityWindowAttribute,
+ NSAccessibilityTopLevelUIElementAttribute,
+ NSAccessibilityPositionAttribute,
+ NSAccessibilitySizeAttribute, nil];
+ }
+ return attributes;
+}
+
+- (id)accessibilityAttributeValue:(NSString*)attribute {
+ NSObject* typed_parent = CAST_CEF_NATIVE_ACCESSIBLE_TO_NSOBJECT(parent_);
+ if (!node_) {
+ return nil;
+ }
+ if ([attribute isEqualToString:NSAccessibilityRoleAttribute]) {
+ return [self axRole];
+ } else if ([attribute
+ isEqualToString:NSAccessibilityRoleDescriptionAttribute]) {
+ return NSAccessibilityRoleDescription([self axRole], nil);
+ } else if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) {
+ // Just check if the app thinks we're focused.
+ id focusedElement = [NSApp
+ accessibilityAttributeValue:NSAccessibilityFocusedUIElementAttribute];
+ return [NSNumber numberWithBool:[focusedElement isEqual:self]];
+ } else if ([attribute isEqualToString:NSAccessibilityParentAttribute]) {
+ return NSAccessibilityUnignoredAncestor(typed_parent);
+ } else if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) {
+ return NSAccessibilityUnignoredChildren([self getKids]);
+ } else if ([attribute isEqualToString:NSAccessibilityWindowAttribute]) {
+ // We're in the same window as our parent.
+ return [typed_parent
+ accessibilityAttributeValue:NSAccessibilityWindowAttribute];
+ } else if ([attribute
+ isEqualToString:NSAccessibilityTopLevelUIElementAttribute]) {
+ // We're in the same top level element as our parent.
+ return [typed_parent
+ accessibilityAttributeValue:NSAccessibilityTopLevelUIElementAttribute];
+ } else if ([attribute isEqualToString:NSAccessibilityPositionAttribute]) {
+ return [NSValue valueWithPoint:[self position]];
+ } else if ([attribute isEqualToString:NSAccessibilitySizeAttribute]) {
+ return [NSValue valueWithSize:[self size]];
+ } else if ([attribute isEqualToString:NSAccessibilityDescriptionAttribute]) {
+ return [self axDescription];
+ } else if ([attribute isEqualToString:NSAccessibilityValueAttribute]) {
+ return [self axValue];
+ } else if ([attribute isEqualToString:NSAccessibilityTitleAttribute]) {
+ return [self axName];
+ }
+ return nil;
+}
+
+- (id)accessibilityHitTest:(NSPoint)point {
+ return NSAccessibilityUnignoredAncestor(self);
+}
+
+- (NSArray*)accessibilityActionNames {
+ return [NSArray arrayWithObject:NSAccessibilityPressAction];
+}
+
+- (NSString*)accessibilityActionDescription:(NSString*)action {
+ return NSAccessibilityActionDescription(action);
+}
+
+- (void)accessibilityPerformAction:(NSString*)action {
+ if ([action isEqualToString:NSAccessibilityPressAction]) {
+ // Do Click on Default action
+ [self doMouseClick:MBT_LEFT];
+ } else if ([action isEqualToString:NSAccessibilityShowMenuAction]) {
+ // Right click for Context Menu
+ [self doMouseClick:MBT_RIGHT];
+ }
+}
+
+- (id)accessibilityFocusedUIElement {
+ return NSAccessibilityUnignoredAncestor(self);
+}
+
+- (BOOL)accessibilityNotifiesWhenDestroyed {
+ // Indicate that BrowserAccessibilityCocoa will post a notification when it's
+ // destroyed (see -detach). This allows VoiceOver to do some internal things
+ // more efficiently.
+ return YES;
+}
+
+@end
+
+namespace client {
+
+void OsrAXNode::NotifyAccessibilityEvent(std::string event_type) const {
+ NSView* view = CAST_CEF_WINDOW_HANDLE_TO_NSVIEW(GetWindowHandle());
+ if (event_type == "focus") {
+ NSAccessibilityPostNotification(
+ view, NSAccessibilityFocusedUIElementChangedNotification);
+ } else if (event_type == "textChanged") {
+ NSAccessibilityPostNotification(view,
+ NSAccessibilityTitleChangedNotification);
+ } else if (event_type == "valueChanged") {
+ NSAccessibilityPostNotification(view,
+ NSAccessibilityValueChangedNotification);
+ } else if (event_type == "textSelectionChanged") {
+ NSAccessibilityPostNotification(view,
+ NSAccessibilityValueChangedNotification);
+ }
+}
+
+void OsrAXNode::Destroy() {
+ if (platform_accessibility_) {
+ NSAccessibilityPostNotification(
+ CAST_CEF_NATIVE_ACCESSIBLE_TO_NSOBJECT(platform_accessibility_),
+ NSAccessibilityUIElementDestroyedNotification);
+ }
+
+ delete this;
+}
+
+// Create and return NSAccessibility Implementation Object for Mac
+CefNativeAccessible* OsrAXNode::GetNativeAccessibleObject(
+ client::OsrAXNode* parent) {
+ if (!platform_accessibility_) {
+ platform_accessibility_ = CAST_NSOBJECT_TO_CEF_NATIVE_ACCESSIBLE(
+ [OsrAXNodeObject elementWithNode:this]);
+ SetParent(parent);
+ }
+ return platform_accessibility_;
+}
+
+} // namespace client
diff --git a/tests/cefclient/browser/osr_accessibility_node_win.cc b/tests/cefclient/browser/osr_accessibility_node_win.cc
new file mode 100644
index 00000000..5c5e64fb
--- /dev/null
+++ b/tests/cefclient/browser/osr_accessibility_node_win.cc
@@ -0,0 +1,739 @@
+// Copyright 2017 The Chromium Embedded Framework Authors. Portions copyright
+// 2013 The Chromium Authors. All rights reserved. Use of this source code is
+// governed by a BSD-style license that can be found in the LICENSE file.
+
+// This class implements our accessible proxy object that handles moving
+// data back and forth between MSAA clients and CefClient renderers.
+// Sample implementation based on ui\accessibility\ax_platform_node_win.h
+
+#include "tests/cefclient/browser/osr_accessibility_node.h"
+
+#if defined(CEF_USE_ATL)
+
+#include <atlbase.h>
+#include <oleacc.h>
+#include <string>
+
+#include "tests/cefclient/browser/osr_accessibility_helper.h"
+
+namespace client {
+
+// Return CO_E_OBJNOTCONNECTED for accessible objects thar still exists but the
+// window and/or object it references has been destroyed.
+#define DATACHECK(node) (node) ? S_OK : CO_E_OBJNOTCONNECTED
+#define VALID_CHILDID(varChild) ((varChild.vt == VT_I4))
+
+namespace {
+
+// Helper function to convert a rectangle from client coordinates to screen
+// coordinates.
+void ClientToScreen(HWND hwnd, LPRECT lpRect) {
+ if (lpRect) {
+ POINT ptTL = {lpRect->left, lpRect->top};
+ POINT ptBR = {lpRect->right, lpRect->bottom};
+ // Win32 API only provides the call for a point.
+ ClientToScreen(hwnd, &ptTL);
+ ClientToScreen(hwnd, &ptBR);
+ SetRect(lpRect, ptTL.x, ptTL.y, ptBR.x, ptBR.y);
+ }
+}
+
+// Helper function to convert to MSAARole
+int AxRoleToMSAARole(const std::string& role_string) {
+ if (role_string == "alert") {
+ return ROLE_SYSTEM_ALERT;
+ }
+ if (role_string == "application") {
+ return ROLE_SYSTEM_APPLICATION;
+ }
+ if (role_string == "buttonDropDown") {
+ return ROLE_SYSTEM_BUTTONDROPDOWN;
+ }
+ if (role_string == "popUpButton") {
+ return ROLE_SYSTEM_BUTTONMENU;
+ }
+ if (role_string == "checkBox") {
+ return ROLE_SYSTEM_CHECKBUTTON;
+ }
+ if (role_string == "comboBox") {
+ return ROLE_SYSTEM_COMBOBOX;
+ }
+ if (role_string == "dialog") {
+ return ROLE_SYSTEM_DIALOG;
+ }
+ if (role_string == "genericContainer") {
+ return ROLE_SYSTEM_GROUPING;
+ }
+ if (role_string == "group") {
+ return ROLE_SYSTEM_GROUPING;
+ }
+ if (role_string == "image") {
+ return ROLE_SYSTEM_GRAPHIC;
+ }
+ if (role_string == "link") {
+ return ROLE_SYSTEM_LINK;
+ }
+ if (role_string == "locationBar") {
+ return ROLE_SYSTEM_GROUPING;
+ }
+ if (role_string == "menuBar") {
+ return ROLE_SYSTEM_MENUBAR;
+ }
+ if (role_string == "menuItem") {
+ return ROLE_SYSTEM_MENUITEM;
+ }
+ if (role_string == "menuListPopup") {
+ return ROLE_SYSTEM_MENUPOPUP;
+ }
+ if (role_string == "tree") {
+ return ROLE_SYSTEM_OUTLINE;
+ }
+ if (role_string == "treeItem") {
+ return ROLE_SYSTEM_OUTLINEITEM;
+ }
+ if (role_string == "tab") {
+ return ROLE_SYSTEM_PAGETAB;
+ }
+ if (role_string == "tabList") {
+ return ROLE_SYSTEM_PAGETABLIST;
+ }
+ if (role_string == "pane") {
+ return ROLE_SYSTEM_PANE;
+ }
+ if (role_string == "progressIndicator") {
+ return ROLE_SYSTEM_PROGRESSBAR;
+ }
+ if (role_string == "button") {
+ return ROLE_SYSTEM_PUSHBUTTON;
+ }
+ if (role_string == "radioButton") {
+ return ROLE_SYSTEM_RADIOBUTTON;
+ }
+ if (role_string == "scrollBar") {
+ return ROLE_SYSTEM_SCROLLBAR;
+ }
+ if (role_string == "splitter") {
+ return ROLE_SYSTEM_SEPARATOR;
+ }
+ if (role_string == "slider") {
+ return ROLE_SYSTEM_SLIDER;
+ }
+ if (role_string == "staticText") {
+ return ROLE_SYSTEM_STATICTEXT;
+ }
+ if (role_string == "textField") {
+ return ROLE_SYSTEM_TEXT;
+ }
+ if (role_string == "titleBar") {
+ return ROLE_SYSTEM_TITLEBAR;
+ }
+ if (role_string == "toolbar") {
+ return ROLE_SYSTEM_TOOLBAR;
+ }
+ if (role_string == "webView") {
+ return ROLE_SYSTEM_GROUPING;
+ }
+ if (role_string == "window") {
+ return ROLE_SYSTEM_WINDOW;
+ }
+ if (role_string == "client") {
+ return ROLE_SYSTEM_CLIENT;
+ }
+ // This is the default role for MSAA.
+ return ROLE_SYSTEM_CLIENT;
+}
+
+static inline int MiddleX(const CefRect& rect) {
+ return rect.x + rect.width / 2;
+}
+
+static inline int MiddleY(const CefRect& rect) {
+ return rect.y + rect.height / 2;
+}
+
+} // namespace
+
+struct CefIAccessible : public IAccessible {
+ public:
+ // Implement IUnknown
+ STDMETHODIMP QueryInterface(REFIID riid, void** ppvObject) override;
+ STDMETHODIMP_(ULONG) AddRef() override;
+ STDMETHODIMP_(ULONG) Release() override;
+
+ //
+ // IAccessible methods.
+ //
+ // Retrieves the child element or child object at a given point on the screen.
+ STDMETHODIMP accHitTest(LONG x_left, LONG y_top, VARIANT* child) override;
+
+ // Performs the object's default action.
+ STDMETHODIMP accDoDefaultAction(VARIANT var_id) override;
+
+ // Retrieves the specified object's current screen location.
+ STDMETHODIMP accLocation(LONG* x_left,
+ LONG* y_top,
+ LONG* width,
+ LONG* height,
+ VARIANT var_id) override;
+
+ // Traverses to another UI element and retrieves the object.
+ STDMETHODIMP accNavigate(LONG nav_dir, VARIANT start, VARIANT* end) override;
+
+ // Retrieves an IDispatch interface pointer for the specified child.
+ STDMETHODIMP get_accChild(VARIANT var_child, IDispatch** disp_child) override;
+
+ // Retrieves the number of accessible children.
+ STDMETHODIMP get_accChildCount(LONG* child_count) override;
+
+ // Retrieves a string that describes the object's default action.
+ STDMETHODIMP get_accDefaultAction(VARIANT var_id,
+ BSTR* default_action) override;
+
+ // Retrieves the tooltip description.
+ STDMETHODIMP get_accDescription(VARIANT var_id, BSTR* desc) override;
+
+ // Retrieves the object that has the keyboard focus.
+ STDMETHODIMP get_accFocus(VARIANT* focus_child) override;
+
+ // Retrieves the specified object's shortcut.
+ STDMETHODIMP get_accKeyboardShortcut(VARIANT var_id,
+ BSTR* access_key) override;
+
+ // Retrieves the name of the specified object.
+ STDMETHODIMP get_accName(VARIANT var_id, BSTR* name) override;
+
+ // Retrieves the IDispatch interface of the object's parent.
+ STDMETHODIMP get_accParent(IDispatch** disp_parent) override;
+
+ // Retrieves information describing the role of the specified object.
+ STDMETHODIMP get_accRole(VARIANT var_id, VARIANT* role) override;
+
+ // Retrieves the current state of the specified object.
+ STDMETHODIMP get_accState(VARIANT var_id, VARIANT* state) override;
+
+ // Gets the help string for the specified object.
+ STDMETHODIMP get_accHelp(VARIANT var_id, BSTR* help) override;
+
+ // Retrieve or set the string value associated with the specified object.
+ // Setting the value is not typically used by screen readers, but it's
+ // used frequently by automation software.
+ STDMETHODIMP get_accValue(VARIANT var_id, BSTR* value) override;
+ STDMETHODIMP put_accValue(VARIANT var_id, BSTR new_value) override;
+
+ // IAccessible methods not implemented.
+ STDMETHODIMP get_accSelection(VARIANT* selected) override;
+ STDMETHODIMP accSelect(LONG flags_sel, VARIANT var_id) override;
+ STDMETHODIMP get_accHelpTopic(BSTR* help_file,
+ VARIANT var_id,
+ LONG* topic_id) override;
+ STDMETHODIMP put_accName(VARIANT var_id, BSTR put_name) override;
+
+ // Implement IDispatch
+ STDMETHODIMP GetTypeInfoCount(unsigned int FAR* pctinfo) override;
+ STDMETHODIMP GetTypeInfo(unsigned int iTInfo,
+ LCID lcid,
+ ITypeInfo FAR* FAR* ppTInfo) override;
+ STDMETHODIMP GetIDsOfNames(REFIID riid,
+ OLECHAR FAR* FAR* rgszNames,
+ unsigned int cNames,
+ LCID lcid,
+ DISPID FAR* rgDispId) override;
+ STDMETHODIMP Invoke(DISPID dispIdMember,
+ REFIID riid,
+ LCID lcid,
+ WORD wFlags,
+ DISPPARAMS FAR* pDispParams,
+ VARIANT FAR* pVarResult,
+ EXCEPINFO FAR* pExcepInfo,
+ unsigned int FAR* puArgErr) override;
+
+ CefIAccessible(OsrAXNode* node) : ref_count_(0), node_(node) {}
+
+ // Remove the node reference when OsrAXNode is destroyed, so that
+ // MSAA clients get CO_E_OBJNOTCONNECTED
+ void MarkDestroyed() { node_ = nullptr; }
+
+ protected:
+ virtual ~CefIAccessible() {}
+
+ // Ref Count
+ ULONG ref_count_;
+ // OsrAXNode* proxy object
+ OsrAXNode* node_;
+};
+
+// Implement IUnknown
+// *********************
+
+// Handles ref counting and querying for other supported interfaces.
+// We only support, IUnknown, IDispatch and IAccessible.
+STDMETHODIMP CefIAccessible::QueryInterface(REFIID riid, void** ppvObject) {
+ if (riid == IID_IAccessible) {
+ *ppvObject = static_cast<IAccessible*>(this);
+ } else if (riid == IID_IDispatch) {
+ *ppvObject = static_cast<IDispatch*>(this);
+ } else if (riid == IID_IUnknown) {
+ *ppvObject = static_cast<IUnknown*>(this);
+ } else {
+ *ppvObject = nullptr;
+ }
+
+ if (*ppvObject) {
+ reinterpret_cast<IUnknown*>(*ppvObject)->AddRef();
+ }
+
+ return (*ppvObject) ? S_OK : E_NOINTERFACE;
+}
+
+// Increments COM objects refcount required by IUnknown for reference counting
+STDMETHODIMP_(ULONG) CefIAccessible::AddRef() {
+ return InterlockedIncrement((LONG volatile*)&ref_count_);
+}
+
+STDMETHODIMP_(ULONG) CefIAccessible::Release() {
+ ULONG ulRefCnt = InterlockedDecrement((LONG volatile*)&ref_count_);
+ if (ulRefCnt == 0) {
+ // Remove reference from OsrAXNode
+ if (node_) {
+ node_->Destroy();
+ }
+ delete this;
+ }
+
+ return ulRefCnt;
+}
+
+// Implement IAccessible
+// *********************
+
+// Returns the parent IAccessible in the form of an IDispatch interface.
+STDMETHODIMP CefIAccessible::get_accParent(IDispatch** ppdispParent) {
+ HRESULT retCode = DATACHECK(node_);
+ if (SUCCEEDED(retCode)) {
+ if (ppdispParent) {
+ CefNativeAccessible* parent = node_->GetParentAccessibleObject();
+ if (!parent) {
+ // Find our parent window
+ HWND hWnd = ::GetParent(node_->GetWindowHandle());
+ // if we have a window attempt to get its IAccessible pointer
+ if (hWnd) {
+ AccessibleObjectFromWindow(hWnd, (DWORD)OBJID_CLIENT, IID_IAccessible,
+ (void**)(&parent));
+ }
+ }
+
+ if (parent) {
+ parent->AddRef();
+ }
+ *ppdispParent = parent;
+ retCode = (*ppdispParent) ? S_OK : S_FALSE;
+ }
+ } else {
+ retCode = E_INVALIDARG;
+ }
+ return retCode;
+}
+
+// Returns the number of children we have for this element.
+STDMETHODIMP CefIAccessible::get_accChildCount(long* pcountChildren) {
+ HRESULT retCode = DATACHECK(node_);
+ if (SUCCEEDED(retCode) && pcountChildren) {
+ // Get Child node count for this from Accessibility tree
+ *pcountChildren = node_->GetChildCount();
+ } else {
+ retCode = E_INVALIDARG;
+ }
+ return retCode;
+}
+
+// Returns a child IAccessible object.
+STDMETHODIMP CefIAccessible::get_accChild(VARIANT varChild,
+ IDispatch** ppdispChild) {
+ HRESULT retCode = DATACHECK(node_);
+ if (SUCCEEDED(retCode)) {
+ int numChilds = node_->GetChildCount();
+ // Mark Leaf node if there are no child
+ if (numChilds <= 0) {
+ *ppdispChild = nullptr;
+ return S_FALSE;
+ } else {
+ if (ppdispChild && VALID_CHILDID(varChild)) {
+ if (varChild.lVal == CHILDID_SELF) {
+ *ppdispChild = this;
+ } else {
+ // Convert to 0 based index and get Child Node.
+ OsrAXNode* child = node_->ChildAtIndex(varChild.lVal - 1);
+ // Fallback to focused node
+ if (!child) {
+ child = node_->GetAccessibilityHelper()->GetFocusedNode();
+ }
+
+ *ppdispChild = child->GetNativeAccessibleObject(node_);
+ }
+ if (*ppdispChild == nullptr) {
+ retCode = S_FALSE;
+ } else {
+ (*ppdispChild)->AddRef();
+ }
+ }
+ }
+ }
+ return retCode;
+}
+
+// Check and returns the accessible name for element from accessibility tree
+STDMETHODIMP CefIAccessible::get_accName(VARIANT varChild, BSTR* pszName) {
+ HRESULT retCode = DATACHECK(node_);
+ if (SUCCEEDED(retCode)) {
+ if (pszName && VALID_CHILDID(varChild)) {
+ std::wstring name = node_->AxName();
+ CComBSTR bstrResult(name.c_str());
+ *pszName = bstrResult.Detach();
+ }
+ } else {
+ retCode = E_INVALIDARG;
+ }
+ return retCode;
+}
+
+// Check and returns the value for element from accessibility tree
+STDMETHODIMP CefIAccessible::get_accValue(VARIANT varChild, BSTR* pszValue) {
+ HRESULT retCode = DATACHECK(node_);
+ if (SUCCEEDED(retCode)) {
+ if (pszValue && VALID_CHILDID(varChild)) {
+ std::wstring name = node_->AxValue();
+ CComBSTR bstrResult(name.c_str());
+ *pszValue = bstrResult.Detach();
+ }
+ } else {
+ retCode = E_INVALIDARG;
+ }
+ return retCode;
+}
+
+// Check and returns the description for element from accessibility tree
+STDMETHODIMP CefIAccessible::get_accDescription(VARIANT varChild,
+ BSTR* pszDescription) {
+ HRESULT retCode = DATACHECK(node_);
+ if (SUCCEEDED(retCode)) {
+ if (pszDescription && VALID_CHILDID(varChild)) {
+ std::wstring name = node_->AxDescription();
+ CComBSTR bstrResult(name.c_str());
+ *pszDescription = bstrResult.Detach();
+ }
+ } else {
+ retCode = E_INVALIDARG;
+ }
+ return retCode;
+}
+
+// Check and returns the MSAA Role for element from accessibility tree
+STDMETHODIMP CefIAccessible::get_accRole(VARIANT varChild, VARIANT* pvarRole) {
+ HRESULT retCode = DATACHECK(node_);
+ if (SUCCEEDED(retCode)) {
+ // Get the accessibilty role and Map to MSAA Role
+ if (pvarRole) {
+ pvarRole->vt = VT_I4;
+ pvarRole->lVal = AxRoleToMSAARole(node_->AxRole());
+ } else {
+ retCode = E_INVALIDARG;
+ }
+ }
+ return retCode;
+}
+
+// Check and returns Accessibility State for element from accessibility tree
+STDMETHODIMP CefIAccessible::get_accState(VARIANT varChild,
+ VARIANT* pvarState) {
+ HRESULT retCode = DATACHECK(node_);
+ if (SUCCEEDED(retCode)) {
+ if (pvarState) {
+ pvarState->vt = VT_I4;
+ pvarState->lVal =
+ (GetFocus() == node_->GetWindowHandle()) ? STATE_SYSTEM_FOCUSED : 0;
+ pvarState->lVal |= STATE_SYSTEM_PRESSED;
+ pvarState->lVal |= STATE_SYSTEM_FOCUSABLE;
+
+ // For child
+ if (varChild.lVal == CHILDID_SELF) {
+ DWORD dwStyle = GetWindowLong(node_->GetWindowHandle(), GWL_STYLE);
+ pvarState->lVal |=
+ ((dwStyle & WS_VISIBLE) == 0) ? STATE_SYSTEM_INVISIBLE : 0;
+ pvarState->lVal |=
+ ((dwStyle & WS_DISABLED) > 0) ? STATE_SYSTEM_UNAVAILABLE : 0;
+ }
+ } else {
+ retCode = E_INVALIDARG;
+ }
+ }
+ return retCode;
+}
+
+// Check and returns Accessibility Shortcut if any for element
+STDMETHODIMP CefIAccessible::get_accKeyboardShortcut(
+ VARIANT varChild,
+ BSTR* pszKeyboardShortcut) {
+ HRESULT retCode = DATACHECK(node_);
+ if (SUCCEEDED(retCode)) {
+ if (pszKeyboardShortcut && VALID_CHILDID(varChild)) {
+ *pszKeyboardShortcut = ::SysAllocString(L"None");
+ } else {
+ retCode = E_INVALIDARG;
+ }
+ }
+ return retCode;
+}
+
+// Return focused element from the accessibility tree
+STDMETHODIMP CefIAccessible::get_accFocus(VARIANT* pFocusChild) {
+ HRESULT retCode = DATACHECK(node_);
+ if (SUCCEEDED(retCode)) {
+ OsrAXNode* focusedNode = node_->GetAccessibilityHelper()->GetFocusedNode();
+ CefNativeAccessible* nativeObj = nullptr;
+ if (focusedNode) {
+ nativeObj = focusedNode->GetNativeAccessibleObject(nullptr);
+ }
+
+ if (nativeObj) {
+ if (nativeObj == this) {
+ pFocusChild->vt = VT_I4;
+ pFocusChild->lVal = CHILDID_SELF;
+ } else {
+ pFocusChild->vt = VT_DISPATCH;
+ pFocusChild->pdispVal = nativeObj;
+ pFocusChild->pdispVal->AddRef();
+ }
+ } else {
+ pFocusChild->vt = VT_EMPTY;
+ }
+ }
+ return retCode;
+}
+
+// Return a selection list for multiple selection items.
+STDMETHODIMP CefIAccessible::get_accSelection(VARIANT* pvarChildren) {
+ HRESULT retCode = DATACHECK(node_);
+ if (SUCCEEDED(retCode)) {
+ if (pvarChildren) {
+ pvarChildren->vt = VT_EMPTY;
+ } else {
+ retCode = E_INVALIDARG;
+ }
+ }
+ return retCode;
+}
+
+// Return a string description of the default action of our element, eg. push
+STDMETHODIMP CefIAccessible::get_accDefaultAction(VARIANT varChild,
+ BSTR* pszDefaultAction) {
+ HRESULT retCode = DATACHECK(node_);
+ if (SUCCEEDED(retCode)) {
+ if (pszDefaultAction && VALID_CHILDID(varChild)) {
+ *pszDefaultAction = ::SysAllocString(L"Push");
+ } else {
+ retCode = E_INVALIDARG;
+ }
+ }
+ return retCode;
+}
+
+// child item selectionor for an item to take focus.
+STDMETHODIMP CefIAccessible::accSelect(long flagsSelect, VARIANT varChild) {
+ HRESULT retCode = DATACHECK(node_);
+ if (SUCCEEDED(retCode)) {
+ if (VALID_CHILDID(varChild)) {
+ HWND hwnd = node_->GetWindowHandle();
+ // we only support SELFLAG_TAKEFOCUS.
+ if (((flagsSelect & SELFLAG_TAKEFOCUS) > 0) && (GetFocus() == hwnd)) {
+ RECT rcWnd;
+ GetClientRect(hwnd, &rcWnd);
+ InvalidateRect(hwnd, &rcWnd, FALSE);
+ } else {
+ retCode = S_FALSE;
+ }
+ } else {
+ retCode = E_INVALIDARG;
+ }
+ }
+
+ return retCode;
+}
+
+// Returns back the screen coordinates of our element or one of its childs
+STDMETHODIMP CefIAccessible::accLocation(long* pxLeft,
+ long* pyTop,
+ long* pcxWidth,
+ long* pcyHeight,
+ VARIANT varChild) {
+ HRESULT retCode = DATACHECK(node_);
+ if (SUCCEEDED(retCode)) {
+ if (pxLeft && pyTop && pcxWidth && pcyHeight && VALID_CHILDID(varChild)) {
+ CefRect loc = node_->AxLocation();
+ RECT rcItem = {loc.x, loc.y, loc.x + loc.width, loc.y + loc.height};
+ HWND hwnd = node_->GetWindowHandle();
+ ClientToScreen(hwnd, &rcItem);
+
+ *pxLeft = rcItem.left;
+ *pyTop = rcItem.top;
+ *pcxWidth = rcItem.right - rcItem.left;
+ *pcyHeight = rcItem.bottom - rcItem.top;
+ } else {
+ retCode = E_INVALIDARG;
+ }
+ }
+ return retCode;
+}
+
+// Allow clients to move the keyboard focus within the control
+// Deprecated
+STDMETHODIMP CefIAccessible::accNavigate(long navDir,
+ VARIANT varStart,
+ VARIANT* pvarEndUpAt) {
+ return E_NOTIMPL;
+}
+
+// Check if the coordinates provided are within our element or child items.
+STDMETHODIMP CefIAccessible::accHitTest(long xLeft,
+ long yTop,
+ VARIANT* pvarChild) {
+ HRESULT retCode = DATACHECK(node_);
+ if (SUCCEEDED(retCode)) {
+ if (pvarChild) {
+ pvarChild->vt = VT_EMPTY;
+
+ CefRect loc = node_->AxLocation();
+ RECT rcItem = {loc.x, loc.y, loc.x + loc.width, loc.y + loc.height};
+ POINT pt = {xLeft, yTop};
+
+ ClientToScreen(node_->GetWindowHandle(), &rcItem);
+
+ if (PtInRect(&rcItem, pt)) {
+ pvarChild->vt = VT_I4;
+ pvarChild->lVal = 1;
+ }
+ } else {
+ retCode = E_INVALIDARG;
+ }
+ }
+
+ return retCode;
+}
+
+// Forces the default action of our element. In simplest cases, send a click.
+STDMETHODIMP CefIAccessible::accDoDefaultAction(VARIANT varChild) {
+ HRESULT retCode = DATACHECK(node_);
+ if (SUCCEEDED(retCode) && VALID_CHILDID(varChild)) {
+ // doing our default action for out button is to simply click the button.
+ CefRefPtr<CefBrowser> browser = node_->GetBrowser();
+ if (browser) {
+ CefMouseEvent mouse_event;
+ const CefRect& rect = node_->AxLocation();
+ mouse_event.x = MiddleX(rect);
+ mouse_event.y = MiddleY(rect);
+
+ mouse_event.modifiers = 0;
+ browser->GetHost()->SendMouseClickEvent(mouse_event, MBT_LEFT, false, 1);
+ browser->GetHost()->SendMouseClickEvent(mouse_event, MBT_LEFT, true, 1);
+ }
+ } else {
+ retCode = E_INVALIDARG;
+ }
+
+ return retCode;
+}
+
+// Set the name for an element in the accessibility tree
+STDMETHODIMP CefIAccessible::put_accName(VARIANT varChild, BSTR szName) {
+ return E_NOTIMPL;
+}
+
+// Set the value for an element in the accessibility tree
+STDMETHODIMP CefIAccessible::put_accValue(VARIANT varChild, BSTR szValue) {
+ return E_NOTIMPL;
+}
+
+// Return E_NOTIMPL as no help file/ topic
+STDMETHODIMP CefIAccessible::get_accHelp(VARIANT varChild, BSTR* pszHelp) {
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CefIAccessible::get_accHelpTopic(BSTR* pszHelpFile,
+ VARIANT varChild,
+ long* pidTopic) {
+ return E_NOTIMPL;
+}
+
+// IDispatch - We are not going to return E_NOTIMPL from IDispatch methods and
+// let Active Accessibility implement the IAccessible interface for them.
+STDMETHODIMP CefIAccessible::GetTypeInfoCount(unsigned int FAR* pctinfo) {
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CefIAccessible::GetTypeInfo(unsigned int iTInfo,
+ LCID lcid,
+ ITypeInfo FAR* FAR* ppTInfo) {
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CefIAccessible::GetIDsOfNames(REFIID riid,
+ OLECHAR FAR* FAR* rgszNames,
+ unsigned int cNames,
+ LCID lcid,
+ DISPID FAR* rgDispId) {
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP CefIAccessible::Invoke(DISPID dispIdMember,
+ REFIID riid,
+ LCID lcid,
+ WORD wFlags,
+ DISPPARAMS FAR* pDispParams,
+ VARIANT FAR* pVarResult,
+ EXCEPINFO FAR* pExcepInfo,
+ unsigned int FAR* puArgErr) {
+ return E_NOTIMPL;
+}
+
+void OsrAXNode::NotifyAccessibilityEvent(std::string event_type) const {
+ if (event_type == "focus") {
+ // Notify Screen Reader of focus change
+ ::NotifyWinEvent(EVENT_OBJECT_FOCUS, GetWindowHandle(), OBJID_CLIENT,
+ node_id_);
+ }
+}
+
+void OsrAXNode::Destroy() {
+ CefIAccessible* ptr = static_cast<CefIAccessible*>(platform_accessibility_);
+ if (ptr) {
+ ptr->MarkDestroyed();
+ }
+ platform_accessibility_ = nullptr;
+}
+
+// Create and return NSAccessibility Implementation Object for Window
+CefNativeAccessible* OsrAXNode::GetNativeAccessibleObject(OsrAXNode* parent) {
+ if (!platform_accessibility_) {
+ platform_accessibility_ = new CefIAccessible(this);
+ platform_accessibility_->AddRef();
+ SetParent(parent);
+ }
+ return platform_accessibility_;
+}
+
+} // namespace client
+
+#else // !defined(CEF_USE_ATL)
+
+namespace client {
+
+void OsrAXNode::NotifyAccessibilityEvent(std::string event_type) const {}
+
+void OsrAXNode::Destroy() {}
+
+CefNativeAccessible* OsrAXNode::GetNativeAccessibleObject(OsrAXNode* parent) {
+ return nullptr;
+}
+
+} // namespace client
+
+#endif // !defined(CEF_USE_ATL)
diff --git a/tests/cefclient/browser/osr_d3d11_win.cc b/tests/cefclient/browser/osr_d3d11_win.cc
new file mode 100644
index 00000000..14af7a9b
--- /dev/null
+++ b/tests/cefclient/browser/osr_d3d11_win.cc
@@ -0,0 +1,936 @@
+// Copyright 2018 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+//
+// Portions Copyright (c) 2018 Daktronics with the following MIT License:
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+
+#include "tests/cefclient/browser/osr_d3d11_win.h"
+
+#include <iomanip> // For std::setw.
+
+#if OS_WIN && ARCH_CPU_ARM_FAMILY
+#define __prefetch(x) x
+#endif
+#include <d3dcompiler.h>
+#include <directxmath.h>
+
+#include "include/base/cef_logging.h"
+#include "include/internal/cef_string.h"
+#include "tests/shared/browser/util_win.h"
+
+namespace client {
+namespace d3d11 {
+
+namespace {
+
+// Wrap a raw COM pointer in a shared_ptr for auto Release().
+template <class T>
+std::shared_ptr<T> to_com_ptr(T* obj) {
+ return std::shared_ptr<T>(obj, [](T* p) {
+ if (p) {
+ p->Release();
+ }
+ });
+}
+
+} // namespace
+
+struct SimpleVertex {
+ DirectX::XMFLOAT3 pos;
+ DirectX::XMFLOAT2 tex;
+};
+
+Context::Context(ID3D11DeviceContext* ctx) : ctx_(to_com_ptr(ctx)) {}
+
+void Context::flush() {
+ ctx_->Flush();
+}
+
+SwapChain::SwapChain(IDXGISwapChain* swapchain,
+ ID3D11RenderTargetView* rtv,
+ ID3D11SamplerState* sampler,
+ ID3D11BlendState* blender)
+ : sampler_(to_com_ptr(sampler)),
+ blender_(to_com_ptr(blender)),
+ swapchain_(to_com_ptr(swapchain)),
+ rtv_(to_com_ptr(rtv)),
+ width_(0),
+ height_(0) {}
+
+void SwapChain::bind(const std::shared_ptr<Context>& ctx) {
+ ctx_ = ctx;
+ ID3D11DeviceContext* d3d11_ctx = (ID3D11DeviceContext*)(*ctx_);
+
+ ID3D11RenderTargetView* rtv[1] = {rtv_.get()};
+ d3d11_ctx->OMSetRenderTargets(1, rtv, nullptr);
+
+ // Set default blending state.
+ if (blender_) {
+ float factor[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ d3d11_ctx->OMSetBlendState(blender_.get(), factor, 0xffffffff);
+ }
+
+ // Set default sampler state.
+ if (sampler_) {
+ ID3D11SamplerState* samplers[1] = {sampler_.get()};
+ d3d11_ctx->PSSetSamplers(0, 1, samplers);
+ }
+}
+
+void SwapChain::unbind() {
+ ctx_.reset();
+}
+
+void SwapChain::clear(float red, float green, float blue, float alpha) {
+ ID3D11DeviceContext* d3d11_ctx = (ID3D11DeviceContext*)(*ctx_);
+ CHECK(d3d11_ctx);
+
+ FLOAT color[4] = {red, green, blue, alpha};
+ d3d11_ctx->ClearRenderTargetView(rtv_.get(), color);
+}
+
+void SwapChain::present(int sync_interval) {
+ swapchain_->Present(sync_interval, 0);
+}
+
+void SwapChain::resize(int width, int height) {
+ if (width <= 0 || height <= 0 || width == width_ || height == height_) {
+ return;
+ }
+ width_ = width;
+ height_ = height;
+
+ ID3D11DeviceContext* d3d11_ctx = (ID3D11DeviceContext*)(*ctx_);
+ CHECK(d3d11_ctx);
+
+ d3d11_ctx->OMSetRenderTargets(0, 0, 0);
+ rtv_.reset();
+
+ DXGI_SWAP_CHAIN_DESC desc;
+ swapchain_->GetDesc(&desc);
+ auto hr = swapchain_->ResizeBuffers(0, width, height, desc.BufferDesc.Format,
+ desc.Flags);
+ if (FAILED(hr)) {
+ LOG(ERROR) << "d3d11: Failed to resize swapchain (" << width << "x"
+ << height << ")";
+ return;
+ }
+
+ ID3D11Texture2D* buffer = nullptr;
+ hr = swapchain_->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&buffer);
+ if (FAILED(hr)) {
+ LOG(ERROR) << "d3d11: Failed to resize swapchain (" << width << "x"
+ << height << ")";
+ return;
+ }
+
+ ID3D11Device* dev = nullptr;
+ d3d11_ctx->GetDevice(&dev);
+ if (dev) {
+ D3D11_RENDER_TARGET_VIEW_DESC vdesc = {};
+ vdesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
+ vdesc.Texture2D.MipSlice = 0;
+ vdesc.Format = desc.BufferDesc.Format;
+
+ ID3D11RenderTargetView* view = nullptr;
+ hr = dev->CreateRenderTargetView(buffer, &vdesc, &view);
+ if (SUCCEEDED(hr)) {
+ rtv_ = to_com_ptr(view);
+ d3d11_ctx->OMSetRenderTargets(1, &view, nullptr);
+ }
+ dev->Release();
+ }
+ buffer->Release();
+
+ D3D11_VIEWPORT vp;
+ vp.Width = static_cast<float>(width);
+ vp.Height = static_cast<float>(height);
+ vp.MinDepth = D3D11_MIN_DEPTH;
+ vp.MaxDepth = D3D11_MAX_DEPTH;
+ vp.TopLeftX = 0;
+ vp.TopLeftY = 0;
+ d3d11_ctx->RSSetViewports(1, &vp);
+}
+
+Effect::Effect(ID3D11VertexShader* vsh,
+ ID3D11PixelShader* psh,
+ ID3D11InputLayout* layout)
+ : vsh_(to_com_ptr(vsh)),
+ psh_(to_com_ptr(psh)),
+ layout_(to_com_ptr(layout)) {}
+
+void Effect::bind(const std::shared_ptr<Context>& ctx) {
+ ctx_ = ctx;
+ ID3D11DeviceContext* d3d11_ctx = (ID3D11DeviceContext*)(*ctx_);
+
+ d3d11_ctx->IASetInputLayout(layout_.get());
+ d3d11_ctx->VSSetShader(vsh_.get(), nullptr, 0);
+ d3d11_ctx->PSSetShader(psh_.get(), nullptr, 0);
+}
+
+void Effect::unbind() {}
+
+Geometry::Geometry(D3D_PRIMITIVE_TOPOLOGY primitive,
+ uint32_t vertices,
+ uint32_t stride,
+ ID3D11Buffer* buffer)
+ : primitive_(primitive),
+ vertices_(vertices),
+ stride_(stride),
+ buffer_(to_com_ptr(buffer)) {}
+
+void Geometry::bind(const std::shared_ptr<Context>& ctx) {
+ ctx_ = ctx;
+ ID3D11DeviceContext* d3d11_ctx = (ID3D11DeviceContext*)(*ctx_);
+
+ // TODO: Handle offset.
+ uint32_t offset = 0;
+
+ ID3D11Buffer* buffers[1] = {buffer_.get()};
+ d3d11_ctx->IASetVertexBuffers(0, 1, buffers, &stride_, &offset);
+ d3d11_ctx->IASetPrimitiveTopology(primitive_);
+}
+
+void Geometry::unbind() {}
+
+void Geometry::draw() {
+ ID3D11DeviceContext* d3d11_ctx = (ID3D11DeviceContext*)(*ctx_);
+ CHECK(d3d11_ctx);
+
+ // TODO: Handle offset.
+ d3d11_ctx->Draw(vertices_, 0);
+}
+
+Texture2D::Texture2D(ID3D11Texture2D* tex, ID3D11ShaderResourceView* srv)
+ : texture_(to_com_ptr(tex)), srv_(to_com_ptr(srv)) {
+ share_handle_ = nullptr;
+
+ IDXGIResource* res = nullptr;
+ if (SUCCEEDED(texture_->QueryInterface(__uuidof(IDXGIResource),
+ reinterpret_cast<void**>(&res)))) {
+ res->GetSharedHandle(&share_handle_);
+ res->Release();
+ }
+
+ // Are we using a keyed mutex?
+ IDXGIKeyedMutex* mutex = nullptr;
+ if (SUCCEEDED(texture_->QueryInterface(__uuidof(IDXGIKeyedMutex),
+ (void**)&mutex))) {
+ keyed_mutex_ = to_com_ptr(mutex);
+ }
+}
+
+uint32_t Texture2D::width() const {
+ D3D11_TEXTURE2D_DESC desc;
+ texture_->GetDesc(&desc);
+ return desc.Width;
+}
+
+uint32_t Texture2D::height() const {
+ D3D11_TEXTURE2D_DESC desc;
+ texture_->GetDesc(&desc);
+ return desc.Height;
+}
+
+DXGI_FORMAT Texture2D::format() const {
+ D3D11_TEXTURE2D_DESC desc;
+ texture_->GetDesc(&desc);
+ return desc.Format;
+}
+
+bool Texture2D::has_mutex() const {
+ return (keyed_mutex_.get() != nullptr);
+}
+
+bool Texture2D::lock_key(uint64_t key, uint32_t timeout_ms) {
+ if (keyed_mutex_) {
+ const auto hr = keyed_mutex_->AcquireSync(key, timeout_ms);
+ return (hr == S_OK);
+ }
+ return true;
+}
+
+void Texture2D::unlock_key(uint64_t key) {
+ if (keyed_mutex_) {
+ keyed_mutex_->ReleaseSync(key);
+ }
+}
+
+void Texture2D::bind(const std::shared_ptr<Context>& ctx) {
+ ctx_ = ctx;
+ ID3D11DeviceContext* d3d11_ctx = (ID3D11DeviceContext*)(*ctx_);
+ if (srv_) {
+ ID3D11ShaderResourceView* views[1] = {srv_.get()};
+ d3d11_ctx->PSSetShaderResources(0, 1, views);
+ }
+}
+
+void Texture2D::unbind() {}
+
+void* Texture2D::share_handle() const {
+ return share_handle_;
+}
+
+void Texture2D::copy_from(const std::shared_ptr<Texture2D>& other) {
+ ID3D11DeviceContext* d3d11_ctx = (ID3D11DeviceContext*)(*ctx_);
+ CHECK(d3d11_ctx);
+ if (other) {
+ d3d11_ctx->CopyResource(texture_.get(), other->texture_.get());
+ }
+}
+
+Device::Device(ID3D11Device* pdev, ID3D11DeviceContext* pctx)
+ : device_(to_com_ptr(pdev)), ctx_(std::make_shared<Context>(pctx)) {
+ lib_compiler_ = LoadLibrary(L"d3dcompiler_47.dll");
+}
+
+// static
+std::shared_ptr<Device> Device::create() {
+ UINT flags = 0;
+#ifdef _DEBUG
+ flags |= D3D11_CREATE_DEVICE_DEBUG;
+#endif
+
+ D3D_FEATURE_LEVEL feature_levels[] = {
+ D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1,
+ D3D_FEATURE_LEVEL_10_0,
+ // D3D_FEATURE_LEVEL_9_3,
+ };
+ UINT num_feature_levels = sizeof(feature_levels) / sizeof(feature_levels[0]);
+
+ ID3D11Device* pdev = nullptr;
+ ID3D11DeviceContext* pctx = nullptr;
+
+ D3D_FEATURE_LEVEL selected_level;
+ HRESULT hr = D3D11CreateDevice(
+ nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, flags, feature_levels,
+ num_feature_levels, D3D11_SDK_VERSION, &pdev, &selected_level, &pctx);
+
+ if (hr == E_INVALIDARG) {
+ // DirectX 11.0 platforms will not recognize D3D_FEATURE_LEVEL_11_1
+ // so we need to retry without it.
+ hr = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, flags,
+ &feature_levels[1], num_feature_levels - 1,
+ D3D11_SDK_VERSION, &pdev, &selected_level, &pctx);
+ }
+
+ if (SUCCEEDED(hr)) {
+ const auto dev = std::make_shared<Device>(pdev, pctx);
+
+ LOG(INFO) << "d3d11: Selected adapter " << dev->adapter_name()
+ << " and feature level 0x" << std::setw(4) << std::hex
+ << selected_level;
+
+ return dev;
+ }
+
+ return nullptr;
+}
+
+std::string Device::adapter_name() const {
+ IDXGIDevice* dxgi_dev = nullptr;
+ auto hr = device_->QueryInterface(__uuidof(dxgi_dev), (void**)&dxgi_dev);
+ if (SUCCEEDED(hr)) {
+ IDXGIAdapter* dxgi_adapt = nullptr;
+ hr = dxgi_dev->GetAdapter(&dxgi_adapt);
+ dxgi_dev->Release();
+ if (SUCCEEDED(hr)) {
+ DXGI_ADAPTER_DESC desc;
+ hr = dxgi_adapt->GetDesc(&desc);
+ dxgi_adapt->Release();
+ if (SUCCEEDED(hr)) {
+ return CefString(desc.Description);
+ }
+ }
+ }
+
+ return "n/a";
+}
+
+std::shared_ptr<Context> Device::immedidate_context() {
+ return ctx_;
+}
+
+std::shared_ptr<SwapChain> Device::create_swapchain(HWND window,
+ int width,
+ int height) {
+ HRESULT hr;
+ IDXGIFactory1* dxgi_factory = nullptr;
+
+ // Default size to the window size unless specified.
+ RECT rc_bounds;
+ GetClientRect(window, &rc_bounds);
+ if (width <= 0) {
+ width = rc_bounds.right - rc_bounds.left;
+ }
+ if (height <= 0) {
+ height = rc_bounds.bottom - rc_bounds.top;
+ }
+
+ {
+ IDXGIDevice* dxgi_dev = nullptr;
+ hr = device_->QueryInterface(__uuidof(IDXGIDevice),
+ reinterpret_cast<void**>(&dxgi_dev));
+ if (FAILED(hr)) {
+ return nullptr;
+ }
+
+ IDXGIAdapter* adapter = nullptr;
+ hr = dxgi_dev->GetAdapter(&adapter);
+ dxgi_dev->Release();
+ if (FAILED(hr)) {
+ return nullptr;
+ }
+
+ hr = adapter->GetParent(__uuidof(IDXGIFactory1),
+ reinterpret_cast<void**>(&dxgi_factory));
+ adapter->Release();
+ }
+
+ if (!dxgi_factory) {
+ return nullptr;
+ }
+
+ IDXGISwapChain* swapchain = nullptr;
+
+ // Create swap chain.
+ IDXGIFactory2* dxgi_factory2 = nullptr;
+ hr = dxgi_factory->QueryInterface(__uuidof(IDXGIFactory2),
+ reinterpret_cast<void**>(&dxgi_factory2));
+ if (dxgi_factory2) {
+ DXGI_SWAP_CHAIN_DESC1 sd;
+ ZeroMemory(&sd, sizeof(sd));
+ sd.Width = width;
+ sd.Height = height;
+ sd.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+ sd.SampleDesc.Count = 1;
+ sd.SampleDesc.Quality = 0;
+ sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
+ sd.BufferCount = 1;
+
+ IDXGISwapChain1* swapchain1 = nullptr;
+ hr = dxgi_factory2->CreateSwapChainForHwnd(device_.get(), window, &sd,
+ nullptr, nullptr, &swapchain1);
+ if (SUCCEEDED(hr)) {
+ hr = swapchain1->QueryInterface(__uuidof(IDXGISwapChain),
+ reinterpret_cast<void**>(&swapchain));
+ swapchain1->Release();
+ }
+
+ dxgi_factory2->Release();
+ } else {
+ // DirectX 11.0 systems.
+ DXGI_SWAP_CHAIN_DESC sd;
+ ZeroMemory(&sd, sizeof(sd));
+ sd.BufferCount = 1;
+ sd.BufferDesc.Width = width;
+ sd.BufferDesc.Height = height;
+ sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+ sd.BufferDesc.RefreshRate.Numerator = 60;
+ sd.BufferDesc.RefreshRate.Denominator = 1;
+ sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
+ sd.OutputWindow = window;
+ sd.SampleDesc.Count = 1;
+ sd.SampleDesc.Quality = 0;
+ sd.Windowed = TRUE;
+
+ hr = dxgi_factory->CreateSwapChain(device_.get(), &sd, &swapchain);
+ }
+
+ // We don't handle full-screen swapchains so we block the ALT+ENTER shortcut.
+ dxgi_factory->MakeWindowAssociation(window, DXGI_MWA_NO_ALT_ENTER);
+ dxgi_factory->Release();
+
+ if (!swapchain) {
+ return nullptr;
+ }
+
+ ID3D11Texture2D* back_buffer = nullptr;
+ hr = swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D),
+ reinterpret_cast<void**>(&back_buffer));
+ if (FAILED(hr)) {
+ swapchain->Release();
+ return nullptr;
+ }
+
+ ID3D11RenderTargetView* rtv = nullptr;
+ hr = device_->CreateRenderTargetView(back_buffer, nullptr, &rtv);
+ back_buffer->Release();
+ if (FAILED(hr)) {
+ swapchain->Release();
+ return nullptr;
+ }
+
+ const auto ctx = (ID3D11DeviceContext*)(*ctx_);
+
+ ctx->OMSetRenderTargets(1, &rtv, nullptr);
+
+ // Setup the viewport.
+ D3D11_VIEWPORT vp;
+ vp.Width = (FLOAT)width;
+ vp.Height = (FLOAT)height;
+ vp.MinDepth = 0.0f;
+ vp.MaxDepth = 1.0f;
+ vp.TopLeftX = 0;
+ vp.TopLeftY = 0;
+ ctx->RSSetViewports(1, &vp);
+
+ // Create a default sampler to use.
+ ID3D11SamplerState* sampler = nullptr;
+ {
+ D3D11_SAMPLER_DESC desc = {};
+ desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
+ desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
+ desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
+ desc.ComparisonFunc = D3D11_COMPARISON_NEVER;
+ desc.MinLOD = 0.0f;
+ desc.MaxLOD = D3D11_FLOAT32_MAX;
+ desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
+ device_->CreateSamplerState(&desc, &sampler);
+ }
+
+ // Create a default blend state to use (pre-multiplied alpha).
+ ID3D11BlendState* blender = nullptr;
+ {
+ D3D11_BLEND_DESC desc;
+ desc.AlphaToCoverageEnable = FALSE;
+ desc.IndependentBlendEnable = FALSE;
+ const auto count = sizeof(desc.RenderTarget) / sizeof(desc.RenderTarget[0]);
+ for (size_t n = 0; n < count; ++n) {
+ desc.RenderTarget[n].BlendEnable = TRUE;
+ desc.RenderTarget[n].SrcBlend = D3D11_BLEND_ONE;
+ desc.RenderTarget[n].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
+ desc.RenderTarget[n].SrcBlendAlpha = D3D11_BLEND_ONE;
+ desc.RenderTarget[n].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
+ desc.RenderTarget[n].BlendOp = D3D11_BLEND_OP_ADD;
+ desc.RenderTarget[n].BlendOpAlpha = D3D11_BLEND_OP_ADD;
+ desc.RenderTarget[n].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
+ }
+ device_->CreateBlendState(&desc, &blender);
+ }
+
+ return std::make_shared<SwapChain>(swapchain, rtv, sampler, blender);
+}
+
+std::shared_ptr<Geometry> Device::create_quad(float x,
+ float y,
+ float width,
+ float height,
+ bool flip) {
+ x = (x * 2.0f) - 1.0f;
+ y = 1.0f - (y * 2.0f);
+ width = width * 2.0f;
+ height = height * 2.0f;
+ float z = 1.0f;
+
+ SimpleVertex vertices[] = {
+
+ {DirectX::XMFLOAT3(x, y, z), DirectX::XMFLOAT2(0.0f, 0.0f)},
+ {DirectX::XMFLOAT3(x + width, y, z), DirectX::XMFLOAT2(1.0f, 0.0f)},
+ {DirectX::XMFLOAT3(x, y - height, z), DirectX::XMFLOAT2(0.0f, 1.0f)},
+ {DirectX::XMFLOAT3(x + width, y - height, z),
+ DirectX::XMFLOAT2(1.0f, 1.0f)}};
+
+ if (flip) {
+ DirectX::XMFLOAT2 tmp(vertices[2].tex);
+ vertices[2].tex = vertices[0].tex;
+ vertices[0].tex = tmp;
+
+ tmp = vertices[3].tex;
+ vertices[3].tex = vertices[1].tex;
+ vertices[1].tex = tmp;
+ }
+
+ D3D11_BUFFER_DESC desc = {};
+ desc.Usage = D3D11_USAGE_DEFAULT;
+ desc.ByteWidth = sizeof(SimpleVertex) * 4;
+ desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
+ desc.CPUAccessFlags = 0;
+
+ D3D11_SUBRESOURCE_DATA srd = {};
+ srd.pSysMem = vertices;
+
+ ID3D11Buffer* buffer = nullptr;
+ const auto hr = device_->CreateBuffer(&desc, &srd, &buffer);
+ if (SUCCEEDED(hr)) {
+ return std::make_shared<Geometry>(
+ D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, 4,
+ static_cast<uint32_t>(sizeof(SimpleVertex)), buffer);
+ }
+
+ return nullptr;
+}
+
+std::shared_ptr<Texture2D> Device::open_shared_texture(void* handle) {
+ ID3D11Texture2D* tex = nullptr;
+ auto hr = device_->OpenSharedResource(handle, __uuidof(ID3D11Texture2D),
+ (void**)(&tex));
+ if (FAILED(hr)) {
+ return nullptr;
+ }
+
+ D3D11_TEXTURE2D_DESC td;
+ tex->GetDesc(&td);
+
+ ID3D11ShaderResourceView* srv = nullptr;
+
+ if (td.BindFlags & D3D11_BIND_SHADER_RESOURCE) {
+ D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc;
+ srv_desc.Format = td.Format;
+ srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
+ srv_desc.Texture2D.MostDetailedMip = 0;
+ srv_desc.Texture2D.MipLevels = 1;
+
+ hr = device_->CreateShaderResourceView(tex, &srv_desc, &srv);
+ if (FAILED(hr)) {
+ tex->Release();
+ return nullptr;
+ }
+ }
+
+ return std::make_shared<Texture2D>(tex, srv);
+}
+
+std::shared_ptr<Texture2D> Device::create_texture(int width,
+ int height,
+ DXGI_FORMAT format,
+ const void* data,
+ size_t row_stride) {
+ D3D11_TEXTURE2D_DESC td;
+ td.ArraySize = 1;
+ td.BindFlags = D3D11_BIND_SHADER_RESOURCE;
+ td.CPUAccessFlags = 0;
+ td.Format = format;
+ td.Width = width;
+ td.Height = height;
+ td.MipLevels = 1;
+ td.MiscFlags = 0;
+ td.SampleDesc.Count = 1;
+ td.SampleDesc.Quality = 0;
+ td.Usage = D3D11_USAGE_DEFAULT;
+
+ D3D11_SUBRESOURCE_DATA srd;
+ srd.pSysMem = data;
+ srd.SysMemPitch = static_cast<uint32_t>(row_stride);
+ srd.SysMemSlicePitch = 0;
+
+ ID3D11Texture2D* tex = nullptr;
+ auto hr = device_->CreateTexture2D(&td, data ? &srd : nullptr, &tex);
+ if (FAILED(hr)) {
+ return nullptr;
+ }
+
+ D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc;
+ srv_desc.Format = td.Format;
+ srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
+ srv_desc.Texture2D.MostDetailedMip = 0;
+ srv_desc.Texture2D.MipLevels = 1;
+
+ ID3D11ShaderResourceView* srv = nullptr;
+ hr = device_->CreateShaderResourceView(tex, &srv_desc, &srv);
+ if (FAILED(hr)) {
+ tex->Release();
+ return nullptr;
+ }
+
+ return std::make_shared<Texture2D>(tex, srv);
+}
+
+std::shared_ptr<ID3DBlob> Device::compile_shader(const std::string& source_code,
+ const std::string& entry_point,
+ const std::string& model) {
+ if (!lib_compiler_) {
+ return nullptr;
+ }
+
+ typedef HRESULT(WINAPI * PFN_D3DCOMPILE)(
+ LPCVOID, SIZE_T, LPCSTR, const D3D_SHADER_MACRO*, ID3DInclude*, LPCSTR,
+ LPCSTR, UINT, UINT, ID3DBlob**, ID3DBlob**);
+
+ const auto fnc_compile = reinterpret_cast<PFN_D3DCOMPILE>(
+ GetProcAddress(lib_compiler_, "D3DCompile"));
+ if (!fnc_compile) {
+ return nullptr;
+ }
+
+ DWORD flags = D3DCOMPILE_ENABLE_STRICTNESS;
+
+#if defined(NDEBUG)
+// flags |= D3DCOMPILE_OPTIMIZATION_LEVEL3;
+// flags |= D3DCOMPILE_AVOID_FLOW_CONTROL;
+#else
+ flags |= D3DCOMPILE_DEBUG;
+ flags |= D3DCOMPILE_SKIP_OPTIMIZATION;
+#endif
+
+ ID3DBlob* blob = nullptr;
+ ID3DBlob* blob_err = nullptr;
+
+ const auto psrc = source_code.c_str();
+ const auto len = source_code.size() + 1;
+
+ const auto hr =
+ fnc_compile(psrc, len, nullptr, nullptr, nullptr, entry_point.c_str(),
+ model.c_str(), flags, 0, &blob, &blob_err);
+
+ if (FAILED(hr)) {
+ if (blob_err) {
+ // TODO: Log the error.
+ blob_err->Release();
+ }
+ return nullptr;
+ }
+
+ if (blob_err) {
+ blob_err->Release();
+ }
+
+ return std::shared_ptr<ID3DBlob>(blob, [](ID3DBlob* p) {
+ if (p) {
+ p->Release();
+ }
+ });
+}
+
+std::shared_ptr<Effect> Device::create_default_effect() {
+ const auto vsh =
+ R"--(struct VS_INPUT
+{
+ float4 pos : POSITION;
+ float2 tex : TEXCOORD0;
+};
+
+struct VS_OUTPUT
+{
+ float4 pos : SV_POSITION;
+ float2 tex : TEXCOORD0;
+};
+
+VS_OUTPUT main(VS_INPUT input)
+{
+ VS_OUTPUT output;
+ output.pos = input.pos;
+ output.tex = input.tex;
+ return output;
+})--";
+
+ const auto psh =
+ R"--(Texture2D tex0 : register(t0);
+SamplerState samp0 : register(s0);
+
+struct VS_OUTPUT
+{
+ float4 pos : SV_POSITION;
+ float2 tex : TEXCOORD0;
+};
+
+float4 main(VS_OUTPUT input) : SV_Target
+{
+ return tex0.Sample(samp0, input.tex);
+})--";
+
+ return create_effect(vsh, "main", "vs_4_0", psh, "main", "ps_4_0");
+}
+
+std::shared_ptr<Effect> Device::create_effect(const std::string& vertex_code,
+ const std::string& vertex_entry,
+ const std::string& vertex_model,
+ const std::string& pixel_code,
+ const std::string& pixel_entry,
+ const std::string& pixel_model) {
+ const auto vs_blob = compile_shader(vertex_code, vertex_entry, vertex_model);
+
+ ID3D11VertexShader* vshdr = nullptr;
+ ID3D11InputLayout* layout = nullptr;
+
+ if (vs_blob) {
+ device_->CreateVertexShader(vs_blob->GetBufferPointer(),
+ vs_blob->GetBufferSize(), nullptr, &vshdr);
+
+ D3D11_INPUT_ELEMENT_DESC layout_desc[] = {
+ {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0,
+ D3D11_INPUT_PER_VERTEX_DATA, 0},
+ {"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12,
+ D3D11_INPUT_PER_VERTEX_DATA, 0},
+ };
+
+ UINT elements = ARRAYSIZE(layout_desc);
+
+ // Create the input layout.
+ device_->CreateInputLayout(layout_desc, elements,
+ vs_blob->GetBufferPointer(),
+ vs_blob->GetBufferSize(), &layout);
+ }
+
+ const auto ps_blob = compile_shader(pixel_code, pixel_entry, pixel_model);
+ ID3D11PixelShader* pshdr = nullptr;
+ if (ps_blob) {
+ device_->CreatePixelShader(ps_blob->GetBufferPointer(),
+ ps_blob->GetBufferSize(), nullptr, &pshdr);
+ }
+
+ return std::make_shared<Effect>(vshdr, pshdr, layout);
+}
+
+Layer::Layer(const std::shared_ptr<Device>& device, bool flip)
+ : device_(device), flip_(flip) {
+ bounds_.x = bounds_.y = bounds_.width = bounds_.height = 0.0f;
+}
+
+Layer::~Layer() {}
+
+void Layer::attach(const std::shared_ptr<Composition>& parent) {
+ composition_ = parent;
+}
+
+std::shared_ptr<Composition> Layer::composition() const {
+ return composition_.lock();
+}
+
+Rect Layer::bounds() const {
+ return bounds_;
+}
+
+void Layer::move(float x, float y, float width, float height) {
+ bounds_.x = x;
+ bounds_.y = y;
+ bounds_.width = width;
+ bounds_.height = height;
+
+ // It's not efficient to create the quad everytime we move, but for now we're
+ // just trying to get something on-screen.
+ geometry_.reset();
+}
+
+void Layer::tick(double) {
+ // Nothing to update in the base class.
+}
+
+void Layer::render_texture(const std::shared_ptr<Context>& ctx,
+ const std::shared_ptr<Texture2D>& texture) {
+ if (!geometry_) {
+ geometry_ = device_->create_quad(bounds_.x, bounds_.y, bounds_.width,
+ bounds_.height, flip_);
+ }
+
+ if (geometry_ && texture) {
+ // We need a shader.
+ if (!effect_) {
+ effect_ = device_->create_default_effect();
+ }
+
+ // Bind our states/resource to the pipeline.
+ ScopedBinder<Geometry> quad_binder(ctx, geometry_);
+ ScopedBinder<Effect> fx_binder(ctx, effect_);
+ ScopedBinder<Texture2D> tex_binder(ctx, texture);
+
+ // Draw the quad.
+ geometry_->draw();
+ }
+}
+
+Composition::Composition(const std::shared_ptr<Device>& device,
+ int width,
+ int height)
+ : width_(width), height_(height), vsync_(true), device_(device) {
+ fps_ = 0.0;
+ time_ = 0.0;
+ frame_ = 0;
+ fps_start_ = GetTimeNow();
+}
+
+bool Composition::is_vsync() const {
+ return vsync_;
+}
+
+double Composition::time() const {
+ return time_;
+}
+
+double Composition::fps() const {
+ return fps_;
+}
+
+void Composition::add_layer(const std::shared_ptr<Layer>& layer) {
+ if (layer) {
+ layers_.push_back(layer);
+
+ // Attach ourselves as the parent.
+ layer->attach(shared_from_this());
+ }
+}
+
+bool Composition::remove_layer(const std::shared_ptr<Layer>& layer) {
+ size_t match = 0;
+ if (layer) {
+ for (auto i = layers_.begin(); i != layers_.end();) {
+ if ((*i).get() == layer.get()) {
+ i = layers_.erase(i);
+ match++;
+ } else {
+ i++;
+ }
+ }
+ }
+ return (match > 0);
+}
+
+void Composition::resize(bool vsync, int width, int height) {
+ vsync_ = vsync;
+ width_ = width;
+ height_ = height;
+}
+
+void Composition::tick(double t) {
+ time_ = t;
+ for (const auto& layer : layers_) {
+ layer->tick(t);
+ }
+}
+
+void Composition::render(const std::shared_ptr<Context>& ctx) {
+ // Use painter's algorithm and render our layers in order (not doing any dept
+ // or 3D here).
+ for (const auto& layer : layers_) {
+ layer->render(ctx);
+ }
+
+ frame_++;
+ const auto now = GetTimeNow();
+ if ((now - fps_start_) > 1000000) {
+ fps_ = frame_ / double((now - fps_start_) / 1000000.0);
+ frame_ = 0;
+ fps_start_ = now;
+ }
+}
+
+FrameBuffer::FrameBuffer(const std::shared_ptr<Device>& device)
+ : device_(device) {}
+
+void FrameBuffer::on_paint(void* shared_handle) {
+ // Did the shared texture change?
+ if (shared_buffer_ && shared_handle != shared_buffer_->share_handle()) {
+ shared_buffer_.reset();
+ }
+
+ // Open the shared texture.
+ if (!shared_buffer_) {
+ shared_buffer_ = device_->open_shared_texture((void*)shared_handle);
+ if (!shared_buffer_) {
+ LOG(ERROR) << "d3d11: Could not open shared texture!";
+ }
+ }
+}
+
+} // namespace d3d11
+} // namespace client
diff --git a/tests/cefclient/browser/osr_d3d11_win.h b/tests/cefclient/browser/osr_d3d11_win.h
new file mode 100644
index 00000000..f1190e38
--- /dev/null
+++ b/tests/cefclient/browser/osr_d3d11_win.h
@@ -0,0 +1,330 @@
+// Copyright 2018 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+//
+// Portions Copyright (c) 2018 Daktronics with the following MIT License:
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_OSR_D3D11_WIN_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_OSR_D3D11_WIN_H_
+#pragma once
+
+#include <d3d11_1.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "include/base/cef_macros.h"
+
+namespace client {
+namespace d3d11 {
+
+class Composition;
+class Context;
+class Effect;
+class Geometry;
+class SwapChain;
+class Texture2D;
+
+// Basic rect for floats.
+struct Rect {
+ float x;
+ float y;
+ float width;
+ float height;
+};
+
+template <class T>
+class ScopedBinder {
+ public:
+ ScopedBinder(const std::shared_ptr<Context>& ctx,
+ const std::shared_ptr<T>& target)
+ : target_(target) {
+ if (target_) {
+ target_->bind(ctx);
+ }
+ }
+ ~ScopedBinder() {
+ if (target_) {
+ target_->unbind();
+ }
+ }
+
+ private:
+ const std::shared_ptr<T> target_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedBinder);
+};
+
+class Context {
+ public:
+ Context(ID3D11DeviceContext*);
+
+ void flush();
+
+ operator ID3D11DeviceContext*() { return ctx_.get(); }
+
+ private:
+ const std::shared_ptr<ID3D11DeviceContext> ctx_;
+};
+
+// Encapsulate a D3D11 Device object.
+class Device {
+ public:
+ Device(ID3D11Device*, ID3D11DeviceContext*);
+
+ static std::shared_ptr<Device> create();
+
+ std::string adapter_name() const;
+
+ operator ID3D11Device*() { return device_.get(); }
+
+ std::shared_ptr<Context> immedidate_context();
+
+ std::shared_ptr<SwapChain> create_swapchain(HWND,
+ int width = 0,
+ int height = 0);
+
+ std::shared_ptr<Geometry> create_quad(float x,
+ float y,
+ float width,
+ float height,
+ bool flip = false);
+
+ std::shared_ptr<Texture2D> create_texture(int width,
+ int height,
+ DXGI_FORMAT format,
+ const void* data,
+ size_t row_stride);
+
+ std::shared_ptr<Texture2D> open_shared_texture(void*);
+
+ // Create some basic shaders so we can draw a textured-quad.
+ std::shared_ptr<Effect> create_default_effect();
+
+ std::shared_ptr<Effect> create_effect(const std::string& vertex_code,
+ const std::string& vertex_entry,
+ const std::string& vertex_model,
+ const std::string& pixel_code,
+ const std::string& pixel_entry,
+ const std::string& pixel_model);
+
+ private:
+ std::shared_ptr<ID3DBlob> compile_shader(const std::string& source_code,
+ const std::string& entry_point,
+ const std::string& model);
+
+ HMODULE lib_compiler_;
+
+ const std::shared_ptr<ID3D11Device> device_;
+ const std::shared_ptr<Context> ctx_;
+
+ DISALLOW_COPY_AND_ASSIGN(Device);
+};
+
+// Encapsulate a DXGI swapchain for a window.
+class SwapChain {
+ public:
+ SwapChain(IDXGISwapChain*,
+ ID3D11RenderTargetView*,
+ ID3D11SamplerState*,
+ ID3D11BlendState*);
+
+ void bind(const std::shared_ptr<Context>& ctx);
+ void unbind();
+
+ void clear(float red, float green, float blue, float alpha);
+
+ void present(int sync_interval);
+ void resize(int width, int height);
+
+ int width() const { return width_; }
+ int height() const { return height_; }
+
+ private:
+ const std::shared_ptr<ID3D11SamplerState> sampler_;
+ const std::shared_ptr<ID3D11BlendState> blender_;
+ const std::shared_ptr<IDXGISwapChain> swapchain_;
+ std::shared_ptr<ID3D11RenderTargetView> rtv_;
+ std::shared_ptr<Context> ctx_;
+ int width_;
+ int height_;
+
+ DISALLOW_COPY_AND_ASSIGN(SwapChain);
+};
+
+class Texture2D {
+ public:
+ Texture2D(ID3D11Texture2D* tex, ID3D11ShaderResourceView* srv);
+
+ void bind(std::shared_ptr<Context> const& ctx);
+ void unbind();
+
+ uint32_t width() const;
+ uint32_t height() const;
+ DXGI_FORMAT format() const;
+
+ bool has_mutex() const;
+
+ bool lock_key(uint64_t key, uint32_t timeout_ms);
+ void unlock_key(uint64_t key);
+
+ void* share_handle() const;
+
+ void copy_from(const std::shared_ptr<Texture2D>&);
+
+ private:
+ HANDLE share_handle_;
+
+ const std::shared_ptr<ID3D11Texture2D> texture_;
+ const std::shared_ptr<ID3D11ShaderResourceView> srv_;
+ std::shared_ptr<IDXGIKeyedMutex> keyed_mutex_;
+ std::shared_ptr<Context> ctx_;
+
+ DISALLOW_COPY_AND_ASSIGN(Texture2D);
+};
+
+class Effect {
+ public:
+ Effect(ID3D11VertexShader* vsh,
+ ID3D11PixelShader* psh,
+ ID3D11InputLayout* layout);
+
+ void bind(const std::shared_ptr<Context>& ctx);
+ void unbind();
+
+ private:
+ const std::shared_ptr<ID3D11VertexShader> vsh_;
+ const std::shared_ptr<ID3D11PixelShader> psh_;
+ const std::shared_ptr<ID3D11InputLayout> layout_;
+ std::shared_ptr<Context> ctx_;
+
+ DISALLOW_COPY_AND_ASSIGN(Effect);
+};
+
+class Geometry {
+ public:
+ Geometry(D3D_PRIMITIVE_TOPOLOGY primitive,
+ uint32_t vertices,
+ uint32_t stride,
+ ID3D11Buffer*);
+
+ void bind(const std::shared_ptr<Context>& ctx);
+ void unbind();
+
+ void draw();
+
+ private:
+ D3D_PRIMITIVE_TOPOLOGY primitive_;
+ uint32_t vertices_;
+ uint32_t stride_;
+ const std::shared_ptr<ID3D11Buffer> buffer_;
+ std::shared_ptr<Context> ctx_;
+
+ DISALLOW_COPY_AND_ASSIGN(Geometry);
+};
+
+// Abstraction for a 2D layer within a composition.
+class Layer {
+ public:
+ Layer(const std::shared_ptr<Device>& device, bool flip);
+ virtual ~Layer();
+
+ void attach(const std::shared_ptr<Composition>&);
+
+ // Uses normalized 0-1.0 coordinates.
+ virtual void move(float x, float y, float width, float height);
+
+ virtual void tick(double t);
+ virtual void render(const std::shared_ptr<Context>& ctx) = 0;
+
+ Rect bounds() const;
+
+ std::shared_ptr<Composition> composition() const;
+
+ protected:
+ // Helper method for derived classes to draw a textured-quad.
+ void render_texture(const std::shared_ptr<Context>& ctx,
+ const std::shared_ptr<Texture2D>& texture);
+
+ const std::shared_ptr<Device> device_;
+ const bool flip_;
+
+ Rect bounds_;
+ std::shared_ptr<Geometry> geometry_;
+ std::shared_ptr<Effect> effect_;
+
+ private:
+ std::weak_ptr<Composition> composition_;
+
+ DISALLOW_COPY_AND_ASSIGN(Layer);
+};
+
+// A collection of layers. Will render 1-N layers to a D3D11 device.
+class Composition : public std::enable_shared_from_this<Composition> {
+ public:
+ Composition(const std::shared_ptr<Device>& device,
+ int width = 0,
+ int height = 0);
+
+ int width() const { return width_; }
+ int height() const { return height_; }
+
+ double fps() const;
+ double time() const;
+
+ bool is_vsync() const;
+
+ void tick(double);
+ void render(const std::shared_ptr<Context>&);
+
+ void add_layer(const std::shared_ptr<Layer>& layer);
+ bool remove_layer(const std::shared_ptr<Layer>& layer);
+ void resize(bool vsync, int width, int height);
+
+ private:
+ int width_;
+ int height_;
+ uint32_t frame_;
+ int64_t fps_start_;
+ double fps_;
+ double time_;
+ bool vsync_;
+
+ const std::shared_ptr<Device> device_;
+ std::vector<std::shared_ptr<Layer>> layers_;
+
+ DISALLOW_COPY_AND_ASSIGN(Composition);
+};
+
+class FrameBuffer {
+ public:
+ explicit FrameBuffer(const std::shared_ptr<Device>& device);
+
+ // Called in response to CEF's OnAcceleratedPaint notification.
+ void on_paint(void* shared_handle);
+
+ // Returns what should be considered the front buffer.
+ std::shared_ptr<Texture2D> texture() const { return shared_buffer_; }
+
+ private:
+ const std::shared_ptr<Device> device_;
+ std::shared_ptr<Texture2D> shared_buffer_;
+
+ DISALLOW_COPY_AND_ASSIGN(FrameBuffer);
+};
+
+} // namespace d3d11
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_OSR_D3D11_WIN_H_
diff --git a/tests/cefclient/browser/osr_dragdrop_events.h b/tests/cefclient/browser/osr_dragdrop_events.h
new file mode 100644
index 00000000..db31e6bc
--- /dev/null
+++ b/tests/cefclient/browser/osr_dragdrop_events.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2014 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_OSR_DRAGDROP_EVENTS_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_OSR_DRAGDROP_EVENTS_H_
+#pragma once
+
+#include "include/cef_render_handler.h"
+#include "tests/cefclient/browser/client_handler.h"
+
+namespace client {
+
+class OsrDragEvents {
+ public:
+ virtual CefBrowserHost::DragOperationsMask OnDragEnter(
+ CefRefPtr<CefDragData> drag_data,
+ CefMouseEvent ev,
+ CefBrowserHost::DragOperationsMask effect) = 0;
+
+ virtual CefBrowserHost::DragOperationsMask OnDragOver(
+ CefMouseEvent ev,
+ CefBrowserHost::DragOperationsMask effect) = 0;
+
+ virtual void OnDragLeave() = 0;
+
+ virtual CefBrowserHost::DragOperationsMask OnDrop(
+ CefMouseEvent ev,
+ CefBrowserHost::DragOperationsMask effect) = 0;
+
+ protected:
+ virtual ~OsrDragEvents() {}
+};
+
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_OSR_DRAGDROP_EVENTS_H_
diff --git a/tests/cefclient/browser/osr_dragdrop_win.cc b/tests/cefclient/browser/osr_dragdrop_win.cc
new file mode 100644
index 00000000..04d69948
--- /dev/null
+++ b/tests/cefclient/browser/osr_dragdrop_win.cc
@@ -0,0 +1,677 @@
+// Copyright (c) 2014 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/osr_dragdrop_win.h"
+
+#if defined(CEF_USE_ATL)
+
+#include <shellapi.h>
+#include <shlobj.h>
+#include <windowsx.h>
+
+#include <algorithm>
+#include <string>
+
+#include "include/wrapper/cef_helpers.h"
+#include "tests/cefclient/browser/bytes_write_handler.h"
+#include "tests/cefclient/browser/resource.h"
+#include "tests/shared/browser/util_win.h"
+
+namespace client {
+
+namespace {
+
+DWORD DragOperationToDropEffect(CefRenderHandler::DragOperation allowed_ops) {
+ DWORD effect = DROPEFFECT_NONE;
+ if (allowed_ops & DRAG_OPERATION_COPY) {
+ effect |= DROPEFFECT_COPY;
+ }
+ if (allowed_ops & DRAG_OPERATION_LINK) {
+ effect |= DROPEFFECT_LINK;
+ }
+ if (allowed_ops & DRAG_OPERATION_MOVE) {
+ effect |= DROPEFFECT_MOVE;
+ }
+ return effect;
+}
+
+CefRenderHandler::DragOperationsMask DropEffectToDragOperation(DWORD effect) {
+ DWORD operation = DRAG_OPERATION_NONE;
+ if (effect & DROPEFFECT_COPY) {
+ operation |= DRAG_OPERATION_COPY;
+ }
+ if (effect & DROPEFFECT_LINK) {
+ operation |= DRAG_OPERATION_LINK;
+ }
+ if (effect & DROPEFFECT_MOVE) {
+ operation |= DRAG_OPERATION_MOVE;
+ }
+ return static_cast<CefRenderHandler::DragOperationsMask>(operation);
+}
+
+CefMouseEvent ToMouseEvent(POINTL p, DWORD key_state, HWND hWnd) {
+ CefMouseEvent ev;
+ POINT screen_point = {p.x, p.y};
+ ScreenToClient(hWnd, &screen_point);
+ ev.x = screen_point.x;
+ ev.y = screen_point.y;
+ ev.modifiers = GetCefMouseModifiers(key_state);
+ return ev;
+}
+
+void GetStorageForBytes(STGMEDIUM* storage, const void* data, size_t bytes) {
+ HANDLE handle = GlobalAlloc(GPTR, static_cast<int>(bytes));
+ if (handle) {
+ memcpy(handle, data, bytes);
+ }
+
+ storage->hGlobal = handle;
+ storage->tymed = TYMED_HGLOBAL;
+ storage->pUnkForRelease = nullptr;
+}
+
+template <typename T>
+void GetStorageForString(STGMEDIUM* stgmed, const std::basic_string<T>& data) {
+ GetStorageForBytes(
+ stgmed, data.c_str(),
+ (data.size() + 1) * sizeof(typename std::basic_string<T>::value_type));
+}
+
+void GetStorageForFileDescriptor(STGMEDIUM* storage,
+ const std::wstring& file_name) {
+ DCHECK(!file_name.empty());
+ HANDLE hdata = GlobalAlloc(GPTR, sizeof(FILEGROUPDESCRIPTOR));
+
+ FILEGROUPDESCRIPTOR* descriptor =
+ reinterpret_cast<FILEGROUPDESCRIPTOR*>(hdata);
+ descriptor->cItems = 1;
+ descriptor->fgd[0].dwFlags = FD_LINKUI;
+ wcsncpy_s(descriptor->fgd[0].cFileName, MAX_PATH, file_name.c_str(),
+ std::min(file_name.size(), static_cast<size_t>(MAX_PATH - 1u)));
+
+ storage->tymed = TYMED_HGLOBAL;
+ storage->hGlobal = hdata;
+ storage->pUnkForRelease = nullptr;
+}
+
+// Helper method for converting from text/html to MS CF_HTML.
+// Documentation for the CF_HTML format is available at
+// http://msdn.microsoft.com/en-us/library/aa767917(VS.85).aspx
+std::string HtmlToCFHtml(const std::string& html, const std::string& base_url) {
+ if (html.empty()) {
+ return std::string();
+ }
+
+#define MAX_DIGITS 10
+#define MAKE_NUMBER_FORMAT_1(digits) MAKE_NUMBER_FORMAT_2(digits)
+#define MAKE_NUMBER_FORMAT_2(digits) "%0" #digits "u"
+#define NUMBER_FORMAT MAKE_NUMBER_FORMAT_1(MAX_DIGITS)
+
+ static const char* header =
+ "Version:0.9\r\n"
+ "StartHTML:" NUMBER_FORMAT
+ "\r\n"
+ "EndHTML:" NUMBER_FORMAT
+ "\r\n"
+ "StartFragment:" NUMBER_FORMAT
+ "\r\n"
+ "EndFragment:" NUMBER_FORMAT "\r\n";
+ static const char* source_url_prefix = "SourceURL:";
+
+ static const char* start_markup = "<html>\r\n<body>\r\n<!--StartFragment-->";
+ static const char* end_markup = "<!--EndFragment-->\r\n</body>\r\n</html>";
+
+ // Calculate offsets
+ size_t start_html_offset =
+ strlen(header) - strlen(NUMBER_FORMAT) * 4 + MAX_DIGITS * 4;
+ if (!base_url.empty()) {
+ start_html_offset +=
+ strlen(source_url_prefix) + base_url.length() + 2; // Add 2 for \r\n.
+ }
+ size_t start_fragment_offset = start_html_offset + strlen(start_markup);
+ size_t end_fragment_offset = start_fragment_offset + html.length();
+ size_t end_html_offset = end_fragment_offset + strlen(end_markup);
+ char raw_result[1024];
+ _snprintf(raw_result, sizeof(1024), header, start_html_offset,
+ end_html_offset, start_fragment_offset, end_fragment_offset);
+ std::string result = raw_result;
+ if (!base_url.empty()) {
+ result.append(source_url_prefix);
+ result.append(base_url);
+ result.append("\r\n");
+ }
+ result.append(start_markup);
+ result.append(html);
+ result.append(end_markup);
+
+#undef MAX_DIGITS
+#undef MAKE_NUMBER_FORMAT_1
+#undef MAKE_NUMBER_FORMAT_2
+#undef NUMBER_FORMAT
+
+ return result;
+}
+
+void CFHtmlExtractMetadata(const std::string& cf_html,
+ std::string* base_url,
+ size_t* html_start,
+ size_t* fragment_start,
+ size_t* fragment_end) {
+ // Obtain base_url if present.
+ if (base_url) {
+ static std::string src_url_str("SourceURL:");
+ size_t line_start = cf_html.find(src_url_str);
+ if (line_start != std::string::npos) {
+ size_t src_end = cf_html.find("\n", line_start);
+ size_t src_start = line_start + src_url_str.length();
+ if (src_end != std::string::npos && src_start != std::string::npos) {
+ *base_url = cf_html.substr(src_start, src_end - src_start);
+ }
+ }
+ }
+
+ // Find the markup between "<!--StartFragment-->" and "<!--EndFragment-->".
+ // If the comments cannot be found, like copying from OpenOffice Writer,
+ // we simply fall back to using StartFragment/EndFragment bytecount values
+ // to determine the fragment indexes.
+ std::string cf_html_lower = cf_html;
+ size_t markup_start = cf_html_lower.find("<html", 0);
+ if (html_start) {
+ *html_start = markup_start;
+ }
+ size_t tag_start = cf_html.find("<!--StartFragment", markup_start);
+ if (tag_start == std::string::npos) {
+ static std::string start_fragment_str("StartFragment:");
+ size_t start_fragment_start = cf_html.find(start_fragment_str);
+ if (start_fragment_start != std::string::npos) {
+ *fragment_start =
+ static_cast<size_t>(atoi(cf_html.c_str() + start_fragment_start +
+ start_fragment_str.length()));
+ }
+
+ static std::string end_fragment_str("EndFragment:");
+ size_t end_fragment_start = cf_html.find(end_fragment_str);
+ if (end_fragment_start != std::string::npos) {
+ *fragment_end = static_cast<size_t>(atoi(
+ cf_html.c_str() + end_fragment_start + end_fragment_str.length()));
+ }
+ } else {
+ *fragment_start = cf_html.find('>', tag_start) + 1;
+ size_t tag_end = cf_html.rfind("<!--EndFragment", std::string::npos);
+ *fragment_end = cf_html.rfind('<', tag_end);
+ }
+}
+
+void CFHtmlToHtml(const std::string& cf_html,
+ std::string* html,
+ std::string* base_url) {
+ size_t frag_start = std::string::npos;
+ size_t frag_end = std::string::npos;
+
+ CFHtmlExtractMetadata(cf_html, base_url, nullptr, &frag_start, &frag_end);
+
+ if (html && frag_start != std::string::npos &&
+ frag_end != std::string::npos) {
+ *html = cf_html.substr(frag_start, frag_end - frag_start);
+ }
+}
+
+const DWORD moz_url_format = ::RegisterClipboardFormat(L"text/x-moz-url");
+const DWORD html_format = ::RegisterClipboardFormat(L"HTML Format");
+const DWORD file_desc_format = ::RegisterClipboardFormat(CFSTR_FILEDESCRIPTOR);
+const DWORD file_contents_format =
+ ::RegisterClipboardFormat(CFSTR_FILECONTENTS);
+
+bool DragDataToDataObject(CefRefPtr<CefDragData> drag_data,
+ IDataObject** data_object) {
+ const int kMaxDataObjects = 10;
+ FORMATETC fmtetcs[kMaxDataObjects];
+ STGMEDIUM stgmeds[kMaxDataObjects];
+ FORMATETC fmtetc = {0, nullptr, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
+ int curr_index = 0;
+ CefString text = drag_data->GetFragmentText();
+ if (!text.empty()) {
+ fmtetc.cfFormat = CF_UNICODETEXT;
+ fmtetcs[curr_index] = fmtetc;
+ GetStorageForString(&stgmeds[curr_index], text.ToWString());
+ curr_index++;
+ }
+ if (drag_data->IsLink() && !drag_data->GetLinkURL().empty()) {
+ std::wstring x_moz_url_str = drag_data->GetLinkURL().ToWString();
+ x_moz_url_str += '\n';
+ x_moz_url_str += drag_data->GetLinkTitle().ToWString();
+ fmtetc.cfFormat = moz_url_format;
+ fmtetcs[curr_index] = fmtetc;
+ GetStorageForString(&stgmeds[curr_index], x_moz_url_str);
+ curr_index++;
+ }
+ CefString html = drag_data->GetFragmentHtml();
+ if (!html.empty()) {
+ CefString base_url = drag_data->GetFragmentBaseURL();
+ std::string cfhtml = HtmlToCFHtml(html.ToString(), base_url.ToString());
+ fmtetc.cfFormat = html_format;
+ fmtetcs[curr_index] = fmtetc;
+ GetStorageForString(&stgmeds[curr_index], cfhtml);
+ curr_index++;
+ }
+
+ size_t bufferSize = drag_data->GetFileContents(nullptr);
+ if (bufferSize) {
+ CefRefPtr<BytesWriteHandler> handler = new BytesWriteHandler(bufferSize);
+ CefRefPtr<CefStreamWriter> writer =
+ CefStreamWriter::CreateForHandler(handler.get());
+ drag_data->GetFileContents(writer);
+ DCHECK_EQ(handler->GetDataSize(), static_cast<int64>(bufferSize));
+ CefString fileName = drag_data->GetFileName();
+ GetStorageForFileDescriptor(&stgmeds[curr_index], fileName.ToWString());
+ fmtetc.cfFormat = file_desc_format;
+ fmtetcs[curr_index] = fmtetc;
+ curr_index++;
+ GetStorageForBytes(&stgmeds[curr_index], handler->GetData(),
+ handler->GetDataSize());
+ fmtetc.cfFormat = file_contents_format;
+ fmtetcs[curr_index] = fmtetc;
+ curr_index++;
+ }
+ DCHECK_LT(curr_index, kMaxDataObjects);
+
+ CComPtr<DataObjectWin> obj =
+ DataObjectWin::Create(fmtetcs, stgmeds, curr_index);
+ (*data_object) = obj.Detach();
+ return true;
+}
+
+CefRefPtr<CefDragData> DataObjectToDragData(IDataObject* data_object) {
+ CefRefPtr<CefDragData> drag_data = CefDragData::Create();
+ IEnumFORMATETC* enumFormats = nullptr;
+ HRESULT res = data_object->EnumFormatEtc(DATADIR_GET, &enumFormats);
+ if (res != S_OK) {
+ return drag_data;
+ }
+ enumFormats->Reset();
+ const int kCelt = 10;
+
+ ULONG celtFetched;
+ do {
+ celtFetched = kCelt;
+ FORMATETC rgelt[kCelt];
+ res = enumFormats->Next(kCelt, rgelt, &celtFetched);
+ for (unsigned i = 0; i < celtFetched; i++) {
+ CLIPFORMAT format = rgelt[i].cfFormat;
+ if (!(format == CF_UNICODETEXT || format == CF_TEXT ||
+ format == moz_url_format || format == html_format ||
+ format == CF_HDROP) ||
+ rgelt[i].tymed != TYMED_HGLOBAL) {
+ continue;
+ }
+ STGMEDIUM medium;
+ if (data_object->GetData(&rgelt[i], &medium) == S_OK) {
+ if (!medium.hGlobal) {
+ ReleaseStgMedium(&medium);
+ continue;
+ }
+ void* hGlobal = GlobalLock(medium.hGlobal);
+ if (!hGlobal) {
+ ReleaseStgMedium(&medium);
+ continue;
+ }
+ if (format == CF_UNICODETEXT) {
+ CefString text;
+ text.FromWString((std::wstring::value_type*)hGlobal);
+ drag_data->SetFragmentText(text);
+ } else if (format == CF_TEXT) {
+ CefString text;
+ text.FromString((std::string::value_type*)hGlobal);
+ drag_data->SetFragmentText(text);
+ } else if (format == moz_url_format) {
+ std::wstring html((std::wstring::value_type*)hGlobal);
+ size_t pos = html.rfind('\n');
+ CefString url(html.substr(0, pos));
+ CefString title(html.substr(pos + 1));
+ drag_data->SetLinkURL(url);
+ drag_data->SetLinkTitle(title);
+ } else if (format == html_format) {
+ std::string cf_html((std::string::value_type*)hGlobal);
+ std::string base_url;
+ std::string html;
+ CFHtmlToHtml(cf_html, &html, &base_url);
+ drag_data->SetFragmentHtml(html);
+ drag_data->SetFragmentBaseURL(base_url);
+ }
+ if (format == CF_HDROP) {
+ HDROP hdrop = (HDROP)hGlobal;
+ const int kMaxFilenameLen = 4096;
+ const unsigned num_files = DragQueryFileW(hdrop, 0xffffffff, 0, 0);
+ for (unsigned int x = 0; x < num_files; ++x) {
+ wchar_t filename[kMaxFilenameLen];
+ if (!DragQueryFileW(hdrop, x, filename, kMaxFilenameLen)) {
+ continue;
+ }
+ WCHAR* name = wcsrchr(filename, '\\');
+ drag_data->AddFile(filename, (name ? name + 1 : filename));
+ }
+ }
+ if (medium.hGlobal) {
+ GlobalUnlock(medium.hGlobal);
+ }
+ if (format == CF_HDROP) {
+ DragFinish((HDROP)hGlobal);
+ } else {
+ ReleaseStgMedium(&medium);
+ }
+ }
+ }
+ } while (res == S_OK);
+ enumFormats->Release();
+ return drag_data;
+}
+
+} // namespace
+
+CComPtr<DropTargetWin> DropTargetWin::Create(OsrDragEvents* callback,
+ HWND hWnd) {
+ return CComPtr<DropTargetWin>(new DropTargetWin(callback, hWnd));
+}
+
+HRESULT DropTargetWin::DragEnter(IDataObject* data_object,
+ DWORD key_state,
+ POINTL cursor_position,
+ DWORD* effect) {
+ if (!callback_) {
+ return E_UNEXPECTED;
+ }
+
+ CefRefPtr<CefDragData> drag_data = current_drag_data_;
+ if (!drag_data) {
+ drag_data = DataObjectToDragData(data_object);
+ }
+ CefMouseEvent ev = ToMouseEvent(cursor_position, key_state, hWnd_);
+ CefBrowserHost::DragOperationsMask mask = DropEffectToDragOperation(*effect);
+ mask = callback_->OnDragEnter(drag_data, ev, mask);
+ *effect = DragOperationToDropEffect(mask);
+ return S_OK;
+}
+
+CefBrowserHost::DragOperationsMask DropTargetWin::StartDragging(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefDragData> drag_data,
+ CefRenderHandler::DragOperationsMask allowed_ops,
+ int x,
+ int y) {
+ CComPtr<IDataObject> dataObject;
+ DWORD resEffect = DROPEFFECT_NONE;
+ if (DragDataToDataObject(drag_data, &dataObject)) {
+ CComPtr<DropSourceWin> dropSource = DropSourceWin::Create();
+ DWORD effect = DragOperationToDropEffect(allowed_ops);
+ current_drag_data_ = drag_data->Clone();
+ current_drag_data_->ResetFileContents();
+ HRESULT res = DoDragDrop(dataObject, dropSource, effect, &resEffect);
+ if (res != DRAGDROP_S_DROP) {
+ resEffect = DROPEFFECT_NONE;
+ }
+ current_drag_data_ = nullptr;
+ }
+ return DropEffectToDragOperation(resEffect);
+}
+
+HRESULT DropTargetWin::DragOver(DWORD key_state,
+ POINTL cursor_position,
+ DWORD* effect) {
+ if (!callback_) {
+ return E_UNEXPECTED;
+ }
+ CefMouseEvent ev = ToMouseEvent(cursor_position, key_state, hWnd_);
+ CefBrowserHost::DragOperationsMask mask = DropEffectToDragOperation(*effect);
+ mask = callback_->OnDragOver(ev, mask);
+ *effect = DragOperationToDropEffect(mask);
+ return S_OK;
+}
+
+HRESULT DropTargetWin::DragLeave() {
+ if (!callback_) {
+ return E_UNEXPECTED;
+ }
+ callback_->OnDragLeave();
+ return S_OK;
+}
+
+HRESULT DropTargetWin::Drop(IDataObject* data_object,
+ DWORD key_state,
+ POINTL cursor_position,
+ DWORD* effect) {
+ if (!callback_) {
+ return E_UNEXPECTED;
+ }
+ CefMouseEvent ev = ToMouseEvent(cursor_position, key_state, hWnd_);
+ CefBrowserHost::DragOperationsMask mask = DropEffectToDragOperation(*effect);
+ mask = callback_->OnDrop(ev, mask);
+ *effect = DragOperationToDropEffect(mask);
+ return S_OK;
+}
+
+CComPtr<DropSourceWin> DropSourceWin::Create() {
+ return CComPtr<DropSourceWin>(new DropSourceWin());
+}
+
+HRESULT DropSourceWin::GiveFeedback(DWORD dwEffect) {
+ return DRAGDROP_S_USEDEFAULTCURSORS;
+}
+
+HRESULT DropSourceWin::QueryContinueDrag(BOOL fEscapePressed,
+ DWORD grfKeyState) {
+ if (fEscapePressed) {
+ return DRAGDROP_S_CANCEL;
+ }
+
+ if (!(grfKeyState & MK_LBUTTON)) {
+ return DRAGDROP_S_DROP;
+ }
+
+ return S_OK;
+}
+
+HRESULT DragEnumFormatEtc::CreateEnumFormatEtc(
+ UINT cfmt,
+ FORMATETC* afmt,
+ IEnumFORMATETC** ppEnumFormatEtc) {
+ if (cfmt == 0 || afmt == 0 || ppEnumFormatEtc == 0) {
+ return E_INVALIDARG;
+ }
+
+ *ppEnumFormatEtc = new DragEnumFormatEtc(afmt, cfmt);
+
+ return (*ppEnumFormatEtc) ? S_OK : E_OUTOFMEMORY;
+}
+
+HRESULT DragEnumFormatEtc::Next(ULONG celt,
+ FORMATETC* pFormatEtc,
+ ULONG* pceltFetched) {
+ ULONG copied = 0;
+
+ // copy the FORMATETC structures into the caller's buffer
+ while (m_nIndex < m_nNumFormats && copied < celt) {
+ DeepCopyFormatEtc(&pFormatEtc[copied], &m_pFormatEtc[m_nIndex]);
+ copied++;
+ m_nIndex++;
+ }
+
+ // store result
+ if (pceltFetched != 0) {
+ *pceltFetched = copied;
+ }
+
+ // did we copy all that was requested?
+ return (copied == celt) ? S_OK : S_FALSE;
+}
+HRESULT DragEnumFormatEtc::Skip(ULONG celt) {
+ m_nIndex += celt;
+ return (m_nIndex <= m_nNumFormats) ? S_OK : S_FALSE;
+}
+HRESULT DragEnumFormatEtc::Reset(void) {
+ m_nIndex = 0;
+ return S_OK;
+}
+HRESULT DragEnumFormatEtc::Clone(IEnumFORMATETC** ppEnumFormatEtc) {
+ HRESULT hResult;
+
+ // make a duplicate enumerator
+ hResult = CreateEnumFormatEtc(m_nNumFormats, m_pFormatEtc, ppEnumFormatEtc);
+
+ if (hResult == S_OK) {
+ // manually set the index state
+ reinterpret_cast<DragEnumFormatEtc*>(*ppEnumFormatEtc)->m_nIndex = m_nIndex;
+ }
+
+ return hResult;
+}
+
+DragEnumFormatEtc::DragEnumFormatEtc(FORMATETC* pFormatEtc, int nNumFormats) {
+ AddRef();
+
+ m_nIndex = 0;
+ m_nNumFormats = nNumFormats;
+ m_pFormatEtc = new FORMATETC[nNumFormats];
+
+ // make a new copy of each FORMATETC structure
+ for (int i = 0; i < nNumFormats; i++) {
+ DeepCopyFormatEtc(&m_pFormatEtc[i], &pFormatEtc[i]);
+ }
+}
+DragEnumFormatEtc::~DragEnumFormatEtc() {
+ // first free any DVTARGETDEVICE structures
+ for (ULONG i = 0; i < m_nNumFormats; i++) {
+ if (m_pFormatEtc[i].ptd) {
+ CoTaskMemFree(m_pFormatEtc[i].ptd);
+ }
+ }
+
+ // now free the main array
+ delete[] m_pFormatEtc;
+}
+
+void DragEnumFormatEtc::DeepCopyFormatEtc(FORMATETC* dest, FORMATETC* source) {
+ // copy the source FORMATETC into dest
+ *dest = *source;
+ if (source->ptd) {
+ // allocate memory for the DVTARGETDEVICE if necessary
+ dest->ptd = reinterpret_cast<DVTARGETDEVICE*>(
+ CoTaskMemAlloc(sizeof(DVTARGETDEVICE)));
+
+ // copy the contents of the source DVTARGETDEVICE into dest->ptd
+ *(dest->ptd) = *(source->ptd);
+ }
+}
+
+CComPtr<DataObjectWin> DataObjectWin::Create(FORMATETC* fmtetc,
+ STGMEDIUM* stgmed,
+ int count) {
+ return CComPtr<DataObjectWin>(new DataObjectWin(fmtetc, stgmed, count));
+}
+
+HRESULT DataObjectWin::GetDataHere(FORMATETC* pFormatEtc, STGMEDIUM* pmedium) {
+ return E_NOTIMPL;
+}
+
+HRESULT DataObjectWin::QueryGetData(FORMATETC* pFormatEtc) {
+ return (LookupFormatEtc(pFormatEtc) == -1) ? DV_E_FORMATETC : S_OK;
+}
+
+HRESULT DataObjectWin::GetCanonicalFormatEtc(FORMATETC* pFormatEct,
+ FORMATETC* pFormatEtcOut) {
+ pFormatEtcOut->ptd = nullptr;
+ return E_NOTIMPL;
+}
+
+HRESULT DataObjectWin::SetData(FORMATETC* pFormatEtc,
+ STGMEDIUM* pMedium,
+ BOOL fRelease) {
+ return E_NOTIMPL;
+}
+
+HRESULT DataObjectWin::DAdvise(FORMATETC* pFormatEtc,
+ DWORD advf,
+ IAdviseSink*,
+ DWORD*) {
+ return E_NOTIMPL;
+}
+
+HRESULT DataObjectWin::DUnadvise(DWORD dwConnection) {
+ return E_NOTIMPL;
+}
+
+HRESULT DataObjectWin::EnumDAdvise(IEnumSTATDATA** ppEnumAdvise) {
+ return E_NOTIMPL;
+}
+
+HRESULT DataObjectWin::EnumFormatEtc(DWORD dwDirection,
+ IEnumFORMATETC** ppEnumFormatEtc) {
+ return DragEnumFormatEtc::CreateEnumFormatEtc(m_nNumFormats, m_pFormatEtc,
+ ppEnumFormatEtc);
+}
+
+HRESULT DataObjectWin::GetData(FORMATETC* pFormatEtc, STGMEDIUM* pMedium) {
+ int idx;
+
+ // try to match the specified FORMATETC with one of our supported formats
+ if ((idx = LookupFormatEtc(pFormatEtc)) == -1) {
+ return DV_E_FORMATETC;
+ }
+
+ // found a match - transfer data into supplied storage medium
+ pMedium->tymed = m_pFormatEtc[idx].tymed;
+ pMedium->pUnkForRelease = 0;
+
+ // copy the data into the caller's storage medium
+ switch (m_pFormatEtc[idx].tymed) {
+ case TYMED_HGLOBAL:
+ pMedium->hGlobal = DupGlobalMem(m_pStgMedium[idx].hGlobal);
+ break;
+
+ default:
+ return DV_E_FORMATETC;
+ }
+ return S_OK;
+}
+
+HGLOBAL DataObjectWin::DupGlobalMem(HGLOBAL hMem) {
+ DWORD len = GlobalSize(hMem);
+ PVOID source = GlobalLock(hMem);
+ PVOID dest = GlobalAlloc(GMEM_FIXED, len);
+
+ memcpy(dest, source, len);
+ GlobalUnlock(hMem);
+ return dest;
+}
+
+int DataObjectWin::LookupFormatEtc(FORMATETC* pFormatEtc) {
+ // check each of our formats in turn to see if one matches
+ for (int i = 0; i < m_nNumFormats; i++) {
+ if ((m_pFormatEtc[i].tymed & pFormatEtc->tymed) &&
+ m_pFormatEtc[i].cfFormat == pFormatEtc->cfFormat &&
+ m_pFormatEtc[i].dwAspect == pFormatEtc->dwAspect) {
+ // return index of stored format
+ return i;
+ }
+ }
+
+ // error, format not found
+ return -1;
+}
+
+DataObjectWin::DataObjectWin(FORMATETC* fmtetc, STGMEDIUM* stgmed, int count)
+ : ref_count_(0) {
+ m_nNumFormats = count;
+
+ m_pFormatEtc = new FORMATETC[count];
+ m_pStgMedium = new STGMEDIUM[count];
+
+ for (int i = 0; i < count; i++) {
+ m_pFormatEtc[i] = fmtetc[i];
+ m_pStgMedium[i] = stgmed[i];
+ }
+}
+
+} // namespace client
+
+#endif // defined(CEF_USE_ATL)
diff --git a/tests/cefclient/browser/osr_dragdrop_win.h b/tests/cefclient/browser/osr_dragdrop_win.h
new file mode 100644
index 00000000..29ef2605
--- /dev/null
+++ b/tests/cefclient/browser/osr_dragdrop_win.h
@@ -0,0 +1,193 @@
+// Copyright (c) 2014 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_OSR_DRAGDROP_WIN_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_OSR_DRAGDROP_WIN_H_
+#pragma once
+
+// When generating projects with CMake the CEF_USE_ATL value will be defined
+// automatically if using a supported Visual Studio version. Pass -DUSE_ATL=OFF
+// to the CMake command-line to disable use of ATL.
+// Uncomment this line to manually enable ATL support.
+// #define CEF_USE_ATL 1
+
+#if defined(CEF_USE_ATL)
+
+#include <atlcomcli.h>
+#include <objidl.h>
+#include <stdio.h>
+
+#include "tests/cefclient/browser/osr_dragdrop_events.h"
+
+namespace client {
+
+#define DEFAULT_QUERY_INTERFACE(__Class) \
+ HRESULT __stdcall QueryInterface(const IID& iid, void** object) { \
+ *object = nullptr; \
+ if (IsEqualIID(iid, IID_IUnknown)) { \
+ IUnknown* obj = this; \
+ *object = obj; \
+ } else if (IsEqualIID(iid, IID_##__Class)) { \
+ __Class* obj = this; \
+ *object = obj; \
+ } else { \
+ return E_NOINTERFACE; \
+ } \
+ AddRef(); \
+ return S_OK; \
+ }
+#define IUNKNOWN_IMPLEMENTATION \
+ ULONG __stdcall AddRef() { \
+ return ++ref_count_; \
+ } \
+ ULONG __stdcall Release() { \
+ if (--ref_count_ == 0) { \
+ delete this; \
+ return 0U; \
+ } \
+ return ref_count_; \
+ } \
+ \
+ protected: \
+ ULONG ref_count_;
+
+class DropTargetWin : public IDropTarget {
+ public:
+ static CComPtr<DropTargetWin> Create(OsrDragEvents* callback, HWND hWnd);
+
+ CefBrowserHost::DragOperationsMask StartDragging(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefDragData> drag_data,
+ CefRenderHandler::DragOperationsMask allowed_ops,
+ int x,
+ int y);
+
+ // IDropTarget implementation:
+ HRESULT __stdcall DragEnter(IDataObject* data_object,
+ DWORD key_state,
+ POINTL cursor_position,
+ DWORD* effect);
+
+ HRESULT __stdcall DragOver(DWORD key_state,
+ POINTL cursor_position,
+ DWORD* effect);
+
+ HRESULT __stdcall DragLeave();
+
+ HRESULT __stdcall Drop(IDataObject* data_object,
+ DWORD key_state,
+ POINTL cursor_position,
+ DWORD* effect);
+
+ DEFAULT_QUERY_INTERFACE(IDropTarget)
+ IUNKNOWN_IMPLEMENTATION
+
+ protected:
+ DropTargetWin(OsrDragEvents* callback, HWND hWnd)
+ : ref_count_(0), callback_(callback), hWnd_(hWnd) {}
+ virtual ~DropTargetWin() {}
+
+ private:
+ OsrDragEvents* callback_;
+ HWND hWnd_;
+
+ CefRefPtr<CefDragData> current_drag_data_;
+};
+
+class DropSourceWin : public IDropSource {
+ public:
+ static CComPtr<DropSourceWin> Create();
+
+ // IDropSource implementation:
+ HRESULT __stdcall GiveFeedback(DWORD dwEffect);
+
+ HRESULT __stdcall QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState);
+
+ DEFAULT_QUERY_INTERFACE(IDropSource)
+ IUNKNOWN_IMPLEMENTATION
+
+ protected:
+ explicit DropSourceWin() : ref_count_(0) {}
+ virtual ~DropSourceWin() {}
+};
+
+class DragEnumFormatEtc : public IEnumFORMATETC {
+ public:
+ static HRESULT CreateEnumFormatEtc(UINT cfmt,
+ FORMATETC* afmt,
+ IEnumFORMATETC** ppEnumFormatEtc);
+
+ //
+ // IEnumFormatEtc members
+ //
+ HRESULT __stdcall Next(ULONG celt,
+ FORMATETC* pFormatEtc,
+ ULONG* pceltFetched);
+ HRESULT __stdcall Skip(ULONG celt);
+ HRESULT __stdcall Reset(void);
+ HRESULT __stdcall Clone(IEnumFORMATETC** ppEnumFormatEtc);
+
+ //
+ // Construction / Destruction
+ //
+ DragEnumFormatEtc(FORMATETC* pFormatEtc, int nNumFormats);
+ virtual ~DragEnumFormatEtc();
+
+ static void DeepCopyFormatEtc(FORMATETC* dest, FORMATETC* source);
+
+ DEFAULT_QUERY_INTERFACE(IEnumFORMATETC)
+ IUNKNOWN_IMPLEMENTATION
+
+ private:
+ ULONG m_nIndex; // current enumerator index
+ ULONG m_nNumFormats; // number of FORMATETC members
+ FORMATETC* m_pFormatEtc; // array of FORMATETC objects
+};
+
+class DataObjectWin : public IDataObject {
+ public:
+ static CComPtr<DataObjectWin> Create(FORMATETC* fmtetc,
+ STGMEDIUM* stgmed,
+ int count);
+
+ // IDataObject memberS
+ HRESULT __stdcall GetDataHere(FORMATETC* pFormatEtc, STGMEDIUM* pmedium);
+ HRESULT __stdcall QueryGetData(FORMATETC* pFormatEtc);
+ HRESULT __stdcall GetCanonicalFormatEtc(FORMATETC* pFormatEct,
+ FORMATETC* pFormatEtcOut);
+ HRESULT __stdcall SetData(FORMATETC* pFormatEtc,
+ STGMEDIUM* pMedium,
+ BOOL fRelease);
+ HRESULT __stdcall DAdvise(FORMATETC* pFormatEtc,
+ DWORD advf,
+ IAdviseSink*,
+ DWORD*);
+ HRESULT __stdcall DUnadvise(DWORD dwConnection);
+ HRESULT __stdcall EnumDAdvise(IEnumSTATDATA** ppEnumAdvise);
+
+ HRESULT __stdcall EnumFormatEtc(DWORD dwDirection,
+ IEnumFORMATETC** ppEnumFormatEtc);
+ HRESULT __stdcall GetData(FORMATETC* pFormatEtc, STGMEDIUM* pMedium);
+
+ DEFAULT_QUERY_INTERFACE(IDataObject)
+ IUNKNOWN_IMPLEMENTATION
+
+ protected:
+ int m_nNumFormats;
+ FORMATETC* m_pFormatEtc;
+ STGMEDIUM* m_pStgMedium;
+
+ static HGLOBAL DupGlobalMem(HGLOBAL hMem);
+
+ int LookupFormatEtc(FORMATETC* pFormatEtc);
+
+ explicit DataObjectWin(FORMATETC* fmtetc, STGMEDIUM* stgmed, int count);
+ virtual ~DataObjectWin() {}
+};
+
+} // namespace client
+
+#endif // defined(CEF_USE_ATL)
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_OSR_DRAGDROP_WIN_H_
diff --git a/tests/cefclient/browser/osr_ime_handler_win.cc b/tests/cefclient/browser/osr_ime_handler_win.cc
new file mode 100644
index 00000000..3f0921cf
--- /dev/null
+++ b/tests/cefclient/browser/osr_ime_handler_win.cc
@@ -0,0 +1,404 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. Portions copyright
+// 2013 The Chromium Authors. All rights reserved. Use of this source code is
+// governed by a BSD-style license that can be found in the LICENSE file.
+
+// Implementation based on ui/base/ime/win/imm32_manager.cc from Chromium.
+
+#include <msctf.h>
+#include <windowsx.h>
+
+#include "include/base/cef_build.h"
+#include "tests/cefclient/browser/osr_ime_handler_win.h"
+#include "tests/cefclient/browser/resource.h"
+#include "tests/shared/browser/geometry_util.h"
+#include "tests/shared/browser/main_message_loop.h"
+#include "tests/shared/browser/util_win.h"
+
+#define ColorUNDERLINE \
+ 0xFF000000 // Black SkColor value for underline,
+ // same as Blink.
+#define ColorBKCOLOR \
+ 0x00000000 // White SkColor value for background,
+ // same as Blink.
+
+namespace client {
+
+namespace {
+
+// Determines whether or not the given attribute represents a selection
+bool IsSelectionAttribute(char attribute) {
+ return (attribute == ATTR_TARGET_CONVERTED ||
+ attribute == ATTR_TARGET_NOTCONVERTED);
+}
+
+// Helper function for OsrImeHandlerWin::GetCompositionInfo() method,
+// to get the target range that's selected by the user in the current
+// composition string.
+void GetCompositionSelectionRange(HIMC imc,
+ int* target_start,
+ int* target_end) {
+ int attribute_size = ::ImmGetCompositionString(imc, GCS_COMPATTR, nullptr, 0);
+ if (attribute_size > 0) {
+ int start = 0;
+ int end = 0;
+ std::vector<char> attribute_data(attribute_size);
+
+ ::ImmGetCompositionString(imc, GCS_COMPATTR, &attribute_data[0],
+ attribute_size);
+ for (start = 0; start < attribute_size; ++start) {
+ if (IsSelectionAttribute(attribute_data[start])) {
+ break;
+ }
+ }
+ for (end = start; end < attribute_size; ++end) {
+ if (!IsSelectionAttribute(attribute_data[end])) {
+ break;
+ }
+ }
+
+ *target_start = start;
+ *target_end = end;
+ }
+}
+
+// Helper function for OsrImeHandlerWin::GetCompositionInfo() method, to get
+// underlines information of the current composition string.
+void GetCompositionUnderlines(
+ HIMC imc,
+ int target_start,
+ int target_end,
+ std::vector<CefCompositionUnderline>& underlines) {
+ int clause_size = ::ImmGetCompositionString(imc, GCS_COMPCLAUSE, nullptr, 0);
+ int clause_length = clause_size / sizeof(uint32);
+ if (clause_length) {
+ std::vector<uint32> clause_data(clause_length);
+
+ ::ImmGetCompositionString(imc, GCS_COMPCLAUSE, &clause_data[0],
+ clause_size);
+ for (int i = 0; i < clause_length - 1; ++i) {
+ cef_composition_underline_t underline = {};
+ underline.range.from = clause_data[i];
+ underline.range.to = clause_data[i + 1];
+ underline.color = ColorUNDERLINE;
+ underline.background_color = ColorBKCOLOR;
+ underline.thick = 0;
+
+ // Use thick underline for the target clause.
+ if (underline.range.from >= target_start &&
+ underline.range.to <= target_end) {
+ underline.thick = 1;
+ }
+ underlines.push_back(underline);
+ }
+ }
+}
+
+} // namespace
+
+OsrImeHandlerWin::OsrImeHandlerWin(HWND hwnd)
+ : is_composing_(false),
+ input_language_id_(LANG_USER_DEFAULT),
+ system_caret_(false),
+ cursor_index_(-1),
+ hwnd_(hwnd) {
+ ime_rect_ = {-1, -1, 0, 0};
+}
+
+OsrImeHandlerWin::~OsrImeHandlerWin() {
+ DestroyImeWindow();
+}
+
+void OsrImeHandlerWin::SetInputLanguage() {
+ // Retrieve the current input language from the system's keyboard layout.
+ // Using GetKeyboardLayoutName instead of GetKeyboardLayout, because
+ // the language from GetKeyboardLayout is the language under where the
+ // keyboard layout is installed. And the language from GetKeyboardLayoutName
+ // indicates the language of the keyboard layout itself.
+ // See crbug.com/344834.
+ WCHAR keyboard_layout[KL_NAMELENGTH];
+ if (::GetKeyboardLayoutNameW(keyboard_layout)) {
+ input_language_id_ =
+ static_cast<LANGID>(_wtoi(&keyboard_layout[KL_NAMELENGTH >> 1]));
+ } else {
+ input_language_id_ = 0x0409; // Fallback to en-US.
+ }
+}
+
+void OsrImeHandlerWin::CreateImeWindow() {
+ // Chinese/Japanese IMEs somehow ignore function calls to
+ // ::ImmSetCandidateWindow(), and use the position of the current system
+ // caret instead -::GetCaretPos().
+ // Therefore, we create a temporary system caret for Chinese IMEs and use
+ // it during this input context.
+ // Since some third-party Japanese IME also uses ::GetCaretPos() to determine
+ // their window position, we also create a caret for Japanese IMEs.
+ if (PRIMARYLANGID(input_language_id_) == LANG_CHINESE ||
+ PRIMARYLANGID(input_language_id_) == LANG_JAPANESE) {
+ if (!system_caret_) {
+ if (::CreateCaret(hwnd_, nullptr, 1, 1)) {
+ system_caret_ = true;
+ }
+ }
+ }
+}
+
+void OsrImeHandlerWin::DestroyImeWindow() {
+ // Destroy the system caret if we have created for this IME input context.
+ if (system_caret_) {
+ ::DestroyCaret();
+ system_caret_ = false;
+ }
+}
+
+void OsrImeHandlerWin::MoveImeWindow() {
+ // Does nothing when the target window has no input focus.
+ if (GetFocus() != hwnd_) {
+ return;
+ }
+
+ CefRect rc = ime_rect_;
+ int location = cursor_index_;
+
+ // If location is not specified fall back to the composition range start.
+ if (location == -1) {
+ location = composition_range_.from;
+ }
+
+ // Offset location by the composition range start if required.
+ if (location >= composition_range_.from) {
+ location -= composition_range_.from;
+ }
+
+ if (location < static_cast<int>(composition_bounds_.size())) {
+ rc = composition_bounds_[location];
+ } else {
+ return;
+ }
+
+ HIMC imc = ::ImmGetContext(hwnd_);
+ if (imc) {
+ const int kCaretMargin = 1;
+ if (PRIMARYLANGID(input_language_id_) == LANG_CHINESE) {
+ // Chinese IMEs ignore function calls to ::ImmSetCandidateWindow()
+ // when a user disables TSF (Text Service Framework) and CUAS (Cicero
+ // Unaware Application Support).
+ // On the other hand, when a user enables TSF and CUAS, Chinese IMEs
+ // ignore the position of the current system caret and use the
+ // parameters given to ::ImmSetCandidateWindow() with its 'dwStyle'
+ // parameter CFS_CANDIDATEPOS.
+ // Therefore, we do not only call ::ImmSetCandidateWindow() but also
+ // set the positions of the temporary system caret if it exists.
+ CANDIDATEFORM candidate_position = {
+ 0, CFS_CANDIDATEPOS, {rc.x, rc.y}, {0, 0, 0, 0}};
+ ::ImmSetCandidateWindow(imc, &candidate_position);
+ }
+ if (system_caret_) {
+ switch (PRIMARYLANGID(input_language_id_)) {
+ case LANG_JAPANESE:
+ ::SetCaretPos(rc.x, rc.y + rc.height);
+ break;
+ default:
+ ::SetCaretPos(rc.x, rc.y);
+ break;
+ }
+ }
+
+ if (PRIMARYLANGID(input_language_id_) == LANG_KOREAN) {
+ // Korean IMEs require the lower-left corner of the caret to move their
+ // candidate windows.
+ rc.y += kCaretMargin;
+ }
+
+ // Japanese IMEs and Korean IMEs also use the rectangle given to
+ // ::ImmSetCandidateWindow() with its 'dwStyle' parameter CFS_EXCLUDE
+ // Therefore, we also set this parameter here.
+ CANDIDATEFORM exclude_rectangle = {
+ 0,
+ CFS_EXCLUDE,
+ {rc.x, rc.y},
+ {rc.x, rc.y, rc.x + rc.width, rc.y + rc.height}};
+ ::ImmSetCandidateWindow(imc, &exclude_rectangle);
+
+ ::ImmReleaseContext(hwnd_, imc);
+ }
+}
+
+void OsrImeHandlerWin::CleanupComposition() {
+ // Notify the IMM attached to the given window to complete the ongoing
+ // composition (when given window is de-activated while composing and
+ // re-activated) and reset the composition status.
+ if (is_composing_) {
+ HIMC imc = ::ImmGetContext(hwnd_);
+ if (imc) {
+ ::ImmNotifyIME(imc, NI_COMPOSITIONSTR, CPS_COMPLETE, 0);
+ ::ImmReleaseContext(hwnd_, imc);
+ }
+ ResetComposition();
+ }
+}
+
+void OsrImeHandlerWin::ResetComposition() {
+ // Reset the composition status.
+ is_composing_ = false;
+ cursor_index_ = -1;
+}
+
+void OsrImeHandlerWin::GetCompositionInfo(
+ HIMC imc,
+ LPARAM lparam,
+ CefString& composition_text,
+ std::vector<CefCompositionUnderline>& underlines,
+ int& composition_start) {
+ // We only care about GCS_COMPATTR, GCS_COMPCLAUSE and GCS_CURSORPOS, and
+ // convert them into underlines and selection range respectively.
+ underlines.clear();
+
+ int length = static_cast<int>(composition_text.length());
+
+ // Find out the range selected by the user.
+ int target_start = length;
+ int target_end = length;
+ if (lparam & GCS_COMPATTR) {
+ GetCompositionSelectionRange(imc, &target_start, &target_end);
+ }
+
+ // Retrieve the selection range information. If CS_NOMOVECARET is specified
+ // it means the cursor should not be moved and we therefore place the caret at
+ // the beginning of the composition string. Otherwise we should honour the
+ // GCS_CURSORPOS value if it's available.
+ // TODO(suzhe): Due to a bug in WebKit we currently can't use selection range
+ // with composition string.
+ // See: https://bugs.webkit.org/show_bug.cgi?id=40805
+ if (!(lparam & CS_NOMOVECARET) && (lparam & GCS_CURSORPOS)) {
+ // IMM32 does not support non-zero-width selection in a composition. So
+ // always use the caret position as selection range.
+ int cursor = ::ImmGetCompositionString(imc, GCS_CURSORPOS, nullptr, 0);
+ composition_start = cursor;
+ } else {
+ composition_start = 0;
+ }
+
+ // Retrieve the clause segmentations and convert them to underlines.
+ if (lparam & GCS_COMPCLAUSE) {
+ GetCompositionUnderlines(imc, target_start, target_end, underlines);
+ }
+
+ // Set default underlines in case there is no clause information.
+ if (!underlines.size()) {
+ CefCompositionUnderline underline;
+ underline.color = ColorUNDERLINE;
+ underline.background_color = ColorBKCOLOR;
+ if (target_start > 0) {
+ underline.range.from = 0;
+ underline.range.to = target_start;
+ underline.thick = 0;
+ underlines.push_back(underline);
+ }
+ if (target_end > target_start) {
+ underline.range.from = target_start;
+ underline.range.to = target_end;
+ underline.thick = 1;
+ underlines.push_back(underline);
+ }
+ if (target_end < length) {
+ underline.range.from = target_end;
+ underline.range.to = length;
+ underline.thick = 0;
+ underlines.push_back(underline);
+ }
+ }
+}
+
+bool OsrImeHandlerWin::GetString(HIMC imc,
+ WPARAM lparam,
+ int type,
+ CefString& result) {
+ if (!(lparam & type)) {
+ return false;
+ }
+ LONG string_size = ::ImmGetCompositionString(imc, type, nullptr, 0);
+ if (string_size <= 0) {
+ return false;
+ }
+
+ // For trailing nullptr - ImmGetCompositionString excludes that.
+ string_size += sizeof(WCHAR);
+
+ std::vector<wchar_t> buffer(string_size);
+ ::ImmGetCompositionString(imc, type, &buffer[0], string_size);
+ result.FromWString(&buffer[0]);
+ return true;
+}
+
+bool OsrImeHandlerWin::GetResult(LPARAM lparam, CefString& result) {
+ bool ret = false;
+ HIMC imc = ::ImmGetContext(hwnd_);
+ if (imc) {
+ ret = GetString(imc, lparam, GCS_RESULTSTR, result);
+ ::ImmReleaseContext(hwnd_, imc);
+ }
+ return ret;
+}
+
+bool OsrImeHandlerWin::GetComposition(
+ LPARAM lparam,
+ CefString& composition_text,
+ std::vector<CefCompositionUnderline>& underlines,
+ int& composition_start) {
+ bool ret = false;
+ HIMC imc = ::ImmGetContext(hwnd_);
+ if (imc) {
+ // Copy the composition string to the CompositionText object.
+ ret = GetString(imc, lparam, GCS_COMPSTR, composition_text);
+
+ if (ret) {
+ // Retrieve the composition underlines and selection range information.
+ GetCompositionInfo(imc, lparam, composition_text, underlines,
+ composition_start);
+
+ // Mark that there is an ongoing composition.
+ is_composing_ = true;
+ }
+
+ ::ImmReleaseContext(hwnd_, imc);
+ }
+ return ret;
+}
+
+void OsrImeHandlerWin::DisableIME() {
+ CleanupComposition();
+ ::ImmAssociateContextEx(hwnd_, nullptr, 0);
+}
+
+void OsrImeHandlerWin::CancelIME() {
+ if (is_composing_) {
+ HIMC imc = ::ImmGetContext(hwnd_);
+ if (imc) {
+ ::ImmNotifyIME(imc, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
+ ::ImmReleaseContext(hwnd_, imc);
+ }
+ ResetComposition();
+ }
+}
+
+void OsrImeHandlerWin::EnableIME() {
+ // Load the default IME context.
+ ::ImmAssociateContextEx(hwnd_, nullptr, IACE_DEFAULT);
+}
+
+void OsrImeHandlerWin::UpdateCaretPosition(int index) {
+ // Save the caret position.
+ cursor_index_ = index;
+ // Move the IME window.
+ MoveImeWindow();
+}
+
+void OsrImeHandlerWin::ChangeCompositionRange(
+ const CefRange& selection_range,
+ const std::vector<CefRect>& bounds) {
+ composition_range_ = selection_range;
+ composition_bounds_ = bounds;
+ MoveImeWindow();
+}
+
+} // namespace client
diff --git a/tests/cefclient/browser/osr_ime_handler_win.h b/tests/cefclient/browser/osr_ime_handler_win.h
new file mode 100644
index 00000000..87589850
--- /dev/null
+++ b/tests/cefclient/browser/osr_ime_handler_win.h
@@ -0,0 +1,115 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. Portions copyright
+// 2013 The Chromium Authors. All rights reserved. Use of this source code is
+// governed by a BSD-style license that can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_OSR_IME_HANDLER_WIN_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_OSR_IME_HANDLER_WIN_H_
+#pragma once
+
+#include <windows.h>
+#include <vector>
+
+#include "include/internal/cef_types_wrappers.h"
+
+namespace client {
+
+// Handles IME for the native parent window that hosts an off-screen browser.
+// This object is only accessed on the CEF UI thread.
+class OsrImeHandlerWin {
+ public:
+ explicit OsrImeHandlerWin(HWND hwnd);
+ virtual ~OsrImeHandlerWin();
+
+ // Retrieves whether or not there is an ongoing composition.
+ bool is_composing() const { return is_composing_; }
+
+ // Retrieves the input language from Windows and update it.
+ void SetInputLanguage();
+
+ // Creates the IME caret windows if required.
+ void CreateImeWindow();
+
+ // Destroys the IME caret windows.
+ void DestroyImeWindow();
+
+ // Cleans up the all resources attached to the given IMM32Manager object, and
+ // reset its composition status.
+ void CleanupComposition();
+
+ // Resets the composition status and cancels the ongoing composition.
+ void ResetComposition();
+
+ // Retrieves a composition result of the ongoing composition if it exists.
+ bool GetResult(LPARAM lparam, CefString& result);
+
+ // Retrieves the current composition status of the ongoing composition.
+ // Includes composition text, underline information and selection range in the
+ // composition text. IMM32 does not support char selection.
+ bool GetComposition(LPARAM lparam,
+ CefString& composition_text,
+ std::vector<CefCompositionUnderline>& underlines,
+ int& composition_start);
+
+ // Enables the IME attached to the given window.
+ virtual void EnableIME();
+
+ // Disables the IME attached to the given window.
+ virtual void DisableIME();
+
+ // Cancels an ongoing composition of the IME.
+ virtual void CancelIME();
+
+ // Updates the IME caret position of the given window.
+ void UpdateCaretPosition(int index);
+
+ // Updates the composition range. |selected_range| is the range of characters
+ // that have been selected. |character_bounds| is the bounds of each character
+ // in view device coordinates.
+ void ChangeCompositionRange(const CefRange& selection_range,
+ const std::vector<CefRect>& character_bounds);
+
+ // Updates the position of the IME windows.
+ void MoveImeWindow();
+
+ private:
+ // Retrieves the composition information.
+ void GetCompositionInfo(HIMC imm_context,
+ LPARAM lparam,
+ CefString& composition_text,
+ std::vector<CefCompositionUnderline>& underlines,
+ int& composition_start);
+
+ // Retrieves a string from the IMM.
+ bool GetString(HIMC imm_context, WPARAM lparam, int type, CefString& result);
+
+ // Represents whether or not there is an ongoing composition.
+ bool is_composing_;
+
+ // The current composition character range and its bounds.
+ std::vector<CefRect> composition_bounds_;
+
+ // The current input Language ID retrieved from Windows -
+ // used for processing language-specific operations in IME.
+ LANGID input_language_id_;
+
+ // Represents whether or not the current input context has created a system
+ // caret to set the position of its IME candidate window.
+ bool system_caret_;
+
+ // The rectangle of the input caret retrieved from a renderer process.
+ CefRect ime_rect_;
+
+ // The current cursor index in composition string.
+ int cursor_index_;
+
+ // The composition range in the string. This may be used to determine the
+ // offset in composition bounds.
+ CefRange composition_range_;
+
+ // Hwnd associated with this instance.
+ HWND hwnd_;
+};
+
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_OSR_IME_HANDLER_WIN_H_
diff --git a/tests/cefclient/browser/osr_render_handler_win.cc b/tests/cefclient/browser/osr_render_handler_win.cc
new file mode 100644
index 00000000..b81a9021
--- /dev/null
+++ b/tests/cefclient/browser/osr_render_handler_win.cc
@@ -0,0 +1,83 @@
+// Copyright 2018 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/osr_render_handler_win.h"
+
+#include "include/base/cef_callback.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "include/wrapper/cef_helpers.h"
+#include "tests/shared/browser/util_win.h"
+
+namespace client {
+
+OsrRenderHandlerWin::OsrRenderHandlerWin(const OsrRendererSettings& settings,
+ HWND hwnd)
+ : settings_(settings),
+ hwnd_(hwnd),
+ begin_frame_pending_(false),
+ weak_factory_(this) {
+ CEF_REQUIRE_UI_THREAD();
+ DCHECK(hwnd_);
+}
+
+OsrRenderHandlerWin::~OsrRenderHandlerWin() {
+ CEF_REQUIRE_UI_THREAD();
+}
+
+void OsrRenderHandlerWin::SetBrowser(CefRefPtr<CefBrowser> browser) {
+ CEF_REQUIRE_UI_THREAD();
+ browser_ = browser;
+ if (browser_ && settings_.external_begin_frame_enabled) {
+ // Start the BeginFrame timer.
+ Invalidate();
+ }
+}
+
+void OsrRenderHandlerWin::Invalidate() {
+ CEF_REQUIRE_UI_THREAD();
+ if (begin_frame_pending_) {
+ // The timer is already running.
+ return;
+ }
+
+ // Trigger the BeginFrame timer.
+ CHECK_GT(settings_.begin_frame_rate, 0);
+ const float delay_us = (1.0 / double(settings_.begin_frame_rate)) * 1000000.0;
+ TriggerBeginFrame(0, delay_us);
+}
+
+void OsrRenderHandlerWin::TriggerBeginFrame(uint64_t last_time_us,
+ float delay_us) {
+ if (begin_frame_pending_ && !settings_.external_begin_frame_enabled) {
+ // Render immediately and then wait for the next call to Invalidate() or
+ // On[Accelerated]Paint().
+ begin_frame_pending_ = false;
+ Render();
+ return;
+ }
+
+ const auto now = GetTimeNow();
+ float offset = now - last_time_us;
+ if (offset > delay_us) {
+ offset = delay_us;
+ }
+
+ if (!begin_frame_pending_) {
+ begin_frame_pending_ = true;
+ }
+
+ // Trigger again after the necessary delay to maintain the desired frame rate.
+ CefPostDelayedTask(TID_UI,
+ base::BindOnce(&OsrRenderHandlerWin::TriggerBeginFrame,
+ weak_factory_.GetWeakPtr(), now, delay_us),
+ int64(offset / 1000.0));
+
+ if (settings_.external_begin_frame_enabled && browser_) {
+ // We're running the BeginFrame timer. Trigger rendering via
+ // On[Accelerated]Paint().
+ browser_->GetHost()->SendExternalBeginFrame();
+ }
+}
+
+} // namespace client
diff --git a/tests/cefclient/browser/osr_render_handler_win.h b/tests/cefclient/browser/osr_render_handler_win.h
new file mode 100644
index 00000000..4eee0249
--- /dev/null
+++ b/tests/cefclient/browser/osr_render_handler_win.h
@@ -0,0 +1,82 @@
+// Copyright 2018 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_OSR_RENDER_HANDLER_WIN_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_OSR_RENDER_HANDLER_WIN_H_
+#pragma once
+
+#include "include/base/cef_weak_ptr.h"
+#include "include/cef_render_handler.h"
+#include "tests/cefclient/browser/osr_renderer_settings.h"
+
+namespace client {
+
+// Abstract base class for implementing OSR rendering with different backends on
+// Windows. Methods are only called on the UI thread.
+class OsrRenderHandlerWin {
+ public:
+ OsrRenderHandlerWin(const OsrRendererSettings& settings, HWND hwnd);
+ virtual ~OsrRenderHandlerWin();
+
+ void SetBrowser(CefRefPtr<CefBrowser> browser);
+
+ // Rotate the texture based on mouse events.
+ virtual void SetSpin(float spinX, float spinY) = 0;
+ virtual void IncrementSpin(float spinDX, float spinDY) = 0;
+
+ // Popup hit testing.
+ virtual bool IsOverPopupWidget(int x, int y) const = 0;
+ virtual int GetPopupXOffset() const = 0;
+ virtual int GetPopupYOffset() const = 0;
+
+ // CefRenderHandler callbacks.
+ virtual void OnPopupShow(CefRefPtr<CefBrowser> browser, bool show) = 0;
+ // |rect| must be in pixel coordinates.
+ virtual void OnPopupSize(CefRefPtr<CefBrowser> browser,
+ const CefRect& rect) = 0;
+
+ // Used when not rendering with shared textures.
+ virtual void OnPaint(CefRefPtr<CefBrowser> browser,
+ CefRenderHandler::PaintElementType type,
+ const CefRenderHandler::RectList& dirtyRects,
+ const void* buffer,
+ int width,
+ int height) = 0;
+
+ // Used when rendering with shared textures.
+ virtual void OnAcceleratedPaint(CefRefPtr<CefBrowser> browser,
+ CefRenderHandler::PaintElementType type,
+ const CefRenderHandler::RectList& dirtyRects,
+ void* share_handle) = 0;
+
+ bool send_begin_frame() const {
+ return settings_.external_begin_frame_enabled;
+ }
+ HWND hwnd() const { return hwnd_; }
+
+ protected:
+ // Called to trigger the BeginFrame timer.
+ void Invalidate();
+
+ // Called by the BeginFrame timer.
+ virtual void Render() = 0;
+
+ private:
+ void TriggerBeginFrame(uint64_t last_time_us, float delay_us);
+
+ // The below members are only accessed on the UI thread.
+ const OsrRendererSettings settings_;
+ const HWND hwnd_;
+ bool begin_frame_pending_;
+ CefRefPtr<CefBrowser> browser_;
+
+ // Must be the last member.
+ base::WeakPtrFactory<OsrRenderHandlerWin> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(OsrRenderHandlerWin);
+};
+
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_OSR_RENDER_HANDLER_WIN_H_
diff --git a/tests/cefclient/browser/osr_render_handler_win_d3d11.cc b/tests/cefclient/browser/osr_render_handler_win_d3d11.cc
new file mode 100644
index 00000000..93de15a5
--- /dev/null
+++ b/tests/cefclient/browser/osr_render_handler_win_d3d11.cc
@@ -0,0 +1,229 @@
+// Copyright 2018 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/osr_render_handler_win_d3d11.h"
+
+#include "include/base/cef_callback.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "include/wrapper/cef_helpers.h"
+#include "tests/shared/browser/util_win.h"
+
+namespace client {
+
+BrowserLayer::BrowserLayer(const std::shared_ptr<d3d11::Device>& device)
+ : d3d11::Layer(device, true /* flip */) {
+ frame_buffer_ = std::make_shared<d3d11::FrameBuffer>(device_);
+}
+
+void BrowserLayer::render(const std::shared_ptr<d3d11::Context>& ctx) {
+ // Use the base class method to draw our texture.
+ render_texture(ctx, frame_buffer_->texture());
+}
+
+void BrowserLayer::on_paint(void* share_handle) {
+ frame_buffer_->on_paint(share_handle);
+}
+
+std::pair<uint32_t, uint32_t> BrowserLayer::texture_size() const {
+ const auto texture = frame_buffer_->texture();
+ return std::make_pair(texture->width(), texture->height());
+}
+
+PopupLayer::PopupLayer(const std::shared_ptr<d3d11::Device>& device)
+ : BrowserLayer(device) {}
+
+void PopupLayer::set_bounds(const CefRect& bounds) {
+ const auto comp = composition();
+ if (!comp) {
+ return;
+ }
+
+ const auto outer_width = comp->width();
+ const auto outer_height = comp->height();
+ if (outer_width == 0 || outer_height == 0) {
+ return;
+ }
+
+ original_bounds_ = bounds;
+ bounds_ = bounds;
+
+ // If x or y are negative, move them to 0.
+ if (bounds_.x < 0) {
+ bounds_.x = 0;
+ }
+ if (bounds_.y < 0) {
+ bounds_.y = 0;
+ }
+ // If popup goes outside the view, try to reposition origin
+ if (bounds_.x + bounds_.width > outer_width) {
+ bounds_.x = outer_width - bounds_.width;
+ }
+ if (bounds_.y + bounds_.height > outer_height) {
+ bounds_.y = outer_height - bounds_.height;
+ }
+ // If x or y became negative, move them to 0 again.
+ if (bounds_.x < 0) {
+ bounds_.x = 0;
+ }
+ if (bounds_.y < 0) {
+ bounds_.y = 0;
+ }
+
+ const auto x = bounds_.x / float(outer_width);
+ const auto y = bounds_.y / float(outer_height);
+ const auto w = bounds_.width / float(outer_width);
+ const auto h = bounds_.height / float(outer_height);
+ move(x, y, w, h);
+}
+
+OsrRenderHandlerWinD3D11::OsrRenderHandlerWinD3D11(
+ const OsrRendererSettings& settings,
+ HWND hwnd)
+ : OsrRenderHandlerWin(settings, hwnd), start_time_(0) {}
+
+bool OsrRenderHandlerWinD3D11::Initialize(CefRefPtr<CefBrowser> browser,
+ int width,
+ int height) {
+ CEF_REQUIRE_UI_THREAD();
+
+ // Create a D3D11 device instance.
+ device_ = d3d11::Device::create();
+ DCHECK(device_);
+ if (!device_) {
+ return false;
+ }
+
+ // Create a D3D11 swapchain for the window.
+ swap_chain_ = device_->create_swapchain(hwnd());
+ DCHECK(swap_chain_);
+ if (!swap_chain_) {
+ return false;
+ }
+
+ // Create the browser layer.
+ browser_layer_ = std::make_shared<BrowserLayer>(device_);
+
+ // Set up the composition.
+ composition_ = std::make_shared<d3d11::Composition>(device_, width, height);
+ composition_->add_layer(browser_layer_);
+
+ // Size to the whole composition.
+ browser_layer_->move(0.0f, 0.0f, 1.0f, 1.0f);
+
+ start_time_ = GetTimeNow();
+
+ SetBrowser(browser);
+ return true;
+}
+
+void OsrRenderHandlerWinD3D11::SetSpin(float spinX, float spinY) {
+ CEF_REQUIRE_UI_THREAD();
+ // Spin support is not implemented.
+}
+
+void OsrRenderHandlerWinD3D11::IncrementSpin(float spinDX, float spinDY) {
+ CEF_REQUIRE_UI_THREAD();
+ // Spin support is not implemented.
+}
+
+bool OsrRenderHandlerWinD3D11::IsOverPopupWidget(int x, int y) const {
+ CEF_REQUIRE_UI_THREAD();
+ return popup_layer_ && popup_layer_->contains(x, y);
+}
+
+int OsrRenderHandlerWinD3D11::GetPopupXOffset() const {
+ CEF_REQUIRE_UI_THREAD();
+ if (popup_layer_) {
+ return popup_layer_->xoffset();
+ }
+ return 0;
+}
+
+int OsrRenderHandlerWinD3D11::GetPopupYOffset() const {
+ CEF_REQUIRE_UI_THREAD();
+ if (popup_layer_) {
+ return popup_layer_->yoffset();
+ }
+ return 0;
+}
+
+void OsrRenderHandlerWinD3D11::OnPopupShow(CefRefPtr<CefBrowser> browser,
+ bool show) {
+ CEF_REQUIRE_UI_THREAD();
+
+ if (show) {
+ DCHECK(!popup_layer_);
+
+ // Create a new layer.
+ popup_layer_ = std::make_shared<PopupLayer>(device_);
+ composition_->add_layer(popup_layer_);
+ } else {
+ DCHECK(popup_layer_);
+
+ composition_->remove_layer(popup_layer_);
+ popup_layer_ = nullptr;
+
+ Render();
+ }
+}
+
+void OsrRenderHandlerWinD3D11::OnPopupSize(CefRefPtr<CefBrowser> browser,
+ const CefRect& rect) {
+ CEF_REQUIRE_UI_THREAD();
+ popup_layer_->set_bounds(rect);
+}
+
+void OsrRenderHandlerWinD3D11::OnPaint(
+ CefRefPtr<CefBrowser> browser,
+ CefRenderHandler::PaintElementType type,
+ const CefRenderHandler::RectList& dirtyRects,
+ const void* buffer,
+ int width,
+ int height) {
+ // Not used with this implementation.
+ NOTREACHED();
+}
+
+void OsrRenderHandlerWinD3D11::OnAcceleratedPaint(
+ CefRefPtr<CefBrowser> browser,
+ CefRenderHandler::PaintElementType type,
+ const CefRenderHandler::RectList& dirtyRects,
+ void* share_handle) {
+ CEF_REQUIRE_UI_THREAD();
+
+ if (type == PET_POPUP) {
+ popup_layer_->on_paint(share_handle);
+ } else {
+ browser_layer_->on_paint(share_handle);
+ }
+
+ Render();
+}
+
+void OsrRenderHandlerWinD3D11::Render() {
+ // Update composition + layers based on time.
+ const auto t = (GetTimeNow() - start_time_) / 1000000.0;
+ composition_->tick(t);
+
+ auto ctx = device_->immedidate_context();
+ swap_chain_->bind(ctx);
+
+ const auto texture_size = browser_layer_->texture_size();
+
+ // Resize the composition and swap chain to match the texture if necessary.
+ composition_->resize(!send_begin_frame(), texture_size.first,
+ texture_size.second);
+ swap_chain_->resize(texture_size.first, texture_size.second);
+
+ // Clear the render target.
+ swap_chain_->clear(0.0f, 0.0f, 1.0f, 1.0f);
+
+ // Render the scene.
+ composition_->render(ctx);
+
+ // Present to window.
+ swap_chain_->present(send_begin_frame() ? 0 : 1);
+}
+
+} // namespace client
diff --git a/tests/cefclient/browser/osr_render_handler_win_d3d11.h b/tests/cefclient/browser/osr_render_handler_win_d3d11.h
new file mode 100644
index 00000000..cd0b8d50
--- /dev/null
+++ b/tests/cefclient/browser/osr_render_handler_win_d3d11.h
@@ -0,0 +1,90 @@
+// Copyright 2018 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_OSR_RENDER_HANDLER_WIN_D3D11_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_OSR_RENDER_HANDLER_WIN_D3D11_H_
+#pragma once
+
+#include "tests/cefclient/browser/osr_d3d11_win.h"
+#include "tests/cefclient/browser/osr_render_handler_win.h"
+#include "tests/cefclient/browser/osr_renderer_settings.h"
+
+namespace client {
+
+class BrowserLayer : public d3d11::Layer {
+ public:
+ explicit BrowserLayer(const std::shared_ptr<d3d11::Device>& device);
+
+ void render(const std::shared_ptr<d3d11::Context>& ctx) override;
+
+ void on_paint(void* share_handle);
+
+ // After calling on_paint() we can query the texture size.
+ std::pair<uint32_t, uint32_t> texture_size() const;
+
+ private:
+ std::shared_ptr<d3d11::FrameBuffer> frame_buffer_;
+
+ DISALLOW_COPY_AND_ASSIGN(BrowserLayer);
+};
+
+class PopupLayer : public BrowserLayer {
+ public:
+ explicit PopupLayer(const std::shared_ptr<d3d11::Device>& device);
+
+ void set_bounds(const CefRect& bounds);
+
+ bool contains(int x, int y) const { return bounds_.Contains(x, y); }
+ int xoffset() const { return original_bounds_.x - bounds_.x; }
+ int yoffset() const { return original_bounds_.y - bounds_.y; }
+
+ private:
+ CefRect original_bounds_;
+ CefRect bounds_;
+
+ DISALLOW_COPY_AND_ASSIGN(PopupLayer);
+};
+
+class OsrRenderHandlerWinD3D11 : public OsrRenderHandlerWin {
+ public:
+ OsrRenderHandlerWinD3D11(const OsrRendererSettings& settings, HWND hwnd);
+
+ // Must be called immediately after object creation.
+ // May fail if D3D11 cannot be initialized.
+ bool Initialize(CefRefPtr<CefBrowser> browser, int width, int height);
+
+ void SetSpin(float spinX, float spinY) override;
+ void IncrementSpin(float spinDX, float spinDY) override;
+ bool IsOverPopupWidget(int x, int y) const override;
+ int GetPopupXOffset() const override;
+ int GetPopupYOffset() const override;
+ void OnPopupShow(CefRefPtr<CefBrowser> browser, bool show) override;
+ void OnPopupSize(CefRefPtr<CefBrowser> browser, const CefRect& rect) override;
+ void OnPaint(CefRefPtr<CefBrowser> browser,
+ CefRenderHandler::PaintElementType type,
+ const CefRenderHandler::RectList& dirtyRects,
+ const void* buffer,
+ int width,
+ int height) override;
+ void OnAcceleratedPaint(CefRefPtr<CefBrowser> browser,
+ CefRenderHandler::PaintElementType type,
+ const CefRenderHandler::RectList& dirtyRects,
+ void* share_handle) override;
+
+ private:
+ void Render() override;
+
+ uint64_t start_time_;
+ std::shared_ptr<d3d11::Device> device_;
+ std::shared_ptr<d3d11::SwapChain> swap_chain_;
+ std::shared_ptr<d3d11::Composition> composition_;
+ std::shared_ptr<BrowserLayer> browser_layer_;
+ std::shared_ptr<PopupLayer> popup_layer_;
+
+ DISALLOW_COPY_AND_ASSIGN(OsrRenderHandlerWinD3D11);
+};
+
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_OSR_RENDER_HANDLER_WIN_D3D11_H_
diff --git a/tests/cefclient/browser/osr_render_handler_win_gl.cc b/tests/cefclient/browser/osr_render_handler_win_gl.cc
new file mode 100644
index 00000000..506214b7
--- /dev/null
+++ b/tests/cefclient/browser/osr_render_handler_win_gl.cc
@@ -0,0 +1,199 @@
+// Copyright 2018 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/osr_render_handler_win_gl.h"
+
+#include "include/base/cef_callback.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "include/wrapper/cef_helpers.h"
+#include "tests/shared/browser/util_win.h"
+
+namespace client {
+
+namespace {
+
+// Helper that calls wglMakeCurrent.
+class ScopedGLContext {
+ public:
+ ScopedGLContext(HDC hdc, HGLRC hglrc, bool swap_buffers)
+ : hdc_(hdc), swap_buffers_(swap_buffers) {
+ [[maybe_unused]] BOOL result = wglMakeCurrent(hdc, hglrc);
+ DCHECK(result);
+ }
+ ~ScopedGLContext() {
+ BOOL result = wglMakeCurrent(nullptr, nullptr);
+ DCHECK(result);
+ if (swap_buffers_) {
+ result = SwapBuffers(hdc_);
+ DCHECK(result);
+ }
+ }
+
+ private:
+ const HDC hdc_;
+ const bool swap_buffers_;
+};
+
+} // namespace
+
+OsrRenderHandlerWinGL::OsrRenderHandlerWinGL(
+ const OsrRendererSettings& settings,
+ HWND hwnd)
+ : OsrRenderHandlerWin(settings, hwnd),
+ renderer_(settings),
+ hdc_(nullptr),
+ hrc_(nullptr),
+ painting_popup_(false) {}
+
+void OsrRenderHandlerWinGL::Initialize(CefRefPtr<CefBrowser> browser) {
+ CEF_REQUIRE_UI_THREAD();
+ SetBrowser(browser);
+}
+
+OsrRenderHandlerWinGL::~OsrRenderHandlerWinGL() {
+ CEF_REQUIRE_UI_THREAD();
+ DisableGL();
+}
+
+void OsrRenderHandlerWinGL::SetSpin(float spinX, float spinY) {
+ CEF_REQUIRE_UI_THREAD();
+ renderer_.SetSpin(spinX, spinY);
+ Invalidate();
+}
+
+void OsrRenderHandlerWinGL::IncrementSpin(float spinDX, float spinDY) {
+ CEF_REQUIRE_UI_THREAD();
+ renderer_.IncrementSpin(spinDX, spinDY);
+ Invalidate();
+}
+
+bool OsrRenderHandlerWinGL::IsOverPopupWidget(int x, int y) const {
+ CEF_REQUIRE_UI_THREAD();
+ const CefRect& rc = renderer_.popup_rect();
+ int popup_right = rc.x + rc.width;
+ int popup_bottom = rc.y + rc.height;
+ return (x >= rc.x) && (x < popup_right) && (y >= rc.y) && (y < popup_bottom);
+}
+
+int OsrRenderHandlerWinGL::GetPopupXOffset() const {
+ CEF_REQUIRE_UI_THREAD();
+ return renderer_.original_popup_rect().x - renderer_.popup_rect().x;
+}
+
+int OsrRenderHandlerWinGL::GetPopupYOffset() const {
+ CEF_REQUIRE_UI_THREAD();
+ return renderer_.original_popup_rect().y - renderer_.popup_rect().y;
+}
+
+void OsrRenderHandlerWinGL::OnPopupShow(CefRefPtr<CefBrowser> browser,
+ bool show) {
+ CEF_REQUIRE_UI_THREAD();
+
+ if (!show) {
+ renderer_.ClearPopupRects();
+ browser->GetHost()->Invalidate(PET_VIEW);
+ }
+
+ renderer_.OnPopupShow(browser, show);
+}
+
+void OsrRenderHandlerWinGL::OnPopupSize(CefRefPtr<CefBrowser> browser,
+ const CefRect& rect) {
+ CEF_REQUIRE_UI_THREAD();
+ renderer_.OnPopupSize(browser, rect);
+}
+
+void OsrRenderHandlerWinGL::OnPaint(
+ CefRefPtr<CefBrowser> browser,
+ CefRenderHandler::PaintElementType type,
+ const CefRenderHandler::RectList& dirtyRects,
+ const void* buffer,
+ int width,
+ int height) {
+ CEF_REQUIRE_UI_THREAD();
+
+ if (painting_popup_) {
+ renderer_.OnPaint(browser, type, dirtyRects, buffer, width, height);
+ return;
+ }
+ if (!hdc_) {
+ EnableGL();
+ }
+
+ ScopedGLContext scoped_gl_context(hdc_, hrc_, true);
+ renderer_.OnPaint(browser, type, dirtyRects, buffer, width, height);
+ if (type == PET_VIEW && !renderer_.popup_rect().IsEmpty()) {
+ painting_popup_ = true;
+ browser->GetHost()->Invalidate(PET_POPUP);
+ painting_popup_ = false;
+ }
+ renderer_.Render();
+}
+
+void OsrRenderHandlerWinGL::OnAcceleratedPaint(
+ CefRefPtr<CefBrowser> browser,
+ CefRenderHandler::PaintElementType type,
+ const CefRenderHandler::RectList& dirtyRects,
+ void* share_handle) {
+ // Not used with this implementation.
+ NOTREACHED();
+}
+
+void OsrRenderHandlerWinGL::Render() {
+ if (!hdc_) {
+ EnableGL();
+ }
+
+ ScopedGLContext scoped_gl_context(hdc_, hrc_, true);
+ renderer_.Render();
+}
+
+void OsrRenderHandlerWinGL::EnableGL() {
+ PIXELFORMATDESCRIPTOR pfd;
+ int format;
+
+ // Get the device context.
+ hdc_ = GetDC(hwnd());
+
+ // Set the pixel format for the DC.
+ ZeroMemory(&pfd, sizeof(pfd));
+ pfd.nSize = sizeof(pfd);
+ pfd.nVersion = 1;
+ pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
+ pfd.iPixelType = PFD_TYPE_RGBA;
+ pfd.cColorBits = 24;
+ pfd.cDepthBits = 16;
+ pfd.iLayerType = PFD_MAIN_PLANE;
+ format = ChoosePixelFormat(hdc_, &pfd);
+ SetPixelFormat(hdc_, format, &pfd);
+
+ // Create and enable the render context.
+ hrc_ = wglCreateContext(hdc_);
+
+ ScopedGLContext scoped_gl_context(hdc_, hrc_, false);
+ renderer_.Initialize();
+}
+
+void OsrRenderHandlerWinGL::DisableGL() {
+ if (!hdc_) {
+ return;
+ }
+
+ {
+ ScopedGLContext scoped_gl_context(hdc_, hrc_, false);
+ renderer_.Cleanup();
+ }
+
+ if (IsWindow(hwnd())) {
+ // wglDeleteContext will make the context not current before deleting it.
+ [[maybe_unused]] BOOL result = wglDeleteContext(hrc_);
+ DCHECK(result);
+ ReleaseDC(hwnd(), hdc_);
+ }
+
+ hdc_ = nullptr;
+ hrc_ = nullptr;
+}
+
+} // namespace client
diff --git a/tests/cefclient/browser/osr_render_handler_win_gl.h b/tests/cefclient/browser/osr_render_handler_win_gl.h
new file mode 100644
index 00000000..88ff0920
--- /dev/null
+++ b/tests/cefclient/browser/osr_render_handler_win_gl.h
@@ -0,0 +1,57 @@
+// Copyright 2018 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_OSR_RENDER_HANDLER_WIN_GL_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_OSR_RENDER_HANDLER_WIN_GL_H_
+#pragma once
+
+#include "tests/cefclient/browser/osr_render_handler_win.h"
+#include "tests/cefclient/browser/osr_renderer.h"
+
+namespace client {
+
+class OsrRenderHandlerWinGL : public OsrRenderHandlerWin {
+ public:
+ OsrRenderHandlerWinGL(const OsrRendererSettings& settings, HWND hwnd);
+ virtual ~OsrRenderHandlerWinGL();
+
+ // Must be called immediately after object creation.
+ void Initialize(CefRefPtr<CefBrowser> browser);
+
+ void SetSpin(float spinX, float spinY) override;
+ void IncrementSpin(float spinDX, float spinDY) override;
+ bool IsOverPopupWidget(int x, int y) const override;
+ int GetPopupXOffset() const override;
+ int GetPopupYOffset() const override;
+ void OnPopupShow(CefRefPtr<CefBrowser> browser, bool show) override;
+ void OnPopupSize(CefRefPtr<CefBrowser> browser, const CefRect& rect) override;
+ void OnPaint(CefRefPtr<CefBrowser> browser,
+ CefRenderHandler::PaintElementType type,
+ const CefRenderHandler::RectList& dirtyRects,
+ const void* buffer,
+ int width,
+ int height) override;
+ void OnAcceleratedPaint(CefRefPtr<CefBrowser> browser,
+ CefRenderHandler::PaintElementType type,
+ const CefRenderHandler::RectList& dirtyRects,
+ void* share_handle) override;
+
+ private:
+ void Render() override;
+
+ void EnableGL();
+ void DisableGL();
+
+ // The below members are only accessed on the UI thread.
+ OsrRenderer renderer_;
+ HDC hdc_;
+ HGLRC hrc_;
+ bool painting_popup_;
+
+ DISALLOW_COPY_AND_ASSIGN(OsrRenderHandlerWinGL);
+};
+
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_OSR_RENDER_HANDLER_WIN_GL_H_
diff --git a/tests/cefclient/browser/osr_renderer.cc b/tests/cefclient/browser/osr_renderer.cc
new file mode 100644
index 00000000..c2804488
--- /dev/null
+++ b/tests/cefclient/browser/osr_renderer.cc
@@ -0,0 +1,412 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license
+// that can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/osr_renderer.h"
+
+#if defined(OS_WIN)
+#include <gl/gl.h>
+#elif defined(OS_MAC)
+#include <OpenGL/gl.h>
+#elif defined(OS_LINUX)
+#include <GL/gl.h>
+#else
+#error Platform is not supported.
+#endif
+
+#include "include/base/cef_logging.h"
+#include "include/wrapper/cef_helpers.h"
+
+#ifndef GL_BGR
+#define GL_BGR 0x80E0
+#endif
+#ifndef GL_BGRA
+#define GL_BGRA 0x80E1
+#endif
+#ifndef GL_UNSIGNED_INT_8_8_8_8_REV
+#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367
+#endif
+
+// DCHECK on gl errors.
+#if DCHECK_IS_ON()
+#define VERIFY_NO_ERROR \
+ { \
+ int _gl_error = glGetError(); \
+ DCHECK(_gl_error == GL_NO_ERROR) << "glGetError returned " << _gl_error; \
+ }
+#else
+#define VERIFY_NO_ERROR
+#endif
+
+namespace client {
+
+OsrRenderer::OsrRenderer(const OsrRendererSettings& settings)
+ : settings_(settings),
+ initialized_(false),
+ texture_id_(0),
+ view_width_(0),
+ view_height_(0),
+ spin_x_(0),
+ spin_y_(0) {}
+
+OsrRenderer::~OsrRenderer() {
+ Cleanup();
+}
+
+void OsrRenderer::Initialize() {
+ if (initialized_) {
+ return;
+ }
+
+ glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
+ VERIFY_NO_ERROR;
+
+ if (IsTransparent()) {
+ glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+ VERIFY_NO_ERROR;
+ } else {
+ glClearColor(float(CefColorGetR(settings_.background_color)) / 255.0f,
+ float(CefColorGetG(settings_.background_color)) / 255.0f,
+ float(CefColorGetB(settings_.background_color)) / 255.0f,
+ 1.0f);
+ VERIFY_NO_ERROR;
+ }
+
+ // Necessary for non-power-of-2 textures to render correctly.
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ VERIFY_NO_ERROR;
+
+ // Create the texture.
+ glGenTextures(1, &texture_id_);
+ VERIFY_NO_ERROR;
+ DCHECK_NE(texture_id_, 0U);
+ VERIFY_NO_ERROR;
+
+ glBindTexture(GL_TEXTURE_2D, texture_id_);
+ VERIFY_NO_ERROR;
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ VERIFY_NO_ERROR;
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ VERIFY_NO_ERROR;
+ glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ VERIFY_NO_ERROR;
+
+ initialized_ = true;
+}
+
+void OsrRenderer::Cleanup() {
+ if (texture_id_ != 0) {
+ glDeleteTextures(1, &texture_id_);
+ }
+}
+
+void OsrRenderer::Render() {
+ if (view_width_ == 0 || view_height_ == 0) {
+ return;
+ }
+
+ DCHECK(initialized_);
+
+ struct {
+ float tu, tv;
+ float x, y, z;
+ } static vertices[] = {{0.0f, 1.0f, -1.0f, -1.0f, 0.0f},
+ {1.0f, 1.0f, 1.0f, -1.0f, 0.0f},
+ {1.0f, 0.0f, 1.0f, 1.0f, 0.0f},
+ {0.0f, 0.0f, -1.0f, 1.0f, 0.0f}};
+
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ VERIFY_NO_ERROR;
+
+ glMatrixMode(GL_MODELVIEW);
+ VERIFY_NO_ERROR;
+ glLoadIdentity();
+ VERIFY_NO_ERROR;
+
+ // Match GL units to screen coordinates.
+ glViewport(0, 0, view_width_, view_height_);
+ VERIFY_NO_ERROR;
+ glMatrixMode(GL_PROJECTION);
+ VERIFY_NO_ERROR;
+ glLoadIdentity();
+ VERIFY_NO_ERROR;
+
+ // Draw the background gradient.
+ glPushAttrib(GL_ALL_ATTRIB_BITS);
+ VERIFY_NO_ERROR;
+ // Don't check for errors until glEnd().
+ glBegin(GL_QUADS);
+ glColor4f(1.0, 0.0, 0.0, 1.0); // red
+ glVertex2f(-1.0, -1.0);
+ glVertex2f(1.0, -1.0);
+ glColor4f(0.0, 0.0, 1.0, 1.0); // blue
+ glVertex2f(1.0, 1.0);
+ glVertex2f(-1.0, 1.0);
+ glEnd();
+ VERIFY_NO_ERROR;
+ glPopAttrib();
+ VERIFY_NO_ERROR;
+
+ // Rotate the view based on the mouse spin.
+ if (spin_x_ != 0) {
+ glRotatef(-spin_x_, 1.0f, 0.0f, 0.0f);
+ VERIFY_NO_ERROR;
+ }
+ if (spin_y_ != 0) {
+ glRotatef(-spin_y_, 0.0f, 1.0f, 0.0f);
+ VERIFY_NO_ERROR;
+ }
+
+ if (IsTransparent()) {
+ // Alpha blending style. Texture values have premultiplied alpha.
+ glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ VERIFY_NO_ERROR;
+
+ // Enable alpha blending.
+ glEnable(GL_BLEND);
+ VERIFY_NO_ERROR;
+ }
+
+ // Enable 2D textures.
+ glEnable(GL_TEXTURE_2D);
+ VERIFY_NO_ERROR;
+
+ // Draw the facets with the texture.
+ DCHECK_NE(texture_id_, 0U);
+ VERIFY_NO_ERROR;
+ glBindTexture(GL_TEXTURE_2D, texture_id_);
+ VERIFY_NO_ERROR;
+ glInterleavedArrays(GL_T2F_V3F, 0, vertices);
+ VERIFY_NO_ERROR;
+ glDrawArrays(GL_QUADS, 0, 4);
+ VERIFY_NO_ERROR;
+
+ // Disable 2D textures.
+ glDisable(GL_TEXTURE_2D);
+ VERIFY_NO_ERROR;
+
+ if (IsTransparent()) {
+ // Disable alpha blending.
+ glDisable(GL_BLEND);
+ VERIFY_NO_ERROR;
+ }
+
+ // Draw a rectangle around the update region.
+ if (settings_.show_update_rect && !update_rect_.IsEmpty()) {
+ int left = update_rect_.x;
+ int right = update_rect_.x + update_rect_.width;
+ int top = update_rect_.y;
+ int bottom = update_rect_.y + update_rect_.height;
+
+#if defined(OS_LINUX)
+ // Shrink the box so that top & right sides are drawn.
+ top += 1;
+ right -= 1;
+#else
+ // Shrink the box so that left & bottom sides are drawn.
+ left += 1;
+ bottom -= 1;
+#endif
+
+ glPushAttrib(GL_ALL_ATTRIB_BITS);
+ VERIFY_NO_ERROR
+ glMatrixMode(GL_PROJECTION);
+ VERIFY_NO_ERROR;
+ glPushMatrix();
+ VERIFY_NO_ERROR;
+ glLoadIdentity();
+ VERIFY_NO_ERROR;
+ glOrtho(0, view_width_, view_height_, 0, 0, 1);
+ VERIFY_NO_ERROR;
+
+ glLineWidth(1);
+ VERIFY_NO_ERROR;
+ glColor3f(1.0f, 0.0f, 0.0f);
+ VERIFY_NO_ERROR;
+ // Don't check for errors until glEnd().
+ glBegin(GL_LINE_STRIP);
+ glVertex2i(left, top);
+ glVertex2i(right, top);
+ glVertex2i(right, bottom);
+ glVertex2i(left, bottom);
+ glVertex2i(left, top);
+ glEnd();
+ VERIFY_NO_ERROR;
+
+ glPopMatrix();
+ VERIFY_NO_ERROR;
+ glPopAttrib();
+ VERIFY_NO_ERROR;
+ }
+}
+
+void OsrRenderer::OnPopupShow(CefRefPtr<CefBrowser> browser, bool show) {
+ if (!show) {
+ // Clear the popup rectangle.
+ ClearPopupRects();
+ }
+}
+
+void OsrRenderer::OnPopupSize(CefRefPtr<CefBrowser> browser,
+ const CefRect& rect) {
+ if (rect.width <= 0 || rect.height <= 0) {
+ return;
+ }
+ original_popup_rect_ = rect;
+ popup_rect_ = GetPopupRectInWebView(original_popup_rect_);
+}
+
+CefRect OsrRenderer::GetPopupRectInWebView(const CefRect& original_rect) {
+ CefRect rc(original_rect);
+ // if x or y are negative, move them to 0.
+ if (rc.x < 0) {
+ rc.x = 0;
+ }
+ if (rc.y < 0) {
+ rc.y = 0;
+ }
+ // if popup goes outside the view, try to reposition origin
+ if (rc.x + rc.width > view_width_) {
+ rc.x = view_width_ - rc.width;
+ }
+ if (rc.y + rc.height > view_height_) {
+ rc.y = view_height_ - rc.height;
+ }
+ // if x or y became negative, move them to 0 again.
+ if (rc.x < 0) {
+ rc.x = 0;
+ }
+ if (rc.y < 0) {
+ rc.y = 0;
+ }
+ return rc;
+}
+
+void OsrRenderer::ClearPopupRects() {
+ popup_rect_.Set(0, 0, 0, 0);
+ original_popup_rect_.Set(0, 0, 0, 0);
+}
+
+void OsrRenderer::OnPaint(CefRefPtr<CefBrowser> browser,
+ CefRenderHandler::PaintElementType type,
+ const CefRenderHandler::RectList& dirtyRects,
+ const void* buffer,
+ int width,
+ int height) {
+ if (!initialized_) {
+ Initialize();
+ }
+
+ if (IsTransparent()) {
+ // Enable alpha blending.
+ glEnable(GL_BLEND);
+ VERIFY_NO_ERROR;
+ }
+
+ // Enable 2D textures.
+ glEnable(GL_TEXTURE_2D);
+ VERIFY_NO_ERROR;
+
+ DCHECK_NE(texture_id_, 0U);
+ glBindTexture(GL_TEXTURE_2D, texture_id_);
+ VERIFY_NO_ERROR;
+
+ if (type == PET_VIEW) {
+ int old_width = view_width_;
+ int old_height = view_height_;
+
+ view_width_ = width;
+ view_height_ = height;
+
+ if (settings_.show_update_rect) {
+ update_rect_ = dirtyRects[0];
+ }
+
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, view_width_);
+ VERIFY_NO_ERROR;
+
+ if (old_width != view_width_ || old_height != view_height_ ||
+ (dirtyRects.size() == 1 &&
+ dirtyRects[0] == CefRect(0, 0, view_width_, view_height_))) {
+ // Update/resize the whole texture.
+ glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
+ VERIFY_NO_ERROR;
+ glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
+ VERIFY_NO_ERROR;
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, view_width_, view_height_, 0,
+ GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, buffer);
+ VERIFY_NO_ERROR;
+ } else {
+ // Update just the dirty rectangles.
+ CefRenderHandler::RectList::const_iterator i = dirtyRects.begin();
+ for (; i != dirtyRects.end(); ++i) {
+ const CefRect& rect = *i;
+ DCHECK(rect.x + rect.width <= view_width_);
+ DCHECK(rect.y + rect.height <= view_height_);
+ glPixelStorei(GL_UNPACK_SKIP_PIXELS, rect.x);
+ VERIFY_NO_ERROR;
+ glPixelStorei(GL_UNPACK_SKIP_ROWS, rect.y);
+ VERIFY_NO_ERROR;
+ glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x, rect.y, rect.width,
+ rect.height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,
+ buffer);
+ VERIFY_NO_ERROR;
+ }
+ }
+ } else if (type == PET_POPUP && popup_rect_.width > 0 &&
+ popup_rect_.height > 0) {
+ int skip_pixels = 0, x = popup_rect_.x;
+ int skip_rows = 0, y = popup_rect_.y;
+ int w = width;
+ int h = height;
+
+ // Adjust the popup to fit inside the view.
+ if (x < 0) {
+ skip_pixels = -x;
+ x = 0;
+ }
+ if (y < 0) {
+ skip_rows = -y;
+ y = 0;
+ }
+ if (x + w > view_width_) {
+ w -= x + w - view_width_;
+ }
+ if (y + h > view_height_) {
+ h -= y + h - view_height_;
+ }
+
+ // Update the popup rectangle.
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
+ VERIFY_NO_ERROR;
+ glPixelStorei(GL_UNPACK_SKIP_PIXELS, skip_pixels);
+ VERIFY_NO_ERROR;
+ glPixelStorei(GL_UNPACK_SKIP_ROWS, skip_rows);
+ VERIFY_NO_ERROR;
+ glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_BGRA,
+ GL_UNSIGNED_INT_8_8_8_8_REV, buffer);
+ VERIFY_NO_ERROR;
+ }
+
+ // Disable 2D textures.
+ glDisable(GL_TEXTURE_2D);
+ VERIFY_NO_ERROR;
+
+ if (IsTransparent()) {
+ // Disable alpha blending.
+ glDisable(GL_BLEND);
+ VERIFY_NO_ERROR;
+ }
+}
+
+void OsrRenderer::SetSpin(float spinX, float spinY) {
+ spin_x_ = spinX;
+ spin_y_ = spinY;
+}
+
+void OsrRenderer::IncrementSpin(float spinDX, float spinDY) {
+ spin_x_ -= spinDX;
+ spin_y_ -= spinDY;
+}
+
+} // namespace client
diff --git a/tests/cefclient/browser/osr_renderer.h b/tests/cefclient/browser/osr_renderer.h
new file mode 100644
index 00000000..f66cc24d
--- /dev/null
+++ b/tests/cefclient/browser/osr_renderer.h
@@ -0,0 +1,75 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license
+// that can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_OSR_RENDERER_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_OSR_RENDERER_H_
+#pragma once
+
+#include "include/cef_browser.h"
+#include "include/cef_render_handler.h"
+#include "tests/cefclient/browser/osr_renderer_settings.h"
+
+namespace client {
+
+class OsrRenderer {
+ public:
+ explicit OsrRenderer(const OsrRendererSettings& settings);
+ ~OsrRenderer();
+
+ // Initialize the OpenGL environment.
+ void Initialize();
+
+ // Clean up the OpenGL environment.
+ void Cleanup();
+
+ // Render to the screen.
+ void Render();
+
+ // Forwarded from CefRenderHandler callbacks.
+ void OnPopupShow(CefRefPtr<CefBrowser> browser, bool show);
+ // |rect| must be in pixel coordinates.
+ void OnPopupSize(CefRefPtr<CefBrowser> browser, const CefRect& rect);
+ void OnPaint(CefRefPtr<CefBrowser> browser,
+ CefRenderHandler::PaintElementType type,
+ const CefRenderHandler::RectList& dirtyRects,
+ const void* buffer,
+ int width,
+ int height);
+
+ // Apply spin.
+ void SetSpin(float spinX, float spinY);
+ void IncrementSpin(float spinDX, float spinDY);
+
+ int GetViewWidth() const { return view_width_; }
+ int GetViewHeight() const { return view_height_; }
+
+ CefRect popup_rect() const { return popup_rect_; }
+ CefRect original_popup_rect() const { return original_popup_rect_; }
+
+ void ClearPopupRects();
+
+ private:
+ CefRect GetPopupRectInWebView(const CefRect& original_rect);
+
+ inline bool IsTransparent() const {
+ return CefColorGetA(settings_.background_color) == 0;
+ }
+
+ const OsrRendererSettings settings_;
+ bool initialized_;
+ unsigned int texture_id_;
+ int view_width_;
+ int view_height_;
+ CefRect popup_rect_;
+ CefRect original_popup_rect_;
+ float spin_x_;
+ float spin_y_;
+ CefRect update_rect_;
+
+ DISALLOW_COPY_AND_ASSIGN(OsrRenderer);
+};
+
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_OSR_RENDERER_H_
diff --git a/tests/cefclient/browser/osr_renderer_settings.h b/tests/cefclient/browser/osr_renderer_settings.h
new file mode 100644
index 00000000..cbd560bb
--- /dev/null
+++ b/tests/cefclient/browser/osr_renderer_settings.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license
+// that can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_OSR_RENDERER_SETTINGS_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_OSR_RENDERER_SETTINGS_H_
+#pragma once
+
+#include "include/internal/cef_types.h"
+
+namespace client {
+
+struct OsrRendererSettings {
+ OsrRendererSettings()
+ : show_update_rect(false),
+ background_color(0),
+ shared_texture_enabled(false),
+ external_begin_frame_enabled(false),
+ begin_frame_rate(0) {}
+
+ // If true draw a border around update rectangles.
+ bool show_update_rect;
+
+ // Background color. Enables transparency if the alpha component is 0.
+ cef_color_t background_color;
+
+ // Render using shared textures. Supported on Windows only via D3D11.
+ bool shared_texture_enabled;
+
+ // Client implements a BeginFrame timer by calling
+ // CefBrowserHost::SendExternalBeginFrame at the specified frame rate.
+ bool external_begin_frame_enabled;
+ int begin_frame_rate;
+};
+
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_OSR_RENDERER_SETTINGS_H_
diff --git a/tests/cefclient/browser/osr_window_win.cc b/tests/cefclient/browser/osr_window_win.cc
new file mode 100644
index 00000000..91351090
--- /dev/null
+++ b/tests/cefclient/browser/osr_window_win.cc
@@ -0,0 +1,1230 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/osr_window_win.h"
+
+#include <windowsx.h>
+#if defined(CEF_USE_ATL)
+#include <oleacc.h>
+#endif
+
+#include "include/base/cef_build.h"
+#include "tests/cefclient/browser/main_context.h"
+#include "tests/cefclient/browser/osr_accessibility_helper.h"
+#include "tests/cefclient/browser/osr_accessibility_node.h"
+#include "tests/cefclient/browser/osr_ime_handler_win.h"
+#include "tests/cefclient/browser/osr_render_handler_win_d3d11.h"
+#include "tests/cefclient/browser/osr_render_handler_win_gl.h"
+#include "tests/cefclient/browser/resource.h"
+#include "tests/shared/browser/geometry_util.h"
+#include "tests/shared/browser/main_message_loop.h"
+#include "tests/shared/browser/util_win.h"
+
+namespace client {
+
+namespace {
+
+const wchar_t kWndClass[] = L"Client_OsrWindow";
+
+// Helper funtion to check if it is Windows8 or greater.
+// https://msdn.microsoft.com/en-us/library/ms724833(v=vs.85).aspx
+inline BOOL IsWindows_8_Or_Newer() {
+ OSVERSIONINFOEX osvi = {0};
+ osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
+ osvi.dwMajorVersion = 6;
+ osvi.dwMinorVersion = 2;
+ DWORDLONG dwlConditionMask = 0;
+ VER_SET_CONDITION(dwlConditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL);
+ VER_SET_CONDITION(dwlConditionMask, VER_MINORVERSION, VER_GREATER_EQUAL);
+ return ::VerifyVersionInfo(&osvi, VER_MAJORVERSION | VER_MINORVERSION,
+ dwlConditionMask);
+}
+
+// Helper function to detect mouse messages coming from emulation of touch
+// events. These should be ignored.
+bool IsMouseEventFromTouch(UINT message) {
+#define MOUSEEVENTF_FROMTOUCH 0xFF515700
+ return (message >= WM_MOUSEFIRST) && (message <= WM_MOUSELAST) &&
+ (GetMessageExtraInfo() & MOUSEEVENTF_FROMTOUCH) ==
+ MOUSEEVENTF_FROMTOUCH;
+}
+
+class CreateBrowserHelper {
+ public:
+ CreateBrowserHelper(HWND hwnd,
+ const RECT& rect,
+ CefRefPtr<CefClient> handler,
+ const std::string& url,
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefDictionaryValue> extra_info,
+ CefRefPtr<CefRequestContext> request_context,
+ OsrWindowWin* osr_window_win)
+ : hwnd_(hwnd),
+ rect_(rect),
+ handler_(handler),
+ url_(url),
+ settings_(settings),
+ extra_info_(extra_info),
+ request_context_(request_context),
+ osr_window_win_(osr_window_win) {}
+
+ HWND hwnd_;
+ RECT rect_;
+ CefRefPtr<CefClient> handler_;
+ std::string url_;
+ CefBrowserSettings settings_;
+ CefRefPtr<CefDictionaryValue> extra_info_;
+ CefRefPtr<CefRequestContext> request_context_;
+ OsrWindowWin* osr_window_win_;
+};
+
+} // namespace
+
+OsrWindowWin::OsrWindowWin(Delegate* delegate,
+ const OsrRendererSettings& settings)
+ : delegate_(delegate),
+ settings_(settings),
+ hwnd_(nullptr),
+ device_scale_factor_(0),
+ hidden_(false),
+ last_mouse_pos_(),
+ current_mouse_pos_(),
+ mouse_rotation_(false),
+ mouse_tracking_(false),
+ last_click_x_(0),
+ last_click_y_(0),
+ last_click_button_(MBT_LEFT),
+ last_click_count_(1),
+ last_click_time_(0),
+ last_mouse_down_on_view_(false) {
+ DCHECK(delegate_);
+ client_rect_ = {0};
+}
+
+OsrWindowWin::~OsrWindowWin() {
+ CEF_REQUIRE_UI_THREAD();
+ // The native window should have already been destroyed.
+ DCHECK(!hwnd_ && !render_handler_.get());
+}
+
+void CreateBrowserWithHelper(CreateBrowserHelper* helper) {
+ helper->osr_window_win_->CreateBrowser(
+ helper->hwnd_, helper->rect_, helper->handler_, helper->settings_,
+ helper->extra_info_, helper->request_context_, helper->url_);
+ delete helper;
+}
+
+void OsrWindowWin::CreateBrowser(HWND parent_hwnd,
+ const RECT& rect,
+ CefRefPtr<CefClient> handler,
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefDictionaryValue> extra_info,
+ CefRefPtr<CefRequestContext> request_context,
+ const std::string& startup_url) {
+ if (!CefCurrentlyOn(TID_UI)) {
+ // Execute this method on the UI thread.
+ CreateBrowserHelper* helper =
+ new CreateBrowserHelper(parent_hwnd, rect, handler, startup_url,
+ settings, extra_info, request_context, this);
+ CefPostTask(TID_UI, base::BindOnce(CreateBrowserWithHelper, helper));
+ return;
+ }
+
+ // Create the native window.
+ Create(parent_hwnd, rect);
+
+ CefWindowInfo window_info;
+ window_info.SetAsWindowless(hwnd_);
+
+ if (GetWindowLongPtr(parent_hwnd, GWL_EXSTYLE) & WS_EX_NOACTIVATE) {
+ // Don't activate the browser window on creation.
+ window_info.ex_style |= WS_EX_NOACTIVATE;
+ }
+
+ window_info.shared_texture_enabled = settings_.shared_texture_enabled;
+ window_info.external_begin_frame_enabled =
+ settings_.external_begin_frame_enabled;
+
+ // Create the browser asynchronously.
+ CefBrowserHost::CreateBrowser(window_info, handler, startup_url, settings,
+ extra_info, request_context);
+}
+
+void OsrWindowWin::ShowPopup(HWND parent_hwnd,
+ int x,
+ int y,
+ size_t width,
+ size_t height) {
+ if (!CefCurrentlyOn(TID_UI)) {
+ // Execute this method on the UI thread.
+ CefPostTask(TID_UI, base::BindOnce(&OsrWindowWin::ShowPopup, this,
+ parent_hwnd, x, y, width, height));
+ return;
+ }
+
+ DCHECK(browser_.get());
+
+ // Create the native window.
+ const RECT rect = {x, y, x + static_cast<int>(width),
+ y + static_cast<int>(height)};
+ Create(parent_hwnd, rect);
+
+ // Create the render handler.
+ EnsureRenderHandler();
+ render_handler_->SetBrowser(browser_);
+
+ // Send resize notification so the compositor is assigned the correct
+ // viewport size and begins rendering.
+ browser_->GetHost()->WasResized();
+
+ Show();
+}
+
+void OsrWindowWin::Show() {
+ if (!CefCurrentlyOn(TID_UI)) {
+ // Execute this method on the UI thread.
+ CefPostTask(TID_UI, base::BindOnce(&OsrWindowWin::Show, this));
+ return;
+ }
+
+ if (!browser_) {
+ return;
+ }
+
+ // Show the native window if not currently visible.
+ if (hwnd_ && !::IsWindowVisible(hwnd_)) {
+ ShowWindow(hwnd_, SW_SHOW);
+ }
+
+ if (hidden_) {
+ // Set the browser as visible.
+ browser_->GetHost()->WasHidden(false);
+ hidden_ = false;
+ }
+
+ // Give focus to the browser.
+ browser_->GetHost()->SetFocus(true);
+}
+
+void OsrWindowWin::Hide() {
+ if (!CefCurrentlyOn(TID_UI)) {
+ // Execute this method on the UI thread.
+ CefPostTask(TID_UI, base::BindOnce(&OsrWindowWin::Hide, this));
+ return;
+ }
+
+ if (!browser_) {
+ return;
+ }
+
+ // Remove focus from the browser.
+ browser_->GetHost()->SetFocus(false);
+
+ if (!hidden_) {
+ // Set the browser as hidden.
+ browser_->GetHost()->WasHidden(true);
+ hidden_ = true;
+ }
+}
+
+void OsrWindowWin::SetBounds(int x, int y, size_t width, size_t height) {
+ if (!CefCurrentlyOn(TID_UI)) {
+ // Execute this method on the UI thread.
+ CefPostTask(TID_UI, base::BindOnce(&OsrWindowWin::SetBounds, this, x, y,
+ width, height));
+ return;
+ }
+
+ if (hwnd_) {
+ // Set the browser window bounds.
+ ::SetWindowPos(hwnd_, nullptr, x, y, static_cast<int>(width),
+ static_cast<int>(height), SWP_NOZORDER);
+ }
+}
+
+void OsrWindowWin::SetFocus() {
+ if (!CefCurrentlyOn(TID_UI)) {
+ // Execute this method on the UI thread.
+ CefPostTask(TID_UI, base::BindOnce(&OsrWindowWin::SetFocus, this));
+ return;
+ }
+
+ if (hwnd_) {
+ // Give focus to the native window.
+ ::SetFocus(hwnd_);
+ }
+}
+
+void OsrWindowWin::SetDeviceScaleFactor(float device_scale_factor) {
+ if (!CefCurrentlyOn(TID_UI)) {
+ // Execute this method on the UI thread.
+ CefPostTask(TID_UI, base::BindOnce(&OsrWindowWin::SetDeviceScaleFactor,
+ this, device_scale_factor));
+ return;
+ }
+
+ if (device_scale_factor == device_scale_factor_) {
+ return;
+ }
+
+ device_scale_factor_ = device_scale_factor;
+ if (browser_) {
+ browser_->GetHost()->NotifyScreenInfoChanged();
+ browser_->GetHost()->WasResized();
+ }
+}
+
+void OsrWindowWin::Create(HWND parent_hwnd, const RECT& rect) {
+ CEF_REQUIRE_UI_THREAD();
+ DCHECK(!hwnd_ && !render_handler_.get());
+ DCHECK(parent_hwnd);
+ DCHECK(!::IsRectEmpty(&rect));
+
+ HINSTANCE hInst = ::GetModuleHandle(nullptr);
+
+ const cef_color_t background_color = MainContext::Get()->GetBackgroundColor();
+ const HBRUSH background_brush = CreateSolidBrush(
+ RGB(CefColorGetR(background_color), CefColorGetG(background_color),
+ CefColorGetB(background_color)));
+
+ RegisterOsrClass(hInst, background_brush);
+
+ DWORD ex_style = 0;
+ if (GetWindowLongPtr(parent_hwnd, GWL_EXSTYLE) & WS_EX_NOACTIVATE) {
+ // Don't activate the browser window on creation.
+ ex_style |= WS_EX_NOACTIVATE;
+ }
+
+ // Create the native window with a border so it's easier to visually identify
+ // OSR windows.
+ hwnd_ = ::CreateWindowEx(
+ ex_style, kWndClass, 0,
+ WS_BORDER | WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE,
+ rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
+ parent_hwnd, 0, hInst, 0);
+ CHECK(hwnd_);
+
+ client_rect_ = rect;
+
+ // Associate |this| with the window.
+ SetUserDataPtr(hwnd_, this);
+
+#if defined(CEF_USE_ATL)
+ accessibility_root_ = nullptr;
+
+ // Create/register the drag&drop handler.
+ drop_target_ = DropTargetWin::Create(this, hwnd_);
+ HRESULT register_res = RegisterDragDrop(hwnd_, drop_target_);
+ DCHECK_EQ(register_res, S_OK);
+#endif
+
+ ime_handler_.reset(new OsrImeHandlerWin(hwnd_));
+
+ // Enable Touch Events if requested
+ if (client::MainContext::Get()->TouchEventsEnabled()) {
+ RegisterTouchWindow(hwnd_, 0);
+ }
+
+ // Notify the window owner.
+ NotifyNativeWindowCreated(hwnd_);
+}
+
+void OsrWindowWin::Destroy() {
+ CEF_REQUIRE_UI_THREAD();
+ DCHECK(hwnd_ != nullptr);
+
+#if defined(CEF_USE_ATL)
+ // Revoke/delete the drag&drop handler.
+ RevokeDragDrop(hwnd_);
+ drop_target_ = nullptr;
+#endif
+
+ render_handler_.reset();
+
+ // Destroy the native window.
+ ::DestroyWindow(hwnd_);
+ ime_handler_.reset();
+ hwnd_ = nullptr;
+}
+
+void OsrWindowWin::NotifyNativeWindowCreated(HWND hwnd) {
+ if (!CURRENTLY_ON_MAIN_THREAD()) {
+ // Execute this method on the main thread.
+ MAIN_POST_CLOSURE(
+ base::BindOnce(&OsrWindowWin::NotifyNativeWindowCreated, this, hwnd));
+ return;
+ }
+
+ delegate_->OnOsrNativeWindowCreated(hwnd);
+}
+
+// static
+void OsrWindowWin::RegisterOsrClass(HINSTANCE hInstance,
+ HBRUSH background_brush) {
+ // Only register the class one time.
+ static bool class_registered = false;
+ if (class_registered) {
+ return;
+ }
+ class_registered = true;
+
+ WNDCLASSEX wcex;
+
+ wcex.cbSize = sizeof(WNDCLASSEX);
+ wcex.style = CS_OWNDC;
+ wcex.lpfnWndProc = OsrWndProc;
+ wcex.cbClsExtra = 0;
+ wcex.cbWndExtra = 0;
+ wcex.hInstance = hInstance;
+ wcex.hIcon = nullptr;
+ wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
+ wcex.hbrBackground = background_brush;
+ wcex.lpszMenuName = nullptr;
+ wcex.lpszClassName = kWndClass;
+ wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
+
+ RegisterClassEx(&wcex);
+}
+
+void OsrWindowWin::OnIMESetContext(UINT message, WPARAM wParam, LPARAM lParam) {
+ // We handle the IME Composition Window ourselves (but let the IME Candidates
+ // Window be handled by IME through DefWindowProc()), so clear the
+ // ISC_SHOWUICOMPOSITIONWINDOW flag:
+ lParam &= ~ISC_SHOWUICOMPOSITIONWINDOW;
+ ::DefWindowProc(hwnd_, message, wParam, lParam);
+
+ // Create Caret Window if required
+ if (ime_handler_) {
+ ime_handler_->CreateImeWindow();
+ ime_handler_->MoveImeWindow();
+ }
+}
+
+void OsrWindowWin::OnIMEStartComposition() {
+ if (ime_handler_) {
+ ime_handler_->CreateImeWindow();
+ ime_handler_->MoveImeWindow();
+ ime_handler_->ResetComposition();
+ }
+}
+
+void OsrWindowWin::OnIMEComposition(UINT message,
+ WPARAM wParam,
+ LPARAM lParam) {
+ if (browser_ && ime_handler_) {
+ CefString cTextStr;
+ if (ime_handler_->GetResult(lParam, cTextStr)) {
+ // Send the text to the browser. The |replacement_range| and
+ // |relative_cursor_pos| params are not used on Windows, so provide
+ // default invalid values.
+ browser_->GetHost()->ImeCommitText(cTextStr,
+ CefRange(UINT32_MAX, UINT32_MAX), 0);
+ ime_handler_->ResetComposition();
+ // Continue reading the composition string - Japanese IMEs send both
+ // GCS_RESULTSTR and GCS_COMPSTR.
+ }
+
+ std::vector<CefCompositionUnderline> underlines;
+ int composition_start = 0;
+
+ if (ime_handler_->GetComposition(lParam, cTextStr, underlines,
+ composition_start)) {
+ // Send the composition string to the browser. The |replacement_range|
+ // param is not used on Windows, so provide a default invalid value.
+ browser_->GetHost()->ImeSetComposition(
+ cTextStr, underlines, CefRange(UINT32_MAX, UINT32_MAX),
+ CefRange(composition_start,
+ static_cast<int>(composition_start + cTextStr.length())));
+
+ // Update the Candidate Window position. The cursor is at the end so
+ // subtract 1. This is safe because IMM32 does not support non-zero-width
+ // in a composition. Also, negative values are safely ignored in
+ // MoveImeWindow
+ ime_handler_->UpdateCaretPosition(composition_start - 1);
+ } else {
+ OnIMECancelCompositionEvent();
+ }
+ }
+}
+
+void OsrWindowWin::OnIMECancelCompositionEvent() {
+ if (browser_ && ime_handler_) {
+ browser_->GetHost()->ImeCancelComposition();
+ ime_handler_->ResetComposition();
+ ime_handler_->DestroyImeWindow();
+ }
+}
+
+// static
+LRESULT CALLBACK OsrWindowWin::OsrWndProc(HWND hWnd,
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam) {
+ CEF_REQUIRE_UI_THREAD();
+
+ OsrWindowWin* self = GetUserDataPtr<OsrWindowWin*>(hWnd);
+ if (!self) {
+ return DefWindowProc(hWnd, message, wParam, lParam);
+ }
+
+ // We want to handle IME events before the OS does any default handling.
+ switch (message) {
+ case WM_IME_SETCONTEXT:
+ self->OnIMESetContext(message, wParam, lParam);
+ return 0;
+ case WM_IME_STARTCOMPOSITION:
+ self->OnIMEStartComposition();
+ return 0;
+ case WM_IME_COMPOSITION:
+ self->OnIMEComposition(message, wParam, lParam);
+ return 0;
+ case WM_IME_ENDCOMPOSITION:
+ self->OnIMECancelCompositionEvent();
+ // Let WTL call::DefWindowProc() and release its resources.
+ break;
+#if defined(CEF_USE_ATL)
+ case WM_GETOBJECT: {
+ // Only the lower 32 bits of lParam are valid when checking the object id
+ // because it sometimes gets sign-extended incorrectly (but not always).
+ DWORD obj_id = static_cast<DWORD>(static_cast<DWORD_PTR>(lParam));
+
+ // Accessibility readers will send an OBJID_CLIENT message.
+ if (static_cast<DWORD>(OBJID_CLIENT) == obj_id) {
+ if (self->accessibility_root_) {
+ return LresultFromObject(
+ IID_IAccessible, wParam,
+ static_cast<IAccessible*>(self->accessibility_root_));
+ } else {
+ // Notify the renderer to enable accessibility.
+ if (self->browser_ && self->browser_->GetHost()) {
+ self->browser_->GetHost()->SetAccessibilityState(STATE_ENABLED);
+ }
+ }
+ }
+ } break;
+#endif
+ case WM_LBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ case WM_MBUTTONDOWN:
+ case WM_LBUTTONUP:
+ case WM_RBUTTONUP:
+ case WM_MBUTTONUP:
+ case WM_MOUSEMOVE:
+ case WM_MOUSELEAVE:
+ case WM_MOUSEWHEEL:
+ self->OnMouseEvent(message, wParam, lParam);
+ break;
+
+ case WM_SIZE:
+ self->OnSize();
+ break;
+
+ case WM_SETFOCUS:
+ case WM_KILLFOCUS:
+ self->OnFocus(message == WM_SETFOCUS);
+ break;
+
+ case WM_CAPTURECHANGED:
+ case WM_CANCELMODE:
+ self->OnCaptureLost();
+ break;
+
+ case WM_SYSCHAR:
+ case WM_SYSKEYDOWN:
+ case WM_SYSKEYUP:
+ case WM_KEYDOWN:
+ case WM_KEYUP:
+ case WM_CHAR:
+ self->OnKeyEvent(message, wParam, lParam);
+ break;
+
+ case WM_PAINT:
+ self->OnPaint();
+ return 0;
+
+ case WM_ERASEBKGND:
+ if (self->OnEraseBkgnd()) {
+ break;
+ }
+ // Don't erase the background.
+ return 0;
+
+ // If your application does not require Win7 support, please do consider
+ // using WM_POINTER* messages instead of WM_TOUCH. WM_POINTER are more
+ // intutive, complete and simpler to code.
+ // https://msdn.microsoft.com/en-us/library/hh454903(v=vs.85).aspx
+ case WM_TOUCH:
+ if (self->OnTouchEvent(message, wParam, lParam)) {
+ return 0;
+ }
+ break;
+
+ case WM_NCDESTROY:
+ // Clear the reference to |self|.
+ SetUserDataPtr(hWnd, nullptr);
+ self->hwnd_ = nullptr;
+ break;
+ }
+
+ return DefWindowProc(hWnd, message, wParam, lParam);
+}
+
+void OsrWindowWin::OnMouseEvent(UINT message, WPARAM wParam, LPARAM lParam) {
+ if (IsMouseEventFromTouch(message)) {
+ return;
+ }
+
+ CefRefPtr<CefBrowserHost> browser_host;
+ if (browser_) {
+ browser_host = browser_->GetHost();
+ }
+
+ LONG currentTime = 0;
+ bool cancelPreviousClick = false;
+
+ if (message == WM_LBUTTONDOWN || message == WM_RBUTTONDOWN ||
+ message == WM_MBUTTONDOWN || message == WM_MOUSEMOVE ||
+ message == WM_MOUSELEAVE) {
+ currentTime = GetMessageTime();
+ int x = GET_X_LPARAM(lParam);
+ int y = GET_Y_LPARAM(lParam);
+ cancelPreviousClick =
+ (abs(last_click_x_ - x) > (GetSystemMetrics(SM_CXDOUBLECLK) / 2)) ||
+ (abs(last_click_y_ - y) > (GetSystemMetrics(SM_CYDOUBLECLK) / 2)) ||
+ ((currentTime - last_click_time_) > GetDoubleClickTime());
+ if (cancelPreviousClick &&
+ (message == WM_MOUSEMOVE || message == WM_MOUSELEAVE)) {
+ last_click_count_ = 1;
+ last_click_x_ = 0;
+ last_click_y_ = 0;
+ last_click_time_ = 0;
+ }
+ }
+
+ switch (message) {
+ case WM_LBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ case WM_MBUTTONDOWN: {
+ ::SetCapture(hwnd_);
+ ::SetFocus(hwnd_);
+ int x = GET_X_LPARAM(lParam);
+ int y = GET_Y_LPARAM(lParam);
+ if (wParam & MK_SHIFT) {
+ // Start rotation effect.
+ last_mouse_pos_.x = current_mouse_pos_.x = x;
+ last_mouse_pos_.y = current_mouse_pos_.y = y;
+ mouse_rotation_ = true;
+ } else {
+ CefBrowserHost::MouseButtonType btnType =
+ (message == WM_LBUTTONDOWN
+ ? MBT_LEFT
+ : (message == WM_RBUTTONDOWN ? MBT_RIGHT : MBT_MIDDLE));
+ if (!cancelPreviousClick && (btnType == last_click_button_)) {
+ ++last_click_count_;
+ } else {
+ last_click_count_ = 1;
+ last_click_x_ = x;
+ last_click_y_ = y;
+ }
+ last_click_time_ = currentTime;
+ last_click_button_ = btnType;
+
+ if (browser_host) {
+ CefMouseEvent mouse_event;
+ mouse_event.x = x;
+ mouse_event.y = y;
+ last_mouse_down_on_view_ = !IsOverPopupWidget(x, y);
+ ApplyPopupOffset(mouse_event.x, mouse_event.y);
+ DeviceToLogical(mouse_event, device_scale_factor_);
+ mouse_event.modifiers = GetCefMouseModifiers(wParam);
+ browser_host->SendMouseClickEvent(mouse_event, btnType, false,
+ last_click_count_);
+ }
+ }
+ } break;
+
+ case WM_LBUTTONUP:
+ case WM_RBUTTONUP:
+ case WM_MBUTTONUP:
+ if (GetCapture() == hwnd_) {
+ ReleaseCapture();
+ }
+ if (mouse_rotation_) {
+ // End rotation effect.
+ mouse_rotation_ = false;
+ render_handler_->SetSpin(0, 0);
+ } else {
+ int x = GET_X_LPARAM(lParam);
+ int y = GET_Y_LPARAM(lParam);
+ CefBrowserHost::MouseButtonType btnType =
+ (message == WM_LBUTTONUP
+ ? MBT_LEFT
+ : (message == WM_RBUTTONUP ? MBT_RIGHT : MBT_MIDDLE));
+ if (browser_host) {
+ CefMouseEvent mouse_event;
+ mouse_event.x = x;
+ mouse_event.y = y;
+ if (last_mouse_down_on_view_ && IsOverPopupWidget(x, y) &&
+ (GetPopupXOffset() || GetPopupYOffset())) {
+ break;
+ }
+ ApplyPopupOffset(mouse_event.x, mouse_event.y);
+ DeviceToLogical(mouse_event, device_scale_factor_);
+ mouse_event.modifiers = GetCefMouseModifiers(wParam);
+ browser_host->SendMouseClickEvent(mouse_event, btnType, true,
+ last_click_count_);
+ }
+ }
+ break;
+
+ case WM_MOUSEMOVE: {
+ int x = GET_X_LPARAM(lParam);
+ int y = GET_Y_LPARAM(lParam);
+ if (mouse_rotation_) {
+ // Apply rotation effect.
+ current_mouse_pos_.x = x;
+ current_mouse_pos_.y = y;
+ render_handler_->IncrementSpin(
+ current_mouse_pos_.x - last_mouse_pos_.x,
+ current_mouse_pos_.y - last_mouse_pos_.y);
+ last_mouse_pos_.x = current_mouse_pos_.x;
+ last_mouse_pos_.y = current_mouse_pos_.y;
+ } else {
+ if (!mouse_tracking_) {
+ // Start tracking mouse leave. Required for the WM_MOUSELEAVE event to
+ // be generated.
+ TRACKMOUSEEVENT tme;
+ tme.cbSize = sizeof(TRACKMOUSEEVENT);
+ tme.dwFlags = TME_LEAVE;
+ tme.hwndTrack = hwnd_;
+ TrackMouseEvent(&tme);
+ mouse_tracking_ = true;
+ }
+
+ if (browser_host) {
+ CefMouseEvent mouse_event;
+ mouse_event.x = x;
+ mouse_event.y = y;
+ ApplyPopupOffset(mouse_event.x, mouse_event.y);
+ DeviceToLogical(mouse_event, device_scale_factor_);
+ mouse_event.modifiers = GetCefMouseModifiers(wParam);
+ browser_host->SendMouseMoveEvent(mouse_event, false);
+ }
+ }
+ break;
+ }
+
+ case WM_MOUSELEAVE: {
+ if (mouse_tracking_) {
+ // Stop tracking mouse leave.
+ TRACKMOUSEEVENT tme;
+ tme.cbSize = sizeof(TRACKMOUSEEVENT);
+ tme.dwFlags = TME_LEAVE & TME_CANCEL;
+ tme.hwndTrack = hwnd_;
+ TrackMouseEvent(&tme);
+ mouse_tracking_ = false;
+ }
+
+ if (browser_host) {
+ // Determine the cursor position in screen coordinates.
+ POINT p;
+ ::GetCursorPos(&p);
+ ::ScreenToClient(hwnd_, &p);
+
+ CefMouseEvent mouse_event;
+ mouse_event.x = p.x;
+ mouse_event.y = p.y;
+ DeviceToLogical(mouse_event, device_scale_factor_);
+ mouse_event.modifiers = GetCefMouseModifiers(wParam);
+ browser_host->SendMouseMoveEvent(mouse_event, true);
+ }
+ } break;
+
+ case WM_MOUSEWHEEL:
+ if (browser_host) {
+ POINT screen_point = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
+ HWND scrolled_wnd = ::WindowFromPoint(screen_point);
+ if (scrolled_wnd != hwnd_) {
+ break;
+ }
+
+ ScreenToClient(hwnd_, &screen_point);
+ int delta = GET_WHEEL_DELTA_WPARAM(wParam);
+
+ CefMouseEvent mouse_event;
+ mouse_event.x = screen_point.x;
+ mouse_event.y = screen_point.y;
+ ApplyPopupOffset(mouse_event.x, mouse_event.y);
+ DeviceToLogical(mouse_event, device_scale_factor_);
+ mouse_event.modifiers = GetCefMouseModifiers(wParam);
+ browser_host->SendMouseWheelEvent(mouse_event,
+ IsKeyDown(VK_SHIFT) ? delta : 0,
+ !IsKeyDown(VK_SHIFT) ? delta : 0);
+ }
+ break;
+ }
+}
+
+void OsrWindowWin::OnSize() {
+ // Keep |client_rect_| up to date.
+ ::GetClientRect(hwnd_, &client_rect_);
+
+ if (browser_) {
+ browser_->GetHost()->WasResized();
+ }
+}
+
+void OsrWindowWin::OnFocus(bool setFocus) {
+ if (browser_) {
+ browser_->GetHost()->SetFocus(setFocus);
+ }
+}
+
+void OsrWindowWin::OnCaptureLost() {
+ if (mouse_rotation_) {
+ return;
+ }
+
+ if (browser_) {
+ browser_->GetHost()->SendCaptureLostEvent();
+ }
+}
+
+void OsrWindowWin::OnKeyEvent(UINT message, WPARAM wParam, LPARAM lParam) {
+ if (!browser_) {
+ return;
+ }
+
+ CefKeyEvent event;
+ event.windows_key_code = wParam;
+ event.native_key_code = lParam;
+ event.is_system_key = message == WM_SYSCHAR || message == WM_SYSKEYDOWN ||
+ message == WM_SYSKEYUP;
+
+ if (message == WM_KEYDOWN || message == WM_SYSKEYDOWN) {
+ event.type = KEYEVENT_RAWKEYDOWN;
+ } else if (message == WM_KEYUP || message == WM_SYSKEYUP) {
+ event.type = KEYEVENT_KEYUP;
+ } else {
+ event.type = KEYEVENT_CHAR;
+ }
+ event.modifiers = GetCefKeyboardModifiers(wParam, lParam);
+
+ // mimic alt-gr check behaviour from
+ // src/ui/events/win/events_win_utils.cc: GetModifiersFromKeyState
+ if ((event.type == KEYEVENT_CHAR) && IsKeyDown(VK_RMENU)) {
+ // reverse AltGr detection taken from PlatformKeyMap::UsesAltGraph
+ // instead of checking all combination for ctrl-alt, just check current char
+ HKL current_layout = ::GetKeyboardLayout(0);
+
+ // https://docs.microsoft.com/en-gb/windows/win32/api/winuser/nf-winuser-vkkeyscanexw
+ // ... high-order byte contains the shift state,
+ // which can be a combination of the following flag bits.
+ // 1 Either SHIFT key is pressed.
+ // 2 Either CTRL key is pressed.
+ // 4 Either ALT key is pressed.
+ SHORT scan_res = ::VkKeyScanExW(wParam, current_layout);
+ constexpr auto ctrlAlt = (2 | 4);
+ if (((scan_res >> 8) & ctrlAlt) == ctrlAlt) { // ctrl-alt pressed
+ event.modifiers &= ~(EVENTFLAG_CONTROL_DOWN | EVENTFLAG_ALT_DOWN);
+ event.modifiers |= EVENTFLAG_ALTGR_DOWN;
+ }
+ }
+
+ browser_->GetHost()->SendKeyEvent(event);
+}
+
+void OsrWindowWin::OnPaint() {
+ // Paint nothing here. Invalidate will cause OnPaint to be called for the
+ // render handler.
+ PAINTSTRUCT ps;
+ BeginPaint(hwnd_, &ps);
+ EndPaint(hwnd_, &ps);
+
+ if (browser_) {
+ browser_->GetHost()->Invalidate(PET_VIEW);
+ }
+}
+
+bool OsrWindowWin::OnEraseBkgnd() {
+ // Erase the background when the browser does not exist.
+ return (browser_ == nullptr);
+}
+
+bool OsrWindowWin::OnTouchEvent(UINT message, WPARAM wParam, LPARAM lParam) {
+ // Handle touch events on Windows.
+ int num_points = LOWORD(wParam);
+ // Chromium only supports upto 16 touch points.
+ if (num_points < 0 || num_points > 16) {
+ return false;
+ }
+ std::unique_ptr<TOUCHINPUT[]> input(new TOUCHINPUT[num_points]);
+ if (GetTouchInputInfo(reinterpret_cast<HTOUCHINPUT>(lParam), num_points,
+ input.get(), sizeof(TOUCHINPUT))) {
+ CefTouchEvent touch_event;
+ for (int i = 0; i < num_points; ++i) {
+ POINT point;
+ point.x = TOUCH_COORD_TO_PIXEL(input[i].x);
+ point.y = TOUCH_COORD_TO_PIXEL(input[i].y);
+
+ if (!IsWindows_8_Or_Newer()) {
+ // Windows 7 sends touch events for touches in the non-client area,
+ // whereas Windows 8 does not. In order to unify the behaviour, always
+ // ignore touch events in the non-client area.
+ LPARAM l_param_ht = MAKELPARAM(point.x, point.y);
+ LRESULT hittest = SendMessage(hwnd_, WM_NCHITTEST, 0, l_param_ht);
+ if (hittest != HTCLIENT) {
+ return false;
+ }
+ }
+
+ ScreenToClient(hwnd_, &point);
+ touch_event.x = DeviceToLogical(point.x, device_scale_factor_);
+ touch_event.y = DeviceToLogical(point.y, device_scale_factor_);
+
+ // Touch point identifier stays consistent in a touch contact sequence
+ touch_event.id = input[i].dwID;
+
+ if (input[i].dwFlags & TOUCHEVENTF_DOWN) {
+ touch_event.type = CEF_TET_PRESSED;
+ } else if (input[i].dwFlags & TOUCHEVENTF_MOVE) {
+ touch_event.type = CEF_TET_MOVED;
+ } else if (input[i].dwFlags & TOUCHEVENTF_UP) {
+ touch_event.type = CEF_TET_RELEASED;
+ }
+
+ touch_event.radius_x = 0;
+ touch_event.radius_y = 0;
+ touch_event.rotation_angle = 0;
+ touch_event.pressure = 0;
+ touch_event.modifiers = 0;
+
+ // Notify the browser of touch event
+ if (browser_) {
+ browser_->GetHost()->SendTouchEvent(touch_event);
+ }
+ }
+ CloseTouchInputHandle(reinterpret_cast<HTOUCHINPUT>(lParam));
+ return true;
+ }
+
+ return false;
+}
+
+bool OsrWindowWin::IsOverPopupWidget(int x, int y) const {
+ if (!render_handler_) {
+ return false;
+ }
+ return render_handler_->IsOverPopupWidget(x, y);
+}
+
+int OsrWindowWin::GetPopupXOffset() const {
+ return render_handler_->GetPopupXOffset();
+}
+
+int OsrWindowWin::GetPopupYOffset() const {
+ return render_handler_->GetPopupYOffset();
+}
+
+void OsrWindowWin::ApplyPopupOffset(int& x, int& y) const {
+ if (IsOverPopupWidget(x, y)) {
+ x += GetPopupXOffset();
+ y += GetPopupYOffset();
+ }
+}
+
+void OsrWindowWin::OnAfterCreated(CefRefPtr<CefBrowser> browser) {
+ CEF_REQUIRE_UI_THREAD();
+ DCHECK(!browser_);
+ browser_ = browser;
+
+ if (hwnd_) {
+ // The native window will already exist for non-popup browsers.
+ EnsureRenderHandler();
+ render_handler_->SetBrowser(browser);
+ }
+
+ if (hwnd_) {
+ // Show the browser window. Called asynchronously so that the browser has
+ // time to create associated internal objects.
+ CefPostTask(TID_UI, base::BindOnce(&OsrWindowWin::Show, this));
+ }
+}
+
+void OsrWindowWin::OnBeforeClose(CefRefPtr<CefBrowser> browser) {
+ CEF_REQUIRE_UI_THREAD();
+ // Detach |this| from the ClientHandlerOsr.
+ static_cast<ClientHandlerOsr*>(browser_->GetHost()->GetClient().get())
+ ->DetachOsrDelegate();
+ browser_ = nullptr;
+ render_handler_->SetBrowser(nullptr);
+ Destroy();
+}
+
+bool OsrWindowWin::GetRootScreenRect(CefRefPtr<CefBrowser> browser,
+ CefRect& rect) {
+ CEF_REQUIRE_UI_THREAD();
+ return false;
+}
+
+void OsrWindowWin::GetViewRect(CefRefPtr<CefBrowser> browser, CefRect& rect) {
+ CEF_REQUIRE_UI_THREAD();
+ DCHECK_GT(device_scale_factor_, 0);
+
+ rect.x = rect.y = 0;
+ rect.width = DeviceToLogical(client_rect_.right - client_rect_.left,
+ device_scale_factor_);
+ if (rect.width == 0) {
+ rect.width = 1;
+ }
+ rect.height = DeviceToLogical(client_rect_.bottom - client_rect_.top,
+ device_scale_factor_);
+ if (rect.height == 0) {
+ rect.height = 1;
+ }
+}
+
+bool OsrWindowWin::GetScreenPoint(CefRefPtr<CefBrowser> browser,
+ int viewX,
+ int viewY,
+ int& screenX,
+ int& screenY) {
+ CEF_REQUIRE_UI_THREAD();
+ DCHECK_GT(device_scale_factor_, 0);
+
+ if (!::IsWindow(hwnd_)) {
+ return false;
+ }
+
+ // Convert from view DIP coordinates to screen device (pixel) coordinates.
+ POINT screen_pt = {LogicalToDevice(viewX, device_scale_factor_),
+ LogicalToDevice(viewY, device_scale_factor_)};
+ ClientToScreen(hwnd_, &screen_pt);
+ screenX = screen_pt.x;
+ screenY = screen_pt.y;
+ return true;
+}
+
+bool OsrWindowWin::GetScreenInfo(CefRefPtr<CefBrowser> browser,
+ CefScreenInfo& screen_info) {
+ CEF_REQUIRE_UI_THREAD();
+ DCHECK_GT(device_scale_factor_, 0);
+
+ if (!::IsWindow(hwnd_)) {
+ return false;
+ }
+
+ CefRect view_rect;
+ GetViewRect(browser, view_rect);
+
+ screen_info.device_scale_factor = device_scale_factor_;
+
+ // The screen info rectangles are used by the renderer to create and position
+ // popups. Keep popups inside the view rectangle.
+ screen_info.rect = view_rect;
+ screen_info.available_rect = view_rect;
+ return true;
+}
+
+void OsrWindowWin::OnPopupShow(CefRefPtr<CefBrowser> browser, bool show) {
+ render_handler_->OnPopupShow(browser, show);
+}
+
+void OsrWindowWin::OnPopupSize(CefRefPtr<CefBrowser> browser,
+ const CefRect& rect) {
+ render_handler_->OnPopupSize(browser,
+ LogicalToDevice(rect, device_scale_factor_));
+}
+
+void OsrWindowWin::OnPaint(CefRefPtr<CefBrowser> browser,
+ CefRenderHandler::PaintElementType type,
+ const CefRenderHandler::RectList& dirtyRects,
+ const void* buffer,
+ int width,
+ int height) {
+ EnsureRenderHandler();
+ render_handler_->OnPaint(browser, type, dirtyRects, buffer, width, height);
+}
+
+void OsrWindowWin::OnAcceleratedPaint(
+ CefRefPtr<CefBrowser> browser,
+ CefRenderHandler::PaintElementType type,
+ const CefRenderHandler::RectList& dirtyRects,
+ void* share_handle) {
+ EnsureRenderHandler();
+ render_handler_->OnAcceleratedPaint(browser, type, dirtyRects, share_handle);
+}
+
+void OsrWindowWin::OnCursorChange(CefRefPtr<CefBrowser> browser,
+ CefCursorHandle cursor,
+ cef_cursor_type_t type,
+ const CefCursorInfo& custom_cursor_info) {
+ CEF_REQUIRE_UI_THREAD();
+
+ if (!::IsWindow(hwnd_)) {
+ return;
+ }
+
+ // Change the window's cursor.
+ SetClassLongPtr(hwnd_, GCLP_HCURSOR,
+ static_cast<LONG>(reinterpret_cast<LONG_PTR>(cursor)));
+ SetCursor(cursor);
+}
+
+bool OsrWindowWin::StartDragging(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefDragData> drag_data,
+ CefRenderHandler::DragOperationsMask allowed_ops,
+ int x,
+ int y) {
+ CEF_REQUIRE_UI_THREAD();
+
+#if defined(CEF_USE_ATL)
+ if (!drop_target_) {
+ return false;
+ }
+
+ current_drag_op_ = DRAG_OPERATION_NONE;
+ CefBrowserHost::DragOperationsMask result =
+ drop_target_->StartDragging(browser, drag_data, allowed_ops, x, y);
+ current_drag_op_ = DRAG_OPERATION_NONE;
+ POINT pt = {};
+ GetCursorPos(&pt);
+ ScreenToClient(hwnd_, &pt);
+
+ browser->GetHost()->DragSourceEndedAt(
+ DeviceToLogical(pt.x, device_scale_factor_),
+ DeviceToLogical(pt.y, device_scale_factor_), result);
+ browser->GetHost()->DragSourceSystemDragEnded();
+ return true;
+#else
+ // Cancel the drag. The dragging implementation requires ATL support.
+ return false;
+#endif
+}
+
+void OsrWindowWin::UpdateDragCursor(CefRefPtr<CefBrowser> browser,
+ CefRenderHandler::DragOperation operation) {
+ CEF_REQUIRE_UI_THREAD();
+
+#if defined(CEF_USE_ATL)
+ current_drag_op_ = operation;
+#endif
+}
+
+void OsrWindowWin::OnImeCompositionRangeChanged(
+ CefRefPtr<CefBrowser> browser,
+ const CefRange& selection_range,
+ const CefRenderHandler::RectList& character_bounds) {
+ CEF_REQUIRE_UI_THREAD();
+
+ if (ime_handler_) {
+ // Convert from view coordinates to device coordinates.
+ CefRenderHandler::RectList device_bounds;
+ CefRenderHandler::RectList::const_iterator it = character_bounds.begin();
+ for (; it != character_bounds.end(); ++it) {
+ device_bounds.push_back(LogicalToDevice(*it, device_scale_factor_));
+ }
+
+ ime_handler_->ChangeCompositionRange(selection_range, device_bounds);
+ }
+}
+
+void OsrWindowWin::UpdateAccessibilityTree(CefRefPtr<CefValue> value) {
+ CEF_REQUIRE_UI_THREAD();
+
+#if defined(CEF_USE_ATL)
+ if (!accessibility_handler_) {
+ accessibility_handler_.reset(new OsrAccessibilityHelper(value, browser_));
+ } else {
+ accessibility_handler_->UpdateAccessibilityTree(value);
+ }
+
+ // Update |accessibility_root_| because UpdateAccessibilityTree may have
+ // cleared it.
+ OsrAXNode* root = accessibility_handler_->GetRootNode();
+ accessibility_root_ =
+ root ? root->GetNativeAccessibleObject(nullptr) : nullptr;
+#endif // defined(CEF_USE_ATL)
+}
+
+void OsrWindowWin::UpdateAccessibilityLocation(CefRefPtr<CefValue> value) {
+ CEF_REQUIRE_UI_THREAD();
+
+#if defined(CEF_USE_ATL)
+ if (accessibility_handler_) {
+ accessibility_handler_->UpdateAccessibilityLocation(value);
+ }
+#endif // defined(CEF_USE_ATL)
+}
+
+#if defined(CEF_USE_ATL)
+
+CefBrowserHost::DragOperationsMask OsrWindowWin::OnDragEnter(
+ CefRefPtr<CefDragData> drag_data,
+ CefMouseEvent ev,
+ CefBrowserHost::DragOperationsMask effect) {
+ if (browser_) {
+ DeviceToLogical(ev, device_scale_factor_);
+ browser_->GetHost()->DragTargetDragEnter(drag_data, ev, effect);
+ browser_->GetHost()->DragTargetDragOver(ev, effect);
+ }
+ return current_drag_op_;
+}
+
+CefBrowserHost::DragOperationsMask OsrWindowWin::OnDragOver(
+ CefMouseEvent ev,
+ CefBrowserHost::DragOperationsMask effect) {
+ if (browser_) {
+ DeviceToLogical(ev, device_scale_factor_);
+ browser_->GetHost()->DragTargetDragOver(ev, effect);
+ }
+ return current_drag_op_;
+}
+
+void OsrWindowWin::OnDragLeave() {
+ if (browser_) {
+ browser_->GetHost()->DragTargetDragLeave();
+ }
+}
+
+CefBrowserHost::DragOperationsMask OsrWindowWin::OnDrop(
+ CefMouseEvent ev,
+ CefBrowserHost::DragOperationsMask effect) {
+ if (browser_) {
+ DeviceToLogical(ev, device_scale_factor_);
+ browser_->GetHost()->DragTargetDragOver(ev, effect);
+ browser_->GetHost()->DragTargetDrop(ev);
+ }
+ return current_drag_op_;
+}
+
+#endif // defined(CEF_USE_ATL)
+
+void OsrWindowWin::EnsureRenderHandler() {
+ CEF_REQUIRE_UI_THREAD();
+ if (!render_handler_) {
+ if (settings_.shared_texture_enabled) {
+ // Try to initialize D3D11 rendering.
+ auto render_handler = new OsrRenderHandlerWinD3D11(settings_, hwnd_);
+ if (render_handler->Initialize(browser_,
+ client_rect_.right - client_rect_.left,
+ client_rect_.bottom - client_rect_.top)) {
+ render_handler_.reset(render_handler);
+ } else {
+ LOG(ERROR) << "Failed to initialize D3D11 rendering.";
+ delete render_handler;
+ }
+ }
+
+ // Fall back to GL rendering.
+ if (!render_handler_) {
+ auto render_handler = new OsrRenderHandlerWinGL(settings_, hwnd_);
+ render_handler->Initialize(browser_);
+ render_handler_.reset(render_handler);
+ }
+ }
+}
+
+} // namespace client
diff --git a/tests/cefclient/browser/osr_window_win.h b/tests/cefclient/browser/osr_window_win.h
new file mode 100644
index 00000000..fea8ec42
--- /dev/null
+++ b/tests/cefclient/browser/osr_window_win.h
@@ -0,0 +1,215 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_OSR_WINDOW_WIN_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_OSR_WINDOW_WIN_H_
+#pragma once
+
+#include "include/base/cef_callback.h"
+#include "include/base/cef_ref_counted.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "include/wrapper/cef_helpers.h"
+#include "tests/cefclient/browser/client_handler_osr.h"
+#include "tests/cefclient/browser/osr_accessibility_node.h"
+#include "tests/cefclient/browser/osr_dragdrop_win.h"
+#include "tests/cefclient/browser/osr_render_handler_win.h"
+#include "tests/cefclient/browser/osr_renderer_settings.h"
+
+namespace client {
+
+class OsrAccessibilityHelper;
+class OsrImeHandlerWin;
+
+// Represents the native parent window for an off-screen browser. This object
+// must live on the CEF UI thread in order to handle CefRenderHandler callbacks.
+// The methods of this class are thread-safe unless otherwise indicated.
+class OsrWindowWin
+ : public base::RefCountedThreadSafe<OsrWindowWin, CefDeleteOnUIThread>,
+ public ClientHandlerOsr::OsrDelegate
+#if defined(CEF_USE_ATL)
+ ,
+ public OsrDragEvents
+#endif
+{
+ public:
+ // This interface is implemented by the owner of the OsrWindowWin. The
+ // methods of this class will be called on the main thread.
+ class Delegate {
+ public:
+ // Called after the native window has been created.
+ virtual void OnOsrNativeWindowCreated(HWND hwnd) = 0;
+
+ protected:
+ virtual ~Delegate() {}
+ };
+
+ // |delegate| must outlive this object.
+ OsrWindowWin(Delegate* delegate, const OsrRendererSettings& settings);
+
+ // Create a new browser and native window.
+ void CreateBrowser(HWND parent_hwnd,
+ const RECT& rect,
+ CefRefPtr<CefClient> handler,
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefDictionaryValue> extra_info,
+ CefRefPtr<CefRequestContext> request_context,
+ const std::string& startup_url);
+
+ // Show the popup window with correct parent and bounds in parent coordinates.
+ void ShowPopup(HWND parent_hwnd, int x, int y, size_t width, size_t height);
+
+ void Show();
+ void Hide();
+ void SetBounds(int x, int y, size_t width, size_t height);
+ void SetFocus();
+ void SetDeviceScaleFactor(float device_scale_factor);
+
+ const OsrRendererSettings& settings() const { return settings_; }
+
+ private:
+ // Only allow deletion via scoped_refptr.
+ friend struct CefDeleteOnThread<TID_UI>;
+ friend class base::RefCountedThreadSafe<OsrWindowWin, CefDeleteOnUIThread>;
+
+ ~OsrWindowWin();
+
+ // Manage native window lifespan.
+ void Create(HWND parent_hwnd, const RECT& rect);
+ void Destroy();
+
+ void NotifyNativeWindowCreated(HWND hwnd);
+
+ static void RegisterOsrClass(HINSTANCE hInstance, HBRUSH background_brush);
+ static LRESULT CALLBACK OsrWndProc(HWND hWnd,
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam);
+
+ // WndProc message handlers.
+ void OnMouseEvent(UINT message, WPARAM wParam, LPARAM lParam);
+ void OnSize();
+ void OnFocus(bool setFocus);
+ void OnCaptureLost();
+ void OnKeyEvent(UINT message, WPARAM wParam, LPARAM lParam);
+ void OnPaint();
+ bool OnEraseBkgnd();
+ bool OnTouchEvent(UINT message, WPARAM wParam, LPARAM lParam);
+
+ void OnIMESetContext(UINT message, WPARAM wParam, LPARAM lParam);
+ void OnIMEStartComposition();
+ void OnIMEComposition(UINT message, WPARAM wParam, LPARAM lParam);
+ void OnIMECancelCompositionEvent();
+
+ // Manage popup bounds.
+ bool IsOverPopupWidget(int x, int y) const;
+ int GetPopupXOffset() const;
+ int GetPopupYOffset() const;
+ void ApplyPopupOffset(int& x, int& y) const;
+
+ // ClientHandlerOsr::OsrDelegate methods.
+ void OnAfterCreated(CefRefPtr<CefBrowser> browser) override;
+ void OnBeforeClose(CefRefPtr<CefBrowser> browser) override;
+ bool GetRootScreenRect(CefRefPtr<CefBrowser> browser, CefRect& rect) override;
+ void GetViewRect(CefRefPtr<CefBrowser> browser, CefRect& rect) override;
+ bool GetScreenPoint(CefRefPtr<CefBrowser> browser,
+ int viewX,
+ int viewY,
+ int& screenX,
+ int& screenY) override;
+ bool GetScreenInfo(CefRefPtr<CefBrowser> browser,
+ CefScreenInfo& screen_info) override;
+ void OnPopupShow(CefRefPtr<CefBrowser> browser, bool show) override;
+ void OnPopupSize(CefRefPtr<CefBrowser> browser, const CefRect& rect) override;
+ void OnPaint(CefRefPtr<CefBrowser> browser,
+ CefRenderHandler::PaintElementType type,
+ const CefRenderHandler::RectList& dirtyRects,
+ const void* buffer,
+ int width,
+ int height) override;
+ void OnAcceleratedPaint(CefRefPtr<CefBrowser> browser,
+ CefRenderHandler::PaintElementType type,
+ const CefRenderHandler::RectList& dirtyRects,
+ void* share_handle) override;
+ void OnCursorChange(CefRefPtr<CefBrowser> browser,
+ CefCursorHandle cursor,
+ cef_cursor_type_t type,
+ const CefCursorInfo& custom_cursor_info) override;
+ bool StartDragging(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefDragData> drag_data,
+ CefRenderHandler::DragOperationsMask allowed_ops,
+ int x,
+ int y) override;
+ void UpdateDragCursor(CefRefPtr<CefBrowser> browser,
+ CefRenderHandler::DragOperation operation) override;
+ void OnImeCompositionRangeChanged(
+ CefRefPtr<CefBrowser> browser,
+ const CefRange& selection_range,
+ const CefRenderHandler::RectList& character_bounds) override;
+
+ void UpdateAccessibilityTree(CefRefPtr<CefValue> value) override;
+
+ void UpdateAccessibilityLocation(CefRefPtr<CefValue> value) override;
+
+#if defined(CEF_USE_ATL)
+ // OsrDragEvents methods.
+ CefBrowserHost::DragOperationsMask OnDragEnter(
+ CefRefPtr<CefDragData> drag_data,
+ CefMouseEvent ev,
+ CefBrowserHost::DragOperationsMask effect) override;
+ CefBrowserHost::DragOperationsMask OnDragOver(
+ CefMouseEvent ev,
+ CefBrowserHost::DragOperationsMask effect) override;
+ void OnDragLeave() override;
+ CefBrowserHost::DragOperationsMask OnDrop(
+ CefMouseEvent ev,
+ CefBrowserHost::DragOperationsMask effect) override;
+#endif // defined(CEF_USE_ATL)
+
+ void EnsureRenderHandler();
+
+ // Only accessed on the main thread.
+ Delegate* delegate_;
+
+ const OsrRendererSettings settings_;
+ HWND hwnd_;
+ std::unique_ptr<OsrRenderHandlerWin> render_handler_;
+
+ // Class that encapsulates IMM32 APIs and controls IMEs attached to a window.
+ std::unique_ptr<OsrImeHandlerWin> ime_handler_;
+
+ RECT client_rect_;
+ float device_scale_factor_;
+
+ CefRefPtr<CefBrowser> browser_;
+
+#if defined(CEF_USE_ATL)
+ CComPtr<DropTargetWin> drop_target_;
+ CefRenderHandler::DragOperation current_drag_op_;
+
+ // Class that abstracts the accessibility information received from the
+ // renderer.
+ std::unique_ptr<OsrAccessibilityHelper> accessibility_handler_;
+ IAccessible* accessibility_root_;
+#endif
+
+ bool hidden_;
+
+ // Mouse state tracking.
+ POINT last_mouse_pos_;
+ POINT current_mouse_pos_;
+ bool mouse_rotation_;
+ bool mouse_tracking_;
+ int last_click_x_;
+ int last_click_y_;
+ CefBrowserHost::MouseButtonType last_click_button_;
+ int last_click_count_;
+ double last_click_time_;
+ bool last_mouse_down_on_view_;
+
+ DISALLOW_COPY_AND_ASSIGN(OsrWindowWin);
+};
+
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_OSR_WINDOW_WIN_H_
diff --git a/tests/cefclient/browser/preferences_test.cc b/tests/cefclient/browser/preferences_test.cc
new file mode 100644
index 00000000..496e3ef9
--- /dev/null
+++ b/tests/cefclient/browser/preferences_test.cc
@@ -0,0 +1,346 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/preferences_test.h"
+
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include "include/base/cef_logging.h"
+#include "include/cef_command_line.h"
+#include "include/cef_parser.h"
+#include "tests/cefclient/browser/test_runner.h"
+
+namespace client {
+namespace preferences_test {
+
+namespace {
+
+const char kTestUrlPath[] = "/preferences";
+
+// Application-specific error codes.
+const int kMessageFormatError = 1;
+const int kPreferenceApplicationError = 1;
+
+// Common to all messages.
+const char kNameKey[] = "name";
+const char kNameValueGet[] = "preferences_get";
+const char kNameValueSet[] = "preferences_set";
+const char kNameValueState[] = "preferences_state";
+
+// Used with "preferences_get" messages.
+const char kIncludeDefaultsKey[] = "include_defaults";
+
+// Used with "preferences_set" messages.
+const char kPreferencesKey[] = "preferences";
+
+// Handle messages in the browser process. Only accessed on the UI thread.
+class Handler : public CefMessageRouterBrowserSide::Handler {
+ public:
+ typedef std::vector<std::string> NameVector;
+
+ Handler() { CEF_REQUIRE_UI_THREAD(); }
+
+ // Called due to cefQuery execution in preferences.html.
+ bool OnQuery(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int64 query_id,
+ const CefString& request,
+ bool persistent,
+ CefRefPtr<Callback> callback) override {
+ CEF_REQUIRE_UI_THREAD();
+
+ // Only handle messages from the test URL.
+ const std::string& url = frame->GetURL();
+ if (!test_runner::IsTestURL(url, kTestUrlPath)) {
+ return false;
+ }
+
+ // Parse |request| as a JSON dictionary.
+ CefRefPtr<CefDictionaryValue> request_dict = ParseJSON(request);
+ if (!request_dict) {
+ callback->Failure(kMessageFormatError, "Incorrect message format");
+ return true;
+ }
+
+ // Verify the "name" key.
+ if (!VerifyKey(request_dict, kNameKey, VTYPE_STRING, callback)) {
+ return true;
+ }
+
+ const std::string& message_name = request_dict->GetString(kNameKey);
+ if (message_name == kNameValueGet) {
+ // JavaScript is requesting a JSON representation of the preferences tree.
+
+ // Verify the "include_defaults" key.
+ if (!VerifyKey(request_dict, kIncludeDefaultsKey, VTYPE_BOOL, callback)) {
+ return true;
+ }
+
+ const bool include_defaults = request_dict->GetBool(kIncludeDefaultsKey);
+
+ OnPreferencesGet(browser, include_defaults, callback);
+
+ return true;
+ } else if (message_name == kNameValueSet) {
+ // JavaScript is requesting that preferences be updated to match the
+ // specified JSON representation.
+
+ // Verify the "preferences" key.
+ if (!VerifyKey(request_dict, kPreferencesKey, VTYPE_DICTIONARY,
+ callback)) {
+ return true;
+ }
+
+ CefRefPtr<CefDictionaryValue> preferences =
+ request_dict->GetDictionary(kPreferencesKey);
+
+ OnPreferencesSet(browser, preferences, callback);
+
+ return true;
+ } else if (message_name == kNameValueState) {
+ // JavaScript is requesting global state information.
+
+ OnPreferencesState(browser, callback);
+
+ return true;
+ }
+
+ return false;
+ }
+
+ private:
+ // Execute |callback| with the preferences dictionary as a JSON string.
+ static void OnPreferencesGet(CefRefPtr<CefBrowser> browser,
+ bool include_defaults,
+ CefRefPtr<Callback> callback) {
+ CefRefPtr<CefRequestContext> context =
+ browser->GetHost()->GetRequestContext();
+
+ // Retrieve all preference values.
+ CefRefPtr<CefDictionaryValue> prefs =
+ context->GetAllPreferences(include_defaults);
+
+ // Serialize the preferences to JSON and return to the JavaScript caller.
+ callback->Success(GetJSON(prefs));
+ }
+
+ // Set preferences based on the contents of |preferences|. Execute |callback|
+ // with a descriptive result message.
+ static void OnPreferencesSet(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefDictionaryValue> preferences,
+ CefRefPtr<Callback> callback) {
+ CefRefPtr<CefRequestContext> context =
+ browser->GetHost()->GetRequestContext();
+
+ CefRefPtr<CefValue> value = CefValue::Create();
+ value->SetDictionary(preferences);
+
+ std::string error;
+ NameVector changed_names;
+
+ // Apply preferences. This may result in errors.
+ const bool success =
+ ApplyPrefs(context, std::string(), value, error, changed_names);
+
+ // Create a message that accurately represents the result.
+ std::string message;
+ if (!changed_names.empty()) {
+ std::stringstream ss;
+ ss << "Successfully changed " << changed_names.size() << " preferences; ";
+ for (size_t i = 0; i < changed_names.size(); ++i) {
+ ss << changed_names[i];
+ if (i < changed_names.size() - 1) {
+ ss << ", ";
+ }
+ }
+ message = ss.str();
+ }
+
+ if (!success) {
+ DCHECK(!error.empty());
+ if (!message.empty()) {
+ message += "\n";
+ }
+ message += error;
+ }
+
+ if (changed_names.empty()) {
+ if (!message.empty()) {
+ message += "\n";
+ }
+ message += "No preferences changed.";
+ }
+
+ // Return the message to the JavaScript caller.
+ if (success) {
+ callback->Success(message);
+ } else {
+ callback->Failure(kPreferenceApplicationError, message);
+ }
+ }
+
+ // Execute |callback| with the global state dictionary as a JSON string.
+ static void OnPreferencesState(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<Callback> callback) {
+ CefRefPtr<CefCommandLine> command_line =
+ CefCommandLine::GetGlobalCommandLine();
+
+ CefRefPtr<CefDictionaryValue> dict = CefDictionaryValue::Create();
+
+ // If spell checking is disabled via the command-line then it cannot be
+ // enabled via preferences.
+ dict->SetBool("spellcheck_disabled",
+ command_line->HasSwitch("disable-spell-checking"));
+
+ // If proxy settings are configured via the command-line then they cannot
+ // be modified via preferences.
+ dict->SetBool("proxy_configured",
+ command_line->HasSwitch("no-proxy-server") ||
+ command_line->HasSwitch("proxy-auto-detect") ||
+ command_line->HasSwitch("proxy-pac-url") ||
+ command_line->HasSwitch("proxy-server"));
+
+ // If allow running insecure content is enabled via the command-line then it
+ // cannot be enabled via preferences.
+ dict->SetBool("allow_running_insecure_content",
+ command_line->HasSwitch("allow-running-insecure-content"));
+
+ // Serialize the state to JSON and return to the JavaScript caller.
+ callback->Success(GetJSON(dict));
+ }
+
+ // Convert a JSON string to a dictionary value.
+ static CefRefPtr<CefDictionaryValue> ParseJSON(const CefString& string) {
+ CefRefPtr<CefValue> value = CefParseJSON(string, JSON_PARSER_RFC);
+ if (value.get() && value->GetType() == VTYPE_DICTIONARY) {
+ return value->GetDictionary();
+ }
+ return nullptr;
+ }
+
+ // Convert a dictionary value to a JSON string.
+ static CefString GetJSON(CefRefPtr<CefDictionaryValue> dictionary) {
+ CefRefPtr<CefValue> value = CefValue::Create();
+ value->SetDictionary(dictionary);
+ return CefWriteJSON(value, JSON_WRITER_DEFAULT);
+ }
+
+ // Verify that |key| exists in |dictionary| and has type |value_type|. Fails
+ // |callback| and returns false on failure.
+ static bool VerifyKey(CefRefPtr<CefDictionaryValue> dictionary,
+ const char* key,
+ cef_value_type_t value_type,
+ CefRefPtr<Callback> callback) {
+ if (!dictionary->HasKey(key) || dictionary->GetType(key) != value_type) {
+ callback->Failure(
+ kMessageFormatError,
+ "Missing or incorrectly formatted message key: " + std::string(key));
+ return false;
+ }
+ return true;
+ }
+
+ // Apply preferences. Returns true on success. Returns false and sets |error|
+ // to a descriptive error string on failure. |changed_names| is the list of
+ // preferences that were successfully changed.
+ static bool ApplyPrefs(CefRefPtr<CefRequestContext> context,
+ const std::string& name,
+ CefRefPtr<CefValue> value,
+ std::string& error,
+ NameVector& changed_names) {
+ if (!name.empty() && context->HasPreference(name)) {
+ // The preference exists. Set the value.
+ return SetPref(context, name, value, error, changed_names);
+ }
+
+ if (value->GetType() == VTYPE_DICTIONARY) {
+ // A dictionary type value that is not an existing preference. Try to set
+ // each of the elements individually.
+ CefRefPtr<CefDictionaryValue> dict = value->GetDictionary();
+
+ CefDictionaryValue::KeyList keys;
+ dict->GetKeys(keys);
+ for (size_t i = 0; i < keys.size(); ++i) {
+ const std::string& key = keys[i];
+ const std::string& current_name = name.empty() ? key : name + "." + key;
+ if (!ApplyPrefs(context, current_name, dict->GetValue(key), error,
+ changed_names)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ error = "Trying to create an unregistered preference: " + name;
+ return false;
+ }
+
+ // Set a specific preference value. Returns true if the value is set
+ // successfully or has not changed. If the value has changed then |name| will
+ // be added to |changed_names|. Returns false and sets |error| to a
+ // descriptive error string on failure.
+ static bool SetPref(CefRefPtr<CefRequestContext> context,
+ const std::string& name,
+ CefRefPtr<CefValue> value,
+ std::string& error,
+ NameVector& changed_names) {
+ CefRefPtr<CefValue> existing_value = context->GetPreference(name);
+ DCHECK(existing_value);
+
+ if (value->GetType() == VTYPE_STRING &&
+ existing_value->GetType() != VTYPE_STRING) {
+ // Since |value| is coming from JSON all basic types will be represented
+ // as strings. Convert to the expected data type.
+ const std::string& string_val = value->GetString();
+ switch (existing_value->GetType()) {
+ case VTYPE_BOOL:
+ if (string_val == "true" || string_val == "1") {
+ value->SetBool(true);
+ } else if (string_val == "false" || string_val == "0") {
+ value->SetBool(false);
+ }
+ break;
+ case VTYPE_INT:
+ value->SetInt(atoi(string_val.c_str()));
+ break;
+ case VTYPE_DOUBLE:
+ value->SetInt(atof(string_val.c_str()));
+ break;
+ default:
+ // Other types cannot be converted.
+ break;
+ }
+ }
+
+ // Nothing to do if the value hasn't changed.
+ if (existing_value->IsEqual(value)) {
+ return true;
+ }
+
+ // Attempt to set the preference.
+ CefString error_str;
+ if (!context->SetPreference(name, value, error_str)) {
+ error = error_str.ToString() + ": " + name;
+ return false;
+ }
+
+ // The preference was set successfully.
+ changed_names.push_back(name);
+ return true;
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(Handler);
+};
+
+} // namespace
+
+void CreateMessageHandlers(test_runner::MessageHandlerSet& handlers) {
+ handlers.insert(new Handler());
+}
+
+} // namespace preferences_test
+} // namespace client
diff --git a/tests/cefclient/browser/preferences_test.h b/tests/cefclient/browser/preferences_test.h
new file mode 100644
index 00000000..b11d89d2
--- /dev/null
+++ b/tests/cefclient/browser/preferences_test.h
@@ -0,0 +1,20 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_PREFERENCES_TEST_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_PREFERENCES_TEST_H_
+#pragma once
+
+#include "tests/cefclient/browser/test_runner.h"
+
+namespace client {
+namespace preferences_test {
+
+// Create message handlers. Called from test_runner.cc.
+void CreateMessageHandlers(test_runner::MessageHandlerSet& handlers);
+
+} // namespace preferences_test
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_PREFERENCES_TEST_H_
diff --git a/tests/cefclient/browser/print_handler_gtk.cc b/tests/cefclient/browser/print_handler_gtk.cc
new file mode 100644
index 00000000..bd924c97
--- /dev/null
+++ b/tests/cefclient/browser/print_handler_gtk.cc
@@ -0,0 +1,649 @@
+// Copyright (c) 2014 The Chromium Embedded Framework Authors.
+// Portions Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "tests/cefclient/browser/print_handler_gtk.h"
+
+#include <memory>
+#include <vector>
+
+#include <gtk/gtk.h>
+#include <gtk/gtkunixprint.h>
+
+#include "include/base/cef_callback.h"
+#include "include/base/cef_logging.h"
+#include "include/base/cef_macros.h"
+#include "include/wrapper/cef_helpers.h"
+
+#include "tests/cefclient/browser/root_window.h"
+#include "tests/cefclient/browser/util_gtk.h"
+
+namespace client {
+
+namespace {
+
+// CUPS Duplex attribute and values.
+const char kCUPSDuplex[] = "cups-Duplex";
+const char kDuplexNone[] = "None";
+const char kDuplexTumble[] = "DuplexTumble";
+const char kDuplexNoTumble[] = "DuplexNoTumble";
+
+// CUPS color mode attribute and values.
+const char kCUPSColorMode[] = "cups-ColorMode";
+const char kCUPSColorModel[] = "cups-ColorModel";
+const char kCUPSPrintoutMode[] = "cups-PrintoutMode";
+const char kCUPSProcessColorModel[] = "cups-ProcessColorModel";
+const char kBlack[] = "Black";
+const char kCMYK[] = "CMYK";
+const char kCMY_K[] = "CMY+K";
+const char kCMY[] = "CMY";
+const char kColor[] = "Color";
+const char kGray[] = "Gray";
+const char kGrayscale[] = "Grayscale";
+const char kGreyscale[] = "Greyscale";
+const char kMonochrome[] = "Monochrome";
+const char kNormal[] = "Normal";
+const char kNormalGray[] = "Normal.Gray";
+const char kRGB[] = "RGB";
+const char kRGBA[] = "RGBA";
+const char kRGB16[] = "RGB16";
+
+// Default margin settings.
+const double kTopMarginInInch = 0.25;
+const double kBottomMarginInInch = 0.56;
+const double kLeftMarginInInch = 0.25;
+const double kRightMarginInInch = 0.25;
+
+// Length of an inch in CSS's 1px unit.
+// http://dev.w3.org/csswg/css3-values/#the-px-unit
+const int kPixelsPerInch = 96;
+
+// LETTER: 8.5 x 11 inches
+const float kLetterWidthInch = 8.5f;
+const float kLetterHeightInch = 11.0f;
+
+class StickyPrintSettingGtk {
+ public:
+ StickyPrintSettingGtk() : last_used_settings_(gtk_print_settings_new()) {}
+ ~StickyPrintSettingGtk() {
+ NOTREACHED(); // The instance is intentionally leaked.
+ }
+
+ GtkPrintSettings* settings() { return last_used_settings_; }
+
+ void SetLastUsedSettings(GtkPrintSettings* settings) {
+ DCHECK(last_used_settings_);
+ g_object_unref(last_used_settings_);
+ last_used_settings_ = gtk_print_settings_copy(settings);
+ }
+
+ private:
+ GtkPrintSettings* last_used_settings_;
+
+ DISALLOW_COPY_AND_ASSIGN(StickyPrintSettingGtk);
+};
+
+// Lazily initialize the singleton instance.
+StickyPrintSettingGtk* GetLastUsedSettings() {
+ static StickyPrintSettingGtk* settings = nullptr;
+ if (!settings) {
+ settings = new StickyPrintSettingGtk();
+ }
+ return settings;
+}
+
+// Helper class to track GTK printers.
+class GtkPrinterList {
+ public:
+ GtkPrinterList() : default_printer_(nullptr) {
+ gtk_enumerate_printers(SetPrinter, this, nullptr, TRUE);
+ }
+
+ ~GtkPrinterList() {
+ for (std::vector<GtkPrinter*>::iterator it = printers_.begin();
+ it < printers_.end(); ++it) {
+ g_object_unref(*it);
+ }
+ }
+
+ // Can return nullptr if there's no default printer. E.g. Printer on a laptop
+ // is "home_printer", but the laptop is at work.
+ GtkPrinter* default_printer() { return default_printer_; }
+
+ // Can return nullptr if the printer cannot be found due to:
+ // - Printer list out of sync with printer dialog UI.
+ // - Querying for non-existant printers like 'Print to PDF'.
+ GtkPrinter* GetPrinterWithName(const std::string& name) {
+ if (name.empty()) {
+ return nullptr;
+ }
+
+ for (std::vector<GtkPrinter*>::iterator it = printers_.begin();
+ it < printers_.end(); ++it) {
+ if (gtk_printer_get_name(*it) == name) {
+ return *it;
+ }
+ }
+
+ return nullptr;
+ }
+
+ private:
+ // Callback function used by gtk_enumerate_printers() to get all printer.
+ static gboolean SetPrinter(GtkPrinter* printer, gpointer data) {
+ GtkPrinterList* printer_list = reinterpret_cast<GtkPrinterList*>(data);
+ if (gtk_printer_is_default(printer)) {
+ printer_list->default_printer_ = printer;
+ }
+
+ g_object_ref(printer);
+ printer_list->printers_.push_back(printer);
+
+ return FALSE;
+ }
+
+ std::vector<GtkPrinter*> printers_;
+ GtkPrinter* default_printer_;
+};
+
+void GetColorModelForMode(CefPrintSettings::ColorModel color_mode,
+ std::string* color_setting_name,
+ std::string* color_value) {
+ color_setting_name->assign(kCUPSColorModel);
+ switch (color_mode) {
+ case COLOR_MODEL_COLOR:
+ color_value->assign(kColor);
+ break;
+ case COLOR_MODEL_CMYK:
+ color_value->assign(kCMYK);
+ break;
+ case COLOR_MODEL_PRINTOUTMODE_NORMAL:
+ color_value->assign(kNormal);
+ color_setting_name->assign(kCUPSPrintoutMode);
+ break;
+ case COLOR_MODEL_PRINTOUTMODE_NORMAL_GRAY:
+ color_value->assign(kNormalGray);
+ color_setting_name->assign(kCUPSPrintoutMode);
+ break;
+ case COLOR_MODEL_RGB16:
+ color_value->assign(kRGB16);
+ break;
+ case COLOR_MODEL_RGBA:
+ color_value->assign(kRGBA);
+ break;
+ case COLOR_MODEL_RGB:
+ color_value->assign(kRGB);
+ break;
+ case COLOR_MODEL_CMY:
+ color_value->assign(kCMY);
+ break;
+ case COLOR_MODEL_CMY_K:
+ color_value->assign(kCMY_K);
+ break;
+ case COLOR_MODEL_BLACK:
+ color_value->assign(kBlack);
+ break;
+ case COLOR_MODEL_GRAY:
+ color_value->assign(kGray);
+ break;
+ case COLOR_MODEL_COLORMODE_COLOR:
+ color_setting_name->assign(kCUPSColorMode);
+ color_value->assign(kColor);
+ break;
+ case COLOR_MODEL_COLORMODE_MONOCHROME:
+ color_setting_name->assign(kCUPSColorMode);
+ color_value->assign(kMonochrome);
+ break;
+ case COLOR_MODEL_HP_COLOR_COLOR:
+ color_setting_name->assign(kColor);
+ color_value->assign(kColor);
+ break;
+ case COLOR_MODEL_HP_COLOR_BLACK:
+ color_setting_name->assign(kColor);
+ color_value->assign(kBlack);
+ break;
+ case COLOR_MODEL_PROCESSCOLORMODEL_CMYK:
+ color_setting_name->assign(kCUPSProcessColorModel);
+ color_value->assign(kCMYK);
+ break;
+ case COLOR_MODEL_PROCESSCOLORMODEL_GREYSCALE:
+ color_setting_name->assign(kCUPSProcessColorModel);
+ color_value->assign(kGreyscale);
+ break;
+ case COLOR_MODEL_PROCESSCOLORMODEL_RGB:
+ color_setting_name->assign(kCUPSProcessColorModel);
+ color_value->assign(kRGB);
+ break;
+ default:
+ color_value->assign(kGrayscale);
+ break;
+ }
+}
+
+void InitPrintSettings(GtkPrintSettings* settings,
+ GtkPageSetup* page_setup,
+ CefRefPtr<CefPrintSettings> print_settings) {
+ DCHECK(settings);
+ DCHECK(page_setup);
+
+ std::string device_name;
+ const gchar* name = gtk_print_settings_get_printer(settings);
+ if (name) {
+ device_name = name;
+ }
+ print_settings->SetDeviceName(device_name);
+
+ CefSize physical_size_device_units;
+ CefRect printable_area_device_units;
+ int dpi = gtk_print_settings_get_resolution(settings);
+ if (dpi) {
+ // Initialize page_setup_device_units_.
+ physical_size_device_units.Set(
+ gtk_page_setup_get_paper_width(page_setup, GTK_UNIT_INCH) * dpi,
+ gtk_page_setup_get_paper_height(page_setup, GTK_UNIT_INCH) * dpi);
+ printable_area_device_units.Set(
+ gtk_page_setup_get_left_margin(page_setup, GTK_UNIT_INCH) * dpi,
+ gtk_page_setup_get_top_margin(page_setup, GTK_UNIT_INCH) * dpi,
+ gtk_page_setup_get_page_width(page_setup, GTK_UNIT_INCH) * dpi,
+ gtk_page_setup_get_page_height(page_setup, GTK_UNIT_INCH) * dpi);
+ } else {
+ // Use default values if we cannot get valid values from the print dialog.
+ dpi = kPixelsPerInch;
+ double page_width_in_pixel = kLetterWidthInch * dpi;
+ double page_height_in_pixel = kLetterHeightInch * dpi;
+ physical_size_device_units.Set(static_cast<int>(page_width_in_pixel),
+ static_cast<int>(page_height_in_pixel));
+ printable_area_device_units.Set(
+ static_cast<int>(kLeftMarginInInch * dpi),
+ static_cast<int>(kTopMarginInInch * dpi),
+ page_width_in_pixel - (kLeftMarginInInch + kRightMarginInInch) * dpi,
+ page_height_in_pixel - (kTopMarginInInch + kBottomMarginInInch) * dpi);
+ }
+
+ print_settings->SetDPI(dpi);
+
+ // Note: With the normal GTK print dialog, when the user selects the landscape
+ // orientation, all that does is change the paper size. Which seems to be
+ // enough to render the right output and send it to the printer.
+ // The orientation value stays as portrait and does not actually affect
+ // printing.
+ // Thus this is only useful in print preview mode, where we manually set the
+ // orientation and change the paper size ourselves.
+ GtkPageOrientation orientation = gtk_print_settings_get_orientation(settings);
+ // Set before SetPrinterPrintableArea to make it flip area if necessary.
+ print_settings->SetOrientation(orientation == GTK_PAGE_ORIENTATION_LANDSCAPE);
+ print_settings->SetPrinterPrintableArea(physical_size_device_units,
+ printable_area_device_units, true);
+}
+
+// Returns the GtkWindow* for the browser. Will return nullptr when using the
+// Views framework.
+GtkWindow* GetWindow(CefRefPtr<CefBrowser> browser) {
+ scoped_refptr<RootWindow> root_window =
+ RootWindow::GetForBrowser(browser->GetIdentifier());
+ if (root_window) {
+ return GTK_WINDOW(root_window->GetWindowHandle());
+ }
+ return nullptr;
+}
+
+void GetWindowAndContinue(CefRefPtr<CefBrowser> browser,
+ base::OnceCallback<void(GtkWindow*)> callback) {
+ if (!CURRENTLY_ON_MAIN_THREAD()) {
+ MAIN_POST_CLOSURE(
+ base::BindOnce(GetWindowAndContinue, browser, std::move(callback)));
+ return;
+ }
+
+ GtkWindow* window = GetWindow(browser);
+ if (window) {
+ CefPostTask(TID_UI, base::BindOnce(std::move(callback), window));
+ }
+}
+
+} // namespace
+
+struct ClientPrintHandlerGtk::PrintHandler {
+ PrintHandler(CefRefPtr<CefBrowser> browser)
+ : browser_(browser),
+ dialog_(nullptr),
+ gtk_settings_(nullptr),
+ page_setup_(nullptr),
+ printer_(nullptr) {}
+
+ ~PrintHandler() {
+ ScopedGdkThreadsEnter scoped_gdk_threads;
+
+ if (dialog_) {
+ gtk_widget_destroy(dialog_);
+ dialog_ = nullptr;
+ }
+ if (gtk_settings_) {
+ g_object_unref(gtk_settings_);
+ gtk_settings_ = nullptr;
+ }
+ if (page_setup_) {
+ g_object_unref(page_setup_);
+ page_setup_ = nullptr;
+ }
+ if (printer_) {
+ g_object_unref(printer_);
+ printer_ = nullptr;
+ }
+ }
+
+ void OnPrintSettings(CefRefPtr<CefPrintSettings> settings,
+ bool get_defaults) {
+ ScopedGdkThreadsEnter scoped_gdk_threads;
+
+ if (get_defaults) {
+ DCHECK(!page_setup_);
+ DCHECK(!printer_);
+
+ // |gtk_settings_| is a new copy.
+ gtk_settings_ =
+ gtk_print_settings_copy(GetLastUsedSettings()->settings());
+ page_setup_ = gtk_page_setup_new();
+ } else {
+ if (!gtk_settings_) {
+ gtk_settings_ =
+ gtk_print_settings_copy(GetLastUsedSettings()->settings());
+ }
+
+ GtkPrinterList* printer_list = new GtkPrinterList;
+ printer_ = printer_list->GetPrinterWithName(settings->GetDeviceName());
+ if (printer_) {
+ g_object_ref(printer_);
+ gtk_print_settings_set_printer(gtk_settings_,
+ gtk_printer_get_name(printer_));
+ if (!page_setup_) {
+ page_setup_ = gtk_printer_get_default_page_size(printer_);
+ }
+ }
+
+ gtk_print_settings_set_n_copies(gtk_settings_, settings->GetCopies());
+ gtk_print_settings_set_collate(gtk_settings_, settings->WillCollate());
+
+ std::string color_value;
+ std::string color_setting_name;
+ GetColorModelForMode(settings->GetColorModel(), &color_setting_name,
+ &color_value);
+ gtk_print_settings_set(gtk_settings_, color_setting_name.c_str(),
+ color_value.c_str());
+
+ if (settings->GetDuplexMode() != DUPLEX_MODE_UNKNOWN) {
+ const char* cups_duplex_mode = nullptr;
+ switch (settings->GetDuplexMode()) {
+ case DUPLEX_MODE_LONG_EDGE:
+ cups_duplex_mode = kDuplexNoTumble;
+ break;
+ case DUPLEX_MODE_SHORT_EDGE:
+ cups_duplex_mode = kDuplexTumble;
+ break;
+ case DUPLEX_MODE_SIMPLEX:
+ cups_duplex_mode = kDuplexNone;
+ break;
+ default: // UNKNOWN_DUPLEX_MODE
+ NOTREACHED();
+ break;
+ }
+ gtk_print_settings_set(gtk_settings_, kCUPSDuplex, cups_duplex_mode);
+ }
+
+ if (!page_setup_) {
+ page_setup_ = gtk_page_setup_new();
+ }
+
+ gtk_print_settings_set_orientation(gtk_settings_,
+ settings->IsLandscape()
+ ? GTK_PAGE_ORIENTATION_LANDSCAPE
+ : GTK_PAGE_ORIENTATION_PORTRAIT);
+
+ delete printer_list;
+ }
+
+ InitPrintSettings(gtk_settings_, page_setup_, settings);
+ }
+
+ void OnPrintDialog(bool has_selection,
+ CefRefPtr<CefPrintDialogCallback> callback,
+ GtkWindow* parent) {
+ dialog_callback_ = callback;
+
+ ScopedGdkThreadsEnter scoped_gdk_threads;
+
+ // TODO(estade): We need a window title here.
+ dialog_ = gtk_print_unix_dialog_new(nullptr, parent);
+ g_signal_connect(dialog_, "delete-event",
+ G_CALLBACK(gtk_widget_hide_on_delete), nullptr);
+
+ // Set modal so user cannot focus the same tab and press print again.
+ gtk_window_set_modal(GTK_WINDOW(dialog_), TRUE);
+
+ // Since we only generate PDF, only show printers that support PDF.
+ // TODO(thestig) Add more capabilities to support?
+ GtkPrintCapabilities cap = static_cast<GtkPrintCapabilities>(
+ GTK_PRINT_CAPABILITY_GENERATE_PDF | GTK_PRINT_CAPABILITY_PAGE_SET |
+ GTK_PRINT_CAPABILITY_COPIES | GTK_PRINT_CAPABILITY_COLLATE |
+ GTK_PRINT_CAPABILITY_REVERSE);
+ gtk_print_unix_dialog_set_manual_capabilities(
+ GTK_PRINT_UNIX_DIALOG(dialog_), cap);
+ gtk_print_unix_dialog_set_embed_page_setup(GTK_PRINT_UNIX_DIALOG(dialog_),
+ TRUE);
+ gtk_print_unix_dialog_set_support_selection(GTK_PRINT_UNIX_DIALOG(dialog_),
+ TRUE);
+ gtk_print_unix_dialog_set_has_selection(GTK_PRINT_UNIX_DIALOG(dialog_),
+ has_selection);
+ gtk_print_unix_dialog_set_settings(GTK_PRINT_UNIX_DIALOG(dialog_),
+ gtk_settings_);
+ g_signal_connect(dialog_, "response", G_CALLBACK(OnDialogResponseThunk),
+ this);
+ gtk_widget_show(dialog_);
+ }
+
+ bool OnPrintJob(const CefString& document_name,
+ const CefString& pdf_file_path,
+ CefRefPtr<CefPrintJobCallback> callback) {
+ // If |printer_| is nullptr then somehow the GTK printer list changed out
+ // under us. In which case, just bail out.
+ if (!printer_) {
+ return false;
+ }
+
+ ScopedGdkThreadsEnter scoped_gdk_threads;
+
+ job_callback_ = callback;
+
+ // Save the settings for next time.
+ GetLastUsedSettings()->SetLastUsedSettings(gtk_settings_);
+
+ GtkPrintJob* print_job = gtk_print_job_new(
+ document_name.ToString().c_str(), printer_, gtk_settings_, page_setup_);
+ gtk_print_job_set_source_file(print_job, pdf_file_path.ToString().c_str(),
+ nullptr);
+ gtk_print_job_send(print_job, OnJobCompletedThunk, this, nullptr);
+
+ return true;
+ }
+
+ private:
+ void OnDialogResponse(GtkDialog* dialog, gint response_id) {
+ int num_matched_handlers = g_signal_handlers_disconnect_by_func(
+ dialog_, reinterpret_cast<gpointer>(&OnDialogResponseThunk), this);
+ DCHECK_EQ(1, num_matched_handlers);
+
+ gtk_widget_hide(dialog_);
+
+ switch (response_id) {
+ case GTK_RESPONSE_OK: {
+ if (gtk_settings_) {
+ g_object_unref(gtk_settings_);
+ }
+ gtk_settings_ =
+ gtk_print_unix_dialog_get_settings(GTK_PRINT_UNIX_DIALOG(dialog_));
+
+ if (printer_) {
+ g_object_unref(printer_);
+ }
+ printer_ = gtk_print_unix_dialog_get_selected_printer(
+ GTK_PRINT_UNIX_DIALOG(dialog_));
+ g_object_ref(printer_);
+
+ if (page_setup_) {
+ g_object_unref(page_setup_);
+ }
+ page_setup_ = gtk_print_unix_dialog_get_page_setup(
+ GTK_PRINT_UNIX_DIALOG(dialog_));
+ g_object_ref(page_setup_);
+
+ // Handle page ranges.
+ CefPrintSettings::PageRangeList ranges_vector;
+ gint num_ranges;
+ bool print_selection_only = false;
+ switch (gtk_print_settings_get_print_pages(gtk_settings_)) {
+ case GTK_PRINT_PAGES_RANGES: {
+ GtkPageRange* gtk_range =
+ gtk_print_settings_get_page_ranges(gtk_settings_, &num_ranges);
+ if (gtk_range) {
+ for (int i = 0; i < num_ranges; ++i) {
+ ranges_vector.push_back(
+ CefRange(gtk_range[i].start, gtk_range[i].end));
+ }
+ g_free(gtk_range);
+ }
+ break;
+ }
+ case GTK_PRINT_PAGES_SELECTION:
+ print_selection_only = true;
+ break;
+ case GTK_PRINT_PAGES_ALL:
+ // Leave |ranges_vector| empty to indicate print all pages.
+ break;
+ case GTK_PRINT_PAGES_CURRENT:
+ default:
+ NOTREACHED();
+ break;
+ }
+
+ CefRefPtr<CefPrintSettings> settings = CefPrintSettings::Create();
+ settings->SetPageRanges(ranges_vector);
+ settings->SetSelectionOnly(print_selection_only);
+ InitPrintSettings(gtk_settings_, page_setup_, settings);
+ dialog_callback_->Continue(settings);
+ dialog_callback_ = nullptr;
+ return;
+ }
+ case GTK_RESPONSE_DELETE_EVENT: // Fall through.
+ case GTK_RESPONSE_CANCEL: {
+ dialog_callback_->Cancel();
+ dialog_callback_ = nullptr;
+ return;
+ }
+ case GTK_RESPONSE_APPLY:
+ default: {
+ NOTREACHED();
+ }
+ }
+ }
+
+ void OnJobCompleted(GtkPrintJob* print_job, const GError* error) {
+ // Continue() will result in a call to ClientPrintHandlerGtk::OnPrintReset
+ // which deletes |this|. Execute it asnychronously so the call stack has a
+ // chance to unwind.
+ CefPostTask(TID_UI, base::BindOnce(&CefPrintJobCallback::Continue,
+ job_callback_.get()));
+ job_callback_ = nullptr;
+ }
+
+ static void OnDialogResponseThunk(GtkDialog* dialog,
+ gint response_id,
+ PrintHandler* handler) {
+ handler->OnDialogResponse(dialog, response_id);
+ }
+
+ static void OnJobCompletedThunk(GtkPrintJob* print_job,
+ void* handler,
+ const GError* error) {
+ static_cast<PrintHandler*>(handler)->OnJobCompleted(print_job, error);
+ }
+
+ CefRefPtr<CefBrowser> browser_;
+
+ GtkWidget* dialog_; // Owned.
+ GtkPrintSettings* gtk_settings_; // Referenced.
+ GtkPageSetup* page_setup_; // Referenced.
+ GtkPrinter* printer_; // Referenced.
+
+ CefRefPtr<CefPrintDialogCallback> dialog_callback_;
+ CefRefPtr<CefPrintJobCallback> job_callback_;
+};
+
+ClientPrintHandlerGtk::ClientPrintHandlerGtk() {}
+
+ClientPrintHandlerGtk::~ClientPrintHandlerGtk() {
+ DCHECK(!print_handler_);
+}
+
+void ClientPrintHandlerGtk::OnPrintStart(CefRefPtr<CefBrowser> browser) {
+ CEF_REQUIRE_UI_THREAD();
+ DCHECK(!print_handler_);
+ print_handler_.reset(new PrintHandler(browser));
+}
+
+void ClientPrintHandlerGtk::OnPrintSettings(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefPrintSettings> settings,
+ bool get_defaults) {
+ CEF_REQUIRE_UI_THREAD();
+
+ print_handler_->OnPrintSettings(settings, get_defaults);
+}
+
+bool ClientPrintHandlerGtk::OnPrintDialog(
+ CefRefPtr<CefBrowser> browser,
+ bool has_selection,
+ CefRefPtr<CefPrintDialogCallback> callback) {
+ CEF_REQUIRE_UI_THREAD();
+
+ GetWindowAndContinue(browser,
+ base::BindOnce(&PrintHandler::OnPrintDialog,
+ base::Unretained(print_handler_.get()),
+ has_selection, callback));
+ return true;
+}
+
+bool ClientPrintHandlerGtk::OnPrintJob(
+ CefRefPtr<CefBrowser> browser,
+ const CefString& document_name,
+ const CefString& pdf_file_path,
+ CefRefPtr<CefPrintJobCallback> callback) {
+ CEF_REQUIRE_UI_THREAD();
+
+ return print_handler_->OnPrintJob(document_name, pdf_file_path, callback);
+}
+
+void ClientPrintHandlerGtk::OnPrintReset(CefRefPtr<CefBrowser> browser) {
+ CEF_REQUIRE_UI_THREAD();
+
+ // Delete the print handler.
+ print_handler_.reset();
+}
+
+CefSize ClientPrintHandlerGtk::GetPdfPaperSize(CefRefPtr<CefBrowser> browser,
+ int device_units_per_inch) {
+ CEF_REQUIRE_UI_THREAD();
+
+ ScopedGdkThreadsEnter scoped_gdk_threads;
+
+ GtkPageSetup* page_setup = gtk_page_setup_new();
+
+ float width = gtk_page_setup_get_paper_width(page_setup, GTK_UNIT_INCH);
+ float height = gtk_page_setup_get_paper_height(page_setup, GTK_UNIT_INCH);
+
+ g_object_unref(page_setup);
+
+ return CefSize(width * device_units_per_inch, height * device_units_per_inch);
+}
+
+} // namespace client
diff --git a/tests/cefclient/browser/print_handler_gtk.h b/tests/cefclient/browser/print_handler_gtk.h
new file mode 100644
index 00000000..6c38381f
--- /dev/null
+++ b/tests/cefclient/browser/print_handler_gtk.h
@@ -0,0 +1,48 @@
+// Copyright (c) 2014 The Chromium Embedded Framework Authors.
+// Portions Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_PRINT_HANDLER_GTK_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_PRINT_HANDLER_GTK_H_
+#pragma once
+
+#include <memory>
+
+#include "include/cef_print_handler.h"
+
+namespace client {
+
+class ClientPrintHandlerGtk : public CefPrintHandler {
+ public:
+ ClientPrintHandlerGtk();
+ virtual ~ClientPrintHandlerGtk();
+
+ // CefPrintHandler methods.
+ void OnPrintStart(CefRefPtr<CefBrowser> browser) override;
+ void OnPrintSettings(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefPrintSettings> settings,
+ bool get_defaults) override;
+ bool OnPrintDialog(CefRefPtr<CefBrowser> browser,
+ bool has_selection,
+ CefRefPtr<CefPrintDialogCallback> callback) override;
+ bool OnPrintJob(CefRefPtr<CefBrowser> browser,
+ const CefString& document_name,
+ const CefString& pdf_file_path,
+ CefRefPtr<CefPrintJobCallback> callback) override;
+ void OnPrintReset(CefRefPtr<CefBrowser> browser) override;
+ CefSize GetPdfPaperSize(CefRefPtr<CefBrowser> browser,
+ int device_units_per_inch) override;
+
+ private:
+ // Print handler.
+ struct PrintHandler;
+ std::unique_ptr<PrintHandler> print_handler_;
+
+ IMPLEMENT_REFCOUNTING(ClientPrintHandlerGtk);
+ DISALLOW_COPY_AND_ASSIGN(ClientPrintHandlerGtk);
+};
+
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_PRINT_HANDLER_GTK_H_
diff --git a/tests/cefclient/browser/resource.h b/tests/cefclient/browser/resource.h
new file mode 100644
index 00000000..0bd35c86
--- /dev/null
+++ b/tests/cefclient/browser/resource.h
@@ -0,0 +1,87 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by cefclient.rc
+//
+#define BINARY 256
+#define IDC_MYICON 2
+#define IDD_CEFCLIENT_DIALOG 102
+#define IDS_APP_TITLE 103
+#define IDD_ABOUTBOX 103
+#define IDM_ABOUT 104
+#define IDM_EXIT 105
+#define IDI_CEFCLIENT 107
+#define IDI_SMALL 108
+#define IDC_CEFCLIENT 109
+#define IDR_MAINFRAME 128
+#define IDC_NAV_BACK 200
+#define IDC_NAV_FORWARD 201
+#define IDC_NAV_RELOAD 202
+#define IDC_NAV_STOP 203
+#define ID_QUIT 32500
+#define ID_FIND 32501
+#define ID_TESTS_FIRST 32700
+#define ID_TESTS_GETSOURCE 32700
+#define ID_TESTS_GETTEXT 32701
+#define ID_TESTS_OTHER_TESTS 32702
+#define ID_TESTS_WINDOW_NEW 32703
+#define ID_TESTS_WINDOW_POPUP 32704
+#define ID_TESTS_PRINT 32705
+#define ID_TESTS_REQUEST 32706
+#define ID_TESTS_TRACING_BEGIN 32707
+#define ID_TESTS_TRACING_END 32708
+#define ID_TESTS_ZOOM_IN 32709
+#define ID_TESTS_ZOOM_OUT 32710
+#define ID_TESTS_ZOOM_RESET 32711
+#define ID_TESTS_OSR_FPS 32712
+#define ID_TESTS_OSR_DSF 32713
+#define ID_TESTS_PRINT_TO_PDF 32714
+#define ID_TESTS_MUTE_AUDIO 32715
+#define ID_TESTS_UNMUTE_AUDIO 32716
+#define ID_TESTS_LAST 32716
+#define IDC_STATIC -1
+#define IDS_BINDING_HTML 1000
+#define IDS_DIALOGS_HTML 1001
+#define IDS_DRAGGABLE_HTML 1002
+#define IDS_IPC_PERFORMANCE_HTML 1003
+#define IDS_LOCALSTORAGE_HTML 1004
+#define IDS_LOGO_PNG 1005
+#define IDS_MEDIA_ROUTER_HTML 1006
+#define IDS_MENU_ICON_1X_PNG 1007
+#define IDS_MENU_ICON_2X_PNG 1008
+#define IDS_OSRTEST_HTML 1009
+#define IDS_OTHER_TESTS_HTML 1010
+#define IDS_PDF_HTML 1011
+#define IDS_PDF_PDF 1012
+#define IDS_PERFORMANCE_HTML 1013
+#define IDS_PERFORMANCE2_HTML 1014
+#define IDS_PREFERENCES_HTML 1015
+#define IDS_RESPONSE_FILTER_HTML 1016
+#define IDS_SERVER_HTML 1017
+#define IDS_TRANSPARENCY_HTML 1018
+#define IDS_URLREQUEST_HTML 1019
+#define IDS_WEBSOCKET_HTML 1020
+#define IDS_WINDOW_HTML 1021
+#define IDS_WINDOW_ICON_1X_PNG 1022
+#define IDS_WINDOW_ICON_2X_PNG 1023
+#define IDS_XMLHTTPREQUEST_HTML 1024
+
+#define IDS_EXTENSIONS_SET_PAGE_COLOR_ICON_PNG 1030
+#define IDS_EXTENSIONS_SET_PAGE_COLOR_MANIFEST_JSON 1031
+#define IDS_EXTENSIONS_SET_PAGE_COLOR_POPUP_HTML 1032
+#define IDS_EXTENSIONS_SET_PAGE_COLOR_POPUP_JS 1033
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NO_MFC 1
+#define _APS_NEXT_RESOURCE_VALUE 130
+#define _APS_NEXT_COMMAND_VALUE 32774
+#define _APS_NEXT_CONTROL_VALUE 1000
+#define _APS_NEXT_SYMED_VALUE 111
+#endif
+#endif
diff --git a/tests/cefclient/browser/resource_util_linux.cc b/tests/cefclient/browser/resource_util_linux.cc
new file mode 100644
index 00000000..0acdd096
--- /dev/null
+++ b/tests/cefclient/browser/resource_util_linux.cc
@@ -0,0 +1,37 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors.
+// Portions copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "tests/shared/browser/resource_util.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+namespace client {
+
+bool GetResourceDir(std::string& dir) {
+ char buff[1024];
+
+ // Retrieve the executable path.
+ ssize_t len = readlink("/proc/self/exe", buff, sizeof(buff) - 1);
+ if (len == -1) {
+ return false;
+ }
+
+ buff[len] = 0;
+
+ // Remove the executable name from the path.
+ char* pos = strrchr(buff, '/');
+ if (!pos) {
+ return false;
+ }
+
+ // Add "cefclient_files" to the path.
+ strcpy(pos + 1, "cefclient_files");
+ dir = std::string(buff);
+ return true;
+}
+
+} // namespace client
diff --git a/tests/cefclient/browser/resource_util_win_idmap.cc b/tests/cefclient/browser/resource_util_win_idmap.cc
new file mode 100644
index 00000000..086932c1
--- /dev/null
+++ b/tests/cefclient/browser/resource_util_win_idmap.cc
@@ -0,0 +1,60 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include <cstring>
+
+#include "tests/cefclient/browser/resource.h"
+
+namespace client {
+
+int GetResourceId(const char* resource_name) {
+ // Map of resource labels to BINARY id values.
+ static struct _resource_map {
+ const char* name;
+ int id;
+ } resource_map[] = {{"binding.html", IDS_BINDING_HTML},
+ {"dialogs.html", IDS_DIALOGS_HTML},
+ {"draggable.html", IDS_DRAGGABLE_HTML},
+ {"extensions/set_page_color/icon.png",
+ IDS_EXTENSIONS_SET_PAGE_COLOR_ICON_PNG},
+ {"extensions/set_page_color/manifest.json",
+ IDS_EXTENSIONS_SET_PAGE_COLOR_MANIFEST_JSON},
+ {"extensions/set_page_color/popup.html",
+ IDS_EXTENSIONS_SET_PAGE_COLOR_POPUP_HTML},
+ {"extensions/set_page_color/popup.js",
+ IDS_EXTENSIONS_SET_PAGE_COLOR_POPUP_JS},
+ {"ipc_performance.html", IDS_IPC_PERFORMANCE_HTML},
+ {"localstorage.html", IDS_LOCALSTORAGE_HTML},
+ {"logo.png", IDS_LOGO_PNG},
+ {"media_router.html", IDS_MEDIA_ROUTER_HTML},
+ {"menu_icon.1x.png", IDS_MENU_ICON_1X_PNG},
+ {"menu_icon.2x.png", IDS_MENU_ICON_2X_PNG},
+ {"osr_test.html", IDS_OSRTEST_HTML},
+ {"other_tests.html", IDS_OTHER_TESTS_HTML},
+ {"pdf.html", IDS_PDF_HTML},
+ {"pdf.pdf", IDS_PDF_PDF},
+ {"performance.html", IDS_PERFORMANCE_HTML},
+ {"performance2.html", IDS_PERFORMANCE2_HTML},
+ {"preferences.html", IDS_PREFERENCES_HTML},
+ {"response_filter.html", IDS_RESPONSE_FILTER_HTML},
+ {"server.html", IDS_SERVER_HTML},
+ {"transparency.html", IDS_TRANSPARENCY_HTML},
+ {"urlrequest.html", IDS_URLREQUEST_HTML},
+ {"websocket.html", IDS_WEBSOCKET_HTML},
+ {"window.html", IDS_WINDOW_HTML},
+ {"window_icon.1x.png", IDS_WINDOW_ICON_1X_PNG},
+ {"window_icon.2x.png", IDS_WINDOW_ICON_2X_PNG},
+ {"xmlhttprequest.html", IDS_XMLHTTPREQUEST_HTML},
+ {"xmlhttprequest.html", IDS_XMLHTTPREQUEST_HTML}};
+
+ for (size_t i = 0; i < sizeof(resource_map) / sizeof(_resource_map); ++i) {
+ if (!strcmp(resource_map[i].name, resource_name)) {
+ return resource_map[i].id;
+ }
+ }
+
+ return 0;
+}
+
+} // namespace client
diff --git a/tests/cefclient/browser/response_filter_test.cc b/tests/cefclient/browser/response_filter_test.cc
new file mode 100644
index 00000000..4e2e2434
--- /dev/null
+++ b/tests/cefclient/browser/response_filter_test.cc
@@ -0,0 +1,246 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/response_filter_test.h"
+
+#include <algorithm>
+#include <sstream>
+#include <string>
+
+#include "include/base/cef_logging.h"
+#include "include/cef_command_line.h"
+#include "tests/cefclient/browser/test_runner.h"
+#include "tests/shared/common/client_switches.h"
+
+namespace client {
+namespace response_filter_test {
+
+namespace {
+
+const char kTestUrlPath[] = "/response_filter";
+const char kFindString[] = "REPLACE_THIS_STRING";
+const char kReplaceString[] = "This is the replaced string!";
+
+// Helper for passing params to Write().
+#define WRITE_PARAMS data_out_ptr, data_out_size, data_out_written
+
+// Filter the contents of response_filter.html by replacing all instances of
+// |kFindString| with |kReplaceString|. Pass the `--enable-filter-testing`
+// command-line flag (which shrinks the buffer size to 32 bytes) to better test
+// the logic in this implementation.
+class FindReplaceResponseFilter : public CefResponseFilter {
+ public:
+ FindReplaceResponseFilter()
+ : find_match_offset_(0U),
+ replace_overflow_size_(0U),
+ replace_count_(0U) {}
+
+ bool InitFilter() override {
+ const size_t find_size = sizeof(kFindString) - 1;
+ const size_t replace_size = sizeof(kReplaceString) - 1;
+
+ // Determine a reasonable amount of space for find/replace overflow. For
+ // example, the amount of space required if the search string is
+ // found/replaced 10 times (plus space for the count).
+ if (replace_size > find_size) {
+ replace_overflow_size_ = (replace_size - find_size + 3) * 10;
+ }
+
+ return true;
+ }
+
+ FilterStatus Filter(void* data_in,
+ size_t data_in_size,
+ size_t& data_in_read,
+ void* data_out,
+ size_t data_out_size,
+ size_t& data_out_written) override {
+ DCHECK((data_in_size == 0U && !data_in) || (data_in_size > 0U && data_in));
+ DCHECK_EQ(data_in_read, 0U);
+ DCHECK(data_out);
+ DCHECK_GT(data_out_size, 0U);
+ DCHECK_EQ(data_out_written, 0U);
+
+ // All data will be read.
+ data_in_read = data_in_size;
+
+ const size_t find_size = sizeof(kFindString) - 1;
+
+ const char* data_in_ptr = static_cast<char*>(data_in);
+ char* data_out_ptr = static_cast<char*>(data_out);
+
+ // Reset the overflow.
+ std::string old_overflow;
+ if (!overflow_.empty()) {
+ old_overflow = overflow_;
+ overflow_.clear();
+ }
+
+ const size_t likely_out_size =
+ data_in_size + replace_overflow_size_ + old_overflow.size();
+ if (data_out_size < likely_out_size) {
+ // We'll likely need to use the overflow buffer. Size it appropriately.
+ overflow_.reserve(likely_out_size - data_out_size);
+ }
+
+ if (!old_overflow.empty()) {
+ // Write the overflow from last time.
+ Write(old_overflow.c_str(), old_overflow.size(), WRITE_PARAMS);
+ }
+
+ // Evaluate each character in the input buffer. Track how many characters in
+ // a row match kFindString. If kFindString is completely matched then write
+ // kReplaceString. Otherwise, write the input characters as-is.
+ for (size_t i = 0U; i < data_in_size; ++i) {
+ if (data_in_ptr[i] == kFindString[find_match_offset_]) {
+ // Matched the next character in the find string.
+ if (++find_match_offset_ == find_size) {
+ // Complete match of the find string. Write the replace string.
+ std::stringstream ss;
+ ss << ++replace_count_ << ". " << kReplaceString;
+ const std::string& replace_str = ss.str();
+ Write(replace_str.c_str(), replace_str.size(), WRITE_PARAMS);
+
+ // Start over looking for a match.
+ find_match_offset_ = 0;
+ }
+ continue;
+ }
+
+ // Character did not match the find string.
+ if (find_match_offset_ > 0) {
+ // Write the portion of the find string that has matched so far.
+ Write(kFindString, find_match_offset_, WRITE_PARAMS);
+
+ // Start over looking for a match.
+ find_match_offset_ = 0;
+ }
+
+ // Write the current character.
+ Write(&data_in_ptr[i], 1, WRITE_PARAMS);
+ }
+
+ // If a match is currently in-progress we need more data. Otherwise, we're
+ // done.
+ return find_match_offset_ > 0 ? RESPONSE_FILTER_NEED_MORE_DATA
+ : RESPONSE_FILTER_DONE;
+ }
+
+ private:
+ inline void Write(const char* str,
+ size_t str_size,
+ char*& data_out_ptr,
+ size_t data_out_size,
+ size_t& data_out_written) {
+ // Number of bytes remaining in the output buffer.
+ const size_t remaining_space = data_out_size - data_out_written;
+ // Maximum number of bytes we can write into the output buffer.
+ const size_t max_write = std::min(str_size, remaining_space);
+
+ // Write the maximum portion that fits in the output buffer.
+ if (max_write == 1) {
+ // Small optimization for single character writes.
+ *data_out_ptr = str[0];
+ data_out_ptr += 1;
+ data_out_written += 1;
+ } else if (max_write > 1) {
+ memcpy(data_out_ptr, str, max_write);
+ data_out_ptr += max_write;
+ data_out_written += max_write;
+ }
+
+ if (max_write < str_size) {
+ // Need to write more bytes than will fit in the output buffer. Store the
+ // remainder in the overflow buffer.
+ overflow_ += std::string(str + max_write, str_size - max_write);
+ }
+ }
+
+ // The portion of the find string that is currently matching.
+ size_t find_match_offset_;
+
+ // The likely amount of overflow.
+ size_t replace_overflow_size_;
+
+ // Overflow from the output buffer.
+ std::string overflow_;
+
+ // Number of times the the string was found/replaced.
+ size_t replace_count_;
+
+ IMPLEMENT_REFCOUNTING(FindReplaceResponseFilter);
+};
+
+// Filter that writes out all of the contents unchanged.
+class PassThruResponseFilter : public CefResponseFilter {
+ public:
+ PassThruResponseFilter() {}
+
+ bool InitFilter() override { return true; }
+
+ FilterStatus Filter(void* data_in,
+ size_t data_in_size,
+ size_t& data_in_read,
+ void* data_out,
+ size_t data_out_size,
+ size_t& data_out_written) override {
+ DCHECK((data_in_size == 0U && !data_in) || (data_in_size > 0U && data_in));
+ DCHECK_EQ(data_in_read, 0U);
+ DCHECK(data_out);
+ DCHECK_GT(data_out_size, 0U);
+ DCHECK_EQ(data_out_written, 0U);
+
+ // Write out the contents unchanged.
+ data_out_written = std::min(data_in_size, data_out_size);
+
+ // All data will be read.
+ data_in_read = data_out_written;
+
+ if (data_out_written > 0) {
+ memcpy(data_out, data_in, data_out_written);
+ }
+
+ return RESPONSE_FILTER_DONE;
+ }
+
+ private:
+ IMPLEMENT_REFCOUNTING(PassThruResponseFilter);
+};
+
+// Returns true if |url| starts with the value specified via the `--filter-url`
+// command-line flag.
+bool MatchesFilterURL(const std::string& url) {
+ CefRefPtr<CefCommandLine> command_line =
+ CefCommandLine::GetGlobalCommandLine();
+ if (command_line->HasSwitch(switches::kFilterURL)) {
+ const std::string& filter_url =
+ command_line->GetSwitchValue(switches::kFilterURL);
+ return url.find(filter_url) == 0;
+ }
+ return false;
+}
+
+} // namespace
+
+CefRefPtr<CefResponseFilter> GetResourceResponseFilter(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response) {
+ // Use the find/replace filter on the test URL.
+ const std::string& url = request->GetURL();
+
+ if (test_runner::IsTestURL(url, kTestUrlPath)) {
+ return new FindReplaceResponseFilter();
+ }
+
+ if (MatchesFilterURL(url)) {
+ return new PassThruResponseFilter();
+ }
+
+ return nullptr;
+}
+
+} // namespace response_filter_test
+} // namespace client
diff --git a/tests/cefclient/browser/response_filter_test.h b/tests/cefclient/browser/response_filter_test.h
new file mode 100644
index 00000000..ddb23207
--- /dev/null
+++ b/tests/cefclient/browser/response_filter_test.h
@@ -0,0 +1,27 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_RESPONSE_FILTER_TEST_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_RESPONSE_FILTER_TEST_H_
+#pragma once
+
+#include "include/cef_browser.h"
+#include "include/cef_request.h"
+#include "include/cef_response.h"
+#include "include/cef_response_filter.h"
+
+namespace client {
+namespace response_filter_test {
+
+// Create a resource response filter. Called from test_runner.cc.
+CefRefPtr<CefResponseFilter> GetResourceResponseFilter(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response);
+
+} // namespace response_filter_test
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_RESPONSE_FILTER_TEST_H_
diff --git a/tests/cefclient/browser/root_window.cc b/tests/cefclient/browser/root_window.cc
new file mode 100644
index 00000000..f2fb4e07
--- /dev/null
+++ b/tests/cefclient/browser/root_window.cc
@@ -0,0 +1,42 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/root_window.h"
+
+#include "include/base/cef_callback_helpers.h"
+
+#include "tests/cefclient/browser/main_context.h"
+#include "tests/cefclient/browser/root_window_manager.h"
+
+namespace client {
+
+RootWindowConfig::RootWindowConfig() : url(MainContext::Get()->GetMainURL()) {}
+
+RootWindow::RootWindow() : delegate_(nullptr) {}
+
+RootWindow::~RootWindow() {}
+
+// static
+scoped_refptr<RootWindow> RootWindow::GetForBrowser(int browser_id) {
+ return MainContext::Get()->GetRootWindowManager()->GetWindowForBrowser(
+ browser_id);
+}
+
+void RootWindow::OnExtensionsChanged(const ExtensionSet& extensions) {
+ REQUIRE_MAIN_THREAD();
+ DCHECK(delegate_);
+ DCHECK(!WithExtension());
+
+ if (extensions.empty()) {
+ return;
+ }
+
+ ExtensionSet::const_iterator it = extensions.begin();
+ for (; it != extensions.end(); ++it) {
+ delegate_->CreateExtensionWindow(*it, CefRect(), nullptr, base::DoNothing(),
+ WithWindowlessRendering());
+ }
+}
+
+} // namespace client
diff --git a/tests/cefclient/browser/root_window.h b/tests/cefclient/browser/root_window.h
new file mode 100644
index 00000000..ba86c0e5
--- /dev/null
+++ b/tests/cefclient/browser/root_window.h
@@ -0,0 +1,205 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_ROOT_WINDOW_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_ROOT_WINDOW_H_
+#pragma once
+
+#include <memory>
+#include <set>
+#include <string>
+
+#include "include/base/cef_callback_forward.h"
+#include "include/base/cef_ref_counted.h"
+#include "include/cef_browser.h"
+#include "include/views/cef_window.h"
+#include "tests/cefclient/browser/client_types.h"
+#include "tests/cefclient/browser/image_cache.h"
+#include "tests/shared/browser/main_message_loop.h"
+
+namespace client {
+
+// Used to configure how a RootWindow is created.
+struct RootWindowConfig {
+ RootWindowConfig();
+
+ // If true the window will always display above other windows.
+ bool always_on_top = false;
+
+ // If true the window will show controls.
+ bool with_controls = true;
+
+ // If true the window will use off-screen rendering.
+ bool with_osr = false;
+
+ // If true the window is hosting an extension app.
+ bool with_extension = false;
+
+ // If true the window will be created initially hidden.
+ bool initially_hidden = false;
+
+ // Requested window position. If |bounds| and |source_bounds| are empty the
+ // default window size and location will be used.
+ CefRect bounds;
+
+ // Position of the UI element that triggered the window creation. If |bounds|
+ // is empty and |source_bounds| is non-empty the new window will be positioned
+ // relative to |source_bounds|. This is currently only implemented for Views-
+ // based windows when |initially_hidden| is also true.
+ CefRect source_bounds;
+
+ // Requested window show state. Only used when |bounds| is non-empty and
+ // |initially_hidden| is false.
+ cef_show_state_t show_state = CEF_SHOW_STATE_NORMAL;
+
+ // Parent window. Only used for Views-based windows.
+ CefRefPtr<CefWindow> parent_window;
+
+ // Callback to be executed when the window is closed. Will be executed on the
+ // main thread. This is currently only implemented for Views-based windows.
+ base::OnceClosure close_callback;
+
+ // Initial URL to load.
+ std::string url;
+};
+
+typedef std::set<CefRefPtr<CefExtension>> ExtensionSet;
+
+// Represents a top-level native window in the browser process. While references
+// to this object are thread-safe the methods must be called on the main thread
+// unless otherwise indicated.
+class RootWindow
+ : public base::RefCountedThreadSafe<RootWindow, DeleteOnMainThread> {
+ public:
+ // This interface is implemented by the owner of the RootWindow. The methods
+ // of this class will be called on the main thread.
+ class Delegate {
+ public:
+ // Called to retrieve the CefRequestContext for browser. Only called for
+ // non-popup browsers. May return nullptr.
+ virtual CefRefPtr<CefRequestContext> GetRequestContext(
+ RootWindow* root_window) = 0;
+
+ // Returns the ImageCache.
+ virtual scoped_refptr<ImageCache> GetImageCache() = 0;
+
+ // Called to execute a test. See resource.h for |test_id| values.
+ virtual void OnTest(RootWindow* root_window, int test_id) = 0;
+
+ // Called to exit the application.
+ virtual void OnExit(RootWindow* root_window) = 0;
+
+ // Called when the RootWindow has been destroyed.
+ virtual void OnRootWindowDestroyed(RootWindow* root_window) = 0;
+
+ // Called when the RootWindow is activated (becomes the foreground window).
+ virtual void OnRootWindowActivated(RootWindow* root_window) = 0;
+
+ // Called when the browser is created for the RootWindow.
+ virtual void OnBrowserCreated(RootWindow* root_window,
+ CefRefPtr<CefBrowser> browser) = 0;
+
+ // Create a window for |extension|. |source_bounds| are the bounds of the
+ // UI element, like a button, that triggered the extension.
+ virtual void CreateExtensionWindow(CefRefPtr<CefExtension> extension,
+ const CefRect& source_bounds,
+ CefRefPtr<CefWindow> parent_window,
+ base::OnceClosure close_callback,
+ bool with_osr) = 0;
+
+ protected:
+ virtual ~Delegate() {}
+ };
+
+ // Create a new RootWindow object. This method may be called on any thread.
+ // Use RootWindowManager::CreateRootWindow() or CreateRootWindowAsPopup()
+ // instead of calling this method directly. |use_views| will be true if the
+ // Views framework should be used.
+ static scoped_refptr<RootWindow> Create(bool use_views);
+
+ // Returns the RootWindow associated with the specified |browser_id|. Must be
+ // called on the main thread.
+ static scoped_refptr<RootWindow> GetForBrowser(int browser_id);
+
+ // Initialize as a normal window. This will create and show a native window
+ // hosting a single browser instance. This method may be called on any thread.
+ // |delegate| must be non-nullptr and outlive this object.
+ // Use RootWindowManager::CreateRootWindow() instead of calling this method
+ // directly.
+ virtual void Init(RootWindow::Delegate* delegate,
+ std::unique_ptr<RootWindowConfig> config,
+ const CefBrowserSettings& settings) = 0;
+
+ // Initialize as a popup window. This is used to attach a new native window to
+ // a single browser instance that will be created later. The native window
+ // will be created and shown once the browser is available. This method may be
+ // called on any thread. |delegate| must be non-nullptr and outlive this
+ // object. Use RootWindowManager::CreateRootWindowAsPopup() instead of calling
+ // this method directly. Called on the UI thread.
+ virtual void InitAsPopup(RootWindow::Delegate* delegate,
+ bool with_controls,
+ bool with_osr,
+ const CefPopupFeatures& popupFeatures,
+ CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient>& client,
+ CefBrowserSettings& settings) = 0;
+
+ enum ShowMode {
+ ShowNormal,
+ ShowMinimized,
+ ShowMaximized,
+ ShowNoActivate,
+ };
+
+ // Show the window.
+ virtual void Show(ShowMode mode) = 0;
+
+ // Hide the window.
+ virtual void Hide() = 0;
+
+ // Set the window bounds in screen coordinates.
+ virtual void SetBounds(int x, int y, size_t width, size_t height) = 0;
+
+ // Close the window. If |force| is true onunload handlers will not be
+ // executed.
+ virtual void Close(bool force) = 0;
+
+ // Set the device scale factor. Only used in combination with off-screen
+ // rendering.
+ virtual void SetDeviceScaleFactor(float device_scale_factor) = 0;
+
+ // Returns the device scale factor. Only used in combination with off-screen
+ // rendering.
+ virtual float GetDeviceScaleFactor() const = 0;
+
+ // Returns the browser that this window contains, if any.
+ virtual CefRefPtr<CefBrowser> GetBrowser() const = 0;
+
+ // Returns the native handle for this window, if any.
+ virtual ClientWindowHandle GetWindowHandle() const = 0;
+
+ // Returns true if this window is using windowless rendering (osr).
+ virtual bool WithWindowlessRendering() const = 0;
+
+ // Returns true if this window is hosting an extension app.
+ virtual bool WithExtension() const = 0;
+
+ // Called when the set of loaded extensions changes. The default
+ // implementation will create a single window instance for each extension.
+ virtual void OnExtensionsChanged(const ExtensionSet& extensions);
+
+ protected:
+ // Allow deletion via scoped_refptr only.
+ friend struct DeleteOnMainThread;
+ friend class base::RefCountedThreadSafe<RootWindow, DeleteOnMainThread>;
+
+ RootWindow();
+ virtual ~RootWindow();
+
+ Delegate* delegate_;
+};
+
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_ROOT_WINDOW_H_
diff --git a/tests/cefclient/browser/root_window_create.cc b/tests/cefclient/browser/root_window_create.cc
new file mode 100644
index 00000000..2ad06cf6
--- /dev/null
+++ b/tests/cefclient/browser/root_window_create.cc
@@ -0,0 +1,36 @@
+// Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/root_window.h"
+
+#include "tests/cefclient/browser/root_window_views.h"
+
+#if defined(OS_WIN)
+#include "tests/cefclient/browser/root_window_win.h"
+#elif defined(OS_LINUX)
+#include "tests/cefclient/browser/root_window_gtk.h"
+#elif defined(OS_MAC)
+#include "tests/cefclient/browser/root_window_mac.h"
+#endif
+
+namespace client {
+
+// static
+scoped_refptr<RootWindow> RootWindow::Create(bool use_views) {
+ if (use_views) {
+ return new RootWindowViews();
+ }
+
+#if defined(OS_WIN)
+ return new RootWindowWin();
+#elif defined(OS_LINUX)
+ return new RootWindowGtk();
+#elif defined(OS_MAC)
+ return new RootWindowMac();
+#else
+#error Unsupported platform
+#endif
+}
+
+} // namespace client
diff --git a/tests/cefclient/browser/root_window_gtk.cc b/tests/cefclient/browser/root_window_gtk.cc
new file mode 100644
index 00000000..cee0041c
--- /dev/null
+++ b/tests/cefclient/browser/root_window_gtk.cc
@@ -0,0 +1,987 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/root_window_gtk.h"
+
+#include <gdk/gdk.h>
+#include <gdk/gdkx.h>
+
+#include <X11/Xlib.h>
+#undef Success // Definition conflicts with cef_message_router.h
+#undef RootWindow // Definition conflicts with root_window.h
+
+#include "include/base/cef_callback.h"
+#include "include/cef_app.h"
+#include "tests/cefclient/browser/browser_window_osr_gtk.h"
+#include "tests/cefclient/browser/browser_window_std_gtk.h"
+#include "tests/cefclient/browser/main_context.h"
+#include "tests/cefclient/browser/resource.h"
+#include "tests/cefclient/browser/temp_window.h"
+#include "tests/cefclient/browser/util_gtk.h"
+#include "tests/cefclient/browser/window_test_runner_gtk.h"
+#include "tests/shared/browser/main_message_loop.h"
+#include "tests/shared/common/client_switches.h"
+
+namespace client {
+
+namespace {
+
+const char kMenuIdKey[] = "menu_id";
+
+void UseDefaultX11VisualForGtk(GtkWidget* widget) {
+#if GTK_CHECK_VERSION(3, 15, 1)
+ // GTK+ > 3.15.1 uses an X11 visual optimized for GTK+'s OpenGL stuff
+ // since revid dae447728d: https://github.com/GNOME/gtk/commit/dae447728d
+ // However, it breaks CEF: https://github.com/cztomczak/cefcapi/issues/9
+ // Let's use the default X11 visual instead of the GTK's blessed one.
+ // Copied from: https://github.com/cztomczak/cefcapi.
+ GdkScreen* screen = gdk_screen_get_default();
+ GList* visuals = gdk_screen_list_visuals(screen);
+
+ GdkX11Screen* x11_screen = GDK_X11_SCREEN(screen);
+ if (x11_screen == nullptr) {
+ return;
+ }
+
+ Visual* default_xvisual = DefaultVisual(GDK_SCREEN_XDISPLAY(x11_screen),
+ GDK_SCREEN_XNUMBER(x11_screen));
+ GList* cursor = visuals;
+ while (cursor != nullptr) {
+ GdkVisual* visual = GDK_X11_VISUAL(cursor->data);
+ if (default_xvisual->visualid ==
+ gdk_x11_visual_get_xvisual(visual)->visualid) {
+ gtk_widget_set_visual(widget, visual);
+ break;
+ }
+ cursor = cursor->next;
+ }
+ g_list_free(visuals);
+#endif
+}
+
+bool IsWindowMaximized(GtkWindow* window) {
+ GdkWindow* gdk_window = gtk_widget_get_window(GTK_WIDGET(window));
+ gint state = gdk_window_get_state(gdk_window);
+ return (state & GDK_WINDOW_STATE_MAXIMIZED) ? true : false;
+}
+
+void MinimizeWindow(GtkWindow* window) {
+ // Unmaximize the window before minimizing so restore behaves correctly.
+ if (IsWindowMaximized(window)) {
+ gtk_window_unmaximize(window);
+ }
+
+ gtk_window_iconify(window);
+}
+
+void MaximizeWindow(GtkWindow* window) {
+ gtk_window_maximize(window);
+}
+
+} // namespace
+
+RootWindowGtk::RootWindowGtk()
+ : with_controls_(false),
+ always_on_top_(false),
+ with_osr_(false),
+ with_extension_(false),
+ is_popup_(false),
+ initialized_(false),
+ window_(nullptr),
+ back_button_(nullptr),
+ forward_button_(nullptr),
+ reload_button_(nullptr),
+ stop_button_(nullptr),
+ url_entry_(nullptr),
+ toolbar_height_(0),
+ menubar_height_(0),
+ window_destroyed_(false),
+ browser_destroyed_(false),
+ force_close_(false),
+ is_closing_(false) {}
+
+RootWindowGtk::~RootWindowGtk() {
+ REQUIRE_MAIN_THREAD();
+
+ // The window and browser should already have been destroyed.
+ DCHECK(window_destroyed_);
+ DCHECK(browser_destroyed_);
+}
+
+void RootWindowGtk::Init(RootWindow::Delegate* delegate,
+ std::unique_ptr<RootWindowConfig> config,
+ const CefBrowserSettings& settings) {
+ DCHECK(delegate);
+ DCHECK(!initialized_);
+
+ delegate_ = delegate;
+ with_controls_ = config->with_controls;
+ always_on_top_ = config->always_on_top;
+ with_osr_ = config->with_osr;
+ with_extension_ = config->with_extension;
+ start_rect_ = config->bounds;
+
+ CreateBrowserWindow(config->url);
+
+ initialized_ = true;
+
+ // Always post asynchronously to avoid reentrancy of the GDK lock.
+ MAIN_POST_CLOSURE(base::BindOnce(&RootWindowGtk::CreateRootWindow, this,
+ settings, config->initially_hidden));
+}
+
+void RootWindowGtk::InitAsPopup(RootWindow::Delegate* delegate,
+ bool with_controls,
+ bool with_osr,
+ const CefPopupFeatures& popupFeatures,
+ CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient>& client,
+ CefBrowserSettings& settings) {
+ DCHECK(delegate);
+ DCHECK(!initialized_);
+
+ delegate_ = delegate;
+ with_controls_ = with_controls;
+ with_osr_ = with_osr;
+ is_popup_ = true;
+
+ if (popupFeatures.xSet) {
+ start_rect_.x = popupFeatures.x;
+ }
+ if (popupFeatures.ySet) {
+ start_rect_.y = popupFeatures.y;
+ }
+ if (popupFeatures.widthSet) {
+ start_rect_.width = popupFeatures.width;
+ }
+ if (popupFeatures.heightSet) {
+ start_rect_.height = popupFeatures.height;
+ }
+
+ CreateBrowserWindow(std::string());
+
+ initialized_ = true;
+
+ // The new popup is initially parented to a temporary window. The native root
+ // window will be created after the browser is created and the popup window
+ // will be re-parented to it at that time.
+ browser_window_->GetPopupConfig(TempWindow::GetWindowHandle(), windowInfo,
+ client, settings);
+}
+
+void RootWindowGtk::Show(ShowMode mode) {
+ REQUIRE_MAIN_THREAD();
+
+ if (!window_) {
+ return;
+ }
+
+ ScopedGdkThreadsEnter scoped_gdk_threads;
+
+ // Show the GTK window.
+ UseDefaultX11VisualForGtk(GTK_WIDGET(window_));
+ gtk_widget_show_all(window_);
+
+ if (mode == ShowMinimized) {
+ MinimizeWindow(GTK_WINDOW(window_));
+ } else if (mode == ShowMaximized) {
+ MaximizeWindow(GTK_WINDOW(window_));
+ }
+
+ // Flush the display to make sure the underlying X11 window gets created
+ // immediately.
+ GdkWindow* gdk_window = gtk_widget_get_window(window_);
+ GdkDisplay* display = gdk_window_get_display(gdk_window);
+ gdk_display_flush(display);
+}
+
+void RootWindowGtk::Hide() {
+ REQUIRE_MAIN_THREAD();
+
+ ScopedGdkThreadsEnter scoped_gdk_threads;
+
+ if (window_) {
+ gtk_widget_hide(window_);
+ }
+}
+
+void RootWindowGtk::SetBounds(int x, int y, size_t width, size_t height) {
+ REQUIRE_MAIN_THREAD();
+
+ if (!window_) {
+ return;
+ }
+
+ ScopedGdkThreadsEnter scoped_gdk_threads;
+
+ GtkWindow* window = GTK_WINDOW(window_);
+ GdkWindow* gdk_window = gtk_widget_get_window(window_);
+
+ // Make sure the window isn't minimized or maximized.
+ if (IsWindowMaximized(window)) {
+ gtk_window_unmaximize(window);
+ } else {
+ gtk_window_present(window);
+ }
+
+ gdk_window_move_resize(gdk_window, x, y, width, height);
+}
+
+void RootWindowGtk::Close(bool force) {
+ REQUIRE_MAIN_THREAD();
+
+ if (window_) {
+ ScopedGdkThreadsEnter scoped_gdk_threads;
+
+ if (force) {
+ NotifyForceClose();
+ }
+ gtk_widget_destroy(window_);
+ }
+}
+
+void RootWindowGtk::SetDeviceScaleFactor(float device_scale_factor) {
+ REQUIRE_MAIN_THREAD();
+
+ if (browser_window_ && with_osr_) {
+ browser_window_->SetDeviceScaleFactor(device_scale_factor);
+ }
+}
+
+float RootWindowGtk::GetDeviceScaleFactor() const {
+ REQUIRE_MAIN_THREAD();
+
+ if (browser_window_ && with_osr_) {
+ return browser_window_->GetDeviceScaleFactor();
+ }
+
+ NOTREACHED();
+ return 0.0f;
+}
+
+CefRefPtr<CefBrowser> RootWindowGtk::GetBrowser() const {
+ REQUIRE_MAIN_THREAD();
+
+ if (browser_window_) {
+ return browser_window_->GetBrowser();
+ }
+ return nullptr;
+}
+
+ClientWindowHandle RootWindowGtk::GetWindowHandle() const {
+ REQUIRE_MAIN_THREAD();
+ return window_;
+}
+
+bool RootWindowGtk::WithWindowlessRendering() const {
+ REQUIRE_MAIN_THREAD();
+ return with_osr_;
+}
+
+bool RootWindowGtk::WithExtension() const {
+ REQUIRE_MAIN_THREAD();
+ return with_extension_;
+}
+
+void RootWindowGtk::CreateBrowserWindow(const std::string& startup_url) {
+ if (with_osr_) {
+ OsrRendererSettings settings = {};
+ MainContext::Get()->PopulateOsrSettings(&settings);
+ browser_window_.reset(
+ new BrowserWindowOsrGtk(this, with_controls_, startup_url, settings));
+ } else {
+ browser_window_.reset(
+ new BrowserWindowStdGtk(this, with_controls_, startup_url));
+ }
+}
+
+void RootWindowGtk::CreateRootWindow(const CefBrowserSettings& settings,
+ bool initially_hidden) {
+ REQUIRE_MAIN_THREAD();
+ DCHECK(!window_);
+
+ // TODO(port): If no x,y position is specified the window will always appear
+ // in the upper-left corner. Maybe there's a better default place to put it?
+ int x = start_rect_.x;
+ int y = start_rect_.y;
+ int width, height;
+ if (start_rect_.IsEmpty()) {
+ // TODO(port): Also, maybe there's a better way to choose the default size.
+ width = 800;
+ height = 600;
+ } else {
+ width = start_rect_.width;
+ height = start_rect_.height;
+ }
+
+ ScopedGdkThreadsEnter scoped_gdk_threads;
+
+ window_ = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ CHECK(window_);
+
+ if (always_on_top_) {
+ gtk_window_set_keep_above(GTK_WINDOW(window_), TRUE);
+ }
+
+ gtk_window_set_default_size(GTK_WINDOW(window_), width, height);
+ g_signal_connect(G_OBJECT(window_), "focus-in-event",
+ G_CALLBACK(&RootWindowGtk::WindowFocusIn), this);
+ g_signal_connect(G_OBJECT(window_), "window-state-event",
+ G_CALLBACK(&RootWindowGtk::WindowState), this);
+ g_signal_connect(G_OBJECT(window_), "configure-event",
+ G_CALLBACK(&RootWindowGtk::WindowConfigure), this);
+ g_signal_connect(G_OBJECT(window_), "destroy",
+ G_CALLBACK(&RootWindowGtk::WindowDestroy), this);
+ g_signal_connect(G_OBJECT(window_), "delete_event",
+ G_CALLBACK(&RootWindowGtk::WindowDelete), this);
+
+ const cef_color_t background_color = MainContext::Get()->GetBackgroundColor();
+ GdkRGBA rgba = {0};
+ rgba.red = CefColorGetR(background_color) * 65535 / 255;
+ rgba.green = CefColorGetG(background_color) * 65535 / 255;
+ rgba.blue = CefColorGetB(background_color) * 65535 / 255;
+ rgba.alpha = 1;
+
+ gchar* css = g_strdup_printf("#* { background-color: %s; }",
+ gdk_rgba_to_string(&rgba));
+ GtkCssProvider* provider = gtk_css_provider_new();
+ gtk_css_provider_load_from_data(provider, css, -1, nullptr);
+ g_free(css);
+ gtk_style_context_add_provider(gtk_widget_get_style_context(window_),
+ GTK_STYLE_PROVIDER(provider),
+ GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
+ g_object_unref(provider);
+
+ GtkWidget* grid = gtk_grid_new();
+ gtk_grid_set_column_homogeneous(GTK_GRID(grid), TRUE);
+ g_signal_connect(grid, "size-allocate",
+ G_CALLBACK(&RootWindowGtk::GridSizeAllocated), this);
+ gtk_container_add(GTK_CONTAINER(window_), grid);
+
+ if (with_controls_) {
+ GtkWidget* menu_bar = CreateMenuBar();
+ g_signal_connect(menu_bar, "size-allocate",
+ G_CALLBACK(&RootWindowGtk::MenubarSizeAllocated), this);
+
+ gtk_grid_attach(GTK_GRID(grid), menu_bar, 0, 0, 1, 1);
+
+ GtkWidget* toolbar = gtk_toolbar_new();
+ // Turn off the labels on the toolbar buttons.
+ gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS);
+ g_signal_connect(toolbar, "size-allocate",
+ G_CALLBACK(&RootWindowGtk::ToolbarSizeAllocated), this);
+
+ back_button_ = gtk_tool_button_new(
+ gtk_image_new_from_icon_name("go-previous", GTK_ICON_SIZE_MENU),
+ nullptr);
+ g_signal_connect(back_button_, "clicked",
+ G_CALLBACK(&RootWindowGtk::BackButtonClicked), this);
+ gtk_toolbar_insert(GTK_TOOLBAR(toolbar), back_button_, -1 /* append */);
+
+ forward_button_ = gtk_tool_button_new(
+ gtk_image_new_from_icon_name("go-next", GTK_ICON_SIZE_MENU), nullptr);
+ g_signal_connect(forward_button_, "clicked",
+ G_CALLBACK(&RootWindowGtk::ForwardButtonClicked), this);
+ gtk_toolbar_insert(GTK_TOOLBAR(toolbar), forward_button_, -1 /* append */);
+
+ reload_button_ = gtk_tool_button_new(
+ gtk_image_new_from_icon_name("view-refresh", GTK_ICON_SIZE_MENU),
+ nullptr);
+ g_signal_connect(reload_button_, "clicked",
+ G_CALLBACK(&RootWindowGtk::ReloadButtonClicked), this);
+ gtk_toolbar_insert(GTK_TOOLBAR(toolbar), reload_button_, -1 /* append */);
+
+ stop_button_ = gtk_tool_button_new(
+ gtk_image_new_from_icon_name("process-stop", GTK_ICON_SIZE_MENU),
+ nullptr);
+ g_signal_connect(stop_button_, "clicked",
+ G_CALLBACK(&RootWindowGtk::StopButtonClicked), this);
+ gtk_toolbar_insert(GTK_TOOLBAR(toolbar), stop_button_, -1 /* append */);
+
+ url_entry_ = gtk_entry_new();
+ g_signal_connect(url_entry_, "activate",
+ G_CALLBACK(&RootWindowGtk::URLEntryActivate), this);
+ g_signal_connect(url_entry_, "button-press-event",
+ G_CALLBACK(&RootWindowGtk::URLEntryButtonPress), this);
+
+ GtkToolItem* tool_item = gtk_tool_item_new();
+ gtk_container_add(GTK_CONTAINER(tool_item), url_entry_);
+ gtk_tool_item_set_expand(tool_item, TRUE);
+ gtk_toolbar_insert(GTK_TOOLBAR(toolbar), tool_item, -1); // append
+
+ gtk_grid_attach_next_to(GTK_GRID(grid), toolbar, menu_bar, GTK_POS_BOTTOM,
+ 1, 1);
+ }
+
+ // Realize (show) the GTK widget. This must be done before the browser is
+ // created because the underlying X11 Window is required. |browser_bounds_|
+ // will be set at this point based on the GTK *SizeAllocated signal callbacks.
+ Show(ShowNormal);
+
+ // Most window managers ignore requests for initial window positions (instead
+ // using a user-defined placement algorithm) and honor requests after the
+ // window has already been shown.
+ gtk_window_move(GTK_WINDOW(window_), x, y);
+
+ // Windowed browsers are parented to the X11 Window underlying the GtkWindow*
+ // and must be sized manually. The OSR GTK widget, on the other hand, can be
+ // added to the grid container for automatic layout-based sizing.
+ GtkWidget* parent = with_osr_ ? grid : window_;
+
+ // Set the Display associated with the browser.
+ ::Display* xdisplay = GDK_WINDOW_XDISPLAY(gtk_widget_get_window(window_));
+ CHECK(xdisplay);
+ if (with_osr_) {
+ static_cast<BrowserWindowOsrGtk*>(browser_window_.get())
+ ->set_xdisplay(xdisplay);
+ } else {
+ static_cast<BrowserWindowStdGtk*>(browser_window_.get())
+ ->set_xdisplay(xdisplay);
+ }
+
+ if (!is_popup_) {
+ // Create the browser window.
+ browser_window_->CreateBrowser(parent, browser_bounds_, settings, nullptr,
+ delegate_->GetRequestContext(this));
+ } else {
+ // With popups we already have a browser window. Parent the browser window
+ // to the root window and show it in the correct location.
+ browser_window_->ShowPopup(parent, browser_bounds_.x, browser_bounds_.y,
+ browser_bounds_.width, browser_bounds_.height);
+ }
+}
+
+void RootWindowGtk::OnBrowserCreated(CefRefPtr<CefBrowser> browser) {
+ REQUIRE_MAIN_THREAD();
+
+ // For popup browsers create the root window once the browser has been
+ // created.
+ if (is_popup_) {
+ CreateRootWindow(CefBrowserSettings(), false);
+ }
+
+ delegate_->OnBrowserCreated(this, browser);
+}
+
+void RootWindowGtk::OnBrowserWindowClosing() {
+ if (!CefCurrentlyOn(TID_UI)) {
+ CefPostTask(TID_UI,
+ base::BindOnce(&RootWindowGtk::OnBrowserWindowClosing, this));
+ return;
+ }
+
+ is_closing_ = true;
+}
+
+void RootWindowGtk::OnBrowserWindowDestroyed() {
+ REQUIRE_MAIN_THREAD();
+
+ browser_window_.reset();
+
+ if (!window_destroyed_) {
+ // The browser was destroyed first. This could be due to the use of
+ // off-screen rendering or execution of JavaScript window.close().
+ // Close the RootWindow.
+ Close(true);
+ }
+
+ NotifyDestroyedIfDone(false, true);
+}
+
+void RootWindowGtk::OnSetAddress(const std::string& url) {
+ REQUIRE_MAIN_THREAD();
+
+ if (url_entry_) {
+ ScopedGdkThreadsEnter scoped_gdk_threads;
+
+ std::string urlStr(url);
+ gtk_entry_set_text(GTK_ENTRY(url_entry_), urlStr.c_str());
+ }
+}
+
+void RootWindowGtk::OnSetTitle(const std::string& title) {
+ REQUIRE_MAIN_THREAD();
+
+ if (window_) {
+ ScopedGdkThreadsEnter scoped_gdk_threads;
+
+ std::string titleStr(title);
+ gtk_window_set_title(GTK_WINDOW(window_), titleStr.c_str());
+ }
+}
+
+void RootWindowGtk::OnSetFullscreen(bool fullscreen) {
+ REQUIRE_MAIN_THREAD();
+
+ CefRefPtr<CefBrowser> browser = GetBrowser();
+ if (browser) {
+ std::unique_ptr<window_test::WindowTestRunnerGtk> test_runner(
+ new window_test::WindowTestRunnerGtk());
+ if (fullscreen) {
+ test_runner->Maximize(browser);
+ } else {
+ test_runner->Restore(browser);
+ }
+ }
+}
+
+void RootWindowGtk::OnAutoResize(const CefSize& new_size) {
+ REQUIRE_MAIN_THREAD();
+
+ if (!window_) {
+ return;
+ }
+
+ ScopedGdkThreadsEnter scoped_gdk_threads;
+
+ GtkWindow* window = GTK_WINDOW(window_);
+ GdkWindow* gdk_window = gtk_widget_get_window(window_);
+
+ // Make sure the window isn't minimized or maximized.
+ if (IsWindowMaximized(window)) {
+ gtk_window_unmaximize(window);
+ } else {
+ gtk_window_present(window);
+ }
+
+ gdk_window_resize(gdk_window, new_size.width, new_size.height);
+}
+
+void RootWindowGtk::OnSetLoadingState(bool isLoading,
+ bool canGoBack,
+ bool canGoForward) {
+ REQUIRE_MAIN_THREAD();
+
+ if (with_controls_) {
+ ScopedGdkThreadsEnter scoped_gdk_threads;
+
+ gtk_widget_set_sensitive(GTK_WIDGET(stop_button_), isLoading);
+ gtk_widget_set_sensitive(GTK_WIDGET(reload_button_), !isLoading);
+ gtk_widget_set_sensitive(GTK_WIDGET(back_button_), canGoBack);
+ gtk_widget_set_sensitive(GTK_WIDGET(forward_button_), canGoForward);
+ }
+}
+
+void RootWindowGtk::OnSetDraggableRegions(
+ const std::vector<CefDraggableRegion>& regions) {
+ REQUIRE_MAIN_THREAD();
+ // TODO(cef): Implement support for draggable regions on this platform.
+}
+
+void RootWindowGtk::NotifyMoveOrResizeStarted() {
+ if (!CURRENTLY_ON_MAIN_THREAD()) {
+ MAIN_POST_CLOSURE(
+ base::BindOnce(&RootWindowGtk::NotifyMoveOrResizeStarted, this));
+ return;
+ }
+
+ // Called when size, position or stack order changes.
+ CefRefPtr<CefBrowser> browser = GetBrowser();
+ if (browser.get()) {
+ // Notify the browser of move/resize events so that:
+ // - Popup windows are displayed in the correct location and dismissed
+ // when the window moves.
+ // - Drag&drop areas are updated accordingly.
+ browser->GetHost()->NotifyMoveOrResizeStarted();
+ }
+}
+
+void RootWindowGtk::NotifySetFocus() {
+ if (!CURRENTLY_ON_MAIN_THREAD()) {
+ MAIN_POST_CLOSURE(base::BindOnce(&RootWindowGtk::NotifySetFocus, this));
+ return;
+ }
+
+ if (!browser_window_.get()) {
+ return;
+ }
+
+ browser_window_->SetFocus(true);
+ delegate_->OnRootWindowActivated(this);
+}
+
+void RootWindowGtk::NotifyVisibilityChange(bool show) {
+ if (!CURRENTLY_ON_MAIN_THREAD()) {
+ MAIN_POST_CLOSURE(
+ base::BindOnce(&RootWindowGtk::NotifyVisibilityChange, this, show));
+ return;
+ }
+
+ if (!browser_window_.get()) {
+ return;
+ }
+
+ if (show) {
+ browser_window_->Show();
+ } else {
+ browser_window_->Hide();
+ }
+}
+
+void RootWindowGtk::NotifyMenuBarHeight(int height) {
+ if (!CURRENTLY_ON_MAIN_THREAD()) {
+ MAIN_POST_CLOSURE(
+ base::BindOnce(&RootWindowGtk::NotifyMenuBarHeight, this, height));
+ return;
+ }
+
+ menubar_height_ = height;
+}
+
+void RootWindowGtk::NotifyContentBounds(int x, int y, int width, int height) {
+ if (!CURRENTLY_ON_MAIN_THREAD()) {
+ MAIN_POST_CLOSURE(base::BindOnce(&RootWindowGtk::NotifyContentBounds, this,
+ x, y, width, height));
+ return;
+ }
+
+ // Offset browser positioning by any controls that will appear in the client
+ // area.
+ const int ux_height = toolbar_height_ + menubar_height_;
+ const int browser_x = x;
+ const int browser_y = y + ux_height;
+ const int browser_width = width;
+ const int browser_height = height - ux_height;
+
+ // Size the browser window to match the GTK widget.
+ browser_bounds_ =
+ CefRect(browser_x, browser_y, browser_width, browser_height);
+ if (browser_window_.get()) {
+ browser_window_->SetBounds(browser_x, browser_y, browser_width,
+ browser_height);
+ }
+}
+
+void RootWindowGtk::NotifyLoadURL(const std::string& url) {
+ if (!CURRENTLY_ON_MAIN_THREAD()) {
+ MAIN_POST_CLOSURE(base::BindOnce(&RootWindowGtk::NotifyLoadURL, this, url));
+ return;
+ }
+
+ CefRefPtr<CefBrowser> browser = GetBrowser();
+ if (browser.get()) {
+ browser->GetMainFrame()->LoadURL(url);
+ }
+}
+
+void RootWindowGtk::NotifyButtonClicked(int id) {
+ if (!CURRENTLY_ON_MAIN_THREAD()) {
+ MAIN_POST_CLOSURE(
+ base::BindOnce(&RootWindowGtk::NotifyButtonClicked, this, id));
+ return;
+ }
+
+ CefRefPtr<CefBrowser> browser = GetBrowser();
+ if (!browser.get()) {
+ return;
+ }
+
+ switch (id) {
+ case IDC_NAV_BACK:
+ browser->GoBack();
+ break;
+ case IDC_NAV_FORWARD:
+ browser->GoForward();
+ break;
+ case IDC_NAV_RELOAD:
+ browser->Reload();
+ break;
+ case IDC_NAV_STOP:
+ browser->StopLoad();
+ break;
+ default:
+ NOTREACHED() << "id=" << id;
+ }
+}
+
+void RootWindowGtk::NotifyMenuItem(int id) {
+ if (!CURRENTLY_ON_MAIN_THREAD()) {
+ MAIN_POST_CLOSURE(base::BindOnce(&RootWindowGtk::NotifyMenuItem, this, id));
+ return;
+ }
+
+ // Run the test.
+ if (delegate_) {
+ delegate_->OnTest(this, id);
+ }
+}
+
+void RootWindowGtk::NotifyForceClose() {
+ if (!CefCurrentlyOn(TID_UI)) {
+ CefPostTask(TID_UI, base::BindOnce(&RootWindowGtk::NotifyForceClose, this));
+ return;
+ }
+
+ force_close_ = true;
+}
+
+void RootWindowGtk::NotifyCloseBrowser() {
+ if (!CURRENTLY_ON_MAIN_THREAD()) {
+ MAIN_POST_CLOSURE(base::BindOnce(&RootWindowGtk::NotifyCloseBrowser, this));
+ return;
+ }
+
+ CefRefPtr<CefBrowser> browser = GetBrowser();
+ if (browser) {
+ browser->GetHost()->CloseBrowser(false);
+ }
+}
+
+void RootWindowGtk::NotifyDestroyedIfDone(bool window_destroyed,
+ bool browser_destroyed) {
+ // Each call will to this method will set only one state flag.
+ DCHECK_EQ(1, window_destroyed + browser_destroyed);
+
+ if (!CURRENTLY_ON_MAIN_THREAD()) {
+ MAIN_POST_CLOSURE(base::BindOnce(&RootWindowGtk::NotifyDestroyedIfDone,
+ this, window_destroyed,
+ browser_destroyed));
+ return;
+ }
+
+ if (window_destroyed) {
+ window_destroyed_ = true;
+ }
+ if (browser_destroyed) {
+ browser_destroyed_ = true;
+ }
+
+ // Notify once both the window and the browser have been destroyed.
+ if (window_destroyed_ && browser_destroyed_) {
+ delegate_->OnRootWindowDestroyed(this);
+ }
+}
+
+// static
+gboolean RootWindowGtk::WindowFocusIn(GtkWidget* widget,
+ GdkEventFocus* event,
+ RootWindowGtk* self) {
+ REQUIRE_MAIN_THREAD();
+
+ if (event->in) {
+ self->NotifySetFocus();
+
+ // Return true for a windowed browser so that focus is not passed to GTK.
+ return self->with_osr_ ? FALSE : TRUE;
+ }
+
+ return FALSE;
+}
+
+// static
+gboolean RootWindowGtk::WindowState(GtkWidget* widget,
+ GdkEventWindowState* event,
+ RootWindowGtk* self) {
+ REQUIRE_MAIN_THREAD();
+
+ // Called when the root window is iconified or restored. Hide the browser
+ // window when the root window is iconified to reduce resource usage.
+ if (event->changed_mask & GDK_WINDOW_STATE_ICONIFIED) {
+ self->NotifyVisibilityChange(
+ !(event->new_window_state & GDK_WINDOW_STATE_ICONIFIED));
+ }
+
+ return TRUE;
+}
+
+// static
+gboolean RootWindowGtk::WindowConfigure(GtkWindow* window,
+ GdkEvent* event,
+ RootWindowGtk* self) {
+ REQUIRE_MAIN_THREAD();
+ self->NotifyMoveOrResizeStarted();
+ return FALSE; // Don't stop this message.
+}
+
+// static
+void RootWindowGtk::WindowDestroy(GtkWidget* widget, RootWindowGtk* self) {
+ // May be called on the main thread or the UI thread.
+ self->NotifyDestroyedIfDone(true, false);
+}
+
+// static
+gboolean RootWindowGtk::WindowDelete(GtkWidget* widget,
+ GdkEvent* event,
+ RootWindowGtk* self) {
+ REQUIRE_MAIN_THREAD();
+
+ // Called to query whether the root window should be closed.
+ if (self->force_close_) {
+ return FALSE; // Allow the close.
+ }
+
+ if (!self->is_closing_) {
+ // Notify the browser window that we would like to close it. This
+ // will result in a call to ClientHandler::DoClose() if the
+ // JavaScript 'onbeforeunload' event handler allows it.
+ self->NotifyCloseBrowser();
+
+ // Cancel the close.
+ return TRUE;
+ }
+
+ // Allow the close.
+ return FALSE;
+}
+
+// static
+void RootWindowGtk::GridSizeAllocated(GtkWidget* widget,
+ GtkAllocation* allocation,
+ RootWindowGtk* self) {
+ // May be called on the main thread and the UI thread.
+ self->NotifyContentBounds(allocation->x, allocation->y, allocation->width,
+ allocation->height);
+}
+
+// static
+void RootWindowGtk::MenubarSizeAllocated(GtkWidget* widget,
+ GtkAllocation* allocation,
+ RootWindowGtk* self) {
+ // May be called on the main thread and the UI thread.
+ self->NotifyMenuBarHeight(allocation->height);
+}
+
+// static
+gboolean RootWindowGtk::MenuItemActivated(GtkWidget* widget,
+ RootWindowGtk* self) {
+ REQUIRE_MAIN_THREAD();
+
+ // Retrieve the menu ID set in AddMenuEntry.
+ int id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), kMenuIdKey));
+ self->NotifyMenuItem(id);
+
+ return FALSE; // Don't stop this message.
+}
+
+// static
+void RootWindowGtk::ToolbarSizeAllocated(GtkWidget* widget,
+ GtkAllocation* allocation,
+ RootWindowGtk* self) {
+ self->toolbar_height_ = allocation->height;
+}
+
+// static
+void RootWindowGtk::BackButtonClicked(GtkButton* button, RootWindowGtk* self) {
+ REQUIRE_MAIN_THREAD();
+ self->NotifyButtonClicked(IDC_NAV_BACK);
+}
+
+// static
+void RootWindowGtk::ForwardButtonClicked(GtkButton* button,
+ RootWindowGtk* self) {
+ REQUIRE_MAIN_THREAD();
+ self->NotifyButtonClicked(IDC_NAV_FORWARD);
+}
+
+// static
+void RootWindowGtk::StopButtonClicked(GtkButton* button, RootWindowGtk* self) {
+ REQUIRE_MAIN_THREAD();
+ self->NotifyButtonClicked(IDC_NAV_STOP);
+}
+
+// static
+void RootWindowGtk::ReloadButtonClicked(GtkButton* button,
+ RootWindowGtk* self) {
+ REQUIRE_MAIN_THREAD();
+ self->NotifyButtonClicked(IDC_NAV_RELOAD);
+}
+
+// static
+void RootWindowGtk::URLEntryActivate(GtkEntry* entry, RootWindowGtk* self) {
+ REQUIRE_MAIN_THREAD();
+ const gchar* url = gtk_entry_get_text(entry);
+ self->NotifyLoadURL(std::string(url));
+}
+
+// static
+gboolean RootWindowGtk::URLEntryButtonPress(GtkWidget* widget,
+ GdkEventButton* event,
+ RootWindowGtk* self) {
+ REQUIRE_MAIN_THREAD();
+
+ // Give focus to the GTK window. This is a work-around for bad focus-related
+ // interaction between the root window managed by GTK and the browser managed
+ // by X11.
+ GtkWidget* window = gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW);
+ GdkWindow* gdk_window = gtk_widget_get_window(window);
+ ::Display* xdisplay = GDK_WINDOW_XDISPLAY(gdk_window);
+ ::Window xwindow = GDK_WINDOW_XID(gdk_window);
+
+ // Retrieve the atoms required by the below XSendEvent call.
+ const char* kAtoms[] = {"WM_PROTOCOLS", "WM_TAKE_FOCUS"};
+ Atom atoms[2];
+ int result =
+ XInternAtoms(xdisplay, const_cast<char**>(kAtoms), 2, false, atoms);
+ if (!result) {
+ NOTREACHED();
+ }
+
+ XEvent e;
+ e.type = ClientMessage;
+ e.xany.display = xdisplay;
+ e.xany.window = xwindow;
+ e.xclient.format = 32;
+ e.xclient.message_type = atoms[0];
+ e.xclient.data.l[0] = atoms[1];
+ e.xclient.data.l[1] = CurrentTime;
+ e.xclient.data.l[2] = 0;
+ e.xclient.data.l[3] = 0;
+ e.xclient.data.l[4] = 0;
+
+ XSendEvent(xdisplay, xwindow, false, 0, &e);
+
+ return FALSE;
+}
+
+GtkWidget* RootWindowGtk::CreateMenuBar() {
+ GtkWidget* menu_bar = gtk_menu_bar_new();
+
+ // Create the test menu.
+ GtkWidget* test_menu = CreateMenu(menu_bar, "Tests");
+ AddMenuEntry(test_menu, "Get Source", ID_TESTS_GETSOURCE);
+ AddMenuEntry(test_menu, "Get Text", ID_TESTS_GETTEXT);
+ AddMenuEntry(test_menu, "New Window", ID_TESTS_WINDOW_NEW);
+ AddMenuEntry(test_menu, "Popup Window", ID_TESTS_WINDOW_POPUP);
+ AddMenuEntry(test_menu, "Request", ID_TESTS_REQUEST);
+ AddMenuEntry(test_menu, "Zoom In", ID_TESTS_ZOOM_IN);
+ AddMenuEntry(test_menu, "Zoom Out", ID_TESTS_ZOOM_OUT);
+ AddMenuEntry(test_menu, "Zoom Reset", ID_TESTS_ZOOM_RESET);
+ if (with_osr_) {
+ AddMenuEntry(test_menu, "Set FPS", ID_TESTS_OSR_FPS);
+ AddMenuEntry(test_menu, "Set Scale Factor", ID_TESTS_OSR_DSF);
+ }
+ AddMenuEntry(test_menu, "Begin Tracing", ID_TESTS_TRACING_BEGIN);
+ AddMenuEntry(test_menu, "End Tracing", ID_TESTS_TRACING_END);
+ AddMenuEntry(test_menu, "Print", ID_TESTS_PRINT);
+ AddMenuEntry(test_menu, "Print to PDF", ID_TESTS_PRINT_TO_PDF);
+ AddMenuEntry(test_menu, "Mute Audio", ID_TESTS_MUTE_AUDIO);
+ AddMenuEntry(test_menu, "Unmute Audio", ID_TESTS_UNMUTE_AUDIO);
+ AddMenuEntry(test_menu, "Other Tests", ID_TESTS_OTHER_TESTS);
+
+ return menu_bar;
+}
+
+GtkWidget* RootWindowGtk::CreateMenu(GtkWidget* menu_bar, const char* text) {
+ GtkWidget* menu_widget = gtk_menu_new();
+ GtkWidget* menu_header = gtk_menu_item_new_with_label(text);
+ gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_header), menu_widget);
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu_bar), menu_header);
+ return menu_widget;
+}
+
+GtkWidget* RootWindowGtk::AddMenuEntry(GtkWidget* menu_widget,
+ const char* text,
+ int id) {
+ GtkWidget* entry = gtk_menu_item_new_with_label(text);
+ g_signal_connect(entry, "activate",
+ G_CALLBACK(&RootWindowGtk::MenuItemActivated), this);
+
+ // Set the menu ID that will be retrieved in MenuItemActivated.
+ g_object_set_data(G_OBJECT(entry), kMenuIdKey, GINT_TO_POINTER(id));
+
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu_widget), entry);
+ return entry;
+}
+
+} // namespace client
diff --git a/tests/cefclient/browser/root_window_gtk.h b/tests/cefclient/browser/root_window_gtk.h
new file mode 100644
index 00000000..6af0c48b
--- /dev/null
+++ b/tests/cefclient/browser/root_window_gtk.h
@@ -0,0 +1,167 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_ROOT_WINDOW_GTK_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_ROOT_WINDOW_GTK_H_
+#pragma once
+
+#include <gtk/gtk.h>
+#include <memory>
+#include <string>
+
+#include "tests/cefclient/browser/browser_window.h"
+#include "tests/cefclient/browser/root_window.h"
+
+namespace client {
+
+// GTK implementation of a top-level native window in the browser process.
+// The methods of this class must be called on the main thread unless otherwise
+// indicated.
+class RootWindowGtk : public RootWindow, public BrowserWindow::Delegate {
+ public:
+ // Constructor may be called on any thread.
+ RootWindowGtk();
+ ~RootWindowGtk();
+
+ // RootWindow methods.
+ void Init(RootWindow::Delegate* delegate,
+ std::unique_ptr<RootWindowConfig> config,
+ const CefBrowserSettings& settings) override;
+ void InitAsPopup(RootWindow::Delegate* delegate,
+ bool with_controls,
+ bool with_osr,
+ const CefPopupFeatures& popupFeatures,
+ CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient>& client,
+ CefBrowserSettings& settings) override;
+ void Show(ShowMode mode) override;
+ void Hide() override;
+ void SetBounds(int x, int y, size_t width, size_t height) override;
+ void Close(bool force) override;
+ void SetDeviceScaleFactor(float device_scale_factor) override;
+ float GetDeviceScaleFactor() const override;
+ CefRefPtr<CefBrowser> GetBrowser() const override;
+ ClientWindowHandle GetWindowHandle() const override;
+ bool WithWindowlessRendering() const override;
+ bool WithExtension() const override;
+
+ private:
+ void CreateBrowserWindow(const std::string& startup_url);
+ void CreateRootWindow(const CefBrowserSettings& settings,
+ bool initially_hidden);
+
+ // BrowserWindow::Delegate methods.
+ void OnBrowserCreated(CefRefPtr<CefBrowser> browser) override;
+ void OnBrowserWindowClosing() override;
+ void OnBrowserWindowDestroyed() override;
+ void OnSetAddress(const std::string& url) override;
+ void OnSetTitle(const std::string& title) override;
+ void OnSetFullscreen(bool fullscreen) override;
+ void OnAutoResize(const CefSize& new_size) override;
+ void OnSetLoadingState(bool isLoading,
+ bool canGoBack,
+ bool canGoForward) override;
+ void OnSetDraggableRegions(
+ const std::vector<CefDraggableRegion>& regions) override;
+
+ void NotifyMoveOrResizeStarted();
+ void NotifySetFocus();
+ void NotifyVisibilityChange(bool show);
+ void NotifyMenuBarHeight(int height);
+ void NotifyContentBounds(int x, int y, int width, int height);
+ void NotifyLoadURL(const std::string& url);
+ void NotifyButtonClicked(int id);
+ void NotifyMenuItem(int id);
+ void NotifyForceClose();
+ void NotifyCloseBrowser();
+ void NotifyDestroyedIfDone(bool window_destroyed, bool browser_destroyed);
+
+ GtkWidget* CreateMenuBar();
+ GtkWidget* CreateMenu(GtkWidget* menu_bar, const char* text);
+ GtkWidget* AddMenuEntry(GtkWidget* menu_widget, const char* text, int id);
+
+ // Signal handlers for the top-level GTK window.
+ static gboolean WindowFocusIn(GtkWidget* widget,
+ GdkEventFocus* event,
+ RootWindowGtk* self);
+ static gboolean WindowState(GtkWidget* widget,
+ GdkEventWindowState* event,
+ RootWindowGtk* self);
+ static gboolean WindowConfigure(GtkWindow* window,
+ GdkEvent* event,
+ RootWindowGtk* self);
+ static void WindowDestroy(GtkWidget* widget, RootWindowGtk* self);
+ static gboolean WindowDelete(GtkWidget* widget,
+ GdkEvent* event,
+ RootWindowGtk* self);
+
+ // Signal handlers for the GTK Vbox containing all UX elements.
+ static void GridSizeAllocated(GtkWidget* widget,
+ GtkAllocation* allocation,
+ RootWindowGtk* self);
+
+ // Signal handlers for the GTK menu bar.
+ static void MenubarSizeAllocated(GtkWidget* widget,
+ GtkAllocation* allocation,
+ RootWindowGtk* self);
+ static gboolean MenuItemActivated(GtkWidget* widget, RootWindowGtk* self);
+
+ // Signal handlers for the GTK toolbar.
+ static void ToolbarSizeAllocated(GtkWidget* widget,
+ GtkAllocation* allocation,
+ RootWindowGtk* self);
+ static void BackButtonClicked(GtkButton* button, RootWindowGtk* self);
+ static void ForwardButtonClicked(GtkButton* button, RootWindowGtk* self);
+ static void StopButtonClicked(GtkButton* button, RootWindowGtk* self);
+ static void ReloadButtonClicked(GtkButton* button, RootWindowGtk* self);
+
+ // Signal handlers for the GTK URL entry field.
+ static void URLEntryActivate(GtkEntry* entry, RootWindowGtk* self);
+ static gboolean URLEntryButtonPress(GtkWidget* widget,
+ GdkEventButton* event,
+ RootWindowGtk* self);
+
+ // After initialization all members are only accessed on the main thread.
+ // Members set during initialization.
+ bool with_controls_;
+ bool always_on_top_;
+ bool with_osr_;
+ bool with_extension_;
+ bool is_popup_;
+ CefRect start_rect_;
+ std::unique_ptr<BrowserWindow> browser_window_;
+ bool initialized_;
+
+ // Main window.
+ GtkWidget* window_;
+
+ // Buttons.
+ GtkToolItem* back_button_;
+ GtkToolItem* forward_button_;
+ GtkToolItem* reload_button_;
+ GtkToolItem* stop_button_;
+
+ // URL text field.
+ GtkWidget* url_entry_;
+
+ // Height of UX controls that affect browser window placement.
+ int toolbar_height_;
+ int menubar_height_;
+
+ CefRect browser_bounds_;
+
+ bool window_destroyed_;
+ bool browser_destroyed_;
+
+ // Members only accessed on the UI thread because they're needed for
+ // WindowDelete.
+ bool force_close_;
+ bool is_closing_;
+
+ DISALLOW_COPY_AND_ASSIGN(RootWindowGtk);
+};
+
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_ROOT_WINDOW_GTK_H_
diff --git a/tests/cefclient/browser/root_window_mac.h b/tests/cefclient/browser/root_window_mac.h
new file mode 100644
index 00000000..7a5d4355
--- /dev/null
+++ b/tests/cefclient/browser/root_window_mac.h
@@ -0,0 +1,78 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_ROOT_WINDOW_MAC_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_ROOT_WINDOW_MAC_H_
+#pragma once
+
+#include <memory>
+#include <string>
+
+#include "tests/cefclient/browser/browser_window.h"
+#include "tests/cefclient/browser/root_window.h"
+
+namespace client {
+
+class RootWindowMacImpl;
+
+// OS X implementation of a top-level native window in the browser process.
+// The methods of this class must be called on the main thread unless otherwise
+// indicated.
+class RootWindowMac : public RootWindow, public BrowserWindow::Delegate {
+ public:
+ // Constructor may be called on any thread.
+ RootWindowMac();
+ ~RootWindowMac();
+
+ BrowserWindow* browser_window() const;
+ RootWindow::Delegate* delegate() const;
+
+ // RootWindow methods.
+ void Init(RootWindow::Delegate* delegate,
+ std::unique_ptr<RootWindowConfig> config,
+ const CefBrowserSettings& settings) override;
+ void InitAsPopup(RootWindow::Delegate* delegate,
+ bool with_controls,
+ bool with_osr,
+ const CefPopupFeatures& popupFeatures,
+ CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient>& client,
+ CefBrowserSettings& settings) override;
+ void Show(ShowMode mode) override;
+ void Hide() override;
+ void SetBounds(int x, int y, size_t width, size_t height) override;
+ void Close(bool force) override;
+ void SetDeviceScaleFactor(float device_scale_factor) override;
+ float GetDeviceScaleFactor() const override;
+ CefRefPtr<CefBrowser> GetBrowser() const override;
+ ClientWindowHandle GetWindowHandle() const override;
+ bool WithWindowlessRendering() const override;
+ bool WithExtension() const override;
+
+ // BrowserWindow::Delegate methods.
+ void OnBrowserCreated(CefRefPtr<CefBrowser> browser) override;
+ void OnBrowserWindowDestroyed() override;
+ void OnSetAddress(const std::string& url) override;
+ void OnSetTitle(const std::string& title) override;
+ void OnSetFullscreen(bool fullscreen) override;
+ void OnAutoResize(const CefSize& new_size) override;
+ void OnSetLoadingState(bool isLoading,
+ bool canGoBack,
+ bool canGoForward) override;
+ void OnSetDraggableRegions(
+ const std::vector<CefDraggableRegion>& regions) override;
+
+ void OnNativeWindowClosed();
+
+ private:
+ CefRefPtr<RootWindowMacImpl> impl_;
+
+ DISALLOW_COPY_AND_ASSIGN(RootWindowMac);
+
+ friend class RootWindowMacImpl;
+};
+
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_ROOT_WINDOW_MAC_H_
diff --git a/tests/cefclient/browser/root_window_mac.mm b/tests/cefclient/browser/root_window_mac.mm
new file mode 100644
index 00000000..1b8c8e47
--- /dev/null
+++ b/tests/cefclient/browser/root_window_mac.mm
@@ -0,0 +1,1108 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/root_window_mac.h"
+
+#include <Cocoa/Cocoa.h>
+
+#include "include/base/cef_callback.h"
+#include "include/cef_app.h"
+#include "include/cef_application_mac.h"
+#include "include/views/cef_display.h"
+#include "tests/cefclient/browser/browser_window_osr_mac.h"
+#include "tests/cefclient/browser/browser_window_std_mac.h"
+#include "tests/cefclient/browser/client_prefs.h"
+#include "tests/cefclient/browser/main_context.h"
+#include "tests/cefclient/browser/temp_window.h"
+#include "tests/cefclient/browser/window_test_runner_mac.h"
+#include "tests/shared/browser/main_message_loop.h"
+#include "tests/shared/common/client_switches.h"
+
+// Receives notifications from controls and the browser window. Will delete
+// itself when done.
+@interface RootWindowDelegate : NSObject <NSWindowDelegate> {
+ @private
+ NSWindow* window_;
+ client::RootWindowMac* root_window_;
+ std::optional<CefRect> last_visible_bounds_;
+ bool force_close_;
+}
+
+@property(nonatomic, readonly) client::RootWindowMac* root_window;
+@property(nonatomic, readwrite) std::optional<CefRect> last_visible_bounds;
+@property(nonatomic, readwrite) bool force_close;
+
+- (id)initWithWindow:(NSWindow*)window
+ andRootWindow:(client::RootWindowMac*)root_window;
+- (IBAction)goBack:(id)sender;
+- (IBAction)goForward:(id)sender;
+- (IBAction)reload:(id)sender;
+- (IBAction)stopLoading:(id)sender;
+- (IBAction)takeURLStringValueFrom:(NSTextField*)sender;
+@end // @interface RootWindowDelegate
+
+namespace client {
+
+namespace {
+
+// Sizes for URL bar layout.
+#define BUTTON_HEIGHT 22
+#define BUTTON_WIDTH 72
+#define BUTTON_MARGIN 8
+#define URLBAR_HEIGHT 32
+
+NSButton* MakeButton(NSRect* rect, NSString* title, NSView* parent) {
+ NSButton* button = [[NSButton alloc] initWithFrame:*rect];
+#if !__has_feature(objc_arc)
+ [button autorelease];
+#endif // !__has_feature(objc_arc)
+ [button setTitle:title];
+ [button setBezelStyle:NSSmallSquareBezelStyle];
+ [button setAutoresizingMask:(NSViewMaxXMargin | NSViewMinYMargin)];
+ [parent addSubview:button];
+ rect->origin.x += BUTTON_WIDTH;
+ return button;
+}
+
+// Returns the current DIP screen bounds for a visible window in the
+// restored position, or nullopt if the window is currently minimized or
+// fullscreen.
+std::optional<CefRect> GetWindowBoundsInScreen(NSWindow* window) {
+ if ([window isMiniaturized] or [window isZoomed]) {
+ return std::nullopt;
+ }
+
+ auto screen = [window screen];
+ if (screen == nil) {
+ screen = [NSScreen mainScreen];
+ }
+
+ const auto bounds = [window frame];
+ const auto screen_bounds = [screen frame];
+
+ if (NSEqualRects(bounds, screen_bounds)) {
+ // Don't include windows that are transitioning to fullscreen.
+ return std::nullopt;
+ }
+
+ CefRect dip_bounds{static_cast<int>(bounds.origin.x),
+ static_cast<int>(bounds.origin.y),
+ static_cast<int>(bounds.size.width),
+ static_cast<int>(bounds.size.height)};
+
+ // Convert from macOS coordinates (bottom-left origin) to DIP coordinates
+ // (top-left origin).
+ dip_bounds.y = static_cast<int>(screen_bounds.size.height) -
+ dip_bounds.height - dip_bounds.y;
+
+ return dip_bounds;
+}
+
+// Keep the frame bounds inside the display work area.
+NSRect ClampNSBoundsToWorkArea(const NSRect& frame_bounds,
+ const CefRect& display_bounds,
+ const CefRect& work_area) {
+ NSRect bounds = frame_bounds;
+
+ // Convert from DIP coordinates (top-left origin) to macOS coordinates
+ // (bottom-left origin).
+ const int work_area_y =
+ display_bounds.height - work_area.height - work_area.y;
+
+ if (bounds.size.width > work_area.width) {
+ bounds.size.width = work_area.width;
+ }
+ if (bounds.size.height > work_area.height) {
+ bounds.size.height = work_area.height;
+ }
+
+ if (bounds.origin.x < work_area.x) {
+ bounds.origin.x = work_area.x;
+ } else if (bounds.origin.x + bounds.size.width >=
+ work_area.x + work_area.width) {
+ bounds.origin.x = work_area.x + work_area.width - bounds.size.width;
+ }
+
+ if (bounds.origin.y < work_area_y) {
+ bounds.origin.y = work_area_y;
+ } else if (bounds.origin.y + bounds.size.height >=
+ work_area_y + work_area.height) {
+ bounds.origin.y = work_area_y + work_area.height - bounds.size.height;
+ }
+
+ return bounds;
+}
+
+// Get frame and content area rects matching the input DIP screen bounds. The
+// resulting window frame will be kept inside the closest display work area. If
+// |input_content_bounds| is true the input size is used for the content area
+// and the input origin is used for the frame. Otherwise, both input size and
+// origin are used for the frame.
+void GetNSBoundsInDisplay(const CefRect& dip_bounds,
+ bool input_content_bounds,
+ NSWindowStyleMask style_mask,
+ NSRect& frame_rect,
+ NSRect& content_rect) {
+ // Identify the closest display.
+ auto display =
+ CefDisplay::GetDisplayMatchingBounds(dip_bounds,
+ /*input_pixel_coords=*/false);
+ const auto display_bounds = display->GetBounds();
+ const auto display_work_area = display->GetWorkArea();
+
+ // Convert from DIP coordinates (top-left origin) to macOS coordinates
+ // (bottom-left origin).
+ NSRect requested_rect = NSMakeRect(dip_bounds.x, dip_bounds.y,
+ dip_bounds.width, dip_bounds.height);
+ requested_rect.origin.y = display_bounds.height - requested_rect.size.height -
+ requested_rect.origin.y;
+
+ // Calculate the equivalent frame and content bounds.
+ if (input_content_bounds) {
+ // Compute frame rect from content rect. Keep the requested origin.
+ content_rect = requested_rect;
+ frame_rect = [NSWindow frameRectForContentRect:content_rect
+ styleMask:style_mask];
+ frame_rect.origin = requested_rect.origin;
+ } else {
+ // Compute content rect from frame rect.
+ frame_rect = requested_rect;
+ content_rect = [NSWindow contentRectForFrameRect:frame_rect
+ styleMask:style_mask];
+ }
+
+ // Keep the frame inside the display work area.
+ const NSRect new_frame_rect =
+ ClampNSBoundsToWorkArea(frame_rect, display_bounds, display_work_area);
+ if (!NSEqualRects(frame_rect, new_frame_rect)) {
+ frame_rect = new_frame_rect;
+ content_rect = [NSWindow contentRectForFrameRect:frame_rect
+ styleMask:style_mask];
+ }
+}
+
+} // namespace
+
+class RootWindowMacImpl
+ : public base::RefCountedThreadSafe<RootWindowMacImpl, DeleteOnMainThread> {
+ public:
+ RootWindowMacImpl(RootWindowMac& root_window);
+ ~RootWindowMacImpl();
+
+ // Called by RootWindowDelegate after the associated NSWindow has been
+ // closed.
+ void OnNativeWindowClosed();
+
+ void CreateBrowserWindow(const std::string& startup_url);
+ void CreateRootWindow(const CefBrowserSettings& settings,
+ bool initially_hidden);
+
+ // RootWindow methods.
+ void Init(RootWindow::Delegate* delegate,
+ std::unique_ptr<RootWindowConfig> config,
+ const CefBrowserSettings& settings);
+ void InitAsPopup(RootWindow::Delegate* delegate,
+ bool with_controls,
+ bool with_osr,
+ const CefPopupFeatures& popupFeatures,
+ CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient>& client,
+ CefBrowserSettings& settings);
+ void Show(RootWindow::ShowMode mode);
+ void Hide();
+ void SetBounds(int x, int y, size_t width, size_t height);
+ void Close(bool force);
+ void SetDeviceScaleFactor(float device_scale_factor);
+ float GetDeviceScaleFactor() const;
+ CefRefPtr<CefBrowser> GetBrowser() const;
+ ClientWindowHandle GetWindowHandle() const;
+ bool WithWindowlessRendering() const;
+ bool WithExtension() const;
+
+ // BrowserWindow::Delegate methods.
+ void OnBrowserCreated(CefRefPtr<CefBrowser> browser);
+ void OnBrowserWindowDestroyed();
+ void OnSetAddress(const std::string& url);
+ void OnSetTitle(const std::string& title);
+ void OnSetFullscreen(bool fullscreen);
+ void OnAutoResize(const CefSize& new_size);
+ void OnSetLoadingState(bool isLoading, bool canGoBack, bool canGoForward);
+ void OnSetDraggableRegions(const std::vector<CefDraggableRegion>& regions);
+
+ void NotifyDestroyedIfDone();
+
+ // After initialization all members are only accessed on the main thread.
+ // Members set during initialization.
+ RootWindowMac& root_window_;
+ bool with_controls_ = false;
+ bool with_osr_ = false;
+ bool with_extension_ = false;
+ bool is_popup_ = false;
+ CefRect initial_bounds_;
+ cef_show_state_t initial_show_state_ = CEF_SHOW_STATE_NORMAL;
+ std::unique_ptr<BrowserWindow> browser_window_;
+ bool initialized_ = false;
+
+ // Main window.
+ NSWindow* window_ = nil;
+ RootWindowDelegate* window_delegate_ = nil;
+
+ // Buttons.
+ NSButton* back_button_ = nil;
+ NSButton* forward_button_ = nil;
+ NSButton* reload_button_ = nil;
+ NSButton* stop_button_ = nil;
+
+ // URL text field.
+ NSTextField* url_textfield_ = nil;
+
+ bool window_destroyed_ = false;
+ bool browser_destroyed_ = false;
+};
+
+RootWindowMacImpl::RootWindowMacImpl(RootWindowMac& root_window)
+ : root_window_(root_window) {}
+
+RootWindowMacImpl::~RootWindowMacImpl() {
+ REQUIRE_MAIN_THREAD();
+
+ // The window and browser should already have been destroyed.
+ DCHECK(window_destroyed_);
+ DCHECK(browser_destroyed_);
+}
+
+void RootWindowMacImpl::Init(RootWindow::Delegate* delegate,
+ std::unique_ptr<RootWindowConfig> config,
+ const CefBrowserSettings& settings) {
+ DCHECK(!initialized_);
+
+ with_controls_ = config->with_controls;
+ with_osr_ = config->with_osr;
+ with_extension_ = config->with_extension;
+
+ if (!config->bounds.IsEmpty()) {
+ // Initial state was specified via the config object.
+ initial_bounds_ = config->bounds;
+ initial_show_state_ = config->show_state;
+ } else {
+ // Initial state may be specified via the command-line or global
+ // preferences.
+ std::optional<CefRect> bounds;
+ if (prefs::LoadWindowRestorePreferences(initial_show_state_, bounds) &&
+ bounds) {
+ initial_bounds_ = *bounds;
+ }
+ }
+
+ CreateBrowserWindow(config->url);
+
+ initialized_ = true;
+
+ CreateRootWindow(settings, config->initially_hidden);
+}
+
+void RootWindowMacImpl::InitAsPopup(RootWindow::Delegate* delegate,
+ bool with_controls,
+ bool with_osr,
+ const CefPopupFeatures& popupFeatures,
+ CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient>& client,
+ CefBrowserSettings& settings) {
+ DCHECK(delegate);
+ DCHECK(!initialized_);
+
+ with_controls_ = with_controls;
+ with_osr_ = with_osr;
+ is_popup_ = true;
+
+ if (popupFeatures.xSet) {
+ initial_bounds_.x = popupFeatures.x;
+ }
+ if (popupFeatures.ySet) {
+ initial_bounds_.y = popupFeatures.y;
+ }
+ if (popupFeatures.widthSet) {
+ initial_bounds_.width = popupFeatures.width;
+ }
+ if (popupFeatures.heightSet) {
+ initial_bounds_.height = popupFeatures.height;
+ }
+
+ CreateBrowserWindow(std::string());
+
+ initialized_ = true;
+
+ // The new popup is initially parented to a temporary window. The native root
+ // window will be created after the browser is created and the popup window
+ // will be re-parented to it at that time.
+ browser_window_->GetPopupConfig(TempWindow::GetWindowHandle(), windowInfo,
+ client, settings);
+}
+
+void RootWindowMacImpl::Show(RootWindow::ShowMode mode) {
+ REQUIRE_MAIN_THREAD();
+
+ if (!window_) {
+ return;
+ }
+
+ const bool is_visible = [window_ isVisible];
+ const bool is_minimized = [window_ isMiniaturized];
+ const bool is_maximized = [window_ isZoomed];
+
+ if ((mode == RootWindow::ShowMinimized && is_minimized) ||
+ (mode == RootWindow::ShowMaximized && is_maximized) ||
+ (mode == RootWindow::ShowNormal && is_visible)) {
+ // The window is already in the desired state.
+ return;
+ }
+
+ // Undo the previous state since it's not the desired state.
+ if (is_minimized) {
+ [window_ deminiaturize:nil];
+ } else if (is_maximized) {
+ [window_ performZoom:nil];
+ }
+
+ // Window visibility may change after (for example) deminiaturizing the
+ // window.
+ if (![window_ isVisible]) {
+ [window_ makeKeyAndOrderFront:nil];
+ }
+
+ if (mode == RootWindow::ShowMinimized) {
+ [window_ performMiniaturize:nil];
+ } else if (mode == RootWindow::ShowMaximized) {
+ [window_ performZoom:nil];
+ }
+}
+
+void RootWindowMacImpl::Hide() {
+ REQUIRE_MAIN_THREAD();
+
+ if (!window_) {
+ return;
+ }
+
+ // Undo miniaturization, if any, so the window will actually be hidden.
+ if ([window_ isMiniaturized]) {
+ [window_ deminiaturize:nil];
+ }
+
+ // Hide the window.
+ [window_ orderOut:nil];
+}
+
+void RootWindowMacImpl::SetBounds(int x, int y, size_t width, size_t height) {
+ REQUIRE_MAIN_THREAD();
+
+ if (!window_) {
+ return;
+ }
+
+ const CefRect dip_bounds(x, y, static_cast<int>(width),
+ static_cast<int>(height));
+
+ // Calculate the equivalent frame and content area bounds.
+ NSRect frame_rect, content_rect;
+ GetNSBoundsInDisplay(dip_bounds, /*input_content_bounds=*/true,
+ [window_ styleMask], frame_rect, content_rect);
+
+ [window_ setFrame:frame_rect display:YES];
+}
+
+void RootWindowMacImpl::Close(bool force) {
+ REQUIRE_MAIN_THREAD();
+
+ if (window_) {
+ static_cast<RootWindowDelegate*>([window_ delegate]).force_close = force;
+ [window_ performClose:nil];
+ window_destroyed_ = true;
+ }
+}
+
+void RootWindowMacImpl::SetDeviceScaleFactor(float device_scale_factor) {
+ REQUIRE_MAIN_THREAD();
+
+ if (browser_window_ && with_osr_) {
+ browser_window_->SetDeviceScaleFactor(device_scale_factor);
+ }
+}
+
+float RootWindowMacImpl::GetDeviceScaleFactor() const {
+ REQUIRE_MAIN_THREAD();
+
+ if (browser_window_ && with_osr_) {
+ return browser_window_->GetDeviceScaleFactor();
+ }
+
+ NOTREACHED();
+ return 0.0f;
+}
+
+CefRefPtr<CefBrowser> RootWindowMacImpl::GetBrowser() const {
+ REQUIRE_MAIN_THREAD();
+
+ if (browser_window_) {
+ return browser_window_->GetBrowser();
+ }
+ return nullptr;
+}
+
+ClientWindowHandle RootWindowMacImpl::GetWindowHandle() const {
+ REQUIRE_MAIN_THREAD();
+ return CAST_NSVIEW_TO_CEF_WINDOW_HANDLE([window_ contentView]);
+}
+
+bool RootWindowMacImpl::WithWindowlessRendering() const {
+ REQUIRE_MAIN_THREAD();
+ return with_osr_;
+}
+
+bool RootWindowMacImpl::WithExtension() const {
+ REQUIRE_MAIN_THREAD();
+ return with_extension_;
+}
+
+void RootWindowMacImpl::OnNativeWindowClosed() {
+ window_ = nil;
+ window_destroyed_ = true;
+ NotifyDestroyedIfDone();
+}
+
+void RootWindowMacImpl::CreateBrowserWindow(const std::string& startup_url) {
+ if (with_osr_) {
+ OsrRendererSettings settings = {};
+ MainContext::Get()->PopulateOsrSettings(&settings);
+ browser_window_.reset(new BrowserWindowOsrMac(&root_window_, with_controls_,
+ startup_url, settings));
+ } else {
+ browser_window_.reset(
+ new BrowserWindowStdMac(&root_window_, with_controls_, startup_url));
+ }
+}
+
+void RootWindowMacImpl::CreateRootWindow(const CefBrowserSettings& settings,
+ bool initially_hidden) {
+ REQUIRE_MAIN_THREAD();
+ DCHECK(!window_);
+
+ // TODO(port): If no x,y position is specified the window will always appear
+ // in the upper-left corner. Maybe there's a better default place to put it?
+ CefRect dip_bounds = initial_bounds_;
+
+ // TODO(port): Also, maybe there's a better way to choose the default size.
+ if (dip_bounds.width <= 0) {
+ dip_bounds.width = 800;
+ }
+ if (dip_bounds.height <= 0) {
+ dip_bounds.height = 600;
+ }
+
+ // For popups, the requested bounds are for the content area and the requested
+ // origin is for the window.
+ if (is_popup_ && with_controls_) {
+ dip_bounds.height += URLBAR_HEIGHT;
+ }
+
+ const NSWindowStyleMask style_mask =
+ (NSWindowStyleMaskTitled | NSWindowStyleMaskClosable |
+ NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable);
+
+ // Calculate the equivalent frame and content area bounds.
+ NSRect frame_rect, content_rect;
+ GetNSBoundsInDisplay(dip_bounds, /*input_content_bounds=*/is_popup_,
+ style_mask, frame_rect, content_rect);
+
+ // The CEF framework library is loaded at runtime so we need to use this
+ // mechanism for retrieving the class.
+ Class window_class = NSClassFromString(@"UnderlayOpenGLHostingWindow");
+ CHECK(window_class);
+
+ // Create the main window.
+ window_ = [[window_class alloc] initWithContentRect:content_rect
+ styleMask:style_mask
+ backing:NSBackingStoreBuffered
+ defer:NO];
+ [window_ setTitle:@"cefclient"];
+ // No dark mode, please
+ window_.appearance = [NSAppearance appearanceNamed:NSAppearanceNameAqua];
+
+ // Create the delegate for control and browser window events.
+ window_delegate_ = [[RootWindowDelegate alloc] initWithWindow:window_
+ andRootWindow:&root_window_];
+
+ if (!initial_bounds_.IsEmpty()) {
+ // Remember the bounds from the previous application run in case the user
+ // does not move or resize the window during this application run.
+ window_delegate_.last_visible_bounds = initial_bounds_;
+ }
+
+ // Rely on the window delegate to clean us up rather than immediately
+ // releasing when the window gets closed. We use the delegate to do
+ // everything from the autorelease pool so the window isn't on the stack
+ // during cleanup (ie, a window close from javascript).
+ [window_ setReleasedWhenClosed:NO];
+
+ const cef_color_t background_color = MainContext::Get()->GetBackgroundColor();
+ [window_
+ setBackgroundColor:[NSColor
+ colorWithCalibratedRed:float(CefColorGetR(
+ background_color)) /
+ 255.0f
+ green:float(CefColorGetG(
+ background_color)) /
+ 255.0f
+ blue:float(CefColorGetB(
+ background_color)) /
+ 255.0f
+ alpha:1.f]];
+
+ NSView* contentView = [window_ contentView];
+ NSRect contentBounds = [contentView bounds];
+
+ if (!with_osr_) {
+ // Make the content view for the window have a layer. This will make all
+ // sub-views have layers. This is necessary to ensure correct layer
+ // ordering of all child views and their layers.
+ [contentView setWantsLayer:YES];
+ }
+
+ if (with_controls_) {
+ // Reduce the browser height by the URL bar height.
+ contentBounds.size.height -= URLBAR_HEIGHT;
+
+ // Create the buttons.
+ NSRect button_rect = contentBounds;
+ button_rect.origin.y =
+ contentBounds.size.height + (URLBAR_HEIGHT - BUTTON_HEIGHT) / 2;
+ button_rect.size.height = BUTTON_HEIGHT;
+ button_rect.origin.x += BUTTON_MARGIN;
+ button_rect.size.width = BUTTON_WIDTH;
+
+ back_button_ = MakeButton(&button_rect, @"Back", contentView);
+ [back_button_ setTarget:window_delegate_];
+ [back_button_ setAction:@selector(goBack:)];
+ [back_button_ setEnabled:NO];
+
+ forward_button_ = MakeButton(&button_rect, @"Forward", contentView);
+ [forward_button_ setTarget:window_delegate_];
+ [forward_button_ setAction:@selector(goForward:)];
+ [forward_button_ setEnabled:NO];
+
+ reload_button_ = MakeButton(&button_rect, @"Reload", contentView);
+ [reload_button_ setTarget:window_delegate_];
+ [reload_button_ setAction:@selector(reload:)];
+ [reload_button_ setEnabled:NO];
+
+ stop_button_ = MakeButton(&button_rect, @"Stop", contentView);
+ [stop_button_ setTarget:window_delegate_];
+ [stop_button_ setAction:@selector(stopLoading:)];
+ [stop_button_ setEnabled:NO];
+
+ // Create the URL text field.
+ button_rect.origin.x += BUTTON_MARGIN;
+ button_rect.size.width =
+ [contentView bounds].size.width - button_rect.origin.x - BUTTON_MARGIN;
+ url_textfield_ = [[NSTextField alloc] initWithFrame:button_rect];
+ [contentView addSubview:url_textfield_];
+ [url_textfield_
+ setAutoresizingMask:(NSViewWidthSizable | NSViewMinYMargin)];
+ [url_textfield_ setTarget:window_delegate_];
+ [url_textfield_ setAction:@selector(takeURLStringValueFrom:)];
+ [url_textfield_ setEnabled:NO];
+ [[url_textfield_ cell] setWraps:NO];
+ [[url_textfield_ cell] setScrollable:YES];
+ }
+
+ // Place the window at the target point. This is required for proper placement
+ // if the point is on a secondary display.
+ [window_ setFrameOrigin:frame_rect.origin];
+
+ if (!is_popup_) {
+ // Create the browser window.
+ browser_window_->CreateBrowser(
+ CAST_NSVIEW_TO_CEF_WINDOW_HANDLE(contentView),
+ CefRect(0, 0, contentBounds.size.width, contentBounds.size.height),
+ settings, nullptr,
+ root_window_.delegate_->GetRequestContext(&root_window_));
+ } else {
+ // With popups we already have a browser window. Parent the browser window
+ // to the root window and show it in the correct location.
+ browser_window_->ShowPopup(CAST_NSVIEW_TO_CEF_WINDOW_HANDLE(contentView), 0,
+ 0, contentBounds.size.width,
+ contentBounds.size.height);
+ }
+
+ if (!initially_hidden) {
+ auto mode = RootWindow::ShowNormal;
+ if (initial_show_state_ == CEF_SHOW_STATE_MAXIMIZED) {
+ mode = RootWindow::ShowMaximized;
+ } else if (initial_show_state_ == CEF_SHOW_STATE_MINIMIZED) {
+ mode = RootWindow::ShowMinimized;
+ }
+
+ // Show the window.
+ Show(mode);
+ }
+}
+
+void RootWindowMacImpl::OnBrowserCreated(CefRefPtr<CefBrowser> browser) {
+ REQUIRE_MAIN_THREAD();
+
+ // For popup browsers create the root window once the browser has been
+ // created.
+ if (is_popup_) {
+ CreateRootWindow(CefBrowserSettings(), false);
+ }
+
+ root_window_.delegate_->OnBrowserCreated(&root_window_, browser);
+}
+
+void RootWindowMacImpl::OnBrowserWindowDestroyed() {
+ REQUIRE_MAIN_THREAD();
+
+ browser_window_.reset();
+
+ if (!window_destroyed_) {
+ // The browser was destroyed first. This could be due to the use of
+ // off-screen rendering or execution of JavaScript window.close().
+ // Close the RootWindow.
+ Close(true);
+ }
+
+ browser_destroyed_ = true;
+ NotifyDestroyedIfDone();
+}
+
+void RootWindowMacImpl::OnSetAddress(const std::string& url) {
+ REQUIRE_MAIN_THREAD();
+
+ if (url_textfield_) {
+ std::string urlStr(url);
+ NSString* str = [NSString stringWithUTF8String:urlStr.c_str()];
+ [url_textfield_ setStringValue:str];
+ }
+}
+
+void RootWindowMacImpl::OnSetDraggableRegions(
+ const std::vector<CefDraggableRegion>& regions) {
+ REQUIRE_MAIN_THREAD();
+ // TODO(cef): Implement support for draggable regions on this platform.
+}
+
+void RootWindowMacImpl::OnSetTitle(const std::string& title) {
+ REQUIRE_MAIN_THREAD();
+
+ if (window_) {
+ std::string titleStr(title);
+ NSString* str = [NSString stringWithUTF8String:titleStr.c_str()];
+ [window_ setTitle:str];
+ }
+}
+
+void RootWindowMacImpl::OnSetFullscreen(bool fullscreen) {
+ REQUIRE_MAIN_THREAD();
+
+ CefRefPtr<CefBrowser> browser = GetBrowser();
+ if (browser) {
+ std::unique_ptr<window_test::WindowTestRunnerMac> test_runner(
+ new window_test::WindowTestRunnerMac());
+ if (fullscreen) {
+ test_runner->Maximize(browser);
+ } else {
+ test_runner->Restore(browser);
+ }
+ }
+}
+
+void RootWindowMacImpl::OnAutoResize(const CefSize& new_size) {
+ REQUIRE_MAIN_THREAD();
+
+ if (!window_) {
+ return;
+ }
+
+ // Desired content rectangle.
+ NSRect content_rect;
+ content_rect.size.width = static_cast<int>(new_size.width);
+ content_rect.size.height =
+ static_cast<int>(new_size.height) + (with_controls_ ? URLBAR_HEIGHT : 0);
+
+ // Convert to a frame rectangle.
+ NSRect frame_rect = [window_ frameRectForContentRect:content_rect];
+ // Don't change the origin.
+ frame_rect.origin = window_.frame.origin;
+
+ [window_ setFrame:frame_rect display:YES];
+
+ // Make sure the window is visible.
+ Show(RootWindow::ShowNormal);
+}
+
+void RootWindowMacImpl::OnSetLoadingState(bool isLoading,
+ bool canGoBack,
+ bool canGoForward) {
+ REQUIRE_MAIN_THREAD();
+
+ if (with_controls_) {
+ [url_textfield_ setEnabled:YES];
+ [reload_button_ setEnabled:!isLoading];
+ [stop_button_ setEnabled:isLoading];
+ [back_button_ setEnabled:canGoBack];
+ [forward_button_ setEnabled:canGoForward];
+ }
+
+ // After Loading is done, check if voiceover is running and accessibility
+ // should be enabled.
+ if (!isLoading) {
+ Boolean keyExists = false;
+ // On OSX there is no API to query if VoiceOver is active or not. The value
+ // however is stored in preferences that can be queried.
+ if (CFPreferencesGetAppBooleanValue(CFSTR("voiceOverOnOffKey"),
+ CFSTR("com.apple.universalaccess"),
+ &keyExists)) {
+ GetBrowser()->GetHost()->SetAccessibilityState(STATE_ENABLED);
+ }
+ }
+}
+
+void RootWindowMacImpl::NotifyDestroyedIfDone() {
+ // Notify once both the window and the browser have been destroyed.
+ if (window_destroyed_ && browser_destroyed_) {
+ root_window_.delegate_->OnRootWindowDestroyed(&root_window_);
+ }
+}
+
+RootWindowMac::RootWindowMac() {
+ impl_ = new RootWindowMacImpl(*this);
+}
+
+RootWindowMac::~RootWindowMac() {}
+
+BrowserWindow* RootWindowMac::browser_window() const {
+ return impl_->browser_window_.get();
+}
+
+RootWindow::Delegate* RootWindowMac::delegate() const {
+ return delegate_;
+}
+
+void RootWindowMac::Init(RootWindow::Delegate* delegate,
+ std::unique_ptr<RootWindowConfig> config,
+ const CefBrowserSettings& settings) {
+ DCHECK(delegate);
+ delegate_ = delegate;
+ impl_->Init(delegate, std::move(config), settings);
+}
+
+void RootWindowMac::InitAsPopup(RootWindow::Delegate* delegate,
+ bool with_controls,
+ bool with_osr,
+ const CefPopupFeatures& popupFeatures,
+ CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient>& client,
+ CefBrowserSettings& settings) {
+ DCHECK(delegate);
+ delegate_ = delegate;
+ impl_->InitAsPopup(delegate, with_controls, with_osr, popupFeatures,
+ windowInfo, client, settings);
+}
+
+void RootWindowMac::Show(ShowMode mode) {
+ impl_->Show(mode);
+}
+
+void RootWindowMac::Hide() {
+ impl_->Hide();
+}
+
+void RootWindowMac::SetBounds(int x, int y, size_t width, size_t height) {
+ impl_->SetBounds(x, y, width, height);
+}
+
+void RootWindowMac::Close(bool force) {
+ impl_->Close(force);
+}
+
+void RootWindowMac::SetDeviceScaleFactor(float device_scale_factor) {
+ impl_->SetDeviceScaleFactor(device_scale_factor);
+}
+
+float RootWindowMac::GetDeviceScaleFactor() const {
+ return impl_->GetDeviceScaleFactor();
+}
+
+CefRefPtr<CefBrowser> RootWindowMac::GetBrowser() const {
+ return impl_->GetBrowser();
+}
+
+ClientWindowHandle RootWindowMac::GetWindowHandle() const {
+ return impl_->GetWindowHandle();
+}
+
+bool RootWindowMac::WithWindowlessRendering() const {
+ return impl_->WithWindowlessRendering();
+}
+
+bool RootWindowMac::WithExtension() const {
+ return impl_->WithExtension();
+}
+
+void RootWindowMac::OnBrowserCreated(CefRefPtr<CefBrowser> browser) {
+ impl_->OnBrowserCreated(browser);
+}
+
+void RootWindowMac::OnBrowserWindowDestroyed() {
+ impl_->OnBrowserWindowDestroyed();
+}
+
+void RootWindowMac::OnSetAddress(const std::string& url) {
+ impl_->OnSetAddress(url);
+}
+
+void RootWindowMac::OnSetTitle(const std::string& title) {
+ impl_->OnSetTitle(title);
+}
+
+void RootWindowMac::OnSetFullscreen(bool fullscreen) {
+ impl_->OnSetFullscreen(fullscreen);
+}
+
+void RootWindowMac::OnAutoResize(const CefSize& new_size) {
+ impl_->OnAutoResize(new_size);
+}
+
+void RootWindowMac::OnSetLoadingState(bool isLoading,
+ bool canGoBack,
+ bool canGoForward) {
+ impl_->OnSetLoadingState(isLoading, canGoBack, canGoForward);
+}
+
+void RootWindowMac::OnSetDraggableRegions(
+ const std::vector<CefDraggableRegion>& regions) {
+ impl_->OnSetDraggableRegions(regions);
+}
+
+void RootWindowMac::OnNativeWindowClosed() {
+ impl_->OnNativeWindowClosed();
+}
+
+} // namespace client
+
+@implementation RootWindowDelegate
+
+@synthesize root_window = root_window_;
+@synthesize last_visible_bounds = last_visible_bounds_;
+@synthesize force_close = force_close_;
+
+- (id)initWithWindow:(NSWindow*)window
+ andRootWindow:(client::RootWindowMac*)root_window {
+ if (self = [super init]) {
+ window_ = window;
+ [window_ setDelegate:self];
+ root_window_ = root_window;
+ force_close_ = false;
+
+ // Register for application hide/unhide notifications.
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(applicationDidHide:)
+ name:NSApplicationDidHideNotification
+ object:nil];
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(applicationDidUnhide:)
+ name:NSApplicationDidUnhideNotification
+ object:nil];
+ }
+ return self;
+}
+
+- (void)dealloc {
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+#if !__has_feature(objc_arc)
+ [super dealloc];
+#endif // !__has_feature(objc_arc)
+}
+
+- (IBAction)goBack:(id)sender {
+ CefRefPtr<CefBrowser> browser = root_window_->GetBrowser();
+ if (browser.get()) {
+ browser->GoBack();
+ }
+}
+
+- (IBAction)goForward:(id)sender {
+ CefRefPtr<CefBrowser> browser = root_window_->GetBrowser();
+ if (browser.get()) {
+ browser->GoForward();
+ }
+}
+
+- (IBAction)reload:(id)sender {
+ CefRefPtr<CefBrowser> browser = root_window_->GetBrowser();
+ if (browser.get()) {
+ browser->Reload();
+ }
+}
+
+- (IBAction)stopLoading:(id)sender {
+ CefRefPtr<CefBrowser> browser = root_window_->GetBrowser();
+ if (browser.get()) {
+ browser->StopLoad();
+ }
+}
+
+- (IBAction)takeURLStringValueFrom:(NSTextField*)sender {
+ CefRefPtr<CefBrowser> browser = root_window_->GetBrowser();
+ if (!browser.get()) {
+ return;
+ }
+
+ NSString* url = [sender stringValue];
+
+ // if it doesn't already have a prefix, add http. If we can't parse it,
+ // just don't bother rather than making things worse.
+ NSURL* tempUrl = [NSURL URLWithString:url];
+ if (tempUrl && ![tempUrl scheme]) {
+ url = [@"http://" stringByAppendingString:url];
+ }
+
+ std::string urlStr = [url UTF8String];
+ browser->GetMainFrame()->LoadURL(urlStr);
+}
+
+// Called when we are activated (when we gain focus).
+- (void)windowDidBecomeKey:(NSNotification*)notification {
+ client::BrowserWindow* browser_window = root_window_->browser_window();
+ if (browser_window) {
+ browser_window->SetFocus(true);
+ }
+ root_window_->delegate()->OnRootWindowActivated(root_window_);
+}
+
+// Called when we are deactivated (when we lose focus).
+- (void)windowDidResignKey:(NSNotification*)notification {
+ client::BrowserWindow* browser_window = root_window_->browser_window();
+ if (browser_window) {
+ browser_window->SetFocus(false);
+ }
+}
+
+// Called when we have been minimized.
+- (void)windowDidMiniaturize:(NSNotification*)notification {
+ client::BrowserWindow* browser_window = root_window_->browser_window();
+ if (browser_window) {
+ browser_window->Hide();
+ }
+}
+
+// Called when we have been unminimized.
+- (void)windowDidDeminiaturize:(NSNotification*)notification {
+ client::BrowserWindow* browser_window = root_window_->browser_window();
+ if (browser_window) {
+ browser_window->Show();
+ }
+}
+
+// Called when we have been resized.
+- (void)windowDidResize:(NSNotification*)notification {
+ // Track the last visible bounds for window restore purposes.
+ const auto dip_bounds = client::GetWindowBoundsInScreen(window_);
+ if (dip_bounds) {
+ last_visible_bounds_ = dip_bounds;
+ }
+}
+
+// Called when we have been moved.
+- (void)windowDidMove:(NSNotification*)notification {
+ // Track the last visible bounds for window restore purposes.
+ const auto dip_bounds = client::GetWindowBoundsInScreen(window_);
+ if (dip_bounds) {
+ last_visible_bounds_ = dip_bounds;
+ }
+}
+
+// Called when the application has been hidden.
+- (void)applicationDidHide:(NSNotification*)notification {
+ // If the window is miniaturized then nothing has really changed.
+ if (![window_ isMiniaturized]) {
+ client::BrowserWindow* browser_window = root_window_->browser_window();
+ if (browser_window) {
+ browser_window->Hide();
+ }
+ }
+}
+
+// Called when the application has been unhidden.
+- (void)applicationDidUnhide:(NSNotification*)notification {
+ // If the window is miniaturized then nothing has really changed.
+ if (![window_ isMiniaturized]) {
+ client::BrowserWindow* browser_window = root_window_->browser_window();
+ if (browser_window) {
+ browser_window->Show();
+ }
+ }
+}
+
+// Called when the window is about to close. Perform the self-destruction
+// sequence by getting rid of the window. By returning YES, we allow the window
+// to be removed from the screen.
+- (BOOL)windowShouldClose:(NSWindow*)window {
+ if (!force_close_) {
+ client::BrowserWindow* browser_window = root_window_->browser_window();
+ if (browser_window && !browser_window->IsClosing()) {
+ CefRefPtr<CefBrowser> browser = browser_window->GetBrowser();
+ if (browser.get()) {
+ // Notify the browser window that we would like to close it. This
+ // will result in a call to ClientHandler::DoClose() if the
+ // JavaScript 'onbeforeunload' event handler allows it.
+ browser->GetHost()->CloseBrowser(false);
+
+ // Cancel the close.
+ return NO;
+ }
+ }
+ }
+
+ // Save window restore position.
+ std::optional<CefRect> dip_bounds;
+ cef_show_state_t show_state = CEF_SHOW_STATE_NORMAL;
+ if ([window_ isMiniaturized]) {
+ show_state = CEF_SHOW_STATE_MINIMIZED;
+ } else if ([window_ isZoomed]) {
+ show_state = CEF_SHOW_STATE_MAXIMIZED;
+ } else {
+ dip_bounds = client::GetWindowBoundsInScreen(window_);
+ }
+
+ if (!dip_bounds) {
+ dip_bounds = last_visible_bounds_;
+ }
+
+ client::prefs::SaveWindowRestorePreferences(show_state, dip_bounds);
+
+ // Clean ourselves up after clearing the stack of anything that might have the
+ // window on it.
+ [self cleanup];
+
+ // Allow the close.
+ return YES;
+}
+
+// Deletes itself.
+- (void)cleanup {
+ // Don't want any more delegate callbacks after we destroy ourselves.
+ window_.delegate = nil;
+ window_.contentView = [[NSView alloc] initWithFrame:NSZeroRect];
+ // Delete the window.
+#if !__has_feature(objc_arc)
+ [window_ autorelease];
+#endif // !__has_feature(objc_arc)
+ window_ = nil;
+ root_window_->OnNativeWindowClosed();
+}
+
+@end // @implementation RootWindowDelegate
diff --git a/tests/cefclient/browser/root_window_manager.cc b/tests/cefclient/browser/root_window_manager.cc
new file mode 100644
index 00000000..303ca372
--- /dev/null
+++ b/tests/cefclient/browser/root_window_manager.cc
@@ -0,0 +1,458 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/root_window_manager.h"
+
+#include <sstream>
+
+#include "include/base/cef_callback.h"
+#include "include/base/cef_logging.h"
+#include "include/wrapper/cef_helpers.h"
+#include "tests/cefclient/browser/client_handler_std.h"
+#include "tests/cefclient/browser/main_context.h"
+#include "tests/cefclient/browser/test_runner.h"
+#include "tests/shared/browser/extension_util.h"
+#include "tests/shared/browser/file_util.h"
+#include "tests/shared/browser/resource_util.h"
+#include "tests/shared/common/client_switches.h"
+
+namespace client {
+
+namespace {
+
+class ClientRequestContextHandler : public CefRequestContextHandler,
+ public CefExtensionHandler {
+ public:
+ ClientRequestContextHandler() {}
+
+ // CefRequestContextHandler methods:
+ void OnRequestContextInitialized(
+ CefRefPtr<CefRequestContext> request_context) override {
+ CEF_REQUIRE_UI_THREAD();
+
+ CefRefPtr<CefCommandLine> command_line =
+ CefCommandLine::GetGlobalCommandLine();
+ if (command_line->HasSwitch(switches::kLoadExtension)) {
+ if (MainContext::Get()
+ ->GetRootWindowManager()
+ ->request_context_per_browser()) {
+ // The example extension loading implementation requires all browsers to
+ // share the same request context.
+ LOG(ERROR)
+ << "Cannot mix --load-extension and --request-context-per-browser";
+ return;
+ }
+
+ // Load one or more extension paths specified on the command-line and
+ // delimited with semicolon.
+ const std::string& extension_path =
+ command_line->GetSwitchValue(switches::kLoadExtension);
+ if (!extension_path.empty()) {
+ std::string part;
+ std::istringstream f(extension_path);
+ while (getline(f, part, ';')) {
+ if (!part.empty()) {
+ extension_util::LoadExtension(request_context, part, this);
+ }
+ }
+ }
+ }
+ }
+
+ // CefExtensionHandler methods:
+ void OnExtensionLoaded(CefRefPtr<CefExtension> extension) override {
+ CEF_REQUIRE_UI_THREAD();
+ MainContext::Get()->GetRootWindowManager()->AddExtension(extension);
+ }
+
+ CefRefPtr<CefBrowser> GetActiveBrowser(CefRefPtr<CefExtension> extension,
+ CefRefPtr<CefBrowser> browser,
+ bool include_incognito) override {
+ CEF_REQUIRE_UI_THREAD();
+
+ // Return the browser for the active/foreground window.
+ CefRefPtr<CefBrowser> active_browser =
+ MainContext::Get()->GetRootWindowManager()->GetActiveBrowser();
+ if (!active_browser) {
+ LOG(WARNING)
+ << "No active browser available for extension "
+ << browser->GetHost()->GetExtension()->GetIdentifier().ToString();
+ } else {
+ // The active browser should not be hosting an extension.
+ DCHECK(!active_browser->GetHost()->GetExtension());
+ }
+ return active_browser;
+ }
+
+ private:
+ IMPLEMENT_REFCOUNTING(ClientRequestContextHandler);
+ DISALLOW_COPY_AND_ASSIGN(ClientRequestContextHandler);
+};
+
+} // namespace
+
+RootWindowManager::RootWindowManager(bool terminate_when_all_windows_closed)
+ : terminate_when_all_windows_closed_(terminate_when_all_windows_closed) {
+ CefRefPtr<CefCommandLine> command_line =
+ CefCommandLine::GetGlobalCommandLine();
+ DCHECK(command_line.get());
+ request_context_per_browser_ =
+ command_line->HasSwitch(switches::kRequestContextPerBrowser);
+ request_context_shared_cache_ =
+ command_line->HasSwitch(switches::kRequestContextSharedCache);
+}
+
+RootWindowManager::~RootWindowManager() {
+ // All root windows should already have been destroyed.
+ DCHECK(root_windows_.empty());
+}
+
+scoped_refptr<RootWindow> RootWindowManager::CreateRootWindow(
+ std::unique_ptr<RootWindowConfig> config) {
+ CefBrowserSettings settings;
+ MainContext::Get()->PopulateBrowserSettings(&settings);
+
+ scoped_refptr<RootWindow> root_window =
+ RootWindow::Create(MainContext::Get()->UseViews());
+ root_window->Init(this, std::move(config), settings);
+
+ // Store a reference to the root window on the main thread.
+ OnRootWindowCreated(root_window);
+
+ return root_window;
+}
+
+scoped_refptr<RootWindow> RootWindowManager::CreateRootWindowAsPopup(
+ bool with_controls,
+ bool with_osr,
+ const CefPopupFeatures& popupFeatures,
+ CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient>& client,
+ CefBrowserSettings& settings) {
+ CEF_REQUIRE_UI_THREAD();
+
+ MainContext::Get()->PopulateBrowserSettings(&settings);
+
+ if (MainContext::Get()->UseDefaultPopup()) {
+ // Use default window creation for the popup. A new |client| instance is
+ // still required by cefclient architecture.
+ client = new ClientHandlerStd(/*delegate=*/nullptr, with_controls,
+ /*startup_url=*/CefString());
+ return nullptr;
+ }
+
+ if (!temp_window_) {
+ // TempWindow must be created on the UI thread.
+ temp_window_.reset(new TempWindow());
+ }
+
+ scoped_refptr<RootWindow> root_window =
+ RootWindow::Create(MainContext::Get()->UseViews());
+ root_window->InitAsPopup(this, with_controls, with_osr, popupFeatures,
+ windowInfo, client, settings);
+
+ // Store a reference to the root window on the main thread.
+ OnRootWindowCreated(root_window);
+
+ return root_window;
+}
+
+scoped_refptr<RootWindow> RootWindowManager::CreateRootWindowAsExtension(
+ CefRefPtr<CefExtension> extension,
+ const CefRect& source_bounds,
+ CefRefPtr<CefWindow> parent_window,
+ base::OnceClosure close_callback,
+ bool with_controls,
+ bool with_osr) {
+ const std::string& extension_url = extension_util::GetExtensionURL(extension);
+ if (extension_url.empty()) {
+ NOTREACHED() << "Extension cannot be loaded directly.";
+ return nullptr;
+ }
+
+ // Create an initially hidden browser window that loads the extension URL.
+ // We'll show the window when the desired size becomes available via
+ // ClientHandler::OnAutoResize.
+ auto config = std::make_unique<RootWindowConfig>();
+ config->with_controls = with_controls;
+ config->with_osr = with_osr;
+ config->with_extension = true;
+ config->initially_hidden = true;
+ config->source_bounds = source_bounds;
+ config->parent_window = parent_window;
+ config->close_callback = std::move(close_callback);
+ config->url = extension_url;
+ return CreateRootWindow(std::move(config));
+}
+
+bool RootWindowManager::HasRootWindowAsExtension(
+ CefRefPtr<CefExtension> extension) {
+ REQUIRE_MAIN_THREAD();
+
+ for (auto root_window : root_windows_) {
+ if (!root_window->WithExtension()) {
+ continue;
+ }
+
+ CefRefPtr<CefBrowser> browser = root_window->GetBrowser();
+ if (!browser) {
+ continue;
+ }
+
+ CefRefPtr<CefExtension> browser_extension =
+ browser->GetHost()->GetExtension();
+ DCHECK(browser_extension);
+ if (browser_extension->GetIdentifier() == extension->GetIdentifier()) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+scoped_refptr<RootWindow> RootWindowManager::GetWindowForBrowser(
+ int browser_id) const {
+ REQUIRE_MAIN_THREAD();
+
+ for (auto root_window : root_windows_) {
+ CefRefPtr<CefBrowser> browser = root_window->GetBrowser();
+ if (browser.get() && browser->GetIdentifier() == browser_id) {
+ return root_window;
+ }
+ }
+ return nullptr;
+}
+
+scoped_refptr<RootWindow> RootWindowManager::GetActiveRootWindow() const {
+ REQUIRE_MAIN_THREAD();
+ return active_root_window_;
+}
+
+CefRefPtr<CefBrowser> RootWindowManager::GetActiveBrowser() const {
+ base::AutoLock lock_scope(active_browser_lock_);
+ return active_browser_;
+}
+
+void RootWindowManager::CloseAllWindows(bool force) {
+ if (!CURRENTLY_ON_MAIN_THREAD()) {
+ // Execute this method on the main thread.
+ MAIN_POST_CLOSURE(base::BindOnce(&RootWindowManager::CloseAllWindows,
+ base::Unretained(this), force));
+ return;
+ }
+
+ if (root_windows_.empty()) {
+ return;
+ }
+
+ // Use a copy of |root_windows_| because the original set may be modified
+ // in OnRootWindowDestroyed while iterating.
+ RootWindowSet root_windows = root_windows_;
+
+ for (auto root_window : root_windows) {
+ root_window->Close(force);
+ }
+}
+
+void RootWindowManager::AddExtension(CefRefPtr<CefExtension> extension) {
+ if (!CURRENTLY_ON_MAIN_THREAD()) {
+ // Execute this method on the main thread.
+ MAIN_POST_CLOSURE(base::BindOnce(&RootWindowManager::AddExtension,
+ base::Unretained(this), extension));
+ return;
+ }
+
+ // Don't track extensions that can't be loaded directly.
+ if (extension_util::GetExtensionURL(extension).empty()) {
+ return;
+ }
+
+ // Don't add the same extension multiple times.
+ ExtensionSet::const_iterator it = extensions_.begin();
+ for (; it != extensions_.end(); ++it) {
+ if ((*it)->GetIdentifier() == extension->GetIdentifier()) {
+ return;
+ }
+ }
+
+ extensions_.insert(extension);
+ NotifyExtensionsChanged();
+}
+
+void RootWindowManager::OnRootWindowCreated(
+ scoped_refptr<RootWindow> root_window) {
+ if (!CURRENTLY_ON_MAIN_THREAD()) {
+ // Execute this method on the main thread.
+ MAIN_POST_CLOSURE(base::BindOnce(&RootWindowManager::OnRootWindowCreated,
+ base::Unretained(this), root_window));
+ return;
+ }
+
+ root_windows_.insert(root_window);
+ if (!root_window->WithExtension()) {
+ root_window->OnExtensionsChanged(extensions_);
+
+ if (root_windows_.size() == 1U) {
+ // The first non-extension root window should be considered the active
+ // window.
+ OnRootWindowActivated(root_window.get());
+ }
+ }
+}
+
+void RootWindowManager::NotifyExtensionsChanged() {
+ REQUIRE_MAIN_THREAD();
+
+ for (auto root_window : root_windows_) {
+ if (!root_window->WithExtension()) {
+ root_window->OnExtensionsChanged(extensions_);
+ }
+ }
+}
+
+CefRefPtr<CefRequestContext> RootWindowManager::GetRequestContext(
+ RootWindow* root_window) {
+ REQUIRE_MAIN_THREAD();
+
+ if (request_context_per_browser_) {
+ // Create a new request context for each browser.
+ CefRequestContextSettings settings;
+
+ CefRefPtr<CefCommandLine> command_line =
+ CefCommandLine::GetGlobalCommandLine();
+ if (command_line->HasSwitch(switches::kCachePath)) {
+ if (request_context_shared_cache_) {
+ // Give each browser the same cache path. The resulting context objects
+ // will share the same storage internally.
+ CefString(&settings.cache_path) =
+ command_line->GetSwitchValue(switches::kCachePath);
+ } else {
+ // Give each browser a unique cache path. This will create completely
+ // isolated context objects.
+ std::stringstream ss;
+ ss << command_line->GetSwitchValue(switches::kCachePath).ToString()
+ << file_util::kPathSep << time(nullptr);
+ CefString(&settings.cache_path) = ss.str();
+ }
+ }
+
+ return CefRequestContext::CreateContext(settings,
+ new ClientRequestContextHandler);
+ }
+
+ // All browsers will share the global request context.
+ if (!shared_request_context_.get()) {
+ shared_request_context_ = CefRequestContext::CreateContext(
+ CefRequestContext::GetGlobalContext(), new ClientRequestContextHandler);
+ }
+ return shared_request_context_;
+}
+
+scoped_refptr<ImageCache> RootWindowManager::GetImageCache() {
+ CEF_REQUIRE_UI_THREAD();
+
+ if (!image_cache_) {
+ image_cache_ = new ImageCache;
+ }
+ return image_cache_;
+}
+
+void RootWindowManager::OnTest(RootWindow* root_window, int test_id) {
+ REQUIRE_MAIN_THREAD();
+
+ test_runner::RunTest(root_window->GetBrowser(), test_id);
+}
+
+void RootWindowManager::OnExit(RootWindow* root_window) {
+ REQUIRE_MAIN_THREAD();
+
+ CloseAllWindows(false);
+}
+
+void RootWindowManager::OnRootWindowDestroyed(RootWindow* root_window) {
+ REQUIRE_MAIN_THREAD();
+
+ RootWindowSet::iterator it = root_windows_.find(root_window);
+ DCHECK(it != root_windows_.end());
+ if (it != root_windows_.end()) {
+ root_windows_.erase(it);
+ }
+
+ if (root_window == active_root_window_) {
+ active_root_window_ = nullptr;
+
+ base::AutoLock lock_scope(active_browser_lock_);
+ active_browser_ = nullptr;
+ }
+
+ if (terminate_when_all_windows_closed_ && root_windows_.empty()) {
+ // All windows have closed. Clean up on the UI thread.
+ CefPostTask(TID_UI, base::BindOnce(&RootWindowManager::CleanupOnUIThread,
+ base::Unretained(this)));
+ }
+}
+
+void RootWindowManager::OnRootWindowActivated(RootWindow* root_window) {
+ REQUIRE_MAIN_THREAD();
+
+ if (root_window->WithExtension()) {
+ // We don't want extension apps to become the active RootWindow.
+ return;
+ }
+
+ if (root_window == active_root_window_) {
+ return;
+ }
+
+ active_root_window_ = root_window;
+
+ {
+ base::AutoLock lock_scope(active_browser_lock_);
+ // May be nullptr at this point, in which case we'll make the association in
+ // OnBrowserCreated.
+ active_browser_ = active_root_window_->GetBrowser();
+ }
+}
+
+void RootWindowManager::OnBrowserCreated(RootWindow* root_window,
+ CefRefPtr<CefBrowser> browser) {
+ REQUIRE_MAIN_THREAD();
+
+ if (root_window == active_root_window_) {
+ base::AutoLock lock_scope(active_browser_lock_);
+ active_browser_ = browser;
+ }
+}
+
+void RootWindowManager::CreateExtensionWindow(
+ CefRefPtr<CefExtension> extension,
+ const CefRect& source_bounds,
+ CefRefPtr<CefWindow> parent_window,
+ base::OnceClosure close_callback,
+ bool with_osr) {
+ REQUIRE_MAIN_THREAD();
+
+ if (!HasRootWindowAsExtension(extension)) {
+ CreateRootWindowAsExtension(extension, source_bounds, parent_window,
+ std::move(close_callback), false, with_osr);
+ }
+}
+
+void RootWindowManager::CleanupOnUIThread() {
+ CEF_REQUIRE_UI_THREAD();
+
+ if (temp_window_) {
+ // TempWindow must be destroyed on the UI thread.
+ temp_window_.reset(nullptr);
+ }
+
+ if (image_cache_) {
+ image_cache_ = nullptr;
+ }
+
+ // Quit the main message loop.
+ MainMessageLoop::Get()->Quit();
+}
+
+} // namespace client
diff --git a/tests/cefclient/browser/root_window_manager.h b/tests/cefclient/browser/root_window_manager.h
new file mode 100644
index 00000000..82f4e171
--- /dev/null
+++ b/tests/cefclient/browser/root_window_manager.h
@@ -0,0 +1,145 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_ROOT_WINDOW_MANAGER_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_ROOT_WINDOW_MANAGER_H_
+#pragma once
+
+#include <memory>
+#include <set>
+
+#include "include/cef_command_line.h"
+#include "include/cef_request_context_handler.h"
+#include "tests/cefclient/browser/image_cache.h"
+#include "tests/cefclient/browser/root_window.h"
+#include "tests/cefclient/browser/temp_window.h"
+
+namespace client {
+
+// Used to create/manage RootWindow instances. The methods of this class can be
+// called from any browser process thread unless otherwise indicated.
+class RootWindowManager : public RootWindow::Delegate {
+ public:
+ // If |terminate_when_all_windows_closed| is true quit the main message loop
+ // after all windows have closed.
+ explicit RootWindowManager(bool terminate_when_all_windows_closed);
+
+ // Create a new top-level native window. This method can be called from
+ // anywhere.
+ scoped_refptr<RootWindow> CreateRootWindow(
+ std::unique_ptr<RootWindowConfig> config);
+
+ // Create a new native popup window.
+ // If |with_controls| is true the window will show controls.
+ // If |with_osr| is true the window will use off-screen rendering.
+ // This method is called from ClientHandler::CreatePopupWindow() to
+ // create a new popup or DevTools window. Must be called on the UI thread.
+ scoped_refptr<RootWindow> CreateRootWindowAsPopup(
+ bool with_controls,
+ bool with_osr,
+ const CefPopupFeatures& popupFeatures,
+ CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient>& client,
+ CefBrowserSettings& settings);
+
+ // Create a new top-level native window to host |extension|.
+ // If |with_controls| is true the window will show controls.
+ // If |with_osr| is true the window will use off-screen rendering.
+ // This method can be called from anywhere.
+ scoped_refptr<RootWindow> CreateRootWindowAsExtension(
+ CefRefPtr<CefExtension> extension,
+ const CefRect& source_bounds,
+ CefRefPtr<CefWindow> parent_window,
+ base::OnceClosure close_callback,
+ bool with_controls,
+ bool with_osr);
+
+ // Returns true if a window hosting |extension| currently exists. Must be
+ // called on the main thread.
+ bool HasRootWindowAsExtension(CefRefPtr<CefExtension> extension);
+
+ // Returns the RootWindow associated with the specified browser ID. Must be
+ // called on the main thread.
+ scoped_refptr<RootWindow> GetWindowForBrowser(int browser_id) const;
+
+ // Returns the currently active/foreground RootWindow. May return nullptr.
+ // Must be called on the main thread.
+ scoped_refptr<RootWindow> GetActiveRootWindow() const;
+
+ // Returns the currently active/foreground browser. May return nullptr. Safe
+ // to call from any thread.
+ CefRefPtr<CefBrowser> GetActiveBrowser() const;
+
+ // Close all existing windows. If |force| is true onunload handlers will not
+ // be executed.
+ void CloseAllWindows(bool force);
+
+ // Manage the set of loaded extensions. RootWindows will be notified via the
+ // OnExtensionsChanged method.
+ void AddExtension(CefRefPtr<CefExtension> extension);
+
+ bool request_context_per_browser() const {
+ return request_context_per_browser_;
+ }
+
+ private:
+ // Allow deletion via std::unique_ptr only.
+ friend std::default_delete<RootWindowManager>;
+
+ ~RootWindowManager();
+
+ void OnRootWindowCreated(scoped_refptr<RootWindow> root_window);
+ void NotifyExtensionsChanged();
+
+ // RootWindow::Delegate methods.
+ CefRefPtr<CefRequestContext> GetRequestContext(
+ RootWindow* root_window) override;
+ scoped_refptr<ImageCache> GetImageCache() override;
+ void OnTest(RootWindow* root_window, int test_id) override;
+ void OnExit(RootWindow* root_window) override;
+ void OnRootWindowDestroyed(RootWindow* root_window) override;
+ void OnRootWindowActivated(RootWindow* root_window) override;
+ void OnBrowserCreated(RootWindow* root_window,
+ CefRefPtr<CefBrowser> browser) override;
+ void CreateExtensionWindow(CefRefPtr<CefExtension> extension,
+ const CefRect& source_bounds,
+ CefRefPtr<CefWindow> parent_window,
+ base::OnceClosure close_callback,
+ bool with_osr) override;
+
+ void CleanupOnUIThread();
+
+ const bool terminate_when_all_windows_closed_;
+ bool request_context_per_browser_;
+ bool request_context_shared_cache_;
+
+ // Existing root windows. Only accessed on the main thread.
+ typedef std::set<scoped_refptr<RootWindow>> RootWindowSet;
+ RootWindowSet root_windows_;
+
+ // The currently active/foreground RootWindow. Only accessed on the main
+ // thread.
+ scoped_refptr<RootWindow> active_root_window_;
+
+ // The currently active/foreground browser. Access is protected by
+ // |active_browser_lock_;
+ mutable base::Lock active_browser_lock_;
+ CefRefPtr<CefBrowser> active_browser_;
+
+ // Singleton window used as the temporary parent for popup browsers.
+ std::unique_ptr<TempWindow> temp_window_;
+
+ CefRefPtr<CefRequestContext> shared_request_context_;
+
+ // Loaded extensions. Only accessed on the main thread.
+ ExtensionSet extensions_;
+
+ scoped_refptr<ImageCache> image_cache_;
+
+ DISALLOW_COPY_AND_ASSIGN(RootWindowManager);
+};
+
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_ROOT_WINDOW_MANAGER_H_
diff --git a/tests/cefclient/browser/root_window_views.cc b/tests/cefclient/browser/root_window_views.cc
new file mode 100644
index 00000000..a8e6ff1c
--- /dev/null
+++ b/tests/cefclient/browser/root_window_views.cc
@@ -0,0 +1,588 @@
+// Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/root_window_views.h"
+
+#include <memory>
+
+#include "include/base/cef_build.h"
+#include "include/base/cef_callback.h"
+#include "include/cef_app.h"
+#include "include/wrapper/cef_helpers.h"
+#include "tests/cefclient/browser/client_handler_std.h"
+#include "tests/cefclient/browser/client_prefs.h"
+
+namespace client {
+
+namespace {
+
+// Images that are loaded early and cached.
+static const char* kDefaultImageCache[] = {"menu_icon", "window_icon"};
+
+} // namespace
+
+RootWindowViews::RootWindowViews() = default;
+
+RootWindowViews::~RootWindowViews() {
+ REQUIRE_MAIN_THREAD();
+}
+
+void RootWindowViews::SetTitlebarHeight(const std::optional<float>& height) {
+ if (window_) {
+ window_->SetTitlebarHeight(height);
+ }
+}
+
+void RootWindowViews::Init(RootWindow::Delegate* delegate,
+ std::unique_ptr<RootWindowConfig> config,
+ const CefBrowserSettings& settings) {
+ DCHECK(delegate);
+ DCHECK(!config->with_osr); // Windowless rendering is not supported.
+ DCHECK(!initialized_);
+
+ delegate_ = delegate;
+ config_ = std::move(config);
+
+ CreateClientHandler(config_->url);
+ initialized_ = true;
+
+ // Continue initialization on the UI thread.
+ InitOnUIThread(settings, delegate_->GetRequestContext(this));
+}
+
+void RootWindowViews::InitAsPopup(RootWindow::Delegate* delegate,
+ bool with_controls,
+ bool with_osr,
+ const CefPopupFeatures& popupFeatures,
+ CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient>& client,
+ CefBrowserSettings& settings) {
+ CEF_REQUIRE_UI_THREAD();
+
+ DCHECK(delegate);
+ DCHECK(!with_osr); // Windowless rendering is not supported.
+ DCHECK(!initialized_);
+
+ delegate_ = delegate;
+ config_ = std::make_unique<RootWindowConfig>();
+ config_->with_controls = with_controls;
+
+ if (popupFeatures.xSet) {
+ initial_bounds_.x = popupFeatures.x;
+ }
+ if (popupFeatures.ySet) {
+ initial_bounds_.y = popupFeatures.y;
+ }
+ if (popupFeatures.widthSet) {
+ initial_bounds_.width = popupFeatures.width;
+ }
+ if (popupFeatures.heightSet) {
+ initial_bounds_.height = popupFeatures.height;
+ }
+
+ CreateClientHandler(std::string());
+ initialized_ = true;
+
+ // The Window will be created in ViewsWindow::OnPopupBrowserViewCreated().
+ client = client_handler_;
+}
+
+void RootWindowViews::Show(ShowMode mode) {
+ if (!CefCurrentlyOn(TID_UI)) {
+ // Execute this method on the UI thread.
+ CefPostTask(TID_UI, base::BindOnce(&RootWindowViews::Show, this, mode));
+ return;
+ }
+
+ if (!window_) {
+ return;
+ }
+
+ window_->Show();
+
+ switch (mode) {
+ case ShowMinimized:
+ window_->Minimize();
+ break;
+ case ShowMaximized:
+ window_->Maximize();
+ break;
+ default:
+ break;
+ }
+}
+
+void RootWindowViews::Hide() {
+ if (!CefCurrentlyOn(TID_UI)) {
+ // Execute this method on the UI thread.
+ CefPostTask(TID_UI, base::BindOnce(&RootWindowViews::Hide, this));
+ return;
+ }
+
+ if (window_) {
+ window_->Hide();
+ }
+}
+
+void RootWindowViews::SetBounds(int x, int y, size_t width, size_t height) {
+ if (!CefCurrentlyOn(TID_UI)) {
+ // Execute this method on the UI thread.
+ CefPostTask(TID_UI, base::BindOnce(&RootWindowViews::SetBounds, this, x, y,
+ width, height));
+ return;
+ }
+
+ if (window_) {
+ window_->SetBounds(
+ CefRect(x, y, static_cast<int>(width), static_cast<int>(height)));
+ }
+}
+
+void RootWindowViews::Close(bool force) {
+ if (!CefCurrentlyOn(TID_UI)) {
+ // Execute this method on the UI thread.
+ CefPostTask(TID_UI, base::BindOnce(&RootWindowViews::Close, this, force));
+ return;
+ }
+
+ if (window_) {
+ window_->Close(force);
+ }
+}
+
+void RootWindowViews::SetDeviceScaleFactor(float device_scale_factor) {
+ REQUIRE_MAIN_THREAD();
+ // Windowless rendering is not supported.
+ NOTREACHED();
+}
+
+float RootWindowViews::GetDeviceScaleFactor() const {
+ REQUIRE_MAIN_THREAD();
+ // Windowless rendering is not supported.
+ NOTREACHED();
+ return 0.0;
+}
+
+CefRefPtr<CefBrowser> RootWindowViews::GetBrowser() const {
+ REQUIRE_MAIN_THREAD();
+ return browser_;
+}
+
+ClientWindowHandle RootWindowViews::GetWindowHandle() const {
+ REQUIRE_MAIN_THREAD();
+#if defined(OS_LINUX)
+ // ClientWindowHandle is a GtkWidget* on Linux and we don't have one of those.
+ return nullptr;
+#else
+ if (browser_) {
+ return browser_->GetHost()->GetWindowHandle();
+ }
+ return kNullWindowHandle;
+#endif
+}
+
+bool RootWindowViews::WithExtension() const {
+ DCHECK(initialized_);
+ return config_->with_extension;
+}
+
+bool RootWindowViews::WithControls() {
+ DCHECK(initialized_);
+ return config_->with_controls;
+}
+
+bool RootWindowViews::WithExtension() {
+ DCHECK(initialized_);
+ return config_->with_extension;
+}
+
+void RootWindowViews::OnExtensionsChanged(const ExtensionSet& extensions) {
+ if (!CefCurrentlyOn(TID_UI)) {
+ // Execute this method on the UI thread.
+ CefPostTask(TID_UI, base::BindOnce(&RootWindowViews::OnExtensionsChanged,
+ this, extensions));
+ return;
+ }
+
+ if (window_) {
+ window_->OnExtensionsChanged(extensions);
+ } else {
+ // Window may not exist yet for popups.
+ pending_extensions_ = extensions;
+ }
+}
+
+bool RootWindowViews::InitiallyHidden() {
+ CEF_REQUIRE_UI_THREAD();
+ return config_->initially_hidden;
+}
+
+CefRefPtr<CefWindow> RootWindowViews::GetParentWindow() {
+ CEF_REQUIRE_UI_THREAD();
+ return config_->parent_window;
+}
+
+CefRect RootWindowViews::GetInitialBounds() {
+ CEF_REQUIRE_UI_THREAD();
+ return initial_bounds_;
+}
+
+cef_show_state_t RootWindowViews::GetInitialShowState() {
+ CEF_REQUIRE_UI_THREAD();
+ return initial_show_state_;
+}
+
+scoped_refptr<ImageCache> RootWindowViews::GetImageCache() {
+ CEF_REQUIRE_UI_THREAD();
+ return image_cache_;
+}
+
+void RootWindowViews::OnViewsWindowCreated(CefRefPtr<ViewsWindow> window) {
+ CEF_REQUIRE_UI_THREAD();
+ DCHECK(!window_);
+ window_ = window;
+ window_->SetAlwaysOnTop(config_->always_on_top);
+
+ if (!pending_extensions_.empty()) {
+ window_->OnExtensionsChanged(pending_extensions_);
+ pending_extensions_.clear();
+ }
+}
+
+void RootWindowViews::OnViewsWindowClosing(CefRefPtr<ViewsWindow> window) {
+ CEF_REQUIRE_UI_THREAD();
+ DCHECK(window_);
+
+ cef_show_state_t show_state;
+ std::optional<CefRect> dip_bounds;
+ if (window_->GetWindowRestorePreferences(show_state, dip_bounds)) {
+ prefs::SaveWindowRestorePreferences(show_state, dip_bounds);
+ }
+}
+
+void RootWindowViews::OnViewsWindowDestroyed(CefRefPtr<ViewsWindow> window) {
+ CEF_REQUIRE_UI_THREAD();
+ window_ = nullptr;
+
+ // Continue on the main thread.
+ MAIN_POST_CLOSURE(
+ base::BindOnce(&RootWindowViews::NotifyViewsWindowDestroyed, this));
+}
+
+void RootWindowViews::OnViewsWindowActivated(CefRefPtr<ViewsWindow> window) {
+ CEF_REQUIRE_UI_THREAD();
+
+ // Continue on the main thread.
+ MAIN_POST_CLOSURE(
+ base::BindOnce(&RootWindowViews::NotifyViewsWindowActivated, this));
+}
+
+ViewsWindow::Delegate* RootWindowViews::GetDelegateForPopup(
+ CefRefPtr<CefClient> client) {
+ CEF_REQUIRE_UI_THREAD();
+ // |handler| was created in RootWindowViews::InitAsPopup().
+ ClientHandlerStd* handler = static_cast<ClientHandlerStd*>(client.get());
+ RootWindowViews* root_window =
+ static_cast<RootWindowViews*>(handler->delegate());
+
+ // May be nullptr when using the default popup behavior.
+ if (root_window) {
+ // Transfer some state to the child RootWindowViews.
+ root_window->image_cache_ = image_cache_;
+ }
+
+ return root_window;
+}
+
+void RootWindowViews::CreateExtensionWindow(CefRefPtr<CefExtension> extension,
+ const CefRect& source_bounds,
+ CefRefPtr<CefWindow> parent_window,
+ base::OnceClosure close_callback) {
+ if (!CURRENTLY_ON_MAIN_THREAD()) {
+ // Execute this method on the main thread.
+ MAIN_POST_CLOSURE(base::BindOnce(&RootWindowViews::CreateExtensionWindow,
+ this, extension, source_bounds,
+ parent_window, std::move(close_callback)));
+ return;
+ }
+
+ delegate_->CreateExtensionWindow(extension, source_bounds, parent_window,
+ std::move(close_callback), false);
+}
+
+void RootWindowViews::OnTest(int test_id) {
+ if (!CURRENTLY_ON_MAIN_THREAD()) {
+ // Execute this method on the main thread.
+ MAIN_POST_CLOSURE(base::BindOnce(&RootWindowViews::OnTest, this, test_id));
+ return;
+ }
+
+ delegate_->OnTest(this, test_id);
+}
+
+void RootWindowViews::OnExit() {
+ if (!CURRENTLY_ON_MAIN_THREAD()) {
+ // Execute this method on the main thread.
+ MAIN_POST_CLOSURE(base::BindOnce(&RootWindowViews::OnExit, this));
+ return;
+ }
+
+ delegate_->OnExit(this);
+}
+
+void RootWindowViews::OnBrowserCreated(CefRefPtr<CefBrowser> browser) {
+ REQUIRE_MAIN_THREAD();
+ DCHECK(!browser_);
+ browser_ = browser;
+ delegate_->OnBrowserCreated(this, browser);
+}
+
+void RootWindowViews::OnBrowserClosing(CefRefPtr<CefBrowser> browser) {
+ REQUIRE_MAIN_THREAD();
+ // Nothing to do here.
+}
+
+void RootWindowViews::OnBrowserClosed(CefRefPtr<CefBrowser> browser) {
+ REQUIRE_MAIN_THREAD();
+ if (browser_) {
+ DCHECK_EQ(browser->GetIdentifier(), browser_->GetIdentifier());
+ browser_ = nullptr;
+ }
+
+ client_handler_->DetachDelegate();
+ client_handler_ = nullptr;
+
+ browser_destroyed_ = true;
+ NotifyDestroyedIfDone();
+}
+
+void RootWindowViews::OnSetAddress(const std::string& url) {
+ if (!CefCurrentlyOn(TID_UI)) {
+ // Execute this method on the UI thread.
+ CefPostTask(TID_UI,
+ base::BindOnce(&RootWindowViews::OnSetAddress, this, url));
+ return;
+ }
+
+ if (window_) {
+ window_->SetAddress(url);
+ }
+}
+
+void RootWindowViews::OnSetTitle(const std::string& title) {
+ if (!CefCurrentlyOn(TID_UI)) {
+ // Execute this method on the UI thread.
+ CefPostTask(TID_UI,
+ base::BindOnce(&RootWindowViews::OnSetTitle, this, title));
+ return;
+ }
+
+ if (window_) {
+ window_->SetTitle(title);
+ }
+}
+
+void RootWindowViews::OnSetFavicon(CefRefPtr<CefImage> image) {
+ if (!CefCurrentlyOn(TID_UI)) {
+ // Execute this method on the UI thread.
+ CefPostTask(TID_UI,
+ base::BindOnce(&RootWindowViews::OnSetFavicon, this, image));
+ return;
+ }
+
+ if (window_) {
+ window_->SetFavicon(image);
+ }
+}
+
+void RootWindowViews::OnSetFullscreen(bool fullscreen) {
+ if (!CefCurrentlyOn(TID_UI)) {
+ // Execute this method on the UI thread.
+ CefPostTask(TID_UI, base::BindOnce(&RootWindowViews::OnSetFullscreen, this,
+ fullscreen));
+ return;
+ }
+
+ if (window_) {
+ window_->SetFullscreen(fullscreen);
+ }
+}
+
+void RootWindowViews::OnAutoResize(const CefSize& new_size) {
+ if (!CefCurrentlyOn(TID_UI)) {
+ // Execute this method on the UI thread.
+ CefPostTask(TID_UI,
+ base::BindOnce(&RootWindowViews::OnAutoResize, this, new_size));
+ return;
+ }
+
+ bool has_position = false;
+ CefPoint position;
+ if (position_on_resize_) {
+ // Position the window centered on and immediately below the source.
+ const int x_offset = (initial_bounds_.width - new_size.width) / 2;
+ position.Set(initial_bounds_.x + x_offset,
+ initial_bounds_.y + initial_bounds_.height);
+ has_position = true;
+
+ // Don't change the window position on future resizes.
+ position_on_resize_ = false;
+ }
+
+ if (window_) {
+ window_->SetBrowserSize(new_size, has_position, position);
+ window_->Show();
+ }
+}
+
+void RootWindowViews::OnSetLoadingState(bool isLoading,
+ bool canGoBack,
+ bool canGoForward) {
+ if (!CefCurrentlyOn(TID_UI)) {
+ // Execute this method on the UI thread.
+ CefPostTask(TID_UI,
+ base::BindOnce(&RootWindowViews::OnSetLoadingState, this,
+ isLoading, canGoBack, canGoForward));
+ return;
+ }
+
+ if (window_) {
+ window_->SetLoadingState(isLoading, canGoBack, canGoForward);
+
+ if (isLoading) {
+ // Reset to the default window icon when loading begins.
+ window_->SetFavicon(
+ delegate_->GetImageCache()->GetCachedImage("window_icon"));
+ }
+ }
+}
+
+void RootWindowViews::OnSetDraggableRegions(
+ const std::vector<CefDraggableRegion>& regions) {
+ if (!CefCurrentlyOn(TID_UI)) {
+ // Execute this method on the UI thread.
+ CefPostTask(TID_UI, base::BindOnce(&RootWindowViews::OnSetDraggableRegions,
+ this, regions));
+ return;
+ }
+
+ if (window_) {
+ window_->SetDraggableRegions(regions);
+ }
+}
+
+void RootWindowViews::OnTakeFocus(bool next) {
+ if (!CefCurrentlyOn(TID_UI)) {
+ // Execute this method on the UI thread.
+ CefPostTask(TID_UI,
+ base::BindOnce(&RootWindowViews::OnTakeFocus, this, next));
+ return;
+ }
+
+ if (window_) {
+ window_->TakeFocus(next);
+ }
+}
+
+void RootWindowViews::OnBeforeContextMenu(CefRefPtr<CefMenuModel> model) {
+ CEF_REQUIRE_UI_THREAD();
+ if (window_) {
+ window_->OnBeforeContextMenu(model);
+ }
+}
+
+void RootWindowViews::CreateClientHandler(const std::string& url) {
+ DCHECK(!client_handler_);
+
+ client_handler_ = new ClientHandlerStd(this, config_->with_controls, url);
+ client_handler_->set_download_favicon_images(true);
+}
+
+void RootWindowViews::InitOnUIThread(
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefRequestContext> request_context) {
+ if (!CefCurrentlyOn(TID_UI)) {
+ // Execute this method on the UI thread.
+ CefPostTask(TID_UI, base::BindOnce(&RootWindowViews::InitOnUIThread, this,
+ settings, request_context));
+ return;
+ }
+
+ if (config_->initially_hidden && !config_->source_bounds.IsEmpty()) {
+ // The window will be sized and positioned in OnAutoResize().
+ initial_bounds_ = config_->source_bounds;
+ position_on_resize_ = true;
+ } else if (!config_->bounds.IsEmpty()) {
+ // Initial state was specified via the config object.
+ initial_bounds_ = config_->bounds;
+ initial_show_state_ = config_->show_state;
+ } else {
+ // Initial state may be specified via the command-line or global
+ // preferences.
+ std::optional<CefRect> bounds;
+ if (prefs::LoadWindowRestorePreferences(initial_show_state_, bounds) &&
+ bounds) {
+ initial_bounds_ = *bounds;
+ }
+ }
+
+ image_cache_ = delegate_->GetImageCache();
+
+ // Populate the default image cache.
+ ImageCache::ImageInfoSet image_set;
+ for (size_t i = 0U; i < std::size(kDefaultImageCache); ++i) {
+ image_set.push_back(ImageCache::ImageInfo::Create2x(kDefaultImageCache[i]));
+ }
+
+ image_cache_->LoadImages(
+ image_set, base::BindOnce(&RootWindowViews::CreateViewsWindow, this,
+ settings, request_context));
+}
+
+void RootWindowViews::CreateViewsWindow(
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefRequestContext> request_context,
+ const ImageCache::ImageSet& images) {
+ CEF_REQUIRE_UI_THREAD();
+ DCHECK(!window_);
+
+#ifndef NDEBUG
+ // Make sure the default images loaded successfully.
+ DCHECK_EQ(images.size(), std::size(kDefaultImageCache));
+ for (size_t i = 0U; i < std::size(kDefaultImageCache); ++i) {
+ DCHECK(images[i]) << "Default image " << i << " failed to load";
+ }
+#endif
+
+ // Create the ViewsWindow. It will show itself after creation.
+ ViewsWindow::Create(this, client_handler_, config_->url, settings,
+ request_context);
+}
+
+void RootWindowViews::NotifyViewsWindowDestroyed() {
+ REQUIRE_MAIN_THREAD();
+ window_destroyed_ = true;
+ NotifyDestroyedIfDone();
+}
+
+void RootWindowViews::NotifyViewsWindowActivated() {
+ REQUIRE_MAIN_THREAD();
+ delegate_->OnRootWindowActivated(this);
+}
+
+void RootWindowViews::NotifyDestroyedIfDone() {
+ // Notify once both the window and the browser have been destroyed.
+ if (window_destroyed_ && browser_destroyed_) {
+ // The delegate may be holding the last reference to |this|, so take a
+ // reference here to keep |this| alive until after the method completes.
+ scoped_refptr<RootWindow> self = this;
+
+ delegate_->OnRootWindowDestroyed(this);
+ if (!config_->close_callback.is_null()) {
+ std::move(config_->close_callback).Run();
+ }
+ }
+}
+
+} // namespace client
diff --git a/tests/cefclient/browser/root_window_views.h b/tests/cefclient/browser/root_window_views.h
new file mode 100644
index 00000000..75997e1a
--- /dev/null
+++ b/tests/cefclient/browser/root_window_views.h
@@ -0,0 +1,129 @@
+// Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_ROOT_WINDOW_VIEWS_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_ROOT_WINDOW_VIEWS_H_
+#pragma once
+
+#include <memory>
+#include <string>
+
+#include "tests/cefclient/browser/client_handler.h"
+#include "tests/cefclient/browser/root_window.h"
+#include "tests/cefclient/browser/views_window.h"
+
+namespace client {
+
+// Views framework implementation of a top-level window in the browser process.
+// The methods of this class must be called on the main thread unless otherwise
+// indicated.
+class RootWindowViews : public RootWindow,
+ public ClientHandler::Delegate,
+ public ViewsWindow::Delegate {
+ public:
+ // Constructor may be called on any thread.
+ RootWindowViews();
+ ~RootWindowViews();
+
+ void SetTitlebarHeight(const std::optional<float>& height);
+
+ // RootWindow methods:
+ void Init(RootWindow::Delegate* delegate,
+ std::unique_ptr<RootWindowConfig> config,
+ const CefBrowserSettings& settings) override;
+ void InitAsPopup(RootWindow::Delegate* delegate,
+ bool with_controls,
+ bool with_osr,
+ const CefPopupFeatures& popupFeatures,
+ CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient>& client,
+ CefBrowserSettings& settings) override;
+ void Show(ShowMode mode) override;
+ void Hide() override;
+ void SetBounds(int x, int y, size_t width, size_t height) override;
+ void Close(bool force) override;
+ void SetDeviceScaleFactor(float device_scale_factor) override;
+ float GetDeviceScaleFactor() const override;
+ CefRefPtr<CefBrowser> GetBrowser() const override;
+ ClientWindowHandle GetWindowHandle() const override;
+ bool WithWindowlessRendering() const override { return false; }
+ bool WithExtension() const override;
+ void OnExtensionsChanged(const ExtensionSet& extensions) override;
+
+ // ViewsWindow::Delegate methods:
+ bool WithControls() override;
+ bool WithExtension() override;
+ bool InitiallyHidden() override;
+ CefRefPtr<CefWindow> GetParentWindow() override;
+ CefRect GetInitialBounds() override;
+ cef_show_state_t GetInitialShowState() override;
+ scoped_refptr<ImageCache> GetImageCache() override;
+ void OnViewsWindowCreated(CefRefPtr<ViewsWindow> window) override;
+ void OnViewsWindowClosing(CefRefPtr<ViewsWindow> window) override;
+ void OnViewsWindowDestroyed(CefRefPtr<ViewsWindow> window) override;
+ void OnViewsWindowActivated(CefRefPtr<ViewsWindow> window) override;
+ ViewsWindow::Delegate* GetDelegateForPopup(
+ CefRefPtr<CefClient> client) override;
+ void CreateExtensionWindow(CefRefPtr<CefExtension> extension,
+ const CefRect& source_bounds,
+ CefRefPtr<CefWindow> parent_window,
+ base::OnceClosure close_callback) override;
+ void OnTest(int test_id) override;
+ void OnExit() override;
+
+ protected:
+ // ClientHandler::Delegate methods:
+ void OnBrowserCreated(CefRefPtr<CefBrowser> browser) override;
+ void OnBrowserClosing(CefRefPtr<CefBrowser> browser) override;
+ void OnBrowserClosed(CefRefPtr<CefBrowser> browser) override;
+ void OnSetAddress(const std::string& url) override;
+ void OnSetTitle(const std::string& title) override;
+ void OnSetFavicon(CefRefPtr<CefImage> image) override;
+ void OnSetFullscreen(bool fullscreen) override;
+ void OnAutoResize(const CefSize& new_size) override;
+ void OnSetLoadingState(bool isLoading,
+ bool canGoBack,
+ bool canGoForward) override;
+ void OnSetDraggableRegions(
+ const std::vector<CefDraggableRegion>& regions) override;
+ void OnTakeFocus(bool next) override;
+ void OnBeforeContextMenu(CefRefPtr<CefMenuModel> model) override;
+
+ private:
+ void CreateClientHandler(const std::string& url);
+
+ void InitOnUIThread(const CefBrowserSettings& settings,
+ CefRefPtr<CefRequestContext> request_context);
+ void CreateViewsWindow(const CefBrowserSettings& settings,
+ CefRefPtr<CefRequestContext> request_context,
+ const ImageCache::ImageSet& images);
+
+ void NotifyViewsWindowDestroyed();
+ void NotifyViewsWindowActivated();
+ void NotifyDestroyedIfDone();
+
+ // Members set during initialization. Safe to access from any thread.
+ std::unique_ptr<RootWindowConfig> config_;
+ CefRefPtr<ClientHandler> client_handler_;
+ bool initialized_ = false;
+
+ // Only accessed on the main thread.
+ CefRefPtr<CefBrowser> browser_;
+ bool window_destroyed_ = false;
+ bool browser_destroyed_ = false;
+
+ // Only accessed on the browser process UI thread.
+ CefRect initial_bounds_;
+ cef_show_state_t initial_show_state_ = CEF_SHOW_STATE_NORMAL;
+ bool position_on_resize_ = false;
+ CefRefPtr<ViewsWindow> window_;
+ ExtensionSet pending_extensions_;
+ scoped_refptr<ImageCache> image_cache_;
+
+ DISALLOW_COPY_AND_ASSIGN(RootWindowViews);
+};
+
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_ROOT_WINDOW_VIEWS_H_
diff --git a/tests/cefclient/browser/root_window_win.cc b/tests/cefclient/browser/root_window_win.cc
new file mode 100644
index 00000000..1a03cf22
--- /dev/null
+++ b/tests/cefclient/browser/root_window_win.cc
@@ -0,0 +1,1314 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/root_window_win.h"
+
+#include <shellscalingapi.h>
+
+#include <optional>
+
+#include "include/base/cef_build.h"
+#include "include/base/cef_callback.h"
+#include "include/cef_app.h"
+#include "include/views/cef_display.h"
+#include "tests/cefclient/browser/browser_window_osr_win.h"
+#include "tests/cefclient/browser/browser_window_std_win.h"
+#include "tests/cefclient/browser/client_prefs.h"
+#include "tests/cefclient/browser/main_context.h"
+#include "tests/cefclient/browser/resource.h"
+#include "tests/cefclient/browser/temp_window.h"
+#include "tests/cefclient/browser/window_test_runner_win.h"
+#include "tests/shared/browser/geometry_util.h"
+#include "tests/shared/browser/main_message_loop.h"
+#include "tests/shared/browser/util_win.h"
+#include "tests/shared/common/client_switches.h"
+
+#define MAX_URL_LENGTH 255
+#define BUTTON_WIDTH 72
+#define URLBAR_HEIGHT 24
+
+namespace client {
+
+namespace {
+
+// Message handler for the About box.
+INT_PTR CALLBACK AboutWndProc(HWND hDlg,
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam) {
+ UNREFERENCED_PARAMETER(lParam);
+ switch (message) {
+ case WM_INITDIALOG:
+ return TRUE;
+
+ case WM_COMMAND:
+ if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) {
+ EndDialog(hDlg, LOWORD(wParam));
+ return TRUE;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+// Returns true if the process is per monitor DPI aware.
+bool IsProcessPerMonitorDpiAware() {
+ enum class PerMonitorDpiAware {
+ UNKNOWN = 0,
+ PER_MONITOR_DPI_UNAWARE,
+ PER_MONITOR_DPI_AWARE,
+ };
+ static PerMonitorDpiAware per_monitor_dpi_aware = PerMonitorDpiAware::UNKNOWN;
+ if (per_monitor_dpi_aware == PerMonitorDpiAware::UNKNOWN) {
+ per_monitor_dpi_aware = PerMonitorDpiAware::PER_MONITOR_DPI_UNAWARE;
+ HMODULE shcore_dll = ::LoadLibrary(L"shcore.dll");
+ if (shcore_dll) {
+ typedef HRESULT(WINAPI * GetProcessDpiAwarenessPtr)(
+ HANDLE, PROCESS_DPI_AWARENESS*);
+ GetProcessDpiAwarenessPtr func_ptr =
+ reinterpret_cast<GetProcessDpiAwarenessPtr>(
+ ::GetProcAddress(shcore_dll, "GetProcessDpiAwareness"));
+ if (func_ptr) {
+ PROCESS_DPI_AWARENESS awareness;
+ if (SUCCEEDED(func_ptr(nullptr, &awareness)) &&
+ awareness == PROCESS_PER_MONITOR_DPI_AWARE) {
+ per_monitor_dpi_aware = PerMonitorDpiAware::PER_MONITOR_DPI_AWARE;
+ }
+ }
+ }
+ }
+ return per_monitor_dpi_aware == PerMonitorDpiAware::PER_MONITOR_DPI_AWARE;
+}
+
+// DPI value for 1x scale factor.
+#define DPI_1X 96.0f
+
+float GetWindowScaleFactor(HWND hwnd) {
+ if (hwnd && IsProcessPerMonitorDpiAware()) {
+ typedef UINT(WINAPI * GetDpiForWindowPtr)(HWND);
+ static GetDpiForWindowPtr func_ptr = reinterpret_cast<GetDpiForWindowPtr>(
+ GetProcAddress(GetModuleHandle(L"user32.dll"), "GetDpiForWindow"));
+ if (func_ptr) {
+ return static_cast<float>(func_ptr(hwnd)) / DPI_1X;
+ }
+ }
+
+ return client::GetDeviceScaleFactor();
+}
+
+int GetButtonWidth(HWND hwnd) {
+ return LogicalToDevice(BUTTON_WIDTH, GetWindowScaleFactor(hwnd));
+}
+
+int GetURLBarHeight(HWND hwnd) {
+ return LogicalToDevice(URLBAR_HEIGHT, GetWindowScaleFactor(hwnd));
+}
+
+} // namespace
+
+RootWindowWin::RootWindowWin() {
+ // Create a HRGN representing the draggable window area.
+ draggable_region_ = ::CreateRectRgn(0, 0, 0, 0);
+}
+
+RootWindowWin::~RootWindowWin() {
+ REQUIRE_MAIN_THREAD();
+
+ ::DeleteObject(draggable_region_);
+ ::DeleteObject(font_);
+
+ // The window and browser should already have been destroyed.
+ DCHECK(window_destroyed_);
+ DCHECK(browser_destroyed_);
+}
+
+void RootWindowWin::Init(RootWindow::Delegate* delegate,
+ std::unique_ptr<RootWindowConfig> config,
+ const CefBrowserSettings& settings) {
+ DCHECK(delegate);
+ DCHECK(!initialized_);
+
+ delegate_ = delegate;
+ with_controls_ = config->with_controls;
+ always_on_top_ = config->always_on_top;
+ with_osr_ = config->with_osr;
+ with_extension_ = config->with_extension;
+
+ CreateBrowserWindow(config->url);
+
+ if (CefCurrentlyOn(TID_UI)) {
+ ContinueInitOnUIThread(std::move(config), settings);
+ } else {
+ CefPostTask(TID_UI, base::BindOnce(&RootWindowWin::ContinueInitOnUIThread,
+ this, std::move(config), settings));
+ }
+}
+
+void RootWindowWin::ContinueInitOnUIThread(
+ std::unique_ptr<RootWindowConfig> config,
+ const CefBrowserSettings& settings) {
+ CEF_REQUIRE_UI_THREAD();
+
+ if (!config->bounds.IsEmpty()) {
+ // Initial state was specified via the config object.
+ initial_bounds_ = config->bounds;
+ initial_show_state_ = config->show_state;
+ } else {
+ // Initial state may be specified via the command-line or global
+ // preferences.
+ std::optional<CefRect> bounds;
+ if (prefs::LoadWindowRestorePreferences(initial_show_state_, bounds) &&
+ bounds) {
+ initial_bounds_ = CefDisplay::ConvertScreenRectToPixels(*bounds);
+ }
+ }
+
+ MAIN_POST_CLOSURE(base::BindOnce(&RootWindowWin::ContinueInitOnMainThread,
+ this, std::move(config), settings));
+}
+
+void RootWindowWin::ContinueInitOnMainThread(
+ std::unique_ptr<RootWindowConfig> config,
+ const CefBrowserSettings& settings) {
+ REQUIRE_MAIN_THREAD();
+
+ initialized_ = true;
+
+ CreateRootWindow(settings, config->initially_hidden);
+}
+
+void RootWindowWin::InitAsPopup(RootWindow::Delegate* delegate,
+ bool with_controls,
+ bool with_osr,
+ const CefPopupFeatures& popupFeatures,
+ CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient>& client,
+ CefBrowserSettings& settings) {
+ CEF_REQUIRE_UI_THREAD();
+
+ DCHECK(delegate);
+ DCHECK(!initialized_);
+
+ delegate_ = delegate;
+ with_controls_ = with_controls;
+ with_osr_ = with_osr;
+ is_popup_ = true;
+
+ if (popupFeatures.xSet) {
+ initial_bounds_.x = popupFeatures.x;
+ }
+ if (popupFeatures.ySet) {
+ initial_bounds_.y = popupFeatures.y;
+ }
+ if (popupFeatures.widthSet) {
+ initial_bounds_.width = popupFeatures.width;
+ }
+ if (popupFeatures.heightSet) {
+ initial_bounds_.height = popupFeatures.height;
+ }
+
+ CreateBrowserWindow(std::string());
+
+ initialized_ = true;
+
+ // The new popup is initially parented to a temporary window. The native root
+ // window will be created after the browser is created and the popup window
+ // will be re-parented to it at that time.
+ browser_window_->GetPopupConfig(TempWindow::GetWindowHandle(), windowInfo,
+ client, settings);
+}
+
+void RootWindowWin::Show(ShowMode mode) {
+ REQUIRE_MAIN_THREAD();
+
+ if (!hwnd_) {
+ return;
+ }
+
+ int nCmdShow = SW_SHOWNORMAL;
+ switch (mode) {
+ case ShowMinimized:
+ nCmdShow = SW_SHOWMINIMIZED;
+ break;
+ case ShowMaximized:
+ nCmdShow = SW_SHOWMAXIMIZED;
+ break;
+ case ShowNoActivate:
+ nCmdShow = SW_SHOWNOACTIVATE;
+ break;
+ default:
+ break;
+ }
+
+ ShowWindow(hwnd_, nCmdShow);
+ if (mode != ShowMinimized) {
+ UpdateWindow(hwnd_);
+ }
+}
+
+void RootWindowWin::Hide() {
+ REQUIRE_MAIN_THREAD();
+
+ if (hwnd_) {
+ ShowWindow(hwnd_, SW_HIDE);
+ }
+}
+
+void RootWindowWin::SetBounds(int x, int y, size_t width, size_t height) {
+ REQUIRE_MAIN_THREAD();
+
+ if (hwnd_) {
+ SetWindowPos(hwnd_, nullptr, x, y, static_cast<int>(width),
+ static_cast<int>(height), SWP_NOZORDER);
+ }
+}
+
+void RootWindowWin::Close(bool force) {
+ REQUIRE_MAIN_THREAD();
+
+ if (hwnd_) {
+ if (force) {
+ DestroyWindow(hwnd_);
+ } else {
+ PostMessage(hwnd_, WM_CLOSE, 0, 0);
+ }
+ }
+}
+
+void RootWindowWin::SetDeviceScaleFactor(float device_scale_factor) {
+ REQUIRE_MAIN_THREAD();
+
+ if (browser_window_ && with_osr_) {
+ browser_window_->SetDeviceScaleFactor(device_scale_factor);
+ }
+}
+
+float RootWindowWin::GetDeviceScaleFactor() const {
+ REQUIRE_MAIN_THREAD();
+
+ if (browser_window_ && with_osr_) {
+ return browser_window_->GetDeviceScaleFactor();
+ }
+
+ NOTREACHED();
+ return 0.0f;
+}
+
+CefRefPtr<CefBrowser> RootWindowWin::GetBrowser() const {
+ REQUIRE_MAIN_THREAD();
+
+ if (browser_window_) {
+ return browser_window_->GetBrowser();
+ }
+ return nullptr;
+}
+
+ClientWindowHandle RootWindowWin::GetWindowHandle() const {
+ REQUIRE_MAIN_THREAD();
+ return hwnd_;
+}
+
+bool RootWindowWin::WithWindowlessRendering() const {
+ REQUIRE_MAIN_THREAD();
+ return with_osr_;
+}
+
+bool RootWindowWin::WithExtension() const {
+ REQUIRE_MAIN_THREAD();
+ return with_extension_;
+}
+
+void RootWindowWin::CreateBrowserWindow(const std::string& startup_url) {
+ if (with_osr_) {
+ OsrRendererSettings settings = {};
+ MainContext::Get()->PopulateOsrSettings(&settings);
+ browser_window_.reset(
+ new BrowserWindowOsrWin(this, with_controls_, startup_url, settings));
+ } else {
+ browser_window_.reset(
+ new BrowserWindowStdWin(this, with_controls_, startup_url));
+ }
+}
+
+void RootWindowWin::CreateRootWindow(const CefBrowserSettings& settings,
+ bool initially_hidden) {
+ REQUIRE_MAIN_THREAD();
+ DCHECK(!hwnd_);
+
+ HINSTANCE hInstance = GetModuleHandle(nullptr);
+
+ // Load strings from the resource file.
+ const std::wstring& window_title = GetResourceString(IDS_APP_TITLE);
+ const std::wstring& window_class = GetResourceString(IDC_CEFCLIENT);
+
+ const cef_color_t background_color = MainContext::Get()->GetBackgroundColor();
+ const HBRUSH background_brush = CreateSolidBrush(
+ RGB(CefColorGetR(background_color), CefColorGetG(background_color),
+ CefColorGetB(background_color)));
+
+ // Register the window class.
+ RegisterRootClass(hInstance, window_class, background_brush);
+
+ // Register the message used with the find dialog.
+ find_message_id_ = RegisterWindowMessage(FINDMSGSTRING);
+ CHECK(find_message_id_);
+
+ CefRefPtr<CefCommandLine> command_line =
+ CefCommandLine::GetGlobalCommandLine();
+ const bool no_activate = command_line->HasSwitch(switches::kNoActivate);
+
+ DWORD dwStyle = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN;
+ DWORD dwExStyle = always_on_top_ ? WS_EX_TOPMOST : 0;
+ if (no_activate) {
+ // Don't activate the browser window on creation.
+ dwExStyle |= WS_EX_NOACTIVATE;
+ }
+
+ if (initial_show_state_ == CEF_SHOW_STATE_MAXIMIZED) {
+ dwStyle |= WS_MAXIMIZE;
+ } else if (initial_show_state_ == CEF_SHOW_STATE_MINIMIZED) {
+ dwStyle |= WS_MINIMIZE;
+ }
+
+ int x, y, width, height;
+ if (initial_bounds_.IsEmpty()) {
+ // Use the default window position/size.
+ x = y = width = height = CW_USEDEFAULT;
+ } else {
+ x = initial_bounds_.x;
+ y = initial_bounds_.y;
+ width = initial_bounds_.width;
+ height = initial_bounds_.height;
+
+ if (is_popup_) {
+ // Adjust the window size to account for window frame and controls. Keep
+ // the origin unchanged.
+ RECT window_rect = {x, y, x + width, y + height};
+ ::AdjustWindowRectEx(&window_rect, dwStyle, with_controls_, dwExStyle);
+ width = window_rect.right - window_rect.left;
+ height = window_rect.bottom - window_rect.top;
+ }
+ }
+
+ browser_settings_ = settings;
+
+ // Create the main window initially hidden.
+ CreateWindowEx(dwExStyle, window_class.c_str(), window_title.c_str(), dwStyle,
+ x, y, width, height, nullptr, nullptr, hInstance, this);
+ CHECK(hwnd_);
+
+ if (!called_enable_non_client_dpi_scaling_ && IsProcessPerMonitorDpiAware()) {
+ // This call gets Windows to scale the non-client area when WM_DPICHANGED
+ // is fired on Windows versions < 10.0.14393.0.
+ // Derived signature; not available in headers.
+ typedef LRESULT(WINAPI * EnableChildWindowDpiMessagePtr)(HWND, BOOL);
+ static EnableChildWindowDpiMessagePtr func_ptr =
+ reinterpret_cast<EnableChildWindowDpiMessagePtr>(GetProcAddress(
+ GetModuleHandle(L"user32.dll"), "EnableChildWindowDpiMessage"));
+ if (func_ptr) {
+ func_ptr(hwnd_, TRUE);
+ }
+ }
+
+ if (!initially_hidden) {
+ ShowMode mode = ShowNormal;
+ if (no_activate) {
+ mode = ShowNoActivate;
+ } else if (initial_show_state_ == CEF_SHOW_STATE_MAXIMIZED) {
+ mode = ShowMaximized;
+ } else if (initial_show_state_ == CEF_SHOW_STATE_MINIMIZED) {
+ mode = ShowMinimized;
+ }
+
+ // Show this window.
+ Show(mode);
+ }
+}
+
+// static
+void RootWindowWin::RegisterRootClass(HINSTANCE hInstance,
+ const std::wstring& window_class,
+ HBRUSH background_brush) {
+ // Only register the class one time.
+ static bool class_registered = false;
+ if (class_registered) {
+ return;
+ }
+ class_registered = true;
+
+ WNDCLASSEX wcex;
+
+ wcex.cbSize = sizeof(WNDCLASSEX);
+
+ wcex.style = CS_HREDRAW | CS_VREDRAW;
+ wcex.lpfnWndProc = RootWndProc;
+ wcex.cbClsExtra = 0;
+ wcex.cbWndExtra = 0;
+ wcex.hInstance = hInstance;
+ wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_CEFCLIENT));
+ wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
+ wcex.hbrBackground = background_brush;
+ wcex.lpszMenuName = MAKEINTRESOURCE(IDC_CEFCLIENT);
+ wcex.lpszClassName = window_class.c_str();
+ wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
+
+ RegisterClassEx(&wcex);
+}
+
+// static
+LRESULT CALLBACK RootWindowWin::EditWndProc(HWND hWnd,
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam) {
+ REQUIRE_MAIN_THREAD();
+
+ RootWindowWin* self = GetUserDataPtr<RootWindowWin*>(hWnd);
+ DCHECK(self);
+ DCHECK(hWnd == self->edit_hwnd_);
+
+ switch (message) {
+ case WM_CHAR:
+ if (wParam == VK_RETURN) {
+ // When the user hits the enter key load the URL.
+ CefRefPtr<CefBrowser> browser = self->GetBrowser();
+ if (browser) {
+ wchar_t strPtr[MAX_URL_LENGTH + 1] = {0};
+ *((LPWORD)strPtr) = MAX_URL_LENGTH;
+ LRESULT strLen = SendMessage(hWnd, EM_GETLINE, 0, (LPARAM)strPtr);
+ if (strLen > 0) {
+ strPtr[strLen] = 0;
+ browser->GetMainFrame()->LoadURL(strPtr);
+ }
+ }
+ return 0;
+ }
+ break;
+ case WM_NCDESTROY:
+ // Clear the reference to |self|.
+ SetUserDataPtr(hWnd, nullptr);
+ self->edit_hwnd_ = nullptr;
+ break;
+ }
+
+ return CallWindowProc(self->edit_wndproc_old_, hWnd, message, wParam, lParam);
+}
+
+// static
+LRESULT CALLBACK RootWindowWin::FindWndProc(HWND hWnd,
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam) {
+ REQUIRE_MAIN_THREAD();
+
+ RootWindowWin* self = GetUserDataPtr<RootWindowWin*>(hWnd);
+ DCHECK(self);
+ DCHECK(hWnd == self->find_hwnd_);
+
+ switch (message) {
+ case WM_ACTIVATE:
+ // Set this dialog as current when activated.
+ MainMessageLoop::Get()->SetCurrentModelessDialog(wParam == 0 ? nullptr
+ : hWnd);
+ return FALSE;
+ case WM_NCDESTROY:
+ // Clear the reference to |self|.
+ SetUserDataPtr(hWnd, nullptr);
+ self->find_hwnd_ = nullptr;
+ break;
+ }
+
+ return CallWindowProc(self->find_wndproc_old_, hWnd, message, wParam, lParam);
+}
+
+// static
+LRESULT CALLBACK RootWindowWin::RootWndProc(HWND hWnd,
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam) {
+ REQUIRE_MAIN_THREAD();
+
+ RootWindowWin* self = nullptr;
+ if (message != WM_NCCREATE) {
+ self = GetUserDataPtr<RootWindowWin*>(hWnd);
+ if (!self) {
+ return DefWindowProc(hWnd, message, wParam, lParam);
+ }
+ DCHECK_EQ(hWnd, self->hwnd_);
+ }
+
+ if (self && message == self->find_message_id_) {
+ // Message targeting the find dialog.
+ LPFINDREPLACE lpfr = reinterpret_cast<LPFINDREPLACE>(lParam);
+ CHECK(lpfr == &self->find_state_);
+ self->OnFindEvent();
+ return 0;
+ }
+
+ // Callback for the main window
+ switch (message) {
+ case WM_COMMAND:
+ if (self->OnCommand(LOWORD(wParam))) {
+ return 0;
+ }
+ break;
+
+ case WM_GETOBJECT: {
+ // Only the lower 32 bits of lParam are valid when checking the object id
+ // because it sometimes gets sign-extended incorrectly (but not always).
+ DWORD obj_id = static_cast<DWORD>(static_cast<DWORD_PTR>(lParam));
+
+ // Accessibility readers will send an OBJID_CLIENT message.
+ if (static_cast<DWORD>(OBJID_CLIENT) == obj_id) {
+ if (self->GetBrowser() && self->GetBrowser()->GetHost()) {
+ self->GetBrowser()->GetHost()->SetAccessibilityState(STATE_ENABLED);
+ }
+ }
+ } break;
+
+ case WM_PAINT:
+ self->OnPaint();
+ return 0;
+
+ case WM_ACTIVATE:
+ self->OnActivate(LOWORD(wParam) != WA_INACTIVE);
+ // Allow DefWindowProc to set keyboard focus.
+ break;
+
+ case WM_SETFOCUS:
+ self->OnFocus();
+ return 0;
+
+ case WM_ENABLE:
+ if (wParam == TRUE) {
+ // Give focus to the browser after EnableWindow enables this window
+ // (e.g. after a modal dialog is dismissed).
+ self->OnFocus();
+ return 0;
+ }
+ break;
+
+ case WM_SIZE:
+ self->OnSize(wParam == SIZE_MINIMIZED);
+ break;
+
+ case WM_MOVING:
+ case WM_MOVE:
+ self->OnMove();
+ return 0;
+
+ case WM_DPICHANGED:
+ self->OnDpiChanged(wParam, lParam);
+ break;
+
+ case WM_ERASEBKGND:
+ if (self->OnEraseBkgnd()) {
+ break;
+ }
+ // Don't erase the background.
+ return 0;
+
+ case WM_ENTERMENULOOP:
+ if (!wParam) {
+ // Entering the menu loop for the application menu.
+ CefSetOSModalLoop(true);
+ }
+ break;
+
+ case WM_EXITMENULOOP:
+ if (!wParam) {
+ // Exiting the menu loop for the application menu.
+ CefSetOSModalLoop(false);
+ }
+ break;
+
+ case WM_CLOSE:
+ if (self->OnClose()) {
+ return 0; // Cancel the close.
+ }
+ break;
+
+ case WM_NCHITTEST: {
+ LRESULT hit = DefWindowProc(hWnd, message, wParam, lParam);
+ if (hit == HTCLIENT) {
+ POINTS points = MAKEPOINTS(lParam);
+ POINT point = {points.x, points.y};
+ ::ScreenToClient(hWnd, &point);
+ if (::PtInRegion(self->draggable_region_, point.x, point.y)) {
+ // If cursor is inside a draggable region return HTCAPTION to allow
+ // dragging.
+ return HTCAPTION;
+ }
+ }
+ return hit;
+ }
+
+ case WM_NCCREATE: {
+ CREATESTRUCT* cs = reinterpret_cast<CREATESTRUCT*>(lParam);
+ self = reinterpret_cast<RootWindowWin*>(cs->lpCreateParams);
+ DCHECK(self);
+ // Associate |self| with the main window.
+ SetUserDataPtr(hWnd, self);
+ self->hwnd_ = hWnd;
+
+ self->OnNCCreate(cs);
+ } break;
+
+ case WM_CREATE:
+ self->OnCreate(reinterpret_cast<CREATESTRUCT*>(lParam));
+ break;
+
+ case WM_NCDESTROY:
+ // Clear the reference to |self|.
+ SetUserDataPtr(hWnd, nullptr);
+ self->hwnd_ = nullptr;
+ self->OnDestroyed();
+ break;
+ }
+
+ return DefWindowProc(hWnd, message, wParam, lParam);
+}
+
+void RootWindowWin::OnPaint() {
+ PAINTSTRUCT ps;
+ BeginPaint(hwnd_, &ps);
+ EndPaint(hwnd_, &ps);
+}
+
+void RootWindowWin::OnFocus() {
+ // Selecting "Close window" from the task bar menu may send a focus
+ // notification even though the window is currently disabled (e.g. while a
+ // modal JS dialog is displayed).
+ if (browser_window_ && ::IsWindowEnabled(hwnd_)) {
+ browser_window_->SetFocus(true);
+ }
+}
+
+void RootWindowWin::OnActivate(bool active) {
+ if (active) {
+ delegate_->OnRootWindowActivated(this);
+ }
+}
+
+void RootWindowWin::OnSize(bool minimized) {
+ if (minimized) {
+ // Notify the browser window that it was hidden and do nothing further.
+ if (browser_window_) {
+ browser_window_->Hide();
+ }
+ return;
+ }
+
+ if (browser_window_) {
+ browser_window_->Show();
+ }
+
+ RECT rect;
+ GetClientRect(hwnd_, &rect);
+
+ if (with_controls_ && edit_hwnd_) {
+ const int button_width = GetButtonWidth(hwnd_);
+ const int urlbar_height = GetURLBarHeight(hwnd_);
+ const int font_height = LogicalToDevice(14, GetWindowScaleFactor(hwnd_));
+
+ if (font_height != font_height_) {
+ font_height_ = font_height;
+ if (font_) {
+ DeleteObject(font_);
+ }
+
+ // Create a scaled font.
+ font_ =
+ ::CreateFont(-font_height, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE,
+ DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
+ DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"Arial");
+
+ SendMessage(back_hwnd_, WM_SETFONT, reinterpret_cast<WPARAM>(font_),
+ TRUE);
+ SendMessage(forward_hwnd_, WM_SETFONT, reinterpret_cast<WPARAM>(font_),
+ TRUE);
+ SendMessage(reload_hwnd_, WM_SETFONT, reinterpret_cast<WPARAM>(font_),
+ TRUE);
+ SendMessage(stop_hwnd_, WM_SETFONT, reinterpret_cast<WPARAM>(font_),
+ TRUE);
+ SendMessage(edit_hwnd_, WM_SETFONT, reinterpret_cast<WPARAM>(font_),
+ TRUE);
+ }
+
+ // Resize the window and address bar to match the new frame size.
+ rect.top += urlbar_height;
+
+ int x_offset = rect.left;
+
+ // |browser_hwnd| may be nullptr if the browser has not yet been created.
+ HWND browser_hwnd = nullptr;
+ if (browser_window_) {
+ browser_hwnd = browser_window_->GetWindowHandle();
+ }
+
+ // Resize all controls.
+ HDWP hdwp = BeginDeferWindowPos(browser_hwnd ? 6 : 5);
+ hdwp = DeferWindowPos(hdwp, back_hwnd_, nullptr, x_offset, 0, button_width,
+ urlbar_height, SWP_NOZORDER);
+ x_offset += button_width;
+ hdwp = DeferWindowPos(hdwp, forward_hwnd_, nullptr, x_offset, 0,
+ button_width, urlbar_height, SWP_NOZORDER);
+ x_offset += button_width;
+ hdwp = DeferWindowPos(hdwp, reload_hwnd_, nullptr, x_offset, 0,
+ button_width, urlbar_height, SWP_NOZORDER);
+ x_offset += button_width;
+ hdwp = DeferWindowPos(hdwp, stop_hwnd_, nullptr, x_offset, 0, button_width,
+ urlbar_height, SWP_NOZORDER);
+ x_offset += button_width;
+ hdwp = DeferWindowPos(hdwp, edit_hwnd_, nullptr, x_offset, 0,
+ rect.right - x_offset, urlbar_height, SWP_NOZORDER);
+
+ if (browser_hwnd) {
+ hdwp = DeferWindowPos(hdwp, browser_hwnd, nullptr, rect.left, rect.top,
+ rect.right - rect.left, rect.bottom - rect.top,
+ SWP_NOZORDER);
+ }
+
+ [[maybe_unused]] BOOL result = EndDeferWindowPos(hdwp);
+ DCHECK(result);
+ } else if (browser_window_) {
+ // Size the browser window to the whole client area.
+ browser_window_->SetBounds(0, 0, rect.right, rect.bottom);
+ }
+}
+
+void RootWindowWin::OnMove() {
+ // Notify the browser of move events so that popup windows are displayed
+ // in the correct location and dismissed when the window moves.
+ CefRefPtr<CefBrowser> browser = GetBrowser();
+ if (browser) {
+ browser->GetHost()->NotifyMoveOrResizeStarted();
+ }
+}
+
+void RootWindowWin::OnDpiChanged(WPARAM wParam, LPARAM lParam) {
+ if (LOWORD(wParam) != HIWORD(wParam)) {
+ NOTIMPLEMENTED() << "Received non-square scaling factors";
+ return;
+ }
+
+ if (browser_window_ && with_osr_) {
+ // Scale factor for the new display.
+ const float display_scale_factor =
+ static_cast<float>(LOWORD(wParam)) / DPI_1X;
+ browser_window_->SetDeviceScaleFactor(display_scale_factor);
+ }
+
+ // Suggested size and position of the current window scaled for the new DPI.
+ const RECT* rect = reinterpret_cast<RECT*>(lParam);
+ SetBounds(rect->left, rect->top, rect->right - rect->left,
+ rect->bottom - rect->top);
+}
+
+bool RootWindowWin::OnEraseBkgnd() {
+ // Erase the background when the browser does not exist.
+ return (GetBrowser() == nullptr);
+}
+
+bool RootWindowWin::OnCommand(UINT id) {
+ if (id >= ID_TESTS_FIRST && id <= ID_TESTS_LAST) {
+ delegate_->OnTest(this, id);
+ return true;
+ }
+
+ switch (id) {
+ case IDM_ABOUT:
+ OnAbout();
+ return true;
+ case IDM_EXIT:
+ delegate_->OnExit(this);
+ return true;
+ case ID_FIND:
+ OnFind();
+ return true;
+ case IDC_NAV_BACK: // Back button
+ if (CefRefPtr<CefBrowser> browser = GetBrowser()) {
+ browser->GoBack();
+ }
+ return true;
+ case IDC_NAV_FORWARD: // Forward button
+ if (CefRefPtr<CefBrowser> browser = GetBrowser()) {
+ browser->GoForward();
+ }
+ return true;
+ case IDC_NAV_RELOAD: // Reload button
+ if (CefRefPtr<CefBrowser> browser = GetBrowser()) {
+ browser->Reload();
+ }
+ return true;
+ case IDC_NAV_STOP: // Stop button
+ if (CefRefPtr<CefBrowser> browser = GetBrowser()) {
+ browser->StopLoad();
+ }
+ return true;
+ }
+
+ return false;
+}
+
+void RootWindowWin::OnFind() {
+ if (find_hwnd_) {
+ // Give focus to the existing find dialog.
+ ::SetFocus(find_hwnd_);
+ return;
+ }
+
+ // Configure dialog state.
+ ZeroMemory(&find_state_, sizeof(find_state_));
+ find_state_.lStructSize = sizeof(find_state_);
+ find_state_.hwndOwner = hwnd_;
+ find_state_.lpstrFindWhat = find_buff_;
+ find_state_.wFindWhatLen = sizeof(find_buff_);
+ find_state_.Flags = FR_HIDEWHOLEWORD | FR_DOWN;
+
+ // Create the dialog.
+ find_hwnd_ = FindText(&find_state_);
+
+ // Override the dialog's window procedure.
+ find_wndproc_old_ = SetWndProcPtr(find_hwnd_, FindWndProc);
+
+ // Associate |self| with the dialog.
+ SetUserDataPtr(find_hwnd_, this);
+}
+
+void RootWindowWin::OnFindEvent() {
+ CefRefPtr<CefBrowser> browser = GetBrowser();
+
+ if (find_state_.Flags & FR_DIALOGTERM) {
+ // The find dialog box has been dismissed so invalidate the handle and
+ // reset the search results.
+ if (browser) {
+ browser->GetHost()->StopFinding(true);
+ find_what_last_.clear();
+ find_next_ = false;
+ }
+ } else if ((find_state_.Flags & FR_FINDNEXT) && browser) {
+ // Search for the requested string.
+ bool match_case = ((find_state_.Flags & FR_MATCHCASE) ? true : false);
+ const std::wstring& find_what = find_buff_;
+ if (match_case != find_match_case_last_ || find_what != find_what_last_) {
+ // The search string has changed, so reset the search results.
+ if (!find_what.empty()) {
+ browser->GetHost()->StopFinding(true);
+ find_next_ = false;
+ }
+ find_match_case_last_ = match_case;
+ find_what_last_ = find_buff_;
+ }
+
+ browser->GetHost()->Find(find_what,
+ (find_state_.Flags & FR_DOWN) ? true : false,
+ match_case, find_next_);
+ if (!find_next_) {
+ find_next_ = true;
+ }
+ }
+}
+
+void RootWindowWin::OnAbout() {
+ // Show the about box.
+ DialogBox(GetModuleHandle(nullptr), MAKEINTRESOURCE(IDD_ABOUTBOX), hwnd_,
+ AboutWndProc);
+}
+
+void RootWindowWin::OnNCCreate(LPCREATESTRUCT lpCreateStruct) {
+ if (IsProcessPerMonitorDpiAware()) {
+ // This call gets Windows to scale the non-client area when WM_DPICHANGED
+ // is fired on Windows versions >= 10.0.14393.0.
+ typedef BOOL(WINAPI * EnableNonClientDpiScalingPtr)(HWND);
+ static EnableNonClientDpiScalingPtr func_ptr =
+ reinterpret_cast<EnableNonClientDpiScalingPtr>(GetProcAddress(
+ GetModuleHandle(L"user32.dll"), "EnableNonClientDpiScaling"));
+ called_enable_non_client_dpi_scaling_ = !!(func_ptr && func_ptr(hwnd_));
+ }
+}
+
+void RootWindowWin::OnCreate(LPCREATESTRUCT lpCreateStruct) {
+ const HINSTANCE hInstance = lpCreateStruct->hInstance;
+
+ RECT rect;
+ GetClientRect(hwnd_, &rect);
+
+ if (with_controls_) {
+ // Create the child controls.
+ int x_offset = 0;
+
+ const int button_width = GetButtonWidth(hwnd_);
+ const int urlbar_height = GetURLBarHeight(hwnd_);
+
+ back_hwnd_ = CreateWindow(
+ L"BUTTON", L"Back", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_DISABLED,
+ x_offset, 0, button_width, urlbar_height, hwnd_,
+ reinterpret_cast<HMENU>(IDC_NAV_BACK), hInstance, 0);
+ CHECK(back_hwnd_);
+ x_offset += button_width;
+
+ forward_hwnd_ =
+ CreateWindow(L"BUTTON", L"Forward",
+ WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_DISABLED,
+ x_offset, 0, button_width, urlbar_height, hwnd_,
+ reinterpret_cast<HMENU>(IDC_NAV_FORWARD), hInstance, 0);
+ CHECK(forward_hwnd_);
+ x_offset += button_width;
+
+ reload_hwnd_ =
+ CreateWindow(L"BUTTON", L"Reload",
+ WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_DISABLED,
+ x_offset, 0, button_width, urlbar_height, hwnd_,
+ reinterpret_cast<HMENU>(IDC_NAV_RELOAD), hInstance, 0);
+ CHECK(reload_hwnd_);
+ x_offset += button_width;
+
+ stop_hwnd_ = CreateWindow(
+ L"BUTTON", L"Stop", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_DISABLED,
+ x_offset, 0, button_width, urlbar_height, hwnd_,
+ reinterpret_cast<HMENU>(IDC_NAV_STOP), hInstance, 0);
+ CHECK(stop_hwnd_);
+ x_offset += button_width;
+
+ edit_hwnd_ = CreateWindow(L"EDIT", 0,
+ WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT |
+ ES_AUTOVSCROLL | ES_AUTOHSCROLL | WS_DISABLED,
+ x_offset, 0, rect.right - button_width * 4,
+ urlbar_height, hwnd_, 0, hInstance, 0);
+ CHECK(edit_hwnd_);
+
+ // Override the edit control's window procedure.
+ edit_wndproc_old_ = SetWndProcPtr(edit_hwnd_, EditWndProc);
+
+ // Associate |this| with the edit window.
+ SetUserDataPtr(edit_hwnd_, this);
+
+ rect.top += urlbar_height;
+
+ if (!with_osr_) {
+ // Remove the menu items that are only used with OSR.
+ HMENU hMenu = ::GetMenu(hwnd_);
+ if (hMenu) {
+ HMENU hTestMenu = ::GetSubMenu(hMenu, 2);
+ if (hTestMenu) {
+ ::RemoveMenu(hTestMenu, ID_TESTS_OSR_FPS, MF_BYCOMMAND);
+ ::RemoveMenu(hTestMenu, ID_TESTS_OSR_DSF, MF_BYCOMMAND);
+ }
+ }
+ }
+ } else {
+ // No controls so also remove the default menu.
+ ::SetMenu(hwnd_, nullptr);
+ }
+
+ const float device_scale_factor = GetWindowScaleFactor(hwnd_);
+
+ if (with_osr_) {
+ browser_window_->SetDeviceScaleFactor(device_scale_factor);
+ }
+
+ if (!is_popup_) {
+ // Create the browser window.
+ CefRect cef_rect(rect.left, rect.top, rect.right - rect.left,
+ rect.bottom - rect.top);
+ browser_window_->CreateBrowser(hwnd_, cef_rect, browser_settings_, nullptr,
+ delegate_->GetRequestContext(this));
+ } else {
+ // With popups we already have a browser window. Parent the browser window
+ // to the root window and show it in the correct location.
+ browser_window_->ShowPopup(hwnd_, rect.left, rect.top,
+ rect.right - rect.left, rect.bottom - rect.top);
+ }
+}
+
+bool RootWindowWin::OnClose() {
+ if (browser_window_ && !browser_window_->IsClosing()) {
+ CefRefPtr<CefBrowser> browser = GetBrowser();
+ if (browser) {
+ // Notify the browser window that we would like to close it. This
+ // will result in a call to ClientHandler::DoClose() if the
+ // JavaScript 'onbeforeunload' event handler allows it.
+ browser->GetHost()->CloseBrowser(false);
+
+ // Cancel the close.
+ return true;
+ }
+ }
+
+ // Retrieve current window placement information.
+ WINDOWPLACEMENT placement;
+ ::GetWindowPlacement(hwnd_, &placement);
+
+ if (CefCurrentlyOn(TID_UI)) {
+ SaveWindowRestoreOnUIThread(placement);
+ } else {
+ CefPostTask(
+ TID_UI,
+ base::BindOnce(&RootWindowWin::SaveWindowRestoreOnUIThread, placement));
+ }
+
+ // Allow the close.
+ return false;
+}
+
+void RootWindowWin::OnDestroyed() {
+ window_destroyed_ = true;
+ NotifyDestroyedIfDone();
+}
+
+void RootWindowWin::OnBrowserCreated(CefRefPtr<CefBrowser> browser) {
+ REQUIRE_MAIN_THREAD();
+
+ if (is_popup_) {
+ // For popup browsers create the root window once the browser has been
+ // created.
+ CreateRootWindow(CefBrowserSettings(), false);
+ } else {
+ // Make sure the browser is sized correctly.
+ OnSize(false);
+ }
+
+ delegate_->OnBrowserCreated(this, browser);
+}
+
+void RootWindowWin::OnBrowserWindowDestroyed() {
+ REQUIRE_MAIN_THREAD();
+
+ browser_window_.reset();
+
+ if (!window_destroyed_) {
+ // The browser was destroyed first. This could be due to the use of
+ // off-screen rendering or execution of JavaScript window.close().
+ // Close the RootWindow.
+ Close(true);
+ }
+
+ browser_destroyed_ = true;
+ NotifyDestroyedIfDone();
+}
+
+void RootWindowWin::OnSetAddress(const std::string& url) {
+ REQUIRE_MAIN_THREAD();
+
+ if (edit_hwnd_) {
+ SetWindowText(edit_hwnd_, CefString(url).ToWString().c_str());
+ }
+}
+
+void RootWindowWin::OnSetTitle(const std::string& title) {
+ REQUIRE_MAIN_THREAD();
+
+ if (hwnd_) {
+ SetWindowText(hwnd_, CefString(title).ToWString().c_str());
+ }
+}
+
+void RootWindowWin::OnSetFullscreen(bool fullscreen) {
+ REQUIRE_MAIN_THREAD();
+
+ CefRefPtr<CefBrowser> browser = GetBrowser();
+ if (browser) {
+ std::unique_ptr<window_test::WindowTestRunnerWin> test_runner(
+ new window_test::WindowTestRunnerWin());
+ if (fullscreen) {
+ test_runner->Maximize(browser);
+ } else {
+ test_runner->Restore(browser);
+ }
+ }
+}
+
+void RootWindowWin::OnAutoResize(const CefSize& new_size) {
+ REQUIRE_MAIN_THREAD();
+
+ if (!hwnd_) {
+ return;
+ }
+
+ int new_width = new_size.width;
+
+ // Make the window wide enough to drag by the top menu bar.
+ if (new_width < 200) {
+ new_width = 200;
+ }
+
+ const float device_scale_factor = GetWindowScaleFactor(hwnd_);
+ RECT rect = {0, 0, LogicalToDevice(new_width, device_scale_factor),
+ LogicalToDevice(new_size.height, device_scale_factor)};
+ DWORD style = GetWindowLong(hwnd_, GWL_STYLE);
+ DWORD ex_style = GetWindowLong(hwnd_, GWL_EXSTYLE);
+ bool has_menu = !(style & WS_CHILD) && (GetMenu(hwnd_) != nullptr);
+
+ // The size value is for the client area. Calculate the whole window size
+ // based on the current style.
+ AdjustWindowRectEx(&rect, style, has_menu, ex_style);
+
+ // Size the window. The left/top values may be negative.
+ // Also show the window if it's not currently visible.
+ SetWindowPos(hwnd_, nullptr, 0, 0, rect.right - rect.left,
+ rect.bottom - rect.top,
+ SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE | SWP_SHOWWINDOW);
+}
+
+void RootWindowWin::OnSetLoadingState(bool isLoading,
+ bool canGoBack,
+ bool canGoForward) {
+ REQUIRE_MAIN_THREAD();
+
+ if (with_controls_) {
+ EnableWindow(back_hwnd_, canGoBack);
+ EnableWindow(forward_hwnd_, canGoForward);
+ EnableWindow(reload_hwnd_, !isLoading);
+ EnableWindow(stop_hwnd_, isLoading);
+ EnableWindow(edit_hwnd_, TRUE);
+ }
+
+ if (!isLoading && GetWindowLongPtr(hwnd_, GWL_EXSTYLE) & WS_EX_NOACTIVATE) {
+ // Done with the initial navigation. Remove the WS_EX_NOACTIVATE style so
+ // that future mouse clicks inside the browser correctly activate and focus
+ // the window. For the top-level window removing this style causes Windows
+ // to display the task bar button.
+ SetWindowLongPtr(hwnd_, GWL_EXSTYLE,
+ GetWindowLongPtr(hwnd_, GWL_EXSTYLE) & ~WS_EX_NOACTIVATE);
+
+ if (browser_window_) {
+ HWND browser_hwnd = browser_window_->GetWindowHandle();
+ SetWindowLongPtr(
+ browser_hwnd, GWL_EXSTYLE,
+ GetWindowLongPtr(browser_hwnd, GWL_EXSTYLE) & ~WS_EX_NOACTIVATE);
+ }
+ }
+}
+
+namespace {
+
+LPCWSTR kParentWndProc = L"CefParentWndProc";
+LPCWSTR kDraggableRegion = L"CefDraggableRegion";
+
+LRESULT CALLBACK SubclassedWindowProc(HWND hWnd,
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam) {
+ WNDPROC hParentWndProc =
+ reinterpret_cast<WNDPROC>(::GetPropW(hWnd, kParentWndProc));
+ HRGN hRegion = reinterpret_cast<HRGN>(::GetPropW(hWnd, kDraggableRegion));
+
+ if (message == WM_NCHITTEST) {
+ LRESULT hit = CallWindowProc(hParentWndProc, hWnd, message, wParam, lParam);
+ if (hit == HTCLIENT) {
+ POINTS points = MAKEPOINTS(lParam);
+ POINT point = {points.x, points.y};
+ ::ScreenToClient(hWnd, &point);
+ if (::PtInRegion(hRegion, point.x, point.y)) {
+ // Let the parent window handle WM_NCHITTEST by returning HTTRANSPARENT
+ // in child windows.
+ return HTTRANSPARENT;
+ }
+ }
+ return hit;
+ }
+
+ return CallWindowProc(hParentWndProc, hWnd, message, wParam, lParam);
+}
+
+void SubclassWindow(HWND hWnd, HRGN hRegion) {
+ HANDLE hParentWndProc = ::GetPropW(hWnd, kParentWndProc);
+ if (hParentWndProc) {
+ return;
+ }
+
+ SetLastError(0);
+ LONG_PTR hOldWndProc = SetWindowLongPtr(
+ hWnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(SubclassedWindowProc));
+ if (hOldWndProc == 0 && GetLastError() != ERROR_SUCCESS) {
+ return;
+ }
+
+ ::SetPropW(hWnd, kParentWndProc, reinterpret_cast<HANDLE>(hOldWndProc));
+ ::SetPropW(hWnd, kDraggableRegion, reinterpret_cast<HANDLE>(hRegion));
+}
+
+void UnSubclassWindow(HWND hWnd) {
+ LONG_PTR hParentWndProc =
+ reinterpret_cast<LONG_PTR>(::GetPropW(hWnd, kParentWndProc));
+ if (hParentWndProc) {
+ [[maybe_unused]] LONG_PTR hPreviousWndProc =
+ SetWindowLongPtr(hWnd, GWLP_WNDPROC, hParentWndProc);
+ DCHECK_EQ(hPreviousWndProc,
+ reinterpret_cast<LONG_PTR>(SubclassedWindowProc));
+ }
+
+ ::RemovePropW(hWnd, kParentWndProc);
+ ::RemovePropW(hWnd, kDraggableRegion);
+}
+
+BOOL CALLBACK SubclassWindowsProc(HWND hwnd, LPARAM lParam) {
+ SubclassWindow(hwnd, reinterpret_cast<HRGN>(lParam));
+ return TRUE;
+}
+
+BOOL CALLBACK UnSubclassWindowsProc(HWND hwnd, LPARAM lParam) {
+ UnSubclassWindow(hwnd);
+ return TRUE;
+}
+
+} // namespace
+
+void RootWindowWin::OnSetDraggableRegions(
+ const std::vector<CefDraggableRegion>& regions) {
+ REQUIRE_MAIN_THREAD();
+
+ // Reset draggable region.
+ ::SetRectRgn(draggable_region_, 0, 0, 0, 0);
+
+ // Determine new draggable region.
+ std::vector<CefDraggableRegion>::const_iterator it = regions.begin();
+ for (; it != regions.end(); ++it) {
+ HRGN region = ::CreateRectRgn(it->bounds.x, it->bounds.y,
+ it->bounds.x + it->bounds.width,
+ it->bounds.y + it->bounds.height);
+ ::CombineRgn(draggable_region_, draggable_region_, region,
+ it->draggable ? RGN_OR : RGN_DIFF);
+ ::DeleteObject(region);
+ }
+
+ // Subclass child window procedures in order to do hit-testing.
+ // This will be a no-op, if it is already subclassed.
+ if (hwnd_) {
+ WNDENUMPROC proc =
+ !regions.empty() ? SubclassWindowsProc : UnSubclassWindowsProc;
+ ::EnumChildWindows(hwnd_, proc,
+ reinterpret_cast<LPARAM>(draggable_region_));
+ }
+}
+
+void RootWindowWin::NotifyDestroyedIfDone() {
+ // Notify once both the window and the browser have been destroyed.
+ if (window_destroyed_ && browser_destroyed_) {
+ delegate_->OnRootWindowDestroyed(this);
+ }
+}
+
+// static
+void RootWindowWin::SaveWindowRestoreOnUIThread(
+ const WINDOWPLACEMENT& placement) {
+ CEF_REQUIRE_UI_THREAD();
+
+ cef_show_state_t show_state = CEF_SHOW_STATE_NORMAL;
+ if (placement.showCmd == SW_SHOWMINIMIZED) {
+ show_state = CEF_SHOW_STATE_MINIMIZED;
+ } else if (placement.showCmd == SW_SHOWMAXIMIZED) {
+ show_state = CEF_SHOW_STATE_MAXIMIZED;
+ }
+
+ // Coordinates when the window is in the restored position.
+ const auto rect = placement.rcNormalPosition;
+ CefRect pixel_bounds(rect.left, rect.top, rect.right - rect.left,
+ rect.bottom - rect.top);
+ const auto dip_bounds = CefDisplay::ConvertScreenRectFromPixels(pixel_bounds);
+
+ prefs::SaveWindowRestorePreferences(show_state, dip_bounds);
+}
+
+} // namespace client
diff --git a/tests/cefclient/browser/root_window_win.h b/tests/cefclient/browser/root_window_win.h
new file mode 100644
index 00000000..f36b2cec
--- /dev/null
+++ b/tests/cefclient/browser/root_window_win.h
@@ -0,0 +1,174 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_ROOT_WINDOW_WIN_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_ROOT_WINDOW_WIN_H_
+#pragma once
+
+#include <windows.h>
+
+#include <commdlg.h>
+
+#include <memory>
+#include <string>
+
+#include "tests/cefclient/browser/browser_window.h"
+#include "tests/cefclient/browser/root_window.h"
+
+namespace client {
+
+// Windows implementation of a top-level native window in the browser process.
+// The methods of this class must be called on the main thread unless otherwise
+// indicated.
+class RootWindowWin : public RootWindow, public BrowserWindow::Delegate {
+ public:
+ // Constructor may be called on any thread.
+ RootWindowWin();
+ ~RootWindowWin();
+
+ // RootWindow methods.
+ void Init(RootWindow::Delegate* delegate,
+ std::unique_ptr<RootWindowConfig> config,
+ const CefBrowserSettings& settings) override;
+ void InitAsPopup(RootWindow::Delegate* delegate,
+ bool with_controls,
+ bool with_osr,
+ const CefPopupFeatures& popupFeatures,
+ CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient>& client,
+ CefBrowserSettings& settings) override;
+ void Show(ShowMode mode) override;
+ void Hide() override;
+ void SetBounds(int x, int y, size_t width, size_t height) override;
+ void Close(bool force) override;
+ void SetDeviceScaleFactor(float device_scale_factor) override;
+ float GetDeviceScaleFactor() const override;
+ CefRefPtr<CefBrowser> GetBrowser() const override;
+ ClientWindowHandle GetWindowHandle() const override;
+ bool WithWindowlessRendering() const override;
+ bool WithExtension() const override;
+
+ private:
+ void ContinueInitOnUIThread(std::unique_ptr<RootWindowConfig> config,
+ const CefBrowserSettings& settings);
+ void ContinueInitOnMainThread(std::unique_ptr<RootWindowConfig> config,
+ const CefBrowserSettings& settings);
+
+ void CreateBrowserWindow(const std::string& startup_url);
+ void CreateRootWindow(const CefBrowserSettings& settings,
+ bool initially_hidden);
+
+ // Register the root window class.
+ static void RegisterRootClass(HINSTANCE hInstance,
+ const std::wstring& window_class,
+ HBRUSH background_brush);
+
+ // Window procedure for the edit field.
+ static LRESULT CALLBACK EditWndProc(HWND hWnd,
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam);
+
+ // Window procedure for the find dialog.
+ static LRESULT CALLBACK FindWndProc(HWND hWnd,
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam);
+
+ // Window procedure for the root window.
+ static LRESULT CALLBACK RootWndProc(HWND hWnd,
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam);
+
+ // Event handlers.
+ void OnPaint();
+ void OnFocus();
+ void OnActivate(bool active);
+ void OnSize(bool minimized);
+ void OnMove();
+ void OnDpiChanged(WPARAM wParam, LPARAM lParam);
+ bool OnEraseBkgnd();
+ bool OnCommand(UINT id);
+ void OnFind();
+ void OnFindEvent();
+ void OnAbout();
+ void OnNCCreate(LPCREATESTRUCT lpCreateStruct);
+ void OnCreate(LPCREATESTRUCT lpCreateStruct);
+ bool OnClose();
+ void OnDestroyed();
+
+ // BrowserWindow::Delegate methods.
+ void OnBrowserCreated(CefRefPtr<CefBrowser> browser) override;
+ void OnBrowserWindowDestroyed() override;
+ void OnSetAddress(const std::string& url) override;
+ void OnSetTitle(const std::string& title) override;
+ void OnSetFullscreen(bool fullscreen) override;
+ void OnAutoResize(const CefSize& new_size) override;
+ void OnSetLoadingState(bool isLoading,
+ bool canGoBack,
+ bool canGoForward) override;
+ void OnSetDraggableRegions(
+ const std::vector<CefDraggableRegion>& regions) override;
+
+ void NotifyDestroyedIfDone();
+
+ static void SaveWindowRestoreOnUIThread(const WINDOWPLACEMENT& placement);
+
+ // After initialization all members are only accessed on the main thread.
+ // Members set during initialization.
+ bool with_controls_ = false;
+ bool always_on_top_ = false;
+ bool with_osr_ = false;
+ bool with_extension_ = false;
+ bool is_popup_ = false;
+ CefRect initial_bounds_;
+ cef_show_state_t initial_show_state_ = CEF_SHOW_STATE_NORMAL;
+ std::unique_ptr<BrowserWindow> browser_window_;
+ CefBrowserSettings browser_settings_;
+ bool initialized_ = false;
+
+ // Main window.
+ HWND hwnd_ = nullptr;
+
+ // Draggable region.
+ HRGN draggable_region_ = nullptr;
+
+ // Font for buttons and text fields.
+ HFONT font_ = nullptr;
+ int font_height_ = 0;
+
+ // Buttons.
+ HWND back_hwnd_ = nullptr;
+ HWND forward_hwnd_ = nullptr;
+ HWND reload_hwnd_ = nullptr;
+ HWND stop_hwnd_ = nullptr;
+
+ // URL text field.
+ HWND edit_hwnd_ = nullptr;
+ WNDPROC edit_wndproc_old_ = nullptr;
+
+ // Find dialog.
+ HWND find_hwnd_ = nullptr;
+ UINT find_message_id_ = 0;
+ WNDPROC find_wndproc_old_ = nullptr;
+
+ // Find dialog state.
+ FINDREPLACE find_state_ = {0};
+ WCHAR find_buff_[80] = {0};
+ std::wstring find_what_last_;
+ bool find_next_ = false;
+ bool find_match_case_last_ = false;
+
+ bool window_destroyed_ = false;
+ bool browser_destroyed_ = false;
+
+ bool called_enable_non_client_dpi_scaling_ = false;
+
+ DISALLOW_COPY_AND_ASSIGN(RootWindowWin);
+};
+
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_ROOT_WINDOW_WIN_H_
diff --git a/tests/cefclient/browser/scheme_test.cc b/tests/cefclient/browser/scheme_test.cc
new file mode 100644
index 00000000..0a781fd5
--- /dev/null
+++ b/tests/cefclient/browser/scheme_test.cc
@@ -0,0 +1,154 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/scheme_test.h"
+
+#include <algorithm>
+#include <string>
+
+#include "include/cef_browser.h"
+#include "include/cef_callback.h"
+#include "include/cef_frame.h"
+#include "include/cef_request.h"
+#include "include/cef_resource_handler.h"
+#include "include/cef_response.h"
+#include "include/cef_scheme.h"
+#include "include/wrapper/cef_helpers.h"
+#include "tests/cefclient/browser/test_runner.h"
+#include "tests/shared/browser/resource_util.h"
+
+namespace client {
+namespace scheme_test {
+
+namespace {
+
+// Implementation of the schema handler for client:// requests.
+class ClientSchemeHandler : public CefResourceHandler {
+ public:
+ ClientSchemeHandler() : offset_(0) {}
+
+ bool Open(CefRefPtr<CefRequest> request,
+ bool& handle_request,
+ CefRefPtr<CefCallback> callback) override {
+ DCHECK(!CefCurrentlyOn(TID_UI) && !CefCurrentlyOn(TID_IO));
+
+ // The request will be continued or canceled based on the return value.
+ handle_request = true;
+
+ bool handled = false;
+
+ std::string url = request->GetURL();
+ if (strstr(url.c_str(), "handler.html") != nullptr) {
+ // Build the response html
+ data_ =
+ "<html><head><title>Client Scheme Handler</title></head>"
+ "<body bgcolor=\"white\">"
+ "This contents of this page page are served by the "
+ "ClientSchemeHandler class handling the client:// protocol."
+ "<br/>You should see an image:"
+ "<br/><img src=\"client://tests/logo.png\"><pre>";
+
+ // Output a string representation of the request
+ const std::string& dump = test_runner::DumpRequestContents(request);
+ data_.append(dump);
+
+ data_.append(
+ "</pre><br/>Try the test form:"
+ "<form method=\"POST\" action=\"handler.html\">"
+ "<input type=\"text\" name=\"field1\">"
+ "<input type=\"text\" name=\"field2\">"
+ "<input type=\"submit\">"
+ "</form></body></html>");
+
+ handled = true;
+
+ // Set the resulting mime type
+ mime_type_ = "text/html";
+ } else if (strstr(url.c_str(), "logo.png") != nullptr) {
+ // Load the response image
+ if (LoadBinaryResource("logo.png", data_)) {
+ handled = true;
+ // Set the resulting mime type
+ mime_type_ = "image/png";
+ }
+ }
+
+ return handled;
+ }
+
+ void GetResponseHeaders(CefRefPtr<CefResponse> response,
+ int64& response_length,
+ CefString& redirectUrl) override {
+ CEF_REQUIRE_IO_THREAD();
+
+ DCHECK(!data_.empty());
+
+ response->SetMimeType(mime_type_);
+ response->SetStatus(200);
+
+ // Set the resulting response length
+ response_length = data_.length();
+ }
+
+ void Cancel() override { CEF_REQUIRE_IO_THREAD(); }
+
+ bool Read(void* data_out,
+ int bytes_to_read,
+ int& bytes_read,
+ CefRefPtr<CefResourceReadCallback> callback) override {
+ DCHECK(!CefCurrentlyOn(TID_UI) && !CefCurrentlyOn(TID_IO));
+
+ bool has_data = false;
+ bytes_read = 0;
+
+ if (offset_ < data_.length()) {
+ // Copy the next block of data into the buffer.
+ int transfer_size =
+ std::min(bytes_to_read, static_cast<int>(data_.length() - offset_));
+ memcpy(data_out, data_.c_str() + offset_, transfer_size);
+ offset_ += transfer_size;
+
+ bytes_read = transfer_size;
+ has_data = true;
+ }
+
+ return has_data;
+ }
+
+ private:
+ std::string data_;
+ std::string mime_type_;
+ size_t offset_;
+
+ IMPLEMENT_REFCOUNTING(ClientSchemeHandler);
+ DISALLOW_COPY_AND_ASSIGN(ClientSchemeHandler);
+};
+
+// Implementation of the factory for for creating schema handlers.
+class ClientSchemeHandlerFactory : public CefSchemeHandlerFactory {
+ public:
+ ClientSchemeHandlerFactory() {}
+
+ // Return a new scheme handler instance to handle the request.
+ CefRefPtr<CefResourceHandler> Create(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const CefString& scheme_name,
+ CefRefPtr<CefRequest> request) override {
+ CEF_REQUIRE_IO_THREAD();
+ return new ClientSchemeHandler();
+ }
+
+ IMPLEMENT_REFCOUNTING(ClientSchemeHandlerFactory);
+ DISALLOW_COPY_AND_ASSIGN(ClientSchemeHandlerFactory);
+};
+
+} // namespace
+
+void RegisterSchemeHandlers() {
+ CefRegisterSchemeHandlerFactory("client", "tests",
+ new ClientSchemeHandlerFactory());
+}
+
+} // namespace scheme_test
+} // namespace client
diff --git a/tests/cefclient/browser/scheme_test.h b/tests/cefclient/browser/scheme_test.h
new file mode 100644
index 00000000..c48d6f6c
--- /dev/null
+++ b/tests/cefclient/browser/scheme_test.h
@@ -0,0 +1,20 @@
+// Copyright (c) 2009 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_SCHEME_TEST_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_SCHEME_TEST_H_
+#pragma once
+
+namespace client {
+namespace scheme_test {
+
+// Create and register the custom scheme handler. See
+// common/scheme_handler_common.h for registration of the custom scheme
+// name/type which must occur in all processes. Called from test_runner.cc.
+void RegisterSchemeHandlers();
+
+} // namespace scheme_test
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_SCHEME_TEST_H_
diff --git a/tests/cefclient/browser/server_test.cc b/tests/cefclient/browser/server_test.cc
new file mode 100644
index 00000000..96760549
--- /dev/null
+++ b/tests/cefclient/browser/server_test.cc
@@ -0,0 +1,395 @@
+// Copyright (c) 2017 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/server_test.h"
+
+#include <algorithm>
+#include <memory>
+#include <string>
+
+#include "include/base/cef_callback.h"
+#include "include/base/cef_weak_ptr.h"
+#include "include/cef_parser.h"
+#include "include/cef_server.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "tests/shared/browser/resource_util.h"
+
+namespace client {
+namespace server_test {
+
+namespace {
+
+// Application-specific error codes.
+const int kMessageFormatError = 1;
+const int kActionStateError = 1;
+
+// JSON dictionary keys.
+const char kActionKey[] = "action";
+const char kResultKey[] = "result";
+const char kPortKey[] = "port";
+const char kStatusKey[] = "status";
+const char kMessageKey[] = "message";
+
+// Required URL for cefQuery execution.
+const char kTestUrl[] = "http://tests/server";
+
+// Server default values.
+const char kServerAddress[] = "127.0.0.1";
+const int kServerPortDefault = 8099;
+const int kServerBacklog = 10;
+const char kDefaultPath[] = "websocket.html";
+
+// Handles the HTTP/WebSocket server.
+class ServerHandler : public CefServerHandler {
+ public:
+ using CompleteCallback = base::OnceCallback<void(bool /* success */)>;
+
+ ServerHandler() {}
+
+ // |complete_callback| will be executed on the UI thread after completion.
+ void StartServer(int port, CompleteCallback complete_callback) {
+ CEF_REQUIRE_UI_THREAD();
+ DCHECK(!server_);
+ DCHECK(port >= 1025 && port <= 65535);
+ port_ = port;
+ complete_callback_ = std::move(complete_callback);
+ CefServer::CreateServer(kServerAddress, port, kServerBacklog, this);
+ }
+
+ // |complete_callback| will be executed on the UI thread after completion.
+ void StopServer(CompleteCallback complete_callback) {
+ CEF_REQUIRE_UI_THREAD();
+ DCHECK(server_);
+ complete_callback_ = std::move(complete_callback);
+ server_->Shutdown();
+ }
+
+ // CefServerHandler methods are called on the server thread.
+
+ void OnServerCreated(CefRefPtr<CefServer> server) override {
+ DCHECK(!server_);
+ server_ = server;
+ RunCompleteCallback(server->IsRunning());
+ }
+
+ void OnServerDestroyed(CefRefPtr<CefServer> server) override {
+ DCHECK(server_);
+ server_ = nullptr;
+ RunCompleteCallback(true);
+ }
+
+ void OnClientConnected(CefRefPtr<CefServer> server,
+ int connection_id) override {}
+
+ void OnClientDisconnected(CefRefPtr<CefServer> server,
+ int connection_id) override {}
+
+ void OnHttpRequest(CefRefPtr<CefServer> server,
+ int connection_id,
+ const CefString& client_address,
+ CefRefPtr<CefRequest> request) override {
+ // Parse the request URL and retrieve the path without leading slash.
+ CefURLParts url_parts;
+ CefParseURL(request->GetURL(), url_parts);
+ std::string path = CefString(&url_parts.path);
+ if (!path.empty() && path[0] == '/') {
+ path = path.substr(1);
+ }
+
+ if (path.empty()) {
+ path = kDefaultPath;
+ }
+
+ std::string mime_type;
+ const size_t sep = path.find_last_of(".");
+ if (sep != std::string::npos) {
+ // Determine the mime type based on the extension.
+ mime_type = CefGetMimeType(path.substr(sep + 1));
+ } else {
+ // No extension. Assume html.
+ path += ".html";
+ }
+ if (mime_type.empty()) {
+ mime_type = "text/html";
+ }
+
+ CefRefPtr<CefStreamReader> stream;
+ CefResponse::HeaderMap extra_headers;
+
+ if (path == "request.html") {
+ // Return the request contents.
+ stream = test_runner::GetDumpResponse(request, extra_headers);
+ }
+
+ if (!stream) {
+ // Load any resource supported by cefclient.
+ stream = GetBinaryResourceReader(path.c_str());
+ }
+
+ if (stream) {
+ SendHttpResponseStream(server, connection_id, mime_type, stream,
+ extra_headers);
+ } else {
+ server->SendHttp404Response(connection_id);
+ }
+ }
+
+ void OnWebSocketRequest(CefRefPtr<CefServer> server,
+ int connection_id,
+ const CefString& client_address,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefCallback> callback) override {
+ // Always accept WebSocket connections.
+ callback->Continue();
+ }
+
+ void OnWebSocketConnected(CefRefPtr<CefServer> server,
+ int connection_id) override {}
+
+ void OnWebSocketMessage(CefRefPtr<CefServer> server,
+ int connection_id,
+ const void* data,
+ size_t data_size) override {
+ // Echo the reverse of the message.
+ std::string message(static_cast<const char*>(data), data_size);
+ std::reverse(message.begin(), message.end());
+
+ server->SendWebSocketMessage(connection_id, message.data(), message.size());
+ }
+
+ int port() const { return port_; }
+
+ private:
+ void RunCompleteCallback(bool success) {
+ if (!CefCurrentlyOn(TID_UI)) {
+ CefPostTask(TID_UI, base::BindOnce(&ServerHandler::RunCompleteCallback,
+ this, success));
+ return;
+ }
+
+ if (!complete_callback_.is_null()) {
+ std::move(complete_callback_).Run(success);
+ }
+ }
+
+ static void SendHttpResponseStream(CefRefPtr<CefServer> server,
+ int connection_id,
+ const std::string& mime_type,
+ CefRefPtr<CefStreamReader> stream,
+ CefResponse::HeaderMap extra_headers) {
+ // Determine the stream size.
+ stream->Seek(0, SEEK_END);
+ int64 content_length = stream->Tell();
+ stream->Seek(0, SEEK_SET);
+
+ // Send response headers.
+ server->SendHttpResponse(connection_id, 200, mime_type, content_length,
+ extra_headers);
+
+ // Send stream contents.
+ char buffer[8192];
+ size_t read;
+ do {
+ read = stream->Read(buffer, 1, sizeof(buffer));
+ if (read > 0) {
+ server->SendRawData(connection_id, buffer, read);
+ }
+ } while (!stream->Eof() && read != 0);
+
+ // Close the connection.
+ server->CloseConnection(connection_id);
+ }
+
+ CefRefPtr<CefServer> server_;
+
+ // The below members are only accessed on the UI thread.
+ int port_;
+ CompleteCallback complete_callback_;
+
+ IMPLEMENT_REFCOUNTING(ServerHandler);
+ DISALLOW_COPY_AND_ASSIGN(ServerHandler);
+};
+
+// Handle messages in the browser process.
+class Handler : public CefMessageRouterBrowserSide::Handler {
+ public:
+ Handler() : weak_ptr_factory_(this) {}
+
+ virtual ~Handler() {
+ if (handler_) {
+ handler_->StopServer(ServerHandler::CompleteCallback());
+ handler_ = nullptr;
+ }
+ }
+
+ // Called due to cefQuery execution in server.html.
+ virtual bool OnQuery(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int64 query_id,
+ const CefString& request,
+ bool persistent,
+ CefRefPtr<Callback> callback) override {
+ CEF_REQUIRE_UI_THREAD();
+
+ // Only handle messages from the test URL.
+ const std::string& url = frame->GetURL();
+ if (url.find(kTestUrl) != 0) {
+ return false;
+ }
+
+ // Parse |request| as a JSON dictionary.
+ CefRefPtr<CefDictionaryValue> request_dict = ParseJSON(request);
+ if (!request_dict) {
+ callback->Failure(kMessageFormatError, "Incorrect message format");
+ return true;
+ }
+
+ if (!VerifyKey(request_dict, kActionKey, VTYPE_STRING, callback)) {
+ return true;
+ }
+
+ const std::string& action = request_dict->GetString(kActionKey);
+ if (action == "query") {
+ HandleQueryAction(request_dict, callback);
+ } else if (action == "start") {
+ HandleStartAction(request_dict, callback);
+ } else if (action == "stop") {
+ HandleStopAction(request_dict, callback);
+ } else {
+ callback->Failure(kMessageFormatError, "Unrecognized action: " + action);
+ }
+
+ return true;
+ }
+
+ private:
+ // Return current server status.
+ void HandleQueryAction(CefRefPtr<CefDictionaryValue> request_dict,
+ CefRefPtr<Callback> callback) {
+ CefRefPtr<CefDictionaryValue> result_dict = CefDictionaryValue::Create();
+ if (handler_) {
+ result_dict->SetInt(kPortKey, handler_->port());
+ result_dict->SetString(kStatusKey, "running");
+ } else {
+ result_dict->SetInt(kPortKey, kServerPortDefault);
+ result_dict->SetString(kStatusKey, "stopped");
+ }
+ SendResponse(callback, true, result_dict);
+ }
+
+ // Start the server.
+ void HandleStartAction(CefRefPtr<CefDictionaryValue> request_dict,
+ CefRefPtr<Callback> callback) {
+ if (handler_) {
+ callback->Failure(kActionStateError, "Server is currently running");
+ return;
+ }
+
+ if (!VerifyKey(request_dict, kPortKey, VTYPE_INT, callback)) {
+ return;
+ }
+
+ const int port = request_dict->GetInt(kPortKey);
+ if (port < 8000 || port > 65535) {
+ callback->Failure(kMessageFormatError, "Invalid port number specified");
+ return;
+ }
+
+ handler_ = new ServerHandler();
+
+ // Start the server. OnComplete will be executed upon completion.
+ handler_->StartServer(
+ port, base::BindOnce(&Handler::OnStartComplete,
+ weak_ptr_factory_.GetWeakPtr(), callback));
+ }
+
+ // Stop the server.
+ void HandleStopAction(CefRefPtr<CefDictionaryValue> request_dict,
+ CefRefPtr<Callback> callback) {
+ if (!handler_) {
+ callback->Failure(kActionStateError, "Server is not currently running");
+ return;
+ }
+
+ // Stop the server. OnComplete will be executed upon completion.
+ handler_->StopServer(base::BindOnce(
+ &Handler::OnStopComplete, weak_ptr_factory_.GetWeakPtr(), callback));
+
+ handler_ = nullptr;
+ }
+
+ // Server start completed.
+ void OnStartComplete(CefRefPtr<Callback> callback, bool success) {
+ CEF_REQUIRE_UI_THREAD();
+ CefRefPtr<CefDictionaryValue> result_dict = CefDictionaryValue::Create();
+ if (!success) {
+ handler_ = nullptr;
+ result_dict->SetString(kMessageKey, "Server failed to start.");
+ }
+ SendResponse(callback, success, result_dict);
+ }
+
+ // Server stop completed.
+ void OnStopComplete(CefRefPtr<Callback> callback, bool success) {
+ CEF_REQUIRE_UI_THREAD();
+ CefRefPtr<CefDictionaryValue> result_dict = CefDictionaryValue::Create();
+ if (!success) {
+ result_dict->SetString(kMessageKey, "Server failed to stop.");
+ }
+ SendResponse(callback, success, result_dict);
+ }
+
+ // Send a response in the format expected by server.html.
+ static void SendResponse(CefRefPtr<Callback> callback,
+ bool success,
+ CefRefPtr<CefDictionaryValue> result_dict) {
+ if (!result_dict) {
+ result_dict = CefDictionaryValue::Create();
+ }
+ result_dict->SetString(kResultKey, success ? "success" : "failure");
+ CefRefPtr<CefValue> value = CefValue::Create();
+ value->SetDictionary(result_dict);
+ const std::string& response = CefWriteJSON(value, JSON_WRITER_DEFAULT);
+ callback->Success(response);
+ }
+
+ // Convert a JSON string to a dictionary value.
+ static CefRefPtr<CefDictionaryValue> ParseJSON(const CefString& string) {
+ CefRefPtr<CefValue> value = CefParseJSON(string, JSON_PARSER_RFC);
+ if (value.get() && value->GetType() == VTYPE_DICTIONARY) {
+ return value->GetDictionary();
+ }
+ return nullptr;
+ }
+
+ // Verify that |key| exists in |dictionary| and has type |value_type|. Fails
+ // |callback| and returns false on failure.
+ static bool VerifyKey(CefRefPtr<CefDictionaryValue> dictionary,
+ const char* key,
+ cef_value_type_t value_type,
+ CefRefPtr<Callback> callback) {
+ if (!dictionary->HasKey(key) || dictionary->GetType(key) != value_type) {
+ callback->Failure(
+ kMessageFormatError,
+ "Missing or incorrectly formatted message key: " + std::string(key));
+ return false;
+ }
+ return true;
+ }
+
+ // Non-nullptr while the server is running.
+ CefRefPtr<ServerHandler> handler_;
+
+ // Must be the last member.
+ base::WeakPtrFactory<Handler> weak_ptr_factory_;
+};
+
+} // namespace
+
+void CreateMessageHandlers(test_runner::MessageHandlerSet& handlers) {
+ handlers.insert(new Handler());
+}
+
+} // namespace server_test
+} // namespace client
diff --git a/tests/cefclient/browser/server_test.h b/tests/cefclient/browser/server_test.h
new file mode 100644
index 00000000..ffe3172a
--- /dev/null
+++ b/tests/cefclient/browser/server_test.h
@@ -0,0 +1,20 @@
+// Copyright (c) 2017 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_SERVER_TEST_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_SERVER_TEST_H_
+#pragma once
+
+#include "tests/cefclient/browser/test_runner.h"
+
+namespace client {
+namespace server_test {
+
+// Create message handlers. Called from test_runner.cc.
+void CreateMessageHandlers(test_runner::MessageHandlerSet& handlers);
+
+} // namespace server_test
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_SERVER_TEST_H_
diff --git a/tests/cefclient/browser/temp_window.h b/tests/cefclient/browser/temp_window.h
new file mode 100644
index 00000000..391bba47
--- /dev/null
+++ b/tests/cefclient/browser/temp_window.h
@@ -0,0 +1,31 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_TEMP_WINDOW_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_TEMP_WINDOW_H_
+#pragma once
+
+#include "tests/cefclient/browser/client_types.h"
+
+#if defined(OS_WIN)
+#include "tests/cefclient/browser/temp_window_win.h"
+#elif defined(OS_LINUX)
+#include "tests/cefclient/browser/temp_window_x11.h"
+#elif defined(OS_MAC)
+#include "tests/cefclient/browser/temp_window_mac.h"
+#endif
+
+namespace client {
+
+#if defined(OS_WIN)
+typedef TempWindowWin TempWindow;
+#elif defined(OS_LINUX)
+typedef TempWindowX11 TempWindow;
+#elif defined(OS_MAC)
+typedef TempWindowMac TempWindow;
+#endif
+
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_TEMP_WINDOW_H_
diff --git a/tests/cefclient/browser/temp_window_mac.h b/tests/cefclient/browser/temp_window_mac.h
new file mode 100644
index 00000000..feded5cc
--- /dev/null
+++ b/tests/cefclient/browser/temp_window_mac.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_TEMP_WINDOW_MAC_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_TEMP_WINDOW_MAC_H_
+#pragma once
+
+#include "tests/cefclient/browser/client_types.h"
+
+namespace client {
+
+class TempWindowMacImpl;
+
+// Represents a singleton hidden window that acts as a temporary parent for
+// popup browsers. Only accessed on the UI thread.
+class TempWindowMac {
+ public:
+ // Returns the singleton window handle.
+ static CefWindowHandle GetWindowHandle();
+
+ private:
+ // A single instance will be created/owned by RootWindowManager.
+ friend class RootWindowManager;
+ // Allow deletion via std::unique_ptr only.
+ friend std::default_delete<TempWindowMac>;
+
+ TempWindowMac();
+ ~TempWindowMac();
+
+ std::unique_ptr<TempWindowMacImpl> impl_;
+
+ DISALLOW_COPY_AND_ASSIGN(TempWindowMac);
+};
+
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_TEMP_WINDOW_MAC_H_
diff --git a/tests/cefclient/browser/temp_window_mac.mm b/tests/cefclient/browser/temp_window_mac.mm
new file mode 100644
index 00000000..c2304458
--- /dev/null
+++ b/tests/cefclient/browser/temp_window_mac.mm
@@ -0,0 +1,59 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/temp_window_mac.h"
+
+#include <Cocoa/Cocoa.h>
+
+#include "include/base/cef_logging.h"
+#include "include/cef_app.h"
+
+namespace client {
+
+namespace {
+
+TempWindowMac* g_temp_window = nullptr;
+
+} // namespace
+
+class TempWindowMacImpl {
+ public:
+ TempWindowMacImpl() {
+ // Create a borderless non-visible 1x1 window.
+ window_ = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 1, 1)
+ styleMask:NSWindowStyleMaskBorderless
+ backing:NSBackingStoreBuffered
+ defer:NO];
+ CHECK(window_);
+ }
+ ~TempWindowMacImpl() {
+ DCHECK(window_);
+ [window_ close];
+ }
+
+ private:
+ NSWindow* window_;
+
+ friend class TempWindowMac;
+};
+
+TempWindowMac::TempWindowMac() {
+ DCHECK(!g_temp_window);
+ impl_.reset(new TempWindowMacImpl);
+ g_temp_window = this;
+}
+
+TempWindowMac::~TempWindowMac() {
+ impl_.reset();
+ g_temp_window = nullptr;
+}
+
+// static
+CefWindowHandle TempWindowMac::GetWindowHandle() {
+ DCHECK(g_temp_window);
+ return CAST_NSVIEW_TO_CEF_WINDOW_HANDLE(
+ g_temp_window->impl_->window_.contentView);
+}
+
+} // namespace client
diff --git a/tests/cefclient/browser/temp_window_win.cc b/tests/cefclient/browser/temp_window_win.cc
new file mode 100644
index 00000000..2bd74614
--- /dev/null
+++ b/tests/cefclient/browser/temp_window_win.cc
@@ -0,0 +1,57 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/temp_window_win.h"
+
+#include <windows.h>
+
+#include "include/base/cef_logging.h"
+
+namespace client {
+
+namespace {
+
+const wchar_t kWndClass[] = L"Client_TempWindow";
+
+// Create the temp window.
+HWND CreateTempWindow() {
+ HINSTANCE hInstance = ::GetModuleHandle(nullptr);
+
+ WNDCLASSEX wc = {0};
+ wc.cbSize = sizeof(wc);
+ wc.lpfnWndProc = DefWindowProc;
+ wc.hInstance = hInstance;
+ wc.lpszClassName = kWndClass;
+ RegisterClassEx(&wc);
+
+ // Create a 1x1 pixel hidden window.
+ return CreateWindow(kWndClass, 0, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, 0, 0,
+ 1, 1, nullptr, nullptr, hInstance, nullptr);
+}
+
+TempWindowWin* g_temp_window = nullptr;
+
+} // namespace
+
+TempWindowWin::TempWindowWin() : hwnd_(nullptr) {
+ DCHECK(!g_temp_window);
+ g_temp_window = this;
+
+ hwnd_ = CreateTempWindow();
+ CHECK(hwnd_);
+}
+
+TempWindowWin::~TempWindowWin() {
+ g_temp_window = nullptr;
+ DCHECK(hwnd_);
+ DestroyWindow(hwnd_);
+}
+
+// static
+CefWindowHandle TempWindowWin::GetWindowHandle() {
+ DCHECK(g_temp_window);
+ return g_temp_window->hwnd_;
+}
+
+} // namespace client
diff --git a/tests/cefclient/browser/temp_window_win.h b/tests/cefclient/browser/temp_window_win.h
new file mode 100644
index 00000000..2716a380
--- /dev/null
+++ b/tests/cefclient/browser/temp_window_win.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_TEMP_WINDOW_WIN_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_TEMP_WINDOW_WIN_H_
+#pragma once
+
+#include "include/cef_base.h"
+
+namespace client {
+
+// Represents a singleton hidden window that acts as a temporary parent for
+// popup browsers. Only accessed on the UI thread.
+class TempWindowWin {
+ public:
+ // Returns the singleton window handle.
+ static CefWindowHandle GetWindowHandle();
+
+ private:
+ // A single instance will be created/owned by RootWindowManager.
+ friend class RootWindowManager;
+ // Allow deletion via std::unique_ptr only.
+ friend std::default_delete<TempWindowWin>;
+
+ TempWindowWin();
+ ~TempWindowWin();
+
+ CefWindowHandle hwnd_;
+
+ DISALLOW_COPY_AND_ASSIGN(TempWindowWin);
+};
+
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_TEMP_WINDOW_WIN_H_
diff --git a/tests/cefclient/browser/temp_window_x11.cc b/tests/cefclient/browser/temp_window_x11.cc
new file mode 100644
index 00000000..de9f45d1
--- /dev/null
+++ b/tests/cefclient/browser/temp_window_x11.cc
@@ -0,0 +1,66 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/temp_window_x11.h"
+
+#include <X11/Xlib.h>
+
+#include "include/base/cef_logging.h"
+#include "include/cef_app.h"
+
+namespace client {
+
+namespace {
+
+// Create the temp window.
+::Window CreateTempWindow() {
+ ::Display* xdisplay = cef_get_xdisplay();
+ CHECK(xdisplay != 0);
+ ::Window parent_xwindow = DefaultRootWindow(xdisplay);
+
+ XSetWindowAttributes swa;
+ memset(&swa, 0, sizeof(swa));
+ swa.background_pixmap = None;
+ swa.override_redirect = false;
+ return XCreateWindow(xdisplay, parent_xwindow, 0, 0, 1, 1, // size (1x1px)
+ 0, // border width
+ CopyFromParent, // depth
+ InputOutput,
+ CopyFromParent, // visual
+ CWBackPixmap | CWOverrideRedirect, &swa);
+}
+
+// Close the temp window.
+void CloseTempWindow(::Window xwindow) {
+ ::Display* xdisplay = cef_get_xdisplay();
+ CHECK(xdisplay != 0);
+ XDestroyWindow(xdisplay, xwindow);
+}
+
+TempWindowX11* g_temp_window = nullptr;
+
+} // namespace
+
+TempWindowX11::TempWindowX11() : xwindow_(kNullWindowHandle) {
+ DCHECK(!g_temp_window);
+ g_temp_window = this;
+
+ xwindow_ = CreateTempWindow();
+ CHECK(xwindow_);
+}
+
+TempWindowX11::~TempWindowX11() {
+ g_temp_window = nullptr;
+ DCHECK(xwindow_);
+
+ CloseTempWindow(xwindow_);
+}
+
+// static
+CefWindowHandle TempWindowX11::GetWindowHandle() {
+ DCHECK(g_temp_window);
+ return g_temp_window->xwindow_;
+}
+
+} // namespace client
diff --git a/tests/cefclient/browser/temp_window_x11.h b/tests/cefclient/browser/temp_window_x11.h
new file mode 100644
index 00000000..849d02f0
--- /dev/null
+++ b/tests/cefclient/browser/temp_window_x11.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_TEMP_WINDOW_X11_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_TEMP_WINDOW_X11_H_
+#pragma once
+
+#include "include/cef_base.h"
+
+namespace client {
+
+// Represents a singleton hidden window that acts as a temporary parent for
+// popup browsers. Only accessed on the UI thread.
+class TempWindowX11 {
+ public:
+ // Returns the singleton window handle.
+ static CefWindowHandle GetWindowHandle();
+
+ private:
+ // A single instance will be created/owned by RootWindowManager.
+ friend class RootWindowManager;
+ // Allow deletion via std::unique_ptr only.
+ friend std::default_delete<TempWindowX11>;
+
+ TempWindowX11();
+ ~TempWindowX11();
+
+ CefWindowHandle xwindow_;
+
+ DISALLOW_COPY_AND_ASSIGN(TempWindowX11);
+};
+
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_TEMP_WINDOW_X11_H_
diff --git a/tests/cefclient/browser/test_runner.cc b/tests/cefclient/browser/test_runner.cc
new file mode 100644
index 00000000..e000b84d
--- /dev/null
+++ b/tests/cefclient/browser/test_runner.cc
@@ -0,0 +1,871 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/test_runner.h"
+
+#include <algorithm>
+#include <map>
+#include <set>
+#include <sstream>
+
+#include "include/base/cef_callback.h"
+#include "include/cef_parser.h"
+#include "include/cef_task.h"
+#include "include/cef_trace.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "include/wrapper/cef_stream_resource_handler.h"
+#include "tests/cefclient/browser/binding_test.h"
+#include "tests/cefclient/browser/client_handler.h"
+#include "tests/cefclient/browser/dialog_test.h"
+#include "tests/cefclient/browser/main_context.h"
+#include "tests/cefclient/browser/media_router_test.h"
+#include "tests/cefclient/browser/preferences_test.h"
+#include "tests/cefclient/browser/resource.h"
+#include "tests/cefclient/browser/response_filter_test.h"
+#include "tests/cefclient/browser/root_window_manager.h"
+#include "tests/cefclient/browser/scheme_test.h"
+#include "tests/cefclient/browser/server_test.h"
+#include "tests/cefclient/browser/urlrequest_test.h"
+#include "tests/cefclient/browser/window_test.h"
+#include "tests/shared/browser/resource_util.h"
+#include "tests/shared/common/string_util.h"
+
+namespace client {
+namespace test_runner {
+
+namespace {
+
+const char kTestHost[] = "tests";
+const char kLocalHost[] = "localhost";
+const char kTestOrigin[] = "http://tests/";
+
+// Pages handled via StringResourceProvider.
+const char kTestGetSourcePage[] = "get_source.html";
+const char kTestGetTextPage[] = "get_text.html";
+
+// Set page data and navigate the browser. Used in combination with
+// StringResourceProvider.
+void LoadStringResourcePage(CefRefPtr<CefBrowser> browser,
+ const std::string& page,
+ const std::string& data) {
+ CefRefPtr<CefClient> client = browser->GetHost()->GetClient();
+ ClientHandler* client_handler = static_cast<ClientHandler*>(client.get());
+ client_handler->SetStringResource(page, data);
+ browser->GetMainFrame()->LoadURL(kTestOrigin + page);
+}
+
+void RunGetSourceTest(CefRefPtr<CefBrowser> browser) {
+ class Visitor : public CefStringVisitor {
+ public:
+ explicit Visitor(CefRefPtr<CefBrowser> browser) : browser_(browser) {}
+ virtual void Visit(const CefString& string) override {
+ std::string source = AsciiStrReplace(string, "<", "&lt;");
+ source = AsciiStrReplace(source, ">", "&gt;");
+ std::stringstream ss;
+ ss << "<html><body bgcolor=\"white\">Source:<pre>" << source
+ << "</pre></body></html>";
+ LoadStringResourcePage(browser_, kTestGetSourcePage, ss.str());
+ }
+
+ private:
+ CefRefPtr<CefBrowser> browser_;
+ IMPLEMENT_REFCOUNTING(Visitor);
+ };
+
+ browser->GetMainFrame()->GetSource(new Visitor(browser));
+}
+
+void RunGetTextTest(CefRefPtr<CefBrowser> browser) {
+ class Visitor : public CefStringVisitor {
+ public:
+ explicit Visitor(CefRefPtr<CefBrowser> browser) : browser_(browser) {}
+ virtual void Visit(const CefString& string) override {
+ std::string text = AsciiStrReplace(string, "<", "&lt;");
+ text = AsciiStrReplace(text, ">", "&gt;");
+ std::stringstream ss;
+ ss << "<html><body bgcolor=\"white\">Text:<pre>" << text
+ << "</pre></body></html>";
+ LoadStringResourcePage(browser_, kTestGetTextPage, ss.str());
+ }
+
+ private:
+ CefRefPtr<CefBrowser> browser_;
+ IMPLEMENT_REFCOUNTING(Visitor);
+ };
+
+ browser->GetMainFrame()->GetText(new Visitor(browser));
+}
+
+void RunRequestTest(CefRefPtr<CefBrowser> browser) {
+ // Create a new request
+ CefRefPtr<CefRequest> request(CefRequest::Create());
+
+ if (browser->GetMainFrame()->GetURL().ToString().find("http://tests/") != 0) {
+ // The LoadRequest method will fail with "bad IPC message" reason
+ // INVALID_INITIATOR_ORIGIN (213) unless you first navigate to the
+ // request origin using some other mechanism (LoadURL, link click, etc).
+ Alert(browser,
+ "Please first navigate to a http://tests/ URL. "
+ "For example, first load Tests > Other Tests.");
+ return;
+ }
+
+ // Set the request URL
+ request->SetURL("http://tests/request");
+
+ // Add post data to the request. The correct method and content-
+ // type headers will be set by CEF.
+ CefRefPtr<CefPostDataElement> postDataElement(CefPostDataElement::Create());
+ std::string data = "arg1=val1&arg2=val2";
+ postDataElement->SetToBytes(data.length(), data.c_str());
+ CefRefPtr<CefPostData> postData(CefPostData::Create());
+ postData->AddElement(postDataElement);
+ request->SetPostData(postData);
+
+ // Add a custom header
+ CefRequest::HeaderMap headerMap;
+ headerMap.insert(std::make_pair("X-My-Header", "My Header Value"));
+ request->SetHeaderMap(headerMap);
+
+ // Load the request
+ browser->GetMainFrame()->LoadRequest(request);
+}
+
+void RunNewWindowTest(CefRefPtr<CefBrowser> browser) {
+ auto config = std::make_unique<RootWindowConfig>();
+ config->with_controls = true;
+ config->with_osr = browser->GetHost()->IsWindowRenderingDisabled();
+ MainContext::Get()->GetRootWindowManager()->CreateRootWindow(
+ std::move(config));
+}
+
+void RunPopupWindowTest(CefRefPtr<CefBrowser> browser) {
+ browser->GetMainFrame()->ExecuteJavaScript(
+ "window.open('https://www.google.com');", "about:blank", 0);
+}
+
+void ModifyZoom(CefRefPtr<CefBrowser> browser, double delta) {
+ if (!CefCurrentlyOn(TID_UI)) {
+ // Execute on the UI thread.
+ CefPostTask(TID_UI, base::BindOnce(&ModifyZoom, browser, delta));
+ return;
+ }
+
+ browser->GetHost()->SetZoomLevel(browser->GetHost()->GetZoomLevel() + delta);
+}
+
+const char kPrompt[] = "Prompt.";
+const char kPromptFPS[] = "FPS";
+const char kPromptDSF[] = "DSF";
+
+// Handles execution of prompt results.
+class PromptHandler : public CefMessageRouterBrowserSide::Handler {
+ public:
+ PromptHandler() {}
+
+ // Called due to cefQuery execution.
+ virtual bool OnQuery(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int64 query_id,
+ const CefString& request,
+ bool persistent,
+ CefRefPtr<Callback> callback) override {
+ // Parse |request| which takes the form "Prompt.[type]:[value]".
+ const std::string& request_str = request;
+ if (request_str.find(kPrompt) != 0) {
+ return false;
+ }
+
+ std::string type = request_str.substr(sizeof(kPrompt) - 1);
+ size_t delim = type.find(':');
+ if (delim == std::string::npos) {
+ return false;
+ }
+
+ const std::string& value = type.substr(delim + 1);
+ type = type.substr(0, delim);
+
+ // Canceling the prompt dialog returns a value of "null".
+ if (value != "null") {
+ if (type == kPromptFPS) {
+ SetFPS(browser, atoi(value.c_str()));
+ } else if (type == kPromptDSF) {
+ SetDSF(browser, static_cast<float>(atof(value.c_str())));
+ }
+ }
+
+ // Nothing is done with the response.
+ callback->Success(CefString());
+ return true;
+ }
+
+ private:
+ void SetFPS(CefRefPtr<CefBrowser> browser, int fps) {
+ if (fps <= 0) {
+ // Reset to the default value.
+ CefBrowserSettings settings;
+ MainContext::Get()->PopulateBrowserSettings(&settings);
+ fps = settings.windowless_frame_rate;
+ }
+
+ browser->GetHost()->SetWindowlessFrameRate(fps);
+ }
+
+ void SetDSF(CefRefPtr<CefBrowser> browser, float dsf) {
+ MainMessageLoop::Get()->PostClosure(
+ base::BindOnce(&PromptHandler::SetDSFOnMainThread, browser, dsf));
+ }
+
+ static void SetDSFOnMainThread(CefRefPtr<CefBrowser> browser, float dsf) {
+ RootWindow::GetForBrowser(browser->GetIdentifier())
+ ->SetDeviceScaleFactor(dsf);
+ }
+};
+
+void Prompt(CefRefPtr<CefBrowser> browser,
+ const std::string& type,
+ const std::string& label,
+ const std::string& default_value) {
+ // Prompt the user for a new value. Works as follows:
+ // 1. Show a prompt() dialog via JavaScript.
+ // 2. Pass the result to window.cefQuery().
+ // 3. Handle the result in PromptHandler::OnQuery.
+ const std::string& code = "window.cefQuery({'request': '" +
+ std::string(kPrompt) + type + ":' + prompt('" +
+ label + "', '" + default_value + "')});";
+ browser->GetMainFrame()->ExecuteJavaScript(
+ code, browser->GetMainFrame()->GetURL(), 0);
+}
+
+void PromptFPS(CefRefPtr<CefBrowser> browser) {
+ if (!CefCurrentlyOn(TID_UI)) {
+ // Execute on the UI thread.
+ CefPostTask(TID_UI, base::BindOnce(&PromptFPS, browser));
+ return;
+ }
+
+ // Format the default value string.
+ std::stringstream ss;
+ ss << browser->GetHost()->GetWindowlessFrameRate();
+
+ Prompt(browser, kPromptFPS, "Enter FPS", ss.str());
+}
+
+void PromptDSF(CefRefPtr<CefBrowser> browser) {
+ if (!MainMessageLoop::Get()->RunsTasksOnCurrentThread()) {
+ // Execute on the main thread.
+ MainMessageLoop::Get()->PostClosure(base::BindOnce(&PromptDSF, browser));
+ return;
+ }
+
+ // Format the default value string.
+ std::stringstream ss;
+ ss << RootWindow::GetForBrowser(browser->GetIdentifier())
+ ->GetDeviceScaleFactor();
+
+ Prompt(browser, kPromptDSF, "Enter Device Scale Factor", ss.str());
+}
+
+void BeginTracing() {
+ if (!CefCurrentlyOn(TID_UI)) {
+ // Execute on the UI thread.
+ CefPostTask(TID_UI, base::BindOnce(&BeginTracing));
+ return;
+ }
+
+ CefBeginTracing(CefString(), nullptr);
+}
+
+void EndTracing(CefRefPtr<CefBrowser> browser) {
+ if (!CefCurrentlyOn(TID_UI)) {
+ // Execute on the UI thread.
+ CefPostTask(TID_UI, base::BindOnce(&EndTracing, browser));
+ return;
+ }
+
+ class Client : public CefEndTracingCallback, public CefRunFileDialogCallback {
+ public:
+ explicit Client(CefRefPtr<CefBrowser> browser) : browser_(browser) {
+ RunDialog();
+ }
+
+ void RunDialog() {
+ static const char kDefaultFileName[] = "trace.txt";
+ std::string path = MainContext::Get()->GetDownloadPath(kDefaultFileName);
+ if (path.empty()) {
+ path = kDefaultFileName;
+ }
+
+ // Results in a call to OnFileDialogDismissed.
+ browser_->GetHost()->RunFileDialog(
+ FILE_DIALOG_SAVE,
+ /*title=*/CefString(), path,
+ /*accept_filters=*/std::vector<CefString>(), this);
+ }
+
+ void OnFileDialogDismissed(
+ const std::vector<CefString>& file_paths) override {
+ if (!file_paths.empty()) {
+ // File selected. Results in a call to OnEndTracingComplete.
+ CefEndTracing(file_paths.front(), this);
+ } else {
+ // No file selected. Discard the trace data.
+ CefEndTracing(CefString(), nullptr);
+ }
+ }
+
+ void OnEndTracingComplete(const CefString& tracing_file) override {
+ Alert(browser_,
+ "File \"" + tracing_file.ToString() + "\" saved successfully.");
+ }
+
+ private:
+ CefRefPtr<CefBrowser> browser_;
+
+ IMPLEMENT_REFCOUNTING(Client);
+ };
+
+ new Client(browser);
+}
+
+void PrintToPDF(CefRefPtr<CefBrowser> browser) {
+ if (!CefCurrentlyOn(TID_UI)) {
+ // Execute on the UI thread.
+ CefPostTask(TID_UI, base::BindOnce(&PrintToPDF, browser));
+ return;
+ }
+
+ class Client : public CefPdfPrintCallback, public CefRunFileDialogCallback {
+ public:
+ explicit Client(CefRefPtr<CefBrowser> browser) : browser_(browser) {
+ RunDialog();
+ }
+
+ void RunDialog() {
+ static const char kDefaultFileName[] = "output.pdf";
+ std::string path = MainContext::Get()->GetDownloadPath(kDefaultFileName);
+ if (path.empty()) {
+ path = kDefaultFileName;
+ }
+
+ std::vector<CefString> accept_filters;
+ accept_filters.push_back(".pdf");
+
+ // Results in a call to OnFileDialogDismissed.
+ browser_->GetHost()->RunFileDialog(FILE_DIALOG_SAVE,
+ /*title=*/CefString(), path,
+ accept_filters, this);
+ }
+
+ void OnFileDialogDismissed(
+ const std::vector<CefString>& file_paths) override {
+ if (!file_paths.empty()) {
+ CefPdfPrintSettings settings;
+
+ // Display a header and footer.
+ settings.display_header_footer = true;
+ CefString(&settings.header_template) =
+ "<div style=\"width: 100%; font-size: 9px; position: relative;\">"
+ "<div style=\"position: absolute; left: 5px;\">"
+ "<span class=\"title\"></span></div>"
+ "</div>";
+ CefString(&settings.footer_template) =
+ "<div style=\"width: 100%; font-size: 9px; position: relative;\">"
+ "<div style=\"position: absolute; left: 5px;\">"
+ "<span class=\"date\"></span></div>"
+ "<div style=\"position: absolute; right: 5px;\">"
+ "<span class=\"pageNumber\"></span>/"
+ "<span class=\"totalPages\"></span></div>"
+ "</div>";
+
+ // Print to the selected PDF file.
+ browser_->GetHost()->PrintToPDF(file_paths[0], settings, this);
+ }
+ }
+
+ void OnPdfPrintFinished(const CefString& path, bool ok) override {
+ Alert(browser_, "File \"" + path.ToString() + "\" " +
+ (ok ? "saved successfully." : "failed to save."));
+ }
+
+ private:
+ CefRefPtr<CefBrowser> browser_;
+
+ IMPLEMENT_REFCOUNTING(Client);
+ };
+
+ new Client(browser);
+}
+
+void MuteAudio(CefRefPtr<CefBrowser> browser, bool mute) {
+ CefRefPtr<CefBrowserHost> host = browser->GetHost();
+ host->SetAudioMuted(mute);
+}
+
+void RunOtherTests(CefRefPtr<CefBrowser> browser) {
+ browser->GetMainFrame()->LoadURL("http://tests/other_tests");
+}
+
+// Provider that dumps the request contents.
+class RequestDumpResourceProvider : public CefResourceManager::Provider {
+ public:
+ explicit RequestDumpResourceProvider(const std::string& url) : url_(url) {
+ DCHECK(!url.empty());
+ }
+
+ bool OnRequest(scoped_refptr<CefResourceManager::Request> request) override {
+ CEF_REQUIRE_IO_THREAD();
+
+ const std::string& url = request->url();
+ if (url != url_) {
+ // Not handled by this provider.
+ return false;
+ }
+
+ CefResponse::HeaderMap response_headers;
+ CefRefPtr<CefStreamReader> response =
+ GetDumpResponse(request->request(), response_headers);
+
+ request->Continue(new CefStreamResourceHandler(200, "OK", "text/html",
+ response_headers, response));
+ return true;
+ }
+
+ private:
+ std::string url_;
+
+ DISALLOW_COPY_AND_ASSIGN(RequestDumpResourceProvider);
+};
+
+// Provider that returns string data for specific pages. Used in combination
+// with LoadStringResourcePage().
+class StringResourceProvider : public CefResourceManager::Provider {
+ public:
+ StringResourceProvider(const std::set<std::string>& pages,
+ StringResourceMap* string_resource_map)
+ : pages_(pages), string_resource_map_(string_resource_map) {
+ DCHECK(!pages.empty());
+ }
+
+ bool OnRequest(scoped_refptr<CefResourceManager::Request> request) override {
+ CEF_REQUIRE_IO_THREAD();
+
+ const std::string& url = request->url();
+ if (url.find(kTestOrigin) != 0U) {
+ // Not handled by this provider.
+ return false;
+ }
+
+ const std::string& page = url.substr(strlen(kTestOrigin));
+ if (pages_.find(page) == pages_.end()) {
+ // Not handled by this provider.
+ return false;
+ }
+
+ std::string value;
+ StringResourceMap::const_iterator it = string_resource_map_->find(page);
+ if (it != string_resource_map_->end()) {
+ value = it->second;
+ } else {
+ value = "<html><body>No data available</body></html>";
+ }
+
+ CefRefPtr<CefStreamReader> response = CefStreamReader::CreateForData(
+ static_cast<void*>(const_cast<char*>(value.c_str())), value.size());
+
+ request->Continue(new CefStreamResourceHandler(
+ 200, "OK", "text/html", CefResponse::HeaderMap(), response));
+ return true;
+ }
+
+ private:
+ const std::set<std::string> pages_;
+
+ // Only accessed on the IO thread.
+ StringResourceMap* string_resource_map_;
+
+ DISALLOW_COPY_AND_ASSIGN(StringResourceProvider);
+};
+
+// Add a file extension to |url| if none is currently specified.
+std::string RequestUrlFilter(const std::string& url) {
+ if (url.find(kTestOrigin) != 0U) {
+ // Don't filter anything outside of the test origin.
+ return url;
+ }
+
+ // Identify where the query or fragment component, if any, begins.
+ size_t suffix_pos = url.find('?');
+ if (suffix_pos == std::string::npos) {
+ suffix_pos = url.find('#');
+ }
+
+ std::string url_base, url_suffix;
+ if (suffix_pos == std::string::npos) {
+ url_base = url;
+ } else {
+ url_base = url.substr(0, suffix_pos);
+ url_suffix = url.substr(suffix_pos);
+ }
+
+ // Identify the last path component.
+ size_t path_pos = url_base.rfind('/');
+ if (path_pos == std::string::npos) {
+ return url;
+ }
+
+ const std::string& path_component = url_base.substr(path_pos);
+
+ // Identify if a file extension is currently specified.
+ size_t ext_pos = path_component.rfind(".");
+ if (ext_pos != std::string::npos) {
+ return url;
+ }
+
+ // Rebuild the URL with a file extension.
+ return url_base + ".html" + url_suffix;
+}
+
+} // namespace
+
+void RunTest(CefRefPtr<CefBrowser> browser, int id) {
+ if (!browser) {
+ return;
+ }
+
+ switch (id) {
+ case ID_TESTS_GETSOURCE:
+ RunGetSourceTest(browser);
+ break;
+ case ID_TESTS_GETTEXT:
+ RunGetTextTest(browser);
+ break;
+ case ID_TESTS_WINDOW_NEW:
+ RunNewWindowTest(browser);
+ break;
+ case ID_TESTS_WINDOW_POPUP:
+ RunPopupWindowTest(browser);
+ break;
+ case ID_TESTS_REQUEST:
+ RunRequestTest(browser);
+ break;
+ case ID_TESTS_ZOOM_IN:
+ ModifyZoom(browser, 0.5);
+ break;
+ case ID_TESTS_ZOOM_OUT:
+ ModifyZoom(browser, -0.5);
+ break;
+ case ID_TESTS_ZOOM_RESET:
+ browser->GetHost()->SetZoomLevel(0.0);
+ break;
+ case ID_TESTS_OSR_FPS:
+ PromptFPS(browser);
+ break;
+ case ID_TESTS_OSR_DSF:
+ PromptDSF(browser);
+ break;
+ case ID_TESTS_TRACING_BEGIN:
+ BeginTracing();
+ break;
+ case ID_TESTS_TRACING_END:
+ EndTracing(browser);
+ break;
+ case ID_TESTS_PRINT:
+ browser->GetHost()->Print();
+ break;
+ case ID_TESTS_PRINT_TO_PDF:
+ PrintToPDF(browser);
+ break;
+ case ID_TESTS_MUTE_AUDIO:
+ MuteAudio(browser, true);
+ break;
+ case ID_TESTS_UNMUTE_AUDIO:
+ MuteAudio(browser, false);
+ break;
+ case ID_TESTS_OTHER_TESTS:
+ RunOtherTests(browser);
+ break;
+ }
+}
+
+std::string DumpRequestContents(CefRefPtr<CefRequest> request) {
+ std::stringstream ss;
+
+ ss << "URL: " << std::string(request->GetURL());
+ ss << "\nMethod: " << std::string(request->GetMethod());
+
+ CefRequest::HeaderMap headerMap;
+ request->GetHeaderMap(headerMap);
+ if (headerMap.size() > 0) {
+ ss << "\nHeaders:";
+ CefRequest::HeaderMap::const_iterator it = headerMap.begin();
+ for (; it != headerMap.end(); ++it) {
+ ss << "\n\t" << std::string((*it).first) << ": "
+ << std::string((*it).second);
+ }
+ }
+
+ CefRefPtr<CefPostData> postData = request->GetPostData();
+ if (postData.get()) {
+ CefPostData::ElementVector elements;
+ postData->GetElements(elements);
+ if (elements.size() > 0) {
+ ss << "\nPost Data:";
+ CefRefPtr<CefPostDataElement> element;
+ CefPostData::ElementVector::const_iterator it = elements.begin();
+ for (; it != elements.end(); ++it) {
+ element = (*it);
+ if (element->GetType() == PDE_TYPE_BYTES) {
+ // the element is composed of bytes
+ ss << "\n\tBytes: ";
+ if (element->GetBytesCount() == 0) {
+ ss << "(empty)";
+ } else {
+ // retrieve the data.
+ size_t size = element->GetBytesCount();
+ char* bytes = new char[size];
+ element->GetBytes(size, bytes);
+ ss << std::string(bytes, size);
+ delete[] bytes;
+ }
+ } else if (element->GetType() == PDE_TYPE_FILE) {
+ ss << "\n\tFile: " << std::string(element->GetFile());
+ }
+ }
+ }
+ }
+
+ return ss.str();
+}
+
+CefRefPtr<CefStreamReader> GetDumpResponse(
+ CefRefPtr<CefRequest> request,
+ CefResponse::HeaderMap& response_headers) {
+ std::string origin;
+
+ // Extract the origin request header, if any. It will be specified for
+ // cross-origin requests.
+ {
+ CefRequest::HeaderMap requestMap;
+ request->GetHeaderMap(requestMap);
+
+ CefRequest::HeaderMap::const_iterator it = requestMap.begin();
+ for (; it != requestMap.end(); ++it) {
+ const std::string& key = AsciiStrToLower(it->first);
+ if (key == "origin") {
+ origin = it->second;
+ break;
+ }
+ }
+ }
+
+ if (!origin.empty() &&
+ (origin.find("http://" + std::string(kTestHost)) == 0 ||
+ origin.find("http://" + std::string(kLocalHost)) == 0)) {
+ // Allow cross-origin XMLHttpRequests from test origins.
+ response_headers.insert(
+ std::make_pair("Access-Control-Allow-Origin", origin));
+
+ // Allow the custom header from the xmlhttprequest.html example.
+ response_headers.insert(
+ std::make_pair("Access-Control-Allow-Headers", "My-Custom-Header"));
+ }
+
+ const std::string& dump = DumpRequestContents(request);
+ std::string str =
+ "<html><body bgcolor=\"white\"><pre>" + dump + "</pre></body></html>";
+ CefRefPtr<CefStreamReader> stream = CefStreamReader::CreateForData(
+ static_cast<void*>(const_cast<char*>(str.c_str())), str.size());
+ DCHECK(stream);
+ return stream;
+}
+
+std::string GetDataURI(const std::string& data, const std::string& mime_type) {
+ return "data:" + mime_type + ";base64," +
+ CefURIEncode(CefBase64Encode(data.data(), data.size()), false)
+ .ToString();
+}
+
+std::string GetErrorString(cef_errorcode_t code) {
+// Case condition that returns |code| as a string.
+#define CASE(code) \
+ case code: \
+ return #code
+
+ switch (code) {
+ CASE(ERR_NONE);
+ CASE(ERR_FAILED);
+ CASE(ERR_ABORTED);
+ CASE(ERR_INVALID_ARGUMENT);
+ CASE(ERR_INVALID_HANDLE);
+ CASE(ERR_FILE_NOT_FOUND);
+ CASE(ERR_TIMED_OUT);
+ CASE(ERR_FILE_TOO_BIG);
+ CASE(ERR_UNEXPECTED);
+ CASE(ERR_ACCESS_DENIED);
+ CASE(ERR_NOT_IMPLEMENTED);
+ CASE(ERR_CONNECTION_CLOSED);
+ CASE(ERR_CONNECTION_RESET);
+ CASE(ERR_CONNECTION_REFUSED);
+ CASE(ERR_CONNECTION_ABORTED);
+ CASE(ERR_CONNECTION_FAILED);
+ CASE(ERR_NAME_NOT_RESOLVED);
+ CASE(ERR_INTERNET_DISCONNECTED);
+ CASE(ERR_SSL_PROTOCOL_ERROR);
+ CASE(ERR_ADDRESS_INVALID);
+ CASE(ERR_ADDRESS_UNREACHABLE);
+ CASE(ERR_SSL_CLIENT_AUTH_CERT_NEEDED);
+ CASE(ERR_TUNNEL_CONNECTION_FAILED);
+ CASE(ERR_NO_SSL_VERSIONS_ENABLED);
+ CASE(ERR_SSL_VERSION_OR_CIPHER_MISMATCH);
+ CASE(ERR_SSL_RENEGOTIATION_REQUESTED);
+ CASE(ERR_CERT_COMMON_NAME_INVALID);
+ CASE(ERR_CERT_DATE_INVALID);
+ CASE(ERR_CERT_AUTHORITY_INVALID);
+ CASE(ERR_CERT_CONTAINS_ERRORS);
+ CASE(ERR_CERT_NO_REVOCATION_MECHANISM);
+ CASE(ERR_CERT_UNABLE_TO_CHECK_REVOCATION);
+ CASE(ERR_CERT_REVOKED);
+ CASE(ERR_CERT_INVALID);
+ CASE(ERR_CERT_END);
+ CASE(ERR_INVALID_URL);
+ CASE(ERR_DISALLOWED_URL_SCHEME);
+ CASE(ERR_UNKNOWN_URL_SCHEME);
+ CASE(ERR_TOO_MANY_REDIRECTS);
+ CASE(ERR_UNSAFE_REDIRECT);
+ CASE(ERR_UNSAFE_PORT);
+ CASE(ERR_INVALID_RESPONSE);
+ CASE(ERR_INVALID_CHUNKED_ENCODING);
+ CASE(ERR_METHOD_NOT_SUPPORTED);
+ CASE(ERR_UNEXPECTED_PROXY_AUTH);
+ CASE(ERR_EMPTY_RESPONSE);
+ CASE(ERR_RESPONSE_HEADERS_TOO_BIG);
+ CASE(ERR_CACHE_MISS);
+ CASE(ERR_INSECURE_RESPONSE);
+ default:
+ return "UNKNOWN";
+ }
+}
+
+void SetupResourceManager(CefRefPtr<CefResourceManager> resource_manager,
+ StringResourceMap* string_resource_map) {
+ if (!CefCurrentlyOn(TID_IO)) {
+ // Execute on the browser IO thread.
+ CefPostTask(TID_IO, base::BindOnce(SetupResourceManager, resource_manager,
+ string_resource_map));
+ return;
+ }
+
+ const std::string& test_origin = kTestOrigin;
+
+ // Add the URL filter.
+ resource_manager->SetUrlFilter(base::BindRepeating(RequestUrlFilter));
+
+ // Add provider for resource dumps.
+ resource_manager->AddProvider(
+ new RequestDumpResourceProvider(test_origin + "request.html"), 0,
+ std::string());
+
+ // Set of supported string pages.
+ std::set<std::string> string_pages;
+ string_pages.insert(kTestGetSourcePage);
+ string_pages.insert(kTestGetTextPage);
+
+ if (string_resource_map) {
+ // Add provider for string resources.
+ resource_manager->AddProvider(
+ new StringResourceProvider(string_pages, string_resource_map), 0,
+ std::string());
+ }
+
+// Add provider for bundled resource files.
+#if defined(OS_WIN)
+ // Read resources from the binary.
+ resource_manager->AddProvider(
+ CreateBinaryResourceProvider(test_origin, std::string()), 100,
+ std::string());
+#elif defined(OS_POSIX)
+ // Read resources from a directory on disk.
+ std::string resource_dir;
+ if (GetResourceDir(resource_dir)) {
+ resource_manager->AddDirectoryProvider(test_origin, resource_dir, 100,
+ std::string());
+ }
+#endif
+}
+
+void Alert(CefRefPtr<CefBrowser> browser, const std::string& message) {
+ if (browser->GetHost()->GetExtension()) {
+ // Alerts originating from extension hosts should instead be displayed in
+ // the active browser.
+ browser = MainContext::Get()->GetRootWindowManager()->GetActiveBrowser();
+ if (!browser) {
+ return;
+ }
+ }
+
+ // Escape special characters in the message.
+ std::string msg = AsciiStrReplace(message, "\\", "\\\\");
+ msg = AsciiStrReplace(msg, "'", "\\'");
+
+ // Execute a JavaScript alert().
+ CefRefPtr<CefFrame> frame = browser->GetMainFrame();
+ frame->ExecuteJavaScript("alert('" + msg + "');", frame->GetURL(), 0);
+}
+
+bool IsTestURL(const std::string& url, const std::string& path) {
+ CefURLParts parts;
+ CefParseURL(url, parts);
+
+ const std::string& url_host = CefString(&parts.host);
+ if (url_host != kTestHost && url_host != kLocalHost) {
+ return false;
+ }
+
+ const std::string& url_path = CefString(&parts.path);
+ return url_path.find(path) == 0;
+}
+
+void CreateMessageHandlers(MessageHandlerSet& handlers) {
+ handlers.insert(new PromptHandler);
+
+ // Create the binding test handlers.
+ binding_test::CreateMessageHandlers(handlers);
+
+ // Create the dialog test handlers.
+ dialog_test::CreateMessageHandlers(handlers);
+
+ // Create the media router test handlers.
+ media_router_test::CreateMessageHandlers(handlers);
+
+ // Create the preferences test handlers.
+ preferences_test::CreateMessageHandlers(handlers);
+
+ // Create the server test handlers.
+ server_test::CreateMessageHandlers(handlers);
+
+ // Create the urlrequest test handlers.
+ urlrequest_test::CreateMessageHandlers(handlers);
+
+ // Create the window test handlers.
+ window_test::CreateMessageHandlers(handlers);
+}
+
+void RegisterSchemeHandlers() {
+ // Register the scheme handler.
+ scheme_test::RegisterSchemeHandlers();
+}
+
+CefRefPtr<CefResponseFilter> GetResourceResponseFilter(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response) {
+ // Create the response filter.
+ return response_filter_test::GetResourceResponseFilter(browser, frame,
+ request, response);
+}
+
+} // namespace test_runner
+} // namespace client
diff --git a/tests/cefclient/browser/test_runner.h b/tests/cefclient/browser/test_runner.h
new file mode 100644
index 00000000..ed0172dd
--- /dev/null
+++ b/tests/cefclient/browser/test_runner.h
@@ -0,0 +1,69 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_TEST_RUNNER_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_TEST_RUNNER_H_
+#pragma once
+
+#include <set>
+#include <string>
+
+#include "include/cef_browser.h"
+#include "include/cef_request.h"
+#include "include/wrapper/cef_message_router.h"
+#include "include/wrapper/cef_resource_manager.h"
+
+namespace client {
+namespace test_runner {
+
+// Run a test.
+void RunTest(CefRefPtr<CefBrowser> browser, int id);
+
+// Returns the contents of the CefRequest as a string.
+std::string DumpRequestContents(CefRefPtr<CefRequest> request);
+
+// Returns the dump response as a stream. |request| is the request.
+// |response_headers| will be populated with extra response headers, if any.
+CefRefPtr<CefStreamReader> GetDumpResponse(
+ CefRefPtr<CefRequest> request,
+ CefResponse::HeaderMap& response_headers);
+
+// Returns a data: URI with the specified contents.
+std::string GetDataURI(const std::string& data, const std::string& mime_type);
+
+// Returns the string representation of the specified error code.
+std::string GetErrorString(cef_errorcode_t code);
+
+typedef std::map<std::string, std::string> StringResourceMap;
+
+// Set up the resource manager for tests.
+void SetupResourceManager(CefRefPtr<CefResourceManager> resource_manager,
+ StringResourceMap* string_resource_map);
+
+// Show a JS alert message.
+void Alert(CefRefPtr<CefBrowser> browser, const std::string& message);
+
+// Returns true if |url| is a test URL with the specified |path|. This matches
+// both http://tests/<path> and http://localhost:xxxx/<path>.
+bool IsTestURL(const std::string& url, const std::string& path);
+
+// Create all CefMessageRouterBrowserSide::Handler objects. They will be
+// deleted when the ClientHandler is destroyed.
+typedef std::set<CefMessageRouterBrowserSide::Handler*> MessageHandlerSet;
+void CreateMessageHandlers(MessageHandlerSet& handlers);
+
+// Register scheme handlers for tests.
+void RegisterSchemeHandlers();
+
+// Create a resource response filter for tests.
+CefRefPtr<CefResponseFilter> GetResourceResponseFilter(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response);
+
+} // namespace test_runner
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_TEST_RUNNER_H_
diff --git a/tests/cefclient/browser/text_input_client_osr_mac.h b/tests/cefclient/browser/text_input_client_osr_mac.h
new file mode 100644
index 00000000..def6d555
--- /dev/null
+++ b/tests/cefclient/browser/text_input_client_osr_mac.h
@@ -0,0 +1,78 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. Portions copyright
+// 2013 The Chromium Authors. All rights reserved. Use of this source code is
+// governed by a BSD-style license that can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_OSR_TEXT_INPUT_CLIENT_OSR_MAC_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_OSR_TEXT_INPUT_CLIENT_OSR_MAC_H_
+#pragma once
+
+#import <Cocoa/Cocoa.h>
+#include <string>
+#include <vector>
+
+#include "include/cef_browser.h"
+#include "include/cef_render_handler.h"
+
+// Implementation for the NSTextInputClient protocol used for enabling IME on
+// mac when window rendering is disabled.
+
+@interface CefTextInputClientOSRMac : NSObject <NSTextInputClient> {
+ @private
+
+ // The range of current marked text inside the whole content of the DOM node
+ // being edited.
+ NSRange markedRange_;
+
+ // The current composition character range and its bounds.
+ CefRange composition_range_;
+ std::vector<CefRect> composition_bounds_;
+
+ // Represents the input-method attributes supported by this object.
+ NSArray* validAttributesForMarkedText_;
+
+ // Indicates if we are currently handling a key down event.
+ BOOL handlingKeyDown_;
+
+ // Indicates if there is any marked text.
+ BOOL hasMarkedText_;
+
+ // Indicates whether there was any marked text prior to handling
+ // the current key event.
+ BOOL oldHasMarkedText_;
+
+ // Indicates if unmarkText is called or not when handling a keyboard
+ // event.
+ BOOL unmarkTextCalled_;
+
+ // The selected range, cached from a message sent by the renderer.
+ NSRange selectedRange_;
+
+ // Text to be inserted which was generated by handling a key down event.
+ std::string textToBeInserted_;
+
+ // Marked text which was generated by handling a key down event.
+ CefString markedText_;
+
+ // Underline information of the |markedText_|.
+ std::vector<CefCompositionUnderline> underlines_;
+
+ // Replacement range information received from |setMarkedText:|.
+ CefRange setMarkedTextReplacementRange_;
+
+ CefRefPtr<CefBrowser> browser_;
+}
+
+@property(nonatomic, readonly) NSRange selectedRange;
+@property(nonatomic) BOOL handlingKeyDown;
+
+- (id)initWithBrowser:(CefRefPtr<CefBrowser>)browser;
+- (void)detach;
+- (void)HandleKeyEventBeforeTextInputClient:(NSEvent*)keyEvent;
+- (void)HandleKeyEventAfterTextInputClient:(CefKeyEvent)keyEvent;
+- (void)ChangeCompositionRange:(CefRange)range
+ character_bounds:(const CefRenderHandler::RectList&)bounds;
+- (void)cancelComposition;
+
+@end
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_OSR_TEXT_INPUT_CLIENT_OSR_MAC_H_
diff --git a/tests/cefclient/browser/text_input_client_osr_mac.mm b/tests/cefclient/browser/text_input_client_osr_mac.mm
new file mode 100644
index 00000000..8e3e902e
--- /dev/null
+++ b/tests/cefclient/browser/text_input_client_osr_mac.mm
@@ -0,0 +1,363 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. Portions copyright
+// 2013 The Chromium Authors. All rights reserved. Use of this source code is
+// governed by a BSD-style license that can be found in the LICENSE file.
+
+// Implementation based on
+// content/browser/renderer_host/render_widget_host_view_mac.mm from Chromium.
+
+#include "text_input_client_osr_mac.h"
+#include "include/cef_client.h"
+
+#define ColorBLACK 0xFF000000 // Same as Blink SKColor.
+
+namespace {
+
+// TODO(suzhe): Upstream this function.
+cef_color_t CefColorFromNSColor(NSColor* color) {
+ CGFloat r, g, b, a;
+ [color getRed:&r green:&g blue:&b alpha:&a];
+
+ return std::max(0, std::min(static_cast<int>(lroundf(255.0f * a)), 255))
+ << 24 |
+ std::max(0, std::min(static_cast<int>(lroundf(255.0f * r)), 255))
+ << 16 |
+ std::max(0, std::min(static_cast<int>(lroundf(255.0f * g)), 255))
+ << 8 |
+ std::max(0, std::min(static_cast<int>(lroundf(255.0f * b)), 255));
+}
+
+// Extract underline information from an attributed string. Mostly copied from
+// third_party/WebKit/Source/WebKit/mac/WebView/WebHTMLView.mm
+void ExtractUnderlines(NSAttributedString* string,
+ std::vector<CefCompositionUnderline>* underlines) {
+ int length = static_cast<int>([[string string] length]);
+ int i = 0;
+ while (i < length) {
+ NSRange range;
+ NSDictionary* attrs = [string attributesAtIndex:i
+ longestEffectiveRange:&range
+ inRange:NSMakeRange(i, length - i)];
+ NSNumber* style = [attrs objectForKey:NSUnderlineStyleAttributeName];
+ if (style) {
+ cef_color_t color = ColorBLACK;
+ if (NSColor* colorAttr =
+ [attrs objectForKey:NSUnderlineColorAttributeName]) {
+ color = CefColorFromNSColor(
+ [colorAttr colorUsingColorSpaceName:NSDeviceRGBColorSpace]);
+ }
+ cef_composition_underline_t line = {{static_cast<int>(range.location),
+ static_cast<int>(NSMaxRange(range))},
+ color,
+ 0,
+ [style intValue] > 1};
+ underlines->push_back(line);
+ }
+ i = static_cast<int>(range.location + range.length);
+ }
+}
+
+} // namespace
+
+extern "C" {
+extern NSString* NSTextInputReplacementRangeAttributeName;
+}
+
+@implementation CefTextInputClientOSRMac
+
+@synthesize selectedRange = selectedRange_;
+@synthesize handlingKeyDown = handlingKeyDown_;
+
+- (id)initWithBrowser:(CefRefPtr<CefBrowser>)browser {
+ self = [super init];
+ browser_ = browser;
+ return self;
+}
+
+- (void)detach {
+ browser_ = nullptr;
+}
+
+- (NSArray*)validAttributesForMarkedText {
+ if (!validAttributesForMarkedText_) {
+ validAttributesForMarkedText_ = [[NSArray alloc]
+ initWithObjects:NSUnderlineStyleAttributeName,
+ NSUnderlineColorAttributeName,
+ NSMarkedClauseSegmentAttributeName,
+ NSTextInputReplacementRangeAttributeName, nil];
+ }
+ return validAttributesForMarkedText_;
+}
+
+- (NSRange)selectedRange {
+ if (selectedRange_.location == NSNotFound || selectedRange_.length == 0) {
+ return NSMakeRange(NSNotFound, 0);
+ }
+ return selectedRange_;
+}
+
+- (NSRange)markedRange {
+ return hasMarkedText_ ? markedRange_ : NSMakeRange(NSNotFound, 0);
+}
+
+- (BOOL)hasMarkedText {
+ return hasMarkedText_;
+}
+
+- (void)insertText:(id)aString replacementRange:(NSRange)replacementRange {
+ BOOL isAttributedString = [aString isKindOfClass:[NSAttributedString class]];
+ NSString* im_text = isAttributedString ? [aString string] : aString;
+ if (handlingKeyDown_) {
+ textToBeInserted_.append([im_text UTF8String]);
+ } else {
+ cef_range_t range = {static_cast<int>(replacementRange.location),
+ static_cast<int>(NSMaxRange(replacementRange))};
+ browser_->GetHost()->ImeCommitText([im_text UTF8String], range, 0);
+ }
+
+ // Inserting text will delete all marked text automatically.
+ hasMarkedText_ = NO;
+}
+
+- (void)doCommandBySelector:(SEL)aSelector {
+ // An input method calls this function to dispatch an editing command to be
+ // handled by this view.
+}
+
+- (void)setMarkedText:(id)aString
+ selectedRange:(NSRange)newSelRange
+ replacementRange:(NSRange)replacementRange {
+ // An input method has updated the composition string. We send the given text
+ // and range to the browser so it can update the composition node of Blink.
+
+ BOOL isAttributedString = [aString isKindOfClass:[NSAttributedString class]];
+ NSString* im_text = isAttributedString ? [aString string] : aString;
+ int length = static_cast<int>([im_text length]);
+
+ // |markedRange_| will get set in a callback from ImeSetComposition().
+ selectedRange_ = newSelRange;
+ markedText_ = [im_text UTF8String];
+ hasMarkedText_ = (length > 0);
+ underlines_.clear();
+
+ if (isAttributedString) {
+ ExtractUnderlines(aString, &underlines_);
+ } else {
+ // Use a thin black underline by default.
+ cef_composition_underline_t line = {{0, length}, ColorBLACK, 0, false};
+ underlines_.push_back(line);
+ }
+
+ // If we are handling a key down event then ImeSetComposition() will be
+ // called from the keyEvent: method.
+ // Input methods of Mac use setMarkedText calls with empty text to cancel an
+ // ongoing composition. Our input method backend will automatically cancel an
+ // ongoing composition when we send empty text.
+ if (handlingKeyDown_) {
+ setMarkedTextReplacementRange_ = {
+ static_cast<int>(replacementRange.location),
+ static_cast<int>(NSMaxRange(replacementRange))};
+ } else if (!handlingKeyDown_) {
+ CefRange replacement_range(static_cast<int>(replacementRange.location),
+ static_cast<int>(NSMaxRange(replacementRange)));
+ CefRange selection_range(static_cast<int>(newSelRange.location),
+ static_cast<int>(NSMaxRange(newSelRange)));
+
+ browser_->GetHost()->ImeSetComposition(markedText_, underlines_,
+ replacement_range, selection_range);
+ }
+}
+
+- (void)unmarkText {
+ // Delete the composition node of the browser and finish an ongoing
+ // composition.
+ // It seems that, instead of calling this method, an input method will call
+ // the setMarkedText method with empty text to cancel ongoing composition.
+ // Implement this method even though we don't expect it to be called.
+ hasMarkedText_ = NO;
+ markedText_.clear();
+ underlines_.clear();
+
+ // If we are handling a key down event then ImeFinishComposingText() will be
+ // called from the keyEvent: method.
+ if (!handlingKeyDown_) {
+ browser_->GetHost()->ImeFinishComposingText(false);
+ } else {
+ unmarkTextCalled_ = YES;
+ }
+}
+
+- (NSAttributedString*)attributedSubstringForProposedRange:(NSRange)range
+ actualRange:
+ (NSRangePointer)actualRange {
+ // Modify the attributed string if required.
+ // Not implemented here as we do not want to control the IME window view.
+ return nil;
+}
+
+- (NSRect)firstViewRectForCharacterRange:(NSRange)theRange
+ actualRange:(NSRangePointer)actualRange {
+ NSRect rect;
+
+ NSUInteger location = theRange.location;
+
+ // If location is not specified fall back to the composition range start.
+ if (location == NSNotFound) {
+ location = markedRange_.location;
+ }
+
+ // Offset location by the composition range start if required.
+ if (location >= markedRange_.location) {
+ location -= markedRange_.location;
+ }
+
+ if (location < composition_bounds_.size()) {
+ const CefRect& rc = composition_bounds_[location];
+ rect = NSMakeRect(rc.x, rc.y, rc.width, rc.height);
+ }
+
+ if (actualRange) {
+ *actualRange = NSMakeRange(location, theRange.length);
+ }
+
+ return rect;
+}
+
+- (NSRect)screenRectFromViewRect:(NSRect)rect {
+ NSRect screenRect;
+
+ int screenX, screenY;
+ browser_->GetHost()->GetClient()->GetRenderHandler()->GetScreenPoint(
+ browser_, rect.origin.x, rect.origin.y, screenX, screenY);
+ screenRect.origin = NSMakePoint(screenX, screenY);
+ screenRect.size = rect.size;
+
+ return screenRect;
+}
+
+- (NSRect)firstRectForCharacterRange:(NSRange)theRange
+ actualRange:(NSRangePointer)actualRange {
+ NSRect rect = [self firstViewRectForCharacterRange:theRange
+ actualRange:actualRange];
+
+ // Convert into screen coordinates for return.
+ rect = [self screenRectFromViewRect:rect];
+
+ if (rect.origin.y >= rect.size.height) {
+ rect.origin.y -= rect.size.height;
+ } else {
+ rect.origin.y = 0;
+ }
+
+ return rect;
+}
+
+- (NSUInteger)characterIndexForPoint:(NSPoint)thePoint {
+ return NSNotFound;
+}
+
+- (void)HandleKeyEventBeforeTextInputClient:(NSEvent*)keyEvent {
+ DCHECK([keyEvent type] == NSEventTypeKeyDown);
+ // Don't call this method recursively.
+ DCHECK(!handlingKeyDown_);
+
+ oldHasMarkedText_ = hasMarkedText_;
+ handlingKeyDown_ = YES;
+
+ // These variables might be set when handling the keyboard event.
+ // Clear them here so that we can know whether they have changed afterwards.
+ textToBeInserted_.clear();
+ markedText_.clear();
+ underlines_.clear();
+ setMarkedTextReplacementRange_ = CefRange(UINT32_MAX, UINT32_MAX);
+ unmarkTextCalled_ = NO;
+}
+
+- (void)HandleKeyEventAfterTextInputClient:(CefKeyEvent)keyEvent {
+ handlingKeyDown_ = NO;
+
+ // Send keypress and/or composition related events.
+ // Note that |textToBeInserted_| is a UTF-16 string but it's fine to only
+ // handle BMP characters here as we can always insert non-BMP characters as
+ // text.
+
+ // If the text to be inserted only contains 1 character then we can just send
+ // a keypress event.
+ if (!hasMarkedText_ && !oldHasMarkedText_ &&
+ textToBeInserted_.length() <= 1) {
+ keyEvent.type = KEYEVENT_KEYDOWN;
+
+ browser_->GetHost()->SendKeyEvent(keyEvent);
+
+ // Don't send a CHAR event for non-char keys like arrows, function keys and
+ // clear.
+ if (keyEvent.modifiers & (EVENTFLAG_IS_KEY_PAD)) {
+ if (keyEvent.native_key_code == 71) {
+ return;
+ }
+ }
+
+ keyEvent.type = KEYEVENT_CHAR;
+ browser_->GetHost()->SendKeyEvent(keyEvent);
+ }
+
+ // If the text to be inserted contains multiple characters then send the text
+ // to the browser using ImeCommitText().
+ BOOL textInserted = NO;
+ if (textToBeInserted_.length() >
+ ((hasMarkedText_ || oldHasMarkedText_) ? 0u : 1u)) {
+ browser_->GetHost()->ImeCommitText(textToBeInserted_,
+ CefRange(UINT32_MAX, UINT32_MAX), 0);
+ textToBeInserted_.clear();
+ }
+
+ // Update or cancel the composition. If some text has been inserted then we
+ // don't need to explicitly cancel the composition.
+ if (hasMarkedText_ && markedText_.length()) {
+ // Update the composition by sending marked text to the browser.
+ // |selectedRange_| is the range being selected inside the marked text.
+ browser_->GetHost()->ImeSetComposition(
+ markedText_, underlines_, setMarkedTextReplacementRange_,
+ CefRange(static_cast<int>(selectedRange_.location),
+ static_cast<int>(NSMaxRange(selectedRange_))));
+ } else if (oldHasMarkedText_ && !hasMarkedText_ && !textInserted) {
+ // There was no marked text or inserted text. Complete or cancel the
+ // composition.
+ if (unmarkTextCalled_) {
+ browser_->GetHost()->ImeFinishComposingText(false);
+ } else {
+ browser_->GetHost()->ImeCancelComposition();
+ }
+ }
+
+ setMarkedTextReplacementRange_ = CefRange(UINT32_MAX, UINT32_MAX);
+}
+
+- (void)ChangeCompositionRange:(CefRange)range
+ character_bounds:(const CefRenderHandler::RectList&)bounds {
+ composition_range_ = range;
+ markedRange_ = NSMakeRange(range.from, range.to - range.from);
+ composition_bounds_ = bounds;
+}
+
+- (void)cancelComposition {
+ if (!hasMarkedText_) {
+ return;
+ }
+
+// Cancel the ongoing composition. [NSInputManager markedTextAbandoned:]
+// doesn't call any NSTextInput functions, such as setMarkedText or
+// insertText.
+// TODO(erikchen): NSInputManager is deprecated since OSX 10.6. Switch to
+// NSTextInputContext. http://www.crbug.com/479010.
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+ NSInputManager* currentInputManager = [NSInputManager currentInputManager];
+ [currentInputManager markedTextAbandoned:self];
+#pragma clang diagnostic pop
+
+ hasMarkedText_ = NO;
+ // Should not call [self unmarkText] here because it'll send unnecessary
+ // cancel composition messages to the browser.
+}
+
+@end
diff --git a/tests/cefclient/browser/urlrequest_test.cc b/tests/cefclient/browser/urlrequest_test.cc
new file mode 100644
index 00000000..a84976bb
--- /dev/null
+++ b/tests/cefclient/browser/urlrequest_test.cc
@@ -0,0 +1,188 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/urlrequest_test.h"
+
+#include <memory>
+#include <string>
+
+#include "include/base/cef_callback.h"
+#include "include/base/cef_logging.h"
+#include "include/cef_urlrequest.h"
+#include "include/wrapper/cef_helpers.h"
+#include "tests/cefclient/browser/test_runner.h"
+
+namespace client {
+namespace urlrequest_test {
+
+namespace {
+
+const char kTestUrlPath[] = "/urlrequest";
+const char kTestMessageName[] = "URLRequestTest";
+
+// Implementation of CefURLRequestClient that stores response information. Only
+// accessed on the UI thread.
+class RequestClient : public CefURLRequestClient {
+ public:
+ // Callback to be executed on request completion.
+ using Callback =
+ base::OnceCallback<void(CefURLRequest::ErrorCode /*error_code*/,
+ const std::string& /*download_data*/)>;
+
+ explicit RequestClient(Callback callback) : callback_(std::move(callback)) {
+ CEF_REQUIRE_UI_THREAD();
+ DCHECK(!callback_.is_null());
+ }
+
+ void Detach() {
+ CEF_REQUIRE_UI_THREAD();
+ if (!callback_.is_null()) {
+ callback_.Reset();
+ }
+ }
+
+ void OnRequestComplete(CefRefPtr<CefURLRequest> request) override {
+ CEF_REQUIRE_UI_THREAD();
+ if (!callback_.is_null()) {
+ std::move(callback_).Run(request->GetRequestError(), download_data_);
+ }
+ }
+
+ void OnUploadProgress(CefRefPtr<CefURLRequest> request,
+ int64 current,
+ int64 total) override {}
+
+ void OnDownloadProgress(CefRefPtr<CefURLRequest> request,
+ int64 current,
+ int64 total) override {}
+
+ void OnDownloadData(CefRefPtr<CefURLRequest> request,
+ const void* data,
+ size_t data_length) override {
+ CEF_REQUIRE_UI_THREAD();
+ download_data_ += std::string(static_cast<const char*>(data), data_length);
+ }
+
+ bool GetAuthCredentials(bool isProxy,
+ const CefString& host,
+ int port,
+ const CefString& realm,
+ const CefString& scheme,
+ CefRefPtr<CefAuthCallback> callback) override {
+ return false;
+ }
+
+ private:
+ Callback callback_;
+ std::string download_data_;
+
+ IMPLEMENT_REFCOUNTING(RequestClient);
+ DISALLOW_COPY_AND_ASSIGN(RequestClient);
+};
+
+// Handle messages in the browser process. Only accessed on the UI thread.
+class Handler : public CefMessageRouterBrowserSide::Handler {
+ public:
+ Handler() { CEF_REQUIRE_UI_THREAD(); }
+
+ ~Handler() { CancelPendingRequest(); }
+
+ // Called due to cefQuery execution in urlrequest.html.
+ bool OnQuery(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int64 query_id,
+ const CefString& request,
+ bool persistent,
+ CefRefPtr<Callback> callback) override {
+ CEF_REQUIRE_UI_THREAD();
+
+ // Only handle messages from the test URL.
+ const std::string& url = frame->GetURL();
+ if (!test_runner::IsTestURL(url, kTestUrlPath)) {
+ return false;
+ }
+
+ const std::string& message_name = request;
+ if (message_name.find(kTestMessageName) == 0) {
+ const std::string& load_url =
+ message_name.substr(sizeof(kTestMessageName));
+
+ CancelPendingRequest();
+
+ DCHECK(!callback_.get());
+ DCHECK(!urlrequest_.get());
+
+ callback_ = callback;
+
+ // Create a CefRequest for the specified URL.
+ CefRefPtr<CefRequest> cef_request = CefRequest::Create();
+ cef_request->SetURL(load_url);
+ cef_request->SetMethod("GET");
+
+ // Callback to be executed on request completion.
+ // It's safe to use base::Unretained() here because there is only one
+ // RequestClient pending at any given time and we explicitly detach the
+ // callback in the Handler destructor.
+ auto request_callback =
+ base::BindOnce(&Handler::OnRequestComplete, base::Unretained(this));
+
+ // Create and start a new CefURLRequest associated with the frame, so
+ // that it shares authentication with ClientHandler::GetAuthCredentials.
+ urlrequest_ = frame->CreateURLRequest(
+ cef_request, new RequestClient(std::move(request_callback)));
+
+ return true;
+ }
+
+ return false;
+ }
+
+ private:
+ // Cancel the currently pending URL request, if any.
+ void CancelPendingRequest() {
+ CEF_REQUIRE_UI_THREAD();
+
+ if (urlrequest_.get()) {
+ // Don't execute the callback when we explicitly cancel the request.
+ static_cast<RequestClient*>(urlrequest_->GetClient().get())->Detach();
+
+ urlrequest_->Cancel();
+ urlrequest_ = nullptr;
+ }
+
+ if (callback_.get()) {
+ // Must always execute |callback_| before deleting it.
+ callback_->Failure(ERR_ABORTED, test_runner::GetErrorString(ERR_ABORTED));
+ callback_ = nullptr;
+ }
+ }
+
+ void OnRequestComplete(CefURLRequest::ErrorCode error_code,
+ const std::string& download_data) {
+ CEF_REQUIRE_UI_THREAD();
+
+ if (error_code == ERR_NONE) {
+ callback_->Success(download_data);
+ } else {
+ callback_->Failure(error_code, test_runner::GetErrorString(error_code));
+ }
+
+ callback_ = nullptr;
+ urlrequest_ = nullptr;
+ }
+
+ CefRefPtr<Callback> callback_;
+ CefRefPtr<CefURLRequest> urlrequest_;
+
+ DISALLOW_COPY_AND_ASSIGN(Handler);
+};
+
+} // namespace
+
+void CreateMessageHandlers(test_runner::MessageHandlerSet& handlers) {
+ handlers.insert(new Handler());
+}
+
+} // namespace urlrequest_test
+} // namespace client
diff --git a/tests/cefclient/browser/urlrequest_test.h b/tests/cefclient/browser/urlrequest_test.h
new file mode 100644
index 00000000..ec572e71
--- /dev/null
+++ b/tests/cefclient/browser/urlrequest_test.h
@@ -0,0 +1,20 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_URLREQUEST_TEST_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_URLREQUEST_TEST_H_
+#pragma once
+
+#include "tests/cefclient/browser/test_runner.h"
+
+namespace client {
+namespace urlrequest_test {
+
+// Create message handlers. Called from test_runner.cc.
+void CreateMessageHandlers(test_runner::MessageHandlerSet& handlers);
+
+} // namespace urlrequest_test
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_URLREQUEST_TEST_H_
diff --git a/tests/cefclient/browser/util_gtk.cc b/tests/cefclient/browser/util_gtk.cc
new file mode 100644
index 00000000..be5e30b6
--- /dev/null
+++ b/tests/cefclient/browser/util_gtk.cc
@@ -0,0 +1,33 @@
+// Copyright (c) 2018 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/util_gtk.h"
+
+#include <gdk/gdk.h>
+
+namespace client {
+
+base::PlatformThreadId ScopedGdkThreadsEnter::locked_thread_ =
+ kInvalidPlatformThreadId;
+
+ScopedGdkThreadsEnter::ScopedGdkThreadsEnter() {
+ // The GDK lock is not reentrant, so don't try to lock again if the current
+ // thread already holds it.
+ base::PlatformThreadId current_thread = base::PlatformThread::CurrentId();
+ take_lock_ = current_thread != locked_thread_;
+
+ if (take_lock_) {
+ gdk_threads_enter();
+ locked_thread_ = current_thread;
+ }
+}
+
+ScopedGdkThreadsEnter::~ScopedGdkThreadsEnter() {
+ if (take_lock_) {
+ locked_thread_ = kInvalidPlatformThreadId;
+ gdk_threads_leave();
+ }
+}
+
+} // namespace client
diff --git a/tests/cefclient/browser/util_gtk.h b/tests/cefclient/browser/util_gtk.h
new file mode 100644
index 00000000..c8836fef
--- /dev/null
+++ b/tests/cefclient/browser/util_gtk.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2018 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_UTIL_GTK_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_UTIL_GTK_H_
+#pragma once
+
+#include "include/base/cef_macros.h"
+#include "include/base/cef_platform_thread.h"
+
+namespace client {
+
+// Scoped helper that manages the global GDK lock by calling gdk_threads_enter()
+// and gdk_threads_leave(). The lock is not reentrant so this helper implements
+// additional checking to avoid deadlocks.
+//
+// When using GTK in multi-threaded mode you must do the following:
+// 1. Call gdk_threads_init() before making any other GTK/GDK/GLib calls.
+// 2. Acquire the global lock before making any GTK/GDK calls, and release the
+// lock afterwards. This should only be done with callbacks that do not
+// originate from GTK signals (because those callbacks already hold the
+// lock).
+//
+// See https://www.geany.org/manual/gtk/gtk-faq/x482.html for more information.
+class ScopedGdkThreadsEnter {
+ public:
+ ScopedGdkThreadsEnter();
+ ~ScopedGdkThreadsEnter();
+
+ private:
+ bool take_lock_;
+
+ static base::PlatformThreadId locked_thread_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedGdkThreadsEnter);
+};
+
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_UTIL_GTK_H_
diff --git a/tests/cefclient/browser/views_menu_bar.cc b/tests/cefclient/browser/views_menu_bar.cc
new file mode 100644
index 00000000..f8746a2b
--- /dev/null
+++ b/tests/cefclient/browser/views_menu_bar.cc
@@ -0,0 +1,322 @@
+// Copyright (c) 2017 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/views_menu_bar.h"
+
+#include "include/cef_i18n_util.h"
+#include "include/views/cef_box_layout.h"
+#include "include/views/cef_window.h"
+#include "tests/cefclient/browser/views_style.h"
+
+namespace client {
+
+namespace {
+
+const int kMenuBarGroupId = 100;
+
+// Convert |c| to lowercase using the current ICU locale.
+// TODO(jshin): What about Turkish locale? See http://crbug.com/81719.
+// If the mnemonic is capital I and the UI language is Turkish, lowercasing it
+// results in 'small dotless i', which is different from a 'dotted i'. Similar
+// issues may exist for az and lt locales.
+char16 ToLower(char16 c) {
+ CefStringUTF16 str16;
+ cef_string_utf16_to_lower(&c, 1, str16.GetWritableStruct());
+ return str16.length() > 0 ? str16.c_str()[0] : 0;
+}
+
+// Extract the mnemonic character from |title|. For example, if |title| is
+// "&Test" then the mnemonic character is 'T'.
+char16 GetMnemonic(const std::u16string& title) {
+ size_t index = 0;
+ do {
+ index = title.find('&', index);
+ if (index != std::u16string::npos) {
+ if (index + 1 != title.size() && title[index + 1] != '&') {
+ return ToLower(title[index + 1]);
+ }
+ index++;
+ }
+ } while (index != std::u16string::npos);
+ return 0;
+}
+
+} // namespace
+
+ViewsMenuBar::ViewsMenuBar(Delegate* delegate, int menu_id_start)
+ : delegate_(delegate),
+ id_start_(menu_id_start),
+ id_next_(menu_id_start),
+ last_nav_with_keyboard_(false) {
+ DCHECK(delegate_);
+ DCHECK_GT(id_start_, 0);
+}
+
+bool ViewsMenuBar::HasMenuId(int menu_id) const {
+ return menu_id >= id_start_ && menu_id < id_next_;
+}
+
+CefRefPtr<CefPanel> ViewsMenuBar::GetMenuPanel() {
+ EnsureMenuPanel();
+ return panel_;
+}
+
+CefRefPtr<CefMenuModel> ViewsMenuBar::CreateMenuModel(const CefString& label,
+ int* menu_id) {
+ EnsureMenuPanel();
+
+ // Assign the new menu ID.
+ const int new_menu_id = id_next_++;
+ if (menu_id) {
+ *menu_id = new_menu_id;
+ }
+
+ // Create the new MenuModel.
+ CefRefPtr<CefMenuModel> model = CefMenuModel::CreateMenuModel(this);
+ views_style::ApplyTo(model);
+ models_.push_back(model);
+
+ // Create the new MenuButton.
+ CefRefPtr<CefMenuButton> button =
+ CefMenuButton::CreateMenuButton(this, label);
+ button->SetID(new_menu_id);
+ views_style::ApplyTo(button.get());
+ button->SetInkDropEnabled(true);
+
+ // Assign a group ID to allow focus traversal between MenuButtons using the
+ // arrow keys when the menu is not displayed.
+ button->SetGroupID(kMenuBarGroupId);
+
+ // Add the new MenuButton to the Planel.
+ panel_->AddChildView(button);
+
+ // Extract the mnemonic that triggers the menu, if any.
+ char16 mnemonic = GetMnemonic(label);
+ if (mnemonic != 0) {
+ mnemonics_.insert(std::make_pair(mnemonic, new_menu_id));
+ }
+
+ return model;
+}
+
+CefRefPtr<CefMenuModel> ViewsMenuBar::GetMenuModel(int menu_id) const {
+ if (HasMenuId(menu_id)) {
+ return models_[menu_id - id_start_];
+ }
+ return nullptr;
+}
+
+void ViewsMenuBar::SetMenuFocusable(bool focusable) {
+ if (!panel_) {
+ return;
+ }
+
+ for (int id = id_start_; id < id_next_; ++id) {
+ panel_->GetViewForID(id)->SetFocusable(focusable);
+ }
+
+ if (focusable) {
+ // Give focus to the first MenuButton.
+ panel_->GetViewForID(id_start_)->RequestFocus();
+ }
+}
+
+bool ViewsMenuBar::OnKeyEvent(const CefKeyEvent& event) {
+ if (!panel_) {
+ return false;
+ }
+
+ if (event.type != KEYEVENT_RAWKEYDOWN) {
+ return false;
+ }
+
+ // Do not check mnemonics if the Alt or Ctrl modifiers are pressed. For
+ // example Ctrl+<T> is an accelerator, but <T> only is a mnemonic.
+ if (event.modifiers & (EVENTFLAG_ALT_DOWN | EVENTFLAG_CONTROL_DOWN)) {
+ return false;
+ }
+
+ MnemonicMap::const_iterator it = mnemonics_.find(ToLower(event.character));
+ if (it == mnemonics_.end()) {
+ return false;
+ }
+
+ // Set status indicating that we navigated using the keyboard.
+ last_nav_with_keyboard_ = true;
+
+ // Show the selected menu.
+ TriggerMenuButton(panel_->GetViewForID(it->second));
+
+ return true;
+}
+
+void ViewsMenuBar::Reset() {
+ panel_ = nullptr;
+ models_.clear();
+ mnemonics_.clear();
+ id_next_ = id_start_;
+}
+
+void ViewsMenuBar::OnMenuButtonPressed(
+ CefRefPtr<CefMenuButton> menu_button,
+ const CefPoint& screen_point,
+ CefRefPtr<CefMenuButtonPressedLock> button_pressed_lock) {
+ CefRefPtr<CefMenuModel> menu_model = GetMenuModel(menu_button->GetID());
+
+ // Adjust menu position to align with the button.
+ CefPoint point = screen_point;
+ if (CefIsRTL()) {
+ point.x += menu_button->GetBounds().width - 4;
+ } else {
+ point.x -= menu_button->GetBounds().width - 4;
+ }
+
+ // Keep track of the current |last_nav_with_keyboard_| status and restore it
+ // after displaying the new menu.
+ bool cur_last_nav_with_keyboard = last_nav_with_keyboard_;
+
+ // May result in the previous menu being closed, in which case MenuClosed will
+ // be called before the new menu is displayed.
+ menu_button->ShowMenu(menu_model, point, CEF_MENU_ANCHOR_TOPLEFT);
+
+ last_nav_with_keyboard_ = cur_last_nav_with_keyboard;
+}
+
+void ViewsMenuBar::ExecuteCommand(CefRefPtr<CefMenuModel> menu_model,
+ int command_id,
+ cef_event_flags_t event_flags) {
+ delegate_->MenuBarExecuteCommand(menu_model, command_id, event_flags);
+}
+
+void ViewsMenuBar::MouseOutsideMenu(CefRefPtr<CefMenuModel> menu_model,
+ const CefPoint& screen_point) {
+ DCHECK(panel_);
+
+ // Retrieve the Window hosting the Panel.
+ CefRefPtr<CefWindow> window = panel_->GetWindow();
+ DCHECK(window);
+
+ // Convert the point from screen to window coordinates.
+ CefPoint window_point = screen_point;
+ if (!window->ConvertPointFromScreen(window_point)) {
+ return;
+ }
+
+ CefRect panel_bounds = panel_->GetBounds();
+
+ if (last_nav_with_keyboard_) {
+ // The user navigated last using the keyboard. Don't change menus using
+ // mouse movements until the mouse exits and re-enters the Panel.
+ if (panel_bounds.Contains(window_point)) {
+ return;
+ }
+ last_nav_with_keyboard_ = false;
+ }
+
+ // Check that the point is inside the Panel.
+ if (!panel_bounds.Contains(window_point)) {
+ return;
+ }
+
+ const int active_menu_id = GetActiveMenuId();
+
+ // Determine which MenuButton is under the specified point.
+ for (int id = id_start_; id < id_next_; ++id) {
+ // Skip the currently active MenuButton.
+ if (id == active_menu_id) {
+ continue;
+ }
+
+ CefRefPtr<CefView> button = panel_->GetViewForID(id);
+ CefRect button_bounds = button->GetBounds();
+ if (CefIsRTL()) {
+ // Adjust for right-to-left button layout.
+ button_bounds.x =
+ panel_bounds.width - button_bounds.x - button_bounds.width;
+ }
+ if (button_bounds.Contains(window_point)) {
+ // Trigger the hovered MenuButton.
+ TriggerMenuButton(button);
+ break;
+ }
+ }
+}
+
+void ViewsMenuBar::UnhandledOpenSubmenu(CefRefPtr<CefMenuModel> menu_model,
+ bool is_rtl) {
+ TriggerNextMenu(is_rtl ? 1 : -1);
+}
+
+void ViewsMenuBar::UnhandledCloseSubmenu(CefRefPtr<CefMenuModel> menu_model,
+ bool is_rtl) {
+ TriggerNextMenu(is_rtl ? -1 : 1);
+}
+
+void ViewsMenuBar::MenuClosed(CefRefPtr<CefMenuModel> menu_model) {
+ // Reset |last_nav_with_keyboard_| status whenever the main menu closes.
+ if (!menu_model->IsSubMenu() && last_nav_with_keyboard_) {
+ last_nav_with_keyboard_ = false;
+ }
+}
+
+void ViewsMenuBar::EnsureMenuPanel() {
+ if (panel_) {
+ return;
+ }
+
+ panel_ = CefPanel::CreatePanel(nullptr);
+ views_style::ApplyTo(panel_);
+
+ // Use a horizontal box layout.
+ CefBoxLayoutSettings top_panel_layout_settings;
+ top_panel_layout_settings.horizontal = true;
+ panel_->SetToBoxLayout(top_panel_layout_settings);
+}
+
+int ViewsMenuBar::GetActiveMenuId() {
+ DCHECK(panel_);
+
+ for (int id = id_start_; id < id_next_; ++id) {
+ CefRefPtr<CefButton> button = panel_->GetViewForID(id)->AsButton();
+ if (button->GetState() == CEF_BUTTON_STATE_PRESSED) {
+ return id;
+ }
+ }
+
+ return -1;
+}
+
+void ViewsMenuBar::TriggerNextMenu(int offset) {
+ DCHECK(panel_);
+
+ const int active_menu_id = GetActiveMenuId();
+ const int menu_count = id_next_ - id_start_;
+ const int active_menu_index = active_menu_id - id_start_;
+
+ // Compute the modulus to avoid negative values.
+ int next_menu_index = (active_menu_index + offset) % menu_count;
+ if (next_menu_index < 0) {
+ next_menu_index += menu_count;
+ }
+
+ // Cancel the existing menu. MenuClosed may be called.
+ panel_->GetWindow()->CancelMenu();
+
+ // Set status indicating that we navigated using the keyboard.
+ last_nav_with_keyboard_ = true;
+
+ // Show the new menu.
+ TriggerMenuButton(panel_->GetViewForID(id_start_ + next_menu_index));
+}
+
+void ViewsMenuBar::TriggerMenuButton(CefRefPtr<CefView> button) {
+ CefRefPtr<CefMenuButton> menu_button =
+ button->AsButton()->AsLabelButton()->AsMenuButton();
+ if (menu_button->IsFocusable()) {
+ menu_button->RequestFocus();
+ }
+ menu_button->TriggerMenu();
+}
+
+} // namespace client
diff --git a/tests/cefclient/browser/views_menu_bar.h b/tests/cefclient/browser/views_menu_bar.h
new file mode 100644
index 00000000..656fd3b1
--- /dev/null
+++ b/tests/cefclient/browser/views_menu_bar.h
@@ -0,0 +1,124 @@
+// Copyright (c) 2017 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_VIEWS_MENU_BAR_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_VIEWS_MENU_BAR_H_
+#pragma once
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "include/cef_menu_model.h"
+#include "include/cef_menu_model_delegate.h"
+#include "include/views/cef_menu_button.h"
+#include "include/views/cef_menu_button_delegate.h"
+#include "include/views/cef_panel.h"
+
+namespace client {
+
+// Implements a menu bar which is composed of CefMenuButtons positioned in a
+// row with automatic switching between them via mouse/keyboard. All methods
+// must be called on the browser process UI thread.
+class ViewsMenuBar : public CefMenuButtonDelegate, public CefMenuModelDelegate {
+ public:
+ // Delegate methods will be called on the browser process UI thread.
+ class Delegate {
+ public:
+ // Called when a menu command is selected.
+ virtual void MenuBarExecuteCommand(CefRefPtr<CefMenuModel> menu_model,
+ int command_id,
+ cef_event_flags_t event_flags) = 0;
+
+ protected:
+ virtual ~Delegate() {}
+ };
+
+ // |delegate| must outlive this object.
+ // |menu_id_start| is the ID for the first CefMenuButton in the bar. An ID
+ // range starting with |menu_id_start| and extending for a reasonable distance
+ // should be reserved in the client for MenuBar usage.
+ ViewsMenuBar(Delegate* delegate, int menu_id_start);
+
+ // Returns true if |menu_id| exists in the menu bar.
+ bool HasMenuId(int menu_id) const;
+
+ // Returns the CefPanel that represents the menu bar.
+ CefRefPtr<CefPanel> GetMenuPanel();
+
+ // Create a new menu with the specified |label|. If |menu_id| is non-nullptr
+ // it will be populated with the new menu ID.
+ CefRefPtr<CefMenuModel> CreateMenuModel(const CefString& label, int* menu_id);
+
+ // Returns the menu with the specified |menu_id|, or nullptr if no such menu
+ // exists.
+ CefRefPtr<CefMenuModel> GetMenuModel(int menu_id) const;
+
+ // Assign or remove focus from the menu bar.
+ // Focus is assigned to the menu bar by ViewsWindow::OnKeyEvent when the ALT
+ // key is pressed. Focus is removed from the menu bar by ViewsWindow::OnFocus
+ // when a control not in the menu bar gains focus.
+ void SetMenuFocusable(bool focusable);
+
+ // Key events forwarded from ViewsWindow::OnKeyEvent when the menu bar has
+ // focus.
+ bool OnKeyEvent(const CefKeyEvent& event);
+
+ // Reset menu bar state.
+ void Reset();
+
+ protected:
+ // CefButtonDelegate methods:
+ void OnButtonPressed(CefRefPtr<CefButton> button) override {}
+
+ // CefMenuButtonDelegate methods:
+ void OnMenuButtonPressed(
+ CefRefPtr<CefMenuButton> menu_button,
+ const CefPoint& screen_point,
+ CefRefPtr<CefMenuButtonPressedLock> button_pressed_lock) override;
+
+ // CefMenuModelDelegate methods:
+ void ExecuteCommand(CefRefPtr<CefMenuModel> menu_model,
+ int command_id,
+ cef_event_flags_t event_flags) override;
+ void MouseOutsideMenu(CefRefPtr<CefMenuModel> menu_model,
+ const CefPoint& screen_point) override;
+ void UnhandledOpenSubmenu(CefRefPtr<CefMenuModel> menu_model,
+ bool is_rtl) override;
+ void UnhandledCloseSubmenu(CefRefPtr<CefMenuModel> menu_model,
+ bool is_rtl) override;
+ void MenuClosed(CefRefPtr<CefMenuModel> menu_model) override;
+
+ private:
+ // Creates the menu panel if it doesn't already exist.
+ void EnsureMenuPanel();
+
+ // Returns the ID for the currently active menu, or -1 if no menu is currently
+ // active.
+ int GetActiveMenuId();
+
+ // Triggers the menu at the specified |offset| from the currently active menu.
+ void TriggerNextMenu(int offset);
+
+ // Triggers the specified MenuButton |button|.
+ void TriggerMenuButton(CefRefPtr<CefView> button);
+
+ Delegate* delegate_; // Not owned by this object.
+ const int id_start_;
+ int id_next_;
+ CefRefPtr<CefPanel> panel_;
+ std::vector<CefRefPtr<CefMenuModel>> models_;
+ bool last_nav_with_keyboard_;
+
+ // Map of mnemonic to MenuButton ID.
+ typedef std::map<char16, int> MnemonicMap;
+ MnemonicMap mnemonics_;
+
+ IMPLEMENT_REFCOUNTING(ViewsMenuBar);
+ DISALLOW_COPY_AND_ASSIGN(ViewsMenuBar);
+};
+
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_VIEWS_MENU_BAR_H_
diff --git a/tests/cefclient/browser/views_overlay_controls.cc b/tests/cefclient/browser/views_overlay_controls.cc
new file mode 100644
index 00000000..d84b19cd
--- /dev/null
+++ b/tests/cefclient/browser/views_overlay_controls.cc
@@ -0,0 +1,230 @@
+// Copyright (c) 2021 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/views_overlay_controls.h"
+
+#include <algorithm>
+#include <array>
+#include <string>
+
+#include "include/views/cef_box_layout.h"
+#include "include/views/cef_window.h"
+#include "tests/cefclient/browser/views_style.h"
+
+namespace client {
+
+namespace {
+
+constexpr int kInsets = 4;
+constexpr int kLocationBarPadding = 100;
+
+// White with 80% opacity.
+constexpr auto kBackgroundColor = CefColorSetARGB(255 * .80, 255, 255, 255);
+
+std::string GetLabel(ViewsOverlayControls::Command command, bool maximized) {
+ switch (command) {
+ case ViewsOverlayControls::Command::kMinimize:
+ return "-";
+ case ViewsOverlayControls::Command::kMaximize:
+ return maximized ? "O" : "o";
+ case ViewsOverlayControls::Command::kClose:
+ return "X";
+ }
+ NOTREACHED();
+ return std::string();
+}
+
+std::array<ViewsOverlayControls::Command, 3> GetButtons() {
+#if defined(OS_MAC)
+ return {ViewsOverlayControls::Command::kClose,
+ ViewsOverlayControls::Command::kMaximize,
+ ViewsOverlayControls::Command::kMinimize};
+#else
+ return {ViewsOverlayControls::Command::kMinimize,
+ ViewsOverlayControls::Command::kMaximize,
+ ViewsOverlayControls::Command::kClose};
+#endif
+}
+
+cef_docking_mode_t GetPanelDockingMode() {
+#if defined(OS_MAC)
+ return CEF_DOCKING_MODE_TOP_LEFT;
+#else
+ return CEF_DOCKING_MODE_TOP_RIGHT;
+#endif
+}
+cef_docking_mode_t GetMenuDockingMode() {
+#if defined(OS_MAC)
+ return CEF_DOCKING_MODE_TOP_RIGHT;
+#else
+ return CEF_DOCKING_MODE_TOP_LEFT;
+#endif
+}
+
+} // namespace
+
+ViewsOverlayControls::ViewsOverlayControls(bool with_window_buttons)
+ : with_window_buttons_(with_window_buttons) {}
+
+void ViewsOverlayControls::Initialize(CefRefPtr<CefWindow> window,
+ CefRefPtr<CefMenuButton> menu_button,
+ CefRefPtr<CefView> location_bar,
+ bool is_chrome_toolbar) {
+ DCHECK(!window_);
+ DCHECK(menu_button);
+ DCHECK(location_bar);
+
+ window_ = window;
+ window_maximized_ = window_->IsMaximized();
+
+ if (with_window_buttons_) {
+ // Window control buttons. These controls are currently text which means
+ // that we can't use a transparent background because subpixel text
+ // rendering will break.
+ // See comments on the related DCHECK in Label::PaintText.
+ panel_ = CefPanel::CreatePanel(nullptr);
+ views_style::ApplyTo(panel_);
+
+ // Use a horizontal box layout.
+ CefBoxLayoutSettings panel_layout_settings;
+ panel_layout_settings.horizontal = true;
+ panel_->SetToBoxLayout(panel_layout_settings);
+
+ for (auto button : GetButtons()) {
+ panel_->AddChildView(CreateButton(button));
+ }
+ panel_controller_ = window->AddOverlayView(panel_, GetPanelDockingMode());
+ panel_controller_->SetInsets(CefInsets(kInsets, kInsets, 0, kInsets));
+ panel_controller_->SetVisible(true);
+ }
+
+ // Menu button.
+ menu_button->SetBackgroundColor(kBackgroundColor);
+ menu_controller_ = window_->AddOverlayView(menu_button, GetMenuDockingMode());
+ menu_controller_->SetInsets(CefInsets(kInsets, kInsets, 0, kInsets));
+ menu_controller_->SetVisible(true);
+
+ // Location bar. Will be made visible in UpdateControls().
+ location_bar_ = location_bar;
+ is_chrome_toolbar_ = is_chrome_toolbar;
+ // Use a 100% transparent background for the Chrome toolbar.
+ location_bar_->SetBackgroundColor(is_chrome_toolbar_ ? 0 : kBackgroundColor);
+ location_controller_ =
+ window_->AddOverlayView(location_bar_, CEF_DOCKING_MODE_CUSTOM);
+}
+
+void ViewsOverlayControls::Destroy() {
+ window_ = nullptr;
+ panel_ = nullptr;
+ if (panel_controller_) {
+ panel_controller_->Destroy();
+ panel_controller_ = nullptr;
+ }
+ menu_controller_->Destroy();
+ menu_controller_ = nullptr;
+ location_bar_ = nullptr;
+ location_controller_->Destroy();
+ location_controller_ = nullptr;
+}
+
+void ViewsOverlayControls::UpdateControls() {
+ // Update location bar size, position and visibility.
+ auto bounds = window_->GetBounds();
+ bounds.x = kLocationBarPadding;
+ bounds.width -= kLocationBarPadding * 2;
+ bounds.y = kInsets;
+ if (is_chrome_toolbar_) {
+ // Fit the standard Chrome toolbar.
+ const auto preferred_size = location_bar_->GetPreferredSize();
+ bounds.height =
+ std::max(menu_controller_->GetSize().height, preferred_size.height);
+ } else {
+ bounds.height = menu_controller_->GetSize().height;
+ }
+ if (bounds.width < kLocationBarPadding * 2) {
+ // Not enough space.
+ location_controller_->SetVisible(false);
+ } else {
+ location_bar_->SetSize(CefSize(bounds.width, bounds.height));
+ location_controller_->SetBounds(bounds);
+ location_controller_->SetVisible(true);
+ }
+
+ MaybeUpdateMaximizeButton();
+}
+
+void ViewsOverlayControls::UpdateDraggableRegions(
+ std::vector<CefDraggableRegion>& window_regions) {
+ if (panel_controller_ && panel_controller_->IsVisible()) {
+ window_regions.push_back(CefDraggableRegion(panel_controller_->GetBounds(),
+ /*draggable=*/false));
+ }
+
+ if (menu_controller_ && menu_controller_->IsVisible()) {
+ window_regions.push_back(
+ CefDraggableRegion(menu_controller_->GetBounds(), /*draggable=*/false));
+ }
+
+ if (location_controller_ && location_controller_->IsVisible()) {
+ window_regions.push_back(CefDraggableRegion(
+ location_controller_->GetBounds(), /*draggable=*/false));
+ }
+}
+
+void ViewsOverlayControls::OnButtonPressed(CefRefPtr<CefButton> button) {
+ auto command = static_cast<Command>(button->GetID());
+ switch (command) {
+ case ViewsOverlayControls::Command::kMinimize:
+ window_->Minimize();
+ break;
+ case ViewsOverlayControls::Command::kMaximize:
+ if (window_->IsMaximized()) {
+ window_->Restore();
+ } else {
+ window_->Maximize();
+ }
+ break;
+ case ViewsOverlayControls::Command::kClose:
+ window_->Close();
+ return;
+ }
+
+ // Explicitly reset button state because the button may have moved and it
+ // won't receive the corresponding mouse move events.
+ button->SetState(CEF_BUTTON_STATE_NORMAL);
+ button->SetInkDropEnabled(false);
+ button->SetInkDropEnabled(true);
+
+ if (command == Command::kMaximize) {
+ MaybeUpdateMaximizeButton();
+ }
+}
+
+CefRefPtr<CefLabelButton> ViewsOverlayControls::CreateButton(Command command) {
+ CefRefPtr<CefLabelButton> button = CefLabelButton::CreateLabelButton(
+ this, GetLabel(command, window_maximized_));
+ button->SetID(static_cast<int>(command));
+ views_style::ApplyTo(button);
+ button->SetInkDropEnabled(true);
+ button->SetFocusable(false); // Don't give focus to the button.
+ return button;
+}
+
+void ViewsOverlayControls::MaybeUpdateMaximizeButton() {
+ if (!with_window_buttons_ || window_->IsMaximized() == window_maximized_) {
+ return;
+ }
+ window_maximized_ = !window_maximized_;
+
+ auto max_button = panel_->GetChildViewAt(1);
+ auto command = static_cast<Command>(max_button->GetID());
+ DCHECK(command == Command::kMaximize);
+ max_button->AsButton()->AsLabelButton()->SetText(
+ GetLabel(command, window_maximized_));
+
+ // Adjust overlay size and placement due to layout changing.
+ panel_controller_->SizeToPreferredSize();
+}
+
+} // namespace client
diff --git a/tests/cefclient/browser/views_overlay_controls.h b/tests/cefclient/browser/views_overlay_controls.h
new file mode 100644
index 00000000..475fd90c
--- /dev/null
+++ b/tests/cefclient/browser/views_overlay_controls.h
@@ -0,0 +1,72 @@
+// Copyright (c) 2021 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_VIEWS_OVERLAY_CONTROLS_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_VIEWS_OVERLAY_CONTROLS_H_
+#pragma once
+
+#include "include/views/cef_button_delegate.h"
+#include "include/views/cef_label_button.h"
+#include "include/views/cef_menu_button.h"
+#include "include/views/cef_overlay_controller.h"
+#include "include/views/cef_panel.h"
+
+namespace client {
+
+// Implements window overlay controls that receive absolute positioning on top
+// of the browser view. All methods must be called on the browser process UI
+// thread.
+class ViewsOverlayControls : public CefButtonDelegate {
+ public:
+ enum class Command {
+ kMinimize = 1,
+ kMaximize,
+ kClose,
+ };
+
+ explicit ViewsOverlayControls(bool with_window_buttons);
+
+ void Initialize(CefRefPtr<CefWindow> window,
+ CefRefPtr<CefMenuButton> menu_button,
+ CefRefPtr<CefView> location_bar,
+ bool is_chrome_toolbar);
+ void Destroy();
+
+ // Update window control button state and location bar bounds.
+ void UpdateControls();
+
+ // Exclude all regions obscured by overlays.
+ void UpdateDraggableRegions(std::vector<CefDraggableRegion>& window_regions);
+
+ private:
+ // CefButtonDelegate methods:
+ void OnButtonPressed(CefRefPtr<CefButton> button) override;
+
+ CefRefPtr<CefLabelButton> CreateButton(Command command);
+
+ void MaybeUpdateMaximizeButton();
+
+ CefRefPtr<CefWindow> window_;
+ bool window_maximized_;
+
+ // Window control buttons.
+ CefRefPtr<CefPanel> panel_;
+ CefRefPtr<CefOverlayController> panel_controller_;
+ const bool with_window_buttons_;
+
+ // Location bar.
+ CefRefPtr<CefView> location_bar_;
+ bool is_chrome_toolbar_;
+ CefRefPtr<CefOverlayController> location_controller_;
+
+ // Menu button.
+ CefRefPtr<CefOverlayController> menu_controller_;
+
+ IMPLEMENT_REFCOUNTING(ViewsOverlayControls);
+ DISALLOW_COPY_AND_ASSIGN(ViewsOverlayControls);
+};
+
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_VIEWS_OVERLAY_CONTROLS_H_
diff --git a/tests/cefclient/browser/views_style.cc b/tests/cefclient/browser/views_style.cc
new file mode 100644
index 00000000..4021ebd9
--- /dev/null
+++ b/tests/cefclient/browser/views_style.cc
@@ -0,0 +1,118 @@
+// Copyright (c) 2017 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/views_style.h"
+
+#include "tests/cefclient/browser/main_context.h"
+
+namespace client {
+
+namespace views_style {
+
+namespace {
+
+cef_color_t g_background_color = 0;
+cef_color_t g_background_hover_color = 0;
+cef_color_t g_text_color = 0;
+
+int GetShade(int component) {
+ return (component < 127) ? component + 75 : component - 75;
+}
+
+void MaybeInitialize() {
+ static bool initialized = false;
+ if (initialized) {
+ return;
+ }
+
+ g_background_color = MainContext::Get()->GetBackgroundColor();
+ if (g_background_color != 0) {
+ // Use a slightly modified shade of the background color for hover.
+ g_background_hover_color =
+ CefColorSetARGB(255, GetShade(CefColorGetR(g_background_color)),
+ GetShade(CefColorGetG(g_background_color)),
+ GetShade(CefColorGetB(g_background_color)));
+
+ // Invert the background color for text.
+ g_text_color = CefColorSetARGB(255, 255 - CefColorGetR(g_background_color),
+ 255 - CefColorGetG(g_background_color),
+ 255 - CefColorGetB(g_background_color));
+ }
+
+ initialized = true;
+}
+
+} // namespace
+
+bool IsSet() {
+ MaybeInitialize();
+ return g_background_color != 0;
+}
+
+void ApplyBackgroundTo(CefRefPtr<CefView> view) {
+ if (!IsSet()) {
+ return;
+ }
+
+ view->SetBackgroundColor(g_background_color);
+}
+
+void ApplyTo(CefRefPtr<CefPanel> panel) {
+ if (!IsSet()) {
+ return;
+ }
+
+ panel->SetBackgroundColor(g_background_color);
+}
+
+void ApplyTo(CefRefPtr<CefLabelButton> label_button) {
+ if (!IsSet()) {
+ return;
+ }
+
+ // All text except disabled gets the same color.
+ label_button->SetEnabledTextColors(g_text_color);
+ label_button->SetTextColor(CEF_BUTTON_STATE_DISABLED,
+ g_background_hover_color);
+
+ label_button->SetBackgroundColor(g_background_color);
+}
+
+void ApplyTo(CefRefPtr<CefTextfield> textfield) {
+ if (!IsSet()) {
+ return;
+ }
+
+ textfield->SetBackgroundColor(g_background_color);
+ textfield->SetTextColor(g_text_color);
+}
+
+void ApplyTo(CefRefPtr<CefMenuModel> menu_model) {
+ if (!IsSet()) {
+ return;
+ }
+
+ // All text except non-hovered accelerator gets the same color.
+ menu_model->SetColorAt(-1, CEF_MENU_COLOR_TEXT, g_text_color);
+ menu_model->SetColorAt(-1, CEF_MENU_COLOR_TEXT_HOVERED, g_text_color);
+ menu_model->SetColorAt(-1, CEF_MENU_COLOR_TEXT_ACCELERATOR,
+ g_background_hover_color);
+ menu_model->SetColorAt(-1, CEF_MENU_COLOR_TEXT_ACCELERATOR_HOVERED,
+ g_text_color);
+
+ menu_model->SetColorAt(-1, CEF_MENU_COLOR_BACKGROUND, g_background_color);
+ menu_model->SetColorAt(-1, CEF_MENU_COLOR_BACKGROUND_HOVERED,
+ g_background_hover_color);
+
+ // Recursively color sub-menus.
+ for (size_t i = 0; i < menu_model->GetCount(); ++i) {
+ if (menu_model->GetTypeAt(i) == MENUITEMTYPE_SUBMENU) {
+ ApplyTo(menu_model->GetSubMenuAt(i));
+ }
+ }
+}
+
+} // namespace views_style
+
+} // namespace client
diff --git a/tests/cefclient/browser/views_style.h b/tests/cefclient/browser/views_style.h
new file mode 100644
index 00000000..f9b7c970
--- /dev/null
+++ b/tests/cefclient/browser/views_style.h
@@ -0,0 +1,32 @@
+// Copyright (c) 2017 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_VIEWS_STYLE_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_VIEWS_STYLE_H_
+#pragma once
+
+#include "include/cef_menu_model.h"
+#include "include/views/cef_label_button.h"
+#include "include/views/cef_panel.h"
+#include "include/views/cef_textfield.h"
+
+namespace client {
+
+namespace views_style {
+
+// Returns true if a style is set.
+bool IsSet();
+
+// Apply style to views objects.
+void ApplyBackgroundTo(CefRefPtr<CefView> view);
+void ApplyTo(CefRefPtr<CefPanel> panel);
+void ApplyTo(CefRefPtr<CefLabelButton> label_button);
+void ApplyTo(CefRefPtr<CefTextfield> textfield);
+void ApplyTo(CefRefPtr<CefMenuModel> menu_model);
+
+} // namespace views_style
+
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_VIEWS_STYLE_H_
diff --git a/tests/cefclient/browser/views_window.cc b/tests/cefclient/browser/views_window.cc
new file mode 100644
index 00000000..a466047e
--- /dev/null
+++ b/tests/cefclient/browser/views_window.cc
@@ -0,0 +1,1288 @@
+// Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/views_window.h"
+
+#include <algorithm>
+
+#include "include/base/cef_build.h"
+#include "include/base/cef_callback.h"
+#include "include/cef_app.h"
+#include "include/cef_i18n_util.h"
+#include "include/views/cef_box_layout.h"
+#include "include/wrapper/cef_helpers.h"
+#include "tests/cefclient/browser/main_context.h"
+#include "tests/cefclient/browser/resource.h"
+#include "tests/cefclient/browser/views_style.h"
+#include "tests/shared/browser/extension_util.h"
+#include "tests/shared/common/client_switches.h"
+
+#if !defined(OS_WIN)
+#define VK_ESCAPE 0x1B
+#define VK_RETURN 0x0D
+#define VK_MENU 0x12 // ALT key.
+#endif
+
+namespace client {
+
+namespace {
+
+const char kDefaultExtensionIcon[] = "window_icon";
+
+// Default window size.
+constexpr int kDefaultWidth = 800;
+constexpr int kDefaultHeight = 600;
+
+#if defined(OS_MAC)
+constexpr int kTitleBarHeight = 35;
+constexpr int kWindowButtonsWidth = 80;
+#endif
+
+// Control IDs for Views in the top-level Window.
+enum ControlIds {
+ ID_WINDOW = 1,
+ ID_BROWSER_VIEW,
+ ID_BACK_BUTTON,
+ ID_FORWARD_BUTTON,
+ ID_STOP_BUTTON,
+ ID_RELOAD_BUTTON,
+ ID_URL_TEXTFIELD,
+ ID_MENU_BUTTON,
+
+ // Reserved range of top menu button IDs.
+ ID_TOP_MENU_FIRST,
+ ID_TOP_MENU_LAST = ID_TOP_MENU_FIRST + 10,
+
+ // Reserved range of extension button IDs.
+ ID_EXTENSION_BUTTON_FIRST,
+ ID_EXTENSION_BUTTON_LAST = ID_EXTENSION_BUTTON_FIRST + 10,
+};
+
+typedef std::vector<CefRefPtr<CefLabelButton>> LabelButtons;
+
+// Make all |buttons| the same size.
+void MakeButtonsSameSize(const LabelButtons& buttons) {
+ CefSize size;
+
+ // Determine the largest button size.
+ for (size_t i = 0U; i < buttons.size(); ++i) {
+ const CefSize& button_size = buttons[i]->GetPreferredSize();
+ if (size.width < button_size.width) {
+ size.width = button_size.width;
+ }
+ if (size.height < button_size.height) {
+ size.height = button_size.height;
+ }
+ }
+
+ for (size_t i = 0U; i < buttons.size(); ++i) {
+ // Set the button's minimum size.
+ buttons[i]->SetMinimumSize(size);
+
+ // Re-layout the button and all parent Views.
+ buttons[i]->InvalidateLayout();
+ }
+}
+
+void AddTestMenuItems(CefRefPtr<CefMenuModel> test_menu) {
+ test_menu->AddItem(ID_TESTS_GETSOURCE, "Get Source");
+ test_menu->AddItem(ID_TESTS_GETTEXT, "Get Text");
+ test_menu->AddItem(ID_TESTS_WINDOW_NEW, "New Window");
+ test_menu->AddItem(ID_TESTS_WINDOW_POPUP, "Popup Window");
+ test_menu->AddItem(ID_TESTS_REQUEST, "Request");
+ test_menu->AddItem(ID_TESTS_ZOOM_IN, "Zoom In");
+ test_menu->AddItem(ID_TESTS_ZOOM_OUT, "Zoom Out");
+ test_menu->AddItem(ID_TESTS_ZOOM_RESET, "Zoom Reset");
+ test_menu->AddItem(ID_TESTS_TRACING_BEGIN, "Begin Tracing");
+ test_menu->AddItem(ID_TESTS_TRACING_END, "End Tracing");
+ test_menu->AddItem(ID_TESTS_PRINT, "Print");
+ test_menu->AddItem(ID_TESTS_PRINT_TO_PDF, "Print to PDF");
+ test_menu->AddItem(ID_TESTS_MUTE_AUDIO, "Mute Audio");
+ test_menu->AddItem(ID_TESTS_UNMUTE_AUDIO, "Unmute Audio");
+ test_menu->AddItem(ID_TESTS_OTHER_TESTS, "Other Tests");
+}
+
+void AddFileMenuItems(CefRefPtr<CefMenuModel> file_menu) {
+ file_menu->AddItem(ID_QUIT, "E&xit");
+
+ // Show the accelerator shortcut text in the menu.
+ file_menu->SetAcceleratorAt(file_menu->GetCount() - 1, 'X', false, false,
+ true);
+}
+
+CefBrowserViewDelegate::ChromeToolbarType CalculateChromeToolbarType(
+ const std::string& toolbar_type,
+ bool hide_toolbar,
+ bool with_overlay_controls) {
+ if (!MainContext::Get()->UseChromeRuntime() || toolbar_type == "none" ||
+ hide_toolbar) {
+ return CEF_CTT_NONE;
+ }
+
+ if (toolbar_type == "location") {
+ return CEF_CTT_LOCATION;
+ }
+
+ return with_overlay_controls ? CEF_CTT_LOCATION : CEF_CTT_NORMAL;
+}
+
+} // namespace
+
+// static
+CefRefPtr<ViewsWindow> ViewsWindow::Create(
+ Delegate* delegate,
+ CefRefPtr<CefClient> client,
+ const CefString& url,
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefRequestContext> request_context) {
+ CEF_REQUIRE_UI_THREAD();
+ DCHECK(delegate);
+
+ // Create a new ViewsWindow.
+ CefRefPtr<ViewsWindow> views_window = new ViewsWindow(delegate, nullptr);
+
+ // Create a new BrowserView.
+ CefRefPtr<CefBrowserView> browser_view = CefBrowserView::CreateBrowserView(
+ client, url, settings, nullptr, request_context, views_window);
+
+ // Associate the BrowserView with the ViewsWindow.
+ views_window->SetBrowserView(browser_view);
+
+ // Create a new top-level Window. It will show itself after creation.
+ CefWindow::CreateTopLevelWindow(views_window);
+
+ return views_window;
+}
+
+void ViewsWindow::Show() {
+ CEF_REQUIRE_UI_THREAD();
+ if (window_) {
+ window_->Show();
+ }
+ if (browser_view_ && !window_->IsMinimized()) {
+ // Give keyboard focus to the BrowserView.
+ browser_view_->RequestFocus();
+ }
+}
+
+void ViewsWindow::Hide() {
+ CEF_REQUIRE_UI_THREAD();
+ if (window_) {
+ window_->Hide();
+ }
+}
+
+void ViewsWindow::Minimize() {
+ CEF_REQUIRE_UI_THREAD();
+ if (window_) {
+ window_->Minimize();
+ }
+}
+
+void ViewsWindow::Maximize() {
+ CEF_REQUIRE_UI_THREAD();
+ if (window_) {
+ window_->Maximize();
+ }
+}
+
+void ViewsWindow::SetBounds(const CefRect& bounds) {
+ CEF_REQUIRE_UI_THREAD();
+ if (window_) {
+ window_->SetBounds(bounds);
+ }
+}
+
+void ViewsWindow::SetBrowserSize(const CefSize& size,
+ bool has_position,
+ const CefPoint& position) {
+ CEF_REQUIRE_UI_THREAD();
+ if (browser_view_) {
+ browser_view_->SetSize(size);
+ }
+ if (window_) {
+ window_->SizeToPreferredSize();
+ if (has_position) {
+ window_->SetPosition(position);
+ }
+ }
+}
+
+void ViewsWindow::Close(bool force) {
+ CEF_REQUIRE_UI_THREAD();
+ if (!browser_view_) {
+ return;
+ }
+
+ CefRefPtr<CefBrowser> browser = browser_view_->GetBrowser();
+ if (browser) {
+ // This will result in a call to CefWindow::Close() which will then call
+ // ViewsWindow::CanClose().
+ browser->GetHost()->CloseBrowser(force);
+ }
+}
+
+void ViewsWindow::SetAddress(const std::string& url) {
+ CEF_REQUIRE_UI_THREAD();
+ if (!window_) {
+ return;
+ }
+
+ // |location_bar_| may instead be a Chrome toolbar.
+ if (location_bar_ && location_bar_->AsTextfield()) {
+ location_bar_->AsTextfield()->SetText(url);
+ }
+}
+
+void ViewsWindow::SetTitle(const std::string& title) {
+ CEF_REQUIRE_UI_THREAD();
+ if (window_) {
+ window_->SetTitle(title);
+ }
+}
+
+void ViewsWindow::SetFavicon(CefRefPtr<CefImage> image) {
+ CEF_REQUIRE_UI_THREAD();
+
+ // Window icons should be 16 DIP in size.
+ DCHECK_EQ(std::max(image->GetWidth(), image->GetHeight()), 16U);
+
+ if (window_) {
+ window_->SetWindowIcon(image);
+ }
+}
+
+void ViewsWindow::SetFullscreen(bool fullscreen) {
+ CEF_REQUIRE_UI_THREAD();
+ if (window_) {
+ // Hide the top controls while in full-screen mode.
+ if (with_controls_) {
+ ShowTopControls(!fullscreen);
+ }
+
+ window_->SetFullscreen(fullscreen);
+ }
+}
+
+void ViewsWindow::SetAlwaysOnTop(bool on_top) {
+ CEF_REQUIRE_UI_THREAD();
+ if (window_) {
+ window_->SetAlwaysOnTop(on_top);
+ }
+}
+
+void ViewsWindow::SetLoadingState(bool isLoading,
+ bool canGoBack,
+ bool canGoForward) {
+ CEF_REQUIRE_UI_THREAD();
+ if (!window_ || chrome_toolbar_type_ == CEF_CTT_NORMAL) {
+ return;
+ }
+
+ if (with_controls_) {
+ EnableView(ID_BACK_BUTTON, canGoBack);
+ EnableView(ID_FORWARD_BUTTON, canGoForward);
+ EnableView(ID_RELOAD_BUTTON, !isLoading);
+ EnableView(ID_STOP_BUTTON, isLoading);
+ }
+ if (location_bar_) {
+ EnableView(ID_URL_TEXTFIELD, true);
+ }
+}
+
+void ViewsWindow::SetDraggableRegions(
+ const std::vector<CefDraggableRegion>& regions) {
+ CEF_REQUIRE_UI_THREAD();
+
+ if (!window_ || !browser_view_) {
+ return;
+ }
+
+ // Convert the regions from BrowserView to Window coordinates.
+ std::vector<CefDraggableRegion> window_regions = regions;
+ for (auto& region : window_regions) {
+ CefPoint origin = CefPoint(region.bounds.x, region.bounds.y);
+ browser_view_->ConvertPointToWindow(origin);
+ region.bounds.x = origin.x;
+ region.bounds.y = origin.y;
+ }
+
+ if (overlay_controls_) {
+ // Exclude all regions obscured by overlays.
+ overlay_controls_->UpdateDraggableRegions(window_regions);
+ }
+
+ window_->SetDraggableRegions(window_regions);
+}
+
+void ViewsWindow::TakeFocus(bool next) {
+ CEF_REQUIRE_UI_THREAD();
+
+ if (!window_) {
+ return;
+ }
+
+ if (chrome_toolbar_type_ == CEF_CTT_NORMAL) {
+ top_toolbar_->RequestFocus();
+ } else if (location_bar_) {
+ // Give focus to the location bar.
+ location_bar_->RequestFocus();
+ }
+}
+
+void ViewsWindow::OnBeforeContextMenu(CefRefPtr<CefMenuModel> model) {
+ CEF_REQUIRE_UI_THREAD();
+
+ views_style::ApplyTo(model);
+}
+
+void ViewsWindow::OnExtensionsChanged(const ExtensionSet& extensions) {
+ CEF_REQUIRE_UI_THREAD();
+
+ if (extensions.empty()) {
+ if (!extensions_.empty()) {
+ extensions_.clear();
+ UpdateExtensionControls();
+ }
+ return;
+ }
+
+ ImageCache::ImageInfoSet image_set;
+
+ ExtensionSet::const_iterator it = extensions.begin();
+ for (; it != extensions.end(); ++it) {
+ CefRefPtr<CefExtension> extension = *it;
+ bool internal = false;
+ const std::string& icon_path =
+ extension_util::GetExtensionIconPath(extension, &internal);
+ if (!icon_path.empty()) {
+ // Load the extension icon.
+ image_set.push_back(
+ ImageCache::ImageInfo::Create1x(icon_path, icon_path, internal));
+ } else {
+ // Get a nullptr image and use the default icon.
+ image_set.push_back(ImageCache::ImageInfo::Empty());
+ }
+ }
+
+ delegate_->GetImageCache()->LoadImages(
+ image_set,
+ base::BindOnce(&ViewsWindow::OnExtensionIconsLoaded, this, extensions));
+}
+
+bool ViewsWindow::GetWindowRestorePreferences(
+ cef_show_state_t& show_state,
+ std::optional<CefRect>& dip_bounds) {
+ CEF_REQUIRE_UI_THREAD();
+ if (!window_) {
+ return false;
+ }
+
+ show_state = CEF_SHOW_STATE_NORMAL;
+ if (window_->IsMinimized()) {
+ show_state = CEF_SHOW_STATE_MINIMIZED;
+ } else if (window_->IsMaximized()) {
+ show_state = CEF_SHOW_STATE_MAXIMIZED;
+ } else if (window_->IsFullscreen()) {
+ show_state = CEF_SHOW_STATE_FULLSCREEN;
+ }
+
+ if (show_state == CEF_SHOW_STATE_NORMAL) {
+ // Use the current visible bounds.
+ dip_bounds = window_->GetBoundsInScreen();
+ } else {
+ // Use the last known visible bounds.
+ dip_bounds = last_visible_bounds_;
+ }
+
+ return true;
+}
+
+void ViewsWindow::SetTitlebarHeight(const std::optional<float>& height) {
+ CEF_REQUIRE_UI_THREAD();
+ if (height.has_value()) {
+ override_titlebar_height_ = height;
+ } else {
+ override_titlebar_height_ = default_titlebar_height_;
+ }
+ NudgeWindow();
+}
+
+CefRefPtr<CefBrowserViewDelegate> ViewsWindow::GetDelegateForPopupBrowserView(
+ CefRefPtr<CefBrowserView> browser_view,
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefClient> client,
+ bool is_devtools) {
+ CEF_REQUIRE_UI_THREAD();
+
+ // The popup browser client is created in CefLifeSpanHandler::OnBeforePopup()
+ // (e.g. via RootWindowViews::InitAsPopup()). The Delegate (RootWindowViews)
+ // knows the association between |client| and itself.
+ Delegate* popup_delegate = delegate_->GetDelegateForPopup(client);
+
+ // May be nullptr when using the default popup behavior.
+ if (!popup_delegate) {
+ return nullptr;
+ }
+
+ // Should not be the same RootWindowViews that owns |this|.
+ DCHECK(popup_delegate != delegate_);
+
+ // Create a new ViewsWindow for the popup BrowserView.
+ return new ViewsWindow(popup_delegate, nullptr);
+}
+
+bool ViewsWindow::OnPopupBrowserViewCreated(
+ CefRefPtr<CefBrowserView> browser_view,
+ CefRefPtr<CefBrowserView> popup_browser_view,
+ bool is_devtools) {
+ CEF_REQUIRE_UI_THREAD();
+
+ // Retrieve the ViewsWindow created in GetDelegateForPopupBrowserView.
+ CefRefPtr<ViewsWindow> popup_window =
+ static_cast<ViewsWindow*>(static_cast<CefBrowserViewDelegate*>(
+ popup_browser_view->GetDelegate().get()));
+
+ // May be nullptr when using the default popup behavior.
+ if (!popup_window) {
+ return false;
+ }
+
+ // Should not be the same ViewsWindow as |this|.
+ DCHECK(popup_window != this);
+
+ // Associate the ViewsWindow with the new popup browser.
+ popup_window->SetBrowserView(popup_browser_view);
+
+ // Create a new top-level Window for the popup. It will show itself after
+ // creation.
+ CefWindow::CreateTopLevelWindow(popup_window);
+
+ // We created the Window.
+ return true;
+}
+
+CefBrowserViewDelegate::ChromeToolbarType ViewsWindow::GetChromeToolbarType() {
+ return chrome_toolbar_type_;
+}
+
+void ViewsWindow::OnButtonPressed(CefRefPtr<CefButton> button) {
+ CEF_REQUIRE_UI_THREAD();
+ DCHECK(with_controls_);
+
+ if (!browser_view_) {
+ return;
+ }
+
+ CefRefPtr<CefBrowser> browser = browser_view_->GetBrowser();
+ if (!browser) {
+ return;
+ }
+
+ switch (button->GetID()) {
+ case ID_BACK_BUTTON:
+ browser->GoBack();
+ break;
+ case ID_FORWARD_BUTTON:
+ browser->GoForward();
+ break;
+ case ID_STOP_BUTTON:
+ browser->StopLoad();
+ break;
+ case ID_RELOAD_BUTTON:
+ browser->Reload();
+ break;
+ case ID_MENU_BUTTON:
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+}
+
+void ViewsWindow::OnMenuButtonPressed(
+ CefRefPtr<CefMenuButton> menu_button,
+ const CefPoint& screen_point,
+ CefRefPtr<CefMenuButtonPressedLock> button_pressed_lock) {
+ CEF_REQUIRE_UI_THREAD();
+
+ const int id = menu_button->GetID();
+ if (id >= ID_EXTENSION_BUTTON_FIRST && id <= ID_EXTENSION_BUTTON_LAST) {
+ const size_t extension_idx = id - ID_EXTENSION_BUTTON_FIRST;
+ if (extension_idx >= extensions_.size()) {
+ LOG(ERROR) << "Invalid extension index " << extension_idx;
+ return;
+ }
+
+ // Keep the button pressed until the extension window is closed.
+ extension_button_pressed_lock_ = button_pressed_lock;
+
+ // Create a window for the extension.
+ delegate_->CreateExtensionWindow(
+ extensions_[extension_idx].extension_, menu_button->GetBoundsInScreen(),
+ window_, base::BindOnce(&ViewsWindow::OnExtensionWindowClosed, this));
+ return;
+ }
+
+ DCHECK(with_controls_ || with_overlay_controls_);
+ DCHECK_EQ(ID_MENU_BUTTON, id);
+
+ auto point = screen_point;
+ if (with_overlay_controls_) {
+ // Align the menu correctly under the button.
+ const int button_width = menu_button->GetSize().width;
+ if (CefIsRTL()) {
+ point.x += button_width - 4;
+ } else {
+ point.x -= button_width - 4;
+ }
+ }
+
+ menu_button->ShowMenu(button_menu_model_, point,
+ with_overlay_controls_ ? CEF_MENU_ANCHOR_TOPLEFT
+ : CEF_MENU_ANCHOR_TOPRIGHT);
+}
+
+void ViewsWindow::ExecuteCommand(CefRefPtr<CefMenuModel> menu_model,
+ int command_id,
+ cef_event_flags_t event_flags) {
+ CEF_REQUIRE_UI_THREAD();
+ DCHECK(with_controls_ || with_overlay_controls_);
+
+ if (command_id == ID_QUIT) {
+ delegate_->OnExit();
+ } else if (command_id >= ID_TESTS_FIRST && command_id <= ID_TESTS_LAST) {
+ delegate_->OnTest(command_id);
+ } else {
+ NOTREACHED();
+ }
+}
+
+bool ViewsWindow::OnKeyEvent(CefRefPtr<CefTextfield> textfield,
+ const CefKeyEvent& event) {
+ CEF_REQUIRE_UI_THREAD();
+ DCHECK_EQ(ID_URL_TEXTFIELD, textfield->GetID());
+
+ // Trigger when the return key is pressed.
+ if (window_ && browser_view_ && event.type == KEYEVENT_RAWKEYDOWN &&
+ event.windows_key_code == VK_RETURN) {
+ CefRefPtr<CefBrowser> browser = browser_view_->GetBrowser();
+ if (browser) {
+ const CefString& url = textfield->GetText();
+ if (!url.empty()) {
+ browser->GetMainFrame()->LoadURL(url);
+ }
+ }
+
+ // We handled the event.
+ return true;
+ }
+
+ return false;
+}
+
+void ViewsWindow::OnWindowCreated(CefRefPtr<CefWindow> window) {
+ CEF_REQUIRE_UI_THREAD();
+ DCHECK(browser_view_);
+ DCHECK(!window_);
+ DCHECK(window);
+
+ window_ = window;
+ window_->SetID(ID_WINDOW);
+
+ with_controls_ = delegate_->WithControls();
+
+ delegate_->OnViewsWindowCreated(this);
+
+ const CefRect bounds = delegate_->GetInitialBounds();
+ if (bounds.IsEmpty()) {
+ // Size the Window and center it at the default size.
+ window_->CenterWindow(CefSize(kDefaultWidth, kDefaultHeight));
+ } else {
+ // Remember the bounds from the previous application run in case the user
+ // does not move or resize the window during this application run.
+ last_visible_bounds_ = bounds;
+ }
+
+ // Set the background color for regions that are not obscured by other Views.
+ views_style::ApplyTo(window_.get());
+
+ if (with_controls_ || with_overlay_controls_) {
+ // Create the MenuModel that will be displayed via the menu button.
+ CreateMenuModel();
+ }
+
+ if (with_controls_) {
+ // Add the BrowserView and other controls to the Window.
+ AddBrowserView();
+
+ // Add keyboard accelerators to the Window.
+ AddAccelerators();
+
+ // Hide the top controls while in full-screen mode.
+ if (delegate_->GetInitialShowState() == CEF_SHOW_STATE_FULLSCREEN) {
+ ShowTopControls(false);
+ }
+ } else {
+ // Add the BrowserView as the only child of the Window.
+ window_->AddChildView(browser_view_);
+
+ if (!delegate_->WithExtension()) {
+ // Choose a reasonable minimum window size.
+ minimum_window_size_ = CefSize(100, 100);
+ }
+ }
+
+ if (!delegate_->InitiallyHidden()) {
+ // Show the Window.
+ Show();
+ }
+}
+
+void ViewsWindow::OnWindowClosing(CefRefPtr<CefWindow> window) {
+ CEF_REQUIRE_UI_THREAD();
+ DCHECK(window_);
+
+ delegate_->OnViewsWindowClosing(this);
+}
+
+void ViewsWindow::OnWindowDestroyed(CefRefPtr<CefWindow> window) {
+ CEF_REQUIRE_UI_THREAD();
+ DCHECK(window_);
+
+ delegate_->OnViewsWindowDestroyed(this);
+
+ browser_view_ = nullptr;
+ button_menu_model_ = nullptr;
+ if (top_menu_bar_) {
+ top_menu_bar_->Reset();
+ top_menu_bar_ = nullptr;
+ }
+ extensions_panel_ = nullptr;
+ menu_button_ = nullptr;
+ window_ = nullptr;
+}
+
+void ViewsWindow::OnWindowActivationChanged(CefRefPtr<CefWindow> window,
+ bool active) {
+ if (!active) {
+ return;
+ }
+
+ delegate_->OnViewsWindowActivated(this);
+}
+
+void ViewsWindow::OnWindowBoundsChanged(CefRefPtr<CefWindow> window,
+ const CefRect& new_bounds) {
+ if (!window->IsMinimized() && !window->IsMaximized() &&
+ !window->IsFullscreen()) {
+ // Track the last visible bounds for window restore purposes.
+ last_visible_bounds_ = new_bounds;
+ }
+
+#if defined(OS_MAC)
+ if (frameless_ && with_standard_buttons_ && top_toolbar_) {
+ auto insets = top_toolbar_->GetInsets();
+ insets.left = window->IsFullscreen() ? 0 : kWindowButtonsWidth;
+ top_toolbar_->SetInsets(insets);
+ }
+#endif
+}
+
+bool ViewsWindow::CanClose(CefRefPtr<CefWindow> window) {
+ CEF_REQUIRE_UI_THREAD();
+
+ // Allow the window to close if the browser says it's OK.
+ CefRefPtr<CefBrowser> browser = browser_view_->GetBrowser();
+ if (browser) {
+ return browser->GetHost()->TryCloseBrowser();
+ }
+ return true;
+}
+
+CefRefPtr<CefWindow> ViewsWindow::GetParentWindow(CefRefPtr<CefWindow> window,
+ bool* is_menu,
+ bool* can_activate_menu) {
+ CEF_REQUIRE_UI_THREAD();
+ CefRefPtr<CefWindow> parent_window = delegate_->GetParentWindow();
+ if (parent_window) {
+ // Should be an extension window, in which case we want it to behave as a
+ // menu and allow activation.
+ DCHECK(delegate_->WithExtension());
+ *is_menu = true;
+ *can_activate_menu = true;
+ }
+ return parent_window;
+}
+
+CefRect ViewsWindow::GetInitialBounds(CefRefPtr<CefWindow> window) {
+ CEF_REQUIRE_UI_THREAD();
+ const CefRect bounds = delegate_->GetInitialBounds();
+ if (frameless_ && bounds.IsEmpty()) {
+ // Need to provide a size for frameless windows that will be centered.
+ return CefRect(0, 0, kDefaultWidth, kDefaultHeight);
+ }
+ return bounds;
+}
+
+cef_show_state_t ViewsWindow::GetInitialShowState(CefRefPtr<CefWindow> window) {
+ CEF_REQUIRE_UI_THREAD();
+ return delegate_->GetInitialShowState();
+}
+
+bool ViewsWindow::IsFrameless(CefRefPtr<CefWindow> window) {
+ CEF_REQUIRE_UI_THREAD();
+ return frameless_;
+}
+
+bool ViewsWindow::WithStandardWindowButtons(CefRefPtr<CefWindow> window) {
+ CEF_REQUIRE_UI_THREAD();
+ return with_standard_buttons_;
+}
+
+bool ViewsWindow::GetTitlebarHeight(CefRefPtr<CefWindow> window,
+ float* titlebar_height) {
+ CEF_REQUIRE_UI_THREAD();
+#if defined(OS_MAC)
+ if (override_titlebar_height_.has_value()) {
+ *titlebar_height = override_titlebar_height_.value();
+ return true;
+ }
+#endif
+
+ return false;
+}
+
+bool ViewsWindow::CanResize(CefRefPtr<CefWindow> window) {
+ CEF_REQUIRE_UI_THREAD();
+ // Don't allow windows hosting extensions to resize.
+ return !delegate_->WithExtension();
+}
+
+bool ViewsWindow::OnAccelerator(CefRefPtr<CefWindow> window, int command_id) {
+ CEF_REQUIRE_UI_THREAD();
+
+ if (command_id == ID_QUIT) {
+ delegate_->OnExit();
+ return true;
+ }
+
+ return false;
+}
+
+bool ViewsWindow::OnKeyEvent(CefRefPtr<CefWindow> window,
+ const CefKeyEvent& event) {
+ CEF_REQUIRE_UI_THREAD();
+
+ if (!window_) {
+ return false;
+ }
+
+ if (delegate_->WithExtension() && event.type == KEYEVENT_RAWKEYDOWN &&
+ event.windows_key_code == VK_ESCAPE) {
+ // Close the extension window on escape.
+ Close(false);
+ return true;
+ }
+
+ if (!with_controls_) {
+ return false;
+ }
+
+ if (event.type == KEYEVENT_RAWKEYDOWN && event.windows_key_code == VK_MENU) {
+ // ALT key is pressed.
+ int last_focused_view = last_focused_view_;
+ bool menu_had_focus = menu_has_focus_;
+
+ // Toggle menu button focusable.
+ SetMenuFocusable(!menu_has_focus_);
+
+ if (menu_had_focus && last_focused_view != 0) {
+ // Restore focus to the view that was previously focused.
+ window_->GetViewForID(last_focused_view)->RequestFocus();
+ }
+
+ return true;
+ }
+
+ if (menu_has_focus_ && top_menu_bar_) {
+ return top_menu_bar_->OnKeyEvent(event);
+ }
+
+ return false;
+}
+
+CefSize ViewsWindow::GetMinimumSize(CefRefPtr<CefView> view) {
+ CEF_REQUIRE_UI_THREAD();
+
+ if (view->GetID() == ID_WINDOW) {
+ return minimum_window_size_;
+ }
+
+ return CefSize();
+}
+
+void ViewsWindow::OnFocus(CefRefPtr<CefView> view) {
+ CEF_REQUIRE_UI_THREAD();
+
+ const int view_id = view->GetID();
+
+ // Keep track of the non-menu view that was last focused.
+ if (last_focused_view_ != view_id &&
+ (!top_menu_bar_ || !top_menu_bar_->HasMenuId(view_id))) {
+ last_focused_view_ = view_id;
+ }
+
+ // When focus leaves the menu buttons make them unfocusable.
+ if (menu_has_focus_) {
+ if (top_menu_bar_) {
+ if (!top_menu_bar_->HasMenuId(view_id)) {
+ SetMenuFocusable(false);
+ }
+ } else if (view_id != ID_MENU_BUTTON) {
+ SetMenuFocusable(false);
+ }
+ }
+}
+
+void ViewsWindow::OnBlur(CefRefPtr<CefView> view) {
+ CEF_REQUIRE_UI_THREAD();
+
+ const int view_id = view->GetID();
+ if (view_id == ID_BROWSER_VIEW && delegate_->WithExtension()) {
+ // Close windows hosting extensions when the browser loses focus.
+ Close(false);
+ }
+}
+
+void ViewsWindow::OnWindowChanged(CefRefPtr<CefView> view, bool added) {
+ const int view_id = view->GetID();
+ if (view_id != ID_BROWSER_VIEW) {
+ return;
+ }
+
+ if (added) {
+ if (with_controls_) {
+ AddControls();
+ }
+
+ if (with_overlay_controls_) {
+ // Add window buttons if we don't have standard ones
+ const bool with_window_buttons = !with_standard_buttons_;
+ overlay_controls_ = new ViewsOverlayControls(with_window_buttons);
+ overlay_controls_->Initialize(window_, CreateMenuButton(),
+ CreateLocationBar(),
+ chrome_toolbar_type_ != CEF_CTT_NONE);
+ }
+ } else {
+ if (overlay_controls_) {
+ // Overlay controls may include the Chrome toolbar, in which case they
+ // need to be removed before the BrowserView.
+ overlay_controls_->Destroy();
+ overlay_controls_ = nullptr;
+ location_bar_ = nullptr;
+ }
+ }
+}
+
+void ViewsWindow::OnLayoutChanged(CefRefPtr<CefView> view,
+ const CefRect& new_bounds) {
+ const int view_id = view->GetID();
+ if (view_id != ID_BROWSER_VIEW) {
+ return;
+ }
+
+ if (overlay_controls_) {
+ overlay_controls_->UpdateControls();
+ }
+}
+
+void ViewsWindow::MenuBarExecuteCommand(CefRefPtr<CefMenuModel> menu_model,
+ int command_id,
+ cef_event_flags_t event_flags) {
+ ExecuteCommand(menu_model, command_id, event_flags);
+}
+
+ViewsWindow::ViewsWindow(Delegate* delegate,
+ CefRefPtr<CefBrowserView> browser_view)
+ : delegate_(delegate),
+ with_controls_(false),
+ menu_has_focus_(false),
+ last_focused_view_(false) {
+ DCHECK(delegate_);
+ if (browser_view) {
+ SetBrowserView(browser_view);
+ }
+
+ CefRefPtr<CefCommandLine> command_line =
+ CefCommandLine::GetGlobalCommandLine();
+
+ const bool hide_frame = command_line->HasSwitch(switches::kHideFrame);
+ const bool hide_overlays = command_line->HasSwitch(switches::kHideOverlays);
+ const bool hide_toolbar =
+ hide_frame && hide_overlays && !delegate_->WithControls();
+ const bool show_window_buttons =
+ command_line->HasSwitch(switches::kShowWindowButtons);
+
+ // Without a window frame.
+ frameless_ = hide_frame || delegate_->WithExtension();
+
+ // With an overlay that mimics window controls.
+ with_overlay_controls_ =
+ hide_frame && !hide_overlays && !delegate_->WithControls();
+
+ // If window has frame or flag passed explicitly
+ with_standard_buttons_ = !frameless_ || show_window_buttons;
+
+#if defined(OS_MAC)
+ if (frameless_ && with_standard_buttons_) {
+ default_titlebar_height_ = kTitleBarHeight;
+ override_titlebar_height_ = kTitleBarHeight;
+ }
+#endif
+
+ const std::string& toolbar_type =
+ command_line->GetSwitchValue(switches::kShowChromeToolbar);
+ chrome_toolbar_type_ = CalculateChromeToolbarType(toolbar_type, hide_toolbar,
+ with_overlay_controls_);
+
+#if !defined(OS_MAC)
+ // On Mac we don't show a top menu on the window. The options are available in
+ // the app menu instead.
+ if (!command_line->HasSwitch(switches::kHideTopMenu)) {
+ top_menu_bar_ = new ViewsMenuBar(this, ID_TOP_MENU_FIRST);
+ }
+#endif
+}
+
+void ViewsWindow::SetBrowserView(CefRefPtr<CefBrowserView> browser_view) {
+ DCHECK(!browser_view_);
+ DCHECK(browser_view);
+ DCHECK(browser_view->IsValid());
+ DCHECK(!browser_view->IsAttached());
+ browser_view_ = browser_view;
+ browser_view_->SetID(ID_BROWSER_VIEW);
+}
+
+void ViewsWindow::CreateMenuModel() {
+ // Create the menu button model.
+ button_menu_model_ = CefMenuModel::CreateMenuModel(this);
+ CefRefPtr<CefMenuModel> test_menu =
+ button_menu_model_->AddSubMenu(0, "&Tests");
+ views_style::ApplyTo(button_menu_model_);
+ AddTestMenuItems(test_menu);
+ AddFileMenuItems(button_menu_model_);
+
+ if (top_menu_bar_) {
+ // Add the menus to the top menu bar.
+ AddFileMenuItems(top_menu_bar_->CreateMenuModel("&File", nullptr));
+ AddTestMenuItems(top_menu_bar_->CreateMenuModel("&Tests", nullptr));
+ }
+}
+
+CefRefPtr<CefLabelButton> ViewsWindow::CreateBrowseButton(
+ const std::string& label,
+ int id) {
+ CefRefPtr<CefLabelButton> button =
+ CefLabelButton::CreateLabelButton(this, label);
+ button->SetID(id);
+ views_style::ApplyTo(button.get());
+ button->SetInkDropEnabled(true);
+ button->SetEnabled(false); // Disabled by default.
+ button->SetFocusable(false); // Don't give focus to the button.
+
+ return button;
+}
+
+CefRefPtr<CefMenuButton> ViewsWindow::CreateMenuButton() {
+ // Create the menu button.
+ DCHECK(!menu_button_);
+ menu_button_ = CefMenuButton::CreateMenuButton(this, CefString());
+ menu_button_->SetID(ID_MENU_BUTTON);
+ menu_button_->SetImage(
+ CEF_BUTTON_STATE_NORMAL,
+ delegate_->GetImageCache()->GetCachedImage("menu_icon"));
+ views_style::ApplyTo(menu_button_.get());
+ menu_button_->SetInkDropEnabled(true);
+ // Override the default minimum size.
+ menu_button_->SetMinimumSize(CefSize(0, 0));
+ return menu_button_;
+}
+
+CefRefPtr<CefView> ViewsWindow::CreateLocationBar() {
+ DCHECK(!location_bar_);
+ if (chrome_toolbar_type_ == CEF_CTT_LOCATION) {
+ // Chrome will provide a minimal location bar.
+ location_bar_ = browser_view_->GetChromeToolbar();
+ DCHECK(location_bar_);
+ views_style::ApplyBackgroundTo(location_bar_);
+ }
+ if (!location_bar_) {
+ // Create the URL textfield.
+ CefRefPtr<CefTextfield> url_textfield = CefTextfield::CreateTextfield(this);
+ url_textfield->SetID(ID_URL_TEXTFIELD);
+ url_textfield->SetEnabled(false); // Disabled by default.
+ views_style::ApplyTo(url_textfield);
+ location_bar_ = url_textfield;
+ }
+ return location_bar_;
+}
+
+void ViewsWindow::AddBrowserView() {
+ // Use a vertical box layout for |window|.
+ CefBoxLayoutSettings window_layout_settings;
+ window_layout_settings.horizontal = false;
+ window_layout_settings.between_child_spacing = 2;
+ CefRefPtr<CefBoxLayout> window_layout =
+ window_->SetToBoxLayout(window_layout_settings);
+
+ window_->AddChildView(browser_view_);
+
+ // Allow |browser_view_| to grow and fill any remaining space.
+ window_layout->SetFlexForView(browser_view_, 1);
+
+ // Remaining setup will be performed in OnWindowChanged after the BrowserView
+ // is added to the CefWindow. This is necessary because Chrome toolbars are
+ // only available after the BrowserView is added.
+}
+
+void ViewsWindow::AddControls() {
+ // Build the remainder of the UI now that the BrowserView has been added to
+ // the CefWindow. This is a requirement to use Chrome toolbars.
+
+ CefRefPtr<CefPanel> top_menu_panel;
+ if (top_menu_bar_) {
+ top_menu_panel = top_menu_bar_->GetMenuPanel();
+ }
+
+ LabelButtons browse_buttons;
+
+ if (chrome_toolbar_type_ == CEF_CTT_NORMAL) {
+ // Chrome will provide a normal toolbar with location, menu, etc.
+ top_toolbar_ = browser_view_->GetChromeToolbar();
+ DCHECK(top_toolbar_);
+ }
+
+ if (!top_toolbar_) {
+ // Create the browse buttons.
+ browse_buttons.push_back(CreateBrowseButton("Back", ID_BACK_BUTTON));
+ browse_buttons.push_back(CreateBrowseButton("Forward", ID_FORWARD_BUTTON));
+ browse_buttons.push_back(CreateBrowseButton("Reload", ID_RELOAD_BUTTON));
+ browse_buttons.push_back(CreateBrowseButton("Stop", ID_STOP_BUTTON));
+
+ CreateLocationBar();
+ CreateMenuButton();
+
+ // Create the top panel.
+ CefRefPtr<CefPanel> top_panel = CefPanel::CreatePanel(nullptr);
+
+ // Use a horizontal box layout for |top_panel|.
+ CefBoxLayoutSettings top_panel_layout_settings;
+ top_panel_layout_settings.horizontal = true;
+ CefRefPtr<CefBoxLayout> top_panel_layout =
+ top_panel->SetToBoxLayout(top_panel_layout_settings);
+
+ // Add the buttons and URL textfield to |top_panel|.
+ for (auto& browse_button : browse_buttons)
+ top_panel->AddChildView(browse_button);
+ top_panel->AddChildView(location_bar_);
+
+ UpdateExtensionControls();
+ DCHECK(extensions_panel_);
+ top_panel->AddChildView(extensions_panel_);
+
+ top_panel->AddChildView(menu_button_);
+ views_style::ApplyTo(top_panel);
+
+ // Allow |location| to grow and fill any remaining space.
+ top_panel_layout->SetFlexForView(location_bar_, 1);
+
+ top_toolbar_ = top_panel;
+ }
+
+#if defined(OS_MAC)
+ if (frameless_ && with_standard_buttons_) {
+ auto insets = top_toolbar_->GetInsets();
+ insets.left = kWindowButtonsWidth;
+ top_toolbar_->SetInsets(insets);
+ }
+#endif
+
+ // Add the top panel and browser view to |window|.
+ int top_index = 0;
+ if (top_menu_panel) {
+ window_->AddChildViewAt(top_menu_panel, top_index++);
+ }
+ window_->AddChildViewAt(top_toolbar_, top_index);
+
+ // Lay out |window| so we can get the default button sizes.
+ window_->Layout();
+
+ int min_width = 200;
+ if (!browse_buttons.empty()) {
+ // Make all browse buttons the same size.
+ MakeButtonsSameSize(browse_buttons);
+
+ // Lay out |window| again with the new button sizes.
+ window_->Layout();
+
+ const int buttons_number = static_cast<int>(browse_buttons.size());
+
+ // Minimum window width is the size of all buttons plus some extra.
+ min_width = browse_buttons[0]->GetBounds().width * buttons_number +
+ menu_button_->GetBounds().width + 100;
+ }
+
+ // Minimum window height is the hight of the top toolbar plus some extra.
+ int min_height = top_toolbar_->GetBounds().height + 100;
+ if (top_menu_panel) {
+ min_height += top_menu_panel->GetBounds().height;
+ }
+
+ minimum_window_size_ = CefSize(min_width, min_height);
+}
+
+void ViewsWindow::AddAccelerators() {
+ // Trigger accelerators without first forwarding to web content.
+ browser_view_->SetPreferAccelerators(true);
+
+ // Specify the accelerators to handle. OnAccelerator will be called when the
+ // accelerator is triggered.
+ window_->SetAccelerator(ID_QUIT, 'X', false, false, true);
+}
+
+void ViewsWindow::SetMenuFocusable(bool focusable) {
+ if (!window_ || !with_controls_) {
+ return;
+ }
+
+ if (top_menu_bar_) {
+ top_menu_bar_->SetMenuFocusable(focusable);
+ } else {
+ window_->GetViewForID(ID_MENU_BUTTON)->SetFocusable(focusable);
+
+ if (focusable) {
+ // Give focus to menu button.
+ window_->GetViewForID(ID_MENU_BUTTON)->RequestFocus();
+ }
+ }
+
+ menu_has_focus_ = focusable;
+}
+
+void ViewsWindow::EnableView(int id, bool enable) {
+ if (!window_) {
+ return;
+ }
+ // Special handling for |location_bar_| which may be an overlay (e.g. not a
+ // child of this view).
+ CefRefPtr<CefView> view =
+ id == ID_URL_TEXTFIELD ? location_bar_ : window_->GetViewForID(id);
+ if (view) {
+ view->SetEnabled(enable);
+ }
+}
+
+void ViewsWindow::ShowTopControls(bool show) {
+ if (!window_ || !with_controls_) {
+ return;
+ }
+
+ // Change the visibility of the top toolbar.
+ if (top_toolbar_->IsVisible() != show) {
+ top_toolbar_->SetVisible(show);
+ top_toolbar_->InvalidateLayout();
+ }
+}
+
+void ViewsWindow::UpdateExtensionControls() {
+ CEF_REQUIRE_UI_THREAD();
+
+ if (!window_ || !with_controls_) {
+ return;
+ }
+
+ if (!extensions_panel_) {
+ extensions_panel_ = CefPanel::CreatePanel(nullptr);
+
+ // Use a horizontal box layout for |top_panel|.
+ CefBoxLayoutSettings top_panel_layout_settings;
+ top_panel_layout_settings.horizontal = true;
+ CefRefPtr<CefBoxLayout> top_panel_layout =
+ extensions_panel_->SetToBoxLayout(top_panel_layout_settings);
+ } else {
+ extensions_panel_->RemoveAllChildViews();
+ }
+
+ if (extensions_.size() >
+ ID_EXTENSION_BUTTON_LAST - ID_EXTENSION_BUTTON_FIRST) {
+ LOG(WARNING) << "Too many extensions loaded. Some will be ignored.";
+ }
+
+ ExtensionInfoSet::const_iterator it = extensions_.begin();
+ for (int id = ID_EXTENSION_BUTTON_FIRST;
+ it != extensions_.end() && id <= ID_EXTENSION_BUTTON_LAST; ++id, ++it) {
+ CefRefPtr<CefMenuButton> button =
+ CefMenuButton::CreateMenuButton(this, CefString());
+ button->SetID(id);
+ button->SetImage(CEF_BUTTON_STATE_NORMAL, (*it).image_);
+ views_style::ApplyTo(button.get());
+ button->SetInkDropEnabled(true);
+ // Override the default minimum size.
+ button->SetMinimumSize(CefSize(0, 0));
+
+ extensions_panel_->AddChildView(button);
+ }
+
+ CefRefPtr<CefView> parent_view = extensions_panel_->GetParentView();
+ if (parent_view) {
+ parent_view->InvalidateLayout();
+ }
+}
+
+void ViewsWindow::OnExtensionIconsLoaded(const ExtensionSet& extensions,
+ const ImageCache::ImageSet& images) {
+ if (!CefCurrentlyOn(TID_UI)) {
+ // Execute this method on the UI thread.
+ CefPostTask(TID_UI, base::BindOnce(&ViewsWindow::OnExtensionIconsLoaded,
+ this, extensions, images));
+ return;
+ }
+
+ DCHECK_EQ(extensions.size(), images.size());
+
+ extensions_.clear();
+
+ ExtensionSet::const_iterator it1 = extensions.begin();
+ ImageCache::ImageSet::const_iterator it2 = images.begin();
+ for (; it1 != extensions.end() && it2 != images.end(); ++it1, ++it2) {
+ CefRefPtr<CefImage> icon = *it2;
+ if (!icon) {
+ icon = delegate_->GetImageCache()->GetCachedImage(kDefaultExtensionIcon);
+ }
+ extensions_.push_back(ExtensionInfo(*it1, icon));
+ }
+
+ UpdateExtensionControls();
+}
+
+void ViewsWindow::OnExtensionWindowClosed() {
+ if (!CefCurrentlyOn(TID_UI)) {
+ // Execute this method on the UI thread.
+ CefPostTask(TID_UI,
+ base::BindOnce(&ViewsWindow::OnExtensionWindowClosed, this));
+ return;
+ }
+
+ // Restore the button state.
+ extension_button_pressed_lock_ = nullptr;
+}
+
+#if !defined(OS_MAC)
+void ViewsWindow::NudgeWindow() {
+ NOTIMPLEMENTED();
+}
+#endif
+
+} // namespace client
diff --git a/tests/cefclient/browser/views_window.h b/tests/cefclient/browser/views_window.h
new file mode 100644
index 00000000..9dc34ada
--- /dev/null
+++ b/tests/cefclient/browser/views_window.h
@@ -0,0 +1,287 @@
+// Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_VIEWS_WINDOW_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_VIEWS_WINDOW_H_
+#pragma once
+
+#include <optional>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "include/base/cef_callback_forward.h"
+#include "include/cef_menu_model_delegate.h"
+#include "include/views/cef_browser_view.h"
+#include "include/views/cef_browser_view_delegate.h"
+#include "include/views/cef_button_delegate.h"
+#include "include/views/cef_label_button.h"
+#include "include/views/cef_menu_button.h"
+#include "include/views/cef_menu_button_delegate.h"
+#include "include/views/cef_overlay_controller.h"
+#include "include/views/cef_textfield.h"
+#include "include/views/cef_textfield_delegate.h"
+#include "include/views/cef_window.h"
+#include "include/views/cef_window_delegate.h"
+#include "tests/cefclient/browser/image_cache.h"
+#include "tests/cefclient/browser/views_menu_bar.h"
+#include "tests/cefclient/browser/views_overlay_controls.h"
+
+namespace client {
+
+typedef std::set<CefRefPtr<CefExtension>> ExtensionSet;
+
+// Implements a CefWindow that hosts a single CefBrowserView and optional
+// Views-based controls. All methods must be called on the browser process UI
+// thread.
+class ViewsWindow : public CefBrowserViewDelegate,
+ public CefMenuButtonDelegate,
+ public CefMenuModelDelegate,
+ public CefTextfieldDelegate,
+ public CefWindowDelegate,
+ public ViewsMenuBar::Delegate {
+ public:
+ // Delegate methods will be called on the browser process UI thread.
+ class Delegate {
+ public:
+ // Return true if the window should show controls.
+ virtual bool WithControls() = 0;
+
+ // Return true if the window is hosting an extension.
+ virtual bool WithExtension() = 0;
+
+ // Return true if the window should be created initially hidden.
+ virtual bool InitiallyHidden() = 0;
+
+ // Returns the parent for this window.
+ virtual CefRefPtr<CefWindow> GetParentWindow() = 0;
+
+ // Return the initial window bounds.
+ virtual CefRect GetInitialBounds() = 0;
+
+ // Return the initial window show state.
+ virtual cef_show_state_t GetInitialShowState() = 0;
+
+ // Returns the ImageCache.
+ virtual scoped_refptr<ImageCache> GetImageCache() = 0;
+
+ // Called when the ViewsWindow is created.
+ virtual void OnViewsWindowCreated(CefRefPtr<ViewsWindow> window) = 0;
+
+ // Called when the ViewsWindow is closing.
+ virtual void OnViewsWindowClosing(CefRefPtr<ViewsWindow> window) = 0;
+
+ // Called when the ViewsWindow is destroyed. All references to |window|
+ // should be released in this callback.
+ virtual void OnViewsWindowDestroyed(CefRefPtr<ViewsWindow> window) = 0;
+
+ // Called when the ViewsWindow is activated (becomes the foreground window).
+ virtual void OnViewsWindowActivated(CefRefPtr<ViewsWindow> window) = 0;
+
+ // Return the Delegate for the popup window controlled by |client|.
+ virtual Delegate* GetDelegateForPopup(CefRefPtr<CefClient> client) = 0;
+
+ // Create a window for |extension|. |source_bounds| are the bounds of the
+ // UI element, like a button, that triggered the extension.
+ virtual void CreateExtensionWindow(CefRefPtr<CefExtension> extension,
+ const CefRect& source_bounds,
+ CefRefPtr<CefWindow> parent_window,
+ base::OnceClosure close_callback) = 0;
+
+ // Called to execute a test. See resource.h for |test_id| values.
+ virtual void OnTest(int test_id) = 0;
+
+ // Called to exit the application.
+ virtual void OnExit() = 0;
+
+ protected:
+ virtual ~Delegate() {}
+ };
+
+ // Create a new top-level ViewsWindow hosting a browser with the specified
+ // configuration.
+ static CefRefPtr<ViewsWindow> Create(
+ Delegate* delegate,
+ CefRefPtr<CefClient> client,
+ const CefString& url,
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefRequestContext> request_context);
+
+ void Show();
+ void Hide();
+ void Minimize();
+ void Maximize();
+ void SetBounds(const CefRect& bounds);
+ void SetBrowserSize(const CefSize& size,
+ bool has_position,
+ const CefPoint& position);
+ void Close(bool force);
+ void SetAddress(const std::string& url);
+ void SetTitle(const std::string& title);
+ void SetFavicon(CefRefPtr<CefImage> image);
+ void SetFullscreen(bool fullscreen);
+ void SetAlwaysOnTop(bool on_top);
+ void SetLoadingState(bool isLoading, bool canGoBack, bool canGoForward);
+ void SetDraggableRegions(const std::vector<CefDraggableRegion>& regions);
+ void TakeFocus(bool next);
+ void OnBeforeContextMenu(CefRefPtr<CefMenuModel> model);
+ void OnExtensionsChanged(const ExtensionSet& extensions);
+
+ bool GetWindowRestorePreferences(cef_show_state_t& show_state,
+ std::optional<CefRect>& dip_bounds);
+ void SetTitlebarHeight(const std::optional<float>& height);
+
+ // CefBrowserViewDelegate methods:
+ CefRefPtr<CefBrowserViewDelegate> GetDelegateForPopupBrowserView(
+ CefRefPtr<CefBrowserView> browser_view,
+ const CefBrowserSettings& settings,
+ CefRefPtr<CefClient> client,
+ bool is_devtools) override;
+ bool OnPopupBrowserViewCreated(CefRefPtr<CefBrowserView> browser_view,
+ CefRefPtr<CefBrowserView> popup_browser_view,
+ bool is_devtools) override;
+ ChromeToolbarType GetChromeToolbarType() override;
+
+ // CefButtonDelegate methods:
+ void OnButtonPressed(CefRefPtr<CefButton> button) override;
+
+ // CefMenuButtonDelegate methods:
+ void OnMenuButtonPressed(
+ CefRefPtr<CefMenuButton> menu_button,
+ const CefPoint& screen_point,
+ CefRefPtr<CefMenuButtonPressedLock> button_pressed_lock) override;
+
+ // CefMenuModelDelegate methods:
+ void ExecuteCommand(CefRefPtr<CefMenuModel> menu_model,
+ int command_id,
+ cef_event_flags_t event_flags) override;
+
+ // CefTextfieldDelegate methods:
+ bool OnKeyEvent(CefRefPtr<CefTextfield> textfield,
+ const CefKeyEvent& event) override;
+
+ // CefWindowDelegate methods:
+ void OnWindowCreated(CefRefPtr<CefWindow> window) override;
+ void OnWindowClosing(CefRefPtr<CefWindow> window) override;
+ void OnWindowDestroyed(CefRefPtr<CefWindow> window) override;
+ void OnWindowActivationChanged(CefRefPtr<CefWindow> window,
+ bool active) override;
+ void OnWindowBoundsChanged(CefRefPtr<CefWindow> window,
+ const CefRect& new_bounds) override;
+ CefRefPtr<CefWindow> GetParentWindow(CefRefPtr<CefWindow> window,
+ bool* is_menu,
+ bool* can_activate_menu) override;
+ CefRect GetInitialBounds(CefRefPtr<CefWindow> window) override;
+ cef_show_state_t GetInitialShowState(CefRefPtr<CefWindow> window) override;
+ bool IsFrameless(CefRefPtr<CefWindow> window) override;
+ bool WithStandardWindowButtons(CefRefPtr<CefWindow> window) override;
+ bool GetTitlebarHeight(CefRefPtr<CefWindow> window,
+ float* titlebar_height) override;
+ bool CanResize(CefRefPtr<CefWindow> window) override;
+ bool CanClose(CefRefPtr<CefWindow> window) override;
+ bool OnAccelerator(CefRefPtr<CefWindow> window, int command_id) override;
+ bool OnKeyEvent(CefRefPtr<CefWindow> window,
+ const CefKeyEvent& event) override;
+
+ // CefViewDelegate methods:
+ CefSize GetMinimumSize(CefRefPtr<CefView> view) override;
+ void OnFocus(CefRefPtr<CefView> view) override;
+ void OnBlur(CefRefPtr<CefView> view) override;
+ void OnWindowChanged(CefRefPtr<CefView> view, bool added) override;
+ void OnLayoutChanged(CefRefPtr<CefView> view,
+ const CefRect& new_bounds) override;
+
+ // ViewsMenuBar::Delegate methods:
+ void MenuBarExecuteCommand(CefRefPtr<CefMenuModel> menu_model,
+ int command_id,
+ cef_event_flags_t event_flags) override;
+
+ private:
+ // |delegate| is guaranteed to outlive this object.
+ // |browser_view| may be nullptr, in which case SetBrowserView() will be
+ // called.
+ ViewsWindow(Delegate* delegate, CefRefPtr<CefBrowserView> browser_view);
+
+ void SetBrowserView(CefRefPtr<CefBrowserView> browser_view);
+
+ // Create controls.
+ void CreateMenuModel();
+ CefRefPtr<CefLabelButton> CreateBrowseButton(const std::string& label,
+ int id);
+ CefRefPtr<CefMenuButton> CreateMenuButton();
+ CefRefPtr<CefView> CreateLocationBar();
+
+ // Add the BrowserView to the Window.
+ void AddBrowserView();
+
+ // Add other controls to the Window.
+ void AddControls();
+
+ // Add keyboard accelerators to the Window.
+ void AddAccelerators();
+
+ // Control whether the top menu butons are focusable.
+ void SetMenuFocusable(bool focusable);
+
+ // Enable or disable a view by |id|.
+ void EnableView(int id, bool enable);
+
+ // Show/hide top controls on the Window.
+ void ShowTopControls(bool show);
+
+ // Update extension controls on the Window.
+ void UpdateExtensionControls();
+
+ void OnExtensionIconsLoaded(const ExtensionSet& extensions,
+ const ImageCache::ImageSet& images);
+ void OnExtensionWindowClosed();
+
+ void NudgeWindow();
+
+ Delegate* delegate_; // Not owned by this object.
+ CefRefPtr<CefBrowserView> browser_view_;
+ bool frameless_;
+ bool with_controls_;
+ bool with_overlay_controls_;
+ bool with_standard_buttons_;
+ ChromeToolbarType chrome_toolbar_type_;
+ CefRefPtr<CefWindow> window_;
+
+ CefRefPtr<CefMenuModel> button_menu_model_;
+ CefRefPtr<ViewsMenuBar> top_menu_bar_;
+ CefRefPtr<CefView> top_toolbar_;
+ CefRefPtr<CefMenuButton> menu_button_;
+ CefRefPtr<CefView> location_bar_;
+ bool menu_has_focus_;
+ int last_focused_view_;
+ std::optional<CefRect> last_visible_bounds_;
+
+ CefSize minimum_window_size_;
+
+ CefRefPtr<ViewsOverlayControls> overlay_controls_;
+
+ std::optional<float> default_titlebar_height_;
+ std::optional<float> override_titlebar_height_;
+
+ // Structure representing an extension.
+ struct ExtensionInfo {
+ ExtensionInfo(CefRefPtr<CefExtension> extension, CefRefPtr<CefImage> image)
+ : extension_(extension), image_(image) {}
+
+ CefRefPtr<CefExtension> extension_;
+ CefRefPtr<CefImage> image_;
+ };
+ typedef std::vector<ExtensionInfo> ExtensionInfoSet;
+
+ ExtensionInfoSet extensions_;
+ CefRefPtr<CefPanel> extensions_panel_;
+ CefRefPtr<CefMenuButtonPressedLock> extension_button_pressed_lock_;
+
+ IMPLEMENT_REFCOUNTING(ViewsWindow);
+ DISALLOW_COPY_AND_ASSIGN(ViewsWindow);
+};
+
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_VIEWS_WINDOW_H_
diff --git a/tests/cefclient/browser/views_window_mac.mm b/tests/cefclient/browser/views_window_mac.mm
new file mode 100644
index 00000000..936a85c0
--- /dev/null
+++ b/tests/cefclient/browser/views_window_mac.mm
@@ -0,0 +1,24 @@
+// Copyright (c) 2023 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/views_window.h"
+
+#include <Cocoa/Cocoa.h>
+
+namespace client {
+
+void ViewsWindow::NudgeWindow() {
+ if (window_) {
+ auto view = CAST_CEF_WINDOW_HANDLE_TO_NSVIEW(window_->GetWindowHandle());
+ NSWindow* main_window = view.window;
+
+ auto theme_frame = main_window.contentView.superview;
+ // Nudge view frame a little to force an update.
+ NSSize size = theme_frame.frame.size;
+ [theme_frame setFrameSize:NSMakeSize(size.width - 1, size.height)];
+ [theme_frame setFrameSize:size];
+ }
+}
+
+}
diff --git a/tests/cefclient/browser/window_test.cc b/tests/cefclient/browser/window_test.cc
new file mode 100644
index 00000000..316f6147
--- /dev/null
+++ b/tests/cefclient/browser/window_test.cc
@@ -0,0 +1,134 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/window_test.h"
+
+#include <algorithm>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include "include/base/cef_callback.h"
+#include "include/wrapper/cef_stream_resource_handler.h"
+#include "tests/cefclient/browser/main_context.h"
+#include "tests/cefclient/browser/test_runner.h"
+#include "tests/cefclient/browser/window_test_runner.h"
+
+#include "tests/cefclient/browser/window_test_runner_views.h"
+
+#if defined(OS_WIN)
+#include "tests/cefclient/browser/window_test_runner_win.h"
+#elif defined(OS_LINUX)
+#include "tests/cefclient/browser/window_test_runner_gtk.h"
+#elif defined(OS_MAC)
+#include "tests/cefclient/browser/window_test_runner_mac.h"
+#endif
+
+namespace client {
+namespace window_test {
+
+namespace {
+
+const char kTestUrlPath[] = "/window";
+const char kMessagePositionName[] = "WindowTest.Position";
+const char kMessageMinimizeName[] = "WindowTest.Minimize";
+const char kMessageMaximizeName[] = "WindowTest.Maximize";
+const char kMessageRestoreName[] = "WindowTest.Restore";
+const char kMessageTitlebarHeightName[] = "WindowTest.TitlebarHeight";
+
+// Create the appropriate platform test runner object.
+std::unique_ptr<WindowTestRunner> CreateWindowTestRunner() {
+ if (MainContext::Get()->UseViews()) {
+ return std::make_unique<WindowTestRunnerViews>();
+ }
+
+#if defined(OS_WIN)
+ return std::make_unique<WindowTestRunnerWin>();
+#elif defined(OS_LINUX)
+ return std::make_unique<WindowTestRunnerGtk>();
+#elif defined(OS_MAC)
+ return std::make_unique<WindowTestRunnerMac>();
+#else
+#error "No implementation available for your platform."
+#endif
+}
+
+// Parse the comma-delimited list of integer values.
+std::vector<int> ParsePosition(const std::string& message_name) {
+ std::vector<int> vec;
+ const std::string& vals = message_name.substr(sizeof(kMessagePositionName));
+ std::stringstream ss(vals);
+ int i;
+ while (ss >> i) {
+ vec.push_back(i);
+ if (ss.peek() == ',') {
+ ss.ignore();
+ }
+ }
+
+ return vec;
+}
+
+std::optional<float> ParseHeight(const std::string& message) {
+ if (message.size() > sizeof(kMessageTitlebarHeightName)) {
+ const std::string& val = message.substr(sizeof(kMessageTitlebarHeightName));
+ return std::stof(val);
+ } else {
+ return std::nullopt;
+ }
+}
+
+// Handle messages in the browser process.
+class Handler : public CefMessageRouterBrowserSide::Handler {
+ public:
+ Handler() : runner_(CreateWindowTestRunner()) {}
+
+ // Called due to cefBroadcast execution in window.html.
+ virtual bool OnQuery(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int64 query_id,
+ const CefString& request,
+ bool persistent,
+ CefRefPtr<Callback> callback) override {
+ // Only handle messages from the test URL.
+ const std::string& url = frame->GetURL();
+ if (!test_runner::IsTestURL(url, kTestUrlPath)) {
+ return false;
+ }
+
+ const std::string& message_name = request;
+ if (message_name.find(kMessagePositionName) == 0) {
+ const auto vec = ParsePosition(message_name);
+ if (vec.size() == 4) {
+ runner_->SetPos(browser, vec[0], vec[1], vec[2], vec[3]);
+ }
+ } else if (message_name == kMessageMinimizeName) {
+ runner_->Minimize(browser);
+ } else if (message_name == kMessageMaximizeName) {
+ runner_->Maximize(browser);
+ } else if (message_name == kMessageRestoreName) {
+ runner_->Restore(browser);
+ } else if (message_name.find(kMessageTitlebarHeightName) == 0) {
+ const auto height = ParseHeight(message_name);
+ runner_->SetTitleBarHeight(browser, height);
+ } else {
+ NOTREACHED();
+ }
+
+ callback->Success("");
+ return true;
+ }
+
+ private:
+ std::unique_ptr<WindowTestRunner> runner_;
+};
+
+} // namespace
+
+void CreateMessageHandlers(test_runner::MessageHandlerSet& handlers) {
+ handlers.insert(new Handler());
+}
+
+} // namespace window_test
+} // namespace client
diff --git a/tests/cefclient/browser/window_test.h b/tests/cefclient/browser/window_test.h
new file mode 100644
index 00000000..2b99bbb8
--- /dev/null
+++ b/tests/cefclient/browser/window_test.h
@@ -0,0 +1,20 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_WINDOW_TEST_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_WINDOW_TEST_H_
+#pragma once
+
+#include "tests/cefclient/browser/test_runner.h"
+
+namespace client {
+namespace window_test {
+
+// Create message handlers. Called from test_runner.cc.
+void CreateMessageHandlers(test_runner::MessageHandlerSet& handlers);
+
+} // namespace window_test
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_WINDOW_TEST_H_
diff --git a/tests/cefclient/browser/window_test_runner.cc b/tests/cefclient/browser/window_test_runner.cc
new file mode 100644
index 00000000..c3edce6f
--- /dev/null
+++ b/tests/cefclient/browser/window_test_runner.cc
@@ -0,0 +1,45 @@
+// Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/window_test_runner.h"
+
+namespace client {
+namespace window_test {
+
+// static
+void WindowTestRunner::ModifyBounds(const CefRect& display, CefRect& window) {
+ window.x += display.x;
+ window.y += display.y;
+
+ if (window.x < display.x) {
+ window.x = display.x;
+ }
+ if (window.y < display.y) {
+ window.y = display.y;
+ }
+ if (window.width < 100) {
+ window.width = 100;
+ } else if (window.width >= display.width) {
+ window.width = display.width;
+ }
+ if (window.height < 100) {
+ window.height = 100;
+ } else if (window.height >= display.height) {
+ window.height = display.height;
+ }
+ if (window.x + window.width >= display.x + display.width) {
+ window.x = display.x + display.width - window.width;
+ }
+ if (window.y + window.height >= display.y + display.height) {
+ window.y = display.y + display.height - window.height;
+ }
+}
+
+void WindowTestRunner::SetTitleBarHeight(CefRefPtr<CefBrowser> browser,
+ const std::optional<float>& height) {
+ NOTIMPLEMENTED();
+}
+
+} // namespace window_test
+} // namespace client
diff --git a/tests/cefclient/browser/window_test_runner.h b/tests/cefclient/browser/window_test_runner.h
new file mode 100644
index 00000000..877fb59e
--- /dev/null
+++ b/tests/cefclient/browser/window_test_runner.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_WINDOW_TEST_RUNNER_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_WINDOW_TEST_RUNNER_H_
+#pragma once
+
+#include "include/cef_browser.h"
+
+#include <optional>
+
+namespace client {
+namespace window_test {
+
+// Implement this interface for different platforms. Methods will be called on
+// the browser process UI thread unless otherwise indicated.
+class WindowTestRunner {
+ public:
+ virtual ~WindowTestRunner() = default;
+
+ virtual void SetPos(CefRefPtr<CefBrowser> browser,
+ int x,
+ int y,
+ int width,
+ int height) = 0;
+ virtual void Minimize(CefRefPtr<CefBrowser> browser) = 0;
+ virtual void Maximize(CefRefPtr<CefBrowser> browser) = 0;
+ virtual void Restore(CefRefPtr<CefBrowser> browser) = 0;
+
+ // Fit |window| inside |display|. Coordinates are relative to the upper-left
+ // corner of the display.
+ static void ModifyBounds(const CefRect& display, CefRect& window);
+
+ virtual void SetTitleBarHeight(CefRefPtr<CefBrowser> browser,
+ const std::optional<float>& height);
+};
+
+} // namespace window_test
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_WINDOW_TEST_RUNNER_H_
diff --git a/tests/cefclient/browser/window_test_runner_gtk.cc b/tests/cefclient/browser/window_test_runner_gtk.cc
new file mode 100644
index 00000000..a5093f16
--- /dev/null
+++ b/tests/cefclient/browser/window_test_runner_gtk.cc
@@ -0,0 +1,142 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/window_test_runner_gtk.h"
+
+#include <gtk/gtk.h>
+
+#include "include/wrapper/cef_helpers.h"
+#include "tests/cefclient/browser/root_window.h"
+#include "tests/cefclient/browser/util_gtk.h"
+#include "tests/shared/browser/main_message_loop.h"
+
+namespace client {
+namespace window_test {
+
+namespace {
+
+GtkWindow* GetWindow(CefRefPtr<CefBrowser> browser) {
+ scoped_refptr<RootWindow> root_window =
+ RootWindow::GetForBrowser(browser->GetIdentifier());
+ if (root_window) {
+ GtkWindow* window = GTK_WINDOW(root_window->GetWindowHandle());
+ if (!window) {
+ LOG(ERROR) << "No GtkWindow for browser";
+ }
+ return window;
+ }
+ return nullptr;
+}
+
+bool IsMaximized(GtkWindow* window) {
+ GdkWindow* gdk_window = gtk_widget_get_window(GTK_WIDGET(window));
+ gint state = gdk_window_get_state(gdk_window);
+ return (state & GDK_WINDOW_STATE_MAXIMIZED) ? true : false;
+}
+
+void SetPosImpl(CefRefPtr<CefBrowser> browser,
+ int x,
+ int y,
+ int width,
+ int height) {
+ REQUIRE_MAIN_THREAD();
+ ScopedGdkThreadsEnter scoped_gdk_threads;
+
+ GtkWindow* window = GetWindow(browser);
+ if (!window) {
+ return;
+ }
+ GdkWindow* gdk_window = gtk_widget_get_window(GTK_WIDGET(window));
+
+ // Make sure the window isn't minimized or maximized.
+ if (IsMaximized(window)) {
+ gtk_window_unmaximize(window);
+ } else {
+ gtk_window_present(window);
+ }
+
+ // Retrieve information about the display that contains the window.
+ GdkScreen* screen = gdk_screen_get_default();
+ gint monitor = gdk_screen_get_monitor_at_window(screen, gdk_window);
+ GdkRectangle rect;
+ gdk_screen_get_monitor_geometry(screen, monitor, &rect);
+
+ // Make sure the window is inside the display.
+ CefRect display_rect(rect.x, rect.y, rect.width, rect.height);
+ CefRect window_rect(x, y, width, height);
+ WindowTestRunner::ModifyBounds(display_rect, window_rect);
+
+ gdk_window_move_resize(gdk_window, window_rect.x, window_rect.y,
+ window_rect.width, window_rect.height);
+}
+
+void MinimizeImpl(CefRefPtr<CefBrowser> browser) {
+ REQUIRE_MAIN_THREAD();
+ ScopedGdkThreadsEnter scoped_gdk_threads;
+
+ GtkWindow* window = GetWindow(browser);
+ if (!window) {
+ return;
+ }
+
+ // Unmaximize the window before minimizing so restore behaves correctly.
+ if (IsMaximized(window)) {
+ gtk_window_unmaximize(window);
+ }
+
+ gtk_window_iconify(window);
+}
+
+void MaximizeImpl(CefRefPtr<CefBrowser> browser) {
+ REQUIRE_MAIN_THREAD();
+ ScopedGdkThreadsEnter scoped_gdk_threads;
+
+ GtkWindow* window = GetWindow(browser);
+ if (!window) {
+ return;
+ }
+ gtk_window_maximize(window);
+}
+
+void RestoreImpl(CefRefPtr<CefBrowser> browser) {
+ REQUIRE_MAIN_THREAD();
+ ScopedGdkThreadsEnter scoped_gdk_threads;
+
+ GtkWindow* window = GetWindow(browser);
+ if (!window) {
+ return;
+ }
+ if (IsMaximized(window)) {
+ gtk_window_unmaximize(window);
+ } else {
+ gtk_window_present(window);
+ }
+}
+
+} // namespace
+
+WindowTestRunnerGtk::WindowTestRunnerGtk() {}
+
+void WindowTestRunnerGtk::SetPos(CefRefPtr<CefBrowser> browser,
+ int x,
+ int y,
+ int width,
+ int height) {
+ MAIN_POST_CLOSURE(base::BindOnce(SetPosImpl, browser, x, y, width, height));
+}
+
+void WindowTestRunnerGtk::Minimize(CefRefPtr<CefBrowser> browser) {
+ MAIN_POST_CLOSURE(base::BindOnce(MinimizeImpl, browser));
+}
+
+void WindowTestRunnerGtk::Maximize(CefRefPtr<CefBrowser> browser) {
+ MAIN_POST_CLOSURE(base::BindOnce(MaximizeImpl, browser));
+}
+
+void WindowTestRunnerGtk::Restore(CefRefPtr<CefBrowser> browser) {
+ MAIN_POST_CLOSURE(base::BindOnce(RestoreImpl, browser));
+}
+
+} // namespace window_test
+} // namespace client
diff --git a/tests/cefclient/browser/window_test_runner_gtk.h b/tests/cefclient/browser/window_test_runner_gtk.h
new file mode 100644
index 00000000..c699039c
--- /dev/null
+++ b/tests/cefclient/browser/window_test_runner_gtk.h
@@ -0,0 +1,32 @@
+// Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_WINDOW_TEST_RUNNER_GTK_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_WINDOW_TEST_RUNNER_GTK_H_
+#pragma once
+
+#include "tests/cefclient/browser/window_test_runner.h"
+
+namespace client {
+namespace window_test {
+
+// GTK platform implementation.
+class WindowTestRunnerGtk : public WindowTestRunner {
+ public:
+ WindowTestRunnerGtk();
+
+ void SetPos(CefRefPtr<CefBrowser> browser,
+ int x,
+ int y,
+ int width,
+ int height) override;
+ void Minimize(CefRefPtr<CefBrowser> browser) override;
+ void Maximize(CefRefPtr<CefBrowser> browser) override;
+ void Restore(CefRefPtr<CefBrowser> browser) override;
+};
+
+} // namespace window_test
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_WINDOW_TEST_RUNNER_GTK_H_
diff --git a/tests/cefclient/browser/window_test_runner_mac.h b/tests/cefclient/browser/window_test_runner_mac.h
new file mode 100644
index 00000000..aebae0e3
--- /dev/null
+++ b/tests/cefclient/browser/window_test_runner_mac.h
@@ -0,0 +1,32 @@
+// Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_WINDOW_TEST_RUNNER_MAC_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_WINDOW_TEST_RUNNER_MAC_H_
+#pragma once
+
+#include "tests/cefclient/browser/window_test_runner.h"
+
+namespace client {
+namespace window_test {
+
+// Mac OS X platform implementation.
+class WindowTestRunnerMac : public WindowTestRunner {
+ public:
+ WindowTestRunnerMac();
+
+ void SetPos(CefRefPtr<CefBrowser> browser,
+ int x,
+ int y,
+ int width,
+ int height) override;
+ void Minimize(CefRefPtr<CefBrowser> browser) override;
+ void Maximize(CefRefPtr<CefBrowser> browser) override;
+ void Restore(CefRefPtr<CefBrowser> browser) override;
+};
+
+} // namespace window_test
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_WINDOW_TEST_RUNNER_MAC_H_
diff --git a/tests/cefclient/browser/window_test_runner_mac.mm b/tests/cefclient/browser/window_test_runner_mac.mm
new file mode 100644
index 00000000..1f181446
--- /dev/null
+++ b/tests/cefclient/browser/window_test_runner_mac.mm
@@ -0,0 +1,95 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/window_test_runner_mac.h"
+
+#import <Cocoa/Cocoa.h>
+
+#include "include/wrapper/cef_helpers.h"
+#include "tests/shared/browser/main_message_loop.h"
+
+namespace client {
+namespace window_test {
+
+namespace {
+
+NSWindow* GetWindow(CefRefPtr<CefBrowser> browser) {
+ NSView* view =
+ CAST_CEF_WINDOW_HANDLE_TO_NSVIEW(browser->GetHost()->GetWindowHandle());
+ return [view window];
+}
+
+} // namespace
+
+WindowTestRunnerMac::WindowTestRunnerMac() {}
+
+void WindowTestRunnerMac::SetPos(CefRefPtr<CefBrowser> browser,
+ int x,
+ int y,
+ int width,
+ int height) {
+ CEF_REQUIRE_UI_THREAD();
+ REQUIRE_MAIN_THREAD();
+
+ NSWindow* window = GetWindow(browser);
+
+ // Make sure the window isn't minimized or maximized.
+ if ([window isMiniaturized]) {
+ [window deminiaturize:nil];
+ } else if ([window isZoomed]) {
+ [window performZoom:nil];
+ }
+
+ // Retrieve information for the display that contains the window.
+ NSScreen* screen = [window screen];
+ if (screen == nil) {
+ screen = [NSScreen mainScreen];
+ }
+ NSRect frame = [screen frame];
+ NSRect visibleFrame = [screen visibleFrame];
+
+ // Make sure the window is inside the display.
+ CefRect display_rect(
+ visibleFrame.origin.x,
+ frame.size.height - visibleFrame.size.height - visibleFrame.origin.y,
+ visibleFrame.size.width, visibleFrame.size.height);
+ CefRect window_rect(x, y, width, height);
+ ModifyBounds(display_rect, window_rect);
+
+ NSRect newRect;
+ newRect.origin.x = window_rect.x;
+ newRect.origin.y = frame.size.height - window_rect.height - window_rect.y;
+ newRect.size.width = window_rect.width;
+ newRect.size.height = window_rect.height;
+ [window setFrame:newRect display:YES];
+}
+
+void WindowTestRunnerMac::Minimize(CefRefPtr<CefBrowser> browser) {
+ CEF_REQUIRE_UI_THREAD();
+ REQUIRE_MAIN_THREAD();
+
+ [GetWindow(browser) performMiniaturize:nil];
+}
+
+void WindowTestRunnerMac::Maximize(CefRefPtr<CefBrowser> browser) {
+ CEF_REQUIRE_UI_THREAD();
+ REQUIRE_MAIN_THREAD();
+
+ [GetWindow(browser) performZoom:nil];
+}
+
+void WindowTestRunnerMac::Restore(CefRefPtr<CefBrowser> browser) {
+ CEF_REQUIRE_UI_THREAD();
+ REQUIRE_MAIN_THREAD();
+
+ NSWindow* window = GetWindow(browser);
+ if ([window isMiniaturized]) {
+ [window deminiaturize:nil];
+ } else if ([window isZoomed]) {
+ [window performZoom:nil];
+ }
+}
+
+} // namespace window_test
+} // namespace client
diff --git a/tests/cefclient/browser/window_test_runner_views.cc b/tests/cefclient/browser/window_test_runner_views.cc
new file mode 100644
index 00000000..9efda0ce
--- /dev/null
+++ b/tests/cefclient/browser/window_test_runner_views.cc
@@ -0,0 +1,79 @@
+// Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/window_test_runner_views.h"
+
+#include "include/views/cef_browser_view.h"
+#include "include/views/cef_display.h"
+#include "include/views/cef_window.h"
+#include "include/wrapper/cef_helpers.h"
+
+#include "tests/cefclient/browser/root_window_views.h"
+#include "tests/cefclient/browser/views_window.h"
+
+namespace client {
+namespace window_test {
+
+namespace {
+
+CefRefPtr<CefWindow> GetWindow(const CefRefPtr<CefBrowser>& browser) {
+ CEF_REQUIRE_UI_THREAD();
+ DCHECK(browser->GetHost()->HasView());
+
+ CefRefPtr<CefBrowserView> browser_view =
+ CefBrowserView::GetForBrowser(browser);
+ DCHECK(browser_view.get());
+
+ CefRefPtr<CefWindow> window = browser_view->GetWindow();
+ DCHECK(window.get());
+ return window;
+}
+
+void SetTitlebarHeight(const CefRefPtr<CefBrowser>& browser,
+ const std::optional<float>& height) {
+ CEF_REQUIRE_UI_THREAD();
+ auto root_window = RootWindow::GetForBrowser(browser->GetIdentifier());
+ DCHECK(root_window.get());
+
+ auto root_window_views = static_cast<RootWindowViews*>(root_window.get());
+ root_window_views->SetTitlebarHeight(height);
+}
+
+} // namespace
+
+WindowTestRunnerViews::WindowTestRunnerViews() {}
+
+void WindowTestRunnerViews::SetPos(CefRefPtr<CefBrowser> browser,
+ int x,
+ int y,
+ int width,
+ int height) {
+ CefRefPtr<CefWindow> window = GetWindow(browser);
+
+ CefRect window_bounds(x, y, width, height);
+ ModifyBounds(window->GetDisplay()->GetWorkArea(), window_bounds);
+
+ window->SetBounds(window_bounds);
+}
+
+void WindowTestRunnerViews::Minimize(CefRefPtr<CefBrowser> browser) {
+ GetWindow(browser)->Minimize();
+}
+
+void WindowTestRunnerViews::Maximize(CefRefPtr<CefBrowser> browser) {
+ GetWindow(browser)->Maximize();
+}
+
+void WindowTestRunnerViews::Restore(CefRefPtr<CefBrowser> browser) {
+ GetWindow(browser)->Restore();
+}
+
+void WindowTestRunnerViews::SetTitleBarHeight(
+ CefRefPtr<CefBrowser> browser,
+ const std::optional<float>& height) {
+ SetTitlebarHeight(browser, height);
+}
+
+} // namespace window_test
+} // namespace client
diff --git a/tests/cefclient/browser/window_test_runner_views.h b/tests/cefclient/browser/window_test_runner_views.h
new file mode 100644
index 00000000..851e3742
--- /dev/null
+++ b/tests/cefclient/browser/window_test_runner_views.h
@@ -0,0 +1,34 @@
+// Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_WINDOW_TEST_RUNNER_VIEWS_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_WINDOW_TEST_RUNNER_VIEWS_H_
+#pragma once
+
+#include "tests/cefclient/browser/window_test_runner.h"
+
+namespace client {
+namespace window_test {
+
+// Views platform implementation.
+class WindowTestRunnerViews : public WindowTestRunner {
+ public:
+ WindowTestRunnerViews();
+
+ void SetPos(CefRefPtr<CefBrowser> browser,
+ int x,
+ int y,
+ int width,
+ int height) override;
+ void Minimize(CefRefPtr<CefBrowser> browser) override;
+ void Maximize(CefRefPtr<CefBrowser> browser) override;
+ void Restore(CefRefPtr<CefBrowser> browser) override;
+ void SetTitleBarHeight(CefRefPtr<CefBrowser> browser,
+ const std::optional<float>& height) override;
+};
+
+} // namespace window_test
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_WINDOW_TEST_RUNNER_VIEWS_H_
diff --git a/tests/cefclient/browser/window_test_runner_win.cc b/tests/cefclient/browser/window_test_runner_win.cc
new file mode 100644
index 00000000..d94e8980
--- /dev/null
+++ b/tests/cefclient/browser/window_test_runner_win.cc
@@ -0,0 +1,145 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/browser/window_test_runner_win.h"
+
+#include "tests/shared/browser/main_message_loop.h"
+
+namespace client {
+namespace window_test {
+
+namespace {
+
+HWND GetRootHwnd(CefRefPtr<CefBrowser> browser) {
+ return ::GetAncestor(browser->GetHost()->GetWindowHandle(), GA_ROOT);
+}
+
+// Toggles the current display state.
+void Toggle(HWND root_hwnd, UINT nCmdShow) {
+ // Retrieve current window placement information.
+ WINDOWPLACEMENT placement;
+ ::GetWindowPlacement(root_hwnd, &placement);
+
+ if (placement.showCmd == nCmdShow) {
+ ::ShowWindow(root_hwnd, SW_RESTORE);
+ } else {
+ ::ShowWindow(root_hwnd, nCmdShow);
+ }
+}
+
+void SetPosImpl(CefRefPtr<CefBrowser> browser,
+ int x,
+ int y,
+ int width,
+ int height) {
+ HWND root_hwnd = GetRootHwnd(browser);
+ if (!root_hwnd) {
+ return;
+ }
+
+ // Retrieve current window placement information.
+ WINDOWPLACEMENT placement;
+ ::GetWindowPlacement(root_hwnd, &placement);
+
+ // Retrieve information about the display that contains the window.
+ HMONITOR monitor =
+ MonitorFromRect(&placement.rcNormalPosition, MONITOR_DEFAULTTONEAREST);
+ MONITORINFO info;
+ info.cbSize = sizeof(info);
+ GetMonitorInfo(monitor, &info);
+
+ // Make sure the window is inside the display.
+ CefRect display_rect(info.rcWork.left, info.rcWork.top,
+ info.rcWork.right - info.rcWork.left,
+ info.rcWork.bottom - info.rcWork.top);
+ CefRect window_rect(x, y, width, height);
+ WindowTestRunner::ModifyBounds(display_rect, window_rect);
+
+ if (placement.showCmd == SW_SHOWMINIMIZED ||
+ placement.showCmd == SW_SHOWMAXIMIZED) {
+ // The window is currently minimized or maximized. Restore it to the desired
+ // position.
+ placement.rcNormalPosition.left = window_rect.x;
+ placement.rcNormalPosition.right = window_rect.x + window_rect.width;
+ placement.rcNormalPosition.top = window_rect.y;
+ placement.rcNormalPosition.bottom = window_rect.y + window_rect.height;
+ ::SetWindowPlacement(root_hwnd, &placement);
+ ::ShowWindow(root_hwnd, SW_RESTORE);
+ } else {
+ // Set the window position.
+ ::SetWindowPos(root_hwnd, nullptr, window_rect.x, window_rect.y,
+ window_rect.width, window_rect.height, SWP_NOZORDER);
+ }
+}
+
+void MinimizeImpl(CefRefPtr<CefBrowser> browser) {
+ HWND root_hwnd = GetRootHwnd(browser);
+ if (!root_hwnd) {
+ return;
+ }
+ Toggle(root_hwnd, SW_MINIMIZE);
+}
+
+void MaximizeImpl(CefRefPtr<CefBrowser> browser) {
+ HWND root_hwnd = GetRootHwnd(browser);
+ if (!root_hwnd) {
+ return;
+ }
+ Toggle(root_hwnd, SW_MAXIMIZE);
+}
+
+void RestoreImpl(CefRefPtr<CefBrowser> browser) {
+ HWND root_hwnd = GetRootHwnd(browser);
+ if (!root_hwnd) {
+ return;
+ }
+ ::ShowWindow(root_hwnd, SW_RESTORE);
+}
+
+} // namespace
+
+WindowTestRunnerWin::WindowTestRunnerWin() {}
+
+void WindowTestRunnerWin::SetPos(CefRefPtr<CefBrowser> browser,
+ int x,
+ int y,
+ int width,
+ int height) {
+ if (CURRENTLY_ON_MAIN_THREAD()) {
+ SetPosImpl(browser, x, y, width, height);
+ } else {
+ // Execute on the main application thread.
+ MAIN_POST_CLOSURE(base::BindOnce(SetPosImpl, browser, x, y, width, height));
+ }
+}
+
+void WindowTestRunnerWin::Minimize(CefRefPtr<CefBrowser> browser) {
+ if (CURRENTLY_ON_MAIN_THREAD()) {
+ MinimizeImpl(browser);
+ } else {
+ // Execute on the main application thread.
+ MAIN_POST_CLOSURE(base::BindOnce(MinimizeImpl, browser));
+ }
+}
+
+void WindowTestRunnerWin::Maximize(CefRefPtr<CefBrowser> browser) {
+ if (CURRENTLY_ON_MAIN_THREAD()) {
+ MaximizeImpl(browser);
+ } else {
+ // Execute on the main application thread.
+ MAIN_POST_CLOSURE(base::BindOnce(MaximizeImpl, browser));
+ }
+}
+
+void WindowTestRunnerWin::Restore(CefRefPtr<CefBrowser> browser) {
+ if (CURRENTLY_ON_MAIN_THREAD()) {
+ RestoreImpl(browser);
+ } else {
+ // Execute on the main application thread.
+ MAIN_POST_CLOSURE(base::BindOnce(RestoreImpl, browser));
+ }
+}
+
+} // namespace window_test
+} // namespace client
diff --git a/tests/cefclient/browser/window_test_runner_win.h b/tests/cefclient/browser/window_test_runner_win.h
new file mode 100644
index 00000000..d6e38ef6
--- /dev/null
+++ b/tests/cefclient/browser/window_test_runner_win.h
@@ -0,0 +1,33 @@
+// Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_WINDOW_TEST_RUNNER_WIN_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_WINDOW_TEST_RUNNER_WIN_H_
+#pragma once
+
+#include "tests/cefclient/browser/window_test_runner.h"
+
+namespace client {
+namespace window_test {
+
+// Windows platform implementation. Methods are safe to call on any browser
+// process thread.
+class WindowTestRunnerWin : public WindowTestRunner {
+ public:
+ WindowTestRunnerWin();
+
+ void SetPos(CefRefPtr<CefBrowser> browser,
+ int x,
+ int y,
+ int width,
+ int height) override;
+ void Minimize(CefRefPtr<CefBrowser> browser) override;
+ void Maximize(CefRefPtr<CefBrowser> browser) override;
+ void Restore(CefRefPtr<CefBrowser> browser) override;
+};
+
+} // namespace window_test
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_WINDOW_TEST_RUNNER_WIN_H_
diff --git a/tests/cefclient/cefclient_gtk.cc b/tests/cefclient/cefclient_gtk.cc
new file mode 100644
index 00000000..f0237a5d
--- /dev/null
+++ b/tests/cefclient/cefclient_gtk.cc
@@ -0,0 +1,170 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include <gtk/gtk.h>
+
+#include <X11/Xlib.h>
+#undef Success // Definition conflicts with cef_message_router.h
+#undef RootWindow // Definition conflicts with root_window.h
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <memory>
+#include <string>
+
+#include "include/base/cef_logging.h"
+#include "include/cef_app.h"
+#include "include/cef_command_line.h"
+#include "include/wrapper/cef_helpers.h"
+#include "tests/cefclient/browser/main_context_impl.h"
+#include "tests/cefclient/browser/main_message_loop_multithreaded_gtk.h"
+#include "tests/cefclient/browser/test_runner.h"
+#include "tests/shared/browser/client_app_browser.h"
+#include "tests/shared/browser/main_message_loop_external_pump.h"
+#include "tests/shared/browser/main_message_loop_std.h"
+#include "tests/shared/common/client_app_other.h"
+#include "tests/shared/common/client_switches.h"
+#include "tests/shared/renderer/client_app_renderer.h"
+
+namespace client {
+namespace {
+
+int XErrorHandlerImpl(Display* display, XErrorEvent* event) {
+ LOG(WARNING) << "X error received: "
+ << "type " << event->type << ", "
+ << "serial " << event->serial << ", "
+ << "error_code " << static_cast<int>(event->error_code) << ", "
+ << "request_code " << static_cast<int>(event->request_code)
+ << ", "
+ << "minor_code " << static_cast<int>(event->minor_code);
+ return 0;
+}
+
+int XIOErrorHandlerImpl(Display* display) {
+ return 0;
+}
+
+void TerminationSignalHandler(int signatl) {
+ LOG(ERROR) << "Received termination signal: " << signatl;
+ MainContext::Get()->GetRootWindowManager()->CloseAllWindows(true);
+}
+
+int RunMain(int argc, char* argv[]) {
+ // Create a copy of |argv| on Linux because Chromium mangles the value
+ // internally (see issue #620).
+ CefScopedArgArray scoped_arg_array(argc, argv);
+ char** argv_copy = scoped_arg_array.array();
+
+ CefMainArgs main_args(argc, argv);
+
+ // Parse command-line arguments.
+ CefRefPtr<CefCommandLine> command_line = CefCommandLine::CreateCommandLine();
+ command_line->InitFromArgv(argc, argv);
+
+ // Create a ClientApp of the correct type.
+ CefRefPtr<CefApp> app;
+ ClientApp::ProcessType process_type = ClientApp::GetProcessType(command_line);
+ if (process_type == ClientApp::BrowserProcess) {
+ app = new ClientAppBrowser();
+ } else if (process_type == ClientApp::RendererProcess ||
+ process_type == ClientApp::ZygoteProcess) {
+ // On Linux the zygote process is used to spawn other process types. Since
+ // we don't know what type of process it will be give it the renderer
+ // client.
+ app = new ClientAppRenderer();
+ } else if (process_type == ClientApp::OtherProcess) {
+ app = new ClientAppOther();
+ }
+
+ // Execute the secondary process, if any.
+ int exit_code = CefExecuteProcess(main_args, app, nullptr);
+ if (exit_code >= 0) {
+ return exit_code;
+ }
+
+ // Create the main context object.
+ auto context = std::make_unique<MainContextImpl>(command_line, true);
+
+ CefSettings settings;
+
+// When generating projects with CMake the CEF_USE_SANDBOX value will be defined
+// automatically. Pass -DUSE_SANDBOX=OFF to the CMake command-line to disable
+// use of the sandbox.
+#if !defined(CEF_USE_SANDBOX)
+ settings.no_sandbox = true;
+#endif
+
+ // Populate the settings based on command line arguments.
+ context->PopulateSettings(&settings);
+
+ if (settings.windowless_rendering_enabled) {
+ // Force the app to use OpenGL <= 3.1 when off-screen rendering is enabled.
+ // TODO(cefclient): Rewrite OSRRenderer to use shaders instead of the
+ // fixed-function pipeline which was removed in OpenGL 3.2 (back in 2009).
+ setenv("MESA_GL_VERSION_OVERRIDE", "3.1", /*overwrite=*/0);
+ }
+
+ // Create the main message loop object.
+ std::unique_ptr<MainMessageLoop> message_loop;
+ if (settings.multi_threaded_message_loop) {
+ message_loop.reset(new MainMessageLoopMultithreadedGtk);
+ } else if (settings.external_message_pump) {
+ message_loop = MainMessageLoopExternalPump::Create();
+ } else {
+ message_loop.reset(new MainMessageLoopStd);
+ }
+
+ // Initialize CEF.
+ context->Initialize(main_args, settings, app, nullptr);
+
+ // Force Gtk to use Xwayland (in case a Wayland compositor is being used).
+ gdk_set_allowed_backends("x11");
+
+ // The Chromium sandbox requires that there only be a single thread during
+ // initialization. Therefore initialize GTK after CEF.
+ gtk_init(&argc, &argv_copy);
+
+ // Install xlib error handlers so that the application won't be terminated
+ // on non-fatal errors. Must be done after initializing GTK.
+ XSetErrorHandler(XErrorHandlerImpl);
+ XSetIOErrorHandler(XIOErrorHandlerImpl);
+
+ // Install a signal handler so we clean up after ourselves.
+ signal(SIGINT, TerminationSignalHandler);
+ signal(SIGTERM, TerminationSignalHandler);
+
+ // Register scheme handlers.
+ test_runner::RegisterSchemeHandlers();
+
+ auto window_config = std::make_unique<RootWindowConfig>();
+ window_config->always_on_top =
+ command_line->HasSwitch(switches::kAlwaysOnTop);
+ window_config->with_controls =
+ !command_line->HasSwitch(switches::kHideControls);
+ window_config->with_osr =
+ settings.windowless_rendering_enabled ? true : false;
+
+ // Create the first window.
+ context->GetRootWindowManager()->CreateRootWindow(std::move(window_config));
+
+ // Run the message loop. This will block until Quit() is called.
+ int result = message_loop->Run();
+
+ // Shut down CEF.
+ context->Shutdown();
+
+ // Release objects in reverse order of creation.
+ message_loop.reset();
+ context.reset();
+
+ return result;
+}
+
+} // namespace
+} // namespace client
+
+// Program entry point function.
+int main(int argc, char* argv[]) {
+ return client::RunMain(argc, argv);
+}
diff --git a/tests/cefclient/cefclient_mac.mm b/tests/cefclient/cefclient_mac.mm
new file mode 100644
index 00000000..b963ec2b
--- /dev/null
+++ b/tests/cefclient/cefclient_mac.mm
@@ -0,0 +1,445 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors.
+// Portions copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <Cocoa/Cocoa.h>
+#include "include/cef_app.h"
+#import "include/cef_application_mac.h"
+#import "include/wrapper/cef_library_loader.h"
+#include "tests/cefclient/browser/main_context_impl.h"
+#include "tests/cefclient/browser/resource.h"
+#include "tests/cefclient/browser/root_window.h"
+#include "tests/cefclient/browser/test_runner.h"
+#include "tests/shared/browser/client_app_browser.h"
+#include "tests/shared/browser/main_message_loop_external_pump.h"
+#include "tests/shared/browser/main_message_loop_std.h"
+#include "tests/shared/common/client_switches.h"
+
+namespace {
+
+// Returns the top menu bar with the specified |tag|.
+NSMenuItem* GetMenuBarMenuWithTag(NSInteger tag) {
+ NSMenu* main_menu = [[NSApplication sharedApplication] mainMenu];
+ NSInteger found_index = [main_menu indexOfItemWithTag:tag];
+ if (found_index >= 0) {
+ return [main_menu itemAtIndex:found_index];
+ }
+ return nil;
+}
+
+// Returns the item in |menu| that has the specified |action_selector|.
+NSMenuItem* GetMenuItemWithAction(NSMenu* menu, SEL action_selector) {
+ for (NSInteger i = 0; i < menu.numberOfItems; ++i) {
+ NSMenuItem* item = [menu itemAtIndex:i];
+ if (item.action == action_selector) {
+ return item;
+ }
+ }
+ return nil;
+}
+
+} // namespace
+
+// Receives notifications from the application. Will delete itself when done.
+@interface ClientAppDelegate : NSObject <NSApplicationDelegate> {
+ @private
+ bool with_controls_;
+ bool with_osr_;
+}
+
+- (id)initWithControls:(bool)with_controls andOsr:(bool)with_osr;
+- (void)createApplication:(id)object;
+- (void)tryToTerminateApplication:(NSApplication*)app;
+- (void)testsItemSelected:(int)command_id;
+- (IBAction)menuTestsGetText:(id)sender;
+- (IBAction)menuTestsGetSource:(id)sender;
+- (IBAction)menuTestsWindowNew:(id)sender;
+- (IBAction)menuTestsWindowPopup:(id)sender;
+- (IBAction)menuTestsRequest:(id)sender;
+- (IBAction)menuTestsZoomIn:(id)sender;
+- (IBAction)menuTestsZoomOut:(id)sender;
+- (IBAction)menuTestsZoomReset:(id)sender;
+- (IBAction)menuTestsSetFPS:(id)sender;
+- (IBAction)menuTestsSetScaleFactor:(id)sender;
+- (IBAction)menuTestsTracingBegin:(id)sender;
+- (IBAction)menuTestsTracingEnd:(id)sender;
+- (IBAction)menuTestsPrint:(id)sender;
+- (IBAction)menuTestsPrintToPdf:(id)sender;
+- (IBAction)menuTestsMuteAudio:(id)sender;
+- (IBAction)menuTestsUnmuteAudio:(id)sender;
+- (IBAction)menuTestsOtherTests:(id)sender;
+- (void)enableAccessibility:(bool)bEnable;
+@end
+
+// Provide the CefAppProtocol implementation required by CEF.
+@interface ClientApplication : NSApplication <CefAppProtocol> {
+ @private
+ BOOL handlingSendEvent_;
+}
+@end
+
+@implementation ClientApplication
+
+- (BOOL)isHandlingSendEvent {
+ return handlingSendEvent_;
+}
+
+- (void)setHandlingSendEvent:(BOOL)handlingSendEvent {
+ handlingSendEvent_ = handlingSendEvent;
+}
+
+- (void)sendEvent:(NSEvent*)event {
+ CefScopedSendingEvent sendingEventScoper;
+ [super sendEvent:event];
+}
+
+// |-terminate:| is the entry point for orderly "quit" operations in Cocoa. This
+// includes the application menu's quit menu item and keyboard equivalent, the
+// application's dock icon menu's quit menu item, "quit" (not "force quit") in
+// the Activity Monitor, and quits triggered by user logout and system restart
+// and shutdown.
+//
+// The default |-terminate:| implementation ends the process by calling exit(),
+// and thus never leaves the main run loop. This is unsuitable for Chromium
+// since Chromium depends on leaving the main run loop to perform an orderly
+// shutdown. We support the normal |-terminate:| interface by overriding the
+// default implementation. Our implementation, which is very specific to the
+// needs of Chromium, works by asking the application delegate to terminate
+// using its |-tryToTerminateApplication:| method.
+//
+// |-tryToTerminateApplication:| differs from the standard
+// |-applicationShouldTerminate:| in that no special event loop is run in the
+// case that immediate termination is not possible (e.g., if dialog boxes
+// allowing the user to cancel have to be shown). Instead, this method tries to
+// close all browsers by calling CloseBrowser(false) via
+// ClientHandler::CloseAllBrowsers. Calling CloseBrowser will result in a call
+// to ClientHandler::DoClose and execution of |-performClose:| on the NSWindow.
+// DoClose sets a flag that is used to differentiate between new close events
+// (e.g., user clicked the window close button) and in-progress close events
+// (e.g., user approved the close window dialog). The NSWindowDelegate
+// |-windowShouldClose:| method checks this flag and either calls
+// CloseBrowser(false) in the case of a new close event or destructs the
+// NSWindow in the case of an in-progress close event.
+// ClientHandler::OnBeforeClose will be called after the CEF NSView hosted in
+// the NSWindow is dealloc'ed.
+//
+// After the final browser window has closed ClientHandler::OnBeforeClose will
+// begin actual tear-down of the application by calling CefQuitMessageLoop.
+// This ends the NSApplication event loop and execution then returns to the
+// main() function for cleanup before application termination.
+//
+// The standard |-applicationShouldTerminate:| is not supported, and code paths
+// leading to it must be redirected.
+- (void)terminate:(id)sender {
+ ClientAppDelegate* delegate = static_cast<ClientAppDelegate*>(
+ [[NSApplication sharedApplication] delegate]);
+ [delegate tryToTerminateApplication:self];
+ // Return, don't exit. The application is responsible for exiting on its own.
+}
+
+// Detect dynamically if VoiceOver is running. Like Chromium, rely upon the
+// undocumented accessibility attribute @"AXEnhancedUserInterface" which is set
+// when VoiceOver is launched and unset when VoiceOver is closed.
+- (void)accessibilitySetValue:(id)value forAttribute:(NSString*)attribute {
+ if ([attribute isEqualToString:@"AXEnhancedUserInterface"]) {
+ ClientAppDelegate* delegate = static_cast<ClientAppDelegate*>(
+ [[NSApplication sharedApplication] delegate]);
+ [delegate enableAccessibility:([value intValue] == 1)];
+ }
+ return [super accessibilitySetValue:value forAttribute:attribute];
+}
+@end
+
+@implementation ClientAppDelegate
+
+- (id)initWithControls:(bool)with_controls andOsr:(bool)with_osr {
+ if (self = [super init]) {
+ with_controls_ = with_controls;
+ with_osr_ = with_osr;
+ }
+ return self;
+}
+
+// Create the application on the UI thread.
+- (void)createApplication:(id)object {
+ NSApplication* application = [NSApplication sharedApplication];
+
+ // The top menu is configured using Interface Builder (IB). To modify the menu
+ // start by loading MainMenu.xib in IB.
+ //
+ // To associate MainMenu.xib with ClientAppDelegate:
+ // 1. Select "File's Owner" from the "Placeholders" section in the left side
+ // pane.
+ // 2. Load the "Identity inspector" tab in the top-right side pane.
+ // 3. In the "Custom Class" section set the "Class" value to
+ // "ClientAppDelegate".
+ // 4. Pass an instance of ClientAppDelegate as the |owner| parameter to
+ // loadNibNamed:.
+ //
+ // To create a new top menu:
+ // 1. Load the "Object library" tab in the bottom-right side pane.
+ // 2. Drag a "Submenu Menu Item" widget from the Object library to the desired
+ // location in the menu bar shown in the center pane.
+ // 3. Select the newly created top menu by left clicking on it.
+ // 4. Load the "Attributes inspector" tab in the top-right side pane.
+ // 5. Under the "Menu Item" section set the "Tag" value to a unique integer.
+ // This is necessary for the GetMenuBarMenuWithTag function to work
+ // properly.
+ //
+ // To create a new menu item in a top menu:
+ // 1. Add a new receiver method in ClientAppDelegate (e.g. menuTestsDoStuff:).
+ // 2. Load the "Object library" tab in the bottom-right side pane.
+ // 3. Drag a "Menu Item" widget from the Object library to the desired
+ // location in the menu bar shown in the center pane.
+ // 4. Double-click on the new menu item to set the label.
+ // 5. Right click on the new menu item to show the "Get Source" dialog.
+ // 6. In the "Sent Actions" section drag from the circle icon and drop on the
+ // new receiver method in the ClientAppDelegate source code file.
+ //
+ // Load the top menu from MainMenu.xib.
+ [[NSBundle mainBundle] loadNibNamed:@"MainMenu"
+ owner:self
+ topLevelObjects:nil];
+
+ // Set the delegate for application events.
+ [application setDelegate:self];
+
+ if (!with_osr_) {
+ // Remove the OSR-related menu items when OSR is disabled.
+ NSMenuItem* tests_menu = GetMenuBarMenuWithTag(8);
+ if (tests_menu) {
+ NSMenuItem* set_fps_item = GetMenuItemWithAction(
+ tests_menu.submenu, @selector(menuTestsSetFPS:));
+ if (set_fps_item) {
+ [tests_menu.submenu removeItem:set_fps_item];
+ }
+ NSMenuItem* set_scale_factor_item = GetMenuItemWithAction(
+ tests_menu.submenu, @selector(menuTestsSetScaleFactor:));
+ if (set_scale_factor_item) {
+ [tests_menu.submenu removeItem:set_scale_factor_item];
+ }
+ }
+ }
+
+ auto window_config = std::make_unique<client::RootWindowConfig>();
+ window_config->with_controls = with_controls_;
+ window_config->with_osr = with_osr_;
+
+ // Create the first window.
+ client::MainContext::Get()->GetRootWindowManager()->CreateRootWindow(
+ std::move(window_config));
+}
+
+- (void)tryToTerminateApplication:(NSApplication*)app {
+ client::MainContext::Get()->GetRootWindowManager()->CloseAllWindows(false);
+}
+
+- (void)orderFrontStandardAboutPanel:(id)sender {
+ [[NSApplication sharedApplication] orderFrontStandardAboutPanel:nil];
+}
+
+- (void)testsItemSelected:(int)command_id {
+ // Retrieve the active RootWindow.
+ auto root_window =
+ client::MainContext::Get()->GetRootWindowManager()->GetActiveRootWindow();
+ if (!root_window) {
+ return;
+ }
+
+ CefRefPtr<CefBrowser> browser = root_window->GetBrowser();
+ if (browser.get()) {
+ client::test_runner::RunTest(browser, command_id);
+ }
+}
+
+- (IBAction)menuTestsGetText:(id)sender {
+ [self testsItemSelected:ID_TESTS_GETTEXT];
+}
+
+- (IBAction)menuTestsGetSource:(id)sender {
+ [self testsItemSelected:ID_TESTS_GETSOURCE];
+}
+
+- (IBAction)menuTestsWindowNew:(id)sender {
+ [self testsItemSelected:ID_TESTS_WINDOW_NEW];
+}
+
+- (IBAction)menuTestsWindowPopup:(id)sender {
+ [self testsItemSelected:ID_TESTS_WINDOW_POPUP];
+}
+
+- (IBAction)menuTestsRequest:(id)sender {
+ [self testsItemSelected:ID_TESTS_REQUEST];
+}
+
+- (IBAction)menuTestsZoomIn:(id)sender {
+ [self testsItemSelected:ID_TESTS_ZOOM_IN];
+}
+
+- (IBAction)menuTestsZoomOut:(id)sender {
+ [self testsItemSelected:ID_TESTS_ZOOM_OUT];
+}
+
+- (IBAction)menuTestsZoomReset:(id)sender {
+ [self testsItemSelected:ID_TESTS_ZOOM_RESET];
+}
+
+- (IBAction)menuTestsSetFPS:(id)sender {
+ [self testsItemSelected:ID_TESTS_OSR_FPS];
+}
+
+- (IBAction)menuTestsSetScaleFactor:(id)sender {
+ [self testsItemSelected:ID_TESTS_OSR_DSF];
+}
+
+- (IBAction)menuTestsTracingBegin:(id)sender {
+ [self testsItemSelected:ID_TESTS_TRACING_BEGIN];
+}
+
+- (IBAction)menuTestsTracingEnd:(id)sender {
+ [self testsItemSelected:ID_TESTS_TRACING_END];
+}
+
+- (IBAction)menuTestsPrint:(id)sender {
+ [self testsItemSelected:ID_TESTS_PRINT];
+}
+
+- (IBAction)menuTestsPrintToPdf:(id)sender {
+ [self testsItemSelected:ID_TESTS_PRINT_TO_PDF];
+}
+
+- (IBAction)menuTestsMuteAudio:(id)sender {
+ [self testsItemSelected:ID_TESTS_MUTE_AUDIO];
+}
+
+- (IBAction)menuTestsUnmuteAudio:(id)sender {
+ [self testsItemSelected:ID_TESTS_UNMUTE_AUDIO];
+}
+
+- (IBAction)menuTestsOtherTests:(id)sender {
+ [self testsItemSelected:ID_TESTS_OTHER_TESTS];
+}
+
+- (void)enableAccessibility:(bool)bEnable {
+ // Retrieve the active RootWindow.
+ auto root_window =
+ client::MainContext::Get()->GetRootWindowManager()->GetActiveRootWindow();
+ if (!root_window) {
+ return;
+ }
+
+ CefRefPtr<CefBrowser> browser = root_window->GetBrowser();
+ if (browser.get()) {
+ browser->GetHost()->SetAccessibilityState(bEnable ? STATE_ENABLED
+ : STATE_DISABLED);
+ }
+}
+
+- (NSApplicationTerminateReply)applicationShouldTerminate:
+ (NSApplication*)sender {
+ return NSTerminateNow;
+}
+
+@end
+
+namespace client {
+namespace {
+
+int RunMain(int argc, char* argv[]) {
+ // Load the CEF framework library at runtime instead of linking directly
+ // as required by the macOS sandbox implementation.
+ CefScopedLibraryLoader library_loader;
+ if (!library_loader.LoadInMain()) {
+ return 1;
+ }
+
+ int result = -1;
+
+ CefMainArgs main_args(argc, argv);
+
+ @autoreleasepool {
+ // Initialize the ClientApplication instance.
+ [ClientApplication sharedApplication];
+
+ // If there was an invocation to NSApp prior to this method, then the NSApp
+ // will not be a ClientApplication, but will instead be an NSApplication.
+ // This is undesirable and we must enforce that this doesn't happen.
+ CHECK([NSApp isKindOfClass:[ClientApplication class]]);
+
+ // Parse command-line arguments.
+ CefRefPtr<CefCommandLine> command_line =
+ CefCommandLine::CreateCommandLine();
+ command_line->InitFromArgv(argc, argv);
+
+ // Create a ClientApp of the correct type.
+ CefRefPtr<CefApp> app;
+ ClientApp::ProcessType process_type =
+ ClientApp::GetProcessType(command_line);
+ if (process_type == ClientApp::BrowserProcess) {
+ app = new ClientAppBrowser();
+ }
+
+ // Create the main context object.
+ std::unique_ptr<MainContextImpl> context(
+ new MainContextImpl(command_line, true));
+
+ CefSettings settings;
+
+// When generating projects with CMake the CEF_USE_SANDBOX value will be defined
+// automatically. Pass -DUSE_SANDBOX=OFF to the CMake command-line to disable
+// use of the sandbox.
+#if !defined(CEF_USE_SANDBOX)
+ settings.no_sandbox = true;
+#endif
+
+ // Populate the settings based on command line arguments.
+ context->PopulateSettings(&settings);
+
+ // Create the main message loop object.
+ std::unique_ptr<MainMessageLoop> message_loop;
+ if (settings.external_message_pump) {
+ message_loop = MainMessageLoopExternalPump::Create();
+ } else {
+ message_loop.reset(new MainMessageLoopStd);
+ }
+
+ // Initialize CEF.
+ context->Initialize(main_args, settings, app, nullptr);
+
+ // Register scheme handlers.
+ test_runner::RegisterSchemeHandlers();
+
+ // Create the application delegate and window.
+ ClientAppDelegate* delegate = [[ClientAppDelegate alloc]
+ initWithControls:!command_line->HasSwitch(switches::kHideControls)
+ andOsr:settings.windowless_rendering_enabled ? true : false];
+ [delegate performSelectorOnMainThread:@selector(createApplication:)
+ withObject:nil
+ waitUntilDone:NO];
+
+ // Run the message loop. This will block until Quit() is called.
+ result = message_loop->Run();
+
+ // Shut down CEF.
+ context->Shutdown();
+
+ // Release objects in reverse order of creation.
+#if !__has_feature(objc_arc)
+ [delegate release];
+#endif // !__has_feature(objc_arc)
+ delegate = nil;
+ message_loop.reset();
+ context.reset();
+ } // @autoreleasepool
+
+ return result;
+}
+
+} // namespace
+} // namespace client
+
+// Entry point function for the browser process.
+int main(int argc, char* argv[]) {
+ return client::RunMain(argc, argv);
+}
diff --git a/tests/cefclient/cefclient_win.cc b/tests/cefclient/cefclient_win.cc
new file mode 100644
index 00000000..d41108ea
--- /dev/null
+++ b/tests/cefclient/cefclient_win.cc
@@ -0,0 +1,154 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include <windows.h>
+
+#include <memory>
+
+#include "include/cef_command_line.h"
+#include "include/cef_sandbox_win.h"
+#include "tests/cefclient/browser/main_context_impl.h"
+#include "tests/cefclient/browser/main_message_loop_multithreaded_win.h"
+#include "tests/cefclient/browser/root_window_manager.h"
+#include "tests/cefclient/browser/test_runner.h"
+#include "tests/shared/browser/client_app_browser.h"
+#include "tests/shared/browser/main_message_loop_external_pump.h"
+#include "tests/shared/browser/main_message_loop_std.h"
+#include "tests/shared/common/client_app_other.h"
+#include "tests/shared/common/client_switches.h"
+#include "tests/shared/renderer/client_app_renderer.h"
+
+// When generating projects with CMake the CEF_USE_SANDBOX value will be defined
+// automatically if using the required compiler version. Pass -DUSE_SANDBOX=OFF
+// to the CMake command-line to disable use of the sandbox.
+// Uncomment this line to manually enable sandbox support.
+// #define CEF_USE_SANDBOX 1
+
+#if defined(CEF_USE_SANDBOX)
+// The cef_sandbox.lib static library may not link successfully with all VS
+// versions.
+#pragma comment(lib, "cef_sandbox.lib")
+#endif
+
+namespace client {
+namespace {
+
+int RunMain(HINSTANCE hInstance, int nCmdShow) {
+ // Enable High-DPI support on Windows 7 or newer.
+ CefEnableHighDPISupport();
+
+ CefMainArgs main_args(hInstance);
+
+ void* sandbox_info = nullptr;
+
+#if defined(CEF_USE_SANDBOX)
+ // Manage the life span of the sandbox information object. This is necessary
+ // for sandbox support on Windows. See cef_sandbox_win.h for complete details.
+ CefScopedSandboxInfo scoped_sandbox;
+ sandbox_info = scoped_sandbox.sandbox_info();
+#endif
+
+ // Parse command-line arguments.
+ CefRefPtr<CefCommandLine> command_line = CefCommandLine::CreateCommandLine();
+ command_line->InitFromString(::GetCommandLineW());
+
+ // Create a ClientApp of the correct type.
+ CefRefPtr<CefApp> app;
+ ClientApp::ProcessType process_type = ClientApp::GetProcessType(command_line);
+ if (process_type == ClientApp::BrowserProcess) {
+ app = new ClientAppBrowser();
+ } else if (process_type == ClientApp::RendererProcess) {
+ app = new ClientAppRenderer();
+ } else if (process_type == ClientApp::OtherProcess) {
+ app = new ClientAppOther();
+ }
+
+ // Execute the secondary process, if any.
+ int exit_code = CefExecuteProcess(main_args, app, sandbox_info);
+ if (exit_code >= 0) {
+ return exit_code;
+ }
+
+ // Create the main context object.
+ auto context = std::make_unique<MainContextImpl>(command_line, true);
+
+ CefSettings settings;
+
+#if !defined(CEF_USE_SANDBOX)
+ settings.no_sandbox = true;
+#endif
+
+ // Populate the settings based on command line arguments.
+ context->PopulateSettings(&settings);
+
+ // Create the main message loop object.
+ std::unique_ptr<MainMessageLoop> message_loop;
+ if (settings.multi_threaded_message_loop) {
+ message_loop.reset(new MainMessageLoopMultithreadedWin);
+ } else if (settings.external_message_pump) {
+ message_loop = MainMessageLoopExternalPump::Create();
+ } else {
+ message_loop.reset(new MainMessageLoopStd);
+ }
+
+ // Initialize CEF.
+ context->Initialize(main_args, settings, app, sandbox_info);
+
+ // Register scheme handlers.
+ test_runner::RegisterSchemeHandlers();
+
+ auto window_config = std::make_unique<RootWindowConfig>();
+ window_config->always_on_top =
+ command_line->HasSwitch(switches::kAlwaysOnTop);
+ window_config->with_controls =
+ !command_line->HasSwitch(switches::kHideControls);
+ window_config->with_osr =
+ settings.windowless_rendering_enabled ? true : false;
+
+ // Create the first window.
+ context->GetRootWindowManager()->CreateRootWindow(std::move(window_config));
+
+ // Run the message loop. This will block until Quit() is called by the
+ // RootWindowManager after all windows have been destroyed.
+ int result = message_loop->Run();
+
+ // Shut down CEF.
+ context->Shutdown();
+
+ // Release objects in reverse order of creation.
+ message_loop.reset();
+ context.reset();
+
+ return result;
+}
+
+} // namespace
+} // namespace client
+
+// Program entry point function.
+int APIENTRY wWinMain(HINSTANCE hInstance,
+ HINSTANCE hPrevInstance,
+ LPTSTR lpCmdLine,
+ int nCmdShow) {
+ UNREFERENCED_PARAMETER(hPrevInstance);
+ UNREFERENCED_PARAMETER(lpCmdLine);
+
+#if defined(ARCH_CPU_32_BITS)
+ // Run the main thread on 32-bit Windows using a fiber with the preferred 4MiB
+ // stack size. This function must be called at the top of the executable entry
+ // point function (`main()` or `wWinMain()`). It is used in combination with
+ // the initial stack size of 0.5MiB configured via the `/STACK:0x80000` linker
+ // flag on executable targets. This saves significant memory on threads (like
+ // those in the Windows thread pool, and others) whose stack size can only be
+ // controlled via the linker flag.
+ int exit_code = CefRunWinMainWithPreferredStackSize(wWinMain, hInstance,
+ lpCmdLine, nCmdShow);
+ if (exit_code >= 0) {
+ // The fiber has completed so return here.
+ return exit_code;
+ }
+#endif
+
+ return client::RunMain(hInstance, nCmdShow);
+}
diff --git a/tests/cefclient/common/client_app_delegates_common.cc b/tests/cefclient/common/client_app_delegates_common.cc
new file mode 100644
index 00000000..493f3e1e
--- /dev/null
+++ b/tests/cefclient/common/client_app_delegates_common.cc
@@ -0,0 +1,15 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/common/scheme_test_common.h"
+#include "tests/shared/common/client_app.h"
+
+namespace client {
+
+// static
+void ClientApp::RegisterCustomSchemes(CefRawPtr<CefSchemeRegistrar> registrar) {
+ scheme_test::RegisterCustomSchemes(registrar);
+}
+
+} // namespace client
diff --git a/tests/cefclient/common/scheme_test_common.cc b/tests/cefclient/common/scheme_test_common.cc
new file mode 100644
index 00000000..7eb1eb66
--- /dev/null
+++ b/tests/cefclient/common/scheme_test_common.cc
@@ -0,0 +1,18 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/common/scheme_test_common.h"
+
+#include "include/cef_scheme.h"
+
+namespace client {
+namespace scheme_test {
+
+void RegisterCustomSchemes(CefRawPtr<CefSchemeRegistrar> registrar) {
+ registrar->AddCustomScheme(
+ "client", CEF_SCHEME_OPTION_STANDARD | CEF_SCHEME_OPTION_CORS_ENABLED);
+}
+
+} // namespace scheme_test
+} // namespace client
diff --git a/tests/cefclient/common/scheme_test_common.h b/tests/cefclient/common/scheme_test_common.h
new file mode 100644
index 00000000..7eb28215
--- /dev/null
+++ b/tests/cefclient/common/scheme_test_common.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2009 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_COMMON_SCHEME_TEST_COMMON_H_
+#define CEF_TESTS_CEFCLIENT_COMMON_SCHEME_TEST_COMMON_H_
+#pragma once
+
+#include <vector>
+
+#include "include/cef_scheme.h"
+
+namespace client {
+namespace scheme_test {
+
+// Register the custom scheme name/type. This must be done in all processes.
+// See browser/scheme_test.h for creation/registration of the custom scheme
+// handler which only occurs in the browser process. Called from
+// client_app_delegates_common.cc.
+void RegisterCustomSchemes(CefRawPtr<CefSchemeRegistrar> registrar);
+
+} // namespace scheme_test
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_COMMON_SCHEME_TEST_COMMON_H_
diff --git a/tests/cefclient/renderer/client_app_delegates_renderer.cc b/tests/cefclient/renderer/client_app_delegates_renderer.cc
new file mode 100644
index 00000000..930c7121
--- /dev/null
+++ b/tests/cefclient/renderer/client_app_delegates_renderer.cc
@@ -0,0 +1,19 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/renderer/client_renderer.h"
+#include "tests/cefclient/renderer/ipc_performance_test.h"
+#include "tests/cefclient/renderer/performance_test.h"
+#include "tests/shared/renderer/client_app_renderer.h"
+
+namespace client {
+
+// static
+void ClientAppRenderer::CreateDelegates(DelegateSet& delegates) {
+ renderer::CreateDelegates(delegates);
+ performance_test::CreateDelegates(delegates);
+ ipc_performance_test::CreateDelegates(delegates);
+}
+
+} // namespace client
diff --git a/tests/cefclient/renderer/client_renderer.cc b/tests/cefclient/renderer/client_renderer.cc
new file mode 100644
index 00000000..106a612b
--- /dev/null
+++ b/tests/cefclient/renderer/client_renderer.cc
@@ -0,0 +1,99 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/renderer/client_renderer.h"
+
+#include <sstream>
+#include <string>
+
+#include "include/cef_crash_util.h"
+#include "include/cef_dom.h"
+#include "include/wrapper/cef_helpers.h"
+#include "include/wrapper/cef_message_router.h"
+
+namespace client {
+namespace renderer {
+
+namespace {
+
+// Must match the value in client_handler.cc.
+const char kFocusedNodeChangedMessage[] = "ClientRenderer.FocusedNodeChanged";
+
+class ClientRenderDelegate : public ClientAppRenderer::Delegate {
+ public:
+ ClientRenderDelegate() : last_node_is_editable_(false) {}
+
+ void OnWebKitInitialized(CefRefPtr<ClientAppRenderer> app) override {
+ if (CefCrashReportingEnabled()) {
+ // Set some crash keys for testing purposes. Keys must be defined in the
+ // "crash_reporter.cfg" file. See cef_crash_util.h for details.
+ CefSetCrashKeyValue("testkey_small1", "value1_small_renderer");
+ CefSetCrashKeyValue("testkey_small2", "value2_small_renderer");
+ CefSetCrashKeyValue("testkey_medium1", "value1_medium_renderer");
+ CefSetCrashKeyValue("testkey_medium2", "value2_medium_renderer");
+ CefSetCrashKeyValue("testkey_large1", "value1_large_renderer");
+ CefSetCrashKeyValue("testkey_large2", "value2_large_renderer");
+ }
+
+ // Create the renderer-side router for query handling.
+ CefMessageRouterConfig config;
+ message_router_ = CefMessageRouterRendererSide::Create(config);
+ }
+
+ void OnContextCreated(CefRefPtr<ClientAppRenderer> app,
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefV8Context> context) override {
+ message_router_->OnContextCreated(browser, frame, context);
+ }
+
+ void OnContextReleased(CefRefPtr<ClientAppRenderer> app,
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefV8Context> context) override {
+ message_router_->OnContextReleased(browser, frame, context);
+ }
+
+ void OnFocusedNodeChanged(CefRefPtr<ClientAppRenderer> app,
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefDOMNode> node) override {
+ bool is_editable = (node.get() && node->IsEditable());
+ if (is_editable != last_node_is_editable_) {
+ // Notify the browser of the change in focused element type.
+ last_node_is_editable_ = is_editable;
+ CefRefPtr<CefProcessMessage> message =
+ CefProcessMessage::Create(kFocusedNodeChangedMessage);
+ message->GetArgumentList()->SetBool(0, is_editable);
+ frame->SendProcessMessage(PID_BROWSER, message);
+ }
+ }
+
+ bool OnProcessMessageReceived(CefRefPtr<ClientAppRenderer> app,
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefProcessId source_process,
+ CefRefPtr<CefProcessMessage> message) override {
+ return message_router_->OnProcessMessageReceived(browser, frame,
+ source_process, message);
+ }
+
+ private:
+ bool last_node_is_editable_;
+
+ // Handles the renderer side of query routing.
+ CefRefPtr<CefMessageRouterRendererSide> message_router_;
+
+ DISALLOW_COPY_AND_ASSIGN(ClientRenderDelegate);
+ IMPLEMENT_REFCOUNTING(ClientRenderDelegate);
+};
+
+} // namespace
+
+void CreateDelegates(ClientAppRenderer::DelegateSet& delegates) {
+ delegates.insert(new ClientRenderDelegate);
+}
+
+} // namespace renderer
+} // namespace client
diff --git a/tests/cefclient/renderer/client_renderer.h b/tests/cefclient/renderer/client_renderer.h
new file mode 100644
index 00000000..08076458
--- /dev/null
+++ b/tests/cefclient/renderer/client_renderer.h
@@ -0,0 +1,21 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_RENDERER_CLIENT_RENDERER_H_
+#define CEF_TESTS_CEFCLIENT_RENDERER_CLIENT_RENDERER_H_
+#pragma once
+
+#include "include/cef_base.h"
+#include "tests/shared/renderer/client_app_renderer.h"
+
+namespace client {
+namespace renderer {
+
+// Create the renderer delegate. Called from client_app_delegates_renderer.cc.
+void CreateDelegates(ClientAppRenderer::DelegateSet& delegates);
+
+} // namespace renderer
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_RENDERER_CLIENT_RENDERER_H_
diff --git a/tests/cefclient/renderer/ipc_performance_test.cc b/tests/cefclient/renderer/ipc_performance_test.cc
new file mode 100644
index 00000000..2593150c
--- /dev/null
+++ b/tests/cefclient/renderer/ipc_performance_test.cc
@@ -0,0 +1,249 @@
+// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/renderer/ipc_performance_test.h"
+
+#include "include/cef_shared_process_message_builder.h"
+#include "include/wrapper/cef_helpers.h"
+#include "tests/shared/common/binary_value_utils.h"
+
+namespace {
+
+// JS object member names.
+constexpr char kMessageSize[] = "size";
+constexpr char kTestId[] = "testId";
+constexpr CefV8Value::PropertyAttribute kAttributes =
+ static_cast<CefV8Value::PropertyAttribute>(
+ V8_PROPERTY_ATTRIBUTE_READONLY | V8_PROPERTY_ATTRIBUTE_DONTENUM |
+ V8_PROPERTY_ATTRIBUTE_DONTDELETE);
+
+struct TestInfo {
+ size_t message_size = 0;
+ int id = 0;
+ bool is_valid = false;
+};
+
+TestInfo GetTest(const CefV8ValueList& arguments, CefString& exception) {
+ TestInfo info{};
+
+ if (arguments.size() != 1 || !arguments[0]->IsObject()) {
+ exception = "Invalid arguments; expecting a single object";
+ return info;
+ }
+
+ CefRefPtr<CefV8Value> arg = arguments[0];
+ CefRefPtr<CefV8Value> message_size = arg->GetValue(kMessageSize);
+ if (!message_size.get() || !message_size->IsInt()) {
+ exception =
+ "Invalid arguments; object member 'size' is required and must have "
+ "integer type";
+ return info;
+ }
+
+ if (message_size->GetIntValue() < 1) {
+ exception =
+ "Invalid arguments; object member 'size' must be "
+ "positive";
+ return info;
+ }
+
+ CefRefPtr<CefV8Value> test_id = arg->GetValue(kTestId);
+ if (!message_size.get() || !message_size->IsInt()) {
+ exception =
+ "Invalid arguments; object member 'testId' is required and must "
+ "have integer type";
+ return info;
+ }
+
+ info.message_size = static_cast<size_t>(message_size->GetIntValue());
+ info.id = test_id->GetIntValue();
+ info.is_valid = true;
+
+ return info;
+}
+
+// Handle bindings in the render process.
+class IpcDelegate final : public client::ClientAppRenderer::Delegate {
+ public:
+ class V8HandlerImpl final : public CefV8Handler {
+ public:
+ explicit V8HandlerImpl(const CefRefPtr<IpcDelegate>& delegate)
+ : delegate_(delegate) {}
+ V8HandlerImpl(const V8HandlerImpl&) = delete;
+ V8HandlerImpl& operator=(const V8HandlerImpl&) = delete;
+
+ bool Execute(const CefString& name,
+ CefRefPtr<CefV8Value> object,
+ const CefV8ValueList& arguments,
+ CefRefPtr<CefV8Value>& retval,
+ CefString& exception) override {
+ if (name == bv_utils::kTestSendProcessMessage) {
+ const auto test = GetTest(arguments, exception);
+ if (test.is_valid) {
+ SendTestProcessMessage(test.message_size, test.id);
+ }
+ return true;
+ }
+
+ if (name == bv_utils::kTestSendSMRProcessMessage) {
+ const auto test = GetTest(arguments, exception);
+ if (test.is_valid) {
+ SendTestSMRProcessMessage(test.message_size, test.id);
+ }
+ return true;
+ }
+
+ return false;
+ }
+
+ private:
+ void SendTestProcessMessage(size_t message_size, int test_id) {
+ auto context = CefV8Context::GetCurrentContext();
+ delegate_->SendTestProcessMessage(context->GetFrame(), message_size,
+ test_id);
+ }
+
+ void SendTestSMRProcessMessage(size_t message_size, int test_id) {
+ auto context = CefV8Context::GetCurrentContext();
+ delegate_->SendTestSMRProcessMessage(context->GetFrame(), message_size,
+ test_id);
+ }
+
+ CefRefPtr<IpcDelegate> delegate_;
+ IMPLEMENT_REFCOUNTING(V8HandlerImpl);
+ };
+
+ IpcDelegate() = default;
+ IpcDelegate(const IpcDelegate&) = delete;
+ IpcDelegate& operator=(const IpcDelegate&) = delete;
+
+ void OnContextCreated(CefRefPtr<client::ClientAppRenderer> app,
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefV8Context> context) override {
+ CEF_REQUIRE_RENDERER_THREAD();
+
+ CefRefPtr<CefV8Handler> handler = new V8HandlerImpl(this);
+
+ // Register function handlers with the 'window' object.
+ auto window = context->GetGlobal();
+ window->SetValue(
+ bv_utils::kTestSendProcessMessage,
+ CefV8Value::CreateFunction(bv_utils::kTestSendProcessMessage, handler),
+ kAttributes);
+
+ window->SetValue(bv_utils::kTestSendSMRProcessMessage,
+ CefV8Value::CreateFunction(
+ bv_utils::kTestSendSMRProcessMessage, handler),
+ kAttributes);
+ }
+
+ bool OnProcessMessageReceived(CefRefPtr<client::ClientAppRenderer> app,
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefProcessId source_process,
+ CefRefPtr<CefProcessMessage> message) override {
+ CEF_REQUIRE_RENDERER_THREAD();
+ const auto finish_time = bv_utils::Now();
+
+ if (message->GetName() == bv_utils::kTestSendProcessMessage) {
+ auto args = message->GetArgumentList();
+ DCHECK_EQ(args->GetSize(), 1U);
+
+ const auto browser_msg =
+ bv_utils::GetBrowserMsgFromBinary(args->GetBinary(0));
+ PassTestResultToJs(frame, finish_time, browser_msg);
+
+ return true;
+ }
+
+ if (message->GetName() == bv_utils::kTestSendSMRProcessMessage) {
+ const auto region = message->GetSharedMemoryRegion();
+ DCHECK(region->IsValid());
+ DCHECK_GE(region->Size(), sizeof(bv_utils::BrowserMessage));
+
+ const auto browser_msg =
+ static_cast<const bv_utils::BrowserMessage*>(region->Memory());
+
+ PassTestResultToJs(frame, finish_time, *browser_msg);
+
+ return true;
+ }
+
+ return false;
+ }
+
+ private:
+ IMPLEMENT_REFCOUNTING(IpcDelegate);
+
+ void SendTestProcessMessage(CefRefPtr<CefFrame> frame,
+ size_t message_size,
+ int test_id) {
+ CEF_REQUIRE_RENDERER_THREAD();
+
+ auto process_message =
+ CefProcessMessage::Create(bv_utils::kTestSendProcessMessage);
+ auto args = process_message->GetArgumentList();
+
+ const auto buffer_size =
+ std::max(message_size, sizeof(bv_utils::RendererMessage));
+ std::vector<uint8_t> buffer(buffer_size);
+
+ const auto renderer_msg =
+ reinterpret_cast<bv_utils::RendererMessage*>(buffer.data());
+
+ renderer_msg->test_id = test_id;
+ renderer_msg->start_time = bv_utils::Now();
+
+ args->SetBinary(0, bv_utils::CreateCefBinaryValue(buffer));
+ frame->SendProcessMessage(PID_BROWSER, process_message);
+ }
+
+ void SendTestSMRProcessMessage(CefRefPtr<CefFrame> frame,
+ size_t message_size,
+ int test_id) {
+ CEF_REQUIRE_RENDERER_THREAD();
+
+ const auto buffer_size =
+ std::max(message_size, sizeof(bv_utils::RendererMessage));
+ const auto start_time = bv_utils::Now();
+
+ auto builder = CefSharedProcessMessageBuilder::Create(
+ bv_utils::kTestSendSMRProcessMessage, buffer_size);
+
+ auto renderer_msg =
+ static_cast<bv_utils::RendererMessage*>(builder->Memory());
+ renderer_msg->test_id = test_id;
+ renderer_msg->start_time = start_time;
+
+ frame->SendProcessMessage(PID_BROWSER, builder->Build());
+ }
+
+ // Execute the onSuccess JavaScript callback.
+ void PassTestResultToJs(CefRefPtr<CefFrame> frame,
+ const bv_utils::TimePoint& finish_time,
+ const bv_utils::BrowserMessage& msg) {
+ const auto rendered_to_browser = msg.duration;
+ const auto browser_to_rendered = finish_time - msg.start_time;
+
+ CefString code = "testSendProcessMessageResult(" +
+ std::to_string(msg.test_id) + ", " +
+ bv_utils::ToMilliString(rendered_to_browser) + ", " +
+ bv_utils::ToMilliString(browser_to_rendered) + ");";
+
+ frame->ExecuteJavaScript(code, frame->GetURL(), 0);
+ }
+};
+
+} // namespace
+
+namespace client {
+namespace ipc_performance_test {
+
+void CreateDelegates(ClientAppRenderer::DelegateSet& delegates) {
+ delegates.insert(new IpcDelegate());
+}
+
+} // namespace ipc_performance_test
+} // namespace client
diff --git a/tests/cefclient/renderer/ipc_performance_test.h b/tests/cefclient/renderer/ipc_performance_test.h
new file mode 100644
index 00000000..1ba2727e
--- /dev/null
+++ b/tests/cefclient/renderer/ipc_performance_test.h
@@ -0,0 +1,19 @@
+// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_RENDERER_IPC_PERFORMANCE_TEST_H_
+#define CEF_TESTS_CEFCLIENT_RENDERER_IPC_PERFORMANCE_TEST_H_
+#pragma once
+
+#include "tests/shared/renderer/client_app_renderer.h"
+
+namespace client {
+namespace ipc_performance_test {
+
+void CreateDelegates(ClientAppRenderer::DelegateSet& delegates);
+
+} // namespace ipc_performance_test
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_RENDERER_IPC_PERFORMANCE_TEST_H_
diff --git a/tests/cefclient/renderer/performance_test.cc b/tests/cefclient/renderer/performance_test.cc
new file mode 100644
index 00000000..9946a683
--- /dev/null
+++ b/tests/cefclient/renderer/performance_test.cc
@@ -0,0 +1,162 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefclient/renderer/performance_test.h"
+
+#include <algorithm>
+#include <string>
+
+#include "include/base/cef_logging.h"
+#include "include/wrapper/cef_stream_resource_handler.h"
+#include "tests/cefclient/renderer/performance_test_setup.h"
+
+namespace client {
+namespace performance_test {
+
+// Use more interations for a Release build.
+#if DCHECK_IS_ON()
+const int kDefaultIterations = 100000;
+#else
+const int kDefaultIterations = 10000;
+#endif
+
+namespace {
+
+const char kGetPerfTests[] = "GetPerfTests";
+const char kRunPerfTest[] = "RunPerfTest";
+const char kPerfTestReturnValue[] = "PerfTestReturnValue";
+
+class V8Handler : public CefV8Handler {
+ public:
+ V8Handler() {}
+
+ virtual bool Execute(const CefString& name,
+ CefRefPtr<CefV8Value> object,
+ const CefV8ValueList& arguments,
+ CefRefPtr<CefV8Value>& retval,
+ CefString& exception) override {
+ if (name == kRunPerfTest) {
+ if (arguments.size() == 1 && arguments[0]->IsString()) {
+ // Run the specified perf test.
+ bool found = false;
+
+ std::string test = arguments[0]->GetStringValue();
+ for (int i = 0; i < kPerfTestsCount; ++i) {
+ if (test == kPerfTests[i].name) {
+ // Execute the test.
+ int64 delta = kPerfTests[i].test(kPerfTests[i].iterations);
+
+ retval = CefV8Value::CreateInt(static_cast<int32>(delta));
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ std::string msg = "Unknown test: ";
+ msg.append(test);
+ exception = msg;
+ }
+ } else {
+ exception = "Invalid function parameters";
+ }
+ } else if (name == kGetPerfTests) {
+ // Retrieve the list of perf tests.
+ retval = CefV8Value::CreateArray(kPerfTestsCount);
+ for (int i = 0; i < kPerfTestsCount; ++i) {
+ CefRefPtr<CefV8Value> val = CefV8Value::CreateArray(2);
+ val->SetValue(0, CefV8Value::CreateString(kPerfTests[i].name));
+ val->SetValue(1, CefV8Value::CreateUInt(kPerfTests[i].iterations));
+ retval->SetValue(i, val);
+ }
+ } else if (name == kPerfTestReturnValue) {
+ if (arguments.size() == 0) {
+ retval = CefV8Value::CreateInt(1);
+ } else if (arguments.size() == 1 && arguments[0]->IsInt()) {
+ int32 type = arguments[0]->GetIntValue();
+ switch (type) {
+ case 0:
+ retval = CefV8Value::CreateUndefined();
+ break;
+ case 1:
+ retval = CefV8Value::CreateNull();
+ break;
+ case 2:
+ retval = CefV8Value::CreateBool(true);
+ break;
+ case 3:
+ retval = CefV8Value::CreateInt(1);
+ break;
+ case 4:
+ retval = CefV8Value::CreateUInt(1);
+ break;
+ case 5:
+ retval = CefV8Value::CreateDouble(1.234);
+ break;
+ case 6:
+ retval = CefV8Value::CreateDate(CefBaseTime::Now());
+ break;
+ case 7:
+ retval = CefV8Value::CreateString("Hello, world!");
+ break;
+ case 8:
+ retval = CefV8Value::CreateObject(nullptr, nullptr);
+ break;
+ case 9:
+ retval = CefV8Value::CreateArray(8);
+ break;
+ case 10:
+ // retval = CefV8Value::CreateFunction(...);
+ exception = "Not implemented";
+ break;
+ default:
+ exception = "Not supported";
+ }
+ }
+ }
+
+ return true;
+ }
+
+ private:
+ IMPLEMENT_REFCOUNTING(V8Handler);
+};
+
+// Handle bindings in the render process.
+class RenderDelegate : public ClientAppRenderer::Delegate {
+ public:
+ RenderDelegate() {}
+
+ virtual void OnContextCreated(CefRefPtr<ClientAppRenderer> app,
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefV8Context> context) override {
+ CefRefPtr<CefV8Value> object = context->GetGlobal();
+
+ CefRefPtr<CefV8Handler> handler = new V8Handler();
+
+ // Bind test functions.
+ object->SetValue(kGetPerfTests,
+ CefV8Value::CreateFunction(kGetPerfTests, handler),
+ V8_PROPERTY_ATTRIBUTE_READONLY);
+ object->SetValue(kRunPerfTest,
+ CefV8Value::CreateFunction(kRunPerfTest, handler),
+ V8_PROPERTY_ATTRIBUTE_READONLY);
+ object->SetValue(kPerfTestReturnValue,
+ CefV8Value::CreateFunction(kPerfTestReturnValue, handler),
+ V8_PROPERTY_ATTRIBUTE_READONLY);
+ }
+
+ private:
+ IMPLEMENT_REFCOUNTING(RenderDelegate);
+};
+
+} // namespace
+
+void CreateDelegates(ClientAppRenderer::DelegateSet& delegates) {
+ delegates.insert(new RenderDelegate);
+}
+
+} // namespace performance_test
+} // namespace client
diff --git a/tests/cefclient/renderer/performance_test.h b/tests/cefclient/renderer/performance_test.h
new file mode 100644
index 00000000..ce016bf1
--- /dev/null
+++ b/tests/cefclient/renderer/performance_test.h
@@ -0,0 +1,20 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_RENDERER_PERFORMANCE_TEST_H_
+#define CEF_TESTS_CEFCLIENT_RENDERER_PERFORMANCE_TEST_H_
+#pragma once
+
+#include "tests/shared/renderer/client_app_renderer.h"
+
+namespace client {
+namespace performance_test {
+
+// Create the renderer delegate. Called from client_app_delegates_renderer.cc.
+void CreateDelegates(ClientAppRenderer::DelegateSet& delegates);
+
+} // namespace performance_test
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_RENDERER_PERFORMANCE_TEST_H_
diff --git a/tests/cefclient/renderer/performance_test_setup.h b/tests/cefclient/renderer/performance_test_setup.h
new file mode 100644
index 00000000..7427a555
--- /dev/null
+++ b/tests/cefclient/renderer/performance_test_setup.h
@@ -0,0 +1,102 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_RENDERER_PERFORMANCE_TEST_SETUP_H_
+#define CEF_TESTS_CEFCLIENT_RENDERER_PERFORMANCE_TEST_SETUP_H_
+#pragma once
+
+#include "include/base/cef_logging.h"
+#include "include/base/cef_macros.h"
+
+namespace client {
+namespace performance_test {
+
+// Default number of iterations.
+extern const int kDefaultIterations;
+
+// Test name.
+#define PERF_TEST_NAME(name) PerfTest##name
+
+// Entry in test array.
+#define PERF_TEST_ENTRY_EX(name, iterations) \
+ { #name, PERF_TEST_NAME(name), iterations }
+#define PERF_TEST_ENTRY(name) PERF_TEST_ENTRY_EX(name, kDefaultIterations)
+
+// Test function declaration.
+#define PERF_TEST_RESULT int64
+#define PERF_TEST_PARAM_ITERATIONS iterations
+#define PERF_TEST_PARAMS int PERF_TEST_PARAM_ITERATIONS
+#define PERF_TEST_FUNC(name) \
+ PERF_TEST_RESULT PERF_TEST_NAME(name)(PERF_TEST_PARAMS)
+
+// Typedef for test pointers.
+typedef PERF_TEST_RESULT(PerfTest(PERF_TEST_PARAMS));
+
+class CefTimer {
+ public:
+ CefTimer() : running_(false) {}
+
+ bool IsRunning() { return running_; }
+
+ void Start() {
+ DCHECK(!running_);
+ running_ = true;
+ start_.Now();
+ }
+
+ void Stop() {
+ stop_.Now();
+ DCHECK(running_);
+ running_ = false;
+ }
+
+ int64 Delta() {
+ DCHECK(!running_);
+ return start_.Delta(stop_);
+ }
+
+ private:
+ bool running_;
+ CefTime start_;
+ CefTime stop_;
+
+ DISALLOW_COPY_AND_ASSIGN(CefTimer);
+};
+
+// Peform test iterations using a user-provided timing result variable.
+#define PERF_ITERATIONS_START_EX() \
+ { \
+ CefTimer _timer; \
+ _timer.Start(); \
+ for (int _i = 0; _i < PERF_TEST_PARAM_ITERATIONS; ++_i) {
+#define PERF_ITERATIONS_END_EX(result) \
+ } \
+ _timer.Stop(); \
+ result = _timer.Delta(); \
+ }
+
+// Perform test iterations and return the timing result.
+#define PERF_ITERATIONS_START() \
+ int64 _result = 0; \
+ PERF_ITERATIONS_START_EX()
+
+#define PERF_ITERATIONS_END() \
+ PERF_ITERATIONS_END_EX(_result) \
+ return _result;
+
+// Perf test entry structure.
+struct PerfTestEntry {
+ const char* name;
+ PerfTest* test;
+ int iterations;
+};
+
+// Array of perf tests.
+extern const PerfTestEntry kPerfTests[];
+extern const int kPerfTestsCount;
+
+} // namespace performance_test
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_RENDERER_PERFORMANCE_TEST_H_
diff --git a/tests/cefclient/renderer/performance_test_tests.cc b/tests/cefclient/renderer/performance_test_tests.cc
new file mode 100644
index 00000000..b94df362
--- /dev/null
+++ b/tests/cefclient/renderer/performance_test_tests.cc
@@ -0,0 +1,396 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "include/cef_v8.h"
+#include "tests/cefclient/renderer/performance_test.h"
+#include "tests/cefclient/renderer/performance_test_setup.h"
+
+namespace client {
+namespace performance_test {
+
+namespace {
+
+// Test function implementations.
+
+PERF_TEST_FUNC(V8NullCreate) {
+ PERF_ITERATIONS_START()
+ CefRefPtr<CefV8Value> value = CefV8Value::CreateNull();
+ PERF_ITERATIONS_END()
+}
+
+PERF_TEST_FUNC(V8BoolCreate) {
+ PERF_ITERATIONS_START()
+ CefRefPtr<CefV8Value> value = CefV8Value::CreateBool(true);
+ PERF_ITERATIONS_END()
+}
+
+PERF_TEST_FUNC(V8IntCreate) {
+ PERF_ITERATIONS_START()
+ CefRefPtr<CefV8Value> value = CefV8Value::CreateInt(-5);
+ PERF_ITERATIONS_END()
+}
+
+PERF_TEST_FUNC(V8UIntCreate) {
+ PERF_ITERATIONS_START()
+ CefRefPtr<CefV8Value> value = CefV8Value::CreateUInt(10);
+ PERF_ITERATIONS_END()
+}
+
+PERF_TEST_FUNC(V8DoubleCreate) {
+ PERF_ITERATIONS_START()
+ CefRefPtr<CefV8Value> value = CefV8Value::CreateDouble(12.432);
+ PERF_ITERATIONS_END()
+}
+
+PERF_TEST_FUNC(V8DateCreate) {
+ static cef_time_t time_exploded = {2012, 1, 0, 1};
+
+ cef_basetime_t basetime;
+ cef_time_to_basetime(&time_exploded, &basetime);
+ CefBaseTime time(basetime);
+
+ PERF_ITERATIONS_START()
+ CefRefPtr<CefV8Value> value = CefV8Value::CreateDate(time);
+ PERF_ITERATIONS_END()
+}
+
+PERF_TEST_FUNC(V8StringCreate) {
+ CefString str = "test string";
+
+ PERF_ITERATIONS_START()
+ CefRefPtr<CefV8Value> value = CefV8Value::CreateString(str);
+ PERF_ITERATIONS_END()
+}
+
+PERF_TEST_FUNC(V8ArrayCreate) {
+ PERF_ITERATIONS_START()
+ CefRefPtr<CefV8Value> value = CefV8Value::CreateArray(1);
+ PERF_ITERATIONS_END()
+}
+
+PERF_TEST_FUNC(V8ArraySetValue) {
+ CefRefPtr<CefV8Value> val = CefV8Value::CreateBool(true);
+ CefRefPtr<CefV8Value> array = CefV8Value::CreateArray(1);
+ array->SetValue(0, val);
+
+ PERF_ITERATIONS_START()
+ array->SetValue(0, val);
+ PERF_ITERATIONS_END()
+}
+
+PERF_TEST_FUNC(V8ArrayGetValue) {
+ CefRefPtr<CefV8Value> val = CefV8Value::CreateBool(true);
+ CefRefPtr<CefV8Value> array = CefV8Value::CreateArray(1);
+ array->SetValue(0, val);
+
+ PERF_ITERATIONS_START()
+ CefRefPtr<CefV8Value> ret = array->GetValue(0);
+ PERF_ITERATIONS_END()
+}
+
+PERF_TEST_FUNC(V8FunctionCreate) {
+ class Handler : public CefV8Handler {
+ public:
+ Handler() {}
+ virtual bool Execute(const CefString& name,
+ CefRefPtr<CefV8Value> object,
+ const CefV8ValueList& arguments,
+ CefRefPtr<CefV8Value>& retval,
+ CefString& exception) override {
+ return false;
+ }
+ IMPLEMENT_REFCOUNTING(Handler);
+ };
+
+ CefString name = "name";
+ CefRefPtr<CefV8Handler> handler = new Handler();
+
+ PERF_ITERATIONS_START()
+ CefRefPtr<CefV8Value> value = CefV8Value::CreateFunction(name, handler);
+ PERF_ITERATIONS_END()
+}
+
+PERF_TEST_FUNC(V8FunctionExecute) {
+ class Handler : public CefV8Handler {
+ public:
+ Handler() {}
+ virtual bool Execute(const CefString& name,
+ CefRefPtr<CefV8Value> object,
+ const CefV8ValueList& arguments,
+ CefRefPtr<CefV8Value>& retval,
+ CefString& exception) override {
+ return true;
+ }
+ IMPLEMENT_REFCOUNTING(Handler);
+ };
+
+ CefString name = "name";
+ CefRefPtr<CefV8Handler> handler = new Handler();
+ CefRefPtr<CefV8Value> func = CefV8Value::CreateFunction(name, handler);
+ CefRefPtr<CefV8Value> obj = CefV8Context::GetCurrentContext()->GetGlobal();
+ CefV8ValueList args;
+
+ PERF_ITERATIONS_START()
+ func->ExecuteFunction(obj, args);
+ PERF_ITERATIONS_END()
+}
+
+PERF_TEST_FUNC(V8FunctionExecuteWithContext) {
+ class Handler : public CefV8Handler {
+ public:
+ Handler() {}
+ virtual bool Execute(const CefString& name,
+ CefRefPtr<CefV8Value> object,
+ const CefV8ValueList& arguments,
+ CefRefPtr<CefV8Value>& retval,
+ CefString& exception) override {
+ return true;
+ }
+ IMPLEMENT_REFCOUNTING(Handler);
+ };
+
+ CefString name = "name";
+ CefRefPtr<CefV8Handler> handler = new Handler();
+ CefRefPtr<CefV8Value> func = CefV8Value::CreateFunction(name, handler);
+ CefRefPtr<CefV8Context> context = CefV8Context::GetCurrentContext();
+ CefRefPtr<CefV8Value> obj = context->GetGlobal();
+ CefV8ValueList args;
+
+ PERF_ITERATIONS_START()
+ func->ExecuteFunctionWithContext(context, obj, args);
+ PERF_ITERATIONS_END()
+}
+
+PERF_TEST_FUNC(V8ObjectCreate) {
+ PERF_ITERATIONS_START()
+ CefRefPtr<CefV8Value> value = CefV8Value::CreateObject(nullptr, nullptr);
+ PERF_ITERATIONS_END()
+}
+
+PERF_TEST_FUNC(V8ObjectCreateWithAccessor) {
+ class Accessor : public CefV8Accessor {
+ public:
+ Accessor() {}
+ virtual bool Get(const CefString& name,
+ const CefRefPtr<CefV8Value> object,
+ CefRefPtr<CefV8Value>& retval,
+ CefString& exception) override {
+ return true;
+ }
+ virtual bool Set(const CefString& name,
+ const CefRefPtr<CefV8Value> object,
+ const CefRefPtr<CefV8Value> value,
+ CefString& exception) override {
+ return true;
+ }
+ IMPLEMENT_REFCOUNTING(Accessor);
+ };
+
+ CefRefPtr<CefV8Accessor> accessor = new Accessor();
+
+ PERF_ITERATIONS_START()
+ CefRefPtr<CefV8Value> value = CefV8Value::CreateObject(accessor, nullptr);
+ PERF_ITERATIONS_END()
+}
+
+PERF_TEST_FUNC(V8ObjectCreateWithInterceptor) {
+ class Interceptor : public CefV8Interceptor {
+ public:
+ Interceptor() {}
+ virtual bool Get(const CefString& name,
+ const CefRefPtr<CefV8Value> object,
+ CefRefPtr<CefV8Value>& retval,
+ CefString& exception) override {
+ return true;
+ }
+ virtual bool Get(int index,
+ const CefRefPtr<CefV8Value> object,
+ CefRefPtr<CefV8Value>& retval,
+ CefString& exception) override {
+ return true;
+ }
+ virtual bool Set(const CefString& name,
+ const CefRefPtr<CefV8Value> object,
+ const CefRefPtr<CefV8Value> value,
+ CefString& exception) override {
+ return true;
+ }
+ virtual bool Set(int index,
+ const CefRefPtr<CefV8Value> object,
+ const CefRefPtr<CefV8Value> value,
+ CefString& exception) override {
+ return true;
+ }
+ IMPLEMENT_REFCOUNTING(Interceptor);
+ };
+
+ CefRefPtr<CefV8Interceptor> interceptor = new Interceptor();
+
+ PERF_ITERATIONS_START()
+ CefRefPtr<CefV8Value> value = CefV8Value::CreateObject(nullptr, interceptor);
+ PERF_ITERATIONS_END()
+}
+
+PERF_TEST_FUNC(V8ObjectSetValue) {
+ CefString name = "name";
+ CefRefPtr<CefV8Value> val = CefV8Value::CreateBool(true);
+ CefRefPtr<CefV8Value> obj = CefV8Value::CreateObject(nullptr, nullptr);
+ obj->SetValue(name, val, V8_PROPERTY_ATTRIBUTE_NONE);
+
+ PERF_ITERATIONS_START()
+ obj->SetValue(name, val, V8_PROPERTY_ATTRIBUTE_NONE);
+ PERF_ITERATIONS_END()
+}
+
+PERF_TEST_FUNC(V8ObjectGetValue) {
+ CefString name = "name";
+ CefRefPtr<CefV8Value> val = CefV8Value::CreateBool(true);
+ CefRefPtr<CefV8Value> obj = CefV8Value::CreateObject(nullptr, nullptr);
+ obj->SetValue(name, val, V8_PROPERTY_ATTRIBUTE_NONE);
+
+ PERF_ITERATIONS_START()
+ CefRefPtr<CefV8Value> ret = obj->GetValue(name);
+ PERF_ITERATIONS_END()
+}
+
+PERF_TEST_FUNC(V8ObjectSetValueWithAccessor) {
+ class Accessor : public CefV8Accessor {
+ public:
+ Accessor() {}
+ virtual bool Get(const CefString& name,
+ const CefRefPtr<CefV8Value> object,
+ CefRefPtr<CefV8Value>& retval,
+ CefString& exception) override {
+ return true;
+ }
+ virtual bool Set(const CefString& name,
+ const CefRefPtr<CefV8Value> object,
+ const CefRefPtr<CefV8Value> value,
+ CefString& exception) override {
+ val_ = value;
+ return true;
+ }
+ CefRefPtr<CefV8Value> val_;
+ IMPLEMENT_REFCOUNTING(Accessor);
+ };
+
+ CefRefPtr<CefV8Accessor> accessor = new Accessor();
+
+ CefString name = "name";
+ CefRefPtr<CefV8Value> val = CefV8Value::CreateBool(true);
+ CefRefPtr<CefV8Value> obj = CefV8Value::CreateObject(accessor, nullptr);
+ obj->SetValue(name, V8_ACCESS_CONTROL_DEFAULT, V8_PROPERTY_ATTRIBUTE_NONE);
+ obj->SetValue(name, val, V8_PROPERTY_ATTRIBUTE_NONE);
+
+ PERF_ITERATIONS_START()
+ obj->SetValue(name, val, V8_PROPERTY_ATTRIBUTE_NONE);
+ PERF_ITERATIONS_END()
+}
+
+PERF_TEST_FUNC(V8ObjectGetValueWithAccessor) {
+ class Accessor : public CefV8Accessor {
+ public:
+ Accessor() : val_(CefV8Value::CreateBool(true)) {}
+ virtual bool Get(const CefString& name,
+ const CefRefPtr<CefV8Value> object,
+ CefRefPtr<CefV8Value>& retval,
+ CefString& exception) override {
+ retval = val_;
+ return true;
+ }
+ virtual bool Set(const CefString& name,
+ const CefRefPtr<CefV8Value> object,
+ const CefRefPtr<CefV8Value> value,
+ CefString& exception) override {
+ return true;
+ }
+ CefRefPtr<CefV8Value> val_;
+ IMPLEMENT_REFCOUNTING(Accessor);
+ };
+
+ CefRefPtr<CefV8Accessor> accessor = new Accessor();
+
+ CefString name = "name";
+ CefRefPtr<CefV8Value> val = CefV8Value::CreateBool(true);
+ CefRefPtr<CefV8Value> obj = CefV8Value::CreateObject(accessor, nullptr);
+ obj->SetValue(name, V8_ACCESS_CONTROL_DEFAULT, V8_PROPERTY_ATTRIBUTE_NONE);
+ obj->SetValue(name, val, V8_PROPERTY_ATTRIBUTE_NONE);
+
+ PERF_ITERATIONS_START()
+ CefRefPtr<CefV8Value> ret = obj->GetValue(name);
+ PERF_ITERATIONS_END()
+}
+
+PERF_TEST_FUNC(V8ArrayBufferCreate) {
+ class ReleaseCallback : public CefV8ArrayBufferReleaseCallback {
+ public:
+ void ReleaseBuffer(void* buffer) override { std::free(buffer); }
+ IMPLEMENT_REFCOUNTING(ReleaseCallback);
+ };
+
+ size_t len = 1;
+ size_t byte_len = len * sizeof(float);
+ CefRefPtr<CefV8ArrayBufferReleaseCallback> callback = new ReleaseCallback();
+
+ PERF_ITERATIONS_START()
+ float* buffer = (float*)std::malloc(byte_len);
+ CefRefPtr<CefV8Value> ret =
+ CefV8Value::CreateArrayBuffer(buffer, byte_len, callback);
+ PERF_ITERATIONS_END()
+}
+
+PERF_TEST_FUNC(V8ContextEnterExit) {
+ CefRefPtr<CefV8Context> context = CefV8Context::GetCurrentContext();
+
+ PERF_ITERATIONS_START()
+ context->Enter();
+ context->Exit();
+ PERF_ITERATIONS_END()
+}
+
+PERF_TEST_FUNC(V8ContextEval) {
+ CefRefPtr<CefV8Context> context = CefV8Context::GetCurrentContext();
+ CefString jsCode = "var i = 0;";
+ CefRefPtr<CefV8Value> retval;
+ CefRefPtr<CefV8Exception> exception;
+
+ PERF_ITERATIONS_START()
+ context->Eval(jsCode, CefString(), 0, retval, exception);
+ PERF_ITERATIONS_END()
+}
+
+} // namespace
+
+// Test function entries.
+
+const PerfTestEntry kPerfTests[] = {
+ PERF_TEST_ENTRY(V8NullCreate),
+ PERF_TEST_ENTRY(V8BoolCreate),
+ PERF_TEST_ENTRY(V8IntCreate),
+ PERF_TEST_ENTRY(V8UIntCreate),
+ PERF_TEST_ENTRY(V8DoubleCreate),
+ PERF_TEST_ENTRY(V8DateCreate),
+ PERF_TEST_ENTRY(V8StringCreate),
+ PERF_TEST_ENTRY(V8ArrayCreate),
+ PERF_TEST_ENTRY(V8ArraySetValue),
+ PERF_TEST_ENTRY(V8ArrayGetValue),
+ PERF_TEST_ENTRY(V8FunctionCreate),
+ PERF_TEST_ENTRY(V8FunctionExecute),
+ PERF_TEST_ENTRY(V8FunctionExecuteWithContext),
+ PERF_TEST_ENTRY(V8ObjectCreate),
+ PERF_TEST_ENTRY(V8ObjectCreateWithAccessor),
+ PERF_TEST_ENTRY(V8ObjectCreateWithInterceptor),
+ PERF_TEST_ENTRY(V8ObjectSetValue),
+ PERF_TEST_ENTRY(V8ObjectGetValue),
+ PERF_TEST_ENTRY(V8ObjectSetValueWithAccessor),
+ PERF_TEST_ENTRY(V8ObjectGetValueWithAccessor),
+ PERF_TEST_ENTRY(V8ArrayBufferCreate),
+ PERF_TEST_ENTRY(V8ContextEnterExit),
+ PERF_TEST_ENTRY(V8ContextEval),
+};
+
+const int kPerfTestsCount = (sizeof(kPerfTests) / sizeof(kPerfTests[0]));
+
+} // namespace performance_test
+} // namespace client
diff --git a/tests/cefclient/resources/binding.html b/tests/cefclient/resources/binding.html
new file mode 100644
index 00000000..855e644b
--- /dev/null
+++ b/tests/cefclient/resources/binding.html
@@ -0,0 +1,41 @@
+<html>
+<head>
+<title>Binding Test</title>
+<script language="JavaScript">
+
+function setup() {
+ if (location.hostname == 'tests' || location.hostname == 'localhost')
+ return;
+
+ alert('This page can only be run from tests or localhost.');
+
+ // Disable all elements.
+ var elements = document.getElementById("form").elements;
+ for (var i = 0, element; element = elements[i++]; ) {
+ element.disabled = true;
+ }
+}
+
+// Send a query to the browser process.
+function sendMessage() {
+ // Results in a call to the OnQuery method in binding_test.cc
+ window.cefQuery({
+ request: 'BindingTest:' + document.getElementById("message").value,
+ onSuccess: function(response) {
+ document.getElementById('result').value = 'Response: '+response;
+ },
+ onFailure: function(error_code, error_message) {}
+ });
+}
+</script>
+
+</head>
+<body bgcolor="white" onload="setup()">
+<form id="form">
+Message: <input type="text" id="message" value="My Message">
+<br/><input type="button" onclick="sendMessage();" value="Send Message">
+<br/>You should see the reverse of your message below:
+<br/><textarea rows="10" cols="40" id="result"></textarea>
+</form>
+</body>
+</html>
diff --git a/tests/cefclient/resources/dialogs.html b/tests/cefclient/resources/dialogs.html
new file mode 100644
index 00000000..537011a1
--- /dev/null
+++ b/tests/cefclient/resources/dialogs.html
@@ -0,0 +1,80 @@
+<html>
+<head>
+<title>Dialog Test</title>
+<script>
+function show_alert() {
+ alert("I am an alert box!");
+}
+
+function show_confirm() {
+ var r = confirm("Press a button");
+ var msg = r ? "You pressed OK!" : "You pressed Cancel!";
+ document.getElementById('cm').innerText = msg;
+}
+
+function show_prompt() {
+ var name = prompt("Please enter your name" ,"Harry Potter");
+ if (name != null && name != "")
+ document.getElementById('pm').innerText = "Hello " + name + "!";
+}
+
+window.onbeforeunload = function() {
+ return 'This is an onbeforeunload message.';
+}
+
+function update_time() {
+ document.getElementById('time').innerText = new Date().toLocaleString();
+}
+
+function setup() {
+ update_time();
+ setInterval(update_time, 1000);
+
+ if (location.hostname != 'tests' && location.hostname != 'localhost') {
+ alert('Parts of this page can only be run from tests or localhost.');
+ return;
+ }
+
+ // Enable all elements.
+ var elements = document.getElementById("form").elements;
+ for (var i = 0, element; element = elements[i++]; ) {
+ element.disabled = false;
+ }
+}
+
+function show_file_dialog(element, test) {
+ var message = 'DialogTest.' + test;
+ var target = document.getElementById(element);
+
+ // Results in a call to the OnQuery method in dialog_test.cpp
+ window.cefQuery({
+ request: message,
+ onSuccess: function(response) {
+ target.innerText = response;
+ },
+ onFailure: function(error_code, error_message) {}
+ });
+}
+
+window.addEventListener('load', setup, false);
+</script>
+</head>
+<body bgcolor="white">
+<form id="form">
+Click a button to show the associated dialog type.
+<br/><input type="button" onclick="show_alert();" value="Show Alert">
+<br/><input type="button" onclick="show_confirm();" value="Show Confirm"> <span id="cm"></span>
+<br/><input type="button" onclick="show_prompt();" value="Show Prompt"> <span id="pm"></span>
+<br/>input type="file" (.png): <input type="file" name="pic" accept=".png">
+<br/>input type="file" (image/*): <input type="file" name="pic" accept="image/*">
+<br/>input type="file" (multiple types): <input type="file" name="pic" accept="text/*,.js,.css,image/*">
+<br/>input type="file" (directory): <input type="file" webkitdirectory accept="text/*,.js,.css,image/*">
+<br/><input type="button" onclick="show_file_dialog('fop', 'FileOpenPng');" value="Show File Open (.png)" disabled="true"> <span id="fop"></span>
+<br/><input type="button" onclick="show_file_dialog('foi', 'FileOpenImage');" value="Show File Open (image/*)" disabled="true"> <span id="foi"></span>
+<br/><input type="button" onclick="show_file_dialog('fom', 'FileOpenMultiple');" value="Show File Open (multiple types/files)" disabled="true"> <span id="fom"></span>
+<br/><input type="button" onclick="show_file_dialog('fof', 'FileOpenFolder');" value="Show File Open Folder" disabled="true"> <span id="fof"></span>
+<br/><input type="button" onclick="show_file_dialog('fs', 'FileSave');" value="Show File Save" disabled="true"> <span id="fs"></span>
+<p id="time"></p>
+</form>
+</body>
+</html>
diff --git a/tests/cefclient/resources/draggable.html b/tests/cefclient/resources/draggable.html
new file mode 100644
index 00000000..354ed57a
--- /dev/null
+++ b/tests/cefclient/resources/draggable.html
@@ -0,0 +1,55 @@
+<html>
+<head>
+<title>Draggable Regions Test</title>
+<style>
+html, body {
+ height: 100%;
+ overflow: hidden;
+}
+.draggable-title {
+ -webkit-app-region: drag;
+ position: absolute;
+ top: 0px;
+ left: 0px;
+ width: 100%;
+ height: 34px;
+ background-color: white;
+ opacity: .5;
+}
+.content {
+ margin-top: 34px;
+ background-color: white;
+}
+.draggable {
+ -webkit-app-region: drag;
+ position: absolute;
+ top: 125px;
+ left: 50px;
+ width: 200px;
+ height: 200px;
+ background-color: red;
+}
+.nondraggable {
+ -webkit-app-region: no-drag;
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ width: 50px;
+ height: 50px;
+ background-color: blue;
+}
+</style>
+</head>
+<body>
+ <div class="draggable-title"></div>
+ <div class="content">
+ Draggable regions can be defined using the -webkit-app-region CSS property.
+ <br/>In the below example the red region is draggable and the blue sub-region is non-draggable.
+ <br/>Windows can be resized by default and closed using JavaScript <a href="#" onClick="window.close(); return false;">window.close()</a>.
+ </div>
+ <div class="draggable">
+ <div class="nondraggable"></div>
+ </div>
+</body>
+</html> \ No newline at end of file
diff --git a/tests/cefclient/resources/extensions/set_page_color/README.md b/tests/cefclient/resources/extensions/set_page_color/README.md
new file mode 100644
index 00000000..550bac34
--- /dev/null
+++ b/tests/cefclient/resources/extensions/set_page_color/README.md
@@ -0,0 +1,17 @@
+# Color Extension
+
+Demonstrates basic extension app loading and integration by using a popup to change the page color.
+
+## Usage
+
+Run `cefclient --load-extension=set_page_color`.
+
+When using the Views framework (`--use-views`) an extension icon will be added to the control bar and clicking the icon will open the extension window. When not using the Views framework an extension window will be opened automatically on application start.
+
+## Implementation
+
+Based on the [set_page_color](https://developer.chrome.com/extensions/samples#search:browser%20action%20with%20a%20popup) example extension.
+
+Calls:
+
+ * [tabs.executeScript](https://developer.chrome.com/extensions/tabs#method-executeScript)
diff --git a/tests/cefclient/resources/extensions/set_page_color/icon.png b/tests/cefclient/resources/extensions/set_page_color/icon.png
new file mode 100644
index 00000000..46819c73
--- /dev/null
+++ b/tests/cefclient/resources/extensions/set_page_color/icon.png
Binary files differ
diff --git a/tests/cefclient/resources/extensions/set_page_color/manifest.json b/tests/cefclient/resources/extensions/set_page_color/manifest.json
new file mode 100644
index 00000000..48f551d9
--- /dev/null
+++ b/tests/cefclient/resources/extensions/set_page_color/manifest.json
@@ -0,0 +1,14 @@
+{
+ "name": "A browser action with a popup that changes the page color",
+ "description": "Change the current page color",
+ "version": "1.0",
+ "permissions": [
+ "tabs", "http://*/*", "https://*/*"
+ ],
+ "browser_action": {
+ "default_title": "Set this page's color.",
+ "default_icon": "icon.png",
+ "default_popup": "popup.html"
+ },
+ "manifest_version": 2
+}
diff --git a/tests/cefclient/resources/extensions/set_page_color/popup.html b/tests/cefclient/resources/extensions/set_page_color/popup.html
new file mode 100644
index 00000000..bf1b42b3
--- /dev/null
+++ b/tests/cefclient/resources/extensions/set_page_color/popup.html
@@ -0,0 +1,55 @@
+<!doctype html>
+<html>
+ <head>
+ <title>Set Page Color Popup</title>
+ <style>
+ body {
+ overflow: hidden;
+ margin: 0px;
+ padding: 0px;
+ background: white;
+ }
+
+ div:first-child {
+ margin-top: 0px;
+ }
+
+ div {
+ cursor: pointer;
+ text-align: center;
+ padding: 1px 3px;
+ font-family: sans-serif;
+ font-size: 0.8em;
+ width: 100px;
+ margin-top: 1px;
+ background: #cccccc;
+ }
+ div:hover {
+ background: #aaaaaa;
+ }
+ #red {
+ border: 1px solid red;
+ color: red;
+ }
+ #blue {
+ border: 1px solid blue;
+ color: blue;
+ }
+ #green {
+ border: 1px solid green;
+ color: green;
+ }
+ #yellow {
+ border: 1px solid yellow;
+ color: yellow;
+ }
+ </style>
+ <script src="popup.js"></script>
+ </head>
+ <body>
+ <div id="red">red</div>
+ <div id="blue">blue</div>
+ <div id="green">green</div>
+ <div id="yellow">yellow</div>
+ </body>
+</html>
diff --git a/tests/cefclient/resources/extensions/set_page_color/popup.js b/tests/cefclient/resources/extensions/set_page_color/popup.js
new file mode 100644
index 00000000..6f627087
--- /dev/null
+++ b/tests/cefclient/resources/extensions/set_page_color/popup.js
@@ -0,0 +1,16 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+
+function click(e) {
+ chrome.tabs.executeScript(null,
+ {code:"document.body.style.backgroundColor='" + e.target.id + "'"});
+}
+
+document.addEventListener('DOMContentLoaded', function () {
+ var divs = document.querySelectorAll('div');
+ for (var i = 0; i < divs.length; i++) {
+ divs[i].addEventListener('click', click);
+ }
+});
diff --git a/tests/cefclient/resources/ipc_performance.html b/tests/cefclient/resources/ipc_performance.html
new file mode 100644
index 00000000..ea05175c
--- /dev/null
+++ b/tests/cefclient/resources/ipc_performance.html
@@ -0,0 +1,448 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>IPC Performance Tests</title>
+ <script src="https://cdn.plot.ly/plotly-2.12.1.min.js"></script>
+ <style>
+ body {
+ font-family: Tahoma, Serif;
+ font-size: 10pt;
+ }
+
+ .left {
+ text-align: left;
+ }
+
+ .right {
+ text-align: right;
+ }
+
+ .positive {
+ color: green;
+ font-weight: bold;
+ }
+
+ .negative {
+ color: red;
+ font-weight: bold;
+ }
+
+ .center {
+ text-align: center;
+ }
+
+ table.resultTable {
+ border: 1px solid black;
+ border-collapse: collapse;
+ empty-cells: show;
+ width: 100%;
+ }
+
+ table.resultTable td {
+ padding: 2px 4px;
+ border: 1px solid black;
+ }
+
+ table.resultTable > thead > tr {
+ font-weight: bold;
+ background: lightblue;
+ }
+
+ table.resultTable > tbody > tr:nth-child(odd) {
+ background: white;
+ }
+
+ table.resultTable > tbody > tr:nth-child(even) {
+ background: lightgray;
+ }
+
+ .hide {
+ display: none;
+ }
+ </style>
+ </head>
+
+ <body background-color="white">
+ <h1>IPC Performance Tests</h1>
+
+ <table>
+ <tr>
+ <td>
+ <p>
+ There is no progress indication of the tests because it
+ significantly influences measurements. <br />It usually takes 30
+ seconds (for 100 samples) to complete the tests. <br /><b>AL</b> -
+ ArgumentList-based process messages. <b>SM</b> -
+ SharedMemoryRegion-based process messages.
+ </p>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ Samples:
+ <input
+ id="sSamples"
+ type="text"
+ value="100"
+ required
+ pattern="[0-9]+"
+ />
+ <button id="sRun" autofocus onclick="runTestSuite()">Run</button>
+ </td>
+ </tr>
+ </table>
+
+ <div style="padding-top: 10px; padding-bottom: 10px">
+ <table id="resultTable" class="resultTable">
+ <thead>
+ <tr>
+ <td class="center" style="width: 8%">Message Size</td>
+ <td class="center" style="width: 8%">AL Round Trip Avg,&nbsp;ms</td>
+ <td class="center" style="width: 8%">SM Round Trip Avg,&nbsp;ms</td>
+ <td class="center" style="width: 10%">Relative Trip Difference</td>
+ <td class="center" style="width: 8%">AL Speed,&nbsp;MB/s</td>
+ <td class="center" style="width: 8%">SM Speed,&nbsp;MB/s</td>
+ <td class="center" style="width: 10%">Relative Speed Difference</td>
+ <td class="center" style="width: 8%">AL Standard Deviation</td>
+ <td class="center" style="width: 8%">SM Standard Deviation</td>
+ </tr>
+ </thead>
+ <tbody>
+ <!-- result rows here -->
+ </tbody>
+ </table>
+ </div>
+
+ <div id="round_trip_avg_chart">
+ <!-- Average round trip linear chart will be drawn inside this DIV -->
+ </div>
+
+ <div id="box_plot_chart">
+ <!-- Box plot of round trip time will be drawn inside this DIV -->
+ </div>
+
+ <script type="text/javascript">
+ let tests = [];
+ let box_plot_test_data = [];
+ let round_trip_avg_plot_data = [];
+
+ function nextTest(test) {
+ setTimeout(() => {
+ execNextTest(test.index);
+ }, 0);
+ }
+
+ function testSendProcessMessageResult(
+ testIndex,
+ fromRendererToBrowser,
+ fromBrowserToRenderer
+ ) {
+ const test = tests[testIndex];
+
+ const roundTrip = fromRendererToBrowser + fromBrowserToRenderer;
+ test.totalRoundTrip += roundTrip;
+ test.sample++;
+ box_plot_test_data[testIndex].x.push(roundTrip);
+
+ setTimeout(() => {
+ execTest(testIndex);
+ }, 10);
+ }
+
+ function sendRequest(size, testIndex) {
+ window.testSendProcessMessage({
+ size: size,
+ testId: testIndex,
+ });
+ }
+
+ function sendSMRRequest(size, testIndex) {
+ window.testSendSMRProcessMessage({
+ size: size,
+ testId: testIndex,
+ });
+ }
+
+ function getStandardDeviation(array, mean) {
+ const n = array.length;
+ if (n < 5) return null;
+ return Math.sqrt(
+ array.map((x) => Math.pow(x - mean, 2)).reduce((a, b) => a + b) /
+ (n - 1)
+ );
+ }
+
+ function execTest(testIndex) {
+ const test = tests[testIndex];
+
+ if (test.sample >= test.totalSamples) {
+ return nextTest(test);
+ }
+
+ test.func(test.index);
+ }
+
+ function column(prepared, value) {
+ return (
+ "<td class='right'>" + (!prepared ? "-" : value.toFixed(2)) + "</td>"
+ );
+ }
+
+ function relativeDiffColumn(prepared, value, isBiggerBetter) {
+ if (!prepared) return "<td class='right'>-</td>";
+
+ const isPositive = value > 0 == isBiggerBetter;
+ return [
+ "<td class='right ",
+ isPositive ? "positive" : "negative",
+ "'>",
+ value > 0 ? "+" : "",
+ value.toFixed(2),
+ "%</td>",
+ ].join("");
+ }
+
+ function displayResult(test) {
+ const id = "testResultRow_" + test.index;
+
+ const markup = [
+ "<tr id='",
+ id,
+ "'>",
+ "<td class='left'>",
+ test.name,
+ "</td>",
+ column(test.prepared, test.avgRoundTrip),
+ column(test.prepared, test.avgRoundTripSMR),
+ relativeDiffColumn(test.prepared, test.relativeTripDiff, false),
+ column(test.prepared, test.speed),
+ column(test.prepared, test.speedSMR),
+ relativeDiffColumn(test.prepared, test.relativeSpeedDiff, true),
+ "<td class='right'>",
+ !test.prepared || test.stdDeviation == null
+ ? "-"
+ : test.stdDeviation.toFixed(2),
+ "</td>",
+ "<td class='right'>",
+ !test.prepared || test.stdDeviationSMR == null
+ ? "-"
+ : test.stdDeviationSMR.toFixed(2),
+ "</td>",
+ "</tr>",
+ ].join("");
+
+ const row = document.getElementById(id);
+ if (row) {
+ row.outerHTML = markup;
+ } else {
+ const tbody = document.getElementById("resultTable").tBodies[0];
+ tbody.insertAdjacentHTML("beforeEnd", markup);
+ }
+ }
+
+ function buildTestResults(tests) {
+ testResults = [];
+
+ let oldRoundTrip = {
+ x: [],
+ y: [],
+ type: "scatter",
+ name: "ArgumentList",
+ };
+
+ let newRoundTrip = {
+ x: [],
+ y: [],
+ type: "scatter",
+ name: "SharedMemoryRegion",
+ };
+
+ for (let i = 0; i < tests.length / 2; i++) {
+ const index = testResults.length;
+
+ const test = tests[i * 2];
+ const testSMR = tests[i * 2 + 1];
+
+ const avgRoundTrip = test.totalRoundTrip / test.totalSamples;
+ const avgRoundTripSMR = testSMR.totalRoundTrip / testSMR.totalSamples;
+ const relativeTripDiff =
+ ((avgRoundTripSMR - avgRoundTrip) / avgRoundTrip) * 100;
+
+ // In MB/s
+ const speed = test.messageSize / (avgRoundTrip * 1000);
+ const speedSMR = testSMR.messageSize / (avgRoundTripSMR * 1000);
+ const relativeSpeedDiff = ((speedSMR - speed) / speed) * 100;
+
+ const stdDeviation = getStandardDeviation(
+ box_plot_test_data[test.index].x,
+ avgRoundTrip
+ );
+ const stdDeviationSMR = getStandardDeviation(
+ box_plot_test_data[testSMR.index].x,
+ avgRoundTripSMR
+ );
+
+ testResults.push({
+ name: humanFileSize(test.messageSize),
+ index: index,
+ prepared: true,
+ avgRoundTrip: avgRoundTrip,
+ avgRoundTripSMR: avgRoundTripSMR,
+ relativeTripDiff: relativeTripDiff,
+ speed: speed,
+ speedSMR: speedSMR,
+ relativeSpeedDiff: relativeSpeedDiff,
+ stdDeviation: stdDeviation,
+ stdDeviationSMR: stdDeviationSMR,
+ });
+
+ oldRoundTrip.x.push(test.messageSize);
+ newRoundTrip.x.push(test.messageSize);
+ oldRoundTrip.y.push(avgRoundTrip);
+ newRoundTrip.y.push(avgRoundTripSMR);
+ }
+
+ round_trip_avg_plot_data = [oldRoundTrip, newRoundTrip];
+ return testResults;
+ }
+
+ function buildEmptyTestResults(tests) {
+ testResults = [];
+ for (let i = 0; i < tests.length / 2; i++) {
+ const index = testResults.length;
+ const test = tests[i * 2];
+
+ testResults.push({
+ name: humanFileSize(test.messageSize),
+ index: index,
+ prepared: false,
+ });
+ }
+ return testResults;
+ }
+
+ function prepareQueuedTests(totalSamples) {
+ if (totalSamples <= 0) totalSamples = 1;
+
+ tests.forEach((test) => {
+ test.sample = 0;
+ test.totalRoundTrip = 0;
+ test.totalSamples = totalSamples;
+ });
+
+ testResults = buildEmptyTestResults(tests);
+ testResults.forEach((result) => displayResult(result));
+
+ round_trip_avg_plot_data = [];
+ box_plot_test_data.forEach((data) => {
+ data.x = [];
+ });
+ }
+
+ function queueTest(name, messageSize, testFunc) {
+ const testIndex = tests.length;
+ test = {
+ name: name,
+ messageSize: messageSize,
+ index: testIndex,
+ func: testFunc,
+ };
+ tests.push(test);
+
+ box_plot_test_data.push({
+ x: [],
+ type: "box",
+ boxpoints: "all",
+ name: name,
+ jitter: 0.3,
+ pointpos: -1.8,
+ });
+ }
+
+ function execNextTest(testIndex) {
+ testIndex++;
+ if (tests.length <= testIndex) {
+ return testSuiteFinished();
+ } else {
+ return execTest(testIndex);
+ }
+ }
+
+ function execQueuedTests(totalSamples) {
+ prepareQueuedTests(totalSamples);
+ // Let the updated table render before starting the tests
+ setTimeout(() => execNextTest(-1), 200);
+ }
+
+ function setSettingsState(disabled) {
+ document.getElementById("sSamples").disabled = disabled;
+ document.getElementById("sRun").disabled = disabled;
+ }
+
+ function testSuiteFinished() {
+ testResults = buildTestResults(tests);
+ testResults.forEach((result) => displayResult(result));
+
+ const round_trip_layout = {
+ title: "Average round trip, ms (Smaller Better)",
+ };
+ Plotly.newPlot(
+ "round_trip_avg_chart",
+ round_trip_avg_plot_data,
+ round_trip_layout
+ );
+
+ const box_plot_layout = {
+ title: "Round Trip Time, ms",
+ };
+ Plotly.newPlot("box_plot_chart", box_plot_test_data, box_plot_layout);
+ setSettingsState(false);
+ }
+
+ function humanFileSize(bytes) {
+ const step = 1024;
+ const originalBytes = bytes;
+
+ if (Math.abs(bytes) < step) {
+ return bytes + " B";
+ }
+
+ const units = [" KB", " MB", " GB"];
+ let u = -1;
+ let count = 0;
+
+ do {
+ bytes /= step;
+ u += 1;
+ count += 1;
+ } while (Math.abs(bytes) >= step && u < units.length - 1);
+
+ return bytes.toString() + units[u];
+ }
+
+ window.runTestSuite = () => {
+ Plotly.purge("round_trip_avg_chart");
+ Plotly.purge("box_plot_chart");
+ setSettingsState(true);
+ const totalSamples = parseInt(
+ document.getElementById("sSamples").value
+ );
+ execQueuedTests(totalSamples);
+ return false;
+ };
+
+ for (let size = 512; size <= 512 * 1024; size = size * 2) {
+ queueTest(humanFileSize(size) + " AL", size, (testIndex) =>
+ sendRequest(size, testIndex)
+ );
+
+ queueTest(humanFileSize(size) + " SM", size, (testIndex) =>
+ sendSMRRequest(size, testIndex)
+ );
+ }
+
+ const totalSamples = parseInt(document.getElementById("sSamples").value);
+ prepareQueuedTests(totalSamples);
+ </script>
+ </body>
+</html> \ No newline at end of file
diff --git a/tests/cefclient/resources/localstorage.html b/tests/cefclient/resources/localstorage.html
new file mode 100644
index 00000000..87c6e68c
--- /dev/null
+++ b/tests/cefclient/resources/localstorage.html
@@ -0,0 +1,24 @@
+<html>
+<body bgcolor="white">
+<script language="JavaScript">
+var val = window.localStorage.getItem('val');
+function addLine() {
+ if(val == null)
+ val = '<br/>One Line.';
+ else
+ val += '<br/>Another Line.';
+ window.localStorage.setItem('val', val);
+ document.getElementById('out').innerHTML = val;
+}
+</script>
+Click the "Add Line" button to add a line or the "Clear" button to clear.<br/>
+This data will persist across sessions if a cache path was specified.<br/>
+<input type="button" value="Add Line" onClick="addLine();"/>
+<input type="button" value="Clear" onClick="window.localStorage.removeItem('val'); window.location.reload();"/>
+<div id="out"></div>
+<script language="JavaScript">
+if(val != null)
+ document.getElementById('out').innerHTML = val;
+</script>
+</body>
+</html>
diff --git a/tests/cefclient/resources/logo.png b/tests/cefclient/resources/logo.png
new file mode 100644
index 00000000..a2a15f44
--- /dev/null
+++ b/tests/cefclient/resources/logo.png
Binary files differ
diff --git a/tests/cefclient/resources/mac/English.lproj/InfoPlist.strings b/tests/cefclient/resources/mac/English.lproj/InfoPlist.strings
new file mode 100644
index 00000000..fe2abe11
--- /dev/null
+++ b/tests/cefclient/resources/mac/English.lproj/InfoPlist.strings
@@ -0,0 +1,3 @@
+/* Localized versions of Info.plist keys */
+
+NSHumanReadableCopyright = "© Chromium Embedded Framework Authors, 2010";
diff --git a/tests/cefclient/resources/mac/English.lproj/MainMenu.xib b/tests/cefclient/resources/mac/English.lproj/MainMenu.xib
new file mode 100644
index 00000000..18109db3
--- /dev/null
+++ b/tests/cefclient/resources/mac/English.lproj/MainMenu.xib
@@ -0,0 +1,427 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="10117" systemVersion="16B2657" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
+ <dependencies>
+ <deployment version="1090" identifier="macosx"/>
+ <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="10117"/>
+ </dependencies>
+ <objects>
+ <customObject id="-2" userLabel="File's Owner" customClass="ClientAppDelegate"/>
+ <customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
+ <customObject id="-3" userLabel="Application" customClass="NSObject"/>
+ <menu title="AMainMenu" systemMenu="main" id="29" userLabel="MainMenu">
+ <items>
+ <menuItem title="cefclient" tag="1" id="56">
+ <menu key="submenu" title="TestShell" systemMenu="apple" id="57">
+ <items>
+ <menuItem title="About cefclient" id="58">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="orderFrontStandardAboutPanel:" target="-2" id="142"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="236">
+ <modifierMask key="keyEquivalentModifierMask" command="YES"/>
+ </menuItem>
+ <menuItem title="Preferences…" keyEquivalent="," id="129" userLabel="121"/>
+ <menuItem isSeparatorItem="YES" id="143">
+ <modifierMask key="keyEquivalentModifierMask" command="YES"/>
+ </menuItem>
+ <menuItem title="Services" id="131">
+ <menu key="submenu" title="Services" systemMenu="services" id="130"/>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="144">
+ <modifierMask key="keyEquivalentModifierMask" command="YES"/>
+ </menuItem>
+ <menuItem title="Hide cefclient" keyEquivalent="h" id="134">
+ <connections>
+ <action selector="hide:" target="-1" id="367"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Hide Others" keyEquivalent="h" id="145">
+ <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
+ <connections>
+ <action selector="hideOtherApplications:" target="-1" id="368"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Show All" id="150">
+ <connections>
+ <action selector="unhideAllApplications:" target="-1" id="370"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="149">
+ <modifierMask key="keyEquivalentModifierMask" command="YES"/>
+ </menuItem>
+ <menuItem title="Quit cefclient" keyEquivalent="q" id="136" userLabel="1111">
+ <connections>
+ <action selector="terminate:" target="-1" id="369"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="File" tag="2" id="83">
+ <menu key="submenu" title="File" id="81">
+ <items>
+ <menuItem title="New" keyEquivalent="n" id="82" userLabel="9">
+ <connections>
+ <action selector="newDocument:" target="-1" id="373"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Open…" keyEquivalent="o" id="72">
+ <connections>
+ <action selector="openDocument:" target="-1" id="374"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Open Recent" id="124">
+ <menu key="submenu" title="Open Recent" systemMenu="recentDocuments" id="125">
+ <items>
+ <menuItem title="Clear Menu" id="126">
+ <connections>
+ <action selector="clearRecentDocuments:" target="-1" id="127"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="79" userLabel="7">
+ <modifierMask key="keyEquivalentModifierMask" command="YES"/>
+ </menuItem>
+ <menuItem title="Close" keyEquivalent="w" id="73" userLabel="1">
+ <connections>
+ <action selector="performClose:" target="-1" id="193"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Save" keyEquivalent="s" id="75" userLabel="3">
+ <connections>
+ <action selector="saveDocument:" target="-1" id="362"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Save As…" keyEquivalent="S" id="80" userLabel="8">
+ <modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
+ <connections>
+ <action selector="saveDocumentAs:" target="-1" id="363"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Revert to Saved" id="112" userLabel="10">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="revertDocumentToSaved:" target="-1" id="364"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="74" userLabel="2">
+ <modifierMask key="keyEquivalentModifierMask" command="YES"/>
+ </menuItem>
+ <menuItem title="Page Setup..." keyEquivalent="P" id="77" userLabel="5">
+ <modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
+ <connections>
+ <action selector="runPageLayout:" target="-1" id="87"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Print…" keyEquivalent="p" id="78" userLabel="6">
+ <connections>
+ <action selector="print:" target="-1" id="86"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="Edit" tag="3" id="217">
+ <menu key="submenu" title="Edit" id="205">
+ <items>
+ <menuItem title="Undo" keyEquivalent="z" id="207">
+ <connections>
+ <action selector="undo:" target="-1" id="223"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Redo" keyEquivalent="Z" id="215">
+ <modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
+ <connections>
+ <action selector="redo:" target="-1" id="231"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="206">
+ <modifierMask key="keyEquivalentModifierMask" command="YES"/>
+ </menuItem>
+ <menuItem title="Cut" keyEquivalent="x" id="199">
+ <connections>
+ <action selector="cut:" target="-1" id="228"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Copy" keyEquivalent="c" id="197">
+ <connections>
+ <action selector="copy:" target="-1" id="224"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Paste" keyEquivalent="v" id="203">
+ <connections>
+ <action selector="paste:" target="-1" id="226"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Delete" id="202">
+ <connections>
+ <action selector="delete:" target="-1" id="235"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Select All" keyEquivalent="a" id="198">
+ <connections>
+ <action selector="selectAll:" target="-1" id="232"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="214">
+ <modifierMask key="keyEquivalentModifierMask" command="YES"/>
+ </menuItem>
+ <menuItem title="Find" id="218">
+ <menu key="submenu" title="Find" id="220">
+ <items>
+ <menuItem title="Find…" tag="1" keyEquivalent="f" id="209">
+ <connections>
+ <action selector="performFindPanelAction:" target="-1" id="241"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Find Next" tag="2" keyEquivalent="g" id="208"/>
+ <menuItem title="Find Previous" tag="3" keyEquivalent="G" id="213">
+ <modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
+ </menuItem>
+ <menuItem title="Use Selection for Find" tag="7" keyEquivalent="e" id="221"/>
+ <menuItem title="Jump to Selection" keyEquivalent="j" id="210">
+ <connections>
+ <action selector="centerSelectionInVisibleArea:" target="-1" id="245"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="Spelling and Grammar" id="216">
+ <menu key="submenu" title="Spelling and Grammar" id="200">
+ <items>
+ <menuItem title="Show Spelling…" keyEquivalent=":" id="204">
+ <connections>
+ <action selector="showGuessPanel:" target="-1" id="230"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Check Spelling" keyEquivalent=";" id="201">
+ <connections>
+ <action selector="checkSpelling:" target="-1" id="225"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Check Spelling While Typing" id="219">
+ <connections>
+ <action selector="toggleContinuousSpellChecking:" target="-1" id="222"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Check Grammar With Spelling" id="346">
+ <connections>
+ <action selector="toggleGrammarChecking:" target="-1" id="347"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="Substitutions" id="348">
+ <menu key="submenu" title="Substitutions" id="349">
+ <items>
+ <menuItem title="Smart Copy/Paste" tag="1" keyEquivalent="f" id="350">
+ <connections>
+ <action selector="toggleSmartInsertDelete:" target="-1" id="355"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Smart Quotes" tag="2" keyEquivalent="g" id="351">
+ <connections>
+ <action selector="toggleAutomaticQuoteSubstitution:" target="-1" id="356"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Smart Links" tag="3" keyEquivalent="G" id="354">
+ <modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
+ <connections>
+ <action selector="toggleAutomaticLinkDetection:" target="-1" id="357"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="Speech" id="211">
+ <menu key="submenu" title="Speech" id="212">
+ <items>
+ <menuItem title="Start Speaking" id="196">
+ <connections>
+ <action selector="startSpeaking:" target="-1" id="233"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Stop Speaking" id="195">
+ <connections>
+ <action selector="stopSpeaking:" target="-1" id="227"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="Format" tag="4" id="299">
+ <menu key="submenu" title="Format" id="300">
+ <items>
+ <menuItem title="Show Fonts" keyEquivalent="t" id="344"/>
+ <menuItem title="Show Colors" keyEquivalent="C" id="345">
+ <modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
+ <connections>
+ <action selector="orderFrontColorPanel:" target="-1" id="361"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="View" tag="5" id="295">
+ <menu key="submenu" title="View" id="296">
+ <items>
+ <menuItem title="Show Toolbar" keyEquivalent="t" id="297">
+ <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
+ <connections>
+ <action selector="toggleToolbarShown:" target="-1" id="366"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Customize Toolbar…" id="298">
+ <connections>
+ <action selector="runToolbarCustomizationPalette:" target="-1" id="365"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="Window" tag="6" id="19">
+ <menu key="submenu" title="Window" systemMenu="window" id="24">
+ <items>
+ <menuItem title="Minimize" keyEquivalent="m" id="23">
+ <connections>
+ <action selector="performMiniaturize:" target="-1" id="37"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Zoom" id="239">
+ <connections>
+ <action selector="performZoom:" target="-1" id="240"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="92">
+ <modifierMask key="keyEquivalentModifierMask" command="YES"/>
+ </menuItem>
+ <menuItem title="Bring All to Front" id="5">
+ <connections>
+ <action selector="arrangeInFront:" target="-1" id="39"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="Help" tag="7" id="103" userLabel="1">
+ <menu key="submenu" title="Help" id="106" userLabel="2">
+ <items>
+ <menuItem title="cefclient Help" keyEquivalent="?" id="111">
+ <connections>
+ <action selector="showHelp:" target="-1" id="360"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="Tests" tag="8" id="Yv2-Jq-Amk">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <menu key="submenu" title="Tests" id="CkQ-OF-S73">
+ <items>
+ <menuItem title="Get Text" id="Lpo-DT-bV3">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="menuTestsGetText:" target="-2" id="wHm-G4-hGW"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Get Source" id="hhS-PS-Frj">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="menuTestsGetSource:" target="-2" id="zj9-5Y-5WK"/>
+ </connections>
+ </menuItem>
+ <menuItem title="New Window" id="I90-8O-ZQB">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="menuTestsWindowNew:" target="-2" id="vBa-IJ-3KK"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Popup Window" id="a52-WG-ltY">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="menuTestsWindowPopup:" target="-2" id="8GQ-Ph-2iP"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Request" id="Ymm-D1-9xh">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="menuTestsRequest:" target="-2" id="bT6-It-UE3"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Zoom In" id="l8B-JC-657">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="menuTestsZoomIn:" target="-2" id="5Eq-yz-nca"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Zoom Out" id="XSc-wR-sjC">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="menuTestsZoomOut:" target="-2" id="xv5-EK-MeY"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Zoom Reset" id="CvI-5Y-Daf">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="menuTestsZoomReset:" target="-2" id="gHk-RN-RLz"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Set FPS" id="pJQ-OF-Zof">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="menuTestsSetFPS:" target="-2" id="tmx-Ro-ryG"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Set Scale Factor" id="NSu-VF-AOB">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="menuTestsSetScaleFactor:" target="-2" id="S47-BI-RtO"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Begin Tracing" id="na7-bM-yBE">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="menuTestsTracingBegin:" target="-2" id="kx2-uj-cIe"/>
+ </connections>
+ </menuItem>
+ <menuItem title="End Tracing" id="q8j-Jh-DDj">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="menuTestsTracingEnd:" target="-2" id="dtx-FX-x9L"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Print" id="gXe-px-Ble">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="menuTestsPrint:" target="-2" id="Ovd-bh-UYy"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Print to PDF" id="khT-ti-jYy">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="menuTestsPrintToPdf:" target="-2" id="f8B-MA-teX"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Other Tests" id="7VD-bm-EOX">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="menuTestsOtherTests:" target="-2" id="HbC-QY-Pwf"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ </items>
+ </menu>
+ <userDefaultsController representsSharedInstance="YES" id="389"/>
+ </objects>
+</document>
diff --git a/tests/cefclient/resources/mac/Info.plist b/tests/cefclient/resources/mac/Info.plist
new file mode 100644
index 00000000..5e7e36d4
--- /dev/null
+++ b/tests/cefclient/resources/mac/Info.plist
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleIconFile</key>
+ <string>cefclient.icns</string>
+ <key>CFBundleIdentifier</key>
+ <string>org.cef.cefclient</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1.0</string>
+ <key>LSEnvironment</key>
+ <dict>
+ <key>MallocNanoZone</key>
+ <string>0</string>
+ </dict>
+ <key>LSMinimumSystemVersion</key>
+ <string>10.13.0</string>
+ <key>NSMainNibFile</key>
+ <string>MainMenu</string>
+ <key>NSPrincipalClass</key>
+ <string>NSApplication</string>
+ <key>NSSupportsAutomaticGraphicsSwitching</key>
+ <true/>
+</dict>
+</plist>
diff --git a/tests/cefclient/resources/mac/cefclient.icns b/tests/cefclient/resources/mac/cefclient.icns
new file mode 100644
index 00000000..f36742de
--- /dev/null
+++ b/tests/cefclient/resources/mac/cefclient.icns
Binary files differ
diff --git a/tests/cefclient/resources/mac/helper-Info.plist b/tests/cefclient/resources/mac/helper-Info.plist
new file mode 100644
index 00000000..bee1aa47
--- /dev/null
+++ b/tests/cefclient/resources/mac/helper-Info.plist
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>en</string>
+ <key>CFBundleDisplayName</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleIdentifier</key>
+ <string>org.cef.cefclient.helper${BUNDLE_ID_SUFFIX}</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>LSEnvironment</key>
+ <dict>
+ <key>MallocNanoZone</key>
+ <string>0</string>
+ </dict>
+ <key>LSFileQuarantineEnabled</key>
+ <true/>
+ <key>LSMinimumSystemVersion</key>
+ <string>10.13.0</string>
+ <key>LSUIElement</key>
+ <string>1</string>
+ <key>NSSupportsAutomaticGraphicsSwitching</key>
+ <true/>
+</dict>
+</plist>
diff --git a/tests/cefclient/resources/media_router.html b/tests/cefclient/resources/media_router.html
new file mode 100644
index 00000000..0e874ff4
--- /dev/null
+++ b/tests/cefclient/resources/media_router.html
@@ -0,0 +1,592 @@
+<html>
+<head>
+<style>
+body {
+ font-family: Verdana, Arial;
+ font-size: 12px;
+}
+
+/* Give the same font styling to form elements. */
+input, select, textarea, button {
+ font-family: inherit;
+ font-size: inherit;
+}
+
+.content {
+ display: flex;
+ flex-direction: column;
+ width: 100%;
+ height: 100%;
+}
+
+.description {
+ padding-bottom: 5px;
+}
+
+.description .title {
+ font-size: 120%;
+ font-weight: bold;
+}
+
+.route_controls {
+ flex: 0;
+ align-self: center;
+ text-align: right;
+ padding-bottom: 5px;
+}
+
+.route_controls .label {
+ display: inline-block;
+ vertical-align: top;
+ font-weight: bold;
+}
+
+.route_controls .control {
+ width: 500px;
+}
+
+.messages {
+ flex: 1;
+ min-height: 100px;
+ border: 1px solid gray;
+ overflow: auto;
+}
+
+.messages .message {
+ padding: 3px;
+ border-bottom: 1px solid #cccbca;
+}
+
+.messages .message .timestamp {
+ font-size: 90%;
+ font-style: italic;
+}
+
+.messages .status {
+ background-color: #d6d6d6; /* light gray */
+}
+
+.messages .sent {
+ background-color: #c5e8fc; /* light blue */
+}
+
+.messages .recv {
+ background-color: #fcf4e3; /* light yellow */
+}
+
+.message_controls {
+ flex: 0;
+ text-align: right;
+ padding-top: 5px;
+}
+
+.message_controls textarea {
+ width: 100%;
+ height: 10em;
+}
+</style>
+<script language="JavaScript">
+// Application state.
+var demoMode = false;
+var currentSubscriptionId = null;
+var currentRouteId = null;
+
+// List of currently supported source protocols.
+var allowedSourceProtocols = ['cast', 'dial'];
+
+// Values from cef_media_route_connection_state_t.
+var CEF_MRCS_UNKNOWN = 0;
+var CEF_MRCS_CONNECTING = 1;
+var CEF_MRCS_CONNECTED = 2;
+var CEF_MRCS_CLOSED = 3;
+var CEF_MRCS_TERMINATED = 4;
+
+function getStateLabel(state) {
+ switch (state) {
+ case CEF_MRCS_CONNECTING: return "CONNECTING";
+ case CEF_MRCS_CONNECTED: return "CONNECTED";
+ case CEF_MRCS_CLOSED: return "CLOSED";
+ case CEF_MRCS_TERMINATED: return "TERMINATED";
+ default: break;
+ }
+ return "UNKNOWN";
+}
+
+// Values from cef_media_sink_icon_type_t.
+var CEF_MSIT_CAST = 0;
+var CEF_MSIT_CAST_AUDIO_GROUP = 1;
+var CEF_MSIT_CAST_AUDIO = 2;
+var CEF_MSIT_MEETING = 3;
+var CEF_MSIT_HANGOUT = 4;
+var CEF_MSIT_EDUCATION = 5;
+var CEF_MSIT_WIRED_DISPLAY = 6;
+var CEF_MSIT_GENERIC = 7;
+
+function getIconTypeLabel(type) {
+ switch (type) {
+ case CEF_MSIT_CAST: return "CAST";
+ case CEF_MSIT_CAST_AUDIO_GROUP: return "CAST_AUDIO_GROUP";
+ case CEF_MSIT_CAST_AUDIO: return "CAST_AUDIO";
+ case CEF_MSIT_MEETING: return "MEETING";
+ case CEF_MSIT_HANGOUT: return "HANGOUT";
+ case CEF_MSIT_EDUCATION: return "EDUCATION";
+ case CEF_MSIT_WIRED_DISPLAY: return "WIRED_DISPLAY";
+ case CEF_MSIT_GENERIC: return "GENERIC";
+ default: break;
+ }
+ return "UNKNOWN";
+}
+
+
+///
+// Manage show/hide of default text for form elements.
+///
+
+// Default messages that are shown until the user focuses on the input field.
+var defaultSourceText = 'Enter URN here and click "Create Route"';
+var defaultMessageText = 'Enter message contents here and click "Send Message"';
+
+function getDefaultText(control) {
+ if (control === 'source')
+ return defaultSourceText;
+ if (control === 'message')
+ return defaultMessageText;
+ return null;
+}
+
+function hideDefaultText(control) {
+ var element = document.getElementById(control);
+ var defaultText = getDefaultText(control);
+ if (element.value === defaultText)
+ element.value = '';
+}
+
+function showDefaultText(control) {
+ var element = document.getElementById(control);
+ var defaultText = getDefaultText(control);
+ if (element.value === '')
+ element.value = defaultText;
+}
+
+function initDefaultText() {
+ showDefaultText('source');
+ showDefaultText('message');
+}
+
+
+///
+// Retrieve current form values. Return null if validation fails.
+///
+
+function getCurrentSource() {
+ var sourceInput = document.getElementById('source');
+ var value = sourceInput.value;
+ if (value === defaultSourceText || value.length === 0 || value.indexOf(':') < 0) {
+ return null;
+ }
+
+ // Validate the URN value.
+ try {
+ var url = new URL(value);
+ if ((url.hostname.length === 0 && url.pathname.length === 0) ||
+ !allowedSourceProtocols.includes(url.protocol.slice(0, -1))) {
+ return null;
+ }
+ } catch (e) {
+ return null;
+ }
+
+ return value;
+}
+
+function getCurrentSink() {
+ var sinksSelect = document.getElementById('sink');
+ if (sinksSelect.options.length === 0)
+ return null;
+ return sinksSelect.value;
+}
+
+function getCurrentMessage() {
+ var messageInput = document.getElementById('message');
+ if (messageInput.value === defaultMessageText || messageInput.value.length === 0)
+ return null;
+ return messageInput.value;
+}
+
+
+///
+// Set disabled state of form elements.
+///
+
+function updateControls() {
+ document.getElementById('source').disabled = hasRoute();
+ document.getElementById('sink').disabled = hasRoute();
+ document.getElementById('create_route').disabled =
+ hasRoute() || getCurrentSource() === null || getCurrentSink() === null;
+ document.getElementById('terminate_route').disabled = !hasRoute();
+ document.getElementById('message').disabled = !hasRoute();
+ document.getElementById('send_message').disabled = !hasRoute() || getCurrentMessage() === null;
+}
+
+
+///
+// Manage the media sinks list.
+///
+
+/*
+Expected format for |sinks| is:
+ [
+ {
+ name: string,
+ type: string ('cast' or 'dial'),
+ id: string,
+ icon: int
+ }, ...
+ ]
+*/
+function updateSinks(sinks) {
+ var sinksSelect = document.getElementById('sink');
+
+ // Currently selected value.
+ var selectedValue = sinksSelect.options.length === 0 ? null : sinksSelect.value;
+
+ // Build a list of old (existing) values.
+ var oldValues = [];
+ for (var i = 0; i < sinksSelect.options.length; ++i) {
+ oldValues.push(sinksSelect.options[i].value);
+ }
+
+ // Build a list of new (possibly new or existing) values.
+ var newValues = [];
+ for(var i = 0; i < sinks.length; i++) {
+ newValues.push(sinks[i].id);
+ }
+
+ // Remove old values that no longer exist.
+ for (var i = sinksSelect.options.length - 1; i >= 0; --i) {
+ if (!newValues.includes(sinksSelect.options[i].value)) {
+ sinksSelect.remove(i);
+ }
+ }
+
+ // Add new values that don't already exist.
+ for(var i = 0; i < sinks.length; i++) {
+ var sink = sinks[i];
+ if (oldValues.includes(sink.id))
+ continue;
+ var opt = document.createElement('option');
+ opt.innerHTML = sink.name + ' (' + sink.model_name + ', ' + sink.type + ', ' +
+ getIconTypeLabel(sink.icon) + ', ' + sink.ip_address + ':' + sink.port + ')';
+ opt.value = sink.id;
+ sinksSelect.appendChild(opt);
+ }
+
+ if (sinksSelect.options.length === 0) {
+ selectedValue = null;
+ } else if (!newValues.includes(selectedValue)) {
+ // The previously selected value no longer exists.
+ // Select the first value in the new list.
+ selectedValue = sinksSelect.options[0].value;
+ sinksSelect.value = selectedValue;
+ }
+
+ updateControls();
+
+ return selectedValue;
+}
+
+
+///
+// Manage the current media route.
+///
+
+function hasRoute() {
+ return currentRouteId !== null;
+}
+
+function createRoute() {
+ console.assert(!hasRoute());
+ var source = getCurrentSource();
+ console.assert(source !== null);
+ var sink = getCurrentSink();
+ console.assert(sink !== null);
+
+ if (demoMode) {
+ onRouteCreated('demo-route-id');
+ return;
+ }
+
+ sendCefQuery(
+ {name: 'createRoute', source_urn: source, sink_id: sink},
+ (message) => onRouteCreated(JSON.parse(message).route_id)
+ );
+}
+
+function onRouteCreated(route_id) {
+ currentRouteId = route_id;
+ showStatusMessage('Route ' + route_id + '\ncreated');
+ updateControls();
+}
+
+function terminateRoute() {
+ console.assert(hasRoute());
+ var source = getCurrentSource();
+ console.assert(source !== null);
+ var sink = getCurrentSink();
+ console.assert(sink !== null);
+
+ if (demoMode) {
+ onRouteTerminated();
+ return;
+ }
+
+ sendCefQuery(
+ {name: 'terminateRoute', route_id: currentRouteId},
+ (unused) => {}
+ );
+}
+
+function onRouteTerminated() {
+ showStatusMessage('Route ' + currentRouteId + '\nterminated');
+ currentRouteId = null;
+ updateControls();
+}
+
+
+///
+// Manage messages.
+///
+
+function sendMessage() {
+ console.assert(hasRoute());
+ var message = getCurrentMessage();
+ console.assert(message !== null);
+
+ if (demoMode) {
+ showSentMessage(message);
+ setTimeout(function(){ if (hasRoute()) { recvMessage('Demo ACK for: ' + message); } }, 1000);
+ return;
+ }
+
+ sendCefQuery(
+ {name: 'sendMessage', route_id: currentRouteId, message: message},
+ (unused) => showSentMessage(message)
+ );
+}
+
+function recvMessage(message) {
+ console.assert(hasRoute());
+ console.assert(message !== undefined && message !== null && message.length > 0);
+ showRecvMessage(message);
+}
+
+function showStatusMessage(message) {
+ showMessage('status', message);
+}
+
+function showSentMessage(message) {
+ showMessage('sent', message);
+}
+
+function showRecvMessage(message) {
+ showMessage('recv', message);
+}
+
+function showMessage(type, message) {
+ if (!['status', 'sent', 'recv'].includes(type)) {
+ console.warn('Invalid message type: ' + type);
+ return;
+ }
+
+ if (message[0] === '{') {
+ try {
+ // Pretty print JSON strings.
+ message = JSON.stringify(JSON.parse(message), null, 2);
+ } catch(e) {}
+ }
+
+ var messagesDiv = document.getElementById('messages');
+
+ var newDiv = document.createElement("div");
+ newDiv.innerHTML =
+ '<span class="timestamp">' + (new Date().toLocaleString()) +
+ ' (' + type.toUpperCase() + ')</span><br/>';
+ // Escape any HTML tags or entities in |message|.
+ var pre = document.createElement('pre');
+ pre.appendChild(document.createTextNode(message));
+ newDiv.appendChild(pre);
+ newDiv.className = 'message ' + type;
+
+ messagesDiv.appendChild(newDiv);
+
+ // Always scroll to bottom.
+ messagesDiv.scrollTop = messagesDiv.scrollHeight;
+}
+
+
+///
+// Manage communication with native code in media_router_test.cc.
+///
+
+function onCefError(code, message) {
+ showStatusMessage('ERROR: ' + message + ' (' + code + ')');
+}
+
+function sendCefQuery(payload, onSuccess, onFailure=onCefError, persistent=false) {
+ // Results in a call to the OnQuery method in media_router_test.cc
+ return window.cefQuery({
+ request: JSON.stringify(payload),
+ onSuccess: onSuccess,
+ onFailure: onFailure,
+ persistent: persistent
+ });
+}
+
+/*
+Expected format for |message| is:
+ {
+ name: string,
+ payload: dictionary
+ }
+*/
+function onCefSubscriptionMessage(message) {
+ if (message.name === 'onSinks') {
+ // List of sinks.
+ updateSinks(message.payload.sinks_list);
+ } else if (message.name === 'onRouteStateChanged') {
+ // Route status changed.
+ if (message.payload.route_id === currentRouteId) {
+ var connection_state = message.payload.connection_state;
+ showStatusMessage('Route ' + currentRouteId +
+ '\nconnection state ' + getStateLabel(connection_state) +
+ ' (' + connection_state + ')');
+ if ([CEF_MRCS_CLOSED, CEF_MRCS_TERMINATED].includes(connection_state)) {
+ onRouteTerminated();
+ }
+ }
+ } else if (message.name === 'onRouteMessageReceived') {
+ // Route message received.
+ if (message.payload.route_id === currentRouteId) {
+ recvMessage(message.payload.message);
+ }
+ }
+}
+
+// Subscribe to ongoing message notifications from the native code.
+function startCefSubscription() {
+ currentSubscriptionId = sendCefQuery(
+ {name: 'subscribe'},
+ (message) => onCefSubscriptionMessage(JSON.parse(message)),
+ (code, message) => {
+ onCefError(code, message);
+ currentSubscriptionId = null;
+ },
+ true
+ );
+}
+
+function stopCefSubscription() {
+ if (currentSubscriptionId !== null) {
+ // Results in a call to the OnQueryCanceled method in media_router_test.cc
+ window.cefQueryCancel(currentSubscriptionId);
+ }
+}
+
+
+///
+// Example app load/unload.
+///
+
+function initDemoMode() {
+ demoMode = true;
+
+ var sinks = [
+ {
+ name: 'Sink 1',
+ type: 'cast',
+ id: 'sink1',
+ icon: CEF_MSIT_CAST
+ },
+ {
+ name: 'Sink 2',
+ type: 'dial',
+ id: 'sink2',
+ icon: CEF_MSIT_GENERIC
+ }
+ ];
+ updateSinks(sinks);
+
+ showStatusMessage('Running in Demo mode.');
+ showSentMessage('Demo sent message.');
+ showRecvMessage('Demo recv message.');
+}
+
+function onLoad() {
+ initDefaultText();
+
+ if (window.cefQuery === undefined) {
+ // Initialize demo mode when running outside of CEF.
+ // This supports development and testing of the HTML/JS behavior outside
+ // of a cefclient build.
+ initDemoMode();
+ return;
+ }
+
+ startCefSubscription()
+}
+
+function onUnload() {
+ if (demoMode)
+ return;
+
+ if (hasRoute())
+ terminateRoute();
+ stopCefSubscription();
+}
+</script>
+<title>Media Router Example</title>
+</head>
+<body bgcolor="white" onLoad="onLoad()" onUnload="onUnload()">
+<div class="content">
+ <div class="description">
+ <span class="title">Media Router Example</span>
+ <p>
+ <b>Overview:</b>
+ Chromium supports communication with devices on the local network via the
+ <a href="https://blog.oakbits.com/google-cast-protocol-overview.html" target="_blank">Cast</a> and
+ <a href="http://www.dial-multiscreen.org/" target="_blank">DIAL</a> protocols.
+ CEF exposes this functionality via the CefMediaRouter interface which is demonstrated by this test.
+ Test code is implemented in resources/media_router.html and browser/media_router_test.cc.
+ </p>
+ <p>
+ <b>Usage:</b>
+ Devices available on your local network will be discovered automatically and populated in the "Sink" list.
+ Enter a URN for "Source", select an available device from the "Sink" list, and click the "Create Route" button.
+ Cast URNs take the form "cast:<i>&lt;appId&gt;</i>?clientId=<i>&lt;clientId&gt;</i>" and DIAL URNs take the form "dial:<i>&lt;appId&gt;</i>",
+ where <i>&lt;appId&gt;</i> is the <a href="https://developers.google.com/cast/docs/registration" target="_blank">registered application ID</a>
+ and <i>&lt;clientId&gt;</i> is an arbitrary numeric identifier.
+ Status information and messages will be displayed in the center of the screen.
+ After creating a route you can send messages to the receiver app using the textarea at the bottom of the screen.
+ Messages are usually in JSON format with a example of Cast communication to be found
+ <a href="https://github.com/chromiumembedded/cef/issues/2900#issuecomment-1465022620" target="_blank">here</a>.
+ </p>
+ </div>
+ <div class="route_controls">
+ <span class="label">Source:</span>
+ <input type="text" id="source" class="control" onInput="updateControls()" onFocus="hideDefaultText('source')" onBlur="showDefaultText('source')"/>
+ <br/>
+ <span class="label">Sink:</span>
+ <select id="sink" size="3" class="control"></select>
+ <br/>
+ <input type="button" id="create_route" onclick="createRoute()" value="Create Route" disabled/>
+ <input type="button" id="terminate_route" onclick="terminateRoute()" value="Terminate Route" disabled/>
+ </div>
+ <div id="messages" class="messages">
+ </div>
+ <div class="message_controls">
+ <textarea id="message" onInput="updateControls()" onFocus="hideDefaultText('message')" onBlur="showDefaultText('message')" disabled></textarea>
+ <br/><input type="button" id="send_message" onclick="sendMessage()" value="Send Message" disabled/>
+ </div>
+</div>
+</body>
+</html>
diff --git a/tests/cefclient/resources/menu_icon.1x.png b/tests/cefclient/resources/menu_icon.1x.png
new file mode 100644
index 00000000..976f524d
--- /dev/null
+++ b/tests/cefclient/resources/menu_icon.1x.png
Binary files differ
diff --git a/tests/cefclient/resources/menu_icon.2x.png b/tests/cefclient/resources/menu_icon.2x.png
new file mode 100644
index 00000000..1ab841c1
--- /dev/null
+++ b/tests/cefclient/resources/menu_icon.2x.png
Binary files differ
diff --git a/tests/cefclient/resources/other_tests.html b/tests/cefclient/resources/other_tests.html
new file mode 100644
index 00000000..87288f46
--- /dev/null
+++ b/tests/cefclient/resources/other_tests.html
@@ -0,0 +1,45 @@
+<html>
+<head>
+<title>Other Tests</title>
+</head>
+<body bgcolor="white">
+<h3>Various other internal and external tests.</h3>
+<ul>
+<li><a href="http://mudcu.be/labs/JS1k/BreathingGalaxies.html">Accelerated 2D Canvas</a></li>
+<li><a href="http://webkit.org/blog-files/3d-transforms/poster-circle.html">Accelerated Layers</a></li>
+<li><a href="https://jigsaw.w3.org/HTTP/Basic/">Authentication (Basic)</a> - credentials returned via GetAuthCredentials</li>
+<li><a href="https://jigsaw.w3.org/HTTP/Digest/">Authentication (Digest)</a> - credentials returned via GetAuthCredentials</li>
+<li><a href="http://html5advent2011.digitpaint.nl/3/index.html">Cursors</a></li>
+<li><a href="dialogs">Dialogs</a></li>
+<li><a href="http://html5demos.com/drag">Drag & Drop</a></li>
+<li><a href="draggable">Draggable Regions</a></li>
+<li>DRM (Clearkey, Widevine) <a href="https://shaka-player-demo.appspot.com/support.html">Codecs support</a>, <a href="https://shaka-player-demo.appspot.com/demo/">Video player demo</a></li>
+<li><a href="http://www.html5test.com">HTML5 Feature Test</a></li>
+<li><a href="http://html5-demos.appspot.com/static/filesystem/filer.js/demos/index.html">HTML5 Filesystem</a> - requires "cache-path" flag</li>
+<li><a href="http://www.youtube.com/watch?v=siOHh0uzcuY&html5=True">HTML5 Video</a></li>
+<li><a href="ipc_performance">IPC Performance Tests</a></li>
+<li><a href="binding">JavaScript Binding</a></li>
+<li><a href="performance">JavaScript Performance Tests</a></li>
+<li><a href="performance2">JavaScript Performance (2) Tests</a></li>
+<li><a href="window">JavaScript Window Manipulation</a></li>
+<li><a href="localstorage">Local Storage</a></li>
+<li><a href="media_router">Media Router (Cast/DIAL)</a></li>
+<li><a href="pdf.pdf">PDF Viewer direct</a></li>
+<li><a href="pdf">PDF Viewer iframe</a></li>
+<li><a href="preferences">Preferences</a></li>
+<li><a href="http://mrdoob.com/lab/javascript/requestanimationframe/">requestAnimationFrame</a></li>
+<li><a href="response_filter">Response Filtering</a></li>
+<li><a href="client://tests/handler.html">Scheme Handler</a></li>
+<li><a href="server">HTTP/WebSocket Server</a></li>
+<li><a href="websocket">WebSocket Client</a></li>
+<li><a href="https://www.google.com/intl/en/chrome/demos/speech.html">Speech Input</a> - requires "enable-speech-input" flag</li>
+<li><a href="transparency">Transparency</a></li>
+<li><a href="http://webglsamples.org/field/field.html">WebGL</a></li>
+<li><a href="http://apprtc.appspot.com/">WebRTC</a> - requires "enable-media-stream" flag</li>
+<li><a href="urlrequest">CefURLRequest</a></li>
+<li><a href="xmlhttprequest">XMLHttpRequest</a></li>
+<li><a href="javascript:window.print();">Print this page with &quot;javascript:window.print();&quot;</a></li>
+<li><a href="https://patrickhlauke.github.io/touch">Touch Feature Tests</a> - requires "touch-events=enabled" flag (and CAPS LOCK on Mac for Trackpad simulation)</li>
+</ul>
+</body>
+</html>
diff --git a/tests/cefclient/resources/performance.html b/tests/cefclient/resources/performance.html
new file mode 100644
index 00000000..aa64d51d
--- /dev/null
+++ b/tests/cefclient/resources/performance.html
@@ -0,0 +1,293 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>Performance Tests</title>
+ <style>
+ body { font-family: Tahoma, Serif; font-size: 9pt; }
+ </style>
+ </head>
+ <body bgcolor="white">
+ <h1>Performance Tests</h1>
+ <input type="button" value="Run Tests" onClick="run();" id="run"/> Filter: <input type="text" size="50" id="filters"/>
+ <div><span id="statusBox"></span> <progress id="progressBox" value="0" style="display:none"></progress></div>
+
+ <div style="padding-top:10px; padding-bottom:10px">
+ <table id="resultTable" border="1" cellspacing="1" cellpadding="4">
+ <thead>
+ <tr>
+ <td>Name</td>
+ <td>Iterations per Run</td>
+ <td>Avg (ms)</td>
+ <td>Min (ms)</td>
+ <td>Max (ms)</td>
+ <td>StdDev (ms)</td>
+ <td>Runs (ms)</td>
+ </tr>
+ </thead>
+ <!-- result rows here -->
+ </table>
+ </div>
+
+ <hr width="80%">
+
+ Result 1: <input type="text" size="100" id="result1"/>
+ <br/>Result 2: <input type="text" size="100" id="result2"/>
+ <br/><input type="button" value="Compare" onClick="compare();" id="compare"/>
+
+ <div style="padding-top:10px; padding-bottom:10px">
+ <table id="compareTable" border="1" cellspacing="1" cellpadding="4">
+ <thead>
+ <tr>
+ <td>Name</td>
+ <td>Result 1 Avg (ms)</td>
+ <td>Result 2 Avg (ms)</td>
+ <td>% Diff</td>
+ </tr>
+ </thead>
+ <!-- result rows here -->
+ </table>
+ </div>
+
+<script type="text/javascript">
+function run() {
+ var runElement = document.getElementById("run");
+ var filtersElement = document.getElementById("filters");
+ var compareElement = document.getElementById("compare");
+ var result1Element = document.getElementById("result1");
+ var result2Element = document.getElementById("result2");
+
+ // Number of runs for each test.
+ var testRuns = 10;
+
+ // Delay between test runs.
+ var runDelay = 0;
+
+ // Retrieve the list of all tests.
+ var allTests = window.GetPerfTests();
+
+ // Populated with the list of tests that will be run.
+ var tests = [];
+ var currentTest = 0;
+
+ var testList = filtersElement.value.trim();
+ if (testList.length > 0) {
+ // Include or exclude specific tests.
+ var included = [];
+ var excluded = [];
+
+ var testNames = testList.split(",");
+
+ // Identify included and excluded tests.
+ for (i = 0; i < testNames.length; ++i) {
+ var testName = testNames[i].trim();
+ if (testName[0] == '-') {
+ // Exclude the test.
+ excluded.push(testName.substr(1));
+ } else {
+ // Include the test.
+ included.push(testName);
+ }
+ }
+
+ if (included.length > 0) {
+ // Only use the included tests.
+ for (i = 0; i < allTests.length; ++i) {
+ var test = allTests[i];
+ var testName = test[0];
+ if (included.indexOf(testName) >= 0)
+ tests.push(test);
+ }
+ } else if (excluded.length > 0) {
+ // Use all tests except the excluded tests.
+ for (i = 0; i < allTests.length; ++i) {
+ var test = allTests[i];
+ var testName = test[0];
+ if (excluded.indexOf(testName) < 0)
+ tests.push(test);
+ }
+ }
+ } else {
+ // Run all tests.
+ tests = allTests;
+ }
+
+ function updateStatusComplete() {
+ var statusBox = document.getElementById("statusBox");
+ statusBox.innerText = 'All tests completed.';
+
+ runElement.disabled = false;
+ filtersElement.disabled = false;
+ result1Element.disabled = false;
+ result2Element.disabled = false;
+ compareElement.disabled = false;
+ }
+
+ function updateStatus(test) {
+ var statusBox = document.getElementById("statusBox");
+ var progressBox = document.getElementById("progressBox");
+
+ if (test.run >= test.totalRuns) {
+ statusBox.innerText = test.name + " completed.";
+ progressBox.style.display = 'none';
+ } else {
+ statusBox.innerText = test.name + " (" + test.run + "/" + test.totalRuns + ")";
+ progressBox.value = (test.run / test.totalRuns);
+ progressBox.style.display = 'inline';
+ }
+ }
+
+ function appendResult(test) {
+ var e = document.getElementById("resultTable");
+
+ // Calculate the average.
+ var avg = test.total / test.totalRuns;
+
+ // Calculate the standard deviation.
+ var sqsum = 0;
+ for (i = 0; i < test.results.length; ++i) {
+ var diff = test.results[i] - avg;
+ sqsum += diff * diff;
+ }
+ var stddev = Math.round(Math.sqrt(sqsum / test.totalRuns) * 100.0) / 100.0;
+
+ e.insertAdjacentHTML("beforeEnd", [
+ "<tr>",
+ "<td>", test.name, "</td>",
+ "<td>", test.iterations, "</td>",
+ "<td>", avg, "</td>",
+ "<td>", test.min, "</td>",
+ "<td>", test.max, "</td>",
+ "<td>", stddev, "</td>",
+ "<td>", test.results.join(", "), "</td>",
+ "<tr>"
+ ].join(""));
+
+ if (result1Element.value.length > 0)
+ result1Element.value += ",";
+ result1Element.value += test.name + "=" + avg;
+ }
+
+ // Execute the test function.
+ function execTestFunc(name) {
+ return window.RunPerfTest(name);
+ }
+
+ // Schedule the next test.
+ function nextTest(test) {
+ appendResult(test);
+ currentTest++;
+ runTest();
+ }
+
+ // Schedule the next step for the current test.
+ function nextTestStep(test) {
+ setTimeout(function () { execTest(test); }, runDelay);
+ }
+
+ // Perform the next step for the current test.
+ function execTest(test) {
+ updateStatus(test);
+
+ if (!test.warmedUp) {
+ execTestFunc(test.name);
+ test.warmedUp = true;
+ return nextTestStep(test);
+ }
+
+ if (test.run >= test.totalRuns)
+ return nextTest(test);
+
+ var elapsed = execTestFunc(test.name);
+ test.results.push(elapsed);
+
+ test.total += elapsed;
+ if (!test.min) test.min = elapsed;
+ else if (test.min > elapsed) test.min = elapsed;
+ if (!test.max) test.max = elapsed;
+ else if (test.max < elapsed) test.max = elapsed;
+
+ test.run++;
+
+ return nextTestStep(test);
+ }
+
+ function runTest() {
+ if (currentTest == tests.length) {
+ updateStatusComplete();
+ return;
+ }
+
+ var test = {
+ name: tests[currentTest][0],
+ iterations: tests[currentTest][1],
+ warmedUp: false,
+ total: 0,
+ totalRuns: testRuns,
+ run: 0,
+ results: []
+ };
+ setTimeout(function () { execTest(test); }, runDelay);
+ }
+
+ // Schedule the first test.
+ if (tests.length > 0) {
+ runElement.disabled = true;
+ filtersElement.disabled = true;
+ result1Element.value = "";
+ result1Element.disabled = true;
+ result2Element.disabled = true;
+ compareElement.disabled = true;
+
+ runTest();
+ }
+}
+
+function compare() {
+ var result1 = document.getElementById("result1").value.trim();
+ var result2 = document.getElementById("result2").value.trim();
+
+ if (result1.length == 0 || result2.length == 0)
+ return;
+
+ var r1values = result1.split(",");
+ var r2values = result2.split(",");
+ for (i = 0; i < r1values.length; ++i) {
+ var r1parts = r1values[i].split("=");
+ var r1name = r1parts[0].trim();
+ var r1val = r1parts[1].trim();
+
+ for (x = 0; x < r2values.length; ++x) {
+ var r2parts = r2values[x].split("=");
+ var r2name = r2parts[0].trim();
+ var r2val = r2parts[1].trim();
+
+ if (r2name == r1name) {
+ appendResult(r1name, r1val, r2val);
+
+ // Remove the matching index.
+ r2values.splice(x, 1);
+ break;
+ }
+ }
+ }
+
+ function appendResult(name, r1val, r2val) {
+ var e = document.getElementById("compareTable");
+
+ // Calculate the percent difference.
+ var diff = Math.round(((r2val - r1val) / r1val) * 10000.0) / 100.0;
+
+ e.insertAdjacentHTML("beforeEnd", [
+ "<tr>",
+ "<td>", name, "</td>",
+ "<td>", r1val, "</td>",
+ "<td>", r2val, "</td>",
+ "<td>", diff, "</td>",
+ "<tr>"
+ ].join(""));
+ }
+}
+</script>
+
+ </body>
+</html>
diff --git a/tests/cefclient/resources/performance2.html b/tests/cefclient/resources/performance2.html
new file mode 100644
index 00000000..6664de7b
--- /dev/null
+++ b/tests/cefclient/resources/performance2.html
@@ -0,0 +1,442 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>Performance Tests (2)</title>
+ <style>
+ body { font-family: Tahoma, Serif; font-size: 9pt; }
+
+ .left { text-align: left; }
+ .right { text-align: right; }
+ .center { text-align: center; }
+
+ table.resultTable
+ {
+ border: 1px solid black;
+ border-collapse: collapse;
+ empty-cells: show;
+ width: 100%;
+ }
+ table.resultTable td
+ {
+ padding: 2px 4px;
+ border: 1px solid black;
+ }
+ table.resultTable > thead > tr
+ {
+ font-weight: bold;
+ background: lightblue;
+ }
+ table.resultTable > tbody > tr:nth-child(odd)
+ {
+ background: white;
+ }
+ table.resultTable > tbody > tr:nth-child(even)
+ {
+ background: lightgray;
+ }
+
+ .hide { display: none; }
+ </style>
+ </head>
+ <body bgcolor="white">
+ <h1>Performance Tests (2)</h1>
+
+ <form id="sForm" onsubmit="runTestSuite();return false">
+ <table>
+ <tr>
+ <td colspan="2">Settings:</td>
+ </tr>
+ <tr>
+ <td class="right">Iterations:</td>
+ <td><input id="sIterations" type="text" value="1000" required pattern="[0-9]+" /></td>
+ </tr>
+ <tr>
+ <td class="right">Samples:</td>
+ <td><input id="sSamples" type="text" value="100" required pattern="[0-9]+" /></td>
+ </tr>
+ <tr>
+ <td class="right">Mode:</td>
+ <td><input id="sAsync" name="sMode" type="radio" value="async" checked>Asynchronous</input>
+ <input id="sSync" name="sMode" type="radio" value="sync">Synchronous</input>
+ </td>
+ </tr>
+ <tr>
+ <td colspan="2"><button type="submit" id="sRun" autofocus>Run!</button></td>
+ </tr>
+ </table>
+ </form>
+
+
+ <div><span id="statusBox"></span> <progress id="progressBox" value="0" style="display:none"></progress></div>
+
+ <div style="padding-top:10px; padding-bottom:10px">
+ <table id="resultTable" class="resultTable">
+ <thead>
+ <tr>
+ <td class="center" style="width:1%">Enabled</td>
+ <td class="center" style="width:10%">Name</td>
+ <td class="center" style="width:5%">Samples x Iterations</td>
+ <td class="center" style="width:5%">Min,&nbsp;ms</td>
+ <td class="center" style="width:5%">Avg,&nbsp;ms</td>
+ <td class="center" style="width:5%">Max,&nbsp;ms</td>
+ <td class="center" style="width:5%">Average calls/sec</td>
+ <td class="center" style="width:5%">Measuring Inacurracy</td>
+ <td class="center hide" style="width:5%">Memory, MB</td>
+ <td class="center hide" style="width:5%">Memory delta, MB</td>
+ <td class="center" style="width:55%">Description</td>
+ </tr>
+ </thead>
+ <tbody>
+ <!-- result rows here -->
+ </tbody>
+ </table>
+ </div>
+
+<script type="text/javascript">
+(function () {
+ function getPrivateWorkingSet() {
+ return 0; // TODO: window.PerfTestGetPrivateWorkingSet();
+ }
+
+ var disableWarmUp = true;
+
+ var asyncExecution = true;
+ var testIterations = 1000;
+ var totalSamples = 100;
+ var sampleDelay = 0;
+
+ var collectSamples = false;
+
+ var tests = [];
+ var testIndex = -1;
+
+ function execTestFunc(test) {
+ try {
+ var begin = new Date();
+ test.func(test.totalIterations);
+ var end = new Date();
+ return (end - begin);
+ } catch (e) {
+ test.error = e.toString();
+ return 0;
+ }
+ }
+
+ function execTest(test) {
+ if (disableWarmUp) { test.warmedUp = true; }
+
+ function nextStep() {
+ if (asyncExecution) {
+ setTimeout(function () { execTest(test); }, sampleDelay);
+ } else {
+ execTest(test);
+ }
+ }
+
+ function nextTest() {
+ updateStatus(test);
+ appendResult(test);
+
+ return execNextTest();
+ }
+
+ updateStatus(test);
+ if (!test.warmedUp) {
+ execTestFunc(test);
+ if (!test.error) {
+ test.warmedUp = true;
+ test.beginMemory = getPrivateWorkingSet();
+ return nextStep();
+ } else {
+ return nextTest();
+ }
+ }
+
+ if (test.sample >= test.totalSamples) {
+ test.avg = test.total / test.totalSamples;
+ test.endMemory = getPrivateWorkingSet();
+ return nextTest();
+ }
+
+ if (test.skipped) return nextTest();
+
+ var elapsed = execTestFunc(test);
+ if (!test.error) {
+ test.total += elapsed;
+ if (!test.min) test.min = elapsed;
+ else if (test.min > elapsed) test.min = elapsed;
+ if (!test.max) test.max = elapsed;
+ else if (test.max < elapsed) test.max = elapsed;
+ if (collectSamples) {
+ test.results.push(elapsed);
+ }
+ test.sample++;
+ return nextStep();
+ } else {
+ return nextTest();
+ }
+ }
+
+ function updateStatus(test) {
+ var statusBox = document.getElementById("statusBox");
+ var progressBox = document.getElementById("progressBox");
+
+ if (test.skipped || test.error || test.sample >= test.totalSamples) {
+ statusBox.innerText = "";
+ progressBox.style.display = "none";
+ } else {
+ statusBox.innerText = (testIndex + 1) + "/" + tests.length + ": " + test.name + " (" + test.sample + "/" + test.totalSamples + ")";
+ progressBox.value = (test.sample / test.totalSamples);
+ progressBox.style.display = "inline";
+ }
+ }
+
+ function appendResult(test) {
+ if (test.name == "warmup") return;
+
+ var id = "testResultRow_" + test.index;
+
+ var nearBound = (test.max - test.avg) < (test.avg - test.min) ? test.max : test.min;
+ var memoryDelta = test.endMemory - test.beginMemory;
+ if (memoryDelta < 0) memoryDelta = "-" + Math.abs(memoryDelta).toFixed(2);
+ else memoryDelta = "+" + Math.abs(memoryDelta).toFixed(2);
+
+ var markup = ["<tr id='" + id + "'>",
+ "<td class='left'><input type='checkbox' id='test_enabled_", test.index ,"' ", (!test.skipped ? "checked" : "") ," /></td>",
+ "<td class='left'>", test.name, "</td>",
+ "<td class='right'>", test.totalSamples, "x", test.totalIterations, "</td>",
+ "<td class='right'>", test.skipped || test.error || !test.prepared ? "-" : test.min.toFixed(2), "</td>",
+ "<td class='right'>", test.skipped || test.error || !test.prepared ? "-" : test.avg.toFixed(2), "</td>",
+ "<td class='right'>", test.skipped || test.error || !test.prepared ? "-" : test.max.toFixed(2), "</td>",
+ "<td class='right'>", test.skipped || test.error || !test.prepared ? "-" : (test.totalIterations * 1000 / test.avg).toFixed(2), "</td>",
+ "<td class='right'>", test.skipped || test.error || !test.prepared ? "-" : ("&#x00B1; " + (Math.abs(test.avg - nearBound) / (test.avg) * (100)).toFixed(2) + "%"), "</td>",
+ "<td class='right hide'>", test.skipped || test.error || !test.prepared ? "-" : test.endMemory.toFixed(2), "</td>",
+ "<td class='right hide'>", test.skipped || test.error || !test.prepared ? "-" : memoryDelta, "</td>",
+ "<td class='left'>", test.description, test.error ? (test.description ? "<br/>" : "") + "<span style='color:red'>" + test.error + "</span>" : "", "</td>",
+ "</tr>"
+ ].join("");
+ // test.results.join(", "), "<br/>",
+
+ var row = document.getElementById(id);
+ if (row) {
+ row.outerHTML = markup;
+ } else {
+ var tbody = document.getElementById("resultTable").tBodies[0];
+ tbody.insertAdjacentHTML("beforeEnd", markup);
+ }
+ }
+
+ function prepareQueuedTests() {
+ testIndex = -1;
+ for (var i = 0; i < tests.length; i++) {
+ var test = tests[i];
+ test.index = i;
+ test.prepared = false;
+ test.warmedUp = false;
+ test.sample = 0;
+ test.total = 0;
+ test.results = [];
+ test.error = false;
+ test.min = null;
+ test.avg = null;
+ test.max = null;
+ test.beginMemory = null;
+ test.endMemory = null;
+ test.totalIterations = parseInt(testIterations / test.complex);
+ test.totalSamples = parseInt(totalSamples / test.complex);
+
+ var skipElement = document.getElementById('test_enabled_' + test.index);
+ test.skipped = skipElement ? !skipElement.checked : (test.skipped || false);
+
+ if (test.totalIterations <= 0) test.totalIterations = 1;
+ if (test.totalSamples <= 0) test.totalSamples = 1;
+
+ appendResult(test);
+ test.prepared = true;
+ }
+ }
+
+ function queueTest(func, name, description) {
+ var test;
+ if (typeof func === "function") {
+ test = {
+ name: name,
+ func: func,
+ description: description
+ };
+ } else {
+ test = func;
+ }
+ test.warmedUp = false;
+ test.complex = test.complex || 1;
+ tests.push(test);
+ }
+
+ function execNextTest() {
+ testIndex++;
+ if (tests.length <= testIndex) {
+ return testSuiteFinished();
+ } else {
+ return execTest(tests[testIndex]);
+ }
+ }
+
+ function execQueuedTests() {
+ prepareQueuedTests();
+ execNextTest();
+ }
+
+ function setSettingsState(disabled) {
+ document.getElementById('sIterations').disabled = disabled;
+ document.getElementById('sSamples').disabled = disabled;
+ document.getElementById('sAsync').disabled = disabled;
+ document.getElementById('sSync').disabled = disabled;
+ document.getElementById('sRun').disabled = disabled;
+ }
+
+ function testSuiteFinished() {
+ setSettingsState(false);
+ }
+
+ window.runTestSuite = function () {
+ setSettingsState(true);
+
+ testIterations = parseInt(document.getElementById('sIterations').value);
+ totalSamples = parseInt(document.getElementById('sSamples').value);
+ asyncExecution = document.getElementById('sAsync').checked;
+
+ setTimeout(execQueuedTests, 0);
+ }
+
+ setTimeout(prepareQueuedTests, 0);
+
+ // Test queue.
+ queueTest({
+ name: "PerfTestReturnValue Default",
+ func: function (count) {
+ for (var i = 0; i < count; i++) {
+ window.PerfTestReturnValue();
+ }
+ },
+ description: "No arguments, returns int32 value.",
+ skipped: true,
+ });
+
+ queueTest({
+ name: "PerfTestReturnValue (0, Undefined)",
+ func: function (count) {
+ for (var i = 0; i < count; i++) {
+ window.PerfTestReturnValue(0);
+ }
+ },
+ description: "Int argument, returns undefined value."
+ });
+
+ queueTest({
+ name: "PerfTestReturnValue (1, Null)",
+ func: function (count) {
+ for (var i = 0; i < count; i++) {
+ window.PerfTestReturnValue(1);
+ }
+ },
+ description: "Int argument, returns null value."
+ });
+
+ queueTest({
+ name: "PerfTestReturnValue (2, Bool)",
+ func: function (count) {
+ for (var i = 0; i < count; i++) {
+ window.PerfTestReturnValue(2);
+ }
+ },
+ description: "Int argument, returns bool value."
+ });
+
+ queueTest({
+ name: "PerfTestReturnValue (3, Int)",
+ func: function (count) {
+ for (var i = 0; i < count; i++) {
+ window.PerfTestReturnValue(3);
+ }
+ },
+ description: "Int argument, returns int value."
+ });
+
+ queueTest({
+ name: "PerfTestReturnValue (4, UInt)",
+ func: function (count) {
+ for (var i = 0; i < count; i++) {
+ window.PerfTestReturnValue(4);
+ }
+ },
+ description: "Int argument, returns uint value."
+ });
+
+ queueTest({
+ name: "PerfTestReturnValue (5, Double)",
+ func: function (count) {
+ for (var i = 0; i < count; i++) {
+ window.PerfTestReturnValue(5);
+ }
+ },
+ description: "Int argument, returns double value."
+ });
+
+ queueTest({
+ name: "PerfTestReturnValue (6, Date)",
+ func: function (count) {
+ for (var i = 0; i < count; i++) {
+ window.PerfTestReturnValue(6);
+ }
+ },
+ description: "Int argument, returns date value.",
+ skipped: true,
+ });
+
+ queueTest({
+ name: "PerfTestReturnValue (7, String)",
+ func: function (count) {
+ for (var i = 0; i < count; i++) {
+ window.PerfTestReturnValue(7);
+ }
+ },
+ description: "Int argument, returns string value."
+ });
+
+ queueTest({
+ name: "PerfTestReturnValue (8, Object)",
+ func: function (count) {
+ for (var i = 0; i < count; i++) {
+ window.PerfTestReturnValue(8);
+ }
+ },
+ description: "Int argument, returns object value."
+ });
+
+ queueTest({
+ name: "PerfTestReturnValue (9, Array)",
+ func: function (count) {
+ for (var i = 0; i < count; i++) {
+ window.PerfTestReturnValue(9);
+ }
+ },
+ description: "Int argument, returns array value."
+ });
+
+ queueTest({
+ name: "PerfTestReturnValue (10, Function)",
+ func: function (count) {
+ for (var i = 0; i < count; i++) {
+ window.PerfTestReturnValue(10);
+ }
+ },
+ description: "Int argument, returns function value.",
+ skipped: true,
+ });
+ // add more tests to queueTest
+
+})();
+</script>
+
+ </body>
+</html>
diff --git a/tests/cefclient/resources/preferences.html b/tests/cefclient/resources/preferences.html
new file mode 100644
index 00000000..1062f1ea
--- /dev/null
+++ b/tests/cefclient/resources/preferences.html
@@ -0,0 +1,338 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Preferences Test</title>
+
+ <!-- When using the mode "code" it's important to specify charset utf-8 -->
+ <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
+
+ <!-- jsoneditor project from https://github.com/josdejong/jsoneditor/
+ script hosting from http://cdnjs.com/libraries/jsoneditor -->
+ <link href="https://cdnjs.cloudflare.com/ajax/libs/jsoneditor/4.2.1/jsoneditor.min.css" rel="stylesheet" type="text/css">
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/jsoneditor/4.2.1/jsoneditor.min.js"></script>
+
+ <script>
+ function setup() {
+ if (location.hostname == 'tests' || location.hostname == 'localhost')
+ return;
+
+ alert('This page can only be run from tests or localhost.');
+
+ // Disable all elements.
+ var elements = document.getElementById("form").elements;
+ for (var i = 0, element; element = elements[i++]; ) {
+ element.disabled = true;
+ }
+ }
+ </script>
+</head>
+<body bgcolor="white" onload="setup()">
+ <!-- Header -->
+ <div id="simple_links">
+ [ <b>Simple</b> ]
+ [ <a href="#" onClick="toggleView(); return false;">Advanced</a> ]
+ </div>
+ <div id="advanced_links" style="display:none">
+ [ <a href="#" onClick="toggleView(); return false;">Simple</a> ]
+ [ <b>Advanced</b> ]
+ </div>
+
+ <form id="form">
+
+ <!-- Simple view -->
+ <div id="simple">
+ <p>
+ This page supports display and configuration of a few sample preferences.
+ <table width="100%" style="border: 1px solid #97B0F8">
+ <tr>
+ <td>
+ <input type="checkbox" id="enable_spellchecking"/> Enable spell checking
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <br/>
+ <input type="checkbox" id="allow_running_insecure_content"/> Allow running insecure content
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <br/>
+ Proxy type:
+ <select id="proxy_type" onChange="proxyTypeChange()">
+ <option value="direct">Direct</option>
+ <option value="auto_detect">Auto-Detect</option>
+ <option value="pac_script">PAC Script</option>
+ <option value="fixed_servers">Fixed Servers</option>
+ <option value="system">System</option>
+ </select>
+ <input id="proxy_value" type="text" size="80" disabled/>
+ </td>
+ </tr>
+ </table>
+ <table border="0" width="100%">
+ <tr>
+ <td align="left">
+ <input type="button" value="Refresh" onClick="refreshSimple()"/>
+ </td>
+ <td align="right">
+ <input type="button" value="Apply Changes" onClick="applySimpleChanges()"/>
+ </td>
+ </tr>
+ </table>
+ </p>
+ </div>
+
+ <!-- Advanced view -->
+ <div id="advanced" style="display:none">
+ <p>
+ This page displays all preferences organized in a tree structure. Arbitrary changes are
+ allowed, however <b>changing preferences in arbitrary ways may result in crashes</b>. If you
+ experience a crash while setting preferences then run a Debug build of CEF/Chromium and watch
+ for DCHECKs in the Chromium code to figure out what went wrong.
+ </p>
+ <div id="jsoneditor" style="width: 100%; height: 100%;"></div>
+ <table border="0" width="100%">
+ <tr>
+ <td align="left">
+ <input type="button" value="Refresh" onClick="refreshEditor()"/>
+ <input type="checkbox" id="hide_defaults"/> Show modified preferences only
+ </td>
+ <td align="right">
+ <input type="button" value="Apply Changes" onClick="applyEditorChanges()"/>
+ </td>
+ </tr>
+ </table>
+ </div>
+
+ </form>
+
+ <script>
+ // Reference to the JSONEditor.
+ var editor = null;
+
+ // Preferences state information.
+ var preferences_state = null;
+
+ // Toggle between the simple and advanced views.
+ function toggleView() {
+ var simple = document.getElementById("simple");
+ var advanced = document.getElementById("advanced");
+ var simple_links = document.getElementById("simple_links");
+ var advanced_links = document.getElementById("advanced_links");
+
+ if (simple.style.display == "none") {
+ // Show the simple view.
+ simple.style.display = "";
+ simple_links.style.display = "";
+ advanced.style.display = "none";
+ advanced_links.style.display = "none";
+
+ // Refresh the simple view contents.
+ refreshSimple();
+ } else {
+ // Show the advanced view.
+ simple.style.display = "none";
+ simple_links.style.display = "none";
+ advanced.style.display = "";
+ advanced_links.style.display = "";
+
+ if (editor == null) {
+ // Create the editor.
+ editor = new JSONEditor(document.getElementById("jsoneditor"));
+ }
+
+ // Refesh the editor contents.
+ refreshEditor();
+ }
+ }
+
+ // Send a request to C++.
+ function sendRequest(request, onSuccessCallback) {
+ // Results in a call to the OnQuery method in preferences_test.cpp.
+ window.cefQuery({
+ request: JSON.stringify(request),
+ onSuccess: onSuccessCallback,
+ onFailure: function(error_code, error_message) {
+ alert(error_message + ' (' + error_code + ')');
+ }
+ });
+ }
+
+ // Get the preferences and execute |onSuccessCallback| with the resulting
+ // JSON object.
+ function getPreferences(include_defaults, onSuccessCallback) {
+ // Create the request object.
+ var request = {};
+ request.name = "preferences_get";
+ request.include_defaults = include_defaults;
+
+ // Send the request to C++.
+ sendRequest(
+ request,
+ function(response) {
+ onSuccessCallback(JSON.parse(response));
+ }
+ );
+ }
+
+ // Set the preferences.
+ function setPreferences(preferences) {
+ // Create the request object.
+ var request = {};
+ request.name = "preferences_set";
+ request.preferences = preferences;
+
+ // Send the request to C++.
+ sendRequest(
+ request,
+ function(response) {
+ // Show the informative response message.
+ alert(response);
+ }
+ );
+ }
+
+ // Get the global preference state.
+ function getPreferenceState() {
+ // Create the request object.
+ var request = {};
+ request.name = "preferences_state";
+
+ // Send the request to C++.
+ sendRequest(
+ request,
+ function(response) {
+ // Populate the global state object.
+ preferences_state = JSON.parse(response);
+
+ // Refresh the simple view contents.
+ refreshSimple();
+ }
+ );
+ }
+
+ // Refresh the editor view contents.
+ function refreshEditor() {
+ include_defaults = !document.getElementById("hide_defaults").checked;
+ getPreferences(include_defaults, function(response) {
+ // Set the JSON in the editor.
+ editor.set(response);
+ });
+ }
+
+ // Apply changes from the editor view.
+ function applyEditorChanges() {
+ setPreferences(editor.get());
+ }
+
+ // Refresh the simple view contents.
+ function refreshSimple() {
+ getPreferences(true, function(response) {
+ // Spellcheck settings.
+ if (preferences_state.spellcheck_disabled) {
+ // Cannot enable spell checking when disabled via the command-line.
+ document.getElementById("enable_spellchecking").checked = false;
+ document.getElementById("enable_spellchecking").disabled = true;
+ } else {
+ document.getElementById("enable_spellchecking").checked =
+ response.browser.enable_spellchecking;
+ }
+
+ // Web content settings.
+ if (preferences_state.allow_running_insecure_content) {
+ // Cannot disable running insecure content when enabled via the
+ // command-line.
+ document.getElementById("allow_running_insecure_content").checked =
+ true;
+ document.getElementById("allow_running_insecure_content").disabled =
+ true;
+ } else {
+ document.getElementById("allow_running_insecure_content").checked =
+ response.webkit.webprefs.allow_running_insecure_content;
+ }
+
+ // Proxy settings.
+ document.getElementById("proxy_type").value = response.proxy.mode;
+
+ // Some proxy modes have associated values.
+ if (response.proxy.mode == "pac_script")
+ proxy_value = response.proxy.pac_url;
+ else if (response.proxy.mode == "fixed_servers")
+ proxy_value = response.proxy.server;
+ else
+ proxy_value = null;
+
+ if (proxy_value != null)
+ document.getElementById("proxy_value").value = proxy_value;
+ document.getElementById("proxy_value").disabled = (proxy_value == null);
+
+ if (preferences_state.proxy_configured) {
+ // Cannot modify proxy settings that are configured via the command-
+ // line.
+ document.getElementById("proxy_type").disabled = true;
+ document.getElementById("proxy_value").disabled = true;
+ }
+ });
+ }
+
+ // Apply changes from the simple view.
+ function applySimpleChanges() {
+ has_preferences = false;
+ preferences = {};
+
+ // Spellcheck settings.
+ if (!preferences_state.spellcheck_disabled) {
+ has_preferences = true;
+
+ preferences.browser = {};
+ preferences.browser.enable_spellchecking =
+ document.getElementById("enable_spellchecking").checked;
+ }
+
+ // Web content settings.
+ if (!preferences_state.allow_running_insecure_content) {
+ has_preferences = true;
+
+ preferences.webkit = {};
+ preferences.webkit.webprefs = {};
+ preferences.webkit.webprefs.allow_running_insecure_content =
+ document.getElementById("allow_running_insecure_content").checked;
+ }
+
+ // Proxy settings.
+ if (!preferences_state.proxy_configured) {
+ has_preferences = true;
+
+ preferences.proxy = {};
+ preferences.proxy.mode = document.getElementById("proxy_type").value;
+
+ // Some proxy modes have associated values.
+ if (preferences.proxy.mode == "pac_script") {
+ preferences.proxy.pac_script =
+ document.getElementById("proxy_value").value;
+ } else if (preferences.proxy.mode == "fixed_servers") {
+ preferences.proxy.server =
+ document.getElementById("proxy_value").value;
+ }
+ }
+
+ if (has_preferences)
+ setPreferences(preferences);
+ }
+
+ // Called when the proxy type is changed.
+ function proxyTypeChange() {
+ proxy_type = document.getElementById("proxy_type").value;
+ document.getElementById("proxy_value").value = "";
+
+ // Only enable the value field for the proxy modes that require it.
+ document.getElementById("proxy_value").disabled =
+ (proxy_type != "pac_script" && proxy_type != "fixed_servers");
+ }
+
+ // Retrieve global preferences state.
+ getPreferenceState();
+ </script>
+</body>
+</html>
diff --git a/tests/cefclient/resources/response_filter.html b/tests/cefclient/resources/response_filter.html
new file mode 100644
index 00000000..d67e4577
--- /dev/null
+++ b/tests/cefclient/resources/response_filter.html
@@ -0,0 +1,142 @@
+<html>
+<head>
+<title>Response Filter Test</title>
+</head>
+<body bgcolor="white">
+<p>The text shown below in <font color="red">red</font> has been replaced by the filter. This document is > 64kb in order to exceed the standard output buffer size.</p>
+<p><font color="red">REPLACE_THIS_STRING</font></p>
+<p>0. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>1. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>2. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>3. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>4. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>5. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>6. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>7. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>8. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>9. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p><font color="red">REPLACE_THIS_STRING</font></p>
+<p>0. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>1. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>2. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>3. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>4. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>5. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>6. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>7. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>8. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>9. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p><font color="red">REPLACE_THIS_STRING</font></p>
+<p>0. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>1. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>2. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>3. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>4. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>5. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>6. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>7. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>8. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>9. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p><font color="red">REPLACE_THIS_STRING</font></p>
+<p>0. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>1. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>2. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>3. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>4. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>5. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>6. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>7. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>8. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>9. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p><font color="red">REPLACE_THIS_STRING</font></p>
+<p>0. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>1. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>2. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>3. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>4. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>5. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>6. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>7. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>8. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>9. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p><font color="red">REPLACE_THIS_STRING</font></p>
+<p>0. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>1. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>2. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>3. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>4. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>5. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>6. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>7. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>8. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>9. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p><font color="red">REPLACE_THIS_STRING</font></p>
+<p>0. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>1. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>2. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>3. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>4. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>5. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>6. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>7. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>8. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>9. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p><font color="red">REPLACE_THIS_STRING</font></p>
+<p>0. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>1. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>2. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>3. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>4. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>5. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>6. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>7. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>8. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>9. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p><font color="red">REPLACE_THIS_STRING</font></p>
+<p>0. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>1. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>2. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>3. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>4. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>5. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>6. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>7. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>8. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>9. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p><font color="red">REPLACE_THIS_STRING</font></p>
+<p>0. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>1. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>2. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>3. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>4. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>5. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>6. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>7. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>8. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>9. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p><font color="red">REPLACE_THIS_STRING</font></p>
+<p>0. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>1. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>2. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>3. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>4. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>5. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>6. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>7. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>8. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>9. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p><font color="red">REPLACE_THIS_STRING</font></p>
+<p>0. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>1. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>2. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>3. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>4. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>5. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>6. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>7. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>8. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p>9. It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to Heaven, we were all going direct the other way -- in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.</p>
+<p><font color="red">REPLACE_THIS_STRING</font></p>
+<p>End.</p>
+</body>
+</html>
diff --git a/tests/cefclient/resources/server.html b/tests/cefclient/resources/server.html
new file mode 100644
index 00000000..9e49e062
--- /dev/null
+++ b/tests/cefclient/resources/server.html
@@ -0,0 +1,104 @@
+<html>
+<head>
+<title>Server Test</title>
+<script language="JavaScript">
+
+// Send a query to the browser process.
+function sendMessage(request, success_callback) {
+ // Results in a call to the OnQuery method in server_test.cc
+ window.cefQuery({
+ request: JSON.stringify(request),
+ onSuccess: function(response) {
+ success_callback(response.length == 0 ? {} : JSON.parse(response));
+ },
+ onFailure: function(error_code, error_message) {
+ alert("Request failed with error " + error_message + "(" + error_code + ")");
+ }
+ });
+}
+
+function setButtonState(start_enabled, stop_enabled) {
+ document.getElementById('start').disabled = !start_enabled;
+ document.getElementById('stop').disabled = !stop_enabled;
+ document.getElementById('open').disabled = !stop_enabled;
+}
+
+function setup() {
+ if (location.origin != 'http://tests') {
+ document.getElementById('warning').style.display = 'block';
+ return;
+ }
+
+ // Query the current server state.
+ sendMessage({'action':'query'}, function(response) {
+ if (response['result'] == 'success') {
+ var running = (response['status'] == 'running')
+ setButtonState(!running, running);
+
+ var port_element = document.getElementById('port');
+ port_element.value = response['port'];
+ port_element.disabled = false;
+ }
+ });
+}
+
+function startServer() {
+ var port = parseInt(document.getElementById('port').value);
+ if (port < 1025 || port > 65535) {
+ alert('Specify a port number between 1025 and 65535');
+ return;
+ }
+
+ setButtonState(false, false);
+
+ sendMessage({'action':'start', 'port':port}, function(response) {
+ if (response['result'] == 'success') {
+ setButtonState(false, true);
+ } else {
+ setButtonState(true, false);
+ alert(response['message']);
+ }
+ });
+}
+
+function stopServer() {
+ setButtonState(false, false);
+
+ sendMessage({'action':'stop'}, function(response) {
+ if (response['result'] == 'success') {
+ setButtonState(true, false);
+ } else {
+ setButtonState(false, true);
+ alert(response['message']);
+ }
+ });
+}
+
+function openServer() {
+ var port = document.getElementById('port').value;
+ window.open('http://localhost:' + port);
+}
+
+</script>
+
+</head>
+<body bgcolor="white" onload="setup()">
+<div id="warning" style="display:none;color:red;font-weight:bold;">
+This page can only be run from the http://tests origin.
+</div>
+<p>
+This page starts an HTTP/WebSocket server on localhost with the specified port number.
+After starting the server click the "Open Example" button to open the WebSocket Client test in a popup window.
+</p>
+<p>
+With this example each browser window can create/manage a separate server instance.
+The server will be stopped automatically when the managing browser window is closed.
+</p>
+<form>
+Server port: <input type="text" id="port" value="" disabled="true">
+<br/><input type="button" id="start" onclick="startServer()" value="Start Server" disabled="true">
+<input type="button" id="stop" onclick="stopServer()" value="Stop Server" disabled="true">
+<input type="button" id="open" onclick="openServer()" value="Open Example" disabled="true">
+</form>
+</body>
+</html>
diff --git a/tests/cefclient/resources/transparency.html b/tests/cefclient/resources/transparency.html
new file mode 100644
index 00000000..a8dd3b46
--- /dev/null
+++ b/tests/cefclient/resources/transparency.html
@@ -0,0 +1,63 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<title>Transparency Examples</title>
+<style type="text/css">
+body {
+font-family: Verdana, Arial;
+}
+img {
+opacity:0.4;
+}
+img:hover {
+opacity:1.0;
+}
+.box_white, .box_black {
+font-size: 14px;
+font-weight: bold;
+text-align: center;
+padding: 10px;
+display: inline-block;
+width: 100px;
+}
+.box_white {
+background-color: white;
+border: 2px solid black;
+color: black;
+}
+.box_black {
+background-color: black;
+border: 2px solid white;
+color: white;
+}
+.box_0 {
+opacity: 1.0;
+}
+.box_25 {
+opacity: 0.75;
+}
+.box_50 {
+opacity: 0.5;
+}
+.box_75 {
+opacity: 0.25;
+}
+.box_100 {
+opacity: 0;
+}
+</style>
+</head>
+<body>
+
+<h1>Image Transparency</h1>
+Hover over an image to make it fully opaque.<br>
+<img src="http://www.w3schools.com/css/klematis.jpg" width="150" height="113" alt="klematis" />
+<img src="http://www.w3schools.com/css/klematis2.jpg" width="150" height="113" alt="klematis" />
+
+<h1>Block Transparency</h1>
+<span class="box_white box_0">White 0%</span> <span class="box_white box_25">White 25%</span> <span class="box_white box_50">White 50%</span> <span class="box_white box_75">White 75%</span> <span class="box_white box_100">White 100%</span>
+<br>
+<span class="box_black box_0">Black 0%</span> <span class="box_black box_25">Black 25%</span> <span class="box_black box_50">Black 50%</span> <span class="box_black box_75">Black 75%</span> <span class="box_black box_100">Black 100%</span>
+
+</body>
+</html>
diff --git a/tests/cefclient/resources/urlrequest.html b/tests/cefclient/resources/urlrequest.html
new file mode 100644
index 00000000..873dbd45
--- /dev/null
+++ b/tests/cefclient/resources/urlrequest.html
@@ -0,0 +1,42 @@
+<html>
+<head>
+<script language="JavaScript">
+
+function setup() {
+ if (location.hostname == 'tests' || location.hostname == 'localhost')
+ return;
+
+ alert('This page can only be run from tests or localhost');
+
+ // Disable all elements.
+ var elements = document.getElementById("form").elements;
+ for (var i = 0, element; element = elements[i++]; ) {
+ element.disabled = true;
+ }
+}
+
+// Send a query to the browser process.
+function execURLRequest() {
+ document.getElementById('ta').value = 'Request pending...';
+
+ // Results in a call to the OnQuery method in urlrequest_test.cpp
+ window.cefQuery({
+ request: 'URLRequestTest:' + document.getElementById("url").value,
+ onSuccess: function(response) {
+ document.getElementById('ta').value = response;
+ },
+ onFailure: function(error_code, error_message) {
+ document.getElementById('ta').value = 'Failed with error ' + error_message + ' (' + error_code + ')';
+ }
+ });
+}
+</script>
+</head>
+<body bgcolor="white" onload="setup()">
+<form id="form">
+URL: <input type="text" id="url" value="https://www.google.com">
+<br/><input type="button" onclick="execURLRequest();" value="Execute CefURLRequest">
+<br/><textarea rows="10" cols="40" id="ta"></textarea>
+</form>
+</body>
+</html>
diff --git a/tests/cefclient/resources/websocket.html b/tests/cefclient/resources/websocket.html
new file mode 100644
index 00000000..e13abc0c
--- /dev/null
+++ b/tests/cefclient/resources/websocket.html
@@ -0,0 +1,107 @@
+<html>
+<head>
+<title>WebSocket Test</title>
+<script language="JavaScript">
+
+var ws = null;
+
+function setup() {
+ // Match the secure state of the current origin.
+ var origin = location.origin;
+ if (origin.indexOf('http://') == 0) {
+ origin = origin.replace('http://', 'ws://');
+ } else if (origin.indexOf('https://') == 0) {
+ origin = origin.replace('https://', 'wss://');
+ } else {
+ origin = '';
+ }
+
+ if (origin.length > 0)
+ document.getElementById('server').value = origin;
+ document.getElementById('server').disabled = false;
+
+ if (location.hostname != 'localhost')
+ document.getElementById('warning').style.display = 'block';
+
+ setConnected(false);
+}
+
+function setConnected(connected) {
+ document.getElementById('connect').disabled = connected;
+ document.getElementById('disconnect').disabled = !connected;
+ document.getElementById('message').disabled = !connected;
+ document.getElementById('response').disabled = !connected;
+ document.getElementById('send').disabled = !connected;
+}
+
+function doConnect() {
+ var url = document.getElementById('server').value;
+ if (url.indexOf('ws://') < 0 && url.indexOf('wss://') < 0) {
+ alert('Specify a valid WebSocket server URL.');
+ return;
+ }
+
+ if (ws) {
+ alert('WebSocket is already connected.');
+ return;
+ }
+
+ ws = new WebSocket(url);
+ ws.onopen = function() { setConnected(true); };
+ ws.onmessage = function(event) {
+ document.getElementById('response').value = event.data;
+ };
+ ws.onclose = function(event) {
+ setConnected(false);
+ ws = null;
+ };
+ ws.onerror = function(event) {
+ if (ws.readyState == 3)
+ alert('WebSocket connection failed.');
+ }
+}
+
+function doDisconnect() {
+ if (!ws) {
+ alert('WebSocket is not currently connected.');
+ return;
+ }
+
+ ws.close();
+}
+
+function doSend() {
+ if (!ws) {
+ alert('WebSocket is not currently connected.');
+ return;
+ }
+
+ var value = document.getElementById('message').value;
+ if (value.length > 0)
+ ws.send(value);
+}
+
+</script>
+
+</head>
+<body bgcolor="white" onload="setup()">
+<div id="warning" style="display:none;color:red;font-weight:bold;">
+This page is most useful when loaded from localhost.
+You should first create a server using the <a href="http://tests/server">HTTP/WebSocket Server test</a>.
+</div>
+<p>
+This page tests a WebSocket connection.
+The example implementation in server_test.cc will then echo the message contents in reverse.
+</p>
+<form>
+Server URL: <input type="text" id="server" value="" disabled="true">
+<br/><input type="button" id="connect" onclick="doConnect()" value="Connect" disabled="true">
+<input type="button" id="disconnect" onclick="doDisconnect()" value="Disconnect" disabled="true">
+<br/>Message: <input type="text" id="message" value="Test Message" disabled="true">
+<input type="button" id="send" onclick="doSend()" value="Send" disabled="true">
+<br/>Response: <input type="text" id="response" value="" disabled="true">
+<br/><br/>
+The example implementation in server_test.cc can also serve the HTTP-based <a href="other_tests">Other Tests</a>.
+</form>
+</body>
+</html>
diff --git a/tests/cefclient/resources/win/cefclient.exe.manifest b/tests/cefclient/resources/win/cefclient.exe.manifest
new file mode 100644
index 00000000..d36f084b
--- /dev/null
+++ b/tests/cefclient/resources/win/cefclient.exe.manifest
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+
+ <!--The compatibility section will be merged from build/win/compatibility.manifest -->
+
+ <dependency>
+ <dependentAssembly>
+ <assemblyIdentity type="Win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"></assemblyIdentity>
+ </dependentAssembly>
+ </dependency>
+
+ <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
+ <security>
+ <requestedPrivileges>
+ <requestedExecutionLevel level="asInvoker" />
+ </requestedPrivileges>
+ </security>
+ </trustInfo>
+
+</assembly>
diff --git a/tests/cefclient/resources/win/cefclient.ico b/tests/cefclient/resources/win/cefclient.ico
new file mode 100644
index 00000000..d551aa3a
--- /dev/null
+++ b/tests/cefclient/resources/win/cefclient.ico
Binary files differ
diff --git a/tests/cefclient/resources/win/cefclient.rc b/tests/cefclient/resources/win/cefclient.rc
new file mode 100644
index 00000000..55a54d02
--- /dev/null
+++ b/tests/cefclient/resources/win/cefclient.rc
@@ -0,0 +1,231 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "tests/cefclient/browser/resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#define APSTUDIO_HIDDEN_SYMBOLS
+#include "windows.h"
+#include "include/cef_version.h"
+#undef APSTUDIO_HIDDEN_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Binary
+//
+
+IDS_BINDING_HTML BINARY "..\\binding.html"
+IDS_DIALOGS_HTML BINARY "..\\dialogs.html"
+IDS_DRAGGABLE_HTML BINARY "..\\draggable.html"
+IDS_IPC_PERFORMANCE_HTML BINARY "..\\ipc_performance.html"
+IDS_LOCALSTORAGE_HTML BINARY "..\\localstorage.html"
+IDS_LOGO_PNG BINARY "..\\logo.png"
+IDS_MEDIA_ROUTER_HTML BINARY "..\\media_router.html"
+IDS_MENU_ICON_1X_PNG BINARY "..\\menu_icon.1x.png"
+IDS_MENU_ICON_2X_PNG BINARY "..\\menu_icon.2x.png"
+IDS_OSRTEST_HTML BINARY "..\\..\\..\\shared\\resources\\osr_test.html"
+IDS_OTHER_TESTS_HTML BINARY "..\\other_tests.html"
+IDS_PDF_HTML BINARY "..\\..\\..\\shared\\resources\\pdf.html"
+IDS_PDF_PDF BINARY "..\\..\\..\\shared\\resources\\pdf.pdf"
+IDS_PERFORMANCE_HTML BINARY "..\\performance.html"
+IDS_PERFORMANCE2_HTML BINARY "..\\performance2.html"
+IDS_PREFERENCES_HTML BINARY "..\\preferences.html"
+IDS_RESPONSE_FILTER_HTML BINARY "..\\response_filter.html"
+IDS_SERVER_HTML BINARY "..\\server.html"
+IDS_TRANSPARENCY_HTML BINARY "..\\transparency.html"
+IDS_URLREQUEST_HTML BINARY "..\\urlrequest.html"
+IDS_WEBSOCKET_HTML BINARY "..\\websocket.html"
+IDS_WINDOW_HTML BINARY "..\\window.html"
+IDS_WINDOW_ICON_1X_PNG BINARY "..\\..\\..\\shared\\resources\\window_icon.1x.png"
+IDS_WINDOW_ICON_2X_PNG BINARY "..\\..\\..\\shared\\resources\\window_icon.2x.png"
+IDS_XMLHTTPREQUEST_HTML BINARY "..\\xmlhttprequest.html"
+
+IDS_EXTENSIONS_SET_PAGE_COLOR_ICON_PNG BINARY "..\\extensions\\set_page_color\\icon.png"
+IDS_EXTENSIONS_SET_PAGE_COLOR_MANIFEST_JSON BINARY "..\\extensions\\set_page_color\\manifest.json"
+IDS_EXTENSIONS_SET_PAGE_COLOR_POPUP_HTML BINARY "..\\extensions\\set_page_color\\popup.html"
+IDS_EXTENSIONS_SET_PAGE_COLOR_POPUP_JS BINARY "..\\extensions\\set_page_color\\popup.js"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_CEFCLIENT ICON "cefclient.ico"
+IDI_SMALL ICON "small.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDC_CEFCLIENT MENU
+BEGIN
+ POPUP "&File"
+ BEGIN
+ MENUITEM "&Find...", ID_FIND
+ MENUITEM SEPARATOR
+ MENUITEM "E&xit", IDM_EXIT
+ END
+ POPUP "&Help"
+ BEGIN
+ MENUITEM "&About ...", IDM_ABOUT
+ END
+ POPUP "Tests"
+ BEGIN
+ MENUITEM "Get Source", ID_TESTS_GETSOURCE
+ MENUITEM "Get Text", ID_TESTS_GETTEXT
+ MENUITEM "New Window", ID_TESTS_WINDOW_NEW
+ MENUITEM "Popup Window", ID_TESTS_WINDOW_POPUP
+ MENUITEM "Request", ID_TESTS_REQUEST
+ MENUITEM "Zoom In", ID_TESTS_ZOOM_IN
+ MENUITEM "Zoom Out", ID_TESTS_ZOOM_OUT
+ MENUITEM "Zoom Reset", ID_TESTS_ZOOM_RESET
+ MENUITEM "Set FPS", ID_TESTS_OSR_FPS
+ MENUITEM "Set Scale Factor", ID_TESTS_OSR_DSF
+ MENUITEM "Begin Tracing", ID_TESTS_TRACING_BEGIN
+ MENUITEM "End Tracing", ID_TESTS_TRACING_END
+ MENUITEM "Print", ID_TESTS_PRINT
+ MENUITEM "Print to PDF", ID_TESTS_PRINT_TO_PDF
+ MENUITEM "Mute Audio", ID_TESTS_MUTE_AUDIO
+ MENUITEM "Unmute Audio", ID_TESTS_UNMUTE_AUDIO
+ MENUITEM "Other Tests", ID_TESTS_OTHER_TESTS
+ END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Accelerator
+//
+
+IDC_CEFCLIENT ACCELERATORS
+BEGIN
+ "?", IDM_ABOUT, ASCII, ALT
+ "/", IDM_ABOUT, ASCII, ALT
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_ABOUTBOX DIALOG 22, 17, 230, 75
+STYLE DS_SETFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU
+CAPTION "About"
+FONT 8, "System"
+BEGIN
+ ICON IDI_CEFCLIENT,IDC_MYICON,14,9,16,16
+ LTEXT "cefclient Version 1.0",IDC_STATIC,49,10,119,8,SS_NOPREFIX
+ LTEXT "Copyright (C) 2008",IDC_STATIC,49,20,119,8
+ DEFPUSHBUTTON "OK",IDOK,195,6,30,11,WS_GROUP
+END
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION CEF_VERSION_MAJOR,CEF_VERSION_MINOR,CEF_VERSION_PATCH,0
+ PRODUCTVERSION CEF_VERSION_MAJOR,CEF_VERSION_MINOR,CEF_VERSION_PATCH,0
+ FILEFLAGSMASK 0x17L
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "FileDescription", "Chromium Embedded Framework (CEF) Client Application"
+ VALUE "FileVersion", CEF_VERSION
+ VALUE "InternalName", "cefclient"
+ VALUE "LegalCopyright", "Copyright (C) " MAKE_STRING(COPYRIGHT_YEAR) " The Chromium Embedded Framework Authors"
+ VALUE "OriginalFilename", "cefclient.exe"
+ VALUE "ProductName", "Chromium Embedded Framework (CEF) Client Application"
+ VALUE "ProductVersion", CEF_VERSION
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#define APSTUDIO_HIDDEN_SYMBOLS\r\n"
+ "#include ""windows.h""\r\n"
+ "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE
+BEGIN
+ IDS_APP_TITLE "cefclient"
+ IDC_CEFCLIENT "CEFCLIENT"
+END
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/tests/cefclient/resources/win/small.ico b/tests/cefclient/resources/win/small.ico
new file mode 100644
index 00000000..d551aa3a
--- /dev/null
+++ b/tests/cefclient/resources/win/small.ico
Binary files differ
diff --git a/tests/cefclient/resources/window.html b/tests/cefclient/resources/window.html
new file mode 100644
index 00000000..f01f7f52
--- /dev/null
+++ b/tests/cefclient/resources/window.html
@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+<html lang="en-US">
+<head>
+<title>Window Test</title>
+<script>
+function setup() {
+ if (location.hostname == 'tests' || location.hostname == 'localhost')
+ return;
+
+ alert('This page can only be run from tests or localhost.');
+
+ // Disable all elements.
+ var elements = document.getElementById("form").elements;
+ for (var i = 0, element; element = elements[i++]; ) {
+ element.disabled = true;
+ }
+}
+
+function send_message(test, params) {
+ var message = 'WindowTest.' + test;
+ if (typeof params != 'undefined')
+ message += ':' + params;
+
+ // Results in a call to the OnQuery method in window_test.cpp.
+ window.cefQuery({'request' : message});
+}
+
+function minimize() {
+ send_message('Minimize');
+}
+
+function maximize() {
+ send_message('Maximize');
+}
+
+function restore() {
+ minimize();
+ setTimeout(function() { send_message('Restore'); }, 1000);
+}
+
+function position() {
+ var x = parseInt(document.getElementById('x').value);
+ var y = parseInt(document.getElementById('y').value);
+ var width = parseInt(document.getElementById('width').value);
+ var height = parseInt(document.getElementById('height').value);
+ if (isNaN(x) || isNaN(y) || isNaN(width) || isNaN(height))
+ alert('Please specify a valid numeric value.');
+ else
+ send_message('Position', x + ',' + y + ',' + width + ',' + height);
+}
+
+function setTitlebarHeight() {
+ const height = parseFloat(document.getElementById('title_bar_height').value);
+ if (isNaN(height))
+ send_message('TitlebarHeight');
+ else
+ send_message('TitlebarHeight', height);
+}
+</script>
+</head>
+<body bgcolor="white" onload="setup()">
+<form id="form">
+Click a button to perform the associated window action.
+<br/><input type="button" onclick="minimize();" value="Minimize">
+<br/><input type="button" onclick="maximize();" value="Maximize">
+<br/><input type="button" onclick="restore();" value="Restore"> (minimizes and then restores the window as topmost)
+<br/><input type="button" onclick="position();" value="Set Position">
+X: <input type="text" size="4" id="x" value="200">
+Y: <input type="text" size="4" id="y" value="100">
+Width: <input type="text" size="4" id="width" value="800">
+Height: <input type="text" size="4" id="height" value="600">
+<br/><input type="button" onclick="setTitlebarHeight();" value="Set Titlebar Height">
+<input type="number" min="0" max="100" id="title_bar_height" value="50"> (works on macOS with Views)
+</form>
+</body>
+</html>
diff --git a/tests/cefclient/resources/xmlhttprequest.html b/tests/cefclient/resources/xmlhttprequest.html
new file mode 100644
index 00000000..8da20f3d
--- /dev/null
+++ b/tests/cefclient/resources/xmlhttprequest.html
@@ -0,0 +1,39 @@
+<html>
+<body bgcolor="white">
+<script language="JavaScript">
+function execXMLHttpRequest()
+{
+ var url = document.getElementById("url").value;
+ var warningElement = document.getElementById("warning");
+ if (url.indexOf(location.origin) != 0) {
+ warningElement.innerHTML =
+ 'For cross-origin requests to succeed the server must return CORS headers:' +
+ '<pre>Access-Control-Allow-Origin: ' + location.origin +
+ '<br/>Access-Control-Allow-Header: My-Custom-Header</pre>';
+ warningElement.style.display = 'block';
+ } else {
+ warningElement.style.display = 'none';
+ }
+
+ xhr = new XMLHttpRequest();
+ xhr.open("GET", url, true);
+ xhr.setRequestHeader('My-Custom-Header', 'Some Value');
+ xhr.onload = function(e) {
+ if (xhr.readyState === 4) {
+ var value = "Status Code: "+xhr.status;
+ if (xhr.status === 200)
+ value += "\n\n"+xhr.responseText;
+ document.getElementById('ta').value = value;
+ }
+ }
+ xhr.send();
+}
+</script>
+<form>
+URL: <input type="text" id="url" value="http://tests/request">
+<br/><input type="button" onclick="execXMLHttpRequest();" value="Execute XMLHttpRequest">
+<br/><textarea rows="10" cols="40" id="ta"></textarea>
+</form>
+<div id="warning" style="display:none;font-weight:bold;"></div>
+</body>
+</html>
diff --git a/tests/cefsimple/CMakeLists.txt.in b/tests/cefsimple/CMakeLists.txt.in
new file mode 100644
index 00000000..9eb0824a
--- /dev/null
+++ b/tests/cefsimple/CMakeLists.txt.in
@@ -0,0 +1,214 @@
+# Copyright (c) 2014 The Chromium Embedded Framework Authors. All rights
+# reserved. Use of this source code is governed by a BSD-style license that
+# can be found in the LICENSE file.
+
+#
+# Source files.
+#
+
+# cefsimple sources.
+{{
+ 'prefix': 'cefsimple',
+ 'set': 'CEFSIMPLE_SRCS',
+ 'includes': [
+ 'cefsimple_sources_common',
+ 'cefsimple_sources_win:WINDOWS',
+ 'cefsimple_sources_mac:MAC',
+ 'cefsimple_sources_linux:LINUX',
+ ],
+}}
+
+# cefsimple helper sources.
+{{
+ 'prefix': 'cefsimple_helper',
+ 'includes': [
+ 'cefsimple_sources_mac_helper:MAC',
+ ],
+}}
+
+# cefsimple resources.
+{{
+ 'prefix': 'cefsimple_resources',
+ 'set': 'CEFSIMPLE_RESOURCES_SRCS',
+ 'includes': [
+ 'cefsimple_bundle_resources_mac:MAC',
+ ],
+}}
+
+
+#
+# Shared configuration.
+#
+
+# Target executable names.
+set(CEF_TARGET "cefsimple")
+if(OS_MAC)
+ set(CEF_HELPER_TARGET "cefsimple_Helper")
+ set(CEF_HELPER_OUTPUT_NAME "cefsimple Helper")
+else()
+ # Logical target used to link the libcef library.
+ ADD_LOGICAL_TARGET("libcef_lib" "${CEF_LIB_DEBUG}" "${CEF_LIB_RELEASE}")
+endif()
+
+# Determine the target output directory.
+SET_CEF_TARGET_OUT_DIR()
+
+
+#
+# Linux configuration.
+#
+
+if(OS_LINUX)
+ # Executable target.
+ add_executable(${CEF_TARGET} ${CEFSIMPLE_SRCS})
+ SET_EXECUTABLE_TARGET_PROPERTIES(${CEF_TARGET})
+ add_dependencies(${CEF_TARGET} libcef_dll_wrapper)
+ target_link_libraries(${CEF_TARGET} libcef_lib libcef_dll_wrapper ${CEF_STANDARD_LIBS})
+
+ # Set rpath so that libraries can be placed next to the executable.
+ set_target_properties(${CEF_TARGET} PROPERTIES INSTALL_RPATH "$ORIGIN")
+ set_target_properties(${CEF_TARGET} PROPERTIES BUILD_WITH_INSTALL_RPATH TRUE)
+ set_target_properties(${CEF_TARGET} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CEF_TARGET_OUT_DIR})
+
+ # Copy binary and resource files to the target output directory.
+ COPY_FILES("${CEF_TARGET}" "${CEF_BINARY_FILES}" "${CEF_BINARY_DIR}" "${CEF_TARGET_OUT_DIR}")
+ COPY_FILES("${CEF_TARGET}" "${CEF_RESOURCE_FILES}" "${CEF_RESOURCE_DIR}" "${CEF_TARGET_OUT_DIR}")
+ if (EXISTS "${CEF_BINARY_DIR}/libminigbm.so")
+ COPY_FILES("${CEF_TARGET}" "libminigbm.so" "${CEF_BINARY_DIR}" "${CEF_TARGET_OUT_DIR}")
+ endif()
+
+ # Set SUID permissions on the chrome-sandbox target.
+ SET_LINUX_SUID_PERMISSIONS("${CEF_TARGET}" "${CEF_TARGET_OUT_DIR}/chrome-sandbox")
+endif()
+
+
+#
+# Mac OS X configuration.
+#
+
+if(OS_MAC)
+ option(OPTION_USE_ARC "Build with ARC (automatic Reference Counting) on macOS." ON)
+ if(OPTION_USE_ARC)
+ list(APPEND CEF_COMPILER_FLAGS
+ -fobjc-arc
+ )
+ set_target_properties(${target} PROPERTIES
+ CLANG_ENABLE_OBJC_ARC "YES"
+ )
+ endif()
+
+ # Output path for the main app bundle.
+ set(CEF_APP "${CEF_TARGET_OUT_DIR}/${CEF_TARGET}.app")
+
+ # Variables referenced from the main Info.plist file.
+ set(EXECUTABLE_NAME "${CEF_TARGET}")
+ set(PRODUCT_NAME "${CEF_TARGET}")
+
+ if(USE_SANDBOX)
+ # Logical target used to link the cef_sandbox library.
+ ADD_LOGICAL_TARGET("cef_sandbox_lib" "${CEF_SANDBOX_LIB_DEBUG}" "${CEF_SANDBOX_LIB_RELEASE}")
+ endif()
+
+ # Main app bundle target.
+ add_executable(${CEF_TARGET} MACOSX_BUNDLE ${CEFSIMPLE_RESOURCES_SRCS} ${CEFSIMPLE_SRCS})
+ SET_EXECUTABLE_TARGET_PROPERTIES(${CEF_TARGET})
+ add_dependencies(${CEF_TARGET} libcef_dll_wrapper)
+ target_link_libraries(${CEF_TARGET} libcef_dll_wrapper ${CEF_STANDARD_LIBS})
+ set_target_properties(${CEF_TARGET} PROPERTIES
+ MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/mac/Info.plist
+ )
+
+ # Copy the CEF framework into the Frameworks directory.
+ add_custom_command(
+ TARGET ${CEF_TARGET}
+ POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy_directory
+ "${CEF_BINARY_DIR}/Chromium Embedded Framework.framework"
+ "${CEF_APP}/Contents/Frameworks/Chromium Embedded Framework.framework"
+ VERBATIM
+ )
+
+ # Create the multiple Helper app bundle targets.
+ foreach(_suffix_list ${CEF_HELPER_APP_SUFFIXES})
+ # Convert to a list and extract the suffix values.
+ string(REPLACE ":" ";" _suffix_list ${_suffix_list})
+ list(GET _suffix_list 0 _name_suffix)
+ list(GET _suffix_list 1 _target_suffix)
+ list(GET _suffix_list 2 _plist_suffix)
+
+ # Define Helper target and output names.
+ set(_helper_target "${CEF_HELPER_TARGET}${_target_suffix}")
+ set(_helper_output_name "${CEF_HELPER_OUTPUT_NAME}${_name_suffix}")
+
+ # Create Helper-specific variants of the helper-Info.plist file. Do this
+ # manually because the configure_file command (which is executed as part of
+ # MACOSX_BUNDLE_INFO_PLIST) uses global env variables and would insert the
+ # wrong values with multiple targets.
+ set(_helper_info_plist "${CMAKE_CURRENT_BINARY_DIR}/helper-Info${_target_suffix}.plist")
+ file(READ "${CMAKE_CURRENT_SOURCE_DIR}/mac/helper-Info.plist" _plist_contents)
+ string(REPLACE "\${EXECUTABLE_NAME}" "${_helper_output_name}" _plist_contents ${_plist_contents})
+ string(REPLACE "\${PRODUCT_NAME}" "${_helper_output_name}" _plist_contents ${_plist_contents})
+ string(REPLACE "\${BUNDLE_ID_SUFFIX}" "${_plist_suffix}" _plist_contents ${_plist_contents})
+ file(WRITE ${_helper_info_plist} ${_plist_contents})
+
+ # Create Helper executable target.
+ add_executable(${_helper_target} MACOSX_BUNDLE ${CEFSIMPLE_HELPER_SRCS})
+ SET_EXECUTABLE_TARGET_PROPERTIES(${_helper_target})
+ add_dependencies(${_helper_target} libcef_dll_wrapper)
+ target_link_libraries(${_helper_target} libcef_dll_wrapper ${CEF_STANDARD_LIBS})
+ set_target_properties(${_helper_target} PROPERTIES
+ MACOSX_BUNDLE_INFO_PLIST ${_helper_info_plist}
+ OUTPUT_NAME ${_helper_output_name}
+ )
+
+ if(USE_SANDBOX)
+ target_link_libraries(${_helper_target} cef_sandbox_lib)
+ endif()
+
+ # Add the Helper as a dependency of the main executable target.
+ add_dependencies(${CEF_TARGET} "${_helper_target}")
+
+ # Copy the Helper app bundle into the Frameworks directory.
+ add_custom_command(
+ TARGET ${CEF_TARGET}
+ POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy_directory
+ "${CEF_TARGET_OUT_DIR}/${_helper_output_name}.app"
+ "${CEF_APP}/Contents/Frameworks/${_helper_output_name}.app"
+ VERBATIM
+ )
+ endforeach()
+
+ # Manually process and copy over resource files.
+ # The Xcode generator can support this via the set_target_properties RESOURCE
+ # directive but that doesn't properly handle nested resource directories.
+ # Remove these prefixes from input file paths.
+ set(PREFIXES "mac/")
+ COPY_MAC_RESOURCES("${CEFSIMPLE_RESOURCES_SRCS}" "${PREFIXES}" "${CEF_TARGET}" "${CMAKE_CURRENT_SOURCE_DIR}" "${CEF_APP}")
+endif()
+
+
+#
+# Windows configuration.
+#
+
+if(OS_WINDOWS)
+ # Executable target.
+ add_executable(${CEF_TARGET} WIN32 ${CEFSIMPLE_SRCS})
+ add_dependencies(${CEF_TARGET} libcef_dll_wrapper)
+ SET_EXECUTABLE_TARGET_PROPERTIES(${CEF_TARGET})
+ target_link_libraries(${CEF_TARGET} libcef_lib libcef_dll_wrapper ${CEF_STANDARD_LIBS})
+
+ if(USE_SANDBOX)
+ # Logical target used to link the cef_sandbox library.
+ ADD_LOGICAL_TARGET("cef_sandbox_lib" "${CEF_SANDBOX_LIB_DEBUG}" "${CEF_SANDBOX_LIB_RELEASE}")
+ target_link_libraries(${CEF_TARGET} cef_sandbox_lib ${CEF_SANDBOX_STANDARD_LIBS})
+ endif()
+
+ # Add the custom manifest files to the executable.
+ ADD_WINDOWS_MANIFEST("${CMAKE_CURRENT_SOURCE_DIR}" "${CEF_TARGET}" "exe")
+
+ # Copy binary and resource files to the target output directory.
+ COPY_FILES("${CEF_TARGET}" "${CEF_BINARY_FILES}" "${CEF_BINARY_DIR}" "${CEF_TARGET_OUT_DIR}")
+ COPY_FILES("${CEF_TARGET}" "${CEF_RESOURCE_FILES}" "${CEF_RESOURCE_DIR}" "${CEF_TARGET_OUT_DIR}")
+endif()
diff --git a/tests/cefsimple/cefsimple.exe.manifest b/tests/cefsimple/cefsimple.exe.manifest
new file mode 100644
index 00000000..d36f084b
--- /dev/null
+++ b/tests/cefsimple/cefsimple.exe.manifest
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+
+ <!--The compatibility section will be merged from build/win/compatibility.manifest -->
+
+ <dependency>
+ <dependentAssembly>
+ <assemblyIdentity type="Win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"></assemblyIdentity>
+ </dependentAssembly>
+ </dependency>
+
+ <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
+ <security>
+ <requestedPrivileges>
+ <requestedExecutionLevel level="asInvoker" />
+ </requestedPrivileges>
+ </security>
+ </trustInfo>
+
+</assembly>
diff --git a/tests/cefsimple/cefsimple.rc b/tests/cefsimple/cefsimple.rc
new file mode 100644
index 00000000..c4f3f297
--- /dev/null
+++ b/tests/cefsimple/cefsimple.rc
@@ -0,0 +1,79 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#define APSTUDIO_HIDDEN_SYMBOLS
+#include "windows.h"
+#undef APSTUDIO_HIDDEN_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_CEFSIMPLE ICON "res\cefsimple.ico"
+IDI_SMALL ICON "res\small.ico"
+
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#define APSTUDIO_HIDDEN_SYMBOLS\r\n"
+ "#include ""windows.h""\r\n"
+ "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/tests/cefsimple/cefsimple_linux.cc b/tests/cefsimple/cefsimple_linux.cc
new file mode 100644
index 00000000..26b3c7b9
--- /dev/null
+++ b/tests/cefsimple/cefsimple_linux.cc
@@ -0,0 +1,91 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefsimple/simple_app.h"
+
+#if defined(CEF_X11)
+#include <X11/Xlib.h>
+#endif
+
+#include "include/base/cef_logging.h"
+#include "include/cef_command_line.h"
+
+#if defined(CEF_X11)
+namespace {
+
+int XErrorHandlerImpl(Display* display, XErrorEvent* event) {
+ LOG(WARNING) << "X error received: "
+ << "type " << event->type << ", "
+ << "serial " << event->serial << ", "
+ << "error_code " << static_cast<int>(event->error_code) << ", "
+ << "request_code " << static_cast<int>(event->request_code)
+ << ", "
+ << "minor_code " << static_cast<int>(event->minor_code);
+ return 0;
+}
+
+int XIOErrorHandlerImpl(Display* display) {
+ return 0;
+}
+
+} // namespace
+#endif // defined(CEF_X11)
+
+// Entry point function for all processes.
+int main(int argc, char* argv[]) {
+ // Provide CEF with command-line arguments.
+ CefMainArgs main_args(argc, argv);
+
+ // CEF applications have multiple sub-processes (render, GPU, etc) that share
+ // the same executable. This function checks the command-line and, if this is
+ // a sub-process, executes the appropriate logic.
+ int exit_code = CefExecuteProcess(main_args, nullptr, nullptr);
+ if (exit_code >= 0) {
+ // The sub-process has completed so return here.
+ return exit_code;
+ }
+
+#if defined(CEF_X11)
+ // Install xlib error handlers so that the application won't be terminated
+ // on non-fatal errors.
+ XSetErrorHandler(XErrorHandlerImpl);
+ XSetIOErrorHandler(XIOErrorHandlerImpl);
+#endif
+
+ // Parse command-line arguments for use in this method.
+ CefRefPtr<CefCommandLine> command_line = CefCommandLine::CreateCommandLine();
+ command_line->InitFromArgv(argc, argv);
+
+ // Specify CEF global settings here.
+ CefSettings settings;
+
+ if (command_line->HasSwitch("enable-chrome-runtime")) {
+ // Enable experimental Chrome runtime. See issue #2969 for details.
+ settings.chrome_runtime = true;
+ }
+
+// When generating projects with CMake the CEF_USE_SANDBOX value will be defined
+// automatically. Pass -DUSE_SANDBOX=OFF to the CMake command-line to disable
+// use of the sandbox.
+#if !defined(CEF_USE_SANDBOX)
+ settings.no_sandbox = true;
+#endif
+
+ // SimpleApp implements application-level callbacks for the browser process.
+ // It will create the first browser instance in OnContextInitialized() after
+ // CEF has initialized.
+ CefRefPtr<SimpleApp> app(new SimpleApp);
+
+ // Initialize CEF for the browser process.
+ CefInitialize(main_args, settings, app.get(), nullptr);
+
+ // Run the CEF message loop. This will block until CefQuitMessageLoop() is
+ // called.
+ CefRunMessageLoop();
+
+ // Shut down CEF.
+ CefShutdown();
+
+ return 0;
+}
diff --git a/tests/cefsimple/cefsimple_mac.mm b/tests/cefsimple/cefsimple_mac.mm
new file mode 100644
index 00000000..6d2c9eda
--- /dev/null
+++ b/tests/cefsimple/cefsimple_mac.mm
@@ -0,0 +1,186 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors.
+// Portions copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <Cocoa/Cocoa.h>
+
+#include "include/cef_application_mac.h"
+#include "include/cef_command_line.h"
+#include "include/wrapper/cef_helpers.h"
+#include "include/wrapper/cef_library_loader.h"
+#include "tests/cefsimple/simple_app.h"
+#include "tests/cefsimple/simple_handler.h"
+
+// Receives notifications from the application.
+@interface SimpleAppDelegate : NSObject <NSApplicationDelegate>
+
+- (void)createApplication:(id)object;
+- (void)tryToTerminateApplication:(NSApplication*)app;
+@end
+
+// Provide the CefAppProtocol implementation required by CEF.
+@interface SimpleApplication : NSApplication <CefAppProtocol> {
+ @private
+ BOOL handlingSendEvent_;
+}
+@end
+
+@implementation SimpleApplication
+- (BOOL)isHandlingSendEvent {
+ return handlingSendEvent_;
+}
+
+- (void)setHandlingSendEvent:(BOOL)handlingSendEvent {
+ handlingSendEvent_ = handlingSendEvent;
+}
+
+- (void)sendEvent:(NSEvent*)event {
+ CefScopedSendingEvent sendingEventScoper;
+ [super sendEvent:event];
+}
+
+// |-terminate:| is the entry point for orderly "quit" operations in Cocoa. This
+// includes the application menu's quit menu item and keyboard equivalent, the
+// application's dock icon menu's quit menu item, "quit" (not "force quit") in
+// the Activity Monitor, and quits triggered by user logout and system restart
+// and shutdown.
+//
+// The default |-terminate:| implementation ends the process by calling exit(),
+// and thus never leaves the main run loop. This is unsuitable for Chromium
+// since Chromium depends on leaving the main run loop to perform an orderly
+// shutdown. We support the normal |-terminate:| interface by overriding the
+// default implementation. Our implementation, which is very specific to the
+// needs of Chromium, works by asking the application delegate to terminate
+// using its |-tryToTerminateApplication:| method.
+//
+// |-tryToTerminateApplication:| differs from the standard
+// |-applicationShouldTerminate:| in that no special event loop is run in the
+// case that immediate termination is not possible (e.g., if dialog boxes
+// allowing the user to cancel have to be shown). Instead, this method tries to
+// close all browsers by calling CloseBrowser(false) via
+// ClientHandler::CloseAllBrowsers. Calling CloseBrowser will result in a call
+// to ClientHandler::DoClose and execution of |-performClose:| on the NSWindow.
+// DoClose sets a flag that is used to differentiate between new close events
+// (e.g., user clicked the window close button) and in-progress close events
+// (e.g., user approved the close window dialog). The NSWindowDelegate
+// |-windowShouldClose:| method checks this flag and either calls
+// CloseBrowser(false) in the case of a new close event or destructs the
+// NSWindow in the case of an in-progress close event.
+// ClientHandler::OnBeforeClose will be called after the CEF NSView hosted in
+// the NSWindow is dealloc'ed.
+//
+// After the final browser window has closed ClientHandler::OnBeforeClose will
+// begin actual tear-down of the application by calling CefQuitMessageLoop.
+// This ends the NSApplication event loop and execution then returns to the
+// main() function for cleanup before application termination.
+//
+// The standard |-applicationShouldTerminate:| is not supported, and code paths
+// leading to it must be redirected.
+- (void)terminate:(id)sender {
+ SimpleAppDelegate* delegate =
+ static_cast<SimpleAppDelegate*>([NSApp delegate]);
+ [delegate tryToTerminateApplication:self];
+ // Return, don't exit. The application is responsible for exiting on its own.
+}
+@end
+
+@implementation SimpleAppDelegate
+
+// Create the application on the UI thread.
+- (void)createApplication:(id)object {
+ [[NSBundle mainBundle] loadNibNamed:@"MainMenu"
+ owner:NSApp
+ topLevelObjects:nil];
+
+ // Set the delegate for application events.
+ [[NSApplication sharedApplication] setDelegate:self];
+}
+
+- (void)tryToTerminateApplication:(NSApplication*)app {
+ SimpleHandler* handler = SimpleHandler::GetInstance();
+ if (handler && !handler->IsClosing()) {
+ handler->CloseAllBrowsers(false);
+ }
+}
+
+- (NSApplicationTerminateReply)applicationShouldTerminate:
+ (NSApplication*)sender {
+ return NSTerminateNow;
+}
+@end
+
+// Entry point function for the browser process.
+int main(int argc, char* argv[]) {
+ // Load the CEF framework library at runtime instead of linking directly
+ // as required by the macOS sandbox implementation.
+ CefScopedLibraryLoader library_loader;
+ if (!library_loader.LoadInMain()) {
+ return 1;
+ }
+
+ // Provide CEF with command-line arguments.
+ CefMainArgs main_args(argc, argv);
+
+ @autoreleasepool {
+ // Initialize the SimpleApplication instance.
+ [SimpleApplication sharedApplication];
+
+ // If there was an invocation to NSApp prior to this method, then the NSApp
+ // will not be a SimpleApplication, but will instead be an NSApplication.
+ // This is undesirable and we must enforce that this doesn't happen.
+ CHECK([NSApp isKindOfClass:[SimpleApplication class]]);
+
+ // Parse command-line arguments for use in this method.
+ CefRefPtr<CefCommandLine> command_line =
+ CefCommandLine::CreateCommandLine();
+ command_line->InitFromArgv(argc, argv);
+
+ // Specify CEF global settings here.
+ CefSettings settings;
+
+ const bool with_chrome_runtime =
+ command_line->HasSwitch("enable-chrome-runtime");
+
+ if (with_chrome_runtime) {
+ // Enable experimental Chrome runtime. See issue #2969 for details.
+ settings.chrome_runtime = true;
+ }
+
+ // When generating projects with CMake the CEF_USE_SANDBOX value will be
+ // defined automatically. Pass -DUSE_SANDBOX=OFF to the CMake command-line
+ // to disable use of the sandbox.
+#if !defined(CEF_USE_SANDBOX)
+ settings.no_sandbox = true;
+#endif
+
+ // SimpleApp implements application-level callbacks for the browser process.
+ // It will create the first browser instance in OnContextInitialized() after
+ // CEF has initialized.
+ CefRefPtr<SimpleApp> app(new SimpleApp);
+
+ // Initialize CEF for the browser process.
+ CefInitialize(main_args, settings, app.get(), nullptr);
+
+ // Create the application delegate.
+ NSObject* delegate = [[SimpleAppDelegate alloc] init];
+ [delegate performSelectorOnMainThread:@selector(createApplication:)
+ withObject:nil
+ waitUntilDone:NO];
+
+ // Run the CEF message loop. This will block until CefQuitMessageLoop() is
+ // called.
+ CefRunMessageLoop();
+
+ // Shut down CEF.
+ CefShutdown();
+
+ // Release the delegate.
+#if !__has_feature(objc_arc)
+ [delegate release];
+#endif // !__has_feature(objc_arc)
+ delegate = nil;
+ } // @autoreleasepool
+
+ return 0;
+}
diff --git a/tests/cefsimple/cefsimple_win.cc b/tests/cefsimple/cefsimple_win.cc
new file mode 100644
index 00000000..ad803c56
--- /dev/null
+++ b/tests/cefsimple/cefsimple_win.cc
@@ -0,0 +1,105 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include <windows.h>
+
+#include "include/cef_command_line.h"
+#include "include/cef_sandbox_win.h"
+#include "tests/cefsimple/simple_app.h"
+
+// When generating projects with CMake the CEF_USE_SANDBOX value will be defined
+// automatically if using the required compiler version. Pass -DUSE_SANDBOX=OFF
+// to the CMake command-line to disable use of the sandbox.
+// Uncomment this line to manually enable sandbox support.
+// #define CEF_USE_SANDBOX 1
+
+#if defined(CEF_USE_SANDBOX)
+// The cef_sandbox.lib static library may not link successfully with all VS
+// versions.
+#pragma comment(lib, "cef_sandbox.lib")
+#endif
+
+// Entry point function for all processes.
+int APIENTRY wWinMain(HINSTANCE hInstance,
+ HINSTANCE hPrevInstance,
+ LPTSTR lpCmdLine,
+ int nCmdShow) {
+ UNREFERENCED_PARAMETER(hPrevInstance);
+ UNREFERENCED_PARAMETER(lpCmdLine);
+
+ int exit_code;
+
+#if defined(ARCH_CPU_32_BITS)
+ // Run the main thread on 32-bit Windows using a fiber with the preferred 4MiB
+ // stack size. This function must be called at the top of the executable entry
+ // point function (`main()` or `wWinMain()`). It is used in combination with
+ // the initial stack size of 0.5MiB configured via the `/STACK:0x80000` linker
+ // flag on executable targets. This saves significant memory on threads (like
+ // those in the Windows thread pool, and others) whose stack size can only be
+ // controlled via the linker flag.
+ exit_code = CefRunWinMainWithPreferredStackSize(wWinMain, hInstance,
+ lpCmdLine, nCmdShow);
+ if (exit_code >= 0) {
+ // The fiber has completed so return here.
+ return exit_code;
+ }
+#endif
+
+ // Enable High-DPI support on Windows 7 or newer.
+ CefEnableHighDPISupport();
+
+ void* sandbox_info = nullptr;
+
+#if defined(CEF_USE_SANDBOX)
+ // Manage the life span of the sandbox information object. This is necessary
+ // for sandbox support on Windows. See cef_sandbox_win.h for complete details.
+ CefScopedSandboxInfo scoped_sandbox;
+ sandbox_info = scoped_sandbox.sandbox_info();
+#endif
+
+ // Provide CEF with command-line arguments.
+ CefMainArgs main_args(hInstance);
+
+ // CEF applications have multiple sub-processes (render, GPU, etc) that share
+ // the same executable. This function checks the command-line and, if this is
+ // a sub-process, executes the appropriate logic.
+ exit_code = CefExecuteProcess(main_args, nullptr, sandbox_info);
+ if (exit_code >= 0) {
+ // The sub-process has completed so return here.
+ return exit_code;
+ }
+
+ // Parse command-line arguments for use in this method.
+ CefRefPtr<CefCommandLine> command_line = CefCommandLine::CreateCommandLine();
+ command_line->InitFromString(::GetCommandLineW());
+
+ // Specify CEF global settings here.
+ CefSettings settings;
+
+ if (command_line->HasSwitch("enable-chrome-runtime")) {
+ // Enable experimental Chrome runtime. See issue #2969 for details.
+ settings.chrome_runtime = true;
+ }
+
+#if !defined(CEF_USE_SANDBOX)
+ settings.no_sandbox = true;
+#endif
+
+ // SimpleApp implements application-level callbacks for the browser process.
+ // It will create the first browser instance in OnContextInitialized() after
+ // CEF has initialized.
+ CefRefPtr<SimpleApp> app(new SimpleApp);
+
+ // Initialize CEF.
+ CefInitialize(main_args, settings, app.get(), sandbox_info);
+
+ // Run the CEF message loop. This will block until CefQuitMessageLoop() is
+ // called.
+ CefRunMessageLoop();
+
+ // Shut down CEF.
+ CefShutdown();
+
+ return 0;
+}
diff --git a/tests/cefsimple/mac/English.lproj/InfoPlist.strings b/tests/cefsimple/mac/English.lproj/InfoPlist.strings
new file mode 100644
index 00000000..dc5ebb06
--- /dev/null
+++ b/tests/cefsimple/mac/English.lproj/InfoPlist.strings
@@ -0,0 +1,3 @@
+/* Localized versions of Info.plist keys */
+
+NSHumanReadableCopyright = "© Chromium Embedded Framework Authors, 2013";
diff --git a/tests/cefsimple/mac/English.lproj/MainMenu.xib b/tests/cefsimple/mac/English.lproj/MainMenu.xib
new file mode 100644
index 00000000..5d2ceece
--- /dev/null
+++ b/tests/cefsimple/mac/English.lproj/MainMenu.xib
@@ -0,0 +1,330 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="10117" systemVersion="16B2657" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
+ <dependencies>
+ <deployment version="1090" identifier="macosx"/>
+ <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="10117"/>
+ </dependencies>
+ <objects>
+ <customObject id="-2" userLabel="File's Owner" customClass="NSApplication"/>
+ <customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
+ <customObject id="-3" userLabel="Application"/>
+ <menu title="AMainMenu" systemMenu="main" id="29" userLabel="MainMenu">
+ <items>
+ <menuItem title="cefsimple" id="56">
+ <menu key="submenu" title="TestShell" systemMenu="apple" id="57">
+ <items>
+ <menuItem title="About cefsimple" id="58">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="orderFrontStandardAboutPanel:" target="-2" id="142"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="236">
+ <modifierMask key="keyEquivalentModifierMask" command="YES"/>
+ </menuItem>
+ <menuItem title="Preferences…" keyEquivalent="," id="129" userLabel="121"/>
+ <menuItem isSeparatorItem="YES" id="143">
+ <modifierMask key="keyEquivalentModifierMask" command="YES"/>
+ </menuItem>
+ <menuItem title="Services" id="131">
+ <menu key="submenu" title="Services" systemMenu="services" id="130"/>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="144">
+ <modifierMask key="keyEquivalentModifierMask" command="YES"/>
+ </menuItem>
+ <menuItem title="Hide cefsimple" keyEquivalent="h" id="134">
+ <connections>
+ <action selector="hide:" target="-1" id="367"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Hide Others" keyEquivalent="h" id="145">
+ <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
+ <connections>
+ <action selector="hideOtherApplications:" target="-1" id="368"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Show All" id="150">
+ <connections>
+ <action selector="unhideAllApplications:" target="-1" id="370"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="149">
+ <modifierMask key="keyEquivalentModifierMask" command="YES"/>
+ </menuItem>
+ <menuItem title="Quit cefsimple" keyEquivalent="q" id="136" userLabel="1111">
+ <connections>
+ <action selector="terminate:" target="-1" id="369"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="File" id="83">
+ <menu key="submenu" title="File" id="81">
+ <items>
+ <menuItem title="New" keyEquivalent="n" id="82" userLabel="9">
+ <connections>
+ <action selector="newDocument:" target="-1" id="373"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Open…" keyEquivalent="o" id="72">
+ <connections>
+ <action selector="openDocument:" target="-1" id="374"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Open Recent" id="124">
+ <menu key="submenu" title="Open Recent" systemMenu="recentDocuments" id="125">
+ <items>
+ <menuItem title="Clear Menu" id="126">
+ <connections>
+ <action selector="clearRecentDocuments:" target="-1" id="127"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="79" userLabel="7">
+ <modifierMask key="keyEquivalentModifierMask" command="YES"/>
+ </menuItem>
+ <menuItem title="Close" keyEquivalent="w" id="73" userLabel="1">
+ <connections>
+ <action selector="performClose:" target="-1" id="193"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Save" keyEquivalent="s" id="75" userLabel="3">
+ <connections>
+ <action selector="saveDocument:" target="-1" id="362"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Save As…" keyEquivalent="S" id="80" userLabel="8">
+ <modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
+ <connections>
+ <action selector="saveDocumentAs:" target="-1" id="363"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Revert to Saved" id="112" userLabel="10">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="revertDocumentToSaved:" target="-1" id="364"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="74" userLabel="2">
+ <modifierMask key="keyEquivalentModifierMask" command="YES"/>
+ </menuItem>
+ <menuItem title="Page Setup..." keyEquivalent="P" id="77" userLabel="5">
+ <modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
+ <connections>
+ <action selector="runPageLayout:" target="-1" id="87"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Print…" keyEquivalent="p" id="78" userLabel="6">
+ <connections>
+ <action selector="print:" target="-1" id="86"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="Edit" id="217">
+ <menu key="submenu" title="Edit" id="205">
+ <items>
+ <menuItem title="Undo" keyEquivalent="z" id="207">
+ <connections>
+ <action selector="undo:" target="-1" id="223"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Redo" keyEquivalent="Z" id="215">
+ <modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
+ <connections>
+ <action selector="redo:" target="-1" id="231"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="206">
+ <modifierMask key="keyEquivalentModifierMask" command="YES"/>
+ </menuItem>
+ <menuItem title="Cut" keyEquivalent="x" id="199">
+ <connections>
+ <action selector="cut:" target="-1" id="228"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Copy" keyEquivalent="c" id="197">
+ <connections>
+ <action selector="copy:" target="-1" id="224"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Paste" keyEquivalent="v" id="203">
+ <connections>
+ <action selector="paste:" target="-1" id="226"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Delete" id="202">
+ <connections>
+ <action selector="delete:" target="-1" id="235"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Select All" keyEquivalent="a" id="198">
+ <connections>
+ <action selector="selectAll:" target="-1" id="232"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="214">
+ <modifierMask key="keyEquivalentModifierMask" command="YES"/>
+ </menuItem>
+ <menuItem title="Find" id="218">
+ <menu key="submenu" title="Find" id="220">
+ <items>
+ <menuItem title="Find…" tag="1" keyEquivalent="f" id="209">
+ <connections>
+ <action selector="performFindPanelAction:" target="-1" id="241"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Find Next" tag="2" keyEquivalent="g" id="208"/>
+ <menuItem title="Find Previous" tag="3" keyEquivalent="G" id="213">
+ <modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
+ </menuItem>
+ <menuItem title="Use Selection for Find" tag="7" keyEquivalent="e" id="221"/>
+ <menuItem title="Jump to Selection" keyEquivalent="j" id="210">
+ <connections>
+ <action selector="centerSelectionInVisibleArea:" target="-1" id="245"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="Spelling and Grammar" id="216">
+ <menu key="submenu" title="Spelling and Grammar" id="200">
+ <items>
+ <menuItem title="Show Spelling…" keyEquivalent=":" id="204">
+ <connections>
+ <action selector="showGuessPanel:" target="-1" id="230"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Check Spelling" keyEquivalent=";" id="201">
+ <connections>
+ <action selector="checkSpelling:" target="-1" id="225"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Check Spelling While Typing" id="219">
+ <connections>
+ <action selector="toggleContinuousSpellChecking:" target="-1" id="222"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Check Grammar With Spelling" id="346">
+ <connections>
+ <action selector="toggleGrammarChecking:" target="-1" id="347"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="Substitutions" id="348">
+ <menu key="submenu" title="Substitutions" id="349">
+ <items>
+ <menuItem title="Smart Copy/Paste" tag="1" keyEquivalent="f" id="350">
+ <connections>
+ <action selector="toggleSmartInsertDelete:" target="-1" id="355"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Smart Quotes" tag="2" keyEquivalent="g" id="351">
+ <connections>
+ <action selector="toggleAutomaticQuoteSubstitution:" target="-1" id="356"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Smart Links" tag="3" keyEquivalent="G" id="354">
+ <modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
+ <connections>
+ <action selector="toggleAutomaticLinkDetection:" target="-1" id="357"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="Speech" id="211">
+ <menu key="submenu" title="Speech" id="212">
+ <items>
+ <menuItem title="Start Speaking" id="196">
+ <connections>
+ <action selector="startSpeaking:" target="-1" id="233"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Stop Speaking" id="195">
+ <connections>
+ <action selector="stopSpeaking:" target="-1" id="227"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="Format" id="299">
+ <menu key="submenu" title="Format" id="300">
+ <items>
+ <menuItem title="Show Fonts" keyEquivalent="t" id="344"/>
+ <menuItem title="Show Colors" keyEquivalent="C" id="345">
+ <modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
+ <connections>
+ <action selector="orderFrontColorPanel:" target="-1" id="361"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="View" id="295">
+ <menu key="submenu" title="View" id="296">
+ <items>
+ <menuItem title="Show Toolbar" keyEquivalent="t" id="297">
+ <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
+ <connections>
+ <action selector="toggleToolbarShown:" target="-1" id="366"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Customize Toolbar…" id="298">
+ <connections>
+ <action selector="runToolbarCustomizationPalette:" target="-1" id="365"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="Window" id="19">
+ <menu key="submenu" title="Window" systemMenu="window" id="24">
+ <items>
+ <menuItem title="Minimize" keyEquivalent="m" id="23">
+ <connections>
+ <action selector="performMiniaturize:" target="-1" id="37"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Zoom" id="239">
+ <connections>
+ <action selector="performZoom:" target="-1" id="240"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="92">
+ <modifierMask key="keyEquivalentModifierMask" command="YES"/>
+ </menuItem>
+ <menuItem title="Bring All to Front" id="5">
+ <connections>
+ <action selector="arrangeInFront:" target="-1" id="39"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="Help" id="103" userLabel="1">
+ <menu key="submenu" title="Help" id="106" userLabel="2">
+ <items>
+ <menuItem title="cefsimple Help" keyEquivalent="?" id="111">
+ <connections>
+ <action selector="showHelp:" target="-1" id="360"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ </items>
+ </menu>
+ <userDefaultsController representsSharedInstance="YES" id="389"/>
+ </objects>
+</document>
diff --git a/tests/cefsimple/mac/Info.plist b/tests/cefsimple/mac/Info.plist
new file mode 100644
index 00000000..c83d7c14
--- /dev/null
+++ b/tests/cefsimple/mac/Info.plist
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleIconFile</key>
+ <string>cefsimple.icns</string>
+ <key>CFBundleIdentifier</key>
+ <string>org.cef.cefsimple</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1.0</string>
+ <key>LSEnvironment</key>
+ <dict>
+ <key>MallocNanoZone</key>
+ <string>0</string>
+ </dict>
+ <key>LSMinimumSystemVersion</key>
+ <string>10.13.0</string>
+ <key>NSMainNibFile</key>
+ <string>MainMenu</string>
+ <key>NSPrincipalClass</key>
+ <string>NSApplication</string>
+ <key>NSSupportsAutomaticGraphicsSwitching</key>
+ <true/>
+</dict>
+</plist>
diff --git a/tests/cefsimple/mac/cefsimple.icns b/tests/cefsimple/mac/cefsimple.icns
new file mode 100644
index 00000000..f36742de
--- /dev/null
+++ b/tests/cefsimple/mac/cefsimple.icns
Binary files differ
diff --git a/tests/cefsimple/mac/helper-Info.plist b/tests/cefsimple/mac/helper-Info.plist
new file mode 100644
index 00000000..17842e2a
--- /dev/null
+++ b/tests/cefsimple/mac/helper-Info.plist
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>en</string>
+ <key>CFBundleDisplayName</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleIdentifier</key>
+ <string>org.cef.cefsimple.helper${BUNDLE_ID_SUFFIX}</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>LSEnvironment</key>
+ <dict>
+ <key>MallocNanoZone</key>
+ <string>0</string>
+ </dict>
+ <key>LSFileQuarantineEnabled</key>
+ <true/>
+ <key>LSMinimumSystemVersion</key>
+ <string>10.13.0</string>
+ <key>LSUIElement</key>
+ <string>1</string>
+ <key>NSSupportsAutomaticGraphicsSwitching</key>
+ <true/>
+</dict>
+</plist>
diff --git a/tests/cefsimple/process_helper_mac.cc b/tests/cefsimple/process_helper_mac.cc
new file mode 100644
index 00000000..bc6d83c0
--- /dev/null
+++ b/tests/cefsimple/process_helper_mac.cc
@@ -0,0 +1,37 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#include "include/cef_app.h"
+#include "include/wrapper/cef_library_loader.h"
+
+// When generating projects with CMake the CEF_USE_SANDBOX value will be defined
+// automatically. Pass -DUSE_SANDBOX=OFF to the CMake command-line to disable
+// use of the sandbox.
+#if defined(CEF_USE_SANDBOX)
+#include "include/cef_sandbox_mac.h"
+#endif
+
+// Entry point function for sub-processes.
+int main(int argc, char* argv[]) {
+#if defined(CEF_USE_SANDBOX)
+ // Initialize the macOS sandbox for this helper process.
+ CefScopedSandboxContext sandbox_context;
+ if (!sandbox_context.Initialize(argc, argv)) {
+ return 1;
+ }
+#endif
+
+ // Load the CEF framework library at runtime instead of linking directly
+ // as required by the macOS sandbox implementation.
+ CefScopedLibraryLoader library_loader;
+ if (!library_loader.LoadInHelper()) {
+ return 1;
+ }
+
+ // Provide CEF with command-line arguments.
+ CefMainArgs main_args(argc, argv);
+
+ // Execute the sub-process.
+ return CefExecuteProcess(main_args, nullptr, nullptr);
+}
diff --git a/tests/cefsimple/res/cefsimple.ico b/tests/cefsimple/res/cefsimple.ico
new file mode 100644
index 00000000..d551aa3a
--- /dev/null
+++ b/tests/cefsimple/res/cefsimple.ico
Binary files differ
diff --git a/tests/cefsimple/res/small.ico b/tests/cefsimple/res/small.ico
new file mode 100644
index 00000000..d551aa3a
--- /dev/null
+++ b/tests/cefsimple/res/small.ico
Binary files differ
diff --git a/tests/cefsimple/resource.h b/tests/cefsimple/resource.h
new file mode 100644
index 00000000..ba1f3a9e
--- /dev/null
+++ b/tests/cefsimple/resource.h
@@ -0,0 +1,26 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by cefsimple.rc
+//
+
+#define IDI_CEFSIMPLE 100
+#define IDI_SMALL 101
+
+// Avoid files associated with MacOS
+#define _X86_
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NO_MFC 1
+#define _APS_NEXT_RESOURCE_VALUE 102
+#define _APS_NEXT_COMMAND_VALUE 32700
+#define _APS_NEXT_CONTROL_VALUE 1000
+#define _APS_NEXT_SYMED_VALUE 102
+#endif
+#endif
diff --git a/tests/cefsimple/simple_app.cc b/tests/cefsimple/simple_app.cc
new file mode 100644
index 00000000..72556cf5
--- /dev/null
+++ b/tests/cefsimple/simple_app.cc
@@ -0,0 +1,136 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefsimple/simple_app.h"
+
+#include <string>
+
+#include "include/cef_browser.h"
+#include "include/cef_command_line.h"
+#include "include/views/cef_browser_view.h"
+#include "include/views/cef_window.h"
+#include "include/wrapper/cef_helpers.h"
+#include "tests/cefsimple/simple_handler.h"
+
+namespace {
+
+// When using the Views framework this object provides the delegate
+// implementation for the CefWindow that hosts the Views-based browser.
+class SimpleWindowDelegate : public CefWindowDelegate {
+ public:
+ explicit SimpleWindowDelegate(CefRefPtr<CefBrowserView> browser_view)
+ : browser_view_(browser_view) {}
+
+ void OnWindowCreated(CefRefPtr<CefWindow> window) override {
+ // Add the browser view and show the window.
+ window->AddChildView(browser_view_);
+ window->Show();
+
+ // Give keyboard focus to the browser view.
+ browser_view_->RequestFocus();
+ }
+
+ void OnWindowDestroyed(CefRefPtr<CefWindow> window) override {
+ browser_view_ = nullptr;
+ }
+
+ bool CanClose(CefRefPtr<CefWindow> window) override {
+ // Allow the window to close if the browser says it's OK.
+ CefRefPtr<CefBrowser> browser = browser_view_->GetBrowser();
+ if (browser) {
+ return browser->GetHost()->TryCloseBrowser();
+ }
+ return true;
+ }
+
+ CefSize GetPreferredSize(CefRefPtr<CefView> view) override {
+ return CefSize(800, 600);
+ }
+
+ private:
+ CefRefPtr<CefBrowserView> browser_view_;
+
+ IMPLEMENT_REFCOUNTING(SimpleWindowDelegate);
+ DISALLOW_COPY_AND_ASSIGN(SimpleWindowDelegate);
+};
+
+class SimpleBrowserViewDelegate : public CefBrowserViewDelegate {
+ public:
+ SimpleBrowserViewDelegate() {}
+
+ bool OnPopupBrowserViewCreated(CefRefPtr<CefBrowserView> browser_view,
+ CefRefPtr<CefBrowserView> popup_browser_view,
+ bool is_devtools) override {
+ // Create a new top-level Window for the popup. It will show itself after
+ // creation.
+ CefWindow::CreateTopLevelWindow(
+ new SimpleWindowDelegate(popup_browser_view));
+
+ // We created the Window.
+ return true;
+ }
+
+ private:
+ IMPLEMENT_REFCOUNTING(SimpleBrowserViewDelegate);
+ DISALLOW_COPY_AND_ASSIGN(SimpleBrowserViewDelegate);
+};
+
+} // namespace
+
+SimpleApp::SimpleApp() {}
+
+void SimpleApp::OnContextInitialized() {
+ CEF_REQUIRE_UI_THREAD();
+
+ CefRefPtr<CefCommandLine> command_line =
+ CefCommandLine::GetGlobalCommandLine();
+
+ // Create the browser using the Views framework if "--use-views" is specified
+ // via the command-line. Otherwise, create the browser using the native
+ // platform framework.
+ const bool use_views = command_line->HasSwitch("use-views");
+
+ // SimpleHandler implements browser-level callbacks.
+ CefRefPtr<SimpleHandler> handler(new SimpleHandler(use_views));
+
+ // Specify CEF browser settings here.
+ CefBrowserSettings browser_settings;
+
+ std::string url;
+
+ // Check if a "--url=" value was provided via the command-line. If so, use
+ // that instead of the default URL.
+ url = command_line->GetSwitchValue("url");
+ if (url.empty()) {
+ url = "http://www.google.com";
+ }
+
+ if (use_views) {
+ // Create the BrowserView.
+ CefRefPtr<CefBrowserView> browser_view = CefBrowserView::CreateBrowserView(
+ handler, url, browser_settings, nullptr, nullptr,
+ new SimpleBrowserViewDelegate());
+
+ // Create the Window. It will show itself after creation.
+ CefWindow::CreateTopLevelWindow(new SimpleWindowDelegate(browser_view));
+ } else {
+ // Information used when creating the native window.
+ CefWindowInfo window_info;
+
+#if defined(OS_WIN)
+ // On Windows we need to specify certain flags that will be passed to
+ // CreateWindowEx().
+ window_info.SetAsPopup(nullptr, "cefsimple");
+#endif
+
+ // Create the first browser window.
+ CefBrowserHost::CreateBrowser(window_info, handler, url, browser_settings,
+ nullptr, nullptr);
+ }
+}
+
+CefRefPtr<CefClient> SimpleApp::GetDefaultClient() {
+ // Called when a new browser window is created via the Chrome runtime UI.
+ return SimpleHandler::GetInstance();
+}
diff --git a/tests/cefsimple/simple_app.h b/tests/cefsimple/simple_app.h
new file mode 100644
index 00000000..81afd54b
--- /dev/null
+++ b/tests/cefsimple/simple_app.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFSIMPLE_SIMPLE_APP_H_
+#define CEF_TESTS_CEFSIMPLE_SIMPLE_APP_H_
+
+#include "include/cef_app.h"
+
+// Implement application-level callbacks for the browser process.
+class SimpleApp : public CefApp, public CefBrowserProcessHandler {
+ public:
+ SimpleApp();
+
+ // CefApp methods:
+ CefRefPtr<CefBrowserProcessHandler> GetBrowserProcessHandler() override {
+ return this;
+ }
+
+ // CefBrowserProcessHandler methods:
+ void OnContextInitialized() override;
+ CefRefPtr<CefClient> GetDefaultClient() override;
+
+ private:
+ // Include the default reference counting implementation.
+ IMPLEMENT_REFCOUNTING(SimpleApp);
+};
+
+#endif // CEF_TESTS_CEFSIMPLE_SIMPLE_APP_H_
diff --git a/tests/cefsimple/simple_handler.cc b/tests/cefsimple/simple_handler.cc
new file mode 100644
index 00000000..e7d977f5
--- /dev/null
+++ b/tests/cefsimple/simple_handler.cc
@@ -0,0 +1,161 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefsimple/simple_handler.h"
+
+#include <sstream>
+#include <string>
+
+#include "include/base/cef_callback.h"
+#include "include/cef_app.h"
+#include "include/cef_parser.h"
+#include "include/views/cef_browser_view.h"
+#include "include/views/cef_window.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "include/wrapper/cef_helpers.h"
+
+namespace {
+
+SimpleHandler* g_instance = nullptr;
+
+// Returns a data: URI with the specified contents.
+std::string GetDataURI(const std::string& data, const std::string& mime_type) {
+ return "data:" + mime_type + ";base64," +
+ CefURIEncode(CefBase64Encode(data.data(), data.size()), false)
+ .ToString();
+}
+
+} // namespace
+
+SimpleHandler::SimpleHandler(bool use_views)
+ : use_views_(use_views), is_closing_(false) {
+ DCHECK(!g_instance);
+ g_instance = this;
+}
+
+SimpleHandler::~SimpleHandler() {
+ g_instance = nullptr;
+}
+
+// static
+SimpleHandler* SimpleHandler::GetInstance() {
+ return g_instance;
+}
+
+void SimpleHandler::OnTitleChange(CefRefPtr<CefBrowser> browser,
+ const CefString& title) {
+ CEF_REQUIRE_UI_THREAD();
+
+ if (use_views_) {
+ // Set the title of the window using the Views framework.
+ CefRefPtr<CefBrowserView> browser_view =
+ CefBrowserView::GetForBrowser(browser);
+ if (browser_view) {
+ CefRefPtr<CefWindow> window = browser_view->GetWindow();
+ if (window) {
+ window->SetTitle(title);
+ }
+ }
+ } else if (!IsChromeRuntimeEnabled()) {
+ // Set the title of the window using platform APIs.
+ PlatformTitleChange(browser, title);
+ }
+}
+
+void SimpleHandler::OnAfterCreated(CefRefPtr<CefBrowser> browser) {
+ CEF_REQUIRE_UI_THREAD();
+
+ // Add to the list of existing browsers.
+ browser_list_.push_back(browser);
+}
+
+bool SimpleHandler::DoClose(CefRefPtr<CefBrowser> browser) {
+ CEF_REQUIRE_UI_THREAD();
+
+ // Closing the main window requires special handling. See the DoClose()
+ // documentation in the CEF header for a detailed destription of this
+ // process.
+ if (browser_list_.size() == 1) {
+ // Set a flag to indicate that the window close should be allowed.
+ is_closing_ = true;
+ }
+
+ // Allow the close. For windowed browsers this will result in the OS close
+ // event being sent.
+ return false;
+}
+
+void SimpleHandler::OnBeforeClose(CefRefPtr<CefBrowser> browser) {
+ CEF_REQUIRE_UI_THREAD();
+
+ // Remove from the list of existing browsers.
+ BrowserList::iterator bit = browser_list_.begin();
+ for (; bit != browser_list_.end(); ++bit) {
+ if ((*bit)->IsSame(browser)) {
+ browser_list_.erase(bit);
+ break;
+ }
+ }
+
+ if (browser_list_.empty()) {
+ // All browser windows have closed. Quit the application message loop.
+ CefQuitMessageLoop();
+ }
+}
+
+void SimpleHandler::OnLoadError(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ ErrorCode errorCode,
+ const CefString& errorText,
+ const CefString& failedUrl) {
+ CEF_REQUIRE_UI_THREAD();
+
+ // Allow Chrome to show the error page.
+ if (IsChromeRuntimeEnabled()) {
+ return;
+ }
+
+ // Don't display an error for downloaded files.
+ if (errorCode == ERR_ABORTED) {
+ return;
+ }
+
+ // Display a load error message using a data: URI.
+ std::stringstream ss;
+ ss << "<html><body bgcolor=\"white\">"
+ "<h2>Failed to load URL "
+ << std::string(failedUrl) << " with error " << std::string(errorText)
+ << " (" << errorCode << ").</h2></body></html>";
+
+ frame->LoadURL(GetDataURI(ss.str(), "text/html"));
+}
+
+void SimpleHandler::CloseAllBrowsers(bool force_close) {
+ if (!CefCurrentlyOn(TID_UI)) {
+ // Execute on the UI thread.
+ CefPostTask(TID_UI, base::BindOnce(&SimpleHandler::CloseAllBrowsers, this,
+ force_close));
+ return;
+ }
+
+ if (browser_list_.empty()) {
+ return;
+ }
+
+ BrowserList::const_iterator it = browser_list_.begin();
+ for (; it != browser_list_.end(); ++it) {
+ (*it)->GetHost()->CloseBrowser(force_close);
+ }
+}
+
+// static
+bool SimpleHandler::IsChromeRuntimeEnabled() {
+ static int value = -1;
+ if (value == -1) {
+ CefRefPtr<CefCommandLine> command_line =
+ CefCommandLine::GetGlobalCommandLine();
+ value = command_line->HasSwitch("enable-chrome-runtime") ? 1 : 0;
+ }
+ return value == 1;
+}
diff --git a/tests/cefsimple/simple_handler.h b/tests/cefsimple/simple_handler.h
new file mode 100644
index 00000000..c53421ec
--- /dev/null
+++ b/tests/cefsimple/simple_handler.h
@@ -0,0 +1,74 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFSIMPLE_SIMPLE_HANDLER_H_
+#define CEF_TESTS_CEFSIMPLE_SIMPLE_HANDLER_H_
+
+#include "include/cef_client.h"
+
+#include <list>
+
+class SimpleHandler : public CefClient,
+ public CefDisplayHandler,
+ public CefLifeSpanHandler,
+ public CefLoadHandler {
+ public:
+ explicit SimpleHandler(bool use_views);
+ ~SimpleHandler();
+
+ // Provide access to the single global instance of this object.
+ static SimpleHandler* GetInstance();
+
+ // CefClient methods:
+ virtual CefRefPtr<CefDisplayHandler> GetDisplayHandler() override {
+ return this;
+ }
+ virtual CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() override {
+ return this;
+ }
+ virtual CefRefPtr<CefLoadHandler> GetLoadHandler() override { return this; }
+
+ // CefDisplayHandler methods:
+ virtual void OnTitleChange(CefRefPtr<CefBrowser> browser,
+ const CefString& title) override;
+
+ // CefLifeSpanHandler methods:
+ virtual void OnAfterCreated(CefRefPtr<CefBrowser> browser) override;
+ virtual bool DoClose(CefRefPtr<CefBrowser> browser) override;
+ virtual void OnBeforeClose(CefRefPtr<CefBrowser> browser) override;
+
+ // CefLoadHandler methods:
+ virtual void OnLoadError(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ ErrorCode errorCode,
+ const CefString& errorText,
+ const CefString& failedUrl) override;
+
+ // Request that all existing browser windows close.
+ void CloseAllBrowsers(bool force_close);
+
+ bool IsClosing() const { return is_closing_; }
+
+ // Returns true if the Chrome runtime is enabled.
+ static bool IsChromeRuntimeEnabled();
+
+ private:
+ // Platform-specific implementation.
+ void PlatformTitleChange(CefRefPtr<CefBrowser> browser,
+ const CefString& title);
+
+ // True if the application is using the Views framework.
+ const bool use_views_;
+
+ // List of existing browser windows. Only accessed on the CEF UI thread.
+ typedef std::list<CefRefPtr<CefBrowser>> BrowserList;
+ BrowserList browser_list_;
+
+ bool is_closing_;
+
+ // Include the default reference counting implementation.
+ IMPLEMENT_REFCOUNTING(SimpleHandler);
+};
+
+#endif // CEF_TESTS_CEFSIMPLE_SIMPLE_HANDLER_H_
diff --git a/tests/cefsimple/simple_handler_linux.cc b/tests/cefsimple/simple_handler_linux.cc
new file mode 100644
index 00000000..92d9a163
--- /dev/null
+++ b/tests/cefsimple/simple_handler_linux.cc
@@ -0,0 +1,52 @@
+// Copyright (c) 2014 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefsimple/simple_handler.h"
+
+#if defined(CEF_X11)
+#include <X11/Xatom.h>
+#include <X11/Xlib.h>
+#endif
+
+#include <string>
+
+#include "include/base/cef_logging.h"
+#include "include/cef_browser.h"
+
+void SimpleHandler::PlatformTitleChange(CefRefPtr<CefBrowser> browser,
+ const CefString& title) {
+ std::string titleStr(title);
+
+#if defined(CEF_X11)
+ // Retrieve the X11 display shared with Chromium.
+ ::Display* display = cef_get_xdisplay();
+ DCHECK(display);
+
+ // Retrieve the X11 window handle for the browser.
+ ::Window window = browser->GetHost()->GetWindowHandle();
+ if (window == kNullWindowHandle) {
+ return;
+ }
+
+ // Retrieve the atoms required by the below XChangeProperty call.
+ const char* kAtoms[] = {"_NET_WM_NAME", "UTF8_STRING"};
+ Atom atoms[2];
+ int result =
+ XInternAtoms(display, const_cast<char**>(kAtoms), 2, false, atoms);
+ if (!result) {
+ NOTREACHED();
+ }
+
+ // Set the window title.
+ XChangeProperty(display, window, atoms[0], atoms[1], 8, PropModeReplace,
+ reinterpret_cast<const unsigned char*>(titleStr.c_str()),
+ titleStr.size());
+
+ // TODO(erg): This is technically wrong. So XStoreName and friends expect
+ // this in Host Portable Character Encoding instead of UTF-8, which I believe
+ // is Compound Text. This shouldn't matter 90% of the time since this is the
+ // fallback to the UTF8 property above.
+ XStoreName(display, browser->GetHost()->GetWindowHandle(), titleStr.c_str());
+#endif // defined(CEF_X11)
+}
diff --git a/tests/cefsimple/simple_handler_mac.mm b/tests/cefsimple/simple_handler_mac.mm
new file mode 100644
index 00000000..5a666627
--- /dev/null
+++ b/tests/cefsimple/simple_handler_mac.mm
@@ -0,0 +1,19 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefsimple/simple_handler.h"
+
+#import <Cocoa/Cocoa.h>
+
+#include "include/cef_browser.h"
+
+void SimpleHandler::PlatformTitleChange(CefRefPtr<CefBrowser> browser,
+ const CefString& title) {
+ NSView* view =
+ CAST_CEF_WINDOW_HANDLE_TO_NSVIEW(browser->GetHost()->GetWindowHandle());
+ NSWindow* window = [view window];
+ std::string titleStr(title);
+ NSString* str = [NSString stringWithUTF8String:titleStr.c_str()];
+ [window setTitle:str];
+}
diff --git a/tests/cefsimple/simple_handler_win.cc b/tests/cefsimple/simple_handler_win.cc
new file mode 100644
index 00000000..3811c67a
--- /dev/null
+++ b/tests/cefsimple/simple_handler_win.cc
@@ -0,0 +1,18 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/cefsimple/simple_handler.h"
+
+#include <windows.h>
+#include <string>
+
+#include "include/cef_browser.h"
+
+void SimpleHandler::PlatformTitleChange(CefRefPtr<CefBrowser> browser,
+ const CefString& title) {
+ CefWindowHandle hwnd = browser->GetHost()->GetWindowHandle();
+ if (hwnd) {
+ SetWindowText(hwnd, std::wstring(title).c_str());
+ }
+}
diff --git a/tests/ceftests/CMakeLists.txt.in b/tests/ceftests/CMakeLists.txt.in
new file mode 100644
index 00000000..f5a418b7
--- /dev/null
+++ b/tests/ceftests/CMakeLists.txt.in
@@ -0,0 +1,251 @@
+# Copyright (c) 2014 The Chromium Embedded Framework Authors. All rights
+# reserved. Use of this source code is governed by a BSD-style license that
+# can be found in the LICENSE file.
+
+#
+# Source files.
+#
+
+# ceftests sources.
+{{
+ 'prefix': 'ceftests',
+ 'set': 'UNITTESTS_SRCS',
+ 'includes': [
+ 'shared_sources_browser',
+ 'shared_sources_common',
+ 'shared_sources_linux:LINUX',
+ 'shared_sources_mac:MAC',
+ 'shared_sources_renderer:WINDOWS',
+ 'shared_sources_renderer:LINUX',
+ 'shared_sources_win:WINDOWS',
+ 'ceftests_sources_common',
+ 'ceftests_sources_linux:LINUX',
+ 'ceftests_sources_mac:MAC',
+ 'ceftests_sources_win:WINDOWS',
+ ],
+}}
+
+# ceftests helper sources.
+{{
+ 'prefix': 'ceftests_helper',
+ 'set': 'UNITTESTS_HELPER_SRCS',
+ 'includes': [
+ 'shared_sources_common',
+ 'shared_sources_mac_helper:MAC',
+ 'shared_sources_renderer',
+ 'ceftests_sources_mac_helper:MAC',
+ ],
+}}
+
+# ceftests resources.
+{{
+ 'prefix': 'ceftests_resources',
+ 'set': 'UNITTESTS_RESOURCES_SRCS',
+ 'includes': [
+ 'shared_sources_resources',
+ 'ceftests_bundle_resources_mac:MAC',
+ ],
+}}
+
+# ceftests data resources.
+{{
+ 'prefix': 'ceftests_data_resources',
+ 'set': 'UNITTESTS_DATA_RESOURCES_SRCS',
+ 'includes': [
+ 'ceftests_data_resources',
+ ],
+}}
+
+#
+# Shared configuration.
+#
+
+# Target executable names.
+set(CEF_TARGET "ceftests")
+if(OS_MAC)
+ set(CEF_HELPER_TARGET "ceftests_Helper")
+ set(CEF_HELPER_OUTPUT_NAME "ceftests Helper")
+else()
+ # Logical target used to link the libcef library.
+ ADD_LOGICAL_TARGET("libcef_lib" "${CEF_LIB_DEBUG}" "${CEF_LIB_RELEASE}")
+endif()
+
+# Determine the target output directory.
+SET_CEF_TARGET_OUT_DIR()
+
+
+#
+# Linux configuration.
+#
+
+if(OS_LINUX)
+ # Find required libraries and update compiler/linker variables.
+ FIND_LINUX_LIBRARIES("glib-2.0")
+
+ # Executable target.
+ add_executable(${CEF_TARGET} ${UNITTESTS_SRCS} ${UNITTESTS_RESOURCES_SRCS})
+ SET_EXECUTABLE_TARGET_PROPERTIES(${CEF_TARGET})
+ add_dependencies(${CEF_TARGET} libcef_dll_wrapper cef_gtest)
+ target_link_libraries(${CEF_TARGET} libcef_lib libcef_dll_wrapper cef_gtest ${CEF_STANDARD_LIBS})
+
+ # Set rpath so that libraries can be placed next to the executable.
+ set_target_properties(${CEF_TARGET} PROPERTIES INSTALL_RPATH "$ORIGIN")
+ set_target_properties(${CEF_TARGET} PROPERTIES BUILD_WITH_INSTALL_RPATH TRUE)
+ set_target_properties(${CEF_TARGET} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CEF_TARGET_OUT_DIR})
+
+ # Copy binary and resource files to the target output directory.
+ COPY_FILES("${CEF_TARGET}" "${CEF_BINARY_FILES}" "${CEF_BINARY_DIR}" "${CEF_TARGET_OUT_DIR}")
+ COPY_FILES("${CEF_TARGET}" "${CEF_RESOURCE_FILES}" "${CEF_RESOURCE_DIR}" "${CEF_TARGET_OUT_DIR}")
+
+ # Copy ceftests resource files to the target output directory.
+ COPY_FILES("${CEF_TARGET}" "${UNITTESTS_RESOURCES_SRCS}" "${CMAKE_CURRENT_SOURCE_DIR}" "${CEF_TARGET_OUT_DIR}/ceftests_files")
+
+ # Copy ceftests data resource files to the target output directory.
+ # Remove these prefixes from input file paths.
+ set(PREFIXES
+ "resources/"
+ )
+ COPY_RESOURCES("${CEF_TARGET}" "${UNITTESTS_DATA_RESOURCES_SRCS}" "${PREFIXES}" "${CMAKE_CURRENT_SOURCE_DIR}" "${CEF_TARGET_OUT_DIR}/ceftests_files")
+
+ # Set SUID permissions on the chrome-sandbox target.
+ SET_LINUX_SUID_PERMISSIONS("${CEF_TARGET}" "${CEF_TARGET_OUT_DIR}/chrome-sandbox")
+endif()
+
+
+#
+# Mac OS X configuration.
+#
+
+if(OS_MAC)
+ # Output path for the main app bundle.
+ set(CEF_APP "${CEF_TARGET_OUT_DIR}/${CEF_TARGET}.app")
+
+ # Variables referenced from the main Info.plist file.
+ set(EXECUTABLE_NAME "${CEF_TARGET}")
+ set(PRODUCT_NAME "${CEF_TARGET}")
+
+ if(USE_SANDBOX)
+ # Logical target used to link the cef_sandbox library.
+ ADD_LOGICAL_TARGET("cef_sandbox_lib" "${CEF_SANDBOX_LIB_DEBUG}" "${CEF_SANDBOX_LIB_RELEASE}")
+ endif()
+
+ # Main app bundle target.
+ add_executable(${CEF_TARGET} MACOSX_BUNDLE ${UNITTESTS_RESOURCES_SRCS} ${UNITTESTS_SRCS})
+ SET_EXECUTABLE_TARGET_PROPERTIES(${CEF_TARGET})
+ add_dependencies(${CEF_TARGET} libcef_dll_wrapper cef_gtest)
+ target_link_libraries(${CEF_TARGET} libcef_dll_wrapper cef_gtest ${CEF_STANDARD_LIBS})
+ set_target_properties(${CEF_TARGET} PROPERTIES
+ MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/resources/mac/Info.plist
+ )
+
+ # Copy the CEF framework into the Frameworks directory.
+ add_custom_command(
+ TARGET ${CEF_TARGET}
+ POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy_directory
+ "${CEF_BINARY_DIR}/Chromium Embedded Framework.framework"
+ "${CEF_APP}/Contents/Frameworks/Chromium Embedded Framework.framework"
+ VERBATIM
+ )
+
+ # Create the multiple Helper app bundle targets.
+ foreach(_suffix_list ${CEF_HELPER_APP_SUFFIXES})
+ # Convert to a list and extract the suffix values.
+ string(REPLACE ":" ";" _suffix_list ${_suffix_list})
+ list(GET _suffix_list 0 _name_suffix)
+ list(GET _suffix_list 1 _target_suffix)
+ list(GET _suffix_list 2 _plist_suffix)
+
+ # Define Helper target and output names.
+ set(_helper_target "${CEF_HELPER_TARGET}${_target_suffix}")
+ set(_helper_output_name "${CEF_HELPER_OUTPUT_NAME}${_name_suffix}")
+
+ # Create Helper-specific variants of the helper-Info.plist file. Do this
+ # manually because the configure_file command (which is executed as part of
+ # MACOSX_BUNDLE_INFO_PLIST) uses global env variables and would insert the
+ # wrong values with multiple targets.
+ set(_helper_info_plist "${CMAKE_CURRENT_BINARY_DIR}/helper-Info${_target_suffix}.plist")
+ file(READ "${CMAKE_CURRENT_SOURCE_DIR}/resources/mac/helper-Info.plist" _plist_contents)
+ string(REPLACE "\${EXECUTABLE_NAME}" "${_helper_output_name}" _plist_contents ${_plist_contents})
+ string(REPLACE "\${PRODUCT_NAME}" "${_helper_output_name}" _plist_contents ${_plist_contents})
+ string(REPLACE "\${BUNDLE_ID_SUFFIX}" "${_plist_suffix}" _plist_contents ${_plist_contents})
+ file(WRITE ${_helper_info_plist} ${_plist_contents})
+
+ # Create Helper executable target.
+ add_executable(${_helper_target} MACOSX_BUNDLE ${UNITTESTS_HELPER_SRCS})
+ SET_EXECUTABLE_TARGET_PROPERTIES(${_helper_target})
+ add_dependencies(${_helper_target} libcef_dll_wrapper cef_gtest)
+ target_link_libraries(${_helper_target} libcef_dll_wrapper cef_gtest ${CEF_STANDARD_LIBS})
+ set_target_properties(${_helper_target} PROPERTIES
+ MACOSX_BUNDLE_INFO_PLIST ${_helper_info_plist}
+ OUTPUT_NAME ${_helper_output_name}
+ )
+
+ if(USE_SANDBOX)
+ target_link_libraries(${_helper_target} cef_sandbox_lib)
+ endif()
+
+ # Add the Helper as a dependency of the main executable target.
+ add_dependencies(${CEF_TARGET} "${_helper_target}")
+
+ # Copy the Helper app bundle into the Frameworks directory.
+ add_custom_command(
+ TARGET ${CEF_TARGET}
+ POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy_directory
+ "${CEF_TARGET_OUT_DIR}/${_helper_output_name}.app"
+ "${CEF_APP}/Contents/Frameworks/${_helper_output_name}.app"
+ VERBATIM
+ )
+ endforeach()
+
+ # Manually process and copy over resource files.
+ # The Xcode generator can support this via the set_target_properties RESOURCE
+ # directive but that doesn't properly handle nested resource directories.
+ # Remove these prefixes from input file paths.
+ set(PREFIXES
+ "resources/mac/"
+ "resources/"
+ "../shared/resources/"
+ )
+ set(RESOURCES ${UNITTESTS_RESOURCES_SRCS} ${UNITTESTS_DATA_RESOURCES_SRCS})
+ COPY_MAC_RESOURCES("${RESOURCES}" "${PREFIXES}" "${CEF_TARGET}" "${CMAKE_CURRENT_SOURCE_DIR}" "${CEF_APP}")
+endif()
+
+
+#
+# Windows configuration.
+#
+
+if(OS_WINDOWS)
+ # Executable target.
+ add_executable(${CEF_TARGET} WIN32 ${UNITTESTS_SRCS} ${UNITTESTS_RESOURCES_SRCS})
+ add_dependencies(${CEF_TARGET} libcef_dll_wrapper cef_gtest)
+
+ list(APPEND CEF_EXE_LINKER_FLAGS
+ /SUBSYSTEM:CONSOLE # Configure as a console application.
+ )
+
+ SET_EXECUTABLE_TARGET_PROPERTIES(${CEF_TARGET})
+ target_link_libraries(${CEF_TARGET} libcef_lib libcef_dll_wrapper cef_gtest ${CEF_STANDARD_LIBS})
+
+ if(USE_SANDBOX)
+ # Logical target used to link the cef_sandbox library.
+ ADD_LOGICAL_TARGET("cef_sandbox_lib" "${CEF_SANDBOX_LIB_DEBUG}" "${CEF_SANDBOX_LIB_RELEASE}")
+ target_link_libraries(${CEF_TARGET} cef_sandbox_lib ${CEF_SANDBOX_STANDARD_LIBS})
+ endif()
+
+ # Add the custom manifest files to the executable.
+ ADD_WINDOWS_MANIFEST("${CMAKE_CURRENT_SOURCE_DIR}/resources/win" "${CEF_TARGET}" "exe")
+
+ # Copy CEF binary and resource files to the target output directory.
+ COPY_FILES("${CEF_TARGET}" "${CEF_BINARY_FILES}" "${CEF_BINARY_DIR}" "${CEF_TARGET_OUT_DIR}")
+ COPY_FILES("${CEF_TARGET}" "${CEF_RESOURCE_FILES}" "${CEF_RESOURCE_DIR}" "${CEF_TARGET_OUT_DIR}")
+
+ # Copy ceftests data resource files to the target output directory.
+ # Remove these prefixes from input file paths.
+ set(PREFIXES
+ "resources/"
+ )
+ COPY_RESOURCES("${CEF_TARGET}" "${UNITTESTS_DATA_RESOURCES_SRCS}" "${PREFIXES}" "${CMAKE_CURRENT_SOURCE_DIR}" "${CEF_TARGET_OUT_DIR}/ceftests_files")
+endif()
diff --git a/tests/ceftests/audio_output_unittest.cc b/tests/ceftests/audio_output_unittest.cc
new file mode 100644
index 00000000..c49a4456
--- /dev/null
+++ b/tests/ceftests/audio_output_unittest.cc
@@ -0,0 +1,1096 @@
+// Copyright (c) 2018 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "include/base/cef_callback.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "tests/ceftests/test_handler.h"
+#include "tests/gtest/include/gtest/gtest.h"
+#include "tests/shared/browser/client_app_browser.h"
+
+using client::ClientAppBrowser;
+
+// Taken from:
+// http://www.iandevlin.com/blog/2012/09/html5/html5-media-and-data-uri/
+#define AUDIO_DATA \
+ "data:audio/" \
+ "ogg;base64,T2dnUwACAAAAAAAAAAA+" \
+ "HAAAAAAAAGyawCEBQGZpc2hlYWQAAwAAAAAAAAAAAAAA6AMAAAAAAAAAAAAAAAAAAOgDAAAAAA" \
+ "AAAAAAAAAAAAAAAAAAAAAAAAAAAABPZ2dTAAIAAAAAAAAAAINDAAAAAAAA9LkergEeAXZvcmJp" \
+ "cwAAAAACRKwAAAAAAAAA7gIAAAAAALgBT2dnUwAAAAAAAAAAAAA+" \
+ "HAAAAQAAAPvOJxcBUGZpc2JvbmUALAAAAINDAAADAAAARKwAAAAAAAABAAAAAAAAAAAAAAAAAA" \
+ "AAAgAAAAAAAABDb250ZW50LVR5cGU6IGF1ZGlvL3ZvcmJpcw0KT2dnUwAAAAAAAAAAAACDQwAA" \
+ "AQAAAGLSAC4Qdv//////////////////" \
+ "cQN2b3JiaXMdAAAAWGlwaC5PcmcgbGliVm9yYmlzIEkgMjAwOTA3MDkCAAAAIwAAAEVOQ09ERV" \
+ "I9ZmZtcGVnMnRoZW9yYS0wLjI2K3N2bjE2OTI0HgAAAFNPVVJDRV9PU0hBU0g9ODExM2FhYWI5" \
+ "YzFiNjhhNwEFdm9yYmlzK0JDVgEACAAAADFMIMWA0JBVAAAQAABgJCkOk2ZJKaWUoSh5mJRISS" \
+ "mllMUwiZiUicUYY4wxxhhjjDHGGGOMIDRkFQAABACAKAmOo+" \
+ "ZJas45ZxgnjnKgOWlOOKcgB4pR4DkJwvUmY26mtKZrbs4pJQgNWQUAAAIAQEghhRRSSCGFFGKI" \
+ "IYYYYoghhxxyyCGnnHIKKqigggoyyCCDTDLppJNOOumoo4466ii00EILLbTSSkwx1VZjrr0GXX" \
+ "xzzjnnnHPOOeecc84JQkNWAQAgAAAEQgYZZBBCCCGFFFKIKaaYcgoyyIDQkFUAACAAgAAAAABH" \
+ "kRRJsRTLsRzN0SRP8ixREzXRM0VTVE1VVVVVdV1XdmXXdnXXdn1ZmIVbuH1ZuIVb2IVd94VhGI" \
+ "ZhGIZhGIZh+" \
+ "H3f933f930gNGQVACABAKAjOZbjKaIiGqLiOaIDhIasAgBkAAAEACAJkiIpkqNJpmZqrmmbtmi" \
+ "rtm3LsizLsgyEhqwCAAABAAQAAAAAAKBpmqZpmqZpmqZpmqZpmqZpmqZpmmZZlmVZlmVZlmVZl" \
+ "mVZlmVZlmVZlmVZlmVZlmVZlmVZlmVZlmVZQGjIKgBAAgBAx3Ecx3EkRVIkx3IsBwgNWQUAyAA" \
+ "ACABAUizFcjRHczTHczzHczxHdETJlEzN9EwPCA1ZBQAAAgAIAAAAAABAMRzFcRzJ0SRPUi3Tc" \
+ "jVXcz3Xc03XdV1XVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVYHQkFUAAAQAACG" \
+ "dZpZqgAgzkGEgNGQVAIAAAAAYoQhDDAgNWQUAAAQAAIih5CCa0JrzzTkOmuWgqRSb08GJVJsnu" \
+ "amYm3POOeecbM4Z45xzzinKmcWgmdCac85JDJqloJnQmnPOeRKbB62p0ppzzhnnnA7GGWGcc85" \
+ "p0poHqdlYm3POWdCa5qi5FJtzzomUmye1uVSbc84555xzzjnnnHPOqV6czsE54Zxzzonam2u5C" \
+ "V2cc875ZJzuzQnhnHPOOeecc84555xzzglCQ1YBAEAAAARh2BjGnYIgfY4GYhQhpiGTHnSPDpO" \
+ "gMcgppB6NjkZKqYNQUhknpXSC0JBVAAAgAACEEFJIIYUUUkghhRRSSCGGGGKIIaeccgoqqKSSi" \
+ "irKKLPMMssss8wyy6zDzjrrsMMQQwwxtNJKLDXVVmONteaec645SGultdZaK6WUUkoppSA0ZBU" \
+ "AAAIAQCBkkEEGGYUUUkghhphyyimnoIIKCA1ZBQAAAgAIAAAA8CTPER3RER3RER3RER3RER3P8" \
+ "RxREiVREiXRMi1TMz1VVFVXdm1Zl3Xbt4Vd2HXf133f141fF4ZlWZZlWZZlWZZlWZZlWZZlCUJ" \
+ "DVgEAIAAAAEIIIYQUUkghhZRijDHHnINOQgmB0JBVAAAgAIAAAAAAR3EUx5EcyZEkS7IkTdIsz" \
+ "fI0T/M00RNFUTRNUxVd0RV10xZlUzZd0zVl01Vl1XZl2bZlW7d9WbZ93/d93/d93/d93/" \
+ "d939d1IDRkFQAgAQCgIzmSIimSIjmO40iSBISGrAIAZAAABACgKI7iOI4jSZIkWZImeZZniZqp" \
+ "mZ7pqaIKhIasAgAAAQAEAAAAAACgaIqnmIqniIrniI4oiZZpiZqquaJsyq7ruq7ruq7ruq7ruq" \
+ "7ruq7ruq7ruq7ruq7ruq7ruq7ruq7rukBoyCoAQAIAQEdyJEdyJEVSJEVyJAcIDVkFAMgAAAgA" \
+ "wDEcQ1Ikx7IsTfM0T/" \
+ "M00RM90TM9VXRFFwgNWQUAAAIACAAAAAAAwJAMS7EczdEkUVIt1VI11VItVVQ9VVVVVVVVVVVV" \
+ "VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV1TRN0zSB0JCVAAAZAAACKcWahFCSQU5K7EVpxiAHrQ" \
+ "blKYQYk9iL6ZhCyFFQKmQMGeRAydQxhhDzYmOnFELMi/" \
+ "Glc4xBL8a4UkIowQhCQ1YEAFEAAAZJIkkkSfI0okj0JM0jijwRgCR6PI/" \
+ "nSZ7I83geAEkUeR7Pk0SR5/" \
+ "E8AQAAAQ4AAAEWQqEhKwKAOAEAiyR5HknyPJLkeTRNFCGKkqaJIs8zTZ5mikxTVaGqkqaJIs8z" \
+ "TZonmkxTVaGqniiqKlV1XarpumTbtmHLniiqKlV1XabqumzZtiHbAAAAJE9TTZpmmjTNNImiak" \
+ "JVJc0zVZpmmjTNNImiqUJVPVN0XabpukzTdbmuLEOWPdF0XaapukzTdbmuLEOWAQAASJ6nqjTN" \
+ "NGmaaRJFU4VqSp6nqjTNNGmaaRJFVYWpeqbpukzTdZmm63JlWYYte6bpukzTdZmm65JdWYYsAw" \
+ "AA0EzTlomi7BJF12WargvX1UxTtomiKxNF12WargvXFVXVlqmmLVNVWea6sgxZFlVVtpmqbFNV" \
+ "Wea6sgxZBgAAAAAAAAAAgKiqtk1VZZlqyjLXlWXIsqiqtk1VZZmpyjLXtWXIsgAAgAEHAIAAE8" \
+ "pAoSErAYAoAACH4liWpokix7EsTRNNjmNZmmaKJEnTPM80oVmeZ5rQNFFUVWiaKKoqAAACAAAK" \
+ "HAAAAmzQlFgcoNCQlQBASACAw3EsS9M8z/" \
+ "NEUTRNk+" \
+ "NYlueJoiiapmmqKsexLM8TRVE0TdNUVZalaZ4niqJomqqqqtA0zxNFUTRNVVVVaJoomqZpqqqq" \
+ "ui40TRRN0zRVVVVdF5rmeaJomqrquq4LPE8UTVNVXdd1AQAAAAAAAAAAAAAAAAAAAAAEAAAcOA" \
+ "AABBhBJxlVFmGjCRcegEJDVgQAUQAAgDGIMcWYUQpCKSU0SkEJJZQKQmmppJRJSK211jIpqbXW" \
+ "WiWltJZay6Ck1lprmYTWWmutAACwAwcAsAMLodCQlQBAHgAAgoxSjDnnHDVGKcacc44aoxRjzj" \
+ "lHlVLKOecgpJQqxZxzDlJKGXPOOecopYw555xzlFLnnHPOOUqplM455xylVErnnHOOUiolY845" \
+ "JwAAqMABACDARpHNCUaCCg1ZCQCkAgAYHMeyPM/" \
+ "zTNE0LUnSNFEURdNUVUuSNE0UTVE1VZVlaZoomqaqui5N0zRRNE1VdV2q6nmmqaqu67pUV/" \
+ "RMU1VdV5YBAAAAAAAAAAAAAQDgCQ4AQAU2rI5wUjQWWGjISgAgAwAAMQYhZAxCyBiEFEIIKaUQ" \
+ "EgAAMOAAABBgQhkoNGQlAJAKAAAYo5RzzklJpUKIMecglNJShRBjzkEopaWoMcYglJJSa1FjjE" \
+ "EoJaXWomshlJJSSq1F10IoJaXWWotSqlRKaq3FGKVUqZTWWosxSqlzSq3FGGOUUveUWoux1iil" \
+ "dDLGGGOtzTnnZIwxxloLAEBocAAAO7BhdYSTorHAQkNWAgB5AAAIQkoxxhhjECGlGGPMMYeQUo" \
+ "wxxhhUijHGHGMOQsgYY4wxByFkjDHnnIMQMsYYY85BCJ1zjjHnIITQOceYcxBC55xjzDkIoXOM" \
+ "MeacAACgAgcAgAAbRTYnGAkqNGQlABAOAAAYw5hzjDkGnYQKIecgdA5CKqlUCDkHoXMQSkmpeA" \
+ "46KSGUUkoqxXMQSgmhlJRaKy6GUkoopaTUUpExhFJKKSWl1ooxpoSQUkqptVaMMaGEVFJKKbZi" \
+ "jI2lpNRaa60VY2wsJZXWWmutGGOMaym1FmOsxRhjXEuppRhrLMYY43tqLcZYYzHGGJ9baimmXA" \
+ "sAMHlwAIBKsHGGlaSzwtHgQkNWAgC5AQAIQkoxxphjzjnnnHPOSaUYc8455yCEEEIIIZRKMeac" \
+ "c85BByGEEEIoGXPOOQchhBBCCCGEUFLqmHMOQgghhBBCCCGl1DnnIIQQQgghhBBCSqlzzkEIIY" \
+ "QQQgghhJRSCCGEEEIIIYQQQggppZRCCCGEEEIIIZQSUkophRBCCCWEEkoIJaSUUgohhBBCKaWE" \
+ "UkJJKaUUQgillFBKKaGUkFJKKaUQQiillFBKKSWllFJKJZRSSikllFBKSimllEoooZRQSimllJ" \
+ "RSSimVUkopJZRSSgkppZRSSqmUUkoppZRSUkoppZRSKaWUUkoppaSUUkoppVJKKaWUEkpJKaWU" \
+ "UkqllFBKKaWUUlJKKaWUSgqllFJKKaUAAKADBwCAACMqLcROM648AkcUMkxAhYasBABSAQAAQi" \
+ "illFJKKTWMUUoppZRSihyklFJKKaWUUkoppZRSSimVUkoppZRSSimllFJKKaWUUkoppZRSSiml" \
+ "lFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKAcDdFw6APh" \
+ "M2rI5wUjQWWGjISgAgFQAAMIYxxphyzjmllHPOOQadlEgp5yB0TkopPYQQQgidhJR6ByGEEEIp" \
+ "KfUYQyghlJRS67GGTjoIpbTUaw8hhJRaaqn3HjKoKKWSUu89tVBSainG3ntLJbPSWmu9595LKi" \
+ "nG2nrvObeSUkwtFgBgEuEAgLhgw+" \
+ "oIJ0VjgYWGrAIAYgAACEMMQkgppZRSSinGGGOMMcYYY4wxxhhjjDHGGGOMMQEAgAkOAAABVrAr" \
+ "s7Rqo7ipk7zog8AndMRmZMilVMzkRNAjNdRiJdihFdzgBWChISsBADIAAMRRrDXGXitiGISSai" \
+ "wNQYxBibllxijlJObWKaWUk1hTyJRSzFmKJXRMKUYpphJCxpSkGGOMKXTSWs49t1RKCwAAgCAA" \
+ "wECEzAQCBVBgIAMADhASpACAwgJDx3AREJBLyCgwKBwTzkmnDQBAECIzRCJiMUhMqAaKiukAYH" \
+ "GBIR8AMjQ20i4uoMsAF3Rx14EQghCEIBYHUEACDk644Yk3POEGJ+" \
+ "gUlToQAAAAAAAIAHgAAEg2gIhoZuY4Ojw+" \
+ "QEJERkhKTE5QUlQEAAAAAAAQAD4AAJIVICKamTmODo8PkBCREZISkxOUFJUAAEAAAQAAAAAQQA" \
+ "ACAgIAAAAAAAEAAAACAk9nZ1MABAAAAAAAAAAAPhwAAAIAAADItsciAQBPZ2dTAABAKgAAAAAA" \
+ "AINDAAACAAAAi/k29xgB/4b/av9h/0j/Wv9g/1r/UP9l/1//" \
+ "Wv8A2jWsrb6NXUc1CJ0sSdewtPbGlo1NaJI8UVTVUGRZipC555WVlSnnZVlZWVlZljm1c+" \
+ "zimE1lYRMrAAAAAEGChIyc4DjOGcNecpzj3e5eskWraU5OsZ1ma2tra+/" \
+ "QoUNbkyPMXUZO1Skw1yh8+fLly+84juMURSFhhhyPx1EDqAmLBR0xchzH8XgcYYYknU5HIoc//" \
+ "F1uAOa6rplb8brWAjo6AuBaCWnBu1yRw+9I6HTe9bomx3Ecj8eHR7jhpx2EJSwhwxKWDtHpSA/" \
+ "hd+Q6Q/" \
+ "XNZeIut1JxXdd1FzPAbGI6kyYm6HQcNmEJi07r6Ojo6OjQ6XQdhMWCTscBwEd2xARjIprIJiYm" \
+ "JiYyf2KCACDkOB6Px+O3AKDQkNscN32A7tIn3tm+wPdQiK1gI2FpTbSPWkfP39+nb29vT9+3/" \
+ "Y+8NdEAfA+OmQ6zRtfR0dHR8ahTR0fH4+PjY0dHx2ynx8dHgB8U/" \
+ "i6fLaUnx1wT25MmJiYmJqYDACDTYdbodB2EQ+9aRwD+Nkw+" \
+ "hfQxSPHBdvQ2TD5FpJFBCCtwtLsEMYc15nbtXNNdkgqHYiKRlIwAAABAlCZiYkIIiThNSRKhE8" \
+ "KqUrnsJ2hxoZt4CRurX076XaZaxJetiVOHTp0a+PgINiJWq8VwfLk+" \
+ "cITkeOQ14Y4rvOkFV5gNbxGwcVJTDea6zsoAASCExwDXWK1chON6pdVirqN3roR6RupwgcQ1uT" \
+ "LXI+" \
+ "HyOoth7KQkYR7fAFOJv3TclGuuX2CS60rmmwgoZRIFU8icwlwDSea3MKrOGxMM1XtqaLgmDcCL" \
+ "YEbscM8PuoIEXYE9Qj08y62k5aQRDimNrAslDCa0CL3XGSYaTW0Q2etDMZyiS435NgHG4HACkQ" \
+ "xzYNnYqtvRwqPLDKAT1fRDd5KIJ45cOoeyA1FHC455K8BYpAAAZ2gMqDAOQPcz9/" \
+ "v3uTNAASBXhW/" \
+ "+wqevLAUrnjUnS7YzOs8s+" \
+ "bpwXYrKdoXXGjBgp10SlQ8A3jb0scTwUeAFrmtD70uMfSS4gJeZlUhIlNsKco2uXVeY2VWl6JR" \
+ "DSAhW4jYAQCYAAJCXD9bEGgGxF1Oz2UgEAhOlC0q5pjzL3fxjlQcAAACAjx8bmMEYnbAb1U4nz" \
+ "BE2MsOHLwGuHz8oUi2qnhqYoTAuZWUNo0sfSn2HJJcA1xVleDATYEDmjGsqfYuV1VW3dhdQ11Y" \
+ "rko0xrJHM6qZIpxW2qPLKAiBzakFdDasdLWtAzpUaGbaUXhZzReGzLuS71zqMZIhap91418WyG" \
+ "4stA5xvC5AWfdPC0KFnhug9EJ6h0yAGfs54rQNMjP2JYPT0RkeosWCnkZ1GGYvGLCMRrhdEj8C" \
+ "h8OOUvsYFzIyKCO+" \
+ "MNsuxBAyvGFnp9QwEhcblgg5xA7gRNLmyHjMwEAWu57SEt2AIXIbqDRCqICCh7QEAvBIAAACSr" \
+ "VYG45afyShwcSuuNzIo4AUK/" \
+ "1ZvfgUABf42jCVGeVhwqQpxQ99SBB86rGrhPqKsDImUIoPYFTmNXd0Vlks7U8FRjYAEAACYOUp" \
+ "Uk8RSEAkCIWK0JOXukmSu2R1+iWGIWLBM+mt0Up2tqni9YR6/" \
+ "b6aK70i+" \
+ "IV0EAzUMs4ZAYRQJwvNSInBWKJtFAgS9MiFgEEYDmIOZMK8E4h5xAegwErEGYWbSzKJ0E5mz+" \
+ "AozI2QYjutAsEbhzsrxtoHkIjxIZo4Ho/" \
+ "RpMMDTvsug986rhaceoIQiQucUUCJPKaOJwDKa0Y2kiRhjDxOG6EGJEyEhATLXC0j4qKckgkeE" \
+ "ugjRA8B1MY8D3sIBr0kOVsvFwQTfLbj3ABCIMrHSLyQ4qbOdjCEK8gghdCNG3wyjgskAAICiE8" \
+ "D3VkkAYPyxpQAAwPXlW2HA/I/NAfx2KQA+3q4MBYDE/" \
+ "X+cAACyJJGwfpZxAP42TMkH+" \
+ "0AOLxIzb8MUfZQRHR7AkSHICOeGMHdG55ULc3qMjEjSBwO0SAEAAAgZYhCWUSyoKAVKKKsQL5v" \
+ "0RJaFKF0iIp4A4u42AYA9HEIPhlrCoWNiOrlxU6OmOcVsXyAWNWWyYvEg1fLKMHi1MRcAqZ6qs" \
+ "KKPcJIoAfWgjkIjWXkBzZLBQ2X0djWBHvsi6aIQ6rQmZ50vcrgEuGNleEwUBA1WpKJiZkbhShj" \
+ "a5TrjZ8uHdL4p6sJpn0748t/" \
+ "4Ky401MB4FwAw6vRWc8BMAjnySEYJoc5+" \
+ "VpmHtCG9622e9msJozQgHQ18GB16oycX3odS6siozeCNd2g8ow/" \
+ "jDOloAgg3GK9JhkfU4FAwCLci2kD8KNGqMLrinHR6yujhyHcCArjgYYwpicBMtEILRJRmAK8nc" \
+ "HC0MBHPNnh8fASAue68jrwrIuG/vZnupwGA/" \
+ "v5t2CyABGSAA942LF5E8x+" \
+ "NWB4kPtqGxYto9scgpxdJx11V1ABBREREEsTMk6t0u1QyNV3MRCIdAgAA4C6ZGSzQBMyUmAhNp" \
+ "RgtYEkrCYlUtqSPpYbpbf2LmAYxxcEodhZD1DDVNE1z4VabMg0MUzksaBW5vkWD45q5luFKQ4x" \
+ "Dl6XhA0w4GGKQyRZwjQbX8Y1Q1y10x21clDHA4EPjADidlLiWSmXCUjIzk18yZHjkFeGU5hOws" \
+ "jSXKma1g2NpIJmVsRIyHQb04fcMMljQLC4eVrUpAsBbR2P80rIFh7xkaD+" \
+ "qQRJAhCF6amxRZzQLYCgAwGHk4tTxhp46UZ1GR01UxokEw3RgDR8aYLLBhBVWdRfXkdlKNjRIn" \
+ "tIN5WpsAhOGYW3WNE6ychBocusS6He+3SoISm3RZ/" \
+ "ity3SkcDrh1O3GnqUWeMII2FsBAACOXK+ZAayOaQAAAMDr9fgQAAAQpgyQURIsAD43bNUE+" \
+ "YGaVgonZW7YqgtmBDX1FCdVPNoASzrC7pwh6GrXnSTOhZliQkJITZQjAQAAEBayiEAASkSEEhU" \
+ "nAlqMIl4iEBUvFwr9KaKiwRKlIixCWBS0QJTtFQwxraBqER3lw4O5wsxcLRbgeBwXM5WRLq6EX" \
+ "AII0SuonlAqIjsEkPAiYT5wvA6YhOuYQ5AkIsK4nA7DuAjJhDkrtwWLUBWrcSQhFlOglSQ3XXB" \
+ "N6sIjyXFczCTkSo5X5hpGyJJ7MtDTHSJLkPBbpMBy2F1Er3PU7qKM5yMsFhDGeEooCKVk4zwFE" \
+ "9pNnPoeCBgAYsJ9JsGHiYDTHHEpzKldb3scr1fvvJRLdLrQPhYwq7FljfBg/" \
+ "R6eNRZEBhQGYVX9QEdsDeG6qA6OAGjMBADgO6AIdQEAlaUfAAAAEM/" \
+ "wQZz6AQAoK06aAAAAAGTherz+MgAAAMAHlAX1Uy0qAL42LNpFsx8HpWdH0LVh0T4i/" \
+ "zhIHWskPTKhHTrYuWpKV5KkjEUnpIYIJAEAAIhAIBSI0aIlSlQoChGhUKQQioEWUqJCUYeEmB9" \
+ "8T5k2E/" \
+ "+DL3t1UQNjJmHEFP+" \
+ "mrQyEabFWhEmubBFIrmAMZaYgjrBwHIfFMHkdTzDRuXSQqUP1KAKoAGJv6IC8ddTpGcyxIIyMN" \
+ "kIHYlVoMSLCOpcBXBAKSR4Z5iJSHo/" \
+ "h+sSn1w1zcL2+t+" \
+ "vggs6EoRb1YfQRvRtEfcwboET1ohMO0JBOF4wuclcSqndFBhgiPPWeAT6CUAZAZwylLtL7MC6Y" \
+ "NRgRVn1YnQwIRYTuUl3EIdFbu47ru3l9uMJcud4JcxHQ6RSD7hqATRcNGv0Q6EIJPAUwANBRKP" \
+ "xWAYAIcjoAAADwMf0lHqCej/" \
+ "n7+" \
+ "9sAAAsWFtSVSDhHPrjcDBlFPWb95RQZfjds3cfIH5Ae5KTOd8PeYkz2Q8BDwXYfeeK0w1i5SQT" \
+ "t1sByrhw9LiVZHOVBEgEAAKDECjFxMWamy8tFabpcQBMlLIwymhKDW/" \
+ "motIQ8H8rNy3MJzBhFOsIQ0gAhTIG23swQ9rJa+" \
+ "Vo1kgrfbpgarwknpUFFUXhkAZnUyFzo9nYLTpTQKNarPtd46sfSmS7CSgl1VkzAxOFWowvyqwi" \
+ "yQM9Io9rMVtMNIw0N6duZoR3zWRYFWWQhVKbjuF7WnVTZYY8CY4e4jCT93sfJJACJBRpY1l6NS" \
+ "QDEmmzDBPqhSdNmLPURTE4SPg9PiIuMSJ5SGvOh8fQAYFSRR2T4XYMZETqDnihEsuKtxoSvzEQ" \
+ "OhhXKl2oCK1LfMJe11t/NvT/" \
+ "EuCdvlaj1JXsG+" \
+ "sLnIEHNJtDRjXHAGhudngIATJQBHPC5X0dy8cgAwAAAnP3s8A77BoAGigofEvUvtSQzzckL3lz" \
+ "5SgA+N2xVxqYfiG2hQDRxw5p0TP7RUFYed2WZkTJkEIIMG+" \
+ "ax2rmxQ086qaIcOihPIgEAQAgBQniAcIAZEPPwclRAKFomKe7hVnULf3/" \
+ "PrQ43ubI48InJ1po2TLadA0rEUDVUsVMxwBjVmBC0w250lKGkDmEFeevFhBnCXCZDGDrECQYkg" \
+ "QebcT2OKzNKQDKHqgnDSkN6oiMCsInFdb1GjTwpqw4J2QmJpC4LKoDrLwrHbc/" \
+ "zI95E+Ki0iHd+wOuhI5EXB7E4UwUkRwKwRFLVul6uHiATCy54aCgNFdC7/" \
+ "pjGcUyYMJw4OrgMxutRSL3lRBFhhNE7tAhCI0BJWCOb1aJpVEbyCMmnhOosy5XrmptCmDLAOhf" \
+ "11KO/3ahqxOhRJZwP1/" \
+ "AEZkTAcQBMVwwAAu8E9KzWgEiZCJPhBQAAMJcCAHp1D6QSAAAAzKfbAVCHthYLAAAAlQI8macA" \
+ "IFQ+AD43bFXEXvzAuvFRN2xdx24/" \
+ "FOvOfNzVZYRMMqQMOWHNBpJ27Ry92YXHdDyJgHJYAAAAPxIzmSBiki6amEBSVBYqBTFapoRCod" \
+ "BcQooSE4rQEqQLIYHXj79ceaxwo/D71/" \
+ "JVcaMMtwDAHFyFJLmS6+" \
+ "hmgeso9zEQShTggBx3gco4QjLABeTBMDMltQ8Brgk7g1kxLtIOwrwCEwhsUeMKC7rG5ArX5HgN" \
+ "fDrOIsfjlFavcc2EnBx3IoaOFs0aHKEuK26Jo1oGKpcKCVPHpO3dn7yJ0X8xXC73Lnd26CXLjg" \
+ "MtCjN5hCFThAQ2oSFtOqOVGSDuE32hhYk4jsTlovpQozGwRbDa4UortUhDwkUAGGOR6jFYw2wX" \
+ "FJWsYBDy4MgWAXCbVTMEAABQEJ9LgCwH3xYAAIBMa6ZNaQCgAcBTJ/" \
+ "x3AOj3+wDAcLwer2MAAAAy2ACgwXf8bXKBCjY2xMkkMx+KLi9G1SRfQ+" \
+ "pkrPnA2nUmeyDHu80EQVKEELbtjomYPTNESOfauaokPSZJA0UIkQAAYM42+guCLGQ+ns1y+" \
+ "KgSupXRApdXJEpi4pSLDJJKRcndw82tg0wkAgPrVMAMn+iQ3W/huqg/" \
+ "Dn51VgoLfPn9gVTIoESUeFyxOCk/hSsDF5NZW70MrmNVrOoWZlo5bmhxTDLHOHTC3u/" \
+ "ymKjiOlaAEIzU6EcUCYPLmDnmVK1esZjWOPXKWdXtVr01YJGhu4TiVoJMBjheB9dxCXLovTEEh" \
+ "RLGaUp2Y+m+" \
+ "rAscdQDonFbotozWUeP0Lop2ZioVzASyLqcOHV0lOE9nZ1MAAUBTAAAAAAAAg0MAAAMAAABNPA" \
+ "GzHHBCSXWA/4hFeXd4eHD/Tf9a/0z/RP9T/1T/" \
+ "VP80TOZAm1Nx5OLKuqg4gORtwnDFBzFFjQzs0XZdrDdKYSDmSjid4LQfDhKi5+" \
+ "h240ACA0CNW3cUDABUawBGbEDXTQBrAQCVA+gxJAeAooIVRYmfpDQ/" \
+ "ADDPAJiZPJ4CKL0VwmKNDgAAABB4wcksgAwAnP100SFYKhzvrKcPFkH6ob/" \
+ "mUaXIRDBTcgHEGFi5xJcO3laj2nwCDrhVGxPvuosRTqeLwWlAfYSrIzNoeauADicEfPVoAlDqQ" \
+ "aRFq+" \
+ "snciCkfCHS4qa8or0MBDMmF1j6cY1Cm4iGhjfGaeO3aieOGe5NDbGwDjMMcczOSPXRFkE9H8+" \
+ "2tivg+AwTAGQNEQxiLnIquGjWEMUgZgkKXsxZc5FSaqfd3Uw1z81sIB8+X5WJ4h5VVZ9m4+" \
+ "6i1buron8SP34vySmxQ7qLMCG0QEz0/" \
+ "dT7XwCo2VZgmg6XM5ywWqdMz5QJ8fsMtqXl9ASTOGbvISIWw86dzoFrOPK5YYp0AJQNE0WyW7g" \
+ "QLT5gX0YMCEhLFyIFZx7T9tdYUcZB0VtJu6JumJQl5fBOSLhW37S5VXs34jK1Jk6VT/" \
+ "x83HsZZHFaDLQov1dP9gNAMvmItMzF99N26+QM0xzGyd1NG3vx7cvGMQe2Flvf/" \
+ "nbSajF9W32brvVMk+7b9uwetObQFh8AUjYUlVb4B2Kq5oLCGBuKhIP8byZy6k0Fy/" \
+ "P7VLTPiCKAqKtn1I4yy4MRVYUi94hYM9q163TiXMVijoCQBlgBIAEAAGyfygLXGCzgsKJUvzv9" \
+ "XsNFCjlU+yZdS4D2WD4dm8oyL0+5TdC9AAAAAOSQ49//" \
+ "kCTDIgMwAI6dPc3tnLUcLWWKMTh3gAtGuRBrX8HcVR2OmbiORPgtuEJZSZiw4OIuJlOhrDgCWN" \
+ "qTvazq8R1kGqXJdTJxtXJKFMGgpws9wcyEk9FRCbfVYK7HpfDKt6iRl2yPW3hTVjWw8HljZcsx" \
+ "BrKd+rDCSQCAGKtxnRWOVybT4lpXTXidEUdPVgF4UL9swRV23u0ZD+" \
+ "F0MRKXIawEFIB1ekIgDYGbwsMKU+" \
+ "0ozKo9Z2TkC0c3gMxmkYQbJsxQOzYjDyQkIuv7bsFeisuWiRwzYCSRqHXOjQg98QZbtYEYxjGc" \
+ "QcARkID2pQDgwPm9ngRunDrVrqxYyYraKzL4/" \
+ "nJO3t3aACCBuWOB5ax1sNREyTiHA2wFfRZkaS4gkWMr6LMg2DOhYKapgsoCSDNCBtw9OxjKFWD" \
+ "CykgduoxFYqpga3WXZEJdsKgHsYBJTARBmHkdFKsAQCmnXnwROSE7Hv6llTQVfDiNLyIjZBf2/" \
+ "ksraS74cBrfqkTCRD5PUtVGNNMKXBQCXNlcVlBc3JeFFaQQFSmXY1K0woOGWAXocnERodAlpA6" \
+ "qrJyaaTkB4Jizva1jptWWCYvjdk79BZjTT5tmqsXOxhCQCDJiPlKf74sLJSRcEWkl5I7tv9mpY" \
+ "BrTuCLSSsgd27/" \
+ "ZqWCapv0HIOTKyCpCDKk6j0huPhQVAAtocQIRWkiGIAYtJsnw9BAjYl4xuuSLUnHcx2tjuUQyZ" \
+ "hTkDACHjsQhFltHamcRO8SwkekNAZhRrXYOp5uxrLd4XtEwbb8z73zWNpwRWZbbM239xM8kh+" \
+ "uMyLLcnj0cip8LZsytqkYyyYqoriqQu5FSj1dkFaJAQSnL43E4lBKlTCgqQknRouwQXhEVEbg7" \
+ "NHGEdOWrR9X0wRWbhOXu4rUZu3p+" \
+ "8FtsDIsThmlnNTCMKQ4thuOOKKuNZUbFxBOPz3vyLzwRKSzpbvMJu4IBp56ICCKJx9zGrmDDqb" \
+ "OGUiFCT7KTkUeojozcJkSBhIijQiLK54mJE4GIKAsFkCwT8yUwIelyMU2EIAJRP8Vo0dPebkqG" \
+ "aBR4ylMQA3+cdMJiYz7r7wm1Mez8OGaorRXUNFVncCyO9y+tTnwJTwwRNQtG5BcKZh5BQ70FA/" \
+ "IHBTPXWRUpUnQexLSqkClyVlENHAqLYQOXD15ITCgkhBDxMhE3DxaKif+" \
+ "YkFkgIqZ4SgmQMW2qv3wdmTb2rsVGrGpx6LhDJ2wcc4TF3saBL6Gd+vhJLbZdxG7+Z25+" \
+ "jQzaNYQuBh1BDYutlYCuIXQx6Aiq1aqVkFstWUNWFBEioowYI7tudxub1uSo3FXFSbHERiQSAg" \
+ "IAAJAymXQJKSDADKEYiBhdQYsKPMVBM0UkxcSYEqFEpJDaskhhOmY6sBhiqCm2YmIRU7Cghi9b" \
+ "QQwceq3qcWAxCjlmZiH6YF0HALHFRchc/" \
+ "IWBhRpjMYxFxrA4wLQKomKVxEB1ozEEOBlBjDOceDHHXZlryEFrZOCVme9uTSOkpQbDgxAsBoQ" \
+ "6dBjBwWrXj4MpbNqgByzqAzrwgIMhAGSRUAI4ImPoj+4YhtEJ450rTr3Te+" \
+ "oKQ0EdEh0AuLwvoUgAWPT6ibwjn2ZyAcMQETA6C9hhQkdsorFi0RUGeqCkDB1Dd4A28ScCMQJw" \
+ "uxH6QfQ/" \
+ "yMCNHCVggaJ1aR0BADDzeh0BwEQEwFyvuyQAAODD7zgA4LJkAL4G9D5GmqVR02oJnHPAa0DvY6" \
+ "RZGjUtlsA5B3Rn1hAyRSpTRUo7mDuT66pYUiZ62NwCAxIAAACNtZcoBlgINkBEZhUtSYASZ1pI" \
+ "CE0IAehCyA7TQgCCvQOL2OG46YRjoqO964AUEUVtMdWiMpMcF3OEHHwIyRNOXSSFFzOi1+" \
+ "tdFlz6MJEIiHfoFEGsBWqK2llRk+NFMszjmrkOYygQDQIEGAA+" \
+ "HOSYuSZcnIoDMgcTuGgKb4MccORxwXUwMNM5NAQ+" \
+ "jEtmJnk8GAgTGCOIAaGRvV5HqNPpDSamPgLUZYEEhXR53c0QJzo6dJE7ZC1BLTrDgLgQUV0Y1Z" \
+ "PI8bg60YUL6iMCM8fjQ0JCwjg9wzJDSCeIN5aeRgETm7ShW7pNB2jdSQAA1YwA0I0Y3ZIcAgAA" \
+ "76QMFAAnAgAAoe4uy6WEMgFavwv68IdhABANMmTIIwAAAAA2XwkkAD43TD0Fe0BLqzkJe6wblp" \
+ "6CPaCl1ZSEPR4R0mKQdrfEUNXOo1NjxXQ2M5EiggQAAKgQTLsoYbmoUISmWBTJoFKcEitjFhGy" \
+ "QCgmQigBDQjFBZ4QZYPjTsiOMNVioDY+dqjHBzjITDKZHBoZrnA6iiCYOUJgwqFq+" \
+ "mDEu24kxORIYLjm+" \
+ "PR65PUKYWASXsmhngAEHkhMCHx4ZAgAmbmSkb5JI4ZhgHh2YtpgAvN4XMOQmTMRjA6aHkCH+" \
+ "jA6FVDEAWqKgjhHlD9ZS4bOogVPLEZQBj2SnvQEZxim+" \
+ "mvvsK7dgCUswSOc9JLIBK6oCaPbNTkHBedS9YS4cPG65rQAudgwO6bHoKsJYTTAMMK4AANmHVx" \
+ "jTJ7Q6QEdEKZ7kpuib8EQLZAqQIkrdnQAGCnS4ojg7a1FusboazG0MBFHAGiOI6/" \
+ "H2pEcTw7goALeNkzFJ3EoxLSYAkePbcNUfBKHQk6LKVD0eNdQEYqElJIghn03CFyXqw6RHi66w" \
+ "hQTcEMAAADsJRmSWJKEhBABRQi7i3sIRDxERcFEIE6J00wooiZWgLI6sqqoaaImA+" \
+ "AdUsJsHFq5eAwXHDQG1CCPzECqbQSSuXI9EjRqkAnfqWtrj2u6Y38kvY8UZgIRAAA9gwTCcT0O" \
+ "QgBi8JqZ4zokjJNENj7UEZiDVyYzBMiQObjpNXAMqKGRYaiDoaEGQAgBHUEGgBAe0gRASDCOv8" \
+ "NijCH5HbiKapzzQjhouA6MQFLiGN2g85EoRSdULj4MpRwDF0XuDnXc2ccYPjlmjuEBMwSjdvQR" \
+ "SBM69k4wgteORhhoAuA7ZAMAoGH0pwAAKjI5AfAMBEZERr9LRwdR/f/" \
+ "WBm+EjcfMXDOQBGAec8FkAsD/" \
+ "AD4HLClF2mYmMaxmckRzw5pKSIdJDqsJz0ecGC0J59zOuW5Oko7MwuxAAgAAiAgkxSBKiREWij" \
+ "MlLi6kaAERZYoCU2IQiGH1rfZGI+Y0W78s/" \
+ "lhtUBVDXdPJ0QA8ZxyJAOSovfLiMcBwMFwRSeciPbgYDXgEeBzcdBDURwTpIjNAHpnhYuYguTK" \
+ "g3unQCUwgGeARIgDDzMxc4XEcTy23Ta6LzCOv15VPDK/" \
+ "MXBnpOulLtVsXBVEAxmithYNQOPXElRBBXLggBE6XkyI0JMwyYBWGMgJ6q9BkKNxjaz1K1TsDI" \
+ "oyDzmvPYKiekGJIEE67I4w5XhwXAANwweMUkuGCQRwqtQSNAIgJWVdWnOzt0Z73R6kl6IqhpHs" \
+ "KQi20iNlJYKzVeep1jEBkLAHjLRq/" \
+ "UnJQIQC0AXjipN3gQHy1Bl5P4B0CMsRhT7d3VQAEcgya72QAvgY0MUVpGiE98OhpDWiijxBNIX" \
+ "iQwwLyXWNlLSkJRJkI5pi5UlTXSULsyMwiIgAAACAhhBASEoKFEC4uToiQFkIImoYERQpM7Jzu" \
+ "sG7HVhTTnGaL1ZaZDDK4tqNimK5HPlyfXuGYK5lrGByZSHqmoJCghDFsJCSBHqEkssICuV7MlS" \
+ "HDpYuwyHgD4CnRASEjTEoCBEN8gwr0npGEhhokDMcVLq6oulqoGphjJoGEXHPku2pJQZM6zuIt" \
+ "3uC7hCC6CBCqj0U4dfoOA9BhlLln1LEUBsTodNAZpm5GSuBRjpJ+R5Ek3R4mHnEpz/" \
+ "woPkxaVjIZVmODUztO1TAhxmg8DmYgD7CYCYOzn0EaEhI3AgAQI7XSEZoyRajTAI3kO0Dr0Emc" \
+ "DwBtiE5koAsZFh2DbidOjEjVWTcA72J0RKGoGj76McwC3UjFxPOcEMipPa7jejAXHjcs0QdzQc" \
+ "ovE8YYN0zJB/" \
+ "lAyR8mjOEuq0UkyCICO4Spq9o1McwpI4rXhEUzgwAAAECCGVJIZgmWaCICIi6ghOIULUoEQhCA" \
+ "6RKI+" \
+ "oEC7IVD7Oysin0xzEStE6bM1rjSClwzOYtrjuHTzMxr5i7CvI6LyeQY5piDQF4Mrwk51tqiBrC" \
+ "gMwfXNWTmOI7HXIrwWSwhShx5b+" \
+ "Ii1xxZywAw5EiYRxgwNJIFRw6Ba3LAcaAiL64jny6u1yTMEI5h4Jh5EVCXHiZidw8ByIsUYNY6" \
+ "nYnwnrh0YRwaCjh1jND6IoN+e8D4SOgefGSnBRCdK+KC+" \
+ "hVLp40uMkAoHI1PHK8Mw0UgALCo07kiQpd1YEHEOLMMAxOMQM0igWcEwKcPiOP5aGVv1DEGeD0" \
+ "41V0twoN6iyaCSnJjqzbkmg9D5s02YTJgmh1GAABAJF1E6GIVBYcAABIAPjesNQUzQkMCPHqaG" \
+ "5aWgrnQlAyPHBnsGoyI2J1YxnYulVRiRRQPzUSSQAAAAOICIkIJxRjulBjTIqJu4hRhEeKQ9BB" \
+ "4sCgoIikBdwJxmhIQEVERePaOrBbUFKsFq9Via8xoMdRixUQUMdH7kA4dmdBkmMnwIExawKglH" \
+ "DM5mAcLxjNur2OQcJDU8jgezKGMoTTCSSjIcISEH/" \
+ "DAZSzCSRGZhkZQFzWOzHzIPI55kVeyaJyOLOjDeMB4x32EThqElRiLbu4hSagB4JPVGX106CQw" \
+ "FxlezAwL1AmnI2OgJ95FTYTXUWJCHXogYjiJ9zeAQk+" \
+ "MMzz6qVPvGfo6OkJ3T2dnUwABQIMAAAAAAACDQwAABAAAAIrNerQYWv9V/0//Xf9p/2H/ef9p/" \
+ "2X/Yf9Q/1b/BEzE2jK0NDQQNcgJ14gIsT+BVgws0GAgojdE9hi06B0utk6OBEYZxNa/" \
+ "YWB1IIIaiC3o9ycQrxHPWQR2Beo57/" \
+ "Q8dRMQZxfcCgCgLFSCVcrkbAMF1KpCqhQAnjY0MQb5gPRhjae0oYk+" \
+ "yA9IH9Z4vmUNKSIyKUUp2G7NVa66kjgVnUUcZ1EOBAAAIIiYWLIJMjJIQolT7uJM00SMFhFj2F" \
+ "nNqfaGWu0x7MVi8SNjYScCA2AY4ksuMpMZDi6yzpho1rAWIcMx8IKBa+" \
+ "IZaoHVE4SPIiKyR1iEDMnFqYXM41L4r2C4C2auQrtpqFOnM5JMmHkkHMeRIeF1vOYxyafjejxe" \
+ "jxzDF+" \
+ "B6cEJaoEZP9HoSwUAZLvROGEM8OINxkgiqB0LJCojXQ98rMUTnbyQgCKKskRBKoYPTAI6RpU8J" \
+ "dfOn9Bj92A+xhdANvOATJADQqojR7XLp+" \
+ "uW0OQjWYCAD4hiDETvevXUkAjpgjECjdaxVgTpi7BgQBghIvwmmQweKgROAYQAnxdyfDyZVwGw" \
+ "GHRx6WToDAiaKIgB0n3G26RFiNDNjZQ4AABbyfsJZF7429M5FZh8N7ZfZo6e2YfQuMhtpGJ9mT" \
+ "56PdjGbaAfz5LpdV+" \
+ "gcuhHFY8dAAAAAUMYUGOJgSkSCAoGAQkH7NEkIxQUUoWgBamtnqDoQx8wwzLa4VuxtRcQwxM6i" \
+ "mGqnKQgBNWW0tiGP43gquIHMiPBMTgaPsCI8ZgZqRyCZFwfDXMfMwIthOI4QjtGYuYgAwPBipc" \
+ "k181o4BlCAhBIGF2aOubgG8uDBHDMz4WKGPHhxVXExgRmmiiZqE1MnGAB6Z0gaGuHOQEANIaCV" \
+ "QV8tAuHgAOBFZmI3honY1a0m+v2+" \
+ "jzxGOAidEZ46gShAZwqN14ePmBfHCnAAAsHotmG8h8swmg5oTWjInYPwm4BSGAA0Qz8WEOK0MK" \
+ "kB6L0BHLkmVidRw/" \
+ "CXKQaiJhRE56mXHICVMMNHIt8dVwAAAADQYAoA9IyMjJ7oqQTSj5kFKAA+N0wtxmQPSB+" \
+ "szA1jTSF7QPgEji6TiF1WMldVeoorFzqdKN4sa+" \
+ "xAICQkRAIAAIZUUE6xD1SQ9LIn8SmvZ8kzWFRMVAhJmWEhSJAyL4MrQAABCCGEfYoqBwVfvvLU" \
+ "rU/" \
+ "4c2L1xM7OVuzTDlVwzGqjVrEI8prXcU0y88plIvltLPrw60Py4gQ40ylhApdQi5FAHcwDkosPF" \
+ "zB9RBhi2eV9xrjA6HRKoY9s4zLPO6ZcHEoCcDGvYTLDPI/" \
+ "PbC+uHFExMNQWcxog2GKZ5jpUTZBGGcM2sX2mQCLtBWzc9M5oBKIhr2nVZDJEvSJUA+" \
+ "bQsEDzom5Y7CBDnBL20EigLuFgAMG9AkZhqAXooQNcJrRGBoQkwGOCCf0JQICKmBWByTq0iKlp" \
+ "+hN3YnvaOAbIg5khYARg0RrITBhYACXbggyTaw4uJi84xkxEBhVUAAAATK6zqrqO9dNIgA+" \
+ "4ABn+NuzexMcPq+gTqae3YYsmmn248EvZQ0C6y6xWikQZGWFyJ9ZmmaCqXU/" \
+ "0xDlHOc08ToQAgQQAACQxCyoKXMYUlIiAeJhQKkm7OrF0BwRSl9Qzyq+naTefUI6H1/" \
+ "G6XhfX6qqwlu8+DWR+cCiM0qKDbrp2C04LrjmuaZEHM1dUC60NP6HujMTM9SCbkDmuHEeu+" \
+ "QETMqpjoWG7hHjqCZiQU2DmIg8qhDnIMY/" \
+ "rSrWjQTUvLdbUWsHpYRhQmVBVRamO7zK3TKPOlFoV1xChAZB7O8K0/" \
+ "17piAkJSr3pA5yUM91WPSEOzTCRBYmgoSE7UhOkc+j0AGASjpYbGQLWggCQDLoB/" \
+ "EqPIhdqU3C5wu9BFhSl5AjAcPBYWnE1mQsAAADhxRjzGPI0AGACAACEOgkoEXAjXOTQg6ja2k2" \
+ "ozdSZmEgougvGG6nOAqNiqqCGKkxTGXF9GFQdEgAQWU8AACxYFD9ZTwBcHAD+" \
+ "NizJxdgf4BeePL0NUzTB/EAIH3jy/" \
+ "K7MDEAicmDsIKnqdq7MQiw6UcSxCUFAYAAAAAYOS8EFAeHGuBwX8vRSBSUAMxGIOSZgEXEBYUp" \
+ "5UkCRGU6IomKqrW8MFWPsE+" \
+ "p4BKLiSo5cWxwy6i2aCIvGlVzkQZhhqre1vk9GIfwduyysMYfp6kqSHOQRAIWFrTlamUtRVOsC" \
+ "i4ASxy2Xp8bxI6UeNLl0JOylIcm8KoEFTxgd0SGyjzADxwVh5p2qbG7NoLBCFj0NvaP21M25Z0" \
+ "CihupMaGN0YHS6fEgnRjQmpm83Ol/" \
+ "jVmSZIsJTR4674wtdQXMxTPU4YYl55a1SW+" \
+ "nKRe3FFAlAmAhGIcmscRzzms0MoAVaoI95esuyDgBoTDDNfS8gTmABgIQQkH4R8cepiMUvv8Yx" \
+ "DR+" \
+ "M3lgy6zpakJmQK0dy8SHhs3CtwLJn7gACzghHACADVAAk4JUSb0tKfjb0UobsAelFTvZ4NnTSR" \
+ "NMDygtPnu/" \
+ "qsiIRAoGNNZ25q+PSqThXbDzNxIIAAAAihw8RwCQFFUtKRCjmFa3wFAiFFWIV5V4RB/" \
+ "aAb4d+jW3v1Ll3hOFnwiIRzm1rGKhPc3yaHNfBNY9j4PW4UCBz3NIMKRb/" \
+ "Yo7Zgi3mhEMIHYwD9BaCSHPCGeE1DxXXzMxpB8z1mEzRc1bhNy7PUAIsIHwGl7vCGhk6Y7wXmG" \
+ "vO4pK+lbRF1hPoXU6dtybCUH349R7h4KmaiyFcmTA3qJCNGVzAkTN2GcUle/" \
+ "mWDIKhu76tydqwxRWyU3KxDUNIu59GGQwRZDu7naQbpjp7QCTjgcxcM6zwF4E5Oq0eoRG0o6+" \
+ "3hCHJ0l8UhguOJFHBYmTcfN4aYJ10jKBL7xEZRcAIaxUQw59h3ALQQJ1wU/" \
+ "pIYPpbVNRfRiBtMpLXDDNMLDGMhsCo2hgOWsIyvao0kQAAgRgAQAPLaiUAXBzCv5fAVKXAdwUB" \
+ "AGRZAl43LF0nmR8b+TdyHHXDNOpY+" \
+ "2MjPvg8HhPD5OZY7Oy621URi7stBMTJI6Qoh0AkAACgRGUm4oQC7aVExEUQLBAFERX47hSBQKW" \
+ "OqROGjZ3VoVVU7GRyl1E27YQKri81sQoR4Yeehgy4+0R0LUBtGnOVfneARcIAs/" \
+ "bIqpLUhiHKQFpM4F0ZjIQrVgjMZLmkwEQVhFaMIWozuVYbnAauQIQXmKtKmBVApYiiqBSFL/" \
+ "NFWWAZvstNhHESPTJXWnpxhDmszIoF0OzhMNHRotGHmZkRViFoQvXSjkfR5jgqXPNU5yPBSWjt" \
+ "ElhAARBjYLXHXDCEqZYhx/" \
+ "BY4WCuWQmktTxgkp+6MDxGQRE1jaGRSdjOKJxwYlrOrE1EEAA9AZV0UwB+" \
+ "SdMZDfoRAACAUfrDY7euoerjy7nMmgTkQxIIJG8Xql1h7lLtxbdXHcFpAAAAoCZPi1BjyeQAAE" \
+ "DcvM4MAFxwRLKT+" \
+ "VIFAB43jMmF7EMR8yeXuGFMJjL7UIifPO6qooqQMkhEMGbu6nhjkrhYRNwsgZmQIpBIAABAGYi" \
+ "YBZiIIJmwkGkRES5RolwhpMUBQaBgYZnA933QqL3VcVcmdTKMmboWrGdB1er50kSGFKPaMT/" \
+ "mePHi0xWF3xwXcyQXmcAjheOaGqx0pDDw0LkYoZYZMseDyfEIrwEmF5lc5LJl1wU5dNFLCAlpT" \
+ "HjoHAxhmLPCkIliCmIFmc6G0QZ71bSoKBgYmIjkDJu/" \
+ "IJRR54TLhyRwMXrDIhj0YW51qHNBRYJDEdbIAPRhyDAMC2pAEZkAPkJPXKBwMl5yEWyF4QqXk8" \
+ "JTuxwXx8XMHWeFOfpIFp36ZVZnREf7pe8jT7pIFKErIuL5806oVQGAulqAwEwAQBQFA9hKQzAA" \
+ "wGQSGHjAXBfDHGGuDzk4nRKiUmplyvR2CNPZAwAAAIZh2idUVVUB4YAA3AXkmytQOFQO/" \
+ "jYsSSalkUYOFznb49swJZksjcxCeZCTuryriiyFFCECllZOnTHtXBLXxtLYhCAMAAAASAgJyYI" \
+ "lS5IshGJCQiAqFIgJxZl9j/" \
+ "333W7fpr05MZp24cSkeH2tSnMsFKXMW9qaikylHLmuSXU4lCgLP05DdRTO3rc7GW11BpMW1kY0" \
+ "WI0IKGm0kx5qjFZjIpiivDq3YqSMulB1Ce/" \
+ "f4dTnLa+" \
+ "O2IKtrKH2mnnSRpi8uE6bvx0rESWgBr6HEKpYWSJNhuqSdKnDhXeh6MSWruKu6hyZM0pIGDjEL" \
+ "xUMwkfCygCHDg3Vha6jhITx+UIAnnjjw+oylIFs7gYnnGElegYIR8hw5Bg+" \
+ "hDkGCCPhdlFHjUvhRwBAFvB6i3CGt80JIf/" \
+ "eAE8RviQdBRYacEIEQRAijEDrmjDFbopMWMVTUQzf7fUeI5iGHsD8pfkrfjOnUgAAAECvF0P7e" \
+ "aABAEBk1zsCAF43bFFH88dEXg0/" \
+ "6oYt6oj8MQl5Nfy4a8iSSCIRDjYnzE3veOwqsYrYTG4CCQAAwCBmEEkhJQtJtBhExUVExQQCCM" \
+ "XFxIgBTkxvbxo6xfAvFov/" \
+ "GfBvljmtJ0T8a1m0dl0zw+" \
+ "u6AjM55vVYFWEIA3NcMMPkw0FeCR1DdyIiyY95XI8p5C3kT3nlAJ4C16gRnoRkRBgPPa1hi+" \
+ "xICJTmMUPITAG1mlZ7MAwbw9VO0Pp9i66wIjSy3hGB0zDC6wx5wIvhNQwBeJAwcDF0TmNRZ6Gv" \
+ "kokIwm8hmNM4Q/" \
+ "VY0Vk0jozLWlAXIgwjP3aag9GR3qUG9hhtuoh82CAPhrnmEwuu6yhGhILBFYlQQp0UodRTCUAL" \
+ "sQ/" \
+ "CRAtBEE2YuEWKMOBAZEAPCBm3AwBqSZcC4BeYmABMAMBYkACOxyMAAABUHLMaUgAA2BqfXgMAA" \
+ "NQLHjcsSUcOI1AfPA9xw5J0TP5A7B6GHndFdRIZMqEUHLN2EIzV7ZxLLC5sinMeAUkCAAAJKUg" \
+ "ykSBmgCgxUTBDhIlAnA6AhpAWEOJXiCahabB1mnjOpaZaDBUMg6lYBAXMAUPUdc3AECmyI4DMZ" \
+ "F6PjbxicKPLSuf1kYQAczHD63qQXLcAVbRu4BgmeZGLgLQwDMzMHD8yoJH1HbhohKH05QjAdXE" \
+ "cjFBH1Bs9o8d1zQOODEAgAhERxsBFJrklKxcDTyRjvJPAGLtbWAm8xRHNaEgYi05XJJ2nLjiBv" \
+ "giHThJpY6P1o4lBLEYihlBCdQRhaHeQ1IHRGO+UHK/" \
+ "JNZMUZdUIdTGA6OBDwhgE6ToiBgCAUADXFJLZRegIIYQoijAitBpBAYB0mAfamTgAAMkqChSAi" \
+ "hVZmAAAoCMFMlhXBQAAQKXfX1ZIgOk/hyXbVQAAfAAuAAf+NozRRI4/NiVcwNswRhM5/" \
+ "NgkF3DXrFYBRMiIyNOM3Vpg2lW6E2NqlUIXnUAEIQEAgJNUJSAFRcFgZqFATOApLVScEtKAmDh" \
+ "Nu4kLKHF2l8sUdJljntIH5tPxOCSuKl7MKvh0zTFIJ4YaqsLwIONWlytkqK4B4Qay8MgE6kzDc" \
+ "VwXgXmRRb2erGJHdpmQFiLadToZYXxknY4YSzNHOKWwiuPDI7kyc+V4C78TrkyOx+" \
+ "T6CpOBqTS8Xj+OzDFkFmE8jajuDNSEtGiNnsEbwOkYSMDFXAFvQPQK+ohQo2XDs8hfHcVMZG+" \
+ "cej0BjCdmMwERRMUU1CL2qFzHHA9eV9RPZ2dTAAEArQAAAAAAAINDAAAFAAAAVx6YmR9Y/2H/" \
+ "V/9m/2H/WP9Z/3VORkpMSk58cGtuam5nZ2tqCCObwnf0LmQeXJnfa+BIPtTG5UaNjfA6/" \
+ "XTYrl1Li5wcMDBMyyEBAF4AAABUOFPjubFDzrqMwarPAKjxugADIIHebgW63cx9egLIFsQMGgk" \
+ "uPwwAFbhABp421M7EjP9ohbCwHc6G0piw+" \
+ "UcKuCR0nV41SQCASbETOXdcdVVFrlJ0c4QJJCMAAADPcA5xIzxWA8M6xnl8N9fwkEppIgEPyXI" \
+ "3oSjtWYZYTHtnDH/Z7mKZTNdfNJ74Fp3eFECMtjGQhfnA9UYpJ/" \
+ "1YvXJYOTJjany7DRgsABTFaIsrEaAurw8LkbAxmeNrAQQr05IYJkEtMEgE9W+" \
+ "PA3LlOF7HhKtFKadthaM1K5xauaZ9l2vmygFMF1ZJqI6V4pUBIDOBmyw6DXHrSMHFUMWvchozI" \
+ "Gwb0TA6EO/yEQB0PhIsIBkT/" \
+ "RZH60dad4vrPXQTKg9UoU0grXHkSLlIuGTg8ehSXBchQwkIM3VasAXXhY8n0g36Ic8XYiWlQQt" \
+ "y6B0tXAROgEgwWAHzCgAAAPezppotW0BBAOCrZgzA9ZIAbrfLxAToYGdTAAAwJlYqgErGhYwDF" \
+ "BfYYEPg7h84CgC+" \
+ "BkxRJo1LIaeFgiLTBkxFJxsW5LQQKPKqSkhAwCJkbLnspE5VuyqLa7pJKULKAQAAAC+" \
+ "VM14YjpC4cagMhwhyKWMIadCdl4iKeFaQ8umy6RmFTzy9AlpMBGJer+" \
+ "FT8iBH5nqQyUG2wAjvysAMw1y5VtnmhHS6Iul8+" \
+ "KkzguhJqEXqgoS8siog00U4CTajcR2vOTIhZCA9jeS0gY5a4Zr5cF2Pa5iAwadjOK4EJtfNnlw" \
+ "gDE7zGAGAKc2R1zFpZAYgw1Dohu8LhgvVmdqchRXCFiw6zuI9hYwa0n8F1dGaMeAawS6RgGF06" \
+ "b2OOkicjlG9t4KZHADwuI5T8ZihdnE8husDr3nwSUgmkE0oTLIEc/" \
+ "EYZh9t0hS9h8uEpMAf6MIv/X/" \
+ "RFyLUMrp4HJEHAG8R8B0BAABxCQBw8TB7JwdsAICKjT0CAKLW6Cx4QDLX9fp0DfnwVQDeNqzFx" \
+ "+YHKBeePLcNWzFJ+QPKQk42xndRAYJMQSdlrrmqXSplrsvCLKUAAAAAC7COyxK+" \
+ "gDiOLYwwEihIqTcioqJiLooSnzad5t+" \
+ "XI0uovdXHMqONWu1trehoTigttn5GYxgHG8NkOF7XrY0L9PqG8IxsjhZYcNZ2LQ0LBYlEXYwl4" \
+ "VWCmQCEa4WbVrf5ckEGxLIEdx5WXWHh0h7AAEdZEniGHUFCRgpmTRgSYXSOC401a4Qh87ZYdDo" \
+ "VkcJurIvWXwpjFF2RnKYI6iwwE5UUojSIgvCdauUWic5Jik642t86i2NiZAeZEMbo9DqjFwgc3" \
+ "dI1QlOla7G0pQzDkLlLrGqyF0BmjlzJ8XSMs77qyLUbDQ95sTx2hEVzhs7PbdbWAT2rl4TFaQE" \
+ "I+" \
+ "D7KBRgTjiQAMLBEOZHA5R4JAELo6Jn16Rh7Ygwshn5kljY5WKeDdAGAIQBuAlQtDFxcAIxFvZ4" \
+ "6HQSeNozOxc1Dk9OFJw9rw+" \
+ "RdhHkYclkNPBnDq45JAGDkEHO77q6E45qlROYgAACAd7s4eePywOcolC/" \
+ "CqoxMsaiwAiIlUUI8iJP+svEx+2QbbYpv9TO1J7H1a6oxTcxBWgfTROPK5IqK8+" \
+ "JhfYfXcWWOuRXMMYiwBWZnV4UXB3PClYAWAbiL+" \
+ "fAQ4UjpD1cJok3mLICBex2oogaEeRjDHLW4YbrlB5mZYQaLg7nWTulBJnM0huPIMR/" \
+ "mEmVyRnVK4iPTIAvdTkcuh/2BCAaHr9EOEIuk2NVw7iAl/bqH56EwAkMkSIdiBdAZvUt/" \
+ "ddH6ZCx6Qr1BEyARBNdw0azorHiMIbngNbOAdrLwOhamZSgiIrQ3Y5i0sPQUNtb5FifoEdtmD6" \
+ "RbgBsb6O+VlBWA0CNsBtuLG4V7IDw4UhUelkBk94g+/" \
+ "WKK6YV11wYAoDduA4B7z1+" \
+ "6Lr2XymIDAACQYEnIPgcsKSbSAj6YKwjQHLBEn7INhBd4fleUGQAyxJHL5NyZ0pUUOyeW6CZHA" \
+ "gAAgMcIhByNclkurFTAJ6Ll4uoVifIQgAgrxMqn+Ip0ZFOu+mBrGr5lMid90mIxp472/" \
+ "h0nd3h8F65wXOGlXkxIaVWNMDNXKcF+" \
+ "XWbyxBk1dBIPP6qBiMpUAyk6MXBNBqgqicXujEyd1JGBMa6QIBSNwMwr18DcXoMrWenWtU9zHc" \
+ "Pjw1yZBA7ChMUXOmkEwh9q0TgRBH2HUggSegw4QUI3ABdsJl62hemlSmOaFWRIAgu3MMEuD3H0" \
+ "e3RHJA4JAy2SxQaaTjfDgFxTUa5cGWDABtb1HhdBq9pox5U1RTkOvXr73dZtaG01Ebq6Tn3EhQ" \
+ "sAgU/" \
+ "oNpFRIgYDVYtOrlF1qXhqryu5JjoinVEAzovr0NEmAmmijwwTu7EjrkABJFseTe0sAIC5XjcDA" \
+ "B439CWWNo2azpJW55jpHokbuhpj7YdOX1bnmOmVuavKIgmZskwZx4plgyWamrXzBBljFucSRaQ" \
+ "nAgEAAMDNwYGJSDxRWeEpLvBShHKoaGgrMYREkqgIXGLihBBHjIWevu8pJAQEAChnMfPpE8x1M" \
+ "Giva5JHjszM9YJrCWbgel1jcW906QAgsipqWic7DN82mBrhoCM6AIbAkPBf6IgFn5zeMeNJWDx" \
+ "8KEGoy5HBSoTj4WyAmmIYgqoxNSwRjA4GufTGBUd6KwcFnATQ1y4XgEOAEmix6dkdRq9bahQaI" \
+ "N1+iK2FyY1BI+" \
+ "sIjbZGR1zUQnK6vLHIIEHTNddrhms0TqZnCEkNSBjXzKwCciCFRabeI9qEQRQoqAc1FkAcp3A6" \
+ "S1QoAGDryQi0GOjDGwCWhRcUABAGLhv4IIR+" \
+ "v98HAMhIAPDppHj2hkWVUlFR2Quwt4tuJIMDuMAHFjYkhSzy/L8ZsuVnkSupZMresCEhRDEM/" \
+ "83E+" \
+ "rPKlVQyUfdHWVGkQIgyiCJFWYQKZWQxNdVNvQGScooeYtPZmEpKYhIAAHCFggYx8hmGFTMyw6X" \
+ "kLgFRCEILqUX4oJUQBrvAvUjJfibTT6cOHNjFTHG87DxduU7Vh1wXTK7hOK7VXhOurRyPXMOkX" \
+ "HD8VhbhdxsEhiGS8OKgRfGlrbZqqHavXmdA4FQYQgIwL1AO1J+" \
+ "p9k6nmV6iJngxIQxLwwDMABxzw2++ASgxOXL8MvPI9zEAkMkcx+" \
+ "MgE8hkAikBLf7alVlCnYIwbGfGzNqCVVuZbUbbzCE969R0OpDQkBYIQQ+" \
+ "GOGKZBm3P5IkRZYC5kDiu65dJEtJipop3Fi9mhhkSgwpHDsAKOQpwg3FnuhicFPXBW8vpSlEFW" \
+ "AEAd6w8ecSZhJ6bwBva91t3Avs1S7b8yQ8yYqiiowpTDXokAFBEALgsFJz7CeCaU3JRPVysbc4" \
+ "KAPABPAV3W0MRxvdyBAX/NBUV3OUMRRi/" \
+ "nyNEch+cSQ2VpTKTNyM0IErFMTvMa4a5MpPhQS5XZL1D6KOyvLBW74Q+/" \
+ "LZQzerw1OCbEgBoYNcAlAULDSuNVA8UfG7aMmChYqWR+" \
+ "gUFvxvTmmpGGXhTFQAawExCsAe1iDDHBw5GF1LvNJsxFm1CGgYLtMU4GJj5ziFCfRjzAmQBdxi" \
+ "QcF6kggXbPLaC5Q2wuD6kggXbNPk8kQApvRGEYqj3IW7UlXAthj2gJnE5JPiQ60gy4RHM1ZBeE" \
+ "I7wIsIAnjgESCiQYNgZpAW9nBhHsr5Ach+" \
+ "YWgt6ODGOZP6A5H5QfwF4cwRTlAHf6yIWknkMlIDhADBRk/" \
+ "k0pFCnwxsjESZ3GmFcMnA9Ul8YE+" \
+ "JlBAHyP6UWANQBCyM4JH8kgZHkfsg6YGEEt8SHzERyL6ijogqQ5j1TUFErK+" \
+ "SzxPUKcwtIRPgdgWuG11w+" \
+ "OtTpLVDDZF4zx6knBlUAhwDICmQALCKB08VwOgaSu6apRiR0jpu3QyC5zziNs7JaCAqQZFQwMN" \
+ "c5uY3QLbMSrgmNzxINUxl7OyYslrwoYTSW5hsgvtFBQqEPnf1YBIBj6z8BXDpDN7Ff+" \
+ "Wx9MUF2jU5VgT/" \
+ "1w1Es0H+1J1qEFCsX5TGX0IZvTtN9S5llTiNyVKec5rJmvh6CYjGTi9Bn4tLhaREGlmcL5nBu+" \
+ "KDZnq2Kiol8RH9qfpfQf6ZSVK0dP/e/" \
+ "nvvUaGuZNm3KVN++ZbvTOpOdjzawOi+O9yoXAHQ+0RXo8vzCWFyz9/lEVuAzf2EuPvO/" \
+ "sjx0WR0hcqc5I4MaznYaOVWEsijZZpWBique7CZhMbGQZfEyWVyG0LMCYp4Oza4KUjZViMiSQg" \
+ "/JWxerNC3JT/767BP/xVSfXYYZZ5wwxSqfPgto4LprbSdcLtEVXI/" \
+ "fo3THu1TCFeTTKaXN2VbNrK4qg85GO2bFWkWILNyZbK/" \
+ "KP1NAdz0CADFN8i4ltJAISgLi0X9a2ynottztoFPoZvWfneL3HKV90HsypJK7Z4GTo+" \
+ "rlc5fjyjLaOUypO8x83scuACw2qQ7qtd7EAgV+" \
+ "5BJXoPs91L7p3TgWRSQRmxcH564OZydzCfU0SV57KRj4ToRDUoFkPXZKTjVV3okKiaruMtXOiJ" \
+ "vA0/zjx//HqlnfY8n74+l7HveURKJzFxWIUOel4rq+e5dTPPUjM/" \
+ "23WFUCjErBCfplfdjiwjcqhRcQp/" \
+ "qYYjPcVVZEYmJ2CVlVIYnssMHUPUuHciRXDLCaCJMScvjseLhRLq8nNuOopQoxmYiKv4i4lWhP" \
+ "UcrfRaso7b1OeIiPC09dSCl4giLiB5UKKWZX6D2OAPgkAGQ+" \
+ "qQOs25VQbOBdQtEVaCs90Di9V11URiLaIeY5Y8x+" \
+ "s01mCsGpqjlRM0w5kbtfAbg2X7Y5ooTqyNL1iX234M3noeyJB8rDzTbe/" \
+ "NOZnDUSdBctE3OXWHOV0Hru/" \
+ "z8zXbkYTn+tVnNvilOx1wIAjE7FAfSov5nimu1oVZtB7Pk3U7xm/" \
+ "4zKyoR2Zhumjfs8c1oUMI8ngKhITnHK41EyJeLu3qyMogICupCAL8aiNMUQp0VFiFBUPJj4EzN" \
+ "25n8O7Wc6Go4cOdiN+LLFwUwc+" \
+ "AAVvvxKAJxS4QD9dn1JxTFeKhXPoF7uDxSL2dtlecgRKUQVisiLrMpA6ggbRs0jjnKEfgOgpdr" \
+ "GJEmCSIha0HPVlKMFk4QiE4JF1+bDDBGaRT0YxK13A0tkcaGKi4iAYFT+/" \
+ "W2YfgarKWpoBQCMUsmKtB5iEFZcwyutkg2cSxwhWlzjv1ElEmfMLMrRNnpJm5k5p0iVFcoR4QY" \
+ "AaqZoCY7B2Ht3D9GSj5UqYu5SuApSXjaqRFGWFWVX7g1JNJIsdMVGBnXsrEM17v79bbU6mtJ+" \
+ "1MbHl20AAFRavZMB3cRI3ALd8C+" \
+ "tnmHEN3GkbvHDtpvihMRpzsEZGciKmJYo5h63sigOZkVZBsqSekW2KwFcl6qEF+" \
+ "YzIkKKQctyeZlBtNogIMHzUTQ571WEF0+a8GJSCLgRqQb+" \
+ "Ga5LgvTOmLssAABPZ2dTAADA1wAAAAAAAINDAAAGAAAAssrB0Bhy/5H/Yv9Z/0j/Wf92/0r/" \
+ "Vv9N/17/" \
+ "VP9sOrUDVEK81OJAtxnVTcDvIWrbbP+qRVGJOCSJg2sRZVYUgzhr8q+" \
+ "OySJtSwRgYVvWvMClNgVxqmmBq7XQR4pyuSiRllAhTU/" \
+ "J80pq59H9GYf2dEFIWTNjavbxba7fe+OzU2w2vu0F347gu3zb2vq6AQBaJx0+LCWy/" \
+ "w6fDJKL0EZwnXRoeIwP/" \
+ "z18GjtrPSVoJb4DAJBZWQaiMiPZj7TIXiTY8nimN0md5gjdTTmENAAJAAAAoAIUURwBLHQ+" \
+ "h8sTCIWiPLNMeQmDxdwkmdC+CLzUAdMyBAIPBUlZIkwN7fnb+" \
+ "9uSwtRWkmuyyocmOYtBEel1HmpeTJ1EVLFOb0lEnO0AXMdjMseLD1Mp8wDCL2uEL0vATRNAZyp" \
+ "a49olwNrQqAJwT3iAkFusfXgdw8VZCVX8WMGwTjUUFEPpfgfmOncd+" \
+ "rHhdRSxWu3EBExD0NS2mRys5YNvKavYqwyfMhfAhNCeup1HCj7GrEZVA7mODVjh+BT+" \
+ "9PvuptHu3jSigQFX1zBEmbaGaDb2JQaCVRhGwwoyevNdOw9O15QrnybH5LqurGVP20xayn4QQB" \
+ "FRLNMQF1QHHcxIBM6wdmFYKUG3AQBwGjQAAAOnZf1Ub/" \
+ "e9v37rOD2YuEfcx5PCbDSLZCYAAKCX25caq19ul9qapX61+" \
+ "lIDABAZSVxfXy8QCQBYc3MAHjkFVsyd/TfmSw7VR2o/O0v5UYpsnz37D/Mhh+wjsZ/" \
+ "V4v2goqyEoiJRoSzJogx4HDqDIpEqE6EqJWUi14uAo+4E4GnIM6qbRCCmFwAAAABEA+" \
+ "qwXTLOUhBj28gygOcTCBhaGosRLslN8EpBjMajIMEsUkAQkyAGBEIBE1AQJ2AKYAGLEBqgKIqi" \
+ "mTCID0NNSEaLLkYDnQvEN18VGb45rkw4rqOnYaV6GJ2YACioYLGzmqZFrQ7FFAciIOiIIzQAAF" \
+ "4XqrYWe4vVBsVQUUGGOSbXcX14JZmdaYqKKIiCoa1NBDF0zSOW7AEDTIwyGBNWY8ImffuJWy/" \
+ "n9DB6AMBHPXz4HIbqDEUEtccwTauqOKLOMMbD5ZrjmhnC9ciHmWlnscFiFSyY2IsDPPLpyHUw4" \
+ "TpYALQIILSubgSg3+/3+/1+v98Pow83Ajh3lCBkrhyPYzJCnQIAAMgovA6uh9EJAABeKZVWTb/" \
+ "60V7qPRw9u5P3C16lVFo1/" \
+ "epHe+" \
+ "nu4ejZnbxfsP4ga4RCkllZkYEAOTnnefRqj3JmH9iZ6QAhtWtTGgAAAAAAwhLwGSFHCB6XRMWU" \
+ "R1nKslxCGD5DweeAwIEwXKCZoigIBdNuXW+" \
+ "u6XmVQBqiHoQyTBsxHNkLpmlrZ6uG48Prxeu6Zo7jw4cPQ/" \
+ "hDnTowOvIY5pjhOq7rypEF4vTGQlhZ3fSY2+" \
+ "AgDOHWUYPHMMxFEsRQFDUNMVA7Hz7l4nhdwPAgwKFaUbW3qGCxcb1CZsJM8kpAaJjj9bgCwwBR" \
+ "mPCFMYS4rlcmBwPMkWFyXJnMdXDMCz5NJvMhMGGA2ohpOCbqmDghiE8PAAAAAAAAYq9qMbFxYI" \
+ "ppZ2M6hmNitXfwIddxvSbD9WEAo402Vgdq65jjamPrUAXEsLERAPV6TcJIAOBooXUEAADAsb5P" \
+ "ql+mBQAAAN4J9ZZPu/wP45f1bp5ZsmuFdUK96tMu/" \
+ "0P7Zb2bZ5bsWmEPRHV1EDUkqbKiSFFUhCiCuV06Xs1G9VyLiZQHAAAAACCClHTIhfTAEMK3JKn" \
+ "VdmIjsNo6ZtoYYmOjIlgdM0yrKXaYNqjVDodWPB6QA8K8rpnJQcJ1zeuagzkWqKckjAW9g+" \
+ "s14fUaOI4HUEYXITpqIkAM1Tu9jut4TciVMITJ8HodCWQ4YfQADOANoUR/" \
+ "A6NjXnPk9SKBgymYKphqWGzAYudxQK6LGQAA3kSYCJcdDm0xTNMiiAiqqoIhYie2IoYQfkcA4C" \
+ "lghIT+" \
+ "Bpe3CDXtBNSRaasI9qbjmjm4Ei6OeRFM03DQo4cAiLFIunWAd11M5hWuOQ4GwhUgD8jBNXNdV3" \
+ "jNwQDAmEBHABgTEWBCWgCgowMAAACu49OHa7GxcYQDHAQoAP74JDM9PfvDL92dfFUybqQ9Osmw" \
+ "p2V/" \
+ "+KW7+" \
+ "apk3Ih7oIaKDBUQUmRZGRlRU0QRe1pQ3VN5Q1SKidQKkXuiGAAAAAAIAsFdEIKLZMmAkwlyuWH" \
+ "BXaYIxWJioCAUsIhLfKqKWkVMwKq2Zntcx8wxuRVpwpV3EW/" \
+ "RRyZeM2FWCsOEa3g9ZmbIMLQY5qwMc1zr0sFAGCMMTGskbXXMFAO1mmJgimGu5HYFwJLEawIzE" \
+ "NapAwBQFsf1Vjzy3QFzHZk7BTENW7W0VRxa1Cr2zGCrPVpMAQDAIGH1DomxGKG2aoM64TDT12C" \
+ "L4rolxwGE0UN39IchwOvxOraYx+" \
+ "t4bwBdhE5ADTUxHNjZ22LYuD7NZF6v1e31zcx6zrEAKfTQU5eHAcLoXQwAANBiX0heAwAAoxl9" \
+ "XQLY2gCw6koAAAAAwJi5JflldKc4cDAPu7NKAQAAANB9/7YUAAAA3vjE1hG/" \
+ "eISH7tv5rFmwJWx8UnWPXj186Hb2SbcVu6ZUSwQ11CIzK5AZqMgQaTcwymUaDxMWgKQ8nxgowo" \
+ "TvGRllZlE2ByJDep1kiMCIE+" \
+ "UBAAAAgIDwJjjo5aaInToqytXNJkNBGrxRElEWdZgihGYwiJBLAiKeyfS0hGkuioJQhMoSuMzr" \
+ "ifT3D1OQMmGwWLh5ywBRCMhQ8o93apqvqaryMorpq5x0LBQTAAEph2La2hoGlmn2FityDMLrGO" \
+ "1k2HS4PjSsrjAd6pDRJdE1kmsZxyOv445hcjDHcb1FHbp5aFF/" \
+ "dXoE86GG6AwGkxNWEHOQAIxqxY/AcAxnFJmGJ1YBFRcA7xhC/" \
+ "zvtjPnm7M3up1AAMMTMAHIwn5W15st2SgAAABBHAABDVEAEI6aaXWD0AYQcpaGbD1/" \
+ "DiJwhDDNMAgAoSgC6Edx44wDgdcETADRHRn+/9/ern6+ur+1+2d2c9XF1M/y93QAAAABz5/" \
+ "ufBgAAAB7pNMoRs33saBnTJ2D0uEU6jXLEbB87Wsb0CRg9btdEVZFU1ZRRkYQkKjJkcBKGoBBZ" \
+ "GYkIVLmatjWrg/II0wm7yQghJiWSBAAAABGzZJAgIkjJLOEKWVDK4/" \
+ "AJhyEMiIBQzKJMWCBOUQxJLCQJAksWzJQIREDTIjSIOAhhATgIPCYzx2WROHU0DBGOBI6EeXDM" \
+ "os5pMQyj8SAW9RHUMOLINUNgMpPXI59myDDAFfDEIqN3MZhqbzHEECVwRwQAAOSaDzyOJHMk4f" \
+ "jAY2axsTPV1lAbAYAf+" \
+ "k3sDkTFztRSiwmmIWAegetg6XowdKMwEQEAiqiomFaHtjaMkWgoBYC1NYDMdQxvCiZWB7Zib2J" \
+ "abEdz5HVdHPPiAbwMFgyIk+giEwDAWPSOdMDoBwCgG1aLAKD3/" \
+ "S0AsGO+VNLeqaW8tpS3+UVmUQAu3sjU/" \
+ "B47Pgb1zr4gS7ISNzI1v8eOj0F9Zl+" \
+ "QA1npfEjVZYYaa0rVRNRQGWrImlA4ZjEcgHY9LcA4EAkwZjAbgKO7qkiEGCWRAAAAAAvBEJJYN" \
+ "CIpWBKxZLBkKSUTxFmEAk0LAEdKEzEhBSZCmmJCiwsYDEIAZjBFgWkBTZiIQxxCBpimCBgOM2j" \
+ "QBG6SLpaiysW0izAYAAC5wkCGB1y5BnIM5FNmCF0k6Bn0kYBPB5kjgWuYORKO12hXCAfAvBhIg" \
+ "CnUYicihokCqgKTSRIyk9cUTId2YkFSAwAAwGKk0vGFVPi8tTC54HhNcj1eTwVkwIi0LkXKBHX" \
+ "gARgOrgw8hmMekwECQ2YE1OkkobwNQBYRJnlri2G1SA2AEuCMFBHhtOCQGFAAiKOBiTjV7/" \
+ "e7fToicLYBgA8/I0JEbe2tpioigHcsJAMsiZ8AgAuwcgG2EoACIAP+6CzKkpRfTI97tbNDya/" \
+ "RmZQ5Kb+YHvdqZ4ew/" \
+ "zWFWguhfSWqoCpTlAWE3diQ2hvp0wIkujNXNRLCeKIYAAAAAMCBv2Zuo0sBJbg8DkTw+" \
+ "MIwCAPKZUDoEgUWEfeCkoAQFJgmTEGUov0iCe1pGvYq9oaihtqiYo4DrjDhFcIV4IKZV2CuMEw" \
+ "yTBheDFNs7VUEBdRUwFTAHMGBaSthCCwAXucxF9fxIddjvjsOVqc6EPc6mGLYMgmoAAiYgfC6y" \
+ "DHXAcOiFsfUsJiqVjF9yBwEAACApje6qBEmAvI7gAkvXjmOxzsdeQKAAQBUUNbBysytJu3F1oh" \
+ "FdRXJMVcAAGC7PGFxhSQkBPJYgAKeXkcIMqqNlemmODCwEdsIO7BcFggFgw4oIuzQE4QadIjBy" \
+ "mC0xnhEg5BQBVsDh6JWC6oC5pYeM69hmNeBEQAAAB4JrdaYSBfbx+ys5DS/" \
+ "SGix57TsYPvYPTnN75qozqCqOlNZERTVJUqIPCezIGsMImlqDbVXjk54G8BQMRM3y4BiAAAAAJ" \
+ "BgiuzGvaSw2COcUPAsKgwQtVLFCAXMjE5kisGCZIk4oKgqJGEATADaK+" \
+ "JGBBRFi1B0EFqu6zGZD5yK7w5uMW46gNdkroOZTDjINWPlOCJ8jJ7ICHT17Ywa4pepioEgZozV" \
+ "BLVrVvUp6wihFEbP0BZBDaymyjQRIY4Wp6b5bo4ClmwhM8OlruXD5FvIACRHyKeT3e6EEYKKho" \
+ "TgnO3b67hOKQIAAPir3b0QhhICAL2E4x1zzGxcR0ZmBTL9qCxGrjFhjGgCiH2YOhgDKmJ1YtJy" \
+ "8xUAANWeUkgZSecbRxsRUxXt4/" \
+ "QEAOR4cVzHpw8fzDoAAADb26LUAxeXWn2M4NKBCQDoUMcAINMAGPK2yQOAifAxxggAAAA+" \
+ "KZ3VGs8Opl93kpyTI2xSuqg1nl9MnzetLicOuR+KTFRDGWR1VZCgOI+" \
+ "IyqoIMjIydNfoqBUj7I2ORdytWZAAAAAAwGcIFVIOy7IChku5BIQGoDEORyB5hHg+" \
+ "SUkMFpICMXcoMEXTghIlQiAUo4itMX/FEAJfOFaddCzcisxAVuDI5C/" \
+ "BAaNwbWSGqmY1Wuqa6qt1FdYsDuaCmYGZFZiZH9fr0GEiFBWq4Sm2NmJVe9c1lSEBFLg52NV2T" \
+ "DBO43HCj2fCdUyAE2rRWyCAs4Au9QQnccwQqfhskEkGAAC8ziIQui0wGgJE2NKnM8J13MkY5nx" \
+ "qwUfou6OV0d0LMDwVwLTgyyL+Ej+GKz80AAAAoBgiiJNi6+" \
+ "xj8W2q1alYxUCsgqc9uAg10OkoJT6yU6oYCBAAYHRFEAAAdAHQIgEUYbVPMI/" \
+ "NmPmU6jRQDKvLdYsxZgD+" \
+ "2FxCl2VHjIAbORGNzjnjs7IRze9PTPwQEyALiQoUlQGC2M8D6B4a2gDjkw8gOmOPvoGFmN5NSq" \
+ "wAZwIAAAAARqNG0ysYsTgPzUCEQgGPbxDyNMKwoAJQCIViREDcKiihCO3uEyIAGJRKChwPdciT" \
+ "pAyT6ODP5QiJiyJgGrSQVUsByq8mQcmUBD1LHlFhQrpERCgFAACgKRYpwNNkVKyGgGFYZTINPA" \
+ "7y4rThFo4ZOKTMgxkVJwwTmEy8gKIrjtdR1fV7UYEUARIDI0fx7TONAC3kxOjfGM6YmExpYh+" \
+ "EtSpleWO+1p6ziSjXSooCmAZA/" \
+ "okWJjoAAAAAjsdJSrFPZ2dTAAHABwEAAAAAAINDAAAHAAAASEashxh0/2H/Tf9Q/1z/a/9J/" \
+ "0P/Uf9f/1v/T/" \
+ "9ThxSNkAfKZZHcwvT9bk446gQtnFQwGkw88zQxMEa6wgUAkqSiKb0lYqgtKiLTxMTADHOsbcED" \
+ "Zm1ioq8n617fHM16LwAAGP0g1wOAGQAAAIBgyvQuAVIIB8Cnu8LjCWrwOJgd1o8nEhcDDFVkEm" \
+ "Kq86YqAF7ZPEBJ42J7xIdyju+ubB4gpYuL6ZUfSrWo+" \
+ "4esKqACKgURiahItg1YTZ3oE9W51Bx6RJw2sAAAAAAAh4LH03mEcIUcygFEWZbH53A5ABEh0qS" \
+ "IuCPOvgrZEaGFspgYAAAA8apAKteLn8K1JdekzFHpUjEH8HoG8EqmugZMOSBPYoTVU4suGL2ip" \
+ "YZOnSLCKJigBghq4LU5Mc2XyVgEBoYJxFL1LmksY7X1I6CYFsMYVG0NW8Pega4AACMRJkZG6KA" \
+ "zYbN1aDvZDk9YDRMQJDKBcxkAAABeBJiTtSISAuEL3V2/caEUAD3l/" \
+ "cT1UdBtEd47CaATYAAA5l8C3vtLABCAOegkFk9j6hlTdRQagUCMdE2NlwJDRyUrsY6VUHkxOWW" \
+ "UhXnGcZ1uNPgARFboAyz0Xm8AEUyIY6K5L2MLIawsNgACDIT5kTIdGGJYLU5FRI2c7lWkCSTXh" \
+ "ZfVygAAAAAe6dxyPkcfmstFTnVHOrecz9GL5mElJ3s/" \
+ "kEUNkIGKskpQBEUlpuoa6ctkB+" \
+ "iJpjI24ngAYQEAAAAAIGDBYSgFjxIenwFLkJKEFFKyEmDhiEpApsXZAcUEDAbNgJQI3URYnAaH" \
+ "VAaDmQEAAKyObK1iUWeLTF92Dm38+" \
+ "BTCiyuP42LIMQ8CxzFzXMwTRh8B43Q5NIQ8eAWFwMzj4G2Ti8ZFcgAEJhetHNcZCRYI9QDUtFi" \
+ "nU7EiqhgCwKm3aABex8yDYzL7oYU4RkCNMhGxYrEaVos9FQGYAQCA4WR0qAfgdDoB6FmMw4gIZ" \
+ "yQLFdCFYdQDGP1+H0YYQQwdpqmK2IGlTAUwFzfkYODIhw/HNddjVWCxlDDXfeBI/" \
+ "VySEdFdiNTCAJSg6qC44iIrRUYLeidggE6tgQgAEAgXKCqLYm/" \
+ "YCDbiC1UrkEshOoDBAB7ZvIlUHHNQXOVBqCSyeRUlS140a3sRGvlAZk0yRAnVWVGKjAxRGUzdS" \
+ "Xmhh92Qk3iciCQAAADAY20asg7iCcEXgFCGAOpMEJBSMZtMMcUik45mOjVLZpwwcSFLOR6PB5D" \
+ "hjluXmVVDXg9mDnjADBNpgFl4XFytJEGCT8fkejw+" \
+ "JaNkARjcrYwzDoRHgk0Yh0RHKWW0ajhjznLYjSUxDK/" \
+ "Md8cFM0MXKMZBXYdrsGEGRFJXrfBtHac4g2oqhNWgTPAUAABOoSKElcjjIqkQADrgzYrqMop5Y" \
+ "Wcni7RSJtA6qrWegui9kxuENayEOC42dzyLXDABFtPO1NJABa37q0EHjB+yz5cgQ/" \
+ "QIT4ALk0ObCELMcSJEXRGM6/ZtpQi9AOPujcpbFJfpDRH/" \
+ "TgwthqkIhpMtGMZQUIlGULX6rZiuB/" \
+ "B6DADAIwBpEgCSVQgA3mi8+" \
+ "5gyE3Tt01gRGbNovLqUliao7dMwvEGNVYlItLlhmdt1UT2uMFGReNyARQjKAQAAAMQQ8GnrgM5" \
+ "huDEOGK4nLWBIuMItWURSVFZCEUI4DQBUXybOjpw6tBF7U896yhwn2j2K0c/" \
+ "EgAVcKxNWMI8Z3LqejHpVW1Eb5kjIA1NpqN7orXSMevC6HpNVSNFhAkmOMDnmw2sq/" \
+ "UVhZipwcYDSb2AIQtRV7rgNoFy3SCwwA6ZDahcFYXG347lwE/" \
+ "NVTKjELdYuy5eJm3qY4l8FBQH4JFyAGYWuKFcxn3INwMw1jBOGATpa1nunK8q03an3RC90jib0" \
+ "w40xMEZYUetcOt3odtA6OtIxwIXEzPyZogjSHCN2uJztxPSq73YIGD0cIjJhCG2ioxVogIUJjd" \
+ "a0ACgkxuyQamJrb7EROxsdVbUs9UwGyVu81z48Kq00ACCyiwAGQRgALGu8AwBeB+" \
+ "w0ZdKMjF9KFMjobjjSlMWkVHwqYRG+" \
+ "oagRRJK5xqaZ3l3eVElV6CyZESIkAAAAaDTKHTwifEIjQpuFoBBjMRFSEhWyoNz3CkWsM6Tt1A" \
+ "krFnvfzn7sygxqu08G9nYWBQtuLSEwxwXXaya6/RhaA/" \
+ "NiEvJ6VMqR6zoyrDbXU8UM2jHXY2vSp8w8HkcZWbTHTCYH/CZbYyBXjqpmwJbGhCGsXDPXZ/" \
+ "geTrtyUIbRJq2maeN/" \
+ "YnoDtYjFWuJARAXTAiscRzIzM6mUokaLBpWDa1QSA2zZdBksXOgD8CBBjihLH3ywlp4YFqqHd1" \
+ "owTlDjlIMArNJpSxgLKzw1Xo+" \
+ "B40U2ZqOcUSIKymQZqsdydKjwiaw40pmcRVqGTWEFlcIcGdYbQy/" \
+ "I3e4JY7MvDI1R2IuCTRVAt2uUAWLLjEhdpgurtZEItvq6sXWj03snCRNW2g/" \
+ "NADYxQIRnpQAp2w8sFGEJ2WP0SjsJAN43nH1J4wAW8NA3nH1JcQCLAjwcmQuCgKkyttcuKZeoi" \
+ "SASUiMIAAAAZDERUQoolxNikjQtzhCnQIEIBJRoOaGIf3vTfgYnJqzTWWY6zUSsjYOvKuD1sXi" \
+ "Mqslr0rhIOK7jRlgkVGcYsTos+LAwC+" \
+ "qMAByG9kcbIojamYKhIipOY3yEt3gAxzETJvmUueY1AwDXNeSYydGCa5hDy+" \
+ "uqvSlKG6jYmIYVcwSO48U8hmSYyZGRHhdk4y2ZYCJRIsfoaYQHAyMeiAQ9nKsI8oY4kxOIEILQ" \
+ "lVBQY0BAAoD2m4uIbsWRIxc8gWu0myBaGsUowfXXk9BX+" \
+ "4kLKYIBTgM4hYGO6p2WDgEkxlCnjkSve+O4tAkAABL/" \
+ "7dSQZsbc+VZbCbmdQasaeBENAOj3GRMZALlKJByPAADUxM5qihoKQGInJgBgbHkCKAB+" \
+ "N2wpBh7I6TIXTuZu2FIM4oEcLnOBZI7MYJGnNDFVjZWuVFwkZopbDBIAAEBETFzoQVOgaBYRCI" \
+ "WUqDglIhCIiFIUEaXERYmIOrCooPZWbB1Xi+t6cOV6HC8CIS9mQEyhbhzjPWOooTC5Ji+" \
+ "YmUxYh4aCBgzRGwpWmaoAouDPdxlEGEON+e4gmXBdjFoEQgIkTl1yhVpFckb2CEl0Ou/" \
+ "IHOERyAwh1wWZDwckTKQEIKz0pgQAAhMbGQowUgZiBkm+dz0ACaxoLwLBIfVO/" \
+ "fUyIlhWARrJjayiTyIkXIDOM8K4/" \
+ "GFyE1ZgVqblQ11wSfg4M55AR51jYoTpcXIMUb91xI7QoQdMJPrHBGijj3C08L3YETVl0OeA/" \
+ "F0BAGAYHAEAsxkwjwtmZgmAFo/" \
+ "rMdasMTEBZ0xMoOi9gMjhpwBIhfUCnjccaw1yguphjce84VhrkBNUD2s87WbS2rmqq9vJ2BWHZ" \
+ "cYNAgAAAECcmaJEaZpFxIlQTCwOsbU4YWOxmo7ZGAaO4RA7MR1XHKhptcWwE1OcUDHFVDFU8Ch" \
+ "cXMSYTISxqEdEZFuFhLxORS4UKnBhdFFQPYWbkvl0XJnM5DrgMTArTLgCB7wyAJMJCwUiNtGFA" \
+ "RwcBObT8ZjAXKBdOebT43Vdr8eHTy9gyAUXGeb1AgLXxKHTh791tTphShMRY6VnND8VJ6I2gWm" \
+ "E5vXS2IRGRA7G6Pplchz9iRiatbSjQw/" \
+ "o9RG0BOPhJt+" \
+ "EXHNrC6QCXPMCIEOYERci0McYOkaI8f8OROg4CHSghUEXiAC1VNB7E0rHWXV0GBecjhRMgPYsP" \
+ "Z+" \
+ "tXz8AAORpKHpnRgT4PxUCgdaFLn1bfpig8MvGGe4AAICpXi8pT3291qQDAAAJPjeckw9mQbUYE" \
+ "jKGueGYYpATxLywPV+" \
+ "qRESUEBkZ01Rd7ZVLrBNmEzsAAABAMpGQzAxIFpItToiNvYkVi42TDsWBGuKEwDgMtoZjlolJG" \
+ "9/leqTFu/" \
+ "hYLbhrsDUFi+" \
+ "2gE4PqNFSm66oco14twjpVYgIJx4MrJ4Jc64CLFRzHXMnA6whruS7CDNerpnTwllKYBMhkOkAf" \
+ "HdGKQDgOXoRg3UuvCqomZ82ka2hluODUte/" \
+ "mQC3fQSZMRKaKIioGQ2O1qNbYwNDtG3YREyAASUQxmggzACoi6IUk74JHXC4n0XlE1ofNBcawX" \
+ "B/jNOd76rjxMMSt30R2vaduv/" \
+ "TDcquhxZXaMUwyR3gRYoUAR0fpACapOgZjAMCCkyAl47SOQlQX9UbPrclh/" \
+ "sCJYACWn7Vu7Pf71cnkAQDERfpnLAC3RVrsh0GH98kRxlNG/" \
+ "F1AN2RXSareh0aDAAwvaVKAkwA+B2zFB9EghsWC5zlgKz7QQFjA87EHkLpzR+" \
+ "7Estuuq7vCLnSOscwcAAAAQNFCSYHAJaDFaUlKICYQgxBi4mJiAC1K0SIQZZoWJQIxlEOMiNC1" \
+ "3a7A8I+NjcWwtZRD0/HpuI5MjvCaYxg4dBhVTIVN77SlMy69/" \
+ "gbXoF5YyVxpkRz5hYHAXCThINdxMDwSLua4huR1JJCoMxiknUEnYOUAhrXVOLi45jWTj7HFNWG" \
+ "OPGocAzOxMrN0DWQCQxi4eB3HxQHizLNywJKAOo0nkdKAcek9a+" \
+ "ttYcQ2wQI3wwAAxngnwSoMHDMzxytkDIWprhvO99dwNHc6vccsXRczx8wcr3VjHLH1O0rtnxB6" \
+ "3sscGhAXHdCDtHtPCXQMhFAn0QGI7FSPk6M2dPvdgVupidB5eFdkq9M3Af3YoJt6QJKOEHCyp4" \
+ "ABq0sII8C1Q+" \
+ "oi6RwPj0SuwCfI9SIAHjcsqQazIHoY4SluWFILdgJe4OmYEAgOMxwGCEBXJ00nhuOkkokbJAAA" \
+ "gLioCE3R4hRhSgChi4iIikiKijBFCcULJhCKCsWZiHCFuyjEiZAZbpQog1BgIiqkaQrPKryGa8" \
+ "gVjrwIk4thgCRzzU1UbWxsmocJkPBccekpoJQfUUgIrCJK1yk9gMl1RXL6MHoD4hkVjHNFYYWB" \
+ "ImpdNILVUdANYbGI+S4P2CBj5PV4MNdk5mBkIDBoTLOmTfR/" \
+ "pze6Rpu4rWPwyMAMMFGnii7jVkOCYBUlMpGNNxPDCEx3UUfOMMzxmg6xYM4viYQWQykoCaVMMW" \
+ "uMD+l9GL8jtYx0wEVIS4uhGUJP1gZCCIOOoEVYDRgyr5mZURKJDkIGPkPr/" \
+ "shgABdMKPorPG8xRIFWCmF7ROs1NMAwwbswp35SMgl5wpgBw3y5frcAAO5RAZ42TC7GyEOjj5e" \
+ "lNLKHtGF0MYgJurhaF03q8a7OShARqchMZ86cOU81OVd0V6mYjB6K5RGQAAAAgCQ0MEsI6sIFK" \
+ "XDJkiIiQtGKifLpycL/" \
+ "qdOjOVkOjLR3Nm3sdq2qatnFV4pTUdT00l86gWIRFNTE9QjDjIIwSbByTQ4Yrhz13GmBQxfhFA" \
+ "RxAkVQVBW5rr8Q5mJWt0LlxBSWFpSZXMegNPNiDoChel1lNACvYZjjmgDHXA+" \
+ "g0ooMHEamoYDxMsdMFsKnUEPH3DbR6PXRFLpI5gAqkWRQwcBwyjh4FJjjQ0NGWCyRO43sAacOQ" \
+ "7ikYB1UbzLJKxNGI1zXdjAwsE9nZ1MAAYA1AQAAAAAAg0MAAAgAAABdaUsxHF7/aP9I/1T/" \
+ "Zf9o/2VCaGv/Yf9P/2xFSERse/" \
+ "9GhzM8e5fRoM+b5OAGfAv2HQqqOog9JsfCj3TjREdf7JhGeAIAhCGAs/" \
+ "3wAwAMjwBAC7pdHQBPIwHifACATdHdiX4sBayk0G+" \
+ "19VdyEWOOLXK8AdCFWC0f5wAAFOAfPgesvcRQqFgV4CluWGoKTKAt4Olup2ZJIMvISBlWHnO50" \
+ "fWUcDoWmck5igUAAHBjumQpndi5qSAu+" \
+ "2RKnKK5XMzEtEIg06kf66Tfx4ZMz1Q3nfoNprOHC5h+kTtLFaUxhFFYm89qYmLZhKF+" \
+ "h0YQywuvFabB5JphZqURU8W0hjYqiF4fhyuXnXqXdRZMigCBCwaGzNaIAWzlgAsmxxwhU1H1uO" \
+ "PC4qUaPWDxURWwBwS/" \
+ "g0sFv5AE6KC6KF8Anowg3yMtWjA6qg8HygEwOinpdrtjYsJgSEGGwEiqi3IwZ4lsKElRsRDvAs" \
+ "YKwBXmtBk2tbC0ZY1ZXUuPMGGCqMuHp1XHDX3UoC+" \
+ "UX9zoGRB19DemuhXgYyIYihW3GykLE9z3UsNEbUEMd2aKFXC69HrP5n+" \
+ "s3moUYlwUXA9esFLvXI+" \
+ "v7UVde0fwAADUYjKA2KsJGswMFQ6tBX4CAIDMl1N4z1MAAAAqGQCeNvSuBCZgBU9pQ29KYAJW8" \
+ "HTXUsoUGSgzDWbMXKnQADGacdErikwJSAAAACmYiEERUkZJEKmgIFrG8BYsrgIqQQkpiNIQgoW" \
+ "EOCLKMNX0b2NvYzdV1M6Yzr8gIogDm9ZCTfOJmZCo5RaToSEpnI50Do0jQ4mLuCwweuqE3iPz5" \
+ "Ua1UONIruPhDfWhHowMniJMJIs+rNc+UjRohCNPrtYiRLGxmphYta2KPYNxwqnz3BAfSR8+" \
+ "r5vo6BH7ITRKPJgMw55pYxAjtzXdYUtYOUlsOwEPjisZOGZGwknTpdBIFnEBgxW45kCnII+" \
+ "JFgUAnjHMZcoLGIfUpWMggzitIVayXObeOyO49pfWMeKET0sAIgghvjs5ZCDUqW+gI3QB/" \
+ "jrBrcgBIbaerbWY0DEmnJkAACsA6Q2wJcNud1FAB+MQ2PmwhiVkBQD+NuwxBjlBVy+" \
+ "j7elt2GIKLKj1Mm3PhwmwYs6ws1cd1+" \
+ "biUjKOMTcBAAAAREXFKFEWEQhFaTFaBJSYQCgUF6NoAYQiFSIQMQ2xsdpYbKyG6ZitgTqy2hoD" \
+ "ajVtNXyZExYfJhjcFq4Lo/" \
+ "YiBlAwCmXUtWSuDFcmjxkh3iCUEHPG47pIAklUBSbXQym55pSOaBgbYtG7XNUnRN7O7SOot4ek" \
+ "OJjHycaH45rJ9el6TUKMIRfMNa9j7UEIugkBwgdrlTEJYRh3hgQCD4C8DjJkVrjgyFqiixylBs" \
+ "4ImGVZRFhpqC6Kl5cybwTJ9CQi4zJOajqANYToGaqJAyAMYQv4ZU64M3TrKELHDYHpidhtgTtW" \
+ "IXgAIGtHONjqd2vVRwIAxlAAoETnLWCKxCC6BXQ6AiD0RyBIkQkCFgCEsoTQB6ByY2wrkAmgTS" \
+ "bzumo8bcity2wT4AC+" \
+ "NmwiBbtMOg9jeF4DFuGDaSY1Xmw7gN4VKgAiIImU2zEBU1XprrhOwmYsdiAAAAAwRvhcDpfyKB" \
+ "VwuVyGAEIxoZtvQjdJAcTFBOI+" \
+ "EXeVSm5lLkogpKUeVnjkuq4Xx3XMmfD6cByzWonS8RjBIqCjq7DAgCNhMoEc36xgMsRFIsLKKP" \
+ "ABCwEADqUu0oP3cKhH+AxA7IjucHffIRFg4FKYTBgeUo5LzMp8un6P4+DDIzMcV+" \
+ "b6njKB2nfHGmABk0G6XlgwAHYKHxFdz/" \
+ "fSgoOFxpQsgHJPDqlT364nHBXXEhvHAVOlBMObCAfXJsNEW8VNDAHgCtVHTXsYoyNh9EQPco1I" \
+ "16PfOos28UYwlLBMdP7qnBTAba2w25wMGRTd9jxoW/" \
+ "0LD8AQqtcXKXDqIYsjEgAgwm+MIGhxJJ1HG0DH6KIA2l5GaCOGjt+" \
+ "N4E7qRgZAqCsiwrsQmRFAyDNdM8DlOOZeAF4HXLwLphj0eSFne64DTjFFZSLq46XIYvB0V0RVC" \
+ "aQoInfFkLNLOVeVuE4sZjIHEgAAgJmVkBAkHRwAgZhAjJZKQGZHjBrIgPHZFvNMi8W08cHq7to" \
+ "oZ1/" \
+ "bnTplsEyvk2IyOF4CJZFLDV+" \
+ "EEnDwpfTQqs3eexZGggtd4arG4ZXxXqLMWaquTbRJGLJIb4YBdM5L6XJGxOkrcoVDLqaKnKmDH" \
+ "FHHLfYMDEjmhCAXr1TKkXkC1Bi0F5CwRsd0gHoU2T6dggaYyJ0ALvh+" \
+ "3QpjABFwHKuw3wDovfPSTREWXBdhIe6UxALG+62jzGeQ04qVOSgC5EyahRCl+" \
+ "cENZIZrYG6lHFm03BczCsVIO1pS9MNEh81Dp2s3pv/" \
+ "aE7kJo25ZBeT4pml0gTAuF5abHe19EskfAfg+TDuffRgA0NuiuNGEEfjlebmjrE5hN/" \
+ "cBZ0I8SQ9wOket640+" \
+ "FiaiT859USQNpVU8JMgANjZ0ySTjIuACT2NDF10wIxAe4OmuqqEylFkZFVlGWZWZu4c4t1gptZ" \
+ "WpvK6EUyUWkdlBJAAAkMYshYwaHkcRRTlLGAIx2lOCEiyniUAgaW6iss8SZevVSrr1uvIalYvh" \
+ "V+H6XY/" \
+ "5I0tvxe+4vskAmWsh9R3utFYXWR+yB+" \
+ "K9uTrjhI3Oul6dRKRkRhSxyOgsOYim6ruDEAioHRctK3dGQkYZjRPLZiPqbsZ316ha6WtSm0mL" \
+ "82GyBnN3TMBMVDHJwJEhOWK1MnARAw4K89uYGQDEI5TonZ5SXRgAOgpG4TLE0kk9YJHApSNw9j" \
+ "A9nTBSHL4Sa/TBpHTpQupIdUSoM3JIT6NvLJm0AteV/" \
+ "JgrQ2wAHWGSQLgVkDAMlPbqcuQyI5oG1LsXYDxvADWwilwj7ST6RgPMyhMDFAJcSDO8Y4LuqbU" \
+ "6XS7ekbjouHmmAwCEugMAAIy/" \
+ "DQA89rVFBlDIcLKVgAVc+UQCDBfOqdq7+" \
+ "gkMSOAcdf9k1ZIZEcwrIRkwtMikFa8WOYBv3mUY9FGF9KsIEDiMDnUkmd2DmqD1wTAcH/" \
+ "LhFQCs+STkJIWbf+" \
+ "i1noRUk8LNa4RaNStrliIy7ZmnJZ6KioqqiuB2ZkveACC5lSARpEUIHQGhRMBlROiLPgrqdPjo" \
+ "gN2JQIRiBgD4pYZpa2+KQ78cs9rMZCZTzafreLRabNW0cYBiiMDvAXwBBb2KvZavEyjk+" \
+ "wIKepX0LF8nqJBv1ayhrChFxNjsdKRpGaG6jIzMVEZlDWUEIA3SdddcSYkTWjQFFAsYTACQKMZ" \
+ "O1oqYJ2Tbmf3GdFJMw960FYemjWlBDQeOY1htBFARwV4cDQTZkZIIGjYUGgX/A/" \
+ "21UBF4jsKEUhJBf2C5eioYLxB6aqyuijIjK7I6iojILMuK6pBFBuw74jgO7aoq9BbPbaS4GiAw" \
+ "EgAAkGBJxEzEIEkEFoIhIKWQDAh3SuiC0KHdxMTFhAIxOLJV1wQMW8PE1vTl9eEZxxxhrmMbrx" \
+ "/MS0UeK9xSwuXSMUXQbhgycx0Mp3Tw4ZUwD2ASItldCUp1C2ktjhwrXjxkUcoMBh08CsMStQIZ" \
+ "nQDIizFhKHXoMJJDBhc8JcQT4vVOC2F1PQgHGRYmpBsjY2hA5nER5rjCVEuuFwGYXKPfDyEIWs" \
+ "TohzgCHVjWMyIk478QRFHTYme1mKYgFluL1dZG1c6hYczUsDHf5dN1VmsPXhcHr2EeA5ODQBYp" \
+ "wngdgH4bQXdo3T66QMAEwshJAACEwyJ1Obi+" \
+ "zPXg03G8clwLdelg6Z2hrgBcj5UOXvn06XHleAsAAIAMAEkAdyjABX42lE6HPoLaZ1POlTwbGi" \
+ "dCjaD2kZwr+" \
+ "Q4VkQA4ogN7WiemLlehh56ejBAssocIkyQAAICQb4yDR8GCoeAR0CK0UITQRETANGFRyG7sC9x" \
+ "lSkTSjRIQERG1ADaIvxETVfXU8GMKID6iYpp4BMIlKmBQuH4TQBuSNXhFbSCTSTLkwyMQwszMg" \
+ "o54Z0R0hpQ0AZ0OnuIiw29a8ABmGNJkDg4e4YTeqbNokeh0xmnC5y0gpJ5Bj1BvPs11ZEmzJMb" \
+ "z0G0v3YFhwKJTTyIc6kOJq+d5GOFVDZiECVpHgA7oATQoo97QCBCXHhkmB0wy5NMxJK8Pr+" \
+ "QKcxw1bQzDtLG3KFZMBXkNC5lkEljwgBMUGFoAAMYagAkmIqDbIQCEgF8Ljhzp0RE2AwAAbSa/" \
+ "ZIXJfHMB83oRAAAAafi2AExM4JxtN/" \
+ "DESd8CtKpCoqoscAA2BjReBHlA7Dr+" \
+ "HNEY0HgZmCD2ncGXE7prqIrKSFkZkRk1tW2cs2HvdjbD0cRyrq2T6rCxiakgAQAABKQRJAlmkk" \
+ "JAKBAVF5cKZFFxSkwoTmgxIRGAZjEKtCglJipmY2uLrWKI/" \
+ "WiYtn7Zy+" \
+ "tWveCVuSbHdTBz5XjNdT2GZpl8RujoCNPweHEwMGGYzMzxLEshzDGZLImB15OIsBEYhvB5gsDM" \
+ "EeAHiGJoD07S7dBLmNetmMcpkSOvJGRmuOA1gdKPvI4jMzw+" \
+ "HT2BsUB1ZqLRRh6A4eARZq6FAN8SsJ4ajPLrBOBC54kTicW7LXMgsZANqjM90+ucyIQE+" \
+ "H1DFQcMemZmH4mh9q0wc7wmU+kDx5UXMQVggMzpNHovTChAe/" \
+ "EA6feMuge9d3rJlADvHSxK6Mpo0EYgjT+" \
+ "lN4DLlZ4t1YUZJwBdgogOevvBVmv29EsXHcYEAIb4qOJcu5TvtVOAaYiBALGE0ykWcDNs+" \
+ "VALJFMcp9F1Fk+" \
+ "wwJmi2BpdTNSsUUrBItgBxJ6CAOCx8ID52yQZjpnXdV0cwlCG2DCmqaY9hnRcJ6cWSr8wmTurP" \
+ "gl89cRIzKBFcO739eUTHFGDJuXU77q8qhII6hA6APgEAp6Qo7xFV495hVEj1zVWI5KLtbUbJY/" \
+ "jlQdd0/" \
+ "cyGKjgGIbvhVNcCwBs+" \
+ "VDDUEANE7nG1o6SDAnUMLFTeVERQTLhCAcQMpQPwmGZLNoaoa4IXSj0kbpjcmOkR7ggzG8dydA" \
+ "bPgixyHjNx8yaACT9fEbDNTnZ7ZPPa0FWTGfW00NVR9TbZtbUtiluzGZGAQTQv7AkEoSmiIebh" \
+ "zhAIABlEHq60XRvRYQoY0q0EDOtDqfMqPamA79tpsPWCccc88ehQ6ti2Nk4cGTnt8UUtbWO9j5" \
+ "WHEdmHh+7C9wIRcbudjS9CXjM7kaocWm3CfsmIKfZpvtHUVaURZ6uy8pxxLmzR5SEHNsXspeo+" \
+ "DDzw4x9MaFSHm6tIyWiFempO9P2dtOMiWnTObTzx19O+Msvi/htb6NqsZ/" \
+ "O3s7eMiJWj9dTFq5AEM9w6Lh/X076mm6aA9sCSIoJAHo13PxwXzBABvcU8c/" \
+ "u7iQHUUTgzNM0Wo1dlmJRzDKZSAAAAAAwJwLO5a/4yl+5v++H209u/" \
+ "94v13Pn59nDcvtSL21xLUpndfvy7VA5//" \
+ "w4f27LOL795PYo+f7974+" \
+ "SXupFFhk591zTOL79eH98nts4eItR07Oe9axnPeuZE0CZ27tPW1u3OzOKit91rOe+" \
+ "1K7jFmVbZRyPx0AxaDGNyYnJp/7+eXL7yaB/9H/Pku1wvejpgenJsPvz+/" \
+ "+mrSgjkevxerzVlbPImoxrYbKeY8BJsnrRY89KMmG12IoUvs3b7eanpycFiVHdouYWg8lsNmt1" \
+ "FS+33+9zIiFVOq5jbU9nZ1MABYA2AQAAAAAAg0MAAAkAAACfd/skAWoWAKqz3++H+/" \
+ "T0pGA6hrVD9XUrrc4zc3Nzc/r9sOZyIGq6bDnpYwKensDQ9y/" \
+ "K37+cAFtbW3TudhWOtwZzlstb/X5/a6vf72/" \
+ "x5+fm5nB6slBlZ3Fcha363d5ut7u3ni1rLoPf728l3KcK"
+
+namespace {
+
+const int kToggleCount = 4;
+const int kNumChannels = 2;
+const int kSampleRate = 44100;
+const int kFramesPerBuffer = 882; // 10ms
+const CefAudioHandler::ChannelLayout kChannelLayout = CEF_CHANNEL_LAYOUT_STEREO;
+
+const char kAudioOutputTestUrl[] = "http://tests/audiooutputtest";
+const char kAudioCloseBrowserTestUrl[] = "http://tests/audioclosebrowsertest";
+const char kAudioTogglePlaybackTestUrl[] =
+ "http://tests/audiotoggleplaybacktest";
+
+const char kTestHtml[] =
+ "<!DOCTYPE html><html><head><meta "
+ "charset=\"utf-8\"/></head><body><p>TEST</p><audio "
+ "id=\"audio_output_frame\" src=\"" AUDIO_DATA
+ "\" autoplay "
+ "style=\"display:none\"></audio></body></html>";
+
+const char kToggleTestHtml[] =
+ "<!DOCTYPE html><html><head><meta charset=\"utf-8\"/>"
+ "<script type=\"text/javascript\">"
+ "var timeouts = [150, 1950, 150, 2000, 150, 2050, 150, 2100, 150, 2200, "
+ "150];"
+ "var count = 0;"
+ "function togglePlayback(el, playing, count) {"
+ " if (playing) {"
+ // " console.log('togglePlayback pause (' + count + ')');"
+ " el.pause();"
+ " } else {"
+ // " console.log('togglePlayback play (' + count + ')');"
+ " el.play();"
+ " }"
+ "}"
+ "function loadHandler() {"
+ " var el = document.getElementById(\"audio_output_frame\");"
+ " el.onplay = (event) => {"
+ " var timeout = timeouts[count];"
+ // " console.log('loadHandler onplay (' + count + ') wait ' + timeout);"
+ " if (count < timeouts.length) {"
+ " setTimeout(togglePlayback, timeout, el, true, count);"
+ " count++;"
+ " }"
+ " };"
+ " el.onpause = (event) => {"
+ " var timeout = timeouts[count];"
+ // " console.log('loadHandler onpause (' + count + ') wait ' + timeout);"
+ " if (count < timeouts.length) {"
+ " setTimeout(togglePlayback, timeout, el, false, count);"
+ " count++;"
+ " }"
+ " };"
+ "}"
+ "</script></head>"
+ "<body onload=\"loadHandler()\"><p>TEST</p>"
+ "<audio id=\"audio_output_frame\" src=\"" AUDIO_DATA
+ "\" autoplay style=\"display:none\"></audio></body></html>";
+
+class AudioOutputTest : public ClientAppBrowser::Delegate {
+ public:
+ AudioOutputTest() {}
+
+ void OnBeforeCommandLineProcessing(
+ CefRefPtr<ClientAppBrowser> app,
+ CefRefPtr<CefCommandLine> command_line) override {
+ // Allow media to autoplay without requiring user interaction.
+ command_line->AppendSwitchWithValue("autoplay-policy",
+ "no-user-gesture-required");
+ }
+
+ protected:
+ IMPLEMENT_REFCOUNTING(AudioOutputTest);
+};
+
+class AudioTestHandler : public TestHandler, public CefAudioHandler {
+ public:
+ AudioTestHandler() {}
+
+ void SetupAudioTest(const std::string& testUrl) {
+ // Add the resource.
+ AddResource(testUrl, kTestHtml, "text/html");
+
+ // Create the browser.
+ CreateBrowser(testUrl);
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout();
+ }
+
+ void OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
+ browser_ = browser;
+ TestHandler::OnAfterCreated(browser);
+ }
+
+ CefRefPtr<CefAudioHandler> GetAudioHandler() override { return this; }
+
+ bool GetAudioParameters(CefRefPtr<CefBrowser> browser,
+ CefAudioParameters& params) override {
+ EXPECT_TRUE(CefCurrentlyOn(TID_UI));
+ params.channel_layout = kChannelLayout;
+ params.sample_rate = kSampleRate;
+ params.frames_per_buffer = kFramesPerBuffer;
+ got_audio_parameters_.yes();
+ return true;
+ }
+
+ void OnAudioStreamStarted(CefRefPtr<CefBrowser> browser,
+ const CefAudioParameters& params,
+ int channels) override {
+ EXPECT_FALSE(got_on_audio_stream_started_);
+ EXPECT_TRUE(got_audio_parameters_);
+ EXPECT_TRUE(browser_->IsSame(browser));
+ EXPECT_EQ(channels, kNumChannels);
+ EXPECT_EQ(params.channel_layout, kChannelLayout);
+ EXPECT_EQ(params.sample_rate, kSampleRate);
+ EXPECT_EQ(params.frames_per_buffer, kFramesPerBuffer);
+ got_on_audio_stream_started_.yes();
+ }
+
+ void OnAudioStreamPacket(CefRefPtr<CefBrowser> browser,
+ const float** data,
+ int frames,
+ int64 pts) override {
+ EXPECT_TRUE(got_on_audio_stream_started_);
+ EXPECT_TRUE(browser_->IsSame(browser));
+ EXPECT_EQ(frames, kFramesPerBuffer);
+ got_on_audio_stream_packet_.yes();
+ }
+
+ void OnAudioStreamStopped(CefRefPtr<CefBrowser> browser) override {
+ EXPECT_FALSE(got_on_audio_stream_stopped_);
+ EXPECT_TRUE(got_on_audio_stream_started_);
+ EXPECT_TRUE(browser_->IsSame(browser));
+ EXPECT_TRUE(CefCurrentlyOn(TID_UI));
+ got_on_audio_stream_stopped_.yes();
+ DestroyTest();
+ }
+
+ void OnAudioStreamError(CefRefPtr<CefBrowser> browser,
+ const CefString& message) override {
+ LOG(WARNING) << "OnAudioStreamError: message = " << message << ".";
+ got_on_audio_stream_error_.yes();
+ DestroyTest();
+ }
+
+ protected:
+ void DestroyTest() override {
+ browser_ = nullptr;
+ EXPECT_TRUE(got_audio_parameters_);
+ EXPECT_TRUE(got_on_audio_stream_started_);
+ EXPECT_TRUE(got_on_audio_stream_packet_);
+ EXPECT_TRUE(got_on_audio_stream_stopped_);
+ EXPECT_FALSE(got_on_audio_stream_error_);
+ TestHandler::DestroyTest();
+ }
+
+ CefRefPtr<CefBrowser> browser_;
+ TrackCallback got_on_audio_stream_started_;
+ TrackCallback got_on_audio_stream_packet_;
+ TrackCallback got_on_audio_stream_stopped_;
+ TrackCallback got_on_audio_stream_error_;
+ TrackCallback got_audio_parameters_;
+};
+
+// A common base class for audio output tests.
+class AudioOutputTestHandler : public AudioTestHandler {
+ public:
+ AudioOutputTestHandler() {}
+
+ void RunTest() override {
+ // Setup the resource.
+ SetupAudioTest(kAudioOutputTestUrl);
+ }
+
+ void OnAudioStreamPacket(CefRefPtr<CefBrowser> browser,
+ const float** data,
+ int frames,
+ int64 pts) override {
+ if (!got_on_audio_stream_packet_.isSet()) {
+ browser->GetMainFrame()->ExecuteJavaScript(
+ "var ifr = document.getElementById(\"audio_output_frame\"); "
+ "ifr.parentNode.removeChild(ifr);",
+ CefString(), 0);
+ }
+ AudioTestHandler::OnAudioStreamPacket(browser, data, frames, pts);
+ }
+
+ protected:
+ IMPLEMENT_REFCOUNTING(AudioOutputTestHandler);
+};
+
+class AudioCloseBrowserTest : public AudioTestHandler {
+ public:
+ AudioCloseBrowserTest() {}
+
+ void RunTest() override {
+ // Setup the resource.
+ SetupAudioTest(kAudioCloseBrowserTestUrl);
+ }
+
+ void OnBeforeClose(CefRefPtr<CefBrowser> browser) override {
+ EXPECT_FALSE(got_on_audio_stream_stopped_);
+ TestHandler::OnBeforeClose(browser);
+ }
+
+ void OnAudioStreamPacket(CefRefPtr<CefBrowser> browser,
+ const float** data,
+ int frames,
+ int64 pts) override {
+ if (!got_on_audio_stream_packet_.isSet()) {
+ CloseBrowser(browser, true);
+ }
+ AudioTestHandler::OnAudioStreamPacket(browser, data, frames, pts);
+ }
+
+ protected:
+ IMPLEMENT_REFCOUNTING(AudioCloseBrowserTest);
+};
+
+// kToggleCount represents the times the OnAudioStreamStarted and
+// OnAudioStreamStopped should have been called.
+// Both get called on playback start and end respectively. As well as when there
+// is a period of silence for more than 2 seconds (see
+// CefBrowserHostImpl::OnAudioStateChangedand and
+// CefBrowserHostImpl::OnRecentlyAudibleTimerFired). The timeouts in kTestHtml
+// represent play and pause timeouts. So for example it should play for 150ms
+// and then pause for 1950ms. In this example OnAudioStreamStopped must not be
+// called because it is below the 2 seconds threshold. So in this 10 timeouts
+// there are exactly 3 which should trigger OnAudioStreamStarted and
+// OnAudioStreamStopped together with the initial stream start and the final
+// stream stop. And due to the need to test the toggle bounderies it results in
+// this nearly 15 seconds test run.
+class AudioTogglePlaybackTest : public AudioTestHandler {
+ public:
+ AudioTogglePlaybackTest() {}
+
+ void RunTest() override {
+ // Add the resource.
+ AddResource(kAudioTogglePlaybackTestUrl, kToggleTestHtml, "text/html");
+
+ // Create the browser.
+ CreateBrowser(kAudioTogglePlaybackTestUrl);
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout(20000);
+ }
+
+ void OnAudioStreamStarted(CefRefPtr<CefBrowser> browser,
+ const CefAudioParameters& params,
+ int channels) override {
+ EXPECT_TRUE(browser_->IsSame(browser));
+ EXPECT_EQ(channels, kNumChannels);
+ EXPECT_EQ(params.channel_layout, kChannelLayout);
+ EXPECT_EQ(params.sample_rate, kSampleRate);
+ EXPECT_EQ(params.frames_per_buffer, kFramesPerBuffer);
+ got_on_audio_stream_started_.yes();
+ start_count_++;
+ }
+
+ void OnAudioStreamStopped(CefRefPtr<CefBrowser> browser) override {
+ EXPECT_EQ(start_count_, ++stop_count_);
+ if (stop_count_ == kToggleCount) {
+ AudioTestHandler::OnAudioStreamStopped(browser);
+ }
+ }
+
+ protected:
+ int start_count_ = 0;
+ int stop_count_ = 0;
+ IMPLEMENT_REFCOUNTING(AudioTogglePlaybackTest);
+};
+
+} // namespace
+
+// Test audio output callbacks called on valid threads.
+TEST(AudioOutputTest, AudioOutputTest) {
+ CefRefPtr<AudioOutputTestHandler> handler = new AudioOutputTestHandler();
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Test audio stream stopped callback is called on browser close.
+TEST(AudioOutputTest, AudioCloseBrowserTest) {
+ CefRefPtr<AudioCloseBrowserTest> handler = new AudioCloseBrowserTest();
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Test audio stream starts/stops properly on certain time bounderies.
+TEST(AudioOutputTest, AudioTogglePlaybackTest) {
+ CefRefPtr<AudioTogglePlaybackTest> handler = new AudioTogglePlaybackTest();
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Entry point for creating audio output test objects.
+// Called from client_app_delegates.cc.
+void CreateAudioOutputTests(ClientAppBrowser::DelegateSet& delegates) {
+ delegates.insert(new AudioOutputTest);
+}
diff --git a/tests/ceftests/browser_info_map_unittest.cc b/tests/ceftests/browser_info_map_unittest.cc
new file mode 100644
index 00000000..ef530508
--- /dev/null
+++ b/tests/ceftests/browser_info_map_unittest.cc
@@ -0,0 +1,712 @@
+// Copyright (c) 2014 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include <list>
+
+#include "libcef_dll/wrapper/cef_browser_info_map.h"
+#include "tests/gtest/include/gtest/gtest.h"
+
+namespace {
+
+struct MyObject {
+ MyObject(int val = 0) : member(val) {}
+ int member;
+};
+
+int g_destruct_ct = 0;
+
+struct MyObjectTraits {
+ static void Destruct(MyObject info) { g_destruct_ct++; }
+};
+
+typedef CefBrowserInfoMap<int, MyObject, MyObjectTraits> MyObjectMap;
+
+class MyVisitor : public MyObjectMap::Visitor {
+ public:
+ MyVisitor(bool remove = false,
+ int remove_browser_id = 0,
+ InfoIdType remove_info_id = 0)
+ : remove_(remove),
+ remove_browser_id_(remove_browser_id),
+ remove_info_id_(remove_info_id) {}
+
+ bool OnNextInfo(int browser_id,
+ InfoIdType info_id,
+ InfoObjectType info,
+ bool* remove) override {
+ Info info_rec;
+ info_rec.browser_id = browser_id;
+ info_rec.info_id = info_id;
+ info_rec.info = info;
+ info_list_.push_back(info_rec);
+
+ // Based on test configuration remove no objects, all objects, or only the
+ // specified object.
+ *remove = remove_ ||
+ (browser_id == remove_browser_id_ && info_id == remove_info_id_);
+ return true;
+ }
+
+ // Returns true if the specified info was passed to OnNextInfo. Removes the
+ // record if found.
+ bool Exists(int browser_id, InfoIdType info_id, InfoObjectType info) {
+ InfoList::iterator it = info_list_.begin();
+ for (; it != info_list_.end(); ++it) {
+ const Info& found_info = *it;
+ if (browser_id == found_info.browser_id &&
+ info_id == found_info.info_id &&
+ info.member == found_info.info.member) {
+ info_list_.erase(it);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ size_t info_size() const { return info_list_.size(); }
+
+ private:
+ bool remove_;
+ int remove_browser_id_;
+ InfoIdType remove_info_id_;
+
+ struct Info {
+ int browser_id;
+ InfoIdType info_id;
+ InfoObjectType info;
+ };
+
+ // Track calls to OnNextInfo.
+ typedef std::list<Info> InfoList;
+ InfoList info_list_;
+};
+
+} // namespace
+
+TEST(BrowserInfoMapTest, AddSingleBrowser) {
+ MyObjectMap map;
+ const int kBrowserId = 1;
+
+ g_destruct_ct = 0;
+
+ EXPECT_EQ(0U, map.size());
+ EXPECT_EQ(0U, map.size(kBrowserId));
+
+ MyObject obj1(1);
+ map.Add(kBrowserId, 1, obj1);
+ EXPECT_EQ(1U, map.size());
+ EXPECT_EQ(1U, map.size(kBrowserId));
+
+ MyObject obj2(2);
+ map.Add(kBrowserId, 2, obj2);
+ EXPECT_EQ(2U, map.size());
+ EXPECT_EQ(2U, map.size(kBrowserId));
+
+ MyObject obj3(3);
+ map.Add(kBrowserId, 3, obj3);
+ EXPECT_EQ(3U, map.size());
+ EXPECT_EQ(3U, map.size(kBrowserId));
+
+ EXPECT_EQ(0, g_destruct_ct);
+
+ map.clear(kBrowserId);
+ EXPECT_EQ(0U, map.size());
+ EXPECT_EQ(0U, map.size(kBrowserId));
+
+ EXPECT_EQ(3, g_destruct_ct);
+}
+
+TEST(BrowserInfoMapTest, AddMultipleBrowsers) {
+ MyObjectMap map;
+ const int kBrowserId1 = 1;
+ const int kBrowserId2 = 2;
+
+ g_destruct_ct = 0;
+
+ EXPECT_EQ(0U, map.size());
+ EXPECT_EQ(0U, map.size(kBrowserId1));
+ EXPECT_EQ(0U, map.size(kBrowserId2));
+
+ MyObject obj1(1);
+ map.Add(kBrowserId1, 1, obj1);
+ EXPECT_EQ(1U, map.size());
+ EXPECT_EQ(1U, map.size(kBrowserId1));
+ EXPECT_EQ(0U, map.size(kBrowserId2));
+
+ MyObject obj2(2);
+ map.Add(kBrowserId1, 2, obj2);
+ EXPECT_EQ(2U, map.size());
+ EXPECT_EQ(2U, map.size(kBrowserId1));
+ EXPECT_EQ(0U, map.size(kBrowserId2));
+
+ MyObject obj3(3);
+ map.Add(kBrowserId2, 3, obj3);
+ EXPECT_EQ(3U, map.size());
+ EXPECT_EQ(2U, map.size(kBrowserId1));
+ EXPECT_EQ(1U, map.size(kBrowserId2));
+
+ MyObject obj4(4);
+ map.Add(kBrowserId2, 4, obj4);
+ EXPECT_EQ(4U, map.size());
+ EXPECT_EQ(2U, map.size(kBrowserId1));
+ EXPECT_EQ(2U, map.size(kBrowserId2));
+
+ EXPECT_EQ(0, g_destruct_ct);
+
+ map.clear(kBrowserId1);
+ EXPECT_EQ(2U, map.size());
+ EXPECT_EQ(0U, map.size(kBrowserId1));
+ EXPECT_EQ(2U, map.size(kBrowserId2));
+
+ EXPECT_EQ(2, g_destruct_ct);
+
+ map.clear(kBrowserId2);
+ EXPECT_EQ(0U, map.size());
+ EXPECT_EQ(0U, map.size(kBrowserId1));
+ EXPECT_EQ(0U, map.size(kBrowserId2));
+
+ EXPECT_EQ(4, g_destruct_ct);
+}
+
+TEST(BrowserInfoMapTest, FindSingleBrowser) {
+ MyObjectMap map;
+ const int kBrowserId = 1;
+
+ g_destruct_ct = 0;
+
+ // obj1 not added yet.
+ MyObject nf1 = map.Find(kBrowserId, 1, nullptr);
+ EXPECT_EQ(0, nf1.member);
+
+ MyObject obj1(1);
+ map.Add(kBrowserId, 1, obj1);
+
+ // obj1 should exist.
+ MyObject f1 = map.Find(kBrowserId, 1, nullptr);
+ EXPECT_EQ(obj1.member, f1.member);
+
+ // obj2 not added yet.
+ MyObject nf2 = map.Find(kBrowserId, 2, nullptr);
+ EXPECT_EQ(0, nf2.member);
+
+ MyObject obj2(2);
+ map.Add(kBrowserId, 2, obj2);
+
+ // obj2 should exist.
+ MyObject f2 = map.Find(kBrowserId, 2, nullptr);
+ EXPECT_EQ(obj2.member, f2.member);
+
+ // find obj1 again.
+ MyObject f1b = map.Find(kBrowserId, 1, nullptr);
+ EXPECT_EQ(obj1.member, f1b.member);
+
+ // find obj2 again.
+ MyObject f2b = map.Find(kBrowserId, 2, nullptr);
+ EXPECT_EQ(obj2.member, f2b.member);
+
+ // doesn't exist.
+ MyObject nf3 = map.Find(kBrowserId, 3, nullptr);
+ EXPECT_EQ(0, nf3.member);
+ MyObject nf4 = map.Find(10, 1, nullptr);
+ EXPECT_EQ(0, nf4.member);
+ MyObject nf5 = map.Find(10, 3, nullptr);
+ EXPECT_EQ(0, nf5.member);
+
+ EXPECT_EQ(0, g_destruct_ct);
+ map.clear();
+ EXPECT_EQ(2, g_destruct_ct);
+}
+
+TEST(BrowserInfoMapTest, FindMultipleBrowsers) {
+ MyObjectMap map;
+ const int kBrowserId1 = 1;
+ const int kBrowserId2 = 2;
+
+ g_destruct_ct = 0;
+
+ // obj1 not added yet.
+ MyObject nf1 = map.Find(kBrowserId1, 1, nullptr);
+ EXPECT_EQ(0, nf1.member);
+
+ MyObject obj1(1);
+ map.Add(kBrowserId1, 1, obj1);
+
+ // obj1 should exist.
+ MyObject f1 = map.Find(kBrowserId1, 1, nullptr);
+ EXPECT_EQ(obj1.member, f1.member);
+
+ // obj2 not added yet.
+ MyObject nf2 = map.Find(kBrowserId1, 2, nullptr);
+ EXPECT_EQ(0, nf2.member);
+
+ MyObject obj2(2);
+ map.Add(kBrowserId1, 2, obj2);
+
+ // obj2 should exist.
+ MyObject f2 = map.Find(kBrowserId1, 2, nullptr);
+ EXPECT_EQ(obj2.member, f2.member);
+
+ // obj3 not added yet.
+ MyObject nf3 = map.Find(kBrowserId2, 3, nullptr);
+ EXPECT_EQ(0, nf3.member);
+
+ MyObject obj3(3);
+ map.Add(kBrowserId2, 3, obj3);
+
+ // obj3 should exist.
+ MyObject f3 = map.Find(kBrowserId2, 3, nullptr);
+ EXPECT_EQ(obj3.member, f3.member);
+
+ // obj4 not added yet.
+ MyObject nf4 = map.Find(kBrowserId2, 4, nullptr);
+ EXPECT_EQ(0, nf4.member);
+
+ MyObject obj4(4);
+ map.Add(kBrowserId2, 4, obj4);
+
+ // obj4 should exist.
+ MyObject f4 = map.Find(kBrowserId2, 4, nullptr);
+ EXPECT_EQ(obj4.member, f4.member);
+
+ // obj1-3 should exist.
+ MyObject f1b = map.Find(kBrowserId1, 1, nullptr);
+ EXPECT_EQ(obj1.member, f1b.member);
+ MyObject f2b = map.Find(kBrowserId1, 2, nullptr);
+ EXPECT_EQ(obj2.member, f2b.member);
+ MyObject f3b = map.Find(kBrowserId2, 3, nullptr);
+ EXPECT_EQ(obj3.member, f3b.member);
+
+ // wrong browser
+ MyObject nf5 = map.Find(kBrowserId1, 4, nullptr);
+ EXPECT_EQ(0, nf5.member);
+ MyObject nf6 = map.Find(kBrowserId2, 1, nullptr);
+ EXPECT_EQ(0, nf6.member);
+
+ // deosn't exist
+ MyObject nf7 = map.Find(kBrowserId2, 5, nullptr);
+ EXPECT_EQ(0, nf7.member);
+ MyObject nf8 = map.Find(8, 1, nullptr);
+ EXPECT_EQ(0, nf8.member);
+ MyObject nf9 = map.Find(8, 10, nullptr);
+ EXPECT_EQ(0, nf9.member);
+
+ EXPECT_EQ(0, g_destruct_ct);
+ map.clear();
+ EXPECT_EQ(4, g_destruct_ct);
+}
+
+TEST(BrowserInfoMapTest, Find) {
+ MyObjectMap map;
+ const int kBrowserId1 = 1;
+ const int kBrowserId2 = 2;
+
+ g_destruct_ct = 0;
+
+ MyObject obj1(1);
+ map.Add(kBrowserId1, 1, obj1);
+
+ MyObject obj2(2);
+ map.Add(kBrowserId1, 2, obj2);
+
+ MyObject obj3(3);
+ map.Add(kBrowserId2, 3, obj3);
+
+ MyObject obj4(4);
+ map.Add(kBrowserId2, 4, obj4);
+
+ EXPECT_EQ(4U, map.size());
+ EXPECT_EQ(2U, map.size(kBrowserId1));
+ EXPECT_EQ(2U, map.size(kBrowserId2));
+
+ // should only visit the single object
+ MyVisitor visitor;
+ map.Find(kBrowserId2, 4, &visitor);
+ EXPECT_EQ(1U, visitor.info_size());
+ EXPECT_TRUE(visitor.Exists(kBrowserId2, 4, obj4));
+ EXPECT_EQ(0U, visitor.info_size());
+
+ EXPECT_EQ(4U, map.size());
+ EXPECT_EQ(2U, map.size(kBrowserId1));
+ EXPECT_EQ(2U, map.size(kBrowserId2));
+
+ EXPECT_EQ(0, g_destruct_ct);
+ map.clear();
+ EXPECT_EQ(4, g_destruct_ct);
+}
+
+TEST(BrowserInfoMapTest, FindAndRemove) {
+ MyObjectMap map;
+ const int kBrowserId1 = 1;
+ const int kBrowserId2 = 2;
+
+ g_destruct_ct = 0;
+
+ MyObject obj1(1);
+ map.Add(kBrowserId1, 1, obj1);
+
+ MyObject obj2(2);
+ map.Add(kBrowserId1, 2, obj2);
+
+ MyObject obj3(3);
+ map.Add(kBrowserId2, 3, obj3);
+
+ MyObject obj4(4);
+ map.Add(kBrowserId2, 4, obj4);
+
+ EXPECT_EQ(4U, map.size());
+ EXPECT_EQ(2U, map.size(kBrowserId1));
+ EXPECT_EQ(2U, map.size(kBrowserId2));
+
+ // should only visit and remove the single object.
+ MyVisitor visitor(true);
+ map.Find(kBrowserId1, 2, &visitor);
+ EXPECT_EQ(1U, visitor.info_size());
+ EXPECT_TRUE(visitor.Exists(kBrowserId1, 2, obj2));
+ EXPECT_EQ(0U, visitor.info_size());
+
+ EXPECT_EQ(3U, map.size());
+ EXPECT_EQ(1U, map.size(kBrowserId1));
+ EXPECT_EQ(2U, map.size(kBrowserId2));
+
+ // visited object shouldn't exist
+ MyObject nf2 = map.Find(kBrowserId1, 2, nullptr);
+ EXPECT_EQ(0, nf2.member);
+
+ // other objects should exist
+ MyObject nf1 = map.Find(kBrowserId1, 1, nullptr);
+ EXPECT_EQ(obj1.member, nf1.member);
+ MyObject nf3 = map.Find(kBrowserId2, 3, nullptr);
+ EXPECT_EQ(obj3.member, nf3.member);
+ MyObject nf4 = map.Find(kBrowserId2, 4, nullptr);
+ EXPECT_EQ(obj4.member, nf4.member);
+
+ EXPECT_EQ(0, g_destruct_ct);
+ map.clear();
+ // should destruct the remaining 3 objects
+ EXPECT_EQ(3, g_destruct_ct);
+}
+
+TEST(BrowserInfoMapTest, FindAll) {
+ MyObjectMap map;
+ const int kBrowserId1 = 1;
+ const int kBrowserId2 = 2;
+
+ g_destruct_ct = 0;
+
+ MyObject obj1(1);
+ map.Add(kBrowserId1, 1, obj1);
+
+ MyObject obj2(2);
+ map.Add(kBrowserId1, 2, obj2);
+
+ MyObject obj3(3);
+ map.Add(kBrowserId2, 3, obj3);
+
+ MyObject obj4(4);
+ map.Add(kBrowserId2, 4, obj4);
+
+ EXPECT_EQ(4U, map.size());
+ EXPECT_EQ(2U, map.size(kBrowserId1));
+ EXPECT_EQ(2U, map.size(kBrowserId2));
+
+ // should visit all objects
+ MyVisitor visitor;
+ map.FindAll(&visitor);
+ EXPECT_EQ(4U, visitor.info_size());
+ EXPECT_TRUE(visitor.Exists(kBrowserId1, 1, obj1));
+ EXPECT_TRUE(visitor.Exists(kBrowserId1, 2, obj2));
+ EXPECT_TRUE(visitor.Exists(kBrowserId2, 3, obj3));
+ EXPECT_TRUE(visitor.Exists(kBrowserId2, 4, obj4));
+ // should be no unexpected visits
+ EXPECT_EQ(0U, visitor.info_size());
+
+ EXPECT_EQ(4U, map.size());
+ EXPECT_EQ(2U, map.size(kBrowserId1));
+ EXPECT_EQ(2U, map.size(kBrowserId2));
+
+ EXPECT_EQ(0, g_destruct_ct);
+ map.clear();
+ EXPECT_EQ(4, g_destruct_ct);
+}
+
+TEST(BrowserInfoMapTest, FindAllByBrowser) {
+ MyObjectMap map;
+ const int kBrowserId1 = 1;
+ const int kBrowserId2 = 2;
+
+ g_destruct_ct = 0;
+
+ MyObject obj1(1);
+ map.Add(kBrowserId1, 1, obj1);
+
+ MyObject obj2(2);
+ map.Add(kBrowserId1, 2, obj2);
+
+ MyObject obj3(3);
+ map.Add(kBrowserId2, 3, obj3);
+
+ MyObject obj4(4);
+ map.Add(kBrowserId2, 4, obj4);
+
+ EXPECT_EQ(4U, map.size());
+ EXPECT_EQ(2U, map.size(kBrowserId1));
+ EXPECT_EQ(2U, map.size(kBrowserId2));
+
+ // should only visit browser2 objects
+ MyVisitor visitor;
+ map.FindAll(kBrowserId2, &visitor);
+ EXPECT_EQ(2U, visitor.info_size());
+ EXPECT_TRUE(visitor.Exists(kBrowserId2, 3, obj3));
+ EXPECT_TRUE(visitor.Exists(kBrowserId2, 4, obj4));
+ // should be no unexpected visits
+ EXPECT_EQ(0U, visitor.info_size());
+
+ EXPECT_EQ(4U, map.size());
+ EXPECT_EQ(2U, map.size(kBrowserId1));
+ EXPECT_EQ(2U, map.size(kBrowserId2));
+
+ EXPECT_EQ(0, g_destruct_ct);
+ map.clear();
+ EXPECT_EQ(4, g_destruct_ct);
+}
+
+TEST(BrowserInfoMapTest, FindAllAndRemoveAll) {
+ MyObjectMap map;
+ const int kBrowserId1 = 1;
+ const int kBrowserId2 = 2;
+
+ g_destruct_ct = 0;
+
+ MyObject obj1(1);
+ map.Add(kBrowserId1, 1, obj1);
+
+ MyObject obj2(2);
+ map.Add(kBrowserId1, 2, obj2);
+
+ MyObject obj3(3);
+ map.Add(kBrowserId2, 3, obj3);
+
+ MyObject obj4(4);
+ map.Add(kBrowserId2, 4, obj4);
+
+ EXPECT_EQ(4U, map.size());
+ EXPECT_EQ(2U, map.size(kBrowserId1));
+ EXPECT_EQ(2U, map.size(kBrowserId2));
+
+ // should visit all objects
+ MyVisitor visitor(true);
+ map.FindAll(&visitor);
+ EXPECT_EQ(4U, visitor.info_size());
+ EXPECT_TRUE(visitor.Exists(kBrowserId1, 1, obj1));
+ EXPECT_TRUE(visitor.Exists(kBrowserId1, 2, obj2));
+ EXPECT_TRUE(visitor.Exists(kBrowserId2, 3, obj3));
+ EXPECT_TRUE(visitor.Exists(kBrowserId2, 4, obj4));
+ // should be no unexpected visits
+ EXPECT_EQ(0U, visitor.info_size());
+
+ EXPECT_EQ(0U, map.size());
+ EXPECT_EQ(0U, map.size(kBrowserId1));
+ EXPECT_EQ(0U, map.size(kBrowserId2));
+
+ EXPECT_EQ(0, g_destruct_ct);
+}
+
+TEST(BrowserInfoMapTest, FindAllAndRemoveOne) {
+ MyObjectMap map;
+ const int kBrowserId1 = 1;
+ const int kBrowserId2 = 2;
+
+ g_destruct_ct = 0;
+
+ MyObject obj1(1);
+ map.Add(kBrowserId1, 1, obj1);
+
+ MyObject obj2(2);
+ map.Add(kBrowserId1, 2, obj2);
+
+ MyObject obj3(3);
+ map.Add(kBrowserId2, 3, obj3);
+
+ MyObject obj4(4);
+ map.Add(kBrowserId2, 4, obj4);
+
+ EXPECT_EQ(4U, map.size());
+ EXPECT_EQ(2U, map.size(kBrowserId1));
+ EXPECT_EQ(2U, map.size(kBrowserId2));
+
+ // should visit all objects and remove one
+ MyVisitor visitor(false, kBrowserId2, 3);
+ map.FindAll(&visitor);
+ EXPECT_EQ(4U, visitor.info_size());
+ EXPECT_TRUE(visitor.Exists(kBrowserId1, 1, obj1));
+ EXPECT_TRUE(visitor.Exists(kBrowserId1, 2, obj2));
+ EXPECT_TRUE(visitor.Exists(kBrowserId2, 3, obj3));
+ EXPECT_TRUE(visitor.Exists(kBrowserId2, 4, obj4));
+ // should be no unexpected visits
+ EXPECT_EQ(0U, visitor.info_size());
+
+ EXPECT_EQ(3U, map.size());
+ EXPECT_EQ(2U, map.size(kBrowserId1));
+ EXPECT_EQ(1U, map.size(kBrowserId2));
+
+ // removed object shouldn't exist
+ MyObject nf3 = map.Find(kBrowserId2, 3, nullptr);
+ EXPECT_EQ(0, nf3.member);
+
+ // other objects should exist
+ MyObject f1 = map.Find(kBrowserId1, 1, nullptr);
+ EXPECT_EQ(obj1.member, f1.member);
+ MyObject f2 = map.Find(kBrowserId1, 2, nullptr);
+ EXPECT_EQ(obj2.member, f2.member);
+ MyObject f4 = map.Find(kBrowserId2, 4, nullptr);
+ EXPECT_EQ(obj4.member, f4.member);
+
+ EXPECT_EQ(0, g_destruct_ct);
+ map.clear();
+ // should destruct the remaining 3 objects
+ EXPECT_EQ(3, g_destruct_ct);
+}
+
+TEST(BrowserInfoMapTest, FindAllAndRemoveAllByBrowser) {
+ MyObjectMap map;
+ const int kBrowserId1 = 1;
+ const int kBrowserId2 = 2;
+
+ g_destruct_ct = 0;
+
+ MyObject obj1(1);
+ map.Add(kBrowserId1, 1, obj1);
+
+ MyObject obj2(2);
+ map.Add(kBrowserId1, 2, obj2);
+
+ MyObject obj3(3);
+ map.Add(kBrowserId2, 3, obj3);
+
+ MyObject obj4(4);
+ map.Add(kBrowserId2, 4, obj4);
+
+ EXPECT_EQ(4U, map.size());
+ EXPECT_EQ(2U, map.size(kBrowserId1));
+ EXPECT_EQ(2U, map.size(kBrowserId2));
+
+ // should only visit browser1 objects
+ MyVisitor visitor(true);
+ map.FindAll(kBrowserId1, &visitor);
+ EXPECT_EQ(2U, visitor.info_size());
+ EXPECT_TRUE(visitor.Exists(kBrowserId1, 1, obj1));
+ EXPECT_TRUE(visitor.Exists(kBrowserId1, 2, obj2));
+ // should be no unexpected visits
+ EXPECT_EQ(0U, visitor.info_size());
+
+ EXPECT_EQ(2U, map.size());
+ EXPECT_EQ(0U, map.size(kBrowserId1));
+ EXPECT_EQ(2U, map.size(kBrowserId2));
+
+ // browser1 objects shouldn't exist
+ MyObject nf1 = map.Find(kBrowserId1, 1, nullptr);
+ EXPECT_EQ(0, nf1.member);
+ MyObject nf2 = map.Find(kBrowserId1, 2, nullptr);
+ EXPECT_EQ(0, nf2.member);
+
+ // browser 2 objects should exist
+ MyObject f3 = map.Find(kBrowserId2, 3, nullptr);
+ EXPECT_EQ(obj3.member, f3.member);
+ MyObject f4 = map.Find(kBrowserId2, 4, nullptr);
+ EXPECT_EQ(obj4.member, f4.member);
+
+ EXPECT_EQ(0, g_destruct_ct);
+ map.clear();
+ // should destruct the remaining 2 objects
+ EXPECT_EQ(2, g_destruct_ct);
+}
+
+TEST(BrowserInfoMapTest, FindAllAndRemoveOneByBrowser) {
+ MyObjectMap map;
+ const int kBrowserId1 = 1;
+ const int kBrowserId2 = 2;
+
+ g_destruct_ct = 0;
+
+ MyObject obj1(1);
+ map.Add(kBrowserId1, 1, obj1);
+
+ MyObject obj2(2);
+ map.Add(kBrowserId1, 2, obj2);
+
+ MyObject obj3(3);
+ map.Add(kBrowserId2, 3, obj3);
+
+ MyObject obj4(4);
+ map.Add(kBrowserId2, 4, obj4);
+
+ EXPECT_EQ(4U, map.size());
+ EXPECT_EQ(2U, map.size(kBrowserId1));
+ EXPECT_EQ(2U, map.size(kBrowserId2));
+
+ // should visit browser2 objects and remove one
+ MyVisitor visitor(false, kBrowserId2, 4);
+ map.FindAll(kBrowserId2, &visitor);
+ EXPECT_EQ(2U, visitor.info_size());
+ EXPECT_TRUE(visitor.Exists(kBrowserId2, 3, obj3));
+ EXPECT_TRUE(visitor.Exists(kBrowserId2, 4, obj4));
+ // should be no unexpected visits
+ EXPECT_EQ(0U, visitor.info_size());
+
+ EXPECT_EQ(3U, map.size());
+ EXPECT_EQ(2U, map.size(kBrowserId1));
+ EXPECT_EQ(1U, map.size(kBrowserId2));
+
+ // removed object shouldn't exist
+ MyObject nf4 = map.Find(kBrowserId2, 4, nullptr);
+ EXPECT_EQ(0, nf4.member);
+
+ // other objects should exist
+ MyObject f1 = map.Find(kBrowserId1, 1, nullptr);
+ EXPECT_EQ(obj1.member, f1.member);
+ MyObject f2 = map.Find(kBrowserId1, 2, nullptr);
+ EXPECT_EQ(obj2.member, f2.member);
+ MyObject f3 = map.Find(kBrowserId2, 3, nullptr);
+ EXPECT_EQ(obj3.member, f3.member);
+
+ EXPECT_EQ(0, g_destruct_ct);
+ map.clear();
+ // should destruct the remaining 3 objects
+ EXPECT_EQ(3, g_destruct_ct);
+}
+
+namespace {
+
+class MyHeapObject {
+ public:
+ MyHeapObject(int* destroy_ct) : destroy_ct_(destroy_ct) {}
+ ~MyHeapObject() { (*destroy_ct_)++; }
+
+ private:
+ int* destroy_ct_;
+};
+
+} // namespace
+
+TEST(BrowserInfoMapTest, DefaultTraits) {
+ CefBrowserInfoMap<int, MyHeapObject*> map;
+
+ int destroy_ct = 0;
+ map.Add(1, 1, new MyHeapObject(&destroy_ct));
+ map.Add(1, 2, new MyHeapObject(&destroy_ct));
+ map.Add(2, 1, new MyHeapObject(&destroy_ct));
+ map.Add(2, 2, new MyHeapObject(&destroy_ct));
+ map.Add(3, 1, new MyHeapObject(&destroy_ct));
+ map.Add(3, 2, new MyHeapObject(&destroy_ct));
+
+ EXPECT_EQ(6U, map.size());
+
+ map.clear(1);
+ EXPECT_EQ(4U, map.size());
+ EXPECT_EQ(2, destroy_ct);
+
+ map.clear();
+ EXPECT_EQ(0U, map.size());
+ EXPECT_EQ(6, destroy_ct);
+}
diff --git a/tests/ceftests/certificate_error_unittest.cc b/tests/ceftests/certificate_error_unittest.cc
new file mode 100644
index 00000000..b6c82933
--- /dev/null
+++ b/tests/ceftests/certificate_error_unittest.cc
@@ -0,0 +1,521 @@
+// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "include/base/cef_callback.h"
+#include "include/test/cef_test_server.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "include/wrapper/cef_stream_resource_handler.h"
+#include "tests/ceftests/test_handler.h"
+#include "tests/ceftests/test_server_observer.h"
+#include "tests/ceftests/test_util.h"
+#include "tests/gtest/include/gtest/gtest.h"
+#include "tests/shared/common/string_util.h"
+
+namespace {
+
+// Used to observe HTTP and HTTPS server requests.
+class OtherServerObserver : public test_server::ObserverHelper {
+ public:
+ using ReadyCallback = base::OnceCallback<void(const std::string& url)>;
+ using RequestCallback =
+ base::RepeatingCallback<bool(CefRefPtr<CefRequest> request,
+ const ResponseCallback& response_callback)>;
+
+ OtherServerObserver(bool https_server,
+ ReadyCallback ready_callback,
+ base::OnceClosure done_callback,
+ const RequestCallback& request_callback)
+ : ready_callback_(std::move(ready_callback)),
+ done_callback_(std::move(done_callback)),
+ request_callback_(request_callback) {
+ EXPECT_TRUE(ready_callback_);
+ EXPECT_TRUE(done_callback_);
+ EXPECT_TRUE(request_callback_);
+ Initialize(https_server);
+ }
+
+ void OnInitialized(const std::string& server_origin) override {
+ EXPECT_UI_THREAD();
+ std::move(ready_callback_).Run(server_origin);
+ }
+
+ void OnShutdown() override {
+ EXPECT_UI_THREAD();
+ std::move(done_callback_).Run();
+ delete this;
+ }
+
+ bool OnTestServerRequest(CefRefPtr<CefRequest> request,
+ const ResponseCallback& response_callback) override {
+ EXPECT_UI_THREAD();
+ return request_callback_.Run(request, response_callback);
+ }
+
+ private:
+ ReadyCallback ready_callback_;
+ base::OnceClosure done_callback_;
+ RequestCallback request_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(OtherServerObserver);
+};
+
+class CertificateErrorTest : public TestHandler, public CefTestServerHandler {
+ public:
+ using ResponseCallback = test_server::ObserverHelper::ResponseCallback;
+
+ enum class OtherServerType {
+ NONE,
+ HTTP,
+ HTTPS,
+ };
+
+ CertificateErrorTest(
+ cef_test_cert_type_t cert_type,
+ bool expect_load_success,
+ bool expect_certificate_error,
+ OtherServerType other_server_type = OtherServerType::NONE)
+ : cert_type_(cert_type),
+ expect_load_success_(expect_load_success),
+ expect_certificate_error_(expect_certificate_error),
+ other_server_type_(other_server_type) {}
+
+ void RunTest() override {
+ SetTestTimeout();
+ CefPostTask(TID_UI,
+ base::BindOnce(&CertificateErrorTest::StartHttpsServer, this));
+ }
+
+ bool OnTestServerRequest(
+ CefRefPtr<CefTestServer> server,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefTestServerConnection> connection) override {
+ CefPostTask(TID_UI,
+ base::BindOnce(&CertificateErrorTest::HandleHttpsRequest, this,
+ request, connection));
+ return true;
+ }
+
+ bool OnOtherServerRequest(CefRefPtr<CefRequest> request,
+ const ResponseCallback& response_callback) {
+ EXPECT_UI_THREAD();
+ HandleOtherServerRequest(request, response_callback);
+ return true;
+ }
+
+ bool OnCertificateError(CefRefPtr<CefBrowser> browser,
+ cef_errorcode_t cert_error,
+ const CefString& request_url,
+ CefRefPtr<CefSSLInfo> ssl_info,
+ CefRefPtr<CefCallback> callback) override {
+ EXPECT_UI_THREAD();
+ got_certificate_error_.yes();
+
+ EXPECT_STREQ(GetEndURL().c_str(), request_url.ToString().c_str());
+
+ if (expect_load_success_) {
+ // Continue the load.
+ callback->Continue();
+ return true;
+ }
+
+ // Cancel the load.
+ return false;
+ }
+
+ void OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int httpStatusCode) override {
+ EXPECT_UI_THREAD();
+
+ TestHandler::OnLoadEnd(browser, frame, httpStatusCode);
+
+ const std::string& url = frame->GetURL();
+ if (url == GetEndURL()) {
+ got_load_end_.yes();
+ MaybeEndTest();
+ }
+ }
+
+ void OnLoadError(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ ErrorCode errorCode,
+ const CefString& errorText,
+ const CefString& failedUrl) override {
+ EXPECT_UI_THREAD();
+
+ const std::string& url = frame->GetURL();
+ if (url == GetEndURL()) {
+ got_load_error_.yes();
+ MaybeEndTest();
+ }
+ }
+
+ void DestroyTest() override {
+ EXPECT_FALSE(server_);
+ EXPECT_FALSE(other_server_);
+
+ EXPECT_TRUE(got_load_end_);
+
+ if (expect_load_success_) {
+ EXPECT_TRUE(got_request_);
+ EXPECT_FALSE(got_load_error_);
+ } else {
+ EXPECT_FALSE(got_request_);
+ EXPECT_TRUE(got_load_error_);
+ }
+
+ EXPECT_EQ(expect_certificate_error_, got_certificate_error_);
+
+ TestHandler::DestroyTest();
+ }
+
+ protected:
+ virtual std::string GetStartURL() const {
+ return server_origin() + "/index.html";
+ }
+ virtual std::string GetEndURL() const { return GetStartURL(); }
+
+ const std::string& server_origin() const { return server_origin_; }
+ const std::string& other_origin() const { return other_origin_; }
+
+ virtual void HandleOtherServerRequest(
+ CefRefPtr<CefRequest> request,
+ const ResponseCallback& response_callback) {}
+
+ private:
+ void HandleHttpsRequest(CefRefPtr<CefRequest> request,
+ CefRefPtr<CefTestServerConnection> connection) {
+ EXPECT_UI_THREAD();
+ got_request_.yes();
+
+ const std::string response = "<html><body>Certificate Test</body></html>";
+ connection->SendHttp200Response("text/html", response.c_str(),
+ response.size());
+
+ MaybeEndTest();
+ }
+
+ void MaybeEndTest() {
+ EXPECT_UI_THREAD();
+
+ bool end_test;
+ if (expect_load_success_) {
+ end_test = got_load_end_ && got_request_;
+ } else {
+ end_test = got_load_end_ && got_load_error_;
+ }
+
+ if (end_test) {
+ StopHttpsServer();
+ }
+ }
+
+ void StartHttpsServer() {
+ EXPECT_UI_THREAD();
+
+ server_ = CefTestServer::CreateAndStart(/*port=*/0, /*https_server=*/true,
+ cert_type_, this);
+ server_origin_ = server_->GetOrigin();
+
+ if (other_server_type_ != OtherServerType::NONE) {
+ StartOtherServer();
+ } else {
+ DoCreateBrowser();
+ }
+ }
+
+ void StartOtherServer() {
+ EXPECT_UI_THREAD();
+ EXPECT_NE(other_server_type_, OtherServerType::NONE);
+
+ // Will delete itself after the server stops.
+ other_server_ = new OtherServerObserver(
+ other_server_type_ == OtherServerType::HTTPS,
+ base::BindOnce(&CertificateErrorTest::StartedOtherServer, this),
+ base::BindOnce(&CertificateErrorTest::StoppedOtherServer, this),
+ base::BindRepeating(&CertificateErrorTest::OnOtherServerRequest, this));
+ }
+
+ void StartedOtherServer(const std::string& other_origin) {
+ EXPECT_UI_THREAD();
+ EXPECT_NE(other_server_type_, OtherServerType::NONE);
+
+ other_origin_ = other_origin;
+ DoCreateBrowser();
+ }
+
+ void DoCreateBrowser() {
+ EXPECT_UI_THREAD();
+
+ // Create a new in-memory context so certificate decisions aren't cached.
+ auto request_context = CreateTestRequestContext(
+ TEST_RC_MODE_CUSTOM, /*cache_path=*/std::string());
+
+ CreateBrowser(GetStartURL(), request_context);
+ }
+
+ void StopHttpsServer() {
+ EXPECT_UI_THREAD();
+
+ server_->Stop();
+ server_ = nullptr;
+
+ if (other_server_type_ != OtherServerType::NONE) {
+ // Stop the other server. Results in a call to StoppedOtherServer().
+ other_server_->Shutdown();
+ } else {
+ DestroyTest();
+ }
+ }
+
+ void StoppedOtherServer() {
+ EXPECT_UI_THREAD();
+ EXPECT_NE(other_server_type_, OtherServerType::NONE);
+
+ other_server_ = nullptr;
+ DestroyTest();
+ }
+
+ const cef_test_cert_type_t cert_type_;
+ const bool expect_load_success_;
+ const bool expect_certificate_error_;
+ const OtherServerType other_server_type_;
+
+ CefRefPtr<CefTestServer> server_;
+ std::string server_origin_;
+
+ OtherServerObserver* other_server_ = nullptr;
+ std::string other_origin_;
+
+ TrackCallback got_request_;
+ TrackCallback got_certificate_error_;
+ TrackCallback got_load_end_;
+ TrackCallback got_load_error_;
+
+ IMPLEMENT_REFCOUNTING(CertificateErrorTest);
+};
+
+} // namespace
+
+TEST(CertificateErrorTest, DirectNoError) {
+ CefRefPtr<CertificateErrorTest> handler = new CertificateErrorTest(
+ /*cert_type=*/CEF_TEST_CERT_OK_DOMAIN, /*expect_load_success=*/true,
+ /*expect_certificate_error=*/false);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(CertificateErrorTest, DirectExpired) {
+ CefRefPtr<CertificateErrorTest> handler = new CertificateErrorTest(
+ /*cert_type=*/CEF_TEST_CERT_EXPIRED, /*expect_load_success=*/false,
+ /*expect_certificate_error=*/true);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+namespace {
+
+class DirectMismatchedTest : public CertificateErrorTest {
+ public:
+ DirectMismatchedTest(bool continue_invalid_certificate)
+ : CertificateErrorTest(
+ /*cert_type=*/CEF_TEST_CERT_OK_DOMAIN,
+ /*expect_load_success=*/continue_invalid_certificate,
+ /*expect_certificate_error=*/true) {}
+
+ protected:
+ std::string GetStartURL() const {
+ // Load by IP address when the certificate expects a domain.
+ return client::AsciiStrReplace(server_origin(), "localhost", "127.0.0.1") +
+ "/index.html";
+ }
+};
+
+} // namespace
+
+TEST(CertificateErrorTest, DirectMismatchedCancel) {
+ CefRefPtr<DirectMismatchedTest> handler =
+ new DirectMismatchedTest(/*continue_invalid_certificate=*/false);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(CertificateErrorTest, DirectMismatchedContinue) {
+ CefRefPtr<DirectMismatchedTest> handler =
+ new DirectMismatchedTest(/*continue_invalid_certificate=*/true);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+namespace {
+
+class RedirectMismatchedFromHandlerTest : public CertificateErrorTest {
+ public:
+ RedirectMismatchedFromHandlerTest(bool continue_invalid_certificate,
+ bool redirect_from_https)
+ : CertificateErrorTest(
+ /*cert_type=*/CEF_TEST_CERT_OK_DOMAIN,
+ /*expect_load_success=*/continue_invalid_certificate,
+ /*expect_certificate_error=*/true),
+ redirect_from_https_(redirect_from_https) {}
+
+ CefRefPtr<CefResourceHandler> GetResourceHandler(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request) override {
+ EXPECT_IO_THREAD();
+
+ const std::string& url = request->GetURL();
+ if (url == GetStartURL()) {
+ // Redirect to the end URL.
+ return new CefStreamResourceHandler(
+ 301, "Permanent Redirect", "text/html", {{"Location", GetEndURL()}},
+ /*stream=*/nullptr);
+ }
+
+ return TestHandler::GetResourceHandler(browser, frame, request);
+ }
+
+ protected:
+ std::string GetStartURL() const override {
+ return redirect_from_https_ ? "https://certificate-test.com/index.html"
+ : "http://certificate-test.com/index.html";
+ }
+
+ std::string GetEndURL() const override {
+ // Load by IP address when the certificate expects a domain.
+ return client::AsciiStrReplace(server_origin(), "localhost", "127.0.0.1") +
+ "/index.html";
+ }
+
+ private:
+ const bool redirect_from_https_;
+};
+
+} // namespace
+
+TEST(CertificateErrorTest, RedirectMismatchedFromHttpsResourceCancel) {
+ CefRefPtr<RedirectMismatchedFromHandlerTest> handler =
+ new RedirectMismatchedFromHandlerTest(
+ /*continue_invalid_certificate=*/false,
+ /*redirect_from_https=*/true);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(CertificateErrorTest, RedirectMismatchedFromHttpsResourceContinue) {
+ CefRefPtr<RedirectMismatchedFromHandlerTest> handler =
+ new RedirectMismatchedFromHandlerTest(
+ /*continue_invalid_certificate=*/true,
+ /*redirect_from_https=*/true);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(CertificateErrorTest, RedirectMismatchedFromHttpResourceCancel) {
+ CefRefPtr<RedirectMismatchedFromHandlerTest> handler =
+ new RedirectMismatchedFromHandlerTest(
+ /*continue_invalid_certificate=*/false,
+ /*redirect_from_https=*/false);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(CertificateErrorTest, RedirectMismatchedFromHttpResourceContinue) {
+ CefRefPtr<RedirectMismatchedFromHandlerTest> handler =
+ new RedirectMismatchedFromHandlerTest(
+ /*continue_invalid_certificate=*/true,
+ /*redirect_from_https=*/false);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+namespace {
+
+class RedirectMismatchedFromServerTest : public CertificateErrorTest {
+ public:
+ RedirectMismatchedFromServerTest(bool continue_invalid_certificate,
+ bool redirect_from_https)
+ : CertificateErrorTest(
+ /*cert_type=*/CEF_TEST_CERT_OK_DOMAIN,
+ /*expect_load_success=*/continue_invalid_certificate,
+ /*expect_certificate_error=*/true,
+ redirect_from_https ? OtherServerType::HTTPS
+ : OtherServerType::HTTP) {}
+
+ void HandleOtherServerRequest(
+ CefRefPtr<CefRequest> request,
+ const ResponseCallback& response_callback) override {
+ EXPECT_UI_THREAD();
+
+ EXPECT_FALSE(got_other_request_);
+ got_other_request_.yes();
+
+ const std::string& url = request->GetURL();
+ EXPECT_STREQ(GetStartURL().c_str(), url.c_str());
+
+ // Redirect to the end URL.
+ auto response = CefResponse::Create();
+ response->SetMimeType("text/html");
+ response->SetStatus(301); // Permanent Redirect
+ response->SetHeaderByName("Location", GetEndURL(),
+ /*overwrite=*/true);
+
+ response_callback.Run(response, /*response_body=*/std::string());
+ }
+
+ void DestroyTest() override {
+ EXPECT_TRUE(got_other_request_);
+ CertificateErrorTest::DestroyTest();
+ }
+
+ protected:
+ std::string GetStartURL() const override {
+ return other_origin() + "/index.html";
+ }
+
+ std::string GetEndURL() const override {
+ // Load by IP address when the certificate expects a domain.
+ return client::AsciiStrReplace(server_origin(), "localhost", "127.0.0.1") +
+ "/index.html";
+ }
+
+ private:
+ TrackCallback got_other_request_;
+};
+
+} // namespace
+
+TEST(CertificateErrorTest, RedirectMismatchedFromHttpsServerCancel) {
+ CefRefPtr<RedirectMismatchedFromServerTest> handler =
+ new RedirectMismatchedFromServerTest(
+ /*continue_invalid_certificate=*/false, /*redirect_from_https=*/true);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(CertificateErrorTest, RedirectMismatchedFromHttpsServerContinue) {
+ CefRefPtr<RedirectMismatchedFromServerTest> handler =
+ new RedirectMismatchedFromServerTest(
+ /*continue_invalid_certificate=*/true, /*redirect_from_https=*/true);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(CertificateErrorTest, RedirectMismatchedFromHttpServerCancel) {
+ CefRefPtr<RedirectMismatchedFromServerTest> handler =
+ new RedirectMismatchedFromServerTest(
+ /*continue_invalid_certificate=*/false,
+ /*redirect_from_https=*/false);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(CertificateErrorTest, RedirectMismatchedFromHttpServerContinue) {
+ CefRefPtr<RedirectMismatchedFromServerTest> handler =
+ new RedirectMismatchedFromServerTest(
+ /*continue_invalid_certificate=*/true, /*redirect_from_https=*/false);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
diff --git a/tests/ceftests/client_app_delegates.cc b/tests/ceftests/client_app_delegates.cc
new file mode 100644
index 00000000..d5b2e737
--- /dev/null
+++ b/tests/ceftests/client_app_delegates.cc
@@ -0,0 +1,154 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/shared/browser/client_app_browser.h"
+#include "tests/shared/renderer/client_app_renderer.h"
+
+using client::ClientAppBrowser;
+using client::ClientAppRenderer;
+
+void CreateBrowserDelegates(ClientAppBrowser::DelegateSet& delegates) {
+ // Bring in audio output tests.
+ extern void CreateAudioOutputTests(ClientAppBrowser::DelegateSet & delegates);
+ CreateAudioOutputTests(delegates);
+
+ // Bring in the CORS tests.
+ extern void CreateCorsBrowserTests(ClientAppBrowser::DelegateSet & delegates);
+ CreateCorsBrowserTests(delegates);
+
+ // Bring in the preference tests.
+ extern void CreatePreferenceBrowserTests(ClientAppBrowser::DelegateSet &
+ delegates);
+ CreatePreferenceBrowserTests(delegates);
+
+ // Bring in the media access tests.
+ extern void CreateMediaAccessBrowserTests(ClientAppBrowser::DelegateSet &
+ delegates);
+ CreateMediaAccessBrowserTests(delegates);
+
+ // Bring in URLRequest tests.
+ extern void CreateURLRequestBrowserTests(ClientAppBrowser::DelegateSet &
+ delegates);
+ CreateURLRequestBrowserTests(delegates);
+}
+
+void CreateRenderDelegates(ClientAppRenderer::DelegateSet& delegates) {
+ // Bring in the Frame tests.
+ extern void CreateFrameRendererTests(ClientAppRenderer::DelegateSet &
+ delegates);
+ CreateFrameRendererTests(delegates);
+
+ // Bring in the DOM tests.
+ extern void CreateDOMRendererTests(ClientAppRenderer::DelegateSet &
+ delegates);
+ CreateDOMRendererTests(delegates);
+
+ // Bring in the message router tests.
+ extern void CreateMessageRouterRendererTests(ClientAppRenderer::DelegateSet &
+ delegates);
+ CreateMessageRouterRendererTests(delegates);
+
+ // Bring in the Navigation tests.
+ extern void CreateNavigationRendererTests(ClientAppRenderer::DelegateSet &
+ delegates);
+ CreateNavigationRendererTests(delegates);
+
+ // Bring in the process message tests.
+ extern void CreateProcessMessageRendererTests(ClientAppRenderer::DelegateSet &
+ delegates);
+ CreateProcessMessageRendererTests(delegates);
+
+ // Bring in the shared process message tests.
+ extern void CreateSharedProcessMessageTests(ClientAppRenderer::DelegateSet &
+ delegates);
+ CreateSharedProcessMessageTests(delegates);
+
+ // Bring in the RequestHandler tests.
+ extern void CreateRequestHandlerRendererTests(ClientAppRenderer::DelegateSet &
+ delegates);
+ CreateRequestHandlerRendererTests(delegates);
+
+ // Bring in the routing test handler delegate.
+ extern void CreateRoutingTestHandlerDelegate(ClientAppRenderer::DelegateSet &
+ delegates);
+ CreateRoutingTestHandlerDelegate(delegates);
+
+ // Bring in the thread tests.
+ extern void CreateThreadRendererTests(ClientAppRenderer::DelegateSet &
+ delegates);
+ CreateThreadRendererTests(delegates);
+
+ // Bring in the URLRequest tests.
+ extern void CreateURLRequestRendererTests(ClientAppRenderer::DelegateSet &
+ delegates);
+ CreateURLRequestRendererTests(delegates);
+
+ // Bring in the V8 tests.
+ extern void CreateV8RendererTests(ClientAppRenderer::DelegateSet & delegates);
+ CreateV8RendererTests(delegates);
+}
+
+void RegisterCustomSchemes(CefRawPtr<CefSchemeRegistrar> registrar) {
+ // Bring in the scheme handler tests.
+ extern void RegisterSchemeHandlerCustomSchemes(
+ CefRawPtr<CefSchemeRegistrar> registrar);
+ RegisterSchemeHandlerCustomSchemes(registrar);
+
+ // Bring in the cookie tests.
+ extern void RegisterCookieCustomSchemes(
+ CefRawPtr<CefSchemeRegistrar> registrar);
+ RegisterCookieCustomSchemes(registrar);
+
+ // Bring in the URLRequest tests.
+ extern void RegisterURLRequestCustomSchemes(
+ CefRawPtr<CefSchemeRegistrar> registrar);
+ RegisterURLRequestCustomSchemes(registrar);
+
+ // Bring in the resource request handler tests.
+ extern void RegisterResourceRequestHandlerCustomSchemes(
+ CefRawPtr<CefSchemeRegistrar> registrar);
+ RegisterResourceRequestHandlerCustomSchemes(registrar);
+}
+
+void RegisterCookieableSchemes(std::vector<std::string>& cookieable_schemes) {
+ // Bring in the scheme handler tests.
+ extern void RegisterSchemeHandlerCookieableSchemes(std::vector<std::string> &
+ cookieable_schemes);
+ RegisterSchemeHandlerCookieableSchemes(cookieable_schemes);
+
+ // Bring in the cookie tests.
+ extern void RegisterCookieCookieableSchemes(std::vector<std::string> &
+ cookieable_schemes);
+ RegisterCookieCookieableSchemes(cookieable_schemes);
+
+ // Bring in the URLRequest tests.
+ extern void RegisterURLRequestCookieableSchemes(std::vector<std::string> &
+ cookieable_schemes);
+ RegisterURLRequestCookieableSchemes(cookieable_schemes);
+}
+
+namespace client {
+
+// static
+void ClientAppBrowser::CreateDelegates(DelegateSet& delegates) {
+ ::CreateBrowserDelegates(delegates);
+}
+
+// static
+void ClientAppRenderer::CreateDelegates(DelegateSet& delegates) {
+ ::CreateRenderDelegates(delegates);
+}
+
+// static
+void ClientApp::RegisterCustomSchemes(CefRawPtr<CefSchemeRegistrar> registrar) {
+ ::RegisterCustomSchemes(registrar);
+}
+
+// static
+void ClientAppBrowser::RegisterCookieableSchemes(
+ std::vector<std::string>& cookieable_schemes) {
+ ::RegisterCookieableSchemes(cookieable_schemes);
+}
+
+} // namespace client
diff --git a/tests/ceftests/command_line_unittest.cc b/tests/ceftests/command_line_unittest.cc
new file mode 100644
index 00000000..978ff1f3
--- /dev/null
+++ b/tests/ceftests/command_line_unittest.cc
@@ -0,0 +1,152 @@
+// Copyright (c) 2011 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "include/cef_command_line.h"
+#include "tests/gtest/include/gtest/gtest.h"
+
+namespace {
+
+void VerifyCommandLine(CefRefPtr<CefCommandLine> command_line,
+ const char* expected_arg1 = "arg1",
+ const char* expected_arg2 = "arg 2") {
+ std::string program = command_line->GetProgram();
+ EXPECT_EQ("test.exe", program);
+
+ EXPECT_TRUE(command_line->HasSwitches());
+
+ EXPECT_TRUE(command_line->HasSwitch("switch1"));
+ std::string switch1 = command_line->GetSwitchValue("switch1");
+ EXPECT_EQ("", switch1);
+ // Switch names are converted to lowercase but values are left unchanged.
+ EXPECT_TRUE(command_line->HasSwitch("SWITCH2"));
+ std::string switch2 = command_line->GetSwitchValue("SWITCH2");
+ EXPECT_EQ("VAL2", switch2);
+ EXPECT_TRUE(command_line->HasSwitch("switch3"));
+ std::string switch3 = command_line->GetSwitchValue("switch3");
+ EXPECT_EQ("val3", switch3);
+ EXPECT_TRUE(command_line->HasSwitch("switch4"));
+ std::string switch4 = command_line->GetSwitchValue("switch4");
+ EXPECT_EQ("val 4", switch4);
+ EXPECT_FALSE(command_line->HasSwitch("switchnoexist"));
+
+ CefCommandLine::SwitchMap switches;
+ command_line->GetSwitches(switches);
+ EXPECT_EQ((size_t)4, switches.size());
+
+ bool has1 = false, has2 = false, has3 = false, has4 = false;
+
+ CefCommandLine::SwitchMap::const_iterator it = switches.begin();
+ for (; it != switches.end(); ++it) {
+ std::string name = it->first;
+ std::string val = it->second;
+
+ if (name == "switch1") {
+ has1 = true;
+ EXPECT_EQ("", val);
+ } else if (name == "switch2") {
+ has2 = true;
+ EXPECT_EQ("VAL2", val);
+ } else if (name == "switch3") {
+ has3 = true;
+ EXPECT_EQ("val3", val);
+ } else if (name == "switch4") {
+ has4 = true;
+ EXPECT_EQ("val 4", val);
+ }
+ }
+
+ EXPECT_TRUE(has1);
+ EXPECT_TRUE(has2);
+ EXPECT_TRUE(has3);
+ EXPECT_TRUE(has4);
+
+ EXPECT_TRUE(command_line->HasArguments());
+
+ CefCommandLine::ArgumentList args;
+ command_line->GetArguments(args);
+ EXPECT_EQ((size_t)2, args.size());
+ std::string arg0 = args[0];
+ EXPECT_EQ(expected_arg1, arg0);
+ std::string arg1 = args[1];
+ EXPECT_EQ(expected_arg2, arg1);
+
+ command_line->Reset();
+ EXPECT_FALSE(command_line->HasSwitches());
+ EXPECT_FALSE(command_line->HasArguments());
+ std::string cur_program = command_line->GetProgram();
+ EXPECT_EQ(program, cur_program);
+}
+
+} // namespace
+
+// Test creating a command line from argc/argv or string.
+TEST(CommandLineTest, Init) {
+ CefRefPtr<CefCommandLine> command_line = CefCommandLine::CreateCommandLine();
+ EXPECT_TRUE(command_line.get() != nullptr);
+
+#if defined(OS_WIN)
+ command_line->InitFromString(
+ "test.exe --switch1 -switch2=VAL2 /switch3=val3 "
+ "-switch4=\"val 4\" arg1 \"arg 2\"");
+#else
+ const char* args[] = {"test.exe", "--switch1", "-switch2=VAL2",
+ "-switch3=val3", "-switch4=val 4", "arg1",
+ "arg 2"};
+ command_line->InitFromArgv(sizeof(args) / sizeof(char*), args);
+#endif
+
+ VerifyCommandLine(command_line);
+}
+
+// Test creating a command line using set and append methods.
+TEST(CommandLineTest, Manual) {
+ CefRefPtr<CefCommandLine> command_line = CefCommandLine::CreateCommandLine();
+ EXPECT_TRUE(command_line.get() != nullptr);
+
+ command_line->SetProgram("test.exe");
+ command_line->AppendSwitch("switch1");
+ command_line->AppendSwitchWithValue("switch2", "VAL2");
+ command_line->AppendSwitchWithValue("switch3", "val3");
+ command_line->AppendSwitchWithValue("switch4", "val 4");
+ command_line->AppendArgument("arg1");
+ command_line->AppendArgument("arg 2");
+
+ VerifyCommandLine(command_line);
+}
+
+// Test that any prefixes included with the switches are ignored.
+TEST(CommandLineTest, IgnorePrefixes) {
+ CefRefPtr<CefCommandLine> command_line = CefCommandLine::CreateCommandLine();
+ EXPECT_TRUE(command_line.get() != nullptr);
+
+ command_line->SetProgram("test.exe");
+ command_line->AppendSwitch("-switch1");
+ command_line->AppendSwitchWithValue("--switch2", "VAL2");
+ command_line->AppendSwitchWithValue("-switch3", "val3");
+ command_line->AppendSwitchWithValue("-switch4", "val 4");
+
+ // Prefixes will not be removed from arguments.
+ const char arg1[] = "-arg1";
+ const char arg2[] = "--arg 2";
+ command_line->AppendArgument(arg1);
+ command_line->AppendArgument(arg2);
+
+ VerifyCommandLine(command_line, arg1, arg2);
+}
+
+// Test that command line switch names are converted to lowercase ASCII.
+TEST(CommandLineTest, IgnoreCase) {
+ CefRefPtr<CefCommandLine> command_line = CefCommandLine::CreateCommandLine();
+ EXPECT_TRUE(command_line.get() != nullptr);
+
+ command_line->SetProgram("test.exe");
+ command_line->AppendSwitch("-Switch1");
+ command_line->AppendSwitchWithValue("-SWITCH2", "VAL2");
+ command_line->AppendSwitchWithValue("-switch3", "val3");
+ command_line->AppendSwitchWithValue("-switch4", "val 4");
+ command_line->AppendArgument("arg1");
+ command_line->AppendArgument("arg 2");
+
+ VerifyCommandLine(command_line);
+}
diff --git a/tests/ceftests/cookie_unittest.cc b/tests/ceftests/cookie_unittest.cc
new file mode 100644
index 00000000..c5733651
--- /dev/null
+++ b/tests/ceftests/cookie_unittest.cc
@@ -0,0 +1,2322 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include <algorithm>
+#include <chrono>
+#include <vector>
+
+#include "include/base/cef_callback.h"
+#include "include/base/cef_logging.h"
+#include "include/base/cef_ref_counted.h"
+#include "include/cef_cookie.h"
+#include "include/cef_request_context_handler.h"
+#include "include/cef_scheme.h"
+#include "include/cef_server.h"
+#include "include/cef_waitable_event.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "tests/ceftests/routing_test_handler.h"
+#include "tests/ceftests/test_handler.h"
+#include "tests/ceftests/test_server_observer.h"
+#include "tests/ceftests/test_suite.h"
+#include "tests/ceftests/test_util.h"
+#include "tests/gtest/include/gtest/gtest.h"
+#include "tests/shared/common/string_util.h"
+
+namespace {
+
+const char* kTestUrl = "http://www.test.com/path/to/cookietest/foo.html";
+const char* kTestDomain = "www.test.com";
+const char* kTestPath = "/path/to/cookietest";
+
+const int kIgnoreNumDeleted = -2;
+
+typedef std::vector<CefCookie> CookieVector;
+
+class TestCompletionCallback : public CefCompletionCallback {
+ public:
+ explicit TestCompletionCallback(CefRefPtr<CefWaitableEvent> event)
+ : event_(event) {}
+
+ void OnComplete() override {
+ EXPECT_TRUE(CefCurrentlyOn(TID_UI));
+ event_->Signal();
+ }
+
+ private:
+ CefRefPtr<CefWaitableEvent> event_;
+
+ IMPLEMENT_REFCOUNTING(TestCompletionCallback);
+ DISALLOW_COPY_AND_ASSIGN(TestCompletionCallback);
+};
+
+class TestSetCookieCallback : public CefSetCookieCallback {
+ public:
+ TestSetCookieCallback(bool expected_success,
+ CefRefPtr<CefWaitableEvent> event)
+ : expected_success_(expected_success), event_(event) {}
+
+ void OnComplete(bool success) override {
+ EXPECT_TRUE(CefCurrentlyOn(TID_UI));
+ EXPECT_EQ(expected_success_, success);
+ event_->Signal();
+ }
+
+ private:
+ bool expected_success_;
+ CefRefPtr<CefWaitableEvent> event_;
+
+ IMPLEMENT_REFCOUNTING(TestSetCookieCallback);
+ DISALLOW_COPY_AND_ASSIGN(TestSetCookieCallback);
+};
+
+class TestDeleteCookiesCallback : public CefDeleteCookiesCallback {
+ public:
+ TestDeleteCookiesCallback(int expected_num_deleted,
+ CefRefPtr<CefWaitableEvent> event)
+ : expected_num_deleted_(expected_num_deleted), event_(event) {}
+
+ void OnComplete(int num_deleted) override {
+ EXPECT_TRUE(CefCurrentlyOn(TID_UI));
+ if (expected_num_deleted_ != kIgnoreNumDeleted) {
+ EXPECT_EQ(expected_num_deleted_, num_deleted);
+ }
+ event_->Signal();
+ }
+
+ private:
+ int expected_num_deleted_;
+ CefRefPtr<CefWaitableEvent> event_;
+
+ IMPLEMENT_REFCOUNTING(TestDeleteCookiesCallback);
+ DISALLOW_COPY_AND_ASSIGN(TestDeleteCookiesCallback);
+};
+
+class TestVisitor : public CefCookieVisitor {
+ public:
+ TestVisitor(CookieVector* cookies,
+ bool deleteCookies,
+ base::OnceClosure callback)
+ : cookies_(cookies),
+ delete_cookies_(deleteCookies),
+ callback_(std::move(callback)) {
+ EXPECT_TRUE(cookies_);
+ EXPECT_FALSE(callback_.is_null());
+ }
+ ~TestVisitor() override { std::move(callback_).Run(); }
+
+ bool Visit(const CefCookie& cookie,
+ int count,
+ int total,
+ bool& deleteCookie) override {
+ EXPECT_TRUE(CefCurrentlyOn(TID_UI));
+ cookies_->push_back(cookie);
+ if (delete_cookies_) {
+ deleteCookie = true;
+ }
+ return true;
+ }
+
+ private:
+ CookieVector* cookies_;
+ bool delete_cookies_;
+ base::OnceClosure callback_;
+
+ IMPLEMENT_REFCOUNTING(TestVisitor);
+};
+
+// Set the cookies.
+void SetCookies(CefRefPtr<CefCookieManager> manager,
+ const CefString& url,
+ const CookieVector& cookies,
+ bool expected_success,
+ CefRefPtr<CefWaitableEvent> event) {
+ CookieVector::const_iterator it = cookies.begin();
+ for (; it != cookies.end(); ++it) {
+ EXPECT_TRUE(manager->SetCookie(
+ url, *it, new TestSetCookieCallback(expected_success, event)));
+ event->Wait();
+ }
+}
+
+// Delete the cookie.
+void DeleteCookies(CefRefPtr<CefCookieManager> manager,
+ const CefString& url,
+ const CefString& cookie_name,
+ int expected_num_deleted,
+ CefRefPtr<CefWaitableEvent> event) {
+ EXPECT_TRUE(manager->DeleteCookies(
+ url, cookie_name,
+ new TestDeleteCookiesCallback(expected_num_deleted, event)));
+ event->Wait();
+}
+
+time_t GetExpiryDate() {
+ static time_t expiry_time = [] {
+ return std::chrono::system_clock::to_time_t(
+ std::chrono::system_clock::now() + std::chrono::hours(1));
+ }();
+ return expiry_time;
+}
+
+// Create a test cookie. If |withDomain| is true a domain cookie will be
+// created, otherwise a host cookie will be created.
+void CreateCookie(CefRefPtr<CefCookieManager> manager,
+ CefCookie& cookie,
+ bool withDomain,
+ bool sessionCookie,
+ CefRefPtr<CefWaitableEvent> event) {
+ CefString(&cookie.name).FromASCII("my_cookie");
+ CefString(&cookie.value).FromASCII("My Value");
+ if (withDomain) {
+ CefString(&cookie.domain).FromASCII(kTestDomain);
+ }
+ CefString(&cookie.path).FromASCII(kTestPath);
+ if (!sessionCookie) {
+ cookie.has_expires = true;
+ // Must choose the expiry date dynamically due to the
+ // "ClampCookieExpiryTo400Days" feature enabled in M104.
+ cef_time_t expiry_time;
+ EXPECT_TRUE(cef_time_from_timet(GetExpiryDate(), &expiry_time));
+ EXPECT_TRUE(cef_time_to_basetime(&expiry_time, &cookie.expires));
+ }
+
+ CookieVector cookies;
+ cookies.push_back(cookie);
+
+ SetCookies(manager, kTestUrl, cookies, true, event);
+}
+
+// Visit URL cookies. Execute |callback| on completion.
+void VisitUrlCookies(CefRefPtr<CefCookieManager> manager,
+ const CefString& url,
+ bool includeHttpOnly,
+ CookieVector& cookies,
+ bool deleteCookies,
+ base::OnceClosure callback) {
+ EXPECT_TRUE(manager->VisitUrlCookies(
+ url, includeHttpOnly,
+ new TestVisitor(&cookies, deleteCookies, std::move(callback))));
+}
+
+// Visit URL cookies. Block on |event|.
+void VisitUrlCookies(CefRefPtr<CefCookieManager> manager,
+ const CefString& url,
+ bool includeHttpOnly,
+ CookieVector& cookies,
+ bool deleteCookies,
+ CefRefPtr<CefWaitableEvent> event) {
+ VisitUrlCookies(manager, url, includeHttpOnly, cookies, deleteCookies,
+ base::BindOnce(&CefWaitableEvent::Signal, event));
+ event->Wait();
+}
+
+// Visit all cookies. Execute |callback| on completion.
+void VisitAllCookies(CefRefPtr<CefCookieManager> manager,
+ CookieVector& cookies,
+ bool deleteCookies,
+ base::OnceClosure callback) {
+ EXPECT_TRUE(manager->VisitAllCookies(
+ new TestVisitor(&cookies, deleteCookies, std::move(callback))));
+}
+
+// Visit all cookies. Block on |event|.
+void VisitAllCookies(CefRefPtr<CefCookieManager> manager,
+ CookieVector& cookies,
+ bool deleteCookies,
+ CefRefPtr<CefWaitableEvent> event) {
+ VisitAllCookies(manager, cookies, deleteCookies,
+ base::BindOnce(&CefWaitableEvent::Signal, event));
+ event->Wait();
+}
+
+// Retrieve the test cookie. If |withDomain| is true check that the cookie
+// is a domain cookie, otherwise a host cookie. if |deleteCookies| is true
+// the cookie will be deleted when it's retrieved.
+void GetCookie(CefRefPtr<CefCookieManager> manager,
+ const CefCookie& cookie,
+ bool withDomain,
+ CefRefPtr<CefWaitableEvent> event,
+ bool deleteCookies) {
+ CookieVector cookies;
+
+ // Get the cookie and delete it.
+ VisitUrlCookies(manager, kTestUrl, false, cookies, deleteCookies, event);
+
+ EXPECT_EQ(1U, cookies.size());
+ if (cookies.size() != 1U) {
+ return;
+ }
+
+ const CefCookie& cookie_read = cookies[0];
+ EXPECT_EQ(CefString(&cookie_read.name), "my_cookie");
+ EXPECT_EQ(CefString(&cookie_read.value), "My Value");
+ if (withDomain) {
+ EXPECT_EQ(CefString(&cookie_read.domain), ".www.test.com");
+ } else {
+ EXPECT_EQ(CefString(&cookie_read.domain), kTestDomain);
+ }
+ EXPECT_EQ(CefString(&cookie_read.path), kTestPath);
+ EXPECT_EQ(cookie.has_expires, cookie_read.has_expires);
+ EXPECT_EQ(cookie.expires.val, cookie_read.expires.val);
+ EXPECT_EQ(cookie.same_site, cookie_read.same_site);
+ EXPECT_EQ(cookie.priority, cookie_read.priority);
+}
+
+// Verify that no cookies exist. If |withUrl| is true it will only check for
+// cookies matching the URL.
+void VerifyNoCookies(CefRefPtr<CefCookieManager> manager,
+ CefRefPtr<CefWaitableEvent> event,
+ bool withUrl) {
+ CookieVector cookies;
+
+ // Verify that the cookie has been deleted.
+ if (withUrl) {
+ VisitUrlCookies(manager, kTestUrl, false, cookies, false, event);
+ } else {
+ VisitAllCookies(manager, cookies, false, event);
+ }
+
+ EXPECT_EQ(0U, cookies.size());
+}
+
+// Delete all system cookies.
+void DeleteAllCookies(CefRefPtr<CefCookieManager> manager,
+ CefRefPtr<CefWaitableEvent> event) {
+ DeleteCookies(manager, CefString(), CefString(), kIgnoreNumDeleted, event);
+}
+
+void TestDomainCookie(CefRefPtr<CefCookieManager> manager,
+ CefRefPtr<CefWaitableEvent> event) {
+ CefCookie cookie;
+
+ // Create a domain cookie.
+ CreateCookie(manager, cookie, true, false, event);
+
+ // Retrieve, verify and delete the domain cookie.
+ GetCookie(manager, cookie, true, event, true);
+
+ // Verify that the cookie was deleted.
+ VerifyNoCookies(manager, event, true);
+}
+
+void TestHostCookie(CefRefPtr<CefCookieManager> manager,
+ CefRefPtr<CefWaitableEvent> event) {
+ CefCookie cookie;
+
+ // Create a host cookie.
+ CreateCookie(manager, cookie, false, false, event);
+
+ // Retrieve, verify and delete the host cookie.
+ GetCookie(manager, cookie, false, event, true);
+
+ // Verify that the cookie was deleted.
+ VerifyNoCookies(manager, event, true);
+}
+
+void TestInvalidCookie(CefRefPtr<CefCookieManager> manager,
+ CefRefPtr<CefWaitableEvent> event) {
+ CookieVector cookies;
+
+ CefCookie cookie;
+ const char* kUrl = "http://www.xyz.com";
+ CefString(&cookie.name).FromASCII("invalid1");
+ CefString(&cookie.value).FromASCII("invalid1");
+ CefString(&cookie.domain).FromASCII(".zyx.com"); // domain mismatch
+
+ cookies.push_back(cookie);
+
+ // No cookies will be set due to non canonical cookie
+ SetCookies(manager, kUrl, cookies, false, event);
+}
+
+void TestMultipleCookies(CefRefPtr<CefCookieManager> manager,
+ CefRefPtr<CefWaitableEvent> event) {
+ std::stringstream ss;
+ int i;
+
+ CookieVector cookies;
+
+ const int kNumCookies = 4;
+
+ // Create the cookies.
+ for (i = 0; i < kNumCookies; i++) {
+ CefCookie cookie;
+
+ ss << "my_cookie" << i;
+ CefString(&cookie.name).FromASCII(ss.str().c_str());
+ ss.str("");
+ ss << "My Value " << i;
+ CefString(&cookie.value).FromASCII(ss.str().c_str());
+ ss.str("");
+
+ cookies.push_back(cookie);
+ }
+
+ // Set the cookies.
+ SetCookies(manager, kTestUrl, cookies, true, event);
+ cookies.clear();
+
+ // Get the cookies without deleting them.
+ VisitUrlCookies(manager, kTestUrl, false, cookies, false, event);
+
+ EXPECT_EQ((CookieVector::size_type)kNumCookies, cookies.size());
+
+ CookieVector::const_iterator it = cookies.begin();
+ for (i = 0; it != cookies.end(); ++it, ++i) {
+ const CefCookie& cookie = *it;
+
+ ss << "my_cookie" << i;
+ EXPECT_EQ(CefString(&cookie.name), ss.str());
+ ss.str("");
+ ss << "My Value " << i;
+ EXPECT_EQ(CefString(&cookie.value), ss.str());
+ ss.str("");
+ }
+
+ cookies.clear();
+
+ // Delete the 2nd cookie.
+ DeleteCookies(manager, kTestUrl, CefString("my_cookie1"), 1, event);
+
+ // Verify that the cookie has been deleted.
+ VisitUrlCookies(manager, kTestUrl, false, cookies, false, event);
+
+ EXPECT_EQ(3U, cookies.size());
+ if (cookies.size() != 3U) {
+ return;
+ }
+
+ EXPECT_EQ(CefString(&cookies[0].name), "my_cookie0");
+ EXPECT_EQ(CefString(&cookies[1].name), "my_cookie2");
+ EXPECT_EQ(CefString(&cookies[2].name), "my_cookie3");
+
+ cookies.clear();
+
+ // Delete the rest of the cookies.
+ DeleteCookies(manager, kTestUrl, CefString(), 3, event);
+
+ // Verify that the cookies have been deleted.
+ VisitUrlCookies(manager, kTestUrl, false, cookies, false, event);
+
+ EXPECT_EQ(0U, cookies.size());
+
+ // Create the cookies.
+ for (i = 0; i < kNumCookies; i++) {
+ CefCookie cookie;
+
+ ss << "my_cookie" << i;
+ CefString(&cookie.name).FromASCII(ss.str().c_str());
+ ss.str("");
+ ss << "My Value " << i;
+ CefString(&cookie.value).FromASCII(ss.str().c_str());
+ ss.str("");
+
+ cookies.push_back(cookie);
+ }
+
+ // Delete all of the cookies using the visitor.
+ VisitUrlCookies(manager, kTestUrl, false, cookies, true, event);
+
+ cookies.clear();
+
+ // Verify that the cookies have been deleted.
+ VisitUrlCookies(manager, kTestUrl, false, cookies, false, event);
+
+ EXPECT_EQ(0U, cookies.size());
+}
+
+void TestAllCookies(CefRefPtr<CefCookieManager> manager,
+ CefRefPtr<CefWaitableEvent> event) {
+ CookieVector cookies;
+
+ // Delete all system cookies just in case something is left over from a
+ // different test.
+ DeleteAllCookies(manager, event);
+
+ // Verify that all system cookies have been deleted.
+ VisitAllCookies(manager, cookies, false, event);
+
+ EXPECT_EQ(0U, cookies.size());
+
+ // Create cookies with 2 separate hosts.
+ CefCookie cookie1;
+ const char* kUrl1 = "http://www.foo.com";
+ CefString(&cookie1.name).FromASCII("my_cookie1");
+ CefString(&cookie1.value).FromASCII("My Value 1");
+
+ cookies.push_back(cookie1);
+ SetCookies(manager, kUrl1, cookies, true, event);
+ cookies.clear();
+
+ CefCookie cookie2;
+ const char* kUrl2 = "http://www.bar.com";
+ CefString(&cookie2.name).FromASCII("my_cookie2");
+ CefString(&cookie2.value).FromASCII("My Value 2");
+
+ cookies.push_back(cookie2);
+ SetCookies(manager, kUrl2, cookies, true, event);
+ cookies.clear();
+
+ // Verify that all system cookies can be retrieved.
+ VisitAllCookies(manager, cookies, false, event);
+
+ EXPECT_EQ(2U, cookies.size());
+ if (cookies.size() != 2U) {
+ return;
+ }
+
+ EXPECT_EQ(CefString(&cookies[0].name), "my_cookie1");
+ EXPECT_EQ(CefString(&cookies[0].value), "My Value 1");
+ EXPECT_EQ(CefString(&cookies[0].domain), "www.foo.com");
+ EXPECT_EQ(CefString(&cookies[1].name), "my_cookie2");
+ EXPECT_EQ(CefString(&cookies[1].value), "My Value 2");
+ EXPECT_EQ(CefString(&cookies[1].domain), "www.bar.com");
+ cookies.clear();
+
+ // Verify that the cookies can be retrieved separately.
+ VisitUrlCookies(manager, kUrl1, false, cookies, false, event);
+
+ EXPECT_EQ(1U, cookies.size());
+ if (cookies.size() != 1U) {
+ return;
+ }
+
+ EXPECT_EQ(CefString(&cookies[0].name), "my_cookie1");
+ EXPECT_EQ(CefString(&cookies[0].value), "My Value 1");
+ EXPECT_EQ(CefString(&cookies[0].domain), "www.foo.com");
+ cookies.clear();
+
+ VisitUrlCookies(manager, kUrl2, false, cookies, false, event);
+
+ EXPECT_EQ(1U, cookies.size());
+ if (cookies.size() != 1U) {
+ return;
+ }
+
+ EXPECT_EQ(CefString(&cookies[0].name), "my_cookie2");
+ EXPECT_EQ(CefString(&cookies[0].value), "My Value 2");
+ EXPECT_EQ(CefString(&cookies[0].domain), "www.bar.com");
+ cookies.clear();
+
+ // Delete all of the system cookies.
+ DeleteAllCookies(manager, event);
+
+ // Verify that all system cookies have been deleted.
+ VerifyNoCookies(manager, event, false);
+}
+
+} // namespace
+
+// Test creation of a invalid cookie.
+TEST(CookieTest, BasicInvalidCookie) {
+ CefRefPtr<CefWaitableEvent> event =
+ CefWaitableEvent::CreateWaitableEvent(true, false);
+
+ CefRefPtr<CefCookieManager> manager =
+ CefCookieManager::GetGlobalManager(new TestCompletionCallback(event));
+ event->Wait();
+ EXPECT_TRUE(manager.get());
+
+ TestInvalidCookie(manager, event);
+}
+
+// Test creation of a domain cookie.
+TEST(CookieTest, BasicDomainCookie) {
+ CefRefPtr<CefWaitableEvent> event =
+ CefWaitableEvent::CreateWaitableEvent(true, false);
+
+ CefRefPtr<CefCookieManager> manager =
+ CefCookieManager::GetGlobalManager(new TestCompletionCallback(event));
+ event->Wait();
+ EXPECT_TRUE(manager.get());
+
+ TestDomainCookie(manager, event);
+}
+
+// Test creation of a host cookie.
+TEST(CookieTest, BasicHostCookie) {
+ CefRefPtr<CefWaitableEvent> event =
+ CefWaitableEvent::CreateWaitableEvent(true, false);
+
+ CefRefPtr<CefCookieManager> manager =
+ CefCookieManager::GetGlobalManager(new TestCompletionCallback(event));
+ event->Wait();
+ EXPECT_TRUE(manager.get());
+
+ TestHostCookie(manager, event);
+}
+
+// Test creation of multiple cookies.
+TEST(CookieTest, BasicMultipleCookies) {
+ CefRefPtr<CefWaitableEvent> event =
+ CefWaitableEvent::CreateWaitableEvent(true, false);
+
+ CefRefPtr<CefCookieManager> manager =
+ CefCookieManager::GetGlobalManager(new TestCompletionCallback(event));
+ event->Wait();
+ EXPECT_TRUE(manager.get());
+
+ TestMultipleCookies(manager, event);
+}
+
+TEST(CookieTest, BasicAllCookies) {
+ CefRefPtr<CefWaitableEvent> event =
+ CefWaitableEvent::CreateWaitableEvent(true, false);
+
+ CefRefPtr<CefCookieManager> manager =
+ CefCookieManager::GetGlobalManager(new TestCompletionCallback(event));
+ event->Wait();
+ EXPECT_TRUE(manager.get());
+
+ TestAllCookies(manager, event);
+}
+
+namespace {
+
+const char* kCookieJSUrl1 = "http://tests/cookie1.html";
+const char* kCookieJSUrl2 = "http://tests/cookie2.html";
+
+class CookieTestJSHandler : public TestHandler {
+ public:
+ CookieTestJSHandler() {}
+
+ void RunTest() override {
+ std::string page =
+ "<html><head>"
+ "<script>"
+ "document.cookie='name1=value1;"
+ // Invalid date should not cause a crash (see issue #2927).
+ " expires=Tue, 07 Nov 94276 07:58:05 GMT'"
+ "</script>"
+ "</head><body>COOKIE TEST1</body></html>";
+ AddResource(kCookieJSUrl1, page, "text/html");
+
+ page =
+ "<html><head>"
+ "<script>"
+ "document.cookie='name2=value2';"
+ "</script>"
+ "</head><body>COOKIE TEST2</body></html>";
+ AddResource(kCookieJSUrl2, page, "text/html");
+
+ // Create the request context that will use an in-memory cache.
+ CefRequestContextSettings settings;
+ CefRefPtr<CefRequestContext> request_context =
+ CefRequestContext::CreateContext(settings, nullptr);
+ manager_ = request_context->GetCookieManager(nullptr);
+
+ // Create the browser.
+ CreateBrowser(kCookieJSUrl1, request_context);
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout();
+ }
+
+ // Go to the next URL.
+ void LoadNextURL(CefRefPtr<CefFrame> frame) {
+ if (!CefCurrentlyOn(TID_UI)) {
+ CefPostTask(TID_UI, base::BindOnce(&CookieTestJSHandler::LoadNextURL,
+ this, frame));
+ return;
+ }
+
+ frame->LoadURL(kCookieJSUrl2);
+ }
+
+ void CompleteTest() {
+ if (!CefCurrentlyOn(TID_UI)) {
+ CefPostTask(TID_UI,
+ base::BindOnce(&CookieTestJSHandler::CompleteTest, this));
+ return;
+ }
+
+ DestroyTest();
+ }
+
+ void OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int httpStatusCode) override {
+ std::string url = frame->GetURL();
+ if (url == kCookieJSUrl1) {
+ got_load_end1_.yes();
+ VerifyCookie(
+ manager_, url, "name1", "value1", true, &got_cookie1_,
+ base::BindOnce(&CookieTestJSHandler::LoadNextURL, this, frame));
+ } else {
+ got_load_end2_.yes();
+ VerifyCookie(manager_, url, "name2", "value2", true, &got_cookie2_,
+ base::BindOnce(&CookieTestJSHandler::CompleteTest, this));
+ }
+ }
+
+ // Verify that the cookie was set successfully.
+ void VerifyCookie(CefRefPtr<CefCookieManager> manager,
+ const std::string& url,
+ const std::string& name,
+ const std::string& value,
+ bool deleteCookie,
+ TrackCallback* callback,
+ base::OnceClosure continue_callback) {
+ // Get the cookie.
+ EXPECT_TRUE(cookies_.empty());
+ VisitUrlCookies(
+ manager, url, false, cookies_, deleteCookie,
+ base::BindOnce(&CookieTestJSHandler::VerifyCookieComplete, this, name,
+ value, callback, std::move(continue_callback)));
+ }
+
+ void VerifyCookieComplete(const std::string& name,
+ const std::string& value,
+ TrackCallback* callback,
+ base::OnceClosure continue_callback) {
+ if (cookies_.size() == 1U && CefString(&cookies_[0].name) == name &&
+ CefString(&cookies_[0].value) == value) {
+ callback->yes();
+ }
+
+ cookies_.clear();
+ std::move(continue_callback).Run();
+ }
+
+ CefRefPtr<CefCookieManager> manager_;
+
+ CookieVector cookies_;
+
+ TrackCallback got_load_end1_;
+ TrackCallback got_load_end2_;
+ TrackCallback got_cookie1_;
+ TrackCallback got_cookie2_;
+
+ IMPLEMENT_REFCOUNTING(CookieTestJSHandler);
+};
+
+} // namespace
+
+// Verify use of multiple cookie managers vis JS.
+TEST(CookieTest, GetCookieManagerJS) {
+ CefRefPtr<CookieTestJSHandler> handler = new CookieTestJSHandler();
+ handler->ExecuteTest();
+
+ EXPECT_TRUE(handler->got_load_end1_);
+ EXPECT_TRUE(handler->got_load_end2_);
+ EXPECT_TRUE(handler->got_cookie1_);
+ EXPECT_TRUE(handler->got_cookie2_);
+
+ ReleaseAndWaitForDestructor(handler);
+}
+
+namespace {
+
+const char kCustomCookieScheme[] = "ccustom";
+
+class CompletionCallback : public CefCompletionCallback {
+ public:
+ explicit CompletionCallback(base::OnceClosure callback)
+ : callback_(std::move(callback)) {}
+
+ void OnComplete() override { std::move(callback_).Run(); }
+
+ private:
+ base::OnceClosure callback_;
+ IMPLEMENT_REFCOUNTING(CompletionCallback);
+};
+
+class CookieTestSchemeHandler : public TestHandler {
+ public:
+ class SchemeHandler : public CefResourceHandler {
+ public:
+ explicit SchemeHandler(CookieTestSchemeHandler* handler)
+ : handler_(handler), offset_(0) {}
+
+ bool Open(CefRefPtr<CefRequest> request,
+ bool& handle_request,
+ CefRefPtr<CefCallback> callback) override {
+ EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO));
+
+ std::string url = request->GetURL();
+ if (url == handler_->url1_) {
+ content_ = "<html><body>COOKIE TEST1</body></html>";
+ cookie_ = "name1=value1";
+ handler_->got_process_request1_.yes();
+ } else if (url == handler_->url2_) {
+ content_ = "<html><body>COOKIE TEST2</body></html>";
+ cookie_ = "name2=value2";
+ handler_->got_process_request2_.yes();
+ } else if (url == handler_->url3_) {
+ content_ = "<html><body>COOKIE TEST3</body></html>";
+ handler_->got_process_request3_.yes();
+
+ // Verify that the cookie was passed in.
+ CefRequest::HeaderMap headerMap;
+ request->GetHeaderMap(headerMap);
+ CefRequest::HeaderMap::iterator it = headerMap.find("Cookie");
+ if (it != headerMap.end() && it->second == "name2=value2") {
+ handler_->got_process_request_cookie_.yes();
+ }
+ }
+
+ // Continue immediately.
+ handle_request = true;
+ return true;
+ }
+
+ void GetResponseHeaders(CefRefPtr<CefResponse> response,
+ int64& response_length,
+ CefString& redirectUrl) override {
+ response_length = content_.size();
+
+ response->SetStatus(200);
+ response->SetMimeType("text/html");
+
+ if (!cookie_.empty()) {
+ CefResponse::HeaderMap headerMap;
+ response->GetHeaderMap(headerMap);
+ headerMap.insert(std::make_pair("Set-Cookie", cookie_));
+ response->SetHeaderMap(headerMap);
+ }
+ }
+
+ bool Read(void* data_out,
+ int bytes_to_read,
+ int& bytes_read,
+ CefRefPtr<CefResourceReadCallback> callback) override {
+ EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO));
+
+ bool has_data = false;
+ bytes_read = 0;
+
+ size_t size = content_.size();
+ if (offset_ < size) {
+ int transfer_size =
+ std::min(bytes_to_read, static_cast<int>(size - offset_));
+ memcpy(data_out, content_.c_str() + offset_, transfer_size);
+ offset_ += transfer_size;
+
+ bytes_read = transfer_size;
+ has_data = true;
+ }
+
+ return has_data;
+ }
+
+ void Cancel() override {}
+
+ private:
+ CookieTestSchemeHandler* handler_;
+ std::string content_;
+ size_t offset_;
+ std::string cookie_;
+
+ IMPLEMENT_REFCOUNTING(SchemeHandler);
+ DISALLOW_COPY_AND_ASSIGN(SchemeHandler);
+ };
+
+ class SchemeHandlerFactory : public CefSchemeHandlerFactory {
+ public:
+ explicit SchemeHandlerFactory(CookieTestSchemeHandler* handler)
+ : handler_(handler) {}
+
+ CefRefPtr<CefResourceHandler> Create(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const CefString& scheme_name,
+ CefRefPtr<CefRequest> request) override {
+ std::string url = request->GetURL();
+ if (url == handler_->url3_) {
+ // Verify that the cookie was not passed in.
+ CefRequest::HeaderMap headerMap;
+ request->GetHeaderMap(headerMap);
+ CefRequest::HeaderMap::iterator it = headerMap.find("Cookie");
+ if (it != headerMap.end() && it->second == "name2=value2") {
+ handler_->got_create_cookie_.yes();
+ }
+ }
+
+ return new SchemeHandler(handler_);
+ }
+
+ private:
+ CookieTestSchemeHandler* handler_;
+
+ IMPLEMENT_REFCOUNTING(SchemeHandlerFactory);
+ DISALLOW_COPY_AND_ASSIGN(SchemeHandlerFactory);
+ };
+
+ CookieTestSchemeHandler(const std::string& scheme,
+ bool use_global,
+ bool block_cookies = false)
+ : scheme_(scheme),
+ use_global_(use_global),
+ block_cookies_(block_cookies) {
+ url1_ = scheme + "://cookie-tests/cookie1.html";
+ url2_ = scheme + "://cookie-tests/cookie2.html";
+ url3_ = scheme + "://cookie-tests/cookie3.html";
+ }
+
+ void RunTest() override {
+ if (use_global_) {
+ request_context_ = CefRequestContext::GetGlobalContext();
+ } else {
+ // Create the request context that will use an in-memory cache.
+ CefRequestContextSettings settings;
+
+ if (scheme_ == kCustomCookieScheme || block_cookies_) {
+ if (!block_cookies_) {
+ CefString(&settings.cookieable_schemes_list) = kCustomCookieScheme;
+ } else {
+ settings.cookieable_schemes_exclude_defaults = true;
+ }
+ }
+
+ request_context_ = CefRequestContext::CreateContext(settings, nullptr);
+ }
+
+ // Register the scheme handler.
+ request_context_->RegisterSchemeHandlerFactory(
+ scheme_, "cookie-tests", new SchemeHandlerFactory(this));
+
+ manager_ = request_context_->GetCookieManager(nullptr);
+
+ // Create the browser.
+ CreateBrowser(url1_, request_context_);
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout();
+ }
+
+ // Go to the next URL.
+ void LoadNextURL(CefRefPtr<CefFrame> frame, const std::string& url) {
+ if (!CefCurrentlyOn(TID_UI)) {
+ CefPostTask(TID_UI, base::BindOnce(&CookieTestSchemeHandler::LoadNextURL,
+ this, frame, url));
+ return;
+ }
+
+ frame->LoadURL(url);
+ }
+
+ void CompleteTest(CefRefPtr<CefBrowser> browser) {
+ if (!CefCurrentlyOn(TID_UI)) {
+ CefPostTask(TID_UI, base::BindOnce(&CookieTestSchemeHandler::CompleteTest,
+ this, browser));
+ return;
+ }
+
+ // Unregister the scheme handler.
+ browser->GetHost()->GetRequestContext()->RegisterSchemeHandlerFactory(
+ scheme_, "cookie-tests", nullptr);
+
+ DestroyTest();
+ }
+
+ void OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int httpStatusCode) override {
+ std::string url = frame->GetURL();
+ if (url == url1_) {
+ got_load_end1_.yes();
+ VerifyCookie(manager_, url, "name1", "value1", true, &got_cookie1_,
+ base::BindOnce(&CookieTestSchemeHandler::LoadNextURL, this,
+ frame, url2_));
+ } else if (url == url2_) {
+ got_load_end2_.yes();
+ VerifyCookie(manager_, url, "name2", "value2", false, &got_cookie2_,
+ base::BindOnce(&CookieTestSchemeHandler::LoadNextURL, this,
+ frame, url3_));
+ } else {
+ got_load_end3_.yes();
+ VerifyCookie(manager_, url, "name2", "value2", true, &got_cookie3_,
+ base::BindOnce(&CookieTestSchemeHandler::CompleteTest, this,
+ browser));
+ }
+ }
+
+ void DestroyTest() override {
+ EXPECT_TRUE(got_process_request1_);
+ EXPECT_TRUE(got_process_request2_);
+ EXPECT_TRUE(got_process_request3_);
+ EXPECT_TRUE(got_load_end1_);
+ EXPECT_TRUE(got_load_end2_);
+ EXPECT_TRUE(got_load_end3_);
+
+ if (block_cookies_) {
+ EXPECT_FALSE(got_create_cookie_);
+ EXPECT_FALSE(got_process_request_cookie_);
+ EXPECT_FALSE(got_cookie1_);
+ EXPECT_FALSE(got_cookie2_);
+ EXPECT_FALSE(got_cookie3_);
+ } else {
+ EXPECT_TRUE(got_create_cookie_);
+ EXPECT_TRUE(got_process_request_cookie_);
+ EXPECT_TRUE(got_cookie1_);
+ EXPECT_TRUE(got_cookie2_);
+ EXPECT_TRUE(got_cookie3_);
+ }
+
+ // Unregister the scheme handler.
+ request_context_->RegisterSchemeHandlerFactory(scheme_, "cookie-tests",
+ nullptr);
+ request_context_ = nullptr;
+
+ TestHandler::DestroyTest();
+ }
+
+ // Verify that the cookie was set successfully.
+ void VerifyCookie(CefRefPtr<CefCookieManager> manager,
+ const std::string& url,
+ const std::string& name,
+ const std::string& value,
+ bool deleteCookie,
+ TrackCallback* callback,
+ base::OnceClosure continue_callback) {
+ // Get the cookie.
+ EXPECT_TRUE(cookies_.empty());
+ VisitUrlCookies(
+ manager, url, false, cookies_, deleteCookie,
+ base::BindOnce(&CookieTestSchemeHandler::VerifyCookieComplete, this,
+ name, value, callback, std::move(continue_callback)));
+ }
+
+ void VerifyCookieComplete(const std::string& name,
+ const std::string& value,
+ TrackCallback* callback,
+ base::OnceClosure continue_callback) {
+ if (cookies_.size() == 1U && CefString(&cookies_[0].name) == name &&
+ CefString(&cookies_[0].value) == value) {
+ callback->yes();
+ }
+
+ cookies_.clear();
+ std::move(continue_callback).Run();
+ }
+
+ const std::string scheme_;
+ const bool use_global_;
+ const bool block_cookies_;
+ std::string url1_;
+ std::string url2_;
+ std::string url3_;
+
+ CefRefPtr<CefRequestContext> request_context_;
+ CefRefPtr<CefCookieManager> manager_;
+
+ CookieVector cookies_;
+
+ TrackCallback got_process_request1_;
+ TrackCallback got_process_request2_;
+ TrackCallback got_process_request3_;
+ TrackCallback got_create_cookie_;
+ TrackCallback got_process_request_cookie_;
+ TrackCallback got_load_end1_;
+ TrackCallback got_load_end2_;
+ TrackCallback got_load_end3_;
+ TrackCallback got_cookie1_;
+ TrackCallback got_cookie2_;
+ TrackCallback got_cookie3_;
+
+ IMPLEMENT_REFCOUNTING(CookieTestSchemeHandler);
+};
+
+} // namespace
+
+// Verify use of the global cookie manager with HTTP.
+TEST(CookieTest, GetCookieManagerHttpGlobal) {
+ CefRefPtr<CookieTestSchemeHandler> handler =
+ new CookieTestSchemeHandler("http", true);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Verify use of an in-memory cookie manager with HTTP.
+TEST(CookieTest, GetCookieManagerHttpInMemory) {
+ CefRefPtr<CookieTestSchemeHandler> handler =
+ new CookieTestSchemeHandler("http", false);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Verify use of an in-memory cookie manager with HTTP to block all cookies.
+TEST(CookieTest, GetCookieManagerHttpInMemoryBlocked) {
+ CefRefPtr<CookieTestSchemeHandler> handler =
+ new CookieTestSchemeHandler("http", false, true);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Verify use of the global cookie manager with a custom scheme.
+TEST(CookieTest, GetCookieManagerCustomGlobal) {
+ CefRefPtr<CookieTestSchemeHandler> handler =
+ new CookieTestSchemeHandler(kCustomCookieScheme, true);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Verify use of an in-memory cookie manager with a custom scheme.
+TEST(CookieTest, GetCookieManagerCustomInMemory) {
+ CefRefPtr<CookieTestSchemeHandler> handler =
+ new CookieTestSchemeHandler(kCustomCookieScheme, false);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+namespace {
+
+constexpr bool kUseHttpsServerScheme = false;
+
+const char kCookieAccessDomain[] = "test-cookies.com";
+
+std::string GetCookieAccessScheme() {
+ return test_server::GetScheme(kUseHttpsServerScheme);
+}
+
+std::string GetCookieAccessOrigin(const std::string& scheme,
+ bool server_backend) {
+ if (server_backend) {
+ EXPECT_STREQ(GetCookieAccessScheme().c_str(), scheme.c_str());
+ return test_server::GetOrigin(kUseHttpsServerScheme);
+ }
+
+ std::stringstream ss;
+ ss << scheme << "://" << kCookieAccessDomain;
+ return ss.str();
+}
+
+std::string GetCookieAccessUrl1(const std::string& scheme,
+ bool server_backend) {
+ return GetCookieAccessOrigin(scheme, server_backend) + "/cookie1.html";
+}
+
+std::string GetCookieAccessUrl2(const std::string& scheme,
+ bool server_backend) {
+ return GetCookieAccessOrigin(scheme, server_backend) + "/cookie2.html";
+}
+
+void TestCookieString(const std::string& cookie_str,
+ int& cookie_js_ct,
+ int& cookie_net_ct) {
+ if (cookie_str.find("name_js=value_js") != std::string::npos) {
+ cookie_js_ct++;
+ }
+ if (cookie_str.find("name_net=value_net") != std::string::npos) {
+ cookie_net_ct++;
+ }
+}
+
+struct CookieAccessData {
+ CefRefPtr<CefResponse> response;
+ std::string response_data;
+
+ int request_ct_ = 0;
+ int cookie_js_ct_ = 0;
+ int cookie_net_ct_ = 0;
+};
+
+class CookieAccessResponseHandler {
+ public:
+ CookieAccessResponseHandler() {}
+ virtual void AddResponse(const std::string& url, CookieAccessData* data) = 0;
+
+ protected:
+ virtual ~CookieAccessResponseHandler() {}
+};
+
+std::string GetHeaderValue(const CefServer::HeaderMap& header_map,
+ const std::string& header_name_lower) {
+ for (const auto& [name, value] : header_map) {
+ if (client::AsciiStrToLower(name) == header_name_lower) {
+ return value;
+ }
+ }
+ return std::string();
+}
+
+// Serves request responses.
+class CookieAccessSchemeHandler : public CefResourceHandler {
+ public:
+ explicit CookieAccessSchemeHandler(CookieAccessData* data)
+ : data_(data), offset_(0) {}
+
+ bool Open(CefRefPtr<CefRequest> request,
+ bool& handle_request,
+ CefRefPtr<CefCallback> callback) override {
+ EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO));
+
+ CefRequest::HeaderMap headerMap;
+ request->GetHeaderMap(headerMap);
+ const std::string& cookie_str = GetHeaderValue(headerMap, "cookie");
+ TestCookieString(cookie_str, data_->cookie_js_ct_, data_->cookie_net_ct_);
+
+ // Continue immediately.
+ handle_request = true;
+ return true;
+ }
+
+ void GetResponseHeaders(CefRefPtr<CefResponse> response,
+ int64& response_length,
+ CefString& redirectUrl) override {
+ EXPECT_IO_THREAD();
+
+ response->SetStatus(data_->response->GetStatus());
+ response->SetStatusText(data_->response->GetStatusText());
+ response->SetMimeType(data_->response->GetMimeType());
+
+ CefResponse::HeaderMap headerMap;
+ data_->response->GetHeaderMap(headerMap);
+ response->SetHeaderMap(headerMap);
+
+ response_length = data_->response_data.length();
+ }
+
+ bool Read(void* data_out,
+ int bytes_to_read,
+ int& bytes_read,
+ CefRefPtr<CefResourceReadCallback> callback) override {
+ EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO));
+
+ bool has_data = false;
+ bytes_read = 0;
+
+ size_t size = data_->response_data.length();
+ if (offset_ < size) {
+ int transfer_size =
+ std::min(bytes_to_read, static_cast<int>(size - offset_));
+ memcpy(data_out, data_->response_data.c_str() + offset_, transfer_size);
+ offset_ += transfer_size;
+
+ bytes_read = transfer_size;
+ has_data = true;
+ }
+
+ return has_data;
+ }
+
+ void Cancel() override { EXPECT_IO_THREAD(); }
+
+ private:
+ static void TestCookie(const CefCookie& cookie,
+ TrackCallback& got_cookie_js,
+ TrackCallback& got_cookie_net) {
+ const std::string& cookie_name = CefString(&cookie.name);
+ const std::string& cookie_val = CefString(&cookie.value);
+ if (cookie_name == "name_js") {
+ EXPECT_STREQ("value_js", cookie_val.c_str());
+ got_cookie_js.yes();
+ } else if (cookie_name == "name_net") {
+ EXPECT_STREQ("value_net", cookie_val.c_str());
+ got_cookie_net.yes();
+ } else {
+ ADD_FAILURE() << "Unexpected cookie: " << cookie_name;
+ }
+ }
+
+ // |data_| is not owned by this object.
+ CookieAccessData* data_;
+
+ size_t offset_;
+
+ IMPLEMENT_REFCOUNTING(CookieAccessSchemeHandler);
+ DISALLOW_COPY_AND_ASSIGN(CookieAccessSchemeHandler);
+};
+
+class CookieAccessSchemeHandlerFactory : public CefSchemeHandlerFactory,
+ public CookieAccessResponseHandler {
+ public:
+ CookieAccessSchemeHandlerFactory() {}
+
+ CefRefPtr<CefResourceHandler> Create(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const CefString& scheme_name,
+ CefRefPtr<CefRequest> request) override {
+ EXPECT_IO_THREAD();
+ const std::string& url = request->GetURL();
+ ResponseDataMap::const_iterator it = data_map_.find(url);
+ if (it != data_map_.end()) {
+ it->second->request_ct_++;
+
+ return new CookieAccessSchemeHandler(it->second);
+ }
+
+ // Unknown test.
+ if (!IgnoreURL(url)) {
+ ADD_FAILURE() << "Unexpected url: " << url;
+ }
+ return nullptr;
+ }
+
+ void AddResponse(const std::string& url, CookieAccessData* data) override {
+ data_map_.insert(std::make_pair(url, data));
+ }
+
+ void Shutdown(base::OnceClosure complete_callback) {
+ if (!CefCurrentlyOn(TID_IO)) {
+ CefPostTask(TID_IO, base::BindOnce(std::move(complete_callback)));
+ return;
+ }
+
+ std::move(complete_callback).Run();
+ }
+
+ private:
+ // Map of URL to Data.
+ typedef std::map<std::string, CookieAccessData*> ResponseDataMap;
+ ResponseDataMap data_map_;
+
+ IMPLEMENT_REFCOUNTING(CookieAccessSchemeHandlerFactory);
+};
+
+// HTTP server handler.
+class CookieAccessServerHandler : public test_server::ObserverHelper,
+ public CookieAccessResponseHandler {
+ public:
+ CookieAccessServerHandler()
+ : initialized_(false),
+ expected_http_request_ct_(-1),
+ actual_http_request_ct_(0) {}
+
+ virtual ~CookieAccessServerHandler() { RunCompleteCallback(); }
+
+ // Must be called before CreateServer().
+ void AddResponse(const std::string& url, CookieAccessData* data) override {
+ data_map_.insert(std::make_pair(url, data));
+ }
+
+ // Must be called before CreateServer().
+ void SetExpectedRequestCount(int count) { expected_http_request_ct_ = count; }
+
+ // |complete_callback| will be executed on the UI thread after the server is
+ // started.
+ void CreateServer(base::OnceClosure complete_callback) {
+ EXPECT_UI_THREAD();
+
+ EXPECT_FALSE(initialized_);
+ initialized_ = true;
+
+ EXPECT_TRUE(complete_callback_.is_null());
+ complete_callback_ = std::move(complete_callback);
+
+ Initialize(kUseHttpsServerScheme);
+ }
+
+ // Results in a call to VerifyResults() and eventual execution of the
+ // |complete_callback| on the UI thread via CookieAccessServerHandler
+ // destruction.
+ void ShutdownServer(base::OnceClosure complete_callback) {
+ EXPECT_UI_THREAD();
+
+ EXPECT_TRUE(complete_callback_.is_null());
+ complete_callback_ = std::move(complete_callback);
+
+ Shutdown();
+ }
+
+ void OnInitialized(const std::string& server_origin) override {
+ EXPECT_UI_THREAD();
+ EXPECT_STREQ(server_origin.c_str(),
+ GetCookieAccessOrigin(GetCookieAccessScheme(), true).c_str());
+
+ EXPECT_FALSE(got_server_created_);
+ got_server_created_.yes();
+
+ RunCompleteCallback();
+ }
+
+ void OnShutdown() override {
+ EXPECT_UI_THREAD();
+
+ EXPECT_FALSE(got_server_destroyed_);
+ got_server_destroyed_.yes();
+
+ VerifyResults();
+
+ delete this;
+ }
+
+ bool OnTestServerRequest(CefRefPtr<CefRequest> request,
+ const ResponseCallback& response_callback) override {
+ EXPECT_UI_THREAD();
+
+ // Log the requests for better error reporting.
+ request_log_ += request->GetMethod().ToString() + " " +
+ request->GetURL().ToString() + "\n";
+
+ actual_http_request_ct_++;
+
+ const std::string& url = request->GetURL();
+ ResponseDataMap::const_iterator it = data_map_.find(url);
+ if (it != data_map_.end()) {
+ it->second->request_ct_++;
+
+ CefRequest::HeaderMap headerMap;
+ request->GetHeaderMap(headerMap);
+ const std::string& cookie_str = GetHeaderValue(headerMap, "cookie");
+ TestCookieString(cookie_str, it->second->cookie_js_ct_,
+ it->second->cookie_net_ct_);
+
+ response_callback.Run(it->second->response, it->second->response_data);
+ return true;
+ } else if (!IgnoreURL(url)) {
+ // Unknown test.
+ ADD_FAILURE() << "Unexpected url: " << url;
+ }
+ return false;
+ }
+
+ private:
+ void VerifyResults() {
+ EXPECT_TRUE(got_server_created_);
+ EXPECT_TRUE(got_server_destroyed_);
+ EXPECT_EQ(expected_http_request_ct_, actual_http_request_ct_)
+ << request_log_;
+ }
+
+ void RunCompleteCallback() {
+ EXPECT_UI_THREAD();
+
+ EXPECT_FALSE(complete_callback_.is_null());
+ std::move(complete_callback_).Run();
+ }
+
+ // Map of URL to Data.
+ typedef std::map<std::string, CookieAccessData*> ResponseDataMap;
+ ResponseDataMap data_map_;
+
+ bool initialized_;
+
+ // Only accessed on the UI thread.
+ base::OnceClosure complete_callback_;
+
+ // After initialization the below members are only accessed on the server
+ // thread.
+
+ TrackCallback got_server_created_;
+ TrackCallback got_server_destroyed_;
+
+ int expected_http_request_ct_;
+ int actual_http_request_ct_;
+
+ std::string request_log_;
+
+ DISALLOW_COPY_AND_ASSIGN(CookieAccessServerHandler);
+};
+
+class CookieAccessTestHandler : public RoutingTestHandler,
+ public CefCookieAccessFilter {
+ public:
+ enum TestMode {
+ ALLOW = 0,
+ BLOCK_READ = 1 << 0,
+ BLOCK_WRITE = 1 << 1,
+ BLOCK_READ_WRITE = BLOCK_READ | BLOCK_WRITE,
+ ALLOW_NO_FILTER = 1 << 2,
+
+ // Block all cookies using CefRequestContextSettings. Can only be used with
+ // a non-global request context because it's too late (during test
+ // execution) to call this method on the global context.
+ BLOCK_ALL_COOKIES = 1 << 3,
+
+ // Return nullptr from GetResourceRequestHandler. Can only be used in
+ // combination with the SERVER or SCHEME_HANDLER backend (the
+ // RESOURCE_HANDLER backend would not be called).
+ ALLOW_NO_HANDLER = 1 << 4,
+ };
+
+ enum TestBackend {
+ // Test an HTTP server backend.
+ SERVER,
+
+ // Test a custom scheme handler backend.
+ SCHEME_HANDLER,
+
+ // Test that GetResourceHandler behaves the same as a custom scheme handler.
+ RESOURCE_HANDLER,
+ };
+
+ CookieAccessTestHandler(TestMode test_mode,
+ TestBackend test_backend,
+ bool custom_scheme,
+ bool use_global)
+ : test_mode_(test_mode),
+ test_backend_(test_backend),
+ scheme_(custom_scheme ? kCustomCookieScheme : GetCookieAccessScheme()),
+ use_global_(use_global) {
+ if (test_mode_ == BLOCK_ALL_COOKIES) {
+ CHECK(!use_global_);
+ } else if (test_mode_ == ALLOW_NO_HANDLER) {
+ CHECK_NE(RESOURCE_HANDLER, test_backend_);
+ }
+ if (test_backend_ == SERVER) {
+ CHECK(!custom_scheme);
+ }
+ }
+
+ void RunTest() override {
+ if (use_global_) {
+ context_ = CefRequestContext::GetGlobalContext();
+ } else {
+ // Create the request context that will use an in-memory cache.
+ CefRequestContextSettings settings;
+
+ const bool block_cookies = (test_mode_ == BLOCK_ALL_COOKIES);
+ if (scheme_ == kCustomCookieScheme || block_cookies) {
+ if (!block_cookies) {
+ CefString(&settings.cookieable_schemes_list) = kCustomCookieScheme;
+ } else {
+ settings.cookieable_schemes_exclude_defaults = true;
+ }
+ }
+
+ context_ = CefRequestContext::CreateContext(settings, nullptr);
+ }
+
+ SetTestTimeout();
+
+ cookie_manager_ = context_->GetCookieManager(nullptr);
+ RunTestSetupContinue();
+ }
+
+ void DestroyTest() override {
+ if (!CefCurrentlyOn(TID_UI)) {
+ CefPostTask(TID_UI,
+ base::BindOnce(&CookieAccessTestHandler::DestroyTest, this));
+ return;
+ }
+
+ cookie_manager_ = nullptr;
+ context_ = nullptr;
+
+ // Got both network requests.
+ EXPECT_EQ(1, data1_.request_ct_);
+ EXPECT_EQ(1, data2_.request_ct_);
+
+ if (test_mode_ == ALLOW_NO_FILTER || test_mode_ == ALLOW_NO_HANDLER) {
+ EXPECT_EQ(0, can_save_cookie1_ct_);
+ EXPECT_EQ(0, can_send_cookie2_ct_);
+ } else {
+ if (test_mode_ == BLOCK_ALL_COOKIES) {
+ // Never send any cookies.
+ EXPECT_EQ(0, can_send_cookie2_ct_);
+ EXPECT_EQ(0, can_save_cookie1_ct_);
+ } else if (test_mode_ & BLOCK_WRITE) {
+ // Get 1 calls to CanSendCookie for the 2nd network request due to the
+ // JS cookie (network cookie is blocked).
+ EXPECT_EQ(1, can_send_cookie2_ct_);
+ // Get 1 call to CanSaveCookie for the 1st network request due to the
+ // network cookie.
+ EXPECT_EQ(1, can_save_cookie1_ct_);
+ } else {
+ // Get 2 calls to CanSendCookie for the 2nd network request due to the
+ // network cookie + JS cookie.
+ EXPECT_EQ(2, can_send_cookie2_ct_);
+ // Get 1 call to CanSaveCookie for the 1st network request due to the
+ // network cookie.
+ EXPECT_EQ(1, can_save_cookie1_ct_);
+ }
+ }
+
+ if (test_mode_ == BLOCK_ALL_COOKIES) {
+ // Never get the JS cookie via JS.
+ EXPECT_EQ(0, cookie_js1_ct_);
+ EXPECT_EQ(0, cookie_js2_ct_);
+ EXPECT_EQ(0, cookie_js3_ct_);
+ } else {
+ // Always get the JS cookie via JS.
+ EXPECT_EQ(1, cookie_js1_ct_);
+ EXPECT_EQ(1, cookie_js2_ct_);
+ EXPECT_EQ(1, cookie_js3_ct_);
+ }
+
+ // Only get the net cookie via JS if cookie write was allowed.
+ if ((test_mode_ & BLOCK_WRITE) || test_mode_ == BLOCK_ALL_COOKIES) {
+ EXPECT_EQ(0, cookie_net1_ct_);
+ EXPECT_EQ(0, cookie_net2_ct_);
+ EXPECT_EQ(0, cookie_net3_ct_);
+ } else {
+ EXPECT_EQ(1, cookie_net1_ct_);
+ EXPECT_EQ(1, cookie_net2_ct_);
+ EXPECT_EQ(1, cookie_net3_ct_);
+ }
+
+ // No cookies sent for the 1st network request.
+ EXPECT_EQ(0, data1_.cookie_js_ct_);
+ EXPECT_EQ(0, data1_.cookie_net_ct_);
+
+ // 2nd network request...
+ if ((test_mode_ & BLOCK_READ) || test_mode_ == BLOCK_ALL_COOKIES) {
+ // No cookies sent if reading was blocked.
+ EXPECT_EQ(0, data2_.cookie_js_ct_);
+ EXPECT_EQ(0, data2_.cookie_net_ct_);
+ } else if (test_mode_ & BLOCK_WRITE) {
+ // Only JS cookie sent if writing was blocked.
+ EXPECT_EQ(1, data2_.cookie_js_ct_);
+ EXPECT_EQ(0, data2_.cookie_net_ct_);
+ } else {
+ // All cookies sent.
+ EXPECT_EQ(1, data2_.cookie_js_ct_);
+ EXPECT_EQ(1, data2_.cookie_net_ct_);
+ }
+
+ TestHandler::DestroyTest();
+ }
+
+ CefRefPtr<CefCookieAccessFilter> GetCookieAccessFilter(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request) override {
+ EXPECT_IO_THREAD();
+
+ if (test_mode_ == ALLOW_NO_FILTER) {
+ return nullptr;
+ }
+
+ return this;
+ }
+
+ CefRefPtr<CefResourceRequestHandler> GetResourceRequestHandler(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ bool is_navigation,
+ bool is_download,
+ const CefString& request_initiator,
+ bool& disable_default_handling) override {
+ if (test_mode_ == ALLOW_NO_HANDLER) {
+ return nullptr;
+ }
+
+ return this;
+ }
+
+ CefRefPtr<CefResourceHandler> GetResourceHandler(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request) override {
+ if (test_backend_ == RESOURCE_HANDLER && scheme_factory_) {
+ return scheme_factory_->Create(browser, frame, scheme_, request);
+ }
+
+ return nullptr;
+ }
+
+ bool CanSendCookie(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ const CefCookie& cookie) override {
+ EXPECT_IO_THREAD();
+
+ const std::string& url = request->GetURL();
+ if (url == GetCookieAccessUrl2(scheme_, test_backend_ == SERVER)) {
+ can_send_cookie2_ct_++;
+ } else if (!IgnoreURL(url)) {
+ ADD_FAILURE() << "Unexpected url: " << url;
+ }
+
+ return !(test_mode_ & BLOCK_READ);
+ }
+
+ bool CanSaveCookie(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response,
+ const CefCookie& cookie) override {
+ EXPECT_IO_THREAD();
+
+ // Expecting the network cookie only.
+ EXPECT_STREQ("name_net", CefString(&cookie.name).ToString().c_str());
+ EXPECT_STREQ("value_net", CefString(&cookie.value).ToString().c_str());
+
+ const std::string& url = request->GetURL();
+ if (url == GetCookieAccessUrl1(scheme_, test_backend_ == SERVER)) {
+ can_save_cookie1_ct_++;
+ } else if (!IgnoreURL(url)) {
+ ADD_FAILURE() << "Unexpected url: " << url;
+ }
+
+ return !(test_mode_ & BLOCK_WRITE);
+ }
+
+ bool OnQuery(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int64 query_id,
+ const CefString& request,
+ bool persistent,
+ CefRefPtr<Callback> callback) override {
+ const std::string& url = frame->GetURL();
+ const std::string& cookie_str = request.ToString();
+ if (url == GetCookieAccessUrl1(scheme_, test_backend_ == SERVER)) {
+ TestCookieString(cookie_str, cookie_js1_ct_, cookie_net1_ct_);
+ browser->GetMainFrame()->LoadURL(
+ GetCookieAccessUrl2(scheme_, test_backend_ == SERVER));
+ } else if (url == GetCookieAccessUrl2(scheme_, test_backend_ == SERVER)) {
+ TestCookieString(cookie_str, cookie_js2_ct_, cookie_net2_ct_);
+ FinishTest();
+ } else {
+ ADD_FAILURE() << "Unexpected url: " << url;
+ }
+ return true;
+ }
+
+ private:
+ void AddResponses(CookieAccessResponseHandler* handler) {
+ // 1st request sets a cookie via net response headers and JS, then retrieves
+ // the cookies via JS.
+ {
+ data1_.response = CefResponse::Create();
+ data1_.response->SetMimeType("text/html");
+ data1_.response->SetStatus(200);
+ data1_.response->SetStatusText("OK");
+
+ CefResponse::HeaderMap headerMap;
+ data1_.response->GetHeaderMap(headerMap);
+ headerMap.insert(std::make_pair("Set-Cookie", "name_net=value_net"));
+ data1_.response->SetHeaderMap(headerMap);
+
+ data1_.response_data =
+ "<html><head>"
+ "<script>"
+ "document.cookie='name_js=value_js';"
+ "window.testQuery({request:document.cookie});"
+ "</script>"
+ "</head><body>COOKIE ACCESS TEST 1</body></html>";
+
+ handler->AddResponse(
+ GetCookieAccessUrl1(scheme_, test_backend_ == SERVER), &data1_);
+ }
+
+ // 2nd request retrieves the cookies via JS.
+ {
+ data2_.response = CefResponse::Create();
+ data2_.response->SetMimeType("text/html");
+ data2_.response->SetStatus(200);
+ data2_.response->SetStatusText("OK");
+
+ data2_.response_data =
+ "<html><head>"
+ "<script>"
+ "window.testQuery({request:document.cookie});"
+ "</script>"
+ "</head><body>COOKIE ACCESS TEST 2</body></html>";
+
+ handler->AddResponse(
+ GetCookieAccessUrl2(scheme_, test_backend_ == SERVER), &data2_);
+ }
+ }
+
+ void RunTestSetupContinue() {
+ CefPostTask(
+ TID_UI,
+ base::BindOnce(
+ &CookieAccessTestHandler::StartBackend, this,
+ base::BindOnce(&CookieAccessTestHandler::RunTestContinue, this)));
+ }
+
+ void StartBackend(base::OnceClosure complete_callback) {
+ if (test_backend_ == SERVER) {
+ StartServer(std::move(complete_callback));
+ } else {
+ StartSchemeHandler(std::move(complete_callback));
+ }
+ }
+
+ void StartServer(base::OnceClosure complete_callback) {
+ EXPECT_FALSE(server_handler_);
+
+ server_handler_ = new CookieAccessServerHandler();
+ server_handler_->CreateServer(std::move(complete_callback));
+ }
+
+ void StartSchemeHandler(base::OnceClosure complete_callback) {
+ // Add the factory registration.
+ scheme_factory_ = new CookieAccessSchemeHandlerFactory();
+ if (test_backend_ == SCHEME_HANDLER) {
+ context_->RegisterSchemeHandlerFactory(scheme_, kCookieAccessDomain,
+ scheme_factory_.get());
+ }
+
+ std::move(complete_callback).Run();
+ }
+
+ void RunTestContinue() {
+ if (!CefCurrentlyOn(TID_UI)) {
+ CefPostTask(TID_UI, base::BindOnce(
+ &CookieAccessTestHandler::RunTestContinue, this));
+ return;
+ }
+
+ if (test_backend_ == SERVER) {
+ AddResponses(server_handler_);
+
+ // 1 request for each URL.
+ server_handler_->SetExpectedRequestCount(2);
+ } else {
+ AddResponses(scheme_factory_.get());
+ }
+
+ CreateBrowser(GetCookieAccessUrl1(scheme_, test_backend_ == SERVER),
+ context_);
+ }
+
+ void FinishTest() {
+ // Verify that cookies were set correctly.
+ class TestVisitor : public CefCookieVisitor {
+ public:
+ explicit TestVisitor(CookieAccessTestHandler* handler)
+ : handler_(handler) {}
+ ~TestVisitor() override {
+ // Destroy the test.
+ CefPostTask(
+ TID_UI,
+ base::BindOnce(&CookieAccessTestHandler::ShutdownBackend, handler_,
+ base::BindOnce(&CookieAccessTestHandler::DestroyTest,
+ handler_)));
+ }
+
+ bool Visit(const CefCookie& cookie,
+ int count,
+ int total,
+ bool& deleteCookie) override {
+ const std::string& name = CefString(&cookie.name);
+ const std::string& value = CefString(&cookie.value);
+ if (name == "name_js" && value == "value_js") {
+ handler_->cookie_js3_ct_++;
+ } else if (name == "name_net" && value == "value_net") {
+ handler_->cookie_net3_ct_++;
+ }
+
+ // Clean up the cookies.
+ deleteCookie = true;
+
+ return true;
+ }
+
+ private:
+ CookieAccessTestHandler* handler_;
+ IMPLEMENT_REFCOUNTING(TestVisitor);
+ };
+
+ cookie_manager_->VisitAllCookies(new TestVisitor(this));
+ }
+
+ void ShutdownBackend(base::OnceClosure complete_callback) {
+ if (test_backend_ == SERVER) {
+ ShutdownServer(std::move(complete_callback));
+ } else {
+ ShutdownSchemeHandler(std::move(complete_callback));
+ }
+ }
+
+ void ShutdownServer(base::OnceClosure complete_callback) {
+ EXPECT_TRUE(server_handler_);
+
+ // |server_handler_| will delete itself after shutdown.
+ server_handler_->ShutdownServer(std::move(complete_callback));
+ server_handler_ = nullptr;
+ }
+
+ void ShutdownSchemeHandler(base::OnceClosure complete_callback) {
+ EXPECT_TRUE(scheme_factory_);
+
+ if (test_backend_ == SCHEME_HANDLER) {
+ context_->RegisterSchemeHandlerFactory(scheme_, kCookieAccessDomain,
+ nullptr);
+ }
+ scheme_factory_->Shutdown(std::move(complete_callback));
+ scheme_factory_ = nullptr;
+ }
+
+ const TestMode test_mode_;
+ const TestBackend test_backend_;
+ const std::string scheme_;
+ const bool use_global_;
+ CefRefPtr<CefRequestContext> context_;
+ CefRefPtr<CefCookieManager> cookie_manager_;
+
+ CookieAccessServerHandler* server_handler_ = nullptr;
+ CefRefPtr<CookieAccessSchemeHandlerFactory> scheme_factory_;
+
+ CookieAccessData data1_;
+ CookieAccessData data2_;
+
+ // 1st request.
+ int can_save_cookie1_ct_ = 0;
+ int cookie_js1_ct_ = 0;
+ int cookie_net1_ct_ = 0;
+
+ // 2nd request.
+ int can_send_cookie2_ct_ = 0;
+ int cookie_js2_ct_ = 0;
+ int cookie_net2_ct_ = 0;
+
+ // From cookie manager.
+ int cookie_js3_ct_ = 0;
+ int cookie_net3_ct_ = 0;
+
+ DISALLOW_COPY_AND_ASSIGN(CookieAccessTestHandler);
+ IMPLEMENT_REFCOUNTING(CookieAccessTestHandler);
+};
+
+} // namespace
+
+#define ACCESS_TEST(name, test_mode, backend_mode, custom_scheme, use_global) \
+ TEST(CookieTest, Access##name) { \
+ CefRefPtr<CookieAccessTestHandler> handler = new CookieAccessTestHandler( \
+ CookieAccessTestHandler::test_mode, \
+ CookieAccessTestHandler::backend_mode, custom_scheme, use_global); \
+ handler->ExecuteTest(); \
+ ReleaseAndWaitForDestructor(handler); \
+ }
+
+#define ACCESS_TEST_ALL_MODES(name, backend_mode, custom_scheme, use_global) \
+ ACCESS_TEST(name##Allow, ALLOW, backend_mode, custom_scheme, use_global) \
+ ACCESS_TEST(name##AllowNoFilter, ALLOW_NO_FILTER, backend_mode, \
+ custom_scheme, use_global) \
+ ACCESS_TEST(name##BlockRead, BLOCK_READ, backend_mode, custom_scheme, \
+ use_global) \
+ ACCESS_TEST(name##BlockWrite, BLOCK_WRITE, backend_mode, custom_scheme, \
+ use_global) \
+ ACCESS_TEST(name##BlockReadWrite, BLOCK_READ_WRITE, backend_mode, \
+ custom_scheme, use_global)
+
+// These tests only work with a non-global context.
+#define ACCESS_TEST_BLOCKALLCOOKIES_MODES(name, backend_mode, custom_scheme) \
+ ACCESS_TEST(name##BlockAllCookies, BLOCK_ALL_COOKIES, backend_mode, \
+ custom_scheme, false)
+
+// These tests only work with SERVER and SCHEME_HANDLER backends.
+#define ACCESS_TEST_ALLOWNOHANDLER_MODES(name, backend_mode, custom_scheme) \
+ ACCESS_TEST(name##GlobalAllowNoHandler, ALLOW_NO_HANDLER, backend_mode, \
+ custom_scheme, false) \
+ ACCESS_TEST(name##InMemoryAllowNoHandler, ALLOW_NO_HANDLER, backend_mode, \
+ custom_scheme, true)
+
+#define ACCESS_TEST_CUSTOM(name, backend_mode) \
+ ACCESS_TEST_ALL_MODES(name##CustomGlobal, backend_mode, true, true) \
+ ACCESS_TEST_ALL_MODES(name##CustomInMemory, backend_mode, true, false) \
+ ACCESS_TEST_BLOCKALLCOOKIES_MODES(name##CustomInMemory, backend_mode, true)
+
+#define ACCESS_TEST_STANDARD(name, backend_mode) \
+ ACCESS_TEST_ALL_MODES(name##StandardGlobal, backend_mode, false, true) \
+ ACCESS_TEST_ALL_MODES(name##StandardInMemory, backend_mode, false, false) \
+ ACCESS_TEST_BLOCKALLCOOKIES_MODES(name##StandardInMemory, backend_mode, false)
+
+// Server backend only works with standard schemes.
+ACCESS_TEST_STANDARD(Server, SERVER)
+ACCESS_TEST_ALLOWNOHANDLER_MODES(ServerStandard, SERVER, false)
+
+// Other backends work with all schemes.
+ACCESS_TEST_CUSTOM(Scheme, SCHEME_HANDLER)
+ACCESS_TEST_ALLOWNOHANDLER_MODES(SchemeCustom, SCHEME_HANDLER, true)
+ACCESS_TEST_STANDARD(Scheme, SCHEME_HANDLER)
+ACCESS_TEST_ALLOWNOHANDLER_MODES(SchemeStandard, SCHEME_HANDLER, false)
+
+ACCESS_TEST_CUSTOM(Resource, RESOURCE_HANDLER)
+ACCESS_TEST_STANDARD(Resource, RESOURCE_HANDLER)
+
+namespace {
+
+// Tests the behavior of restarting of a network request that sets cookies and
+// a network request that includes cookies.
+// 1. Begin loading URL1, then restart the request in OnResourceResponse.
+// No cookies are saved.
+// 2. Load URL1 successfully. Network and JS cookies are saved.
+// 3. Begin loading URL2, then restart the request in OnResourceResponse.
+// Cookies are sent with the request/response.
+// 4. Load URL2 successfully. Cookies are sent with the request/response.
+class CookieRestartTestHandler : public RoutingTestHandler,
+ public CefCookieAccessFilter {
+ public:
+ explicit CookieRestartTestHandler(bool use_global)
+ : scheme_(GetCookieAccessScheme()), use_global_(use_global) {}
+
+ void RunTest() override {
+ if (use_global_) {
+ context_ = CefRequestContext::GetGlobalContext();
+ } else {
+ // Create the request context that will use an in-memory cache.
+ CefRequestContextSettings settings;
+ context_ = CefRequestContext::CreateContext(settings, nullptr);
+ }
+
+ cookie_manager_ = context_->GetCookieManager(nullptr);
+
+ SetTestTimeout();
+ RunTestSetupContinue();
+ }
+
+ void DestroyTest() override {
+ if (!CefCurrentlyOn(TID_UI)) {
+ CefPostTask(TID_UI,
+ base::BindOnce(&CookieRestartTestHandler::DestroyTest, this));
+ return;
+ }
+
+ cookie_manager_ = nullptr;
+ context_ = nullptr;
+
+ // Get 2 network requests for each URL.
+ EXPECT_EQ(2, data1_.request_ct_);
+ EXPECT_EQ(2, data2_.request_ct_);
+
+ // Get resource request callbacks for all requests (2 for each URL).
+ EXPECT_EQ(4, before_resource_load_ct_);
+ EXPECT_EQ(4, resource_response_ct_);
+
+ // Get JS query callbacks for the successful requests (1 for each URL).
+ EXPECT_EQ(2, query_ct_);
+
+ // No cookies sent for the URL1 network requests because (a) we don't have
+ // any cookies set initially and (b) we don't save cookies from the 1st URL1
+ // request which is restarted.
+ EXPECT_EQ(0, data1_.cookie_js_ct_);
+ EXPECT_EQ(0, data1_.cookie_net_ct_);
+
+ // Net and JS cookies sent for both URL2 network requests.
+ EXPECT_EQ(2, data2_.cookie_js_ct_);
+ EXPECT_EQ(2, data2_.cookie_net_ct_);
+
+ // 1 call to CanSaveCookie for the net cookie returned by the successful
+ // URL1 request.
+ EXPECT_EQ(1, can_save_cookie_ct_);
+ // 4 calls to CanSendCookie because both net and JS cookies are sent for
+ // each URL2 request.
+ EXPECT_EQ(4, can_send_cookie_ct_);
+
+ // Get the net and JS cookies from the JS query for the successful requests
+ // (1 for each URL).
+ EXPECT_EQ(1, cookie_js1_ct_);
+ EXPECT_EQ(1, cookie_net1_ct_);
+ EXPECT_EQ(1, cookie_js2_ct_);
+ EXPECT_EQ(1, cookie_net2_ct_);
+
+ // Get the net and JS cookies from the cookie manager at the end.
+ EXPECT_EQ(1, cookie_manager_js_ct_);
+ EXPECT_EQ(1, cookie_manager_net_ct_);
+
+ TestHandler::DestroyTest();
+ }
+
+ CefRefPtr<CefCookieAccessFilter> GetCookieAccessFilter(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request) override {
+ EXPECT_IO_THREAD();
+ return this;
+ }
+
+ CefRefPtr<CefResourceRequestHandler> GetResourceRequestHandler(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ bool is_navigation,
+ bool is_download,
+ const CefString& request_initiator,
+ bool& disable_default_handling) override {
+ return this;
+ }
+
+ CefRefPtr<CefResourceHandler> GetResourceHandler(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request) override {
+ return nullptr;
+ }
+
+ bool CanSendCookie(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ const CefCookie& cookie) override {
+ EXPECT_IO_THREAD();
+ can_send_cookie_ct_++;
+
+ // Called before the URL2 network requests.
+ EXPECT_LE(2, before_resource_load_ct_);
+
+ return true;
+ }
+
+ bool CanSaveCookie(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response,
+ const CefCookie& cookie) override {
+ EXPECT_IO_THREAD();
+ can_save_cookie_ct_++;
+
+ // Called after the successful URL1 network request.
+ EXPECT_EQ(2, before_resource_load_ct_);
+
+ // Expecting the network cookie only.
+ EXPECT_STREQ("name_net", CefString(&cookie.name).ToString().c_str());
+ EXPECT_STREQ("value_net", CefString(&cookie.value).ToString().c_str());
+
+ return true;
+ }
+
+ cef_return_value_t OnBeforeResourceLoad(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefCallback> callback) override {
+ EXPECT_IO_THREAD();
+ before_resource_load_ct_++;
+
+ const std::string& url = request->GetURL();
+
+ if (before_resource_load_ct_ <= 2) {
+ EXPECT_STREQ(GetCookieAccessUrl1(scheme_, true).c_str(), url.c_str());
+ } else {
+ EXPECT_STREQ(GetCookieAccessUrl2(scheme_, true).c_str(), url.c_str());
+ }
+
+ const std::string& cookie_str = request->GetHeaderByName("Cookie");
+ int cookie_js_ct = 0;
+ int cookie_net_ct = 0;
+ TestCookieString(cookie_str, cookie_js_ct, cookie_net_ct);
+
+ // Expect both cookies with the URL2 requests only.
+ if (before_resource_load_ct_ >= 3) {
+ EXPECT_EQ(1, cookie_js_ct);
+ EXPECT_EQ(1, cookie_net_ct);
+ } else {
+ EXPECT_EQ(0, cookie_js_ct);
+ EXPECT_EQ(0, cookie_net_ct);
+ }
+
+ return RV_CONTINUE;
+ }
+
+ bool OnResourceResponse(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response) override {
+ EXPECT_IO_THREAD();
+ resource_response_ct_++;
+
+ const std::string& url = request->GetURL();
+ const std::string& set_cookie_str = response->GetHeaderByName("Set-Cookie");
+
+ // Expect the network cookie with URL1 requests only.
+ if (resource_response_ct_ <= 2) {
+ EXPECT_STREQ(GetCookieAccessUrl1(scheme_, true).c_str(), url.c_str());
+ EXPECT_STREQ("name_net=value_net", set_cookie_str.c_str());
+ } else {
+ EXPECT_STREQ(GetCookieAccessUrl2(scheme_, true).c_str(), url.c_str());
+ EXPECT_TRUE(set_cookie_str.empty());
+ }
+
+ if (resource_response_ct_ == 1 || resource_response_ct_ == 3) {
+ // Restart the request loading this data.
+ request->SetHeaderByName("X-Custom-Header", "value", false);
+ return true;
+ }
+ return false;
+ }
+
+ bool OnQuery(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int64 query_id,
+ const CefString& request,
+ bool persistent,
+ CefRefPtr<Callback> callback) override {
+ query_ct_++;
+
+ const std::string& url = frame->GetURL();
+ const std::string& cookie_str = request.ToString();
+ if (url == GetCookieAccessUrl1(scheme_, true)) {
+ TestCookieString(cookie_str, cookie_js1_ct_, cookie_net1_ct_);
+ browser->GetMainFrame()->LoadURL(GetCookieAccessUrl2(scheme_, true));
+ } else if (url == GetCookieAccessUrl2(scheme_, true)) {
+ TestCookieString(cookie_str, cookie_js2_ct_, cookie_net2_ct_);
+ FinishTest();
+ } else {
+ ADD_FAILURE() << "Unexpected url: " << url;
+ }
+ return true;
+ }
+
+ private:
+ void AddResponses(CookieAccessResponseHandler* handler) {
+ // Sets a cookie via net response headers and JS, then retrieves the cookies
+ // via JS.
+ {
+ data1_.response = CefResponse::Create();
+ data1_.response->SetMimeType("text/html");
+ data1_.response->SetStatus(200);
+ data1_.response->SetStatusText("OK");
+
+ CefResponse::HeaderMap headerMap;
+ data1_.response->GetHeaderMap(headerMap);
+ headerMap.insert(std::make_pair("Set-Cookie", "name_net=value_net"));
+ data1_.response->SetHeaderMap(headerMap);
+
+ data1_.response_data =
+ "<html><head>"
+ "<script>"
+ "document.cookie='name_js=value_js';"
+ "window.testQuery({request:document.cookie});"
+ "</script>"
+ "</head><body>COOKIE RESTART TEST1</body></html>";
+
+ handler->AddResponse(GetCookieAccessUrl1(scheme_, true), &data1_);
+ }
+
+ // Retrieves the cookies via JS.
+ {
+ data2_.response = CefResponse::Create();
+ data2_.response->SetMimeType("text/html");
+ data2_.response->SetStatus(200);
+ data2_.response->SetStatusText("OK");
+
+ data2_.response_data =
+ "<html><head>"
+ "<script>"
+ "window.testQuery({request:document.cookie});"
+ "</script>"
+ "</head><body>COOKIE RESTART TEST2</body></html>";
+
+ handler->AddResponse(GetCookieAccessUrl2(scheme_, true), &data2_);
+ }
+ }
+
+ void RunTestSetupContinue() {
+ CefPostTask(
+ TID_UI,
+ base::BindOnce(
+ &CookieRestartTestHandler::StartServer, this,
+ base::BindOnce(&CookieRestartTestHandler::RunTestContinue, this)));
+ }
+
+ void StartServer(base::OnceClosure complete_callback) {
+ EXPECT_FALSE(server_handler_);
+
+ server_handler_ = new CookieAccessServerHandler();
+ server_handler_->CreateServer(std::move(complete_callback));
+ }
+
+ void RunTestContinue() {
+ if (!CefCurrentlyOn(TID_UI)) {
+ CefPostTask(
+ TID_UI,
+ base::BindOnce(&CookieRestartTestHandler::RunTestContinue, this));
+ return;
+ }
+
+ AddResponses(server_handler_);
+
+ // 2 requests for each URL.
+ server_handler_->SetExpectedRequestCount(4);
+
+ CreateBrowser(GetCookieAccessUrl1(scheme_, true), context_);
+ }
+
+ void FinishTest() {
+ // Verify that cookies were set correctly.
+ class TestVisitor : public CefCookieVisitor {
+ public:
+ explicit TestVisitor(CookieRestartTestHandler* handler)
+ : handler_(handler) {}
+ ~TestVisitor() override {
+ // Destroy the test.
+ CefPostTask(TID_UI,
+ base::BindOnce(
+ &CookieRestartTestHandler::ShutdownServer, handler_,
+ base::BindOnce(&CookieRestartTestHandler::DestroyTest,
+ handler_)));
+ }
+
+ bool Visit(const CefCookie& cookie,
+ int count,
+ int total,
+ bool& deleteCookie) override {
+ const std::string& name = CefString(&cookie.name);
+ const std::string& value = CefString(&cookie.value);
+ if (name == "name_js" && value == "value_js") {
+ handler_->cookie_manager_js_ct_++;
+ } else if (name == "name_net" && value == "value_net") {
+ handler_->cookie_manager_net_ct_++;
+ }
+
+ // Clean up the cookies.
+ deleteCookie = true;
+
+ return true;
+ }
+
+ private:
+ CookieRestartTestHandler* handler_;
+ IMPLEMENT_REFCOUNTING(TestVisitor);
+ };
+
+ cookie_manager_->VisitAllCookies(new TestVisitor(this));
+ }
+
+ void ShutdownServer(base::OnceClosure complete_callback) {
+ EXPECT_TRUE(server_handler_);
+
+ // |server_handler_| will delete itself after shutdown.
+ server_handler_->ShutdownServer(std::move(complete_callback));
+ server_handler_ = nullptr;
+ }
+
+ const std::string scheme_;
+ const bool use_global_;
+ CefRefPtr<CefRequestContext> context_;
+ CefRefPtr<CefCookieManager> cookie_manager_;
+
+ CookieAccessServerHandler* server_handler_ = nullptr;
+
+ CookieAccessData data1_;
+ CookieAccessData data2_;
+
+ int before_resource_load_ct_ = 0;
+ int resource_response_ct_ = 0;
+ int query_ct_ = 0;
+
+ // From network requests.
+ int can_save_cookie_ct_ = 0;
+ int can_send_cookie_ct_ = 0;
+ int cookie_js1_ct_ = 0;
+ int cookie_net1_ct_ = 0;
+ int cookie_js2_ct_ = 0;
+ int cookie_net2_ct_ = 0;
+
+ // From cookie manager.
+ int cookie_manager_js_ct_ = 0;
+ int cookie_manager_net_ct_ = 0;
+
+ DISALLOW_COPY_AND_ASSIGN(CookieRestartTestHandler);
+ IMPLEMENT_REFCOUNTING(CookieRestartTestHandler);
+};
+
+} // namespace
+
+TEST(CookieTest, RestartGlobal) {
+ CefRefPtr<CookieRestartTestHandler> handler =
+ new CookieRestartTestHandler(true);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(CookieTest, RestartInMemory) {
+ CefRefPtr<CookieRestartTestHandler> handler =
+ new CookieRestartTestHandler(false);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Entry point for registering custom schemes.
+// Called from client_app_delegates.cc.
+void RegisterCookieCustomSchemes(CefRawPtr<CefSchemeRegistrar> registrar) {
+ // Used by GetCookieManagerCustom* tests.
+ registrar->AddCustomScheme(
+ kCustomCookieScheme,
+ CEF_SCHEME_OPTION_STANDARD | CEF_SCHEME_OPTION_CORS_ENABLED);
+}
+
+// Entry point for registering cookieable schemes.
+// Called from client_app_delegates.cc.
+void RegisterCookieCookieableSchemes(
+ std::vector<std::string>& cookieable_schemes) {
+ // Used by GetCookieManagerCustom* tests.
+ cookieable_schemes.push_back(kCustomCookieScheme);
+}
diff --git a/tests/ceftests/cors_unittest.cc b/tests/ceftests/cors_unittest.cc
new file mode 100644
index 00000000..a0be8144
--- /dev/null
+++ b/tests/ceftests/cors_unittest.cc
@@ -0,0 +1,1854 @@
+// Copyright (c) 2020 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include <algorithm>
+#include <set>
+#include <vector>
+
+#include "include/base/cef_callback.h"
+#include "include/cef_callback.h"
+#include "include/cef_origin_whitelist.h"
+#include "include/cef_scheme.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "tests/ceftests/routing_test_handler.h"
+#include "tests/ceftests/test_request.h"
+#include "tests/ceftests/test_server_observer.h"
+#include "tests/ceftests/test_util.h"
+#include "tests/shared/browser/client_app_browser.h"
+
+namespace {
+
+// Browser-side app delegate.
+class CorsBrowserTest : public client::ClientAppBrowser::Delegate {
+ public:
+ CorsBrowserTest() {}
+
+ void OnContextInitialized(CefRefPtr<client::ClientAppBrowser> app) override {
+ if (IsChromeRuntimeEnabled()) {
+ // Disable InsecureFormNavigationThrottle which blocks 307 redirect of
+ // POST requests from HTTPS to custom non-standard scheme causing the
+ // CorsTest.RedirectPost307HttpSchemeToCustomNonStandardScheme test to
+ // fail.
+ CefRefPtr<CefValue> value = CefValue::Create();
+ value->SetBool(false);
+ CefString error;
+ bool result = CefRequestContext::GetGlobalContext()->SetPreference(
+ "profile.mixed_forms_warnings", value, error);
+ CHECK(result) << error.ToString();
+ }
+ }
+
+ private:
+ IMPLEMENT_REFCOUNTING(CorsBrowserTest);
+};
+
+constexpr bool kUseHttpsServerScheme = false;
+
+const char kMimeTypeHtml[] = "text/html";
+const char kMimeTypeText[] = "text/plain";
+
+const char kDefaultHtml[] = "<html><body>TEST</body></html>";
+const char kDefaultText[] = "TEST";
+const char kDefaultCookie[] = "testCookie=testVal";
+
+const char kSuccessMsg[] = "CorsTestHandler.Success";
+const char kFailureMsg[] = "CorsTestHandler.Failure";
+
+// Source that will handle the request.
+enum class HandlerType {
+ SERVER,
+ HTTP_SCHEME,
+ CUSTOM_STANDARD_SCHEME,
+ CUSTOM_NONSTANDARD_SCHEME,
+ CUSTOM_UNREGISTERED_SCHEME,
+};
+
+std::string GetOrigin(HandlerType handler) {
+ switch (handler) {
+ case HandlerType::SERVER:
+ return test_server::GetOrigin(kUseHttpsServerScheme);
+ case HandlerType::HTTP_SCHEME:
+ // Use HTTPS because requests from HTTP to the loopback address will be
+ // blocked by https://chromestatus.com/feature/5436853517811712.
+ return "https://corstest.com";
+ case HandlerType::CUSTOM_STANDARD_SCHEME:
+ // Standard scheme that's registered as CORS and fetch enabled.
+ // Registered in scheme_handler_unittest.cc.
+ return "customstdfetch://corstest";
+ case HandlerType::CUSTOM_NONSTANDARD_SCHEME:
+ // Non-standard schemes are not CORS or fetch enabled.
+ // Registered in scheme_handler_unittest.cc.
+ return "customnonstd:corstest";
+ case HandlerType::CUSTOM_UNREGISTERED_SCHEME:
+ // A scheme that isn't registered anywhere is treated as a non-standard
+ // scheme.
+ return "customstdunregistered://corstest";
+ }
+ NOTREACHED();
+ return std::string();
+}
+
+std::string GetScheme(HandlerType handler) {
+ switch (handler) {
+ case HandlerType::SERVER:
+ return test_server::GetScheme(kUseHttpsServerScheme);
+ case HandlerType::HTTP_SCHEME:
+ return "https";
+ case HandlerType::CUSTOM_STANDARD_SCHEME:
+ return "customstdfetch";
+ case HandlerType::CUSTOM_NONSTANDARD_SCHEME:
+ return "customnonstd";
+ case HandlerType::CUSTOM_UNREGISTERED_SCHEME:
+ return "customstdunregistered";
+ }
+ NOTREACHED();
+ return std::string();
+}
+
+bool IsNonStandardType(HandlerType handler) {
+ return handler == HandlerType::CUSTOM_NONSTANDARD_SCHEME ||
+ handler == HandlerType::CUSTOM_UNREGISTERED_SCHEME;
+}
+
+bool IsStandardType(HandlerType handler) {
+ return !IsNonStandardType(handler);
+}
+
+std::string GetPathURL(HandlerType handler, const std::string& path) {
+ return GetOrigin(handler) + path;
+}
+
+struct Resource {
+ // Uniquely identifies the resource.
+ HandlerType handler = HandlerType::SERVER;
+ std::string path;
+ // If non-empty the method value must match.
+ std::string method;
+
+ // Response information that will be returned.
+ CefRefPtr<CefResponse> response;
+ std::string response_data;
+
+ // Expected error code in OnLoadError.
+ cef_errorcode_t expected_error_code = ERR_NONE;
+
+ // Expected number of responses.
+ int expected_response_ct = 1;
+
+ // Expected number of OnQuery calls.
+ int expected_success_query_ct = 0;
+ int expected_failure_query_ct = 0;
+
+ // Actual number of responses.
+ int response_ct = 0;
+
+ // Actual number of OnQuery calls.
+ int success_query_ct = 0;
+ int failure_query_ct = 0;
+
+ Resource() {}
+ Resource(HandlerType request_handler,
+ const std::string& request_path,
+ const std::string& mime_type = kMimeTypeHtml,
+ const std::string& data = kDefaultHtml,
+ int status = 200) {
+ Init(request_handler, request_path, mime_type, data, status);
+ }
+
+ // Perform basic initialization.
+ void Init(HandlerType request_handler,
+ const std::string& request_path,
+ const std::string& mime_type = kMimeTypeHtml,
+ const std::string& data = kDefaultHtml,
+ int status = 200) {
+ handler = request_handler;
+ path = request_path;
+ response_data = data;
+ response = CefResponse::Create();
+ response->SetMimeType(mime_type);
+ response->SetStatus(status);
+ }
+
+ // Validate expected initial state.
+ void Validate() const {
+ DCHECK(!path.empty());
+ DCHECK(response);
+ DCHECK(!response->GetMimeType().empty());
+ DCHECK_EQ(0, response_ct);
+ DCHECK_GE(expected_response_ct, 0);
+ }
+
+ std::string GetPathURL() const { return ::GetPathURL(handler, path); }
+
+ // Returns true if all expectations have been met.
+ bool IsDone() const {
+ return response_ct == expected_response_ct &&
+ success_query_ct == expected_success_query_ct &&
+ failure_query_ct == expected_failure_query_ct;
+ }
+
+ void AssertDone() const {
+ EXPECT_EQ(expected_response_ct, response_ct) << GetPathURL();
+ EXPECT_EQ(expected_success_query_ct, success_query_ct) << GetPathURL();
+ EXPECT_EQ(expected_failure_query_ct, failure_query_ct) << GetPathURL();
+ }
+
+ // Optionally override to verify request contents.
+ virtual bool VerifyRequest(CefRefPtr<CefRequest> request) const {
+ return true;
+ }
+};
+
+struct TestSetup {
+ // Available resources.
+ typedef std::vector<Resource*> ResourceList;
+ ResourceList resources;
+
+ struct ConsoleMessage {
+ std::string message;
+
+ // Number of times the message was received. All registered messages are
+ // expected at least one time.
+ size_t count = 0;
+ };
+
+ // Used for testing received console messages.
+ std::vector<ConsoleMessage> console_messages;
+
+ // If true cookies will be cleared after every test run.
+ bool clear_cookies = false;
+
+ void AddResource(Resource* resource) {
+ DCHECK(resource);
+ resource->Validate();
+ resources.push_back(resource);
+ }
+
+ void AddConsoleMessage(const std::string& message) {
+ DCHECK(!message.empty());
+ console_messages.push_back({message, 0U});
+ }
+
+ Resource* GetResource(const std::string& url,
+ const std::string& method = std::string()) const {
+ if (resources.empty()) {
+ return nullptr;
+ }
+
+ std::set<std::string> matching_methods;
+ if (method.empty()) {
+ // Match standard HTTP methods.
+ matching_methods.insert("GET");
+ matching_methods.insert("POST");
+ } else {
+ matching_methods.insert(method);
+ }
+
+ const std::string& path_url = test_request::GetPathURL(url);
+ ResourceList::const_iterator it = resources.begin();
+ for (; it != resources.end(); ++it) {
+ Resource* resource = *it;
+ if (resource->GetPathURL() == path_url &&
+ (resource->method.empty() ||
+ matching_methods.find(resource->method) != matching_methods.end())) {
+ return resource;
+ }
+ }
+ return nullptr;
+ }
+
+ Resource* GetResource(CefRefPtr<CefRequest> request) const {
+ return GetResource(request->GetURL(), request->GetMethod());
+ }
+
+ // Optional initialization after the test server is started.
+ virtual void Initialize() {}
+
+ // Validate expected initial state.
+ void Validate() const { DCHECK(!resources.empty()); }
+
+ std::string GetMainURL() const { return resources.front()->GetPathURL(); }
+
+ // Returns true if the server will be used.
+ virtual bool NeedsServer() const {
+ ResourceList::const_iterator it = resources.begin();
+ for (; it != resources.end(); ++it) {
+ Resource* resource = *it;
+ if (resource->handler == HandlerType::SERVER) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // Returns true if all expectations have been met.
+ bool IsDone() const {
+ ResourceList::const_iterator it = resources.begin();
+ for (; it != resources.end(); ++it) {
+ Resource* resource = *it;
+ if (!resource->IsDone()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ void AssertDone() const {
+ ResourceList::const_iterator it = resources.begin();
+ for (; it != resources.end(); ++it) {
+ (*it)->AssertDone();
+ }
+ }
+
+ // Optionally override to verify cleared cookie contents.
+ virtual bool VerifyClearedCookies(
+ const test_request::CookieVector& cookies) const {
+ return true;
+ }
+};
+
+class TestServerObserver : public test_server::ObserverHelper {
+ public:
+ TestServerObserver(TestSetup* setup,
+ base::OnceClosure ready_callback,
+ base::OnceClosure done_callback)
+ : setup_(setup),
+ ready_callback_(std::move(ready_callback)),
+ done_callback_(std::move(done_callback)) {
+ DCHECK(setup);
+ Initialize(kUseHttpsServerScheme);
+ }
+
+ ~TestServerObserver() override { std::move(done_callback_).Run(); }
+
+ void OnInitialized(const std::string& server_origin) override {
+ CEF_REQUIRE_UI_THREAD();
+ std::move(ready_callback_).Run();
+ }
+
+ bool OnTestServerRequest(CefRefPtr<CefRequest> request,
+ const ResponseCallback& response_callback) override {
+ CEF_REQUIRE_UI_THREAD();
+ Resource* resource = setup_->GetResource(request);
+ if (!resource) {
+ // Not a request we handle.
+ return false;
+ }
+
+ resource->response_ct++;
+ EXPECT_TRUE(resource->VerifyRequest(request))
+ << request->GetURL().ToString();
+ response_callback.Run(resource->response, resource->response_data);
+
+ // Stop propagating the callback.
+ return true;
+ }
+
+ void OnShutdown() override {
+ CEF_REQUIRE_UI_THREAD();
+ delete this;
+ }
+
+ private:
+ TestSetup* const setup_;
+ base::OnceClosure ready_callback_;
+ base::OnceClosure done_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestServerObserver);
+};
+
+class CorsTestHandler : public RoutingTestHandler {
+ public:
+ explicit CorsTestHandler(TestSetup* setup) : setup_(setup) {}
+
+ void RunTest() override {
+ StartServer(base::BindOnce(&CorsTestHandler::TriggerCreateBrowser, this));
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout();
+ }
+
+ // Necessary to make the method public in order to destroy the test from
+ // ClientSchemeHandlerType::ProcessRequest().
+ void DestroyTest() override {
+ EXPECT_TRUE(shutting_down_);
+
+ if (setup_->NeedsServer()) {
+ EXPECT_TRUE(got_stopped_server_);
+ } else {
+ EXPECT_FALSE(got_stopped_server_);
+ }
+
+ if (setup_->clear_cookies) {
+ EXPECT_TRUE(got_cleared_cookies_);
+ } else {
+ EXPECT_FALSE(got_cleared_cookies_);
+ }
+
+ setup_->AssertDone();
+ for (const auto& cm : setup_->console_messages) {
+ EXPECT_GT(cm.count, 0U)
+ << "Did not receive expected console message: " << cm.message;
+ }
+
+ RoutingTestHandler::DestroyTest();
+ }
+
+ CefRefPtr<CefResourceHandler> GetResourceHandler(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request) override {
+ CEF_REQUIRE_IO_THREAD();
+ const std::string& url = request->GetURL();
+ const std::string& method = request->GetMethod();
+ if (method == "OPTIONS") {
+ // We should never see the CORS preflight request.
+ ADD_FAILURE() << "Unexpected CORS preflight for " << url;
+ }
+
+ Resource* resource = setup_->GetResource(request);
+ if (resource && resource->handler != HandlerType::SERVER) {
+ resource->response_ct++;
+ EXPECT_TRUE(resource->VerifyRequest(request)) << url;
+ return test_request::CreateResourceHandler(resource->response,
+ resource->response_data);
+ }
+ return RoutingTestHandler::GetResourceHandler(browser, frame, request);
+ }
+
+ void OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int httpStatusCode) override {
+ const std::string& url = frame->GetURL();
+ Resource* resource = GetResource(url);
+ if (!resource) {
+ return;
+ }
+
+ const int expected_status = resource->response->GetStatus();
+ if (url == main_url_ || expected_status != 200) {
+ // Test that the status code is correct.
+ EXPECT_EQ(expected_status, httpStatusCode) << url;
+ }
+
+ TriggerDestroyTestIfDone();
+ }
+
+ void OnLoadError(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ ErrorCode errorCode,
+ const CefString& errorText,
+ const CefString& failedUrl) override {
+ Resource* resource = GetResource(failedUrl);
+ if (!resource) {
+ return;
+ }
+
+ const cef_errorcode_t expected_error = resource->response->GetError();
+
+ // Tests sometimes also fail with ERR_ABORTED.
+ if (!(expected_error == ERR_NONE && errorCode == ERR_ABORTED)) {
+ EXPECT_EQ(expected_error, errorCode) << failedUrl.ToString();
+ }
+
+ TriggerDestroyTestIfDone();
+ }
+
+ bool OnQuery(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int64 query_id,
+ const CefString& request,
+ bool persistent,
+ CefRefPtr<Callback> callback) override {
+ Resource* resource = GetResource(frame->GetURL());
+ if (!resource) {
+ return false;
+ }
+
+ if (request.ToString() == kSuccessMsg ||
+ request.ToString() == kFailureMsg) {
+ callback->Success("");
+ if (request.ToString() == kSuccessMsg) {
+ resource->success_query_ct++;
+ } else {
+ resource->failure_query_ct++;
+ }
+ TriggerDestroyTestIfDone();
+ return true;
+ }
+ return false;
+ }
+
+ bool OnConsoleMessage(CefRefPtr<CefBrowser> browser,
+ cef_log_severity_t level,
+ const CefString& message,
+ const CefString& source,
+ int line) override {
+ bool expected = false;
+ if (!setup_->console_messages.empty()) {
+ const std::string& actual = message.ToString();
+ for (auto& cm : setup_->console_messages) {
+ if (actual.find(cm.message) == 0U) {
+ expected = true;
+ cm.count++;
+ break;
+ }
+ }
+ }
+
+ EXPECT_TRUE(expected) << "Unexpected console message: "
+ << message.ToString();
+ return false;
+ }
+
+ protected:
+ void TriggerCreateBrowser() {
+ setup_->Initialize();
+ setup_->Validate();
+
+ main_url_ = setup_->GetMainURL();
+ CreateBrowser(main_url_);
+ }
+
+ void TriggerDestroyTestIfDone() {
+ CefPostTask(TID_UI,
+ base::BindOnce(&CorsTestHandler::DestroyTestIfDone, this));
+ }
+
+ void DestroyTestIfDone() {
+ CEF_REQUIRE_UI_THREAD();
+ if (shutting_down_) {
+ return;
+ }
+
+ if (setup_->IsDone()) {
+ shutting_down_ = true;
+ StopServer();
+ }
+ }
+
+ void StartServer(base::OnceClosure next_step) {
+ if (!CefCurrentlyOn(TID_UI)) {
+ CefPostTask(TID_UI, base::BindOnce(&CorsTestHandler::StartServer, this,
+ std::move(next_step)));
+ return;
+ }
+
+ if (!setup_->NeedsServer()) {
+ std::move(next_step).Run();
+ return;
+ }
+
+ // Will delete itself after the server stops.
+ server_ = new TestServerObserver(
+ setup_, std::move(next_step),
+ base::BindOnce(&CorsTestHandler::StoppedServer, this));
+ }
+
+ void StopServer() {
+ CEF_REQUIRE_UI_THREAD();
+ if (!server_) {
+ DCHECK(!setup_->NeedsServer());
+ AfterStoppedServer();
+ return;
+ }
+
+ // Results in a call to StoppedServer().
+ server_->Shutdown();
+ }
+
+ void StoppedServer() {
+ CEF_REQUIRE_UI_THREAD();
+ got_stopped_server_.yes();
+ server_ = nullptr;
+ AfterStoppedServer();
+ }
+
+ void AfterStoppedServer() {
+ CEF_REQUIRE_UI_THREAD();
+ if (setup_->clear_cookies) {
+ ClearCookies();
+ } else {
+ DestroyTest();
+ }
+ }
+
+ void ClearCookies() {
+ CEF_REQUIRE_UI_THREAD();
+ DCHECK(setup_->clear_cookies);
+ test_request::GetAllCookies(
+ CefCookieManager::GetGlobalManager(nullptr), /*delete_cookies=*/true,
+ base::BindOnce(&CorsTestHandler::ClearedCookies, this));
+ }
+
+ void ClearedCookies(const test_request::CookieVector& cookies) {
+ CEF_REQUIRE_UI_THREAD();
+ got_cleared_cookies_.yes();
+ EXPECT_TRUE(setup_->VerifyClearedCookies(cookies));
+ DestroyTest();
+ }
+
+ Resource* GetResource(const std::string& url) const {
+ Resource* resource = setup_->GetResource(url);
+ EXPECT_TRUE(resource) << url;
+ return resource;
+ }
+
+ TestSetup* setup_;
+ std::string main_url_;
+ TestServerObserver* server_ = nullptr;
+ bool shutting_down_ = false;
+
+ TrackCallback got_stopped_server_;
+ TrackCallback got_cleared_cookies_;
+
+ IMPLEMENT_REFCOUNTING(CorsTestHandler);
+ DISALLOW_COPY_AND_ASSIGN(CorsTestHandler);
+};
+
+// JS that results in a call to CorsTestHandler::OnQuery.
+std::string GetMsgJS(const std::string& msg) {
+ return "window.testQuery({request:'" + msg + "'});";
+}
+
+std::string GetSuccessMsgJS() {
+ return GetMsgJS(kSuccessMsg);
+}
+std::string GetFailureMsgJS() {
+ return GetMsgJS(kFailureMsg);
+}
+
+std::string GetDefaultSuccessMsgHtml() {
+ return "<html><body>TEST<script>" + GetSuccessMsgJS() +
+ "</script></body></html>";
+}
+
+} // namespace
+
+// Verify the test harness for server requests.
+TEST(CorsTest, BasicServer) {
+ TestSetup setup;
+ Resource resource(HandlerType::SERVER, "/CorsTest.BasicServer");
+ setup.AddResource(&resource);
+
+ CefRefPtr<CorsTestHandler> handler = new CorsTestHandler(&setup);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Like above, but also send a query JS message.
+TEST(CorsTest, BasicServerWithQuery) {
+ TestSetup setup;
+ Resource resource(HandlerType::SERVER, "/CorsTest.BasicServerWithQuery",
+ kMimeTypeHtml, GetDefaultSuccessMsgHtml());
+ resource.expected_success_query_ct = 1;
+ setup.AddResource(&resource);
+
+ CefRefPtr<CorsTestHandler> handler = new CorsTestHandler(&setup);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Verify the test harness for http scheme requests.
+TEST(CorsTest, BasicHttpScheme) {
+ TestSetup setup;
+ Resource resource(HandlerType::HTTP_SCHEME, "/CorsTest.BasicHttpScheme");
+ setup.AddResource(&resource);
+
+ CefRefPtr<CorsTestHandler> handler = new CorsTestHandler(&setup);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Like above, but also send a query JS message.
+TEST(CorsTest, BasicHttpSchemeWithQuery) {
+ TestSetup setup;
+ Resource resource(HandlerType::HTTP_SCHEME,
+ "/CorsTest.BasicHttpSchemeWithQuery", kMimeTypeHtml,
+ GetDefaultSuccessMsgHtml());
+ resource.expected_success_query_ct = 1;
+ setup.AddResource(&resource);
+
+ CefRefPtr<CorsTestHandler> handler = new CorsTestHandler(&setup);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Verify the test harness for custom standard scheme requests.
+TEST(CorsTest, BasicCustomStandardScheme) {
+ TestSetup setup;
+ Resource resource(HandlerType::CUSTOM_STANDARD_SCHEME,
+ "/CorsTest.BasicCustomStandardScheme");
+ setup.AddResource(&resource);
+
+ CefRefPtr<CorsTestHandler> handler = new CorsTestHandler(&setup);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Like above, but also send a query JS message.
+TEST(CorsTest, BasicCustomStandardSchemeWithQuery) {
+ TestSetup setup;
+ Resource resource(HandlerType::CUSTOM_STANDARD_SCHEME,
+ "/CorsTest.BasicCustomStandardSchemeWithQuery",
+ kMimeTypeHtml, GetDefaultSuccessMsgHtml());
+ resource.expected_success_query_ct = 1;
+ setup.AddResource(&resource);
+
+ CefRefPtr<CorsTestHandler> handler = new CorsTestHandler(&setup);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+namespace {
+
+struct CookieTestSetup : TestSetup {
+ CookieTestSetup() {}
+
+ bool expect_cookie = false;
+
+ bool VerifyClearedCookies(
+ const test_request::CookieVector& cookies) const override {
+ if (!expect_cookie) {
+ EXPECT_TRUE(cookies.empty());
+ return cookies.empty();
+ }
+
+ EXPECT_EQ(1U, cookies.size());
+ const std::string& cookie = CefString(&cookies[0].name).ToString() + "=" +
+ CefString(&cookies[0].value).ToString();
+ EXPECT_STREQ(kDefaultCookie, cookie.c_str());
+ return cookie == kDefaultCookie;
+ }
+};
+
+struct CookieResource : Resource {
+ CookieResource() {}
+
+ bool expect_cookie = false;
+
+ void InitSetCookie() {
+ response->SetHeaderByName("Set-Cookie", kDefaultCookie,
+ /*override=*/true);
+ }
+
+ bool VerifyRequest(CefRefPtr<CefRequest> request) const override {
+ const std::string& cookie = request->GetHeaderByName("Cookie");
+ const std::string& expected_cookie =
+ expect_cookie ? kDefaultCookie : std::string();
+ EXPECT_STREQ(expected_cookie.c_str(), cookie.c_str()) << GetPathURL();
+ return expected_cookie == cookie;
+ }
+};
+
+void SetupCookieExpectations(CookieTestSetup* setup,
+ CookieResource* main_resource,
+ CookieResource* sub_resource) {
+ // All schemes except custom non-standard support cookies.
+ const bool supports_cookies = IsStandardType(main_resource->handler);
+
+ // The main resource may set the cookie (if cookies are supported), but should
+ // not receive one.
+ main_resource->InitSetCookie();
+ main_resource->expect_cookie = false;
+
+ // A cookie will be set only for schemes that support cookies.
+ setup->expect_cookie = supports_cookies;
+ // Always clear cookies so we can verify that one wasn't set unexpectedly.
+ setup->clear_cookies = true;
+
+ // Expect the sub-resource to receive the cookie for same-origin requests
+ // only.
+ sub_resource->expect_cookie =
+ supports_cookies && main_resource->handler == sub_resource->handler;
+}
+
+std::string GetIframeMainHtml(const std::string& iframe_url,
+ const std::string& sandbox_attribs) {
+ return "<html><body>TEST<iframe src=\"" + iframe_url + "\" sandbox=\"" +
+ sandbox_attribs + "\"></iframe></body></html>";
+}
+
+std::string GetIframeSubHtml() {
+ // Try to script the parent frame, then send the SuccessMsg.
+ return "<html><body>TEST<script>try { parent.document.body; } catch "
+ "(exception) { console.log(exception.toString()); }" +
+ GetSuccessMsgJS() + "</script></body></html>";
+}
+
+bool HasSandboxAttrib(const std::string& sandbox_attribs,
+ const std::string& attrib) {
+ return sandbox_attribs.find(attrib) != std::string::npos;
+}
+
+void SetupIframeRequest(CookieTestSetup* setup,
+ const std::string& test_name,
+ HandlerType main_handler,
+ CookieResource* main_resource,
+ HandlerType iframe_handler,
+ CookieResource* iframe_resource,
+ const std::string& sandbox_attribs) {
+ const std::string& base_path = "/" + test_name;
+
+ // Expect a single iframe request.
+ iframe_resource->Init(iframe_handler, base_path + ".iframe.html",
+ kMimeTypeHtml, GetIframeSubHtml());
+
+ // Expect a single main frame request.
+ const std::string& iframe_url = iframe_resource->GetPathURL();
+ main_resource->Init(main_handler, base_path, kMimeTypeHtml,
+ GetIframeMainHtml(iframe_url, sandbox_attribs));
+
+ SetupCookieExpectations(setup, main_resource, iframe_resource);
+
+ if (HasSandboxAttrib(sandbox_attribs, "allow-scripts")) {
+ // Expect the iframe to load successfully and send the SuccessMsg.
+ iframe_resource->expected_success_query_ct = 1;
+
+ const bool has_same_origin =
+ HasSandboxAttrib(sandbox_attribs, "allow-same-origin");
+ if (!has_same_origin ||
+ (has_same_origin &&
+ (IsNonStandardType(main_handler) || main_handler != iframe_handler))) {
+ // Expect parent frame scripting to fail if:
+ // - "allow-same-origin" is not specified;
+ // - the main frame is a non-standard scheme (e.g. CORS disabled);
+ // - the main frame and iframe origins don't match.
+ // The reported origin will be "null" if "allow-same-origin" is not
+ // specified, or if the iframe is hosted on a non-standard scheme.
+ const std::string& origin =
+ !has_same_origin || IsNonStandardType(iframe_handler)
+ ? "null"
+ : GetOrigin(iframe_handler);
+ setup->AddConsoleMessage("SecurityError: Blocked a frame with origin \"" +
+ origin +
+ "\" from accessing a cross-origin frame.");
+ }
+
+ if (has_same_origin && main_handler == iframe_handler &&
+ IsStandardType(main_handler)) {
+ setup->AddConsoleMessage(
+ "An iframe which has both allow-scripts and allow-same-origin for "
+ "its sandbox attribute can remove its sandboxing.");
+ }
+ } else {
+ // Expect JavaScript execution to fail.
+ setup->AddConsoleMessage("Blocked script execution in '" + iframe_url +
+ "' because the document's frame is sandboxed and "
+ "the 'allow-scripts' permission is not set.");
+ }
+
+ setup->AddResource(main_resource);
+ setup->AddResource(iframe_resource);
+}
+
+struct IframeTestSetup : CookieTestSetup {
+ IframeTestSetup(const std::string& test_name,
+ HandlerType main_handler,
+ HandlerType iframe_handler,
+ const std::string& sandbox_attribs)
+ : test_name_(test_name),
+ main_handler_(main_handler),
+ iframe_handler_(iframe_handler),
+ sandbox_attribs_(sandbox_attribs) {}
+
+ bool NeedsServer() const override {
+ return main_handler_ == HandlerType::SERVER ||
+ iframe_handler_ == HandlerType::SERVER;
+ }
+
+ void Initialize() override {
+ SetupIframeRequest(this, test_name_, main_handler_, &resource_main_,
+ iframe_handler_, &resource_iframe_, sandbox_attribs_);
+ }
+
+ private:
+ const std::string test_name_;
+ const HandlerType main_handler_;
+ const HandlerType iframe_handler_;
+ const std::string sandbox_attribs_;
+
+ CookieResource resource_main_;
+ CookieResource resource_iframe_;
+};
+
+} // namespace
+
+// Test iframe sandbox attributes with different origin combinations.
+#define CORS_TEST_IFRAME(test_name, handler_main, handler_iframe, \
+ sandbox_attribs) \
+ TEST(CorsTest, Iframe##test_name) { \
+ IframeTestSetup setup("CorsTest.Iframe" #test_name, \
+ HandlerType::handler_main, \
+ HandlerType::handler_iframe, sandbox_attribs); \
+ CefRefPtr<CorsTestHandler> handler = new CorsTestHandler(&setup); \
+ handler->ExecuteTest(); \
+ ReleaseAndWaitForDestructor(handler); \
+ }
+
+// Test all origin combinations (same and cross-origin).
+#define CORS_TEST_IFRAME_ALL(name, sandbox_attribs) \
+ CORS_TEST_IFRAME(name##ServerToServer, SERVER, SERVER, sandbox_attribs) \
+ CORS_TEST_IFRAME(name##ServerToHttpScheme, SERVER, HTTP_SCHEME, \
+ sandbox_attribs) \
+ CORS_TEST_IFRAME(name##ServerToCustomStandardScheme, SERVER, \
+ CUSTOM_STANDARD_SCHEME, sandbox_attribs) \
+ CORS_TEST_IFRAME(name##ServerToCustomNonStandardScheme, SERVER, \
+ CUSTOM_NONSTANDARD_SCHEME, sandbox_attribs) \
+ CORS_TEST_IFRAME(name##ServerToCustomUnregisteredScheme, SERVER, \
+ CUSTOM_UNREGISTERED_SCHEME, sandbox_attribs) \
+ CORS_TEST_IFRAME(name##HttpSchemeToServer, HTTP_SCHEME, SERVER, \
+ sandbox_attribs) \
+ CORS_TEST_IFRAME(name##HttpSchemeToHttpScheme, HTTP_SCHEME, HTTP_SCHEME, \
+ sandbox_attribs) \
+ CORS_TEST_IFRAME(name##HttpSchemeToCustomStandardScheme, HTTP_SCHEME, \
+ CUSTOM_STANDARD_SCHEME, sandbox_attribs) \
+ CORS_TEST_IFRAME(name##HttpSchemeToCustomNonStandardScheme, HTTP_SCHEME, \
+ CUSTOM_NONSTANDARD_SCHEME, sandbox_attribs) \
+ CORS_TEST_IFRAME(name##HttpSchemeToCustomUnregisteredScheme, HTTP_SCHEME, \
+ CUSTOM_UNREGISTERED_SCHEME, sandbox_attribs) \
+ CORS_TEST_IFRAME(name##CustomStandardSchemeToServer, CUSTOM_STANDARD_SCHEME, \
+ SERVER, sandbox_attribs) \
+ CORS_TEST_IFRAME(name##CustomStandardSchemeToHttpScheme, \
+ CUSTOM_STANDARD_SCHEME, HTTP_SCHEME, sandbox_attribs) \
+ CORS_TEST_IFRAME(name##CustomStandardSchemeToCustomStandardScheme, \
+ CUSTOM_STANDARD_SCHEME, CUSTOM_STANDARD_SCHEME, \
+ sandbox_attribs) \
+ CORS_TEST_IFRAME(name##CustomStandardSchemeToCustomNonStandardScheme, \
+ CUSTOM_STANDARD_SCHEME, CUSTOM_NONSTANDARD_SCHEME, \
+ sandbox_attribs) \
+ CORS_TEST_IFRAME(name##CustomStandardSchemeToCustomUnregisteredScheme, \
+ CUSTOM_STANDARD_SCHEME, CUSTOM_UNREGISTERED_SCHEME, \
+ sandbox_attribs) \
+ CORS_TEST_IFRAME(name##CustomNonStandardSchemeToServer, \
+ CUSTOM_NONSTANDARD_SCHEME, SERVER, sandbox_attribs) \
+ CORS_TEST_IFRAME(name##CustomNonStandardSchemeToHttpScheme, \
+ CUSTOM_NONSTANDARD_SCHEME, HTTP_SCHEME, sandbox_attribs) \
+ CORS_TEST_IFRAME(name##CustomNonStandardSchemeToCustomStandardScheme, \
+ CUSTOM_NONSTANDARD_SCHEME, CUSTOM_STANDARD_SCHEME, \
+ sandbox_attribs) \
+ CORS_TEST_IFRAME(name##CustomNonStandardSchemeToCustomNonStandardScheme, \
+ CUSTOM_NONSTANDARD_SCHEME, CUSTOM_NONSTANDARD_SCHEME, \
+ sandbox_attribs) \
+ CORS_TEST_IFRAME(name##CustomNonStandardSchemeToCustomUnregisteredScheme, \
+ CUSTOM_NONSTANDARD_SCHEME, CUSTOM_UNREGISTERED_SCHEME, \
+ sandbox_attribs) \
+ CORS_TEST_IFRAME(name##CustomUnregisteredSchemeToServer, \
+ CUSTOM_UNREGISTERED_SCHEME, SERVER, sandbox_attribs) \
+ CORS_TEST_IFRAME(name##CustomUnregisteredSchemeToHttpScheme, \
+ CUSTOM_UNREGISTERED_SCHEME, HTTP_SCHEME, sandbox_attribs) \
+ CORS_TEST_IFRAME(name##CustomUnregisteredSchemeToCustomStandardScheme, \
+ CUSTOM_UNREGISTERED_SCHEME, CUSTOM_STANDARD_SCHEME, \
+ sandbox_attribs) \
+ CORS_TEST_IFRAME(name##CustomUnregisteredSchemeToCustomNonStandardScheme, \
+ CUSTOM_UNREGISTERED_SCHEME, CUSTOM_NONSTANDARD_SCHEME, \
+ sandbox_attribs) \
+ CORS_TEST_IFRAME(name##CustomUnregisteredSchemeToCustomUnregisteredScheme, \
+ CUSTOM_UNREGISTERED_SCHEME, CUSTOM_UNREGISTERED_SCHEME, \
+ sandbox_attribs)
+
+// Everything is blocked.
+CORS_TEST_IFRAME_ALL(None, "")
+
+// JavaScript execution is allowed.
+CORS_TEST_IFRAME_ALL(AllowScripts, "allow-scripts")
+
+// JavaScript execution is allowed and scripting the parent is allowed for
+// same-origin only.
+CORS_TEST_IFRAME_ALL(AllowScriptsAndSameOrigin,
+ "allow-scripts allow-same-origin")
+
+namespace {
+
+const char kSubRequestMethod[] = "GET";
+const char kSubUnsafeHeaderName[] = "x-unsafe-header";
+const char kSubUnsafeHeaderValue[] = "not-safe";
+
+struct SubResource : CookieResource {
+ SubResource() {}
+
+ std::string main_origin;
+ bool supports_cors = false;
+ bool is_cross_origin = false;
+
+ void InitCors(HandlerType main_handler, bool add_header) {
+ // Must specify the method to differentiate from the preflight request.
+ method = kSubRequestMethod;
+
+ // Origin is always "null" for non-standard schemes.
+ main_origin =
+ IsNonStandardType(main_handler) ? "null" : GetOrigin(main_handler);
+
+ // True if cross-origin requests are allowed. XHR requests to non-standard
+ // schemes are not allowed (due to the "null" origin).
+ supports_cors = IsStandardType(handler);
+ if (!supports_cors) {
+ // Don't expect the xhr request.
+ expected_response_ct = 0;
+ }
+
+ // True if the request is considered cross-origin. Any requests between
+ // non-standard schemes are considered cross-origin (due to the "null"
+ // origin).
+ is_cross_origin =
+ main_handler != handler ||
+ (IsNonStandardType(main_handler) && handler == main_handler);
+
+ if (is_cross_origin && add_header) {
+ response->SetHeaderByName("Access-Control-Allow-Origin", main_origin,
+ false);
+ }
+ }
+
+ bool VerifyRequest(CefRefPtr<CefRequest> request) const override {
+ if (!CookieResource::VerifyRequest(request)) {
+ return false;
+ }
+
+ const std::string& request_method = request->GetMethod();
+ EXPECT_STREQ(method.c_str(), request_method.c_str()) << GetPathURL();
+ if (request_method != method) {
+ return false;
+ }
+
+ // Verify that the "Origin" header contains the expected value.
+ const std::string& origin = request->GetHeaderByName("Origin");
+ const std::string& expected_origin =
+ is_cross_origin ? main_origin : std::string();
+ EXPECT_STREQ(expected_origin.c_str(), origin.c_str()) << GetPathURL();
+ if (expected_origin != origin) {
+ return false;
+ }
+
+ // Verify that the "X-Unsafe-Header" header contains the expected value.
+ const std::string& unsafe_header =
+ request->GetHeaderByName(kSubUnsafeHeaderName);
+ EXPECT_STREQ(kSubUnsafeHeaderValue, unsafe_header.c_str()) << GetPathURL();
+ return unsafe_header == kSubUnsafeHeaderValue;
+ }
+};
+
+// See https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request
+// for details of CORS preflight behavior.
+struct PreflightResource : Resource {
+ std::string main_origin;
+
+ void InitPreflight(HandlerType main_handler) {
+ // CORS preflight requests originate from PreflightController in the network
+ // process, so we only expect them for server requests.
+ EXPECT_EQ(HandlerType::SERVER, handler);
+
+ // Origin is always "null" for non-standard schemes.
+ main_origin =
+ IsNonStandardType(main_handler) ? "null" : GetOrigin(main_handler);
+
+ method = "OPTIONS";
+ response->SetHeaderByName("Access-Control-Allow-Methods",
+ "GET,HEAD,OPTIONS,POST", false);
+ response->SetHeaderByName("Access-Control-Allow-Headers",
+ kSubUnsafeHeaderName, false);
+ response->SetHeaderByName("Access-Control-Allow-Origin", main_origin,
+ false);
+ }
+
+ bool VerifyRequest(CefRefPtr<CefRequest> request) const override {
+ const std::string& request_method = request->GetMethod();
+ EXPECT_STREQ(method.c_str(), request_method.c_str()) << GetPathURL();
+ if (request_method != method) {
+ return false;
+ }
+
+ const std::string& origin = request->GetHeaderByName("Origin");
+ EXPECT_STREQ(main_origin.c_str(), origin.c_str()) << GetPathURL();
+ if (main_origin != origin) {
+ return false;
+ }
+
+ const std::string& ac_request_method =
+ request->GetHeaderByName("Access-Control-Request-Method");
+ EXPECT_STREQ(kSubRequestMethod, ac_request_method.c_str()) << GetPathURL();
+ if (ac_request_method != kSubRequestMethod) {
+ return false;
+ }
+
+ const std::string& ac_request_headers =
+ request->GetHeaderByName("Access-Control-Request-Headers");
+ EXPECT_STREQ(kSubUnsafeHeaderName, ac_request_headers.c_str())
+ << GetPathURL();
+ if (ac_request_headers != kSubUnsafeHeaderName) {
+ return false;
+ }
+
+ return true;
+ }
+};
+
+enum class ExecMode {
+ XHR,
+ FETCH,
+};
+
+std::string GetXhrExecJS(const std::string& sub_url) {
+ // Inclusion of an unsafe header triggers CORS preflight for cross-origin
+ // requests to the server.
+ return "xhr = new XMLHttpRequest();\n"
+ "xhr.open(\"GET\", \"" +
+ sub_url +
+ "\", true)\n;"
+ "xhr.setRequestHeader('" +
+ kSubUnsafeHeaderName + "', '" + kSubUnsafeHeaderValue +
+ "');\n"
+ "xhr.onload = function(e) {\n"
+ " if (xhr.readyState === 4) {\n"
+ " if (xhr.status === 200) {\n"
+ " onResult(xhr.responseText);\n"
+ " } else {\n"
+ " console.log('XMLHttpRequest failed with status ' + "
+ "xhr.status);\n"
+ " onResult('FAILURE');\n"
+ " }\n"
+ " }\n"
+ "};\n"
+ "xhr.onerror = function(e) {\n"
+ " onResult('FAILURE');\n"
+ "};\n"
+ "xhr.send();\n";
+}
+
+std::string GetFetchExecJS(const std::string& sub_url) {
+ // Inclusion of an unsafe header triggers CORS preflight for cross-origin
+ // requests to the server.
+ return std::string() +
+ "let h = new Headers();\n"
+ "h.append('" +
+ kSubUnsafeHeaderName + "', '" + kSubUnsafeHeaderValue +
+ "');\n"
+ "fetch('" +
+ sub_url +
+ "', {headers: h})\n"
+ ".then(function(response) {\n"
+ " if (response.status === 200) {\n"
+ " response.text().then(function(text) {\n"
+ " onResult(text);\n"
+ " }).catch(function(e) {\n"
+ " onResult('FAILURE')\n; "
+ " })\n;"
+ " } else {\n"
+ " onResult('FAILURE');\n"
+ " }\n"
+ "}).catch(function(e) {\n"
+ " onResult('FAILURE');\n"
+ "});\n";
+}
+
+std::string GetExecMainHtml(ExecMode mode, const std::string& sub_url) {
+ return std::string() +
+ "<html><head>\n"
+ "<script language=\"JavaScript\">\n" +
+ "function onResult(val) {\n"
+ " if (val === '" +
+ kDefaultText + "') {" + GetSuccessMsgJS() + "} else {" +
+ GetFailureMsgJS() +
+ "}\n}\n"
+ "function execRequest() {\n" +
+ (mode == ExecMode::XHR ? GetXhrExecJS(sub_url)
+ : GetFetchExecJS(sub_url)) +
+ "}\n</script>\n"
+ "</head><body onload=\"execRequest();\">"
+ "Running execRequest..."
+ "</body></html>";
+}
+
+// XHR and fetch requests behave the same, except for console message contents.
+// In addition to basic CORS header behaviors and request blocking, this test
+// verifies that CORS preflight requests are sent and received when expected.
+// Since preflight behavior is implemented in the network process we expect it
+// to already have substantial test coverage in Chromium.
+void SetupExecRequest(ExecMode mode,
+ CookieTestSetup* setup,
+ const std::string& test_name,
+ HandlerType main_handler,
+ CookieResource* main_resource,
+ HandlerType sub_handler,
+ SubResource* sub_resource,
+ PreflightResource* preflight_resource,
+ bool add_header) {
+ const std::string& base_path = "/" + test_name;
+
+ // Expect a single xhr request.
+ const std::string& sub_path = base_path + ".sub.txt";
+ sub_resource->Init(sub_handler, sub_path, kMimeTypeText, kDefaultText);
+ sub_resource->InitCors(main_handler, add_header);
+
+ // Expect a single main frame request.
+ const std::string& sub_url = sub_resource->GetPathURL();
+ main_resource->Init(main_handler, base_path, kMimeTypeHtml,
+ GetExecMainHtml(mode, sub_url));
+
+ SetupCookieExpectations(setup, main_resource, sub_resource);
+
+ // Cross-origin requests to a server sub-resource will receive a CORS
+ // preflight request because we add an unsafe header.
+ const bool expect_cors_preflight =
+ sub_resource->is_cross_origin && sub_handler == HandlerType::SERVER;
+
+ if (sub_resource->is_cross_origin &&
+ (!sub_resource->supports_cors || !add_header)) {
+ // Expect the cross-origin XHR to be blocked.
+ main_resource->expected_failure_query_ct = 1;
+
+ if (sub_resource->supports_cors && !add_header) {
+ // The request supports CORS, but we didn't add the
+ // "Access-Control-Allow-Origin" header.
+ if (!expect_cors_preflight || preflight_resource != nullptr) {
+ // This is the error message when not expecting a CORS preflight
+ // request, or when the preflight request is handled by the server.
+ // Unhandled preflight requests will output a different error message
+ // (see below).
+ if (mode == ExecMode::XHR) {
+ setup->AddConsoleMessage(
+ "Access to XMLHttpRequest at '" + sub_url + "' from origin '" +
+ sub_resource->main_origin +
+ "' has been blocked by CORS policy: No "
+ "'Access-Control-Allow-Origin' "
+ "header is present on the requested resource.");
+ } else {
+ setup->AddConsoleMessage(
+ "Access to fetch at '" + sub_url + "' from origin '" +
+ sub_resource->main_origin +
+ "' has been blocked by CORS policy: No "
+ "'Access-Control-Allow-Origin' header is present on the "
+ "requested "
+ "resource. If an opaque response serves your needs, set the "
+ "request's mode to 'no-cors' to fetch the resource with CORS "
+ "disabled.");
+ }
+ }
+ } else if (mode == ExecMode::XHR) {
+ setup->AddConsoleMessage(
+ "Access to XMLHttpRequest at '" + sub_url + "' from origin '" +
+ sub_resource->main_origin +
+ "' has been blocked by CORS policy: Cross origin requests are only "
+ "supported for protocol schemes:");
+ } else {
+ setup->AddConsoleMessage("Fetch API cannot load " + sub_url +
+ ". URL scheme \"" + GetScheme(sub_handler) +
+ "\" is not supported.");
+ }
+ } else {
+ // Expect the (possibly cross-origin) XHR to be allowed.
+ main_resource->expected_success_query_ct = 1;
+ }
+
+ setup->AddResource(main_resource);
+ setup->AddResource(sub_resource);
+
+ if (expect_cors_preflight) {
+ // Expect a CORS preflight request.
+ if (preflight_resource) {
+ // The server will handle the preflight request. The cross-origin XHR may
+ // still be blocked if the "Access-Control-Allow-Origin" header is missing
+ // (see above).
+ preflight_resource->Init(sub_handler, sub_path, kMimeTypeText,
+ std::string());
+ preflight_resource->InitPreflight(main_handler);
+ setup->AddResource(preflight_resource);
+ } else {
+ // The server will not handle the preflight request. Expect the
+ // cross-origin XHR to be blocked.
+ main_resource->expected_failure_query_ct = 1;
+ main_resource->expected_success_query_ct = 0;
+ sub_resource->expected_response_ct = 0;
+
+ if (mode == ExecMode::XHR) {
+ setup->AddConsoleMessage(
+ "Access to XMLHttpRequest at '" + sub_url + "' from origin '" +
+ sub_resource->main_origin +
+ "' has been blocked by CORS policy: Response to preflight request "
+ "doesn't pass access control check: No "
+ "'Access-Control-Allow-Origin' header is present on the requested "
+ "resource.");
+ } else {
+ setup->AddConsoleMessage(
+ "Access to fetch at '" + sub_url + "' from origin '" +
+ sub_resource->main_origin +
+ "' has been blocked by CORS policy: Response to preflight request "
+ "doesn't pass access control check: No "
+ "'Access-Control-Allow-Origin' header is present on the requested "
+ "resource. If an opaque response serves your needs, set the "
+ "request's mode to 'no-cors' to fetch the resource with CORS "
+ "disabled.");
+ }
+ }
+ }
+}
+
+} // namespace
+
+// Test XHR requests with different origin combinations.
+#define CORS_TEST_XHR(test_name, handler_main, handler_sub, add_header) \
+ TEST(CorsTest, Xhr##test_name) { \
+ CookieTestSetup setup; \
+ CookieResource resource_main; \
+ SubResource resource_sub; \
+ PreflightResource resource_preflight; \
+ SetupExecRequest(ExecMode::XHR, &setup, "CorsTest.Xhr" #test_name, \
+ HandlerType::handler_main, &resource_main, \
+ HandlerType::handler_sub, &resource_sub, \
+ &resource_preflight, add_header); \
+ CefRefPtr<CorsTestHandler> handler = new CorsTestHandler(&setup); \
+ handler->ExecuteTest(); \
+ ReleaseAndWaitForDestructor(handler); \
+ }
+
+// Test all origin combinations (same and cross-origin).
+#define CORS_TEST_XHR_ALL(name, add_header) \
+ CORS_TEST_XHR(name##ServerToServer, SERVER, SERVER, add_header) \
+ CORS_TEST_XHR(name##ServerToHttpScheme, SERVER, HTTP_SCHEME, add_header) \
+ CORS_TEST_XHR(name##ServerToCustomStandardScheme, SERVER, \
+ CUSTOM_STANDARD_SCHEME, add_header) \
+ CORS_TEST_XHR(name##ServerToCustomNonStandardScheme, SERVER, \
+ CUSTOM_NONSTANDARD_SCHEME, add_header) \
+ CORS_TEST_XHR(name##ServerToCustomUnregisteredScheme, SERVER, \
+ CUSTOM_UNREGISTERED_SCHEME, add_header) \
+ CORS_TEST_XHR(name##HttpSchemeToServer, HTTP_SCHEME, SERVER, add_header) \
+ CORS_TEST_XHR(name##HttpSchemeToHttpScheme, HTTP_SCHEME, HTTP_SCHEME, \
+ add_header) \
+ CORS_TEST_XHR(name##HttpSchemeToCustomStandardScheme, HTTP_SCHEME, \
+ CUSTOM_STANDARD_SCHEME, add_header) \
+ CORS_TEST_XHR(name##HttpSchemeToCustomNonStandardScheme, HTTP_SCHEME, \
+ CUSTOM_NONSTANDARD_SCHEME, add_header) \
+ CORS_TEST_XHR(name##HttpSchemeToCustomUnregisteredScheme, HTTP_SCHEME, \
+ CUSTOM_UNREGISTERED_SCHEME, add_header) \
+ CORS_TEST_XHR(name##CustomStandardSchemeToServer, CUSTOM_STANDARD_SCHEME, \
+ SERVER, add_header) \
+ CORS_TEST_XHR(name##CustomStandardSchemeToHttpScheme, \
+ CUSTOM_STANDARD_SCHEME, HTTP_SCHEME, add_header) \
+ CORS_TEST_XHR(name##CustomStandardSchemeToCustomStandardScheme, \
+ CUSTOM_STANDARD_SCHEME, CUSTOM_STANDARD_SCHEME, add_header) \
+ CORS_TEST_XHR(name##CustomStandardSchemeToCustomNonStandardScheme, \
+ CUSTOM_STANDARD_SCHEME, CUSTOM_NONSTANDARD_SCHEME, add_header) \
+ CORS_TEST_XHR(name##CustomStandardSchemeToCustomUnregisteredScheme, \
+ CUSTOM_STANDARD_SCHEME, CUSTOM_UNREGISTERED_SCHEME, \
+ add_header) \
+ CORS_TEST_XHR(name##CustomNonStandardSchemeToServer, \
+ CUSTOM_NONSTANDARD_SCHEME, SERVER, add_header) \
+ CORS_TEST_XHR(name##CustomNonStandardSchemeToHttpScheme, \
+ CUSTOM_NONSTANDARD_SCHEME, HTTP_SCHEME, add_header) \
+ CORS_TEST_XHR(name##CustomNonStandardSchemeToCustomStandardScheme, \
+ CUSTOM_NONSTANDARD_SCHEME, CUSTOM_STANDARD_SCHEME, add_header) \
+ CORS_TEST_XHR(name##CustomNonStandardSchemeToCustomNonStandardScheme, \
+ CUSTOM_NONSTANDARD_SCHEME, CUSTOM_NONSTANDARD_SCHEME, \
+ add_header) \
+ CORS_TEST_XHR(name##CustomNonStandardSchemeToCustomUnregisteredScheme, \
+ CUSTOM_NONSTANDARD_SCHEME, CUSTOM_UNREGISTERED_SCHEME, \
+ add_header) \
+ CORS_TEST_XHR(name##CustomUnregisteredSchemeToServer, \
+ CUSTOM_UNREGISTERED_SCHEME, SERVER, add_header) \
+ CORS_TEST_XHR(name##CustomUnregisteredSchemeToHttpScheme, \
+ CUSTOM_UNREGISTERED_SCHEME, HTTP_SCHEME, add_header) \
+ CORS_TEST_XHR(name##CustomUnregisteredSchemeToCustomStandardScheme, \
+ CUSTOM_UNREGISTERED_SCHEME, CUSTOM_STANDARD_SCHEME, \
+ add_header) \
+ CORS_TEST_XHR(name##CustomUnregisteredSchemeToCustomNonStandardScheme, \
+ CUSTOM_UNREGISTERED_SCHEME, CUSTOM_NONSTANDARD_SCHEME, \
+ add_header) \
+ CORS_TEST_XHR(name##CustomUnregisteredSchemeToCustomUnregisteredScheme, \
+ CUSTOM_UNREGISTERED_SCHEME, CUSTOM_UNREGISTERED_SCHEME, \
+ add_header)
+
+// XHR requests without the "Access-Control-Allow-Origin" header.
+CORS_TEST_XHR_ALL(NoHeader, false)
+
+// XHR requests with the "Access-Control-Allow-Origin" header.
+CORS_TEST_XHR_ALL(WithHeader, true)
+
+// Like above, but without handling CORS preflight requests.
+#define CORS_TEST_XHR_NO_PREFLIGHT(test_name, handler_main, handler_sub, \
+ add_header) \
+ TEST(CorsTest, Xhr##test_name) { \
+ CookieTestSetup setup; \
+ CookieResource resource_main; \
+ SubResource resource_sub; \
+ SetupExecRequest(ExecMode::XHR, &setup, "CorsTest.Xhr" #test_name, \
+ HandlerType::handler_main, &resource_main, \
+ HandlerType::handler_sub, &resource_sub, nullptr, \
+ add_header); \
+ CefRefPtr<CorsTestHandler> handler = new CorsTestHandler(&setup); \
+ handler->ExecuteTest(); \
+ ReleaseAndWaitForDestructor(handler); \
+ }
+
+#define CORS_TEST_XHR_NO_PREFLIGHT_SERVER(name, add_header) \
+ CORS_TEST_XHR_NO_PREFLIGHT(name##ServerToServer, SERVER, SERVER, add_header) \
+ CORS_TEST_XHR_NO_PREFLIGHT(name##HttpSchemeToServer, HTTP_SCHEME, SERVER, \
+ add_header) \
+ CORS_TEST_XHR_NO_PREFLIGHT(name##CustomStandardSchemeToServer, \
+ CUSTOM_STANDARD_SCHEME, SERVER, add_header) \
+ CORS_TEST_XHR_NO_PREFLIGHT(name##CustomNonStandardSchemeToServer, \
+ CUSTOM_NONSTANDARD_SCHEME, SERVER, add_header)
+
+// XHR requests without the "Access-Control-Allow-Origin" header.
+CORS_TEST_XHR_NO_PREFLIGHT_SERVER(NoHeaderNoPreflight, false)
+
+// XHR requests with the "Access-Control-Allow-Origin" header.
+CORS_TEST_XHR_NO_PREFLIGHT_SERVER(WithHeaderNoPreflight, true)
+
+// Test fetch requests with different origin combinations.
+#define CORS_TEST_FETCH(test_name, handler_main, handler_sub, add_header) \
+ TEST(CorsTest, Fetch##test_name) { \
+ CookieTestSetup setup; \
+ CookieResource resource_main; \
+ SubResource resource_sub; \
+ PreflightResource resource_preflight; \
+ SetupExecRequest(ExecMode::FETCH, &setup, "CorsTest.Fetch" #test_name, \
+ HandlerType::handler_main, &resource_main, \
+ HandlerType::handler_sub, &resource_sub, \
+ &resource_preflight, add_header); \
+ CefRefPtr<CorsTestHandler> handler = new CorsTestHandler(&setup); \
+ handler->ExecuteTest(); \
+ ReleaseAndWaitForDestructor(handler); \
+ }
+
+// Test all origin combinations (same and cross-origin).
+#define CORS_TEST_FETCH_ALL(name, add_header) \
+ CORS_TEST_FETCH(name##ServerToServer, SERVER, SERVER, add_header) \
+ CORS_TEST_FETCH(name##ServerToHttpScheme, SERVER, HTTP_SCHEME, add_header) \
+ CORS_TEST_FETCH(name##ServerToCustomStandardScheme, SERVER, \
+ CUSTOM_STANDARD_SCHEME, add_header) \
+ CORS_TEST_FETCH(name##ServerToCustomNonStandardScheme, SERVER, \
+ CUSTOM_NONSTANDARD_SCHEME, add_header) \
+ CORS_TEST_FETCH(name##ServerToCustomUnregisteredScheme, SERVER, \
+ CUSTOM_UNREGISTERED_SCHEME, add_header) \
+ CORS_TEST_FETCH(name##HttpSchemeToServer, HTTP_SCHEME, SERVER, add_header) \
+ CORS_TEST_FETCH(name##HttpSchemeToHttpScheme, HTTP_SCHEME, HTTP_SCHEME, \
+ add_header) \
+ CORS_TEST_FETCH(name##HttpSchemeToCustomStandardScheme, HTTP_SCHEME, \
+ CUSTOM_STANDARD_SCHEME, add_header) \
+ CORS_TEST_FETCH(name##HttpSchemeToCustomNonStandardScheme, HTTP_SCHEME, \
+ CUSTOM_NONSTANDARD_SCHEME, add_header) \
+ CORS_TEST_FETCH(name##HttpSchemeToCustomUnregisteredScheme, HTTP_SCHEME, \
+ CUSTOM_UNREGISTERED_SCHEME, add_header) \
+ CORS_TEST_FETCH(name##CustomStandardSchemeToServer, CUSTOM_STANDARD_SCHEME, \
+ SERVER, add_header) \
+ CORS_TEST_FETCH(name##CustomStandardSchemeToHttpScheme, \
+ CUSTOM_STANDARD_SCHEME, HTTP_SCHEME, add_header) \
+ CORS_TEST_FETCH(name##CustomStandardSchemeToCustomStandardScheme, \
+ CUSTOM_STANDARD_SCHEME, CUSTOM_STANDARD_SCHEME, add_header) \
+ CORS_TEST_FETCH(name##CustomStandardSchemeToCustomNonStandardScheme, \
+ CUSTOM_STANDARD_SCHEME, CUSTOM_NONSTANDARD_SCHEME, \
+ add_header) \
+ CORS_TEST_FETCH(name##CustomStandardSchemeToCustomUnregisteredScheme, \
+ CUSTOM_STANDARD_SCHEME, CUSTOM_UNREGISTERED_SCHEME, \
+ add_header) \
+ CORS_TEST_FETCH(name##CustomNonStandardSchemeToServer, \
+ CUSTOM_NONSTANDARD_SCHEME, SERVER, add_header) \
+ CORS_TEST_FETCH(name##CustomNonStandardSchemeToHttpScheme, \
+ CUSTOM_NONSTANDARD_SCHEME, HTTP_SCHEME, add_header) \
+ CORS_TEST_FETCH(name##CustomNonStandardSchemeToCustomStandardScheme, \
+ CUSTOM_NONSTANDARD_SCHEME, CUSTOM_STANDARD_SCHEME, \
+ add_header) \
+ CORS_TEST_FETCH(name##CustomNonStandardSchemeToCustomNonStandardScheme, \
+ CUSTOM_NONSTANDARD_SCHEME, CUSTOM_NONSTANDARD_SCHEME, \
+ add_header) \
+ CORS_TEST_FETCH(name##CustomNonStandardSchemeToCustomUnregisteredScheme, \
+ CUSTOM_NONSTANDARD_SCHEME, CUSTOM_UNREGISTERED_SCHEME, \
+ add_header) \
+ CORS_TEST_FETCH(name##CustomUnregisteredSchemeToServer, \
+ CUSTOM_UNREGISTERED_SCHEME, SERVER, add_header) \
+ CORS_TEST_FETCH(name##CustomUnregisteredSchemeToHttpScheme, \
+ CUSTOM_UNREGISTERED_SCHEME, HTTP_SCHEME, add_header) \
+ CORS_TEST_FETCH(name##CustomUnregisteredSchemeToCustomStandardScheme, \
+ CUSTOM_UNREGISTERED_SCHEME, CUSTOM_STANDARD_SCHEME, \
+ add_header) \
+ CORS_TEST_FETCH(name##CustomUnregisteredSchemeToCustomNonStandardScheme, \
+ CUSTOM_UNREGISTERED_SCHEME, CUSTOM_NONSTANDARD_SCHEME, \
+ add_header) \
+ CORS_TEST_FETCH(name##CustomUnregisteredSchemeToCustomUnregisteredScheme, \
+ CUSTOM_UNREGISTERED_SCHEME, CUSTOM_UNREGISTERED_SCHEME, \
+ add_header)
+
+// Fetch requests without the "Access-Control-Allow-Origin" header.
+CORS_TEST_FETCH_ALL(NoHeader, false)
+
+// Fetch requests with the "Access-Control-Allow-Origin" header.
+CORS_TEST_FETCH_ALL(WithHeader, true)
+
+// Like above, but without handling CORS preflight requests.
+#define CORS_TEST_FETCH_NO_PREFLIGHT(test_name, handler_main, handler_sub, \
+ add_header) \
+ TEST(CorsTest, Fetch##test_name) { \
+ CookieTestSetup setup; \
+ CookieResource resource_main; \
+ SubResource resource_sub; \
+ SetupExecRequest(ExecMode::FETCH, &setup, "CorsTest.Fetch" #test_name, \
+ HandlerType::handler_main, &resource_main, \
+ HandlerType::handler_sub, &resource_sub, nullptr, \
+ add_header); \
+ CefRefPtr<CorsTestHandler> handler = new CorsTestHandler(&setup); \
+ handler->ExecuteTest(); \
+ ReleaseAndWaitForDestructor(handler); \
+ }
+
+#define CORS_TEST_FETCH_NO_PREFLIGHT_SERVER(name, add_header) \
+ CORS_TEST_FETCH_NO_PREFLIGHT(name##ServerToServer, SERVER, SERVER, \
+ add_header) \
+ CORS_TEST_FETCH_NO_PREFLIGHT(name##HttpSchemeToServer, HTTP_SCHEME, SERVER, \
+ add_header) \
+ CORS_TEST_FETCH_NO_PREFLIGHT(name##CustomStandardSchemeToServer, \
+ CUSTOM_STANDARD_SCHEME, SERVER, add_header) \
+ CORS_TEST_FETCH_NO_PREFLIGHT(name##CustomNonStandardSchemeToServer, \
+ CUSTOM_NONSTANDARD_SCHEME, SERVER, add_header)
+
+// Fetch requests without the "Access-Control-Allow-Origin" header.
+CORS_TEST_FETCH_NO_PREFLIGHT_SERVER(NoHeaderNoPreflight, false)
+
+// Fetch requests with the "Access-Control-Allow-Origin" header.
+CORS_TEST_FETCH_NO_PREFLIGHT_SERVER(WithHeaderNoPreflight, true)
+
+namespace {
+
+enum class RedirectMode {
+ MODE_302,
+ MODE_307,
+};
+
+struct RedirectGetResource : CookieResource {
+ RedirectGetResource() {}
+
+ bool VerifyRequest(CefRefPtr<CefRequest> request) const override {
+ if (!CookieResource::VerifyRequest(request)) {
+ return false;
+ }
+
+ // The "Origin" header should never be present for a redirect.
+ const std::string& origin = request->GetHeaderByName("Origin");
+ EXPECT_TRUE(origin.empty()) << GetPathURL();
+ return origin.empty();
+ }
+};
+
+void SetupRedirectResponse(RedirectMode mode,
+ const std::string& redirect_url,
+ CefRefPtr<CefResponse> response) {
+ if (mode == RedirectMode::MODE_302) {
+ response->SetStatus(302);
+ } else if (mode == RedirectMode::MODE_307) {
+ response->SetStatus(307);
+ } else {
+ NOTREACHED();
+ }
+
+ response->SetHeaderByName("Location", redirect_url,
+ /*override=*/false);
+}
+
+// Test redirect requests.
+void SetupRedirectGetRequest(RedirectMode mode,
+ CookieTestSetup* setup,
+ const std::string& test_name,
+ HandlerType main_handler,
+ CookieResource* main_resource,
+ HandlerType redirect_handler,
+ RedirectGetResource* redirect_resource) {
+ const std::string& base_path = "/" + test_name;
+
+ // Expect a single redirect request that sends SuccessMsg.
+ redirect_resource->Init(redirect_handler, base_path + ".redirect.html",
+ kMimeTypeHtml, GetDefaultSuccessMsgHtml());
+ redirect_resource->expected_success_query_ct = 1;
+
+ // Expect a single main request that results in a redirect.
+ const std::string& redirect_url = redirect_resource->GetPathURL();
+ main_resource->Init(main_handler, base_path, kMimeTypeHtml, std::string());
+ SetupRedirectResponse(mode, redirect_url, main_resource->response);
+
+ SetupCookieExpectations(setup, main_resource, redirect_resource);
+
+ setup->AddResource(main_resource);
+ setup->AddResource(redirect_resource);
+}
+
+} // namespace
+
+// Test redirect GET requests with different origin combinations.
+#define CORS_TEST_REDIRECT_GET(test_name, mode, handler_main, \
+ handler_redirect) \
+ TEST(CorsTest, RedirectGet##test_name) { \
+ CookieTestSetup setup; \
+ CookieResource resource_main; \
+ RedirectGetResource resource_redirect; \
+ SetupRedirectGetRequest( \
+ RedirectMode::mode, &setup, "CorsTest.RedirectGet" #test_name, \
+ HandlerType::handler_main, &resource_main, \
+ HandlerType::handler_redirect, &resource_redirect); \
+ CefRefPtr<CorsTestHandler> handler = new CorsTestHandler(&setup); \
+ handler->ExecuteTest(); \
+ ReleaseAndWaitForDestructor(handler); \
+ }
+
+// Test all redirect GET combinations (same and cross-origin).
+#define CORS_TEST_REDIRECT_GET_ALL(name, mode) \
+ CORS_TEST_REDIRECT_GET(name##ServerToServer, mode, SERVER, SERVER) \
+ CORS_TEST_REDIRECT_GET(name##ServerToHttpScheme, mode, SERVER, HTTP_SCHEME) \
+ CORS_TEST_REDIRECT_GET(name##ServerToCustomStandardScheme, mode, SERVER, \
+ CUSTOM_STANDARD_SCHEME) \
+ CORS_TEST_REDIRECT_GET(name##ServerToCustomNonStandardScheme, mode, SERVER, \
+ CUSTOM_NONSTANDARD_SCHEME) \
+ CORS_TEST_REDIRECT_GET(name##ServerToCustomUnregisteredScheme, mode, SERVER, \
+ CUSTOM_UNREGISTERED_SCHEME) \
+ CORS_TEST_REDIRECT_GET(name##HttpSchemeToServer, mode, HTTP_SCHEME, SERVER) \
+ CORS_TEST_REDIRECT_GET(name##HttpSchemeToHttpScheme, mode, HTTP_SCHEME, \
+ HTTP_SCHEME) \
+ CORS_TEST_REDIRECT_GET(name##HttpSchemeToCustomStandardScheme, mode, \
+ HTTP_SCHEME, CUSTOM_STANDARD_SCHEME) \
+ CORS_TEST_REDIRECT_GET(name##HttpSchemeToCustomNonStandardScheme, mode, \
+ HTTP_SCHEME, CUSTOM_NONSTANDARD_SCHEME) \
+ CORS_TEST_REDIRECT_GET(name##HttpSchemeToCustomUnregisteredScheme, mode, \
+ HTTP_SCHEME, CUSTOM_UNREGISTERED_SCHEME) \
+ CORS_TEST_REDIRECT_GET(name##CustomStandardSchemeToServer, mode, \
+ CUSTOM_STANDARD_SCHEME, SERVER) \
+ CORS_TEST_REDIRECT_GET(name##CustomStandardSchemeToHttpScheme, mode, \
+ CUSTOM_STANDARD_SCHEME, HTTP_SCHEME) \
+ CORS_TEST_REDIRECT_GET(name##CustomStandardSchemeToCustomStandardScheme, \
+ mode, CUSTOM_STANDARD_SCHEME, CUSTOM_STANDARD_SCHEME) \
+ CORS_TEST_REDIRECT_GET(name##CustomStandardSchemeToCustomNonStandardScheme, \
+ mode, CUSTOM_STANDARD_SCHEME, \
+ CUSTOM_NONSTANDARD_SCHEME) \
+ CORS_TEST_REDIRECT_GET(name##CustomStandardSchemeToCustomUnregisteredScheme, \
+ mode, CUSTOM_STANDARD_SCHEME, \
+ CUSTOM_UNREGISTERED_SCHEME) \
+ CORS_TEST_REDIRECT_GET(name##CustomNonStandardSchemeToServer, mode, \
+ CUSTOM_NONSTANDARD_SCHEME, SERVER) \
+ CORS_TEST_REDIRECT_GET(name##CustomNonStandardSchemeToHttpScheme, mode, \
+ CUSTOM_NONSTANDARD_SCHEME, HTTP_SCHEME) \
+ CORS_TEST_REDIRECT_GET(name##CustomNonStandardSchemeToCustomStandardScheme, \
+ mode, CUSTOM_NONSTANDARD_SCHEME, \
+ CUSTOM_STANDARD_SCHEME) \
+ CORS_TEST_REDIRECT_GET( \
+ name##CustomNonStandardSchemeToCustomNonStandardScheme, mode, \
+ CUSTOM_NONSTANDARD_SCHEME, CUSTOM_NONSTANDARD_SCHEME) \
+ CORS_TEST_REDIRECT_GET( \
+ name##CustomNonStandardSchemeToCustomUnregisteredScheme, mode, \
+ CUSTOM_NONSTANDARD_SCHEME, CUSTOM_UNREGISTERED_SCHEME) \
+ CORS_TEST_REDIRECT_GET(name##CustomUnregisteredSchemeToServer, mode, \
+ CUSTOM_UNREGISTERED_SCHEME, SERVER) \
+ CORS_TEST_REDIRECT_GET(name##CustomUnregisteredSchemeToHttpScheme, mode, \
+ CUSTOM_UNREGISTERED_SCHEME, HTTP_SCHEME) \
+ CORS_TEST_REDIRECT_GET(name##CustomUnregisteredSchemeToCustomStandardScheme, \
+ mode, CUSTOM_UNREGISTERED_SCHEME, \
+ CUSTOM_STANDARD_SCHEME) \
+ CORS_TEST_REDIRECT_GET( \
+ name##CustomUnregisteredSchemeToCustomNonStandardScheme, mode, \
+ CUSTOM_UNREGISTERED_SCHEME, CUSTOM_NONSTANDARD_SCHEME) \
+ CORS_TEST_REDIRECT_GET( \
+ name##CustomUnregisteredSchemeToCustomUnregisteredScheme, mode, \
+ CUSTOM_UNREGISTERED_SCHEME, CUSTOM_UNREGISTERED_SCHEME)
+
+// Redirect GET requests.
+CORS_TEST_REDIRECT_GET_ALL(302, MODE_302)
+CORS_TEST_REDIRECT_GET_ALL(307, MODE_307)
+
+namespace {
+
+struct PostResource : CookieResource {
+ PostResource() {}
+
+ bool expect_downgrade_to_get = false;
+ bool was_redirected = false;
+
+ std::string main_origin;
+ bool is_cross_origin;
+
+ void InitOrigin(HandlerType main_handler) {
+ // Origin is always "null" for non-HTTP(S) schemes.
+ // This should only be "null" for non-standard schemes, but Blink is likely
+ // using SchemeIsHTTPOrHTTPS() when submitting the form request.
+ main_origin = IsNonStandardType(main_handler) ||
+ main_handler == HandlerType::CUSTOM_STANDARD_SCHEME
+ ? "null"
+ : GetOrigin(main_handler);
+
+ // True if the request is considered cross-origin. Any requests between
+ // non-standard schemes are considered cross-origin (due to the "null"
+ // origin).
+ is_cross_origin =
+ main_handler != handler ||
+ (IsNonStandardType(main_handler) && handler == main_handler);
+ }
+
+ bool VerifyRequest(CefRefPtr<CefRequest> request) const override {
+ if (!CookieResource::VerifyRequest(request)) {
+ return false;
+ }
+
+ // The "Origin" header should be present if the request is POST, and was not
+ // redirected cross-origin.
+ std::string expected_origin;
+ if (!expect_downgrade_to_get) {
+ if (was_redirected && is_cross_origin) {
+ // Always "null" for cross-origin redirects.
+ expected_origin = "null";
+ } else {
+ expected_origin = main_origin;
+ }
+ }
+
+ const std::string& origin = request->GetHeaderByName("Origin");
+ EXPECT_STREQ(expected_origin.c_str(), origin.c_str()) << GetPathURL();
+ if (expected_origin != origin) {
+ return false;
+ }
+
+ const std::string& req_method = request->GetMethod();
+ const bool has_post_data = request->GetPostData() != nullptr;
+ if (expect_downgrade_to_get) {
+ EXPECT_FALSE(has_post_data) << GetPathURL();
+ EXPECT_STREQ("GET", req_method.c_str()) << GetPathURL();
+ return !has_post_data && req_method == "GET";
+ } else {
+ EXPECT_TRUE(has_post_data) << GetPathURL();
+ EXPECT_STREQ("POST", req_method.c_str()) << GetPathURL();
+ return has_post_data && req_method == "POST";
+ }
+ }
+};
+
+std::string GetPostFormHtml(const std::string& submit_url) {
+ return "<html><body>"
+ "<form id=\"f\" action=\"" +
+ submit_url +
+ "\" method=\"post\">"
+ "<input type=\"hidden\" name=\"n\" value=\"v\"></form>"
+ "<script>document.getElementById('f').submit();</script>"
+ "</body></html>";
+}
+
+// Test redirect requests.
+void SetupRedirectPostRequest(RedirectMode mode,
+ CookieTestSetup* setup,
+ const std::string& test_name,
+ HandlerType main_handler,
+ CookieResource* main_resource,
+ PostResource* submit_resource,
+ HandlerType redirect_handler,
+ PostResource* redirect_resource) {
+ const std::string& base_path = "/" + test_name;
+
+ // Expect a single redirect request that sends SuccessMsg.
+ redirect_resource->Init(redirect_handler, base_path + ".redirect.html",
+ kMimeTypeHtml, GetDefaultSuccessMsgHtml());
+ redirect_resource->InitOrigin(main_handler);
+ redirect_resource->expected_success_query_ct = 1;
+
+ // 302 redirects will downgrade POST requests to GET.
+ redirect_resource->expect_downgrade_to_get = mode == RedirectMode::MODE_302;
+ redirect_resource->was_redirected = true;
+
+ // Expect a single submit request that redirects the response.
+ const std::string& redirect_url = redirect_resource->GetPathURL();
+ submit_resource->Init(main_handler, base_path + ".submit.html", kMimeTypeHtml,
+ std::string());
+ submit_resource->InitOrigin(main_handler);
+ SetupRedirectResponse(mode, redirect_url, submit_resource->response);
+
+ // Expect a single main request that submits the form.
+ const std::string& submit_url = submit_resource->GetPathURL();
+ main_resource->Init(main_handler, base_path, kMimeTypeHtml,
+ GetPostFormHtml(submit_url));
+
+ SetupCookieExpectations(setup, main_resource, submit_resource);
+ SetupCookieExpectations(setup, main_resource, redirect_resource);
+
+ setup->AddResource(main_resource);
+ setup->AddResource(submit_resource);
+ setup->AddResource(redirect_resource);
+}
+
+} // namespace
+
+// Test redirect GET requests with different origin combinations.
+#define CORS_TEST_REDIRECT_POST(test_name, mode, handler_main, \
+ handler_redirect) \
+ TEST(CorsTest, RedirectPost##test_name) { \
+ CookieTestSetup setup; \
+ CookieResource resource_main; \
+ PostResource resource_submit, resource_redirect; \
+ SetupRedirectPostRequest( \
+ RedirectMode::mode, &setup, "CorsTest.RedirectPost" #test_name, \
+ HandlerType::handler_main, &resource_main, &resource_submit, \
+ HandlerType::handler_redirect, &resource_redirect); \
+ CefRefPtr<CorsTestHandler> handler = new CorsTestHandler(&setup); \
+ handler->ExecuteTest(); \
+ ReleaseAndWaitForDestructor(handler); \
+ }
+
+// Test all redirect GET combinations (same and cross-origin).
+#define CORS_TEST_REDIRECT_POST_ALL(name, mode) \
+ CORS_TEST_REDIRECT_POST(name##ServerToServer, mode, SERVER, SERVER) \
+ CORS_TEST_REDIRECT_POST(name##ServerToHttpScheme, mode, SERVER, HTTP_SCHEME) \
+ CORS_TEST_REDIRECT_POST(name##ServerToCustomStandardScheme, mode, SERVER, \
+ CUSTOM_STANDARD_SCHEME) \
+ CORS_TEST_REDIRECT_POST(name##ServerToCustomNonStandardScheme, mode, SERVER, \
+ CUSTOM_NONSTANDARD_SCHEME) \
+ CORS_TEST_REDIRECT_POST(name##ServerToCustomUnregisteredScheme, mode, \
+ SERVER, CUSTOM_UNREGISTERED_SCHEME) \
+ CORS_TEST_REDIRECT_POST(name##HttpSchemeToServer, mode, HTTP_SCHEME, SERVER) \
+ CORS_TEST_REDIRECT_POST(name##HttpSchemeToHttpScheme, mode, HTTP_SCHEME, \
+ HTTP_SCHEME) \
+ CORS_TEST_REDIRECT_POST(name##HttpSchemeToCustomStandardScheme, mode, \
+ HTTP_SCHEME, CUSTOM_STANDARD_SCHEME) \
+ CORS_TEST_REDIRECT_POST(name##HttpSchemeToCustomNonStandardScheme, mode, \
+ HTTP_SCHEME, CUSTOM_NONSTANDARD_SCHEME) \
+ CORS_TEST_REDIRECT_POST(name##HttpSchemeToCustomUnregisteredScheme, mode, \
+ HTTP_SCHEME, CUSTOM_UNREGISTERED_SCHEME) \
+ CORS_TEST_REDIRECT_POST(name##CustomStandardSchemeToServer, mode, \
+ CUSTOM_STANDARD_SCHEME, SERVER) \
+ CORS_TEST_REDIRECT_POST(name##CustomStandardSchemeToHttpScheme, mode, \
+ CUSTOM_STANDARD_SCHEME, HTTP_SCHEME) \
+ CORS_TEST_REDIRECT_POST(name##CustomStandardSchemeToCustomStandardScheme, \
+ mode, CUSTOM_STANDARD_SCHEME, \
+ CUSTOM_STANDARD_SCHEME) \
+ CORS_TEST_REDIRECT_POST(name##CustomStandardSchemeToCustomNonStandardScheme, \
+ mode, CUSTOM_STANDARD_SCHEME, \
+ CUSTOM_NONSTANDARD_SCHEME) \
+ CORS_TEST_REDIRECT_POST( \
+ name##CustomStandardSchemeToCustomUnregisteredScheme, mode, \
+ CUSTOM_STANDARD_SCHEME, CUSTOM_UNREGISTERED_SCHEME) \
+ CORS_TEST_REDIRECT_POST(name##CustomNonStandardSchemeToServer, mode, \
+ CUSTOM_NONSTANDARD_SCHEME, SERVER) \
+ CORS_TEST_REDIRECT_POST(name##CustomNonStandardSchemeToHttpScheme, mode, \
+ CUSTOM_NONSTANDARD_SCHEME, HTTP_SCHEME) \
+ CORS_TEST_REDIRECT_POST(name##CustomNonStandardSchemeToCustomStandardScheme, \
+ mode, CUSTOM_NONSTANDARD_SCHEME, \
+ CUSTOM_STANDARD_SCHEME) \
+ CORS_TEST_REDIRECT_POST( \
+ name##CustomNonStandardSchemeToCustomNonStandardScheme, mode, \
+ CUSTOM_NONSTANDARD_SCHEME, CUSTOM_NONSTANDARD_SCHEME) \
+ CORS_TEST_REDIRECT_POST( \
+ name##CustomNonStandardSchemeToCustomUnregisteredScheme, mode, \
+ CUSTOM_NONSTANDARD_SCHEME, CUSTOM_UNREGISTERED_SCHEME) \
+ CORS_TEST_REDIRECT_POST(name##CustomUnregisteredSchemeToServer, mode, \
+ CUSTOM_UNREGISTERED_SCHEME, SERVER) \
+ CORS_TEST_REDIRECT_POST(name##CustomUnregisteredSchemeToHttpScheme, mode, \
+ CUSTOM_UNREGISTERED_SCHEME, HTTP_SCHEME) \
+ CORS_TEST_REDIRECT_POST( \
+ name##CustomUnregisteredSchemeToCustomStandardScheme, mode, \
+ CUSTOM_UNREGISTERED_SCHEME, CUSTOM_STANDARD_SCHEME) \
+ CORS_TEST_REDIRECT_POST( \
+ name##CustomUnregisteredSchemeToCustomNonStandardScheme, mode, \
+ CUSTOM_UNREGISTERED_SCHEME, CUSTOM_NONSTANDARD_SCHEME) \
+ CORS_TEST_REDIRECT_POST( \
+ name##CustomUnregisteredSchemeToCustomUnregisteredScheme, mode, \
+ CUSTOM_UNREGISTERED_SCHEME, CUSTOM_UNREGISTERED_SCHEME)
+
+// Redirect GET requests.
+CORS_TEST_REDIRECT_POST_ALL(302, MODE_302)
+CORS_TEST_REDIRECT_POST_ALL(307, MODE_307)
+
+// Entry point for creating CORS browser test objects.
+// Called from client_app_delegates.cc.
+void CreateCorsBrowserTests(client::ClientAppBrowser::DelegateSet& delegates) {
+ delegates.insert(new CorsBrowserTest);
+}
diff --git a/tests/ceftests/devtools_message_unittest.cc b/tests/ceftests/devtools_message_unittest.cc
new file mode 100644
index 00000000..0282f0c7
--- /dev/null
+++ b/tests/ceftests/devtools_message_unittest.cc
@@ -0,0 +1,377 @@
+// Copyright (c) 2020 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include <algorithm>
+#include <sstream>
+
+#include "include/base/cef_callback.h"
+#include "include/base/cef_callback_helpers.h"
+#include "include/cef_callback.h"
+#include "include/cef_devtools_message_observer.h"
+#include "include/cef_parser.h"
+#include "include/wrapper/cef_closure_task.h"
+
+#include "tests/ceftests/test_handler.h"
+#include "tests/gtest/include/gtest/gtest.h"
+
+namespace {
+
+const char kTestUrl1[] = "http://tests/DevToolsMessage1";
+const char kTestUrl2[] = "http://tests/DevToolsMessage2";
+
+class DevToolsMessageTestHandler : public TestHandler {
+ public:
+ DevToolsMessageTestHandler() {}
+
+ void RunTest() override {
+ // Add HTML resources.
+ AddResource(kTestUrl1, "<html><body>Test1</body></html>", "text/html");
+ AddResource(kTestUrl2, "<html><body>Test2</body></html>", "text/html");
+
+ // Create the browser.
+ CreateBrowser(kTestUrl1);
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout();
+ }
+
+ void OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
+ TestHandler::OnAfterCreated(browser);
+
+ // STEP 1: Add the DevTools observer. Wait for the 1st load.
+ registration_ = browser->GetHost()->AddDevToolsMessageObserver(
+ new TestMessageObserver(this));
+ EXPECT_TRUE(registration_);
+ }
+
+ void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
+ bool isLoading,
+ bool canGoBack,
+ bool canGoForward) override {
+ if (!isLoading) {
+ load_ct_++;
+ if (load_ct_ == 1) {
+ // STEP 2: 1st load has completed. Now enable page domain notifications
+ // and wait for the method result.
+ ExecuteMethod(
+ "Page.enable", "",
+ base::BindOnce(&DevToolsMessageTestHandler::Navigate, this));
+ } else if (load_ct_ == 2) {
+ MaybeDestroyTest();
+ }
+ }
+ }
+
+ void DestroyTest() override {
+ // STEP 7: Remove the DevTools observer. This should result in the observer
+ // object being destroyed.
+ EXPECT_TRUE(registration_);
+ registration_ = nullptr;
+ EXPECT_TRUE(observer_destroyed_);
+
+ // Each send message variant should be called at least a single time.
+ EXPECT_GE(method_send_ct_, 1);
+ EXPECT_GE(method_execute_ct_, 1);
+
+ // All sent messages should receive a result callback.
+ EXPECT_EQ(expected_method_ct_, method_send_ct_ + method_execute_ct_);
+ EXPECT_EQ(expected_method_ct_, result_ct_);
+ EXPECT_EQ(expected_method_ct_, last_result_id_);
+
+ // Every received message should parse successfully to a result or event
+ // callback.
+ EXPECT_EQ(message_ct_, result_ct_ + event_ct_);
+
+ // Should receive 1 or more events (probably just 1, but who knows?).
+ EXPECT_GE(event_ct_, 1);
+
+ // OnLoadingStateChange(isLoading=false) should be called twice.
+ EXPECT_EQ(expected_load_ct_, load_ct_);
+
+ // Should get callbacks for agent attached but not detached.
+ EXPECT_EQ(1, attached_ct_);
+ EXPECT_EQ(0, detached_ct_);
+
+ TestHandler::DestroyTest();
+ }
+
+ private:
+ struct MethodResult {
+ int message_id;
+ bool success;
+ std::string result;
+ };
+
+ struct Event {
+ std::string method;
+ std::string params;
+ };
+
+ class TestMessageObserver : public CefDevToolsMessageObserver {
+ public:
+ explicit TestMessageObserver(DevToolsMessageTestHandler* handler)
+ : handler_(handler) {}
+
+ virtual ~TestMessageObserver() { handler_->observer_destroyed_.yes(); }
+
+ bool OnDevToolsMessage(CefRefPtr<CefBrowser> browser,
+ const void* message,
+ size_t message_size) override {
+ EXPECT_TRUE(browser.get());
+ EXPECT_EQ(handler_->GetBrowserId(), browser->GetIdentifier());
+ handler_->message_ct_++;
+ return false;
+ }
+
+ void OnDevToolsMethodResult(CefRefPtr<CefBrowser> browser,
+ int message_id,
+ bool success,
+ const void* result,
+ size_t result_size) override {
+ EXPECT_TRUE(browser.get());
+ EXPECT_EQ(handler_->GetBrowserId(), browser->GetIdentifier());
+ handler_->result_ct_++;
+
+ MethodResult mr;
+ mr.message_id = message_id;
+ mr.success = success;
+ if (result) {
+ // Intentionally truncating at small size.
+ mr.result = std::string(static_cast<const char*>(result),
+ std::min(static_cast<int>(result_size), 80));
+ }
+ handler_->OnMethodResult(mr);
+ }
+
+ void OnDevToolsEvent(CefRefPtr<CefBrowser> browser,
+ const CefString& method,
+ const void* params,
+ size_t params_size) override {
+ EXPECT_TRUE(browser.get());
+ EXPECT_EQ(handler_->GetBrowserId(), browser->GetIdentifier());
+ handler_->event_ct_++;
+
+ Event ev;
+ ev.method = method;
+ if (params) {
+ // Intentionally truncating at small size.
+ ev.params = std::string(static_cast<const char*>(params),
+ std::min(static_cast<int>(params_size), 80));
+ }
+ handler_->OnEvent(ev);
+ }
+
+ void OnDevToolsAgentAttached(CefRefPtr<CefBrowser> browser) override {
+ EXPECT_TRUE(browser.get());
+ EXPECT_EQ(handler_->GetBrowserId(), browser->GetIdentifier());
+ handler_->attached_ct_++;
+ }
+
+ void OnDevToolsAgentDetached(CefRefPtr<CefBrowser> browser) override {
+ EXPECT_TRUE(browser.get());
+ EXPECT_EQ(handler_->GetBrowserId(), browser->GetIdentifier());
+ handler_->detached_ct_++;
+ }
+
+ private:
+ DevToolsMessageTestHandler* handler_;
+
+ IMPLEMENT_REFCOUNTING(TestMessageObserver);
+ DISALLOW_COPY_AND_ASSIGN(TestMessageObserver);
+ };
+
+ // Execute a DevTools method. Expected results will be verified in
+ // OnMethodResult, and |next_step| will then be executed.
+ // |expected_result| can be a fragment that the result should start with.
+ void ExecuteMethod(const std::string& method,
+ const std::string& params,
+ base::OnceClosure next_step,
+ const std::string& expected_result = "{}",
+ bool expected_success = true) {
+ CHECK(!method.empty());
+ CHECK(!next_step.is_null());
+
+ int message_id = next_message_id_++;
+
+ std::stringstream message;
+ message << "{\"id\":" << message_id << ",\"method\":\"" << method << "\"";
+ if (!params.empty()) {
+ message << ",\"params\":" << params;
+ }
+ message << "}";
+
+ // Set expected result state.
+ pending_message_ = message.str();
+ pending_result_next_ = std::move(next_step);
+ pending_result_ = {message_id, expected_success, expected_result};
+
+ if (message_id % 2 == 0) {
+ // Use the less structured method.
+ method_send_ct_++;
+ GetBrowser()->GetHost()->SendDevToolsMessage(pending_message_.data(),
+ pending_message_.size());
+ } else {
+ // Use the more structured method.
+ method_execute_ct_++;
+ CefRefPtr<CefDictionaryValue> dict;
+ if (!params.empty()) {
+ CefRefPtr<CefValue> value =
+ CefParseJSON(params.data(), params.size(), JSON_PARSER_RFC);
+ EXPECT_TRUE(value && value->GetType() == VTYPE_DICTIONARY)
+ << "failed to parse: " << params;
+ if (value && value->GetType() == VTYPE_DICTIONARY) {
+ dict = value->GetDictionary();
+ }
+ }
+ GetBrowser()->GetHost()->ExecuteDevToolsMethod(message_id, method, dict);
+ }
+ }
+
+ // Every call to ExecuteMethod should result in a single call to this method
+ // with the same message_id.
+ void OnMethodResult(const MethodResult& result) {
+ EXPECT_EQ(pending_result_.message_id, result.message_id)
+ << "with message=" << pending_message_;
+ if (result.message_id != pending_result_.message_id) {
+ return;
+ }
+
+ EXPECT_EQ(pending_result_.success, result.success)
+ << "with message=" << pending_message_;
+
+ EXPECT_TRUE(result.result.find(pending_result_.result) == 0)
+ << "with message=" << pending_message_
+ << "\nand actual result=" << result.result
+ << "\nand expected result=" << pending_result_.result;
+
+ last_result_id_ = result.message_id;
+
+ // Continue asynchronously to allow the callstack to unwind.
+ CefPostTask(TID_UI, std::move(pending_result_next_));
+
+ // Clear expected result state.
+ pending_message_.clear();
+ pending_result_ = {};
+ }
+
+ void OnEvent(const Event& event) {
+ if (event.method != pending_event_.method) {
+ return;
+ }
+
+ EXPECT_TRUE(event.params.find(pending_event_.params) == 0)
+ << "with method=" << event.method
+ << "\nand actual params=" << event.params
+ << "\nand expected params=" << pending_event_.params;
+
+ // Continue asynchronously to allow the callstack to unwind.
+ CefPostTask(TID_UI, std::move(pending_event_next_));
+
+ // Clear expected result state.
+ pending_event_ = {};
+ }
+
+ void Navigate() {
+ pending_event_ = {"Page.frameNavigated", "{\"frame\":"};
+ pending_event_next_ =
+ base::BindOnce(&DevToolsMessageTestHandler::AfterNavigate, this);
+
+ std::stringstream params;
+ params << "{\"url\":\"" << kTestUrl2 << "\"}";
+
+ // STEP 3: Page domain notifications are enabled. Now start a new
+ // navigation (but do nothing on method result) and wait for the
+ // "Page.frameNavigated" event.
+ ExecuteMethod("Page.navigate", params.str(), base::DoNothing(),
+ /*expected_result=*/"{\"frameId\":");
+ }
+
+ void AfterNavigate() {
+ // STEP 4: Got the "Page.frameNavigated" event. Now disable page domain
+ // notifications.
+ ExecuteMethod(
+ "Page.disable", "",
+ base::BindOnce(&DevToolsMessageTestHandler::AfterPageDisabled, this));
+ }
+
+ void AfterPageDisabled() {
+ // STEP 5: Got the the "Page.disable" method result. Now call a non-existant
+ // method to verify an error result, and then destroy the test when done.
+ ExecuteMethod(
+ "Foo.doesNotExist", "",
+ base::BindOnce(&DevToolsMessageTestHandler::MaybeDestroyTest, this),
+ /*expected_result=*/
+ "{\"code\":-32601,\"message\":\"'Foo.doesNotExist' wasn't found\"}",
+ /*expected_success=*/false);
+ }
+
+ void MaybeDestroyTest() {
+ if (result_ct_ == expected_method_ct_ && load_ct_ == expected_load_ct_) {
+ // STEP 6: Got confirmation of all expected method results and load
+ // events. Now destroy the test.
+ DestroyTest();
+ }
+ }
+
+ // Total # of times we're planning to call ExecuteMethod.
+ const int expected_method_ct_ = 4;
+
+ // Total # of times we're expecting OnLoadingStateChange(isLoading=false) to
+ // be called.
+ const int expected_load_ct_ = 2;
+
+ // In ExecuteMethod:
+ // Next message ID to use.
+ int next_message_id_ = 1;
+ // Last message that was sent (used for debug messages only).
+ std::string pending_message_;
+ // SendDevToolsMessage call count.
+ int method_send_ct_ = 0;
+ // ExecuteDevToolsMethod call count.
+ int method_execute_ct_ = 0;
+
+ // Expect |pending_result_.message_id| in OnMethodResult.
+ // The result should start with the |pending_result_.result| fragment.
+ MethodResult pending_result_;
+ // Tracks the last message ID received.
+ int last_result_id_ = -1;
+ // When received, execute this callback.
+ base::OnceClosure pending_result_next_;
+
+ // Wait for |pending_event_.method| in OnEvent.
+ // The params should start with the |pending_event_.params| fragment.
+ Event pending_event_;
+ // When received, execute this callback.
+ base::OnceClosure pending_event_next_;
+
+ CefRefPtr<CefRegistration> registration_;
+
+ // Observer callback count.
+ int message_ct_ = 0;
+ int result_ct_ = 0;
+ int event_ct_ = 0;
+ int attached_ct_ = 0;
+ int detached_ct_ = 0;
+
+ // OnLoadingStateChange(isLoading=false) count.
+ int load_ct_ = 0;
+
+ TrackCallback observer_destroyed_;
+
+ IMPLEMENT_REFCOUNTING(DevToolsMessageTestHandler);
+ DISALLOW_COPY_AND_ASSIGN(DevToolsMessageTestHandler);
+};
+
+} // namespace
+
+// Test everything related to DevTools messages:
+// - CefDevToolsMessageObserver registration and life span.
+// - SendDevToolsMessage/ExecuteDevToolsMethod calls.
+// - CefDevToolsMessageObserver callbacks for method results and events.
+TEST(DevToolsMessageTest, Messages) {
+ CefRefPtr<DevToolsMessageTestHandler> handler =
+ new DevToolsMessageTestHandler();
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
diff --git a/tests/ceftests/dialog_unittest.cc b/tests/ceftests/dialog_unittest.cc
new file mode 100644
index 00000000..e80dd26a
--- /dev/null
+++ b/tests/ceftests/dialog_unittest.cc
@@ -0,0 +1,318 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "include/base/cef_callback.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "tests/ceftests/test_handler.h"
+#include "tests/ceftests/test_util.h"
+#include "tests/gtest/include/gtest/gtest.h"
+
+namespace {
+
+const char* kTestUrl = "http://tests/DialogTestHandler";
+
+class DialogTestHandler : public TestHandler {
+ public:
+ struct TestConfig {
+ explicit TestConfig(FileDialogMode dialog_mode)
+ : mode(dialog_mode),
+ title("Test Title"),
+ default_file_name("Test File Name"),
+ callback_async(false),
+ callback_cancel(false) {
+ accept_types.push_back("text/*");
+ accept_types.push_back(".js");
+ accept_types.push_back(".css");
+ }
+
+ FileDialogMode mode;
+ CefString title;
+ CefString default_file_name;
+ std::vector<CefString> accept_types;
+
+ bool callback_async; // True if the callback should execute asynchronously.
+ bool callback_cancel; // True if the callback should cancel.
+ std::vector<CefString> callback_paths; // Resulting paths if not cancelled.
+ };
+
+ class Callback : public CefRunFileDialogCallback {
+ public:
+ explicit Callback(DialogTestHandler* handler) : handler_(handler) {}
+
+ void OnFileDialogDismissed(
+ const std::vector<CefString>& file_paths) override {
+ handler_->got_onfiledialogdismissed_.yes();
+
+ if (handler_->config_.callback_cancel) {
+ EXPECT_TRUE(file_paths.empty());
+ } else {
+ TestStringVectorEqual(handler_->config_.callback_paths, file_paths);
+ }
+
+ handler_->DestroyTest();
+ handler_ = nullptr;
+ }
+
+ private:
+ DialogTestHandler* handler_;
+
+ IMPLEMENT_REFCOUNTING(Callback);
+ };
+
+ explicit DialogTestHandler(const TestConfig& config) : config_(config) {}
+
+ void RunTest() override {
+ AddResource(kTestUrl, "<html><body>TEST</body></html>", "text/html");
+
+ // Create the browser
+ CreateBrowser(kTestUrl);
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout();
+ }
+
+ void OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int httpStatusCode) override {
+ browser->GetHost()->RunFileDialog(config_.mode, config_.title,
+ config_.default_file_name,
+ config_.accept_types, new Callback(this));
+ }
+
+ void ExecuteCallback(CefRefPtr<CefFileDialogCallback> callback) {
+ if (config_.callback_cancel) {
+ callback->Cancel();
+ } else {
+ callback->Continue(config_.callback_paths);
+ }
+ }
+
+ // CefDialogHandler
+ bool OnFileDialog(CefRefPtr<CefBrowser> browser,
+ FileDialogMode mode,
+ const CefString& title,
+ const CefString& default_file_name,
+ const std::vector<CefString>& accept_types,
+ CefRefPtr<CefFileDialogCallback> callback) override {
+ got_onfiledialog_.yes();
+
+ std::string url = browser->GetMainFrame()->GetURL();
+ EXPECT_STREQ(kTestUrl, url.c_str());
+
+ EXPECT_EQ(config_.mode, mode);
+ EXPECT_STREQ(config_.title.ToString().c_str(), title.ToString().c_str());
+ EXPECT_STREQ(config_.default_file_name.ToString().c_str(),
+ default_file_name.ToString().c_str());
+ TestStringVectorEqual(config_.accept_types, accept_types);
+
+ if (config_.callback_async) {
+ CefPostTask(TID_UI, base::BindOnce(&DialogTestHandler::ExecuteCallback,
+ this, callback));
+ } else {
+ ExecuteCallback(callback);
+ }
+
+ return true;
+ }
+
+ void DestroyTest() override {
+ EXPECT_TRUE(got_onfiledialog_);
+ EXPECT_TRUE(got_onfiledialogdismissed_);
+
+ TestHandler::DestroyTest();
+ }
+
+ TestConfig config_;
+
+ TrackCallback got_onfiledialog_;
+ TrackCallback got_onfiledialogdismissed_;
+
+ IMPLEMENT_REFCOUNTING(DialogTestHandler);
+};
+
+} // namespace
+
+// Test with all parameters empty.
+TEST(DialogTest, FileEmptyParams) {
+ DialogTestHandler::TestConfig config(FILE_DIALOG_OPEN);
+ config.title.clear();
+ config.default_file_name.clear();
+ config.accept_types.clear();
+ config.callback_async = false;
+ config.callback_cancel = false;
+
+ CefRefPtr<DialogTestHandler> handler = new DialogTestHandler(config);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(DialogTest, FileOpen) {
+ DialogTestHandler::TestConfig config(FILE_DIALOG_OPEN);
+ config.callback_async = false;
+ config.callback_cancel = false;
+ config.callback_paths.push_back("/path/to/file1.txt");
+
+ CefRefPtr<DialogTestHandler> handler = new DialogTestHandler(config);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(DialogTest, FileOpenCancel) {
+ DialogTestHandler::TestConfig config(FILE_DIALOG_OPEN);
+ config.callback_async = false;
+ config.callback_cancel = true;
+
+ CefRefPtr<DialogTestHandler> handler = new DialogTestHandler(config);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(DialogTest, FileOpenAsync) {
+ DialogTestHandler::TestConfig config(FILE_DIALOG_OPEN);
+ config.callback_async = true;
+ config.callback_cancel = false;
+ config.callback_paths.push_back("/path/to/file1.txt");
+
+ CefRefPtr<DialogTestHandler> handler = new DialogTestHandler(config);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(DialogTest, FileOpenAsyncCancel) {
+ DialogTestHandler::TestConfig config(FILE_DIALOG_OPEN);
+ config.callback_async = false;
+ config.callback_cancel = true;
+
+ CefRefPtr<DialogTestHandler> handler = new DialogTestHandler(config);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(DialogTest, FileOpenMultiple) {
+ DialogTestHandler::TestConfig config(FILE_DIALOG_OPEN_MULTIPLE);
+ config.callback_async = false;
+ config.callback_cancel = false;
+ config.callback_paths.push_back("/path/to/file1.txt");
+ config.callback_paths.push_back("/path/to/file2.txt");
+
+ CefRefPtr<DialogTestHandler> handler = new DialogTestHandler(config);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(DialogTest, FileOpenMultipleCancel) {
+ DialogTestHandler::TestConfig config(FILE_DIALOG_OPEN_MULTIPLE);
+ config.callback_async = false;
+ config.callback_cancel = true;
+
+ CefRefPtr<DialogTestHandler> handler = new DialogTestHandler(config);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(DialogTest, FileOpenMultipleAsync) {
+ DialogTestHandler::TestConfig config(FILE_DIALOG_OPEN_MULTIPLE);
+ config.callback_async = true;
+ config.callback_cancel = false;
+ config.callback_paths.push_back("/path/to/file1.txt");
+ config.callback_paths.push_back("/path/to/file2.txt");
+
+ CefRefPtr<DialogTestHandler> handler = new DialogTestHandler(config);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(DialogTest, FileOpenMultipleAsyncCancel) {
+ DialogTestHandler::TestConfig config(FILE_DIALOG_OPEN_MULTIPLE);
+ config.callback_async = false;
+ config.callback_cancel = true;
+
+ CefRefPtr<DialogTestHandler> handler = new DialogTestHandler(config);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(DialogTest, FileOpenFolder) {
+ DialogTestHandler::TestConfig config(FILE_DIALOG_OPEN_FOLDER);
+ config.callback_async = false;
+ config.callback_cancel = false;
+ config.callback_paths.push_back("/path/to/folder");
+
+ CefRefPtr<DialogTestHandler> handler = new DialogTestHandler(config);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(DialogTest, FileOpenFolderCancel) {
+ DialogTestHandler::TestConfig config(FILE_DIALOG_OPEN_FOLDER);
+ config.callback_async = false;
+ config.callback_cancel = true;
+
+ CefRefPtr<DialogTestHandler> handler = new DialogTestHandler(config);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(DialogTest, FileOpenFolderAsync) {
+ DialogTestHandler::TestConfig config(FILE_DIALOG_OPEN_FOLDER);
+ config.callback_async = true;
+ config.callback_cancel = false;
+ config.callback_paths.push_back("/path/to/folder");
+
+ CefRefPtr<DialogTestHandler> handler = new DialogTestHandler(config);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(DialogTest, FileOpenFolderAsyncCancel) {
+ DialogTestHandler::TestConfig config(FILE_DIALOG_OPEN_FOLDER);
+ config.callback_async = false;
+ config.callback_cancel = true;
+
+ CefRefPtr<DialogTestHandler> handler = new DialogTestHandler(config);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(DialogTest, FileSave) {
+ DialogTestHandler::TestConfig config(FILE_DIALOG_SAVE);
+ config.callback_async = false;
+ config.callback_cancel = false;
+ config.callback_paths.push_back("/path/to/file1.txt");
+
+ CefRefPtr<DialogTestHandler> handler = new DialogTestHandler(config);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(DialogTest, FileSaveCancel) {
+ DialogTestHandler::TestConfig config(FILE_DIALOG_SAVE);
+ config.callback_async = false;
+ config.callback_cancel = true;
+
+ CefRefPtr<DialogTestHandler> handler = new DialogTestHandler(config);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(DialogTest, FileSaveAsync) {
+ DialogTestHandler::TestConfig config(FILE_DIALOG_SAVE);
+ config.callback_async = true;
+ config.callback_cancel = false;
+ config.callback_paths.push_back("/path/to/file1.txt");
+
+ CefRefPtr<DialogTestHandler> handler = new DialogTestHandler(config);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(DialogTest, FileSaveAsyncCancel) {
+ DialogTestHandler::TestConfig config(FILE_DIALOG_SAVE);
+ config.callback_async = false;
+ config.callback_cancel = true;
+
+ CefRefPtr<DialogTestHandler> handler = new DialogTestHandler(config);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
diff --git a/tests/ceftests/display_unittest.cc b/tests/ceftests/display_unittest.cc
new file mode 100644
index 00000000..563f6cb6
--- /dev/null
+++ b/tests/ceftests/display_unittest.cc
@@ -0,0 +1,532 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include <list>
+
+#include "include/base/cef_callback.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "tests/ceftests/routing_test_handler.h"
+#include "tests/ceftests/test_handler.h"
+#include "tests/gtest/include/gtest/gtest.h"
+
+namespace {
+
+// How it works:
+// 1. Load kTitleUrl1 (title should be kTitleStr1)
+// 2. Load kTitleUrl2 (title should be kTitleStr2)
+// 3. History back to kTitleUrl1 (title should be kTitleStr1)
+// 4. History forward to kTitleUrl2 (title should be kTitleStr2)
+// 5. Set title via JavaScript (title should be kTitleStr3)
+
+const char kTitleUrl1[] = "http://tests-title/nav1.html";
+const char kTitleUrl2[] = "http://tests-title/nav2.html";
+const char kTitleStr1[] = "Title 1";
+const char kTitleStr2[] = "Title 2";
+const char kTitleStr3[] = "Title 3";
+
+// Browser side.
+class TitleTestHandler : public TestHandler {
+ public:
+ TitleTestHandler()
+ : step_(0), got_title_change_(false), got_loading_state_change_(false) {}
+
+ void RunTest() override {
+ // Add the resources that we will navigate to/from.
+ AddResource(kTitleUrl1,
+ "<html><head><title>" + std::string(kTitleStr1) +
+ "</title></head>Nav1</html>",
+ "text/html");
+ AddResource(kTitleUrl2,
+ "<html><head><title>" + std::string(kTitleStr2) +
+ "</title></head>Nav2" +
+ "<script>function setTitle() { window.document.title = '" +
+ std::string(kTitleStr3) + "'; }</script>" + "</html>",
+ "text/html");
+
+ // Create the browser.
+ CreateBrowser(kTitleUrl1);
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout();
+ }
+
+ void OnTitleChange(CefRefPtr<CefBrowser> browser,
+ const CefString& title) override {
+ // Ignore the 2nd OnTitleChange call which arrives after navigation
+ // completion.
+ if (got_title_change_) {
+ return;
+ }
+
+ std::string title_str = title;
+ if (step_ == 0 || step_ == 2) {
+ EXPECT_STREQ(kTitleStr1, title_str.c_str());
+ } else if (step_ == 1 || step_ == 3) {
+ EXPECT_STREQ(kTitleStr2, title_str.c_str());
+ } else if (step_ == 4) {
+ EXPECT_STREQ(kTitleStr3, title_str.c_str());
+ }
+
+ got_title_[step_].yes();
+
+ if (step_ == 4) {
+ DestroyTest();
+ } else {
+ got_title_change_ = true;
+ NextIfReady(browser);
+ }
+ }
+
+ void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
+ bool isLoading,
+ bool canGoBack,
+ bool canGoForward) override {
+ if (isLoading) {
+ return;
+ }
+
+ // Call NextIfReady asynchronously because an additional call to
+ // OnTitleChange will be triggered later in the current call stack due to
+ // navigation completion and we want that call to arrive before execution of
+ // NextIfReady.
+ got_loading_state_change_ = true;
+ CefPostTask(TID_UI,
+ base::BindOnce(&TitleTestHandler::NextIfReady, this, browser));
+ }
+
+ private:
+ void NextIfReady(CefRefPtr<CefBrowser> browser) {
+ if (!got_title_change_ || !got_loading_state_change_) {
+ return;
+ }
+
+ got_title_change_ = false;
+ got_loading_state_change_ = false;
+
+ switch (step_++) {
+ case 0:
+ browser->GetMainFrame()->LoadURL(kTitleUrl2);
+ break;
+ case 1:
+ browser->GoBack();
+ break;
+ case 2:
+ browser->GoForward();
+ break;
+ case 3:
+ browser->GetMainFrame()->ExecuteJavaScript("setTitle()", kTitleUrl2, 0);
+ break;
+ default:
+ EXPECT_TRUE(false); // Not reached.
+ }
+ }
+
+ void DestroyTest() override {
+ for (int i = 0; i < 5; ++i) {
+ EXPECT_TRUE(got_title_[i]) << "step " << i;
+ }
+
+ TestHandler::DestroyTest();
+ }
+
+ int step_;
+
+ bool got_title_change_;
+ bool got_loading_state_change_;
+
+ TrackCallback got_title_[5];
+
+ IMPLEMENT_REFCOUNTING(TitleTestHandler);
+};
+
+} // namespace
+
+// Test title notifications.
+TEST(DisplayTest, Title) {
+ CefRefPtr<TitleTestHandler> handler = new TitleTestHandler();
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+namespace {
+
+const char kAutoResizeUrl[] = "http://tests-display/auto-resize.html";
+
+class AutoResizeTestHandler : public RoutingTestHandler {
+ public:
+ AutoResizeTestHandler() {}
+
+ void RunTest() override {
+ // Add the resources that we will navigate to/from.
+ AddResource(kAutoResizeUrl,
+ "<html><head><style>"
+ "body {overflow:hidden;margin:0px;padding:0px;}"
+ "</style></head><body><div id=a>Content</div></body></html>",
+ "text/html");
+
+ // Create the browser.
+ CreateBrowser(kAutoResizeUrl);
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout();
+ }
+
+ void OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
+ RoutingTestHandler::OnAfterCreated(browser);
+ browser->GetHost()->SetAutoResizeEnabled(true, CefSize(10, 10),
+ CefSize(500, 500));
+ }
+
+ bool OnAutoResize(CefRefPtr<CefBrowser> browser,
+ const CefSize& new_size) override {
+ if (new_size.width == 1064 && new_size.height == 576) {
+ // Ignore this initial resize that may or may not occur.
+ } else if (!got_auto_resize1_) {
+ got_auto_resize1_.yes();
+ EXPECT_EQ(50, new_size.width);
+ EXPECT_EQ(18, new_size.height);
+
+ // Trigger a resize.
+ browser->GetMainFrame()->ExecuteJavaScript(
+ "document.getElementById('a').innerText='New Content';",
+ kAutoResizeUrl, 0);
+ } else if (!got_auto_resize2_) {
+ got_auto_resize2_.yes();
+ EXPECT_EQ(50, new_size.width);
+ EXPECT_EQ(37, new_size.height);
+
+ // Disable resize notifications.
+ browser->GetHost()->SetAutoResizeEnabled(false, CefSize(), CefSize());
+
+ // There should be no more resize notifications. End the test after a
+ // short delay.
+ browser->GetMainFrame()->ExecuteJavaScript(
+ "document.getElementById('a').innerText='New Content Again';"
+ "var interval = setInterval(function() {"
+ "window.testQuery({request:'done'});clearInterval(interval);}, 50);",
+ kAutoResizeUrl, 0);
+ } else {
+ EXPECT_TRUE(false); // Not reached.
+ }
+ return true;
+ }
+
+ bool OnQuery(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int64 query_id,
+ const CefString& request,
+ bool persistent,
+ CefRefPtr<Callback> callback) override {
+ EXPECT_STREQ("done", request.ToString().c_str());
+ EXPECT_FALSE(got_done_message_);
+ got_done_message_.yes();
+ DestroyTest();
+ return true;
+ }
+
+ void DestroyTest() override {
+ EXPECT_TRUE(got_auto_resize1_);
+ EXPECT_TRUE(got_auto_resize2_);
+ EXPECT_TRUE(got_done_message_);
+ TestHandler::DestroyTest();
+ }
+
+ private:
+ TrackCallback got_auto_resize1_;
+ TrackCallback got_auto_resize2_;
+ TrackCallback got_done_message_;
+
+ IMPLEMENT_REFCOUNTING(AutoResizeTestHandler);
+};
+
+} // namespace
+
+// Test OnAutoResize notification.
+TEST(DisplayTest, AutoResize) {
+ CefRefPtr<AutoResizeTestHandler> handler = new AutoResizeTestHandler();
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+namespace {
+
+// Browser side.
+class ConsoleTestHandler : public TestHandler {
+ public:
+ struct TestConfig {
+ // Use something other than 1 as |line| for testing.
+ explicit TestConfig(cef_log_severity_t message_level)
+ : level(message_level),
+ message("'Test Message'"),
+ expected_message("Test Message"),
+ source("http://tests-console-message/level.html"),
+ line(42) {}
+
+ cef_log_severity_t level;
+ std::string message;
+ std::string expected_message;
+ std::string source;
+ int line;
+ std::string function;
+ };
+
+ ConsoleTestHandler(const TestConfig& config) : config_(config) {}
+
+ void RunTest() override {
+ // Add the resources that will be used to print to console.
+ AddResource(
+ config_.source,
+ CreateResourceContent(config_.message, config_.function, config_.line),
+ "text/html");
+
+ // Create the browser.
+ CreateBrowser(config_.source);
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout();
+ }
+
+ void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
+ bool isLoading,
+ bool canGoBack,
+ bool canGoForward) override {
+ if (isLoading) {
+ return;
+ }
+
+ // Print console message after loading.
+ browser->GetMainFrame()->ExecuteJavaScript("printMessage()", config_.source,
+ 0);
+ }
+
+ bool OnConsoleMessage(CefRefPtr<CefBrowser> browser,
+ cef_log_severity_t level,
+ const CefString& message,
+ const CefString& source,
+ int line) override {
+ EXPECT_EQ(config_.level, level);
+ EXPECT_EQ(config_.expected_message, message.ToString());
+ EXPECT_EQ(config_.source, source.ToString());
+ EXPECT_EQ(config_.line, line);
+
+ TestHandler::DestroyTest();
+
+ return false;
+ }
+
+ private:
+ std::string CreateResourceContent(const CefString& message,
+ const CefString& function,
+ int line) {
+ std::string content = "<html><script>function printMessage() { ";
+ for (int i = 1; i < line; ++i) {
+ // Add additional lines to test the |line| argument in |OnConsoleMessage|.
+ content += ";\n";
+ }
+ content += "console." + function.ToString() + "(" + message.ToString() +
+ "); }</script></html>";
+
+ return content;
+ }
+
+ TestConfig config_;
+
+ IMPLEMENT_REFCOUNTING(ConsoleTestHandler);
+};
+
+} // namespace
+
+TEST(DisplayTest, OnConsoleMessageDebug) {
+ ConsoleTestHandler::TestConfig config(LOGSEVERITY_DEBUG);
+ config.function = "debug";
+
+ CefRefPtr<ConsoleTestHandler> handler = new ConsoleTestHandler(config);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(DisplayTest, OnConsoleMessageCount) {
+ ConsoleTestHandler::TestConfig config(LOGSEVERITY_DEBUG);
+ config.function = "count";
+ config.expected_message = "Test Message: 1";
+
+ CefRefPtr<ConsoleTestHandler> handler = new ConsoleTestHandler(config);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(DisplayTest, OnConsoleMessageTimeEnd) {
+ ConsoleTestHandler::TestConfig config(LOGSEVERITY_WARNING);
+ config.function = "timeEnd";
+ config.expected_message = "Timer 'Test Message' does not exist";
+
+ CefRefPtr<ConsoleTestHandler> handler = new ConsoleTestHandler(config);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(DisplayTest, OnConsoleMessageInfo) {
+ ConsoleTestHandler::TestConfig config(LOGSEVERITY_INFO);
+ config.function = "info";
+
+ CefRefPtr<ConsoleTestHandler> handler = new ConsoleTestHandler(config);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(DisplayTest, OnConsoleMessageLog) {
+ ConsoleTestHandler::TestConfig config(LOGSEVERITY_INFO);
+ config.function = "log";
+
+ CefRefPtr<ConsoleTestHandler> handler = new ConsoleTestHandler(config);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(DisplayTest, OnConsoleMessageGroup) {
+ ConsoleTestHandler::TestConfig config(LOGSEVERITY_INFO);
+ config.function = "group";
+
+ CefRefPtr<ConsoleTestHandler> handler = new ConsoleTestHandler(config);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(DisplayTest, OnConsoleMessageGroupCollapsed) {
+ ConsoleTestHandler::TestConfig config(LOGSEVERITY_INFO);
+ config.function = "groupCollapsed";
+
+ CefRefPtr<ConsoleTestHandler> handler = new ConsoleTestHandler(config);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(DisplayTest, OnConsoleMessageGroupEnd) {
+ ConsoleTestHandler::TestConfig config(LOGSEVERITY_INFO);
+ config.function = "groupEnd";
+
+ CefRefPtr<ConsoleTestHandler> handler = new ConsoleTestHandler(config);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(DisplayTest, OnConsoleMessageTable) {
+ ConsoleTestHandler::TestConfig config(LOGSEVERITY_INFO);
+ config.function = "table";
+ config.message = "[1, 2, 3]";
+ config.expected_message = "1,2,3";
+
+ CefRefPtr<ConsoleTestHandler> handler = new ConsoleTestHandler(config);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(DisplayTest, OnConsoleMessageTrace) {
+ ConsoleTestHandler::TestConfig config(LOGSEVERITY_INFO);
+ config.function = "trace";
+ config.message = "";
+ config.expected_message = "console.trace";
+
+ CefRefPtr<ConsoleTestHandler> handler = new ConsoleTestHandler(config);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(DisplayTest, OnConsoleMessageWarn) {
+ ConsoleTestHandler::TestConfig config(LOGSEVERITY_WARNING);
+ config.function = "warn";
+
+ CefRefPtr<ConsoleTestHandler> handler = new ConsoleTestHandler(config);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(DisplayTest, OnConsoleMessageError) {
+ ConsoleTestHandler::TestConfig config(LOGSEVERITY_ERROR);
+ config.function = "error";
+
+ CefRefPtr<ConsoleTestHandler> handler = new ConsoleTestHandler(config);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(DisplayTest, OnConsoleMessageAssert) {
+ ConsoleTestHandler::TestConfig config(LOGSEVERITY_ERROR);
+ config.function = "assert";
+ config.message = "false";
+ config.expected_message = "console.assert";
+
+ CefRefPtr<ConsoleTestHandler> handler = new ConsoleTestHandler(config);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+namespace {
+
+const char kLoadinProgressUrl[] = "http://tests-display/loading-progress.html";
+
+// Browser side.
+class LoadingProgressTestHandler : public TestHandler {
+ public:
+ LoadingProgressTestHandler() {}
+
+ void RunTest() override {
+ // Add the resources that we will navigate to/from.
+ AddResource(kLoadinProgressUrl,
+ "<html><head><style>"
+ "body {overflow:hidden;margin:0px;padding:0px;}"
+ "</style></head><body><div id=a>Content</div></body></html>",
+ "text/html");
+
+ // Create the browser.
+ CreateBrowser(kLoadinProgressUrl);
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout();
+ }
+
+ void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
+ bool isLoading,
+ bool canGoBack,
+ bool canGoForward) override {
+ if (isLoading) {
+ return;
+ }
+
+ DestroyTest();
+ }
+
+ void OnLoadingProgressChange(CefRefPtr<CefBrowser> browser,
+ double progress) override {
+ if (!got_loading_progress_change0_) {
+ got_loading_progress_change0_.yes();
+ EXPECT_GE(progress, 0.0);
+ } else if (!got_loading_progress_change1_) {
+ got_loading_progress_change1_.yes();
+ EXPECT_LE(progress, 1.0);
+ }
+ }
+
+ void DestroyTest() override {
+ EXPECT_TRUE(got_loading_progress_change0_);
+ EXPECT_TRUE(got_loading_progress_change1_);
+ TestHandler::DestroyTest();
+ }
+
+ private:
+ TrackCallback got_loading_progress_change0_;
+ TrackCallback got_loading_progress_change1_;
+
+ IMPLEMENT_REFCOUNTING(LoadingProgressTestHandler);
+};
+
+} // namespace
+
+// Test OnLoadingProgressChange notification.
+TEST(DisplayTest, LoadingProgress) {
+ CefRefPtr<LoadingProgressTestHandler> handler =
+ new LoadingProgressTestHandler();
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
diff --git a/tests/ceftests/dom_unittest.cc b/tests/ceftests/dom_unittest.cc
new file mode 100644
index 00000000..0be485c7
--- /dev/null
+++ b/tests/ceftests/dom_unittest.cc
@@ -0,0 +1,379 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "include/cef_dom.h"
+#include "tests/ceftests/test_handler.h"
+#include "tests/gtest/include/gtest/gtest.h"
+#include "tests/shared/renderer/client_app_renderer.h"
+
+using client::ClientAppRenderer;
+
+namespace {
+
+const char* kTestUrl = "http://tests/DOMTest.Test";
+const char* kTestMessage = "DOMTest.Message";
+
+enum DOMTestType {
+ DOM_TEST_STRUCTURE,
+ DOM_TEST_MODIFY,
+};
+
+class TestDOMVisitor : public CefDOMVisitor {
+ public:
+ explicit TestDOMVisitor(CefRefPtr<CefBrowser> browser, DOMTestType test_type)
+ : browser_(browser), test_type_(test_type) {}
+
+ void TestHeadNodeStructure(CefRefPtr<CefDOMNode> headNode) {
+ EXPECT_TRUE(headNode.get());
+ EXPECT_TRUE(headNode->IsElement());
+ EXPECT_FALSE(headNode->IsText());
+ EXPECT_EQ(headNode->GetName(), "HEAD");
+ EXPECT_EQ(headNode->GetElementTagName(), "HEAD");
+
+ EXPECT_TRUE(headNode->HasChildren());
+ EXPECT_FALSE(headNode->HasElementAttributes());
+
+ CefRefPtr<CefDOMNode> titleNode = headNode->GetFirstChild();
+ EXPECT_TRUE(titleNode.get());
+ EXPECT_TRUE(titleNode->IsElement());
+ EXPECT_FALSE(titleNode->IsText());
+ EXPECT_EQ(titleNode->GetName(), "TITLE");
+ EXPECT_EQ(titleNode->GetElementTagName(), "TITLE");
+ EXPECT_TRUE(titleNode->GetParent()->IsSame(headNode));
+
+ EXPECT_FALSE(titleNode->GetNextSibling().get());
+ EXPECT_FALSE(titleNode->GetPreviousSibling().get());
+ EXPECT_TRUE(titleNode->HasChildren());
+ EXPECT_FALSE(titleNode->HasElementAttributes());
+
+ CefRefPtr<CefDOMNode> textNode = titleNode->GetFirstChild();
+ EXPECT_TRUE(textNode.get());
+ EXPECT_FALSE(textNode->IsElement());
+ EXPECT_TRUE(textNode->IsText());
+ EXPECT_EQ(textNode->GetValue(), "The Title");
+ EXPECT_TRUE(textNode->GetParent()->IsSame(titleNode));
+
+ EXPECT_FALSE(textNode->GetNextSibling().get());
+ EXPECT_FALSE(textNode->GetPreviousSibling().get());
+ EXPECT_FALSE(textNode->HasChildren());
+ }
+
+ void TestBodyNodeStructure(CefRefPtr<CefDOMNode> bodyNode,
+ float devicePixelRatio) {
+ EXPECT_TRUE(bodyNode.get());
+ EXPECT_TRUE(bodyNode->IsElement());
+ EXPECT_FALSE(bodyNode->IsText());
+ EXPECT_EQ(bodyNode->GetName(), "BODY");
+ EXPECT_EQ(bodyNode->GetElementTagName(), "BODY");
+
+ EXPECT_TRUE(bodyNode->HasChildren());
+ EXPECT_FALSE(bodyNode->HasElementAttributes());
+
+ CefRefPtr<CefDOMNode> h1Node = bodyNode->GetFirstChild();
+ EXPECT_TRUE(h1Node.get());
+ EXPECT_TRUE(h1Node->IsElement());
+ EXPECT_FALSE(h1Node->IsText());
+ EXPECT_EQ(h1Node->GetName(), "H1");
+ EXPECT_EQ(h1Node->GetElementTagName(), "H1");
+
+ EXPECT_TRUE(h1Node->GetNextSibling().get());
+ EXPECT_FALSE(h1Node->GetPreviousSibling().get());
+ EXPECT_TRUE(h1Node->HasChildren());
+ EXPECT_FALSE(h1Node->HasElementAttributes());
+
+ CefRefPtr<CefDOMNode> textNode = h1Node->GetFirstChild();
+ EXPECT_TRUE(textNode.get());
+ EXPECT_FALSE(textNode->IsElement());
+ EXPECT_TRUE(textNode->IsText());
+ EXPECT_EQ(textNode->GetValue(), "Hello From");
+
+ EXPECT_FALSE(textNode->GetPreviousSibling().get());
+ EXPECT_FALSE(textNode->HasChildren());
+
+ CefRefPtr<CefDOMNode> brNode = textNode->GetNextSibling();
+ EXPECT_TRUE(brNode.get());
+ EXPECT_TRUE(brNode->IsElement());
+ EXPECT_FALSE(brNode->IsText());
+ EXPECT_EQ(brNode->GetName(), "BR");
+ EXPECT_EQ(brNode->GetElementTagName(), "BR");
+
+ EXPECT_FALSE(brNode->HasChildren());
+
+ EXPECT_TRUE(brNode->HasElementAttributes());
+ EXPECT_TRUE(brNode->HasElementAttribute("class"));
+ EXPECT_EQ(brNode->GetElementAttribute("class"), "some_class");
+ EXPECT_TRUE(brNode->HasElementAttribute("id"));
+ EXPECT_EQ(brNode->GetElementAttribute("id"), "some_id");
+ EXPECT_FALSE(brNode->HasElementAttribute("no_existing"));
+
+ CefDOMNode::AttributeMap map;
+ brNode->GetElementAttributes(map);
+ ASSERT_EQ(map.size(), (size_t)2);
+ EXPECT_EQ(map["class"], "some_class");
+ EXPECT_EQ(map["id"], "some_id");
+
+ // Can also retrieve by ID.
+ brNode = bodyNode->GetDocument()->GetElementById("some_id");
+ EXPECT_TRUE(brNode.get());
+ EXPECT_TRUE(brNode->IsElement());
+ EXPECT_FALSE(brNode->IsText());
+ EXPECT_EQ(brNode->GetName(), "BR");
+ EXPECT_EQ(brNode->GetElementTagName(), "BR");
+
+ textNode = brNode->GetNextSibling();
+ EXPECT_TRUE(textNode.get());
+ EXPECT_FALSE(textNode->IsElement());
+ EXPECT_TRUE(textNode->IsText());
+ EXPECT_EQ(textNode->GetValue(), "Main Frame");
+
+ EXPECT_FALSE(textNode->GetNextSibling().get());
+ EXPECT_FALSE(textNode->HasChildren());
+
+ CefRefPtr<CefDOMNode> divNode = h1Node->GetNextSibling();
+ EXPECT_TRUE(divNode.get());
+ EXPECT_TRUE(divNode->IsElement());
+ EXPECT_FALSE(divNode->IsText());
+
+ // Returned bounds are in device pixels.
+ CefRect divRect = divNode->GetElementBounds();
+ EXPECT_NEAR(divRect.width, 50.0 * devicePixelRatio, 1);
+ EXPECT_NEAR(divRect.height, 25.0 * devicePixelRatio, 1);
+ EXPECT_NEAR(divRect.x, 150.0 * devicePixelRatio, 1);
+ EXPECT_NEAR(divRect.y, 100.0 * devicePixelRatio, 1);
+
+ EXPECT_FALSE(divNode->GetNextSibling().get());
+ }
+
+ // Test document structure by iterating through the DOM tree.
+ void TestStructure(CefRefPtr<CefDOMDocument> document) {
+ EXPECT_EQ(document->GetTitle(), "The Title");
+ EXPECT_EQ(document->GetBaseURL(), kTestUrl);
+ EXPECT_EQ(document->GetCompleteURL("foo.html"), "http://tests/foo.html");
+
+ // Navigate the complete document structure.
+ CefRefPtr<CefDOMNode> docNode = document->GetDocument();
+ EXPECT_TRUE(docNode.get());
+ EXPECT_FALSE(docNode->IsElement());
+ EXPECT_FALSE(docNode->IsText());
+
+ CefRefPtr<CefDOMNode> htmlNode = docNode->GetFirstChild();
+ EXPECT_TRUE(htmlNode.get());
+ EXPECT_TRUE(htmlNode->IsElement());
+ EXPECT_FALSE(htmlNode->IsText());
+ EXPECT_EQ(htmlNode->GetName(), "HTML");
+ EXPECT_EQ(htmlNode->GetElementTagName(), "HTML");
+
+ EXPECT_TRUE(htmlNode->HasChildren());
+ EXPECT_FALSE(htmlNode->HasElementAttributes());
+
+ CefRefPtr<CefDOMNode> headNode = htmlNode->GetFirstChild();
+ TestHeadNodeStructure(headNode);
+
+ const float devicePixelRatio = GetDevicePixelRatio();
+
+ CefRefPtr<CefDOMNode> bodyNode = headNode->GetNextSibling();
+ TestBodyNodeStructure(bodyNode, devicePixelRatio);
+
+ // Retrieve the head node directly.
+ headNode = document->GetHead();
+ TestHeadNodeStructure(headNode);
+
+ // Retrieve the body node directly.
+ bodyNode = document->GetBody();
+ TestBodyNodeStructure(bodyNode, devicePixelRatio);
+ }
+
+ // Test document modification by changing the H1 tag.
+ void TestModify(CefRefPtr<CefDOMDocument> document) {
+ CefRefPtr<CefDOMNode> bodyNode = document->GetBody();
+ CefRefPtr<CefDOMNode> h1Node = bodyNode->GetFirstChild();
+
+ ASSERT_EQ(h1Node->GetAsMarkup(),
+ "<h1>Hello From<br class=\"some_class\" id=\"some_id\">"
+ "Main Frame</h1>");
+
+ CefRefPtr<CefDOMNode> textNode = h1Node->GetFirstChild();
+ ASSERT_EQ(textNode->GetValue(), "Hello From");
+ ASSERT_TRUE(textNode->SetValue("A Different Message From"));
+ ASSERT_EQ(textNode->GetValue(), "A Different Message From");
+
+ CefRefPtr<CefDOMNode> brNode = textNode->GetNextSibling();
+ EXPECT_EQ(brNode->GetElementAttribute("class"), "some_class");
+ EXPECT_TRUE(brNode->SetElementAttribute("class", "a_different_class"));
+ EXPECT_EQ(brNode->GetElementAttribute("class"), "a_different_class");
+
+ ASSERT_EQ(h1Node->GetAsMarkup(),
+ "<h1>A Different Message From<br class=\"a_different_class\" "
+ "id=\"some_id\">Main Frame</h1>");
+
+ ASSERT_FALSE(h1Node->SetValue("Something Different"));
+ }
+
+ void Visit(CefRefPtr<CefDOMDocument> document) override {
+ if (test_type_ == DOM_TEST_STRUCTURE) {
+ TestStructure(document);
+ } else if (test_type_ == DOM_TEST_MODIFY) {
+ TestModify(document);
+ }
+
+ DestroyTest();
+ }
+
+ protected:
+ // Return from the test.
+ void DestroyTest() {
+ // Check if the test has failed.
+ bool result = !TestFailed();
+
+ // Return the result to the browser process.
+ CefRefPtr<CefProcessMessage> return_msg =
+ CefProcessMessage::Create(kTestMessage);
+ EXPECT_TRUE(return_msg->GetArgumentList()->SetBool(0, result));
+ browser_->GetMainFrame()->SendProcessMessage(PID_BROWSER, return_msg);
+ }
+
+ // Used to convert between device pixels and CSS pixels.
+ float GetDevicePixelRatio() {
+ auto context = browser_->GetMainFrame()->GetV8Context();
+ EXPECT_TRUE(context);
+
+ CefRefPtr<CefV8Value> retval;
+ CefRefPtr<CefV8Exception> exception;
+ EXPECT_TRUE(context->Eval("window.devicePixelRatio", CefString(), 0, retval,
+ exception));
+ if (exception) {
+ ADD_FAILURE() << exception->GetMessage().c_str();
+ return 1.0;
+ }
+
+ if (retval->IsValid() && retval->IsDouble()) {
+ return static_cast<float>(retval->GetDoubleValue());
+ }
+
+ ADD_FAILURE() << "Failed to retrieve devicePixelRatio";
+ return 1.0;
+ }
+
+ CefRefPtr<CefBrowser> browser_;
+ DOMTestType test_type_;
+
+ IMPLEMENT_REFCOUNTING(TestDOMVisitor);
+};
+
+// Used in the render process.
+class DOMRendererTest : public ClientAppRenderer::Delegate {
+ public:
+ DOMRendererTest() {}
+
+ bool OnProcessMessageReceived(CefRefPtr<ClientAppRenderer> app,
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefProcessId source_process,
+ CefRefPtr<CefProcessMessage> message) override {
+ if (message->GetName() == kTestMessage) {
+ EXPECT_EQ(message->GetArgumentList()->GetSize(), (size_t)1);
+ int test_type = message->GetArgumentList()->GetInt(0);
+
+ browser->GetMainFrame()->VisitDOM(
+ new TestDOMVisitor(browser, static_cast<DOMTestType>(test_type)));
+ return true;
+ }
+ return false;
+ }
+
+ private:
+ IMPLEMENT_REFCOUNTING(DOMRendererTest);
+};
+
+// Used in the browser process.
+class TestDOMHandler : public TestHandler {
+ public:
+ explicit TestDOMHandler(DOMTestType test) : test_type_(test) {}
+
+ void RunTest() override {
+ // Specified values are in CSS pixels.
+ std::stringstream mainHtml;
+ mainHtml << "<html>"
+ "<head><title>The Title</title></head>"
+ "<body>"
+ "<h1>Hello From<br class=\"some_class\"/ id=\"some_id\"/>"
+ "Main Frame</h1>"
+ "<div id=\"sized_element\" style=\"width: 50px; height: 25px; "
+ "position: fixed; top: 100px; left: 150px;\"/>"
+ "</body>"
+ "</html>";
+
+ AddResource(kTestUrl, mainHtml.str(), "text/html");
+ CreateBrowser(kTestUrl);
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout();
+ }
+
+ void OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int httpStatusCode) override {
+ if (frame->IsMain()) {
+ // Start the test in the render process.
+ CefRefPtr<CefProcessMessage> message(
+ CefProcessMessage::Create(kTestMessage));
+ message->GetArgumentList()->SetInt(0, test_type_);
+ frame->SendProcessMessage(PID_RENDERER, message);
+ }
+ }
+
+ bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefProcessId source_process,
+ CefRefPtr<CefProcessMessage> message) override {
+ EXPECT_STREQ(message->GetName().ToString().c_str(), kTestMessage);
+
+ got_message_.yes();
+
+ if (message->GetArgumentList()->GetBool(0)) {
+ got_success_.yes();
+ }
+
+ // Test is complete.
+ DestroyTest();
+
+ return true;
+ }
+
+ DOMTestType test_type_;
+ TrackCallback got_message_;
+ TrackCallback got_success_;
+
+ IMPLEMENT_REFCOUNTING(TestDOMHandler);
+};
+
+} // namespace
+
+// Test DOM structure reading.
+TEST(DOMTest, Read) {
+ CefRefPtr<TestDOMHandler> handler = new TestDOMHandler(DOM_TEST_STRUCTURE);
+ handler->ExecuteTest();
+
+ EXPECT_TRUE(handler->got_message_);
+ EXPECT_TRUE(handler->got_success_);
+
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Test DOM modifications.
+TEST(DOMTest, Modify) {
+ CefRefPtr<TestDOMHandler> handler = new TestDOMHandler(DOM_TEST_MODIFY);
+ handler->ExecuteTest();
+
+ EXPECT_TRUE(handler->got_message_);
+ EXPECT_TRUE(handler->got_success_);
+
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Entry point for creating DOM renderer test objects.
+// Called from client_app_delegates.cc.
+void CreateDOMRendererTests(ClientAppRenderer::DelegateSet& delegates) {
+ delegates.insert(new DOMRendererTest);
+}
diff --git a/tests/ceftests/download_unittest.cc b/tests/ceftests/download_unittest.cc
new file mode 100644
index 00000000..c31c7049
--- /dev/null
+++ b/tests/ceftests/download_unittest.cc
@@ -0,0 +1,600 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include <algorithm>
+#include <memory>
+
+#include "include/base/cef_callback.h"
+#include "include/base/cef_callback_helpers.h"
+#include "include/cef_scheme.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "include/wrapper/cef_scoped_temp_dir.h"
+#include "tests/ceftests/test_handler.h"
+#include "tests/ceftests/test_util.h"
+#include "tests/gtest/include/gtest/gtest.h"
+#include "tests/shared/browser/file_util.h"
+
+namespace {
+
+const char kTestDomain[] = "test-download.com";
+const char kTestStartUrl[] = "http://test-download.com/test.html";
+const char kTestDownloadUrl[] = "http://test-download.com/download.txt";
+const char kTestNavUrl[] = "http://test-download-nav.com/nav.html";
+const char kTestFileName[] = "download_test.txt";
+const char kTestContentDisposition[] =
+ "attachment; filename=\"download_test.txt\"";
+const char kTestMimeType[] = "text/plain";
+const char kTestContent[] = "Download test text";
+
+using DelayCallback = base::OnceCallback<void(base::OnceClosure /*callback*/)>;
+
+class DownloadSchemeHandler : public CefResourceHandler {
+ public:
+ DownloadSchemeHandler(DelayCallback delay_callback,
+ TrackCallback* got_download_request)
+ : delay_callback_(std::move(delay_callback)),
+ got_download_request_(got_download_request),
+ should_delay_(false),
+ offset_(0) {}
+
+ bool Open(CefRefPtr<CefRequest> request,
+ bool& handle_request,
+ CefRefPtr<CefCallback> callback) override {
+ EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO));
+
+ std::string url = request->GetURL();
+ if (url == kTestDownloadUrl) {
+ got_download_request_->yes();
+ content_ = kTestContent;
+ mime_type_ = kTestMimeType;
+ content_disposition_ = kTestContentDisposition;
+ should_delay_ = true;
+ } else {
+ EXPECT_TRUE(false); // Not reached.
+
+ // Cancel immediately.
+ handle_request = true;
+ return false;
+ }
+
+ // Continue immediately.
+ handle_request = true;
+ return true;
+ }
+
+ void GetResponseHeaders(CefRefPtr<CefResponse> response,
+ int64& response_length,
+ CefString& redirectUrl) override {
+ response_length = content_.size();
+
+ response->SetStatus(200);
+ response->SetMimeType(mime_type_);
+
+ if (!content_disposition_.empty()) {
+ CefResponse::HeaderMap headerMap;
+ response->GetHeaderMap(headerMap);
+ headerMap.insert(
+ std::make_pair("Content-Disposition", content_disposition_));
+ response->SetHeaderMap(headerMap);
+ }
+ }
+
+ bool Read(void* data_out,
+ int bytes_to_read,
+ int& bytes_read,
+ CefRefPtr<CefResourceReadCallback> callback) override {
+ EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO));
+
+ bytes_read = 0;
+
+ if (should_delay_ && !delay_callback_.is_null()) {
+ // Delay the download response a single time.
+ std::move(delay_callback_)
+ .Run(base::BindOnce(&DownloadSchemeHandler::ContinueRead, this,
+ data_out, bytes_to_read, callback));
+ return true;
+ }
+
+ return DoRead(data_out, bytes_to_read, bytes_read);
+ }
+
+ void Cancel() override {}
+
+ private:
+ void ContinueRead(void* data_out,
+ int bytes_to_read,
+ CefRefPtr<CefResourceReadCallback> callback) {
+ int bytes_read = 0;
+ DoRead(data_out, bytes_to_read, bytes_read);
+ callback->Continue(bytes_read);
+ }
+
+ bool DoRead(void* data_out, int bytes_to_read, int& bytes_read) {
+ bool has_data = false;
+ size_t size = content_.size();
+ if (offset_ < size) {
+ int transfer_size =
+ std::min(bytes_to_read, static_cast<int>(size - offset_));
+ memcpy(data_out, content_.c_str() + offset_, transfer_size);
+ offset_ += transfer_size;
+
+ bytes_read = transfer_size;
+ has_data = true;
+ }
+
+ return has_data;
+ }
+
+ DelayCallback delay_callback_;
+ TrackCallback* got_download_request_;
+ bool should_delay_;
+ std::string content_;
+ std::string mime_type_;
+ std::string content_disposition_;
+ size_t offset_;
+ CefRefPtr<CefResourceReadCallback> read_callback_;
+
+ IMPLEMENT_REFCOUNTING(DownloadSchemeHandler);
+ DISALLOW_COPY_AND_ASSIGN(DownloadSchemeHandler);
+};
+
+using DelayCallbackVendor = base::RepeatingCallback<DelayCallback(void)>;
+
+class DownloadSchemeHandlerFactory : public CefSchemeHandlerFactory {
+ public:
+ DownloadSchemeHandlerFactory(const DelayCallbackVendor& delay_callback_vendor,
+ TrackCallback* got_download_request)
+ : delay_callback_vendor_(delay_callback_vendor),
+ got_download_request_(got_download_request) {}
+
+ CefRefPtr<CefResourceHandler> Create(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const CefString& scheme_name,
+ CefRefPtr<CefRequest> request) override {
+ return new DownloadSchemeHandler(delay_callback_vendor_.is_null()
+ ? base::NullCallback()
+ : delay_callback_vendor_.Run(),
+ got_download_request_);
+ }
+
+ private:
+ DelayCallbackVendor delay_callback_vendor_;
+ TrackCallback* got_download_request_;
+
+ IMPLEMENT_REFCOUNTING(DownloadSchemeHandlerFactory);
+ DISALLOW_COPY_AND_ASSIGN(DownloadSchemeHandlerFactory);
+};
+
+class DownloadTestHandler : public TestHandler {
+ public:
+ enum TestMode {
+ PROGRAMMATIC,
+ NAVIGATED,
+ PENDING,
+ CLICKED,
+ CLICKED_INVALID,
+ CLICKED_BLOCKED,
+ };
+
+ DownloadTestHandler(TestMode test_mode,
+ TestRequestContextMode rc_mode,
+ const std::string& rc_cache_path)
+ : test_mode_(test_mode),
+ rc_mode_(rc_mode),
+ rc_cache_path_(rc_cache_path),
+ download_id_(0),
+ verified_results_(false) {}
+
+ bool is_clicked() const {
+ return test_mode_ == CLICKED || test_mode_ == CLICKED_INVALID ||
+ test_mode_ == CLICKED_BLOCKED;
+ }
+
+ bool is_clicked_and_downloaded() const { return test_mode_ == CLICKED; }
+
+ bool is_downloaded() const {
+ return test_mode_ == PROGRAMMATIC || test_mode_ == NAVIGATED ||
+ is_clicked_and_downloaded();
+ }
+
+ void RunTest() override {
+ DelayCallbackVendor delay_callback_vendor;
+ if (test_mode_ == NAVIGATED || test_mode_ == PENDING) {
+ delay_callback_vendor = base::BindRepeating(
+ [](CefRefPtr<DownloadTestHandler> self) {
+ return base::BindOnce(&DownloadTestHandler::OnDelayCallback, self);
+ },
+ CefRefPtr<DownloadTestHandler>(this));
+ }
+
+ CefRefPtr<CefSchemeHandlerFactory> scheme_factory =
+ new DownloadSchemeHandlerFactory(delay_callback_vendor,
+ &got_download_request_);
+
+ CefRefPtr<CefRequestContext> request_context =
+ CreateTestRequestContext(rc_mode_, rc_cache_path_);
+ if (request_context) {
+ request_context->RegisterSchemeHandlerFactory("http", kTestDomain,
+ scheme_factory);
+ } else {
+ CefRegisterSchemeHandlerFactory("http", kTestDomain, scheme_factory);
+ }
+
+ if (!is_clicked() || is_clicked_and_downloaded()) {
+ // Create a new temporary directory.
+ EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
+ test_path_ =
+ client::file_util::JoinPath(temp_dir_.GetPath(), kTestFileName);
+ }
+
+ if (test_mode_ == NAVIGATED) {
+ // Add the resource that we'll navigate to.
+ AddResource(kTestNavUrl, "<html><body>Navigated</body></html>",
+ "text/html");
+ }
+
+ if (is_clicked()) {
+ if (test_mode_ == CLICKED || test_mode_ == CLICKED_BLOCKED) {
+ download_url_ = kTestDownloadUrl;
+ } else if (test_mode_ == CLICKED_INVALID) {
+ download_url_ = "invalid:foo@example.com";
+ } else {
+ EXPECT_TRUE(false); // Not reached.
+ }
+ AddResource(kTestStartUrl,
+ "<html><body><a href=\"" + download_url_ +
+ "\">CLICK ME</a></body></html>",
+ "text/html");
+ } else {
+ download_url_ = kTestStartUrl;
+ AddResource(kTestStartUrl, "<html><body>Download Test</body></html>",
+ "text/html");
+ }
+
+ // Create the browser
+ CreateBrowser(kTestStartUrl, request_context);
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout();
+ }
+
+ void OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int httpStatusCode) override {
+ const std::string& url = frame->GetURL().ToString();
+ if (url == kTestNavUrl) {
+ got_nav_load_.yes();
+ ContinueNavigatedIfReady();
+ return;
+ }
+
+ if (is_clicked()) {
+ // Begin the download by clicking a link.
+ // ALT key will trigger download of custom protocol links.
+ SendClick(browser,
+ test_mode_ == CLICKED_INVALID ? EVENTFLAG_ALT_DOWN : 0);
+
+ if (is_clicked() && !is_clicked_and_downloaded()) {
+ // Destroy the test after a bit because there will be no further
+ // callbacks.
+ CefPostDelayedTask(
+ TID_UI, base::BindOnce(&DownloadTestHandler::DestroyTest, this),
+ 200);
+ }
+ } else {
+ // Begin the download progammatically.
+ browser->GetHost()->StartDownload(kTestDownloadUrl);
+ }
+ }
+
+ // Callback from the scheme handler when the download request is delayed.
+ void OnDelayCallback(base::OnceClosure callback) {
+ if (!CefCurrentlyOn(TID_UI)) {
+ CefPostTask(TID_UI, base::BindOnce(&DownloadTestHandler::OnDelayCallback,
+ this, std::move(callback)));
+ return;
+ }
+
+ got_delay_callback_.yes();
+
+ if (test_mode_ == NAVIGATED) {
+ delay_callback_ = std::move(callback);
+ ContinueNavigatedIfReady();
+ } else if (test_mode_ == PENDING) {
+ ContinuePendingIfReady();
+ } else {
+ EXPECT_TRUE(false); // Not reached.
+ }
+ }
+
+ void ContinueNavigatedIfReady() {
+ EXPECT_EQ(test_mode_, NAVIGATED);
+ if (got_delay_callback_ && got_nav_load_) {
+ EXPECT_FALSE(delay_callback_.is_null());
+ std::move(delay_callback_).Run();
+ }
+ }
+
+ void ContinuePendingIfReady() {
+ EXPECT_EQ(test_mode_, PENDING);
+ if (got_delay_callback_ && got_on_before_download_ &&
+ got_on_download_updated_) {
+ // Destroy the test without waiting for the download to complete.
+ DestroyTest();
+ }
+ }
+
+ bool CanDownload(CefRefPtr<CefBrowser> browser,
+ const CefString& url,
+ const CefString& request_method) override {
+ EXPECT_TRUE(CefCurrentlyOn(TID_UI));
+ EXPECT_FALSE(got_can_download_);
+ EXPECT_FALSE(got_on_before_download_);
+ EXPECT_TRUE(is_clicked());
+
+ got_can_download_.yes();
+
+ EXPECT_TRUE(browser->IsSame(GetBrowser()));
+ EXPECT_STREQ(download_url_.c_str(), url.ToString().c_str());
+ EXPECT_STREQ("GET", request_method.ToString().c_str());
+
+ return test_mode_ != CLICKED_BLOCKED;
+ }
+
+ void OnBeforeDownload(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefDownloadItem> download_item,
+ const CefString& suggested_name,
+ CefRefPtr<CefBeforeDownloadCallback> callback) override {
+ EXPECT_TRUE(CefCurrentlyOn(TID_UI));
+ EXPECT_FALSE(got_on_before_download_);
+
+ if (is_clicked()) {
+ EXPECT_TRUE(got_can_download_);
+ } else {
+ EXPECT_FALSE(got_can_download_);
+ }
+
+ got_on_before_download_.yes();
+
+ EXPECT_TRUE(browser->IsSame(GetBrowser()));
+ EXPECT_STREQ(kTestFileName, suggested_name.ToString().c_str());
+ EXPECT_TRUE(download_item.get());
+ EXPECT_TRUE(callback.get());
+
+ download_id_ = download_item->GetId();
+ EXPECT_LT(0U, download_id_);
+
+ EXPECT_TRUE(download_item->IsValid());
+ EXPECT_TRUE(download_item->IsInProgress());
+ EXPECT_FALSE(download_item->IsComplete());
+ EXPECT_FALSE(download_item->IsCanceled());
+ EXPECT_EQ(static_cast<int64>(sizeof(kTestContent) - 1),
+ download_item->GetTotalBytes());
+ EXPECT_EQ(0UL, download_item->GetFullPath().length());
+ EXPECT_STREQ(kTestDownloadUrl, download_item->GetURL().ToString().c_str());
+ EXPECT_EQ(0UL, download_item->GetSuggestedFileName().length());
+ EXPECT_STREQ(kTestContentDisposition,
+ download_item->GetContentDisposition().ToString().c_str());
+ EXPECT_STREQ(kTestMimeType,
+ download_item->GetMimeType().ToString().c_str());
+
+ callback->Continue(test_path_, false);
+
+ if (test_mode_ == NAVIGATED) {
+ CefRefPtr<CefFrame> main_frame = browser->GetMainFrame();
+ EXPECT_TRUE(main_frame->IsMain());
+ main_frame->LoadURL(kTestNavUrl);
+ } else if (test_mode_ == PENDING) {
+ ContinuePendingIfReady();
+ }
+ }
+
+ void OnDownloadUpdated(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefDownloadItem> download_item,
+ CefRefPtr<CefDownloadItemCallback> callback) override {
+ EXPECT_TRUE(CefCurrentlyOn(TID_UI));
+
+ if (destroyed_) {
+ return;
+ }
+
+ got_on_download_updated_.yes();
+
+ EXPECT_TRUE(browser->IsSame(GetBrowser()));
+ EXPECT_TRUE(download_item.get());
+ EXPECT_TRUE(callback.get());
+
+ if (got_on_before_download_) {
+ EXPECT_EQ(download_id_, download_item->GetId());
+ }
+
+ EXPECT_LE(0LL, download_item->GetCurrentSpeed());
+ EXPECT_LE(0, download_item->GetPercentComplete());
+
+ EXPECT_TRUE(download_item->IsValid());
+ EXPECT_FALSE(download_item->IsCanceled());
+ EXPECT_STREQ(kTestDownloadUrl, download_item->GetURL().ToString().c_str());
+ EXPECT_STREQ(kTestContentDisposition,
+ download_item->GetContentDisposition().ToString().c_str());
+ EXPECT_STREQ(kTestMimeType,
+ download_item->GetMimeType().ToString().c_str());
+
+ std::string full_path = download_item->GetFullPath();
+ if (!full_path.empty()) {
+ got_full_path_.yes();
+ EXPECT_STREQ(test_path_.c_str(), full_path.c_str());
+ }
+
+ if (download_item->IsComplete()) {
+ got_download_complete_.yes();
+
+ EXPECT_FALSE(download_item->IsInProgress());
+ EXPECT_EQ(100, download_item->GetPercentComplete());
+ EXPECT_EQ(static_cast<int64>(sizeof(kTestContent) - 1),
+ download_item->GetReceivedBytes());
+ EXPECT_EQ(static_cast<int64>(sizeof(kTestContent) - 1),
+ download_item->GetTotalBytes());
+
+ DestroyTest();
+ } else {
+ EXPECT_TRUE(download_item->IsInProgress());
+ EXPECT_LE(0LL, download_item->GetReceivedBytes());
+ }
+
+ if (test_mode_ == PENDING) {
+ download_item_callback_ = callback;
+ ContinuePendingIfReady();
+ }
+ }
+
+ void VerifyResultsOnFileThread() {
+ EXPECT_TRUE(CefCurrentlyOn(TID_FILE_USER_VISIBLE));
+
+ if (test_mode_ != PENDING) {
+ // Verify the file contents.
+ std::string contents;
+ EXPECT_TRUE(client::file_util::ReadFileToString(test_path_, &contents));
+ EXPECT_STREQ(kTestContent, contents.c_str());
+ }
+
+ EXPECT_TRUE(temp_dir_.Delete());
+ EXPECT_TRUE(temp_dir_.IsEmpty());
+
+ CefPostTask(TID_UI,
+ base::BindOnce(&DownloadTestHandler::DestroyTest, this));
+ }
+
+ void DestroyTest() override {
+ if (!verified_results_ && !temp_dir_.IsEmpty()) {
+ // Avoid an endless failure loop.
+ verified_results_ = true;
+ // Clean up temp_dir_ on the FILE thread before destroying the test.
+ CefPostTask(TID_FILE_USER_VISIBLE,
+ base::BindOnce(
+ &DownloadTestHandler::VerifyResultsOnFileThread, this));
+ return;
+ }
+
+ destroyed_ = true;
+
+ if (download_item_callback_) {
+ // Cancel the pending download to avoid leaking request objects.
+ download_item_callback_->Cancel();
+ download_item_callback_ = nullptr;
+ }
+
+ if (request_context_) {
+ request_context_->RegisterSchemeHandlerFactory("http", kTestDomain,
+ nullptr);
+ request_context_ = nullptr;
+ } else {
+ CefRegisterSchemeHandlerFactory("http", kTestDomain, nullptr);
+ }
+
+ if (is_clicked()) {
+ EXPECT_TRUE(got_can_download_);
+ } else {
+ EXPECT_FALSE(got_can_download_);
+ }
+
+ if (test_mode_ == CLICKED_INVALID) {
+ // The invalid protocol request is not handled.
+ EXPECT_FALSE(got_download_request_);
+ } else {
+ EXPECT_TRUE(got_download_request_);
+ }
+
+ if (is_clicked() && !is_clicked_and_downloaded()) {
+ // The download never proceeds.
+ EXPECT_FALSE(got_on_before_download_);
+ EXPECT_FALSE(got_on_download_updated_);
+ } else {
+ EXPECT_TRUE(got_on_before_download_);
+ EXPECT_TRUE(got_on_download_updated_);
+ }
+
+ if (test_mode_ == NAVIGATED) {
+ EXPECT_TRUE(got_nav_load_);
+ } else {
+ EXPECT_FALSE(got_nav_load_);
+ }
+
+ if (!is_downloaded()) {
+ // The download never completes.
+ EXPECT_FALSE(got_download_complete_);
+ EXPECT_FALSE(got_full_path_);
+ } else {
+ EXPECT_TRUE(got_download_complete_);
+ EXPECT_TRUE(got_full_path_);
+ }
+
+ TestHandler::DestroyTest();
+ }
+
+ private:
+ void SendClick(CefRefPtr<CefBrowser> browser, uint32_t modifiers) {
+ EXPECT_TRUE(is_clicked());
+ CefMouseEvent mouse_event;
+ mouse_event.x = 20;
+ mouse_event.y = 20;
+ mouse_event.modifiers = modifiers;
+ SendMouseClickEvent(browser, mouse_event);
+ }
+
+ const TestMode test_mode_;
+ const TestRequestContextMode rc_mode_;
+ const std::string rc_cache_path_;
+
+ CefRefPtr<CefRequestContext> request_context_;
+
+ // Used with NAVIGATED and PENDING test modes.
+ base::OnceClosure delay_callback_;
+
+ // Used with PENDING test mode.
+ CefRefPtr<CefDownloadItemCallback> download_item_callback_;
+
+ std::string download_url_;
+ CefScopedTempDir temp_dir_;
+ std::string test_path_;
+ uint32 download_id_;
+ bool verified_results_;
+ bool destroyed_ = false;
+
+ TrackCallback got_download_request_;
+ TrackCallback got_can_download_;
+ TrackCallback got_on_before_download_;
+ TrackCallback got_on_download_updated_;
+ TrackCallback got_full_path_;
+ TrackCallback got_download_complete_;
+ TrackCallback got_delay_callback_;
+ TrackCallback got_nav_load_;
+
+ IMPLEMENT_REFCOUNTING(DownloadTestHandler);
+};
+
+} // namespace
+
+#define DOWNLOAD_TEST_GROUP(test_name, test_mode) \
+ RC_TEST_GROUP_ALL(DownloadTest, test_name, DownloadTestHandler, test_mode)
+
+// Test a programmatic download.
+DOWNLOAD_TEST_GROUP(Programmatic, PROGRAMMATIC)
+
+// Test a clicked download.
+DOWNLOAD_TEST_GROUP(Clicked, CLICKED)
+
+// Test a clicked download where the protocol is invalid and therefore rejected.
+// There will be no resulting CefDownloadHandler callbacks.
+DOWNLOAD_TEST_GROUP(ClickedInvalid, CLICKED_INVALID)
+
+// Test a clicked download where CanDownload returns false.
+// There will be no resulting CefDownloadHandler callbacks.
+DOWNLOAD_TEST_GROUP(ClickedBlocked, CLICKED_BLOCKED)
+
+// Test where the download completes after cross-origin navigation.
+DOWNLOAD_TEST_GROUP(Navigated, NAVIGATED)
+
+// Test where the download is still pending when the browser is destroyed.
+DOWNLOAD_TEST_GROUP(Pending, PENDING)
diff --git a/tests/ceftests/draggable_regions_unittest.cc b/tests/ceftests/draggable_regions_unittest.cc
new file mode 100644
index 00000000..f541731d
--- /dev/null
+++ b/tests/ceftests/draggable_regions_unittest.cc
@@ -0,0 +1,267 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "include/base/cef_callback.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "tests/ceftests/test_handler.h"
+#include "tests/gtest/include/gtest/gtest.h"
+
+// Set to 1 to enable verbose debugging info logging.
+#define VERBOSE_DEBUGGING 0
+
+namespace {
+
+const char kTestHTMLWithRegions[] =
+ "<html>"
+ " <body>"
+ " <div style=\"position: absolute; top: 50px; left: 50px; width: 200px; "
+ "height: 200px; background-color: red; -webkit-app-region: drag;\">"
+ " <div style=\"position: absolute; top: 50%; left: 50%; "
+ "transform: translate(-50%, -50%); width: 50px; height: 50px; "
+ "background-color: blue; -webkit-app-region: no-drag;\">"
+ " </div>"
+ " </div>"
+ " </body>"
+ "</html>";
+
+const char kTestHTMLWithoutRegions[] = "<html><body>Hello World!</body></html>";
+
+const char kTestHTMLWithChangingRegions[] =
+ "<html>"
+ " <body>"
+ " <div id=\"layer\" style=\"position: absolute; top: 50px; left: 50px; "
+ "width: 200px; height: 200px; background-color: red; "
+ "-webkit-app-region: drag;\">"
+ " <div style=\"position: absolute; top: 50%; left: 50%; "
+ "transform: translate(-50%, -50%); width: 50px; height: 50px; "
+ "background-color: blue; -webkit-app-region: no-drag;\">"
+ " </div>"
+ " </div>"
+ " <script>"
+ " window.setTimeout(function() {"
+ " var layer = document.getElementById('layer');"
+ " layer.style.top = '0px';"
+ " layer.style.left = '0px';"
+ " }, 500);"
+ " </script>"
+ " </body>"
+ "</html>";
+
+class DraggableRegionsTestHandler : public TestHandler,
+ public CefDragHandler,
+ public CefFrameHandler {
+ public:
+ // Test steps executed in order.
+ enum Step {
+ // Nav 1: Two regions (get notification).
+ kStepWithRegions = 1,
+ // Nav 2: Starts with the same region as Nav 1 (no notification),
+ // then a changed region (get notification).
+ kStepWithChangingRegions,
+ // Nav 3: No regions (get notification).
+ kStepWithoutRegions,
+ // GoBack: Two regions (get notification), then a changed region (get
+ // notification). Note the first notification is not sent if
+ // BackForwardCache is enabled.
+ kStepWithChangingRegions2,
+ kStepWithChangingRegions3,
+ // GoForward: No regions (get notification).
+ kStepWithoutRegions2,
+
+ kStepMax = kStepWithoutRegions2,
+ };
+
+ explicit DraggableRegionsTestHandler(bool same_origin)
+ : same_origin_(same_origin) {}
+
+ void RunTest() override {
+ // Add HTML documents with and without draggable regions.
+ AddResource(GetURL(kStepWithRegions), kTestHTMLWithRegions, "text/html");
+ AddResource(GetURL(kStepWithChangingRegions), kTestHTMLWithChangingRegions,
+ "text/html");
+ AddResource(GetURL(kStepWithoutRegions), kTestHTMLWithoutRegions,
+ "text/html");
+
+ // Create the browser
+ CreateBrowser(GetURL(kStepWithRegions));
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout();
+ }
+
+ CefRefPtr<CefDragHandler> GetDragHandler() override { return this; }
+ CefRefPtr<CefFrameHandler> GetFrameHandler() override { return this; }
+
+ void OnDraggableRegionsChanged(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const std::vector<CefDraggableRegion>& regions) override {
+ EXPECT_UI_THREAD();
+ EXPECT_TRUE(browser->IsSame(GetBrowser()));
+ EXPECT_TRUE(frame->IsMain());
+
+ draggable_regions_changed_ct_++;
+
+#if VERBOSE_DEBUGGING
+ LOG(INFO) << "step " << step_ << " regions.size " << regions.size()
+ << " url " << frame->GetURL().ToString();
+ if (regions.size() == 2) {
+ LOG(INFO) << " region[0] x " << regions[0].bounds.x << " y "
+ << regions[0].bounds.y << " width " << regions[0].bounds.width
+ << " height " << regions[0].bounds.height;
+ LOG(INFO) << " region[1] x " << regions[1].bounds.x << " y "
+ << regions[1].bounds.y << " width " << regions[1].bounds.width
+ << " height " << regions[1].bounds.height;
+ }
+#endif // VERBOSE_DEBUGGING
+
+ switch (step_) {
+ case kStepWithRegions:
+ case kStepWithChangingRegions2:
+ EXPECT_EQ(2U, regions.size()) << step_;
+ if (regions.size() != 2U) {
+ break;
+ }
+ EXPECT_NEAR(50, regions[0].bounds.x, 1);
+ EXPECT_NEAR(50, regions[0].bounds.y, 1);
+ EXPECT_NEAR(200, regions[0].bounds.width, 1);
+ EXPECT_NEAR(200, regions[0].bounds.height, 1);
+ EXPECT_EQ(1, regions[0].draggable);
+ EXPECT_NEAR(125, regions[1].bounds.x, 1);
+ EXPECT_NEAR(125, regions[1].bounds.y, 1);
+ EXPECT_NEAR(50, regions[1].bounds.width, 1);
+ EXPECT_NEAR(50, regions[1].bounds.height, 1);
+ EXPECT_EQ(0, regions[1].draggable);
+ break;
+ case kStepWithChangingRegions:
+ case kStepWithChangingRegions3:
+ EXPECT_EQ(2U, regions.size()) << step_;
+ if (regions.size() != 2U) {
+ break;
+ }
+ EXPECT_EQ(0, regions[0].bounds.x);
+ EXPECT_EQ(0, regions[0].bounds.y);
+ EXPECT_NEAR(200, regions[0].bounds.width, 1);
+ EXPECT_NEAR(200, regions[0].bounds.height, 1);
+ EXPECT_EQ(1, regions[0].draggable);
+ EXPECT_NEAR(75, regions[1].bounds.x, 1);
+ EXPECT_NEAR(75, regions[1].bounds.y, 1);
+ EXPECT_NEAR(50, regions[1].bounds.width, 2);
+ EXPECT_NEAR(50, regions[1].bounds.height, 2);
+ EXPECT_EQ(0, regions[1].draggable);
+ break;
+ case kStepWithoutRegions:
+ case kStepWithoutRegions2:
+ EXPECT_TRUE(regions.empty()) << step_;
+ break;
+ }
+
+ NextTest(browser);
+ }
+
+ void OnFrameAttached(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ bool reattached) override {
+ EXPECT_UI_THREAD();
+ EXPECT_TRUE(browser->IsSame(GetBrowser()));
+ EXPECT_TRUE(frame->IsMain());
+
+ if (reattached) {
+ // When BackForwardCache is enabled and we go back to
+ // kTestHTMLWithChangingRegions, draggable regions will already be in the
+ // final position because the page content is not reloaded.
+ if (step_ == kStepWithChangingRegions2) {
+ step_ = kStepWithChangingRegions3;
+ expected_draggable_regions_changed_ct_--;
+ }
+ }
+ }
+
+ void DestroyTest() override {
+ EXPECT_EQ(expected_draggable_regions_changed_ct_,
+ draggable_regions_changed_ct_);
+
+ TestHandler::DestroyTest();
+ }
+
+ private:
+ void NextTest(CefRefPtr<CefBrowser> browser) {
+ CefRefPtr<CefFrame> frame(browser->GetMainFrame());
+
+ switch (step_) {
+ case kStepWithRegions:
+ step_ = kStepWithChangingRegions;
+ frame->LoadURL(GetURL(kStepWithChangingRegions));
+ break;
+ case kStepWithChangingRegions:
+ step_ = kStepWithoutRegions;
+ frame->LoadURL(GetURL(kStepWithoutRegions));
+ break;
+ case kStepWithoutRegions: {
+ step_ = kStepWithChangingRegions2;
+ browser->GoBack();
+ break;
+ }
+ case kStepWithChangingRegions2: {
+ step_ = kStepWithChangingRegions3;
+ break;
+ }
+ case kStepWithChangingRegions3: {
+ step_ = kStepWithoutRegions2;
+ browser->GoForward();
+ break;
+ }
+ case kStepWithoutRegions2: {
+ DestroyTest();
+ break;
+ }
+ }
+ }
+
+ std::string GetURL(Step step) const {
+ // When |same_origin_| is true every other URL gets a different origin.
+ switch (step) {
+ case kStepWithRegions:
+ return same_origin_ ? "http://test.com/regions"
+ : "http://test2.com/regions";
+ case kStepWithChangingRegions:
+ case kStepWithChangingRegions2:
+ case kStepWithChangingRegions3:
+ return "http://test.com/changing-regions";
+ case kStepWithoutRegions:
+ case kStepWithoutRegions2:
+ return same_origin_ ? "http://test.com/no-regions"
+ : "http://test2.com/no-regions";
+ }
+
+ NOTREACHED();
+ return "";
+ }
+
+ const bool same_origin_;
+
+ Step step_ = kStepWithRegions;
+ int draggable_regions_changed_ct_ = 0;
+ int expected_draggable_regions_changed_ct_ = kStepMax;
+
+ IMPLEMENT_REFCOUNTING(DraggableRegionsTestHandler);
+};
+
+} // namespace
+
+// Verify that draggable regions work in the same origin.
+TEST(DraggableRegionsTest, DraggableRegionsSameOrigin) {
+ CefRefPtr<DraggableRegionsTestHandler> handler =
+ new DraggableRegionsTestHandler(/*same_origin=*/true);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Verify that draggable regions work cross-origin.
+TEST(DraggableRegionsTest, DraggableRegionsCrossOrigin) {
+ CefRefPtr<DraggableRegionsTestHandler> handler =
+ new DraggableRegionsTestHandler(/*same_origin=*/false);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
diff --git a/tests/ceftests/extensions/background_unittest.cc b/tests/ceftests/extensions/background_unittest.cc
new file mode 100644
index 00000000..a043f167
--- /dev/null
+++ b/tests/ceftests/extensions/background_unittest.cc
@@ -0,0 +1,294 @@
+// Copyright (c) 2017 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/ceftests/extensions/extension_test_handler.h"
+
+#include "tests/ceftests/test_util.h"
+#include "tests/shared/browser/client_app_browser.h"
+#include "tests/shared/browser/extension_util.h"
+
+using client::ClientAppBrowser;
+
+namespace {
+
+const char kExtensionPath[] = "background-extension";
+const char kBackgroundScript[] = "background.js";
+// HTML file created internally to load the background script.
+const char kGeneratedBackgroundPage[] = "_generated_background_page.html";
+
+// Test load/unload of an extension with a background script.
+class BackgroundLoadUnloadTestHandler : public ExtensionTestHandler {
+ public:
+ explicit BackgroundLoadUnloadTestHandler(
+ RequestContextType request_context_type)
+ : ExtensionTestHandler(request_context_type) {
+ // Only creating the extension browser.
+ set_create_main_browser(false);
+ }
+
+ // CefExtensionHandler methods:
+ void OnExtensionLoaded(CefRefPtr<CefExtension> extension) override {
+ EXPECT_TRUE(CefCurrentlyOn(TID_UI));
+ EXPECT_TRUE(extension);
+ EXPECT_TRUE(extension->IsLoaded());
+ EXPECT_TRUE(extension->GetLoaderContext());
+ EXPECT_TRUE(
+ loader_request_context()->IsSame(extension->GetLoaderContext()));
+ VerifyExtension(extension);
+
+ EXPECT_FALSE(got_loaded_);
+ got_loaded_.yes();
+
+ EXPECT_FALSE(extension_);
+ extension_ = extension;
+
+ background_page_url_ = GetExtensionURL(extension, kGeneratedBackgroundPage);
+
+ // Add extension resources.
+ script_url_ = GetExtensionURL(extension, kBackgroundScript);
+ AddResource(script_url_, GetMessageJS("extension_onload"),
+ "text/javascript");
+ }
+
+ void OnExtensionUnloaded(CefRefPtr<CefExtension> extension) override {
+ EXPECT_TRUE(CefCurrentlyOn(TID_UI));
+ EXPECT_TRUE(extension);
+ EXPECT_FALSE(extension->IsLoaded());
+ EXPECT_FALSE(extension->GetLoaderContext());
+
+ EXPECT_FALSE(got_unloaded_);
+ got_unloaded_.yes();
+
+ EXPECT_TRUE(extension_);
+ EXPECT_TRUE(extension_->IsSame(extension));
+
+ // The extension should no longer be registered with the context.
+ if (loader_request_context()) {
+ VerifyExtensionInContext(extension, loader_request_context(), false,
+ true);
+ }
+ if (request_context() && !request_context_same_loader()) {
+ VerifyExtensionInContext(extension, request_context(), false, false);
+ }
+
+ extension_ = nullptr;
+
+ // Execute asynchronously so call stacks have a chance to unwind.
+ // Will close the browser windows.
+ CefPostTask(
+ TID_UI,
+ base::BindOnce(&BackgroundLoadUnloadTestHandler::DestroyTest, this));
+ }
+
+ bool OnBeforeBackgroundBrowser(CefRefPtr<CefExtension> extension,
+ const CefString& url,
+ CefRefPtr<CefClient>& client,
+ CefBrowserSettings& settings) override {
+ EXPECT_TRUE(CefCurrentlyOn(TID_UI));
+ EXPECT_TRUE(extension);
+ EXPECT_TRUE(extension->IsLoaded());
+ EXPECT_TRUE(extension->GetLoaderContext());
+ EXPECT_TRUE(
+ loader_request_context()->IsSame(extension->GetLoaderContext()));
+ VerifyExtension(extension);
+
+ const std::string& background_page_url =
+ GetExtensionURL(extension, kGeneratedBackgroundPage);
+ EXPECT_STREQ(background_page_url.c_str(), url.ToString().c_str());
+
+ EXPECT_FALSE(client);
+ client = this;
+
+ // Allow the browser creation.
+ return false;
+ }
+
+ // CefLoadHandler methods:
+ void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
+ bool isLoading,
+ bool canGoBack,
+ bool canGoForward) override {
+ EXPECT_TRUE(browser->GetHost()->IsBackgroundHost());
+
+ CefRefPtr<CefExtension> extension = browser->GetHost()->GetExtension();
+ EXPECT_TRUE(extension);
+ EXPECT_TRUE(extension_->IsSame(extension));
+
+ if (isLoading) {
+ EXPECT_FALSE(extension_browser_);
+ extension_browser_ = browser;
+ } else {
+ EXPECT_TRUE(browser->IsSame(extension_browser_));
+
+ const std::string& url = browser->GetMainFrame()->GetURL();
+ EXPECT_STREQ(background_page_url_.c_str(), url.c_str());
+
+ EXPECT_FALSE(got_load_done_);
+ got_load_done_.yes();
+
+ TriggerDestroyTestIfDone();
+ }
+ }
+
+ // CefResourceRequestHandler methods:
+ CefRefPtr<CefResourceHandler> GetResourceHandler(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request) override {
+ EXPECT_TRUE(browser->GetHost()->IsBackgroundHost());
+ EXPECT_TRUE(browser->IsSame(extension_browser_));
+
+ CefRefPtr<CefExtension> extension = browser->GetHost()->GetExtension();
+ EXPECT_TRUE(extension);
+ EXPECT_TRUE(extension_->IsSame(extension));
+
+ const std::string& url = request->GetURL();
+ if (url == background_page_url_) {
+ EXPECT_FALSE(got_background_page_url_request_);
+ got_background_page_url_request_.yes();
+ } else if (url == script_url_) {
+ EXPECT_FALSE(got_script_url_request_);
+ got_script_url_request_.yes();
+ } else {
+ EXPECT_TRUE(false); // Not reached.
+ }
+
+ // Handle the resource request.
+ return RoutingTestHandler::GetResourceHandler(browser, frame, request);
+ }
+
+ CefRefPtr<CefExtension> extension() const { return extension_; }
+
+ // Verify |extension| contents.
+ void VerifyExtension(CefRefPtr<CefExtension> extension) const {
+ EXPECT_STREQ(("extensions/" + std::string(kExtensionPath)).c_str(),
+ client::extension_util::GetInternalExtensionResourcePath(
+ extension->GetPath())
+ .c_str());
+
+ CefRefPtr<CefDictionaryValue> expected_manifest = CreateManifest();
+ TestDictionaryEqual(expected_manifest, extension->GetManifest());
+
+ VerifyExtensionInContext(extension, loader_request_context(), true, true);
+ if (!request_context_same_loader()) {
+ VerifyExtensionInContext(extension, request_context(), true, false);
+ }
+ }
+
+ std::string GetExtensionURL(CefRefPtr<CefExtension> extension,
+ const std::string& resource_path) const {
+ const std::string& identifier = extension->GetIdentifier();
+ const std::string& origin =
+ client::extension_util::GetExtensionOrigin(identifier);
+ EXPECT_FALSE(origin.empty());
+ return origin + resource_path;
+ }
+
+ protected:
+ void OnLoadExtensions() override {
+ LoadExtension(kExtensionPath, CreateManifest());
+ }
+
+ bool OnMessage(CefRefPtr<CefBrowser> browser,
+ const std::string& message) override {
+ EXPECT_STREQ("extension_onload", message.c_str());
+ EXPECT_TRUE(browser->GetHost()->IsBackgroundHost());
+
+ CefRefPtr<CefExtension> extension = browser->GetHost()->GetExtension();
+ EXPECT_TRUE(extension);
+ EXPECT_TRUE(extension_->IsSame(extension));
+
+ EXPECT_TRUE(browser->IsSame(extension_browser_));
+ EXPECT_TRUE(browser->GetHost()->IsBackgroundHost());
+
+ EXPECT_FALSE(got_body_onload_);
+ got_body_onload_.yes();
+
+ TriggerDestroyTestIfDone();
+ return true;
+ }
+
+ void OnDestroyTest() override {
+ extension_browser_ = nullptr;
+
+ EXPECT_TRUE(got_loaded_);
+ EXPECT_TRUE(got_background_page_url_request_);
+ EXPECT_TRUE(got_script_url_request_);
+ EXPECT_TRUE(got_body_onload_);
+ EXPECT_TRUE(got_load_done_);
+ EXPECT_TRUE(got_unloaded_);
+ }
+
+ // Create a manifest with background script.
+ CefRefPtr<CefDictionaryValue> CreateManifest() const {
+ CefRefPtr<CefDictionaryValue> manifest =
+ CreateDefaultManifest(ApiPermissionsList());
+
+ CefRefPtr<CefDictionaryValue> background = CefDictionaryValue::Create();
+ CefRefPtr<CefListValue> scripts = CefListValue::Create();
+ scripts->SetString(0, kBackgroundScript);
+ background->SetList("scripts", scripts);
+ manifest->SetDictionary("background", background);
+
+ return manifest;
+ }
+
+ void TriggerDestroyTestIfDone() {
+ if (got_body_onload_ && got_load_done_) {
+ TriggerDestroyTest();
+ }
+ }
+
+ virtual void TriggerDestroyTest() {
+ // Execute asynchronously so call stacks have a chance to unwind.
+ CefPostTask(TID_UI, base::BindOnce(
+ &BackgroundLoadUnloadTestHandler::UnloadExtension,
+ this, extension_));
+ }
+
+ CefRefPtr<CefExtension> extension_;
+ std::string script_url_;
+ std::string background_page_url_;
+ CefRefPtr<CefBrowser> extension_browser_;
+
+ TrackCallback got_loaded_;
+ TrackCallback got_background_page_url_request_;
+ TrackCallback got_script_url_request_;
+ TrackCallback got_body_onload_;
+ TrackCallback got_load_done_;
+ TrackCallback got_unloaded_;
+
+ IMPLEMENT_REFCOUNTING(BackgroundLoadUnloadTestHandler);
+ DISALLOW_COPY_AND_ASSIGN(BackgroundLoadUnloadTestHandler);
+};
+
+} // namespace
+
+EXTENSION_TEST_GROUP_ALL(BackgroundLoadUnload, BackgroundLoadUnloadTestHandler)
+
+namespace {
+
+// Same as above but without the unload. Only do this with a custom context to
+// avoid poluting the global context.
+class BackgroundLoadNoUnloadTestHandler
+ : public BackgroundLoadUnloadTestHandler {
+ public:
+ explicit BackgroundLoadNoUnloadTestHandler(
+ RequestContextType request_context_type)
+ : BackgroundLoadUnloadTestHandler(request_context_type) {}
+
+ protected:
+ void TriggerDestroyTest() override {
+ // Release everything that references the request context. This should
+ // trigger unload of the extension.
+ CloseBrowser(extension_browser_, false);
+ extension_browser_ = nullptr;
+ ReleaseRequestContexts();
+ }
+};
+
+} // namespace
+
+EXTENSION_TEST_GROUP_MINIMAL_CUSTOM(BackgroundLoadNoUnload,
+ BackgroundLoadNoUnloadTestHandler)
diff --git a/tests/ceftests/extensions/chrome_alarms_unittest.cc b/tests/ceftests/extensions/chrome_alarms_unittest.cc
new file mode 100644
index 00000000..25809a41
--- /dev/null
+++ b/tests/ceftests/extensions/chrome_alarms_unittest.cc
@@ -0,0 +1,340 @@
+// Copyright (c) 2017 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/ceftests/extensions/extension_test_handler.h"
+#include "tests/ceftests/test_util.h"
+#include "tests/shared/browser/extension_util.h"
+
+#define ALARMS_TEST_GROUP_ALL(name, test_class) \
+ EXTENSION_TEST_GROUP_ALL(ChromeAlarms##name, test_class)
+#define ALARMS_TEST_GROUP_MINIMAL(name, test_class) \
+ EXTENSION_TEST_GROUP_MINIMAL(ChromeAlarms##name, test_class)
+
+namespace {
+
+const char kExtensionPath[] = "alarms-extension";
+const char kSuccessMessage[] = "success";
+
+// Base class for testing chrome.alarms methods.
+// See https://developer.chrome.com/extensions/alarms
+class AlarmsTestHandler : public ExtensionTestHandler {
+ public:
+ explicit AlarmsTestHandler(RequestContextType request_context_type)
+ : ExtensionTestHandler(request_context_type) {
+ // Only creating the extension browser.
+ set_create_main_browser(false);
+ }
+
+ // CefExtensionHandler methods:
+ void OnExtensionLoaded(CefRefPtr<CefExtension> extension) override {
+ EXPECT_TRUE(CefCurrentlyOn(TID_UI));
+ EXPECT_FALSE(got_loaded_);
+ got_loaded_.yes();
+
+ // Verify |extension| contents.
+ EXPECT_FALSE(extension->GetIdentifier().empty());
+ EXPECT_STREQ(("extensions/" + std::string(kExtensionPath)).c_str(),
+ client::extension_util::GetInternalExtensionResourcePath(
+ extension->GetPath())
+ .c_str());
+ TestDictionaryEqual(CreateManifest(), extension->GetManifest());
+
+ EXPECT_FALSE(extension_);
+ extension_ = extension;
+
+ CreateBrowserForExtension();
+ }
+
+ void OnExtensionUnloaded(CefRefPtr<CefExtension> extension) override {
+ EXPECT_TRUE(CefCurrentlyOn(TID_UI));
+ EXPECT_TRUE(extension_);
+ EXPECT_TRUE(extension_->IsSame(extension));
+ EXPECT_FALSE(got_unloaded_);
+ got_unloaded_.yes();
+ extension_ = nullptr;
+
+ // Execute asynchronously so call stacks have a chance to unwind.
+ // Will close the browser windows.
+ CefPostTask(TID_UI, base::BindOnce(&AlarmsTestHandler::DestroyTest, this));
+ }
+
+ // CefLoadHandler methods:
+ void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
+ bool isLoading,
+ bool canGoBack,
+ bool canGoForward) override {
+ CefRefPtr<CefExtension> extension = browser->GetHost()->GetExtension();
+ EXPECT_TRUE(extension);
+ EXPECT_TRUE(extension_->IsSame(extension));
+
+ if (isLoading) {
+ EXPECT_FALSE(extension_browser_);
+ extension_browser_ = browser;
+ } else {
+ EXPECT_TRUE(browser->IsSame(extension_browser_));
+
+ const std::string& url = browser->GetMainFrame()->GetURL();
+ EXPECT_STREQ(extension_url_.c_str(), url.c_str());
+ }
+ }
+
+ // CefResourceRequestHandler methods:
+ CefRefPtr<CefResourceHandler> GetResourceHandler(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request) override {
+ EXPECT_TRUE(browser->IsSame(extension_browser_));
+
+ CefRefPtr<CefExtension> extension = browser->GetHost()->GetExtension();
+ EXPECT_TRUE(extension);
+ EXPECT_TRUE(extension_->IsSame(extension));
+
+ const std::string& url = request->GetURL();
+ EXPECT_STREQ(extension_url_.c_str(), url.c_str());
+
+ EXPECT_FALSE(got_url_request_);
+ got_url_request_.yes();
+
+ // Handle the resource request.
+ return RoutingTestHandler::GetResourceHandler(browser, frame, request);
+ }
+
+ protected:
+ void OnLoadExtensions() override {
+ LoadExtension(kExtensionPath, CreateManifest());
+ }
+
+ bool OnMessage(CefRefPtr<CefBrowser> browser,
+ const std::string& message) override {
+ if (message == "extension_onload") {
+ // From body onLoad in the extension browser.
+ EXPECT_TRUE(browser->IsSame(extension_browser_));
+ EXPECT_FALSE(got_body_onload_);
+ got_body_onload_.yes();
+ TriggerAlarmsApiJSFunction();
+ return true;
+ }
+ EXPECT_TRUE(browser->IsSame(extension_browser_));
+ EXPECT_FALSE(got_success_message_);
+ got_success_message_.yes();
+ EXPECT_STREQ(kSuccessMessage, message.c_str());
+ TriggerDestroyTest();
+ return true;
+ }
+
+ void OnDestroyTest() override {
+ extension_browser_ = nullptr;
+
+ EXPECT_TRUE(got_loaded_);
+ EXPECT_TRUE(got_url_request_);
+ EXPECT_TRUE(got_body_onload_);
+ EXPECT_TRUE(got_trigger_api_function_);
+ EXPECT_TRUE(got_success_message_);
+ EXPECT_TRUE(got_unloaded_);
+ }
+
+ // Create a manifest that grants access to the alarms API.
+ virtual CefRefPtr<CefDictionaryValue> CreateManifest() const {
+ ApiPermissionsList api_permissions;
+ api_permissions.push_back("alarms");
+ return CreateDefaultManifest(api_permissions);
+ }
+
+ // Add resources in the extension browser.
+ virtual void OnAddExtensionResources(const std::string& origin) {
+ extension_url_ = origin + "extension.html";
+ AddResource(extension_url_, GetExtensionHTML(), "text/html");
+ }
+
+ // Returns the chrome.alarms.* JS that is executed in the extension browser
+ // when the triggerAlarmsApi() JS function is called.
+ virtual std::string GetAlarmsApiJS() const = 0;
+
+ // Returns the JS that will be loaded in the extension browser. This
+ // implements the triggerAlarmsApi() JS function called from
+ // TriggerAlarmsApiJSFunction().
+ virtual std::string GetExtensionJS() const {
+ return "function triggerAlarmsApi() {" + GetAlarmsApiJS() + "}";
+ }
+
+ // Returns the HTML that will be loaded in the extension browser.
+ virtual std::string GetExtensionHTML() const {
+ return "<html><head><script>" + GetExtensionJS() +
+ "</script></head><body onLoad=" + GetMessageJS("extension_onload") +
+ ">Extension</body></html>";
+ }
+
+ virtual void TriggerDestroyTest() {
+ // Execute asynchronously so call stacks have a chance to unwind.
+ CefPostTask(TID_UI, base::BindOnce(&AlarmsTestHandler::UnloadExtension,
+ this, extension_));
+ }
+
+ CefRefPtr<CefExtension> extension() const { return extension_; }
+ std::string extension_url() const { return extension_url_; }
+ CefRefPtr<CefBrowser> extension_browser() const { return extension_browser_; }
+
+ bool got_success_message() const { return got_success_message_; }
+
+ private:
+ void CreateBrowserForExtension() {
+ const std::string& identifier = extension_->GetIdentifier();
+ EXPECT_FALSE(identifier.empty());
+ const std::string& origin =
+ client::extension_util::GetExtensionOrigin(identifier);
+ EXPECT_FALSE(origin.empty());
+
+ // Add extension resources.
+ OnAddExtensionResources(origin);
+
+ // Create a browser to host the extension.
+ CreateBrowser(extension_url_, request_context());
+ }
+
+ void TriggerAlarmsApiJSFunction() {
+ EXPECT_FALSE(got_trigger_api_function_);
+ got_trigger_api_function_.yes();
+
+ extension_browser_->GetMainFrame()->ExecuteJavaScript("triggerAlarmsApi();",
+ extension_url_, 0);
+ }
+
+ CefRefPtr<CefExtension> extension_;
+ std::string extension_url_;
+ CefRefPtr<CefBrowser> extension_browser_;
+
+ TrackCallback got_loaded_;
+ TrackCallback got_url_request_;
+ TrackCallback got_body_onload_;
+ TrackCallback got_trigger_api_function_;
+ TrackCallback got_success_message_;
+ TrackCallback got_unloaded_;
+};
+} // namespace
+
+namespace {
+
+// Test for chrome.alarms.create(string name, object alarmInfo)
+// and chrome.alarms.onAlarm.addListener(function callback)
+class CreateAlarmTestHandler : public AlarmsTestHandler {
+ public:
+ explicit CreateAlarmTestHandler(RequestContextType request_context_type)
+ : AlarmsTestHandler(request_context_type) {}
+
+ protected:
+ std::string GetAlarmsApiJS() const override {
+ return "chrome.alarms.onAlarm.addListener(function (alarm) {" +
+ GetMessageJS(kSuccessMessage) +
+ "});"
+ "chrome.alarms.create(\"test\", {delayInMinutes:0.01})";
+ }
+
+ private:
+ IMPLEMENT_REFCOUNTING(CreateAlarmTestHandler);
+ DISALLOW_COPY_AND_ASSIGN(CreateAlarmTestHandler);
+};
+} // namespace
+
+ALARMS_TEST_GROUP_ALL(CreateAlarm, CreateAlarmTestHandler)
+
+namespace {
+
+// Test for chrome.alarms.get(string name, function callback)
+class GetAlarmTestHandler : public AlarmsTestHandler {
+ public:
+ explicit GetAlarmTestHandler(RequestContextType request_context_type)
+ : AlarmsTestHandler(request_context_type) {}
+
+ protected:
+ std::string GetAlarmsApiJS() const override {
+ return "chrome.alarms.create(\"test\", {delayInMinutes:1});"
+ "setTimeout(function() {"
+ "chrome.alarms.get(\"test\", function (alarm) {" +
+ GetMessageJS(kSuccessMessage) + "})}, 100)";
+ }
+
+ private:
+ IMPLEMENT_REFCOUNTING(GetAlarmTestHandler);
+ DISALLOW_COPY_AND_ASSIGN(GetAlarmTestHandler);
+};
+} // namespace
+
+ALARMS_TEST_GROUP_MINIMAL(GetAlarm, GetAlarmTestHandler)
+
+namespace {
+
+// Test for chrome.alarms.getAll(function callback)
+class GetAllAlarmsTestHandler : public AlarmsTestHandler {
+ public:
+ explicit GetAllAlarmsTestHandler(RequestContextType request_context_type)
+ : AlarmsTestHandler(request_context_type) {}
+
+ protected:
+ std::string GetAlarmsApiJS() const override {
+ return "chrome.alarms.create(\"alarm1\", {delayInMinutes:1});"
+ "chrome.alarms.create(\"alarm2\", {delayInMinutes:1});"
+ "setTimeout(function() {"
+ "chrome.alarms.getAll(function (alarms) {"
+ "if (alarms.length == 2) {" +
+ GetMessageJS(kSuccessMessage) + "}})}, 100)";
+ }
+
+ private:
+ IMPLEMENT_REFCOUNTING(GetAllAlarmsTestHandler);
+ DISALLOW_COPY_AND_ASSIGN(GetAllAlarmsTestHandler);
+};
+} // namespace
+
+ALARMS_TEST_GROUP_MINIMAL(GetAllAlarms, GetAllAlarmsTestHandler)
+
+namespace {
+
+// Test for chrome.alarms.clear(string name, function callback)
+class ClearAlarmTestHandler : public AlarmsTestHandler {
+ public:
+ explicit ClearAlarmTestHandler(RequestContextType request_context_type)
+ : AlarmsTestHandler(request_context_type) {}
+
+ protected:
+ std::string GetAlarmsApiJS() const override {
+ return "chrome.alarms.create(\"test\", {delayInMinutes:1});"
+ "setTimeout(function() {"
+ "chrome.alarms.clear(\"test\", function (wasCleared) {"
+ "if (wasCleared) {" +
+ GetMessageJS(kSuccessMessage) + "}})}, 100)";
+ }
+
+ private:
+ IMPLEMENT_REFCOUNTING(ClearAlarmTestHandler);
+ DISALLOW_COPY_AND_ASSIGN(ClearAlarmTestHandler);
+};
+} // namespace
+
+ALARMS_TEST_GROUP_MINIMAL(ClearAlarm, ClearAlarmTestHandler)
+
+namespace {
+
+// Test for chrome.alarms.clearAll(function callback)
+class ClearAllAlarmsTestHandler : public AlarmsTestHandler {
+ public:
+ explicit ClearAllAlarmsTestHandler(RequestContextType request_context_type)
+ : AlarmsTestHandler(request_context_type) {}
+
+ protected:
+ std::string GetAlarmsApiJS() const override {
+ return "chrome.alarms.create(\"alarm1\", {delayInMinutes:1});"
+ "chrome.alarms.create(\"alarm2\", {delayInMinutes:1});"
+ "setTimeout(function() {"
+ "chrome.alarms.clearAll(function (wasCleared) {"
+ "if (wasCleared) {" +
+ GetMessageJS(kSuccessMessage) + "}})}, 100)";
+ }
+
+ private:
+ IMPLEMENT_REFCOUNTING(ClearAllAlarmsTestHandler);
+ DISALLOW_COPY_AND_ASSIGN(ClearAllAlarmsTestHandler);
+};
+} // namespace
+
+ALARMS_TEST_GROUP_MINIMAL(ClearAllAlarms, ClearAllAlarmsTestHandler)
diff --git a/tests/ceftests/extensions/chrome_storage_unittest.cc b/tests/ceftests/extensions/chrome_storage_unittest.cc
new file mode 100644
index 00000000..28fe1c35
--- /dev/null
+++ b/tests/ceftests/extensions/chrome_storage_unittest.cc
@@ -0,0 +1,480 @@
+// Copyright (c) 2017 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/ceftests/extensions/extension_test_handler.h"
+#include "tests/ceftests/test_util.h"
+#include "tests/shared/browser/extension_util.h"
+
+#define STORAGE_TEST_GROUP_ALL(name, test_class) \
+ EXTENSION_TEST_GROUP_ALL(ChromeStorage##name, test_class)
+#define STORAGE_TEST_GROUP_MINIMAL(name, test_class) \
+ EXTENSION_TEST_GROUP_MINIMAL(ChromeStorage##name, test_class)
+
+namespace {
+
+const char kExtensionPath[] = "storage-extension";
+const char kSuccessMessage[] = "success";
+
+// Base class for testing chrome.storage methods.
+// See https://developer.chrome.com/extensions/storage
+class StorageTestHandler : public ExtensionTestHandler {
+ public:
+ explicit StorageTestHandler(RequestContextType request_context_type)
+ : ExtensionTestHandler(request_context_type) {
+ // Only creating the extension browser.
+ set_create_main_browser(false);
+ }
+
+ // CefExtensionHandler methods:
+ void OnExtensionLoaded(CefRefPtr<CefExtension> extension) override {
+ EXPECT_TRUE(CefCurrentlyOn(TID_UI));
+ EXPECT_FALSE(got_loaded_);
+ got_loaded_.yes();
+
+ // Verify |extension| contents.
+ EXPECT_FALSE(extension->GetIdentifier().empty());
+ EXPECT_STREQ(("extensions/" + std::string(kExtensionPath)).c_str(),
+ client::extension_util::GetInternalExtensionResourcePath(
+ extension->GetPath())
+ .c_str());
+ TestDictionaryEqual(CreateManifest(), extension->GetManifest());
+
+ EXPECT_FALSE(extension_);
+ extension_ = extension;
+
+ CreateBrowserForExtension();
+ }
+
+ void OnExtensionUnloaded(CefRefPtr<CefExtension> extension) override {
+ EXPECT_TRUE(CefCurrentlyOn(TID_UI));
+ EXPECT_TRUE(extension_);
+ EXPECT_TRUE(extension_->IsSame(extension));
+ EXPECT_FALSE(got_unloaded_);
+ got_unloaded_.yes();
+ extension_ = nullptr;
+
+ // Execute asynchronously so call stacks have a chance to unwind.
+ // Will close the browser windows.
+ CefPostTask(TID_UI, base::BindOnce(&StorageTestHandler::DestroyTest, this));
+ }
+
+ // CefLoadHandler methods:
+ void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
+ bool isLoading,
+ bool canGoBack,
+ bool canGoForward) override {
+ CefRefPtr<CefExtension> extension = browser->GetHost()->GetExtension();
+ EXPECT_TRUE(extension);
+ EXPECT_TRUE(extension_->IsSame(extension));
+
+ if (isLoading) {
+ EXPECT_FALSE(extension_browser_);
+ extension_browser_ = browser;
+ } else {
+ EXPECT_TRUE(browser->IsSame(extension_browser_));
+
+ const std::string& url = browser->GetMainFrame()->GetURL();
+ EXPECT_STREQ(extension_url_.c_str(), url.c_str());
+ }
+ }
+
+ // CefResourceRequestHandler methods:
+ CefRefPtr<CefResourceHandler> GetResourceHandler(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request) override {
+ EXPECT_TRUE(browser->IsSame(extension_browser_));
+
+ CefRefPtr<CefExtension> extension = browser->GetHost()->GetExtension();
+ EXPECT_TRUE(extension);
+ EXPECT_TRUE(extension_->IsSame(extension));
+
+ const std::string& url = request->GetURL();
+ EXPECT_STREQ(extension_url_.c_str(), url.c_str());
+
+ EXPECT_FALSE(got_url_request_);
+ got_url_request_.yes();
+
+ // Handle the resource request.
+ return RoutingTestHandler::GetResourceHandler(browser, frame, request);
+ }
+
+ protected:
+ void OnLoadExtensions() override {
+ LoadExtension(kExtensionPath, CreateManifest());
+ }
+
+ bool OnMessage(CefRefPtr<CefBrowser> browser,
+ const std::string& message) override {
+ if (message == "extension_onload") {
+ // From body onLoad in the extension browser.
+ EXPECT_TRUE(browser->IsSame(extension_browser_));
+ EXPECT_FALSE(got_body_onload_);
+ got_body_onload_.yes();
+ TriggerStorageApiJSFunction();
+ return true;
+ }
+ EXPECT_TRUE(browser->IsSame(extension_browser_));
+ EXPECT_FALSE(got_success_message_);
+ got_success_message_.yes();
+ EXPECT_STREQ(kSuccessMessage, message.c_str());
+ TriggerDestroyTest();
+ return true;
+ }
+
+ void OnDestroyTest() override {
+ extension_browser_ = nullptr;
+
+ EXPECT_TRUE(got_loaded_);
+ EXPECT_TRUE(got_url_request_);
+ EXPECT_TRUE(got_body_onload_);
+ EXPECT_TRUE(got_trigger_api_function_);
+ EXPECT_TRUE(got_success_message_);
+ EXPECT_TRUE(got_unloaded_);
+ }
+
+ // Create a manifest that grants access to the storage API.
+ virtual CefRefPtr<CefDictionaryValue> CreateManifest() const {
+ ApiPermissionsList api_permissions;
+ api_permissions.push_back("storage");
+ return CreateDefaultManifest(api_permissions);
+ }
+
+ // Add resources in the extension browser.
+ virtual void OnAddExtensionResources(const std::string& origin) {
+ extension_url_ = origin + "extension.html";
+ AddResource(extension_url_, GetExtensionHTML(), "text/html");
+ }
+
+ // Returns the chrome.storage.* JS that is executed in the extension browser
+ // when the triggerStorageApi() JS function is called.
+ virtual std::string GetStorageApiJS() const = 0;
+
+ // Returns the JS that will be loaded in the extension browser. This
+ // implements the triggerStorageApi() JS function called from
+ // TriggerStorageApiJSFunction().
+ virtual std::string GetExtensionJS() const {
+ return "function triggerStorageApi() {" + GetStorageApiJS() + "}";
+ }
+
+ // Returns the HTML that will be loaded in the extension browser.
+ virtual std::string GetExtensionHTML() const {
+ return "<html><head><script>" + GetExtensionJS() +
+ "</script></head><body onLoad=" + GetMessageJS("extension_onload") +
+ ">Extension</body></html>";
+ }
+
+ virtual void TriggerDestroyTest() {
+ // Execute asynchronously so call stacks have a chance to unwind.
+ CefPostTask(TID_UI, base::BindOnce(&StorageTestHandler::UnloadExtension,
+ this, extension_));
+ }
+
+ CefRefPtr<CefExtension> extension() const { return extension_; }
+ std::string extension_url() const { return extension_url_; }
+ CefRefPtr<CefBrowser> extension_browser() const { return extension_browser_; }
+
+ bool got_success_message() const { return got_success_message_; }
+
+ private:
+ void CreateBrowserForExtension() {
+ const std::string& identifier = extension_->GetIdentifier();
+ EXPECT_FALSE(identifier.empty());
+ const std::string& origin =
+ client::extension_util::GetExtensionOrigin(identifier);
+ EXPECT_FALSE(origin.empty());
+
+ // Add extension resources.
+ OnAddExtensionResources(origin);
+
+ // Create a browser to host the extension.
+ CreateBrowser(extension_url_, request_context());
+ }
+
+ void TriggerStorageApiJSFunction() {
+ EXPECT_FALSE(got_trigger_api_function_);
+ got_trigger_api_function_.yes();
+
+ extension_browser_->GetMainFrame()->ExecuteJavaScript(
+ "triggerStorageApi();", extension_url_, 0);
+ }
+
+ CefRefPtr<CefExtension> extension_;
+ std::string extension_url_;
+ CefRefPtr<CefBrowser> extension_browser_;
+
+ TrackCallback got_loaded_;
+ TrackCallback got_url_request_;
+ TrackCallback got_body_onload_;
+ TrackCallback got_trigger_api_function_;
+ TrackCallback got_success_message_;
+ TrackCallback got_unloaded_;
+};
+} // namespace
+
+namespace {
+
+// Test for chrome.storage.local.set(object items, function callback)
+// and for chrome.storage.local.get(string or array of string or object keys,
+// function callback)
+class LocalStorageTestHandler : public StorageTestHandler {
+ public:
+ explicit LocalStorageTestHandler(RequestContextType request_context_type)
+ : StorageTestHandler(request_context_type) {}
+
+ protected:
+ std::string GetStorageApiJS() const override {
+ return "chrome.storage.local.set({\"local_key_1\": \"local_value_1\"}, "
+ "function() {"
+ "chrome.storage.local.get(\"local_key_1\", function (items) {"
+ "if(items[\"local_key_1\"] == \"local_value_1\") {" +
+ GetMessageJS(kSuccessMessage) +
+ "}});"
+ "});";
+ }
+
+ private:
+ IMPLEMENT_REFCOUNTING(LocalStorageTestHandler);
+ DISALLOW_COPY_AND_ASSIGN(LocalStorageTestHandler);
+};
+} // namespace
+
+STORAGE_TEST_GROUP_ALL(LocalStorage, LocalStorageTestHandler)
+
+namespace {
+
+// Test for chrome.storage.local.getBytesInUse(string or array of string keys,
+// function callback)
+class LocalStorageGetBytesInUseTestHandler : public StorageTestHandler {
+ public:
+ explicit LocalStorageGetBytesInUseTestHandler(
+ RequestContextType request_context_type)
+ : StorageTestHandler(request_context_type) {}
+
+ protected:
+ std::string GetStorageApiJS() const override {
+ return "chrome.storage.local.set({\"local_key_2\": \"local_value_2\"}, "
+ "function() {"
+ "chrome.storage.local.getBytesInUse(\"local_key_2\", function "
+ "(bytesInUse) {"
+ "if (bytesInUse == 26) {" +
+ GetMessageJS(kSuccessMessage) +
+ "}});"
+ "});";
+ }
+
+ private:
+ IMPLEMENT_REFCOUNTING(LocalStorageGetBytesInUseTestHandler);
+ DISALLOW_COPY_AND_ASSIGN(LocalStorageGetBytesInUseTestHandler);
+};
+} // namespace
+
+STORAGE_TEST_GROUP_MINIMAL(LocalStorageGetBytesInUse,
+ LocalStorageGetBytesInUseTestHandler)
+
+namespace {
+
+// Test for chrome.storage.local.remove(string or array of string keys, function
+// callback)
+class LocalStorageRemoveTestHandler : public StorageTestHandler {
+ public:
+ explicit LocalStorageRemoveTestHandler(
+ RequestContextType request_context_type)
+ : StorageTestHandler(request_context_type) {}
+
+ protected:
+ std::string GetStorageApiJS() const override {
+ return "chrome.storage.local.set({\"local_key_3\": \"local_value_3\"}, "
+ "function() {"
+ "chrome.storage.local.remove(\"local_key_3\", function () {"
+ "chrome.storage.local.get(\"local_key_3\", function(items) {"
+ "if (items[\"local_key_3\"] == undefined) {" +
+ GetMessageJS(kSuccessMessage) +
+ "}})})"
+ "});";
+ }
+
+ private:
+ IMPLEMENT_REFCOUNTING(LocalStorageRemoveTestHandler);
+ DISALLOW_COPY_AND_ASSIGN(LocalStorageRemoveTestHandler);
+};
+} // namespace
+
+STORAGE_TEST_GROUP_MINIMAL(LocalStorageRemove, LocalStorageRemoveTestHandler)
+
+namespace {
+
+// Test for chrome.storage.local.clear(function callback)
+class LocalStorageClearTestHandler : public StorageTestHandler {
+ public:
+ explicit LocalStorageClearTestHandler(RequestContextType request_context_type)
+ : StorageTestHandler(request_context_type) {}
+
+ protected:
+ std::string GetStorageApiJS() const override {
+ return "var value1Cleared = false;"
+ "var value2Cleared = false;"
+ "function checkCleared() {"
+ "if (value1Cleared && value2Cleared) {" +
+ GetMessageJS(kSuccessMessage) +
+ "}}"
+ "chrome.storage.local.set({\"local_key_4\": \"local_value_4\","
+ "\"local_key_5\": \"local_value_5\"}, function() {"
+ "chrome.storage.local.clear(function () {"
+
+ "chrome.storage.local.get(\"local_key_4\", function(items) {"
+ "if (items[\"local_key_4\"] == undefined) {"
+ "value1Cleared = true;"
+ "checkCleared();"
+ "}});"
+
+ "chrome.storage.local.get(\"local_key_5\", function(items) {"
+ "if (items[\"local_key_5\"] == undefined) {"
+ "value2Cleared = true;"
+ "checkCleared();"
+ "}});"
+ "})});";
+ }
+
+ private:
+ IMPLEMENT_REFCOUNTING(LocalStorageClearTestHandler);
+ DISALLOW_COPY_AND_ASSIGN(LocalStorageClearTestHandler);
+};
+} // namespace
+
+STORAGE_TEST_GROUP_MINIMAL(LocalStorageClear, LocalStorageClearTestHandler)
+
+namespace {
+
+// Test for chrome.storage.sync.set(object items, function callback)
+// and for chrome.storage.sync.get(string or array of string or object keys,
+// function callback)
+class SyncStorageTestHandler : public StorageTestHandler {
+ public:
+ explicit SyncStorageTestHandler(RequestContextType request_context_type)
+ : StorageTestHandler(request_context_type) {}
+
+ protected:
+ std::string GetStorageApiJS() const override {
+ return "chrome.storage.sync.set({\"sync_key_1\": \"sync_value_1\"}, "
+ "function() {"
+ "chrome.storage.sync.get(\"sync_key_1\", function (items) {"
+ "if (items[\"sync_key_1\"] == \"sync_value_1\") {" +
+ GetMessageJS(kSuccessMessage) +
+ "}});"
+ "});";
+ }
+
+ private:
+ IMPLEMENT_REFCOUNTING(SyncStorageTestHandler);
+ DISALLOW_COPY_AND_ASSIGN(SyncStorageTestHandler);
+};
+} // namespace
+
+STORAGE_TEST_GROUP_ALL(SyncStorage, SyncStorageTestHandler)
+
+namespace {
+
+// Test for chrome.storage.sync.getBytesInUse(string or array of string keys,
+// function callback)
+class SyncStorageGetBytesInUseTestHandler : public StorageTestHandler {
+ public:
+ explicit SyncStorageGetBytesInUseTestHandler(
+ RequestContextType request_context_type)
+ : StorageTestHandler(request_context_type) {}
+
+ protected:
+ std::string GetStorageApiJS() const override {
+ return "chrome.storage.sync.set({\"sync_key_2\": \"sync_value_2\"}, "
+ "function() {"
+ "chrome.storage.sync.getBytesInUse(\"sync_key_2\", function "
+ "(bytesInUse) {"
+ "if (bytesInUse == 24) {" +
+ GetMessageJS(kSuccessMessage) +
+ "}});"
+ "});";
+ }
+
+ private:
+ IMPLEMENT_REFCOUNTING(SyncStorageGetBytesInUseTestHandler);
+ DISALLOW_COPY_AND_ASSIGN(SyncStorageGetBytesInUseTestHandler);
+};
+} // namespace
+
+STORAGE_TEST_GROUP_MINIMAL(SyncStorageGetBytesInUse,
+ SyncStorageGetBytesInUseTestHandler)
+
+namespace {
+
+// Test for chrome.storage.sync.remove(string or array of string keys, function
+// callback)
+class SyncStorageRemoveTestHandler : public StorageTestHandler {
+ public:
+ explicit SyncStorageRemoveTestHandler(RequestContextType request_context_type)
+ : StorageTestHandler(request_context_type) {}
+
+ protected:
+ std::string GetStorageApiJS() const override {
+ return "chrome.storage.sync.set({\"sync_key_3\": \"sync_value_3\"}, "
+ "function() {"
+ "chrome.storage.sync.remove(\"sync_key_3\", function () {"
+ "chrome.storage.sync.get(\"sync_key_3\", function(items) {"
+ "if (items[\"sync_key_3\"] == undefined) {" +
+ GetMessageJS(kSuccessMessage) +
+ "}})})"
+ "});";
+ }
+
+ private:
+ IMPLEMENT_REFCOUNTING(SyncStorageRemoveTestHandler);
+ DISALLOW_COPY_AND_ASSIGN(SyncStorageRemoveTestHandler);
+};
+} // namespace
+
+STORAGE_TEST_GROUP_MINIMAL(SyncStorageRemove, SyncStorageRemoveTestHandler)
+
+namespace {
+
+// Test for chrome.storage.sync.clear(function callback)
+class SyncStorageClearTestHandler : public StorageTestHandler {
+ public:
+ explicit SyncStorageClearTestHandler(RequestContextType request_context_type)
+ : StorageTestHandler(request_context_type) {}
+
+ protected:
+ std::string GetStorageApiJS() const override {
+ return "var value1Cleared = false;"
+ "var value2Cleared = false;"
+
+ "function checkCleared() {"
+ "if (value1Cleared && value2Cleared) {" +
+ GetMessageJS(kSuccessMessage) +
+ "}}"
+
+ "chrome.storage.sync.set({\"sync_key_4\": \"sync_value_4\","
+ "\"sync_key_5\": \"sync_value_5\"}, function() {"
+ "chrome.storage.sync.clear(function () {"
+
+ "chrome.storage.sync.get(\"sync_key_4\", function(items) {"
+ "if (items[\"sync_key_4\"] == undefined) {"
+ "value1Cleared = true;"
+ "checkCleared();"
+ "}});"
+
+ "chrome.storage.sync.get(\"sync_key_5\", function(items) {"
+ "if (items[\"sync_key_5\"] == undefined) {"
+ "value2Cleared = true;"
+ "checkCleared();"
+ "}});"
+
+ "})});";
+ }
+
+ private:
+ IMPLEMENT_REFCOUNTING(SyncStorageClearTestHandler);
+ DISALLOW_COPY_AND_ASSIGN(SyncStorageClearTestHandler);
+};
+} // namespace
+
+STORAGE_TEST_GROUP_MINIMAL(SyncStorageClear, SyncStorageClearTestHandler)
diff --git a/tests/ceftests/extensions/chrome_tabs_unittest.cc b/tests/ceftests/extensions/chrome_tabs_unittest.cc
new file mode 100644
index 00000000..c40043e4
--- /dev/null
+++ b/tests/ceftests/extensions/chrome_tabs_unittest.cc
@@ -0,0 +1,1223 @@
+// Copyright (c) 2017 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/ceftests/extensions/extension_test_handler.h"
+
+#include <sstream>
+
+#include "include/cef_parser.h"
+
+#include "tests/ceftests/test_util.h"
+#include "tests/shared/browser/extension_util.h"
+
+#define TABS_TEST_GROUP_ALL(name, test_class) \
+ EXTENSION_TEST_GROUP_ALL(ChromeTabs##name, test_class)
+#define TABS_TEST_GROUP_MINIMAL(name, test_class) \
+ EXTENSION_TEST_GROUP_MINIMAL(ChromeTabs##name, test_class)
+
+namespace {
+
+const char kMainBrowserURL[] = "https://test-extensions.com/chrome-tabs";
+const char kExtensionPath[] = "tabs-extension";
+const char kSuccessMessage[] = "success";
+
+// Base class for testing chrome.tabs methods.
+// See https://developer.chrome.com/extensions/tabs
+class TabsTestHandler : public ExtensionTestHandler {
+ public:
+ explicit TabsTestHandler(RequestContextType request_context_type)
+ : ExtensionTestHandler(request_context_type),
+ create_main_browser_first_(false),
+ expect_get_active_browser_(true),
+ expect_success_in_main_browser_(true),
+ expected_api_call_count_(1),
+ got_get_active_browser_count_(0),
+ got_can_access_browser_count_(0) {}
+
+ // CefExtensionHandler methods:
+ void OnExtensionLoaded(CefRefPtr<CefExtension> extension) override {
+ EXPECT_TRUE(CefCurrentlyOn(TID_UI));
+ EXPECT_FALSE(got_extension_loaded_);
+ got_extension_loaded_.yes();
+
+ // Verify |extension| contents.
+ EXPECT_FALSE(extension->GetIdentifier().empty());
+ EXPECT_STREQ(("extensions/" + std::string(kExtensionPath)).c_str(),
+ client::extension_util::GetInternalExtensionResourcePath(
+ extension->GetPath())
+ .c_str());
+ TestDictionaryEqual(CreateManifest(), extension->GetManifest());
+
+ EXPECT_FALSE(extension_);
+ extension_ = extension;
+
+ if (create_main_browser_first_) {
+ CreateBrowserForExtensionIfReady();
+ } else {
+ CreateBrowserForExtension();
+ }
+ }
+
+ void OnExtensionUnloaded(CefRefPtr<CefExtension> extension) override {
+ EXPECT_TRUE(CefCurrentlyOn(TID_UI));
+ EXPECT_TRUE(extension_);
+ EXPECT_TRUE(extension_->IsSame(extension));
+ EXPECT_FALSE(got_extension_unloaded_);
+ got_extension_unloaded_.yes();
+ extension_ = nullptr;
+
+ // Execute asynchronously so call stacks have a chance to unwind.
+ // Will close the browser windows.
+ CefPostTask(TID_UI, base::BindOnce(&TabsTestHandler::DestroyTest, this));
+ }
+
+ CefRefPtr<CefBrowser> GetActiveBrowser(CefRefPtr<CefExtension> extension,
+ CefRefPtr<CefBrowser> browser,
+ bool include_incognito) override {
+ EXPECT_TRUE(CefCurrentlyOn(TID_UI));
+ EXPECT_TRUE(extension_);
+ EXPECT_TRUE(extension_->IsSame(extension));
+ EXPECT_TRUE(main_browser_);
+
+ EXPECT_LE(got_get_active_browser_count_, expected_api_call_count_);
+ got_get_active_browser_count_++;
+
+ // Tabs APIs will operate on the main browser.
+ return main_browser_;
+ }
+
+ bool CanAccessBrowser(CefRefPtr<CefExtension> extension,
+ CefRefPtr<CefBrowser> browser,
+ bool include_incognito,
+ CefRefPtr<CefBrowser> target_browser) override {
+ EXPECT_TRUE(CefCurrentlyOn(TID_UI));
+ EXPECT_TRUE(extension_);
+ EXPECT_TRUE(extension_->IsSame(extension));
+ EXPECT_TRUE(main_browser_);
+ EXPECT_TRUE(main_browser_->IsSame(target_browser));
+
+ EXPECT_LE(got_can_access_browser_count_, expected_api_call_count_);
+ got_can_access_browser_count_++;
+
+ return true;
+ }
+
+ // CefLoadHandler methods:
+ void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
+ bool isLoading,
+ bool canGoBack,
+ bool canGoForward) override {
+ if (isLoading) {
+ // Keep a reference to both browsers.
+ if (browser->GetHost()->GetExtension()) {
+ EXPECT_FALSE(extension_browser_);
+ extension_browser_ = browser;
+ } else {
+ EXPECT_FALSE(main_browser_);
+ main_browser_ = browser;
+ }
+ } else {
+ const std::string& url = browser->GetMainFrame()->GetURL();
+ if (browser->GetHost()->GetExtension()) {
+ EXPECT_TRUE(browser->IsSame(extension_browser_));
+ EXPECT_STREQ(extension_url_.c_str(), url.c_str());
+ } else {
+ EXPECT_TRUE(browser->IsSame(main_browser_));
+ EXPECT_STREQ(kMainBrowserURL, url.c_str());
+ }
+ }
+ }
+
+ // CefResourceRequestHandler methods:
+ CefRefPtr<CefResourceHandler> GetResourceHandler(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request) override {
+ const std::string& url = request->GetURL();
+ if (url == kMainBrowserURL) {
+ EXPECT_TRUE(browser->IsSame(main_browser_));
+ EXPECT_FALSE(got_main_url_request_);
+ got_main_url_request_.yes();
+ } else if (url == extension_url_) {
+ EXPECT_TRUE(browser->IsSame(extension_browser_));
+ EXPECT_FALSE(got_extension_url_request_);
+ got_extension_url_request_.yes();
+ }
+
+ // Handle the resource request.
+ return RoutingTestHandler::GetResourceHandler(browser, frame, request);
+ }
+
+ protected:
+ void OnAddMainBrowserResources() override {
+ AddResource(kMainBrowserURL, GetMainBrowserHTML(), "text/html");
+ }
+
+ void OnCreateMainBrowser() override {
+ CreateBrowser(kMainBrowserURL, request_context());
+ }
+
+ void OnLoadExtensions() override {
+ LoadExtension(kExtensionPath, CreateManifest());
+ }
+
+ bool OnMessage(CefRefPtr<CefBrowser> browser,
+ const std::string& message) override {
+ if (message == "main_onload") {
+ // From body onLoad in the main browser.
+ EXPECT_TRUE(browser->IsSame(main_browser_));
+ EXPECT_FALSE(got_main_body_onload_);
+ got_main_body_onload_.yes();
+ if (create_main_browser_first_) {
+ CreateBrowserForExtensionIfReady();
+ }
+ TriggerTabsApiJSFunctionIfReady();
+ return true;
+ }
+ if (message == "extension_onload") {
+ // From body onLoad in the extension browser.
+ EXPECT_TRUE(browser->IsSame(extension_browser_));
+ EXPECT_FALSE(got_extension_body_onload_);
+ got_extension_body_onload_.yes();
+ TriggerTabsApiJSFunctionIfReady();
+ return true;
+ }
+
+ // The success message usually orginates from the logic in
+ // GetMainBrowserSuccessHEAD/BODY(). It may occasionally originate from the
+ // extension browser if we don't know how to detect success in the main
+ // browser.
+ if (expect_success_in_main_browser_) {
+ EXPECT_TRUE(browser->IsSame(main_browser_));
+ } else {
+ EXPECT_TRUE(browser->IsSame(extension_browser_));
+ }
+ EXPECT_FALSE(got_success_message_);
+ got_success_message_.yes();
+ EXPECT_STREQ(kSuccessMessage, message.c_str());
+ TriggerDestroyTest();
+ return true;
+ }
+
+ void OnDestroyTest() override {
+ main_browser_ = nullptr;
+ extension_browser_ = nullptr;
+
+ EXPECT_TRUE(got_extension_loaded_);
+ EXPECT_TRUE(got_main_url_request_);
+ EXPECT_TRUE(got_extension_url_request_);
+ EXPECT_TRUE(got_main_body_onload_);
+ EXPECT_TRUE(got_extension_body_onload_);
+ EXPECT_TRUE(got_trigger_api_function_);
+ EXPECT_TRUE(got_success_message_);
+ EXPECT_TRUE(got_extension_unloaded_);
+
+ if (expect_get_active_browser_) {
+ EXPECT_EQ(expected_api_call_count_, got_get_active_browser_count_);
+ EXPECT_EQ(0, got_can_access_browser_count_);
+ } else {
+ EXPECT_EQ(0, got_get_active_browser_count_);
+ EXPECT_EQ(expected_api_call_count_, got_can_access_browser_count_);
+ }
+ }
+
+ // Create a manifest that grants access to the tabs API.
+ virtual CefRefPtr<CefDictionaryValue> CreateManifest() const {
+ ApiPermissionsList api_permissions;
+ api_permissions.push_back("tabs");
+ return CreateDefaultManifest(api_permissions);
+ }
+
+ // Add resources in the extension browser.
+ virtual void OnAddExtensionResources(const std::string& origin) {
+ extension_url_ = origin + "extension.html";
+ AddResource(extension_url_, GetExtensionHTML(), "text/html");
+ }
+
+ // Returns the target tabId (null, or value >= 0).
+ virtual std::string GetTargetTabId() const { return "null"; }
+
+ // Returns the logic in the main browser that triggers on success. It should
+ // execute GetMessageJS(kSuccessMessage).
+ virtual std::string GetMainBrowserSuccessHEAD() const {
+ return std::string();
+ }
+ virtual std::string GetMainBrowserSuccessBODY() const {
+ return std::string();
+ }
+
+ // Returns the HTML that will be loaded in the main browser.
+ virtual std::string GetMainBrowserHTML() const {
+ return "<html><head>" + GetMainBrowserSuccessHEAD() +
+ "</head><body onLoad=" + GetMessageJS("main_onload") + ">Main" +
+ GetMainBrowserSuccessBODY() + "</body></html>";
+ }
+
+ // Returns the chrome.tabs.* JS that is executed in the extension browser
+ // when the triggerTabsApi() JS function is called.
+ virtual std::string GetTabsApiJS() const = 0;
+
+ // Returns the JS that will be loaded in the extension browser. This
+ // implements the triggerTabsApi() JS function called from
+ // TriggerTabsApiJSFunction().
+ virtual std::string GetExtensionJS() const {
+ return "function triggerTabsApi() {" + GetTabsApiJS() + "}";
+ }
+
+ // Returns the HTML that will be loaded in the extension browser.
+ virtual std::string GetExtensionHTML() const {
+ return "<html><head><script>" + GetExtensionJS() +
+ "</script></head><body onLoad=" + GetMessageJS("extension_onload") +
+ ">Extension</body></html>";
+ }
+
+ virtual void TriggerDestroyTest() {
+ // Execute asynchronously so call stacks have a chance to unwind.
+ CefPostTask(TID_UI, base::BindOnce(&TabsTestHandler::UnloadExtension, this,
+ extension_));
+ }
+
+ CefRefPtr<CefExtension> extension() const { return extension_; }
+ std::string extension_url() const { return extension_url_; }
+ CefRefPtr<CefBrowser> main_browser() const { return main_browser_; }
+ CefRefPtr<CefBrowser> extension_browser() const { return extension_browser_; }
+
+ void set_create_main_browser_first(bool val) {
+ create_main_browser_first_ = val;
+ }
+ void set_expect_get_active_browser(bool val) {
+ expect_get_active_browser_ = val;
+ }
+ void set_expect_success_in_main_browser(bool val) {
+ expect_success_in_main_browser_ = val;
+ }
+ void set_expected_api_call_count(int val) { expected_api_call_count_ = val; }
+
+ bool got_success_message() const { return got_success_message_; }
+ void set_got_success_message() { got_success_message_.yes(); }
+
+ private:
+ void CreateBrowserForExtensionIfReady() {
+ DCHECK(create_main_browser_first_);
+ if (extension_ && main_browser_) {
+ CreateBrowserForExtension();
+ }
+ }
+
+ void CreateBrowserForExtension() {
+ const std::string& identifier = extension_->GetIdentifier();
+ EXPECT_FALSE(identifier.empty());
+ const std::string& origin =
+ client::extension_util::GetExtensionOrigin(identifier);
+ EXPECT_FALSE(origin.empty());
+
+ // Add extension resources.
+ OnAddExtensionResources(origin);
+
+ // Create a browser to host the extension.
+ CreateBrowser(extension_url_, request_context());
+ }
+
+ void TriggerTabsApiJSFunctionIfReady() {
+ if (got_main_body_onload_ && got_extension_body_onload_) {
+ TriggerTabsApiJSFunction();
+ }
+ }
+
+ void TriggerTabsApiJSFunction() {
+ EXPECT_FALSE(got_trigger_api_function_);
+ got_trigger_api_function_.yes();
+
+ extension_browser_->GetMainFrame()->ExecuteJavaScript("triggerTabsApi();",
+ extension_url_, 0);
+ }
+
+ // If true the main browser will be created before the extension browser.
+ // Otherwise the creation order is undefined.
+ bool create_main_browser_first_;
+
+ // If true we expect GetActiveBrowser() but not CanAccessBrowser() to be
+ // called. Else visa-versa.
+ bool expect_get_active_browser_;
+
+ // If true we expect the success message to be delivered in the main browser.
+ // Else expect it in the extension browser.
+ bool expect_success_in_main_browser_;
+
+ // Number of expected calls to GetActiveBrowser or CanAccessBrowser. This
+ // should match the number of calls to chrome.tabs.* API functions in the
+ // test.
+ int expected_api_call_count_;
+
+ CefRefPtr<CefExtension> extension_;
+ std::string extension_url_;
+ CefRefPtr<CefBrowser> main_browser_;
+ CefRefPtr<CefBrowser> extension_browser_;
+
+ TrackCallback got_extension_loaded_;
+ TrackCallback got_main_url_request_;
+ TrackCallback got_extension_url_request_;
+ TrackCallback got_main_body_onload_;
+ TrackCallback got_extension_body_onload_;
+ TrackCallback got_trigger_api_function_;
+ TrackCallback got_success_message_;
+ TrackCallback got_extension_unloaded_;
+
+ int got_get_active_browser_count_;
+ int got_can_access_browser_count_;
+};
+
+//
+// chrome.tabs.create tests.
+//
+
+const char kCreateBrowserURL[] =
+ "https://test-extensions.com/chrome-tabs-create";
+const char kTabCallbackMessage[] = "tab-callback";
+const int kCreateTabIndex = 2;
+
+// Class for chrome.tabs.create tests.
+class CreateTestHandler : public TabsTestHandler {
+ public:
+ explicit CreateTestHandler(RequestContextType request_context_type)
+ : TabsTestHandler(request_context_type) {}
+
+ bool OnBeforeBrowser(CefRefPtr<CefExtension> extension,
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefBrowser> active_browser,
+ int index,
+ const CefString& url,
+ bool foreground,
+ CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient>& client,
+ CefBrowserSettings& settings) override {
+ EXPECT_TRUE(extension->IsSame(this->extension()));
+ EXPECT_TRUE(browser->IsSame(extension_browser()));
+ EXPECT_TRUE(active_browser->IsSame(main_browser()));
+ EXPECT_EQ(kCreateTabIndex, index);
+ EXPECT_STREQ(kCreateBrowserURL, url.ToString().c_str());
+ EXPECT_TRUE(foreground);
+ EXPECT_TRUE(client);
+
+ EXPECT_FALSE(got_on_before_browser_);
+ got_on_before_browser_.yes();
+
+ return false;
+ }
+
+ void OnAddMainBrowserResources() override {
+ AddResource(kCreateBrowserURL, GetCreatedBrowserHTML(), "text/html");
+
+ TabsTestHandler::OnAddMainBrowserResources();
+ }
+
+ void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
+ bool isLoading,
+ bool canGoBack,
+ bool canGoForward) override {
+ if (extension_browser() && main_browser()) {
+ if (isLoading) {
+ // Keep a reference to the newly created browser.
+ EXPECT_FALSE(created_browser_);
+ created_browser_ = browser;
+ return;
+ } else {
+ const std::string& url = browser->GetMainFrame()->GetURL();
+ if (url == kCreateBrowserURL) {
+ EXPECT_TRUE(browser->IsSame(created_browser_));
+ return;
+ }
+ }
+ }
+
+ TabsTestHandler::OnLoadingStateChange(browser, isLoading, canGoBack,
+ canGoForward);
+ }
+
+ CefRefPtr<CefResourceHandler> GetResourceHandler(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request) override {
+ const std::string& url = request->GetURL();
+ if (url == kCreateBrowserURL) {
+ EXPECT_TRUE(browser->IsSame(created_browser_));
+ EXPECT_FALSE(got_create_browser_url_request_);
+ got_create_browser_url_request_.yes();
+ }
+
+ return TabsTestHandler::GetResourceHandler(browser, frame, request);
+ }
+
+ protected:
+ std::string GetTabsApiJS() const override {
+ std::stringstream ss;
+ ss << kCreateTabIndex;
+
+ return "chrome.tabs.create({url: \"" + std::string(kCreateBrowserURL) +
+ "\", index: " + ss.str() +
+ "}, function(tab) { window.testQuery({request:'" +
+ kTabCallbackMessage + ":' + JSON.stringify(tab)}); });";
+ }
+
+ bool OnMessage(CefRefPtr<CefBrowser> browser,
+ const std::string& message) override {
+ if (message.find(kTabCallbackMessage) != std::string::npos) {
+ EXPECT_TRUE(browser->IsSame(extension_browser()));
+ EXPECT_FALSE(got_tab_callback_message_);
+ got_tab_callback_message_.yes();
+
+ // Verify the contents of the Tab object.
+ const std::string& json_str =
+ message.substr(strlen(kTabCallbackMessage) + 1);
+ CefRefPtr<CefValue> obj = CefParseJSON(json_str, JSON_PARSER_RFC);
+ EXPECT_TRUE(obj);
+ EXPECT_EQ(VTYPE_DICTIONARY, obj->GetType());
+ CefRefPtr<CefDictionaryValue> dict = obj->GetDictionary();
+
+ int index = dict->GetInt("index");
+ EXPECT_EQ(kCreateTabIndex, index);
+
+ int id = dict->GetInt("id");
+ int windowId = dict->GetInt("windowId");
+ EXPECT_EQ(created_browser_->GetIdentifier(), id);
+ EXPECT_EQ(created_browser_->GetIdentifier(), windowId);
+
+ const std::string& url = dict->GetString("url");
+ EXPECT_STREQ(kCreateBrowserURL, url.c_str());
+
+ TriggerDestroyTestIfReady();
+ return true;
+ } else if (message == kSuccessMessage) {
+ // Overriding default kSuccessMessage handling.
+ EXPECT_TRUE(browser->IsSame(created_browser_));
+ EXPECT_FALSE(got_success_message());
+ set_got_success_message();
+ TriggerDestroyTestIfReady();
+ return true;
+ }
+
+ return TabsTestHandler::OnMessage(browser, message);
+ }
+
+ void OnDestroyTest() override {
+ created_browser_ = nullptr;
+
+ EXPECT_TRUE(got_on_before_browser_);
+ EXPECT_TRUE(got_create_browser_url_request_);
+ EXPECT_TRUE(got_tab_callback_message_);
+
+ TabsTestHandler::OnDestroyTest();
+ }
+
+ private:
+ std::string GetCreatedBrowserHTML() {
+ return "<html><body onLoad=" + GetMessageJS(kSuccessMessage) +
+ ">Created</body></html>";
+ }
+
+ void TriggerDestroyTestIfReady() {
+ if (got_tab_callback_message_ && got_success_message()) {
+ TriggerDestroyTest();
+ }
+ }
+
+ CefRefPtr<CefBrowser> created_browser_;
+
+ TrackCallback got_on_before_browser_;
+ TrackCallback got_create_browser_url_request_;
+ TrackCallback got_tab_callback_message_;
+
+ IMPLEMENT_REFCOUNTING(CreateTestHandler);
+ DISALLOW_COPY_AND_ASSIGN(CreateTestHandler);
+};
+
+} // namespace
+
+TABS_TEST_GROUP_ALL(Create, CreateTestHandler)
+
+namespace {
+
+//
+// chrome.tabs.executeScript tests.
+//
+
+// Base class for chrome.tabs.executeScript tests.
+class ExecuteScriptTestHandler : public TabsTestHandler {
+ public:
+ explicit ExecuteScriptTestHandler(RequestContextType request_context_type)
+ : TabsTestHandler(request_context_type) {}
+
+ protected:
+ std::string GetMainBrowserSuccessHEAD() const override {
+ return "<script>function onTrigger() {" + GetMessageJS(kSuccessMessage) +
+ "}</script>";
+ }
+
+ // Returns the code that will be injected as a content script.
+ virtual std::string GetContentScriptJS() const {
+ // Execute the onTrigger() JS function.
+ return "var s = document.createElement('script');"
+ "s.textContent = 'onTrigger();';"
+ "document.head.appendChild(s);";
+ }
+
+ std::string GetTabsApiJS() const override {
+ return "chrome.tabs.executeScript(" + GetTargetTabId() + ", {code:\"" +
+ GetContentScriptJS() + "\"});";
+ }
+};
+
+// Test for chrome.tabs.executeScript with a null tabId value.
+class ExecuteScriptNullTabTestHandler : public ExecuteScriptTestHandler {
+ public:
+ explicit ExecuteScriptNullTabTestHandler(
+ RequestContextType request_context_type)
+ : ExecuteScriptTestHandler(request_context_type) {}
+
+ private:
+ IMPLEMENT_REFCOUNTING(ExecuteScriptNullTabTestHandler);
+ DISALLOW_COPY_AND_ASSIGN(ExecuteScriptNullTabTestHandler);
+};
+
+} // namespace
+
+TABS_TEST_GROUP_ALL(ExecuteScriptNullTab, ExecuteScriptNullTabTestHandler)
+
+namespace {
+
+// Test for chrome.tabs.executeScript with an explicit tabId value.
+class ExecuteScriptExplicitTabTestHandler : public ExecuteScriptTestHandler {
+ public:
+ explicit ExecuteScriptExplicitTabTestHandler(
+ RequestContextType request_context_type)
+ : ExecuteScriptTestHandler(request_context_type) {
+ // Create the main browser first so we can retrieve the id.
+ set_create_main_browser_first(true);
+ // When a tabId is specified we should get a call to CanAccessBrowser
+ // instead of GetActiveBrowser.
+ set_expect_get_active_browser(false);
+ }
+
+ protected:
+ std::string GetTargetTabId() const override {
+ DCHECK(main_browser());
+ std::stringstream ss;
+ ss << main_browser()->GetIdentifier();
+ return ss.str();
+ }
+
+ private:
+ IMPLEMENT_REFCOUNTING(ExecuteScriptExplicitTabTestHandler);
+ DISALLOW_COPY_AND_ASSIGN(ExecuteScriptExplicitTabTestHandler);
+};
+
+} // namespace
+
+TABS_TEST_GROUP_ALL(ExecuteScriptExplicitTab,
+ ExecuteScriptExplicitTabTestHandler)
+
+namespace {
+
+// Test for chrome.tabs.executeScript with a file argument loading a content
+// script.
+class ExecuteScriptFileTestHandler : public ExecuteScriptTestHandler {
+ public:
+ explicit ExecuteScriptFileTestHandler(RequestContextType request_context_type)
+ : ExecuteScriptTestHandler(request_context_type) {}
+
+ // CefExtensionHandler methods:
+ bool GetExtensionResource(
+ CefRefPtr<CefExtension> extension,
+ CefRefPtr<CefBrowser> browser,
+ const CefString& file,
+ CefRefPtr<CefGetExtensionResourceCallback> callback) override {
+ EXPECT_TRUE(CefCurrentlyOn(TID_UI));
+ EXPECT_TRUE(this->extension());
+ EXPECT_TRUE(this->extension()->IsSame(extension));
+
+ if (file == "script.js") {
+ EXPECT_FALSE(got_get_extension_resource_);
+ got_get_extension_resource_.yes();
+
+ const std::string& content = GetContentScriptJS();
+ CefRefPtr<CefStreamReader> stream = CefStreamReader::CreateForData(
+ const_cast<char*>(content.data()), content.size());
+ callback->Continue(stream);
+ return true;
+ }
+
+ EXPECT_FALSE(true); // Not reached.
+ return false;
+ }
+
+ protected:
+ std::string GetTabsApiJS() const override {
+ return "chrome.tabs.executeScript(" + GetTargetTabId() +
+ ", {file:\"script.js\"});";
+ }
+
+ void OnDestroyTest() override {
+ ExecuteScriptTestHandler::OnDestroyTest();
+ EXPECT_TRUE(got_get_extension_resource_);
+ }
+
+ private:
+ TrackCallback got_get_extension_resource_;
+
+ IMPLEMENT_REFCOUNTING(ExecuteScriptFileTestHandler);
+ DISALLOW_COPY_AND_ASSIGN(ExecuteScriptFileTestHandler);
+};
+
+} // namespace
+
+TABS_TEST_GROUP_ALL(ExecuteScriptFile, ExecuteScriptFileTestHandler)
+
+namespace {
+
+// Test for chrome.tabs.executeScript with a callback argument.
+class ExecuteScriptCallbackTestHandler : public ExecuteScriptTestHandler {
+ public:
+ explicit ExecuteScriptCallbackTestHandler(
+ RequestContextType request_context_type)
+ : ExecuteScriptTestHandler(request_context_type) {}
+
+ protected:
+ bool OnMessage(CefRefPtr<CefBrowser> browser,
+ const std::string& message) override {
+ if (message == "callback") {
+ EXPECT_FALSE(got_callback_message_);
+ got_callback_message_.yes();
+ EXPECT_TRUE(browser->IsSame(extension_browser()));
+ TriggerDestroyTest();
+ return true;
+ }
+ return ExecuteScriptTestHandler::OnMessage(browser, message);
+ }
+
+ std::string GetTabsApiJS() const override {
+ return "chrome.tabs.executeScript(" + GetTargetTabId() + ", {code:\"" +
+ GetContentScriptJS() + "\"}, function(results) {" +
+ GetMessageJS("callback") + "});";
+ }
+
+ void TriggerDestroyTest() override {
+ // Only destroy the test if we got both callbacks.
+ if (got_callback_message_ && got_success_message()) {
+ ExecuteScriptTestHandler::TriggerDestroyTest();
+ }
+ }
+
+ void OnDestroyTest() override {
+ ExecuteScriptTestHandler::OnDestroyTest();
+ EXPECT_TRUE(got_callback_message_);
+ }
+
+ private:
+ TrackCallback got_callback_message_;
+
+ IMPLEMENT_REFCOUNTING(ExecuteScriptCallbackTestHandler);
+ DISALLOW_COPY_AND_ASSIGN(ExecuteScriptCallbackTestHandler);
+};
+
+} // namespace
+
+TABS_TEST_GROUP_MINIMAL(ExecuteScriptCallback, ExecuteScriptCallbackTestHandler)
+
+namespace {
+
+// Test for chrome.tabs.executeScript with execution occuring from a separate
+// resource script.
+class ExecuteScriptResourceTabTestHandler : public ExecuteScriptTestHandler {
+ public:
+ explicit ExecuteScriptResourceTabTestHandler(
+ RequestContextType request_context_type)
+ : ExecuteScriptTestHandler(request_context_type) {}
+
+ // CefResourceRequestHandler methods:
+ CefRefPtr<CefResourceHandler> GetResourceHandler(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request) override {
+ const std::string& url = request->GetURL();
+ if (url == resource_url_) {
+ EXPECT_TRUE(browser->IsSame(extension_browser()));
+ EXPECT_FALSE(got_resource_url_request_);
+ got_resource_url_request_.yes();
+ }
+
+ return ExecuteScriptTestHandler::GetResourceHandler(browser, frame,
+ request);
+ }
+
+ protected:
+ void OnAddExtensionResources(const std::string& origin) override {
+ ExecuteScriptTestHandler::OnAddExtensionResources(origin);
+ resource_url_ = origin + "resource.js";
+ AddResource(resource_url_, GetExtensionJS(), "text/javascript");
+ }
+
+ std::string GetExtensionHTML() const override {
+ return "<html><head><script src=\"resource.js\"></script></head><body "
+ "onLoad=" +
+ GetMessageJS("extension_onload") + ">Extension</body></html>";
+ }
+
+ void OnDestroyTest() override {
+ ExecuteScriptTestHandler::OnDestroyTest();
+ EXPECT_TRUE(got_resource_url_request_);
+ }
+
+ private:
+ std::string resource_url_;
+ TrackCallback got_resource_url_request_;
+
+ IMPLEMENT_REFCOUNTING(ExecuteScriptResourceTabTestHandler);
+ DISALLOW_COPY_AND_ASSIGN(ExecuteScriptResourceTabTestHandler);
+};
+
+} // namespace
+
+TABS_TEST_GROUP_MINIMAL(ExecuteScriptResource,
+ ExecuteScriptResourceTabTestHandler)
+
+//
+// chrome.tabs.insertCSS tests.
+//
+
+namespace {
+
+// Base class for chrome.tabs.insertCSS tests.
+class InsertCSSTestHandler : public TabsTestHandler {
+ public:
+ explicit InsertCSSTestHandler(RequestContextType request_context_type)
+ : TabsTestHandler(request_context_type) {}
+
+ protected:
+ std::string GetMainBrowserSuccessBODY() const override {
+ // We can't use a MutationObserver here because insertCSS does not modify
+ // the style attribute. We could detect the change by tracking modifications
+ // to document.styleSheets but that's complicated. Use a simple timer loop
+ // implementation calling getComputedStyle instead.
+ return "<script>var interval = setInterval(function() {"
+ "if (window.getComputedStyle(document.body,null)."
+ "getPropertyValue('background-color') == 'rgb(255, 0, 0)') {" +
+ GetMessageJS(kSuccessMessage) +
+ "clearInterval(interval);}}, 100);</script>";
+ }
+
+ // Returns the code that will be injected as a content script.
+ virtual std::string GetContentScriptCSS() const {
+ return "body{background-color:red}";
+ }
+
+ std::string GetTabsApiJS() const override {
+ return "chrome.tabs.insertCSS(" + GetTargetTabId() + ", {code:\"" +
+ GetContentScriptCSS() + "\"});";
+ }
+};
+
+// Test for chrome.tabs.insertCSS with a null tabId value.
+class InsertCSSNullTabTestHandler : public InsertCSSTestHandler {
+ public:
+ explicit InsertCSSNullTabTestHandler(RequestContextType request_context_type)
+ : InsertCSSTestHandler(request_context_type) {}
+
+ private:
+ IMPLEMENT_REFCOUNTING(InsertCSSNullTabTestHandler);
+ DISALLOW_COPY_AND_ASSIGN(InsertCSSNullTabTestHandler);
+};
+
+} // namespace
+
+TABS_TEST_GROUP_ALL(InsertCSSNullTab, InsertCSSNullTabTestHandler)
+
+namespace {
+
+// Test for chrome.tabs.insertCSS with an explicit tabId value.
+class InsertCSSExplicitTabTestHandler : public InsertCSSTestHandler {
+ public:
+ explicit InsertCSSExplicitTabTestHandler(
+ RequestContextType request_context_type)
+ : InsertCSSTestHandler(request_context_type) {
+ // Create the main browser first so we can retrieve the id.
+ set_create_main_browser_first(true);
+ // When a tabId is specified we should get a call to CanAccessBrowser
+ // instead of GetActiveBrowser.
+ set_expect_get_active_browser(false);
+ }
+
+ protected:
+ std::string GetTargetTabId() const override {
+ DCHECK(main_browser());
+ std::stringstream ss;
+ ss << main_browser()->GetIdentifier();
+ return ss.str();
+ }
+
+ private:
+ IMPLEMENT_REFCOUNTING(InsertCSSExplicitTabTestHandler);
+ DISALLOW_COPY_AND_ASSIGN(InsertCSSExplicitTabTestHandler);
+};
+
+} // namespace
+
+TABS_TEST_GROUP_ALL(InsertCSSExplicitTab, InsertCSSExplicitTabTestHandler)
+
+namespace {
+
+// Test for chrome.tabs.insertCSS with a file argument loading a content
+// script.
+class InsertCSSFileTestHandler : public InsertCSSTestHandler {
+ public:
+ explicit InsertCSSFileTestHandler(RequestContextType request_context_type)
+ : InsertCSSTestHandler(request_context_type) {}
+
+ // CefExtensionHandler methods:
+ bool GetExtensionResource(
+ CefRefPtr<CefExtension> extension,
+ CefRefPtr<CefBrowser> browser,
+ const CefString& file,
+ CefRefPtr<CefGetExtensionResourceCallback> callback) override {
+ EXPECT_TRUE(CefCurrentlyOn(TID_UI));
+ EXPECT_TRUE(this->extension());
+ EXPECT_TRUE(this->extension()->IsSame(extension));
+
+ if (file == "script.css") {
+ EXPECT_FALSE(got_get_extension_resource_);
+ got_get_extension_resource_.yes();
+
+ const std::string& content = GetContentScriptCSS();
+ CefRefPtr<CefStreamReader> stream = CefStreamReader::CreateForData(
+ const_cast<char*>(content.data()), content.size());
+ callback->Continue(stream);
+ return true;
+ }
+
+ EXPECT_FALSE(true); // Not reached.
+ return false;
+ }
+
+ protected:
+ std::string GetTabsApiJS() const override {
+ return "chrome.tabs.insertCSS(" + GetTargetTabId() +
+ ", {file:\"script.css\"});";
+ }
+
+ void OnDestroyTest() override {
+ InsertCSSTestHandler::OnDestroyTest();
+ EXPECT_TRUE(got_get_extension_resource_);
+ }
+
+ private:
+ TrackCallback got_get_extension_resource_;
+
+ IMPLEMENT_REFCOUNTING(InsertCSSFileTestHandler);
+ DISALLOW_COPY_AND_ASSIGN(InsertCSSFileTestHandler);
+};
+
+} // namespace
+
+TABS_TEST_GROUP_ALL(InsertCSSFile, InsertCSSFileTestHandler)
+
+namespace {
+
+// Test for chrome.tabs.insertCSS with a callback argument.
+class InsertCSSCallbackTestHandler : public InsertCSSTestHandler {
+ public:
+ explicit InsertCSSCallbackTestHandler(RequestContextType request_context_type)
+ : InsertCSSTestHandler(request_context_type) {}
+
+ protected:
+ bool OnMessage(CefRefPtr<CefBrowser> browser,
+ const std::string& message) override {
+ if (message == "callback") {
+ EXPECT_FALSE(got_callback_message_);
+ got_callback_message_.yes();
+ EXPECT_TRUE(browser->IsSame(extension_browser()));
+ TriggerDestroyTest();
+ return true;
+ }
+ return InsertCSSTestHandler::OnMessage(browser, message);
+ }
+
+ std::string GetTabsApiJS() const override {
+ return "chrome.tabs.insertCSS(" + GetTargetTabId() + ", {code:\"" +
+ GetContentScriptCSS() + "\"}, function(results) {" +
+ GetMessageJS("callback") + "});";
+ }
+
+ void TriggerDestroyTest() override {
+ // Only destroy the test if we got both callbacks.
+ if (got_callback_message_ && got_success_message()) {
+ InsertCSSTestHandler::TriggerDestroyTest();
+ }
+ }
+
+ void OnDestroyTest() override {
+ InsertCSSTestHandler::OnDestroyTest();
+ EXPECT_TRUE(got_callback_message_);
+ }
+
+ private:
+ TrackCallback got_callback_message_;
+
+ IMPLEMENT_REFCOUNTING(InsertCSSCallbackTestHandler);
+ DISALLOW_COPY_AND_ASSIGN(InsertCSSCallbackTestHandler);
+};
+
+} // namespace
+
+TABS_TEST_GROUP_MINIMAL(InsertCSSCallback, InsertCSSCallbackTestHandler)
+
+namespace {
+
+// Test for chrome.tabs.insertCSS with execution occuring from a separate
+// resource script.
+class InsertCSSResourceTabTestHandler : public InsertCSSTestHandler {
+ public:
+ explicit InsertCSSResourceTabTestHandler(
+ RequestContextType request_context_type)
+ : InsertCSSTestHandler(request_context_type) {}
+
+ // CefResourceRequestHandler methods:
+ CefRefPtr<CefResourceHandler> GetResourceHandler(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request) override {
+ const std::string& url = request->GetURL();
+ if (url == resource_url_) {
+ EXPECT_TRUE(browser->IsSame(extension_browser()));
+ EXPECT_FALSE(got_resource_url_request_);
+ got_resource_url_request_.yes();
+ }
+
+ return InsertCSSTestHandler::GetResourceHandler(browser, frame, request);
+ }
+
+ protected:
+ void OnAddExtensionResources(const std::string& origin) override {
+ InsertCSSTestHandler::OnAddExtensionResources(origin);
+ resource_url_ = origin + "resource.js";
+ AddResource(resource_url_, GetExtensionJS(), "text/javascript");
+ }
+
+ std::string GetExtensionHTML() const override {
+ return "<html><head><script src=\"resource.js\"></script></head><body "
+ "onLoad=" +
+ GetMessageJS("extension_onload") + ">Extension</body></html>";
+ }
+
+ void OnDestroyTest() override {
+ InsertCSSTestHandler::OnDestroyTest();
+ EXPECT_TRUE(got_resource_url_request_);
+ }
+
+ private:
+ std::string resource_url_;
+ TrackCallback got_resource_url_request_;
+
+ IMPLEMENT_REFCOUNTING(InsertCSSResourceTabTestHandler);
+ DISALLOW_COPY_AND_ASSIGN(InsertCSSResourceTabTestHandler);
+};
+
+} // namespace
+
+TABS_TEST_GROUP_MINIMAL(InsertCSSResource, InsertCSSResourceTabTestHandler)
+
+//
+// chrome.tabs.setZoom/getZoom tests.
+//
+
+namespace {
+
+// Base class for chrome.tabs.setZoom/getZoom tests.
+class ZoomTestHandler : public TabsTestHandler {
+ public:
+ explicit ZoomTestHandler(RequestContextType request_context_type)
+ : TabsTestHandler(request_context_type) {
+ // We call API functions three times in this handler.
+ set_expected_api_call_count(3);
+ }
+
+ protected:
+ std::string GetMainBrowserSuccessHEAD() const override {
+ return "<script>var orig_width = window.innerWidth;</script>";
+ }
+
+ std::string GetMainBrowserSuccessBODY() const override {
+ // We can't directly detect zoom changes, so instead we look for changes
+ // in window.innerWidth.
+ return "<script>var interval = setInterval(function() {"
+ "if (window.innerWidth != orig_width) {" +
+ GetMessageJS(kSuccessMessage) +
+ "clearInterval(interval);}}, 100);</script>";
+ }
+
+ std::string GetTabsApiJS() const override {
+ // Results in a change to window.innerWidth.
+ return "chrome.tabs.setZoom(" + GetTargetTabId() + ", 2.0);";
+ }
+
+ bool OnMessage(CefRefPtr<CefBrowser> browser,
+ const std::string& message) override {
+ if (message == "restored") {
+ EXPECT_TRUE(browser->IsSame(extension_browser()));
+ EXPECT_FALSE(got_restored_message_);
+ got_restored_message_.yes();
+ // Destroy the test for real.
+ TabsTestHandler::TriggerDestroyTest();
+ return true;
+ }
+ return TabsTestHandler::OnMessage(browser, message);
+ }
+
+ void TriggerDestroyTest() override {
+ // Before destroying the test we need to restore the zoom factor so that
+ // it doesn't persist in the RequestContext. This also tests the callback
+ // argument and the getZoom function so there's no need to do that
+ // separately.
+ extension_browser()->GetMainFrame()->ExecuteJavaScript(
+ "chrome.tabs.setZoom(" + GetTargetTabId() + ", 1.0, function() {" +
+ "chrome.tabs.getZoom(" + GetTargetTabId() +
+ ", function(zoomFactor) { if (zoomFactor == 1.0) {" +
+ GetMessageJS("restored") + "}})});",
+ extension_url(), 0);
+ }
+
+ void OnDestroyTest() override {
+ TabsTestHandler::OnDestroyTest();
+ EXPECT_TRUE(got_restored_message_);
+ }
+
+ private:
+ TrackCallback got_restored_message_;
+};
+
+// Test for chrome.tabs.setZoom/getZoom with a null tabId value.
+class ZoomNullTabTestHandler : public ZoomTestHandler {
+ public:
+ explicit ZoomNullTabTestHandler(RequestContextType request_context_type)
+ : ZoomTestHandler(request_context_type) {}
+
+ private:
+ IMPLEMENT_REFCOUNTING(ZoomNullTabTestHandler);
+ DISALLOW_COPY_AND_ASSIGN(ZoomNullTabTestHandler);
+};
+
+} // namespace
+
+TABS_TEST_GROUP_ALL(ZoomNullTab, ZoomNullTabTestHandler)
+
+namespace {
+
+// Test for chrome.tabs.setZoom/getZoom with an explicit tabId value.
+class ZoomExplicitTabTestHandler : public ZoomTestHandler {
+ public:
+ explicit ZoomExplicitTabTestHandler(RequestContextType request_context_type)
+ : ZoomTestHandler(request_context_type) {
+ // Create the main browser first so we can retrieve the id.
+ set_create_main_browser_first(true);
+ // When a tabId is specified we should get a call to CanAccessBrowser
+ // instead of GetActiveBrowser.
+ set_expect_get_active_browser(false);
+ }
+
+ protected:
+ std::string GetTargetTabId() const override {
+ DCHECK(main_browser());
+ std::stringstream ss;
+ ss << main_browser()->GetIdentifier();
+ return ss.str();
+ }
+
+ private:
+ IMPLEMENT_REFCOUNTING(ZoomExplicitTabTestHandler);
+ DISALLOW_COPY_AND_ASSIGN(ZoomExplicitTabTestHandler);
+};
+
+} // namespace
+
+TABS_TEST_GROUP_ALL(ZoomExplicitTab, ZoomExplicitTabTestHandler)
+
+//
+// chrome.tabs.setZoomSettings/getZoomSettings tests.
+//
+
+namespace {
+
+// Base class for chrome.tabs.setZoomSettings/getZoomSettings tests.
+class ZoomSettingsTestHandler : public TabsTestHandler {
+ public:
+ explicit ZoomSettingsTestHandler(RequestContextType request_context_type)
+ : TabsTestHandler(request_context_type) {
+ // We call API functions two times in this handler.
+ set_expected_api_call_count(2);
+ // Success message will be delivered in the extension browser because we
+ // don't know how to detect zoom settings changes in the main browser.
+ set_expect_success_in_main_browser(false);
+ }
+
+ protected:
+ std::string GetTabsApiJS() const override {
+ // Set and restore the zoom settings. This also tests the callback argument
+ // and the getZoomSettings function so there's no need to do that
+ // separately. This is safe because zoom settings are not persisted in the
+ // RequestContext across navigations.
+ return "chrome.tabs.setZoomSettings(" + GetTargetTabId() +
+ ", {mode: 'manual', scope: 'per-tab'}, function() {" +
+ "chrome.tabs.getZoomSettings(" + GetTargetTabId() +
+ ", function(zoomSettings) { if (zoomSettings.mode == 'manual' "
+ "&& zoomSettings.scope == 'per-tab') {" +
+ GetMessageJS(kSuccessMessage) + "}})});";
+ }
+};
+
+// Test for chrome.tabs.setZoomSettings/getZoomSettings with a null tabId value.
+class ZoomSettingsNullTabTestHandler : public ZoomSettingsTestHandler {
+ public:
+ explicit ZoomSettingsNullTabTestHandler(
+ RequestContextType request_context_type)
+ : ZoomSettingsTestHandler(request_context_type) {}
+
+ private:
+ IMPLEMENT_REFCOUNTING(ZoomSettingsNullTabTestHandler);
+ DISALLOW_COPY_AND_ASSIGN(ZoomSettingsNullTabTestHandler);
+};
+
+} // namespace
+
+TABS_TEST_GROUP_ALL(ZoomSettingsNullTab, ZoomSettingsNullTabTestHandler)
+
+namespace {
+
+// Test for chrome.tabs.setZoomSettings/getZoomSettings with an explicit tabId
+// value.
+class ZoomSettingsExplicitTabTestHandler : public ZoomSettingsTestHandler {
+ public:
+ explicit ZoomSettingsExplicitTabTestHandler(
+ RequestContextType request_context_type)
+ : ZoomSettingsTestHandler(request_context_type) {
+ // Create the main browser first so we can retrieve the id.
+ set_create_main_browser_first(true);
+ // When a tabId is specified we should get a call to CanAccessBrowser
+ // instead of GetActiveBrowser.
+ set_expect_get_active_browser(false);
+ }
+
+ protected:
+ std::string GetTargetTabId() const override {
+ DCHECK(main_browser());
+ std::stringstream ss;
+ ss << main_browser()->GetIdentifier();
+ return ss.str();
+ }
+
+ private:
+ IMPLEMENT_REFCOUNTING(ZoomSettingsExplicitTabTestHandler);
+ DISALLOW_COPY_AND_ASSIGN(ZoomSettingsExplicitTabTestHandler);
+};
+
+} // namespace
+
+TABS_TEST_GROUP_ALL(ZoomSettingsExplicitTab, ZoomSettingsExplicitTabTestHandler)
diff --git a/tests/ceftests/extensions/extension_test_handler.cc b/tests/ceftests/extensions/extension_test_handler.cc
new file mode 100644
index 00000000..22259c22
--- /dev/null
+++ b/tests/ceftests/extensions/extension_test_handler.cc
@@ -0,0 +1,240 @@
+// Copyright (c) 2017 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/ceftests/extensions/extension_test_handler.h"
+
+#include "include/cef_request_context_handler.h"
+#include "tests/ceftests/test_suite.h"
+#include "tests/ceftests/test_util.h"
+
+ExtensionTestHandler::ExtensionTestHandler(
+ RequestContextType request_context_type)
+ : request_context_type_(request_context_type), create_main_browser_(true) {
+ // Verify supported flag combinations.
+ if (request_context_on_disk()) {
+ EXPECT_TRUE(request_context_is_custom());
+ }
+ if (request_context_load_with_handler()) {
+ EXPECT_FALSE(request_context_load_without_handler());
+ }
+ if (request_context_load_without_handler()) {
+ EXPECT_TRUE(request_context_with_handler());
+ EXPECT_FALSE(request_context_load_with_handler());
+ }
+}
+
+ExtensionTestHandler::~ExtensionTestHandler() {
+ if (!request_context_temp_dir_.IsEmpty()) {
+ // Temporary directory will be deleted on shutdown.
+ request_context_temp_dir_.Take();
+ }
+}
+
+void ExtensionTestHandler::RunTest() {
+ if (create_main_browser_) {
+ OnAddMainBrowserResources();
+ }
+
+ CefRefPtr<CefRequestContextHandler> rc_handler;
+ if (request_context_with_handler()) {
+ class Handler : public CefRequestContextHandler {
+ public:
+ explicit Handler(ExtensionTestHandler* test_handler)
+ : test_handler_(test_handler) {}
+
+ void OnRequestContextInitialized(
+ CefRefPtr<CefRequestContext> request_context) override {
+ if (test_handler_->create_main_browser()) {
+ // Load extensions after the RequestContext has been initialized by
+ // creation of the main browser.
+ test_handler_->OnLoadExtensions();
+ }
+ }
+
+ private:
+ ExtensionTestHandler* test_handler_;
+
+ IMPLEMENT_REFCOUNTING(Handler);
+ };
+ rc_handler = new Handler(this);
+ }
+
+ if (request_context_is_custom()) {
+ CefRequestContextSettings settings;
+
+ if (request_context_on_disk()) {
+ // Create a new temporary directory.
+ EXPECT_TRUE(request_context_temp_dir_.CreateUniqueTempDirUnderPath(
+ CefTestSuite::GetInstance()->root_cache_path()));
+ CefString(&settings.cache_path) = request_context_temp_dir_.GetPath();
+ }
+
+ request_context_ = CefRequestContext::CreateContext(settings, rc_handler);
+ } else {
+ request_context_ = CefRequestContext::CreateContext(
+ CefRequestContext::GetGlobalContext(), rc_handler);
+ }
+
+ if (request_context_load_with_handler()) {
+ class Handler : public CefRequestContextHandler {
+ public:
+ Handler() {}
+
+ private:
+ IMPLEMENT_REFCOUNTING(Handler);
+ };
+ loader_request_context_ =
+ CefRequestContext::CreateContext(request_context_, new Handler());
+ } else if (request_context_load_without_handler()) {
+ loader_request_context_ =
+ CefRequestContext::CreateContext(request_context_, nullptr);
+ } else {
+ loader_request_context_ = request_context_;
+ }
+
+ if (create_main_browser_) {
+ OnCreateMainBrowser();
+ } else {
+ // Creation of the extension browser will trigger initialization of the
+ // RequestContext, so just load the extensions now.
+ OnLoadExtensions();
+ }
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout();
+}
+
+void ExtensionTestHandler::DestroyTest() {
+ OnDestroyTest();
+ ReleaseRequestContexts();
+ RoutingTestHandler::DestroyTest();
+}
+
+void ExtensionTestHandler::OnAfterCreated(CefRefPtr<CefBrowser> browser) {
+ RoutingTestHandler::OnAfterCreated(browser);
+
+ if (create_main_browser() && !request_context_with_handler() &&
+ GetBrowserId() == browser->GetIdentifier()) {
+ // When the RequestContext doesn't have a handler we won't get a
+ // notification for RequestContext initialization. Instead use main browser
+ // creation to indicate that the RequestContext has been initialized.
+ OnLoadExtensions();
+ }
+}
+
+void ExtensionTestHandler::OnExtensionLoadFailed(cef_errorcode_t result) {
+ EXPECT_TRUE(CefCurrentlyOn(TID_UI));
+ EXPECT_TRUE(false); // Not reached.
+}
+
+// CefMessageRouterBrowserSide::Handler methods:
+bool ExtensionTestHandler::OnQuery(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int64 query_id,
+ const CefString& request,
+ bool persistent,
+ CefRefPtr<Callback> callback) {
+ if (OnMessage(browser, request)) {
+ return true;
+ }
+
+ EXPECT_FALSE(true) << "Unexpected message: " << request.ToString();
+ return false;
+}
+
+// static
+CefRefPtr<CefDictionaryValue> ExtensionTestHandler::CreateDefaultManifest(
+ const std::vector<std::string>& api_permissions) {
+ CefRefPtr<CefDictionaryValue> manifest = CefDictionaryValue::Create();
+ manifest->SetString("name", "An extension");
+ manifest->SetString("description", "An extension description");
+ manifest->SetString("version", "1.0");
+ manifest->SetInt("manifest_version", 2);
+
+ CefRefPtr<CefListValue> permissions = CefListValue::Create();
+ permissions->SetSize(api_permissions.size() + 2);
+ size_t idx = 0;
+ for (; idx < api_permissions.size(); ++idx) {
+ permissions->SetString(idx, api_permissions[idx]);
+ }
+
+ // Allow access to all http/https origins.
+ permissions->SetString(idx++, "http://*/*");
+ permissions->SetString(idx++, "https://*/*");
+
+ manifest->SetList("permissions", permissions);
+
+ return manifest;
+}
+
+// static
+std::string ExtensionTestHandler::GetMessageJS(const std::string& message) {
+ EXPECT_TRUE(!message.empty());
+ return "window.testQuery({request:'" + message + "'});";
+}
+
+// static
+void ExtensionTestHandler::VerifyExtensionInContext(
+ CefRefPtr<CefExtension> extension,
+ CefRefPtr<CefRequestContext> context,
+ bool has_access,
+ bool is_loader) {
+ const CefString& extension_id = extension->GetIdentifier();
+ EXPECT_FALSE(extension_id.empty());
+
+ if (has_access) {
+ EXPECT_TRUE(context->DidLoadExtension(extension_id));
+ EXPECT_TRUE(context->HasExtension(extension_id));
+ } else {
+ EXPECT_FALSE(context->DidLoadExtension(extension_id));
+ EXPECT_FALSE(context->HasExtension(extension_id));
+ }
+
+ CefRefPtr<CefExtension> extension2 = context->GetExtension(extension_id);
+ if (has_access) {
+ EXPECT_TRUE(extension2);
+ EXPECT_TRUE(extension->IsSame(extension2));
+ TestDictionaryEqual(extension->GetManifest(), extension2->GetManifest());
+ } else {
+ EXPECT_FALSE(extension2);
+ }
+
+ std::vector<CefString> extension_ids;
+ EXPECT_TRUE(context->GetExtensions(extension_ids));
+
+ // Should be our test extension and possibly the builtin PDF extension if it
+ // has finished loading (our extension may load first if the call to
+ // LoadExtension initializes the request context).
+ bool has_extension = false;
+ for (size_t i = 0; i < extension_ids.size(); ++i) {
+ if (extension_ids[i] == extension_id) {
+ has_extension = true;
+ break;
+ }
+ }
+ if (has_access) {
+ EXPECT_TRUE(has_extension);
+ } else {
+ EXPECT_FALSE(has_extension);
+ }
+}
+
+void ExtensionTestHandler::LoadExtension(
+ const std::string& extension_path,
+ CefRefPtr<CefDictionaryValue> manifest) {
+ EXPECT_TRUE(!extension_path.empty());
+ loader_request_context_->LoadExtension(extension_path, manifest, this);
+}
+
+void ExtensionTestHandler::UnloadExtension(CefRefPtr<CefExtension> extension) {
+ EXPECT_TRUE(extension);
+ extension->Unload();
+ EXPECT_FALSE(extension->IsLoaded());
+ EXPECT_FALSE(extension->GetLoaderContext());
+}
+
+void ExtensionTestHandler::ReleaseRequestContexts() {
+ request_context_ = nullptr;
+ loader_request_context_ = nullptr;
+}
diff --git a/tests/ceftests/extensions/extension_test_handler.h b/tests/ceftests/extensions/extension_test_handler.h
new file mode 100644
index 00000000..6e916e35
--- /dev/null
+++ b/tests/ceftests/extensions/extension_test_handler.h
@@ -0,0 +1,238 @@
+// Copyright (c) 2017 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFTESTS_EXTENSIONS_EXTENSION_TEST_HANDLER_H_
+#define CEF_TESTS_CEFTESTS_EXTENSIONS_EXTENSION_TEST_HANDLER_H_
+#pragma once
+
+#include <vector>
+
+#include "include/cef_extension_handler.h"
+#include "include/cef_values.h"
+#include "include/wrapper/cef_scoped_temp_dir.h"
+#include "tests/ceftests/routing_test_handler.h"
+#include "tests/gtest/include/gtest/gtest.h"
+
+class ExtensionTestHandler : public RoutingTestHandler,
+ public CefExtensionHandler {
+ public:
+ // All tests must be able to run with all RequestContext combinations. See the
+ // EXTENSION_TEST_GROUP_* macros below.
+ enum RequestContextType {
+ // If set create a custom context. Otherwise, use the global context.
+ RC_TYPE_FLAG_CUSTOM = 1 << 0,
+
+ // If set store data on disk. Otherwise, store data in memory.
+ // Requires RC_TYPE_FLAG_CUSTOM.
+ RC_TYPE_FLAG_ON_DISK = 1 << 1,
+
+ // If set use a handler. Otherwise, don't.
+ RC_TYPE_FLAG_WITH_HANDLER = 1 << 2,
+
+ // If set load extensions with a different context that shares the same
+ // storage but specifies a different handler.
+ // Excludes RC_TYPE_FLAG_LOAD_WITHOUT_HANDLER.
+ RC_TYPE_FLAG_LOAD_WITH_HANDLER = 1 << 3,
+
+ // If set load extensions with a different context that shares the same
+ // storage but doesn't specify a handler.
+ // Requires RC_TYPE_FLAG_WITH_HANDLER.
+ // Excludes RC_TYPE_FLAG_LOAD_WITH_HANDLER.
+ RC_TYPE_FLAG_LOAD_WITHOUT_HANDLER = 1 << 4,
+ };
+
+ explicit ExtensionTestHandler(RequestContextType request_context_type);
+ virtual ~ExtensionTestHandler();
+
+ // TestHandler methods:
+ void RunTest() override;
+ void DestroyTest() override;
+ void OnAfterCreated(CefRefPtr<CefBrowser> browser) override;
+
+ // CefExtensionHandler methods:
+ void OnExtensionLoadFailed(cef_errorcode_t result) override;
+
+ // CefMessageRouterBrowserSide::Handler methods:
+ bool OnQuery(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int64 query_id,
+ const CefString& request,
+ bool persistent,
+ CefRefPtr<Callback> callback) override;
+
+ CefRefPtr<CefRequestContext> request_context() const {
+ return request_context_;
+ }
+ CefRefPtr<CefRequestContext> loader_request_context() const {
+ return loader_request_context_;
+ }
+
+ bool request_context_is_custom() const {
+ return !!(request_context_type_ & RC_TYPE_FLAG_CUSTOM);
+ }
+ bool request_context_on_disk() const {
+ return !!(request_context_type_ & RC_TYPE_FLAG_ON_DISK);
+ }
+ bool request_context_with_handler() const {
+ return !!(request_context_type_ & RC_TYPE_FLAG_WITH_HANDLER);
+ }
+ bool request_context_load_with_handler() const {
+ return !!(request_context_type_ & RC_TYPE_FLAG_LOAD_WITH_HANDLER);
+ }
+ bool request_context_load_without_handler() const {
+ return !!(request_context_type_ & RC_TYPE_FLAG_LOAD_WITHOUT_HANDLER);
+ }
+ bool request_context_same_loader() const {
+ return !(request_context_load_with_handler() ||
+ request_context_load_without_handler());
+ }
+
+ protected:
+ // Returns the default extension manifest.
+ typedef std::vector<std::string> ApiPermissionsList;
+ static CefRefPtr<CefDictionaryValue> CreateDefaultManifest(
+ const ApiPermissionsList& api_permissions);
+
+ // Returns the JS code that, when executed, will deliver |message| to the
+ // OnMessage callback.
+ static std::string GetMessageJS(const std::string& message);
+
+ // Run checks on the state of |extension| in |context|. If |has_access| is
+ // true then |context| is expected to have access to |extension|. If
+ // |is_loader| is true then |context| is expected to have loaded |extension|.
+ static void VerifyExtensionInContext(CefRefPtr<CefExtension> extension,
+ CefRefPtr<CefRequestContext> context,
+ bool has_access,
+ bool is_loader);
+
+ // Helper for loading/unloading an extension.
+ void LoadExtension(const std::string& extension_path,
+ CefRefPtr<CefDictionaryValue> manifest);
+ void UnloadExtension(CefRefPtr<CefExtension> extension);
+
+ // Release request contexts. This is normally called from DestroyTest().
+ void ReleaseRequestContexts();
+
+ void set_create_main_browser(bool val) { create_main_browser_ = val; }
+ bool create_main_browser() const { return create_main_browser_; }
+
+ // Called when its time to add resources for the main browser if
+ // |create_main_browser_| is true.
+ virtual void OnAddMainBrowserResources() {}
+ // Called when its time to create the main browser if
+ // |create_main_browser_| is true.
+ virtual void OnCreateMainBrowser() {}
+
+ // Called when its time to load extensions.
+ virtual void OnLoadExtensions() = 0;
+
+ // Called when |browser| receives |message|. Return true if the message is
+ // handled. The JS code that sends messages is created by GetMessageJS().
+ virtual bool OnMessage(CefRefPtr<CefBrowser> browser,
+ const std::string& message) = 0;
+
+ // Called to perform verification on test destruction.
+ virtual void OnDestroyTest() = 0;
+
+ private:
+ const RequestContextType request_context_type_;
+ CefScopedTempDir request_context_temp_dir_;
+
+ // Context used when creating browsers.
+ CefRefPtr<CefRequestContext> request_context_;
+
+ // Context used when loading extensions.
+ CefRefPtr<CefRequestContext> loader_request_context_;
+
+ // If true expect creation of a main browser. Default is true.
+ bool create_main_browser_;
+
+ DISALLOW_COPY_AND_ASSIGN(ExtensionTestHandler);
+};
+
+// Helper for implementing an extension test.
+#define EXTENSION_TEST(name, test_class, rc_type) \
+ TEST(ExtensionTest, name) { \
+ CefRefPtr<test_class> handler = new test_class( \
+ static_cast<ExtensionTestHandler::RequestContextType>(rc_type)); \
+ handler->ExecuteTest(); \
+ ReleaseAndWaitForDestructor(handler); \
+ }
+
+// Helper for implementing extension tests that include all RequestContext
+// combinations. When two or more extension tests significantly overlap in
+// tested functionality the first test should use the ALL macro and the others
+// should use the MINIMAL macro.
+#define EXTENSION_TEST_GROUP_ALL(name, test_class) \
+ EXTENSION_TEST(name##RCGlobal, test_class, 0) \
+ EXTENSION_TEST(name##RCGlobalLoadWithHandler, test_class, \
+ ExtensionTestHandler::RC_TYPE_FLAG_LOAD_WITH_HANDLER) \
+ EXTENSION_TEST(name##RCGlobalWithHandler, test_class, \
+ ExtensionTestHandler::RC_TYPE_FLAG_WITH_HANDLER) \
+ EXTENSION_TEST(name##RCGlobalWithHandlerLoadWithHandler, test_class, \
+ ExtensionTestHandler::RC_TYPE_FLAG_WITH_HANDLER | \
+ ExtensionTestHandler::RC_TYPE_FLAG_LOAD_WITH_HANDLER) \
+ EXTENSION_TEST(name##RCGlobalWithHandlerLoadWithoutHandler, test_class, \
+ ExtensionTestHandler::RC_TYPE_FLAG_WITH_HANDLER | \
+ ExtensionTestHandler::RC_TYPE_FLAG_LOAD_WITHOUT_HANDLER) \
+ EXTENSION_TEST(name##RCCustomInMemory, test_class, \
+ ExtensionTestHandler::RC_TYPE_FLAG_CUSTOM) \
+ EXTENSION_TEST(name##RCCustomInMemoryLoadWithHandler, test_class, \
+ ExtensionTestHandler::RC_TYPE_FLAG_CUSTOM | \
+ ExtensionTestHandler::RC_TYPE_FLAG_LOAD_WITH_HANDLER) \
+ EXTENSION_TEST(name##RCCustomInMemoryWithHandler, test_class, \
+ ExtensionTestHandler::RC_TYPE_FLAG_CUSTOM | \
+ ExtensionTestHandler::RC_TYPE_FLAG_WITH_HANDLER) \
+ EXTENSION_TEST(name##RCCustomInMemoryWithHandlerLoadWithHandler, test_class, \
+ ExtensionTestHandler::RC_TYPE_FLAG_CUSTOM | \
+ ExtensionTestHandler::RC_TYPE_FLAG_WITH_HANDLER | \
+ ExtensionTestHandler::RC_TYPE_FLAG_LOAD_WITH_HANDLER) \
+ EXTENSION_TEST(name##RCCustomInMemoryWithHandlerLoadWithoutHandler, \
+ test_class, \
+ ExtensionTestHandler::RC_TYPE_FLAG_CUSTOM | \
+ ExtensionTestHandler::RC_TYPE_FLAG_WITH_HANDLER | \
+ ExtensionTestHandler::RC_TYPE_FLAG_LOAD_WITHOUT_HANDLER) \
+ EXTENSION_TEST(name##RCCustomOnDisk, test_class, \
+ ExtensionTestHandler::RC_TYPE_FLAG_CUSTOM | \
+ ExtensionTestHandler::RC_TYPE_FLAG_ON_DISK) \
+ EXTENSION_TEST(name##RCCustomOnDiskLoadWithHandler, test_class, \
+ ExtensionTestHandler::RC_TYPE_FLAG_CUSTOM | \
+ ExtensionTestHandler::RC_TYPE_FLAG_ON_DISK | \
+ ExtensionTestHandler::RC_TYPE_FLAG_LOAD_WITH_HANDLER) \
+ EXTENSION_TEST(name##RCCustomOnDiskWithHandler, test_class, \
+ ExtensionTestHandler::RC_TYPE_FLAG_CUSTOM | \
+ ExtensionTestHandler::RC_TYPE_FLAG_ON_DISK | \
+ ExtensionTestHandler::RC_TYPE_FLAG_WITH_HANDLER) \
+ EXTENSION_TEST(name##RCCustomOnDiskWithHandlerLoadWithHandler, test_class, \
+ ExtensionTestHandler::RC_TYPE_FLAG_CUSTOM | \
+ ExtensionTestHandler::RC_TYPE_FLAG_ON_DISK | \
+ ExtensionTestHandler::RC_TYPE_FLAG_WITH_HANDLER | \
+ ExtensionTestHandler::RC_TYPE_FLAG_LOAD_WITH_HANDLER) \
+ EXTENSION_TEST(name##RCCustomOnDiskWithHandlerLoadWithoutHandler, \
+ test_class, \
+ ExtensionTestHandler::RC_TYPE_FLAG_CUSTOM | \
+ ExtensionTestHandler::RC_TYPE_FLAG_ON_DISK | \
+ ExtensionTestHandler::RC_TYPE_FLAG_WITH_HANDLER | \
+ ExtensionTestHandler::RC_TYPE_FLAG_LOAD_WITHOUT_HANDLER)
+
+#define EXTENSION_TEST_GROUP_MINIMAL_GLOBAL(name, test_class) \
+ EXTENSION_TEST(name##RCGlobal, test_class, 0) \
+ EXTENSION_TEST(name##RCGlobalWithHandler, test_class, \
+ ExtensionTestHandler::RC_TYPE_FLAG_WITH_HANDLER)
+
+#define EXTENSION_TEST_GROUP_MINIMAL_CUSTOM(name, test_class) \
+ EXTENSION_TEST(name##RCCustomInMemory, test_class, \
+ ExtensionTestHandler::RC_TYPE_FLAG_CUSTOM) \
+ EXTENSION_TEST(name##RCCustomInMemoryWithHandler, test_class, \
+ ExtensionTestHandler::RC_TYPE_FLAG_CUSTOM | \
+ ExtensionTestHandler::RC_TYPE_FLAG_WITH_HANDLER)
+
+// Helper for implementing extension tests that include a minimal set of
+// RequestContext combinations. This mostly just verifies that the test runs
+// and doesn't leak state information in the context.
+#define EXTENSION_TEST_GROUP_MINIMAL(name, test_class) \
+ EXTENSION_TEST_GROUP_MINIMAL_GLOBAL(name, test_class) \
+ EXTENSION_TEST_GROUP_MINIMAL_CUSTOM(name, test_class)
+
+#endif // CEF_TESTS_CEFTESTS_EXTENSIONS_EXTENSION_TEST_HANDLER_H_
diff --git a/tests/ceftests/extensions/view_unittest.cc b/tests/ceftests/extensions/view_unittest.cc
new file mode 100644
index 00000000..4d9c03cb
--- /dev/null
+++ b/tests/ceftests/extensions/view_unittest.cc
@@ -0,0 +1,245 @@
+// Copyright (c) 2017 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/ceftests/extensions/extension_test_handler.h"
+
+#include "tests/ceftests/test_util.h"
+#include "tests/shared/browser/extension_util.h"
+
+namespace {
+
+const char kExtensionPath[] = "view-extension";
+
+// Test extension load/unload.
+class ViewLoadUnloadTestHandler : public ExtensionTestHandler {
+ public:
+ explicit ViewLoadUnloadTestHandler(RequestContextType request_context_type)
+ : ExtensionTestHandler(request_context_type) {
+ // Only creating the extension browser.
+ set_create_main_browser(false);
+ }
+
+ // CefExtensionHandler methods:
+ void OnExtensionLoaded(CefRefPtr<CefExtension> extension) override {
+ EXPECT_TRUE(CefCurrentlyOn(TID_UI));
+ EXPECT_TRUE(extension);
+ EXPECT_TRUE(extension->IsLoaded());
+ EXPECT_TRUE(extension->GetLoaderContext());
+ EXPECT_TRUE(
+ loader_request_context()->IsSame(extension->GetLoaderContext()));
+ VerifyExtension(extension);
+
+ EXPECT_FALSE(got_loaded_);
+ got_loaded_.yes();
+
+ EXPECT_FALSE(extension_);
+ extension_ = extension;
+
+ CreateBrowserForExtension();
+ }
+
+ void OnExtensionUnloaded(CefRefPtr<CefExtension> extension) override {
+ EXPECT_TRUE(CefCurrentlyOn(TID_UI));
+ EXPECT_TRUE(extension);
+ EXPECT_FALSE(extension->IsLoaded());
+ EXPECT_FALSE(extension->GetLoaderContext());
+
+ EXPECT_FALSE(got_unloaded_);
+ got_unloaded_.yes();
+
+ EXPECT_TRUE(extension_);
+ EXPECT_TRUE(extension_->IsSame(extension));
+
+ // The extension should no longer be registered with the context.
+ if (loader_request_context()) {
+ VerifyExtensionInContext(extension, loader_request_context(), false,
+ true);
+ }
+ if (request_context() && !request_context_same_loader()) {
+ VerifyExtensionInContext(extension, request_context(), false, false);
+ }
+
+ extension_ = nullptr;
+
+ // Execute asynchronously so call stacks have a chance to unwind.
+ // Will close the browser windows.
+ CefPostTask(TID_UI,
+ base::BindOnce(&ViewLoadUnloadTestHandler::DestroyTest, this));
+ }
+
+ // CefLoadHandler methods:
+ void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
+ bool isLoading,
+ bool canGoBack,
+ bool canGoForward) override {
+ EXPECT_FALSE(browser->GetHost()->IsBackgroundHost());
+
+ CefRefPtr<CefExtension> extension = browser->GetHost()->GetExtension();
+ EXPECT_TRUE(extension);
+ EXPECT_TRUE(extension_->IsSame(extension));
+
+ if (isLoading) {
+ EXPECT_FALSE(extension_browser_);
+ extension_browser_ = browser;
+ } else {
+ EXPECT_TRUE(browser->IsSame(extension_browser_));
+
+ const std::string& url = browser->GetMainFrame()->GetURL();
+ EXPECT_STREQ(extension_url_.c_str(), url.c_str());
+
+ EXPECT_FALSE(got_load_done_);
+ got_load_done_.yes();
+
+ TriggerDestroyTestIfDone();
+ }
+ }
+
+ // CefResourceRequestHandler methods:
+ CefRefPtr<CefResourceHandler> GetResourceHandler(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request) override {
+ EXPECT_FALSE(browser->GetHost()->IsBackgroundHost());
+ EXPECT_TRUE(browser->IsSame(extension_browser_));
+
+ CefRefPtr<CefExtension> extension = browser->GetHost()->GetExtension();
+ EXPECT_TRUE(extension);
+ EXPECT_TRUE(extension_->IsSame(extension));
+
+ const std::string& url = request->GetURL();
+ EXPECT_STREQ(extension_url_.c_str(), url.c_str());
+
+ EXPECT_FALSE(got_url_request_);
+ got_url_request_.yes();
+
+ // Handle the resource request.
+ return RoutingTestHandler::GetResourceHandler(browser, frame, request);
+ }
+
+ protected:
+ void OnLoadExtensions() override {
+ LoadExtension(kExtensionPath, CreateManifest());
+ }
+
+ bool OnMessage(CefRefPtr<CefBrowser> browser,
+ const std::string& message) override {
+ EXPECT_FALSE(browser->GetHost()->IsBackgroundHost());
+ EXPECT_STREQ("extension_onload", message.c_str());
+
+ CefRefPtr<CefExtension> extension = browser->GetHost()->GetExtension();
+ EXPECT_TRUE(extension);
+ EXPECT_TRUE(extension_->IsSame(extension));
+
+ EXPECT_TRUE(browser->IsSame(extension_browser_));
+
+ EXPECT_FALSE(got_body_onload_);
+ got_body_onload_.yes();
+
+ TriggerDestroyTestIfDone();
+ return true;
+ }
+
+ void OnDestroyTest() override {
+ extension_browser_ = nullptr;
+
+ EXPECT_TRUE(got_loaded_);
+ EXPECT_TRUE(got_url_request_);
+ EXPECT_TRUE(got_body_onload_);
+ EXPECT_TRUE(got_load_done_);
+ EXPECT_TRUE(got_unloaded_);
+ }
+
+ // Create the default manifest.
+ CefRefPtr<CefDictionaryValue> CreateManifest() const {
+ return CreateDefaultManifest(ApiPermissionsList());
+ }
+
+ // Verify |extension| contents.
+ void VerifyExtension(CefRefPtr<CefExtension> extension) const {
+ EXPECT_STREQ(("extensions/" + std::string(kExtensionPath)).c_str(),
+ client::extension_util::GetInternalExtensionResourcePath(
+ extension->GetPath())
+ .c_str());
+
+ CefRefPtr<CefDictionaryValue> expected_manifest = CreateManifest();
+ TestDictionaryEqual(expected_manifest, extension->GetManifest());
+
+ VerifyExtensionInContext(extension, loader_request_context(), true, true);
+ if (!request_context_same_loader()) {
+ VerifyExtensionInContext(extension, request_context(), true, false);
+ }
+ }
+
+ void CreateBrowserForExtension() {
+ const std::string& identifier = extension_->GetIdentifier();
+ EXPECT_FALSE(identifier.empty());
+ const std::string& origin =
+ client::extension_util::GetExtensionOrigin(identifier);
+ EXPECT_FALSE(origin.empty());
+
+ // Add extension resources.
+ extension_url_ = origin + "extension.html";
+ AddResource(extension_url_,
+ "<html><body onLoad=" + GetMessageJS("extension_onload") +
+ ">Extension</body></html>",
+ "text/html");
+
+ // Create a browser to host the extension.
+ CreateBrowser(extension_url_, request_context());
+ }
+
+ void TriggerDestroyTestIfDone() {
+ if (got_body_onload_ && got_load_done_) {
+ TriggerDestroyTest();
+ }
+ }
+
+ virtual void TriggerDestroyTest() {
+ // Execute asynchronously so call stacks have a chance to unwind.
+ CefPostTask(TID_UI,
+ base::BindOnce(&ViewLoadUnloadTestHandler::UnloadExtension,
+ this, extension_));
+ }
+
+ CefRefPtr<CefExtension> extension_;
+ std::string extension_url_;
+ CefRefPtr<CefBrowser> extension_browser_;
+
+ TrackCallback got_loaded_;
+ TrackCallback got_url_request_;
+ TrackCallback got_body_onload_;
+ TrackCallback got_load_done_;
+ TrackCallback got_unloaded_;
+
+ IMPLEMENT_REFCOUNTING(ViewLoadUnloadTestHandler);
+ DISALLOW_COPY_AND_ASSIGN(ViewLoadUnloadTestHandler);
+};
+
+} // namespace
+
+EXTENSION_TEST_GROUP_ALL(ViewLoadUnload, ViewLoadUnloadTestHandler)
+
+namespace {
+
+// Same as above but without the unload. Only do this with a custom context to
+// avoid poluting the global context.
+class ViewLoadNoUnloadTestHandler : public ViewLoadUnloadTestHandler {
+ public:
+ explicit ViewLoadNoUnloadTestHandler(RequestContextType request_context_type)
+ : ViewLoadUnloadTestHandler(request_context_type) {}
+
+ protected:
+ void TriggerDestroyTest() override {
+ // Release everything that references the request context. This should
+ // trigger unload of the extension.
+ CloseBrowser(extension_browser_, false);
+ extension_browser_ = nullptr;
+ ReleaseRequestContexts();
+ }
+};
+
+} // namespace
+
+EXTENSION_TEST_GROUP_MINIMAL_CUSTOM(ViewLoadNoUnload,
+ ViewLoadNoUnloadTestHandler)
diff --git a/tests/ceftests/file_util_unittest.cc b/tests/ceftests/file_util_unittest.cc
new file mode 100644
index 00000000..9a54ba4c
--- /dev/null
+++ b/tests/ceftests/file_util_unittest.cc
@@ -0,0 +1,60 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. Portions copyright
+// 2011 The Chromium Authors. All rights reserved. Use of this source code is
+// governed by a BSD-style license that can be found in the LICENSE file.
+
+#include <string>
+
+#include "include/wrapper/cef_scoped_temp_dir.h"
+#include "tests/gtest/include/gtest/gtest.h"
+#include "tests/shared/browser/file_util.h"
+
+TEST(FileUtil, JoinPath) {
+ // Should return whichever path component is non-empty.
+ EXPECT_STREQ("", client::file_util::JoinPath("", "").c_str());
+ EXPECT_STREQ("path1", client::file_util::JoinPath("path1", "").c_str());
+ EXPECT_STREQ("path2", client::file_util::JoinPath("", "path2").c_str());
+
+ const std::string& expected =
+ std::string("path1") + client::file_util::kPathSep + std::string("path2");
+
+ // Should always be 1 kPathSep character between paths.
+ EXPECT_STREQ(expected.c_str(),
+ client::file_util::JoinPath("path1", "path2").c_str());
+ EXPECT_STREQ(expected.c_str(),
+ client::file_util::JoinPath(
+ std::string("path1") + client::file_util::kPathSep, "path2")
+ .c_str());
+ EXPECT_STREQ(expected.c_str(),
+ client::file_util::JoinPath(
+ "path1", client::file_util::kPathSep + std::string("path2"))
+ .c_str());
+ EXPECT_STREQ(expected.c_str(),
+ client::file_util::JoinPath(
+ std::string("path1") + client::file_util::kPathSep,
+ client::file_util::kPathSep + std::string("path2"))
+ .c_str());
+}
+
+TEST(FileUtil, WriteAndReadFile) {
+ CefScopedTempDir dir;
+ EXPECT_TRUE(dir.CreateUniqueTempDir());
+
+ const std::string& data = "Test contents to read/write";
+ const std::string& path =
+ client::file_util::JoinPath(dir.GetPath(), "test.txt");
+
+ EXPECT_EQ(static_cast<int>(data.size()),
+ client::file_util::WriteFile(path.c_str(), data.data(),
+ static_cast<int>(data.size())));
+
+ std::string read;
+ EXPECT_TRUE(client::file_util::ReadFileToString(path.c_str(), &read));
+ EXPECT_STREQ(data.c_str(), read.c_str());
+}
+
+TEST(FileUtil, GetFileExtension) {
+ EXPECT_TRUE(client::file_util::GetFileExtension(std::string()).empty());
+ EXPECT_TRUE(client::file_util::GetFileExtension("/path/to/foo").empty());
+ EXPECT_STREQ("ext",
+ client::file_util::GetFileExtension("/path/to/foo.ext").c_str());
+}
diff --git a/tests/ceftests/frame_handler_unittest.cc b/tests/ceftests/frame_handler_unittest.cc
new file mode 100644
index 00000000..ac9a3393
--- /dev/null
+++ b/tests/ceftests/frame_handler_unittest.cc
@@ -0,0 +1,1722 @@
+// Copyright 2021 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#include <limits>
+#include <map>
+#include <memory>
+#include <queue>
+#include <sstream>
+#include <string>
+
+#include "include/base/cef_callback.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "tests/ceftests/routing_test_handler.h"
+#include "tests/ceftests/test_handler.h"
+#include "tests/ceftests/test_util.h"
+#include "tests/gtest/include/gtest/gtest.h"
+
+// Set to 1 to enable verbose debugging info logging.
+#define VERBOSE_DEBUGGING 0
+
+namespace {
+
+// Must match CefFrameHostImpl::kInvalidFrameId.
+const int kInvalidFrameId = -4;
+
+// Tracks callback status for a single frame object.
+struct FrameStatus {
+ // Callbacks in expected order. Not all callbacks are executed in all cases
+ // (see IsExpectedCallback).
+ enum CallbackType {
+ FRAME_CREATED,
+ MAIN_FRAME_INITIAL_ASSIGNED,
+ AFTER_CREATED,
+ FRAME_ATTACHED,
+ MAIN_FRAME_CHANGED_ASSIGNED,
+ LOAD_START,
+ LOAD_END,
+ BEFORE_CLOSE,
+ FRAME_DETACHED,
+ MAIN_FRAME_CHANGED_REMOVED,
+ MAIN_FRAME_FINAL_REMOVED,
+
+ CALLBACK_LAST = MAIN_FRAME_FINAL_REMOVED,
+ };
+
+ static const char* GetCallbackName(int type) {
+ switch (type) {
+ case FRAME_CREATED:
+ return "OnFrameCreated";
+ case MAIN_FRAME_INITIAL_ASSIGNED:
+ return "OnMainFrameChanged(initial_assigned)";
+ case AFTER_CREATED:
+ return "OnAfterCreated";
+ case FRAME_ATTACHED:
+ return "OnFrameAttached";
+ case MAIN_FRAME_CHANGED_ASSIGNED:
+ return "OnMainFrameChanged(changed_assigned)";
+ case LOAD_START:
+ return "OnLoadStart";
+ case LOAD_END:
+ return "OnLoadEnd";
+ case BEFORE_CLOSE:
+ return "OnBeforeClose";
+ case FRAME_DETACHED:
+ return "OnFrameDetached";
+ case MAIN_FRAME_CHANGED_REMOVED:
+ return "OnMainFrameChanged(changed_removed)";
+ case MAIN_FRAME_FINAL_REMOVED:
+ return "OnMainFrameChanged(final_removed)";
+ }
+ NOTREACHED();
+ return "Unknown";
+ }
+
+ // Returns true for callbacks that should only execute for main frames.
+ static bool IsMainFrameOnlyCallback(int type) {
+ return (type == MAIN_FRAME_INITIAL_ASSIGNED || type == AFTER_CREATED ||
+ type == MAIN_FRAME_CHANGED_ASSIGNED || type == BEFORE_CLOSE ||
+ type == MAIN_FRAME_CHANGED_REMOVED ||
+ type == MAIN_FRAME_FINAL_REMOVED);
+ }
+
+ static std::string GetFrameDebugString(CefRefPtr<CefFrame> frame) {
+ // Match the logic in frame_util::GetFrameDebugString.
+ // Specific formulation of the frame ID is an implementation detail that
+ // should generally not be relied upon, but this decomposed format makes the
+ // debug logging easier to follow.
+ uint64 frame_id = frame->GetIdentifier();
+ uint32_t process_id = frame_id >> 32;
+ uint32_t routing_id = std::numeric_limits<uint32_t>::max() & frame_id;
+ std::stringstream ss;
+ ss << (frame->IsMain() ? "main" : " sub") << "[" << process_id << ","
+ << routing_id << "]";
+ return ss.str();
+ }
+
+ FrameStatus(CefRefPtr<CefFrame> frame)
+ : frame_id_(frame->GetIdentifier()),
+ is_main_(frame->IsMain()),
+ ident_str_(GetFrameDebugString(frame)) {}
+
+ int64 frame_id() const { return frame_id_; }
+ bool is_main() const { return is_main_; }
+
+ bool AllQueriesDelivered(std::string* msg = nullptr) const {
+ EXPECT_UI_THREAD();
+ const int expected_ct = is_temporary_ ? 0 : expected_query_ct_;
+#if VERBOSE_DEBUGGING
+ if (msg) {
+ std::stringstream ss;
+ ss << ident_str_ << "(expected=" << expected_ct
+ << " delivered=" << delivered_query_ct_ << ")";
+ *msg += ss.str();
+ }
+#endif
+ return delivered_query_ct_ == expected_ct;
+ }
+ int QueriesDeliveredCount() const {
+ EXPECT_UI_THREAD();
+ return delivered_query_ct_;
+ }
+
+ bool IsSame(CefRefPtr<CefFrame> frame) const {
+ return frame->GetIdentifier() == frame_id();
+ }
+
+ bool IsLoaded(std::string* msg = nullptr) const {
+#if VERBOSE_DEBUGGING
+ if (msg) {
+ std::stringstream ss;
+ ss << ident_str_ << "(";
+ for (int i = 0; i <= LOAD_END; ++i) {
+ ss << GetCallbackName(i) << "=" << got_callback_[i];
+ if (i < LOAD_END) {
+ ss << " ";
+ }
+ }
+ ss << ")";
+ *msg += ss.str();
+ }
+#endif
+ return got_callback_[LOAD_END];
+ }
+ bool IsDetached() const { return got_callback_[FRAME_DETACHED]; }
+
+ void SetIsFirstMain(bool val) {
+ EXPECT_TRUE(is_main_);
+ is_first_main_ = val;
+ if (is_first_main_) {
+ // Also expect OnAfterCreated
+ expected_query_ct_++;
+ }
+ }
+ void SetIsLastMain(bool val) {
+ EXPECT_TRUE(is_main_);
+ is_last_main_ = val;
+ }
+
+ void SetIsTemporary(bool val) {
+ EXPECT_FALSE(is_main_);
+ is_temporary_ = val;
+ }
+ bool IsTemporary() const { return is_temporary_; }
+
+ void SetAdditionalDebugInfo(const std::string& debug_info) {
+ debug_info_ = debug_info;
+ }
+
+ std::string GetDebugString() const { return debug_info_ + ident_str_; }
+
+ // The main frame will be reused for same-origin navigations.
+ void ResetMainLoadStatus() {
+ EXPECT_TRUE(is_main_);
+
+ ResetCallbackStatus(LOAD_START, /*expect_query=*/true);
+ ResetCallbackStatus(LOAD_END, /*expect_query=*/true);
+ }
+
+ void OnFrameCreated(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) {
+ EXPECT_UI_THREAD();
+ VerifyBrowser(__FUNCTION__, browser);
+ VerifyFrame(__FUNCTION__, frame);
+
+ GotCallback(__FUNCTION__, FRAME_CREATED);
+
+ // Test delivery of messages using a frame that isn't connected yet.
+ // This tests queuing of messages in the browser process and possibly the
+ // renderer process.
+ ExecuteQuery(frame, FRAME_CREATED);
+ }
+
+ void OnFrameAttached(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) {
+ EXPECT_UI_THREAD();
+ VerifyBrowser(__FUNCTION__, browser);
+ VerifyFrame(__FUNCTION__, frame);
+
+ GotCallback(__FUNCTION__, FRAME_ATTACHED);
+
+ // Test delivery of messages using a frame that just connected.
+ // This tests queuing of messages in the browser process and possibly the
+ // renderer process.
+ ExecuteQuery(frame, FRAME_ATTACHED);
+ }
+
+ void OnFrameDetached(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) {
+ EXPECT_UI_THREAD();
+ VerifyBrowser(__FUNCTION__, browser);
+ // A frame is never valid after it's detached.
+ VerifyFrame(__FUNCTION__, frame, /*expect_valid=*/false);
+
+ GotCallback(__FUNCTION__, FRAME_DETACHED);
+ }
+
+ void OnMainFrameChanged(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> old_frame,
+ CefRefPtr<CefFrame> new_frame) {
+ EXPECT_UI_THREAD();
+ EXPECT_TRUE(is_main_);
+ VerifyBrowser(__FUNCTION__, browser);
+
+ bool got_match = false;
+
+ if (old_frame && new_frame) {
+ EXPECT_NE(old_frame->GetIdentifier(), new_frame->GetIdentifier());
+ }
+
+ if (old_frame && IsSame(old_frame)) {
+ got_match = true;
+ // A frame is never valid after it's detached.
+ VerifyFrame(__FUNCTION__, old_frame, /*expect_valid=*/false);
+ GotCallback(__FUNCTION__, new_frame ? MAIN_FRAME_CHANGED_REMOVED
+ : MAIN_FRAME_FINAL_REMOVED);
+ if (is_last_main_) {
+ EXPECT_FALSE(new_frame);
+ }
+ }
+
+ if (new_frame && IsSame(new_frame)) {
+ got_match = true;
+ VerifyFrame(__FUNCTION__, new_frame);
+ GotCallback(__FUNCTION__, old_frame ? MAIN_FRAME_CHANGED_ASSIGNED
+ : MAIN_FRAME_INITIAL_ASSIGNED);
+ if (is_first_main_) {
+ EXPECT_FALSE(old_frame);
+ }
+ }
+
+ EXPECT_TRUE(got_match);
+ }
+
+ void OnAfterCreated(CefRefPtr<CefBrowser> browser) {
+ EXPECT_UI_THREAD();
+ VerifyBrowser(__FUNCTION__, browser);
+
+ auto frame = browser->GetMainFrame();
+ VerifyFrame(__FUNCTION__, frame);
+
+ GotCallback(__FUNCTION__, AFTER_CREATED);
+ ExecuteQuery(frame, AFTER_CREATED);
+ }
+
+ // Called for all existing frames, not just the target frame.
+ // We need to track this status to know if the browser should be valid in
+ // following calls to OnFrameDetached.
+ void OnBeforeClose(CefRefPtr<CefBrowser> browser) {
+ EXPECT_UI_THREAD();
+ VerifyBrowser(__FUNCTION__, browser);
+
+ auto frame = browser->GetMainFrame();
+ EXPECT_TRUE(frame->IsValid());
+
+ got_before_close_ = true;
+ if (IsSame(frame)) {
+ VerifyFrame(__FUNCTION__, frame);
+ GotCallback(__FUNCTION__, BEFORE_CLOSE);
+ }
+ }
+
+ void OnLoadStart(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame) {
+ EXPECT_UI_THREAD();
+ VerifyBrowser(__FUNCTION__, browser);
+ VerifyFrame(__FUNCTION__, frame);
+
+ GotCallback(__FUNCTION__, LOAD_START);
+ ExecuteQuery(frame, LOAD_START);
+ }
+
+ void OnLoadEnd(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame) {
+ EXPECT_UI_THREAD();
+ VerifyBrowser(__FUNCTION__, browser);
+ VerifyFrame(__FUNCTION__, frame);
+
+ GotCallback(__FUNCTION__, LOAD_END);
+ ExecuteQuery(frame, LOAD_END);
+ }
+
+ void OnQuery(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const CefString& request) {
+ EXPECT_UI_THREAD();
+
+ const std::string& received_query = request;
+
+#if VERBOSE_DEBUGGING
+ LOG(INFO) << GetDebugString() << " recv query " << received_query << " ("
+ << (delivered_query_ct_ + 1) << " of " << expected_query_ct_
+ << ")";
+#endif
+
+ VerifyBrowser(__FUNCTION__, browser);
+ VerifyFrame(__FUNCTION__, frame);
+
+ EXPECT_GE(pending_queries_.size(), 1U);
+ const std::string& expected_query = pending_queries_.front();
+ EXPECT_STREQ(expected_query.c_str(), received_query.c_str());
+ if (expected_query == received_query) {
+ pending_queries_.pop();
+ }
+
+ EXPECT_LT(delivered_query_ct_, expected_query_ct_);
+ delivered_query_ct_++;
+ }
+
+ void VerifyTestResults() {
+ EXPECT_UI_THREAD();
+
+ // Verify that all expected callbacks have executed.
+ VerifyCallbackStatus(__FUNCTION__, CALLBACK_LAST + 1);
+
+ if (is_temporary_) {
+ // Should not receive any queries.
+ EXPECT_FALSE(is_main_);
+ EXPECT_EQ(0, delivered_query_ct_);
+ } else {
+ // Verify that all expected messages have been sent and received.
+ EXPECT_EQ(expected_query_ct_, delivered_query_ct_);
+ EXPECT_EQ(0U, pending_queries_.size());
+ while (!pending_queries_.empty()) {
+ ADD_FAILURE() << "Query sent but not received: "
+ << pending_queries_.front();
+ pending_queries_.pop();
+ }
+ }
+ }
+
+ bool DidGetCallback(int callback) const { return got_callback_[callback]; }
+
+ private:
+ void GotCallback(const std::string& func, int callback) {
+#if VERBOSE_DEBUGGING
+ LOG(INFO) << GetDebugString() << " callback " << GetCallbackName(callback);
+#endif
+
+ EXPECT_TRUE(IsExpectedCallback(callback)) << func;
+ VerifyCallbackStatus(func, callback);
+ got_callback_[callback].yes();
+ }
+
+ bool IsExpectedCallback(int callback) const {
+ if (!is_main_ && IsMainFrameOnlyCallback(callback)) {
+ return false;
+ }
+
+ if (is_main_) {
+ if ((callback == MAIN_FRAME_INITIAL_ASSIGNED ||
+ callback == AFTER_CREATED) &&
+ !is_first_main_) {
+ return false;
+ }
+ if ((callback == BEFORE_CLOSE || callback == MAIN_FRAME_FINAL_REMOVED) &&
+ !is_last_main_) {
+ return false;
+ }
+ if (callback == MAIN_FRAME_CHANGED_ASSIGNED && is_first_main_) {
+ return false;
+ }
+ if (callback == MAIN_FRAME_CHANGED_REMOVED && is_last_main_) {
+ return false;
+ }
+ } else if (is_temporary_) {
+ // For cross-process sub-frame navigation a sub-frame is first created in
+ // the parent's renderer process. That sub-frame is then discarded after
+ // the real cross-origin sub-frame is created in a different renderer
+ // process. These discarded sub-frames will get OnFrameCreated/
+ // OnFrameAttached immediately followed by OnFrameDetached.
+ return callback == FRAME_CREATED || callback == FRAME_ATTACHED ||
+ callback == FRAME_DETACHED;
+ }
+
+ return true;
+ }
+
+ void VerifyCallbackStatus(const std::string& func,
+ int current_callback) const {
+ EXPECT_UI_THREAD();
+
+ for (int i = 0; i <= CALLBACK_LAST; ++i) {
+ if (i < current_callback && IsExpectedCallback(i)) {
+ EXPECT_TRUE(got_callback_[i])
+ << "inside " << func << " should already have gotten "
+ << GetCallbackName(i);
+ } else {
+ EXPECT_FALSE(got_callback_[i])
+ << "inside " << func << " should not already have gotten "
+ << GetCallbackName(i);
+ }
+ }
+ }
+
+ void VerifyBrowser(const std::string& func,
+ CefRefPtr<CefBrowser> browser) const {
+ const bool expect_valid = !got_before_close_;
+ if (expect_valid) {
+ EXPECT_TRUE(browser->IsValid()) << func;
+ } else {
+ EXPECT_FALSE(browser->IsValid()) << func;
+ }
+
+ // Note that this might not be the same main frame as us when navigating
+ // cross-origin, because the new main frame object is assigned to the
+ // browser before the CefFrameHandler callbacks related to main frame change
+ // have executed. This started out as an implementation detail but it fits
+ // nicely with the concept that "GetMainFrame() always returns a frame that
+ // can be used", which wouldn't be the case if we returned the old frame
+ // when calling GetMainFrame() from inside OnFrameCreated (for the new
+ // frame), OnFrameDetached (for the old frame) or OnMainFrameChanged.
+ auto main_frame = browser->GetMainFrame();
+ if (expect_valid) {
+ EXPECT_TRUE(main_frame) << func;
+ EXPECT_TRUE(main_frame->IsValid()) << func;
+ EXPECT_TRUE(main_frame->IsMain()) << func;
+ } else {
+ // GetMainFrame() returns nullptr after OnBeforeClose.
+ EXPECT_FALSE(main_frame) << func;
+ }
+ }
+
+ void VerifyFrame(const std::string& func,
+ CefRefPtr<CefFrame> frame,
+ bool expect_valid = true) const {
+ if (expect_valid) {
+ EXPECT_TRUE(frame->IsValid()) << func;
+ } else {
+ EXPECT_FALSE(frame->IsValid()) << func;
+ }
+
+ // |frame| should be us. This checks the frame type and ID.
+ EXPECT_STREQ(ident_str_.c_str(), GetFrameDebugString(frame).c_str())
+ << func;
+ }
+
+ void ExecuteQuery(CefRefPtr<CefFrame> frame, int callback) {
+ EXPECT_UI_THREAD();
+ const std::string& value = GetCallbackName(callback);
+
+ std::string js_string;
+
+#if VERBOSE_DEBUGGING
+ LOG(INFO) << GetDebugString() << " sent query " << value;
+ js_string +=
+ "console.log('" + GetDebugString() + " exec query " + value + "');";
+#endif
+
+ js_string += "window.testQuery({request:'" + value + "'});";
+
+ pending_queries_.push(value);
+
+ // GetURL() will return an empty string for early callbacks, but that
+ // doesn't appear to cause any issues.
+ frame->ExecuteJavaScript(js_string, frame->GetURL(), 0);
+ }
+
+ // Reset state so we can get the same callback again.
+ void ResetCallbackStatus(int callback, bool expect_query) {
+ EXPECT_UI_THREAD();
+
+ EXPECT_TRUE(got_callback_[callback]) << GetCallbackName(callback);
+ got_callback_[callback].reset();
+
+ if (expect_query) {
+ delivered_query_ct_--;
+ }
+ }
+
+ const int64 frame_id_;
+ const bool is_main_;
+ const std::string ident_str_;
+
+ bool is_first_main_ = false;
+ bool is_last_main_ = false;
+ bool is_temporary_ = false;
+ std::string debug_info_;
+
+ bool got_before_close_ = false;
+
+ TrackCallback got_callback_[CALLBACK_LAST + 1];
+
+ std::queue<std::string> pending_queries_;
+
+ // Expect OnCreated, OnAttached, OnLoadStart, OnLoadEnd.
+ int expected_query_ct_ = 4;
+ int delivered_query_ct_ = 0;
+};
+
+const char kOrderMainUrl[] = "http://tests-frame-handler/main-order.html";
+
+class OrderMainTestHandler : public RoutingTestHandler, public CefFrameHandler {
+ public:
+ OrderMainTestHandler(CompletionState* completion_state = nullptr)
+ : RoutingTestHandler(completion_state) {}
+
+ CefRefPtr<CefFrameHandler> GetFrameHandler() override {
+ get_frame_handler_ct_++;
+ return this;
+ }
+
+ void RunTest() override {
+ // Add the main resource that we will navigate to/from.
+ AddResource(GetMainURL(), GetMainHtml(), "text/html");
+
+ // Create the browser.
+ CreateBrowser(GetMainURL());
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout();
+ }
+
+ void OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
+ EXPECT_UI_THREAD();
+ RoutingTestHandler::OnAfterCreated(browser);
+
+ EXPECT_FALSE(got_after_created_);
+ got_after_created_ = true;
+
+ EXPECT_TRUE(current_main_frame_);
+ current_main_frame_->OnAfterCreated(browser);
+ }
+
+ void OnLoadStart(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ TransitionType transition_type) override {
+ EXPECT_UI_THREAD();
+ RoutingTestHandler::OnLoadStart(browser, frame, transition_type);
+
+ EXPECT_TRUE(current_main_frame_);
+ current_main_frame_->OnLoadStart(browser, frame);
+ }
+
+ void OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int httpStatusCode) override {
+ EXPECT_UI_THREAD();
+ RoutingTestHandler::OnLoadEnd(browser, frame, httpStatusCode);
+
+ EXPECT_TRUE(current_main_frame_);
+ current_main_frame_->OnLoadEnd(browser, frame);
+
+ MaybeDestroyTest();
+ }
+
+ void OnBeforeClose(CefRefPtr<CefBrowser> browser) override {
+ EXPECT_UI_THREAD();
+
+ EXPECT_FALSE(got_before_close_);
+ got_before_close_ = true;
+
+ EXPECT_TRUE(current_main_frame_);
+ current_main_frame_->OnBeforeClose(browser);
+
+ RoutingTestHandler::OnBeforeClose(browser);
+ }
+
+ bool OnQuery(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int64 query_id,
+ const CefString& request,
+ bool persistent,
+ CefRefPtr<Callback> callback) override {
+ EXPECT_UI_THREAD();
+
+ // Messages for the old and new frames are interleaved during cross-origin
+ // navigation.
+ if (pending_main_frame_) {
+ EXPECT_TRUE(IsCrossOriginOrSameSiteBFCacheEnabled());
+ pending_main_frame_->OnQuery(browser, frame, request);
+ } else {
+ EXPECT_TRUE(current_main_frame_);
+ current_main_frame_->OnQuery(browser, frame, request);
+ }
+
+ MaybeDestroyTest();
+ return true;
+ }
+
+ void OnFrameCreated(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) override {
+ EXPECT_UI_THREAD();
+
+ EXPECT_TRUE(frame->IsMain());
+ EXPECT_FALSE(pending_main_frame_);
+
+ // First callback referencing the new frame.
+ pending_main_frame_ = new FrameStatus(frame);
+ pending_main_frame_->SetAdditionalDebugInfo(GetAdditionalDebugInfo());
+ pending_main_frame_->SetIsFirstMain(!got_after_created_);
+ pending_main_frame_->SetIsLastMain(
+ !IsCrossOriginOrSameSiteBFCacheEnabled() || IsLastNavigation());
+ pending_main_frame_->OnFrameCreated(browser, frame);
+ }
+
+ void OnFrameAttached(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ bool reattached) override {
+ EXPECT_UI_THREAD();
+
+ // May arrive before or after OnMainFrameChanged switches the frame (after
+ // on initial browser creation, before on cross-origin navigation).
+ if (pending_main_frame_) {
+ EXPECT_TRUE(IsCrossOriginOrSameSiteBFCacheEnabled());
+ pending_main_frame_->OnFrameAttached(browser, frame);
+ } else {
+ EXPECT_TRUE(current_main_frame_);
+ current_main_frame_->OnFrameAttached(browser, frame);
+ }
+ }
+
+ void OnFrameDetached(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) override {
+ EXPECT_UI_THREAD();
+ EXPECT_TRUE(current_main_frame_);
+ current_main_frame_->OnFrameDetached(browser, frame);
+ }
+
+ void OnMainFrameChanged(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> old_frame,
+ CefRefPtr<CefFrame> new_frame) override {
+ EXPECT_UI_THREAD();
+ EXPECT_TRUE(old_frame || new_frame);
+ if (old_frame) {
+ EXPECT_FALSE(old_frame->IsValid());
+ EXPECT_TRUE(old_frame->IsMain());
+
+ // May be nullptr with PopupOrderMainTestHandler.
+ if (current_main_frame_) {
+ // Last callback referencing the old frame.
+ EXPECT_TRUE(current_main_frame_);
+ current_main_frame_->OnMainFrameChanged(browser, old_frame, new_frame);
+ current_main_frame_->VerifyTestResults();
+ delete current_main_frame_;
+ current_main_frame_ = nullptr;
+ }
+ }
+ if (new_frame) {
+ EXPECT_TRUE(new_frame->IsValid());
+ EXPECT_TRUE(new_frame->IsMain());
+
+ // Always called after OnFrameCreated. See also comments in
+ // OnFrameAttached.
+ EXPECT_TRUE(pending_main_frame_);
+ pending_main_frame_->OnMainFrameChanged(browser, old_frame, new_frame);
+
+ // The pending frame becomes the current frame.
+ EXPECT_FALSE(current_main_frame_);
+ current_main_frame_ = pending_main_frame_;
+ pending_main_frame_ = nullptr;
+ }
+
+ if (old_frame && new_frame) {
+ // Main frame changed due to cross-origin navigation.
+ EXPECT_TRUE(IsCrossOriginOrSameSiteBFCacheEnabled());
+ main_frame_changed_ct_++;
+ }
+
+ if (old_frame && !new_frame) {
+ // Very last callback.
+ VerifyTestResults();
+ }
+ }
+
+ protected:
+ virtual std::string GetMainURL() const { return kOrderMainUrl; }
+
+ virtual std::string GetMainHtml() const {
+ return "<html><body>TEST</body></html>";
+ }
+
+ virtual std::string GetNextMainURL() { return std::string(); }
+ virtual bool IsFirstNavigation() const { return true; }
+ virtual bool IsLastNavigation() const { return true; }
+ virtual bool IsCrossOrigin() const { return false; }
+
+ bool IsCrossOriginOrSameSiteBFCacheEnabled() const {
+ return IsCrossOrigin() || IsSameSiteBFCacheEnabled();
+ }
+
+ virtual std::string GetAdditionalDebugInfo() const { return std::string(); }
+
+ virtual bool AllQueriesDelivered(std::string* msg = nullptr) const {
+ EXPECT_UI_THREAD();
+ if (pending_main_frame_) {
+ return false;
+ }
+ return current_main_frame_->AllQueriesDelivered(msg);
+ }
+
+ virtual bool AllFramesLoaded(std::string* msg = nullptr) const {
+ EXPECT_UI_THREAD();
+ if (pending_main_frame_) {
+ return false;
+ }
+ return current_main_frame_->IsLoaded(msg);
+ }
+
+ void MaybeDestroyTest() {
+#if VERBOSE_DEBUGGING
+ std::string delivered_msg, loaded_msg;
+ const bool all_queries_delivered = AllQueriesDelivered(&delivered_msg);
+ const bool all_frames_loaded = AllFramesLoaded(&loaded_msg);
+ LOG(INFO) << (current_main_frame_ ? current_main_frame_->GetDebugString()
+ : "")
+ << " AllQueriesDelivered=" << all_queries_delivered << " {"
+ << delivered_msg << "}"
+ << " AllFramesLoaded=" << all_frames_loaded << " {" << loaded_msg
+ << "}";
+ if (all_queries_delivered && all_frames_loaded) {
+#else
+ if (AllQueriesDelivered() && AllFramesLoaded()) {
+#endif
+ const std::string& next_url = GetNextMainURL();
+ if (!next_url.empty()) {
+ if (!IsCrossOriginOrSameSiteBFCacheEnabled()) {
+ // Reusing the same main frame for same origin nav.
+ current_main_frame_->ResetMainLoadStatus();
+ }
+
+#if VERBOSE_DEBUGGING
+ LOG(INFO) << current_main_frame_->GetDebugString()
+ << "--> Navigating to " << next_url;
+#endif
+ GetBrowser()->GetMainFrame()->LoadURL(next_url);
+ } else {
+#if VERBOSE_DEBUGGING
+ LOG(INFO) << "--> Destroy test";
+#endif
+ DestroyTest();
+ }
+ }
+ }
+
+ virtual void VerifyTestResults() {
+ EXPECT_UI_THREAD();
+
+ // OnMainFrameChanged should have cleaned up.
+ EXPECT_FALSE(pending_main_frame_);
+ EXPECT_FALSE(current_main_frame_);
+
+ EXPECT_TRUE(got_after_created_);
+ EXPECT_TRUE(got_before_close_);
+
+ // We document GetFrameHandler() as only being called a single time.
+ EXPECT_EQ(1, get_frame_handler_ct_);
+
+ // Make sure we get the expected number OnMainFrameChanged callbacks for the
+ // main frame.
+ EXPECT_EQ(expected_main_frame_changed_ct_, main_frame_changed_ct_);
+ }
+
+ // Number of times we expect the main frame to change (e.g. once per
+ // cross-origin navigation).
+ int expected_main_frame_changed_ct_ = 0;
+
+ bool got_after_created_ = false;
+ bool got_before_close_ = false;
+
+ private:
+ int get_frame_handler_ct_ = 0;
+ int main_frame_changed_ct_ = 0;
+
+ FrameStatus* current_main_frame_ = nullptr;
+ FrameStatus* pending_main_frame_ = nullptr;
+
+ IMPLEMENT_REFCOUNTING(OrderMainTestHandler);
+};
+
+} // namespace
+
+// Test the ordering and behavior of main frame callbacks.
+TEST(FrameHandlerTest, OrderMain) {
+ CefRefPtr<OrderMainTestHandler> handler = new OrderMainTestHandler();
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+namespace {
+
+const char kOrderMainUrlPrefix[] = "http://tests-frame-handler";
+
+class NavigateOrderMainTestHandler : public OrderMainTestHandler {
+ public:
+ NavigateOrderMainTestHandler(bool cross_origin, int additional_nav_ct = 2)
+ : cross_origin_(cross_origin), additional_nav_ct_(additional_nav_ct) {}
+
+ void RunTest() override {
+ // Once for each cross-origin LoadURL call.
+ expected_main_frame_changed_ct_ =
+ IsCrossOriginOrSameSiteBFCacheEnabled() ? additional_nav_ct_ : 0;
+
+ // Resources for the 2nd+ navigation.
+ for (int i = 1; i <= additional_nav_ct_; i++) {
+ AddResource(GetURLForNav(i), GetMainHtmlForNav(i), "text/html");
+ }
+
+ OrderMainTestHandler::RunTest();
+ }
+
+ protected:
+ // Loaded when the browser is created.
+ std::string GetMainURL() const override { return GetURLForNav(0); }
+ std::string GetMainHtml() const override { return GetMainHtmlForNav(0); }
+
+ std::string GetNextMainURL() override {
+ if (current_nav_ct_ == additional_nav_ct_) {
+ // No more navigations.
+ return std::string();
+ }
+ return GetURLForNav(++current_nav_ct_);
+ }
+
+ bool IsFirstNavigation() const override { return current_nav_ct_ == 0U; }
+ bool IsLastNavigation() const override {
+ return current_nav_ct_ == additional_nav_ct_;
+ }
+ bool IsCrossOrigin() const override { return cross_origin_; }
+ int additional_nav_ct() const { return additional_nav_ct_; }
+
+ void VerifyTestResults() override {
+ OrderMainTestHandler::VerifyTestResults();
+ EXPECT_TRUE(IsLastNavigation());
+ }
+
+ virtual std::string GetMainHtmlForNav(int nav) const {
+ return "<html><body>TEST " + std::to_string(nav) + "</body></html>";
+ }
+
+ std::string GetURLForNav(int nav, const std::string& suffix = "") const {
+ std::stringstream ss;
+ if (cross_origin_) {
+ ss << kOrderMainUrlPrefix << nav << "/cross-origin" << suffix << ".html";
+ } else {
+ ss << kOrderMainUrlPrefix << "/" << nav << "same-origin" << suffix
+ << ".html";
+ }
+ return ss.str();
+ }
+
+ private:
+ const bool cross_origin_;
+ const int additional_nav_ct_;
+
+ int current_nav_ct_ = 0;
+};
+
+} // namespace
+
+// Main frame navigating to different URLs with the same origin.
+TEST(FrameHandlerTest, OrderMainNavSameOrigin) {
+ CefRefPtr<NavigateOrderMainTestHandler> handler =
+ new NavigateOrderMainTestHandler(/*cross_origin=*/false);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Main frame navigating cross-origin.
+TEST(FrameHandlerTest, OrderMainNavCrossOrigin) {
+ CefRefPtr<NavigateOrderMainTestHandler> handler =
+ new NavigateOrderMainTestHandler(/*cross_origin=*/true);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+namespace {
+
+// Tracks sub-frames for a single main frame load.
+class FrameStatusMap {
+ public:
+ explicit FrameStatusMap(size_t expected_frame_ct)
+ : expected_frame_ct_(expected_frame_ct) {}
+ ~FrameStatusMap() { EXPECT_TRUE(frame_map_.empty()); }
+
+ bool Contains(CefRefPtr<CefFrame> frame) const {
+ return frame_map_.find(frame->GetIdentifier()) != frame_map_.end();
+ }
+
+ FrameStatus* CreateFrameStatus(CefRefPtr<CefFrame> frame) {
+ EXPECT_UI_THREAD();
+
+ EXPECT_LT(size(), expected_frame_ct_);
+
+ const int64 id = frame->GetIdentifier();
+ EXPECT_NE(kInvalidFrameId, id);
+ EXPECT_EQ(frame_map_.find(id), frame_map_.end());
+
+ FrameStatus* status = new FrameStatus(frame);
+ frame_map_.insert(std::make_pair(id, status));
+ return status;
+ }
+
+ FrameStatus* GetFrameStatus(CefRefPtr<CefFrame> frame) const {
+ EXPECT_UI_THREAD();
+
+ const int64 id = frame->GetIdentifier();
+ EXPECT_NE(kInvalidFrameId, id);
+ Map::const_iterator it = frame_map_.find(id);
+ EXPECT_NE(it, frame_map_.end());
+ return it->second;
+ }
+
+ void RemoveFrameStatus(CefRefPtr<CefFrame> frame) {
+ const int64 id = frame->GetIdentifier();
+ Map::iterator it = frame_map_.find(id);
+ EXPECT_NE(it, frame_map_.end());
+ frame_map_.erase(it);
+ }
+
+ void OnBeforeClose(CefRefPtr<CefBrowser> browser) {
+ Map::const_iterator it = frame_map_.begin();
+ for (; it != frame_map_.end(); ++it) {
+ it->second->OnBeforeClose(browser);
+ }
+ }
+
+ bool AllQueriesDelivered(std::string* msg = nullptr) const {
+ if (size() != expected_frame_ct_) {
+#if VERBOSE_DEBUGGING
+ if (msg) {
+ std::stringstream ss;
+ ss << " SUB COUNT MISMATCH! size=" << size()
+ << " expected=" << expected_frame_ct_;
+ *msg += ss.str();
+ }
+#endif
+ return false;
+ }
+
+ Map::const_iterator it = frame_map_.begin();
+ for (; it != frame_map_.end(); ++it) {
+ if (!it->second->AllQueriesDelivered(msg)) {
+#if VERBOSE_DEBUGGING
+ if (msg) {
+ *msg += " " + it->second->GetDebugString() + " PENDING";
+ }
+#endif
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ bool AllFramesLoaded(std::string* msg = nullptr) const {
+ if (size() != expected_frame_ct_) {
+#if VERBOSE_DEBUGGING
+ if (msg) {
+ std::stringstream ss;
+ ss << " SUB COUNT MISMATCH! size=" << size()
+ << " expected=" << expected_frame_ct_;
+ *msg += ss.str();
+ }
+#endif
+ return false;
+ }
+
+ Map::const_iterator it = frame_map_.begin();
+ for (; it != frame_map_.end(); ++it) {
+ if (!it->second->IsTemporary() && !it->second->IsLoaded(msg)) {
+#if VERBOSE_DEBUGGING
+ if (msg) {
+ *msg += " " + it->second->GetDebugString() + " PENDING";
+ }
+#endif
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ bool AllFramesDetached() const {
+ if (size() != expected_frame_ct_) {
+ return false;
+ }
+
+ Map::const_iterator it = frame_map_.begin();
+ for (; it != frame_map_.end(); ++it) {
+ if (!it->second->IsDetached()) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ void VerifyAndClearTestResults() {
+ EXPECT_EQ(expected_frame_ct_, size());
+ Map::const_iterator it = frame_map_.begin();
+ for (; it != frame_map_.end(); ++it) {
+ it->second->VerifyTestResults();
+ delete it->second;
+ }
+ frame_map_.clear();
+ }
+
+ size_t size() const { return frame_map_.size(); }
+
+ private:
+ using Map = std::map<int64, FrameStatus*>;
+ Map frame_map_;
+
+ // The expected number of sub-frames.
+ const size_t expected_frame_ct_;
+};
+
+class OrderSubTestHandler : public NavigateOrderMainTestHandler {
+ public:
+ enum TestMode {
+ // Two sub-frames at the same level.
+ SUBFRAME_PEERS,
+
+ // One sub-frame inside the other.
+ SUBFRAME_CHILDREN,
+ };
+
+ OrderSubTestHandler(bool cross_origin,
+ int additional_nav_ct,
+ TestMode mode,
+ size_t expected_frame_ct = 2U)
+ : NavigateOrderMainTestHandler(cross_origin, additional_nav_ct),
+ test_mode_(mode),
+ expected_frame_ct_(expected_frame_ct) {}
+ ~OrderSubTestHandler() override { EXPECT_TRUE(frame_maps_.empty()); }
+
+ void RunTest() override {
+ for (int i = 0; i <= additional_nav_ct(); i++) {
+ AddResource(GetSubURL1ForNav(i), GetSubFrameHtml1ForNav(i), "text/html");
+ AddResource(GetSubURL2ForNav(i), GetSubFrameHtml2ForNav(i), "text/html");
+ }
+
+ NavigateOrderMainTestHandler::RunTest();
+ }
+
+ void OnBeforeClose(CefRefPtr<CefBrowser> browser) override {
+ NavigateOrderMainTestHandler::OnBeforeClose(browser);
+
+ for (auto& map : frame_maps_) {
+ // Also need to notify any sub-frames.
+ map->OnBeforeClose(browser);
+ }
+ }
+
+ bool OnQuery(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int64 query_id,
+ const CefString& request,
+ bool persistent,
+ CefRefPtr<Callback> callback) override {
+ if (!frame->IsMain()) {
+ auto map = GetFrameMap(frame);
+ auto status = map->GetFrameStatus(frame);
+ status->OnQuery(browser, frame, request);
+ if (status->AllQueriesDelivered()) {
+ MaybeDestroyTest();
+ }
+ return true;
+ }
+
+ return NavigateOrderMainTestHandler::OnQuery(browser, frame, query_id,
+ request, persistent, callback);
+ }
+
+ void OnFrameCreated(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) override {
+ if (!frame->IsMain()) {
+ // Potentially the first notification of a new sub-frame after navigation.
+ auto map = GetOrCreateFrameMap(frame);
+ auto status = map->CreateFrameStatus(frame);
+ status->SetAdditionalDebugInfo(GetAdditionalDebugInfo());
+ status->OnFrameCreated(browser, frame);
+ return;
+ }
+
+ NavigateOrderMainTestHandler::OnFrameCreated(browser, frame);
+ }
+
+ void OnFrameAttached(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ bool reattached) override {
+ if (!frame->IsMain()) {
+ auto map = GetFrameMap(frame);
+ auto status = map->GetFrameStatus(frame);
+ status->OnFrameAttached(browser, frame);
+ return;
+ }
+
+ NavigateOrderMainTestHandler::OnFrameAttached(browser, frame, reattached);
+ }
+
+ void OnFrameDetached(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) override {
+ if (!frame->IsMain()) {
+ // Potentially the last notification for an old sub-frame after
+ // navigation.
+ auto map = GetFrameMap(frame);
+ auto status = map->GetFrameStatus(frame);
+ status->OnFrameDetached(browser, frame);
+
+ if (map->AllFramesDetached()) {
+ // Verify results from the previous navigation.
+ VerifyAndClearSubFrameTestResults(map);
+ }
+ return;
+ }
+
+ NavigateOrderMainTestHandler::OnFrameDetached(browser, frame);
+ }
+
+ void OnLoadStart(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ TransitionType transition_type) override {
+ if (!frame->IsMain()) {
+ auto map = GetFrameMap(frame);
+ auto status = map->GetFrameStatus(frame);
+ status->OnLoadStart(browser, frame);
+ return;
+ }
+
+ NavigateOrderMainTestHandler::OnLoadStart(browser, frame, transition_type);
+ }
+
+ void OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int httpStatusCode) override {
+ if (!frame->IsMain()) {
+ auto map = GetFrameMap(frame);
+ auto status = map->GetFrameStatus(frame);
+ status->OnLoadEnd(browser, frame);
+ return;
+ }
+
+ NavigateOrderMainTestHandler::OnLoadEnd(browser, frame, httpStatusCode);
+ }
+
+ protected:
+ virtual std::string GetSubURL1ForNav(int nav) const {
+ return GetURLForNav(nav, "sub1");
+ }
+
+ std::string GetSubFrameHtml1ForNav(int nav) const {
+ if (test_mode_ == SUBFRAME_CHILDREN) {
+ return "<iframe src=\"" + GetSubURL2ForNav(nav) + "\">";
+ }
+ return "<html><body>Sub1</body></html>";
+ }
+
+ virtual std::string GetSubURL2ForNav(int nav) const {
+ return GetURLForNav(nav, "sub2");
+ }
+
+ std::string GetSubFrameHtml2ForNav(int nav) const {
+ return "<html><body>Sub2</body></html>";
+ }
+
+ std::string GetMainHtmlForNav(int nav) const override {
+ if (test_mode_ == SUBFRAME_PEERS) {
+ return "<html><body><iframe src=\"" + GetSubURL1ForNav(nav) +
+ "\"></iframe><iframe src=\"" + GetSubURL2ForNav(nav) +
+ "\"></iframe></body></html>";
+ } else if (test_mode_ == SUBFRAME_CHILDREN) {
+ return "<html><body><iframe src=\"" + GetSubURL1ForNav(nav) +
+ "\"></iframe></iframe></body></html>";
+ }
+ NOTREACHED();
+ return std::string();
+ }
+
+ bool AllQueriesDelivered(std::string* msg = nullptr) const override {
+ if (!NavigateOrderMainTestHandler::AllQueriesDelivered(msg)) {
+#if VERBOSE_DEBUGGING
+ if (msg) {
+ *msg += " MAIN PENDING";
+ }
+#endif
+ return false;
+ }
+
+ if (frame_maps_.empty()) {
+#if VERBOSE_DEBUGGING
+ if (msg) {
+ *msg += " NO SUBS";
+ }
+#endif
+ return false;
+ }
+
+ if (!frame_maps_.back()->AllQueriesDelivered(msg)) {
+#if VERBOSE_DEBUGGING
+ if (msg) {
+ *msg += " SUBS PENDING";
+ }
+#endif
+ return false;
+ }
+ return true;
+ }
+
+ bool AllFramesLoaded(std::string* msg = nullptr) const override {
+ if (!NavigateOrderMainTestHandler::AllFramesLoaded(msg)) {
+#if VERBOSE_DEBUGGING
+ if (msg) {
+ *msg += " MAIN PENDING";
+ }
+#endif
+ return false;
+ }
+
+ if (frame_maps_.empty()) {
+#if VERBOSE_DEBUGGING
+ if (msg) {
+ *msg += " NO SUBS";
+ }
+#endif
+ return false;
+ }
+
+ if (!frame_maps_.back()->AllFramesLoaded(msg)) {
+#if VERBOSE_DEBUGGING
+ if (msg) {
+ *msg += " SUBS PENDING";
+ }
+#endif
+ return false;
+ }
+ return true;
+ }
+
+ void VerifyTestResults() override {
+ NavigateOrderMainTestHandler::VerifyTestResults();
+ EXPECT_TRUE(frame_maps_.empty());
+ }
+
+ size_t expected_frame_ct() const { return expected_frame_ct_; }
+
+ FrameStatusMap* GetFrameMap(CefRefPtr<CefFrame> frame) const {
+ for (auto& map : frame_maps_) {
+ if (map->Contains(frame)) {
+ return map.get();
+ }
+ }
+ return nullptr;
+ }
+
+ private:
+ // All sub-frame objects should already have received all callbacks.
+ void VerifyAndClearSubFrameTestResults(FrameStatusMap* map) {
+ map->VerifyAndClearTestResults();
+
+ bool found = false;
+ FrameStatusMapVector::iterator it = frame_maps_.begin();
+ for (; it != frame_maps_.end(); ++it) {
+ if ((*it).get() == map) {
+ frame_maps_.erase(it);
+ found = true;
+ break;
+ }
+ }
+
+ EXPECT_TRUE(found);
+ }
+
+ FrameStatusMap* GetOrCreateFrameMap(CefRefPtr<CefFrame> frame) {
+ if (auto map = GetFrameMap(frame)) {
+ return map;
+ }
+
+ if (frame_maps_.empty() ||
+ frame_maps_.back()->size() >= expected_frame_ct_) {
+ // Start a new frame map.
+ auto map = std::make_unique<FrameStatusMap>(expected_frame_ct_);
+ frame_maps_.push_back(std::move(map));
+ }
+
+ return frame_maps_.back().get();
+ }
+
+ const TestMode test_mode_;
+
+ // The expected number of sub-frames.
+ const size_t expected_frame_ct_;
+
+ using FrameStatusMapVector = std::vector<std::unique_ptr<FrameStatusMap>>;
+ FrameStatusMapVector frame_maps_;
+};
+
+} // namespace
+
+// Main frame loads two sub-frames that are peers in the same origin.
+TEST(FrameHandlerTest, OrderSubSameOriginPeers) {
+ CefRefPtr<OrderSubTestHandler> handler =
+ new OrderSubTestHandler(/*cross_origin=*/false, /*additional_nav_ct=*/0,
+ OrderSubTestHandler::SUBFRAME_PEERS);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Main frame loads two sub-frames that are peers in the same origin, then
+// navigates in the same origin and does it again twice.
+TEST(FrameHandlerTest, OrderSubSameOriginPeersNavSameOrigin) {
+ CefRefPtr<OrderSubTestHandler> handler =
+ new OrderSubTestHandler(/*cross_origin=*/false, /*additional_nav_ct=*/2,
+ OrderSubTestHandler::SUBFRAME_PEERS);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Main frame loads two sub-frames that are peers in the same origin, then
+// navigates cross-origin and does it again twice.
+TEST(FrameHandlerTest, OrderSubSameOriginPeersNavCrossOrigin) {
+ CefRefPtr<OrderSubTestHandler> handler =
+ new OrderSubTestHandler(/*cross_origin=*/true, /*additional_nav_ct=*/2,
+ OrderSubTestHandler::SUBFRAME_PEERS);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Main frame loads a sub-frame that then has it's own sub-frame.
+TEST(FrameHandlerTest, OrderSubSameOriginChildren) {
+ CefRefPtr<OrderSubTestHandler> handler =
+ new OrderSubTestHandler(/*cross_origin=*/false, /*additional_nav_ct=*/0,
+ OrderSubTestHandler::SUBFRAME_CHILDREN);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Main frame loads a sub-frame that then has it's own sub-frame, then navigates
+// in the same origin and does it again twice.
+TEST(FrameHandlerTest, OrderSubSameOriginChildrenNavSameOrigin) {
+ CefRefPtr<OrderSubTestHandler> handler =
+ new OrderSubTestHandler(/*cross_origin=*/false, /*additional_nav_ct=*/2,
+ OrderSubTestHandler::SUBFRAME_CHILDREN);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Main frame loads a sub-frame that then has it's own sub-frame, then navigates
+// cross-origin and does it again twice.
+TEST(FrameHandlerTest, OrderSubSameOriginChildrenNavCrossOrigin) {
+ CefRefPtr<OrderSubTestHandler> handler =
+ new OrderSubTestHandler(/*cross_origin=*/true, /*additional_nav_ct=*/2,
+ OrderSubTestHandler::SUBFRAME_CHILDREN);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+namespace {
+
+// Like above, but also navigating the sub-frames cross-origin.
+class CrossOriginOrderSubTestHandler : public OrderSubTestHandler {
+ public:
+ CrossOriginOrderSubTestHandler(int additional_nav_ct, TestMode mode)
+ : OrderSubTestHandler(/*cross_origin=*/true,
+ additional_nav_ct,
+ mode,
+ /*expected_frame_ct=*/4U) {}
+
+ void OnFrameDetached(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) override {
+ // A sub-frame is first created in the parent's renderer process. That
+ // sub-frame is then discarded after the real cross-origin sub-frame is
+ // created in a different renderer process. These discarded sub-frames will
+ // get OnFrameCreated/OnFrameAttached immediately followed by
+ // OnFrameDetached.
+ if (!frame->IsMain()) {
+ auto map = GetFrameMap(frame);
+ auto status = map->GetFrameStatus(frame);
+ if (status && !status->DidGetCallback(FrameStatus::LOAD_START)) {
+ status->SetIsTemporary(true);
+ temp_frame_detached_ct_++;
+ }
+ }
+
+ OrderSubTestHandler::OnFrameDetached(browser, frame);
+ }
+
+ protected:
+ std::string GetSubURL1ForNav(int nav) const override {
+ std::stringstream ss;
+ ss << kOrderMainUrlPrefix << nav << "-sub1/sub-cross-origin.html";
+ return ss.str();
+ }
+
+ std::string GetSubURL2ForNav(int nav) const override {
+ std::stringstream ss;
+ ss << kOrderMainUrlPrefix << nav << "-sub2/sub-cross-origin.html";
+ return ss.str();
+ }
+
+ void VerifyTestResults() override {
+ OrderSubTestHandler::VerifyTestResults();
+
+ const size_t expected_temp_ct =
+ (expected_frame_ct() / 2U) * (1U + additional_nav_ct());
+ EXPECT_EQ(expected_temp_ct, temp_frame_detached_ct_);
+ }
+
+ private:
+ size_t temp_frame_detached_ct_ = 0U;
+};
+
+} // namespace
+
+// Main frame loads two sub-frames that are peers in a different origin.
+TEST(FrameHandlerTest, OrderSubCrossOriginPeers) {
+ CefRefPtr<CrossOriginOrderSubTestHandler> handler =
+ new CrossOriginOrderSubTestHandler(
+ /*additional_nav_ct=*/0,
+ CrossOriginOrderSubTestHandler::SUBFRAME_PEERS);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Main frame loads two sub-frames that are peers in a different origin, then
+// navigates cross-origin and does it again twice.
+TEST(FrameHandlerTest, OrderSubCrossOriginPeersNavCrossOrigin) {
+ CefRefPtr<CrossOriginOrderSubTestHandler> handler =
+ new CrossOriginOrderSubTestHandler(
+ /*additional_nav_ct=*/2,
+ CrossOriginOrderSubTestHandler::SUBFRAME_PEERS);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Main frame loads a sub-frame in a different origin that then has it's own
+// sub-frame in a different origin.
+TEST(FrameHandlerTest, OrderSubCrossOriginChildren) {
+ CefRefPtr<CrossOriginOrderSubTestHandler> handler =
+ new CrossOriginOrderSubTestHandler(
+ /*additional_nav_ct=*/0,
+ CrossOriginOrderSubTestHandler::SUBFRAME_CHILDREN);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Main frame loads a sub-frame in a different origin that then has it's own
+// sub-frame in a different origin, then navigates cross-origin and does it
+// again twice.
+TEST(FrameHandlerTest, OrderSubCrossOriginChildrenNavCrossOrigin) {
+ CefRefPtr<CrossOriginOrderSubTestHandler> handler =
+ new CrossOriginOrderSubTestHandler(
+ /*additional_nav_ct=*/2,
+ CrossOriginOrderSubTestHandler::SUBFRAME_CHILDREN);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+namespace {
+
+const char kOrderMainCrossUrl[] =
+ "http://tests-frame-handler-cross/main-order.html";
+
+// Will be assigned as popup handler via
+// ParentOrderMainTestHandler::OnBeforePopup.
+class PopupOrderMainTestHandler : public OrderMainTestHandler {
+ public:
+ PopupOrderMainTestHandler(CompletionState* completion_state,
+ bool cross_origin)
+ : OrderMainTestHandler(completion_state), cross_origin_(cross_origin) {
+ expected_main_frame_changed_ct_ = cross_origin_ ? 1 : 0;
+ }
+
+ void SetupTest() override {
+ // Proceed to RunTest().
+ SetupComplete();
+ }
+
+ void RunTest() override {
+ // Add the main resource that we will navigate to/from.
+ AddResource(GetMainURL(), GetMainHtml(), "text/html");
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout();
+ }
+
+ void OnFrameCreated(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) override {
+ EXPECT_UI_THREAD();
+
+ EXPECT_TRUE(frame->IsMain());
+ if (cross_origin_ && !temp_main_frame_) {
+ // The first main frame in the popup will be created in the parent
+ // process.
+ EXPECT_FALSE(got_temp_created_);
+ got_temp_created_.yes();
+
+ temp_main_frame_ = new FrameStatus(frame);
+ temp_main_frame_->SetAdditionalDebugInfo(GetAdditionalDebugInfo() +
+ "temp ");
+ temp_main_frame_->SetIsFirstMain(true);
+ temp_main_frame_->OnFrameCreated(browser, frame);
+ return;
+ }
+
+ OrderMainTestHandler::OnFrameCreated(browser, frame);
+ }
+
+ void OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
+ if (temp_main_frame_ && temp_main_frame_->IsSame(browser->GetMainFrame())) {
+ EXPECT_FALSE(got_after_created_);
+ got_after_created_ = true;
+
+ EXPECT_TRUE(cross_origin_);
+ temp_main_frame_->OnAfterCreated(browser);
+
+ // Intentionally skipping the immediate parent class method.
+ RoutingTestHandler::OnAfterCreated(browser);
+ return;
+ }
+
+ OrderMainTestHandler::OnAfterCreated(browser);
+ }
+
+ void OnFrameAttached(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ bool reattached) override {
+ if (temp_main_frame_ && temp_main_frame_->IsSame(frame)) {
+ EXPECT_TRUE(cross_origin_);
+ temp_main_frame_->OnFrameAttached(browser, frame);
+ return;
+ }
+
+ OrderMainTestHandler::OnFrameAttached(browser, frame, reattached);
+ }
+
+ void OnMainFrameChanged(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> old_frame,
+ CefRefPtr<CefFrame> new_frame) override {
+ if (temp_main_frame_ && temp_main_frame_->IsSame(new_frame)) {
+ EXPECT_TRUE(cross_origin_);
+ temp_main_frame_->OnMainFrameChanged(browser, old_frame, new_frame);
+ return;
+ }
+
+ OrderMainTestHandler::OnMainFrameChanged(browser, old_frame, new_frame);
+ }
+
+ void OnFrameDetached(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) override {
+ if (temp_main_frame_ && temp_main_frame_->IsSame(frame)) {
+ EXPECT_TRUE(cross_origin_);
+ EXPECT_FALSE(got_temp_destroyed_);
+ got_temp_destroyed_.yes();
+
+#if VERBOSE_DEBUGGING
+ LOG(INFO) << temp_main_frame_->GetDebugString()
+ << " callback OnFrameDetached(discarded)";
+#endif
+
+ // All of the initial main frame callbacks go to the proxy.
+ EXPECT_TRUE(temp_main_frame_->DidGetCallback(FrameStatus::AFTER_CREATED));
+ EXPECT_TRUE(temp_main_frame_->DidGetCallback(
+ FrameStatus::MAIN_FRAME_INITIAL_ASSIGNED));
+ EXPECT_TRUE(!temp_main_frame_->DidGetCallback(FrameStatus::LOAD_START));
+ EXPECT_TRUE(temp_main_frame_->DidGetCallback(FrameStatus::FRAME_CREATED));
+ EXPECT_TRUE(
+ temp_main_frame_->DidGetCallback(FrameStatus::FRAME_ATTACHED));
+
+ // Should receive queries for OnFrameCreated, OnAfterCreated,
+ // OnFrameAttached.
+ EXPECT_EQ(temp_main_frame_->QueriesDeliveredCount(), 3);
+
+ delete temp_main_frame_;
+ temp_main_frame_ = nullptr;
+ return;
+ }
+
+ OrderMainTestHandler::OnFrameDetached(browser, frame);
+ }
+
+ bool OnQuery(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int64 query_id,
+ const CefString& request,
+ bool persistent,
+ CefRefPtr<Callback> callback) override {
+ if (temp_main_frame_ && temp_main_frame_->IsSame(frame)) {
+ EXPECT_TRUE(cross_origin_);
+ temp_main_frame_->OnQuery(browser, frame, request);
+ return true;
+ }
+
+ return OrderMainTestHandler::OnQuery(browser, frame, query_id, request,
+ persistent, callback);
+ }
+
+ std::string GetMainURL() const override {
+ return cross_origin_ ? kOrderMainCrossUrl : kOrderMainUrl;
+ }
+
+ protected:
+ bool IsCrossOrigin() const override { return cross_origin_; }
+
+ void VerifyTestResults() override {
+ OrderMainTestHandler::VerifyTestResults();
+
+ if (cross_origin_) {
+ EXPECT_TRUE(got_temp_created_);
+ EXPECT_TRUE(got_temp_destroyed_);
+ } else {
+ EXPECT_FALSE(got_temp_created_);
+ EXPECT_FALSE(got_temp_destroyed_);
+ }
+ EXPECT_FALSE(temp_main_frame_);
+ }
+
+ private:
+ std::string GetAdditionalDebugInfo() const override { return " popup: "; }
+
+ const bool cross_origin_;
+
+ TrackCallback got_temp_created_;
+ TrackCallback got_temp_destroyed_;
+ FrameStatus* temp_main_frame_ = nullptr;
+};
+
+class ParentOrderMainTestHandler : public OrderMainTestHandler {
+ public:
+ ParentOrderMainTestHandler(CompletionState* completion_state,
+ CefRefPtr<PopupOrderMainTestHandler> popup_handler)
+ : OrderMainTestHandler(completion_state), popup_handler_(popup_handler) {}
+
+ bool OnBeforePopup(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const CefString& target_url,
+ const CefString& target_frame_name,
+ CefLifeSpanHandler::WindowOpenDisposition target_disposition,
+ bool user_gesture,
+ const CefPopupFeatures& popupFeatures,
+ CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient>& client,
+ CefBrowserSettings& settings,
+ CefRefPtr<CefDictionaryValue>& extra_info,
+ bool* no_javascript_access) override {
+ // Intentionally not calling the parent class method.
+ EXPECT_FALSE(got_on_before_popup_);
+ got_on_before_popup_.yes();
+
+ client = popup_handler_;
+ popup_handler_ = nullptr;
+
+ // Proceed with popup creation.
+ return false;
+ }
+
+ void OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
+ OrderMainTestHandler::OnAfterCreated(browser);
+
+ // Create the popup ASAP.
+ browser->GetMainFrame()->ExecuteJavaScript(
+ "window.open('" + popup_handler_->GetMainURL() + "');", CefString(), 0);
+ }
+
+ void SetupTest() override {
+ // Proceed to RunTest().
+ SetupComplete();
+ }
+
+ void DestroyTest() override {
+ EXPECT_TRUE(got_on_before_popup_);
+ OrderMainTestHandler::DestroyTest();
+ }
+
+ private:
+ std::string GetAdditionalDebugInfo() const override { return "parent: "; }
+
+ CefRefPtr<PopupOrderMainTestHandler> popup_handler_;
+
+ TrackCallback got_on_before_popup_;
+};
+
+void RunOrderMainPopupTest(bool cross_origin) {
+ TestHandler::CompletionState completion_state(/*count=*/2);
+ TestHandler::Collection collection(&completion_state);
+
+ CefRefPtr<PopupOrderMainTestHandler> popup_handler =
+ new PopupOrderMainTestHandler(&completion_state, cross_origin);
+ CefRefPtr<ParentOrderMainTestHandler> parent_handler =
+ new ParentOrderMainTestHandler(&completion_state, popup_handler);
+
+ collection.AddTestHandler(popup_handler.get());
+ collection.AddTestHandler(parent_handler.get());
+ collection.ExecuteTests();
+
+ ReleaseAndWaitForDestructor(parent_handler);
+ ReleaseAndWaitForDestructor(popup_handler);
+}
+
+} // namespace
+
+// Test the ordering and behavior of main frame callbacks in a popup with the
+// same origin.
+TEST(FrameHandlerTest, OrderMainPopupSameOrigin) {
+ RunOrderMainPopupTest(/*cross_origin=*/false);
+}
+
+// Test the ordering and behavior of main frame callbacks in a popup with a
+// different origin.
+TEST(FrameHandlerTest, OrderMainPopupCrossOrigin) {
+ RunOrderMainPopupTest(/*cross_origin=*/true);
+}
diff --git a/tests/ceftests/frame_unittest.cc b/tests/ceftests/frame_unittest.cc
new file mode 100644
index 00000000..b1650aef
--- /dev/null
+++ b/tests/ceftests/frame_unittest.cc
@@ -0,0 +1,2326 @@
+// Copyright (c) 2014 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include <memory>
+
+#include "include/base/cef_callback.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "include/wrapper/cef_stream_resource_handler.h"
+#include "tests/ceftests/test_handler.h"
+#include "tests/ceftests/test_util.h"
+#include "tests/gtest/include/gtest/gtest.h"
+#include "tests/shared/browser/client_app_browser.h"
+#include "tests/shared/renderer/client_app_renderer.h"
+
+using client::ClientAppBrowser;
+using client::ClientAppRenderer;
+
+namespace {
+
+// The frame navigation test harness work as follows:
+//
+// In the browser process:
+// 1. TEST() function creates a new FrameNavTestHandler instance with a unique
+// FrameNavFactoryId.
+// 2. FrameNavTestHandler calls FrameNavExpectationsFactoryBrowser::FromID to
+// create a new factory instance.
+// 3. FrameNavTestHandler calls FrameNavExpectationsFactoryBrowser::Create to
+// create a new FrameNavExpectationsBrowser instance for the current
+// navigation.
+// 4. FrameNavTestHandler retrieves the URL to load via
+// FrameNavExpectationsBrowser::GetMainURL and calls either CreateBrowser
+// (for the first navigation) or LoadURL (for the following navigations).
+// 5. If the renderer process does not already exist CEF creates it with
+// command-line arguments that specify the FrameNavFactoryId via
+// FrameNavBrowserTest::OnBeforeChildProcessLaunch.
+//
+// In the renderer process:
+// 6. If the renderer process is newly created FrameNavRendererTest calls
+// FrameNavExpectationsFactoryRenderer::FromID to create a new factory
+// instance.
+// 7. FrameNavRendererTest calls FrameNavExpectationsFactoryRenderer::Create to
+// create a new FrameNavExpectationsRenderer instance for the current
+// navigation.
+//
+// In both processes:
+// 8. Callback notifications are sent to the FrameNavExpectations* instances.
+//
+// In the renderer process:
+// 9. When the FrameNavExpectationsRenderer instance determines that the
+// renderer side of the test is complete it calls SignalComplete which
+// finalizes and deletes the FrameNavExpectationsRenderer instance and
+// sends an IPC message to the browser process.
+//
+// In the browser process:
+// 11.FrameNavExpectationsBrowser::OnRendererComplete is called in response to
+// renderer-side test completion message.
+// 12.When the FrameNavExpectationsBrowser instance determines that the browser
+// side of the test is complete it calls SignalComplete which finalizes and
+// deletes the FrameNavExpectationsBrowser instance.
+// 13.If FrameNavExpectationsFactoryBrowser::HasMoreNavigations returns false
+// then DestroyTest is called and the test ends. Otherwise, the navigation
+// count is incremented and the process repeats starting with step #3.
+//
+//
+// To add a new test case:
+// 1. Add a new value to the FrameNavFactoryId enumeration.
+// 2. Provide implementations of FrameNavExpectations*.
+// 3. Add a case for the new factory ID to FrameNavExpectationsFactory*::FromID.
+// 4. Implement a TEST() function that creates a FrameNavTestHandler instance
+// and passes the new factory ID.
+//
+//
+// Run with the `--single-process` command-line flag to see expectation failures
+// from the renderer process.
+//
+
+// All known factory IDs.
+enum FrameNavFactoryId {
+ FNF_ID_INVALID = 0,
+ FNF_ID_SINGLE_NAV_HARNESS,
+ FNF_ID_SINGLE_NAV,
+ FNF_ID_MULTI_NAV_HARNESS,
+ FNF_ID_MULTI_NAV,
+ FNF_ID_NESTED_IFRAMES_SAME_ORIGIN,
+ FNF_ID_NESTED_IFRAMES_DIFF_ORIGIN,
+};
+
+// IPC message name.
+const char kFrameNavMsg[] = "FrameTest.Navigation";
+
+// Extra info parameter keys.
+const char kFrameNavTestCmdKey[] = "frame-nav-test";
+
+// Origins used in tests.
+const char kFrameNavOrigin0[] = "http://tests-framenav0.com/";
+const char kFrameNavOrigin1[] = "http://tests-framenav1.com/";
+const char kFrameNavOrigin2[] = "http://tests-framenav2.com/";
+const char kFrameNavOrigin3[] = "http://tests-framenav3.com/";
+
+// Maximum number of navigations. Should be kept synchronized with the number
+// of kFrameNavOrigin* values. Don't modify this value without checking the
+// below use cases.
+const int kMaxMultiNavNavigations = 4;
+
+// Abstract base class representing expectations that result from a navigation.
+class FrameNavExpectations {
+ public:
+ typedef base::OnceCallback<void(CefRefPtr<CefBrowser>, CefRefPtr<CefFrame>)>
+ CompletionCallback;
+
+ FrameNavExpectations(int nav, bool renderer)
+ : nav_(nav), renderer_(renderer) {}
+ virtual ~FrameNavExpectations() {}
+
+ // Browser and renderer notifications.
+ virtual bool OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
+ bool isLoading) {
+ return true;
+ }
+ virtual bool OnLoadStart(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) {
+ return true;
+ }
+ virtual bool OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) {
+ return true;
+ }
+
+ // Final expectations check before this object is deleted.
+ virtual bool Finalize() = 0;
+
+ // Signal that all expectations are completed. Should be called as a result of
+ // notifications.
+ void SignalComplete(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) {
+ if (!completion_callback_.is_null()) {
+ // Execute the callback asynchronously to avoid any issues with what's
+ // currently on the stack.
+ CefPostTask(
+ (renderer_ ? TID_RENDERER : TID_UI),
+ base::BindOnce(std::move(completion_callback_), browser, frame));
+ }
+ }
+
+ // Returns the current navigation count. In the browser process this value
+ // increments over the life span of the FrameNavTestHandler instance. In the
+ // renderer process this value increments over the life span of a single
+ // renderer instance (i.e. cross-origin navigations will cause this value to
+ // reset).
+ int nav() const { return nav_; }
+
+ // Returns true if this is a renderer-side expectation object.
+ bool renderer() const { return renderer_; }
+
+ void set_completion_callback(CompletionCallback completion_callback) {
+ completion_callback_ = std::move(completion_callback);
+ }
+
+ private:
+ int nav_;
+ bool renderer_;
+ CompletionCallback completion_callback_;
+};
+
+// Browser process expectations abstract base class.
+class FrameNavExpectationsBrowser : public FrameNavExpectations {
+ public:
+ explicit FrameNavExpectationsBrowser(int nav)
+ : FrameNavExpectations(nav, false) {}
+
+ // Loading information.
+ virtual std::string GetMainURL() = 0;
+ virtual std::string GetContentForURL(const std::string& url) = 0;
+
+ // Browser-only notifications.
+ virtual bool OnAfterCreated(CefRefPtr<CefBrowser> browser) {
+ EXPECT_TRUE(browser.get());
+ return true;
+ }
+ virtual bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const std::string& url) {
+ EXPECT_TRUE(browser.get());
+ EXPECT_TRUE(frame.get());
+ EXPECT_FALSE(url.empty());
+ return true;
+ }
+ virtual bool GetResourceHandler(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) {
+ EXPECT_TRUE(browser.get());
+ EXPECT_TRUE(frame.get());
+ return true;
+ }
+
+ // Called when the renderer signals completion.
+ virtual bool OnRendererComplete(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int renderer_nav,
+ bool renderer_result) = 0;
+};
+
+// Renderer process expectations abstract base class.
+class FrameNavExpectationsRenderer : public FrameNavExpectations {
+ public:
+ explicit FrameNavExpectationsRenderer(int nav)
+ : FrameNavExpectations(nav, true) {}
+};
+
+// Abstract base class for the factory that creates expectations objects.
+class FrameNavExpectationsFactory {
+ public:
+ FrameNavExpectationsFactory() {}
+ virtual ~FrameNavExpectationsFactory() {}
+
+ // Returns the unique ID for this factory type.
+ virtual FrameNavFactoryId GetID() const = 0;
+};
+
+// Browser process expectations factory abstact base class.
+class FrameNavExpectationsFactoryBrowser : public FrameNavExpectationsFactory {
+ public:
+ FrameNavExpectationsFactoryBrowser() {}
+
+ // Create a new factory instance of the specified type.
+ static std::unique_ptr<FrameNavExpectationsFactoryBrowser> FromID(
+ FrameNavFactoryId id);
+
+ // Returns true if there will be more navigations in the browser process
+ // handler.
+ virtual bool HasMoreNavigations() const = 0;
+
+ // Verify final expectations results.
+ virtual bool Finalize() = 0;
+
+ std::unique_ptr<FrameNavExpectationsBrowser> Create(
+ int nav,
+ FrameNavExpectations::CompletionCallback completion_callback) {
+ auto expectations = Create(nav);
+ expectations->set_completion_callback(std::move(completion_callback));
+ return expectations;
+ }
+
+ protected:
+ // Implement in the test-specific factory instance.
+ virtual std::unique_ptr<FrameNavExpectationsBrowser> Create(int nav) = 0;
+};
+
+// Renderer process expectations factory abstact base class.
+class FrameNavExpectationsFactoryRenderer : public FrameNavExpectationsFactory {
+ public:
+ FrameNavExpectationsFactoryRenderer() {}
+
+ // Create a new factory instance of the specified type.
+ static std::unique_ptr<FrameNavExpectationsFactoryRenderer> FromID(
+ FrameNavFactoryId id);
+
+ std::unique_ptr<FrameNavExpectationsRenderer> Create(
+ int nav,
+ FrameNavExpectations::CompletionCallback completion_callback) {
+ auto expectations = Create(nav);
+ expectations->set_completion_callback(std::move(completion_callback));
+ return expectations;
+ }
+
+ protected:
+ // Implement in the test-specific factory instance.
+ virtual std::unique_ptr<FrameNavExpectationsRenderer> Create(int nav) = 0;
+};
+
+// Renderer side handler.
+class FrameNavRendererTest : public ClientAppRenderer::Delegate,
+ public CefLoadHandler {
+ public:
+ FrameNavRendererTest() : run_test_(false), nav_(0) {}
+
+ void OnBrowserCreated(CefRefPtr<ClientAppRenderer> app,
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefDictionaryValue> extra_info) override {
+ if (!extra_info || !extra_info->HasKey(kFrameNavTestCmdKey)) {
+ return;
+ }
+
+ FrameNavFactoryId factory_id =
+ static_cast<FrameNavFactoryId>(extra_info->GetInt(kFrameNavTestCmdKey));
+ run_test_ = factory_id != FNF_ID_INVALID;
+ if (!run_test_) {
+ return;
+ }
+
+ factory_ = FrameNavExpectationsFactoryRenderer::FromID(factory_id);
+ }
+
+ CefRefPtr<CefLoadHandler> GetLoadHandler(
+ CefRefPtr<ClientAppRenderer> app) override {
+ if (!run_test_) {
+ return nullptr;
+ }
+
+ return this;
+ }
+
+ void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
+ bool isLoading,
+ bool canGoBack,
+ bool canGoForward) override {
+ CreateExpectationsIfNecessary();
+ EXPECT_TRUE(expectations_->OnLoadingStateChange(browser, isLoading))
+ << "isLoading = " << isLoading << ", nav = " << nav_;
+ }
+
+ void OnLoadStart(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ TransitionType transition_type) override {
+ CreateExpectationsIfNecessary();
+ EXPECT_TRUE(expectations_->OnLoadStart(browser, frame)) << "nav = " << nav_;
+ }
+
+ void OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int httpStatusCode) override {
+ CreateExpectationsIfNecessary();
+ EXPECT_TRUE(expectations_->OnLoadEnd(browser, frame)) << "nav = " << nav_;
+ }
+
+ protected:
+ // Create a new expectations object if one does not already exist for the
+ // current navigation.
+ void CreateExpectationsIfNecessary() {
+ if (expectations_) {
+ return;
+ }
+ expectations_ = factory_->Create(
+ nav_, base::BindOnce(&FrameNavRendererTest::SendTestResults, this));
+ }
+
+ // Send the test results.
+ // Will be called via FrameNavExpectations::SignalComplete.
+ void SendTestResults(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) {
+ // End of the current expectations object.
+ EXPECT_TRUE(expectations_->Finalize()) << "nav = " << nav_;
+ expectations_.reset(nullptr);
+
+ // Check if the test has failed.
+ bool result = !TestFailed();
+
+ // Return the result to the browser process.
+ CefRefPtr<CefProcessMessage> return_msg =
+ CefProcessMessage::Create(kFrameNavMsg);
+ CefRefPtr<CefListValue> args = return_msg->GetArgumentList();
+ EXPECT_TRUE(args.get());
+ EXPECT_TRUE(args->SetInt(0, nav_));
+ EXPECT_TRUE(args->SetBool(1, result));
+
+ const int64 frame_id = frame->GetIdentifier();
+ EXPECT_TRUE(args->SetInt(2, CefInt64GetLow(frame_id)));
+ EXPECT_TRUE(args->SetInt(3, CefInt64GetHigh(frame_id)));
+
+ frame->SendProcessMessage(PID_BROWSER, return_msg);
+
+ nav_++;
+ }
+
+ bool run_test_;
+ int nav_;
+ std::unique_ptr<FrameNavExpectationsFactoryRenderer> factory_;
+ std::unique_ptr<FrameNavExpectationsRenderer> expectations_;
+
+ IMPLEMENT_REFCOUNTING(FrameNavRendererTest);
+};
+
+// Browser side handler.
+class FrameNavTestHandler : public TestHandler {
+ public:
+ explicit FrameNavTestHandler(FrameNavFactoryId factory_id)
+ : nav_(0),
+ factory_(FrameNavExpectationsFactoryBrowser::FromID(factory_id)) {}
+
+ ~FrameNavTestHandler() override { EXPECT_TRUE(got_destroyed_); }
+
+ void RunTest() override {
+ // Create the first expectations object.
+ expectations_ = factory_->Create(
+ nav_, base::BindOnce(&FrameNavTestHandler::RunNextNav, this));
+
+ CefRefPtr<CefDictionaryValue> extra_info = CefDictionaryValue::Create();
+ extra_info->SetInt(kFrameNavTestCmdKey, factory_->GetID());
+
+ // Create the browser with the initial URL.
+ CreateBrowser(expectations_->GetMainURL(), nullptr, extra_info);
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout(15000);
+ }
+
+ // Transition to the next navigation.
+ // Will be called via FrameNavExpectations::SignalComplete.
+ void RunNextNav(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame) {
+ // End of the current expectations object.
+ EXPECT_TRUE(expectations_->Finalize());
+ expectations_.reset(nullptr);
+
+ if (!factory_->HasMoreNavigations()) {
+ // End of the test.
+ DestroyTest();
+ return;
+ }
+
+ nav_++;
+
+ // Create the next expectations object.
+ expectations_ = factory_->Create(
+ nav_, base::BindOnce(&FrameNavTestHandler::RunNextNav, this));
+
+ // Load the main URL.
+ browser->GetMainFrame()->LoadURL(expectations_->GetMainURL());
+ }
+
+ void OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
+ TestHandler::OnAfterCreated(browser);
+
+ EXPECT_TRUE(expectations_->OnAfterCreated(browser)) << "nav = " << nav_;
+ }
+
+ CefRefPtr<CefResourceHandler> GetResourceHandler(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request) override {
+ const std::string& url = request->GetURL();
+ if (IgnoreURL(url)) {
+ return nullptr;
+ }
+
+ EXPECT_TRUE(expectations_->GetResourceHandler(browser, frame))
+ << "nav = " << nav_;
+
+ const std::string& content = expectations_->GetContentForURL(url);
+ EXPECT_TRUE(!content.empty()) << "nav = " << nav_;
+
+ CefRefPtr<CefStreamReader> stream = CefStreamReader::CreateForData(
+ static_cast<void*>(const_cast<char*>(content.c_str())),
+ content.length());
+ return new CefStreamResourceHandler("text/html", stream);
+ }
+
+ bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ bool user_gesture,
+ bool is_redirect) override {
+ EXPECT_TRUE(
+ expectations_->OnBeforeBrowse(browser, frame, request->GetURL()))
+ << "nav = " << nav_;
+
+ return false;
+ }
+
+ void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
+ bool isLoading,
+ bool canGoBack,
+ bool canGoForward) override {
+ EXPECT_TRUE(expectations_->OnLoadingStateChange(browser, isLoading))
+ << "isLoading = " << isLoading << ", nav = " << nav_;
+ ;
+ }
+
+ void OnLoadStart(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ TransitionType transition_type) override {
+ EXPECT_TRUE(expectations_->OnLoadStart(browser, frame)) << "nav = " << nav_;
+ }
+
+ void OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int httpStatusCode) override {
+ EXPECT_TRUE(expectations_->OnLoadEnd(browser, frame)) << "nav = " << nav_;
+ }
+
+ bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefProcessId source_process,
+ CefRefPtr<CefProcessMessage> message) override {
+ if (message->GetName().ToString() == kFrameNavMsg) {
+ // Test that the renderer side succeeded.
+ CefRefPtr<CefListValue> args = message->GetArgumentList();
+ EXPECT_TRUE(args.get());
+
+ EXPECT_TRUE(expectations_->OnRendererComplete(
+ browser, frame, args->GetInt(0), args->GetBool(1)))
+ << "nav = " << nav_;
+
+ // Test that browser and render process frame IDs match.
+ const int64 frame_id = CefInt64Set(args->GetInt(2), args->GetInt(3));
+ EXPECT_EQ(frame->GetIdentifier(), frame_id);
+
+ return true;
+ }
+
+ // Message not handled.
+ return false;
+ }
+
+ void DestroyTest() override {
+ if (got_destroyed_) {
+ return;
+ }
+
+ got_destroyed_.yes();
+
+ // The expectations should have been tested already.
+ EXPECT_FALSE(expectations_.get());
+
+ // Test that factory conditions we met.
+ EXPECT_TRUE(factory_->Finalize()) << "nav = " << nav_;
+
+ TestHandler::DestroyTest();
+ }
+
+ int nav_;
+ TrackCallback got_destroyed_;
+ std::unique_ptr<FrameNavExpectationsFactoryBrowser> factory_;
+ std::unique_ptr<FrameNavExpectationsBrowser> expectations_;
+
+ IMPLEMENT_REFCOUNTING(FrameNavTestHandler);
+};
+
+// Helper for defining frame tests.
+#define FRAME_TEST(name, factory_id) \
+ TEST(FrameTest, name) { \
+ CefRefPtr<FrameNavTestHandler> handler = \
+ new FrameNavTestHandler(factory_id); \
+ handler->ExecuteTest(); \
+ ReleaseAndWaitForDestructor(handler); \
+ }
+
+// Browser process expectations for a single navigation.
+class FrameNavExpectationsBrowserSingleNav
+ : public FrameNavExpectationsBrowser {
+ public:
+ explicit FrameNavExpectationsBrowserSingleNav(int nav)
+ : FrameNavExpectationsBrowser(nav) {}
+
+ ~FrameNavExpectationsBrowserSingleNav() override {
+ EXPECT_TRUE(got_finalize_);
+ }
+
+ bool OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
+ bool isLoading) override {
+ if (isLoading) {
+ EXPECT_FALSE(got_loading_state_change_start_);
+ got_loading_state_change_start_.yes();
+ } else {
+ EXPECT_FALSE(got_loading_state_change_end_);
+ got_loading_state_change_end_.yes();
+ SignalCompleteIfDone(browser, browser->GetMainFrame());
+ }
+ return true;
+ }
+
+ bool OnLoadStart(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) override {
+ EXPECT_FALSE(got_load_start_);
+ got_load_start_.yes();
+ return true;
+ }
+
+ bool OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) override {
+ EXPECT_FALSE(got_load_end_);
+ got_load_end_.yes();
+ SignalCompleteIfDone(browser, frame);
+ return true;
+ }
+
+ bool OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
+ EXPECT_FALSE(got_after_created_);
+ got_after_created_.yes();
+ return true;
+ }
+
+ bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const std::string& url) override {
+ EXPECT_FALSE(got_before_browse_);
+ got_before_browse_.yes();
+ return true;
+ }
+
+ bool GetResourceHandler(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) override {
+ EXPECT_FALSE(got_get_resource_handler_);
+ got_get_resource_handler_.yes();
+ return true;
+ }
+
+ bool OnRendererComplete(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int renderer_nav,
+ bool renderer_result) override {
+ EXPECT_EQ(nav(), renderer_nav);
+ EXPECT_TRUE(renderer_result);
+ EXPECT_FALSE(got_renderer_done_);
+ got_renderer_done_.yes();
+ SignalCompleteIfDone(browser, frame);
+ return true;
+ }
+
+ bool Finalize() override {
+ V_DECLARE();
+ V_EXPECT_TRUE(got_load_start_);
+ V_EXPECT_TRUE(got_load_end_);
+ V_EXPECT_TRUE(got_loading_state_change_start_);
+ V_EXPECT_TRUE(got_loading_state_change_end_);
+ V_EXPECT_TRUE(got_renderer_done_);
+ V_EXPECT_TRUE(got_after_created_);
+ V_EXPECT_TRUE(got_before_browse_);
+ V_EXPECT_TRUE(got_get_resource_handler_);
+ V_EXPECT_FALSE(got_finalize_);
+
+ got_finalize_.yes();
+
+ V_RETURN();
+ }
+
+ private:
+ void SignalCompleteIfDone(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) {
+ if (got_renderer_done_ && got_load_end_ && got_loading_state_change_end_) {
+ SignalComplete(browser, frame);
+ }
+ }
+
+ TrackCallback got_load_start_;
+ TrackCallback got_load_end_;
+ TrackCallback got_loading_state_change_start_;
+ TrackCallback got_loading_state_change_end_;
+ TrackCallback got_renderer_done_;
+ TrackCallback got_after_created_;
+ TrackCallback got_before_browse_;
+ TrackCallback got_get_resource_handler_;
+ TrackCallback got_finalize_;
+};
+
+// Renderer process expectations for a single navigation.
+class FrameNavExpectationsRendererSingleNav
+ : public FrameNavExpectationsRenderer {
+ public:
+ explicit FrameNavExpectationsRendererSingleNav(int nav)
+ : FrameNavExpectationsRenderer(nav) {}
+
+ ~FrameNavExpectationsRendererSingleNav() override {
+ EXPECT_TRUE(got_finalize_);
+ }
+
+ bool OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
+ bool isLoading) override {
+ if (isLoading) {
+ EXPECT_FALSE(got_loading_state_change_start_);
+ got_loading_state_change_start_.yes();
+ } else {
+ EXPECT_FALSE(got_loading_state_change_end_);
+ got_loading_state_change_end_.yes();
+ SignalCompleteIfDone(browser, browser->GetMainFrame());
+ }
+ return true;
+ }
+
+ bool OnLoadStart(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) override {
+ EXPECT_FALSE(got_load_start_);
+ got_load_start_.yes();
+ return true;
+ }
+
+ bool OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) override {
+ EXPECT_FALSE(got_load_end_);
+ got_load_end_.yes();
+ SignalCompleteIfDone(browser, frame);
+ return true;
+ }
+
+ bool Finalize() override {
+ V_DECLARE();
+ V_EXPECT_TRUE(got_load_start_);
+ V_EXPECT_TRUE(got_load_end_);
+ V_EXPECT_TRUE(got_loading_state_change_start_);
+ V_EXPECT_TRUE(got_loading_state_change_end_);
+ V_EXPECT_FALSE(got_finalize_);
+
+ got_finalize_.yes();
+
+ V_RETURN();
+ }
+
+ private:
+ void SignalCompleteIfDone(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) {
+ if (got_load_end_ && got_loading_state_change_end_) {
+ SignalComplete(browser, frame);
+ }
+ }
+
+ TrackCallback got_load_start_;
+ TrackCallback got_load_end_;
+ TrackCallback got_loading_state_change_start_;
+ TrackCallback got_loading_state_change_end_;
+ TrackCallback got_finalize_;
+};
+
+// Test that the single nav harness works.
+class FrameNavExpectationsBrowserTestSingleNavHarness
+ : public FrameNavExpectationsBrowserSingleNav {
+ public:
+ typedef FrameNavExpectationsBrowserSingleNav parent;
+
+ explicit FrameNavExpectationsBrowserTestSingleNavHarness(int nav)
+ : parent(nav) {}
+
+ ~FrameNavExpectationsBrowserTestSingleNavHarness() override {
+ EXPECT_TRUE(got_finalize_);
+ }
+
+ std::string GetMainURL() override {
+ EXPECT_FALSE(got_get_main_url_);
+ got_get_main_url_.yes();
+ return kFrameNavOrigin0;
+ }
+
+ std::string GetContentForURL(const std::string& url) override {
+ EXPECT_FALSE(got_get_content_for_url_);
+ got_get_content_for_url_.yes();
+ EXPECT_STREQ(kFrameNavOrigin0, url.c_str());
+ return "<html><body>Nav</body></html>";
+ }
+
+ bool Finalize() override {
+ EXPECT_FALSE(got_finalize_);
+ got_finalize_.yes();
+
+ V_DECLARE();
+ V_EXPECT_TRUE(got_get_main_url_);
+ V_EXPECT_TRUE(got_get_content_for_url_);
+ V_EXPECT_TRUE(parent::Finalize());
+ V_RETURN();
+ }
+
+ private:
+ TrackCallback got_get_main_url_;
+ TrackCallback got_get_content_for_url_;
+ TrackCallback got_finalize_;
+};
+
+class FrameNavExpectationsRendererTestSingleNavHarness
+ : public FrameNavExpectationsRendererSingleNav {
+ public:
+ typedef FrameNavExpectationsRendererSingleNav parent;
+
+ explicit FrameNavExpectationsRendererTestSingleNavHarness(int nav)
+ : parent(nav) {}
+
+ ~FrameNavExpectationsRendererTestSingleNavHarness() override {
+ EXPECT_TRUE(got_finalize_);
+ }
+
+ bool Finalize() override {
+ EXPECT_FALSE(got_finalize_);
+ got_finalize_.yes();
+ return parent::Finalize();
+ }
+
+ private:
+ TrackCallback got_finalize_;
+};
+
+class FrameNavExpectationsFactoryBrowserTestSingleNavHarness
+ : public FrameNavExpectationsFactoryBrowser {
+ public:
+ FrameNavExpectationsFactoryBrowserTestSingleNavHarness() {}
+
+ ~FrameNavExpectationsFactoryBrowserTestSingleNavHarness() override {
+ EXPECT_TRUE(got_finalize_);
+ }
+
+ FrameNavFactoryId GetID() const override { return FNF_ID_SINGLE_NAV_HARNESS; }
+
+ bool HasMoreNavigations() const override {
+ EXPECT_FALSE(got_get_browser_navigation_count_);
+ got_get_browser_navigation_count_.yes();
+ return false;
+ }
+
+ bool Finalize() override {
+ EXPECT_FALSE(got_finalize_);
+ got_finalize_.yes();
+
+ V_DECLARE();
+ V_EXPECT_TRUE(got_get_browser_navigation_count_);
+ V_EXPECT_TRUE(got_create_);
+ V_RETURN();
+ }
+
+ protected:
+ std::unique_ptr<FrameNavExpectationsBrowser> Create(int nav) override {
+ EXPECT_FALSE(got_create_);
+ got_create_.yes();
+ return std::make_unique<FrameNavExpectationsBrowserTestSingleNavHarness>(
+ nav);
+ }
+
+ private:
+ mutable TrackCallback got_get_browser_navigation_count_;
+ TrackCallback got_create_;
+ TrackCallback got_finalize_;
+};
+
+class FrameNavExpectationsFactoryRendererTestSingleNavHarness
+ : public FrameNavExpectationsFactoryRenderer {
+ public:
+ FrameNavExpectationsFactoryRendererTestSingleNavHarness() {}
+
+ FrameNavFactoryId GetID() const override { return FNF_ID_SINGLE_NAV_HARNESS; }
+
+ protected:
+ std::unique_ptr<FrameNavExpectationsRenderer> Create(int nav) override {
+ return std::make_unique<FrameNavExpectationsRendererTestSingleNavHarness>(
+ nav);
+ }
+};
+
+} // namespace
+
+// Test that the single nav harness works.
+FRAME_TEST(SingleNavHarness, FNF_ID_SINGLE_NAV_HARNESS)
+
+namespace {
+
+bool VerifySingleBrowserFrame(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const std::string& expected_url) {
+ V_DECLARE();
+ V_EXPECT_TRUE(frame.get());
+ V_EXPECT_TRUE(frame->IsValid());
+ const int64 frame_id = frame->GetIdentifier();
+ V_EXPECT_TRUE(frame_id > 0) << frame_id;
+ V_EXPECT_TRUE(frame->IsValid());
+ V_EXPECT_TRUE(frame->IsMain());
+ V_EXPECT_TRUE(frame->IsFocused());
+ V_EXPECT_FALSE(frame->GetParent().get());
+ V_EXPECT_TRUE(frame->GetName().empty());
+ V_EXPECT_TRUE(browser->GetIdentifier() ==
+ frame->GetBrowser()->GetIdentifier());
+
+ const std::string& frame_url = frame->GetURL();
+ V_EXPECT_TRUE(frame_url == expected_url)
+ << "frame_url = " << frame_url << ", expected_url = " << expected_url;
+
+ V_RETURN();
+}
+
+bool VerifySingleBrowserFrames(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const std::string& expected_url) {
+ V_DECLARE();
+ V_EXPECT_TRUE(browser.get());
+
+ // |frame| may be nullptr for callbacks that don't specify one.
+ if (frame.get()) {
+ V_EXPECT_TRUE(VerifySingleBrowserFrame(browser, frame, expected_url));
+ }
+
+ CefRefPtr<CefFrame> main_frame = browser->GetMainFrame();
+ V_EXPECT_TRUE(VerifySingleBrowserFrame(browser, main_frame, expected_url));
+
+ CefRefPtr<CefFrame> focused_frame = browser->GetFocusedFrame();
+ V_EXPECT_TRUE(VerifySingleBrowserFrame(browser, focused_frame, expected_url));
+
+ size_t frame_count = browser->GetFrameCount();
+ V_EXPECT_TRUE(frame_count == 1U);
+
+ std::vector<int64> identifiers;
+ browser->GetFrameIdentifiers(identifiers);
+ V_EXPECT_TRUE(identifiers.size() == 1U);
+ if (identifiers.size() == 1U) {
+ V_EXPECT_TRUE(identifiers[0] == main_frame->GetIdentifier());
+ V_EXPECT_TRUE(identifiers[0] == focused_frame->GetIdentifier());
+ }
+
+ // Names may be empty for callbacks that execute while the frame is loading.
+ std::vector<CefString> names;
+ browser->GetFrameNames(names);
+ V_EXPECT_TRUE(names.size() <= 1U);
+ if (names.size() == 1U) {
+ V_EXPECT_TRUE(names[0].ToString() == main_frame->GetName().ToString());
+ V_EXPECT_TRUE(names[0].ToString() == focused_frame->GetName().ToString());
+ }
+
+ V_RETURN();
+}
+
+// Test that single navigation works.
+class FrameNavExpectationsBrowserTestSingleNav
+ : public FrameNavExpectationsBrowserSingleNav {
+ public:
+ typedef FrameNavExpectationsBrowserSingleNav parent;
+
+ explicit FrameNavExpectationsBrowserTestSingleNav(int nav) : parent(nav) {}
+
+ std::string GetMainURL() override { return kFrameNavOrigin0; }
+
+ std::string GetContentForURL(const std::string& url) override {
+ return "<html><body>Nav</body></html>";
+ }
+
+ bool OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
+ bool isLoading) override {
+ V_DECLARE();
+ V_EXPECT_TRUE(VerifySingleBrowserFrames(
+ browser, nullptr, isLoading ? std::string() : kFrameNavOrigin0));
+ V_EXPECT_TRUE(parent::OnLoadingStateChange(browser, isLoading));
+ V_RETURN();
+ }
+
+ bool OnLoadStart(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) override {
+ V_DECLARE();
+ V_EXPECT_TRUE(VerifySingleBrowserFrames(browser, frame, kFrameNavOrigin0));
+ V_EXPECT_TRUE(parent::OnLoadStart(browser, frame));
+ V_RETURN();
+ }
+
+ bool OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) override {
+ V_DECLARE();
+ V_EXPECT_TRUE(VerifySingleBrowserFrames(browser, frame, kFrameNavOrigin0));
+ V_EXPECT_TRUE(parent::OnLoadEnd(browser, frame));
+ V_RETURN();
+ }
+
+ bool OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
+ V_DECLARE();
+ V_EXPECT_TRUE(VerifySingleBrowserFrames(browser, nullptr, std::string()));
+ V_EXPECT_TRUE(parent::OnAfterCreated(browser));
+ V_RETURN();
+ }
+
+ bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const std::string& url) override {
+ V_DECLARE();
+ V_EXPECT_TRUE(VerifySingleBrowserFrames(browser, frame, std::string()));
+ V_EXPECT_TRUE(parent::OnBeforeBrowse(browser, frame, url));
+ V_RETURN();
+ }
+
+ bool GetResourceHandler(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) override {
+ V_DECLARE();
+ V_EXPECT_TRUE(VerifySingleBrowserFrames(browser, frame, std::string()));
+ V_EXPECT_TRUE(parent::GetResourceHandler(browser, frame));
+ V_RETURN();
+ }
+
+ bool OnRendererComplete(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int renderer_nav,
+ bool renderer_result) override {
+ return parent::OnRendererComplete(browser, frame, renderer_nav,
+ renderer_result);
+ }
+
+ bool Finalize() override { return parent::Finalize(); }
+};
+
+class FrameNavExpectationsRendererTestSingleNav
+ : public FrameNavExpectationsRendererSingleNav {
+ public:
+ typedef FrameNavExpectationsRendererSingleNav parent;
+
+ explicit FrameNavExpectationsRendererTestSingleNav(int nav) : parent(nav) {}
+
+ bool OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
+ bool isLoading) override {
+ V_DECLARE();
+ // A frame should always exist in the renderer process.
+ V_EXPECT_TRUE(
+ VerifySingleBrowserFrames(browser, nullptr, kFrameNavOrigin0));
+ V_EXPECT_TRUE(parent::OnLoadingStateChange(browser, isLoading));
+ V_RETURN();
+ }
+
+ bool OnLoadStart(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) override {
+ V_DECLARE();
+ V_EXPECT_TRUE(VerifySingleBrowserFrames(browser, frame, kFrameNavOrigin0));
+ V_EXPECT_TRUE(parent::OnLoadStart(browser, frame));
+ V_RETURN();
+ }
+
+ bool OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) override {
+ V_DECLARE();
+ V_EXPECT_TRUE(VerifySingleBrowserFrames(browser, frame, kFrameNavOrigin0));
+ V_EXPECT_TRUE(parent::OnLoadEnd(browser, frame));
+ V_RETURN();
+ }
+
+ bool Finalize() override { return parent::Finalize(); }
+};
+
+class FrameNavExpectationsFactoryBrowserTestSingleNav
+ : public FrameNavExpectationsFactoryBrowser {
+ public:
+ FrameNavExpectationsFactoryBrowserTestSingleNav() {}
+
+ FrameNavFactoryId GetID() const override { return FNF_ID_SINGLE_NAV; }
+
+ bool HasMoreNavigations() const override { return false; }
+
+ bool Finalize() override { return true; }
+
+ protected:
+ std::unique_ptr<FrameNavExpectationsBrowser> Create(int nav) override {
+ return std::make_unique<FrameNavExpectationsBrowserTestSingleNav>(nav);
+ }
+};
+
+class FrameNavExpectationsFactoryRendererTestSingleNav
+ : public FrameNavExpectationsFactoryRenderer {
+ public:
+ FrameNavExpectationsFactoryRendererTestSingleNav() {}
+
+ FrameNavFactoryId GetID() const override { return FNF_ID_SINGLE_NAV; }
+
+ protected:
+ std::unique_ptr<FrameNavExpectationsRenderer> Create(int nav) override {
+ return std::make_unique<FrameNavExpectationsRendererTestSingleNav>(nav);
+ }
+};
+
+} // namespace
+
+// Test that single navigation works.
+FRAME_TEST(SingleNav, FNF_ID_SINGLE_NAV)
+
+namespace {
+
+// Browser process expectations for a multiple navigations.
+class FrameNavExpectationsBrowserMultiNav : public FrameNavExpectationsBrowser {
+ public:
+ explicit FrameNavExpectationsBrowserMultiNav(int nav)
+ : FrameNavExpectationsBrowser(nav) {}
+
+ ~FrameNavExpectationsBrowserMultiNav() override {
+ EXPECT_TRUE(got_finalize_);
+ }
+
+ // Returns true if all navigation is done.
+ virtual bool IsNavigationDone() const = 0;
+
+ bool OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
+ bool isLoading) override {
+ if (!isLoading) {
+ SignalCompleteIfDone(browser, browser->GetMainFrame());
+ }
+ return true;
+ }
+
+ bool OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) override {
+ SignalCompleteIfDone(browser, frame);
+ return true;
+ }
+
+ bool OnRendererComplete(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int renderer_nav,
+ bool renderer_result) override {
+ EXPECT_TRUE(renderer_result);
+ SignalCompleteIfDone(browser, frame);
+ return true;
+ }
+
+ bool Finalize() override {
+ V_DECLARE();
+ V_EXPECT_FALSE(got_finalize_);
+
+ got_finalize_.yes();
+
+ V_RETURN();
+ }
+
+ private:
+ void SignalCompleteIfDone(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) {
+ if (IsNavigationDone()) {
+ SignalComplete(browser, frame);
+ }
+ }
+
+ TrackCallback got_finalize_;
+};
+
+// Renderer process expectations for a multiple navigations.
+class FrameNavExpectationsRendererMultiNav
+ : public FrameNavExpectationsRenderer {
+ public:
+ explicit FrameNavExpectationsRendererMultiNav(int nav)
+ : FrameNavExpectationsRenderer(nav) {}
+
+ ~FrameNavExpectationsRendererMultiNav() override {
+ EXPECT_TRUE(got_finalize_);
+ }
+
+ // Returns true if all navigation is done.
+ virtual bool IsNavigationDone() const = 0;
+
+ bool OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
+ bool isLoading) override {
+ if (!isLoading) {
+ SignalCompleteIfDone(browser, browser->GetMainFrame());
+ }
+ return true;
+ }
+
+ bool OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) override {
+ SignalCompleteIfDone(browser, frame);
+ return true;
+ }
+
+ bool Finalize() override {
+ V_DECLARE();
+ V_EXPECT_FALSE(got_finalize_);
+
+ got_finalize_.yes();
+
+ V_RETURN();
+ }
+
+ private:
+ void SignalCompleteIfDone(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) {
+ if (IsNavigationDone()) {
+ SignalComplete(browser, frame);
+ }
+ }
+
+ TrackCallback got_finalize_;
+};
+
+// Create a URL containing the nav number.
+std::string GetMultiNavURL(const std::string& origin, int nav) {
+ std::stringstream ss;
+ ss << origin << "nav" << nav << ".html";
+ return ss.str();
+}
+
+// Extract the nav number from the URL.
+int GetNavFromMultiNavURL(const std::string& url) {
+ const size_t start = url.find("/nav");
+ const size_t end = url.find(".html", start);
+ EXPECT_TRUE(start < end && start > 0U);
+ const std::string& nav = url.substr(start + 4, end - start - 4);
+ return atoi(nav.c_str());
+}
+
+// Extract the origin from the URL.
+std::string GetOriginFromMultiNavURL(const std::string& url) {
+ const size_t pos = url.rfind("/");
+ EXPECT_TRUE(pos > 0U);
+ return url.substr(0, pos + 1);
+}
+
+// Test that the multi nav harness works.
+class FrameNavExpectationsBrowserTestMultiNavHarness
+ : public FrameNavExpectationsBrowserMultiNav {
+ public:
+ typedef FrameNavExpectationsBrowserMultiNav parent;
+
+ explicit FrameNavExpectationsBrowserTestMultiNavHarness(int nav)
+ : parent(nav), navigation_done_count_(0) {}
+
+ ~FrameNavExpectationsBrowserTestMultiNavHarness() override {
+ EXPECT_TRUE(got_finalize_);
+ }
+
+ std::string GetMainURL() override {
+ EXPECT_FALSE(got_get_main_url_);
+ got_get_main_url_.yes();
+ return GetMultiNavURL(kFrameNavOrigin0, nav());
+ }
+
+ std::string GetContentForURL(const std::string& url) override {
+ EXPECT_FALSE(got_get_content_for_url_);
+ got_get_content_for_url_.yes();
+ EXPECT_STREQ(GetMultiNavURL(kFrameNavOrigin0, nav()).c_str(), url.c_str());
+ return "<html><body>Nav</body></html>";
+ }
+
+ bool IsNavigationDone() const override {
+ navigation_done_count_++;
+ return got_load_state_change_done_ && got_load_end_ &&
+ got_renderer_complete_;
+ }
+
+ bool OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
+ bool isLoading) override {
+ if (!isLoading) {
+ EXPECT_FALSE(got_load_state_change_done_);
+ got_load_state_change_done_.yes();
+ }
+ return parent::OnLoadingStateChange(browser, isLoading);
+ }
+
+ bool OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) override {
+ EXPECT_FALSE(got_load_end_);
+ got_load_end_.yes();
+ return parent::OnLoadEnd(browser, frame);
+ }
+
+ bool OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
+ EXPECT_FALSE(got_on_after_created_);
+ got_on_after_created_.yes();
+ return parent::OnAfterCreated(browser);
+ }
+
+ bool OnRendererComplete(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int renderer_nav,
+ bool renderer_result) override {
+ EXPECT_FALSE(got_renderer_complete_);
+ got_renderer_complete_.yes();
+ EXPECT_EQ(nav(), renderer_nav);
+ return parent::OnRendererComplete(browser, frame, renderer_nav,
+ renderer_result);
+ }
+
+ bool Finalize() override {
+ EXPECT_FALSE(got_finalize_);
+ got_finalize_.yes();
+
+ V_DECLARE();
+ V_EXPECT_TRUE(got_get_main_url_);
+ V_EXPECT_TRUE(got_get_content_for_url_);
+ V_EXPECT_TRUE(got_load_state_change_done_);
+ V_EXPECT_TRUE(got_load_end_);
+ if (nav() == 0) {
+ V_EXPECT_TRUE(got_on_after_created_);
+ } else {
+ V_EXPECT_FALSE(got_on_after_created_);
+ }
+ V_EXPECT_TRUE(got_renderer_complete_);
+ V_EXPECT_TRUE(navigation_done_count_ == 3);
+ V_EXPECT_TRUE(parent::Finalize());
+ V_RETURN();
+ }
+
+ private:
+ TrackCallback got_get_main_url_;
+ TrackCallback got_get_content_for_url_;
+ TrackCallback got_load_state_change_done_;
+ TrackCallback got_load_end_;
+ TrackCallback got_on_after_created_;
+ TrackCallback got_renderer_complete_;
+ mutable int navigation_done_count_;
+ TrackCallback got_finalize_;
+};
+
+class FrameNavExpectationsRendererTestMultiNavHarness
+ : public FrameNavExpectationsRendererMultiNav {
+ public:
+ typedef FrameNavExpectationsRendererMultiNav parent;
+
+ explicit FrameNavExpectationsRendererTestMultiNavHarness(int nav)
+ : parent(nav), navigation_done_count_(0) {}
+
+ ~FrameNavExpectationsRendererTestMultiNavHarness() override {
+ EXPECT_TRUE(got_finalize_);
+ }
+
+ bool IsNavigationDone() const override {
+ navigation_done_count_++;
+ return got_load_state_change_done_ && got_load_end_;
+ }
+
+ bool OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
+ bool isLoading) override {
+ if (!isLoading) {
+ EXPECT_FALSE(got_load_state_change_done_);
+ got_load_state_change_done_.yes();
+ }
+ return parent::OnLoadingStateChange(browser, isLoading);
+ }
+
+ bool OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) override {
+ EXPECT_FALSE(got_load_end_);
+ got_load_end_.yes();
+ return parent::OnLoadEnd(browser, frame);
+ }
+
+ bool Finalize() override {
+ EXPECT_FALSE(got_finalize_);
+ got_finalize_.yes();
+
+ V_DECLARE();
+ V_EXPECT_TRUE(got_load_state_change_done_);
+ V_EXPECT_TRUE(got_load_end_);
+ V_EXPECT_TRUE(navigation_done_count_ == 2);
+ V_EXPECT_TRUE(parent::Finalize());
+ V_RETURN();
+ }
+
+ private:
+ TrackCallback got_load_state_change_done_;
+ TrackCallback got_load_end_;
+ mutable int navigation_done_count_;
+ TrackCallback got_finalize_;
+};
+
+class FrameNavExpectationsFactoryBrowserTestMultiNavHarness
+ : public FrameNavExpectationsFactoryBrowser {
+ public:
+ FrameNavExpectationsFactoryBrowserTestMultiNavHarness()
+ : get_browser_navigation_count_(0), create_count_(0) {}
+
+ ~FrameNavExpectationsFactoryBrowserTestMultiNavHarness() override {
+ EXPECT_TRUE(got_finalize_);
+ }
+
+ FrameNavFactoryId GetID() const override { return FNF_ID_MULTI_NAV_HARNESS; }
+
+ bool HasMoreNavigations() const override {
+ get_browser_navigation_count_++;
+ return (get_browser_navigation_count_ < kMaxMultiNavNavigations);
+ }
+
+ bool Finalize() override {
+ EXPECT_FALSE(got_finalize_);
+ got_finalize_.yes();
+
+ V_DECLARE();
+ V_EXPECT_TRUE(get_browser_navigation_count_ == kMaxMultiNavNavigations);
+ V_EXPECT_TRUE(create_count_ == kMaxMultiNavNavigations);
+ V_RETURN();
+ }
+
+ protected:
+ std::unique_ptr<FrameNavExpectationsBrowser> Create(int nav) override {
+ create_count_++;
+ return std::make_unique<FrameNavExpectationsBrowserTestMultiNavHarness>(
+ nav);
+ }
+
+ private:
+ mutable int get_browser_navigation_count_;
+ int create_count_;
+ TrackCallback got_finalize_;
+};
+
+class FrameNavExpectationsFactoryRendererTestMultiNavHarness
+ : public FrameNavExpectationsFactoryRenderer {
+ public:
+ FrameNavExpectationsFactoryRendererTestMultiNavHarness() {}
+
+ FrameNavFactoryId GetID() const override { return FNF_ID_MULTI_NAV_HARNESS; }
+
+ protected:
+ std::unique_ptr<FrameNavExpectationsRenderer> Create(int nav) override {
+ return std::make_unique<FrameNavExpectationsRendererTestMultiNavHarness>(
+ nav);
+ }
+};
+
+} // namespace
+
+// Test that the multiple nav harness works.
+FRAME_TEST(MultiNavHarness, FNF_ID_MULTI_NAV_HARNESS)
+
+namespace {
+
+// Test that multiple navigation works.
+class FrameNavExpectationsBrowserTestMultiNav
+ : public FrameNavExpectationsBrowserMultiNav {
+ public:
+ typedef FrameNavExpectationsBrowserMultiNav parent;
+
+ explicit FrameNavExpectationsBrowserTestMultiNav(int nav) : parent(nav) {}
+
+ std::string GetMainURL() override {
+ return GetMultiNavURL(kFrameNavOrigin0, nav());
+ }
+
+ std::string GetContentForURL(const std::string& url) override {
+ return "<html><body>Nav</body></html>";
+ }
+
+ bool IsNavigationDone() const override {
+ return got_load_state_change_done_ && got_load_end_ &&
+ got_renderer_complete_;
+ }
+
+ bool OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
+ bool isLoading) override {
+ if (!isLoading) {
+ got_load_state_change_done_.yes();
+ }
+ V_DECLARE();
+ if (isLoading && nav() == 0) {
+ V_EXPECT_TRUE(VerifySingleBrowserFrames(browser, nullptr, std::string()));
+ } else if (isLoading) {
+ // Expect the URL from the previous load.
+ V_EXPECT_TRUE(
+ VerifySingleBrowserFrames(browser, nullptr, GetPreviousMainURL()));
+ } else {
+ V_EXPECT_TRUE(VerifySingleBrowserFrames(browser, nullptr, GetMainURL()));
+ }
+ V_EXPECT_TRUE(parent::OnLoadingStateChange(browser, isLoading));
+ V_RETURN();
+ }
+
+ bool OnLoadStart(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) override {
+ V_DECLARE();
+ V_EXPECT_TRUE(VerifySingleBrowserFrames(browser, frame, GetMainURL()));
+ V_EXPECT_TRUE(parent::OnLoadStart(browser, frame));
+ V_RETURN();
+ }
+
+ bool OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) override {
+ got_load_end_.yes();
+ V_DECLARE();
+ V_EXPECT_TRUE(VerifySingleBrowserFrames(browser, frame, GetMainURL()));
+ V_EXPECT_TRUE(parent::OnLoadEnd(browser, frame));
+ V_RETURN();
+ }
+
+ bool OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
+ V_DECLARE();
+ V_EXPECT_TRUE(VerifySingleBrowserFrames(browser, nullptr, std::string()));
+ V_EXPECT_TRUE(parent::OnAfterCreated(browser));
+ V_RETURN();
+ }
+
+ bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const std::string& url) override {
+ V_DECLARE();
+ std::string expected_url;
+ if (nav() > 0) {
+ expected_url = GetPreviousMainURL();
+ }
+ V_EXPECT_TRUE(VerifySingleBrowserFrames(browser, frame, expected_url));
+ V_EXPECT_TRUE(parent::OnBeforeBrowse(browser, frame, url));
+ V_RETURN();
+ }
+
+ bool GetResourceHandler(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) override {
+ V_DECLARE();
+ std::string expected_url;
+ if (nav() > 0) {
+ expected_url = GetPreviousMainURL();
+ }
+ V_EXPECT_TRUE(VerifySingleBrowserFrames(browser, frame, expected_url));
+ V_EXPECT_TRUE(parent::GetResourceHandler(browser, frame));
+ V_RETURN();
+ }
+
+ bool OnRendererComplete(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int renderer_nav,
+ bool renderer_result) override {
+ got_renderer_complete_.yes();
+ V_DECLARE();
+ V_EXPECT_TRUE(nav() == renderer_nav);
+ V_EXPECT_TRUE(parent::OnRendererComplete(browser, frame, renderer_nav,
+ renderer_result));
+ V_RETURN();
+ }
+
+ bool Finalize() override {
+ V_DECLARE();
+ V_EXPECT_TRUE(got_load_state_change_done_);
+ V_EXPECT_TRUE(got_load_end_);
+ V_EXPECT_TRUE(got_renderer_complete_);
+ V_EXPECT_TRUE(parent::Finalize());
+ V_RETURN();
+ }
+
+ private:
+ // Helper for VerifySingleBrowserFrames.
+ std::string GetPreviousMainURL() {
+ EXPECT_GT(nav(), 0);
+ return GetMultiNavURL(kFrameNavOrigin0, nav() - 1);
+ }
+
+ TrackCallback got_load_state_change_done_;
+ TrackCallback got_load_end_;
+ TrackCallback got_renderer_complete_;
+};
+
+class FrameNavExpectationsRendererTestMultiNav
+ : public FrameNavExpectationsRendererMultiNav {
+ public:
+ typedef FrameNavExpectationsRendererMultiNav parent;
+
+ explicit FrameNavExpectationsRendererTestMultiNav(int nav) : parent(nav) {}
+
+ bool IsNavigationDone() const override {
+ return got_load_state_change_done_ && got_load_end_;
+ }
+
+ bool OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
+ bool isLoading) override {
+ if (!isLoading) {
+ got_load_state_change_done_.yes();
+ }
+ V_DECLARE();
+ V_EXPECT_TRUE(VerifySingleBrowserFrames(browser, nullptr, GetMainURL()));
+ V_EXPECT_TRUE(parent::OnLoadingStateChange(browser, isLoading));
+ V_RETURN();
+ }
+
+ bool OnLoadStart(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) override {
+ V_DECLARE();
+ V_EXPECT_TRUE(VerifySingleBrowserFrames(browser, frame, GetMainURL()));
+ V_EXPECT_TRUE(parent::OnLoadStart(browser, frame));
+ V_RETURN();
+ }
+
+ bool OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) override {
+ got_load_end_.yes();
+ V_DECLARE();
+ V_EXPECT_TRUE(VerifySingleBrowserFrames(browser, frame, GetMainURL()));
+ V_EXPECT_TRUE(parent::OnLoadEnd(browser, frame));
+ V_RETURN();
+ }
+
+ bool Finalize() override {
+ V_DECLARE();
+ V_EXPECT_TRUE(got_load_state_change_done_);
+ V_EXPECT_TRUE(got_load_end_);
+ V_EXPECT_TRUE(parent::Finalize());
+ V_RETURN();
+ }
+
+ private:
+ // Helpers for calling VerifySingleBrowserFrames.
+ std::string GetMainURL() const {
+ return GetMultiNavURL(kFrameNavOrigin0, nav());
+ }
+ std::string GetPreviousMainURL() {
+ EXPECT_GT(nav(), 0);
+ return GetMultiNavURL(kFrameNavOrigin0, nav() - 1);
+ }
+
+ TrackCallback got_load_state_change_done_;
+ TrackCallback got_load_end_;
+};
+
+class FrameNavExpectationsFactoryBrowserTestMultiNav
+ : public FrameNavExpectationsFactoryBrowser {
+ public:
+ FrameNavExpectationsFactoryBrowserTestMultiNav() : nav_count_(0) {}
+
+ FrameNavFactoryId GetID() const override { return FNF_ID_MULTI_NAV; }
+
+ bool HasMoreNavigations() const override {
+ return (nav_count_ < kMaxMultiNavNavigations);
+ }
+
+ bool Finalize() override {
+ V_DECLARE();
+ V_EXPECT_TRUE(nav_count_ == kMaxMultiNavNavigations);
+ V_RETURN();
+ }
+
+ protected:
+ std::unique_ptr<FrameNavExpectationsBrowser> Create(int nav) override {
+ nav_count_++;
+ return std::make_unique<FrameNavExpectationsBrowserTestMultiNav>(nav);
+ }
+
+ private:
+ int nav_count_;
+};
+
+class FrameNavExpectationsFactoryRendererTestMultiNav
+ : public FrameNavExpectationsFactoryRenderer {
+ public:
+ FrameNavExpectationsFactoryRendererTestMultiNav() {}
+
+ FrameNavFactoryId GetID() const override { return FNF_ID_MULTI_NAV; }
+
+ protected:
+ std::unique_ptr<FrameNavExpectationsRenderer> Create(int nav) override {
+ return std::make_unique<FrameNavExpectationsRendererTestMultiNav>(nav);
+ }
+};
+
+} // namespace
+
+// Test that multiple navigation works.
+FRAME_TEST(MultiNav, FNF_ID_MULTI_NAV)
+
+namespace {
+
+const char kFrame0Name[] = "";
+const char kFrame1Name[] = "nav2";
+const char kFrame2Name[] = "<!--framePath //nav2/<!--frame0-->-->";
+const char kFrame3Name[] = "nav3";
+
+bool VerifyBrowserIframe(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const std::string& origin,
+ int frame_number) {
+ V_DECLARE();
+
+ // frame0 contains frame1 contains frame2, contains frame3.
+ CefRefPtr<CefFrame> frame0, frame1, frame2, frame3;
+ CefRefPtr<CefFrame> frame0b, frame1b, frame2b, frame3b;
+ int64 frame0id, frame1id, frame2id, frame3id;
+ std::string frame0url, frame1url, frame2url, frame3url;
+
+ // Verify the GetFrameNames result.
+ std::set<std::string> expected_names = {kFrame0Name, kFrame1Name, kFrame2Name,
+ kFrame3Name};
+
+ std::vector<CefString> names;
+ browser->GetFrameNames(names);
+ V_EXPECT_TRUE(names.size() == expected_names.size())
+ << "expected: " << expected_names.size() << " actual: " << names.size();
+
+ for (const auto& name : names) {
+ const std::string& nameStr = name;
+ auto it = expected_names.find(nameStr);
+ V_EXPECT_FALSE(it == expected_names.end())
+ << "Unexpected name: \"" << nameStr << "\"";
+ if (it != expected_names.end()) {
+ expected_names.erase(it);
+ }
+ }
+
+ for (const auto& name : expected_names) {
+ V_EXPECT_FALSE(true) << "Missing name: \"" << name << "\"";
+ }
+
+ // Find frames by name.
+ frame0 = browser->GetFrame(kFrame0Name);
+ V_EXPECT_TRUE(frame0.get());
+ frame1 = browser->GetFrame(kFrame1Name);
+ V_EXPECT_TRUE(frame1.get());
+ frame2 = browser->GetFrame(kFrame2Name);
+ V_EXPECT_TRUE(frame2.get());
+ frame3 = browser->GetFrame(kFrame3Name);
+ V_EXPECT_TRUE(frame3.get());
+
+ if (!frame0 || !frame1 || !frame2 || !frame3) {
+ V_RETURN();
+ }
+
+ // Verify that the name matches.
+ V_EXPECT_TRUE(frame0->GetName().ToString() == kFrame0Name)
+ << "expected: " << kFrame0Name
+ << " actual: " << frame0->GetName().ToString();
+ V_EXPECT_TRUE(frame1->GetName().ToString() == kFrame1Name)
+ << "expected: " << kFrame1Name
+ << " actual: " << frame1->GetName().ToString();
+ V_EXPECT_TRUE(frame2->GetName().ToString() == kFrame2Name)
+ << "expected: " << kFrame2Name
+ << " actual: " << frame2->GetName().ToString();
+ V_EXPECT_TRUE(frame3->GetName().ToString() == kFrame3Name)
+ << "expected: " << kFrame3Name
+ << " actual: " << frame3->GetName().ToString();
+
+ // Verify that the URL matches.
+ frame0url = GetMultiNavURL(origin, 0);
+ V_EXPECT_TRUE(frame0->GetURL() == frame0url)
+ << "expected: " << frame0url
+ << " actual: " << frame0->GetURL().ToString();
+ frame1url = GetMultiNavURL(origin, 1);
+ V_EXPECT_TRUE(frame1->GetURL() == frame1url)
+ << "expected: " << frame1url
+ << " actual: " << frame1->GetURL().ToString();
+ frame2url = GetMultiNavURL(origin, 2);
+ V_EXPECT_TRUE(frame2->GetURL() == frame2url)
+ << "expected: " << frame2url
+ << " actual: " << frame2->GetURL().ToString();
+ frame3url = GetMultiNavURL(origin, 3);
+ V_EXPECT_TRUE(frame3->GetURL() == frame3url)
+ << "expected: " << frame3url
+ << " actual: " << frame3->GetURL().ToString();
+
+ // Verify that the frame id is valid.
+ frame0id = frame0->GetIdentifier();
+ V_EXPECT_TRUE(frame0id > 0) << "actual: " << frame0id;
+ frame1id = frame1->GetIdentifier();
+ V_EXPECT_TRUE(frame1id > 0) << "actual: " << frame1id;
+ frame2id = frame2->GetIdentifier();
+ V_EXPECT_TRUE(frame2id > 0) << "actual: " << frame2id;
+ frame3id = frame3->GetIdentifier();
+ V_EXPECT_TRUE(frame3id > 0) << "actual: " << frame3id;
+
+ // Verify that the current frame has the correct id.
+ if (frame_number == 0) {
+ V_EXPECT_TRUE(frame->GetIdentifier() == frame0id)
+ << "expected: " << frame0id << " actual: " << frame->GetIdentifier();
+ } else if (frame_number == 1) {
+ V_EXPECT_TRUE(frame->GetIdentifier() == frame1id)
+ << "expected: " << frame1id << " actual: " << frame->GetIdentifier();
+ } else if (frame_number == 2) {
+ V_EXPECT_TRUE(frame->GetIdentifier() == frame2id)
+ << "expected: " << frame2id << " actual: " << frame->GetIdentifier();
+ } else if (frame_number == 3) {
+ V_EXPECT_TRUE(frame->GetIdentifier() == frame3id)
+ << "expected: " << frame3id << " actual: " << frame->GetIdentifier();
+ }
+
+ // Find frames by id.
+ frame0b = browser->GetFrame(frame0->GetIdentifier());
+ V_EXPECT_TRUE(frame0b.get());
+ frame1b = browser->GetFrame(frame1->GetIdentifier());
+ V_EXPECT_TRUE(frame1b.get());
+ frame2b = browser->GetFrame(frame2->GetIdentifier());
+ V_EXPECT_TRUE(frame2b.get());
+ frame3b = browser->GetFrame(frame3->GetIdentifier());
+ V_EXPECT_TRUE(frame3b.get());
+
+ if (!frame0b || !frame1b || !frame2b || !frame3b) {
+ V_RETURN();
+ }
+
+ // Verify that the id matches.
+ V_EXPECT_TRUE(frame0b->GetIdentifier() == frame0id)
+ << "expected: " << frame0id << " actual: " << frame0b->GetIdentifier();
+ V_EXPECT_TRUE(frame1b->GetIdentifier() == frame1id)
+ << "expected: " << frame1id << " actual: " << frame1b->GetIdentifier();
+ V_EXPECT_TRUE(frame2b->GetIdentifier() == frame2id)
+ << "expected: " << frame2id << " actual: " << frame2b->GetIdentifier();
+ V_EXPECT_TRUE(frame3b->GetIdentifier() == frame3id)
+ << "expected: " << frame3id << " actual: " << frame3b->GetIdentifier();
+
+ size_t frame_count = browser->GetFrameCount();
+ V_EXPECT_TRUE(frame_count == 4U) << " actual: " << frame_count;
+
+ // Verify the GetFrameIdentifiers result.
+ std::set<int64> expected_idents = {frame0id, frame1id, frame2id, frame3id};
+
+ std::vector<int64> idents;
+ browser->GetFrameIdentifiers(idents);
+ V_EXPECT_TRUE(idents.size() == expected_idents.size())
+ << "expected: " << expected_idents.size() << " actual: " << idents.size();
+
+ for (const auto& ident : idents) {
+ auto it = expected_idents.find(ident);
+ V_EXPECT_FALSE(it == expected_idents.end()) << "Unexpected id: " << ident;
+ if (it != expected_idents.end()) {
+ expected_idents.erase(it);
+ }
+ }
+
+ for (const auto& ident : expected_idents) {
+ V_EXPECT_FALSE(true) << "Missing id: " << ident;
+ }
+
+ // Verify parent hierarchy.
+ V_EXPECT_FALSE(frame0->GetParent().get());
+ V_EXPECT_TRUE(frame1->GetParent()->GetIdentifier() == frame0id)
+ << "expected: " << frame0id
+ << " actual: " << frame1->GetParent()->GetIdentifier();
+ V_EXPECT_TRUE(frame2->GetParent()->GetIdentifier() == frame1id)
+ << "expected: " << frame1id
+ << " actual: " << frame2->GetParent()->GetIdentifier();
+ V_EXPECT_TRUE(frame3->GetParent()->GetIdentifier() == frame2id)
+ << "expected: " << frame2id
+ << " actual: " << frame3->GetParent()->GetIdentifier();
+
+ V_RETURN();
+}
+
+// Test that nested iframes work.
+class FrameNavExpectationsBrowserTestNestedIframes
+ : public FrameNavExpectationsBrowserMultiNav {
+ public:
+ typedef FrameNavExpectationsBrowserMultiNav parent;
+
+ FrameNavExpectationsBrowserTestNestedIframes(int nav, bool same_origin)
+ : parent(nav), same_origin_(same_origin) {
+ // In the browser process we can rely on the |nav| value to determine the
+ // origin.
+ if (same_origin) {
+ origin_ = kFrameNavOrigin0;
+ } else {
+ switch (nav) {
+ case 0:
+ origin_ = kFrameNavOrigin0;
+ break;
+ case 1:
+ origin_ = kFrameNavOrigin1;
+ break;
+ case 2:
+ origin_ = kFrameNavOrigin2;
+ break;
+ case 3:
+ origin_ = kFrameNavOrigin3;
+ break;
+ default:
+ EXPECT_TRUE(false); // Not reached.
+ break;
+ }
+ }
+ }
+
+ std::string GetMainURL() override {
+ // Load the first (main) frame.
+ return GetMultiNavURL(origin_, 0);
+ }
+
+ std::string GetContentForURL(const std::string& url) override {
+ const int frame_number = GetNavFromMultiNavURL(url);
+ switch (frame_number) {
+ case 0:
+ // Frame 0. Contains a named iframe.
+ return "<html><body>Nav1<iframe src=\"" + GetMultiNavURL(origin_, 1) +
+ "\" name=\"nav2\"></body></html>";
+ case 1:
+ // Frame 1. Contains an unnamed iframe.
+ return "<html><body>Nav2<iframe src=\"" + GetMultiNavURL(origin_, 2) +
+ "\"></body></html>";
+ case 2: {
+ // Frame 2. Contains an named iframe created via javascript.
+ std::stringstream ss;
+ ss << "<html><script>"
+ << " function createFrame() {"
+ << " var f = document.createElement('iframe');"
+ << " f.name = 'nav3';"
+ << " f.src = '" << GetMultiNavURL(origin_, 3) << "';"
+ << " document.body.appendChild(f);"
+ << " }</script><body onload=\"createFrame()\">Nav3</body></html>";
+ return ss.str();
+ }
+ case 3:
+ // Frame 3.
+ return "<html><body>Nav4</body></html>";
+ default:
+ EXPECT_TRUE(false); // Not reached.
+ return "";
+ }
+ }
+
+ bool IsNavigationDone() const override {
+ return got_load_state_change_done_ && got_renderer_complete_ &&
+ got_load_end_[0] && got_load_end_[1] && got_load_end_[2] &&
+ got_load_end_[3];
+ }
+
+ bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const std::string& url) override {
+ V_DECLARE();
+ V_EXPECT_TRUE(frame.get());
+ const int frame_number = GetNavFromMultiNavURL(url);
+ if (frame_number == 0) {
+ // Main frame.
+ V_EXPECT_TRUE(frame->IsMain());
+ } else {
+ // Sub frame.
+ V_EXPECT_FALSE(frame->IsMain());
+ }
+ V_EXPECT_TRUE(parent::OnBeforeBrowse(browser, frame, url));
+ V_RETURN();
+ }
+
+ bool OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
+ bool isLoading) override {
+ V_DECLARE();
+ V_EXPECT_FALSE(got_load_state_change_done_);
+
+ if (!isLoading) {
+ got_load_state_change_done_.yes();
+ }
+
+ V_EXPECT_TRUE(parent::OnLoadingStateChange(browser, isLoading));
+ V_RETURN();
+ }
+
+ bool OnLoadStart(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) override {
+ const int frame_number = GetNavFromMultiNavURL(frame->GetURL());
+
+ V_DECLARE();
+ V_EXPECT_FALSE(got_load_start_[frame_number]);
+ V_EXPECT_FALSE(got_load_end_[frame_number]);
+
+ // Notification should be received for parent frame before child frame.
+ if (frame_number == 0) {
+ V_EXPECT_FALSE(got_load_start_[1]);
+ V_EXPECT_FALSE(got_load_start_[2]);
+ V_EXPECT_FALSE(got_load_start_[3]);
+ } else if (frame_number == 1) {
+ V_EXPECT_TRUE(got_load_start_[0]);
+ V_EXPECT_FALSE(got_load_start_[2]);
+ V_EXPECT_FALSE(got_load_start_[3]);
+ } else if (frame_number == 2) {
+ V_EXPECT_TRUE(got_load_start_[0]);
+ V_EXPECT_TRUE(got_load_start_[1]);
+ V_EXPECT_FALSE(got_load_start_[3]);
+ } else if (frame_number == 3) {
+ V_EXPECT_TRUE(got_load_start_[0]);
+ V_EXPECT_TRUE(got_load_start_[1]);
+ V_EXPECT_TRUE(got_load_start_[2]);
+ } else {
+ V_EXPECT_TRUE(false); // Not reached.
+ }
+
+ got_load_start_[frame_number].yes();
+
+ V_EXPECT_TRUE(parent::OnLoadStart(browser, frame));
+ V_RETURN();
+ }
+
+ bool OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) override {
+ const int frame_number = GetNavFromMultiNavURL(frame->GetURL());
+
+ V_DECLARE();
+ V_EXPECT_TRUE(got_load_start_[frame_number]);
+ V_EXPECT_FALSE(got_load_end_[frame_number]);
+
+ // Notification should be received for child frame before parent frame.
+ if (frame_number == 0) {
+ V_EXPECT_TRUE(got_load_end_[1]);
+ V_EXPECT_TRUE(got_load_end_[2]);
+ V_EXPECT_TRUE(got_load_end_[3]);
+ } else if (frame_number == 1) {
+ V_EXPECT_FALSE(got_load_end_[0]);
+ V_EXPECT_TRUE(got_load_end_[2]);
+ V_EXPECT_TRUE(got_load_end_[3]);
+ } else if (frame_number == 2) {
+ V_EXPECT_FALSE(got_load_end_[0]);
+ V_EXPECT_FALSE(got_load_end_[1]);
+ V_EXPECT_TRUE(got_load_end_[3]);
+ } else if (frame_number == 3) {
+ V_EXPECT_FALSE(got_load_end_[0]);
+ V_EXPECT_FALSE(got_load_end_[1]);
+ V_EXPECT_FALSE(got_load_end_[2]);
+ } else {
+ V_EXPECT_TRUE(false); // Not reached.
+ }
+
+ V_EXPECT_TRUE(VerifyBrowserIframe(browser, frame, origin_, frame_number))
+ << "frame_number = " << frame_number;
+
+ got_load_end_[frame_number].yes();
+
+ V_EXPECT_TRUE(parent::OnLoadEnd(browser, frame));
+ V_RETURN();
+ }
+
+ bool OnRendererComplete(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int renderer_nav,
+ bool renderer_result) override {
+ V_DECLARE();
+ V_EXPECT_FALSE(got_renderer_complete_);
+ if (same_origin_) {
+ V_EXPECT_TRUE(renderer_nav == nav());
+ } else {
+ // Because each navigation is in a new renderer process.
+ V_EXPECT_TRUE(renderer_nav == 0);
+ }
+
+ got_renderer_complete_.yes();
+
+ V_EXPECT_TRUE(parent::OnRendererComplete(browser, frame, renderer_nav,
+ renderer_result));
+ V_RETURN();
+ }
+
+ bool Finalize() override {
+ V_DECLARE();
+ V_EXPECT_TRUE(got_load_state_change_done_);
+ V_EXPECT_TRUE(got_load_start_[0]);
+ V_EXPECT_TRUE(got_load_start_[1]);
+ V_EXPECT_TRUE(got_load_start_[2]);
+ V_EXPECT_TRUE(got_load_start_[3]);
+ V_EXPECT_TRUE(got_load_end_[0]);
+ V_EXPECT_TRUE(got_load_end_[1]);
+ V_EXPECT_TRUE(got_load_end_[2]);
+ V_EXPECT_TRUE(got_load_end_[3]);
+ V_EXPECT_TRUE(got_renderer_complete_);
+ V_EXPECT_TRUE(parent::Finalize());
+ V_RETURN();
+ }
+
+ private:
+ bool same_origin_;
+ std::string origin_;
+
+ TrackCallback got_load_state_change_done_;
+ TrackCallback got_load_start_[4];
+ TrackCallback got_load_end_[4];
+ TrackCallback got_renderer_complete_;
+};
+
+class FrameNavExpectationsRendererTestNestedIframes
+ : public FrameNavExpectationsRendererMultiNav {
+ public:
+ typedef FrameNavExpectationsRendererMultiNav parent;
+
+ FrameNavExpectationsRendererTestNestedIframes(int nav, bool same_origin)
+ : parent(nav) {
+ if (same_origin) {
+ origin_ = kFrameNavOrigin0;
+ }
+ }
+
+ bool IsNavigationDone() const override {
+ return got_load_state_change_done_ && got_load_end_[0] &&
+ got_load_end_[1] && got_load_end_[2] && got_load_end_[3];
+ }
+
+ bool OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
+ bool isLoading) override {
+ V_DECLARE();
+ V_EXPECT_FALSE(got_load_state_change_done_);
+
+ if (!isLoading) {
+ got_load_state_change_done_.yes();
+ }
+
+ V_EXPECT_TRUE(parent::OnLoadingStateChange(browser, isLoading));
+ V_RETURN();
+ }
+
+ bool OnLoadStart(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) override {
+ if (origin_.empty()) {
+ // When navigating different origins we can't rely on the nav() value
+ // because each navigation creates a new renderer process. Get the origin
+ // by parsing the URL instead.
+ origin_ = GetOriginFromMultiNavURL(browser->GetMainFrame()->GetURL());
+ }
+
+ const int frame_number = GetNavFromMultiNavURL(frame->GetURL());
+
+ V_DECLARE();
+ V_EXPECT_FALSE(got_load_start_[frame_number]);
+ V_EXPECT_FALSE(got_load_end_[frame_number]);
+
+ // Notification should be received for parent frame before child frame.
+ if (frame_number == 0) {
+ V_EXPECT_FALSE(got_load_start_[1]);
+ V_EXPECT_FALSE(got_load_start_[2]);
+ V_EXPECT_FALSE(got_load_start_[3]);
+ } else if (frame_number == 1) {
+ V_EXPECT_TRUE(got_load_start_[0]);
+ V_EXPECT_FALSE(got_load_start_[2]);
+ V_EXPECT_FALSE(got_load_start_[3]);
+ } else if (frame_number == 2) {
+ V_EXPECT_TRUE(got_load_start_[0]);
+ V_EXPECT_TRUE(got_load_start_[1]);
+ V_EXPECT_FALSE(got_load_start_[3]);
+ } else if (frame_number == 3) {
+ V_EXPECT_TRUE(got_load_start_[0]);
+ V_EXPECT_TRUE(got_load_start_[1]);
+ V_EXPECT_TRUE(got_load_start_[2]);
+ }
+
+ got_load_start_[frame_number].yes();
+
+ V_EXPECT_TRUE(parent::OnLoadStart(browser, frame));
+ V_RETURN();
+ }
+
+ bool OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) override {
+ const int frame_number = GetNavFromMultiNavURL(frame->GetURL());
+
+ V_DECLARE();
+ V_EXPECT_TRUE(got_load_start_[frame_number]);
+ V_EXPECT_FALSE(got_load_end_[frame_number]);
+
+ // Notification should be received for child frame before parent frame.
+ if (frame_number == 0) {
+ V_EXPECT_TRUE(got_load_end_[1]);
+ V_EXPECT_TRUE(got_load_end_[2]);
+ V_EXPECT_TRUE(got_load_end_[3]);
+ } else if (frame_number == 1) {
+ V_EXPECT_FALSE(got_load_end_[0]);
+ V_EXPECT_TRUE(got_load_end_[2]);
+ V_EXPECT_TRUE(got_load_end_[3]);
+ } else if (frame_number == 2) {
+ V_EXPECT_FALSE(got_load_end_[0]);
+ V_EXPECT_FALSE(got_load_end_[1]);
+ V_EXPECT_TRUE(got_load_end_[3]);
+ } else if (frame_number == 3) {
+ V_EXPECT_FALSE(got_load_end_[0]);
+ V_EXPECT_FALSE(got_load_end_[1]);
+ V_EXPECT_FALSE(got_load_end_[2]);
+ }
+
+ V_EXPECT_TRUE(VerifyBrowserIframe(browser, frame, origin_, frame_number))
+ << "frame_number = " << frame_number;
+
+ got_load_end_[frame_number].yes();
+
+ V_EXPECT_TRUE(parent::OnLoadEnd(browser, frame));
+ V_RETURN();
+ }
+
+ bool Finalize() override {
+ V_DECLARE();
+ V_EXPECT_TRUE(got_load_state_change_done_);
+ V_EXPECT_TRUE(got_load_start_[0]);
+ V_EXPECT_TRUE(got_load_start_[1]);
+ V_EXPECT_TRUE(got_load_start_[2]);
+ V_EXPECT_TRUE(got_load_start_[3]);
+ V_EXPECT_TRUE(got_load_end_[0]);
+ V_EXPECT_TRUE(got_load_end_[1]);
+ V_EXPECT_TRUE(got_load_end_[2]);
+ V_EXPECT_TRUE(got_load_end_[3]);
+ V_EXPECT_TRUE(parent::Finalize());
+ V_RETURN();
+ }
+
+ private:
+ std::string origin_;
+
+ TrackCallback got_load_state_change_done_;
+ TrackCallback got_load_start_[4];
+ TrackCallback got_load_end_[4];
+};
+
+class FrameNavExpectationsFactoryBrowserTestNestedIframesSameOrigin
+ : public FrameNavExpectationsFactoryBrowser {
+ public:
+ FrameNavExpectationsFactoryBrowserTestNestedIframesSameOrigin()
+ : create_count_(0) {}
+
+ FrameNavFactoryId GetID() const override {
+ return FNF_ID_NESTED_IFRAMES_SAME_ORIGIN;
+ }
+
+ bool HasMoreNavigations() const override {
+ return (create_count_ < kMaxMultiNavNavigations);
+ }
+
+ bool Finalize() override {
+ V_DECLARE();
+ V_EXPECT_TRUE(create_count_ == kMaxMultiNavNavigations);
+ V_RETURN();
+ }
+
+ protected:
+ std::unique_ptr<FrameNavExpectationsBrowser> Create(int nav) override {
+ create_count_++;
+ return std::make_unique<FrameNavExpectationsBrowserTestNestedIframes>(nav,
+ true);
+ }
+
+ private:
+ int create_count_;
+};
+
+class FrameNavExpectationsFactoryRendererTestNestedIframesSameOrigin
+ : public FrameNavExpectationsFactoryRenderer {
+ public:
+ FrameNavExpectationsFactoryRendererTestNestedIframesSameOrigin() {}
+
+ FrameNavFactoryId GetID() const override {
+ return FNF_ID_NESTED_IFRAMES_SAME_ORIGIN;
+ }
+
+ protected:
+ std::unique_ptr<FrameNavExpectationsRenderer> Create(int nav) override {
+ return std::make_unique<FrameNavExpectationsRendererTestNestedIframes>(
+ nav, true);
+ }
+};
+
+} // namespace
+
+// Test that nested iframes work.
+FRAME_TEST(NestedIframesSameOrigin, FNF_ID_NESTED_IFRAMES_SAME_ORIGIN)
+
+namespace {
+
+class FrameNavExpectationsFactoryBrowserTestNestedIframesDiffOrigin
+ : public FrameNavExpectationsFactoryBrowser {
+ public:
+ FrameNavExpectationsFactoryBrowserTestNestedIframesDiffOrigin()
+ : create_count_(0) {}
+
+ FrameNavFactoryId GetID() const override {
+ return FNF_ID_NESTED_IFRAMES_DIFF_ORIGIN;
+ }
+
+ bool HasMoreNavigations() const override {
+ return (create_count_ < kMaxMultiNavNavigations);
+ }
+
+ bool Finalize() override {
+ V_DECLARE();
+ V_EXPECT_TRUE(create_count_ == kMaxMultiNavNavigations);
+ V_RETURN();
+ }
+
+ protected:
+ std::unique_ptr<FrameNavExpectationsBrowser> Create(int nav) override {
+ create_count_++;
+ return std::make_unique<FrameNavExpectationsBrowserTestNestedIframes>(
+ nav, false);
+ }
+
+ private:
+ int create_count_;
+};
+
+class FrameNavExpectationsFactoryRendererTestNestedIframesDiffOrigin
+ : public FrameNavExpectationsFactoryRenderer {
+ public:
+ FrameNavExpectationsFactoryRendererTestNestedIframesDiffOrigin() {}
+
+ FrameNavFactoryId GetID() const override {
+ return FNF_ID_NESTED_IFRAMES_DIFF_ORIGIN;
+ }
+
+ protected:
+ std::unique_ptr<FrameNavExpectationsRenderer> Create(int nav) override {
+ return std::make_unique<FrameNavExpectationsRendererTestNestedIframes>(
+ nav, false);
+ }
+};
+
+} // namespace
+
+// Test that nested iframes work.
+FRAME_TEST(NestedIframesDiffOrigin, FNF_ID_NESTED_IFRAMES_DIFF_ORIGIN)
+
+namespace {
+
+// Returns a new factory in the browser or renderer process. All factory types
+// must be listed here.
+
+// static
+std::unique_ptr<FrameNavExpectationsFactoryBrowser>
+FrameNavExpectationsFactoryBrowser::FromID(FrameNavFactoryId id) {
+ std::unique_ptr<FrameNavExpectationsFactoryBrowser> factory;
+ switch (id) {
+ case FNF_ID_SINGLE_NAV_HARNESS:
+ factory.reset(new FrameNavExpectationsFactoryBrowserTestSingleNavHarness);
+ break;
+ case FNF_ID_SINGLE_NAV:
+ factory.reset(new FrameNavExpectationsFactoryBrowserTestSingleNav);
+ break;
+ case FNF_ID_MULTI_NAV_HARNESS:
+ factory.reset(new FrameNavExpectationsFactoryBrowserTestMultiNavHarness);
+ break;
+ case FNF_ID_MULTI_NAV:
+ factory.reset(new FrameNavExpectationsFactoryBrowserTestMultiNav);
+ break;
+ case FNF_ID_NESTED_IFRAMES_SAME_ORIGIN:
+ factory.reset(
+ new FrameNavExpectationsFactoryBrowserTestNestedIframesSameOrigin);
+ break;
+ case FNF_ID_NESTED_IFRAMES_DIFF_ORIGIN:
+ factory.reset(
+ new FrameNavExpectationsFactoryBrowserTestNestedIframesDiffOrigin);
+ break;
+ default:
+ break;
+ }
+ EXPECT_TRUE(factory);
+ EXPECT_EQ(id, factory->GetID());
+ return factory;
+}
+
+// static
+std::unique_ptr<FrameNavExpectationsFactoryRenderer>
+FrameNavExpectationsFactoryRenderer::FromID(FrameNavFactoryId id) {
+ std::unique_ptr<FrameNavExpectationsFactoryRenderer> factory;
+ switch (id) {
+ case FNF_ID_SINGLE_NAV_HARNESS:
+ factory.reset(
+ new FrameNavExpectationsFactoryRendererTestSingleNavHarness);
+ break;
+ case FNF_ID_SINGLE_NAV:
+ factory.reset(new FrameNavExpectationsFactoryRendererTestSingleNav);
+ break;
+ case FNF_ID_MULTI_NAV_HARNESS:
+ factory.reset(new FrameNavExpectationsFactoryRendererTestMultiNavHarness);
+ break;
+ case FNF_ID_MULTI_NAV:
+ factory.reset(new FrameNavExpectationsFactoryRendererTestMultiNav);
+ break;
+ case FNF_ID_NESTED_IFRAMES_SAME_ORIGIN:
+ factory.reset(
+ new FrameNavExpectationsFactoryRendererTestNestedIframesSameOrigin);
+ break;
+ case FNF_ID_NESTED_IFRAMES_DIFF_ORIGIN:
+ factory.reset(
+ new FrameNavExpectationsFactoryRendererTestNestedIframesDiffOrigin);
+ break;
+ default:
+ break;
+ }
+ EXPECT_TRUE(factory);
+ EXPECT_EQ(id, factory->GetID());
+ return factory;
+}
+
+} // namespace
+
+// Entry point for creating frame renderer test objects.
+// Called from client_app_delegates.cc.
+void CreateFrameRendererTests(ClientAppRenderer::DelegateSet& delegates) {
+ delegates.insert(new FrameNavRendererTest);
+}
diff --git a/tests/ceftests/hsts_redirect_unittest.cc b/tests/ceftests/hsts_redirect_unittest.cc
new file mode 100644
index 00000000..218ba16d
--- /dev/null
+++ b/tests/ceftests/hsts_redirect_unittest.cc
@@ -0,0 +1,317 @@
+// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "include/base/cef_callback.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "tests/ceftests/test_handler.h"
+#include "tests/ceftests/test_server.h"
+#include "tests/ceftests/test_server_observer.h"
+#include "tests/ceftests/test_util.h"
+#include "tests/gtest/include/gtest/gtest.h"
+#include "tests/shared/common/string_util.h"
+
+namespace {
+
+// Set the "Strict-Transport-Security" header on an HTTPS response to enable
+// HSTS redirects for follow-up HTTP requests to the same origin. See
+// https://www.chromium.org/hsts/.
+//
+// HSTS is implemented in the network service so real servers are required to
+// test the redirect behavior. It also requires a "localhost" domain certificate
+// instead of IP address (see https://crbug.com/456712). See additional comments
+// in OnResourceRedirect about redirect behavior with non-standard port numbers.
+//
+// The test works as follows:
+// 1. Start HTTP and HTTPS servers.
+// 2. Load an HTTP URL that redirects to an HTTPS URL.
+// 3. Set the "Strict-Transport-Security" header in response to the first HTTPS
+// request.
+// 4. Load the same HTTP URL additional times to trigger the internal HTTP to
+// HTTPS redirect.
+
+// Number of times to load the same HTTP URL. Must be > 1.
+constexpr size_t kHSTSLoadCount = 3;
+
+constexpr char kHSTSURLPath[] = "/index.html";
+
+// Used to observe HTTP and HTTPS server requests.
+class HSTSTestServerObserver : public test_server::ObserverHelper {
+ public:
+ using ReadyCallback = base::OnceCallback<void(const std::string& url)>;
+
+ HSTSTestServerObserver(bool https_server,
+ size_t& nav_ct,
+ TrackCallback (&got_request)[kHSTSLoadCount],
+ ReadyCallback ready_callback,
+ base::OnceClosure done_callback)
+ : https_server_(https_server),
+ nav_ct_(nav_ct),
+ got_request_(got_request),
+ ready_callback_(std::move(ready_callback)),
+ done_callback_(std::move(done_callback)) {
+ Initialize(https_server);
+ }
+
+ void OnInitialized(const std::string& server_origin) override {
+ EXPECT_UI_THREAD();
+
+ origin_ = ToLocalhostOrigin(server_origin);
+ url_ = origin_ + kHSTSURLPath;
+
+ std::move(ready_callback_).Run(url_);
+ }
+
+ void OnShutdown() override {
+ EXPECT_UI_THREAD();
+ std::move(done_callback_).Run();
+ delete this;
+ }
+
+ bool OnTestServerRequest(CefRefPtr<CefRequest> request,
+ const ResponseCallback& response_callback) override {
+ EXPECT_UI_THREAD();
+
+ // At most 1 request per load.
+ EXPECT_FALSE(got_request_[nav_ct_]) << nav_ct_;
+ got_request_[nav_ct_].yes();
+
+ const std::string& url = ToLocalhostOrigin(request->GetURL());
+
+ auto response = CefResponse::Create();
+ response->SetMimeType("text/html");
+ std::string response_body;
+
+ if (!https_server_) {
+ // Redirect to the HTTPS URL.
+ EXPECT_STREQ(url_.c_str(), url.c_str()) << nav_ct_;
+ response->SetStatus(301); // Permanent Redirect
+ response->SetHeaderByName("Location",
+ GetLocalhostURL(/*https_server=*/true),
+ /*overwrite=*/true);
+ } else {
+ // Normal response after an HTTP to HTTPS redirect.
+ EXPECT_STREQ(url_.c_str(), url.c_str()) << nav_ct_;
+ response->SetStatus(200);
+
+ if (nav_ct_ == 0) {
+ // Set the "Strict-Transport-Security" header in response to the first
+ // HTTPS request.
+ response->SetHeaderByName("Strict-Transport-Security",
+ "max-age=16070400",
+ /*overwrite=*/true);
+ }
+
+ // Don't cache the HTTPS response (so we see all the requests).
+ response->SetHeaderByName("Cache-Control", "no-cache",
+ /*overwrite=*/true);
+
+ response_body = "<html><body>Test1</body></html>";
+ }
+
+ response_callback.Run(response, response_body);
+
+ // Stop propagating the callback.
+ return true;
+ }
+
+ private:
+ static std::string ToLocalhostOrigin(const std::string& origin) {
+ // Need to explicitly use the "localhost" domain instead of the IP address.
+ // HTTPS URLs will already be using "localhost".
+ return client::AsciiStrReplace(origin, "127.0.0.1", "localhost");
+ }
+
+ static std::string GetLocalhostOrigin(bool https_server) {
+ return ToLocalhostOrigin(test_server::GetOrigin(https_server));
+ }
+
+ static std::string GetLocalhostURL(bool https_server) {
+ return GetLocalhostOrigin(/*https_server=*/true) + kHSTSURLPath;
+ }
+
+ const bool https_server_;
+
+ size_t& nav_ct_;
+ TrackCallback (&got_request_)[kHSTSLoadCount];
+ ReadyCallback ready_callback_;
+ base::OnceClosure done_callback_;
+
+ std::string origin_;
+ std::string url_;
+
+ DISALLOW_COPY_AND_ASSIGN(HSTSTestServerObserver);
+};
+
+class HSTSRedirectTest : public TestHandler {
+ public:
+ HSTSRedirectTest() = default;
+
+ void RunTest() override {
+ SetTestTimeout();
+ CefPostTask(TID_UI,
+ base::BindOnce(&HSTSRedirectTest::StartHttpServer, this));
+ }
+
+ void OnResourceRedirect(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response,
+ CefString& new_url) override {
+ EXPECT_IO_THREAD();
+
+ EXPECT_FALSE(got_redirect_[nav_ct_]) << nav_ct_;
+ got_redirect_[nav_ct_].yes();
+
+ EXPECT_STREQ(http_url_.c_str(), request->GetURL().ToString().c_str())
+ << nav_ct_;
+
+ if (nav_ct_ == 0) {
+ // Initial HTTP to HTTPS redirect.
+ EXPECT_STREQ(https_url_.c_str(), new_url.ToString().c_str()) << nav_ct_;
+ } else {
+ // HSTS HTTP to HTTPS redirect. This will use the wrong "localhost" port
+ // number, per spec. From RFC 6797:
+ // The UA MUST replace the URI scheme with "https" [RFC2818], and if the
+ // URI contains an explicit port component of "80", then the UA MUST
+ // convert the port component to be "443", or if the URI contains an
+ // explicit port component that is not equal to "80", the port component
+ // value MUST be preserved; otherwise, if the URI does not contain an
+ // explicit port component, the UA MUST NOT add one.
+ const std::string& expected_https_url =
+ client::AsciiStrReplace(http_url_, "http:", "https:");
+ EXPECT_STREQ(expected_https_url.c_str(), new_url.ToString().c_str())
+ << nav_ct_;
+
+ // Redirect to the correct HTTPS URL instead.
+ new_url = https_url_;
+ }
+ }
+
+ void OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int httpStatusCode) override {
+ EXPECT_UI_THREAD();
+
+ TestHandler::OnLoadEnd(browser, frame, httpStatusCode);
+
+ EXPECT_FALSE(got_load_end_[nav_ct_]) << nav_ct_;
+ got_load_end_[nav_ct_].yes();
+
+ // Expect only the HTTPS URL to load.
+ EXPECT_STREQ(https_url_.c_str(), frame->GetURL().ToString().c_str())
+ << nav_ct_;
+
+ if (++nav_ct_ == kHSTSLoadCount) {
+ StopHttpServer();
+ } else {
+ // Load the same HTTP URL again.
+ browser->GetMainFrame()->LoadURL(http_url_);
+ }
+ }
+
+ void DestroyTest() override {
+ EXPECT_FALSE(http_server_);
+ EXPECT_FALSE(https_server_);
+
+ EXPECT_EQ(kHSTSLoadCount, nav_ct_);
+ for (size_t i = 0; i < kHSTSLoadCount; ++i) {
+ EXPECT_TRUE(got_redirect_[i]) << i;
+ EXPECT_TRUE(got_load_end_[i]) << i;
+ }
+
+ for (size_t i = 0; i < kHSTSLoadCount; ++i) {
+ // Should only see the 1st HTTP request due to the internal HSTS redirect
+ // for the 2nd+ requests.
+ EXPECT_EQ(i == 0, got_http_request_[i]) << i;
+
+ // Should see all HTTPS requests.
+ EXPECT_TRUE(got_https_request_[i]) << i;
+ }
+
+ TestHandler::DestroyTest();
+ }
+
+ private:
+ void StartHttpServer() {
+ EXPECT_UI_THREAD();
+
+ // Will delete itself after the server stops.
+ http_server_ = new HSTSTestServerObserver(
+ /*https_server=*/false, nav_ct_, got_http_request_,
+ base::BindOnce(&HSTSRedirectTest::StartedHttpServer, this),
+ base::BindOnce(&HSTSRedirectTest::StoppedHttpServer, this));
+ }
+
+ void StartedHttpServer(const std::string& url) {
+ EXPECT_UI_THREAD();
+
+ http_url_ = url;
+ EXPECT_TRUE(http_url_.find("http://localhost:") == 0);
+
+ // Start the HTTPS server. Will delete itself after the server stops.
+ https_server_ = new HSTSTestServerObserver(
+ /*https_server=*/true, nav_ct_, got_https_request_,
+ base::BindOnce(&HSTSRedirectTest::StartedHttpsServer, this),
+ base::BindOnce(&HSTSRedirectTest::StoppedHttpsServer, this));
+ }
+
+ void StartedHttpsServer(const std::string& url) {
+ EXPECT_UI_THREAD();
+
+ https_url_ = url;
+ EXPECT_TRUE(https_url_.find("https://localhost:") == 0);
+
+ // Create a new in-memory context so HSTS decisions aren't cached.
+ auto request_context = CreateTestRequestContext(
+ TEST_RC_MODE_CUSTOM, /*cache_path=*/std::string());
+
+ CreateBrowser(http_url_, request_context);
+ }
+
+ void StopHttpServer() {
+ EXPECT_UI_THREAD();
+
+ // Results in a call to StoppedHttpServer().
+ http_server_->Shutdown();
+ }
+
+ void StoppedHttpServer() {
+ EXPECT_UI_THREAD();
+
+ http_server_ = nullptr;
+
+ // Stop the HTTPS server. Results in a call to StoppedHttpsServer().
+ https_server_->Shutdown();
+ }
+
+ void StoppedHttpsServer() {
+ EXPECT_UI_THREAD();
+
+ https_server_ = nullptr;
+
+ DestroyTest();
+ }
+
+ HSTSTestServerObserver* http_server_ = nullptr;
+ std::string http_url_;
+
+ HSTSTestServerObserver* https_server_ = nullptr;
+ std::string https_url_;
+
+ size_t nav_ct_ = 0U;
+ TrackCallback got_http_request_[kHSTSLoadCount];
+ TrackCallback got_https_request_[kHSTSLoadCount];
+ TrackCallback got_load_end_[kHSTSLoadCount];
+ TrackCallback got_redirect_[kHSTSLoadCount];
+
+ IMPLEMENT_REFCOUNTING(HSTSRedirectTest);
+};
+
+} // namespace
+
+TEST(HSTSRedirectTest, Redirect) {
+ CefRefPtr<HSTSRedirectTest> handler = new HSTSRedirectTest();
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
diff --git a/tests/ceftests/image_unittest.cc b/tests/ceftests/image_unittest.cc
new file mode 100644
index 00000000..f41da5e5
--- /dev/null
+++ b/tests/ceftests/image_unittest.cc
@@ -0,0 +1,284 @@
+// Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "include/cef_image.h"
+#include "tests/ceftests/image_util.h"
+#include "tests/gtest/include/gtest/gtest.h"
+
+namespace {
+
+// The expected image size in device independent pixels (DIPs).
+const int kExpectedDIPSize = 16;
+
+void LoadImage(CefRefPtr<CefImage> image, double scale_factor) {
+ image_util::LoadIconImage(image, scale_factor);
+}
+
+void VerifyScaleEmpty(CefRefPtr<CefImage> image, float scale_factor) {
+ float actual_scale_factor = 0.0f;
+ int pixel_width = 0;
+ int pixel_height = 0;
+
+ EXPECT_FALSE(image->HasRepresentation(scale_factor));
+ EXPECT_FALSE(image->GetRepresentationInfo(scale_factor, actual_scale_factor,
+ pixel_width, pixel_height));
+ EXPECT_EQ(0.0f, actual_scale_factor);
+ EXPECT_EQ(0, pixel_width);
+ EXPECT_EQ(0, pixel_height);
+ EXPECT_FALSE(image->RemoveRepresentation(scale_factor));
+}
+
+void VerifyScaleExists(CefRefPtr<CefImage> image,
+ float scale_factor,
+ float expected_scale_factor) {
+ float actual_scale_factor = 0.0f;
+ int pixel_width = 0;
+ int pixel_height = 0;
+ int expected_pixel_size = kExpectedDIPSize * expected_scale_factor;
+
+ // Only returns true for exact matches.
+ if (scale_factor == expected_scale_factor) {
+ EXPECT_TRUE(image->HasRepresentation(scale_factor));
+ } else {
+ EXPECT_FALSE(image->HasRepresentation(scale_factor));
+ }
+
+ // Returns the closest match.
+ EXPECT_TRUE(image->GetRepresentationInfo(scale_factor, actual_scale_factor,
+ pixel_width, pixel_height));
+ EXPECT_EQ(expected_scale_factor, actual_scale_factor);
+ EXPECT_EQ(expected_pixel_size, pixel_width);
+ EXPECT_EQ(expected_pixel_size, pixel_height);
+
+ // Only returns true for exact matches.
+ if (scale_factor == expected_scale_factor) {
+ EXPECT_TRUE(image->RemoveRepresentation(scale_factor));
+ EXPECT_FALSE(image->HasRepresentation(scale_factor));
+ } else {
+ EXPECT_FALSE(image->RemoveRepresentation(scale_factor));
+ }
+}
+
+void VerifySaveAsBitmap(CefRefPtr<CefImage> image,
+ float scale_factor,
+ float expected_scale_factor) {
+ int pixel_width = 0;
+ int pixel_height = 0;
+ int expected_pixel_size = kExpectedDIPSize * expected_scale_factor;
+ size_t expected_data_size = expected_pixel_size * expected_pixel_size * 4U;
+
+ CefRefPtr<CefBinaryValue> value = image->GetAsBitmap(
+ scale_factor, CEF_COLOR_TYPE_RGBA_8888, CEF_ALPHA_TYPE_PREMULTIPLIED,
+ pixel_width, pixel_height);
+ EXPECT_TRUE(value.get());
+ size_t data_size = value->GetSize();
+ EXPECT_EQ(expected_data_size, data_size);
+ EXPECT_EQ(expected_pixel_size, pixel_width);
+ EXPECT_EQ(expected_pixel_size, pixel_height);
+
+ std::vector<unsigned char> data(data_size);
+ value->GetData(&data[0], data_size, 0U);
+
+ CefRefPtr<CefImage> image2 = CefImage::CreateImage();
+ EXPECT_TRUE(image2.get());
+ EXPECT_TRUE(image2->AddBitmap(expected_scale_factor, pixel_width,
+ pixel_height, CEF_COLOR_TYPE_RGBA_8888,
+ CEF_ALPHA_TYPE_PREMULTIPLIED, &data[0],
+ data_size));
+ VerifyScaleExists(image2, expected_scale_factor, expected_scale_factor);
+}
+
+void VerifySaveAsPNG(CefRefPtr<CefImage> image,
+ float scale_factor,
+ float expected_scale_factor) {
+ int pixel_width = 0;
+ int pixel_height = 0;
+ int expected_pixel_size = kExpectedDIPSize * expected_scale_factor;
+
+ CefRefPtr<CefBinaryValue> value =
+ image->GetAsPNG(scale_factor, true, pixel_width, pixel_height);
+ EXPECT_TRUE(value.get());
+ size_t data_size = value->GetSize();
+ EXPECT_GT(data_size, 0U);
+ EXPECT_EQ(expected_pixel_size, pixel_width);
+ EXPECT_EQ(expected_pixel_size, pixel_height);
+
+ std::vector<unsigned char> data(data_size);
+ value->GetData(&data[0], data_size, 0U);
+
+ CefRefPtr<CefImage> image2 = CefImage::CreateImage();
+ EXPECT_TRUE(image2.get());
+ EXPECT_TRUE(image2->AddPNG(expected_scale_factor, &data[0], data_size));
+ VerifyScaleExists(image2, expected_scale_factor, expected_scale_factor);
+}
+
+void VerifySaveAsJPEG(CefRefPtr<CefImage> image,
+ float scale_factor,
+ float expected_scale_factor) {
+ int pixel_width = 0;
+ int pixel_height = 0;
+ int expected_pixel_size = kExpectedDIPSize * expected_scale_factor;
+
+ CefRefPtr<CefBinaryValue> value =
+ image->GetAsJPEG(scale_factor, 80, pixel_width, pixel_height);
+ EXPECT_TRUE(value.get());
+ size_t data_size = value->GetSize();
+ EXPECT_GT(data_size, 0U);
+ EXPECT_EQ(expected_pixel_size, pixel_width);
+ EXPECT_EQ(expected_pixel_size, pixel_height);
+
+ std::vector<unsigned char> data(data_size);
+ value->GetData(&data[0], data_size, 0U);
+
+ CefRefPtr<CefImage> image2 = CefImage::CreateImage();
+ EXPECT_TRUE(image2.get());
+ EXPECT_TRUE(image2->AddJPEG(expected_scale_factor, &data[0], data_size));
+ VerifyScaleExists(image2, expected_scale_factor, expected_scale_factor);
+}
+
+} // namespace
+
+TEST(ImageTest, Empty) {
+ CefRefPtr<CefImage> image = CefImage::CreateImage();
+ EXPECT_TRUE(image.get());
+
+ // An image is the same as itself.
+ EXPECT_TRUE(image->IsSame(image));
+
+ EXPECT_TRUE(image->IsEmpty());
+ EXPECT_EQ(0U, image->GetWidth());
+ EXPECT_EQ(0U, image->GetHeight());
+
+ // Empty images are the same.
+ CefRefPtr<CefImage> image2 = CefImage::CreateImage();
+ EXPECT_TRUE(image->IsSame(image2));
+ EXPECT_TRUE(image2->IsSame(image));
+
+ // 1x scale does not exist.
+ VerifyScaleEmpty(image, 1.0f);
+
+ // 2x scale does not exist.
+ VerifyScaleEmpty(image, 2.0f);
+}
+
+TEST(ImageTest, Scale1x) {
+ CefRefPtr<CefImage> image = CefImage::CreateImage();
+ EXPECT_TRUE(image.get());
+
+ LoadImage(image, 1.0f);
+
+ // 1x scale should exist.
+ VerifyScaleExists(image, 1.0f, 1.0f);
+
+ // 2x scale should not exist.
+ VerifyScaleEmpty(image, 2.0f);
+}
+
+TEST(ImageTest, Scale2x) {
+ CefRefPtr<CefImage> image = CefImage::CreateImage();
+ EXPECT_TRUE(image.get());
+
+ LoadImage(image, 2.0f);
+
+ // 1x scale should return the 2x image.
+ VerifyScaleExists(image, 1.0f, 2.0f);
+
+ // 2x scale should exist.
+ VerifyScaleExists(image, 2.0f, 2.0f);
+}
+
+TEST(ImageTest, ScaleMulti) {
+ CefRefPtr<CefImage> image = CefImage::CreateImage();
+ EXPECT_TRUE(image.get());
+
+ LoadImage(image, 1.0f);
+ LoadImage(image, 2.0f);
+
+ // 1x scale should exist.
+ VerifyScaleExists(image, 1.0f, 1.0f);
+
+ // 2x scale should exist.
+ VerifyScaleExists(image, 2.0f, 2.0f);
+}
+
+TEST(ImageTest, SaveBitmap1x) {
+ CefRefPtr<CefImage> image = CefImage::CreateImage();
+ EXPECT_TRUE(image.get());
+
+ LoadImage(image, 1.0f);
+
+ VerifySaveAsBitmap(image, 1.0f, 1.0f);
+}
+
+TEST(ImageTest, SaveBitmap2x) {
+ CefRefPtr<CefImage> image = CefImage::CreateImage();
+ EXPECT_TRUE(image.get());
+
+ LoadImage(image, 2.0f);
+
+ VerifySaveAsBitmap(image, 2.0f, 2.0f);
+}
+
+TEST(ImageTest, SaveBitmapMulti) {
+ CefRefPtr<CefImage> image = CefImage::CreateImage();
+ EXPECT_TRUE(image.get());
+
+ LoadImage(image, 2.0f);
+
+ VerifySaveAsBitmap(image, 1.0f, 2.0f);
+}
+
+TEST(ImageTest, SavePNG1x) {
+ CefRefPtr<CefImage> image = CefImage::CreateImage();
+ EXPECT_TRUE(image.get());
+
+ LoadImage(image, 1.0f);
+
+ VerifySaveAsPNG(image, 1.0f, 1.0f);
+}
+
+TEST(ImageTest, SavePNG2x) {
+ CefRefPtr<CefImage> image = CefImage::CreateImage();
+ EXPECT_TRUE(image.get());
+
+ LoadImage(image, 2.0f);
+
+ VerifySaveAsPNG(image, 2.0f, 2.0f);
+}
+
+TEST(ImageTest, SavePNGMulti) {
+ CefRefPtr<CefImage> image = CefImage::CreateImage();
+ EXPECT_TRUE(image.get());
+
+ LoadImage(image, 2.0f);
+
+ VerifySaveAsPNG(image, 1.0f, 2.0f);
+}
+
+TEST(ImageTest, SaveJPEG1x) {
+ CefRefPtr<CefImage> image = CefImage::CreateImage();
+ EXPECT_TRUE(image.get());
+
+ LoadImage(image, 1.0f);
+
+ VerifySaveAsJPEG(image, 1.0f, 1.0f);
+}
+
+TEST(ImageTest, SaveJPEG2x) {
+ CefRefPtr<CefImage> image = CefImage::CreateImage();
+ EXPECT_TRUE(image.get());
+
+ LoadImage(image, 2.0f);
+
+ VerifySaveAsJPEG(image, 2.0f, 2.0f);
+}
+
+TEST(ImageTest, SaveJPEGMulti) {
+ CefRefPtr<CefImage> image = CefImage::CreateImage();
+ EXPECT_TRUE(image.get());
+
+ LoadImage(image, 2.0f);
+
+ VerifySaveAsJPEG(image, 1.0f, 2.0f);
+}
diff --git a/tests/ceftests/image_util.cc b/tests/ceftests/image_util.cc
new file mode 100644
index 00000000..c31d9056
--- /dev/null
+++ b/tests/ceftests/image_util.cc
@@ -0,0 +1,39 @@
+// Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/ceftests/image_util.h"
+
+#include "tests/gtest/include/gtest/gtest.h"
+#include "tests/shared/browser/resource_util.h"
+
+namespace image_util {
+
+void LoadImage(CefRefPtr<CefImage> image,
+ double scale_factor,
+ const std::string& name,
+ const CefSize& expected_size) {
+ std::string image_str;
+
+ std::string name_str;
+ if (scale_factor == 1.0f) {
+ name_str = name + ".1x.png";
+ } else if (scale_factor == 2.0f) {
+ name_str = name + ".2x.png";
+ }
+
+ EXPECT_TRUE(client::LoadBinaryResource(name_str.c_str(), image_str));
+ EXPECT_TRUE(image->AddPNG(scale_factor, image_str.c_str(), image_str.size()));
+
+ EXPECT_FALSE(image->IsEmpty());
+ EXPECT_EQ(expected_size.width, static_cast<int>(image->GetWidth()));
+ EXPECT_EQ(expected_size.height, static_cast<int>(image->GetHeight()));
+}
+
+void LoadIconImage(CefRefPtr<CefImage> image,
+ double scale_factor,
+ const std::string& name) {
+ LoadImage(image, scale_factor, name, CefSize(16, 16));
+}
+
+} // namespace image_util
diff --git a/tests/ceftests/image_util.h b/tests/ceftests/image_util.h
new file mode 100644
index 00000000..823fc08d
--- /dev/null
+++ b/tests/ceftests/image_util.h
@@ -0,0 +1,27 @@
+// Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFTESTS_IMAGE_UTIL_H_
+#define CEF_TESTS_CEFTESTS_IMAGE_UTIL_H_
+#pragma once
+
+#include "include/cef_image.h"
+
+namespace image_util {
+
+// Load an PNG image. Tests that the size is |expected_size| in DIPs. Call
+// multiple times to load the same image at different scale factors.
+void LoadImage(CefRefPtr<CefImage> image,
+ double scale_factor,
+ const std::string& name,
+ const CefSize& expected_size);
+
+// Load an icon image. Expected size is 16x16 DIPs.
+void LoadIconImage(CefRefPtr<CefImage> image,
+ double scale_factor,
+ const std::string& name = "window_icon");
+
+} // namespace image_util
+
+#endif // CEF_TESTS_CEFTESTS_IMAGE_UTIL_H_
diff --git a/tests/ceftests/jsdialog_unittest.cc b/tests/ceftests/jsdialog_unittest.cc
new file mode 100644
index 00000000..4f75e84b
--- /dev/null
+++ b/tests/ceftests/jsdialog_unittest.cc
@@ -0,0 +1,450 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "include/base/cef_callback.h"
+#include "include/test/cef_test_helpers.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "tests/ceftests/test_handler.h"
+#include "tests/gtest/include/gtest/gtest.h"
+
+namespace {
+
+const char* kStartUrl = "http://tests/JSDialogTestHandler.Start";
+const char* kEndUrl = "http://tests/JSDialogTestHandler.End?r=";
+
+class JSDialogTestHandler : public TestHandler {
+ public:
+ enum TestType {
+ TYPE_ALERT,
+ TYPE_CONFIRM,
+ TYPE_PROMPT,
+ TYPE_ONBEFOREUNLOAD,
+ };
+ enum TestMode {
+ MODE_SUPPRESS,
+ MODE_RUN_IMMEDIATE,
+ MODE_RUN_DELAYED,
+ };
+
+ JSDialogTestHandler(TestType type,
+ TestMode mode,
+ bool success,
+ const std::string& user_input,
+ const std::string& result)
+ : type_(type),
+ mode_(mode),
+ success_(success),
+ user_input_(user_input),
+ result_(result) {}
+
+ void RunTest() override {
+ std::string content = "<html><head><body>START<script>";
+ if (type_ == TYPE_ALERT) {
+ content +=
+ "alert('My alert message'); "
+ "document.location='" +
+ std::string(kEndUrl) + "';";
+ } else if (type_ == TYPE_CONFIRM) {
+ content +=
+ "var r = confirm('My confirm message')?'ok':'cancel'; "
+ "document.location='" +
+ std::string(kEndUrl) + "'+r;";
+ } else if (type_ == TYPE_PROMPT) {
+ content +=
+ "var r = prompt('My prompt message','my default'); "
+ "document.location='" +
+ std::string(kEndUrl) + "'+r;";
+ } else if (type_ == TYPE_ONBEFOREUNLOAD) {
+ content +=
+ "window.onbeforeunload=function() {"
+ " return 'My unload message'; };";
+ }
+ content += "</script></body></html>";
+
+ AddResource(kStartUrl, content, "text/html");
+ AddResource(kEndUrl, "<html><body>END</body></html>", "text/html");
+
+ // Create the browser
+ CreateBrowser(kStartUrl);
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout();
+ }
+
+ void OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int httpStatusCode) override {
+ if (!frame->IsMain()) {
+ return;
+ }
+
+ std::string url = frame->GetURL();
+ if (url.find(kEndUrl) == 0) {
+ got_onloadend_.yes();
+
+ std::string result = url.substr(strlen(kEndUrl));
+ EXPECT_STREQ(result_.c_str(), result.c_str());
+
+ DestroyTest();
+ } else if (type_ == TYPE_ONBEFOREUNLOAD) {
+ // Send the page a user gesture to enable firing of the onbefureunload
+ // handler. See https://crbug.com/707007.
+ CefExecuteJavaScriptWithUserGestureForTests(frame, CefString());
+
+ // Trigger the onunload handler.
+ frame->LoadURL(kEndUrl);
+ }
+ }
+
+ void Continue(CefRefPtr<CefJSDialogCallback> callback) {
+ callback->Continue(success_, user_input_);
+ }
+
+ bool OnJSDialog(CefRefPtr<CefBrowser> browser,
+ const CefString& origin_url,
+ JSDialogType dialog_type,
+ const CefString& message_text,
+ const CefString& default_prompt_text,
+ CefRefPtr<CefJSDialogCallback> callback,
+ bool& suppress_message) override {
+ got_onjsdialog_.yes();
+
+ EXPECT_STREQ(kStartUrl, origin_url.ToString().c_str());
+
+ if (type_ == TYPE_ALERT) {
+ EXPECT_EQ(JSDIALOGTYPE_ALERT, dialog_type);
+ EXPECT_STREQ("My alert message", message_text.ToString().c_str());
+ EXPECT_TRUE(default_prompt_text.empty());
+ } else if (type_ == TYPE_CONFIRM) {
+ EXPECT_EQ(JSDIALOGTYPE_CONFIRM, dialog_type);
+ EXPECT_STREQ("My confirm message", message_text.ToString().c_str());
+ EXPECT_TRUE(default_prompt_text.empty());
+ } else if (type_ == TYPE_PROMPT) {
+ EXPECT_EQ(JSDIALOGTYPE_PROMPT, dialog_type);
+ EXPECT_STREQ("My prompt message", message_text.ToString().c_str());
+ EXPECT_STREQ("my default", default_prompt_text.ToString().c_str());
+ }
+
+ EXPECT_FALSE(suppress_message);
+
+ if (mode_ == MODE_SUPPRESS) {
+ // Suppress the dialog.
+ suppress_message = true;
+ return false;
+ } else if (mode_ == MODE_RUN_IMMEDIATE) {
+ // Continue immediately.
+ callback->Continue(success_, user_input_);
+ } else if (mode_ == MODE_RUN_DELAYED) {
+ // Continue asynchronously.
+ CefPostTask(TID_UI, base::BindOnce(&JSDialogTestHandler::Continue, this,
+ callback));
+ }
+
+ return true;
+ }
+
+ bool OnBeforeUnloadDialog(CefRefPtr<CefBrowser> browser,
+ const CefString& message_text,
+ bool is_reload,
+ CefRefPtr<CefJSDialogCallback> callback) override {
+ got_onbeforeunloaddialog_.yes();
+
+ if (type_ == TYPE_ONBEFOREUNLOAD) {
+ // The message is no longer configurable via JavaScript.
+ // See http://crbug.com/587940.
+ EXPECT_STREQ("Is it OK to leave/reload this page?",
+ message_text.ToString().c_str());
+ EXPECT_FALSE(is_reload);
+ }
+
+ if (mode_ == MODE_RUN_IMMEDIATE) {
+ // Continue immediately.
+ callback->Continue(success_, user_input_);
+ } else if (mode_ == MODE_RUN_DELAYED) {
+ // Continue asynchronously.
+ CefPostTask(TID_UI, base::BindOnce(&JSDialogTestHandler::Continue, this,
+ callback));
+ }
+
+ return true;
+ }
+
+ void OnResetDialogState(CefRefPtr<CefBrowser> browser) override {
+ got_onresetdialogstate_.yes();
+ }
+
+ TestType type_;
+ TestMode mode_;
+ bool success_;
+ std::string user_input_;
+ std::string result_;
+
+ TrackCallback got_onjsdialog_;
+ TrackCallback got_onbeforeunloaddialog_;
+ TrackCallback got_onresetdialogstate_;
+ TrackCallback got_onloadend_;
+
+ IMPLEMENT_REFCOUNTING(JSDialogTestHandler);
+};
+
+} // namespace
+
+// Alert dialog with suppression.
+TEST(JSDialogTest, AlertSuppress) {
+ CefRefPtr<JSDialogTestHandler> handler = new JSDialogTestHandler(
+ JSDialogTestHandler::TYPE_ALERT, JSDialogTestHandler::MODE_SUPPRESS,
+ true, // success
+ "", // user_input
+ ""); // result
+ handler->ExecuteTest();
+
+ EXPECT_TRUE(handler->got_onjsdialog_);
+ EXPECT_FALSE(handler->got_onbeforeunloaddialog_);
+ EXPECT_TRUE(handler->got_onresetdialogstate_);
+ EXPECT_TRUE(handler->got_onloadend_);
+
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Alert dialog with immediate callback.
+TEST(JSDialogTest, AlertRunImmediate) {
+ CefRefPtr<JSDialogTestHandler> handler = new JSDialogTestHandler(
+ JSDialogTestHandler::TYPE_ALERT, JSDialogTestHandler::MODE_RUN_IMMEDIATE,
+ true, // success
+ "", // user_input
+ ""); // result
+ handler->ExecuteTest();
+
+ EXPECT_TRUE(handler->got_onjsdialog_);
+ EXPECT_FALSE(handler->got_onbeforeunloaddialog_);
+ EXPECT_TRUE(handler->got_onresetdialogstate_);
+ EXPECT_TRUE(handler->got_onloadend_);
+
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Alert dialog with delayed callback.
+TEST(JSDialogTest, AlertRunDelayed) {
+ CefRefPtr<JSDialogTestHandler> handler = new JSDialogTestHandler(
+ JSDialogTestHandler::TYPE_ALERT, JSDialogTestHandler::MODE_RUN_DELAYED,
+ true, // success
+ "", // user_input
+ ""); // result
+ handler->ExecuteTest();
+
+ EXPECT_TRUE(handler->got_onjsdialog_);
+ EXPECT_FALSE(handler->got_onbeforeunloaddialog_);
+ EXPECT_TRUE(handler->got_onresetdialogstate_);
+ EXPECT_TRUE(handler->got_onloadend_);
+
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Confirm dialog with suppression.
+TEST(JSDialogTest, ConfirmSuppress) {
+ CefRefPtr<JSDialogTestHandler> handler = new JSDialogTestHandler(
+ JSDialogTestHandler::TYPE_CONFIRM, JSDialogTestHandler::MODE_SUPPRESS,
+ true, // success
+ "", // user_input
+ "cancel"); // result
+ handler->ExecuteTest();
+
+ EXPECT_TRUE(handler->got_onjsdialog_);
+ EXPECT_FALSE(handler->got_onbeforeunloaddialog_);
+ EXPECT_TRUE(handler->got_onresetdialogstate_);
+ EXPECT_TRUE(handler->got_onloadend_);
+
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Confirm dialog run immediately return OK.
+TEST(JSDialogTest, ConfirmRunImmediateOk) {
+ CefRefPtr<JSDialogTestHandler> handler =
+ new JSDialogTestHandler(JSDialogTestHandler::TYPE_CONFIRM,
+ JSDialogTestHandler::MODE_RUN_IMMEDIATE,
+ true, // success
+ "", // user_input
+ "ok"); // result
+ handler->ExecuteTest();
+
+ EXPECT_TRUE(handler->got_onjsdialog_);
+ EXPECT_FALSE(handler->got_onbeforeunloaddialog_);
+ EXPECT_TRUE(handler->got_onresetdialogstate_);
+ EXPECT_TRUE(handler->got_onloadend_);
+
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Confirm dialog run immediately return Cancel.
+TEST(JSDialogTest, ConfirmRunImmediateCancel) {
+ CefRefPtr<JSDialogTestHandler> handler =
+ new JSDialogTestHandler(JSDialogTestHandler::TYPE_CONFIRM,
+ JSDialogTestHandler::MODE_RUN_IMMEDIATE,
+ false, // success
+ "", // user_input
+ "cancel"); // result
+ handler->ExecuteTest();
+
+ EXPECT_TRUE(handler->got_onjsdialog_);
+ EXPECT_FALSE(handler->got_onbeforeunloaddialog_);
+ EXPECT_TRUE(handler->got_onresetdialogstate_);
+ EXPECT_TRUE(handler->got_onloadend_);
+
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Confirm dialog run delayed return OK.
+TEST(JSDialogTest, ConfirmRunDelayedOk) {
+ CefRefPtr<JSDialogTestHandler> handler = new JSDialogTestHandler(
+ JSDialogTestHandler::TYPE_CONFIRM, JSDialogTestHandler::MODE_RUN_DELAYED,
+ true, // success
+ "", // user_input
+ "ok"); // result
+ handler->ExecuteTest();
+
+ EXPECT_TRUE(handler->got_onjsdialog_);
+ EXPECT_FALSE(handler->got_onbeforeunloaddialog_);
+ EXPECT_TRUE(handler->got_onresetdialogstate_);
+ EXPECT_TRUE(handler->got_onloadend_);
+
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Confirm dialog run delayed return Cancel.
+TEST(JSDialogTest, ConfirmRunDelayedCancel) {
+ CefRefPtr<JSDialogTestHandler> handler = new JSDialogTestHandler(
+ JSDialogTestHandler::TYPE_CONFIRM, JSDialogTestHandler::MODE_RUN_DELAYED,
+ false, // success
+ "", // user_input
+ "cancel"); // result
+ handler->ExecuteTest();
+
+ EXPECT_TRUE(handler->got_onjsdialog_);
+ EXPECT_FALSE(handler->got_onbeforeunloaddialog_);
+ EXPECT_TRUE(handler->got_onresetdialogstate_);
+ EXPECT_TRUE(handler->got_onloadend_);
+
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Prompt dialog with suppression.
+TEST(JSDialogTest, PromptSuppress) {
+ CefRefPtr<JSDialogTestHandler> handler = new JSDialogTestHandler(
+ JSDialogTestHandler::TYPE_PROMPT, JSDialogTestHandler::MODE_SUPPRESS,
+ true, // success
+ "some_value", // user_input
+ "null"); // result
+ handler->ExecuteTest();
+
+ EXPECT_TRUE(handler->got_onjsdialog_);
+ EXPECT_FALSE(handler->got_onbeforeunloaddialog_);
+ EXPECT_TRUE(handler->got_onresetdialogstate_);
+ EXPECT_TRUE(handler->got_onloadend_);
+
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Prompt dialog run immediately return OK.
+TEST(JSDialogTest, PromptRunImmediateOk) {
+ CefRefPtr<JSDialogTestHandler> handler = new JSDialogTestHandler(
+ JSDialogTestHandler::TYPE_PROMPT, JSDialogTestHandler::MODE_RUN_IMMEDIATE,
+ true, // success
+ "some_value", // user_input
+ "some_value"); // result
+ handler->ExecuteTest();
+
+ EXPECT_TRUE(handler->got_onjsdialog_);
+ EXPECT_FALSE(handler->got_onbeforeunloaddialog_);
+ EXPECT_TRUE(handler->got_onresetdialogstate_);
+ EXPECT_TRUE(handler->got_onloadend_);
+
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Prompt dialog run immediately return Cancel.
+TEST(JSDialogTest, PromptRunImmediateCancel) {
+ CefRefPtr<JSDialogTestHandler> handler = new JSDialogTestHandler(
+ JSDialogTestHandler::TYPE_PROMPT, JSDialogTestHandler::MODE_RUN_IMMEDIATE,
+ false, // success
+ "some_value", // user_input
+ "null"); // result
+ handler->ExecuteTest();
+
+ EXPECT_TRUE(handler->got_onjsdialog_);
+ EXPECT_FALSE(handler->got_onbeforeunloaddialog_);
+ EXPECT_TRUE(handler->got_onresetdialogstate_);
+ EXPECT_TRUE(handler->got_onloadend_);
+
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Prompt dialog run delayed return OK.
+TEST(JSDialogTest, PromptRunDelayedOk) {
+ CefRefPtr<JSDialogTestHandler> handler = new JSDialogTestHandler(
+ JSDialogTestHandler::TYPE_PROMPT, JSDialogTestHandler::MODE_RUN_DELAYED,
+ true, // success
+ "some_value", // user_input
+ "some_value"); // result
+ handler->ExecuteTest();
+
+ EXPECT_TRUE(handler->got_onjsdialog_);
+ EXPECT_FALSE(handler->got_onbeforeunloaddialog_);
+ EXPECT_TRUE(handler->got_onresetdialogstate_);
+ EXPECT_TRUE(handler->got_onloadend_);
+
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Prompt dialog run delayed return Cancel.
+TEST(JSDialogTest, PromptRunDelayedCancel) {
+ CefRefPtr<JSDialogTestHandler> handler = new JSDialogTestHandler(
+ JSDialogTestHandler::TYPE_PROMPT, JSDialogTestHandler::MODE_RUN_DELAYED,
+ false, // success
+ "some_value", // user_input
+ "null"); // result
+ handler->ExecuteTest();
+
+ EXPECT_TRUE(handler->got_onjsdialog_);
+ EXPECT_FALSE(handler->got_onbeforeunloaddialog_);
+ EXPECT_TRUE(handler->got_onresetdialogstate_);
+ EXPECT_TRUE(handler->got_onloadend_);
+
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// OnBeforeUnload dialog with immediate callback.
+TEST(JSDialogTest, OnBeforeUnloadRunImmediate) {
+ CefRefPtr<JSDialogTestHandler> handler =
+ new JSDialogTestHandler(JSDialogTestHandler::TYPE_ONBEFOREUNLOAD,
+ JSDialogTestHandler::MODE_RUN_IMMEDIATE,
+ true, // success
+ "", // user_input
+ ""); // result
+ handler->ExecuteTest();
+
+ EXPECT_FALSE(handler->got_onjsdialog_);
+ EXPECT_TRUE(handler->got_onbeforeunloaddialog_);
+ EXPECT_TRUE(handler->got_onresetdialogstate_);
+ EXPECT_TRUE(handler->got_onloadend_);
+
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// OnBeforeUnload dialog with delayed callback.
+TEST(JSDialogTest, OnBeforeUnloadRunDelayed) {
+ CefRefPtr<JSDialogTestHandler> handler =
+ new JSDialogTestHandler(JSDialogTestHandler::TYPE_ONBEFOREUNLOAD,
+ JSDialogTestHandler::MODE_RUN_DELAYED,
+ true, // success
+ "", // user_input
+ ""); // result
+ handler->ExecuteTest();
+
+ EXPECT_FALSE(handler->got_onjsdialog_);
+ EXPECT_TRUE(handler->got_onbeforeunloaddialog_);
+ EXPECT_TRUE(handler->got_onresetdialogstate_);
+ EXPECT_TRUE(handler->got_onloadend_);
+
+ ReleaseAndWaitForDestructor(handler);
+}
diff --git a/tests/ceftests/life_span_unittest.cc b/tests/ceftests/life_span_unittest.cc
new file mode 100644
index 00000000..262bb7a5
--- /dev/null
+++ b/tests/ceftests/life_span_unittest.cc
@@ -0,0 +1,347 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "include/base/cef_callback.h"
+#include "include/test/cef_test_helpers.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "tests/ceftests/routing_test_handler.h"
+#include "tests/gtest/include/gtest/gtest.h"
+
+namespace {
+
+const char kLifeSpanUrl[] = "http://tests-life-span/test.html";
+const char kUnloadDialogText[] = "Are you sure?";
+const char kUnloadMsg[] = "LifeSpanTestHandler.Unload";
+
+// Browser side.
+class LifeSpanTestHandler : public RoutingTestHandler {
+ public:
+ struct Settings {
+ Settings()
+ : force_close(false),
+ add_onunload_handler(false),
+ allow_do_close(true),
+ accept_before_unload_dialog(true) {}
+
+ bool force_close;
+ bool add_onunload_handler;
+ bool allow_do_close;
+ bool accept_before_unload_dialog;
+ };
+
+ explicit LifeSpanTestHandler(const Settings& settings)
+ : settings_(settings), executing_delay_close_(false) {
+ // By default no LifeSpan tests call DestroyTest().
+ SetDestroyTestExpected(false);
+ }
+
+ void RunTest() override {
+ // Add the resources that we will navigate to/from.
+ std::string page = "<html><script>";
+
+ page += "window.onunload = function() { window.testQuery({request:'" +
+ std::string(kUnloadMsg) + "'}); };";
+
+ if (settings_.add_onunload_handler) {
+ page += "window.onbeforeunload = function() { return '" +
+ std::string(kUnloadDialogText) + "'; };";
+ }
+
+ page += "</script><body>Page</body></html>";
+ AddResource(kLifeSpanUrl, page, "text/html");
+
+ // Create the browser.
+ CreateBrowser(kLifeSpanUrl);
+
+ // Intentionally don't call SetTestTimeout() for these tests.
+ }
+
+ void OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
+ got_after_created_.yes();
+ RoutingTestHandler::OnAfterCreated(browser);
+ }
+
+ bool DoClose(CefRefPtr<CefBrowser> browser) override {
+ if (executing_delay_close_) {
+ return false;
+ }
+
+ EXPECT_TRUE(browser->IsSame(GetBrowser()));
+
+ got_do_close_.yes();
+
+ if (!settings_.allow_do_close) {
+ // The close will be canceled.
+ ScheduleDelayClose();
+ }
+
+ return !settings_.allow_do_close;
+ }
+
+ void OnBeforeClose(CefRefPtr<CefBrowser> browser) override {
+ if (!executing_delay_close_) {
+ got_before_close_.yes();
+ EXPECT_TRUE(browser->IsSame(GetBrowser()));
+ }
+
+ RoutingTestHandler::OnBeforeClose(browser);
+ }
+
+ bool OnBeforeUnloadDialog(CefRefPtr<CefBrowser> browser,
+ const CefString& message_text,
+ bool is_reload,
+ CefRefPtr<CefJSDialogCallback> callback) override {
+ if (executing_delay_close_) {
+ callback->Continue(true, CefString());
+ return true;
+ }
+
+ EXPECT_TRUE(browser->IsSame(GetBrowser()));
+
+ // The message is no longer configurable via JavaScript.
+ // See http://crbug.com/587940.
+ EXPECT_STREQ("Is it OK to leave/reload this page?",
+ message_text.ToString().c_str());
+
+ EXPECT_FALSE(is_reload);
+ EXPECT_TRUE(callback.get());
+
+ if (!settings_.accept_before_unload_dialog) {
+ // The close will be canceled.
+ ScheduleDelayClose();
+ }
+
+ got_before_unload_dialog_.yes();
+ callback->Continue(settings_.accept_before_unload_dialog, CefString());
+ return true;
+ }
+
+ void OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int httpStatusCode) override {
+ got_load_end_.yes();
+ EXPECT_TRUE(browser->IsSame(GetBrowser()));
+
+ if (settings_.add_onunload_handler) {
+ // Send the page a user gesture to enable firing of the onbefureunload
+ // handler. See https://crbug.com/707007.
+ CefExecuteJavaScriptWithUserGestureForTests(frame, CefString());
+ }
+
+ // Attempt to close the browser.
+ CloseBrowser(browser, settings_.force_close);
+ }
+
+ bool OnQuery(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int64 query_id,
+ const CefString& request,
+ bool persistent,
+ CefRefPtr<Callback> callback) override {
+ if (request.ToString() == kUnloadMsg) {
+ if (!executing_delay_close_) {
+ got_unload_message_.yes();
+ }
+ }
+ callback->Success("");
+ return true;
+ }
+
+ TrackCallback got_after_created_;
+ TrackCallback got_do_close_;
+ TrackCallback got_before_close_;
+ TrackCallback got_before_unload_dialog_;
+ TrackCallback got_unload_message_;
+ TrackCallback got_load_end_;
+ TrackCallback got_delay_close_;
+
+ private:
+ // Wait a bit to make sure no additional events are received and then close
+ // the window.
+ void ScheduleDelayClose() {
+ // This test will call DestroyTest().
+ SetDestroyTestExpected(true);
+
+ CefPostDelayedTask(
+ TID_UI, base::BindOnce(&LifeSpanTestHandler::DelayClose, this), 100);
+ }
+
+ void DelayClose() {
+ got_delay_close_.yes();
+ executing_delay_close_ = true;
+ DestroyTest();
+ }
+
+ Settings settings_;
+
+ // Forces the window to close (bypasses test conditions).
+ bool executing_delay_close_;
+
+ IMPLEMENT_REFCOUNTING(LifeSpanTestHandler);
+};
+
+} // namespace
+
+TEST(LifeSpanTest, DoCloseAllow) {
+ LifeSpanTestHandler::Settings settings;
+ settings.allow_do_close = true;
+ CefRefPtr<LifeSpanTestHandler> handler = new LifeSpanTestHandler(settings);
+ handler->ExecuteTest();
+
+ EXPECT_TRUE(handler->got_after_created_);
+ EXPECT_TRUE(handler->got_do_close_);
+ EXPECT_TRUE(handler->got_before_close_);
+ EXPECT_FALSE(handler->got_before_unload_dialog_);
+ EXPECT_TRUE(handler->got_unload_message_);
+ EXPECT_TRUE(handler->got_load_end_);
+ EXPECT_FALSE(handler->got_delay_close_);
+
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(LifeSpanTest, DoCloseAllowForce) {
+ LifeSpanTestHandler::Settings settings;
+ settings.allow_do_close = true;
+ settings.force_close = true;
+ CefRefPtr<LifeSpanTestHandler> handler = new LifeSpanTestHandler(settings);
+ handler->ExecuteTest();
+
+ EXPECT_TRUE(handler->got_after_created_);
+ EXPECT_TRUE(handler->got_do_close_);
+ EXPECT_TRUE(handler->got_before_close_);
+ EXPECT_FALSE(handler->got_before_unload_dialog_);
+ EXPECT_TRUE(handler->got_unload_message_);
+ EXPECT_TRUE(handler->got_load_end_);
+ EXPECT_FALSE(handler->got_delay_close_);
+
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(LifeSpanTest, DoCloseDisallow) {
+ LifeSpanTestHandler::Settings settings;
+ settings.allow_do_close = false;
+ CefRefPtr<LifeSpanTestHandler> handler = new LifeSpanTestHandler(settings);
+ handler->ExecuteTest();
+
+ EXPECT_TRUE(handler->got_after_created_);
+ EXPECT_TRUE(handler->got_do_close_);
+ EXPECT_FALSE(handler->got_before_close_);
+ EXPECT_FALSE(handler->got_before_unload_dialog_);
+ EXPECT_TRUE(handler->got_unload_message_);
+ EXPECT_TRUE(handler->got_load_end_);
+ EXPECT_TRUE(handler->got_delay_close_);
+
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(LifeSpanTest, DoCloseDisallowForce) {
+ LifeSpanTestHandler::Settings settings;
+ settings.allow_do_close = false;
+ settings.force_close = true;
+ CefRefPtr<LifeSpanTestHandler> handler = new LifeSpanTestHandler(settings);
+ handler->ExecuteTest();
+
+ EXPECT_TRUE(handler->got_after_created_);
+ EXPECT_TRUE(handler->got_do_close_);
+ EXPECT_FALSE(handler->got_before_close_);
+ EXPECT_FALSE(handler->got_before_unload_dialog_);
+ EXPECT_TRUE(handler->got_unload_message_);
+ EXPECT_TRUE(handler->got_load_end_);
+ EXPECT_TRUE(handler->got_delay_close_);
+
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(LifeSpanTest, DoCloseDisallowWithOnUnloadAllow) {
+ LifeSpanTestHandler::Settings settings;
+ settings.allow_do_close = false;
+ settings.add_onunload_handler = true;
+ settings.accept_before_unload_dialog = true;
+ CefRefPtr<LifeSpanTestHandler> handler = new LifeSpanTestHandler(settings);
+ handler->ExecuteTest();
+
+ EXPECT_TRUE(handler->got_after_created_);
+ EXPECT_TRUE(handler->got_do_close_);
+ EXPECT_FALSE(handler->got_before_close_);
+ EXPECT_TRUE(handler->got_before_unload_dialog_);
+ EXPECT_TRUE(handler->got_unload_message_);
+ EXPECT_TRUE(handler->got_load_end_);
+ EXPECT_TRUE(handler->got_delay_close_);
+
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(LifeSpanTest, DoCloseAllowWithOnUnloadForce) {
+ LifeSpanTestHandler::Settings settings;
+ settings.allow_do_close = true;
+ settings.add_onunload_handler = true;
+ settings.force_close = true;
+ CefRefPtr<LifeSpanTestHandler> handler = new LifeSpanTestHandler(settings);
+ handler->ExecuteTest();
+
+ EXPECT_TRUE(handler->got_after_created_);
+ EXPECT_TRUE(handler->got_do_close_);
+ EXPECT_TRUE(handler->got_before_close_);
+ EXPECT_FALSE(handler->got_before_unload_dialog_);
+ EXPECT_TRUE(handler->got_unload_message_);
+ EXPECT_TRUE(handler->got_load_end_);
+ EXPECT_FALSE(handler->got_delay_close_);
+
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(LifeSpanTest, DoCloseDisallowWithOnUnloadForce) {
+ LifeSpanTestHandler::Settings settings;
+ settings.allow_do_close = false;
+ settings.add_onunload_handler = true;
+ settings.force_close = true;
+ CefRefPtr<LifeSpanTestHandler> handler = new LifeSpanTestHandler(settings);
+ handler->ExecuteTest();
+
+ EXPECT_TRUE(handler->got_after_created_);
+ EXPECT_TRUE(handler->got_do_close_);
+ EXPECT_FALSE(handler->got_before_close_);
+ EXPECT_FALSE(handler->got_before_unload_dialog_);
+ EXPECT_TRUE(handler->got_unload_message_);
+ EXPECT_TRUE(handler->got_load_end_);
+ EXPECT_TRUE(handler->got_delay_close_);
+
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(LifeSpanTest, OnUnloadAllow) {
+ LifeSpanTestHandler::Settings settings;
+ settings.add_onunload_handler = true;
+ settings.accept_before_unload_dialog = true;
+ CefRefPtr<LifeSpanTestHandler> handler = new LifeSpanTestHandler(settings);
+ handler->ExecuteTest();
+
+ EXPECT_TRUE(handler->got_after_created_);
+ EXPECT_TRUE(handler->got_do_close_);
+ EXPECT_TRUE(handler->got_before_close_);
+ EXPECT_TRUE(handler->got_before_unload_dialog_);
+ EXPECT_TRUE(handler->got_unload_message_);
+ EXPECT_TRUE(handler->got_load_end_);
+ EXPECT_FALSE(handler->got_delay_close_);
+
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(LifeSpanTest, OnUnloadDisallow) {
+ LifeSpanTestHandler::Settings settings;
+ settings.add_onunload_handler = true;
+ settings.accept_before_unload_dialog = false;
+ CefRefPtr<LifeSpanTestHandler> handler = new LifeSpanTestHandler(settings);
+ handler->ExecuteTest();
+
+ EXPECT_TRUE(handler->got_after_created_);
+ EXPECT_FALSE(handler->got_do_close_);
+ EXPECT_FALSE(handler->got_before_close_);
+ EXPECT_TRUE(handler->got_before_unload_dialog_);
+ EXPECT_FALSE(handler->got_unload_message_);
+ EXPECT_TRUE(handler->got_load_end_);
+ EXPECT_TRUE(handler->got_delay_close_);
+
+ ReleaseAndWaitForDestructor(handler);
+}
diff --git a/tests/ceftests/media_access_unittest.cc b/tests/ceftests/media_access_unittest.cc
new file mode 100644
index 00000000..96d0f593
--- /dev/null
+++ b/tests/ceftests/media_access_unittest.cc
@@ -0,0 +1,725 @@
+// Copyright 2022 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#include <string>
+#include <vector>
+
+#include "include/base/cef_bind.h"
+#include "include/cef_parser.h"
+#include "include/cef_permission_handler.h"
+#include "include/cef_request_context_handler.h"
+#include "include/test/cef_test_helpers.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "include/wrapper/cef_stream_resource_handler.h"
+#include "tests/ceftests/test_handler.h"
+#include "tests/ceftests/test_suite.h"
+#include "tests/ceftests/test_util.h"
+#include "tests/gtest/include/gtest/gtest.h"
+#include "tests/shared/browser/client_app_browser.h"
+
+namespace {
+
+// Media access requires HTTPS.
+const char kMediaUrl[] = "https://media-access-test/media.html";
+const char kMediaOrigin[] = "https://media-access-test/";
+
+constexpr char kMediaNavUrl[] = "https://media-access-test/nav.html";
+
+// Browser-side app delegate.
+class MediaAccessBrowserTest : public client::ClientAppBrowser::Delegate,
+ public CefPermissionHandler {
+ public:
+ MediaAccessBrowserTest() {}
+
+ void OnBeforeCommandLineProcessing(
+ CefRefPtr<client::ClientAppBrowser> app,
+ CefRefPtr<CefCommandLine> command_line) override {
+ // We might run tests on systems that don't have media device,
+ // so just use fake devices.
+ command_line->AppendSwitch("use-fake-device-for-media-stream");
+ }
+
+ private:
+ IMPLEMENT_REFCOUNTING(MediaAccessBrowserTest);
+};
+
+class TestSetup {
+ public:
+ TestSetup() {}
+
+ // CONFIGURATION
+
+ // True if a user gesture is required for the getDisplayMedia call.
+ bool needs_user_gesture = false;
+
+ // Deny the prompt by returning false in OnRequestMediaAccessPermission.
+ bool deny_implicitly = false;
+
+ // Deny the prompt by returning true in OnRequestMediaAccessPermission but
+ // then never calling CefMediaAccessCallback::Continue.
+ bool deny_with_navigation = false;
+
+ // Don't synchronously execute the callback in OnRequestMediaAccessPermission.
+ bool continue_async = false;
+
+ // RESULTS
+
+ // Method callbacks.
+ TrackCallback got_request;
+ TrackCallback got_change;
+
+ // JS success state.
+ TrackCallback got_js_success;
+ TrackCallback got_audio;
+ TrackCallback got_video;
+
+ // JS error state.
+ TrackCallback got_js_error;
+ std::string js_error_str;
+
+ // JS timeout state.
+ TrackCallback got_js_timeout;
+};
+
+class MediaAccessTestHandler : public TestHandler, public CefPermissionHandler {
+ public:
+ MediaAccessTestHandler(TestSetup* tr, uint32 request, uint32 response)
+ : test_setup_(tr), request_(request), response_(response) {}
+
+ cef_return_value_t OnBeforeResourceLoad(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefCallback> callback) override {
+ std::string newUrl = request->GetURL();
+ if (newUrl.find("tests/exit") != std::string::npos) {
+ if (newUrl.find("SUCCESS") != std::string::npos) {
+ EXPECT_FALSE(test_setup_->got_js_success);
+ test_setup_->got_js_success.yes();
+
+ auto dict = ParseURLData(newUrl);
+ if (dict->GetBool("got_video_track")) {
+ test_setup_->got_video.yes();
+ }
+ if (dict->GetBool("got_audio_track")) {
+ test_setup_->got_audio.yes();
+ }
+ } else if (newUrl.find("ERROR") != std::string::npos) {
+ EXPECT_FALSE(test_setup_->got_js_error);
+ test_setup_->got_js_error.yes();
+
+ auto dict = ParseURLData(newUrl);
+ test_setup_->js_error_str = dict->GetString("error_str");
+ } else if (newUrl.find("TIMEOUT") != std::string::npos) {
+ EXPECT_FALSE(test_setup_->got_js_timeout);
+ test_setup_->got_js_timeout.yes();
+ }
+ DestroyTest();
+ return RV_CANCEL;
+ }
+
+ return RV_CONTINUE;
+ }
+
+ void RunTest() override {
+ std::string page =
+ "<html><head>"
+ "<script>"
+ "function onResult(val, data) {"
+ " if(!data) {"
+ " data = {};"
+ " }"
+ " document.location = "
+ "`http://tests/"
+ "exit?result=${val}&data=${encodeURIComponent(JSON.stringify(data))}`;"
+ "}"
+ "function runTest() {";
+
+ if (want_audio_device() || want_video_device()) {
+ page += std::string("navigator.mediaDevices.getUserMedia({audio: ") +
+ (want_audio_device() ? "true" : "false") +
+ ", video: " + (want_video_device() ? "true" : "false") + "})";
+ } else {
+ page += std::string("navigator.mediaDevices.getDisplayMedia({audio: ") +
+ (want_audio_desktop() ? "true" : "false") +
+ ", video: " + (want_video_desktop() ? "true" : "false") + "})";
+ }
+
+ page +=
+ ".then(function(stream) {"
+ " onResult(`SUCCESS`, {got_audio_track: "
+ "stream.getAudioTracks().length "
+ "> 0, got_video_track: stream.getVideoTracks().length > 0});"
+ "})"
+ ".catch(function(err) {"
+ " console.log(err.toString());"
+ " onResult(`ERROR`, {error_str: err.toString()});"
+ "});"
+ "}";
+
+ if (test_setup_->deny_implicitly && IsChromeRuntimeEnabled()) {
+ // Default behavior with the Chrome runtime is to show a UI prompt, so add
+ // a timeout.
+ page += "setTimeout(() => { onResult(`TIMEOUT`); }, 1000);";
+ } else if (test_setup_->deny_with_navigation) {
+ // Cancel the pending request by navigating.
+ page += "setTimeout(() => { document.location = '" +
+ std::string(kMediaNavUrl) + "'; }, 1000);";
+ }
+
+ page +=
+ "</script>"
+ "</head><body>";
+
+ if (!test_setup_->needs_user_gesture) {
+ page += "<script>runTest();</script>";
+ }
+
+ page += "MEDIA ACCESS TEST</body></html>";
+
+ // Create the request context that will use an in-memory cache.
+ CefRequestContextSettings settings;
+ CefRefPtr<CefRequestContext> request_context =
+ CefRequestContext::CreateContext(settings, nullptr);
+
+ AddResource(kMediaUrl, page, "text/html");
+
+ if (test_setup_->deny_with_navigation) {
+ AddResource(kMediaNavUrl, "<html><body>Navigated</body></html>",
+ "text/html");
+ }
+
+ // Create the browser.
+ CreateBrowser(kMediaUrl, request_context);
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout();
+ }
+
+ CefRefPtr<CefPermissionHandler> GetPermissionHandler() override {
+ return this;
+ }
+
+ void OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int httpStatusCode) override {
+ if (test_setup_->deny_with_navigation) {
+ if (frame->GetURL().ToString() == kMediaNavUrl) {
+ DestroyTest();
+ }
+ } else if (test_setup_->needs_user_gesture) {
+ CefExecuteJavaScriptWithUserGestureForTests(frame, "runTest()");
+ }
+ }
+
+ bool OnRequestMediaAccessPermission(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const CefString& requesting_origin,
+ uint32 requested_permissions,
+ CefRefPtr<CefMediaAccessCallback> callback) override {
+ EXPECT_UI_THREAD();
+ EXPECT_TRUE(frame->IsMain());
+
+ EXPECT_EQ(requested_permissions, request_);
+ EXPECT_STREQ(kMediaOrigin, requesting_origin.ToString().c_str());
+
+ EXPECT_FALSE(test_setup_->got_request);
+ test_setup_->got_request.yes();
+
+ if (test_setup_->deny_implicitly) {
+ return false;
+ }
+
+ if (test_setup_->deny_with_navigation) {
+ // Handle the request, but never execute the callback.
+ callback_ = callback;
+ return true;
+ }
+
+ if (test_setup_->continue_async) {
+ CefPostTask(TID_UI, base::BindOnce(&CefMediaAccessCallback::Continue,
+ callback, response_));
+ } else {
+ callback->Continue(response_);
+ }
+ return true;
+ }
+
+ void OnMediaAccessChange(CefRefPtr<CefBrowser> browser,
+ bool has_video_access,
+ bool has_audio_access) override {
+ EXPECT_UI_THREAD();
+ EXPECT_EQ(got_video_device() || got_video_desktop(), has_video_access);
+ EXPECT_EQ(got_audio_device() || got_audio_desktop(), has_audio_access);
+ EXPECT_FALSE(test_setup_->got_change);
+ test_setup_->got_change.yes();
+ }
+
+ void DestroyTest() override {
+ callback_ = nullptr;
+
+ const size_t js_outcome_ct = test_setup_->got_js_success +
+ test_setup_->got_js_error +
+ test_setup_->got_js_timeout;
+ if (test_setup_->deny_with_navigation) {
+ // Expect no JS outcome.
+ EXPECT_EQ(0U, js_outcome_ct);
+ } else {
+ // Expect a single JS outcome.
+ EXPECT_EQ(1U, js_outcome_ct);
+ }
+
+ TestHandler::DestroyTest();
+ }
+
+ private:
+ bool want_audio_device() const {
+ return request_ & CEF_MEDIA_PERMISSION_DEVICE_AUDIO_CAPTURE;
+ }
+ bool want_video_device() const {
+ return request_ & CEF_MEDIA_PERMISSION_DEVICE_VIDEO_CAPTURE;
+ }
+ bool want_audio_desktop() const {
+ return request_ & CEF_MEDIA_PERMISSION_DESKTOP_AUDIO_CAPTURE;
+ }
+ bool want_video_desktop() const {
+ return request_ & CEF_MEDIA_PERMISSION_DESKTOP_VIDEO_CAPTURE;
+ }
+
+ bool got_audio_device() const {
+ return response_ & CEF_MEDIA_PERMISSION_DEVICE_AUDIO_CAPTURE;
+ }
+ bool got_video_device() const {
+ return response_ & CEF_MEDIA_PERMISSION_DEVICE_VIDEO_CAPTURE;
+ }
+ bool got_audio_desktop() const {
+ return response_ & CEF_MEDIA_PERMISSION_DESKTOP_AUDIO_CAPTURE;
+ }
+ bool got_video_desktop() const {
+ return response_ & CEF_MEDIA_PERMISSION_DESKTOP_VIDEO_CAPTURE;
+ }
+
+ CefRefPtr<CefDictionaryValue> ParseURLData(const std::string& url) {
+ const std::string& find_str = "&data=";
+ const std::string& data_string =
+ url.substr(url.find(find_str) + std::string(find_str).length());
+ const std::string& data_string_decoded = CefURIDecode(
+ data_string, false,
+ static_cast<cef_uri_unescape_rule_t>(
+ UU_SPACES | UU_URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS));
+ auto obj =
+ CefParseJSON(data_string_decoded, JSON_PARSER_ALLOW_TRAILING_COMMAS);
+ return obj->GetDictionary();
+ }
+
+ TestSetup* const test_setup_;
+ const uint32 request_;
+ const uint32 response_;
+
+ CefRefPtr<CefMediaAccessCallback> callback_;
+
+ IMPLEMENT_REFCOUNTING(MediaAccessTestHandler);
+};
+} // namespace
+
+// Capture device tests
+TEST(MediaAccessTest, DeviceFailureWhenReturningFalse) {
+ TestSetup test_setup;
+ test_setup.deny_implicitly = true;
+
+ CefRefPtr<MediaAccessTestHandler> handler =
+ new MediaAccessTestHandler(&test_setup,
+ CEF_MEDIA_PERMISSION_DEVICE_AUDIO_CAPTURE |
+ CEF_MEDIA_PERMISSION_DEVICE_VIDEO_CAPTURE,
+ CEF_MEDIA_PERMISSION_NONE);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(test_setup.got_request);
+ if (IsChromeRuntimeEnabled()) {
+ // Chrome shows a UI prompt, so we time out.
+ EXPECT_TRUE(test_setup.got_js_timeout);
+ } else {
+ EXPECT_TRUE(test_setup.got_js_error);
+ EXPECT_STREQ("NotAllowedError: Permission denied",
+ test_setup.js_error_str.c_str());
+ }
+ EXPECT_FALSE(test_setup.got_change);
+}
+
+TEST(MediaAccessTest, DeviceFailureWhenNoCallback) {
+ TestSetup test_setup;
+ test_setup.deny_with_navigation = true;
+
+ CefRefPtr<MediaAccessTestHandler> handler =
+ new MediaAccessTestHandler(&test_setup,
+ CEF_MEDIA_PERMISSION_DEVICE_AUDIO_CAPTURE |
+ CEF_MEDIA_PERMISSION_DEVICE_VIDEO_CAPTURE,
+ CEF_MEDIA_PERMISSION_NONE);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ // No JS result.
+ EXPECT_TRUE(test_setup.got_request);
+ EXPECT_FALSE(test_setup.got_change);
+}
+
+TEST(MediaAccessTest, DeviceFailureWhenReturningNoPermission) {
+ TestSetup test_setup;
+
+ CefRefPtr<MediaAccessTestHandler> handler =
+ new MediaAccessTestHandler(&test_setup,
+ CEF_MEDIA_PERMISSION_DEVICE_AUDIO_CAPTURE |
+ CEF_MEDIA_PERMISSION_DEVICE_VIDEO_CAPTURE,
+ CEF_MEDIA_PERMISSION_NONE);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(test_setup.got_request);
+ EXPECT_TRUE(test_setup.got_js_error);
+ EXPECT_STREQ("NotAllowedError: Permission denied",
+ test_setup.js_error_str.c_str());
+ EXPECT_FALSE(test_setup.got_change);
+}
+
+TEST(MediaAccessTest, DeviceFailureWhenReturningNoPermissionAsync) {
+ TestSetup test_setup;
+ test_setup.continue_async = true;
+
+ CefRefPtr<MediaAccessTestHandler> handler =
+ new MediaAccessTestHandler(&test_setup,
+ CEF_MEDIA_PERMISSION_DEVICE_AUDIO_CAPTURE |
+ CEF_MEDIA_PERMISSION_DEVICE_VIDEO_CAPTURE,
+ CEF_MEDIA_PERMISSION_NONE);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(test_setup.got_request);
+ EXPECT_TRUE(test_setup.got_js_error);
+ EXPECT_STREQ("NotAllowedError: Permission denied",
+ test_setup.js_error_str.c_str());
+ EXPECT_FALSE(test_setup.got_change);
+}
+
+TEST(MediaAccessTest, DeviceFailureWhenRequestingAudioButReturningVideo) {
+ TestSetup test_setup;
+
+ CefRefPtr<MediaAccessTestHandler> handler = new MediaAccessTestHandler(
+ &test_setup, CEF_MEDIA_PERMISSION_DEVICE_AUDIO_CAPTURE,
+ CEF_MEDIA_PERMISSION_DEVICE_VIDEO_CAPTURE);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(test_setup.got_request);
+ EXPECT_TRUE(test_setup.got_js_error);
+ EXPECT_STREQ("NotAllowedError: Invalid state",
+ test_setup.js_error_str.c_str());
+ EXPECT_FALSE(test_setup.got_change);
+}
+
+TEST(MediaAccessTest, DeviceFailureWhenRequestingVideoButReturningAudio) {
+ TestSetup test_setup;
+
+ CefRefPtr<MediaAccessTestHandler> handler = new MediaAccessTestHandler(
+ &test_setup, CEF_MEDIA_PERMISSION_DEVICE_VIDEO_CAPTURE,
+ CEF_MEDIA_PERMISSION_DEVICE_AUDIO_CAPTURE);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(test_setup.got_request);
+ EXPECT_TRUE(test_setup.got_js_error);
+ EXPECT_STREQ("NotAllowedError: Invalid state",
+ test_setup.js_error_str.c_str());
+ EXPECT_FALSE(test_setup.got_change);
+}
+
+TEST(MediaAccessTest, DevicePartialFailureReturningVideo) {
+ TestSetup test_setup;
+
+ CefRefPtr<MediaAccessTestHandler> handler =
+ new MediaAccessTestHandler(&test_setup,
+ CEF_MEDIA_PERMISSION_DEVICE_AUDIO_CAPTURE |
+ CEF_MEDIA_PERMISSION_DEVICE_VIDEO_CAPTURE,
+ CEF_MEDIA_PERMISSION_DEVICE_VIDEO_CAPTURE);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(test_setup.got_request);
+ EXPECT_TRUE(test_setup.got_js_error);
+ EXPECT_STREQ("NotAllowedError: Invalid state",
+ test_setup.js_error_str.c_str());
+ EXPECT_FALSE(test_setup.got_change);
+}
+
+TEST(MediaAccessTest, DevicePartialFailureReturningAudio) {
+ TestSetup test_setup;
+
+ CefRefPtr<MediaAccessTestHandler> handler =
+ new MediaAccessTestHandler(&test_setup,
+ CEF_MEDIA_PERMISSION_DEVICE_AUDIO_CAPTURE |
+ CEF_MEDIA_PERMISSION_DEVICE_VIDEO_CAPTURE,
+ CEF_MEDIA_PERMISSION_DEVICE_AUDIO_CAPTURE);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(test_setup.got_request);
+ EXPECT_TRUE(test_setup.got_js_error);
+ EXPECT_STREQ("NotAllowedError: Invalid state",
+ test_setup.js_error_str.c_str());
+ EXPECT_FALSE(test_setup.got_change);
+}
+
+TEST(MediaAccessTest, DeviceFailureWhenReturningScreenCapture1) {
+ TestSetup test_setup;
+
+ CefRefPtr<MediaAccessTestHandler> handler =
+ new MediaAccessTestHandler(&test_setup,
+ CEF_MEDIA_PERMISSION_DEVICE_AUDIO_CAPTURE |
+ CEF_MEDIA_PERMISSION_DEVICE_VIDEO_CAPTURE,
+ CEF_MEDIA_PERMISSION_DESKTOP_AUDIO_CAPTURE);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(test_setup.got_request);
+ EXPECT_TRUE(test_setup.got_js_error);
+ EXPECT_STREQ("NotAllowedError: Invalid state",
+ test_setup.js_error_str.c_str());
+ EXPECT_FALSE(test_setup.got_change);
+}
+
+TEST(MediaAccessTest, DeviceFailureWhenReturningScreenCapture2) {
+ TestSetup test_setup;
+
+ CefRefPtr<MediaAccessTestHandler> handler =
+ new MediaAccessTestHandler(&test_setup,
+ CEF_MEDIA_PERMISSION_DEVICE_AUDIO_CAPTURE |
+ CEF_MEDIA_PERMISSION_DEVICE_VIDEO_CAPTURE,
+ CEF_MEDIA_PERMISSION_DESKTOP_VIDEO_CAPTURE);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(test_setup.got_request);
+ EXPECT_TRUE(test_setup.got_js_error);
+ EXPECT_STREQ("NotAllowedError: Invalid state",
+ test_setup.js_error_str.c_str());
+ EXPECT_FALSE(test_setup.got_change);
+}
+
+TEST(MediaAccessTest, DeviceFailureWhenReturningScreenCapture3) {
+ TestSetup test_setup;
+
+ CefRefPtr<MediaAccessTestHandler> handler = new MediaAccessTestHandler(
+ &test_setup, CEF_MEDIA_PERMISSION_DEVICE_AUDIO_CAPTURE,
+ CEF_MEDIA_PERMISSION_DESKTOP_VIDEO_CAPTURE);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(test_setup.got_request);
+ EXPECT_TRUE(test_setup.got_js_error);
+ EXPECT_STREQ("NotAllowedError: Invalid state",
+ test_setup.js_error_str.c_str());
+ EXPECT_FALSE(test_setup.got_change);
+}
+
+TEST(MediaAccessTest, DeviceFailureWhenReturningScreenCapture4) {
+ TestSetup test_setup;
+
+ CefRefPtr<MediaAccessTestHandler> handler = new MediaAccessTestHandler(
+ &test_setup, CEF_MEDIA_PERMISSION_DEVICE_AUDIO_CAPTURE,
+ CEF_MEDIA_PERMISSION_DESKTOP_AUDIO_CAPTURE);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(test_setup.got_request);
+ EXPECT_TRUE(test_setup.got_js_error);
+ EXPECT_STREQ("NotAllowedError: Invalid state",
+ test_setup.js_error_str.c_str());
+ EXPECT_FALSE(test_setup.got_change);
+}
+
+TEST(MediaAccessTest, DeviceFailureWhenReturningScreenCapture5) {
+ TestSetup test_setup;
+
+ CefRefPtr<MediaAccessTestHandler> handler = new MediaAccessTestHandler(
+ &test_setup, CEF_MEDIA_PERMISSION_DEVICE_VIDEO_CAPTURE,
+ CEF_MEDIA_PERMISSION_DESKTOP_VIDEO_CAPTURE);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(test_setup.got_request);
+ EXPECT_TRUE(test_setup.got_js_error);
+ EXPECT_STREQ("NotAllowedError: Invalid state",
+ test_setup.js_error_str.c_str());
+ EXPECT_FALSE(test_setup.got_change);
+}
+
+TEST(MediaAccessTest, DeviceFailureWhenReturningScreenCapture6) {
+ TestSetup test_setup;
+
+ CefRefPtr<MediaAccessTestHandler> handler = new MediaAccessTestHandler(
+ &test_setup, CEF_MEDIA_PERMISSION_DEVICE_VIDEO_CAPTURE,
+ CEF_MEDIA_PERMISSION_DESKTOP_AUDIO_CAPTURE);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(test_setup.got_request);
+ EXPECT_TRUE(test_setup.got_js_error);
+ EXPECT_STREQ("NotAllowedError: Invalid state",
+ test_setup.js_error_str.c_str());
+ EXPECT_FALSE(test_setup.got_change);
+}
+
+TEST(MediaAccessTest, DeviceSuccessAudioOnly) {
+ TestSetup test_setup;
+
+ CefRefPtr<MediaAccessTestHandler> handler = new MediaAccessTestHandler(
+ &test_setup, CEF_MEDIA_PERMISSION_DEVICE_AUDIO_CAPTURE,
+ CEF_MEDIA_PERMISSION_DEVICE_AUDIO_CAPTURE);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(test_setup.got_request);
+ EXPECT_TRUE(test_setup.got_js_success);
+ EXPECT_TRUE(test_setup.got_audio);
+ EXPECT_FALSE(test_setup.got_video);
+ EXPECT_TRUE(test_setup.got_change);
+}
+
+TEST(MediaAccessTest, DeviceSuccessVideoOnly) {
+ TestSetup test_setup;
+
+ CefRefPtr<MediaAccessTestHandler> handler = new MediaAccessTestHandler(
+ &test_setup, CEF_MEDIA_PERMISSION_DEVICE_VIDEO_CAPTURE,
+ CEF_MEDIA_PERMISSION_DEVICE_VIDEO_CAPTURE);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(test_setup.got_request);
+ EXPECT_TRUE(test_setup.got_js_success);
+ EXPECT_FALSE(test_setup.got_audio);
+ EXPECT_TRUE(test_setup.got_video);
+ EXPECT_TRUE(test_setup.got_change);
+}
+
+TEST(MediaAccessTest, DeviceSuccessAudioVideo) {
+ TestSetup test_setup;
+
+ CefRefPtr<MediaAccessTestHandler> handler =
+ new MediaAccessTestHandler(&test_setup,
+ CEF_MEDIA_PERMISSION_DEVICE_VIDEO_CAPTURE |
+ CEF_MEDIA_PERMISSION_DEVICE_AUDIO_CAPTURE,
+ CEF_MEDIA_PERMISSION_DEVICE_VIDEO_CAPTURE |
+ CEF_MEDIA_PERMISSION_DEVICE_AUDIO_CAPTURE);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(test_setup.got_request);
+ EXPECT_TRUE(test_setup.got_js_success);
+ EXPECT_TRUE(test_setup.got_audio);
+ EXPECT_TRUE(test_setup.got_video);
+ EXPECT_TRUE(test_setup.got_change);
+}
+
+TEST(MediaAccessTest, DeviceSuccessAudioVideoAsync) {
+ TestSetup test_setup;
+ test_setup.continue_async = true;
+
+ CefRefPtr<MediaAccessTestHandler> handler =
+ new MediaAccessTestHandler(&test_setup,
+ CEF_MEDIA_PERMISSION_DEVICE_VIDEO_CAPTURE |
+ CEF_MEDIA_PERMISSION_DEVICE_AUDIO_CAPTURE,
+ CEF_MEDIA_PERMISSION_DEVICE_VIDEO_CAPTURE |
+ CEF_MEDIA_PERMISSION_DEVICE_AUDIO_CAPTURE);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(test_setup.got_request);
+ EXPECT_TRUE(test_setup.got_js_success);
+ EXPECT_TRUE(test_setup.got_audio);
+ EXPECT_TRUE(test_setup.got_video);
+ EXPECT_TRUE(test_setup.got_change);
+}
+
+// Screen capture tests
+TEST(MediaAccessTest, DesktopFailureWhenReturningNoPermission) {
+ TestSetup test_setup;
+ test_setup.needs_user_gesture = true;
+
+ CefRefPtr<MediaAccessTestHandler> handler =
+ new MediaAccessTestHandler(&test_setup,
+ CEF_MEDIA_PERMISSION_DESKTOP_AUDIO_CAPTURE |
+ CEF_MEDIA_PERMISSION_DESKTOP_VIDEO_CAPTURE,
+ CEF_MEDIA_PERMISSION_NONE);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(test_setup.got_request);
+ EXPECT_TRUE(test_setup.got_js_error);
+ EXPECT_STREQ("NotAllowedError: Permission denied",
+ test_setup.js_error_str.c_str());
+ EXPECT_FALSE(test_setup.got_change);
+}
+
+TEST(MediaAccessTest, DesktopFailureWhenRequestingVideoButReturningAudio) {
+ TestSetup test_setup;
+ test_setup.needs_user_gesture = true;
+
+ CefRefPtr<MediaAccessTestHandler> handler = new MediaAccessTestHandler(
+ &test_setup, CEF_MEDIA_PERMISSION_DESKTOP_VIDEO_CAPTURE,
+ CEF_MEDIA_PERMISSION_DESKTOP_AUDIO_CAPTURE);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(test_setup.got_request);
+ EXPECT_TRUE(test_setup.got_js_error);
+ EXPECT_STREQ("NotAllowedError: Invalid state",
+ test_setup.js_error_str.c_str());
+ EXPECT_FALSE(test_setup.got_change);
+}
+
+TEST(MediaAccessTest, DesktopPartialSuccessReturningVideo) {
+ TestSetup test_setup;
+ test_setup.needs_user_gesture = true;
+
+ CefRefPtr<MediaAccessTestHandler> handler =
+ new MediaAccessTestHandler(&test_setup,
+ CEF_MEDIA_PERMISSION_DESKTOP_AUDIO_CAPTURE |
+ CEF_MEDIA_PERMISSION_DESKTOP_VIDEO_CAPTURE,
+ CEF_MEDIA_PERMISSION_DESKTOP_VIDEO_CAPTURE);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(test_setup.got_request);
+ EXPECT_TRUE(test_setup.got_js_success);
+ EXPECT_FALSE(test_setup.got_audio);
+ EXPECT_TRUE(test_setup.got_video);
+ EXPECT_TRUE(test_setup.got_change);
+}
+
+TEST(MediaAccessTest, DesktopPartialFailureReturningAudio) {
+ TestSetup test_setup;
+ test_setup.needs_user_gesture = true;
+
+ CefRefPtr<MediaAccessTestHandler> handler =
+ new MediaAccessTestHandler(&test_setup,
+ CEF_MEDIA_PERMISSION_DESKTOP_AUDIO_CAPTURE |
+ CEF_MEDIA_PERMISSION_DESKTOP_VIDEO_CAPTURE,
+ CEF_MEDIA_PERMISSION_DESKTOP_AUDIO_CAPTURE);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(test_setup.got_request);
+ EXPECT_TRUE(test_setup.got_js_error);
+ EXPECT_STREQ("NotAllowedError: Invalid state",
+ test_setup.js_error_str.c_str());
+ EXPECT_FALSE(test_setup.got_change);
+}
+
+// Entry point for creating media access browser test objects.
+// Called from client_app_delegates.cc.
+void CreateMediaAccessBrowserTests(
+ client::ClientAppBrowser::DelegateSet& delegates) {
+ delegates.insert(new MediaAccessBrowserTest);
+}
diff --git a/tests/ceftests/message_router_harness_unittest.cc b/tests/ceftests/message_router_harness_unittest.cc
new file mode 100644
index 00000000..42ac0331
--- /dev/null
+++ b/tests/ceftests/message_router_harness_unittest.cc
@@ -0,0 +1,81 @@
+// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/ceftests/message_router_unittest_utils.h"
+
+namespace {
+
+// Used to verify that the test harness (bound functions) behave correctly.
+class HarnessTestHandler : public SingleLoadTestHandler {
+ public:
+ HarnessTestHandler(bool test_success) : test_success_(test_success) {}
+
+ std::string GetMainHTML() override {
+ std::string html;
+ if (test_success_) {
+ // All assertions should pass.
+ html =
+ "<html><body><script>\n"
+ "var fail_ct = 0;\n"
+ "try { window.mrtAssertTotalCount(" LINESTR
+ ",0); } catch (e) { fail_ct++; }\n"
+ "try { window.mrtAssertBrowserCount(" LINESTR
+ ",0); } catch (e) { fail_ct++; }\n"
+ "try { window.mrtAssertContextCount(" LINESTR
+ ",0); } catch (e) { fail_ct++; }\n"
+ "window.mrtNotify('' + (fail_ct == 0));"
+ "</script></body></html>";
+ } else {
+ // All assertions should fail.
+ html =
+ "<html><body><script>\n"
+ "var fail_ct = 0;\n"
+ "try { window.mrtAssertTotalCount(" LINESTR
+ ",1); } catch (e) { fail_ct++; }\n"
+ "try { window.mrtAssertBrowserCount(" LINESTR
+ ",1); } catch (e) { fail_ct++; }\n"
+ "try { window.mrtAssertContextCount(" LINESTR
+ ",1); } catch (e) { fail_ct++; }\n"
+ "window.mrtNotify('' + (fail_ct == 3));"
+ "</script></body></html>";
+ }
+ return html;
+ }
+
+ void OnNotify(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const std::string& message) override {
+ AssertMainBrowser(browser);
+ AssertMainFrame(frame);
+
+ got_done_.yes();
+ EXPECT_STREQ("true", message.c_str());
+ DestroyTest();
+ }
+
+ void DestroyTest() override {
+ EXPECT_TRUE(got_done_);
+ TestHandler::DestroyTest();
+ }
+
+ private:
+ const bool test_success_;
+ TrackCallback got_done_;
+};
+
+} // namespace
+
+// Verify that the test harness works with successful assertions.
+TEST(MessageRouterTest, HarnessSuccess) {
+ CefRefPtr<HarnessTestHandler> handler = new HarnessTestHandler(true);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Verify that the test harness works with failed assertions.
+TEST(MessageRouterTest, HarnessFailure) {
+ CefRefPtr<HarnessTestHandler> handler = new HarnessTestHandler(false);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
diff --git a/tests/ceftests/message_router_multi_query_unittest.cc b/tests/ceftests/message_router_multi_query_unittest.cc
new file mode 100644
index 00000000..9e842089
--- /dev/null
+++ b/tests/ceftests/message_router_multi_query_unittest.cc
@@ -0,0 +1,2013 @@
+// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/ceftests/message_router_unittest_utils.h"
+
+namespace {
+
+const char kTestDomain1[] = "http://tests-mr1.com/";
+const char kTestDomain2[] = "http://tests-mr2.com/";
+const char kTestDomain3[] = "http://tests-mr3.com/";
+
+const char kMultiQueryRequestId[] = "request_id";
+const char kMultiQueryRepeatCt[] = "repeat_ct";
+const char kMultiQueryRequest[] = "request";
+const char kMultiQueryResponse[] = "response";
+const char kMultiQuerySuccess[] = "success";
+const char kMultiQueryError[] = "error";
+const char kMultiQueryErrorMessage[] = "errormsg";
+const int kMultiQueryPersistentResponseCount = 5;
+
+// Generates HTML and verifies results for multiple simultanious queries.
+class MultiQueryManager : public CefMessageRouterBrowserSide::Handler {
+ public:
+ enum TestType {
+ // Initiates a non-persistent query with a successful response.
+ // OnQuery and OnNotify will be called.
+ SUCCESS,
+
+ // Initiates a non-persistent query with a failure response.
+ // OnQuery and OnNotify will be called.
+ FAILURE,
+
+ // Initiates a persistent query with multiple successful responses.
+ // OnQuery, OnNotify and OnQueryCanceled will be called.
+ PERSISTENT_SUCCESS,
+
+ // Initiates a persistent query with multiple successful responses and one
+ // failure response.
+ // OnQuery and OnNotify will be called.
+ PERSISTENT_FAILURE,
+
+ // Initiates a non-persistent query that will be canceled via JavaScript.
+ // No JavaScript callbacks will be executed.
+ // OnQuery and OnQueryCanceled will be called.
+ CANCEL,
+
+ // Initiates a non-persistent query that will not be manually canceled.
+ // No JavaScript callbacks will be executed.
+ // OnQuery and OnQueryCanceled will be called.
+ AUTOCANCEL,
+
+ // Initiates a persistent query with multiple successful responses that will
+ // not be manually canceled.
+ // OnQuery, OnNotify and OnQueryCanceled will be called.
+ PERSISTENT_AUTOCANCEL,
+ };
+
+ class Observer {
+ public:
+ // Called when all manual queries are complete.
+ virtual void OnManualQueriesCompleted(MultiQueryManager* manager) {}
+
+ // Called when all queries are complete.
+ virtual void OnAllQueriesCompleted(MultiQueryManager* manager) {}
+
+ protected:
+ virtual ~Observer() {}
+ };
+
+ MultiQueryManager(const std::string& label,
+ bool synchronous,
+ int id_offset = 0)
+ : label_(label),
+ synchronous_(synchronous),
+ id_offset_(id_offset),
+ finalized_(false),
+ running_(false),
+ manual_total_(0),
+ received_count_(0),
+ manual_complete_count_(0),
+ auto_complete_count_(0),
+ will_cancel_by_removing_handler_(false),
+ weak_ptr_factory_(this) {}
+
+ virtual ~MultiQueryManager() {}
+
+ std::string label() const { return label_; }
+
+ void AddObserver(Observer* observer) {
+ EXPECT_FALSE(running_);
+ observer_set_.insert(observer);
+ }
+
+ void RemoveObserver(Observer* observer) {
+ EXPECT_FALSE(running_);
+ EXPECT_TRUE(observer_set_.erase(observer));
+ }
+
+ // Can be called from any thread, but should always be called from the same
+ // thread.
+ void AddTestQuery(TestType type) {
+ EXPECT_FALSE(finalized_);
+ test_query_vector_.push_back(TestQuery(type));
+ if (!IsAuto(type)) {
+ manual_total_++;
+ }
+ }
+
+ // Must be called after AddTestQuery and before the manager is used.
+ void Finalize() {
+ EXPECT_FALSE(finalized_);
+ finalized_ = true;
+ }
+
+ // Call after all manual queries have completed if you intend to cancel auto
+ // queries by removing the handler.
+ void WillCancelByRemovingHandler() {
+ EXPECT_TRUE(IsManualComplete());
+ will_cancel_by_removing_handler_ = true;
+ }
+
+ std::string GetHTML(bool assert_total, bool assert_browser) const {
+ EXPECT_TRUE(finalized_);
+ EXPECT_FALSE(running_);
+
+ std::string html;
+
+ html = "<html><body>" + label_ + "<script>\n";
+
+ // No requests should exist.
+ if (assert_total) {
+ html += "window.mrtAssertTotalCount(" LINESTR ",0);\n";
+ }
+ if (assert_browser) {
+ html += "window.mrtAssertBrowserCount(" LINESTR ",0);\n";
+ }
+ html += "window.mrtAssertContextCount(" LINESTR ",0);\n";
+
+ if (synchronous_) {
+ // Run all of the queries synchronously. None will complete before the
+ // last one begins.
+ for (size_t i = 0; i < test_query_vector_.size(); ++i) {
+ const TestQuery& query = test_query_vector_[i];
+ html += GetQueryHTML(static_cast<int>(i), query);
+ }
+
+ const int total_ct = static_cast<int>(test_query_vector_.size());
+
+ // Pending requests should match the total created.
+ const std::string& total_val = GetIntString(total_ct);
+ if (assert_total) {
+ html += "window.mrtAssertTotalCount(" LINESTR "," + total_val + ");\n";
+ }
+ if (assert_browser) {
+ html +=
+ "window.mrtAssertBrowserCount(" LINESTR "," + total_val + ");\n";
+ }
+ html += "window.mrtAssertContextCount(" LINESTR "," + total_val + ");\n";
+
+ int cancel_ct = 0;
+
+ // Cancel all of the queries with type CANCEL.
+ for (size_t i = 0; i < test_query_vector_.size(); ++i) {
+ const TestQuery& query = test_query_vector_[i];
+ if (query.type == CANCEL) {
+ html += GetCancelHTML(static_cast<int>(i), query);
+ cancel_ct++;
+ }
+ }
+
+ if (cancel_ct > 0) {
+ // Pending requests should match the total not canceled.
+ const std::string& cancel_val = GetIntString(total_ct - cancel_ct);
+ if (assert_total) {
+ html +=
+ "window.mrtAssertTotalCount(" LINESTR "," + cancel_val + ");\n";
+ }
+ if (assert_browser) {
+ html +=
+ "window.mrtAssertBrowserCount(" LINESTR "," + cancel_val + ");\n";
+ }
+ html +=
+ "window.mrtAssertContextCount(" LINESTR "," + cancel_val + ");\n";
+ }
+ } else {
+ // Run all of the queries asynchronously. Some may complete before
+ // others begin.
+ for (size_t i = 0; i < test_query_vector_.size(); ++i) {
+ const TestQuery& query = test_query_vector_[i];
+
+ const int index = static_cast<int>(i);
+
+ // Each request is delayed by 10ms from the previous request.
+ const std::string& delay_val = GetIntString(index);
+ const std::string& query_html = GetQueryHTML(index, query);
+
+ html += "window.setTimeout(function() {\n" + query_html;
+
+ if (query.type == CANCEL) {
+ // Cancel the query asynchronously with a 10ms delay.
+ const std::string& request_id_var =
+ GetIDString(kMultiQueryRequestId, index);
+ html +=
+ " window.setTimeout(function() {\n"
+ " window.mrtQueryCancel(" +
+ request_id_var +
+ ");\n"
+ " }, 1);\n";
+ }
+
+ html += "\n}, " + delay_val + ");\n";
+ }
+ }
+
+ html += "</script></body></html>";
+
+ return html;
+ }
+
+ void OnNotify(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const std::string& message) {
+ EXPECT_TRUE(finalized_);
+ EXPECT_UI_THREAD();
+
+ if (!running_) {
+ running_ = true;
+ }
+
+ EXPECT_TRUE(browser.get());
+ EXPECT_TRUE(frame.get());
+
+ std::string value;
+ int index = 0;
+ EXPECT_TRUE(SplitIDString(message, &value, &index));
+
+ TestQuery& query = test_query_vector_[index];
+
+ // Verify that browser and frame are the same.
+ EXPECT_EQ(query.browser_id, browser->GetIdentifier()) << index;
+ EXPECT_EQ(query.frame_id, frame->GetIdentifier()) << index;
+
+ // Verify a successful/expected result.
+ if (will_cancel_by_removing_handler_) {
+ // Auto queries receive an onFailure callback which will notify with error
+ // when the handler is removed.
+ EXPECT_STREQ(kMultiQueryError, value.c_str()) << index;
+ EXPECT_TRUE(IsAuto(query.type)) << index;
+ EXPECT_TRUE(query.got_query) << index;
+ if (query.type == PERSISTENT_AUTOCANCEL) {
+ EXPECT_TRUE(query.got_success) << index;
+ } else {
+ EXPECT_FALSE(query.got_success) << index;
+ }
+
+ query.got_error.yes();
+
+ // There's a race between OnQueryCanceled and OnNotification. Only call
+ // OnQueryCompleted a single time.
+ if (query.got_query_canceled) {
+ OnQueryCompleted(query.type);
+ }
+ } else {
+ EXPECT_STREQ(kMultiQuerySuccess, value.c_str()) << index;
+ EXPECT_TRUE(WillNotify(query.type)) << index;
+ EXPECT_TRUE(query.got_query) << index;
+ EXPECT_FALSE(query.got_query_canceled) << index;
+ EXPECT_FALSE(query.got_success) << index;
+
+ query.got_success.yes();
+
+ // PERSISTENT_AUTOCANCEL doesn't call OnReceiveCompleted from OnQuery.
+ if (query.type == PERSISTENT_AUTOCANCEL) {
+ OnReceiveCompleted(query.type);
+ }
+
+ // Call OnQueryCompleted for types that don't get OnQueryCanceled.
+ if (!WillCancel(query.type)) {
+ OnQueryCompleted(query.type);
+ }
+ }
+ }
+
+ bool OnQuery(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int64 query_id,
+ const CefString& request,
+ bool persistent,
+ CefRefPtr<Callback> callback) override {
+ EXPECT_TRUE(finalized_);
+ EXPECT_UI_THREAD();
+
+ if (!running_) {
+ running_ = true;
+ }
+
+ EXPECT_TRUE(browser.get());
+ EXPECT_TRUE(frame.get());
+ EXPECT_NE(0, query_id);
+
+ std::string value;
+ int index = 0;
+ EXPECT_TRUE(SplitIDString(request, &value, &index));
+
+ TestQuery& query = test_query_vector_[index];
+
+ if (IsPersistent(query.type)) {
+ EXPECT_TRUE(persistent);
+ } else {
+ EXPECT_FALSE(persistent);
+ }
+
+ // Verify expected request.
+ EXPECT_STREQ(kMultiQueryRequest, value.c_str()) << index;
+
+ // Verify that call order is correct.
+ EXPECT_FALSE(query.got_query) << index;
+ EXPECT_FALSE(query.got_query_canceled) << index;
+ EXPECT_FALSE(query.got_success) << index;
+ EXPECT_FALSE(query.got_error) << index;
+
+ query.got_query.yes();
+
+ query.browser_id = browser->GetIdentifier();
+ query.frame_id = frame->GetIdentifier();
+ query.is_main_frame = frame->IsMain();
+
+ if (query.type == SUCCESS) {
+ // Send the single success response.
+ callback->Success(GetIDString(kMultiQueryResponse, index));
+ } else if (IsPersistent(query.type)) {
+ // Send the required number of successful responses.
+ const std::string& response = GetIDString(kMultiQueryResponse, index);
+ for (int i = 0; i < kMultiQueryPersistentResponseCount; ++i) {
+ callback->Success(response);
+ }
+ }
+
+ if (WillFail(query.type)) {
+ // Send the single failure response.
+ callback->Failure(index, GetIDString(kMultiQueryErrorMessage, index));
+ }
+
+ if (WillCancel(query.type)) {
+ // Hold onto the callback until the query is canceled.
+ query.query_id = query_id;
+ query.callback = callback;
+ }
+
+ // PERSISTENT_AUTOCANCEL will call OnReceiveCompleted once the success
+ // notification is received.
+ if (query.type != PERSISTENT_AUTOCANCEL) {
+ OnReceiveCompleted(query.type);
+ }
+
+ return true;
+ }
+
+ void OnQueryCanceled(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int64 query_id) override {
+ EXPECT_TRUE(finalized_);
+ EXPECT_UI_THREAD();
+
+ if (!running_) {
+ running_ = true;
+ }
+
+ EXPECT_TRUE(browser.get());
+ EXPECT_TRUE(frame.get());
+ EXPECT_NE(0, query_id);
+
+ bool found = false;
+ for (size_t i = 0; i < test_query_vector_.size(); ++i) {
+ TestQuery& query = test_query_vector_[i];
+ if (query.query_id == query_id) {
+ // Verify that browser and frame are the same.
+ EXPECT_EQ(query.browser_id, browser->GetIdentifier()) << i;
+ if (query.is_main_frame) {
+ EXPECT_TRUE(frame->IsMain()) << i;
+ } else {
+ EXPECT_FALSE(frame->IsMain()) << i;
+ EXPECT_EQ(query.frame_id, frame->GetIdentifier()) << i;
+ }
+
+ // Verify a successful/expected result.
+ EXPECT_TRUE(WillCancel(query.type)) << i;
+ EXPECT_TRUE(query.callback.get()) << i;
+
+ // Release the callback.
+ query.callback = nullptr;
+
+ // Verify that call order is correct.
+ EXPECT_TRUE(query.got_query) << i;
+
+ if (query.type == CANCEL || query.type == AUTOCANCEL) {
+ // No JavaScript onSuccess callback executes.
+ EXPECT_FALSE(query.got_success) << i;
+ } else {
+ // JavaScript onSuccess does execute before cancellation.
+ EXPECT_TRUE(query.got_success) << i;
+ }
+
+ query.got_query_canceled.yes();
+
+ if (will_cancel_by_removing_handler_) {
+ // There's a race between OnQueryCanceled and OnNotification. Only
+ // call OnQueryCompleted a single time.
+ if (query.got_error) {
+ OnQueryCompleted(query.type);
+ }
+ } else {
+ EXPECT_FALSE(query.got_error) << i;
+
+ // Cancellation is always completion.
+ OnQueryCompleted(query.type);
+ }
+
+ found = true;
+ break;
+ }
+ }
+ EXPECT_TRUE(found);
+ }
+
+ // Asserts that all queries have completed.
+ void AssertAllComplete() const {
+ EXPECT_TRUE(finalized_);
+ EXPECT_FALSE(running_);
+ EXPECT_UI_THREAD();
+
+ for (size_t i = 0; i < test_query_vector_.size(); ++i) {
+ const TestQuery& query = test_query_vector_[i];
+ EXPECT_TRUE(query.got_query) << i;
+
+ if (WillCancel(query.type)) {
+ EXPECT_TRUE(query.got_query_canceled) << i;
+ } else {
+ EXPECT_FALSE(query.got_query_canceled) << i;
+ }
+
+ if (WillNotify(query.type)) {
+ EXPECT_TRUE(query.got_success) << i;
+ } else {
+ EXPECT_FALSE(query.got_success) << i;
+ }
+
+ if (IsAuto(query.type) && will_cancel_by_removing_handler_) {
+ EXPECT_TRUE(query.got_error);
+ } else {
+ EXPECT_FALSE(query.got_error);
+ }
+
+ EXPECT_FALSE(query.callback.get()) << i;
+ }
+ }
+
+ // Returns true if all manual queries have completed.
+ bool IsManualComplete() const {
+ EXPECT_TRUE(finalized_);
+ EXPECT_UI_THREAD();
+
+ return (manual_complete_count_ == manual_total_);
+ }
+
+ // Returns true if all queries have completed.
+ bool IsAllComplete() const {
+ EXPECT_TRUE(finalized_);
+ EXPECT_UI_THREAD();
+
+ return (manual_complete_count_ + auto_complete_count_ ==
+ static_cast<int>(test_query_vector_.size()));
+ }
+
+ bool HasAutoQueries() const {
+ return (manual_total_ != static_cast<int>(test_query_vector_.size()));
+ }
+
+ private:
+ struct TestQuery {
+ explicit TestQuery(TestType test_type)
+ : type(test_type),
+ browser_id(0),
+ frame_id(0),
+ is_main_frame(false),
+ query_id(0) {}
+
+ TestType type;
+
+ // Set in OnQuery and verified in OnNotify or OnQueryCanceled.
+ int browser_id;
+ int64 frame_id;
+ bool is_main_frame;
+
+ // Used when a query is canceled.
+ int64 query_id;
+ CefRefPtr<Callback> callback;
+
+ TrackCallback got_query;
+ TrackCallback got_query_canceled;
+ TrackCallback got_success;
+ TrackCallback got_error;
+ };
+
+ class NotifyTask : public CefTask {
+ public:
+ NotifyTask(base::WeakPtr<MultiQueryManager> weak_ptr, bool notify_all)
+ : weak_ptr_(weak_ptr), notify_all_(notify_all) {}
+
+ void Execute() override {
+ if (weak_ptr_) {
+ if (notify_all_) {
+ weak_ptr_->NotifyAllQueriesCompleted();
+ } else {
+ weak_ptr_->NotifyManualQueriesCompleted();
+ }
+ }
+ }
+
+ private:
+ base::WeakPtr<MultiQueryManager> weak_ptr_;
+ const bool notify_all_;
+
+ IMPLEMENT_REFCOUNTING(NotifyTask);
+ };
+
+ static bool IsAuto(TestType type) {
+ return (type == AUTOCANCEL || type == PERSISTENT_AUTOCANCEL);
+ }
+
+ static bool IsPersistent(TestType type) {
+ return (type == PERSISTENT_SUCCESS || type == PERSISTENT_FAILURE ||
+ type == PERSISTENT_AUTOCANCEL);
+ }
+
+ static bool WillFail(TestType type) {
+ return (type == FAILURE || type == PERSISTENT_FAILURE);
+ }
+
+ static bool WillCancel(TestType type) {
+ return (type == PERSISTENT_SUCCESS || type == CANCEL ||
+ type == AUTOCANCEL || type == PERSISTENT_AUTOCANCEL);
+ }
+
+ static bool WillNotify(TestType type) {
+ return (type == SUCCESS || type == PERSISTENT_SUCCESS || type == FAILURE ||
+ type == PERSISTENT_FAILURE || type == PERSISTENT_AUTOCANCEL);
+ }
+
+ void OnReceiveCompleted(TestType type) {
+ const int total_count = static_cast<int>(test_query_vector_.size());
+ if (++received_count_ == total_count && manual_total_ == 0) {
+ // There aren't any manual queries so notify here.
+ CefPostTask(TID_UI,
+ new NotifyTask(weak_ptr_factory_.GetWeakPtr(), false));
+ }
+ }
+
+ void OnQueryCompleted(TestType type) {
+ const int total_count = static_cast<int>(test_query_vector_.size());
+ EXPECT_LT(manual_complete_count_ + auto_complete_count_, total_count);
+ EXPECT_LE(manual_complete_count_, manual_total_);
+
+ const bool is_auto = IsAuto(type);
+ if (is_auto) {
+ auto_complete_count_++;
+ } else if (++manual_complete_count_ == manual_total_) {
+ CefPostTask(TID_UI,
+ new NotifyTask(weak_ptr_factory_.GetWeakPtr(), false));
+ }
+
+ if (auto_complete_count_ + manual_complete_count_ == total_count) {
+ running_ = false;
+ CefPostTask(TID_UI, new NotifyTask(weak_ptr_factory_.GetWeakPtr(), true));
+ }
+ }
+
+ void NotifyManualQueriesCompleted() {
+ if (observer_set_.empty()) {
+ return;
+ }
+
+ // Use a copy of the set in case an Observer is removed while we're
+ // iterating.
+ ObserverSet observer_set = observer_set_;
+
+ ObserverSet::const_iterator it = observer_set.begin();
+ for (; it != observer_set.end(); ++it) {
+ (*it)->OnManualQueriesCompleted(this);
+ }
+ }
+
+ void NotifyAllQueriesCompleted() {
+ if (observer_set_.empty()) {
+ return;
+ }
+
+ // Use a copy of the set in case an Observer is removed while we're
+ // iterating.
+ ObserverSet observer_set = observer_set_;
+
+ ObserverSet::const_iterator it = observer_set.begin();
+ for (; it != observer_set.end(); ++it) {
+ (*it)->OnAllQueriesCompleted(this);
+ }
+ }
+
+ std::string GetQueryHTML(const int index, const TestQuery& query) const {
+ const std::string& request_id_var =
+ GetIDString(kMultiQueryRequestId, index);
+ const std::string& repeat_ct_var = GetIDString(kMultiQueryRepeatCt, index);
+ const std::string& request_val =
+ GetIDString(std::string(kMultiQueryRequest) + ":", index);
+ const std::string& success_val =
+ GetIDString(std::string(kMultiQuerySuccess) + ":", index);
+ const std::string& error_val =
+ GetIDString(std::string(kMultiQueryError) + ":", index);
+
+ std::string html;
+
+ const bool persistent = IsPersistent(query.type);
+
+ if (persistent) {
+ html += "var " + repeat_ct_var + " = 0;\n";
+ }
+
+ html += "var " + request_id_var +
+ " = window.mrtQuery({\n"
+ " request: '" +
+ request_val +
+ "',\n"
+ " persistent: " +
+ (persistent ? "true" : "false") + ",\n";
+
+ if (query.type == SUCCESS) {
+ const std::string& response_val = GetIDString(kMultiQueryResponse, index);
+
+ html +=
+ " onSuccess: function(response) {\n"
+ " if (response == '" +
+ response_val +
+ "')\n"
+ " window.mrtNotify('" +
+ success_val +
+ "');\n"
+ " else\n"
+ " window.mrtNotify('" +
+ error_val +
+ "');\n"
+ " },\n"
+ " onFailure: function(error_code, error_message) {\n"
+ " window.mrtNotify('" +
+ error_val +
+ "');\n"
+ " }\n";
+ } else if (query.type == FAILURE) {
+ const std::string& error_code_val = GetIntString(index);
+ const std::string& error_message_val =
+ GetIDString(kMultiQueryErrorMessage, index);
+
+ html +=
+ " onSuccess: function(response) {\n"
+ " window.mrtNotify('" +
+ error_val +
+ "');\n"
+ " },\n"
+ " onFailure: function(error_code, error_message) {\n"
+ " if (error_code == " +
+ error_code_val + " && error_message == '" + error_message_val +
+ "')\n"
+ " window.mrtNotify('" +
+ success_val +
+ "');\n"
+ " else\n"
+ " window.mrtNotify('" +
+ error_val +
+ "');\n"
+ " }\n";
+ } else if (query.type == PERSISTENT_SUCCESS ||
+ query.type == PERSISTENT_AUTOCANCEL) {
+ const std::string& response_val = GetIDString(kMultiQueryResponse, index);
+ const std::string& repeat_ct =
+ GetIntString(kMultiQueryPersistentResponseCount);
+
+ html +=
+ " onSuccess: function(response) {\n"
+ " if (response == '" +
+ response_val +
+ "') {\n"
+ // Should get repeat_ct number of successful responses.
+ " if (++" +
+ repeat_ct_var + " == " + repeat_ct +
+ ") {\n"
+ " window.mrtNotify('" +
+ success_val + "');\n";
+
+ if (query.type == PERSISTENT_SUCCESS) {
+ // Manually cancel the request.
+ html += " window.mrtQueryCancel(" + request_id_var + ");\n";
+ }
+
+ html +=
+ " }\n"
+ " } else {\n"
+ " window.mrtNotify('" +
+ error_val +
+ "');\n"
+ " }\n"
+ " },\n"
+ " onFailure: function(error_code, error_message) {\n"
+ " window.mrtNotify('" +
+ error_val +
+ "');\n"
+ " }\n";
+ } else if (query.type == PERSISTENT_FAILURE) {
+ const std::string& error_code_val = GetIntString(index);
+ const std::string& error_message_val =
+ GetIDString(kMultiQueryErrorMessage, index);
+ const std::string& repeat_ct =
+ GetIntString(kMultiQueryPersistentResponseCount);
+
+ html +=
+ " onSuccess: function(response) {\n"
+ // Should get some successful responses before failure.
+ " if (++" +
+ repeat_ct_var + " > " + repeat_ct +
+ ") {\n"
+ " window.mrtNotify('" +
+ error_val +
+ "');\n"
+ " }\n"
+ " },\n"
+ " onFailure: function(error_code, error_message) {\n"
+ " if (error_code == " +
+ error_code_val + " && error_message == '" + error_message_val +
+ "'"
+ " && " +
+ repeat_ct_var + " == " + repeat_ct +
+ ")\n"
+ " window.mrtNotify('" +
+ success_val +
+ "');\n"
+ " else\n"
+ " window.mrtNotify('" +
+ error_val +
+ "');\n"
+ " }\n";
+ } else if (query.type == CANCEL || query.type == AUTOCANCEL) {
+ html +=
+ " onSuccess: function(response) {\n"
+ " window.mrtNotify('" +
+ error_val +
+ "');\n"
+ " },\n"
+ " onFailure: function(error_code, error_message) {\n"
+ " window.mrtNotify('" +
+ error_val +
+ "');\n"
+ " }\n";
+ }
+
+ html += "});\n";
+
+ return html;
+ }
+
+ std::string GetCancelHTML(const int index, const TestQuery& query) const {
+ const std::string& request_id_var =
+ GetIDString(kMultiQueryRequestId, index);
+ return "window.mrtQueryCancel(" + request_id_var + ");\n";
+ }
+
+ std::string GetIDString(const std::string& prefix, int index) const {
+ EXPECT_TRUE(!prefix.empty());
+ std::stringstream ss;
+ ss << prefix << GetIDFromIndex(index);
+ return ss.str();
+ }
+
+ bool SplitIDString(const std::string& str,
+ std::string* value,
+ int* index) const {
+ size_t pos = str.find(':');
+ if (pos != std::string::npos) {
+ *value = str.substr(0, pos);
+ *index = GetIndexFromID(atoi(str.substr(pos + 1).c_str()));
+ return (*index >= 0 &&
+ *index < static_cast<int>(test_query_vector_.size()));
+ }
+
+ return false;
+ }
+
+ std::string GetIntString(int val) const {
+ std::stringstream ss;
+ ss << val;
+ return ss.str();
+ }
+
+ int GetIDFromIndex(int index) const { return id_offset_ + index; }
+ int GetIndexFromID(int id) const { return id - id_offset_; }
+
+ const std::string label_;
+ const bool synchronous_;
+ const int id_offset_;
+
+ typedef std::vector<TestQuery> TestQueryVector;
+ TestQueryVector test_query_vector_;
+
+ typedef std::set<Observer*> ObserverSet;
+ ObserverSet observer_set_;
+
+ // Set to true after all queries have been added.
+ bool finalized_;
+ // Set to true while queries are pending.
+ bool running_;
+
+ // Total number of queries that will manually complete.
+ int manual_total_;
+
+ // Number of queries that have been received.
+ int received_count_;
+
+ // Number of queries that have completed successfully.
+ int manual_complete_count_;
+ int auto_complete_count_;
+
+ // If true any pending queries will receive an onFailure callback in addition
+ // to be canceled.
+ bool will_cancel_by_removing_handler_;
+
+ // Should always be the last member.
+ base::WeakPtrFactory<MultiQueryManager> weak_ptr_factory_;
+};
+
+void MakeTestQueries(MultiQueryManager* manager,
+ bool some,
+ int many_count = 200) {
+ if (some) {
+ // Test some queries of arbitrary types.
+ // Use a hard-coded list so the behavior is deterministic across test runs.
+ MultiQueryManager::TestType types[] = {
+ MultiQueryManager::PERSISTENT_AUTOCANCEL,
+ MultiQueryManager::SUCCESS,
+ MultiQueryManager::AUTOCANCEL,
+ MultiQueryManager::PERSISTENT_FAILURE,
+ MultiQueryManager::CANCEL,
+ MultiQueryManager::FAILURE,
+ MultiQueryManager::AUTOCANCEL,
+ MultiQueryManager::SUCCESS,
+ MultiQueryManager::PERSISTENT_SUCCESS,
+ MultiQueryManager::SUCCESS,
+ MultiQueryManager::PERSISTENT_AUTOCANCEL,
+ MultiQueryManager::CANCEL,
+ MultiQueryManager::PERSISTENT_SUCCESS,
+ MultiQueryManager::FAILURE,
+ };
+ for (size_t i = 0; i < sizeof(types) / sizeof(types[0]); ++i) {
+ manager->AddTestQuery(types[i]);
+ }
+ } else {
+ // Test every type of query.
+ for (int i = 0; i < many_count; ++i) {
+ MultiQueryManager::TestType type = MultiQueryManager::SUCCESS;
+ switch (i % 7) {
+ case 0:
+ type = MultiQueryManager::SUCCESS;
+ break;
+ case 1:
+ type = MultiQueryManager::FAILURE;
+ break;
+ case 2:
+ type = MultiQueryManager::PERSISTENT_SUCCESS;
+ break;
+ case 3:
+ type = MultiQueryManager::PERSISTENT_FAILURE;
+ break;
+ case 4:
+ type = MultiQueryManager::CANCEL;
+ break;
+ case 5:
+ type = MultiQueryManager::AUTOCANCEL;
+ break;
+ case 6:
+ type = MultiQueryManager::PERSISTENT_AUTOCANCEL;
+ break;
+ }
+ manager->AddTestQuery(type);
+ }
+ }
+ manager->Finalize();
+}
+
+// Test multiple queries in a single page load with a single frame.
+class MultiQuerySingleFrameTestHandler : public SingleLoadTestHandler,
+ public MultiQueryManager::Observer {
+ public:
+ enum CancelType {
+ CANCEL_BY_NAVIGATION,
+ CANCEL_BY_REMOVING_HANDLER,
+ CANCEL_BY_CLOSING_BROWSER,
+ };
+
+ MultiQuerySingleFrameTestHandler(
+ bool synchronous,
+ CancelType cancel_type = CANCEL_BY_NAVIGATION)
+ : manager_(std::string(), synchronous), cancel_type_(cancel_type) {
+ manager_.AddObserver(this);
+ }
+
+ std::string GetMainHTML() override { return manager_.GetHTML(true, true); }
+
+ void OnNotify(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const std::string& message) override {
+ AssertMainBrowser(browser);
+ AssertMainFrame(frame);
+
+ manager_.OnNotify(browser, frame, message);
+ }
+
+ bool OnQuery(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int64 query_id,
+ const CefString& request,
+ bool persistent,
+ CefRefPtr<Callback> callback) override {
+ AssertMainBrowser(browser);
+ AssertMainFrame(frame);
+
+ return manager_.OnQuery(browser, frame, query_id, request, persistent,
+ callback);
+ }
+
+ void OnQueryCanceled(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int64 query_id) override {
+ AssertMainBrowser(browser);
+ AssertMainFrame(frame);
+
+ manager_.OnQueryCanceled(browser, frame, query_id);
+ }
+
+ void OnManualQueriesCompleted(MultiQueryManager* manager) override {
+ EXPECT_EQ(manager, &manager_);
+ if (manager_.HasAutoQueries()) {
+ if (cancel_type_ == CANCEL_BY_NAVIGATION) {
+ // Navigate somewhere else to terminate the auto queries.
+ GetBrowser()->GetMainFrame()->LoadURL(std::string(kTestDomain1) +
+ "cancel.html");
+ } else if (cancel_type_ == CANCEL_BY_REMOVING_HANDLER) {
+ // Change the expected behavior in the manager.
+ manager_.WillCancelByRemovingHandler();
+ GetRouter()->RemoveHandler(this);
+ // All queries should be immediately canceled.
+ AssertQueryCount(nullptr, nullptr, 0);
+ } else if (cancel_type_ == CANCEL_BY_CLOSING_BROWSER) {
+ // Change the expected behavior in the handler.
+ SetSignalCompletionWhenAllBrowsersClose(false);
+ CloseBrowser(GetBrowser(), false);
+ }
+ }
+ }
+
+ void OnAllQueriesCompleted(MultiQueryManager* manager) override {
+ EXPECT_EQ(manager, &manager_);
+
+ // All queries should be canceled.
+ AssertQueryCount(nullptr, nullptr, 0);
+
+ DestroyTest();
+
+ if (!SignalCompletionWhenAllBrowsersClose()) {
+ // Complete asynchronously so the call stack has a chance to unwind.
+ CefPostTask(TID_UI,
+ base::BindOnce(
+ &MultiQuerySingleFrameTestHandler::TestComplete, this));
+ }
+ }
+
+ void DestroyTest() override {
+ manager_.AssertAllComplete();
+ TestHandler::DestroyTest();
+ }
+
+ MultiQueryManager* GetManager() { return &manager_; }
+
+ private:
+ MultiQueryManager manager_;
+ const CancelType cancel_type_;
+};
+
+} // namespace
+
+#define MULTI_QUERY_SINGLE_FRAME_TYPE_TEST(name, type, synchronous) \
+ TEST(MessageRouterTest, name) { \
+ CefRefPtr<MultiQuerySingleFrameTestHandler> handler = \
+ new MultiQuerySingleFrameTestHandler(synchronous); \
+ MultiQueryManager* manager = handler->GetManager(); \
+ manager->AddTestQuery(MultiQueryManager::type); \
+ manager->Finalize(); \
+ handler->ExecuteTest(); \
+ ReleaseAndWaitForDestructor(handler); \
+ }
+
+// Test the query types individually.
+MULTI_QUERY_SINGLE_FRAME_TYPE_TEST(MultiQuerySingleFrameSyncSuccess,
+ SUCCESS,
+ true)
+MULTI_QUERY_SINGLE_FRAME_TYPE_TEST(MultiQuerySingleFrameAsyncSuccess,
+ SUCCESS,
+ false)
+MULTI_QUERY_SINGLE_FRAME_TYPE_TEST(MultiQuerySingleFrameSyncFailure,
+ FAILURE,
+ true)
+MULTI_QUERY_SINGLE_FRAME_TYPE_TEST(MultiQuerySingleFrameAsyncFailure,
+ FAILURE,
+ false)
+MULTI_QUERY_SINGLE_FRAME_TYPE_TEST(MultiQuerySingleFrameSyncPersistentSuccess,
+ PERSISTENT_SUCCESS,
+ true)
+MULTI_QUERY_SINGLE_FRAME_TYPE_TEST(MultiQuerySingleFrameAsyncPersistentSuccess,
+ PERSISTENT_SUCCESS,
+ false)
+MULTI_QUERY_SINGLE_FRAME_TYPE_TEST(MultiQuerySingleFrameSyncPersistentFailure,
+ PERSISTENT_FAILURE,
+ true)
+MULTI_QUERY_SINGLE_FRAME_TYPE_TEST(MultiQuerySingleFrameAsyncPersistentFailure,
+ PERSISTENT_FAILURE,
+ false)
+MULTI_QUERY_SINGLE_FRAME_TYPE_TEST(MultiQuerySingleFrameCancel, CANCEL, true)
+MULTI_QUERY_SINGLE_FRAME_TYPE_TEST(MultiQuerySingleFrameAutoCancel,
+ AUTOCANCEL,
+ true)
+MULTI_QUERY_SINGLE_FRAME_TYPE_TEST(MultiQuerySingleFramePersistentAutoCancel,
+ PERSISTENT_AUTOCANCEL,
+ true)
+
+// Test that one frame can run some queries successfully in a synchronous
+// manner.
+TEST(MessageRouterTest, MultiQuerySingleFrameSyncSome) {
+ CefRefPtr<MultiQuerySingleFrameTestHandler> handler =
+ new MultiQuerySingleFrameTestHandler(true);
+ MakeTestQueries(handler->GetManager(), true);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Test that one frame can run some queries successfully in an asynchronous
+// manner.
+TEST(MessageRouterTest, MultiQuerySingleFrameAsyncSome) {
+ CefRefPtr<MultiQuerySingleFrameTestHandler> handler =
+ new MultiQuerySingleFrameTestHandler(false);
+ MakeTestQueries(handler->GetManager(), true);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Test that one frame can run many queries successfully in a synchronous
+// manner.
+TEST(MessageRouterTest, MultiQuerySingleFrameSyncMany) {
+ CefRefPtr<MultiQuerySingleFrameTestHandler> handler =
+ new MultiQuerySingleFrameTestHandler(true);
+ MakeTestQueries(handler->GetManager(), false);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Test that one frame can run many queries successfully in an asynchronous
+// manner.
+TEST(MessageRouterTest, MultiQuerySingleFrameAsyncMany) {
+ CefRefPtr<MultiQuerySingleFrameTestHandler> handler =
+ new MultiQuerySingleFrameTestHandler(false);
+ MakeTestQueries(handler->GetManager(), false);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Test that pending queries can be canceled by removing the handler.
+TEST(MessageRouterTest, MultiQuerySingleFrameCancelByRemovingHandler) {
+ CefRefPtr<MultiQuerySingleFrameTestHandler> handler =
+ new MultiQuerySingleFrameTestHandler(
+ false, MultiQuerySingleFrameTestHandler::CANCEL_BY_REMOVING_HANDLER);
+ MakeTestQueries(handler->GetManager(), false);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Test that pending queries can be canceled by closing the browser.
+TEST(MessageRouterTest, MultiQuerySingleFrameCancelByClosingBrowser) {
+ CefRefPtr<MultiQuerySingleFrameTestHandler> handler =
+ new MultiQuerySingleFrameTestHandler(
+ false, MultiQuerySingleFrameTestHandler::CANCEL_BY_CLOSING_BROWSER);
+ MakeTestQueries(handler->GetManager(), false);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+namespace {
+
+// Test multiple handlers.
+class MultiQueryMultiHandlerTestHandler : public SingleLoadTestHandler,
+ public MultiQueryManager::Observer {
+ public:
+ class Handler : public CefMessageRouterBrowserSide::Handler {
+ public:
+ Handler(MultiQueryMultiHandlerTestHandler* test_handler, int index)
+ : test_handler_(test_handler), index_(index), query_id_(0) {}
+
+ bool OnQuery(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int64 query_id,
+ const CefString& request,
+ bool persistent,
+ CefRefPtr<Callback> callback) override {
+ // Each handler only handles a single request.
+ std::stringstream ss;
+ ss << kMultiQueryRequest << ":" << index_;
+ const std::string& handled_request = ss.str();
+ if (request != handled_request) {
+ return false;
+ }
+
+ // Verify that handlers are called in the correct order.
+ if (index_ == 0) {
+ EXPECT_FALSE(test_handler_->got_query0_);
+ EXPECT_FALSE(test_handler_->got_query1_);
+ EXPECT_FALSE(test_handler_->got_query2_);
+
+ test_handler_->got_query0_.yes();
+ } else if (index_ == 1) {
+ EXPECT_TRUE(test_handler_->got_query0_);
+ EXPECT_FALSE(test_handler_->got_query1_);
+ EXPECT_FALSE(test_handler_->got_query2_);
+
+ test_handler_->got_query1_.yes();
+ } else if (index_ == 2) {
+ EXPECT_TRUE(test_handler_->got_query0_);
+ EXPECT_TRUE(test_handler_->got_query1_);
+ EXPECT_FALSE(test_handler_->got_query2_);
+
+ test_handler_->got_query2_.yes();
+ }
+
+ query_id_ = query_id;
+ return test_handler_->OnQuery(browser, frame, query_id, request,
+ persistent, callback);
+ }
+
+ void OnQueryCanceled(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int64 query_id) override {
+ // Verify that the correct handler is called for cancellation.
+ EXPECT_EQ(query_id_, query_id);
+
+ if (index_ == 0) {
+ EXPECT_FALSE(test_handler_->got_query_canceled0_);
+ test_handler_->got_query_canceled0_.yes();
+ } else if (index_ == 1) {
+ EXPECT_FALSE(test_handler_->got_query_canceled1_);
+ test_handler_->got_query_canceled1_.yes();
+ } else if (index_ == 2) {
+ EXPECT_FALSE(test_handler_->got_query_canceled2_);
+ test_handler_->got_query_canceled2_.yes();
+ }
+
+ test_handler_->OnQueryCanceled(browser, frame, query_id);
+ }
+
+ private:
+ MultiQueryMultiHandlerTestHandler* test_handler_;
+ const int index_;
+ int64 query_id_;
+ };
+
+ MultiQueryMultiHandlerTestHandler(bool synchronous,
+ bool cancel_by_removing_handler)
+ : manager_(std::string(), synchronous, 0),
+ handler0_(this, 0),
+ handler1_(this, 1),
+ handler2_(this, 2),
+ cancel_by_removing_handler_(cancel_by_removing_handler) {
+ manager_.AddObserver(this);
+
+ // Each handler will handle one of the queries.
+ manager_.AddTestQuery(MultiQueryManager::PERSISTENT_AUTOCANCEL);
+ manager_.AddTestQuery(MultiQueryManager::PERSISTENT_AUTOCANCEL);
+ manager_.AddTestQuery(MultiQueryManager::PERSISTENT_AUTOCANCEL);
+ manager_.Finalize();
+ }
+
+ std::string GetMainHTML() override { return manager_.GetHTML(true, true); }
+
+ void OnNotify(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const std::string& message) override {
+ AssertMainBrowser(browser);
+ AssertMainFrame(frame);
+
+ manager_.OnNotify(browser, frame, message);
+ }
+
+ bool OnQuery(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int64 query_id,
+ const CefString& request,
+ bool persistent,
+ CefRefPtr<Callback> callback) override {
+ AssertMainBrowser(browser);
+ AssertMainFrame(frame);
+
+ return manager_.OnQuery(browser, frame, query_id, request, persistent,
+ callback);
+ }
+
+ void OnQueryCanceled(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int64 query_id) override {
+ AssertMainBrowser(browser);
+ AssertMainFrame(frame);
+
+ manager_.OnQueryCanceled(browser, frame, query_id);
+ }
+
+ void OnManualQueriesCompleted(MultiQueryManager* manager) override {
+ EXPECT_EQ(manager, &manager_);
+
+ EXPECT_TRUE(got_query0_);
+ EXPECT_TRUE(got_query1_);
+ EXPECT_TRUE(got_query2_);
+ EXPECT_FALSE(got_query_canceled0_);
+ EXPECT_FALSE(got_query_canceled1_);
+ EXPECT_FALSE(got_query_canceled2_);
+
+ EXPECT_TRUE(manager_.HasAutoQueries());
+
+ CefRefPtr<CefMessageRouterBrowserSide> router = GetRouter();
+
+ // Remove one handler to cancel a query.
+
+ if (cancel_by_removing_handler_) {
+ manager_.WillCancelByRemovingHandler();
+
+ // Each query should be canceled as the handler is removed.
+ EXPECT_TRUE(router->RemoveHandler(&handler1_));
+ EXPECT_FALSE(got_query_canceled0_);
+ EXPECT_TRUE(got_query_canceled1_);
+ EXPECT_FALSE(got_query_canceled2_);
+
+ EXPECT_TRUE(router->RemoveHandler(&handler2_));
+ EXPECT_FALSE(got_query_canceled0_);
+ EXPECT_TRUE(got_query_canceled2_);
+
+ EXPECT_TRUE(router->RemoveHandler(&handler0_));
+ EXPECT_TRUE(got_query_canceled0_);
+ } else {
+ GetBrowser()->GetMainFrame()->LoadURL(std::string(kTestDomain1) +
+ "cancel.html");
+ }
+ }
+
+ void OnAllQueriesCompleted(MultiQueryManager* manager) override {
+ EXPECT_EQ(manager, &manager_);
+
+ // All queries should be canceled.
+ AssertQueryCount(nullptr, nullptr, 0);
+
+ DestroyTest();
+ }
+
+ void DestroyTest() override {
+ EXPECT_TRUE(got_query0_);
+ EXPECT_TRUE(got_query1_);
+ EXPECT_TRUE(got_query2_);
+ EXPECT_TRUE(got_query_canceled0_);
+ EXPECT_TRUE(got_query_canceled1_);
+ EXPECT_TRUE(got_query_canceled2_);
+
+ manager_.AssertAllComplete();
+ TestHandler::DestroyTest();
+ }
+
+ protected:
+ void AddHandlers(
+ CefRefPtr<CefMessageRouterBrowserSide> message_router) override {
+ // OnQuery call order will verify that the first/last ordering works as
+ // expected.
+ EXPECT_TRUE(message_router->AddHandler(&handler1_, true));
+ EXPECT_TRUE(message_router->AddHandler(&handler0_, true));
+ EXPECT_TRUE(message_router->AddHandler(&handler2_, false));
+
+ // Can't add the same handler multiple times.
+ EXPECT_FALSE(message_router->AddHandler(&handler1_, true));
+ }
+
+ private:
+ MultiQueryManager manager_;
+ Handler handler0_;
+ Handler handler1_;
+ Handler handler2_;
+
+ const bool cancel_by_removing_handler_;
+
+ TrackCallback got_query0_;
+ TrackCallback got_query1_;
+ TrackCallback got_query2_;
+
+ TrackCallback got_query_canceled0_;
+ TrackCallback got_query_canceled1_;
+ TrackCallback got_query_canceled2_;
+};
+
+} // namespace
+
+// Test that multiple handlers behave correctly.
+TEST(MessageRouterTest, MultiQueryMultiHandler) {
+ CefRefPtr<MultiQueryMultiHandlerTestHandler> handler =
+ new MultiQueryMultiHandlerTestHandler(false, false);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Test that multiple handlers behave correctly. Cancel by removing the
+// handlers.
+TEST(MessageRouterTest, MultiQueryMultiHandlerCancelByRemovingHandler) {
+ CefRefPtr<MultiQueryMultiHandlerTestHandler> handler =
+ new MultiQueryMultiHandlerTestHandler(false, true);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+namespace {
+
+// Map of managers on a per-URL basis.
+class MultiQueryManagerMap : public CefMessageRouterBrowserSide::Handler,
+ public MultiQueryManager::Observer {
+ public:
+ class Observer {
+ public:
+ // Called when all manual queries are complete.
+ virtual void OnMapManualQueriesCompleted(MultiQueryManagerMap* map) {}
+
+ // Called when all queries are complete.
+ virtual void OnMapAllQueriesCompleted(MultiQueryManagerMap* map) {}
+
+ protected:
+ virtual ~Observer() {}
+ };
+
+ MultiQueryManagerMap()
+ : finalized_(false),
+ running_(false),
+ manual_complete_count_(0),
+ total_complete_count_(0) {}
+
+ virtual ~MultiQueryManagerMap() { RemoveAllManagers(); }
+
+ void AddObserver(Observer* observer) {
+ EXPECT_FALSE(running_);
+ observer_set_.insert(observer);
+ }
+
+ void RemoveObserver(Observer* observer) {
+ EXPECT_FALSE(running_);
+ EXPECT_TRUE(observer_set_.erase(observer));
+ }
+
+ MultiQueryManager* CreateManager(const std::string& url, bool synchronous) {
+ EXPECT_FALSE(finalized_);
+
+ MultiQueryManager* manager = new MultiQueryManager(
+ url, synchronous, static_cast<int>(manager_map_.size()) * 1000);
+ manager->AddObserver(this);
+ all_managers_.push_back(manager);
+ pending_managers_.push_back(manager);
+
+ return manager;
+ }
+
+ void Finalize() {
+ EXPECT_FALSE(finalized_);
+ finalized_ = true;
+ }
+
+ std::string GetMainHTML() const {
+ EXPECT_TRUE(finalized_);
+ EXPECT_FALSE(running_);
+
+ std::string html = "<html><body>\n";
+
+ for (size_t i = 0; i < all_managers_.size(); ++i) {
+ const std::string& url = all_managers_[i]->label();
+ const std::string& name = GetNameForURL(url);
+ html += "<iframe id=\"" + name + "\" src=\"" + url + "\"></iframe>\n";
+ }
+
+ html += "</body></html>";
+ return html;
+ }
+
+ void OnNotify(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const std::string& message) {
+ EXPECT_TRUE(finalized_);
+ if (!running_) {
+ running_ = true;
+ }
+
+ MultiQueryManager* manager = GetManager(browser, frame);
+ manager->OnNotify(browser, frame, message);
+ }
+
+ bool OnQuery(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int64 query_id,
+ const CefString& request,
+ bool persistent,
+ CefRefPtr<Callback> callback) override {
+ EXPECT_TRUE(finalized_);
+ if (!running_) {
+ running_ = true;
+ }
+
+ MultiQueryManager* manager = GetManager(browser, frame);
+ return manager->OnQuery(browser, frame, query_id, request, persistent,
+ callback);
+ }
+
+ void OnQueryCanceled(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int64 query_id) override {
+ EXPECT_TRUE(finalized_);
+ if (!running_) {
+ running_ = true;
+ }
+
+ MultiQueryManager* manager = GetManager(browser, frame);
+ manager->OnQueryCanceled(browser, frame, query_id);
+ }
+
+ void OnManualQueriesCompleted(MultiQueryManager* manager) override {
+ const int size = static_cast<int>(all_managers_.size());
+ EXPECT_LT(manual_complete_count_, size);
+ if (++manual_complete_count_ == size) {
+ running_ = false;
+
+ // Notify observers.
+ if (!observer_set_.empty()) {
+ // Use a copy of the set in case an Observer is removed while we're
+ // iterating.
+ ObserverSet observer_set = observer_set_;
+
+ ObserverSet::const_iterator it = observer_set.begin();
+ for (; it != observer_set.end(); ++it) {
+ (*it)->OnMapManualQueriesCompleted(this);
+ }
+ }
+ }
+ }
+
+ void OnAllQueriesCompleted(MultiQueryManager* manager) override {
+ const int size = static_cast<int>(all_managers_.size());
+ EXPECT_LT(total_complete_count_, size);
+ if (++total_complete_count_ == size) {
+ running_ = false;
+
+ // Notify observers.
+ if (!observer_set_.empty()) {
+ // Use a copy of the set in case an Observer is removed while we're
+ // iterating.
+ ObserverSet observer_set = observer_set_;
+
+ ObserverSet::const_iterator it = observer_set.begin();
+ for (; it != observer_set.end(); ++it) {
+ (*it)->OnMapAllQueriesCompleted(this);
+ }
+ }
+ }
+ }
+
+ bool AllComplete() const {
+ EXPECT_TRUE(finalized_);
+
+ for (size_t i = 0; i < all_managers_.size(); ++i) {
+ if (!all_managers_[i]->IsAllComplete()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ void AssertAllComplete() const {
+ EXPECT_TRUE(finalized_);
+ EXPECT_TRUE(pending_managers_.empty());
+ EXPECT_FALSE(running_);
+
+ for (size_t i = 0; i < all_managers_.size(); ++i) {
+ all_managers_[i]->AssertAllComplete();
+ }
+ }
+
+ bool HasAutoQueries() const {
+ for (size_t i = 0; i < all_managers_.size(); ++i) {
+ if (all_managers_[i]->HasAutoQueries()) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ void OnLoadStart(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame) {
+ if (pending_managers_.empty()) {
+ return;
+ }
+
+ const std::string& expected_url = frame->GetURL();
+ MultiQueryManager* next_manager = nullptr;
+
+ // Find the pending manager that matches the expected URL.
+ ManagerList::iterator it = pending_managers_.begin();
+ for (; it != pending_managers_.end(); ++it) {
+ if ((*it)->label() == expected_url) {
+ next_manager = *it;
+ pending_managers_.erase(it);
+ break;
+ }
+ }
+
+ EXPECT_TRUE(next_manager);
+
+ const int browser_id = browser->GetIdentifier();
+ // Always use the same ID for the main frame.
+ const int64 frame_id = frame->IsMain() ? -1 : frame->GetIdentifier();
+
+ const std::pair<int, int64>& id = std::make_pair(browser_id, frame_id);
+
+ // Remove the currently active manager, if any.
+ ManagerMap::iterator it2 = manager_map_.find(id);
+ if (it2 != manager_map_.end()) {
+ manager_map_.erase(it2);
+ }
+
+ // Add the next manager to the active map.
+ manager_map_.insert(std::make_pair(id, next_manager));
+ }
+
+ MultiQueryManager* GetManager(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) const {
+ const int browser_id = browser->GetIdentifier();
+ // Always use the same ID for the main frame.
+ const int64 frame_id = frame->IsMain() ? -1 : frame->GetIdentifier();
+
+ // Find the manager in the active map.
+ ManagerMap::const_iterator it =
+ manager_map_.find(std::make_pair(browser_id, frame_id));
+ EXPECT_NE(it, manager_map_.end())
+ << "browser_id = " << browser_id << ", frame_id = " << frame_id;
+ return it->second;
+ }
+
+ void RemoveAllManagers() {
+ EXPECT_TRUE(pending_managers_.empty());
+ if (all_managers_.empty()) {
+ return;
+ }
+
+ for (size_t i = 0; i < all_managers_.size(); ++i) {
+ delete all_managers_[i];
+ }
+ all_managers_.clear();
+ manager_map_.clear();
+ }
+
+ static std::string GetNameForURL(const std::string& url) {
+ // Extract the file name without extension.
+ int pos1 = static_cast<int>(url.rfind("/"));
+ int pos2 = static_cast<int>(url.rfind("."));
+ EXPECT_TRUE(pos1 >= 0 && pos2 >= 0 && pos1 < pos2);
+ return url.substr(pos1 + 1, pos2 - pos1 - 1);
+ }
+
+ private:
+ typedef std::vector<MultiQueryManager*> ManagerList;
+ // Map of (browser ID, frame ID) to manager.
+ typedef std::map<std::pair<int, int64>, MultiQueryManager*> ManagerMap;
+
+ // All managers that have been created.
+ ManagerList all_managers_;
+ // Managers that have not yet associated with a frame.
+ ManagerList pending_managers_;
+ // Managers that are currently active.
+ ManagerMap manager_map_;
+
+ typedef std::set<Observer*> ObserverSet;
+ ObserverSet observer_set_;
+
+ // Set to true after all query managers have been added.
+ bool finalized_;
+ // Set to true while queries are pending.
+ bool running_;
+
+ // Number of managers that have completed.
+ int manual_complete_count_;
+ int total_complete_count_;
+};
+
+// Test multiple queries in a single page load with multiple frames.
+class MultiQueryMultiFrameTestHandler : public SingleLoadTestHandler,
+ public MultiQueryManagerMap::Observer {
+ public:
+ MultiQueryMultiFrameTestHandler(bool synchronous, bool cancel_with_subnav)
+ : synchronous_(synchronous), cancel_with_subnav_(cancel_with_subnav) {
+ manager_map_.AddObserver(this);
+ }
+
+ void AddOtherResources() override {
+ AddSubFrameResource("sub1");
+ AddSubFrameResource("sub2");
+ AddSubFrameResource("sub3");
+ manager_map_.Finalize();
+
+ if (manager_map_.HasAutoQueries()) {
+ cancel_url_ = std::string(kTestDomain1) + "cancel.html";
+ AddResource(cancel_url_, "<html><body>cancel</body></html>", "text/html");
+ }
+ }
+
+ std::string GetMainHTML() override { return manager_map_.GetMainHTML(); }
+
+ void OnLoadStart(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ TransitionType transition_type) override {
+ AssertMainBrowser(browser);
+ if (!frame->IsMain()) {
+ manager_map_.OnLoadStart(browser, frame);
+ }
+ }
+
+ void OnNotify(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const std::string& message) override {
+ AssertMainBrowser(browser);
+ EXPECT_FALSE(frame->IsMain());
+
+ manager_map_.OnNotify(browser, frame, message);
+ }
+
+ bool OnQuery(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int64 query_id,
+ const CefString& request,
+ bool persistent,
+ CefRefPtr<Callback> callback) override {
+ AssertMainBrowser(browser);
+ EXPECT_FALSE(frame->IsMain());
+
+ return manager_map_.OnQuery(browser, frame, query_id, request, persistent,
+ callback);
+ }
+
+ void OnQueryCanceled(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int64 query_id) override {
+ AssertMainBrowser(browser);
+ EXPECT_FALSE(frame->IsMain());
+
+ manager_map_.OnQueryCanceled(browser, frame, query_id);
+ }
+
+ void OnMapManualQueriesCompleted(MultiQueryManagerMap* map) override {
+ EXPECT_EQ(map, &manager_map_);
+ if (manager_map_.HasAutoQueries()) {
+ CefRefPtr<CefFrame> frame = GetBrowser()->GetMainFrame();
+
+ // Navigate somewhere else to terminate the auto queries.
+ if (cancel_with_subnav_) {
+ // Navigate each subframe individually.
+ const std::string js = "document.getElementById('sub1').src = '" +
+ cancel_url_ +
+ "';"
+ "document.getElementById('sub2').src = '" +
+ cancel_url_ +
+ "';"
+ "document.getElementById('sub3').src = '" +
+ cancel_url_ + "';";
+
+ frame->ExecuteJavaScript(js, frame->GetURL(), 0);
+ } else {
+ // Navigate the main frame.
+ frame->LoadURL(cancel_url_);
+ }
+ }
+ }
+
+ void OnMapAllQueriesCompleted(MultiQueryManagerMap* map) override {
+ EXPECT_EQ(map, &manager_map_);
+ DestroyTest();
+ }
+
+ void DestroyTest() override {
+ manager_map_.AssertAllComplete();
+ TestHandler::DestroyTest();
+ }
+
+ private:
+ void AddSubFrameResource(const std::string& name) {
+ const std::string& url = std::string(kTestDomain1) + name + ".html";
+
+ MultiQueryManager* manager = manager_map_.CreateManager(url, synchronous_);
+ MakeTestQueries(manager, false, 100);
+
+ const std::string& html = manager->GetHTML(false, false);
+ AddResource(url, html, "text/html");
+ }
+
+ const bool synchronous_;
+ const bool cancel_with_subnav_;
+
+ MultiQueryManagerMap manager_map_;
+
+ std::string cancel_url_;
+};
+
+} // namespace
+
+// Test that multiple frames can run many queries successfully in a synchronous
+// manner.
+TEST(MessageRouterTest, MultiQueryMultiFrameSync) {
+ CefRefPtr<MultiQueryMultiFrameTestHandler> handler =
+ new MultiQueryMultiFrameTestHandler(true, false);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Test that multiple frames can run many queries successfully in an
+// asynchronous manner.
+TEST(MessageRouterTest, MultiQueryMultiFrameAsync) {
+ CefRefPtr<MultiQueryMultiFrameTestHandler> handler =
+ new MultiQueryMultiFrameTestHandler(false, false);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Test that multiple frames can run many queries successfully in a synchronous
+// manner. Cancel auto queries with sub-frame navigation.
+TEST(MessageRouterTest, MultiQueryMultiFrameSyncSubnavCancel) {
+ CefRefPtr<MultiQueryMultiFrameTestHandler> handler =
+ new MultiQueryMultiFrameTestHandler(true, true);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Test that multiple frames can run many queries successfully in an
+// asynchronous manner. Cancel auto queries with sub-frame navigation.
+TEST(MessageRouterTest, MultiQueryMultiFrameAsyncSubnavCancel) {
+ CefRefPtr<MultiQueryMultiFrameTestHandler> handler =
+ new MultiQueryMultiFrameTestHandler(false, true);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+namespace {
+
+// Implementation of MRTestHandler that loads multiple pages and/or browsers and
+// executes multiple queries.
+class MultiQueryMultiLoadTestHandler
+ : public MRTestHandler,
+ public CefMessageRouterBrowserSide::Handler,
+ public MultiQueryManagerMap::Observer,
+ public MultiQueryManager::Observer {
+ public:
+ MultiQueryMultiLoadTestHandler(bool some, bool synchronous)
+ : some_(some), synchronous_(synchronous) {
+ manager_map_.AddObserver(this);
+ }
+
+ void OnLoadStart(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ TransitionType transition_type) override {
+ manager_map_.OnLoadStart(browser, frame);
+ }
+
+ void OnNotify(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const std::string& message) override {
+ manager_map_.OnNotify(browser, frame, message);
+ }
+
+ bool OnQuery(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int64 query_id,
+ const CefString& request,
+ bool persistent,
+ CefRefPtr<Callback> callback) override {
+ return manager_map_.OnQuery(browser, frame, query_id, request, persistent,
+ callback);
+ }
+
+ void OnQueryCanceled(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int64 query_id) override {
+ manager_map_.OnQueryCanceled(browser, frame, query_id);
+ }
+
+ void OnMapManualQueriesCompleted(MultiQueryManagerMap* map) override {
+ EXPECT_EQ(map, &manager_map_);
+ if (manager_map_.HasAutoQueries()) {
+ // Navigate all browsers somewhere else to terminate the auto queries.
+ BrowserMap browser_map;
+ GetAllBrowsers(&browser_map);
+
+ BrowserMap::const_iterator it = browser_map.begin();
+ for (; it != browser_map.end(); ++it) {
+ it->second->GetMainFrame()->LoadURL(cancel_url_);
+ }
+ }
+ }
+
+ void OnMapAllQueriesCompleted(MultiQueryManagerMap* map) override {
+ EXPECT_EQ(map, &manager_map_);
+ DestroyTest();
+ }
+
+ void DestroyTest() override {
+ manager_map_.AssertAllComplete();
+ TestHandler::DestroyTest();
+ }
+
+ protected:
+ void AddHandlers(
+ CefRefPtr<CefMessageRouterBrowserSide> message_router) override {
+ message_router->AddHandler(this, false);
+ }
+
+ void AddManagedResource(const std::string& url,
+ bool assert_total,
+ bool assert_browser) {
+ MultiQueryManager* manager = manager_map_.CreateManager(url, synchronous_);
+ manager->AddObserver(this);
+ MakeTestQueries(manager, some_, 75);
+
+ const std::string& html = manager->GetHTML(assert_total, assert_browser);
+ AddResource(url, html, "text/html");
+ }
+
+ void Finalize() {
+ manager_map_.Finalize();
+
+ if (manager_map_.HasAutoQueries()) {
+ cancel_url_ = std::string(kTestDomain1) + "cancel.html";
+ AddResource(cancel_url_, "<html><body>cancel</body></html>", "text/html");
+ }
+ }
+
+ MultiQueryManagerMap manager_map_;
+
+ private:
+ const bool some_;
+ const bool synchronous_;
+
+ std::string cancel_url_;
+};
+
+// Test multiple browsers that send queries at the same time.
+class MultiQueryMultiBrowserTestHandler
+ : public MultiQueryMultiLoadTestHandler {
+ public:
+ MultiQueryMultiBrowserTestHandler(bool synchronous, bool same_origin)
+ : MultiQueryMultiLoadTestHandler(false, synchronous),
+ same_origin_(same_origin) {}
+
+ protected:
+ void RunMRTest() override {
+ const std::string& url1 = std::string(kTestDomain1) + "browser1.html";
+ const std::string& url2 =
+ std::string(same_origin_ ? kTestDomain1 : kTestDomain2) +
+ "browser2.html";
+ const std::string& url3 =
+ std::string(same_origin_ ? kTestDomain1 : kTestDomain3) +
+ "browser3.html";
+
+ AddManagedResource(url1, false, true);
+ AddManagedResource(url2, false, true);
+ AddManagedResource(url3, false, true);
+ Finalize();
+
+ // Create 2 browsers simultaniously.
+ CreateBrowser(url1, nullptr);
+ CreateBrowser(url2, nullptr);
+ CreateBrowser(url3, nullptr);
+ }
+
+ private:
+ bool same_origin_;
+};
+
+} // namespace
+
+// Test that multiple browsers can query simultaniously from the same origin.
+TEST(MessageRouterTest, MultiQueryMultiBrowserSameOriginSync) {
+ CefRefPtr<MultiQueryMultiBrowserTestHandler> handler =
+ new MultiQueryMultiBrowserTestHandler(true, true);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Test that multiple browsers can query simultaniously from the same origin.
+TEST(MessageRouterTest, MultiQueryMultiBrowserSameOriginAsync) {
+ CefRefPtr<MultiQueryMultiBrowserTestHandler> handler =
+ new MultiQueryMultiBrowserTestHandler(false, true);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Test that multiple browsers can query simultaniously from different origins.
+TEST(MessageRouterTest, MultiQueryMultiBrowserDifferentOriginSync) {
+ CefRefPtr<MultiQueryMultiBrowserTestHandler> handler =
+ new MultiQueryMultiBrowserTestHandler(true, false);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Test that multiple browsers can query simultaniously from different origins.
+TEST(MessageRouterTest, MultiQueryMultiBrowserDifferentOriginAsync) {
+ CefRefPtr<MultiQueryMultiBrowserTestHandler> handler =
+ new MultiQueryMultiBrowserTestHandler(false, false);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+namespace {
+
+// Test multiple navigations that send queries sequentially.
+class MultiQueryMultiNavigateTestHandler
+ : public MultiQueryMultiLoadTestHandler {
+ public:
+ MultiQueryMultiNavigateTestHandler(bool synchronous, bool same_origin)
+ : MultiQueryMultiLoadTestHandler(false, synchronous),
+ same_origin_(same_origin) {}
+
+ void OnManualQueriesCompleted(MultiQueryManager* manager) override {
+ const std::string& url = manager->label();
+ if (url == url1_) { // 2. Load the 2nd url.
+ GetBrowser()->GetMainFrame()->LoadURL(url2_);
+ } else if (url == url2_) { // 3. Load the 3rd url.
+ GetBrowser()->GetMainFrame()->LoadURL(url3_);
+ }
+ }
+
+ protected:
+ void RunMRTest() override {
+ url1_ = std::string(kTestDomain1) + "browser1.html";
+ url2_ = std::string(same_origin_ ? kTestDomain1 : kTestDomain2) +
+ "browser2.html";
+ url3_ = std::string(same_origin_ ? kTestDomain1 : kTestDomain3) +
+ "browser3.html";
+
+ // With same-site BFCache enabled a new browser will be created for each
+ // same-site navigation in the renderer process, resulting in "total count"
+ // values that potentially span multiple navigations.
+ const bool should_assert = !(same_origin_ && IsSameSiteBFCacheEnabled());
+ AddManagedResource(url1_, should_assert, should_assert);
+ AddManagedResource(url2_, should_assert, should_assert);
+ AddManagedResource(url3_, should_assert, should_assert);
+ Finalize();
+
+ // 1. Load the 1st url.
+ CreateBrowser(url1_, nullptr);
+ }
+
+ private:
+ bool same_origin_;
+
+ std::string url1_;
+ std::string url2_;
+ std::string url3_;
+};
+
+} // namespace
+
+// Test that multiple navigations can query from the same origin.
+TEST(MessageRouterTest, MultiQueryMultiNavigateSameOriginSync) {
+ CefRefPtr<MultiQueryMultiNavigateTestHandler> handler =
+ new MultiQueryMultiNavigateTestHandler(true, true);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Test that multiple navigations can query from the same origin.
+TEST(MessageRouterTest, MultiQueryMultiNavigateSameOriginAsync) {
+ CefRefPtr<MultiQueryMultiNavigateTestHandler> handler =
+ new MultiQueryMultiNavigateTestHandler(false, true);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Test that multiple navigations can query from different origins.
+TEST(MessageRouterTest, MultiQueryMultiNavigateDifferentOriginSync) {
+ CefRefPtr<MultiQueryMultiNavigateTestHandler> handler =
+ new MultiQueryMultiNavigateTestHandler(true, false);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Test that multiple navigations can query from different origins.
+TEST(MessageRouterTest, MultiQueryMultiNavigateDifferentOriginAsync) {
+ CefRefPtr<MultiQueryMultiNavigateTestHandler> handler =
+ new MultiQueryMultiNavigateTestHandler(false, false);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
diff --git a/tests/ceftests/message_router_single_query_unittest.cc b/tests/ceftests/message_router_single_query_unittest.cc
new file mode 100644
index 00000000..bb5373a0
--- /dev/null
+++ b/tests/ceftests/message_router_single_query_unittest.cc
@@ -0,0 +1,629 @@
+// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/ceftests/message_router_unittest_utils.h"
+
+namespace {
+
+const char kSingleQueryRequest[] = "request_context";
+const char kSingleQueryResponse[] = "success_response";
+const int kSingleQueryErrorCode = 5;
+const char kSingleQueryErrorMessage[] = "error_message";
+
+// Test a single query in a single page load.
+class SingleQueryTestHandler : public SingleLoadTestHandler {
+ public:
+ enum TestType {
+ SUCCESS,
+ FAILURE,
+ CANCEL,
+ };
+
+ SingleQueryTestHandler(TestType type, bool sync_callback)
+ : test_type_(type), sync_callback_(sync_callback), query_id_(0) {}
+
+ std::string GetMainHTML() override {
+ std::string html;
+
+ std::stringstream ss;
+ ss << kSingleQueryErrorCode;
+ const std::string& errorCodeStr = ss.str();
+
+ html =
+ "<html><body><script>\n"
+ // No requests should exist.
+ "window.mrtAssertTotalCount(" LINESTR
+ ",0);\n"
+ "window.mrtAssertBrowserCount(" LINESTR
+ ",0);\n"
+ "window.mrtAssertContextCount(" LINESTR
+ ",0);\n"
+ // Send the query.
+ "var request_id = window.mrtQuery({\n"
+ " request: '" +
+ std::string(kSingleQueryRequest) +
+ "',\n"
+ " persistent: false,\n"
+ " onSuccess: function(response) {\n"
+ // Request should be removed before callback is executed.
+ " window.mrtAssertTotalCount(" LINESTR
+ ",0);\n"
+ " window.mrtAssertBrowserCount(" LINESTR
+ ",0);\n"
+ " window.mrtAssertContextCount(" LINESTR
+ ",0);\n"
+ " if (response == '" +
+ std::string(kSingleQueryResponse) +
+ "')\n"
+ " window.mrtNotify('success');\n"
+ " else\n"
+ " window.mrtNotify('error-onSuccess');\n"
+ " },\n"
+ " onFailure: function(error_code, error_message) {\n"
+ // Request should be removed before callback is executed.
+ " window.mrtAssertTotalCount(" LINESTR
+ ",0);\n"
+ " window.mrtAssertBrowserCount(" LINESTR
+ ",0);\n"
+ " window.mrtAssertContextCount(" LINESTR
+ ",0);\n"
+ " if (error_code == " +
+ errorCodeStr + " && error_message == '" +
+ std::string(kSingleQueryErrorMessage) +
+ "')\n"
+ " window.mrtNotify('failure');\n"
+ " else\n"
+ " window.mrtNotify('error-onFailure');\n"
+ " }\n"
+ "});\n"
+ // Request should exist.
+ "window.mrtAssertTotalCount(" LINESTR
+ ",1);\n"
+ "window.mrtAssertBrowserCount(" LINESTR
+ ",1);\n"
+ "window.mrtAssertContextCount(" LINESTR ",1);\n";
+
+ if (test_type_ == CANCEL) {
+ html +=
+ "window.mrtQueryCancel(request_id);\n"
+ // Request should be removed immediately.
+ "window.mrtAssertTotalCount(" LINESTR
+ ",0);\n"
+ "window.mrtAssertBrowserCount(" LINESTR
+ ",0);\n"
+ "window.mrtAssertContextCount(" LINESTR
+ ",0);\n"
+ "window.mrtNotify('cancel');\n";
+ }
+
+ html += "</script></body></html>";
+ return html;
+ }
+
+ void OnNotify(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const std::string& message) override {
+ AssertMainBrowser(browser);
+ AssertMainFrame(frame);
+
+ // OnNotify only be called once.
+ EXPECT_FALSE(got_notify_);
+ got_notify_.yes();
+
+ if (test_type_ == SUCCESS) {
+ EXPECT_STREQ("success", message.c_str());
+ } else if (test_type_ == FAILURE) {
+ EXPECT_STREQ("failure", message.c_str());
+ } else if (test_type_ == CANCEL) {
+ EXPECT_STREQ("cancel", message.c_str());
+ }
+
+ DestroyTestIfDone();
+ }
+
+ void ExecuteCallback() {
+ EXPECT_TRUE(callback_.get());
+ if (test_type_ == SUCCESS) {
+ callback_->Success(kSingleQueryResponse);
+ } else if (test_type_ == FAILURE) {
+ callback_->Failure(kSingleQueryErrorCode, kSingleQueryErrorMessage);
+ } else {
+ ADD_FAILURE(); // Not reached.
+ }
+ callback_ = nullptr;
+ }
+
+ bool OnQuery(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int64 query_id,
+ const CefString& request,
+ bool persistent,
+ CefRefPtr<Callback> callback) override {
+ AssertMainBrowser(browser);
+ AssertMainFrame(frame);
+ EXPECT_NE(0, query_id);
+ EXPECT_FALSE(persistent);
+ EXPECT_STREQ(kSingleQueryRequest, request.ToString().c_str());
+
+ got_on_query_.yes();
+
+ query_id_ = query_id;
+ callback_ = callback;
+
+ if (test_type_ == SUCCESS || test_type_ == FAILURE) {
+ if (sync_callback_) {
+ ExecuteCallback();
+ } else {
+ CefPostTask(
+ TID_UI,
+ base::BindOnce(&SingleQueryTestHandler::ExecuteCallback, this));
+ }
+ }
+
+ return true;
+ }
+
+ void OnQueryCanceled(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int64 query_id) override {
+ AssertMainBrowser(browser);
+ AssertMainFrame(frame);
+ EXPECT_EQ(test_type_, CANCEL);
+ EXPECT_EQ(query_id_, query_id);
+ EXPECT_TRUE(got_on_query_);
+ EXPECT_TRUE(callback_.get());
+
+ got_on_query_canceled_.yes();
+ callback_ = nullptr;
+
+ DestroyTestIfDone();
+ }
+
+ void DestroyTestIfDone() {
+ bool destroy_test = false;
+ if (test_type_ == CANCEL) {
+ destroy_test = got_notify_ && got_on_query_canceled_;
+ } else {
+ destroy_test = got_notify_;
+ }
+ if (destroy_test) {
+ DestroyTest();
+ }
+ }
+
+ void DestroyTest() override {
+ EXPECT_TRUE(got_notify_);
+ EXPECT_TRUE(got_on_query_);
+ EXPECT_FALSE(callback_.get());
+
+ if (test_type_ == CANCEL) {
+ EXPECT_TRUE(got_on_query_canceled_);
+ } else {
+ EXPECT_FALSE(got_on_query_canceled_);
+ }
+
+ TestHandler::DestroyTest();
+ }
+
+ private:
+ const TestType test_type_;
+ const bool sync_callback_;
+
+ int64 query_id_;
+ CefRefPtr<Callback> callback_;
+
+ TrackCallback got_on_query_;
+ TrackCallback got_on_query_canceled_;
+ TrackCallback got_notify_;
+};
+
+} // namespace
+
+// Test that a single query with successful result delivered synchronously.
+TEST(MessageRouterTest, SingleQuerySuccessSyncCallback) {
+ CefRefPtr<SingleQueryTestHandler> handler =
+ new SingleQueryTestHandler(SingleQueryTestHandler::SUCCESS, true);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Test that a single query with successful result delivered asynchronously.
+TEST(MessageRouterTest, SingleQuerySuccessAsyncCallback) {
+ CefRefPtr<SingleQueryTestHandler> handler =
+ new SingleQueryTestHandler(SingleQueryTestHandler::SUCCESS, false);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Test that a single query with failure result delivered synchronously.
+TEST(MessageRouterTest, SingleQueryFailureSyncCallback) {
+ CefRefPtr<SingleQueryTestHandler> handler =
+ new SingleQueryTestHandler(SingleQueryTestHandler::FAILURE, true);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Test that a single query with failure result delivered asynchronously.
+TEST(MessageRouterTest, SingleQueryFailureAsyncCallback) {
+ CefRefPtr<SingleQueryTestHandler> handler =
+ new SingleQueryTestHandler(SingleQueryTestHandler::FAILURE, false);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Test that a single query with cancellation.
+TEST(MessageRouterTest, SingleQueryCancel) {
+ CefRefPtr<SingleQueryTestHandler> handler =
+ new SingleQueryTestHandler(SingleQueryTestHandler::CANCEL, true);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+namespace {
+
+const int kSinglePersistentQueryResponseCount = 10;
+
+// Test a single persistent query in a single page load.
+class SinglePersistentQueryTestHandler : public SingleLoadTestHandler {
+ public:
+ enum TestType {
+ SUCCESS,
+ FAILURE,
+ };
+
+ SinglePersistentQueryTestHandler(TestType test_type, bool sync_callback)
+ : test_type_(test_type), sync_callback_(sync_callback), query_id_(0) {}
+
+ std::string GetMainHTML() override {
+ std::string html;
+
+ std::stringstream ss;
+ ss << kSinglePersistentQueryResponseCount;
+ const std::string& responseCountStr = ss.str();
+ ss.str("");
+ ss << kSingleQueryErrorCode;
+ const std::string& errorCodeStr = ss.str();
+
+ html =
+ "<html><body><script>\n"
+ // No requests should exist.
+ "window.mrtAssertTotalCount(" LINESTR
+ ",0);\n"
+ "window.mrtAssertBrowserCount(" LINESTR
+ ",0);\n"
+ "window.mrtAssertContextCount(" LINESTR
+ ",0);\n"
+ // Keep track of the number of responses.
+ "var count = 0;\n"
+ // Send the query.
+ "var request_id = window.mrtQuery({\n"
+ " request: '" +
+ std::string(kSingleQueryRequest) +
+ "',\n"
+ " persistent: true,\n"
+ " onSuccess: function(response) {\n"
+ // Request should not be removed.
+ " window.mrtAssertTotalCount(" LINESTR
+ ",1);\n"
+ " window.mrtAssertBrowserCount(" LINESTR
+ ",1);\n"
+ " window.mrtAssertContextCount(" LINESTR
+ ",1);\n"
+ " if (response == '" +
+ std::string(kSingleQueryResponse) +
+ "') {\n"
+ " if (++count == " +
+ responseCountStr +
+ ") {\n"
+ " window.mrtNotify('success');\n"
+ " window.mrtQueryCancel(request_id);\n"
+ // Request should be removed immediately.
+ " window.mrtAssertTotalCount(" LINESTR
+ ",0);\n"
+ " window.mrtAssertBrowserCount(" LINESTR
+ ",0);\n"
+ " window.mrtAssertContextCount(" LINESTR
+ ",0);\n"
+ " }\n"
+ " } else {\n"
+ " window.mrtNotify('error-onSuccess');\n"
+ " }\n"
+ " },\n"
+ " onFailure: function(error_code, error_message) {\n"
+ // Request should be removed before callback is executed.
+ " window.mrtAssertTotalCount(" LINESTR
+ ",0);\n"
+ " window.mrtAssertBrowserCount(" LINESTR
+ ",0);\n"
+ " window.mrtAssertContextCount(" LINESTR
+ ",0);\n"
+ " if (error_code == " +
+ errorCodeStr + " && error_message == '" +
+ std::string(kSingleQueryErrorMessage) +
+ "') {\n"
+ " window.mrtNotify('failure');\n"
+ " } else {\n"
+ " window.mrtNotify('error-onFailure');\n"
+ " }\n"
+ " }\n"
+ "});\n"
+ // Request should exist.
+ "window.mrtAssertTotalCount(" LINESTR
+ ",1);\n"
+ "window.mrtAssertBrowserCount(" LINESTR
+ ",1);\n"
+ "window.mrtAssertContextCount(" LINESTR ",1);\n";
+
+ html += "</script></body></html>";
+ return html;
+ }
+
+ void OnNotify(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const std::string& message) override {
+ AssertMainBrowser(browser);
+ AssertMainFrame(frame);
+
+ if (test_type_ == SUCCESS) {
+ EXPECT_STREQ("success", message.c_str());
+ } else if (test_type_ == FAILURE) {
+ EXPECT_STREQ("failure", message.c_str());
+ }
+
+ got_notify_.yes();
+
+ DestroyTestIfDone();
+ }
+
+ void ExecuteCallback() {
+ EXPECT_TRUE(callback_.get());
+ if (test_type_ == SUCCESS) {
+ callback_->Success(kSingleQueryResponse);
+ } else {
+ callback_->Failure(kSingleQueryErrorCode, kSingleQueryErrorMessage);
+ callback_ = nullptr;
+ }
+ }
+
+ bool OnQuery(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int64 query_id,
+ const CefString& request,
+ bool persistent,
+ CefRefPtr<Callback> callback) override {
+ AssertMainBrowser(browser);
+ AssertMainFrame(frame);
+ EXPECT_NE(0, query_id);
+ EXPECT_TRUE(persistent);
+ EXPECT_STREQ(kSingleQueryRequest, request.ToString().c_str());
+
+ got_on_query_.yes();
+
+ query_id_ = query_id;
+ callback_ = callback;
+
+ int repeat =
+ (test_type_ == SUCCESS ? kSinglePersistentQueryResponseCount : 1);
+
+ for (int i = 0; i < repeat; ++i) {
+ if (sync_callback_) {
+ ExecuteCallback();
+ } else {
+ CefPostTask(
+ TID_UI,
+ base::BindOnce(&SinglePersistentQueryTestHandler::ExecuteCallback,
+ this));
+ }
+ }
+
+ return true;
+ }
+
+ void OnQueryCanceled(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int64 query_id) override {
+ AssertMainBrowser(browser);
+ AssertMainFrame(frame);
+ EXPECT_EQ(query_id_, query_id);
+ EXPECT_TRUE(got_on_query_);
+ EXPECT_TRUE(callback_.get());
+
+ got_on_query_canceled_.yes();
+ callback_ = nullptr;
+
+ DestroyTestIfDone();
+ }
+
+ void DestroyTestIfDone() {
+ bool destroy_test = false;
+ if (test_type_ == SUCCESS) {
+ if (got_on_query_ && got_on_query_canceled_ && got_notify_) {
+ destroy_test = true;
+ }
+ } else if (got_on_query_ && got_notify_) {
+ destroy_test = true;
+ }
+
+ if (destroy_test) {
+ DestroyTest();
+ }
+ }
+
+ void DestroyTest() override {
+ EXPECT_TRUE(got_notify_);
+ EXPECT_TRUE(got_on_query_);
+ EXPECT_FALSE(callback_.get());
+
+ if (test_type_ == SUCCESS) {
+ EXPECT_TRUE(got_on_query_canceled_);
+ } else {
+ EXPECT_FALSE(got_on_query_canceled_);
+ }
+
+ TestHandler::DestroyTest();
+ }
+
+ private:
+ const TestType test_type_;
+ const bool sync_callback_;
+
+ int64 query_id_;
+ CefRefPtr<Callback> callback_;
+
+ TrackCallback got_on_query_;
+ TrackCallback got_on_query_canceled_;
+ TrackCallback got_notify_;
+};
+
+} // namespace
+
+// Test that a single query with successful result delivered synchronously.
+TEST(MessageRouterTest, SinglePersistentQuerySuccessSyncCallback) {
+ CefRefPtr<SinglePersistentQueryTestHandler> handler =
+ new SinglePersistentQueryTestHandler(
+ SinglePersistentQueryTestHandler::SUCCESS, true);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Test that a single query with successful result delivered asynchronously.
+TEST(MessageRouterTest, SinglePersistentQuerySuccessAsyncCallback) {
+ CefRefPtr<SinglePersistentQueryTestHandler> handler =
+ new SinglePersistentQueryTestHandler(
+ SinglePersistentQueryTestHandler::SUCCESS, false);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Test that a single query with failure result delivered synchronously.
+TEST(MessageRouterTest, SinglePersistentQueryFailureSyncCallback) {
+ CefRefPtr<SinglePersistentQueryTestHandler> handler =
+ new SinglePersistentQueryTestHandler(
+ SinglePersistentQueryTestHandler::FAILURE, true);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Test that a single query with failure result delivered asynchronously.
+TEST(MessageRouterTest, SinglePersistentQueryFailureAsyncCallback) {
+ CefRefPtr<SinglePersistentQueryTestHandler> handler =
+ new SinglePersistentQueryTestHandler(
+ SinglePersistentQueryTestHandler::FAILURE, false);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+namespace {
+
+// Test a single unhandled query in a single page load.
+class SingleUnhandledQueryTestHandler : public SingleLoadTestHandler {
+ public:
+ SingleUnhandledQueryTestHandler() {}
+
+ std::string GetMainHTML() override {
+ std::string html;
+
+ html =
+ "<html><body><script>\n"
+ // No requests should exist.
+ "window.mrtAssertTotalCount(" LINESTR
+ ",0);\n"
+ "window.mrtAssertBrowserCount(" LINESTR
+ ",0);\n"
+ "window.mrtAssertContextCount(" LINESTR
+ ",0);\n"
+ // Keep track of the number of responses.
+ "var count = 0;\n"
+ // Send the query.
+ "var request_id = window.mrtQuery({\n"
+ " request: '" +
+ std::string(kSingleQueryRequest) +
+ "',\n"
+ " persistent: false,\n"
+ " onSuccess: function(response) {\n"
+ " window.mrtNotify('error-onSuccess');\n"
+ " },\n"
+ " onFailure: function(error_code, error_message) {\n"
+ // Request should be removed before callback is executed.
+ " window.mrtAssertTotalCount(" LINESTR
+ ",0);\n"
+ " window.mrtAssertBrowserCount(" LINESTR
+ ",0);\n"
+ " window.mrtAssertContextCount(" LINESTR
+ ",0);\n"
+ " if (error_code == -1 && "
+ "error_message == 'The query has been canceled') {\n"
+ " window.mrtNotify('failure');\n"
+ " } else {\n"
+ " window.mrtNotify('error-onFailure');\n"
+ " }\n"
+ " }\n"
+ "});\n"
+ // Request should exist.
+ "window.mrtAssertTotalCount(" LINESTR
+ ",1);\n"
+ "window.mrtAssertBrowserCount(" LINESTR
+ ",1);\n"
+ "window.mrtAssertContextCount(" LINESTR ",1);\n";
+
+ html += "</script></body></html>";
+ return html;
+ }
+
+ void OnNotify(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const std::string& message) override {
+ AssertMainBrowser(browser);
+ AssertMainFrame(frame);
+ EXPECT_STREQ("failure", message.c_str());
+
+ got_notify_.yes();
+
+ DestroyTest();
+ }
+
+ bool OnQuery(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int64 query_id,
+ const CefString& request,
+ bool persistent,
+ CefRefPtr<Callback> callback) override {
+ AssertMainBrowser(browser);
+ AssertMainFrame(frame);
+ EXPECT_NE(0, query_id);
+ EXPECT_FALSE(persistent);
+ EXPECT_STREQ(kSingleQueryRequest, request.ToString().c_str());
+
+ got_on_query_.yes();
+
+ return false;
+ }
+
+ void OnQueryCanceled(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int64 query_id) override {
+ EXPECT_FALSE(true); // Not reached.
+ }
+
+ void DestroyTest() override {
+ EXPECT_TRUE(got_on_query_);
+ EXPECT_TRUE(got_notify_);
+
+ TestHandler::DestroyTest();
+ }
+
+ private:
+ TrackCallback got_on_query_;
+ TrackCallback got_notify_;
+};
+
+} // namespace
+
+// Test that a single unhandled query results in a call to onFailure.
+TEST(MessageRouterTest, SingleUnhandledQuery) {
+ CefRefPtr<SingleUnhandledQueryTestHandler> handler =
+ new SingleUnhandledQueryTestHandler();
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
diff --git a/tests/ceftests/message_router_threshold_unittest.cc b/tests/ceftests/message_router_threshold_unittest.cc
new file mode 100644
index 00000000..0c17a91d
--- /dev/null
+++ b/tests/ceftests/message_router_threshold_unittest.cc
@@ -0,0 +1,225 @@
+// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/ceftests/message_router_unittest_utils.h"
+
+namespace {
+
+constexpr int kSingleQueryErrorCode = 5;
+constexpr size_t kMessageSizeThreshold = 16000;
+
+enum class TestType { SUCCESS, FAILURE };
+
+CefString GenerateResponse(size_t size, char ch) {
+ return CefString(std::string(size, ch));
+}
+
+CefString GenerateResponse(size_t size, wchar_t ch) {
+ return CefString(std::wstring(size, ch));
+}
+
+template <class CharType>
+class ThresholdTestHandler final : public SingleLoadTestHandler {
+ public:
+ ThresholdTestHandler(TestType type, size_t message_size, CharType symbol)
+ : test_type_(type),
+ message_size_(message_size),
+ message_size_str_(std::to_string(message_size)),
+ symbol_(symbol) {}
+
+ std::string GetMainHTML() override {
+ const std::string& errorCodeStr = std::to_string(kSingleQueryErrorCode);
+
+ std::string html =
+ "<html><body><script>\n"
+ // Send the query.
+ "var request_id = window." +
+ std::string(kJSQueryFunc) + "({\n request: '" + message_size_str_ +
+ "',\n persistent: false,\n"
+ " onSuccess: function(response) {\n"
+ " window.mrtNotify(response);\n"
+ " },\n"
+ " onFailure: function(error_code, error_message) {\n"
+ " if (error_code == " +
+ errorCodeStr +
+ ")\n"
+ " window.mrtNotify(error_message);\n"
+ " else\n"
+ " window.mrtNotify('error-onFailure');\n"
+ " }\n"
+ "});\n</script></body></html>";
+
+ return html;
+ }
+
+ void OnNotify(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const std::string& message) override {
+ AssertMainBrowser(browser);
+ AssertMainFrame(frame);
+
+ // OnNotify only be called once.
+ EXPECT_FALSE(got_notify_);
+ got_notify_.yes();
+
+ auto expected = GenerateResponse(message_size_, symbol_);
+
+ switch (test_type_) {
+ case TestType::SUCCESS:
+ EXPECT_EQ(expected, message);
+ break;
+ case TestType::FAILURE:
+ EXPECT_EQ(expected, message);
+ break;
+ default:
+ ADD_FAILURE();
+ break;
+ }
+
+ DestroyTest();
+ }
+
+ void ExecuteCallback(size_t response_size) {
+ auto response = GenerateResponse(response_size, symbol_);
+
+ EXPECT_TRUE(callback_.get());
+ switch (test_type_) {
+ case TestType::SUCCESS:
+ callback_->Success(response);
+ break;
+ case TestType::FAILURE:
+ callback_->Failure(kSingleQueryErrorCode, response);
+ break;
+ default:
+ ADD_FAILURE();
+ break;
+ }
+ callback_ = nullptr;
+ }
+
+ bool OnQuery(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int64 query_id,
+ const CefString& request,
+ bool persistent,
+ CefRefPtr<Callback> callback) override {
+ AssertMainBrowser(browser);
+ AssertMainFrame(frame);
+ EXPECT_NE(0, query_id);
+ EXPECT_FALSE(persistent);
+ EXPECT_EQ(message_size_str_, request.ToString());
+
+ const size_t message_size =
+ static_cast<size_t>(std::stoi(request.ToString()));
+ got_on_query_.yes();
+
+ callback_ = callback;
+ ExecuteCallback(message_size);
+
+ return true;
+ }
+
+ void DestroyTest() override {
+ EXPECT_TRUE(got_notify_);
+ EXPECT_TRUE(got_on_query_);
+ EXPECT_FALSE(callback_.get());
+
+ TestHandler::DestroyTest();
+ }
+
+ private:
+ const TestType test_type_;
+ const size_t message_size_;
+ const std::string message_size_str_;
+ const CharType symbol_;
+
+ CefRefPtr<Callback> callback_;
+
+ TrackCallback got_on_query_;
+ TrackCallback got_notify_;
+};
+
+using CharTestHandler = ThresholdTestHandler<char>;
+using CharTestHandlerPtr = CefRefPtr<CharTestHandler>;
+
+using WCharTestHandler = ThresholdTestHandler<wchar_t>;
+using WCharTestHandlerPtr = CefRefPtr<WCharTestHandler>;
+
+} // namespace
+
+TEST(MessageRouterTest, ThresholdMessageUnderSuccessCallback) {
+ const auto UnderThreshold = kMessageSizeThreshold - 1;
+ CharTestHandlerPtr handler =
+ new CharTestHandler(TestType::SUCCESS, UnderThreshold, 'A');
+ handler->SetMessageSizeThreshold(kMessageSizeThreshold);
+
+ handler->ExecuteTest();
+
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(MessageRouterTest, ThresholMessageExactdSuccessCallback) {
+ CharTestHandlerPtr handler =
+ new CharTestHandler(TestType::SUCCESS, kMessageSizeThreshold, 'A');
+ handler->SetMessageSizeThreshold(kMessageSizeThreshold);
+
+ handler->ExecuteTest();
+
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(MessageRouterTest, ThresholdMessageOverSuccessCallback) {
+ const auto OverThreshold = kMessageSizeThreshold + 1;
+ CharTestHandlerPtr handler =
+ new CharTestHandler(TestType::SUCCESS, OverThreshold, 'A');
+ handler->SetMessageSizeThreshold(kMessageSizeThreshold);
+
+ handler->ExecuteTest();
+
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(MessageRouterTest, ThresholdMessageUnderFailureCallback) {
+ const auto UnderThreshold = kMessageSizeThreshold - 1;
+ CharTestHandlerPtr handler =
+ new CharTestHandler(TestType::FAILURE, UnderThreshold, 'A');
+ handler->SetMessageSizeThreshold(kMessageSizeThreshold);
+
+ handler->ExecuteTest();
+
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(MessageRouterTest, ThresholMessageOverdFailureCallback) {
+ const auto OverThreshold = kMessageSizeThreshold + 1;
+ CharTestHandlerPtr handler =
+ new CharTestHandler(TestType::FAILURE, OverThreshold, 'A');
+ handler->SetMessageSizeThreshold(kMessageSizeThreshold);
+
+ handler->ExecuteTest();
+
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(MessageRouterTest, ThresholdUtf8MessageUnderSuccessCallback) {
+ const auto UnderThreshold = kMessageSizeThreshold - 1;
+ WCharTestHandlerPtr handler =
+ new WCharTestHandler(TestType::SUCCESS, UnderThreshold, L'\u304B');
+ handler->SetMessageSizeThreshold(kMessageSizeThreshold);
+
+ handler->ExecuteTest();
+
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(MessageRouterTest, ThresholdUtf8MessageOverSuccessCallback) {
+ const auto OverThreshold = kMessageSizeThreshold + 1;
+ WCharTestHandlerPtr handler =
+ new WCharTestHandler(TestType::SUCCESS, OverThreshold, L'\u304B');
+ handler->SetMessageSizeThreshold(kMessageSizeThreshold);
+
+ handler->ExecuteTest();
+
+ ReleaseAndWaitForDestructor(handler);
+}
diff --git a/tests/ceftests/message_router_unittest_utils.cc b/tests/ceftests/message_router_unittest_utils.cc
new file mode 100644
index 00000000..29800f1a
--- /dev/null
+++ b/tests/ceftests/message_router_unittest_utils.cc
@@ -0,0 +1,260 @@
+// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/ceftests/message_router_unittest_utils.h"
+
+extern const char kJSQueryFunc[] = "mrtQuery";
+extern const char kJSQueryCancelFunc[] = "mrtQueryCancel";
+
+namespace {
+
+const char kTestDomainRoot[] = "http://tests-mr";
+const char kDoneMessageName[] = "mrtNotifyMsg";
+const char kJSNotifyFunc[] = "mrtNotify";
+const char kJSAssertTotalCountFunc[] = "mrtAssertTotalCount";
+const char kJSAssertBrowserCountFunc[] = "mrtAssertBrowserCount";
+const char kJSAssertContextCountFunc[] = "mrtAssertContextCount";
+
+void SetRouterConfig(CefMessageRouterConfig& config) {
+ config.js_query_function = kJSQueryFunc;
+ config.js_cancel_function = kJSQueryCancelFunc;
+}
+
+} // namespace
+
+// Entry point for creating the test delegate.
+// Called from client_app_delegates.cc.
+void CreateMessageRouterRendererTests(
+ ClientAppRenderer::DelegateSet& delegates) {
+ delegates.insert(new MRRenderDelegate);
+}
+
+bool MRRenderDelegate::V8HandlerImpl::Execute(const CefString& name,
+ CefRefPtr<CefV8Value> object,
+ const CefV8ValueList& arguments,
+ CefRefPtr<CefV8Value>& retval,
+ CefString& exception) {
+ const std::string& message_name = name;
+ if (message_name == kJSNotifyFunc) {
+ EXPECT_EQ(1U, arguments.size());
+ EXPECT_TRUE(arguments[0]->IsString());
+
+ const CefString& msg = arguments[0]->GetStringValue();
+ CefRefPtr<CefV8Context> context = CefV8Context::GetCurrentContext();
+ CefRefPtr<CefFrame> frame = context->GetFrame();
+
+ CefRefPtr<CefProcessMessage> message =
+ CefProcessMessage::Create(kDoneMessageName);
+ CefRefPtr<CefListValue> args = message->GetArgumentList();
+ args->SetString(0, msg);
+ frame->SendProcessMessage(PID_BROWSER, message);
+ return true;
+ } else {
+ EXPECT_EQ(2U, arguments.size());
+ EXPECT_TRUE(arguments[0]->IsInt());
+ EXPECT_TRUE(arguments[1]->IsInt());
+
+ const int line_no = arguments[0]->GetIntValue();
+ const int expected_count = arguments[1]->GetIntValue();
+ int actual_count = -1;
+
+ CefRefPtr<CefV8Context> context = CefV8Context::GetCurrentContext();
+ CefRefPtr<CefBrowser> browser = context->GetBrowser();
+
+ if (name == kJSAssertTotalCountFunc) {
+ actual_count =
+ delegate_->message_router_->GetPendingCount(nullptr, nullptr);
+ } else if (name == kJSAssertBrowserCountFunc) {
+ actual_count =
+ delegate_->message_router_->GetPendingCount(browser, nullptr);
+ } else if (name == kJSAssertContextCountFunc) {
+ actual_count =
+ delegate_->message_router_->GetPendingCount(browser, context);
+ }
+
+ if (expected_count != actual_count) {
+ std::stringstream ss;
+ ss << message_name << " failed (line " << line_no << "); expected "
+ << expected_count << ", got " << actual_count;
+ exception = ss.str();
+ }
+ }
+
+ return true;
+}
+
+void MRRenderDelegate::OnWebKitInitialized(CefRefPtr<ClientAppRenderer> app) {
+ // Create the renderer-side router for query handling.
+ CefMessageRouterConfig config;
+ SetRouterConfig(config);
+ message_router_ = CefMessageRouterRendererSide::Create(config);
+}
+
+void MRRenderDelegate::OnContextCreated(CefRefPtr<ClientAppRenderer> app,
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefV8Context> context) {
+ const std::string& url = frame->GetURL();
+ if (url.find(kTestDomainRoot) != 0) {
+ return;
+ }
+
+ message_router_->OnContextCreated(browser, frame, context);
+
+ // Register function handlers with the 'window' object.
+ CefRefPtr<CefV8Value> window = context->GetGlobal();
+
+ CefRefPtr<V8HandlerImpl> handler = new V8HandlerImpl(this);
+ CefV8Value::PropertyAttribute attributes =
+ static_cast<CefV8Value::PropertyAttribute>(
+ V8_PROPERTY_ATTRIBUTE_READONLY | V8_PROPERTY_ATTRIBUTE_DONTENUM |
+ V8_PROPERTY_ATTRIBUTE_DONTDELETE);
+
+ CefRefPtr<CefV8Value> notify_func =
+ CefV8Value::CreateFunction(kJSNotifyFunc, handler.get());
+ window->SetValue(kJSNotifyFunc, notify_func, attributes);
+
+ CefRefPtr<CefV8Value> total_count_func =
+ CefV8Value::CreateFunction(kJSAssertTotalCountFunc, handler.get());
+ window->SetValue(kJSAssertTotalCountFunc, total_count_func, attributes);
+
+ CefRefPtr<CefV8Value> browser_count_func =
+ CefV8Value::CreateFunction(kJSAssertBrowserCountFunc, handler.get());
+ window->SetValue(kJSAssertBrowserCountFunc, browser_count_func, attributes);
+
+ CefRefPtr<CefV8Value> context_count_func =
+ CefV8Value::CreateFunction(kJSAssertContextCountFunc, handler.get());
+ window->SetValue(kJSAssertContextCountFunc, context_count_func, attributes);
+}
+
+void MRRenderDelegate::OnContextReleased(CefRefPtr<ClientAppRenderer> app,
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefV8Context> context) {
+ const std::string& url = frame->GetURL();
+ if (url.find(kTestDomainRoot) != 0) {
+ return;
+ }
+
+ message_router_->OnContextReleased(browser, frame, context);
+}
+
+bool MRRenderDelegate::OnProcessMessageReceived(
+ CefRefPtr<ClientAppRenderer> app,
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefProcessId source_process,
+ CefRefPtr<CefProcessMessage> message) {
+ const std::string& url = frame->GetURL();
+ if (url.find(kTestDomainRoot) != 0) {
+ return false;
+ }
+
+ return message_router_->OnProcessMessageReceived(browser, frame,
+ source_process, message);
+}
+
+void MRTestHandler::RunTest() {
+ RunMRTest();
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout(10000);
+}
+
+void MRTestHandler::OnAfterCreated(CefRefPtr<CefBrowser> browser) {
+ if (!message_router_.get()) {
+ // Create the browser-side router for query handling.
+ CefMessageRouterConfig config;
+
+ SetRouterConfig(config);
+ if (message_size_threshold_) {
+ config.message_size_threshold = message_size_threshold_;
+ }
+
+ message_router_ = CefMessageRouterBrowserSide::Create(config);
+ AddHandlers(message_router_);
+ }
+ TestHandler::OnAfterCreated(browser);
+}
+
+void MRTestHandler::OnBeforeClose(CefRefPtr<CefBrowser> browser) {
+ message_router_->OnBeforeClose(browser);
+ TestHandler::OnBeforeClose(browser);
+}
+
+void MRTestHandler::OnRenderProcessTerminated(CefRefPtr<CefBrowser> browser,
+ TerminationStatus status) {
+ message_router_->OnRenderProcessTerminated(browser);
+}
+
+bool MRTestHandler::OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ bool user_gesture,
+ bool is_redirect) {
+ message_router_->OnBeforeBrowse(browser, frame);
+ return false;
+}
+
+// Returns true if the router handled the navigation.
+bool MRTestHandler::OnProcessMessageReceived(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefProcessId source_process,
+ CefRefPtr<CefProcessMessage> message) {
+ const std::string& message_name = message->GetName();
+ if (message_name == kDoneMessageName) {
+ CefRefPtr<CefListValue> args = message->GetArgumentList();
+ EXPECT_EQ(1U, args->GetSize());
+ EXPECT_EQ(VTYPE_STRING, args->GetType(0));
+ OnNotify(browser, frame, args->GetString(0));
+ return true;
+ }
+
+ return message_router_->OnProcessMessageReceived(browser, frame,
+ source_process, message);
+}
+
+CefRefPtr<CefMessageRouterBrowserSide> MRTestHandler::GetRouter() const {
+ return message_router_;
+}
+
+void MRTestHandler::SetMessageSizeThreshold(size_t message_size_threshold) {
+ message_size_threshold_ = message_size_threshold;
+}
+
+bool MRTestHandler::AssertQueryCount(
+ CefRefPtr<CefBrowser> browser,
+ CefMessageRouterBrowserSide::Handler* handler,
+ int expected_count) {
+ int actual_count = message_router_->GetPendingCount(browser, handler);
+ EXPECT_EQ(expected_count, actual_count);
+ return (expected_count == actual_count);
+}
+
+void MRTestHandler::AssertMainBrowser(CefRefPtr<CefBrowser> browser) {
+ EXPECT_TRUE(browser.get());
+ EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
+}
+
+SingleLoadTestHandler::SingleLoadTestHandler()
+ : main_url_("http://tests-mr.com/main.html") {}
+
+void SingleLoadTestHandler::RunMRTest() {
+ AddOtherResources();
+ AddResource(main_url_, GetMainHTML(), "text/html");
+
+ CreateBrowser(main_url_, nullptr);
+}
+
+void SingleLoadTestHandler::AddHandlers(
+ CefRefPtr<CefMessageRouterBrowserSide> message_router) {
+ message_router->AddHandler(this, false);
+}
+
+void SingleLoadTestHandler::AssertMainFrame(CefRefPtr<CefFrame> frame) {
+ EXPECT_TRUE(frame.get());
+ EXPECT_TRUE(frame->IsMain());
+ EXPECT_STREQ(main_url_.c_str(), frame->GetURL().ToString().c_str());
+}
diff --git a/tests/ceftests/message_router_unittest_utils.h b/tests/ceftests/message_router_unittest_utils.h
new file mode 100644
index 00000000..25d57598
--- /dev/null
+++ b/tests/ceftests/message_router_unittest_utils.h
@@ -0,0 +1,137 @@
+// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFTESTS_MESSAGE_ROUTER_UNITTEST_UTILS_H_
+#define CEF_TESTS_CEFTESTS_MESSAGE_ROUTER_UNITTEST_UTILS_H_
+#pragma once
+
+#include <cstdlib>
+
+#include "include/base/cef_callback.h"
+#include "include/base/cef_weak_ptr.h"
+#include "include/cef_v8.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "tests/ceftests/routing_test_handler.h"
+#include "tests/ceftests/test_util.h"
+#include "tests/gtest/include/gtest/gtest.h"
+#include "tests/shared/renderer/client_app_renderer.h"
+
+using client::ClientAppRenderer;
+
+extern const char kJSQueryFunc[];
+extern const char kJSQueryCancelFunc[];
+
+#define S1(N) #N
+#define S2(N) S1(N)
+#define LINESTR S2(__LINE__)
+
+// Handle the renderer side of the routing implementation.
+class MRRenderDelegate : public ClientAppRenderer::Delegate {
+ public:
+ class V8HandlerImpl : public CefV8Handler {
+ public:
+ explicit V8HandlerImpl(CefRefPtr<MRRenderDelegate> delegate)
+ : delegate_(delegate) {}
+
+ bool Execute(const CefString& name,
+ CefRefPtr<CefV8Value> object,
+ const CefV8ValueList& arguments,
+ CefRefPtr<CefV8Value>& retval,
+ CefString& exception) override;
+
+ private:
+ CefRefPtr<MRRenderDelegate> delegate_;
+
+ IMPLEMENT_REFCOUNTING(V8HandlerImpl);
+ };
+
+ void OnWebKitInitialized(CefRefPtr<ClientAppRenderer> app) override;
+
+ void OnContextCreated(CefRefPtr<ClientAppRenderer> app,
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefV8Context> context) override;
+
+ void OnContextReleased(CefRefPtr<ClientAppRenderer> app,
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefV8Context> context) override;
+
+ bool OnProcessMessageReceived(CefRefPtr<ClientAppRenderer> app,
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefProcessId source_process,
+ CefRefPtr<CefProcessMessage> message) override;
+
+ private:
+ CefRefPtr<CefMessageRouterRendererSide> message_router_;
+
+ IMPLEMENT_REFCOUNTING(MRRenderDelegate);
+};
+
+class MRTestHandler : public TestHandler {
+ public:
+ void RunTest() override;
+ void OnAfterCreated(CefRefPtr<CefBrowser> browser) override;
+ void OnBeforeClose(CefRefPtr<CefBrowser> browser) override;
+ void OnRenderProcessTerminated(CefRefPtr<CefBrowser> browser,
+ TerminationStatus status) override;
+
+ // Only call this method if the navigation isn't canceled.
+ bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ bool user_gesture,
+ bool is_redirect) override;
+ // Returns true if the router handled the navigation.
+ bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefProcessId source_process,
+ CefRefPtr<CefProcessMessage> message) override;
+
+ CefRefPtr<CefMessageRouterBrowserSide> GetRouter() const;
+ void SetMessageSizeThreshold(size_t message_size_treshold);
+
+ protected:
+ virtual void RunMRTest() = 0;
+
+ virtual void AddHandlers(
+ CefRefPtr<CefMessageRouterBrowserSide> message_router) = 0;
+
+ virtual void OnNotify(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const std::string& message) = 0;
+
+ bool AssertQueryCount(CefRefPtr<CefBrowser> browser,
+ CefMessageRouterBrowserSide::Handler* handler,
+ int expected_count);
+ void AssertMainBrowser(CefRefPtr<CefBrowser> browser);
+
+ private:
+ CefRefPtr<CefMessageRouterBrowserSide> message_router_;
+ size_t message_size_threshold_ = 0;
+
+ IMPLEMENT_REFCOUNTING(MRTestHandler);
+};
+
+// Implementation of MRTestHandler that loads a single page.
+class SingleLoadTestHandler : public MRTestHandler,
+ public CefMessageRouterBrowserSide::Handler {
+ public:
+ SingleLoadTestHandler();
+ const std::string& GetMainURL() { return main_url_; }
+
+ protected:
+ void RunMRTest() override;
+ void AddHandlers(
+ CefRefPtr<CefMessageRouterBrowserSide> message_router) override;
+ virtual void AddOtherResources() {}
+ virtual std::string GetMainHTML() = 0;
+ void AssertMainFrame(CefRefPtr<CefFrame> frame);
+
+ private:
+ const std::string main_url_;
+};
+
+#endif // CEF_TESTS_CEFTESTS_MESSAGE_ROUTER_UNITTEST_UTILS_H_
diff --git a/tests/ceftests/navigation_unittest.cc b/tests/ceftests/navigation_unittest.cc
new file mode 100644
index 00000000..fcedb7e2
--- /dev/null
+++ b/tests/ceftests/navigation_unittest.cc
@@ -0,0 +1,3670 @@
+// Copyright (c) 2011 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include <algorithm>
+#include <list>
+
+#include "include/base/cef_callback.h"
+#include "include/cef_callback.h"
+#include "include/cef_scheme.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "tests/ceftests/test_handler.h"
+#include "tests/ceftests/test_util.h"
+#include "tests/gtest/include/gtest/gtest.h"
+#include "tests/shared/browser/client_app_browser.h"
+#include "tests/shared/renderer/client_app_renderer.h"
+
+// Set to 1 to enable verbose debugging info logging.
+#define VERBOSE_DEBUGGING 0
+
+using client::ClientAppBrowser;
+using client::ClientAppRenderer;
+
+namespace {
+
+const char kHNav1[] = "http://tests-hnav.com/nav1.html";
+const char kHNav2[] = "http://tests-hnav.com/nav2.html";
+const char kHNav3[] = "http://tests-hnav.com/nav3.html";
+const char kHistoryNavMsg[] = "NavigationTest.HistoryNav";
+const char kHistoryNavTestCmdKey[] = "nav-history-test";
+
+const cef_transition_type_t kTransitionExplicitLoad =
+ static_cast<cef_transition_type_t>(TT_EXPLICIT | TT_DIRECT_LOAD_FLAG);
+
+// TT_FORWARD_BACK_FLAG is added to the original transition flags.
+const cef_transition_type_t kTransitionExplicitForwardBack =
+ static_cast<cef_transition_type_t>(kTransitionExplicitLoad |
+ TT_FORWARD_BACK_FLAG);
+
+enum NavAction { NA_LOAD = 1, NA_BACK, NA_FORWARD };
+
+#if VERBOSE_DEBUGGING
+const char* NavActionString(NavAction action) {
+ switch (action) {
+ case NA_LOAD:
+ return "LOAD";
+ case NA_BACK:
+ return "BACK";
+ case NA_FORWARD:
+ return "FORWARD";
+ }
+ return "INVALID";
+}
+#endif // VERBOSE_DEBUGGING
+
+bool ExpectResourceLoadEvents(NavAction action) {
+ if (IsSameSiteBFCacheEnabled()) {
+ return action == NA_LOAD;
+ }
+ return true;
+}
+
+typedef struct {
+ NavAction action; // What to do
+ const char* target; // Where to be after navigation
+ bool can_go_back; // After navigation, can go back?
+ bool can_go_forward; // After navigation, can go forward?
+} NavListItem;
+
+// Array of navigation actions: X = current page, . = history exists
+static NavListItem kHNavList[] = {
+ // kHNav1 | kHNav2 | kHNav3
+ {NA_LOAD, kHNav1, false, false}, // X
+ {NA_LOAD, kHNav2, true, false}, // . X
+ {NA_BACK, kHNav1, false, true}, // X .
+ {NA_FORWARD, kHNav2, true, false}, // . X
+ {NA_LOAD, kHNav3, true, false}, // . . X
+ {NA_BACK, kHNav2, true, true}, // . X .
+};
+
+#define NAV_LIST_SIZE() (sizeof(kHNavList) / sizeof(NavListItem))
+
+// Renderer side.
+class HistoryNavRendererTest : public ClientAppRenderer::Delegate,
+ public CefLoadHandler {
+ public:
+ HistoryNavRendererTest() : run_test_(false), nav_(0) {}
+
+ void OnBrowserCreated(CefRefPtr<ClientAppRenderer> app,
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefDictionaryValue> extra_info) override {
+ run_test_ = extra_info && extra_info->HasKey(kHistoryNavTestCmdKey);
+ }
+
+ CefRefPtr<CefLoadHandler> GetLoadHandler(
+ CefRefPtr<ClientAppRenderer> app) override {
+ if (!run_test_) {
+ return nullptr;
+ }
+
+ return this;
+ }
+
+ void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
+ bool isLoading,
+ bool canGoBack,
+ bool canGoForward) override {
+ const NavListItem& item = kHNavList[nav_];
+#if VERBOSE_DEBUGGING
+ LOG(INFO) << "render nav=" << nav_ << " " << NavActionString(item.action)
+ << " OnLoadingStateChange isLoading=" << isLoading;
+#endif
+
+ const std::string& url = browser->GetMainFrame()->GetURL();
+ EXPECT_STREQ(item.target, url.c_str());
+
+ EXPECT_EQ(item.can_go_back, browser->CanGoBack())
+ << "nav: " << nav_ << " isLoading: " << isLoading;
+ EXPECT_EQ(item.can_go_back, canGoBack)
+ << "nav: " << nav_ << " isLoading: " << isLoading;
+ EXPECT_EQ(item.can_go_forward, browser->CanGoForward())
+ << "nav: " << nav_ << " isLoading: " << isLoading;
+ EXPECT_EQ(item.can_go_forward, canGoForward)
+ << "nav: " << nav_ << " isLoading: " << isLoading;
+
+ if (isLoading) {
+ EXPECT_FALSE(got_loading_state_start_);
+ got_loading_state_start_.yes();
+ } else {
+ EXPECT_FALSE(got_loading_state_end_);
+ got_loading_state_end_.yes();
+ SendTestResultsIfDone(browser, browser->GetMainFrame());
+ }
+ }
+
+ void OnLoadStart(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ TransitionType transition_type) override {
+ const NavListItem& item = kHNavList[nav_];
+#if VERBOSE_DEBUGGING
+ LOG(INFO) << "render nav=" << nav_ << " " << NavActionString(item.action)
+ << " OnLoadStart";
+#endif
+
+ EXPECT_FALSE(got_load_start_);
+ got_load_start_.yes();
+
+ const std::string& url = frame->GetURL();
+ EXPECT_STREQ(item.target, url.c_str());
+
+ EXPECT_EQ(TT_EXPLICIT, transition_type);
+
+ EXPECT_EQ(item.can_go_back, browser->CanGoBack());
+ EXPECT_EQ(item.can_go_forward, browser->CanGoForward());
+ }
+
+ void OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int httpStatusCode) override {
+ const NavListItem& item = kHNavList[nav_];
+#if VERBOSE_DEBUGGING
+ LOG(INFO) << "render nav=" << nav_ << " " << NavActionString(item.action)
+ << " OnLoadEnd";
+#endif
+
+ EXPECT_FALSE(got_load_end_);
+ got_load_end_.yes();
+
+ const std::string& url = frame->GetURL();
+ EXPECT_STREQ(item.target, url.c_str());
+
+ EXPECT_EQ(item.can_go_back, browser->CanGoBack());
+ EXPECT_EQ(item.can_go_forward, browser->CanGoForward());
+
+ SendTestResultsIfDone(browser, frame);
+ }
+
+ protected:
+ void SendTestResultsIfDone(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) {
+ if (got_load_end_ && got_loading_state_end_) {
+ SendTestResults(browser, frame);
+ }
+ }
+
+ // Send the test results.
+ void SendTestResults(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) {
+#if VERBOSE_DEBUGGING
+ const NavListItem& item = kHNavList[nav_];
+ LOG(INFO) << "render nav=" << nav_ << " " << NavActionString(item.action)
+ << " SendTestResults";
+#endif
+
+ EXPECT_TRUE(got_loading_state_start_);
+ EXPECT_TRUE(got_loading_state_end_);
+ EXPECT_TRUE(got_load_start_);
+ EXPECT_TRUE(got_load_end_);
+
+ // Check if the test has failed.
+ bool result = !TestFailed();
+
+ // Return the result to the browser process.
+ CefRefPtr<CefProcessMessage> return_msg =
+ CefProcessMessage::Create(kHistoryNavMsg);
+ CefRefPtr<CefListValue> args = return_msg->GetArgumentList();
+ EXPECT_TRUE(args.get());
+ EXPECT_TRUE(args->SetInt(0, nav_));
+ EXPECT_TRUE(args->SetBool(1, result));
+ frame->SendProcessMessage(PID_BROWSER, return_msg);
+
+ // Reset the test results for the next navigation.
+ got_loading_state_start_.reset();
+ got_loading_state_end_.reset();
+ got_load_start_.reset();
+ got_load_end_.reset();
+
+ nav_++;
+ }
+
+ bool run_test_;
+ int nav_;
+
+ TrackCallback got_loading_state_start_;
+ TrackCallback got_loading_state_end_;
+ TrackCallback got_load_start_;
+ TrackCallback got_load_end_;
+
+ IMPLEMENT_REFCOUNTING(HistoryNavRendererTest);
+};
+
+class NavigationEntryVisitor : public CefNavigationEntryVisitor {
+ public:
+ NavigationEntryVisitor(int nav, TrackCallback* callback)
+ : nav_(nav),
+ callback_(callback),
+ expected_total_(0),
+ expected_current_index_(-1),
+ expected_forwardback_(),
+ callback_count_(0) {
+ // Determine the expected values.
+ for (int i = 0; i <= nav_; ++i) {
+ if (kHNavList[i].action == NA_LOAD) {
+ expected_total_++;
+ expected_current_index_++;
+ } else if (kHNavList[i].action == NA_BACK) {
+ expected_current_index_--;
+ } else if (kHNavList[i].action == NA_FORWARD) {
+ expected_current_index_++;
+ }
+ expected_forwardback_[expected_current_index_] =
+ (kHNavList[i].action != NA_LOAD);
+ }
+ }
+
+ ~NavigationEntryVisitor() override {
+ EXPECT_EQ(callback_count_, expected_total_);
+ callback_->yes();
+ }
+
+ bool Visit(CefRefPtr<CefNavigationEntry> entry,
+ bool current,
+ int index,
+ int total) override {
+ // Only 3 loads total.
+ EXPECT_LT(index, 3);
+ EXPECT_LE(total, 3);
+
+ EXPECT_EQ((expected_current_index_ == index), current);
+ EXPECT_EQ(callback_count_, index);
+ EXPECT_EQ(expected_total_, total);
+
+ std::string expected_url;
+ std::string expected_title;
+ if (index == 0) {
+ expected_url = kHNav1;
+ expected_title = "Nav1";
+ } else if (index == 1) {
+ expected_url = kHNav2;
+ expected_title = "Nav2";
+ } else if (index == 2) {
+ expected_url = kHNav3;
+ expected_title = "Nav3";
+ }
+
+ EXPECT_TRUE(entry->IsValid());
+ EXPECT_STREQ(expected_url.c_str(), entry->GetURL().ToString().c_str());
+ EXPECT_STREQ(expected_url.c_str(),
+ entry->GetDisplayURL().ToString().c_str());
+ EXPECT_STREQ(expected_url.c_str(),
+ entry->GetOriginalURL().ToString().c_str());
+ EXPECT_STREQ(expected_title.c_str(), entry->GetTitle().ToString().c_str());
+
+ const auto transition_type = entry->GetTransitionType();
+ if (expected_forwardback_[index]) {
+ EXPECT_EQ(kTransitionExplicitForwardBack, transition_type);
+ } else {
+ EXPECT_EQ(kTransitionExplicitLoad, transition_type);
+ }
+
+ EXPECT_FALSE(entry->HasPostData());
+ EXPECT_GT(CefTimeFrom(entry->GetCompletionTime()).GetTimeT(), 0);
+ EXPECT_EQ(200, entry->GetHttpStatusCode());
+
+ callback_count_++;
+ return true;
+ }
+
+ private:
+ const int nav_;
+ TrackCallback* callback_;
+ int expected_total_;
+ int expected_current_index_;
+ bool expected_forwardback_[3]; // Only 3 loads total.
+ int callback_count_;
+
+ IMPLEMENT_REFCOUNTING(NavigationEntryVisitor);
+};
+
+// Browser side.
+class HistoryNavTestHandler : public TestHandler {
+ public:
+ HistoryNavTestHandler() = default;
+
+ void RunTest() override {
+ // Add the resources that we will navigate to/from.
+ AddResource(
+ kHNav1,
+ "<html><head><title>Nav1</title></head><body>Nav1</body></html>",
+ "text/html");
+ AddResource(kHNav2,
+ "<html><head><title>Nav2</title><body>Nav2</body></html>",
+ "text/html");
+ AddResource(kHNav3,
+ "<html><head><title>Nav3</title><body>Nav3</body></html>",
+ "text/html");
+
+ CefRefPtr<CefDictionaryValue> extra_info = CefDictionaryValue::Create();
+ extra_info->SetBool(kHistoryNavTestCmdKey, true);
+
+ // Create the browser.
+ CreateBrowser(CefString(), nullptr, extra_info);
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout();
+ }
+
+ void RunNav(CefRefPtr<CefBrowser> browser) {
+ if (nav_ == NAV_LIST_SIZE()) {
+ // End of the nav list.
+ DestroyTest();
+ return;
+ }
+
+ const NavListItem& item = kHNavList[nav_];
+
+ // Perform the action.
+ switch (item.action) {
+ case NA_LOAD:
+ browser->GetMainFrame()->LoadURL(item.target);
+ break;
+ case NA_BACK:
+ browser->GoBack();
+ break;
+ case NA_FORWARD:
+ browser->GoForward();
+ break;
+ default:
+ break;
+ }
+ }
+
+ void RunNextNavIfReady(CefRefPtr<CefBrowser> browser) {
+#if VERBOSE_DEBUGGING
+ LOG(INFO) << "browser nav=" << nav_
+ << " load_end_confirmation_=" << load_end_confirmation_
+ << " load_state_change_loaded_confirmation_="
+ << load_state_change_loaded_confirmation_
+ << " renderer_confirmation_=" << renderer_confirmation_;
+#endif
+
+ if (load_end_confirmation_ && load_state_change_loaded_confirmation_ &&
+ renderer_confirmation_) {
+ load_end_confirmation_ = false;
+ load_state_change_loaded_confirmation_ = false;
+ renderer_confirmation_ = false;
+ nav_++;
+ RunNav(browser);
+ }
+ }
+
+ void OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
+ TestHandler::OnAfterCreated(browser);
+
+ RunNav(browser);
+ }
+
+ bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ bool user_gesture,
+ bool is_redirect) override {
+ const NavListItem& item = kHNavList[nav_];
+
+#if VERBOSE_DEBUGGING
+ LOG(INFO) << "browser nav=" << nav_ << " " << NavActionString(item.action)
+ << " OnBeforeBrowse";
+#endif
+
+ EXPECT_FALSE(got_before_browse_[nav_]);
+ got_before_browse_[nav_].yes();
+
+ std::string url = request->GetURL();
+ EXPECT_STREQ(item.target, url.c_str());
+
+ EXPECT_EQ(RT_MAIN_FRAME, request->GetResourceType());
+
+ const auto transition_type = request->GetTransitionType();
+ if (item.action == NA_LOAD) {
+ EXPECT_EQ(kTransitionExplicitLoad, transition_type);
+ } else if (item.action == NA_BACK || item.action == NA_FORWARD) {
+ EXPECT_EQ(kTransitionExplicitForwardBack, transition_type);
+ }
+
+ if (nav_ > 0) {
+ const NavListItem& last_item = kHNavList[nav_ - 1];
+ EXPECT_EQ(last_item.can_go_back, browser->CanGoBack());
+ EXPECT_EQ(last_item.can_go_forward, browser->CanGoForward());
+ } else {
+ EXPECT_FALSE(browser->CanGoBack());
+ EXPECT_FALSE(browser->CanGoForward());
+ }
+
+ return false;
+ }
+
+ cef_return_value_t OnBeforeResourceLoad(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefCallback> callback) override {
+ if (IsChromeRuntimeEnabled() && request->GetResourceType() == RT_FAVICON) {
+ // Ignore favicon requests.
+ return RV_CANCEL;
+ }
+
+ const NavListItem& item = kHNavList[nav_];
+ const std::string& url = request->GetURL();
+
+ EXPECT_EQ(RT_MAIN_FRAME, request->GetResourceType())
+ << "nav=" << nav_ << " url=" << url;
+
+ const auto transition_type = request->GetTransitionType();
+ if (item.action == NA_LOAD) {
+ EXPECT_EQ(kTransitionExplicitLoad, transition_type)
+ << "nav=" << nav_ << " url=" << url;
+ } else if (item.action == NA_BACK || item.action == NA_FORWARD) {
+ EXPECT_EQ(kTransitionExplicitForwardBack, transition_type)
+ << "nav=" << nav_ << " url=" << url;
+ }
+
+ EXPECT_FALSE(got_before_resource_load_[nav_]);
+ got_before_resource_load_[nav_].yes();
+
+ if (url == item.target) {
+ got_correct_target_[nav_].yes();
+ }
+
+ return RV_CONTINUE;
+ }
+
+ void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
+ bool isLoading,
+ bool canGoBack,
+ bool canGoForward) override {
+ const NavListItem& item = kHNavList[nav_];
+
+#if VERBOSE_DEBUGGING
+ LOG(INFO) << "browser nav=" << nav_ << " " << NavActionString(item.action)
+ << " OnLoadingStateChange isLoading=" << isLoading;
+#endif
+
+ if (isLoading) {
+ EXPECT_FALSE(got_loading_state_change_loading_[nav_]);
+ got_loading_state_change_loading_[nav_].yes();
+ return;
+ }
+
+ EXPECT_FALSE(got_loading_state_change_loaded_[nav_]);
+ got_loading_state_change_loaded_[nav_].yes();
+
+ if (item.can_go_back == canGoBack) {
+ got_correct_can_go_back_[nav_].yes();
+ }
+ if (item.can_go_forward == canGoForward) {
+ got_correct_can_go_forward_[nav_].yes();
+ }
+
+ load_state_change_loaded_confirmation_ = true;
+ RunNextNavIfReady(browser);
+ }
+
+ void OnLoadStart(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ TransitionType transition_type) override {
+ if (browser->IsPopup() || !frame->IsMain()) {
+ return;
+ }
+
+ const NavListItem& item = kHNavList[nav_];
+
+#if VERBOSE_DEBUGGING
+ LOG(INFO) << "browser nav=" << nav_ << " " << NavActionString(item.action)
+ << " OnLoadStart";
+#endif
+
+ EXPECT_FALSE(got_load_start_[nav_]);
+ got_load_start_[nav_].yes();
+
+ if (item.action == NA_LOAD) {
+ EXPECT_EQ(kTransitionExplicitLoad, transition_type);
+ } else if (item.action == NA_BACK || item.action == NA_FORWARD) {
+ EXPECT_EQ(kTransitionExplicitForwardBack, transition_type);
+ }
+
+ std::string url1 = browser->GetMainFrame()->GetURL();
+ std::string url2 = frame->GetURL();
+ if (url1 == item.target && url2 == item.target) {
+ got_correct_load_start_url_[nav_].yes();
+ }
+ }
+
+ void OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int httpStatusCode) override {
+ if (browser->IsPopup() || !frame->IsMain()) {
+ return;
+ }
+
+ const NavListItem& item = kHNavList[nav_];
+
+#if VERBOSE_DEBUGGING
+ LOG(INFO) << "browser nav=" << nav_ << " " << NavActionString(item.action)
+ << " OnLoadEnd";
+#endif
+
+ EXPECT_FALSE(got_load_end_[nav_]);
+ got_load_end_[nav_].yes();
+
+ // Test that navigation entries are correct.
+ CefRefPtr<NavigationEntryVisitor> visitor =
+ new NavigationEntryVisitor(nav_, &got_correct_history_[nav_]);
+ browser->GetHost()->GetNavigationEntries(visitor.get(), false);
+ visitor = nullptr;
+
+ std::string url1 = browser->GetMainFrame()->GetURL();
+ std::string url2 = frame->GetURL();
+ if (url1 == item.target && url2 == item.target) {
+ got_correct_load_end_url_[nav_].yes();
+ }
+
+ load_end_confirmation_ = true;
+ RunNextNavIfReady(browser);
+ }
+
+ bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefProcessId source_process,
+ CefRefPtr<CefProcessMessage> message) override {
+ if (message->GetName().ToString() == kHistoryNavMsg) {
+ EXPECT_FALSE(got_before_navigation_[nav_]);
+ got_before_navigation_[nav_].yes();
+
+ // Test that the renderer side succeeded.
+ CefRefPtr<CefListValue> args = message->GetArgumentList();
+ EXPECT_TRUE(args.get());
+ EXPECT_EQ(nav_, args->GetInt(0));
+ EXPECT_TRUE(args->GetBool(1));
+
+ renderer_confirmation_ = true;
+ RunNextNavIfReady(browser);
+ return true;
+ }
+
+ // Message not handled.
+ return false;
+ }
+
+ int nav_ = 0;
+ bool load_end_confirmation_ = false;
+ bool load_state_change_loaded_confirmation_ = false;
+ bool renderer_confirmation_ = false;
+
+ TrackCallback got_before_browse_[NAV_LIST_SIZE()];
+ TrackCallback got_before_navigation_[NAV_LIST_SIZE()];
+ TrackCallback got_before_resource_load_[NAV_LIST_SIZE()];
+ TrackCallback got_correct_target_[NAV_LIST_SIZE()];
+ TrackCallback got_loading_state_change_loading_[NAV_LIST_SIZE()];
+ TrackCallback got_loading_state_change_loaded_[NAV_LIST_SIZE()];
+ TrackCallback got_correct_can_go_back_[NAV_LIST_SIZE()];
+ TrackCallback got_correct_can_go_forward_[NAV_LIST_SIZE()];
+ TrackCallback got_load_start_[NAV_LIST_SIZE()];
+ TrackCallback got_correct_load_start_url_[NAV_LIST_SIZE()];
+ TrackCallback got_load_end_[NAV_LIST_SIZE()];
+ TrackCallback got_correct_history_[NAV_LIST_SIZE()];
+ TrackCallback got_correct_load_end_url_[NAV_LIST_SIZE()];
+
+ IMPLEMENT_REFCOUNTING(HistoryNavTestHandler);
+};
+
+} // namespace
+
+// Verify history navigation.
+TEST(NavigationTest, History) {
+ CefRefPtr<HistoryNavTestHandler> handler = new HistoryNavTestHandler();
+ handler->ExecuteTest();
+
+ for (size_t i = 0; i < NAV_LIST_SIZE(); ++i) {
+ if (ExpectResourceLoadEvents(kHNavList[i].action)) {
+ EXPECT_TRUE(handler->got_before_browse_[i]) << "i = " << i;
+ EXPECT_TRUE(handler->got_before_resource_load_[i]) << "i = " << i;
+ EXPECT_TRUE(handler->got_correct_target_[i]) << "i = " << i;
+ } else {
+ EXPECT_FALSE(handler->got_before_browse_[i]) << "i = " << i;
+ EXPECT_FALSE(handler->got_before_resource_load_[i]) << "i = " << i;
+ EXPECT_FALSE(handler->got_correct_target_[i]) << "i = " << i;
+ }
+
+ EXPECT_TRUE(handler->got_before_navigation_[i]) << "i = " << i;
+ EXPECT_TRUE(handler->got_load_start_[i]) << "i = " << i;
+ EXPECT_TRUE(handler->got_correct_load_start_url_[i]) << "i = " << i;
+ EXPECT_TRUE(handler->got_load_end_[i]) << "i = " << i;
+ EXPECT_TRUE(handler->got_correct_load_end_url_[i]) << "i = " << i;
+ EXPECT_TRUE(handler->got_correct_history_[i]) << "i = " << i;
+
+ EXPECT_TRUE(handler->got_loading_state_change_loading_[i]) << "i = " << i;
+ EXPECT_TRUE(handler->got_loading_state_change_loaded_[i]) << "i = " << i;
+ EXPECT_TRUE(handler->got_correct_can_go_back_[i]) << "i = " << i;
+ EXPECT_TRUE(handler->got_correct_can_go_forward_[i]) << "i = " << i;
+ }
+
+ ReleaseAndWaitForDestructor(handler);
+}
+
+namespace {
+
+const char kDynIfrNav1[] = "http://tests-dynframe/nav1.html";
+const char kDynIfrNav2[] = "http://tests-dynframe/nav2.html";
+
+// Browser side.
+class HistoryDynamicIFramesNavTestHandler : public TestHandler {
+ public:
+ HistoryDynamicIFramesNavTestHandler() : nav_(-1) {}
+
+ void RunTest() override {
+ // Add the resources that we will navigate to/from.
+ AddResource(kDynIfrNav1,
+ "<html>"
+ " <head>"
+ " <title>Nav1</title>"
+ " <script language='javascript'>"
+ " function onload() {"
+ " fr = Math.floor(Math.random() * 10);"
+ " if(fr == 0) "
+ " fr = 1;"
+ " console.log('fr=' + fr);"
+ " for(i = 1; i <= fr; i++) {"
+ " try {"
+ " var n = 'DYN_' + Math.floor(Math.random() * 10000);"
+ " "
+ " d = document.createElement('div');"
+ " d.id = 'sf' + i; "
+ " d.innerText = n; "
+ " document.body.appendChild(d); "
+ " "
+ " f = document.createElement('iframe'); "
+ " f.id = 'f_' + i; "
+ " f.name = n; "
+ " f.src = 'nav2.html'; "
+ " document.body.appendChild(f); "
+ " } catch(e) { "
+ " console.log('frame[' + i + ']: ' + e); "
+ " } "
+ " } "
+ " } "
+ " </script> "
+ " </head> "
+ " <body onload='onload();'> "
+ " Nav1 "
+ " </body> "
+ "</html>",
+ "text/html");
+ AddResource(
+ kDynIfrNav2,
+ "<html><head><title>Nav2</title></head><body>Nav2</body></html>",
+ "text/html");
+
+ // Create the browser.
+ CreateBrowser(CefString());
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout();
+ }
+
+ void RunNav(CefRefPtr<CefBrowser> browser) {
+ EXPECT_LE(nav_, 3);
+ EXPECT_FALSE(got_load_start_[nav_]);
+ EXPECT_FALSE(got_load_end_[nav_]);
+
+ if (nav_ == 0) {
+ browser->GetMainFrame()->LoadURL(kDynIfrNav1);
+ } else if (nav_ == 1) {
+ browser->GetMainFrame()->LoadURL(kDynIfrNav2);
+ } else if (nav_ == 2) {
+ browser->GoBack();
+ } else if (nav_ == 3) {
+ browser->Reload();
+ }
+ }
+
+ void OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
+ TestHandler::OnAfterCreated(browser);
+
+ nav_ = 0;
+ RunNav(browser);
+ }
+
+ void OnLoadStart(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ TransitionType transition_type) override {
+ if (!frame->IsMain()) {
+ return;
+ }
+ got_load_start_[nav_].yes();
+ }
+
+ void OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int httpStatusCode) override {
+ if (!frame->IsMain()) {
+ return;
+ }
+ CefString url = browser->GetMainFrame()->GetURL();
+ got_load_end_[nav_].yes();
+
+ if (nav_ == 3) {
+ EXPECT_STREQ(url.ToString().c_str(), kDynIfrNav1);
+ DestroyTest();
+ return;
+ }
+
+ nav_++;
+ RunNav(browser);
+ }
+
+ int nav_;
+ TrackCallback got_load_start_[4];
+ TrackCallback got_load_end_[4];
+
+ IMPLEMENT_REFCOUNTING(HistoryDynamicIFramesNavTestHandler);
+};
+
+} // namespace
+
+// Verify history navigation of pages containing dynamically created iframes.
+// See issue #2022 for background.
+TEST(NavigationTest, HistoryDynamicIFrames) {
+ CefRefPtr<HistoryDynamicIFramesNavTestHandler> handler =
+ new HistoryDynamicIFramesNavTestHandler();
+ handler->ExecuteTest();
+
+ for (int i = 0; i < 4; ++i) {
+ EXPECT_TRUE(handler->got_load_start_[i]);
+ EXPECT_TRUE(handler->got_load_end_[i]);
+ }
+
+ ReleaseAndWaitForDestructor(handler);
+}
+
+namespace {
+
+const char kRNav1[] = "http://tests/nav1.html";
+const char kRNav2[] = "http://tests/nav2.html";
+const char kRNav3[] = "http://tests/nav3.html";
+const char kRNav4[] = "http://tests/nav4.html";
+
+bool g_got_nav1_request = false;
+bool g_got_nav3_request = false;
+bool g_got_nav4_request = false;
+bool g_got_invalid_request = false;
+
+class RedirectSchemeHandler : public CefResourceHandler {
+ public:
+ RedirectSchemeHandler() : offset_(0), status_(0) {}
+
+ bool Open(CefRefPtr<CefRequest> request,
+ bool& handle_request,
+ CefRefPtr<CefCallback> callback) override {
+ EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO));
+
+ std::string url = request->GetURL();
+ if (url == kRNav1) {
+ // Redirect using HTTP 302
+ g_got_nav1_request = true;
+ status_ = 302;
+ location_ = kRNav2;
+ content_ = "<html><body>Redirected Nav1</body></html>";
+ } else if (url == kRNav3) {
+ // Redirect using redirectUrl
+ g_got_nav3_request = true;
+ status_ = -1;
+ location_ = kRNav4;
+ content_ = "<html><body>Redirected Nav3</body></html>";
+ } else if (url == kRNav4) {
+ g_got_nav4_request = true;
+ status_ = 200;
+ content_ = "<html><body>Nav4</body></html>";
+ }
+
+ handle_request = true;
+
+ if (status_ != 0) {
+ // Continue request.
+ return true;
+ }
+
+ // Cancel request.
+ g_got_invalid_request = true;
+ return false;
+ }
+
+ void GetResponseHeaders(CefRefPtr<CefResponse> response,
+ int64& response_length,
+ CefString& redirectUrl) override {
+ EXPECT_TRUE(CefCurrentlyOn(TID_IO));
+
+ EXPECT_NE(status_, 0);
+
+ response->SetStatus(status_);
+ response->SetMimeType("text/html");
+ response_length = content_.size();
+
+ if (status_ == 302) {
+ // Redirect using HTTP 302
+ EXPECT_GT(location_.size(), static_cast<size_t>(0));
+ response->SetStatusText("Found");
+ CefResponse::HeaderMap headers;
+ response->GetHeaderMap(headers);
+ headers.insert(std::make_pair("Location", location_));
+ response->SetHeaderMap(headers);
+ } else if (status_ == -1) {
+ // Rdirect using redirectUrl
+ EXPECT_GT(location_.size(), static_cast<size_t>(0));
+ redirectUrl = location_;
+ }
+ }
+
+ void Cancel() override { EXPECT_TRUE(CefCurrentlyOn(TID_IO)); }
+
+ bool Read(void* data_out,
+ int bytes_to_read,
+ int& bytes_read,
+ CefRefPtr<CefResourceReadCallback> callback) override {
+ EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO));
+
+ bytes_read = 0;
+ bool has_data = false;
+
+ size_t size = content_.size();
+ if (offset_ < size) {
+ int transfer_size =
+ std::min(bytes_to_read, static_cast<int>(size - offset_));
+ memcpy(data_out, content_.c_str() + offset_, transfer_size);
+ offset_ += transfer_size;
+
+ bytes_read = transfer_size;
+ has_data = true;
+ }
+
+ return has_data;
+ }
+
+ protected:
+ std::string content_;
+ size_t offset_;
+ int status_;
+ std::string location_;
+
+ IMPLEMENT_REFCOUNTING(RedirectSchemeHandler);
+ DISALLOW_COPY_AND_ASSIGN(RedirectSchemeHandler);
+};
+
+class RedirectSchemeHandlerFactory : public CefSchemeHandlerFactory {
+ public:
+ RedirectSchemeHandlerFactory() {
+ g_got_nav1_request = false;
+ g_got_nav3_request = false;
+ g_got_nav4_request = false;
+ g_got_invalid_request = false;
+ }
+
+ CefRefPtr<CefResourceHandler> Create(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const CefString& scheme_name,
+ CefRefPtr<CefRequest> request) override {
+ EXPECT_TRUE(CefCurrentlyOn(TID_IO));
+ return new RedirectSchemeHandler();
+ }
+
+ IMPLEMENT_REFCOUNTING(RedirectSchemeHandlerFactory);
+ DISALLOW_COPY_AND_ASSIGN(RedirectSchemeHandlerFactory);
+};
+
+class RedirectTestHandler : public TestHandler {
+ public:
+ RedirectTestHandler() {}
+
+ void RunTest() override {
+ // Create the browser.
+ CreateBrowser(kRNav1);
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout();
+ }
+
+ cef_return_value_t OnBeforeResourceLoad(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefCallback> callback) override {
+ if (IsChromeRuntimeEnabled() && request->GetResourceType() == RT_FAVICON) {
+ // Ignore favicon requests.
+ return RV_CANCEL;
+ }
+
+ // Should be called for all but the second URL.
+ std::string url = request->GetURL();
+
+ EXPECT_EQ(RT_MAIN_FRAME, request->GetResourceType());
+ EXPECT_EQ(kTransitionExplicitLoad, request->GetTransitionType());
+
+ if (url == kRNav1) {
+ got_nav1_before_resource_load_.yes();
+ } else if (url == kRNav3) {
+ got_nav3_before_resource_load_.yes();
+ } else if (url == kRNav4) {
+ got_nav4_before_resource_load_.yes();
+ } else {
+ got_invalid_before_resource_load_.yes();
+ }
+
+ return RV_CONTINUE;
+ }
+
+ void OnResourceRedirect(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response,
+ CefString& new_url) override {
+ // Should be called for each redirected URL.
+
+ const std::string& old_url = request->GetURL();
+ if (old_url == kRNav1 && new_url == kRNav2) {
+ // Called due to the nav1 redirect response.
+ got_nav1_redirect_.yes();
+
+ EXPECT_EQ(302, response->GetStatus());
+ EXPECT_STREQ("Found", response->GetStatusText().ToString().c_str());
+ EXPECT_STREQ("", response->GetMimeType().ToString().c_str());
+ EXPECT_STREQ(kRNav2,
+ response->GetHeaderByName("Location").ToString().c_str());
+
+ // Change the redirect to the 3rd URL.
+ new_url = kRNav3;
+ } else if (old_url == kRNav1 && new_url == kRNav3) {
+ // Called due to the redirect change above.
+ got_nav2_redirect_.yes();
+
+ EXPECT_EQ(307, response->GetStatus());
+ EXPECT_STREQ("Internal Redirect",
+ response->GetStatusText().ToString().c_str());
+ EXPECT_TRUE(response->GetMimeType().empty());
+ EXPECT_STREQ(kRNav3,
+ response->GetHeaderByName("Location").ToString().c_str());
+ } else if (old_url == kRNav3 && new_url == kRNav4) {
+ // Called due to the nav3 redirect response.
+ got_nav3_redirect_.yes();
+
+ EXPECT_EQ(307, response->GetStatus());
+ EXPECT_STREQ("Temporary Redirect",
+ response->GetStatusText().ToString().c_str());
+ EXPECT_STREQ("", response->GetMimeType().ToString().c_str());
+ } else {
+ got_invalid_redirect_.yes();
+ }
+ }
+
+ void OnLoadStart(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ TransitionType transition_type) override {
+ // Should only be called for the final loaded URL.
+ std::string url = frame->GetURL();
+
+ EXPECT_EQ(kTransitionExplicitLoad, transition_type);
+
+ if (url == kRNav4) {
+ got_nav4_load_start_.yes();
+ } else {
+ got_invalid_load_start_.yes();
+ }
+ }
+
+ void OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int httpStatusCode) override {
+ // Should only be called for the final loaded URL.
+ std::string url = frame->GetURL();
+
+ if (url == kRNav4) {
+ got_nav4_load_end_.yes();
+ DestroyTest();
+ } else {
+ got_invalid_load_end_.yes();
+ }
+ }
+
+ TrackCallback got_nav1_before_resource_load_;
+ TrackCallback got_nav3_before_resource_load_;
+ TrackCallback got_nav4_before_resource_load_;
+ TrackCallback got_invalid_before_resource_load_;
+ TrackCallback got_nav4_load_start_;
+ TrackCallback got_invalid_load_start_;
+ TrackCallback got_nav4_load_end_;
+ TrackCallback got_invalid_load_end_;
+ TrackCallback got_nav1_redirect_;
+ TrackCallback got_nav2_redirect_;
+ TrackCallback got_nav3_redirect_;
+ TrackCallback got_invalid_redirect_;
+
+ IMPLEMENT_REFCOUNTING(RedirectTestHandler);
+};
+
+// Like above but destroy the WebContents while the redirect is in-progress.
+class RedirectDestroyTestHandler : public TestHandler {
+ public:
+ RedirectDestroyTestHandler() {}
+
+ void RunTest() override {
+ // Create the browser.
+ CreateBrowser(kRNav1);
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout();
+ }
+
+ void OnResourceRedirect(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response,
+ CefString& new_url) override {
+ const std::string& old_url = request->GetURL();
+ if (old_url == kRNav1 && new_url == kRNav2) {
+ // Called due to the nav1 redirect response.
+ got_nav1_redirect_.yes();
+
+ new_url = "about:blank";
+
+ // Destroy the test (and the underlying WebContents) while the redirect
+ // is still pending.
+ DestroyTest();
+ }
+ }
+
+ TrackCallback got_nav1_redirect_;
+
+ IMPLEMENT_REFCOUNTING(RedirectDestroyTestHandler);
+};
+
+} // namespace
+
+// Verify frame names and identifiers.
+TEST(NavigationTest, Redirect) {
+ CefRegisterSchemeHandlerFactory("http", "tests",
+ new RedirectSchemeHandlerFactory());
+ WaitForIOThread();
+
+ CefRefPtr<RedirectTestHandler> handler = new RedirectTestHandler();
+ handler->ExecuteTest();
+
+ CefClearSchemeHandlerFactories();
+ WaitForIOThread();
+
+ EXPECT_TRUE(handler->got_nav1_before_resource_load_);
+ EXPECT_TRUE(handler->got_nav3_before_resource_load_);
+ EXPECT_TRUE(handler->got_nav4_before_resource_load_);
+ EXPECT_FALSE(handler->got_invalid_before_resource_load_);
+ EXPECT_TRUE(handler->got_nav4_load_start_);
+ EXPECT_FALSE(handler->got_invalid_load_start_);
+ EXPECT_TRUE(handler->got_nav4_load_end_);
+ EXPECT_FALSE(handler->got_invalid_load_end_);
+ EXPECT_TRUE(handler->got_nav1_redirect_);
+ EXPECT_FALSE(handler->got_nav2_redirect_);
+ EXPECT_TRUE(handler->got_nav3_redirect_);
+ EXPECT_FALSE(handler->got_invalid_redirect_);
+ EXPECT_TRUE(g_got_nav1_request);
+ EXPECT_TRUE(g_got_nav3_request);
+ EXPECT_TRUE(g_got_nav4_request);
+ EXPECT_FALSE(g_got_invalid_request);
+
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Verify that destroying the WebContents while the redirect is in-progress does
+// not result in a crash.
+TEST(NavigationTest, RedirectDestroy) {
+ CefRegisterSchemeHandlerFactory("http", "tests",
+ new RedirectSchemeHandlerFactory());
+ WaitForIOThread();
+
+ CefRefPtr<RedirectDestroyTestHandler> handler =
+ new RedirectDestroyTestHandler();
+ handler->ExecuteTest();
+
+ CefClearSchemeHandlerFactories();
+ WaitForIOThread();
+
+ EXPECT_TRUE(handler->got_nav1_redirect_);
+ EXPECT_TRUE(g_got_nav1_request);
+ EXPECT_FALSE(g_got_nav3_request);
+ EXPECT_FALSE(g_got_nav4_request);
+ EXPECT_FALSE(g_got_invalid_request);
+
+ ReleaseAndWaitForDestructor(handler);
+}
+
+namespace {
+
+const char KONav1[] = "http://tests-onav.com/nav1.html";
+const char KONav2[] = "http://tests-onav.com/nav2.html";
+const char kOrderNavMsg[] = "NavigationTest.OrderNav";
+const char kOrderNavClosedMsg[] = "NavigationTest.OrderNavClosed";
+const char kOrderNavTestCmdKey[] = "nav-order-test";
+
+class OrderNavLoadState {
+ public:
+ OrderNavLoadState(bool is_popup, bool browser_side)
+ : is_popup_(is_popup), browser_side_(browser_side) {}
+
+ void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
+ bool isLoading,
+ bool canGoBack,
+ bool canGoForward) {
+ if (isLoading) {
+ EXPECT_TRUE(Verify(false, false, false, false));
+
+ got_loading_state_start_.yes();
+ } else {
+ EXPECT_TRUE(Verify(true, false, true, true));
+
+ got_loading_state_end_.yes();
+ }
+ }
+
+ void OnLoadStart(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame) {
+ EXPECT_TRUE(Verify(true, false, false, false));
+
+ got_load_start_.yes();
+ }
+
+ void OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int httpStatusCode) {
+ EXPECT_TRUE(Verify(true, false, true, false));
+
+ got_load_end_.yes();
+ }
+
+ bool IsStarted() const {
+ return got_loading_state_start_ || got_loading_state_end_ ||
+ got_load_start_ || got_load_end_;
+ }
+
+ bool IsDone() const {
+ return got_loading_state_start_ && got_loading_state_end_ &&
+ got_load_start_ && got_load_end_;
+ }
+
+ bool Verify(bool got_loading_state_start,
+ bool got_loading_state_end,
+ bool got_load_start,
+ bool got_load_end) const {
+ EXPECT_EQ(got_loading_state_start, got_loading_state_start_)
+ << "Popup: " << is_popup_ << "; Browser Side: " << browser_side_;
+ EXPECT_EQ(got_loading_state_end, got_loading_state_end_)
+ << "Popup: " << is_popup_ << "; Browser Side: " << browser_side_;
+ EXPECT_EQ(got_load_start, got_load_start_)
+ << "Popup: " << is_popup_ << "; Browser Side: " << browser_side_;
+ EXPECT_EQ(got_load_end, got_load_end_)
+ << "Popup: " << is_popup_ << "; Browser Side: " << browser_side_;
+
+ return got_loading_state_start == got_loading_state_start_ &&
+ got_loading_state_end == got_loading_state_end_ &&
+ got_load_start == got_load_start_ && got_load_end == got_load_end_;
+ }
+
+ private:
+ bool is_popup_;
+ bool browser_side_;
+
+ TrackCallback got_loading_state_start_;
+ TrackCallback got_loading_state_end_;
+ TrackCallback got_load_start_;
+ TrackCallback got_load_end_;
+};
+
+// Renderer side.
+class OrderNavRendererTest : public ClientAppRenderer::Delegate,
+ public CefLoadHandler {
+ public:
+ OrderNavRendererTest()
+ : run_test_(false),
+ browser_id_main_(0),
+ browser_id_popup_(0),
+ state_main_(false, false),
+ state_popup_(true, false) {}
+
+ void OnWebKitInitialized(CefRefPtr<ClientAppRenderer> app) override {
+ EXPECT_FALSE(got_webkit_initialized_);
+
+ got_webkit_initialized_.yes();
+ }
+
+ void OnBrowserCreated(CefRefPtr<ClientAppRenderer> app,
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefDictionaryValue> extra_info) override {
+ run_test_ = extra_info && extra_info->HasKey(kOrderNavTestCmdKey);
+ if (!run_test_) {
+ return;
+ }
+
+ EXPECT_TRUE(got_webkit_initialized_);
+
+ if (browser->IsPopup()) {
+ EXPECT_FALSE(got_browser_created_popup_);
+ EXPECT_FALSE(got_browser_destroyed_popup_);
+ EXPECT_FALSE(state_popup_.IsStarted());
+
+ got_browser_created_popup_.yes();
+ browser_id_popup_ = browser->GetIdentifier();
+ EXPECT_GT(browser->GetIdentifier(), 0);
+ } else {
+ EXPECT_FALSE(got_browser_created_main_);
+ EXPECT_FALSE(got_browser_destroyed_main_);
+ EXPECT_FALSE(state_main_.IsStarted());
+
+ got_browser_created_main_.yes();
+ browser_id_main_ = browser->GetIdentifier();
+ EXPECT_GT(browser->GetIdentifier(), 0);
+
+ browser_main_ = browser;
+ }
+ }
+
+ void OnBrowserDestroyed(CefRefPtr<ClientAppRenderer> app,
+ CefRefPtr<CefBrowser> browser) override {
+ if (!run_test_) {
+ return;
+ }
+
+ EXPECT_TRUE(got_webkit_initialized_);
+
+ if (browser->IsPopup()) {
+ EXPECT_TRUE(got_browser_created_popup_);
+ EXPECT_FALSE(got_browser_destroyed_popup_);
+ EXPECT_TRUE(state_popup_.IsDone());
+
+ got_browser_destroyed_popup_.yes();
+ EXPECT_EQ(browser_id_popup_, browser->GetIdentifier());
+ EXPECT_GT(browser->GetIdentifier(), 0);
+
+ // Use |browser_main_| to send the message otherwise it will fail.
+ SendTestResults(browser_main_, browser_main_->GetMainFrame(),
+ kOrderNavClosedMsg);
+ } else {
+ EXPECT_TRUE(got_browser_created_main_);
+ EXPECT_FALSE(got_browser_destroyed_main_);
+ EXPECT_TRUE(state_main_.IsDone());
+
+ got_browser_destroyed_main_.yes();
+ EXPECT_EQ(browser_id_main_, browser->GetIdentifier());
+ EXPECT_GT(browser->GetIdentifier(), 0);
+
+ browser_main_ = nullptr;
+ }
+ }
+
+ CefRefPtr<CefLoadHandler> GetLoadHandler(
+ CefRefPtr<ClientAppRenderer> app) override {
+ if (!run_test_) {
+ return nullptr;
+ }
+
+ return this;
+ }
+
+ void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
+ bool isLoading,
+ bool canGoBack,
+ bool canGoForward) override {
+ EXPECT_TRUE(got_webkit_initialized_);
+
+ if (browser->IsPopup()) {
+ EXPECT_TRUE(got_browser_created_popup_);
+ EXPECT_FALSE(got_browser_destroyed_popup_);
+
+ state_popup_.OnLoadingStateChange(browser, isLoading, canGoBack,
+ canGoForward);
+ } else {
+ EXPECT_TRUE(got_browser_created_main_);
+ EXPECT_FALSE(got_browser_destroyed_main_);
+
+ state_main_.OnLoadingStateChange(browser, isLoading, canGoBack,
+ canGoForward);
+ }
+
+ if (!isLoading) {
+ SendTestResultsIfDone(browser, browser->GetMainFrame());
+ }
+ }
+
+ void OnLoadStart(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ TransitionType transition_type) override {
+ EXPECT_TRUE(got_webkit_initialized_);
+
+ if (browser->IsPopup()) {
+ EXPECT_TRUE(got_browser_created_popup_);
+ EXPECT_FALSE(got_browser_destroyed_popup_);
+
+ state_popup_.OnLoadStart(browser, frame);
+ } else {
+ EXPECT_TRUE(got_browser_created_main_);
+ EXPECT_FALSE(got_browser_destroyed_main_);
+
+ state_main_.OnLoadStart(browser, frame);
+ }
+ }
+
+ void OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int httpStatusCode) override {
+ EXPECT_TRUE(got_webkit_initialized_);
+
+ if (browser->IsPopup()) {
+ EXPECT_TRUE(got_browser_created_popup_);
+ EXPECT_FALSE(got_browser_destroyed_popup_);
+
+ state_popup_.OnLoadEnd(browser, frame, httpStatusCode);
+ } else {
+ EXPECT_TRUE(got_browser_created_main_);
+ EXPECT_FALSE(got_browser_destroyed_main_);
+
+ state_main_.OnLoadEnd(browser, frame, httpStatusCode);
+ }
+
+ SendTestResultsIfDone(browser, frame);
+ }
+
+ void OnLoadError(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ ErrorCode errorCode,
+ const CefString& errorText,
+ const CefString& failedUrl) override {
+ ADD_FAILURE() << "renderer OnLoadError url: " << failedUrl.ToString()
+ << " error: " << errorCode;
+ }
+
+ protected:
+ void SendTestResultsIfDone(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) {
+ bool done = false;
+ if (browser->IsPopup()) {
+ done = state_popup_.IsDone();
+ } else {
+ done = state_main_.IsDone();
+ }
+
+ if (done) {
+ SendTestResults(browser, frame, kOrderNavMsg);
+ }
+ }
+
+ // Send the test results.
+ void SendTestResults(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const char* msg_name) {
+ // Check if the test has failed.
+ bool result = !TestFailed();
+
+ // Return the result to the browser process.
+ CefRefPtr<CefProcessMessage> return_msg =
+ CefProcessMessage::Create(msg_name);
+ CefRefPtr<CefListValue> args = return_msg->GetArgumentList();
+ EXPECT_TRUE(args.get());
+ EXPECT_TRUE(args->SetBool(0, result));
+ if (browser->IsPopup()) {
+ EXPECT_TRUE(args->SetInt(1, browser_id_popup_));
+ } else {
+ EXPECT_TRUE(args->SetInt(1, browser_id_main_));
+ }
+ frame->SendProcessMessage(PID_BROWSER, return_msg);
+ }
+
+ bool run_test_;
+
+ int browser_id_main_;
+ int browser_id_popup_;
+ CefRefPtr<CefBrowser> browser_main_;
+ TrackCallback got_webkit_initialized_;
+ TrackCallback got_browser_created_main_;
+ TrackCallback got_browser_destroyed_main_;
+ TrackCallback got_browser_created_popup_;
+ TrackCallback got_browser_destroyed_popup_;
+
+ OrderNavLoadState state_main_;
+ OrderNavLoadState state_popup_;
+
+ IMPLEMENT_REFCOUNTING(OrderNavRendererTest);
+};
+
+// Browser side.
+class OrderNavTestHandler : public TestHandler {
+ public:
+ OrderNavTestHandler()
+ : browser_id_main_(0),
+ browser_id_popup_(0),
+ state_main_(false, true),
+ state_popup_(true, true),
+ got_message_(false) {}
+
+ // Returns state that will be checked in the renderer process via
+ // OrderNavRendererTest::OnBrowserCreated.
+ CefRefPtr<CefDictionaryValue> GetExtraInfo() {
+ CefRefPtr<CefDictionaryValue> extra_info = CefDictionaryValue::Create();
+ extra_info->SetBool(kOrderNavTestCmdKey, true);
+ return extra_info;
+ }
+
+ void RunTest() override {
+ // Add the resources that we will navigate to/from.
+ AddResource(KONav1, "<html>Nav1</html>", "text/html");
+ AddResource(KONav2, "<html>Nav2</html>", "text/html");
+
+ // Create the browser.
+ CreateBrowser(KONav1, nullptr, GetExtraInfo());
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout();
+ }
+
+ void ContinueIfReady(CefRefPtr<CefBrowser> browser) {
+ if (!got_message_) {
+ return;
+ }
+
+ bool done = false;
+ if (browser->IsPopup()) {
+ done = state_popup_.IsDone();
+ } else {
+ done = state_main_.IsDone();
+ }
+ if (!done) {
+ return;
+ }
+
+ got_message_ = false;
+
+ if (!browser->IsPopup()) {
+ // Create the popup window.
+ browser->GetMainFrame()->ExecuteJavaScript(
+ "window.open('" + std::string(KONav2) + "');", CefString(), 0);
+ } else {
+ // Close the popup window.
+ CloseBrowser(browser_popup_, false);
+ }
+ }
+
+ bool OnBeforePopup(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const CefString& target_url,
+ const CefString& target_frame_name,
+ CefLifeSpanHandler::WindowOpenDisposition target_disposition,
+ bool user_gesture,
+ const CefPopupFeatures& popupFeatures,
+ CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient>& client,
+ CefBrowserSettings& settings,
+ CefRefPtr<CefDictionaryValue>& extra_info,
+ bool* no_javascript_access) override {
+ extra_info = GetExtraInfo();
+ return false;
+ }
+
+ void OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
+ TestHandler::OnAfterCreated(browser);
+
+ if (browser->IsPopup()) {
+ browser_id_popup_ = browser->GetIdentifier();
+ EXPECT_GT(browser_id_popup_, 0);
+ browser_popup_ = browser;
+ } else {
+ browser_id_main_ = browser->GetIdentifier();
+ EXPECT_GT(browser_id_main_, 0);
+ }
+ }
+
+ bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ bool user_gesture,
+ bool is_redirect) override {
+ EXPECT_EQ(RT_MAIN_FRAME, request->GetResourceType());
+
+ if (browser->IsPopup()) {
+ EXPECT_EQ(TT_LINK, request->GetTransitionType());
+ EXPECT_GT(browser->GetIdentifier(), 0);
+ EXPECT_EQ(browser_id_popup_, browser->GetIdentifier());
+ got_before_browse_popup_.yes();
+ } else {
+ EXPECT_EQ(kTransitionExplicitLoad, request->GetTransitionType());
+ EXPECT_GT(browser->GetIdentifier(), 0);
+ EXPECT_EQ(browser_id_main_, browser->GetIdentifier());
+ got_before_browse_main_.yes();
+ }
+
+ std::string url = request->GetURL();
+ if (url == KONav1) {
+ EXPECT_FALSE(browser->IsPopup());
+ } else if (url == KONav2) {
+ EXPECT_TRUE(browser->IsPopup());
+ } else {
+ EXPECT_TRUE(false); // not reached
+ }
+
+ return false;
+ }
+
+ cef_return_value_t OnBeforeResourceLoad(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefCallback> callback) override {
+ if (IsChromeRuntimeEnabled() && request->GetResourceType() == RT_FAVICON) {
+ // Ignore favicon requests.
+ return RV_CANCEL;
+ }
+
+ EXPECT_EQ(RT_MAIN_FRAME, request->GetResourceType());
+
+ if (browser->IsPopup()) {
+ EXPECT_EQ(TT_LINK, request->GetTransitionType());
+ EXPECT_GT(browser->GetIdentifier(), 0);
+ EXPECT_EQ(browser_id_popup_, browser->GetIdentifier());
+ } else {
+ EXPECT_EQ(kTransitionExplicitLoad, request->GetTransitionType());
+ EXPECT_GT(browser->GetIdentifier(), 0);
+ EXPECT_EQ(browser_id_main_, browser->GetIdentifier());
+ }
+
+ return RV_CONTINUE;
+ }
+
+ void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
+ bool isLoading,
+ bool canGoBack,
+ bool canGoForward) override {
+ if (browser->IsPopup()) {
+ state_popup_.OnLoadingStateChange(browser, isLoading, canGoBack,
+ canGoForward);
+ } else {
+ state_main_.OnLoadingStateChange(browser, isLoading, canGoBack,
+ canGoForward);
+ }
+
+ if (!isLoading) {
+ ContinueIfReady(browser);
+ }
+ }
+
+ void OnLoadStart(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ TransitionType transition_type) override {
+ if (browser->IsPopup()) {
+ EXPECT_EQ(TT_LINK, transition_type);
+ state_popup_.OnLoadStart(browser, frame);
+ } else {
+ EXPECT_EQ(kTransitionExplicitLoad, transition_type);
+ state_main_.OnLoadStart(browser, frame);
+ }
+ }
+
+ void OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int httpStatusCode) override {
+ if (browser->IsPopup()) {
+ state_popup_.OnLoadEnd(browser, frame, httpStatusCode);
+ } else {
+ state_main_.OnLoadEnd(browser, frame, httpStatusCode);
+ }
+
+ ContinueIfReady(browser);
+ }
+
+ void OnLoadError(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ ErrorCode errorCode,
+ const CefString& errorText,
+ const CefString& failedUrl) override {
+ ADD_FAILURE() << "browser OnLoadError url: " << failedUrl.ToString()
+ << " error: " << errorCode;
+ }
+
+ bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefProcessId source_process,
+ CefRefPtr<CefProcessMessage> message) override {
+ if (browser->IsPopup()) {
+ EXPECT_GT(browser->GetIdentifier(), 0);
+ EXPECT_EQ(browser_id_popup_, browser->GetIdentifier());
+ } else {
+ EXPECT_GT(browser->GetIdentifier(), 0);
+ EXPECT_EQ(browser_id_main_, browser->GetIdentifier());
+ }
+
+ const std::string& msg_name = message->GetName();
+ if (msg_name == kOrderNavMsg || msg_name == kOrderNavClosedMsg) {
+ // Test that the renderer side succeeded.
+ CefRefPtr<CefListValue> args = message->GetArgumentList();
+ EXPECT_TRUE(args.get());
+ EXPECT_TRUE(args->GetBool(0));
+
+ if (browser->IsPopup()) {
+ EXPECT_EQ(browser_id_popup_, args->GetInt(1));
+ } else {
+ EXPECT_EQ(browser_id_main_, args->GetInt(1));
+ }
+
+ if (msg_name == kOrderNavMsg) {
+ // Continue with the test.
+ got_message_ = true;
+ ContinueIfReady(browser);
+ } else {
+ // Popup was closed. End the test.
+ browser_popup_ = nullptr;
+ DestroyTest();
+ }
+
+ return true;
+ }
+
+ // Message not handled.
+ return false;
+ }
+
+ protected:
+ void DestroyTest() override {
+ // Verify test expectations.
+ EXPECT_TRUE(got_before_browse_main_);
+ EXPECT_TRUE(got_before_browse_popup_);
+
+ EXPECT_TRUE(state_main_.Verify(true, true, true, true));
+ EXPECT_TRUE(state_popup_.Verify(true, true, true, true));
+
+ TestHandler::DestroyTest();
+ }
+
+ int browser_id_main_;
+ int browser_id_popup_;
+ CefRefPtr<CefBrowser> browser_popup_;
+
+ TrackCallback got_before_browse_main_;
+ TrackCallback got_before_browse_popup_;
+
+ OrderNavLoadState state_main_;
+ OrderNavLoadState state_popup_;
+
+ bool got_message_;
+
+ IMPLEMENT_REFCOUNTING(OrderNavTestHandler);
+};
+
+} // namespace
+
+// Verify the order of navigation-related callbacks.
+TEST(NavigationTest, Order) {
+ CefRefPtr<OrderNavTestHandler> handler = new OrderNavTestHandler();
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+namespace {
+
+const char kLoadNav1[] = "http://tests-conav1.com/nav1.html";
+const char kLoadNavSameOrigin2[] = "http://tests-conav1.com/nav2.html";
+const char kLoadNavCrossOrigin2[] = "http://tests-conav2.com/nav2.html";
+const char kLoadNavMsg[] = "NavigationTest.LoadNav";
+const char kLoadNavTestCmdKey[] = "nav-load-test";
+
+// Renderer side.
+class LoadNavRendererTest : public ClientAppRenderer::Delegate,
+ public CefLoadHandler {
+ public:
+ LoadNavRendererTest() = default;
+
+ void OnBrowserCreated(CefRefPtr<ClientAppRenderer> app,
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefDictionaryValue> extra_info) override {
+ run_test_ = extra_info && extra_info->HasKey(kLoadNavTestCmdKey);
+ if (!run_test_) {
+ return;
+ }
+
+ // We'll get multiple calls to OnBrowserCreated for same-site navigations
+ // with same-site BFCache enabled.
+ const int new_browser_id = browser->GetIdentifier();
+ if (browser_id_ != 0) {
+ EXPECT_EQ(browser_id_, new_browser_id);
+ } else {
+ browser_id_ = new_browser_id;
+ EXPECT_GT(browser_id_, 0);
+ }
+ browser_created_ct_++;
+ }
+
+ void OnBrowserDestroyed(CefRefPtr<ClientAppRenderer> app,
+ CefRefPtr<CefBrowser> browser) override {
+ if (!run_test_) {
+ return;
+ }
+
+ EXPECT_GT(load_ct_, 0);
+ EXPECT_GT(browser_created_ct_, 0);
+ EXPECT_EQ(browser_id_, browser->GetIdentifier());
+ }
+
+ CefRefPtr<CefLoadHandler> GetLoadHandler(
+ CefRefPtr<ClientAppRenderer> app) override {
+ if (!run_test_) {
+ return nullptr;
+ }
+
+ return this;
+ }
+
+ void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
+ bool isLoading,
+ bool canGoBack,
+ bool canGoForward) override {
+ if (!isLoading) {
+ EXPECT_GT(browser_created_ct_, 0);
+ EXPECT_EQ(browser_id_, browser->GetIdentifier());
+
+ load_ct_++;
+ SendTestResults(browser, browser->GetMainFrame());
+ }
+ }
+
+ protected:
+ // Send the test results.
+ void SendTestResults(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) {
+ // Check if the test has failed.
+ bool result = !TestFailed();
+
+ // Return the result to the browser process.
+ CefRefPtr<CefProcessMessage> return_msg =
+ CefProcessMessage::Create(kLoadNavMsg);
+ CefRefPtr<CefListValue> args = return_msg->GetArgumentList();
+ EXPECT_TRUE(args.get());
+ EXPECT_TRUE(args->SetBool(0, result));
+ EXPECT_TRUE(args->SetInt(1, browser->GetIdentifier()));
+ EXPECT_TRUE(args->SetInt(2, browser_created_ct_));
+ EXPECT_TRUE(args->SetInt(3, load_ct_));
+ frame->SendProcessMessage(PID_BROWSER, return_msg);
+ }
+
+ bool run_test_ = false;
+
+ int browser_id_ = 0;
+ int load_ct_ = 0;
+ int browser_created_ct_ = 0;
+
+ IMPLEMENT_REFCOUNTING(LoadNavRendererTest);
+};
+
+// Browser side.
+class LoadNavTestHandler : public TestHandler {
+ public:
+ enum TestMode {
+ LOAD,
+ LEFT_CLICK,
+ MIDDLE_CLICK,
+ CTRL_LEFT_CLICK,
+ };
+
+ LoadNavTestHandler(TestMode mode,
+ bool same_origin,
+ bool cancel_in_open_url = false)
+ : mode_(mode),
+ same_origin_(same_origin),
+ cancel_in_open_url_(cancel_in_open_url) {}
+
+ std::string GetURL2() const {
+ return same_origin_ ? kLoadNavSameOrigin2 : kLoadNavCrossOrigin2;
+ }
+
+ bool ExpectOpenURL() const {
+ return mode_ == MIDDLE_CLICK || mode_ == CTRL_LEFT_CLICK;
+ }
+
+ void RunTest() override {
+ const std::string& url2 = GetURL2();
+ std::string link;
+ if (mode_ != LOAD) {
+ link = "<a href=\"" + url2 + "\">CLICK ME</a>";
+ }
+
+ // Add the resources that we will navigate to/from.
+ AddResource(kLoadNav1,
+ "<html><body><h1>" + link + "Nav1</h1></body></html>",
+ "text/html");
+ AddResource(url2, "<html>Nav2</html>", "text/html");
+
+ CefRefPtr<CefDictionaryValue> extra_info = CefDictionaryValue::Create();
+ extra_info->SetBool(kLoadNavTestCmdKey, true);
+
+ // Create the browser.
+ CreateBrowser(kLoadNav1, nullptr, extra_info);
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout();
+ }
+
+ void ContinueIfReady(CefRefPtr<CefBrowser> browser) {
+ if (!got_message_ || !got_load_end_) {
+ return;
+ }
+
+ std::string url = browser->GetMainFrame()->GetURL();
+ if (url == kLoadNav1) {
+ // Verify the behavior of the previous load.
+ EXPECT_TRUE(got_before_browse_);
+ EXPECT_TRUE(got_before_resource_load_);
+ EXPECT_TRUE(got_load_start_);
+ EXPECT_TRUE(got_load_end_);
+ EXPECT_FALSE(got_open_url_from_tab_);
+
+ got_before_browse_.reset();
+ got_before_resource_load_.reset();
+ got_load_start_.reset();
+ got_load_end_.reset();
+ got_message_.reset();
+
+ EXPECT_EQ(1, renderer_load_ct_);
+
+ // Load the next url.
+ if (mode_ == LOAD) {
+ browser->GetMainFrame()->LoadURL(GetURL2());
+ } else {
+ // Navigate to the URL by clicking a link.
+ CefMouseEvent mouse_event;
+ mouse_event.x = 20;
+ mouse_event.y = 20;
+#if defined(OS_MAC)
+ // Use cmd instead of ctrl on OS X.
+ mouse_event.modifiers =
+ (mode_ == CTRL_LEFT_CLICK ? EVENTFLAG_COMMAND_DOWN : 0);
+#else
+ mouse_event.modifiers =
+ (mode_ == CTRL_LEFT_CLICK ? EVENTFLAG_CONTROL_DOWN : 0);
+#endif
+
+ cef_mouse_button_type_t button_type =
+ (mode_ == MIDDLE_CLICK ? MBT_MIDDLE : MBT_LEFT);
+ SendMouseClickEvent(browser, mouse_event, button_type);
+ }
+
+ if (cancel_in_open_url_) {
+ // The next navigation should not occur. Therefore call DestroyTest()
+ // after a reasonable timeout.
+ CefPostDelayedTask(
+ TID_UI, base::BindOnce(&LoadNavTestHandler::DestroyTest, this),
+ 500);
+ }
+ } else {
+ // Done with the test.
+ DestroyTest();
+ }
+ }
+
+ void OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
+ TestHandler::OnAfterCreated(browser);
+
+ EXPECT_EQ(browser_id_current_, 0);
+ browser_id_current_ = browser->GetIdentifier();
+ EXPECT_GT(browser_id_current_, 0);
+ }
+
+ cef_transition_type_t ExpectedOpenURLTransitionType() const {
+ if (mode_ != LEFT_CLICK && IsChromeRuntimeEnabled()) {
+ // Because we triggered the navigation with LoadURL in OnOpenURLFromTab.
+ return kTransitionExplicitLoad;
+ }
+ return TT_LINK;
+ }
+
+ bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ bool user_gesture,
+ bool is_redirect) override {
+ EXPECT_EQ(RT_MAIN_FRAME, request->GetResourceType());
+ if (mode_ == LOAD || request->GetURL() == kLoadNav1) {
+ EXPECT_EQ(kTransitionExplicitLoad, request->GetTransitionType());
+ if (IsChromeRuntimeEnabled()) {
+ // With the Chrome runtime this is true on initial navigation via
+ // chrome::AddTabAt() and also true for clicked links.
+ EXPECT_TRUE(user_gesture);
+ } else {
+ EXPECT_FALSE(user_gesture);
+ }
+ } else {
+ EXPECT_EQ(ExpectedOpenURLTransitionType(), request->GetTransitionType());
+
+ if (mode_ == LEFT_CLICK || IsChromeRuntimeEnabled()) {
+ EXPECT_TRUE(user_gesture);
+ } else {
+ EXPECT_FALSE(user_gesture);
+ }
+ }
+
+ EXPECT_GT(browser_id_current_, 0);
+ EXPECT_EQ(browser_id_current_, browser->GetIdentifier());
+
+ if (ExpectOpenURL() && request->GetURL() == GetURL2()) {
+ // OnOpenURLFromTab should be called first for the file URL navigation.
+ EXPECT_TRUE(got_open_url_from_tab_);
+ } else {
+ EXPECT_FALSE(got_open_url_from_tab_);
+ }
+
+ got_before_browse_.yes();
+
+ return false;
+ }
+
+ bool OnOpenURLFromTab(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const CefString& target_url,
+ cef_window_open_disposition_t target_disposition,
+ bool user_gesture) override {
+ EXPECT_TRUE(CefCurrentlyOn(TID_UI));
+
+ EXPECT_GT(browser_id_current_, 0);
+ EXPECT_EQ(browser_id_current_, browser->GetIdentifier());
+
+ // OnOpenURLFromTab should only be called for the file URL.
+ EXPECT_STREQ(GetURL2().c_str(), target_url.ToString().c_str());
+
+ if (mode_ == LOAD) {
+ EXPECT_FALSE(user_gesture);
+ } else {
+ EXPECT_TRUE(user_gesture);
+ }
+
+ EXPECT_EQ(WOD_NEW_BACKGROUND_TAB, target_disposition);
+
+ // OnOpenURLFromTab should be called before OnBeforeBrowse for the file URL.
+ EXPECT_FALSE(got_before_browse_);
+
+ got_open_url_from_tab_.yes();
+
+ if (!cancel_in_open_url_ && IsChromeRuntimeEnabled()) {
+ // The chrome runtime may create a new popup window, which is not the
+ // behavior that this test expects. Instead, match the alloy runtime
+ // behavior by navigating in the current window.
+ browser->GetMainFrame()->LoadURL(target_url);
+ return true;
+ }
+
+ return cancel_in_open_url_;
+ }
+
+ cef_return_value_t OnBeforeResourceLoad(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefCallback> callback) override {
+ if (IsChromeRuntimeEnabled() && request->GetResourceType() == RT_FAVICON) {
+ // Ignore favicon requests.
+ return RV_CANCEL;
+ }
+
+ EXPECT_EQ(RT_MAIN_FRAME, request->GetResourceType());
+
+ const auto transition_type = request->GetTransitionType();
+ if (mode_ == LOAD || request->GetURL() == kLoadNav1) {
+ EXPECT_EQ(kTransitionExplicitLoad, transition_type);
+ } else {
+ EXPECT_EQ(ExpectedOpenURLTransitionType(), transition_type);
+ }
+
+ EXPECT_GT(browser_id_current_, 0);
+ EXPECT_EQ(browser_id_current_, browser->GetIdentifier());
+
+ got_before_resource_load_.yes();
+
+ return RV_CONTINUE;
+ }
+
+ void OnLoadStart(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ TransitionType transition_type) override {
+ EXPECT_GT(browser_id_current_, 0);
+ EXPECT_EQ(browser_id_current_, browser->GetIdentifier());
+
+ if (mode_ == LOAD || frame->GetURL() == kLoadNav1) {
+ EXPECT_EQ(kTransitionExplicitLoad, transition_type);
+ } else {
+ EXPECT_EQ(ExpectedOpenURLTransitionType(), transition_type);
+ }
+
+ got_load_start_.yes();
+ }
+
+ void OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int httpStatusCode) override {
+ EXPECT_GT(browser_id_current_, 0);
+ EXPECT_EQ(browser_id_current_, browser->GetIdentifier());
+
+ got_load_end_.yes();
+ ContinueIfReady(browser);
+ }
+
+ bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefProcessId source_process,
+ CefRefPtr<CefProcessMessage> message) override {
+ EXPECT_GT(browser_id_current_, 0);
+ EXPECT_EQ(browser_id_current_, browser->GetIdentifier());
+
+ const std::string& msg_name = message->GetName();
+ if (msg_name == kLoadNavMsg) {
+ // Test that the renderer side succeeded.
+ CefRefPtr<CefListValue> args = message->GetArgumentList();
+ EXPECT_TRUE(args.get());
+ EXPECT_TRUE(args->GetBool(0));
+
+ EXPECT_EQ(browser_id_current_, args->GetInt(1));
+
+ renderer_browser_created_ct_ = args->GetInt(2);
+ EXPECT_GE(renderer_browser_created_ct_, 1);
+ renderer_load_ct_ = args->GetInt(3);
+ EXPECT_GE(renderer_load_ct_, 1);
+
+ // Continue with the test.
+ got_message_.yes();
+ ContinueIfReady(browser);
+
+ return true;
+ }
+
+ // Message not handled.
+ return false;
+ }
+
+ void DestroyTest() override {
+ if (cancel_in_open_url_) {
+ EXPECT_FALSE(got_before_browse_);
+ EXPECT_FALSE(got_before_resource_load_);
+ EXPECT_FALSE(got_load_start_);
+ EXPECT_FALSE(got_load_end_);
+ EXPECT_FALSE(got_message_);
+
+ // We should only navigate a single time if the 2nd load is canceled.
+ EXPECT_EQ(1, renderer_load_ct_);
+ EXPECT_EQ(1, renderer_browser_created_ct_);
+ } else {
+ EXPECT_TRUE(got_before_browse_);
+ EXPECT_TRUE(got_before_resource_load_);
+ EXPECT_TRUE(got_load_start_);
+ EXPECT_TRUE(got_load_end_);
+ EXPECT_TRUE(got_message_);
+
+ if (same_origin_) {
+ // The renderer process should always be reused.
+ EXPECT_EQ(2, renderer_load_ct_);
+ if (IsSameSiteBFCacheEnabled()) {
+ // We expect multiple calls to OnBrowserCreated for same-site
+ // navigations with same-site BFCache enabled.
+ EXPECT_EQ(2, renderer_browser_created_ct_);
+ } else {
+ EXPECT_EQ(1, renderer_browser_created_ct_);
+ }
+ } else {
+ // Each renderer process is only used for a single navigation.
+ EXPECT_EQ(1, renderer_load_ct_);
+ EXPECT_EQ(1, renderer_browser_created_ct_);
+ }
+ }
+
+ if (ExpectOpenURL()) {
+ EXPECT_TRUE(got_open_url_from_tab_);
+ } else {
+ EXPECT_FALSE(got_open_url_from_tab_);
+ }
+
+ TestHandler::DestroyTest();
+ }
+
+ protected:
+ const TestMode mode_;
+ const bool same_origin_;
+ const bool cancel_in_open_url_;
+
+ int browser_id_current_ = 0;
+ int renderer_browser_created_ct_ = 0;
+ int renderer_load_ct_ = 0;
+
+ TrackCallback got_before_browse_;
+ TrackCallback got_open_url_from_tab_;
+ TrackCallback got_before_resource_load_;
+ TrackCallback got_load_start_;
+ TrackCallback got_load_end_;
+ TrackCallback got_message_;
+
+ IMPLEMENT_REFCOUNTING(LoadNavTestHandler);
+};
+
+} // namespace
+
+// Verify navigation-related callbacks when browsing same-origin via LoadURL().
+TEST(NavigationTest, LoadSameOriginLoadURL) {
+ CefRefPtr<LoadNavTestHandler> handler =
+ new LoadNavTestHandler(LoadNavTestHandler::LOAD, true);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Verify navigation-related callbacks when browsing same-origin via left-click.
+TEST(NavigationTest, LoadSameOriginLeftClick) {
+ CefRefPtr<LoadNavTestHandler> handler =
+ new LoadNavTestHandler(LoadNavTestHandler::LEFT_CLICK, true);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Verify navigation-related callbacks when browsing same-origin via middle-
+// click.
+TEST(NavigationTest, LoadSameOriginMiddleClick) {
+ CefRefPtr<LoadNavTestHandler> handler =
+ new LoadNavTestHandler(LoadNavTestHandler::MIDDLE_CLICK, true);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Same as above but cancel the 2nd navigation in OnOpenURLFromTab.
+TEST(NavigationTest, LoadSameOriginMiddleClickCancel) {
+ CefRefPtr<LoadNavTestHandler> handler =
+ new LoadNavTestHandler(LoadNavTestHandler::MIDDLE_CLICK, true, true);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Verify navigation-related callbacks when browsing same-origin via ctrl+left-
+// click.
+TEST(NavigationTest, LoadSameOriginCtrlLeftClick) {
+ CefRefPtr<LoadNavTestHandler> handler =
+ new LoadNavTestHandler(LoadNavTestHandler::CTRL_LEFT_CLICK, true);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Same as above but cancel the 2nd navigation in OnOpenURLFromTab.
+TEST(NavigationTest, LoadSameOriginCtrlLeftClickCancel) {
+ CefRefPtr<LoadNavTestHandler> handler =
+ new LoadNavTestHandler(LoadNavTestHandler::CTRL_LEFT_CLICK, true, true);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Verify navigation-related callbacks when browsing cross-origin via LoadURL().
+TEST(NavigationTest, LoadCrossOriginLoadURL) {
+ CefRefPtr<LoadNavTestHandler> handler =
+ new LoadNavTestHandler(LoadNavTestHandler::LOAD, false);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Verify navigation-related callbacks when browsing cross-origin via left-
+// click.
+TEST(NavigationTest, LoadCrossOriginLeftClick) {
+ CefRefPtr<LoadNavTestHandler> handler =
+ new LoadNavTestHandler(LoadNavTestHandler::LEFT_CLICK, false);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Verify navigation-related callbacks when browsing cross-origin via middle-
+// click.
+TEST(NavigationTest, LoadCrossOriginMiddleClick) {
+ CefRefPtr<LoadNavTestHandler> handler =
+ new LoadNavTestHandler(LoadNavTestHandler::MIDDLE_CLICK, false);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Same as above but cancel the 2nd navigation in OnOpenURLFromTab.
+TEST(NavigationTest, LoadCrossOriginMiddleClickCancel) {
+ CefRefPtr<LoadNavTestHandler> handler =
+ new LoadNavTestHandler(LoadNavTestHandler::MIDDLE_CLICK, false, true);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Verify navigation-related callbacks when browsing cross-origin via ctrl+left-
+// click.
+TEST(NavigationTest, LoadCrossOriginCtrlLeftClick) {
+ CefRefPtr<LoadNavTestHandler> handler =
+ new LoadNavTestHandler(LoadNavTestHandler::CTRL_LEFT_CLICK, false);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Same as above but cancel the 2nd navigation in OnOpenURLFromTab.
+TEST(NavigationTest, LoadCrossOriginCtrlLeftClickCancel) {
+ CefRefPtr<LoadNavTestHandler> handler =
+ new LoadNavTestHandler(LoadNavTestHandler::CTRL_LEFT_CLICK, false, true);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+namespace {
+
+const char kSimultPopupMainUrl[] = "http://www.tests-sp.com/main.html";
+const char kSimultPopupPopupUrl[] = "http://www.tests-sp.com/popup";
+const size_t kSimultPopupCount = 5U;
+
+// Test multiple popups simultaniously.
+class PopupSimultaneousTestHandler : public TestHandler {
+ public:
+ explicit PopupSimultaneousTestHandler(bool same_url)
+ : same_url_(same_url),
+ before_popup_ct_(0U),
+ after_created_ct_(0U),
+ before_close_ct_(0U) {}
+
+ void RunTest() override {
+ std::string main_html = "<html><script>\n";
+ for (size_t i = 0; i < kSimultPopupCount; ++i) {
+ if (same_url_) {
+ popup_url_[i] = std::string(kSimultPopupPopupUrl) + ".html";
+ } else {
+ std::stringstream ss;
+ ss << kSimultPopupPopupUrl << i << ".html";
+ popup_url_[i] = ss.str();
+ }
+ main_html += "window.open('" + popup_url_[i] + "');\n";
+ AddResource(popup_url_[i], "<html>Popup " + popup_url_[i] + "</html>",
+ "text/html");
+ }
+ main_html += "</script></html>";
+
+ AddResource(kSimultPopupMainUrl, main_html, "text/html");
+
+ // Create the browser.
+ CreateBrowser(kSimultPopupMainUrl);
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout();
+ }
+
+ bool OnBeforePopup(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const CefString& target_url,
+ const CefString& target_frame_name,
+ cef_window_open_disposition_t target_disposition,
+ bool user_gesture,
+ const CefPopupFeatures& popupFeatures,
+ CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient>& client,
+ CefBrowserSettings& settings,
+ CefRefPtr<CefDictionaryValue>& extra_info,
+ bool* no_javascript_access) override {
+ const std::string& url = target_url;
+ EXPECT_LT(before_popup_ct_, kSimultPopupCount);
+ EXPECT_STREQ(popup_url_[before_popup_ct_].c_str(), url.c_str())
+ << before_popup_ct_;
+ before_popup_ct_++;
+ return false;
+ }
+
+ void OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
+ TestHandler::OnAfterCreated(browser);
+
+ if (browser->IsPopup()) {
+ EXPECT_LT(after_created_ct_, kSimultPopupCount);
+ browser_id_[after_created_ct_] = browser->GetIdentifier();
+ after_created_ct_++;
+ }
+ }
+
+ void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
+ bool isLoading,
+ bool canGoBack,
+ bool canGoForward) override {
+ if (isLoading) {
+ return;
+ }
+
+ if (browser->IsPopup()) {
+ const std::string& url = browser->GetMainFrame()->GetURL();
+ for (size_t i = 0; i < kSimultPopupCount; ++i) {
+ if (browser->GetIdentifier() == browser_id_[i]) {
+ EXPECT_STREQ(popup_url_[i].c_str(), url.c_str()) << i;
+
+ got_loading_state_change_[i].yes();
+ CloseBrowser(browser, true);
+ return;
+ }
+ }
+ EXPECT_FALSE(true); // Not reached.
+ }
+ }
+
+ void OnBeforeClose(CefRefPtr<CefBrowser> browser) override {
+ TestHandler::OnBeforeClose(browser);
+
+ if (browser->IsPopup()) {
+ const std::string& url = browser->GetMainFrame()->GetURL();
+ for (size_t i = 0; i < kSimultPopupCount; ++i) {
+ if (browser->GetIdentifier() == browser_id_[i]) {
+ EXPECT_TRUE(got_loading_state_change_[i]);
+ EXPECT_STREQ(popup_url_[i].c_str(), url.c_str()) << i;
+
+ got_before_close_[i].yes();
+
+ if (++before_close_ct_ == kSimultPopupCount) {
+ DestroyTest();
+ }
+ return;
+ }
+ }
+ EXPECT_FALSE(true); // Not reached.
+ }
+ }
+
+ private:
+ void DestroyTest() override {
+ EXPECT_EQ(kSimultPopupCount, before_popup_ct_);
+ EXPECT_EQ(kSimultPopupCount, after_created_ct_);
+ EXPECT_EQ(kSimultPopupCount, before_close_ct_);
+
+ for (size_t i = 0; i < kSimultPopupCount; ++i) {
+ EXPECT_GT(browser_id_[i], 0) << i;
+ EXPECT_TRUE(got_loading_state_change_[i]) << i;
+ EXPECT_TRUE(got_before_close_[i]) << i;
+ }
+
+ TestHandler::DestroyTest();
+ }
+
+ const bool same_url_;
+ std::string popup_url_[kSimultPopupCount];
+ size_t before_popup_ct_;
+ int browser_id_[kSimultPopupCount];
+ size_t after_created_ct_;
+ TrackCallback got_loading_state_change_[kSimultPopupCount];
+ TrackCallback got_before_close_[kSimultPopupCount];
+ size_t before_close_ct_;
+
+ IMPLEMENT_REFCOUNTING(PopupSimultaneousTestHandler);
+};
+
+} // namespace
+
+// Test simultaneous popups with different URLs.
+TEST(NavigationTest, PopupSimultaneousDifferentUrl) {
+ CefRefPtr<PopupSimultaneousTestHandler> handler =
+ new PopupSimultaneousTestHandler(false);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Test simultaneous popups with the same URL.
+TEST(NavigationTest, PopupSimultaneousSameUrl) {
+ CefRefPtr<PopupSimultaneousTestHandler> handler =
+ new PopupSimultaneousTestHandler(true);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+namespace {
+
+const char kPopupJSOpenMainUrl[] = "http://www.tests-pjso.com/main.html";
+const char kPopupJSOpenPopupUrl[] = "http://www.tests-pjso.com/popup.html";
+
+// Test a popup where the URL is a JavaScript URI that opens another popup.
+class PopupJSWindowOpenTestHandler : public TestHandler {
+ public:
+ PopupJSWindowOpenTestHandler()
+ : before_popup_ct_(0U),
+ after_created_ct_(0U),
+ load_end_ct_(0U),
+ before_close_ct_(0U) {}
+
+ void RunTest() override {
+ AddResource(kPopupJSOpenMainUrl, "<html>Main</html>", "text/html");
+ AddResource(kPopupJSOpenPopupUrl, "<html>Popup</html>", "text/html");
+
+ // Create the browser.
+ CreateBrowser(kPopupJSOpenMainUrl);
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout();
+ }
+
+ bool OnBeforePopup(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const CefString& target_url,
+ const CefString& target_frame_name,
+ cef_window_open_disposition_t target_disposition,
+ bool user_gesture,
+ const CefPopupFeatures& popupFeatures,
+ CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient>& client,
+ CefBrowserSettings& settings,
+ CefRefPtr<CefDictionaryValue>& extra_info,
+ bool* no_javascript_access) override {
+ before_popup_ct_++;
+ return false;
+ }
+
+ void OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
+ TestHandler::OnAfterCreated(browser);
+
+ if (browser->IsPopup()) {
+ after_created_ct_++;
+ if (!popup1_) {
+ popup1_ = browser;
+ } else if (!popup2_) {
+ popup2_ = browser;
+ } else {
+ ADD_FAILURE();
+ }
+ }
+ }
+
+ void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
+ bool isLoading,
+ bool canGoBack,
+ bool canGoForward) override {
+ if (isLoading) {
+ return;
+ }
+
+ if (browser->IsPopup()) {
+ const std::string& url = browser->GetMainFrame()->GetURL();
+ if (url == kPopupJSOpenPopupUrl) {
+ EXPECT_TRUE(browser->IsSame(popup2_));
+ popup2_ = nullptr;
+
+ // OnLoadingStateChange is not currently called for browser-side
+ // navigations of empty popups. See https://crbug.com/789252.
+ // Explicitly close the empty popup here as a workaround.
+ CloseBrowser(popup1_, true);
+ popup1_ = nullptr;
+ } else {
+ // Empty popup.
+ EXPECT_TRUE(url.empty());
+ EXPECT_TRUE(browser->IsSame(popup1_));
+ popup1_ = nullptr;
+ }
+
+ load_end_ct_++;
+ CloseBrowser(browser, true);
+ } else if (browser->GetMainFrame()->GetURL() == kPopupJSOpenMainUrl) {
+ // Load the problematic JS URI.
+ // This will result in 2 popups being created:
+ // - An empty popup
+ // - A popup that loads kPopupJSOpenPopupUrl
+ browser->GetMainFrame()->LoadURL(
+ "javascript:window.open(\"javascript:window.open('" +
+ std::string(kPopupJSOpenPopupUrl) + "')\")");
+ }
+ }
+
+ void OnLoadError(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ ErrorCode errorCode,
+ const CefString& errorText,
+ const CefString& failedUrl) override {
+ ADD_FAILURE() << "OnLoadError url: " << failedUrl.ToString()
+ << " error: " << errorCode;
+ }
+
+ void OnBeforeClose(CefRefPtr<CefBrowser> browser) override {
+ TestHandler::OnBeforeClose(browser);
+
+ before_close_ct_++;
+ if (before_close_ct_ == 2U) {
+ DestroyTest();
+ }
+ }
+
+ private:
+ void DestroyTest() override {
+ EXPECT_EQ(2U, before_popup_ct_);
+ EXPECT_EQ(2U, after_created_ct_);
+ EXPECT_EQ(2U, before_close_ct_);
+
+ // OnLoadingStateChange is not currently called for browser-side
+ // navigations of empty popups. See https://crbug.com/789252.
+ EXPECT_EQ(1U, load_end_ct_);
+
+ TestHandler::DestroyTest();
+ }
+
+ CefRefPtr<CefBrowser> popup1_;
+ CefRefPtr<CefBrowser> popup2_;
+
+ size_t before_popup_ct_;
+ size_t after_created_ct_;
+ size_t load_end_ct_;
+ size_t before_close_ct_;
+
+ IMPLEMENT_REFCOUNTING(PopupJSWindowOpenTestHandler);
+};
+
+} // namespace
+
+// Test a popup where the URL is a JavaScript URI that opens another popup.
+TEST(NavigationTest, PopupJSWindowOpen) {
+ CefRefPtr<PopupJSWindowOpenTestHandler> handler =
+ new PopupJSWindowOpenTestHandler();
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+namespace {
+
+const char kPopupJSEmptyMainUrl[] = "http://www.tests-pjse.com/main.html";
+
+// Test creation of a popup where the URL is empty.
+class PopupJSWindowEmptyTestHandler : public TestHandler {
+ public:
+ PopupJSWindowEmptyTestHandler() {}
+
+ void RunTest() override {
+ AddResource(kPopupJSEmptyMainUrl, "<html>Main</html>", "text/html");
+
+ // Create the browser.
+ CreateBrowser(kPopupJSEmptyMainUrl);
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout();
+ }
+
+ bool OnBeforePopup(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const CefString& target_url,
+ const CefString& target_frame_name,
+ cef_window_open_disposition_t target_disposition,
+ bool user_gesture,
+ const CefPopupFeatures& popupFeatures,
+ CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient>& client,
+ CefBrowserSettings& settings,
+ CefRefPtr<CefDictionaryValue>& extra_info,
+ bool* no_javascript_access) override {
+ got_before_popup_.yes();
+ return false;
+ }
+
+ void OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
+ TestHandler::OnAfterCreated(browser);
+
+ if (browser->IsPopup()) {
+ got_after_created_popup_.yes();
+ }
+ }
+
+ void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
+ bool isLoading,
+ bool canGoBack,
+ bool canGoForward) override {
+ if (isLoading) {
+ return;
+ }
+
+ if (browser->IsPopup()) {
+ got_load_end_popup_.yes();
+ CloseBrowser(browser, true);
+ } else {
+ browser->GetMainFrame()->LoadURL("javascript:window.open('')");
+ }
+ }
+
+ void OnLoadError(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ ErrorCode errorCode,
+ const CefString& errorText,
+ const CefString& failedUrl) override {
+ ADD_FAILURE() << "OnLoadError url: " << failedUrl.ToString()
+ << " error: " << errorCode;
+ }
+
+ void OnBeforeClose(CefRefPtr<CefBrowser> browser) override {
+ TestHandler::OnBeforeClose(browser);
+
+ if (browser->IsPopup()) {
+ got_before_close_popup_.yes();
+ DestroyTest();
+ }
+ }
+
+ private:
+ void DestroyTest() override {
+ EXPECT_TRUE(got_before_popup_);
+ EXPECT_TRUE(got_after_created_popup_);
+ EXPECT_TRUE(got_load_end_popup_);
+ EXPECT_TRUE(got_before_close_popup_);
+
+ TestHandler::DestroyTest();
+ }
+
+ TrackCallback got_before_popup_;
+ TrackCallback got_after_created_popup_;
+ TrackCallback got_load_end_popup_;
+ TrackCallback got_before_close_popup_;
+
+ IMPLEMENT_REFCOUNTING(PopupJSWindowEmptyTestHandler);
+};
+
+} // namespace
+
+// Test creation of a popup where the URL is empty.
+TEST(NavigationTest, PopupJSWindowEmpty) {
+ CefRefPtr<PopupJSWindowEmptyTestHandler> handler =
+ new PopupJSWindowEmptyTestHandler();
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+namespace {
+
+const char kBrowseNavPageUrl[] = "http://tests-browsenav/nav.html";
+
+// Browser side.
+class BrowseNavTestHandler : public TestHandler {
+ public:
+ BrowseNavTestHandler(bool allow) : allow_(allow), destroyed_(false) {}
+
+ void RunTest() override {
+ AddResource(kBrowseNavPageUrl, "<html>Test</html>", "text/html");
+
+ // Create the browser.
+ CreateBrowser(kBrowseNavPageUrl);
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout();
+ }
+
+ bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ bool user_gesture,
+ bool is_redirect) override {
+ const std::string& url = request->GetURL();
+ EXPECT_STREQ(kBrowseNavPageUrl, url.c_str());
+ EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
+ EXPECT_TRUE(frame->IsMain());
+
+ got_before_browse_.yes();
+
+ return !allow_;
+ }
+
+ void OnLoadStart(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ TransitionType transition_type) override {
+ const std::string& url = frame->GetURL();
+ EXPECT_STREQ(kBrowseNavPageUrl, url.c_str());
+ EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
+ EXPECT_TRUE(frame->IsMain());
+
+ got_load_start_.yes();
+ }
+
+ void OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int httpStatusCode) override {
+ const std::string& url = frame->GetURL();
+ EXPECT_STREQ(kBrowseNavPageUrl, url.c_str());
+ EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
+ EXPECT_TRUE(frame->IsMain());
+
+ got_load_end_.yes();
+ DestroyTestIfDone();
+ }
+
+ void OnLoadError(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ ErrorCode errorCode,
+ const CefString& errorText,
+ const CefString& failedUrl) override {
+ const std::string& url = frame->GetURL();
+ EXPECT_STREQ("", url.c_str());
+ EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
+ EXPECT_TRUE(frame->IsMain());
+
+ EXPECT_EQ(ERR_ABORTED, errorCode);
+ EXPECT_STREQ(kBrowseNavPageUrl, failedUrl.ToString().c_str());
+
+ got_load_error_.yes();
+ DestroyTestIfDone();
+ }
+
+ void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
+ bool isLoading,
+ bool canGoBack,
+ bool canGoForward) override {
+ const std::string& url = browser->GetMainFrame()->GetURL();
+ EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
+
+ if (isLoading) {
+ EXPECT_STREQ("", url.c_str());
+
+ got_loading_state_changed_start_.yes();
+ } else {
+ if (allow_) {
+ EXPECT_STREQ(kBrowseNavPageUrl, url.c_str());
+ } else {
+ EXPECT_STREQ("", url.c_str());
+ }
+
+ got_loading_state_changed_end_.yes();
+ DestroyTestIfDone();
+ }
+ }
+
+ private:
+ void DestroyTestIfDone() {
+ if (destroyed_) {
+ return;
+ }
+
+ if (got_loading_state_changed_end_) {
+ if (allow_) {
+ if (got_load_end_) {
+ DestroyTest();
+ }
+ } else if (got_load_error_) {
+ DestroyTest();
+ }
+ }
+ }
+
+ void DestroyTest() override {
+ if (destroyed_) {
+ return;
+ }
+ destroyed_ = true;
+
+ EXPECT_TRUE(got_before_browse_);
+ EXPECT_TRUE(got_loading_state_changed_start_);
+ EXPECT_TRUE(got_loading_state_changed_end_);
+
+ if (allow_) {
+ EXPECT_TRUE(got_load_start_);
+ EXPECT_TRUE(got_load_end_);
+ EXPECT_FALSE(got_load_error_);
+ } else {
+ EXPECT_FALSE(got_load_start_);
+ EXPECT_FALSE(got_load_end_);
+ EXPECT_TRUE(got_load_error_);
+ }
+
+ TestHandler::DestroyTest();
+ }
+
+ bool allow_;
+ bool destroyed_;
+
+ TrackCallback got_before_browse_;
+ TrackCallback got_load_start_;
+ TrackCallback got_load_end_;
+ TrackCallback got_load_error_;
+ TrackCallback got_loading_state_changed_start_;
+ TrackCallback got_loading_state_changed_end_;
+
+ IMPLEMENT_REFCOUNTING(BrowseNavTestHandler);
+};
+
+} // namespace
+
+// Test allowing navigation.
+TEST(NavigationTest, BrowseAllow) {
+ CefRefPtr<BrowseNavTestHandler> handler = new BrowseNavTestHandler(true);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Test denying navigation.
+TEST(NavigationTest, BrowseDeny) {
+ CefRefPtr<BrowseNavTestHandler> handler = new BrowseNavTestHandler(false);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+namespace {
+
+const char kSameNavPageUrl[] = "http://tests-samenav/nav.html";
+
+// Browser side.
+class SameNavTestHandler : public TestHandler {
+ public:
+ SameNavTestHandler() : destroyed_(false), step_(0) {}
+
+ void RunTest() override {
+ AddResource(kSameNavPageUrl, "<html>Test</html>", "text/html");
+
+ // Create the browser.
+ expected_url_ = kSameNavPageUrl;
+ CreateBrowser(kSameNavPageUrl);
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout();
+ }
+
+ bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ bool user_gesture,
+ bool is_redirect) override {
+ const std::string& url = request->GetURL();
+ EXPECT_STREQ(expected_url_.c_str(), url.c_str());
+ EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
+ EXPECT_TRUE(frame->IsMain());
+
+ got_before_browse_.yes();
+
+ return false;
+ }
+
+ void OnLoadStart(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ TransitionType transition_type) override {
+ const std::string& url = frame->GetURL();
+ EXPECT_STREQ(expected_url_.c_str(), url.c_str());
+ EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
+ EXPECT_TRUE(frame->IsMain());
+
+ got_load_start_.yes();
+ }
+
+ void OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int httpStatusCode) override {
+ const std::string& url = frame->GetURL();
+ EXPECT_STREQ(expected_url_.c_str(), url.c_str());
+ EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
+ EXPECT_TRUE(frame->IsMain());
+
+ got_load_end_.yes();
+ ContinueTestIfDone();
+ }
+
+ void OnLoadError(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ ErrorCode errorCode,
+ const CefString& errorText,
+ const CefString& failedUrl) override {
+ got_load_error_.yes();
+ }
+
+ void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
+ bool isLoading,
+ bool canGoBack,
+ bool canGoForward) override {
+ const std::string& url = browser->GetMainFrame()->GetURL();
+ EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
+
+ if (isLoading) {
+ // Verify the previous URL.
+ if (step_ == 0) {
+ EXPECT_TRUE(url.empty());
+ } else {
+ EXPECT_STREQ(kSameNavPageUrl, url.c_str());
+ }
+
+ got_loading_state_changed_start_.yes();
+ } else {
+ EXPECT_STREQ(expected_url_.c_str(), url.c_str());
+
+ got_loading_state_changed_end_.yes();
+ ContinueTestIfDone();
+ }
+ }
+
+ private:
+ void ContinueTestIfDone() {
+ if (step_ == 0) {
+ // First navigation should trigger all callbacks except OnLoadError.
+ if (got_loading_state_changed_end_ && got_load_end_) {
+ EXPECT_TRUE(got_before_browse_);
+ EXPECT_TRUE(got_loading_state_changed_start_);
+ EXPECT_TRUE(got_load_start_);
+ EXPECT_FALSE(got_load_error_);
+
+ got_before_browse_.reset();
+ got_loading_state_changed_start_.reset();
+ got_loading_state_changed_end_.reset();
+ got_load_start_.reset();
+ got_load_end_.reset();
+
+ step_++;
+ expected_url_ = kSameNavPageUrl + std::string("#fragment");
+ GetBrowser()->GetMainFrame()->LoadURL(expected_url_);
+ }
+ } else if (step_ == 1) {
+ step_++;
+ DestroyTest();
+ } else {
+ EXPECT_TRUE(false); // Not reached.
+ }
+ }
+
+ void DestroyTest() override {
+ if (destroyed_) {
+ return;
+ }
+ destroyed_ = true;
+
+ EXPECT_EQ(2, step_);
+
+ // Second (fragment) navigation should only trigger OnLoadingStateChange.
+ EXPECT_FALSE(got_before_browse_);
+ EXPECT_TRUE(got_loading_state_changed_start_);
+ EXPECT_TRUE(got_loading_state_changed_end_);
+ EXPECT_FALSE(got_load_start_);
+ EXPECT_FALSE(got_load_end_);
+ EXPECT_FALSE(got_load_error_);
+
+ TestHandler::DestroyTest();
+ }
+
+ bool destroyed_;
+ int step_;
+ std::string expected_url_;
+
+ TrackCallback got_before_browse_;
+ TrackCallback got_load_start_;
+ TrackCallback got_load_end_;
+ TrackCallback got_load_error_;
+ TrackCallback got_loading_state_changed_start_;
+ TrackCallback got_loading_state_changed_end_;
+
+ IMPLEMENT_REFCOUNTING(SameNavTestHandler);
+};
+
+} // namespace
+
+// Test that same page navigation does not call OnLoadStart/OnLoadEnd.
+TEST(NavigationTest, SamePage) {
+ CefRefPtr<SameNavTestHandler> handler = new SameNavTestHandler();
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+namespace {
+
+const char kCancelPageUrl[] = "http://tests-cancelnav/nav.html";
+
+// A scheme handler that never starts sending data.
+class UnstartedSchemeHandler : public CefResourceHandler {
+ public:
+ UnstartedSchemeHandler() {}
+
+ bool Open(CefRefPtr<CefRequest> request,
+ bool& handle_request,
+ CefRefPtr<CefCallback> callback) override {
+ EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO));
+
+ // Continue immediately.
+ handle_request = true;
+ return true;
+ }
+
+ void GetResponseHeaders(CefRefPtr<CefResponse> response,
+ int64& response_length,
+ CefString& redirectUrl) override {
+ response->SetStatus(200);
+ response->SetMimeType("text/html");
+ response_length = 100;
+ }
+
+ void Cancel() override { callback_ = nullptr; }
+
+ bool Read(void* data_out,
+ int bytes_to_read,
+ int& bytes_read,
+ CefRefPtr<CefResourceReadCallback> callback) override {
+ EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO));
+
+ callback_ = callback;
+
+ // Pretend that we'll provide the data later.
+ bytes_read = 0;
+ return true;
+ }
+
+ protected:
+ CefRefPtr<CefResourceReadCallback> callback_;
+
+ IMPLEMENT_REFCOUNTING(UnstartedSchemeHandler);
+ DISALLOW_COPY_AND_ASSIGN(UnstartedSchemeHandler);
+};
+
+// Browser side.
+class CancelBeforeNavTestHandler : public TestHandler {
+ public:
+ CancelBeforeNavTestHandler() : destroyed_(false) {}
+
+ void RunTest() override {
+ // Create the browser.
+ CreateBrowser(kCancelPageUrl);
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout();
+ }
+
+ bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ bool user_gesture,
+ bool is_redirect) override {
+ EXPECT_TRUE(got_loading_state_changed_start_);
+ EXPECT_FALSE(got_before_browse_);
+ EXPECT_FALSE(got_get_resource_handler_);
+ EXPECT_FALSE(got_load_start_);
+ EXPECT_FALSE(got_cancel_load_);
+ EXPECT_FALSE(got_load_error_);
+ EXPECT_FALSE(got_load_end_);
+ EXPECT_FALSE(got_loading_state_changed_end_);
+
+ const std::string& url = request->GetURL();
+ EXPECT_STREQ(kCancelPageUrl, url.c_str());
+ EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
+ EXPECT_TRUE(frame->IsMain());
+
+ got_before_browse_.yes();
+
+ return false;
+ }
+
+ CefRefPtr<CefResourceHandler> GetResourceHandler(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request) override {
+ EXPECT_TRUE(got_loading_state_changed_start_);
+ EXPECT_TRUE(got_before_browse_);
+ EXPECT_FALSE(got_get_resource_handler_);
+ EXPECT_FALSE(got_load_start_);
+ EXPECT_FALSE(got_cancel_load_);
+ EXPECT_FALSE(got_load_error_);
+ EXPECT_FALSE(got_load_end_);
+ EXPECT_FALSE(got_loading_state_changed_end_);
+
+ const std::string& url = request->GetURL();
+ EXPECT_STREQ(kCancelPageUrl, url.c_str());
+ EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
+ EXPECT_TRUE(frame->IsMain());
+
+ got_get_resource_handler_.yes();
+
+ CefPostTask(TID_UI,
+ base::BindOnce(&CancelBeforeNavTestHandler::CancelLoad, this));
+
+ return new UnstartedSchemeHandler();
+ }
+
+ void OnLoadStart(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ TransitionType transition_type) override {
+ EXPECT_TRUE(false); // Not reached.
+ got_load_start_.yes();
+ }
+
+ void OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int httpStatusCode) override {
+ EXPECT_TRUE(false); // Not reached.
+ got_load_end_.yes();
+ }
+
+ void OnLoadError(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ ErrorCode errorCode,
+ const CefString& errorText,
+ const CefString& failedUrl) override {
+ EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
+ EXPECT_STREQ("", frame->GetURL().ToString().c_str());
+ EXPECT_EQ(ERR_ABORTED, errorCode);
+ EXPECT_STREQ(kCancelPageUrl, failedUrl.ToString().c_str());
+ got_load_error_.yes();
+ }
+
+ void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
+ bool isLoading,
+ bool canGoBack,
+ bool canGoForward) override {
+ const std::string& url = browser->GetMainFrame()->GetURL();
+ EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
+ EXPECT_TRUE(url.empty());
+
+ if (isLoading) {
+ EXPECT_FALSE(got_loading_state_changed_start_);
+ EXPECT_FALSE(got_before_browse_);
+ EXPECT_FALSE(got_get_resource_handler_);
+ EXPECT_FALSE(got_load_start_);
+ EXPECT_FALSE(got_cancel_load_);
+ EXPECT_FALSE(got_load_error_);
+ EXPECT_FALSE(got_load_end_);
+ EXPECT_FALSE(got_loading_state_changed_end_);
+
+ got_loading_state_changed_start_.yes();
+ } else {
+ EXPECT_TRUE(got_loading_state_changed_start_);
+ EXPECT_TRUE(got_before_browse_);
+ EXPECT_TRUE(got_get_resource_handler_);
+ EXPECT_FALSE(got_load_start_);
+ EXPECT_TRUE(got_cancel_load_);
+ EXPECT_TRUE(got_load_error_);
+ EXPECT_FALSE(got_load_end_);
+ EXPECT_FALSE(got_loading_state_changed_end_);
+
+ got_loading_state_changed_end_.yes();
+
+ DestroyTest();
+ }
+ }
+
+ private:
+ void CancelLoad() {
+ got_cancel_load_.yes();
+ GetBrowser()->StopLoad();
+ }
+
+ void DestroyTest() override {
+ if (destroyed_) {
+ return;
+ }
+ destroyed_ = true;
+
+ EXPECT_TRUE(got_loading_state_changed_start_);
+ EXPECT_TRUE(got_before_browse_);
+ EXPECT_TRUE(got_get_resource_handler_);
+ EXPECT_FALSE(got_load_start_);
+ EXPECT_TRUE(got_cancel_load_);
+ EXPECT_TRUE(got_load_error_);
+ EXPECT_FALSE(got_load_end_);
+ EXPECT_TRUE(got_loading_state_changed_end_);
+
+ TestHandler::DestroyTest();
+ }
+
+ bool destroyed_;
+
+ TrackCallback got_loading_state_changed_start_;
+ TrackCallback got_before_browse_;
+ TrackCallback got_get_resource_handler_;
+ TrackCallback got_load_start_;
+ TrackCallback got_cancel_load_;
+ TrackCallback got_load_error_;
+ TrackCallback got_load_end_;
+ TrackCallback got_loading_state_changed_end_;
+
+ IMPLEMENT_REFCOUNTING(CancelBeforeNavTestHandler);
+};
+
+} // namespace
+
+// Test that navigation canceled before commit does not call
+// OnLoadStart/OnLoadEnd.
+TEST(NavigationTest, CancelBeforeCommit) {
+ CefRefPtr<CancelBeforeNavTestHandler> handler =
+ new CancelBeforeNavTestHandler();
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+namespace {
+
+// A scheme handler that stalls after writing some data.
+class StalledSchemeHandler : public CefResourceHandler {
+ public:
+ StalledSchemeHandler() : offset_(0), write_size_(0) {}
+
+ bool Open(CefRefPtr<CefRequest> request,
+ bool& handle_request,
+ CefRefPtr<CefCallback> callback) override {
+ EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO));
+
+ // Continue immediately.
+ handle_request = true;
+ return true;
+ }
+
+ void GetResponseHeaders(CefRefPtr<CefResponse> response,
+ int64& response_length,
+ CefString& redirectUrl) override {
+ response->SetStatus(200);
+ response->SetMimeType("text/html");
+ content_ = "<html><body>Test</body></html>";
+ // Write this number of bytes and then stall.
+ write_size_ = content_.size() / 2U;
+ response_length = content_.size();
+ }
+
+ void Cancel() override { callback_ = nullptr; }
+
+ bool Read(void* data_out,
+ int bytes_to_read,
+ int& bytes_read,
+ CefRefPtr<CefResourceReadCallback> callback) override {
+ EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO));
+
+ bytes_read = 0;
+
+ size_t size = content_.size();
+ if (offset_ >= write_size_) {
+ // Now stall.
+ callback_ = callback;
+ return true;
+ }
+
+ bool has_data = false;
+
+ if (offset_ < size) {
+ // Write up to |write_size_| bytes.
+ int transfer_size =
+ std::min(bytes_to_read, std::min(static_cast<int>(write_size_),
+ static_cast<int>(size - offset_)));
+ memcpy(data_out, content_.c_str() + offset_, transfer_size);
+ offset_ += transfer_size;
+
+ bytes_read = transfer_size;
+ has_data = true;
+ }
+
+ return has_data;
+ }
+
+ protected:
+ std::string content_;
+ size_t offset_;
+ size_t write_size_;
+ CefRefPtr<CefResourceReadCallback> callback_;
+
+ IMPLEMENT_REFCOUNTING(StalledSchemeHandler);
+ DISALLOW_COPY_AND_ASSIGN(StalledSchemeHandler);
+};
+
+// Browser side.
+class CancelAfterNavTestHandler : public TestHandler {
+ public:
+ CancelAfterNavTestHandler() : destroyed_(false) {}
+
+ void RunTest() override {
+ // Create the browser.
+ CreateBrowser(kCancelPageUrl);
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout();
+ }
+
+ bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ bool user_gesture,
+ bool is_redirect) override {
+ EXPECT_TRUE(got_loading_state_changed_start_);
+ EXPECT_FALSE(got_before_browse_);
+ EXPECT_FALSE(got_get_resource_handler_);
+ EXPECT_FALSE(got_load_start_);
+ EXPECT_FALSE(got_cancel_load_);
+ EXPECT_FALSE(got_load_error_);
+ EXPECT_FALSE(got_load_end_);
+ EXPECT_FALSE(got_loading_state_changed_end_);
+
+ const std::string& url = request->GetURL();
+ EXPECT_STREQ(kCancelPageUrl, url.c_str());
+ EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
+ EXPECT_TRUE(frame->IsMain());
+
+ got_before_browse_.yes();
+
+ return false;
+ }
+
+ CefRefPtr<CefResourceHandler> GetResourceHandler(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request) override {
+ EXPECT_TRUE(got_loading_state_changed_start_);
+ EXPECT_TRUE(got_before_browse_);
+ EXPECT_FALSE(got_get_resource_handler_);
+ EXPECT_FALSE(got_load_start_);
+ EXPECT_FALSE(got_cancel_load_);
+ EXPECT_FALSE(got_load_error_);
+ EXPECT_FALSE(got_load_end_);
+ EXPECT_FALSE(got_loading_state_changed_end_);
+
+ const std::string& url = request->GetURL();
+ EXPECT_STREQ(kCancelPageUrl, url.c_str());
+ EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
+ EXPECT_TRUE(frame->IsMain());
+
+ got_get_resource_handler_.yes();
+
+ // The required delay is longer when browser-side navigation is enabled.
+ CefPostDelayedTask(
+ TID_UI, base::BindOnce(&CancelAfterNavTestHandler::CancelLoad, this),
+ 1000);
+
+ return new StalledSchemeHandler();
+ }
+
+ void OnLoadStart(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ TransitionType transition_type) override {
+ EXPECT_TRUE(got_loading_state_changed_start_);
+ EXPECT_TRUE(got_before_browse_);
+ EXPECT_TRUE(got_get_resource_handler_);
+ EXPECT_FALSE(got_load_start_);
+ EXPECT_FALSE(got_cancel_load_);
+ EXPECT_FALSE(got_load_error_);
+ EXPECT_FALSE(got_load_end_);
+ EXPECT_FALSE(got_loading_state_changed_end_);
+
+ const std::string& url = frame->GetURL();
+ EXPECT_STREQ(kCancelPageUrl, url.c_str());
+ EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
+ EXPECT_TRUE(frame->IsMain());
+
+ got_load_start_.yes();
+ }
+
+ void OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int httpStatusCode) override {
+ EXPECT_TRUE(got_loading_state_changed_start_);
+ EXPECT_TRUE(got_before_browse_);
+ EXPECT_TRUE(got_get_resource_handler_);
+ EXPECT_TRUE(got_load_start_);
+ EXPECT_TRUE(got_cancel_load_);
+ EXPECT_TRUE(got_load_error_);
+ EXPECT_FALSE(got_load_end_);
+ EXPECT_FALSE(got_loading_state_changed_end_);
+
+ const std::string& url = frame->GetURL();
+ EXPECT_STREQ(kCancelPageUrl, url.c_str());
+ EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
+ EXPECT_TRUE(frame->IsMain());
+
+ got_load_end_.yes();
+ DestroyTestIfDone();
+ }
+
+ void OnLoadError(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ ErrorCode errorCode,
+ const CefString& errorText,
+ const CefString& failedUrl) override {
+ EXPECT_TRUE(got_loading_state_changed_start_);
+ EXPECT_TRUE(got_before_browse_);
+ EXPECT_TRUE(got_get_resource_handler_);
+ EXPECT_TRUE(got_load_start_);
+ EXPECT_TRUE(got_cancel_load_);
+ EXPECT_FALSE(got_load_error_);
+ EXPECT_FALSE(got_load_end_);
+ EXPECT_FALSE(got_loading_state_changed_end_);
+
+ const std::string& url = failedUrl;
+ EXPECT_STREQ(kCancelPageUrl, url.c_str());
+ EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
+ EXPECT_TRUE(frame->IsMain());
+
+ got_load_error_.yes();
+ }
+
+ void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
+ bool isLoading,
+ bool canGoBack,
+ bool canGoForward) override {
+ const std::string& url = browser->GetMainFrame()->GetURL();
+ EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
+
+ if (isLoading) {
+ EXPECT_FALSE(got_loading_state_changed_start_);
+ EXPECT_FALSE(got_before_browse_);
+ EXPECT_FALSE(got_get_resource_handler_);
+ EXPECT_FALSE(got_load_start_);
+ EXPECT_FALSE(got_cancel_load_);
+ EXPECT_FALSE(got_load_error_);
+ EXPECT_FALSE(got_load_end_);
+ EXPECT_FALSE(got_loading_state_changed_end_);
+
+ EXPECT_TRUE(url.empty());
+
+ got_loading_state_changed_start_.yes();
+ } else {
+ EXPECT_TRUE(got_loading_state_changed_start_);
+ EXPECT_TRUE(got_before_browse_);
+ EXPECT_TRUE(got_get_resource_handler_);
+ EXPECT_TRUE(got_load_start_);
+ EXPECT_TRUE(got_cancel_load_);
+ EXPECT_TRUE(got_load_error_);
+ EXPECT_TRUE(got_load_end_);
+ EXPECT_FALSE(got_loading_state_changed_end_);
+
+ EXPECT_STREQ(kCancelPageUrl, url.c_str());
+
+ got_loading_state_changed_end_.yes();
+ DestroyTestIfDone();
+ }
+ }
+
+ private:
+ void CancelLoad() {
+ got_cancel_load_.yes();
+ GetBrowser()->StopLoad();
+ }
+
+ void DestroyTestIfDone() {
+ if (got_loading_state_changed_end_ && got_load_end_) {
+ DestroyTest();
+ }
+ }
+
+ void DestroyTest() override {
+ if (destroyed_) {
+ return;
+ }
+ destroyed_ = true;
+
+ EXPECT_TRUE(got_loading_state_changed_start_);
+ EXPECT_TRUE(got_before_browse_);
+ EXPECT_TRUE(got_get_resource_handler_);
+ EXPECT_TRUE(got_load_start_);
+ EXPECT_TRUE(got_cancel_load_);
+ EXPECT_TRUE(got_load_error_);
+ EXPECT_TRUE(got_load_end_);
+ EXPECT_TRUE(got_loading_state_changed_end_);
+
+ TestHandler::DestroyTest();
+ }
+
+ bool destroyed_;
+
+ TrackCallback got_loading_state_changed_start_;
+ TrackCallback got_before_browse_;
+ TrackCallback got_get_resource_handler_;
+ TrackCallback got_load_start_;
+ TrackCallback got_cancel_load_;
+ TrackCallback got_load_error_;
+ TrackCallback got_load_end_;
+ TrackCallback got_loading_state_changed_end_;
+
+ IMPLEMENT_REFCOUNTING(CancelAfterNavTestHandler);
+};
+
+} // namespace
+
+// Test that navigation canceled after commit calls everything.
+TEST(NavigationTest, CancelAfterCommit) {
+ CefRefPtr<CancelAfterNavTestHandler> handler =
+ new CancelAfterNavTestHandler();
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+namespace {
+
+const char kExtraInfoUrl[] = "http://tests-extrainfonav.com/extra.html";
+const char kExtraInfoPopupUrl[] =
+ "http://tests-extrainfonav.com/extra_popup.html";
+const char kExtraInfoNavMsg[] = "NavigationTest.ExtraInfoNav";
+const char kExtraInfoTestCmdKey[] = "nav-extra-info-test";
+
+void SetBrowserExtraInfo(CefRefPtr<CefDictionaryValue> extra_info) {
+ // Necessary for identifying the test case.
+ extra_info->SetBool(kExtraInfoTestCmdKey, true);
+
+ // Arbitrary data for testing.
+ extra_info->SetBool("bool", true);
+ CefRefPtr<CefDictionaryValue> dict = CefDictionaryValue::Create();
+ dict->SetInt("key1", 5);
+ dict->SetString("key2", "test string");
+ extra_info->SetDictionary("dictionary", dict);
+ extra_info->SetDouble("double", 5.43322);
+ extra_info->SetString("string", "some string");
+}
+
+// Renderer side
+class ExtraInfoNavRendererTest : public ClientAppRenderer::Delegate {
+ public:
+ ExtraInfoNavRendererTest() : run_test_(false) {}
+
+ void OnBrowserCreated(CefRefPtr<ClientAppRenderer> app,
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefDictionaryValue> extra_info) override {
+ run_test_ = extra_info && extra_info->HasKey(kExtraInfoTestCmdKey);
+ if (!run_test_) {
+ return;
+ }
+
+ CefRefPtr<CefDictionaryValue> expected = CefDictionaryValue::Create();
+ SetBrowserExtraInfo(expected);
+ TestDictionaryEqual(expected, extra_info);
+
+ SendTestResults(browser, browser->GetMainFrame());
+ }
+
+ protected:
+ // Send the test results.
+ void SendTestResults(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) {
+ // Check if the test has failed.
+ bool result = !TestFailed();
+
+ CefRefPtr<CefProcessMessage> return_msg =
+ CefProcessMessage::Create(kExtraInfoNavMsg);
+ CefRefPtr<CefListValue> args = return_msg->GetArgumentList();
+ EXPECT_TRUE(args.get());
+ EXPECT_TRUE(args->SetBool(0, result));
+ EXPECT_TRUE(args->SetBool(1, browser->IsPopup()));
+ frame->SendProcessMessage(PID_BROWSER, return_msg);
+ }
+
+ bool run_test_;
+
+ IMPLEMENT_REFCOUNTING(ExtraInfoNavRendererTest);
+};
+
+class ExtraInfoNavTestHandler : public TestHandler {
+ public:
+ ExtraInfoNavTestHandler() : popup_opened_(false) {}
+
+ void RunTest() override {
+ AddResource(kExtraInfoUrl,
+ "<html><head></head><body>ExtraInfo</body></html>",
+ "text/html");
+ AddResource(kExtraInfoPopupUrl, "<html>ExtraInfoPopup</html>", "text/html");
+
+ CefRefPtr<CefDictionaryValue> extra_info = CefDictionaryValue::Create();
+ SetBrowserExtraInfo(extra_info);
+
+ // Create the browser.
+ CreateBrowser(kExtraInfoUrl, nullptr, extra_info);
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout();
+ }
+
+ void OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int httpStatusCode) override {
+ if (popup_opened_) {
+ DestroyTest();
+ } else {
+ browser->GetMainFrame()->ExecuteJavaScript(
+ "window.open('" + std::string(kExtraInfoPopupUrl) + "');",
+ CefString(), 0);
+ }
+ }
+
+ bool OnBeforePopup(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const CefString& target_url,
+ const CefString& target_frame_name,
+ cef_window_open_disposition_t target_disposition,
+ bool user_gesture,
+ const CefPopupFeatures& popupFeatures,
+ CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient>& client,
+ CefBrowserSettings& settings,
+ CefRefPtr<CefDictionaryValue>& extra_info,
+ bool* no_javascript_access) override {
+ const std::string& url = target_url;
+ EXPECT_FALSE(popup_opened_);
+ EXPECT_STREQ(kExtraInfoPopupUrl, url.c_str());
+
+ CefRefPtr<CefDictionaryValue> extra = CefDictionaryValue::Create();
+ SetBrowserExtraInfo(extra);
+
+ extra_info = extra;
+
+ popup_opened_ = true;
+ return false;
+ }
+
+ bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefProcessId source_process,
+ CefRefPtr<CefProcessMessage> message) override {
+ if (message->GetName().ToString() == kExtraInfoNavMsg) {
+ // Test that the renderer side succeeded.
+ CefRefPtr<CefListValue> args = message->GetArgumentList();
+ EXPECT_TRUE(args.get());
+ EXPECT_TRUE(args->GetBool(0));
+ if (popup_opened_) {
+ EXPECT_TRUE(args->GetBool(1));
+ got_process_message_popup_.yes();
+ } else {
+ EXPECT_FALSE(args->GetBool(1));
+ got_process_message_main_.yes();
+ }
+ return true;
+ }
+
+ // Message not handled.
+ return false;
+ }
+
+ protected:
+ bool popup_opened_;
+ TrackCallback got_process_message_main_;
+ TrackCallback got_process_message_popup_;
+
+ void DestroyTest() override {
+ // Verify test expectations.
+ EXPECT_TRUE(got_process_message_main_);
+ EXPECT_TRUE(got_process_message_popup_);
+
+ TestHandler::DestroyTest();
+ }
+
+ IMPLEMENT_REFCOUNTING(ExtraInfoNavTestHandler);
+};
+
+} // namespace
+
+TEST(NavigationTest, ExtraInfo) {
+ CefRefPtr<ExtraInfoNavTestHandler> handler = new ExtraInfoNavTestHandler();
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Entry point for creating navigation renderer test objects.
+// Called from client_app_delegates.cc.
+void CreateNavigationRendererTests(ClientAppRenderer::DelegateSet& delegates) {
+ delegates.insert(new HistoryNavRendererTest);
+ delegates.insert(new OrderNavRendererTest);
+ delegates.insert(new LoadNavRendererTest);
+ delegates.insert(new ExtraInfoNavRendererTest);
+}
diff --git a/tests/ceftests/os_rendering_unittest.cc b/tests/ceftests/os_rendering_unittest.cc
new file mode 100644
index 00000000..5d167866
--- /dev/null
+++ b/tests/ceftests/os_rendering_unittest.cc
@@ -0,0 +1,1912 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "include/base/cef_callback.h"
+#include "include/base/cef_logging.h"
+#include "include/cef_parser.h"
+#include "include/cef_v8.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "include/wrapper/cef_stream_resource_handler.h"
+#include "tests/ceftests/routing_test_handler.h"
+#include "tests/ceftests/test_util.h"
+#include "tests/gtest/include/gtest/gtest.h"
+#include "tests/shared/browser/geometry_util.h"
+#include "tests/shared/browser/resource_util.h"
+
+#if defined(OS_MAC)
+#include <Carbon/Carbon.h> // For character codes.
+#include "tests/ceftests/os_rendering_unittest_mac.h"
+#elif defined(OS_LINUX)
+#include <X11/keysym.h>
+#elif defined(OS_WIN)
+// Required for resource_util_win, which uses this as an extern
+HINSTANCE hInst = ::GetModuleHandle(nullptr);
+#endif
+
+// Set to 1 to enable verbose debugging info logging.
+#define VERBOSE_DEBUGGING 0
+
+namespace {
+
+const char kTestUrl[] = "http://tests/osrtest";
+
+// Must be both large enough for the drag/drop region to be visible and small
+// enough for a little vertical offset with scrollbar.
+const int kOsrWidth = 600;
+const int kOsrHeight = 450;
+
+// bounding client rects for edit box and navigate button
+#if defined(OS_WIN)
+const CefRect kExpandedSelectRect(462, 42, 81, 334);
+#elif defined(OS_MAC)
+const CefRect kExpandedSelectRect(462, 42, 75, 334);
+#elif defined(OS_LINUX)
+const CefRect kExpandedSelectRect(462, 42, 79, 334);
+#else
+#error "Unsupported platform"
+#endif // defined(OS_WIN)
+
+// word to be written into edit box
+const char kKeyTestWord[] = "done";
+
+constexpr uint32_t kAllTouchHandleFlags =
+ (CEF_THS_FLAG_ENABLED | CEF_THS_FLAG_ORIENTATION | CEF_THS_FLAG_ORIGIN |
+ CEF_THS_FLAG_ALPHA);
+
+#if defined(OS_LINUX)
+
+// From ui/events/keycodes/keyboard_codes_posix.h
+#define VKEY_D 0x44
+#define VKEY_O 0x4F
+#define VKEY_N 0x4E
+#define VKEY_E 0x45
+#define VKEY_ESCAPE 0x1B
+#define VKEY_TAB 0x09
+
+const unsigned int kNativeKeyTestCodes[] = {XK_d, XK_o, XK_n, XK_e};
+
+const unsigned int kNativeKeyEscape = XK_Escape;
+const unsigned int kNativeKeyTab = XK_Tab;
+
+#elif defined(OS_MAC)
+
+// See kKeyCodesMap in ui/events/keycodes/keyboard_code_conversion_mac.mm
+#define VKEY_D 'd'
+#define VKEY_O 'o'
+#define VKEY_N 'n'
+#define VKEY_E 'e'
+#define VKEY_ESCAPE kEscapeCharCode
+#define VKEY_TAB kTabCharCode
+
+const unsigned int kNativeKeyTestCodes[] = {kVK_ANSI_D, kVK_ANSI_O, kVK_ANSI_N,
+ kVK_ANSI_E};
+
+const unsigned int kNativeKeyEscape = kVK_Escape;
+const unsigned int kNativeKeyTab = kVK_Tab;
+
+#endif
+
+#if defined(OS_MAC) || defined(OS_LINUX)
+
+const unsigned int kKeyTestCodes[] = {VKEY_D, VKEY_O, VKEY_N, VKEY_E};
+
+#endif
+
+// test type
+enum OSRTestType {
+ // IsWindowRenderingDisabled should be true
+ OSR_TEST_IS_WINDOWLESS,
+ // focusing webview, LI00 will get red & repainted
+ OSR_TEST_FOCUS,
+ // tab key traversal should iterate the focus across HTML element and
+ // subsequently after last element CefFocusHandler::OnTakeFocus should be
+ // called to allow giving focus to the next component.
+ OSR_TEST_TAKE_FOCUS,
+ // send focus event should set focus on the webview
+ OSR_TEST_GOT_FOCUS,
+ // loading webview should trigger a full paint (L01)
+ OSR_TEST_PAINT,
+ // same as OSR_TEST_PAINT but with alpha values
+ OSR_TEST_TRANSPARENCY,
+ // moving mouse over L02, OnCursorChange will be called
+ OSR_TEST_CURSOR,
+ // moving mouse on L03, OnPaint will be called for its bounding rectangle
+ OSR_TEST_MOUSE_MOVE,
+ // right clicking an element (L04), OnBeforeContextMenu should be called
+ OSR_TEST_CLICK_RIGHT,
+ // right clicking an element (L04), context menu will query screen point
+ OSR_TEST_SCREEN_POINT,
+ // left click in text box should query repainting edit box area
+ OSR_TEST_CLICK_LEFT,
+ // Resize should trigger a full repaint with the new given size
+ OSR_TEST_RESIZE,
+ // Invalidate should trigger repaint synchronously
+ OSR_TEST_INVALIDATE,
+ // write into editbox LI08, click to navigate on LI09
+ OSR_TEST_KEY_EVENTS,
+ // mouse over LI10 will show a tooltip
+ OSR_TEST_TOOLTIP,
+ // mouse wheel will trigger a scroll event
+ OSR_TEST_SCROLLING,
+ // Right click will trigger a context menu, and on destroying the test, it
+ // should not crash
+ OSR_TEST_CONTEXT_MENU,
+ // In certain scenarios, the quick menu should be shown instead of the context
+ // menu
+ OSR_TEST_QUICK_MENU,
+ // clicking on dropdown box, PET_POPUP OnPaint is triggered
+ OSR_TEST_POPUP_PAINT,
+ // clicking on dropdown box, a popup will show up
+ OSR_TEST_POPUP_SHOW,
+ // clicking on dropdown box, OnPopupSize should be called
+ OSR_TEST_POPUP_SIZE,
+ // taking focus away from the webview, will close popup
+ OSR_TEST_POPUP_HIDE_ON_BLUR,
+ // clicking outside the popup widget will close popup
+ OSR_TEST_POPUP_HIDE_ON_CLICK,
+ // scrolling outside the popup widget will close popup
+ OSR_TEST_POPUP_HIDE_ON_SCROLL,
+ // pressing ESC will close popup
+ OSR_TEST_POPUP_HIDE_ON_ESC,
+ // scrolling inside the popup should trigger repaint for popup area
+ OSR_TEST_POPUP_SCROLL_INSIDE,
+ // clicking and moving the mouse will call StartDragging
+ OSR_TEST_DRAG_DROP_START_DRAGGING,
+ // starting dragging over the drop region will call UpdateDragCursor
+ OSR_TEST_DRAG_DROP_UPDATE_CURSOR,
+ // dropping element inside drop region will move the element
+ OSR_TEST_DRAG_DROP_DROP,
+ // IMESetComposition will update the composition range
+ OSR_TEST_IME_SET_COMPOSITION,
+ // IMECommitText inserts the specified text
+ OSR_TEST_IME_COMMIT_TEXT,
+ // IMEFinishComposition will commit the text present composition text
+ OSR_TEST_IME_FINISH_COMPOSITION,
+ // IMECancelComposition will update the composition range
+ OSR_TEST_IME_CANCEL_COMPOSITION,
+ // text selection range changed
+ OSR_TEST_TEXT_SELECTION_CHANGE,
+ // clicking on text input will call OnVirtualKeyboardRequested
+ OSR_TEST_VIRTUAL_KEYBOARD,
+ // touchStart event is triggered and contains the touch point count
+ OSR_TEST_TOUCH_START,
+ // touchMove event is triggered and contains the changed touch points
+ OSR_TEST_TOUCH_MOVE,
+ // touchEnd is triggered on completion
+ OSR_TEST_TOUCH_END,
+ // touchCancel is triggered on dismissing
+ OSR_TEST_TOUCH_CANCEL,
+ // CEF_POINTER_TYPE_PEN is mapped to pen pointer event
+ OSR_TEST_PEN,
+ // Define the range for popup tests.
+ OSR_TEST_POPUP_FIRST = OSR_TEST_POPUP_PAINT,
+ OSR_TEST_POPUP_LAST = OSR_TEST_POPUP_SCROLL_INSIDE,
+};
+
+// Used in the browser process.
+class OSRTestHandler : public RoutingTestHandler,
+ public CefFocusHandler,
+ public CefRenderHandler,
+ public CefContextMenuHandler {
+ public:
+ OSRTestHandler(OSRTestType test_type, float scale_factor)
+ : test_type_(test_type), scale_factor_(scale_factor) {}
+
+ // TestHandler methods
+ void RunTest() override {
+ CreateOSRBrowser(kTestUrl);
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout();
+ }
+
+ void OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
+ if (test_type_ == OSR_TEST_IS_WINDOWLESS) {
+ EXPECT_TRUE(browser->GetHost()->IsWindowRenderingDisabled());
+ DestroySucceededTestSoon();
+ }
+ RoutingTestHandler::OnAfterCreated(browser);
+ }
+
+ void OnLoadStart(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ TransitionType transition_type) override {
+#if VERBOSE_DEBUGGING
+ LOG(INFO) << "OnLoadStart started=" << started()
+ << " finished=" << finished();
+#endif
+
+ // Only interested in the 2nd+ load.
+ if (!started()) {
+ return;
+ }
+
+ switch (test_type_) {
+ case OSR_TEST_KEY_EVENTS: {
+ const std::string& expected_url =
+ std::string(kTestUrl) + "?k=" + kKeyTestWord;
+ EXPECT_STREQ(expected_url.c_str(), frame->GetURL().ToString().c_str());
+ DestroySucceededTestSoon();
+ } break;
+ case OSR_TEST_IME_COMMIT_TEXT: {
+ const std::string& expected_url =
+ std::string(kTestUrl) + "?k=osrimecommit";
+ EXPECT_STREQ(expected_url.c_str(), frame->GetURL().ToString().c_str());
+ DestroySucceededTestSoon();
+ } break;
+ case OSR_TEST_IME_FINISH_COMPOSITION: {
+ const std::string& expected_url =
+ std::string(kTestUrl) + "?k=" + kKeyTestWord;
+ EXPECT_STREQ(expected_url.c_str(), frame->GetURL().ToString().c_str());
+ DestroySucceededTestSoon();
+ } break;
+ case OSR_TEST_IME_CANCEL_COMPOSITION: {
+ const std::string& expected_url = std::string(kTestUrl) + "?k=";
+ EXPECT_STREQ(expected_url.c_str(), frame->GetURL().ToString().c_str());
+ DestroySucceededTestSoon();
+ } break;
+ default:
+ // Intentionally left blank
+ break;
+ }
+ }
+
+ void OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int httpStatusCode) override {
+#if VERBOSE_DEBUGGING
+ LOG(INFO) << "OnLoadEnd started=" << started()
+ << " finished=" << finished();
+#endif
+
+ // Only interested in the first load.
+ if (started()) {
+ return;
+ }
+
+ if (test_type_ >= OSR_TEST_POPUP_FIRST &&
+ test_type_ <= OSR_TEST_POPUP_LAST) {
+ StartTest();
+ ExpandDropDown();
+ return;
+ }
+
+ switch (test_type_) {
+ case OSR_TEST_TOOLTIP:
+ if (StartTest()) {
+ CefMouseEvent mouse_event;
+ const CefRect& expected_rect = GetElementBounds("LI10");
+ mouse_event.x = MiddleX(expected_rect);
+ mouse_event.y = MiddleY(expected_rect);
+ mouse_event.modifiers = 0;
+ browser->GetHost()->SendMouseMoveEvent(mouse_event, false);
+ }
+ break;
+ case OSR_TEST_FOCUS:
+ if (StartTest()) {
+ // body.onfocus will make LI00 red
+ browser->GetHost()->SetFocus(true);
+ }
+ break;
+ case OSR_TEST_TAKE_FOCUS:
+ if (StartTest()) {
+ // Give focus to the last input element.
+ browser->GetMainFrame()->ExecuteJavaScript(
+ "document.getElementById('email').focus()",
+ browser->GetMainFrame()->GetURL(), 0);
+
+ // Tab traversal across HTML element.
+#if defined(OS_WIN)
+ CefPostDelayedTask(TID_UI,
+ base::BindOnce(&OSRTestHandler::SendKeyEvent, this,
+ browser, VK_TAB),
+ 50);
+#elif defined(OS_MAC) || defined(OS_LINUX)
+ CefPostDelayedTask(TID_UI,
+ base::BindOnce(&OSRTestHandler::SendKeyEvent, this,
+ browser, kNativeKeyTab, VKEY_TAB),
+ 50);
+#else
+#error "Unsupported platform"
+#endif
+ }
+ break;
+ case OSR_TEST_GOT_FOCUS:
+ if (StartTest()) {
+ browser->GetHost()->SetFocus(true);
+ }
+ break;
+ case OSR_TEST_CURSOR:
+ if (StartTest()) {
+ // enter mouse in the LI2 element having hand cursor
+ CefMouseEvent mouse_event;
+ const CefRect& expected_rect = GetElementBounds("LI02");
+ mouse_event.x = MiddleX(expected_rect);
+ mouse_event.y = MiddleY(expected_rect);
+ browser->GetHost()->SendMouseMoveEvent(mouse_event, false);
+ }
+ break;
+ case OSR_TEST_MOUSE_MOVE:
+ if (StartTest()) {
+ CefMouseEvent mouse_event;
+ const CefRect& expected_rect = GetElementBounds("LI03");
+ mouse_event.x = MiddleX(expected_rect);
+ mouse_event.y = MiddleY(expected_rect);
+ mouse_event.modifiers = 0;
+ browser->GetHost()->SendMouseMoveEvent(mouse_event, false);
+ }
+ break;
+ case OSR_TEST_CLICK_RIGHT:
+ case OSR_TEST_SCREEN_POINT:
+ case OSR_TEST_CONTEXT_MENU:
+ if (StartTest()) {
+ CefMouseEvent mouse_event;
+ const CefRect& expected_rect = GetElementBounds("LI04");
+ mouse_event.x = MiddleX(expected_rect);
+ mouse_event.y = MiddleY(expected_rect);
+ mouse_event.modifiers = 0;
+ SendMouseClickEvent(browser, mouse_event, MBT_RIGHT);
+ }
+ break;
+ case OSR_TEST_QUICK_MENU:
+ if (StartTest()) {
+ CefTouchEvent touch_event_pressed;
+ touch_event_pressed.type = CEF_TET_PRESSED;
+ const CefRect& expected_rect = GetElementBounds("quickmenu");
+ touch_event_pressed.x = MiddleX(expected_rect);
+ touch_event_pressed.y = MiddleY(expected_rect);
+ browser->GetHost()->SendTouchEvent(touch_event_pressed);
+ }
+ break;
+ case OSR_TEST_CLICK_LEFT:
+ if (StartTest()) {
+ CefMouseEvent mouse_event;
+ const CefRect& expected_rect = GetElementBounds("LI00");
+ mouse_event.x = MiddleX(expected_rect);
+ mouse_event.y = MiddleY(expected_rect);
+ mouse_event.modifiers = 0;
+ SendMouseClickEvent(browser, mouse_event);
+ }
+ break;
+ case OSR_TEST_DRAG_DROP_START_DRAGGING:
+ case OSR_TEST_DRAG_DROP_UPDATE_CURSOR:
+ case OSR_TEST_DRAG_DROP_DROP: {
+ // trigger the StartDragging event
+ if (StartTest()) {
+ // move the mouse over the element to drag
+ CefMouseEvent mouse_event;
+ const CefRect& dragdiv = GetElementBounds("dragdiv");
+ mouse_event.x = MiddleX(dragdiv);
+ mouse_event.y = MiddleY(dragdiv);
+ mouse_event.modifiers = 0;
+
+ // The div drag point must be visible.
+ EXPECT_LT(mouse_event.y, kOsrHeight);
+
+ browser->GetHost()->SendMouseMoveEvent(mouse_event, false);
+ // click on the element to drag
+ mouse_event.modifiers = EVENTFLAG_LEFT_MOUSE_BUTTON;
+ CefPostDelayedTask(
+ TID_UI,
+ base::BindOnce(&CefBrowserHost::SendMouseClickEvent,
+ browser->GetHost(), mouse_event, MBT_LEFT, false,
+ 1),
+ 50);
+ // move the mouse to start dragging
+ mouse_event.x -= 5;
+ mouse_event.y -= 5;
+ CefPostDelayedTask(
+ TID_UI,
+ base::BindOnce(&CefBrowserHost::SendMouseMoveEvent,
+ browser->GetHost(), mouse_event, false),
+ 100);
+ }
+ } break;
+ case OSR_TEST_KEY_EVENTS:
+ case OSR_TEST_IME_COMMIT_TEXT:
+ case OSR_TEST_IME_FINISH_COMPOSITION:
+ case OSR_TEST_IME_CANCEL_COMPOSITION:
+ case OSR_TEST_IME_SET_COMPOSITION:
+ if (StartTest()) {
+ // Results in a call to OnQuery.
+ FocusEditBox(browser);
+ }
+ break;
+ case OSR_TEST_TEXT_SELECTION_CHANGE: {
+ // trigger the text selection changed event
+ if (StartTest()) {
+ // click inside list element so text range will be selected.
+ CefMouseEvent mouse_event;
+ const CefRect& expected_rect = GetElementBounds("LI11");
+ mouse_event.x = MiddleX(expected_rect);
+ mouse_event.y = MiddleY(expected_rect);
+ mouse_event.modifiers = 0;
+ SendMouseClickEvent(browser, mouse_event);
+ }
+ } break;
+ case OSR_TEST_VIRTUAL_KEYBOARD: {
+ if (StartTest()) {
+ CefMouseEvent mouse_event;
+ const CefRect& input = GetElementBounds("email");
+ mouse_event.x = MiddleX(input);
+ mouse_event.y = MiddleY(input);
+ mouse_event.modifiers = 0;
+ SendMouseClickEvent(browser, mouse_event);
+ }
+ } break;
+ case OSR_TEST_TOUCH_START:
+ case OSR_TEST_TOUCH_MOVE:
+ case OSR_TEST_TOUCH_END:
+ case OSR_TEST_TOUCH_CANCEL: {
+ // We trigger a valid Touch workflow sequence and close the tests
+ // at seperate points for the 4 cases
+ if (StartTest()) {
+ const CefRect& touchdiv = GetElementBounds("touchdiv");
+ std::vector<CefTouchEvent> touch_events;
+
+ // click inside edit box so that text could be entered
+ CefTouchEvent touch_event1;
+ touch_event1.id = 0;
+ touch_event1.x = MiddleX(touchdiv) - 45;
+ touch_event1.y = MiddleY(touchdiv);
+ touch_event1.modifiers = 0;
+ touch_event1.type = CEF_TET_PRESSED;
+ touch_events.push_back(touch_event1);
+
+ CefTouchEvent touch_event2;
+ touch_event2.id = 1;
+ touch_event2.x = MiddleX(touchdiv) + 45;
+ touch_event2.y = MiddleY(touchdiv);
+ touch_event2.modifiers = 0;
+ touch_event2.type = CEF_TET_PRESSED;
+ touch_events.push_back(touch_event2);
+
+ if (test_type_ >= OSR_TEST_TOUCH_MOVE) {
+ // Move the Touch fingers closer
+ touch_event1.type = touch_event2.type = CEF_TET_MOVED;
+ for (size_t i = 0; i < 40; i++) {
+ touch_event1.x++;
+ touch_event2.x--;
+ touch_events.push_back(touch_event1);
+ touch_events.push_back(touch_event2);
+ }
+ }
+
+ // Now release the Touch fingers or cancel them
+ if (test_type_ == OSR_TEST_TOUCH_CANCEL) {
+ touch_event1.type = touch_event2.type = CEF_TET_CANCELLED;
+ } else {
+ touch_event1.type = touch_event2.type = CEF_TET_RELEASED;
+ }
+ touch_events.push_back(touch_event1);
+ touch_events.push_back(touch_event2);
+
+ CefPostDelayedTask(TID_UI,
+ base::BindOnce(&OSRTestHandler::SendTouchEvents,
+ this, std::move(touch_events)),
+ 100);
+ }
+ } break;
+ case OSR_TEST_PEN: {
+ if (StartTest()) {
+ const CefRect& pointerdiv = GetElementBounds("pointerdiv");
+ std::vector<CefTouchEvent> touch_events;
+
+ CefTouchEvent touch_event;
+ touch_event.x = MiddleX(pointerdiv) - 45;
+ touch_event.y = MiddleY(pointerdiv);
+ touch_event.type = CEF_TET_PRESSED;
+ touch_event.pointer_type = CEF_POINTER_TYPE_PEN;
+
+ touch_events.push_back(touch_event);
+
+ touch_event.type = CEF_TET_MOVED;
+ for (size_t i = 0; i < 40; i++) {
+ touch_event.x++;
+ touch_events.push_back(touch_event);
+ }
+
+ touch_event.type = CEF_TET_RELEASED;
+ touch_events.push_back(touch_event);
+
+ CefPostDelayedTask(TID_UI,
+ base::BindOnce(&OSRTestHandler::SendTouchEvents,
+ this, std::move(touch_events)),
+ 100);
+ }
+ } break;
+ default:
+ break;
+ }
+ }
+
+ bool OnQuery(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int64 query_id,
+ const CefString& request,
+ bool persistent,
+ CefRefPtr<Callback> callback) override {
+ EXPECT_TRUE(browser.get());
+
+ const std::string& messageStr = request;
+ if (messageStr.length() > 0 && messageStr[0] == '{') {
+ return handleBoundsQuery(browser, frame, query_id, request, persistent,
+ callback);
+ }
+
+#if VERBOSE_DEBUGGING
+ LOG(INFO) << "OnQuery message=" << messageStr;
+#endif
+
+ switch (test_type_) {
+ case OSR_TEST_FOCUS:
+ if (messageStr == "osrfocus") {
+ DestroySucceededTestSoon();
+ }
+ break;
+ case OSR_TEST_CLICK_LEFT:
+ if (messageStr == "osrclick0") {
+ DestroySucceededTestSoon();
+ }
+ break;
+ case OSR_TEST_MOUSE_MOVE:
+ if (messageStr == "osrmousemove") {
+ DestroySucceededTestSoon();
+ }
+ break;
+ case OSR_TEST_DRAG_DROP_DROP:
+ if (messageStr == "osrdrop") {
+ DestroySucceededTestSoon();
+ }
+ break;
+ case OSR_TEST_KEY_EVENTS:
+ if (messageStr == "osrfocuseditbox") {
+ SendKeyEvents();
+ }
+ break;
+ case OSR_TEST_IME_COMMIT_TEXT:
+ if (messageStr == "osrfocuseditbox") {
+ SendIMECommitText();
+ }
+ break;
+ case OSR_TEST_IME_FINISH_COMPOSITION:
+ if (messageStr == "osrfocuseditbox") {
+ SendIMEFinishComposition();
+ }
+ break;
+ case OSR_TEST_IME_CANCEL_COMPOSITION:
+ if (messageStr == "osrfocuseditbox") {
+ SendIMECancelComposition();
+ }
+ break;
+ case OSR_TEST_IME_SET_COMPOSITION:
+ if (messageStr == "osrfocuseditbox") {
+ SendIMESetComposition();
+ }
+ break;
+ case OSR_TEST_TOUCH_START:
+ case OSR_TEST_TOUCH_MOVE:
+ case OSR_TEST_TOUCH_END:
+ case OSR_TEST_TOUCH_CANCEL: {
+ switch (touch_state_) {
+ case CEF_TET_CANCELLED: {
+ // The first message expected is touchstart.
+ // We expect multitouch, so touches length should be 2.
+ // Ignore intermediate touch start events.
+ if (messageStr == "osrtouchstart1") {
+ break;
+ }
+ EXPECT_STREQ(messageStr.c_str(), "osrtouchstart2");
+ // Close Touch Start Tests.
+ if (test_type_ == OSR_TEST_TOUCH_START) {
+ DestroySucceededTestSoon();
+ touch_state_ = CEF_TET_RELEASED;
+ } else {
+ touch_state_ = CEF_TET_PRESSED;
+ }
+ } break;
+ case CEF_TET_PRESSED: {
+ // Touch Move include the touches that changed, should be 2.
+ EXPECT_STREQ(messageStr.c_str(), "osrtouchmove2");
+ if (test_type_ == OSR_TEST_TOUCH_MOVE) {
+ DestroySucceededTestSoon();
+ touch_state_ = CEF_TET_RELEASED;
+ } else {
+ touch_state_ = CEF_TET_MOVED;
+ }
+ } break;
+ case CEF_TET_MOVED: {
+ // There might be multiple touchmove events, ignore.
+ if (messageStr != "osrtouchmove2") {
+ if (test_type_ == OSR_TEST_TOUCH_END) {
+ EXPECT_STREQ(messageStr.c_str(), "osrtouchend");
+ DestroySucceededTestSoon();
+ touch_state_ = CEF_TET_RELEASED;
+ } else if (test_type_ == OSR_TEST_TOUCH_CANCEL) {
+ EXPECT_STREQ(messageStr.c_str(), "osrtouchcancel");
+ DestroySucceededTestSoon();
+ touch_state_ = CEF_TET_RELEASED;
+ }
+ }
+ } break;
+ default:
+ break;
+ }
+ } break;
+ case OSR_TEST_PEN: {
+ switch (touch_state_) {
+ case CEF_TET_CANCELLED:
+ // The first message expected is pointerdown.
+ EXPECT_STREQ(messageStr.c_str(), "osrpointerdown pen");
+ touch_state_ = CEF_TET_PRESSED;
+ break;
+ case CEF_TET_PRESSED:
+ EXPECT_STREQ(messageStr.c_str(), "osrpointermove pen");
+ touch_state_ = CEF_TET_MOVED;
+ break;
+ case CEF_TET_MOVED:
+ // There might be multiple pointermove events, ignore.
+ if (messageStr != "osrpointermove pen") {
+ EXPECT_STREQ(messageStr.c_str(), "osrpointerup pen");
+ DestroySucceededTestSoon();
+ }
+ break;
+ default:
+ break;
+ }
+ } break;
+ default:
+ // Intentionally left blank
+ break;
+ }
+ callback->Success("");
+ return true;
+ }
+
+ bool handleBoundsQuery(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int64 query_id,
+ const CefString& request,
+ bool persistent,
+ CefRefPtr<Callback> callback) {
+ CefRefPtr<CefValue> jsonObj = CefParseJSON(request, JSON_PARSER_RFC);
+ if (jsonObj.get()) {
+ CefRefPtr<CefDictionaryValue> dict = jsonObj->GetDictionary();
+ const std::string& type = dict->GetString("type");
+ if (type == "ElementBounds") {
+ CefRefPtr<CefListValue> elems = dict->GetList("elems");
+
+ for (size_t i = 0; i < elems->GetSize(); i++) {
+ CefRefPtr<CefDictionaryValue> elem = elems->GetDictionary(i);
+ std::string elementId = elem->GetString("id");
+ CefRect bounds(elem->GetInt("x"), elem->GetInt("y"),
+ elem->GetInt("width"), elem->GetInt("height"));
+ element_bounds_.insert(std::make_pair(elementId, bounds));
+ }
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ // CefClient methods, providing handlers
+ CefRefPtr<CefFocusHandler> GetFocusHandler() override { return this; }
+
+ CefRefPtr<CefRenderHandler> GetRenderHandler() override { return this; }
+
+ CefRefPtr<CefContextMenuHandler> GetContextMenuHandler() override {
+ return this;
+ }
+
+ // CefResourceRequestHandler methods
+ CefRefPtr<CefResourceHandler> GetResourceHandler(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request) override {
+ std::string url = request->GetURL();
+
+ if (url.find(kTestUrl) == 0) {
+ // Show the osr test contents
+ CefRefPtr<CefStreamReader> stream =
+ client::GetBinaryResourceReader("osr_test.html");
+ return new CefStreamResourceHandler("text/html", stream);
+ }
+
+ return nullptr;
+ }
+
+ // CefRenderHandler methods
+ void GetViewRect(CefRefPtr<CefBrowser> browser, CefRect& rect) override {
+ if (test_type_ == OSR_TEST_RESIZE && started()) {
+ rect = CefRect(0, 0, kOsrWidth * 2, kOsrHeight * 2);
+ return;
+ }
+ rect = CefRect(0, 0, kOsrWidth, kOsrHeight);
+ }
+
+ bool GetScreenPoint(CefRefPtr<CefBrowser> browser,
+ int viewX,
+ int viewY,
+ int& screenX,
+ int& screenY) override {
+ if (test_type_ == OSR_TEST_SCREEN_POINT && started()) {
+ const CefRect& expected_rect = GetElementBounds("LI04");
+ EXPECT_EQ(viewX, MiddleX(expected_rect));
+ EXPECT_EQ(viewY, MiddleY(expected_rect));
+ DestroySucceededTestSoon();
+ } else if (test_type_ == OSR_TEST_CONTEXT_MENU && started()) {
+ screenX = 0;
+ screenY = 0;
+ return true;
+ }
+ // we don't want to see a contextual menu. stop here.
+ return false;
+ }
+
+ bool GetScreenInfo(CefRefPtr<CefBrowser> browser,
+ CefScreenInfo& screen_info) override {
+ screen_info.device_scale_factor = scale_factor_;
+
+ // The screen info rectangles are used by the renderer to create and
+ // position popups. If not overwritten in this function, the rectangle
+ // returned from GetViewRect will be used to popuplate them.
+ // The popup in the test fits without modifications in the test window, so
+ // setting the screen to the test window size does not affect its
+ // rectangle.
+ screen_info.rect = CefRect(0, 0, kOsrWidth, kOsrHeight);
+ screen_info.available_rect = screen_info.rect;
+ return true;
+ }
+
+ void OnPopupShow(CefRefPtr<CefBrowser> browser, bool show) override {
+#if VERBOSE_DEBUGGING
+ LOG(INFO) << "OnPopupShow show=" << show << " started=" << started()
+ << " finished=" << finished();
+#endif
+
+ if (finished()) {
+ // OnPopupShow(show=false) may arrive after DestroyTest.
+ EXPECT_FALSE(show);
+ return;
+ }
+
+ EXPECT_TRUE(started());
+
+ if (show) {
+ switch (test_type_) {
+ case OSR_TEST_POPUP_SHOW:
+ DestroySucceededTestSoon();
+ break;
+ default:
+ break;
+ }
+ } else {
+ switch (test_type_) {
+ case OSR_TEST_POPUP_HIDE_ON_BLUR:
+ case OSR_TEST_POPUP_HIDE_ON_CLICK:
+ case OSR_TEST_POPUP_HIDE_ON_ESC:
+ case OSR_TEST_POPUP_HIDE_ON_SCROLL:
+ DestroySucceededTestSoon();
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ void OnPopupSize(CefRefPtr<CefBrowser> browser,
+ const CefRect& rect) override {
+#if VERBOSE_DEBUGGING
+ LOG(INFO) << "OnPopupSize started=" << started()
+ << " finished=" << finished();
+#endif
+
+ if (finished()) {
+ // For OSR_TEST_POPUP_SHOW, OnPopupSize may arrive after DestroyTest.
+ EXPECT_EQ(OSR_TEST_POPUP_SHOW, test_type_);
+ return;
+ }
+
+ EXPECT_TRUE(started());
+
+ switch (test_type_) {
+ case OSR_TEST_POPUP_SIZE:
+ EXPECT_EQ(kExpandedSelectRect.x, rect.x);
+ EXPECT_EQ(kExpandedSelectRect.y, rect.y);
+ if (ExpectComputedPopupSize()) {
+ EXPECT_EQ(kExpandedSelectRect.width, rect.width);
+ EXPECT_EQ(kExpandedSelectRect.height, rect.height);
+ } else {
+ EXPECT_GE(rect.width, kExpandedSelectRect.width);
+ EXPECT_GE(rect.height, kExpandedSelectRect.height);
+ }
+ DestroySucceededTestSoon();
+ break;
+ default:
+ break;
+ }
+ }
+
+ void OnPaint(CefRefPtr<CefBrowser> browser,
+ PaintElementType type,
+ const RectList& dirtyRects,
+ const void* buffer,
+ int width,
+ int height) override {
+ // bitmap must as big as GetViewRect said
+ if (test_type_ != OSR_TEST_RESIZE && type == PET_VIEW) {
+ EXPECT_EQ(GetScaledInt(kOsrWidth), width);
+ EXPECT_EQ(GetScaledInt(kOsrHeight), height);
+ } else if (type == PET_POPUP) {
+ const CefRect& expanded_select_rect = GetScaledRect(kExpandedSelectRect);
+ if (ExpectComputedPopupSize()) {
+ EXPECT_EQ(expanded_select_rect.width, width);
+ EXPECT_EQ(expanded_select_rect.height, height);
+ } else {
+ EXPECT_GT(width, kExpandedSelectRect.width);
+ EXPECT_GT(height, kExpandedSelectRect.height);
+ }
+ }
+
+ EXPECT_TRUE(browser->GetHost()->IsWindowRenderingDisabled());
+
+ // start test only when painting something else then background
+ if (IsBackgroundInBuffer(
+ reinterpret_cast<const uint32*>(buffer), width * height,
+ test_type_ == OSR_TEST_TRANSPARENCY ? 0x00000000 : 0xFFFFFFFF)) {
+ return;
+ }
+
+ // Send events after the first full repaint
+ switch (test_type_) {
+ case OSR_TEST_PAINT:
+ if (StartTest()) {
+ // test that we have a full repaint
+ EXPECT_EQ(dirtyRects.size(), 1U);
+ EXPECT_TRUE(IsFullRepaint(dirtyRects[0], GetScaledInt(kOsrWidth),
+ GetScaledInt(kOsrHeight)));
+ EXPECT_EQ(0xffff7f7fU, *(reinterpret_cast<const uint32*>(buffer)));
+ DestroySucceededTestSoon();
+ }
+ break;
+ case OSR_TEST_TRANSPARENCY:
+ if (StartTest()) {
+ // test that we have a full repaint
+ EXPECT_EQ(dirtyRects.size(), 1U);
+ EXPECT_TRUE(IsFullRepaint(dirtyRects[0], GetScaledInt(kOsrWidth),
+ GetScaledInt(kOsrHeight)));
+ EXPECT_EQ(0x80800000U, *(reinterpret_cast<const uint32*>(buffer)));
+ DestroySucceededTestSoon();
+ }
+ break;
+ case OSR_TEST_RESIZE:
+ if (StartTest()) {
+ browser->GetHost()->WasResized();
+ } else {
+ // There may be some partial repaints before the full repaint at the
+ // desired size.
+ const int desired_width = GetScaledInt(kOsrWidth) * 2;
+ const int desired_height = GetScaledInt(kOsrHeight) * 2;
+
+ EXPECT_EQ(dirtyRects.size(), 1U);
+ if (width == desired_width && height == desired_height &&
+ IsFullRepaint(dirtyRects[0], width, height)) {
+ DestroySucceededTestSoon();
+ }
+ }
+ break;
+ case OSR_TEST_INVALIDATE: {
+ if (StartTest()) {
+ browser->GetHost()->Invalidate(PET_VIEW);
+ } else {
+ EXPECT_EQ(dirtyRects.size(), 1U);
+ const CefRect& expected_rect =
+ GetScaledRect(CefRect(0, 0, kOsrWidth, kOsrHeight));
+ // There may be some partial repaints before the full repaint.
+ if (dirtyRects[0] == expected_rect) {
+ DestroySucceededTestSoon();
+ }
+ }
+ break;
+ }
+ case OSR_TEST_SCROLLING: {
+ static const int deltaY = 10;
+ if (StartTest()) {
+ // scroll down once
+ CefMouseEvent mouse_event;
+ const CefRect& expected_rect = GetElementBounds("LI00");
+ mouse_event.x = MiddleX(expected_rect);
+ mouse_event.y = MiddleY(expected_rect);
+ mouse_event.modifiers = 0;
+ browser->GetHost()->SendMouseWheelEvent(mouse_event, 0, -deltaY);
+ } else {
+ EXPECT_EQ(dirtyRects.size(), 1U);
+ const CefRect& expected_rect =
+ GetScaledRect(CefRect(0, 0, kOsrWidth, kOsrHeight));
+ // There may be some partial repaints before the full repaint.
+ if (dirtyRects[0] == expected_rect) {
+ DestroySucceededTestSoon();
+ }
+ }
+ break;
+ }
+ case OSR_TEST_POPUP_HIDE_ON_CLICK:
+ // Wait for the first popup paint to occur
+ if (type == PET_POPUP) {
+ CefMouseEvent mouse_event;
+ mouse_event.x = 1;
+ mouse_event.y = 1;
+ mouse_event.modifiers = 0;
+ SendMouseClickEvent(browser, mouse_event);
+ }
+ break;
+ case OSR_TEST_POPUP_HIDE_ON_SCROLL:
+ // Wait for the first popup paint to occur
+ if (type == PET_POPUP) {
+ CefMouseEvent mouse_event;
+ mouse_event.x = mouse_event.y = 1;
+ mouse_event.modifiers = 0;
+ browser->GetHost()->SendMouseWheelEvent(mouse_event, 0, -10);
+ }
+ break;
+ case OSR_TEST_POPUP_HIDE_ON_BLUR:
+ // Wait for the first popup paint to occur
+ if (type == PET_POPUP) {
+ browser->GetHost()->SetFocus(false);
+ }
+ break;
+ case OSR_TEST_POPUP_HIDE_ON_ESC:
+ // Wait for the first popup paint to occur
+ if (type == PET_POPUP) {
+#if defined(OS_WIN)
+ SendKeyEvent(browser, VK_ESCAPE);
+#elif defined(OS_MAC) || defined(OS_LINUX)
+ SendKeyEvent(browser, kNativeKeyEscape, VKEY_ESCAPE);
+#else
+#error "Unsupported platform"
+#endif
+ }
+ break;
+ case OSR_TEST_POPUP_PAINT:
+ // Wait for the first popup paint to occur
+ if (type == PET_POPUP) {
+ EXPECT_EQ(dirtyRects.size(), 1U);
+ const CefRect& expanded_select_rect =
+ GetScaledRect(kExpandedSelectRect);
+ EXPECT_EQ(0, dirtyRects[0].x);
+ EXPECT_EQ(0, dirtyRects[0].y);
+ if (ExpectComputedPopupSize()) {
+ EXPECT_EQ(expanded_select_rect.width, dirtyRects[0].width);
+ EXPECT_EQ(expanded_select_rect.height, dirtyRects[0].height);
+ } else {
+ EXPECT_GT(dirtyRects[0].width, kExpandedSelectRect.width);
+ EXPECT_GT(dirtyRects[0].height, kExpandedSelectRect.height);
+ }
+
+ // Unselected option background color is cyan.
+ // Go down 100 pixels to skip the selected option and over 5 pixels
+ // to avoid hitting the border.
+ const uint32 offset = dirtyRects[0].width * 100 + 5;
+ EXPECT_EQ(0xff00ffff,
+ *(reinterpret_cast<const uint32*>(buffer) + offset));
+
+ if (ExpectComputedPopupSize()) {
+ EXPECT_EQ(expanded_select_rect.width, width);
+ EXPECT_EQ(expanded_select_rect.height, height);
+ } else {
+ EXPECT_GT(width, kExpandedSelectRect.width);
+ EXPECT_GT(height, kExpandedSelectRect.height);
+ }
+ DestroySucceededTestSoon();
+ }
+ break;
+ case OSR_TEST_POPUP_SCROLL_INSIDE: {
+ static enum { Started, Scrolled } scroll_inside_state = Started;
+ // Wait for the first popup paint to occur
+ if (type == PET_POPUP) {
+ if (scroll_inside_state == Started) {
+ CefMouseEvent mouse_event;
+ mouse_event.x = MiddleX(kExpandedSelectRect);
+ mouse_event.y = MiddleY(kExpandedSelectRect);
+ mouse_event.modifiers = 0;
+ browser->GetHost()->SendMouseWheelEvent(mouse_event, 0, -10);
+ scroll_inside_state = Scrolled;
+ } else if (scroll_inside_state == Scrolled) {
+ const CefRect& expanded_select_rect =
+ GetScaledRect(kExpandedSelectRect);
+ EXPECT_EQ(dirtyRects.size(), 1U);
+
+ const int scaled_int_1 = GetScaledInt(1);
+ EXPECT_NEAR(0, dirtyRects[0].x, scaled_int_1);
+ EXPECT_NEAR(0, dirtyRects[0].y, scaled_int_1);
+ if (ExpectComputedPopupSize()) {
+ EXPECT_NEAR(expanded_select_rect.width, dirtyRects[0].width,
+ scaled_int_1 * 2);
+ EXPECT_NEAR(expanded_select_rect.height, dirtyRects[0].height,
+ scaled_int_1 * 2);
+ } else {
+ EXPECT_GT(dirtyRects[0].width, kExpandedSelectRect.width);
+ EXPECT_GT(dirtyRects[0].height, kExpandedSelectRect.height);
+ }
+ DestroySucceededTestSoon();
+ }
+ }
+ } break;
+ default:
+ break;
+ }
+ }
+
+ bool OnSetFocus(CefRefPtr<CefBrowser> browser, FocusSource source) override {
+#if VERBOSE_DEBUGGING
+ LOG(INFO) << "OnSetFocus started=" << started();
+#endif
+
+ if (source == FOCUS_SOURCE_NAVIGATION) {
+ got_navigation_focus_event_.yes();
+
+ // Ignore focus from the original navigation when we're testing focus
+ // event delivery.
+ if (test_type_ == OSR_TEST_FOCUS) {
+ return true;
+ }
+ return false;
+ }
+
+ EXPECT_EQ(source, FOCUS_SOURCE_SYSTEM);
+ got_system_focus_event_.yes();
+ return false;
+ }
+
+ void OnTakeFocus(CefRefPtr<CefBrowser> browser, bool next) override {
+#if VERBOSE_DEBUGGING
+ LOG(INFO) << "OnTakeFocus next=" << next << " started=" << started();
+#endif
+
+ if (test_type_ == OSR_TEST_TAKE_FOCUS) {
+ DestroySucceededTestSoon();
+ }
+ }
+
+ void OnGotFocus(CefRefPtr<CefBrowser> browser) override {
+#if VERBOSE_DEBUGGING
+ LOG(INFO) << "OnGotFocus started=" << started();
+#endif
+
+ if (test_type_ == OSR_TEST_GOT_FOCUS) {
+ DestroySucceededTestSoon();
+ }
+ }
+
+ bool OnCursorChange(CefRefPtr<CefBrowser> browser,
+ CefCursorHandle cursor,
+ cef_cursor_type_t type,
+ const CefCursorInfo& custom_cursor_info) override {
+ if (test_type_ == OSR_TEST_CURSOR && started()) {
+ EXPECT_EQ(CT_HAND, type);
+ EXPECT_EQ(nullptr, custom_cursor_info.buffer);
+ DestroySucceededTestSoon();
+ }
+ return true;
+ }
+
+ void OnImeCompositionRangeChanged(
+ CefRefPtr<CefBrowser> browser,
+ const CefRange& range,
+ const CefRenderHandler::RectList& bounds) override {
+ if (test_type_ == OSR_TEST_IME_SET_COMPOSITION && started()) {
+ EXPECT_EQ(range.from, 0);
+ EXPECT_EQ(range.to, 1);
+ EXPECT_EQ(1U, bounds.size());
+ DestroySucceededTestSoon();
+ }
+ }
+
+ bool StartDragging(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefDragData> drag_data,
+ CefRenderHandler::DragOperationsMask allowed_ops,
+ int x,
+ int y) override {
+ if (test_type_ == OSR_TEST_DRAG_DROP_START_DRAGGING && started()) {
+ // Verify the drag image representation.
+ const CefRect& dragdiv = GetElementBounds("dragdiv");
+ EXPECT_TRUE(drag_data->HasImage());
+ CefRefPtr<CefImage> image = drag_data->GetImage();
+ EXPECT_TRUE(image.get() != nullptr);
+ if (image.get()) {
+ // Drag image height seems to always be + 1px greater than the drag
+ // rect on Linux. Therefore allow it to be +/- 1px.
+ EXPECT_NEAR(static_cast<int>(image->GetWidth()), dragdiv.width, 1);
+ EXPECT_NEAR(static_cast<int>(image->GetHeight()), dragdiv.height, 1);
+ }
+ // During testing hotspot (x, y) was (15, 23) at 1x scale and (15, 18)
+ // at 2x scale. Since the mechanism for determining this position is
+ // unclear test only that it falls within the rect boundaries.
+ CefPoint hotspot = drag_data->GetImageHotspot();
+ EXPECT_GT(hotspot.x, 0);
+ EXPECT_LE(hotspot.x, GetScaledInt(dragdiv.width));
+ EXPECT_GT(hotspot.y, 0);
+ EXPECT_LE(hotspot.y, GetScaledInt(dragdiv.height));
+
+ DestroySucceededTestSoon();
+ return false;
+ } else if ((test_type_ == OSR_TEST_DRAG_DROP_UPDATE_CURSOR ||
+ test_type_ == OSR_TEST_DRAG_DROP_DROP) &&
+ started()) {
+ // place the mouse over the drop area to trigger UpdateDragCursor
+ CefRefPtr<CefDragData> data = drag_data->Clone();
+ data->ResetFileContents();
+ CefMouseEvent ev;
+ const CefRect& dragdiv = GetElementBounds("dragdiv");
+ ev.x = MiddleX(dragdiv) - 5;
+ ev.y = MiddleY(dragdiv) - 5;
+ ev.modifiers = EVENTFLAG_LEFT_MOUSE_BUTTON;
+ browser->GetHost()->DragTargetDragEnter(data, ev, allowed_ops);
+
+ const CefRect& dropdiv = GetElementBounds("dropdiv");
+ ev.x = MiddleX(dropdiv);
+ ev.y = MiddleY(dropdiv);
+ browser->GetHost()->SendMouseMoveEvent(ev, false);
+ browser->GetHost()->DragTargetDragOver(ev, allowed_ops);
+
+ ev.x += 5;
+ ev.y += 5;
+ browser->GetHost()->SendMouseMoveEvent(ev, false);
+ browser->GetHost()->DragTargetDragOver(ev, allowed_ops);
+ return true;
+ }
+ return false;
+ }
+
+ void UpdateDragCursor(CefRefPtr<CefBrowser> browser,
+ DragOperation operation) override {
+ if (test_type_ == OSR_TEST_DRAG_DROP_UPDATE_CURSOR && started()) {
+ if (operation != DRAG_OPERATION_NONE) {
+ const CefRect& dropdiv = GetElementBounds("dropdiv");
+ browser->GetHost()->DragSourceEndedAt(
+ MiddleX(dropdiv), MiddleY(dropdiv), DRAG_OPERATION_NONE);
+ browser->GetHost()->DragSourceSystemDragEnded();
+ DestroySucceededTestSoon();
+ }
+ } else if (test_type_ == OSR_TEST_DRAG_DROP_DROP && started()) {
+ // Don't end the drag multiple times.
+ if (got_update_cursor_) {
+ return;
+ }
+ got_update_cursor_.yes();
+
+ CefMouseEvent ev;
+ const CefRect& dropdiv = GetElementBounds("dropdiv");
+ ev.x = MiddleX(dropdiv);
+ ev.y = MiddleY(dropdiv);
+ ev.modifiers = 0;
+ browser->GetHost()->SendMouseClickEvent(ev, MBT_LEFT, true, 1);
+ browser->GetHost()->DragTargetDrop(ev);
+ browser->GetHost()->DragSourceEndedAt(ev.x, ev.y, operation);
+ browser->GetHost()->DragSourceSystemDragEnded();
+ }
+ }
+
+ void OnTextSelectionChanged(CefRefPtr<CefBrowser> browser,
+ const CefString& selected_text,
+ const CefRange& selected_range) override {
+ if (test_type_ == OSR_TEST_TEXT_SELECTION_CHANGE && started()) {
+ if (!got_initial_text_selection_event_) {
+ got_initial_text_selection_event_.yes();
+ } else {
+ EXPECT_STREQ("SELECTED_TEXT_RANGE", selected_text.ToString().c_str());
+ DestroySucceededTestSoon();
+ }
+ }
+ }
+
+ void OnVirtualKeyboardRequested(CefRefPtr<CefBrowser> browser,
+ TextInputMode input_mode) override {
+ if (test_type_ == OSR_TEST_VIRTUAL_KEYBOARD && started()) {
+ if (!got_virtual_keyboard_event_.isSet()) {
+ got_virtual_keyboard_event_.yes();
+ EXPECT_EQ(CEF_TEXT_INPUT_MODE_EMAIL, input_mode);
+
+ CefMouseEvent mouse_event;
+ const CefRect& input = GetElementBounds("LI01");
+ mouse_event.x = MiddleX(input);
+ mouse_event.y = MiddleY(input);
+ mouse_event.modifiers = 0;
+ SendMouseClickEvent(browser, mouse_event);
+ } else {
+ EXPECT_EQ(CEF_TEXT_INPUT_MODE_NONE, input_mode);
+ DestroySucceededTestSoon();
+ }
+ }
+ }
+
+ bool OnTooltip(CefRefPtr<CefBrowser> browser, CefString& text) override {
+ if (test_type_ == OSR_TEST_TOOLTIP && started()) {
+ EXPECT_STREQ("EXPECTED_TOOLTIP", text.ToString().c_str());
+ DestroySucceededTestSoon();
+ }
+ return false;
+ }
+
+ void OnBeforeContextMenu(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefContextMenuParams> params,
+ CefRefPtr<CefMenuModel> model) override {
+ if (!started()) {
+ return;
+ }
+ if (test_type_ == OSR_TEST_CLICK_RIGHT) {
+ const CefRect& expected_rect = GetElementBounds("LI04");
+ EXPECT_EQ(params->GetXCoord(), MiddleX(expected_rect));
+ EXPECT_EQ(params->GetYCoord(), MiddleY(expected_rect));
+ DestroySucceededTestSoon();
+ } else if (test_type_ == OSR_TEST_CONTEXT_MENU) {
+ // This test will pass if it does not crash on destruction
+ DestroySucceededTestSoon();
+ }
+ }
+
+ bool RunContextMenu(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefContextMenuParams> params,
+ CefRefPtr<CefMenuModel> model,
+ CefRefPtr<CefRunContextMenuCallback> callback) override {
+ if (!started()) {
+ return false;
+ }
+
+ EXPECT_UI_THREAD();
+
+ auto current_browser = GetBrowser();
+ EXPECT_TRUE(current_browser->IsSame(browser));
+ EXPECT_EQ(current_browser->GetFocusedFrame()->GetIdentifier(),
+ frame->GetIdentifier());
+
+ if (test_type_ == OSR_TEST_QUICK_MENU) {
+ EXPECT_EQ(2U, got_touch_handle_enabled_ct_);
+ EXPECT_EQ(2U, got_touch_handle_size_ct_);
+ EXPECT_TRUE(got_quick_menu_);
+ EXPECT_TRUE(got_quick_menu_command_);
+ EXPECT_TRUE(got_quick_menu_dismissed_);
+ EXPECT_EQ(2U, got_touch_handle_disabled_ct_);
+ EXPECT_FALSE(got_context_menu_);
+
+ got_context_menu_.yes();
+
+ // Got all expected callbacks.
+ DestroySucceededTestSoon();
+
+ // Cancel the menu immediately.
+ callback->Cancel();
+ return true;
+ }
+
+ return false;
+ }
+
+ bool RunQuickMenu(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const CefPoint& location,
+ const CefSize& size,
+ QuickMenuEditStateFlags edit_state_flags,
+ CefRefPtr<CefRunQuickMenuCallback> callback) override {
+ if (!started()) {
+ return false;
+ }
+
+ EXPECT_UI_THREAD();
+
+ auto current_browser = GetBrowser();
+ EXPECT_TRUE(current_browser->IsSame(browser));
+ EXPECT_EQ(current_browser->GetFocusedFrame()->GetIdentifier(),
+ frame->GetIdentifier());
+
+ EXPECT_EQ(OSR_TEST_QUICK_MENU, test_type_);
+
+ EXPECT_GT(location.x, 0);
+ EXPECT_GT(location.y, 0);
+ EXPECT_GT(size.width, 0);
+ EXPECT_GT(size.height, 0);
+ EXPECT_EQ(static_cast<QuickMenuEditStateFlags>(QM_EDITFLAG_CAN_ELLIPSIS |
+ QM_EDITFLAG_CAN_COPY),
+ edit_state_flags);
+ EXPECT_TRUE(callback.get());
+
+ EXPECT_EQ(2U, got_touch_handle_enabled_ct_);
+ EXPECT_EQ(2U, got_touch_handle_size_ct_);
+ EXPECT_FALSE(got_quick_menu_);
+ EXPECT_FALSE(got_quick_menu_command_);
+ EXPECT_FALSE(got_quick_menu_dismissed_);
+ EXPECT_EQ(0U, got_touch_handle_disabled_ct_);
+ EXPECT_FALSE(got_context_menu_);
+
+ got_quick_menu_.yes();
+
+ // Proceed to OnQuickMenuCommand.
+ callback->Continue(QM_EDITFLAG_CAN_ELLIPSIS,
+ static_cast<cef_event_flags_t>(EVENTFLAG_SHIFT_DOWN));
+ return true;
+ }
+
+ bool OnQuickMenuCommand(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int command_id,
+ EventFlags event_flags) override {
+ EXPECT_UI_THREAD();
+
+ auto current_browser = GetBrowser();
+ EXPECT_TRUE(current_browser->IsSame(browser));
+ EXPECT_EQ(current_browser->GetFocusedFrame()->GetIdentifier(),
+ frame->GetIdentifier());
+
+ EXPECT_EQ(OSR_TEST_QUICK_MENU, test_type_);
+
+ // Values passed to Continue() in RunQuickMenu.
+ EXPECT_EQ(QM_EDITFLAG_CAN_ELLIPSIS, command_id);
+ EXPECT_EQ(EVENTFLAG_SHIFT_DOWN, event_flags);
+
+ EXPECT_EQ(2U, got_touch_handle_enabled_ct_);
+ EXPECT_EQ(2U, got_touch_handle_size_ct_);
+ EXPECT_TRUE(got_quick_menu_);
+ EXPECT_FALSE(got_quick_menu_command_);
+ EXPECT_FALSE(got_quick_menu_dismissed_);
+ EXPECT_EQ(0U, got_touch_handle_disabled_ct_);
+ EXPECT_FALSE(got_context_menu_);
+
+ got_quick_menu_command_.yes();
+
+ // Proceed to OnQuickMenuDismissed and RunContextMenu.
+ return false;
+ }
+
+ void OnQuickMenuDismissed(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) override {
+ EXPECT_UI_THREAD();
+
+ auto current_browser = GetBrowser();
+ EXPECT_TRUE(current_browser->IsSame(browser));
+ EXPECT_EQ(current_browser->GetFocusedFrame()->GetIdentifier(),
+ frame->GetIdentifier());
+
+ EXPECT_EQ(OSR_TEST_QUICK_MENU, test_type_);
+
+ EXPECT_EQ(2U, got_touch_handle_enabled_ct_);
+ EXPECT_EQ(2U, got_touch_handle_size_ct_);
+ EXPECT_TRUE(got_quick_menu_);
+ EXPECT_TRUE(got_quick_menu_command_);
+ EXPECT_FALSE(got_quick_menu_dismissed_);
+ EXPECT_EQ(0U, got_touch_handle_disabled_ct_);
+ EXPECT_FALSE(got_context_menu_);
+
+ EXPECT_EQ(kAllTouchHandleFlags, touch_handle_flags_);
+
+ got_quick_menu_dismissed_.yes();
+ }
+
+ void GetTouchHandleSize(CefRefPtr<CefBrowser> browser,
+ cef_horizontal_alignment_t orientation,
+ CefSize& size) override {
+ size = CefSize(24, 24);
+ got_touch_handle_size_ct_++;
+ }
+
+ void OnTouchHandleStateChanged(CefRefPtr<CefBrowser> browser,
+ const CefTouchHandleState& state) override {
+ if (!started()) {
+ return;
+ }
+
+ EXPECT_UI_THREAD();
+
+ auto current_browser = GetBrowser();
+ EXPECT_TRUE(current_browser->IsSame(browser));
+
+ if (test_type_ == OSR_TEST_QUICK_MENU) {
+ if (state.flags & CEF_THS_FLAG_ENABLED) {
+ EXPECT_EQ(state.orientation, 0);
+ EXPECT_EQ(state.origin.x, 0);
+ EXPECT_EQ(state.origin.y, 0);
+ EXPECT_EQ(state.alpha, 0);
+
+ if (state.enabled) {
+ got_touch_handle_enabled_ct_++;
+ EXPECT_FALSE(got_quick_menu_);
+ EXPECT_FALSE(got_quick_menu_command_);
+ EXPECT_FALSE(got_quick_menu_dismissed_);
+ EXPECT_EQ(0U, got_touch_handle_disabled_ct_);
+ EXPECT_FALSE(got_context_menu_);
+
+ touch_handle_flags_ |= CEF_THS_FLAG_ENABLED;
+ } else {
+ got_touch_handle_disabled_ct_++;
+ EXPECT_EQ(2U, got_touch_handle_enabled_ct_);
+ EXPECT_EQ(2U, got_touch_handle_size_ct_);
+ EXPECT_TRUE(got_quick_menu_);
+ EXPECT_TRUE(got_quick_menu_command_);
+ EXPECT_TRUE(got_quick_menu_dismissed_);
+ EXPECT_FALSE(got_context_menu_);
+ }
+ }
+ if (state.flags & CEF_THS_FLAG_ORIENTATION) {
+ EXPECT_EQ(state.enabled, false);
+ EXPECT_GE(state.orientation, 0);
+ EXPECT_EQ(state.origin.x, 0);
+ EXPECT_EQ(state.origin.y, 0);
+ EXPECT_EQ(state.alpha, 0);
+ touch_handle_flags_ |= CEF_THS_FLAG_ORIENTATION;
+ }
+ if (state.flags & CEF_THS_FLAG_ORIGIN) {
+ EXPECT_EQ(state.enabled, false);
+ EXPECT_EQ(state.orientation, 0);
+ EXPECT_GT(state.origin.x, 0);
+ EXPECT_GT(state.origin.y, 0);
+ EXPECT_EQ(state.alpha, 0);
+ touch_handle_flags_ |= CEF_THS_FLAG_ORIGIN;
+ }
+ if (state.flags & CEF_THS_FLAG_ALPHA) {
+ EXPECT_EQ(state.enabled, false);
+ EXPECT_EQ(state.orientation, 0);
+ EXPECT_EQ(state.origin.x, 0);
+ EXPECT_EQ(state.origin.y, 0);
+ EXPECT_GE(state.alpha, 0);
+ touch_handle_flags_ |= CEF_THS_FLAG_ALPHA;
+ }
+ }
+ }
+
+ // OSRTestHandler functions
+ void CreateOSRBrowser(const CefString& url) {
+ CefWindowInfo windowInfo;
+ CefBrowserSettings settings;
+
+ if (test_type_ != OSR_TEST_TRANSPARENCY) {
+ // Explicitly set an opaque background color to disable transparency.
+ settings.background_color = CefColorSetARGB(255, 255, 255, 255);
+ }
+
+#if defined(OS_WIN)
+ windowInfo.SetAsWindowless(GetDesktopWindow());
+#elif defined(OS_MAC)
+ // An actual vies is needed only for the ContextMenu test. The menu runner
+ // checks if the view is not nil before showing the context menu.
+ if (test_type_ == OSR_TEST_CONTEXT_MENU) {
+ windowInfo.SetAsWindowless(osr_unittests::GetFakeView());
+ } else {
+ windowInfo.SetAsWindowless(kNullWindowHandle);
+ }
+#elif defined(OS_LINUX)
+ windowInfo.SetAsWindowless(kNullWindowHandle);
+#else
+#error "Unsupported platform"
+#endif
+ CefBrowserHost::CreateBrowser(windowInfo, this, url, settings, nullptr,
+ nullptr);
+ }
+
+ CefRect GetScaledRect(const CefRect& rect) const {
+ return client::LogicalToDevice(rect, scale_factor_);
+ }
+
+ int GetScaledInt(int value) const {
+ return client::LogicalToDevice(value, scale_factor_);
+ }
+
+ CefRect GetElementBounds(const std::string& id) {
+ ElementBoundsMap::const_iterator it = element_bounds_.find(id);
+ if (it != element_bounds_.end()) {
+ return it->second;
+ }
+ return CefRect();
+ }
+
+ static bool IsFullRepaint(const CefRect& rc, int width, int height) {
+ return rc.width == width && rc.height == height;
+ }
+
+ static bool IsBackgroundInBuffer(const uint32* buffer,
+ size_t size,
+ uint32 rgba) {
+ for (size_t i = 0; i < size; i++) {
+ if (buffer[i] != rgba) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ static inline int MiddleX(const CefRect& rect) {
+ return rect.x + rect.width / 2;
+ }
+
+ static inline int MiddleY(const CefRect& rect) {
+ return rect.y + rect.height / 2;
+ }
+
+ bool ExpectComputedPopupSize() const {
+ // The device scale factor is ignored in Blink when computing
+ // the default form control font size (see https://crbug.com/674663#c11).
+ // This results in better font size display but also means that we won't
+ // get the expected (scaled) width/height value for non-1.0 scale factor
+ // select popups.
+ // The non-1.0 scale factor size is off by a few pixels so we can't
+ // perform an exact comparison.
+ return scale_factor_ == 1.0;
+ }
+
+ static void FocusEditBox(CefRefPtr<CefBrowser> browser) {
+ browser->GetMainFrame()->ExecuteJavaScript(
+ "document.getElementById('editbox').focus()",
+ browser->GetMainFrame()->GetURL(), 0);
+ }
+
+ static void ClickButtonToNavigate(CefRefPtr<CefBrowser> browser) {
+ browser->GetMainFrame()->ExecuteJavaScript(
+ "document.getElementById('btnnavigate').click()",
+ browser->GetMainFrame()->GetURL(), 0);
+ }
+
+ void SendKeyEvents() {
+ auto browser = GetBrowser();
+
+ // write "done" word
+ CefKeyEvent event;
+ event.is_system_key = false;
+ event.modifiers = 0;
+
+ size_t word_length = strlen(kKeyTestWord);
+ for (size_t i = 0; i < word_length; ++i) {
+#if defined(OS_WIN)
+ SendKeyEvent(browser, kKeyTestWord[i]);
+#elif defined(OS_MAC) || defined(OS_LINUX)
+ SendKeyEvent(browser, kNativeKeyTestCodes[i], kKeyTestCodes[i]);
+#else
+#error "Unsupported platform"
+#endif
+ }
+
+ ClickButtonToNavigate(browser);
+ }
+
+ void SendIMECommitText() {
+ auto browser = GetBrowser();
+
+ size_t word_length = strlen(kKeyTestWord);
+ // Add some input keys to edit box
+ for (size_t i = 0; i < word_length; ++i) {
+#if defined(OS_WIN)
+ SendKeyEvent(browser, kKeyTestWord[i]);
+#elif defined(OS_MAC) || defined(OS_LINUX)
+ SendKeyEvent(browser, kNativeKeyTestCodes[i], kKeyTestCodes[i]);
+#else
+#error "Unsupported platform"
+#endif
+ }
+ // This text should be honored instead of 'ka' added via key events
+ CefString markedText("osrimecommit");
+
+ CefRange range(0, static_cast<int>(markedText.length()));
+ browser->GetHost()->ImeCommitText(markedText, range, 0);
+
+ ClickButtonToNavigate(browser);
+ }
+
+ void SendIMEFinishComposition() {
+ auto browser = GetBrowser();
+
+ size_t word_length = strlen(kKeyTestWord);
+ // Add some input keys to edit box
+ for (size_t i = 0; i < word_length; ++i) {
+#if defined(OS_WIN)
+ SendKeyEvent(browser, kKeyTestWord[i]);
+#elif defined(OS_MAC) || defined(OS_LINUX)
+ SendKeyEvent(browser, kNativeKeyTestCodes[i], kKeyTestCodes[i]);
+#else
+#error "Unsupported platform"
+#endif
+ }
+
+ // Finish Composition should set the existing composition
+ browser->GetHost()->ImeFinishComposingText(true);
+
+ ClickButtonToNavigate(browser);
+ }
+
+ void SendIMECancelComposition() {
+ auto browser = GetBrowser();
+
+ // Add some input keys to edit box
+ CefString markedText(L"\u304B");
+ std::vector<CefCompositionUnderline> underlines;
+
+ // Use a thin black underline by default.
+ CefRange range(0, static_cast<int>(markedText.length()));
+ cef_composition_underline_t line = {range, 0xFF000000, 0, false};
+ underlines.push_back(line);
+
+ CefRange replacement_range(0, static_cast<int>(markedText.length()));
+ CefRange selection_range(0, static_cast<int>(markedText.length()));
+
+ // Composition should be updated
+ browser->GetHost()->ImeSetComposition(markedText, underlines,
+ replacement_range, selection_range);
+
+ // CancelComposition should clean up the edit text
+ browser->GetHost()->ImeCancelComposition();
+
+ ClickButtonToNavigate(browser);
+ }
+
+ void SendIMESetComposition() {
+ auto browser = GetBrowser();
+
+ // Now set some intermediate text composition
+ CefString markedText(L"\u304B");
+ std::vector<CefCompositionUnderline> underlines;
+
+ // Use a thin black underline by default.
+ CefRange range(0, static_cast<int>(markedText.length()));
+ cef_composition_underline_t line = {range, 0xFF000000, 0, false};
+ underlines.push_back(line);
+
+ CefRange replacement_range(0, static_cast<int>(markedText.length()));
+ CefRange selection_range(0, static_cast<int>(markedText.length()));
+
+ // This should update composition range and
+ // trigger the compositionRangeChanged callback
+ browser->GetHost()->ImeSetComposition(markedText, underlines,
+ replacement_range, selection_range);
+ }
+
+ void SendTouchEvents(std::vector<CefTouchEvent> touch_events) {
+ auto host = GetBrowser()->GetHost();
+ for (const auto& te : touch_events) {
+ host->SendTouchEvent(te);
+ }
+ }
+
+ void DestroySucceededTestSoon() {
+#if VERBOSE_DEBUGGING
+ LOG(INFO) << "DestroySucceededTestSoon finished=" << finished();
+#endif
+
+ if (finished()) {
+ return;
+ }
+ finished_ = true;
+ CefPostTask(TID_UI, base::BindOnce(&OSRTestHandler::DestroyTest, this));
+ }
+
+ void DestroyTest() override {
+#if VERBOSE_DEBUGGING
+ LOG(INFO) << "DestroyTest";
+#endif
+
+ // Always get the OnSetFocus call for the initial navigation.
+ EXPECT_TRUE(got_navigation_focus_event_);
+
+ if (test_type_ == OSR_TEST_FOCUS) {
+ // SetFocus is called by the system when we explicitly set the focus and
+ // when popups are dismissed.
+ EXPECT_TRUE(got_system_focus_event_);
+ } else if (test_type_ == OSR_TEST_TEXT_SELECTION_CHANGE) {
+ EXPECT_TRUE(got_initial_text_selection_event_);
+ } else {
+ EXPECT_FALSE(got_system_focus_event_);
+ }
+
+ if (test_type_ == OSR_TEST_QUICK_MENU) {
+ EXPECT_EQ(2U, got_touch_handle_enabled_ct_);
+ EXPECT_EQ(2U, got_touch_handle_size_ct_);
+ EXPECT_TRUE(got_quick_menu_);
+ EXPECT_TRUE(got_quick_menu_command_);
+ EXPECT_TRUE(got_quick_menu_dismissed_);
+ EXPECT_EQ(2U, got_touch_handle_disabled_ct_);
+ EXPECT_TRUE(got_context_menu_);
+ EXPECT_EQ(kAllTouchHandleFlags, touch_handle_flags_);
+ }
+
+ RoutingTestHandler::DestroyTest();
+ }
+
+ void ExpandDropDown() {
+#if VERBOSE_DEBUGGING
+ LOG(INFO) << "ExpandDropDown";
+#endif
+
+ EXPECT_TRUE(started());
+ EXPECT_FALSE(finished());
+
+ const CefRect& LI11select = GetElementBounds("LI11select");
+ CefMouseEvent mouse_event;
+ mouse_event.x = MiddleX(LI11select);
+ mouse_event.y = MiddleY(LI11select);
+ mouse_event.modifiers = 0;
+ SendMouseClickEvent(GetBrowser(), mouse_event);
+ }
+
+ void SendKeyEvent(CefRefPtr<CefBrowser> browser,
+#if defined(OS_LINUX) || defined(OS_MAC)
+ unsigned int native_key_code,
+#endif
+ int key_code) {
+ CefKeyEvent event;
+ event.is_system_key = false;
+ event.modifiers = 0;
+
+#if defined(OS_WIN)
+ BYTE VkCode = LOBYTE(VkKeyScanA(key_code));
+ UINT scanCode = MapVirtualKey(VkCode, MAPVK_VK_TO_VSC);
+ event.native_key_code = (scanCode << 16) | // key scan code
+ 1; // key repeat count
+ event.windows_key_code = VkCode;
+#elif defined(OS_MAC)
+ event.native_key_code = native_key_code;
+ // Note that this is only correct for lower-case characters. If |key_code|
+ // was an upper-case character then |event.character| would be the upper-
+ // case character and |event.unmodified_character| would be the lower-case
+ // character (e.g. the character without the shift modifier applied).
+ event.character = event.unmodified_character = key_code;
+#elif defined(OS_LINUX)
+ event.native_key_code = native_key_code;
+ event.windows_key_code = key_code;
+ event.character = event.unmodified_character = native_key_code;
+#else
+ NOTREACHED();
+#endif
+ event.type = KEYEVENT_RAWKEYDOWN;
+ browser->GetHost()->SendKeyEvent(event);
+
+#if defined(OS_WIN)
+ event.windows_key_code = key_code;
+#endif
+ event.type = KEYEVENT_CHAR;
+ browser->GetHost()->SendKeyEvent(event);
+
+#if defined(OS_WIN)
+ event.windows_key_code = VkCode;
+ // bits 30 and 31 should be always 1 for WM_KEYUP
+ event.native_key_code |= 0xC0000000;
+#endif
+ event.type = KEYEVENT_KEYUP;
+ browser->GetHost()->SendKeyEvent(event);
+ }
+
+ // true if the events for this test are already sent
+ bool started() const { return started_; }
+
+ // true if the exit point was reached, even the result is not
+ // the expected one
+ bool finished() const { return finished_; }
+
+ // will mark test as started and will return true only the first time
+ // it is called
+ bool StartTest() {
+ if (started_) {
+ return false;
+ }
+ started_ = true;
+ return true;
+ }
+
+ private:
+ const OSRTestType test_type_;
+ const float scale_factor_;
+
+ bool started_ = false;
+ bool finished_ = false;
+ cef_touch_event_type_t touch_state_ = CEF_TET_CANCELLED;
+
+ TrackCallback got_update_cursor_;
+ TrackCallback got_navigation_focus_event_;
+ TrackCallback got_system_focus_event_;
+ TrackCallback got_initial_text_selection_event_;
+ TrackCallback got_virtual_keyboard_event_;
+
+ uint32_t touch_handle_flags_ = 0U;
+ size_t got_touch_handle_enabled_ct_ = 0U;
+ size_t got_touch_handle_size_ct_ = 0U;
+ TrackCallback got_quick_menu_;
+ TrackCallback got_quick_menu_command_;
+ TrackCallback got_quick_menu_dismissed_;
+ size_t got_touch_handle_disabled_ct_ = 0U;
+ TrackCallback got_context_menu_;
+
+ typedef std::map<std::string, CefRect> ElementBoundsMap;
+ ElementBoundsMap element_bounds_;
+
+ IMPLEMENT_REFCOUNTING(OSRTestHandler);
+};
+
+} // namespace
+
+// generic test
+#define OSR_TEST(name, test_mode, scale_factor) \
+ TEST(OSRTest, name) { \
+ CefRefPtr<OSRTestHandler> handler = \
+ new OSRTestHandler(test_mode, scale_factor); \
+ handler->ExecuteTest(); \
+ EXPECT_TRUE(handler->finished()); \
+ ReleaseAndWaitForDestructor(handler); \
+ }
+
+// tests
+OSR_TEST(Windowless, OSR_TEST_IS_WINDOWLESS, 1.0f)
+OSR_TEST(Windowless2x, OSR_TEST_IS_WINDOWLESS, 2.0f)
+OSR_TEST(Focus, OSR_TEST_FOCUS, 1.0f)
+OSR_TEST(Focus2x, OSR_TEST_FOCUS, 2.0f)
+OSR_TEST(TakeFocus, OSR_TEST_TAKE_FOCUS, 1.0f)
+OSR_TEST(TakeFocus2x, OSR_TEST_TAKE_FOCUS, 2.0f)
+OSR_TEST(GotFocus, OSR_TEST_GOT_FOCUS, 1.0f)
+OSR_TEST(GotFocus2x, OSR_TEST_GOT_FOCUS, 2.0f)
+OSR_TEST(Paint, OSR_TEST_PAINT, 1.0f)
+OSR_TEST(Paint2x, OSR_TEST_PAINT, 2.0f)
+OSR_TEST(TransparentPaint, OSR_TEST_TRANSPARENCY, 1.0f)
+OSR_TEST(TransparentPaint2x, OSR_TEST_TRANSPARENCY, 2.0f)
+OSR_TEST(Cursor, OSR_TEST_CURSOR, 1.0f)
+OSR_TEST(Cursor2x, OSR_TEST_CURSOR, 2.0f)
+OSR_TEST(MouseMove, OSR_TEST_MOUSE_MOVE, 1.0f)
+OSR_TEST(MouseMove2x, OSR_TEST_MOUSE_MOVE, 2.0f)
+OSR_TEST(MouseRightClick, OSR_TEST_CLICK_RIGHT, 1.0f)
+OSR_TEST(MouseRightClick2x, OSR_TEST_CLICK_RIGHT, 2.0f)
+OSR_TEST(MouseLeftClick, OSR_TEST_CLICK_LEFT, 1.0f)
+OSR_TEST(MouseLeftClick2x, OSR_TEST_CLICK_LEFT, 2.0f)
+OSR_TEST(ScreenPoint, OSR_TEST_SCREEN_POINT, 1.0f)
+OSR_TEST(ScreenPoint2x, OSR_TEST_SCREEN_POINT, 2.0f)
+OSR_TEST(Resize, OSR_TEST_RESIZE, 1.0f)
+OSR_TEST(Resize2x, OSR_TEST_RESIZE, 2.0f)
+OSR_TEST(Invalidate, OSR_TEST_INVALIDATE, 1.0f)
+OSR_TEST(Invalidate2x, OSR_TEST_INVALIDATE, 2.0f)
+OSR_TEST(KeyEvents, OSR_TEST_KEY_EVENTS, 1.0f)
+OSR_TEST(KeyEvents2x, OSR_TEST_KEY_EVENTS, 2.0f)
+OSR_TEST(Tooltip, OSR_TEST_TOOLTIP, 1.0f)
+OSR_TEST(Tooltip2x, OSR_TEST_TOOLTIP, 2.0f)
+OSR_TEST(Scrolling, OSR_TEST_SCROLLING, 1.0f)
+OSR_TEST(Scrolling2x, OSR_TEST_SCROLLING, 2.0f)
+OSR_TEST(ContextMenu, OSR_TEST_CONTEXT_MENU, 1.0f)
+OSR_TEST(ContextMenu2x, OSR_TEST_CONTEXT_MENU, 2.0f)
+OSR_TEST(QuickMenu, OSR_TEST_QUICK_MENU, 1.0f)
+OSR_TEST(QuickMenu2x, OSR_TEST_CONTEXT_MENU, 2.0f)
+OSR_TEST(PopupPaint, OSR_TEST_POPUP_PAINT, 1.0f)
+OSR_TEST(PopupPaint2x, OSR_TEST_POPUP_PAINT, 2.0f)
+OSR_TEST(PopupShow, OSR_TEST_POPUP_SHOW, 1.0f)
+OSR_TEST(PopupShow2x, OSR_TEST_POPUP_SHOW, 2.0f)
+OSR_TEST(PopupSize, OSR_TEST_POPUP_SIZE, 1.0f)
+OSR_TEST(PopupSize2x, OSR_TEST_POPUP_SIZE, 2.0f)
+OSR_TEST(PopupHideOnBlur, OSR_TEST_POPUP_HIDE_ON_BLUR, 1.0f)
+OSR_TEST(PopupHideOnBlur2x, OSR_TEST_POPUP_HIDE_ON_BLUR, 2.0f)
+OSR_TEST(PopupHideOnClick, OSR_TEST_POPUP_HIDE_ON_CLICK, 1.0f)
+OSR_TEST(PopupHideOnClick2x, OSR_TEST_POPUP_HIDE_ON_CLICK, 2.0f)
+OSR_TEST(PopupHideOnScroll, OSR_TEST_POPUP_HIDE_ON_SCROLL, 1.0f)
+OSR_TEST(PopupHideOnScroll2x, OSR_TEST_POPUP_HIDE_ON_SCROLL, 2.0f)
+OSR_TEST(PopupHideOnEsc, OSR_TEST_POPUP_HIDE_ON_ESC, 1.0f)
+OSR_TEST(PopupHideOnEsc2x, OSR_TEST_POPUP_HIDE_ON_ESC, 2.0f)
+OSR_TEST(PopupScrollInside, OSR_TEST_POPUP_SCROLL_INSIDE, 1.0f)
+OSR_TEST(PopupScrollInside2x, OSR_TEST_POPUP_SCROLL_INSIDE, 2.0f)
+OSR_TEST(DragDropStartDragging, OSR_TEST_DRAG_DROP_START_DRAGGING, 1.0f)
+OSR_TEST(DragDropStartDragging2x, OSR_TEST_DRAG_DROP_START_DRAGGING, 2.0f)
+OSR_TEST(DragDropUpdateCursor, OSR_TEST_DRAG_DROP_UPDATE_CURSOR, 1.0f)
+OSR_TEST(DragDropUpdateCursor2x, OSR_TEST_DRAG_DROP_UPDATE_CURSOR, 2.0f)
+OSR_TEST(DragDropDropElement, OSR_TEST_DRAG_DROP_DROP, 1.0f)
+OSR_TEST(DragDropDropElement2x, OSR_TEST_DRAG_DROP_DROP, 2.0f)
+OSR_TEST(IMESetComposition, OSR_TEST_IME_SET_COMPOSITION, 1.0f)
+OSR_TEST(IMESetComposition2x, OSR_TEST_IME_SET_COMPOSITION, 2.0f)
+OSR_TEST(IMECommitText, OSR_TEST_IME_COMMIT_TEXT, 1.0f)
+OSR_TEST(IMECommitText2x, OSR_TEST_IME_COMMIT_TEXT, 2.0f)
+OSR_TEST(IMEFinishComposition, OSR_TEST_IME_FINISH_COMPOSITION, 1.0f)
+OSR_TEST(IMEFinishComposition2x, OSR_TEST_IME_FINISH_COMPOSITION, 2.0f)
+OSR_TEST(IMECancelComposition, OSR_TEST_IME_CANCEL_COMPOSITION, 1.0f)
+OSR_TEST(IMECancelComposition2x, OSR_TEST_IME_CANCEL_COMPOSITION, 2.0f)
+OSR_TEST(TextSelectionChanged, OSR_TEST_TEXT_SELECTION_CHANGE, 1.0f)
+OSR_TEST(TextSelectionChanged2x, OSR_TEST_TEXT_SELECTION_CHANGE, 2.0f)
+OSR_TEST(VirtualKeyboard, OSR_TEST_VIRTUAL_KEYBOARD, 1.0f)
+OSR_TEST(TouchStart, OSR_TEST_TOUCH_START, 1.0f)
+OSR_TEST(TouchStart2x, OSR_TEST_TOUCH_START, 2.0f)
+OSR_TEST(TouchMove, OSR_TEST_TOUCH_MOVE, 1.0f)
+OSR_TEST(TouchMove2x, OSR_TEST_TOUCH_MOVE, 2.0f)
+OSR_TEST(TouchEnd, OSR_TEST_TOUCH_END, 1.0f)
+OSR_TEST(TouchEnd2x, OSR_TEST_TOUCH_END, 2.0f)
+OSR_TEST(TouchCancel, OSR_TEST_TOUCH_CANCEL, 1.0f)
+OSR_TEST(TouchCancel2x, OSR_TEST_TOUCH_CANCEL, 2.0f)
+OSR_TEST(PenEvent, OSR_TEST_PEN, 1.0f)
diff --git a/tests/ceftests/os_rendering_unittest_mac.h b/tests/ceftests/os_rendering_unittest_mac.h
new file mode 100644
index 00000000..8a54bef9
--- /dev/null
+++ b/tests/ceftests/os_rendering_unittest_mac.h
@@ -0,0 +1,16 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license
+// that can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFTESTS_OS_RENDERING_UNITTEST_MAC_H_
+#define CEF_TESTS_CEFTESTS_OS_RENDERING_UNITTEST_MAC_H_
+
+#include "include/cef_base.h"
+
+namespace osr_unittests {
+
+CefWindowHandle GetFakeView();
+
+} // namespace osr_unittests
+
+#endif // CEF_TESTS_CEFTESTS_OS_RENDERING_UNITTEST_MAC_H_
diff --git a/tests/ceftests/os_rendering_unittest_mac.mm b/tests/ceftests/os_rendering_unittest_mac.mm
new file mode 100644
index 00000000..6e24dc93
--- /dev/null
+++ b/tests/ceftests/os_rendering_unittest_mac.mm
@@ -0,0 +1,18 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license
+// that can be found in the LICENSE file.
+
+#import <Cocoa/Cocoa.h>
+
+#include "tests/ceftests/os_rendering_unittest_mac.h"
+
+namespace osr_unittests {
+
+CefWindowHandle GetFakeView() {
+ NSScreen* mainScreen = [NSScreen mainScreen];
+ NSRect screenRect = [mainScreen visibleFrame];
+ NSView* fakeView = [[NSView alloc] initWithFrame:screenRect];
+ return CAST_NSVIEW_TO_CEF_WINDOW_HANDLE(fakeView);
+}
+
+} // namespace osr_unittests
diff --git a/tests/ceftests/osr_accessibility_unittest.cc b/tests/ceftests/osr_accessibility_unittest.cc
new file mode 100644
index 00000000..abb10e00
--- /dev/null
+++ b/tests/ceftests/osr_accessibility_unittest.cc
@@ -0,0 +1,463 @@
+// Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "include/base/cef_callback.h"
+#include "include/cef_accessibility_handler.h"
+#include "include/cef_parser.h"
+#include "include/cef_waitable_event.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "tests/ceftests/test_handler.h"
+#include "tests/ceftests/test_util.h"
+#include "tests/gtest/include/gtest/gtest.h"
+
+namespace {
+
+const char kTestUrl[] = "https://tests/AccessibilityTestHandler";
+const char kTipText[] = "Also known as User ID";
+
+// Default OSR widget size.
+const int kOsrWidth = 600;
+const int kOsrHeight = 400;
+
+// Test type.
+enum AccessibilityTestType {
+ // Enabling Accessibility should trigger the AccessibilityHandler callback
+ // with Accessibility tree details
+ TEST_ENABLE,
+ // Disabling Accessibility should disable accessibility notification changes
+ TEST_DISABLE,
+ // Focus change on element should trigger Accessibility focus event
+ TEST_FOCUS_CHANGE,
+ // Hide/Show etc should trigger Location Change callbacks
+ TEST_LOCATION_CHANGE
+};
+
+class AccessibilityTestHandler : public TestHandler,
+ public CefRenderHandler,
+ public CefAccessibilityHandler {
+ public:
+ AccessibilityTestHandler(const AccessibilityTestType& type)
+ : test_type_(type), edit_box_id_(-1), accessibility_disabled_(false) {}
+
+ CefRefPtr<CefAccessibilityHandler> GetAccessibilityHandler() override {
+ return this;
+ }
+
+ CefRefPtr<CefRenderHandler> GetRenderHandler() override { return this; }
+
+ // Cef Renderer Handler Methods
+ void GetViewRect(CefRefPtr<CefBrowser> browser, CefRect& rect) override {
+ rect = CefRect(0, 0, kOsrWidth, kOsrHeight);
+ }
+
+ bool GetScreenInfo(CefRefPtr<CefBrowser> browser,
+ CefScreenInfo& screen_info) override {
+ screen_info.rect = CefRect(0, 0, kOsrWidth, kOsrHeight);
+ screen_info.available_rect = screen_info.rect;
+ return true;
+ }
+
+ void OnPaint(CefRefPtr<CefBrowser> browser,
+ CefRenderHandler::PaintElementType type,
+ const CefRenderHandler::RectList& dirtyRects,
+ const void* buffer,
+ int width,
+ int height) override {
+ // Do nothing.
+ }
+
+ void RunTest() override {
+ std::string html =
+ "<html><head><title>AccessibilityTest</title></head>"
+ "<body><span id='tipspan' role='tooltip' style='color:red;"
+ "margin:20px'>";
+ html += kTipText;
+ html +=
+ "</span>"
+ "<input id='editbox' type='text' aria-describedby='tipspan' "
+ "value='editbox' size='25px'/><input id='button' type='button' "
+ "value='button' style='margin:20px'/></body></html>";
+ AddResource(kTestUrl, html, "text/html");
+
+ // Create the browser
+ CreateOSRBrowser(kTestUrl);
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout(5000);
+ }
+
+ void OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int httpStatusCode) override {
+ // Enable Accessibility
+ browser->GetHost()->SetAccessibilityState(STATE_ENABLED);
+ switch (test_type_) {
+ case TEST_ENABLE: {
+ // This should trigger OnAccessibilityTreeChange
+ // And update will be validated
+ } break;
+ case TEST_DISABLE: {
+ // Post a delayed task to disable Accessibility
+ CefPostDelayedTask(
+ TID_UI,
+ base::BindOnce(&AccessibilityTestHandler::DisableAccessibility,
+ this, browser),
+ 200);
+ } break;
+ // Delayed task will posted later after we have initial details
+ case TEST_FOCUS_CHANGE: {
+ } break;
+ case TEST_LOCATION_CHANGE: {
+ } break;
+ }
+ }
+
+ void OnAccessibilityTreeChange(CefRefPtr<CefValue> value) override {
+ switch (test_type_) {
+ case TEST_ENABLE: {
+ TestEnableAccessibilityUpdate(value);
+ } break;
+ case TEST_DISABLE: {
+ // Once Accessibility is disabled in the delayed Task
+ // We should not reach here
+ EXPECT_FALSE(accessibility_disabled_);
+ } break;
+ case TEST_LOCATION_CHANGE: {
+ // find accessibility id of the edit box, before setting focus
+ if (edit_box_id_ == -1) {
+ CefRefPtr<CefDictionaryValue> update, event;
+ GetFirstUpdateAndEvent(value, update, event);
+ EXPECT_TRUE(update.get());
+
+ // Ignore other events.
+ if (!event.get() ||
+ event->GetString("event_type") != "loadComplete") {
+ break;
+ }
+
+ SetEditBoxIdAndRect(update);
+ EXPECT_NE(edit_box_id_, -1);
+ // Post a delayed task to hide the span and trigger location change
+ CefPostDelayedTask(
+ TID_UI,
+ base::BindOnce(&AccessibilityTestHandler::HideEditBox, this,
+ GetBrowser()),
+ 200);
+ }
+ } break;
+ case TEST_FOCUS_CHANGE: {
+ // find accessibility id of the edit box, before setting focus
+ if (edit_box_id_ == -1) {
+ CefRefPtr<CefDictionaryValue> update, event;
+ GetFirstUpdateAndEvent(value, update, event);
+ EXPECT_TRUE(update.get());
+
+ // Ignore other events.
+ if (!event.get() ||
+ event->GetString("event_type") != "loadComplete") {
+ break;
+ }
+
+ // Now post a delayed task to trigger focus to edit box
+ SetEditBoxIdAndRect(update);
+ EXPECT_NE(edit_box_id_, -1);
+
+ CefPostDelayedTask(
+ TID_UI,
+ base::BindOnce(&AccessibilityTestHandler::SetFocusOnEditBox, this,
+ GetBrowser()),
+ 200);
+ } else {
+ // Retrieve the "focus" event.
+ CefRefPtr<CefDictionaryValue> event;
+ if (!GetFirstMatchingEvent(value, "focus", event)) {
+ return;
+ }
+ EXPECT_TRUE(event.get());
+
+ // Verify that focus is set to expected element edit_box.
+ EXPECT_EQ(edit_box_id_, event->GetInt("id"));
+
+ // Now Post a delayed task to destroy the test giving
+ // sufficient time for any accessibility updates to come through
+ CefPostDelayedTask(
+ TID_UI,
+ base::BindOnce(&AccessibilityTestHandler::DestroyTest, this),
+ 500);
+ }
+ } break;
+ }
+ }
+
+ void OnAccessibilityLocationChange(CefRefPtr<CefValue> value) override {
+ if (test_type_ == TEST_LOCATION_CHANGE) {
+ EXPECT_NE(edit_box_id_, -1);
+ EXPECT_TRUE(value.get());
+
+ // Change has a valid list
+ EXPECT_EQ(VTYPE_LIST, value->GetType());
+ CefRefPtr<CefListValue> list = value->GetList();
+ EXPECT_TRUE(list.get());
+
+ got_accessibility_location_change_.yes();
+ }
+
+ if (got_hide_edit_box_) {
+ // Now destroy the test.
+ CefPostTask(TID_UI,
+ base::BindOnce(&AccessibilityTestHandler::DestroyTest, this));
+ }
+ }
+
+ private:
+ void CreateOSRBrowser(const CefString& url) {
+ CefWindowInfo windowInfo;
+ CefBrowserSettings settings;
+
+#if defined(OS_WIN)
+ windowInfo.SetAsWindowless(GetDesktopWindow());
+#elif defined(OS_MAC)
+ windowInfo.SetAsWindowless(kNullWindowHandle);
+#elif defined(OS_LINUX)
+ windowInfo.SetAsWindowless(kNullWindowHandle);
+#else
+#error "Unsupported platform"
+#endif
+ CefBrowserHost::CreateBrowser(windowInfo, this, url, settings, nullptr,
+ nullptr);
+ }
+
+ void HideEditBox(CefRefPtr<CefBrowser> browser) {
+ // Hide the edit box.
+ // This should trigger Location update if enabled
+ browser->GetMainFrame()->ExecuteJavaScript(
+ "document.getElementById('editbox').style.display = 'none';", kTestUrl,
+ 0);
+
+ got_hide_edit_box_.yes();
+ }
+
+ void SetFocusOnEditBox(CefRefPtr<CefBrowser> browser) {
+ // Set focus on edit box
+ // This should trigger accessibility update if enabled
+ browser->GetMainFrame()->ExecuteJavaScript(
+ "document.getElementById('editbox').focus();", kTestUrl, 0);
+ }
+
+ void DisableAccessibility(CefRefPtr<CefBrowser> browser) {
+ browser->GetHost()->SetAccessibilityState(STATE_DISABLED);
+ accessibility_disabled_ = true;
+ // Set focus on edit box
+ SetFocusOnEditBox(browser);
+
+ // Now Post a delayed task to destroy the test
+ // giving sufficient time for any accessibility updates to come through
+ CefPostDelayedTask(
+ TID_UI, base::BindOnce(&AccessibilityTestHandler::DestroyTest, this),
+ 500);
+ }
+
+ static CefRefPtr<CefListValue> GetUpdateList(CefRefPtr<CefValue> value) {
+ EXPECT_TRUE(value.get());
+ EXPECT_EQ(value->GetType(), VTYPE_DICTIONARY);
+ CefRefPtr<CefDictionaryValue> topLevel = value->GetDictionary();
+ EXPECT_TRUE(topLevel.get());
+
+ return topLevel->GetList("updates");
+ }
+
+ static size_t GetUpdateListSize(CefRefPtr<CefValue> value) {
+ CefRefPtr<CefListValue> updates = GetUpdateList(value);
+ if (updates) {
+ return updates->GetSize();
+ }
+ return 0U;
+ }
+
+ static CefRefPtr<CefDictionaryValue> GetUpdateValue(CefRefPtr<CefValue> value,
+ size_t index) {
+ CefRefPtr<CefListValue> updates = GetUpdateList(value);
+ if (!updates) {
+ return nullptr;
+ }
+ EXPECT_LT(index, updates->GetSize());
+ CefRefPtr<CefDictionaryValue> update = updates->GetDictionary(index);
+ EXPECT_TRUE(update);
+ return update;
+ }
+
+ static CefRefPtr<CefListValue> GetEventList(CefRefPtr<CefValue> value) {
+ EXPECT_TRUE(value.get());
+ EXPECT_EQ(value->GetType(), VTYPE_DICTIONARY);
+ CefRefPtr<CefDictionaryValue> topLevel = value->GetDictionary();
+ EXPECT_TRUE(topLevel.get());
+
+ return topLevel->GetList("events");
+ }
+
+ static size_t GetEventListSize(CefRefPtr<CefValue> value) {
+ CefRefPtr<CefListValue> events = GetEventList(value);
+ if (events) {
+ return events->GetSize();
+ }
+ return 0U;
+ }
+
+ static CefRefPtr<CefDictionaryValue> GetEventValue(CefRefPtr<CefValue> value,
+ size_t index) {
+ CefRefPtr<CefListValue> events = GetEventList(value);
+ if (!events) {
+ return nullptr;
+ }
+ EXPECT_LT(index, events->GetSize());
+ CefRefPtr<CefDictionaryValue> event = events->GetDictionary(index);
+ EXPECT_TRUE(event);
+ return event;
+ }
+
+ static void GetFirstUpdateAndEvent(CefRefPtr<CefValue> value,
+ CefRefPtr<CefDictionaryValue>& update,
+ CefRefPtr<CefDictionaryValue>& event) {
+ if (GetUpdateListSize(value) > 0U) {
+ update = GetUpdateValue(value, 0U);
+ }
+ if (GetEventListSize(value) > 0U) {
+ event = GetEventValue(value, 0U);
+ }
+ }
+
+ static bool GetFirstMatchingEvent(CefRefPtr<CefValue> value,
+ const std::string& event_type,
+ CefRefPtr<CefDictionaryValue>& event) {
+ // Return the first event that matches the requested |event_type|.
+ const size_t event_size = GetEventListSize(value);
+ for (size_t i = 0; i < event_size; ++i) {
+ CefRefPtr<CefDictionaryValue> cur_event = GetEventValue(value, i);
+ const std::string& cur_event_type = cur_event->GetString("event_type");
+ if (cur_event_type == event_type) {
+ event = cur_event;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ void TestEnableAccessibilityUpdate(CefRefPtr<CefValue> value) {
+ CefRefPtr<CefDictionaryValue> update, event;
+ GetFirstUpdateAndEvent(value, update, event);
+ EXPECT_TRUE(update.get());
+
+ // Ignore other events.
+ if (!event.get() || event->GetString("event_type") != "loadComplete") {
+ return;
+ }
+
+ // Get update and validate it has tree data
+ EXPECT_TRUE(update->GetBool("has_tree_data"));
+ CefRefPtr<CefDictionaryValue> treeData = update->GetDictionary("tree_data");
+
+ // Validate title and Url
+ EXPECT_STREQ("AccessibilityTest",
+ treeData->GetString("title").ToString().c_str());
+ EXPECT_STREQ(kTestUrl, treeData->GetString("url").ToString().c_str());
+
+ // Validate node data
+ CefRefPtr<CefListValue> nodes = update->GetList("nodes");
+ EXPECT_TRUE(nodes.get());
+ EXPECT_GT(nodes->GetSize(), 0U);
+
+ // Update has a valid root
+ CefRefPtr<CefDictionaryValue> root;
+ for (size_t index = 0; index < nodes->GetSize(); index++) {
+ CefRefPtr<CefDictionaryValue> node = nodes->GetDictionary(index);
+ if (node->GetString("role").ToString() == "rootWebArea") {
+ root = node;
+ break;
+ }
+ }
+ EXPECT_TRUE(root.get());
+
+ // One div containing the tree elements.
+ CefRefPtr<CefListValue> childIDs = root->GetList("child_ids");
+ EXPECT_TRUE(childIDs.get());
+ EXPECT_EQ(1U, childIDs->GetSize());
+
+ // Now Post a delayed task to destroy the test
+ // giving sufficient time for any accessibility updates to come through
+ CefPostDelayedTask(
+ TID_UI, base::BindOnce(&AccessibilityTestHandler::DestroyTest, this),
+ 500);
+ }
+
+ // Find Edit box Id in accessibility tree.
+ void SetEditBoxIdAndRect(CefRefPtr<CefDictionaryValue> value) {
+ EXPECT_TRUE(value.get());
+ // Validate node data.
+ CefRefPtr<CefListValue> nodes = value->GetList("nodes");
+ EXPECT_TRUE(nodes.get());
+ EXPECT_GT(nodes->GetSize(), 0U);
+
+ // Find accessibility id for the text field.
+ for (size_t index = 0; index < nodes->GetSize(); index++) {
+ CefRefPtr<CefDictionaryValue> node = nodes->GetDictionary(index);
+ if (node->GetString("role").ToString() == "textField") {
+ edit_box_id_ = node->GetInt("id");
+ CefRefPtr<CefDictionaryValue> loc = node->GetDictionary("location");
+ EXPECT_TRUE(loc.get());
+ EXPECT_GT(loc->GetDouble("x"), 0);
+ EXPECT_GT(loc->GetDouble("y"), 0);
+ EXPECT_GT(loc->GetDouble("width"), 0);
+ EXPECT_GT(loc->GetDouble("height"), 0);
+ break;
+ }
+ }
+ }
+
+ void DestroyTest() override {
+ if (test_type_ == TEST_LOCATION_CHANGE) {
+ EXPECT_GT(edit_box_id_, 0);
+ EXPECT_TRUE(got_hide_edit_box_);
+ EXPECT_TRUE(got_accessibility_location_change_);
+ }
+ TestHandler::DestroyTest();
+ }
+
+ AccessibilityTestType test_type_;
+ int edit_box_id_;
+ bool accessibility_disabled_;
+ TrackCallback got_hide_edit_box_;
+ TrackCallback got_accessibility_location_change_;
+
+ IMPLEMENT_REFCOUNTING(AccessibilityTestHandler);
+};
+
+} // namespace
+
+TEST(OSRTest, AccessibilityEnable) {
+ CefRefPtr<AccessibilityTestHandler> handler =
+ new AccessibilityTestHandler(TEST_ENABLE);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(OSRTest, AccessibilityDisable) {
+ CefRefPtr<AccessibilityTestHandler> handler =
+ new AccessibilityTestHandler(TEST_DISABLE);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(OSRTest, AccessibilityFocusChange) {
+ CefRefPtr<AccessibilityTestHandler> handler =
+ new AccessibilityTestHandler(TEST_FOCUS_CHANGE);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(OSRTest, AccessibilityLocationChange) {
+ CefRefPtr<AccessibilityTestHandler> handler =
+ new AccessibilityTestHandler(TEST_LOCATION_CHANGE);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
diff --git a/tests/ceftests/osr_display_unittest.cc b/tests/ceftests/osr_display_unittest.cc
new file mode 100644
index 00000000..05a6a04a
--- /dev/null
+++ b/tests/ceftests/osr_display_unittest.cc
@@ -0,0 +1,398 @@
+// Copyright (c) 2017 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "include/base/cef_callback.h"
+#include "include/wrapper/cef_closure_task.h"
+
+#include "tests/ceftests/routing_test_handler.h"
+#include "tests/gtest/include/gtest/gtest.h"
+
+namespace {
+
+const char kTestUrl1[] = "https://tests/DisplayTestHandler.START";
+const char kTestUrl2[] = "https://tests/DisplayTestHandler.NAVIGATE";
+const char kTestMsg[] = "DisplayTestHandler.Status";
+
+// Default OSR widget size.
+const int kOsrWidth = 600;
+const int kOsrHeight = 400;
+
+class DisplayTestHandler : public RoutingTestHandler, public CefRenderHandler {
+ public:
+ DisplayTestHandler() : status_(START) {}
+
+ CefRefPtr<CefRenderHandler> GetRenderHandler() override { return this; }
+
+ void GetViewRect(CefRefPtr<CefBrowser> browser, CefRect& rect) override {
+ rect = CefRect(0, 0, kOsrWidth, kOsrHeight);
+ }
+
+ bool GetScreenInfo(CefRefPtr<CefBrowser> browser,
+ CefScreenInfo& screen_info) override {
+ screen_info.rect = CefRect(0, 0, kOsrWidth, kOsrHeight);
+ screen_info.available_rect = screen_info.rect;
+ return true;
+ }
+
+ void OnPaint(CefRefPtr<CefBrowser> browser,
+ CefRenderHandler::PaintElementType type,
+ const CefRenderHandler::RectList& dirtyRects,
+ const void* buffer,
+ int width,
+ int height) override {
+ if (!got_paint_[status_]) {
+ got_paint_[status_].yes();
+
+ if (status_ == START) {
+ OnStartIfDone();
+ } else if (status_ == SHOW) {
+ CefPostTask(TID_UI,
+ base::BindOnce(&DisplayTestHandler::DestroyTest, this));
+ } else {
+ ADD_FAILURE();
+ }
+ }
+ }
+
+ void RunTest() override {
+ // Add the resources that we will navigate to/from.
+ AddResource(kTestUrl1, GetPageContents("Page1", "START"), "text/html");
+ AddResource(kTestUrl2, GetPageContents("Page2", "NAVIGATE"), "text/html");
+
+ // Create the browser.
+ CreateOSRBrowser(kTestUrl1);
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout(5000);
+ }
+
+ bool OnQuery(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int64 query_id,
+ const CefString& request,
+ bool persistent,
+ CefRefPtr<Callback> callback) override {
+ const std::string& request_str = request.ToString();
+ if (request_str.find(kTestMsg) == 0) {
+ const std::string& status = request_str.substr(sizeof(kTestMsg));
+ if (status == "START") {
+ got_start_msg_.yes();
+ OnStartIfDone();
+ } else if (status == "NAVIGATE") {
+ got_navigate_msg_.yes();
+ // Wait a bit to verify no OnPaint callback.
+ CefPostDelayedTask(
+ TID_UI, base::BindOnce(&DisplayTestHandler::OnNavigate, this), 250);
+ }
+ }
+ callback->Success("");
+ return true;
+ }
+
+ void DestroyTest() override {
+ EXPECT_TRUE(got_paint_[START]);
+ EXPECT_FALSE(got_paint_[NAVIGATE]);
+ EXPECT_TRUE(got_paint_[SHOW]);
+
+ EXPECT_TRUE(got_start_msg_);
+ EXPECT_TRUE(got_navigate_msg_);
+
+ EXPECT_EQ(status_, SHOW);
+
+ RoutingTestHandler::DestroyTest();
+ }
+
+ private:
+ void CreateOSRBrowser(const CefString& url) {
+ CefWindowInfo windowInfo;
+ CefBrowserSettings settings;
+
+#if defined(OS_WIN)
+ windowInfo.SetAsWindowless(GetDesktopWindow());
+#else
+ windowInfo.SetAsWindowless(kNullWindowHandle);
+#endif
+
+ CefBrowserHost::CreateBrowser(windowInfo, this, url, settings, nullptr,
+ nullptr);
+ }
+
+ std::string GetPageContents(const std::string& name,
+ const std::string& status) {
+ return "<html><body>" + name + "<script>window.testQuery({request:'" +
+ std::string(kTestMsg) + ":" + status + "'});</script></body></html>";
+ }
+
+ void OnStartIfDone() {
+ if (got_start_msg_ && got_paint_[START]) {
+ CefPostTask(TID_UI, base::BindOnce(&DisplayTestHandler::OnStart, this));
+ }
+ }
+
+ void OnStart() {
+ EXPECT_EQ(status_, START);
+
+ // Hide the browser. OnPaint should not be called again until
+ // WasHidden(false) is explicitly called.
+ GetBrowser()->GetHost()->WasHidden(true);
+ status_ = NAVIGATE;
+
+ GetBrowser()->GetMainFrame()->LoadURL(kTestUrl2);
+ }
+
+ void OnNavigate() {
+ EXPECT_EQ(status_, NAVIGATE);
+
+ // Show the browser.
+ status_ = SHOW;
+ GetBrowser()->GetHost()->WasHidden(false);
+
+ // Force a call to OnPaint.
+ GetBrowser()->GetHost()->Invalidate(PET_VIEW);
+ }
+
+ enum Status {
+ START,
+ NAVIGATE,
+ SHOW,
+ STATUS_COUNT,
+ };
+ Status status_;
+
+ TrackCallback got_paint_[STATUS_COUNT];
+ TrackCallback got_start_msg_;
+ TrackCallback got_navigate_msg_;
+
+ IMPLEMENT_REFCOUNTING(DisplayTestHandler);
+};
+
+} // namespace
+
+// Test that browser visibility is not changed due to navigation.
+TEST(OSRTest, NavigateWhileHidden) {
+ CefRefPtr<DisplayTestHandler> handler = new DisplayTestHandler();
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+namespace {
+
+const char kOsrPopupJSOtherClientMainUrl[] =
+ "http://www.tests-pjse.com/main.html";
+
+class OsrPopupJSOtherClientTestHandler : public TestHandler,
+ public CefRenderHandler {
+ public:
+ OsrPopupJSOtherClientTestHandler(CefRefPtr<CefClient> other) {
+ other_ = other;
+ }
+
+ virtual CefRefPtr<CefRenderHandler> GetRenderHandler() override {
+ return this;
+ }
+
+ virtual void GetViewRect(CefRefPtr<CefBrowser> browser,
+ CefRect& rect) override {
+ rect = CefRect(0, 0, kOsrWidth, kOsrHeight);
+ }
+
+ virtual void OnPaint(CefRefPtr<CefBrowser> browser,
+ PaintElementType type,
+ const RectList& dirtyRects,
+ const void* buffer,
+ int width,
+ int height) override {}
+
+ void RunTest() override {
+ AddResource(kOsrPopupJSOtherClientMainUrl, "<html>Main</html>",
+ "text/html");
+
+ // Create the browser.
+ CreateOSRBrowser(kOsrPopupJSOtherClientMainUrl);
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout();
+ }
+
+ bool OnBeforePopup(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const CefString& target_url,
+ const CefString& target_frame_name,
+ cef_window_open_disposition_t target_disposition,
+ bool user_gesture,
+ const CefPopupFeatures& popupFeatures,
+ CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient>& client,
+ CefBrowserSettings& settings,
+ CefRefPtr<CefDictionaryValue>& extra_info,
+ bool* no_javascript_access) override {
+#if defined(OS_WIN)
+ windowInfo.SetAsWindowless(GetDesktopWindow());
+#else
+ windowInfo.SetAsWindowless(kNullWindowHandle);
+#endif
+
+ client = other_;
+
+ got_before_popup_.yes();
+ return false;
+ }
+
+ void Close(CefRefPtr<CefBrowser> browser) {
+ browser->StopLoad();
+ CloseBrowser(browser, true);
+ }
+
+ void OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
+ TestHandler::OnAfterCreated(browser);
+ if (browser->IsPopup()) {
+ got_after_created_popup_.yes();
+ }
+ }
+
+ void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
+ bool isLoading,
+ bool canGoBack,
+ bool canGoForward) override {
+ if (isLoading) {
+ return;
+ }
+
+ if (browser->IsPopup()) {
+ got_load_end_popup_.yes();
+ CefPostDelayedTask(
+ TID_UI,
+ base::BindOnce(&OsrPopupJSOtherClientTestHandler::Close, this,
+ browser),
+ 100);
+ } else {
+ browser->GetMainFrame()->LoadURL("javascript:window.open('about:blank')");
+ }
+ }
+
+ void OnBeforeClose(CefRefPtr<CefBrowser> browser) override {
+ TestHandler::OnBeforeClose(browser);
+ other_ = nullptr;
+ if (browser->IsPopup()) {
+ got_before_close_popup_.yes();
+ DestroyTest();
+ }
+ }
+
+ private:
+ void CreateOSRBrowser(const CefString& url) {
+ CefWindowInfo windowInfo;
+ CefBrowserSettings settings;
+
+#if defined(OS_WIN)
+ windowInfo.SetAsWindowless(GetDesktopWindow());
+#else
+ windowInfo.SetAsWindowless(kNullWindowHandle);
+#endif
+
+ CefBrowserHost::CreateBrowser(windowInfo, this, url, settings, nullptr,
+ nullptr);
+ }
+
+ void DestroyTest() override {
+ EXPECT_TRUE(got_after_created_popup_);
+ EXPECT_TRUE(got_load_end_popup_);
+ EXPECT_TRUE(got_before_close_popup_);
+ EXPECT_TRUE(got_before_popup_);
+ TestHandler::DestroyTest();
+ }
+
+ TrackCallback got_before_popup_;
+ TrackCallback got_after_created_popup_;
+ TrackCallback got_load_end_popup_;
+ TrackCallback got_before_close_popup_;
+ CefRefPtr<CefClient> other_;
+
+ IMPLEMENT_REFCOUNTING(OsrPopupJSOtherClientTestHandler);
+};
+
+class OsrPopupJSOtherCefClient : public CefClient,
+ public CefLoadHandler,
+ public CefLifeSpanHandler,
+ public CefRenderHandler {
+ public:
+ OsrPopupJSOtherCefClient() { handler_ = nullptr; }
+
+ void SetHandler(CefRefPtr<OsrPopupJSOtherClientTestHandler> handler) {
+ handler_ = handler;
+ }
+
+ virtual CefRefPtr<CefLoadHandler> GetLoadHandler() override { return this; }
+
+ virtual CefRefPtr<CefRenderHandler> GetRenderHandler() override {
+ return this;
+ }
+
+ virtual CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() override {
+ return this;
+ }
+
+ virtual void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
+ bool isLoading,
+ bool canGoBack,
+ bool canGoForward) override {
+ if (handler_) {
+ handler_->OnLoadingStateChange(browser, isLoading, canGoBack,
+ canGoForward);
+ }
+ }
+
+ virtual void OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
+ handler_->OnAfterCreated(browser);
+ }
+
+ virtual void OnBeforeClose(CefRefPtr<CefBrowser> browser) override {
+ handler_->OnBeforeClose(browser);
+ handler_ = nullptr;
+ }
+
+ virtual bool OnBeforePopup(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const CefString& target_url,
+ const CefString& target_frame_name,
+ cef_window_open_disposition_t target_disposition,
+ bool user_gesture,
+ const CefPopupFeatures& popupFeatures,
+ CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient>& client,
+ CefBrowserSettings& settings,
+ CefRefPtr<CefDictionaryValue>& extra_info,
+ bool* no_javascript_access) override {
+ return true;
+ }
+
+ virtual void GetViewRect(CefRefPtr<CefBrowser> browser,
+ CefRect& rect) override {
+ rect = CefRect(0, 0, kOsrWidth, kOsrHeight);
+ }
+
+ virtual void OnPaint(CefRefPtr<CefBrowser> browser,
+ PaintElementType type,
+ const RectList& dirtyRects,
+ const void* buffer,
+ int width,
+ int height) override {}
+
+ private:
+ CefRefPtr<OsrPopupJSOtherClientTestHandler> handler_;
+
+ IMPLEMENT_REFCOUNTING(OsrPopupJSOtherCefClient);
+};
+
+} // namespace
+
+// Test creation of an OSR-popup with another client.
+TEST(OSRTest, OsrPopupJSOtherClient) {
+ CefRefPtr<OsrPopupJSOtherCefClient> client = new OsrPopupJSOtherCefClient();
+ CefRefPtr<OsrPopupJSOtherClientTestHandler> handler =
+ new OsrPopupJSOtherClientTestHandler(client);
+ client->SetHandler(handler);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
diff --git a/tests/ceftests/parser_unittest.cc b/tests/ceftests/parser_unittest.cc
new file mode 100644
index 00000000..28c5cbcb
--- /dev/null
+++ b/tests/ceftests/parser_unittest.cc
@@ -0,0 +1,496 @@
+// Copyright (c) 2011 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "include/cef_parser.h"
+#include "tests/gtest/include/gtest/gtest.h"
+
+// Create the URL using the spec.
+TEST(ParserTest, CreateURLSpec) {
+ CefURLParts parts;
+ CefString url;
+ CefString(&parts.spec)
+ .FromASCII(
+ "http://user:pass@www.example.com:88/path/"
+ "to.html?foo=test&bar=test2");
+ EXPECT_TRUE(CefCreateURL(parts, url));
+ EXPECT_STREQ(
+ "http://user:pass@www.example.com:88/path/to.html?foo=test&bar=test2",
+ url.ToString().c_str());
+}
+
+// Test that host is required.
+TEST(ParserTest, CreateURLHostRequired) {
+ CefURLParts parts;
+ CefString url;
+ CefString(&parts.scheme).FromASCII("http");
+ EXPECT_FALSE(CefCreateURL(parts, url));
+}
+
+// Test that scheme is required.
+TEST(ParserTest, CreateURLSchemeRequired) {
+ CefURLParts parts;
+ CefString url;
+ CefString(&parts.host).FromASCII("www.example.com");
+ EXPECT_FALSE(CefCreateURL(parts, url));
+}
+
+// Create the URL using scheme and host.
+TEST(ParserTest, CreateURLSchemeHost) {
+ CefURLParts parts;
+ CefString url;
+ CefString(&parts.scheme).FromASCII("http");
+ CefString(&parts.host).FromASCII("www.example.com");
+ EXPECT_TRUE(CefCreateURL(parts, url));
+ EXPECT_STREQ("http://www.example.com/", url.ToString().c_str());
+}
+
+// Create the URL using scheme, host and path.
+TEST(ParserTest, CreateURLSchemeHostPath) {
+ CefURLParts parts;
+ CefString url;
+ CefString(&parts.scheme).FromASCII("http");
+ CefString(&parts.host).FromASCII("www.example.com");
+ CefString(&parts.path).FromASCII("/path/to.html");
+ EXPECT_TRUE(CefCreateURL(parts, url));
+ EXPECT_STREQ("http://www.example.com/path/to.html", url.ToString().c_str());
+}
+
+// Create the URL using scheme, host, path and query.
+TEST(ParserTest, CreateURLSchemeHostPathQuery) {
+ CefURLParts parts;
+ CefString url;
+ CefString(&parts.scheme).FromASCII("http");
+ CefString(&parts.host).FromASCII("www.example.com");
+ CefString(&parts.path).FromASCII("/path/to.html");
+ CefString(&parts.query).FromASCII("foo=test&bar=test2");
+ EXPECT_TRUE(CefCreateURL(parts, url));
+ EXPECT_STREQ("http://www.example.com/path/to.html?foo=test&bar=test2",
+ url.ToString().c_str());
+}
+
+// Create the URL using scheme, host, path, query and Fragment
+TEST(ParserTest, CreateURLSchemeHostPathQueryFragment) {
+ CefURLParts parts;
+ CefString url;
+ CefString(&parts.scheme).FromASCII("http");
+ CefString(&parts.host).FromASCII("www.example.com");
+ CefString(&parts.path).FromASCII("/path/to.html");
+ CefString(&parts.query).FromASCII("foo=test&bar=test2");
+ CefString(&parts.fragment).FromASCII("ref");
+ EXPECT_TRUE(CefCreateURL(parts, url));
+ EXPECT_STREQ("http://www.example.com/path/to.html?foo=test&bar=test2#ref",
+ url.ToString().c_str());
+}
+
+// Create the URL using all the various components.
+TEST(ParserTest, CreateURLAll) {
+ CefURLParts parts;
+ CefString url;
+ CefString(&parts.scheme).FromASCII("http");
+ CefString(&parts.username).FromASCII("user");
+ CefString(&parts.password).FromASCII("pass");
+ CefString(&parts.host).FromASCII("www.example.com");
+ CefString(&parts.port).FromASCII("88");
+ CefString(&parts.path).FromASCII("/path/to.html");
+ CefString(&parts.query).FromASCII("foo=test&bar=test2");
+ CefString(&parts.fragment).FromASCII("ref");
+ EXPECT_TRUE(CefCreateURL(parts, url));
+ EXPECT_STREQ(
+ "http://user:pass@www.example.com:88/path/to.html?foo=test&bar=test2#ref",
+ url.ToString().c_str());
+}
+
+// Parse the URL using scheme and host.
+TEST(ParserTest, ParseURLSchemeHost) {
+ CefURLParts parts;
+ CefString url;
+ url.FromASCII("http://www.example.com");
+ EXPECT_TRUE(CefParseURL(url, parts));
+
+ CefString spec(&parts.spec);
+ EXPECT_STREQ("http://www.example.com/", spec.ToString().c_str());
+ EXPECT_EQ(0U, parts.username.length);
+ EXPECT_EQ(0U, parts.password.length);
+ CefString scheme(&parts.scheme);
+ EXPECT_STREQ("http", scheme.ToString().c_str());
+ CefString host(&parts.host);
+ EXPECT_STREQ("www.example.com", host.ToString().c_str());
+ EXPECT_EQ(0U, parts.port.length);
+ CefString origin(&parts.origin);
+ EXPECT_STREQ(origin.ToString().c_str(), "http://www.example.com/");
+ CefString path(&parts.path);
+ EXPECT_STREQ("/", path.ToString().c_str());
+ EXPECT_EQ(0U, parts.query.length);
+}
+
+// Parse the URL using scheme, host and path.
+TEST(ParserTest, ParseURLSchemeHostPath) {
+ CefURLParts parts;
+ CefString url;
+ url.FromASCII("http://www.example.com/path/to.html");
+ EXPECT_TRUE(CefParseURL(url, parts));
+
+ CefString spec(&parts.spec);
+ EXPECT_STREQ("http://www.example.com/path/to.html", spec.ToString().c_str());
+ EXPECT_EQ(0U, parts.username.length);
+ EXPECT_EQ(0U, parts.password.length);
+ CefString scheme(&parts.scheme);
+ EXPECT_STREQ("http", scheme.ToString().c_str());
+ CefString host(&parts.host);
+ EXPECT_STREQ("www.example.com", host.ToString().c_str());
+ EXPECT_EQ(0U, parts.port.length);
+ CefString origin(&parts.origin);
+ EXPECT_STREQ(origin.ToString().c_str(), "http://www.example.com/");
+ CefString path(&parts.path);
+ EXPECT_STREQ("/path/to.html", path.ToString().c_str());
+ EXPECT_EQ(0U, parts.query.length);
+}
+
+// Parse the URL using scheme, host, path and query.
+TEST(ParserTest, ParseURLSchemeHostPathQuery) {
+ CefURLParts parts;
+ CefString url;
+ url.FromASCII("http://www.example.com/path/to.html?foo=test&bar=test2");
+ EXPECT_TRUE(CefParseURL(url, parts));
+
+ CefString spec(&parts.spec);
+ EXPECT_STREQ("http://www.example.com/path/to.html?foo=test&bar=test2",
+ spec.ToString().c_str());
+ EXPECT_EQ(0U, parts.username.length);
+ EXPECT_EQ(0U, parts.password.length);
+ CefString scheme(&parts.scheme);
+ EXPECT_STREQ("http", scheme.ToString().c_str());
+ CefString host(&parts.host);
+ EXPECT_STREQ("www.example.com", host.ToString().c_str());
+ EXPECT_EQ(0U, parts.port.length);
+ CefString origin(&parts.origin);
+ EXPECT_STREQ(origin.ToString().c_str(), "http://www.example.com/");
+ CefString path(&parts.path);
+ EXPECT_STREQ("/path/to.html", path.ToString().c_str());
+ CefString query(&parts.query);
+ EXPECT_STREQ("foo=test&bar=test2", query.ToString().c_str());
+}
+
+// Parse the URL using scheme, host, path, query and fragment.
+TEST(ParserTest, ParseURLSchemeHostPathQueryFragment) {
+ CefURLParts parts;
+ CefString url;
+ url.FromASCII("http://www.example.com/path/to.html?foo=test&bar=test2#ref");
+ EXPECT_TRUE(CefParseURL(url, parts));
+
+ CefString spec(&parts.spec);
+ EXPECT_STREQ("http://www.example.com/path/to.html?foo=test&bar=test2#ref",
+ spec.ToString().c_str());
+ EXPECT_EQ(0U, parts.username.length);
+ EXPECT_EQ(0U, parts.password.length);
+ CefString scheme(&parts.scheme);
+ EXPECT_STREQ("http", scheme.ToString().c_str());
+ CefString host(&parts.host);
+ EXPECT_STREQ("www.example.com", host.ToString().c_str());
+ EXPECT_EQ(0U, parts.port.length);
+ CefString origin(&parts.origin);
+ EXPECT_STREQ(origin.ToString().c_str(), "http://www.example.com/");
+ CefString path(&parts.path);
+ EXPECT_STREQ("/path/to.html", path.ToString().c_str());
+ CefString query(&parts.query);
+ EXPECT_STREQ("foo=test&bar=test2", query.ToString().c_str());
+ CefString ref(&parts.fragment);
+ EXPECT_STREQ("ref", ref.ToString().c_str());
+}
+
+// Parse the URL using all the various components.
+TEST(ParserTest, ParseURLAll) {
+ CefURLParts parts;
+ CefString url;
+ url.FromASCII(
+ "http://user:pass@www.example.com:88/path/"
+ "to.html?foo=test&bar=test2#ref");
+ EXPECT_TRUE(CefParseURL(url, parts));
+
+ CefString spec(&parts.spec);
+ EXPECT_STREQ(
+ "http://user:pass@www.example.com:88/path/to.html?foo=test&bar=test2#ref",
+ spec.ToString().c_str());
+ CefString scheme(&parts.scheme);
+ EXPECT_STREQ("http", scheme.ToString().c_str());
+ CefString username(&parts.username);
+ EXPECT_STREQ("user", username.ToString().c_str());
+ CefString password(&parts.password);
+ EXPECT_STREQ("pass", password.ToString().c_str());
+ CefString host(&parts.host);
+ EXPECT_STREQ("www.example.com", host.ToString().c_str());
+ CefString port(&parts.port);
+ EXPECT_STREQ("88", port.ToString().c_str());
+ CefString origin(&parts.origin);
+ EXPECT_STREQ(origin.ToString().c_str(), "http://www.example.com:88/");
+ CefString path(&parts.path);
+ EXPECT_STREQ("/path/to.html", path.ToString().c_str());
+ CefString query(&parts.query);
+ EXPECT_STREQ("foo=test&bar=test2", query.ToString().c_str());
+ CefString ref(&parts.fragment);
+ EXPECT_STREQ("ref", ref.ToString().c_str());
+}
+
+// Parse an invalid URL.
+TEST(ParserTest, ParseURLInvalid) {
+ CefURLParts parts;
+ CefString url;
+ url.FromASCII("www.example.com");
+ EXPECT_FALSE(CefParseURL(url, parts));
+}
+
+// Parse a non-standard scheme.
+TEST(ParserTest, ParseURLNonStandard) {
+ CefURLParts parts;
+ CefString url;
+ url.FromASCII("custom:something%20else?foo#ref");
+ EXPECT_TRUE(CefParseURL(url, parts));
+
+ CefString spec(&parts.spec);
+ EXPECT_STREQ("custom:something%20else?foo#ref", spec.ToString().c_str());
+ EXPECT_EQ(0U, parts.username.length);
+ EXPECT_EQ(0U, parts.password.length);
+ CefString scheme(&parts.scheme);
+ EXPECT_STREQ("custom", scheme.ToString().c_str());
+ EXPECT_EQ(0U, parts.host.length);
+ EXPECT_EQ(0U, parts.port.length);
+ EXPECT_EQ(0U, parts.origin.length);
+ CefString path(&parts.path);
+ EXPECT_STREQ("something%20else", path.ToString().c_str());
+ CefString query(&parts.query);
+ EXPECT_STREQ("foo", query.ToString().c_str());
+ CefString ref(&parts.fragment);
+ EXPECT_STREQ("ref", ref.ToString().c_str());
+}
+
+// Combine and parse an absolute and relative URL.
+TEST(ParserTest, ParseAbsoluteAndRelativeURL) {
+ CefString base_url;
+ base_url.FromASCII("https://www.example.com");
+ CefString relative_url;
+ relative_url.FromASCII("/example");
+ CefString resolved_url;
+ EXPECT_TRUE(CefResolveURL(base_url, relative_url, resolved_url));
+ EXPECT_STREQ("https://www.example.com/example",
+ resolved_url.ToString().c_str());
+}
+
+TEST(ParserTest, FormatUrlForSecurityDisplay) {
+ CefString result;
+
+ // Omits the protocol if it's standard.
+ result = CefFormatUrlForSecurityDisplay("http://tests.com/foo.html");
+ EXPECT_STREQ("http://tests.com", result.ToString().c_str());
+
+ // Omits the port if it's the expected value for the protocol.
+ result = CefFormatUrlForSecurityDisplay("http://tests.com:80/foo.html");
+ EXPECT_STREQ("http://tests.com", result.ToString().c_str());
+
+ // Don't omit non-standard ports.
+ result = CefFormatUrlForSecurityDisplay("http://tests.com:8088/foo.html");
+ EXPECT_STREQ("http://tests.com:8088", result.ToString().c_str());
+
+ // Don't omit the protocol for file URLs.
+ result = CefFormatUrlForSecurityDisplay("file:///c/tests/foo.html");
+ EXPECT_STREQ("file:///c/tests/foo.html", result.ToString().c_str());
+}
+
+TEST(ParserTest, GetMimeType) {
+ CefString mime_type;
+
+ mime_type = CefGetMimeType("html");
+ EXPECT_STREQ("text/html", mime_type.ToString().c_str());
+
+ mime_type = CefGetMimeType("txt");
+ EXPECT_STREQ("text/plain", mime_type.ToString().c_str());
+
+ mime_type = CefGetMimeType("gif");
+ EXPECT_STREQ("image/gif", mime_type.ToString().c_str());
+}
+
+TEST(ParserTest, Base64Encode) {
+ const std::string& test_str_decoded = "A test string";
+ const std::string& test_str_encoded = "QSB0ZXN0IHN0cmluZw==";
+ const CefString& encoded_value =
+ CefBase64Encode(test_str_decoded.data(), test_str_decoded.size());
+ EXPECT_STREQ(test_str_encoded.c_str(), encoded_value.ToString().c_str());
+}
+
+TEST(ParserTest, Base64Decode) {
+ const std::string& test_str_decoded = "A test string";
+ const std::string& test_str_encoded = "QSB0ZXN0IHN0cmluZw==";
+ CefRefPtr<CefBinaryValue> decoded_value = CefBase64Decode(test_str_encoded);
+ EXPECT_TRUE(decoded_value.get());
+
+ const size_t decoded_size = decoded_value->GetSize();
+ EXPECT_EQ(test_str_decoded.size(), decoded_size);
+
+ std::string decoded_str;
+ decoded_str.resize(decoded_size + 1); // Include space for NUL-terminator.
+ const size_t get_data_result = decoded_value->GetData(
+ const_cast<char*>(decoded_str.data()), decoded_size, 0);
+ EXPECT_EQ(decoded_size, get_data_result);
+ EXPECT_STREQ(test_str_decoded.c_str(), decoded_str.c_str());
+}
+
+TEST(ParserTest, URIEncode) {
+ const std::string& test_str_decoded = "A test string=";
+ const std::string& test_str_encoded = "A%20test%20string%3D";
+ const CefString& encoded_value = CefURIEncode(test_str_decoded, false);
+ EXPECT_STREQ(test_str_encoded.c_str(), encoded_value.ToString().c_str());
+}
+
+TEST(ParserTest, URIEncodeWithPlusSpace) {
+ const std::string& test_str_decoded = "A test string=";
+ const std::string& test_str_encoded = "A+test+string%3D";
+ const CefString& encoded_value = CefURIEncode(test_str_decoded, true);
+ EXPECT_STREQ(test_str_encoded.c_str(), encoded_value.ToString().c_str());
+}
+
+TEST(ParserTest, URIDecode) {
+ const std::string& test_str_decoded = "A test string=";
+ const std::string& test_str_encoded = "A%20test%20string%3D";
+ const CefString& decoded_value = CefURIDecode(
+ test_str_encoded, false,
+ static_cast<cef_uri_unescape_rule_t>(
+ UU_SPACES | UU_URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS));
+ EXPECT_STREQ(test_str_decoded.c_str(), decoded_value.ToString().c_str());
+}
+
+TEST(ParserTest, URIDecodeWithPlusSpace) {
+ const std::string& test_str_decoded = "A test string=";
+ const std::string& test_str_encoded = "A+test+string%3D";
+ const CefString& decoded_value =
+ CefURIDecode(test_str_encoded, false,
+ static_cast<cef_uri_unescape_rule_t>(
+ UU_SPACES | UU_URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS |
+ UU_REPLACE_PLUS_WITH_SPACE));
+ EXPECT_STREQ(test_str_decoded.c_str(), decoded_value.ToString().c_str());
+}
+
+TEST(ParserTest, ParseJSONInvalid) {
+ const char data[] = "This is my test data";
+ CefRefPtr<CefValue> value = CefParseJSON(data, JSON_PARSER_RFC);
+ EXPECT_FALSE(value.get());
+}
+
+TEST(ParserTest, ParseJSONNull) {
+ const char data[] = "{\"key1\":null}";
+ CefRefPtr<CefValue> value = CefParseJSON(data, JSON_PARSER_RFC);
+ EXPECT_TRUE(value.get());
+ EXPECT_TRUE(value->IsValid());
+ EXPECT_TRUE(value->GetType() == VTYPE_DICTIONARY);
+ EXPECT_FALSE(value->IsOwned());
+ CefRefPtr<CefDictionaryValue> dict = value->GetDictionary();
+ CefDictionaryValue::KeyList key_list;
+ EXPECT_TRUE(dict->GetKeys(key_list));
+ EXPECT_EQ(1U, key_list.size());
+ EXPECT_EQ("key1", key_list[0].ToString());
+ EXPECT_EQ(VTYPE_NULL, dict->GetType("key1"));
+
+ // generate string from parsed result
+ CefString result = CefWriteJSON(value, JSON_WRITER_DEFAULT);
+ CefString expected_result = data;
+ EXPECT_EQ(expected_result, result);
+}
+
+TEST(ParserTest, WriteJSONBinary) {
+ const char data[] = "\00\01\02";
+ CefRefPtr<CefDictionaryValue> dict = CefDictionaryValue::Create();
+ CefRefPtr<CefBinaryValue> binary = CefBinaryValue::Create(data, sizeof(data));
+ dict->SetBinary("key1", binary);
+ CefRefPtr<CefValue> node = CefValue::Create();
+ node->SetDictionary(dict);
+ CefString result = CefWriteJSON(node, JSON_WRITER_DEFAULT);
+ CefString expect_result = "";
+ // binary data will be omitted.
+ EXPECT_EQ(expect_result, result);
+}
+
+TEST(ParserTest, ParseJSONDictionary) {
+ const char data[] = "{\"key1\":\"value1\",\"key2\":123,\"key3\":[1,2,3]}";
+ CefRefPtr<CefValue> value = CefParseJSON(data, JSON_PARSER_RFC);
+ EXPECT_TRUE(value.get());
+ EXPECT_TRUE(value->IsValid());
+ EXPECT_FALSE(value->IsOwned());
+ EXPECT_TRUE(value->GetType() == VTYPE_DICTIONARY);
+ CefRefPtr<CefDictionaryValue> dict = value->GetDictionary();
+ CefDictionaryValue::KeyList key_list;
+ EXPECT_TRUE(dict->GetKeys(key_list));
+ EXPECT_EQ(3U, key_list.size());
+ EXPECT_EQ("key1", key_list[0].ToString());
+ EXPECT_EQ("key2", key_list[1].ToString());
+ EXPECT_EQ("key3", key_list[2].ToString());
+ EXPECT_EQ(VTYPE_STRING, dict->GetType("key1"));
+ EXPECT_EQ(dict->GetString("key1"), "value1");
+ EXPECT_EQ(VTYPE_INT, dict->GetType("key2"));
+ EXPECT_EQ(123, dict->GetInt("key2"));
+ EXPECT_EQ(VTYPE_LIST, dict->GetType("key3"));
+ CefRefPtr<CefListValue> key3 = dict->GetList("key3");
+ EXPECT_TRUE(nullptr != key3);
+ EXPECT_TRUE(key3->IsValid());
+ EXPECT_EQ(3U, key3->GetSize());
+ EXPECT_EQ(1, key3->GetInt(0));
+ EXPECT_EQ(2, key3->GetInt(1));
+ EXPECT_EQ(3, key3->GetInt(2));
+
+ // generate string from parsed result
+ CefString result = CefWriteJSON(value, JSON_WRITER_DEFAULT);
+ CefString expected_result = data;
+ EXPECT_EQ(expected_result, result);
+}
+
+TEST(ParserTest, ParseJSONList) {
+ const char data[] = "[\"value1\", 123, {\"key3\": [1, 2, 3]}]";
+ CefRefPtr<CefValue> value = CefParseJSON(data, JSON_PARSER_RFC);
+ EXPECT_TRUE(value.get());
+ EXPECT_TRUE(value->IsValid());
+ EXPECT_TRUE(value->GetType() == VTYPE_LIST);
+ EXPECT_FALSE(value->IsOwned());
+ CefRefPtr<CefListValue> list = value->GetList();
+ EXPECT_TRUE(nullptr != list);
+ EXPECT_TRUE(list->IsValid());
+ EXPECT_EQ(3U, list->GetSize());
+
+ EXPECT_EQ(VTYPE_STRING, list->GetType(0));
+ EXPECT_EQ(list->GetString(0), "value1");
+ EXPECT_EQ(VTYPE_INT, list->GetType(1));
+ EXPECT_EQ(123, list->GetInt(1));
+ EXPECT_EQ(VTYPE_DICTIONARY, list->GetType(2));
+ CefRefPtr<CefDictionaryValue> dict = list->GetDictionary(2);
+ CefDictionaryValue::KeyList key_list2;
+ EXPECT_TRUE(dict->GetKeys(key_list2));
+ EXPECT_EQ(1U, key_list2.size());
+ CefRefPtr<CefListValue> list2 = dict->GetList("key3");
+ EXPECT_EQ(3U, list2->GetSize());
+ EXPECT_EQ(1, list2->GetInt(0));
+ EXPECT_EQ(2, list2->GetInt(1));
+ EXPECT_EQ(3, list2->GetInt(2));
+
+ // generate string from parsed result
+ CefString result = CefWriteJSON(value, JSON_WRITER_DEFAULT);
+ CefString expected_result = "[\"value1\",123,{\"key3\":[1,2,3]}]";
+ EXPECT_EQ(expected_result.ToString(), result.ToString());
+}
+
+TEST(ParserTest, ParseJSONAndReturnErrorInvalid) {
+ const char data[] = "This is my test data";
+ CefString error_msg;
+ CefRefPtr<CefValue> value =
+ CefParseJSONAndReturnError(data, JSON_PARSER_RFC, error_msg);
+ CefString expect_error_msg = "Line: 1, column: 1, Unexpected token.";
+ EXPECT_FALSE(value.get());
+ EXPECT_EQ(expect_error_msg, error_msg);
+}
+
+TEST(ParserTest, ParseJSONAndReturnErrorTrailingComma) {
+ const char data[] = "{\"key1\":123,}";
+ CefString error_msg;
+ CefRefPtr<CefValue> value =
+ CefParseJSONAndReturnError(data, JSON_PARSER_RFC, error_msg);
+ CefString expect_error_msg =
+ "Line: 1, column: 13, Trailing comma not allowed.";
+ EXPECT_FALSE(value.get());
+ EXPECT_EQ(expect_error_msg, error_msg);
+}
diff --git a/tests/ceftests/pdf_viewer_unittest.cc b/tests/ceftests/pdf_viewer_unittest.cc
new file mode 100644
index 00000000..7db93382
--- /dev/null
+++ b/tests/ceftests/pdf_viewer_unittest.cc
@@ -0,0 +1,233 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "include/base/cef_callback.h"
+#include "include/cef_pack_resources.h"
+#include "include/cef_request_context_handler.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "include/wrapper/cef_stream_resource_handler.h"
+#include "tests/ceftests/test_handler.h"
+#include "tests/ceftests/test_util.h"
+#include "tests/gtest/include/gtest/gtest.h"
+#include "tests/shared/browser/client_app_browser.h"
+#include "tests/shared/browser/resource_util.h"
+
+namespace {
+
+const char kPdfHtmlUrl[] = "http://tests/pdf.html";
+const char kPdfDirectUrl[] = "http://tests/pdf.pdf";
+
+// Delay waiting for iframe tests to load the PDF file.
+#if defined(OS_LINUX)
+const int64 kPdfLoadDelayMs = 7000;
+#else
+const int64 kPdfLoadDelayMs = 5000;
+#endif
+
+// Browser-side test handler.
+class PdfViewerTestHandler : public TestHandler, public CefContextMenuHandler {
+ public:
+ enum Mode {
+ // No specified context or handler (implicitly uses the global context).
+ GLOBAL_DEFAULT,
+
+ // Global context with no handler.
+ GLOBAL_NO_HANDLER,
+
+ // Custom context with no handler.
+ CUSTOM_NO_HANDLER,
+ };
+
+ PdfViewerTestHandler(Mode mode, const std::string& url)
+ : mode_(mode), url_(url) {}
+
+ // Loading the PDF directly in the main frame instead of a sub-frame.
+ bool HasDirectPdfLoad() const { return url_ == kPdfDirectUrl; }
+
+ CefRefPtr<CefContextMenuHandler> GetContextMenuHandler() override {
+ return this;
+ }
+
+ void RunTest() override {
+ CefRefPtr<CefRequestContext> request_context;
+
+ if (mode_ == GLOBAL_NO_HANDLER) {
+ // Use the global request context.
+ request_context = CefRequestContext::CreateContext(
+ CefRequestContext::GetGlobalContext(), nullptr);
+ } else if (mode_ == CUSTOM_NO_HANDLER) {
+ // Create the request context that will use an in-memory cache.
+ CefRequestContextSettings settings;
+ request_context = CefRequestContext::CreateContext(settings, nullptr);
+ }
+
+ // Create the browser.
+ CreateBrowser(url_, request_context);
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout(5000 + kPdfLoadDelayMs);
+ }
+
+ CefRefPtr<CefResourceHandler> GetResourceHandler(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request) override {
+ const std::string& url = request->GetURL();
+ if (url == kPdfHtmlUrl) {
+ CefRefPtr<CefStreamReader> stream =
+ client::GetBinaryResourceReader("pdf.html");
+ return new CefStreamResourceHandler("text/html", stream);
+ } else if (url == kPdfDirectUrl) {
+ CefRefPtr<CefStreamReader> stream =
+ client::GetBinaryResourceReader("pdf.pdf");
+ return new CefStreamResourceHandler("application/pdf", stream);
+ }
+
+ return nullptr;
+ }
+
+ void OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int httpStatusCode) override {
+ bool is_pdf1 = false;
+ const std::string& url = frame->GetURL();
+ if (url == "about:blank") {
+ return;
+ }
+
+ if (url == kPdfHtmlUrl) {
+ if (!got_on_load_end_html_) {
+ got_on_load_end_html_.yes();
+ } else {
+ NOTREACHED();
+ }
+ } else if (url == kPdfDirectUrl) {
+ if (!got_on_load_end_pdf1_) {
+ got_on_load_end_pdf1_.yes();
+ is_pdf1 = true;
+ } else if (!got_on_load_end_pdf2_) {
+ got_on_load_end_pdf2_.yes();
+ } else {
+ NOTREACHED();
+ }
+ } else {
+ NOTREACHED() << "url=" << url;
+ }
+
+ if (is_pdf1) {
+ // The first PDF document has loaded.
+ // TODO(chrome): Add support for custom context menus.
+ if (IsChromeRuntimeEnabled() || got_context_menu_dismissed_) {
+ // After context menu display. Destroy the test.
+ CefPostDelayedTask(
+ TID_UI, base::BindOnce(&PdfViewerTestHandler::DestroyTest, this),
+ kPdfLoadDelayMs);
+ } else {
+ // Trigger the context menu.
+ CefPostDelayedTask(
+ TID_UI,
+ base::BindOnce(&PdfViewerTestHandler::TriggerContextMenu, this,
+ frame->GetBrowser()),
+ kPdfLoadDelayMs);
+ }
+ }
+ }
+
+ void TriggerContextMenu(CefRefPtr<CefBrowser> browser) {
+ CefMouseEvent mouse_event;
+
+ if (HasDirectPdfLoad()) {
+ // Somewhere in the main PDF viewing area (avoid left preview bar).
+ mouse_event.x = 400;
+ mouse_event.y = 200;
+ } else {
+ // Somewhere in the first PDF viewing area.
+ mouse_event.x = 100;
+ mouse_event.y = 100;
+ }
+
+ // Send right-click mouse down and mouse up to tigger context menu.
+ SendMouseClickEvent(browser, mouse_event, MBT_RIGHT);
+ }
+
+ bool RunContextMenu(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefContextMenuParams> params,
+ CefRefPtr<CefMenuModel> model,
+ CefRefPtr<CefRunContextMenuCallback> callback) override {
+ EXPECT_FALSE(got_run_context_menu_);
+ got_run_context_menu_.yes();
+
+ // Do nothing with the context menu.
+ callback->Cancel();
+
+ return true;
+ }
+
+ void OnContextMenuDismissed(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame) override {
+ EXPECT_FALSE(got_context_menu_dismissed_);
+ got_context_menu_dismissed_.yes();
+
+ CefPostTask(TID_UI,
+ base::BindOnce(&PdfViewerTestHandler::DestroyTest, this));
+ }
+
+ void DestroyTest() override {
+ // TODO(chrome): Add support for custom context menus.
+ if (!IsChromeRuntimeEnabled()) {
+ EXPECT_TRUE(got_run_context_menu_);
+ EXPECT_TRUE(got_context_menu_dismissed_);
+ } else {
+ EXPECT_FALSE(got_run_context_menu_);
+ EXPECT_FALSE(got_context_menu_dismissed_);
+ }
+
+ if (url_ == kPdfHtmlUrl) {
+ // The HTML file will load the PDF twice in iframes.
+ EXPECT_TRUE(got_on_load_end_html_);
+ EXPECT_TRUE(got_on_load_end_pdf1_);
+ EXPECT_TRUE(got_on_load_end_pdf2_);
+ } else if (url_ == kPdfDirectUrl) {
+ // Load the PDF file directly.
+ EXPECT_FALSE(got_on_load_end_html_);
+ EXPECT_TRUE(got_on_load_end_pdf1_);
+ EXPECT_FALSE(got_on_load_end_pdf2_);
+ } else {
+ NOTREACHED();
+ }
+
+ TestHandler::DestroyTest();
+ }
+
+ const Mode mode_;
+ const std::string url_;
+
+ TrackCallback got_on_load_end_html_;
+ TrackCallback got_on_load_end_pdf1_;
+ TrackCallback got_on_load_end_pdf2_;
+ TrackCallback got_run_context_menu_;
+ TrackCallback got_context_menu_dismissed_;
+
+ IMPLEMENT_REFCOUNTING(PdfViewerTestHandler);
+};
+
+} // namespace
+
+#define RUN_TEST(name, type, url) \
+ TEST(PdfViewerTest, name) { \
+ CefRefPtr<PdfViewerTestHandler> handler = \
+ new PdfViewerTestHandler(PdfViewerTestHandler::type, url); \
+ handler->ExecuteTest(); \
+ ReleaseAndWaitForDestructor(handler); \
+ }
+
+RUN_TEST(GlobalDefaultPdfDirect, GLOBAL_DEFAULT, kPdfDirectUrl)
+RUN_TEST(GlobalDefaultPdfHtml, GLOBAL_DEFAULT, kPdfHtmlUrl)
+
+RUN_TEST(GlobalNoHandlerPdfDirect, GLOBAL_NO_HANDLER, kPdfDirectUrl)
+RUN_TEST(GlobalNoHandlerPdfHtml, GLOBAL_NO_HANDLER, kPdfHtmlUrl)
+
+RUN_TEST(CustomNoHandlerPdfDirect, CUSTOM_NO_HANDLER, kPdfDirectUrl)
+RUN_TEST(CustomNoHandlerPdfHtml, CUSTOM_NO_HANDLER, kPdfHtmlUrl)
diff --git a/tests/ceftests/permission_prompt_unittest.cc b/tests/ceftests/permission_prompt_unittest.cc
new file mode 100644
index 00000000..83381886
--- /dev/null
+++ b/tests/ceftests/permission_prompt_unittest.cc
@@ -0,0 +1,484 @@
+// Copyright 2022 The Chromium Embedded Framework Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be found
+// in the LICENSE file.
+
+#include <string>
+#include <vector>
+
+#include "include/base/cef_callback.h"
+#include "include/cef_parser.h"
+#include "include/cef_permission_handler.h"
+#include "include/cef_request_context_handler.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "include/wrapper/cef_stream_resource_handler.h"
+#include "tests/ceftests/test_handler.h"
+#include "tests/ceftests/test_suite.h"
+#include "tests/ceftests/test_util.h"
+#include "tests/gtest/include/gtest/gtest.h"
+#include "tests/shared/browser/client_app_browser.h"
+
+namespace {
+
+// Most permissions require HTTPS.
+constexpr char kPromptUrl[] = "https://permission-prompt-test/prompt.html";
+constexpr char kPromptOrigin[] = "https://permission-prompt-test/";
+
+constexpr char kPromptNavUrl[] = "https://permission-prompt-test/nav.html";
+
+class TestSetup {
+ public:
+ TestSetup() {}
+
+ // CONFIGURATION
+
+ // Deny the prompt by returning false in OnShowPermissionPrompt.
+ bool deny_implicitly = false;
+
+ // Deny the prompt (implicitly) by not triggering it via a user gesture to
+ // begin with.
+ bool deny_no_gesture = false;
+
+ // Deny the prompt by returning true in OnShowPermissionPrompt but then never
+ // calling CefPermissionPromptCallback::Continue.
+ bool deny_with_navigation = false;
+
+ // Don't synchronously execute the callback in OnShowPermissionPrompt.
+ bool continue_async = false;
+
+ // RESULTS
+
+ // Method callbacks.
+ TrackCallback got_prompt;
+ TrackCallback got_dismiss;
+
+ // JS success state.
+ TrackCallback got_js_success;
+ TrackCallback got_js_success_data;
+
+ // JS error state.
+ TrackCallback got_js_error;
+ std::string js_error_str;
+
+ // JS timeout state.
+ TrackCallback got_js_timeout;
+};
+
+class PermissionPromptTestHandler : public TestHandler,
+ public CefPermissionHandler {
+ public:
+ PermissionPromptTestHandler(TestSetup* tr,
+ uint32 request,
+ cef_permission_request_result_t result)
+ : test_setup_(tr), request_(request), result_(result) {}
+
+ cef_return_value_t OnBeforeResourceLoad(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefCallback> callback) override {
+ std::string newUrl = request->GetURL();
+ if (newUrl.find("tests/exit") != std::string::npos) {
+ if (newUrl.find("SUCCESS") != std::string::npos) {
+ EXPECT_FALSE(test_setup_->got_js_success);
+ test_setup_->got_js_success.yes();
+
+ auto dict = ParseURLData(newUrl);
+ if (dict->GetBool("got_data")) {
+ test_setup_->got_js_success_data.yes();
+ }
+ } else if (newUrl.find("ERROR") != std::string::npos) {
+ EXPECT_FALSE(test_setup_->got_js_error);
+ test_setup_->got_js_error.yes();
+
+ auto dict = ParseURLData(newUrl);
+ test_setup_->js_error_str = dict->GetString("error_str");
+ } else if (newUrl.find("TIMEOUT") != std::string::npos) {
+ EXPECT_FALSE(test_setup_->got_js_timeout);
+ test_setup_->got_js_timeout.yes();
+ }
+
+ DestroyTest();
+ return RV_CANCEL;
+ }
+
+ return RV_CONTINUE;
+ }
+
+ void RunTest() override {
+ std::string page =
+ "<html><head>"
+ "<script>"
+ "function onResult(val, data) {"
+ " if(!data) {"
+ " data = {};"
+ " }"
+ " document.location = "
+ "`http://tests/"
+ "exit?result=${val}&data=${encodeURIComponent(JSON.stringify(data))}`;"
+ "}"
+ "function makeRequest() {";
+
+ if (request_ == CEF_PERMISSION_TYPE_WINDOW_MANAGEMENT) {
+ page +=
+ " window.getScreenDetails().then(function(details) {"
+ " onResult(`SUCCESS`, {got_data: details.screens.length > 0});"
+ " })";
+ }
+
+ page +=
+ " .catch(function(err) {"
+ " console.log(err.toString());"
+ " onResult(`ERROR`, {error_str: err.toString()});"
+ " });";
+
+ if (test_setup_->deny_implicitly) {
+ // Implicit IGNORE result means the promise will never resolve, so add a
+ // timeout.
+ page += " setTimeout(() => { onResult(`TIMEOUT`); }, 1000);";
+ } else if (test_setup_->deny_with_navigation) {
+ // Cancel the pending permission request by navigating.
+ page += " setTimeout(() => { document.location = '" +
+ std::string(kPromptNavUrl) + "'; }, 1000);";
+ }
+
+ page +=
+ "}"
+ "</script>"
+ "</head><body>";
+
+ if (test_setup_->deny_no_gesture) {
+ // Expect this request to be blocked. See comments on OnLoadEnd.
+ page += "<script>makeRequest();</script>";
+ } else {
+ page += "<a href='#' onclick='makeRequest(); return false;'>CLICK ME</a>";
+ }
+
+ page += "</body></html>";
+
+ // Create the request context that will use an in-memory cache.
+ CefRequestContextSettings settings;
+ CefRefPtr<CefRequestContext> request_context =
+ CefRequestContext::CreateContext(settings, nullptr);
+
+ AddResource(kPromptUrl, page, "text/html");
+
+ if (test_setup_->deny_with_navigation) {
+ AddResource(kPromptNavUrl, "<html><body>Navigated</body></html>",
+ "text/html");
+ }
+
+ // Create the browser.
+ CreateBrowser(kPromptUrl, request_context);
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout();
+ }
+
+ CefRefPtr<CefPermissionHandler> GetPermissionHandler() override {
+ return this;
+ }
+
+ void OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int httpStatusCode) override {
+ if (test_setup_->deny_no_gesture) {
+ return;
+ }
+
+ if (test_setup_->deny_with_navigation) {
+ if (frame->GetURL().ToString() == kPromptNavUrl) {
+ DestroyTest();
+ return;
+ }
+ }
+
+ // Begin the permissions request by clicking a link. This is necessary
+ // because some prompts may be blocked without a transient user activation
+ // (HasTransientUserActivation returning true in Chromium).
+ SendClick(browser);
+ }
+
+ bool OnShowPermissionPrompt(
+ CefRefPtr<CefBrowser> browser,
+ uint64 prompt_id,
+ const CefString& requesting_origin,
+ uint32 requested_permissions,
+ CefRefPtr<CefPermissionPromptCallback> callback) override {
+ EXPECT_UI_THREAD();
+
+ prompt_id_ = prompt_id;
+ EXPECT_GT(prompt_id, 0U);
+
+ EXPECT_EQ(request_, requested_permissions);
+ EXPECT_STREQ(kPromptOrigin, requesting_origin.ToString().c_str());
+
+ EXPECT_FALSE(test_setup_->got_prompt);
+ test_setup_->got_prompt.yes();
+
+ if (test_setup_->deny_implicitly) {
+ // Causes implicit IGNORE result for the permission request.
+ return false;
+ }
+
+ if (test_setup_->deny_with_navigation) {
+ // Handle the permission request, but never execute the callback.
+ return true;
+ }
+
+ if (test_setup_->continue_async) {
+ CefPostTask(TID_UI, base::BindOnce(&CefPermissionPromptCallback::Continue,
+ callback, result_));
+ } else {
+ callback->Continue(result_);
+ }
+ return true;
+ }
+
+ void OnDismissPermissionPrompt(
+ CefRefPtr<CefBrowser> browser,
+ uint64 prompt_id,
+ cef_permission_request_result_t result) override {
+ EXPECT_UI_THREAD();
+ EXPECT_EQ(prompt_id_, prompt_id);
+ EXPECT_EQ(result_, result);
+ EXPECT_FALSE(test_setup_->got_dismiss);
+ test_setup_->got_dismiss.yes();
+ }
+
+ void DestroyTest() override {
+ const size_t js_outcome_ct = test_setup_->got_js_success +
+ test_setup_->got_js_error +
+ test_setup_->got_js_timeout;
+ if (test_setup_->deny_with_navigation) {
+ // Expect no JS outcome.
+ EXPECT_EQ(0U, js_outcome_ct);
+ } else {
+ // Expect a single JS outcome.
+ EXPECT_EQ(1U, js_outcome_ct);
+ }
+
+ TestHandler::DestroyTest();
+ }
+
+ private:
+ void SendClick(CefRefPtr<CefBrowser> browser) {
+ CefMouseEvent mouse_event;
+ mouse_event.x = 20;
+ mouse_event.y = 20;
+ SendMouseClickEvent(browser, mouse_event);
+ }
+
+ CefRefPtr<CefDictionaryValue> ParseURLData(const std::string& url) {
+ const std::string& find_str = "&data=";
+ const std::string& data_string =
+ url.substr(url.find(find_str) + std::string(find_str).length());
+ const std::string& data_string_decoded = CefURIDecode(
+ data_string, false,
+ static_cast<cef_uri_unescape_rule_t>(
+ UU_SPACES | UU_URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS));
+ auto obj =
+ CefParseJSON(data_string_decoded, JSON_PARSER_ALLOW_TRAILING_COMMAS);
+ return obj->GetDictionary();
+ }
+
+ TestSetup* const test_setup_;
+ const uint32 request_;
+ const cef_permission_request_result_t result_;
+ uint64 prompt_id_ = 0U;
+
+ IMPLEMENT_REFCOUNTING(PermissionPromptTestHandler);
+};
+
+} // namespace
+
+// Window placement permission requests.
+TEST(PermissionPromptTest, WindowManagementReturningFalse) {
+ TestSetup test_setup;
+ test_setup.deny_implicitly = true;
+
+ CefRefPtr<PermissionPromptTestHandler> handler =
+ new PermissionPromptTestHandler(&test_setup,
+ CEF_PERMISSION_TYPE_WINDOW_MANAGEMENT,
+ CEF_PERMISSION_RESULT_IGNORE);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ // No OnDismissPermissionPrompt callback for default handling.
+ EXPECT_TRUE(test_setup.got_prompt);
+ EXPECT_TRUE(test_setup.got_js_timeout);
+ EXPECT_FALSE(test_setup.got_dismiss);
+}
+
+TEST(PermissionPromptTest, WindowManagementNoGesture) {
+ TestSetup test_setup;
+ test_setup.deny_no_gesture = true;
+
+ CefRefPtr<PermissionPromptTestHandler> handler =
+ new PermissionPromptTestHandler(&test_setup,
+ CEF_PERMISSION_TYPE_WINDOW_MANAGEMENT,
+ CEF_PERMISSION_RESULT_IGNORE);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ // No OnShowPermissionPrompt or OnDismissPermissionPrompt callbacks for
+ // prompts that are blocked.
+ EXPECT_FALSE(test_setup.got_prompt);
+ EXPECT_TRUE(test_setup.got_js_error);
+ EXPECT_STREQ("NotAllowedError: Permission decision deferred.",
+ test_setup.js_error_str.c_str());
+ EXPECT_FALSE(test_setup.got_dismiss);
+}
+
+TEST(PermissionPromptTest, WindowManagementNoContinue) {
+ TestSetup test_setup;
+ test_setup.deny_with_navigation = true;
+
+ CefRefPtr<PermissionPromptTestHandler> handler =
+ new PermissionPromptTestHandler(&test_setup,
+ CEF_PERMISSION_TYPE_WINDOW_MANAGEMENT,
+ CEF_PERMISSION_RESULT_IGNORE);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ // Callbacks but no JS result.
+ EXPECT_TRUE(test_setup.got_prompt);
+ EXPECT_TRUE(test_setup.got_dismiss);
+}
+
+TEST(PermissionPromptTest, WindowManagementResultAccept) {
+ TestSetup test_setup;
+
+ CefRefPtr<PermissionPromptTestHandler> handler =
+ new PermissionPromptTestHandler(&test_setup,
+ CEF_PERMISSION_TYPE_WINDOW_MANAGEMENT,
+ CEF_PERMISSION_RESULT_ACCEPT);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(test_setup.got_prompt);
+ EXPECT_TRUE(test_setup.got_js_success);
+ EXPECT_TRUE(test_setup.got_js_success_data);
+ EXPECT_TRUE(test_setup.got_dismiss);
+}
+
+TEST(PermissionPromptTest, WindowManagementResultAcceptAsync) {
+ TestSetup test_setup;
+ test_setup.continue_async = true;
+
+ CefRefPtr<PermissionPromptTestHandler> handler =
+ new PermissionPromptTestHandler(&test_setup,
+ CEF_PERMISSION_TYPE_WINDOW_MANAGEMENT,
+ CEF_PERMISSION_RESULT_ACCEPT);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(test_setup.got_prompt);
+ EXPECT_TRUE(test_setup.got_js_success);
+ EXPECT_TRUE(test_setup.got_js_success_data);
+ EXPECT_TRUE(test_setup.got_dismiss);
+}
+
+TEST(PermissionPromptTest, WindowManagementResultDeny) {
+ TestSetup test_setup;
+
+ CefRefPtr<PermissionPromptTestHandler> handler =
+ new PermissionPromptTestHandler(&test_setup,
+ CEF_PERMISSION_TYPE_WINDOW_MANAGEMENT,
+ CEF_PERMISSION_RESULT_DENY);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(test_setup.got_prompt);
+ EXPECT_TRUE(test_setup.got_js_error);
+ EXPECT_STREQ("NotAllowedError: Permission denied.",
+ test_setup.js_error_str.c_str());
+ EXPECT_TRUE(test_setup.got_dismiss);
+}
+
+TEST(PermissionPromptTest, WindowManagementResultDenyAsync) {
+ TestSetup test_setup;
+ test_setup.continue_async = true;
+
+ CefRefPtr<PermissionPromptTestHandler> handler =
+ new PermissionPromptTestHandler(&test_setup,
+ CEF_PERMISSION_TYPE_WINDOW_MANAGEMENT,
+ CEF_PERMISSION_RESULT_DENY);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(test_setup.got_prompt);
+ EXPECT_TRUE(test_setup.got_js_error);
+ EXPECT_STREQ("NotAllowedError: Permission denied.",
+ test_setup.js_error_str.c_str());
+ EXPECT_TRUE(test_setup.got_dismiss);
+}
+
+TEST(PermissionPromptTest, WindowManagementResultDismiss) {
+ TestSetup test_setup;
+
+ CefRefPtr<PermissionPromptTestHandler> handler =
+ new PermissionPromptTestHandler(&test_setup,
+ CEF_PERMISSION_TYPE_WINDOW_MANAGEMENT,
+ CEF_PERMISSION_RESULT_DISMISS);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(test_setup.got_prompt);
+ EXPECT_TRUE(test_setup.got_js_error);
+ EXPECT_STREQ("NotAllowedError: Permission decision deferred.",
+ test_setup.js_error_str.c_str());
+ EXPECT_TRUE(test_setup.got_dismiss);
+}
+
+TEST(PermissionPromptTest, WindowManagementResultDismissAsync) {
+ TestSetup test_setup;
+ test_setup.continue_async = true;
+
+ CefRefPtr<PermissionPromptTestHandler> handler =
+ new PermissionPromptTestHandler(&test_setup,
+ CEF_PERMISSION_TYPE_WINDOW_MANAGEMENT,
+ CEF_PERMISSION_RESULT_DISMISS);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(test_setup.got_prompt);
+ EXPECT_TRUE(test_setup.got_js_error);
+ EXPECT_STREQ("NotAllowedError: Permission decision deferred.",
+ test_setup.js_error_str.c_str());
+ EXPECT_TRUE(test_setup.got_dismiss);
+}
+
+TEST(PermissionPromptTest, WindowManagementResultIgnore) {
+ TestSetup test_setup;
+
+ CefRefPtr<PermissionPromptTestHandler> handler =
+ new PermissionPromptTestHandler(&test_setup,
+ CEF_PERMISSION_TYPE_WINDOW_MANAGEMENT,
+ CEF_PERMISSION_RESULT_IGNORE);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(test_setup.got_prompt);
+ EXPECT_TRUE(test_setup.got_js_error);
+ EXPECT_STREQ("NotAllowedError: Permission decision deferred.",
+ test_setup.js_error_str.c_str());
+ EXPECT_TRUE(test_setup.got_dismiss);
+}
+
+TEST(PermissionPromptTest, WindowManagementResultIgnoreAsync) {
+ TestSetup test_setup;
+ test_setup.continue_async = true;
+
+ CefRefPtr<PermissionPromptTestHandler> handler =
+ new PermissionPromptTestHandler(&test_setup,
+ CEF_PERMISSION_TYPE_WINDOW_MANAGEMENT,
+ CEF_PERMISSION_RESULT_IGNORE);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(test_setup.got_prompt);
+ EXPECT_TRUE(test_setup.got_js_error);
+ EXPECT_STREQ("NotAllowedError: Permission decision deferred.",
+ test_setup.js_error_str.c_str());
+ EXPECT_TRUE(test_setup.got_dismiss);
+}
diff --git a/tests/ceftests/preference_unittest.cc b/tests/ceftests/preference_unittest.cc
new file mode 100644
index 00000000..f04db957
--- /dev/null
+++ b/tests/ceftests/preference_unittest.cc
@@ -0,0 +1,650 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "include/base/cef_callback.h"
+#include "include/cef_request_context_handler.h"
+#include "include/cef_waitable_event.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "tests/ceftests/test_handler.h"
+#include "tests/ceftests/test_util.h"
+#include "tests/gtest/include/gtest/gtest.h"
+#include "tests/shared/browser/client_app_browser.h"
+
+namespace {
+
+// Fully qualified preference names.
+const char kPrefTest[] = "test";
+const char kPrefTestBool[] = "test.bool";
+const char kPrefTestInt[] = "test.int";
+const char kPrefTestDouble[] = "test.double";
+const char kPrefTestString[] = "test.string";
+const char kPrefTestList[] = "test.list";
+const char kPrefTestDict[] = "test.dict";
+const char kPrefTestNoExist[] = "test.noexist";
+
+// Unqualified preference names.
+const char kPrefBool[] = "bool";
+const char kPrefInt[] = "int";
+const char kPrefDouble[] = "double";
+const char kPrefString[] = "string";
+const char kPrefList[] = "list";
+const char kPrefDict[] = "dict";
+
+std::string* PendingAction() {
+ static std::string str;
+ return &str;
+}
+
+CefRefPtr<CefValue> CreateBoolValue(bool value) {
+ auto val = CefValue::Create();
+ val->SetBool(value);
+ return val;
+}
+
+CefRefPtr<CefValue> CreateIntValue(int value) {
+ auto val = CefValue::Create();
+ val->SetInt(value);
+ return val;
+}
+
+CefRefPtr<CefValue> CreateDoubleValue(double value) {
+ auto val = CefValue::Create();
+ val->SetDouble(value);
+ return val;
+}
+
+CefRefPtr<CefValue> CreateStringValue(const std::string& value) {
+ auto val = CefValue::Create();
+ val->SetString(value);
+ return val;
+}
+
+CefRefPtr<CefValue> CreateListValue(CefRefPtr<CefListValue> value) {
+ auto val = CefValue::Create();
+ val->SetList(value);
+ return val;
+}
+
+CefRefPtr<CefValue> CreateDictionaryValue(CefRefPtr<CefDictionaryValue> value) {
+ auto val = CefValue::Create();
+ val->SetDictionary(value);
+ return val;
+}
+
+// Browser-side app delegate.
+class PreferenceBrowserTest : public client::ClientAppBrowser::Delegate {
+ public:
+ PreferenceBrowserTest() {}
+
+ void OnRegisterCustomPreferences(
+ CefRefPtr<client::ClientAppBrowser> app,
+ cef_preferences_type_t type,
+ CefRawPtr<CefPreferenceRegistrar> registrar) override {
+ // Register test preferences.
+ registrar->AddPreference(kPrefTestBool, CreateBoolValue(true));
+ registrar->AddPreference(kPrefTestInt, CreateIntValue(2));
+ registrar->AddPreference(kPrefTestDouble, CreateDoubleValue(5.0));
+ registrar->AddPreference(kPrefTestString, CreateStringValue("default"));
+ registrar->AddPreference(kPrefTestList,
+ CreateListValue(CefListValue::Create()));
+ registrar->AddPreference(
+ kPrefTestDict, CreateDictionaryValue(CefDictionaryValue::Create()));
+ }
+
+ private:
+ IMPLEMENT_REFCOUNTING(PreferenceBrowserTest);
+};
+
+void ValidateReset(CefRefPtr<CefPreferenceManager> context, const char* name) {
+ EXPECT_TRUE(context->HasPreference(name));
+ EXPECT_TRUE(context->CanSetPreference(name));
+
+ CefString error;
+ EXPECT_TRUE(context->SetPreference(name, nullptr, error));
+ EXPECT_TRUE(error.empty());
+}
+
+void ValidateBool(CefRefPtr<CefPreferenceManager> context,
+ bool set,
+ bool expected,
+ const char* name = kPrefTestBool) {
+ EXPECT_TRUE(context->HasPreference(name));
+ EXPECT_TRUE(context->CanSetPreference(name));
+
+ if (set) {
+ CefString error;
+ EXPECT_TRUE(context->SetPreference(name, CreateBoolValue(expected), error));
+ EXPECT_TRUE(error.empty());
+ }
+
+ auto value = context->GetPreference(name);
+ EXPECT_TRUE(value.get());
+ EXPECT_EQ(VTYPE_BOOL, value->GetType());
+ EXPECT_EQ(expected, value->GetBool()) << *PendingAction();
+}
+
+void ValidateInt(CefRefPtr<CefPreferenceManager> context,
+ bool set,
+ int expected,
+ const char* name = kPrefTestInt) {
+ EXPECT_TRUE(context->HasPreference(name));
+ EXPECT_TRUE(context->CanSetPreference(name));
+
+ if (set) {
+ CefString error;
+ EXPECT_TRUE(context->SetPreference(name, CreateIntValue(expected), error));
+ EXPECT_TRUE(error.empty());
+ }
+
+ auto value = context->GetPreference(name);
+ EXPECT_TRUE(value.get());
+ EXPECT_EQ(VTYPE_INT, value->GetType());
+ EXPECT_EQ(expected, value->GetInt()) << *PendingAction();
+}
+
+void ValidateDouble(CefRefPtr<CefPreferenceManager> context,
+ bool set,
+ double expected,
+ const char* name = kPrefTestDouble) {
+ EXPECT_TRUE(context->HasPreference(name));
+ EXPECT_TRUE(context->CanSetPreference(name));
+
+ if (set) {
+ CefString error;
+ EXPECT_TRUE(
+ context->SetPreference(name, CreateDoubleValue(expected), error));
+ EXPECT_TRUE(error.empty());
+ }
+
+ auto value = context->GetPreference(name);
+ EXPECT_TRUE(value.get());
+ EXPECT_EQ(VTYPE_DOUBLE, value->GetType());
+ EXPECT_EQ(expected, value->GetDouble()) << *PendingAction();
+}
+
+void ValidateString(CefRefPtr<CefPreferenceManager> context,
+ bool set,
+ const std::string& expected,
+ const char* name = kPrefTestString) {
+ EXPECT_TRUE(context->HasPreference(name));
+ EXPECT_TRUE(context->CanSetPreference(name));
+
+ if (set) {
+ CefString error;
+ EXPECT_TRUE(
+ context->SetPreference(name, CreateStringValue(expected), error));
+ EXPECT_TRUE(error.empty());
+ }
+
+ auto value = context->GetPreference(name);
+ EXPECT_TRUE(value.get());
+ EXPECT_EQ(VTYPE_STRING, value->GetType());
+ EXPECT_STREQ(expected.c_str(), value->GetString().ToString().c_str())
+ << *PendingAction();
+}
+
+void ValidateList(CefRefPtr<CefPreferenceManager> context,
+ bool set,
+ CefRefPtr<CefListValue> expected,
+ const char* name = kPrefTestList) {
+ EXPECT_TRUE(context->HasPreference(name));
+ EXPECT_TRUE(context->CanSetPreference(name));
+
+ if (set) {
+ CefString error;
+ EXPECT_TRUE(context->SetPreference(name, CreateListValue(expected), error));
+ EXPECT_TRUE(error.empty());
+ }
+
+ auto value = context->GetPreference(name);
+ EXPECT_TRUE(value.get());
+ EXPECT_EQ(VTYPE_LIST, value->GetType());
+ CefRefPtr<CefListValue> list_val = value->GetList();
+ EXPECT_TRUE(list_val);
+ TestListEqual(expected, list_val);
+}
+
+void ValidateDict(CefRefPtr<CefPreferenceManager> context,
+ bool set,
+ CefRefPtr<CefDictionaryValue> expected,
+ const char* name = kPrefTestDict) {
+ EXPECT_TRUE(context->HasPreference(name));
+ EXPECT_TRUE(context->CanSetPreference(name));
+
+ if (set) {
+ CefString error;
+ EXPECT_TRUE(
+ context->SetPreference(name, CreateDictionaryValue(expected), error));
+ EXPECT_TRUE(error.empty());
+ }
+
+ auto value = context->GetPreference(name);
+ EXPECT_TRUE(value.get());
+ EXPECT_EQ(VTYPE_DICTIONARY, value->GetType());
+ CefRefPtr<CefDictionaryValue> dict_val = value->GetDictionary();
+ EXPECT_TRUE(dict_val);
+ TestDictionaryEqual(expected, dict_val);
+}
+
+void ValidateNoExist(CefRefPtr<CefPreferenceManager> context,
+ bool set,
+ const char* name = kPrefTestNoExist) {
+ EXPECT_FALSE(context->HasPreference(name));
+ EXPECT_FALSE(context->CanSetPreference(name));
+
+ if (set) {
+ CefString error;
+ EXPECT_FALSE(context->SetPreference(name, CreateBoolValue(false), error));
+ EXPECT_FALSE(error.empty());
+ }
+
+ auto value = context->GetPreference(name);
+ EXPECT_FALSE(value.get()) << *PendingAction();
+}
+
+void PopulateRootDefaults(CefRefPtr<CefDictionaryValue> val) {
+ // Should match the values in OnRegisterCustomPreferences.
+ val->SetBool(kPrefBool, true);
+ val->SetInt(kPrefInt, 2);
+ val->SetDouble(kPrefDouble, 5.0);
+ val->SetString(kPrefString, "default");
+ val->SetList(kPrefList, CefListValue::Create());
+ val->SetDictionary(kPrefDict, CefDictionaryValue::Create());
+}
+
+void ValidateRoot(CefRefPtr<CefDictionaryValue> root,
+ CefRefPtr<CefDictionaryValue> expected,
+ const char* name = kPrefTest) {
+ EXPECT_TRUE(root->HasKey(kPrefTest));
+ EXPECT_EQ(VTYPE_DICTIONARY, root->GetType(kPrefTest));
+
+ CefRefPtr<CefDictionaryValue> actual = root->GetDictionary(kPrefTest);
+ TestDictionaryEqual(expected, actual);
+}
+
+// Validate getting default values.
+void ValidateDefaults(CefRefPtr<CefPreferenceManager> context,
+ bool reset,
+ CefRefPtr<CefWaitableEvent> event) {
+ if (!CefCurrentlyOn(TID_UI)) {
+ CefPostTask(TID_UI,
+ base::BindOnce(ValidateDefaults, context, reset, event));
+ return;
+ }
+
+ if (reset) {
+ // Reset default values.
+ ValidateReset(context, kPrefTestBool);
+ ValidateReset(context, kPrefTestInt);
+ ValidateReset(context, kPrefTestDouble);
+ ValidateReset(context, kPrefTestString);
+ ValidateReset(context, kPrefTestList);
+ ValidateReset(context, kPrefTestDict);
+ }
+
+ // Test default values.
+ // Should match the values in CefBrowserPrefStore::CreateService.
+ ValidateBool(context, false, true);
+ ValidateInt(context, false, 2);
+ ValidateDouble(context, false, 5.0);
+ ValidateString(context, false, "default");
+ ValidateList(context, false, CefListValue::Create());
+ ValidateDict(context, false, CefDictionaryValue::Create());
+ ValidateNoExist(context, false);
+
+ // Expected value of the tests root.
+ CefRefPtr<CefDictionaryValue> expected = CefDictionaryValue::Create();
+ PopulateRootDefaults(expected);
+
+ // Test all preferences including defaults.
+ ValidateRoot(context->GetAllPreferences(true), expected);
+
+ // Test all preferences excluding defaults.
+ EXPECT_FALSE(context->GetAllPreferences(false)->HasKey(kPrefTest));
+
+ event->Signal();
+}
+
+void PopulateListValue(CefRefPtr<CefListValue> val) {
+ // Test list values.
+ val->SetInt(0, 54);
+ val->SetString(1, "foobar");
+ val->SetDouble(2, 99.7643);
+}
+
+void PopulateDictValue(CefRefPtr<CefDictionaryValue> val) {
+ // Test dictionary values.
+ val->SetString("key1", "some string");
+ val->SetBool("key2", false);
+
+ CefRefPtr<CefListValue> list_val = CefListValue::Create();
+ PopulateListValue(list_val);
+ val->SetList("key3", list_val);
+}
+
+void PopulateRootSet(CefRefPtr<CefDictionaryValue> val) {
+ CefRefPtr<CefListValue> list_val = CefListValue::Create();
+ CefRefPtr<CefDictionaryValue> dict_val = CefDictionaryValue::Create();
+
+ PopulateListValue(list_val);
+ PopulateDictValue(dict_val);
+
+ // Should match the values in ValidateSetGet and ValidateGet.
+ val->SetBool(kPrefBool, true);
+ val->SetInt(kPrefInt, 65);
+ val->SetDouble(kPrefDouble, 54.5443);
+ val->SetString(kPrefString, "My test string");
+ val->SetList(kPrefList, list_val);
+ val->SetDictionary(kPrefDict, dict_val);
+}
+
+// Validate getting and setting values.
+void ValidateSetGet(CefRefPtr<CefPreferenceManager> context,
+ CefRefPtr<CefWaitableEvent> event) {
+ if (!CefCurrentlyOn(TID_UI)) {
+ CefPostTask(TID_UI, base::BindOnce(ValidateSetGet, context, event));
+ return;
+ }
+
+ CefRefPtr<CefListValue> list_val = CefListValue::Create();
+ CefRefPtr<CefDictionaryValue> dict_val = CefDictionaryValue::Create();
+
+ PopulateListValue(list_val);
+ PopulateDictValue(dict_val);
+
+ // Test setting/getting values.
+ // Should match the values in PopulateRootSet and ValidateGet.
+ ValidateBool(context, true, true);
+ ValidateInt(context, true, 65);
+ ValidateDouble(context, true, 54.5443);
+ ValidateString(context, true, "My test string");
+ ValidateList(context, true, list_val);
+ ValidateDict(context, true, dict_val);
+ ValidateNoExist(context, true);
+
+ // Expected value of the tests root.
+ CefRefPtr<CefDictionaryValue> expected = CefDictionaryValue::Create();
+ PopulateRootSet(expected);
+
+ // Validate all preferences including defaults.
+ ValidateRoot(context->GetAllPreferences(true), expected);
+
+ // Validate all preferences excluding defaults.
+ ValidateRoot(context->GetAllPreferences(false), expected);
+
+ event->Signal();
+}
+
+// Validate getting values.
+void ValidateGet(CefRefPtr<CefPreferenceManager> context,
+ CefRefPtr<CefWaitableEvent> event) {
+ if (!CefCurrentlyOn(TID_UI)) {
+ CefPostTask(TID_UI, base::BindOnce(ValidateGet, context, event));
+ return;
+ }
+
+ CefRefPtr<CefListValue> list_val = CefListValue::Create();
+ CefRefPtr<CefDictionaryValue> dict_val = CefDictionaryValue::Create();
+
+ PopulateListValue(list_val);
+ PopulateDictValue(dict_val);
+
+ // Test getting values.
+ // Should match the values in PopulateRootSet and ValidateSetGet.
+ ValidateBool(context, false, true);
+ ValidateInt(context, false, 65);
+ ValidateDouble(context, false, 54.5443);
+ ValidateString(context, false, "My test string");
+ ValidateList(context, false, list_val);
+ ValidateDict(context, false, dict_val);
+ ValidateNoExist(context, false);
+
+ // Expected value of the tests root.
+ CefRefPtr<CefDictionaryValue> expected = CefDictionaryValue::Create();
+ PopulateRootSet(expected);
+
+ // Validate all preferences including defaults.
+ ValidateRoot(context->GetAllPreferences(true), expected);
+
+ // Validate all preferences excluding defaults.
+ ValidateRoot(context->GetAllPreferences(false), expected);
+
+ event->Signal();
+}
+
+// No-op implementation.
+class TestRequestContextHandler : public CefRequestContextHandler {
+ public:
+ TestRequestContextHandler() {}
+ explicit TestRequestContextHandler(CefRefPtr<CefWaitableEvent> event)
+ : event_(event) {}
+
+ void OnRequestContextInitialized(
+ CefRefPtr<CefRequestContext> context) override {
+ if (event_) {
+ event_->Signal();
+ event_ = nullptr;
+ }
+ }
+
+ private:
+ CefRefPtr<CefWaitableEvent> event_;
+
+ IMPLEMENT_REFCOUNTING(TestRequestContextHandler);
+};
+
+} // namespace
+
+// Verify default preference values on the global state.
+TEST(PreferenceTest, GlobalDefaults) {
+ CefRefPtr<CefWaitableEvent> event =
+ CefWaitableEvent::CreateWaitableEvent(true, false);
+
+ auto context = CefPreferenceManager::GetGlobalPreferenceManager();
+ EXPECT_TRUE(context.get());
+
+ ValidateDefaults(context, false, event);
+ event->Wait();
+}
+
+// Verify setting/getting preference values on the global state.
+TEST(PreferenceTest, GlobalSetGet) {
+ CefRefPtr<CefWaitableEvent> event =
+ CefWaitableEvent::CreateWaitableEvent(true, false);
+
+ auto context = CefPreferenceManager::GetGlobalPreferenceManager();
+ EXPECT_TRUE(context.get());
+
+ ValidateSetGet(context, event);
+ event->Wait();
+
+ // Reset to the default values.
+ ValidateDefaults(context, true, event);
+ event->Wait();
+}
+
+// Verify default preference values on the global request context.
+TEST(PreferenceTest, RequestContextGlobalDefaults) {
+ CefRefPtr<CefWaitableEvent> event =
+ CefWaitableEvent::CreateWaitableEvent(true, false);
+
+ CefRefPtr<CefRequestContext> context = CefRequestContext::GetGlobalContext();
+ EXPECT_TRUE(context.get());
+
+ ValidateDefaults(context, false, event);
+ event->Wait();
+}
+
+// Verify setting/getting preference values on the global request context.
+TEST(PreferenceTest, RequestContextGlobalSetGet) {
+ CefRefPtr<CefWaitableEvent> event =
+ CefWaitableEvent::CreateWaitableEvent(true, false);
+
+ CefRefPtr<CefRequestContext> context = CefRequestContext::GetGlobalContext();
+ EXPECT_TRUE(context.get());
+
+ ValidateSetGet(context, event);
+ event->Wait();
+
+ // Reset to the default values.
+ ValidateDefaults(context, true, event);
+ event->Wait();
+}
+
+// Verify setting/getting preference values on shared global request contexts.
+TEST(PreferenceTest, RequestContextGlobalSetGetShared) {
+ CefRefPtr<CefWaitableEvent> event =
+ CefWaitableEvent::CreateWaitableEvent(true, false);
+
+ CefRefPtr<CefRequestContext> context = CefRequestContext::GetGlobalContext();
+ EXPECT_TRUE(context.get());
+
+ // Sharing storage.
+ CefRefPtr<CefRequestContext> context2 =
+ CefRequestContext::CreateContext(context, nullptr);
+ EXPECT_TRUE(context2.get());
+
+ // Sharing storage.
+ CefRefPtr<CefRequestContext> context3 =
+ CefRequestContext::CreateContext(context, new TestRequestContextHandler);
+ EXPECT_TRUE(context3.get());
+
+ // Unassociated context.
+ CefRequestContextSettings settings;
+ CefRefPtr<CefRequestContext> context4 = CefRequestContext::CreateContext(
+ settings, new TestRequestContextHandler(event));
+ EXPECT_TRUE(context4.get());
+ // Wait for the context to be fully initialized.
+ event->Wait();
+
+ // Set/get the values on the first context.
+ *PendingAction() = "Set/get the values on the first context";
+ ValidateSetGet(context, event);
+ event->Wait();
+
+ // Get the values from the 2nd and 3rd contexts. They should be the same.
+ *PendingAction() = "Get the values from the 2nd context.";
+ ValidateGet(context2, event);
+ event->Wait();
+ *PendingAction() = "Get the values from the 3rd context.";
+ ValidateGet(context3, event);
+ event->Wait();
+
+ // Get the values from the 4th context.
+ *PendingAction() = "Get the values from the 4th context.";
+ if (IsChromeRuntimeEnabled()) {
+ // With the Chrome runtime, prefs set via an incognito profile will become
+ // an overlay on top of the global (parent) profile. The incognito profile
+ // shares the prefs in this case because they were set via the global
+ // profile.
+ ValidateGet(context4, event);
+ } else {
+ // They should be at the default.
+ ValidateDefaults(context4, false, event);
+ }
+ event->Wait();
+
+ // Reset to the default values.
+ *PendingAction() = "Reset to the default values.";
+ ValidateDefaults(context, true, event);
+ event->Wait();
+}
+
+// Verify default preference values on a custom request context.
+TEST(PreferenceTest, RequestContextCustomDefaults) {
+ CefRefPtr<CefWaitableEvent> event =
+ CefWaitableEvent::CreateWaitableEvent(true, false);
+
+ CefRequestContextSettings settings;
+ CefRefPtr<CefRequestContext> context = CefRequestContext::CreateContext(
+ settings, new TestRequestContextHandler(event));
+ EXPECT_TRUE(context.get());
+ // Wait for the context to be fully initialized.
+ event->Wait();
+
+ ValidateDefaults(context, false, event);
+ event->Wait();
+}
+
+// Verify setting/getting preference values on a custom request context.
+TEST(PreferenceTest, RequestContextCustomSetGet) {
+ CefRefPtr<CefWaitableEvent> event =
+ CefWaitableEvent::CreateWaitableEvent(true, false);
+
+ CefRequestContextSettings settings;
+ CefRefPtr<CefRequestContext> context = CefRequestContext::CreateContext(
+ settings, new TestRequestContextHandler(event));
+ EXPECT_TRUE(context.get());
+ // Wait for the context to be fully initialized.
+ event->Wait();
+
+ ValidateSetGet(context, event);
+ event->Wait();
+
+ // Reset to the default values.
+ ValidateDefaults(context, true, event);
+ event->Wait();
+}
+
+// Verify setting/getting preference values on shared custom request contexts.
+TEST(PreferenceTest, RequestContextCustomSetGetShared) {
+ CefRefPtr<CefWaitableEvent> event =
+ CefWaitableEvent::CreateWaitableEvent(true, false);
+
+ CefRequestContextSettings settings;
+ CefRefPtr<CefRequestContext> context = CefRequestContext::CreateContext(
+ settings, new TestRequestContextHandler(event));
+ EXPECT_TRUE(context.get());
+ // Wait for the context to be fully initialized.
+ event->Wait();
+
+ // Sharing storage.
+ CefRefPtr<CefRequestContext> context2 =
+ CefRequestContext::CreateContext(context, nullptr);
+ EXPECT_TRUE(context2.get());
+
+ // Sharing storage.
+ CefRefPtr<CefRequestContext> context3 =
+ CefRequestContext::CreateContext(context, new TestRequestContextHandler);
+ EXPECT_TRUE(context3.get());
+
+ // Unassociated context.
+ CefRefPtr<CefRequestContext> context4 = CefRequestContext::CreateContext(
+ settings, new TestRequestContextHandler(event));
+ EXPECT_TRUE(context4.get());
+ // Wait for the context to be fully initialized.
+ event->Wait();
+
+ // Set/get the values on the first context.
+ *PendingAction() = "Set/get the values on the first context";
+ ValidateSetGet(context, event);
+ event->Wait();
+
+ // Get the values from the 2nd and 3d contexts. They should be the same.
+ *PendingAction() = "Get the values from the 2nd context.";
+ ValidateGet(context2, event);
+ event->Wait();
+ *PendingAction() = "Get the values from the 3rd context.";
+ ValidateGet(context3, event);
+ event->Wait();
+
+ // Get the values from the 4th context. They should be at the default.
+ // This works with the Chrome runtime because the preference changes only
+ // exist in the other incognito profile's overlay.
+ *PendingAction() = "Get the values from the 4th context.";
+ ValidateDefaults(context4, false, event);
+ event->Wait();
+
+ // Reset to the default values.
+ *PendingAction() = "Reset to the default values.";
+ ValidateDefaults(context, true, event);
+ event->Wait();
+}
+
+// Entry point for creating preference browser test objects.
+// Called from client_app_delegates.cc.
+void CreatePreferenceBrowserTests(
+ client::ClientAppBrowser::DelegateSet& delegates) {
+ delegates.insert(new PreferenceBrowserTest);
+}
diff --git a/tests/ceftests/print_unittest.cc b/tests/ceftests/print_unittest.cc
new file mode 100644
index 00000000..d05848c0
--- /dev/null
+++ b/tests/ceftests/print_unittest.cc
@@ -0,0 +1,70 @@
+// Copyright (c) 2014 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include <algorithm>
+
+#include "include/cef_print_settings.h"
+#include "tests/gtest/include/gtest/gtest.h"
+
+// Verify Set/Get methods for CefPrintSettings.
+TEST(PrintTest, SettingsSetGet) {
+ // CefRequest CreateRequest
+ CefRefPtr<CefPrintSettings> settings(CefPrintSettings::Create());
+ EXPECT_TRUE(settings.get() != nullptr);
+ EXPECT_TRUE(settings->IsValid());
+ EXPECT_FALSE(settings->IsReadOnly());
+
+ bool landscape = true;
+ settings->SetOrientation(landscape);
+ EXPECT_EQ(landscape, settings->IsLandscape());
+ landscape = false;
+ settings->SetOrientation(landscape);
+ EXPECT_EQ(landscape, settings->IsLandscape());
+
+ const char device_name[] = "my_device_name";
+ settings->SetDeviceName(device_name);
+ EXPECT_STREQ(device_name, settings->GetDeviceName().ToString().c_str());
+
+ int dpi = 25;
+ settings->SetDPI(dpi);
+ EXPECT_EQ(dpi, settings->GetDPI());
+
+ CefPrintSettings::PageRangeList page_ranges;
+ page_ranges.push_back(CefRange(1, 3));
+ page_ranges.push_back(CefRange(5, 6));
+ settings->SetPageRanges(page_ranges);
+ EXPECT_EQ(page_ranges.size(), settings->GetPageRangesCount());
+ CefPrintSettings::PageRangeList page_ranges2;
+ settings->GetPageRanges(page_ranges2);
+ EXPECT_EQ(page_ranges.size(), page_ranges2.size());
+ for (size_t i = 0; i < page_ranges.size(); ++i) {
+ EXPECT_EQ(page_ranges[i], page_ranges2[i]);
+ }
+
+ bool selection_only = true;
+ settings->SetSelectionOnly(selection_only);
+ EXPECT_EQ(selection_only, settings->IsSelectionOnly());
+ selection_only = false;
+ settings->SetSelectionOnly(selection_only);
+ EXPECT_EQ(selection_only, settings->IsSelectionOnly());
+
+ bool collate = true;
+ settings->SetCollate(collate);
+ EXPECT_EQ(collate, settings->WillCollate());
+ collate = false;
+ settings->SetCollate(collate);
+ EXPECT_EQ(collate, settings->WillCollate());
+
+ CefPrintSettings::ColorModel color_model = COLOR_MODEL_CMYK;
+ settings->SetColorModel(color_model);
+ EXPECT_EQ(color_model, settings->GetColorModel());
+
+ int copies = 3;
+ settings->SetCopies(copies);
+ EXPECT_EQ(copies, settings->GetCopies());
+
+ CefPrintSettings::DuplexMode duplex_mode = DUPLEX_MODE_SIMPLEX;
+ settings->SetDuplexMode(duplex_mode);
+ EXPECT_EQ(duplex_mode, settings->GetDuplexMode());
+}
diff --git a/tests/ceftests/process_message_unittest.cc b/tests/ceftests/process_message_unittest.cc
new file mode 100644
index 00000000..a91b2ab2
--- /dev/null
+++ b/tests/ceftests/process_message_unittest.cc
@@ -0,0 +1,201 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "include/base/cef_callback.h"
+#include "include/cef_process_message.h"
+#include "include/cef_task.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "tests/ceftests/test_handler.h"
+#include "tests/ceftests/test_util.h"
+#include "tests/gtest/include/gtest/gtest.h"
+#include "tests/shared/renderer/client_app_renderer.h"
+
+using client::ClientAppRenderer;
+
+namespace {
+
+// Unique values for the SendRecv test.
+const char kSendRecvUrl[] = "http://tests/ProcessMessageTest.SendRecv";
+const char kSendRecvMsg[] = "ProcessMessageTest.SendRecv";
+
+// Creates a test message.
+CefRefPtr<CefProcessMessage> CreateTestMessage() {
+ CefRefPtr<CefProcessMessage> msg = CefProcessMessage::Create(kSendRecvMsg);
+ EXPECT_TRUE(msg.get());
+ EXPECT_TRUE(msg->IsValid());
+ EXPECT_FALSE(msg->IsReadOnly());
+
+ CefRefPtr<CefListValue> args = msg->GetArgumentList();
+ EXPECT_TRUE(args.get());
+ EXPECT_TRUE(args->IsValid());
+ EXPECT_FALSE(args->IsReadOnly());
+
+ size_t index = 0;
+ args->SetNull(index++);
+ args->SetInt(index++, 5);
+ args->SetDouble(index++, 10.543);
+ args->SetBool(index++, true);
+ args->SetString(index++, "test string");
+ args->SetList(index++, args->Copy());
+
+ EXPECT_EQ(index, args->GetSize());
+
+ return msg;
+}
+
+// Renderer side.
+class SendRecvRendererTest : public ClientAppRenderer::Delegate {
+ public:
+ SendRecvRendererTest() {}
+
+ bool OnProcessMessageReceived(CefRefPtr<ClientAppRenderer> app,
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefProcessId source_process,
+ CefRefPtr<CefProcessMessage> message) override {
+ if (message->GetName() == kSendRecvMsg) {
+ EXPECT_TRUE(browser.get());
+ EXPECT_TRUE(frame.get());
+ EXPECT_EQ(PID_BROWSER, source_process);
+ EXPECT_TRUE(message.get());
+ EXPECT_TRUE(message->IsValid());
+ EXPECT_TRUE(message->IsReadOnly());
+
+ const std::string& url = frame->GetURL();
+ if (url == kSendRecvUrl) {
+ // Echo the message back to the sender natively.
+ frame->SendProcessMessage(PID_BROWSER, message);
+ EXPECT_FALSE(message->IsValid());
+ return true;
+ }
+ }
+
+ // Message not handled.
+ return false;
+ }
+
+ IMPLEMENT_REFCOUNTING(SendRecvRendererTest);
+};
+
+// Browser side.
+class SendRecvTestHandler : public TestHandler {
+ public:
+ explicit SendRecvTestHandler(cef_thread_id_t send_thread)
+ : send_thread_(send_thread) {}
+
+ void RunTest() override {
+ AddResource(kSendRecvUrl, "<html><body>TEST</body></html>", "text/html");
+ CreateBrowser(kSendRecvUrl);
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout();
+ }
+
+ void OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int httpStatusCode) override {
+ EXPECT_TRUE(CefCurrentlyOn(TID_UI));
+
+ // Send the message to the renderer process.
+ if (!CefCurrentlyOn(send_thread_)) {
+ CefPostTask(send_thread_,
+ base::BindOnce(&SendRecvTestHandler::SendMessage, this,
+ browser, frame));
+ } else {
+ SendMessage(browser, frame);
+ }
+ }
+
+ bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefProcessId source_process,
+ CefRefPtr<CefProcessMessage> message) override {
+ EXPECT_TRUE(CefCurrentlyOn(TID_UI));
+ EXPECT_TRUE(browser.get());
+ EXPECT_TRUE(frame.get());
+ EXPECT_EQ(PID_RENDERER, source_process);
+ EXPECT_TRUE(message.get());
+ EXPECT_TRUE(message->IsValid());
+ EXPECT_TRUE(message->IsReadOnly());
+
+ // Verify that the recieved message is the same as the sent message.
+ TestProcessMessageEqual(CreateTestMessage(), message);
+
+ got_message_.yes();
+
+ // Test is complete.
+ DestroyTest();
+
+ return true;
+ }
+
+ protected:
+ void DestroyTest() override {
+ EXPECT_TRUE(got_message_);
+ TestHandler::DestroyTest();
+ }
+
+ private:
+ void SendMessage(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame) {
+ EXPECT_TRUE(CefCurrentlyOn(send_thread_));
+ auto message = CreateTestMessage();
+ frame->SendProcessMessage(PID_RENDERER, message);
+
+ // The message will be invalidated immediately, no matter what thread we
+ // send from.
+ EXPECT_FALSE(message->IsValid());
+ }
+
+ cef_thread_id_t send_thread_;
+ TrackCallback got_message_;
+
+ IMPLEMENT_REFCOUNTING(SendRecvTestHandler);
+};
+
+} // namespace
+
+// Verify send from the UI thread and recieve.
+TEST(ProcessMessageTest, SendRecvUI) {
+ CefRefPtr<SendRecvTestHandler> handler = new SendRecvTestHandler(TID_UI);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Verify send from the IO thread and recieve.
+TEST(ProcessMessageTest, SendRecvIO) {
+ CefRefPtr<SendRecvTestHandler> handler = new SendRecvTestHandler(TID_IO);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Verify create.
+TEST(ProcessMessageTest, Create) {
+ CefRefPtr<CefProcessMessage> message =
+ CefProcessMessage::Create(kSendRecvMsg);
+ EXPECT_TRUE(message.get());
+ EXPECT_TRUE(message->IsValid());
+ EXPECT_FALSE(message->IsReadOnly());
+ EXPECT_STREQ(kSendRecvMsg, message->GetName().ToString().c_str());
+
+ CefRefPtr<CefListValue> args = message->GetArgumentList();
+ EXPECT_TRUE(args.get());
+ EXPECT_TRUE(args->IsValid());
+ EXPECT_FALSE(args->IsOwned());
+ EXPECT_FALSE(args->IsReadOnly());
+}
+
+// Verify copy.
+TEST(ProcessMessageTest, Copy) {
+ CefRefPtr<CefProcessMessage> message = CreateTestMessage();
+ CefRefPtr<CefProcessMessage> message2 = message->Copy();
+ TestProcessMessageEqual(message, message2);
+}
+
+// Entry point for creating process message renderer test objects.
+// Called from client_app_delegates.cc.
+void CreateProcessMessageRendererTests(
+ ClientAppRenderer::DelegateSet& delegates) {
+ // For ProcessMessageTest.SendRecv
+ delegates.insert(new SendRecvRendererTest);
+}
diff --git a/tests/ceftests/request_context_unittest.cc b/tests/ceftests/request_context_unittest.cc
new file mode 100644
index 00000000..18a6cc77
--- /dev/null
+++ b/tests/ceftests/request_context_unittest.cc
@@ -0,0 +1,916 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "include/base/cef_callback.h"
+#include "include/cef_request_context.h"
+#include "include/cef_request_context_handler.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "include/wrapper/cef_scoped_temp_dir.h"
+#include "tests/ceftests/test_handler.h"
+#include "tests/ceftests/test_util.h"
+#include "tests/gtest/include/gtest/gtest.h"
+
+TEST(RequestContextTest, BasicGetGlobal) {
+ CefRefPtr<CefRequestContext> context1 = CefRequestContext::GetGlobalContext();
+ EXPECT_TRUE(context1.get());
+ EXPECT_TRUE(context1->IsGlobal());
+ EXPECT_TRUE(context1->IsSame(context1));
+ EXPECT_TRUE(context1->IsSharingWith(context1));
+
+ CefRefPtr<CefRequestContext> context2 = CefRequestContext::GetGlobalContext();
+ EXPECT_TRUE(context2.get());
+ EXPECT_TRUE(context2->IsGlobal());
+ EXPECT_TRUE(context2->IsSame(context2));
+ EXPECT_TRUE(context2->IsSharingWith(context2));
+
+ EXPECT_TRUE(context1->IsSame(context2));
+ EXPECT_TRUE(context2->IsSame(context1));
+ EXPECT_TRUE(context1->IsSharingWith(context2));
+ EXPECT_TRUE(context2->IsSharingWith(context1));
+}
+
+TEST(RequestContextTest, BasicCreate) {
+ class Handler : public CefRequestContextHandler {
+ public:
+ Handler() {}
+
+ private:
+ IMPLEMENT_REFCOUNTING(Handler);
+ };
+
+ CefRefPtr<CefRequestContextHandler> handler = new Handler();
+
+ CefRequestContextSettings settings;
+
+ CefRefPtr<CefRequestContext> context1 =
+ CefRequestContext::CreateContext(settings, handler.get());
+ EXPECT_TRUE(context1.get());
+ EXPECT_FALSE(context1->IsGlobal());
+ EXPECT_TRUE(context1->IsSame(context1));
+ EXPECT_TRUE(context1->IsSharingWith(context1));
+ EXPECT_EQ(context1->GetHandler().get(), handler.get());
+
+ CefRefPtr<CefRequestContext> context2 =
+ CefRequestContext::CreateContext(settings, handler.get());
+ EXPECT_TRUE(context2.get());
+ EXPECT_FALSE(context2->IsGlobal());
+ EXPECT_TRUE(context2->IsSame(context2));
+ EXPECT_TRUE(context2->IsSharingWith(context2));
+ EXPECT_EQ(context2->GetHandler().get(), handler.get());
+
+ EXPECT_FALSE(context1->IsSame(context2));
+ EXPECT_FALSE(context1->IsSharingWith(context2));
+ EXPECT_FALSE(context2->IsSame(context1));
+ EXPECT_FALSE(context2->IsSharingWith(context1));
+
+ CefRefPtr<CefRequestContext> context3 = CefRequestContext::GetGlobalContext();
+ EXPECT_TRUE(context3.get());
+ EXPECT_FALSE(context3->IsSame(context1));
+ EXPECT_FALSE(context3->IsSharingWith(context1));
+ EXPECT_FALSE(context3->IsSame(context2));
+ EXPECT_FALSE(context3->IsSharingWith(context2));
+ EXPECT_FALSE(context1->IsSame(context3));
+ EXPECT_FALSE(context1->IsSharingWith(context3));
+ EXPECT_FALSE(context2->IsSame(context3));
+ EXPECT_FALSE(context2->IsSharingWith(context3));
+}
+
+TEST(RequestContextTest, BasicCreateNoHandler) {
+ CefRequestContextSettings settings;
+
+ CefRefPtr<CefRequestContext> context1 =
+ CefRequestContext::CreateContext(settings, nullptr);
+ EXPECT_TRUE(context1.get());
+ EXPECT_FALSE(context1->IsGlobal());
+ EXPECT_TRUE(context1->IsSame(context1));
+ EXPECT_TRUE(context1->IsSharingWith(context1));
+ EXPECT_FALSE(context1->GetHandler().get());
+
+ CefRefPtr<CefRequestContext> context2 =
+ CefRequestContext::CreateContext(settings, nullptr);
+ EXPECT_TRUE(context2.get());
+ EXPECT_FALSE(context2->IsGlobal());
+ EXPECT_TRUE(context2->IsSame(context2));
+ EXPECT_TRUE(context2->IsSharingWith(context2));
+ EXPECT_FALSE(context2->GetHandler().get());
+
+ EXPECT_FALSE(context1->IsSame(context2));
+ EXPECT_FALSE(context1->IsSharingWith(context2));
+ EXPECT_FALSE(context2->IsSame(context1));
+ EXPECT_FALSE(context2->IsSharingWith(context1));
+
+ CefRefPtr<CefRequestContext> context3 = CefRequestContext::GetGlobalContext();
+ EXPECT_TRUE(context3.get());
+ EXPECT_FALSE(context3->IsSame(context1));
+ EXPECT_FALSE(context3->IsSharingWith(context1));
+ EXPECT_FALSE(context3->IsSame(context2));
+ EXPECT_FALSE(context3->IsSharingWith(context2));
+ EXPECT_FALSE(context1->IsSame(context3));
+ EXPECT_FALSE(context1->IsSharingWith(context3));
+ EXPECT_FALSE(context2->IsSame(context3));
+ EXPECT_FALSE(context2->IsSharingWith(context3));
+}
+
+TEST(RequestContextTest, BasicCreateSharedGlobal) {
+ CefRequestContextSettings settings;
+
+ CefRefPtr<CefRequestContext> context1 = CefRequestContext::GetGlobalContext();
+ EXPECT_TRUE(context1.get());
+ EXPECT_TRUE(context1->IsGlobal());
+ EXPECT_TRUE(context1->IsSame(context1));
+ EXPECT_TRUE(context1->IsSharingWith(context1));
+
+ // Returns the same global context.
+ CefRefPtr<CefRequestContext> context2 =
+ CefRequestContext::CreateContext(context1, nullptr);
+ EXPECT_TRUE(context2.get());
+ EXPECT_TRUE(context2->IsGlobal());
+ EXPECT_TRUE(context2->IsSame(context2));
+ EXPECT_TRUE(context2->IsSame(context1));
+ EXPECT_TRUE(context1->IsSame(context2));
+ EXPECT_TRUE(context2->IsSharingWith(context2));
+ EXPECT_TRUE(context2->IsSharingWith(context1));
+ EXPECT_TRUE(context1->IsSharingWith(context2));
+}
+
+TEST(RequestContextTest, BasicCreateSharedOnDisk) {
+ CefScopedTempDir tempdir;
+ EXPECT_TRUE(tempdir.CreateUniqueTempDirUnderPath(
+ CefTestSuite::GetInstance()->root_cache_path()));
+
+ CefRequestContextSettings settings;
+ CefString(&settings.cache_path) = tempdir.GetPath();
+
+ CefRefPtr<CefRequestContext> context1 =
+ CefRequestContext::CreateContext(settings, nullptr);
+ EXPECT_TRUE(context1.get());
+ EXPECT_FALSE(context1->IsGlobal());
+ EXPECT_TRUE(context1->IsSame(context1));
+ EXPECT_TRUE(context1->IsSharingWith(context1));
+
+ CefRefPtr<CefRequestContext> context2 =
+ CefRequestContext::CreateContext(context1, nullptr);
+ EXPECT_TRUE(context2.get());
+ EXPECT_FALSE(context2->IsGlobal());
+ EXPECT_TRUE(context2->IsSame(context2));
+ EXPECT_FALSE(context2->IsSame(context1));
+ EXPECT_FALSE(context1->IsSame(context2));
+ EXPECT_TRUE(context2->IsSharingWith(context2));
+ EXPECT_TRUE(context2->IsSharingWith(context1));
+ EXPECT_TRUE(context1->IsSharingWith(context2));
+
+ CefRefPtr<CefRequestContext> context3 =
+ CefRequestContext::CreateContext(context2, nullptr);
+ EXPECT_TRUE(context3.get());
+ EXPECT_FALSE(context3->IsGlobal());
+ EXPECT_TRUE(context3->IsSame(context3));
+ EXPECT_FALSE(context3->IsSame(context2));
+ EXPECT_FALSE(context3->IsSame(context1));
+ EXPECT_FALSE(context1->IsSame(context3));
+ EXPECT_FALSE(context2->IsSame(context3));
+ EXPECT_TRUE(context3->IsSharingWith(context3));
+ EXPECT_TRUE(context3->IsSharingWith(context2));
+ EXPECT_TRUE(context3->IsSharingWith(context1));
+ EXPECT_TRUE(context1->IsSharingWith(context3));
+ EXPECT_TRUE(context2->IsSharingWith(context3));
+
+ CefRefPtr<CefRequestContext> context4 =
+ CefRequestContext::CreateContext(context1, nullptr);
+ EXPECT_TRUE(context4.get());
+ EXPECT_FALSE(context4->IsGlobal());
+ EXPECT_TRUE(context4->IsSame(context4));
+ EXPECT_FALSE(context4->IsSame(context3));
+ EXPECT_FALSE(context4->IsSame(context2));
+ EXPECT_FALSE(context4->IsSame(context1));
+ EXPECT_FALSE(context1->IsSame(context4));
+ EXPECT_FALSE(context2->IsSame(context4));
+ EXPECT_FALSE(context3->IsSame(context4));
+ EXPECT_TRUE(context4->IsSharingWith(context4));
+ EXPECT_TRUE(context4->IsSharingWith(context3));
+ EXPECT_TRUE(context4->IsSharingWith(context2));
+ EXPECT_TRUE(context4->IsSharingWith(context1));
+ EXPECT_TRUE(context1->IsSharingWith(context4));
+ EXPECT_TRUE(context2->IsSharingWith(context4));
+ EXPECT_TRUE(context3->IsSharingWith(context4));
+}
+
+namespace {
+
+class PopupTestHandler : public TestHandler {
+ public:
+ enum Mode {
+ MODE_WINDOW_OPEN,
+ MODE_TARGETED_LINK,
+ MODE_NOREFERRER_LINK,
+ };
+
+ PopupTestHandler(bool same_origin, Mode mode) : mode_(mode) {
+ url_ = "http://tests-simple-rch1.com/nav1.html";
+ if (same_origin) {
+ popup_url_ = "http://tests-simple-rch1.com/pop1.html";
+ } else {
+ popup_url_ = "http://tests-simple-rch2.com/pop1.html";
+ }
+ }
+
+ void RunTest() override {
+ std::string link;
+ if (mode_ == MODE_TARGETED_LINK) {
+ link = "<a href=\"" + std::string(popup_url_) +
+ "\" target=\"mytarget\"\">CLICK ME</a>";
+ } else if (mode_ == MODE_NOREFERRER_LINK) {
+ link = "<a href=\"" + std::string(popup_url_) +
+ "\" rel=\"noreferrer\" target=\"_blank\"\">CLICK ME</a>";
+ }
+
+ AddResource(url_,
+ "<html>"
+ "<head><script>document.cookie='name1=value1';"
+ "function doPopup() { window.open('" +
+ std::string(popup_url_) +
+ "'); }"
+ "</script></head>"
+ "<body><h1>" +
+ link +
+ "</h1></body>"
+ "</html>",
+ "text/html");
+
+ AddResource(popup_url_,
+ "<html>"
+ "<head><script>document.cookie='name2=value2';</script></head>"
+ "<body>Nav1</body>"
+ "</html>",
+ "text/html");
+
+ CefRequestContextSettings settings;
+
+ context_ = CefRequestContext::CreateContext(settings, nullptr);
+ cookie_manager_ = context_->GetCookieManager(nullptr);
+
+ // Create browser that loads the 1st URL.
+ CreateBrowser(url_, context_);
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout();
+ }
+
+ void OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int httpStatusCode) override {
+ CefRefPtr<CefRequestContext> context =
+ browser->GetHost()->GetRequestContext();
+ EXPECT_TRUE(context.get());
+ EXPECT_TRUE(context->IsSame(context_));
+ EXPECT_FALSE(context->IsGlobal());
+
+ EXPECT_TRUE(frame->IsMain());
+
+ const std::string& url = frame->GetURL();
+ if (url == url_) {
+ got_load_end1_.yes();
+ LaunchPopup(browser);
+ } else if (url == popup_url_) {
+ got_load_end2_.yes();
+ EXPECT_TRUE(browser->IsPopup());
+ // Close the popup window.
+ CloseBrowser(browser, true);
+ }
+ }
+
+ bool OnBeforePopup(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const CefString& target_url,
+ const CefString& target_frame_name,
+ cef_window_open_disposition_t target_disposition,
+ bool user_gesture,
+ const CefPopupFeatures& popupFeatures,
+ CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient>& client,
+ CefBrowserSettings& settings,
+ CefRefPtr<CefDictionaryValue>& extra_info,
+ bool* no_javascript_access) override {
+ got_on_before_popup_.yes();
+
+ const std::string& url = target_url;
+ EXPECT_STREQ(url.c_str(), popup_url_.c_str());
+
+ EXPECT_EQ(WOD_NEW_FOREGROUND_TAB, target_disposition);
+
+ if (mode_ == MODE_WINDOW_OPEN) {
+ EXPECT_FALSE(user_gesture);
+ } else {
+ EXPECT_TRUE(user_gesture);
+ }
+
+ return false;
+ }
+
+ void OnBeforeClose(CefRefPtr<CefBrowser> browser) override {
+ TestHandler::OnBeforeClose(browser);
+
+ if (browser->IsPopup()) {
+ FinishTest();
+ }
+ }
+
+ protected:
+ void LaunchPopup(CefRefPtr<CefBrowser> browser) {
+ if (mode_ == MODE_WINDOW_OPEN) {
+ browser->GetMainFrame()->ExecuteJavaScript("doPopup()", url_, 0);
+ } else if (mode_ == MODE_TARGETED_LINK || mode_ == MODE_NOREFERRER_LINK) {
+ CefMouseEvent mouse_event;
+ mouse_event.x = 20;
+ mouse_event.y = 20;
+ mouse_event.modifiers = 0;
+ SendMouseClickEvent(browser, mouse_event);
+ } else {
+ ADD_FAILURE(); // Not reached.
+ }
+ }
+
+ void FinishTest() {
+ // Verify that the cookies were set correctly.
+ class TestVisitor : public CefCookieVisitor {
+ public:
+ explicit TestVisitor(PopupTestHandler* handler) : handler_(handler) {}
+ ~TestVisitor() override {
+ // Destroy the test.
+ CefPostTask(TID_UI,
+ base::BindOnce(&PopupTestHandler::DestroyTest, handler_));
+ }
+
+ bool Visit(const CefCookie& cookie,
+ int count,
+ int total,
+ bool& deleteCookie) override {
+ const std::string& name = CefString(&cookie.name);
+ const std::string& value = CefString(&cookie.value);
+ if (name == "name1" && value == "value1") {
+ handler_->got_cookie1_.yes();
+ deleteCookie = true;
+ } else if (name == "name2" && value == "value2") {
+ handler_->got_cookie2_.yes();
+ deleteCookie = true;
+ }
+ return true;
+ }
+
+ private:
+ PopupTestHandler* handler_;
+ IMPLEMENT_REFCOUNTING(TestVisitor);
+ };
+
+ cookie_manager_->VisitAllCookies(new TestVisitor(this));
+ }
+
+ void DestroyTest() override {
+ // Verify test expectations.
+ EXPECT_TRUE(got_load_end1_);
+ EXPECT_TRUE(got_on_before_popup_);
+ EXPECT_TRUE(got_load_end2_);
+ EXPECT_TRUE(got_cookie1_);
+ EXPECT_TRUE(got_cookie2_);
+ context_ = nullptr;
+
+ TestHandler::DestroyTest();
+ }
+
+ std::string url_;
+ std::string popup_url_;
+ Mode mode_;
+
+ CefRefPtr<CefRequestContext> context_;
+ CefRefPtr<CefCookieManager> cookie_manager_;
+
+ TrackCallback got_load_end1_;
+ TrackCallback got_on_before_popup_;
+ TrackCallback got_load_end2_;
+ TrackCallback got_cookie1_;
+ TrackCallback got_cookie2_;
+
+ IMPLEMENT_REFCOUNTING(PopupTestHandler);
+};
+
+} // namespace
+
+// Test that a popup created using window.open() will get the same request
+// context as the parent browser.
+TEST(RequestContextTest, PopupBasicWindowOpenSameOrigin) {
+ CefRefPtr<PopupTestHandler> handler =
+ new PopupTestHandler(true, PopupTestHandler::MODE_WINDOW_OPEN);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(RequestContextTest, PopupBasicWindowOpenDifferentOrigin) {
+ CefRefPtr<PopupTestHandler> handler =
+ new PopupTestHandler(false, PopupTestHandler::MODE_WINDOW_OPEN);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Test that a popup created using a targeted link will get the same request
+// context as the parent browser.
+TEST(RequestContextTest, PopupBasicTargetedLinkSameOrigin) {
+ CefRefPtr<PopupTestHandler> handler =
+ new PopupTestHandler(true, PopupTestHandler::MODE_TARGETED_LINK);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(RequestContextTest, PopupBasicTargetedLinkDifferentOrigin) {
+ CefRefPtr<PopupTestHandler> handler =
+ new PopupTestHandler(false, PopupTestHandler::MODE_TARGETED_LINK);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Test that a popup created using a noreferrer link will get the same
+// request context as the parent browser. A new render process will
+// be created for the popup browser.
+TEST(RequestContextTest, PopupBasicNoReferrerLinkSameOrigin) {
+ CefRefPtr<PopupTestHandler> handler =
+ new PopupTestHandler(true, PopupTestHandler::MODE_NOREFERRER_LINK);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(RequestContextTest, PopupBasicNoReferrerLinkDifferentOrigin) {
+ CefRefPtr<PopupTestHandler> handler =
+ new PopupTestHandler(false, PopupTestHandler::MODE_NOREFERRER_LINK);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+namespace {
+
+const char kPopupNavPageUrl[] = "http://tests-popup.com/page.html";
+const char kPopupNavPopupUrl[] = "http://tests-popup.com/popup.html";
+const char kPopupNavPopupUrl2[] = "http://tests-popup2.com/popup.html";
+const char kPopupNavPopupName[] = "my_popup";
+
+// Browser side.
+class PopupNavTestHandler : public TestHandler {
+ public:
+ enum TestMode {
+ ALLOW_CLOSE_POPUP_FIRST,
+ ALLOW_CLOSE_POPUP_LAST,
+ DENY,
+ NAVIGATE_AFTER_CREATION,
+ DESTROY_PARENT_BEFORE_CREATION,
+ DESTROY_PARENT_BEFORE_CREATION_FORCE,
+ DESTROY_PARENT_DURING_CREATION,
+ DESTROY_PARENT_DURING_CREATION_FORCE,
+ DESTROY_PARENT_AFTER_CREATION,
+ DESTROY_PARENT_AFTER_CREATION_FORCE,
+ };
+
+ PopupNavTestHandler(TestMode test_mode,
+ TestRequestContextMode rc_mode,
+ const std::string& rc_cache_path)
+ : mode_(test_mode), rc_mode_(rc_mode), rc_cache_path_(rc_cache_path) {}
+
+ void RunTest() override {
+ // Add the resources that we will navigate to/from.
+ std::string page = "<html><script>function doPopup() { window.open('" +
+ std::string(kPopupNavPopupUrl) + "', '" +
+ std::string(kPopupNavPopupName) +
+ "'); }</script>Page</html>";
+ AddResource(kPopupNavPageUrl, page, "text/html");
+ AddResource(kPopupNavPopupUrl, "<html>Popup</html>", "text/html");
+ if (mode_ == NAVIGATE_AFTER_CREATION) {
+ AddResource(kPopupNavPopupUrl2, "<html>Popup2</html>", "text/html");
+ }
+
+ CefRefPtr<CefRequestContext> request_context =
+ CreateTestRequestContext(rc_mode_, rc_cache_path_);
+
+ // Create the browser.
+ CreateBrowser(kPopupNavPageUrl, request_context);
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout();
+ }
+
+ bool OnBeforePopup(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const CefString& target_url,
+ const CefString& target_frame_name,
+ cef_window_open_disposition_t target_disposition,
+ bool user_gesture,
+ const CefPopupFeatures& popupFeatures,
+ CefWindowInfo& windowInfo,
+ CefRefPtr<CefClient>& client,
+ CefBrowserSettings& settings,
+ CefRefPtr<CefDictionaryValue>& extra_info,
+ bool* no_javascript_access) override {
+ EXPECT_FALSE(got_on_before_popup_);
+ got_on_before_popup_.yes();
+
+ EXPECT_TRUE(CefCurrentlyOn(TID_UI));
+ EXPECT_EQ(GetBrowserId(), browser->GetIdentifier());
+ EXPECT_STREQ(kPopupNavPageUrl, frame->GetURL().ToString().c_str());
+ EXPECT_STREQ(kPopupNavPopupUrl, target_url.ToString().c_str());
+ EXPECT_STREQ(kPopupNavPopupName, target_frame_name.ToString().c_str());
+ EXPECT_EQ(WOD_NEW_FOREGROUND_TAB, target_disposition);
+ EXPECT_FALSE(user_gesture);
+ EXPECT_FALSE(*no_javascript_access);
+
+ if (mode_ == DESTROY_PARENT_DURING_CREATION ||
+ mode_ == DESTROY_PARENT_DURING_CREATION_FORCE) {
+ // Destroy the main (parent) browser while popup creation is pending.
+ CloseBrowser(browser, mode_ == DESTROY_PARENT_DURING_CREATION_FORCE);
+ }
+
+ return (mode_ == DENY); // Return true to cancel the popup.
+ }
+
+ void OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
+ TestHandler::OnAfterCreated(browser);
+
+ if (browser->IsPopup() && (mode_ == DESTROY_PARENT_AFTER_CREATION ||
+ mode_ == DESTROY_PARENT_AFTER_CREATION_FORCE)) {
+ // Destroy the main (parent) browser immediately after the popup is
+ // created.
+ CloseBrowser(GetBrowser(), mode_ == DESTROY_PARENT_AFTER_CREATION_FORCE);
+ }
+
+ if (mode_ == NAVIGATE_AFTER_CREATION && browser->IsPopup()) {
+ // Navigate to the 2nd popup URL instead of the 1st popup URL.
+ browser->GetMainFrame()->LoadURL(kPopupNavPopupUrl2);
+ }
+ }
+
+ void OnLoadStart(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ TransitionType transition_type) override {
+ const std::string& url = frame->GetURL();
+ if (url == kPopupNavPageUrl) {
+ EXPECT_FALSE(got_load_start_);
+ got_load_start_.yes();
+ } else if (url == kPopupNavPopupUrl) {
+ EXPECT_FALSE(got_popup_load_start_);
+ got_popup_load_start_.yes();
+ } else if (url == kPopupNavPopupUrl2) {
+ EXPECT_FALSE(got_popup_load_start2_);
+ got_popup_load_start2_.yes();
+ }
+ }
+
+ void OnLoadError(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ ErrorCode errorCode,
+ const CefString& errorText,
+ const CefString& failedUrl) override {
+ if (failedUrl == kPopupNavPageUrl) {
+ EXPECT_FALSE(got_load_error_);
+ got_load_error_.yes();
+ } else if (failedUrl == kPopupNavPopupUrl) {
+ EXPECT_FALSE(got_popup_load_error_);
+ got_popup_load_error_.yes();
+ } else if (failedUrl == kPopupNavPopupUrl2) {
+ EXPECT_FALSE(got_popup_load_error2_);
+ got_popup_load_error2_.yes();
+ }
+ }
+
+ void OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int httpStatusCode) override {
+ const std::string& url = frame->GetURL();
+ if (url == kPopupNavPageUrl) {
+ EXPECT_FALSE(got_load_end_);
+ got_load_end_.yes();
+
+ frame->ExecuteJavaScript("doPopup()", kPopupNavPageUrl, 0);
+
+ if (mode_ == DESTROY_PARENT_BEFORE_CREATION ||
+ mode_ == DESTROY_PARENT_BEFORE_CREATION_FORCE) {
+ // Destroy the main (parent) browser immediately before the popup is
+ // created.
+ CloseBrowser(browser, mode_ == DESTROY_PARENT_BEFORE_CREATION_FORCE);
+ }
+
+ if (mode_ == DENY) {
+ // Wait a bit to make sure the popup window isn't created.
+ CefPostDelayedTask(
+ TID_UI, base::BindOnce(&PopupNavTestHandler::DestroyTest, this),
+ 200);
+ }
+ } else if (url == kPopupNavPopupUrl) {
+ EXPECT_FALSE(got_popup_load_end_);
+ got_popup_load_end_.yes();
+
+ if (mode_ == ALLOW_CLOSE_POPUP_FIRST) {
+ // Close the popup browser first.
+ CloseBrowser(browser, false);
+ } else if (mode_ == ALLOW_CLOSE_POPUP_LAST) {
+ // Close the main browser first.
+ CloseBrowser(GetBrowser(), false);
+ } else if (mode_ != NAVIGATE_AFTER_CREATION) {
+ EXPECT_FALSE(true); // Not reached.
+ }
+ } else if (url == kPopupNavPopupUrl2) {
+ EXPECT_FALSE(got_popup_load_end2_);
+ got_popup_load_end2_.yes();
+
+ if (mode_ == NAVIGATE_AFTER_CREATION) {
+ // Close the popup browser first.
+ CloseBrowser(browser, false);
+ } else {
+ EXPECT_FALSE(true); // Not reached.
+ }
+ } else {
+ EXPECT_FALSE(true); // Not reached.
+ }
+ }
+
+ void OnBeforeClose(CefRefPtr<CefBrowser> browser) override {
+ TestHandler::OnBeforeClose(browser);
+
+ bool destroy_test = false;
+ if (mode_ == ALLOW_CLOSE_POPUP_FIRST || mode_ == NAVIGATE_AFTER_CREATION) {
+ // Destroy the test after the popup browser closes.
+ if (browser->IsPopup()) {
+ destroy_test = true;
+ }
+ } else if (mode_ == ALLOW_CLOSE_POPUP_LAST ||
+ mode_ == DESTROY_PARENT_BEFORE_CREATION ||
+ mode_ == DESTROY_PARENT_BEFORE_CREATION_FORCE ||
+ mode_ == DESTROY_PARENT_DURING_CREATION ||
+ mode_ == DESTROY_PARENT_DURING_CREATION_FORCE ||
+ mode_ == DESTROY_PARENT_AFTER_CREATION ||
+ mode_ == DESTROY_PARENT_AFTER_CREATION_FORCE) {
+ // Destroy the test after the main browser closes.
+ if (!browser->IsPopup()) {
+ destroy_test = true;
+ }
+ }
+
+ if (destroy_test) {
+ CefPostTask(TID_UI,
+ base::BindOnce(&PopupNavTestHandler::DestroyTest, this));
+ }
+ }
+
+ private:
+ void DestroyTest() override {
+ EXPECT_TRUE(got_load_start_);
+ EXPECT_FALSE(got_load_error_);
+ EXPECT_TRUE(got_load_end_);
+
+ // OnBeforePopup may come before or after browser destruction with the
+ // DESTROY_PARENT_BEFORE_CREATION* tests.
+ if (mode_ != DESTROY_PARENT_BEFORE_CREATION &&
+ mode_ != DESTROY_PARENT_BEFORE_CREATION_FORCE) {
+ EXPECT_TRUE(got_on_before_popup_);
+ }
+
+ if (mode_ == ALLOW_CLOSE_POPUP_FIRST || mode_ == ALLOW_CLOSE_POPUP_LAST) {
+ EXPECT_TRUE(got_popup_load_start_);
+ EXPECT_FALSE(got_popup_load_error_);
+ EXPECT_TRUE(got_popup_load_end_);
+ EXPECT_FALSE(got_popup_load_start2_);
+ EXPECT_FALSE(got_popup_load_error2_);
+ EXPECT_FALSE(got_popup_load_end2_);
+ } else if (mode_ == DENY || mode_ == DESTROY_PARENT_BEFORE_CREATION ||
+ mode_ == DESTROY_PARENT_BEFORE_CREATION_FORCE ||
+ mode_ == DESTROY_PARENT_DURING_CREATION ||
+ mode_ == DESTROY_PARENT_DURING_CREATION_FORCE ||
+ mode_ == DESTROY_PARENT_AFTER_CREATION ||
+ mode_ == DESTROY_PARENT_AFTER_CREATION_FORCE) {
+ EXPECT_FALSE(got_popup_load_start_);
+ EXPECT_FALSE(got_popup_load_error_);
+ EXPECT_FALSE(got_popup_load_end_);
+ EXPECT_FALSE(got_popup_load_start2_);
+ EXPECT_FALSE(got_popup_load_error2_);
+ EXPECT_FALSE(got_popup_load_end2_);
+ } else if (mode_ == NAVIGATE_AFTER_CREATION) {
+ EXPECT_FALSE(got_popup_load_start_);
+
+ // With browser-side navigation we will never actually begin the
+ // navigation to the 1st popup URL, so there will be no load error.
+ EXPECT_FALSE(got_popup_load_error_);
+
+ EXPECT_FALSE(got_popup_load_end_);
+ EXPECT_TRUE(got_popup_load_start2_);
+ EXPECT_FALSE(got_popup_load_error2_);
+ EXPECT_TRUE(got_popup_load_end2_);
+ }
+
+ // Will trigger destruction of all remaining browsers.
+ TestHandler::DestroyTest();
+ }
+
+ const TestMode mode_;
+ const TestRequestContextMode rc_mode_;
+ const std::string rc_cache_path_;
+
+ TrackCallback got_on_before_popup_;
+ TrackCallback got_load_start_;
+ TrackCallback got_load_error_;
+ TrackCallback got_load_end_;
+ TrackCallback got_popup_load_start_;
+ TrackCallback got_popup_load_error_;
+ TrackCallback got_popup_load_end_;
+ TrackCallback got_popup_load_start2_;
+ TrackCallback got_popup_load_error2_;
+ TrackCallback got_popup_load_end2_;
+
+ IMPLEMENT_REFCOUNTING(PopupNavTestHandler);
+};
+
+} // namespace
+#define POPUP_TEST_GROUP(test_name, test_mode) \
+ RC_TEST_GROUP_IN_MEMORY(RequestContextTest, PopupNav##test_name, \
+ PopupNavTestHandler, test_mode)
+
+// Test allowing popups and closing the popup browser first.
+POPUP_TEST_GROUP(AllowClosePopupFirst, ALLOW_CLOSE_POPUP_FIRST)
+
+// Test allowing popups and closing the main browser first to verify
+// that internal objects are tracked correctly (see issue #2162).
+POPUP_TEST_GROUP(AllowClosePopupLast, ALLOW_CLOSE_POPUP_LAST)
+
+// Test denying popups.
+POPUP_TEST_GROUP(Deny, DENY)
+
+// Test navigation to a different origin after popup creation to
+// verify that internal objects are tracked correctly (see issue
+// #1392).
+POPUP_TEST_GROUP(NavigateAfterCreation, NAVIGATE_AFTER_CREATION)
+
+// Test destroying the parent browser during or immediately after
+// popup creation to verify that internal objects are tracked
+// correctly (see issue #2041).
+POPUP_TEST_GROUP(DestroyParentBeforeCreation, DESTROY_PARENT_BEFORE_CREATION)
+POPUP_TEST_GROUP(DestroyParentBeforeCreationForce,
+ DESTROY_PARENT_BEFORE_CREATION_FORCE)
+POPUP_TEST_GROUP(DestroyParentDuringCreation, DESTROY_PARENT_DURING_CREATION)
+POPUP_TEST_GROUP(DestroyParentDuringCreationForce,
+ DESTROY_PARENT_DURING_CREATION_FORCE)
+POPUP_TEST_GROUP(DestroyParentAfterCreation, DESTROY_PARENT_AFTER_CREATION)
+POPUP_TEST_GROUP(DestroyParentAfterCreationForce,
+ DESTROY_PARENT_AFTER_CREATION_FORCE)
+
+namespace {
+
+const char kResolveOrigin[] = "http://www.google.com";
+
+class MethodTestHandler : public TestHandler {
+ public:
+ enum Method {
+ METHOD_CLEAR_CERTIFICATE_EXCEPTIONS,
+ METHOD_CLOSE_ALL_CONNECTIONS,
+ METHOD_RESOLVE_HOST,
+ };
+
+ class CompletionCallback : public CefCompletionCallback,
+ public CefResolveCallback {
+ public:
+ CompletionCallback(MethodTestHandler* test_handler,
+ CefRefPtr<CefBrowser> browser)
+ : test_handler_(test_handler), browser_(browser) {}
+
+ ~CompletionCallback() override {
+ // OnComplete should be executed.
+ EXPECT_FALSE(test_handler_);
+ }
+
+ void OnComplete() override {
+ EXPECT_UI_THREAD();
+
+ // OnComplete should be executed only one time.
+ EXPECT_TRUE(test_handler_);
+ test_handler_->OnCompleteCallback(browser_);
+ test_handler_ = nullptr;
+ browser_ = nullptr;
+ }
+
+ void OnResolveCompleted(
+ cef_errorcode_t result,
+ const std::vector<CefString>& resolved_ips) override {
+ EXPECT_EQ(ERR_NONE, result);
+ EXPECT_TRUE(!resolved_ips.empty());
+ OnComplete();
+ }
+
+ private:
+ MethodTestHandler* test_handler_;
+ CefRefPtr<CefBrowser> browser_;
+
+ IMPLEMENT_REFCOUNTING(CompletionCallback);
+ };
+
+ MethodTestHandler(bool global_context, Method method)
+ : global_context_(global_context), method_(method) {}
+
+ void RunTest() override {
+ const char kUrl[] = "http://tests/method.html";
+
+ AddResource(kUrl, "<html><body>Method</body></html>", "text/html");
+
+ CefRefPtr<CefRequestContext> request_context;
+ if (!global_context_) {
+ CefRequestContextSettings settings;
+ request_context = CefRequestContext::CreateContext(settings, nullptr);
+ }
+
+ CreateBrowser(kUrl, request_context);
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout();
+ }
+
+ void OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int httpStatusCode) override {
+ CefRefPtr<CefRequestContext> context =
+ browser->GetHost()->GetRequestContext();
+ CefRefPtr<CompletionCallback> callback =
+ new CompletionCallback(this, browser);
+ if (method_ == METHOD_CLEAR_CERTIFICATE_EXCEPTIONS) {
+ context->ClearCertificateExceptions(callback);
+ } else if (method_ == METHOD_CLOSE_ALL_CONNECTIONS) {
+ context->CloseAllConnections(callback);
+ } else if (method_ == METHOD_RESOLVE_HOST) {
+ context->ResolveHost(kResolveOrigin, callback);
+ }
+ }
+
+ void OnCompleteCallback(CefRefPtr<CefBrowser> browser) {
+ EXPECT_UI_THREAD();
+ EXPECT_FALSE(got_completion_callback_);
+ got_completion_callback_.yes();
+
+ DestroyTest();
+ }
+
+ private:
+ void DestroyTest() override {
+ EXPECT_TRUE(got_completion_callback_);
+ TestHandler::DestroyTest();
+ }
+
+ const bool global_context_;
+ const Method method_;
+
+ TrackCallback got_completion_callback_;
+
+ IMPLEMENT_REFCOUNTING(MethodTestHandler);
+};
+
+} // namespace
+
+// Test CefRequestContext::ClearCertificateExceptions with the global
+// context.
+TEST(RequestContextTest, ClearCertificateExceptionsGlobal) {
+ CefRefPtr<MethodTestHandler> handler = new MethodTestHandler(
+ true, MethodTestHandler::METHOD_CLEAR_CERTIFICATE_EXCEPTIONS);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Test CefRequestContext::ClearCertificateExceptions with a custom
+// context.
+TEST(RequestContextTest, ClearCertificateExceptionsCustom) {
+ CefRefPtr<MethodTestHandler> handler = new MethodTestHandler(
+ false, MethodTestHandler::METHOD_CLEAR_CERTIFICATE_EXCEPTIONS);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Test CefRequestContext::CloseAllConnections with the global
+// context.
+TEST(RequestContextTest, CloseAllConnectionsGlobal) {
+ CefRefPtr<MethodTestHandler> handler = new MethodTestHandler(
+ true, MethodTestHandler::METHOD_CLOSE_ALL_CONNECTIONS);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Test CefRequestContext::CloseAllConnections with a custom context.
+TEST(RequestContextTest, CloseAllConnectionsCustom) {
+ CefRefPtr<MethodTestHandler> handler = new MethodTestHandler(
+ false, MethodTestHandler::METHOD_CLOSE_ALL_CONNECTIONS);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Test CefRequestContext::ResolveHost with the global context.
+TEST(RequestContextTest, ResolveHostGlobal) {
+ CefRefPtr<MethodTestHandler> handler =
+ new MethodTestHandler(true, MethodTestHandler::METHOD_RESOLVE_HOST);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Test CefRequestContext::ResolveHost with a custom context.
+TEST(RequestContextTest, ResolveHostCustom) {
+ CefRefPtr<MethodTestHandler> handler =
+ new MethodTestHandler(false, MethodTestHandler::METHOD_RESOLVE_HOST);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
diff --git a/tests/ceftests/request_handler_unittest.cc b/tests/ceftests/request_handler_unittest.cc
new file mode 100644
index 00000000..a86df244
--- /dev/null
+++ b/tests/ceftests/request_handler_unittest.cc
@@ -0,0 +1,539 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include <algorithm>
+#include <cmath>
+#include <memory>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include "include/base/cef_callback.h"
+#include "include/cef_cookie.h"
+#include "include/cef_request_context_handler.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "include/wrapper/cef_stream_resource_handler.h"
+#include "tests/ceftests/test_handler.h"
+#include "tests/ceftests/test_util.h"
+#include "tests/gtest/include/gtest/gtest.h"
+#include "tests/shared/browser/client_app_browser.h"
+#include "tests/shared/renderer/client_app_renderer.h"
+
+using client::ClientAppBrowser;
+using client::ClientAppRenderer;
+
+namespace {
+
+enum NetNotifyTestType {
+ NNTT_NONE = 0,
+ NNTT_NORMAL,
+ NNTT_DELAYED_RENDERER,
+ NNTT_DELAYED_BROWSER,
+};
+
+const char kNetNotifyOrigin1[] = "http://tests-netnotify1/";
+const char kNetNotifyOrigin2[] = "http://tests-netnotify2/";
+const char kNetNotifyMsg[] = "RequestHandlerTest.NetNotify";
+const char kNetNotifyTestCmdKey[] = "rh-net-notify-test";
+
+// Browser side.
+class NetNotifyTestHandler : public TestHandler {
+ public:
+ NetNotifyTestHandler(CompletionState* completion_state,
+ NetNotifyTestType test_type,
+ bool same_origin)
+ : TestHandler(completion_state),
+ test_type_(test_type),
+ same_origin_(same_origin) {}
+
+ void SetupTest() override {
+ std::stringstream ss;
+ ss << kNetNotifyOrigin1 << "nav1.html?t=" << test_type_;
+ url1_ = ss.str();
+ ss.str("");
+ ss << (same_origin_ ? kNetNotifyOrigin1 : kNetNotifyOrigin2)
+ << "nav2.html?t=" << test_type_;
+ url2_ = ss.str();
+
+ const std::string& resource1 =
+ "<html>"
+ "<head><script>document.cookie='name1=value1';</script></head>"
+ "<body>Nav1</body>"
+ "</html>";
+ response_length1_ = static_cast<int64>(resource1.size());
+ AddResource(url1_, resource1, "text/html");
+
+ const std::string& resource2 =
+ "<html>"
+ "<head><script>document.cookie='name2=value2';</script></head>"
+ "<body>Nav2</body>"
+ "</html>";
+ response_length2_ = static_cast<int64>(resource2.size());
+ AddResource(url2_, resource2, "text/html");
+
+ // Create the request context that will use an in-memory cache.
+ CefRequestContextSettings settings;
+ CefRefPtr<CefRequestContext> request_context =
+ CefRequestContext::CreateContext(settings, nullptr);
+ cookie_manager_ = request_context->GetCookieManager(nullptr);
+
+ CefRefPtr<CefDictionaryValue> extra_info = CefDictionaryValue::Create();
+ extra_info->SetBool(kNetNotifyTestCmdKey, true);
+
+ // Create browser that loads the 1st URL.
+ CreateBrowser(url1_, request_context, extra_info);
+ }
+
+ void RunTest() override {
+ // Navigate to the 2nd URL.
+ GetBrowser()->GetMainFrame()->LoadURL(url2_);
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout();
+ }
+
+ cef_return_value_t OnBeforeResourceLoad(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefCallback> callback) override {
+ EXPECT_TRUE(CefCurrentlyOn(TID_IO));
+
+ const std::string& url = request->GetURL();
+ if (IgnoreURL(url)) {
+ return RV_CONTINUE;
+ }
+
+ if (url.find(url1_) == 0) {
+ got_before_resource_load1_.yes();
+ } else if (url.find(url2_) == 0) {
+ got_before_resource_load2_.yes();
+ } else {
+ EXPECT_TRUE(false); // Not reached
+ }
+
+ return RV_CONTINUE;
+ }
+
+ CefRefPtr<CefResourceHandler> GetResourceHandler(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request) override {
+ EXPECT_TRUE(CefCurrentlyOn(TID_IO));
+
+ const std::string& url = request->GetURL();
+ if (IgnoreURL(url)) {
+ return nullptr;
+ }
+
+ if (url.find(url1_) == 0) {
+ got_get_resource_handler1_.yes();
+ } else if (url.find(url2_) == 0) {
+ got_get_resource_handler2_.yes();
+ } else {
+ EXPECT_TRUE(false); // Not reached
+ }
+
+ return TestHandler::GetResourceHandler(browser, frame, request);
+ }
+
+ void OnResourceLoadComplete(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response,
+ URLRequestStatus status,
+ int64 received_content_length) override {
+ EXPECT_TRUE(CefCurrentlyOn(TID_IO));
+
+ const std::string& url = request->GetURL();
+ if (IgnoreURL(url)) {
+ return;
+ }
+
+ EXPECT_EQ(UR_SUCCESS, status);
+ if (url.find(url1_) == 0) {
+ got_resource_load_complete1_.yes();
+ EXPECT_EQ(response_length1_, received_content_length);
+ } else if (url.find(url2_) == 0) {
+ got_resource_load_complete2_.yes();
+ EXPECT_EQ(response_length2_, received_content_length);
+ } else {
+ EXPECT_TRUE(false); // Not reached
+ }
+ }
+
+ bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ bool user_gesture,
+ bool is_redirect) override {
+ std::string url = request->GetURL();
+
+ // Check if the load has already been delayed.
+ bool delay_loaded = (url.find("delayed=true") != std::string::npos);
+
+ if (url.find(url1_) == 0) {
+ got_before_browse1_.yes();
+ EXPECT_FALSE(delay_loaded);
+ } else if (url.find(url2_) == 0) {
+ got_before_browse2_.yes();
+ if (delay_loaded) {
+ got_before_browse2_delayed_.yes();
+ } else if (test_type_ == NNTT_DELAYED_RENDERER ||
+ test_type_ == NNTT_DELAYED_BROWSER) {
+ got_before_browse2_will_delay_.yes();
+
+ // Navigating cross-origin from the browser process will cause a new
+ // render process to be created. We therefore need some information in
+ // the request itself to tell us that the navigation has already been
+ // delayed.
+ // Navigating cross-origin from the renderer process will cause the
+ // process to be terminated with "bad IPC message" reason
+ // INVALID_INITIATOR_ORIGIN (213).
+ url += "&delayed=true";
+
+ if (test_type_ == NNTT_DELAYED_RENDERER) {
+ // Load the URL from the render process.
+ CefRefPtr<CefProcessMessage> message =
+ CefProcessMessage::Create(kNetNotifyMsg);
+ CefRefPtr<CefListValue> args = message->GetArgumentList();
+ args->SetInt(0, test_type_);
+ args->SetString(1, url);
+ frame->SendProcessMessage(PID_RENDERER, message);
+ } else {
+ // Load the URL from the browser process.
+ frame->LoadURL(url);
+ }
+
+ // Cancel the load.
+ return true;
+ }
+ } else {
+ EXPECT_TRUE(false); // Not reached
+ }
+
+ // Allow the load to continue.
+ return false;
+ }
+
+ void OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int httpStatusCode) override {
+ const std::string& url = frame->GetURL();
+ if (url.find(url1_) == 0) {
+ got_load_end1_.yes();
+ SetupCompleteIfDone();
+ } else if (url.find(url2_) == 0) {
+ got_load_end2_.yes();
+ FinishTestIfDone();
+ } else {
+ EXPECT_TRUE(false); // Not reached
+ }
+ }
+
+ bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefProcessId source_process,
+ CefRefPtr<CefProcessMessage> message) override {
+ if (message->GetName().ToString() == kNetNotifyMsg) {
+ CefRefPtr<CefListValue> args = message->GetArgumentList();
+ EXPECT_TRUE(args.get());
+
+ std::string url = args->GetString(0);
+ if (url.find(url1_) == 0) {
+ got_process_message1_.yes();
+ SetupCompleteIfDone();
+ } else if (url.find(url2_) == 0) {
+ got_process_message2_.yes();
+ FinishTestIfDone();
+ } else {
+ EXPECT_TRUE(false); // Not reached
+ }
+
+ return true;
+ }
+
+ // Message not handled.
+ return false;
+ }
+
+ void OnRenderProcessTerminated(CefRefPtr<CefBrowser> browser,
+ TerminationStatus status) override {
+ got_process_terminated_ct_++;
+
+ // Termination is expected for cross-origin requests initiated from the
+ // renderer process.
+ if (!(test_type_ == NNTT_DELAYED_RENDERER && !same_origin_)) {
+ TestHandler::OnRenderProcessTerminated(browser, status);
+ }
+
+ FinishTest();
+ }
+
+ protected:
+ void SetupCompleteIfDone() {
+ if (got_load_end1_ && got_process_message1_) {
+ SetupComplete();
+ }
+ }
+
+ void FinishTestIfDone() {
+ if (got_load_end2_ && got_process_message2_) {
+ FinishTest();
+ }
+ }
+
+ void FinishTest() {
+ // Verify that cookies were set correctly.
+ class TestVisitor : public CefCookieVisitor {
+ public:
+ explicit TestVisitor(NetNotifyTestHandler* handler) : handler_(handler) {}
+ ~TestVisitor() override {
+ // Destroy the test.
+ CefPostTask(TID_UI, base::BindOnce(&NetNotifyTestHandler::DestroyTest,
+ handler_));
+ }
+
+ bool Visit(const CefCookie& cookie,
+ int count,
+ int total,
+ bool& deleteCookie) override {
+ const std::string& name = CefString(&cookie.name);
+ const std::string& value = CefString(&cookie.value);
+ if (name == "name1" && value == "value1") {
+ handler_->got_cookie1_.yes();
+ deleteCookie = true;
+ } else if (name == "name2" && value == "value2") {
+ handler_->got_cookie2_.yes();
+ deleteCookie = true;
+ }
+ return true;
+ }
+
+ private:
+ NetNotifyTestHandler* handler_;
+ IMPLEMENT_REFCOUNTING(TestVisitor);
+ };
+
+ cookie_manager_->VisitAllCookies(new TestVisitor(this));
+ }
+
+ void DestroyTest() override {
+ int browser_id = GetBrowser()->GetIdentifier();
+
+ // Verify test expectations.
+ EXPECT_TRUE(got_before_browse1_) << " browser " << browser_id;
+ EXPECT_TRUE(got_load_end1_) << " browser " << browser_id;
+ EXPECT_TRUE(got_before_resource_load1_) << " browser " << browser_id;
+ EXPECT_TRUE(got_get_resource_handler1_) << " browser " << browser_id;
+ EXPECT_TRUE(got_resource_load_complete1_) << " browser " << browser_id;
+ EXPECT_TRUE(got_cookie1_) << " browser " << browser_id;
+ EXPECT_TRUE(got_process_message1_) << " browser " << browser_id;
+ EXPECT_TRUE(got_before_browse2_) << " browser " << browser_id;
+
+ if (test_type_ == NNTT_DELAYED_RENDERER && !same_origin_) {
+ EXPECT_EQ(1, got_process_terminated_ct_) << " browser " << browser_id;
+ EXPECT_FALSE(got_load_end2_) << " browser " << browser_id;
+ EXPECT_FALSE(got_before_resource_load2_) << " browser " << browser_id;
+ EXPECT_FALSE(got_get_resource_handler2_) << " browser " << browser_id;
+ EXPECT_FALSE(got_resource_load_complete2_) << " browser " << browser_id;
+ EXPECT_FALSE(got_cookie2_) << " browser " << browser_id;
+ EXPECT_FALSE(got_process_message2_) << " browser " << browser_id;
+ } else {
+ EXPECT_EQ(0, got_process_terminated_ct_) << " browser " << browser_id;
+ EXPECT_TRUE(got_load_end2_) << " browser " << browser_id;
+ EXPECT_TRUE(got_before_resource_load2_) << " browser " << browser_id;
+ EXPECT_TRUE(got_get_resource_handler2_) << " browser " << browser_id;
+ EXPECT_TRUE(got_resource_load_complete2_) << " browser " << browser_id;
+ EXPECT_TRUE(got_cookie2_) << " browser " << browser_id;
+ EXPECT_TRUE(got_process_message2_) << " browser " << browser_id;
+ }
+
+ if (test_type_ == NNTT_DELAYED_RENDERER ||
+ test_type_ == NNTT_DELAYED_BROWSER) {
+ EXPECT_TRUE(got_before_browse2_will_delay_) << " browser " << browser_id;
+ if (test_type_ == NNTT_DELAYED_RENDERER && !same_origin_) {
+ EXPECT_FALSE(got_before_browse2_delayed_) << " browser " << browser_id;
+ } else {
+ EXPECT_TRUE(got_before_browse2_delayed_) << " browser " << browser_id;
+ }
+ } else {
+ EXPECT_FALSE(got_before_browse2_will_delay_) << " browser " << browser_id;
+ EXPECT_FALSE(got_before_browse2_delayed_) << " browser " << browser_id;
+ }
+
+ cookie_manager_ = nullptr;
+
+ TestHandler::DestroyTest();
+ }
+
+ NetNotifyTestType test_type_;
+ bool same_origin_;
+ std::string url1_;
+ std::string url2_;
+
+ CefRefPtr<CefCookieManager> cookie_manager_;
+
+ TrackCallback got_before_browse1_;
+ TrackCallback got_load_end1_;
+ TrackCallback got_before_resource_load1_;
+ TrackCallback got_get_resource_handler1_;
+ TrackCallback got_resource_load_complete1_;
+ TrackCallback got_cookie1_;
+ TrackCallback got_process_message1_;
+ TrackCallback got_before_browse2_;
+ TrackCallback got_load_end2_;
+ TrackCallback got_before_resource_load2_;
+ TrackCallback got_get_resource_handler2_;
+ TrackCallback got_resource_load_complete2_;
+ TrackCallback got_cookie2_;
+ TrackCallback got_process_message2_;
+ TrackCallback got_before_browse2_will_delay_;
+ TrackCallback got_before_browse2_delayed_;
+ int got_process_terminated_ct_ = 0;
+
+ int64 response_length1_;
+ int64 response_length2_;
+
+ IMPLEMENT_REFCOUNTING(NetNotifyTestHandler);
+};
+
+// Renderer side.
+class NetNotifyRendererTest : public ClientAppRenderer::Delegate,
+ public CefLoadHandler {
+ public:
+ NetNotifyRendererTest() : run_test_(false) {}
+
+ void OnBrowserCreated(CefRefPtr<ClientAppRenderer> app,
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefDictionaryValue> extra_info) override {
+ run_test_ = extra_info && extra_info->HasKey(kNetNotifyTestCmdKey);
+ }
+
+ CefRefPtr<CefLoadHandler> GetLoadHandler(
+ CefRefPtr<ClientAppRenderer> app) override {
+ if (run_test_) {
+ return this;
+ }
+ return nullptr;
+ }
+
+ void OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int httpStatusCode) override {
+ if (!run_test_) {
+ return;
+ }
+
+ const std::string& url = frame->GetURL();
+
+ // Continue in the browser process.
+ CefRefPtr<CefProcessMessage> message =
+ CefProcessMessage::Create(kNetNotifyMsg);
+ CefRefPtr<CefListValue> args = message->GetArgumentList();
+ args->SetString(0, url);
+ frame->SendProcessMessage(PID_BROWSER, message);
+ }
+
+ bool OnProcessMessageReceived(CefRefPtr<ClientAppRenderer> app,
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefProcessId source_process,
+ CefRefPtr<CefProcessMessage> message) override {
+ if (message->GetName().ToString() == kNetNotifyMsg) {
+ CefRefPtr<CefListValue> args = message->GetArgumentList();
+ EXPECT_TRUE(args.get());
+
+ NetNotifyTestType test_type =
+ static_cast<NetNotifyTestType>(args->GetInt(0));
+ EXPECT_EQ(test_type, NNTT_DELAYED_RENDERER);
+
+ const std::string& url = args->GetString(1);
+
+ // Load the URL from the render process.
+ frame->LoadURL(url);
+ return true;
+ }
+
+ // Message not handled.
+ return false;
+ }
+
+ private:
+ bool run_test_;
+
+ IMPLEMENT_REFCOUNTING(NetNotifyRendererTest);
+};
+
+void RunNetNotifyTest(NetNotifyTestType test_type,
+ bool same_origin,
+ size_t count = 3U) {
+ TestHandler::CompletionState completion_state(static_cast<int>(count));
+ TestHandler::Collection collection(&completion_state);
+
+ std::vector<CefRefPtr<NetNotifyTestHandler>> handlers;
+ for (size_t i = 0U; i < count; ++i) {
+ CefRefPtr<NetNotifyTestHandler> handler =
+ new NetNotifyTestHandler(&completion_state, test_type, same_origin);
+ collection.AddTestHandler(handler.get());
+ handlers.push_back(handler);
+ }
+
+ collection.ExecuteTests();
+
+ while (!handlers.empty()) {
+ auto handler = handlers.front();
+ handlers.erase(handlers.begin());
+ ReleaseAndWaitForDestructor(handler);
+ }
+}
+
+} // namespace
+
+// Verify network notifications for multiple browsers existing simultaniously.
+// URL loading is from the same origin and is not delayed.
+TEST(RequestHandlerTest, NotificationsSameOriginDirect) {
+ RunNetNotifyTest(NNTT_NORMAL, true);
+}
+
+// Verify network notifications for multiple browsers existing simultaniously.
+// URL loading is from the same origin and is continued asynchronously from the
+// render process.
+TEST(RequestHandlerTest, NotificationsSameOriginDelayedRenderer) {
+ RunNetNotifyTest(NNTT_DELAYED_RENDERER, true);
+}
+
+// Verify network notifications for multiple browsers existing simultaniously.
+// URL loading is from the same origin and is continued asynchronously from the
+// browser process.
+TEST(RequestHandlerTest, NotificationsSameOriginDelayedBrowser) {
+ RunNetNotifyTest(NNTT_DELAYED_BROWSER, true);
+}
+
+// Verify network notifications for multiple browsers existing simultaniously.
+// URL loading is from a different origin and is not delayed.
+TEST(RequestHandlerTest, NotificationsCrossOriginDirect) {
+ RunNetNotifyTest(NNTT_NORMAL, false);
+}
+
+// Verify network notifications for multiple browsers existing simultaniously.
+// URL loading is from a different origin and is continued asynchronously from
+// the render process.
+TEST(RequestHandlerTest, NotificationsCrossOriginDelayedRenderer) {
+ RunNetNotifyTest(NNTT_DELAYED_RENDERER, false);
+}
+
+// Verify network notifications for multiple browsers existing simultaniously.
+// URL loading is from a different origin and is continued asynchronously from
+// the browser process.
+TEST(RequestHandlerTest, NotificationsCrossOriginDelayedBrowser) {
+ RunNetNotifyTest(NNTT_DELAYED_BROWSER, false);
+}
+
+// Entry point for creating request handler renderer test objects.
+// Called from client_app_delegates.cc.
+void CreateRequestHandlerRendererTests(
+ ClientAppRenderer::DelegateSet& delegates) {
+ delegates.insert(new NetNotifyRendererTest);
+}
diff --git a/tests/ceftests/request_unittest.cc b/tests/ceftests/request_unittest.cc
new file mode 100644
index 00000000..46d463dd
--- /dev/null
+++ b/tests/ceftests/request_unittest.cc
@@ -0,0 +1,632 @@
+// Copyright (c) 2011 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include <map>
+
+#include "include/base/cef_callback.h"
+#include "include/cef_request.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "tests/ceftests/test_handler.h"
+#include "tests/ceftests/test_util.h"
+#include "tests/gtest/include/gtest/gtest.h"
+#include "tests/shared/renderer/client_app_renderer.h"
+
+using client::ClientAppRenderer;
+
+// Verify Set/Get methods for CefRequest, CefPostData and CefPostDataElement.
+TEST(RequestTest, SetGet) {
+ // CefRequest CreateRequest
+ CefRefPtr<CefRequest> request(CefRequest::Create());
+ EXPECT_TRUE(request.get() != nullptr);
+ EXPECT_EQ(0U, request->GetIdentifier());
+
+ CefString url = "http://tests.com/run.html";
+ CefString method = "POST";
+ CefRequest::HeaderMap setHeaders, getHeaders;
+ setHeaders.insert(std::make_pair("HeaderA", "ValueA"));
+ setHeaders.insert(std::make_pair("HeaderB", "ValueB"));
+
+ // CefPostData CreatePostData
+ CefRefPtr<CefPostData> postData(CefPostData::Create());
+ EXPECT_TRUE(postData.get() != nullptr);
+
+ // CefPostDataElement CreatePostDataElement
+ CefRefPtr<CefPostDataElement> element1(CefPostDataElement::Create());
+ EXPECT_TRUE(element1.get() != nullptr);
+ CefRefPtr<CefPostDataElement> element2(CefPostDataElement::Create());
+ EXPECT_TRUE(element2.get() != nullptr);
+
+ // CefPostDataElement SetToFile
+ CefString file = "c:\\path\\to\\file.ext";
+ element1->SetToFile(file);
+ EXPECT_EQ(PDE_TYPE_FILE, element1->GetType());
+ EXPECT_EQ(file, element1->GetFile());
+
+ // CefPostDataElement SetToBytes
+ char bytes[] = "Test Bytes";
+ element2->SetToBytes(sizeof(bytes), bytes);
+ EXPECT_EQ(PDE_TYPE_BYTES, element2->GetType());
+ EXPECT_EQ(sizeof(bytes), element2->GetBytesCount());
+ char bytesOut[sizeof(bytes)];
+ element2->GetBytes(sizeof(bytes), bytesOut);
+ EXPECT_TRUE(!memcmp(bytes, bytesOut, sizeof(bytes)));
+
+ // CefPostData AddElement
+ postData->AddElement(element1);
+ postData->AddElement(element2);
+ EXPECT_EQ((size_t)2, postData->GetElementCount());
+
+ // CefPostData RemoveElement
+ postData->RemoveElement(element1);
+ EXPECT_EQ((size_t)1, postData->GetElementCount());
+
+ // CefPostData RemoveElements
+ postData->RemoveElements();
+ EXPECT_EQ((size_t)0, postData->GetElementCount());
+
+ postData->AddElement(element1);
+ postData->AddElement(element2);
+ EXPECT_EQ((size_t)2, postData->GetElementCount());
+ CefPostData::ElementVector elements;
+ postData->GetElements(elements);
+ CefPostData::ElementVector::const_iterator it = elements.begin();
+ for (size_t i = 0; it != elements.end(); ++it, ++i) {
+ if (i == 0) {
+ TestPostDataElementEqual(element1, (*it).get());
+ } else if (i == 1) {
+ TestPostDataElementEqual(element2, (*it).get());
+ }
+ }
+
+ // CefRequest SetURL
+ request->SetURL(url);
+ EXPECT_EQ(url, request->GetURL());
+
+ // CefRequest SetMethod
+ request->SetMethod(method);
+ EXPECT_EQ(method, request->GetMethod());
+
+ // CefRequest SetReferrer
+ CefString referrer = "http://tests.com/referrer.html";
+ CefRequest::ReferrerPolicy policy = REFERRER_POLICY_ORIGIN;
+ request->SetReferrer(referrer, policy);
+ EXPECT_STREQ("http://tests.com/",
+ request->GetReferrerURL().ToString().c_str());
+ EXPECT_EQ(policy, request->GetReferrerPolicy());
+
+ // CefRequest SetHeaderMap
+ request->SetHeaderMap(setHeaders);
+ request->GetHeaderMap(getHeaders);
+ TestMapEqual(setHeaders, getHeaders, false);
+ getHeaders.clear();
+
+ // CefRequest SetPostData
+ request->SetPostData(postData);
+ TestPostDataEqual(postData, request->GetPostData());
+
+ EXPECT_EQ(0U, request->GetIdentifier());
+
+ request = CefRequest::Create();
+ EXPECT_TRUE(request.get() != nullptr);
+ EXPECT_EQ(0U, request->GetIdentifier());
+
+ // CefRequest Set
+ request->Set(url, method, postData, setHeaders);
+ EXPECT_EQ(0U, request->GetIdentifier());
+ EXPECT_EQ(url, request->GetURL());
+ EXPECT_EQ(method, request->GetMethod());
+ request->GetHeaderMap(getHeaders);
+ TestMapEqual(setHeaders, getHeaders, false);
+ getHeaders.clear();
+ TestPostDataEqual(postData, request->GetPostData());
+}
+
+TEST(RequestTest, SetGetHeaderByName) {
+ CefRefPtr<CefRequest> request(CefRequest::Create());
+ EXPECT_TRUE(request.get() != nullptr);
+
+ CefRequest::HeaderMap headers, expectedHeaders;
+
+ request->SetHeaderByName("HeaderA", "ValueA", false);
+ request->SetHeaderByName("HeaderB", "ValueB", false);
+
+ expectedHeaders.insert(std::make_pair("HeaderA", "ValueA"));
+ expectedHeaders.insert(std::make_pair("HeaderB", "ValueB"));
+
+ // Case insensitive retrieval.
+ EXPECT_STREQ("ValueA",
+ request->GetHeaderByName("headera").ToString().c_str());
+ EXPECT_STREQ("ValueB",
+ request->GetHeaderByName("headerb").ToString().c_str());
+ EXPECT_STREQ("", request->GetHeaderByName("noexist").ToString().c_str());
+
+ request->GetHeaderMap(headers);
+ TestMapEqual(expectedHeaders, headers, false);
+
+ // Replace an existing value.
+ request->SetHeaderByName("HeaderA", "ValueANew", true);
+
+ expectedHeaders.clear();
+ expectedHeaders.insert(std::make_pair("HeaderA", "ValueANew"));
+ expectedHeaders.insert(std::make_pair("HeaderB", "ValueB"));
+
+ // Case insensitive retrieval.
+ EXPECT_STREQ("ValueANew",
+ request->GetHeaderByName("headerA").ToString().c_str());
+
+ request->GetHeaderMap(headers);
+ TestMapEqual(expectedHeaders, headers, false);
+
+ // Header with multiple values.
+ expectedHeaders.clear();
+ expectedHeaders.insert(std::make_pair("HeaderA", "ValueA1"));
+ expectedHeaders.insert(std::make_pair("HeaderA", "ValueA2"));
+ expectedHeaders.insert(std::make_pair("HeaderB", "ValueB"));
+ request->SetHeaderMap(expectedHeaders);
+
+ // When there are multiple values only the first is returned.
+ EXPECT_STREQ("ValueA1",
+ request->GetHeaderByName("headera").ToString().c_str());
+
+ // Don't overwrite the value.
+ request->SetHeaderByName("HeaderA", "ValueANew", false);
+
+ request->GetHeaderMap(headers);
+ TestMapEqual(expectedHeaders, headers, false);
+
+ // Overwrite the value (remove the duplicates).
+ request->SetHeaderByName("HeaderA", "ValueANew", true);
+
+ expectedHeaders.clear();
+ expectedHeaders.insert(std::make_pair("HeaderA", "ValueANew"));
+ expectedHeaders.insert(std::make_pair("HeaderB", "ValueB"));
+
+ request->GetHeaderMap(headers);
+ TestMapEqual(expectedHeaders, headers, false);
+}
+
+namespace {
+
+const char kTestUrl[] = "http://tests.com/run.html";
+
+void CreateRequest(CefRefPtr<CefRequest>& request) {
+ request = CefRequest::Create();
+ EXPECT_TRUE(request.get() != nullptr);
+
+ request->SetURL(kTestUrl);
+ request->SetMethod("POST");
+
+ request->SetReferrer("http://tests.com/main.html", REFERRER_POLICY_DEFAULT);
+
+ CefRequest::HeaderMap headers;
+ headers.insert(std::make_pair("HeaderA", "ValueA"));
+ headers.insert(std::make_pair("HeaderB", "ValueB"));
+ request->SetHeaderMap(headers);
+
+ CefRefPtr<CefPostData> postData(CefPostData::Create());
+ EXPECT_TRUE(postData.get() != nullptr);
+
+ CefRefPtr<CefPostDataElement> element1(CefPostDataElement::Create());
+ EXPECT_TRUE(element1.get() != nullptr);
+ char bytes[] = "Test Bytes";
+ element1->SetToBytes(sizeof(bytes), bytes);
+ postData->AddElement(element1);
+
+ request->SetPostData(postData);
+}
+
+class RequestSendRecvTestHandler : public TestHandler {
+ public:
+ RequestSendRecvTestHandler() : response_length_(0), request_id_(0U) {}
+
+ void RunTest() override {
+ // Create the test request.
+ CreateRequest(request_);
+
+ const std::string& resource = "<html><body>SendRecv Test</body></html>";
+ response_length_ = static_cast<int64>(resource.size());
+ AddResource(kTestUrl, resource, "text/html");
+
+ // Create the browser.
+ CreateBrowser("about:blank");
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout();
+ }
+
+ void OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
+ TestHandler::OnAfterCreated(browser);
+
+ // Load the test request.
+ browser->GetMainFrame()->LoadRequest(request_);
+ }
+
+ cef_return_value_t OnBeforeResourceLoad(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefCallback> callback) override {
+ EXPECT_IO_THREAD();
+
+ request_id_ = request->GetIdentifier();
+ DCHECK_GT(request_id_, 0U);
+
+ TestRequest(request);
+ EXPECT_FALSE(request->IsReadOnly());
+
+ got_before_resource_load_.yes();
+
+ return RV_CONTINUE;
+ }
+
+ CefRefPtr<CefResourceHandler> GetResourceHandler(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request) override {
+ EXPECT_IO_THREAD();
+
+ TestRequest(request);
+ EXPECT_TRUE(request->IsReadOnly());
+
+ got_resource_handler_.yes();
+
+ return TestHandler::GetResourceHandler(browser, frame, request);
+ }
+
+ bool OnResourceResponse(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response) override {
+ EXPECT_IO_THREAD();
+
+ TestRequest(request);
+ EXPECT_FALSE(request->IsReadOnly());
+ TestResponse(response);
+ EXPECT_TRUE(response->IsReadOnly());
+
+ got_resource_response_.yes();
+
+ return false;
+ }
+
+ CefRefPtr<CefResponseFilter> GetResourceResponseFilter(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response) override {
+ EXPECT_IO_THREAD();
+
+ TestRequest(request);
+ EXPECT_TRUE(request->IsReadOnly());
+ TestResponse(response);
+ EXPECT_TRUE(response->IsReadOnly());
+
+ got_resource_response_filter_.yes();
+ return nullptr;
+ }
+
+ void OnResourceLoadComplete(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response,
+ URLRequestStatus status,
+ int64 received_content_length) override {
+ EXPECT_IO_THREAD();
+
+ if (IsChromeRuntimeEnabled() && request->GetResourceType() == RT_FAVICON) {
+ // Ignore favicon requests.
+ return;
+ }
+
+ TestRequest(request);
+ EXPECT_TRUE(request->IsReadOnly());
+ TestResponse(response);
+ EXPECT_TRUE(response->IsReadOnly());
+ EXPECT_EQ(UR_SUCCESS, status);
+ EXPECT_EQ(response_length_, received_content_length);
+
+ got_resource_load_complete_.yes();
+
+ DestroyTest();
+ }
+
+ private:
+ void TestRequest(CefRefPtr<CefRequest> request) {
+ TestRequestEqual(request_, request, true);
+ EXPECT_EQ(request_id_, request->GetIdentifier());
+ EXPECT_EQ(RT_MAIN_FRAME, request->GetResourceType());
+ EXPECT_EQ(TT_FORM_SUBMIT, request->GetTransitionType());
+ }
+
+ void TestResponse(CefRefPtr<CefResponse> response) {
+ EXPECT_EQ(200, response->GetStatus());
+ EXPECT_STREQ("OK", response->GetStatusText().ToString().c_str());
+ EXPECT_STREQ("text/html", response->GetMimeType().ToString().c_str());
+ }
+
+ void DestroyTest() override {
+ EXPECT_TRUE(got_before_resource_load_);
+ EXPECT_TRUE(got_resource_handler_);
+ EXPECT_TRUE(got_resource_response_);
+ EXPECT_TRUE(got_resource_response_filter_);
+ EXPECT_TRUE(got_resource_load_complete_);
+
+ TestHandler::DestroyTest();
+ }
+
+ CefRefPtr<CefRequest> request_;
+ int64 response_length_;
+ uint64 request_id_;
+
+ TrackCallback got_before_resource_load_;
+ TrackCallback got_resource_handler_;
+ TrackCallback got_resource_response_;
+ TrackCallback got_resource_response_filter_;
+ TrackCallback got_resource_load_complete_;
+
+ IMPLEMENT_REFCOUNTING(RequestSendRecvTestHandler);
+};
+
+} // namespace
+
+// Verify send and recieve
+TEST(RequestTest, SendRecv) {
+ CefRefPtr<RequestSendRecvTestHandler> handler =
+ new RequestSendRecvTestHandler();
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+namespace {
+
+const char kTypeTestOrigin[] = "http://tests-requesttt.com/";
+const cef_transition_type_t kTransitionExplicitLoad =
+ static_cast<cef_transition_type_t>(TT_EXPLICIT | TT_DIRECT_LOAD_FLAG);
+
+static struct TypeExpected {
+ const char* file;
+ bool navigation; // True if this expectation represents a navigation.
+ cef_transition_type_t transition_type;
+ cef_resource_type_t resource_type;
+ int expected_count;
+} g_type_expected[] = {
+ // Initial main frame load due to browser creation.
+ {"main.html", true, kTransitionExplicitLoad, RT_MAIN_FRAME, 1},
+
+ // Sub frame load.
+ {"sub.html", true, TT_AUTO_SUBFRAME, RT_SUB_FRAME, 1},
+
+ // Stylesheet load.
+ {"style.css", false, TT_LINK, RT_STYLESHEET, 1},
+
+ // Script load.
+ {"script.js", false, TT_LINK, RT_SCRIPT, 1},
+
+ // Image load.
+ {"image.png", false, TT_LINK, RT_IMAGE, 1},
+
+ // Font load.
+ {"font.ttf", false, TT_LINK, RT_FONT_RESOURCE, 1},
+
+ // XHR load.
+ {"xhr.html", false, TT_LINK, RT_XHR, 1},
+};
+
+class TypeExpectations {
+ public:
+ explicit TypeExpectations(bool navigation) : navigation_(navigation) {
+ // Build the map of relevant requests.
+ for (int i = 0;
+ i < static_cast<int>(sizeof(g_type_expected) / sizeof(TypeExpected));
+ ++i) {
+ if (navigation_ && g_type_expected[i].navigation != navigation_) {
+ continue;
+ }
+
+ request_count_.insert(std::make_pair(i, 0));
+ }
+ }
+
+ // Notify that a request has been received. Returns true if the request is
+ // something we care about.
+ bool GotRequest(CefRefPtr<CefRequest> request) {
+ const std::string& url = request->GetURL();
+ if (url.find(kTypeTestOrigin) != 0) {
+ return false;
+ }
+
+ const std::string& file = url.substr(sizeof(kTypeTestOrigin) - 1);
+ cef_transition_type_t transition_type = request->GetTransitionType();
+ cef_resource_type_t resource_type = request->GetResourceType();
+
+ const int index = GetExpectedIndex(file, transition_type, resource_type);
+ EXPECT_GE(index, 0) << "File: " << file.c_str()
+ << "; Navigation: " << navigation_
+ << "; Transition Type: " << transition_type
+ << "; Resource Type: " << resource_type;
+
+ RequestCount::iterator it = request_count_.find(index);
+ EXPECT_TRUE(it != request_count_.end());
+
+ const int actual_count = ++it->second;
+ const int expected_count = g_type_expected[index].expected_count;
+ EXPECT_LE(actual_count, expected_count)
+ << "File: " << file.c_str() << "; Navigation: " << navigation_
+ << "; Transition Type: " << transition_type
+ << "; Resource Type: " << resource_type;
+
+ return true;
+ }
+
+ // Test if all expectations have been met.
+ bool IsDone(bool assert) {
+ for (int i = 0;
+ i < static_cast<int>(sizeof(g_type_expected) / sizeof(TypeExpected));
+ ++i) {
+ if (navigation_ && g_type_expected[i].navigation != navigation_) {
+ continue;
+ }
+
+ RequestCount::const_iterator it = request_count_.find(i);
+ EXPECT_TRUE(it != request_count_.end());
+ if (it->second != g_type_expected[i].expected_count) {
+ if (assert) {
+ EXPECT_EQ(g_type_expected[i].expected_count, it->second)
+ << "File: " << g_type_expected[i].file
+ << "; Navigation: " << navigation_
+ << "; Transition Type: " << g_type_expected[i].transition_type
+ << "; Resource Type: " << g_type_expected[i].resource_type;
+ }
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private:
+ // Returns the index for the specified navigation.
+ int GetExpectedIndex(const std::string& file,
+ cef_transition_type_t transition_type,
+ cef_resource_type_t resource_type) {
+ for (int i = 0;
+ i < static_cast<int>(sizeof(g_type_expected) / sizeof(TypeExpected));
+ ++i) {
+ if (g_type_expected[i].file == file &&
+ (!navigation_ || g_type_expected[i].navigation == navigation_) &&
+ g_type_expected[i].transition_type == transition_type &&
+ g_type_expected[i].resource_type == resource_type) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ bool navigation_;
+
+ // Map of TypeExpected index to actual request count.
+ typedef std::map<int, int> RequestCount;
+ RequestCount request_count_;
+};
+
+// Browser side.
+class TypeTestHandler : public TestHandler {
+ public:
+ TypeTestHandler()
+ : browse_expectations_(true),
+ load_expectations_(false),
+ get_expectations_(false),
+ completed_browser_side_(false),
+ destroyed_(false) {}
+
+ void RunTest() override {
+ AddResource(std::string(kTypeTestOrigin) + "main.html",
+ "<html>"
+ "<head>"
+ "<link rel=\"stylesheet\" href=\"style.css\" type=\"text/css\">"
+ "<script type=\"text/javascript\" src=\"script.js\"></script>"
+ "</head>"
+ "<body><p>Main</p>"
+ "<script>xhr = new XMLHttpRequest();"
+ "xhr.open('GET', 'xhr.html', false);"
+ "xhr.send();</script>"
+ "<iframe src=\"sub.html\"></iframe>"
+ "<img src=\"image.png\">"
+ "</body></html>",
+ "text/html");
+ AddResource(std::string(kTypeTestOrigin) + "sub.html", "<html>Sub</html>",
+ "text/html");
+ AddResource(std::string(kTypeTestOrigin) + "style.css",
+ "@font-face {"
+ " font-family: custom_font;"
+ " src: url('font.ttf');"
+ "}"
+ "p {"
+ " font-family: custom_font;"
+ "}",
+ "text/css");
+ AddResource(std::string(kTypeTestOrigin) + "script.js", "<!-- -->",
+ "text/javascript");
+ AddResource(std::string(kTypeTestOrigin) + "image.png", "<!-- -->",
+ "image/png");
+ AddResource(std::string(kTypeTestOrigin) + "font.ttf", "<!-- -->",
+ "font/ttf");
+ AddResource(std::string(kTypeTestOrigin) + "xhr.html", "<html>XHR</html>",
+ "text/html");
+ AddResource(std::string(kTypeTestOrigin) + "fetch.html",
+ "<html>Fetch</html>", "text/html");
+
+ CreateBrowser(std::string(kTypeTestOrigin) + "main.html");
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout();
+ }
+
+ bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ bool user_gesture,
+ bool is_redirect) override {
+ browse_expectations_.GotRequest(request);
+
+ return false;
+ }
+
+ cef_return_value_t OnBeforeResourceLoad(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefCallback> callback) override {
+ load_expectations_.GotRequest(request);
+
+ return RV_CONTINUE;
+ }
+
+ CefRefPtr<CefResourceHandler> GetResourceHandler(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request) override {
+ if (get_expectations_.GotRequest(request) &&
+ get_expectations_.IsDone(false)) {
+ completed_browser_side_ = true;
+ // Destroy the test on the UI thread.
+ CefPostTask(TID_UI, base::BindOnce(&TypeTestHandler::DestroyTest, this));
+ }
+
+ return TestHandler::GetResourceHandler(browser, frame, request);
+ }
+
+ private:
+ void DestroyTest() override {
+ if (destroyed_) {
+ return;
+ }
+ destroyed_ = true;
+
+ // Verify test expectations.
+ EXPECT_TRUE(completed_browser_side_);
+ EXPECT_TRUE(browse_expectations_.IsDone(true));
+ EXPECT_TRUE(load_expectations_.IsDone(true));
+ EXPECT_TRUE(get_expectations_.IsDone(true));
+
+ TestHandler::DestroyTest();
+ }
+
+ TypeExpectations browse_expectations_;
+ TypeExpectations load_expectations_;
+ TypeExpectations get_expectations_;
+
+ bool completed_browser_side_;
+ bool destroyed_;
+
+ IMPLEMENT_REFCOUNTING(TypeTestHandler);
+};
+
+} // namespace
+
+// Verify the order of navigation-related callbacks.
+TEST(RequestTest, ResourceAndTransitionType) {
+ CefRefPtr<TypeTestHandler> handler = new TypeTestHandler();
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
diff --git a/tests/ceftests/resource.h b/tests/ceftests/resource.h
new file mode 100644
index 00000000..f87af0ff
--- /dev/null
+++ b/tests/ceftests/resource.h
@@ -0,0 +1,26 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by cefclient.rc
+//
+#define BINARY 256
+#define IDS_OSRTEST_HTML 1000
+#define IDS_PDF_HTML 1001
+#define IDS_PDF_PDF 1002
+#define IDS_WINDOW_ICON_1X_PNG 1003
+#define IDS_WINDOW_ICON_2X_PNG 1004
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NO_MFC 1
+#define _APS_NEXT_RESOURCE_VALUE 130
+#define _APS_NEXT_COMMAND_VALUE 32774
+#define _APS_NEXT_CONTROL_VALUE 1000
+#define _APS_NEXT_SYMED_VALUE 111
+#endif
+#endif
diff --git a/tests/ceftests/resource_manager_unittest.cc b/tests/ceftests/resource_manager_unittest.cc
new file mode 100644
index 00000000..df532502
--- /dev/null
+++ b/tests/ceftests/resource_manager_unittest.cc
@@ -0,0 +1,1930 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include <memory>
+#include <vector>
+
+#include "include/base/cef_callback.h"
+#include "include/base/cef_lock.h"
+#include "include/cef_file_util.h"
+#include "include/cef_waitable_event.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "include/wrapper/cef_resource_manager.h"
+#include "include/wrapper/cef_scoped_temp_dir.h"
+#include "include/wrapper/cef_stream_resource_handler.h"
+#include "tests/ceftests/routing_test_handler.h"
+#include "tests/ceftests/test_util.h"
+#include "tests/gtest/include/gtest/gtest.h"
+#include "tests/shared/browser/file_util.h"
+
+namespace {
+
+std::string CreateMessage(const std::string& name, const std::string& value) {
+ return name + ":" + value;
+}
+
+// The returned contents execute a JavaScript callback containing |message|.
+std::string CreateContents(const std::string& message) {
+ return "<html><body>" + message +
+ "<script>"
+ "window.testQuery({request:'" +
+ message +
+ "'});"
+ "</script></html></body>";
+}
+
+void WriteFile(const std::string& path, const std::string& contents) {
+ int contents_size = static_cast<int>(contents.size());
+ int write_ct =
+ client::file_util::WriteFile(path, contents.data(), contents_size);
+ EXPECT_EQ(contents_size, write_ct);
+}
+
+CefRefPtr<CefResourceHandler> CreateContentsResourceHandler(
+ const std::string& message) {
+ const std::string& contents = CreateContents(message);
+ CefRefPtr<CefStreamReader> stream = CefStreamReader::CreateForData(
+ static_cast<void*>(const_cast<char*>(contents.data())),
+ contents.length());
+ return new CefStreamResourceHandler("text/html", stream);
+}
+
+const char kDoneMsg[] = "ResourceManagerTestHandler.Done";
+const char kNotHandled[] = "NotHandled";
+
+// Browser side.
+class ResourceManagerTestHandler : public RoutingTestHandler {
+ public:
+ struct State {
+ State() : manager_(new CefResourceManager()), expected_message_ct_(0) {}
+
+ CefRefPtr<CefResourceManager> manager_;
+
+ // Set of URLs that will be loaded.
+ std::vector<std::string> urls_;
+
+ // Set of messages that were received.
+ std::vector<std::string> messages_;
+
+ // If non-zero the test will not complete until the expected number of
+ // messages have been received.
+ size_t expected_message_ct_;
+ };
+
+ explicit ResourceManagerTestHandler(State* state)
+ : state_(state), current_url_(0) {
+ EXPECT_TRUE(state_);
+ EXPECT_TRUE(state_->manager_.get());
+ EXPECT_TRUE(!state_->urls_.empty());
+ EXPECT_TRUE(state_->messages_.empty());
+ }
+
+ void RunTest() override {
+ // Create the browser.
+ CreateBrowser(GetNextURL());
+
+ SetTestTimeout(5000);
+ }
+
+ cef_return_value_t OnBeforeResourceLoad(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefCallback> callback) override {
+ if (IsChromeRuntimeEnabled() && request->GetResourceType() == RT_FAVICON) {
+ // Ignore favicon requests.
+ return RV_CANCEL;
+ }
+
+ return state_->manager_->OnBeforeResourceLoad(browser, frame, request,
+ callback);
+ }
+
+ CefRefPtr<CefResourceHandler> GetResourceHandler(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request) override {
+ // The ProviderDoNothing test destroys the manager before the handler.
+ if (state_->manager_) {
+ CefRefPtr<CefResourceHandler> handler =
+ state_->manager_->GetResourceHandler(browser, frame, request);
+ if (handler.get()) {
+ return handler;
+ }
+ }
+
+ return CreateContentsResourceHandler(CreateMessage(kDoneMsg, kNotHandled));
+ }
+
+ bool OnQuery(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int64 query_id,
+ const CefString& request,
+ bool persistent,
+ CefRefPtr<Callback> callback) override {
+ state_->messages_.push_back(request);
+ callback->Success("");
+
+ CefPostTask(TID_UI, base::BindOnce(&ResourceManagerTestHandler::Continue,
+ this, browser));
+
+ return true;
+ }
+
+ // Wait a bit before destroying the test. Used with ProviderDoNothing.
+ void DelayedDestroyTest() {
+ CefPostDelayedTask(
+ TID_UI, base::BindOnce(&ResourceManagerTestHandler::DestroyTest, this),
+ 100);
+ }
+
+ private:
+ void Continue(CefRefPtr<CefBrowser> browser) {
+ if (state_->expected_message_ct_ == 0) {
+ // Load each URL sequentially.
+ const std::string& next_url = GetNextURL();
+ if (next_url.empty()) {
+ DestroyTest();
+ } else {
+ browser->GetMainFrame()->LoadURL(next_url);
+ }
+ } else if (state_->messages_.size() == state_->expected_message_ct_) {
+ DestroyTest();
+ }
+ }
+
+ std::string GetNextURL() {
+ if (current_url_ >= state_->urls_.size()) {
+ return std::string();
+ }
+ return state_->urls_[current_url_++];
+ }
+
+ State* state_;
+ size_t current_url_;
+
+ IMPLEMENT_REFCOUNTING(ResourceManagerTestHandler);
+};
+
+} // namespace
+
+// Test with no providers.
+TEST(ResourceManagerTest, NoProviders) {
+ const char kUrl[] = "http://test.com/ResourceManagerTest";
+
+ ResourceManagerTestHandler::State state;
+ state.urls_.push_back(kUrl);
+
+ CefRefPtr<ResourceManagerTestHandler> handler =
+ new ResourceManagerTestHandler(&state);
+ handler->ExecuteTest();
+
+ ReleaseAndWaitForDestructor(handler);
+
+ state.manager_ = nullptr;
+
+ // Should get the message returned from GetResourceHandler when the request is
+ // not handled.
+ EXPECT_EQ(state.messages_.size(), 1U);
+ EXPECT_EQ(CreateMessage(kDoneMsg, kNotHandled), state.messages_[0]);
+}
+
+namespace {
+
+// Content provider that tracks execution state.
+class TestProvider : public CefResourceManager::Provider {
+ public:
+ struct State {
+ TrackCallback got_on_request_;
+ TrackCallback got_on_request_canceled_;
+ TrackCallback got_destruct_;
+ base::OnceClosure destruct_callback_;
+ std::string request_url_;
+ };
+
+ explicit TestProvider(State* state) : state_(state) { EXPECT_TRUE(state_); }
+
+ ~TestProvider() {
+ CEF_REQUIRE_IO_THREAD();
+ state_->got_destruct_.yes();
+ if (!state_->destruct_callback_.is_null()) {
+ std::move(state_->destruct_callback_).Run();
+ }
+ }
+
+ bool OnRequest(scoped_refptr<CefResourceManager::Request> request) override {
+ CEF_REQUIRE_IO_THREAD();
+ EXPECT_FALSE(state_->got_on_request_);
+ EXPECT_FALSE(state_->got_on_request_canceled_);
+
+ state_->got_on_request_.yes();
+ state_->request_url_ = request->url();
+
+ return false;
+ }
+
+ void OnRequestCanceled(
+ scoped_refptr<CefResourceManager::Request> request) override {
+ CEF_REQUIRE_IO_THREAD();
+ EXPECT_TRUE(state_->got_on_request_);
+ EXPECT_FALSE(state_->got_on_request_canceled_);
+
+ state_->got_on_request_canceled_.yes();
+ EXPECT_STREQ(state_->request_url_.c_str(), request->url().c_str());
+ }
+
+ private:
+ State* state_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestProvider);
+};
+
+// Helper that blocks on destruction of 1 or more TestProviders.
+class ProviderDestructHelper {
+ public:
+ explicit ProviderDestructHelper(int expected_count)
+ : expected_count_(expected_count),
+ event_(CefWaitableEvent::CreateWaitableEvent(true, false)) {
+ CHECK_GT(expected_count_, 0);
+ }
+
+ base::OnceClosure callback() {
+ return base::BindOnce(
+ [](ProviderDestructHelper* self) { self->DestructCallback(); },
+ base::Unretained(this));
+ }
+
+ void Wait() { event_->Wait(); }
+
+ private:
+ void DestructCallback() {
+ bool signal = false;
+
+ {
+ base::AutoLock lock_scope(lock_);
+ CHECK_LT(current_count_, expected_count_);
+ if (++current_count_ == expected_count_) {
+ signal = true;
+ }
+ }
+
+ if (signal) {
+ // Don't access any members after calling Signal(), which causes |this| to
+ // be deleted on a different thread.
+ auto event = event_;
+ event->Signal();
+ }
+ }
+
+ const int expected_count_;
+ int current_count_ = 0;
+ CefRefPtr<CefWaitableEvent> event_;
+ base::Lock lock_;
+};
+
+// Test that that the URL retrieved via Request::url() is parsed as expected.
+// Fragment or query components in any order should be removed.
+void TestUrlParsing(const char* kUrl) {
+ const char kRequestUrl[] = "http://test.com/ResourceManagerTest";
+
+ ResourceManagerTestHandler::State state;
+ state.urls_.push_back(kUrl);
+
+ TestProvider::State provider_state;
+
+ ProviderDestructHelper destruct_helper(1);
+ provider_state.destruct_callback_ = destruct_helper.callback();
+
+ state.manager_->AddProvider(new TestProvider(&provider_state), 0,
+ std::string());
+
+ CefRefPtr<ResourceManagerTestHandler> handler =
+ new ResourceManagerTestHandler(&state);
+ handler->ExecuteTest();
+
+ ReleaseAndWaitForDestructor(handler);
+
+ state.manager_ = nullptr;
+
+ // Wait for the manager to be deleted.
+ destruct_helper.Wait();
+
+ // The provider is called.
+ EXPECT_TRUE(provider_state.got_on_request_);
+ EXPECT_FALSE(provider_state.got_on_request_canceled_);
+ EXPECT_TRUE(provider_state.got_destruct_);
+
+ // The expected URL is received.
+ EXPECT_STREQ(kRequestUrl, provider_state.request_url_.c_str());
+
+ // The request is not handled.
+ EXPECT_EQ(state.messages_.size(), 1U);
+ EXPECT_EQ(CreateMessage(kDoneMsg, kNotHandled), state.messages_[0]);
+}
+
+} // namespace
+
+TEST(ResourceManagerTest, UrlParsingNoQueryOrFragment) {
+ TestUrlParsing("http://test.com/ResourceManagerTest");
+}
+
+TEST(ResourceManagerTest, UrlParsingWithQuery) {
+ TestUrlParsing("http://test.com/ResourceManagerTest?foo=bar&choo=too");
+}
+
+TEST(ResourceManagerTest, UrlParsingWithFragment) {
+ TestUrlParsing("http://test.com/ResourceManagerTest#some/fragment");
+}
+
+TEST(ResourceManagerTest, UrlParsingWithQueryAndFragment) {
+ TestUrlParsing("http://test.com/ResourceManagerTest?foo=bar#some/fragment");
+}
+
+TEST(ResourceManagerTest, UrlParsingWithFragmentAndQuery) {
+ TestUrlParsing("http://test.com/ResourceManagerTest#some/fragment?foo=bar");
+}
+
+namespace {
+
+const char kProviderId[] = "provider";
+
+// Content provider that performs simple tests.
+class SimpleTestProvider : public TestProvider {
+ public:
+ enum Mode {
+ NOT_HANDLED,
+ CONTINUE,
+ STOP,
+ REMOVE,
+ REMOVE_ALL,
+ DO_NOTHING,
+ };
+
+ SimpleTestProvider(State* state, Mode mode, CefResourceManager* manager)
+ : TestProvider(state), mode_(mode), manager_(manager) {}
+
+ SimpleTestProvider(State* state,
+ Mode mode,
+ CefResourceManager* manager,
+ base::OnceClosure do_nothing_callback)
+ : TestProvider(state),
+ mode_(mode),
+ manager_(manager),
+ do_nothing_callback_(std::move(do_nothing_callback)) {}
+
+ bool OnRequest(scoped_refptr<CefResourceManager::Request> request) override {
+ TestProvider::OnRequest(request);
+
+ if (mode_ == NOT_HANDLED) {
+ return false;
+ } else if (mode_ == CONTINUE) {
+ request->Continue(nullptr);
+ } else if (mode_ == STOP) {
+ request->Stop();
+ } else if (mode_ == REMOVE) {
+ manager_->RemoveProviders(kProviderId);
+ } else if (mode_ == REMOVE_ALL) {
+ manager_->RemoveAllProviders();
+ } else if (mode_ == DO_NOTHING) {
+ EXPECT_FALSE(do_nothing_callback_.is_null());
+ std::move(do_nothing_callback_).Run();
+ }
+
+ return true;
+ }
+
+ private:
+ Mode mode_;
+ CefResourceManager* manager_; // Weak reference.
+ base::OnceClosure do_nothing_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(SimpleTestProvider);
+};
+
+} // namespace
+
+// Test with multiple providers that do not handle the request.
+TEST(ResourceManagerTest, ProviderNotHandled) {
+ const char kUrl[] = "http://test.com/ResourceManagerTest";
+
+ ResourceManagerTestHandler::State state;
+ state.urls_.push_back(kUrl);
+
+ TestProvider::State provider_state1;
+ TestProvider::State provider_state2;
+
+ ProviderDestructHelper destruct_helper(2);
+ provider_state1.destruct_callback_ = destruct_helper.callback();
+ provider_state2.destruct_callback_ = destruct_helper.callback();
+
+ state.manager_->AddProvider(
+ new SimpleTestProvider(&provider_state1, SimpleTestProvider::NOT_HANDLED,
+ nullptr),
+ 0, std::string());
+ state.manager_->AddProvider(
+ new SimpleTestProvider(&provider_state2, SimpleTestProvider::NOT_HANDLED,
+ nullptr),
+ 0, std::string());
+
+ CefRefPtr<ResourceManagerTestHandler> handler =
+ new ResourceManagerTestHandler(&state);
+ handler->ExecuteTest();
+
+ ReleaseAndWaitForDestructor(handler);
+
+ state.manager_ = nullptr;
+
+ // Wait for the manager to be deleted.
+ destruct_helper.Wait();
+
+ // All providers are called.
+ EXPECT_TRUE(provider_state1.got_on_request_);
+ EXPECT_FALSE(provider_state1.got_on_request_canceled_);
+ EXPECT_TRUE(provider_state1.got_destruct_);
+
+ EXPECT_TRUE(provider_state2.got_on_request_);
+ EXPECT_FALSE(provider_state2.got_on_request_canceled_);
+ EXPECT_TRUE(provider_state2.got_destruct_);
+
+ EXPECT_EQ(state.messages_.size(), 1U);
+ EXPECT_EQ(CreateMessage(kDoneMsg, kNotHandled), state.messages_[0]);
+}
+
+// Test with multiple providers that all continue.
+TEST(ResourceManagerTest, ProviderContinue) {
+ const char kUrl[] = "http://test.com/ResourceManagerTest";
+
+ ResourceManagerTestHandler::State state;
+ state.urls_.push_back(kUrl);
+
+ TestProvider::State provider_state1;
+ TestProvider::State provider_state2;
+
+ ProviderDestructHelper destruct_helper(2);
+ provider_state1.destruct_callback_ = destruct_helper.callback();
+ provider_state2.destruct_callback_ = destruct_helper.callback();
+
+ state.manager_->AddProvider(
+ new SimpleTestProvider(&provider_state1, SimpleTestProvider::CONTINUE,
+ nullptr),
+ 0, std::string());
+ state.manager_->AddProvider(
+ new SimpleTestProvider(&provider_state2, SimpleTestProvider::CONTINUE,
+ nullptr),
+ 0, std::string());
+
+ CefRefPtr<ResourceManagerTestHandler> handler =
+ new ResourceManagerTestHandler(&state);
+ handler->ExecuteTest();
+
+ ReleaseAndWaitForDestructor(handler);
+
+ state.manager_ = nullptr;
+
+ // Wait for the manager to be deleted.
+ destruct_helper.Wait();
+
+ // All providers are called.
+ EXPECT_TRUE(provider_state1.got_on_request_);
+ EXPECT_FALSE(provider_state1.got_on_request_canceled_);
+ EXPECT_TRUE(provider_state1.got_destruct_);
+
+ EXPECT_TRUE(provider_state2.got_on_request_);
+ EXPECT_FALSE(provider_state2.got_on_request_canceled_);
+ EXPECT_TRUE(provider_state2.got_destruct_);
+
+ EXPECT_EQ(state.messages_.size(), 1U);
+ EXPECT_EQ(CreateMessage(kDoneMsg, kNotHandled), state.messages_[0]);
+}
+
+// Test with multiple providers where the first one stops.
+TEST(ResourceManagerTest, ProviderStop) {
+ const char kUrl[] = "http://test.com/ResourceManagerTest";
+
+ ResourceManagerTestHandler::State state;
+ state.urls_.push_back(kUrl);
+
+ TestProvider::State provider_state1;
+ TestProvider::State provider_state2;
+
+ ProviderDestructHelper destruct_helper(2);
+ provider_state1.destruct_callback_ = destruct_helper.callback();
+ provider_state2.destruct_callback_ = destruct_helper.callback();
+
+ state.manager_->AddProvider(
+ new SimpleTestProvider(&provider_state1, SimpleTestProvider::STOP,
+ nullptr),
+ 0, std::string());
+ state.manager_->AddProvider(
+ new SimpleTestProvider(&provider_state2, SimpleTestProvider::CONTINUE,
+ nullptr),
+ 0, std::string());
+
+ CefRefPtr<ResourceManagerTestHandler> handler =
+ new ResourceManagerTestHandler(&state);
+ handler->ExecuteTest();
+
+ ReleaseAndWaitForDestructor(handler);
+
+ state.manager_ = nullptr;
+
+ // Wait for the manager to be deleted.
+ destruct_helper.Wait();
+
+ // 1st provider is called.
+ EXPECT_TRUE(provider_state1.got_on_request_);
+ EXPECT_FALSE(provider_state1.got_on_request_canceled_);
+ EXPECT_TRUE(provider_state1.got_destruct_);
+
+ // 2nd provider is not called because the 1st provider stopped.
+ EXPECT_FALSE(provider_state2.got_on_request_);
+ EXPECT_FALSE(provider_state2.got_on_request_canceled_);
+ EXPECT_TRUE(provider_state2.got_destruct_);
+
+ EXPECT_EQ(state.messages_.size(), 1U);
+ EXPECT_EQ(CreateMessage(kDoneMsg, kNotHandled), state.messages_[0]);
+}
+
+// Test with multiple providers where the first one removes multiple providers
+// including itself.
+TEST(ResourceManagerTest, ProviderRemove) {
+ const char kUrl[] = "http://test.com/ResourceManagerTest";
+
+ ResourceManagerTestHandler::State state;
+ state.urls_.push_back(kUrl);
+
+ TestProvider::State provider_state1;
+ TestProvider::State provider_state2;
+ TestProvider::State provider_state3;
+
+ ProviderDestructHelper destruct_helper(3);
+ provider_state1.destruct_callback_ = destruct_helper.callback();
+ provider_state2.destruct_callback_ = destruct_helper.callback();
+ provider_state3.destruct_callback_ = destruct_helper.callback();
+
+ state.manager_->AddProvider(
+ new SimpleTestProvider(&provider_state1, SimpleTestProvider::REMOVE,
+ state.manager_.get()),
+ 0, kProviderId);
+ state.manager_->AddProvider(
+ new SimpleTestProvider(&provider_state2, SimpleTestProvider::CONTINUE,
+ nullptr),
+ 0, kProviderId);
+ state.manager_->AddProvider(
+ new SimpleTestProvider(&provider_state3, SimpleTestProvider::CONTINUE,
+ nullptr),
+ 1, std::string());
+
+ CefRefPtr<ResourceManagerTestHandler> handler =
+ new ResourceManagerTestHandler(&state);
+ handler->ExecuteTest();
+
+ ReleaseAndWaitForDestructor(handler);
+
+ state.manager_ = nullptr;
+
+ // Wait for the manager to be deleted.
+ destruct_helper.Wait();
+
+ // 1st provider is called and canceled.
+ EXPECT_TRUE(provider_state1.got_on_request_);
+ EXPECT_TRUE(provider_state1.got_on_request_canceled_);
+ EXPECT_TRUE(provider_state1.got_destruct_);
+
+ // 2nd provider is removed with the 1st provider due to sharing the same
+ // identifier.
+ EXPECT_FALSE(provider_state2.got_on_request_);
+ EXPECT_FALSE(provider_state2.got_on_request_canceled_);
+ EXPECT_TRUE(provider_state2.got_destruct_);
+
+ // 3rd provider is called.
+ EXPECT_TRUE(provider_state3.got_on_request_);
+ EXPECT_FALSE(provider_state3.got_on_request_canceled_);
+ EXPECT_TRUE(provider_state3.got_destruct_);
+
+ EXPECT_EQ(state.messages_.size(), 1U);
+ EXPECT_EQ(CreateMessage(kDoneMsg, kNotHandled), state.messages_[0]);
+}
+
+// Test with multiple providers where the first provider removes all.
+TEST(ResourceManagerTest, ProviderRemoveAll) {
+ const char kUrl[] = "http://test.com/ResourceManagerTest";
+
+ ResourceManagerTestHandler::State state;
+ state.urls_.push_back(kUrl);
+
+ TestProvider::State provider_state1;
+ TestProvider::State provider_state2;
+ TestProvider::State provider_state3;
+
+ ProviderDestructHelper destruct_helper(3);
+ provider_state1.destruct_callback_ = destruct_helper.callback();
+ provider_state2.destruct_callback_ = destruct_helper.callback();
+ provider_state3.destruct_callback_ = destruct_helper.callback();
+
+ state.manager_->AddProvider(
+ new SimpleTestProvider(&provider_state1, SimpleTestProvider::REMOVE_ALL,
+ state.manager_.get()),
+ 0, std::string());
+ state.manager_->AddProvider(
+ new SimpleTestProvider(&provider_state2, SimpleTestProvider::CONTINUE,
+ nullptr),
+ 0, std::string());
+ state.manager_->AddProvider(
+ new SimpleTestProvider(&provider_state3, SimpleTestProvider::CONTINUE,
+ nullptr),
+ 1, std::string());
+
+ CefRefPtr<ResourceManagerTestHandler> handler =
+ new ResourceManagerTestHandler(&state);
+ handler->ExecuteTest();
+
+ ReleaseAndWaitForDestructor(handler);
+
+ state.manager_ = nullptr;
+
+ // Wait for the manager to be deleted.
+ destruct_helper.Wait();
+
+ // 1st provider is called and canceled.
+ EXPECT_TRUE(provider_state1.got_on_request_);
+ EXPECT_TRUE(provider_state1.got_on_request_canceled_);
+ EXPECT_TRUE(provider_state1.got_destruct_);
+
+ // 2nd and 3rd providers are not called due to removal.
+ EXPECT_FALSE(provider_state2.got_on_request_);
+ EXPECT_FALSE(provider_state2.got_on_request_canceled_);
+ EXPECT_TRUE(provider_state2.got_destruct_);
+
+ EXPECT_FALSE(provider_state3.got_on_request_);
+ EXPECT_FALSE(provider_state3.got_on_request_canceled_);
+ EXPECT_TRUE(provider_state3.got_destruct_);
+
+ EXPECT_EQ(state.messages_.size(), 1U);
+ EXPECT_EQ(CreateMessage(kDoneMsg, kNotHandled), state.messages_[0]);
+}
+
+// Test with multiple providers that do not continue and will be destroyed when
+// the manager is destroyed.
+TEST(ResourceManagerTest, ProviderDoNothing) {
+ const char kUrl[] = "http://test.com/ResourceManagerTest";
+
+ ResourceManagerTestHandler::State state;
+ state.urls_.push_back(kUrl);
+
+ TestProvider::State provider_state1;
+ TestProvider::State provider_state2;
+
+ ProviderDestructHelper destruct_helper(2);
+ provider_state1.destruct_callback_ = destruct_helper.callback();
+ provider_state2.destruct_callback_ = destruct_helper.callback();
+
+ CefRefPtr<ResourceManagerTestHandler> handler =
+ new ResourceManagerTestHandler(&state);
+
+ // DelayedDestroyTest will be executed from SimpleTestHandler::OnRequest.
+ state.manager_->AddProvider(
+ new SimpleTestProvider(
+ &provider_state1, SimpleTestProvider::DO_NOTHING, nullptr,
+ base::BindOnce(&ResourceManagerTestHandler::DelayedDestroyTest,
+ handler)),
+ 0, std::string());
+ state.manager_->AddProvider(
+ new SimpleTestProvider(&provider_state2, SimpleTestProvider::DO_NOTHING,
+ nullptr),
+ 0, std::string());
+
+ handler->ExecuteTest();
+
+ // Destroy the resource manager before the handler so that pending requests
+ // are canceled. ResourceManagerTestHandler::GetResourceHandler will be called
+ // after the manager is destroyed.
+ state.manager_ = nullptr;
+
+ // Wait for the manager to be deleted.
+ destruct_helper.Wait();
+
+ ReleaseAndWaitForDestructor(handler);
+
+ // Only the first provider is called. It will be canceled when the manager is
+ // destroyed.
+ EXPECT_TRUE(provider_state1.got_on_request_);
+ EXPECT_TRUE(provider_state1.got_on_request_canceled_);
+ EXPECT_TRUE(provider_state1.got_destruct_);
+
+ EXPECT_FALSE(provider_state2.got_on_request_);
+ EXPECT_FALSE(provider_state2.got_on_request_canceled_);
+ EXPECT_TRUE(provider_state2.got_destruct_);
+
+ // Nothing completed.
+ EXPECT_EQ(state.messages_.size(), 0U);
+}
+
+// Test AddContentProvider.
+TEST(ResourceManagerTest, ContentProvider) {
+ const char kUrl1[] = "http://test.com/ResourceManagerTest1";
+ const char kUrl2[] = "http://test.com/ResourceManagerTest2";
+ const char kUrl3[] = "http://test.com/ResourceManagerTest3";
+
+ const std::string& success1_message = CreateMessage(kDoneMsg, "Success1");
+ const std::string& success2_message = CreateMessage(kDoneMsg, "Success2");
+ const std::string& not_handled_message = CreateMessage(kDoneMsg, kNotHandled);
+
+ ResourceManagerTestHandler::State state;
+ state.urls_.push_back(kUrl1);
+ state.urls_.push_back(kUrl2);
+ state.urls_.push_back(kUrl3);
+
+ // Only the first 2 URLs will be handled.
+ state.manager_->AddContentProvider(kUrl1, CreateContents(success1_message),
+ "text/html", 0, std::string());
+ state.manager_->AddContentProvider(kUrl2, CreateContents(success2_message),
+ "text/html", 0, std::string());
+
+ CefRefPtr<ResourceManagerTestHandler> handler =
+ new ResourceManagerTestHandler(&state);
+ handler->ExecuteTest();
+
+ ReleaseAndWaitForDestructor(handler);
+
+ state.manager_ = nullptr;
+
+ // Wait for the manager to be deleted.
+ WaitForIOThread();
+
+ // Both providers are called and return the expected results.
+ EXPECT_EQ(state.messages_.size(), 3U);
+ EXPECT_EQ(success1_message, state.messages_[0]);
+ EXPECT_EQ(success2_message, state.messages_[1]);
+ EXPECT_EQ(not_handled_message, state.messages_[2]);
+}
+
+// Test AddDirectoryProvider.
+TEST(ResourceManagerTest, DirectoryProvider) {
+ const char kUrlBase[] = "http://test.com/ResourceManager";
+ const char kFile1[] = "File1.html";
+ const char kFile2[] = "File2.html";
+ const char kFile3[] = "File3.html";
+ const char kFile4[] = "File4.html";
+
+ const std::string& success1_message = CreateMessage(kDoneMsg, "Success1");
+ const std::string& success2_message = CreateMessage(kDoneMsg, "Success2");
+ const std::string& success3_message = CreateMessage(kDoneMsg, "Success3");
+ const std::string& not_handled_message = CreateMessage(kDoneMsg, kNotHandled);
+
+ ResourceManagerTestHandler::State state;
+ state.urls_.push_back(kUrlBase + std::string("/") + kFile1);
+ state.urls_.push_back(kUrlBase + std::string("/") + kFile2);
+ state.urls_.push_back(kUrlBase + std::string("/sub/") + kFile3);
+ state.urls_.push_back(kUrlBase + std::string("/") + kFile4);
+
+ CefScopedTempDir scoped_dir;
+ EXPECT_TRUE(scoped_dir.CreateUniqueTempDir());
+
+ // Write the files to disk.
+ const std::string& temp_dir = scoped_dir.GetPath();
+ WriteFile(client::file_util::JoinPath(temp_dir, kFile1),
+ CreateContents(success1_message));
+ WriteFile(client::file_util::JoinPath(temp_dir, kFile2),
+ CreateContents(success2_message));
+
+ // Also include a subdirectory.
+ const std::string& sub_dir = client::file_util::JoinPath(temp_dir, "sub");
+ EXPECT_TRUE(CefCreateDirectory(sub_dir));
+ WriteFile(client::file_util::JoinPath(sub_dir, kFile3),
+ CreateContents(success3_message));
+
+ state.manager_->AddDirectoryProvider(kUrlBase, temp_dir, 0, std::string());
+
+ CefRefPtr<ResourceManagerTestHandler> handler =
+ new ResourceManagerTestHandler(&state);
+ handler->ExecuteTest();
+
+ ReleaseAndWaitForDestructor(handler);
+
+ state.manager_ = nullptr;
+
+ // Wait for the manager to be deleted.
+ WaitForIOThread();
+
+ EXPECT_TRUE(scoped_dir.Delete());
+
+ // The first 3 URLs are handled.
+ EXPECT_EQ(state.messages_.size(), 4U);
+ EXPECT_EQ(success1_message, state.messages_[0]);
+ EXPECT_EQ(success2_message, state.messages_[1]);
+ EXPECT_EQ(success3_message, state.messages_[2]);
+ EXPECT_EQ(not_handled_message, state.messages_[3]);
+}
+
+// Test AddArchiveProvider.
+TEST(ResourceManagerTest, ArchiveProvider) {
+ const char kUrlBase[] = "http://test.com/ResourceManager";
+ const char kFile1[] = "File1.html";
+ const char kFile2[] = "File2.html";
+ const char kFile3[] = "File3.html";
+ const char kFile4[] = "File4.html";
+
+ const std::string& success1_message = CreateMessage(kDoneMsg, "Success1");
+ const std::string& success2_message = CreateMessage(kDoneMsg, "Success2");
+ const std::string& success3_message = CreateMessage(kDoneMsg, "Success3");
+ const std::string& not_handled_message = CreateMessage(kDoneMsg, kNotHandled);
+
+ ResourceManagerTestHandler::State state;
+ state.urls_.push_back(kUrlBase + std::string("/") + kFile1);
+ state.urls_.push_back(kUrlBase + std::string("/") + kFile2);
+ state.urls_.push_back(kUrlBase + std::string("/sub/") + kFile3);
+ state.urls_.push_back(kUrlBase + std::string("/") + kFile4);
+
+ // Only the first 2 URLs will be handled.
+ CefScopedTempDir scoped_dir;
+ EXPECT_TRUE(scoped_dir.CreateUniqueTempDir());
+
+ const std::string& temp_dir = scoped_dir.GetPath();
+
+ // Write the files to disk.
+ const std::string& file_dir = client::file_util::JoinPath(temp_dir, "files");
+ EXPECT_TRUE(CefCreateDirectory(file_dir));
+ WriteFile(client::file_util::JoinPath(file_dir, kFile1),
+ CreateContents(success1_message));
+ WriteFile(client::file_util::JoinPath(file_dir, kFile2),
+ CreateContents(success2_message));
+
+ // Also include a subdirectory.
+ const std::string& sub_dir = client::file_util::JoinPath(file_dir, "sub");
+ EXPECT_TRUE(CefCreateDirectory(sub_dir));
+ WriteFile(client::file_util::JoinPath(sub_dir, kFile3),
+ CreateContents(success3_message));
+
+ const std::string& archive_path =
+ client::file_util::JoinPath(temp_dir, "archive.zip");
+
+ // Create the archive file.
+ EXPECT_TRUE(CefZipDirectory(file_dir, archive_path, false));
+
+ state.manager_->AddArchiveProvider(kUrlBase, archive_path, std::string(), 0,
+ std::string());
+
+ CefRefPtr<ResourceManagerTestHandler> handler =
+ new ResourceManagerTestHandler(&state);
+ handler->ExecuteTest();
+
+ ReleaseAndWaitForDestructor(handler);
+
+ state.manager_ = nullptr;
+
+ // Wait for the manager to be deleted.
+ WaitForIOThread();
+
+ EXPECT_TRUE(scoped_dir.Delete());
+
+ // The first 3 URLs are handled.
+ EXPECT_EQ(state.messages_.size(), 4U);
+ EXPECT_EQ(success1_message, state.messages_[0]);
+ EXPECT_EQ(success2_message, state.messages_[1]);
+ EXPECT_EQ(success3_message, state.messages_[2]);
+ EXPECT_EQ(not_handled_message, state.messages_[3]);
+}
+
+namespace {
+
+// Content provider that only handles a single request.
+class OneShotProvider : public CefResourceManager::Provider {
+ public:
+ OneShotProvider(const std::string& content,
+ base::OnceClosure destruct_callback)
+ : done_(false),
+ content_(content),
+ destruct_callback_(std::move(destruct_callback)) {
+ EXPECT_FALSE(content.empty());
+ }
+
+ ~OneShotProvider() {
+ CEF_REQUIRE_IO_THREAD();
+ std::move(destruct_callback_).Run();
+ }
+
+ bool OnRequest(scoped_refptr<CefResourceManager::Request> request) override {
+ CEF_REQUIRE_IO_THREAD();
+
+ if (done_) {
+ // Provider only handles a single request.
+ return false;
+ }
+
+ done_ = true;
+
+ CefRefPtr<CefStreamReader> stream = CefStreamReader::CreateForData(
+ static_cast<void*>(const_cast<char*>(content_.data())),
+ content_.length());
+
+ request->Continue(new CefStreamResourceHandler("text/html", stream));
+ return true;
+ }
+
+ private:
+ bool done_;
+ std::string content_;
+ base::OnceClosure destruct_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(OneShotProvider);
+};
+
+} // namespace
+
+// Test that providers are called in the expected order and return expected
+// results.
+TEST(ResourceManagerTest, ProviderOrder) {
+ const char kUrl1[] = "http://test.com/ResourceManagerTest1";
+ const char kUrl2[] = "http://test.com/ResourceManagerTest2";
+ const char kUrl3[] = "http://test.com/ResourceManagerTest3";
+ const char kUrl4[] = "http://test.com/ResourceManagerTest4";
+ const char kUrl5[] = "http://test.com/ResourceManagerTest5";
+
+ const std::string& success1_message = CreateMessage(kDoneMsg, "Success1");
+ const std::string& success2_message = CreateMessage(kDoneMsg, "Success2");
+ const std::string& success3_message = CreateMessage(kDoneMsg, "Success3");
+ const std::string& success4_message = CreateMessage(kDoneMsg, "Success4");
+ const std::string& not_handled_message = CreateMessage(kDoneMsg, kNotHandled);
+
+ ResourceManagerTestHandler::State state;
+ state.urls_.push_back(kUrl1);
+ state.urls_.push_back(kUrl2);
+ state.urls_.push_back(kUrl3);
+ state.urls_.push_back(kUrl4);
+ state.urls_.push_back(kUrl5);
+
+ ProviderDestructHelper destruct_helper(4);
+
+ // Resulting order should be sequential; success1 .. success4.
+ state.manager_->AddProvider(
+ new OneShotProvider(CreateContents(success2_message),
+ destruct_helper.callback()),
+ 0, std::string());
+ state.manager_->AddProvider(
+ new OneShotProvider(CreateContents(success1_message),
+ destruct_helper.callback()),
+ -100, std::string());
+ state.manager_->AddProvider(
+ new OneShotProvider(CreateContents(success4_message),
+ destruct_helper.callback()),
+ 100, std::string());
+ state.manager_->AddProvider(
+ new OneShotProvider(CreateContents(success3_message),
+ destruct_helper.callback()),
+ 0, std::string());
+
+ CefRefPtr<ResourceManagerTestHandler> handler =
+ new ResourceManagerTestHandler(&state);
+ handler->ExecuteTest();
+
+ ReleaseAndWaitForDestructor(handler);
+
+ state.manager_ = nullptr;
+
+ // Wait for the manager to be deleted.
+ destruct_helper.Wait();
+
+ EXPECT_EQ(state.messages_.size(), 5U);
+ EXPECT_EQ(success1_message, state.messages_[0]);
+ EXPECT_EQ(success2_message, state.messages_[1]);
+ EXPECT_EQ(success3_message, state.messages_[2]);
+ EXPECT_EQ(success4_message, state.messages_[3]);
+ EXPECT_EQ(not_handled_message, state.messages_[4]);
+}
+
+namespace {
+
+// Content provider that returns the path component as the result.
+class EchoProvider : public CefResourceManager::Provider {
+ public:
+ EchoProvider(const std::string& base_url) : base_url_(base_url) {
+ EXPECT_TRUE(!base_url_.empty());
+ }
+
+ bool OnRequest(scoped_refptr<CefResourceManager::Request> request) override {
+ CEF_REQUIRE_IO_THREAD();
+
+ const std::string& url = request->url();
+ if (url.find(base_url_) != 0U) {
+ // Not handled by this provider.
+ return false;
+ }
+
+ const std::string& content = CreateContents(url);
+
+ // Parse the URL to identify the delay.
+ int delay = atoi(url.substr(base_url_.size()).data());
+ EXPECT_GE(delay, 0);
+
+ CefRefPtr<CefStreamReader> stream = CefStreamReader::CreateForData(
+ static_cast<void*>(const_cast<char*>(content.data())),
+ content.length());
+
+ CefRefPtr<CefStreamResourceHandler> handler(
+ new CefStreamResourceHandler("text/html", stream));
+ CefPostDelayedTask(TID_IO,
+ base::BindOnce(&CefResourceManager::Request::Continue,
+ request, handler),
+ delay);
+
+ return true;
+ }
+
+ private:
+ std::string base_url_;
+
+ DISALLOW_COPY_AND_ASSIGN(EchoProvider);
+};
+
+} // namespace
+
+// Test that many requests pending at the same time complete in the expected
+// order and return correct results.
+TEST(ResourceManagerTest, ManyRequests) {
+ const char kUrl[] = "http://test.com/ResourceManagerTest";
+ const char kBaseUrl[] = "http://test.com/ResourceManagerSubTest/";
+
+ ResourceManagerTestHandler::State state;
+ state.urls_.push_back(kUrl);
+
+ state.expected_message_ct_ = 50U;
+
+ // Build a page with lots of iframes.
+ std::stringstream ss;
+ ss << "<html><body>";
+ for (size_t i = 0U; i < state.expected_message_ct_; ++i) {
+ ss << "<iframe src=\"" << kBaseUrl << (i * 10) << "\"></iframe>";
+ }
+ ss << "</body></html>";
+
+ state.manager_->AddContentProvider(kUrl, ss.str(), "text/html", 0,
+ std::string());
+ state.manager_->AddProvider(new EchoProvider(kBaseUrl), 0, std::string());
+
+ CefRefPtr<ResourceManagerTestHandler> handler =
+ new ResourceManagerTestHandler(&state);
+ handler->ExecuteTest();
+
+ ReleaseAndWaitForDestructor(handler);
+
+ state.manager_ = nullptr;
+
+ // Wait for the manager to be deleted.
+ WaitForIOThread();
+
+ EXPECT_EQ(state.messages_.size(), state.expected_message_ct_);
+
+ // Requests should complete in order due to the delay.
+ for (size_t i = 0; i < state.messages_.size(); ++i) {
+ ss.str("");
+ ss << kBaseUrl << (i * 10);
+ EXPECT_EQ(ss.str(), state.messages_[i]);
+ }
+}
+
+namespace {
+
+// Content provider that only handles a single request and then removes itself
+// from the manager.
+class OneShotRemovalProvider : public TestProvider {
+ public:
+ OneShotRemovalProvider(State* state,
+ const std::string& content,
+ CefResourceManager* manager,
+ const std::string& identifier,
+ bool remove_before_continue)
+ : TestProvider(state),
+ content_(content),
+ manager_(manager),
+ identifier_(identifier),
+ remove_before_continue_(remove_before_continue) {
+ EXPECT_FALSE(content.empty());
+ }
+
+ bool OnRequest(scoped_refptr<CefResourceManager::Request> request) override {
+ TestProvider::OnRequest(request);
+
+ CefRefPtr<CefStreamReader> stream = CefStreamReader::CreateForData(
+ static_cast<void*>(const_cast<char*>(content_.data())),
+ content_.length());
+
+ if (remove_before_continue_) {
+ // Removing the provider before continuing should trigger a call to
+ // OnRequestCanceled.
+ if (identifier_.empty()) {
+ manager_->RemoveAllProviders();
+ } else {
+ manager_->RemoveProviders(identifier_);
+ }
+ }
+
+ request->Continue(new CefStreamResourceHandler("text/html", stream));
+
+ if (!remove_before_continue_) {
+ // The request has already completed so OnRequestCanceled is not called.
+ if (identifier_.empty()) {
+ manager_->RemoveAllProviders();
+ } else {
+ manager_->RemoveProviders(identifier_);
+ }
+ }
+
+ return true;
+ }
+
+ private:
+ std::string content_;
+ CefResourceManager* manager_; // Weak reference.
+ std::string identifier_;
+ bool remove_before_continue_;
+
+ DISALLOW_COPY_AND_ASSIGN(OneShotRemovalProvider);
+};
+
+} // namespace
+
+// Test that removal of the current provider after continue has the expected
+// results.
+TEST(ResourceManagerTest, RemoveProviderAfterContinue) {
+ const char kUrl1[] = "http://test.com/ResourceManagerTest1";
+ const char kUrl2[] = "http://test.com/ResourceManagerTest2";
+ const char kUrl3[] = "http://test.com/ResourceManagerTest3";
+ const char kUrl4[] = "http://test.com/ResourceManagerTest4";
+
+ const std::string& success1_message = CreateMessage(kDoneMsg, "Success1");
+ const std::string& success2_message = CreateMessage(kDoneMsg, "Success2");
+ const std::string& success3_message = CreateMessage(kDoneMsg, "Success3");
+ const std::string& success4_message = CreateMessage(kDoneMsg, "Success4");
+ const std::string& not_handled_message = CreateMessage(kDoneMsg, kNotHandled);
+
+ ResourceManagerTestHandler::State state;
+ state.urls_.push_back(kUrl1);
+ state.urls_.push_back(kUrl2);
+ state.urls_.push_back(kUrl3);
+ state.urls_.push_back(kUrl4);
+
+ TestProvider::State provider_state1;
+ TestProvider::State provider_state2;
+ TestProvider::State provider_state3;
+ TestProvider::State provider_state4;
+
+ ProviderDestructHelper destruct_helper(4);
+ provider_state1.destruct_callback_ = destruct_helper.callback();
+ provider_state2.destruct_callback_ = destruct_helper.callback();
+ provider_state3.destruct_callback_ = destruct_helper.callback();
+ provider_state4.destruct_callback_ = destruct_helper.callback();
+
+ const char kIdentifier1[] = "id1";
+ const char kIdentifier2[] = "id2";
+ const char kIdentifier4[] = "id4";
+
+ // Resulting order should be sequential; success1 .. success4.
+ state.manager_->AddProvider(
+ new OneShotRemovalProvider(&provider_state2,
+ CreateContents(success2_message),
+ state.manager_.get(), kIdentifier2, false),
+ 0, kIdentifier2);
+ state.manager_->AddProvider(
+ new OneShotRemovalProvider(&provider_state1,
+ CreateContents(success1_message),
+ state.manager_.get(), kIdentifier1, false),
+ -100, kIdentifier1);
+ state.manager_->AddProvider(
+ new OneShotRemovalProvider(&provider_state4,
+ CreateContents(success4_message),
+ state.manager_.get(), kIdentifier4, false),
+ 100, kIdentifier4);
+ // Will be removed at the same time as #2 and therefore never called.
+ state.manager_->AddProvider(
+ new OneShotRemovalProvider(&provider_state3,
+ CreateContents(success3_message),
+ state.manager_.get(), kIdentifier2, false),
+ 0, kIdentifier2);
+
+ CefRefPtr<ResourceManagerTestHandler> handler =
+ new ResourceManagerTestHandler(&state);
+ handler->ExecuteTest();
+
+ ReleaseAndWaitForDestructor(handler);
+
+ state.manager_ = nullptr;
+
+ // Wait for the manager to be deleted.
+ destruct_helper.Wait();
+
+ // All providers except for 3 (which is removed at the same time as 2 and
+ // therefore never executed) should complete.
+ EXPECT_EQ(state.messages_.size(), 4U);
+ EXPECT_EQ(success1_message, state.messages_[0]);
+ EXPECT_EQ(success2_message, state.messages_[1]);
+ EXPECT_EQ(success4_message, state.messages_[2]);
+ EXPECT_EQ(not_handled_message, state.messages_[3]);
+
+ EXPECT_TRUE(provider_state1.got_on_request_);
+ EXPECT_FALSE(provider_state1.got_on_request_canceled_);
+ EXPECT_TRUE(provider_state1.got_destruct_);
+
+ EXPECT_TRUE(provider_state2.got_on_request_);
+ EXPECT_FALSE(provider_state2.got_on_request_canceled_);
+ EXPECT_TRUE(provider_state2.got_destruct_);
+
+ // Removed at the same time as 2 and therefore not executed.
+ EXPECT_FALSE(provider_state3.got_on_request_);
+ EXPECT_FALSE(provider_state3.got_on_request_canceled_);
+ EXPECT_TRUE(provider_state3.got_destruct_);
+
+ EXPECT_TRUE(provider_state4.got_on_request_);
+ EXPECT_FALSE(provider_state4.got_on_request_canceled_);
+ EXPECT_TRUE(provider_state4.got_destruct_);
+}
+
+// Test that removal of the current provider before continue has the expected
+// results.
+TEST(ResourceManagerTest, RemoveProviderBeforeContinue) {
+ const char kUrl1[] = "http://test.com/ResourceManagerTest1";
+ const char kUrl2[] = "http://test.com/ResourceManagerTest2";
+ const char kUrl3[] = "http://test.com/ResourceManagerTest3";
+ const char kUrl4[] = "http://test.com/ResourceManagerTest4";
+
+ const std::string& success1_message = CreateMessage(kDoneMsg, "Success1");
+ const std::string& success2_message = CreateMessage(kDoneMsg, "Success2");
+ const std::string& success3_message = CreateMessage(kDoneMsg, "Success3");
+ const std::string& success4_message = CreateMessage(kDoneMsg, "Success4");
+ const std::string& not_handled_message = CreateMessage(kDoneMsg, kNotHandled);
+
+ ResourceManagerTestHandler::State state;
+ state.urls_.push_back(kUrl1);
+ state.urls_.push_back(kUrl2);
+ state.urls_.push_back(kUrl3);
+ state.urls_.push_back(kUrl4);
+
+ TestProvider::State provider_state1;
+ TestProvider::State provider_state2;
+ TestProvider::State provider_state3;
+ TestProvider::State provider_state4;
+
+ ProviderDestructHelper destruct_helper(4);
+ provider_state1.destruct_callback_ = destruct_helper.callback();
+ provider_state2.destruct_callback_ = destruct_helper.callback();
+ provider_state3.destruct_callback_ = destruct_helper.callback();
+ provider_state4.destruct_callback_ = destruct_helper.callback();
+
+ const char kIdentifier1[] = "id1";
+ const char kIdentifier2[] = "id2";
+ const char kIdentifier4[] = "id4";
+
+ // Resulting order should be sequential; success1 .. success4.
+ state.manager_->AddProvider(
+ new OneShotRemovalProvider(&provider_state2,
+ CreateContents(success2_message),
+ state.manager_.get(), kIdentifier2, true),
+ 0, kIdentifier2);
+ state.manager_->AddProvider(
+ new OneShotRemovalProvider(&provider_state1,
+ CreateContents(success1_message),
+ state.manager_.get(), kIdentifier1, true),
+ -100, kIdentifier1);
+ state.manager_->AddProvider(
+ new OneShotRemovalProvider(&provider_state4,
+ CreateContents(success4_message),
+ state.manager_.get(), kIdentifier4, true),
+ 100, kIdentifier4);
+ state.manager_->AddProvider(
+ new OneShotRemovalProvider(&provider_state3,
+ CreateContents(success3_message),
+ state.manager_.get(), kIdentifier2, true),
+ 0, kIdentifier2);
+
+ CefRefPtr<ResourceManagerTestHandler> handler =
+ new ResourceManagerTestHandler(&state);
+ handler->ExecuteTest();
+
+ ReleaseAndWaitForDestructor(handler);
+
+ state.manager_ = nullptr;
+
+ // Wait for the manager to be deleted.
+ destruct_helper.Wait();
+
+ // No providers should complete.
+ EXPECT_EQ(state.messages_.size(), 4U);
+ EXPECT_EQ(not_handled_message, state.messages_[0]);
+ EXPECT_EQ(not_handled_message, state.messages_[1]);
+ EXPECT_EQ(not_handled_message, state.messages_[2]);
+ EXPECT_EQ(not_handled_message, state.messages_[3]);
+
+ // All providers except 3 should be called and then canceled.
+ EXPECT_TRUE(provider_state1.got_on_request_);
+ EXPECT_TRUE(provider_state1.got_on_request_canceled_);
+ EXPECT_TRUE(provider_state1.got_destruct_);
+
+ EXPECT_TRUE(provider_state2.got_on_request_);
+ EXPECT_TRUE(provider_state2.got_on_request_canceled_);
+ EXPECT_TRUE(provider_state2.got_destruct_);
+
+ // Removed at the same time as 2 and therefore not executed.
+ EXPECT_FALSE(provider_state3.got_on_request_);
+ EXPECT_FALSE(provider_state3.got_on_request_canceled_);
+ EXPECT_TRUE(provider_state3.got_destruct_);
+
+ EXPECT_TRUE(provider_state4.got_on_request_);
+ EXPECT_TRUE(provider_state4.got_on_request_canceled_);
+ EXPECT_TRUE(provider_state4.got_destruct_);
+}
+
+// Test that removal of all providers after continue has the expected results.
+TEST(ResourceManagerTest, RemoveAllProvidersAfterContinue) {
+ const char kUrl1[] = "http://test.com/ResourceManagerTest1";
+ const char kUrl2[] = "http://test.com/ResourceManagerTest2";
+ const char kUrl3[] = "http://test.com/ResourceManagerTest3";
+ const char kUrl4[] = "http://test.com/ResourceManagerTest4";
+
+ const std::string& success1_message = CreateMessage(kDoneMsg, "Success1");
+ const std::string& success2_message = CreateMessage(kDoneMsg, "Success2");
+ const std::string& success3_message = CreateMessage(kDoneMsg, "Success3");
+ const std::string& success4_message = CreateMessage(kDoneMsg, "Success4");
+ const std::string& not_handled_message = CreateMessage(kDoneMsg, kNotHandled);
+
+ ResourceManagerTestHandler::State state;
+ state.urls_.push_back(kUrl1);
+ state.urls_.push_back(kUrl2);
+ state.urls_.push_back(kUrl3);
+ state.urls_.push_back(kUrl4);
+
+ TestProvider::State provider_state1;
+ TestProvider::State provider_state2;
+ TestProvider::State provider_state3;
+ TestProvider::State provider_state4;
+
+ ProviderDestructHelper destruct_helper(4);
+ provider_state1.destruct_callback_ = destruct_helper.callback();
+ provider_state2.destruct_callback_ = destruct_helper.callback();
+ provider_state3.destruct_callback_ = destruct_helper.callback();
+ provider_state4.destruct_callback_ = destruct_helper.callback();
+
+ // Resulting order should be sequential; success1 .. success4.
+ state.manager_->AddProvider(
+ new OneShotRemovalProvider(&provider_state2,
+ CreateContents(success2_message),
+ state.manager_.get(), std::string(), false),
+ 0, std::string());
+ state.manager_->AddProvider(
+ new OneShotRemovalProvider(&provider_state1,
+ CreateContents(success1_message),
+ state.manager_.get(), std::string(), false),
+ -100, std::string());
+ state.manager_->AddProvider(
+ new OneShotRemovalProvider(&provider_state4,
+ CreateContents(success4_message),
+ state.manager_.get(), std::string(), false),
+ 100, std::string());
+ // Will be removed at the same time as #2 and therefore never called.
+ state.manager_->AddProvider(
+ new OneShotRemovalProvider(&provider_state3,
+ CreateContents(success3_message),
+ state.manager_.get(), std::string(), false),
+ 0, std::string());
+
+ CefRefPtr<ResourceManagerTestHandler> handler =
+ new ResourceManagerTestHandler(&state);
+ handler->ExecuteTest();
+
+ ReleaseAndWaitForDestructor(handler);
+
+ state.manager_ = nullptr;
+
+ // Wait for the manager to be deleted.
+ destruct_helper.Wait();
+
+ // Only the 1st provider should complete
+ EXPECT_EQ(state.messages_.size(), 4U);
+ EXPECT_EQ(success1_message, state.messages_[0]);
+ EXPECT_EQ(not_handled_message, state.messages_[1]);
+ EXPECT_EQ(not_handled_message, state.messages_[2]);
+ EXPECT_EQ(not_handled_message, state.messages_[3]);
+
+ EXPECT_TRUE(provider_state1.got_on_request_);
+ EXPECT_FALSE(provider_state1.got_on_request_canceled_);
+ EXPECT_TRUE(provider_state1.got_destruct_);
+
+ EXPECT_FALSE(provider_state2.got_on_request_);
+ EXPECT_FALSE(provider_state2.got_on_request_canceled_);
+ EXPECT_TRUE(provider_state2.got_destruct_);
+
+ EXPECT_FALSE(provider_state3.got_on_request_);
+ EXPECT_FALSE(provider_state3.got_on_request_canceled_);
+ EXPECT_TRUE(provider_state3.got_destruct_);
+
+ EXPECT_FALSE(provider_state4.got_on_request_);
+ EXPECT_FALSE(provider_state4.got_on_request_canceled_);
+ EXPECT_TRUE(provider_state4.got_destruct_);
+}
+
+// Test that removal of all providers before continue has the expected results.
+TEST(ResourceManagerTest, RemoveAllProvidersBeforeContinue) {
+ const char kUrl1[] = "http://test.com/ResourceManagerTest1";
+ const char kUrl2[] = "http://test.com/ResourceManagerTest2";
+ const char kUrl3[] = "http://test.com/ResourceManagerTest3";
+ const char kUrl4[] = "http://test.com/ResourceManagerTest4";
+
+ const std::string& success1_message = CreateMessage(kDoneMsg, "Success1");
+ const std::string& success2_message = CreateMessage(kDoneMsg, "Success2");
+ const std::string& success3_message = CreateMessage(kDoneMsg, "Success3");
+ const std::string& success4_message = CreateMessage(kDoneMsg, "Success4");
+ const std::string& not_handled_message = CreateMessage(kDoneMsg, kNotHandled);
+
+ ResourceManagerTestHandler::State state;
+ state.urls_.push_back(kUrl1);
+ state.urls_.push_back(kUrl2);
+ state.urls_.push_back(kUrl3);
+ state.urls_.push_back(kUrl4);
+
+ TestProvider::State provider_state1;
+ TestProvider::State provider_state2;
+ TestProvider::State provider_state3;
+ TestProvider::State provider_state4;
+
+ ProviderDestructHelper destruct_helper(4);
+ provider_state1.destruct_callback_ = destruct_helper.callback();
+ provider_state2.destruct_callback_ = destruct_helper.callback();
+ provider_state3.destruct_callback_ = destruct_helper.callback();
+ provider_state4.destruct_callback_ = destruct_helper.callback();
+
+ // Resulting order should be sequential; success1 .. success4.
+ state.manager_->AddProvider(
+ new OneShotRemovalProvider(&provider_state2,
+ CreateContents(success2_message),
+ state.manager_.get(), std::string(), true),
+ 0, std::string());
+ state.manager_->AddProvider(
+ new OneShotRemovalProvider(&provider_state1,
+ CreateContents(success1_message),
+ state.manager_.get(), std::string(), true),
+ -100, std::string());
+ state.manager_->AddProvider(
+ new OneShotRemovalProvider(&provider_state4,
+ CreateContents(success4_message),
+ state.manager_.get(), std::string(), true),
+ 100, std::string());
+ // Will be removed at the same time as #2 and therefore never called.
+ state.manager_->AddProvider(
+ new OneShotRemovalProvider(&provider_state3,
+ CreateContents(success3_message),
+ state.manager_.get(), std::string(), true),
+ 0, std::string());
+
+ CefRefPtr<ResourceManagerTestHandler> handler =
+ new ResourceManagerTestHandler(&state);
+ handler->ExecuteTest();
+
+ ReleaseAndWaitForDestructor(handler);
+
+ state.manager_ = nullptr;
+
+ // Wait for the manager to be deleted.
+ destruct_helper.Wait();
+
+ // No providers should complete.
+ EXPECT_EQ(state.messages_.size(), 4U);
+ EXPECT_EQ(not_handled_message, state.messages_[0]);
+ EXPECT_EQ(not_handled_message, state.messages_[1]);
+ EXPECT_EQ(not_handled_message, state.messages_[2]);
+ EXPECT_EQ(not_handled_message, state.messages_[3]);
+
+ // 1st provider should also be canceled.
+ EXPECT_TRUE(provider_state1.got_on_request_);
+ EXPECT_TRUE(provider_state1.got_on_request_canceled_);
+ EXPECT_TRUE(provider_state1.got_destruct_);
+
+ EXPECT_FALSE(provider_state2.got_on_request_);
+ EXPECT_FALSE(provider_state2.got_on_request_canceled_);
+ EXPECT_TRUE(provider_state2.got_destruct_);
+
+ EXPECT_FALSE(provider_state3.got_on_request_);
+ EXPECT_FALSE(provider_state3.got_on_request_canceled_);
+ EXPECT_TRUE(provider_state3.got_destruct_);
+
+ EXPECT_FALSE(provider_state4.got_on_request_);
+ EXPECT_FALSE(provider_state4.got_on_request_canceled_);
+ EXPECT_TRUE(provider_state4.got_destruct_);
+}
+
+namespace {
+
+// Test the URL filter capability.
+class UrlFilterTestProvider : public TestProvider {
+ public:
+ UrlFilterTestProvider(State* state,
+ const std::string& expected_url,
+ const std::string& expected_url_after_filter)
+ : TestProvider(state),
+ expected_url_(expected_url),
+ expected_url_after_filter_(expected_url_after_filter) {}
+
+ bool OnRequest(scoped_refptr<CefResourceManager::Request> request) override {
+ TestProvider::OnRequest(request);
+
+ // Request::url is already filtered.
+ EXPECT_EQ(expected_url_, request->url());
+
+ // Explicitly filter the URL again.
+ const std::string& filtered_url =
+ request->url_filter().Run(request->request()->GetURL());
+ EXPECT_EQ(expected_url_after_filter_, filtered_url);
+
+ request->Continue(nullptr);
+ return true;
+ }
+
+ private:
+ std::string expected_url_;
+ std::string expected_url_after_filter_;
+ DISALLOW_COPY_AND_ASSIGN(UrlFilterTestProvider);
+};
+
+std::string TestUrlFilter(const std::string& url) {
+ return url + "Rewrite";
+}
+
+// Add to the URL but keep the query component.
+std::string TestUrlFilterWithQuery(const std::string& url) {
+ size_t pos = url.find('?');
+ if (pos == std::string::npos) {
+ return url;
+ }
+ return url.substr(0, pos) + "Rewrite" + url.substr(pos);
+}
+
+// Add to the URL but keep the fragment component.
+std::string TestUrlFilterWithFragment(const std::string& url) {
+ size_t pos = url.find('#');
+ if (pos == std::string::npos) {
+ return url;
+ }
+ return url.substr(0, pos) + "Rewrite" + url.substr(pos);
+}
+
+} // namespace
+
+// Test the URL filter capability.
+TEST(ResourceManagerTest, UrlFilter) {
+ const char kUrl[] = "http://test.com/ResourceManagerTest";
+ const char kExpectedUrl[] = "http://test.com/ResourceManagerTestRewrite";
+
+ ResourceManagerTestHandler::State state;
+ state.urls_.push_back(kUrl);
+
+ // Set the URL filter.
+ state.manager_->SetUrlFilter(base::BindRepeating(TestUrlFilter));
+
+ TestProvider::State provider_state1;
+ TestProvider::State provider_state2;
+
+ ProviderDestructHelper destruct_helper(2);
+ provider_state1.destruct_callback_ = destruct_helper.callback();
+ provider_state2.destruct_callback_ = destruct_helper.callback();
+
+ state.manager_->AddProvider(
+ new UrlFilterTestProvider(&provider_state1, kExpectedUrl, kExpectedUrl),
+ 0, std::string());
+ state.manager_->AddProvider(
+ new UrlFilterTestProvider(&provider_state2, kExpectedUrl, kExpectedUrl),
+ 0, std::string());
+
+ CefRefPtr<ResourceManagerTestHandler> handler =
+ new ResourceManagerTestHandler(&state);
+ handler->ExecuteTest();
+
+ ReleaseAndWaitForDestructor(handler);
+
+ state.manager_ = nullptr;
+
+ // Wait for the manager to be deleted.
+ destruct_helper.Wait();
+
+ // All providers are called.
+ EXPECT_TRUE(provider_state1.got_on_request_);
+ EXPECT_FALSE(provider_state1.got_on_request_canceled_);
+ EXPECT_TRUE(provider_state1.got_destruct_);
+
+ EXPECT_TRUE(provider_state2.got_on_request_);
+ EXPECT_FALSE(provider_state2.got_on_request_canceled_);
+ EXPECT_TRUE(provider_state2.got_destruct_);
+
+ EXPECT_EQ(state.messages_.size(), 1U);
+ EXPECT_EQ(CreateMessage(kDoneMsg, kNotHandled), state.messages_[0]);
+}
+
+// Test the URL filter capability with a query component.
+TEST(ResourceManagerTest, UrlFilterWithQuery) {
+ const char kUrl[] = "http://test.com/ResourceManagerTest?foo=bar";
+ const char kExpectedUrl[] = "http://test.com/ResourceManagerTestRewrite";
+ const char kExpectedUrlAfterFilter[] =
+ "http://test.com/ResourceManagerTestRewrite?foo=bar";
+
+ ResourceManagerTestHandler::State state;
+ state.urls_.push_back(kUrl);
+
+ // Set the URL filter.
+ state.manager_->SetUrlFilter(base::BindRepeating(TestUrlFilterWithQuery));
+
+ TestProvider::State provider_state1;
+ TestProvider::State provider_state2;
+
+ ProviderDestructHelper destruct_helper(2);
+ provider_state1.destruct_callback_ = destruct_helper.callback();
+ provider_state2.destruct_callback_ = destruct_helper.callback();
+
+ state.manager_->AddProvider(
+ new UrlFilterTestProvider(&provider_state1, kExpectedUrl,
+ kExpectedUrlAfterFilter),
+ 0, std::string());
+ state.manager_->AddProvider(
+ new UrlFilterTestProvider(&provider_state2, kExpectedUrl,
+ kExpectedUrlAfterFilter),
+ 0, std::string());
+
+ CefRefPtr<ResourceManagerTestHandler> handler =
+ new ResourceManagerTestHandler(&state);
+ handler->ExecuteTest();
+
+ ReleaseAndWaitForDestructor(handler);
+
+ state.manager_ = nullptr;
+
+ // Wait for the manager to be deleted.
+ destruct_helper.Wait();
+
+ // All providers are called.
+ EXPECT_TRUE(provider_state1.got_on_request_);
+ EXPECT_FALSE(provider_state1.got_on_request_canceled_);
+ EXPECT_TRUE(provider_state1.got_destruct_);
+
+ EXPECT_TRUE(provider_state2.got_on_request_);
+ EXPECT_FALSE(provider_state2.got_on_request_canceled_);
+ EXPECT_TRUE(provider_state2.got_destruct_);
+
+ EXPECT_EQ(state.messages_.size(), 1U);
+ EXPECT_EQ(CreateMessage(kDoneMsg, kNotHandled), state.messages_[0]);
+}
+
+// Test the URL filter capability with a fragment component.
+TEST(ResourceManagerTest, UrlFilterWithFragment) {
+ // Fragment components will not be passed with the request.
+ const char kUrl[] = "http://test.com/ResourceManagerTest#fragment";
+ const char kExpectedUrl[] = "http://test.com/ResourceManagerTestRewrite";
+ const char kExpectedUrlAfterFilter[] =
+ "http://test.com/ResourceManagerTestRewrite#fragment";
+
+ ResourceManagerTestHandler::State state;
+ state.urls_.push_back(kUrl);
+
+ // Set the URL filter.
+ state.manager_->SetUrlFilter(base::BindRepeating(TestUrlFilterWithFragment));
+
+ TestProvider::State provider_state1;
+ TestProvider::State provider_state2;
+
+ ProviderDestructHelper destruct_helper(2);
+ provider_state1.destruct_callback_ = destruct_helper.callback();
+ provider_state2.destruct_callback_ = destruct_helper.callback();
+
+ state.manager_->AddProvider(
+ new UrlFilterTestProvider(&provider_state1, kExpectedUrl,
+ kExpectedUrlAfterFilter),
+ 0, std::string());
+ state.manager_->AddProvider(
+ new UrlFilterTestProvider(&provider_state2, kExpectedUrl,
+ kExpectedUrlAfterFilter),
+ 0, std::string());
+
+ CefRefPtr<ResourceManagerTestHandler> handler =
+ new ResourceManagerTestHandler(&state);
+ handler->ExecuteTest();
+
+ ReleaseAndWaitForDestructor(handler);
+
+ state.manager_ = nullptr;
+
+ // Wait for the manager to be deleted.
+ destruct_helper.Wait();
+
+ // All providers are called.
+ EXPECT_TRUE(provider_state1.got_on_request_);
+ EXPECT_FALSE(provider_state1.got_on_request_canceled_);
+ EXPECT_TRUE(provider_state1.got_destruct_);
+
+ EXPECT_TRUE(provider_state2.got_on_request_);
+ EXPECT_FALSE(provider_state2.got_on_request_canceled_);
+ EXPECT_TRUE(provider_state2.got_destruct_);
+
+ EXPECT_EQ(state.messages_.size(), 1U);
+ EXPECT_EQ(CreateMessage(kDoneMsg, kNotHandled), state.messages_[0]);
+}
+
+namespace {
+
+// Test the mime type resolver capability.
+class MimeTypeTestProvider : public TestProvider {
+ public:
+ MimeTypeTestProvider(State* state, const std::string& expected_mime_type)
+ : TestProvider(state), expected_mime_type_(expected_mime_type) {}
+
+ bool OnRequest(scoped_refptr<CefResourceManager::Request> request) override {
+ TestProvider::OnRequest(request);
+
+ const std::string& mime_type =
+ request->mime_type_resolver().Run(request->url());
+ EXPECT_EQ(expected_mime_type_, mime_type);
+
+ request->Continue(nullptr);
+ return true;
+ }
+
+ private:
+ std::string expected_mime_type_;
+ DISALLOW_COPY_AND_ASSIGN(MimeTypeTestProvider);
+};
+
+const char kExpectedMimeType[] = "foo/bar";
+
+std::string TestMimeTypeResolver(const std::string& url) {
+ return kExpectedMimeType;
+}
+
+} // namespace
+
+// Test the mime type resolver capability.
+TEST(ResourceManagerTest, MimeTypeResolver) {
+ const char kUrl[] = "http://test.com/ResourceManagerTest";
+
+ ResourceManagerTestHandler::State state;
+ state.urls_.push_back(kUrl);
+
+ // Set the mime type resolver.
+ state.manager_->SetMimeTypeResolver(
+ base::BindRepeating(TestMimeTypeResolver));
+
+ TestProvider::State provider_state1;
+ TestProvider::State provider_state2;
+
+ ProviderDestructHelper destruct_helper(2);
+ provider_state1.destruct_callback_ = destruct_helper.callback();
+ provider_state2.destruct_callback_ = destruct_helper.callback();
+
+ state.manager_->AddProvider(
+ new MimeTypeTestProvider(&provider_state1, kExpectedMimeType), 0,
+ std::string());
+ state.manager_->AddProvider(
+ new MimeTypeTestProvider(&provider_state2, kExpectedMimeType), 0,
+ std::string());
+
+ CefRefPtr<ResourceManagerTestHandler> handler =
+ new ResourceManagerTestHandler(&state);
+ handler->ExecuteTest();
+
+ ReleaseAndWaitForDestructor(handler);
+
+ state.manager_ = nullptr;
+
+ // Wait for the manager to be deleted.
+ destruct_helper.Wait();
+
+ // All providers are called.
+ EXPECT_TRUE(provider_state1.got_on_request_);
+ EXPECT_FALSE(provider_state1.got_on_request_canceled_);
+ EXPECT_TRUE(provider_state1.got_destruct_);
+
+ EXPECT_TRUE(provider_state2.got_on_request_);
+ EXPECT_FALSE(provider_state2.got_on_request_canceled_);
+ EXPECT_TRUE(provider_state2.got_destruct_);
+
+ EXPECT_EQ(state.messages_.size(), 1U);
+ EXPECT_EQ(CreateMessage(kDoneMsg, kNotHandled), state.messages_[0]);
+}
+
+namespace {
+
+// Content provider that adds another provider before or after the current
+// provider.
+class AddingTestProvider : public TestProvider {
+ public:
+ AddingTestProvider(State* state,
+ State* new_state,
+ CefResourceManager* manager,
+ bool before)
+ : TestProvider(state),
+ new_state_(new_state),
+ manager_(manager),
+ before_(before) {}
+
+ bool OnRequest(scoped_refptr<CefResourceManager::Request> request) override {
+ TestProvider::OnRequest(request);
+
+ manager_->AddProvider(
+ new SimpleTestProvider(new_state_, SimpleTestProvider::CONTINUE,
+ nullptr),
+ before_ ? -1 : 1, std::string());
+
+ request->Continue(nullptr);
+ return true;
+ }
+
+ private:
+ State* new_state_;
+ CefResourceManager* manager_; // Weak reference.
+ bool before_;
+
+ DISALLOW_COPY_AND_ASSIGN(AddingTestProvider);
+};
+
+} // namespace
+
+// Test adding a new provider after the current provider.
+TEST(ResourceManagerTest, AddProviderAfter) {
+ const char kUrl[] = "http://test.com/ResourceManagerTest";
+
+ ResourceManagerTestHandler::State state;
+ state.urls_.push_back(kUrl);
+
+ TestProvider::State provider_state1;
+ TestProvider::State provider_state2;
+
+ ProviderDestructHelper destruct_helper(2);
+ provider_state1.destruct_callback_ = destruct_helper.callback();
+ provider_state2.destruct_callback_ = destruct_helper.callback();
+
+ state.manager_->AddProvider(
+ new AddingTestProvider(&provider_state1, &provider_state2,
+ state.manager_.get(), false),
+ 0, std::string());
+
+ CefRefPtr<ResourceManagerTestHandler> handler =
+ new ResourceManagerTestHandler(&state);
+ handler->ExecuteTest();
+
+ ReleaseAndWaitForDestructor(handler);
+
+ state.manager_ = nullptr;
+
+ // Wait for the manager to be deleted.
+ destruct_helper.Wait();
+
+ // All providers are called.
+ EXPECT_TRUE(provider_state1.got_on_request_);
+ EXPECT_FALSE(provider_state1.got_on_request_canceled_);
+ EXPECT_TRUE(provider_state1.got_destruct_);
+
+ EXPECT_TRUE(provider_state2.got_on_request_);
+ EXPECT_FALSE(provider_state2.got_on_request_canceled_);
+ EXPECT_TRUE(provider_state2.got_destruct_);
+
+ EXPECT_EQ(state.messages_.size(), 1U);
+ EXPECT_EQ(CreateMessage(kDoneMsg, kNotHandled), state.messages_[0]);
+}
+
+// Test adding a new provider before the current provider.
+TEST(ResourceManagerTest, AddProviderBefore) {
+ const char kUrl[] = "http://test.com/ResourceManagerTest";
+
+ ResourceManagerTestHandler::State state;
+ state.urls_.push_back(kUrl);
+
+ TestProvider::State provider_state1;
+ TestProvider::State provider_state2;
+
+ ProviderDestructHelper destruct_helper(2);
+ provider_state1.destruct_callback_ = destruct_helper.callback();
+ provider_state2.destruct_callback_ = destruct_helper.callback();
+
+ state.manager_->AddProvider(
+ new AddingTestProvider(&provider_state1, &provider_state2,
+ state.manager_.get(), true),
+ 0, std::string());
+
+ CefRefPtr<ResourceManagerTestHandler> handler =
+ new ResourceManagerTestHandler(&state);
+ handler->ExecuteTest();
+
+ ReleaseAndWaitForDestructor(handler);
+
+ state.manager_ = nullptr;
+
+ // Wait for the manager to be deleted.
+ destruct_helper.Wait();
+
+ // 1st provider is called.
+ EXPECT_TRUE(provider_state1.got_on_request_);
+ EXPECT_FALSE(provider_state1.got_on_request_canceled_);
+ EXPECT_TRUE(provider_state1.got_destruct_);
+
+ // 2nd provider is not called because it was added before the 1st provider.
+ EXPECT_FALSE(provider_state2.got_on_request_);
+ EXPECT_FALSE(provider_state2.got_on_request_canceled_);
+ EXPECT_TRUE(provider_state2.got_destruct_);
+
+ EXPECT_EQ(state.messages_.size(), 1U);
+ EXPECT_EQ(CreateMessage(kDoneMsg, kNotHandled), state.messages_[0]);
+}
diff --git a/tests/ceftests/resource_request_handler_unittest.cc b/tests/ceftests/resource_request_handler_unittest.cc
new file mode 100644
index 00000000..ecfb782d
--- /dev/null
+++ b/tests/ceftests/resource_request_handler_unittest.cc
@@ -0,0 +1,4007 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include <algorithm>
+#include <cmath>
+#include <memory>
+#include <sstream>
+#include <string>
+
+#include "include/base/cef_callback.h"
+#include "include/cef_request_context_handler.h"
+#include "include/cef_scheme.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "include/wrapper/cef_stream_resource_handler.h"
+#include "tests/ceftests/routing_test_handler.h"
+#include "tests/ceftests/test_handler.h"
+#include "tests/ceftests/test_util.h"
+#include "tests/gtest/include/gtest/gtest.h"
+
+namespace {
+
+// Normal stream resource handler implementation that additionally verifies
+// calls to Cancel.
+// This also tests the CefStreamResourceHandler implementation.
+class NormalResourceHandler : public CefStreamResourceHandler {
+ public:
+ NormalResourceHandler(int status_code,
+ const CefString& status_text,
+ const CefString& mime_type,
+ CefResponse::HeaderMap header_map,
+ CefRefPtr<CefStreamReader> stream,
+ base::OnceClosure destroy_callback)
+ : CefStreamResourceHandler(status_code,
+ status_text,
+ mime_type,
+ header_map,
+ stream),
+ destroy_callback_(std::move(destroy_callback)) {}
+
+ ~NormalResourceHandler() override {
+ EXPECT_EQ(1, cancel_ct_);
+ std::move(destroy_callback_).Run();
+ }
+
+ void Cancel() override {
+ EXPECT_IO_THREAD();
+ cancel_ct_++;
+ }
+
+ private:
+ base::OnceClosure destroy_callback_;
+ int cancel_ct_ = 0;
+};
+
+// Normal stream resource handler implementation that additionally continues
+// using the callback object and verifies calls to Cancel.
+class CallbackResourceHandler : public CefResourceHandler {
+ public:
+ enum Mode {
+ DELAYED_OPEN,
+ DELAYED_READ,
+ IMMEDIATE_OPEN,
+ IMMEDIATE_READ,
+ DELAYED_ALL,
+ IMMEDIATE_ALL,
+ };
+
+ bool IsDelayedOpen() const {
+ return mode_ == DELAYED_OPEN || mode_ == DELAYED_ALL;
+ }
+
+ bool IsDelayedRead() const {
+ return mode_ == DELAYED_READ || mode_ == DELAYED_ALL;
+ }
+
+ bool IsImmediateOpen() const {
+ return mode_ == IMMEDIATE_OPEN || mode_ == IMMEDIATE_ALL;
+ }
+
+ bool IsImmediateRead() const {
+ return mode_ == IMMEDIATE_READ || mode_ == IMMEDIATE_ALL;
+ }
+
+ CallbackResourceHandler(Mode mode,
+ int status_code,
+ const CefString& status_text,
+ const CefString& mime_type,
+ CefResponse::HeaderMap header_map,
+ CefRefPtr<CefStreamReader> stream,
+ base::OnceClosure destroy_callback)
+ : mode_(mode),
+ status_code_(status_code),
+ status_text_(status_text),
+ mime_type_(mime_type),
+ header_map_(header_map),
+ stream_(stream),
+ destroy_callback_(std::move(destroy_callback)) {
+ DCHECK(!mime_type_.empty());
+ DCHECK(stream_.get());
+ }
+
+ ~CallbackResourceHandler() override {
+ EXPECT_EQ(1, cancel_ct_);
+ std::move(destroy_callback_).Run();
+ }
+
+ bool Open(CefRefPtr<CefRequest> request,
+ bool& handle_request,
+ CefRefPtr<CefCallback> callback) override {
+ EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO));
+
+ if (IsDelayedOpen()) {
+ // Continue the request asynchronously by executing the callback.
+ CefPostTask(TID_FILE_USER_VISIBLE,
+ base::BindOnce(&CefCallback::Continue, callback));
+ handle_request = false;
+ return true;
+ } else if (IsImmediateOpen()) {
+ // Continue the request immediately be executing the callback.
+ callback->Continue();
+ handle_request = false;
+ return true;
+ }
+
+ // Continue the request immediately in the default manner.
+ handle_request = true;
+ return true;
+ }
+
+ void GetResponseHeaders(CefRefPtr<CefResponse> response,
+ int64& response_length,
+ CefString& redirectUrl) override {
+ response->SetStatus(status_code_);
+ response->SetStatusText(status_text_);
+ response->SetMimeType(mime_type_);
+
+ if (!header_map_.empty()) {
+ response->SetHeaderMap(header_map_);
+ }
+
+ response_length = -1;
+ }
+
+ bool Read(void* data_out,
+ int bytes_to_read,
+ int& bytes_read,
+ CefRefPtr<CefResourceReadCallback> callback) override {
+ EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO));
+ EXPECT_GT(bytes_to_read, 0);
+
+ bytes_read = 0;
+
+ if (IsDelayedRead()) {
+ // Continue the request asynchronously by executing the callback.
+ CefPostTask(TID_FILE_USER_VISIBLE,
+ base::BindOnce(&CallbackResourceHandler::ContinueRead, this,
+ data_out, bytes_to_read, callback));
+ return true;
+ } else if (IsImmediateRead()) {
+ // Continue the request immediately be executing the callback.
+ ContinueRead(data_out, bytes_to_read, callback);
+ return true;
+ }
+
+ // Continue the request immediately in the default manner.
+ return DoRead(data_out, bytes_to_read, bytes_read);
+ }
+
+ void Cancel() override {
+ EXPECT_IO_THREAD();
+ cancel_ct_++;
+ }
+
+ private:
+ void ContinueRead(void* data_out,
+ int bytes_to_read,
+ CefRefPtr<CefResourceReadCallback> callback) {
+ EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO));
+
+ int bytes_read = 0;
+ DoRead(data_out, bytes_to_read, bytes_read);
+ callback->Continue(bytes_read);
+ }
+
+ bool DoRead(void* data_out, int bytes_to_read, int& bytes_read) {
+ DCHECK_GT(bytes_to_read, 0);
+
+ // Read until the buffer is full or until Read() returns 0 to indicate no
+ // more data.
+ bytes_read = 0;
+ int read = 0;
+ do {
+ read = static_cast<int>(
+ stream_->Read(static_cast<char*>(data_out) + bytes_read, 1,
+ bytes_to_read - bytes_read));
+ bytes_read += read;
+ } while (read != 0 && bytes_read < bytes_to_read);
+
+ return (bytes_read > 0);
+ }
+
+ const Mode mode_;
+
+ const int status_code_;
+ const CefString status_text_;
+ const CefString mime_type_;
+ const CefResponse::HeaderMap header_map_;
+ const CefRefPtr<CefStreamReader> stream_;
+
+ base::OnceClosure destroy_callback_;
+ int cancel_ct_ = 0;
+
+ IMPLEMENT_REFCOUNTING(CallbackResourceHandler);
+ DISALLOW_COPY_AND_ASSIGN(CallbackResourceHandler);
+};
+
+// Resource handler implementation that never completes. Used to test
+// destruction handling behavior for in-progress requests.
+class IncompleteResourceHandlerOld : public CefResourceHandler {
+ public:
+ enum TestMode {
+ BLOCK_PROCESS_REQUEST,
+ BLOCK_READ_RESPONSE,
+ };
+
+ IncompleteResourceHandlerOld(TestMode test_mode,
+ const std::string& mime_type,
+ base::OnceClosure destroy_callback)
+ : test_mode_(test_mode),
+ mime_type_(mime_type),
+ destroy_callback_(std::move(destroy_callback)) {}
+
+ ~IncompleteResourceHandlerOld() override {
+ EXPECT_EQ(1, process_request_ct_);
+
+ EXPECT_EQ(1, cancel_ct_);
+
+ if (test_mode_ == BLOCK_READ_RESPONSE) {
+ EXPECT_EQ(1, get_response_headers_ct_);
+ EXPECT_EQ(1, read_response_ct_);
+ } else {
+ EXPECT_EQ(0, get_response_headers_ct_);
+ EXPECT_EQ(0, read_response_ct_);
+ }
+
+ std::move(destroy_callback_).Run();
+ }
+
+ bool ProcessRequest(CefRefPtr<CefRequest> request,
+ CefRefPtr<CefCallback> callback) override {
+ EXPECT_IO_THREAD();
+
+ process_request_ct_++;
+
+ if (test_mode_ == BLOCK_PROCESS_REQUEST) {
+ // Never release or execute this callback.
+ incomplete_callback_ = callback;
+ } else {
+ callback->Continue();
+ }
+ return true;
+ }
+
+ void GetResponseHeaders(CefRefPtr<CefResponse> response,
+ int64& response_length,
+ CefString& redirectUrl) override {
+ EXPECT_IO_THREAD();
+ EXPECT_EQ(test_mode_, BLOCK_READ_RESPONSE);
+
+ get_response_headers_ct_++;
+
+ response->SetStatus(200);
+ response->SetStatusText("OK");
+ response->SetMimeType(mime_type_);
+ response_length = 100;
+ }
+
+ bool ReadResponse(void* data_out,
+ int bytes_to_read,
+ int& bytes_read,
+ CefRefPtr<CefCallback> callback) override {
+ EXPECT_IO_THREAD();
+ EXPECT_EQ(test_mode_, BLOCK_READ_RESPONSE);
+
+ read_response_ct_++;
+
+ // Never release or execute this callback.
+ incomplete_callback_ = callback;
+ bytes_read = 0;
+ return true;
+ }
+
+ void Cancel() override {
+ EXPECT_IO_THREAD();
+ cancel_ct_++;
+ }
+
+ private:
+ const TestMode test_mode_;
+ const std::string mime_type_;
+ base::OnceClosure destroy_callback_;
+
+ int process_request_ct_ = 0;
+ int get_response_headers_ct_ = 0;
+ int read_response_ct_ = 0;
+ int cancel_ct_ = 0;
+
+ CefRefPtr<CefCallback> incomplete_callback_;
+
+ IMPLEMENT_REFCOUNTING(IncompleteResourceHandlerOld);
+ DISALLOW_COPY_AND_ASSIGN(IncompleteResourceHandlerOld);
+};
+
+class IncompleteResourceHandler : public CefResourceHandler {
+ public:
+ enum TestMode {
+ BLOCK_OPEN,
+ BLOCK_READ,
+ };
+
+ IncompleteResourceHandler(TestMode test_mode,
+ const std::string& mime_type,
+ base::OnceClosure destroy_callback)
+ : test_mode_(test_mode),
+ mime_type_(mime_type),
+ destroy_callback_(std::move(destroy_callback)) {}
+
+ ~IncompleteResourceHandler() override {
+ EXPECT_EQ(1, open_ct_);
+
+ EXPECT_EQ(1, cancel_ct_);
+
+ if (test_mode_ == BLOCK_READ) {
+ EXPECT_EQ(1, get_response_headers_ct_);
+ EXPECT_EQ(1, read_ct_);
+ } else {
+ EXPECT_EQ(0, get_response_headers_ct_);
+ EXPECT_EQ(0, read_ct_);
+ }
+
+ std::move(destroy_callback_).Run();
+ }
+
+ bool Open(CefRefPtr<CefRequest> request,
+ bool& handle_request,
+ CefRefPtr<CefCallback> callback) override {
+ EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO));
+
+ open_ct_++;
+
+ if (test_mode_ == BLOCK_OPEN) {
+ // Never release or execute this callback.
+ incomplete_open_callback_ = callback;
+ } else {
+ // Continue immediately.
+ handle_request = true;
+ }
+ return true;
+ }
+
+ bool ProcessRequest(CefRefPtr<CefRequest> request,
+ CefRefPtr<CefCallback> callback) override {
+ EXPECT_TRUE(false); // Not reached.
+ return false;
+ }
+
+ void GetResponseHeaders(CefRefPtr<CefResponse> response,
+ int64& response_length,
+ CefString& redirectUrl) override {
+ EXPECT_IO_THREAD();
+ EXPECT_EQ(test_mode_, BLOCK_READ);
+
+ get_response_headers_ct_++;
+
+ response->SetStatus(200);
+ response->SetStatusText("OK");
+ response->SetMimeType(mime_type_);
+ response_length = 100;
+ }
+
+ bool Read(void* data_out,
+ int bytes_to_read,
+ int& bytes_read,
+ CefRefPtr<CefResourceReadCallback> callback) override {
+ EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO));
+ EXPECT_EQ(test_mode_, BLOCK_READ);
+
+ read_ct_++;
+
+ // Never release or execute this callback.
+ incomplete_read_callback_ = callback;
+ bytes_read = 0;
+ return true;
+ }
+
+ bool ReadResponse(void* data_out,
+ int bytes_to_read,
+ int& bytes_read,
+ CefRefPtr<CefCallback> callback) override {
+ EXPECT_TRUE(false); // Not reached.
+ bytes_read = -2;
+ return false;
+ }
+
+ void Cancel() override {
+ EXPECT_IO_THREAD();
+ cancel_ct_++;
+ }
+
+ private:
+ const TestMode test_mode_;
+ const std::string mime_type_;
+ base::OnceClosure destroy_callback_;
+
+ int open_ct_ = 0;
+ int get_response_headers_ct_ = 0;
+ int read_ct_ = 0;
+ int cancel_ct_ = 0;
+
+ CefRefPtr<CefCallback> incomplete_open_callback_;
+ CefRefPtr<CefResourceReadCallback> incomplete_read_callback_;
+
+ IMPLEMENT_REFCOUNTING(IncompleteResourceHandler);
+ DISALLOW_COPY_AND_ASSIGN(IncompleteResourceHandler);
+};
+
+class BasicResponseTest : public TestHandler {
+ public:
+ enum TestMode {
+ // Normal load, nothing fancy.
+ LOAD,
+
+ // Close the browser in OnAfterCreated to verify destruction handling of
+ // uninitialized requests.
+ ABORT_AFTER_CREATED,
+
+ // Close the browser in OnBeforeBrowse to verify destruction handling of
+ // uninitialized requests.
+ ABORT_BEFORE_BROWSE,
+
+ // Don't continue from OnBeforeResourceLoad, then close the browser to
+ // verify destruction handling of in-progress requests.
+ INCOMPLETE_BEFORE_RESOURCE_LOAD,
+
+ // Modify the request (add headers) in OnBeforeResourceLoad.
+ MODIFY_BEFORE_RESOURCE_LOAD,
+
+ // Redirect the request (change the URL) in OnBeforeResourceLoad.
+ REDIRECT_BEFORE_RESOURCE_LOAD,
+
+ // Return a CefResourceHandler from GetResourceHandler that continues
+ // immediately by using the callback object instead of the return value.
+ IMMEDIATE_REQUEST_HANDLER_OPEN,
+ IMMEDIATE_REQUEST_HANDLER_READ,
+ IMMEDIATE_REQUEST_HANDLER_ALL,
+
+ // Return a CefResourceHandler from GetResourceHandler that continues with
+ // a delay by using the callback object.
+ DELAYED_REQUEST_HANDLER_OPEN,
+ DELAYED_REQUEST_HANDLER_READ,
+ DELAYED_REQUEST_HANDLER_ALL,
+
+ // Return a CefResourceHandler from GetResourceHandler that never completes,
+ // then close the browser to verify destruction handling of in-progress
+ // requests.
+ INCOMPLETE_REQUEST_HANDLER_OPEN,
+ INCOMPLETE_REQUEST_HANDLER_READ,
+
+ // Redirect the request using a CefResourceHandler returned from
+ // GetResourceHandler.
+ REDIRECT_REQUEST_HANDLER,
+
+ // Redirect the request (change the URL) an additional time in
+ // OnResourceRedirect after using a CefResourceHandler returned from
+ // GetResourceHandler for the first redirect.
+ REDIRECT_RESOURCE_REDIRECT,
+
+ // Redirect the request (change the URL) in OnResourceResponse.
+ REDIRECT_RESOURCE_RESPONSE,
+
+ // Restart the request (add headers) in OnResourceResponse.
+ RESTART_RESOURCE_RESPONSE,
+ };
+
+ // If |custom_scheme| is true all requests will use a custom scheme.
+ // If |unhandled| is true the final request (after any redirects) will be
+ // unhandled, meaning that default handling is disabled and GetResourceHandler
+ // returns null.
+ BasicResponseTest(TestMode mode, bool custom_scheme, bool unhandled)
+ : mode_(mode), custom_scheme_(custom_scheme), unhandled_(unhandled) {}
+
+ void RunTest() override {
+ CreateBrowser(GetStartupURL());
+ SetTestTimeout();
+ }
+
+ void OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
+ EXPECT_UI_THREAD();
+ TestHandler::OnAfterCreated(browser);
+
+ if (mode_ == ABORT_AFTER_CREATED) {
+ SetSignalCompletionWhenAllBrowsersClose(false);
+ CloseBrowser(browser, false);
+ }
+ }
+
+ void OnBeforeClose(CefRefPtr<CefBrowser> browser) override {
+ EXPECT_UI_THREAD();
+ TestHandler::OnBeforeClose(browser);
+
+ if (IsAborted()) {
+ DestroyTest();
+ }
+ }
+
+ bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ bool user_gesture,
+ bool is_redirect) override {
+ EXPECT_UI_THREAD();
+ if (browser_id_ == 0) {
+ // This is the first callback that provides a browser ID.
+ browser_id_ = browser->GetIdentifier();
+ EXPECT_GT(browser_id_, 0);
+ } else {
+ EXPECT_EQ(browser_id_, browser->GetIdentifier());
+ }
+ EXPECT_TRUE(frame->IsMain());
+
+ if (IsChromeRuntimeEnabled()) {
+ // With the Chrome runtime this is true on initial navigation via
+ // chrome::AddTabAt() and also true for clicked links.
+ EXPECT_TRUE(user_gesture);
+ } else {
+ EXPECT_FALSE(user_gesture);
+ }
+ if (on_before_browse_ct_ == 0 || mode_ == RESTART_RESOURCE_RESPONSE) {
+ EXPECT_FALSE(is_redirect) << on_before_browse_ct_;
+ } else {
+ EXPECT_TRUE(is_redirect) << on_before_browse_ct_;
+ }
+
+ on_before_browse_ct_++;
+
+ VerifyState(kOnBeforeBrowse, request, nullptr);
+
+ if (mode_ == ABORT_BEFORE_BROWSE) {
+ SetSignalCompletionWhenAllBrowsersClose(false);
+ CloseBrowser(browser, false);
+ }
+
+ return false;
+ }
+
+ CefRefPtr<CefResourceRequestHandler> GetResourceRequestHandler(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ bool is_navigation,
+ bool is_download,
+ const CefString& request_initiator,
+ bool& disable_default_handling) override {
+ EXPECT_IO_THREAD();
+ EXPECT_EQ(browser_id_, browser->GetIdentifier());
+ EXPECT_TRUE(frame->IsMain());
+
+ if (request_id_ == 0U) {
+ // This is the first callback that provides a request ID.
+ request_id_ = request->GetIdentifier();
+ EXPECT_GT(request_id_, 0U);
+ }
+
+ VerifyState(kGetResourceRequestHandler, request, nullptr);
+
+ EXPECT_TRUE(is_navigation);
+ EXPECT_FALSE(is_download);
+ EXPECT_STREQ("null", request_initiator.ToString().c_str());
+
+ // Check expected default value.
+ if (custom_scheme_) {
+ // There is no default handling for custom schemes.
+ EXPECT_TRUE(disable_default_handling);
+ } else {
+ EXPECT_FALSE(disable_default_handling);
+ // If |unhandled_| is true then we don't want default handling of requests
+ // (e.g. attempts to resolve over the network).
+ disable_default_handling = unhandled_;
+ }
+
+ get_resource_request_handler_ct_++;
+
+ return this;
+ }
+
+ CefRefPtr<CefCookieAccessFilter> GetCookieAccessFilter(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request) override {
+ EXPECT_IO_THREAD();
+ EXPECT_EQ(browser_id_, browser->GetIdentifier());
+ EXPECT_TRUE(frame->IsMain());
+
+ VerifyState(kGetCookieAccessFilter, request, nullptr);
+
+ get_cookie_access_filter_ct_++;
+
+ return nullptr;
+ }
+
+ cef_return_value_t OnBeforeResourceLoad(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefCallback> callback) override {
+ EXPECT_IO_THREAD();
+ if (IsChromeRuntimeEnabled() && request->GetResourceType() == RT_FAVICON) {
+ // Ignore favicon requests.
+ return RV_CANCEL;
+ }
+
+ EXPECT_EQ(browser_id_, browser->GetIdentifier());
+ EXPECT_TRUE(frame->IsMain());
+
+ VerifyState(kOnBeforeResourceLoad, request, nullptr);
+
+ on_before_resource_load_ct_++;
+
+ if (mode_ == INCOMPLETE_BEFORE_RESOURCE_LOAD) {
+ incomplete_callback_ = callback;
+
+ // Close the browser asynchronously to complete the test.
+ CloseBrowserAsync();
+ return RV_CONTINUE_ASYNC;
+ }
+
+ if (mode_ == MODIFY_BEFORE_RESOURCE_LOAD) {
+ // Expect this data in the request for future callbacks.
+ SetCustomHeader(request);
+ } else if (mode_ == REDIRECT_BEFORE_RESOURCE_LOAD) {
+ // Redirect to this URL.
+ request->SetURL(GetURL(RESULT_HTML));
+ }
+
+ // Other continuation modes are tested by
+ // ResourceRequestHandlerTest.BeforeResourceLoad*.
+ return RV_CONTINUE;
+ }
+
+ CefRefPtr<CefResourceHandler> GetResourceHandler(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request) override {
+ EXPECT_IO_THREAD();
+ EXPECT_EQ(browser_id_, browser->GetIdentifier());
+ EXPECT_TRUE(frame->IsMain());
+
+ VerifyState(kGetResourceHandler, request, nullptr);
+
+ get_resource_handler_ct_++;
+
+ if (IsIncompleteRequestHandler()) {
+ // Close the browser asynchronously to complete the test.
+ CloseBrowserAsync();
+ return GetIncompleteResource();
+ }
+
+ const std::string& url = request->GetURL();
+ if (url == GetURL(RESULT_HTML) && mode_ == RESTART_RESOURCE_RESPONSE) {
+ if (get_resource_handler_ct_ == 1) {
+ // First request that will be restarted after response.
+ return GetOKResource();
+ } else {
+ // Restarted request.
+ if (unhandled_) {
+ return nullptr;
+ }
+ return GetOKResource();
+ }
+ } else if (url == GetURL(RESULT_HTML)) {
+ if (unhandled_) {
+ return nullptr;
+ }
+ return GetOKResource();
+ } else if (url == GetURL(REDIRECT_HTML) &&
+ mode_ == REDIRECT_RESOURCE_RESPONSE) {
+ if (get_resource_handler_ct_ == 1) {
+ // First request that will be redirected after response.
+ return GetOKResource();
+ } else {
+ // Redirected request.
+ if (unhandled_) {
+ return nullptr;
+ }
+ return GetOKResource();
+ }
+ } else if (url == GetURL(REDIRECT_HTML) || url == GetURL(REDIRECT2_HTML)) {
+ std::string redirect_url;
+ if (mode_ == REDIRECT_REQUEST_HANDLER ||
+ mode_ == REDIRECT_RESOURCE_RESPONSE) {
+ EXPECT_STREQ(GetURL(REDIRECT_HTML), url.c_str());
+ redirect_url = GetURL(RESULT_HTML);
+ } else if (mode_ == REDIRECT_RESOURCE_REDIRECT) {
+ EXPECT_STREQ(GetURL(REDIRECT2_HTML), url.c_str());
+ redirect_url = GetURL(REDIRECT_HTML);
+ } else {
+ NOTREACHED();
+ }
+
+ return GetRedirectResource(redirect_url);
+ } else {
+ NOTREACHED();
+ return nullptr;
+ }
+ }
+
+ void OnResourceRedirect(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response,
+ CefString& new_url) override {
+ EXPECT_IO_THREAD();
+ EXPECT_EQ(browser_id_, browser->GetIdentifier());
+ EXPECT_TRUE(frame->IsMain());
+
+ VerifyState(kOnResourceRedirect, request, response);
+
+ if (mode_ == REDIRECT_REQUEST_HANDLER ||
+ mode_ == REDIRECT_RESOURCE_RESPONSE) {
+ // The URL redirected to from GetResourceHandler or OnResourceResponse.
+ EXPECT_STREQ(GetURL(RESULT_HTML), new_url.ToString().c_str());
+ } else if (mode_ == REDIRECT_RESOURCE_REDIRECT) {
+ if (on_resource_redirect_ct_ == 0) {
+ // The URL redirected to from GetResourceHandler.
+ EXPECT_STREQ(GetURL(REDIRECT_HTML), new_url.ToString().c_str());
+ // Redirect again.
+ new_url = GetURL(RESULT_HTML);
+ } else {
+ NOTREACHED();
+ }
+ }
+
+ on_resource_redirect_ct_++;
+ }
+
+ bool OnResourceResponse(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response) override {
+ EXPECT_IO_THREAD();
+ EXPECT_EQ(browser_id_, browser->GetIdentifier());
+ EXPECT_TRUE(frame->IsMain());
+
+ VerifyState(kOnResourceResponse, request, response);
+
+ on_resource_response_ct_++;
+
+ if (on_resource_response_ct_ == 1) {
+ if (mode_ == REDIRECT_RESOURCE_RESPONSE) {
+ // Redirect the request to this URL.
+ request->SetURL(GetURL(RESULT_HTML));
+ return true;
+ } else if (mode_ == RESTART_RESOURCE_RESPONSE) {
+ // Restart the request loading this data.
+ SetCustomHeader(request);
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ CefRefPtr<CefResponseFilter> GetResourceResponseFilter(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response) override {
+ EXPECT_IO_THREAD();
+ EXPECT_EQ(browser_id_, browser->GetIdentifier());
+ EXPECT_TRUE(frame->IsMain());
+
+ VerifyState(kGetResourceResponseFilter, request, response);
+
+ get_resource_response_filter_ct_++;
+
+ return nullptr;
+ }
+
+ void OnResourceLoadComplete(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response,
+ URLRequestStatus status,
+ int64 received_content_length) override {
+ EXPECT_IO_THREAD();
+
+ if (IsChromeRuntimeEnabled() && request->GetResourceType() == RT_FAVICON) {
+ // Ignore favicon requests.
+ return;
+ }
+
+ EXPECT_EQ(browser_id_, browser->GetIdentifier());
+ EXPECT_TRUE(frame->IsMain());
+
+ VerifyState(kOnResourceLoadComplete, request, response);
+
+ if (unhandled_ || IsIncomplete() || (IsAborted() && status == UR_FAILED)) {
+ EXPECT_EQ(UR_FAILED, status);
+ EXPECT_EQ(0, received_content_length);
+ } else {
+ EXPECT_EQ(UR_SUCCESS, status);
+ EXPECT_EQ(static_cast<int64>(GetResponseBody().length()),
+ received_content_length);
+ }
+
+ on_resource_load_complete_ct_++;
+
+ if (IsIncomplete()) {
+ MaybeDestroyTest(false);
+ }
+ }
+
+ void OnProtocolExecution(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ bool& allow_os_execution) override {
+ EXPECT_IO_THREAD();
+ EXPECT_EQ(browser_id_, browser->GetIdentifier());
+ EXPECT_TRUE(frame->IsMain());
+
+ EXPECT_TRUE(custom_scheme_);
+ EXPECT_TRUE(unhandled_);
+
+ // Check expected default value.
+ EXPECT_FALSE(allow_os_execution);
+
+ VerifyState(kOnProtocolExecution, request, nullptr);
+ on_protocol_execution_ct_++;
+ }
+
+ void OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int httpStatusCode) override {
+ EXPECT_UI_THREAD();
+ EXPECT_EQ(browser_id_, browser->GetIdentifier());
+ EXPECT_TRUE(frame->IsMain());
+
+ if (unhandled_) {
+ if (IsRedirect()) {
+ EXPECT_EQ(httpStatusCode, 307);
+ } else {
+ EXPECT_EQ(httpStatusCode, 0);
+ }
+ } else {
+ EXPECT_EQ(httpStatusCode, 200);
+ }
+
+ on_load_end_ct_++;
+
+ TestHandler::OnLoadEnd(browser, frame, httpStatusCode);
+ DestroyTest();
+ }
+
+ void DestroyTest() override {
+ if (mode_ == RESTART_RESOURCE_RESPONSE) {
+ EXPECT_EQ(1, on_before_browse_ct_);
+ EXPECT_EQ(2, get_resource_request_handler_ct_);
+ EXPECT_EQ(2, get_cookie_access_filter_ct_);
+ EXPECT_EQ(2, on_before_resource_load_ct_);
+ EXPECT_EQ(2, get_resource_handler_ct_);
+ EXPECT_EQ(0, on_resource_redirect_ct_);
+ // Unhandled requests won't see a call to GetResourceResponseFilter or
+ // OnResourceResponse. In this case we're restarting from inside
+ // OnResourceResponse.
+ if (unhandled_) {
+ EXPECT_EQ(0, get_resource_response_filter_ct_);
+ EXPECT_EQ(1, on_resource_response_ct_);
+ } else {
+ EXPECT_EQ(1, get_resource_response_filter_ct_);
+ EXPECT_EQ(2, on_resource_response_ct_);
+ }
+ } else if (IsLoad()) {
+ EXPECT_EQ(1, on_before_browse_ct_);
+ EXPECT_EQ(1, get_resource_request_handler_ct_);
+ EXPECT_EQ(1, get_cookie_access_filter_ct_);
+ EXPECT_EQ(1, on_before_resource_load_ct_);
+ EXPECT_EQ(1, get_resource_handler_ct_);
+ EXPECT_EQ(0, on_resource_redirect_ct_);
+
+ // Unhandled requests won't see a call to GetResourceResponseFilter
+ // or OnResourceResponse.
+ if (unhandled_) {
+ EXPECT_EQ(0, get_resource_response_filter_ct_);
+ EXPECT_EQ(0, on_resource_response_ct_);
+ } else {
+ EXPECT_EQ(1, get_resource_response_filter_ct_);
+ EXPECT_EQ(1, on_resource_response_ct_);
+ }
+ } else if (IsRedirect()) {
+ EXPECT_EQ(2, on_before_browse_ct_);
+ EXPECT_EQ(2, get_resource_request_handler_ct_);
+ EXPECT_EQ(2, get_cookie_access_filter_ct_);
+ EXPECT_EQ(2, on_before_resource_load_ct_);
+ if (mode_ == REDIRECT_BEFORE_RESOURCE_LOAD) {
+ EXPECT_EQ(1, get_resource_handler_ct_);
+ } else {
+ EXPECT_EQ(2, get_resource_handler_ct_);
+ }
+ EXPECT_EQ(1, on_resource_redirect_ct_);
+
+ // Unhandled requests won't see a call to GetResourceResponseFilter.
+ if (unhandled_) {
+ EXPECT_EQ(0, get_resource_response_filter_ct_);
+ } else {
+ EXPECT_EQ(1, get_resource_response_filter_ct_);
+ }
+
+ // Unhandled requests won't see a call to OnResourceResponse.
+ if (mode_ == REDIRECT_RESOURCE_RESPONSE) {
+ // In this case we're redirecting from inside OnResourceResponse.
+ if (unhandled_) {
+ EXPECT_EQ(1, on_resource_response_ct_);
+ } else {
+ EXPECT_EQ(2, on_resource_response_ct_);
+ }
+ } else {
+ if (unhandled_) {
+ EXPECT_EQ(0, on_resource_response_ct_);
+ } else {
+ EXPECT_EQ(1, on_resource_response_ct_);
+ }
+ }
+ } else if (IsIncomplete()) {
+ EXPECT_EQ(1, on_before_browse_ct_);
+ EXPECT_EQ(1, get_resource_request_handler_ct_);
+ EXPECT_EQ(1, get_cookie_access_filter_ct_);
+ EXPECT_EQ(1, on_before_resource_load_ct_);
+
+ if (IsIncompleteRequestHandler()) {
+ EXPECT_EQ(1, get_resource_handler_ct_);
+ } else {
+ EXPECT_EQ(0, get_resource_handler_ct_);
+ }
+
+ EXPECT_EQ(0, on_resource_redirect_ct_);
+
+ if (mode_ == INCOMPLETE_REQUEST_HANDLER_READ) {
+ EXPECT_EQ(1, get_resource_response_filter_ct_);
+ EXPECT_EQ(1, on_resource_response_ct_);
+ } else {
+ EXPECT_EQ(0, get_resource_response_filter_ct_);
+ EXPECT_EQ(0, on_resource_response_ct_);
+ }
+ } else if (IsAborted()) {
+ EXPECT_EQ(1, on_before_browse_ct_);
+ // The callbacks executed may vary based on timing.
+ EXPECT_NEAR(0, get_resource_request_handler_ct_, 1);
+ EXPECT_NEAR(0, get_cookie_access_filter_ct_, 1);
+ EXPECT_NEAR(0, on_before_resource_load_ct_, 1);
+ EXPECT_NEAR(0, get_resource_handler_ct_, 1);
+ EXPECT_NEAR(0, get_resource_response_filter_ct_, 1);
+ EXPECT_NEAR(0, on_resource_response_ct_, 1);
+ EXPECT_EQ(0, on_resource_redirect_ct_);
+ } else {
+ NOTREACHED();
+ }
+
+ if (IsAborted()) {
+ // The callbacks executed may vary based on timing.
+ EXPECT_NEAR(0, on_load_end_ct_, 1);
+ EXPECT_NEAR(resource_handler_created_ct_, resource_handler_destroyed_ct_,
+ 1);
+ EXPECT_NEAR(0, on_resource_load_complete_ct_, 1);
+ } else {
+ EXPECT_EQ(resource_handler_created_ct_, resource_handler_destroyed_ct_);
+ EXPECT_EQ(1, on_resource_load_complete_ct_);
+ }
+
+ if (IsIncomplete()) {
+ EXPECT_EQ(0, on_load_end_ct_);
+ } else if (!IsAborted()) {
+ EXPECT_EQ(1, on_load_end_ct_);
+ }
+
+ if (custom_scheme_ && unhandled_ && !(IsIncomplete() || IsAborted())) {
+ EXPECT_EQ(1, on_protocol_execution_ct_);
+ } else if (IsAborted()) {
+ // The callbacks executed may vary based on timing.
+ EXPECT_NEAR(0, on_protocol_execution_ct_, 1);
+ } else {
+ EXPECT_EQ(0, on_protocol_execution_ct_);
+ }
+
+ TestHandler::DestroyTest();
+
+ if (!SignalCompletionWhenAllBrowsersClose()) {
+ // Complete asynchronously so the call stack has a chance to unwind.
+ CefPostTask(TID_UI,
+ base::BindOnce(&BasicResponseTest::TestComplete, this));
+ }
+ }
+
+ private:
+ enum TestUrl {
+ RESULT_HTML,
+ REDIRECT_HTML,
+ REDIRECT2_HTML,
+ };
+
+ const char* GetURL(TestUrl url) const {
+ if (custom_scheme_) {
+ if (url == RESULT_HTML) {
+ return "rrhcustom://test.com/result.html";
+ }
+ if (url == REDIRECT_HTML) {
+ return "rrhcustom://test.com/redirect.html";
+ }
+ if (url == REDIRECT2_HTML) {
+ return "rrhcustom://test.com/redirect2.html";
+ }
+ } else {
+ if (url == RESULT_HTML) {
+ return "http://test.com/result.html";
+ }
+ if (url == REDIRECT_HTML) {
+ return "http://test.com/redirect.html";
+ }
+ if (url == REDIRECT2_HTML) {
+ return "http://test.com/redirect2.html";
+ }
+ }
+
+ NOTREACHED();
+ return "";
+ }
+
+ const char* GetStartupURL() const {
+ if (IsLoad() || IsIncomplete() || IsAborted()) {
+ return GetURL(RESULT_HTML);
+ } else if (mode_ == REDIRECT_RESOURCE_REDIRECT) {
+ return GetURL(REDIRECT2_HTML);
+ } else if (IsRedirect()) {
+ return GetURL(REDIRECT_HTML);
+ }
+
+ NOTREACHED();
+ return "";
+ }
+
+ std::string GetResponseBody() const {
+ return "<html><body>Response</body></html>";
+ }
+ std::string GetRedirectBody() const {
+ return "<html><body>Redirect</body></html>";
+ }
+
+ base::OnceClosure GetResourceDestroyCallback() {
+ resource_handler_created_ct_++;
+ return base::BindOnce(&BasicResponseTest::MaybeDestroyTest, this, true);
+ }
+
+ bool GetCallbackResourceHandlerMode(CallbackResourceHandler::Mode& mode) {
+ switch (mode_) {
+ case IMMEDIATE_REQUEST_HANDLER_OPEN:
+ mode = CallbackResourceHandler::IMMEDIATE_OPEN;
+ return true;
+ case IMMEDIATE_REQUEST_HANDLER_READ:
+ mode = CallbackResourceHandler::IMMEDIATE_READ;
+ return true;
+ case IMMEDIATE_REQUEST_HANDLER_ALL:
+ mode = CallbackResourceHandler::IMMEDIATE_ALL;
+ return true;
+ case DELAYED_REQUEST_HANDLER_OPEN:
+ mode = CallbackResourceHandler::DELAYED_OPEN;
+ return true;
+ case DELAYED_REQUEST_HANDLER_READ:
+ mode = CallbackResourceHandler::DELAYED_READ;
+ return true;
+ case DELAYED_REQUEST_HANDLER_ALL:
+ mode = CallbackResourceHandler::DELAYED_ALL;
+ return true;
+ default:
+ break;
+ }
+ return false;
+ }
+
+ CefRefPtr<CefResourceHandler> GetResource(int status_code,
+ const CefString& status_text,
+ const CefString& mime_type,
+ CefResponse::HeaderMap header_map,
+ const std::string& body) {
+ CefRefPtr<CefStreamReader> stream = CefStreamReader::CreateForData(
+ const_cast<char*>(body.c_str()), body.size());
+
+ CallbackResourceHandler::Mode handler_mode;
+ if (GetCallbackResourceHandlerMode(handler_mode)) {
+ return new CallbackResourceHandler(handler_mode, status_code, status_text,
+ mime_type, header_map, stream,
+ GetResourceDestroyCallback());
+ }
+
+ return new NormalResourceHandler(status_code, status_text, mime_type,
+ header_map, stream,
+ GetResourceDestroyCallback());
+ }
+
+ CefRefPtr<CefResourceHandler> GetOKResource() {
+ return GetResource(200, "OK", "text/html", CefResponse::HeaderMap(),
+ GetResponseBody());
+ }
+
+ CefRefPtr<CefResourceHandler> GetRedirectResource(
+ const std::string& redirect_url) {
+ CefResponse::HeaderMap headerMap;
+ headerMap.insert(std::make_pair("Location", redirect_url));
+
+ return GetResource(307, "Temporary Redirect", "text/html", headerMap,
+ GetRedirectBody());
+ }
+
+ CefRefPtr<CefResourceHandler> GetIncompleteResource() {
+ if (TestOldResourceAPI()) {
+ return new IncompleteResourceHandlerOld(
+ mode_ == INCOMPLETE_REQUEST_HANDLER_OPEN
+ ? IncompleteResourceHandlerOld::BLOCK_PROCESS_REQUEST
+ : IncompleteResourceHandlerOld::BLOCK_READ_RESPONSE,
+ "text/html", GetResourceDestroyCallback());
+ }
+
+ return new IncompleteResourceHandler(
+ mode_ == INCOMPLETE_REQUEST_HANDLER_OPEN
+ ? IncompleteResourceHandler::BLOCK_OPEN
+ : IncompleteResourceHandler::BLOCK_READ,
+ "text/html", GetResourceDestroyCallback());
+ }
+
+ bool IsLoad() const {
+ return mode_ == LOAD || mode_ == MODIFY_BEFORE_RESOURCE_LOAD ||
+ mode_ == RESTART_RESOURCE_RESPONSE ||
+ mode_ == IMMEDIATE_REQUEST_HANDLER_OPEN ||
+ mode_ == IMMEDIATE_REQUEST_HANDLER_READ ||
+ mode_ == IMMEDIATE_REQUEST_HANDLER_ALL ||
+ mode_ == DELAYED_REQUEST_HANDLER_OPEN ||
+ mode_ == DELAYED_REQUEST_HANDLER_READ ||
+ mode_ == DELAYED_REQUEST_HANDLER_ALL;
+ }
+
+ bool IsIncompleteRequestHandler() const {
+ return mode_ == INCOMPLETE_REQUEST_HANDLER_OPEN ||
+ mode_ == INCOMPLETE_REQUEST_HANDLER_READ;
+ }
+
+ bool IsIncomplete() const {
+ return mode_ == INCOMPLETE_BEFORE_RESOURCE_LOAD ||
+ IsIncompleteRequestHandler();
+ }
+
+ bool IsAborted() const {
+ return mode_ == ABORT_AFTER_CREATED || mode_ == ABORT_BEFORE_BROWSE;
+ }
+
+ bool IsRedirect() const {
+ return mode_ == REDIRECT_BEFORE_RESOURCE_LOAD ||
+ mode_ == REDIRECT_REQUEST_HANDLER ||
+ mode_ == REDIRECT_RESOURCE_REDIRECT ||
+ mode_ == REDIRECT_RESOURCE_RESPONSE;
+ }
+
+ static void SetCustomHeader(CefRefPtr<CefRequest> request) {
+ EXPECT_FALSE(request->IsReadOnly());
+ request->SetHeaderByName("X-Custom-Header", "value", false);
+ }
+
+ static std::string GetCustomHeader(CefRefPtr<CefRequest> request) {
+ return request->GetHeaderByName("X-Custom-Header");
+ }
+
+ // Resource-related callbacks.
+ enum Callback {
+ kOnBeforeBrowse,
+ kGetResourceRequestHandler,
+ kGetCookieAccessFilter,
+ kOnBeforeResourceLoad,
+ kGetResourceHandler,
+ kOnResourceRedirect,
+ kOnResourceResponse,
+ kGetResourceResponseFilter,
+ kOnResourceLoadComplete,
+ kOnProtocolExecution,
+ };
+
+ bool ShouldHaveResponse(Callback callback) const {
+ return callback >= kOnResourceRedirect &&
+ callback <= kOnResourceLoadComplete;
+ }
+
+ bool ShouldHaveWritableRequest(Callback callback) const {
+ return callback == kOnBeforeResourceLoad || callback == kOnResourceResponse;
+ }
+
+ void VerifyState(Callback callback,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response) const {
+ EXPECT_TRUE(request) << callback;
+
+ if (ShouldHaveResponse(callback)) {
+ EXPECT_TRUE(response) << callback;
+ EXPECT_TRUE(response->IsReadOnly()) << callback;
+ } else {
+ EXPECT_FALSE(response) << callback;
+ }
+
+ if (ShouldHaveWritableRequest(callback)) {
+ EXPECT_FALSE(request->IsReadOnly()) << callback;
+ } else {
+ EXPECT_TRUE(request->IsReadOnly()) << callback;
+ }
+
+ if (callback == kOnBeforeBrowse) {
+ // Browser-side navigation no longer exposes the actual request
+ // information.
+ EXPECT_EQ(0U, request->GetIdentifier()) << callback;
+ } else {
+ // All resource-related callbacks share the same request ID.
+ EXPECT_EQ(request_id_, request->GetIdentifier()) << callback;
+ }
+
+ if (IsLoad() || IsIncomplete() || IsAborted()) {
+ EXPECT_STREQ("GET", request->GetMethod().ToString().c_str()) << callback;
+ EXPECT_STREQ(GetURL(RESULT_HTML), request->GetURL().ToString().c_str())
+ << callback;
+
+ // Expect the header for all callbacks following the callback that
+ // initially sets it.
+ const std::string& custom_header = GetCustomHeader(request);
+ if ((mode_ == RESTART_RESOURCE_RESPONSE &&
+ on_resource_response_ct_ > 0) ||
+ (mode_ == MODIFY_BEFORE_RESOURCE_LOAD &&
+ on_before_resource_load_ct_ > 0)) {
+ EXPECT_STREQ("value", custom_header.c_str()) << callback;
+ } else {
+ EXPECT_STREQ("", custom_header.c_str()) << callback;
+ }
+
+ if (response) {
+ VerifyOKResponse(callback, response);
+ }
+ } else if (IsRedirect()) {
+ EXPECT_STREQ("GET", request->GetMethod().ToString().c_str()) << callback;
+ if (on_before_browse_ct_ == 1) {
+ // Before the redirect.
+ EXPECT_STREQ(GetStartupURL(), request->GetURL().ToString().c_str())
+ << callback;
+ } else if (on_before_browse_ct_ == 2) {
+ // After the redirect.
+ EXPECT_STREQ(GetURL(RESULT_HTML), request->GetURL().ToString().c_str())
+ << callback;
+ } else {
+ NOTREACHED() << callback;
+ }
+
+ if (response) {
+ if (callback == kOnResourceRedirect) {
+ // Before the redirect.
+ VerifyRedirectResponse(callback, response);
+ } else {
+ // After the redirect.
+ VerifyOKResponse(callback, response);
+ }
+ }
+ } else {
+ NOTREACHED() << callback;
+ }
+ }
+
+ void VerifyOKResponse(Callback callback,
+ CefRefPtr<CefResponse> response) const {
+ const auto error_code = response->GetError();
+
+ // True for the first response in cases where we're redirecting/restarting
+ // from inside OnResourceResponse (e.g. the first response always succeeds).
+ const bool override_unhandled = unhandled_ &&
+ (mode_ == REDIRECT_RESOURCE_RESPONSE ||
+ mode_ == RESTART_RESOURCE_RESPONSE) &&
+ get_resource_handler_ct_ == 1;
+
+ // True for tests where the request will be incomplete and never receive a
+ // response.
+ const bool incomplete_unhandled =
+ (mode_ == INCOMPLETE_BEFORE_RESOURCE_LOAD ||
+ mode_ == INCOMPLETE_REQUEST_HANDLER_OPEN ||
+ (IsAborted() && !custom_scheme_ && error_code != ERR_NONE));
+
+ if ((unhandled_ && !override_unhandled) || incomplete_unhandled) {
+ EXPECT_TRUE(ERR_ABORTED == error_code ||
+ ERR_UNKNOWN_URL_SCHEME == error_code)
+ << callback << error_code;
+ EXPECT_EQ(0, response->GetStatus()) << callback;
+ EXPECT_STREQ("", response->GetStatusText().ToString().c_str())
+ << callback;
+ EXPECT_STREQ("", response->GetURL().ToString().c_str()) << callback;
+ EXPECT_STREQ("", response->GetMimeType().ToString().c_str()) << callback;
+ EXPECT_STREQ("", response->GetCharset().ToString().c_str()) << callback;
+ } else {
+ if ((mode_ == INCOMPLETE_REQUEST_HANDLER_READ || IsAborted()) &&
+ callback == kOnResourceLoadComplete &&
+ response->GetError() != ERR_NONE) {
+ // We got a response, but we also got aborted.
+ EXPECT_EQ(ERR_ABORTED, response->GetError()) << callback;
+ } else {
+ EXPECT_EQ(ERR_NONE, response->GetError()) << callback;
+ }
+ EXPECT_EQ(200, response->GetStatus()) << callback;
+ EXPECT_STREQ("OK", response->GetStatusText().ToString().c_str())
+ << callback;
+ EXPECT_STREQ("", response->GetURL().ToString().c_str()) << callback;
+ EXPECT_STREQ("text/html", response->GetMimeType().ToString().c_str())
+ << callback;
+ EXPECT_STREQ("", response->GetCharset().ToString().c_str()) << callback;
+ }
+ }
+
+ void VerifyRedirectResponse(Callback callback,
+ CefRefPtr<CefResponse> response) const {
+ EXPECT_EQ(ERR_NONE, response->GetError()) << callback;
+ EXPECT_EQ(307, response->GetStatus()) << callback;
+ const std::string& status_text = response->GetStatusText();
+ EXPECT_TRUE(status_text == "Internal Redirect" ||
+ status_text == "Temporary Redirect")
+ << status_text << callback;
+ EXPECT_STREQ("", response->GetURL().ToString().c_str()) << callback;
+ EXPECT_STREQ("", response->GetMimeType().ToString().c_str()) << callback;
+ EXPECT_STREQ("", response->GetCharset().ToString().c_str()) << callback;
+ }
+
+ void CloseBrowserAsync() {
+ EXPECT_TRUE(IsIncomplete());
+ SetSignalCompletionWhenAllBrowsersClose(false);
+ CefPostDelayedTask(
+ TID_UI, base::BindOnce(&TestHandler::CloseBrowser, GetBrowser(), false),
+ 100);
+ }
+
+ void MaybeDestroyTest(bool from_handler) {
+ if (!CefCurrentlyOn(TID_UI)) {
+ CefPostTask(TID_UI, base::BindOnce(&BasicResponseTest::MaybeDestroyTest,
+ this, from_handler));
+ return;
+ }
+
+ if (from_handler) {
+ resource_handler_destroyed_ct_++;
+ }
+
+ bool destroy_test = false;
+ if (IsIncomplete()) {
+ // Destroy the test if we got OnResourceLoadComplete and either the
+ // resource handler will never complete or it was destroyed.
+ destroy_test =
+ on_resource_load_complete_ct_ > 0 &&
+ (!IsIncompleteRequestHandler() ||
+ resource_handler_destroyed_ct_ == resource_handler_created_ct_);
+ } else {
+ // Destroy the test if we got OnLoadEnd and the expected number of
+ // resource handlers were destroyed.
+ destroy_test = on_load_end_ct_ > 0 && resource_handler_destroyed_ct_ ==
+ resource_handler_created_ct_;
+ }
+
+ if (destroy_test) {
+ DestroyTest();
+ }
+ }
+
+ const TestMode mode_;
+ const bool custom_scheme_;
+ const bool unhandled_;
+
+ int browser_id_ = 0;
+ uint64 request_id_ = 0U;
+
+ int resource_handler_created_ct_ = 0;
+
+ int on_before_browse_ct_ = 0;
+ int on_load_end_ct_ = 0;
+
+ int get_resource_request_handler_ct_ = 0;
+ int on_before_resource_load_ct_ = 0;
+ int get_cookie_access_filter_ct_ = 0;
+ int get_resource_handler_ct_ = 0;
+ int on_resource_redirect_ct_ = 0;
+ int on_resource_response_ct_ = 0;
+ int get_resource_response_filter_ct_ = 0;
+ int on_resource_load_complete_ct_ = 0;
+ int on_protocol_execution_ct_ = 0;
+ int resource_handler_destroyed_ct_ = 0;
+
+ // Used with INCOMPLETE_BEFORE_RESOURCE_LOAD.
+ CefRefPtr<CefCallback> incomplete_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(BasicResponseTest);
+ IMPLEMENT_REFCOUNTING(BasicResponseTest);
+};
+
+} // namespace
+
+#define BASIC_TEST(name, test_mode, custom, unhandled) \
+ TEST(ResourceRequestHandlerTest, Basic##name) { \
+ CefRefPtr<BasicResponseTest> handler = new BasicResponseTest( \
+ BasicResponseTest::test_mode, custom, unhandled); \
+ handler->ExecuteTest(); \
+ ReleaseAndWaitForDestructor(handler); \
+ }
+
+#define BASIC_TEST_ALL_MODES(name, custom, unhandled) \
+ BASIC_TEST(name##Load, LOAD, custom, unhandled) \
+ BASIC_TEST(name##AbortAfterCreated, ABORT_AFTER_CREATED, custom, unhandled) \
+ BASIC_TEST(name##AbortBeforeBrowse, ABORT_BEFORE_BROWSE, custom, unhandled) \
+ BASIC_TEST(name##ModifyBeforeResourceLoad, MODIFY_BEFORE_RESOURCE_LOAD, \
+ custom, unhandled) \
+ BASIC_TEST(name##RedirectBeforeResourceLoad, REDIRECT_BEFORE_RESOURCE_LOAD, \
+ custom, unhandled) \
+ BASIC_TEST(name##RedirectRequestHandler, REDIRECT_REQUEST_HANDLER, custom, \
+ unhandled) \
+ BASIC_TEST(name##RedirectResourceRedirect, REDIRECT_RESOURCE_REDIRECT, \
+ custom, unhandled) \
+ BASIC_TEST(name##RedirectResourceResponse, REDIRECT_RESOURCE_RESPONSE, \
+ custom, unhandled) \
+ BASIC_TEST(name##RestartResourceResponse, RESTART_RESOURCE_RESPONSE, custom, \
+ unhandled)
+
+// Tests only supported in handled mode.
+#define BASIC_TEST_HANDLED_MODES(name, custom) \
+ BASIC_TEST(name##ImmediateRequestHandlerOpen, \
+ IMMEDIATE_REQUEST_HANDLER_OPEN, custom, false) \
+ BASIC_TEST(name##ImmediateRequestHandlerRead, \
+ IMMEDIATE_REQUEST_HANDLER_READ, custom, false) \
+ BASIC_TEST(name##ImmediateRequestHandlerAll, IMMEDIATE_REQUEST_HANDLER_ALL, \
+ custom, false) \
+ BASIC_TEST(name##DelayedRequestHandlerOpen, DELAYED_REQUEST_HANDLER_OPEN, \
+ custom, false) \
+ BASIC_TEST(name##DelayedRequestHandlerRead, DELAYED_REQUEST_HANDLER_READ, \
+ custom, false) \
+ BASIC_TEST(name##DelayedRequestHandlerAll, DELAYED_REQUEST_HANDLER_ALL, \
+ custom, false) \
+ BASIC_TEST(name##IncompleteBeforeResourceLoad, \
+ INCOMPLETE_BEFORE_RESOURCE_LOAD, custom, false) \
+ BASIC_TEST(name##IncompleteRequestHandlerOpen, \
+ INCOMPLETE_REQUEST_HANDLER_OPEN, custom, false) \
+ BASIC_TEST(name##IncompleteRequestHandlerRead, \
+ INCOMPLETE_REQUEST_HANDLER_READ, custom, false)
+
+BASIC_TEST_ALL_MODES(StandardHandled, false, false)
+BASIC_TEST_ALL_MODES(StandardUnhandled, false, true)
+BASIC_TEST_ALL_MODES(CustomHandled, true, false)
+BASIC_TEST_ALL_MODES(CustomUnhandled, true, true)
+
+BASIC_TEST_HANDLED_MODES(StandardHandled, false)
+BASIC_TEST_HANDLED_MODES(CustomHandled, true)
+
+namespace {
+
+const char kSubresourceProcessMsg[] = "SubresourceMsg";
+
+class SubresourceResponseTest : public RoutingTestHandler {
+ public:
+ enum TestMode {
+ // Normal load, nothing fancy.
+ LOAD,
+
+ // Don't continue from OnBeforeResourceLoad, then close the browser to
+ // verify destruction handling of in-progress requests.
+ INCOMPLETE_BEFORE_RESOURCE_LOAD,
+
+ // Modify the request (add headers) in OnBeforeResourceLoad.
+ MODIFY_BEFORE_RESOURCE_LOAD,
+
+ // Redirect the request (change the URL) in OnBeforeResourceLoad.
+ REDIRECT_BEFORE_RESOURCE_LOAD,
+
+ // Return a CefResourceHandler from GetResourceHandler that continues
+ // immediately by using the callback object instead of the return value.
+ IMMEDIATE_REQUEST_HANDLER_OPEN,
+ IMMEDIATE_REQUEST_HANDLER_READ,
+ IMMEDIATE_REQUEST_HANDLER_ALL,
+
+ // Return a CefResourceHandler from GetResourceHandler that continues with
+ // a delay by using the callback object.
+ DELAYED_REQUEST_HANDLER_OPEN,
+ DELAYED_REQUEST_HANDLER_READ,
+ DELAYED_REQUEST_HANDLER_ALL,
+
+ // Return a CefResourceHandler from GetResourceHandler that never completes,
+ // then close the browser to verify destruction handling of in-progress
+ // requests.
+ INCOMPLETE_REQUEST_HANDLER_OPEN,
+ INCOMPLETE_REQUEST_HANDLER_READ,
+
+ // Redirect the request using a CefResourceHandler returned from
+ // GetResourceHandler.
+ REDIRECT_REQUEST_HANDLER,
+
+ // Redirect the request (change the URL) an additional time in
+ // OnResourceRedirect after using a CefResourceHandler returned from
+ // GetResourceHandler for the first redirect.
+ REDIRECT_RESOURCE_REDIRECT,
+
+ // Redirect the request (change the URL) in OnResourceResponse.
+ REDIRECT_RESOURCE_RESPONSE,
+
+ // Restart the request (add headers) in OnResourceResponse.
+ RESTART_RESOURCE_RESPONSE,
+ };
+
+ // If |custom_scheme| is true all requests will use a custom scheme.
+ // If |unhandled| is true the final request (after any redirects) will be
+ // unhandled, meaning that default handling is disabled and GetResourceHandler
+ // returns null.
+ // If |subframe| is true the resource will be loaded in an iframe.
+ SubresourceResponseTest(TestMode mode,
+ bool custom_scheme,
+ bool unhandled,
+ bool subframe)
+ : mode_(mode),
+ custom_scheme_(custom_scheme),
+ unhandled_(unhandled),
+ subframe_(subframe) {}
+
+ void RunTest() override {
+ CreateBrowser(GetMainURL());
+ SetTestTimeout();
+ }
+
+ bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ bool user_gesture,
+ bool is_redirect) override {
+ EXPECT_UI_THREAD();
+ if (browser_id_ == 0) {
+ // This is the first callback that provides a browser ID.
+ browser_id_ = browser->GetIdentifier();
+ EXPECT_GT(browser_id_, 0);
+ } else {
+ EXPECT_EQ(browser_id_, browser->GetIdentifier());
+ }
+
+ const std::string& url = request->GetURL();
+ if (IsMainURL(url)) {
+ EXPECT_TRUE(frame->IsMain());
+ } else if (IsSubURL(url)) {
+ EXPECT_FALSE(frame->IsMain());
+ EXPECT_TRUE(subframe_);
+ } else {
+ EXPECT_FALSE(true); // Not reached.
+ }
+
+ if (IsChromeRuntimeEnabled() && IsMainURL(url)) {
+ // With the Chrome runtime this is true on initial navigation via
+ // chrome::AddTabAt() and also true for clicked links.
+ EXPECT_TRUE(user_gesture);
+ } else {
+ EXPECT_FALSE(user_gesture);
+ }
+
+ EXPECT_FALSE(is_redirect);
+
+ on_before_browse_ct_++;
+ return false;
+ }
+
+ CefRefPtr<CefResourceRequestHandler> GetResourceRequestHandler(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ bool is_navigation,
+ bool is_download,
+ const CefString& request_initiator,
+ bool& disable_default_handling) override {
+ EXPECT_IO_THREAD();
+ EXPECT_EQ(browser_id_, browser->GetIdentifier());
+
+ const std::string& url = request->GetURL();
+ if (IgnoreURL(url)) {
+ return nullptr;
+ }
+
+ const bool is_main_url = IsMainURL(url);
+ const bool is_sub_url = IsSubURL(url);
+
+ if (is_main_url) {
+ EXPECT_TRUE(frame->IsMain());
+ } else if (is_sub_url) {
+ EXPECT_FALSE(frame->IsMain());
+ EXPECT_TRUE(subframe_);
+ }
+
+ if (is_main_url || is_sub_url) {
+ // Track the frame ID that we'll expect for resource callbacks.
+ // Do this here instead of OnBeforeBrowse because OnBeforeBrowse may
+ // return -4 (kInvalidFrameId) for the initial navigation.
+ if (frame_id_ == 0) {
+ if (subframe_) {
+ if (is_sub_url) {
+ frame_id_ = frame->GetIdentifier();
+ }
+ } else {
+ frame_id_ = frame->GetIdentifier();
+ }
+ }
+ return this;
+ }
+
+ VerifyFrame(kGetResourceRequestHandler, frame);
+
+ if (request_id_ == 0U) {
+ // This is the first callback that provides a request ID.
+ request_id_ = request->GetIdentifier();
+ EXPECT_GT(request_id_, 0U);
+ }
+
+ VerifyState(kGetResourceRequestHandler, request, nullptr);
+
+ EXPECT_FALSE(is_navigation);
+ EXPECT_FALSE(is_download);
+ EXPECT_STREQ(GetOrigin(), request_initiator.ToString().c_str());
+
+ // Check expected default value.
+ if (custom_scheme_) {
+ // There is no default handling for custom schemes.
+ EXPECT_TRUE(disable_default_handling);
+ } else {
+ EXPECT_FALSE(disable_default_handling);
+ // If |unhandled_| is true then we don't want default handling of requests
+ // (e.g. attempts to resolve over the network).
+ disable_default_handling = unhandled_;
+ }
+
+ get_resource_request_handler_ct_++;
+
+ return this;
+ }
+
+ CefRefPtr<CefCookieAccessFilter> GetCookieAccessFilter(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request) override {
+ EXPECT_IO_THREAD();
+ EXPECT_EQ(browser_id_, browser->GetIdentifier());
+
+ const std::string& url = request->GetURL();
+ if (IgnoreURL(url)) {
+ return nullptr;
+ }
+
+ if (IsMainURL(url)) {
+ EXPECT_TRUE(frame->IsMain());
+ return nullptr;
+ } else if (IsSubURL(url)) {
+ EXPECT_FALSE(frame->IsMain());
+ EXPECT_TRUE(subframe_);
+ return nullptr;
+ }
+
+ VerifyFrame(kGetCookieAccessFilter, frame);
+
+ VerifyState(kGetCookieAccessFilter, request, nullptr);
+
+ get_cookie_access_filter_ct_++;
+
+ return nullptr;
+ }
+
+ cef_return_value_t OnBeforeResourceLoad(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefCallback> callback) override {
+ EXPECT_IO_THREAD();
+
+ if (IsChromeRuntimeEnabled() && request->GetResourceType() == RT_FAVICON) {
+ // Ignore favicon requests.
+ return RV_CANCEL;
+ }
+
+ EXPECT_EQ(browser_id_, browser->GetIdentifier());
+
+ if (IsMainURL(request->GetURL())) {
+ EXPECT_TRUE(frame->IsMain());
+ return RV_CONTINUE;
+ } else if (IsSubURL(request->GetURL())) {
+ EXPECT_FALSE(frame->IsMain());
+ EXPECT_TRUE(subframe_);
+ return RV_CONTINUE;
+ }
+
+ VerifyFrame(kOnBeforeResourceLoad, frame);
+
+ VerifyState(kOnBeforeResourceLoad, request, nullptr);
+
+ on_before_resource_load_ct_++;
+
+ if (mode_ == INCOMPLETE_BEFORE_RESOURCE_LOAD) {
+ incomplete_callback_ = callback;
+
+ // Close the browser asynchronously to complete the test.
+ CloseBrowserAsync();
+ return RV_CONTINUE_ASYNC;
+ }
+
+ if (mode_ == MODIFY_BEFORE_RESOURCE_LOAD) {
+ // Expect this data in the request for future callbacks.
+ SetCustomHeader(request);
+ } else if (mode_ == REDIRECT_BEFORE_RESOURCE_LOAD) {
+ // Redirect to this URL.
+ request->SetURL(GetURL(RESULT_JS));
+ }
+
+ // Other continuation modes are tested by
+ // ResourceRequestHandlerTest.BeforeResourceLoad*.
+ return RV_CONTINUE;
+ }
+
+ CefRefPtr<CefResourceHandler> GetResourceHandler(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request) override {
+ EXPECT_IO_THREAD();
+ EXPECT_EQ(browser_id_, browser->GetIdentifier());
+
+ if (IsMainURL(request->GetURL())) {
+ EXPECT_TRUE(frame->IsMain());
+ return GetMainResource();
+ } else if (IsSubURL(request->GetURL())) {
+ EXPECT_FALSE(frame->IsMain());
+ EXPECT_TRUE(subframe_);
+ return GetSubResource();
+ }
+
+ VerifyFrame(kGetResourceHandler, frame);
+
+ VerifyState(kGetResourceHandler, request, nullptr);
+
+ get_resource_handler_ct_++;
+
+ if (IsIncompleteRequestHandler()) {
+ // Close the browser asynchronously to complete the test.
+ CloseBrowserAsync();
+ return GetIncompleteResource();
+ }
+
+ const std::string& url = request->GetURL();
+ if (url == GetURL(RESULT_JS) && mode_ == RESTART_RESOURCE_RESPONSE) {
+ if (get_resource_handler_ct_ == 1) {
+ // First request that will be restarted after response.
+ return GetOKResource();
+ } else {
+ // Restarted request.
+ if (unhandled_) {
+ return nullptr;
+ }
+ return GetOKResource();
+ }
+ } else if (url == GetURL(RESULT_JS)) {
+ if (unhandled_) {
+ return nullptr;
+ }
+ return GetOKResource();
+ } else if (url == GetURL(REDIRECT_JS) &&
+ mode_ == REDIRECT_RESOURCE_RESPONSE) {
+ if (get_resource_handler_ct_ == 1) {
+ // First request that will be redirected after response.
+ return GetOKResource();
+ } else {
+ // Redirected request.
+ if (unhandled_) {
+ return nullptr;
+ }
+ return GetOKResource();
+ }
+ } else if (url == GetURL(REDIRECT_JS) || url == GetURL(REDIRECT2_JS)) {
+ std::string redirect_url;
+ if (mode_ == REDIRECT_REQUEST_HANDLER ||
+ mode_ == REDIRECT_RESOURCE_RESPONSE) {
+ EXPECT_STREQ(GetURL(REDIRECT_JS), url.c_str());
+ redirect_url = GetURL(RESULT_JS);
+ } else if (mode_ == REDIRECT_RESOURCE_REDIRECT) {
+ EXPECT_STREQ(GetURL(REDIRECT2_JS), url.c_str());
+ redirect_url = GetURL(REDIRECT_JS);
+ } else {
+ NOTREACHED();
+ }
+
+ return GetRedirectResource(redirect_url);
+ } else {
+ NOTREACHED();
+ return nullptr;
+ }
+ }
+
+ void OnResourceRedirect(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response,
+ CefString& new_url) override {
+ EXPECT_IO_THREAD();
+ EXPECT_EQ(browser_id_, browser->GetIdentifier());
+
+ if (IsMainURL(request->GetURL()) || IsSubURL(request->GetURL())) {
+ EXPECT_FALSE(true); // Not reached.
+ return;
+ }
+
+ VerifyFrame(kOnResourceRedirect, frame);
+
+ VerifyState(kOnResourceRedirect, request, response);
+
+ if (mode_ == REDIRECT_REQUEST_HANDLER ||
+ mode_ == REDIRECT_RESOURCE_RESPONSE) {
+ // The URL redirected to from GetResourceHandler or OnResourceResponse.
+ EXPECT_STREQ(GetURL(RESULT_JS), new_url.ToString().c_str());
+ } else if (mode_ == REDIRECT_RESOURCE_REDIRECT) {
+ if (on_resource_redirect_ct_ == 0) {
+ // The URL redirected to from GetResourceHandler.
+ EXPECT_STREQ(GetURL(REDIRECT_JS), new_url.ToString().c_str());
+ // Redirect again.
+ new_url = GetURL(RESULT_JS);
+ } else {
+ NOTREACHED();
+ }
+ }
+
+ on_resource_redirect_ct_++;
+ }
+
+ bool OnResourceResponse(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response) override {
+ EXPECT_IO_THREAD();
+ EXPECT_EQ(browser_id_, browser->GetIdentifier());
+
+ if (IsMainURL(request->GetURL())) {
+ EXPECT_TRUE(frame->IsMain());
+ return false;
+ } else if (IsSubURL(request->GetURL())) {
+ EXPECT_FALSE(frame->IsMain());
+ EXPECT_TRUE(subframe_);
+ return false;
+ }
+
+ VerifyFrame(kOnResourceResponse, frame);
+
+ VerifyState(kOnResourceResponse, request, response);
+
+ on_resource_response_ct_++;
+
+ if (on_resource_response_ct_ == 1) {
+ if (mode_ == REDIRECT_RESOURCE_RESPONSE) {
+ // Redirect the request to this URL.
+ request->SetURL(GetURL(RESULT_JS));
+ return true;
+ } else if (mode_ == RESTART_RESOURCE_RESPONSE) {
+ // Restart the request loading this data.
+ SetCustomHeader(request);
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ CefRefPtr<CefResponseFilter> GetResourceResponseFilter(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response) override {
+ EXPECT_IO_THREAD();
+ EXPECT_EQ(browser_id_, browser->GetIdentifier());
+
+ if (IsMainURL(request->GetURL())) {
+ EXPECT_TRUE(frame->IsMain());
+ return nullptr;
+ } else if (IsSubURL(request->GetURL())) {
+ EXPECT_FALSE(frame->IsMain());
+ EXPECT_TRUE(subframe_);
+ return nullptr;
+ }
+
+ VerifyFrame(kGetResourceResponseFilter, frame);
+
+ VerifyState(kGetResourceResponseFilter, request, response);
+
+ get_resource_response_filter_ct_++;
+
+ return nullptr;
+ }
+
+ void OnResourceLoadComplete(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response,
+ URLRequestStatus status,
+ int64 received_content_length) override {
+ EXPECT_IO_THREAD();
+
+ if (IsChromeRuntimeEnabled() && request->GetResourceType() == RT_FAVICON) {
+ // Ignore favicon requests.
+ return;
+ }
+
+ EXPECT_EQ(browser_id_, browser->GetIdentifier());
+
+ if (IsMainURL(request->GetURL())) {
+ EXPECT_TRUE(frame->IsMain());
+ EXPECT_EQ(UR_SUCCESS, status);
+ EXPECT_EQ(static_cast<int64>(GetMainResponseBody().length()),
+ received_content_length);
+ return;
+ } else if (IsSubURL(request->GetURL())) {
+ EXPECT_FALSE(frame->IsMain());
+ EXPECT_EQ(UR_SUCCESS, status);
+ EXPECT_EQ(static_cast<int64>(GetSubResponseBody().length()),
+ received_content_length);
+ EXPECT_TRUE(subframe_);
+ return;
+ }
+
+ VerifyFrame(kOnResourceLoadComplete, frame);
+
+ VerifyState(kOnResourceLoadComplete, request, response);
+
+ if (unhandled_ || IsIncomplete()) {
+ EXPECT_EQ(UR_FAILED, status);
+ EXPECT_EQ(0, received_content_length);
+ } else {
+ EXPECT_EQ(UR_SUCCESS, status);
+ EXPECT_EQ(static_cast<int64>(GetResponseBody().length()),
+ received_content_length);
+ }
+
+ on_resource_load_complete_ct_++;
+
+ if (IsIncomplete()) {
+ MaybeDestroyTest(false);
+ }
+ }
+
+ void OnProtocolExecution(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ bool& allow_os_execution) override {
+ EXPECT_IO_THREAD();
+ EXPECT_EQ(browser_id_, browser->GetIdentifier());
+
+ if (IsMainURL(request->GetURL()) || IsSubURL(request->GetURL())) {
+ EXPECT_FALSE(true); // Not reached.
+ return;
+ }
+
+ VerifyFrame(kOnProtocolExecution, frame);
+
+ EXPECT_TRUE(custom_scheme_);
+ EXPECT_TRUE(unhandled_);
+
+ // Check expected default value.
+ EXPECT_FALSE(allow_os_execution);
+
+ VerifyState(kOnProtocolExecution, request, nullptr);
+ on_protocol_execution_ct_++;
+ }
+
+ void OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int httpStatusCode) override {
+ EXPECT_UI_THREAD();
+ EXPECT_EQ(browser_id_, browser->GetIdentifier());
+
+ EXPECT_EQ(httpStatusCode, 200);
+
+ on_load_end_ct_++;
+
+ TestHandler::OnLoadEnd(browser, frame, httpStatusCode);
+ MaybeDestroyTest(false);
+ }
+
+ bool OnQuery(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int64 query_id,
+ const CefString& request,
+ bool persistent,
+ CefRefPtr<Callback> callback) override {
+ EXPECT_UI_THREAD();
+ EXPECT_EQ(browser_id_, browser->GetIdentifier());
+
+ EXPECT_STREQ(kSubresourceProcessMsg, request.ToString().c_str());
+
+ VerifyFrame(kOnQuery, frame);
+
+ callback->Success("");
+
+ on_query_ct_++;
+ MaybeDestroyTest(false);
+
+ return true;
+ }
+
+ void DestroyTest() override {
+ // Only called for the main and/or sub frame load.
+ if (subframe_) {
+ EXPECT_EQ(2, on_before_browse_ct_);
+ } else {
+ EXPECT_EQ(1, on_before_browse_ct_);
+ }
+
+ if (mode_ == RESTART_RESOURCE_RESPONSE) {
+ EXPECT_EQ(2, get_resource_request_handler_ct_);
+ EXPECT_EQ(2, get_cookie_access_filter_ct_);
+ EXPECT_EQ(2, on_before_resource_load_ct_);
+ EXPECT_EQ(2, get_resource_handler_ct_);
+ EXPECT_EQ(0, on_resource_redirect_ct_);
+ // Unhandled requests won't see a call to GetResourceResponseFilter or
+ // OnResourceResponse. In this case we're restarting from inside
+ // OnResourceResponse.
+ if (unhandled_) {
+ EXPECT_EQ(0, get_resource_response_filter_ct_);
+ EXPECT_EQ(1, on_resource_response_ct_);
+ } else {
+ EXPECT_EQ(1, get_resource_response_filter_ct_);
+ EXPECT_EQ(2, on_resource_response_ct_);
+ }
+ } else if (IsLoad()) {
+ EXPECT_EQ(1, get_resource_request_handler_ct_);
+ EXPECT_EQ(1, get_cookie_access_filter_ct_);
+ EXPECT_EQ(1, on_before_resource_load_ct_);
+ EXPECT_EQ(1, get_resource_handler_ct_);
+ EXPECT_EQ(0, on_resource_redirect_ct_);
+ // Unhandled requests won't see a call to GetResourceResponseFilter or
+ // OnResourceResponse.
+ if (unhandled_) {
+ EXPECT_EQ(0, get_resource_response_filter_ct_);
+ EXPECT_EQ(0, on_resource_response_ct_);
+ } else {
+ EXPECT_EQ(1, get_resource_response_filter_ct_);
+ EXPECT_EQ(1, on_resource_response_ct_);
+ }
+ } else if (IsRedirect()) {
+ EXPECT_EQ(2, get_resource_request_handler_ct_);
+ EXPECT_EQ(2, get_cookie_access_filter_ct_);
+ EXPECT_EQ(2, on_before_resource_load_ct_);
+ if (mode_ == REDIRECT_BEFORE_RESOURCE_LOAD) {
+ EXPECT_EQ(1, get_resource_handler_ct_);
+ } else {
+ EXPECT_EQ(2, get_resource_handler_ct_);
+ }
+ EXPECT_EQ(1, on_resource_redirect_ct_);
+
+ // Unhandled requests won't see a call to GetResourceResponseFilter.
+ if (unhandled_) {
+ EXPECT_EQ(0, get_resource_response_filter_ct_);
+ } else {
+ EXPECT_EQ(1, get_resource_response_filter_ct_);
+ }
+
+ // Unhandled requests won't see a call to OnResourceResponse.
+ if (mode_ == REDIRECT_RESOURCE_RESPONSE) {
+ // In this case we're redirecting from inside OnResourceResponse.
+ if (unhandled_) {
+ EXPECT_EQ(1, on_resource_response_ct_);
+ } else {
+ EXPECT_EQ(2, on_resource_response_ct_);
+ }
+ } else {
+ if (unhandled_) {
+ EXPECT_EQ(0, on_resource_response_ct_);
+ } else {
+ EXPECT_EQ(1, on_resource_response_ct_);
+ }
+ }
+ } else if (IsIncomplete()) {
+ EXPECT_EQ(1, get_resource_request_handler_ct_);
+ EXPECT_EQ(1, get_cookie_access_filter_ct_);
+ EXPECT_EQ(1, on_before_resource_load_ct_);
+
+ if (IsIncompleteRequestHandler()) {
+ EXPECT_EQ(1, get_resource_handler_ct_);
+ } else {
+ EXPECT_EQ(0, get_resource_handler_ct_);
+ }
+
+ EXPECT_EQ(0, on_resource_redirect_ct_);
+
+ if (mode_ == INCOMPLETE_REQUEST_HANDLER_READ) {
+ EXPECT_EQ(1, get_resource_response_filter_ct_);
+ EXPECT_EQ(1, on_resource_response_ct_);
+ } else {
+ EXPECT_EQ(0, get_resource_response_filter_ct_);
+ EXPECT_EQ(0, on_resource_response_ct_);
+ }
+ } else {
+ NOTREACHED();
+ }
+
+ EXPECT_EQ(resource_handler_created_ct_, resource_handler_destroyed_ct_);
+ EXPECT_EQ(1, on_resource_load_complete_ct_);
+
+ // Only called for the main and/or sub frame load.
+ if (IsIncomplete()) {
+ EXPECT_EQ(0, on_load_end_ct_);
+ } else {
+ if (subframe_) {
+ EXPECT_EQ(2, on_load_end_ct_);
+ } else {
+ EXPECT_EQ(1, on_load_end_ct_);
+ }
+ }
+
+ if (unhandled_ || IsIncomplete()) {
+ EXPECT_EQ(0, on_query_ct_);
+ } else {
+ EXPECT_EQ(1, on_query_ct_);
+ }
+
+ if (custom_scheme_ && unhandled_ && !IsIncomplete()) {
+ EXPECT_EQ(1, on_protocol_execution_ct_);
+ } else {
+ EXPECT_EQ(0, on_protocol_execution_ct_);
+ }
+
+ TestHandler::DestroyTest();
+
+ if (!SignalCompletionWhenAllBrowsersClose()) {
+ // Complete asynchronously so the call stack has a chance to unwind.
+ CefPostTask(TID_UI,
+ base::BindOnce(&SubresourceResponseTest::TestComplete, this));
+ }
+ }
+
+ private:
+ const char* GetMainURL() const {
+ if (custom_scheme_) {
+ return "rrhcustom://test.com/main.html";
+ } else {
+ return "http://test.com/main.html";
+ }
+ }
+
+ const char* GetSubURL() const {
+ if (custom_scheme_) {
+ return "rrhcustom://test.com/subframe.html";
+ } else {
+ return "http://test.com/subframe.html";
+ }
+ }
+
+ const char* GetOrigin() const {
+ if (custom_scheme_) {
+ return "rrhcustom://test.com";
+ } else {
+ return "http://test.com";
+ }
+ }
+
+ bool IsMainURL(const std::string& url) const { return url == GetMainURL(); }
+ bool IsSubURL(const std::string& url) const { return url == GetSubURL(); }
+
+ enum TestUrl {
+ RESULT_JS,
+ REDIRECT_JS,
+ REDIRECT2_JS,
+ };
+
+ const char* GetURL(TestUrl url) const {
+ if (custom_scheme_) {
+ if (url == RESULT_JS) {
+ return "rrhcustom://test.com/result.js";
+ }
+ if (url == REDIRECT_JS) {
+ return "rrhcustom://test.com/redirect.js";
+ }
+ if (url == REDIRECT2_JS) {
+ return "rrhcustom://test.com/redirect2.js";
+ }
+ } else {
+ if (url == RESULT_JS) {
+ return "http://test.com/result.js";
+ }
+ if (url == REDIRECT_JS) {
+ return "http://test.com/redirect.js";
+ }
+ if (url == REDIRECT2_JS) {
+ return "http://test.com/redirect2.js";
+ }
+ }
+
+ NOTREACHED();
+ return "";
+ }
+
+ const char* GetStartupURL() const {
+ if (IsLoad() || IsIncomplete()) {
+ return GetURL(RESULT_JS);
+ } else if (mode_ == REDIRECT_RESOURCE_REDIRECT) {
+ return GetURL(REDIRECT2_JS);
+ } else if (IsRedirect()) {
+ return GetURL(REDIRECT_JS);
+ }
+
+ NOTREACHED();
+ return "";
+ }
+
+ std::string GetMainResponseBody() const {
+ std::stringstream html;
+ html << "<html><head>";
+
+ if (subframe_) {
+ const std::string& url = GetSubURL();
+ html << "<iframe src=\"" << url << "\"></iframe>";
+ } else {
+ const std::string& url = GetStartupURL();
+ html << "<script type=\"text/javascript\" src=\"" << url
+ << "\"></script>";
+ }
+
+ html << "</head><body><p>Main</p></body></html>";
+ return html.str();
+ }
+
+ std::string GetSubResponseBody() const {
+ DCHECK(subframe_);
+
+ std::stringstream html;
+ html << "<html><head>";
+
+ const std::string& url = GetStartupURL();
+ html << "<script type=\"text/javascript\" src=\"" << url << "\"></script>";
+
+ html << "</head><body><p>Sub</p></body></html>";
+ return html.str();
+ }
+
+ std::string GetResponseBody() const {
+ return "window.testQuery({request:'" + std::string(kSubresourceProcessMsg) +
+ "'});";
+ }
+ std::string GetRedirectBody() const {
+ return "<html><body>Redirect</body></html>";
+ }
+
+ base::OnceClosure GetResourceDestroyCallback() {
+ resource_handler_created_ct_++;
+ return base::BindOnce(&SubresourceResponseTest::MaybeDestroyTest, this,
+ true);
+ }
+
+ bool GetCallbackResourceHandlerMode(CallbackResourceHandler::Mode& mode) {
+ switch (mode_) {
+ case IMMEDIATE_REQUEST_HANDLER_OPEN:
+ mode = CallbackResourceHandler::IMMEDIATE_OPEN;
+ return true;
+ case IMMEDIATE_REQUEST_HANDLER_READ:
+ mode = CallbackResourceHandler::IMMEDIATE_READ;
+ return true;
+ case IMMEDIATE_REQUEST_HANDLER_ALL:
+ mode = CallbackResourceHandler::IMMEDIATE_ALL;
+ return true;
+ case DELAYED_REQUEST_HANDLER_OPEN:
+ mode = CallbackResourceHandler::DELAYED_OPEN;
+ return true;
+ case DELAYED_REQUEST_HANDLER_READ:
+ mode = CallbackResourceHandler::DELAYED_READ;
+ return true;
+ case DELAYED_REQUEST_HANDLER_ALL:
+ mode = CallbackResourceHandler::DELAYED_ALL;
+ return true;
+ default:
+ break;
+ }
+ return false;
+ }
+
+ CefRefPtr<CefResourceHandler> GetResource(int status_code,
+ const CefString& status_text,
+ const CefString& mime_type,
+ CefResponse::HeaderMap header_map,
+ const std::string& body) {
+ CefRefPtr<CefStreamReader> stream = CefStreamReader::CreateForData(
+ const_cast<char*>(body.c_str()), body.size());
+
+ CallbackResourceHandler::Mode handler_mode;
+ if (GetCallbackResourceHandlerMode(handler_mode)) {
+ return new CallbackResourceHandler(handler_mode, status_code, status_text,
+ mime_type, header_map, stream,
+ GetResourceDestroyCallback());
+ }
+
+ return new NormalResourceHandler(status_code, status_text, mime_type,
+ header_map, stream,
+ GetResourceDestroyCallback());
+ }
+
+ CefRefPtr<CefResourceHandler> GetMainResource() {
+ return GetResource(200, "OK", "text/html", CefResponse::HeaderMap(),
+ GetMainResponseBody());
+ }
+
+ CefRefPtr<CefResourceHandler> GetSubResource() {
+ return GetResource(200, "OK", "text/html", CefResponse::HeaderMap(),
+ GetSubResponseBody());
+ }
+
+ CefRefPtr<CefResourceHandler> GetOKResource() {
+ return GetResource(200, "OK", "text/javascript", CefResponse::HeaderMap(),
+ GetResponseBody());
+ }
+
+ CefRefPtr<CefResourceHandler> GetRedirectResource(
+ const std::string& redirect_url) {
+ CefResponse::HeaderMap headerMap;
+ headerMap.insert(std::make_pair("Location", redirect_url));
+
+ return GetResource(307, "Temporary Redirect", "text/javascript", headerMap,
+ GetRedirectBody());
+ }
+
+ CefRefPtr<CefResourceHandler> GetIncompleteResource() {
+ if (TestOldResourceAPI()) {
+ return new IncompleteResourceHandlerOld(
+ mode_ == INCOMPLETE_REQUEST_HANDLER_OPEN
+ ? IncompleteResourceHandlerOld::BLOCK_PROCESS_REQUEST
+ : IncompleteResourceHandlerOld::BLOCK_READ_RESPONSE,
+ "text/javascript", GetResourceDestroyCallback());
+ }
+
+ return new IncompleteResourceHandler(
+ mode_ == INCOMPLETE_REQUEST_HANDLER_OPEN
+ ? IncompleteResourceHandler::BLOCK_OPEN
+ : IncompleteResourceHandler::BLOCK_READ,
+ "text/javascript", GetResourceDestroyCallback());
+ }
+
+ bool IsLoad() const {
+ return mode_ == LOAD || mode_ == MODIFY_BEFORE_RESOURCE_LOAD ||
+ mode_ == RESTART_RESOURCE_RESPONSE ||
+ mode_ == IMMEDIATE_REQUEST_HANDLER_OPEN ||
+ mode_ == IMMEDIATE_REQUEST_HANDLER_READ ||
+ mode_ == IMMEDIATE_REQUEST_HANDLER_ALL ||
+ mode_ == DELAYED_REQUEST_HANDLER_OPEN ||
+ mode_ == DELAYED_REQUEST_HANDLER_READ ||
+ mode_ == DELAYED_REQUEST_HANDLER_ALL;
+ }
+
+ bool IsIncompleteRequestHandler() const {
+ return mode_ == INCOMPLETE_REQUEST_HANDLER_OPEN ||
+ mode_ == INCOMPLETE_REQUEST_HANDLER_READ;
+ }
+
+ bool IsIncomplete() const {
+ return mode_ == INCOMPLETE_BEFORE_RESOURCE_LOAD ||
+ IsIncompleteRequestHandler();
+ }
+
+ bool IsRedirect() const {
+ return mode_ == REDIRECT_BEFORE_RESOURCE_LOAD ||
+ mode_ == REDIRECT_REQUEST_HANDLER ||
+ mode_ == REDIRECT_RESOURCE_REDIRECT ||
+ mode_ == REDIRECT_RESOURCE_RESPONSE;
+ }
+
+ static void SetCustomHeader(CefRefPtr<CefRequest> request) {
+ EXPECT_FALSE(request->IsReadOnly());
+ request->SetHeaderByName("X-Custom-Header", "value", false);
+ }
+
+ static std::string GetCustomHeader(CefRefPtr<CefRequest> request) {
+ return request->GetHeaderByName("X-Custom-Header");
+ }
+
+ // Resource-related callbacks.
+ enum Callback {
+ kGetResourceRequestHandler,
+ kGetCookieAccessFilter,
+ kOnBeforeResourceLoad,
+ kGetResourceHandler,
+ kOnResourceRedirect,
+ kOnResourceResponse,
+ kGetResourceResponseFilter,
+ kOnResourceLoadComplete,
+ kOnProtocolExecution,
+ kOnQuery,
+ };
+
+ bool ShouldHaveResponse(Callback callback) const {
+ return callback >= kOnResourceRedirect &&
+ callback <= kOnResourceLoadComplete;
+ }
+
+ bool ShouldHaveWritableRequest(Callback callback) const {
+ return callback == kOnBeforeResourceLoad || callback == kOnResourceResponse;
+ }
+
+ void VerifyFrame(Callback callback, CefRefPtr<CefFrame> frame) const {
+ EXPECT_TRUE(frame);
+
+ if (subframe_) {
+ EXPECT_FALSE(frame->IsMain()) << callback;
+ } else {
+ EXPECT_TRUE(frame->IsMain()) << callback;
+ }
+
+ EXPECT_EQ(frame_id_, frame->GetIdentifier()) << callback;
+ }
+
+ void VerifyState(Callback callback,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response) const {
+ EXPECT_TRUE(request) << callback;
+
+ if (ShouldHaveResponse(callback)) {
+ EXPECT_TRUE(response) << callback;
+ EXPECT_TRUE(response->IsReadOnly()) << callback;
+ } else {
+ EXPECT_FALSE(response) << callback;
+ }
+
+ if (ShouldHaveWritableRequest(callback)) {
+ EXPECT_FALSE(request->IsReadOnly()) << callback;
+ } else {
+ EXPECT_TRUE(request->IsReadOnly()) << callback;
+ }
+
+ // All resource-related callbacks share the same request ID.
+ EXPECT_EQ(request_id_, request->GetIdentifier()) << callback;
+
+ if (IsLoad() || IsIncomplete()) {
+ EXPECT_STREQ("GET", request->GetMethod().ToString().c_str()) << callback;
+ EXPECT_STREQ(GetURL(RESULT_JS), request->GetURL().ToString().c_str())
+ << callback;
+
+ // Expect the header for all callbacks following the callback that
+ // initially sets it.
+ const std::string& custom_header = GetCustomHeader(request);
+ if ((mode_ == RESTART_RESOURCE_RESPONSE &&
+ on_resource_response_ct_ > 0) ||
+ (mode_ == MODIFY_BEFORE_RESOURCE_LOAD &&
+ on_before_resource_load_ct_ > 0)) {
+ EXPECT_STREQ("value", custom_header.c_str()) << callback;
+ } else {
+ EXPECT_STREQ("", custom_header.c_str()) << callback;
+ }
+
+ if (response) {
+ VerifyOKResponse(callback, response);
+ }
+ } else if (IsRedirect()) {
+ EXPECT_STREQ("GET", request->GetMethod().ToString().c_str()) << callback;
+ // Subresource loads don't get OnBeforeBrowse calls, so this check is a
+ // bit less exact then with main resource loads.
+ if (on_resource_redirect_ct_ == 0) {
+ // Before the redirect.
+ EXPECT_STREQ(GetStartupURL(), request->GetURL().ToString().c_str())
+ << callback;
+ } else {
+ // After the redirect.
+ EXPECT_STREQ(GetURL(RESULT_JS), request->GetURL().ToString().c_str())
+ << callback;
+ }
+
+ if (response) {
+ if (callback == kOnResourceRedirect) {
+ // Before the redirect.
+ VerifyRedirectResponse(callback, response);
+ } else {
+ // After the redirect.
+ VerifyOKResponse(callback, response);
+ }
+ }
+ } else {
+ NOTREACHED() << callback;
+ }
+ }
+
+ void VerifyOKResponse(Callback callback,
+ CefRefPtr<CefResponse> response) const {
+ // True for the first response in cases where we're redirecting/restarting
+ // from inside OnResourceResponse (e.g. the first response always succeeds).
+ const bool override_unhandled = unhandled_ &&
+ (mode_ == REDIRECT_RESOURCE_RESPONSE ||
+ mode_ == RESTART_RESOURCE_RESPONSE) &&
+ get_resource_handler_ct_ == 1;
+
+ // True for tests where the request will be incomplete and never receive a
+ // response.
+ const bool incomplete_unhandled =
+ (mode_ == INCOMPLETE_BEFORE_RESOURCE_LOAD ||
+ mode_ == INCOMPLETE_REQUEST_HANDLER_OPEN);
+
+ if ((unhandled_ && !override_unhandled) || incomplete_unhandled) {
+ if (incomplete_unhandled) {
+ EXPECT_EQ(ERR_ABORTED, response->GetError()) << callback;
+ } else {
+ EXPECT_EQ(ERR_UNKNOWN_URL_SCHEME, response->GetError()) << callback;
+ }
+ EXPECT_EQ(0, response->GetStatus()) << callback;
+ EXPECT_STREQ("", response->GetStatusText().ToString().c_str())
+ << callback;
+ EXPECT_STREQ("", response->GetURL().ToString().c_str()) << callback;
+ EXPECT_STREQ("", response->GetMimeType().ToString().c_str()) << callback;
+ EXPECT_STREQ("", response->GetCharset().ToString().c_str()) << callback;
+ } else {
+ if (mode_ == INCOMPLETE_REQUEST_HANDLER_READ &&
+ callback == kOnResourceLoadComplete) {
+ // We got a response, but we also got aborted.
+ EXPECT_EQ(ERR_ABORTED, response->GetError()) << callback;
+ } else {
+ EXPECT_EQ(ERR_NONE, response->GetError()) << callback;
+ }
+ EXPECT_EQ(200, response->GetStatus()) << callback;
+ EXPECT_STREQ("OK", response->GetStatusText().ToString().c_str())
+ << callback;
+ EXPECT_STREQ("", response->GetURL().ToString().c_str()) << callback;
+ EXPECT_STREQ("text/javascript",
+ response->GetMimeType().ToString().c_str())
+ << callback;
+ EXPECT_STREQ("", response->GetCharset().ToString().c_str()) << callback;
+ }
+ }
+
+ void VerifyRedirectResponse(Callback callback,
+ CefRefPtr<CefResponse> response) const {
+ EXPECT_EQ(ERR_NONE, response->GetError()) << callback;
+ EXPECT_EQ(307, response->GetStatus()) << callback;
+ const std::string& status_text = response->GetStatusText();
+ EXPECT_TRUE(status_text == "Internal Redirect" ||
+ status_text == "Temporary Redirect")
+ << status_text << callback;
+ EXPECT_STREQ("", response->GetURL().ToString().c_str()) << callback;
+ EXPECT_STREQ("", response->GetMimeType().ToString().c_str()) << callback;
+ EXPECT_STREQ("", response->GetCharset().ToString().c_str()) << callback;
+ }
+
+ void CloseBrowserAsync() {
+ EXPECT_TRUE(IsIncomplete());
+ SetSignalCompletionWhenAllBrowsersClose(false);
+ CefPostDelayedTask(
+ TID_UI, base::BindOnce(&TestHandler::CloseBrowser, GetBrowser(), false),
+ 100);
+ }
+
+ void MaybeDestroyTest(bool from_handler) {
+ if (!CefCurrentlyOn(TID_UI)) {
+ CefPostTask(TID_UI,
+ base::BindOnce(&SubresourceResponseTest::MaybeDestroyTest,
+ this, from_handler));
+ return;
+ }
+
+ if (from_handler) {
+ resource_handler_destroyed_ct_++;
+ }
+
+ bool destroy_test = false;
+ if (IsIncomplete()) {
+ // Destroy the test if we got OnResourceLoadComplete and either the
+ // resource handler will never complete or it was destroyed.
+ destroy_test =
+ on_resource_load_complete_ct_ > 0 &&
+ (!IsIncompleteRequestHandler() ||
+ resource_handler_destroyed_ct_ == resource_handler_created_ct_);
+ } else {
+ // Destroy the test if we got the expected number of OnLoadEnd and
+ // OnQuery, and the expected number of resource handlers were destroyed.
+ destroy_test =
+ on_load_end_ct_ > (subframe_ ? 1 : 0) &&
+ (on_query_ct_ > 0 || unhandled_) &&
+ resource_handler_destroyed_ct_ == resource_handler_created_ct_;
+ }
+
+ if (destroy_test) {
+ DestroyTest();
+ }
+ }
+
+ const TestMode mode_;
+ const bool custom_scheme_;
+ const bool unhandled_;
+ const bool subframe_;
+
+ int browser_id_ = 0;
+ int64 frame_id_ = 0;
+ uint64 request_id_ = 0U;
+
+ int resource_handler_created_ct_ = 0;
+
+ int on_before_browse_ct_ = 0;
+ int on_load_end_ct_ = 0;
+ int on_query_ct_ = 0;
+
+ int get_resource_request_handler_ct_ = 0;
+ int get_cookie_access_filter_ct_ = 0;
+ int on_before_resource_load_ct_ = 0;
+ int get_resource_handler_ct_ = 0;
+ int on_resource_redirect_ct_ = 0;
+ int on_resource_response_ct_ = 0;
+ int get_resource_response_filter_ct_ = 0;
+ int on_resource_load_complete_ct_ = 0;
+ int on_protocol_execution_ct_ = 0;
+ int resource_handler_destroyed_ct_ = 0;
+
+ // Used with INCOMPLETE_BEFORE_RESOURCE_LOAD.
+ CefRefPtr<CefCallback> incomplete_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(SubresourceResponseTest);
+ IMPLEMENT_REFCOUNTING(SubresourceResponseTest);
+};
+
+} // namespace
+
+#define SUBRESOURCE_TEST(name, test_mode, custom, unhandled, subframe) \
+ TEST(ResourceRequestHandlerTest, Subresource##name) { \
+ CefRefPtr<SubresourceResponseTest> handler = new SubresourceResponseTest( \
+ SubresourceResponseTest::test_mode, custom, unhandled, subframe); \
+ handler->ExecuteTest(); \
+ ReleaseAndWaitForDestructor(handler); \
+ }
+
+#define SUBRESOURCE_TEST_ALL_MODES(name, custom, unhandled, subframe) \
+ SUBRESOURCE_TEST(name##Load, LOAD, custom, unhandled, subframe) \
+ SUBRESOURCE_TEST(name##ModifyBeforeResourceLoad, \
+ MODIFY_BEFORE_RESOURCE_LOAD, custom, unhandled, subframe) \
+ SUBRESOURCE_TEST(name##RedirectBeforeResourceLoad, \
+ REDIRECT_BEFORE_RESOURCE_LOAD, custom, unhandled, subframe) \
+ SUBRESOURCE_TEST(name##RedirectRequestHandler, REDIRECT_REQUEST_HANDLER, \
+ custom, unhandled, subframe) \
+ SUBRESOURCE_TEST(name##RedirectResourceRedirect, REDIRECT_RESOURCE_REDIRECT, \
+ custom, unhandled, subframe) \
+ SUBRESOURCE_TEST(name##RedirectResourceResponse, REDIRECT_RESOURCE_RESPONSE, \
+ custom, unhandled, subframe) \
+ SUBRESOURCE_TEST(name##RestartResourceResponse, RESTART_RESOURCE_RESPONSE, \
+ custom, unhandled, subframe)
+
+// Tests only supported in handled mode.
+#define SUBRESOURCE_TEST_HANDLED_MODES(name, custom, subframe) \
+ SUBRESOURCE_TEST(name##ImmediateRequestHandlerOpen, \
+ IMMEDIATE_REQUEST_HANDLER_OPEN, custom, false, subframe) \
+ SUBRESOURCE_TEST(name##ImmediateRequestHandlerRead, \
+ IMMEDIATE_REQUEST_HANDLER_READ, custom, false, subframe) \
+ SUBRESOURCE_TEST(name##ImmediateRequestHandlerAll, \
+ IMMEDIATE_REQUEST_HANDLER_ALL, custom, false, subframe) \
+ SUBRESOURCE_TEST(name##DelayedRequestHandlerOpen, \
+ DELAYED_REQUEST_HANDLER_OPEN, custom, false, subframe) \
+ SUBRESOURCE_TEST(name##DelayedRequestHandlerRead, \
+ DELAYED_REQUEST_HANDLER_READ, custom, false, subframe) \
+ SUBRESOURCE_TEST(name##DelayedRequestHandlerAll, \
+ DELAYED_REQUEST_HANDLER_ALL, custom, false, subframe) \
+ SUBRESOURCE_TEST(name##IncompleteBeforeResourceLoad, \
+ INCOMPLETE_BEFORE_RESOURCE_LOAD, custom, false, subframe) \
+ SUBRESOURCE_TEST(name##IncompleteRequestHandlerOpen, \
+ INCOMPLETE_REQUEST_HANDLER_OPEN, custom, false, subframe) \
+ SUBRESOURCE_TEST(name##IncompleteRequestHandlerRead, \
+ INCOMPLETE_REQUEST_HANDLER_READ, custom, false, subframe)
+
+SUBRESOURCE_TEST_ALL_MODES(StandardHandledMainFrame, false, false, false)
+SUBRESOURCE_TEST_ALL_MODES(StandardUnhandledMainFrame, false, true, false)
+SUBRESOURCE_TEST_ALL_MODES(CustomHandledMainFrame, true, false, false)
+SUBRESOURCE_TEST_ALL_MODES(CustomUnhandledMainFrame, true, true, false)
+
+SUBRESOURCE_TEST_ALL_MODES(StandardHandledSubFrame, false, false, true)
+SUBRESOURCE_TEST_ALL_MODES(StandardUnhandledSubFrame, false, true, true)
+SUBRESOURCE_TEST_ALL_MODES(CustomHandledSubFrame, true, false, true)
+SUBRESOURCE_TEST_ALL_MODES(CustomUnhandledSubFrame, true, true, true)
+
+SUBRESOURCE_TEST_HANDLED_MODES(StandardHandledMainFrame, false, false)
+SUBRESOURCE_TEST_HANDLED_MODES(CustomHandledMainFrame, true, false)
+
+SUBRESOURCE_TEST_HANDLED_MODES(StandardHandledSubFrame, false, true)
+SUBRESOURCE_TEST_HANDLED_MODES(CustomHandledSubFrame, true, true)
+
+namespace {
+
+const char kResourceTestHtml[] = "http://test.com/resource.html";
+
+class RedirectResponseTest : public TestHandler {
+ public:
+ enum TestMode {
+ URL,
+ HEADER,
+ POST,
+ };
+
+ RedirectResponseTest(TestMode mode, bool via_request_context_handler)
+ : via_request_context_handler_(via_request_context_handler) {
+ if (mode == URL) {
+ resource_test_.reset(new UrlResourceTest);
+ } else if (mode == HEADER) {
+ resource_test_.reset(new HeaderResourceTest);
+ } else {
+ resource_test_.reset(new PostResourceTest);
+ }
+ }
+
+ void RunTest() override {
+ AddResource(kResourceTestHtml, GetHtml(), "text/html");
+
+ resource_request_handler_ = new ResourceRequestHandler(this);
+
+ CefRefPtr<CefRequestContext> request_context =
+ CefRequestContext::GetGlobalContext();
+ if (via_request_context_handler_) {
+ CefRefPtr<CefRequestContextHandler> request_context_handler =
+ new RequestContextHandler(resource_request_handler_.get());
+ CefRequestContextSettings settings;
+ request_context = CefRequestContext::CreateContext(
+ request_context, request_context_handler);
+ }
+
+ CreateBrowser(kResourceTestHtml, request_context);
+ SetTestTimeout();
+ }
+
+ CefRefPtr<CefResourceRequestHandler> GetResourceRequestHandler(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ bool is_navigation,
+ bool is_download,
+ const CefString& request_initiator,
+ bool& disable_default_handling) override {
+ if (via_request_context_handler_) {
+ // Use the handler returned by RequestContextHandler.
+ return nullptr;
+ }
+ return resource_request_handler_.get();
+ }
+
+ bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ bool user_gesture,
+ bool is_redirect) override {
+ EXPECT_UI_THREAD();
+ EXPECT_EQ(0, browser_id_);
+ browser_id_ = browser->GetIdentifier();
+ EXPECT_GT(browser_id_, 0);
+
+ // This method is only called for the main resource.
+ EXPECT_STREQ(kResourceTestHtml, request->GetURL().ToString().c_str());
+
+ // Browser-side navigation no longer exposes the actual request information.
+ EXPECT_EQ(0U, request->GetIdentifier());
+
+ return false;
+ }
+
+ void OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int httpStatusCode) override {
+ EXPECT_UI_THREAD();
+ EXPECT_EQ(browser_id_, browser->GetIdentifier());
+
+ TestHandler::OnLoadEnd(browser, frame, httpStatusCode);
+ DestroyTest();
+ }
+
+ void DestroyTest() override {
+ resource_test_->CheckExpected();
+ resource_test_.reset(nullptr);
+
+ TestHandler::DestroyTest();
+ }
+
+ private:
+ std::string GetHtml() const {
+ std::stringstream html;
+ html << "<html><head>";
+
+ const std::string& url = resource_test_->start_url();
+ html << "<script type=\"text/javascript\" src=\"" << url << "\"></script>";
+
+ html << "</head><body><p>Main</p></body></html>";
+ return html.str();
+ }
+
+ class ResourceTest {
+ public:
+ ResourceTest(const std::string& start_url,
+ size_t expected_resource_response_ct = 2U,
+ size_t expected_before_resource_load_ct = 1U,
+ size_t expected_resource_redirect_ct = 0U,
+ size_t expected_resource_load_complete_ct = 1U)
+ : start_url_(start_url),
+ expected_resource_response_ct_(expected_resource_response_ct),
+ expected_before_resource_load_ct_(expected_before_resource_load_ct),
+ expected_resource_redirect_ct_(expected_resource_redirect_ct),
+ expected_resource_load_complete_ct_(
+ expected_resource_load_complete_ct) {}
+ virtual ~ResourceTest() {}
+
+ const std::string& start_url() const { return start_url_; }
+
+ virtual bool OnBeforeResourceLoad(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request) {
+ before_resource_load_ct_++;
+ return false;
+ }
+
+ virtual CefRefPtr<CefResourceHandler> GetResourceHandler(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request) {
+ get_resource_handler_ct_++;
+
+ const std::string& js_content = "<!-- -->";
+
+ CefRefPtr<CefStreamReader> stream = CefStreamReader::CreateForData(
+ const_cast<char*>(js_content.c_str()), js_content.size());
+
+ return new CefStreamResourceHandler(200, "OK", "text/javascript",
+ CefResponse::HeaderMap(), stream);
+ }
+
+ virtual void OnResourceRedirect(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefString& new_url) {
+ resource_redirect_ct_++;
+ }
+
+ bool OnResourceResponse(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response) {
+ EXPECT_TRUE(CheckUrl(request->GetURL()));
+
+ // Verify the response returned by GetResourceHandler.
+ EXPECT_EQ(200, response->GetStatus());
+ EXPECT_STREQ("OK", response->GetStatusText().ToString().c_str());
+ EXPECT_STREQ("text/javascript",
+ response->GetMimeType().ToString().c_str());
+
+ if (resource_response_ct_++ == 0U) {
+ // Always redirect at least one time.
+ OnResourceReceived(browser, frame, request, response);
+ return true;
+ }
+
+ OnRetryReceived(browser, frame, request, response);
+ return (resource_response_ct_ < expected_resource_response_ct_);
+ }
+
+ CefRefPtr<CefResponseFilter> GetResourceResponseFilter(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response) {
+ get_resource_response_filter_ct_++;
+ return nullptr;
+ }
+
+ void OnResourceLoadComplete(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response,
+ URLRequestStatus status,
+ int64 received_content_length) {
+ EXPECT_TRUE(CheckUrl(request->GetURL()));
+
+ // Verify the response returned by GetResourceHandler.
+ EXPECT_EQ(200, response->GetStatus());
+ EXPECT_STREQ("OK", response->GetStatusText().ToString().c_str());
+ EXPECT_STREQ("text/javascript",
+ response->GetMimeType().ToString().c_str());
+
+ resource_load_complete_ct_++;
+ }
+
+ virtual bool CheckUrl(const std::string& url) const {
+ return (url == start_url_);
+ }
+
+ virtual void CheckExpected() {
+ EXPECT_TRUE(got_resource_);
+ EXPECT_TRUE(got_resource_retry_);
+
+ EXPECT_EQ(expected_resource_response_ct_, resource_response_ct_);
+ EXPECT_EQ(expected_resource_response_ct_, get_resource_handler_ct_);
+ EXPECT_EQ(expected_resource_load_complete_ct_,
+ get_resource_response_filter_ct_);
+ EXPECT_EQ(expected_before_resource_load_ct_, before_resource_load_ct_);
+ EXPECT_EQ(expected_resource_redirect_ct_, resource_redirect_ct_);
+ EXPECT_EQ(expected_resource_load_complete_ct_,
+ resource_load_complete_ct_);
+ }
+
+ protected:
+ virtual void OnResourceReceived(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response) {
+ got_resource_.yes();
+ }
+
+ virtual void OnRetryReceived(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response) {
+ got_resource_retry_.yes();
+ }
+
+ private:
+ std::string start_url_;
+
+ size_t resource_response_ct_ = 0U;
+ size_t expected_resource_response_ct_;
+ size_t before_resource_load_ct_ = 0U;
+ size_t expected_before_resource_load_ct_;
+ size_t get_resource_handler_ct_ = 0U;
+ size_t resource_redirect_ct_ = 0U;
+ size_t expected_resource_redirect_ct_;
+ size_t get_resource_response_filter_ct_ = 0U;
+ size_t resource_load_complete_ct_ = 0U;
+ size_t expected_resource_load_complete_ct_;
+
+ TrackCallback got_resource_;
+ TrackCallback got_resource_retry_;
+ };
+
+ class UrlResourceTest : public ResourceTest {
+ public:
+ // With NetworkService we don't get an additional (unnecessary) redirect
+ // callback.
+ UrlResourceTest()
+ : ResourceTest("http://test.com/start_url.js", 2U, 2U, 1U) {
+ redirect_url_ = "http://test.com/redirect_url.js";
+ }
+
+ bool CheckUrl(const std::string& url) const override {
+ if (url == redirect_url_) {
+ return true;
+ }
+
+ return ResourceTest::CheckUrl(url);
+ }
+
+ void OnResourceRedirect(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefString& new_url) override {
+ ResourceTest::OnResourceRedirect(browser, frame, request, new_url);
+ const std::string& old_url = request->GetURL();
+ EXPECT_STREQ(start_url().c_str(), old_url.c_str());
+ EXPECT_STREQ(redirect_url_.c_str(), new_url.ToString().c_str());
+ }
+
+ private:
+ void OnResourceReceived(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response) override {
+ ResourceTest::OnResourceReceived(browser, frame, request, response);
+ request->SetURL(redirect_url_);
+ }
+
+ void OnRetryReceived(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response) override {
+ ResourceTest::OnRetryReceived(browser, frame, request, response);
+ const std::string& new_url = request->GetURL();
+ EXPECT_STREQ(redirect_url_.c_str(), new_url.c_str());
+ }
+
+ std::string redirect_url_;
+ };
+
+ class HeaderResourceTest : public ResourceTest {
+ public:
+ // With NetworkService we restart the request, so we get another call to
+ // OnBeforeResourceLoad.
+ HeaderResourceTest()
+ : ResourceTest("http://test.com/start_header.js", 2U, 2U) {
+ expected_headers_.insert(std::make_pair("Test-Key1", "Value1"));
+ expected_headers_.insert(std::make_pair("Test-Key2", "Value2"));
+ }
+
+ private:
+ void OnResourceReceived(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response) override {
+ ResourceTest::OnResourceReceived(browser, frame, request, response);
+ request->SetHeaderMap(expected_headers_);
+ }
+
+ void OnRetryReceived(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response) override {
+ ResourceTest::OnRetryReceived(browser, frame, request, response);
+ CefRequest::HeaderMap actual_headers;
+ request->GetHeaderMap(actual_headers);
+ TestMapEqual(expected_headers_, actual_headers, true);
+ }
+
+ CefRequest::HeaderMap expected_headers_;
+ };
+
+ class PostResourceTest : public ResourceTest {
+ public:
+ // With NetworkService we restart the request, so we get another call to
+ // OnBeforeResourceLoad.
+ PostResourceTest() : ResourceTest("http://test.com/start_post.js", 2U, 2U) {
+ CefRefPtr<CefPostDataElement> elem = CefPostDataElement::Create();
+ const std::string data("Test Post Data");
+ elem->SetToBytes(data.size(), data.c_str());
+
+ expected_post_ = CefPostData::Create();
+ expected_post_->AddElement(elem);
+ }
+
+ private:
+ void OnResourceReceived(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response) override {
+ ResourceTest::OnResourceReceived(browser, frame, request, response);
+ request->SetPostData(expected_post_);
+ }
+
+ void OnRetryReceived(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response) override {
+ ResourceTest::OnRetryReceived(browser, frame, request, response);
+ CefRefPtr<CefPostData> actual_post = request->GetPostData();
+ TestPostDataEqual(expected_post_, actual_post);
+ }
+
+ CefRefPtr<CefPostData> expected_post_;
+ };
+
+ class RequestContextHandler : public CefRequestContextHandler {
+ public:
+ explicit RequestContextHandler(
+ CefRefPtr<CefResourceRequestHandler> resource_request_handler)
+ : resource_request_handler_(resource_request_handler) {}
+
+ CefRefPtr<CefResourceRequestHandler> GetResourceRequestHandler(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ bool is_navigation,
+ bool is_download,
+ const CefString& request_initiator,
+ bool& disable_default_handling) override {
+ return resource_request_handler_;
+ }
+
+ private:
+ CefRefPtr<CefResourceRequestHandler> resource_request_handler_;
+
+ IMPLEMENT_REFCOUNTING(RequestContextHandler);
+ DISALLOW_COPY_AND_ASSIGN(RequestContextHandler);
+ };
+
+ class ResourceRequestHandler : public CefResourceRequestHandler {
+ public:
+ explicit ResourceRequestHandler(RedirectResponseTest* test) : test_(test) {}
+
+ cef_return_value_t OnBeforeResourceLoad(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefCallback> callback) override {
+ EXPECT_IO_THREAD();
+
+ if (IsChromeRuntimeEnabled() &&
+ request->GetResourceType() == RT_FAVICON) {
+ // Ignore favicon requests.
+ return RV_CANCEL;
+ }
+
+ EXPECT_EQ(test_->browser_id_, browser->GetIdentifier());
+
+ if (request->GetURL() == kResourceTestHtml) {
+ // All loads of the main resource should keep the same request id.
+ EXPECT_EQ(0U, main_request_id_);
+ main_request_id_ = request->GetIdentifier();
+ EXPECT_GT(main_request_id_, 0U);
+ return RV_CONTINUE;
+ }
+
+ // All redirects of the sub-resource should keep the same request id.
+ if (sub_request_id_ == 0U) {
+ sub_request_id_ = request->GetIdentifier();
+ EXPECT_GT(sub_request_id_, 0U);
+ } else {
+ EXPECT_EQ(sub_request_id_, request->GetIdentifier());
+ }
+
+ return test_->resource_test_->OnBeforeResourceLoad(browser, frame,
+ request)
+ ? RV_CANCEL
+ : RV_CONTINUE;
+ }
+
+ CefRefPtr<CefResourceHandler> GetResourceHandler(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request) override {
+ EXPECT_IO_THREAD();
+ EXPECT_EQ(test_->browser_id_, browser->GetIdentifier());
+
+ if (request->GetURL() == kResourceTestHtml) {
+ EXPECT_EQ(main_request_id_, request->GetIdentifier());
+ return test_->GetResourceHandler(browser, frame, request);
+ }
+
+ EXPECT_EQ(sub_request_id_, request->GetIdentifier());
+ return test_->resource_test_->GetResourceHandler(browser, frame, request);
+ }
+
+ void OnResourceRedirect(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response,
+ CefString& new_url) override {
+ EXPECT_IO_THREAD();
+ EXPECT_EQ(test_->browser_id_, browser->GetIdentifier());
+ EXPECT_EQ(sub_request_id_, request->GetIdentifier());
+
+ test_->resource_test_->OnResourceRedirect(browser, frame, request,
+ new_url);
+ }
+
+ bool OnResourceResponse(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response) override {
+ EXPECT_IO_THREAD();
+ EXPECT_TRUE(browser.get());
+ EXPECT_EQ(test_->browser_id_, browser->GetIdentifier());
+
+ EXPECT_TRUE(frame.get());
+ EXPECT_TRUE(frame->IsMain());
+
+ if (request->GetURL() == kResourceTestHtml) {
+ EXPECT_EQ(main_request_id_, request->GetIdentifier());
+ return false;
+ }
+
+ EXPECT_EQ(sub_request_id_, request->GetIdentifier());
+ return test_->resource_test_->OnResourceResponse(browser, frame, request,
+ response);
+ }
+
+ CefRefPtr<CefResponseFilter> GetResourceResponseFilter(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response) override {
+ EXPECT_IO_THREAD();
+ EXPECT_TRUE(browser.get());
+ EXPECT_EQ(test_->browser_id_, browser->GetIdentifier());
+
+ EXPECT_TRUE(frame.get());
+ EXPECT_TRUE(frame->IsMain());
+
+ if (request->GetURL() == kResourceTestHtml) {
+ EXPECT_EQ(main_request_id_, request->GetIdentifier());
+ return nullptr;
+ }
+
+ return test_->resource_test_->GetResourceResponseFilter(
+ browser, frame, request, response);
+ }
+
+ void OnResourceLoadComplete(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response,
+ URLRequestStatus status,
+ int64 received_content_length) override {
+ EXPECT_IO_THREAD();
+
+ if (IsChromeRuntimeEnabled() &&
+ request->GetResourceType() == RT_FAVICON) {
+ // Ignore favicon requests.
+ return;
+ }
+
+ EXPECT_TRUE(browser.get());
+ EXPECT_EQ(test_->browser_id_, browser->GetIdentifier());
+
+ EXPECT_TRUE(frame.get());
+ EXPECT_TRUE(frame->IsMain());
+
+ if (request->GetURL() == kResourceTestHtml) {
+ EXPECT_EQ(main_request_id_, request->GetIdentifier());
+ return;
+ }
+
+ EXPECT_EQ(sub_request_id_, request->GetIdentifier());
+ test_->resource_test_->OnResourceLoadComplete(
+ browser, frame, request, response, status, received_content_length);
+ }
+
+ private:
+ RedirectResponseTest* const test_;
+
+ uint64 main_request_id_ = 0U;
+ uint64 sub_request_id_ = 0U;
+
+ IMPLEMENT_REFCOUNTING(ResourceRequestHandler);
+ DISALLOW_COPY_AND_ASSIGN(ResourceRequestHandler);
+ };
+
+ const bool via_request_context_handler_;
+
+ int browser_id_ = 0;
+ std::unique_ptr<ResourceTest> resource_test_;
+ CefRefPtr<ResourceRequestHandler> resource_request_handler_;
+
+ IMPLEMENT_REFCOUNTING(RedirectResponseTest);
+};
+
+} // namespace
+
+// Verify redirect with client handler.
+TEST(ResourceRequestHandlerTest, RedirectURLViaClient) {
+ CefRefPtr<RedirectResponseTest> handler =
+ new RedirectResponseTest(RedirectResponseTest::URL, false);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Verify redirect + modified headers with client handler.
+TEST(ResourceRequestHandlerTest, RedirectHeaderViaClient) {
+ CefRefPtr<RedirectResponseTest> handler =
+ new RedirectResponseTest(RedirectResponseTest::HEADER, false);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Verify redirect + modified post data with client handler.
+TEST(ResourceRequestHandlerTest, RedirectPostViaClient) {
+ CefRefPtr<RedirectResponseTest> handler =
+ new RedirectResponseTest(RedirectResponseTest::POST, false);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Verify redirect with context handler.
+TEST(ResourceRequestHandlerTest, RedirectURLViaContext) {
+ CefRefPtr<RedirectResponseTest> handler =
+ new RedirectResponseTest(RedirectResponseTest::URL, true);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Verify redirect + modified headers with context handler.
+TEST(ResourceRequestHandlerTest, RedirectHeaderViaContext) {
+ CefRefPtr<RedirectResponseTest> handler =
+ new RedirectResponseTest(RedirectResponseTest::HEADER, true);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Verify redirect + modified post data with context handler.
+TEST(ResourceRequestHandlerTest, RedirectPostViaContext) {
+ CefRefPtr<RedirectResponseTest> handler =
+ new RedirectResponseTest(RedirectResponseTest::POST, true);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+namespace {
+
+const char kResourceTestHtml2[] = "http://test.com/resource2.html";
+
+class BeforeResourceLoadTest : public TestHandler {
+ public:
+ enum TestMode {
+ CANCEL,
+ CANCEL_ASYNC,
+ CANCEL_NAV,
+ CONTINUE,
+ CONTINUE_ASYNC,
+ };
+
+ explicit BeforeResourceLoadTest(TestMode mode) : test_mode_(mode) {}
+
+ void RunTest() override {
+ AddResource(kResourceTestHtml, "<html><body>Test</body></html>",
+ "text/html");
+ AddResource(kResourceTestHtml2, "<html><body>Test2</body></html>",
+ "text/html");
+ CreateBrowser(kResourceTestHtml);
+ SetTestTimeout();
+ }
+
+ cef_return_value_t OnBeforeResourceLoad(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefCallback> callback) override {
+ EXPECT_IO_THREAD();
+
+ if (IsChromeRuntimeEnabled() && request->GetResourceType() == RT_FAVICON) {
+ // Ignore favicon requests.
+ return RV_CANCEL;
+ }
+
+ // Allow the 2nd navigation to continue.
+ const std::string& url = request->GetURL();
+ if (url == kResourceTestHtml2) {
+ got_before_resource_load2_.yes();
+ EXPECT_EQ(CANCEL_NAV, test_mode_);
+ return RV_CONTINUE;
+ }
+
+ EXPECT_FALSE(got_before_resource_load_);
+ got_before_resource_load_.yes();
+
+ if (test_mode_ == CANCEL) {
+ // Cancel immediately.
+ return RV_CANCEL;
+ } else if (test_mode_ == CONTINUE) {
+ // Continue immediately.
+ return RV_CONTINUE;
+ } else {
+ if (test_mode_ == CANCEL_NAV) {
+ // Cancel the request by navigating to a new URL.
+ browser->GetMainFrame()->LoadURL(kResourceTestHtml2);
+ } else if (test_mode_ == CONTINUE_ASYNC) {
+ // Continue asynchronously.
+ CefPostTask(TID_UI,
+ base::BindOnce(&CefCallback::Continue, callback.get()));
+ } else {
+ // Cancel asynchronously.
+ CefPostTask(TID_UI,
+ base::BindOnce(&CefCallback::Cancel, callback.get()));
+ }
+ return RV_CONTINUE_ASYNC;
+ }
+ }
+
+ void OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int httpStatusCode) override {
+ EXPECT_UI_THREAD();
+
+ EXPECT_FALSE(got_load_end_);
+ got_load_end_.yes();
+
+ const std::string& url = frame->GetURL();
+ if (test_mode_ == CANCEL_NAV) {
+ EXPECT_STREQ(kResourceTestHtml2, url.data());
+ } else {
+ EXPECT_STREQ(kResourceTestHtml, url.data());
+ }
+
+ TestHandler::OnLoadEnd(browser, frame, httpStatusCode);
+ DestroyTest();
+ }
+
+ void OnLoadError(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ ErrorCode errorCode,
+ const CefString& errorText,
+ const CefString& failedUrl) override {
+ EXPECT_UI_THREAD();
+
+ EXPECT_FALSE(got_load_error_);
+ got_load_error_.yes();
+
+ const std::string& url = failedUrl;
+ EXPECT_STREQ(kResourceTestHtml, url.data());
+
+ TestHandler::OnLoadError(browser, frame, errorCode, errorText, failedUrl);
+ if (test_mode_ != CANCEL_NAV) {
+ DestroyTest();
+ }
+ }
+
+ void DestroyTest() override {
+ EXPECT_TRUE(got_before_resource_load_);
+
+ if (test_mode_ == CANCEL_NAV) {
+ EXPECT_TRUE(got_before_resource_load2_);
+ } else {
+ EXPECT_FALSE(got_before_resource_load2_);
+ }
+
+ if (test_mode_ == CONTINUE || test_mode_ == CONTINUE_ASYNC) {
+ EXPECT_TRUE(got_load_end_);
+ EXPECT_FALSE(got_load_error_);
+ } else if (test_mode_ == CANCEL || test_mode_ == CANCEL_ASYNC) {
+ EXPECT_FALSE(got_load_end_);
+ EXPECT_TRUE(got_load_error_);
+ }
+
+ TestHandler::DestroyTest();
+ }
+
+ private:
+ const TestMode test_mode_;
+
+ TrackCallback got_before_resource_load_;
+ TrackCallback got_before_resource_load2_;
+ TrackCallback got_load_end_;
+ TrackCallback got_load_error_;
+
+ IMPLEMENT_REFCOUNTING(BeforeResourceLoadTest);
+};
+
+} // namespace
+
+TEST(ResourceRequestHandlerTest, BeforeResourceLoadCancel) {
+ CefRefPtr<BeforeResourceLoadTest> handler =
+ new BeforeResourceLoadTest(BeforeResourceLoadTest::CANCEL);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(ResourceRequestHandlerTest, BeforeResourceLoadCancelAsync) {
+ CefRefPtr<BeforeResourceLoadTest> handler =
+ new BeforeResourceLoadTest(BeforeResourceLoadTest::CANCEL_ASYNC);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(ResourceRequestHandlerTest, BeforeResourceLoadCancelNav) {
+ CefRefPtr<BeforeResourceLoadTest> handler =
+ new BeforeResourceLoadTest(BeforeResourceLoadTest::CANCEL_NAV);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(ResourceRequestHandlerTest, BeforeResourceLoadContinue) {
+ CefRefPtr<BeforeResourceLoadTest> handler =
+ new BeforeResourceLoadTest(BeforeResourceLoadTest::CONTINUE);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(ResourceRequestHandlerTest, BeforeResourceLoadContinueAsync) {
+ CefRefPtr<BeforeResourceLoadTest> handler =
+ new BeforeResourceLoadTest(BeforeResourceLoadTest::CONTINUE_ASYNC);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+namespace {
+
+// For response filtering we need to test:
+// - Passing through content unchanged.
+// - Not reading all of the input buffer.
+// - Needing more input and getting it.
+// - Needing more input and not getting it.
+// - Filter error.
+
+const char kResponseFilterTestUrl[] = "http://tests.com/response_filter.html";
+
+size_t GetResponseBufferSize() {
+ // Match the default |capacity_num_bytes| value from
+ // mojo::Core::CreateDataPipe.
+ return 64 * 1024; // 64kb
+}
+
+const char kInputHeader[] = "<html><head></head><body>";
+const char kInputFooter[] = "</body></html>";
+
+// Repeat |content| the minimum number of times necessary to satisfy
+// |desired_min_size|. If |calculated_repeat_ct| is non-nullptr it will be set
+// to the number of times that |content| was repeated.
+std::string CreateInput(const std::string& content,
+ size_t desired_min_size,
+ size_t* calculated_repeat_ct = nullptr) {
+ const size_t header_footer_size =
+ sizeof(kInputHeader) + sizeof(kInputFooter) - 2;
+ EXPECT_GE(desired_min_size, header_footer_size + content.size());
+ desired_min_size -= header_footer_size;
+
+ size_t repeat_ct =
+ static_cast<size_t>(std::ceil(static_cast<double>(desired_min_size) /
+ static_cast<double>(content.size())));
+ if (calculated_repeat_ct) {
+ *calculated_repeat_ct = repeat_ct;
+ }
+
+ std::string result;
+ result.reserve(header_footer_size + (content.size() * repeat_ct));
+
+ result = kInputHeader;
+ while (repeat_ct--) {
+ result += content;
+ }
+ result += kInputFooter;
+
+ return result;
+}
+
+std::string CreateOutput(const std::string& content, size_t repeat_ct) {
+ const size_t header_footer_size =
+ sizeof(kInputHeader) + sizeof(kInputFooter) - 2;
+
+ std::string result;
+ result.reserve(header_footer_size + (content.size() * repeat_ct));
+
+ result = kInputHeader;
+ while (repeat_ct--) {
+ result += content;
+ }
+ result += kInputFooter;
+
+ return result;
+}
+
+// Base class for test filters.
+class ResponseFilterTestBase : public CefResponseFilter {
+ public:
+ ResponseFilterTestBase() : filter_count_(0U) {}
+
+ bool InitFilter() override {
+ EXPECT_FALSE(got_init_filter_);
+ got_init_filter_.yes();
+ return true;
+ }
+
+ FilterStatus Filter(void* data_in,
+ size_t data_in_size,
+ size_t& data_in_read,
+ void* data_out,
+ size_t data_out_size,
+ size_t& data_out_written) override {
+ if (data_in_size == 0U) {
+ EXPECT_FALSE(data_in);
+ } else {
+ EXPECT_TRUE(data_in);
+ }
+ EXPECT_EQ(data_in_read, 0U);
+ EXPECT_TRUE(data_out);
+ EXPECT_GT(data_out_size, 0U);
+ EXPECT_EQ(data_out_written, 0U);
+ filter_count_++;
+ return RESPONSE_FILTER_ERROR;
+ }
+
+ // Returns the input that will be fed into the filter.
+ virtual std::string GetInput() = 0;
+
+ // Verify the output from the filter.
+ virtual void VerifyOutput(cef_urlrequest_status_t status,
+ int64 received_content_length,
+ const std::string& received_content) {
+ EXPECT_TRUE(got_init_filter_);
+ EXPECT_GT(filter_count_, 0U);
+ }
+
+ virtual void VerifyStatusCode(int httpStatusCode) const {
+ EXPECT_TRUE(httpStatusCode == 0 || httpStatusCode == 200) << httpStatusCode;
+ }
+
+ protected:
+ TrackCallback got_init_filter_;
+ size_t filter_count_;
+
+ IMPLEMENT_REFCOUNTING(ResponseFilterTestBase);
+};
+
+// Pass through the contents unchanged.
+class ResponseFilterPassThru : public ResponseFilterTestBase {
+ public:
+ explicit ResponseFilterPassThru(bool limit_read) : limit_read_(limit_read) {}
+
+ FilterStatus Filter(void* data_in,
+ size_t data_in_size,
+ size_t& data_in_read,
+ void* data_out,
+ size_t data_out_size,
+ size_t& data_out_written) override {
+ ResponseFilterTestBase::Filter(data_in, data_in_size, data_in_read,
+ data_out, data_out_size, data_out_written);
+
+ if (limit_read_) {
+ // Read at most 1k bytes.
+ data_in_read = std::min(data_in_size, static_cast<size_t>(1024U));
+ } else {
+ // Read all available bytes.
+ data_in_read = data_in_size;
+ }
+
+ data_out_written = std::min(data_in_read, data_out_size);
+ memcpy(data_out, data_in, data_out_written);
+
+ return RESPONSE_FILTER_DONE;
+ }
+
+ std::string GetInput() override {
+ input_ = CreateInput("FOOBAR ", GetResponseBufferSize() * 2U + 1);
+ return input_;
+ }
+
+ void VerifyOutput(cef_urlrequest_status_t status,
+ int64 received_content_length,
+ const std::string& received_content) override {
+ ResponseFilterTestBase::VerifyOutput(status, received_content_length,
+ received_content);
+
+ if (limit_read_) {
+ // Expected to read 2 full buffers of GetResponseBufferSize() at 1kb
+ // increments and one partial buffer.
+ EXPECT_EQ(2U * (GetResponseBufferSize() / 1024) + 1U, filter_count_);
+ } else {
+ // Expected to read 2 full buffers of GetResponseBufferSize() and one
+ // partial buffer.
+ EXPECT_EQ(3U, filter_count_);
+ }
+ EXPECT_STREQ(input_.c_str(), received_content.c_str());
+
+ // Input size and content size should match.
+ EXPECT_EQ(input_.size(), static_cast<size_t>(received_content_length));
+ EXPECT_EQ(input_.size(), received_content.size());
+ }
+
+ private:
+ std::string input_;
+ bool limit_read_;
+};
+
+const char kFindString[] = "REPLACE_THIS_STRING";
+const char kReplaceString[] = "This is the replaced string!";
+
+// Helper for passing params to Write().
+#define WRITE_PARAMS data_out_ptr, data_out_size, data_out_written
+
+// Replace all instances of |kFindString| with |kReplaceString|.
+// This implementation is similar to the example in
+// tests/shared/response_filter_test.cc.
+class ResponseFilterNeedMore : public ResponseFilterTestBase {
+ public:
+ ResponseFilterNeedMore()
+ : find_match_offset_(0U),
+ replace_overflow_size_(0U),
+ input_size_(0U),
+ repeat_ct_(0U) {}
+
+ FilterStatus Filter(void* data_in,
+ size_t data_in_size,
+ size_t& data_in_read,
+ void* data_out,
+ size_t data_out_size,
+ size_t& data_out_written) override {
+ ResponseFilterTestBase::Filter(data_in, data_in_size, data_in_read,
+ data_out, data_out_size, data_out_written);
+
+ // All data will be read.
+ data_in_read = data_in_size;
+
+ const size_t find_size = sizeof(kFindString) - 1;
+
+ const char* data_in_ptr = static_cast<char*>(data_in);
+ char* data_out_ptr = static_cast<char*>(data_out);
+
+ // Reset the overflow.
+ std::string old_overflow;
+ if (!overflow_.empty()) {
+ old_overflow = overflow_;
+ overflow_.clear();
+ }
+
+ const size_t likely_out_size =
+ data_in_size + replace_overflow_size_ + old_overflow.size();
+ if (data_out_size < likely_out_size) {
+ // We'll likely need to use the overflow buffer. Size it appropriately.
+ overflow_.reserve(likely_out_size - data_out_size);
+ }
+
+ if (!old_overflow.empty()) {
+ // Write the overflow from last time.
+ Write(old_overflow.c_str(), old_overflow.size(), WRITE_PARAMS);
+ }
+
+ // Evaluate each character in the input buffer. Track how many characters in
+ // a row match kFindString. If kFindString is completely matched then write
+ // kReplaceString. Otherwise, write the input characters as-is.
+ for (size_t i = 0U; i < data_in_size; ++i) {
+ if (data_in_ptr[i] == kFindString[find_match_offset_]) {
+ // Matched the next character in the find string.
+ if (++find_match_offset_ == find_size) {
+ // Complete match of the find string. Write the replace string.
+ Write(kReplaceString, sizeof(kReplaceString) - 1, WRITE_PARAMS);
+
+ // Start over looking for a match.
+ find_match_offset_ = 0;
+ }
+ continue;
+ }
+
+ // Character did not match the find string.
+ if (find_match_offset_ > 0) {
+ // Write the portion of the find string that has matched so far.
+ Write(kFindString, find_match_offset_, WRITE_PARAMS);
+
+ // Start over looking for a match.
+ find_match_offset_ = 0;
+ }
+
+ // Write the current character.
+ Write(&data_in_ptr[i], 1, WRITE_PARAMS);
+ }
+
+ // If a match is currently in-progress and input was provided then we need
+ // more data. Otherwise, we're done.
+ return find_match_offset_ > 0 && data_in_size > 0
+ ? RESPONSE_FILTER_NEED_MORE_DATA
+ : RESPONSE_FILTER_DONE;
+ }
+
+ std::string GetInput() override {
+ const std::string& input =
+ CreateInput(std::string(kFindString) + " ",
+ GetResponseBufferSize() * 2U + 1, &repeat_ct_);
+ input_size_ = input.size();
+
+ const size_t find_size = sizeof(kFindString) - 1;
+ const size_t replace_size = sizeof(kReplaceString) - 1;
+
+ // Determine a reasonable amount of space for find/replace overflow.
+ if (replace_size > find_size) {
+ replace_overflow_size_ = (replace_size - find_size) * repeat_ct_;
+ }
+
+ return input;
+ }
+
+ void VerifyOutput(cef_urlrequest_status_t status,
+ int64 received_content_length,
+ const std::string& received_content) override {
+ ResponseFilterTestBase::VerifyOutput(status, received_content_length,
+ received_content);
+
+ const std::string& output =
+ CreateOutput(std::string(kReplaceString) + " ", repeat_ct_);
+ EXPECT_STREQ(output.c_str(), received_content.c_str());
+
+ // Pre-filter content length should be the original input size.
+ EXPECT_EQ(input_size_, static_cast<size_t>(received_content_length));
+
+ // Filtered content length should be the output size.
+ EXPECT_EQ(output.size(), received_content.size());
+
+ // Expected to read 2 full buffers of GetResponseBufferSize() and one
+ // partial buffer, and then one additional call to drain the overflow.
+ EXPECT_EQ(4U, filter_count_);
+ }
+
+ private:
+ inline void Write(const char* str,
+ size_t str_size,
+ char*& data_out_ptr,
+ size_t data_out_size,
+ size_t& data_out_written) {
+ // Number of bytes remaining in the output buffer.
+ const size_t remaining_space = data_out_size - data_out_written;
+ // Maximum number of bytes we can write into the output buffer.
+ const size_t max_write = std::min(str_size, remaining_space);
+
+ // Write the maximum portion that fits in the output buffer.
+ if (max_write == 1) {
+ // Small optimization for single character writes.
+ *data_out_ptr = str[0];
+ data_out_ptr += 1;
+ data_out_written += 1;
+ } else if (max_write > 1) {
+ memcpy(data_out_ptr, str, max_write);
+ data_out_ptr += max_write;
+ data_out_written += max_write;
+ }
+
+ if (max_write < str_size) {
+ // Need to write more bytes than will fit in the output buffer. Store the
+ // remainder in the overflow buffer.
+ overflow_ += std::string(str + max_write, str_size - max_write);
+ }
+ }
+
+ // The portion of the find string that is currently matching.
+ size_t find_match_offset_;
+
+ // The likely amount of overflow.
+ size_t replace_overflow_size_;
+
+ // Overflow from the output buffer.
+ std::string overflow_;
+
+ // The original input size.
+ size_t input_size_;
+
+ // The number of times the find string was repeated.
+ size_t repeat_ct_;
+};
+
+// Return a filter error.
+class ResponseFilterError : public ResponseFilterTestBase {
+ public:
+ ResponseFilterError() {}
+
+ FilterStatus Filter(void* data_in,
+ size_t data_in_size,
+ size_t& data_in_read,
+ void* data_out,
+ size_t data_out_size,
+ size_t& data_out_written) override {
+ ResponseFilterTestBase::Filter(data_in, data_in_size, data_in_read,
+ data_out, data_out_size, data_out_written);
+
+ return RESPONSE_FILTER_ERROR;
+ }
+
+ std::string GetInput() override {
+ return kInputHeader + std::string("ERROR") + kInputFooter;
+ }
+
+ void VerifyOutput(cef_urlrequest_status_t status,
+ int64 received_content_length,
+ const std::string& received_content) override {
+ ResponseFilterTestBase::VerifyOutput(status, received_content_length,
+ received_content);
+
+ EXPECT_EQ(UR_FAILED, status);
+
+ // Expect empty content.
+ EXPECT_STREQ("", received_content.c_str());
+ EXPECT_EQ(0U, received_content_length);
+
+ // Expect to only be called one time.
+ EXPECT_EQ(filter_count_, 1U);
+ }
+
+ void VerifyStatusCode(int httpStatusCode) const override {
+ EXPECT_EQ(ERR_CONTENT_DECODING_FAILED, httpStatusCode);
+ }
+};
+
+class ResponseFilterTestHandler : public TestHandler {
+ public:
+ explicit ResponseFilterTestHandler(
+ CefRefPtr<ResponseFilterTestBase> response_filter)
+ : response_filter_(response_filter) {}
+
+ void RunTest() override {
+ const std::string& resource = response_filter_->GetInput();
+ AddResource(kResponseFilterTestUrl, resource, "text/html");
+
+ // Create the browser.
+ CreateBrowser(kResponseFilterTestUrl);
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout();
+ }
+
+ CefRefPtr<CefResponseFilter> GetResourceResponseFilter(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response) override {
+ EXPECT_IO_THREAD();
+
+ DCHECK(!got_resource_response_filter_);
+ got_resource_response_filter_.yes();
+ return response_filter_;
+ }
+
+ void OnResourceLoadComplete(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response,
+ URLRequestStatus status,
+ int64 received_content_length) override {
+ EXPECT_IO_THREAD();
+
+ if (IsChromeRuntimeEnabled() && request->GetResourceType() == RT_FAVICON) {
+ // Ignore favicon requests.
+ return;
+ }
+
+ DCHECK(!got_resource_load_complete_);
+ got_resource_load_complete_.yes();
+
+ status_ = status;
+ received_content_length_ = received_content_length;
+ }
+
+ void OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int httpStatusCode) override {
+ DCHECK(!got_load_end_);
+ got_load_end_.yes();
+
+ response_filter_->VerifyStatusCode(httpStatusCode);
+
+ GetOutputContent(frame);
+ }
+
+ private:
+ // Retrieve the output content using a StringVisitor. This effectively
+ // serializes the DOM from the renderer process so any comparison to the
+ // filter output is somewhat error-prone.
+ void GetOutputContent(CefRefPtr<CefFrame> frame) {
+ class StringVisitor : public CefStringVisitor {
+ public:
+ using VisitorCallback =
+ base::OnceCallback<void(const std::string& /*received_content*/)>;
+
+ explicit StringVisitor(VisitorCallback callback)
+ : callback_(std::move(callback)) {}
+
+ void Visit(const CefString& string) override {
+ std::move(callback_).Run(string);
+ }
+
+ private:
+ VisitorCallback callback_;
+
+ IMPLEMENT_REFCOUNTING(StringVisitor);
+ };
+
+ frame->GetSource(new StringVisitor(
+ base::BindOnce(&ResponseFilterTestHandler::VerifyOutput, this)));
+ }
+
+ void VerifyOutput(const std::string& received_content) {
+ response_filter_->VerifyOutput(status_, received_content_length_,
+ received_content);
+ response_filter_ = nullptr;
+
+ DestroyTest();
+ }
+
+ void DestroyTest() override {
+ EXPECT_TRUE(got_resource_response_filter_);
+ EXPECT_TRUE(got_resource_load_complete_);
+ EXPECT_TRUE(got_load_end_);
+
+ TestHandler::DestroyTest();
+ }
+
+ CefRefPtr<ResponseFilterTestBase> response_filter_;
+
+ TrackCallback got_resource_response_filter_;
+ TrackCallback got_resource_load_complete_;
+ TrackCallback got_load_end_;
+
+ URLRequestStatus status_;
+ int64 received_content_length_;
+
+ IMPLEMENT_REFCOUNTING(ResponseFilterTestHandler);
+};
+
+} // namespace
+
+// Pass through contents unchanged. Read all available input.
+TEST(ResourceRequestHandlerTest, FilterPassThruReadAll) {
+ CefRefPtr<ResponseFilterTestHandler> handler =
+ new ResponseFilterTestHandler(new ResponseFilterPassThru(false));
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Pass through contents unchanged. Read limited input.
+TEST(ResourceRequestHandlerTest, FilterPassThruReadLimited) {
+ CefRefPtr<ResponseFilterTestHandler> handler =
+ new ResponseFilterTestHandler(new ResponseFilterPassThru(true));
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Find/replace contents such that we occasionally need more data.
+TEST(ResourceRequestHandlerTest, FilterNeedMore) {
+ CefRefPtr<ResponseFilterTestHandler> handler =
+ new ResponseFilterTestHandler(new ResponseFilterNeedMore());
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Error during filtering.
+TEST(ResourceRequestHandlerTest, FilterError) {
+ CefRefPtr<ResponseFilterTestHandler> handler =
+ new ResponseFilterTestHandler(new ResponseFilterError());
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Entry point for registering custom schemes.
+// Called from client_app_delegates.cc.
+void RegisterResourceRequestHandlerCustomSchemes(
+ CefRawPtr<CefSchemeRegistrar> registrar) {
+ // Add a custom standard scheme.
+ registrar->AddCustomScheme(
+ "rrhcustom", CEF_SCHEME_OPTION_STANDARD | CEF_SCHEME_OPTION_CORS_ENABLED);
+}
diff --git a/tests/ceftests/resource_util_linux.cc b/tests/ceftests/resource_util_linux.cc
new file mode 100644
index 00000000..110d09bd
--- /dev/null
+++ b/tests/ceftests/resource_util_linux.cc
@@ -0,0 +1,37 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors.
+// Portions copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "tests/shared/browser/resource_util.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+namespace client {
+
+bool GetResourceDir(std::string& dir) {
+ char buff[1024];
+
+ // Retrieve the executable path.
+ ssize_t len = readlink("/proc/self/exe", buff, sizeof(buff) - 1);
+ if (len == -1) {
+ return false;
+ }
+
+ buff[len] = 0;
+
+ // Remove the executable name from the path.
+ char* pos = strrchr(buff, '/');
+ if (!pos) {
+ return false;
+ }
+
+ // Add "ceftests_files" to the path.
+ strcpy(pos + 1, "ceftests_files");
+ dir = std::string(buff);
+ return true;
+}
+
+} // namespace client
diff --git a/tests/ceftests/resource_util_win_dir.cc b/tests/ceftests/resource_util_win_dir.cc
new file mode 100644
index 00000000..3df18d5e
--- /dev/null
+++ b/tests/ceftests/resource_util_win_dir.cc
@@ -0,0 +1,36 @@
+// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/shared/browser/resource_util.h"
+
+#include <windows.h>
+
+#include "include/internal/cef_string_wrappers.h"
+
+namespace client {
+
+bool GetResourceDir(std::string& dir) {
+ wchar_t buff[MAX_PATH];
+
+ // Retrieve the executable path.
+ auto len = GetModuleFileName(nullptr, buff, MAX_PATH);
+ if (len == 0) {
+ return false;
+ }
+
+ buff[len] = 0;
+
+ // Remove the executable name from the path.
+ auto* pos = wcsrchr(buff, L'\\');
+ if (!pos) {
+ return false;
+ }
+
+ // Add "ceftests_files" to the path.
+ wcscpy(pos + 1, L"ceftests_files");
+ dir = CefStringWide(buff).ToString();
+ return true;
+}
+
+} // namespace client
diff --git a/tests/ceftests/resource_util_win_idmap.cc b/tests/ceftests/resource_util_win_idmap.cc
new file mode 100644
index 00000000..33a684b4
--- /dev/null
+++ b/tests/ceftests/resource_util_win_idmap.cc
@@ -0,0 +1,33 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include <cstring>
+
+#include "tests/ceftests/resource.h"
+
+namespace client {
+
+int GetResourceId(const char* resource_name) {
+ // Map of resource labels to BINARY id values.
+ static struct _resource_map {
+ const char* name;
+ int id;
+ } resource_map[] = {
+ {"osr_test.html", IDS_OSRTEST_HTML},
+ {"pdf.html", IDS_PDF_HTML},
+ {"pdf.pdf", IDS_PDF_PDF},
+ {"window_icon.1x.png", IDS_WINDOW_ICON_1X_PNG},
+ {"window_icon.2x.png", IDS_WINDOW_ICON_2X_PNG},
+ };
+
+ for (size_t i = 0; i < sizeof(resource_map) / sizeof(_resource_map); ++i) {
+ if (!strcmp(resource_map[i].name, resource_name)) {
+ return resource_map[i].id;
+ }
+ }
+
+ return 0;
+}
+
+} // namespace client
diff --git a/tests/ceftests/resources/mac/English.lproj/InfoPlist.strings b/tests/ceftests/resources/mac/English.lproj/InfoPlist.strings
new file mode 100644
index 00000000..fe2abe11
--- /dev/null
+++ b/tests/ceftests/resources/mac/English.lproj/InfoPlist.strings
@@ -0,0 +1,3 @@
+/* Localized versions of Info.plist keys */
+
+NSHumanReadableCopyright = "© Chromium Embedded Framework Authors, 2010";
diff --git a/tests/ceftests/resources/mac/English.lproj/MainMenu.xib b/tests/ceftests/resources/mac/English.lproj/MainMenu.xib
new file mode 100644
index 00000000..bd8a2c07
--- /dev/null
+++ b/tests/ceftests/resources/mac/English.lproj/MainMenu.xib
@@ -0,0 +1,330 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="10117" systemVersion="16B2657" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
+ <dependencies>
+ <deployment version="1090" identifier="macosx"/>
+ <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="10117"/>
+ </dependencies>
+ <objects>
+ <customObject id="-2" userLabel="File's Owner" customClass="NSApplication"/>
+ <customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
+ <customObject id="-3" userLabel="Application"/>
+ <menu title="AMainMenu" systemMenu="main" id="29" userLabel="MainMenu">
+ <items>
+ <menuItem title="cefclient" id="56">
+ <menu key="submenu" title="TestShell" systemMenu="apple" id="57">
+ <items>
+ <menuItem title="About cefclient" id="58">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="orderFrontStandardAboutPanel:" target="-2" id="142"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="236">
+ <modifierMask key="keyEquivalentModifierMask" command="YES"/>
+ </menuItem>
+ <menuItem title="Preferences…" keyEquivalent="," id="129" userLabel="121"/>
+ <menuItem isSeparatorItem="YES" id="143">
+ <modifierMask key="keyEquivalentModifierMask" command="YES"/>
+ </menuItem>
+ <menuItem title="Services" id="131">
+ <menu key="submenu" title="Services" systemMenu="services" id="130"/>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="144">
+ <modifierMask key="keyEquivalentModifierMask" command="YES"/>
+ </menuItem>
+ <menuItem title="Hide cefclient" keyEquivalent="h" id="134">
+ <connections>
+ <action selector="hide:" target="-1" id="367"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Hide Others" keyEquivalent="h" id="145">
+ <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
+ <connections>
+ <action selector="hideOtherApplications:" target="-1" id="368"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Show All" id="150">
+ <connections>
+ <action selector="unhideAllApplications:" target="-1" id="370"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="149">
+ <modifierMask key="keyEquivalentModifierMask" command="YES"/>
+ </menuItem>
+ <menuItem title="Quit cefclient" keyEquivalent="q" id="136" userLabel="1111">
+ <connections>
+ <action selector="terminate:" target="-1" id="369"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="File" id="83">
+ <menu key="submenu" title="File" id="81">
+ <items>
+ <menuItem title="New" keyEquivalent="n" id="82" userLabel="9">
+ <connections>
+ <action selector="newDocument:" target="-1" id="373"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Open…" keyEquivalent="o" id="72">
+ <connections>
+ <action selector="openDocument:" target="-1" id="374"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Open Recent" id="124">
+ <menu key="submenu" title="Open Recent" systemMenu="recentDocuments" id="125">
+ <items>
+ <menuItem title="Clear Menu" id="126">
+ <connections>
+ <action selector="clearRecentDocuments:" target="-1" id="127"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="79" userLabel="7">
+ <modifierMask key="keyEquivalentModifierMask" command="YES"/>
+ </menuItem>
+ <menuItem title="Close" keyEquivalent="w" id="73" userLabel="1">
+ <connections>
+ <action selector="performClose:" target="-1" id="193"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Save" keyEquivalent="s" id="75" userLabel="3">
+ <connections>
+ <action selector="saveDocument:" target="-1" id="362"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Save As…" keyEquivalent="S" id="80" userLabel="8">
+ <modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
+ <connections>
+ <action selector="saveDocumentAs:" target="-1" id="363"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Revert to Saved" id="112" userLabel="10">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="revertDocumentToSaved:" target="-1" id="364"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="74" userLabel="2">
+ <modifierMask key="keyEquivalentModifierMask" command="YES"/>
+ </menuItem>
+ <menuItem title="Page Setup..." keyEquivalent="P" id="77" userLabel="5">
+ <modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
+ <connections>
+ <action selector="runPageLayout:" target="-1" id="87"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Print…" keyEquivalent="p" id="78" userLabel="6">
+ <connections>
+ <action selector="print:" target="-1" id="86"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="Edit" id="217">
+ <menu key="submenu" title="Edit" id="205">
+ <items>
+ <menuItem title="Undo" keyEquivalent="z" id="207">
+ <connections>
+ <action selector="undo:" target="-1" id="223"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Redo" keyEquivalent="Z" id="215">
+ <modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
+ <connections>
+ <action selector="redo:" target="-1" id="231"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="206">
+ <modifierMask key="keyEquivalentModifierMask" command="YES"/>
+ </menuItem>
+ <menuItem title="Cut" keyEquivalent="x" id="199">
+ <connections>
+ <action selector="cut:" target="-1" id="228"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Copy" keyEquivalent="c" id="197">
+ <connections>
+ <action selector="copy:" target="-1" id="224"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Paste" keyEquivalent="v" id="203">
+ <connections>
+ <action selector="paste:" target="-1" id="226"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Delete" id="202">
+ <connections>
+ <action selector="delete:" target="-1" id="235"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Select All" keyEquivalent="a" id="198">
+ <connections>
+ <action selector="selectAll:" target="-1" id="232"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="214">
+ <modifierMask key="keyEquivalentModifierMask" command="YES"/>
+ </menuItem>
+ <menuItem title="Find" id="218">
+ <menu key="submenu" title="Find" id="220">
+ <items>
+ <menuItem title="Find…" tag="1" keyEquivalent="f" id="209">
+ <connections>
+ <action selector="performFindPanelAction:" target="-1" id="241"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Find Next" tag="2" keyEquivalent="g" id="208"/>
+ <menuItem title="Find Previous" tag="3" keyEquivalent="G" id="213">
+ <modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
+ </menuItem>
+ <menuItem title="Use Selection for Find" tag="7" keyEquivalent="e" id="221"/>
+ <menuItem title="Jump to Selection" keyEquivalent="j" id="210">
+ <connections>
+ <action selector="centerSelectionInVisibleArea:" target="-1" id="245"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="Spelling and Grammar" id="216">
+ <menu key="submenu" title="Spelling and Grammar" id="200">
+ <items>
+ <menuItem title="Show Spelling…" keyEquivalent=":" id="204">
+ <connections>
+ <action selector="showGuessPanel:" target="-1" id="230"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Check Spelling" keyEquivalent=";" id="201">
+ <connections>
+ <action selector="checkSpelling:" target="-1" id="225"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Check Spelling While Typing" id="219">
+ <connections>
+ <action selector="toggleContinuousSpellChecking:" target="-1" id="222"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Check Grammar With Spelling" id="346">
+ <connections>
+ <action selector="toggleGrammarChecking:" target="-1" id="347"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="Substitutions" id="348">
+ <menu key="submenu" title="Substitutions" id="349">
+ <items>
+ <menuItem title="Smart Copy/Paste" tag="1" keyEquivalent="f" id="350">
+ <connections>
+ <action selector="toggleSmartInsertDelete:" target="-1" id="355"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Smart Quotes" tag="2" keyEquivalent="g" id="351">
+ <connections>
+ <action selector="toggleAutomaticQuoteSubstitution:" target="-1" id="356"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Smart Links" tag="3" keyEquivalent="G" id="354">
+ <modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
+ <connections>
+ <action selector="toggleAutomaticLinkDetection:" target="-1" id="357"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="Speech" id="211">
+ <menu key="submenu" title="Speech" id="212">
+ <items>
+ <menuItem title="Start Speaking" id="196">
+ <connections>
+ <action selector="startSpeaking:" target="-1" id="233"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Stop Speaking" id="195">
+ <connections>
+ <action selector="stopSpeaking:" target="-1" id="227"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="Format" id="299">
+ <menu key="submenu" title="Format" id="300">
+ <items>
+ <menuItem title="Show Fonts" keyEquivalent="t" id="344"/>
+ <menuItem title="Show Colors" keyEquivalent="C" id="345">
+ <modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
+ <connections>
+ <action selector="orderFrontColorPanel:" target="-1" id="361"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="View" id="295">
+ <menu key="submenu" title="View" id="296">
+ <items>
+ <menuItem title="Show Toolbar" keyEquivalent="t" id="297">
+ <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
+ <connections>
+ <action selector="toggleToolbarShown:" target="-1" id="366"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Customize Toolbar…" id="298">
+ <connections>
+ <action selector="runToolbarCustomizationPalette:" target="-1" id="365"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="Window" id="19">
+ <menu key="submenu" title="Window" systemMenu="window" id="24">
+ <items>
+ <menuItem title="Minimize" keyEquivalent="m" id="23">
+ <connections>
+ <action selector="performMiniaturize:" target="-1" id="37"/>
+ </connections>
+ </menuItem>
+ <menuItem title="Zoom" id="239">
+ <connections>
+ <action selector="performZoom:" target="-1" id="240"/>
+ </connections>
+ </menuItem>
+ <menuItem isSeparatorItem="YES" id="92">
+ <modifierMask key="keyEquivalentModifierMask" command="YES"/>
+ </menuItem>
+ <menuItem title="Bring All to Front" id="5">
+ <connections>
+ <action selector="arrangeInFront:" target="-1" id="39"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ <menuItem title="Help" id="103" userLabel="1">
+ <menu key="submenu" title="Help" id="106" userLabel="2">
+ <items>
+ <menuItem title="cefclient Help" keyEquivalent="?" id="111">
+ <connections>
+ <action selector="showHelp:" target="-1" id="360"/>
+ </connections>
+ </menuItem>
+ </items>
+ </menu>
+ </menuItem>
+ </items>
+ </menu>
+ <userDefaultsController representsSharedInstance="YES" id="389"/>
+ </objects>
+</document>
diff --git a/tests/ceftests/resources/mac/Info.plist b/tests/ceftests/resources/mac/Info.plist
new file mode 100644
index 00000000..7103cade
--- /dev/null
+++ b/tests/ceftests/resources/mac/Info.plist
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleIconFile</key>
+ <string>ceftests.icns</string>
+ <key>CFBundleIdentifier</key>
+ <string>org.cef.ceftests</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1.0</string>
+ <key>LSEnvironment</key>
+ <dict>
+ <key>MallocNanoZone</key>
+ <string>0</string>
+ </dict>
+ <key>LSMinimumSystemVersion</key>
+ <string>10.13.0</string>
+ <key>NSMainNibFile</key>
+ <string>MainMenu</string>
+ <key>NSPrincipalClass</key>
+ <string>NSApplication</string>
+ <key>NSSupportsAutomaticGraphicsSwitching</key>
+ <true/>
+</dict>
+</plist>
diff --git a/tests/ceftests/resources/mac/ceftests.icns b/tests/ceftests/resources/mac/ceftests.icns
new file mode 100644
index 00000000..f36742de
--- /dev/null
+++ b/tests/ceftests/resources/mac/ceftests.icns
Binary files differ
diff --git a/tests/ceftests/resources/mac/helper-Info.plist b/tests/ceftests/resources/mac/helper-Info.plist
new file mode 100644
index 00000000..d44d0d0a
--- /dev/null
+++ b/tests/ceftests/resources/mac/helper-Info.plist
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>en</string>
+ <key>CFBundleDisplayName</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleIdentifier</key>
+ <string>org.cef.ceftests.helper${BUNDLE_ID_SUFFIX}</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>LSEnvironment</key>
+ <dict>
+ <key>MallocNanoZone</key>
+ <string>0</string>
+ </dict>
+ <key>LSFileQuarantineEnabled</key>
+ <true/>
+ <key>LSMinimumSystemVersion</key>
+ <string>10.13.0</string>
+ <key>LSUIElement</key>
+ <string>1</string>
+ <key>NSSupportsAutomaticGraphicsSwitching</key>
+ <true/>
+</dict>
+</plist>
diff --git a/tests/ceftests/resources/win/ceftests.exe.manifest b/tests/ceftests/resources/win/ceftests.exe.manifest
new file mode 100644
index 00000000..d36f084b
--- /dev/null
+++ b/tests/ceftests/resources/win/ceftests.exe.manifest
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+
+ <!--The compatibility section will be merged from build/win/compatibility.manifest -->
+
+ <dependency>
+ <dependentAssembly>
+ <assemblyIdentity type="Win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"></assemblyIdentity>
+ </dependentAssembly>
+ </dependency>
+
+ <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
+ <security>
+ <requestedPrivileges>
+ <requestedExecutionLevel level="asInvoker" />
+ </requestedPrivileges>
+ </security>
+ </trustInfo>
+
+</assembly>
diff --git a/tests/ceftests/resources/win/ceftests.ico b/tests/ceftests/resources/win/ceftests.ico
new file mode 100644
index 00000000..d551aa3a
--- /dev/null
+++ b/tests/ceftests/resources/win/ceftests.ico
Binary files differ
diff --git a/tests/ceftests/resources/win/ceftests.rc b/tests/ceftests/resources/win/ceftests.rc
new file mode 100644
index 00000000..841b8ebc
--- /dev/null
+++ b/tests/ceftests/resources/win/ceftests.rc
@@ -0,0 +1,126 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "tests/ceftests/resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#define APSTUDIO_HIDDEN_SYMBOLS
+#include "windows.h"
+#include "include/cef_version.h"
+#undef APSTUDIO_HIDDEN_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Binary
+//
+
+IDS_OSRTEST_HTML BINARY "..\\..\\..\\shared\\resources\\osr_test.html"
+IDS_PDF_HTML BINARY "..\\..\\..\\shared\\resources\\pdf.html"
+IDS_PDF_PDF BINARY "..\\..\\..\\shared\\resources\\pdf.pdf"
+IDS_WINDOW_ICON_1X_PNG BINARY "..\\..\\..\\shared\\resources\\window_icon.1x.png"
+IDS_WINDOW_ICON_2X_PNG BINARY "..\\..\\..\\shared\\resources\\window_icon.2x.png"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+ICI_UNITTESTS ICON "ceftests.ico"
+IDI_SMALL ICON "small.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION CEF_VERSION_MAJOR,CEF_VERSION_MINOR,CEF_VERSION_PATCH,0
+ PRODUCTVERSION CEF_VERSION_MAJOR,CEF_VERSION_MINOR,CEF_VERSION_PATCH,0
+ FILEFLAGSMASK 0x17L
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "FileDescription", "Chromium Embedded Framework (CEF) Unit Test Application"
+ VALUE "FileVersion", CEF_VERSION
+ VALUE "InternalName", "ceftests"
+ VALUE "LegalCopyright", "Copyright (C) " MAKE_STRING(COPYRIGHT_YEAR) " The Chromium Embedded Framework Authors"
+ VALUE "OriginalFilename", "ceftests.exe"
+ VALUE "ProductName", "Chromium Embedded Framework (CEF) Unit Test Application"
+ VALUE "ProductVersion", CEF_VERSION
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#define APSTUDIO_HIDDEN_SYMBOLS\r\n"
+ "#include ""windows.h""\r\n"
+ "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/tests/ceftests/resources/win/small.ico b/tests/ceftests/resources/win/small.ico
new file mode 100644
index 00000000..d551aa3a
--- /dev/null
+++ b/tests/ceftests/resources/win/small.ico
Binary files differ
diff --git a/tests/ceftests/response_unittest.cc b/tests/ceftests/response_unittest.cc
new file mode 100644
index 00000000..4ef70be8
--- /dev/null
+++ b/tests/ceftests/response_unittest.cc
@@ -0,0 +1,71 @@
+// Copyright (c) 2019 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "include/cef_response.h"
+#include "tests/ceftests/test_util.h"
+#include "tests/gtest/include/gtest/gtest.h"
+
+TEST(ResponseTest, SetGetHeaderByName) {
+ CefRefPtr<CefResponse> response(CefResponse::Create());
+ EXPECT_TRUE(response.get() != nullptr);
+
+ CefResponse::HeaderMap headers, expectedHeaders;
+
+ response->SetHeaderByName("HeaderA", "ValueA", false);
+ response->SetHeaderByName("HeaderB", "ValueB", false);
+
+ expectedHeaders.insert(std::make_pair("HeaderA", "ValueA"));
+ expectedHeaders.insert(std::make_pair("HeaderB", "ValueB"));
+
+ // Case insensitive retrieval.
+ EXPECT_STREQ("ValueA",
+ response->GetHeaderByName("headera").ToString().c_str());
+ EXPECT_STREQ("ValueB",
+ response->GetHeaderByName("headerb").ToString().c_str());
+ EXPECT_STREQ("", response->GetHeaderByName("noexist").ToString().c_str());
+
+ response->GetHeaderMap(headers);
+ TestMapEqual(expectedHeaders, headers, false);
+
+ // Replace an existing value.
+ response->SetHeaderByName("HeaderA", "ValueANew", true);
+
+ expectedHeaders.clear();
+ expectedHeaders.insert(std::make_pair("HeaderA", "ValueANew"));
+ expectedHeaders.insert(std::make_pair("HeaderB", "ValueB"));
+
+ // Case insensitive retrieval.
+ EXPECT_STREQ("ValueANew",
+ response->GetHeaderByName("headerA").ToString().c_str());
+
+ response->GetHeaderMap(headers);
+ TestMapEqual(expectedHeaders, headers, false);
+
+ // Header with multiple values.
+ expectedHeaders.clear();
+ expectedHeaders.insert(std::make_pair("HeaderA", "ValueA1"));
+ expectedHeaders.insert(std::make_pair("HeaderA", "ValueA2"));
+ expectedHeaders.insert(std::make_pair("HeaderB", "ValueB"));
+ response->SetHeaderMap(expectedHeaders);
+
+ // When there are multiple values only the first is returned.
+ EXPECT_STREQ("ValueA1",
+ response->GetHeaderByName("headera").ToString().c_str());
+
+ // Don't overwrite the value.
+ response->SetHeaderByName("HeaderA", "ValueANew", false);
+
+ response->GetHeaderMap(headers);
+ TestMapEqual(expectedHeaders, headers, false);
+
+ // Overwrite the value (remove the duplicates).
+ response->SetHeaderByName("HeaderA", "ValueANew", true);
+
+ expectedHeaders.clear();
+ expectedHeaders.insert(std::make_pair("HeaderA", "ValueANew"));
+ expectedHeaders.insert(std::make_pair("HeaderB", "ValueB"));
+
+ response->GetHeaderMap(headers);
+ TestMapEqual(expectedHeaders, headers, false);
+}
diff --git a/tests/ceftests/routing_test_handler.cc b/tests/ceftests/routing_test_handler.cc
new file mode 100644
index 00000000..7702aafd
--- /dev/null
+++ b/tests/ceftests/routing_test_handler.cc
@@ -0,0 +1,108 @@
+// Copyright (c) 2014 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/ceftests/routing_test_handler.h"
+#include "tests/shared/renderer/client_app_renderer.h"
+
+using client::ClientAppRenderer;
+
+namespace {
+
+void SetRouterConfig(CefMessageRouterConfig& config) {
+ config.js_query_function = "testQuery";
+ config.js_cancel_function = "testQueryCancel";
+}
+
+// Handle the renderer side of the routing implementation.
+class RoutingRenderDelegate : public ClientAppRenderer::Delegate {
+ public:
+ RoutingRenderDelegate() {}
+
+ void OnWebKitInitialized(CefRefPtr<ClientAppRenderer> app) override {
+ // Create the renderer-side router for query handling.
+ CefMessageRouterConfig config;
+ SetRouterConfig(config);
+ message_router_ = CefMessageRouterRendererSide::Create(config);
+ }
+
+ void OnContextCreated(CefRefPtr<ClientAppRenderer> app,
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefV8Context> context) override {
+ message_router_->OnContextCreated(browser, frame, context);
+ }
+
+ void OnContextReleased(CefRefPtr<ClientAppRenderer> app,
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefV8Context> context) override {
+ message_router_->OnContextReleased(browser, frame, context);
+ }
+
+ bool OnProcessMessageReceived(CefRefPtr<ClientAppRenderer> app,
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefProcessId source_process,
+ CefRefPtr<CefProcessMessage> message) override {
+ return message_router_->OnProcessMessageReceived(browser, frame,
+ source_process, message);
+ }
+
+ private:
+ CefRefPtr<CefMessageRouterRendererSide> message_router_;
+
+ IMPLEMENT_REFCOUNTING(RoutingRenderDelegate);
+};
+
+} // namespace
+
+RoutingTestHandler::RoutingTestHandler(CompletionState* completion_state)
+ : TestHandler(completion_state) {}
+
+void RoutingTestHandler::OnAfterCreated(CefRefPtr<CefBrowser> browser) {
+ if (!message_router_.get()) {
+ // Create the browser-side router for query handling.
+ CefMessageRouterConfig config;
+ SetRouterConfig(config);
+ message_router_ = CefMessageRouterBrowserSide::Create(config);
+ message_router_->AddHandler(this, false);
+ }
+ TestHandler::OnAfterCreated(browser);
+}
+
+void RoutingTestHandler::OnBeforeClose(CefRefPtr<CefBrowser> browser) {
+ message_router_->OnBeforeClose(browser);
+ TestHandler::OnBeforeClose(browser);
+}
+
+void RoutingTestHandler::OnRenderProcessTerminated(
+ CefRefPtr<CefBrowser> browser,
+ TerminationStatus status) {
+ message_router_->OnRenderProcessTerminated(browser);
+}
+
+bool RoutingTestHandler::OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ bool user_gesture,
+ bool is_redirect) {
+ message_router_->OnBeforeBrowse(browser, frame);
+ return false;
+}
+
+bool RoutingTestHandler::OnProcessMessageReceived(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefProcessId source_process,
+ CefRefPtr<CefProcessMessage> message) {
+ return message_router_->OnProcessMessageReceived(browser, frame,
+ source_process, message);
+}
+
+// Entry point for creating the test delegate.
+// Called from client_app_delegates.cc.
+void CreateRoutingTestHandlerDelegate(
+ ClientAppRenderer::DelegateSet& delegates) {
+ delegates.insert(new RoutingRenderDelegate);
+}
diff --git a/tests/ceftests/routing_test_handler.h b/tests/ceftests/routing_test_handler.h
new file mode 100644
index 00000000..431772d4
--- /dev/null
+++ b/tests/ceftests/routing_test_handler.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2014 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFTESTS_ROUTING_TEST_HANDLER_H_
+#define CEF_TESTS_CEFTESTS_ROUTING_TEST_HANDLER_H_
+#pragma once
+
+#include "include/wrapper/cef_message_router.h"
+#include "tests/ceftests/test_handler.h"
+
+// Extends TestHandler to provide message routing functionality. The
+// RoutingTestHandler implementation must be called from subclass
+// overrides unless otherwise indicated.
+class RoutingTestHandler : public TestHandler,
+ public CefMessageRouterBrowserSide::Handler {
+ public:
+ RoutingTestHandler(CompletionState* completion_state = nullptr);
+
+ void OnAfterCreated(CefRefPtr<CefBrowser> browser) override;
+ void OnBeforeClose(CefRefPtr<CefBrowser> browser) override;
+ void OnRenderProcessTerminated(CefRefPtr<CefBrowser> browser,
+ TerminationStatus status) override;
+
+ // Only call this method if the navigation isn't canceled.
+ bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ bool user_gesture,
+ bool is_redirect) override;
+
+ // Returns true if the router handled the navigation.
+ bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefProcessId source_process,
+ CefRefPtr<CefProcessMessage> message) override;
+
+ private:
+ CefRefPtr<CefMessageRouterBrowserSide> message_router_;
+};
+
+#endif // CEF_TESTS_CEFTESTS_ROUTING_TEST_HANDLER_H_
diff --git a/tests/ceftests/run_all_unittests.cc b/tests/ceftests/run_all_unittests.cc
new file mode 100644
index 00000000..427b3a70
--- /dev/null
+++ b/tests/ceftests/run_all_unittests.cc
@@ -0,0 +1,277 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "include/base/cef_build.h"
+#include "include/cef_config.h"
+
+#if defined(OS_LINUX) && defined(CEF_X11)
+#include <X11/Xlib.h>
+// Definitions conflict with gtest.
+#undef None
+#undef Bool
+#endif
+
+#if defined(OS_POSIX)
+#include <unistd.h>
+#endif
+
+#include "include/base/cef_callback.h"
+#include "include/cef_app.h"
+#include "include/cef_task.h"
+#include "include/cef_thread.h"
+#include "include/cef_waitable_event.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "include/wrapper/cef_helpers.h"
+#include "tests/ceftests/test_handler.h"
+#include "tests/ceftests/test_server.h"
+#include "tests/ceftests/test_suite.h"
+#include "tests/shared/browser/client_app_browser.h"
+#include "tests/shared/browser/main_message_loop_external_pump.h"
+#include "tests/shared/browser/main_message_loop_std.h"
+#include "tests/shared/common/client_app_other.h"
+#include "tests/shared/renderer/client_app_renderer.h"
+
+#if defined(OS_MAC)
+#include "include/wrapper/cef_library_loader.h"
+#endif
+
+// When generating projects with CMake the CEF_USE_SANDBOX value will be defined
+// automatically if using the required compiler version. Pass -DUSE_SANDBOX=OFF
+// to the CMake command-line to disable use of the sandbox.
+#if defined(OS_WIN) && defined(CEF_USE_SANDBOX)
+#include "include/cef_sandbox_win.h"
+
+// The cef_sandbox.lib static library may not link successfully with all VS
+// versions.
+#pragma comment(lib, "cef_sandbox.lib")
+#endif
+
+namespace {
+
+void QuitMessageLoop() {
+ CEF_REQUIRE_UI_THREAD();
+ client::MainMessageLoop* message_loop = client::MainMessageLoop::Get();
+ if (message_loop) {
+ message_loop->Quit();
+ } else {
+ CefQuitMessageLoop();
+ }
+}
+
+void sleep(int64 ms) {
+#if defined(OS_WIN)
+ Sleep(ms);
+#elif defined(OS_POSIX)
+ usleep(static_cast<useconds_t>(ms * 1000));
+#else
+#error Unsupported platform
+#endif
+}
+
+// Called on the test thread.
+void RunTestsOnTestThread() {
+ // Run the test suite.
+ CefTestSuite::GetInstance()->Run();
+
+ // Wait for all browsers to exit.
+ while (TestHandler::HasBrowser()) {
+ sleep(100);
+ }
+
+ // Wait for the test server to stop, and then quit the CEF message loop.
+ test_server::Stop(base::BindOnce(QuitMessageLoop));
+}
+
+// Called on the UI thread.
+void ContinueOnUIThread(CefRefPtr<CefTaskRunner> test_task_runner) {
+ // Run the test suite on the test thread.
+ test_task_runner->PostTask(
+ CefCreateClosureTask(base::BindOnce(&RunTestsOnTestThread)));
+}
+
+#if defined(OS_LINUX) && defined(CEF_X11)
+int XErrorHandlerImpl(Display* display, XErrorEvent* event) {
+ LOG(WARNING) << "X error received: "
+ << "type " << event->type << ", "
+ << "serial " << event->serial << ", "
+ << "error_code " << static_cast<int>(event->error_code) << ", "
+ << "request_code " << static_cast<int>(event->request_code)
+ << ", "
+ << "minor_code " << static_cast<int>(event->minor_code);
+ return 0;
+}
+
+int XIOErrorHandlerImpl(Display* display) {
+ return 0;
+}
+#endif // defined(OS_LINUX) && defined(CEF_X11)
+
+} // namespace
+
+int main(int argc, char* argv[]) {
+#if !defined(OS_MAC)
+ int exit_code;
+#endif
+
+#if defined(OS_WIN) && defined(ARCH_CPU_32_BITS)
+ // Run the main thread on 32-bit Windows using a fiber with the preferred 4MiB
+ // stack size. This function must be called at the top of the executable entry
+ // point function (`main()` or `wWinMain()`). It is used in combination with
+ // the initial stack size of 0.5MiB configured via the `/STACK:0x80000` linker
+ // flag on executable targets. This saves significant memory on threads (like
+ // those in the Windows thread pool, and others) whose stack size can only be
+ // controlled via the linker flag.
+ exit_code = CefRunMainWithPreferredStackSize(main, argc, argv);
+ if (exit_code >= 0) {
+ // The fiber has completed so return here.
+ return exit_code;
+ }
+#endif
+
+#if defined(OS_MAC)
+ // Load the CEF framework library at runtime instead of linking directly
+ // as required by the macOS sandbox implementation.
+ CefScopedLibraryLoader library_loader;
+ if (!library_loader.LoadInMain()) {
+ return 1;
+ }
+#endif
+
+ // Create the singleton test suite object.
+ CefTestSuite test_suite(argc, argv);
+
+#if defined(OS_WIN)
+ if (test_suite.command_line()->HasSwitch("enable-high-dpi-support")) {
+ // Enable High-DPI support on Windows 7 and newer.
+ CefEnableHighDPISupport();
+ }
+
+ CefMainArgs main_args(::GetModuleHandle(nullptr));
+#else
+ CefMainArgs main_args(argc, argv);
+#endif
+
+ void* windows_sandbox_info = nullptr;
+
+#if defined(OS_WIN) && defined(CEF_USE_SANDBOX)
+ // Manages the life span of the sandbox information object.
+ CefScopedSandboxInfo scoped_sandbox;
+ windows_sandbox_info = scoped_sandbox.sandbox_info();
+#endif
+
+ // Create a ClientApp of the correct type.
+ CefRefPtr<CefApp> app;
+ client::ClientApp::ProcessType process_type =
+ client::ClientApp::GetProcessType(test_suite.command_line());
+ if (process_type == client::ClientApp::BrowserProcess) {
+ app = new client::ClientAppBrowser();
+#if !defined(OS_MAC)
+ } else if (process_type == client::ClientApp::RendererProcess ||
+ process_type == client::ClientApp::ZygoteProcess) {
+ app = new client::ClientAppRenderer();
+ } else if (process_type == client::ClientApp::OtherProcess) {
+ app = new client::ClientAppOther();
+ }
+
+ // Execute the secondary process, if any.
+ exit_code = CefExecuteProcess(main_args, app, windows_sandbox_info);
+ if (exit_code >= 0) {
+ return exit_code;
+ }
+#else
+ } else {
+ // On OS X this executable is only used for the main process.
+ NOTREACHED();
+ }
+#endif
+
+ CefSettings settings;
+
+#if !defined(CEF_USE_SANDBOX)
+ settings.no_sandbox = true;
+#endif
+
+ client::ClientAppBrowser::PopulateSettings(test_suite.command_line(),
+ settings);
+ test_suite.GetSettings(settings);
+
+#if defined(OS_MAC)
+ // Platform-specific initialization.
+ extern void PlatformInit();
+ PlatformInit();
+#endif
+
+#if defined(OS_LINUX) && defined(CEF_X11)
+ // Install xlib error handlers so that the application won't be terminated
+ // on non-fatal errors.
+ XSetErrorHandler(XErrorHandlerImpl);
+ XSetIOErrorHandler(XIOErrorHandlerImpl);
+#endif
+
+ // Create the MessageLoop.
+ std::unique_ptr<client::MainMessageLoop> message_loop;
+ if (!settings.multi_threaded_message_loop) {
+ if (settings.external_message_pump) {
+ message_loop = client::MainMessageLoopExternalPump::Create();
+ } else {
+ message_loop.reset(new client::MainMessageLoopStd);
+ }
+ }
+
+ // Initialize CEF.
+ CefInitialize(main_args, settings, app, windows_sandbox_info);
+
+ // Initialize the testing framework.
+ test_suite.InitMainProcess();
+
+ int retval;
+
+ if (settings.multi_threaded_message_loop) {
+ // Run the test suite on the main thread.
+ retval = test_suite.Run();
+
+ // Wait for the test server to stop.
+ CefRefPtr<CefWaitableEvent> event =
+ CefWaitableEvent::CreateWaitableEvent(true, false);
+ test_server::Stop(base::BindOnce(&CefWaitableEvent::Signal, event));
+ event->Wait();
+ } else {
+ // Create and start the test thread.
+ CefRefPtr<CefThread> thread = CefThread::CreateThread("test_thread");
+ if (!thread) {
+ return 1;
+ }
+
+ // Start the tests from the UI thread so that any pending UI tasks get a
+ // chance to execute first.
+ CefPostTask(TID_UI,
+ base::BindOnce(&ContinueOnUIThread, thread->GetTaskRunner()));
+
+ // Run the CEF message loop.
+ message_loop->Run();
+
+ // The test suite has completed.
+ retval = test_suite.retval();
+
+ // Terminate the test thread.
+ thread->Stop();
+ thread = nullptr;
+ }
+
+ // Shut down CEF.
+ CefShutdown();
+
+ test_suite.DeleteTempDirectories();
+
+ // Destroy the MessageLoop.
+ message_loop.reset(nullptr);
+
+#if defined(OS_MAC)
+ // Platform-specific cleanup.
+ extern void PlatformCleanup();
+ PlatformCleanup();
+#endif
+
+ return retval;
+}
diff --git a/tests/ceftests/run_all_unittests_mac.mm b/tests/ceftests/run_all_unittests_mac.mm
new file mode 100644
index 00000000..144371a7
--- /dev/null
+++ b/tests/ceftests/run_all_unittests_mac.mm
@@ -0,0 +1,44 @@
+// Copyright (c) 2011 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "include/cef_app.h"
+#import "include/cef_application_mac.h"
+
+// Memory AutoRelease pool.
+static NSAutoreleasePool* g_autopool = nil;
+
+// Provide the CefAppProtocol implementation required by CEF.
+@interface TestApplication : NSApplication <CefAppProtocol> {
+ @private
+ BOOL handlingSendEvent_;
+}
+@end
+
+@implementation TestApplication
+- (BOOL)isHandlingSendEvent {
+ return handlingSendEvent_;
+}
+
+- (void)setHandlingSendEvent:(BOOL)handlingSendEvent {
+ handlingSendEvent_ = handlingSendEvent;
+}
+
+- (void)sendEvent:(NSEvent*)event {
+ CefScopedSendingEvent sendingEventScoper;
+ [super sendEvent:event];
+}
+@end
+
+void PlatformInit() {
+ // Initialize the AutoRelease pool.
+ g_autopool = [[NSAutoreleasePool alloc] init];
+
+ // Initialize the TestApplication instance.
+ [TestApplication sharedApplication];
+}
+
+void PlatformCleanup() {
+ // Release the AutoRelease pool.
+ [g_autopool release];
+}
diff --git a/tests/ceftests/scheme_handler_unittest.cc b/tests/ceftests/scheme_handler_unittest.cc
new file mode 100644
index 00000000..7d9aab39
--- /dev/null
+++ b/tests/ceftests/scheme_handler_unittest.cc
@@ -0,0 +1,2620 @@
+// Copyright (c) 2011 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include <algorithm>
+#include <vector>
+
+#include "include/base/cef_callback.h"
+#include "include/cef_callback.h"
+#include "include/cef_origin_whitelist.h"
+#include "include/cef_scheme.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "tests/ceftests/test_handler.h"
+#include "tests/ceftests/test_suite.h"
+#include "tests/ceftests/test_util.h"
+
+namespace {
+
+class TestResults {
+ public:
+ TestResults() : status_code(200), sub_status_code(200), delay(0) {}
+
+ void reset() {
+ url.clear();
+ html.clear();
+ status_code = 200;
+ response_error_code = ERR_NONE;
+ expected_error_code = ERR_NONE;
+ redirect_url.clear();
+ sub_url.clear();
+ sub_html.clear();
+ sub_status_code = 200;
+ sub_allow_origin.clear();
+ exit_url.clear();
+ accept_language.clear();
+ console_messages.clear();
+ delay = 0;
+ got_request.reset();
+ got_read.reset();
+ got_output.reset();
+ got_sub_output.reset();
+ got_redirect.reset();
+ got_error.reset();
+ got_sub_error.reset();
+ got_sub_request.reset();
+ got_sub_read.reset();
+ got_sub_success.reset();
+ got_exit_request.reset();
+ }
+
+ std::string url;
+ std::string html;
+ int status_code;
+
+ // Error code set on the response.
+ cef_errorcode_t response_error_code;
+ // Error code expected in OnLoadError.
+ cef_errorcode_t expected_error_code;
+
+ // Used for testing redirects
+ std::string redirect_url;
+
+ // Used for testing XHR requests
+ std::string sub_url;
+ std::string sub_html;
+ int sub_status_code;
+ std::string sub_allow_origin;
+ std::string sub_redirect_url;
+ std::string exit_url;
+
+ // Used for testing per-browser Accept-Language.
+ std::string accept_language;
+
+ // Used for testing received console messages.
+ std::vector<std::string> console_messages;
+
+ // Delay for returning scheme handler results.
+ int delay;
+
+ TrackCallback got_request, got_read, got_output, got_sub_output, got_redirect,
+ got_error, got_sub_error, got_sub_redirect, got_sub_request, got_sub_read,
+ got_sub_success, got_exit_request;
+};
+
+// Current scheme handler object. Used when destroying the test from
+// ClientSchemeHandler::ProcessRequest().
+class TestSchemeHandler;
+TestSchemeHandler* g_current_handler = nullptr;
+
+class TestSchemeHandler : public TestHandler {
+ public:
+ explicit TestSchemeHandler(TestResults* tr) : test_results_(tr) {
+ g_current_handler = this;
+ }
+
+ void PopulateBrowserSettings(CefBrowserSettings* settings) override {
+ if (!test_results_->accept_language.empty()) {
+ CefString(&settings->accept_language_list) =
+ test_results_->accept_language;
+ }
+ }
+
+ void RunTest() override {
+ CreateBrowser(test_results_->url);
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout();
+ }
+
+ // Necessary to make the method public in order to destroy the test from
+ // ClientSchemeHandler::ProcessRequest().
+ void DestroyTest() override {
+ EXPECT_TRUE(test_results_->console_messages.empty())
+ << "Did not receive expected console message: "
+ << test_results_->console_messages.front();
+
+ TestHandler::DestroyTest();
+ }
+
+ void DestroyTestIfDone() {
+ if (!test_results_->exit_url.empty() && !test_results_->got_exit_request) {
+ return;
+ }
+
+ if (!test_results_->sub_url.empty() &&
+ !(test_results_->got_sub_output || test_results_->got_sub_error ||
+ test_results_->got_exit_request)) {
+ return;
+ }
+
+ if (!(test_results_->got_output || test_results_->got_error)) {
+ return;
+ }
+
+ DestroyTest();
+ }
+
+ bool IsExitURL(const std::string& url) const {
+ return !test_results_->exit_url.empty() &&
+ url.find(test_results_->exit_url) != std::string::npos;
+ }
+
+ cef_return_value_t OnBeforeResourceLoad(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefCallback> callback) override {
+ if (IsChromeRuntimeEnabled() && request->GetResourceType() == RT_FAVICON) {
+ // Ignore favicon requests.
+ return RV_CANCEL;
+ }
+
+ const std::string& newUrl = request->GetURL();
+ if (IsExitURL(newUrl)) {
+ test_results_->got_exit_request.yes();
+ // XHR tests use an exit URL to destroy the test.
+ if (newUrl.find("SUCCESS") != std::string::npos) {
+ test_results_->got_sub_success.yes();
+ }
+ DestroyTestIfDone();
+ return RV_CANCEL;
+ }
+
+ if (!test_results_->sub_redirect_url.empty() &&
+ newUrl == test_results_->sub_redirect_url) {
+ test_results_->got_sub_redirect.yes();
+ // Redirect to the sub URL.
+ request->SetURL(test_results_->sub_url);
+ } else if (newUrl == test_results_->redirect_url) {
+ test_results_->got_redirect.yes();
+
+ // No read should have occurred for the redirect.
+ EXPECT_TRUE(test_results_->got_request);
+ EXPECT_FALSE(test_results_->got_read);
+
+ // Now loading the redirect URL.
+ test_results_->url = test_results_->redirect_url;
+ test_results_->redirect_url.clear();
+ }
+
+ return RV_CONTINUE;
+ }
+
+ void OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int httpStatusCode) override {
+ const std::string& url = frame->GetURL();
+ if (url == test_results_->url) {
+ test_results_->got_output.yes();
+ } else if (url == test_results_->sub_url) {
+ test_results_->got_sub_output.yes();
+ } else if (IsExitURL(url)) {
+ return;
+ }
+
+ if (url == test_results_->url || test_results_->status_code != 200) {
+ // Test that the status code is correct.
+ EXPECT_EQ(httpStatusCode, test_results_->status_code);
+ }
+
+ DestroyTestIfDone();
+ }
+
+ void OnLoadError(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ ErrorCode errorCode,
+ const CefString& errorText,
+ const CefString& failedUrl) override {
+ const std::string& url = failedUrl;
+ if (url == test_results_->url) {
+ test_results_->got_error.yes();
+ } else if (url == test_results_->sub_url) {
+ test_results_->got_sub_error.yes();
+ } else if (IsExitURL(url)) {
+ return;
+ }
+
+ // Tests sometimes also fail with ERR_ABORTED or ERR_UNKNOWN_URL_SCHEME.
+ if (!(test_results_->expected_error_code == 0 &&
+ (errorCode == ERR_ABORTED || errorCode == ERR_UNKNOWN_URL_SCHEME))) {
+ EXPECT_EQ(test_results_->expected_error_code, errorCode)
+ << failedUrl.ToString();
+ }
+
+ DestroyTestIfDone();
+ }
+
+ bool OnConsoleMessage(CefRefPtr<CefBrowser> browser,
+ cef_log_severity_t level,
+ const CefString& message,
+ const CefString& source,
+ int line) override {
+ bool expected = false;
+ if (!test_results_->console_messages.empty()) {
+ std::vector<std::string>::iterator it =
+ test_results_->console_messages.begin();
+ for (; it != test_results_->console_messages.end(); ++it) {
+ const std::string& possible = *it;
+ const std::string& actual = message.ToString();
+ if (actual.find(possible) == 0U) {
+ expected = true;
+ test_results_->console_messages.erase(it);
+ break;
+ }
+ }
+ }
+
+ EXPECT_TRUE(expected) << "Unexpected console message: "
+ << message.ToString();
+ return false;
+ }
+
+ protected:
+ TestResults* test_results_;
+
+ IMPLEMENT_REFCOUNTING(TestSchemeHandler);
+};
+
+class ClientSchemeHandlerOld : public CefResourceHandler {
+ public:
+ explicit ClientSchemeHandlerOld(TestResults* tr)
+ : test_results_(tr), offset_(0), is_sub_(false), has_delayed_(false) {}
+
+ bool ProcessRequest(CefRefPtr<CefRequest> request,
+ CefRefPtr<CefCallback> callback) override {
+ EXPECT_TRUE(CefCurrentlyOn(TID_IO));
+
+ bool handled = false;
+
+ std::string url = request->GetURL();
+ is_sub_ =
+ (!test_results_->sub_url.empty() && test_results_->sub_url == url);
+
+ if (is_sub_) {
+ test_results_->got_sub_request.yes();
+
+ if (!test_results_->sub_html.empty()) {
+ handled = true;
+ }
+ } else {
+ EXPECT_EQ(url, test_results_->url);
+
+ test_results_->got_request.yes();
+
+ if (!test_results_->html.empty()) {
+ handled = true;
+ }
+ }
+
+ std::string accept_language;
+ CefRequest::HeaderMap headerMap;
+ CefRequest::HeaderMap::iterator headerIter;
+ request->GetHeaderMap(headerMap);
+ headerIter = headerMap.find("Accept-Language");
+ if (headerIter != headerMap.end()) {
+ accept_language = headerIter->second;
+ }
+ EXPECT_TRUE(!accept_language.empty());
+
+ if (!test_results_->accept_language.empty()) {
+ // Value from CefBrowserSettings.accept_language set in
+ // PopulateBrowserSettings().
+ EXPECT_STREQ(test_results_->accept_language.data(),
+ accept_language.data());
+ } else {
+ // CEF_SETTINGS_ACCEPT_LANGUAGE value from
+ // CefSettings.accept_language_list set in CefTestSuite::GetSettings()
+ // and expanded internally by ComputeAcceptLanguageFromPref.
+ EXPECT_STREQ("en-GB,en;q=0.9", accept_language.data());
+ }
+
+ if (handled) {
+ if (test_results_->delay > 0) {
+ // Continue after the delay.
+ CefPostDelayedTask(
+ TID_IO, base::BindOnce(&CefCallback::Continue, callback.get()),
+ test_results_->delay);
+ } else {
+ // Continue immediately.
+ callback->Continue();
+ }
+ return true;
+ } else if (test_results_->response_error_code != ERR_NONE) {
+ // Propagate the error code.
+ callback->Continue();
+ return true;
+ }
+
+ // Response was canceled.
+ if (g_current_handler) {
+ g_current_handler->DestroyTest();
+ }
+ return false;
+ }
+
+ void GetResponseHeaders(CefRefPtr<CefResponse> response,
+ int64& response_length,
+ CefString& redirectUrl) override {
+ if (is_sub_) {
+ response->SetStatus(test_results_->sub_status_code);
+
+ if (!test_results_->sub_allow_origin.empty()) {
+ // Set the Access-Control-Allow-Origin header to allow cross-domain
+ // scripting.
+ CefResponse::HeaderMap headers;
+ headers.insert(std::make_pair("Access-Control-Allow-Origin",
+ test_results_->sub_allow_origin));
+ response->SetHeaderMap(headers);
+ }
+
+ if (!test_results_->sub_html.empty()) {
+ response->SetMimeType("text/html");
+ response_length = test_results_->sub_html.size();
+ }
+ } else if (!test_results_->redirect_url.empty()) {
+ redirectUrl = test_results_->redirect_url;
+ } else if (test_results_->response_error_code != ERR_NONE) {
+ response->SetError(test_results_->response_error_code);
+ } else {
+ response->SetStatus(test_results_->status_code);
+
+ if (!test_results_->html.empty()) {
+ response->SetMimeType("text/html");
+ response_length = test_results_->html.size();
+ }
+ }
+ }
+
+ void Cancel() override { EXPECT_TRUE(CefCurrentlyOn(TID_IO)); }
+
+ bool ReadResponse(void* data_out,
+ int bytes_to_read,
+ int& bytes_read,
+ CefRefPtr<CefCallback> callback) override {
+ EXPECT_TRUE(CefCurrentlyOn(TID_IO));
+
+ if (test_results_->delay > 0) {
+ if (!has_delayed_) {
+ // Continue after a delay.
+ CefPostDelayedTask(
+ TID_IO,
+ base::BindOnce(&ClientSchemeHandlerOld::ContinueAfterDelay, this,
+ callback),
+ test_results_->delay);
+ bytes_read = 0;
+ return true;
+ }
+
+ has_delayed_ = false;
+ }
+
+ std::string* data;
+
+ if (is_sub_) {
+ test_results_->got_sub_read.yes();
+ data = &test_results_->sub_html;
+ } else {
+ test_results_->got_read.yes();
+ data = &test_results_->html;
+ }
+
+ bool has_data = false;
+ bytes_read = 0;
+
+ size_t size = data->size();
+ if (offset_ < size) {
+ int transfer_size =
+ std::min(bytes_to_read, static_cast<int>(size - offset_));
+ memcpy(data_out, data->c_str() + offset_, transfer_size);
+ offset_ += transfer_size;
+
+ bytes_read = transfer_size;
+ has_data = true;
+ }
+
+ return has_data;
+ }
+
+ private:
+ void ContinueAfterDelay(CefRefPtr<CefCallback> callback) {
+ has_delayed_ = true;
+ callback->Continue();
+ }
+
+ TestResults* test_results_;
+ size_t offset_;
+ bool is_sub_;
+ bool has_delayed_;
+
+ IMPLEMENT_REFCOUNTING(ClientSchemeHandlerOld);
+ DISALLOW_COPY_AND_ASSIGN(ClientSchemeHandlerOld);
+};
+
+class ClientSchemeHandler : public CefResourceHandler {
+ public:
+ explicit ClientSchemeHandler(TestResults* tr)
+ : test_results_(tr), offset_(0), is_sub_(false), has_delayed_(false) {}
+
+ bool Open(CefRefPtr<CefRequest> request,
+ bool& handle_request,
+ CefRefPtr<CefCallback> callback) override {
+ EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO));
+
+ if (IsChromeRuntimeEnabled() && request->GetResourceType() == RT_FAVICON) {
+ // Ignore favicon requests.
+ return false;
+ }
+
+ bool handled = false;
+
+ std::string url = request->GetURL();
+ is_sub_ =
+ (!test_results_->sub_url.empty() && test_results_->sub_url == url);
+
+ if (is_sub_) {
+ test_results_->got_sub_request.yes();
+
+ if (!test_results_->sub_html.empty()) {
+ handled = true;
+ }
+ } else {
+ EXPECT_EQ(url, test_results_->url);
+
+ test_results_->got_request.yes();
+
+ if (!test_results_->html.empty()) {
+ handled = true;
+ }
+ }
+
+ std::string accept_language;
+ CefRequest::HeaderMap headerMap;
+ CefRequest::HeaderMap::iterator headerIter;
+ request->GetHeaderMap(headerMap);
+ headerIter = headerMap.find("Accept-Language");
+ if (headerIter != headerMap.end()) {
+ accept_language = headerIter->second;
+ }
+ EXPECT_TRUE(!accept_language.empty());
+
+ if (!test_results_->accept_language.empty()) {
+ // Value from CefBrowserSettings.accept_language set in
+ // PopulateBrowserSettings().
+ EXPECT_STREQ(test_results_->accept_language.data(),
+ accept_language.data());
+ } else {
+ // CEF_SETTINGS_ACCEPT_LANGUAGE value from
+ // CefSettings.accept_language_list set in CefTestSuite::GetSettings()
+ // and expanded internally by ComputeAcceptLanguageFromPref.
+ EXPECT_STREQ("en-GB,en;q=0.9", accept_language.data());
+ }
+
+ // Continue or cancel the request immediately based on the return value.
+ handle_request = true;
+
+ if (handled) {
+ if (test_results_->delay > 0) {
+ // Continue after the delay.
+ handle_request = false;
+ CefPostDelayedTask(
+ TID_FILE_USER_BLOCKING,
+ base::BindOnce(&CefCallback::Continue, callback.get()),
+ test_results_->delay);
+ }
+ return true;
+ } else if (test_results_->response_error_code != ERR_NONE) {
+ // Propagate the error code.
+ return true;
+ }
+
+ // Response was canceled.
+ if (g_current_handler) {
+ g_current_handler->DestroyTest();
+ }
+ return false;
+ }
+
+ bool ProcessRequest(CefRefPtr<CefRequest> request,
+ CefRefPtr<CefCallback> callback) override {
+ if (IsChromeRuntimeEnabled() && request->GetResourceType() == RT_FAVICON) {
+ // Ignore favicon requests.
+ return false;
+ }
+
+ EXPECT_TRUE(false); // Not reached.
+ return false;
+ }
+
+ void GetResponseHeaders(CefRefPtr<CefResponse> response,
+ int64& response_length,
+ CefString& redirectUrl) override {
+ if (is_sub_) {
+ response->SetStatus(test_results_->sub_status_code);
+
+ if (!test_results_->sub_allow_origin.empty()) {
+ // Set the Access-Control-Allow-Origin header to allow cross-domain
+ // scripting.
+ CefResponse::HeaderMap headers;
+ headers.insert(std::make_pair("Access-Control-Allow-Origin",
+ test_results_->sub_allow_origin));
+ response->SetHeaderMap(headers);
+ }
+
+ if (!test_results_->sub_html.empty()) {
+ response->SetMimeType("text/html");
+ response_length = test_results_->sub_html.size();
+ }
+ } else if (!test_results_->redirect_url.empty()) {
+ redirectUrl = test_results_->redirect_url;
+ } else if (test_results_->response_error_code != ERR_NONE) {
+ response->SetError(test_results_->response_error_code);
+ } else {
+ response->SetStatus(test_results_->status_code);
+
+ if (!test_results_->html.empty()) {
+ response->SetMimeType("text/html");
+ response_length = test_results_->html.size();
+ }
+ }
+ }
+
+ void Cancel() override { EXPECT_TRUE(CefCurrentlyOn(TID_IO)); }
+
+ bool Read(void* data_out,
+ int bytes_to_read,
+ int& bytes_read,
+ CefRefPtr<CefResourceReadCallback> callback) override {
+ EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO));
+
+ if (test_results_->delay > 0) {
+ if (!has_delayed_) {
+ // Continue after a delay.
+ CefPostDelayedTask(
+ TID_FILE_USER_BLOCKING,
+ base::BindOnce(&ClientSchemeHandler::ContinueAfterDelay, this,
+ data_out, bytes_to_read, callback),
+ test_results_->delay);
+ bytes_read = 0;
+ return true;
+ }
+
+ has_delayed_ = false;
+ }
+
+ return GetData(data_out, bytes_to_read, bytes_read);
+ }
+
+ bool ReadResponse(void* data_out,
+ int bytes_to_read,
+ int& bytes_read,
+ CefRefPtr<CefCallback> callback) override {
+ EXPECT_TRUE(false); // Not reached.
+ bytes_read = -2;
+ return false;
+ }
+
+ private:
+ void ContinueAfterDelay(void* data_out,
+ int bytes_to_read,
+ CefRefPtr<CefResourceReadCallback> callback) {
+ EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO));
+
+ has_delayed_ = true;
+
+ int bytes_read = 0;
+ GetData(data_out, bytes_to_read, bytes_read);
+ callback->Continue(bytes_read);
+ }
+
+ bool GetData(void* data_out, int bytes_to_read, int& bytes_read) {
+ std::string* data;
+
+ if (is_sub_) {
+ test_results_->got_sub_read.yes();
+ data = &test_results_->sub_html;
+ } else {
+ test_results_->got_read.yes();
+ data = &test_results_->html;
+ }
+
+ // Default to response complete.
+ bool has_data = false;
+ bytes_read = 0;
+
+ size_t size = data->size();
+ if (offset_ < size) {
+ int transfer_size =
+ std::min(bytes_to_read, static_cast<int>(size - offset_));
+ memcpy(data_out, data->c_str() + offset_, transfer_size);
+ offset_ += transfer_size;
+
+ bytes_read = transfer_size;
+ has_data = true;
+ }
+
+ return has_data;
+ }
+
+ TestResults* test_results_;
+ size_t offset_;
+ bool is_sub_;
+ bool has_delayed_;
+
+ IMPLEMENT_REFCOUNTING(ClientSchemeHandler);
+ DISALLOW_COPY_AND_ASSIGN(ClientSchemeHandler);
+};
+
+class ClientSchemeHandlerFactory : public CefSchemeHandlerFactory {
+ public:
+ explicit ClientSchemeHandlerFactory(TestResults* tr) : test_results_(tr) {}
+
+ CefRefPtr<CefResourceHandler> Create(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const CefString& scheme_name,
+ CefRefPtr<CefRequest> request) override {
+ EXPECT_TRUE(CefCurrentlyOn(TID_IO));
+ if (TestOldResourceAPI()) {
+ return new ClientSchemeHandlerOld(test_results_);
+ }
+ return new ClientSchemeHandler(test_results_);
+ }
+
+ TestResults* test_results_;
+
+ IMPLEMENT_REFCOUNTING(ClientSchemeHandlerFactory);
+ DISALLOW_COPY_AND_ASSIGN(ClientSchemeHandlerFactory);
+};
+
+// Global test results object.
+TestResults g_TestResults;
+
+// If |domain| is empty the scheme will be registered as non-standard.
+void RegisterTestScheme(const std::string& scheme, const std::string& domain) {
+ g_TestResults.reset();
+
+ EXPECT_TRUE(CefRegisterSchemeHandlerFactory(
+ scheme, domain, new ClientSchemeHandlerFactory(&g_TestResults)));
+ WaitForIOThread();
+}
+
+void ClearTestSchemes() {
+ EXPECT_TRUE(CefClearSchemeHandlerFactories());
+ WaitForIOThread();
+}
+
+struct XHRTestSettings {
+ XHRTestSettings() : synchronous(true) {}
+
+ std::string url;
+ std::string sub_url;
+ std::string sub_allow_origin;
+ std::string sub_redirect_url;
+ bool synchronous;
+};
+
+void SetUpXHR(const XHRTestSettings& settings) {
+ g_TestResults.sub_url = settings.sub_url;
+ g_TestResults.sub_html = "SUCCESS";
+ g_TestResults.sub_allow_origin = settings.sub_allow_origin;
+ g_TestResults.sub_redirect_url = settings.sub_redirect_url;
+
+ std::string request_url;
+ if (!settings.sub_redirect_url.empty()) {
+ request_url = settings.sub_redirect_url;
+ } else {
+ request_url = settings.sub_url;
+ }
+
+ g_TestResults.url = settings.url;
+ std::stringstream ss;
+ ss << "<html><head>"
+ "<script language=\"JavaScript\">"
+ "function onResult(val) {"
+ " document.location = \"http://tests/exit?result=\"+val;"
+ "}"
+ "function execXMLHttpRequest() {";
+ if (settings.synchronous) {
+ ss << "var result = 'FAILURE';"
+ "try {"
+ " xhr = new XMLHttpRequest();"
+ " xhr.open(\"GET\", \""
+ << request_url.c_str()
+ << "\", false);"
+ " xhr.send();"
+ " result = xhr.responseText;"
+ "} catch(e) {}"
+ "onResult(result)";
+ } else {
+ ss << "xhr = new XMLHttpRequest();"
+ "xhr.open(\"GET\", \""
+ << request_url.c_str()
+ << "\", true);"
+ "xhr.onload = function(e) {"
+ " if (xhr.readyState === 4) {"
+ " if (xhr.status === 200) {"
+ " onResult(xhr.responseText);"
+ " } else {"
+ " console.log('XMLHttpRequest failed with status ' + "
+ "xhr.status);"
+ " onResult('FAILURE');"
+ " }"
+ " }"
+ "};"
+ "xhr.onerror = function(e) {"
+ " onResult('FAILURE');"
+ "};"
+ "xhr.send()";
+ }
+ ss << "}"
+ "</script>"
+ "</head><body onload=\"execXMLHttpRequest();\">"
+ "Running execXMLHttpRequest..."
+ "</body></html>";
+ g_TestResults.html = ss.str();
+
+ g_TestResults.exit_url = "http://tests/exit";
+}
+
+struct FetchTestSettings {
+ FetchTestSettings() {}
+
+ std::string url;
+ std::string sub_url;
+ std::string sub_allow_origin;
+ std::string sub_redirect_url;
+};
+
+void SetUpFetch(const FetchTestSettings& settings) {
+ g_TestResults.sub_url = settings.sub_url;
+ g_TestResults.sub_html = "SUCCESS";
+ g_TestResults.sub_allow_origin = settings.sub_allow_origin;
+ g_TestResults.sub_redirect_url = settings.sub_redirect_url;
+
+ std::string request_url;
+ if (!settings.sub_redirect_url.empty()) {
+ request_url = settings.sub_redirect_url;
+ } else {
+ request_url = settings.sub_url;
+ }
+
+ g_TestResults.url = settings.url;
+ std::stringstream ss;
+ ss << "<html><head>"
+ "<script language=\"JavaScript\">"
+ "function onResult(val) {"
+ " document.location = \"http://tests/exit?result=\"+val;"
+ "}"
+ "function execFetchHttpRequest() {";
+ ss << "fetch('" << request_url.c_str()
+ << "')"
+ ".then(function(response) {"
+ " if (response.status === 200) {"
+ " response.text().then(function(text) {"
+ " onResult(text);"
+ " }).catch(function(e) {"
+ " onResult('FAILURE'); "
+ " });"
+ " } else {"
+ " onResult('FAILURE');"
+ " }"
+ "}).catch(function(e) {"
+ " onResult('FAILURE');"
+ "});"
+ << "}"
+ "</script>"
+ "</head><body onload=\"execFetchHttpRequest();\">"
+ "Running execFetchHttpRequest..."
+ "</body></html>";
+ g_TestResults.html = ss.str();
+
+ g_TestResults.exit_url = "http://tests/exit";
+} // namespace
+
+void SetUpXSS(const std::string& url,
+ const std::string& sub_url,
+ const std::string& domain = std::string()) {
+ // 1. Load |url| which contains an iframe.
+ // 2. The iframe loads |sub_url|.
+ // 3. |sub_url| tries to call a JS function in |url|.
+ // 4. |url| tries to call a JS function in |sub_url|.
+
+ std::stringstream ss;
+ std::string domain_line;
+ if (!domain.empty()) {
+ domain_line = "document.domain = '" + domain + "';";
+ }
+
+ g_TestResults.sub_url = sub_url;
+ ss << "<html><head>"
+ "<script language=\"JavaScript\">"
+ << domain_line
+ << "function getResult() {"
+ " return 'SUCCESS';"
+ "}"
+ "function execXSSRequest() {"
+ " var result = 'FAILURE';"
+ " try {"
+ " result = parent.getResult();"
+ " } catch(e) { console.log(e.stack); }"
+ " document.location = \"http://tests/exit?result=\"+result;"
+ "}"
+ "</script>"
+ "</head><body onload=\"execXSSRequest();\">"
+ "Running execXSSRequest..."
+ "</body></html>";
+ g_TestResults.sub_html = ss.str();
+
+ g_TestResults.url = url;
+ ss.str("");
+ ss << "<html><head>"
+ "<script language=\"JavaScript\">"
+ << domain_line
+ << ""
+ "function getResult() {"
+ " try {"
+ " return document.getElementById('s').contentWindow.getResult();"
+ " } catch(e) { console.log(e.stack); }"
+ " return 'FAILURE';"
+ "}"
+ "</script>"
+ "</head><body>"
+ "<iframe src=\""
+ << sub_url.c_str()
+ << "\" id=\"s\">"
+ "</body></html>";
+ g_TestResults.html = ss.str();
+
+ g_TestResults.exit_url = "http://tests/exit";
+}
+
+} // namespace
+
+// Test that scheme registration/unregistration works as expected.
+TEST(SchemeHandlerTest, Registration) {
+ RegisterTestScheme("customstd", "test");
+ g_TestResults.url = "customstd://test/run.html";
+ g_TestResults.html =
+ "<html><head></head><body><h1>Success!</h1></body></html>";
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+
+ // Unregister the handler.
+ EXPECT_TRUE(CefRegisterSchemeHandlerFactory("customstd", "test", nullptr));
+ WaitForIOThread();
+
+ g_TestResults.got_request.reset();
+ g_TestResults.got_read.reset();
+ g_TestResults.got_output.reset();
+ g_TestResults.expected_error_code = ERR_UNKNOWN_URL_SCHEME;
+ handler->ExecuteTest();
+
+ EXPECT_TRUE(g_TestResults.got_error);
+ EXPECT_FALSE(g_TestResults.got_request);
+ EXPECT_FALSE(g_TestResults.got_read);
+ EXPECT_FALSE(g_TestResults.got_output);
+
+ // Re-register the handler.
+ EXPECT_TRUE(CefRegisterSchemeHandlerFactory(
+ "customstd", "test", new ClientSchemeHandlerFactory(&g_TestResults)));
+ WaitForIOThread();
+
+ g_TestResults.got_error.reset();
+ g_TestResults.expected_error_code = ERR_NONE;
+ handler->ExecuteTest();
+
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_FALSE(g_TestResults.got_error);
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+
+ ClearTestSchemes();
+}
+
+// Test that a custom standard scheme can return normal results.
+TEST(SchemeHandlerTest, CustomStandardNormalResponse) {
+ RegisterTestScheme("customstd", "test");
+ g_TestResults.url = "customstd://test/run.html";
+ g_TestResults.html =
+ "<html><head></head><body><h1>Success!</h1></body></html>";
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+
+ ClearTestSchemes();
+}
+
+// Test that a custom standard scheme can return normal results with delayed
+// responses.
+TEST(SchemeHandlerTest, CustomStandardNormalResponseDelayed) {
+ RegisterTestScheme("customstd", "test");
+ g_TestResults.url = "customstd://test/run.html";
+ g_TestResults.html =
+ "<html><head></head><body><h1>Success!</h1></body></html>";
+ g_TestResults.delay = 100;
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+
+ ClearTestSchemes();
+}
+
+// Test that a custom nonstandard scheme can return normal results.
+TEST(SchemeHandlerTest, CustomNonStandardNormalResponse) {
+ RegisterTestScheme("customnonstd", std::string());
+ g_TestResults.url = "customnonstd:some%20value";
+ g_TestResults.html =
+ "<html><head></head><body><h1>Success!</h1></body></html>";
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+
+ ClearTestSchemes();
+}
+
+// Test that a custom standard scheme can return an error code.
+TEST(SchemeHandlerTest, CustomStandardErrorResponse) {
+ RegisterTestScheme("customstd", "test");
+ g_TestResults.url = "customstd://test/run.html";
+ g_TestResults.html = "<html><head></head><body><h1>404</h1></body></html>";
+ g_TestResults.status_code = 404;
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+
+ ClearTestSchemes();
+}
+
+// Test that a custom standard scheme can return a CEF error code in the
+// response.
+TEST(SchemeHandlerTest, CustomStandardErrorCodeResponse) {
+ RegisterTestScheme("customstd", "test");
+ g_TestResults.url = "customstd://test/run.html";
+ g_TestResults.response_error_code = ERR_FILE_TOO_BIG;
+ g_TestResults.expected_error_code = ERR_FILE_TOO_BIG;
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_FALSE(g_TestResults.got_read);
+ EXPECT_FALSE(g_TestResults.got_output);
+ EXPECT_TRUE(g_TestResults.got_error);
+
+ ClearTestSchemes();
+}
+
+// Test that a custom nonstandard scheme can return an error code.
+TEST(SchemeHandlerTest, CustomNonStandardErrorResponse) {
+ RegisterTestScheme("customnonstd", std::string());
+ g_TestResults.url = "customnonstd:some%20value";
+ g_TestResults.html = "<html><head></head><body><h1>404</h1></body></html>";
+ g_TestResults.status_code = 404;
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+
+ ClearTestSchemes();
+}
+
+// Test that custom standard scheme handling fails when the scheme name is
+// incorrect.
+TEST(SchemeHandlerTest, CustomStandardNameNotHandled) {
+ RegisterTestScheme("customstd", "test");
+ g_TestResults.url = "customstd2://test/run.html";
+ g_TestResults.expected_error_code = ERR_UNKNOWN_URL_SCHEME;
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_FALSE(g_TestResults.got_request);
+ EXPECT_FALSE(g_TestResults.got_read);
+ EXPECT_FALSE(g_TestResults.got_output);
+ EXPECT_TRUE(g_TestResults.got_error);
+
+ ClearTestSchemes();
+}
+
+// Test that custom nonstandard scheme handling fails when the scheme name is
+// incorrect.
+TEST(SchemeHandlerTest, CustomNonStandardNameNotHandled) {
+ RegisterTestScheme("customnonstd", std::string());
+ g_TestResults.url = "customnonstd2:some%20value";
+ g_TestResults.expected_error_code = ERR_UNKNOWN_URL_SCHEME;
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_FALSE(g_TestResults.got_request);
+ EXPECT_FALSE(g_TestResults.got_read);
+ EXPECT_FALSE(g_TestResults.got_output);
+ EXPECT_TRUE(g_TestResults.got_error);
+
+ ClearTestSchemes();
+}
+
+// Test that custom standard scheme handling fails when the domain name is
+// incorrect.
+TEST(SchemeHandlerTest, CustomStandardDomainNotHandled) {
+ RegisterTestScheme("customstd", "test");
+ g_TestResults.url = "customstd://noexist/run.html";
+ g_TestResults.expected_error_code = ERR_UNKNOWN_URL_SCHEME;
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_FALSE(g_TestResults.got_request);
+ EXPECT_FALSE(g_TestResults.got_read);
+ EXPECT_FALSE(g_TestResults.got_output);
+ EXPECT_TRUE(g_TestResults.got_error);
+
+ ClearTestSchemes();
+}
+
+// Test that a custom standard scheme can return no response.
+TEST(SchemeHandlerTest, CustomStandardNoResponse) {
+ RegisterTestScheme("customstd", "test");
+ g_TestResults.url = "customstd://test/run.html";
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_FALSE(g_TestResults.got_read);
+ EXPECT_FALSE(g_TestResults.got_output);
+
+ ClearTestSchemes();
+}
+
+// Test that a custom nonstandard scheme can return no response.
+TEST(SchemeHandlerTest, CustomNonStandardNoResponse) {
+ RegisterTestScheme("customnonstd", std::string());
+ g_TestResults.url = "customnonstd:some%20value";
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_FALSE(g_TestResults.got_read);
+ EXPECT_FALSE(g_TestResults.got_output);
+
+ ClearTestSchemes();
+}
+
+// Test that a custom standard scheme can generate redirects.
+TEST(SchemeHandlerTest, CustomStandardRedirect) {
+ RegisterTestScheme("customstd", "test");
+ g_TestResults.url = "customstd://test/run.html";
+ g_TestResults.redirect_url = "customstd://test/redirect.html";
+ g_TestResults.html =
+ "<html><head></head><body><h1>Redirected</h1></body></html>";
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+ EXPECT_TRUE(g_TestResults.got_redirect);
+
+ ClearTestSchemes();
+}
+
+// Test that a custom nonstandard scheme can generate redirects.
+TEST(SchemeHandlerTest, CustomNonStandardRedirect) {
+ RegisterTestScheme("customnonstd", std::string());
+ g_TestResults.url = "customnonstd:some%20value";
+ g_TestResults.redirect_url = "customnonstd:some%20other%20value";
+ g_TestResults.html =
+ "<html><head></head><body><h1>Redirected</h1></body></html>";
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+ EXPECT_TRUE(g_TestResults.got_redirect);
+
+ ClearTestSchemes();
+}
+
+// Test that a custom standard scheme can generate same origin XHR requests.
+TEST(SchemeHandlerTest, CustomStandardXHRSameOriginSync) {
+ RegisterTestScheme("customstd", "test");
+
+ XHRTestSettings settings;
+ settings.url = "customstd://test/run.html";
+ settings.sub_url = "customstd://test/xhr.html";
+ SetUpXHR(settings);
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+ EXPECT_TRUE(g_TestResults.got_sub_request);
+ EXPECT_TRUE(g_TestResults.got_sub_read);
+ EXPECT_TRUE(g_TestResults.got_sub_success);
+
+ ClearTestSchemes();
+}
+
+// Test that a custom standard scheme can generate same origin XHR requests.
+TEST(SchemeHandlerTest, CustomStandardXHRSameOriginAsync) {
+ RegisterTestScheme("customstd", "test");
+
+ XHRTestSettings settings;
+ settings.url = "customstd://test/run.html";
+ settings.sub_url = "customstd://test/xhr.html";
+ settings.synchronous = false;
+ SetUpXHR(settings);
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+ EXPECT_TRUE(g_TestResults.got_sub_request);
+ EXPECT_TRUE(g_TestResults.got_sub_read);
+ EXPECT_TRUE(g_TestResults.got_sub_success);
+
+ ClearTestSchemes();
+}
+
+// Test that custom nonstandard schemes are treated as unique origins that
+// cannot generate XHR requests.
+TEST(SchemeHandlerTest, CustomNonStandardXHRSameOriginSync) {
+ RegisterTestScheme("customnonstd", std::string());
+
+ XHRTestSettings settings;
+ settings.url = "customnonstd:some%20value";
+ settings.sub_url = "customnonstd:xhr%20value";
+ SetUpXHR(settings);
+
+ g_TestResults.console_messages.push_back(
+ "Access to XMLHttpRequest at 'customnonstd:xhr%20value' from origin "
+ "'null' has been blocked by CORS policy: Cross origin requests are only "
+ "supported for protocol schemes:");
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+ EXPECT_FALSE(g_TestResults.got_sub_request);
+ EXPECT_FALSE(g_TestResults.got_sub_read);
+ EXPECT_FALSE(g_TestResults.got_sub_success);
+
+ ClearTestSchemes();
+}
+
+// Test that custom nonstandard schemes are treated as unique origins that
+// cannot generate XHR requests.
+TEST(SchemeHandlerTest, CustomNonStandardXHRSameOriginAsync) {
+ RegisterTestScheme("customnonstd", std::string());
+
+ XHRTestSettings settings;
+ settings.url = "customnonstd:some%20value";
+ settings.sub_url = "customnonstd:xhr%20value";
+ settings.synchronous = false;
+ SetUpXHR(settings);
+
+ g_TestResults.console_messages.push_back(
+ "Access to XMLHttpRequest at 'customnonstd:xhr%20value' from origin "
+ "'null' has been blocked by CORS policy: Cross origin requests are only "
+ "supported for protocol schemes:");
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+ EXPECT_FALSE(g_TestResults.got_sub_request);
+ EXPECT_FALSE(g_TestResults.got_sub_read);
+ EXPECT_FALSE(g_TestResults.got_sub_success);
+
+ ClearTestSchemes();
+}
+
+// Test that a non fetch enabled custom standard scheme can't generate same
+// origin Fetch requests.
+TEST(SchemeHandlerTest, CustomStandardFetchSameOrigin) {
+ RegisterTestScheme("customstd", "test");
+
+ FetchTestSettings settings;
+ settings.url = "customstd://test/run.html";
+ settings.sub_url = "customstd://test/fetch.html";
+ SetUpFetch(settings);
+
+ g_TestResults.console_messages.push_back(
+ "Fetch API cannot load customstd://test/fetch.html. URL scheme "
+ "\"customstd\" is not supported.");
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+ EXPECT_FALSE(g_TestResults.got_sub_request);
+ EXPECT_FALSE(g_TestResults.got_sub_read);
+ EXPECT_FALSE(g_TestResults.got_sub_success);
+
+ ClearTestSchemes();
+}
+
+// Test that a fetch enabled custom standard scheme can generate same origin
+// Fetch requests.
+TEST(SchemeHandlerTest, FetchCustomStandardFetchSameOrigin) {
+ RegisterTestScheme("customstdfetch", "test");
+
+ FetchTestSettings settings;
+ settings.url = "customstdfetch://test/run.html";
+ settings.sub_url = "customstdfetch://test/fetch.html";
+ SetUpFetch(settings);
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+ EXPECT_TRUE(g_TestResults.got_sub_request);
+ EXPECT_TRUE(g_TestResults.got_sub_read);
+ EXPECT_TRUE(g_TestResults.got_sub_success);
+
+ ClearTestSchemes();
+}
+
+// Test that custom nonstandard schemes are treated as unique origins that
+// cannot generate Fetch requests.
+TEST(SchemeHandlerTest, CustomNonStandardFetchSameOrigin) {
+ RegisterTestScheme("customnonstd", std::string());
+
+ FetchTestSettings settings;
+ settings.url = "customnonstd:some%20value";
+ settings.sub_url = "customnonstd:xhr%20value";
+ SetUpFetch(settings);
+
+ g_TestResults.console_messages.push_back(
+ "Fetch API cannot load customnonstd:xhr%20value. URL scheme "
+ "\"customnonstd\" is not supported.");
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+ EXPECT_FALSE(g_TestResults.got_sub_request);
+ EXPECT_FALSE(g_TestResults.got_sub_read);
+ EXPECT_FALSE(g_TestResults.got_sub_success);
+
+ ClearTestSchemes();
+}
+
+// Test that a custom standard scheme can generate same origin XSS requests.
+TEST(SchemeHandlerTest, CustomStandardXSSSameOrigin) {
+ RegisterTestScheme("customstd", "test");
+ SetUpXSS("customstd://test/run.html", "customstd://test/iframe.html");
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+ EXPECT_TRUE(g_TestResults.got_sub_request);
+ EXPECT_TRUE(g_TestResults.got_sub_read);
+ EXPECT_TRUE(g_TestResults.got_sub_success);
+
+ ClearTestSchemes();
+}
+
+// Test that custom nonstandard schemes are treated as unique origins that
+// cannot generate XSS requests.
+TEST(SchemeHandlerTest, CustomNonStandardXSSSameOrigin) {
+ RegisterTestScheme("customnonstd", std::string());
+ SetUpXSS("customnonstd:some%20value", "customnonstd:xhr%20value");
+
+ g_TestResults.console_messages.push_back(
+ "Error: Blocked a frame with origin \"null\" from accessing a "
+ "cross-origin frame.");
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+ EXPECT_TRUE(g_TestResults.got_sub_request);
+ EXPECT_TRUE(g_TestResults.got_sub_read);
+ EXPECT_FALSE(g_TestResults.got_sub_success);
+
+ ClearTestSchemes();
+}
+
+// Test that a custom standard scheme cannot generate cross-domain XHR requests
+// by default. Behavior should be the same as with HTTP.
+TEST(SchemeHandlerTest, CustomStandardXHRDifferentOriginSync) {
+ RegisterTestScheme("customstd", "test1");
+ RegisterTestScheme("customstd", "test2");
+
+ XHRTestSettings settings;
+ settings.url = "customstd://test1/run.html";
+ settings.sub_url = "customstd://test2/xhr.html";
+ SetUpXHR(settings);
+
+ g_TestResults.console_messages.push_back(
+ "Access to XMLHttpRequest at 'customstd://test2/xhr.html' from origin "
+ "'customstd://test1' has been blocked by CORS policy: No "
+ "'Access-Control-Allow-Origin' header is present on the requested "
+ "resource.");
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+ EXPECT_TRUE(g_TestResults.got_sub_request);
+ EXPECT_TRUE(g_TestResults.got_sub_read);
+ EXPECT_FALSE(g_TestResults.got_sub_success);
+
+ ClearTestSchemes();
+}
+
+// Test that a custom standard scheme cannot generate cross-domain XHR requests
+// by default. Behavior should be the same as with HTTP.
+TEST(SchemeHandlerTest, CustomStandardXHRDifferentOriginAsync) {
+ RegisterTestScheme("customstd", "test1");
+ RegisterTestScheme("customstd", "test2");
+
+ XHRTestSettings settings;
+ settings.url = "customstd://test1/run.html";
+ settings.sub_url = "customstd://test2/xhr.html";
+ settings.synchronous = false;
+ SetUpXHR(settings);
+
+ g_TestResults.console_messages.push_back(
+ "Access to XMLHttpRequest at 'customstd://test2/xhr.html' from origin "
+ "'customstd://test1' has been blocked by CORS policy: No "
+ "'Access-Control-Allow-Origin' header is present on the requested "
+ "resource.");
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+ EXPECT_TRUE(g_TestResults.got_sub_request);
+ EXPECT_TRUE(g_TestResults.got_sub_read);
+ EXPECT_FALSE(g_TestResults.got_sub_success);
+
+ ClearTestSchemes();
+}
+
+// Test that a custom standard scheme cannot generate cross-domain Fetch
+// requests by default. Behavior should be the same as with HTTP.
+TEST(SchemeHandlerTest, CustomStandardFetchDifferentOrigin) {
+ RegisterTestScheme("customstdfetch", "test1");
+ RegisterTestScheme("customstdfetch", "test2");
+
+ FetchTestSettings settings;
+ settings.url = "customstdfetch://test1/run.html";
+ settings.sub_url = "customstdfetch://test2/fetch.html";
+ SetUpFetch(settings);
+
+ g_TestResults.console_messages.push_back(
+ "Access to fetch at 'customstdfetch://test2/fetch.html' from origin "
+ "'customstdfetch://test1' has been blocked by CORS policy: No "
+ "'Access-Control-Allow-Origin' header is present on the requested "
+ "resource. If an opaque response serves your needs, set the request's "
+ "mode to 'no-cors' to fetch the resource with CORS disabled.");
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+ EXPECT_TRUE(g_TestResults.got_sub_request);
+ EXPECT_TRUE(g_TestResults.got_sub_read);
+ EXPECT_FALSE(g_TestResults.got_sub_success);
+
+ ClearTestSchemes();
+}
+
+// Test that a custom standard scheme cannot generate cross-domain XSS requests
+// by default.
+TEST(SchemeHandlerTest, CustomStandardXSSDifferentOrigin) {
+ RegisterTestScheme("customstd", "test1");
+ RegisterTestScheme("customstd", "test2");
+ SetUpXSS("customstd://test1/run.html", "customstd://test2/iframe.html");
+
+ g_TestResults.console_messages.push_back(
+ "Error: Blocked a frame with origin \"customstd://test2\" from accessing "
+ "a cross-origin frame.");
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+ EXPECT_TRUE(g_TestResults.got_sub_request);
+ EXPECT_TRUE(g_TestResults.got_sub_read);
+ EXPECT_FALSE(g_TestResults.got_sub_success);
+
+ ClearTestSchemes();
+}
+
+// Test that a cross-protocol iframe load succeeds, and that the custom
+// standard scheme cannot generate XSS requests to the HTTP protocol by default.
+TEST(SchemeHandlerTest, CustomStandardXSSDifferentProtocolHttp) {
+ RegisterTestScheme("customstd", "test1");
+ RegisterTestScheme("http", "test2");
+ SetUpXSS("customstd://test1/run.html", "http://test2/iframe.html");
+
+ g_TestResults.console_messages.push_back(
+ "Error: Blocked a frame with origin \"http://test2\" from accessing a "
+ "cross-origin frame.");
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+ EXPECT_TRUE(g_TestResults.got_sub_request);
+ EXPECT_TRUE(g_TestResults.got_sub_read);
+ EXPECT_FALSE(g_TestResults.got_sub_success);
+
+ ClearTestSchemes();
+}
+
+// Test that a cross-protocol iframe load succeeds, and that the custom
+// standard scheme cannot generate XSS requests to a non-standard scheme by
+// default.
+TEST(SchemeHandlerTest, CustomStandardXSSDifferentProtocolCustomNonStandard) {
+ RegisterTestScheme("customstd", "test1");
+ RegisterTestScheme("customnonstd", std::string());
+ SetUpXSS("customstd://test1/run.html", "customnonstd:some%20value");
+
+ g_TestResults.console_messages.push_back(
+ "Error: Blocked a frame with origin \"null\" from accessing a "
+ "cross-origin frame.");
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+ EXPECT_TRUE(g_TestResults.got_sub_request);
+ EXPECT_TRUE(g_TestResults.got_sub_read);
+ EXPECT_FALSE(g_TestResults.got_sub_success);
+
+ ClearTestSchemes();
+}
+
+// Test that a cross-protocol iframe load succeeds, and that the HTTP protocol
+// cannot generate XSS requests to the custom standard scheme by default.
+TEST(SchemeHandlerTest, HttpXSSDifferentProtocolCustomStandard) {
+ RegisterTestScheme("http", "test1");
+ RegisterTestScheme("customstd", "test2");
+ SetUpXSS("http://test1/run.html", "customstd://test2/iframe.html");
+
+ g_TestResults.console_messages.push_back(
+ "Error: Blocked a frame with origin \"customstd://test2\" from accessing "
+ "a cross-origin frame.");
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+ EXPECT_TRUE(g_TestResults.got_sub_request);
+ EXPECT_TRUE(g_TestResults.got_sub_read);
+ EXPECT_FALSE(g_TestResults.got_sub_success);
+
+ ClearTestSchemes();
+}
+
+// Test that a cross-protocol iframe load succeeds, and that the HTTP protocol
+// cannot generate XSS requests to the custom non-standard scheme by default.
+TEST(SchemeHandlerTest, HttpXSSDifferentProtocolCustomNonStandard) {
+ RegisterTestScheme("http", "test1");
+ RegisterTestScheme("customnonstd", std::string());
+ SetUpXSS("http://test1/run.html", "customnonstd:some%20value");
+
+ g_TestResults.console_messages.push_back(
+ "Error: Blocked a frame with origin \"null\" from accessing a "
+ "cross-origin frame.");
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+ EXPECT_TRUE(g_TestResults.got_sub_request);
+ EXPECT_TRUE(g_TestResults.got_sub_read);
+ EXPECT_FALSE(g_TestResults.got_sub_success);
+
+ ClearTestSchemes();
+}
+
+// Test that an HTTP scheme cannot generate cross-domain XHR requests by
+// default.
+TEST(SchemeHandlerTest, HttpXHRDifferentOriginSync) {
+ RegisterTestScheme("http", "test1");
+ RegisterTestScheme("http", "test2");
+
+ XHRTestSettings settings;
+ settings.url = "http://test1/run.html";
+ settings.sub_url = "http://test2/xhr.html";
+ SetUpXHR(settings);
+
+ g_TestResults.console_messages.push_back(
+ "Access to XMLHttpRequest at 'http://test2/xhr.html' from origin "
+ "'http://test1' has been blocked by CORS policy: No "
+ "'Access-Control-Allow-Origin' header is present on the requested "
+ "resource.");
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+ EXPECT_TRUE(g_TestResults.got_sub_request);
+ EXPECT_TRUE(g_TestResults.got_sub_read);
+ EXPECT_FALSE(g_TestResults.got_sub_success);
+
+ ClearTestSchemes();
+}
+
+// Test that an HTTP scheme cannot generate cross-domain XHR requests by
+// default.
+TEST(SchemeHandlerTest, HttpXHRDifferentOriginAsync) {
+ RegisterTestScheme("http", "test1");
+ RegisterTestScheme("http", "test2");
+
+ XHRTestSettings settings;
+ settings.url = "http://test1/run.html";
+ settings.sub_url = "http://test2/xhr.html";
+ settings.synchronous = false;
+ SetUpXHR(settings);
+
+ g_TestResults.console_messages.push_back(
+ "Access to XMLHttpRequest at 'http://test2/xhr.html' from origin "
+ "'http://test1' has been blocked by CORS policy: No "
+ "'Access-Control-Allow-Origin' header is present on the requested "
+ "resource.");
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+ EXPECT_TRUE(g_TestResults.got_sub_request);
+ EXPECT_TRUE(g_TestResults.got_sub_read);
+ EXPECT_FALSE(g_TestResults.got_sub_success);
+
+ ClearTestSchemes();
+}
+
+// Test that an HTTP scheme cannot generate cross-domain Fetch requests by
+// default.
+TEST(SchemeHandlerTest, HttpFetchDifferentOriginAsync) {
+ RegisterTestScheme("http", "test1");
+ RegisterTestScheme("http", "test2");
+
+ FetchTestSettings settings;
+ settings.url = "http://test1/run.html";
+ settings.sub_url = "http://test2/fetch.html";
+ SetUpFetch(settings);
+
+ g_TestResults.console_messages.push_back(
+ "Access to fetch at 'http://test2/fetch.html' from origin 'http://test1' "
+ "has been blocked by CORS policy: No 'Access-Control-Allow-Origin' "
+ "header is present on the requested resource. If an opaque response "
+ "serves your needs, set the request's mode to 'no-cors' to fetch the "
+ "resource with CORS disabled.");
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+ EXPECT_TRUE(g_TestResults.got_sub_request);
+ EXPECT_TRUE(g_TestResults.got_sub_read);
+ EXPECT_FALSE(g_TestResults.got_sub_success);
+
+ ClearTestSchemes();
+}
+
+// Test that an HTTP scheme cannot generate cross-domain XSS requests by
+// default.
+TEST(SchemeHandlerTest, HttpXSSDifferentOrigin) {
+ RegisterTestScheme("http", "test1");
+ RegisterTestScheme("http", "test2");
+ SetUpXSS("http://test1/run.html", "http://test2/xss.html");
+
+ g_TestResults.console_messages.push_back(
+ "Error: Blocked a frame with origin \"http://test2\" from accessing a "
+ "cross-origin frame.");
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+ EXPECT_TRUE(g_TestResults.got_sub_request);
+ EXPECT_TRUE(g_TestResults.got_sub_read);
+ EXPECT_FALSE(g_TestResults.got_sub_success);
+
+ ClearTestSchemes();
+}
+
+// Test that a custom standard scheme can generate cross-domain XHR requests
+// when setting the Access-Control-Allow-Origin header. Should behave the same
+// as HTTP.
+TEST(SchemeHandlerTest, CustomStandardXHRDifferentOriginWithHeaderSync) {
+ RegisterTestScheme("customstd", "test1");
+ RegisterTestScheme("customstd", "test2");
+
+ XHRTestSettings settings;
+ settings.url = "customstd://test1/run.html";
+ settings.sub_url = "customstd://test2/xhr.html";
+ settings.sub_allow_origin = "customstd://test1";
+ SetUpXHR(settings);
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+ EXPECT_TRUE(g_TestResults.got_sub_request);
+ EXPECT_TRUE(g_TestResults.got_sub_read);
+ EXPECT_TRUE(g_TestResults.got_sub_success);
+
+ ClearTestSchemes();
+}
+
+// Test that a custom standard scheme can generate cross-domain XHR requests
+// when setting the Access-Control-Allow-Origin header. Should behave the same
+// as HTTP.
+TEST(SchemeHandlerTest, CustomStandardXHRDifferentOriginWithHeaderAsync) {
+ RegisterTestScheme("customstd", "test1");
+ RegisterTestScheme("customstd", "test2");
+
+ XHRTestSettings settings;
+ settings.url = "customstd://test1/run.html";
+ settings.sub_url = "customstd://test2/xhr.html";
+ settings.sub_allow_origin = "customstd://test1";
+ settings.synchronous = false;
+ SetUpXHR(settings);
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+ EXPECT_TRUE(g_TestResults.got_sub_request);
+ EXPECT_TRUE(g_TestResults.got_sub_read);
+ EXPECT_TRUE(g_TestResults.got_sub_success);
+
+ ClearTestSchemes();
+}
+
+// Test that a custom standard scheme can generate cross-domain Fetch requests
+// when setting the Access-Control-Allow-Origin header. Should behave the same
+// as HTTP.
+TEST(SchemeHandlerTest, CustomStandardFetchDifferentOriginWithHeader) {
+ RegisterTestScheme("customstdfetch", "test1");
+ RegisterTestScheme("customstdfetch", "test2");
+
+ FetchTestSettings settings;
+ settings.url = "customstdfetch://test1/run.html";
+ settings.sub_url = "customstdfetch://test2/fetch.html";
+ settings.sub_allow_origin = "customstdfetch://test1";
+ SetUpFetch(settings);
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+ EXPECT_TRUE(g_TestResults.got_sub_request);
+ EXPECT_TRUE(g_TestResults.got_sub_read);
+ EXPECT_TRUE(g_TestResults.got_sub_success);
+
+ ClearTestSchemes();
+}
+
+// Test that a custom standard scheme can generate cross-domain XHR requests
+// when using the cross-origin whitelist.
+TEST(SchemeHandlerTest, CustomStandardXHRDifferentOriginWithWhitelistSync1) {
+ RegisterTestScheme("customstd", "test1");
+ RegisterTestScheme("customstd", "test2");
+
+ XHRTestSettings settings;
+ settings.url = "customstd://test1/run.html";
+ settings.sub_url = "customstd://test2/xhr.html";
+ SetUpXHR(settings);
+
+ EXPECT_TRUE(CefAddCrossOriginWhitelistEntry("customstd://test1", "customstd",
+ "test2", false));
+ WaitForUIThread();
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+ EXPECT_TRUE(g_TestResults.got_sub_request);
+ EXPECT_TRUE(g_TestResults.got_sub_read);
+ EXPECT_TRUE(g_TestResults.got_sub_success);
+
+ EXPECT_TRUE(CefClearCrossOriginWhitelist());
+ WaitForUIThread();
+
+ ClearTestSchemes();
+}
+
+// Same as above but origin whitelist matches any domain.
+TEST(SchemeHandlerTest, CustomStandardXHRDifferentOriginWithWhitelistSync2) {
+ RegisterTestScheme("customstd", "test1");
+ RegisterTestScheme("customstd", "test2");
+
+ XHRTestSettings settings;
+ settings.url = "customstd://test1/run.html";
+ settings.sub_url = "customstd://test2/xhr.html";
+ SetUpXHR(settings);
+
+ EXPECT_TRUE(CefAddCrossOriginWhitelistEntry("customstd://test1", "customstd",
+ CefString(), true));
+ WaitForUIThread();
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+ EXPECT_TRUE(g_TestResults.got_sub_request);
+ EXPECT_TRUE(g_TestResults.got_sub_read);
+ EXPECT_TRUE(g_TestResults.got_sub_success);
+
+ EXPECT_TRUE(CefClearCrossOriginWhitelist());
+ WaitForUIThread();
+
+ ClearTestSchemes();
+}
+
+// Same as above but origin whitelist matches sub-domains.
+TEST(SchemeHandlerTest, CustomStandardXHRDifferentOriginWithWhitelistSync3) {
+ RegisterTestScheme("customstd", "test1");
+ RegisterTestScheme("customstd", "a.test2.foo");
+
+ XHRTestSettings settings;
+ settings.url = "customstd://test1/run.html";
+ settings.sub_url = "customstd://a.test2.foo/xhr.html";
+ SetUpXHR(settings);
+
+ EXPECT_TRUE(CefAddCrossOriginWhitelistEntry("customstd://test1", "customstd",
+ "test2.foo", true));
+ WaitForUIThread();
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+ EXPECT_TRUE(g_TestResults.got_sub_request);
+ EXPECT_TRUE(g_TestResults.got_sub_read);
+ EXPECT_TRUE(g_TestResults.got_sub_success);
+
+ EXPECT_TRUE(CefClearCrossOriginWhitelist());
+ WaitForUIThread();
+
+ ClearTestSchemes();
+}
+
+// Test that a custom standard scheme can generate cross-domain XHR requests
+// when using the cross-origin whitelist.
+TEST(SchemeHandlerTest, CustomStandardXHRDifferentOriginWithWhitelistAsync1) {
+ RegisterTestScheme("customstd", "test1");
+ RegisterTestScheme("customstd", "test2");
+
+ XHRTestSettings settings;
+ settings.url = "customstd://test1/run.html";
+ settings.sub_url = "customstd://test2/xhr.html";
+ settings.synchronous = false;
+ SetUpXHR(settings);
+
+ EXPECT_TRUE(CefAddCrossOriginWhitelistEntry("customstd://test1", "customstd",
+ "test2", false));
+ WaitForUIThread();
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+ EXPECT_TRUE(g_TestResults.got_sub_request);
+ EXPECT_TRUE(g_TestResults.got_sub_read);
+ EXPECT_TRUE(g_TestResults.got_sub_success);
+
+ EXPECT_TRUE(CefClearCrossOriginWhitelist());
+ WaitForUIThread();
+
+ ClearTestSchemes();
+}
+
+// Same as above but origin whitelist matches any domain.
+TEST(SchemeHandlerTest, CustomStandardXHRDifferentOriginWithWhitelistAsync2) {
+ RegisterTestScheme("customstd", "test1");
+ RegisterTestScheme("customstd", "test2");
+
+ XHRTestSettings settings;
+ settings.url = "customstd://test1/run.html";
+ settings.sub_url = "customstd://test2/xhr.html";
+ settings.synchronous = false;
+ SetUpXHR(settings);
+
+ EXPECT_TRUE(CefAddCrossOriginWhitelistEntry("customstd://test1", "customstd",
+ CefString(), true));
+ WaitForUIThread();
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+ EXPECT_TRUE(g_TestResults.got_sub_request);
+ EXPECT_TRUE(g_TestResults.got_sub_read);
+ EXPECT_TRUE(g_TestResults.got_sub_success);
+
+ EXPECT_TRUE(CefClearCrossOriginWhitelist());
+ WaitForUIThread();
+
+ ClearTestSchemes();
+}
+
+// Same as above but origin whitelist matches sub-domains.
+TEST(SchemeHandlerTest, CustomStandardXHRDifferentOriginWithWhitelistAsync3) {
+ RegisterTestScheme("customstd", "test1");
+ RegisterTestScheme("customstd", "a.test2.foo");
+
+ XHRTestSettings settings;
+ settings.url = "customstd://test1/run.html";
+ settings.sub_url = "customstd://a.test2.foo/xhr.html";
+ settings.synchronous = false;
+ SetUpXHR(settings);
+
+ EXPECT_TRUE(CefAddCrossOriginWhitelistEntry("customstd://test1", "customstd",
+ "test2.foo", true));
+ WaitForUIThread();
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+ EXPECT_TRUE(g_TestResults.got_sub_request);
+ EXPECT_TRUE(g_TestResults.got_sub_read);
+ EXPECT_TRUE(g_TestResults.got_sub_success);
+
+ EXPECT_TRUE(CefClearCrossOriginWhitelist());
+ WaitForUIThread();
+
+ ClearTestSchemes();
+}
+
+// Test that a custom standard scheme can generate cross-domain Fetch requests
+// when using the cross-origin whitelist.
+TEST(SchemeHandlerTest, CustomStandardFetchDifferentOriginWithWhitelist1) {
+ RegisterTestScheme("customstdfetch", "test1");
+ RegisterTestScheme("customstdfetch", "test2");
+
+ FetchTestSettings settings;
+ settings.url = "customstdfetch://test1/run.html";
+ settings.sub_url = "customstdfetch://test2/fetch.html";
+ SetUpFetch(settings);
+
+ EXPECT_TRUE(CefAddCrossOriginWhitelistEntry(
+ "customstdfetch://test1", "customstdfetch", "test2", false));
+ WaitForUIThread();
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+ EXPECT_TRUE(g_TestResults.got_sub_request);
+ EXPECT_TRUE(g_TestResults.got_sub_read);
+ EXPECT_TRUE(g_TestResults.got_sub_success);
+
+ EXPECT_TRUE(CefClearCrossOriginWhitelist());
+ WaitForUIThread();
+
+ ClearTestSchemes();
+}
+
+// Same as above but origin whitelist matches any domain.
+TEST(SchemeHandlerTest, CustomStandardFetchDifferentOriginWithWhitelist2) {
+ RegisterTestScheme("customstdfetch", "test1");
+ RegisterTestScheme("customstdfetch", "test2");
+
+ FetchTestSettings settings;
+ settings.url = "customstdfetch://test1/run.html";
+ settings.sub_url = "customstdfetch://test2/fetch.html";
+ SetUpFetch(settings);
+
+ EXPECT_TRUE(CefAddCrossOriginWhitelistEntry(
+ "customstdfetch://test1", "customstdfetch", CefString(), true));
+ WaitForUIThread();
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+ EXPECT_TRUE(g_TestResults.got_sub_request);
+ EXPECT_TRUE(g_TestResults.got_sub_read);
+ EXPECT_TRUE(g_TestResults.got_sub_success);
+
+ EXPECT_TRUE(CefClearCrossOriginWhitelist());
+ WaitForUIThread();
+
+ ClearTestSchemes();
+}
+
+// Same as above but origin whitelist matches sub-domains.
+TEST(SchemeHandlerTest, CustomStandardFetchDifferentOriginWithWhitelist3) {
+ RegisterTestScheme("customstdfetch", "test1");
+ RegisterTestScheme("customstdfetch", "a.test2.foo");
+
+ FetchTestSettings settings;
+ settings.url = "customstdfetch://test1/run.html";
+ settings.sub_url = "customstdfetch://a.test2.foo/fetch.html";
+ SetUpFetch(settings);
+
+ EXPECT_TRUE(CefAddCrossOriginWhitelistEntry(
+ "customstdfetch://test1", "customstdfetch", "test2.foo", true));
+ WaitForUIThread();
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+ EXPECT_TRUE(g_TestResults.got_sub_request);
+ EXPECT_TRUE(g_TestResults.got_sub_read);
+ EXPECT_TRUE(g_TestResults.got_sub_success);
+
+ EXPECT_TRUE(CefClearCrossOriginWhitelist());
+ WaitForUIThread();
+
+ ClearTestSchemes();
+}
+
+// Test that an HTTP scheme can generate cross-domain XHR requests when setting
+// the Access-Control-Allow-Origin header.
+TEST(SchemeHandlerTest, HttpXHRDifferentOriginWithHeaderSync) {
+ RegisterTestScheme("http", "test1");
+ RegisterTestScheme("http", "test2");
+
+ XHRTestSettings settings;
+ settings.url = "http://test1/run.html";
+ settings.sub_url = "http://test2/xhr.html";
+ settings.sub_allow_origin = "http://test1";
+ SetUpXHR(settings);
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+ EXPECT_TRUE(g_TestResults.got_sub_request);
+ EXPECT_TRUE(g_TestResults.got_sub_read);
+ EXPECT_TRUE(g_TestResults.got_sub_success);
+
+ ClearTestSchemes();
+}
+
+// Test that an HTTP scheme can generate cross-domain XHR requests when setting
+// the Access-Control-Allow-Origin header.
+TEST(SchemeHandlerTest, HttpXHRDifferentOriginWithHeaderAsync) {
+ RegisterTestScheme("http", "test1");
+ RegisterTestScheme("http", "test2");
+
+ XHRTestSettings settings;
+ settings.url = "http://test1/run.html";
+ settings.sub_url = "http://test2/xhr.html";
+ settings.sub_allow_origin = "http://test1";
+ settings.synchronous = false;
+ SetUpXHR(settings);
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+ EXPECT_TRUE(g_TestResults.got_sub_request);
+ EXPECT_TRUE(g_TestResults.got_sub_read);
+ EXPECT_TRUE(g_TestResults.got_sub_success);
+
+ ClearTestSchemes();
+}
+
+// Test that an HTTP scheme can generate cross-domain XHR requests when setting
+// the Access-Control-Allow-Origin header.
+TEST(SchemeHandlerTest, HttpFetchDifferentOriginWithHeader) {
+ RegisterTestScheme("http", "test1");
+ RegisterTestScheme("http", "test2");
+
+ FetchTestSettings settings;
+ settings.url = "http://test1/run.html";
+ settings.sub_url = "http://test2/fetch.html";
+ settings.sub_allow_origin = "http://test1";
+ SetUpFetch(settings);
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+ EXPECT_TRUE(g_TestResults.got_sub_request);
+ EXPECT_TRUE(g_TestResults.got_sub_read);
+ EXPECT_TRUE(g_TestResults.got_sub_success);
+
+ ClearTestSchemes();
+}
+
+// Test that a custom standard scheme can generate cross-domain XSS requests
+// when using document.domain.
+TEST(SchemeHandlerTest, CustomStandardXSSDifferentOriginWithDomain) {
+ RegisterTestScheme("customstd", "a.test.com");
+ RegisterTestScheme("customstd", "b.test.com");
+ SetUpXSS("customstd://a.test.com/run.html",
+ "customstd://b.test.com/iframe.html", "test.com");
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+ EXPECT_TRUE(g_TestResults.got_sub_request);
+ EXPECT_TRUE(g_TestResults.got_sub_read);
+ EXPECT_TRUE(g_TestResults.got_sub_success);
+
+ ClearTestSchemes();
+}
+
+// Test that an HTTP scheme can generate cross-domain XSS requests when using
+// document.domain.
+TEST(SchemeHandlerTest, HttpXSSDifferentOriginWithDomain) {
+ RegisterTestScheme("http", "a.test.com");
+ RegisterTestScheme("http", "b.test.com");
+ SetUpXSS("http://a.test.com/run.html", "http://b.test.com/iframe.html",
+ "test.com");
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+ EXPECT_TRUE(g_TestResults.got_sub_request);
+ EXPECT_TRUE(g_TestResults.got_sub_read);
+ EXPECT_TRUE(g_TestResults.got_sub_success);
+
+ ClearTestSchemes();
+}
+
+// Test that a custom standard scheme cannot generate cross-domain XHR requests
+// that perform redirects.
+TEST(SchemeHandlerTest, CustomStandardXHRDifferentOriginRedirectSync) {
+ RegisterTestScheme("customstd", "test1");
+ RegisterTestScheme("customstd", "test2");
+
+ XHRTestSettings settings;
+ settings.url = "customstd://test1/run.html";
+ settings.sub_url = "customstd://test2/xhr.html";
+ settings.sub_redirect_url = "customstd://test1/xhr.html";
+ SetUpXHR(settings);
+
+ g_TestResults.console_messages.push_back(
+ "Access to XMLHttpRequest at 'customstd://test2/xhr.html' (redirected "
+ "from 'customstd://test1/xhr.html') from origin 'customstd://test1' has "
+ "been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is "
+ "present on the requested resource.");
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+ EXPECT_TRUE(g_TestResults.got_sub_redirect);
+ EXPECT_TRUE(g_TestResults.got_sub_request);
+ EXPECT_TRUE(g_TestResults.got_sub_read);
+ EXPECT_FALSE(g_TestResults.got_sub_success);
+
+ ClearTestSchemes();
+}
+
+// Test that a custom standard scheme cannot generate cross-domain XHR requests
+// that perform redirects.
+TEST(SchemeHandlerTest, CustomStandardXHRDifferentOriginRedirectAsync) {
+ RegisterTestScheme("customstd", "test1");
+ RegisterTestScheme("customstd", "test2");
+
+ XHRTestSettings settings;
+ settings.url = "customstd://test1/run.html";
+ settings.sub_url = "customstd://test2/xhr.html";
+ settings.sub_redirect_url = "customstd://test1/xhr.html";
+ settings.synchronous = false;
+ SetUpXHR(settings);
+
+ g_TestResults.console_messages.push_back(
+ "Access to XMLHttpRequest at 'customstd://test2/xhr.html' (redirected "
+ "from 'customstd://test1/xhr.html') from origin 'customstd://test1' has "
+ "been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is "
+ "present on the requested resource.");
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+ EXPECT_TRUE(g_TestResults.got_sub_redirect);
+ EXPECT_TRUE(g_TestResults.got_sub_request);
+ EXPECT_TRUE(g_TestResults.got_sub_read);
+ EXPECT_FALSE(g_TestResults.got_sub_success);
+
+ ClearTestSchemes();
+}
+
+// Test that a custom standard scheme cannot generate cross-domain Fetch
+// requests that perform redirects.
+TEST(SchemeHandlerTest, CustomStandardFetchDifferentOriginRedirect) {
+ RegisterTestScheme("customstdfetch", "test1");
+ RegisterTestScheme("customstdfetch", "test2");
+
+ FetchTestSettings settings;
+ settings.url = "customstdfetch://test1/run.html";
+ settings.sub_url = "customstdfetch://test2/fetch.html";
+ settings.sub_redirect_url = "customstdfetch://test1/fetch.html";
+ SetUpFetch(settings);
+
+ g_TestResults.console_messages.push_back(
+ "Access to fetch at 'customstdfetch://test2/fetch.html' (redirected from "
+ "'customstdfetch://test1/fetch.html') from origin "
+ "'customstdfetch://test1' has been blocked by CORS policy: No "
+ "'Access-Control-Allow-Origin' header is present on the requested "
+ "resource. If an opaque response serves your needs, set the request's "
+ "mode to 'no-cors' to fetch the resource with CORS disabled.");
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+ EXPECT_TRUE(g_TestResults.got_sub_redirect);
+ EXPECT_TRUE(g_TestResults.got_sub_request);
+ EXPECT_TRUE(g_TestResults.got_sub_read);
+ EXPECT_FALSE(g_TestResults.got_sub_success);
+
+ ClearTestSchemes();
+}
+
+// Test that a custom standard scheme can generate cross-domain XHR requests
+// that perform redirects when using the cross-origin whitelist.
+TEST(SchemeHandlerTest,
+ CustomStandardXHRDifferentOriginRedirectWithWhitelistSync) {
+ RegisterTestScheme("customstd", "test1");
+ RegisterTestScheme("customstd", "test2");
+
+ XHRTestSettings settings;
+ settings.url = "customstd://test1/run.html";
+ settings.sub_url = "customstd://test2/xhr.html";
+ settings.sub_redirect_url = "customstd://test1/xhr.html";
+ SetUpXHR(settings);
+
+ EXPECT_TRUE(CefAddCrossOriginWhitelistEntry("customstd://test1", "customstd",
+ "test2", false));
+ WaitForUIThread();
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+ EXPECT_TRUE(g_TestResults.got_sub_redirect);
+ EXPECT_TRUE(g_TestResults.got_sub_request);
+ EXPECT_TRUE(g_TestResults.got_sub_read);
+ EXPECT_TRUE(g_TestResults.got_sub_success);
+
+ EXPECT_TRUE(CefClearCrossOriginWhitelist());
+ WaitForUIThread();
+
+ ClearTestSchemes();
+}
+
+// Test that a custom standard scheme can generate cross-domain XHR requests
+// that perform redirects when using the cross-origin whitelist.
+TEST(SchemeHandlerTest,
+ CustomStandardXHRDifferentOriginRedirectWithWhitelistAsync1) {
+ RegisterTestScheme("customstd", "test1");
+ RegisterTestScheme("customstd", "test2");
+
+ XHRTestSettings settings;
+ settings.url = "customstd://test1/run.html";
+ settings.sub_url = "customstd://test2/xhr.html";
+ settings.sub_redirect_url = "customstd://test1/xhr.html";
+ settings.synchronous = false;
+ SetUpXHR(settings);
+
+ EXPECT_TRUE(CefAddCrossOriginWhitelistEntry("customstd://test1", "customstd",
+ "test2", false));
+ WaitForUIThread();
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+ EXPECT_TRUE(g_TestResults.got_sub_redirect);
+ EXPECT_TRUE(g_TestResults.got_sub_request);
+ EXPECT_TRUE(g_TestResults.got_sub_read);
+ EXPECT_TRUE(g_TestResults.got_sub_success);
+
+ EXPECT_TRUE(CefClearCrossOriginWhitelist());
+ WaitForUIThread();
+
+ ClearTestSchemes();
+}
+
+// Same as above but origin whitelist matches any domain.
+TEST(SchemeHandlerTest,
+ CustomStandardXHRDifferentOriginRedirectWithWhitelistAsync2) {
+ RegisterTestScheme("customstd", "test1");
+ RegisterTestScheme("customstd", "test2");
+
+ XHRTestSettings settings;
+ settings.url = "customstd://test1/run.html";
+ settings.sub_url = "customstd://test2/xhr.html";
+ settings.sub_redirect_url = "customstd://test1/xhr.html";
+ settings.synchronous = false;
+ SetUpXHR(settings);
+
+ EXPECT_TRUE(CefAddCrossOriginWhitelistEntry("customstd://test1", "customstd",
+ CefString(), true));
+ WaitForUIThread();
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+ EXPECT_TRUE(g_TestResults.got_sub_redirect);
+ EXPECT_TRUE(g_TestResults.got_sub_request);
+ EXPECT_TRUE(g_TestResults.got_sub_read);
+ EXPECT_TRUE(g_TestResults.got_sub_success);
+
+ EXPECT_TRUE(CefClearCrossOriginWhitelist());
+ WaitForUIThread();
+
+ ClearTestSchemes();
+}
+
+// Same as above but origin whitelist matches sub-domains.
+TEST(SchemeHandlerTest,
+ CustomStandardXHRDifferentOriginRedirectWithWhitelistAsync3) {
+ RegisterTestScheme("customstd", "test1");
+ RegisterTestScheme("customstd", "a.test2.foo");
+
+ XHRTestSettings settings;
+ settings.url = "customstd://test1/run.html";
+ settings.sub_url = "customstd://a.test2.foo/xhr.html";
+ settings.sub_redirect_url = "customstd://test1/xhr.html";
+ settings.synchronous = false;
+ SetUpXHR(settings);
+
+ EXPECT_TRUE(CefAddCrossOriginWhitelistEntry("customstd://test1", "customstd",
+ "test2.foo", true));
+ WaitForUIThread();
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+ EXPECT_TRUE(g_TestResults.got_sub_redirect);
+ EXPECT_TRUE(g_TestResults.got_sub_request);
+ EXPECT_TRUE(g_TestResults.got_sub_read);
+ EXPECT_TRUE(g_TestResults.got_sub_success);
+
+ EXPECT_TRUE(CefClearCrossOriginWhitelist());
+ WaitForUIThread();
+
+ ClearTestSchemes();
+}
+
+// Test that a custom standard scheme can generate cross-domain Fetch requests
+// that perform redirects when using the cross-origin whitelist.
+TEST(SchemeHandlerTest,
+ CustomStandardFetchDifferentOriginRedirectWithWhitelist1) {
+ RegisterTestScheme("customstdfetch", "test1");
+ RegisterTestScheme("customstdfetch", "test2");
+
+ FetchTestSettings settings;
+ settings.url = "customstdfetch://test1/run.html";
+ settings.sub_url = "customstdfetch://test2/fetch.html";
+ settings.sub_redirect_url = "customstdfetch://test1/fetch.html";
+ SetUpFetch(settings);
+
+ EXPECT_TRUE(CefAddCrossOriginWhitelistEntry(
+ "customstdfetch://test1", "customstdfetch", "test2", false));
+ WaitForUIThread();
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+ EXPECT_TRUE(g_TestResults.got_sub_redirect);
+ EXPECT_TRUE(g_TestResults.got_sub_request);
+ EXPECT_TRUE(g_TestResults.got_sub_read);
+ EXPECT_TRUE(g_TestResults.got_sub_success);
+
+ EXPECT_TRUE(CefClearCrossOriginWhitelist());
+ WaitForUIThread();
+
+ ClearTestSchemes();
+}
+
+// Same as above but origin whitelist matches any domain.
+TEST(SchemeHandlerTest,
+ CustomStandardFetchDifferentOriginRedirectWithWhitelist2) {
+ RegisterTestScheme("customstdfetch", "test1");
+ RegisterTestScheme("customstdfetch", "test2");
+
+ FetchTestSettings settings;
+ settings.url = "customstdfetch://test1/run.html";
+ settings.sub_url = "customstdfetch://test2/fetch.html";
+ settings.sub_redirect_url = "customstdfetch://test1/fetch.html";
+ SetUpFetch(settings);
+
+ EXPECT_TRUE(CefAddCrossOriginWhitelistEntry(
+ "customstdfetch://test1", "customstdfetch", CefString(), true));
+ WaitForUIThread();
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+ EXPECT_TRUE(g_TestResults.got_sub_redirect);
+ EXPECT_TRUE(g_TestResults.got_sub_request);
+ EXPECT_TRUE(g_TestResults.got_sub_read);
+ EXPECT_TRUE(g_TestResults.got_sub_success);
+
+ EXPECT_TRUE(CefClearCrossOriginWhitelist());
+ WaitForUIThread();
+
+ ClearTestSchemes();
+}
+
+// Same as above but origin whitelist matches sub-domains.
+TEST(SchemeHandlerTest,
+ CustomStandardFetchDifferentOriginRedirectWithWhitelist3) {
+ RegisterTestScheme("customstdfetch", "test1");
+ RegisterTestScheme("customstdfetch", "a.test2.foo");
+
+ FetchTestSettings settings;
+ settings.url = "customstdfetch://test1/run.html";
+ settings.sub_url = "customstdfetch://a.test2.foo/fetch.html";
+ settings.sub_redirect_url = "customstdfetch://test1/fetch.html";
+ SetUpFetch(settings);
+
+ EXPECT_TRUE(CefAddCrossOriginWhitelistEntry(
+ "customstdfetch://test1", "customstdfetch", "test2.foo", true));
+ WaitForUIThread();
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+ EXPECT_TRUE(g_TestResults.got_sub_redirect);
+ EXPECT_TRUE(g_TestResults.got_sub_request);
+ EXPECT_TRUE(g_TestResults.got_sub_read);
+ EXPECT_TRUE(g_TestResults.got_sub_success);
+
+ EXPECT_TRUE(CefClearCrossOriginWhitelist());
+ WaitForUIThread();
+
+ ClearTestSchemes();
+}
+
+// Test per-browser setting of Accept-Language.
+TEST(SchemeHandlerTest, AcceptLanguage) {
+ RegisterTestScheme("customstd", "test");
+ g_TestResults.url = "customstd://test/run.html";
+ g_TestResults.html =
+ "<html><head></head><body><h1>Success!</h1></body></html>";
+
+ // Value that will be set via CefBrowserSettings.accept_language in
+ // PopulateBrowserSettings().
+ g_TestResults.accept_language = "uk";
+
+ CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+
+ EXPECT_TRUE(g_TestResults.got_request);
+ EXPECT_TRUE(g_TestResults.got_read);
+ EXPECT_TRUE(g_TestResults.got_output);
+
+ ClearTestSchemes();
+}
+
+// Entry point for registering custom schemes.
+// Called from client_app_delegates.cc.
+void RegisterSchemeHandlerCustomSchemes(
+ CefRawPtr<CefSchemeRegistrar> registrar) {
+ // Registering the custom standard schemes as secure because requests from
+ // non-secure origins to the loopback address will be blocked by
+ // https://chromestatus.com/feature/5436853517811712.
+
+ // Add a custom standard scheme.
+ registrar->AddCustomScheme("customstd", CEF_SCHEME_OPTION_STANDARD |
+ CEF_SCHEME_OPTION_SECURE |
+ CEF_SCHEME_OPTION_CORS_ENABLED);
+ // Also used in cors_unittest.cc.
+ registrar->AddCustomScheme(
+ "customstdfetch", CEF_SCHEME_OPTION_STANDARD | CEF_SCHEME_OPTION_SECURE |
+ CEF_SCHEME_OPTION_CORS_ENABLED |
+ CEF_SCHEME_OPTION_FETCH_ENABLED);
+ // Add a custom non-standard scheme.
+ registrar->AddCustomScheme("customnonstd", CEF_SCHEME_OPTION_NONE);
+ registrar->AddCustomScheme("customnonstdfetch",
+ CEF_SCHEME_OPTION_FETCH_ENABLED);
+}
+
+// Entry point for registering cookieable schemes.
+// Called from client_app_delegates.cc.
+void RegisterSchemeHandlerCookieableSchemes(
+ std::vector<std::string>& cookieable_schemes) {
+ cookieable_schemes.push_back("customstd");
+ // Also used in cors_unittest.cc.
+ cookieable_schemes.push_back("customstdfetch");
+}
diff --git a/tests/ceftests/scoped_temp_dir_unittest.cc b/tests/ceftests/scoped_temp_dir_unittest.cc
new file mode 100644
index 00000000..5728aff7
--- /dev/null
+++ b/tests/ceftests/scoped_temp_dir_unittest.cc
@@ -0,0 +1,90 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. Portions copyright
+// 2011 The Chromium Authors. All rights reserved. Use of this source code is
+// governed by a BSD-style license that can be found in the LICENSE file.
+
+#include <string>
+
+#include "include/cef_file_util.h"
+#include "include/wrapper/cef_scoped_temp_dir.h"
+#include "tests/gtest/include/gtest/gtest.h"
+
+TEST(ScopedTempDir, FullPath) {
+ CefString test_path;
+ CefCreateNewTempDirectory("scoped_temp_dir", test_path);
+
+ // Against an existing dir, it should get destroyed when leaving scope.
+ EXPECT_TRUE(CefDirectoryExists(test_path));
+ {
+ CefScopedTempDir dir;
+ EXPECT_TRUE(dir.Set(test_path));
+ EXPECT_TRUE(dir.IsValid());
+ }
+ EXPECT_FALSE(CefDirectoryExists(test_path));
+
+ {
+ CefScopedTempDir dir;
+ EXPECT_TRUE(dir.Set(test_path));
+ // Now the dir doesn't exist, so ensure that it gets created.
+ EXPECT_TRUE(CefDirectoryExists(test_path));
+ // When we call Take(), it shouldn't get destroyed when leaving scope.
+ CefString path = dir.Take();
+ EXPECT_STREQ(path.ToString().c_str(), test_path.ToString().c_str());
+ EXPECT_FALSE(dir.IsValid());
+ }
+ EXPECT_TRUE(CefDirectoryExists(test_path));
+
+ // Clean up.
+ {
+ CefScopedTempDir dir;
+ EXPECT_TRUE(dir.Set(test_path));
+ }
+ EXPECT_FALSE(CefDirectoryExists(test_path));
+}
+
+TEST(ScopedTempDir, TempDir) {
+ // In this case, just verify that a directory was created and that it's a
+ // child of TempDir.
+ CefString test_path;
+ {
+ CefScopedTempDir dir;
+ EXPECT_TRUE(dir.CreateUniqueTempDir());
+ test_path = dir.GetPath();
+ EXPECT_TRUE(CefDirectoryExists(test_path));
+ CefString tmp_dir;
+ EXPECT_TRUE(CefGetTempDirectory(tmp_dir));
+ EXPECT_TRUE(test_path.ToString().find(tmp_dir.ToString()) !=
+ std::string::npos);
+ }
+ EXPECT_FALSE(CefDirectoryExists(test_path));
+}
+
+TEST(ScopedTempDir, UniqueTempDirUnderPath) {
+ // Create a path which will contain a unique temp path.
+ CefString base_path;
+ ASSERT_TRUE(CefCreateNewTempDirectory("base_dir", base_path));
+
+ CefString test_path;
+ {
+ CefScopedTempDir dir;
+ EXPECT_TRUE(dir.CreateUniqueTempDirUnderPath(base_path));
+ test_path = dir.GetPath();
+ EXPECT_TRUE(CefDirectoryExists(test_path));
+ EXPECT_TRUE(test_path.ToString().find(base_path.ToString()) == 0);
+ }
+ EXPECT_FALSE(CefDirectoryExists(test_path));
+ CefDeleteFile(base_path, true);
+}
+
+TEST(ScopedTempDir, MultipleInvocations) {
+ CefScopedTempDir dir;
+ EXPECT_TRUE(dir.CreateUniqueTempDir());
+ EXPECT_FALSE(dir.CreateUniqueTempDir());
+ EXPECT_TRUE(dir.Delete());
+ EXPECT_TRUE(dir.CreateUniqueTempDir());
+ EXPECT_FALSE(dir.CreateUniqueTempDir());
+ CefScopedTempDir other_dir;
+ EXPECT_TRUE(other_dir.Set(dir.Take()));
+ EXPECT_TRUE(dir.CreateUniqueTempDir());
+ EXPECT_FALSE(dir.CreateUniqueTempDir());
+ EXPECT_FALSE(other_dir.CreateUniqueTempDir());
+}
diff --git a/tests/ceftests/send_shared_process_message_unittest.cc b/tests/ceftests/send_shared_process_message_unittest.cc
new file mode 100644
index 00000000..66cc2589
--- /dev/null
+++ b/tests/ceftests/send_shared_process_message_unittest.cc
@@ -0,0 +1,173 @@
+// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "include/base/cef_callback.h"
+#include "include/cef_shared_process_message_builder.h"
+#include "include/cef_task.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "tests/ceftests/test_handler.h"
+#include "tests/gtest/include/gtest/gtest.h"
+#include "tests/shared/renderer/client_app_renderer.h"
+
+#include <array>
+
+using client::ClientAppRenderer;
+
+namespace {
+
+struct TestData {
+ bool flag = true;
+ int value = 1;
+ double d_value = 77.77;
+ std::array<size_t, 50> buffer{};
+};
+
+const char kSharedMessageUrl[] = "http://tests/SendSharedProcessMessageTest";
+const char kSharedMessageName[] = "SendSharedProcessMessageTest";
+
+CefRefPtr<CefProcessMessage> CreateTestMessage(const TestData& data) {
+ auto builder =
+ CefSharedProcessMessageBuilder::Create(kSharedMessageName, sizeof(data));
+ std::memcpy(builder->Memory(), reinterpret_cast<const void*>(&data),
+ sizeof(data));
+ return builder->Build();
+}
+
+// Renderer side.
+class SharedMessageRendererTest final : public ClientAppRenderer::Delegate {
+ public:
+ bool OnProcessMessageReceived(CefRefPtr<ClientAppRenderer> app,
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefProcessId source_process,
+ CefRefPtr<CefProcessMessage> message) override {
+ if (message->GetName() == kSharedMessageName) {
+ EXPECT_TRUE(browser.get());
+ EXPECT_TRUE(frame.get());
+ EXPECT_EQ(PID_BROWSER, source_process);
+ EXPECT_TRUE(message.get());
+ EXPECT_TRUE(message->IsValid());
+ EXPECT_TRUE(message->IsReadOnly());
+ EXPECT_EQ(message->GetArgumentList(), nullptr);
+
+ const std::string& url = frame->GetURL();
+ if (url == kSharedMessageUrl) {
+ // Echo the message back to the sender natively.
+ frame->SendProcessMessage(PID_BROWSER, message);
+ EXPECT_FALSE(message->IsValid());
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ IMPLEMENT_REFCOUNTING(SharedMessageRendererTest);
+};
+
+// Browser side.
+class SharedMessageTestHandler final : public TestHandler {
+ public:
+ explicit SharedMessageTestHandler(cef_thread_id_t send_thread)
+ : send_thread_(send_thread) {}
+
+ void RunTest() override {
+ AddResource(kSharedMessageUrl, "<html><body>TEST</body></html>",
+ "text/html");
+ CreateBrowser(kSharedMessageUrl);
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout();
+ }
+
+ void OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int httpStatusCode) override {
+ EXPECT_TRUE(CefCurrentlyOn(TID_UI));
+
+ // Send the message to the renderer process.
+ if (!CefCurrentlyOn(send_thread_)) {
+ CefPostTask(send_thread_,
+ base::BindOnce(&SharedMessageTestHandler::SendProcessMessage,
+ this, browser, frame));
+ } else {
+ SendProcessMessage(browser, frame);
+ }
+ }
+
+ bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefProcessId source_process,
+ CefRefPtr<CefProcessMessage> message) override {
+ EXPECT_TRUE(CefCurrentlyOn(TID_UI));
+ EXPECT_TRUE(browser.get());
+ EXPECT_TRUE(frame.get());
+ EXPECT_EQ(PID_RENDERER, source_process);
+ EXPECT_TRUE(message.get());
+ EXPECT_TRUE(message->IsValid());
+ EXPECT_TRUE(message->IsReadOnly());
+ EXPECT_EQ(message->GetArgumentList(), nullptr);
+
+ // Verify that the recieved message is the same as the sent message.
+ auto region = message->GetSharedMemoryRegion();
+ const TestData* received = static_cast<const TestData*>(region->Memory());
+ EXPECT_EQ(data_.flag, received->flag);
+ EXPECT_EQ(data_.value, received->value);
+ EXPECT_EQ(data_.d_value, received->d_value);
+
+ got_message_.yes();
+
+ // Test is complete.
+ DestroyTest();
+
+ return true;
+ }
+
+ protected:
+ void DestroyTest() override {
+ EXPECT_TRUE(got_message_);
+ TestHandler::DestroyTest();
+ }
+
+ private:
+ void SendProcessMessage(const CefRefPtr<CefBrowser>& browser,
+ const CefRefPtr<CefFrame>& frame) {
+ EXPECT_TRUE(CefCurrentlyOn(send_thread_));
+
+ auto message = CreateTestMessage(data_);
+ frame->SendProcessMessage(PID_RENDERER, message);
+
+ // The message is invalidated immediately
+ EXPECT_FALSE(message->IsValid());
+ }
+
+ cef_thread_id_t send_thread_;
+ TrackCallback got_message_;
+ const TestData data_;
+
+ IMPLEMENT_REFCOUNTING(SharedMessageTestHandler);
+};
+
+} // namespace
+
+TEST(SendSharedProcessMessageTest, CanSendAndReceiveFromUiThread) {
+ CefRefPtr<SharedMessageTestHandler> handler =
+ new SharedMessageTestHandler(TID_UI);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(SendSharedProcessMessageTest, CanSendAndReceiveFromIoThread) {
+ CefRefPtr<SharedMessageTestHandler> handler =
+ new SharedMessageTestHandler(TID_IO);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Entry point for creating shared process message renderer test objects.
+// Called from client_app_delegates.cc.
+void CreateSharedProcessMessageTests(
+ ClientAppRenderer::DelegateSet& delegates) {
+ delegates.insert(new SharedMessageRendererTest());
+}
diff --git a/tests/ceftests/server_unittest.cc b/tests/ceftests/server_unittest.cc
new file mode 100644
index 00000000..c558e564
--- /dev/null
+++ b/tests/ceftests/server_unittest.cc
@@ -0,0 +1,1498 @@
+// Copyright (c) 2017 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include <list>
+#include <map>
+#include <memory>
+#include <set>
+
+#include "include/base/cef_callback.h"
+#include "include/base/cef_ref_counted.h"
+#include "include/cef_command_line.h"
+#include "include/cef_server.h"
+#include "include/cef_task.h"
+#include "include/cef_urlrequest.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "tests/ceftests/routing_test_handler.h"
+#include "tests/ceftests/test_util.h"
+#include "tests/gtest/include/gtest/gtest.h"
+
+namespace {
+
+// Must use a different port than test_server.cc.
+const char kTestServerAddress[] = "127.0.0.1";
+const uint16 kTestServerPort = 8099;
+const int kTestTimeout = 5000;
+
+std::string GetTestServerOrigin(bool is_websocket) {
+ std::stringstream ss;
+ ss << (is_websocket ? "ws://" : "http://") << kTestServerAddress << ":"
+ << kTestServerPort;
+ return ss.str();
+}
+
+// Handles the test server. Used for both HTTP and WebSocket tests.
+class TestServerHandler : public CefServerHandler {
+ public:
+ // HTTP test handler.
+ // The methods of this class are always executed on the server thread.
+ class HttpRequestHandler {
+ public:
+ virtual ~HttpRequestHandler() {}
+ virtual bool HandleRequest(CefRefPtr<CefServer> server,
+ int connection_id,
+ const CefString& client_address,
+ CefRefPtr<CefRequest> request) = 0;
+ virtual bool VerifyResults() = 0;
+ virtual std::string ToString() = 0;
+ };
+
+ // WebSocket test handler.
+ // The methods of this class are always executed on the server thread.
+ class WsRequestHandler {
+ public:
+ virtual ~WsRequestHandler() {}
+ virtual bool HandleRequest(CefRefPtr<CefServer> server,
+ int connection_id,
+ const CefString& client_address,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefCallback> callback) = 0;
+ virtual bool HandleConnected(CefRefPtr<CefServer> server,
+ int connection_id) = 0;
+ virtual bool HandleMessage(CefRefPtr<CefServer> server,
+ int connection_id,
+ const void* data,
+ size_t data_size) = 0;
+ virtual bool VerifyResults() = 0;
+ virtual std::string ToString() = 0;
+ };
+
+ // |start_callback| will be executed on the UI thread after the server is
+ // started.
+ // |destroy_callback| will be executed on the UI thread after this handler
+ // object is destroyed.
+ TestServerHandler(base::OnceClosure start_callback,
+ base::OnceClosure destroy_callback)
+ : initialized_(false),
+ start_callback_(std::move(start_callback)),
+ destroy_callback_(std::move(destroy_callback)),
+ expected_connection_ct_(0),
+ actual_connection_ct_(0),
+ expected_http_request_ct_(0),
+ actual_http_request_ct_(0),
+ expected_ws_request_ct_(0),
+ actual_ws_request_ct_(0),
+ expected_ws_connected_ct_(0),
+ actual_ws_connected_ct_(0),
+ expected_ws_message_ct_(0),
+ actual_ws_message_ct_(0) {
+ EXPECT_FALSE(destroy_callback_.is_null());
+ }
+
+ virtual ~TestServerHandler() {
+ EXPECT_UI_THREAD();
+
+ if (!http_request_handler_list_.empty()) {
+ HttpRequestHandlerList::const_iterator it =
+ http_request_handler_list_.begin();
+ for (; it != http_request_handler_list_.end(); ++it) {
+ delete *it;
+ }
+ }
+
+ if (!ws_request_handler_list_.empty()) {
+ WsRequestHandlerList::const_iterator it =
+ ws_request_handler_list_.begin();
+ for (; it != ws_request_handler_list_.end(); ++it) {
+ delete *it;
+ }
+ }
+
+ std::move(destroy_callback_).Run();
+ }
+
+ // Must be called before CreateServer().
+ void SetExpectedConnectionCount(int expected) {
+ EXPECT_FALSE(initialized_);
+ expected_connection_ct_ = expected;
+ }
+
+ // Must be called before CreateServer().
+ void AddHttpRequestHandler(
+ std::unique_ptr<HttpRequestHandler> request_handler) {
+ EXPECT_FALSE(initialized_);
+ EXPECT_TRUE(request_handler);
+ http_request_handler_list_.push_back(request_handler.release());
+ }
+
+ // Must be called before CreateServer().
+ void SetExpectedHttpRequestCount(int expected) {
+ EXPECT_FALSE(initialized_);
+ expected_http_request_ct_ = expected;
+ }
+
+ // Must be called before CreateServer().
+ void AddWsRequestHandler(std::unique_ptr<WsRequestHandler> request_handler) {
+ EXPECT_FALSE(initialized_);
+ EXPECT_TRUE(request_handler);
+ ws_request_handler_list_.push_back(request_handler.release());
+ }
+
+ // Must be called before CreateServer().
+ void SetExpectedWsRequestCount(int expected) {
+ EXPECT_FALSE(initialized_);
+ expected_ws_request_ct_ = expected;
+ }
+
+ // Must be called before CreateServer().
+ void SetExpectedWsConnectedCount(int expected) {
+ EXPECT_FALSE(initialized_);
+ expected_ws_connected_ct_ = expected;
+ }
+
+ // Must be called before CreateServer().
+ void SetExpectedWsMessageCount(int expected) {
+ EXPECT_FALSE(initialized_);
+ expected_ws_message_ct_ = expected;
+ }
+
+ void CreateServer() {
+ EXPECT_FALSE(initialized_);
+ initialized_ = true;
+ CefServer::CreateServer(kTestServerAddress, kTestServerPort, 10, this);
+ }
+
+ // Results in a call to VerifyResults() and eventual execution of the
+ // |destroy_callback|.
+ void ShutdownServer() {
+ EXPECT_TRUE(server_);
+ if (server_) {
+ server_->Shutdown();
+ }
+ }
+
+ void OnServerCreated(CefRefPtr<CefServer> server) override {
+ EXPECT_TRUE(server);
+ EXPECT_TRUE(server->IsRunning());
+ EXPECT_FALSE(server->HasConnection());
+
+ EXPECT_FALSE(got_server_created_);
+ got_server_created_.yes();
+
+ EXPECT_FALSE(server_);
+ server_ = server;
+
+ EXPECT_FALSE(server_runner_);
+ server_runner_ = server_->GetTaskRunner();
+ EXPECT_TRUE(server_runner_);
+ EXPECT_TRUE(server_runner_->BelongsToCurrentThread());
+
+ RunStartCallback();
+ }
+
+ void OnServerDestroyed(CefRefPtr<CefServer> server) override {
+ EXPECT_TRUE(VerifyServer(server));
+ EXPECT_FALSE(server->IsRunning());
+ EXPECT_FALSE(server->HasConnection());
+
+ EXPECT_FALSE(got_server_destroyed_);
+ got_server_destroyed_.yes();
+
+ server_ = nullptr;
+
+ VerifyResults();
+ }
+
+ void OnClientConnected(CefRefPtr<CefServer> server,
+ int connection_id) override {
+ EXPECT_TRUE(VerifyServer(server));
+ EXPECT_TRUE(server->HasConnection());
+ EXPECT_TRUE(server->IsValidConnection(connection_id));
+
+ EXPECT_TRUE(connection_id_set_.find(connection_id) ==
+ connection_id_set_.end());
+ connection_id_set_.insert(connection_id);
+
+ actual_connection_ct_++;
+ }
+
+ void OnClientDisconnected(CefRefPtr<CefServer> server,
+ int connection_id) override {
+ EXPECT_TRUE(VerifyServer(server));
+ EXPECT_FALSE(server->IsValidConnection(connection_id));
+
+ ConnectionIdSet::iterator it = connection_id_set_.find(connection_id);
+ EXPECT_TRUE(it != connection_id_set_.end());
+ connection_id_set_.erase(it);
+
+ ConnectionIdSet::iterator it2 = ws_connection_id_set_.find(connection_id);
+ if (it2 != ws_connection_id_set_.end()) {
+ ws_connection_id_set_.erase(it2);
+ }
+
+ if (connection_id_set_.empty()) {
+ EXPECT_TRUE(ws_connection_id_set_.empty());
+ EXPECT_FALSE(server->HasConnection());
+ }
+ }
+
+ void OnHttpRequest(CefRefPtr<CefServer> server,
+ int connection_id,
+ const CefString& client_address,
+ CefRefPtr<CefRequest> request) override {
+ EXPECT_TRUE(VerifyServer(server));
+ EXPECT_TRUE(VerifyConnection(connection_id));
+ EXPECT_FALSE(client_address.empty());
+ EXPECT_TRUE(VerifyRequest(request, false));
+
+ bool handled = false;
+ HttpRequestHandlerList::const_iterator it =
+ http_request_handler_list_.begin();
+ for (; it != http_request_handler_list_.end(); ++it) {
+ handled =
+ (*it)->HandleRequest(server, connection_id, client_address, request);
+ if (handled) {
+ break;
+ }
+ }
+ EXPECT_TRUE(handled) << "missing HttpRequestHandler for "
+ << request->GetURL().ToString();
+
+ actual_http_request_ct_++;
+ }
+
+ void OnWebSocketRequest(CefRefPtr<CefServer> server,
+ int connection_id,
+ const CefString& client_address,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefCallback> callback) override {
+ EXPECT_TRUE(VerifyServer(server));
+ EXPECT_TRUE(VerifyConnection(connection_id));
+ EXPECT_FALSE(client_address.empty());
+ EXPECT_TRUE(VerifyRequest(request, true));
+
+ EXPECT_TRUE(ws_connection_id_set_.find(connection_id) ==
+ ws_connection_id_set_.end());
+ ws_connection_id_set_.insert(connection_id);
+
+ bool handled = false;
+ WsRequestHandlerList::const_iterator it = ws_request_handler_list_.begin();
+ for (; it != ws_request_handler_list_.end(); ++it) {
+ handled = (*it)->HandleRequest(server, connection_id, client_address,
+ request, callback);
+ if (handled) {
+ break;
+ }
+ }
+ EXPECT_TRUE(handled) << "missing WsRequestHandler for "
+ << request->GetURL().ToString();
+
+ actual_ws_request_ct_++;
+ }
+
+ void OnWebSocketConnected(CefRefPtr<CefServer> server,
+ int connection_id) override {
+ EXPECT_TRUE(VerifyServer(server));
+ EXPECT_TRUE(VerifyConnection(connection_id));
+
+ EXPECT_TRUE(ws_connection_id_set_.find(connection_id) !=
+ ws_connection_id_set_.end());
+
+ bool handled = false;
+ WsRequestHandlerList::const_iterator it = ws_request_handler_list_.begin();
+ for (; it != ws_request_handler_list_.end(); ++it) {
+ handled = (*it)->HandleConnected(server, connection_id);
+ if (handled) {
+ break;
+ }
+ }
+ EXPECT_TRUE(handled) << "missing WsRequestHandler for " << connection_id;
+
+ actual_ws_connected_ct_++;
+ }
+
+ void OnWebSocketMessage(CefRefPtr<CefServer> server,
+ int connection_id,
+ const void* data,
+ size_t data_size) override {
+ EXPECT_TRUE(VerifyServer(server));
+ EXPECT_TRUE(VerifyConnection(connection_id));
+ EXPECT_TRUE(data);
+ EXPECT_GT(data_size, 0U);
+
+ EXPECT_TRUE(ws_connection_id_set_.find(connection_id) !=
+ ws_connection_id_set_.end());
+
+ bool handled = false;
+ WsRequestHandlerList::const_iterator it = ws_request_handler_list_.begin();
+ for (; it != ws_request_handler_list_.end(); ++it) {
+ handled = (*it)->HandleMessage(server, connection_id, data, data_size);
+ if (handled) {
+ break;
+ }
+ }
+ EXPECT_TRUE(handled) << "missing WsRequestHandler for " << connection_id;
+
+ actual_ws_message_ct_++;
+ }
+
+ private:
+ bool RunningOnServerThread() {
+ return server_runner_ && server_runner_->BelongsToCurrentThread();
+ }
+
+ bool VerifyServer(CefRefPtr<CefServer> server) {
+ V_DECLARE();
+ V_EXPECT_TRUE(RunningOnServerThread());
+ V_EXPECT_TRUE(server);
+ V_EXPECT_TRUE(server_);
+ V_EXPECT_TRUE(server->GetAddress().ToString() ==
+ server_->GetAddress().ToString());
+ V_RETURN();
+ }
+
+ bool VerifyConnection(int connection_id) {
+ return connection_id_set_.find(connection_id) != connection_id_set_.end();
+ }
+
+ bool VerifyRequest(CefRefPtr<CefRequest> request, bool is_websocket) {
+ V_DECLARE();
+
+ V_EXPECT_FALSE(request->GetMethod().empty());
+
+ const std::string& url = request->GetURL();
+ V_EXPECT_FALSE(url.empty());
+ const std::string& address = server_->GetAddress();
+ V_EXPECT_TRUE(url.find((is_websocket ? "ws://" : "http://") + address) == 0)
+ << "url " << url << " address " << address;
+
+ CefRefPtr<CefPostData> post_data = request->GetPostData();
+ if (post_data) {
+ CefPostData::ElementVector elements;
+ post_data->GetElements(elements);
+ V_EXPECT_TRUE(elements.size() == 1);
+ V_EXPECT_TRUE(elements[0]->GetBytesCount() > 0U);
+ }
+
+ V_RETURN();
+ }
+
+ void VerifyResults() {
+ EXPECT_TRUE(RunningOnServerThread());
+
+ EXPECT_TRUE(got_server_created_);
+ EXPECT_TRUE(got_server_destroyed_);
+ EXPECT_TRUE(connection_id_set_.empty());
+ EXPECT_EQ(expected_connection_ct_, actual_connection_ct_);
+
+ // HTTP
+
+ EXPECT_EQ(expected_http_request_ct_, actual_http_request_ct_);
+
+ if (!http_request_handler_list_.empty()) {
+ HttpRequestHandlerList::const_iterator it =
+ http_request_handler_list_.begin();
+ for (; it != http_request_handler_list_.end(); ++it) {
+ EXPECT_TRUE((*it)->VerifyResults())
+ << "HttpRequestHandler for " << (*it)->ToString();
+ }
+ }
+
+ // WebSocket
+
+ EXPECT_EQ(expected_ws_request_ct_, actual_ws_request_ct_);
+ EXPECT_EQ(expected_ws_connected_ct_, actual_ws_connected_ct_);
+ EXPECT_EQ(expected_ws_message_ct_, actual_ws_message_ct_);
+
+ if (!ws_request_handler_list_.empty()) {
+ WsRequestHandlerList::const_iterator it =
+ ws_request_handler_list_.begin();
+ for (; it != ws_request_handler_list_.end(); ++it) {
+ EXPECT_TRUE((*it)->VerifyResults())
+ << "WsRequestHandler for " << (*it)->ToString();
+ }
+ }
+ }
+
+ private:
+ void RunStartCallback() {
+ if (!CefCurrentlyOn(TID_UI)) {
+ CefPostTask(TID_UI,
+ base::BindOnce(&TestServerHandler::RunStartCallback, this));
+ return;
+ }
+
+ EXPECT_FALSE(start_callback_.is_null());
+ std::move(start_callback_).Run();
+ }
+
+ CefRefPtr<CefServer> server_;
+ CefRefPtr<CefTaskRunner> server_runner_;
+ bool initialized_;
+
+ // After initialization only accessed on the UI thread.
+ base::OnceClosure start_callback_;
+ base::OnceClosure destroy_callback_;
+
+ // After initialization the below members are only accessed on the server
+ // thread.
+
+ TrackCallback got_server_created_;
+ TrackCallback got_server_destroyed_;
+
+ typedef std::set<int> ConnectionIdSet;
+ ConnectionIdSet connection_id_set_;
+
+ int expected_connection_ct_;
+ int actual_connection_ct_;
+
+ // HTTP
+
+ typedef std::list<HttpRequestHandler*> HttpRequestHandlerList;
+ HttpRequestHandlerList http_request_handler_list_;
+
+ int expected_http_request_ct_;
+ int actual_http_request_ct_;
+
+ // WebSocket
+
+ typedef std::list<WsRequestHandler*> WsRequestHandlerList;
+ WsRequestHandlerList ws_request_handler_list_;
+
+ ConnectionIdSet ws_connection_id_set_;
+
+ int expected_ws_request_ct_;
+ int actual_ws_request_ct_;
+
+ int expected_ws_connected_ct_;
+ int actual_ws_connected_ct_;
+
+ int expected_ws_message_ct_;
+ int actual_ws_message_ct_;
+
+ IMPLEMENT_REFCOUNTING(TestServerHandler);
+ DISALLOW_COPY_AND_ASSIGN(TestServerHandler);
+};
+
+// HTTP TESTS
+
+// Test runner for 1 or more HTTP requests/responses.
+// Works similarly to TestHandler but without the CefClient dependencies.
+class HttpTestRunner : public base::RefCountedThreadSafe<HttpTestRunner> {
+ public:
+ // The methods of this class are always executed on the UI thread.
+ class RequestRunner {
+ public:
+ virtual ~RequestRunner() {}
+
+ // Create the server-side handler for the request.
+ virtual std::unique_ptr<TestServerHandler::HttpRequestHandler>
+ CreateHttpRequestHandler() = 0;
+
+ // Run the request and execute |complete_callback| on completion.
+ virtual void RunRequest(base::OnceClosure complete_callback) = 0;
+
+ virtual bool VerifyResults() = 0;
+ virtual std::string ToString() = 0;
+ };
+
+ // If |parallel_requests| is true all requests will be run at the same time,
+ // otherwise one request will be run at a time.
+ HttpTestRunner(bool parallel_requests)
+ : parallel_requests_(parallel_requests),
+ initialized_(false),
+ next_request_id_(0) {}
+
+ virtual ~HttpTestRunner() {
+ if (destroy_event_) {
+ destroy_event_->Signal();
+ }
+ }
+
+ void AddRequestRunner(std::unique_ptr<RequestRunner> request_runner) {
+ EXPECT_FALSE(initialized_);
+ request_runner_map_.insert(
+ std::make_pair(++next_request_id_, request_runner.release()));
+ }
+
+ // Blocks until the test has completed or timed out.
+ void ExecuteTest() {
+ EXPECT_FALSE(CefCurrentlyOn(TID_UI));
+
+ handler_ = new TestServerHandler(
+ base::BindOnce(&HttpTestRunner::OnServerStarted, this),
+ base::BindOnce(&HttpTestRunner::OnServerDestroyed, this));
+
+ run_event_ = CefWaitableEvent::CreateWaitableEvent(false, false);
+
+ CefPostTask(TID_UI, base::BindOnce(&HttpTestRunner::RunTest, this));
+
+ // Block until test completion.
+ run_event_->Wait();
+ }
+
+ // Event that will be signaled from the HttpTestRunner destructor.
+ // Used by ReleaseAndWaitForDestructor.
+ void SetDestroyEvent(CefRefPtr<CefWaitableEvent> event) {
+ destroy_event_ = event;
+ }
+
+ private:
+ void RunTest() {
+ EXPECT_UI_THREAD();
+ EXPECT_FALSE(initialized_);
+ initialized_ = true;
+
+ EXPECT_FALSE(request_runner_map_.empty());
+ RequestRunnerMap::const_iterator it = request_runner_map_.begin();
+ for (; it != request_runner_map_.end(); ++it) {
+ handler_->AddHttpRequestHandler(it->second->CreateHttpRequestHandler());
+ }
+
+ handler_->SetExpectedConnectionCount(
+ static_cast<int>(request_runner_map_.size()));
+ handler_->SetExpectedHttpRequestCount(
+ static_cast<int>(request_runner_map_.size()));
+
+ handler_->CreateServer();
+
+ SetTestTimeout(kTestTimeout);
+ }
+
+ void OnServerStarted() {
+ EXPECT_UI_THREAD();
+ if (parallel_requests_) {
+ RunAllRequests();
+ } else {
+ RunNextRequest();
+ }
+ }
+
+ void OnServerDestroyed() {
+ EXPECT_UI_THREAD();
+ EXPECT_FALSE(got_server_destroyed_);
+ got_server_destroyed_.yes();
+
+ // Allow the call stack to unwind.
+ CefPostTask(TID_UI, base::BindOnce(&HttpTestRunner::DestroyTest, this));
+ }
+
+ // Run all requests in parallel.
+ void RunAllRequests() {
+ RequestRunnerMap::const_iterator it = request_runner_map_.begin();
+ for (; it != request_runner_map_.end(); ++it) {
+ it->second->RunRequest(
+ base::BindOnce(&HttpTestRunner::OnRequestComplete, this, it->first));
+ }
+ }
+
+ // Run one request at a time.
+ void RunNextRequest() {
+ RequestRunnerMap::const_iterator it = request_runner_map_.begin();
+ it->second->RunRequest(
+ base::BindOnce(&HttpTestRunner::OnRequestComplete, this, it->first));
+ }
+
+ void OnRequestComplete(int request_id) {
+ EXPECT_UI_THREAD()
+ // Allow the call stack to unwind.
+ CefPostTask(TID_UI,
+ base::BindOnce(&HttpTestRunner::OnRequestCompleteContinue, this,
+ request_id));
+ }
+
+ void OnRequestCompleteContinue(int request_id) {
+ RequestRunnerMap::iterator it = request_runner_map_.find(request_id);
+ EXPECT_TRUE(it != request_runner_map_.end());
+
+ // Verify the request results.
+ EXPECT_TRUE(it->second->VerifyResults())
+ << "request_id " << request_id << " RequestRunner for "
+ << it->second->ToString();
+ delete it->second;
+ request_runner_map_.erase(it);
+
+ if (request_runner_map_.empty()) {
+ got_all_requests_.yes();
+
+ // Will trigger TestServerHandler::HttpRequestHandler verification and a
+ // call to OnServerDestroyed().
+ handler_->ShutdownServer();
+ handler_ = nullptr;
+ } else if (!parallel_requests_) {
+ RunNextRequest();
+ }
+ }
+
+ void DestroyTest() {
+ EXPECT_UI_THREAD();
+
+ EXPECT_TRUE(got_all_requests_);
+ EXPECT_TRUE(got_server_destroyed_);
+ EXPECT_TRUE(request_runner_map_.empty());
+
+ // Cancel the timeout, if any.
+ if (ui_thread_helper_) {
+ ui_thread_helper_.reset();
+ }
+
+ // Signal test completion.
+ run_event_->Signal();
+ }
+
+ TestHandler::UIThreadHelper* GetUIThreadHelper() {
+ EXPECT_UI_THREAD();
+ if (!ui_thread_helper_) {
+ ui_thread_helper_.reset(new TestHandler::UIThreadHelper());
+ }
+ return ui_thread_helper_.get();
+ }
+
+ void SetTestTimeout(int timeout_ms) {
+ EXPECT_UI_THREAD();
+ const auto timeout = GetConfiguredTestTimeout(timeout_ms);
+ if (!timeout) {
+ return;
+ }
+
+ // Use a weak reference to |this| via UIThreadHelper so that the
+ // test runner can be destroyed before the timeout expires.
+ GetUIThreadHelper()->PostDelayedTask(
+ base::BindOnce(&HttpTestRunner::OnTestTimeout, base::Unretained(this),
+ *timeout),
+ *timeout);
+ }
+
+ void OnTestTimeout(int timeout_ms) {
+ EXPECT_UI_THREAD();
+ EXPECT_TRUE(false) << "Test timed out after " << timeout_ms << "ms";
+ DestroyTest();
+ }
+
+ bool parallel_requests_;
+ CefRefPtr<CefWaitableEvent> run_event_;
+ CefRefPtr<CefWaitableEvent> destroy_event_;
+ CefRefPtr<TestServerHandler> handler_;
+ bool initialized_;
+
+ // After initialization the below members are only accessed on the UI thread.
+
+ int next_request_id_;
+
+ // Map of request ID to RequestRunner.
+ typedef std::map<int, RequestRunner*> RequestRunnerMap;
+ RequestRunnerMap request_runner_map_;
+
+ TrackCallback got_all_requests_;
+ TrackCallback got_server_destroyed_;
+
+ std::unique_ptr<TestHandler::UIThreadHelper> ui_thread_helper_;
+
+ DISALLOW_COPY_AND_ASSIGN(HttpTestRunner);
+};
+
+// Structure representing the data that can be sent via
+// CefServer::SendHttp*Response().
+struct HttpServerResponse {
+ enum Type { TYPE_200, TYPE_404, TYPE_500, TYPE_CUSTOM };
+
+ explicit HttpServerResponse(Type response_type)
+ : type(response_type), no_content_length(false) {}
+
+ Type type;
+
+ // Used with 200 and CUSTOM response type.
+ std::string content;
+ std::string content_type;
+
+ // Used with 500 response type.
+ std::string error_message;
+
+ // Used with CUSTOM response type.
+ int response_code;
+ CefServer::HeaderMap extra_headers;
+ bool no_content_length;
+};
+
+void SendHttpServerResponse(CefRefPtr<CefServer> server,
+ int connection_id,
+ const HttpServerResponse& response) {
+ EXPECT_TRUE(server->GetTaskRunner()->BelongsToCurrentThread());
+ EXPECT_TRUE(server->IsValidConnection(connection_id));
+
+ switch (response.type) {
+ case HttpServerResponse::TYPE_200:
+ EXPECT_TRUE(!response.content_type.empty());
+ server->SendHttp200Response(connection_id, response.content_type,
+ response.content.data(),
+ response.content.size());
+ break;
+ case HttpServerResponse::TYPE_404:
+ server->SendHttp404Response(connection_id);
+ break;
+ case HttpServerResponse::TYPE_500:
+ server->SendHttp500Response(connection_id, response.error_message);
+ break;
+ case HttpServerResponse::TYPE_CUSTOM:
+ EXPECT_TRUE(!response.content_type.empty());
+ server->SendHttpResponse(
+ connection_id, response.response_code, response.content_type,
+ response.no_content_length
+ ? -1
+ : static_cast<int64>(response.content.size()),
+ response.extra_headers);
+ if (!response.content.empty()) {
+ server->SendRawData(connection_id, response.content.data(),
+ response.content.size());
+ }
+ if (!response.content.empty() ||
+ (response.content.empty() && response.no_content_length)) {
+ server->CloseConnection(connection_id);
+ }
+ break;
+ }
+
+ // All of the above responses should close the connection.
+ EXPECT_FALSE(server->IsValidConnection(connection_id));
+}
+
+std::string GetHeaderValue(const CefServer::HeaderMap& header_map,
+ const std::string& header_name) {
+ CefServer::HeaderMap::const_iterator it = header_map.find(header_name);
+ if (it != header_map.end()) {
+ return it->second;
+ }
+ return std::string();
+}
+
+void VerifyHttpServerResponse(const HttpServerResponse& expected_response,
+ CefRefPtr<CefResponse> response,
+ const std::string& data) {
+ CefServer::HeaderMap header_map;
+ response->GetHeaderMap(header_map);
+
+ switch (expected_response.type) {
+ case HttpServerResponse::TYPE_200:
+ EXPECT_EQ(200, response->GetStatus());
+ EXPECT_STREQ(expected_response.content_type.c_str(),
+ GetHeaderValue(header_map, "Content-Type").c_str());
+ EXPECT_STREQ(expected_response.content.c_str(), data.c_str());
+ break;
+ case HttpServerResponse::TYPE_404:
+ EXPECT_EQ(404, response->GetStatus());
+ break;
+ case HttpServerResponse::TYPE_500:
+ EXPECT_EQ(500, response->GetStatus());
+ break;
+ case HttpServerResponse::TYPE_CUSTOM:
+ EXPECT_EQ(expected_response.response_code, response->GetStatus());
+ EXPECT_STREQ(expected_response.content_type.c_str(),
+ GetHeaderValue(header_map, "Content-Type").c_str());
+ if (expected_response.no_content_length) {
+ EXPECT_TRUE(GetHeaderValue(header_map, "Content-Length").empty());
+ } else {
+ EXPECT_FALSE(GetHeaderValue(header_map, "Content-Length").empty());
+ }
+ EXPECT_STREQ(expected_response.content.c_str(), data.c_str());
+ TestMapEqual(expected_response.extra_headers, header_map, true);
+ break;
+ }
+}
+
+CefRefPtr<CefRequest> CreateTestServerRequest(
+ const std::string& path,
+ const std::string& method,
+ const std::string& data = std::string(),
+ const std::string& content_type = std::string(),
+ const CefRequest::HeaderMap& extra_headers = CefRequest::HeaderMap()) {
+ CefRefPtr<CefRequest> request = CefRequest::Create();
+ request->SetURL(GetTestServerOrigin(false) + "/" + path);
+ request->SetMethod(method);
+
+ CefRequest::HeaderMap header_map;
+
+ if (!data.empty()) {
+ CefRefPtr<CefPostData> post_data = CefPostData::Create();
+ CefRefPtr<CefPostDataElement> post_element = CefPostDataElement::Create();
+ post_element->SetToBytes(data.size(), data.data());
+ post_data->AddElement(post_element);
+ request->SetPostData(post_data);
+
+ EXPECT_FALSE(content_type.empty());
+ header_map.insert(std::make_pair("content-type", content_type));
+ }
+
+ if (!extra_headers.empty()) {
+ header_map.insert(extra_headers.begin(), extra_headers.end());
+ }
+ request->SetHeaderMap(header_map);
+
+ return request;
+}
+
+// RequestHandler that returns a static response for 1 or more requests.
+class StaticHttpServerRequestHandler
+ : public TestServerHandler::HttpRequestHandler {
+ public:
+ StaticHttpServerRequestHandler(CefRefPtr<CefRequest> expected_request,
+ int expected_request_ct,
+ const HttpServerResponse& response)
+ : expected_request_(expected_request),
+ expected_request_ct_(expected_request_ct),
+ actual_request_ct_(0),
+ response_(response) {}
+
+ bool HandleRequest(CefRefPtr<CefServer> server,
+ int connection_id,
+ const CefString& client_address,
+ CefRefPtr<CefRequest> request) override {
+ if (request->GetURL() == expected_request_->GetURL() &&
+ request->GetMethod() == expected_request_->GetMethod()) {
+ TestRequestEqual(expected_request_, request, true);
+ actual_request_ct_++;
+
+ SendHttpServerResponse(server, connection_id, response_);
+ return true;
+ }
+
+ return false;
+ }
+
+ bool VerifyResults() override {
+ EXPECT_EQ(expected_request_ct_, actual_request_ct_);
+ return expected_request_ct_ == actual_request_ct_;
+ }
+
+ std::string ToString() override { return expected_request_->GetURL(); }
+
+ private:
+ CefRefPtr<CefRequest> expected_request_;
+ int expected_request_ct_;
+ int actual_request_ct_;
+ HttpServerResponse response_;
+
+ DISALLOW_COPY_AND_ASSIGN(StaticHttpServerRequestHandler);
+};
+
+// URLRequestClient that runs a single request and executes a callback with the
+// response.
+class StaticHttpURLRequestClient : public CefURLRequestClient {
+ public:
+ using ResponseCallback =
+ base::OnceCallback<void(cef_errorcode_t /* error */,
+ CefRefPtr<CefResponse> /* response */,
+ const std::string& /* data */)>;
+
+ // |response_callback| will be executed on the UI thread when the response
+ // is complete.
+ StaticHttpURLRequestClient(CefRefPtr<CefRequest> request,
+ ResponseCallback response_callback)
+ : request_(request), response_callback_(std::move(response_callback)) {
+ EXPECT_TRUE(request_);
+ EXPECT_FALSE(response_callback_.is_null());
+ }
+
+ void RunRequest() {
+ EXPECT_UI_THREAD();
+ CefURLRequest::Create(request_, this, nullptr);
+ }
+
+ void OnRequestComplete(CefRefPtr<CefURLRequest> request) override {
+ EXPECT_FALSE(response_callback_.is_null());
+ std::move(response_callback_)
+ .Run(request->GetRequestError(), request->GetResponse(), data_);
+ }
+
+ void OnUploadProgress(CefRefPtr<CefURLRequest> request,
+ int64 current,
+ int64 total) override {}
+
+ void OnDownloadProgress(CefRefPtr<CefURLRequest> request,
+ int64 current,
+ int64 total) override {}
+
+ void OnDownloadData(CefRefPtr<CefURLRequest> request,
+ const void* data,
+ size_t data_length) override {
+ data_.append(static_cast<const char*>(data), data_length);
+ }
+
+ bool GetAuthCredentials(bool isProxy,
+ const CefString& host,
+ int port,
+ const CefString& realm,
+ const CefString& scheme,
+ CefRefPtr<CefAuthCallback> callback) override {
+ return false;
+ }
+
+ private:
+ CefRefPtr<CefRequest> request_;
+ ResponseCallback response_callback_;
+ std::string data_;
+
+ IMPLEMENT_REFCOUNTING(StaticHttpURLRequestClient);
+ DISALLOW_COPY_AND_ASSIGN(StaticHttpURLRequestClient);
+};
+
+// RequestRunner that will manage a single static HTTP request/response.
+class StaticHttpRequestRunner : public HttpTestRunner::RequestRunner {
+ public:
+ StaticHttpRequestRunner(CefRefPtr<CefRequest> request,
+ const HttpServerResponse& response)
+ : request_(request), response_(response) {}
+
+ static std::unique_ptr<HttpTestRunner::RequestRunner> Create200(
+ const std::string& path,
+ bool with_content = true) {
+ CefRefPtr<CefRequest> request = CreateTestServerRequest(path, "GET");
+ HttpServerResponse response(HttpServerResponse::TYPE_200);
+ response.content_type = "text/html";
+ if (with_content) {
+ response.content = "<html>200 response content</html>";
+ }
+ return std::make_unique<StaticHttpRequestRunner>(request, response);
+ }
+
+ static std::unique_ptr<HttpTestRunner::RequestRunner> Create404(
+ const std::string& path) {
+ CefRefPtr<CefRequest> request = CreateTestServerRequest(path, "GET");
+ HttpServerResponse response(HttpServerResponse::TYPE_404);
+ return std::make_unique<StaticHttpRequestRunner>(request, response);
+ }
+
+ static std::unique_ptr<HttpTestRunner::RequestRunner> Create500(
+ const std::string& path) {
+ CefRefPtr<CefRequest> request = CreateTestServerRequest(path, "GET");
+ // Don't retry the request.
+ request->SetFlags(UR_FLAG_NO_RETRY_ON_5XX);
+ HttpServerResponse response(HttpServerResponse::TYPE_500);
+ response.error_message = "Something went wrong!";
+ return std::make_unique<StaticHttpRequestRunner>(request, response);
+ }
+
+ static std::unique_ptr<HttpTestRunner::RequestRunner> CreateCustom(
+ const std::string& path,
+ bool with_content = true,
+ bool with_content_length = true) {
+ CefRequest::HeaderMap request_headers;
+ request_headers.insert(std::make_pair("x-request-custom1", "My Value A"));
+ request_headers.insert(std::make_pair("x-request-custom2", "My Value B"));
+ CefRefPtr<CefRequest> request = CreateTestServerRequest(
+ path, "POST", "foo=bar&choo=too", "application/x-www-form-urlencoded",
+ request_headers);
+ request->SetReferrer("http://tests/referer.html", REFERRER_POLICY_DEFAULT);
+
+ HttpServerResponse response(HttpServerResponse::TYPE_CUSTOM);
+ response.response_code = 202;
+ if (with_content) {
+ response.content = "BlahBlahBlah";
+ }
+ if (!with_content_length) {
+ response.no_content_length = true;
+ }
+ response.content_type = "application/x-blah-blah";
+ response.extra_headers.insert(
+ std::make_pair("x-response-custom1", "My Value 1"));
+ response.extra_headers.insert(
+ std::make_pair("x-response-custom2", "My Value 2"));
+
+ return std::make_unique<StaticHttpRequestRunner>(request, response);
+ }
+
+ std::unique_ptr<TestServerHandler::HttpRequestHandler>
+ CreateHttpRequestHandler() override {
+ EXPECT_FALSE(got_create_handler_);
+ got_create_handler_.yes();
+ return std::make_unique<StaticHttpServerRequestHandler>(request_, 1,
+ response_);
+ }
+
+ void RunRequest(base::OnceClosure complete_callback) override {
+ EXPECT_UI_THREAD();
+
+ EXPECT_FALSE(got_run_request_);
+ got_run_request_.yes();
+
+ complete_callback_ = std::move(complete_callback);
+
+ request_client_ = new StaticHttpURLRequestClient(
+ request_, base::BindOnce(&StaticHttpRequestRunner::OnResponseComplete,
+ base::Unretained(this)));
+ request_client_->RunRequest();
+ }
+
+ bool VerifyResults() override {
+ V_DECLARE();
+ V_EXPECT_TRUE(got_create_handler_);
+ V_EXPECT_TRUE(got_run_request_);
+ V_EXPECT_TRUE(got_response_complete_);
+ V_RETURN();
+ }
+
+ std::string ToString() override { return request_->GetURL(); }
+
+ private:
+ void OnResponseComplete(cef_errorcode_t error,
+ CefRefPtr<CefResponse> response,
+ const std::string& data) {
+ EXPECT_UI_THREAD();
+
+ EXPECT_FALSE(got_response_complete_);
+ got_response_complete_.yes();
+
+ EXPECT_EQ(error, ERR_NONE)
+ << "OnResponseComplete for " << request_->GetURL().ToString();
+ if (error == ERR_NONE) {
+ VerifyHttpServerResponse(response_, response, data);
+ }
+
+ std::move(complete_callback_).Run();
+ }
+
+ CefRefPtr<CefRequest> request_;
+ HttpServerResponse response_;
+
+ CefRefPtr<StaticHttpURLRequestClient> request_client_;
+ base::OnceClosure complete_callback_;
+
+ TrackCallback got_run_request_;
+ TrackCallback got_create_handler_;
+ TrackCallback got_response_complete_;
+
+ DISALLOW_COPY_AND_ASSIGN(StaticHttpRequestRunner);
+};
+
+} // namespace
+
+// Verify handling of a single HTTP 200 request.
+TEST(ServerTest, HttpSingle200) {
+ CefRefPtr<HttpTestRunner> runner = new HttpTestRunner(false);
+ runner->AddRequestRunner(StaticHttpRequestRunner::Create200("200.html"));
+ runner->ExecuteTest();
+ ReleaseAndWaitForDestructor(runner);
+}
+
+// Verify handling of a single HTTP 200 request with no content.
+TEST(ServerTest, HttpSingle200NoContent) {
+ CefRefPtr<HttpTestRunner> runner = new HttpTestRunner(false);
+ runner->AddRequestRunner(
+ StaticHttpRequestRunner::Create200("200.html", false));
+ runner->ExecuteTest();
+ ReleaseAndWaitForDestructor(runner);
+}
+
+// Verify handling of a single HTTP 404 request.
+TEST(ServerTest, HttpSingle404) {
+ CefRefPtr<HttpTestRunner> runner = new HttpTestRunner(false);
+ runner->AddRequestRunner(StaticHttpRequestRunner::Create404("404.html"));
+ runner->ExecuteTest();
+ ReleaseAndWaitForDestructor(runner);
+}
+
+// Verify handling of a single HTTP 500 request.
+TEST(ServerTest, HttpSingle500) {
+ CefRefPtr<HttpTestRunner> runner = new HttpTestRunner(false);
+ runner->AddRequestRunner(StaticHttpRequestRunner::Create500("500.html"));
+ runner->ExecuteTest();
+ ReleaseAndWaitForDestructor(runner);
+}
+
+// Verify handling of a single HTTP custom request.
+TEST(ServerTest, HttpSingleCustom) {
+ CefRefPtr<HttpTestRunner> runner = new HttpTestRunner(false);
+ runner->AddRequestRunner(StaticHttpRequestRunner::CreateCustom("202.html"));
+ runner->ExecuteTest();
+ ReleaseAndWaitForDestructor(runner);
+}
+
+// Verify handling of a single HTTP custom request with no content.
+TEST(ServerTest, HttpSingleCustomNoContent) {
+ CefRefPtr<HttpTestRunner> runner = new HttpTestRunner(false);
+ runner->AddRequestRunner(
+ StaticHttpRequestRunner::CreateCustom("202.html", false));
+ runner->ExecuteTest();
+ ReleaseAndWaitForDestructor(runner);
+}
+
+// Verify handling of a single HTTP custom request with no Content-Length
+// header.
+TEST(ServerTest, HttpSingleCustomNoContentLength) {
+ CefRefPtr<HttpTestRunner> runner = new HttpTestRunner(false);
+ runner->AddRequestRunner(
+ StaticHttpRequestRunner::CreateCustom("202.html", true, false));
+ runner->ExecuteTest();
+ ReleaseAndWaitForDestructor(runner);
+}
+
+// Verify handling of a single HTTP custom request with no content and no
+// Content-Length header.
+TEST(ServerTest, HttpSingleCustomNoContentAndNoLength) {
+ CefRefPtr<HttpTestRunner> runner = new HttpTestRunner(false);
+ runner->AddRequestRunner(
+ StaticHttpRequestRunner::CreateCustom("202.html", false, false));
+ runner->ExecuteTest();
+ ReleaseAndWaitForDestructor(runner);
+}
+
+// Verify handling of multiple HTTP requests in parallel.
+TEST(ServerTest, HttpMultipleParallel200) {
+ CefRefPtr<HttpTestRunner> runner = new HttpTestRunner(true);
+ runner->AddRequestRunner(StaticHttpRequestRunner::Create200("200a.html"));
+ runner->AddRequestRunner(StaticHttpRequestRunner::Create200("200b.html"));
+ runner->AddRequestRunner(StaticHttpRequestRunner::Create200("200c.html"));
+ runner->ExecuteTest();
+ ReleaseAndWaitForDestructor(runner);
+}
+
+// Verify handling of multiple HTTP requests in serial.
+TEST(ServerTest, HttpMultipleSerial200) {
+ CefRefPtr<HttpTestRunner> runner = new HttpTestRunner(false);
+ runner->AddRequestRunner(StaticHttpRequestRunner::Create200("200a.html"));
+ runner->AddRequestRunner(StaticHttpRequestRunner::Create200("200b.html"));
+ runner->AddRequestRunner(StaticHttpRequestRunner::Create200("200c.html"));
+ runner->ExecuteTest();
+ ReleaseAndWaitForDestructor(runner);
+}
+
+// Verify handling of multiple HTTP requests in parallel.
+TEST(ServerTest, HttpMultipleParallelMixed) {
+ CefRefPtr<HttpTestRunner> runner = new HttpTestRunner(true);
+ runner->AddRequestRunner(StaticHttpRequestRunner::Create200("200.html"));
+ runner->AddRequestRunner(StaticHttpRequestRunner::Create404("404.html"));
+ runner->AddRequestRunner(StaticHttpRequestRunner::Create500("500.html"));
+ runner->AddRequestRunner(StaticHttpRequestRunner::CreateCustom("202.html"));
+ runner->ExecuteTest();
+ ReleaseAndWaitForDestructor(runner);
+}
+
+// Verify handling of multiple HTTP requests in serial.
+TEST(ServerTest, HttpMultipleSerialMixed) {
+ CefRefPtr<HttpTestRunner> runner = new HttpTestRunner(false);
+ runner->AddRequestRunner(StaticHttpRequestRunner::Create200("200.html"));
+ runner->AddRequestRunner(StaticHttpRequestRunner::Create404("404.html"));
+ runner->AddRequestRunner(StaticHttpRequestRunner::Create500("500.html"));
+ runner->AddRequestRunner(StaticHttpRequestRunner::CreateCustom("202.html"));
+ runner->ExecuteTest();
+ ReleaseAndWaitForDestructor(runner);
+}
+
+namespace {
+
+// WEBSOCKET TESTS
+
+const char kWebSocketUrl[] = "http://tests-display/websocket.html";
+const char kDoneMsgPrefix[] = "done:";
+
+class WebSocketTestHandler : public RoutingTestHandler {
+ public:
+ WebSocketTestHandler() {}
+
+ void RunTest() override {
+ handler_ = new TestServerHandler(
+ base::BindOnce(&WebSocketTestHandler::OnServerStarted, this),
+ base::BindOnce(&WebSocketTestHandler::OnServerDestroyed, this));
+ OnHandlerCreated(handler_);
+
+ handler_->CreateServer();
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout();
+ }
+
+ bool OnQuery(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int64 query_id,
+ const CefString& request,
+ bool persistent,
+ CefRefPtr<Callback> callback) override {
+ const std::string& request_str = request.ToString();
+ if (request_str.find(kDoneMsgPrefix) == 0) {
+ EXPECT_FALSE(got_done_message_);
+ got_done_message_.yes();
+ OnDoneMessage(request_str.substr(strlen(kDoneMsgPrefix)));
+ DestroyTestIfDone();
+ return true;
+ }
+ return false;
+ }
+
+ void DestroyTest() override {
+ EXPECT_TRUE(got_server_started_);
+ EXPECT_TRUE(got_done_message_);
+ EXPECT_TRUE(got_server_destroyed_);
+
+ TestHandler::DestroyTest();
+ }
+
+ protected:
+ // Returns the HTML/JS for the client.
+ virtual std::string GetClientHtml() = 0;
+
+ // Called after the server handler is created to set test expectations.
+ virtual void OnHandlerCreated(CefRefPtr<TestServerHandler> handler) = 0;
+
+ // Returns the JS to execute when the test is done.
+ std::string GetDoneJS(const std::string& result) {
+ return "window.testQuery({request:'" + std::string(kDoneMsgPrefix) +
+ "' + " + result + "});";
+ }
+
+ // Called with the result from the done message.
+ virtual void OnDoneMessage(const std::string& result) = 0;
+
+ void ShutdownServer() {
+ EXPECT_TRUE(handler_);
+ handler_->ShutdownServer();
+ handler_ = nullptr;
+ }
+
+ private:
+ void OnServerStarted() {
+ EXPECT_UI_THREAD();
+ EXPECT_FALSE(got_server_started_);
+ got_server_started_.yes();
+
+ // Add the WebSocket client code.
+ AddResource(kWebSocketUrl, GetClientHtml(), "text/html");
+
+ // Create the browser.
+ CreateBrowser(kWebSocketUrl);
+ }
+
+ void OnServerDestroyed() {
+ EXPECT_UI_THREAD();
+ EXPECT_FALSE(got_server_destroyed_);
+ got_server_destroyed_.yes();
+ DestroyTestIfDone();
+ }
+
+ void DestroyTestIfDone() {
+ if (got_server_destroyed_ && got_done_message_) {
+ // Allow the call stack to unwind.
+ CefPostTask(TID_UI,
+ base::BindOnce(&WebSocketTestHandler::DestroyTest, this));
+ }
+ }
+
+ CefRefPtr<TestServerHandler> handler_;
+
+ TrackCallback got_server_started_;
+ TrackCallback got_done_message_;
+ TrackCallback got_server_destroyed_;
+
+ DISALLOW_COPY_AND_ASSIGN(WebSocketTestHandler);
+};
+
+// WebSocket request handler that echoes each message sent.
+class EchoWebSocketRequestHandler : public TestServerHandler::WsRequestHandler {
+ public:
+ explicit EchoWebSocketRequestHandler(int expected_message_ct)
+ : expected_message_ct_(expected_message_ct), actual_message_ct_(0) {}
+
+ std::string GetWebSocketUrl() { return GetTestServerOrigin(true) + "/echo"; }
+
+ bool HandleRequest(CefRefPtr<CefServer> server,
+ int connection_id,
+ const CefString& client_address,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefCallback> callback) override {
+ EXPECT_STREQ(GetWebSocketUrl().c_str(),
+ request->GetURL().ToString().c_str());
+
+ callback->Continue();
+ return true;
+ }
+
+ bool HandleConnected(CefRefPtr<CefServer> server,
+ int connection_id) override {
+ return true;
+ }
+
+ bool HandleMessage(CefRefPtr<CefServer> server,
+ int connection_id,
+ const void* data,
+ size_t data_size) override {
+ actual_message_ct_++;
+
+ // Echo the message back to the sender.
+ server->SendWebSocketMessage(connection_id, data, data_size);
+
+ return true;
+ }
+
+ bool VerifyResults() override {
+ EXPECT_EQ(expected_message_ct_, actual_message_ct_);
+ return expected_message_ct_ == actual_message_ct_;
+ }
+
+ std::string ToString() override { return "EchoRequestHandler"; }
+
+ private:
+ int expected_message_ct_;
+ int actual_message_ct_;
+
+ DISALLOW_COPY_AND_ASSIGN(EchoWebSocketRequestHandler);
+};
+
+class EchoWebSocketTestHandler : public WebSocketTestHandler {
+ public:
+ // Create |connection_ct| connections and send |message_ct| messages to each
+ // connection. If |in_parallel| is true the connections will be created in
+ // parallel.
+ EchoWebSocketTestHandler(int connection_ct, int message_ct, bool in_parallel)
+ : connection_ct_(connection_ct),
+ message_ct_(message_ct),
+ in_parallel_(in_parallel) {}
+
+ std::string GetClientHtml() override {
+ std::stringstream ss;
+ ss << connection_ct_;
+ std::string cct_str = ss.str();
+ ss.str("");
+ ss << message_ct_;
+ std::string mct_str = ss.str();
+
+ // clang-format off
+ return
+ "<html><body><script>\n"
+
+ // Input variables.
+ "var url = '" + ws_url_ +"';\n"
+ "var expected_connection_ct = " + cct_str + ";\n"
+ "var expected_message_ct = " + mct_str + ";\n"
+ "var in_parallel = " + (in_parallel_ ? "true" : "false") + ";\n"
+ "var complete_callback = function() { " +
+ GetDoneJS("complete_message_ct") + " }\n"
+
+ // Result variables.
+ "var complete_connection_ct = 0;\n"
+ "var complete_message_ct = 0;\n"
+
+ // Send the next message on the connection asynchronously, or close the
+ // connection if all messages have been sent.
+ "function sendNextMessage(ws, connection_id, message_id) {\n"
+ " if (message_id < expected_message_ct) {\n"
+ " setTimeout(function() {\n"
+ " ws.send('message:' + connection_id + ':' + message_id);\n"
+ " }, 1);\n"
+ " } else {\n"
+ " ws.close();\n"
+ " }\n"
+ "}\n"
+
+ // Handle a received message.
+ "function onMessage(ws, connection_id, data) {\n"
+ " var parts = data.split(':');\n"
+ " if (parts.length == 3 && parts[0] == 'message') {\n"
+ " var cid = parseInt(parts[1]);\n"
+ " var mid = parseInt(parts[2]);\n"
+ " if (cid == connection_id) {\n"
+ " complete_message_ct++;\n"
+ " sendNextMessage(ws, connection_id, mid + 1);\n"
+ " } else {\n"
+ " console.log('Connection id mismatch; expected ' +\n"
+ " connection_id + ', actual ' + cid);\n"
+ " }\n"
+ " } else {\n"
+ " console.log('Unexpected message format: ' + data);\n"
+ " }\n"
+ "}\n"
+
+ // Handle socket closed. If all messages have been sent on all
+ // connections then complete the test.
+ "function onClose(ws) {\n"
+ " if (++complete_connection_ct == expected_connection_ct) {\n"
+ " complete_callback();\n"
+ " } else if (!in_parallel) {\n"
+ " startConnection(complete_connection_ct);\n"
+ " }\n"
+ "}\n"
+
+ // Start a new WebSocket connection.
+ "function startConnection(connection_id) {\n"
+ " var ws = new WebSocket(url);\n"
+ " ws.onopen = function() {\n"
+ " sendNextMessage(ws, connection_id, 0);\n"
+ " };\n"
+ " ws.onmessage = function(event) {\n"
+ " onMessage(ws, connection_id, event.data);\n"
+ " };\n"
+ " ws.onclose = function() { onClose(ws); };\n"
+ "}\n"
+
+ // JS entry point.
+ "if (in_parallel) {\n"
+ " for (var i = 0; i < expected_connection_ct; ++i) {\n"
+ " startConnection(i);\n"
+ " }\n"
+ "} else {\n"
+ " startConnection(0);\n"
+ "}\n"
+
+ "</script>WebSocket Test</body></html>";
+ // clang-format on
+ }
+
+ void OnHandlerCreated(CefRefPtr<TestServerHandler> handler) override {
+ handler->SetExpectedConnectionCount(connection_ct_);
+ handler->SetExpectedWsRequestCount(connection_ct_);
+ handler->SetExpectedWsConnectedCount(connection_ct_);
+ handler->SetExpectedWsMessageCount(connection_ct_ * message_ct_);
+
+ auto echo_handler = std::make_unique<EchoWebSocketRequestHandler>(
+ connection_ct_ * message_ct_);
+ ws_url_ = echo_handler->GetWebSocketUrl();
+ handler->AddWsRequestHandler(std::move(echo_handler));
+ }
+
+ void OnDoneMessage(const std::string& result) override {
+ const int complete_message_ct = atoi(result.c_str());
+ EXPECT_EQ(connection_ct_ * message_ct_, complete_message_ct);
+ ShutdownServer();
+ }
+
+ private:
+ int connection_ct_;
+ int message_ct_;
+ bool in_parallel_;
+ std::string ws_url_;
+
+ IMPLEMENT_REFCOUNTING(EchoWebSocketTestHandler);
+ DISALLOW_COPY_AND_ASSIGN(EchoWebSocketTestHandler);
+};
+
+} // namespace
+
+// Test handling of a single connection with a single message.
+TEST(ServerTest, WebSocketSingleConnectionSingleMessage) {
+ CefRefPtr<EchoWebSocketTestHandler> handler =
+ new EchoWebSocketTestHandler(1, 1, true);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Test handling of a single connection with multiple messages.
+TEST(ServerTest, WebSocketSingleConnectionMultipleMessages) {
+ CefRefPtr<EchoWebSocketTestHandler> handler =
+ new EchoWebSocketTestHandler(1, 5, true);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Test handling of multiple connections and multiple messages in parallel.
+TEST(ServerTest, WebSocketMultipleConnectionsMultipleMessagesInParallel) {
+ CefRefPtr<EchoWebSocketTestHandler> handler =
+ new EchoWebSocketTestHandler(4, 6, true);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Test handling of multiple connections and multiple messages in serial.
+TEST(ServerTest, WebSocketMultipleConnectionsMultipleMessagesInSerial) {
+ CefRefPtr<EchoWebSocketTestHandler> handler =
+ new EchoWebSocketTestHandler(4, 6, false);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
diff --git a/tests/ceftests/shared_process_message_unittest.cc b/tests/ceftests/shared_process_message_unittest.cc
new file mode 100644
index 00000000..ed1730aa
--- /dev/null
+++ b/tests/ceftests/shared_process_message_unittest.cc
@@ -0,0 +1,94 @@
+// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "include/cef_shared_process_message_builder.h"
+
+#include "tests/gtest/include/gtest/gtest.h"
+
+#include <array>
+
+namespace {
+
+constexpr bool kTestFlag = true;
+constexpr int kTestValue = 42;
+constexpr double kTestDoubleValue = 123.456;
+
+struct TestData {
+ bool flag = kTestFlag;
+ int value = kTestValue;
+ double doubleValue = kTestDoubleValue;
+ std::array<size_t, 50> buffer{};
+};
+
+const char kSharedMessageName[] = "SharedProcessMessageTest";
+
+CefRefPtr<CefSharedProcessMessageBuilder> CreateTestBuilder() {
+ auto builder = CefSharedProcessMessageBuilder::Create(kSharedMessageName,
+ sizeof(TestData));
+ EXPECT_NE(builder, nullptr);
+ EXPECT_TRUE(builder->IsValid());
+
+ auto data = static_cast<TestData*>(builder->Memory());
+ EXPECT_NE(data, nullptr);
+
+ data->value = kTestValue;
+ data->doubleValue = kTestDoubleValue;
+ data->flag = kTestFlag;
+ for (size_t i = 0; i < data->buffer.size(); ++i) {
+ data->buffer[i] = i;
+ }
+
+ return builder;
+}
+
+} // namespace
+
+TEST(SharedProcessMessageTest, CanBuildSharedMessageUsingBuilder) {
+ auto builder = CreateTestBuilder();
+
+ auto message = builder->Build();
+ EXPECT_FALSE(builder->IsValid());
+ EXPECT_NE(message, nullptr);
+ EXPECT_TRUE(message->IsValid());
+ EXPECT_TRUE(message->IsReadOnly());
+
+ auto region = message->GetSharedMemoryRegion();
+ EXPECT_TRUE(region->IsValid());
+ auto read_data = static_cast<const TestData*>(region->Memory());
+
+ EXPECT_EQ(read_data->flag, kTestFlag);
+ EXPECT_EQ(read_data->value, kTestValue);
+ EXPECT_EQ(read_data->doubleValue, kTestDoubleValue);
+ for (size_t i = 0; i < read_data->buffer.size(); ++i) {
+ EXPECT_EQ(read_data->buffer[i], i);
+ }
+}
+
+TEST(SharedProcessMessageTest, CopyingIsNotSupportedBySharedMessage) {
+ auto builder = CefSharedProcessMessageBuilder::Create(kSharedMessageName,
+ sizeof(TestData));
+ CefRefPtr<CefProcessMessage> message = builder->Build();
+ CefRefPtr<CefProcessMessage> message_copy = message->Copy();
+ EXPECT_EQ(message_copy, nullptr);
+}
+
+TEST(SharedProcessMessageTest,
+ RegionRemainsValidAfterSharedMessageDestruction) {
+ CefRefPtr<CefSharedMemoryRegion> region;
+ {
+ auto builder = CreateTestBuilder();
+ auto message = builder->Build();
+ region = message->GetSharedMemoryRegion();
+ }
+
+ EXPECT_TRUE(region->IsValid());
+ auto read_data = static_cast<const TestData*>(region->Memory());
+
+ EXPECT_EQ(read_data->flag, kTestFlag);
+ EXPECT_EQ(read_data->value, kTestValue);
+ EXPECT_EQ(read_data->doubleValue, kTestDoubleValue);
+ for (size_t i = 0; i < read_data->buffer.size(); ++i) {
+ EXPECT_EQ(read_data->buffer[i], i);
+ }
+}
diff --git a/tests/ceftests/stream_resource_handler_unittest.cc b/tests/ceftests/stream_resource_handler_unittest.cc
new file mode 100644
index 00000000..0c83d3c2
--- /dev/null
+++ b/tests/ceftests/stream_resource_handler_unittest.cc
@@ -0,0 +1,180 @@
+// Copyright (c) 2014 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include <algorithm>
+#include <cstdlib>
+#include <string>
+
+#include "include/base/cef_callback.h"
+#include "include/cef_stream.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "include/wrapper/cef_stream_resource_handler.h"
+#include "tests/ceftests/routing_test_handler.h"
+#include "tests/gtest/include/gtest/gtest.h"
+
+namespace {
+
+const char kTestUrl[] = "http://tests-srh/test.html";
+const size_t kReadBlockSize = 1024U; // 1k.
+
+// The usual network buffer size is about 32k. Choose a value that's larger.
+const size_t kReadDesiredSize = 100U * 1024U; // 100k
+
+class ReadHandler : public CefReadHandler {
+ public:
+ explicit ReadHandler(bool may_block)
+ : may_block_(may_block), offset_(0), expected_result_(0) {}
+
+ void CreateContent() {
+ // To verify that the data transers successfully we're going to make a big
+ // math problem.
+ content_.reserve(kReadDesiredSize + 50U);
+ content_ = "<html><body><script>var myratherlongvariablename=0;";
+
+ while (content_.size() < kReadDesiredSize) {
+ content_ += "myratherlongvariablename=myratherlongvariablename+1;";
+ expected_result_++;
+ }
+
+ content_ +=
+ "window.testQuery({request:myratherlongvariablename+''});"
+ "</script></body></html>";
+ }
+
+ int GetExpectedResult() const { return expected_result_; }
+
+ size_t Read(void* ptr, size_t size, size_t n) override {
+ EXPECT_EQ(1U, size);
+
+ // Read the minimum of requested size, remaining size or kReadBlockSize.
+ const size_t read_bytes =
+ std::min(std::min(size * n, content_.size() - offset_), kReadBlockSize);
+ if (read_bytes > 0) {
+ memcpy(ptr, content_.c_str() + offset_, read_bytes);
+ offset_ += read_bytes;
+ }
+
+ return read_bytes;
+ }
+
+ int Seek(int64 offset, int whence) override {
+ EXPECT_TRUE(false); // Not reached.
+ return 0;
+ }
+
+ int64 Tell() override {
+ EXPECT_TRUE(false); // Not reached.
+ return 0;
+ }
+
+ int Eof() override {
+ EXPECT_TRUE(false); // Not reached.
+ return 0;
+ }
+
+ bool MayBlock() override { return may_block_; }
+
+ private:
+ const bool may_block_;
+ std::string content_;
+ size_t offset_;
+ int expected_result_;
+
+ IMPLEMENT_REFCOUNTING(ReadHandler);
+};
+
+class ReadTestHandler : public RoutingTestHandler {
+ public:
+ explicit ReadTestHandler(bool may_block)
+ : may_block_(may_block), expected_result_(0) {}
+
+ void RunTest() override {
+ // Create the browser.
+ CreateBrowser(kTestUrl);
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout();
+ }
+
+ CefRefPtr<CefResourceHandler> GetResourceHandler(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request) override {
+ got_resource_handler_.yes();
+
+ const std::string& url = request->GetURL();
+ EXPECT_STREQ(kTestUrl, url.c_str());
+
+ CefRefPtr<ReadHandler> handler = new ReadHandler(may_block_);
+ handler->CreateContent();
+ expected_result_ = handler->GetExpectedResult();
+
+ CefRefPtr<CefStreamReader> stream =
+ CefStreamReader::CreateForHandler(handler.get());
+ return new CefStreamResourceHandler("text/html", stream);
+ }
+
+ bool OnQuery(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int64 query_id,
+ const CefString& request,
+ bool persistent,
+ CefRefPtr<Callback> callback) override {
+ got_on_query_.yes();
+
+ const int actual_result = atoi(request.ToString().c_str());
+ EXPECT_EQ(expected_result_, actual_result);
+
+ DestroyTestIfDone();
+
+ return true;
+ }
+
+ void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
+ bool isLoading,
+ bool canGoBack,
+ bool canGoForward) override {
+ if (!isLoading) {
+ got_on_loading_state_change_done_.yes();
+ DestroyTestIfDone();
+ }
+ }
+
+ private:
+ void DestroyTestIfDone() {
+ if (got_on_query_ && got_on_loading_state_change_done_) {
+ DestroyTest();
+ }
+ }
+
+ void DestroyTest() override {
+ EXPECT_TRUE(got_resource_handler_);
+ EXPECT_TRUE(got_on_query_);
+ EXPECT_TRUE(got_on_loading_state_change_done_);
+ RoutingTestHandler::DestroyTest();
+ }
+
+ const bool may_block_;
+
+ int expected_result_;
+ TrackCallback got_resource_handler_;
+ TrackCallback got_on_query_;
+ TrackCallback got_on_loading_state_change_done_;
+
+ IMPLEMENT_REFCOUNTING(ReadTestHandler);
+};
+
+} // namespace
+
+TEST(StreamResourceHandlerTest, ReadWillBlock) {
+ CefRefPtr<ReadTestHandler> handler = new ReadTestHandler(true);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+TEST(StreamResourceHandlerTest, ReadWontBlock) {
+ CefRefPtr<ReadTestHandler> handler = new ReadTestHandler(false);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
diff --git a/tests/ceftests/stream_unittest.cc b/tests/ceftests/stream_unittest.cc
new file mode 100644
index 00000000..89c7df9e
--- /dev/null
+++ b/tests/ceftests/stream_unittest.cc
@@ -0,0 +1,367 @@
+// Copyright (c) 2009 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include <algorithm>
+
+#include "include/cef_stream.h"
+#include "tests/gtest/include/gtest/gtest.h"
+
+static void VerifyStreamReadBehavior(CefRefPtr<CefStreamReader> stream,
+ const std::string& contents) {
+ int contentSize = static_cast<int>(contents.size());
+ const char* contentStr = contents.c_str();
+
+ // Move to the beginning of the stream
+ ASSERT_EQ(0, stream->Seek(0, SEEK_SET));
+ ASSERT_EQ(0, stream->Tell());
+
+ // Move to the end of the stream
+ ASSERT_EQ(0, stream->Seek(0, SEEK_END));
+ ASSERT_EQ(contentSize, stream->Tell());
+
+ // Move to the beginning of the stream
+ ASSERT_EQ(0, stream->Seek(-contentSize, SEEK_CUR));
+ ASSERT_EQ(0, stream->Tell());
+
+ // Read 10 characters at a time and verify the result
+ char buff[10];
+ int res, read, offset = 0;
+ do {
+ read = std::min(static_cast<int>(sizeof(buff)), contentSize - offset);
+ res = static_cast<int>(stream->Read(buff, 1, read));
+ ASSERT_EQ(read, res);
+ ASSERT_TRUE(!memcmp(contentStr + offset, buff, res));
+ offset += res;
+ } while (offset < contentSize);
+
+ // Read past the end of the file
+ stream->Read(buff, 1, 1);
+ ASSERT_TRUE(stream->Eof());
+}
+
+static void VerifyStreamWriteBehavior(CefRefPtr<CefStreamWriter> stream,
+ const std::string& contents) {
+ int contentSize = static_cast<int>(contents.size());
+ const char* contentStr = contents.c_str();
+
+ // Write 10 characters at a time and verify the result
+ int res, write, offset = 0;
+ do {
+ write = std::min(10, contentSize - offset);
+ res = static_cast<int>(stream->Write(contentStr + offset, 1, write));
+ ASSERT_EQ(write, res);
+ offset += res;
+ ASSERT_EQ(offset, stream->Tell());
+ } while (offset < contentSize);
+
+ // Move to the beginning of the stream
+ ASSERT_EQ(0, stream->Seek(-contentSize, SEEK_CUR));
+ ASSERT_EQ(0, stream->Tell());
+
+ // Move to the end of the stream
+ ASSERT_EQ(0, stream->Seek(0, SEEK_END));
+ ASSERT_EQ(contentSize, stream->Tell());
+
+ // Move to the beginning of the stream
+ ASSERT_EQ(0, stream->Seek(0, SEEK_SET));
+ ASSERT_EQ(0, stream->Tell());
+}
+
+TEST(StreamTest, ReadFile) {
+ const char* fileName = "StreamTest.VerifyReadFile.txt";
+ CefString fileNameStr = "StreamTest.VerifyReadFile.txt";
+ std::string contents = "This is my test\ncontents for the file";
+
+ // Create the file
+ FILE* f = nullptr;
+#ifdef _WIN32
+ fopen_s(&f, fileName, "wb");
+#else
+ f = fopen(fileName, "wb");
+#endif
+ ASSERT_TRUE(f != nullptr);
+ ASSERT_EQ((size_t)1, fwrite(contents.c_str(), contents.size(), 1, f));
+ fclose(f);
+
+ // Test the stream
+ CefRefPtr<CefStreamReader> stream(
+ CefStreamReader::CreateForFile(fileNameStr));
+ ASSERT_TRUE(stream.get() != nullptr);
+ ASSERT_TRUE(stream->MayBlock());
+ VerifyStreamReadBehavior(stream, contents);
+
+ // Release the file pointer
+ stream = nullptr;
+
+// Delete the file
+#ifdef _WIN32
+ ASSERT_EQ(0, _unlink(fileName));
+#else
+ ASSERT_EQ(0, unlink(fileName));
+#endif
+}
+
+TEST(StreamTest, ReadData) {
+ std::string contents = "This is my test\ncontents for the file";
+
+ // Test the stream
+ CefRefPtr<CefStreamReader> stream(CefStreamReader::CreateForData(
+ static_cast<void*>(const_cast<char*>(contents.c_str())),
+ contents.size()));
+ ASSERT_TRUE(stream.get() != nullptr);
+ ASSERT_FALSE(stream->MayBlock());
+ VerifyStreamReadBehavior(stream, contents);
+}
+
+TEST(StreamTest, WriteFile) {
+ const char* fileName = "StreamTest.VerifyWriteFile.txt";
+ CefString fileNameStr = "StreamTest.VerifyWriteFile.txt";
+ std::string contents = "This is my test\ncontents for the file";
+
+ // Test the stream
+ CefRefPtr<CefStreamWriter> stream(
+ CefStreamWriter::CreateForFile(fileNameStr));
+ ASSERT_TRUE(stream.get() != nullptr);
+ ASSERT_TRUE(stream->MayBlock());
+ VerifyStreamWriteBehavior(stream, contents);
+
+ // Release the file pointer
+ stream = nullptr;
+
+ // Read the file that was written
+ FILE* f = nullptr;
+ char* buff = new char[contents.size()];
+#ifdef _WIN32
+ fopen_s(&f, fileName, "rb");
+#else
+ f = fopen(fileName, "rb");
+#endif
+ ASSERT_TRUE(f != nullptr);
+ ASSERT_EQ((size_t)1, fread(buff, contents.size(), 1, f));
+
+ // Read past the end of the file
+ fgetc(f);
+ ASSERT_TRUE(feof(f));
+ fclose(f);
+
+ // Verify the file contents
+ ASSERT_TRUE(!memcmp(contents.c_str(), buff, contents.size()));
+ delete[] buff;
+
+// Delete the file
+#ifdef _WIN32
+ ASSERT_EQ(0, _unlink(fileName));
+#else
+ ASSERT_EQ(0, unlink(fileName));
+#endif
+}
+
+bool g_ReadHandlerTesterDeleted = false;
+
+class ReadHandlerTester : public CefReadHandler {
+ public:
+ ReadHandlerTester()
+ : read_called_(false),
+ read_ptr_(nullptr),
+ read_size_(0),
+ read_n_(0),
+ seek_called_(false),
+ seek_offset_(0),
+ seek_whence_(0),
+ tell_called_(false),
+ eof_called_(false) {}
+ ~ReadHandlerTester() override { g_ReadHandlerTesterDeleted = true; }
+
+ size_t Read(void* ptr, size_t size, size_t n) override {
+ read_called_ = true;
+ read_ptr_ = ptr;
+ read_size_ = size;
+ read_n_ = n;
+ return 10;
+ }
+
+ int Seek(int64 offset, int whence) override {
+ seek_called_ = true;
+ seek_offset_ = offset;
+ seek_whence_ = whence;
+ return 10;
+ }
+
+ int64 Tell() override {
+ tell_called_ = true;
+ return 10;
+ }
+
+ int Eof() override {
+ eof_called_ = true;
+ return 10;
+ }
+
+ bool MayBlock() override { return false; }
+
+ bool read_called_;
+ const void* read_ptr_;
+ size_t read_size_;
+ size_t read_n_;
+
+ bool seek_called_;
+ int64 seek_offset_;
+ int seek_whence_;
+
+ bool tell_called_;
+
+ bool eof_called_;
+
+ IMPLEMENT_REFCOUNTING(ReadHandlerTester);
+};
+
+TEST(StreamTest, ReadHandler) {
+ ReadHandlerTester* handler = new ReadHandlerTester();
+ ASSERT_TRUE(handler != nullptr);
+
+ CefRefPtr<CefStreamReader> stream(CefStreamReader::CreateForHandler(handler));
+ ASSERT_TRUE(stream.get() != nullptr);
+ ASSERT_FALSE(stream->MayBlock());
+
+ // CefReadHandler Read
+ const char* read_ptr = "My data";
+ size_t read_size = sizeof(read_ptr);
+ size_t read_n = 1;
+ size_t read_res = stream->Read(
+ static_cast<void*>(const_cast<char*>(read_ptr)), read_size, read_n);
+ ASSERT_TRUE(handler->read_called_);
+ ASSERT_EQ((size_t)10, read_res);
+ ASSERT_EQ(read_ptr, handler->read_ptr_);
+ ASSERT_EQ(read_size, handler->read_size_);
+ ASSERT_EQ(read_n, handler->read_n_);
+
+ // CefReadHandler Seek
+ int64 seek_offset = 10;
+ int seek_whence = SEEK_CUR;
+ int seek_res = stream->Seek(seek_offset, seek_whence);
+ ASSERT_TRUE(handler->seek_called_);
+ ASSERT_EQ(10, seek_res);
+ ASSERT_EQ(seek_offset, handler->seek_offset_);
+ ASSERT_EQ(seek_whence, handler->seek_whence_);
+
+ // CefReadHandler Tell
+ int64 tell_res = stream->Tell();
+ ASSERT_TRUE(handler->tell_called_);
+ ASSERT_EQ(10, tell_res);
+
+ // CefReadHandler Eof
+ int eof_res = stream->Eof();
+ ASSERT_TRUE(handler->eof_called_);
+ ASSERT_EQ(10, eof_res);
+
+ // Delete the stream
+ stream = nullptr;
+
+ // Verify that the handler object was deleted
+ ASSERT_TRUE(g_ReadHandlerTesterDeleted);
+}
+
+bool g_WriteHandlerTesterDeleted = false;
+
+class WriteHandlerTester : public CefWriteHandler {
+ public:
+ WriteHandlerTester()
+ : write_called_(false),
+ write_ptr_(nullptr),
+ write_size_(0),
+ write_n_(0),
+ seek_called_(false),
+ seek_offset_(0),
+ seek_whence_(0),
+ tell_called_(false),
+ flush_called_(false) {}
+ ~WriteHandlerTester() override { g_WriteHandlerTesterDeleted = true; }
+
+ size_t Write(const void* ptr, size_t size, size_t n) override {
+ write_called_ = true;
+ write_ptr_ = ptr;
+ write_size_ = size;
+ write_n_ = n;
+ return 10;
+ }
+
+ int Seek(int64 offset, int whence) override {
+ seek_called_ = true;
+ seek_offset_ = offset;
+ seek_whence_ = whence;
+ return 10;
+ }
+
+ int64 Tell() override {
+ tell_called_ = true;
+ return 10;
+ }
+
+ int Flush() override {
+ flush_called_ = true;
+ return 10;
+ }
+
+ bool MayBlock() override { return false; }
+
+ bool write_called_;
+ const void* write_ptr_;
+ size_t write_size_;
+ size_t write_n_;
+
+ bool seek_called_;
+ int64 seek_offset_;
+ int seek_whence_;
+
+ bool tell_called_;
+
+ bool flush_called_;
+
+ IMPLEMENT_REFCOUNTING(WriteHandlerTester);
+};
+
+TEST(StreamTest, WriteHandler) {
+ WriteHandlerTester* handler = new WriteHandlerTester();
+ ASSERT_TRUE(handler != nullptr);
+
+ CefRefPtr<CefStreamWriter> stream(CefStreamWriter::CreateForHandler(handler));
+ ASSERT_TRUE(stream.get() != nullptr);
+ ASSERT_FALSE(stream->MayBlock());
+
+ // CefWriteHandler Write
+ const char* write_ptr = "My data";
+ size_t write_size = sizeof(write_ptr);
+ size_t write_n = 1;
+ size_t write_res = stream->Write(write_ptr, write_size, write_n);
+ ASSERT_TRUE(handler->write_called_);
+ ASSERT_EQ((size_t)10, write_res);
+ ASSERT_EQ(write_ptr, handler->write_ptr_);
+ ASSERT_EQ(write_size, handler->write_size_);
+ ASSERT_EQ(write_n, handler->write_n_);
+
+ // CefWriteHandler Seek
+ int64 seek_offset = 10;
+ int seek_whence = SEEK_CUR;
+ int seek_res = stream->Seek(seek_offset, seek_whence);
+ ASSERT_TRUE(handler->seek_called_);
+ ASSERT_EQ(10, seek_res);
+ ASSERT_EQ(seek_offset, handler->seek_offset_);
+ ASSERT_EQ(seek_whence, handler->seek_whence_);
+
+ // CefWriteHandler Tell
+ int64 tell_res = stream->Tell();
+ ASSERT_TRUE(handler->tell_called_);
+ ASSERT_EQ(10, tell_res);
+
+ // CefWriteHandler Flush
+ int flush_res = stream->Flush();
+ ASSERT_TRUE(handler->flush_called_);
+ ASSERT_EQ(10, flush_res);
+
+ // Delete the stream
+ stream = nullptr;
+
+ // Verify that the handler object was deleted
+ ASSERT_TRUE(g_WriteHandlerTesterDeleted);
+}
diff --git a/tests/ceftests/string_unittest.cc b/tests/ceftests/string_unittest.cc
new file mode 100644
index 00000000..3e77616b
--- /dev/null
+++ b/tests/ceftests/string_unittest.cc
@@ -0,0 +1,485 @@
+// Copyright (c) 2010 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include <map>
+#include <vector>
+
+#include "include/internal/cef_string.h"
+#include "include/internal/cef_string_list.h"
+#include "include/internal/cef_string_map.h"
+#include "include/internal/cef_string_multimap.h"
+#include "tests/gtest/include/gtest/gtest.h"
+
+// Test UTF8 strings.
+TEST(StringTest, UTF8) {
+ CefStringUTF8 str1("Test String");
+ EXPECT_EQ(str1.length(), (size_t)11);
+ EXPECT_FALSE(str1.empty());
+ EXPECT_TRUE(str1.IsOwner());
+
+ // Test equality.
+ CefStringUTF8 str2("Test String");
+ EXPECT_EQ(str1, str2);
+ EXPECT_LE(str1, str2);
+ EXPECT_GE(str1, str2);
+
+ str2 = "Test Test";
+ EXPECT_LT(str1, str2);
+ EXPECT_GT(str2, str1);
+
+ // When strings are the same but of unequal length, the longer string is
+ // greater.
+ str2 = "Test";
+ EXPECT_LT(str2, str1);
+ EXPECT_GT(str1, str2);
+
+ // Test conversions.
+ str2 = str1.ToString();
+ EXPECT_EQ(str1, str2);
+ str2 = str1.ToWString();
+ EXPECT_EQ(str1, str2);
+
+ // Test userfree assignment.
+ cef_string_userfree_utf8_t uf = str2.DetachToUserFree();
+ EXPECT_TRUE(uf != nullptr);
+ EXPECT_TRUE(str2.empty());
+ str2.AttachToUserFree(uf);
+ EXPECT_FALSE(str2.empty());
+ EXPECT_EQ(str1, str2);
+}
+
+// Test UTF16 strings.
+TEST(StringTest, UTF16) {
+ CefStringUTF16 str1("Test String");
+ EXPECT_EQ(str1.length(), (size_t)11);
+ EXPECT_FALSE(str1.empty());
+ EXPECT_TRUE(str1.IsOwner());
+
+ // Test equality.
+ CefStringUTF16 str2("Test String");
+ EXPECT_EQ(str1, str2);
+ EXPECT_LE(str1, str2);
+ EXPECT_GE(str1, str2);
+
+ str2 = "Test Test";
+ EXPECT_LT(str1, str2);
+ EXPECT_GT(str2, str1);
+
+ // When strings are the same but of unequal length, the longer string is
+ // greater.
+ str2 = "Test";
+ EXPECT_LT(str2, str1);
+ EXPECT_GT(str1, str2);
+
+ // Test conversions.
+ str2 = str1.ToString();
+ EXPECT_EQ(str1, str2);
+ str2 = str1.ToWString();
+ EXPECT_EQ(str1, str2);
+
+ // Test userfree assignment.
+ cef_string_userfree_utf16_t uf = str2.DetachToUserFree();
+ EXPECT_TRUE(uf != nullptr);
+ EXPECT_TRUE(str2.empty());
+ str2.AttachToUserFree(uf);
+ EXPECT_FALSE(str2.empty());
+ EXPECT_EQ(str1, str2);
+}
+
+// Test wide strings.
+TEST(StringTest, Wide) {
+ CefStringWide str1("Test String");
+ EXPECT_EQ(str1.length(), (size_t)11);
+ EXPECT_FALSE(str1.empty());
+ EXPECT_TRUE(str1.IsOwner());
+
+ // Test equality.
+ CefStringWide str2("Test String");
+ EXPECT_EQ(str1, str2);
+ EXPECT_LE(str1, str2);
+ EXPECT_GE(str1, str2);
+
+ str2 = "Test Test";
+ EXPECT_LT(str1, str2);
+ EXPECT_GT(str2, str1);
+
+ // When strings are the same but of unequal length, the longer string is
+ // greater.
+ str2 = "Test";
+ EXPECT_LT(str2, str1);
+ EXPECT_GT(str1, str2);
+
+ // Test conversions.
+ str2 = str1.ToString();
+ EXPECT_EQ(str1, str2);
+ str2 = str1.ToWString();
+ EXPECT_EQ(str1, str2);
+
+ // Test userfree assignment.
+ cef_string_userfree_wide_t uf = str2.DetachToUserFree();
+ EXPECT_TRUE(uf != nullptr);
+ EXPECT_TRUE(str2.empty());
+ str2.AttachToUserFree(uf);
+ EXPECT_FALSE(str2.empty());
+ EXPECT_EQ(str1, str2);
+}
+
+// Test std::u16string convertion to/from CefString types.
+TEST(StringTest, string16) {
+ CefStringUTF8 str8("Test String 1"), str8b;
+ CefStringUTF16 str16("Test String 2"), str16b;
+ CefStringWide strwide("Test String 3"), strwideb;
+ std::u16string base_str;
+
+ base_str = str8;
+ str8b = base_str;
+ EXPECT_EQ(str8, base_str);
+ EXPECT_EQ(str8, str8b);
+
+ base_str = str16;
+ str16b = base_str;
+ EXPECT_EQ(str16, base_str);
+ EXPECT_EQ(str16, str16b);
+
+ base_str = strwide;
+ strwideb = base_str;
+ EXPECT_EQ(strwide, base_str);
+ EXPECT_EQ(strwide, strwideb);
+}
+
+// Test string lists.
+TEST(StringTest, List) {
+ typedef std::vector<CefString> ListType;
+ ListType list;
+ list.push_back("String 1");
+ list.push_back("String 2");
+ list.push_back("String 3");
+
+ EXPECT_EQ(list[0], "String 1");
+ EXPECT_EQ(list[1], "String 2");
+ EXPECT_EQ(list[2], "String 3");
+
+ cef_string_list_t listPtr = cef_string_list_alloc();
+ EXPECT_TRUE(listPtr != nullptr);
+ ListType::const_iterator it = list.begin();
+ for (; it != list.end(); ++it) {
+ cef_string_list_append(listPtr, it->GetStruct());
+ }
+
+ CefString str;
+ int ret;
+
+ EXPECT_EQ(cef_string_list_size(listPtr), 3U);
+
+ ret = cef_string_list_value(listPtr, 0U, str.GetWritableStruct());
+ EXPECT_TRUE(ret);
+ EXPECT_EQ(str, "String 1");
+ ret = cef_string_list_value(listPtr, 1U, str.GetWritableStruct());
+ EXPECT_TRUE(ret);
+ EXPECT_EQ(str, "String 2");
+ ret = cef_string_list_value(listPtr, 2U, str.GetWritableStruct());
+ EXPECT_TRUE(ret);
+ EXPECT_EQ(str, "String 3");
+
+ cef_string_list_t listPtr2 = cef_string_list_copy(listPtr);
+ cef_string_list_clear(listPtr);
+ EXPECT_EQ(cef_string_list_size(listPtr), 0U);
+ cef_string_list_free(listPtr);
+
+ EXPECT_EQ(cef_string_list_size(listPtr2), 3U);
+
+ ret = cef_string_list_value(listPtr2, 0U, str.GetWritableStruct());
+ EXPECT_TRUE(ret);
+ EXPECT_EQ(str, "String 1");
+ ret = cef_string_list_value(listPtr2, 1U, str.GetWritableStruct());
+ EXPECT_TRUE(ret);
+ EXPECT_EQ(str, "String 2");
+ ret = cef_string_list_value(listPtr2, 2U, str.GetWritableStruct());
+ EXPECT_TRUE(ret);
+ EXPECT_EQ(str, "String 3");
+
+ cef_string_list_free(listPtr2);
+}
+
+// Test string maps.
+TEST(StringTest, Map) {
+ typedef std::map<CefString, CefString> MapType;
+ MapType map;
+ map.insert(std::make_pair("Key 1", "String 1"));
+ map.insert(std::make_pair("Key 2", "String 2"));
+ map.insert(std::make_pair("Key 3", "String 3"));
+
+ MapType::const_iterator it;
+
+ it = map.find("Key 2");
+ EXPECT_TRUE(it != map.end());
+ EXPECT_EQ(it->first, "Key 2");
+ EXPECT_EQ(it->second, "String 2");
+
+ it = map.find(L"Key 2");
+ EXPECT_TRUE(it != map.end());
+ EXPECT_EQ(it->first, L"Key 2");
+ EXPECT_EQ(it->second, L"String 2");
+
+ EXPECT_EQ(map["Key 1"], "String 1");
+ EXPECT_EQ(map["Key 2"], "String 2");
+ EXPECT_EQ(map["Key 3"], "String 3");
+
+ cef_string_map_t mapPtr = cef_string_map_alloc();
+
+ it = map.begin();
+ for (; it != map.end(); ++it) {
+ cef_string_map_append(mapPtr, it->first.GetStruct(),
+ it->second.GetStruct());
+ }
+
+ CefString str;
+ int ret;
+
+ EXPECT_EQ(cef_string_map_size(mapPtr), 3U);
+
+ ret = cef_string_map_key(mapPtr, 0U, str.GetWritableStruct());
+ EXPECT_TRUE(ret);
+ EXPECT_EQ(str, "Key 1");
+ ret = cef_string_map_value(mapPtr, 0U, str.GetWritableStruct());
+ EXPECT_TRUE(ret);
+ EXPECT_EQ(str, "String 1");
+
+ ret = cef_string_map_key(mapPtr, 1U, str.GetWritableStruct());
+ EXPECT_TRUE(ret);
+ EXPECT_EQ(str, "Key 2");
+ ret = cef_string_map_value(mapPtr, 1U, str.GetWritableStruct());
+ EXPECT_TRUE(ret);
+ EXPECT_EQ(str, "String 2");
+
+ ret = cef_string_map_key(mapPtr, 2U, str.GetWritableStruct());
+ EXPECT_TRUE(ret);
+ EXPECT_EQ(str, "Key 3");
+ ret = cef_string_map_value(mapPtr, 2U, str.GetWritableStruct());
+ EXPECT_TRUE(ret);
+ EXPECT_EQ(str, "String 3");
+
+ CefString key;
+ key.FromASCII("Key 2");
+ ret = cef_string_map_find(mapPtr, key.GetStruct(), str.GetWritableStruct());
+ EXPECT_TRUE(ret);
+ EXPECT_EQ(str, "String 2");
+
+ cef_string_map_clear(mapPtr);
+ EXPECT_EQ(cef_string_map_size(mapPtr), 0U);
+
+ cef_string_map_free(mapPtr);
+}
+
+// Test string maps.
+TEST(StringTest, Multimap) {
+ typedef std::multimap<CefString, CefString> MapType;
+ MapType map;
+ map.insert(std::make_pair("Key 1", "String 1"));
+ map.insert(std::make_pair("Key 2", "String 2"));
+ map.insert(std::make_pair("Key 2", "String 2.1"));
+ map.insert(std::make_pair("Key 3", "String 3"));
+
+ MapType::const_iterator it;
+
+ it = map.find("Key 2");
+ EXPECT_TRUE(it != map.end());
+ EXPECT_EQ(it->first, "Key 2");
+ EXPECT_EQ(it->second, "String 2");
+
+ std::pair<MapType::const_iterator, MapType::const_iterator> range_it =
+ map.equal_range("Key 2");
+ EXPECT_TRUE(range_it.first != range_it.second);
+ MapType::const_iterator same_key_it = range_it.first;
+ // Either of "String 2" or "String 2.1" is fine since
+ // std::multimap provides no guarantee wrt the order of
+ // values with the same key.
+ EXPECT_EQ(same_key_it->second.ToString().find("String 2"), 0U);
+ EXPECT_EQ((++same_key_it)->second.ToString().find("String 2"), 0U);
+ EXPECT_EQ(map.count("Key 2"), 2U);
+
+ EXPECT_EQ(map.find("Key 1")->second, "String 1");
+ EXPECT_EQ(map.find("Key 3")->second, "String 3");
+
+ cef_string_multimap_t mapPtr = cef_string_multimap_alloc();
+
+ it = map.begin();
+ for (; it != map.end(); ++it) {
+ cef_string_multimap_append(mapPtr, it->first.GetStruct(),
+ it->second.GetStruct());
+ }
+
+ CefString str;
+ int ret;
+
+ EXPECT_EQ(cef_string_multimap_size(mapPtr), 4U);
+
+ ret = cef_string_multimap_key(mapPtr, 0U, str.GetWritableStruct());
+ EXPECT_TRUE(ret);
+ EXPECT_EQ(str, "Key 1");
+ ret = cef_string_multimap_value(mapPtr, 0U, str.GetWritableStruct());
+ EXPECT_TRUE(ret);
+ EXPECT_EQ(str, "String 1");
+
+ ret = cef_string_multimap_key(mapPtr, 1U, str.GetWritableStruct());
+ EXPECT_TRUE(ret);
+ EXPECT_EQ(str, "Key 2");
+ ret = cef_string_multimap_value(mapPtr, 1U, str.GetWritableStruct());
+ EXPECT_TRUE(ret);
+ EXPECT_EQ(str.ToString().find("String 2"), 0U);
+
+ ret = cef_string_multimap_key(mapPtr, 2U, str.GetWritableStruct());
+ EXPECT_TRUE(ret);
+ EXPECT_EQ(str, "Key 2");
+ ret = cef_string_multimap_value(mapPtr, 2U, str.GetWritableStruct());
+ EXPECT_TRUE(ret);
+ EXPECT_EQ(str.ToString().find("String 2"), 0U);
+
+ ret = cef_string_multimap_key(mapPtr, 3U, str.GetWritableStruct());
+ EXPECT_TRUE(ret);
+ EXPECT_EQ(str, "Key 3");
+ ret = cef_string_multimap_value(mapPtr, 3U, str.GetWritableStruct());
+ EXPECT_TRUE(ret);
+ EXPECT_EQ(str, "String 3");
+
+ CefString key;
+ key.FromASCII("Key 2");
+ size_t size = cef_string_multimap_find_count(mapPtr, key.GetStruct());
+ EXPECT_EQ(size, 2U);
+
+ ret = cef_string_multimap_enumerate(mapPtr, key.GetStruct(), 0U,
+ str.GetWritableStruct());
+ EXPECT_TRUE(ret);
+ EXPECT_EQ(str.ToString().find("String 2"), 0U);
+
+ ret = cef_string_multimap_enumerate(mapPtr, key.GetStruct(), 1U,
+ str.GetWritableStruct());
+ EXPECT_TRUE(ret);
+ EXPECT_EQ(str.ToString().find("String 2"), 0U);
+
+ cef_string_multimap_clear(mapPtr);
+ EXPECT_EQ(cef_string_multimap_size(mapPtr), 0U);
+
+ cef_string_multimap_free(mapPtr);
+}
+
+// Test that CefString ownership behaves as expected.
+TEST(StringTest, Ownership) {
+ const char* test_cstr = "Test string";
+
+ // Initial owner makes a copy of |test_cstr|.
+ CefStringUTF8 str(test_cstr);
+ EXPECT_TRUE(str.IsOwner());
+ EXPECT_STREQ(test_cstr, str.c_str());
+ const char* str_str = str.c_str();
+ const auto str_struct = str.GetStruct();
+ EXPECT_NE(test_cstr, str_str);
+
+ // REFERENCE CREATION
+
+ // Take a reference (requires explicit use of GetStruct).
+ CefStringUTF8 str_ref(str.GetStruct());
+
+ // Nothing changes with |str|.
+ EXPECT_TRUE(str.IsOwner());
+ EXPECT_STREQ(test_cstr, str.c_str());
+ EXPECT_EQ(str.GetStruct(), str_struct);
+ EXPECT_EQ(str.c_str(), str_str);
+
+ // |str_ref| has the same value.
+ EXPECT_FALSE(str_ref.IsOwner());
+ EXPECT_STREQ(test_cstr, str_ref.c_str());
+ // Referencing the same structure and string.
+ EXPECT_EQ(str.GetStruct(), str_ref.GetStruct());
+ EXPECT_EQ(str.c_str(), str_ref.c_str());
+
+ // REFERENCE DETACH/ATTACH
+
+ // DetachToUserFree. |str_ref| loses its reference.
+ auto userfree = str_ref.DetachToUserFree();
+
+ // Nothing changes with |str|.
+ EXPECT_TRUE(str.IsOwner());
+ EXPECT_STREQ(test_cstr, str.c_str());
+ EXPECT_EQ(str.GetStruct(), str_struct);
+ EXPECT_EQ(str.c_str(), str_str);
+
+ // |str_ref| is now empty.
+ EXPECT_FALSE(str_ref.IsOwner());
+ EXPECT_TRUE(str_ref.empty());
+ EXPECT_EQ(nullptr, str_ref.GetStruct());
+
+ // AttachToUserFree. |str2| becomes an owner of the copy.
+ CefStringUTF8 str2;
+ str2.AttachToUserFree(userfree);
+
+ // Nothing changes with |str|.
+ EXPECT_TRUE(str.IsOwner());
+ EXPECT_STREQ(test_cstr, str.c_str());
+ EXPECT_EQ(str.GetStruct(), str_struct);
+ EXPECT_EQ(str.c_str(), str_str);
+
+ // |str2| is now an owner of a copy.
+ EXPECT_TRUE(str2.IsOwner());
+ EXPECT_STREQ(test_cstr, str2.c_str());
+ // Not referencing the same structure or string.
+ EXPECT_NE(str.GetStruct(), str2.GetStruct());
+ EXPECT_NE(str.c_str(), str2.c_str());
+
+ // |str_ref| is still empty.
+ EXPECT_FALSE(str_ref.IsOwner());
+ EXPECT_TRUE(str_ref.empty());
+ EXPECT_EQ(nullptr, str_ref.GetStruct());
+
+ // OWNER COPY CREATION
+
+ // Making a copy (default copy constructor behavior).
+ CefStringUTF8 str3(str);
+
+ // Nothing changes with |str|.
+ EXPECT_TRUE(str.IsOwner());
+ EXPECT_STREQ(test_cstr, str.c_str());
+ EXPECT_EQ(str.GetStruct(), str_struct);
+ EXPECT_EQ(str.c_str(), str_str);
+
+ // |str3| is now an owner of a copy.
+ EXPECT_TRUE(str3.IsOwner());
+ EXPECT_STREQ(test_cstr, str3.c_str());
+ // Not referencing the same structure or string.
+ EXPECT_NE(str.GetStruct(), str3.GetStruct());
+ EXPECT_NE(str.c_str(), str3.c_str());
+
+ // OWNER DETACH/ATTACH
+
+ // DetachToUserFree. |str3| loses its ownership.
+ const char* str3_str = str3.c_str();
+ auto userfree3 = str3.DetachToUserFree();
+
+ // Nothing changes with |str|.
+ EXPECT_TRUE(str.IsOwner());
+ EXPECT_STREQ(test_cstr, str.c_str());
+ EXPECT_EQ(str.GetStruct(), str_struct);
+ EXPECT_EQ(str.c_str(), str_str);
+
+ // |str3| is now empty.
+ EXPECT_FALSE(str3.IsOwner());
+ EXPECT_TRUE(str3.empty());
+ EXPECT_EQ(nullptr, str3.GetStruct());
+
+ // AttachToUserFree. |str3| regains its ownership.
+ str3.AttachToUserFree(userfree3);
+
+ // Nothing changes with |str|.
+ EXPECT_TRUE(str.IsOwner());
+ EXPECT_STREQ(test_cstr, str.c_str());
+ EXPECT_EQ(str.GetStruct(), str_struct);
+ EXPECT_EQ(str.c_str(), str_str);
+
+ // |str3| is now an owner of the same string that it had previously.
+ // The structure will also be re-allocated, but we don't test that because
+ // the same address might be reused.
+ EXPECT_TRUE(str3.IsOwner());
+ EXPECT_STREQ(test_cstr, str3.c_str());
+ EXPECT_EQ(str3_str, str3.c_str());
+}
diff --git a/tests/ceftests/task_unittest.cc b/tests/ceftests/task_unittest.cc
new file mode 100644
index 00000000..b413fa99
--- /dev/null
+++ b/tests/ceftests/task_unittest.cc
@@ -0,0 +1,332 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "include/base/cef_callback.h"
+#include "include/cef_command_line.h"
+#include "include/cef_task.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "tests/ceftests/test_handler.h"
+#include "tests/ceftests/test_util.h"
+#include "tests/gtest/include/gtest/gtest.h"
+
+namespace {
+
+void WaitForEvent(CefRefPtr<CefWaitableEvent> event) {
+ const auto timeout = GetConfiguredTestTimeout(/*timeout_ms=*/1000);
+ if (!timeout) {
+ event->Wait();
+ } else {
+ EXPECT_TRUE(event->TimedWait(*timeout));
+ }
+}
+
+void GetForCurrentThread(bool* ran_test, CefRefPtr<CefWaitableEvent> event) {
+ // Currently on the FILE thread.
+ CefRefPtr<CefTaskRunner> runner = CefTaskRunner::GetForCurrentThread();
+ EXPECT_TRUE(runner.get());
+ EXPECT_TRUE(runner->BelongsToCurrentThread());
+ EXPECT_TRUE(runner->BelongsToThread(TID_FILE_USER_VISIBLE));
+ EXPECT_FALSE(runner->BelongsToThread(TID_IO));
+ EXPECT_TRUE(runner->IsSame(runner));
+
+ CefRefPtr<CefTaskRunner> runner2 = CefTaskRunner::GetForCurrentThread();
+ EXPECT_TRUE(runner2.get());
+ EXPECT_TRUE(runner->IsSame(runner2));
+ EXPECT_TRUE(runner2->IsSame(runner));
+
+ // Not on the IO thread.
+ CefRefPtr<CefTaskRunner> runner3 = CefTaskRunner::GetForThread(TID_IO);
+ EXPECT_TRUE(runner3.get());
+ EXPECT_FALSE(runner->IsSame(runner3));
+ EXPECT_FALSE(runner3->IsSame(runner));
+
+ *ran_test = true;
+ event->Signal();
+}
+
+void GetForThread(bool* ran_test, CefRefPtr<CefWaitableEvent> event) {
+ // Currently on the FILE thread.
+ CefRefPtr<CefTaskRunner> runner = CefTaskRunner::GetForThread(TID_IO);
+ EXPECT_TRUE(runner.get());
+ EXPECT_FALSE(runner->BelongsToCurrentThread());
+ EXPECT_TRUE(runner->BelongsToThread(TID_IO));
+ EXPECT_FALSE(runner->BelongsToThread(TID_FILE_USER_VISIBLE));
+ EXPECT_TRUE(runner->IsSame(runner));
+
+ CefRefPtr<CefTaskRunner> runner2 = CefTaskRunner::GetForThread(TID_IO);
+ EXPECT_TRUE(runner2.get());
+ EXPECT_TRUE(runner->IsSame(runner2));
+ EXPECT_TRUE(runner2->IsSame(runner));
+
+ CefRefPtr<CefTaskRunner> runner3 =
+ CefTaskRunner::GetForThread(TID_FILE_USER_VISIBLE);
+ EXPECT_TRUE(runner3.get());
+ EXPECT_FALSE(runner->IsSame(runner3));
+ EXPECT_FALSE(runner3->IsSame(runner));
+
+ *ran_test = true;
+ event->Signal();
+}
+
+void PostTaskEvent1(bool* ran_test,
+ CefRefPtr<CefWaitableEvent> event,
+ CefRefPtr<CefTaskRunner> runner) {
+ // Currently on the IO thread.
+ EXPECT_TRUE(runner->BelongsToCurrentThread());
+ EXPECT_TRUE(runner->BelongsToThread(TID_IO));
+ EXPECT_FALSE(runner->BelongsToThread(TID_FILE_USER_VISIBLE));
+
+ // Current thread should be the IO thread.
+ CefRefPtr<CefTaskRunner> runner2 = CefTaskRunner::GetForCurrentThread();
+ EXPECT_TRUE(runner2.get());
+ EXPECT_TRUE(runner2->BelongsToCurrentThread());
+ EXPECT_TRUE(runner2->BelongsToThread(TID_IO));
+ EXPECT_FALSE(runner2->BelongsToThread(TID_FILE_USER_VISIBLE));
+ EXPECT_TRUE(runner->IsSame(runner2));
+ EXPECT_TRUE(runner2->IsSame(runner));
+
+ // Current thread should be the IO thread.
+ CefRefPtr<CefTaskRunner> runner3 = CefTaskRunner::GetForThread(TID_IO);
+ EXPECT_TRUE(runner3.get());
+ EXPECT_TRUE(runner3->BelongsToCurrentThread());
+ EXPECT_TRUE(runner3->BelongsToThread(TID_IO));
+ EXPECT_FALSE(runner3->BelongsToThread(TID_FILE_USER_VISIBLE));
+ EXPECT_TRUE(runner->IsSame(runner3));
+ EXPECT_TRUE(runner3->IsSame(runner));
+
+ // Current thread should not be the FILE thread.
+ CefRefPtr<CefTaskRunner> runner4 =
+ CefTaskRunner::GetForThread(TID_FILE_USER_VISIBLE);
+ EXPECT_TRUE(runner4.get());
+ EXPECT_FALSE(runner4->BelongsToCurrentThread());
+ EXPECT_FALSE(runner4->BelongsToThread(TID_IO));
+ EXPECT_TRUE(runner4->BelongsToThread(TID_FILE_USER_VISIBLE));
+ EXPECT_FALSE(runner->IsSame(runner4));
+ EXPECT_FALSE(runner4->IsSame(runner));
+
+ *ran_test = true;
+ event->Signal();
+}
+
+void PostOnceTask1(bool* ran_test, CefRefPtr<CefWaitableEvent> event) {
+ // Currently on the FILE thread.
+ CefRefPtr<CefTaskRunner> runner = CefTaskRunner::GetForThread(TID_IO);
+ EXPECT_TRUE(runner.get());
+ EXPECT_FALSE(runner->BelongsToCurrentThread());
+ EXPECT_TRUE(runner->BelongsToThread(TID_IO));
+
+ runner->PostTask(CefCreateClosureTask(
+ base::BindOnce(&PostTaskEvent1, ran_test, event, runner)));
+}
+
+void PostRepeatingTask1(bool* ran_test, CefRefPtr<CefWaitableEvent> event) {
+ // Currently on the FILE thread.
+ CefRefPtr<CefTaskRunner> runner = CefTaskRunner::GetForThread(TID_IO);
+ EXPECT_TRUE(runner.get());
+ EXPECT_FALSE(runner->BelongsToCurrentThread());
+ EXPECT_TRUE(runner->BelongsToThread(TID_IO));
+
+ runner->PostTask(CefCreateClosureTask(
+ base::BindRepeating(&PostTaskEvent1, ran_test, event, runner)));
+}
+
+void PostOnceDelayedTask1(bool* ran_test, CefRefPtr<CefWaitableEvent> event) {
+ // Currently on the FILE thread.
+ CefRefPtr<CefTaskRunner> runner = CefTaskRunner::GetForThread(TID_IO);
+ EXPECT_TRUE(runner.get());
+ EXPECT_FALSE(runner->BelongsToCurrentThread());
+ EXPECT_TRUE(runner->BelongsToThread(TID_IO));
+
+ runner->PostDelayedTask(CefCreateClosureTask(base::BindOnce(
+ &PostTaskEvent1, ran_test, event, runner)),
+ 0);
+}
+
+void PostRepeatingDelayedTask1(bool* ran_test,
+ CefRefPtr<CefWaitableEvent> event) {
+ // Currently on the FILE thread.
+ CefRefPtr<CefTaskRunner> runner = CefTaskRunner::GetForThread(TID_IO);
+ EXPECT_TRUE(runner.get());
+ EXPECT_FALSE(runner->BelongsToCurrentThread());
+ EXPECT_TRUE(runner->BelongsToThread(TID_IO));
+
+ runner->PostDelayedTask(CefCreateClosureTask(base::BindRepeating(
+ &PostTaskEvent1, ran_test, event, runner)),
+ 0);
+}
+
+void PostTaskEvent2(bool* ran_test, CefRefPtr<CefWaitableEvent> event) {
+ EXPECT_TRUE(CefCurrentlyOn(TID_IO));
+ EXPECT_FALSE(CefCurrentlyOn(TID_FILE_USER_VISIBLE));
+
+ *ran_test = true;
+ event->Signal();
+}
+
+void PostOnceTask2(bool* ran_test, CefRefPtr<CefWaitableEvent> event) {
+ // Currently on the FILE thread.
+ EXPECT_FALSE(CefCurrentlyOn(TID_IO));
+
+ CefPostTask(TID_IO, CefCreateClosureTask(
+ base::BindOnce(&PostTaskEvent2, ran_test, event)));
+}
+
+void PostRepeatingTask2(bool* ran_test, CefRefPtr<CefWaitableEvent> event) {
+ // Currently on the FILE thread.
+ EXPECT_FALSE(CefCurrentlyOn(TID_IO));
+
+ CefPostTask(TID_IO, CefCreateClosureTask(base::BindRepeating(
+ &PostTaskEvent2, ran_test, event)));
+}
+
+void PostOnceDelayedTask2(bool* ran_test, CefRefPtr<CefWaitableEvent> event) {
+ // Currently on the FILE thread.
+ EXPECT_FALSE(CefCurrentlyOn(TID_IO));
+
+ CefPostDelayedTask(
+ TID_IO,
+ CefCreateClosureTask(base::BindOnce(&PostTaskEvent2, ran_test, event)),
+ 0);
+}
+
+void PostRepeatingDelayedTask2(bool* ran_test,
+ CefRefPtr<CefWaitableEvent> event) {
+ // Currently on the FILE thread.
+ EXPECT_FALSE(CefCurrentlyOn(TID_IO));
+
+ CefPostDelayedTask(TID_IO,
+ CefCreateClosureTask(
+ base::BindRepeating(&PostTaskEvent2, ran_test, event)),
+ 0);
+}
+
+} // namespace
+
+TEST(TaskTest, GetOnceForCurrentThread) {
+ bool ran_test = false;
+ CefRefPtr<CefWaitableEvent> event =
+ CefWaitableEvent::CreateWaitableEvent(true, false);
+ CefPostTask(TID_FILE_USER_VISIBLE,
+ CefCreateClosureTask(
+ base::BindOnce(&GetForCurrentThread, &ran_test, event)));
+ WaitForEvent(event);
+ EXPECT_TRUE(ran_test);
+}
+
+TEST(TaskTest, GetRepeatingForCurrentThread) {
+ bool ran_test = false;
+ CefRefPtr<CefWaitableEvent> event =
+ CefWaitableEvent::CreateWaitableEvent(true, false);
+ CefPostTask(TID_FILE_USER_VISIBLE,
+ CefCreateClosureTask(
+ base::BindRepeating(&GetForCurrentThread, &ran_test, event)));
+ WaitForEvent(event);
+ EXPECT_TRUE(ran_test);
+}
+
+TEST(TaskTest, GetOnceForThread) {
+ bool ran_test = false;
+ CefRefPtr<CefWaitableEvent> event =
+ CefWaitableEvent::CreateWaitableEvent(true, false);
+ CefPostTask(TID_FILE_USER_VISIBLE, CefCreateClosureTask(base::BindOnce(
+ &GetForThread, &ran_test, event)));
+ WaitForEvent(event);
+ EXPECT_TRUE(ran_test);
+}
+
+TEST(TaskTest, GetRepeatingForThread) {
+ bool ran_test = false;
+ CefRefPtr<CefWaitableEvent> event =
+ CefWaitableEvent::CreateWaitableEvent(true, false);
+ CefPostTask(TID_FILE_USER_VISIBLE, CefCreateClosureTask(base::BindRepeating(
+ &GetForThread, &ran_test, event)));
+ WaitForEvent(event);
+ EXPECT_TRUE(ran_test);
+}
+
+TEST(TaskTest, PostOnceTask1) {
+ bool ran_test = false;
+ CefRefPtr<CefWaitableEvent> event =
+ CefWaitableEvent::CreateWaitableEvent(true, false);
+ CefPostTask(TID_FILE_USER_VISIBLE, CefCreateClosureTask(base::BindOnce(
+ &PostOnceTask1, &ran_test, event)));
+ WaitForEvent(event);
+ EXPECT_TRUE(ran_test);
+}
+
+TEST(TaskTest, PostRepeatingTask1) {
+ bool ran_test = false;
+ CefRefPtr<CefWaitableEvent> event =
+ CefWaitableEvent::CreateWaitableEvent(true, false);
+ CefPostTask(TID_FILE_USER_VISIBLE,
+ CefCreateClosureTask(
+ base::BindRepeating(&PostRepeatingTask1, &ran_test, event)));
+ WaitForEvent(event);
+ EXPECT_TRUE(ran_test);
+}
+
+TEST(TaskTest, PostOnceDelayedTask1) {
+ bool ran_test = false;
+ CefRefPtr<CefWaitableEvent> event =
+ CefWaitableEvent::CreateWaitableEvent(true, false);
+ CefPostTask(TID_FILE_USER_VISIBLE,
+ CefCreateClosureTask(
+ base::BindOnce(&PostOnceDelayedTask1, &ran_test, event)));
+ WaitForEvent(event);
+ EXPECT_TRUE(ran_test);
+}
+
+TEST(TaskTest, PostRepeatingDelayedTask1) {
+ bool ran_test = false;
+ CefRefPtr<CefWaitableEvent> event =
+ CefWaitableEvent::CreateWaitableEvent(true, false);
+ CefPostTask(TID_FILE_USER_VISIBLE,
+ CefCreateClosureTask(base::BindRepeating(
+ &PostRepeatingDelayedTask1, &ran_test, event)));
+ WaitForEvent(event);
+ EXPECT_TRUE(ran_test);
+}
+
+TEST(TaskTest, PostOnceTask2) {
+ bool ran_test = false;
+ CefRefPtr<CefWaitableEvent> event =
+ CefWaitableEvent::CreateWaitableEvent(true, false);
+ CefPostTask(TID_FILE_USER_VISIBLE, CefCreateClosureTask(base::BindOnce(
+ &PostOnceTask2, &ran_test, event)));
+ WaitForEvent(event);
+ EXPECT_TRUE(ran_test);
+}
+
+TEST(TaskTest, PostRepeatingTask2) {
+ bool ran_test = false;
+ CefRefPtr<CefWaitableEvent> event =
+ CefWaitableEvent::CreateWaitableEvent(true, false);
+ CefPostTask(TID_FILE_USER_VISIBLE,
+ CefCreateClosureTask(
+ base::BindRepeating(&PostRepeatingTask2, &ran_test, event)));
+ WaitForEvent(event);
+ EXPECT_TRUE(ran_test);
+}
+
+TEST(TaskTest, PostOnceDelayedTask2) {
+ bool ran_test = false;
+ CefRefPtr<CefWaitableEvent> event =
+ CefWaitableEvent::CreateWaitableEvent(true, false);
+ CefPostTask(TID_FILE_USER_VISIBLE,
+ CefCreateClosureTask(
+ base::BindOnce(&PostOnceDelayedTask2, &ran_test, event)));
+ WaitForEvent(event);
+ EXPECT_TRUE(ran_test);
+}
+
+TEST(TaskTest, PostRepeatingDelayedTask2) {
+ bool ran_test = false;
+ CefRefPtr<CefWaitableEvent> event =
+ CefWaitableEvent::CreateWaitableEvent(true, false);
+ CefPostTask(TID_FILE_USER_VISIBLE,
+ CefCreateClosureTask(base::BindRepeating(
+ &PostRepeatingDelayedTask2, &ran_test, event)));
+ WaitForEvent(event);
+ EXPECT_TRUE(ran_test);
+}
diff --git a/tests/ceftests/test_handler.cc b/tests/ceftests/test_handler.cc
new file mode 100644
index 00000000..3ebf4ae1
--- /dev/null
+++ b/tests/ceftests/test_handler.cc
@@ -0,0 +1,494 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/ceftests/test_handler.h"
+
+#include "include/base/cef_callback.h"
+#include "include/base/cef_logging.h"
+#include "include/cef_command_line.h"
+#include "include/cef_stream.h"
+#include "include/views/cef_browser_view.h"
+#include "include/views/cef_window.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "include/wrapper/cef_stream_resource_handler.h"
+#include "tests/ceftests/test_request.h"
+#include "tests/ceftests/test_util.h"
+#include "tests/shared/common/client_switches.h"
+
+namespace {
+
+// Delegate implementation for the CefWindow that will host the Views-based
+// browser.
+class TestWindowDelegate : public CefWindowDelegate {
+ public:
+ // Create a new top-level Window hosting |browser_view|.
+ static void CreateBrowserWindow(CefRefPtr<CefBrowserView> browser_view,
+ const std::string& title) {
+ CefWindow::CreateTopLevelWindow(
+ new TestWindowDelegate(browser_view, "CefUnitTestViews " + title));
+ }
+
+ // CefWindowDelegate methods:
+
+ void OnWindowCreated(CefRefPtr<CefWindow> window) override {
+ // Add the browser view and show the window.
+ window->CenterWindow(CefSize(800, 600));
+ window->SetTitle(title_);
+ window->AddChildView(browser_view_);
+ window->Show();
+ }
+
+ void OnWindowDestroyed(CefRefPtr<CefWindow> window) override {
+ browser_view_ = nullptr;
+ }
+
+ bool CanClose(CefRefPtr<CefWindow> window) override {
+ // Allow the window to close if the browser says it's OK.
+ CefRefPtr<CefBrowser> browser = browser_view_->GetBrowser();
+ if (browser) {
+ return browser->GetHost()->TryCloseBrowser();
+ }
+ return true;
+ }
+
+ private:
+ TestWindowDelegate(CefRefPtr<CefBrowserView> browser_view,
+ const CefString& title)
+ : browser_view_(browser_view), title_(title) {}
+
+ CefRefPtr<CefBrowserView> browser_view_;
+ CefString title_;
+
+ IMPLEMENT_REFCOUNTING(TestWindowDelegate);
+ DISALLOW_COPY_AND_ASSIGN(TestWindowDelegate);
+};
+
+// Delegate implementation for the CefBrowserView.
+class TestBrowserViewDelegate : public CefBrowserViewDelegate {
+ public:
+ TestBrowserViewDelegate() {}
+
+ // CefBrowserViewDelegate methods:
+
+ bool OnPopupBrowserViewCreated(CefRefPtr<CefBrowserView> browser_view,
+ CefRefPtr<CefBrowserView> popup_browser_view,
+ bool is_devtools) override {
+ // Create our own Window for popups. It will show itself after creation.
+ TestWindowDelegate::CreateBrowserWindow(popup_browser_view,
+ is_devtools ? "DevTools" : "Popup");
+ return true;
+ }
+
+ private:
+ IMPLEMENT_REFCOUNTING(TestBrowserViewDelegate);
+ DISALLOW_COPY_AND_ASSIGN(TestBrowserViewDelegate);
+};
+
+} // namespace
+
+// TestHandler::CompletionState
+
+TestHandler::CompletionState::CompletionState(int total)
+ : total_(total), count_(0) {
+ event_ = CefWaitableEvent::CreateWaitableEvent(true, false);
+}
+
+void TestHandler::CompletionState::TestComplete() {
+ if (++count_ == total_) {
+ count_ = 0;
+
+ // Signal that the test is now complete. Do not access any object members
+ // after this call because |this| might be deleted.
+ event_->Signal();
+ }
+}
+
+void TestHandler::CompletionState::WaitForTests() {
+ // Wait for the test to complete
+ event_->Wait();
+
+ // Reset the event so the same test can be executed again.
+ event_->Reset();
+}
+
+// TestHandler::Collection
+
+TestHandler::Collection::Collection(CompletionState* completion_state)
+ : completion_state_(completion_state) {
+ EXPECT_TRUE(completion_state_);
+}
+
+void TestHandler::Collection::AddTestHandler(TestHandler* test_handler) {
+ EXPECT_EQ(test_handler->completion_state_, completion_state_);
+ handler_list_.push_back(test_handler);
+}
+
+void TestHandler::Collection::ExecuteTests() {
+ EXPECT_GT(handler_list_.size(), 0UL);
+
+ TestHandlerList::const_iterator it;
+
+ it = handler_list_.begin();
+ for (; it != handler_list_.end(); ++it) {
+ (*it)->SetupTest();
+ }
+
+ completion_state_->WaitForTests();
+
+ it = handler_list_.begin();
+ for (; it != handler_list_.end(); ++it) {
+ (*it)->RunTest();
+ }
+
+ completion_state_->WaitForTests();
+}
+
+// TestHandler::UIThreadHelper
+
+TestHandler::UIThreadHelper::UIThreadHelper() : weak_ptr_factory_(this) {}
+
+void TestHandler::UIThreadHelper::PostTask(base::OnceClosure task) {
+ EXPECT_UI_THREAD();
+ CefPostTask(TID_UI,
+ base::BindOnce(&UIThreadHelper::TaskHelper,
+ weak_ptr_factory_.GetWeakPtr(), std::move(task)));
+}
+
+void TestHandler::UIThreadHelper::PostDelayedTask(base::OnceClosure task,
+ int delay_ms) {
+ EXPECT_UI_THREAD();
+ CefPostDelayedTask(
+ TID_UI,
+ base::BindOnce(&UIThreadHelper::TaskHelper,
+ weak_ptr_factory_.GetWeakPtr(), std::move(task)),
+ delay_ms);
+}
+
+void TestHandler::UIThreadHelper::TaskHelper(base::OnceClosure task) {
+ EXPECT_UI_THREAD();
+ std::move(task).Run();
+}
+
+// TestHandler
+
+int TestHandler::browser_count_ = 0;
+
+TestHandler::TestHandler(CompletionState* completion_state)
+ : first_browser_id_(0),
+ signal_completion_when_all_browsers_close_(true),
+ destroy_event_(nullptr),
+ destroy_test_expected_(true),
+ destroy_test_called_(false) {
+ if (completion_state) {
+ completion_state_ = completion_state;
+ completion_state_owned_ = false;
+ } else {
+ completion_state_ = new CompletionState(1);
+ completion_state_owned_ = true;
+ }
+}
+
+TestHandler::~TestHandler() {
+ DCHECK(!ui_thread_helper_.get());
+ if (destroy_test_expected_) {
+ EXPECT_TRUE(destroy_test_called_);
+ } else {
+ EXPECT_FALSE(destroy_test_called_);
+ }
+ EXPECT_TRUE(browser_map_.empty());
+
+ if (completion_state_owned_) {
+ delete completion_state_;
+ }
+
+ if (destroy_event_) {
+ destroy_event_->Signal();
+ }
+}
+
+void TestHandler::OnAfterCreated(CefRefPtr<CefBrowser> browser) {
+ EXPECT_UI_THREAD();
+
+ browser_count_++;
+
+ const int browser_id = browser->GetIdentifier();
+ EXPECT_EQ(browser_map_.find(browser_id), browser_map_.end());
+ if (browser_map_.empty()) {
+ first_browser_id_ = browser_id;
+ first_browser_ = browser;
+ }
+ browser_map_.insert(std::make_pair(browser_id, browser));
+}
+
+void TestHandler::OnBeforeClose(CefRefPtr<CefBrowser> browser) {
+ EXPECT_UI_THREAD();
+
+ // Free the browser pointer so that the browser can be destroyed.
+ const int browser_id = browser->GetIdentifier();
+ BrowserMap::iterator it = browser_map_.find(browser_id);
+ EXPECT_NE(it, browser_map_.end());
+ browser_map_.erase(it);
+
+ if (browser_id == first_browser_id_) {
+ first_browser_id_ = 0;
+ first_browser_ = nullptr;
+ }
+
+ if (browser_map_.empty() && signal_completion_when_all_browsers_close_) {
+ // Signal that the test is now complete.
+ TestComplete();
+ }
+
+ browser_count_--;
+}
+
+namespace {
+
+CefResponse::HeaderMap ToCefHeaderMap(
+ const ResourceContent::HeaderMap& headerMap) {
+ CefResponse::HeaderMap result;
+ ResourceContent::HeaderMap::const_iterator it = headerMap.begin();
+ for (; it != headerMap.end(); ++it) {
+ result.insert(std::pair<CefString, CefString>(it->first, it->second));
+ }
+ return result;
+}
+
+} // namespace
+
+CefRefPtr<CefResourceHandler> TestHandler::GetResourceHandler(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request) {
+ EXPECT_IO_THREAD();
+
+ if (resource_map_.size() > 0) {
+ const std::string& url = test_request::GetPathURL(request->GetURL());
+ ResourceMap::const_iterator it = resource_map_.find(url);
+ if (it != resource_map_.end()) {
+ // Return the previously mapped resource
+ CefRefPtr<CefStreamReader> stream = CefStreamReader::CreateForData(
+ static_cast<void*>(const_cast<char*>(it->second.content().c_str())),
+ it->second.content().length());
+ return new CefStreamResourceHandler(
+ 200, "OK", it->second.mimeType(),
+ ToCefHeaderMap(it->second.headerMap()), stream);
+ }
+ }
+
+ return nullptr;
+}
+
+void TestHandler::OnRenderProcessTerminated(CefRefPtr<CefBrowser> browser,
+ TerminationStatus status) {
+ LOG(WARNING) << "OnRenderProcessTerminated: status = " << status << ".";
+}
+
+CefRefPtr<CefBrowser> TestHandler::GetBrowser() const {
+ return first_browser_;
+}
+
+int TestHandler::GetBrowserId() const {
+ return first_browser_id_;
+}
+
+void TestHandler::GetAllBrowsers(BrowserMap* map) {
+ EXPECT_UI_THREAD();
+ EXPECT_TRUE(map);
+ *map = browser_map_;
+}
+
+void TestHandler::ExecuteTest() {
+ EXPECT_EQ(completion_state_->total(), 1);
+
+ // Reset any state from the previous run.
+ if (destroy_test_called_) {
+ destroy_test_called_ = false;
+ }
+
+ // Run the test.
+ RunTest();
+
+ // Wait for the test to complete.
+ completion_state_->WaitForTests();
+}
+
+void TestHandler::SetupComplete() {
+ // Signal that the test setup is complete.
+ completion_state_->TestComplete();
+}
+
+void TestHandler::DestroyTest() {
+ if (!CefCurrentlyOn(TID_UI)) {
+ CefPostTask(TID_UI, base::BindOnce(&TestHandler::DestroyTest, this));
+ return;
+ }
+
+ EXPECT_TRUE(destroy_test_expected_);
+ if (destroy_test_called_) {
+ return;
+ }
+ destroy_test_called_ = true;
+
+ if (!browser_map_.empty()) {
+ // Use a copy of the map since the original may be modified while we're
+ // iterating.
+ BrowserMap browser_map = browser_map_;
+
+ // Tell all browsers to close.
+ BrowserMap::const_iterator it = browser_map.begin();
+ for (; it != browser_map.end(); ++it) {
+ CloseBrowser(it->second, false);
+ }
+ }
+
+ if (ui_thread_helper_.get()) {
+ ui_thread_helper_.reset(nullptr);
+ }
+}
+
+void TestHandler::OnTestTimeout(int timeout_ms, bool treat_as_error) {
+ EXPECT_UI_THREAD();
+ if (treat_as_error) {
+ EXPECT_TRUE(false) << "Test timed out after " << timeout_ms << "ms";
+ }
+ DestroyTest();
+}
+
+void TestHandler::CreateBrowser(const CefString& url,
+ CefRefPtr<CefRequestContext> request_context,
+ CefRefPtr<CefDictionaryValue> extra_info) {
+ const bool use_views = CefCommandLine::GetGlobalCommandLine()->HasSwitch(
+ client::switches::kUseViews);
+ if (use_views && !CefCurrentlyOn(TID_UI)) {
+ // Views classes must be accessed on the UI thread.
+ CefPostTask(TID_UI, base::BindOnce(&TestHandler::CreateBrowser, this, url,
+ request_context, extra_info));
+ return;
+ }
+
+ CefWindowInfo windowInfo;
+ CefBrowserSettings settings;
+ PopulateBrowserSettings(&settings);
+
+ if (use_views) {
+ // Create the BrowserView.
+ CefRefPtr<CefBrowserView> browser_view = CefBrowserView::CreateBrowserView(
+ this, url, settings, extra_info, request_context,
+ new TestBrowserViewDelegate());
+
+ // Create the Window. It will show itself after creation.
+ TestWindowDelegate::CreateBrowserWindow(browser_view, std::string());
+ } else {
+#if defined(OS_WIN)
+ windowInfo.SetAsPopup(nullptr, "CefUnitTest");
+ windowInfo.style |= WS_VISIBLE;
+#endif
+ CefBrowserHost::CreateBrowser(windowInfo, this, url, settings, extra_info,
+ request_context);
+ }
+}
+
+// static
+void TestHandler::CloseBrowser(CefRefPtr<CefBrowser> browser,
+ bool force_close) {
+ browser->GetHost()->CloseBrowser(force_close);
+}
+
+void TestHandler::AddResource(const std::string& url,
+ const std::string& content,
+ const std::string& mime_type,
+ const ResourceContent::HeaderMap& header_map) {
+ ResourceContent rc = ResourceContent(content, mime_type, header_map);
+ AddResourceEx(url, rc);
+}
+
+void TestHandler::AddResourceEx(const std::string& url,
+ const ResourceContent& content) {
+ if (!CefCurrentlyOn(TID_IO)) {
+ CefPostTask(TID_IO, base::BindOnce(&TestHandler::AddResourceEx, this, url,
+ content));
+ return;
+ }
+
+ // Ignore the query component, if any.
+ std::string urlStr = url;
+ size_t idx = urlStr.find('?');
+ if (idx > 0) {
+ urlStr = urlStr.substr(0, idx);
+ }
+
+ resource_map_.insert(std::make_pair(urlStr, content));
+}
+
+void TestHandler::ClearResources() {
+ if (!CefCurrentlyOn(TID_IO)) {
+ CefPostTask(TID_IO, base::BindOnce(&TestHandler::ClearResources, this));
+ return;
+ }
+
+ resource_map_.clear();
+}
+
+void TestHandler::SetTestTimeout(int timeout_ms, bool treat_as_error) {
+ if (!CefCurrentlyOn(TID_UI)) {
+ CefPostTask(TID_UI, base::BindOnce(&TestHandler::SetTestTimeout, this,
+ timeout_ms, treat_as_error));
+ return;
+ }
+
+ if (destroy_test_called_) {
+ // No need to set the timeout if the test has already completed.
+ return;
+ }
+
+ const auto timeout = GetConfiguredTestTimeout(timeout_ms);
+ if (treat_as_error && !timeout) {
+ return;
+ }
+
+ // Use a weak reference to |this| via UIThreadHelper so that the TestHandler
+ // can be destroyed before the timeout expires.
+ GetUIThreadHelper()->PostDelayedTask(
+ base::BindOnce(&TestHandler::OnTestTimeout, base::Unretained(this),
+ *timeout, treat_as_error),
+ *timeout);
+}
+
+void TestHandler::TestComplete() {
+ if (!CefCurrentlyOn(TID_UI)) {
+ CefPostTask(TID_UI, base::BindOnce(&TestHandler::TestComplete, this));
+ return;
+ }
+
+ EXPECT_TRUE(browser_map_.empty());
+ completion_state_->TestComplete();
+}
+
+TestHandler::UIThreadHelper* TestHandler::GetUIThreadHelper() {
+ EXPECT_UI_THREAD();
+ CHECK(!destroy_test_called_);
+
+ if (!ui_thread_helper_.get()) {
+ ui_thread_helper_.reset(new UIThreadHelper());
+ }
+ return ui_thread_helper_.get();
+}
+
+// global functions
+
+bool TestFailed() {
+ CefRefPtr<CefCommandLine> command_line =
+ CefCommandLine::GetGlobalCommandLine();
+ if (command_line->HasSwitch("single-process")) {
+ // Check for a failure on the current test only.
+ return ::testing::UnitTest::GetInstance()
+ ->current_test_info()
+ ->result()
+ ->Failed();
+ } else {
+ // Check for any global failure.
+ return ::testing::UnitTest::GetInstance()->Failed();
+ }
+}
diff --git a/tests/ceftests/test_handler.h b/tests/ceftests/test_handler.h
new file mode 100644
index 00000000..afb213e1
--- /dev/null
+++ b/tests/ceftests/test_handler.h
@@ -0,0 +1,352 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFTESTS_TEST_HANDLER_H_
+#define CEF_TESTS_CEFTESTS_TEST_HANDLER_H_
+#pragma once
+
+#include <list>
+#include <map>
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "include/base/cef_callback.h"
+#include "include/cef_browser.h"
+#include "include/cef_client.h"
+#include "include/cef_frame.h"
+#include "include/cef_task.h"
+#include "include/cef_waitable_event.h"
+#include "tests/ceftests/thread_helper.h"
+#include "tests/ceftests/track_callback.h"
+#include "tests/gtest/include/gtest/gtest.h"
+
+class ResourceContent {
+ public:
+ typedef std::multimap<std::string, std::string> HeaderMap;
+
+ ResourceContent(const std::string& content,
+ const std::string& mime_type,
+ const HeaderMap& header_map)
+ : content_(content), mime_type_(mime_type), header_map_(header_map) {}
+
+ const std::string& content() const { return content_; }
+ const std::string& mimeType() const { return mime_type_; }
+ const HeaderMap& headerMap() const { return header_map_; }
+
+ private:
+ std::string content_;
+ std::string mime_type_;
+ HeaderMap header_map_;
+};
+
+// Base implementation of CefClient for unit tests. Add new interfaces as needed
+// by test cases.
+class TestHandler : public CefClient,
+ public CefDialogHandler,
+ public CefDisplayHandler,
+ public CefDownloadHandler,
+ public CefJSDialogHandler,
+ public CefLifeSpanHandler,
+ public CefLoadHandler,
+ public CefRequestHandler,
+ public CefResourceRequestHandler {
+ public:
+ // Tracks the completion state of related test runs.
+ class CompletionState {
+ public:
+ // |total| is the number of times that TestComplete() must be called before
+ // WaitForTests() will return.
+ explicit CompletionState(int total);
+
+ // Call this method to indicate that a test has completed.
+ void TestComplete();
+
+ // This method blocks until TestComplete() has been called the required
+ // number of times.
+ void WaitForTests();
+
+ int total() const { return total_; }
+ int count() const { return count_; }
+
+ private:
+ int total_;
+ int count_;
+
+ // Handle used to notify when the test is complete
+ CefRefPtr<CefWaitableEvent> event_;
+ };
+
+ // Represents a collection of related tests that need to be run
+ // simultaniously.
+ class Collection {
+ public:
+ // The |completion_state| object must outlive this class.
+ explicit Collection(CompletionState* completion_state);
+
+ // The |test_handler| object must outlive this class and it must share the
+ // same CompletionState object passed to the constructor.
+ void AddTestHandler(TestHandler* test_handler);
+
+ // Manages the test run.
+ // 1. Calls TestHandler::SetupTest() for all of the test objects.
+ // 2. Waits for all TestHandler objects to report that initial setup is
+ // complete by calling TestHandler::SetupComplete().
+ // 3. Calls TestHandler::RunTest() for all of the test objects.
+ // 4. Waits for all TestHandler objects to report that the test is
+ // complete by calling TestHandler::DestroyTest().
+ void ExecuteTests();
+
+ private:
+ CompletionState* completion_state_;
+
+ typedef std::list<TestHandler*> TestHandlerList;
+ TestHandlerList handler_list_;
+ };
+
+ typedef std::map<int, CefRefPtr<CefBrowser>> BrowserMap;
+
+ // Helper for executing methods using WeakPtr references to TestHandler.
+ class UIThreadHelper {
+ public:
+ UIThreadHelper();
+
+ // Pass in a |task| with an unretained reference to TestHandler. |task| will
+ // be executed only if TestHandler::DestroyTest has not yet been called.
+ // For example:
+ // GetUIThreadHelper()->PostTask(
+ // base::BindOnce(&TestHandler::DoSomething,
+ // base::Unretained(this)));
+ void PostTask(base::OnceClosure task);
+ void PostDelayedTask(base::OnceClosure task, int delay_ms);
+
+ private:
+ void TaskHelper(base::OnceClosure task);
+
+ // Must be the last member.
+ base::WeakPtrFactory<UIThreadHelper> weak_ptr_factory_;
+ };
+
+ // The |completion_state| object if specified must outlive this class.
+ explicit TestHandler(CompletionState* completion_state = nullptr);
+ ~TestHandler() override;
+
+ // Implement this method to set up the test. Only used in combination with a
+ // Collection. Call SetupComplete() once the setup is complete.
+ virtual void SetupTest() {}
+
+ // Implement this method to run the test. Call DestroyTest() once the test is
+ // complete.
+ virtual void RunTest() = 0;
+
+ // CefClient methods. Add new methods as needed by test cases.
+ CefRefPtr<CefDialogHandler> GetDialogHandler() override { return this; }
+ CefRefPtr<CefDisplayHandler> GetDisplayHandler() override { return this; }
+ CefRefPtr<CefDownloadHandler> GetDownloadHandler() override { return this; }
+ CefRefPtr<CefJSDialogHandler> GetJSDialogHandler() override { return this; }
+ CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() override { return this; }
+ CefRefPtr<CefLoadHandler> GetLoadHandler() override { return this; }
+ CefRefPtr<CefRequestHandler> GetRequestHandler() override { return this; }
+
+ // CefDownloadHandler methods
+ void OnBeforeDownload(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefDownloadItem> download_item,
+ const CefString& suggested_name,
+ CefRefPtr<CefBeforeDownloadCallback> callback) override {}
+
+ // CefLifeSpanHandler methods
+ void OnAfterCreated(CefRefPtr<CefBrowser> browser) override;
+ void OnBeforeClose(CefRefPtr<CefBrowser> browser) override;
+
+ // CefRequestHandler methods
+ CefRefPtr<CefResourceRequestHandler> GetResourceRequestHandler(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ bool is_navigation,
+ bool is_download,
+ const CefString& request_initiator,
+ bool& disable_default_handling) override {
+ return this;
+ }
+
+ // CefResourceRequestHandler methods
+ CefRefPtr<CefResourceHandler> GetResourceHandler(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request) override;
+
+ void OnRenderProcessTerminated(CefRefPtr<CefBrowser> browser,
+ TerminationStatus status) override;
+
+ // These methods should only be used if at most one non-popup browser exists.
+ CefRefPtr<CefBrowser> GetBrowser() const;
+ int GetBrowserId() const;
+
+ // Copies the map of all the currently existing browsers into |map|. Must be
+ // called on the UI thread.
+ void GetAllBrowsers(BrowserMap* map);
+
+ // Called by the test function to execute the test. This method blocks until
+ // the test is complete. Do not reference the object after this method
+ // returns. Do not use this method if the CompletionState object is shared by
+ // multiple handlers or when using a Collection object.
+ void ExecuteTest();
+
+ // Event that will be signaled from the TestHandler destructor.
+ // Used by ReleaseAndWaitForDestructor.
+ void SetDestroyEvent(CefRefPtr<CefWaitableEvent> event) {
+ destroy_event_ = event;
+ }
+
+ // If a test will not call DestroyTest() indicate so using this method.
+ void SetDestroyTestExpected(bool expected) {
+ destroy_test_expected_ = expected;
+ }
+
+ // Returns true if a browser currently exists.
+ static bool HasBrowser() { return browser_count_ > 0; }
+
+ protected:
+ // Indicate that test setup is complete. Only used in combination with a
+ // Collection.
+ virtual void SetupComplete();
+
+ // Close any existing non-popup browsers. Test completion will be signaled
+ // once all the browsers have closed if
+ // |signal_completion_when_all_browsers_close_| is true (default value).
+ // If no browsers exist then this method will do nothing and
+ // TestComplete() must be called manually.
+ virtual void DestroyTest();
+
+ // Called on the UI thread if the test times out as a result of calling
+ // SetTestTimeout(). Calls DestroyTest() by default.
+ virtual void OnTestTimeout(int timeout_ms, bool treat_as_error);
+
+ // Called from CreateBrowser() to optionally set per-browser settings.
+ virtual void PopulateBrowserSettings(CefBrowserSettings* settings) {}
+
+ void CreateBrowser(const CefString& url,
+ CefRefPtr<CefRequestContext> request_context = nullptr,
+ CefRefPtr<CefDictionaryValue> extra_info = nullptr);
+ static void CloseBrowser(CefRefPtr<CefBrowser> browser, bool force_close);
+
+ void AddResource(const std::string& url,
+ const std::string& content,
+ const std::string& mime_type,
+ const ResourceContent::HeaderMap& header_map = {});
+
+ void AddResourceEx(const std::string& url, const ResourceContent& content);
+
+ void ClearResources();
+
+ void SetSignalCompletionWhenAllBrowsersClose(bool val) {
+ signal_completion_when_all_browsers_close_ = val;
+ }
+ bool SignalCompletionWhenAllBrowsersClose() const {
+ return signal_completion_when_all_browsers_close_;
+ }
+
+ // Call OnTestTimeout() after the specified amount of time.
+ void SetTestTimeout(int timeout_ms = 5000, bool treat_as_error = true);
+
+ // Signal that the test is complete. This will be called automatically when
+ // all existing non-popup browsers are closed if
+ // |signal_completion_when_all_browsers_close_| is true (default value). It
+ // is an error to call this method before all browsers have closed.
+ void TestComplete();
+
+ // Returns the single UIThreadHelper instance, creating it if necessary. Must
+ // be called on the UI thread.
+ UIThreadHelper* GetUIThreadHelper();
+
+ private:
+ // Used to notify when the test is complete. Can be accessed on any thread.
+ CompletionState* completion_state_;
+ bool completion_state_owned_;
+
+ // Map browser ID to browser object for non-popup browsers. Only accessed on
+ // the UI thread.
+ BrowserMap browser_map_;
+
+ // Values for the first created browser. Modified on the UI thread but can be
+ // accessed on any thread.
+ int first_browser_id_;
+ CefRefPtr<CefBrowser> first_browser_;
+
+ // Map of resources that can be automatically loaded. Only accessed on the
+ // IO thread.
+ typedef std::map<std::string, ResourceContent> ResourceMap;
+ ResourceMap resource_map_;
+
+ // If true test completion will be signaled when all browsers have closed.
+ bool signal_completion_when_all_browsers_close_;
+
+ CefRefPtr<CefWaitableEvent> destroy_event_;
+
+ // Tracks whether DestroyTest() is expected or has been called.
+ bool destroy_test_expected_;
+ bool destroy_test_called_;
+
+ std::unique_ptr<UIThreadHelper> ui_thread_helper_;
+
+ // Used to track the number of currently existing browser windows.
+ static int browser_count_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestHandler);
+};
+
+// Release |handler| and wait for the destructor to be called.
+// This function is used to avoid test state leakage and to verify that
+// all Handler references have been released on test completion.
+template <typename T>
+void ReleaseAndWaitForDestructor(CefRefPtr<T>& handler, int delay_ms = 2000) {
+ CefRefPtr<CefWaitableEvent> event =
+ CefWaitableEvent::CreateWaitableEvent(true, false);
+ handler->SetDestroyEvent(event);
+ T* _handler_ptr = handler.get();
+ handler = nullptr;
+ bool handler_destructed = event->TimedWait(delay_ms);
+ EXPECT_TRUE(handler_destructed);
+ if (!handler_destructed) {
+ // |event| is a stack variable so clear the reference before returning.
+ _handler_ptr->SetDestroyEvent(nullptr);
+ }
+}
+
+// Returns true if the currently running test has failed.
+bool TestFailed();
+
+// Helper macros for executing checks in a method with a boolean return value.
+// For example:
+//
+// bool VerifyVals(bool a, bool b) {
+// V_DECLARE();
+// V_EXPECT_TRUE(a);
+// V_EXPECT_FALSE(b);
+// V_RETURN();
+// }
+//
+// EXPECT_TRUE(VerifyVals(true, false));
+
+#define V_DECLARE() \
+ bool __verify = true; \
+ bool __result
+
+#define V_RETURN() return __verify
+
+#define V_EXPECT_TRUE(condition) \
+ __result = !!(condition); \
+ __verify &= __result; \
+ GTEST_TEST_BOOLEAN_(__result, #condition, false, true, \
+ GTEST_NONFATAL_FAILURE_)
+
+#define V_EXPECT_FALSE(condition) \
+ __result = !!(condition); \
+ __verify &= !__result; \
+ GTEST_TEST_BOOLEAN_(!(__result), #condition, true, false, \
+ GTEST_NONFATAL_FAILURE_)
+
+#endif // CEF_TESTS_CEFTESTS_TEST_HANDLER_H_
diff --git a/tests/ceftests/test_request.cc b/tests/ceftests/test_request.cc
new file mode 100644
index 00000000..440137e5
--- /dev/null
+++ b/tests/ceftests/test_request.cc
@@ -0,0 +1,206 @@
+// Copyright (c) 2020 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/ceftests/test_request.h"
+
+#include <algorithm>
+#include <memory>
+
+#include "include/cef_stream.h"
+#include "include/cef_urlrequest.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "include/wrapper/cef_helpers.h"
+#include "include/wrapper/cef_stream_resource_handler.h"
+
+namespace test_request {
+
+namespace {
+
+// Implementation of CefURLRequestClient that stores response information.
+class RequestClient : public CefURLRequestClient, public State {
+ public:
+ RequestClient(const bool has_credentials,
+ const std::string& username,
+ const std::string& password,
+ RequestDoneCallback done_callback)
+ : has_credentials_(has_credentials),
+ username_(username),
+ password_(password),
+ done_callback_(std::move(done_callback)) {
+ DCHECK(!done_callback_.is_null());
+ }
+
+ void OnUploadProgress(CefRefPtr<CefURLRequest> request,
+ int64 current,
+ int64 total) override {
+ upload_progress_ct_++;
+ upload_total_ = total;
+ }
+
+ void OnDownloadProgress(CefRefPtr<CefURLRequest> request,
+ int64 current,
+ int64 total) override {
+ response_ = request->GetResponse();
+ DCHECK(response_.get());
+ DCHECK(response_->IsReadOnly());
+ download_progress_ct_++;
+ download_total_ = total;
+ }
+
+ void OnDownloadData(CefRefPtr<CefURLRequest> request,
+ const void* data,
+ size_t data_length) override {
+ response_ = request->GetResponse();
+ DCHECK(response_.get());
+ DCHECK(response_->IsReadOnly());
+ download_data_ct_++;
+ download_data_ += std::string(static_cast<const char*>(data), data_length);
+ }
+
+ bool GetAuthCredentials(bool isProxy,
+ const CefString& host,
+ int port,
+ const CefString& realm,
+ const CefString& scheme,
+ CefRefPtr<CefAuthCallback> callback) override {
+ auth_credentials_ct_++;
+ if (has_credentials_) {
+ callback->Continue(username_, password_);
+ return true;
+ }
+ return false;
+ }
+
+ void OnRequestComplete(CefRefPtr<CefURLRequest> request) override {
+ request_complete_ct_++;
+
+ request_ = request->GetRequest();
+ DCHECK(request_->IsReadOnly());
+ status_ = request->GetRequestStatus();
+ error_code_ = request->GetRequestError();
+ response_was_cached_ = request->ResponseWasCached();
+ response_ = request->GetResponse();
+ if (response_) {
+ DCHECK(response_->IsReadOnly());
+ }
+
+ std::move(done_callback_).Run(*this);
+ }
+
+ private:
+ const bool has_credentials_;
+ const std::string username_;
+ const std::string password_;
+ RequestDoneCallback done_callback_;
+
+ IMPLEMENT_REFCOUNTING(RequestClient);
+ DISALLOW_COPY_AND_ASSIGN(RequestClient);
+};
+
+// Implementation that collects all cookies, and optionally deletes them.
+class CookieVisitor : public CefCookieVisitor {
+ public:
+ CookieVisitor(bool deleteCookies, CookieDoneCallback callback)
+ : delete_cookies_(deleteCookies), callback_(std::move(callback)) {
+ DCHECK(!callback_.is_null());
+ }
+
+ ~CookieVisitor() override {
+ CEF_REQUIRE_UI_THREAD();
+ std::move(callback_).Run(cookies_);
+ }
+
+ bool Visit(const CefCookie& cookie,
+ int count,
+ int total,
+ bool& deleteCookie) override {
+ CEF_REQUIRE_UI_THREAD();
+ cookies_.push_back(cookie);
+ if (delete_cookies_) {
+ deleteCookie = true;
+ }
+ return true;
+ }
+
+ private:
+ CookieVector cookies_;
+ bool delete_cookies_;
+ CookieDoneCallback callback_;
+
+ IMPLEMENT_REFCOUNTING(CookieVisitor);
+ DISALLOW_COPY_AND_ASSIGN(CookieVisitor);
+};
+
+} // namespace
+
+void Send(const SendConfig& config, RequestDoneCallback callback) {
+ DCHECK(config.request_);
+ CefRefPtr<RequestClient> client =
+ new RequestClient(config.has_credentials_, config.username_,
+ config.password_, std::move(callback));
+ if (config.frame_) {
+ config.frame_->CreateURLRequest(config.request_, client.get());
+ } else {
+ CefURLRequest::Create(config.request_, client.get(),
+ config.request_context_);
+ }
+}
+
+std::string GetPathURL(const std::string& url) {
+ const size_t index1 = url.find('?');
+ const size_t index2 = url.find('#');
+ size_t index = std::string::npos;
+ if (index1 != std::string::npos && index2 != std::string::npos) {
+ index = std::min(index1, index2);
+ } else if (index1 != std::string::npos) {
+ index = index1;
+ } else if (index2 != std::string::npos) {
+ index = index2;
+ }
+ if (index != std::string::npos) {
+ return url.substr(0, index);
+ }
+ return url;
+}
+
+CefRefPtr<CefResourceHandler> CreateResourceHandler(
+ CefRefPtr<CefResponse> response,
+ const std::string& response_data) {
+ CefRefPtr<CefStreamReader> stream;
+ if (!response_data.empty()) {
+ stream = CefStreamReader::CreateForData(
+ static_cast<void*>(const_cast<char*>(response_data.c_str())),
+ response_data.length());
+ }
+
+ CefResponse::HeaderMap headerMap;
+ response->GetHeaderMap(headerMap);
+
+ return new CefStreamResourceHandler(
+ response->GetStatus(), response->GetStatusText(), response->GetMimeType(),
+ headerMap, stream);
+}
+
+void GetAllCookies(CefRefPtr<CefCookieManager> manager,
+ bool deleteCookies,
+ CookieDoneCallback callback) {
+ bool result = manager->VisitAllCookies(
+ new CookieVisitor(deleteCookies, std::move(callback)));
+ DCHECK(result);
+}
+
+// Retrieves URL cookies from |manager| and executes |callback| upon completion.
+// If |deleteCookies| is true the cookies will also be deleted.
+void GetUrlCookies(CefRefPtr<CefCookieManager> manager,
+ const CefString& url,
+ bool includeHttpOnly,
+ bool deleteCookies,
+ CookieDoneCallback callback) {
+ bool result = manager->VisitUrlCookies(
+ url, includeHttpOnly,
+ new CookieVisitor(deleteCookies, std::move(callback)));
+ DCHECK(result);
+}
+
+} // namespace test_request
diff --git a/tests/ceftests/test_request.h b/tests/ceftests/test_request.h
new file mode 100644
index 00000000..ff17c894
--- /dev/null
+++ b/tests/ceftests/test_request.h
@@ -0,0 +1,97 @@
+// Copyright (c) 2020 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFTESTS_TEST_REQUEST_H_
+#define CEF_TESTS_CEFTESTS_TEST_REQUEST_H_
+#pragma once
+
+#include <string>
+
+#include "include/base/cef_callback.h"
+#include "include/cef_cookie.h"
+#include "include/cef_frame.h"
+#include "include/cef_request.h"
+#include "include/cef_request_context.h"
+#include "include/cef_resource_handler.h"
+#include "include/cef_response.h"
+
+namespace test_request {
+
+// Stores all state passed to CefURLRequestClient.
+struct State {
+ public:
+ // Number of times each callback is executed.
+ int upload_progress_ct_ = 0;
+ int download_progress_ct_ = 0;
+ int download_data_ct_ = 0;
+ int auth_credentials_ct_ = 0;
+ int request_complete_ct_ = 0;
+
+ // From OnUploadProgress.
+ int64 upload_total_ = 0;
+
+ // From OnDownloadProgress.
+ int64 download_total_ = 0;
+
+ // From OnDownloadData.
+ std::string download_data_;
+
+ // From OnRequestComplete.
+ CefRefPtr<CefRequest> request_;
+ cef_urlrequest_status_t status_ = UR_UNKNOWN;
+ cef_errorcode_t error_code_ = ERR_NONE;
+ CefRefPtr<CefResponse> response_;
+ bool response_was_cached_ = false;
+};
+
+using RequestDoneCallback = base::OnceCallback<void(const State& state)>;
+
+struct SendConfig {
+ // Send using |frame_| or |request_context_| if non-nullptr.
+ // Sends using the global request context if both are nullptr.
+ CefRefPtr<CefFrame> frame_;
+ CefRefPtr<CefRequestContext> request_context_;
+
+ // The request to send.
+ CefRefPtr<CefRequest> request_;
+
+ // Returned via GetAuthCredentials if |has_credentials_| is true.
+ bool has_credentials_ = false;
+ std::string username_;
+ std::string password_;
+};
+
+// Send a request. |callback| will be executed on the calling thread after the
+// request completes.
+void Send(const SendConfig& config, RequestDoneCallback callback);
+
+// Removes query and/or fragment components from |url|.
+std::string GetPathURL(const std::string& url);
+
+// Creates a new resource handler that returns the specified response.
+CefRefPtr<CefResourceHandler> CreateResourceHandler(
+ CefRefPtr<CefResponse> response,
+ const std::string& response_data);
+
+using CookieVector = std::vector<CefCookie>;
+using CookieDoneCallback =
+ base::OnceCallback<void(const CookieVector& cookies)>;
+
+// Retrieves all cookies from |manager| and executes |callback| upon completion.
+// If |deleteCookies| is true the cookies will also be deleted.
+void GetAllCookies(CefRefPtr<CefCookieManager> manager,
+ bool deleteCookies,
+ CookieDoneCallback callback);
+
+// Retrieves URL cookies from |manager| and executes |callback| upon completion.
+// If |deleteCookies| is true the cookies will also be deleted.
+void GetUrlCookies(CefRefPtr<CefCookieManager> manager,
+ const CefString& url,
+ bool includeHttpOnly,
+ bool deleteCookies,
+ CookieDoneCallback callback);
+
+} // namespace test_request
+
+#endif // CEF_TESTS_CEFTESTS_TEST_REQUEST_H_
diff --git a/tests/ceftests/test_server.cc b/tests/ceftests/test_server.cc
new file mode 100644
index 00000000..855e2cf6
--- /dev/null
+++ b/tests/ceftests/test_server.cc
@@ -0,0 +1,58 @@
+// Copyright (c) 2020 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/ceftests/test_server.h"
+
+#include "tests/ceftests/test_server_manager.h"
+
+#include <vector>
+
+namespace test_server {
+
+// Must use a different port than server_unittest.cc.
+const char kHttpServerAddress[] = "127.0.0.1";
+const uint16 kHttpServerPort = 8098;
+
+const char kIncompleteDoNotSendData[] = "DO NOT SEND";
+
+CefRefPtr<CefResponse> Create404Response() {
+ auto response = CefResponse::Create();
+ response->SetStatus(404);
+ response->SetMimeType("text/html");
+ return response;
+}
+
+void Stop(base::OnceClosure callback) {
+ // Stop both HTTPS and HTTP servers in a chain.
+ Manager::Stop(base::BindOnce(
+ [](base::OnceClosure callback) {
+ Manager::Stop(std::move(callback),
+ /*https_server=*/false);
+ },
+ std::move(callback)),
+ /*https_server=*/true);
+}
+
+std::string GetOrigin(bool https_server) {
+ return Manager::GetOrigin(https_server);
+}
+
+std::string GetScheme(bool https_server) {
+ return https_server ? "https" : "http";
+}
+
+std::string GetHost(bool https_server, bool include_port) {
+ const auto& origin = GetOrigin(https_server);
+
+ const auto scheme_offset = origin.find("//");
+ const auto& origin_without_scheme = origin.substr(scheme_offset + 2);
+ if (include_port) {
+ return origin_without_scheme;
+ }
+
+ const auto port_offset = origin_without_scheme.find(':');
+ return origin_without_scheme.substr(0, port_offset);
+}
+
+} // namespace test_server
diff --git a/tests/ceftests/test_server.h b/tests/ceftests/test_server.h
new file mode 100644
index 00000000..4a1c1e53
--- /dev/null
+++ b/tests/ceftests/test_server.h
@@ -0,0 +1,50 @@
+// Copyright (c) 2020 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFTESTS_TEST_SERVER_H_
+#define CEF_TESTS_CEFTESTS_TEST_SERVER_H_
+#pragma once
+
+#include <string>
+
+#include "include/base/cef_callback.h"
+#include "include/cef_registration.h"
+#include "include/cef_request.h"
+#include "include/cef_response.h"
+
+namespace test_server {
+
+// Use of these values is deprecated. Instead use GetOrigin/GetHost in the
+// browser process after server initialization.
+extern const char kHttpServerAddress[];
+extern const uint16 kHttpServerPort;
+
+// Used with incomplete tests for data that should not be sent.
+extern const char kIncompleteDoNotSendData[];
+
+// Create a 404 response for passing to ResponseCallback.
+CefRefPtr<CefResponse> Create404Response();
+
+using ResponseCallback =
+ base::RepeatingCallback<void(CefRefPtr<CefResponse> response,
+ const std::string& response_data)>;
+
+// Stops all servers that are currently running and executes |callback| on the
+// UI thread. This method will be called by the test framework on shutdown.
+void Stop(base::OnceClosure callback);
+
+// Returns the origin for the currently running server (e.g.
+// "[http|https]://127.0.0.1:<port>").
+std::string GetOrigin(bool https_server);
+
+// Returns the scheme for the currently running server (e.g. "http" or "https").
+std::string GetScheme(bool https_server);
+
+// Returns the host for the currently running server (e.g.
+// "127.0.0.1[:<port>]").
+std::string GetHost(bool https_server, bool include_port);
+
+} // namespace test_server
+
+#endif // CEF_TESTS_CEFTESTS_TEST_SERVER_H_
diff --git a/tests/ceftests/test_server_manager.cc b/tests/ceftests/test_server_manager.cc
new file mode 100644
index 00000000..df6d96f3
--- /dev/null
+++ b/tests/ceftests/test_server_manager.cc
@@ -0,0 +1,303 @@
+// Copyright (c) 2020 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/ceftests/test_server_manager.h"
+
+#include "include/wrapper/cef_closure_task.h"
+#include "include/wrapper/cef_helpers.h"
+#include "tests/gtest/include/gtest/gtest.h"
+
+namespace test_server {
+
+namespace {
+
+Manager* g_http_manager = nullptr;
+Manager* g_https_manager = nullptr;
+
+} // namespace
+
+// May be created on any thread but will be destroyed on the UI thread.
+class ObserverRegistration : public CefRegistration {
+ public:
+ ObserverRegistration(Observer* observer, bool https_server)
+ : observer_(observer), https_server_(https_server) {
+ EXPECT_TRUE(observer_);
+ }
+
+ ~ObserverRegistration() override {
+ CEF_REQUIRE_UI_THREAD();
+
+ if (auto manager = Manager::GetInstance(https_server_)) {
+ manager->RemoveObserver(
+ observer_,
+ base::BindOnce([](Observer* observer) { observer->OnUnregistered(); },
+ base::Unretained(observer_)));
+ }
+ }
+
+ void Initialize() {
+ CEF_REQUIRE_UI_THREAD();
+ Manager::GetOrCreateInstance(https_server_)->AddObserver(observer_);
+ observer_->OnRegistered();
+ }
+
+ static void InitializeRegistration(
+ CefRefPtr<ObserverRegistration> registration,
+ Manager::DoneCallback callback) {
+ if (!CefCurrentlyOn(TID_UI)) {
+ CefPostTask(TID_UI, base::BindOnce(InitializeRegistration, registration,
+ std::move(callback)));
+ return;
+ }
+
+ registration->Initialize();
+ if (!callback.is_null()) {
+ std::move(callback).Run();
+ }
+ }
+
+ private:
+ Observer* const observer_;
+ const bool https_server_;
+
+ IMPLEMENT_REFCOUNTING_DELETE_ON_UIT(ObserverRegistration);
+ DISALLOW_COPY_AND_ASSIGN(ObserverRegistration);
+};
+
+Manager::Manager(bool https_server) : https_server_(https_server) {
+ CEF_REQUIRE_UI_THREAD();
+
+ if (https_server) {
+ DCHECK(!g_https_manager);
+ g_https_manager = this;
+ } else {
+ DCHECK(!g_http_manager);
+ g_http_manager = this;
+ }
+}
+
+Manager::~Manager() {
+ CEF_REQUIRE_UI_THREAD();
+ EXPECT_TRUE(observer_list_.empty());
+ EXPECT_TRUE(start_callback_list_.empty());
+ EXPECT_TRUE(stop_callback_.is_null());
+
+ if (https_server_) {
+ g_https_manager = nullptr;
+ } else {
+ g_http_manager = nullptr;
+ }
+}
+
+// static
+Manager* Manager::GetInstance(bool https_server) {
+ return https_server ? g_https_manager : g_http_manager;
+}
+
+// static
+Manager* Manager::GetOrCreateInstance(bool https_server) {
+ if (auto manager = GetInstance(https_server)) {
+ return manager;
+ }
+
+ new Manager(https_server);
+ auto manager = GetInstance(https_server);
+ DCHECK(manager);
+ return manager;
+}
+
+// static
+void Manager::Start(StartDoneCallback callback, bool https_server) {
+ EXPECT_FALSE(callback.is_null());
+ if (!CefCurrentlyOn(TID_UI)) {
+ CefPostTask(TID_UI, base::BindOnce(Manager::Start, std::move(callback),
+ https_server));
+ return;
+ }
+
+ Manager::GetOrCreateInstance(https_server)->StartImpl(std::move(callback));
+}
+
+// static
+void Manager::Stop(DoneCallback callback, bool https_server) {
+ EXPECT_FALSE(callback.is_null());
+ if (!CefCurrentlyOn(TID_UI)) {
+ CefPostTask(TID_UI, base::BindOnce(Manager::Stop, std::move(callback),
+ https_server));
+ return;
+ }
+
+ if (auto manager = Manager::GetInstance(https_server)) {
+ manager->StopImpl(std::move(callback));
+ } else {
+ std::move(callback).Run();
+ }
+}
+
+// static
+CefRefPtr<CefRegistration> Manager::AddObserver(Observer* observer,
+ DoneCallback callback,
+ bool https_server) {
+ EXPECT_TRUE(observer);
+ CefRefPtr<ObserverRegistration> registration =
+ new ObserverRegistration(observer, https_server);
+ ObserverRegistration::InitializeRegistration(registration,
+ std::move(callback));
+ return registration.get();
+}
+
+// static
+CefRefPtr<CefRegistration> Manager::AddObserverAndStart(
+ Observer* observer,
+ StartDoneCallback callback,
+ bool https_server) {
+ return AddObserver(
+ observer,
+ base::BindOnce(Manager::Start, std::move(callback), https_server),
+ https_server);
+}
+
+// static
+std::string Manager::GetOrigin(bool https_server) {
+ if (auto manager = Manager::GetInstance(https_server)) {
+ return manager->origin_;
+ }
+ NOTREACHED();
+ return std::string();
+}
+
+void Manager::StartImpl(StartDoneCallback callback) {
+ CEF_REQUIRE_UI_THREAD();
+ EXPECT_FALSE(stopping_);
+
+ if (!origin_.empty()) {
+ // The server is already running.
+ std::move(callback).Run(origin_);
+ return;
+ }
+
+ // If tests run in parallel, and the server is starting, then there may be
+ // multiple pending callbacks.
+ start_callback_list_.push_back(std::move(callback));
+
+ // Only create the runner a single time.
+ if (!runner_) {
+ runner_ = Runner::Create(this, https_server_);
+ runner_->StartServer();
+ }
+}
+
+void Manager::StopImpl(DoneCallback callback) {
+ CEF_REQUIRE_UI_THREAD();
+ if (!runner_) {
+ // The server is not currently running.
+ std::move(callback).Run();
+ return;
+ }
+
+ // Stop will be called one time on test framework shutdown.
+ EXPECT_FALSE(stopping_);
+ stopping_ = true;
+
+ // Only 1 stop callback supported.
+ EXPECT_TRUE(stop_callback_.is_null());
+ stop_callback_ = std::move(callback);
+
+ runner_->ShutdownServer();
+}
+
+void Manager::AddObserver(Observer* observer) {
+ CEF_REQUIRE_UI_THREAD();
+ EXPECT_FALSE(stopping_);
+ observer_list_.push_back(observer);
+}
+
+void Manager::RemoveObserver(Observer* observer, DoneCallback callback) {
+ CEF_REQUIRE_UI_THREAD();
+ bool found = false;
+ ObserverList::iterator it = observer_list_.begin();
+ for (; it != observer_list_.end(); ++it) {
+ if (*it == observer) {
+ observer_list_.erase(it);
+ found = true;
+ break;
+ }
+ }
+ EXPECT_TRUE(found);
+
+ if (observer_list_.empty() && https_server_ && !stopping_) {
+ // Stop the HTTPS server when the last Observer is removed. We can't
+ // currently reuse the HTTPS server between tests due to
+ // https://crrev.com/dd2a57d753 causing cert registration issues.
+ StopImpl(std::move(callback));
+ } else {
+ std::move(callback).Run();
+ }
+}
+
+void Manager::OnServerCreated(const std::string& server_origin) {
+ CEF_REQUIRE_UI_THREAD();
+
+ EXPECT_TRUE(origin_.empty());
+ origin_ = server_origin;
+
+ for (auto& callback : start_callback_list_) {
+ std::move(callback).Run(origin_);
+ }
+ start_callback_list_.clear();
+}
+
+void Manager::OnServerDestroyed() {
+ CEF_REQUIRE_UI_THREAD();
+
+ origin_.clear();
+ runner_.reset();
+}
+
+// All server-related objects have been torn down.
+void Manager::OnServerHandlerDeleted() {
+ CEF_REQUIRE_UI_THREAD();
+
+ EXPECT_FALSE(stop_callback_.is_null());
+ std::move(stop_callback_).Run();
+
+ delete this;
+}
+
+void Manager::OnTestServerRequest(CefRefPtr<CefRequest> request,
+ const ResponseCallback& response_callback) {
+ CEF_REQUIRE_UI_THREAD();
+
+ // TODO(chrome-runtime): Debug why favicon requests don't always have the
+ // correct resource type.
+ const std::string& url = request->GetURL();
+ if (request->GetResourceType() == RT_FAVICON ||
+ url.find("/favicon.ico") != std::string::npos) {
+ // We don't currently handle favicon requests.
+ response_callback.Run(Create404Response(), std::string());
+ return;
+ }
+
+ EXPECT_FALSE(observer_list_.empty()) << url;
+
+ // Use a copy in case |observer_list_| is modified during iteration.
+ ObserverList list = observer_list_;
+
+ bool handled = false;
+
+ ObserverList::const_iterator it = list.begin();
+ for (; it != list.end(); ++it) {
+ if ((*it)->OnTestServerRequest(request, response_callback)) {
+ handled = true;
+ break;
+ }
+ }
+
+ if (!handled) {
+ LOG(WARNING) << "Unhandled request for: " << url;
+ response_callback.Run(Create404Response(), std::string());
+ }
+}
+
+} // namespace test_server
diff --git a/tests/ceftests/test_server_manager.h b/tests/ceftests/test_server_manager.h
new file mode 100644
index 00000000..30d6c652
--- /dev/null
+++ b/tests/ceftests/test_server_manager.h
@@ -0,0 +1,101 @@
+// Copyright (c) 2020 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFTESTS_TEST_SERVER_MANAGER_H_
+#define CEF_TESTS_CEFTESTS_TEST_SERVER_MANAGER_H_
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include "include/base/cef_callback.h"
+#include "include/cef_registration.h"
+#include "include/cef_request.h"
+#include "include/cef_response.h"
+#include "tests/ceftests/test_server_observer.h"
+#include "tests/ceftests/test_server_runner.h"
+
+namespace test_server {
+
+class ObserverRegistration;
+
+// Static methods are safe to call on any thread. Non-static methods are only
+// called on the UI thread. Deletes itself after the server is stopped. Use
+// ObserverHelper instead of calling these methods directly.
+class Manager : public Runner::Delegate {
+ public:
+ using StartDoneCallback =
+ base::OnceCallback<void(const std::string& server_origin)>;
+ using DoneCallback = base::OnceClosure;
+
+ // Starts the server if it is not currently running, and executes |callback|
+ // on the UI thread.
+ static void Start(StartDoneCallback callback, bool https_server);
+
+ // Stops the server if it is currently running, and executes |callback| on the
+ // UI thread. This method will be called by the test framework on shutdown.
+ static void Stop(DoneCallback callback, bool https_server);
+
+ // Add an observer for server callbacks. Remains registered until the returned
+ // CefRegistration object is destroyed. Registered observers will be executed
+ // in the order of registration until one returns true to indicate that it
+ // handled the callback. |callback| will be executed on the UI thread after
+ // registration is complete.
+ static CefRefPtr<CefRegistration> AddObserver(Observer* observer,
+ DoneCallback callback,
+ bool https_server);
+
+ // Combination of AddObserver() followed by Start().
+ static CefRefPtr<CefRegistration> AddObserverAndStart(
+ Observer* observer,
+ StartDoneCallback callback,
+ bool https_server);
+
+ // Returns the origin for an existing server.
+ static std::string GetOrigin(bool https_server);
+
+ private:
+ friend class ObserverRegistration;
+
+ explicit Manager(bool https_server);
+ ~Manager();
+
+ static Manager* GetInstance(bool https_server);
+ static Manager* GetOrCreateInstance(bool https_server);
+
+ void StartImpl(StartDoneCallback callback);
+ void StopImpl(DoneCallback callback);
+
+ void AddObserver(Observer* observer);
+ void RemoveObserver(Observer* observer, DoneCallback callback);
+
+ // Runner::Delegate methods:
+ void OnServerCreated(const std::string& server_origin) override;
+ void OnServerDestroyed() override;
+ void OnServerHandlerDeleted() override;
+ void OnTestServerRequest(CefRefPtr<CefRequest> request,
+ const ResponseCallback& response_callback) override;
+
+ private:
+ const bool https_server_;
+
+ std::unique_ptr<Runner> runner_;
+ std::string origin_;
+
+ using StartDoneCallbackList = std::vector<StartDoneCallback>;
+ StartDoneCallbackList start_callback_list_;
+
+ DoneCallback stop_callback_;
+
+ using ObserverList = std::vector<Observer*>;
+ ObserverList observer_list_;
+
+ bool stopping_ = false;
+
+ DISALLOW_COPY_AND_ASSIGN(Manager);
+};
+
+} // namespace test_server
+
+#endif // CEF_TESTS_CEFTESTS_TEST_SERVER_MANAGER_H_
diff --git a/tests/ceftests/test_server_observer.cc b/tests/ceftests/test_server_observer.cc
new file mode 100644
index 00000000..9422e40c
--- /dev/null
+++ b/tests/ceftests/test_server_observer.cc
@@ -0,0 +1,57 @@
+// Copyright (c) 2020 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/ceftests/test_server.h"
+
+#include "include/wrapper/cef_helpers.h"
+#include "tests/ceftests/test_server_manager.h"
+#include "tests/gtest/include/gtest/gtest.h"
+
+#include <vector>
+
+namespace test_server {
+
+ObserverHelper::ObserverHelper() : weak_ptr_factory_(this) {
+ CEF_REQUIRE_UI_THREAD();
+}
+
+ObserverHelper::~ObserverHelper() {
+ EXPECT_TRUE(state_ == State::NONE);
+}
+
+void ObserverHelper::Initialize(bool https_server) {
+ CEF_REQUIRE_UI_THREAD();
+ EXPECT_TRUE(state_ == State::NONE);
+ state_ = State::INITIALIZING;
+ registration_ = Manager::AddObserverAndStart(
+ this,
+ base::BindOnce(&ObserverHelper::OnStartDone,
+ weak_ptr_factory_.GetWeakPtr()),
+ https_server);
+}
+
+void ObserverHelper::Shutdown() {
+ CEF_REQUIRE_UI_THREAD();
+ EXPECT_TRUE(state_ == State::INITIALIZED);
+ state_ = State::SHUTTINGDOWN;
+ registration_ = nullptr;
+}
+
+void ObserverHelper::OnStartDone(const std::string& server_origin) {
+ EXPECT_TRUE(state_ == State::INITIALIZING);
+ state_ = State::INITIALIZED;
+ OnInitialized(server_origin);
+}
+
+void ObserverHelper::OnRegistered() {
+ EXPECT_TRUE(state_ == State::INITIALIZING);
+}
+
+void ObserverHelper::OnUnregistered() {
+ EXPECT_TRUE(state_ == State::SHUTTINGDOWN);
+ state_ = State::NONE;
+ OnShutdown();
+}
+
+} // namespace test_server
diff --git a/tests/ceftests/test_server_observer.h b/tests/ceftests/test_server_observer.h
new file mode 100644
index 00000000..75d4070e
--- /dev/null
+++ b/tests/ceftests/test_server_observer.h
@@ -0,0 +1,84 @@
+// Copyright (c) 2020 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFTESTS_TEST_SERVER_OBSERVER_H_
+#define CEF_TESTS_CEFTESTS_TEST_SERVER_OBSERVER_H_
+#pragma once
+
+#include <string>
+
+#include "include/base/cef_callback.h"
+#include "include/base/cef_weak_ptr.h"
+#include "include/cef_registration.h"
+#include "include/cef_request.h"
+#include "tests/ceftests/test_server.h"
+
+namespace test_server {
+
+// Observer for server callbacks. Methods will be called on the UI thread.
+class Observer {
+ public:
+ using ResponseCallback = test_server::ResponseCallback;
+
+ // Called when this Observer is registered.
+ virtual void OnRegistered() = 0;
+
+ // Called when this Observer is unregistered.
+ virtual void OnUnregistered() = 0;
+
+ // Return true and execute |response_callback| either synchronously or
+ // asynchronously if the request was handled. Do not execute
+ // |response_callback| when returning false.
+ virtual bool OnTestServerRequest(
+ CefRefPtr<CefRequest> request,
+ const ResponseCallback& response_callback) = 0;
+
+ protected:
+ virtual ~Observer() = default;
+};
+
+// Helper for managing Observer registration and callbacks. Only used on the UI
+// thread.
+class ObserverHelper : public Observer {
+ public:
+ ObserverHelper();
+ ~ObserverHelper() override;
+
+ // Initialize the registration. If |https_server| is true an HTTPS server will
+ // be used, otherwise an HTTP server will be used. Results in a call to
+ // OnInitialized().
+ void Initialize(bool https_server);
+
+ // Shut down the registration. Results in a call to OnShutdown().
+ void Shutdown();
+
+ // Implement this method to start sending server requests after Initialize().
+ // |server_origin| will be value like "http://127.0.0.1:<port>".
+ virtual void OnInitialized(const std::string& server_origin) = 0;
+
+ // Implement this method to continue the test after Shutdown().
+ virtual void OnShutdown() = 0;
+
+ private:
+ void OnStartDone(const std::string& server_origin);
+ void OnRegistered() override;
+ void OnUnregistered() override;
+
+ CefRefPtr<CefRegistration> registration_;
+
+ enum class State {
+ NONE,
+ INITIALIZING,
+ INITIALIZED,
+ SHUTTINGDOWN,
+ } state_ = State::NONE;
+
+ base::WeakPtrFactory<ObserverHelper> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(ObserverHelper);
+};
+
+} // namespace test_server
+
+#endif // CEF_TESTS_CEFTESTS_TEST_SERVER_OBSERVER_H_
diff --git a/tests/ceftests/test_server_observer_unittest.cc b/tests/ceftests/test_server_observer_unittest.cc
new file mode 100644
index 00000000..dca95560
--- /dev/null
+++ b/tests/ceftests/test_server_observer_unittest.cc
@@ -0,0 +1,232 @@
+// Copyright (c) 2020 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include <sstream>
+
+#include "include/cef_command_line.h"
+#include "include/cef_task.h"
+#include "include/cef_waitable_event.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "include/wrapper/cef_helpers.h"
+#include "tests/ceftests/test_request.h"
+#include "tests/ceftests/test_server_observer.h"
+#include "tests/ceftests/test_util.h"
+#include "tests/ceftests/track_callback.h"
+#include "tests/gtest/include/gtest/gtest.h"
+
+namespace {
+
+struct TestState {
+ bool https_server = false;
+
+ TrackCallback got_initialized_;
+ TrackCallback got_request_;
+ TrackCallback got_response_;
+ TrackCallback got_shutdown_;
+
+ bool ExpectAll() {
+ EXPECT_TRUE(got_initialized_);
+ EXPECT_TRUE(got_request_);
+ EXPECT_TRUE(got_response_);
+ EXPECT_TRUE(got_shutdown_);
+ return got_initialized_ && got_request_ && got_response_ && got_shutdown_;
+ }
+};
+
+const char kResponseData[] = "Test data";
+
+class TestServerObserver : public test_server::ObserverHelper {
+ public:
+ TestServerObserver(TestState* state,
+ const std::string& path,
+ base::OnceClosure done_callback)
+ : state_(state),
+ path_(path),
+ done_callback_(std::move(done_callback)),
+ weak_ptr_factory_(this) {
+ DCHECK(state);
+ DCHECK(!path.empty());
+ DCHECK(!done_callback_.is_null());
+ Initialize(state_->https_server);
+ }
+
+ ~TestServerObserver() override { std::move(done_callback_).Run(); }
+
+ void OnInitialized(const std::string& server_origin) override {
+ CEF_REQUIRE_UI_THREAD();
+ EXPECT_FALSE(state_->got_initialized_);
+ EXPECT_FALSE(state_->got_request_);
+ EXPECT_FALSE(state_->got_response_);
+ EXPECT_FALSE(state_->got_shutdown_);
+
+ state_->got_initialized_.yes();
+
+ url_ = server_origin + path_;
+
+ // Send a request to the server.
+ test_request::SendConfig config;
+ config.request_ = CefRequest::Create();
+ config.request_->SetURL(url_);
+ test_request::Send(config,
+ base::BindOnce(&TestServerObserver::OnRequestResponse,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
+
+ bool OnTestServerRequest(CefRefPtr<CefRequest> request,
+ const ResponseCallback& response_callback) override {
+ CEF_REQUIRE_UI_THREAD();
+ const std::string& url = request->GetURL();
+ if (url != url_) {
+ return false;
+ }
+
+ EXPECT_TRUE(state_->got_initialized_);
+ EXPECT_FALSE(state_->got_request_);
+ EXPECT_FALSE(state_->got_response_);
+ EXPECT_FALSE(state_->got_shutdown_);
+
+ state_->got_request_.yes();
+
+ auto response = CefResponse::Create();
+ response->SetStatus(200);
+ response->SetMimeType("text/plain");
+
+ response_callback.Run(response, kResponseData);
+
+ // Stop propagating the callback.
+ return true;
+ }
+
+ void OnRequestResponse(const test_request::State& state) {
+ CEF_REQUIRE_UI_THREAD();
+ // Don't test for disconnected, which may race response.
+ EXPECT_TRUE(state_->got_initialized_);
+ EXPECT_TRUE(state_->got_request_);
+ EXPECT_FALSE(state_->got_response_);
+ EXPECT_FALSE(state_->got_shutdown_);
+
+ state_->got_response_.yes();
+
+ EXPECT_STREQ(url_.c_str(), state.request_->GetURL().ToString().c_str());
+ EXPECT_EQ(UR_SUCCESS, state.status_);
+ EXPECT_EQ(ERR_NONE, state.error_code_);
+ EXPECT_EQ(200, state.response_->GetStatus());
+ EXPECT_STREQ(kResponseData, state.download_data_.c_str());
+
+ // Trigger shutdown asynchronously.
+ CefPostTask(TID_UI, base::BindOnce(&TestServerObserver::Shutdown,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
+
+ void OnShutdown() override {
+ CEF_REQUIRE_UI_THREAD();
+ EXPECT_TRUE(state_->got_initialized_);
+ EXPECT_TRUE(state_->got_request_);
+ EXPECT_TRUE(state_->got_response_);
+ EXPECT_FALSE(state_->got_shutdown_);
+
+ state_->got_shutdown_.yes();
+
+ // End the test.
+ delete this;
+ }
+
+ private:
+ TestState* const state_;
+ const std::string path_;
+ base::OnceClosure done_callback_;
+
+ std::string url_;
+
+ base::WeakPtrFactory<TestServerObserver> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestServerObserver);
+};
+
+void CreateObserverOnUIThread(TestState* state,
+ const std::string& path,
+ base::OnceClosure done_callback) {
+ if (!CefCurrentlyOn(TID_UI)) {
+ CefPostTask(TID_UI, base::BindOnce(CreateObserverOnUIThread,
+ base::Unretained(state), path,
+ std::move(done_callback)));
+ return;
+ }
+
+ new TestServerObserver(state, path, std::move(done_callback));
+}
+
+void SignalIfDone(CefRefPtr<CefWaitableEvent> event,
+ size_t* count,
+ size_t total) {
+ if (++(*count) == total) {
+ event->Signal();
+ }
+}
+
+void Wait(CefRefPtr<CefWaitableEvent> event) {
+ const auto timeout = GetConfiguredTestTimeout(/*timeout_ms=*/2000);
+ if (!timeout) {
+ event->Wait();
+ } else {
+ event->TimedWait(*timeout);
+ }
+}
+
+void RunHelperSingle(bool https_server) {
+ CefRefPtr<CefWaitableEvent> event =
+ CefWaitableEvent::CreateWaitableEvent(true, false);
+
+ TestState state;
+ state.https_server = https_server;
+ CreateObserverOnUIThread(&state, "/TestServerTest.ObserverHelperSingle",
+ base::BindOnce(&CefWaitableEvent::Signal, event));
+
+ Wait(event);
+
+ EXPECT_TRUE(state.ExpectAll());
+}
+
+void RunHelperMultiple(bool https_server) {
+ CefRefPtr<CefWaitableEvent> event =
+ CefWaitableEvent::CreateWaitableEvent(true, false);
+
+ TestState states[3];
+ size_t count = 0;
+ const size_t size = std::size(states);
+
+ for (size_t i = 0; i < size; ++i) {
+ std::stringstream ss;
+ ss << "/TestServerTest.ObserverHelperMultiple" << i;
+ auto done_callback =
+ base::BindOnce(SignalIfDone, event, base::Unretained(&count), size);
+ states[i].https_server = https_server;
+ CreateObserverOnUIThread(&states[i], ss.str(), std::move(done_callback));
+ }
+
+ Wait(event);
+
+ EXPECT_EQ(size, count);
+ for (size_t i = 0; i < size; ++i) {
+ EXPECT_TRUE(states[i].ExpectAll()) << i;
+ }
+}
+
+} // namespace
+
+TEST(TestServerObserverTest, HelperSingleHttp) {
+ RunHelperSingle(/*https_server=*/false);
+}
+
+TEST(TestServerObserverTest, HelperMultipleHttp) {
+ RunHelperMultiple(/*https_server=*/false);
+}
+
+TEST(TestServerObserverTest, HelperSingleHttps) {
+ RunHelperSingle(/*https_server=*/true);
+}
+
+TEST(TestServerObserverTest, HelperMultipleHttps) {
+ RunHelperMultiple(/*https_server=*/true);
+}
diff --git a/tests/ceftests/test_server_runner.cc b/tests/ceftests/test_server_runner.cc
new file mode 100644
index 00000000..1980bba2
--- /dev/null
+++ b/tests/ceftests/test_server_runner.cc
@@ -0,0 +1,33 @@
+// Copyright (c) 2020 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/ceftests/test_server_runner.h"
+
+#include "tests/shared/common/client_switches.h"
+
+#include "include/base/cef_logging.h"
+#include "include/cef_command_line.h"
+
+namespace test_server {
+
+Runner::Runner(Delegate* delegate) : delegate_(delegate) {
+ DCHECK(delegate_);
+}
+
+// static
+std::unique_ptr<Runner> Runner::Create(Runner::Delegate* delegate,
+ bool https_server) {
+ static bool use_test_http_server = [] {
+ auto command_line = CefCommandLine::GetGlobalCommandLine();
+ return command_line->HasSwitch(client::switches::kUseTestHttpServer);
+ }();
+
+ if (https_server || use_test_http_server) {
+ return CreateTest(delegate, https_server);
+ }
+
+ return CreateNormal(delegate);
+}
+
+} // namespace test_server
diff --git a/tests/ceftests/test_server_runner.h b/tests/ceftests/test_server_runner.h
new file mode 100644
index 00000000..04541702
--- /dev/null
+++ b/tests/ceftests/test_server_runner.h
@@ -0,0 +1,69 @@
+// Copyright (c) 2020 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFTESTS_TEST_SERVER_RUNNER_H_
+#define CEF_TESTS_CEFTESTS_TEST_SERVER_RUNNER_H_
+#pragma once
+
+#include <memory>
+#include <string>
+
+#include "include/cef_request.h"
+#include "include/internal/cef_types.h"
+#include "tests/ceftests/test_server.h"
+
+namespace test_server {
+
+// Runs the server. All methods will be called on the UI thread.
+class Runner {
+ public:
+ // Interface implemented by the Manager that creates/owns the Runner.
+ class Delegate {
+ public:
+ // Server created notification.
+ virtual void OnServerCreated(const std::string& server_origin) = 0;
+
+ // Server destroyed notification. May delete the Runner.
+ virtual void OnServerDestroyed() = 0;
+
+ // Server handler deleted notification. May delete the Manager.
+ virtual void OnServerHandlerDeleted() = 0;
+
+ // Server request notification.
+ virtual void OnTestServerRequest(
+ CefRefPtr<CefRequest> request,
+ const ResponseCallback& response_callback) = 0;
+
+ protected:
+ virtual ~Delegate() = default;
+ };
+
+ // |delegate| will outlive this object.
+ explicit Runner(Delegate* delegate);
+ virtual ~Runner() = default;
+
+ // Called by the Manager to create the Runner.
+ static std::unique_ptr<Runner> Create(Delegate* delegate, bool https_server);
+
+ // Called by the Manager to create/destroy the server handler.
+ virtual void StartServer() = 0;
+ virtual void ShutdownServer() = 0;
+
+ private:
+ // Create a Runner based on CefServer.
+ static std::unique_ptr<Runner> CreateNormal(Delegate* delegate);
+
+ // Create a Runner based on CefTestServer.
+ static std::unique_ptr<Runner> CreateTest(Delegate* delegate,
+ bool https_server);
+
+ protected:
+ Delegate* const delegate_;
+
+ DISALLOW_COPY_AND_ASSIGN(Runner);
+};
+
+} // namespace test_server
+
+#endif // CEF_TESTS_CEFTESTS_TEST_SERVER_RUNNER_H_
diff --git a/tests/ceftests/test_server_runner_normal.cc b/tests/ceftests/test_server_runner_normal.cc
new file mode 100644
index 00000000..c261af0c
--- /dev/null
+++ b/tests/ceftests/test_server_runner_normal.cc
@@ -0,0 +1,196 @@
+// Copyright (c) 2020 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/ceftests/test_server_runner.h"
+
+#include "include/cef_server.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "include/wrapper/cef_helpers.h"
+#include "tests/gtest/include/gtest/gtest.h"
+
+namespace test_server {
+
+namespace {
+
+const int kHttpServerBacklog = 10;
+
+// Created on the UI thread and called on the dedicated server thread.
+class ServerHandler : public CefServerHandler {
+ public:
+ explicit ServerHandler(Runner::Delegate* delegate) : delegate_(delegate) {}
+
+ ~ServerHandler() override {
+ CEF_REQUIRE_UI_THREAD();
+ EXPECT_FALSE(server_);
+ delegate_->OnServerHandlerDeleted();
+ }
+
+ void Shutdown() { server_->Shutdown(); }
+
+ // CefServerHandler methods:
+ void OnServerCreated(CefRefPtr<CefServer> server) override {
+ EXPECT_TRUE(server->GetTaskRunner()->BelongsToCurrentThread());
+ server_ = server;
+ NotifyServerCreated("http://" + server->GetAddress().ToString());
+ }
+
+ void OnServerDestroyed(CefRefPtr<CefServer> server) override {
+ EXPECT_TRUE(server->GetTaskRunner()->BelongsToCurrentThread());
+ server_ = nullptr;
+ NotifyServerDestroyed();
+ }
+
+ void OnClientConnected(CefRefPtr<CefServer> server,
+ int connection_id) override {
+ EXPECT_TRUE(server->GetTaskRunner()->BelongsToCurrentThread());
+ EXPECT_TRUE(server->HasConnection());
+ EXPECT_TRUE(server->IsValidConnection(connection_id));
+ }
+
+ void OnClientDisconnected(CefRefPtr<CefServer> server,
+ int connection_id) override {
+ EXPECT_TRUE(server->GetTaskRunner()->BelongsToCurrentThread());
+ EXPECT_FALSE(server->IsValidConnection(connection_id));
+ }
+
+ void OnHttpRequest(CefRefPtr<CefServer> server,
+ int connection_id,
+ const CefString& client_address,
+ CefRefPtr<CefRequest> request) override {
+ EXPECT_TRUE(server->GetTaskRunner()->BelongsToCurrentThread());
+ NotifyTestServerRequest(server, connection_id, client_address, request);
+ }
+
+ void OnWebSocketRequest(CefRefPtr<CefServer> server,
+ int connection_id,
+ const CefString& client_address,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefCallback> callback) override {}
+ void OnWebSocketConnected(CefRefPtr<CefServer> server,
+ int connection_id) override {}
+ void OnWebSocketMessage(CefRefPtr<CefServer> server,
+ int connection_id,
+ const void* data,
+ size_t data_size) override {}
+
+ private:
+ void NotifyServerCreated(const std::string& server_origin) {
+ if (!CefCurrentlyOn(TID_UI)) {
+ CefPostTask(TID_UI, base::BindOnce(&ServerHandler::NotifyServerCreated,
+ this, server_origin));
+ return;
+ }
+
+ delegate_->OnServerCreated(server_origin);
+ }
+
+ void NotifyServerDestroyed() {
+ if (!CefCurrentlyOn(TID_UI)) {
+ CefPostTask(TID_UI,
+ base::BindOnce(&ServerHandler::NotifyServerDestroyed, this));
+ return;
+ }
+
+ delegate_->OnServerDestroyed();
+ }
+
+ void NotifyTestServerRequest(CefRefPtr<CefServer> server,
+ int connection_id,
+ const CefString& client_address,
+ CefRefPtr<CefRequest> request) {
+ if (!CefCurrentlyOn(TID_UI)) {
+ CefPostTask(TID_UI, base::BindOnce(
+ &ServerHandler::NotifyTestServerRequest, this,
+ server, connection_id, client_address, request));
+ return;
+ }
+
+ auto response_callback = base::BindRepeating(&ServerHandler::SendResponse,
+ server, connection_id);
+ delegate_->OnTestServerRequest(request, response_callback);
+ }
+
+ static void SendResponse(CefRefPtr<CefServer> server,
+ int connection_id,
+ CefRefPtr<CefResponse> response,
+ const std::string& response_data) {
+ // Execute on the server thread because some methods require it.
+ CefRefPtr<CefTaskRunner> task_runner = server->GetTaskRunner();
+ if (!task_runner->BelongsToCurrentThread()) {
+ task_runner->PostTask(CefCreateClosureTask(
+ base::BindOnce(ServerHandler::SendResponse, server, connection_id,
+ response, response_data)));
+ return;
+ }
+
+ // No response should be sent yet.
+ EXPECT_TRUE(server->IsValidConnection(connection_id));
+
+ const int response_code = response->GetStatus();
+ if (response_code <= 0) {
+ // Intentionally not responding for incomplete request tests.
+ return;
+ }
+
+ const CefString& content_type = response->GetMimeType();
+ int64 content_length = static_cast<int64>(response_data.size());
+
+ CefResponse::HeaderMap extra_headers;
+ response->GetHeaderMap(extra_headers);
+
+ server->SendHttpResponse(connection_id, response_code, content_type,
+ content_length, extra_headers);
+
+ if (response_data == kIncompleteDoNotSendData) {
+ // Intentionally not sending data for incomplete request tests.
+ return;
+ }
+
+ if (content_length != 0) {
+ server->SendRawData(connection_id, response_data.data(),
+ response_data.size());
+ server->CloseConnection(connection_id);
+ }
+
+ // The connection should be closed.
+ EXPECT_FALSE(server->IsValidConnection(connection_id));
+ }
+
+ Runner::Delegate* const delegate_;
+ CefRefPtr<CefServer> server_;
+
+ IMPLEMENT_REFCOUNTING(ServerHandler);
+ DISALLOW_COPY_AND_ASSIGN(ServerHandler);
+};
+
+class ServerRunner : public Runner {
+ public:
+ explicit ServerRunner(Delegate* delegate) : Runner(delegate) {}
+
+ void StartServer() override {
+ CEF_REQUIRE_UI_THREAD();
+ DCHECK(!handler_);
+ handler_ = new ServerHandler(delegate_);
+ CefServer::CreateServer(kHttpServerAddress, kHttpServerPort,
+ kHttpServerBacklog, handler_);
+ }
+
+ void ShutdownServer() override {
+ CEF_REQUIRE_UI_THREAD();
+ DCHECK(handler_);
+ handler_->Shutdown();
+ handler_ = nullptr;
+ }
+
+ private:
+ CefRefPtr<ServerHandler> handler_;
+};
+
+} // namespace
+
+std::unique_ptr<Runner> Runner::CreateNormal(Delegate* delegate) {
+ return std::make_unique<ServerRunner>(delegate);
+}
+
+} // namespace test_server
diff --git a/tests/ceftests/test_server_runner_test.cc b/tests/ceftests/test_server_runner_test.cc
new file mode 100644
index 00000000..b8022969
--- /dev/null
+++ b/tests/ceftests/test_server_runner_test.cc
@@ -0,0 +1,155 @@
+// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/ceftests/test_server_runner.h"
+
+#include "include/test/cef_test_server.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "include/wrapper/cef_helpers.h"
+#include "tests/gtest/include/gtest/gtest.h"
+
+namespace test_server {
+
+namespace {
+
+// Created on the UI thread and called on the dedicated server thread.
+class ServerHandler : public CefTestServerHandler {
+ public:
+ ServerHandler(Runner::Delegate* delegate, bool https_server)
+ : delegate_(delegate), https_server_(https_server) {}
+
+ ~ServerHandler() override {
+ CEF_REQUIRE_UI_THREAD();
+
+ EXPECT_FALSE(server_);
+ delegate_->OnServerHandlerDeleted();
+ }
+
+ void Start() {
+ CEF_REQUIRE_UI_THREAD();
+
+ // Use any available port number for HTTPS and the legacy port number for
+ // HTTP.
+ const uint16 port = https_server_ ? 0 : kHttpServerPort;
+
+ // Use a "localhost" domain certificate instead of IP address. This is
+ // required for HSTS tests (see https://crbug.com/456712).
+ const auto cert_type = CEF_TEST_CERT_OK_DOMAIN;
+
+ server_ =
+ CefTestServer::CreateAndStart(port, https_server_, cert_type, this);
+
+ // Always execute asynchronously.
+ CefPostTask(TID_UI, base::BindOnce(&ServerHandler::NotifyServerCreated,
+ this, server_->GetOrigin()));
+ }
+
+ void Shutdown() {
+ CEF_REQUIRE_UI_THREAD();
+
+ server_->Stop();
+ server_ = nullptr;
+
+ // Always execute asynchronously.
+ CefPostTask(TID_UI,
+ base::BindOnce(&ServerHandler::NotifyServerDestroyed, this));
+ }
+
+ bool OnTestServerRequest(
+ CefRefPtr<CefTestServer> server,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefTestServerConnection> connection) override {
+ NotifyTestServerRequest(request, connection);
+ return true;
+ }
+
+ private:
+ void NotifyServerCreated(const std::string& server_origin) {
+ CEF_REQUIRE_UI_THREAD();
+ delegate_->OnServerCreated(server_origin);
+ }
+
+ void NotifyServerDestroyed() {
+ CEF_REQUIRE_UI_THREAD();
+ delegate_->OnServerDestroyed();
+ }
+
+ void NotifyTestServerRequest(CefRefPtr<CefRequest> request,
+ CefRefPtr<CefTestServerConnection> connection) {
+ if (!CefCurrentlyOn(TID_UI)) {
+ CefPostTask(TID_UI,
+ base::BindOnce(&ServerHandler::NotifyTestServerRequest, this,
+ request, connection));
+ return;
+ }
+
+ auto response_callback =
+ base::BindRepeating(&ServerHandler::SendResponse, connection);
+ delegate_->OnTestServerRequest(request, response_callback);
+ }
+
+ static void SendResponse(CefRefPtr<CefTestServerConnection> connection,
+ CefRefPtr<CefResponse> response,
+ const std::string& response_data) {
+ const int response_code = response->GetStatus();
+ if (response_code <= 0) {
+ // Intentionally not responding for incomplete request tests.
+ return;
+ }
+
+ // Incomplete response data is not supported.
+ EXPECT_NE(kIncompleteDoNotSendData, response_data.c_str());
+
+ const CefString& content_type = response->GetMimeType();
+ EXPECT_TRUE(!content_type.empty());
+
+ CefResponse::HeaderMap extra_headers;
+ response->GetHeaderMap(extra_headers);
+
+ connection->SendHttpResponse(response_code, content_type,
+ response_data.c_str(), response_data.size(),
+ extra_headers);
+ }
+
+ Runner::Delegate* const delegate_;
+ const bool https_server_;
+
+ CefRefPtr<CefTestServer> server_;
+
+ IMPLEMENT_REFCOUNTING(ServerHandler);
+ DISALLOW_COPY_AND_ASSIGN(ServerHandler);
+};
+
+class ServerRunner : public Runner {
+ public:
+ ServerRunner(Delegate* delegate, bool https_server)
+ : Runner(delegate), https_server_(https_server) {}
+
+ void StartServer() override {
+ CEF_REQUIRE_UI_THREAD();
+ DCHECK(!handler_);
+ handler_ = new ServerHandler(delegate_, https_server_);
+ handler_->Start();
+ }
+
+ void ShutdownServer() override {
+ CEF_REQUIRE_UI_THREAD();
+ DCHECK(handler_);
+ handler_->Shutdown();
+ handler_ = nullptr;
+ }
+
+ private:
+ const bool https_server_;
+ CefRefPtr<ServerHandler> handler_;
+};
+
+} // namespace
+
+std::unique_ptr<Runner> Runner::CreateTest(Delegate* delegate,
+ bool https_server) {
+ return std::make_unique<ServerRunner>(delegate, https_server);
+}
+
+} // namespace test_server
diff --git a/tests/ceftests/test_server_unittest.cc b/tests/ceftests/test_server_unittest.cc
new file mode 100644
index 00000000..d81a5151
--- /dev/null
+++ b/tests/ceftests/test_server_unittest.cc
@@ -0,0 +1,977 @@
+// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include <list>
+#include <map>
+#include <memory>
+#include <set>
+
+#include "include/base/cef_callback.h"
+#include "include/base/cef_ref_counted.h"
+#include "include/cef_command_line.h"
+#include "include/cef_task.h"
+#include "include/cef_urlrequest.h"
+#include "include/test/cef_test_server.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "tests/ceftests/routing_test_handler.h"
+#include "tests/ceftests/test_util.h"
+#include "tests/gtest/include/gtest/gtest.h"
+
+namespace {
+
+const char kPlaceholderOrigin[] = "http://placeholder/";
+const int kTestTimeout = 5000;
+
+// Handles the test server. Used for both HTTP and HTTPS tests.
+class TestServerHandler : public CefTestServerHandler {
+ public:
+ // HTTP test handler.
+ // The methods of this class are always executed on the server thread.
+ class HttpRequestHandler {
+ public:
+ virtual ~HttpRequestHandler() {}
+ virtual bool HandleRequest(
+ CefRefPtr<CefTestServer> server,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefTestServerConnection> connection) = 0;
+ virtual bool VerifyResults() = 0;
+ virtual std::string ToString() = 0;
+ };
+
+ using StartCallback =
+ base::OnceCallback<void(const std::string& server_origin)>;
+
+ // |start_callback| will be executed on the UI thread after the server is
+ // started.
+ // |destroy_callback| will be executed on the UI thread after this handler
+ // object is destroyed.
+ TestServerHandler(StartCallback start_callback,
+ base::OnceClosure destroy_callback)
+ : initialized_(false),
+ start_callback_(std::move(start_callback)),
+ destroy_callback_(std::move(destroy_callback)),
+ expected_http_request_ct_(0),
+ actual_http_request_ct_(0) {
+ EXPECT_FALSE(destroy_callback_.is_null());
+ }
+
+ virtual ~TestServerHandler() {
+ EXPECT_UI_THREAD();
+ std::move(destroy_callback_).Run();
+ }
+
+ // Must be called before CreateServer().
+ void AddHttpRequestHandler(
+ std::unique_ptr<HttpRequestHandler> request_handler) {
+ EXPECT_FALSE(initialized_);
+ EXPECT_TRUE(request_handler);
+ http_request_handler_list_.push_back(std::move(request_handler));
+ }
+
+ // Must be called before CreateServer().
+ void SetExpectedHttpRequestCount(int expected) {
+ EXPECT_FALSE(initialized_);
+ expected_http_request_ct_ = expected;
+ }
+
+ void CreateServer(bool https_server) {
+ EXPECT_FALSE(initialized_);
+ initialized_ = true;
+ https_server_ = https_server;
+
+ // Blocks until the server is created.
+ server_ = CefTestServer::CreateAndStart(/*port=*/0, https_server,
+ CEF_TEST_CERT_OK_DOMAIN, this);
+
+ origin_ = server_->GetOrigin();
+ EXPECT_TRUE(VerifyOrigin(origin_));
+
+ RunStartCallback();
+ }
+
+ // Results in a call to VerifyResults() and eventual execution of the
+ // |destroy_callback|.
+ void ShutdownServer() {
+ EXPECT_TRUE(server_);
+ server_->Stop();
+ server_ = nullptr;
+ VerifyResults();
+ }
+
+ bool OnTestServerRequest(
+ CefRefPtr<CefTestServer> server,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefTestServerConnection> connection) override {
+ EXPECT_TRUE(server);
+ EXPECT_STREQ(origin_.c_str(), server->GetOrigin().ToString().c_str());
+
+ EXPECT_TRUE(request);
+ EXPECT_TRUE(VerifyRequest(request));
+
+ EXPECT_TRUE(connection);
+
+ bool handled = false;
+ for (const auto& handler : http_request_handler_list_) {
+ handled = handler->HandleRequest(server, request, connection);
+ if (handled) {
+ break;
+ }
+ }
+ EXPECT_TRUE(handled) << "missing HttpRequestHandler for "
+ << request->GetURL().ToString();
+
+ actual_http_request_ct_++;
+
+ return handled;
+ }
+
+ private:
+ bool VerifyOrigin(const std::string& origin) const {
+ V_DECLARE();
+ V_EXPECT_TRUE(origin.find(https_server_ ? "https://" : "http://") == 0)
+ << "origin " << origin_;
+ V_RETURN();
+ }
+
+ bool VerifyRequest(CefRefPtr<CefRequest> request) const {
+ V_DECLARE();
+
+ V_EXPECT_FALSE(request->GetMethod().empty());
+
+ const std::string& url = request->GetURL();
+ V_EXPECT_FALSE(url.empty());
+ V_EXPECT_TRUE(VerifyOrigin(url)) << "url " << url;
+
+ CefRefPtr<CefPostData> post_data = request->GetPostData();
+ if (post_data) {
+ CefPostData::ElementVector elements;
+ post_data->GetElements(elements);
+ V_EXPECT_TRUE(elements.size() == 1);
+ V_EXPECT_TRUE(elements[0]->GetBytesCount() > 0U);
+ }
+
+ V_RETURN();
+ }
+
+ void VerifyResults() const {
+ EXPECT_EQ(expected_http_request_ct_, actual_http_request_ct_);
+
+ for (const auto& handler : http_request_handler_list_) {
+ EXPECT_TRUE(handler->VerifyResults())
+ << "HttpRequestHandler for " << handler->ToString();
+ }
+ }
+
+ private:
+ void RunStartCallback() {
+ if (!CefCurrentlyOn(TID_UI)) {
+ CefPostTask(TID_UI,
+ base::BindOnce(&TestServerHandler::RunStartCallback, this));
+ return;
+ }
+
+ EXPECT_FALSE(start_callback_.is_null());
+ std::move(start_callback_).Run(server_->GetOrigin());
+ }
+
+ CefRefPtr<CefTestServer> server_;
+ bool initialized_;
+
+ // After initialization only accessed on the UI thread.
+ StartCallback start_callback_;
+ base::OnceClosure destroy_callback_;
+
+ bool https_server_ = false;
+ std::string origin_;
+
+ // After initialization the below members are only accessed on the server
+ // thread.
+
+ std::list<std::unique_ptr<HttpRequestHandler>> http_request_handler_list_;
+
+ int expected_http_request_ct_;
+ int actual_http_request_ct_;
+
+ IMPLEMENT_REFCOUNTING(TestServerHandler);
+ DISALLOW_COPY_AND_ASSIGN(TestServerHandler);
+};
+
+// HTTP TESTS
+
+// Test runner for 1 or more HTTP requests/responses.
+// Works similarly to TestHandler but without the CefClient dependencies.
+class HttpTestRunner : public base::RefCountedThreadSafe<HttpTestRunner> {
+ public:
+ // The methods of this class are always executed on the UI thread.
+ class RequestRunner {
+ public:
+ virtual ~RequestRunner() {}
+
+ // Create the server-side handler for the request.
+ virtual std::unique_ptr<TestServerHandler::HttpRequestHandler>
+ CreateHttpRequestHandler() = 0;
+
+ // Run the request and execute |complete_callback| on completion.
+ virtual void RunRequest(const std::string& server_origin,
+ base::OnceClosure complete_callback) = 0;
+
+ virtual bool VerifyResults() = 0;
+ virtual std::string ToString() = 0;
+ };
+
+ // If |parallel_requests| is true all requests will be run at the same time,
+ // otherwise one request will be run at a time.
+ HttpTestRunner(bool https_server, bool parallel_requests)
+ : https_server_(https_server), parallel_requests_(parallel_requests) {}
+
+ virtual ~HttpTestRunner() {
+ if (destroy_event_) {
+ destroy_event_->Signal();
+ }
+ }
+
+ void AddRequestRunner(std::unique_ptr<RequestRunner> request_runner) {
+ EXPECT_FALSE(initialized_);
+ request_runner_map_.insert(
+ std::make_pair(++next_request_id_, request_runner.release()));
+ }
+
+ // Blocks until the test has completed or timed out.
+ void ExecuteTest() {
+ EXPECT_FALSE(CefCurrentlyOn(TID_UI));
+
+ handler_ = new TestServerHandler(
+ base::BindOnce(&HttpTestRunner::OnServerStarted, this),
+ base::BindOnce(&HttpTestRunner::OnServerDestroyed, this));
+
+ run_event_ = CefWaitableEvent::CreateWaitableEvent(false, false);
+
+ CefPostTask(TID_UI, base::BindOnce(&HttpTestRunner::RunTest, this));
+
+ // Block until test completion.
+ run_event_->Wait();
+ }
+
+ // Event that will be signaled from the HttpTestRunner destructor.
+ // Used by ReleaseAndWaitForDestructor.
+ void SetDestroyEvent(CefRefPtr<CefWaitableEvent> event) {
+ destroy_event_ = event;
+ }
+
+ private:
+ void RunTest() {
+ EXPECT_UI_THREAD();
+ EXPECT_FALSE(initialized_);
+ initialized_ = true;
+
+ EXPECT_FALSE(request_runner_map_.empty());
+ RequestRunnerMap::const_iterator it = request_runner_map_.begin();
+ for (; it != request_runner_map_.end(); ++it) {
+ handler_->AddHttpRequestHandler(it->second->CreateHttpRequestHandler());
+ }
+
+ handler_->SetExpectedHttpRequestCount(
+ static_cast<int>(request_runner_map_.size()));
+
+ handler_->CreateServer(https_server_);
+
+ SetTestTimeout(kTestTimeout);
+ }
+
+ void OnServerStarted(const std::string& server_origin) {
+ EXPECT_UI_THREAD();
+ server_origin_ = server_origin;
+ if (parallel_requests_) {
+ RunAllRequests();
+ } else {
+ RunNextRequest();
+ }
+ }
+
+ void OnServerDestroyed() {
+ EXPECT_UI_THREAD();
+ EXPECT_FALSE(got_server_destroyed_);
+ got_server_destroyed_.yes();
+
+ // Allow the call stack to unwind.
+ CefPostTask(TID_UI, base::BindOnce(&HttpTestRunner::DestroyTest, this));
+ }
+
+ // Run all requests in parallel.
+ void RunAllRequests() {
+ RequestRunnerMap::const_iterator it = request_runner_map_.begin();
+ for (; it != request_runner_map_.end(); ++it) {
+ it->second->RunRequest(
+ server_origin_,
+ base::BindOnce(&HttpTestRunner::OnRequestComplete, this, it->first));
+ }
+ }
+
+ // Run one request at a time.
+ void RunNextRequest() {
+ RequestRunnerMap::const_iterator it = request_runner_map_.begin();
+ it->second->RunRequest(
+ server_origin_,
+ base::BindOnce(&HttpTestRunner::OnRequestComplete, this, it->first));
+ }
+
+ void OnRequestComplete(int request_id) {
+ EXPECT_UI_THREAD()
+ // Allow the call stack to unwind.
+ CefPostTask(TID_UI,
+ base::BindOnce(&HttpTestRunner::OnRequestCompleteContinue, this,
+ request_id));
+ }
+
+ void OnRequestCompleteContinue(int request_id) {
+ RequestRunnerMap::iterator it = request_runner_map_.find(request_id);
+ EXPECT_TRUE(it != request_runner_map_.end());
+
+ // Verify the request results.
+ EXPECT_TRUE(it->second->VerifyResults())
+ << "request_id " << request_id << " RequestRunner for "
+ << it->second->ToString();
+ delete it->second;
+ request_runner_map_.erase(it);
+
+ if (request_runner_map_.empty()) {
+ got_all_requests_.yes();
+
+ // Will trigger TestServerHandler::HttpRequestHandler verification and a
+ // call to OnServerDestroyed().
+ handler_->ShutdownServer();
+ handler_ = nullptr;
+ } else if (!parallel_requests_) {
+ RunNextRequest();
+ }
+ }
+
+ void DestroyTest() {
+ EXPECT_UI_THREAD();
+
+ EXPECT_TRUE(got_all_requests_);
+ EXPECT_TRUE(got_server_destroyed_);
+ EXPECT_TRUE(request_runner_map_.empty());
+
+ // Cancel the timeout, if any.
+ if (ui_thread_helper_) {
+ ui_thread_helper_.reset();
+ }
+
+ // Signal test completion.
+ run_event_->Signal();
+ }
+
+ TestHandler::UIThreadHelper* GetUIThreadHelper() {
+ EXPECT_UI_THREAD();
+ if (!ui_thread_helper_) {
+ ui_thread_helper_.reset(new TestHandler::UIThreadHelper());
+ }
+ return ui_thread_helper_.get();
+ }
+
+ void SetTestTimeout(int timeout_ms) {
+ EXPECT_UI_THREAD();
+ const auto timeout = GetConfiguredTestTimeout(timeout_ms);
+ if (!timeout) {
+ return;
+ }
+
+ // Use a weak reference to |this| via UIThreadHelper so that the
+ // test runner can be destroyed before the timeout expires.
+ GetUIThreadHelper()->PostDelayedTask(
+ base::BindOnce(&HttpTestRunner::OnTestTimeout, base::Unretained(this),
+ *timeout),
+ *timeout);
+ }
+
+ void OnTestTimeout(int timeout_ms) {
+ EXPECT_UI_THREAD();
+ EXPECT_TRUE(false) << "Test timed out after " << timeout_ms << "ms";
+ DestroyTest();
+ }
+
+ const bool https_server_;
+ const bool parallel_requests_;
+ CefRefPtr<CefWaitableEvent> run_event_;
+ CefRefPtr<CefWaitableEvent> destroy_event_;
+ CefRefPtr<TestServerHandler> handler_;
+ bool initialized_ = false;
+
+ // After initialization the below members are only accessed on the UI thread.
+
+ std::string server_origin_;
+ int next_request_id_ = 0;
+
+ // Map of request ID to RequestRunner.
+ typedef std::map<int, RequestRunner*> RequestRunnerMap;
+ RequestRunnerMap request_runner_map_;
+
+ TrackCallback got_all_requests_;
+ TrackCallback got_server_destroyed_;
+
+ std::unique_ptr<TestHandler::UIThreadHelper> ui_thread_helper_;
+
+ DISALLOW_COPY_AND_ASSIGN(HttpTestRunner);
+};
+
+// Structure representing the data that can be sent via
+// CefServer::SendHttp*Response().
+struct HttpServerResponse {
+ enum Type { TYPE_200, TYPE_404, TYPE_500, TYPE_CUSTOM };
+
+ explicit HttpServerResponse(Type response_type) : type(response_type) {}
+
+ Type type;
+
+ // Used with 200 and CUSTOM response type.
+ std::string content;
+ std::string content_type;
+
+ // Used with 500 response type.
+ std::string error_message;
+
+ // Used with CUSTOM response type.
+ int response_code;
+ CefRequest::HeaderMap extra_headers;
+};
+
+void SendHttpServerResponse(CefRefPtr<CefTestServerConnection> connection,
+ const HttpServerResponse& response) {
+ switch (response.type) {
+ case HttpServerResponse::TYPE_200:
+ EXPECT_TRUE(!response.content_type.empty());
+ connection->SendHttp200Response(response.content_type,
+ response.content.data(),
+ response.content.size());
+ break;
+ case HttpServerResponse::TYPE_404:
+ connection->SendHttp404Response();
+ break;
+ case HttpServerResponse::TYPE_500:
+ connection->SendHttp500Response(response.error_message);
+ break;
+ case HttpServerResponse::TYPE_CUSTOM:
+ EXPECT_TRUE(!response.content_type.empty());
+ connection->SendHttpResponse(
+ response.response_code, response.content_type,
+ response.content.data(), response.content.size(),
+ response.extra_headers);
+ break;
+ }
+}
+
+std::string GetHeaderValue(const CefRequest::HeaderMap& header_map,
+ const std::string& header_name) {
+ CefRequest::HeaderMap::const_iterator it = header_map.find(header_name);
+ if (it != header_map.end()) {
+ return it->second;
+ }
+ return std::string();
+}
+
+void VerifyHttpServerResponse(const HttpServerResponse& expected_response,
+ CefRefPtr<CefResponse> response,
+ const std::string& data) {
+ CefRequest::HeaderMap header_map;
+ response->GetHeaderMap(header_map);
+
+ switch (expected_response.type) {
+ case HttpServerResponse::TYPE_200:
+ EXPECT_EQ(200, response->GetStatus());
+ EXPECT_STREQ(expected_response.content_type.c_str(),
+ GetHeaderValue(header_map, "Content-Type").c_str());
+ EXPECT_STREQ(expected_response.content.c_str(), data.c_str());
+ break;
+ case HttpServerResponse::TYPE_404:
+ EXPECT_EQ(404, response->GetStatus());
+ break;
+ case HttpServerResponse::TYPE_500:
+ EXPECT_EQ(500, response->GetStatus());
+ break;
+ case HttpServerResponse::TYPE_CUSTOM:
+ EXPECT_EQ(expected_response.response_code, response->GetStatus());
+ EXPECT_STREQ(expected_response.content_type.c_str(),
+ GetHeaderValue(header_map, "Content-Type").c_str());
+ EXPECT_EQ(static_cast<int>(expected_response.content.size()),
+ atoi(GetHeaderValue(header_map, "Content-Length").c_str()));
+ EXPECT_STREQ(expected_response.content.c_str(), data.c_str());
+ TestMapEqual(expected_response.extra_headers, header_map, true);
+ break;
+ }
+}
+
+CefRefPtr<CefRequest> CreateTestServerRequest(
+ const std::string& path,
+ const std::string& method,
+ const std::string& data = std::string(),
+ const std::string& content_type = std::string(),
+ const CefRequest::HeaderMap& extra_headers = CefRequest::HeaderMap()) {
+ CefRefPtr<CefRequest> request = CefRequest::Create();
+
+ request->SetURL(kPlaceholderOrigin + path);
+ request->SetMethod(method);
+
+ CefRequest::HeaderMap header_map;
+
+ if (!data.empty()) {
+ CefRefPtr<CefPostData> post_data = CefPostData::Create();
+ CefRefPtr<CefPostDataElement> post_element = CefPostDataElement::Create();
+ post_element->SetToBytes(data.size(), data.data());
+ post_data->AddElement(post_element);
+ request->SetPostData(post_data);
+
+ EXPECT_FALSE(content_type.empty());
+ header_map.insert(std::make_pair("content-type", content_type));
+ }
+
+ if (!extra_headers.empty()) {
+ header_map.insert(extra_headers.begin(), extra_headers.end());
+ }
+ request->SetHeaderMap(header_map);
+
+ return request;
+}
+
+// RequestHandler that returns a static response for 1 or more requests.
+class StaticHttpServerRequestHandler
+ : public TestServerHandler::HttpRequestHandler {
+ public:
+ StaticHttpServerRequestHandler(CefRefPtr<CefRequest> expected_request,
+ int expected_request_ct,
+ const HttpServerResponse& response)
+ : expected_request_(expected_request),
+ expected_request_ct_(expected_request_ct),
+ actual_request_ct_(0),
+ response_(response) {}
+
+ bool HandleRequest(CefRefPtr<CefTestServer> server,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefTestServerConnection> connection) override {
+ if (request->GetURL() == expected_request_->GetURL() &&
+ request->GetMethod() == expected_request_->GetMethod()) {
+ TestRequestEqual(expected_request_, request, true);
+ actual_request_ct_++;
+
+ SendHttpServerResponse(connection, response_);
+ return true;
+ }
+
+ return false;
+ }
+
+ bool VerifyResults() override {
+ EXPECT_EQ(expected_request_ct_, actual_request_ct_);
+ return expected_request_ct_ == actual_request_ct_;
+ }
+
+ std::string ToString() override { return expected_request_->GetURL(); }
+
+ private:
+ CefRefPtr<CefRequest> expected_request_;
+ int expected_request_ct_;
+ int actual_request_ct_;
+ HttpServerResponse response_;
+
+ DISALLOW_COPY_AND_ASSIGN(StaticHttpServerRequestHandler);
+};
+
+// URLRequestClient that runs a single request and executes a callback with the
+// response.
+class StaticHttpURLRequestClient : public CefURLRequestClient {
+ public:
+ using ResponseCallback =
+ base::OnceCallback<void(cef_errorcode_t /* error */,
+ CefRefPtr<CefResponse> /* response */,
+ const std::string& /* data */)>;
+
+ // |response_callback| will be executed on the UI thread when the response
+ // is complete.
+ StaticHttpURLRequestClient(CefRefPtr<CefRequest> request,
+ ResponseCallback response_callback)
+ : request_(request), response_callback_(std::move(response_callback)) {
+ EXPECT_TRUE(request_);
+ EXPECT_FALSE(response_callback_.is_null());
+ }
+
+ void RunRequest() {
+ EXPECT_UI_THREAD();
+ CefURLRequest::Create(request_, this, nullptr);
+ }
+
+ void OnRequestComplete(CefRefPtr<CefURLRequest> request) override {
+ EXPECT_FALSE(response_callback_.is_null());
+ std::move(response_callback_)
+ .Run(request->GetRequestError(), request->GetResponse(), data_);
+ }
+
+ void OnUploadProgress(CefRefPtr<CefURLRequest> request,
+ int64 current,
+ int64 total) override {}
+
+ void OnDownloadProgress(CefRefPtr<CefURLRequest> request,
+ int64 current,
+ int64 total) override {}
+
+ void OnDownloadData(CefRefPtr<CefURLRequest> request,
+ const void* data,
+ size_t data_length) override {
+ data_.append(static_cast<const char*>(data), data_length);
+ }
+
+ bool GetAuthCredentials(bool isProxy,
+ const CefString& host,
+ int port,
+ const CefString& realm,
+ const CefString& scheme,
+ CefRefPtr<CefAuthCallback> callback) override {
+ return false;
+ }
+
+ private:
+ CefRefPtr<CefRequest> request_;
+ ResponseCallback response_callback_;
+ std::string data_;
+
+ IMPLEMENT_REFCOUNTING(StaticHttpURLRequestClient);
+ DISALLOW_COPY_AND_ASSIGN(StaticHttpURLRequestClient);
+};
+
+// RequestRunner that will manage a single static HTTP request/response.
+class StaticHttpRequestRunner : public HttpTestRunner::RequestRunner {
+ public:
+ StaticHttpRequestRunner(CefRefPtr<CefRequest> request,
+ const HttpServerResponse& response)
+ : request_(request), response_(response) {}
+
+ static std::unique_ptr<HttpTestRunner::RequestRunner> Create200(
+ const std::string& path,
+ bool with_content = true) {
+ CefRefPtr<CefRequest> request = CreateTestServerRequest(path, "GET");
+ HttpServerResponse response(HttpServerResponse::TYPE_200);
+ response.content_type = "text/html";
+ if (with_content) {
+ response.content = "<html>200 response content</html>";
+ }
+ return std::make_unique<StaticHttpRequestRunner>(request, response);
+ }
+
+ static std::unique_ptr<HttpTestRunner::RequestRunner> Create404(
+ const std::string& path) {
+ CefRefPtr<CefRequest> request = CreateTestServerRequest(path, "GET");
+ HttpServerResponse response(HttpServerResponse::TYPE_404);
+ return std::make_unique<StaticHttpRequestRunner>(request, response);
+ }
+
+ static std::unique_ptr<HttpTestRunner::RequestRunner> Create500(
+ const std::string& path) {
+ CefRefPtr<CefRequest> request = CreateTestServerRequest(path, "GET");
+ // Don't retry the request.
+ request->SetFlags(UR_FLAG_NO_RETRY_ON_5XX);
+ HttpServerResponse response(HttpServerResponse::TYPE_500);
+ response.error_message = "Something went wrong!";
+ return std::make_unique<StaticHttpRequestRunner>(request, response);
+ }
+
+ static std::unique_ptr<HttpTestRunner::RequestRunner> CreateCustom(
+ const std::string& path,
+ bool with_content = true) {
+ CefRequest::HeaderMap request_headers;
+ request_headers.insert(std::make_pair("x-request-custom1", "My Value A"));
+ request_headers.insert(std::make_pair("x-request-custom2", "My Value B"));
+ CefRefPtr<CefRequest> request = CreateTestServerRequest(
+ path, "POST", "foo=bar&choo=too", "application/x-www-form-urlencoded",
+ request_headers);
+ request->SetReferrer("http://tests/referer.html", REFERRER_POLICY_DEFAULT);
+
+ HttpServerResponse response(HttpServerResponse::TYPE_CUSTOM);
+ response.response_code = 202;
+ if (with_content) {
+ response.content = "BlahBlahBlah";
+ }
+ response.content_type = "application/x-blah-blah";
+ response.extra_headers.insert(
+ std::make_pair("x-response-custom1", "My Value 1"));
+ response.extra_headers.insert(
+ std::make_pair("x-response-custom2", "My Value 2"));
+
+ return std::make_unique<StaticHttpRequestRunner>(request, response);
+ }
+
+ std::unique_ptr<TestServerHandler::HttpRequestHandler>
+ CreateHttpRequestHandler() override {
+ EXPECT_FALSE(got_create_handler_);
+ got_create_handler_.yes();
+ return std::make_unique<StaticHttpServerRequestHandler>(request_, 1,
+ response_);
+ }
+
+ void RunRequest(const std::string& server_origin,
+ base::OnceClosure complete_callback) override {
+ EXPECT_UI_THREAD();
+
+ EXPECT_FALSE(got_run_request_);
+ got_run_request_.yes();
+
+ complete_callback_ = std::move(complete_callback);
+
+ // Replace the placeholder with the actual server origin.
+ const std::string& url = request_->GetURL();
+ EXPECT_TRUE(url.find(kPlaceholderOrigin) == 0);
+ const std::string& real_url =
+ server_origin + "/" + url.substr(sizeof(kPlaceholderOrigin) - 1);
+ request_->SetURL(real_url);
+
+ request_client_ = new StaticHttpURLRequestClient(
+ request_, base::BindOnce(&StaticHttpRequestRunner::OnResponseComplete,
+ base::Unretained(this)));
+ request_client_->RunRequest();
+ }
+
+ bool VerifyResults() override {
+ V_DECLARE();
+ V_EXPECT_TRUE(got_create_handler_);
+ V_EXPECT_TRUE(got_run_request_);
+ V_EXPECT_TRUE(got_response_complete_);
+ V_RETURN();
+ }
+
+ std::string ToString() override { return request_->GetURL(); }
+
+ private:
+ void OnResponseComplete(cef_errorcode_t error,
+ CefRefPtr<CefResponse> response,
+ const std::string& data) {
+ EXPECT_UI_THREAD();
+
+ EXPECT_FALSE(got_response_complete_);
+ got_response_complete_.yes();
+
+ EXPECT_EQ(error, ERR_NONE)
+ << "OnResponseComplete for " << request_->GetURL().ToString();
+ if (error == ERR_NONE) {
+ VerifyHttpServerResponse(response_, response, data);
+ }
+
+ std::move(complete_callback_).Run();
+ }
+
+ CefRefPtr<CefRequest> request_;
+ HttpServerResponse response_;
+
+ CefRefPtr<StaticHttpURLRequestClient> request_client_;
+ base::OnceClosure complete_callback_;
+
+ TrackCallback got_run_request_;
+ TrackCallback got_create_handler_;
+ TrackCallback got_response_complete_;
+
+ DISALLOW_COPY_AND_ASSIGN(StaticHttpRequestRunner);
+};
+
+} // namespace
+
+// Verify handling of a single HTTP 200 request.
+TEST(TestServerTest, HttpSingle200) {
+ CefRefPtr<HttpTestRunner> runner =
+ new HttpTestRunner(/*https_server=*/false, /*parallel_requests=*/false);
+ runner->AddRequestRunner(StaticHttpRequestRunner::Create200("200.html"));
+ runner->ExecuteTest();
+ ReleaseAndWaitForDestructor(runner);
+}
+
+// Verify handling of a single HTTPS 200 request.
+TEST(TestServerTest, HttpsSingle200) {
+ CefRefPtr<HttpTestRunner> runner =
+ new HttpTestRunner(/*https_server=*/true, /*parallel_requests=*/false);
+ runner->AddRequestRunner(StaticHttpRequestRunner::Create200("200.html"));
+ runner->ExecuteTest();
+ ReleaseAndWaitForDestructor(runner);
+}
+
+// Verify handling of a single HTTP 200 request with no content.
+TEST(TestServerTest, HttpSingle200NoContent) {
+ CefRefPtr<HttpTestRunner> runner =
+ new HttpTestRunner(/*https_server=*/false, /*parallel_requests=*/false);
+ runner->AddRequestRunner(
+ StaticHttpRequestRunner::Create200("200.html", false));
+ runner->ExecuteTest();
+ ReleaseAndWaitForDestructor(runner);
+}
+
+// Verify handling of a single HTTPS 200 request with no content.
+TEST(TestServerTest, HttpsSingle200NoContent) {
+ CefRefPtr<HttpTestRunner> runner =
+ new HttpTestRunner(/*https_server=*/true, /*parallel_requests=*/false);
+ runner->AddRequestRunner(
+ StaticHttpRequestRunner::Create200("200.html", false));
+ runner->ExecuteTest();
+ ReleaseAndWaitForDestructor(runner);
+}
+
+// Verify handling of a single HTTP 404 request.
+TEST(TestServerTest, HttpSingle404) {
+ CefRefPtr<HttpTestRunner> runner =
+ new HttpTestRunner(/*https_server=*/false, /*parallel_requests=*/false);
+ runner->AddRequestRunner(StaticHttpRequestRunner::Create404("404.html"));
+ runner->ExecuteTest();
+ ReleaseAndWaitForDestructor(runner);
+}
+
+// Verify handling of a single HTTPS 404 request.
+TEST(TestServerTest, HttpsSingle404) {
+ CefRefPtr<HttpTestRunner> runner =
+ new HttpTestRunner(/*https_server=*/true, /*parallel_requests=*/false);
+ runner->AddRequestRunner(StaticHttpRequestRunner::Create404("404.html"));
+ runner->ExecuteTest();
+ ReleaseAndWaitForDestructor(runner);
+}
+
+// Verify handling of a single HTTP 500 request.
+TEST(TestServerTest, HttpSingle500) {
+ CefRefPtr<HttpTestRunner> runner =
+ new HttpTestRunner(/*https_server=*/false, /*parallel_requests=*/false);
+ runner->AddRequestRunner(StaticHttpRequestRunner::Create500("500.html"));
+ runner->ExecuteTest();
+ ReleaseAndWaitForDestructor(runner);
+}
+
+// Verify handling of a single HTTPS 500 request.
+TEST(TestServerTest, HttpsSingle500) {
+ CefRefPtr<HttpTestRunner> runner =
+ new HttpTestRunner(/*https_server=*/true, /*parallel_requests=*/false);
+ runner->AddRequestRunner(StaticHttpRequestRunner::Create500("500.html"));
+ runner->ExecuteTest();
+ ReleaseAndWaitForDestructor(runner);
+}
+
+// Verify handling of a single HTTP custom request.
+TEST(TestServerTest, HttpSingleCustom) {
+ CefRefPtr<HttpTestRunner> runner =
+ new HttpTestRunner(/*https_server=*/false, /*parallel_requests=*/false);
+ runner->AddRequestRunner(StaticHttpRequestRunner::CreateCustom("202.html"));
+ runner->ExecuteTest();
+ ReleaseAndWaitForDestructor(runner);
+}
+
+// Verify handling of a single HTTP custom request.
+TEST(TestServerTest, HttpsSingleCustom) {
+ CefRefPtr<HttpTestRunner> runner =
+ new HttpTestRunner(/*https_server=*/true, /*parallel_requests=*/false);
+ runner->AddRequestRunner(StaticHttpRequestRunner::CreateCustom("202.html"));
+ runner->ExecuteTest();
+ ReleaseAndWaitForDestructor(runner);
+}
+
+// Verify handling of a single HTTP custom request with no content.
+TEST(TestServerTest, HttpSingleCustomNoContent) {
+ CefRefPtr<HttpTestRunner> runner =
+ new HttpTestRunner(/*https_server=*/false, /*parallel_requests=*/false);
+ runner->AddRequestRunner(StaticHttpRequestRunner::CreateCustom(
+ "202.html", /*with_content=*/false));
+ runner->ExecuteTest();
+ ReleaseAndWaitForDestructor(runner);
+}
+
+// Verify handling of a single HTTPS custom request with no content.
+TEST(TestServerTest, HttpsSingleCustomNoContent) {
+ CefRefPtr<HttpTestRunner> runner =
+ new HttpTestRunner(/*https_server=*/true, /*parallel_requests=*/false);
+ runner->AddRequestRunner(StaticHttpRequestRunner::CreateCustom(
+ "202.html", /*with_content=*/false));
+ runner->ExecuteTest();
+ ReleaseAndWaitForDestructor(runner);
+}
+
+// Verify handling of multiple HTTP requests in parallel.
+TEST(TestServerTest, HttpMultipleParallel200) {
+ CefRefPtr<HttpTestRunner> runner =
+ new HttpTestRunner(/*https_server=*/false, /*parallel_requests=*/true);
+ runner->AddRequestRunner(StaticHttpRequestRunner::Create200("200a.html"));
+ runner->AddRequestRunner(StaticHttpRequestRunner::Create200("200b.html"));
+ runner->AddRequestRunner(StaticHttpRequestRunner::Create200("200c.html"));
+ runner->ExecuteTest();
+ ReleaseAndWaitForDestructor(runner);
+}
+
+// Verify handling of multiple HTTPS requests in parallel.
+TEST(TestServerTest, HttpsMultipleParallel200) {
+ CefRefPtr<HttpTestRunner> runner =
+ new HttpTestRunner(/*https_server=*/true, /*parallel_requests=*/true);
+ runner->AddRequestRunner(StaticHttpRequestRunner::Create200("200a.html"));
+ runner->AddRequestRunner(StaticHttpRequestRunner::Create200("200b.html"));
+ runner->AddRequestRunner(StaticHttpRequestRunner::Create200("200c.html"));
+ runner->ExecuteTest();
+ ReleaseAndWaitForDestructor(runner);
+}
+
+// Verify handling of multiple HTTP requests in serial.
+TEST(TestServerTest, HttpMultipleSerial200) {
+ CefRefPtr<HttpTestRunner> runner =
+ new HttpTestRunner(/*https_server=*/false, /*parallel_requests=*/false);
+ runner->AddRequestRunner(StaticHttpRequestRunner::Create200("200a.html"));
+ runner->AddRequestRunner(StaticHttpRequestRunner::Create200("200b.html"));
+ runner->AddRequestRunner(StaticHttpRequestRunner::Create200("200c.html"));
+ runner->ExecuteTest();
+ ReleaseAndWaitForDestructor(runner);
+}
+
+// Verify handling of multiple HTTPS requests in serial.
+TEST(TestServerTest, HttpsMultipleSerial200) {
+ CefRefPtr<HttpTestRunner> runner =
+ new HttpTestRunner(/*https_server=*/true, /*parallel_requests=*/false);
+ runner->AddRequestRunner(StaticHttpRequestRunner::Create200("200a.html"));
+ runner->AddRequestRunner(StaticHttpRequestRunner::Create200("200b.html"));
+ runner->AddRequestRunner(StaticHttpRequestRunner::Create200("200c.html"));
+ runner->ExecuteTest();
+ ReleaseAndWaitForDestructor(runner);
+}
+
+// Verify handling of multiple HTTP requests in parallel.
+TEST(TestServerTest, HttpMultipleParallelMixed) {
+ CefRefPtr<HttpTestRunner> runner =
+ new HttpTestRunner(/*https_server=*/false, /*parallel_requests=*/true);
+ runner->AddRequestRunner(StaticHttpRequestRunner::Create200("200.html"));
+ runner->AddRequestRunner(StaticHttpRequestRunner::Create404("404.html"));
+ runner->AddRequestRunner(StaticHttpRequestRunner::Create500("500.html"));
+ runner->AddRequestRunner(StaticHttpRequestRunner::CreateCustom("202.html"));
+ runner->ExecuteTest();
+ ReleaseAndWaitForDestructor(runner);
+}
+
+// Verify handling of multiple HTTPS requests in parallel.
+TEST(TestServerTest, HttpsMultipleParallelMixed) {
+ CefRefPtr<HttpTestRunner> runner =
+ new HttpTestRunner(/*https_server=*/true, /*parallel_requests=*/true);
+ runner->AddRequestRunner(StaticHttpRequestRunner::Create200("200.html"));
+ runner->AddRequestRunner(StaticHttpRequestRunner::Create404("404.html"));
+ runner->AddRequestRunner(StaticHttpRequestRunner::Create500("500.html"));
+ runner->AddRequestRunner(StaticHttpRequestRunner::CreateCustom("202.html"));
+ runner->ExecuteTest();
+ ReleaseAndWaitForDestructor(runner);
+}
+
+// Verify handling of multiple HTTP requests in serial.
+TEST(TestServerTest, HttpMultipleSerialMixed) {
+ CefRefPtr<HttpTestRunner> runner =
+ new HttpTestRunner(/*https_server=*/false, /*parallel_requests=*/false);
+ runner->AddRequestRunner(StaticHttpRequestRunner::Create200("200.html"));
+ runner->AddRequestRunner(StaticHttpRequestRunner::Create404("404.html"));
+ runner->AddRequestRunner(StaticHttpRequestRunner::Create500("500.html"));
+ runner->AddRequestRunner(StaticHttpRequestRunner::CreateCustom("202.html"));
+ runner->ExecuteTest();
+ ReleaseAndWaitForDestructor(runner);
+}
+
+// Verify handling of multiple HTTPS requests in serial.
+TEST(TestServerTest, HttpsMultipleSerialMixed) {
+ CefRefPtr<HttpTestRunner> runner =
+ new HttpTestRunner(/*https_server=*/true, /*parallel_requests=*/false);
+ runner->AddRequestRunner(StaticHttpRequestRunner::Create200("200.html"));
+ runner->AddRequestRunner(StaticHttpRequestRunner::Create404("404.html"));
+ runner->AddRequestRunner(StaticHttpRequestRunner::Create500("500.html"));
+ runner->AddRequestRunner(StaticHttpRequestRunner::CreateCustom("202.html"));
+ runner->ExecuteTest();
+ ReleaseAndWaitForDestructor(runner);
+}
diff --git a/tests/ceftests/test_suite.cc b/tests/ceftests/test_suite.cc
new file mode 100644
index 00000000..d7cf1b4d
--- /dev/null
+++ b/tests/ceftests/test_suite.cc
@@ -0,0 +1,222 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. Postions copyright
+// 2012 The Chromium Authors. All rights reserved. Use of this source code is
+// governed by a BSD-style license that can be found in the LICENSE file.
+
+#include "tests/ceftests/test_suite.h"
+
+#include "include/base/cef_logging.h"
+#include "include/cef_file_util.h"
+#include "include/test/cef_test_helpers.h"
+#include "include/wrapper/cef_scoped_temp_dir.h"
+#include "tests/gtest/include/gtest/gtest.h"
+#include "tests/gtest/teamcity/include/teamcity_gtest.h"
+#include "tests/shared/browser/resource_util.h"
+#include "tests/shared/common/client_switches.h"
+
+namespace {
+
+CefTestSuite* g_test_suite = nullptr;
+
+#if defined(OS_WIN)
+
+// From base/process/launch_win.cc.
+void RouteStdioToConsole(bool create_console_if_not_found) {
+ // Don't change anything if stdout or stderr already point to a
+ // valid stream.
+ //
+ // If we are running under Buildbot or under Cygwin's default
+ // terminal (mintty), stderr and stderr will be pipe handles. In
+ // that case, we don't want to open CONOUT$, because its output
+ // likely does not go anywhere.
+ //
+ // We don't use GetStdHandle() to check stdout/stderr here because
+ // it can return dangling IDs of handles that were never inherited
+ // by this process. These IDs could have been reused by the time
+ // this function is called. The CRT checks the validity of
+ // stdout/stderr on startup (before the handle IDs can be reused).
+ // _fileno(stdout) will return -2 (_NO_CONSOLE_FILENO) if stdout was
+ // invalid.
+ if (_fileno(stdout) >= 0 || _fileno(stderr) >= 0) {
+ return;
+ }
+
+ if (!AttachConsole(ATTACH_PARENT_PROCESS)) {
+ unsigned int result = GetLastError();
+ // Was probably already attached.
+ if (result == ERROR_ACCESS_DENIED) {
+ return;
+ }
+ // Don't bother creating a new console for each child process if the
+ // parent process is invalid (eg: crashed).
+ if (result == ERROR_GEN_FAILURE) {
+ return;
+ }
+ if (create_console_if_not_found) {
+ // Make a new console if attaching to parent fails with any other error.
+ // It should be ERROR_INVALID_HANDLE at this point, which means the
+ // browser was likely not started from a console.
+ AllocConsole();
+ } else {
+ return;
+ }
+ }
+
+ // Arbitrary byte count to use when buffering output lines. More
+ // means potential waste, less means more risk of interleaved
+ // log-lines in output.
+ enum { kOutputBufferSize = 64 * 1024 };
+
+ if (freopen("CONOUT$", "w", stdout)) {
+ setvbuf(stdout, nullptr, _IOLBF, kOutputBufferSize);
+ // Overwrite FD 1 for the benefit of any code that uses this FD
+ // directly. This is safe because the CRT allocates FDs 0, 1 and
+ // 2 at startup even if they don't have valid underlying Windows
+ // handles. This means we won't be overwriting an FD created by
+ // _open() after startup.
+ _dup2(_fileno(stdout), 1);
+ }
+ if (freopen("CONOUT$", "w", stderr)) {
+ setvbuf(stderr, nullptr, _IOLBF, kOutputBufferSize);
+ _dup2(_fileno(stderr), 2);
+ }
+
+ // Fix all cout, wcout, cin, wcin, cerr, wcerr, clog and wclog.
+ std::ios::sync_with_stdio();
+}
+
+#endif // defined(OS_WIN)
+
+} // namespace
+
+CefTestSuite::CefTestSuite(int argc, char** argv)
+ : argc_(argc), argv_(argc, argv), retval_(0) {
+ g_test_suite = this;
+
+ // Keep a representation of the original command-line.
+ command_line_ = CefCommandLine::CreateCommandLine();
+#if defined(OS_WIN)
+ command_line_->InitFromString(::GetCommandLineW());
+#else
+ command_line_->InitFromArgv(argc, argv);
+#endif
+
+ if (!command_line_->HasSwitch("type")) {
+ // Initialize in the main process only.
+ root_cache_path_ =
+ command_line_->GetSwitchValue(client::switches::kCachePath);
+ if (root_cache_path_.empty()) {
+ CefScopedTempDir temp_dir;
+ CHECK(temp_dir.CreateUniqueTempDir());
+ root_cache_path_ = temp_dir.Take();
+ RegisterTempDirectory(root_cache_path_);
+ }
+ }
+}
+
+CefTestSuite::~CefTestSuite() {
+ g_test_suite = nullptr;
+}
+
+// static
+CefTestSuite* CefTestSuite::GetInstance() {
+ return g_test_suite;
+}
+
+void CefTestSuite::InitMainProcess() {
+ PreInitialize();
+
+ // This will modify |argc_| and |argv_|.
+ testing::InitGoogleTest(&argc_, argv_.array());
+
+ if (jetbrains::teamcity::underTeamcity()) {
+ auto& listeners = ::testing::UnitTest::GetInstance()->listeners();
+ listeners.Append(
+ new jetbrains::teamcity::TeamcityGoogleTestEventListener());
+ }
+}
+
+// Don't add additional code to this method. Instead add it to Initialize().
+int CefTestSuite::Run() {
+ Initialize();
+ retval_ = RUN_ALL_TESTS();
+ Shutdown();
+ return retval_;
+}
+
+void CefTestSuite::GetSettings(CefSettings& settings) const {
+ // Enable the experimental Chrome runtime. See issue #2969 for details.
+ settings.chrome_runtime =
+ command_line_->HasSwitch(client::switches::kEnableChromeRuntime);
+
+ CefString(&settings.cache_path) = root_cache_path_;
+ CefString(&settings.root_cache_path) = root_cache_path_;
+ CefString(&settings.user_data_path) = root_cache_path_;
+
+ // Always expose the V8 gc() function to give tests finer-grained control over
+ // memory management.
+ std::string javascript_flags = "--expose-gc";
+ // Value of kJavascriptFlags switch.
+ std::string other_javascript_flags =
+ command_line_->GetSwitchValue("js-flags");
+ if (!other_javascript_flags.empty()) {
+ javascript_flags += " " + other_javascript_flags;
+ }
+ CefString(&settings.javascript_flags) = javascript_flags;
+
+ // Necessary for V8Test.OnUncaughtException tests.
+ settings.uncaught_exception_stack_size = 10;
+
+ // Necessary for the OSRTest tests.
+ settings.windowless_rendering_enabled = true;
+
+ // For Accept-Language test
+ CefString(&settings.accept_language_list) = CEF_SETTINGS_ACCEPT_LANGUAGE;
+}
+
+void CefTestSuite::RegisterTempDirectory(const CefString& directory) {
+ base::AutoLock lock_scope(temp_directories_lock_);
+ temp_directories_.push_back(directory);
+}
+
+void CefTestSuite::DeleteTempDirectories() {
+ base::AutoLock lock_scope(temp_directories_lock_);
+ for (size_t i = 0U; i < temp_directories_.size(); ++i) {
+ CefDeleteFile(temp_directories_[i], true);
+ }
+ temp_directories_.clear();
+}
+
+void CefTestSuite::PreInitialize() {
+#if defined(OS_WIN)
+ testing::GTEST_FLAG(catch_exceptions) = false;
+
+ // Enable termination on heap corruption.
+ // Ignore the result code. Supported starting with XP SP3 and Vista.
+ HeapSetInformation(nullptr, HeapEnableTerminationOnCorruption, nullptr, 0);
+#endif
+
+#if defined(OS_LINUX)
+ // When calling native char conversion functions (e.g wrctomb) we need to
+ // have the locale set. In the absence of such a call the "C" locale is the
+ // default. In the gtk code (below) gtk_init() implicitly sets a locale.
+ setlocale(LC_ALL, "");
+#endif // defined(OS_LINUX)
+
+ // Don't add additional code to this function. Instead add it to Initialize().
+}
+
+void CefTestSuite::Initialize() {
+#if defined(OS_WIN)
+ RouteStdioToConsole(true);
+#endif // defined(OS_WIN)
+
+#if !defined(CEF_TESTS_IN_SRC_DIRECTORY)
+ // Configure the directory that contains test data resources.
+ std::string resource_dir;
+ bool result = client::GetResourceDir(resource_dir);
+ CHECK(result && !resource_dir.empty());
+ CefSetDataDirectoryForTests(resource_dir);
+#endif // !defined(CEF_TESTS_IN_SRC_DIRECTORY)
+}
+
+void CefTestSuite::Shutdown() {}
diff --git a/tests/ceftests/test_suite.h b/tests/ceftests/test_suite.h
new file mode 100644
index 00000000..ccae2d90
--- /dev/null
+++ b/tests/ceftests/test_suite.h
@@ -0,0 +1,60 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. Postions copyright
+// 2012 The Chromium Authors. All rights reserved. Use of this source code is
+// governed by a BSD-style license that can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFTESTS_TEST_SUITE_H_
+#define CEF_TESTS_CEFTESTS_TEST_SUITE_H_
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include "include/cef_command_line.h"
+#include "include/wrapper/cef_helpers.h"
+
+// A single instance of this object will be created by main() in
+// run_all_unittests.cc.
+class CefTestSuite {
+ public:
+ CefTestSuite(int argc, char** argv);
+ ~CefTestSuite();
+
+ static CefTestSuite* GetInstance();
+
+ void InitMainProcess();
+ int Run();
+
+ void GetSettings(CefSettings& settings) const;
+
+ // Register a temp directory that should be deleted on shutdown.
+ void RegisterTempDirectory(const CefString& directory);
+
+ // Called after shutdown to delete any registered temp directories.
+ void DeleteTempDirectories();
+
+ CefRefPtr<CefCommandLine> command_line() const { return command_line_; }
+ CefString root_cache_path() const { return root_cache_path_; }
+
+ // The return value from Run().
+ int retval() const { return retval_; }
+
+ private:
+ void PreInitialize();
+ void Initialize();
+ void Shutdown();
+
+ int argc_;
+ CefScopedArgArray argv_;
+ CefRefPtr<CefCommandLine> command_line_;
+
+ std::vector<CefString> temp_directories_;
+ base::Lock temp_directories_lock_;
+
+ CefString root_cache_path_;
+
+ int retval_;
+};
+
+#define CEF_SETTINGS_ACCEPT_LANGUAGE "en-GB"
+
+#endif // CEF_TESTS_CEFTESTS_TEST_SUITE_H_
diff --git a/tests/ceftests/test_util.cc b/tests/ceftests/test_util.cc
new file mode 100644
index 00000000..4ec7c58d
--- /dev/null
+++ b/tests/ceftests/test_util.cc
@@ -0,0 +1,414 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/ceftests/test_util.h"
+
+#include <algorithm>
+#include <cmath>
+#include <cstdlib>
+
+#include "include/base/cef_callback.h"
+#include "include/cef_base.h"
+#include "include/cef_command_line.h"
+#include "include/cef_request_context_handler.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "tests/gtest/include/gtest/gtest.h"
+#include "tests/shared/common/string_util.h"
+
+void TestMapEqual(const CefRequest::HeaderMap& map1,
+ const CefRequest::HeaderMap& map2,
+ bool allowExtras) {
+ if (!allowExtras) {
+ EXPECT_EQ(map1.size(), map2.size());
+ }
+
+ TestMapNoDuplicates(map1);
+ TestMapNoDuplicates(map2);
+
+ CefRequest::HeaderMap::const_iterator it1, it2;
+
+ for (it1 = map1.begin(); it1 != map1.end(); ++it1) {
+ bool found = false;
+ std::string name1 = client::AsciiStrToLower(it1->first);
+ for (it2 = map2.begin(); it2 != map2.end(); ++it2) {
+ std::string name2 = client::AsciiStrToLower(it2->first);
+ if (name1 == name2 && it1->second == it2->second) {
+ found = true;
+ break;
+ }
+ }
+ EXPECT_TRUE(found) << "No entry for " << it1->first.ToString() << ": "
+ << it1->second.ToString();
+ }
+}
+
+void TestMapNoDuplicates(const CefRequest::HeaderMap& map) {
+ CefRequest::HeaderMap::const_iterator it1 = map.begin();
+ for (; it1 != map.end(); ++it1) {
+ CefRequest::HeaderMap::const_iterator it2 = it1;
+ for (++it2; it2 != map.end(); ++it2) {
+ EXPECT_FALSE(it1->first == it2->first && it1->second == it2->second)
+ << "Duplicate entry for " << it1->first.ToString() << ": "
+ << it1->second.ToString();
+ }
+ }
+}
+
+void TestPostDataElementEqual(CefRefPtr<CefPostDataElement> elem1,
+ CefRefPtr<CefPostDataElement> elem2) {
+ EXPECT_TRUE(elem1.get());
+ EXPECT_TRUE(elem2.get());
+
+ EXPECT_EQ(elem1->GetType(), elem2->GetType());
+ switch (elem1->GetType()) {
+ case PDE_TYPE_BYTES: {
+ EXPECT_EQ(elem1->GetBytesCount(), elem2->GetBytesCount());
+ size_t bytesCt = elem1->GetBytesCount();
+ char* buff1 = new char[bytesCt];
+ char* buff2 = new char[bytesCt];
+ elem1->GetBytes(bytesCt, buff1);
+ elem2->GetBytes(bytesCt, buff2);
+ EXPECT_TRUE(!memcmp(buff1, buff2, bytesCt));
+ delete[] buff1;
+ delete[] buff2;
+ } break;
+ case PDE_TYPE_FILE:
+ EXPECT_EQ(elem1->GetFile(), elem2->GetFile());
+ break;
+ default:
+ break;
+ }
+}
+
+void TestPostDataEqual(CefRefPtr<CefPostData> postData1,
+ CefRefPtr<CefPostData> postData2) {
+ EXPECT_TRUE(postData1.get());
+ EXPECT_TRUE(postData2.get());
+
+ EXPECT_EQ(postData1->GetElementCount(), postData2->GetElementCount());
+
+ CefPostData::ElementVector ev1, ev2;
+ postData1->GetElements(ev1);
+ postData1->GetElements(ev2);
+ ASSERT_EQ(ev1.size(), ev2.size());
+
+ CefPostData::ElementVector::const_iterator it1 = ev1.begin();
+ CefPostData::ElementVector::const_iterator it2 = ev2.begin();
+ for (; it1 != ev1.end() && it2 != ev2.end(); ++it1, ++it2) {
+ TestPostDataElementEqual((*it1), (*it2));
+ }
+}
+
+void TestRequestEqual(CefRefPtr<CefRequest> request1,
+ CefRefPtr<CefRequest> request2,
+ bool allowExtras) {
+ EXPECT_TRUE(request1.get());
+ EXPECT_TRUE(request2.get());
+
+ EXPECT_STREQ(request1->GetURL().ToString().c_str(),
+ request2->GetURL().ToString().c_str());
+ EXPECT_STREQ(request1->GetMethod().ToString().c_str(),
+ request2->GetMethod().ToString().c_str());
+
+ EXPECT_STREQ(request1->GetReferrerURL().ToString().c_str(),
+ request2->GetReferrerURL().ToString().c_str());
+ EXPECT_EQ(request1->GetReferrerPolicy(), request2->GetReferrerPolicy());
+
+ CefRequest::HeaderMap headers1, headers2;
+ request1->GetHeaderMap(headers1);
+ request2->GetHeaderMap(headers2);
+ TestMapEqual(headers1, headers2, allowExtras);
+
+ CefRefPtr<CefPostData> postData1 = request1->GetPostData();
+ CefRefPtr<CefPostData> postData2 = request2->GetPostData();
+ EXPECT_EQ(!!(postData1.get()), !!(postData2.get()));
+ if (postData1.get() && postData2.get()) {
+ TestPostDataEqual(postData1, postData2);
+ }
+}
+
+void TestResponseEqual(CefRefPtr<CefResponse> response1,
+ CefRefPtr<CefResponse> response2,
+ bool allowExtras) {
+ EXPECT_TRUE(response1.get());
+ EXPECT_TRUE(response2.get());
+
+ EXPECT_EQ(response1->GetStatus(), response2->GetStatus());
+ EXPECT_STREQ(response1->GetStatusText().ToString().c_str(),
+ response2->GetStatusText().ToString().c_str());
+ EXPECT_STREQ(response1->GetMimeType().ToString().c_str(),
+ response2->GetMimeType().ToString().c_str());
+
+ CefRequest::HeaderMap headers1, headers2;
+ response1->GetHeaderMap(headers1);
+ response2->GetHeaderMap(headers2);
+ TestMapEqual(headers1, headers2, allowExtras);
+}
+
+void TestBinaryEqual(CefRefPtr<CefBinaryValue> val1,
+ CefRefPtr<CefBinaryValue> val2) {
+ EXPECT_TRUE(val1.get());
+ EXPECT_TRUE(val2.get());
+
+ EXPECT_TRUE(val1->IsEqual(val2));
+ EXPECT_TRUE(val2->IsEqual(val1));
+
+ size_t data_size = val1->GetSize();
+ EXPECT_EQ(data_size, val2->GetSize());
+
+ EXPECT_GT(data_size, (size_t)0);
+
+ char* data1 = new char[data_size + 1];
+ char* data2 = new char[data_size + 1];
+
+ EXPECT_EQ(data_size, val1->GetData(data1, data_size, 0));
+ data1[data_size] = 0;
+ EXPECT_EQ(data_size, val2->GetData(data2, data_size, 0));
+ data2[data_size] = 0;
+
+ EXPECT_STREQ(data1, data2);
+
+ delete[] data1;
+ delete[] data2;
+}
+
+void TestDictionaryEqual(CefRefPtr<CefDictionaryValue> val1,
+ CefRefPtr<CefDictionaryValue> val2) {
+ EXPECT_TRUE(val1.get());
+ EXPECT_TRUE(val2.get());
+
+ EXPECT_TRUE(val1->IsEqual(val2));
+ EXPECT_TRUE(val2->IsEqual(val1));
+
+ EXPECT_EQ(val1->GetSize(), val2->GetSize());
+
+ CefDictionaryValue::KeyList keys;
+ EXPECT_TRUE(val1->GetKeys(keys));
+
+ CefDictionaryValue::KeyList::const_iterator it = keys.begin();
+ for (; it != keys.end(); ++it) {
+ CefString key = *it;
+ EXPECT_TRUE(val2->HasKey(key));
+ CefValueType type = val1->GetType(key);
+ EXPECT_EQ(type, val2->GetType(key));
+ switch (type) {
+ case VTYPE_INVALID:
+ case VTYPE_NULL:
+ break;
+ case VTYPE_BOOL:
+ EXPECT_EQ(val1->GetBool(key), val2->GetBool(key));
+ break;
+ case VTYPE_INT:
+ EXPECT_EQ(val1->GetInt(key), val2->GetInt(key));
+ break;
+ case VTYPE_DOUBLE:
+ EXPECT_EQ(val1->GetDouble(key), val2->GetDouble(key));
+ break;
+ case VTYPE_STRING:
+ EXPECT_EQ(val1->GetString(key), val2->GetString(key));
+ break;
+ case VTYPE_BINARY:
+ TestBinaryEqual(val1->GetBinary(key), val2->GetBinary(key));
+ break;
+ case VTYPE_DICTIONARY:
+ TestDictionaryEqual(val1->GetDictionary(key), val2->GetDictionary(key));
+ break;
+ case VTYPE_LIST:
+ TestListEqual(val1->GetList(key), val2->GetList(key));
+ break;
+ }
+ }
+}
+
+void TestListEqual(CefRefPtr<CefListValue> val1, CefRefPtr<CefListValue> val2) {
+ EXPECT_TRUE(val1.get());
+ EXPECT_TRUE(val2.get());
+
+ EXPECT_TRUE(val1->IsEqual(val2));
+ EXPECT_TRUE(val2->IsEqual(val1));
+
+ size_t size = val1->GetSize();
+ EXPECT_EQ(size, val2->GetSize());
+
+ for (size_t i = 0; i < size; ++i) {
+ CefValueType type = val1->GetType(i);
+ EXPECT_EQ(type, val2->GetType(i));
+ switch (type) {
+ case VTYPE_INVALID:
+ case VTYPE_NULL:
+ break;
+ case VTYPE_BOOL:
+ EXPECT_EQ(val1->GetBool(i), val2->GetBool(i));
+ break;
+ case VTYPE_INT:
+ EXPECT_EQ(val1->GetInt(i), val2->GetInt(i));
+ break;
+ case VTYPE_DOUBLE:
+ EXPECT_EQ(val1->GetDouble(i), val2->GetDouble(i));
+ break;
+ case VTYPE_STRING:
+ EXPECT_EQ(val1->GetString(i), val2->GetString(i));
+ break;
+ case VTYPE_BINARY:
+ TestBinaryEqual(val1->GetBinary(i), val2->GetBinary(i));
+ break;
+ case VTYPE_DICTIONARY:
+ TestDictionaryEqual(val1->GetDictionary(i), val2->GetDictionary(i));
+ break;
+ case VTYPE_LIST:
+ TestListEqual(val1->GetList(i), val2->GetList(i));
+ break;
+ }
+ }
+}
+
+void TestProcessMessageEqual(CefRefPtr<CefProcessMessage> val1,
+ CefRefPtr<CefProcessMessage> val2) {
+ EXPECT_TRUE(val1.get());
+ EXPECT_TRUE(val2.get());
+ EXPECT_EQ(val1->GetName(), val2->GetName());
+
+ TestListEqual(val1->GetArgumentList(), val2->GetArgumentList());
+}
+
+void TestStringVectorEqual(const std::vector<CefString>& val1,
+ const std::vector<CefString>& val2) {
+ EXPECT_EQ(val1.size(), val2.size());
+
+ for (size_t i = 0; i < val1.size(); ++i) {
+ EXPECT_STREQ(val1[i].ToString().c_str(), val2[i].ToString().c_str());
+ }
+}
+
+bool TestOldResourceAPI() {
+ static bool state = []() {
+ return CefCommandLine::GetGlobalCommandLine()->HasSwitch(
+ "test-old-resource-api");
+ }();
+ return state;
+}
+
+bool IsChromeRuntimeEnabled() {
+ static bool state = []() {
+ return CefCommandLine::GetGlobalCommandLine()->HasSwitch(
+ "enable-chrome-runtime");
+ }();
+ return state;
+}
+
+bool IsBFCacheEnabled() {
+ // Supported by the Chrome runtime only, see issue #3237.
+ if (!IsChromeRuntimeEnabled()) {
+ return false;
+ }
+
+ static bool state = []() {
+ const std::string& value =
+ CefCommandLine::GetGlobalCommandLine()->GetSwitchValue(
+ "disable-features");
+ return value.find("BackForwardCache") == std::string::npos;
+ }();
+ return state;
+}
+
+bool IsSameSiteBFCacheEnabled() {
+ // Same-site BFCache is enabled by default starting in M101 and does not have
+ // a separate configuration flag.
+ return IsBFCacheEnabled();
+}
+
+bool IgnoreURL(const std::string& url) {
+ return IsChromeRuntimeEnabled() &&
+ url.find("/favicon.ico") != std::string::npos;
+}
+
+std::optional<int> GetConfiguredTestTimeout(int timeout_ms) {
+ static std::optional<double> multiplier = []() -> std::optional<double> {
+ auto command_line = CefCommandLine::GetGlobalCommandLine();
+ if (command_line->HasSwitch("disable-test-timeout")) {
+ return std::nullopt;
+ }
+ const std::string& sval =
+ command_line->GetSwitchValue("test-timeout-multiplier");
+ if (!sval.empty()) {
+ if (double dval = std::atof(sval.c_str())) {
+ return dval;
+ }
+ }
+ return IsChromeRuntimeEnabled() ? 2.0 : 1.0;
+ }();
+
+ if (!multiplier) {
+ // Test timeout is disabled.
+ return std::nullopt;
+ }
+
+ return static_cast<int>(
+ std::round(static_cast<double>(timeout_ms) * (*multiplier)));
+}
+
+void SendMouseClickEvent(CefRefPtr<CefBrowser> browser,
+ const CefMouseEvent& mouse_event,
+ cef_mouse_button_type_t mouse_button_type) {
+ auto host = browser->GetHost();
+ CefPostDelayedTask(TID_UI,
+ base::BindOnce(&CefBrowserHost::SendMouseClickEvent, host,
+ mouse_event, mouse_button_type, false, 1),
+ 50);
+ CefPostDelayedTask(TID_UI,
+ base::BindOnce(&CefBrowserHost::SendMouseClickEvent, host,
+ mouse_event, mouse_button_type, true, 1),
+ 100);
+}
+
+CefRefPtr<CefRequestContext> CreateTestRequestContext(
+ TestRequestContextMode mode,
+ const std::string& cache_path) {
+ EXPECT_TRUE(cache_path.empty() || mode == TEST_RC_MODE_CUSTOM ||
+ mode == TEST_RC_MODE_CUSTOM_WITH_HANDLER);
+
+ if (mode == TEST_RC_MODE_NONE) {
+ return nullptr;
+ }
+ if (mode == TEST_RC_MODE_GLOBAL) {
+ return CefRequestContext::GetGlobalContext();
+ }
+
+ CefRefPtr<CefRequestContextHandler> rc_handler;
+ if (mode == TEST_RC_MODE_GLOBAL_WITH_HANDLER ||
+ mode == TEST_RC_MODE_CUSTOM_WITH_HANDLER) {
+ class Handler : public CefRequestContextHandler {
+ public:
+ Handler() {}
+
+ private:
+ IMPLEMENT_REFCOUNTING(Handler);
+ };
+ rc_handler = new Handler();
+ }
+
+ if (mode == TEST_RC_MODE_CUSTOM || mode == TEST_RC_MODE_CUSTOM_WITH_HANDLER) {
+ CefRequestContextSettings settings;
+ if (!cache_path.empty()) {
+ CefString(&settings.cache_path) = cache_path;
+ }
+ return CefRequestContext::CreateContext(settings, rc_handler);
+ }
+
+ EXPECT_EQ(mode, TEST_RC_MODE_GLOBAL_WITH_HANDLER);
+ return CefRequestContext::CreateContext(CefRequestContext::GetGlobalContext(),
+ rc_handler);
+}
+
+CefTime CefTimeFrom(CefBaseTime value) {
+ CefTime time;
+ cef_time_from_basetime(value, &time);
+ return time;
+}
+
+CefBaseTime CefBaseTimeFrom(const CefTime& value) {
+ cef_basetime_t temp;
+ cef_time_to_basetime(&value, &temp);
+ return CefBaseTime(temp);
+}
diff --git a/tests/ceftests/test_util.h b/tests/ceftests/test_util.h
new file mode 100644
index 00000000..7b7684e7
--- /dev/null
+++ b/tests/ceftests/test_util.h
@@ -0,0 +1,209 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFTESTS_TEST_UTIL_H_
+#define CEF_TESTS_CEFTESTS_TEST_UTIL_H_
+#pragma once
+
+#include <optional>
+
+#include "include/cef_process_message.h"
+#include "include/cef_request.h"
+#include "include/cef_request_context.h"
+#include "include/cef_response.h"
+#include "include/cef_values.h"
+#include "tests/ceftests/test_suite.h"
+
+CefTime CefTimeFrom(CefBaseTime value);
+CefBaseTime CefBaseTimeFrom(const CefTime& value);
+
+// Test that CefRequest::HeaderMap objects are equal. Multiple values with the
+// same key are allowed, but not duplicate entries with the same key/value. If
+// |allowExtras| is true then additional header fields will be allowed in
+// |map2|.
+void TestMapEqual(const CefRequest::HeaderMap& map1,
+ const CefRequest::HeaderMap& map2,
+ bool allowExtras);
+
+// Test that the CefRequest::HeaderMap object contains no duplicate entries.
+void TestMapNoDuplicates(const CefRequest::HeaderMap& map);
+
+// Test that CefPostDataElement objects are equal
+void TestPostDataElementEqual(CefRefPtr<CefPostDataElement> elem1,
+ CefRefPtr<CefPostDataElement> elem2);
+
+// Test that CefPostData objects are equal
+void TestPostDataEqual(CefRefPtr<CefPostData> postData1,
+ CefRefPtr<CefPostData> postData2);
+
+// Test that CefRequest objects are equal
+// If |allowExtras| is true then additional header fields will be allowed in
+// |request2|.
+void TestRequestEqual(CefRefPtr<CefRequest> request1,
+ CefRefPtr<CefRequest> request2,
+ bool allowExtras);
+
+// Test that CefResponse objects are equal
+// If |allowExtras| is true then additional header fields will be allowed in
+// |response2|.
+void TestResponseEqual(CefRefPtr<CefResponse> response1,
+ CefRefPtr<CefResponse> response2,
+ bool allowExtras);
+
+// Test if two binary values are equal.
+void TestBinaryEqual(CefRefPtr<CefBinaryValue> val1,
+ CefRefPtr<CefBinaryValue> val2);
+
+// Test if two list values are equal.
+void TestListEqual(CefRefPtr<CefListValue> val1, CefRefPtr<CefListValue> val2);
+
+// Test if two dictionary values are equal.
+void TestDictionaryEqual(CefRefPtr<CefDictionaryValue> val1,
+ CefRefPtr<CefDictionaryValue> val2);
+
+// Test if two process message values are equal.
+void TestProcessMessageEqual(CefRefPtr<CefProcessMessage> val1,
+ CefRefPtr<CefProcessMessage> val2);
+
+// Test if two CefString vectors are equal.
+void TestStringVectorEqual(const std::vector<CefString>& val1,
+ const std::vector<CefString>& val2);
+
+enum TestRequestContextMode {
+ TEST_RC_MODE_NONE,
+ TEST_RC_MODE_GLOBAL,
+ TEST_RC_MODE_GLOBAL_WITH_HANDLER,
+ TEST_RC_MODE_CUSTOM,
+ TEST_RC_MODE_CUSTOM_WITH_HANDLER,
+};
+
+inline bool IsTestRequestContextModeCustom(TestRequestContextMode mode) {
+ return mode == TEST_RC_MODE_CUSTOM ||
+ mode == TEST_RC_MODE_CUSTOM_WITH_HANDLER;
+}
+
+// Returns true if the old CefResourceHandler API should be tested.
+bool TestOldResourceAPI();
+
+// Returns true if the Chrome runtime is enabled.
+bool IsChromeRuntimeEnabled();
+
+// Returns true if BFCache is enabled.
+bool IsBFCacheEnabled();
+
+// Returns true if same-site BFCache is enabled.
+bool IsSameSiteBFCacheEnabled();
+
+// Returns true if requests for |url| should be ignored by tests.
+bool IgnoreURL(const std::string& url);
+
+// Returns |timeout_ms| as scaled by the current configuration, or std::nullopt
+// if timeouts are disabled.
+std::optional<int> GetConfiguredTestTimeout(int timeout_ms);
+
+// Send a mouse click event with the necessary delay to avoid having events
+// dropped or rate limited.
+void SendMouseClickEvent(CefRefPtr<CefBrowser> browser,
+ const CefMouseEvent& mouse_event,
+ cef_mouse_button_type_t mouse_button_type = MBT_LEFT);
+
+// Return a RequestContext object matching the specified |mode|.
+// |cache_path| may be specified for CUSTOM modes.
+// Use the RC_TEST_GROUP_BASE macro to test all valid combinations.
+CefRefPtr<CefRequestContext> CreateTestRequestContext(
+ TestRequestContextMode mode,
+ const std::string& cache_path);
+
+// Helper macro for testing a single RequestContextMode value.
+// See RC_TEST_GROUP_ALL documentation for example usage.
+#define RC_TEST_BASE(test_case_name, test_name, test_class, test_mode, \
+ rc_mode, with_cache_path) \
+ TEST(test_case_name, test_name) { \
+ CefScopedTempDir scoped_temp_dir; \
+ std::string cache_path; \
+ if (with_cache_path) { \
+ EXPECT_TRUE(scoped_temp_dir.CreateUniqueTempDirUnderPath( \
+ CefTestSuite::GetInstance()->root_cache_path())); \
+ cache_path = scoped_temp_dir.GetPath(); \
+ } \
+ CefRefPtr<test_class> handler = \
+ new test_class(test_class::test_mode, rc_mode, cache_path); \
+ handler->ExecuteTest(); \
+ ReleaseAndWaitForDestructor(handler); \
+ if (!scoped_temp_dir.IsEmpty()) { \
+ scoped_temp_dir.Take(); \
+ } \
+ }
+
+// RequestContextModes that operate in memory.
+#define RC_TEST_GROUP_IN_MEMORY(test_case_name, test_name, test_class, \
+ test_mode) \
+ RC_TEST_BASE(test_case_name, test_name##RCNone, test_class, test_mode, \
+ TEST_RC_MODE_NONE, false) \
+ RC_TEST_BASE(test_case_name, test_name##RCGlobal, test_class, test_mode, \
+ TEST_RC_MODE_GLOBAL, false) \
+ RC_TEST_BASE(test_case_name, test_name##RCGlobalWithHandler, test_class, \
+ test_mode, TEST_RC_MODE_GLOBAL_WITH_HANDLER, false) \
+ RC_TEST_BASE(test_case_name, test_name##RCCustomInMemory, test_class, \
+ test_mode, TEST_RC_MODE_CUSTOM, false) \
+ RC_TEST_BASE(test_case_name, test_name##RCCustomInMemoryWithHandler, \
+ test_class, test_mode, TEST_RC_MODE_CUSTOM_WITH_HANDLER, false)
+
+// RequestContextModes that operate on disk.
+#define RC_TEST_GROUP_ON_DISK(test_case_name, test_name, test_class, \
+ test_mode) \
+ RC_TEST_BASE(test_case_name, test_name##RCCustomOnDisk, test_class, \
+ test_mode, TEST_RC_MODE_CUSTOM, true) \
+ RC_TEST_BASE(test_case_name, test_name##RCCustomOnDiskWithHandler, \
+ test_class, test_mode, TEST_RC_MODE_CUSTOM_WITH_HANDLER, true)
+
+// Helper macro for testing all valid combinations of RequestContextMode values.
+// For example:
+//
+// // Test handler implementation.
+// class MyTestHandler : public TestHandler {
+// public:
+// // Test modes supported by MyTestHandler.
+// enum TestMode {
+// FIRST,
+// SECOND,
+// };
+//
+// // Constructor always accepts three arguments.
+// MyTestHandler(TestMode test_mode,
+// TestRequestContextMode rc_mode,
+// const std::string& rc_cache_path)
+// : test_mode_(test_mode), rc_mode_(rc_mode),
+// rc_cache_path_(rc_cache_path) {}
+//
+// void RunTest() override {
+// // Create a RequestContext with the specified attributes.
+// CefRefPtr<CefRequestContext> request_context =
+// CreateTestRequestContext(rc_mode_, rc_cache_path_);
+//
+// // Do something with |test_mode_| and |request_context|...
+// }
+//
+// private:
+// const TestMode test_mode_;
+// const TestRequestContextMode rc_mode_;
+// const std::string rc_cache_path_;
+//
+// IMPLEMENT_REFCOUNTING(MyTestHandler);
+// };
+//
+// // Helper macro for defining tests using MyTestHandler.
+// #define MY_TEST_GROUP(test_name, test_mode) \
+// RC_TEST_GROUP_ALL(MyTest, test_name, MyTestHandler, test_mode)
+//
+// // Implementation for MyTest.First* tests.
+// MY_TEST_GROUP(First, FIRST);
+// // Implementation for MyTest.Second* tests.
+// MY_TEST_GROUP(Second, SECOND);
+//
+#define RC_TEST_GROUP_ALL(test_case_name, test_name, test_class, test_mode) \
+ RC_TEST_GROUP_IN_MEMORY(test_case_name, test_name, test_class, test_mode) \
+ RC_TEST_GROUP_ON_DISK(test_case_name, test_name, test_class, test_mode)
+
+#endif // CEF_TESTS_CEFTESTS_TEST_UTIL_H_
diff --git a/tests/ceftests/thread_helper.cc b/tests/ceftests/thread_helper.cc
new file mode 100644
index 00000000..326c95dc
--- /dev/null
+++ b/tests/ceftests/thread_helper.cc
@@ -0,0 +1,54 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/ceftests/thread_helper.h"
+
+#include <memory>
+
+#include "include/wrapper/cef_closure_task.h"
+
+void SignalEvent(CefRefPtr<CefWaitableEvent> event) {
+ event->Signal();
+}
+
+void WaitForThread(CefThreadId thread_id, int64 delay_ms) {
+ CefRefPtr<CefWaitableEvent> event =
+ CefWaitableEvent::CreateWaitableEvent(true, false);
+ CefPostDelayedTask(thread_id, base::BindOnce(SignalEvent, event), delay_ms);
+ event->Wait();
+}
+
+void WaitForThread(CefRefPtr<CefTaskRunner> task_runner, int64 delay_ms) {
+ CefRefPtr<CefWaitableEvent> event =
+ CefWaitableEvent::CreateWaitableEvent(true, false);
+ task_runner->PostDelayedTask(
+ CefCreateClosureTask(base::BindOnce(SignalEvent, event)), delay_ms);
+ event->Wait();
+}
+
+void RunOnThread(CefThreadId thread_id,
+ base::OnceClosure test_impl,
+ CefRefPtr<CefWaitableEvent> event) {
+ if (!CefCurrentlyOn(thread_id)) {
+ CefPostTask(thread_id, base::BindOnce(RunOnThread, thread_id,
+ std::move(test_impl), event));
+ return;
+ }
+
+ std::move(test_impl).Run();
+ SignalEvent(event);
+}
+
+void RunOnThreadAsync(
+ CefThreadId thread_id,
+ base::OnceCallback<void(CefRefPtr<CefWaitableEvent>)> test_impl,
+ CefRefPtr<CefWaitableEvent> event) {
+ if (!CefCurrentlyOn(thread_id)) {
+ CefPostTask(thread_id, base::BindOnce(RunOnThreadAsync, thread_id,
+ std::move(test_impl), event));
+ return;
+ }
+
+ std::move(test_impl).Run(event);
+}
diff --git a/tests/ceftests/thread_helper.h b/tests/ceftests/thread_helper.h
new file mode 100644
index 00000000..e68ecd41
--- /dev/null
+++ b/tests/ceftests/thread_helper.h
@@ -0,0 +1,73 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFTESTS_THREAD_HELPER_H_
+#define CEF_TESTS_CEFTESTS_THREAD_HELPER_H_
+#pragma once
+
+#include "include/base/cef_callback.h"
+#include "include/cef_task.h"
+#include "include/cef_waitable_event.h"
+
+// Helper for signaling |event|.
+void SignalEvent(CefRefPtr<CefWaitableEvent> event);
+
+// Post a task to the specified thread and wait for the task to execute as
+// indication that all previously pending tasks on that thread have completed.
+void WaitForThread(CefThreadId thread_id, int64 delay_ms = 0);
+void WaitForThread(CefRefPtr<CefTaskRunner> task_runner, int64 delay_ms = 0);
+
+#define WaitForIOThread() WaitForThread(TID_IO)
+#define WaitForUIThread() WaitForThread(TID_UI)
+#define WaitForFILEThread() WaitForThread(TID_FILE_USER_VISIBLE)
+#define WaitForIOThreadWithDelay(delay_ms) WaitForThread(TID_IO, delay_ms)
+#define WaitForUIThreadWithDelay(delay_ms) WaitForThread(TID_UI, delay_ms)
+#define WaitForFILEThreadWithDelay(delay_ms) \
+ WaitForThread(TID_FILE_USER_VISIBLE, delay_ms)
+
+// Assert that execution is occuring on the named thread.
+#define EXPECT_UI_THREAD() EXPECT_TRUE(CefCurrentlyOn(TID_UI));
+#define EXPECT_IO_THREAD() EXPECT_TRUE(CefCurrentlyOn(TID_IO));
+#define EXPECT_FILE_THREAD() EXPECT_TRUE(CefCurrentlyOn(TID_FILE_USER_VISIBLE));
+#define EXPECT_RENDERER_THREAD() EXPECT_TRUE(CefCurrentlyOn(TID_RENDERER));
+
+// Executes |test_impl| on the specified |thread_id|. |event| will be signaled
+// once execution is complete.
+void RunOnThread(CefThreadId thread_id,
+ base::OnceClosure test_impl,
+ CefRefPtr<CefWaitableEvent> event);
+
+#define NAMED_THREAD_TEST(thread_id, test_case_name, test_name) \
+ TEST(test_case_name, test_name) { \
+ CefRefPtr<CefWaitableEvent> event = \
+ CefWaitableEvent::CreateWaitableEvent(true, false); \
+ RunOnThread(thread_id, base::BindOnce(test_name##Impl), event); \
+ event->Wait(); \
+ }
+
+// Execute "test_case_name.test_name" test on the named thread. The test
+// implementation is "void test_nameImpl()".
+#define UI_THREAD_TEST(test_case_name, test_name) \
+ NAMED_THREAD_TEST(TID_UI, test_case_name, test_name)
+
+// Like RunOnThread() but |test_impl| is responsible for signaling |event|.
+void RunOnThreadAsync(
+ CefThreadId thread_id,
+ base::OnceCallback<void(CefRefPtr<CefWaitableEvent>)> test_impl,
+ CefRefPtr<CefWaitableEvent>);
+
+#define NAMED_THREAD_TEST_ASYNC(thread_id, test_case_name, test_name) \
+ TEST(test_case_name, test_name) { \
+ CefRefPtr<CefWaitableEvent> event = \
+ CefWaitableEvent::CreateWaitableEvent(true, false); \
+ RunOnThreadAsync(thread_id, base::BindOnce(test_name##Impl), event); \
+ event->Wait(); \
+ }
+
+// Execute "test_case_name.test_name" test on the named thread. The test
+// implementation is "void test_nameImpl(CefRefPtr<CefWaitableEvent> event)".
+#define UI_THREAD_TEST_ASYNC(test_case_name, test_name) \
+ NAMED_THREAD_TEST_ASYNC(TID_UI, test_case_name, test_name)
+
+#endif // CEF_TESTS_CEFTESTS_THREAD_HELPER_H_
diff --git a/tests/ceftests/thread_unittest.cc b/tests/ceftests/thread_unittest.cc
new file mode 100644
index 00000000..f5152a20
--- /dev/null
+++ b/tests/ceftests/thread_unittest.cc
@@ -0,0 +1,445 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "include/base/cef_callback.h"
+#include "include/base/cef_callback_helpers.h"
+#include "include/cef_task.h"
+#include "include/cef_thread.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "tests/ceftests/test_handler.h"
+#include "tests/gtest/include/gtest/gtest.h"
+#include "tests/shared/browser/client_app_browser.h"
+#include "tests/shared/renderer/client_app_renderer.h"
+
+using client::ClientAppBrowser;
+using client::ClientAppRenderer;
+
+namespace {
+
+// Base class for creating and testing threads.
+class ThreadTest : public base::RefCountedThreadSafe<ThreadTest> {
+ public:
+ ThreadTest() {}
+ virtual ~ThreadTest() {}
+
+ // Create the test thread. Should only be called one time.
+ void CreateTestThread() {
+ EXPECT_TRUE(!thread_.get());
+
+ owner_task_runner_ = CefTaskRunner::GetForCurrentThread();
+ EXPECT_TRUE(owner_task_runner_.get());
+ EXPECT_TRUE(owner_task_runner_->BelongsToCurrentThread());
+
+ thread_ = CefThread::CreateThread("test_thread");
+ EXPECT_TRUE(thread_.get());
+ EXPECT_TRUE(thread_->IsRunning());
+
+ thread_id_ = thread_->GetPlatformThreadId();
+ EXPECT_NE(thread_id_, kInvalidPlatformThreadId);
+
+ thread_task_runner_ = thread_->GetTaskRunner();
+ EXPECT_TRUE(thread_task_runner_.get());
+
+ AssertOwnerThread();
+ }
+
+ // Destroy the test thread. Should only be called one time.
+ void DestroyTestThread() {
+ EXPECT_TRUE(thread_.get());
+ AssertOwnerThread();
+
+ EXPECT_TRUE(thread_->IsRunning());
+ thread_->Stop();
+ EXPECT_FALSE(thread_->IsRunning());
+
+ AssertOwnerThread();
+
+ thread_ = nullptr;
+ }
+
+ // Execute |test_task| on the test thread. After execution |callback| will be
+ // posted to |callback_task_runner|.
+ void PostOnTestThreadAndCallback(
+ base::OnceClosure test_task,
+ CefRefPtr<CefTaskRunner> callback_task_runner,
+ base::OnceClosure callback) {
+ EXPECT_TRUE(thread_.get());
+ thread_task_runner_->PostTask(CefCreateClosureTask(base::BindOnce(
+ &ThreadTest::ExecuteOnTestThread, this, std::move(test_task),
+ callback_task_runner, std::move(callback))));
+ }
+
+ CefRefPtr<CefTaskRunner> owner_task_runner() const {
+ return owner_task_runner_;
+ }
+ CefRefPtr<CefTaskRunner> thread_task_runner() const {
+ return thread_task_runner_;
+ }
+
+ // Assert that we're running on the owner thread.
+ void AssertOwnerThread() {
+ EXPECT_TRUE(owner_task_runner_->BelongsToCurrentThread());
+ EXPECT_FALSE(thread_task_runner_->BelongsToCurrentThread());
+ EXPECT_TRUE(thread_task_runner_->IsSame(thread_->GetTaskRunner()));
+ EXPECT_EQ(thread_id_, thread_->GetPlatformThreadId());
+ }
+
+ // Assert that we're running on the test thread.
+ void AssertTestThread() {
+ EXPECT_FALSE(owner_task_runner_->BelongsToCurrentThread());
+ EXPECT_TRUE(thread_task_runner_->BelongsToCurrentThread());
+ EXPECT_TRUE(thread_task_runner_->IsSame(thread_->GetTaskRunner()));
+ EXPECT_EQ(thread_id_, thread_->GetPlatformThreadId());
+ }
+
+ private:
+ // Helper for PostOnTestThreadAndCallback().
+ void ExecuteOnTestThread(base::OnceClosure test_task,
+ CefRefPtr<CefTaskRunner> callback_task_runner,
+ base::OnceClosure callback) {
+ AssertTestThread();
+
+ std::move(test_task).Run();
+
+ callback_task_runner->PostTask(CefCreateClosureTask(std::move(callback)));
+ }
+
+ CefRefPtr<CefTaskRunner> owner_task_runner_;
+
+ CefRefPtr<CefThread> thread_;
+ cef_platform_thread_id_t thread_id_;
+ CefRefPtr<CefTaskRunner> thread_task_runner_;
+
+ DISALLOW_COPY_AND_ASSIGN(ThreadTest);
+};
+
+} // namespace
+
+// Test thread creation and destruction without any task execution.
+TEST(ThreadTest, Create) {
+ scoped_refptr<ThreadTest> thread_test = new ThreadTest();
+ thread_test->CreateTestThread();
+ thread_test->DestroyTestThread();
+ thread_test = nullptr;
+}
+
+namespace {
+
+// Simple implementation of ThreadTest that creates a thread, executes tasks
+// on the thread, then destroys the thread after all tasks have completed.
+class SimpleThreadTest : public ThreadTest {
+ public:
+ SimpleThreadTest(size_t expected_task_count,
+ base::OnceClosure task_callback,
+ base::OnceClosure done_callback)
+ : expected_task_count_(expected_task_count),
+ task_callback_(std::move(task_callback)),
+ done_callback_(std::move(done_callback)),
+ got_task_count_(0U),
+ got_done_count_(0U) {}
+
+ void RunTest() {
+ // Create the test thread.
+ CreateTestThread();
+
+ for (size_t i = 0U; i < expected_task_count_; ++i) {
+ // Execute Task() on the test thread and then call Done() on this thread.
+ PostOnTestThreadAndCallback(
+ base::BindOnce(&SimpleThreadTest::Task, this), owner_task_runner(),
+ base::BindOnce(&SimpleThreadTest::Done, this));
+ }
+ }
+
+ void DestroyTest() {
+ EXPECT_EQ(expected_task_count_, got_task_count_);
+ EXPECT_EQ(expected_task_count_, got_done_count_);
+
+ // Destroy the test thread.
+ DestroyTestThread();
+ }
+
+ private:
+ void Task() {
+ AssertTestThread();
+ got_task_count_++;
+ if (!task_callback_.is_null()) {
+ std::move(task_callback_).Run();
+ }
+ }
+
+ void Done() {
+ AssertOwnerThread();
+ if (++got_done_count_ == expected_task_count_ &&
+ !done_callback_.is_null()) {
+ std::move(done_callback_).Run();
+ }
+ }
+
+ const size_t expected_task_count_;
+ base::OnceClosure task_callback_;
+ base::OnceClosure done_callback_;
+
+ size_t got_task_count_;
+ size_t got_done_count_;
+
+ DISALLOW_COPY_AND_ASSIGN(SimpleThreadTest);
+};
+
+// Test creation/execution of threads in the browser process.
+
+const char kBrowserThreadTestHtml[] = "http://test.com/browserthread.html";
+
+// Browser side.
+class BrowserThreadTestHandler : public TestHandler {
+ public:
+ explicit BrowserThreadTestHandler(CefThreadId owner_thread_id)
+ : owner_thread_id_(owner_thread_id) {}
+
+ void RunTest() override {
+ AddResource(kBrowserThreadTestHtml, "<html><body>Test</body></html>",
+ "text/html");
+
+ CreateBrowser(kBrowserThreadTestHtml);
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout();
+ }
+
+ void RunThreadTestOnOwnerThread() {
+ if (!CefCurrentlyOn(owner_thread_id_)) {
+ // Run the test on the desired owner thread.
+ CefPostTask(
+ owner_thread_id_,
+ base::BindOnce(&BrowserThreadTestHandler::RunThreadTestOnOwnerThread,
+ this));
+ return;
+ }
+
+ EXPECT_FALSE(thread_test_.get());
+ thread_test_ = new SimpleThreadTest(
+ 3, base::DoNothing(),
+ base::BindOnce(&BrowserThreadTestHandler::DoneOnOwnerThread, this));
+ thread_test_->RunTest();
+ }
+
+ void DoneOnOwnerThread() {
+ // Let the call stack unwind before destroying |thread_test_|.
+ CefPostTask(owner_thread_id_,
+ base::BindOnce(
+ &BrowserThreadTestHandler::DestroyTestOnOwnerThread, this));
+ }
+
+ void DestroyTestOnOwnerThread() {
+ EXPECT_TRUE(CefCurrentlyOn(owner_thread_id_));
+
+ EXPECT_TRUE(thread_test_.get());
+ if (thread_test_) {
+ thread_test_->DestroyTest();
+ thread_test_ = nullptr;
+ }
+
+ got_test_done_.yes();
+
+ // Call DestroyTest() on the UI thread.
+ CefPostTask(TID_UI,
+ base::BindOnce(&BrowserThreadTestHandler::DestroyTest, this));
+ }
+
+ void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
+ bool isLoading,
+ bool canGoBack,
+ bool canGoForward) override {
+ if (!isLoading) {
+ RunThreadTestOnOwnerThread();
+ }
+ }
+
+ private:
+ void DestroyTest() override {
+ EXPECT_FALSE(thread_test_.get());
+ EXPECT_TRUE(got_test_done_);
+
+ TestHandler::DestroyTest();
+ }
+
+ const CefThreadId owner_thread_id_;
+
+ scoped_refptr<SimpleThreadTest> thread_test_;
+ TrackCallback got_test_done_;
+
+ IMPLEMENT_REFCOUNTING(BrowserThreadTestHandler);
+ DISALLOW_COPY_AND_ASSIGN(BrowserThreadTestHandler);
+};
+
+} // namespace
+
+// Test creation of new threads from the browser UI thread.
+TEST(ThreadTest, CreateFromBrowserUIThread) {
+ CefRefPtr<BrowserThreadTestHandler> handler =
+ new BrowserThreadTestHandler(TID_UI);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Test creation of new threads from the browser IO thread.
+TEST(ThreadTest, CreateFromBrowserIOThread) {
+ CefRefPtr<BrowserThreadTestHandler> handler =
+ new BrowserThreadTestHandler(TID_IO);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Test creation of new threads from the browser FILE thread.
+TEST(ThreadTest, CreateFromBrowserFILEThread) {
+ // Use a FILE thread that will run tasks relatively quickly.
+ CefRefPtr<BrowserThreadTestHandler> handler =
+ new BrowserThreadTestHandler(TID_FILE_USER_VISIBLE);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+namespace {
+
+// Test creation/execution of threads in the render process.
+
+const char kRenderThreadTestHtml[] = "http://test.com/renderthread.html";
+const char kRenderThreadTestMsg[] = "ThreadTest.RenderThreadTest";
+
+// Browser side.
+class RenderThreadTestHandler : public TestHandler {
+ public:
+ RenderThreadTestHandler() {}
+
+ void RunTest() override {
+ AddResource(kRenderThreadTestHtml, "<html><body>Test</body></html>",
+ "text/html");
+
+ CreateBrowser(kRenderThreadTestHtml);
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout();
+ }
+
+ void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
+ bool isLoading,
+ bool canGoBack,
+ bool canGoForward) override {
+ if (!isLoading) {
+ // Return the test in the render process.
+ CefRefPtr<CefProcessMessage> msg =
+ CefProcessMessage::Create(kRenderThreadTestMsg);
+ browser->GetMainFrame()->SendProcessMessage(PID_RENDERER, msg);
+ }
+ }
+
+ bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefProcessId source_process,
+ CefRefPtr<CefProcessMessage> message) override {
+ EXPECT_TRUE(browser.get());
+ EXPECT_TRUE(frame.get());
+ EXPECT_EQ(PID_RENDERER, source_process);
+ EXPECT_TRUE(message.get());
+ EXPECT_TRUE(message->IsReadOnly());
+
+ const std::string& message_name = message->GetName();
+ EXPECT_STREQ(kRenderThreadTestMsg, message_name.c_str());
+
+ got_message_.yes();
+
+ if (message->GetArgumentList()->GetBool(0)) {
+ got_success_.yes();
+ }
+
+ // Test is complete.
+ DestroyTest();
+
+ return true;
+ }
+
+ protected:
+ void DestroyTest() override {
+ EXPECT_TRUE(got_message_);
+ EXPECT_TRUE(got_success_);
+
+ TestHandler::DestroyTest();
+ }
+
+ TrackCallback got_message_;
+ TrackCallback got_success_;
+
+ IMPLEMENT_REFCOUNTING(RenderThreadTestHandler);
+ DISALLOW_COPY_AND_ASSIGN(RenderThreadTestHandler);
+};
+
+// Renderer side.
+class RenderThreadRendererTest : public ClientAppRenderer::Delegate {
+ public:
+ RenderThreadRendererTest() {}
+
+ bool OnProcessMessageReceived(CefRefPtr<ClientAppRenderer> app,
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefProcessId source_process,
+ CefRefPtr<CefProcessMessage> message) override {
+ if (message->GetName().ToString() == kRenderThreadTestMsg) {
+ browser_ = browser;
+ EXPECT_FALSE(thread_test_.get());
+ thread_test_ = new SimpleThreadTest(
+ 3, base::DoNothing(),
+ base::BindOnce(&RenderThreadRendererTest::Done, this));
+ thread_test_->RunTest();
+ return true;
+ }
+
+ // Message not handled.
+ return false;
+ }
+
+ private:
+ void Done() {
+ // Let the call stack unwind before destroying |thread_test_|.
+ CefPostTask(TID_RENDERER,
+ base::BindOnce(&RenderThreadRendererTest::DestroyTest, this));
+ }
+
+ void DestroyTest() {
+ EXPECT_TRUE(thread_test_.get());
+ if (thread_test_) {
+ thread_test_->DestroyTest();
+ thread_test_ = nullptr;
+ }
+
+ // Check if the test has failed.
+ bool result = !TestFailed();
+
+ // Return the result to the browser process.
+ CefRefPtr<CefProcessMessage> return_msg =
+ CefProcessMessage::Create(kRenderThreadTestMsg);
+ EXPECT_TRUE(return_msg->GetArgumentList()->SetBool(0, result));
+ browser_->GetMainFrame()->SendProcessMessage(PID_BROWSER, return_msg);
+
+ browser_ = nullptr;
+ }
+
+ CefRefPtr<CefBrowser> browser_;
+ scoped_refptr<SimpleThreadTest> thread_test_;
+
+ IMPLEMENT_REFCOUNTING(RenderThreadRendererTest);
+ DISALLOW_COPY_AND_ASSIGN(RenderThreadRendererTest);
+};
+
+} // namespace
+
+TEST(ThreadTest, CreateFromRenderThread) {
+ CefRefPtr<RenderThreadTestHandler> handler = new RenderThreadTestHandler();
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Entry point for creating request handler renderer test objects.
+// Called from client_app_delegates.cc.
+void CreateThreadRendererTests(ClientAppRenderer::DelegateSet& delegates) {
+ delegates.insert(new RenderThreadRendererTest);
+}
diff --git a/tests/ceftests/time_unittest.cc b/tests/ceftests/time_unittest.cc
new file mode 100644
index 00000000..e6049722
--- /dev/null
+++ b/tests/ceftests/time_unittest.cc
@@ -0,0 +1,85 @@
+// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "include/internal/cef_time_wrappers.h"
+#include "tests/gtest/include/gtest/gtest.h"
+
+TEST(TimeTest, Now) {
+ // Sanity check, what it returns something.
+ cef_basetime_t now = cef_basetime_now();
+ EXPECT_NE(now.val, 0);
+}
+
+TEST(TimeTest, TimeToBaseTime) {
+ // Choosing some date which should be always representable on any platform.
+ cef_time_t date{};
+ date.year = 2001;
+ date.month = 2;
+ date.day_of_week = 1;
+ date.day_of_month = 5;
+ date.hour = 6;
+ date.minute = 7;
+ date.second = 8;
+ date.millisecond = 9;
+
+ cef_basetime_t basetime{};
+
+ // Null parameter handling.
+ ASSERT_FALSE(cef_time_to_basetime(nullptr, nullptr));
+ ASSERT_FALSE(cef_time_to_basetime(&date, nullptr));
+ ASSERT_FALSE(cef_time_to_basetime(nullptr, &basetime));
+
+ ASSERT_TRUE(cef_time_to_basetime(&date, &basetime));
+ ASSERT_EQ(basetime.val, 12625826828009000);
+}
+
+TEST(TimeTest, BaseTimeToTime) {
+ cef_basetime_t basetime{12625826828009000};
+
+ // Choosing some date which should be always representable on any platform.
+ cef_time_t date{};
+
+ ASSERT_TRUE(cef_time_from_basetime(basetime, &date) != 0);
+
+ EXPECT_EQ(date.year, 2001);
+ EXPECT_EQ(date.month, 2);
+ EXPECT_EQ(date.day_of_week, 1);
+ EXPECT_EQ(date.day_of_month, 5);
+ EXPECT_EQ(date.hour, 6);
+ EXPECT_EQ(date.minute, 7);
+ EXPECT_EQ(date.second, 8);
+ EXPECT_EQ(date.millisecond, 9);
+}
+
+TEST(TimeTest, InvalidTimeToBaseTime) {
+ // Some time which can't be represented
+ cef_time_t date{};
+ date.year = 90000;
+ cef_basetime_t basetime{999999999};
+
+ ASSERT_FALSE(cef_time_to_basetime(&date, &basetime) != 0);
+ ASSERT_EQ(basetime.val, 0); // Output should always be set.
+}
+
+// Only run on Windows because POSIX supports a wider range of dates.
+#if defined(OS_WIN)
+TEST(TimeTest, InvalidBaseTimeToTime) {
+ // Unrepresentable.
+ cef_basetime_t basetime{std::numeric_limits<int64_t>::max()};
+ cef_time_t date{};
+ date.year = 999999999;
+
+ ASSERT_FALSE(cef_time_from_basetime(basetime, &date) != 0);
+
+ // Output should always be set.
+ EXPECT_EQ(date.year, 0);
+ EXPECT_EQ(date.month, 0);
+ EXPECT_EQ(date.day_of_week, 0);
+ EXPECT_EQ(date.day_of_month, 0);
+ EXPECT_EQ(date.hour, 0);
+ EXPECT_EQ(date.minute, 0);
+ EXPECT_EQ(date.second, 0);
+ EXPECT_EQ(date.millisecond, 0);
+}
+#endif // defined(OS_WIN)
diff --git a/tests/ceftests/tracing_unittest.cc b/tests/ceftests/tracing_unittest.cc
new file mode 100644
index 00000000..938737f6
--- /dev/null
+++ b/tests/ceftests/tracing_unittest.cc
@@ -0,0 +1,436 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "include/base/cef_callback.h"
+#include "include/cef_file_util.h"
+#include "include/cef_task.h"
+#include "include/cef_trace.h"
+#include "include/cef_waitable_event.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "tests/ceftests/test_handler.h"
+#include "tests/gtest/include/gtest/gtest.h"
+#include "tests/shared/browser/file_util.h"
+
+// Use the CEF version of the TRACE_* macros instead of the Chromium version.
+#undef USING_CHROMIUM_INCLUDES
+#include "include/base/cef_trace_event.h"
+
+enum TracingTestType {
+ TT_TRACE_EVENT0,
+ TT_TRACE_EVENT1,
+ TT_TRACE_EVENT2,
+ TT_TRACE_EVENT_INSTANT0,
+ TT_TRACE_EVENT_INSTANT1,
+ TT_TRACE_EVENT_INSTANT2,
+ TT_TRACE_EVENT_COPY_INSTANT0,
+ TT_TRACE_EVENT_COPY_INSTANT1,
+ TT_TRACE_EVENT_COPY_INSTANT2,
+ TT_TRACE_EVENT_BEGIN0,
+ TT_TRACE_EVENT_BEGIN1,
+ TT_TRACE_EVENT_BEGIN2,
+ TT_TRACE_EVENT_COPY_BEGIN0,
+ TT_TRACE_EVENT_COPY_BEGIN1,
+ TT_TRACE_EVENT_COPY_BEGIN2,
+ TT_TRACE_EVENT_END0,
+ TT_TRACE_EVENT_END1,
+ TT_TRACE_EVENT_END2,
+ TT_TRACE_EVENT_COPY_END0,
+ TT_TRACE_EVENT_COPY_END1,
+ TT_TRACE_EVENT_COPY_END2,
+ TT_TRACE_COUNTER1,
+ TT_TRACE_COPY_COUNTER1,
+ TT_TRACE_COUNTER2,
+ TT_TRACE_COPY_COUNTER2,
+ TT_TRACE_COUNTER_ID1,
+ TT_TRACE_COPY_COUNTER_ID1,
+ TT_TRACE_COUNTER_ID2,
+ TT_TRACE_COPY_COUNTER_ID2,
+ TT_TRACE_EVENT_ASYNC_BEGIN0,
+ TT_TRACE_EVENT_ASYNC_BEGIN1,
+ TT_TRACE_EVENT_ASYNC_BEGIN2,
+ TT_TRACE_EVENT_COPY_ASYNC_BEGIN0,
+ TT_TRACE_EVENT_COPY_ASYNC_BEGIN1,
+ TT_TRACE_EVENT_COPY_ASYNC_BEGIN2,
+ TT_TRACE_EVENT_ASYNC_STEP_INTO0,
+ TT_TRACE_EVENT_ASYNC_STEP_INTO1,
+ TT_TRACE_EVENT_COPY_ASYNC_STEP_INTO0,
+ TT_TRACE_EVENT_COPY_ASYNC_STEP_INTO1,
+ TT_TRACE_EVENT_ASYNC_STEP_PAST0,
+ TT_TRACE_EVENT_ASYNC_STEP_PAST1,
+ TT_TRACE_EVENT_COPY_ASYNC_STEP_PAST0,
+ TT_TRACE_EVENT_COPY_ASYNC_STEP_PAST1,
+ TT_TRACE_EVENT_ASYNC_END0,
+ TT_TRACE_EVENT_ASYNC_END1,
+ TT_TRACE_EVENT_ASYNC_END2,
+ TT_TRACE_EVENT_COPY_ASYNC_END0,
+ TT_TRACE_EVENT_COPY_ASYNC_END1,
+ TT_TRACE_EVENT_COPY_ASYNC_END2
+};
+
+const char kTraceTestCategory[] = "cef.client";
+
+class TracingTestHandler : public CefEndTracingCallback,
+ public CefCompletionCallback {
+ public:
+ TracingTestHandler(TracingTestType type, const char* trace_type)
+ : trace_type_(trace_type), type_(type) {
+ completion_event_ = CefWaitableEvent::CreateWaitableEvent(true, false);
+ }
+
+ void ExecuteTest() {
+ // Run the test.
+ CefPostTask(TID_UI,
+ base::BindOnce(&TracingTestHandler::BeginTracing, this));
+
+ // Wait for the test to complete.
+ completion_event_->Wait();
+
+ // Verify the results.
+ EXPECT_TRUE(!trace_data_.empty());
+ EXPECT_TRUE(trace_type_ != nullptr);
+ EXPECT_TRUE(strstr(trace_data_.c_str(), trace_type_) != nullptr);
+ }
+
+ void BeginTracing() {
+ EXPECT_UI_THREAD();
+
+ // Results in a call to OnComplete.
+ CefBeginTracing(kTraceTestCategory, this);
+ }
+
+ void OnComplete() override {
+ EXPECT_UI_THREAD();
+
+ // Add some delay to avoid timing-related test failures.
+ CefPostDelayedTask(
+ TID_UI, base::BindOnce(&TracingTestHandler::TestTracing, this), 50);
+ }
+
+ void TestTracing() {
+ EXPECT_UI_THREAD();
+
+ switch (type_) {
+ case TT_TRACE_EVENT0: {
+ TRACE_EVENT0(kTraceTestCategory, "TT_TRACE_EVENT0");
+ } break;
+ case TT_TRACE_EVENT1: {
+ TRACE_EVENT1(kTraceTestCategory, "TT_TRACE_EVENT1", "arg1", 1);
+ } break;
+ case TT_TRACE_EVENT2: {
+ TRACE_EVENT2(kTraceTestCategory, "TT_TRACE_EVENT2", "arg1", 1, "arg2",
+ 2);
+ } break;
+ case TT_TRACE_EVENT_INSTANT0:
+ TRACE_EVENT_INSTANT0(kTraceTestCategory, "TT_TRACE_EVENT_INSTANT0");
+ break;
+ case TT_TRACE_EVENT_INSTANT1:
+ TRACE_EVENT_INSTANT1(kTraceTestCategory, "TT_TRACE_EVENT_INSTANT1",
+ "arg1", 1);
+ break;
+ case TT_TRACE_EVENT_INSTANT2:
+ TRACE_EVENT_INSTANT2(kTraceTestCategory, "TT_TRACE_EVENT_INSTANT2",
+ "arg1", 1, "arg2", 2);
+ break;
+ case TT_TRACE_EVENT_COPY_INSTANT0:
+ TRACE_EVENT_COPY_INSTANT0(kTraceTestCategory,
+ "TT_TRACE_EVENT_COPY_INSTANT0");
+ break;
+ case TT_TRACE_EVENT_COPY_INSTANT1:
+ TRACE_EVENT_COPY_INSTANT1(kTraceTestCategory,
+ "TT_TRACE_EVENT_COPY_INSTANT1", "arg1", 1);
+ break;
+ case TT_TRACE_EVENT_COPY_INSTANT2:
+ TRACE_EVENT_COPY_INSTANT2(kTraceTestCategory,
+ "TT_TRACE_EVENT_COPY_INSTANT2", "arg1", 1,
+ "arg2", 2);
+ break;
+ case TT_TRACE_EVENT_BEGIN0:
+ TRACE_EVENT_BEGIN0(kTraceTestCategory, "TT_TRACE_EVENT_BEGIN0");
+ break;
+ case TT_TRACE_EVENT_BEGIN1:
+ TRACE_EVENT_BEGIN1(kTraceTestCategory, "TT_TRACE_EVENT_BEGIN1", "arg1",
+ 1);
+ break;
+ case TT_TRACE_EVENT_BEGIN2:
+ TRACE_EVENT_BEGIN2(kTraceTestCategory, "TT_TRACE_EVENT_BEGIN2", "arg1",
+ 1, "arg2", 2);
+ break;
+ case TT_TRACE_EVENT_COPY_BEGIN0:
+ TRACE_EVENT_COPY_BEGIN0(kTraceTestCategory,
+ "TT_TRACE_EVENT_COPY_BEGIN0");
+ break;
+ case TT_TRACE_EVENT_COPY_BEGIN1:
+ TRACE_EVENT_COPY_BEGIN1(kTraceTestCategory,
+ "TT_TRACE_EVENT_COPY_BEGIN1", "arg1", 1);
+ break;
+ case TT_TRACE_EVENT_COPY_BEGIN2:
+ TRACE_EVENT_COPY_BEGIN2(kTraceTestCategory,
+ "TT_TRACE_EVENT_COPY_BEGIN2", "arg1", 1, "arg2",
+ 2);
+ break;
+ case TT_TRACE_EVENT_END0:
+ TRACE_EVENT_BEGIN0(kTraceTestCategory, "TT_TRACE_EVENT_END0");
+ TRACE_EVENT_END0(kTraceTestCategory, "TT_TRACE_EVENT_END0");
+ break;
+ case TT_TRACE_EVENT_END1:
+ TRACE_EVENT_BEGIN1(kTraceTestCategory, "TT_TRACE_EVENT_END1", "arg1",
+ 1);
+ TRACE_EVENT_END1(kTraceTestCategory, "TT_TRACE_EVENT_END1", "arg1", 1);
+ break;
+ case TT_TRACE_EVENT_END2:
+ TRACE_EVENT_BEGIN2(kTraceTestCategory, "TT_TRACE_EVENT_END2", "arg1", 1,
+ "arg2", 2);
+ TRACE_EVENT_END2(kTraceTestCategory, "TT_TRACE_EVENT_END2", "arg1", 1,
+ "arg2", 2);
+ break;
+ case TT_TRACE_EVENT_COPY_END0:
+ TRACE_EVENT_COPY_BEGIN0(kTraceTestCategory, "TT_TRACE_EVENT_COPY_END0");
+ TRACE_EVENT_COPY_END0(kTraceTestCategory, "TT_TRACE_EVENT_COPY_END0");
+ break;
+ case TT_TRACE_EVENT_COPY_END1:
+ TRACE_EVENT_COPY_BEGIN1(kTraceTestCategory, "TT_TRACE_EVENT_COPY_END1",
+ "arg1", 1);
+ TRACE_EVENT_COPY_END1(kTraceTestCategory, "TT_TRACE_EVENT_COPY_END1",
+ "arg1", 1);
+ break;
+ case TT_TRACE_EVENT_COPY_END2:
+ TRACE_EVENT_COPY_BEGIN2(kTraceTestCategory, "TT_TRACE_EVENT_COPY_END2",
+ "arg1", 1, "arg2", 2);
+ TRACE_EVENT_COPY_END2(kTraceTestCategory, "TT_TRACE_EVENT_COPY_END2",
+ "arg1", 1, "arg2", 2);
+ break;
+ case TT_TRACE_COUNTER1:
+ TRACE_COUNTER1(kTraceTestCategory, "TT_TRACE_COUNTER1", 5);
+ break;
+ case TT_TRACE_COPY_COUNTER1:
+ TRACE_COPY_COUNTER1(kTraceTestCategory, "TT_TRACE_COPY_COUNTER1", 5);
+ break;
+ case TT_TRACE_COUNTER2:
+ TRACE_COUNTER2(kTraceTestCategory, "TT_TRACE_COUNTER2", "val1", 5,
+ "val2", 10);
+ break;
+ case TT_TRACE_COPY_COUNTER2:
+ TRACE_COPY_COUNTER2(kTraceTestCategory, "TT_TRACE_COPY_COUNTER2",
+ "val1", 5, "val2", 10);
+ break;
+ case TT_TRACE_COUNTER_ID1:
+ TRACE_COUNTER_ID1(kTraceTestCategory, "TT_TRACE_COUNTER_ID1", 100, 5);
+ break;
+ case TT_TRACE_COPY_COUNTER_ID1:
+ TRACE_COPY_COUNTER_ID1(kTraceTestCategory, "TT_TRACE_COPY_COUNTER_ID1",
+ 100, 5);
+ break;
+ case TT_TRACE_COUNTER_ID2:
+ TRACE_COUNTER_ID2(kTraceTestCategory, "TT_TRACE_COUNTER_ID2", 100,
+ "val1", 5, "val2", 10);
+ break;
+ case TT_TRACE_COPY_COUNTER_ID2:
+ TRACE_COPY_COUNTER_ID2(kTraceTestCategory, "TT_TRACE_COPY_COUNTER_ID2",
+ 100, "val1", 5, "val2", 10);
+ break;
+ case TT_TRACE_EVENT_ASYNC_BEGIN0:
+ TRACE_EVENT_ASYNC_BEGIN0(kTraceTestCategory,
+ "TT_TRACE_EVENT_ASYNC_BEGIN0", 100);
+ break;
+ case TT_TRACE_EVENT_ASYNC_BEGIN1:
+ TRACE_EVENT_ASYNC_BEGIN1(kTraceTestCategory,
+ "TT_TRACE_EVENT_ASYNC_BEGIN1", 100, "arg1", 1);
+ break;
+ case TT_TRACE_EVENT_ASYNC_BEGIN2:
+ TRACE_EVENT_ASYNC_BEGIN2(kTraceTestCategory,
+ "TT_TRACE_EVENT_ASYNC_BEGIN2", 100, "arg1", 1,
+ "arg2", 2);
+ break;
+ case TT_TRACE_EVENT_COPY_ASYNC_BEGIN0:
+ TRACE_EVENT_COPY_ASYNC_BEGIN0(kTraceTestCategory,
+ "TT_TRACE_EVENT_COPY_ASYNC_BEGIN0", 100);
+ break;
+ case TT_TRACE_EVENT_COPY_ASYNC_BEGIN1:
+ TRACE_EVENT_COPY_ASYNC_BEGIN1(kTraceTestCategory,
+ "TT_TRACE_EVENT_COPY_ASYNC_BEGIN1", 100,
+ "arg1", 1);
+ break;
+ case TT_TRACE_EVENT_COPY_ASYNC_BEGIN2:
+ TRACE_EVENT_COPY_ASYNC_BEGIN2(kTraceTestCategory,
+ "TT_TRACE_EVENT_COPY_ASYNC_BEGIN2", 100,
+ "arg1", 1, "arg2", 2);
+ break;
+ case TT_TRACE_EVENT_ASYNC_STEP_INTO0:
+ TRACE_EVENT_ASYNC_STEP_INTO0(
+ kTraceTestCategory, "TT_TRACE_EVENT_ASYNC_STEP_INTO0", 100, 1000);
+ break;
+ case TT_TRACE_EVENT_ASYNC_STEP_INTO1:
+ TRACE_EVENT_ASYNC_STEP_INTO1(kTraceTestCategory,
+ "TT_TRACE_EVENT_ASYNC_STEP_INTO1", 100,
+ 1000, "arg1", 1);
+ break;
+ case TT_TRACE_EVENT_COPY_ASYNC_STEP_INTO0:
+ TRACE_EVENT_COPY_ASYNC_STEP_INTO0(
+ kTraceTestCategory, "TT_TRACE_EVENT_COPY_ASYNC_STEP_INTO0", 100,
+ 1000);
+ break;
+ case TT_TRACE_EVENT_COPY_ASYNC_STEP_INTO1:
+ TRACE_EVENT_COPY_ASYNC_STEP_INTO1(
+ kTraceTestCategory, "TT_TRACE_EVENT_COPY_ASYNC_STEP_INTO1", 100,
+ 1000, "arg1", 1);
+ break;
+ case TT_TRACE_EVENT_ASYNC_STEP_PAST0:
+ TRACE_EVENT_ASYNC_STEP_PAST0(
+ kTraceTestCategory, "TT_TRACE_EVENT_ASYNC_STEP_PAST0", 100, 1000);
+ break;
+ case TT_TRACE_EVENT_ASYNC_STEP_PAST1:
+ TRACE_EVENT_ASYNC_STEP_PAST1(kTraceTestCategory,
+ "TT_TRACE_EVENT_ASYNC_STEP_PAST1", 100,
+ 1000, "arg1", 1);
+ break;
+ case TT_TRACE_EVENT_COPY_ASYNC_STEP_PAST0:
+ TRACE_EVENT_COPY_ASYNC_STEP_PAST0(
+ kTraceTestCategory, "TT_TRACE_EVENT_COPY_ASYNC_STEP_PAST0", 100,
+ 1000);
+ break;
+ case TT_TRACE_EVENT_COPY_ASYNC_STEP_PAST1:
+ TRACE_EVENT_COPY_ASYNC_STEP_PAST1(
+ kTraceTestCategory, "TT_TRACE_EVENT_COPY_ASYNC_STEP_PAST1", 100,
+ 1000, "arg1", 1);
+ break;
+ case TT_TRACE_EVENT_ASYNC_END0:
+ TRACE_EVENT_ASYNC_BEGIN0(kTraceTestCategory,
+ "TT_TRACE_EVENT_ASYNC_END0", 100);
+ TRACE_EVENT_ASYNC_END0(kTraceTestCategory, "TT_TRACE_EVENT_ASYNC_END0",
+ 100);
+ break;
+ case TT_TRACE_EVENT_ASYNC_END1:
+ TRACE_EVENT_ASYNC_BEGIN1(kTraceTestCategory,
+ "TT_TRACE_EVENT_ASYNC_END1", 100, "arg1", 1);
+ TRACE_EVENT_ASYNC_END1(kTraceTestCategory, "TT_TRACE_EVENT_ASYNC_END1",
+ 100, "arg1", 1);
+ break;
+ case TT_TRACE_EVENT_ASYNC_END2:
+ TRACE_EVENT_ASYNC_BEGIN2(kTraceTestCategory,
+ "TT_TRACE_EVENT_ASYNC_END2", 100, "arg1", 1,
+ "arg2", 2);
+ TRACE_EVENT_ASYNC_END2(kTraceTestCategory, "TT_TRACE_EVENT_ASYNC_END2",
+ 100, "arg1", 1, "arg2", 2);
+ break;
+ case TT_TRACE_EVENT_COPY_ASYNC_END0:
+ TRACE_EVENT_COPY_ASYNC_BEGIN0(kTraceTestCategory,
+ "TT_TRACE_EVENT_COPY_ASYNC_END0", 100);
+ TRACE_EVENT_COPY_ASYNC_END0(kTraceTestCategory,
+ "TT_TRACE_EVENT_COPY_ASYNC_END0", 100);
+ break;
+ case TT_TRACE_EVENT_COPY_ASYNC_END1:
+ TRACE_EVENT_COPY_ASYNC_BEGIN1(kTraceTestCategory,
+ "TT_TRACE_EVENT_COPY_ASYNC_END1", 100,
+ "arg1", 1);
+ TRACE_EVENT_COPY_ASYNC_END1(kTraceTestCategory,
+ "TT_TRACE_EVENT_COPY_ASYNC_END1", 100,
+ "arg1", 1);
+ break;
+ case TT_TRACE_EVENT_COPY_ASYNC_END2:
+ TRACE_EVENT_COPY_ASYNC_BEGIN2(kTraceTestCategory,
+ "TT_TRACE_EVENT_COPY_ASYNC_END2", 100,
+ "arg1", 1, "arg2", 2);
+ TRACE_EVENT_COPY_ASYNC_END2(kTraceTestCategory,
+ "TT_TRACE_EVENT_COPY_ASYNC_END2", 100,
+ "arg1", 1, "arg2", 2);
+ break;
+ }
+
+ // Results in a call to OnEndTracingComplete.
+ CefEndTracing(CefString(), this);
+ }
+
+ void OnEndTracingComplete(const CefString& tracing_file) override {
+ EXPECT_UI_THREAD();
+
+ CefPostTask(TID_FILE_USER_VISIBLE,
+ base::BindOnce(&TracingTestHandler::ReadTracingFile, this,
+ tracing_file));
+ }
+
+ void ReadTracingFile(const std::string& file_path) {
+ EXPECT_FILE_THREAD();
+
+ EXPECT_TRUE(client::file_util::ReadFileToString(file_path, &trace_data_));
+ EXPECT_TRUE(CefDeleteFile(file_path, false));
+
+ completion_event_->Signal();
+ }
+
+ private:
+ ~TracingTestHandler() override {}
+
+ // Handle used to notify when the test is complete.
+ CefRefPtr<CefWaitableEvent> completion_event_;
+
+ const char* trace_type_;
+ TracingTestType type_;
+ std::string trace_data_;
+
+ IMPLEMENT_REFCOUNTING(TracingTestHandler);
+};
+
+// Helper for defining tracing tests.
+#define TRACING_TEST(name, test_type) \
+ TEST(TracingTest, name) { \
+ CefRefPtr<TracingTestHandler> handler = \
+ new TracingTestHandler(test_type, #test_type); \
+ handler->ExecuteTest(); \
+ }
+
+// Define the tests.
+TRACING_TEST(TraceEvent0, TT_TRACE_EVENT0)
+TRACING_TEST(TraceEvent1, TT_TRACE_EVENT1)
+TRACING_TEST(TraceEvent2, TT_TRACE_EVENT2)
+TRACING_TEST(TraceEventInstant0, TT_TRACE_EVENT_INSTANT0)
+TRACING_TEST(TraceEventInstant1, TT_TRACE_EVENT_INSTANT1)
+TRACING_TEST(TraceEventInstant2, TT_TRACE_EVENT_INSTANT2)
+TRACING_TEST(TraceEventCopyInstant0, TT_TRACE_EVENT_COPY_INSTANT0)
+TRACING_TEST(TraceEventCopyInstant1, TT_TRACE_EVENT_COPY_INSTANT1)
+TRACING_TEST(TraceEventCopyInstant2, TT_TRACE_EVENT_COPY_INSTANT2)
+TRACING_TEST(TraceEventBegin0, TT_TRACE_EVENT_BEGIN0)
+TRACING_TEST(TraceEventBegin1, TT_TRACE_EVENT_BEGIN1)
+TRACING_TEST(TraceEventBegin2, TT_TRACE_EVENT_BEGIN2)
+TRACING_TEST(TraceEventCopyBegin0, TT_TRACE_EVENT_COPY_BEGIN0)
+TRACING_TEST(TraceEventCopyBegin1, TT_TRACE_EVENT_COPY_BEGIN1)
+TRACING_TEST(TraceEventCopyBegin2, TT_TRACE_EVENT_COPY_BEGIN2)
+TRACING_TEST(TraceEventEnd0, TT_TRACE_EVENT_END0)
+TRACING_TEST(TraceEventEnd1, TT_TRACE_EVENT_END1)
+TRACING_TEST(TraceEventEnd2, TT_TRACE_EVENT_END2)
+TRACING_TEST(TraceEventCopyEnd0, TT_TRACE_EVENT_COPY_END0)
+TRACING_TEST(TraceEventCopyEnd1, TT_TRACE_EVENT_COPY_END1)
+TRACING_TEST(TraceEventCopyEnd2, TT_TRACE_EVENT_COPY_END1)
+TRACING_TEST(TraceCounter1, TT_TRACE_COUNTER1)
+TRACING_TEST(TraceCopyCounter1, TT_TRACE_COPY_COUNTER1)
+TRACING_TEST(TraceCounter2, TT_TRACE_COUNTER2)
+TRACING_TEST(TraceCopyCounter2, TT_TRACE_COPY_COUNTER2)
+TRACING_TEST(TraceCounterId1, TT_TRACE_COUNTER_ID1)
+TRACING_TEST(TraceCopyCounterId1, TT_TRACE_COPY_COUNTER_ID1)
+TRACING_TEST(TraceCounterId2, TT_TRACE_COUNTER_ID2)
+TRACING_TEST(TraceCopyCounterId2, TT_TRACE_COPY_COUNTER_ID1)
+TRACING_TEST(TraceEventAsyncBegin0, TT_TRACE_EVENT_ASYNC_BEGIN0)
+TRACING_TEST(TraceEventAsyncBegin1, TT_TRACE_EVENT_ASYNC_BEGIN1)
+TRACING_TEST(TraceEventAsyncBegin2, TT_TRACE_EVENT_ASYNC_BEGIN2)
+TRACING_TEST(TraceEventCopyAsyncBegin0, TT_TRACE_EVENT_COPY_ASYNC_BEGIN0)
+TRACING_TEST(TraceEventCopyAsyncBegin1, TT_TRACE_EVENT_COPY_ASYNC_BEGIN1)
+TRACING_TEST(TraceEventCopyAsyncBegin2, TT_TRACE_EVENT_COPY_ASYNC_BEGIN2)
+TRACING_TEST(TraceEventAsyncStepInto0, TT_TRACE_EVENT_ASYNC_STEP_INTO0)
+TRACING_TEST(TraceEventAsyncStepInto1, TT_TRACE_EVENT_ASYNC_STEP_INTO1)
+TRACING_TEST(TraceEventCopyAsyncStepInto0, TT_TRACE_EVENT_COPY_ASYNC_STEP_INTO0)
+TRACING_TEST(TraceEventCopyAsyncStepInto1, TT_TRACE_EVENT_COPY_ASYNC_STEP_INTO1)
+TRACING_TEST(TraceEventAsyncStepPast0, TT_TRACE_EVENT_ASYNC_STEP_PAST0)
+TRACING_TEST(TraceEventAsyncStepPast1, TT_TRACE_EVENT_ASYNC_STEP_PAST1)
+TRACING_TEST(TraceEventCopyAsyncStepPast0, TT_TRACE_EVENT_COPY_ASYNC_STEP_PAST0)
+TRACING_TEST(TraceEventCopyAsyncStepPast1, TT_TRACE_EVENT_COPY_ASYNC_STEP_PAST1)
+TRACING_TEST(TraceEventAsyncEnd0, TT_TRACE_EVENT_ASYNC_END0)
+TRACING_TEST(TraceEventAsyncEnd1, TT_TRACE_EVENT_ASYNC_END1)
+TRACING_TEST(TraceEventAsyncEnd2, TT_TRACE_EVENT_ASYNC_END2)
+TRACING_TEST(TraceEventCopyAsyncEnd0, TT_TRACE_EVENT_COPY_ASYNC_END0)
+TRACING_TEST(TraceEventCopyAsyncEnd1, TT_TRACE_EVENT_COPY_ASYNC_END1)
+TRACING_TEST(TraceEventCopyAsyncEnd2, TT_TRACE_EVENT_COPY_ASYNC_END2)
+
+TEST(TracingTest, NowFromSystemTraceTime) {
+ int64 val = CefNowFromSystemTraceTime();
+ EXPECT_NE(val, 0);
+}
diff --git a/tests/ceftests/track_callback.h b/tests/ceftests/track_callback.h
new file mode 100644
index 00000000..76013026
--- /dev/null
+++ b/tests/ceftests/track_callback.h
@@ -0,0 +1,21 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFTESTS_TRACK_CALLBACK_H_
+#define CEF_TESTS_CEFTESTS_TRACK_CALLBACK_H_
+#pragma once
+
+class TrackCallback {
+ public:
+ TrackCallback() : gotit_(false) {}
+ void yes() { gotit_ = true; }
+ bool isSet() { return gotit_; }
+ void reset() { gotit_ = false; }
+ operator bool() const { return gotit_; }
+
+ protected:
+ bool gotit_;
+};
+
+#endif // CEF_TESTS_CEFTESTS_TRACK_CALLBACK_H_
diff --git a/tests/ceftests/translator_unittest.cc b/tests/ceftests/translator_unittest.cc
new file mode 100644
index 00000000..12e05ece
--- /dev/null
+++ b/tests/ceftests/translator_unittest.cc
@@ -0,0 +1,736 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "include/test/cef_translator_test.h"
+#include "tests/ceftests/test_handler.h"
+#include "tests/gtest/include/gtest/gtest.h"
+
+// Test getting/setting primitive types.
+TEST(TranslatorTest, Primitive) {
+ CefRefPtr<CefTranslatorTest> obj = CefTranslatorTest::Create();
+ obj->GetVoid(); // Does nothing, but shouldn't crash.
+ EXPECT_EQ(TEST_BOOL_VAL, obj->GetBool());
+ EXPECT_EQ(TEST_INT_VAL, obj->GetInt());
+ EXPECT_EQ(TEST_DOUBLE_VAL, obj->GetDouble());
+ EXPECT_EQ(TEST_LONG_VAL, obj->GetLong());
+ EXPECT_EQ(TEST_SIZET_VAL, obj->GetSizet());
+ EXPECT_TRUE(obj->SetVoid()); // Does nothing, but shouldn't crash.
+ EXPECT_TRUE(obj->SetBool(TEST_BOOL_VAL));
+ EXPECT_TRUE(obj->SetInt(TEST_INT_VAL));
+ EXPECT_TRUE(obj->SetDouble(TEST_DOUBLE_VAL));
+ EXPECT_TRUE(obj->SetLong(TEST_LONG_VAL));
+ EXPECT_TRUE(obj->SetSizet(TEST_SIZET_VAL));
+
+ // Only one reference to the object should exist.
+ EXPECT_TRUE(obj->HasOneRef());
+}
+
+// Test getting/setting primitive list types.
+TEST(TranslatorTest, PrimitiveList) {
+ CefRefPtr<CefTranslatorTest> obj = CefTranslatorTest::Create();
+
+ std::vector<int> list;
+ list.push_back(TEST_INT_VAL);
+ list.push_back(TEST_INT_VAL2);
+ EXPECT_TRUE(obj->SetIntList(list));
+
+ list.clear();
+ EXPECT_TRUE(obj->GetIntListByRef(list));
+ EXPECT_EQ(2U, list.size());
+ EXPECT_EQ(TEST_INT_VAL, list[0]);
+ EXPECT_EQ(TEST_INT_VAL2, list[1]);
+
+ // Only one reference to the object should exist.
+ EXPECT_TRUE(obj->HasOneRef());
+}
+
+// Test getting/setting string types.
+TEST(TranslatorTest, String) {
+ CefRefPtr<CefTranslatorTest> obj = CefTranslatorTest::Create();
+ EXPECT_STREQ(TEST_STRING_VAL, obj->GetString().ToString().c_str());
+ EXPECT_TRUE(obj->SetString(TEST_STRING_VAL));
+
+ CefString str;
+ obj->GetStringByRef(str);
+ EXPECT_STREQ(TEST_STRING_VAL, str.ToString().c_str());
+
+ // Only one reference to the object should exist.
+ EXPECT_TRUE(obj->HasOneRef());
+}
+
+// Test getting/setting string list types.
+TEST(TranslatorTest, StringList) {
+ CefRefPtr<CefTranslatorTest> obj = CefTranslatorTest::Create();
+
+ std::vector<CefString> list;
+ list.push_back(TEST_STRING_VAL);
+ list.push_back(TEST_STRING_VAL2);
+ list.push_back(TEST_STRING_VAL3);
+ EXPECT_TRUE(obj->SetStringList(list));
+
+ list.clear();
+ EXPECT_TRUE(obj->GetStringListByRef(list));
+ EXPECT_EQ(3U, list.size());
+ EXPECT_STREQ(TEST_STRING_VAL, list[0].ToString().c_str());
+ EXPECT_STREQ(TEST_STRING_VAL2, list[1].ToString().c_str());
+ EXPECT_STREQ(TEST_STRING_VAL3, list[2].ToString().c_str());
+
+ // Only one reference to the object should exist.
+ EXPECT_TRUE(obj->HasOneRef());
+}
+
+// Test getting/setting string map types.
+TEST(TranslatorTest, StringMap) {
+ CefRefPtr<CefTranslatorTest> obj = CefTranslatorTest::Create();
+
+ CefTranslatorTest::StringMap map;
+ map.insert(std::make_pair(TEST_STRING_KEY, TEST_STRING_VAL));
+ map.insert(std::make_pair(TEST_STRING_KEY2, TEST_STRING_VAL2));
+ map.insert(std::make_pair(TEST_STRING_KEY3, TEST_STRING_VAL3));
+ EXPECT_TRUE(obj->SetStringMap(map));
+
+ map.clear();
+ EXPECT_TRUE(obj->GetStringMapByRef(map));
+ EXPECT_EQ(3U, map.size());
+
+ CefTranslatorTest::StringMap::const_iterator it;
+
+ it = map.find(TEST_STRING_KEY);
+ EXPECT_TRUE(it != map.end() && it->second == TEST_STRING_VAL);
+ it = map.find(TEST_STRING_KEY2);
+ EXPECT_TRUE(it != map.end() && it->second == TEST_STRING_VAL2);
+ it = map.find(TEST_STRING_KEY3);
+ EXPECT_TRUE(it != map.end() && it->second == TEST_STRING_VAL3);
+
+ // Only one reference to the object should exist.
+ EXPECT_TRUE(obj->HasOneRef());
+}
+
+// Test getting/setting string multimap types.
+TEST(TranslatorTest, StringMultimap) {
+ CefRefPtr<CefTranslatorTest> obj = CefTranslatorTest::Create();
+
+ CefTranslatorTest::StringMultimap map;
+ map.insert(std::make_pair(TEST_STRING_KEY, TEST_STRING_VAL));
+ map.insert(std::make_pair(TEST_STRING_KEY2, TEST_STRING_VAL2));
+ map.insert(std::make_pair(TEST_STRING_KEY3, TEST_STRING_VAL3));
+ EXPECT_TRUE(obj->SetStringMultimap(map));
+
+ map.clear();
+ EXPECT_TRUE(obj->GetStringMultimapByRef(map));
+ EXPECT_EQ(3U, map.size());
+
+ CefTranslatorTest::StringMultimap::const_iterator it;
+
+ it = map.find(TEST_STRING_KEY);
+ EXPECT_TRUE(it != map.end() && it->second == TEST_STRING_VAL);
+ it = map.find(TEST_STRING_KEY2);
+ EXPECT_TRUE(it != map.end() && it->second == TEST_STRING_VAL2);
+ it = map.find(TEST_STRING_KEY3);
+ EXPECT_TRUE(it != map.end() && it->second == TEST_STRING_VAL3);
+
+ // Only one reference to the object should exist.
+ EXPECT_TRUE(obj->HasOneRef());
+}
+
+// Test getting/setting struct types.
+TEST(TranslatorTest, Struct) {
+ CefRefPtr<CefTranslatorTest> obj = CefTranslatorTest::Create();
+
+ CefPoint point(TEST_X_VAL, TEST_Y_VAL);
+ EXPECT_EQ(point, obj->GetPoint());
+ EXPECT_TRUE(obj->SetPoint(point));
+
+ CefPoint point2;
+ obj->GetPointByRef(point2);
+ EXPECT_EQ(point, point2);
+
+ // Only one reference to the object should exist.
+ EXPECT_TRUE(obj->HasOneRef());
+}
+
+// Test getting/setting struct list types.
+TEST(TranslatorTest, StructList) {
+ CefRefPtr<CefTranslatorTest> obj = CefTranslatorTest::Create();
+
+ std::vector<CefPoint> list;
+ list.push_back(CefPoint(TEST_X_VAL, TEST_Y_VAL));
+ list.push_back(CefPoint(TEST_X_VAL2, TEST_Y_VAL2));
+ EXPECT_TRUE(obj->SetPointList(list));
+
+ list.clear();
+ EXPECT_TRUE(obj->GetPointListByRef(list));
+ EXPECT_EQ(2U, list.size());
+ EXPECT_EQ(CefPoint(TEST_X_VAL, TEST_Y_VAL), list[0]);
+ EXPECT_EQ(CefPoint(TEST_X_VAL2, TEST_Y_VAL2), list[1]);
+
+ // Only one reference to the object should exist.
+ EXPECT_TRUE(obj->HasOneRef());
+}
+
+// Test getting/setting library-side RefPtr types.
+TEST(TranslatorTest, RefPtrLibrary) {
+ CefRefPtr<CefTranslatorTest> obj = CefTranslatorTest::Create();
+
+ const int kTestVal = 12;
+ CefRefPtr<CefTranslatorTestRefPtrLibrary> test_obj =
+ CefTranslatorTestRefPtrLibrary::Create(kTestVal);
+ EXPECT_EQ(kTestVal, test_obj->GetValue());
+ int retval = obj->SetRefPtrLibrary(test_obj);
+ EXPECT_EQ(kTestVal, retval);
+ EXPECT_EQ(kTestVal, test_obj->GetValue());
+
+ const int kTestVal2 = 30;
+ CefRefPtr<CefTranslatorTestRefPtrLibrary> test_obj2 =
+ obj->GetRefPtrLibrary(kTestVal2);
+ EXPECT_EQ(kTestVal2, test_obj2->GetValue());
+ int retval2 = obj->SetRefPtrLibrary(test_obj2);
+ EXPECT_EQ(kTestVal2, retval2);
+ EXPECT_EQ(kTestVal2, test_obj2->GetValue());
+
+ // Only one reference to the object should exist.
+ EXPECT_TRUE(obj->HasOneRef());
+ EXPECT_TRUE(test_obj->HasOneRef());
+ EXPECT_TRUE(test_obj2->HasOneRef());
+}
+
+// Test getting/setting inherited library-side RefPtr types.
+TEST(TranslatorTest, RefPtrLibraryInherit) {
+ CefRefPtr<CefTranslatorTest> obj = CefTranslatorTest::Create();
+
+ const int kTestVal = 12;
+ const int kTestVal2 = 40;
+ CefRefPtr<CefTranslatorTestRefPtrLibraryChild> test_obj =
+ CefTranslatorTestRefPtrLibraryChild::Create(kTestVal, kTestVal2);
+ EXPECT_EQ(kTestVal, test_obj->GetValue());
+ EXPECT_EQ(kTestVal2, test_obj->GetOtherValue());
+ int retval = obj->SetRefPtrLibrary(test_obj);
+ EXPECT_EQ(kTestVal, retval);
+ EXPECT_EQ(kTestVal, test_obj->GetValue());
+ EXPECT_EQ(kTestVal2, test_obj->GetOtherValue());
+
+ EXPECT_EQ(kTestVal, obj->SetChildRefPtrLibrary(test_obj));
+ EXPECT_EQ(kTestVal,
+ obj->SetChildRefPtrLibraryAndReturnParent(test_obj)->GetValue());
+
+ const int kTestVal3 = 100;
+ CefRefPtr<CefTranslatorTestRefPtrLibraryChildChild> test_obj2 =
+ CefTranslatorTestRefPtrLibraryChildChild::Create(kTestVal, kTestVal2,
+ kTestVal3);
+ EXPECT_EQ(kTestVal, test_obj2->GetValue());
+ EXPECT_EQ(kTestVal2, test_obj2->GetOtherValue());
+ EXPECT_EQ(kTestVal3, test_obj2->GetOtherOtherValue());
+ int retval2 = obj->SetRefPtrLibrary(test_obj2);
+ EXPECT_EQ(kTestVal, retval2);
+ EXPECT_EQ(kTestVal, test_obj2->GetValue());
+ EXPECT_EQ(kTestVal2, test_obj2->GetOtherValue());
+ EXPECT_EQ(kTestVal3, test_obj2->GetOtherOtherValue());
+
+ EXPECT_EQ(kTestVal, obj->SetChildRefPtrLibrary(test_obj2));
+ EXPECT_EQ(kTestVal,
+ obj->SetChildRefPtrLibraryAndReturnParent(test_obj2)->GetValue());
+
+ // Only one reference to the object should exist.
+ EXPECT_TRUE(obj->HasOneRef());
+ EXPECT_TRUE(test_obj->HasOneRef());
+ EXPECT_TRUE(test_obj2->HasOneRef());
+}
+
+// Test getting/setting library-side RefPtr list types.
+TEST(TranslatorTest, RefPtrLibraryList) {
+ CefRefPtr<CefTranslatorTest> obj = CefTranslatorTest::Create();
+
+ const int kVal1 = 34;
+ const int kVal2 = 10;
+
+ CefRefPtr<CefTranslatorTestRefPtrLibrary> val1 =
+ CefTranslatorTestRefPtrLibrary::Create(kVal1);
+ CefRefPtr<CefTranslatorTestRefPtrLibrary> val2 =
+ CefTranslatorTestRefPtrLibraryChild::Create(kVal2, 0);
+
+ std::vector<CefRefPtr<CefTranslatorTestRefPtrLibrary>> list;
+ list.push_back(val1);
+ list.push_back(val2);
+ EXPECT_TRUE(obj->SetRefPtrLibraryList(list, kVal1, kVal2));
+
+ list.clear();
+ EXPECT_TRUE(obj->GetRefPtrLibraryListByRef(list, kVal1, kVal2));
+ EXPECT_EQ(2U, list.size());
+ EXPECT_EQ(kVal1, list[0]->GetValue());
+ EXPECT_EQ(kVal2, list[1]->GetValue());
+
+ list.clear();
+
+ // Only one reference to the object should exist.
+ EXPECT_TRUE(obj->HasOneRef());
+ EXPECT_TRUE(val1->HasOneRef());
+ EXPECT_TRUE(val2->HasOneRef());
+}
+
+namespace {
+
+class TranslatorTestRefPtrClient : public CefTranslatorTestRefPtrClient {
+ public:
+ explicit TranslatorTestRefPtrClient(const int val) : val_(val) {}
+
+ virtual int GetValue() override { return val_; }
+
+ private:
+ const int val_;
+
+ IMPLEMENT_REFCOUNTING(TranslatorTestRefPtrClient);
+ DISALLOW_COPY_AND_ASSIGN(TranslatorTestRefPtrClient);
+};
+
+class TranslatorTestRefPtrClientChild
+ : public CefTranslatorTestRefPtrClientChild {
+ public:
+ TranslatorTestRefPtrClientChild(const int val, const int other_val)
+ : val_(val), other_val_(other_val) {}
+
+ virtual int GetValue() override { return val_; }
+
+ virtual int GetOtherValue() override { return other_val_; }
+
+ private:
+ const int val_;
+ const int other_val_;
+
+ IMPLEMENT_REFCOUNTING(TranslatorTestRefPtrClientChild);
+ DISALLOW_COPY_AND_ASSIGN(TranslatorTestRefPtrClientChild);
+};
+
+} // namespace
+
+// Test getting/setting client-side RefPtr types.
+TEST(TranslatorTest, RefPtrClient) {
+ CefRefPtr<CefTranslatorTest> obj = CefTranslatorTest::Create();
+
+ const int kTestVal = 12;
+
+ CefRefPtr<TranslatorTestRefPtrClient> test_obj =
+ new TranslatorTestRefPtrClient(kTestVal);
+ EXPECT_EQ(kTestVal, test_obj->GetValue());
+ EXPECT_EQ(kTestVal, obj->SetRefPtrClient(test_obj.get()));
+ CefRefPtr<CefTranslatorTestRefPtrClient> handler =
+ obj->SetRefPtrClientAndReturn(test_obj.get());
+ EXPECT_EQ(test_obj.get(), handler.get());
+ EXPECT_EQ(kTestVal, handler->GetValue());
+ handler = nullptr;
+
+ // Only one reference to the object should exist.
+ EXPECT_TRUE(obj->HasOneRef());
+ EXPECT_TRUE(test_obj->HasOneRef());
+}
+
+// Test getting/setting inherited client-side RefPtr types.
+TEST(TranslatorTest, RefPtrClientInherit) {
+ CefRefPtr<CefTranslatorTest> obj = CefTranslatorTest::Create();
+
+ const int kTestVal = 12;
+ const int kTestVal2 = 86;
+
+ CefRefPtr<TranslatorTestRefPtrClientChild> test_obj =
+ new TranslatorTestRefPtrClientChild(kTestVal, kTestVal2);
+ EXPECT_EQ(kTestVal, test_obj->GetValue());
+ EXPECT_EQ(kTestVal2, test_obj->GetOtherValue());
+ int retval = obj->SetRefPtrClient(test_obj);
+ EXPECT_EQ(kTestVal, retval);
+ EXPECT_EQ(kTestVal, test_obj->GetValue());
+ EXPECT_EQ(kTestVal2, test_obj->GetOtherValue());
+
+ EXPECT_EQ(kTestVal, obj->SetChildRefPtrClient(test_obj));
+ CefRefPtr<CefTranslatorTestRefPtrClient> handler =
+ obj->SetChildRefPtrClientAndReturnParent(test_obj);
+ EXPECT_EQ(kTestVal, handler->GetValue());
+ EXPECT_EQ(test_obj.get(), handler.get());
+ handler = nullptr;
+
+ // Only one reference to the object should exist.
+ EXPECT_TRUE(obj->HasOneRef());
+ EXPECT_TRUE(test_obj->HasOneRef());
+}
+
+// Test getting/setting client-side RefPtr list types.
+TEST(TranslatorTest, RefPtrClientList) {
+ CefRefPtr<CefTranslatorTest> obj = CefTranslatorTest::Create();
+
+ const int kVal1 = 34;
+ const int kVal2 = 10;
+
+ CefRefPtr<CefTranslatorTestRefPtrClient> val1 =
+ new TranslatorTestRefPtrClient(kVal1);
+ CefRefPtr<CefTranslatorTestRefPtrClient> val2 =
+ new TranslatorTestRefPtrClientChild(kVal2, 0);
+
+ std::vector<CefRefPtr<CefTranslatorTestRefPtrClient>> list;
+ list.push_back(val1);
+ list.push_back(val2);
+ EXPECT_TRUE(obj->SetRefPtrClientList(list, kVal1, kVal2));
+
+ list.clear();
+ EXPECT_TRUE(obj->GetRefPtrClientListByRef(list, val1, val2));
+ EXPECT_EQ(2U, list.size());
+ EXPECT_EQ(kVal1, list[0]->GetValue());
+ EXPECT_EQ(val1.get(), list[0].get());
+ EXPECT_EQ(kVal2, list[1]->GetValue());
+ EXPECT_EQ(val2.get(), list[1].get());
+
+ list.clear();
+
+ // Only one reference to the object should exist.
+ EXPECT_TRUE(obj->HasOneRef());
+ EXPECT_TRUE(val1->HasOneRef());
+ EXPECT_TRUE(val2->HasOneRef());
+}
+
+// Test getting/setting library-side OwnPtr types.
+TEST(TranslatorTest, OwnPtrLibrary) {
+ CefRefPtr<CefTranslatorTest> obj = CefTranslatorTest::Create();
+
+ const int kTestVal = 12;
+ CefOwnPtr<CefTranslatorTestScopedLibrary> test_obj =
+ CefTranslatorTestScopedLibrary::Create(kTestVal);
+ EXPECT_TRUE(test_obj.get());
+ EXPECT_EQ(kTestVal, test_obj->GetValue());
+ int retval = obj->SetOwnPtrLibrary(std::move(test_obj));
+ EXPECT_EQ(kTestVal, retval);
+ EXPECT_FALSE(test_obj.get());
+
+ const int kTestVal2 = 30;
+ CefOwnPtr<CefTranslatorTestScopedLibrary> test_obj2 =
+ obj->GetOwnPtrLibrary(kTestVal2);
+ EXPECT_TRUE(test_obj2.get());
+ EXPECT_EQ(kTestVal2, test_obj2->GetValue());
+ int retval2 = obj->SetOwnPtrLibrary(std::move(test_obj2));
+ EXPECT_EQ(kTestVal2, retval2);
+ EXPECT_FALSE(test_obj2.get());
+
+ // Only one reference to the object should exist.
+ EXPECT_TRUE(obj->HasOneRef());
+}
+
+// Test getting/setting inherited library-side OwnPtr types.
+TEST(TranslatorTest, OwnPtrLibraryInherit) {
+ CefRefPtr<CefTranslatorTest> obj = CefTranslatorTest::Create();
+
+ const int kTestVal = 12;
+ const int kTestVal2 = 40;
+ CefOwnPtr<CefTranslatorTestScopedLibraryChild> test_obj =
+ CefTranslatorTestScopedLibraryChild::Create(kTestVal, kTestVal2);
+ EXPECT_TRUE(test_obj.get());
+ EXPECT_EQ(kTestVal, test_obj->GetValue());
+ EXPECT_EQ(kTestVal2, test_obj->GetOtherValue());
+ int retval = obj->SetOwnPtrLibrary(std::move(test_obj));
+ EXPECT_EQ(kTestVal, retval);
+ EXPECT_FALSE(test_obj.get());
+
+ test_obj = CefTranslatorTestScopedLibraryChild::Create(kTestVal, kTestVal2);
+ EXPECT_TRUE(test_obj.get());
+ EXPECT_EQ(kTestVal, obj->SetChildOwnPtrLibrary(std::move(test_obj)));
+ EXPECT_FALSE(test_obj.get());
+
+ test_obj = CefTranslatorTestScopedLibraryChild::Create(kTestVal, kTestVal2);
+ EXPECT_TRUE(test_obj.get());
+ CefOwnPtr<CefTranslatorTestScopedLibrary> test_obj_parent =
+ obj->SetChildOwnPtrLibraryAndReturnParent(std::move(test_obj));
+ EXPECT_FALSE(test_obj.get());
+ EXPECT_TRUE(test_obj_parent.get());
+ EXPECT_EQ(kTestVal, test_obj_parent->GetValue());
+ test_obj_parent.reset(nullptr);
+
+ const int kTestVal3 = 100;
+ CefOwnPtr<CefTranslatorTestScopedLibraryChildChild> test_obj2 =
+ CefTranslatorTestScopedLibraryChildChild::Create(kTestVal, kTestVal2,
+ kTestVal3);
+ EXPECT_EQ(kTestVal, test_obj2->GetValue());
+ EXPECT_EQ(kTestVal2, test_obj2->GetOtherValue());
+ EXPECT_EQ(kTestVal3, test_obj2->GetOtherOtherValue());
+ int retval2 = obj->SetOwnPtrLibrary(std::move(test_obj2));
+ EXPECT_EQ(kTestVal, retval2);
+ EXPECT_FALSE(test_obj2.get());
+
+ test_obj2 = CefTranslatorTestScopedLibraryChildChild::Create(
+ kTestVal, kTestVal2, kTestVal3);
+ EXPECT_EQ(kTestVal, obj->SetChildOwnPtrLibrary(std::move(test_obj2)));
+ EXPECT_FALSE(test_obj2.get());
+
+ test_obj2 = CefTranslatorTestScopedLibraryChildChild::Create(
+ kTestVal, kTestVal2, kTestVal3);
+ test_obj_parent =
+ obj->SetChildOwnPtrLibraryAndReturnParent(std::move(test_obj2));
+ EXPECT_FALSE(test_obj2.get());
+ EXPECT_TRUE(test_obj_parent.get());
+ EXPECT_EQ(kTestVal, test_obj_parent->GetValue());
+ test_obj_parent.reset(nullptr);
+
+ // Only one reference to the object should exist.
+ EXPECT_TRUE(obj->HasOneRef());
+}
+
+namespace {
+
+class TranslatorTestScopedClient : public CefTranslatorTestScopedClient {
+ public:
+ TranslatorTestScopedClient(const int val, TrackCallback* got_delete)
+ : val_(val), got_delete_(got_delete) {}
+ ~TranslatorTestScopedClient() override { got_delete_->yes(); }
+
+ virtual int GetValue() override { return val_; }
+
+ private:
+ const int val_;
+ TrackCallback* got_delete_;
+
+ DISALLOW_COPY_AND_ASSIGN(TranslatorTestScopedClient);
+};
+
+class TranslatorTestScopedClientChild
+ : public CefTranslatorTestScopedClientChild {
+ public:
+ TranslatorTestScopedClientChild(const int val,
+ const int other_val,
+ TrackCallback* got_delete)
+ : val_(val), other_val_(other_val), got_delete_(got_delete) {}
+ ~TranslatorTestScopedClientChild() override { got_delete_->yes(); }
+
+ virtual int GetValue() override { return val_; }
+
+ virtual int GetOtherValue() override { return other_val_; }
+
+ private:
+ const int val_;
+ const int other_val_;
+ TrackCallback* got_delete_;
+
+ DISALLOW_COPY_AND_ASSIGN(TranslatorTestScopedClientChild);
+};
+
+} // namespace
+
+// Test getting/setting client-side OwnPtr types.
+TEST(TranslatorTest, OwnPtrClient) {
+ CefRefPtr<CefTranslatorTest> obj = CefTranslatorTest::Create();
+
+ const int kTestVal = 12;
+ TrackCallback got_delete;
+
+ CefOwnPtr<CefTranslatorTestScopedClient> test_obj(
+ new TranslatorTestScopedClient(kTestVal, &got_delete));
+ EXPECT_EQ(kTestVal, test_obj->GetValue());
+ EXPECT_EQ(kTestVal, obj->SetOwnPtrClient(std::move(test_obj)));
+ EXPECT_FALSE(test_obj.get());
+ EXPECT_TRUE(got_delete);
+
+ got_delete.reset();
+ test_obj.reset(new TranslatorTestScopedClient(kTestVal, &got_delete));
+ CefOwnPtr<CefTranslatorTestScopedClient> handler =
+ obj->SetOwnPtrClientAndReturn(std::move(test_obj));
+ EXPECT_FALSE(test_obj.get());
+ EXPECT_TRUE(handler.get());
+ EXPECT_FALSE(got_delete);
+ EXPECT_EQ(kTestVal, handler->GetValue());
+ handler.reset(nullptr);
+ EXPECT_TRUE(got_delete);
+
+ // Only one reference to the object should exist.
+ EXPECT_TRUE(obj->HasOneRef());
+}
+
+// Test getting/setting inherited client-side OwnPtr types.
+TEST(TranslatorTest, OwnPtrClientInherit) {
+ CefRefPtr<CefTranslatorTest> obj = CefTranslatorTest::Create();
+
+ const int kTestVal = 12;
+ const int kTestVal2 = 86;
+ TrackCallback got_delete;
+
+ CefOwnPtr<CefTranslatorTestScopedClientChild> test_obj(
+ new TranslatorTestScopedClientChild(kTestVal, kTestVal2, &got_delete));
+ EXPECT_EQ(kTestVal, test_obj->GetValue());
+ EXPECT_EQ(kTestVal2, test_obj->GetOtherValue());
+ EXPECT_EQ(kTestVal, obj->SetOwnPtrClient(std::move(test_obj)));
+ EXPECT_FALSE(test_obj.get());
+ EXPECT_TRUE(got_delete);
+
+ got_delete.reset();
+ test_obj.reset(
+ new TranslatorTestScopedClientChild(kTestVal, kTestVal2, &got_delete));
+ EXPECT_EQ(kTestVal, obj->SetChildOwnPtrClient(std::move(test_obj)));
+ EXPECT_FALSE(test_obj.get());
+ EXPECT_TRUE(got_delete);
+
+ got_delete.reset();
+ test_obj.reset(
+ new TranslatorTestScopedClientChild(kTestVal, kTestVal2, &got_delete));
+ CefOwnPtr<CefTranslatorTestScopedClient> handler(
+ obj->SetChildOwnPtrClientAndReturnParent(std::move(test_obj)));
+ EXPECT_EQ(kTestVal, handler->GetValue());
+ EXPECT_FALSE(test_obj.get());
+ EXPECT_FALSE(got_delete);
+ handler.reset(nullptr);
+ EXPECT_TRUE(got_delete);
+
+ // Only one reference to the object should exist.
+ EXPECT_TRUE(obj->HasOneRef());
+}
+
+// Test getting/setting library-side RawPtr types.
+TEST(TranslatorTest, RawPtrLibrary) {
+ CefRefPtr<CefTranslatorTest> obj = CefTranslatorTest::Create();
+
+ const int kTestVal = 12;
+ CefOwnPtr<CefTranslatorTestScopedLibrary> test_obj(
+ CefTranslatorTestScopedLibrary::Create(kTestVal));
+ EXPECT_EQ(kTestVal, test_obj->GetValue());
+ int retval = obj->SetRawPtrLibrary(test_obj.get());
+ EXPECT_EQ(kTestVal, retval);
+ EXPECT_EQ(kTestVal, test_obj->GetValue());
+
+ const int kTestVal2 = 30;
+ CefOwnPtr<CefTranslatorTestScopedLibrary> test_obj2(
+ obj->GetOwnPtrLibrary(kTestVal2));
+ EXPECT_EQ(kTestVal2, test_obj2->GetValue());
+ int retval2 = obj->SetRawPtrLibrary(test_obj2.get());
+ EXPECT_EQ(kTestVal2, retval2);
+ EXPECT_EQ(kTestVal2, test_obj2->GetValue());
+
+ // Only one reference to the object should exist.
+ EXPECT_TRUE(obj->HasOneRef());
+}
+
+// Test getting/setting inherited library-side RawPtr types.
+TEST(TranslatorTest, RawPtrLibraryInherit) {
+ CefRefPtr<CefTranslatorTest> obj = CefTranslatorTest::Create();
+
+ const int kTestVal = 12;
+ const int kTestVal2 = 40;
+ CefOwnPtr<CefTranslatorTestScopedLibraryChild> test_obj(
+ CefTranslatorTestScopedLibraryChild::Create(kTestVal, kTestVal2));
+ EXPECT_EQ(kTestVal, test_obj->GetValue());
+ EXPECT_EQ(kTestVal2, test_obj->GetOtherValue());
+ int retval = obj->SetRawPtrLibrary(test_obj.get());
+ EXPECT_EQ(kTestVal, retval);
+ EXPECT_EQ(kTestVal, test_obj->GetValue());
+ EXPECT_EQ(kTestVal2, test_obj->GetOtherValue());
+
+ EXPECT_EQ(kTestVal, obj->SetChildRawPtrLibrary(test_obj.get()));
+
+ const int kTestVal3 = 100;
+ CefOwnPtr<CefTranslatorTestScopedLibraryChildChild> test_obj2(
+ CefTranslatorTestScopedLibraryChildChild::Create(kTestVal, kTestVal2,
+ kTestVal3));
+ EXPECT_EQ(kTestVal, test_obj2->GetValue());
+ EXPECT_EQ(kTestVal2, test_obj2->GetOtherValue());
+ EXPECT_EQ(kTestVal3, test_obj2->GetOtherOtherValue());
+ int retval2 = obj->SetRawPtrLibrary(test_obj2.get());
+ EXPECT_EQ(kTestVal, retval2);
+ EXPECT_EQ(kTestVal, test_obj2->GetValue());
+ EXPECT_EQ(kTestVal2, test_obj2->GetOtherValue());
+ EXPECT_EQ(kTestVal3, test_obj2->GetOtherOtherValue());
+
+ EXPECT_EQ(kTestVal, obj->SetChildRawPtrLibrary(test_obj2.get()));
+
+ // Only one reference to the object should exist.
+ EXPECT_TRUE(obj->HasOneRef());
+}
+
+// Test getting/setting library-side RawPtr list types.
+TEST(TranslatorTest, RawPtrLibraryList) {
+ CefRefPtr<CefTranslatorTest> obj = CefTranslatorTest::Create();
+
+ const int kVal1 = 34;
+ const int kVal2 = 10;
+
+ CefOwnPtr<CefTranslatorTestScopedLibrary> val1(
+ CefTranslatorTestScopedLibrary::Create(kVal1));
+ CefOwnPtr<CefTranslatorTestScopedLibraryChild> val2(
+ CefTranslatorTestScopedLibraryChild::Create(kVal2, 0));
+
+ std::vector<CefRawPtr<CefTranslatorTestScopedLibrary>> list;
+ list.push_back(val1.get());
+ list.push_back(val2.get());
+ EXPECT_TRUE(obj->SetRawPtrLibraryList(list, kVal1, kVal2));
+ list.clear();
+
+ // Only one reference to the object should exist.
+ EXPECT_TRUE(obj->HasOneRef());
+}
+
+// Test getting/setting client-side RawPtr types.
+TEST(TranslatorTest, RawPtrClient) {
+ CefRefPtr<CefTranslatorTest> obj = CefTranslatorTest::Create();
+
+ const int kTestVal = 12;
+ TrackCallback got_delete;
+
+ CefOwnPtr<TranslatorTestScopedClient> test_obj(
+ new TranslatorTestScopedClient(kTestVal, &got_delete));
+ EXPECT_EQ(kTestVal, test_obj->GetValue());
+ EXPECT_EQ(kTestVal, obj->SetRawPtrClient(test_obj.get()));
+ EXPECT_FALSE(got_delete);
+ test_obj.reset(nullptr);
+ EXPECT_TRUE(got_delete);
+
+ // Only one reference to the object should exist.
+ EXPECT_TRUE(obj->HasOneRef());
+}
+
+// Test getting/setting inherited client-side RawPtr types.
+TEST(TranslatorTest, RawPtrClientInherit) {
+ CefRefPtr<CefTranslatorTest> obj = CefTranslatorTest::Create();
+
+ const int kTestVal = 12;
+ const int kTestVal2 = 86;
+ TrackCallback got_delete;
+
+ CefOwnPtr<TranslatorTestScopedClientChild> test_obj(
+ new TranslatorTestScopedClientChild(kTestVal, kTestVal2, &got_delete));
+ EXPECT_EQ(kTestVal, test_obj->GetValue());
+ EXPECT_EQ(kTestVal2, test_obj->GetOtherValue());
+ int retval = obj->SetRawPtrClient(test_obj.get());
+ EXPECT_EQ(kTestVal, retval);
+ EXPECT_EQ(kTestVal, test_obj->GetValue());
+ EXPECT_EQ(kTestVal2, test_obj->GetOtherValue());
+ EXPECT_FALSE(got_delete);
+
+ EXPECT_EQ(kTestVal, obj->SetChildRawPtrClient(test_obj.get()));
+ EXPECT_FALSE(got_delete);
+ test_obj.reset(nullptr);
+ EXPECT_TRUE(got_delete);
+
+ // Only one reference to the object should exist.
+ EXPECT_TRUE(obj->HasOneRef());
+}
+
+// Test getting/setting client-side RawPtr list types.
+TEST(TranslatorTest, RawPtrClientList) {
+ CefRefPtr<CefTranslatorTest> obj = CefTranslatorTest::Create();
+
+ const int kVal1 = 34;
+ const int kVal2 = 10;
+ TrackCallback got_delete1, got_delete2;
+
+ CefOwnPtr<CefTranslatorTestScopedClient> val1(
+ new TranslatorTestScopedClient(kVal1, &got_delete1));
+ CefOwnPtr<CefTranslatorTestScopedClient> val2(
+ new TranslatorTestScopedClientChild(kVal2, 0, &got_delete2));
+
+ std::vector<CefRawPtr<CefTranslatorTestScopedClient>> list;
+ list.push_back(val1.get());
+ list.push_back(val2.get());
+ EXPECT_TRUE(obj->SetRawPtrClientList(list, kVal1, kVal2));
+ list.clear();
+
+ EXPECT_FALSE(got_delete1);
+ val1.reset(nullptr);
+ EXPECT_TRUE(got_delete1);
+
+ EXPECT_FALSE(got_delete2);
+ val2.reset(nullptr);
+ EXPECT_TRUE(got_delete2);
+
+ // Only one reference to the object should exist.
+ EXPECT_TRUE(obj->HasOneRef());
+}
diff --git a/tests/ceftests/urlrequest_unittest.cc b/tests/ceftests/urlrequest_unittest.cc
new file mode 100644
index 00000000..22218d45
--- /dev/null
+++ b/tests/ceftests/urlrequest_unittest.cc
@@ -0,0 +1,3467 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include <algorithm>
+#include <map>
+#include <memory>
+#include <sstream>
+
+#include "include/base/cef_callback.h"
+#include "include/cef_parser.h"
+#include "include/cef_request_context_handler.h"
+#include "include/cef_scheme.h"
+#include "include/cef_server.h"
+#include "include/cef_task.h"
+#include "include/cef_urlrequest.h"
+#include "include/cef_waitable_event.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "include/wrapper/cef_scoped_temp_dir.h"
+#include "tests/ceftests/test_handler.h"
+#include "tests/ceftests/test_request.h"
+#include "tests/ceftests/test_server_observer.h"
+#include "tests/ceftests/test_suite.h"
+#include "tests/ceftests/test_util.h"
+#include "tests/gtest/include/gtest/gtest.h"
+#include "tests/shared/browser/client_app_browser.h"
+#include "tests/shared/browser/file_util.h"
+#include "tests/shared/common/string_util.h"
+#include "tests/shared/renderer/client_app_renderer.h"
+
+using client::ClientAppRenderer;
+
+// How to add a new test:
+// 1. Add a new value to the RequestTestMode enumeration.
+// 2. Add methods to set up and run the test in RequestTestRunner.
+// 3. Add a line for the test in the RequestTestRunner constructor.
+// 4. Add lines for the test in the "Define the tests" section at the bottom of
+// the file.
+
+namespace {
+
+// Browser-side app delegate.
+class URLRequestBrowserTest : public client::ClientAppBrowser::Delegate {
+ public:
+ URLRequestBrowserTest() {}
+
+ void OnBeforeCommandLineProcessing(
+ CefRefPtr<client::ClientAppBrowser> app,
+ CefRefPtr<CefCommandLine> command_line) override {
+ // Delegate auth callbacks to GetAuthCredentials with the chrome runtime.
+ command_line->AppendSwitch("disable-chrome-login-prompt");
+
+ // Disable component extensions that require creation of a background
+ // WebContents because they slow down test runs.
+ command_line->AppendSwitch(
+ "disable-component-extensions-with-background-pages");
+ }
+
+ private:
+ IMPLEMENT_REFCOUNTING(URLRequestBrowserTest);
+};
+
+// Unique values for URLRequest tests.
+const char kRequestTestMsg[] = "URLRequestTest.Test";
+const char kIncompleteRequestTestMsg[] = "URLRequestTest.IncompleteRequestTest";
+
+// TEST DATA
+
+// Custom scheme handler backend.
+const char kRequestSchemeCustom[] = "urcustom";
+const char kRequestHostCustom[] = "test";
+
+// Server backend. These values are hard-coded because they're used in both the
+// browser and renderer processes.
+const char* kRequestAddressServer = test_server::kHttpServerAddress;
+const uint16 kRequestPortServer = test_server::kHttpServerPort;
+const char kRequestSchemeServer[] = "http";
+
+const char kRequestSendCookieName[] = "urcookie_send";
+const char kRequestSaveCookieName[] = "urcookie_save";
+
+const char kCacheControlHeader[] = "cache-control";
+
+enum RequestTestMode {
+ REQTEST_GET = 0,
+ REQTEST_GET_NODATA,
+ REQTEST_GET_PARTIAL_CONTENT,
+ REQTEST_GET_ALLOWCOOKIES,
+ REQTEST_GET_REDIRECT,
+ REQTEST_GET_REDIRECT_STOP,
+ REQTEST_GET_REDIRECT_LOCATION,
+ REQTEST_GET_REFERRER,
+ REQTEST_GET_AUTH,
+ REQTEST_POST,
+ REQTEST_POST_FILE,
+ REQTEST_POST_WITHPROGRESS,
+ REQTEST_POST_REDIRECT,
+ REQTEST_POST_REDIRECT_TOGET,
+ REQTEST_HEAD,
+ REQTEST_CACHE_WITH_CONTROL,
+ REQTEST_CACHE_WITHOUT_CONTROL,
+ REQTEST_CACHE_SKIP_FLAG,
+ REQTEST_CACHE_SKIP_HEADER,
+ REQTEST_CACHE_ONLY_FAILURE_FLAG,
+ REQTEST_CACHE_ONLY_FAILURE_HEADER,
+ REQTEST_CACHE_ONLY_SUCCESS_FLAG,
+ REQTEST_CACHE_ONLY_SUCCESS_HEADER,
+ REQTEST_CACHE_DISABLE_FLAG,
+ REQTEST_CACHE_DISABLE_HEADER,
+ REQTEST_INCOMPLETE_PROCESS_REQUEST,
+ REQTEST_INCOMPLETE_READ_RESPONSE,
+};
+
+enum ContextTestMode {
+ CONTEXT_GLOBAL,
+ CONTEXT_INMEMORY,
+ CONTEXT_ONDISK,
+};
+
+// Defines test expectations for a request.
+struct RequestRunSettings {
+ RequestRunSettings() {}
+
+ // Set expectations for request failure.
+ void SetRequestFailureExpected(cef_errorcode_t error_code) {
+ expect_upload_progress = false;
+ expect_download_progress = false;
+ expect_download_data = false;
+ expected_status = UR_FAILED;
+ expected_error_code = error_code;
+ response = nullptr;
+ response_data.clear();
+ }
+
+ // Request that will be sent.
+ CefRefPtr<CefRequest> request;
+
+ // Response that will be returned by the backend.
+ CefRefPtr<CefResponse> response;
+
+ // Optional response data that will be returned by the backend.
+ std::string response_data;
+
+ // Create an incomplete request to test shutdown behavior.
+ enum IncompleteType {
+ INCOMPLETE_NONE,
+ INCOMPLETE_PROCESS_REQUEST,
+ INCOMPLETE_READ_RESPONSE,
+ };
+ IncompleteType incomplete_type = INCOMPLETE_NONE;
+
+ // If true upload progress notification will be expected.
+ bool expect_upload_progress = false;
+
+ // If true download progress notification will be expected.
+ bool expect_download_progress = true;
+
+ // If true download data will be expected.
+ bool expect_download_data = true;
+
+ // The offset from what we passed that we expect to receive.
+ size_t expected_download_offset = 0;
+
+ // Expected status value.
+ CefURLRequest::Status expected_status = UR_SUCCESS;
+
+ // Expected error code value.
+ CefURLRequest::ErrorCode expected_error_code = ERR_NONE;
+
+ // If true the request cookie should be sent to the server.
+ bool expect_send_cookie = false;
+
+ // If true the response cookie should be saved.
+ bool expect_save_cookie = false;
+
+ // If true the test will begin by requiring Basic authentication and then
+ // continue with the actual request. The UR_FLAG_ALLOW_STORED_CREDENTIALS
+ // flag must be set on the request. When using the global request context
+ // CefRequestContext::ClearHttpAuthCredentials should be called to avoid
+ // leaking state across test runs. Authentication is only supported with
+ // browser-initiated requests and the server backend.
+ bool expect_authentication = false;
+ std::string username;
+ std::string password;
+
+ // If specified the test will begin with this redirect request and response.
+ CefRefPtr<CefRequest> redirect_request;
+ CefRefPtr<CefResponse> redirect_response;
+
+ // If true the redirect is expected to be followed.
+ bool expect_follow_redirect = true;
+
+ // If true the response is expected to be served from cache.
+ bool expect_response_was_cached = false;
+
+ // The expected number of requests to send, or -1 if unspecified.
+ // Used only with the server backend.
+ int expected_send_count = -1;
+
+ // The expected number of requests to receive, or -1 if unspecified.
+ // Used only with the server backend.
+ int expected_receive_count = -1;
+
+ using NextRequestCallback =
+ base::OnceCallback<void(int /* next_send_count */,
+ base::OnceClosure /* complete_callback */)>;
+
+ // If non-null this callback will be executed before subsequent requests are
+ // sent.
+ NextRequestCallback setup_next_request;
+};
+
+// Manages the map of request URL to test expectations.
+class RequestDataMap {
+ public:
+ struct Entry {
+ enum Type {
+ TYPE_UNKNOWN,
+ TYPE_NORMAL,
+ TYPE_REDIRECT,
+ };
+
+ Entry(Type entry_type) : type(entry_type), settings(nullptr) {}
+
+ Type type;
+
+ // Used with TYPE_NORMAL.
+ // |settings| is not owned by this object.
+ RequestRunSettings* settings;
+
+ // Used with TYPE_REDIRECT.
+ CefRefPtr<CefRequest> redirect_request;
+ CefRefPtr<CefResponse> redirect_response;
+ };
+
+ RequestDataMap() : owner_task_runner_(CefTaskRunner::GetForCurrentThread()) {}
+
+ // Pass ownership to the specified |task_runner| thread.
+ // If |task_runner| is nullptr the test is considered destroyed.
+ void SetOwnerTaskRunner(CefRefPtr<CefTaskRunner> task_runner) {
+ EXPECT_TRUE(owner_task_runner_->BelongsToCurrentThread());
+ owner_task_runner_ = task_runner;
+ }
+
+ void AddSchemeHandler(RequestRunSettings* settings) {
+ EXPECT_TRUE(settings);
+ EXPECT_TRUE(owner_task_runner_->BelongsToCurrentThread());
+
+ const std::string& url = settings->request->GetURL();
+ data_map_.insert(std::make_pair(url, settings));
+
+ if (settings->redirect_request) {
+ const std::string& redirect_url = settings->redirect_request->GetURL();
+ redirect_data_map_.insert(std::make_pair(
+ redirect_url, std::make_pair(settings->redirect_request,
+ settings->redirect_response)));
+ }
+ }
+
+ Entry Find(const std::string& url) {
+ EXPECT_TRUE(owner_task_runner_->BelongsToCurrentThread());
+
+ Entry entry(Entry::TYPE_UNKNOWN);
+
+ // Try to find a test match.
+ {
+ DataMap::const_iterator it = data_map_.find(url);
+ if (it != data_map_.end()) {
+ entry.type = Entry::TYPE_NORMAL;
+ entry.settings = it->second;
+ return entry;
+ }
+ }
+
+ // Try to find a redirect match.
+ {
+ RedirectDataMap::const_iterator it = redirect_data_map_.find(url);
+ if (it != redirect_data_map_.end()) {
+ entry.type = Entry::TYPE_REDIRECT;
+ entry.redirect_request = it->second.first;
+ entry.redirect_response = it->second.second;
+ return entry;
+ }
+ }
+
+ // Unknown test.
+ ADD_FAILURE() << "url: " << url;
+ return entry;
+ }
+
+ size_t size() const { return data_map_.size() + redirect_data_map_.size(); }
+
+ private:
+ CefRefPtr<CefTaskRunner> owner_task_runner_;
+
+ // The below members are only accessed on the |owner_task_runner_| thread.
+
+ // RequestRunSettings pointer is not owned by this object.
+ typedef std::map<std::string, RequestRunSettings*> DataMap;
+ DataMap data_map_;
+
+ typedef std::map<std::string,
+ std::pair<CefRefPtr<CefRequest>, CefRefPtr<CefResponse>>>
+ RedirectDataMap;
+ RedirectDataMap redirect_data_map_;
+};
+
+class TestCompletionCallback : public CefCompletionCallback {
+ public:
+ explicit TestCompletionCallback(base::OnceClosure complete_callback)
+ : complete_callback_(std::move(complete_callback)) {
+ EXPECT_FALSE(complete_callback_.is_null());
+ }
+
+ void OnComplete() override { std::move(complete_callback_).Run(); }
+
+ private:
+ base::OnceClosure complete_callback_;
+
+ IMPLEMENT_REFCOUNTING(TestCompletionCallback);
+};
+
+std::string GetRequestScheme(bool server_backend) {
+ return server_backend ? kRequestSchemeServer : kRequestSchemeCustom;
+}
+
+std::string GetRequestHost(bool server_backend, bool with_port) {
+ if (server_backend) {
+ if (with_port) {
+ std::stringstream ss;
+ ss << kRequestAddressServer << ":" << kRequestPortServer;
+ return ss.str();
+ } else {
+ return kRequestAddressServer;
+ }
+ } else {
+ return kRequestHostCustom;
+ }
+}
+
+std::string GetRequestOrigin(bool server_backend) {
+ return GetRequestScheme(server_backend) + "://" +
+ GetRequestHost(server_backend, true);
+}
+
+void SetUploadData(CefRefPtr<CefRequest> request, const std::string& data) {
+ CefRefPtr<CefPostData> postData = CefPostData::Create();
+ CefRefPtr<CefPostDataElement> element = CefPostDataElement::Create();
+ element->SetToBytes(data.size(), data.c_str());
+ postData->AddElement(element);
+ request->SetPostData(postData);
+}
+
+void SetUploadFile(CefRefPtr<CefRequest> request, const std::string& file) {
+ CefRefPtr<CefPostData> postData = CefPostData::Create();
+ CefRefPtr<CefPostDataElement> element = CefPostDataElement::Create();
+ element->SetToFile(file);
+ postData->AddElement(element);
+ request->SetPostData(postData);
+}
+
+void GetUploadData(CefRefPtr<CefRequest> request, std::string& data) {
+ CefRefPtr<CefPostData> postData = request->GetPostData();
+ EXPECT_TRUE(postData.get());
+ CefPostData::ElementVector elements;
+ postData->GetElements(elements);
+ EXPECT_EQ((size_t)1, elements.size());
+ CefRefPtr<CefPostDataElement> element = elements[0];
+ EXPECT_TRUE(element.get());
+
+ size_t size = element->GetBytesCount();
+
+ data.resize(size);
+ EXPECT_EQ(size, data.size());
+ EXPECT_EQ(size, element->GetBytes(size, const_cast<char*>(data.c_str())));
+}
+
+// Set a cookie so that we can test if it's sent with the request.
+void SetTestCookie(CefRefPtr<CefRequestContext> request_context,
+ bool server_backend,
+ base::OnceClosure callback) {
+ class Callback : public CefSetCookieCallback {
+ public:
+ explicit Callback(base::OnceClosure callback)
+ : callback_(std::move(callback)) {
+ EXPECT_FALSE(callback_.is_null());
+ }
+
+ void OnComplete(bool success) override {
+ EXPECT_TRUE(success);
+ std::move(callback_).Run();
+ }
+
+ private:
+ base::OnceClosure callback_;
+
+ IMPLEMENT_REFCOUNTING(Callback);
+ };
+
+ CefCookie cookie;
+ CefString(&cookie.name) = kRequestSendCookieName;
+ CefString(&cookie.value) = "send-cookie-value";
+ CefString(&cookie.domain) = GetRequestHost(server_backend, false);
+ CefString(&cookie.path) = "/";
+ cookie.has_expires = false;
+ EXPECT_TRUE(request_context->GetCookieManager(nullptr)->SetCookie(
+ GetRequestOrigin(server_backend), cookie,
+ new Callback(std::move(callback))));
+}
+
+using GetTestCookieCallback =
+ base::OnceCallback<void(bool /* cookie exists */)>;
+
+// Tests if the save cookie has been set. If set, it will be deleted at the same
+// time.
+void GetTestCookie(CefRefPtr<CefRequestContext> request_context,
+ bool server_backend,
+ GetTestCookieCallback callback) {
+ class Visitor : public CefCookieVisitor {
+ public:
+ explicit Visitor(GetTestCookieCallback callback)
+ : callback_(std::move(callback)), cookie_exists_(false) {
+ EXPECT_FALSE(callback_.is_null());
+ }
+ ~Visitor() override { std::move(callback_).Run(cookie_exists_); }
+
+ bool Visit(const CefCookie& cookie,
+ int count,
+ int total,
+ bool& deleteCookie) override {
+ std::string cookie_name = CefString(&cookie.name);
+ if (cookie_name == kRequestSaveCookieName) {
+ cookie_exists_ = true;
+ deleteCookie = true;
+ return false;
+ }
+ return true;
+ }
+
+ private:
+ GetTestCookieCallback callback_;
+ bool cookie_exists_;
+
+ IMPLEMENT_REFCOUNTING(Visitor);
+ };
+
+ CefRefPtr<CefCookieManager> cookie_manager =
+ request_context->GetCookieManager(nullptr);
+ cookie_manager->VisitUrlCookies(GetRequestOrigin(server_backend), true,
+ new Visitor(std::move(callback)));
+}
+
+std::string GetHeaderValue(const CefRequest::HeaderMap& header_map,
+ const std::string& header_name_lower) {
+ CefRequest::HeaderMap::const_iterator it = header_map.begin();
+ for (; it != header_map.end(); ++it) {
+ std::string name = client::AsciiStrToLower(it->first);
+ if (name == header_name_lower) {
+ return it->second;
+ }
+ }
+ return std::string();
+}
+
+// Verify normal request expectations.
+void VerifyNormalRequest(const RequestRunSettings* settings,
+ CefRefPtr<CefRequest> request,
+ bool server_backend) {
+ // Shouldn't get here if we're not following redirects.
+ EXPECT_TRUE(settings->expect_follow_redirect);
+
+ // Verify that the request was sent correctly.
+ TestRequestEqual(settings->request, request, true);
+
+ CefRequest::HeaderMap headerMap;
+ request->GetHeaderMap(headerMap);
+
+ // Check if the default headers were sent.
+ EXPECT_FALSE(GetHeaderValue(headerMap, "user-agent").empty());
+
+ // CEF_SETTINGS_ACCEPT_LANGUAGE value from CefSettings.accept_language_list
+ // set in CefTestSuite::GetSettings() and expanded internally by
+ // ComputeAcceptLanguageFromPref.
+ EXPECT_STREQ("en-GB,en;q=0.9",
+ GetHeaderValue(headerMap, "accept-language").c_str());
+
+ if (server_backend) {
+ EXPECT_FALSE(GetHeaderValue(headerMap, "accept-encoding").empty());
+ EXPECT_STREQ(GetRequestHost(true, true).c_str(),
+ GetHeaderValue(headerMap, "host").c_str());
+ }
+
+ // Check if the request cookie was sent.
+ const std::string& cookie_value = GetHeaderValue(headerMap, "cookie");
+ bool has_send_cookie = false;
+ if (!cookie_value.empty() &&
+ cookie_value.find(kRequestSendCookieName) != std::string::npos) {
+ has_send_cookie = true;
+ }
+
+ EXPECT_EQ(settings->expect_send_cookie, has_send_cookie);
+}
+
+// Populate normal response contents.
+void GetNormalResponse(const RequestRunSettings* settings,
+ CefRefPtr<CefResponse> response) {
+ EXPECT_TRUE(settings->response);
+ if (!settings->response) {
+ return;
+ }
+
+ response->SetStatus(settings->response->GetStatus());
+ response->SetStatusText(settings->response->GetStatusText());
+ response->SetMimeType(settings->response->GetMimeType());
+
+ CefResponse::HeaderMap headerMap;
+ settings->response->GetHeaderMap(headerMap);
+
+ if (settings->expect_save_cookie) {
+ std::stringstream ss;
+ ss << kRequestSaveCookieName << "="
+ << "save-cookie-value";
+ headerMap.insert(std::make_pair("Set-Cookie", ss.str()));
+ }
+
+ response->SetHeaderMap(headerMap);
+}
+
+// Based on https://en.wikipedia.org/wiki/Basic_access_authentication#Protocol
+void GetAuthResponse(CefRefPtr<CefResponse> response) {
+ response->SetStatus(401);
+ response->SetStatusText("Unauthorized");
+ response->SetMimeType("text/html");
+
+ CefResponse::HeaderMap headerMap;
+ headerMap.insert(
+ std::make_pair("WWW-Authenticate", "Basic realm=\"Test Realm\""));
+ response->SetHeaderMap(headerMap);
+}
+
+bool IsAuthorized(CefRefPtr<CefRequest> request,
+ const std::string& username,
+ const std::string& password) {
+ const std::string& authHeader = request->GetHeaderByName("Authorization");
+ if (authHeader.empty()) {
+ return false;
+ }
+
+ if (authHeader.find("Basic ") == 0) {
+ const std::string& base64 = authHeader.substr(6);
+ CefRefPtr<CefBinaryValue> data = CefBase64Decode(base64);
+ EXPECT_TRUE(data);
+ if (!data) {
+ LOG(ERROR) << "Failed to decode Authorization value: " << base64;
+ return false;
+ }
+
+ std::string decoded;
+ decoded.resize(data->GetSize());
+ data->GetData(&decoded[0], data->GetSize(), 0);
+
+ const std::string& expected = username + ":" + password;
+ EXPECT_STREQ(expected.c_str(), decoded.c_str());
+ return decoded == expected;
+ }
+
+ LOG(ERROR) << "Unexpected Authorization value: " << authHeader;
+ return false;
+}
+
+// SCHEME HANDLER BACKEND
+
+// Serves request responses.
+class RequestSchemeHandlerOld : public CefResourceHandler {
+ public:
+ RequestSchemeHandlerOld(RequestRunSettings* settings,
+ base::OnceClosure destroy_callback)
+ : settings_(settings), destroy_callback_(std::move(destroy_callback)) {}
+
+ ~RequestSchemeHandlerOld() override {
+ EXPECT_EQ(1, cancel_ct_);
+ std::move(destroy_callback_).Run();
+ }
+
+ bool ProcessRequest(CefRefPtr<CefRequest> request,
+ CefRefPtr<CefCallback> callback) override {
+ EXPECT_IO_THREAD();
+ VerifyNormalRequest(settings_, request, false);
+
+ // HEAD requests are identical to GET requests except no response data is
+ // sent.
+ if (request->GetMethod() != "HEAD") {
+ response_data_ = settings_->response_data;
+ }
+
+ // Continue immediately.
+ callback->Continue();
+ return true;
+ }
+
+ void GetResponseHeaders(CefRefPtr<CefResponse> response,
+ int64& response_length,
+ CefString& redirectUrl) override {
+ EXPECT_IO_THREAD();
+ GetNormalResponse(settings_, response);
+ response_length = response_data_.length();
+ }
+
+ bool ReadResponse(void* data_out,
+ int bytes_to_read,
+ int& bytes_read,
+ CefRefPtr<CefCallback> callback) override {
+ EXPECT_IO_THREAD();
+
+ bool has_data = false;
+ bytes_read = 0;
+
+ size_t size = response_data_.length();
+ if (offset_ < size) {
+ int transfer_size =
+ std::min(bytes_to_read, static_cast<int>(size - offset_));
+ memcpy(data_out, response_data_.c_str() + offset_, transfer_size);
+ offset_ += transfer_size;
+
+ bytes_read = transfer_size;
+ has_data = true;
+ }
+
+ return has_data;
+ }
+
+ void Cancel() override {
+ EXPECT_IO_THREAD();
+ cancel_ct_++;
+ }
+
+ private:
+ // |settings_| is not owned by this object.
+ RequestRunSettings* settings_;
+ base::OnceClosure destroy_callback_;
+
+ std::string response_data_;
+ size_t offset_ = 0;
+
+ int cancel_ct_ = 0;
+
+ IMPLEMENT_REFCOUNTING(RequestSchemeHandlerOld);
+ DISALLOW_COPY_AND_ASSIGN(RequestSchemeHandlerOld);
+};
+
+class RequestSchemeHandler : public CefResourceHandler {
+ public:
+ RequestSchemeHandler(RequestRunSettings* settings,
+ base::OnceClosure destroy_callback)
+ : settings_(settings), destroy_callback_(std::move(destroy_callback)) {}
+
+ ~RequestSchemeHandler() override {
+ EXPECT_EQ(1, cancel_ct_);
+ std::move(destroy_callback_).Run();
+ }
+
+ bool Open(CefRefPtr<CefRequest> request,
+ bool& handle_request,
+ CefRefPtr<CefCallback> callback) override {
+ EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO));
+ VerifyNormalRequest(settings_, request, false);
+
+ // HEAD requests are identical to GET requests except no response data is
+ // sent.
+ if (request->GetMethod() != "HEAD") {
+ response_data_ = settings_->response_data;
+ }
+
+ // Continue immediately.
+ handle_request = true;
+ return true;
+ }
+
+ bool ProcessRequest(CefRefPtr<CefRequest> request,
+ CefRefPtr<CefCallback> callback) override {
+ EXPECT_TRUE(false); // Not reached.
+ return false;
+ }
+
+ void GetResponseHeaders(CefRefPtr<CefResponse> response,
+ int64& response_length,
+ CefString& redirectUrl) override {
+ EXPECT_IO_THREAD();
+ GetNormalResponse(settings_, response);
+ response_length = response_data_.length() - offset_;
+ }
+
+ bool Skip(int64 bytes_to_skip,
+ int64& bytes_skipped,
+ CefRefPtr<CefResourceSkipCallback> callback) override {
+ size_t size = response_data_.length();
+ if (offset_ < size) {
+ bytes_skipped =
+ std::min(bytes_to_skip, static_cast<int64>(size - offset_));
+ offset_ += bytes_skipped;
+ } else {
+ bytes_skipped = ERR_FAILED;
+ }
+
+ return bytes_skipped > 0;
+ }
+
+ bool Read(void* data_out,
+ int bytes_to_read,
+ int& bytes_read,
+ CefRefPtr<CefResourceReadCallback> callback) override {
+ EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO));
+
+ // Default to response complete.
+ bool has_data = false;
+ bytes_read = 0;
+
+ size_t size = response_data_.length();
+ if (offset_ < size) {
+ int transfer_size =
+ std::min(bytes_to_read, static_cast<int>(size - offset_));
+ memcpy(data_out, response_data_.c_str() + offset_, transfer_size);
+ offset_ += transfer_size;
+
+ bytes_read = transfer_size;
+ has_data = true;
+ }
+
+ return has_data;
+ }
+
+ bool ReadResponse(void* data_out,
+ int bytes_to_read,
+ int& bytes_read,
+ CefRefPtr<CefCallback> callback) override {
+ EXPECT_TRUE(false); // Not reached.
+ bytes_read = -2;
+ return false;
+ }
+
+ void Cancel() override {
+ EXPECT_IO_THREAD();
+ cancel_ct_++;
+ }
+
+ private:
+ // |settings_| is not owned by this object.
+ RequestRunSettings* settings_;
+ base::OnceClosure destroy_callback_;
+
+ std::string response_data_;
+ size_t offset_ = 0;
+
+ int cancel_ct_ = 0;
+
+ IMPLEMENT_REFCOUNTING(RequestSchemeHandler);
+ DISALLOW_COPY_AND_ASSIGN(RequestSchemeHandler);
+};
+
+// Serves redirect request responses.
+class RequestRedirectSchemeHandlerOld : public CefResourceHandler {
+ public:
+ RequestRedirectSchemeHandlerOld(CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response,
+ base::OnceClosure destroy_callback)
+ : request_(request),
+ response_(response),
+ destroy_callback_(std::move(destroy_callback)) {}
+
+ ~RequestRedirectSchemeHandlerOld() override {
+ EXPECT_EQ(1, cancel_ct_);
+ std::move(destroy_callback_).Run();
+ }
+
+ bool ProcessRequest(CefRefPtr<CefRequest> request,
+ CefRefPtr<CefCallback> callback) override {
+ EXPECT_IO_THREAD();
+
+ // Verify that the request was sent correctly.
+ TestRequestEqual(request_, request, true);
+
+ // Continue immediately.
+ callback->Continue();
+ return true;
+ }
+
+ void GetResponseHeaders(CefRefPtr<CefResponse> response,
+ int64& response_length,
+ CefString& redirectUrl) override {
+ EXPECT_IO_THREAD();
+
+ response->SetStatus(response_->GetStatus());
+ response->SetStatusText(response_->GetStatusText());
+ response->SetMimeType(response_->GetMimeType());
+
+ CefResponse::HeaderMap headerMap;
+ response_->GetHeaderMap(headerMap);
+ response->SetHeaderMap(headerMap);
+
+ response_length = 0;
+ }
+
+ bool ReadResponse(void* response_data_out,
+ int bytes_to_read,
+ int& bytes_read,
+ CefRefPtr<CefCallback> callback) override {
+ EXPECT_IO_THREAD();
+ NOTREACHED();
+ return false;
+ }
+
+ void Cancel() override {
+ EXPECT_IO_THREAD();
+ cancel_ct_++;
+ }
+
+ private:
+ CefRefPtr<CefRequest> request_;
+ CefRefPtr<CefResponse> response_;
+ base::OnceClosure destroy_callback_;
+
+ int cancel_ct_ = 0;
+
+ IMPLEMENT_REFCOUNTING(RequestRedirectSchemeHandlerOld);
+ DISALLOW_COPY_AND_ASSIGN(RequestRedirectSchemeHandlerOld);
+};
+
+class RequestRedirectSchemeHandler : public CefResourceHandler {
+ public:
+ RequestRedirectSchemeHandler(CefRefPtr<CefRequest> request,
+ CefRefPtr<CefResponse> response,
+ base::OnceClosure destroy_callback)
+ : request_(request),
+ response_(response),
+ destroy_callback_(std::move(destroy_callback)) {}
+
+ ~RequestRedirectSchemeHandler() override {
+ EXPECT_EQ(1, cancel_ct_);
+ std::move(destroy_callback_).Run();
+ }
+
+ bool Open(CefRefPtr<CefRequest> request,
+ bool& handle_request,
+ CefRefPtr<CefCallback> callback) override {
+ EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO));
+
+ // Verify that the request was sent correctly.
+ TestRequestEqual(request_, request, true);
+
+ // Continue immediately.
+ handle_request = true;
+ return true;
+ }
+
+ bool ProcessRequest(CefRefPtr<CefRequest> request,
+ CefRefPtr<CefCallback> callback) override {
+ EXPECT_TRUE(false); // Not reached.
+ return false;
+ }
+
+ void GetResponseHeaders(CefRefPtr<CefResponse> response,
+ int64& response_length,
+ CefString& redirectUrl) override {
+ EXPECT_IO_THREAD();
+
+ response->SetStatus(response_->GetStatus());
+ response->SetStatusText(response_->GetStatusText());
+ response->SetMimeType(response_->GetMimeType());
+
+ CefResponse::HeaderMap headerMap;
+ response_->GetHeaderMap(headerMap);
+ response->SetHeaderMap(headerMap);
+
+ response_length = 0;
+ }
+
+ bool Read(void* data_out,
+ int bytes_to_read,
+ int& bytes_read,
+ CefRefPtr<CefResourceReadCallback> callback) override {
+ EXPECT_TRUE(false); // Not reached.
+ bytes_read = -1;
+ return false;
+ }
+
+ bool ReadResponse(void* data_out,
+ int bytes_to_read,
+ int& bytes_read,
+ CefRefPtr<CefCallback> callback) override {
+ EXPECT_TRUE(false); // Not reached.
+ bytes_read = -2;
+ return false;
+ }
+
+ void Cancel() override {
+ EXPECT_IO_THREAD();
+ cancel_ct_++;
+ }
+
+ private:
+ CefRefPtr<CefRequest> request_;
+ CefRefPtr<CefResponse> response_;
+ base::OnceClosure destroy_callback_;
+
+ int cancel_ct_ = 0;
+
+ IMPLEMENT_REFCOUNTING(RequestRedirectSchemeHandler);
+ DISALLOW_COPY_AND_ASSIGN(RequestRedirectSchemeHandler);
+};
+
+// Resource handler implementation that never completes. Used to test
+// destruction handling behavior for in-progress requests.
+class IncompleteSchemeHandlerOld : public CefResourceHandler {
+ public:
+ IncompleteSchemeHandlerOld(RequestRunSettings* settings,
+ base::OnceClosure destroy_callback)
+ : settings_(settings), destroy_callback_(std::move(destroy_callback)) {
+ EXPECT_NE(settings_->incomplete_type, RequestRunSettings::INCOMPLETE_NONE);
+ }
+
+ ~IncompleteSchemeHandlerOld() override {
+ EXPECT_EQ(1, process_request_ct_);
+ EXPECT_EQ(1, cancel_ct_);
+
+ if (settings_->incomplete_type ==
+ RequestRunSettings::INCOMPLETE_READ_RESPONSE) {
+ EXPECT_EQ(1, get_response_headers_ct_);
+ EXPECT_EQ(1, read_response_ct_);
+ } else {
+ EXPECT_EQ(0, get_response_headers_ct_);
+ EXPECT_EQ(0, read_response_ct_);
+ }
+
+ std::move(destroy_callback_).Run();
+ }
+
+ bool ProcessRequest(CefRefPtr<CefRequest> request,
+ CefRefPtr<CefCallback> callback) override {
+ EXPECT_IO_THREAD();
+
+ process_request_ct_++;
+
+ if (settings_->incomplete_type ==
+ RequestRunSettings::INCOMPLETE_PROCESS_REQUEST) {
+ // Never release or execute this callback.
+ incomplete_callback_ = callback;
+ } else {
+ callback->Continue();
+ }
+ return true;
+ }
+
+ void GetResponseHeaders(CefRefPtr<CefResponse> response,
+ int64& response_length,
+ CefString& redirectUrl) override {
+ EXPECT_IO_THREAD();
+ EXPECT_EQ(settings_->incomplete_type,
+ RequestRunSettings::INCOMPLETE_READ_RESPONSE);
+
+ get_response_headers_ct_++;
+
+ response->SetStatus(settings_->response->GetStatus());
+ response->SetStatusText(settings_->response->GetStatusText());
+ response->SetMimeType(settings_->response->GetMimeType());
+
+ CefResponse::HeaderMap headerMap;
+ settings_->response->GetHeaderMap(headerMap);
+ settings_->response->SetHeaderMap(headerMap);
+
+ response_length = static_cast<int64>(settings_->response_data.size());
+ }
+
+ bool ReadResponse(void* data_out,
+ int bytes_to_read,
+ int& bytes_read,
+ CefRefPtr<CefCallback> callback) override {
+ EXPECT_IO_THREAD();
+ EXPECT_EQ(settings_->incomplete_type,
+ RequestRunSettings::INCOMPLETE_READ_RESPONSE);
+
+ read_response_ct_++;
+
+ // Never release or execute this callback.
+ incomplete_callback_ = callback;
+ bytes_read = 0;
+ return true;
+ }
+
+ void Cancel() override {
+ EXPECT_IO_THREAD();
+ cancel_ct_++;
+ }
+
+ private:
+ RequestRunSettings* const settings_;
+ base::OnceClosure destroy_callback_;
+
+ int process_request_ct_ = 0;
+ int get_response_headers_ct_ = 0;
+ int read_response_ct_ = 0;
+ int cancel_ct_ = 0;
+
+ CefRefPtr<CefCallback> incomplete_callback_;
+
+ IMPLEMENT_REFCOUNTING(IncompleteSchemeHandlerOld);
+ DISALLOW_COPY_AND_ASSIGN(IncompleteSchemeHandlerOld);
+};
+
+class IncompleteSchemeHandler : public CefResourceHandler {
+ public:
+ IncompleteSchemeHandler(RequestRunSettings* settings,
+ base::OnceClosure destroy_callback)
+ : settings_(settings), destroy_callback_(std::move(destroy_callback)) {
+ EXPECT_NE(settings_->incomplete_type, RequestRunSettings::INCOMPLETE_NONE);
+ }
+
+ ~IncompleteSchemeHandler() override {
+ EXPECT_EQ(1, open_ct_);
+ EXPECT_EQ(1, cancel_ct_);
+
+ if (settings_->incomplete_type ==
+ RequestRunSettings::INCOMPLETE_READ_RESPONSE) {
+ EXPECT_EQ(1, get_response_headers_ct_);
+ EXPECT_EQ(1, read_ct_);
+ } else {
+ EXPECT_EQ(0, get_response_headers_ct_);
+ EXPECT_EQ(0, read_ct_);
+ }
+
+ std::move(destroy_callback_).Run();
+ }
+
+ bool Open(CefRefPtr<CefRequest> request,
+ bool& handle_request,
+ CefRefPtr<CefCallback> callback) override {
+ EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO));
+
+ open_ct_++;
+
+ if (settings_->incomplete_type ==
+ RequestRunSettings::INCOMPLETE_PROCESS_REQUEST) {
+ // Never release or execute this callback.
+ incomplete_open_callback_ = callback;
+ } else {
+ // Continue immediately.
+ handle_request = true;
+ }
+ return true;
+ }
+
+ bool ProcessRequest(CefRefPtr<CefRequest> request,
+ CefRefPtr<CefCallback> callback) override {
+ EXPECT_TRUE(false); // Not reached.
+ return false;
+ }
+
+ void GetResponseHeaders(CefRefPtr<CefResponse> response,
+ int64& response_length,
+ CefString& redirectUrl) override {
+ EXPECT_IO_THREAD();
+ EXPECT_EQ(settings_->incomplete_type,
+ RequestRunSettings::INCOMPLETE_READ_RESPONSE);
+
+ get_response_headers_ct_++;
+
+ response->SetStatus(settings_->response->GetStatus());
+ response->SetStatusText(settings_->response->GetStatusText());
+ response->SetMimeType(settings_->response->GetMimeType());
+
+ CefResponse::HeaderMap headerMap;
+ settings_->response->GetHeaderMap(headerMap);
+ settings_->response->SetHeaderMap(headerMap);
+
+ response_length = static_cast<int64>(settings_->response_data.size());
+ }
+
+ bool Read(void* data_out,
+ int bytes_to_read,
+ int& bytes_read,
+ CefRefPtr<CefResourceReadCallback> callback) override {
+ EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO));
+ EXPECT_EQ(settings_->incomplete_type,
+ RequestRunSettings::INCOMPLETE_READ_RESPONSE);
+
+ read_ct_++;
+
+ // Never release or execute this callback.
+ incomplete_read_callback_ = callback;
+ bytes_read = 0;
+ return true;
+ }
+
+ bool ReadResponse(void* data_out,
+ int bytes_to_read,
+ int& bytes_read,
+ CefRefPtr<CefCallback> callback) override {
+ EXPECT_TRUE(false); // Not reached.
+ bytes_read = -2;
+ return false;
+ }
+
+ void Cancel() override {
+ EXPECT_IO_THREAD();
+ cancel_ct_++;
+ }
+
+ private:
+ RequestRunSettings* const settings_;
+ base::OnceClosure destroy_callback_;
+
+ int open_ct_ = 0;
+ int get_response_headers_ct_ = 0;
+ int read_ct_ = 0;
+ int cancel_ct_ = 0;
+
+ CefRefPtr<CefCallback> incomplete_open_callback_;
+ CefRefPtr<CefResourceReadCallback> incomplete_read_callback_;
+
+ IMPLEMENT_REFCOUNTING(IncompleteSchemeHandler);
+ DISALLOW_COPY_AND_ASSIGN(IncompleteSchemeHandler);
+};
+
+class RequestSchemeHandlerFactory : public CefSchemeHandlerFactory {
+ public:
+ RequestSchemeHandlerFactory() {}
+
+ CefRefPtr<CefResourceHandler> Create(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ const CefString& scheme_name,
+ CefRefPtr<CefRequest> request) override {
+ EXPECT_IO_THREAD();
+
+ handler_create_ct_++;
+ auto destroy_callback =
+ base::BindOnce(&RequestSchemeHandlerFactory::OnHandlerDestroyed, this);
+
+ RequestDataMap::Entry entry = data_map_.Find(request->GetURL());
+ if (entry.type == RequestDataMap::Entry::TYPE_NORMAL) {
+ if (entry.settings->incomplete_type ==
+ RequestRunSettings::INCOMPLETE_NONE) {
+ if (TestOldResourceAPI()) {
+ return new RequestSchemeHandlerOld(entry.settings,
+ std::move(destroy_callback));
+ }
+ return new RequestSchemeHandler(entry.settings,
+ std::move(destroy_callback));
+ }
+
+ if (TestOldResourceAPI()) {
+ return new IncompleteSchemeHandlerOld(entry.settings,
+ std::move(destroy_callback));
+ }
+ return new IncompleteSchemeHandler(entry.settings,
+ std::move(destroy_callback));
+ } else if (entry.type == RequestDataMap::Entry::TYPE_REDIRECT) {
+ if (TestOldResourceAPI()) {
+ return new RequestRedirectSchemeHandlerOld(entry.redirect_request,
+ entry.redirect_response,
+ std::move(destroy_callback));
+ }
+ return new RequestRedirectSchemeHandler(entry.redirect_request,
+ entry.redirect_response,
+ std::move(destroy_callback));
+ }
+
+ // Unknown test.
+ ADD_FAILURE();
+ return nullptr;
+ }
+
+ void SetOwnerTaskRunner(CefRefPtr<CefTaskRunner> task_runner) {
+ data_map_.SetOwnerTaskRunner(task_runner);
+ }
+
+ void AddSchemeHandler(RequestRunSettings* settings) {
+ const std::string& scheme = GetRequestScheme(false);
+
+ // Verify that the scheme is correct.
+ const std::string& url = settings->request->GetURL();
+ EXPECT_EQ(0U, url.find(scheme));
+
+ if (settings->redirect_request) {
+ // Verify that the scheme is correct.
+ const std::string& redirect_url = settings->redirect_request->GetURL();
+ EXPECT_EQ(0U, redirect_url.find(scheme));
+ }
+
+ data_map_.AddSchemeHandler(settings);
+ }
+
+ void OnHandlerDestroyed() {
+ if (!CefCurrentlyOn(TID_IO)) {
+ CefPostTask(TID_IO,
+ base::BindOnce(
+ &RequestSchemeHandlerFactory::OnHandlerDestroyed, this));
+ return;
+ }
+
+ handler_destroy_ct_++;
+
+ MaybeShutdown();
+ }
+
+ void Shutdown(base::OnceClosure complete_callback) {
+ if (!CefCurrentlyOn(TID_IO)) {
+ CefPostTask(TID_IO, base::BindOnce(&RequestSchemeHandlerFactory::Shutdown,
+ this, std::move(complete_callback)));
+ return;
+ }
+
+ EXPECT_TRUE(shutdown_callback_.is_null());
+ shutdown_callback_ = std::move(complete_callback);
+
+ data_map_.SetOwnerTaskRunner(nullptr);
+
+ MaybeShutdown();
+ }
+
+ private:
+ void MaybeShutdown() {
+ if (!shutdown_callback_.is_null() &&
+ handler_create_ct_ == handler_destroy_ct_) {
+ std::move(shutdown_callback_).Run();
+ }
+ }
+
+ RequestDataMap data_map_;
+
+ int handler_create_ct_ = 0;
+ int handler_destroy_ct_ = 0;
+ base::OnceClosure shutdown_callback_;
+
+ IMPLEMENT_REFCOUNTING(RequestSchemeHandlerFactory);
+ DISALLOW_COPY_AND_ASSIGN(RequestSchemeHandlerFactory);
+};
+
+// SERVER BACKEND
+
+// HTTP server handler.
+class RequestServerHandler : public test_server::ObserverHelper {
+ public:
+ RequestServerHandler()
+ : initialized_(false),
+ expected_http_request_ct_(-1),
+ actual_http_request_ct_(0) {}
+
+ virtual ~RequestServerHandler() { RunCompleteCallback(false); }
+
+ // Must be called before CreateServer().
+ void AddSchemeHandler(RequestRunSettings* settings) {
+ EXPECT_FALSE(initialized_);
+ data_map_.AddSchemeHandler(settings);
+ }
+
+ // Must be called before CreateServer().
+ void SetExpectedRequestCount(int count) {
+ EXPECT_FALSE(initialized_);
+ expected_http_request_ct_ = count;
+ }
+
+ // |complete_callback| will be executed on the UI thread after the server is
+ // started.
+ void CreateServer(base::OnceClosure complete_callback) {
+ EXPECT_UI_THREAD();
+
+ if (expected_http_request_ct_ < 0) {
+ // Default to the assumption of one request per registered URL.
+ SetExpectedRequestCount(static_cast<int>(data_map_.size()));
+ }
+
+ EXPECT_FALSE(initialized_);
+ initialized_ = true;
+
+ EXPECT_TRUE(complete_callback_.is_null());
+ complete_callback_ = std::move(complete_callback);
+
+ Initialize(/*https_server=*/false);
+ }
+
+ // Results in a call to VerifyResults() and eventual execution of the
+ // |complete_callback| on the UI thread via RequestServerHandler destruction.
+ void ShutdownServer(base::OnceClosure complete_callback) {
+ EXPECT_UI_THREAD();
+
+ EXPECT_TRUE(complete_callback_.is_null());
+ complete_callback_ = std::move(complete_callback);
+
+ Shutdown();
+ }
+
+ void OnInitialized(const std::string& server_origin) override {
+ EXPECT_UI_THREAD();
+ EXPECT_STREQ(server_origin.c_str(), GetRequestOrigin(true).c_str());
+ EXPECT_FALSE(got_initialized_);
+ got_initialized_.yes();
+
+ RunCompleteCallback(true);
+ }
+
+ void OnShutdown() override {
+ EXPECT_UI_THREAD();
+ EXPECT_FALSE(got_shutdown_);
+ got_shutdown_.yes();
+
+ data_map_.SetOwnerTaskRunner(nullptr);
+
+ VerifyResults();
+
+ delete this;
+ }
+
+ bool OnTestServerRequest(CefRefPtr<CefRequest> request,
+ const ResponseCallback& response_callback) override {
+ EXPECT_UI_THREAD();
+
+ // Log the requests for better error reporting.
+ request_log_ += request->GetMethod().ToString() + " " +
+ request->GetURL().ToString() + "\n";
+
+ actual_http_request_ct_++;
+
+ return HandleRequest(request, response_callback);
+ }
+
+ private:
+ void VerifyResults() {
+ EXPECT_TRUE(got_initialized_);
+ EXPECT_TRUE(got_shutdown_);
+ EXPECT_EQ(expected_http_request_ct_, actual_http_request_ct_)
+ << request_log_;
+ }
+
+ bool HandleRequest(CefRefPtr<CefRequest> request,
+ const ResponseCallback& response_callback) {
+ RequestDataMap::Entry entry = data_map_.Find(request->GetURL());
+ if (entry.type == RequestDataMap::Entry::TYPE_NORMAL) {
+ const bool needs_auth = entry.settings->expect_authentication &&
+ !IsAuthorized(request, entry.settings->username,
+ entry.settings->password);
+ if (needs_auth) {
+ return HandleAuthRequest(request, response_callback);
+ }
+
+ return HandleNormalRequest(request, response_callback, entry.settings);
+ } else if (entry.type == RequestDataMap::Entry::TYPE_REDIRECT) {
+ return HandleRedirectRequest(request, response_callback,
+ entry.redirect_request,
+ entry.redirect_response);
+ } else {
+ // Unknown test.
+ ADD_FAILURE() << "url: " << request->GetURL().ToString();
+ }
+ return false;
+ }
+
+ static bool HandleAuthRequest(CefRefPtr<CefRequest> request,
+ const ResponseCallback& response_callback) {
+ CefRefPtr<CefResponse> response = CefResponse::Create();
+ GetAuthResponse(response);
+ response_callback.Run(response, std::string());
+ return true;
+ }
+
+ static bool HandleNormalRequest(CefRefPtr<CefRequest> request,
+ const ResponseCallback& response_callback,
+ RequestRunSettings* settings) {
+ VerifyNormalRequest(settings, request, true);
+
+ CefRefPtr<CefResponse> response = CefResponse::Create();
+ GetNormalResponse(settings, response);
+
+ // HEAD requests are identical to GET requests except no response data is
+ // sent.
+ std::string response_data;
+ if (request->GetMethod() != "HEAD") {
+ size_t expected_offset = settings->expected_download_offset;
+ response_data = settings->response_data.substr(expected_offset);
+ }
+
+ response_callback.Run(response, response_data);
+ return true;
+ }
+
+ static bool HandleRedirectRequest(CefRefPtr<CefRequest> request,
+ const ResponseCallback& response_callback,
+ CefRefPtr<CefRequest> redirect_request,
+ CefRefPtr<CefResponse> redirect_response) {
+ if (redirect_response->GetStatus() == 302) {
+ // Simulate wrong copying of POST-specific headers Content-Type and
+ // Content-Length. A 302 redirect should end up in a GET request and
+ // these headers should not propagate from a 302 POST-to-GET redirect.
+ CefResponse::HeaderMap redirectHeaderMap;
+ redirect_response->GetHeaderMap(redirectHeaderMap);
+ redirectHeaderMap.insert(
+ std::make_pair("content-type", "application/x-www-form-urlencoded"));
+ redirectHeaderMap.insert(std::make_pair("content-length", "0"));
+ redirect_response->SetHeaderMap(redirectHeaderMap);
+ }
+
+ // Verify that the request was sent correctly.
+ TestRequestEqual(redirect_request, request, true);
+
+ response_callback.Run(redirect_response, std::string());
+ return true;
+ }
+
+ void RunCompleteCallback(bool startup) {
+ EXPECT_UI_THREAD();
+
+ if (startup) {
+ // Transfer DataMap ownership to the UI thread.
+ data_map_.SetOwnerTaskRunner(CefTaskRunner::GetForCurrentThread());
+ }
+
+ EXPECT_FALSE(complete_callback_.is_null());
+ std::move(complete_callback_).Run();
+ }
+
+ RequestDataMap data_map_;
+
+ bool initialized_;
+
+ // Only accessed on the UI thread.
+ base::OnceClosure complete_callback_;
+
+ // After initialization the below members are only accessed on the server
+ // thread.
+
+ TrackCallback got_initialized_;
+ TrackCallback got_shutdown_;
+
+ int expected_http_request_ct_;
+ int actual_http_request_ct_;
+
+ std::string request_log_;
+};
+
+// SHARED TEST RUNNER
+
+// Executes the tests.
+class RequestTestRunner : public base::RefCountedThreadSafe<RequestTestRunner> {
+ public:
+ using TestCallback = base::RepeatingCallback<void(base::OnceClosure)>;
+
+ RequestTestRunner(bool is_browser_process,
+ bool is_server_backend,
+ bool use_frame_method,
+ bool run_in_browser_process,
+ base::OnceClosure incomplete_request_callback)
+ : is_browser_process_(is_browser_process),
+ is_server_backend_(is_server_backend),
+ use_frame_method_(use_frame_method),
+ run_in_browser_process_(run_in_browser_process),
+ incomplete_request_callback_(std::move(incomplete_request_callback)) {
+ owner_task_runner_ = CefTaskRunner::GetForCurrentThread();
+ EXPECT_TRUE(owner_task_runner_.get());
+ EXPECT_TRUE(owner_task_runner_->BelongsToCurrentThread());
+ }
+
+ void Initialize() {
+// Helper macro for registering test callbacks.
+#define REGISTER_TEST(test_mode, setup_method, run_method) \
+ RegisterTest(test_mode, \
+ base::BindRepeating(&RequestTestRunner::setup_method, this), \
+ base::BindRepeating(&RequestTestRunner::run_method, this));
+
+ // Register the test callbacks.
+ REGISTER_TEST(REQTEST_GET, SetupGetTest, SingleRunTest);
+ REGISTER_TEST(REQTEST_GET_NODATA, SetupGetNoDataTest, SingleRunTest);
+ REGISTER_TEST(REQTEST_GET_PARTIAL_CONTENT, SetupGetPartialContentTest,
+ SingleRunTest);
+ REGISTER_TEST(REQTEST_GET_ALLOWCOOKIES, SetupGetAllowCookiesTest,
+ SingleRunTest);
+ REGISTER_TEST(REQTEST_GET_REDIRECT, SetupGetRedirectTest, SingleRunTest);
+ REGISTER_TEST(REQTEST_GET_REDIRECT_STOP, SetupGetRedirectStopTest,
+ SingleRunTest);
+ REGISTER_TEST(REQTEST_GET_REDIRECT_LOCATION, SetupGetRedirectLocationTest,
+ SingleRunTest);
+ REGISTER_TEST(REQTEST_GET_REFERRER, SetupGetReferrerTest, SingleRunTest);
+ REGISTER_TEST(REQTEST_GET_AUTH, SetupGetAuthTest, SingleRunTest);
+ REGISTER_TEST(REQTEST_POST, SetupPostTest, SingleRunTest);
+ REGISTER_TEST(REQTEST_POST_FILE, SetupPostFileTest, SingleRunTest);
+ REGISTER_TEST(REQTEST_POST_WITHPROGRESS, SetupPostWithProgressTest,
+ SingleRunTest);
+ REGISTER_TEST(REQTEST_POST_REDIRECT, SetupPostRedirectTest, SingleRunTest);
+ REGISTER_TEST(REQTEST_POST_REDIRECT_TOGET, SetupPostRedirectToGetTest,
+ SingleRunTest);
+ REGISTER_TEST(REQTEST_HEAD, SetupHeadTest, SingleRunTest);
+ REGISTER_TEST(REQTEST_CACHE_WITH_CONTROL, SetupCacheWithControlTest,
+ MultipleRunTest);
+ REGISTER_TEST(REQTEST_CACHE_WITHOUT_CONTROL, SetupCacheWithoutControlTest,
+ MultipleRunTest);
+ REGISTER_TEST(REQTEST_CACHE_SKIP_FLAG, SetupCacheSkipFlagTest,
+ MultipleRunTest);
+ REGISTER_TEST(REQTEST_CACHE_SKIP_HEADER, SetupCacheSkipHeaderTest,
+ MultipleRunTest);
+ REGISTER_TEST(REQTEST_CACHE_ONLY_FAILURE_FLAG,
+ SetupCacheOnlyFailureFlagTest, MultipleRunTest);
+ REGISTER_TEST(REQTEST_CACHE_ONLY_FAILURE_HEADER,
+ SetupCacheOnlyFailureHeaderTest, MultipleRunTest);
+ REGISTER_TEST(REQTEST_CACHE_ONLY_SUCCESS_FLAG,
+ SetupCacheOnlySuccessFlagTest, MultipleRunTest);
+ REGISTER_TEST(REQTEST_CACHE_ONLY_SUCCESS_HEADER,
+ SetupCacheOnlySuccessHeaderTest, MultipleRunTest);
+ REGISTER_TEST(REQTEST_CACHE_DISABLE_FLAG, SetupCacheDisableFlagTest,
+ MultipleRunTest);
+ REGISTER_TEST(REQTEST_CACHE_DISABLE_HEADER, SetupCacheDisableHeaderTest,
+ MultipleRunTest);
+ REGISTER_TEST(REQTEST_INCOMPLETE_PROCESS_REQUEST,
+ SetupIncompleteProcessRequestTest, SingleRunTest);
+ REGISTER_TEST(REQTEST_INCOMPLETE_READ_RESPONSE,
+ SetupIncompleteReadResponseTest, SingleRunTest);
+ }
+
+ void Destroy() {
+ owner_task_runner_ = nullptr;
+ request_context_ = nullptr;
+ incomplete_request_callback_.Reset();
+ }
+
+ // Called in the browser process to set the request context that will be used
+ // when creating the URL request.
+ void SetRequestContext(CefRefPtr<CefRequestContext> request_context) {
+ request_context_ = request_context;
+ }
+ CefRefPtr<CefRequestContext> GetRequestContext() const {
+ return request_context_;
+ }
+
+ // Called in both the browser and render process to setup the test.
+ void SetupTest(RequestTestMode test_mode,
+ base::OnceClosure complete_callback) {
+ EXPECT_TRUE(owner_task_runner_->BelongsToCurrentThread());
+
+ TestMap::const_iterator it = test_map_.find(test_mode);
+ if (it != test_map_.end()) {
+ auto safe_complete_callback =
+ base::BindOnce(&RequestTestRunner::CompleteOnCorrectThread, this,
+ std::move(complete_callback));
+ it->second.setup.Run(base::BindOnce(&RequestTestRunner::SetupContinue,
+ this,
+ std::move(safe_complete_callback)));
+ } else {
+ // Unknown test.
+ ADD_FAILURE();
+ std::move(complete_callback).Run();
+ }
+ }
+
+ // Called in either the browser or render process to run the test.
+ void RunTest(RequestTestMode test_mode,
+ CefRefPtr<CefFrame> frame,
+ base::OnceClosure complete_callback) {
+ EXPECT_TRUE(owner_task_runner_->BelongsToCurrentThread());
+
+ frame_ = frame;
+
+ TestMap::const_iterator it = test_map_.find(test_mode);
+ if (it != test_map_.end()) {
+ auto safe_complete_callback =
+ base::BindOnce(&RequestTestRunner::CompleteOnCorrectThread, this,
+ std::move(complete_callback));
+ it->second.run.Run(std::move(safe_complete_callback));
+ } else {
+ // Unknown test.
+ ADD_FAILURE();
+ std::move(complete_callback).Run();
+ }
+ }
+
+ // Called in both the browser and render process to shut down the test.
+ void ShutdownTest(base::OnceClosure complete_callback) {
+ EXPECT_TRUE(owner_task_runner_->BelongsToCurrentThread());
+
+ auto safe_complete_callback =
+ base::BindOnce(&RequestTestRunner::CompleteOnCorrectThread, this,
+ std::move(complete_callback));
+
+ if (!post_file_tmpdir_.IsEmpty()) {
+ EXPECT_TRUE(is_browser_process_);
+ CefPostTask(TID_FILE_USER_VISIBLE,
+ base::BindOnce(&RequestTestRunner::RunDeleteTempDirectory,
+ this, std::move(safe_complete_callback)));
+ return;
+ }
+
+ // Continue with test shutdown.
+ RunShutdown(std::move(safe_complete_callback));
+ }
+
+ private:
+ // Continued after |settings_| is populated for the test.
+ void SetupContinue(base::OnceClosure complete_callback) {
+ if (!owner_task_runner_->BelongsToCurrentThread()) {
+ owner_task_runner_->PostTask(CefCreateClosureTask(
+ base::BindOnce(&RequestTestRunner::SetupContinue, this,
+ std::move(complete_callback))));
+ return;
+ }
+
+ if (is_browser_process_) {
+ SetupTestBackend(std::move(complete_callback));
+ } else {
+ std::move(complete_callback).Run();
+ }
+ }
+
+ std::string GetTestPath(const std::string& name) {
+ return std::string(run_in_browser_process_ ? "/Browser" : "/Renderer") +
+ name;
+ }
+
+ std::string GetTestURL(const std::string& name) {
+ // Avoid name duplication between tests running in different processes.
+ // Otherwise we'll get unexpected state leakage (cache hits) when running
+ // multiple tests.
+ return GetRequestOrigin(is_server_backend_) + GetTestPath(name);
+ }
+
+ void SetupGetTestShared() {
+ settings_.request = CefRequest::Create();
+ settings_.request->SetURL(GetTestURL("GetTest.html"));
+ settings_.request->SetMethod("GET");
+
+ settings_.response = CefResponse::Create();
+ settings_.response->SetMimeType("text/html");
+ settings_.response->SetStatus(200);
+ settings_.response->SetStatusText("OK");
+
+ settings_.response_data = "GET TEST SUCCESS";
+ }
+
+ void SetupGetTest(base::OnceClosure complete_callback) {
+ SetupGetTestShared();
+ std::move(complete_callback).Run();
+ }
+
+ void SetupGetNoDataTest(base::OnceClosure complete_callback) {
+ // Start with the normal get test.
+ SetupGetTestShared();
+
+ // Disable download data notifications.
+ settings_.request->SetFlags(UR_FLAG_NO_DOWNLOAD_DATA);
+
+ settings_.expect_download_data = false;
+
+ std::move(complete_callback).Run();
+ }
+
+ void SetupGetPartialContentTest(base::OnceClosure complete_callback) {
+ // Start with the normal get test.
+ SetupGetTestShared();
+
+ // Skip first 4 bytes of content and expect to receive the rest
+ settings_.request->SetHeaderByName("Range", "bytes=4-", true);
+ settings_.response->SetHeaderByName("Content-Range", "bytes 4-8/8", true);
+ settings_.response->SetStatus(206);
+ settings_.response->SetStatusText("Partial Content");
+ settings_.expected_download_offset = 4;
+
+ std::move(complete_callback).Run();
+ }
+
+ void SetupGetAllowCookiesTest(base::OnceClosure complete_callback) {
+ // Start with the normal get test.
+ SetupGetTestShared();
+
+ // Send cookies.
+ settings_.request->SetFlags(UR_FLAG_ALLOW_STORED_CREDENTIALS);
+
+ settings_.expect_save_cookie = true;
+ settings_.expect_send_cookie = true;
+
+ std::move(complete_callback).Run();
+ }
+
+ void SetupGetRedirectTest(base::OnceClosure complete_callback) {
+ // Start with the normal get test.
+ SetupGetTestShared();
+
+ // Add a redirect request.
+ settings_.redirect_request = CefRequest::Create();
+ settings_.redirect_request->SetURL(GetTestURL("redirect.html"));
+ settings_.redirect_request->SetMethod("GET");
+
+ settings_.redirect_response = CefResponse::Create();
+ settings_.redirect_response->SetMimeType("text/html");
+ settings_.redirect_response->SetStatus(302);
+ settings_.redirect_response->SetStatusText("Found");
+
+ CefResponse::HeaderMap headerMap;
+ headerMap.insert(std::make_pair("Location", settings_.request->GetURL()));
+ settings_.redirect_response->SetHeaderMap(headerMap);
+
+ std::move(complete_callback).Run();
+ }
+
+ void SetupGetRedirectStopTest(base::OnceClosure complete_callback) {
+ settings_.request = CefRequest::Create();
+ settings_.request->SetURL(GetTestURL("GetTest.html"));
+ settings_.request->SetMethod("GET");
+
+ // With the test server only the status is expected
+ // on stop redirects.
+ settings_.response = CefResponse::Create();
+ settings_.response->SetStatus(302);
+ if (is_browser_process_) {
+ settings_.response->SetStatusText("Found");
+ }
+
+ // Add a redirect request.
+ settings_.redirect_request = CefRequest::Create();
+ settings_.redirect_request->SetURL(GetTestURL("redirect.html"));
+ settings_.redirect_request->SetMethod("GET");
+ settings_.redirect_request->SetFlags(UR_FLAG_STOP_ON_REDIRECT);
+
+ settings_.redirect_response = CefResponse::Create();
+ settings_.redirect_response->SetMimeType("text/html");
+ settings_.redirect_response->SetStatus(302);
+ settings_.redirect_response->SetStatusText("Found");
+
+ CefResponse::HeaderMap headerMap;
+ headerMap.insert(std::make_pair("Location", settings_.request->GetURL()));
+ settings_.redirect_response->SetHeaderMap(headerMap);
+
+ settings_.expected_status = UR_CANCELED;
+ settings_.expected_error_code = ERR_ABORTED;
+ settings_.expect_download_data = false;
+ settings_.expect_download_progress = false;
+ settings_.expected_send_count = 1;
+ settings_.expected_receive_count = 1;
+
+ std::move(complete_callback).Run();
+ }
+
+ void SetupGetRedirectLocationTest(base::OnceClosure complete_callback) {
+ // Start with the normal get test.
+ SetupGetTestShared();
+
+ // Add a redirect request.
+ settings_.redirect_request = CefRequest::Create();
+ settings_.redirect_request->SetURL(GetTestURL("redirect.html"));
+ settings_.redirect_request->SetMethod("GET");
+
+ settings_.redirect_response = CefResponse::Create();
+ settings_.redirect_response->SetMimeType("text/html");
+ settings_.redirect_response->SetStatus(302);
+ settings_.redirect_response->SetStatusText("Found");
+
+ CefResponse::HeaderMap headerMap;
+ headerMap.insert(std::make_pair("LoCaTioN", GetTestPath("GetTest.html")));
+ settings_.redirect_response->SetHeaderMap(headerMap);
+
+ std::move(complete_callback).Run();
+ }
+
+ void SetupGetReferrerTest(base::OnceClosure complete_callback) {
+ settings_.request = CefRequest::Create();
+ settings_.request->SetURL(GetTestURL("GetTest.html"));
+ settings_.request->SetMethod("GET");
+
+ // The referrer URL must be HTTP or HTTPS. This is enforced by
+ // GURL::GetAsReferrer() called from URLRequest::SetReferrer().
+ settings_.request->SetReferrer("http://tests.com/referrer.html",
+ REFERRER_POLICY_DEFAULT);
+
+ settings_.response = CefResponse::Create();
+ settings_.response->SetMimeType("text/html");
+ settings_.response->SetStatus(200);
+ settings_.response->SetStatusText("OK");
+
+ settings_.response_data = "GET TEST SUCCESS";
+
+ std::move(complete_callback).Run();
+ }
+
+ void SetupGetAuthTest(base::OnceClosure complete_callback) {
+ // Start with the normal get test.
+ SetupGetTestShared();
+
+ // Require Basic authentication.
+ settings_.expect_authentication = true;
+ settings_.username = "user";
+ settings_.password = "pass";
+
+ // This flag is required to support credentials, which means we'll also get
+ // the cookies.
+ settings_.request->SetFlags(UR_FLAG_ALLOW_STORED_CREDENTIALS);
+ settings_.expect_save_cookie = true;
+ settings_.expect_send_cookie = true;
+
+ // The authentication request will come first, then the actual request.
+ settings_.expected_receive_count = 2;
+ settings_.expected_send_count = 2;
+
+ std::move(complete_callback).Run();
+ }
+
+ void SetupPostTestShared() {
+ settings_.request = CefRequest::Create();
+ settings_.request->SetURL(GetTestURL("PostTest.html"));
+ settings_.request->SetMethod("POST");
+ SetUploadData(settings_.request, "the_post_data");
+
+ settings_.response = CefResponse::Create();
+ settings_.response->SetMimeType("text/html");
+ settings_.response->SetStatus(200);
+ settings_.response->SetStatusText("OK");
+
+ settings_.response_data = "POST TEST SUCCESS";
+ }
+
+ void SetupPostTest(base::OnceClosure complete_callback) {
+ SetupPostTestShared();
+ std::move(complete_callback).Run();
+ }
+
+ void SetupPostFileTest(base::OnceClosure complete_callback) {
+ // This test is only supported in the browser process.
+ EXPECT_TRUE(is_browser_process_);
+
+ settings_.request = CefRequest::Create();
+ settings_.request->SetURL(GetTestURL("PostFileTest.html"));
+ settings_.request->SetMethod("POST");
+
+ settings_.response = CefResponse::Create();
+ settings_.response->SetMimeType("text/html");
+ settings_.response->SetStatus(200);
+ settings_.response->SetStatusText("OK");
+
+ settings_.response_data = "POST TEST SUCCESS";
+
+ CefPostTask(TID_FILE_USER_VISIBLE,
+ base::BindOnce(&RequestTestRunner::SetupPostFileTestContinue,
+ this, std::move(complete_callback)));
+ }
+
+ void SetupPostFileTestContinue(base::OnceClosure complete_callback) {
+ EXPECT_TRUE(CefCurrentlyOn(TID_FILE_USER_VISIBLE));
+
+ EXPECT_TRUE(post_file_tmpdir_.CreateUniqueTempDir());
+ const std::string& path =
+ client::file_util::JoinPath(post_file_tmpdir_.GetPath(), "example.txt");
+ const char content[] = "HELLO FRIEND!";
+ int write_ct =
+ client::file_util::WriteFile(path, content, sizeof(content) - 1);
+ EXPECT_EQ(static_cast<int>(sizeof(content) - 1), write_ct);
+ SetUploadFile(settings_.request, path);
+
+ std::move(complete_callback).Run();
+ }
+
+ void SetupPostWithProgressTest(base::OnceClosure complete_callback) {
+ // Start with the normal post test.
+ SetupPostTestShared();
+
+ // Enable upload progress notifications.
+ settings_.request->SetFlags(UR_FLAG_REPORT_UPLOAD_PROGRESS);
+
+ settings_.expect_upload_progress = true;
+
+ std::move(complete_callback).Run();
+ }
+
+ void SetupPostRedirectTest(base::OnceClosure complete_callback) {
+ // Start with the normal post test.
+ SetupPostTestShared();
+
+ // Add a redirect request.
+ settings_.redirect_request = CefRequest::Create();
+ settings_.redirect_request->SetURL(GetTestURL("redirect.html"));
+ settings_.redirect_request->SetMethod("POST");
+ SetUploadData(settings_.redirect_request, "the_post_data");
+
+ settings_.redirect_response = CefResponse::Create();
+ settings_.redirect_response->SetMimeType("text/html");
+ // Only 307 is supported for redirecting the same method and post data.
+ settings_.redirect_response->SetStatus(307);
+ settings_.redirect_response->SetStatusText("Found");
+
+ CefResponse::HeaderMap headerMap;
+ headerMap.insert(std::make_pair("Location", settings_.request->GetURL()));
+ settings_.redirect_response->SetHeaderMap(headerMap);
+
+ std::move(complete_callback).Run();
+ }
+
+ void SetupPostRedirectToGetTest(base::OnceClosure complete_callback) {
+ // Start with the normal post test.
+ SetupPostTestShared();
+
+ // The expected result after redirect is a GET request without POST data.
+ settings_.request = CefRequest::Create();
+ settings_.request->SetURL(GetTestURL("PostTest.html"));
+ settings_.request->SetMethod("GET");
+
+ // Add a redirect request.
+ settings_.redirect_request = CefRequest::Create();
+ settings_.redirect_request->SetURL(GetTestURL("redirect.html"));
+ settings_.redirect_request->SetMethod("POST");
+ SetUploadData(settings_.redirect_request, "the_post_data");
+
+ settings_.redirect_response = CefResponse::Create();
+ settings_.redirect_response->SetMimeType("text/html");
+ // Redirect codes other than 307 will cause conversion to GET and removal
+ // of POST data.
+ settings_.redirect_response->SetStatus(302);
+ settings_.redirect_response->SetStatusText("Found");
+
+ CefResponse::HeaderMap headerMap;
+ headerMap.insert(std::make_pair("Location", settings_.request->GetURL()));
+ settings_.redirect_response->SetHeaderMap(headerMap);
+
+ std::move(complete_callback).Run();
+ }
+
+ void SetupHeadTest(base::OnceClosure complete_callback) {
+ settings_.request = CefRequest::Create();
+ settings_.request->SetURL(GetTestURL("HeadTest.html"));
+ settings_.request->SetMethod("HEAD");
+
+ settings_.response = CefResponse::Create();
+ settings_.response->SetMimeType("text/html");
+ settings_.response->SetStatus(200);
+ settings_.response->SetStatusText("OK");
+
+ // The backend will disregard this value when it returns the result.
+ settings_.response_data = "HEAD TEST SUCCESS";
+
+ settings_.expect_download_progress = false;
+ settings_.expect_download_data = false;
+
+ std::move(complete_callback).Run();
+ }
+
+ void SetupCacheShared(const std::string& name, bool with_cache_control) {
+ // Start with the normal get test.
+ SetupGetTestShared();
+
+ // Specify a unique URL.
+ settings_.request->SetURL(GetTestURL(name));
+
+ if (with_cache_control) {
+ // Allow the page to be cached for 10 seconds.
+ CefResponse::HeaderMap headerMap;
+ headerMap.insert(std::make_pair(kCacheControlHeader, "max-age=10"));
+ settings_.response->SetHeaderMap(headerMap);
+ }
+ }
+
+ void SetupCacheWithControlTest(base::OnceClosure complete_callback) {
+ SetupCacheShared("CacheWithControlTest.html", true);
+
+ // Send multiple requests. With the Cache-Control response header the 2nd+
+ // should receive cached data.
+ settings_.expected_send_count = 3;
+ settings_.expected_receive_count = 1;
+ settings_.setup_next_request =
+ base::BindOnce(&RequestTestRunner::SetupCacheWithControlTestNext, this);
+
+ std::move(complete_callback).Run();
+ }
+
+ void SetupCacheWithControlTestNext(int next_send_count,
+ base::OnceClosure complete_callback) {
+ // Only handle from the cache.
+ settings_.expect_response_was_cached = true;
+
+ // The following requests will use the same setup, so no more callbacks
+ // are required.
+ EXPECT_TRUE(settings_.setup_next_request.is_null());
+
+ std::move(complete_callback).Run();
+ }
+
+ void SetupCacheWithoutControlTest(base::OnceClosure complete_callback) {
+ SetupCacheShared("CacheWithoutControlTest.html", false);
+
+ // Send multiple requests. Without the Cache-Control response header all
+ // should be received.
+ settings_.expected_send_count = 3;
+ settings_.expected_receive_count = 3;
+
+ std::move(complete_callback).Run();
+ }
+
+ void SetupCacheSkipFlagTest(base::OnceClosure complete_callback) {
+ SetupCacheShared("CacheSkipFlagTest.html", true);
+
+ // Skip the cache despite the the Cache-Control response header.
+ // This will not read from the cache, but still write to the cache.
+ settings_.request->SetFlags(UR_FLAG_SKIP_CACHE);
+
+ // Send multiple requests. The 1st request will be handled normally,
+ // but not result in any reads from the cache. The 2nd request will
+ // expect a cached response and the 3nd request will skip the cache
+ // again.
+ settings_.expected_send_count = 3;
+ settings_.expected_receive_count = 2;
+ settings_.setup_next_request =
+ base::BindOnce(&RequestTestRunner::SetupCacheSkipFlagTestNext, this);
+
+ std::move(complete_callback).Run();
+ }
+
+ void SetupCacheSkipFlagTestNext(int next_send_count,
+ base::OnceClosure complete_callback) {
+ // Recreate the request object because the existing object will now be
+ // read-only.
+ EXPECT_TRUE(settings_.request->IsReadOnly());
+ SetupCacheShared("CacheSkipFlagTest.html", true);
+
+ // Expect a cached response.
+ settings_.expect_response_was_cached = true;
+ settings_.setup_next_request =
+ base::BindOnce(&RequestTestRunner::SetupCacheSkipFlagTestLast, this);
+
+ std::move(complete_callback).Run();
+ }
+
+ void SetupCacheSkipFlagTestLast(int next_send_count,
+ base::OnceClosure complete_callback) {
+ // Recreate the request object because the existing object will now be
+ // read-only.
+ EXPECT_TRUE(settings_.request->IsReadOnly());
+ SetupCacheShared("CacheSkipFlagTest.html", true);
+
+ // Skip the cache despite the the Cache-Control response header.
+ settings_.request->SetFlags(UR_FLAG_SKIP_CACHE);
+
+ // Expect the cache to be skipped.
+ settings_.expect_response_was_cached = false;
+ EXPECT_TRUE(settings_.setup_next_request.is_null());
+
+ std::move(complete_callback).Run();
+ }
+
+ void SetupCacheSkipHeaderTest(base::OnceClosure complete_callback) {
+ SetupCacheShared("CacheSkipHeaderTest.html", true);
+
+ // Skip the cache despite the the Cache-Control response header.
+ // This will not read from the cache, but still write to the cache.
+ CefRequest::HeaderMap headerMap;
+ headerMap.insert(std::make_pair(kCacheControlHeader, "no-cache"));
+ settings_.request->SetHeaderMap(headerMap);
+
+ // Send multiple requests. The 1st request will be handled normally,
+ // but not result in any reads from the cache. The 2nd request will
+ // expect a cached response and the 3nd request will skip the cache
+ // again.
+ settings_.expected_send_count = 3;
+ settings_.expected_receive_count = 2;
+ settings_.setup_next_request =
+ base::BindOnce(&RequestTestRunner::SetupCacheSkipHeaderTestNext, this);
+
+ std::move(complete_callback).Run();
+ }
+
+ void SetupCacheSkipHeaderTestNext(int next_send_count,
+ base::OnceClosure complete_callback) {
+ // Recreate the request object because the existing object will now be
+ // read-only.
+ EXPECT_TRUE(settings_.request->IsReadOnly());
+ SetupCacheShared("CacheSkipHeaderTest.html", true);
+
+ // Expect a cached response.
+ settings_.expect_response_was_cached = true;
+ settings_.setup_next_request =
+ base::BindOnce(&RequestTestRunner::SetupCacheSkipHeaderTestLast, this);
+
+ std::move(complete_callback).Run();
+ }
+
+ void SetupCacheSkipHeaderTestLast(int next_send_count,
+ base::OnceClosure complete_callback) {
+ // Recreate the request object because the existing object will now be
+ // read-only.
+ EXPECT_TRUE(settings_.request->IsReadOnly());
+ SetupCacheShared("CacheSkipHeaderTest.html", true);
+
+ // Skip the cache despite the the Cache-Control response header.
+ settings_.request->SetFlags(UR_FLAG_SKIP_CACHE);
+
+ // Expect the cache to be skipped.
+ settings_.expect_response_was_cached = false;
+ EXPECT_TRUE(settings_.setup_next_request.is_null());
+
+ std::move(complete_callback).Run();
+ }
+
+ void SetupCacheOnlyFailureFlagTest(base::OnceClosure complete_callback) {
+ SetupCacheShared("CacheOnlyFailureFlagTest.html", true);
+
+ // Only handle from the cache.
+ settings_.request->SetFlags(UR_FLAG_ONLY_FROM_CACHE);
+
+ // Send multiple requests. All should fail because there's no entry in the
+ // cache currently.
+ settings_.expected_send_count = 3;
+ settings_.expected_receive_count = 0;
+
+ // The request is expected to fail.
+ settings_.SetRequestFailureExpected(ERR_CACHE_MISS);
+
+ std::move(complete_callback).Run();
+ }
+
+ void SetupCacheOnlyFailureHeaderTest(base::OnceClosure complete_callback) {
+ SetupCacheShared("CacheOnlyFailureFlagTest.html", true);
+
+ // Only handle from the cache.
+ CefRequest::HeaderMap headerMap;
+ headerMap.insert(std::make_pair(kCacheControlHeader, "only-if-cached"));
+ settings_.request->SetHeaderMap(headerMap);
+
+ // Send multiple requests. All should fail because there's no entry in the
+ // cache currently.
+ settings_.expected_send_count = 3;
+ settings_.expected_receive_count = 0;
+
+ // The request is expected to fail.
+ settings_.SetRequestFailureExpected(ERR_CACHE_MISS);
+
+ std::move(complete_callback).Run();
+ }
+
+ void SetupCacheOnlySuccessFlagTest(base::OnceClosure complete_callback) {
+ SetupCacheShared("CacheOnlySuccessFlagTest.html", false);
+
+ // Send multiple requests. The 1st request will be handled normally. The
+ // 2nd+ requests will be configured by SetupCacheOnlySuccessFlagNext to
+ // require cached data.
+ settings_.expected_send_count = 3;
+ settings_.expected_receive_count = 1;
+ settings_.setup_next_request =
+ base::BindOnce(&RequestTestRunner::SetupCacheOnlySuccessFlagNext, this);
+
+ std::move(complete_callback).Run();
+ }
+
+ void SetupCacheOnlySuccessFlagNext(int next_send_count,
+ base::OnceClosure complete_callback) {
+ // Recreate the request object because the existing object will now be
+ // read-only.
+ EXPECT_TRUE(settings_.request->IsReadOnly());
+ SetupCacheShared("CacheOnlySuccessFlagTest.html", false);
+
+ // Only handle from the cache.
+ settings_.request->SetFlags(UR_FLAG_ONLY_FROM_CACHE);
+ settings_.expect_response_was_cached = true;
+
+ // The following requests will use the same setup, so no more callbacks
+ // are required.
+ EXPECT_TRUE(settings_.setup_next_request.is_null());
+
+ std::move(complete_callback).Run();
+ }
+
+ void SetupCacheOnlySuccessHeaderTest(base::OnceClosure complete_callback) {
+ SetupCacheShared("CacheOnlySuccessHeaderTest.html", false);
+
+ // Send multiple requests. The 1st request will be handled normally. The
+ // 2nd+ requests will be configured by SetupCacheOnlySuccessHeaderNext to
+ // require cached data.
+ settings_.expected_send_count = 3;
+ settings_.expected_receive_count = 1;
+ settings_.setup_next_request = base::BindOnce(
+ &RequestTestRunner::SetupCacheOnlySuccessHeaderNext, this);
+
+ std::move(complete_callback).Run();
+ }
+
+ void SetupCacheOnlySuccessHeaderNext(int next_send_count,
+ base::OnceClosure complete_callback) {
+ // Recreate the request object because the existing object will now be
+ // read-only.
+ EXPECT_TRUE(settings_.request->IsReadOnly());
+ SetupCacheShared("CacheOnlySuccessHeaderTest.html", false);
+
+ // Only handle from the cache.
+ CefRequest::HeaderMap headerMap;
+ headerMap.insert(std::make_pair(kCacheControlHeader, "only-if-cached"));
+ settings_.request->SetHeaderMap(headerMap);
+ settings_.expect_response_was_cached = true;
+
+ // The following requests will use the same setup, so no more callbacks
+ // are required.
+ EXPECT_TRUE(settings_.setup_next_request.is_null());
+
+ std::move(complete_callback).Run();
+ }
+
+ void SetupCacheDisableFlagTest(base::OnceClosure complete_callback) {
+ SetupCacheShared("CacheDisableFlagTest.html", true);
+
+ // Disable the cache despite the the Cache-Control response header.
+ settings_.request->SetFlags(UR_FLAG_DISABLE_CACHE);
+
+ // Send multiple requests. The 1st request will be handled normally,
+ // but not result in any reads from or writes to the cache.
+ // Therefore all following requests that are set to be only handled
+ // from the cache should fail.
+ settings_.expected_send_count = 3;
+ settings_.expected_receive_count = 1;
+ settings_.setup_next_request =
+ base::BindOnce(&RequestTestRunner::SetupCacheDisableFlagTestNext, this);
+
+ std::move(complete_callback).Run();
+ }
+
+ void SetupCacheDisableFlagTestNext(int next_send_count,
+ base::OnceClosure complete_callback) {
+ // Recreate the request object because the existing object will now be
+ // read-only.
+ EXPECT_TRUE(settings_.request->IsReadOnly());
+ SetupCacheShared("CacheDisableFlagTest.html", true);
+
+ // Only handle from the cache.
+ settings_.request->SetFlags(UR_FLAG_ONLY_FROM_CACHE);
+
+ // The request is expected to fail.
+ settings_.SetRequestFailureExpected(ERR_CACHE_MISS);
+
+ // The following requests will use the same setup, so no more callbacks
+ // are required.
+ EXPECT_TRUE(settings_.setup_next_request.is_null());
+
+ std::move(complete_callback).Run();
+ }
+
+ void SetupCacheDisableHeaderTest(base::OnceClosure complete_callback) {
+ SetupCacheShared("CacheDisableHeaderTest.html", true);
+
+ // Disable the cache despite the the Cache-Control response header.
+ CefRequest::HeaderMap headerMap;
+ headerMap.insert(std::make_pair(kCacheControlHeader, "no-store"));
+ settings_.request->SetHeaderMap(headerMap);
+
+ // Send multiple requests. The 1st request will be handled normally,
+ // but not result in any reads from or writes to the cache.
+ // Therefore all following requests that are set to be only handled
+ // from the cache should fail.
+ settings_.expected_send_count = 3;
+ settings_.expected_receive_count = 1;
+ settings_.setup_next_request = base::BindOnce(
+ &RequestTestRunner::SetupCacheDisableHeaderTestNext, this);
+
+ std::move(complete_callback).Run();
+ }
+
+ void SetupCacheDisableHeaderTestNext(int next_send_count,
+ base::OnceClosure complete_callback) {
+ // Recreate the request object because the existing object will now be
+ // read-only.
+ EXPECT_TRUE(settings_.request->IsReadOnly());
+ SetupCacheShared("CacheDisableHeaderTest.html", true);
+
+ // Only handle from the cache.
+ CefRequest::HeaderMap headerMap;
+ headerMap.insert(std::make_pair(kCacheControlHeader, "only-if-cached"));
+ settings_.request->SetHeaderMap(headerMap);
+
+ // The request is expected to fail.
+ settings_.SetRequestFailureExpected(ERR_CACHE_MISS);
+
+ // The following requests will use the same setup, so no more callbacks
+ // are required.
+ EXPECT_TRUE(settings_.setup_next_request.is_null());
+
+ std::move(complete_callback).Run();
+ }
+
+ void SetupIncompleteProcessRequestTest(base::OnceClosure complete_callback) {
+ // Start with the normal get test.
+ SetupGetTestShared();
+
+ settings_.incomplete_type = RequestRunSettings::INCOMPLETE_PROCESS_REQUEST;
+
+ // There will be no response and the request will be aborted.
+ settings_.response = CefResponse::Create();
+ settings_.response_data.clear();
+ settings_.expected_error_code = ERR_ABORTED;
+ settings_.expected_status = UR_FAILED;
+ settings_.expect_download_progress = false;
+ settings_.expect_download_data = false;
+
+ std::move(complete_callback).Run();
+ }
+
+ void SetupIncompleteReadResponseTest(base::OnceClosure complete_callback) {
+ // Start with the normal get test.
+ SetupGetTestShared();
+
+ settings_.incomplete_type = RequestRunSettings::INCOMPLETE_READ_RESPONSE;
+
+ // There will be a response but the request will be aborted without
+ // receiving any data.
+ settings_.response_data = test_server::kIncompleteDoNotSendData;
+ settings_.expected_error_code = ERR_ABORTED;
+ settings_.expected_status = UR_FAILED;
+ // TODO(network): Download progress notifications are sent for incomplete
+ // (with no data sent) requests in the browser process but not the renderer
+ // process. Consider standardizing this behavior.
+ settings_.expect_download_progress = is_browser_process_;
+ settings_.expect_download_data = false;
+
+ std::move(complete_callback).Run();
+ }
+
+ // Send a request. |complete_callback| will be executed on request completion.
+ void SendRequest(test_request::RequestDoneCallback done_callback) {
+ if (!is_browser_process_) {
+ // Render process requests must use CefFrame::CreateURLRequest.
+ EXPECT_TRUE(use_frame_method_);
+ }
+
+ test_request::SendConfig config;
+
+ if (settings_.redirect_request) {
+ config.request_ = settings_.redirect_request;
+ } else {
+ config.request_ = settings_.request;
+ }
+ EXPECT_TRUE(config.request_.get());
+
+ // Not delegating to CefRequestHandler::GetAuthCredentials.
+ if (!use_frame_method_ && settings_.expect_authentication) {
+ config.has_credentials_ = true;
+ config.username_ = settings_.username;
+ config.password_ = settings_.password;
+ }
+
+ if (use_frame_method_) {
+ EXPECT_TRUE(frame_);
+ config.frame_ = frame_;
+ } else {
+ config.request_context_ = request_context_;
+ }
+
+ test_request::Send(config, std::move(done_callback));
+
+ if (settings_.incomplete_type != RequestRunSettings::INCOMPLETE_NONE) {
+ std::move(incomplete_request_callback_).Run();
+ }
+ }
+
+ // Verify a response.
+ void VerifyResponse(const test_request::State* const client) {
+ CefRefPtr<CefRequest> expected_request;
+ CefRefPtr<CefResponse> expected_response;
+
+ if (settings_.redirect_request) {
+ expected_request = settings_.redirect_request;
+ } else {
+ expected_request = settings_.request;
+ }
+
+ if (settings_.redirect_response && !settings_.expect_follow_redirect) {
+ // A redirect response was sent but the redirect is not expected to be
+ // followed.
+ expected_response = settings_.redirect_response;
+ } else {
+ expected_response = settings_.response;
+ }
+
+ TestRequestEqual(expected_request, client->request_, false);
+
+ EXPECT_EQ(settings_.expected_status, client->status_);
+ EXPECT_EQ(settings_.expected_error_code, client->error_code_);
+ if (expected_response && client->response_) {
+ TestResponseEqual(expected_response, client->response_, true);
+ }
+
+ EXPECT_EQ(settings_.expect_response_was_cached,
+ client->response_was_cached_);
+
+ EXPECT_EQ(1, client->request_complete_ct_);
+
+ if (settings_.expect_upload_progress) {
+ EXPECT_LE(1, client->upload_progress_ct_);
+
+ std::string upload_data;
+ GetUploadData(expected_request, upload_data);
+ EXPECT_EQ((int64)upload_data.size(), client->upload_total_);
+ } else {
+ EXPECT_EQ(0, client->upload_progress_ct_);
+ EXPECT_EQ(0, client->upload_total_);
+ }
+
+ if (settings_.expect_download_progress) {
+ EXPECT_LE(1, client->download_progress_ct_);
+ EXPECT_EQ((int64)(settings_.response_data.size() -
+ settings_.expected_download_offset),
+ client->download_total_);
+ } else {
+ EXPECT_EQ(0, client->download_progress_ct_);
+ EXPECT_EQ(0, client->download_total_);
+ }
+
+ if (settings_.expect_download_data) {
+ size_t expected_offset = settings_.expected_download_offset;
+ EXPECT_LE(1, client->download_data_ct_);
+ EXPECT_STREQ(settings_.response_data.substr(expected_offset).c_str(),
+ client->download_data_.c_str());
+ } else {
+ EXPECT_EQ(0, client->download_data_ct_);
+ EXPECT_TRUE(client->download_data_.empty());
+ }
+
+ if (settings_.expect_authentication) {
+ EXPECT_EQ(1, client->auth_credentials_ct_);
+ } else {
+ EXPECT_EQ(0, client->auth_credentials_ct_);
+ }
+ }
+
+ // Run a test with a single request.
+ void SingleRunTest(base::OnceClosure complete_callback) {
+ SendRequest(base::BindOnce(&RequestTestRunner::SingleRunTestComplete, this,
+ std::move(complete_callback)));
+ }
+
+ void SingleRunTestComplete(base::OnceClosure complete_callback,
+ const test_request::State& completed_client) {
+ VerifyResponse(&completed_client);
+ std::move(complete_callback).Run();
+ }
+
+ // Run a test with multiple requests.
+ void MultipleRunTest(base::OnceClosure complete_callback) {
+ EXPECT_GT(settings_.expected_send_count, 0);
+ EXPECT_GE(settings_.expected_receive_count, 0);
+ MultipleRunTestContinue(std::move(complete_callback), 1);
+ }
+
+ void MultipleRunTestContinue(base::OnceClosure complete_callback,
+ int send_count) {
+ // Send the next request.
+ SendRequest(base::BindOnce(&RequestTestRunner::MultipleRunTestNext, this,
+ std::move(complete_callback), send_count));
+ }
+
+ void MultipleRunTestNext(base::OnceClosure complete_callback,
+ int send_count,
+ const test_request::State& completed_client) {
+ // Verify the completed request.
+ VerifyResponse(&completed_client);
+
+ if (send_count == settings_.expected_send_count) {
+ // All requests complete.
+ std::move(complete_callback).Run();
+ return;
+ }
+
+ const int next_send_count = send_count + 1;
+ auto continue_callback =
+ base::BindOnce(&RequestTestRunner::MultipleRunTestContinue, this,
+ std::move(complete_callback), next_send_count);
+
+ if (!settings_.setup_next_request.is_null()) {
+ // Provide an opportunity to modify expectations before the next request.
+ std::move(settings_.setup_next_request)
+ .Run(next_send_count, std::move(continue_callback));
+ } else {
+ std::move(continue_callback).Run();
+ }
+ }
+
+ // Register a test. Called in the constructor.
+ void RegisterTest(RequestTestMode test_mode,
+ TestCallback setup,
+ TestCallback run) {
+ TestEntry entry = {setup, run};
+ test_map_.insert(std::make_pair(test_mode, entry));
+ }
+
+ void CompleteOnCorrectThread(base::OnceClosure complete_callback) {
+ if (!owner_task_runner_->BelongsToCurrentThread()) {
+ owner_task_runner_->PostTask(CefCreateClosureTask(
+ base::BindOnce(&RequestTestRunner::CompleteOnCorrectThread, this,
+ std::move(complete_callback))));
+ return;
+ }
+
+ std::move(complete_callback).Run();
+ }
+
+ void RunDeleteTempDirectory(base::OnceClosure complete_callback) {
+ EXPECT_TRUE(CefCurrentlyOn(TID_FILE_USER_VISIBLE));
+
+ EXPECT_TRUE(post_file_tmpdir_.Delete());
+ EXPECT_TRUE(post_file_tmpdir_.IsEmpty());
+
+ // Continue with test shutdown.
+ RunShutdown(std::move(complete_callback));
+ }
+
+ void RunShutdown(base::OnceClosure complete_callback) {
+ if (!owner_task_runner_->BelongsToCurrentThread()) {
+ owner_task_runner_->PostTask(CefCreateClosureTask(
+ base::BindOnce(&RequestTestRunner::RunShutdown, this,
+ std::move(complete_callback))));
+ return;
+ }
+
+ if (is_browser_process_) {
+ ShutdownTestBackend(std::move(complete_callback));
+ } else {
+ std::move(complete_callback).Run();
+ }
+ }
+
+ // Create the backend for the current test. Called during test setup.
+ void SetupTestBackend(base::OnceClosure complete_callback) {
+ // Backends are only created in the browser process.
+ EXPECT_TRUE(is_browser_process_);
+
+ EXPECT_TRUE(settings_.request.get());
+ EXPECT_TRUE(settings_.response.get() ||
+ settings_.expected_status == UR_FAILED);
+
+ if (is_server_backend_) {
+ StartServer(std::move(complete_callback));
+ } else {
+ AddSchemeHandler(std::move(complete_callback));
+ }
+ }
+
+ void StartServer(base::OnceClosure complete_callback) {
+ EXPECT_FALSE(server_handler_);
+
+ server_handler_ = new RequestServerHandler();
+
+ server_handler_->AddSchemeHandler(&settings_);
+ if (settings_.expected_receive_count >= 0) {
+ server_handler_->SetExpectedRequestCount(
+ settings_.expected_receive_count);
+ }
+
+ server_handler_->CreateServer(std::move(complete_callback));
+ }
+
+ void AddSchemeHandler(base::OnceClosure complete_callback) {
+ EXPECT_FALSE(scheme_factory_);
+
+ // Add the factory registration.
+ scheme_factory_ = new RequestSchemeHandlerFactory();
+ request_context_->RegisterSchemeHandlerFactory(GetRequestScheme(false),
+ GetRequestHost(false, false),
+ scheme_factory_.get());
+
+ scheme_factory_->AddSchemeHandler(&settings_);
+
+ // Any further calls will come from the IO thread.
+ scheme_factory_->SetOwnerTaskRunner(CefTaskRunner::GetForThread(TID_IO));
+
+ std::move(complete_callback).Run();
+ }
+
+ // Shutdown the backend for the current test. Called during test shutdown.
+ void ShutdownTestBackend(base::OnceClosure complete_callback) {
+ // Backends are only created in the browser process.
+ EXPECT_TRUE(is_browser_process_);
+ if (is_server_backend_) {
+ ShutdownServer(std::move(complete_callback));
+ } else {
+ RemoveSchemeHandler(std::move(complete_callback));
+ }
+ }
+
+ void ShutdownServer(base::OnceClosure complete_callback) {
+ EXPECT_TRUE(server_handler_);
+
+ // |server_handler_| will delete itself after shutdown.
+ server_handler_->ShutdownServer(std::move(complete_callback));
+ server_handler_ = nullptr;
+ }
+
+ void RemoveSchemeHandler(base::OnceClosure complete_callback) {
+ EXPECT_TRUE(scheme_factory_);
+
+ // Remove the factory registration.
+ request_context_->RegisterSchemeHandlerFactory(
+ GetRequestScheme(false), GetRequestHost(false, false), nullptr);
+ scheme_factory_->Shutdown(std::move(complete_callback));
+ scheme_factory_ = nullptr;
+ }
+
+ const bool is_browser_process_;
+ const bool is_server_backend_;
+ const bool use_frame_method_;
+ const bool run_in_browser_process_;
+
+ // Used with incomplete request tests.
+ base::OnceClosure incomplete_request_callback_;
+
+ // Primary thread runner for the object that owns us. In the browser process
+ // this will be the UI thread and in the renderer process this will be the
+ // RENDERER thread.
+ CefRefPtr<CefTaskRunner> owner_task_runner_;
+
+ CefRefPtr<CefRequestContext> request_context_;
+
+ // Frame that originates the request. May be nullptr.
+ CefRefPtr<CefFrame> frame_;
+
+ struct TestEntry {
+ TestCallback setup;
+ TestCallback run;
+ };
+ typedef std::map<RequestTestMode, TestEntry> TestMap;
+ TestMap test_map_;
+
+ // Server backend.
+ RequestServerHandler* server_handler_ = nullptr;
+
+ // Scheme handler backend.
+ std::string scheme_name_;
+ CefRefPtr<RequestSchemeHandlerFactory> scheme_factory_;
+
+ CefScopedTempDir post_file_tmpdir_;
+
+ public:
+ RequestRunSettings settings_;
+};
+
+// RENDERER-SIDE TEST HARNESS
+
+class RequestRendererTest : public ClientAppRenderer::Delegate {
+ public:
+ RequestRendererTest() {}
+
+ bool OnProcessMessageReceived(CefRefPtr<ClientAppRenderer> app,
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefProcessId source_process,
+ CefRefPtr<CefProcessMessage> message) override {
+ if (message->GetName() == kRequestTestMsg) {
+ EXPECT_TRUE(CefCurrentlyOn(TID_RENDERER));
+ EXPECT_TRUE(frame->IsMain());
+
+ app_ = app;
+ browser_ = browser;
+ frame_ = nullptr;
+
+ CefRefPtr<CefListValue> args = message->GetArgumentList();
+
+ const bool use_frame_method = args->GetBool(2);
+ if (use_frame_method) {
+ frame_ = frame;
+ }
+
+ test_mode_ = static_cast<RequestTestMode>(args->GetInt(0));
+ test_runner_ = new RequestTestRunner(
+ false, args->GetBool(1), use_frame_method, false,
+ base::BindOnce(&RequestRendererTest::OnIncompleteRequest, this));
+ test_runner_->Initialize();
+
+ // Setup the test. This will create the objects that we test against but
+ // not register any backend (because we're in the render process).
+ test_runner_->SetupTest(
+ test_mode_,
+ base::BindOnce(&RequestRendererTest::OnSetupComplete, this));
+
+ return true;
+ }
+
+ // Message not handled.
+ return false;
+ }
+
+ private:
+ void OnSetupComplete() {
+ EXPECT_TRUE(CefCurrentlyOn(TID_RENDERER));
+
+ // Run the test.
+ test_runner_->RunTest(
+ test_mode_, frame_,
+ base::BindOnce(&RequestRendererTest::OnRunComplete, this));
+ }
+
+ void OnRunComplete() {
+ EXPECT_TRUE(CefCurrentlyOn(TID_RENDERER));
+
+ // Shutdown the test.
+ test_runner_->ShutdownTest(
+ base::BindOnce(&RequestRendererTest::OnShutdownComplete, this));
+ }
+
+ void OnIncompleteRequest() {
+ EXPECT_TRUE(CefCurrentlyOn(TID_RENDERER));
+
+ // This method will only be called for incomplete requests.
+ EXPECT_NE(test_runner_->settings_.incomplete_type,
+ RequestRunSettings::INCOMPLETE_NONE);
+
+ // Check if the test has failed.
+ bool result = !TestFailed();
+
+ // The browser will be closed to abort in-progress requests.
+ CefRefPtr<CefProcessMessage> return_msg =
+ CefProcessMessage::Create(kIncompleteRequestTestMsg);
+ EXPECT_TRUE(return_msg->GetArgumentList()->SetBool(0, result));
+ browser_->GetMainFrame()->SendProcessMessage(PID_BROWSER, return_msg);
+ }
+
+ void OnShutdownComplete() {
+ EXPECT_TRUE(CefCurrentlyOn(TID_RENDERER));
+
+ if (test_runner_->settings_.incomplete_type !=
+ RequestRunSettings::INCOMPLETE_NONE) {
+ // For incomplete tests there's a race between process destruction due to
+ // the browser closing, and the test possibly completing due to request
+ // cancellation. We therefore ignore test completion in this case.
+ return;
+ }
+
+ // Check if the test has failed.
+ bool result = !TestFailed();
+
+ // Return the result to the browser process.
+ CefRefPtr<CefProcessMessage> return_msg =
+ CefProcessMessage::Create(kRequestTestMsg);
+ EXPECT_TRUE(return_msg->GetArgumentList()->SetBool(0, result));
+ browser_->GetMainFrame()->SendProcessMessage(PID_BROWSER, return_msg);
+
+ app_ = nullptr;
+ browser_ = nullptr;
+ }
+
+ CefRefPtr<ClientAppRenderer> app_;
+ CefRefPtr<CefBrowser> browser_;
+ CefRefPtr<CefFrame> frame_;
+ RequestTestMode test_mode_;
+
+ scoped_refptr<RequestTestRunner> test_runner_;
+
+ IMPLEMENT_REFCOUNTING(RequestRendererTest);
+};
+
+// BROWSER-SIDE TEST HARNESS
+
+class RequestTestHandler : public TestHandler {
+ public:
+ RequestTestHandler(RequestTestMode test_mode,
+ ContextTestMode context_mode,
+ bool test_in_browser,
+ bool test_server_backend,
+ bool test_frame_method)
+ : test_mode_(test_mode),
+ context_mode_(context_mode),
+ test_in_browser_(test_in_browser),
+ test_server_backend_(test_server_backend),
+ test_frame_method_(test_frame_method),
+ // Must use the request origin to avoid failures in
+ // CorsURLLoaderFactory::IsSane for requests originating from the
+ // renderer process.
+ test_url_(GetRequestOrigin(test_server_backend) +
+ "/URLRequestTest.Test") {}
+
+ void RunTest() override {
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout(5000);
+
+ // Start pre-setup actions.
+ PreSetupStart();
+ }
+
+ void PreSetupStart() {
+ CefPostTask(TID_FILE_USER_VISIBLE,
+ base::BindOnce(&RequestTestHandler::PreSetupFileTasks, this));
+ }
+
+ void PreSetupFileTasks() {
+ EXPECT_TRUE(CefCurrentlyOn(TID_FILE_USER_VISIBLE));
+
+ if (context_mode_ == CONTEXT_ONDISK) {
+ EXPECT_TRUE(context_tmpdir_.CreateUniqueTempDirUnderPath(
+ CefTestSuite::GetInstance()->root_cache_path()));
+ context_tmpdir_path_ = context_tmpdir_.GetPath();
+ EXPECT_FALSE(context_tmpdir_path_.empty());
+ }
+
+ CefPostTask(TID_UI,
+ base::BindOnce(&RequestTestHandler::PreSetupContinue, this));
+ }
+
+ void PreSetupContinue() {
+ EXPECT_TRUE(CefCurrentlyOn(TID_UI));
+
+ test_runner_ = new RequestTestRunner(
+ true, test_server_backend_, test_frame_method_, test_in_browser_,
+ base::BindOnce(&RequestTestHandler::OnIncompleteRequest, this));
+ test_runner_->Initialize();
+
+ // Get or create the request context.
+ if (context_mode_ == CONTEXT_GLOBAL) {
+ CefRefPtr<CefRequestContext> request_context =
+ CefRequestContext::GetGlobalContext();
+ EXPECT_TRUE(request_context.get());
+ test_runner_->SetRequestContext(request_context);
+
+ PreSetupComplete();
+ } else {
+ // Don't end the test until the temporary request context has been
+ // destroyed.
+ SetSignalCompletionWhenAllBrowsersClose(false);
+
+ CefRequestContextSettings settings;
+
+ if (context_mode_ == CONTEXT_ONDISK) {
+ EXPECT_FALSE(context_tmpdir_.IsEmpty());
+ CefString(&settings.cache_path) = context_tmpdir_path_;
+ }
+
+ if (!test_server_backend_) {
+ // Set the schemes that are allowed to store cookies.
+ CefString(&settings.cookieable_schemes_list) = GetRequestScheme(false);
+ }
+
+ // Create a new temporary request context. Calls OnContextInitialized.
+ CefRequestContext::CreateContext(settings,
+ new RequestContextHandler(this));
+ }
+ }
+
+ void OnContextInitialized(CefRefPtr<CefRequestContext> request_context) {
+ EXPECT_TRUE(CefCurrentlyOn(TID_UI));
+ EXPECT_TRUE(request_context.get());
+ test_runner_->SetRequestContext(request_context);
+ PreSetupComplete();
+ }
+
+ void PreSetupComplete() {
+ if (!CefCurrentlyOn(TID_UI)) {
+ CefPostTask(TID_UI,
+ base::BindOnce(&RequestTestHandler::PreSetupComplete, this));
+ return;
+ }
+
+ // Setup the test. This will create the objects that we test against and
+ // register the backend.
+ test_runner_->SetupTest(
+ test_mode_, base::BindOnce(&RequestTestHandler::OnSetupComplete, this));
+ }
+
+ // Browser process setup is complete.
+ void OnSetupComplete() {
+ // Start post-setup actions.
+ SetTestCookie(test_runner_->GetRequestContext(), test_server_backend_,
+ base::BindOnce(&RequestTestHandler::PostSetupComplete, this));
+ }
+
+ void PostSetupComplete() {
+ if (!CefCurrentlyOn(TID_UI)) {
+ CefPostTask(TID_UI,
+ base::BindOnce(&RequestTestHandler::PostSetupComplete, this));
+ return;
+ }
+
+ if (test_in_browser_) {
+ if (test_frame_method_) {
+ AddResource(test_url_, "<html><body>TEST</body></html>", "text/html");
+
+ // Create the browser who's main frame will be the initiator for the
+ // request.
+ CreateBrowser(test_url_, test_runner_->GetRequestContext());
+ } else {
+ // Run the test now.
+ test_running_ = true;
+ test_runner_->RunTest(
+ test_mode_, nullptr /* frame */,
+ base::BindOnce(&RequestTestHandler::OnRunComplete, this));
+ }
+ } else {
+ AddResource(test_url_, "<html><body>TEST</body></html>", "text/html");
+
+ // Create a browser to run the test in the renderer process.
+ CreateBrowser(test_url_, test_runner_->GetRequestContext());
+ }
+ }
+
+ ReturnValue OnBeforeResourceLoad(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefRequest> request,
+ CefRefPtr<CefCallback> callback) override {
+ if (test_running_ && test_frame_method_) {
+ EXPECT_TRUE(frame);
+ EXPECT_EQ(test_frame_->GetIdentifier(), frame->GetIdentifier());
+ test_frame_resource_load_ct_++;
+ }
+
+ return TestHandler::OnBeforeResourceLoad(browser, frame, request, callback);
+ }
+
+ bool GetAuthCredentials(CefRefPtr<CefBrowser> browser,
+ const CefString& origin_url,
+ bool isProxy,
+ const CefString& host,
+ int port,
+ const CefString& realm,
+ const CefString& scheme,
+ CefRefPtr<CefAuthCallback> callback) override {
+ EXPECT_TRUE(test_in_browser_);
+ EXPECT_TRUE(test_frame_method_);
+ auth_credentials_ct_++;
+ if (test_runner_->settings_.expect_authentication) {
+ callback->Continue(test_runner_->settings_.username,
+ test_runner_->settings_.password);
+ return true;
+ }
+ return false;
+ }
+
+ void OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int httpStatusCode) override {
+ if (test_in_browser_ && test_frame_method_) {
+ // Run the test now.
+ test_frame_ = frame;
+ test_running_ = true;
+ test_runner_->RunTest(
+ test_mode_, frame,
+ base::BindOnce(&RequestTestHandler::OnRunComplete, this));
+ return;
+ }
+
+ EXPECT_FALSE(test_in_browser_);
+ if (frame->IsMain()) {
+ CefRefPtr<CefProcessMessage> test_message =
+ CefProcessMessage::Create(kRequestTestMsg);
+ CefRefPtr<CefListValue> args = test_message->GetArgumentList();
+ EXPECT_TRUE(args->SetInt(0, test_mode_));
+ EXPECT_TRUE(args->SetBool(1, test_server_backend_));
+ EXPECT_TRUE(args->SetBool(2, test_frame_method_));
+
+ if (test_frame_method_) {
+ test_frame_ = frame;
+ }
+ test_running_ = true;
+
+ // Send a message to the renderer process to run the test.
+ frame->SendProcessMessage(PID_RENDERER, test_message);
+ }
+ }
+
+ bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefProcessId source_process,
+ CefRefPtr<CefProcessMessage> message) override {
+ EXPECT_TRUE(browser.get());
+ EXPECT_TRUE(frame.get());
+ EXPECT_EQ(PID_RENDERER, source_process);
+ EXPECT_TRUE(message.get());
+ EXPECT_TRUE(message->IsReadOnly());
+ EXPECT_FALSE(test_in_browser_);
+
+ EXPECT_FALSE(got_message_);
+ got_message_.yes();
+
+ if (message->GetArgumentList()->GetBool(0)) {
+ got_success_.yes();
+ }
+
+ const std::string& message_name = message->GetName();
+ if (message_name == kRequestTestMsg) {
+ // Renderer process test is complete.
+ OnRunComplete();
+ } else if (message_name == kIncompleteRequestTestMsg) {
+ // Incomplete renderer tests will not complete normally. Instead, trigger
+ // browser close and then signal completion from OnBeforeClose.
+ OnIncompleteRequest();
+ }
+
+ return true;
+ }
+
+ void OnBeforeClose(CefRefPtr<CefBrowser> browser) override {
+ if (!test_in_browser_ && test_runner_->settings_.incomplete_type !=
+ RequestRunSettings::INCOMPLETE_NONE) {
+ // Incomplete tests running in the renderer process will never recieve the
+ // test complete process message, so call the method here.
+ OnRunComplete();
+ }
+
+ TestHandler::OnBeforeClose(browser);
+ }
+
+ // Incomplete tests will not complete normally. Instead, we trigger a browser
+ // close to abort in-progress requests.
+ void OnIncompleteRequest() {
+ if (!CefCurrentlyOn(TID_UI)) {
+ CefPostTask(TID_UI, base::BindOnce(
+ &RequestTestHandler::OnIncompleteRequest, this));
+ return;
+ }
+
+ EXPECT_TRUE(test_frame_method_);
+ EXPECT_NE(RequestRunSettings::INCOMPLETE_NONE,
+ test_runner_->settings_.incomplete_type);
+
+ // TestComplete will eventually be called from DestroyTest instead of being
+ // triggered by browser destruction.
+ SetSignalCompletionWhenAllBrowsersClose(false);
+ CefPostDelayedTask(
+ TID_UI, base::BindOnce(&TestHandler::CloseBrowser, GetBrowser(), false),
+ 1000);
+ }
+
+ // Test run is complete. It ran in either the browser or render process.
+ void OnRunComplete() {
+ GetTestCookie(test_runner_->GetRequestContext(), test_server_backend_,
+ base::BindOnce(&RequestTestHandler::PostRunComplete, this));
+ }
+
+ void PostRunComplete(bool has_save_cookie) {
+ if (!CefCurrentlyOn(TID_UI)) {
+ CefPostTask(TID_UI, base::BindOnce(&RequestTestHandler::PostRunComplete,
+ this, has_save_cookie));
+ return;
+ }
+
+ EXPECT_EQ(test_runner_->settings_.expect_save_cookie, has_save_cookie);
+
+ // Shut down the browser side of the test.
+ test_runner_->ShutdownTest(
+ base::BindOnce(&RequestTestHandler::MaybeClearAuthCredentials, this));
+ }
+
+ void MaybeClearAuthCredentials() {
+ if (test_runner_->settings_.expect_authentication &&
+ context_mode_ == CONTEXT_GLOBAL) {
+ // Clear the HTTP authentication cache to avoid leaking state between
+ // test runs when using the global request context.
+ test_runner_->GetRequestContext()->ClearHttpAuthCredentials(
+ new TestCompletionCallback(
+ base::BindOnce(&RequestTestHandler::DestroyTest, this)));
+ return;
+ }
+
+ DestroyTest();
+ }
+
+ void DestroyTest() override {
+ if (!test_in_browser_) {
+ EXPECT_TRUE(got_message_);
+ EXPECT_TRUE(got_success_);
+ }
+
+ if (test_frame_method_) {
+ // Expect at least 1 call to OnBeforeResourceLoad for every test.
+ // Redirect tests may get multiple calls.
+ EXPECT_LE(1, test_frame_resource_load_ct_);
+ }
+
+ // CefRequestHandler::GetAuthCredentials should be called after
+ // CefURLRequestClient::GetAuthCredentials when the request has an
+ // associated frame.
+ if (test_in_browser_ && test_frame_method_ &&
+ test_runner_->settings_.expect_authentication) {
+ EXPECT_EQ(1, auth_credentials_ct_);
+ } else {
+ EXPECT_EQ(0, auth_credentials_ct_);
+ }
+
+ TestHandler::DestroyTest();
+
+ // For non-global contexts OnTestComplete() will be called when the
+ // RequestContextHandler is destroyed.
+ bool call_test_complete = false;
+ if (context_mode_ == CONTEXT_GLOBAL) {
+ if (test_in_browser_ && !test_frame_method_) {
+ // These tests don't create a browser that would signal implicitly.
+ call_test_complete = true;
+ } else if (!SignalCompletionWhenAllBrowsersClose()) {
+ // These tests close the browser to terminate in-progress requests
+ // before test completion.
+ call_test_complete = true;
+ }
+ }
+
+ // Release references to the context and handler.
+ test_runner_->Destroy();
+
+ if (call_test_complete) {
+ OnTestComplete();
+ }
+ }
+
+ void OnTestComplete() {
+ if (!CefCurrentlyOn(TID_UI)) {
+ CefPostTask(TID_UI,
+ base::BindOnce(&RequestTestHandler::OnTestComplete, this));
+ return;
+ }
+
+ EXPECT_FALSE(got_on_test_complete_);
+ got_on_test_complete_.yes();
+
+ if (!context_tmpdir_.IsEmpty()) {
+ // Temp directory will be deleted on application shutdown.
+ context_tmpdir_.Take();
+ }
+
+ TestComplete();
+ }
+
+ private:
+ // Used with temporary request contexts to signal test completion once the
+ // temporary context has been destroyed.
+ class RequestContextHandler : public CefRequestContextHandler {
+ public:
+ explicit RequestContextHandler(CefRefPtr<RequestTestHandler> test_handler)
+ : test_handler_(test_handler) {}
+ ~RequestContextHandler() override { test_handler_->OnTestComplete(); }
+
+ void OnRequestContextInitialized(
+ CefRefPtr<CefRequestContext> request_context) override {
+ test_handler_->OnContextInitialized(request_context);
+ }
+
+ private:
+ CefRefPtr<RequestTestHandler> test_handler_;
+
+ IMPLEMENT_REFCOUNTING(RequestContextHandler);
+ };
+
+ const RequestTestMode test_mode_;
+ const ContextTestMode context_mode_;
+ const bool test_in_browser_;
+ const bool test_server_backend_;
+ const bool test_frame_method_;
+ const std::string test_url_;
+
+ scoped_refptr<RequestTestRunner> test_runner_;
+
+ bool test_running_ = false;
+
+ CefRefPtr<CefFrame> test_frame_;
+ int test_frame_resource_load_ct_ = 0;
+
+ CefScopedTempDir context_tmpdir_;
+ CefString context_tmpdir_path_;
+
+ public:
+ // Only used when the test runs in the render process.
+ TrackCallback got_message_;
+ TrackCallback got_success_;
+
+ int auth_credentials_ct_ = 0;
+ TrackCallback got_on_test_complete_;
+
+ IMPLEMENT_REFCOUNTING(RequestTestHandler);
+};
+
+bool IsTestSupported(RequestTestMode test_mode,
+ ContextTestMode context_mode,
+ bool test_in_browser,
+ bool test_server_backend,
+ bool test_frame_method) {
+ if (!test_in_browser && !test_frame_method) {
+ // Render process requests must use CefFrame::CreateURLRequest.
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace
+
+// Entry point for creating URLRequest renderer test objects.
+// Called from client_app_delegates.cc.
+void CreateURLRequestRendererTests(ClientAppRenderer::DelegateSet& delegates) {
+ delegates.insert(new RequestRendererTest);
+}
+
+// Entry point for registering custom schemes.
+// Called from client_app_delegates.cc.
+void RegisterURLRequestCustomSchemes(CefRawPtr<CefSchemeRegistrar> registrar) {
+ const std::string& scheme = GetRequestScheme(false);
+ registrar->AddCustomScheme(
+ scheme, CEF_SCHEME_OPTION_STANDARD | CEF_SCHEME_OPTION_CORS_ENABLED);
+}
+
+// Entry point for registering cookieable schemes.
+// Called from client_app_delegates.cc.
+void RegisterURLRequestCookieableSchemes(
+ std::vector<std::string>& cookieable_schemes) {
+ const std::string& scheme = GetRequestScheme(false);
+ cookieable_schemes.push_back(scheme);
+}
+
+// Helpers for defining URLRequest tests.
+#define REQ_TEST_EX(name, test_mode, context_mode, test_in_browser, \
+ test_server_backend, test_frame_method) \
+ TEST(URLRequestTest, name) { \
+ if (!IsTestSupported(test_mode, context_mode, test_in_browser, \
+ test_server_backend, test_frame_method)) { \
+ return; \
+ } \
+ CefRefPtr<RequestTestHandler> handler = \
+ new RequestTestHandler(test_mode, context_mode, test_in_browser, \
+ test_server_backend, test_frame_method); \
+ handler->ExecuteTest(); \
+ ReleaseAndWaitForDestructor(handler); \
+ }
+
+#define REQ_TEST(name, test_mode, context_mode, test_in_browser, \
+ test_server_backend, test_frame_method) \
+ REQ_TEST_EX(name, test_mode, context_mode, test_in_browser, \
+ test_server_backend, test_frame_method)
+
+// Define the tests.
+#define REQ_TEST_SET_EX(suffix, context_mode, test_server_backend, \
+ test_frame_method) \
+ REQ_TEST(BrowserGET##suffix, REQTEST_GET, context_mode, true, \
+ test_server_backend, test_frame_method) \
+ REQ_TEST(BrowserGETNoData##suffix, REQTEST_GET_NODATA, context_mode, true, \
+ test_server_backend, test_frame_method) \
+ REQ_TEST(BrowserGETPartialContent##suffix, REQTEST_GET_PARTIAL_CONTENT, \
+ context_mode, true, test_server_backend, test_frame_method) \
+ REQ_TEST(BrowserGETAllowCookies##suffix, REQTEST_GET_ALLOWCOOKIES, \
+ context_mode, true, test_server_backend, test_frame_method) \
+ REQ_TEST(BrowserGETRedirect##suffix, REQTEST_GET_REDIRECT, context_mode, \
+ true, test_server_backend, test_frame_method) \
+ REQ_TEST(BrowserGETRedirectStop##suffix, REQTEST_GET_REDIRECT_STOP, \
+ context_mode, true, test_server_backend, test_frame_method) \
+ REQ_TEST(BrowserGETRedirectLocation##suffix, REQTEST_GET_REDIRECT_LOCATION, \
+ context_mode, true, test_server_backend, test_frame_method) \
+ REQ_TEST(BrowserGETReferrer##suffix, REQTEST_GET_REFERRER, context_mode, \
+ true, test_server_backend, test_frame_method) \
+ REQ_TEST(BrowserPOST##suffix, REQTEST_POST, context_mode, true, \
+ test_server_backend, test_frame_method) \
+ REQ_TEST(BrowserPOSTFile##suffix, REQTEST_POST_FILE, context_mode, true, \
+ test_server_backend, test_frame_method) \
+ REQ_TEST(BrowserPOSTWithProgress##suffix, REQTEST_POST_WITHPROGRESS, \
+ context_mode, true, test_server_backend, test_frame_method) \
+ REQ_TEST(BrowserPOSTRedirect##suffix, REQTEST_POST_REDIRECT, context_mode, \
+ true, test_server_backend, test_frame_method) \
+ REQ_TEST(BrowserPOSTRedirectToGET##suffix, REQTEST_POST_REDIRECT_TOGET, \
+ context_mode, true, test_server_backend, test_frame_method) \
+ REQ_TEST(BrowserHEAD##suffix, REQTEST_HEAD, context_mode, true, \
+ test_server_backend, test_frame_method) \
+ REQ_TEST(RendererGET##suffix, REQTEST_GET, context_mode, false, \
+ test_server_backend, test_frame_method) \
+ REQ_TEST(RendererGETNoData##suffix, REQTEST_GET_NODATA, context_mode, false, \
+ test_server_backend, test_frame_method) \
+ REQ_TEST(RendererGETAllowCookies##suffix, REQTEST_GET_ALLOWCOOKIES, \
+ context_mode, false, test_server_backend, test_frame_method) \
+ REQ_TEST(RendererGETRedirect##suffix, REQTEST_GET_REDIRECT, context_mode, \
+ false, test_server_backend, test_frame_method) \
+ REQ_TEST(RendererGETRedirectStop##suffix, REQTEST_GET_REDIRECT_STOP, \
+ context_mode, false, test_server_backend, test_frame_method) \
+ REQ_TEST(RendererGETRedirectLocation##suffix, REQTEST_GET_REDIRECT_LOCATION, \
+ context_mode, false, test_server_backend, test_frame_method) \
+ REQ_TEST(RendererGETReferrer##suffix, REQTEST_GET_REFERRER, context_mode, \
+ false, test_server_backend, test_frame_method) \
+ REQ_TEST(RendererPOST##suffix, REQTEST_POST, context_mode, false, \
+ test_server_backend, test_frame_method) \
+ REQ_TEST(RendererPOSTWithProgress##suffix, REQTEST_POST_WITHPROGRESS, \
+ context_mode, false, test_server_backend, test_frame_method) \
+ REQ_TEST(RendererPOSTRedirect##suffix, REQTEST_POST_REDIRECT, context_mode, \
+ false, test_server_backend, test_frame_method) \
+ REQ_TEST(RendererPOSTRedirectToGET##suffix, REQTEST_POST_REDIRECT_TOGET, \
+ context_mode, false, test_server_backend, test_frame_method) \
+ REQ_TEST(RendererHEAD##suffix, REQTEST_HEAD, context_mode, false, \
+ test_server_backend, test_frame_method)
+
+#define REQ_TEST_SET(suffix, test_frame_method) \
+ REQ_TEST_SET_EX(ContextGlobalCustom##suffix, CONTEXT_GLOBAL, false, \
+ test_frame_method) \
+ REQ_TEST_SET_EX(ContextInMemoryCustom##suffix, CONTEXT_INMEMORY, false, \
+ test_frame_method) \
+ REQ_TEST_SET_EX(ContextOnDiskCustom##suffix, CONTEXT_ONDISK, false, \
+ test_frame_method) \
+ REQ_TEST_SET_EX(ContextGlobalServer##suffix, CONTEXT_GLOBAL, true, \
+ test_frame_method) \
+ REQ_TEST_SET_EX(ContextInMemoryServer##suffix, CONTEXT_INMEMORY, true, \
+ test_frame_method) \
+ REQ_TEST_SET_EX(ContextOnDiskServer##suffix, CONTEXT_ONDISK, true, \
+ test_frame_method)
+
+REQ_TEST_SET(WithoutFrame, false)
+REQ_TEST_SET(WithFrame, true)
+
+// Define tests that can only run with a frame.
+#define REQ_TEST_FRAME_SET_EX(suffix, context_mode, test_server_backend) \
+ REQ_TEST(BrowserIncompleteProcessRequest##suffix, \
+ REQTEST_INCOMPLETE_PROCESS_REQUEST, context_mode, true, \
+ test_server_backend, true) \
+ REQ_TEST(BrowserIncompleteReadResponse##suffix, \
+ REQTEST_INCOMPLETE_READ_RESPONSE, context_mode, true, \
+ test_server_backend, true) \
+ REQ_TEST(RendererIncompleteProcessRequest##suffix, \
+ REQTEST_INCOMPLETE_PROCESS_REQUEST, context_mode, false, \
+ test_server_backend, true) \
+ REQ_TEST(RendererIncompleteReadResponse##suffix, \
+ REQTEST_INCOMPLETE_READ_RESPONSE, context_mode, false, \
+ test_server_backend, true)
+
+#define REQ_TEST_FRAME_SET() \
+ REQ_TEST_FRAME_SET_EX(ContextGlobalCustomWithFrame, CONTEXT_GLOBAL, false) \
+ REQ_TEST_FRAME_SET_EX(ContextInMemoryCustomWithFrame, CONTEXT_INMEMORY, \
+ false) \
+ REQ_TEST_FRAME_SET_EX(ContextOnDiskCustomWithFrame, CONTEXT_ONDISK, false) \
+ REQ_TEST_FRAME_SET_EX(ContextGlobalServerWithFrame, CONTEXT_GLOBAL, true) \
+ REQ_TEST_FRAME_SET_EX(ContextInMemoryServerWithFrame, CONTEXT_INMEMORY, \
+ true) \
+ REQ_TEST_FRAME_SET_EX(ContextOnDiskServerWithFrame, CONTEXT_ONDISK, true)
+
+REQ_TEST_FRAME_SET()
+
+// Cache and authentication tests can only be run with the server backend.
+#define REQ_TEST_CACHE_SET_EX(suffix, context_mode, test_frame_method) \
+ REQ_TEST(BrowserGETCacheWithControl##suffix, REQTEST_CACHE_WITH_CONTROL, \
+ context_mode, true, true, test_frame_method) \
+ REQ_TEST(BrowserGETCacheWithoutControl##suffix, \
+ REQTEST_CACHE_WITHOUT_CONTROL, context_mode, true, true, \
+ test_frame_method) \
+ REQ_TEST(BrowserGETCacheSkipFlag##suffix, REQTEST_CACHE_SKIP_FLAG, \
+ context_mode, true, true, test_frame_method) \
+ REQ_TEST(BrowserGETCacheSkipHeader##suffix, REQTEST_CACHE_SKIP_HEADER, \
+ context_mode, true, true, test_frame_method) \
+ REQ_TEST(BrowserGETCacheOnlyFailureFlag##suffix, \
+ REQTEST_CACHE_ONLY_FAILURE_FLAG, context_mode, true, true, \
+ test_frame_method) \
+ REQ_TEST(BrowserGETCacheOnlyFailureHeader##suffix, \
+ REQTEST_CACHE_ONLY_FAILURE_HEADER, context_mode, true, true, \
+ test_frame_method) \
+ REQ_TEST(BrowserGETCacheOnlySuccessFlag##suffix, \
+ REQTEST_CACHE_ONLY_SUCCESS_FLAG, context_mode, true, true, \
+ test_frame_method) \
+ REQ_TEST(BrowserGETCacheOnlySuccessHeader##suffix, \
+ REQTEST_CACHE_ONLY_SUCCESS_HEADER, context_mode, true, true, \
+ test_frame_method) \
+ REQ_TEST(BrowserGETCacheDisableFlag##suffix, REQTEST_CACHE_DISABLE_FLAG, \
+ context_mode, true, true, test_frame_method) \
+ REQ_TEST(BrowserGETCacheDisableHeader##suffix, REQTEST_CACHE_DISABLE_HEADER, \
+ context_mode, true, true, test_frame_method) \
+ REQ_TEST(RendererGETCacheWithControl##suffix, REQTEST_CACHE_WITH_CONTROL, \
+ context_mode, false, true, test_frame_method) \
+ REQ_TEST(RendererGETCacheWithoutControl##suffix, \
+ REQTEST_CACHE_WITHOUT_CONTROL, context_mode, false, true, \
+ test_frame_method) \
+ REQ_TEST(BrowserGETAuth##suffix, REQTEST_GET_AUTH, context_mode, true, true, \
+ test_frame_method) \
+ REQ_TEST(RendererGETCacheSkipFlag##suffix, REQTEST_CACHE_SKIP_FLAG, \
+ context_mode, false, true, test_frame_method) \
+ REQ_TEST(RendererGETCacheSkipHeader##suffix, REQTEST_CACHE_SKIP_HEADER, \
+ context_mode, false, true, test_frame_method) \
+ REQ_TEST(RendererGETCacheOnlyFailureFlag##suffix, \
+ REQTEST_CACHE_ONLY_FAILURE_FLAG, context_mode, false, true, \
+ test_frame_method) \
+ REQ_TEST(RendererGETCacheOnlyFailureHeader##suffix, \
+ REQTEST_CACHE_ONLY_FAILURE_HEADER, context_mode, false, true, \
+ test_frame_method) \
+ REQ_TEST(RendererGETCacheOnlySuccessFlag##suffix, \
+ REQTEST_CACHE_ONLY_SUCCESS_FLAG, context_mode, false, true, \
+ test_frame_method) \
+ REQ_TEST(RendererGETCacheOnlySuccessHeader##suffix, \
+ REQTEST_CACHE_ONLY_SUCCESS_HEADER, context_mode, false, true, \
+ test_frame_method) \
+ REQ_TEST(RendererGETCacheDisableFlag##suffix, REQTEST_CACHE_DISABLE_FLAG, \
+ context_mode, false, true, test_frame_method) \
+ REQ_TEST(RendererGETCacheDisableHeader##suffix, \
+ REQTEST_CACHE_DISABLE_HEADER, context_mode, false, true, \
+ test_frame_method)
+
+#define REQ_TEST_CACHE_SET(suffix, test_frame_method) \
+ REQ_TEST_CACHE_SET_EX(ContextGlobalServer##suffix, CONTEXT_GLOBAL, \
+ test_frame_method) \
+ REQ_TEST_CACHE_SET_EX(ContextInMemoryServer##suffix, CONTEXT_INMEMORY, \
+ test_frame_method) \
+ REQ_TEST_CACHE_SET_EX(ContextOnDiskServer##suffix, CONTEXT_ONDISK, \
+ test_frame_method)
+
+REQ_TEST_CACHE_SET(WithoutFrame, false)
+REQ_TEST_CACHE_SET(WithFrame, true)
+
+namespace {
+
+class InvalidURLTestClient : public CefURLRequestClient {
+ public:
+ InvalidURLTestClient() {
+ event_ = CefWaitableEvent::CreateWaitableEvent(true, false);
+ }
+
+ void RunTest() {
+ CefPostTask(TID_UI,
+ base::BindOnce(&InvalidURLTestClient::RunOnUIThread, this));
+
+ // Wait for the test to complete.
+ event_->Wait();
+ }
+
+ void OnRequestComplete(CefRefPtr<CefURLRequest> client) override {
+ EXPECT_EQ(UR_FAILED, client->GetRequestStatus());
+ EXPECT_EQ(ERR_UNKNOWN_URL_SCHEME, client->GetRequestError());
+
+ // Let the call stack unwind before signaling completion.
+ CefPostTask(TID_UI, base::BindOnce(
+ &InvalidURLTestClient::CompleteOnUIThread, this));
+ }
+
+ void OnUploadProgress(CefRefPtr<CefURLRequest> request,
+ int64 current,
+ int64 total) override {
+ EXPECT_TRUE(false); // Not reached.
+ }
+
+ void OnDownloadProgress(CefRefPtr<CefURLRequest> request,
+ int64 current,
+ int64 total) override {
+ EXPECT_TRUE(false); // Not reached.
+ }
+
+ void OnDownloadData(CefRefPtr<CefURLRequest> request,
+ const void* data,
+ size_t data_length) override {
+ EXPECT_TRUE(false); // Not reached.
+ }
+
+ bool GetAuthCredentials(bool isProxy,
+ const CefString& host,
+ int port,
+ const CefString& realm,
+ const CefString& scheme,
+ CefRefPtr<CefAuthCallback> callback) override {
+ EXPECT_TRUE(false); // Not reached.
+ return false;
+ }
+
+ private:
+ void RunOnUIThread() {
+ EXPECT_UI_THREAD();
+ CefRefPtr<CefRequest> request = CefRequest::Create();
+ request->SetMethod("GET");
+ request->SetURL("foo://invalidurl");
+
+ CefURLRequest::Create(request, this, nullptr);
+ }
+
+ void CompleteOnUIThread() {
+ EXPECT_UI_THREAD();
+ // Signal that the test is complete.
+ event_->Signal();
+ }
+
+ CefRefPtr<CefWaitableEvent> event_;
+
+ IMPLEMENT_REFCOUNTING(InvalidURLTestClient);
+};
+
+} // namespace
+
+// Verify that failed requests do not leak references.
+TEST(URLRequestTest, BrowserInvalidURL) {
+ CefRefPtr<InvalidURLTestClient> client = new InvalidURLTestClient();
+ client->RunTest();
+}
+
+// Entry point for creating URLRequest browser test objects.
+// Called from client_app_delegates.cc.
+void CreateURLRequestBrowserTests(
+ client::ClientAppBrowser::DelegateSet& delegates) {
+ delegates.insert(new URLRequestBrowserTest);
+}
diff --git a/tests/ceftests/v8_unittest.cc b/tests/ceftests/v8_unittest.cc
new file mode 100644
index 00000000..7d883c54
--- /dev/null
+++ b/tests/ceftests/v8_unittest.cc
@@ -0,0 +1,3371 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include <sstream>
+
+#include "include/base/cef_callback.h"
+#include "include/cef_task.h"
+#include "include/cef_v8.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "tests/ceftests/test_handler.h"
+#include "tests/ceftests/test_util.h"
+#include "tests/gtest/include/gtest/gtest.h"
+#include "tests/shared/browser/client_app_browser.h"
+#include "tests/shared/renderer/client_app_renderer.h"
+
+using client::ClientAppBrowser;
+using client::ClientAppRenderer;
+
+// How to add a new test:
+// 1. Add a new value to the V8TestMode enumeration.
+// 2. Add a method that implements the test in V8RendererTest.
+// 3. Add a case for the new enumeration value in V8RendererTest::RunTest.
+// 4. Add a line for the test in the "Define the tests" section at the bottom of
+// the file.
+
+namespace {
+
+// Unique values for V8 tests.
+const char kV8TestUrl[] = "http://tests/V8Test.Test";
+const char kV8BindingTestUrl[] = "http://tests/V8Test.BindingTest";
+const char kV8ContextParentTestUrl[] = "http://tests/V8Test.ContextParentTest";
+const char kV8ContextChildTestUrl[] = "http://tests/V8Test.ContextChildTest";
+const char kV8NavTestUrl[] = "http://tests/V8Test.NavTest";
+const char kV8ContextEvalCspBypassUnsafeEval[] =
+ "http://tests/V8Test.ContextEvalCspBypassUnsafeEval";
+const char kV8ContextEvalCspBypassSandbox[] =
+ "http://tests/V8Test.ContextEvalCspBypassSandbox";
+const char kV8OnUncaughtExceptionTestUrl[] =
+ "http://tests/V8Test.OnUncaughtException";
+const char kV8HandlerCallOnReleasedContextUrl[] =
+ "http://tests/V8Test.HandlerCallOnReleasedContext/main.html";
+const char kV8HandlerCallOnReleasedContextChildUrl[] =
+ "http://tests/V8Test.HandlerCallOnReleasedContext/child.html";
+const char kV8TestMsg[] = "V8Test.Test";
+const char kV8TestCmdKey[] = "v8-test";
+const char kV8RunTestMsg[] = "V8Test.RunTest";
+
+enum V8TestMode {
+ V8TEST_NONE = 0,
+ V8TEST_NULL_CREATE,
+ V8TEST_BOOL_CREATE,
+ V8TEST_INT_CREATE,
+ V8TEST_UINT_CREATE,
+ V8TEST_DOUBLE_CREATE,
+ V8TEST_DATE_CREATE,
+ V8TEST_STRING_CREATE,
+ V8TEST_EMPTY_STRING_CREATE,
+ V8TEST_ARRAY_CREATE,
+ V8TEST_ARRAY_VALUE,
+ V8TEST_ARRAY_BUFFER,
+ V8TEST_ARRAY_BUFFER_VALUE,
+ V8TEST_OBJECT_CREATE,
+ V8TEST_OBJECT_USERDATA,
+ V8TEST_OBJECT_ACCESSOR,
+ V8TEST_OBJECT_ACCESSOR_EXCEPTION,
+ V8TEST_OBJECT_ACCESSOR_FAIL,
+ V8TEST_OBJECT_ACCESSOR_READONLY,
+ V8TEST_OBJECT_INTERCEPTOR,
+ V8TEST_OBJECT_INTERCEPTOR_FAIL,
+ V8TEST_OBJECT_INTERCEPTOR_EXCEPTION,
+ V8TEST_OBJECT_INTERCEPTOR_AND_ACCESSOR,
+ V8TEST_OBJECT_VALUE,
+ V8TEST_OBJECT_VALUE_READONLY,
+ V8TEST_OBJECT_VALUE_ENUM,
+ V8TEST_OBJECT_VALUE_DONTENUM,
+ V8TEST_OBJECT_VALUE_DELETE,
+ V8TEST_OBJECT_VALUE_DONTDELETE,
+ V8TEST_OBJECT_VALUE_EMPTYKEY,
+ V8TEST_FUNCTION_CREATE,
+ V8TEST_FUNCTION_HANDLER,
+ V8TEST_FUNCTION_HANDLER_EXCEPTION,
+ V8TEST_FUNCTION_HANDLER_FAIL,
+ V8TEST_FUNCTION_HANDLER_NO_OBJECT,
+ V8TEST_FUNCTION_HANDLER_WITH_CONTEXT,
+ V8TEST_FUNCTION_HANDLER_EMPTY_STRING,
+ V8TEST_PROMISE_CREATE,
+ V8TEST_PROMISE_RESOLVE,
+ V8TEST_PROMISE_RESOLVE_NO_ARGUMENT,
+ V8TEST_PROMISE_RESOLVE_HANDLER,
+ V8TEST_PROMISE_REJECT,
+ V8TEST_PROMISE_REJECT_HANDLER,
+ V8TEST_CONTEXT_EVAL,
+ V8TEST_CONTEXT_EVAL_EXCEPTION,
+ V8TEST_CONTEXT_EVAL_CSP_BYPASS_UNSAFE_EVAL,
+ V8TEST_CONTEXT_EVAL_CSP_BYPASS_SANDBOX,
+ V8TEST_CONTEXT_ENTERED,
+ V8TEST_BINDING,
+ V8TEST_STACK_TRACE,
+ V8TEST_ON_UNCAUGHT_EXCEPTION,
+ V8TEST_ON_UNCAUGHT_EXCEPTION_DEV_TOOLS,
+ V8TEST_EXTENSION,
+ V8TEST_HANDLER_CALL_ON_RELEASED_CONTEXT,
+};
+
+// Renderer side.
+class V8RendererTest : public ClientAppRenderer::Delegate,
+ public CefLoadHandler {
+ public:
+ V8RendererTest() : test_mode_(V8TEST_NONE) {}
+
+ // Run a test when the process message is received from the browser.
+ void RunTest() {
+ switch (test_mode_) {
+ case V8TEST_NULL_CREATE:
+ RunNullCreateTest();
+ break;
+ case V8TEST_BOOL_CREATE:
+ RunBoolCreateTest();
+ break;
+ case V8TEST_INT_CREATE:
+ RunIntCreateTest();
+ break;
+ case V8TEST_UINT_CREATE:
+ RunUIntCreateTest();
+ break;
+ case V8TEST_DOUBLE_CREATE:
+ RunDoubleCreateTest();
+ break;
+ case V8TEST_DATE_CREATE:
+ RunDateCreateTest();
+ break;
+ case V8TEST_STRING_CREATE:
+ RunStringCreateTest();
+ break;
+ case V8TEST_EMPTY_STRING_CREATE:
+ RunEmptyStringCreateTest();
+ break;
+ case V8TEST_ARRAY_CREATE:
+ RunArrayCreateTest();
+ break;
+ case V8TEST_ARRAY_VALUE:
+ RunArrayValueTest();
+ break;
+ case V8TEST_ARRAY_BUFFER:
+ RunArrayBufferTest();
+ break;
+ case V8TEST_ARRAY_BUFFER_VALUE:
+ RunArrayBufferValueTest();
+ break;
+ case V8TEST_OBJECT_CREATE:
+ RunObjectCreateTest();
+ break;
+ case V8TEST_OBJECT_USERDATA:
+ RunObjectUserDataTest();
+ break;
+ case V8TEST_OBJECT_ACCESSOR:
+ RunObjectAccessorTest();
+ break;
+ case V8TEST_OBJECT_ACCESSOR_EXCEPTION:
+ RunObjectAccessorExceptionTest();
+ break;
+ case V8TEST_OBJECT_ACCESSOR_FAIL:
+ RunObjectAccessorFailTest();
+ break;
+ case V8TEST_OBJECT_ACCESSOR_READONLY:
+ RunObjectAccessorReadOnlyTest();
+ break;
+ case V8TEST_OBJECT_INTERCEPTOR:
+ RunObjectInterceptorTest();
+ break;
+ case V8TEST_OBJECT_INTERCEPTOR_FAIL:
+ RunObjectInterceptorFailTest();
+ break;
+ case V8TEST_OBJECT_INTERCEPTOR_EXCEPTION:
+ RunObjectInterceptorExceptionTest();
+ break;
+ case V8TEST_OBJECT_INTERCEPTOR_AND_ACCESSOR:
+ RunObjectInterceptorAndAccessorTest();
+ break;
+ case V8TEST_OBJECT_VALUE:
+ RunObjectValueTest();
+ break;
+ case V8TEST_OBJECT_VALUE_READONLY:
+ RunObjectValueReadOnlyTest();
+ break;
+ case V8TEST_OBJECT_VALUE_ENUM:
+ RunObjectValueEnumTest();
+ break;
+ case V8TEST_OBJECT_VALUE_DONTENUM:
+ RunObjectValueDontEnumTest();
+ break;
+ case V8TEST_OBJECT_VALUE_DELETE:
+ RunObjectValueDeleteTest();
+ break;
+ case V8TEST_OBJECT_VALUE_DONTDELETE:
+ RunObjectValueDontDeleteTest();
+ break;
+ case V8TEST_OBJECT_VALUE_EMPTYKEY:
+ RunObjectValueEmptyKeyTest();
+ break;
+ case V8TEST_FUNCTION_CREATE:
+ RunFunctionCreateTest();
+ break;
+ case V8TEST_FUNCTION_HANDLER:
+ RunFunctionHandlerTest();
+ break;
+ case V8TEST_FUNCTION_HANDLER_EXCEPTION:
+ RunFunctionHandlerExceptionTest();
+ break;
+ case V8TEST_FUNCTION_HANDLER_FAIL:
+ RunFunctionHandlerFailTest();
+ break;
+ case V8TEST_FUNCTION_HANDLER_NO_OBJECT:
+ RunFunctionHandlerNoObjectTest();
+ break;
+ case V8TEST_FUNCTION_HANDLER_WITH_CONTEXT:
+ RunFunctionHandlerWithContextTest();
+ break;
+ case V8TEST_FUNCTION_HANDLER_EMPTY_STRING:
+ RunFunctionHandlerEmptyStringTest();
+ break;
+ case V8TEST_PROMISE_CREATE:
+ RunPromiseCreateTest();
+ break;
+ case V8TEST_PROMISE_RESOLVE:
+ RunPromiseResolveTest();
+ break;
+ case V8TEST_PROMISE_RESOLVE_NO_ARGUMENT:
+ RunPromiseResolveNoArgumentTest();
+ break;
+ case V8TEST_PROMISE_RESOLVE_HANDLER:
+ RunPromiseResolveHandlerTest();
+ break;
+ case V8TEST_PROMISE_REJECT:
+ RunPromiseRejectTest();
+ break;
+ case V8TEST_PROMISE_REJECT_HANDLER:
+ RunPromiseRejectHandlerTest();
+ break;
+ case V8TEST_CONTEXT_EVAL:
+ RunContextEvalTest();
+ break;
+ case V8TEST_CONTEXT_EVAL_EXCEPTION:
+ RunContextEvalExceptionTest();
+ break;
+ case V8TEST_CONTEXT_EVAL_CSP_BYPASS_UNSAFE_EVAL:
+ RunContextEvalCspBypassUnsafeEval();
+ break;
+ case V8TEST_CONTEXT_EVAL_CSP_BYPASS_SANDBOX:
+ RunContextEvalCspBypassSandbox();
+ break;
+ case V8TEST_CONTEXT_ENTERED:
+ RunContextEnteredTest();
+ break;
+ case V8TEST_BINDING:
+ RunBindingTest();
+ break;
+ case V8TEST_STACK_TRACE:
+ RunStackTraceTest();
+ break;
+ case V8TEST_ON_UNCAUGHT_EXCEPTION:
+ RunOnUncaughtExceptionTest();
+ break;
+ case V8TEST_HANDLER_CALL_ON_RELEASED_CONTEXT:
+ break;
+ default:
+ // Was a startup test.
+ EXPECT_TRUE(startup_test_success_);
+ DestroyTest();
+ break;
+ }
+ }
+
+ // Run a test on render process startup.
+ void RunStartupTest() {
+ switch (test_mode_) {
+ case V8TEST_EXTENSION:
+ RunExtensionTest();
+ break;
+ default:
+ break;
+ }
+ }
+
+ void RunNullCreateTest() {
+ CefRefPtr<CefV8Value> value = CefV8Value::CreateNull();
+ EXPECT_TRUE(value.get());
+ EXPECT_TRUE(value->IsNull());
+
+ EXPECT_FALSE(value->IsUndefined());
+ EXPECT_FALSE(value->IsArray());
+ EXPECT_FALSE(value->IsBool());
+ EXPECT_FALSE(value->IsDate());
+ EXPECT_FALSE(value->IsDouble());
+ EXPECT_FALSE(value->IsFunction());
+ EXPECT_FALSE(value->IsInt());
+ EXPECT_FALSE(value->IsUInt());
+ EXPECT_FALSE(value->IsObject());
+ EXPECT_FALSE(value->IsPromise());
+ EXPECT_FALSE(value->IsString());
+
+ DestroyTest();
+ }
+
+ void RunBoolCreateTest() {
+ CefRefPtr<CefV8Value> value = CefV8Value::CreateBool(true);
+ EXPECT_TRUE(value.get());
+ EXPECT_TRUE(value->IsBool());
+ EXPECT_EQ(true, value->GetBoolValue());
+
+ EXPECT_FALSE(value->IsUndefined());
+ EXPECT_FALSE(value->IsArray());
+ EXPECT_FALSE(value->IsDate());
+ EXPECT_FALSE(value->IsDouble());
+ EXPECT_FALSE(value->IsFunction());
+ EXPECT_FALSE(value->IsInt());
+ EXPECT_FALSE(value->IsUInt());
+ EXPECT_FALSE(value->IsNull());
+ EXPECT_FALSE(value->IsObject());
+ EXPECT_FALSE(value->IsPromise());
+ EXPECT_FALSE(value->IsString());
+
+ DestroyTest();
+ }
+
+ void RunIntCreateTest() {
+ CefRefPtr<CefV8Value> value = CefV8Value::CreateInt(12);
+ EXPECT_TRUE(value.get());
+ EXPECT_TRUE(value->IsInt());
+ EXPECT_TRUE(value->IsUInt());
+ EXPECT_TRUE(value->IsDouble());
+ EXPECT_EQ(12, value->GetIntValue());
+ EXPECT_EQ((uint32)12, value->GetUIntValue());
+ EXPECT_EQ(12, value->GetDoubleValue());
+
+ EXPECT_FALSE(value->IsUndefined());
+ EXPECT_FALSE(value->IsArray());
+ EXPECT_FALSE(value->IsBool());
+ EXPECT_FALSE(value->IsDate());
+ EXPECT_FALSE(value->IsFunction());
+ EXPECT_FALSE(value->IsNull());
+ EXPECT_FALSE(value->IsObject());
+ EXPECT_FALSE(value->IsPromise());
+ EXPECT_FALSE(value->IsString());
+
+ DestroyTest();
+ }
+
+ void RunUIntCreateTest() {
+ CefRefPtr<CefV8Value> value = CefV8Value::CreateUInt(12);
+ EXPECT_TRUE(value.get());
+ EXPECT_TRUE(value->IsInt());
+ EXPECT_TRUE(value->IsUInt());
+ EXPECT_TRUE(value->IsDouble());
+ EXPECT_EQ(12, value->GetIntValue());
+ EXPECT_EQ((uint32)12, value->GetUIntValue());
+ EXPECT_EQ(12, value->GetDoubleValue());
+
+ EXPECT_FALSE(value->IsUndefined());
+ EXPECT_FALSE(value->IsArray());
+ EXPECT_FALSE(value->IsBool());
+ EXPECT_FALSE(value->IsDate());
+ EXPECT_FALSE(value->IsFunction());
+ EXPECT_FALSE(value->IsNull());
+ EXPECT_FALSE(value->IsObject());
+ EXPECT_FALSE(value->IsPromise());
+ EXPECT_FALSE(value->IsString());
+
+ DestroyTest();
+ }
+
+ void RunDoubleCreateTest() {
+ CefRefPtr<CefV8Value> value = CefV8Value::CreateDouble(12.1223);
+ EXPECT_TRUE(value.get());
+ EXPECT_TRUE(value->IsDouble());
+ EXPECT_EQ(12.1223, value->GetDoubleValue());
+
+ EXPECT_FALSE(value->IsUndefined());
+ EXPECT_FALSE(value->IsArray());
+ EXPECT_FALSE(value->IsBool());
+ EXPECT_FALSE(value->IsDate());
+ EXPECT_FALSE(value->IsFunction());
+ EXPECT_FALSE(value->IsInt());
+ EXPECT_FALSE(value->IsUInt());
+ EXPECT_FALSE(value->IsNull());
+ EXPECT_FALSE(value->IsObject());
+ EXPECT_FALSE(value->IsPromise());
+ EXPECT_FALSE(value->IsString());
+
+ DestroyTest();
+ }
+
+ void RunDateCreateTest() {
+ CefRefPtr<CefV8Context> context = GetContext();
+
+ CefTime date;
+ date.year = 2200;
+ date.month = 4;
+#if !defined(OS_MAC)
+ date.day_of_week = 5;
+#endif
+ date.day_of_month = 11;
+ date.hour = 20;
+ date.minute = 15;
+ date.second = 42;
+
+ // Enter the V8 context.
+ EXPECT_TRUE(context->Enter());
+
+ CefRefPtr<CefV8Value> value = CefV8Value::CreateDate(CefBaseTimeFrom(date));
+ EXPECT_TRUE(value.get());
+ EXPECT_TRUE(value->IsDate());
+ EXPECT_EQ(date.GetTimeT(), CefTimeFrom(value->GetDateValue()).GetTimeT());
+
+ // Exit the V8 context.
+ EXPECT_TRUE(context->Exit());
+
+ EXPECT_FALSE(value->IsUndefined());
+ EXPECT_FALSE(value->IsArray());
+ EXPECT_FALSE(value->IsBool());
+ EXPECT_FALSE(value->IsDouble());
+ EXPECT_FALSE(value->IsFunction());
+ EXPECT_FALSE(value->IsInt());
+ EXPECT_FALSE(value->IsUInt());
+ EXPECT_FALSE(value->IsObject());
+ EXPECT_FALSE(value->IsNull());
+ EXPECT_FALSE(value->IsPromise());
+ EXPECT_FALSE(value->IsString());
+
+ DestroyTest();
+ }
+
+ void RunStringCreateTest() {
+ CefRefPtr<CefV8Value> value = CefV8Value::CreateString("My string");
+ EXPECT_TRUE(value.get());
+ EXPECT_TRUE(value->IsString());
+ EXPECT_STREQ("My string", value->GetStringValue().ToString().c_str());
+
+ EXPECT_FALSE(value->IsUndefined());
+ EXPECT_FALSE(value->IsArray());
+ EXPECT_FALSE(value->IsBool());
+ EXPECT_FALSE(value->IsDate());
+ EXPECT_FALSE(value->IsDouble());
+ EXPECT_FALSE(value->IsFunction());
+ EXPECT_FALSE(value->IsInt());
+ EXPECT_FALSE(value->IsUInt());
+ EXPECT_FALSE(value->IsNull());
+ EXPECT_FALSE(value->IsPromise());
+ EXPECT_FALSE(value->IsObject());
+
+ DestroyTest();
+ }
+
+ void RunEmptyStringCreateTest() {
+ CefRefPtr<CefV8Value> value = CefV8Value::CreateString(CefString());
+ EXPECT_TRUE(value.get());
+ EXPECT_TRUE(value->IsString());
+ EXPECT_STREQ("", value->GetStringValue().ToString().c_str());
+
+ EXPECT_FALSE(value->IsUndefined());
+ EXPECT_FALSE(value->IsArray());
+ EXPECT_FALSE(value->IsBool());
+ EXPECT_FALSE(value->IsDate());
+ EXPECT_FALSE(value->IsDouble());
+ EXPECT_FALSE(value->IsFunction());
+ EXPECT_FALSE(value->IsInt());
+ EXPECT_FALSE(value->IsUInt());
+ EXPECT_FALSE(value->IsNull());
+ EXPECT_FALSE(value->IsObject());
+ EXPECT_FALSE(value->IsPromise());
+
+ DestroyTest();
+ }
+
+ void RunArrayCreateTest() {
+ CefRefPtr<CefV8Context> context = GetContext();
+
+ // Enter the V8 context.
+ EXPECT_TRUE(context->Enter());
+
+ CefRefPtr<CefV8Value> value = CefV8Value::CreateArray(2);
+ EXPECT_TRUE(value.get());
+ EXPECT_TRUE(value->IsArray());
+ EXPECT_TRUE(value->IsObject());
+ EXPECT_EQ(2, value->GetArrayLength());
+ EXPECT_FALSE(value->HasValue(0));
+ EXPECT_FALSE(value->HasValue(1));
+
+ // Exit the V8 context.
+ EXPECT_TRUE(context->Exit());
+
+ EXPECT_FALSE(value->IsUndefined());
+ EXPECT_FALSE(value->IsBool());
+ EXPECT_FALSE(value->IsDate());
+ EXPECT_FALSE(value->IsDouble());
+ EXPECT_FALSE(value->IsFunction());
+ EXPECT_FALSE(value->IsInt());
+ EXPECT_FALSE(value->IsUInt());
+ EXPECT_FALSE(value->IsNull());
+ EXPECT_FALSE(value->IsPromise());
+ EXPECT_FALSE(value->IsString());
+
+ DestroyTest();
+ }
+
+ void RunArrayValueTest() {
+ CefRefPtr<CefV8Context> context = GetContext();
+
+ // Enter the V8 context.
+ EXPECT_TRUE(context->Enter());
+
+ CefRefPtr<CefV8Value> value = CefV8Value::CreateArray(0);
+ EXPECT_TRUE(value.get());
+ EXPECT_TRUE(value->IsArray());
+ EXPECT_EQ(0, value->GetArrayLength());
+
+ // Test addng values.
+ EXPECT_FALSE(value->HasValue(0));
+ EXPECT_FALSE(value->HasValue(1));
+
+ EXPECT_TRUE(value->SetValue(0, CefV8Value::CreateInt(10)));
+ EXPECT_FALSE(value->HasException());
+ EXPECT_TRUE(value->HasValue(0));
+ EXPECT_FALSE(value->HasValue(1));
+
+ EXPECT_TRUE(value->GetValue(0)->IsInt());
+ EXPECT_EQ(10, value->GetValue(0)->GetIntValue());
+ EXPECT_FALSE(value->HasException());
+ EXPECT_EQ(1, value->GetArrayLength());
+
+ EXPECT_TRUE(value->SetValue(1, CefV8Value::CreateInt(43)));
+ EXPECT_FALSE(value->HasException());
+ EXPECT_TRUE(value->HasValue(0));
+ EXPECT_TRUE(value->HasValue(1));
+
+ EXPECT_TRUE(value->GetValue(1)->IsInt());
+ EXPECT_EQ(43, value->GetValue(1)->GetIntValue());
+ EXPECT_FALSE(value->HasException());
+ EXPECT_EQ(2, value->GetArrayLength());
+
+ EXPECT_TRUE(value->DeleteValue(0));
+ EXPECT_FALSE(value->HasValue(0));
+ EXPECT_TRUE(value->HasValue(1));
+ EXPECT_EQ(2, value->GetArrayLength());
+
+ EXPECT_TRUE(value->DeleteValue(1));
+ EXPECT_FALSE(value->HasValue(0));
+ EXPECT_FALSE(value->HasValue(1));
+ EXPECT_EQ(2, value->GetArrayLength());
+
+ // Exit the V8 context.
+ EXPECT_TRUE(context->Exit());
+
+ DestroyTest();
+ }
+
+ void RunArrayBufferTest() {
+ class TestArrayBufferReleaseCallback
+ : public CefV8ArrayBufferReleaseCallback {
+ public:
+ TestArrayBufferReleaseCallback(bool* destructorCalled,
+ bool* releaseBufferCalled)
+ : destructorCalled_(destructorCalled),
+ releaseBufferCalled_(releaseBufferCalled) {}
+
+ ~TestArrayBufferReleaseCallback() { *destructorCalled_ = true; }
+
+ void ReleaseBuffer(void* buffer) override {
+ *releaseBufferCalled_ = true;
+ }
+
+ IMPLEMENT_REFCOUNTING(TestArrayBufferReleaseCallback);
+
+ private:
+ bool* destructorCalled_;
+ bool* releaseBufferCalled_;
+ };
+
+ CefRefPtr<CefV8Context> context = GetContext();
+
+ bool destructorCalled = false;
+ bool releaseBufferCalled = false;
+ // Enter the V8 context.
+ EXPECT_TRUE(context->Enter());
+ {
+ int static_data[16];
+ CefRefPtr<TestArrayBufferReleaseCallback> release_callback =
+ new TestArrayBufferReleaseCallback(&destructorCalled,
+ &releaseBufferCalled);
+ CefRefPtr<CefV8Value> value = CefV8Value::CreateArrayBuffer(
+ static_data, sizeof(static_data), release_callback);
+ EXPECT_TRUE(value.get());
+ EXPECT_TRUE(value->IsArrayBuffer());
+ EXPECT_TRUE(value->IsObject());
+ EXPECT_FALSE(value->HasValue(0));
+ EXPECT_TRUE(value->GetArrayBufferReleaseCallback().get() != nullptr);
+ EXPECT_TRUE(((TestArrayBufferReleaseCallback*)value
+ ->GetArrayBufferReleaseCallback()
+ .get()) == release_callback);
+
+ // |Value| buffer is explicitly freed by NeuterArrayBuffer().
+ EXPECT_FALSE(destructorCalled);
+ EXPECT_FALSE(releaseBufferCalled);
+ EXPECT_TRUE(value->NeuterArrayBuffer());
+ EXPECT_TRUE(releaseBufferCalled);
+ }
+ // Exit the V8 context.
+ EXPECT_TRUE(destructorCalled);
+ EXPECT_TRUE(context->Exit());
+ DestroyTest();
+ }
+
+ void RunArrayBufferValueTest() {
+ class TestArrayBufferReleaseCallback
+ : public CefV8ArrayBufferReleaseCallback {
+ public:
+ TestArrayBufferReleaseCallback() {}
+
+ ~TestArrayBufferReleaseCallback() {}
+
+ void ReleaseBuffer(void* buffer) override {}
+
+ IMPLEMENT_REFCOUNTING(TestArrayBufferReleaseCallback);
+ };
+
+ CefRefPtr<CefV8Context> context = GetContext();
+
+ // Enter the V8 context.
+ CefRefPtr<CefV8Value> value;
+
+ CefRefPtr<TestArrayBufferReleaseCallback> owner =
+ new TestArrayBufferReleaseCallback();
+ EXPECT_TRUE(context->Enter());
+ int static_data[16];
+ static_data[0] = 3;
+ value =
+ CefV8Value::CreateArrayBuffer(static_data, sizeof(static_data), owner);
+
+ CefRefPtr<CefV8Value> object = context->GetGlobal();
+ EXPECT_TRUE(object.get());
+ object->SetValue("arr", value, V8_PROPERTY_ATTRIBUTE_NONE);
+ std::string test =
+ "let data = new Int32Array(window.arr); data[0] += data.length";
+ CefRefPtr<CefV8Value> retval;
+ CefRefPtr<CefV8Exception> exception;
+ EXPECT_TRUE(context->Eval(test, CefString(), 0, retval, exception));
+ if (exception.get()) {
+ ADD_FAILURE() << exception->GetMessage().c_str();
+ }
+
+ EXPECT_TRUE(static_data[0] == 19);
+ EXPECT_TRUE(value->GetArrayBufferReleaseCallback().get() != nullptr);
+ EXPECT_TRUE(value->NeuterArrayBuffer());
+
+ // Exit the V8 context.
+ EXPECT_TRUE(context->Exit());
+ DestroyTest();
+ }
+
+ void RunObjectCreateTest() {
+ CefRefPtr<CefV8Context> context = GetContext();
+
+ // Enter the V8 context.
+ EXPECT_TRUE(context->Enter());
+
+ CefRefPtr<CefV8Value> value = CefV8Value::CreateObject(nullptr, nullptr);
+
+ EXPECT_TRUE(value.get());
+ EXPECT_TRUE(value->IsObject());
+ EXPECT_FALSE(value->GetUserData().get());
+
+ EXPECT_FALSE(value->IsUndefined());
+ EXPECT_FALSE(value->IsArray());
+ EXPECT_FALSE(value->IsBool());
+ EXPECT_FALSE(value->IsDate());
+ EXPECT_FALSE(value->IsDouble());
+ EXPECT_FALSE(value->IsFunction());
+ EXPECT_FALSE(value->IsInt());
+ EXPECT_FALSE(value->IsUInt());
+ EXPECT_FALSE(value->IsNull());
+ EXPECT_FALSE(value->IsPromise());
+ EXPECT_FALSE(value->IsString());
+
+ // Exit the V8 context.
+ EXPECT_TRUE(context->Exit());
+
+ DestroyTest();
+ }
+
+ void RunObjectUserDataTest() {
+ CefRefPtr<CefV8Context> context = GetContext();
+
+ class UserData : public CefBaseRefCounted {
+ public:
+ explicit UserData(int value) : value_(value) {}
+ int value_;
+ IMPLEMENT_REFCOUNTING(UserData);
+ };
+
+ // Enter the V8 context.
+ EXPECT_TRUE(context->Enter());
+
+ CefRefPtr<CefV8Value> value = CefV8Value::CreateObject(nullptr, nullptr);
+ EXPECT_TRUE(value.get());
+
+ EXPECT_TRUE(value->SetUserData(new UserData(10)));
+
+ CefRefPtr<CefBaseRefCounted> user_data = value->GetUserData();
+ EXPECT_TRUE(user_data.get());
+ UserData* user_data_impl = static_cast<UserData*>(user_data.get());
+ EXPECT_EQ(10, user_data_impl->value_);
+
+ // Exit the V8 context.
+ EXPECT_TRUE(context->Exit());
+
+ DestroyTest();
+ }
+
+ void RunObjectAccessorTest() {
+ CefRefPtr<CefV8Context> context = GetContext();
+
+ static const char* kName = "val";
+ static const int kValue = 20;
+
+ class Accessor : public CefV8Accessor {
+ public:
+ Accessor() : value_(0) {}
+ bool Get(const CefString& name,
+ const CefRefPtr<CefV8Value> object,
+ CefRefPtr<CefV8Value>& retval,
+ CefString& exception) override {
+ EXPECT_STREQ(kName, name.ToString().c_str());
+
+ EXPECT_TRUE(object.get());
+ EXPECT_TRUE(object->IsSame(object_));
+
+ EXPECT_FALSE(retval.get());
+ EXPECT_TRUE(exception.empty());
+
+ got_get_.yes();
+ retval = CefV8Value::CreateInt(value_);
+ EXPECT_EQ(kValue, retval->GetIntValue());
+ return true;
+ }
+
+ bool Set(const CefString& name,
+ const CefRefPtr<CefV8Value> object,
+ const CefRefPtr<CefV8Value> value,
+ CefString& exception) override {
+ EXPECT_STREQ(kName, name.ToString().c_str());
+
+ EXPECT_TRUE(object.get());
+ EXPECT_TRUE(object->IsSame(object_));
+
+ EXPECT_TRUE(value.get());
+ EXPECT_TRUE(exception.empty());
+
+ got_set_.yes();
+ value_ = value->GetIntValue();
+ EXPECT_EQ(kValue, value_);
+ return true;
+ }
+
+ CefRefPtr<CefV8Value> object_;
+ int value_;
+ TrackCallback got_get_;
+ TrackCallback got_set_;
+
+ IMPLEMENT_REFCOUNTING(Accessor);
+ };
+
+ // Enter the V8 context.
+ EXPECT_TRUE(context->Enter());
+
+ Accessor* accessor = new Accessor;
+ CefRefPtr<CefV8Accessor> accessorPtr(accessor);
+
+ CefRefPtr<CefV8Value> object = CefV8Value::CreateObject(accessor, nullptr);
+ EXPECT_TRUE(object.get());
+ accessor->object_ = object;
+
+ EXPECT_FALSE(object->HasValue(kName));
+
+ EXPECT_TRUE(object->SetValue(kName, V8_ACCESS_CONTROL_DEFAULT,
+ V8_PROPERTY_ATTRIBUTE_NONE));
+ EXPECT_FALSE(object->HasException());
+ EXPECT_TRUE(object->HasValue(kName));
+
+ EXPECT_TRUE(object->SetValue(kName, CefV8Value::CreateInt(kValue),
+ V8_PROPERTY_ATTRIBUTE_NONE));
+ EXPECT_FALSE(object->HasException());
+ EXPECT_TRUE(accessor->got_set_);
+ EXPECT_EQ(kValue, accessor->value_);
+
+ CefRefPtr<CefV8Value> val = object->GetValue(kName);
+ EXPECT_FALSE(object->HasException());
+ EXPECT_TRUE(val.get());
+ EXPECT_TRUE(accessor->got_get_);
+ EXPECT_TRUE(val->IsInt());
+ EXPECT_EQ(kValue, val->GetIntValue());
+
+ accessor->object_ = nullptr;
+
+ // Exit the V8 context.
+ EXPECT_TRUE(context->Exit());
+
+ DestroyTest();
+ }
+
+ void RunObjectAccessorExceptionTest() {
+ CefRefPtr<CefV8Context> context = GetContext();
+
+ static const char* kName = "val";
+ static const char* kGetException = "My get exception";
+ static const char* kSetException = "My set exception";
+ static const char* kGetExceptionMsg = "Uncaught Error: My get exception";
+ static const char* kSetExceptionMsg = "Uncaught Error: My set exception";
+
+ class Accessor : public CefV8Accessor {
+ public:
+ Accessor() {}
+ bool Get(const CefString& name,
+ const CefRefPtr<CefV8Value> object,
+ CefRefPtr<CefV8Value>& retval,
+ CefString& exception) override {
+ got_get_.yes();
+ exception = kGetException;
+ return true;
+ }
+
+ bool Set(const CefString& name,
+ const CefRefPtr<CefV8Value> object,
+ const CefRefPtr<CefV8Value> value,
+ CefString& exception) override {
+ got_set_.yes();
+ exception = kSetException;
+ return true;
+ }
+
+ TrackCallback got_get_;
+ TrackCallback got_set_;
+
+ IMPLEMENT_REFCOUNTING(Accessor);
+ };
+
+ // Enter the V8 context.
+ EXPECT_TRUE(context->Enter());
+
+ CefRefPtr<CefV8Exception> exception;
+ Accessor* accessor = new Accessor;
+ CefRefPtr<CefV8Accessor> accessorPtr(accessor);
+
+ CefRefPtr<CefV8Value> object = CefV8Value::CreateObject(accessor, nullptr);
+ EXPECT_TRUE(object.get());
+
+ EXPECT_FALSE(object->HasValue(kName));
+
+ EXPECT_TRUE(object->SetValue(kName, V8_ACCESS_CONTROL_DEFAULT,
+ V8_PROPERTY_ATTRIBUTE_NONE));
+ EXPECT_FALSE(object->HasException());
+ EXPECT_TRUE(object->HasValue(kName));
+
+ EXPECT_FALSE(object->SetValue(kName, CefV8Value::CreateInt(1),
+ V8_PROPERTY_ATTRIBUTE_NONE));
+ EXPECT_TRUE(object->HasException());
+ EXPECT_TRUE(accessor->got_set_);
+ exception = object->GetException();
+ EXPECT_TRUE(exception.get());
+ EXPECT_STREQ(kSetExceptionMsg, exception->GetMessage().ToString().c_str());
+
+ EXPECT_TRUE(object->ClearException());
+ EXPECT_FALSE(object->HasException());
+
+ CefRefPtr<CefV8Value> val = object->GetValue(kName);
+ EXPECT_FALSE(val.get());
+ EXPECT_TRUE(object->HasException());
+ EXPECT_TRUE(accessor->got_get_);
+ exception = object->GetException();
+ EXPECT_TRUE(exception.get());
+ EXPECT_STREQ(kGetExceptionMsg, exception->GetMessage().ToString().c_str());
+
+ // Exit the V8 context.
+ EXPECT_TRUE(context->Exit());
+
+ DestroyTest();
+ }
+
+ void RunObjectAccessorFailTest() {
+ CefRefPtr<CefV8Context> context = GetContext();
+
+ static const char* kName = "val";
+
+ class Accessor : public CefV8Accessor {
+ public:
+ Accessor() {}
+ bool Get(const CefString& name,
+ const CefRefPtr<CefV8Value> object,
+ CefRefPtr<CefV8Value>& retval,
+ CefString& exception) override {
+ got_get_.yes();
+ return false;
+ }
+
+ bool Set(const CefString& name,
+ const CefRefPtr<CefV8Value> object,
+ const CefRefPtr<CefV8Value> value,
+ CefString& exception) override {
+ got_set_.yes();
+ return false;
+ }
+
+ TrackCallback got_get_;
+ TrackCallback got_set_;
+
+ IMPLEMENT_REFCOUNTING(Accessor);
+ };
+
+ // Enter the V8 context.
+ EXPECT_TRUE(context->Enter());
+
+ CefRefPtr<CefV8Exception> exception;
+ Accessor* accessor = new Accessor;
+ CefRefPtr<CefV8Accessor> accessorPtr(accessor);
+
+ CefRefPtr<CefV8Value> object = CefV8Value::CreateObject(accessor, nullptr);
+ EXPECT_TRUE(object.get());
+
+ EXPECT_FALSE(object->HasValue(kName));
+
+ EXPECT_TRUE(object->SetValue(kName, V8_ACCESS_CONTROL_DEFAULT,
+ V8_PROPERTY_ATTRIBUTE_NONE));
+ EXPECT_FALSE(object->HasException());
+ EXPECT_TRUE(object->HasValue(kName));
+
+ EXPECT_TRUE(object->SetValue(kName, CefV8Value::CreateInt(1),
+ V8_PROPERTY_ATTRIBUTE_NONE));
+ EXPECT_FALSE(object->HasException());
+ EXPECT_TRUE(accessor->got_set_);
+
+ CefRefPtr<CefV8Value> val = object->GetValue(kName);
+ EXPECT_TRUE(val.get());
+ EXPECT_FALSE(object->HasException());
+ EXPECT_TRUE(accessor->got_get_);
+ EXPECT_TRUE(val->IsUndefined());
+
+ // Exit the V8 context.
+ EXPECT_TRUE(context->Exit());
+
+ DestroyTest();
+ }
+
+ void RunObjectAccessorReadOnlyTest() {
+ CefRefPtr<CefV8Context> context = GetContext();
+
+ static const char* kName = "val";
+
+ class Accessor : public CefV8Accessor {
+ public:
+ Accessor() {}
+ bool Get(const CefString& name,
+ const CefRefPtr<CefV8Value> object,
+ CefRefPtr<CefV8Value>& retval,
+ CefString& exception) override {
+ got_get_.yes();
+ return true;
+ }
+
+ bool Set(const CefString& name,
+ const CefRefPtr<CefV8Value> object,
+ const CefRefPtr<CefV8Value> value,
+ CefString& exception) override {
+ got_set_.yes();
+ return true;
+ }
+
+ TrackCallback got_get_;
+ TrackCallback got_set_;
+
+ IMPLEMENT_REFCOUNTING(Accessor);
+ };
+
+ // Enter the V8 context.
+ EXPECT_TRUE(context->Enter());
+
+ CefRefPtr<CefV8Exception> exception;
+ Accessor* accessor = new Accessor;
+ CefRefPtr<CefV8Accessor> accessorPtr(accessor);
+
+ CefRefPtr<CefV8Value> object = CefV8Value::CreateObject(accessor, nullptr);
+ EXPECT_TRUE(object.get());
+
+ EXPECT_FALSE(object->HasValue(kName));
+
+ EXPECT_TRUE(object->SetValue(kName, V8_ACCESS_CONTROL_DEFAULT,
+ V8_PROPERTY_ATTRIBUTE_READONLY));
+ EXPECT_FALSE(object->HasException());
+ EXPECT_TRUE(object->HasValue(kName));
+
+ EXPECT_TRUE(object->SetValue(kName, CefV8Value::CreateInt(1),
+ V8_PROPERTY_ATTRIBUTE_NONE));
+ EXPECT_FALSE(object->HasException());
+ EXPECT_FALSE(accessor->got_set_);
+
+ CefRefPtr<CefV8Value> val = object->GetValue(kName);
+ EXPECT_TRUE(val.get());
+ EXPECT_FALSE(object->HasException());
+ EXPECT_TRUE(accessor->got_get_);
+ EXPECT_TRUE(val->IsUndefined());
+
+ // Exit the V8 context.
+ EXPECT_TRUE(context->Exit());
+
+ DestroyTest();
+ }
+
+ void RunObjectInterceptorTest() {
+ CefRefPtr<CefV8Context> context = GetContext();
+
+ static const char* kName1 = "val1";
+ static const char* kName2 = "val2";
+ static const char* kName3 = "val3";
+
+ static const int kValue1 = 20;
+ static const uint32 kValue2 = 30u;
+ static const char* kValue3 = "40";
+
+ static const int kArray[] = {50, 60, 70};
+
+ class Interceptor : public CefV8Interceptor {
+ public:
+ Interceptor() : value1_(0), value2_(0u), array_() {}
+ virtual bool Get(const CefString& name,
+ const CefRefPtr<CefV8Value> object,
+ CefRefPtr<CefV8Value>& retval,
+ CefString& exception) override {
+ EXPECT_TRUE(name.ToString() == kName1 || name.ToString() == kName2 ||
+ name.ToString() == kName3);
+
+ EXPECT_TRUE(object.get());
+ EXPECT_TRUE(object->IsSame(object_));
+
+ EXPECT_FALSE(retval.get());
+ EXPECT_TRUE(exception.empty());
+
+ got_get_byname_.yes();
+ if (name.ToString() == kName1) {
+ retval = CefV8Value::CreateInt(value1_);
+ EXPECT_EQ(kValue1, retval->GetIntValue());
+ } else if (name.ToString() == kName2) {
+ retval = CefV8Value::CreateUInt(value2_);
+ EXPECT_EQ(kValue2, retval->GetUIntValue());
+ } else if (name.ToString() == kName3) {
+ retval = CefV8Value::CreateString(value3_);
+ EXPECT_STREQ(kValue3, retval->GetStringValue().ToString().c_str());
+ }
+ return true;
+ }
+
+ virtual bool Get(int index,
+ const CefRefPtr<CefV8Value> object,
+ CefRefPtr<CefV8Value>& retval,
+ CefString& exception) override {
+ EXPECT_TRUE(index >= 0 && index < 3);
+
+ EXPECT_TRUE(object.get());
+ EXPECT_TRUE(object->IsSame(object_));
+
+ EXPECT_FALSE(retval.get());
+ EXPECT_TRUE(exception.empty());
+
+ got_get_byindex_.yes();
+ retval = CefV8Value::CreateInt(array_[index]);
+ EXPECT_EQ(kArray[index], retval->GetIntValue());
+ return true;
+ }
+
+ virtual bool Set(const CefString& name,
+ const CefRefPtr<CefV8Value> object,
+ const CefRefPtr<CefV8Value> value,
+ CefString& exception) override {
+ EXPECT_TRUE(name.ToString() == kName1 || name.ToString() == kName2 ||
+ name.ToString() == kName3);
+
+ EXPECT_TRUE(object.get());
+ EXPECT_TRUE(object->IsSame(object_));
+
+ EXPECT_TRUE(value.get());
+ EXPECT_TRUE(exception.empty());
+
+ got_set_byname_.yes();
+ if (name.ToString() == kName1) {
+ value1_ = value->GetIntValue();
+ EXPECT_EQ(kValue1, value1_);
+ } else if (name.ToString() == kName2) {
+ value2_ = value->GetUIntValue();
+ EXPECT_EQ(kValue2, value2_);
+ } else if (name.ToString() == kName3) {
+ value3_ = value->GetStringValue();
+ EXPECT_STREQ(kValue3, value3_.ToString().c_str());
+ }
+ return true;
+ }
+
+ virtual bool Set(int index,
+ const CefRefPtr<CefV8Value> object,
+ const CefRefPtr<CefV8Value> value,
+ CefString& exception) override {
+ EXPECT_TRUE(index >= 0 && index < 3);
+
+ EXPECT_TRUE(object.get());
+ EXPECT_TRUE(object->IsSame(object_));
+
+ EXPECT_TRUE(value.get());
+ EXPECT_TRUE(exception.empty());
+
+ got_set_byindex_.yes();
+ array_[index] = value->GetIntValue();
+ EXPECT_EQ(array_[index], kArray[index]);
+ return true;
+ }
+
+ CefRefPtr<CefV8Value> object_;
+ int value1_;
+ unsigned int value2_;
+ CefString value3_;
+ int array_[3];
+
+ TrackCallback got_get_byname_;
+ TrackCallback got_get_byindex_;
+ TrackCallback got_set_byname_;
+ TrackCallback got_set_byindex_;
+
+ IMPLEMENT_REFCOUNTING(Interceptor);
+ };
+
+ // Enter the V8 context.
+ EXPECT_TRUE(context->Enter());
+
+ Interceptor* interceptor = new Interceptor;
+ CefRefPtr<CefV8Interceptor> interceptorPtr(interceptor);
+
+ CefRefPtr<CefV8Value> object =
+ CefV8Value::CreateObject(nullptr, interceptor);
+ EXPECT_TRUE(object.get());
+ interceptor->object_ = object;
+
+ EXPECT_FALSE(object->HasException());
+
+ EXPECT_TRUE(object->SetValue(kName1, CefV8Value::CreateInt(kValue1),
+ V8_PROPERTY_ATTRIBUTE_NONE));
+ EXPECT_FALSE(object->HasException());
+ EXPECT_TRUE(interceptor->got_set_byname_);
+ interceptor->got_set_byname_.reset();
+
+ EXPECT_TRUE(object->SetValue(kName2, CefV8Value::CreateUInt(kValue2),
+ V8_PROPERTY_ATTRIBUTE_NONE));
+ EXPECT_FALSE(object->HasException());
+ EXPECT_TRUE(interceptor->got_set_byname_);
+ interceptor->got_set_byname_.reset();
+
+ EXPECT_TRUE(object->SetValue(kName3, CefV8Value::CreateString(kValue3),
+ V8_PROPERTY_ATTRIBUTE_NONE));
+ EXPECT_FALSE(object->HasException());
+ EXPECT_TRUE(interceptor->got_set_byname_);
+ interceptor->got_set_byname_.reset();
+
+ EXPECT_EQ(kValue1, interceptor->value1_);
+ EXPECT_EQ(kValue2, interceptor->value2_);
+ EXPECT_STREQ(kValue3, interceptor->value3_.ToString().c_str());
+
+ for (int i = 0; i < 3; ++i) {
+ EXPECT_TRUE(object->SetValue(i, CefV8Value::CreateInt(kArray[i])));
+ EXPECT_FALSE(object->HasException());
+ EXPECT_TRUE(interceptor->got_set_byindex_);
+ interceptor->got_set_byindex_.reset();
+ EXPECT_EQ(kArray[i], interceptor->array_[i]);
+ }
+
+ CefRefPtr<CefV8Value> val1 = object->GetValue(kName1);
+ EXPECT_FALSE(object->HasException());
+ EXPECT_TRUE(val1.get());
+ EXPECT_TRUE(interceptor->got_get_byname_);
+ interceptor->got_get_byname_.reset();
+ EXPECT_TRUE(val1->IsInt());
+ EXPECT_EQ(kValue1, val1->GetIntValue());
+
+ CefRefPtr<CefV8Value> val2 = object->GetValue(kName2);
+ EXPECT_FALSE(object->HasException());
+ EXPECT_TRUE(val2.get());
+ EXPECT_TRUE(interceptor->got_get_byname_);
+ interceptor->got_get_byname_.reset();
+ EXPECT_TRUE(val2->IsUInt());
+ EXPECT_EQ(kValue2, val2->GetUIntValue());
+
+ CefRefPtr<CefV8Value> val3 = object->GetValue(kName3);
+ EXPECT_FALSE(object->HasException());
+ EXPECT_TRUE(val3.get());
+ EXPECT_TRUE(interceptor->got_get_byname_);
+ interceptor->got_get_byname_.reset();
+ EXPECT_TRUE(val3->IsString());
+ EXPECT_STREQ(kValue3, val3->GetStringValue().ToString().c_str());
+
+ for (int i = 0; i < 3; ++i) {
+ CefRefPtr<CefV8Value> val = object->GetValue(i);
+ EXPECT_FALSE(object->HasException());
+ EXPECT_TRUE(val.get());
+ EXPECT_TRUE(interceptor->got_get_byindex_);
+ interceptor->got_get_byname_.reset();
+ EXPECT_EQ(kArray[i], val->GetIntValue());
+ }
+
+ interceptor->object_ = nullptr;
+
+ // Exit the V8 context.
+ EXPECT_TRUE(context->Exit());
+
+ DestroyTest();
+ }
+
+ void RunObjectInterceptorFailTest() {
+ CefRefPtr<CefV8Context> context = GetContext();
+
+ static const char* kName = "val";
+ static const int kIndex = 0;
+ static const int kValue1 = 20;
+ static const int kValue2 = 30;
+
+ class Interceptor : public CefV8Interceptor {
+ typedef std::map<int, int> IntMap;
+ typedef std::map<std::string, int> StringMap;
+
+ public:
+ Interceptor() {}
+ virtual bool Get(const CefString& name,
+ const CefRefPtr<CefV8Value> object,
+ CefRefPtr<CefV8Value>& retval,
+ CefString& exception) override {
+ got_get_byname_.yes();
+ StringMap::iterator it = string_map_.find(name.ToString());
+ if (it != string_map_.end()) {
+ retval = CefV8Value::CreateInt(it->second);
+ }
+ return true;
+ }
+
+ virtual bool Get(int index,
+ const CefRefPtr<CefV8Value> object,
+ CefRefPtr<CefV8Value>& retval,
+ CefString& exception) override {
+ got_get_byindex_.yes();
+ IntMap::iterator it = int_map_.find(index);
+ if (it != int_map_.end()) {
+ retval = CefV8Value::CreateInt(it->second);
+ }
+ return true;
+ }
+
+ virtual bool Set(const CefString& name,
+ const CefRefPtr<CefV8Value> object,
+ const CefRefPtr<CefV8Value> value,
+ CefString& exception) override {
+ EXPECT_TRUE(value->IsInt());
+ got_set_byname_.yes();
+ string_map_[name.ToString()] = value->GetIntValue();
+ return true;
+ }
+
+ virtual bool Set(int index,
+ const CefRefPtr<CefV8Value> object,
+ const CefRefPtr<CefV8Value> value,
+ CefString& exception) override {
+ EXPECT_TRUE(value->IsInt());
+ got_set_byindex_.yes();
+ int_map_[index] = value->GetIntValue();
+ return true;
+ }
+
+ IntMap int_map_;
+ StringMap string_map_;
+
+ TrackCallback got_get_byname_;
+ TrackCallback got_get_byindex_;
+ TrackCallback got_set_byname_;
+ TrackCallback got_set_byindex_;
+
+ IMPLEMENT_REFCOUNTING(Interceptor);
+ };
+
+ // Enter the V8 context.
+ EXPECT_TRUE(context->Enter());
+
+ Interceptor* interceptor = new Interceptor;
+ CefRefPtr<CefV8Interceptor> interceptorPtr(interceptor);
+
+ CefRefPtr<CefV8Value> object =
+ CefV8Value::CreateObject(nullptr, interceptor);
+ EXPECT_TRUE(object.get());
+
+ EXPECT_FALSE(object->HasValue(kName));
+ EXPECT_FALSE(object->HasException());
+ EXPECT_TRUE(interceptor->got_get_byname_);
+ interceptor->got_get_byname_.reset();
+
+ CefRefPtr<CefV8Value> val1 = object->GetValue(kName);
+ EXPECT_TRUE(val1.get());
+ EXPECT_FALSE(object->HasException());
+ EXPECT_TRUE(interceptor->got_get_byname_);
+ EXPECT_TRUE(val1->IsUndefined());
+ interceptor->got_get_byname_.reset();
+
+ EXPECT_TRUE(object->SetValue(kName, CefV8Value::CreateInt(kValue1),
+ V8_PROPERTY_ATTRIBUTE_NONE));
+ EXPECT_FALSE(object->HasException());
+ EXPECT_TRUE(interceptor->got_set_byname_);
+
+ val1 = object->GetValue(kName);
+ EXPECT_TRUE(val1.get());
+ EXPECT_FALSE(object->HasException());
+ EXPECT_TRUE(interceptor->got_get_byname_);
+ EXPECT_EQ(kValue1, val1->GetIntValue());
+
+ EXPECT_FALSE(object->HasValue(kIndex));
+ EXPECT_FALSE(object->HasException());
+ EXPECT_TRUE(interceptor->got_get_byindex_);
+ interceptor->got_get_byindex_.reset();
+
+ CefRefPtr<CefV8Value> val2 = object->GetValue(kIndex);
+ EXPECT_TRUE(val2.get());
+ EXPECT_FALSE(object->HasException());
+ EXPECT_TRUE(interceptor->got_get_byindex_);
+ EXPECT_TRUE(val2->IsUndefined());
+ interceptor->got_get_byindex_.reset();
+
+ EXPECT_TRUE(object->SetValue(kIndex, CefV8Value::CreateInt(kValue2)));
+ EXPECT_FALSE(object->HasException());
+ EXPECT_TRUE(interceptor->got_set_byindex_);
+
+ val2 = object->GetValue(kIndex);
+ EXPECT_TRUE(val2.get());
+ EXPECT_FALSE(object->HasException());
+ EXPECT_TRUE(interceptor->got_get_byindex_);
+ EXPECT_EQ(kValue2, val2->GetIntValue());
+
+ // Exit the V8 context.
+ EXPECT_TRUE(context->Exit());
+
+ DestroyTest();
+ }
+
+ void RunObjectInterceptorExceptionTest() {
+ CefRefPtr<CefV8Context> context = GetContext();
+ static const char* kName = "val";
+ static const int kIndex = 1;
+
+ static const char* kGetByNameException = "My get_byname exception";
+ static const char* kGetByIndexException = "My get_byindex exception";
+ static const char* kSetByNameException = "My set_byname exception";
+ static const char* kSetByIndexException = "My set_byindex exception";
+
+ static const char* kGetByNameExceptionMsg =
+ "Uncaught Error: My get_byname exception";
+ static const char* kGetByIndexExceptionMsg =
+ "Uncaught Error: My get_byindex exception";
+ static const char* kSetByNameExceptionMsg =
+ "Uncaught Error: My set_byname exception";
+ static const char* kSetByIndexExceptionMsg =
+ "Uncaught Error: My set_byindex exception";
+
+ class Interceptor : public CefV8Interceptor {
+ public:
+ Interceptor() {}
+ virtual bool Get(const CefString& name,
+ const CefRefPtr<CefV8Value> object,
+ CefRefPtr<CefV8Value>& retval,
+ CefString& exception) override {
+ got_get_byname_.yes();
+ exception = kGetByNameException;
+ return true;
+ }
+
+ virtual bool Get(int index,
+ const CefRefPtr<CefV8Value> object,
+ CefRefPtr<CefV8Value>& retval,
+ CefString& exception) override {
+ got_get_byindex_.yes();
+ exception = kGetByIndexException;
+ return true;
+ }
+
+ virtual bool Set(const CefString& name,
+ const CefRefPtr<CefV8Value> object,
+ const CefRefPtr<CefV8Value> value,
+ CefString& exception) override {
+ got_set_byname_.yes();
+ exception = kSetByNameException;
+ return true;
+ }
+
+ virtual bool Set(int index,
+ const CefRefPtr<CefV8Value> object,
+ const CefRefPtr<CefV8Value> value,
+ CefString& exception) override {
+ got_set_byindex_.yes();
+ exception = kSetByIndexException;
+ return true;
+ }
+
+ TrackCallback got_get_byname_;
+ TrackCallback got_get_byindex_;
+ TrackCallback got_set_byname_;
+ TrackCallback got_set_byindex_;
+
+ IMPLEMENT_REFCOUNTING(Interceptor);
+ };
+
+ // Enter the V8 context.
+ EXPECT_TRUE(context->Enter());
+
+ CefRefPtr<CefV8Exception> exception;
+ Interceptor* interceptor = new Interceptor;
+ CefRefPtr<CefV8Interceptor> interceptorPtr(interceptor);
+
+ CefRefPtr<CefV8Value> object =
+ CefV8Value::CreateObject(nullptr, interceptor);
+ EXPECT_TRUE(object.get());
+
+ EXPECT_FALSE(object->SetValue(kName, CefV8Value::CreateInt(1),
+ V8_PROPERTY_ATTRIBUTE_NONE));
+ EXPECT_TRUE(object->HasException());
+ EXPECT_TRUE(interceptor->got_set_byname_);
+ exception = object->GetException();
+ EXPECT_TRUE(exception.get());
+ EXPECT_STREQ(kSetByNameExceptionMsg,
+ exception->GetMessage().ToString().c_str());
+
+ EXPECT_TRUE(object->ClearException());
+ EXPECT_FALSE(object->HasException());
+
+ CefRefPtr<CefV8Value> val1 = object->GetValue(kName);
+ EXPECT_FALSE(val1.get());
+ EXPECT_TRUE(object->HasException());
+ EXPECT_TRUE(interceptor->got_get_byname_);
+ exception = object->GetException();
+ EXPECT_TRUE(exception.get());
+ EXPECT_STREQ(kGetByNameExceptionMsg,
+ exception->GetMessage().ToString().c_str());
+
+ EXPECT_TRUE(object->ClearException());
+ EXPECT_FALSE(object->HasException());
+
+ EXPECT_FALSE(object->SetValue(kIndex, CefV8Value::CreateInt(1)));
+ EXPECT_TRUE(object->HasException());
+ EXPECT_TRUE(interceptor->got_set_byindex_);
+ exception = object->GetException();
+ EXPECT_TRUE(exception.get());
+ EXPECT_STREQ(kSetByIndexExceptionMsg,
+ exception->GetMessage().ToString().c_str());
+
+ EXPECT_TRUE(object->ClearException());
+ EXPECT_FALSE(object->HasException());
+
+ CefRefPtr<CefV8Value> val2 = object->GetValue(kIndex);
+ EXPECT_FALSE(val2.get());
+ EXPECT_TRUE(object->HasException());
+ EXPECT_TRUE(interceptor->got_get_byindex_);
+ exception = object->GetException();
+ EXPECT_TRUE(exception.get());
+ EXPECT_STREQ(kGetByIndexExceptionMsg,
+ exception->GetMessage().ToString().c_str());
+
+ // Exit the V8 context.
+ EXPECT_TRUE(context->Exit());
+
+ DestroyTest();
+ }
+
+ void RunObjectInterceptorAndAccessorTest() {
+ CefRefPtr<CefV8Context> context = GetContext();
+ static const char* kInterceptorName = "val1";
+ static const char* kAccessorName = "val2";
+
+ static const int kInterceptorValue = 20;
+ static const int kAccessorValue = 30;
+
+ class Interceptor : public CefV8Interceptor {
+ public:
+ Interceptor() {}
+ virtual bool Get(const CefString& name,
+ const CefRefPtr<CefV8Value> object,
+ CefRefPtr<CefV8Value>& retval,
+ CefString& exception) override {
+ EXPECT_FALSE(retval.get());
+ got_get_byname_.yes();
+ if (name.ToString() == kInterceptorName) {
+ retval = CefV8Value::CreateInt(kInterceptorValue);
+ }
+ return true;
+ }
+
+ virtual bool Get(int index,
+ const CefRefPtr<CefV8Value> object,
+ CefRefPtr<CefV8Value>& retval,
+ CefString& exception) override {
+ got_get_byindex_.yes();
+ return true;
+ }
+
+ virtual bool Set(const CefString& name,
+ const CefRefPtr<CefV8Value> object,
+ const CefRefPtr<CefV8Value> value,
+ CefString& exception) override {
+ got_set_byname_.yes();
+ return true;
+ }
+
+ virtual bool Set(int index,
+ const CefRefPtr<CefV8Value> object,
+ const CefRefPtr<CefV8Value> value,
+ CefString& exception) override {
+ got_set_byindex_.yes();
+ return true;
+ }
+
+ TrackCallback got_get_byname_;
+ TrackCallback got_get_byindex_;
+ TrackCallback got_set_byname_;
+ TrackCallback got_set_byindex_;
+
+ IMPLEMENT_REFCOUNTING(Interceptor);
+ };
+
+ class Accessor : public CefV8Accessor {
+ public:
+ Accessor() {}
+ virtual bool Get(const CefString& name,
+ const CefRefPtr<CefV8Value> object,
+ CefRefPtr<CefV8Value>& retval,
+ CefString& exception) override {
+ got_get_.yes();
+ retval = CefV8Value::CreateInt(kAccessorValue);
+ return true;
+ }
+
+ virtual bool Set(const CefString& name,
+ const CefRefPtr<CefV8Value> object,
+ const CefRefPtr<CefV8Value> value,
+ CefString& exception) override {
+ got_set_.yes();
+ return true;
+ }
+
+ TrackCallback got_get_;
+ TrackCallback got_set_;
+
+ IMPLEMENT_REFCOUNTING(Accessor);
+ };
+
+ // Enter the V8 context.
+ EXPECT_TRUE(context->Enter());
+
+ Interceptor* interceptor = new Interceptor;
+ CefRefPtr<CefV8Interceptor> interceptorPtr(interceptor);
+
+ Accessor* accessor = new Accessor;
+ CefRefPtr<CefV8Accessor> accessorPtr(accessor);
+
+ CefRefPtr<CefV8Value> object =
+ CefV8Value::CreateObject(accessor, interceptor);
+ EXPECT_TRUE(object.get());
+
+ // We register both names for accessor.
+ EXPECT_TRUE(object->SetValue(kAccessorName, V8_ACCESS_CONTROL_DEFAULT,
+ V8_PROPERTY_ATTRIBUTE_NONE));
+ EXPECT_FALSE(object->HasException());
+
+ EXPECT_TRUE(object->SetValue(kInterceptorName, V8_ACCESS_CONTROL_DEFAULT,
+ V8_PROPERTY_ATTRIBUTE_NONE));
+ EXPECT_FALSE(object->HasException());
+
+ EXPECT_TRUE(object->SetValue(kAccessorName,
+ CefV8Value::CreateInt(kAccessorValue),
+ V8_PROPERTY_ATTRIBUTE_NONE));
+ EXPECT_FALSE(object->HasException());
+ EXPECT_TRUE(accessor->got_set_);
+ accessor->got_set_.reset();
+ EXPECT_TRUE(interceptor->got_set_byname_);
+ interceptor->got_set_byname_.reset();
+
+ EXPECT_TRUE(object->SetValue(kInterceptorName,
+ CefV8Value::CreateInt(kInterceptorValue),
+ V8_PROPERTY_ATTRIBUTE_NONE));
+ EXPECT_FALSE(object->HasException());
+ EXPECT_TRUE(accessor->got_set_);
+ accessor->got_set_.reset();
+ EXPECT_TRUE(interceptor->got_set_byname_);
+ interceptor->got_set_byname_.reset();
+
+ // When interceptor returns nothing, accessor's getter is called.
+ CefRefPtr<CefV8Value> val1 = object->GetValue(kAccessorName);
+ EXPECT_TRUE(val1.get());
+ EXPECT_TRUE(interceptor->got_get_byname_);
+ interceptor->got_get_byname_.reset();
+ EXPECT_TRUE(accessor->got_get_);
+ accessor->got_get_.reset();
+ EXPECT_EQ(kAccessorValue, val1->GetIntValue());
+
+ // When interceptor returns value, accessor's getter is not called.
+ CefRefPtr<CefV8Value> val2 = object->GetValue(kInterceptorName);
+ EXPECT_TRUE(val2.get());
+ EXPECT_TRUE(interceptor->got_get_byname_);
+ EXPECT_FALSE(accessor->got_get_);
+ EXPECT_EQ(kInterceptorValue, val2->GetIntValue());
+
+ EXPECT_FALSE(interceptor->got_get_byindex_);
+ EXPECT_FALSE(interceptor->got_set_byindex_);
+
+ // Exit the V8 context.
+ EXPECT_TRUE(context->Exit());
+
+ DestroyTest();
+ }
+
+ void RunObjectValueTest() {
+ CefRefPtr<CefV8Context> context = GetContext();
+
+ static const char* kName = "test_arg";
+ static const int kVal1 = 13;
+ static const int kVal2 = 65;
+
+ // Enter the V8 context.
+ EXPECT_TRUE(context->Enter());
+
+ CefRefPtr<CefV8Value> object = context->GetGlobal();
+ EXPECT_TRUE(object.get());
+
+ object->SetValue(kName, CefV8Value::CreateInt(kVal1),
+ V8_PROPERTY_ATTRIBUTE_NONE);
+
+ std::stringstream test;
+ test << "if (window." << kName << " != " << kVal1 << ") throw 'Fail';\n"
+ << "window." << kName << " = " << kVal2 << ";";
+
+ CefRefPtr<CefV8Value> retval;
+ CefRefPtr<CefV8Exception> exception;
+
+ EXPECT_TRUE(context->Eval(test.str(), CefString(), 0, retval, exception));
+ if (exception.get()) {
+ ADD_FAILURE() << exception->GetMessage().c_str();
+ }
+
+ CefRefPtr<CefV8Value> newval = object->GetValue(kName);
+ EXPECT_TRUE(newval.get());
+ EXPECT_TRUE(newval->IsInt());
+ EXPECT_EQ(kVal2, newval->GetIntValue());
+
+ // Exit the V8 context.
+ EXPECT_TRUE(context->Exit());
+
+ DestroyTest();
+ }
+
+ void RunObjectValueReadOnlyTest() {
+ CefRefPtr<CefV8Context> context = GetContext();
+
+ static const char* kName = "test_arg";
+ static const int kVal1 = 13;
+ static const int kVal2 = 65;
+
+ // Enter the V8 context.
+ EXPECT_TRUE(context->Enter());
+
+ CefRefPtr<CefV8Value> object = context->GetGlobal();
+ EXPECT_TRUE(object.get());
+
+ object->SetValue(kName, CefV8Value::CreateInt(kVal1),
+ V8_PROPERTY_ATTRIBUTE_READONLY);
+
+ std::stringstream test;
+ test << "if (window." << kName << " != " << kVal1 << ") throw 'Fail';\n"
+ << "window." << kName << " = " << kVal2 << ";";
+
+ CefRefPtr<CefV8Value> retval;
+ CefRefPtr<CefV8Exception> exception;
+
+ EXPECT_TRUE(context->Eval(test.str(), CefString(), 0, retval, exception));
+ if (exception.get()) {
+ ADD_FAILURE() << exception->GetMessage().c_str();
+ }
+
+ CefRefPtr<CefV8Value> newval = object->GetValue(kName);
+ EXPECT_TRUE(newval.get());
+ EXPECT_TRUE(newval->IsInt());
+ EXPECT_EQ(kVal1, newval->GetIntValue());
+
+ // Exit the V8 context.
+ EXPECT_TRUE(context->Exit());
+
+ DestroyTest();
+ }
+
+ void RunObjectValueEnumTest() {
+ CefRefPtr<CefV8Context> context = GetContext();
+
+ static const char* kObjName = "test_obj";
+ static const char* kArgName = "test_arg";
+
+ // Enter the V8 context.
+ EXPECT_TRUE(context->Enter());
+
+ CefRefPtr<CefV8Value> object = context->GetGlobal();
+ EXPECT_TRUE(object.get());
+
+ CefRefPtr<CefV8Value> obj1 = CefV8Value::CreateObject(nullptr, nullptr);
+ object->SetValue(kObjName, obj1, V8_PROPERTY_ATTRIBUTE_NONE);
+
+ obj1->SetValue(kArgName, CefV8Value::CreateInt(0),
+ V8_PROPERTY_ATTRIBUTE_NONE);
+
+ std::stringstream test;
+ test << "for (var i in window." << kObjName
+ << ") {\n"
+ "window."
+ << kObjName
+ << "[i]++;\n"
+ "}";
+
+ CefRefPtr<CefV8Value> retval;
+ CefRefPtr<CefV8Exception> exception;
+
+ EXPECT_TRUE(context->Eval(test.str(), CefString(), 0, retval, exception));
+ if (exception.get()) {
+ ADD_FAILURE() << exception->GetMessage().c_str();
+ }
+
+ CefRefPtr<CefV8Value> newval = obj1->GetValue(kArgName);
+ EXPECT_TRUE(newval.get());
+ EXPECT_TRUE(newval->IsInt());
+ EXPECT_EQ(1, newval->GetIntValue());
+
+ // Exit the V8 context.
+ EXPECT_TRUE(context->Exit());
+
+ DestroyTest();
+ }
+
+ void RunObjectValueDontEnumTest() {
+ CefRefPtr<CefV8Context> context = GetContext();
+
+ static const char* kObjName = "test_obj";
+ static const char* kArgName = "test_arg";
+
+ // Enter the V8 context.
+ EXPECT_TRUE(context->Enter());
+
+ CefRefPtr<CefV8Value> object = context->GetGlobal();
+ EXPECT_TRUE(object.get());
+
+ CefRefPtr<CefV8Value> obj1 = CefV8Value::CreateObject(nullptr, nullptr);
+ object->SetValue(kObjName, obj1, V8_PROPERTY_ATTRIBUTE_NONE);
+
+ obj1->SetValue(kArgName, CefV8Value::CreateInt(0),
+ V8_PROPERTY_ATTRIBUTE_DONTENUM);
+
+ std::stringstream test;
+ test << "for (var i in window." << kObjName
+ << ") {\n"
+ "window."
+ << kObjName
+ << "[i]++;\n"
+ "}";
+
+ CefRefPtr<CefV8Value> retval;
+ CefRefPtr<CefV8Exception> exception;
+
+ EXPECT_TRUE(context->Eval(test.str(), CefString(), 0, retval, exception));
+ if (exception.get()) {
+ ADD_FAILURE() << exception->GetMessage().c_str();
+ }
+
+ CefRefPtr<CefV8Value> newval = obj1->GetValue(kArgName);
+ EXPECT_TRUE(newval.get());
+ EXPECT_TRUE(newval->IsInt());
+ EXPECT_EQ(0, newval->GetIntValue());
+
+ // Exit the V8 context.
+ EXPECT_TRUE(context->Exit());
+
+ DestroyTest();
+ }
+
+ void RunObjectValueDeleteTest() {
+ CefRefPtr<CefV8Context> context = GetContext();
+
+ static const char* kName = "test_arg";
+ static const int kVal1 = 13;
+ static const int kVal2 = 65;
+
+ // Enter the V8 context.
+ EXPECT_TRUE(context->Enter());
+
+ CefRefPtr<CefV8Value> object = context->GetGlobal();
+ EXPECT_TRUE(object.get());
+
+ object->SetValue(kName, CefV8Value::CreateInt(kVal1),
+ V8_PROPERTY_ATTRIBUTE_NONE);
+
+ std::stringstream test;
+ test << "if (window." << kName << " != " << kVal1 << ") throw 'Fail';\n"
+ << "window." << kName << " = " << kVal2
+ << ";\n"
+ "delete window."
+ << kName << ";";
+
+ CefRefPtr<CefV8Value> retval;
+ CefRefPtr<CefV8Exception> exception;
+
+ EXPECT_TRUE(context->Eval(test.str(), CefString(), 0, retval, exception));
+ if (exception.get()) {
+ ADD_FAILURE() << exception->GetMessage().c_str();
+ }
+
+ CefRefPtr<CefV8Value> newval = object->GetValue(kName);
+ EXPECT_TRUE(newval.get());
+ EXPECT_TRUE(newval->IsUndefined());
+ EXPECT_FALSE(newval->IsInt());
+
+ // Exit the V8 context.
+ EXPECT_TRUE(context->Exit());
+
+ DestroyTest();
+ }
+
+ void RunObjectValueDontDeleteTest() {
+ CefRefPtr<CefV8Context> context = GetContext();
+
+ static const char* kName = "test_arg";
+ static const int kVal1 = 13;
+ static const int kVal2 = 65;
+
+ // Enter the V8 context.
+ EXPECT_TRUE(context->Enter());
+
+ CefRefPtr<CefV8Value> object = context->GetGlobal();
+ EXPECT_TRUE(object.get());
+
+ object->SetValue(kName, CefV8Value::CreateInt(kVal1),
+ V8_PROPERTY_ATTRIBUTE_DONTDELETE);
+
+ std::stringstream test;
+ test << "if (window." << kName << " != " << kVal1 << ") throw 'Fail';\n"
+ << "window." << kName << " = " << kVal2
+ << ";\n"
+ "delete window."
+ << kName << ";";
+
+ CefRefPtr<CefV8Value> retval;
+ CefRefPtr<CefV8Exception> exception;
+
+ EXPECT_TRUE(context->Eval(test.str(), CefString(), 0, retval, exception));
+ if (exception.get()) {
+ ADD_FAILURE() << exception->GetMessage().c_str();
+ }
+
+ CefRefPtr<CefV8Value> newval = object->GetValue(kName);
+ EXPECT_TRUE(newval.get());
+ EXPECT_TRUE(newval->IsInt());
+ EXPECT_EQ(kVal2, newval->GetIntValue());
+
+ // Exit the V8 context.
+ EXPECT_TRUE(context->Exit());
+
+ DestroyTest();
+ }
+
+ void RunObjectValueEmptyKeyTest() {
+ CefRefPtr<CefV8Context> context = GetContext();
+
+ static const char* kName = "";
+ static const int kVal = 13;
+
+ // Enter the V8 context.
+ EXPECT_TRUE(context->Enter());
+
+ CefRefPtr<CefV8Value> object = context->GetGlobal();
+ EXPECT_TRUE(object.get());
+
+ EXPECT_FALSE(object->HasValue(kName));
+
+ object->SetValue(kName, CefV8Value::CreateInt(kVal),
+ V8_PROPERTY_ATTRIBUTE_NONE);
+ EXPECT_TRUE(object->HasValue(kName));
+
+ CefRefPtr<CefV8Value> newval = object->GetValue(kName);
+ EXPECT_TRUE(newval.get());
+ EXPECT_TRUE(newval->IsInt());
+ EXPECT_EQ(kVal, newval->GetIntValue());
+
+ EXPECT_TRUE(object->DeleteValue(kName));
+ EXPECT_FALSE(object->HasValue(kName));
+
+ // Exit the V8 context.
+ EXPECT_TRUE(context->Exit());
+
+ DestroyTest();
+ }
+
+ void RunFunctionCreateTest() {
+ CefRefPtr<CefV8Context> context = GetContext();
+
+ class Handler : public CefV8Handler {
+ public:
+ Handler() {}
+ bool Execute(const CefString& name,
+ CefRefPtr<CefV8Value> object,
+ const CefV8ValueList& arguments,
+ CefRefPtr<CefV8Value>& retval,
+ CefString& exception) override {
+ return false;
+ }
+ IMPLEMENT_REFCOUNTING(Handler);
+ };
+
+ // Enter the V8 context.
+ EXPECT_TRUE(context->Enter());
+
+ CefRefPtr<CefV8Value> value = CefV8Value::CreateFunction("f", new Handler);
+
+ // Exit the V8 context.
+ EXPECT_TRUE(context->Exit());
+
+ EXPECT_TRUE(value.get());
+ EXPECT_TRUE(value->IsFunction());
+ EXPECT_TRUE(value->IsObject());
+
+ EXPECT_FALSE(value->IsUndefined());
+ EXPECT_FALSE(value->IsArray());
+ EXPECT_FALSE(value->IsBool());
+ EXPECT_FALSE(value->IsDate());
+ EXPECT_FALSE(value->IsDouble());
+ EXPECT_FALSE(value->IsInt());
+ EXPECT_FALSE(value->IsUInt());
+ EXPECT_FALSE(value->IsNull());
+ EXPECT_FALSE(value->IsPromise());
+ EXPECT_FALSE(value->IsString());
+
+ DestroyTest();
+ }
+
+ void RunFunctionHandlerTest() {
+ CefRefPtr<CefV8Context> context = GetContext();
+
+ static const char* kFuncName = "myfunc";
+ static const int kVal1 = 32;
+ static const int kVal2 = 41;
+ static const int kRetVal = 8;
+
+ class Handler : public CefV8Handler {
+ public:
+ Handler() {}
+ bool Execute(const CefString& name,
+ CefRefPtr<CefV8Value> object,
+ const CefV8ValueList& arguments,
+ CefRefPtr<CefV8Value>& retval,
+ CefString& exception) override {
+ EXPECT_STREQ(kFuncName, name.ToString().c_str());
+ EXPECT_TRUE(object->IsSame(object_));
+
+ EXPECT_EQ((size_t)2, arguments.size());
+ EXPECT_TRUE(arguments[0]->IsInt());
+ EXPECT_EQ(kVal1, arguments[0]->GetIntValue());
+ EXPECT_TRUE(arguments[1]->IsInt());
+ EXPECT_EQ(kVal2, arguments[1]->GetIntValue());
+
+ EXPECT_TRUE(exception.empty());
+
+ retval = CefV8Value::CreateInt(kRetVal);
+ EXPECT_TRUE(retval.get());
+ EXPECT_EQ(kRetVal, retval->GetIntValue());
+
+ got_execute_.yes();
+ return true;
+ }
+
+ CefRefPtr<CefV8Value> object_;
+ TrackCallback got_execute_;
+
+ IMPLEMENT_REFCOUNTING(Handler);
+ };
+
+ // Enter the V8 context.
+ EXPECT_TRUE(context->Enter());
+
+ Handler* handler = new Handler;
+ CefRefPtr<CefV8Handler> handlerPtr(handler);
+
+ CefRefPtr<CefV8Value> func = CefV8Value::CreateFunction(kFuncName, handler);
+ EXPECT_TRUE(func.get());
+
+ CefRefPtr<CefV8Value> obj = CefV8Value::CreateObject(nullptr, nullptr);
+ EXPECT_TRUE(obj.get());
+ handler->object_ = obj;
+
+ CefV8ValueList args;
+ args.push_back(CefV8Value::CreateInt(kVal1));
+ args.push_back(CefV8Value::CreateInt(kVal2));
+
+ CefRefPtr<CefV8Value> retval = func->ExecuteFunction(obj, args);
+ EXPECT_TRUE(handler->got_execute_);
+ EXPECT_TRUE(retval.get());
+ EXPECT_FALSE(func->HasException());
+ EXPECT_TRUE(retval->IsInt());
+ EXPECT_EQ(kRetVal, retval->GetIntValue());
+
+ handler->object_ = nullptr;
+
+ // Exit the V8 context.
+ EXPECT_TRUE(context->Exit());
+
+ DestroyTest();
+ }
+
+ void RunFunctionHandlerExceptionTest() {
+ CefRefPtr<CefV8Context> context = GetContext();
+
+ static const char* kException = "My error";
+ static const char* kExceptionMsg = "Uncaught Error: My error";
+
+ class Handler : public CefV8Handler {
+ public:
+ Handler() {}
+ bool Execute(const CefString& name,
+ CefRefPtr<CefV8Value> object,
+ const CefV8ValueList& arguments,
+ CefRefPtr<CefV8Value>& retval,
+ CefString& exception) override {
+ exception = kException;
+ got_execute_.yes();
+ return true;
+ }
+
+ TrackCallback got_execute_;
+
+ IMPLEMENT_REFCOUNTING(Handler);
+ };
+
+ // Enter the V8 context.
+ EXPECT_TRUE(context->Enter());
+
+ Handler* handler = new Handler;
+ CefRefPtr<CefV8Handler> handlerPtr(handler);
+
+ CefRefPtr<CefV8Value> func = CefV8Value::CreateFunction("myfunc", handler);
+ EXPECT_TRUE(func.get());
+
+ CefV8ValueList args;
+
+ CefRefPtr<CefV8Value> retval = func->ExecuteFunction(nullptr, args);
+ EXPECT_TRUE(handler->got_execute_);
+ EXPECT_FALSE(retval.get());
+ EXPECT_TRUE(func->HasException());
+ CefRefPtr<CefV8Exception> exception = func->GetException();
+ EXPECT_TRUE(exception.get());
+ EXPECT_STREQ(kExceptionMsg, exception->GetMessage().ToString().c_str());
+
+ // Exit the V8 context.
+ EXPECT_TRUE(context->Exit());
+
+ DestroyTest();
+ }
+
+ void RunFunctionHandlerFailTest() {
+ CefRefPtr<CefV8Context> context = GetContext();
+
+ class Handler : public CefV8Handler {
+ public:
+ Handler() {}
+ bool Execute(const CefString& name,
+ CefRefPtr<CefV8Value> object,
+ const CefV8ValueList& arguments,
+ CefRefPtr<CefV8Value>& retval,
+ CefString& exception) override {
+ got_execute_.yes();
+ return false;
+ }
+
+ TrackCallback got_execute_;
+
+ IMPLEMENT_REFCOUNTING(Handler);
+ };
+
+ // Enter the V8 context.
+ EXPECT_TRUE(context->Enter());
+
+ Handler* handler = new Handler;
+ CefRefPtr<CefV8Handler> handlerPtr(handler);
+
+ CefRefPtr<CefV8Value> func = CefV8Value::CreateFunction("myfunc", handler);
+ EXPECT_TRUE(func.get());
+
+ CefV8ValueList args;
+
+ CefRefPtr<CefV8Value> retval = func->ExecuteFunction(nullptr, args);
+ EXPECT_TRUE(handler->got_execute_);
+ EXPECT_TRUE(retval.get());
+ EXPECT_FALSE(func->HasException());
+ EXPECT_TRUE(retval->IsUndefined());
+
+ // Exit the V8 context.
+ EXPECT_TRUE(context->Exit());
+
+ DestroyTest();
+ }
+
+ void RunFunctionHandlerNoObjectTest() {
+ CefRefPtr<CefV8Context> context = GetContext();
+
+ class Handler : public CefV8Handler {
+ public:
+ Handler() {}
+ bool Execute(const CefString& name,
+ CefRefPtr<CefV8Value> object,
+ const CefV8ValueList& arguments,
+ CefRefPtr<CefV8Value>& retval,
+ CefString& exception) override {
+ EXPECT_TRUE(object.get());
+ CefRefPtr<CefV8Context> context = CefV8Context::GetCurrentContext();
+ EXPECT_TRUE(context.get());
+ CefRefPtr<CefV8Value> global = context->GetGlobal();
+ EXPECT_TRUE(global.get());
+ EXPECT_TRUE(global->IsSame(object));
+
+ got_execute_.yes();
+ return true;
+ }
+
+ TrackCallback got_execute_;
+
+ IMPLEMENT_REFCOUNTING(Handler);
+ };
+
+ // Enter the V8 context.
+ EXPECT_TRUE(context->Enter());
+
+ Handler* handler = new Handler;
+ CefRefPtr<CefV8Handler> handlerPtr(handler);
+
+ CefRefPtr<CefV8Value> func = CefV8Value::CreateFunction("myfunc", handler);
+ EXPECT_TRUE(func.get());
+
+ CefV8ValueList args;
+
+ CefRefPtr<CefV8Value> retval = func->ExecuteFunction(nullptr, args);
+ EXPECT_TRUE(handler->got_execute_);
+ EXPECT_TRUE(retval.get());
+ EXPECT_FALSE(func->HasException());
+
+ // Exit the V8 context.
+ EXPECT_TRUE(context->Exit());
+
+ DestroyTest();
+ }
+
+ void RunFunctionHandlerWithContextTest() {
+ CefRefPtr<CefV8Context> context = GetContext();
+
+ class Handler : public CefV8Handler {
+ public:
+ Handler() {}
+ bool Execute(const CefString& name,
+ CefRefPtr<CefV8Value> object,
+ const CefV8ValueList& arguments,
+ CefRefPtr<CefV8Value>& retval,
+ CefString& exception) override {
+ CefRefPtr<CefV8Context> context = CefV8Context::GetCurrentContext();
+ EXPECT_TRUE(context.get());
+ EXPECT_TRUE(context->IsSame(context_));
+ got_execute_.yes();
+ return true;
+ }
+
+ CefRefPtr<CefV8Context> context_;
+ TrackCallback got_execute_;
+
+ IMPLEMENT_REFCOUNTING(Handler);
+ };
+
+ // Enter the V8 context.
+ EXPECT_TRUE(context->Enter());
+
+ Handler* handler = new Handler;
+ CefRefPtr<CefV8Handler> handlerPtr(handler);
+ handler->context_ = context;
+
+ CefRefPtr<CefV8Value> func = CefV8Value::CreateFunction("myfunc", handler);
+ EXPECT_TRUE(func.get());
+
+ // Exit the V8 context.
+ EXPECT_TRUE(context->Exit());
+
+ CefV8ValueList args;
+
+ CefRefPtr<CefV8Value> retval =
+ func->ExecuteFunctionWithContext(context, nullptr, args);
+ EXPECT_TRUE(handler->got_execute_);
+ EXPECT_TRUE(retval.get());
+ EXPECT_FALSE(func->HasException());
+
+ handler->context_ = nullptr;
+
+ DestroyTest();
+ }
+
+ void RunFunctionHandlerEmptyStringTest() {
+ CefRefPtr<CefV8Context> context = GetContext();
+
+ class Handler : public CefV8Handler {
+ public:
+ Handler() {}
+ bool Execute(const CefString& name,
+ CefRefPtr<CefV8Value> object,
+ const CefV8ValueList& arguments,
+ CefRefPtr<CefV8Value>& retval,
+ CefString& exception) override {
+ EXPECT_TRUE(object.get());
+ CefRefPtr<CefV8Context> context = CefV8Context::GetCurrentContext();
+ EXPECT_TRUE(context.get());
+ CefRefPtr<CefV8Value> global = context->GetGlobal();
+ EXPECT_TRUE(global.get());
+ EXPECT_TRUE(global->IsSame(object));
+
+ EXPECT_EQ((size_t)1, arguments.size());
+ EXPECT_TRUE(arguments[0]->IsString());
+ EXPECT_STREQ("", arguments[0]->GetStringValue().ToString().c_str());
+
+ retval = CefV8Value::CreateString(CefString());
+
+ got_execute_.yes();
+ return true;
+ }
+
+ TrackCallback got_execute_;
+
+ IMPLEMENT_REFCOUNTING(Handler);
+ };
+
+ // Enter the V8 context.
+ EXPECT_TRUE(context->Enter());
+
+ Handler* handler = new Handler;
+ CefRefPtr<CefV8Handler> handlerPtr(handler);
+
+ CefRefPtr<CefV8Value> func = CefV8Value::CreateFunction("myfunc", handler);
+ EXPECT_TRUE(func.get());
+
+ CefV8ValueList args;
+ args.push_back(CefV8Value::CreateString(CefString()));
+
+ CefRefPtr<CefV8Value> retval = func->ExecuteFunction(nullptr, args);
+ EXPECT_TRUE(handler->got_execute_);
+ EXPECT_TRUE(retval.get());
+ EXPECT_FALSE(func->HasException());
+
+ EXPECT_TRUE(retval->IsString());
+ EXPECT_STREQ("", retval->GetStringValue().ToString().c_str());
+
+ // Exit the V8 context.
+ EXPECT_TRUE(context->Exit());
+
+ DestroyTest();
+ }
+
+ void RunPromiseCreateTest() {
+ CefRefPtr<CefV8Context> context = GetContext();
+
+ // Enter the V8 context.
+ EXPECT_TRUE(context->Enter());
+
+ CefRefPtr<CefV8Value> value = CefV8Value::CreatePromise();
+
+ // Exit the V8 context.
+ EXPECT_TRUE(context->Exit());
+
+ EXPECT_TRUE(value.get());
+ EXPECT_TRUE(value->IsPromise());
+ EXPECT_TRUE(value->IsObject());
+
+ EXPECT_FALSE(value->IsUndefined());
+ EXPECT_FALSE(value->IsArray());
+ EXPECT_FALSE(value->IsBool());
+ EXPECT_FALSE(value->IsDate());
+ EXPECT_FALSE(value->IsDouble());
+ EXPECT_FALSE(value->IsFunction());
+ EXPECT_FALSE(value->IsInt());
+ EXPECT_FALSE(value->IsUInt());
+ EXPECT_FALSE(value->IsNull());
+ EXPECT_FALSE(value->IsString());
+
+ DestroyTest();
+ }
+
+ void RunPromiseResolveTest() {
+ CefRefPtr<CefV8Context> context = GetContext();
+
+ // Enter the V8 context.
+ EXPECT_TRUE(context->Enter());
+
+ CefRefPtr<CefV8Value> value = CefV8Value::CreatePromise();
+ CefRefPtr<CefV8Value> obj = CefV8Value::CreateObject(nullptr, nullptr);
+
+ EXPECT_TRUE(value.get());
+ EXPECT_TRUE(value->ResolvePromise(obj));
+
+ // Exit the V8 context.
+ EXPECT_TRUE(context->Exit());
+
+ DestroyTest();
+ }
+
+ void RunPromiseResolveNoArgumentTest() {
+ CefRefPtr<CefV8Context> context = GetContext();
+
+ // Enter the V8 context.
+ EXPECT_TRUE(context->Enter());
+
+ CefRefPtr<CefV8Value> value = CefV8Value::CreatePromise();
+
+ EXPECT_TRUE(value.get());
+ EXPECT_TRUE(value->ResolvePromise(nullptr));
+
+ // Exit the V8 context.
+ EXPECT_TRUE(context->Exit());
+
+ DestroyTest();
+ }
+
+ void RunPromiseResolveHandlerTest() {
+ CefRefPtr<CefV8Context> context = GetContext();
+
+ static const char* kPromiseName = "myprom";
+ static const char* kResolveName = "myresolve";
+ static const char* kRejectName = "myreject";
+ static const int kVal1 = 32;
+
+ class Handler : public CefV8Handler {
+ public:
+ Handler() {}
+ bool Execute(const CefString& name,
+ CefRefPtr<CefV8Value> object,
+ const CefV8ValueList& arguments,
+ CefRefPtr<CefV8Value>& retval,
+ CefString& exception) override {
+ EXPECT_STREQ(kResolveName, name.ToString().c_str());
+ EXPECT_EQ((size_t)1, arguments.size());
+ EXPECT_TRUE(arguments[0]->IsInt());
+ EXPECT_EQ(kVal1, arguments[0]->GetIntValue());
+
+ got_execute_.yes();
+
+ return false;
+ }
+
+ TrackCallback got_execute_;
+
+ IMPLEMENT_REFCOUNTING(Handler);
+ };
+
+ // Enter the V8 context.
+ EXPECT_TRUE(context->Enter());
+
+ Handler* resolveHandler = new Handler;
+ Handler* rejectHandler = new Handler;
+
+ CefRefPtr<CefV8Handler> resolveHandlerPtr(resolveHandler);
+ CefRefPtr<CefV8Handler> rejectHandlerPtr(rejectHandler);
+
+ CefRefPtr<CefV8Value> resolveFunc =
+ CefV8Value::CreateFunction(kResolveName, resolveHandler);
+ EXPECT_TRUE(resolveFunc.get());
+ EXPECT_TRUE(context->GetGlobal()->SetValue(kResolveName, resolveFunc,
+ V8_PROPERTY_ATTRIBUTE_NONE));
+
+ CefRefPtr<CefV8Value> rejectFunc =
+ CefV8Value::CreateFunction(kRejectName, rejectHandler);
+ EXPECT_TRUE(rejectFunc.get());
+ EXPECT_TRUE(context->GetGlobal()->SetValue(kRejectName, rejectFunc,
+ V8_PROPERTY_ATTRIBUTE_NONE));
+
+ CefRefPtr<CefV8Value> value = CefV8Value::CreatePromise();
+
+ EXPECT_TRUE(value.get());
+ EXPECT_TRUE(context->GetGlobal()->SetValue(kPromiseName, value,
+ V8_PROPERTY_ATTRIBUTE_NONE));
+
+ CefRefPtr<CefV8Value> retval;
+ CefRefPtr<CefV8Exception> exception;
+
+ std::stringstream test;
+ test << "window." << kPromiseName << ".then(" << kResolveName << ").catch("
+ << kRejectName << ")";
+
+ EXPECT_TRUE(context->Eval(test.str(), CefString(), 0, retval, exception));
+ EXPECT_TRUE(retval.get());
+ EXPECT_TRUE(retval->IsPromise());
+ EXPECT_FALSE(exception.get());
+
+ CefRefPtr<CefV8Value> arg = CefV8Value::CreateInt(kVal1);
+ EXPECT_TRUE(value->ResolvePromise(arg));
+
+ // Exit the V8 context.
+ EXPECT_TRUE(context->Exit());
+
+ EXPECT_TRUE(resolveHandler->got_execute_);
+ EXPECT_FALSE(rejectHandler->got_execute_);
+
+ DestroyTest();
+ }
+
+ void RunPromiseRejectTest() {
+ CefRefPtr<CefV8Context> context = GetContext();
+
+ // Enter the V8 context.
+ EXPECT_TRUE(context->Enter());
+
+ CefRefPtr<CefV8Value> value = CefV8Value::CreatePromise();
+
+ EXPECT_TRUE(value.get());
+ EXPECT_TRUE(value->RejectPromise("Error: Unknown"));
+
+ // Exit the V8 context.
+ EXPECT_TRUE(context->Exit());
+
+ DestroyTest();
+ }
+
+ void RunPromiseRejectHandlerTest() {
+ CefRefPtr<CefV8Context> context = GetContext();
+
+ static const char* kPromiseName = "myprom";
+ static const char* kResolveName = "myresolve";
+ static const char* kRejectName = "myreject";
+
+ class Handler : public CefV8Handler {
+ public:
+ Handler() {}
+ bool Execute(const CefString& name,
+ CefRefPtr<CefV8Value> object,
+ const CefV8ValueList& arguments,
+ CefRefPtr<CefV8Value>& retval,
+ CefString& exception) override {
+ EXPECT_STREQ(kRejectName, name.ToString().c_str());
+ EXPECT_EQ((size_t)1, arguments.size());
+ EXPECT_TRUE(arguments[0]->IsObject());
+
+ got_execute_.yes();
+
+ return false;
+ }
+
+ TrackCallback got_execute_;
+
+ IMPLEMENT_REFCOUNTING(Handler);
+ };
+
+ // Enter the V8 context.
+ EXPECT_TRUE(context->Enter());
+
+ Handler* resolveHandler = new Handler;
+ Handler* rejectHandler = new Handler;
+
+ CefRefPtr<CefV8Handler> resolveHandlerPtr(resolveHandler);
+ CefRefPtr<CefV8Handler> rejectHandlerPtr(rejectHandler);
+
+ CefRefPtr<CefV8Value> resolveFunc =
+ CefV8Value::CreateFunction(kResolveName, resolveHandler);
+ EXPECT_TRUE(resolveFunc.get());
+ EXPECT_TRUE(context->GetGlobal()->SetValue(kResolveName, resolveFunc,
+ V8_PROPERTY_ATTRIBUTE_NONE));
+
+ CefRefPtr<CefV8Value> rejectFunc =
+ CefV8Value::CreateFunction(kRejectName, rejectHandler);
+ EXPECT_TRUE(rejectFunc.get());
+ EXPECT_TRUE(context->GetGlobal()->SetValue(kRejectName, rejectFunc,
+ V8_PROPERTY_ATTRIBUTE_NONE));
+
+ CefRefPtr<CefV8Value> value = CefV8Value::CreatePromise();
+
+ EXPECT_TRUE(value.get());
+ EXPECT_TRUE(context->GetGlobal()->SetValue(kPromiseName, value,
+ V8_PROPERTY_ATTRIBUTE_NONE));
+
+ CefRefPtr<CefV8Value> retval;
+ CefRefPtr<CefV8Exception> exception;
+
+ std::stringstream test;
+ test << "window." << kPromiseName << ".then(" << kResolveName << ").catch("
+ << kRejectName << ")";
+
+ EXPECT_TRUE(context->Eval(test.str(), CefString(), 0, retval, exception));
+ EXPECT_TRUE(retval.get());
+ EXPECT_TRUE(retval->IsPromise());
+ EXPECT_FALSE(exception.get());
+
+ EXPECT_TRUE(value->RejectPromise("Error: Unknown"));
+
+ // Exit the V8 context.
+ EXPECT_TRUE(context->Exit());
+
+ EXPECT_FALSE(resolveHandler->got_execute_);
+ EXPECT_TRUE(rejectHandler->got_execute_);
+
+ DestroyTest();
+ }
+
+ void RunContextEvalTest() {
+ CefRefPtr<CefV8Context> context = GetContext();
+
+ CefRefPtr<CefV8Value> retval;
+ CefRefPtr<CefV8Exception> exception;
+
+ EXPECT_TRUE(context->Eval("1+2", CefString(), 0, retval, exception));
+ EXPECT_TRUE(retval.get());
+ EXPECT_TRUE(retval->IsInt());
+ EXPECT_EQ(3, retval->GetIntValue());
+ EXPECT_FALSE(exception.get());
+
+ DestroyTest();
+ }
+
+ void RunContextEvalExceptionTest() {
+ CefRefPtr<CefV8Context> context = GetContext();
+
+ CefRefPtr<CefV8Value> retval;
+ CefRefPtr<CefV8Exception> exception;
+
+ EXPECT_FALSE(
+ context->Eval("\n\n\n1+foo", CefString(), 0, retval, exception));
+ EXPECT_FALSE(retval.get());
+ EXPECT_TRUE(exception.get());
+ EXPECT_EQ(4, exception->GetLineNumber());
+
+ DestroyTest();
+ }
+
+ void RunContextEvalCspBypassUnsafeEval() {
+ CefRefPtr<CefV8Context> context = GetContext();
+
+ CefRefPtr<CefV8Value> retval;
+ CefRefPtr<CefV8Exception> exception;
+
+ bool success =
+ context->Eval("(document.getElementById('result').innerHTML)",
+ CefString(), 0, retval, exception);
+ if (exception.get()) {
+ ADD_FAILURE() << exception->GetMessage().c_str();
+ EXPECT_FALSE(success);
+ }
+
+ EXPECT_TRUE(success);
+ EXPECT_TRUE(retval.get());
+ if (retval.get()) {
+ EXPECT_TRUE(retval->IsString());
+ EXPECT_EQ(CefString("CSP_BYPASSED"), retval->GetStringValue());
+ }
+
+ DestroyTest();
+ }
+
+ void RunContextEvalCspBypassSandbox() {
+ CefRefPtr<CefV8Context> context = GetContext();
+
+ CefRefPtr<CefV8Value> retval;
+ CefRefPtr<CefV8Exception> exception;
+
+ bool success =
+ context->Eval("(document.getElementById('result').innerHTML)",
+ CefString(), 0, retval, exception);
+ if (exception.get()) {
+ ADD_FAILURE() << exception->GetMessage().c_str();
+ EXPECT_FALSE(success);
+ }
+
+ EXPECT_TRUE(success);
+ EXPECT_TRUE(retval.get());
+ if (retval.get()) {
+ EXPECT_TRUE(retval->IsString());
+ EXPECT_EQ(CefString("CSP_BYPASSED"), retval->GetStringValue());
+ }
+
+ DestroyTest();
+ }
+
+ void RunContextEnteredTest() {
+ CefRefPtr<CefV8Context> context = GetContext();
+
+ CefRefPtr<CefV8Value> retval;
+ CefRefPtr<CefV8Exception> exception;
+
+ // Test value defined in OnContextCreated
+ EXPECT_TRUE(context->Eval(
+ "document.getElementById('f').contentWindow.v8_context_entered_test()",
+ CefString(), 0, retval, exception));
+ if (exception.get()) {
+ ADD_FAILURE() << exception->GetMessage().c_str();
+ }
+
+ EXPECT_TRUE(retval.get());
+ EXPECT_TRUE(retval->IsInt());
+ EXPECT_EQ(21, retval->GetIntValue());
+
+ DestroyTest();
+ }
+
+ void RunBindingTest() {
+ CefRefPtr<CefV8Context> context = GetContext();
+
+ // Enter the V8 context.
+ EXPECT_TRUE(context->Enter());
+
+ CefRefPtr<CefV8Value> object = context->GetGlobal();
+ EXPECT_TRUE(object.get());
+
+ // Test value defined in OnContextCreated
+ CefRefPtr<CefV8Value> value = object->GetValue("v8_binding_test");
+ EXPECT_TRUE(value.get());
+ EXPECT_TRUE(value->IsInt());
+ EXPECT_EQ(12, value->GetIntValue());
+
+ // Exit the V8 context.
+ EXPECT_TRUE(context->Exit());
+
+ DestroyTest();
+ }
+
+ void RunStackTraceTest() {
+ CefRefPtr<CefV8Context> context = GetContext();
+
+ static const char* kFuncName = "myfunc";
+
+ class Handler : public CefV8Handler {
+ public:
+ Handler() {}
+ bool Execute(const CefString& name,
+ CefRefPtr<CefV8Value> object,
+ const CefV8ValueList& arguments,
+ CefRefPtr<CefV8Value>& retval,
+ CefString& exception) override {
+ EXPECT_STREQ(kFuncName, name.ToString().c_str());
+
+ stack_trace_ = CefV8StackTrace::GetCurrent(10);
+
+ retval = CefV8Value::CreateInt(3);
+ got_execute_.yes();
+ return true;
+ }
+
+ TrackCallback got_execute_;
+ CefRefPtr<CefV8StackTrace> stack_trace_;
+
+ IMPLEMENT_REFCOUNTING(Handler);
+ };
+
+ // Enter the V8 context.
+ EXPECT_TRUE(context->Enter());
+
+ Handler* handler = new Handler;
+ CefRefPtr<CefV8Handler> handlerPtr(handler);
+
+ CefRefPtr<CefV8Value> func = CefV8Value::CreateFunction(kFuncName, handler);
+ EXPECT_TRUE(func.get());
+ CefRefPtr<CefV8Value> obj = context->GetGlobal();
+ EXPECT_TRUE(obj.get());
+ obj->SetValue(kFuncName, func, V8_PROPERTY_ATTRIBUTE_NONE);
+
+ CefRefPtr<CefV8Value> retval;
+ CefRefPtr<CefV8Exception> exception;
+
+ EXPECT_TRUE(
+ context->Eval("function jsfunc() { return window.myfunc(); }\n"
+ "jsfunc();",
+ CefString(), 0, retval, exception));
+ EXPECT_TRUE(retval.get());
+ EXPECT_TRUE(retval->IsInt());
+ EXPECT_EQ(3, retval->GetIntValue());
+ EXPECT_FALSE(exception.get());
+
+ EXPECT_TRUE(handler->stack_trace_.get());
+ EXPECT_EQ(2, handler->stack_trace_->GetFrameCount());
+
+ CefRefPtr<CefV8StackFrame> frame;
+
+ frame = handler->stack_trace_->GetFrame(0);
+ EXPECT_TRUE(frame->GetScriptName().empty());
+ EXPECT_TRUE(frame->GetScriptNameOrSourceURL().empty());
+ EXPECT_STREQ("jsfunc", frame->GetFunctionName().ToString().c_str());
+ EXPECT_EQ(1, frame->GetLineNumber());
+ EXPECT_EQ(35, frame->GetColumn());
+ EXPECT_TRUE(frame.get());
+ EXPECT_FALSE(frame->IsEval());
+ EXPECT_FALSE(frame->IsConstructor());
+
+ frame = handler->stack_trace_->GetFrame(1);
+ EXPECT_TRUE(frame->GetScriptName().empty());
+ EXPECT_TRUE(frame->GetScriptNameOrSourceURL().empty());
+ EXPECT_TRUE(frame->GetFunctionName().empty());
+ EXPECT_EQ(2, frame->GetLineNumber());
+ EXPECT_EQ(1, frame->GetColumn());
+ EXPECT_TRUE(frame.get());
+ EXPECT_FALSE(frame->IsEval());
+ EXPECT_FALSE(frame->IsConstructor());
+
+ // Exit the V8 context.
+ EXPECT_TRUE(context->Exit());
+
+ DestroyTest();
+ }
+
+ void RunOnUncaughtExceptionTest() {
+ test_context_ = browser_->GetMainFrame()->GetV8Context();
+ browser_->GetMainFrame()->ExecuteJavaScript(
+ "window.setTimeout(test, 0)", browser_->GetMainFrame()->GetURL(), 0);
+ }
+
+ // Test execution of a native function when the extension is loaded.
+ void RunExtensionTest() {
+ std::string code =
+ "native function v8_extension_test();"
+ "v8_extension_test();";
+
+ class Handler : public CefV8Handler {
+ public:
+ Handler(TrackCallback* callback) : callback_(callback) {}
+
+ bool Execute(const CefString& name,
+ CefRefPtr<CefV8Value> object,
+ const CefV8ValueList& arguments,
+ CefRefPtr<CefV8Value>& retval,
+ CefString& exception) override {
+ EXPECT_STREQ("v8_extension_test", name.ToString().c_str());
+ callback_->yes();
+ return true;
+ }
+
+ TrackCallback* callback_;
+
+ IMPLEMENT_REFCOUNTING(Handler);
+ };
+
+ CefRegisterExtension("v8/test-extension", code,
+ new Handler(&startup_test_success_));
+ }
+
+ void OnBrowserCreated(CefRefPtr<ClientAppRenderer> app,
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefDictionaryValue> extra_info) override {
+ if (extra_info && extra_info->HasKey(kV8TestCmdKey)) {
+ test_mode_ = static_cast<V8TestMode>(extra_info->GetInt(kV8TestCmdKey));
+ }
+ if (test_mode_ > V8TEST_NONE) {
+ RunStartupTest();
+ }
+ if (test_mode_ == V8TEST_CONTEXT_EVAL_CSP_BYPASS_UNSAFE_EVAL ||
+ test_mode_ == V8TEST_CONTEXT_EVAL_CSP_BYPASS_SANDBOX) {
+ browser_ = browser;
+ }
+ }
+
+ CefRefPtr<CefLoadHandler> GetLoadHandler(
+ CefRefPtr<ClientAppRenderer> app) override {
+ if (test_mode_ == V8TEST_NONE) {
+ return nullptr;
+ }
+
+ return this;
+ }
+
+ void OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int httpStatusCode) override {
+ if (test_mode_ == V8TEST_ON_UNCAUGHT_EXCEPTION_DEV_TOOLS &&
+ browser->IsPopup()) {
+ DevToolsLoadHook(browser);
+ }
+ }
+
+ void OnContextCreated(CefRefPtr<ClientAppRenderer> app,
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefV8Context> context) override {
+ if (test_mode_ == V8TEST_NONE) {
+ return;
+ }
+
+ if (test_mode_ == V8TEST_ON_UNCAUGHT_EXCEPTION_DEV_TOOLS) {
+ if (!browser->IsPopup()) {
+ app_ = app;
+ browser_ = browser;
+ test_context_ = context;
+ }
+ return;
+ }
+
+ app_ = app;
+ browser_ = browser;
+
+ std::string url = frame->GetURL();
+ if (url == kV8ContextChildTestUrl) {
+ // For V8TEST_CONTEXT_ENTERED
+ class Handler : public CefV8Handler {
+ public:
+ Handler() {}
+ bool Execute(const CefString& name,
+ CefRefPtr<CefV8Value> object,
+ const CefV8ValueList& arguments,
+ CefRefPtr<CefV8Value>& retval,
+ CefString& exception) override {
+ // context for the sub-frame
+ CefRefPtr<CefV8Context> context = CefV8Context::GetCurrentContext();
+ EXPECT_TRUE(context.get());
+
+ // entered context should be the same as the main frame context
+ CefRefPtr<CefV8Context> entered = CefV8Context::GetEnteredContext();
+ EXPECT_TRUE(entered.get());
+ EXPECT_TRUE(entered->IsSame(context_));
+
+ context_ = nullptr;
+ retval = CefV8Value::CreateInt(21);
+ return true;
+ }
+
+ CefRefPtr<CefV8Context> context_;
+ IMPLEMENT_REFCOUNTING(Handler);
+ };
+
+ Handler* handler = new Handler;
+ CefRefPtr<CefV8Handler> handlerPtr(handler);
+
+ // main frame context
+ handler->context_ = GetContext();
+
+ // Function that will be called from the parent frame context.
+ CefRefPtr<CefV8Value> func =
+ CefV8Value::CreateFunction("v8_context_entered_test", handler);
+ EXPECT_TRUE(func.get());
+
+ CefRefPtr<CefV8Value> object = context->GetGlobal();
+ EXPECT_TRUE(object.get());
+ EXPECT_TRUE(object->SetValue("v8_context_entered_test", func,
+ V8_PROPERTY_ATTRIBUTE_NONE));
+ } else if (url == kV8ContextParentTestUrl) {
+ // For V8TEST_CONTEXT_ENTERED. Do nothing.
+ return;
+ } else if (url == kV8BindingTestUrl) {
+ // For V8TEST_BINDING
+ CefRefPtr<CefV8Value> object = context->GetGlobal();
+ EXPECT_TRUE(object.get());
+ EXPECT_TRUE(object->SetValue("v8_binding_test", CefV8Value::CreateInt(12),
+ V8_PROPERTY_ATTRIBUTE_NONE));
+ } else if (url == kV8HandlerCallOnReleasedContextUrl) {
+ // For V8TEST_HANDLER_CALL_ON_RELEASED_CONTEXT
+ class Handler : public CefV8Handler {
+ public:
+ Handler(CefRefPtr<V8RendererTest> renderer_test)
+ : renderer_test_(renderer_test) {}
+
+ bool Execute(const CefString& name,
+ CefRefPtr<CefV8Value> object,
+ const CefV8ValueList& arguments,
+ CefRefPtr<CefV8Value>& retval,
+ CefString& exception) override {
+ if (name == "notify_test_done") {
+ CefPostDelayedTask(TID_RENDERER,
+ base::BindOnce(&V8RendererTest::DestroyTest,
+ renderer_test_.get()),
+ 1000);
+ return true;
+ }
+
+ return false;
+ }
+
+ private:
+ CefRefPtr<V8RendererTest> renderer_test_;
+ IMPLEMENT_REFCOUNTING(Handler);
+ };
+
+ Handler* handler = new Handler(this);
+ CefRefPtr<CefV8Handler> handlerPtr(handler);
+
+ // Function that will be called from the parent frame context.
+ CefRefPtr<CefV8Value> func =
+ CefV8Value::CreateFunction("notify_test_done", handler);
+ EXPECT_TRUE(func.get());
+
+ CefRefPtr<CefV8Value> object = context->GetGlobal();
+ EXPECT_TRUE(object.get());
+ EXPECT_TRUE(object->SetValue("notify_test_done", func,
+ V8_PROPERTY_ATTRIBUTE_NONE));
+ } else if (url == kV8HandlerCallOnReleasedContextChildUrl) {
+ // For V8TEST_HANDLER_CALL_ON_RELEASED_CONTEXT
+ class Handler : public CefV8Handler {
+ public:
+ Handler() {}
+ bool Execute(const CefString& name,
+ CefRefPtr<CefV8Value> object,
+ const CefV8ValueList& arguments,
+ CefRefPtr<CefV8Value>& retval,
+ CefString& exception) override {
+ if (name == "v8_context_is_alive") {
+ retval = CefV8Value::CreateBool(true);
+ return true;
+ }
+
+ return false;
+ }
+
+ IMPLEMENT_REFCOUNTING(Handler);
+ };
+
+ Handler* handler = new Handler;
+ CefRefPtr<CefV8Handler> handlerPtr(handler);
+
+ // Function that will be called from the parent frame context.
+ CefRefPtr<CefV8Value> func =
+ CefV8Value::CreateFunction("v8_context_is_alive", handler);
+ EXPECT_TRUE(func.get());
+
+ CefRefPtr<CefV8Value> object = context->GetGlobal();
+ EXPECT_TRUE(object.get());
+ EXPECT_TRUE(object->SetValue("v8_context_is_alive", func,
+ V8_PROPERTY_ATTRIBUTE_NONE));
+ }
+ }
+
+ void OnUncaughtException(CefRefPtr<ClientAppRenderer> app,
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefV8Context> context,
+ CefRefPtr<CefV8Exception> exception,
+ CefRefPtr<CefV8StackTrace> stackTrace) override {
+ if (test_mode_ == V8TEST_NONE) {
+ return;
+ }
+
+ if (test_mode_ == V8TEST_ON_UNCAUGHT_EXCEPTION ||
+ test_mode_ == V8TEST_ON_UNCAUGHT_EXCEPTION_DEV_TOOLS) {
+ EXPECT_TRUE(test_context_->IsSame(context));
+ EXPECT_STREQ("Uncaught ReferenceError: asd is not defined",
+ exception->GetMessage().ToString().c_str());
+ std::ostringstream stackFormatted;
+ for (int i = 0; i < stackTrace->GetFrameCount(); ++i) {
+ stackFormatted << "at "
+ << stackTrace->GetFrame(i)->GetFunctionName().ToString()
+ << "() in "
+ << stackTrace->GetFrame(i)->GetScriptName().ToString()
+ << " on line "
+ << stackTrace->GetFrame(i)->GetLineNumber() << "\n";
+ }
+ const char* stackFormattedShouldBe =
+ "at test2() in http://tests/V8Test.OnUncaughtException on line 3\n"
+ "at test() in http://tests/V8Test.OnUncaughtException on line 2\n";
+ EXPECT_STREQ(stackFormattedShouldBe, stackFormatted.str().c_str());
+ DestroyTest();
+ }
+ }
+
+ bool OnProcessMessageReceived(CefRefPtr<ClientAppRenderer> app,
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefProcessId source_process,
+ CefRefPtr<CefProcessMessage> message) override {
+ if (test_mode_ == V8TEST_NONE) {
+ return false;
+ }
+
+ const std::string& message_name = message->GetName();
+ if (message_name == kV8RunTestMsg) {
+ // Run the test asynchronously.
+ CefPostTask(TID_RENDERER, base::BindOnce(&V8RendererTest::RunTest, this));
+ return true;
+ }
+ return false;
+ }
+
+ void DevToolsLoadHook(CefRefPtr<CefBrowser> browser) {
+ EXPECT_TRUE(browser->IsPopup());
+ CefRefPtr<CefFrame> frame = browser->GetMainFrame();
+ CefRefPtr<CefV8Context> context = frame->GetV8Context();
+ static const char* kFuncName = "DevToolsLoaded";
+
+ class Handler : public CefV8Handler {
+ public:
+ Handler() {}
+ bool Execute(const CefString& name,
+ CefRefPtr<CefV8Value> object,
+ const CefV8ValueList& arguments,
+ CefRefPtr<CefV8Value>& retval,
+ CefString& exception) override {
+ EXPECT_STREQ(kFuncName, name.ToString().c_str());
+ if (name == kFuncName) {
+ EXPECT_TRUE(exception.empty());
+ retval = CefV8Value::CreateNull();
+ EXPECT_TRUE(retval.get());
+ renderer_test_->DevToolsLoaded(browser_);
+ return true;
+ }
+ return false;
+ }
+ CefRefPtr<V8RendererTest> renderer_test_;
+ CefRefPtr<CefBrowser> browser_;
+ IMPLEMENT_REFCOUNTING(Handler);
+ };
+
+ EXPECT_TRUE(context->Enter());
+ Handler* handler = new Handler;
+ handler->renderer_test_ = this;
+ handler->browser_ = browser;
+ CefRefPtr<CefV8Handler> handlerPtr(handler);
+ CefRefPtr<CefV8Value> func = CefV8Value::CreateFunction(kFuncName, handler);
+ EXPECT_TRUE(func.get());
+ EXPECT_TRUE(context->GetGlobal()->SetValue(kFuncName, func,
+ V8_PROPERTY_ATTRIBUTE_NONE));
+ EXPECT_TRUE(context->Exit());
+
+ // Dismiss the DevTools window after 500ms. It would be better to hook the
+ // DevTools JS to receive notification of when loading is complete but that
+ // is no longer possible.
+ CefPostDelayedTask(
+ TID_RENDERER,
+ base::BindOnce(&CefFrame::ExecuteJavaScript, frame.get(),
+ "window.DevToolsLoaded()", frame->GetURL(), 0),
+ 500);
+ }
+
+ void DevToolsLoaded(CefRefPtr<CefBrowser> browser) {
+ EXPECT_TRUE(browser->IsPopup());
+ // |browser_| will be nullptr if the DevTools window is opened in a separate
+ // render process.
+ const int other_browser_id =
+ (browser_.get() ? browser_->GetIdentifier() : -1);
+ EXPECT_NE(browser->GetIdentifier(), other_browser_id);
+
+ // Close the DevTools window. This will trigger OnBeforeClose in the browser
+ // process.
+ CefRefPtr<CefV8Value> retval;
+ CefRefPtr<CefV8Exception> exception;
+ EXPECT_TRUE(browser->GetMainFrame()->GetV8Context()->Eval(
+ "window.close()", CefString(), 0, retval, exception));
+ }
+
+ protected:
+ // Return from the test.
+ void DestroyTest() {
+ EXPECT_TRUE(CefCurrentlyOn(TID_RENDERER));
+
+ // Check if the test has failed.
+ bool result = !TestFailed();
+
+ // Return the result to the browser process.
+ CefRefPtr<CefProcessMessage> return_msg =
+ CefProcessMessage::Create(kV8TestMsg);
+ EXPECT_TRUE(return_msg->GetArgumentList()->SetBool(0, result));
+ browser_->GetMainFrame()->SendProcessMessage(PID_BROWSER, return_msg);
+
+ app_ = nullptr;
+ browser_ = nullptr;
+ test_context_ = nullptr;
+ test_object_ = nullptr;
+ }
+
+ // Return the V8 context.
+ CefRefPtr<CefV8Context> GetContext() {
+ CefRefPtr<CefV8Context> context = browser_->GetMainFrame()->GetV8Context();
+ EXPECT_TRUE(context.get());
+ return context;
+ }
+
+ CefRefPtr<ClientAppRenderer> app_;
+ CefRefPtr<CefBrowser> browser_;
+ V8TestMode test_mode_;
+
+ CefRefPtr<CefV8Context> test_context_;
+ CefRefPtr<CefV8Value> test_object_;
+
+ // Used by startup tests to indicate success.
+ TrackCallback startup_test_success_;
+
+ IMPLEMENT_REFCOUNTING(V8RendererTest);
+};
+
+// Browser side.
+class V8TestHandler : public TestHandler {
+ public:
+ V8TestHandler(V8TestMode test_mode, const char* test_url)
+ : test_mode_(test_mode), test_url_(test_url) {}
+
+ void RunTest() override {
+ CefRefPtr<CefDictionaryValue> extra_info = CefDictionaryValue::Create();
+ extra_info->SetInt(kV8TestCmdKey, test_mode_);
+
+ // Nested script tag forces creation of the V8 context.
+ if (test_mode_ == V8TEST_CONTEXT_EVAL_CSP_BYPASS_UNSAFE_EVAL ||
+ test_mode_ == V8TEST_CONTEXT_EVAL_CSP_BYPASS_SANDBOX) {
+ std::string url;
+ ResourceContent::HeaderMap headers;
+ if (test_mode_ == V8TEST_CONTEXT_EVAL_CSP_BYPASS_UNSAFE_EVAL) {
+ url = kV8ContextEvalCspBypassUnsafeEval;
+ headers.insert(std::pair<std::string, std::string>(
+ "Content-Security-Policy", "script-src 'self'"));
+ } else if (test_mode_ == V8TEST_CONTEXT_EVAL_CSP_BYPASS_SANDBOX) {
+ url = kV8ContextEvalCspBypassSandbox;
+ headers.insert(std::pair<std::string, std::string>(
+ "Content-Security-Policy", "sandbox"));
+ } else {
+ NOTREACHED();
+ }
+ AddResource(url,
+ "<html><body>" + url +
+ "<p id='result' style='display:none'>CSP_BYPASSED</p>"
+ "</body></html>",
+ "text/html", headers);
+ CreateBrowser(test_url_, nullptr, extra_info);
+ } else if (test_mode_ == V8TEST_CONTEXT_ENTERED) {
+ AddResource(kV8ContextParentTestUrl,
+ "<html><body>"
+ "<script>var i = 0;</script><iframe src=\"" +
+ std::string(kV8ContextChildTestUrl) +
+ "\" id=\"f\"></iframe></body>"
+ "</html>",
+ "text/html");
+ AddResource(kV8ContextChildTestUrl,
+ "<html><body>"
+ "<script>var i = 0;</script>CHILD</body></html>",
+ "text/html");
+ CreateBrowser(kV8ContextParentTestUrl, nullptr, extra_info);
+ } else if (test_mode_ == V8TEST_ON_UNCAUGHT_EXCEPTION ||
+ test_mode_ == V8TEST_ON_UNCAUGHT_EXCEPTION_DEV_TOOLS) {
+ AddResource(kV8OnUncaughtExceptionTestUrl,
+ "<html><body>"
+ "<h1>OnUncaughtException</h1>"
+ "<script>\n"
+ "function test(){ test2(); }\n"
+ "function test2(){ asd(); }\n"
+ "</script>\n"
+ "</body></html>\n",
+ "text/html");
+ CreateBrowser(kV8OnUncaughtExceptionTestUrl, nullptr, extra_info);
+ } else if (test_mode_ == V8TEST_HANDLER_CALL_ON_RELEASED_CONTEXT) {
+ AddResource(kV8HandlerCallOnReleasedContextUrl,
+ "<html><body onload='createFrame()'>"
+ "(main)"
+ "<script>"
+ "function createFrame() {"
+ " var el = document.createElement('iframe');"
+ " el.id = 'child';"
+ " el.src = '" +
+ std::string(kV8HandlerCallOnReleasedContextChildUrl) +
+ "';"
+ " el.onload = function() {"
+ " setTimeout(function() {"
+ " try {"
+ " el.contentWindow.removeMe();"
+ " window.notify_test_done();"
+ " } catch (e) { alert('Unit test error.\\n' + e); }"
+ " }, 1000);"
+ " };"
+ " document.body.appendChild(el);"
+ "}"
+ ""
+ "function removeFrame(id) {"
+ " var el = document.getElementById(id);"
+ " if (el) { el.parentElement.removeChild(el); }"
+ " else { alert('Error in test. No element \"' + id + "
+ "'\" found.'); }"
+ "}"
+ "</script>"
+ "</body></html>",
+ "text/html");
+ AddResource(kV8HandlerCallOnReleasedContextChildUrl,
+ "<html><body>"
+ "(child)"
+ "<script>"
+ "try {"
+ " if (!window.v8_context_is_alive()) {"
+ " throw 'v8_context_is_alive returns non-true value.';"
+ " }"
+ "} catch (e) {"
+ " alert('Unit test error.\\n' + e);"
+ "}"
+ ""
+ "function removeMe() {"
+ " var w = window;"
+ " w.parent.removeFrame('child');"
+ " return w.v8_context_is_alive();"
+ "}"
+ "</script>"
+ "</body></html>",
+ "text/html");
+ CreateBrowser(kV8HandlerCallOnReleasedContextUrl, nullptr, extra_info);
+ } else {
+ EXPECT_TRUE(test_url_ != nullptr);
+ AddResource(test_url_,
+ "<html><body>"
+ "<script>var i = 0;</script>TEST</body></html>",
+ "text/html");
+ CreateBrowser(test_url_, nullptr, extra_info);
+ }
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout(test_mode_ == V8TEST_ON_UNCAUGHT_EXCEPTION_DEV_TOOLS ? 10000
+ : 5000);
+ }
+
+ void OnBeforeClose(CefRefPtr<CefBrowser> browser) override {
+ if (test_mode_ == V8TEST_ON_UNCAUGHT_EXCEPTION_DEV_TOOLS &&
+ browser->IsPopup()) {
+ // Generate the uncaught exception in the main browser. Use a 200ms delay
+ // because there's a bit of a lag between destroying the DevToolsAgent and
+ // re-registering for uncaught exceptions.
+ GetBrowser()->GetMainFrame()->ExecuteJavaScript(
+ "window.setTimeout(test, 200);",
+ GetBrowser()->GetMainFrame()->GetURL(), 0);
+ }
+
+ TestHandler::OnBeforeClose(browser);
+ }
+
+ void OnLoadEnd(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ int httpStatusCode) override {
+ if (test_mode_ == V8TEST_ON_UNCAUGHT_EXCEPTION_DEV_TOOLS) {
+ if (!browser->IsPopup()) {
+ // Create the DevTools window.
+ CefWindowInfo windowInfo;
+ CefBrowserSettings settings;
+
+#if defined(OS_WIN)
+ windowInfo.SetAsPopup(browser->GetHost()->GetWindowHandle(),
+ "DevTools");
+#endif
+
+ browser->GetHost()->ShowDevTools(windowInfo, this, settings,
+ CefPoint());
+ }
+ return;
+ }
+
+ const std::string& url = frame->GetURL();
+ if (url != kV8NavTestUrl && url != kV8ContextParentTestUrl &&
+ url.find("http://tests/") != std::string::npos) {
+ // Run the test.
+ CefRefPtr<CefProcessMessage> return_msg =
+ CefProcessMessage::Create(kV8RunTestMsg);
+ frame->SendProcessMessage(PID_RENDERER, return_msg);
+ }
+ }
+
+ bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefProcessId source_process,
+ CefRefPtr<CefProcessMessage> message) override {
+ EXPECT_TRUE(browser.get());
+ EXPECT_TRUE(frame.get());
+ EXPECT_TRUE(frame->IsMain());
+ EXPECT_EQ(PID_RENDERER, source_process);
+ EXPECT_TRUE(message.get());
+ EXPECT_TRUE(message->IsReadOnly());
+
+ const std::string& message_name = message->GetName();
+ EXPECT_STREQ(kV8TestMsg, message_name.c_str());
+
+ got_message_.yes();
+
+ if (message->GetArgumentList()->GetBool(0)) {
+ got_success_.yes();
+ }
+
+ // Test is complete.
+ DestroyTest();
+
+ return true;
+ }
+
+ V8TestMode test_mode_;
+ const char* test_url_;
+ TrackCallback got_message_;
+ TrackCallback got_success_;
+
+ IMPLEMENT_REFCOUNTING(V8TestHandler);
+};
+
+} // namespace
+
+// Entry point for creating V8 renderer test objects.
+// Called from client_app_delegates.cc.
+void CreateV8RendererTests(ClientAppRenderer::DelegateSet& delegates) {
+ delegates.insert(new V8RendererTest);
+}
+
+// Helpers for defining V8 tests.
+#define V8_TEST_EX(name, test_mode, test_url) \
+ TEST(V8Test, name) { \
+ CefRefPtr<V8TestHandler> handler = new V8TestHandler(test_mode, test_url); \
+ handler->ExecuteTest(); \
+ EXPECT_TRUE(handler->got_message_); \
+ EXPECT_TRUE(handler->got_success_); \
+ ReleaseAndWaitForDestructor(handler); \
+ }
+
+#define V8_TEST(name, test_mode) V8_TEST_EX(name, test_mode, kV8TestUrl)
+
+// Define the tests.
+V8_TEST(NullCreate, V8TEST_NULL_CREATE)
+V8_TEST(BoolCreate, V8TEST_BOOL_CREATE)
+V8_TEST(IntCreate, V8TEST_INT_CREATE)
+V8_TEST(UIntCreate, V8TEST_UINT_CREATE)
+V8_TEST(DoubleCreate, V8TEST_DOUBLE_CREATE)
+V8_TEST(DateCreate, V8TEST_DATE_CREATE)
+V8_TEST(StringCreate, V8TEST_STRING_CREATE)
+V8_TEST(EmptyStringCreate, V8TEST_EMPTY_STRING_CREATE)
+V8_TEST(ArrayCreate, V8TEST_ARRAY_CREATE)
+V8_TEST(ArrayValue, V8TEST_ARRAY_VALUE)
+V8_TEST(ArrayBuffer, V8TEST_ARRAY_BUFFER)
+V8_TEST(ArrayBufferValue, V8TEST_ARRAY_BUFFER_VALUE)
+V8_TEST(ObjectCreate, V8TEST_OBJECT_CREATE)
+V8_TEST(ObjectUserData, V8TEST_OBJECT_USERDATA)
+V8_TEST(ObjectAccessor, V8TEST_OBJECT_ACCESSOR)
+V8_TEST(ObjectAccessorException, V8TEST_OBJECT_ACCESSOR_EXCEPTION)
+V8_TEST(ObjectAccessorFail, V8TEST_OBJECT_ACCESSOR_FAIL)
+V8_TEST(ObjectAccessorReadOnly, V8TEST_OBJECT_ACCESSOR_READONLY)
+V8_TEST(ObjectInterceptor, V8TEST_OBJECT_INTERCEPTOR)
+V8_TEST(ObjectInterceptorFail, V8TEST_OBJECT_INTERCEPTOR_FAIL)
+V8_TEST(ObjectInterceptorException, V8TEST_OBJECT_INTERCEPTOR_EXCEPTION)
+V8_TEST(ObjectInterceptorAndAccessor, V8TEST_OBJECT_INTERCEPTOR_AND_ACCESSOR)
+V8_TEST(ObjectValue, V8TEST_OBJECT_VALUE)
+V8_TEST(ObjectValueReadOnly, V8TEST_OBJECT_VALUE_READONLY)
+V8_TEST(ObjectValueEnum, V8TEST_OBJECT_VALUE_ENUM)
+V8_TEST(ObjectValueDontEnum, V8TEST_OBJECT_VALUE_DONTENUM)
+V8_TEST(ObjectValueDelete, V8TEST_OBJECT_VALUE_DELETE)
+V8_TEST(ObjectValueDontDelete, V8TEST_OBJECT_VALUE_DONTDELETE)
+V8_TEST(ObjectValueEmptyKey, V8TEST_OBJECT_VALUE_EMPTYKEY)
+V8_TEST(FunctionCreate, V8TEST_FUNCTION_CREATE)
+V8_TEST(FunctionHandler, V8TEST_FUNCTION_HANDLER)
+V8_TEST(FunctionHandlerException, V8TEST_FUNCTION_HANDLER_EXCEPTION)
+V8_TEST(FunctionHandlerFail, V8TEST_FUNCTION_HANDLER_FAIL)
+V8_TEST(FunctionHandlerNoObject, V8TEST_FUNCTION_HANDLER_NO_OBJECT)
+V8_TEST(FunctionHandlerWithContext, V8TEST_FUNCTION_HANDLER_WITH_CONTEXT)
+V8_TEST(FunctionHandlerEmptyString, V8TEST_FUNCTION_HANDLER_EMPTY_STRING)
+V8_TEST(PromiseCreate, V8TEST_PROMISE_CREATE)
+V8_TEST(PromiseResolve, V8TEST_PROMISE_RESOLVE)
+V8_TEST(PromiseResolveNoArgument, V8TEST_PROMISE_RESOLVE_NO_ARGUMENT)
+V8_TEST(PromiseResolveHandler, V8TEST_PROMISE_RESOLVE_HANDLER)
+V8_TEST(PromiseReject, V8TEST_PROMISE_REJECT)
+V8_TEST(PromiseRejectHandler, V8TEST_PROMISE_REJECT_HANDLER)
+V8_TEST(ContextEval, V8TEST_CONTEXT_EVAL)
+V8_TEST(ContextEvalException, V8TEST_CONTEXT_EVAL_EXCEPTION)
+V8_TEST_EX(ContextEvalCspBypassUnsafeEval,
+ V8TEST_CONTEXT_EVAL_CSP_BYPASS_UNSAFE_EVAL,
+ kV8ContextEvalCspBypassUnsafeEval)
+V8_TEST_EX(ContextEvalCspBypassSandbox,
+ V8TEST_CONTEXT_EVAL_CSP_BYPASS_SANDBOX,
+ kV8ContextEvalCspBypassSandbox)
+V8_TEST_EX(ContextEntered, V8TEST_CONTEXT_ENTERED, nullptr)
+V8_TEST_EX(Binding, V8TEST_BINDING, kV8BindingTestUrl)
+V8_TEST(StackTrace, V8TEST_STACK_TRACE)
+V8_TEST(OnUncaughtException, V8TEST_ON_UNCAUGHT_EXCEPTION)
+V8_TEST(OnUncaughtExceptionDevTools, V8TEST_ON_UNCAUGHT_EXCEPTION_DEV_TOOLS)
+V8_TEST(Extension, V8TEST_EXTENSION)
+V8_TEST_EX(HandlerCallOnReleasedContext,
+ V8TEST_HANDLER_CALL_ON_RELEASED_CONTEXT,
+ kV8HandlerCallOnReleasedContextUrl)
diff --git a/tests/ceftests/values_unittest.cc b/tests/ceftests/values_unittest.cc
new file mode 100644
index 00000000..fa91ad98
--- /dev/null
+++ b/tests/ceftests/values_unittest.cc
@@ -0,0 +1,1379 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "include/cef_task.h"
+#include "include/cef_values.h"
+#include "tests/ceftests/test_handler.h"
+#include "tests/ceftests/test_util.h"
+#include "tests/gtest/include/gtest/gtest.h"
+
+namespace {
+
+// Dictionary test keys.
+const char* kNullKey = "null_key";
+const char* kBoolKey = "bool_key";
+const char* kIntKey = "int_key";
+const char* kDoubleKey = "double_key";
+const char* kStringKey = "string_key";
+const char* kBinaryKey = "binary_key";
+const char* kDictionaryKey = "dict_key";
+const char* kListKey = "list_key";
+
+// List test indexes.
+enum {
+ kNullIndex = 0,
+ kBoolIndex,
+ kIntIndex,
+ kDoubleIndex,
+ kStringIndex,
+ kBinaryIndex,
+ kDictionaryIndex,
+ kListIndex,
+};
+
+// Dictionary/list test values.
+const bool kBoolValue = true;
+const int kIntValue = 12;
+const double kDoubleValue = 4.5432;
+const char* kStringValue = "My string value";
+
+// BINARY TEST HELPERS
+
+// Test a binary value.
+void TestBinary(CefRefPtr<CefBinaryValue> value, char* data, size_t data_size) {
+ // Testing requires strings longer than 15 characters.
+ EXPECT_GT(data_size, 15U);
+
+ EXPECT_EQ(data_size, value->GetSize());
+
+ char* buff = new char[data_size + 1];
+ char old_char;
+
+ // Test full read.
+ memset(buff, 0, data_size + 1);
+ EXPECT_EQ(data_size, value->GetData(buff, data_size, 0));
+ EXPECT_TRUE(!strcmp(buff, data));
+
+ // Test partial read with offset.
+ memset(buff, 0, data_size + 1);
+ old_char = data[15];
+ data[15] = 0;
+ EXPECT_EQ(10U, value->GetData(buff, 10, 5));
+ EXPECT_TRUE(!strcmp(buff, data + 5));
+ data[15] = old_char;
+
+ // Test that changes to the original data have no effect.
+ memset(buff, 0, data_size + 1);
+ old_char = data[0];
+ data[0] = '.';
+ EXPECT_EQ(1U, value->GetData(buff, 1, 0));
+ EXPECT_EQ(old_char, buff[0]);
+ data[0] = old_char;
+
+ // Test copy.
+ CefRefPtr<CefBinaryValue> copy = value->Copy();
+ TestBinaryEqual(copy, value);
+
+ delete[] buff;
+}
+
+// Used to test access of binary data on a different thread.
+class BinaryTask : public CefTask {
+ public:
+ BinaryTask(CefRefPtr<CefBinaryValue> value, char* data, size_t data_size)
+ : value_(value), data_(data), data_size_(data_size) {}
+
+ void Execute() override { TestBinary(value_, data_, data_size_); }
+
+ private:
+ CefRefPtr<CefBinaryValue> value_;
+ char* data_;
+ size_t data_size_;
+
+ IMPLEMENT_REFCOUNTING(BinaryTask);
+};
+
+// DICTIONARY TEST HELPERS
+
+// Test dictionary null value.
+void TestDictionaryNull(CefRefPtr<CefDictionaryValue> value) {
+ EXPECT_FALSE(value->HasKey(kNullKey));
+ EXPECT_TRUE(value->SetNull(kNullKey));
+ EXPECT_TRUE(value->HasKey(kNullKey));
+ EXPECT_EQ(VTYPE_NULL, value->GetType(kNullKey));
+}
+
+// Test dictionary bool value.
+void TestDictionaryBool(CefRefPtr<CefDictionaryValue> value) {
+ EXPECT_FALSE(value->HasKey(kBoolKey));
+ EXPECT_TRUE(value->SetBool(kBoolKey, kBoolValue));
+ EXPECT_TRUE(value->HasKey(kBoolKey));
+ EXPECT_EQ(VTYPE_BOOL, value->GetType(kBoolKey));
+ EXPECT_EQ(kBoolValue, value->GetBool(kBoolKey));
+}
+
+// Test dictionary int value.
+void TestDictionaryInt(CefRefPtr<CefDictionaryValue> value) {
+ EXPECT_FALSE(value->HasKey(kIntKey));
+ EXPECT_TRUE(value->SetInt(kIntKey, kIntValue));
+ EXPECT_TRUE(value->HasKey(kIntKey));
+ EXPECT_EQ(VTYPE_INT, value->GetType(kIntKey));
+ EXPECT_EQ(kIntValue, value->GetInt(kIntKey));
+}
+
+// Test dictionary double value.
+void TestDictionaryDouble(CefRefPtr<CefDictionaryValue> value) {
+ EXPECT_FALSE(value->HasKey(kDoubleKey));
+ EXPECT_TRUE(value->SetDouble(kDoubleKey, kDoubleValue));
+ EXPECT_TRUE(value->HasKey(kDoubleKey));
+ EXPECT_EQ(VTYPE_DOUBLE, value->GetType(kDoubleKey));
+ EXPECT_EQ(kDoubleValue, value->GetDouble(kDoubleKey));
+}
+
+// Test dictionary string value.
+void TestDictionaryString(CefRefPtr<CefDictionaryValue> value) {
+ EXPECT_FALSE(value->HasKey(kStringKey));
+ EXPECT_TRUE(value->SetString(kStringKey, kStringValue));
+ EXPECT_TRUE(value->HasKey(kStringKey));
+ EXPECT_EQ(VTYPE_STRING, value->GetType(kStringKey));
+ EXPECT_EQ(kStringValue, value->GetString(kStringKey).ToString());
+}
+
+// Test dictionary binary value.
+void TestDictionaryBinary(CefRefPtr<CefDictionaryValue> value,
+ char* binary_data,
+ size_t binary_data_size,
+ CefRefPtr<CefBinaryValue>& binary_value) {
+ binary_value = CefBinaryValue::Create(binary_data, binary_data_size);
+ EXPECT_TRUE(binary_value.get());
+ EXPECT_TRUE(binary_value->IsValid());
+ EXPECT_FALSE(binary_value->IsOwned());
+ EXPECT_FALSE(value->HasKey(kBinaryKey));
+ EXPECT_TRUE(value->SetBinary(kBinaryKey, binary_value));
+ EXPECT_FALSE(binary_value->IsValid()); // Value should be detached
+ EXPECT_TRUE(value->HasKey(kBinaryKey));
+ EXPECT_EQ(VTYPE_BINARY, value->GetType(kBinaryKey));
+ binary_value = value->GetBinary(kBinaryKey);
+ EXPECT_TRUE(binary_value.get());
+ EXPECT_TRUE(binary_value->IsValid());
+ EXPECT_TRUE(binary_value->IsOwned());
+ TestBinary(binary_value, binary_data, binary_data_size);
+}
+
+// Test dictionary dictionary value.
+void TestDictionaryDictionary(CefRefPtr<CefDictionaryValue> value,
+ CefRefPtr<CefDictionaryValue>& dictionary_value) {
+ dictionary_value = CefDictionaryValue::Create();
+ EXPECT_TRUE(dictionary_value.get());
+ EXPECT_TRUE(dictionary_value->IsValid());
+ EXPECT_FALSE(dictionary_value->IsOwned());
+ EXPECT_FALSE(dictionary_value->IsReadOnly());
+ EXPECT_TRUE(dictionary_value->SetInt(kIntKey, kIntValue));
+ EXPECT_EQ(1U, dictionary_value->GetSize());
+ EXPECT_FALSE(value->HasKey(kDictionaryKey));
+ EXPECT_TRUE(value->SetDictionary(kDictionaryKey, dictionary_value));
+ EXPECT_FALSE(dictionary_value->IsValid()); // Value should be detached
+ EXPECT_TRUE(value->HasKey(kDictionaryKey));
+ EXPECT_EQ(VTYPE_DICTIONARY, value->GetType(kDictionaryKey));
+ dictionary_value = value->GetDictionary(kDictionaryKey);
+ EXPECT_TRUE(dictionary_value.get());
+ EXPECT_TRUE(dictionary_value->IsValid());
+ EXPECT_TRUE(dictionary_value->IsOwned());
+ EXPECT_FALSE(dictionary_value->IsReadOnly());
+ EXPECT_EQ(1U, dictionary_value->GetSize());
+ EXPECT_EQ(kIntValue, dictionary_value->GetInt(kIntKey));
+}
+
+// Test dictionary list value.
+void TestDictionaryList(CefRefPtr<CefDictionaryValue> value,
+ CefRefPtr<CefListValue>& list_value) {
+ list_value = CefListValue::Create();
+ EXPECT_TRUE(list_value.get());
+ EXPECT_TRUE(list_value->IsValid());
+ EXPECT_FALSE(list_value->IsOwned());
+ EXPECT_FALSE(list_value->IsReadOnly());
+ EXPECT_TRUE(list_value->SetInt(0, kIntValue));
+ EXPECT_EQ(1U, list_value->GetSize());
+ EXPECT_FALSE(value->HasKey(kListKey));
+ EXPECT_TRUE(value->SetList(kListKey, list_value));
+ EXPECT_FALSE(list_value->IsValid()); // Value should be detached
+ EXPECT_TRUE(value->HasKey(kListKey));
+ EXPECT_EQ(VTYPE_LIST, value->GetType(kListKey));
+ list_value = value->GetList(kListKey);
+ EXPECT_TRUE(list_value.get());
+ EXPECT_TRUE(list_value->IsValid());
+ EXPECT_TRUE(list_value->IsOwned());
+ EXPECT_FALSE(list_value->IsReadOnly());
+ EXPECT_EQ(1U, list_value->GetSize());
+ EXPECT_EQ(kIntValue, list_value->GetInt(0));
+}
+
+// Test dictionary value.
+void TestDictionary(CefRefPtr<CefDictionaryValue> value,
+ char* binary_data,
+ size_t binary_data_size) {
+ CefRefPtr<CefBinaryValue> binary_value;
+ CefRefPtr<CefDictionaryValue> dictionary_value;
+ CefRefPtr<CefListValue> list_value;
+
+ // Test the size.
+ EXPECT_EQ(0U, value->GetSize());
+
+ TestDictionaryNull(value);
+ TestDictionaryBool(value);
+ TestDictionaryInt(value);
+ TestDictionaryDouble(value);
+ TestDictionaryString(value);
+ TestDictionaryBinary(value, binary_data, binary_data_size, binary_value);
+ TestDictionaryDictionary(value, dictionary_value);
+ TestDictionaryList(value, list_value);
+
+ // Test the size.
+ EXPECT_EQ(8U, value->GetSize());
+
+ // Test copy.
+ CefRefPtr<CefDictionaryValue> copy = value->Copy(false);
+ TestDictionaryEqual(value, copy);
+
+ // Test removal.
+ EXPECT_TRUE(value->Remove(kNullKey));
+ EXPECT_FALSE(value->HasKey(kNullKey));
+
+ EXPECT_TRUE(value->Remove(kBoolKey));
+ EXPECT_FALSE(value->HasKey(kBoolKey));
+
+ EXPECT_TRUE(value->Remove(kIntKey));
+ EXPECT_FALSE(value->HasKey(kIntKey));
+
+ EXPECT_TRUE(value->Remove(kDoubleKey));
+ EXPECT_FALSE(value->HasKey(kDoubleKey));
+
+ EXPECT_TRUE(value->Remove(kStringKey));
+ EXPECT_FALSE(value->HasKey(kStringKey));
+
+ EXPECT_TRUE(value->Remove(kBinaryKey));
+ EXPECT_FALSE(value->HasKey(kBinaryKey));
+ EXPECT_FALSE(binary_value->IsValid()); // Value should be detached
+
+ EXPECT_TRUE(value->Remove(kDictionaryKey));
+ EXPECT_FALSE(value->HasKey(kDictionaryKey));
+ EXPECT_FALSE(dictionary_value->IsValid()); // Value should be detached
+
+ EXPECT_TRUE(value->Remove(kListKey));
+ EXPECT_FALSE(value->HasKey(kListKey));
+ EXPECT_FALSE(list_value->IsValid()); // Value should be detached
+
+ // Test the size.
+ EXPECT_EQ(0U, value->GetSize());
+
+ // Re-add some values.
+ TestDictionaryNull(value);
+ TestDictionaryBool(value);
+ TestDictionaryDictionary(value, dictionary_value);
+
+ // Test the size.
+ EXPECT_EQ(3U, value->GetSize());
+
+ // Clear the values.
+ EXPECT_TRUE(value->Clear());
+ EXPECT_EQ(0U, value->GetSize());
+ EXPECT_FALSE(dictionary_value->IsValid()); // Value should be detached
+}
+
+// Used to test access of dictionary data on a different thread.
+class DictionaryTask : public CefTask {
+ public:
+ DictionaryTask(CefRefPtr<CefDictionaryValue> value,
+ char* binary_data,
+ size_t binary_data_size)
+ : value_(value),
+ binary_data_(binary_data),
+ binary_data_size_(binary_data_size) {}
+
+ void Execute() override {
+ TestDictionary(value_, binary_data_, binary_data_size_);
+ }
+
+ private:
+ CefRefPtr<CefDictionaryValue> value_;
+ char* binary_data_;
+ size_t binary_data_size_;
+
+ IMPLEMENT_REFCOUNTING(DictionaryTask);
+};
+
+// LIST TEST HELPERS
+
+// Test list null value.
+void TestListNull(CefRefPtr<CefListValue> value, size_t index) {
+ CefValueType type = value->GetType(index);
+ EXPECT_TRUE(type == VTYPE_INVALID || type == VTYPE_NULL);
+
+ EXPECT_TRUE(value->SetNull(index));
+ EXPECT_EQ(VTYPE_NULL, value->GetType(index));
+}
+
+// Test list bool value.
+void TestListBool(CefRefPtr<CefListValue> value, size_t index) {
+ CefValueType type = value->GetType(index);
+ EXPECT_TRUE(type == VTYPE_INVALID || type == VTYPE_NULL);
+
+ EXPECT_TRUE(value->SetBool(index, kBoolValue));
+ EXPECT_EQ(VTYPE_BOOL, value->GetType(index));
+ EXPECT_EQ(kBoolValue, value->GetBool(index));
+}
+
+// Test list int value.
+void TestListInt(CefRefPtr<CefListValue> value, size_t index) {
+ CefValueType type = value->GetType(index);
+ EXPECT_TRUE(type == VTYPE_INVALID || type == VTYPE_NULL);
+
+ EXPECT_TRUE(value->SetInt(index, kIntValue));
+ EXPECT_EQ(VTYPE_INT, value->GetType(index));
+ EXPECT_EQ(kIntValue, value->GetInt(index));
+}
+
+// Test list double value.
+void TestListDouble(CefRefPtr<CefListValue> value, size_t index) {
+ CefValueType type = value->GetType(index);
+ EXPECT_TRUE(type == VTYPE_INVALID || type == VTYPE_NULL);
+
+ EXPECT_TRUE(value->SetDouble(index, kDoubleValue));
+ EXPECT_EQ(VTYPE_DOUBLE, value->GetType(index));
+ EXPECT_EQ(kDoubleValue, value->GetDouble(index));
+}
+
+// Test list string value.
+void TestListString(CefRefPtr<CefListValue> value, size_t index) {
+ CefValueType type = value->GetType(index);
+ EXPECT_TRUE(type == VTYPE_INVALID || type == VTYPE_NULL);
+
+ EXPECT_TRUE(value->SetString(index, kStringValue));
+ EXPECT_EQ(VTYPE_STRING, value->GetType(index));
+ EXPECT_EQ(kStringValue, value->GetString(index).ToString());
+}
+
+// Test list binary value.
+void TestListBinary(CefRefPtr<CefListValue> value,
+ size_t index,
+ char* binary_data,
+ size_t binary_data_size,
+ CefRefPtr<CefBinaryValue>& binary_value) {
+ binary_value = CefBinaryValue::Create(binary_data, binary_data_size);
+ EXPECT_TRUE(binary_value.get());
+ EXPECT_TRUE(binary_value->IsValid());
+ EXPECT_FALSE(binary_value->IsOwned());
+
+ CefValueType type = value->GetType(index);
+ EXPECT_TRUE(type == VTYPE_INVALID || type == VTYPE_NULL);
+
+ EXPECT_TRUE(value->SetBinary(index, binary_value));
+ EXPECT_FALSE(binary_value->IsValid()); // Value should be detached
+ EXPECT_EQ(VTYPE_BINARY, value->GetType(index));
+ binary_value = value->GetBinary(index);
+ EXPECT_TRUE(binary_value.get());
+ EXPECT_TRUE(binary_value->IsValid());
+ EXPECT_TRUE(binary_value->IsOwned());
+ TestBinary(binary_value, binary_data, binary_data_size);
+}
+
+// Test list dictionary value.
+void TestListDictionary(CefRefPtr<CefListValue> value,
+ size_t index,
+ CefRefPtr<CefDictionaryValue>& dictionary_value) {
+ dictionary_value = CefDictionaryValue::Create();
+ EXPECT_TRUE(dictionary_value.get());
+ EXPECT_TRUE(dictionary_value->IsValid());
+ EXPECT_FALSE(dictionary_value->IsOwned());
+ EXPECT_FALSE(dictionary_value->IsReadOnly());
+ EXPECT_TRUE(dictionary_value->SetInt(kIntKey, kIntValue));
+ EXPECT_EQ(1U, dictionary_value->GetSize());
+
+ CefValueType type = value->GetType(index);
+ EXPECT_TRUE(type == VTYPE_INVALID || type == VTYPE_NULL);
+
+ EXPECT_TRUE(value->SetDictionary(index, dictionary_value));
+ EXPECT_FALSE(dictionary_value->IsValid()); // Value should be detached
+ EXPECT_EQ(VTYPE_DICTIONARY, value->GetType(index));
+ dictionary_value = value->GetDictionary(index);
+ EXPECT_TRUE(dictionary_value.get());
+ EXPECT_TRUE(dictionary_value->IsValid());
+ EXPECT_TRUE(dictionary_value->IsOwned());
+ EXPECT_FALSE(dictionary_value->IsReadOnly());
+ EXPECT_EQ(1U, dictionary_value->GetSize());
+ EXPECT_EQ(kIntValue, dictionary_value->GetInt(kIntKey));
+}
+
+// Test list list value.
+void TestListList(CefRefPtr<CefListValue> value,
+ size_t index,
+ CefRefPtr<CefListValue>& list_value) {
+ list_value = CefListValue::Create();
+ EXPECT_TRUE(list_value.get());
+ EXPECT_TRUE(list_value->IsValid());
+ EXPECT_FALSE(list_value->IsOwned());
+ EXPECT_FALSE(list_value->IsReadOnly());
+ EXPECT_TRUE(list_value->SetInt(0, kIntValue));
+ EXPECT_EQ(1U, list_value->GetSize());
+
+ CefValueType type = value->GetType(index);
+ EXPECT_TRUE(type == VTYPE_INVALID || type == VTYPE_NULL);
+
+ EXPECT_TRUE(value->SetList(index, list_value));
+ EXPECT_FALSE(list_value->IsValid()); // Value should be detached
+ EXPECT_EQ(VTYPE_LIST, value->GetType(index));
+ list_value = value->GetList(index);
+ EXPECT_TRUE(list_value.get());
+ EXPECT_TRUE(list_value->IsValid());
+ EXPECT_TRUE(list_value->IsOwned());
+ EXPECT_FALSE(list_value->IsReadOnly());
+ EXPECT_EQ(1U, list_value->GetSize());
+ EXPECT_EQ(kIntValue, list_value->GetInt(0));
+}
+
+// Test list value.
+void TestList(CefRefPtr<CefListValue> value,
+ char* binary_data,
+ size_t binary_data_size) {
+ CefRefPtr<CefBinaryValue> binary_value;
+ CefRefPtr<CefDictionaryValue> dictionary_value;
+ CefRefPtr<CefListValue> list_value;
+
+ // Test the size.
+ EXPECT_EQ(0U, value->GetSize());
+
+ // Set the size.
+ EXPECT_TRUE(value->SetSize(8));
+ EXPECT_EQ(8U, value->GetSize());
+
+ EXPECT_EQ(VTYPE_NULL, value->GetType(kNullIndex));
+ TestListNull(value, kNullIndex);
+ EXPECT_EQ(VTYPE_NULL, value->GetType(kBoolIndex));
+ TestListBool(value, kBoolIndex);
+ EXPECT_EQ(VTYPE_NULL, value->GetType(kIntIndex));
+ TestListInt(value, kIntIndex);
+ EXPECT_EQ(VTYPE_NULL, value->GetType(kDoubleIndex));
+ TestListDouble(value, kDoubleIndex);
+ EXPECT_EQ(VTYPE_NULL, value->GetType(kStringIndex));
+ TestListString(value, kStringIndex);
+ EXPECT_EQ(VTYPE_NULL, value->GetType(kBinaryIndex));
+ TestListBinary(value, kBinaryIndex, binary_data, binary_data_size,
+ binary_value);
+ EXPECT_EQ(VTYPE_NULL, value->GetType(kDictionaryIndex));
+ TestListDictionary(value, kDictionaryIndex, dictionary_value);
+ EXPECT_EQ(VTYPE_NULL, value->GetType(kListIndex));
+ TestListList(value, kListIndex, list_value);
+
+ // Test the size.
+ EXPECT_EQ(8U, value->GetSize());
+
+ // Test various operations with invalid index.
+ EXPECT_FALSE(list_value->Remove(9U));
+ EXPECT_TRUE(list_value->GetType(10U) == VTYPE_INVALID);
+ EXPECT_FALSE(list_value->GetValue(11U).get() != nullptr &&
+ list_value->GetValue(11U)->IsValid());
+
+ // Test copy.
+ CefRefPtr<CefListValue> copy = value->Copy();
+ TestListEqual(value, copy);
+
+ // Test removal (in reverse order so indexes stay valid).
+ EXPECT_TRUE(value->Remove(kListIndex));
+ EXPECT_EQ(7U, value->GetSize());
+ EXPECT_FALSE(list_value->IsValid()); // Value should be detached
+
+ EXPECT_TRUE(value->Remove(kDictionaryIndex));
+ EXPECT_EQ(6U, value->GetSize());
+ EXPECT_FALSE(dictionary_value->IsValid()); // Value should be detached
+
+ EXPECT_TRUE(value->Remove(kBinaryIndex));
+ EXPECT_EQ(5U, value->GetSize());
+ EXPECT_FALSE(binary_value->IsValid()); // Value should be detached
+
+ EXPECT_TRUE(value->Remove(kStringIndex));
+ EXPECT_EQ(4U, value->GetSize());
+
+ EXPECT_TRUE(value->Remove(kDoubleIndex));
+ EXPECT_EQ(3U, value->GetSize());
+
+ EXPECT_TRUE(value->Remove(kIntIndex));
+ EXPECT_EQ(2U, value->GetSize());
+
+ EXPECT_TRUE(value->Remove(kBoolIndex));
+ EXPECT_EQ(1U, value->GetSize());
+
+ EXPECT_TRUE(value->Remove(kNullIndex));
+ EXPECT_EQ(0U, value->GetSize());
+
+ // Re-add some values.
+ EXPECT_EQ(VTYPE_INVALID, value->GetType(0));
+ TestListNull(value, 0);
+ EXPECT_EQ(VTYPE_INVALID, value->GetType(1));
+ TestListBool(value, 1);
+ EXPECT_EQ(VTYPE_INVALID, value->GetType(2));
+ TestListList(value, 2, list_value);
+
+ // Test the size.
+ EXPECT_EQ(3U, value->GetSize());
+
+ // Clear the values.
+ EXPECT_TRUE(value->Clear());
+ EXPECT_EQ(0U, value->GetSize());
+ EXPECT_FALSE(list_value->IsValid()); // Value should be detached
+
+ // Add some values in random order.
+ EXPECT_EQ(VTYPE_INVALID, value->GetType(2));
+ TestListInt(value, 2);
+ EXPECT_EQ(VTYPE_NULL, value->GetType(0));
+ TestListBool(value, 0);
+ EXPECT_EQ(VTYPE_NULL, value->GetType(1));
+ TestListList(value, 1, list_value);
+
+ EXPECT_EQ(VTYPE_BOOL, value->GetType(0));
+ EXPECT_EQ(VTYPE_LIST, value->GetType(1));
+ EXPECT_EQ(VTYPE_INT, value->GetType(2));
+
+ // Test the size.
+ EXPECT_EQ(3U, value->GetSize());
+
+ // Clear some values.
+ EXPECT_TRUE(value->SetSize(1));
+ EXPECT_EQ(1U, value->GetSize());
+ EXPECT_FALSE(list_value->IsValid()); // Value should be detached
+
+ EXPECT_EQ(VTYPE_BOOL, value->GetType(0));
+ EXPECT_EQ(VTYPE_INVALID, value->GetType(1));
+ EXPECT_EQ(VTYPE_INVALID, value->GetType(2));
+
+ // Clear all values.
+ EXPECT_TRUE(value->Clear());
+ EXPECT_EQ(0U, value->GetSize());
+}
+
+// Used to test access of list data on a different thread.
+class ListTask : public CefTask {
+ public:
+ ListTask(CefRefPtr<CefListValue> value,
+ char* binary_data,
+ size_t binary_data_size)
+ : value_(value),
+ binary_data_(binary_data),
+ binary_data_size_(binary_data_size) {}
+
+ void Execute() override { TestList(value_, binary_data_, binary_data_size_); }
+
+ private:
+ CefRefPtr<CefListValue> value_;
+ char* binary_data_;
+ size_t binary_data_size_;
+
+ IMPLEMENT_REFCOUNTING(ListTask);
+};
+
+void CreateAndCompareCopy(CefRefPtr<CefValue> value) {
+ CefRefPtr<CefValue> value2 = value->Copy();
+ EXPECT_TRUE(value->IsEqual(value));
+ EXPECT_TRUE(value->IsSame(value));
+ EXPECT_TRUE(value2->IsEqual(value2));
+ EXPECT_TRUE(value2->IsSame(value2));
+ EXPECT_TRUE(value->IsEqual(value2));
+ EXPECT_FALSE(value->IsSame(value2));
+ EXPECT_TRUE(value2->IsEqual(value));
+ EXPECT_FALSE(value2->IsSame(value));
+}
+
+CefRefPtr<CefBinaryValue> CreateBinaryValue() {
+ char binary_data[] = "This is my test data";
+ const size_t binary_data_size = sizeof(binary_data) - 1;
+
+ CefRefPtr<CefBinaryValue> binary_value =
+ CefBinaryValue::Create(binary_data, binary_data_size);
+ EXPECT_TRUE(binary_value.get());
+ EXPECT_TRUE(binary_value->IsValid());
+ EXPECT_FALSE(binary_value->IsOwned());
+ TestBinary(binary_value, binary_data, binary_data_size);
+ return binary_value;
+}
+
+CefRefPtr<CefListValue> CreateListValue() {
+ CefRefPtr<CefListValue> list_value = CefListValue::Create();
+ EXPECT_TRUE(list_value.get());
+ EXPECT_TRUE(list_value->IsValid());
+ EXPECT_FALSE(list_value->IsOwned());
+ EXPECT_FALSE(list_value->IsReadOnly());
+ EXPECT_TRUE(list_value->SetInt(0, kIntValue));
+ EXPECT_TRUE(list_value->SetInt(1, kDoubleValue));
+ return list_value;
+}
+
+const char* kKey1 = "key1";
+const char* kKey2 = "key2";
+
+CefRefPtr<CefDictionaryValue> CreateDictionaryValue() {
+ // Create the dictionary.
+ CefRefPtr<CefDictionaryValue> dict_value = CefDictionaryValue::Create();
+ EXPECT_TRUE(dict_value.get());
+ EXPECT_TRUE(dict_value->IsValid());
+ EXPECT_FALSE(dict_value->IsOwned());
+ EXPECT_FALSE(dict_value->IsReadOnly());
+ EXPECT_TRUE(dict_value->SetInt(kKey1, kIntValue));
+ EXPECT_TRUE(dict_value->SetInt(kKey2, kDoubleValue));
+ return dict_value;
+}
+
+} // namespace
+
+// Test binary value access.
+TEST(ValuesTest, BinaryAccess) {
+ char data[] = "This is my test data";
+
+ CefRefPtr<CefBinaryValue> value =
+ CefBinaryValue::Create(data, sizeof(data) - 1);
+ EXPECT_TRUE(value.get());
+ EXPECT_TRUE(value->IsValid());
+ EXPECT_FALSE(value->IsOwned());
+
+ // Test on this thread.
+ TestBinary(value, data, sizeof(data) - 1);
+}
+
+// Test binary value access on a different thread.
+TEST(ValuesTest, BinaryAccessOtherThread) {
+ char data[] = "This is my test data";
+
+ CefRefPtr<CefBinaryValue> value =
+ CefBinaryValue::Create(data, sizeof(data) - 1);
+ EXPECT_TRUE(value.get());
+ EXPECT_TRUE(value->IsValid());
+ EXPECT_FALSE(value->IsOwned());
+
+ // Test on a different thread.
+ CefPostTask(TID_UI, new BinaryTask(value, data, sizeof(data) - 1));
+ WaitForUIThread();
+}
+
+// Test dictionary value access.
+TEST(ValuesTest, DictionaryAccess) {
+ CefRefPtr<CefDictionaryValue> value = CefDictionaryValue::Create();
+ EXPECT_TRUE(value.get());
+ EXPECT_TRUE(value->IsValid());
+ EXPECT_FALSE(value->IsOwned());
+ EXPECT_FALSE(value->IsReadOnly());
+
+ char binary_data[] = "This is my test data";
+
+ // Test on this thread.
+ TestDictionary(value, binary_data, sizeof(binary_data) - 1);
+}
+
+// Test dictionary value access on a different thread.
+TEST(ValuesTest, DictionaryAccessOtherThread) {
+ CefRefPtr<CefDictionaryValue> value = CefDictionaryValue::Create();
+ EXPECT_TRUE(value.get());
+ EXPECT_TRUE(value->IsValid());
+ EXPECT_FALSE(value->IsOwned());
+ EXPECT_FALSE(value->IsReadOnly());
+
+ char binary_data[] = "This is my test data";
+
+ // Test on a different thread.
+ CefPostTask(TID_UI,
+ new DictionaryTask(value, binary_data, sizeof(binary_data) - 1));
+ WaitForUIThread();
+}
+
+// Test dictionary value nested detachment
+TEST(ValuesTest, DictionaryDetachment) {
+ CefRefPtr<CefDictionaryValue> value = CefDictionaryValue::Create();
+ EXPECT_TRUE(value.get());
+ EXPECT_TRUE(value->IsValid());
+ EXPECT_FALSE(value->IsOwned());
+ EXPECT_FALSE(value->IsReadOnly());
+
+ CefRefPtr<CefDictionaryValue> dictionary_value = CefDictionaryValue::Create();
+ CefRefPtr<CefDictionaryValue> dictionary_value2 =
+ CefDictionaryValue::Create();
+ CefRefPtr<CefDictionaryValue> dictionary_value3 =
+ CefDictionaryValue::Create();
+
+ dictionary_value2->SetDictionary(kDictionaryKey, dictionary_value3);
+ EXPECT_FALSE(dictionary_value3->IsValid());
+ dictionary_value->SetDictionary(kDictionaryKey, dictionary_value2);
+ EXPECT_FALSE(dictionary_value2->IsValid());
+ value->SetDictionary(kDictionaryKey, dictionary_value);
+ EXPECT_FALSE(dictionary_value->IsValid());
+
+ dictionary_value = value->GetDictionary(kDictionaryKey);
+ EXPECT_TRUE(dictionary_value.get());
+ EXPECT_TRUE(dictionary_value->IsValid());
+
+ dictionary_value2 = dictionary_value->GetDictionary(kDictionaryKey);
+ EXPECT_TRUE(dictionary_value2.get());
+ EXPECT_TRUE(dictionary_value2->IsValid());
+
+ dictionary_value3 = dictionary_value2->GetDictionary(kDictionaryKey);
+ EXPECT_TRUE(dictionary_value3.get());
+ EXPECT_TRUE(dictionary_value3->IsValid());
+
+ EXPECT_TRUE(value->Remove(kDictionaryKey));
+ EXPECT_FALSE(dictionary_value->IsValid());
+ EXPECT_FALSE(dictionary_value2->IsValid());
+ EXPECT_FALSE(dictionary_value3->IsValid());
+}
+
+// Test list value access.
+TEST(ValuesTest, ListAccess) {
+ CefRefPtr<CefListValue> value = CefListValue::Create();
+ EXPECT_TRUE(value.get());
+ EXPECT_TRUE(value->IsValid());
+ EXPECT_FALSE(value->IsOwned());
+ EXPECT_FALSE(value->IsReadOnly());
+
+ char binary_data[] = "This is my test data";
+
+ // Test on this thread.
+ TestList(value, binary_data, sizeof(binary_data) - 1);
+}
+
+// Test list value access on a different thread.
+TEST(ValuesTest, ListAccessOtherThread) {
+ CefRefPtr<CefListValue> value = CefListValue::Create();
+ EXPECT_TRUE(value.get());
+ EXPECT_TRUE(value->IsValid());
+ EXPECT_FALSE(value->IsOwned());
+ EXPECT_FALSE(value->IsReadOnly());
+
+ char binary_data[] = "This is my test data";
+
+ // Test on a different thread.
+ CefPostTask(TID_UI,
+ new ListTask(value, binary_data, sizeof(binary_data) - 1));
+ WaitForUIThread();
+}
+
+// Test list value nested detachment
+TEST(ValuesTest, ListDetachment) {
+ CefRefPtr<CefListValue> value = CefListValue::Create();
+ EXPECT_TRUE(value.get());
+ EXPECT_TRUE(value->IsValid());
+ EXPECT_FALSE(value->IsOwned());
+ EXPECT_FALSE(value->IsReadOnly());
+
+ CefRefPtr<CefListValue> list_value = CefListValue::Create();
+ CefRefPtr<CefListValue> list_value2 = CefListValue::Create();
+ CefRefPtr<CefListValue> list_value3 = CefListValue::Create();
+
+ list_value2->SetList(0, list_value3);
+ EXPECT_FALSE(list_value3->IsValid());
+ list_value->SetList(0, list_value2);
+ EXPECT_FALSE(list_value2->IsValid());
+ value->SetList(0, list_value);
+ EXPECT_FALSE(list_value->IsValid());
+
+ list_value = value->GetList(0);
+ EXPECT_TRUE(list_value.get());
+ EXPECT_TRUE(list_value->IsValid());
+
+ list_value2 = list_value->GetList(0);
+ EXPECT_TRUE(list_value2.get());
+ EXPECT_TRUE(list_value2->IsValid());
+
+ list_value3 = list_value2->GetList(0);
+ EXPECT_TRUE(list_value3.get());
+ EXPECT_TRUE(list_value3->IsValid());
+
+ EXPECT_TRUE(value->Remove(0));
+ EXPECT_FALSE(list_value->IsValid());
+ EXPECT_FALSE(list_value2->IsValid());
+ EXPECT_FALSE(list_value3->IsValid());
+}
+
+// Test get/set of a CefValue simple types.
+TEST(ValuesTest, ValueSimple) {
+ CefRefPtr<CefValue> value = CefValue::Create();
+ EXPECT_TRUE(value.get());
+ EXPECT_TRUE(value->IsValid());
+ EXPECT_FALSE(value->IsReadOnly());
+ EXPECT_FALSE(value->IsOwned());
+ EXPECT_EQ(VTYPE_NULL, value->GetType());
+ CreateAndCompareCopy(value);
+
+ EXPECT_TRUE(value->SetBool(true));
+ EXPECT_EQ(VTYPE_BOOL, value->GetType());
+ EXPECT_TRUE(value->GetBool());
+ EXPECT_TRUE(value->IsValid());
+ EXPECT_FALSE(value->IsReadOnly());
+ EXPECT_FALSE(value->IsOwned());
+ CreateAndCompareCopy(value);
+
+ EXPECT_TRUE(value->SetBool(false));
+ EXPECT_EQ(VTYPE_BOOL, value->GetType());
+ EXPECT_FALSE(value->GetBool());
+ EXPECT_TRUE(value->IsValid());
+ EXPECT_FALSE(value->IsReadOnly());
+ EXPECT_FALSE(value->IsOwned());
+ CreateAndCompareCopy(value);
+
+ EXPECT_TRUE(value->SetInt(3));
+ EXPECT_EQ(VTYPE_INT, value->GetType());
+ EXPECT_EQ(3, value->GetInt());
+ EXPECT_TRUE(value->IsValid());
+ EXPECT_FALSE(value->IsReadOnly());
+ EXPECT_FALSE(value->IsOwned());
+ CreateAndCompareCopy(value);
+
+ EXPECT_TRUE(value->SetDouble(5.665));
+ EXPECT_EQ(VTYPE_DOUBLE, value->GetType());
+ EXPECT_EQ(5.665, value->GetDouble());
+ EXPECT_TRUE(value->IsValid());
+ EXPECT_FALSE(value->IsReadOnly());
+ EXPECT_FALSE(value->IsOwned());
+ CreateAndCompareCopy(value);
+
+ const char* str = "Test string";
+ EXPECT_TRUE(value->SetString(str));
+ EXPECT_EQ(VTYPE_STRING, value->GetType());
+ EXPECT_STREQ(str, value->GetString().ToString().data());
+ EXPECT_TRUE(value->IsValid());
+ EXPECT_FALSE(value->IsReadOnly());
+ EXPECT_FALSE(value->IsOwned());
+ CreateAndCompareCopy(value);
+
+ EXPECT_TRUE(value->SetNull());
+ EXPECT_EQ(VTYPE_NULL, value->GetType());
+ EXPECT_TRUE(value->IsValid());
+ EXPECT_FALSE(value->IsReadOnly());
+ EXPECT_FALSE(value->IsOwned());
+ CreateAndCompareCopy(value);
+}
+
+// Test association of a CefValue simple type with a CefListValue.
+TEST(ValuesTest, ValueSimpleToList) {
+ const double double_value = 5.665;
+
+ CefRefPtr<CefValue> value = CefValue::Create();
+ EXPECT_TRUE(value->SetDouble(double_value));
+
+ // Add the value to the target list.
+ CefRefPtr<CefListValue> target_list = CefListValue::Create();
+ EXPECT_TRUE(target_list->SetValue(0, value));
+
+ // Test the value in the target list.
+ EXPECT_EQ(VTYPE_DOUBLE, target_list->GetType(0));
+ EXPECT_EQ(double_value, target_list->GetDouble(0));
+
+ // Get the value from the target list.
+ CefRefPtr<CefValue> value2 = target_list->GetValue(0);
+ EXPECT_TRUE(value2.get());
+ EXPECT_FALSE(value2->IsOwned());
+ EXPECT_FALSE(value2->IsReadOnly());
+ EXPECT_EQ(VTYPE_DOUBLE, value2->GetType());
+ EXPECT_EQ(double_value, value2->GetDouble());
+
+ // Values are equal but not the same.
+ EXPECT_TRUE(value->IsEqual(value2));
+ EXPECT_TRUE(value2->IsEqual(value));
+ EXPECT_FALSE(value->IsSame(value2));
+ EXPECT_FALSE(value2->IsSame(value));
+
+ // Change the value in the target list.
+ EXPECT_TRUE(target_list->SetInt(0, 5));
+ EXPECT_EQ(VTYPE_INT, target_list->GetType(0));
+ EXPECT_EQ(5, target_list->GetInt(0));
+
+ // The other values are still valid.
+ EXPECT_TRUE(value->IsValid());
+ EXPECT_TRUE(value2->IsValid());
+}
+
+// Test association of a CefValue simple type with a CefDictionaryValue.
+TEST(ValuesTest, ValueSimpleToDictionary) {
+ const double double_value = 5.665;
+ const char* key = "key";
+
+ CefRefPtr<CefValue> value = CefValue::Create();
+ EXPECT_TRUE(value->SetDouble(double_value));
+
+ // Add the value to the target dictionary.
+ CefRefPtr<CefDictionaryValue> target_dict = CefDictionaryValue::Create();
+ EXPECT_TRUE(target_dict->SetValue(key, value));
+
+ // Test the value in the target dictionary.
+ EXPECT_EQ(VTYPE_DOUBLE, target_dict->GetType(key));
+ EXPECT_EQ(double_value, target_dict->GetDouble(key));
+
+ // Get the value from the target dictionary.
+ CefRefPtr<CefValue> value2 = target_dict->GetValue(key);
+ EXPECT_TRUE(value2.get());
+ EXPECT_FALSE(value2->IsOwned());
+ EXPECT_FALSE(value2->IsReadOnly());
+ EXPECT_EQ(VTYPE_DOUBLE, value2->GetType());
+ EXPECT_EQ(double_value, value2->GetDouble());
+
+ // Values are equal but not the same.
+ EXPECT_TRUE(value->IsEqual(value2));
+ EXPECT_TRUE(value2->IsEqual(value));
+ EXPECT_FALSE(value->IsSame(value2));
+ EXPECT_FALSE(value2->IsSame(value));
+
+ // Change the value in the target dictionary.
+ EXPECT_TRUE(target_dict->SetInt(key, 5));
+ EXPECT_EQ(VTYPE_INT, target_dict->GetType(key));
+ EXPECT_EQ(5, target_dict->GetInt(key));
+
+ // The other values are still valid.
+ EXPECT_TRUE(value->IsValid());
+ EXPECT_TRUE(value2->IsValid());
+}
+
+// Test get/set of a CefValue binary type.
+TEST(ValuesTest, ValueBinary) {
+ // Create the binary.
+ CefRefPtr<CefBinaryValue> binary_value = CreateBinaryValue();
+
+ // Create the value.
+ CefRefPtr<CefValue> value = CefValue::Create();
+ EXPECT_TRUE(value->SetBinary(binary_value));
+ EXPECT_EQ(VTYPE_BINARY, value->GetType());
+ EXPECT_TRUE(value->IsValid());
+ EXPECT_TRUE(value->IsReadOnly()); // Binary values are always read-only.
+ EXPECT_FALSE(value->IsOwned());
+ CreateAndCompareCopy(value);
+
+ // Get the binary reference from the value.
+ CefRefPtr<CefBinaryValue> binary_value2 = value->GetBinary();
+ EXPECT_TRUE(binary_value2.get());
+ EXPECT_TRUE(binary_value2->IsValid());
+ EXPECT_FALSE(binary_value2->IsOwned());
+
+ // The binaries are the same and equal.
+ TestBinaryEqual(binary_value, binary_value2);
+ EXPECT_TRUE(binary_value->IsSame(binary_value2));
+ EXPECT_TRUE(binary_value2->IsSame(binary_value));
+}
+
+// Test association of a CefValue binary with a CefListValue.
+TEST(ValuesTest, ValueBinaryToList) {
+ // Create the binary.
+ CefRefPtr<CefBinaryValue> binary_value = CreateBinaryValue();
+
+ // Add the binary to a value.
+ CefRefPtr<CefValue> value = CefValue::Create();
+ EXPECT_TRUE(value->SetBinary(binary_value));
+
+ // Add the value to the target list.
+ CefRefPtr<CefListValue> target_list = CefListValue::Create();
+ EXPECT_TRUE(target_list->SetValue(0, value));
+
+ // The binary value is now owned by the target list.
+ EXPECT_FALSE(binary_value->IsValid());
+
+ // The value is still valid and points to the new reference list.
+ EXPECT_TRUE(value->IsValid());
+
+ CefRefPtr<CefBinaryValue> binary_value2 = value->GetBinary();
+ CefRefPtr<CefBinaryValue> binary_value3 = target_list->GetBinary(0);
+ CefRefPtr<CefValue> value2 = target_list->GetValue(0);
+ CefRefPtr<CefBinaryValue> binary_value4 = value2->GetBinary();
+
+ // All values are owned by the target list.
+ EXPECT_TRUE(value->IsOwned());
+ EXPECT_TRUE(value2->IsOwned());
+ EXPECT_TRUE(binary_value2->IsOwned());
+ EXPECT_TRUE(binary_value3->IsOwned());
+ EXPECT_TRUE(binary_value4->IsOwned());
+
+ // All values are the same.
+ EXPECT_TRUE(binary_value2->IsSame(binary_value3));
+ TestBinaryEqual(binary_value2, binary_value3);
+ EXPECT_TRUE(binary_value2->IsSame(binary_value4));
+ TestBinaryEqual(binary_value2, binary_value4);
+
+ // Change the value to something else.
+ EXPECT_TRUE(target_list->SetInt(0, kIntValue));
+ EXPECT_EQ(VTYPE_INT, target_list->GetType(0));
+ EXPECT_EQ(kIntValue, target_list->GetInt(0));
+
+ // Now the references are invalid.
+ EXPECT_FALSE(value->IsValid());
+ EXPECT_FALSE(value2->IsValid());
+ EXPECT_FALSE(binary_value2->IsValid());
+ EXPECT_FALSE(binary_value3->IsValid());
+ EXPECT_FALSE(binary_value4->IsValid());
+
+ // Verify that adding a binary to a list directly invalidates both the binary
+ // and the value that references it.
+ binary_value = CreateBinaryValue();
+ value = CefValue::Create();
+ EXPECT_TRUE(value->SetBinary(binary_value));
+ target_list->SetBinary(0, binary_value);
+ EXPECT_FALSE(binary_value->IsValid());
+ EXPECT_FALSE(value->IsValid());
+}
+
+// Test association of a CefValue binary with a CefDictionaryValue.
+TEST(ValuesTest, ValueBinaryToDictionary) {
+ const char* key = "key";
+
+ // Create the binary.
+ CefRefPtr<CefBinaryValue> binary_value = CreateBinaryValue();
+
+ // Add the binary to a value.
+ CefRefPtr<CefValue> value = CefValue::Create();
+ EXPECT_TRUE(value->SetBinary(binary_value));
+
+ // Add the value to the target dictionary.
+ CefRefPtr<CefDictionaryValue> target_dict = CefDictionaryValue::Create();
+ EXPECT_TRUE(target_dict->SetValue(key, value));
+
+ // The list value is now owned by the target dictionary.
+ EXPECT_FALSE(binary_value->IsValid());
+
+ // The value is still valid and points to the new reference list.
+ EXPECT_TRUE(value->IsValid());
+
+ CefRefPtr<CefBinaryValue> binary_value2 = value->GetBinary();
+ CefRefPtr<CefBinaryValue> binary_value3 = target_dict->GetBinary(key);
+ CefRefPtr<CefValue> value2 = target_dict->GetValue(key);
+ CefRefPtr<CefBinaryValue> binary_value4 = value2->GetBinary();
+
+ // All values are owned by the target dictionary.
+ EXPECT_TRUE(value->IsOwned());
+ EXPECT_TRUE(value2->IsOwned());
+ EXPECT_TRUE(binary_value2->IsOwned());
+ EXPECT_TRUE(binary_value3->IsOwned());
+ EXPECT_TRUE(binary_value4->IsOwned());
+
+ // All values are the same.
+ EXPECT_TRUE(binary_value2->IsSame(binary_value3));
+ TestBinaryEqual(binary_value2, binary_value3);
+ EXPECT_TRUE(binary_value2->IsSame(binary_value4));
+ TestBinaryEqual(binary_value2, binary_value4);
+
+ // Change the value to something else.
+ EXPECT_TRUE(target_dict->SetInt(key, kIntValue));
+ EXPECT_EQ(VTYPE_INT, target_dict->GetType(key));
+ EXPECT_EQ(kIntValue, target_dict->GetInt(key));
+
+ // Now the references are invalid.
+ EXPECT_FALSE(value->IsValid());
+ EXPECT_FALSE(value2->IsValid());
+ EXPECT_FALSE(binary_value2->IsValid());
+ EXPECT_FALSE(binary_value3->IsValid());
+ EXPECT_FALSE(binary_value4->IsValid());
+
+ // Verify that adding a binary to a dictionary directly invalidates both the
+ // binary and the value that references it.
+ binary_value = CreateBinaryValue();
+ value = CefValue::Create();
+ EXPECT_TRUE(value->SetBinary(binary_value));
+ target_dict->SetBinary(key, binary_value);
+ EXPECT_FALSE(binary_value->IsValid());
+ EXPECT_FALSE(value->IsValid());
+}
+
+// Test get/set of a CefValue list type.
+TEST(ValuesTest, ValueList) {
+ // Create the list.
+ CefRefPtr<CefListValue> list_value = CreateListValue();
+
+ // Create the value.
+ CefRefPtr<CefValue> value = CefValue::Create();
+ EXPECT_TRUE(value->SetList(list_value));
+ EXPECT_EQ(VTYPE_LIST, value->GetType());
+ EXPECT_TRUE(value->IsValid());
+ EXPECT_FALSE(value->IsReadOnly());
+ EXPECT_FALSE(value->IsOwned());
+ CreateAndCompareCopy(value);
+
+ // Get the list reference from the value.
+ CefRefPtr<CefListValue> list_value2 = value->GetList();
+ EXPECT_TRUE(list_value2.get());
+ EXPECT_TRUE(list_value2->IsValid());
+ EXPECT_FALSE(list_value2->IsOwned());
+ EXPECT_FALSE(list_value2->IsReadOnly());
+
+ // The lists are the same and equal.
+ TestListEqual(list_value, list_value2);
+ EXPECT_TRUE(list_value->IsSame(list_value2));
+ EXPECT_TRUE(list_value2->IsSame(list_value));
+
+ // Change a value in one list and verify that it's changed in the other list.
+ EXPECT_TRUE(list_value->SetString(0, kStringValue));
+ EXPECT_EQ(VTYPE_STRING, list_value->GetType(0));
+ EXPECT_STREQ(kStringValue, list_value->GetString(0).ToString().data());
+}
+
+// Test association of a CefValue list with a CefListValue.
+TEST(ValuesTest, ValueListToList) {
+ // Create the list.
+ CefRefPtr<CefListValue> list_value = CreateListValue();
+
+ // Add the list to a value.
+ CefRefPtr<CefValue> value = CefValue::Create();
+ EXPECT_TRUE(value->SetList(list_value));
+
+ // Add the value to the target list.
+ CefRefPtr<CefListValue> target_list = CefListValue::Create();
+ EXPECT_TRUE(target_list->SetValue(0, value));
+
+ // The list value is now owned by the target list.
+ EXPECT_FALSE(list_value->IsValid());
+
+ // The value is still valid and points to the new reference list.
+ EXPECT_TRUE(value->IsValid());
+
+ CefRefPtr<CefListValue> list_value2 = value->GetList();
+ CefRefPtr<CefListValue> list_value3 = target_list->GetList(0);
+ CefRefPtr<CefValue> value2 = target_list->GetValue(0);
+ CefRefPtr<CefListValue> list_value4 = value2->GetList();
+
+ // All values are owned by the target list.
+ EXPECT_TRUE(value->IsOwned());
+ EXPECT_TRUE(value2->IsOwned());
+ EXPECT_TRUE(list_value2->IsOwned());
+ EXPECT_TRUE(list_value3->IsOwned());
+ EXPECT_TRUE(list_value4->IsOwned());
+
+ // All values are the same.
+ EXPECT_TRUE(list_value2->IsSame(list_value3));
+ TestListEqual(list_value2, list_value3);
+ EXPECT_TRUE(list_value2->IsSame(list_value4));
+ TestListEqual(list_value2, list_value4);
+
+ // Change the value to something else.
+ EXPECT_TRUE(target_list->SetInt(0, kIntValue));
+ EXPECT_EQ(VTYPE_INT, target_list->GetType(0));
+ EXPECT_EQ(kIntValue, target_list->GetInt(0));
+
+ // Now the references are invalid.
+ EXPECT_FALSE(value->IsValid());
+ EXPECT_FALSE(value2->IsValid());
+ EXPECT_FALSE(list_value2->IsValid());
+ EXPECT_FALSE(list_value3->IsValid());
+ EXPECT_FALSE(list_value4->IsValid());
+
+ // Verify that adding a list to a list directly invalidates both the list
+ // and the value that references it.
+ list_value = CreateListValue();
+ value = CefValue::Create();
+ EXPECT_TRUE(value->SetList(list_value));
+ target_list->SetList(0, list_value);
+ EXPECT_FALSE(list_value->IsValid());
+ EXPECT_FALSE(value->IsValid());
+}
+
+// Test association of a CefValue list with a CefDictionaryValue.
+TEST(ValuesTest, ValueListToDictionary) {
+ const char* key = "key";
+
+ // Create the list.
+ CefRefPtr<CefListValue> list_value = CreateListValue();
+
+ // Add the list to a value.
+ CefRefPtr<CefValue> value = CefValue::Create();
+ EXPECT_TRUE(value->SetList(list_value));
+
+ // Add the value to the target dictionary.
+ CefRefPtr<CefDictionaryValue> target_dict = CefDictionaryValue::Create();
+ EXPECT_TRUE(target_dict->SetValue(key, value));
+
+ // The list value is now owned by the target dictionary.
+ EXPECT_FALSE(list_value->IsValid());
+
+ // The value is still valid and points to the new reference list.
+ EXPECT_TRUE(value->IsValid());
+
+ CefRefPtr<CefListValue> list_value2 = value->GetList();
+ CefRefPtr<CefListValue> list_value3 = target_dict->GetList(key);
+ CefRefPtr<CefValue> value2 = target_dict->GetValue(key);
+ CefRefPtr<CefListValue> list_value4 = value2->GetList();
+
+ // All values are owned by the target dictionary.
+ EXPECT_TRUE(value->IsOwned());
+ EXPECT_TRUE(value2->IsOwned());
+ EXPECT_TRUE(list_value2->IsOwned());
+ EXPECT_TRUE(list_value3->IsOwned());
+ EXPECT_TRUE(list_value4->IsOwned());
+
+ // All values are the same.
+ EXPECT_TRUE(list_value2->IsSame(list_value3));
+ TestListEqual(list_value2, list_value3);
+ EXPECT_TRUE(list_value2->IsSame(list_value4));
+ TestListEqual(list_value2, list_value4);
+
+ // Change the value to something else.
+ EXPECT_TRUE(target_dict->SetInt(key, kIntValue));
+ EXPECT_EQ(VTYPE_INT, target_dict->GetType(key));
+ EXPECT_EQ(kIntValue, target_dict->GetInt(key));
+
+ // Now the references are invalid.
+ EXPECT_FALSE(value->IsValid());
+ EXPECT_FALSE(value2->IsValid());
+ EXPECT_FALSE(list_value2->IsValid());
+ EXPECT_FALSE(list_value3->IsValid());
+ EXPECT_FALSE(list_value4->IsValid());
+
+ // Verify that adding a list to a dictionary directly invalidates both the
+ // list and the value that references it.
+ list_value = CreateListValue();
+ value = CefValue::Create();
+ EXPECT_TRUE(value->SetList(list_value));
+ target_dict->SetList(key, list_value);
+ EXPECT_FALSE(list_value->IsValid());
+ EXPECT_FALSE(value->IsValid());
+}
+
+// Test get/set of a CefValue dictionary type.
+TEST(ValuesTest, ValueDictionary) {
+ // Create the dictionary.
+ CefRefPtr<CefDictionaryValue> dict_value = CreateDictionaryValue();
+
+ // Create the value.
+ CefRefPtr<CefValue> value = CefValue::Create();
+ EXPECT_TRUE(value->SetDictionary(dict_value));
+ EXPECT_EQ(VTYPE_DICTIONARY, value->GetType());
+ EXPECT_TRUE(value->IsValid());
+ EXPECT_FALSE(value->IsReadOnly());
+ EXPECT_FALSE(value->IsOwned());
+ CreateAndCompareCopy(value);
+
+ // Get the dictionary reference from the value.
+ CefRefPtr<CefDictionaryValue> dict_value2 = value->GetDictionary();
+ EXPECT_TRUE(dict_value2.get());
+ EXPECT_TRUE(dict_value2->IsValid());
+ EXPECT_FALSE(dict_value2->IsOwned());
+ EXPECT_FALSE(dict_value2->IsReadOnly());
+
+ // The dictionaries are the same and equal.
+ TestDictionaryEqual(dict_value, dict_value2);
+ EXPECT_TRUE(dict_value->IsSame(dict_value2));
+ EXPECT_TRUE(dict_value2->IsSame(dict_value));
+
+ // Change a value in one dictionary and verify that it's changed in the other
+ // dictionary.
+ EXPECT_TRUE(dict_value->SetString(kKey1, kStringValue));
+ EXPECT_EQ(VTYPE_STRING, dict_value->GetType(kKey1));
+ EXPECT_STREQ(kStringValue, dict_value->GetString(kKey1).ToString().data());
+}
+
+// Test association of a CefValue dictionary with a CefListValue.
+TEST(ValuesTest, ValueDictionaryToList) {
+ // Create the dictionary.
+ CefRefPtr<CefDictionaryValue> dict_value = CreateDictionaryValue();
+
+ // Add the list to a value.
+ CefRefPtr<CefValue> value = CefValue::Create();
+ EXPECT_TRUE(value->SetDictionary(dict_value));
+
+ // Add the value to the target list.
+ CefRefPtr<CefListValue> target_list = CefListValue::Create();
+ EXPECT_TRUE(target_list->SetValue(0, value));
+
+ // The list value is now owned by the target list.
+ EXPECT_FALSE(dict_value->IsValid());
+
+ // The value is still valid and points to the new reference list.
+ EXPECT_TRUE(value->IsValid());
+
+ CefRefPtr<CefDictionaryValue> dict_value2 = value->GetDictionary();
+ CefRefPtr<CefDictionaryValue> dict_value3 = target_list->GetDictionary(0);
+ CefRefPtr<CefValue> value2 = target_list->GetValue(0);
+ CefRefPtr<CefDictionaryValue> dict_value4 = value2->GetDictionary();
+
+ // All values are owned by the target list.
+ EXPECT_TRUE(value->IsOwned());
+ EXPECT_TRUE(value2->IsOwned());
+ EXPECT_TRUE(dict_value2->IsOwned());
+ EXPECT_TRUE(dict_value3->IsOwned());
+ EXPECT_TRUE(dict_value4->IsOwned());
+
+ // All values are the same.
+ EXPECT_TRUE(dict_value2->IsSame(dict_value3));
+ TestDictionaryEqual(dict_value2, dict_value3);
+ EXPECT_TRUE(dict_value2->IsSame(dict_value4));
+ TestDictionaryEqual(dict_value2, dict_value4);
+
+ // Change the value to something else.
+ EXPECT_TRUE(target_list->SetInt(0, kIntValue));
+ EXPECT_EQ(VTYPE_INT, target_list->GetType(0));
+ EXPECT_EQ(kIntValue, target_list->GetInt(0));
+
+ // Now the references are invalid.
+ EXPECT_FALSE(value->IsValid());
+ EXPECT_FALSE(value2->IsValid());
+ EXPECT_FALSE(dict_value2->IsValid());
+ EXPECT_FALSE(dict_value3->IsValid());
+ EXPECT_FALSE(dict_value4->IsValid());
+
+ // Verify that adding a dictionary to a list directly invalidates both the
+ // dictionary and the value that references it.
+ dict_value = CreateDictionaryValue();
+ value = CefValue::Create();
+ EXPECT_TRUE(value->SetDictionary(dict_value));
+ target_list->SetDictionary(0, dict_value);
+ EXPECT_FALSE(dict_value->IsValid());
+ EXPECT_FALSE(value->IsValid());
+}
+
+// Test association of a CefValue dictionary with a CefDictionaryValue.
+TEST(ValuesTest, ValueDictionaryToDictionary) {
+ const char* key = "key";
+
+ // Create the dictionary.
+ CefRefPtr<CefDictionaryValue> dict_value = CreateDictionaryValue();
+
+ // Add the list to a value.
+ CefRefPtr<CefValue> value = CefValue::Create();
+ EXPECT_TRUE(value->SetDictionary(dict_value));
+
+ // Add the value to the target dictionary.
+ CefRefPtr<CefDictionaryValue> target_dict = CefDictionaryValue::Create();
+ EXPECT_TRUE(target_dict->SetValue(key, value));
+
+ // The list value is now owned by the target dictionary.
+ EXPECT_FALSE(dict_value->IsValid());
+
+ // The value is still valid and points to the new reference list.
+ EXPECT_TRUE(value->IsValid());
+
+ CefRefPtr<CefDictionaryValue> dict_value2 = value->GetDictionary();
+ CefRefPtr<CefDictionaryValue> dict_value3 = target_dict->GetDictionary(key);
+ CefRefPtr<CefValue> value2 = target_dict->GetValue(key);
+ CefRefPtr<CefDictionaryValue> dict_value4 = value2->GetDictionary();
+
+ // All values are owned by the target dictionary.
+ EXPECT_TRUE(value->IsOwned());
+ EXPECT_TRUE(value2->IsOwned());
+ EXPECT_TRUE(dict_value2->IsOwned());
+ EXPECT_TRUE(dict_value3->IsOwned());
+ EXPECT_TRUE(dict_value4->IsOwned());
+
+ // All values are the same.
+ EXPECT_TRUE(dict_value2->IsSame(dict_value3));
+ TestDictionaryEqual(dict_value2, dict_value3);
+ EXPECT_TRUE(dict_value2->IsSame(dict_value4));
+ TestDictionaryEqual(dict_value2, dict_value4);
+
+ // Change the value to something else.
+ EXPECT_TRUE(target_dict->SetInt(key, kIntValue));
+ EXPECT_EQ(VTYPE_INT, target_dict->GetType(key));
+ EXPECT_EQ(kIntValue, target_dict->GetInt(key));
+
+ // Now the references are invalid.
+ EXPECT_FALSE(value->IsValid());
+ EXPECT_FALSE(value2->IsValid());
+ EXPECT_FALSE(dict_value2->IsValid());
+ EXPECT_FALSE(dict_value3->IsValid());
+ EXPECT_FALSE(dict_value4->IsValid());
+
+ // Verify that adding a dictionary to a dictionary directly invalidates both
+ // the dictionary and the value that references it.
+ dict_value = CreateDictionaryValue();
+ value = CefValue::Create();
+ EXPECT_TRUE(value->SetDictionary(dict_value));
+ target_dict->SetDictionary(key, dict_value);
+ EXPECT_FALSE(dict_value->IsValid());
+ EXPECT_FALSE(value->IsValid());
+}
diff --git a/tests/ceftests/version_unittest.cc b/tests/ceftests/version_unittest.cc
new file mode 100644
index 00000000..54776e5c
--- /dev/null
+++ b/tests/ceftests/version_unittest.cc
@@ -0,0 +1,24 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "include/cef_api_hash.h"
+#include "include/cef_version.h"
+#include "tests/gtest/include/gtest/gtest.h"
+
+TEST(VersionTest, VersionInfo) {
+ EXPECT_EQ(CEF_VERSION_MAJOR, cef_version_info(0));
+ EXPECT_EQ(CEF_VERSION_MINOR, cef_version_info(1));
+ EXPECT_EQ(CEF_VERSION_PATCH, cef_version_info(2));
+ EXPECT_EQ(CEF_COMMIT_NUMBER, cef_version_info(3));
+ EXPECT_EQ(CHROME_VERSION_MAJOR, cef_version_info(4));
+ EXPECT_EQ(CHROME_VERSION_MINOR, cef_version_info(5));
+ EXPECT_EQ(CHROME_VERSION_BUILD, cef_version_info(6));
+ EXPECT_EQ(CHROME_VERSION_PATCH, cef_version_info(7));
+}
+
+TEST(VersionTest, ApiHash) {
+ EXPECT_STREQ(CEF_API_HASH_PLATFORM, cef_api_hash(0));
+ EXPECT_STREQ(CEF_API_HASH_UNIVERSAL, cef_api_hash(1));
+ EXPECT_STREQ(CEF_COMMIT_HASH, cef_api_hash(2));
+}
diff --git a/tests/ceftests/views/button_unittest.cc b/tests/ceftests/views/button_unittest.cc
new file mode 100644
index 00000000..5c0c73b6
--- /dev/null
+++ b/tests/ceftests/views/button_unittest.cc
@@ -0,0 +1,662 @@
+// Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "include/base/cef_callback.h"
+#include "include/views/cef_button.h"
+#include "include/views/cef_button_delegate.h"
+#include "include/views/cef_label_button.h"
+#include "include/views/cef_menu_button.h"
+#include "include/views/cef_menu_button_delegate.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "tests/ceftests/image_util.h"
+#include "tests/ceftests/test_handler.h"
+#include "tests/ceftests/thread_helper.h"
+#include "tests/ceftests/views/test_window_delegate.h"
+#include "tests/gtest/include/gtest/gtest.h"
+
+#define BUTTON_TEST(name) UI_THREAD_TEST(ViewsButtonTest, name)
+#define BUTTON_TEST_ASYNC(name) UI_THREAD_TEST_ASYNC(ViewsButtonTest, name)
+
+namespace {
+
+CefRefPtr<CefImage> CreateIconImage() {
+ CefRefPtr<CefImage> image = CefImage::CreateImage();
+ image_util::LoadIconImage(image, 1.0);
+ image_util::LoadIconImage(image, 2.0);
+ return image;
+}
+
+const char kButtonText[] = "My Button";
+
+void VerifyButtonStyle(CefRefPtr<CefButton> button) {
+ // Test state.
+ EXPECT_EQ(CEF_BUTTON_STATE_NORMAL, button->GetState());
+ button->SetState(CEF_BUTTON_STATE_HOVERED);
+ EXPECT_EQ(CEF_BUTTON_STATE_HOVERED, button->GetState());
+ button->SetState(CEF_BUTTON_STATE_PRESSED);
+ EXPECT_EQ(CEF_BUTTON_STATE_PRESSED, button->GetState());
+ button->SetState(CEF_BUTTON_STATE_DISABLED);
+ EXPECT_EQ(CEF_BUTTON_STATE_DISABLED, button->GetState());
+ button->SetState(CEF_BUTTON_STATE_NORMAL);
+
+ button->SetTooltipText("Some tooltip text");
+ button->SetAccessibleName("MyButton");
+}
+
+void VerifyLabelButtonImage(CefRefPtr<CefLabelButton> button,
+ cef_button_state_t state,
+ CefRefPtr<CefImage> image) {
+ EXPECT_FALSE(button->GetImage(state).get()) << "state = " << state;
+ button->SetImage(state, image);
+ EXPECT_TRUE(image->IsSame(button->GetImage(state))) << "state = " << state;
+ button->SetImage(state, nullptr);
+ EXPECT_FALSE(button->GetImage(state).get()) << "state = " << state;
+}
+
+void VerifyLabelButtonStyle(CefRefPtr<CefLabelButton> button) {
+ VerifyButtonStyle(button);
+
+ // Test set/get text.
+ EXPECT_STREQ(kButtonText, button->GetText().ToString().c_str());
+ const char kText[] = "My text";
+ button->SetText(kText);
+ EXPECT_STREQ(kText, button->GetText().ToString().c_str());
+
+ // Test images.
+ CefRefPtr<CefImage> image = CreateIconImage();
+ VerifyLabelButtonImage(button, CEF_BUTTON_STATE_NORMAL, image);
+ VerifyLabelButtonImage(button, CEF_BUTTON_STATE_HOVERED, image);
+ VerifyLabelButtonImage(button, CEF_BUTTON_STATE_PRESSED, image);
+ VerifyLabelButtonImage(button, CEF_BUTTON_STATE_DISABLED, image);
+
+ // Test colors.
+ const cef_color_t color = CefColorSetARGB(255, 255, 0, 255);
+ button->SetTextColor(CEF_BUTTON_STATE_NORMAL, color);
+ button->SetTextColor(CEF_BUTTON_STATE_HOVERED, color);
+ button->SetTextColor(CEF_BUTTON_STATE_PRESSED, color);
+ button->SetTextColor(CEF_BUTTON_STATE_DISABLED, color);
+ button->SetEnabledTextColors(color);
+
+ // Test alignment.
+ button->SetHorizontalAlignment(CEF_HORIZONTAL_ALIGNMENT_LEFT);
+ button->SetHorizontalAlignment(CEF_HORIZONTAL_ALIGNMENT_CENTER);
+ button->SetHorizontalAlignment(CEF_HORIZONTAL_ALIGNMENT_RIGHT);
+
+ // Test fonts.
+ button->SetFontList("Arial, 14px");
+
+ // Test sizes.
+ button->SetMinimumSize(CefSize(100, 100));
+ button->SetMaximumSize(CefSize(100, 100));
+}
+
+void VerifyMenuButtonStyle(CefRefPtr<CefMenuButton> button) {
+ VerifyLabelButtonStyle(button);
+}
+
+class EmptyMenuButtonDelegate : public CefMenuButtonDelegate {
+ public:
+ EmptyMenuButtonDelegate() {}
+
+ void OnMenuButtonPressed(
+ CefRefPtr<CefMenuButton> menu_button,
+ const CefPoint& screen_point,
+ CefRefPtr<CefMenuButtonPressedLock> button_pressed_lock) override {
+ EXPECT_TRUE(false); // Not reached.
+ }
+
+ void OnButtonPressed(CefRefPtr<CefButton> button) override {
+ EXPECT_TRUE(false); // Not reached.
+ }
+
+ private:
+ IMPLEMENT_REFCOUNTING(EmptyMenuButtonDelegate);
+ DISALLOW_COPY_AND_ASSIGN(EmptyMenuButtonDelegate);
+};
+
+void RunLabelButtonStyle(CefRefPtr<CefWindow> window) {
+ CefRefPtr<CefLabelButton> button = CefLabelButton::CreateLabelButton(
+ new EmptyMenuButtonDelegate(), kButtonText);
+
+ // Must be added to a parent window before retrieving the style to avoid
+ // a CHECK() in View::GetNativeTheme(). See https://crbug.com/1056756.
+ window->AddChildView(button);
+ window->Layout();
+
+ VerifyLabelButtonStyle(button);
+}
+
+void LabelButtonStyleImpl(CefRefPtr<CefWaitableEvent> event) {
+ auto config = std::make_unique<TestWindowDelegate::Config>();
+ config->on_window_created = base::BindOnce(RunLabelButtonStyle);
+ TestWindowDelegate::RunTest(event, std::move(config));
+}
+
+void RunMenuButtonStyle(CefRefPtr<CefWindow> window) {
+ CefRefPtr<CefMenuButton> button = CefMenuButton::CreateMenuButton(
+ new EmptyMenuButtonDelegate(), kButtonText);
+
+ // Must be added to a parent window before retrieving the style to avoid
+ // a CHECK() in View::GetNativeTheme(). See https://crbug.com/1056756.
+ window->AddChildView(button);
+ window->Layout();
+
+ VerifyMenuButtonStyle(button);
+}
+
+void MenuButtonStyleImpl(CefRefPtr<CefWaitableEvent> event) {
+ auto config = std::make_unique<TestWindowDelegate::Config>();
+ config->on_window_created = base::BindOnce(RunMenuButtonStyle);
+ TestWindowDelegate::RunTest(event, std::move(config));
+}
+
+} // namespace
+
+// Test Button getters/setters.
+BUTTON_TEST_ASYNC(LabelButtonStyle)
+BUTTON_TEST_ASYNC(MenuButtonStyle)
+
+namespace {
+
+// Mouse click delay in MS.
+const int kClickDelayMS = 100;
+
+const int kButtonID = 1;
+
+class TestButtonDelegate : public CefButtonDelegate {
+ public:
+ TestButtonDelegate() {}
+
+ void OnButtonPressed(CefRefPtr<CefButton> button) override {
+ EXPECT_TRUE(button.get());
+ EXPECT_EQ(button->GetID(), kButtonID);
+
+ // Complete the test by closing the window.
+ button->GetWindow()->Close();
+ }
+
+ private:
+ IMPLEMENT_REFCOUNTING(TestButtonDelegate);
+ DISALLOW_COPY_AND_ASSIGN(TestButtonDelegate);
+};
+
+void ClickButton(CefRefPtr<CefWindow> window, int button_id) {
+ CefRefPtr<CefView> button = window->GetViewForID(button_id);
+ EXPECT_TRUE(button->AsButton());
+
+ // Determine the middle of the button in screen coordinates.
+ const CefRect& bounds = button->GetBoundsInScreen();
+ const CefPoint& click_point =
+ CefPoint(bounds.x + bounds.width / 2, bounds.y + bounds.height / 2);
+
+ // Click the button.
+ window->SendMouseMove(click_point.x, click_point.y);
+ window->SendMouseEvents(MBT_LEFT, true, true);
+}
+
+void AddImage(CefRefPtr<CefLabelButton> button) {
+ CefRefPtr<CefImage> image = CreateIconImage();
+ button->SetImage(CEF_BUTTON_STATE_NORMAL, image);
+}
+
+void RunLabelButtonClick(bool with_text,
+ bool with_image,
+ CefRefPtr<CefWindow> window) {
+ CefRefPtr<CefLabelButton> button = CefLabelButton::CreateLabelButton(
+ new TestButtonDelegate(), with_text ? kButtonText : "");
+ button->SetID(kButtonID);
+
+ EXPECT_TRUE(button->AsButton());
+ EXPECT_TRUE(button->AsButton()->AsLabelButton());
+ EXPECT_EQ(kButtonID, button->GetID());
+ EXPECT_TRUE(button->IsVisible());
+ EXPECT_FALSE(button->IsDrawn());
+
+ if (with_text) {
+ EXPECT_STREQ(kButtonText, button->GetText().ToString().c_str());
+ } else {
+ EXPECT_TRUE(button->GetText().empty());
+ }
+
+ if (with_image) {
+ AddImage(button);
+ }
+
+ window->AddChildView(button);
+ window->Layout();
+
+ EXPECT_TRUE(window->IsSame(button->GetWindow()));
+ EXPECT_TRUE(window->IsSame(button->GetParentView()));
+ EXPECT_TRUE(button->IsSame(window->GetViewForID(kButtonID)));
+ EXPECT_TRUE(button->IsVisible());
+ EXPECT_TRUE(button->IsDrawn());
+
+ window->Show();
+
+ // Wait a bit before trying to click the button.
+ CefPostDelayedTask(TID_UI, base::BindOnce(ClickButton, window, kButtonID),
+ kClickDelayMS);
+}
+
+void LabelButtonClick(CefRefPtr<CefWaitableEvent> event,
+ bool with_button_frame,
+ bool with_button_text,
+ bool with_button_image) {
+ auto config = std::make_unique<TestWindowDelegate::Config>();
+ config->on_window_created =
+ base::BindOnce(RunLabelButtonClick, with_button_text, with_button_image);
+ config->frameless = false;
+ config->close_window = false;
+ TestWindowDelegate::RunTest(event, std::move(config));
+}
+
+void LabelButtonClickFramedWithTextWithImageFramelessWindowImpl(
+ CefRefPtr<CefWaitableEvent> event) {
+ LabelButtonClick(event, true, true, true);
+}
+
+void LabelButtonClickFramedWithTextNoImageFramelessWindowImpl(
+ CefRefPtr<CefWaitableEvent> event) {
+ LabelButtonClick(event, true, true, false);
+}
+
+void LabelButtonClickFramedNoTextWithImageFramelessWindowImpl(
+ CefRefPtr<CefWaitableEvent> event) {
+ LabelButtonClick(event, true, false, true);
+}
+
+void LabelButtonClickFramedNoTextNoImageFramelessWindowImpl(
+ CefRefPtr<CefWaitableEvent> event) {
+ LabelButtonClick(event, true, false, false);
+}
+
+void LabelButtonClickFramelessWithTextWithImageFramelessWindowImpl(
+ CefRefPtr<CefWaitableEvent> event) {
+ LabelButtonClick(event, false, true, true);
+}
+
+void LabelButtonClickFramelessWithTextNoImageFramelessWindowImpl(
+ CefRefPtr<CefWaitableEvent> event) {
+ LabelButtonClick(event, false, true, false);
+}
+
+void LabelButtonClickFramelessNoTextWithImageFramelessWindowImpl(
+ CefRefPtr<CefWaitableEvent> event) {
+ LabelButtonClick(event, false, false, true);
+}
+
+void LabelButtonClickFramelessNoTextNoImageFramelessWindowImpl(
+ CefRefPtr<CefWaitableEvent> event) {
+ LabelButtonClick(event, false, false, false);
+}
+
+} // namespace
+
+// Test LabelButton functionality. This is primarily to exercise exposed CEF
+// APIs and is not intended to comprehensively test button-related behavior
+// (which we presume that Chromium is testing).
+BUTTON_TEST_ASYNC(LabelButtonClickFramedWithTextWithImageFramelessWindow)
+BUTTON_TEST_ASYNC(LabelButtonClickFramedWithTextNoImageFramelessWindow)
+BUTTON_TEST_ASYNC(LabelButtonClickFramedNoTextWithImageFramelessWindow)
+BUTTON_TEST_ASYNC(LabelButtonClickFramedNoTextNoImageFramelessWindow)
+BUTTON_TEST_ASYNC(LabelButtonClickFramelessWithTextWithImageFramelessWindow)
+BUTTON_TEST_ASYNC(LabelButtonClickFramelessWithTextNoImageFramelessWindow)
+BUTTON_TEST_ASYNC(LabelButtonClickFramelessNoTextWithImageFramelessWindow)
+BUTTON_TEST_ASYNC(LabelButtonClickFramelessNoTextNoImageFramelessWindow)
+
+namespace {
+
+const int kMenuItemID = 2;
+const char kMenuItemLabel[] = "My Menu Item";
+
+void ClickMenuItem(CefRefPtr<CefMenuButton> menu_button) {
+ // Determine the lower-right corner of the menu button, then offset a bit to
+ // hit the first menu item.
+ const CefRect& bounds = menu_button->GetBoundsInScreen();
+ const CefPoint& click_point =
+ CefPoint(bounds.x + bounds.width + 10, bounds.y + bounds.height + 10);
+
+ // Click the menu item.
+ CefRefPtr<CefWindow> window = menu_button->GetWindow();
+ window->SendMouseMove(click_point.x, click_point.y);
+ window->SendMouseEvents(MBT_LEFT, true, true);
+}
+
+class TestMenuButtonDelegate : public CefMenuButtonDelegate,
+ public CefMenuModelDelegate {
+ public:
+ TestMenuButtonDelegate() {}
+
+ void OnMenuButtonPressed(
+ CefRefPtr<CefMenuButton> menu_button,
+ const CefPoint& screen_point,
+ CefRefPtr<CefMenuButtonPressedLock> button_pressed_lock) override {
+ window_ = menu_button->GetWindow();
+
+ CefRefPtr<CefMenuModel> model = CefMenuModel::CreateMenuModel(this);
+ model->AddItem(kMenuItemID, kMenuItemLabel);
+
+ // Verify color accessors.
+ for (int i = 0; i < CEF_MENU_COLOR_COUNT; ++i) {
+ cef_menu_color_type_t color_type = static_cast<cef_menu_color_type_t>(i);
+ cef_color_t color_out;
+ cef_color_t color = CefColorSetARGB(255, 255, 255, i);
+
+ // No color set yet.
+ color_out = 1;
+ EXPECT_TRUE(model->GetColor(kMenuItemID, color_type, color_out));
+ EXPECT_EQ(0U, color_out);
+ color_out = 1;
+ EXPECT_TRUE(model->GetColorAt(0, color_type, color_out));
+ EXPECT_EQ(0U, color_out);
+ color_out = 1;
+ EXPECT_TRUE(model->GetColorAt(-1, color_type, color_out));
+ EXPECT_EQ(0U, color_out);
+
+ // Set the default color.
+ EXPECT_TRUE(model->SetColorAt(-1, color_type, color));
+ color_out = 1;
+ EXPECT_TRUE(model->GetColorAt(-1, color_type, color_out));
+ EXPECT_EQ(color, color_out);
+
+ // Clear the default color.
+ EXPECT_TRUE(model->SetColorAt(-1, color_type, 0));
+ color_out = 1;
+ EXPECT_TRUE(model->GetColorAt(-1, color_type, color_out));
+ EXPECT_EQ(0U, color_out);
+
+ // Set the index color.
+ EXPECT_TRUE(model->SetColorAt(0, color_type, color));
+ color_out = 1;
+ EXPECT_TRUE(model->GetColorAt(0, color_type, color_out));
+ EXPECT_EQ(color, color_out);
+
+ // Clear the index color.
+ EXPECT_TRUE(model->SetColorAt(0, color_type, 0));
+ color_out = 1;
+ EXPECT_TRUE(model->GetColorAt(0, color_type, color_out));
+ EXPECT_EQ(0U, color_out);
+
+ // Set the ID color.
+ EXPECT_TRUE(model->SetColor(kMenuItemID, color_type, color));
+ color_out = 1;
+ EXPECT_TRUE(model->GetColor(kMenuItemID, color_type, color_out));
+ EXPECT_EQ(color, color_out);
+
+ // Clear the ID color.
+ EXPECT_TRUE(model->SetColor(kMenuItemID, color_type, 0));
+ color_out = 1;
+ EXPECT_TRUE(model->GetColor(kMenuItemID, color_type, color_out));
+ EXPECT_EQ(0U, color_out);
+
+ // Index/ID doesn't exist.
+ EXPECT_FALSE(model->SetColorAt(4, color_type, color));
+ EXPECT_FALSE(model->SetColor(4, color_type, color));
+ color_out = 1;
+ EXPECT_FALSE(model->GetColorAt(4, color_type, color_out));
+ EXPECT_FALSE(model->GetColor(4, color_type, color_out));
+ EXPECT_EQ(1U, color_out);
+ }
+
+ // Verify font accessors.
+ const std::string& font = "Tahoma, 12px";
+ EXPECT_TRUE(model->SetFontListAt(0, font));
+ EXPECT_TRUE(model->SetFontListAt(0, CefString()));
+ EXPECT_TRUE(model->SetFontList(kMenuItemID, font));
+ EXPECT_TRUE(model->SetFontList(kMenuItemID, CefString()));
+
+ // Index/ID doesn't exist.
+ EXPECT_FALSE(model->SetFontListAt(4, font));
+ EXPECT_FALSE(model->SetFontList(4, font));
+
+ // Wait a bit before trying to click the menu item.
+ CefPostDelayedTask(TID_UI, base::BindOnce(ClickMenuItem, menu_button),
+ kClickDelayMS);
+
+ menu_button->ShowMenu(model, screen_point, CEF_MENU_ANCHOR_TOPLEFT);
+ }
+
+ void OnButtonPressed(CefRefPtr<CefButton> button) override {}
+
+ void ExecuteCommand(CefRefPtr<CefMenuModel> menu_model,
+ int command_id,
+ cef_event_flags_t event_flags) override {
+ EXPECT_TRUE(menu_model.get());
+ EXPECT_EQ(command_id, kMenuItemID);
+
+ // Complete the test by closing the window.
+ window_->GetWindow()->Close();
+ window_ = nullptr;
+ }
+
+ private:
+ CefRefPtr<CefWindow> window_;
+
+ IMPLEMENT_REFCOUNTING(TestMenuButtonDelegate);
+ DISALLOW_COPY_AND_ASSIGN(TestMenuButtonDelegate);
+};
+
+void RunMenuButtonClick(bool with_text,
+ bool with_image,
+ CefRefPtr<CefWindow> window) {
+ CefRefPtr<CefMenuButton> button = CefMenuButton::CreateMenuButton(
+ new TestMenuButtonDelegate(), with_text ? kButtonText : "");
+ button->SetID(kButtonID);
+
+ EXPECT_TRUE(button->AsButton());
+ EXPECT_TRUE(button->AsButton()->AsLabelButton());
+ EXPECT_TRUE(button->AsButton()->AsLabelButton()->AsMenuButton());
+ EXPECT_EQ(kButtonID, button->GetID());
+ EXPECT_TRUE(button->IsVisible());
+ EXPECT_FALSE(button->IsDrawn());
+
+ if (with_text) {
+ EXPECT_STREQ(kButtonText, button->GetText().ToString().c_str());
+ } else {
+ EXPECT_TRUE(button->GetText().empty());
+ }
+
+ if (with_image) {
+ AddImage(button);
+ }
+
+ window->AddChildView(button);
+ window->Layout();
+
+ EXPECT_TRUE(window->IsSame(button->GetWindow()));
+ EXPECT_TRUE(window->IsSame(button->GetParentView()));
+ EXPECT_TRUE(button->IsSame(window->GetViewForID(kButtonID)));
+ EXPECT_TRUE(button->IsVisible());
+ EXPECT_TRUE(button->IsDrawn());
+
+ window->Show();
+
+ // Wait a bit before trying to click the button.
+ CefPostDelayedTask(TID_UI, base::BindOnce(ClickButton, window, kButtonID),
+ kClickDelayMS);
+}
+
+void MenuButtonClick(CefRefPtr<CefWaitableEvent> event,
+ bool with_button_frame,
+ bool with_button_text,
+ bool with_button_image) {
+ auto config = std::make_unique<TestWindowDelegate::Config>();
+ config->on_window_created =
+ base::BindOnce(RunMenuButtonClick, with_button_text, with_button_image);
+ config->frameless = false;
+ config->close_window = false;
+ TestWindowDelegate::RunTest(event, std::move(config));
+}
+
+void MenuButtonClickFramedWithTextWithImageFramelessWindowImpl(
+ CefRefPtr<CefWaitableEvent> event) {
+ MenuButtonClick(event, true, true, true);
+}
+
+void MenuButtonClickFramedWithTextNoImageFramelessWindowImpl(
+ CefRefPtr<CefWaitableEvent> event) {
+ MenuButtonClick(event, true, true, false);
+}
+
+void MenuButtonClickFramedNoTextWithImageFramelessWindowImpl(
+ CefRefPtr<CefWaitableEvent> event) {
+ MenuButtonClick(event, true, false, true);
+}
+
+void MenuButtonClickFramedNoTextNoImageFramelessWindowImpl(
+ CefRefPtr<CefWaitableEvent> event) {
+ MenuButtonClick(event, true, false, false);
+}
+
+void MenuButtonClickFramelessWithTextWithImageFramelessWindowImpl(
+ CefRefPtr<CefWaitableEvent> event) {
+ MenuButtonClick(event, false, true, true);
+}
+
+void MenuButtonClickFramelessWithTextNoImageFramelessWindowImpl(
+ CefRefPtr<CefWaitableEvent> event) {
+ MenuButtonClick(event, false, true, false);
+}
+
+void MenuButtonClickFramelessNoTextWithImageFramelessWindowImpl(
+ CefRefPtr<CefWaitableEvent> event) {
+ MenuButtonClick(event, false, false, true);
+}
+
+void MenuButtonClickFramelessNoTextNoImageFramelessWindowImpl(
+ CefRefPtr<CefWaitableEvent> event) {
+ MenuButtonClick(event, false, false, false);
+}
+
+} // namespace
+
+// Test MenuButton functionality. This is primarily to exercise exposed CEF
+// APIs and is not intended to comprehensively test button-related behavior
+// (which we presume that Chromium is testing).
+BUTTON_TEST_ASYNC(MenuButtonClickFramedWithTextWithImageFramelessWindow)
+BUTTON_TEST_ASYNC(MenuButtonClickFramedWithTextNoImageFramelessWindow)
+BUTTON_TEST_ASYNC(MenuButtonClickFramedNoTextWithImageFramelessWindow)
+BUTTON_TEST_ASYNC(MenuButtonClickFramedNoTextNoImageFramelessWindow)
+BUTTON_TEST_ASYNC(MenuButtonClickFramelessWithTextWithImageFramelessWindow)
+BUTTON_TEST_ASYNC(MenuButtonClickFramelessWithTextNoImageFramelessWindow)
+BUTTON_TEST_ASYNC(MenuButtonClickFramelessNoTextWithImageFramelessWindow)
+BUTTON_TEST_ASYNC(MenuButtonClickFramelessNoTextNoImageFramelessWindow)
+
+namespace {
+
+class TestMenuButtonCustomPopupDelegate : public CefMenuButtonDelegate,
+ public CefWindowDelegate {
+ public:
+ explicit TestMenuButtonCustomPopupDelegate(bool can_activate)
+ : can_activate_(can_activate) {}
+
+ void OnMenuButtonPressed(
+ CefRefPtr<CefMenuButton> menu_button,
+ const CefPoint& screen_point,
+ CefRefPtr<CefMenuButtonPressedLock> button_pressed_lock) override {
+ parent_window_ = menu_button->GetWindow();
+ button_pressed_lock_ = button_pressed_lock;
+
+ popup_window_ = CefWindow::CreateTopLevelWindow(this);
+ popup_window_->SetBounds(CefRect(screen_point.x, screen_point.y, 100, 100));
+
+ CefRefPtr<CefLabelButton> button =
+ CefLabelButton::CreateLabelButton(this, "Button");
+ button->SetFocusable(can_activate_);
+ popup_window_->AddChildView(button);
+
+ popup_window_->Show();
+
+ // Wait a bit before trying to click the popup button.
+ CefPostDelayedTask(TID_UI, base::BindOnce(ClickMenuItem, menu_button),
+ kClickDelayMS);
+ }
+
+ void OnButtonPressed(CefRefPtr<CefButton> button) override {
+ EXPECT_TRUE(button->GetWindow()->IsSame(popup_window_));
+ popup_window_->Close();
+ popup_window_ = nullptr;
+ button_pressed_lock_ = nullptr;
+ }
+
+ CefRefPtr<CefWindow> GetParentWindow(CefRefPtr<CefWindow> window,
+ bool* is_menu,
+ bool* can_activate_menu) override {
+ EXPECT_TRUE(parent_window_);
+ *is_menu = true;
+ *can_activate_menu = can_activate_;
+ return parent_window_;
+ }
+
+ bool IsFrameless(CefRefPtr<CefWindow> window) override { return true; }
+
+ void OnFocus(CefRefPtr<CefView> view) override {
+ if (popup_window_ && view->GetWindow()->IsSame(popup_window_)) {
+ EXPECT_TRUE(can_activate_);
+ got_focus_.yes();
+ }
+ }
+
+ void OnWindowDestroyed(CefRefPtr<CefWindow> window) override {
+ if (can_activate_) {
+ EXPECT_TRUE(got_focus_);
+ } else {
+ EXPECT_FALSE(got_focus_);
+ }
+
+ // Complete the test by closing the parent window.
+ parent_window_->Close();
+ parent_window_ = nullptr;
+ }
+
+ private:
+ const bool can_activate_;
+
+ CefRefPtr<CefWindow> parent_window_;
+ CefRefPtr<CefWindow> popup_window_;
+ CefRefPtr<CefMenuButtonPressedLock> button_pressed_lock_;
+
+ TrackCallback got_focus_;
+
+ IMPLEMENT_REFCOUNTING(TestMenuButtonCustomPopupDelegate);
+ DISALLOW_COPY_AND_ASSIGN(TestMenuButtonCustomPopupDelegate);
+};
+
+void RunMenuButtonCustomPopupClick(bool can_activate,
+ CefRefPtr<CefWindow> window) {
+ CefRefPtr<CefMenuButton> button = CefMenuButton::CreateMenuButton(
+ new TestMenuButtonCustomPopupDelegate(can_activate), "Custom");
+ button->SetID(kButtonID);
+
+ window->AddChildView(button);
+ window->Layout();
+
+ window->Show();
+
+ // Wait a bit before trying to click the button.
+ CefPostDelayedTask(TID_UI, base::BindOnce(ClickButton, window, kButtonID),
+ kClickDelayMS);
+}
+
+void MenuButtonCustomPopupClick(CefRefPtr<CefWaitableEvent> event,
+ bool can_activate) {
+ auto config = std::make_unique<TestWindowDelegate::Config>();
+ config->on_window_created =
+ base::BindOnce(RunMenuButtonCustomPopupClick, can_activate);
+ config->close_window = false;
+ TestWindowDelegate::RunTest(event, std::move(config));
+}
+
+void MenuButtonCustomPopupActivateImpl(CefRefPtr<CefWaitableEvent> event) {
+ MenuButtonCustomPopupClick(event, true);
+}
+
+void MenuButtonCustomPopupNoActivateImpl(CefRefPtr<CefWaitableEvent> event) {
+ MenuButtonCustomPopupClick(event, false);
+}
+
+} // namespace
+
+BUTTON_TEST_ASYNC(MenuButtonCustomPopupActivate)
+BUTTON_TEST_ASYNC(MenuButtonCustomPopupNoActivate)
diff --git a/tests/ceftests/views/panel_unittest.cc b/tests/ceftests/views/panel_unittest.cc
new file mode 100644
index 00000000..370635e8
--- /dev/null
+++ b/tests/ceftests/views/panel_unittest.cc
@@ -0,0 +1,1394 @@
+// Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "include/views/cef_box_layout.h"
+#include "include/views/cef_fill_layout.h"
+#include "include/views/cef_layout.h"
+#include "include/views/cef_panel.h"
+#include "include/views/cef_panel_delegate.h"
+#include "include/views/cef_window.h"
+#include "tests/ceftests/thread_helper.h"
+#include "tests/gtest/include/gtest/gtest.h"
+
+#define PANEL_TEST(name) UI_THREAD_TEST(ViewsPanelTest, name)
+
+namespace {
+
+class EmptyPanelDelegate : public CefPanelDelegate {
+ public:
+ EmptyPanelDelegate() {}
+
+ private:
+ IMPLEMENT_REFCOUNTING(EmptyPanelDelegate);
+ DISALLOW_COPY_AND_ASSIGN(EmptyPanelDelegate);
+};
+
+void CreatePanel(CefRefPtr<CefPanelDelegate> delegate) {
+ CefRefPtr<CefPanel> panel = CefPanel::CreatePanel(delegate);
+ EXPECT_TRUE(panel.get());
+
+ // Verify the derived View relationship.
+ EXPECT_TRUE(panel->AsPanel().get());
+ EXPECT_FALSE(panel->AsWindow().get());
+ EXPECT_TRUE(panel->IsSame(panel));
+
+ // Verify default View state.
+ EXPECT_STREQ("Panel", panel->GetTypeString().ToString().c_str());
+ EXPECT_TRUE(panel->IsValid());
+ EXPECT_FALSE(panel->IsAttached());
+ if (delegate) {
+ EXPECT_EQ(delegate.get(), panel->GetDelegate().get());
+ } else {
+ EXPECT_FALSE(panel->GetDelegate().get());
+ }
+ EXPECT_EQ(0, panel->GetID());
+ EXPECT_FALSE(panel->GetParentView().get());
+ EXPECT_EQ(CefRect(0, 0, 0, 0), panel->GetBounds());
+ EXPECT_EQ(CefRect(0, 0, 0, 0), panel->GetBoundsInScreen());
+ EXPECT_EQ(CefSize(0, 0), panel->GetPreferredSize());
+ EXPECT_EQ(CefSize(0, 0), panel->GetMinimumSize());
+ EXPECT_EQ(CefSize(0, 0), panel->GetMaximumSize());
+ EXPECT_EQ(CefSize(0, 0), panel->GetMaximumSize());
+ EXPECT_EQ(0, panel->GetHeightForWidth(100));
+ EXPECT_TRUE(panel->IsVisible());
+ EXPECT_FALSE(panel->IsDrawn());
+ EXPECT_TRUE(panel->IsEnabled());
+ EXPECT_FALSE(panel->IsFocusable());
+ EXPECT_FALSE(panel->IsAccessibilityFocusable());
+ EXPECT_EQ(CefColorSetARGB(255, 255, 255, 255), panel->GetBackgroundColor());
+
+ // Verify default Panel state.
+ EXPECT_TRUE(panel->GetLayout().get());
+ EXPECT_EQ(0U, panel->GetChildViewCount());
+
+ // Destroy the Panel.
+ panel = nullptr;
+
+ if (delegate) {
+ // Verify that nothing is keeping a reference to the delegate.
+ EXPECT_TRUE(delegate->HasOneRef());
+ }
+}
+
+void CreatePanelNoDelegateImpl() {
+ CreatePanel(nullptr);
+}
+
+void CreatePanelWithDelegateImpl() {
+ CreatePanel(new EmptyPanelDelegate);
+}
+
+} // namespace
+
+// Test creation.
+PANEL_TEST(CreatePanelNoDelegate)
+PANEL_TEST(CreatePanelWithDelegate)
+
+namespace {
+
+class ParentPanelDelegate : public CefPanelDelegate {
+ public:
+ ParentPanelDelegate() {}
+
+ void OnParentViewChanged(CefRefPtr<CefView> view,
+ bool added,
+ CefRefPtr<CefView> parent) override {
+ EXPECT_FALSE(true); // Not reached.
+ }
+
+ void OnChildViewChanged(CefRefPtr<CefView> view,
+ bool added,
+ CefRefPtr<CefView> child) override {
+ Changed changed;
+ changed.view_ = view;
+ changed.added_ = added;
+ changed.child_ = child;
+ changed_.push_back(changed);
+ }
+
+ void Verify(int callback_index,
+ CefRefPtr<CefView> view,
+ bool added,
+ CefRefPtr<CefView> child) {
+ EXPECT_LT(callback_index, static_cast<int>(changed_.size()));
+ EXPECT_TRUE(view->IsSame(changed_[callback_index].view_))
+ << "callback_index " << callback_index;
+ EXPECT_EQ(added, changed_[callback_index].added_)
+ << "callback_index " << callback_index;
+ EXPECT_TRUE(child->IsSame(changed_[callback_index].child_))
+ << "callback_index " << callback_index;
+ }
+
+ void Reset() { changed_.clear(); }
+
+ bool IsReset() const { return changed_.empty(); }
+
+ struct Changed {
+ CefRefPtr<CefView> view_;
+ bool added_ = false;
+ CefRefPtr<CefView> child_;
+ };
+ std::vector<Changed> changed_;
+
+ private:
+ IMPLEMENT_REFCOUNTING(ParentPanelDelegate);
+ DISALLOW_COPY_AND_ASSIGN(ParentPanelDelegate);
+};
+
+class ChildPanelDelegate : public CefPanelDelegate {
+ public:
+ ChildPanelDelegate() {}
+
+ void OnParentViewChanged(CefRefPtr<CefView> view,
+ bool added,
+ CefRefPtr<CefView> parent) override {
+ EXPECT_FALSE(on_parent_view_changed_);
+ on_parent_view_changed_ = true;
+ view_ = view;
+ added_ = added;
+ parent_ = parent;
+ }
+
+ void OnChildViewChanged(CefRefPtr<CefView> view,
+ bool added,
+ CefRefPtr<CefView> child) override {
+ EXPECT_FALSE(true); // Not reached.
+ }
+
+ void Verify(CefRefPtr<CefView> view, bool added, CefRefPtr<CefView> parent) {
+ EXPECT_TRUE(on_parent_view_changed_);
+ EXPECT_TRUE(view->IsSame(view_));
+ EXPECT_EQ(added, added_);
+ EXPECT_TRUE(parent->IsSame(parent_));
+ }
+
+ void Reset() {
+ on_parent_view_changed_ = false;
+ view_ = nullptr;
+ added_ = false;
+ parent_ = nullptr;
+ }
+
+ bool IsReset() const { return !on_parent_view_changed_; }
+
+ bool on_parent_view_changed_ = false;
+ CefRefPtr<CefView> view_;
+ bool added_ = false;
+ CefRefPtr<CefView> parent_;
+
+ private:
+ IMPLEMENT_REFCOUNTING(ChildPanelDelegate);
+ DISALLOW_COPY_AND_ASSIGN(ChildPanelDelegate);
+};
+
+void ChildVerifyRemovedState(CefRefPtr<ParentPanelDelegate> parent_delegate,
+ CefRefPtr<CefPanel> parent_panel,
+ CefRefPtr<ChildPanelDelegate> child_delegate,
+ CefRefPtr<CefPanel> child_panel) {
+ EXPECT_FALSE(parent_panel->IsSame(child_panel));
+ EXPECT_FALSE(child_panel->IsSame(parent_panel));
+ EXPECT_FALSE(parent_panel->IsAttached());
+ EXPECT_FALSE(child_panel->IsAttached());
+ EXPECT_FALSE(parent_panel->GetParentView().get());
+ EXPECT_FALSE(child_panel->GetParentView().get());
+}
+
+void ChildVerifyAddedState(CefRefPtr<ParentPanelDelegate> parent_delegate,
+ CefRefPtr<CefPanel> parent_panel,
+ CefRefPtr<ChildPanelDelegate> child_delegate,
+ CefRefPtr<CefPanel> child_panel,
+ int expected_child_index) {
+ EXPECT_FALSE(parent_panel->IsSame(child_panel));
+ EXPECT_FALSE(child_panel->IsSame(parent_panel));
+ EXPECT_FALSE(parent_panel->IsAttached());
+ EXPECT_TRUE(child_panel->IsAttached());
+ EXPECT_TRUE(
+ child_panel->IsSame(parent_panel->GetChildViewAt(expected_child_index)));
+ EXPECT_TRUE(child_panel->GetParentView()->IsSame(parent_panel));
+}
+
+void ChildVerifyFinalCallbackState(
+ CefRefPtr<ParentPanelDelegate> parent_delegate,
+ CefRefPtr<CefPanel> parent_panel,
+ CefRefPtr<ChildPanelDelegate> child_delegate,
+ CefRefPtr<CefPanel> child_panel,
+ int expected_parent_callback_index,
+ bool added) {
+ parent_delegate->Verify(expected_parent_callback_index, parent_panel, added,
+ child_panel);
+ child_delegate->Verify(child_panel, added, parent_panel);
+}
+
+void ChildAdd(CefRefPtr<ParentPanelDelegate> parent_delegate,
+ CefRefPtr<CefPanel> parent_panel,
+ CefRefPtr<ChildPanelDelegate> child_delegate,
+ CefRefPtr<CefPanel> child_panel,
+ int expected_child_index = 0,
+ int expected_parent_callback_index = 0) {
+ // Verify initial parent/child state.
+ ChildVerifyRemovedState(parent_delegate, parent_panel, child_delegate,
+ child_panel);
+
+ // Verify initial child callback state.
+ EXPECT_TRUE(child_delegate->IsReset());
+
+ // Add the child view.
+ parent_panel->AddChildView(child_panel);
+
+ // Verify final callback state.
+ ChildVerifyFinalCallbackState(parent_delegate, parent_panel, child_delegate,
+ child_panel, expected_parent_callback_index,
+ true);
+
+ // Reset child callback state.
+ child_delegate->Reset();
+
+ // Verify final parent/child state.
+ ChildVerifyAddedState(parent_delegate, parent_panel, child_delegate,
+ child_panel, expected_child_index);
+}
+
+void ChildAddAt(CefRefPtr<ParentPanelDelegate> parent_delegate,
+ CefRefPtr<CefPanel> parent_panel,
+ CefRefPtr<ChildPanelDelegate> child_delegate,
+ CefRefPtr<CefPanel> child_panel,
+ int child_index,
+ int expected_parent_callback_index) {
+ // Verify initial parent/child state.
+ ChildVerifyRemovedState(parent_delegate, parent_panel, child_delegate,
+ child_panel);
+
+ // Verify initial child callback state.
+ EXPECT_TRUE(child_delegate->IsReset());
+
+ // Add the child view.
+ parent_panel->AddChildViewAt(child_panel, child_index);
+
+ // Verify final callback state.
+ ChildVerifyFinalCallbackState(parent_delegate, parent_panel, child_delegate,
+ child_panel, expected_parent_callback_index,
+ true);
+
+ // Reset child callback state.
+ child_delegate->Reset();
+
+ // Verify final parent/child state.
+ ChildVerifyAddedState(parent_delegate, parent_panel, child_delegate,
+ child_panel, child_index);
+}
+
+void ChildRemove(CefRefPtr<ParentPanelDelegate> parent_delegate,
+ CefRefPtr<CefPanel> parent_panel,
+ CefRefPtr<ChildPanelDelegate> child_delegate,
+ CefRefPtr<CefPanel> child_panel,
+ bool remove_all,
+ int expected_child_index = 0,
+ int expected_parent_callback_index = 0) {
+ // Verify initial parent/child state.
+ ChildVerifyAddedState(parent_delegate, parent_panel, child_delegate,
+ child_panel, expected_child_index);
+
+ // Verify initial child callback state.
+ EXPECT_TRUE(child_delegate->IsReset());
+
+ // Remove the child view.
+ if (remove_all) {
+ parent_panel->RemoveAllChildViews();
+ } else {
+ parent_panel->RemoveChildView(child_panel);
+ }
+
+ // Verify final callback state.
+ ChildVerifyFinalCallbackState(parent_delegate, parent_panel, child_delegate,
+ child_panel, expected_parent_callback_index,
+ false);
+
+ // Reset child callback state.
+ child_delegate->Reset();
+
+ // Verify final parent/child state.
+ ChildVerifyRemovedState(parent_delegate, parent_panel, child_delegate,
+ child_panel);
+}
+
+void ChildAddRemoveSingleImpl() {
+ CefRefPtr<ParentPanelDelegate> parent_delegate = new ParentPanelDelegate();
+ CefRefPtr<CefPanel> parent_panel = CefPanel::CreatePanel(parent_delegate);
+
+ CefRefPtr<ChildPanelDelegate> child_delegate = new ChildPanelDelegate();
+ CefRefPtr<CefPanel> child_panel = CefPanel::CreatePanel(child_delegate);
+
+ // Add and explicitly remove the child view.
+ EXPECT_TRUE(parent_delegate->IsReset());
+ ChildAdd(parent_delegate, parent_panel, child_delegate, child_panel);
+ parent_delegate->Reset();
+
+ ChildRemove(parent_delegate, parent_panel, child_delegate, child_panel,
+ false);
+ parent_delegate->Reset();
+
+ // Add and implicitly remove the child view.
+ ChildAdd(parent_delegate, parent_panel, child_delegate, child_panel);
+ parent_delegate->Reset();
+
+ ChildRemove(parent_delegate, parent_panel, child_delegate, child_panel,
+ false);
+ parent_delegate->Reset();
+}
+
+void ChildAddRemoveMultipleImpl() {
+ CefRefPtr<ParentPanelDelegate> parent_delegate = new ParentPanelDelegate();
+ CefRefPtr<CefPanel> parent_panel = CefPanel::CreatePanel(parent_delegate);
+
+ CefRefPtr<ChildPanelDelegate> child_delegate1 = new ChildPanelDelegate();
+ CefRefPtr<CefPanel> child_panel1 = CefPanel::CreatePanel(child_delegate1);
+
+ CefRefPtr<ChildPanelDelegate> child_delegate2 = new ChildPanelDelegate();
+ CefRefPtr<CefPanel> child_panel2 = CefPanel::CreatePanel(child_delegate2);
+
+ // Add multiple child views.
+ EXPECT_TRUE(parent_delegate->IsReset());
+ ChildAdd(parent_delegate, parent_panel, child_delegate1, child_panel1, 0, 0);
+ EXPECT_TRUE(child_delegate2->IsReset()); // child2 not called.
+ ChildAdd(parent_delegate, parent_panel, child_delegate2, child_panel2, 1, 1);
+ EXPECT_TRUE(child_delegate1->IsReset()); // child1 not called.
+ parent_delegate->Reset();
+
+ EXPECT_EQ(2U, parent_panel->GetChildViewCount());
+
+ // Explicitly remove specific child views.
+ ChildRemove(parent_delegate, parent_panel, child_delegate1, child_panel1,
+ false, 0, 0);
+ EXPECT_TRUE(child_delegate2->IsReset()); // child2 not called.
+ ChildRemove(parent_delegate, parent_panel, child_delegate2, child_panel2,
+ false, 0, 1);
+ EXPECT_TRUE(child_delegate1->IsReset()); // child1 not called.
+ parent_delegate->Reset();
+
+ EXPECT_EQ(0U, parent_panel->GetChildViewCount());
+
+ // Add multiple child views.
+ ChildAdd(parent_delegate, parent_panel, child_delegate1, child_panel1, 0, 0);
+ EXPECT_TRUE(child_delegate2->IsReset()); // child2 not called.
+ ChildAdd(parent_delegate, parent_panel, child_delegate2, child_panel2, 1, 1);
+ EXPECT_TRUE(child_delegate1->IsReset()); // child1 not called.
+ parent_delegate->Reset();
+
+ EXPECT_EQ(2U, parent_panel->GetChildViewCount());
+
+ EXPECT_TRUE(child_delegate1->IsReset());
+ EXPECT_TRUE(child_delegate2->IsReset());
+
+ // Implicitly remove all child views.
+ parent_panel->RemoveAllChildViews();
+
+ // Verify final callback state.
+ ChildVerifyFinalCallbackState(parent_delegate, parent_panel, child_delegate1,
+ child_panel1, 0, false);
+ ChildVerifyFinalCallbackState(parent_delegate, parent_panel, child_delegate2,
+ child_panel2, 1, false);
+
+ EXPECT_EQ(0U, parent_panel->GetChildViewCount());
+
+ // Reset callback state.
+ parent_delegate->Reset();
+ child_delegate1->Reset();
+ child_delegate2->Reset();
+
+ // Verify final parent/child state.
+ ChildVerifyRemovedState(parent_delegate, parent_panel, child_delegate1,
+ child_panel1);
+ ChildVerifyRemovedState(parent_delegate, parent_panel, child_delegate2,
+ child_panel2);
+}
+
+void ChildOrderImpl() {
+ CefRefPtr<ParentPanelDelegate> parent_delegate = new ParentPanelDelegate();
+ CefRefPtr<CefPanel> parent_panel = CefPanel::CreatePanel(parent_delegate);
+
+ CefRefPtr<ChildPanelDelegate> child_delegate1 = new ChildPanelDelegate();
+ CefRefPtr<CefPanel> child_panel1 = CefPanel::CreatePanel(child_delegate1);
+
+ CefRefPtr<ChildPanelDelegate> child_delegate2 = new ChildPanelDelegate();
+ CefRefPtr<CefPanel> child_panel2 = CefPanel::CreatePanel(child_delegate2);
+
+ CefRefPtr<ChildPanelDelegate> child_delegate3 = new ChildPanelDelegate();
+ CefRefPtr<CefPanel> child_panel3 = CefPanel::CreatePanel(child_delegate3);
+
+ // Add child views at specific indexes.
+ ChildAddAt(parent_delegate, parent_panel, child_delegate2, child_panel2, 0,
+ 0);
+ ChildAddAt(parent_delegate, parent_panel, child_delegate3, child_panel3, 0,
+ 1);
+ ChildAddAt(parent_delegate, parent_panel, child_delegate1, child_panel1, 1,
+ 2);
+ parent_delegate->Reset();
+
+ EXPECT_EQ(3U, parent_panel->GetChildViewCount());
+
+ // ChildAddAt() will verify these results but let's check again just to make
+ // sure.
+ EXPECT_TRUE(child_panel3->IsSame(parent_panel->GetChildViewAt(0)));
+ EXPECT_TRUE(child_panel1->IsSame(parent_panel->GetChildViewAt(1)));
+ EXPECT_TRUE(child_panel2->IsSame(parent_panel->GetChildViewAt(2)));
+
+ // Move panel2 to the front.
+ parent_panel->ReorderChildView(child_panel2, 0);
+
+ EXPECT_TRUE(child_panel2->IsSame(parent_panel->GetChildViewAt(0)));
+ EXPECT_TRUE(child_panel3->IsSame(parent_panel->GetChildViewAt(1)));
+ EXPECT_TRUE(child_panel1->IsSame(parent_panel->GetChildViewAt(2)));
+
+ // Move panel3 to the end.
+ parent_panel->ReorderChildView(child_panel3, -1);
+
+ EXPECT_TRUE(child_panel2->IsSame(parent_panel->GetChildViewAt(0)));
+ EXPECT_TRUE(child_panel1->IsSame(parent_panel->GetChildViewAt(1)));
+ EXPECT_TRUE(child_panel3->IsSame(parent_panel->GetChildViewAt(2)));
+}
+
+void ChildVisibleImpl() {
+ CefRefPtr<CefPanel> parent_panel = CefPanel::CreatePanel(nullptr);
+ CefRefPtr<CefPanel> child_panel1 = CefPanel::CreatePanel(nullptr);
+ CefRefPtr<CefPanel> child_panel2 = CefPanel::CreatePanel(nullptr);
+
+ // Nothing drawn by default.
+ EXPECT_FALSE(parent_panel->IsDrawn());
+ EXPECT_FALSE(child_panel1->IsDrawn());
+ EXPECT_FALSE(child_panel2->IsDrawn());
+
+ // Everything visible by default.
+ EXPECT_TRUE(parent_panel->IsVisible());
+ EXPECT_TRUE(child_panel1->IsVisible());
+ EXPECT_TRUE(child_panel2->IsVisible());
+
+ parent_panel->AddChildView(child_panel1);
+ parent_panel->AddChildView(child_panel2);
+
+ // Still the same.
+ EXPECT_FALSE(parent_panel->IsDrawn());
+ EXPECT_FALSE(child_panel1->IsDrawn());
+ EXPECT_FALSE(child_panel2->IsDrawn());
+ EXPECT_TRUE(parent_panel->IsVisible());
+ EXPECT_TRUE(child_panel1->IsVisible());
+ EXPECT_TRUE(child_panel2->IsVisible());
+
+ child_panel1->SetVisible(false);
+
+ // Child1 not visible.
+ EXPECT_TRUE(parent_panel->IsVisible());
+ EXPECT_FALSE(child_panel1->IsVisible());
+ EXPECT_TRUE(child_panel2->IsVisible());
+
+ child_panel1->SetVisible(true);
+
+ // Everything visible.
+ EXPECT_TRUE(parent_panel->IsVisible());
+ EXPECT_TRUE(child_panel1->IsVisible());
+ EXPECT_TRUE(child_panel2->IsVisible());
+
+ parent_panel->SetVisible(false);
+
+ // Children visible.
+ EXPECT_FALSE(parent_panel->IsVisible());
+ EXPECT_TRUE(child_panel1->IsVisible());
+ EXPECT_TRUE(child_panel2->IsVisible());
+
+ parent_panel->SetVisible(true);
+
+ // Everything visible.
+ EXPECT_TRUE(parent_panel->IsVisible());
+ EXPECT_TRUE(child_panel1->IsVisible());
+ EXPECT_TRUE(child_panel2->IsVisible());
+}
+
+void ChildDrawnImpl() {
+ CefRefPtr<CefPanel> parent_panel = CefPanel::CreatePanel(nullptr);
+ CefRefPtr<CefPanel> child_panel1 = CefPanel::CreatePanel(nullptr);
+ CefRefPtr<CefPanel> child_panel2 = CefPanel::CreatePanel(nullptr);
+
+ // Nothing drawn by default.
+ EXPECT_FALSE(parent_panel->IsDrawn());
+ EXPECT_FALSE(child_panel1->IsDrawn());
+ EXPECT_FALSE(child_panel2->IsDrawn());
+
+ // Everything visible by default.
+ EXPECT_TRUE(parent_panel->IsVisible());
+ EXPECT_TRUE(child_panel1->IsVisible());
+ EXPECT_TRUE(child_panel2->IsVisible());
+
+ parent_panel->AddChildView(child_panel1);
+ parent_panel->AddChildView(child_panel2);
+
+ // Create and show a Window.
+ CefRefPtr<CefWindow> window = CefWindow::CreateTopLevelWindow(nullptr);
+ window->AddChildView(parent_panel);
+ window->CenterWindow(CefSize(400, 400));
+ window->Show();
+
+ // Everything visible and drawn now.
+ EXPECT_TRUE(parent_panel->IsVisible());
+ EXPECT_TRUE(parent_panel->IsDrawn());
+ EXPECT_TRUE(child_panel1->IsVisible());
+ EXPECT_TRUE(child_panel1->IsDrawn());
+ EXPECT_TRUE(child_panel2->IsVisible());
+ EXPECT_TRUE(child_panel2->IsDrawn());
+
+ child_panel1->SetVisible(false);
+
+ // Child1 not visible or drawn.
+ EXPECT_TRUE(parent_panel->IsVisible());
+ EXPECT_TRUE(parent_panel->IsDrawn());
+ EXPECT_FALSE(child_panel1->IsVisible());
+ EXPECT_FALSE(child_panel1->IsDrawn());
+ EXPECT_TRUE(child_panel2->IsVisible());
+ EXPECT_TRUE(child_panel2->IsDrawn());
+
+ child_panel1->SetVisible(true);
+
+ // Everything visible and drawn.
+ EXPECT_TRUE(parent_panel->IsVisible());
+ EXPECT_TRUE(parent_panel->IsDrawn());
+ EXPECT_TRUE(child_panel1->IsVisible());
+ EXPECT_TRUE(child_panel1->IsDrawn());
+ EXPECT_TRUE(child_panel2->IsVisible());
+ EXPECT_TRUE(child_panel2->IsDrawn());
+
+ parent_panel->SetVisible(false);
+
+ // Children visible, but nothing drawn.
+ EXPECT_FALSE(parent_panel->IsVisible());
+ EXPECT_FALSE(parent_panel->IsDrawn());
+ EXPECT_TRUE(child_panel1->IsVisible());
+ EXPECT_FALSE(child_panel1->IsDrawn());
+ EXPECT_TRUE(child_panel2->IsVisible());
+ EXPECT_FALSE(child_panel2->IsDrawn());
+
+ parent_panel->SetVisible(true);
+
+ // Everything visible and drawn.
+ EXPECT_TRUE(parent_panel->IsVisible());
+ EXPECT_TRUE(parent_panel->IsDrawn());
+ EXPECT_TRUE(child_panel1->IsVisible());
+ EXPECT_TRUE(child_panel1->IsDrawn());
+ EXPECT_TRUE(child_panel2->IsVisible());
+ EXPECT_TRUE(child_panel2->IsDrawn());
+
+ // Close the window.
+ window->Close();
+}
+
+} // namespace
+
+// Test child behaviors.
+PANEL_TEST(ChildAddRemoveSingle)
+PANEL_TEST(ChildAddRemoveMultiple)
+PANEL_TEST(ChildOrder)
+PANEL_TEST(ChildVisible)
+PANEL_TEST(ChildDrawn)
+
+namespace {
+
+class SizingPanelDelegate : public CefPanelDelegate {
+ public:
+ SizingPanelDelegate() {}
+
+ CefSize GetPreferredSize(CefRefPtr<CefView> view) override {
+ got_get_preferred_size_ = true;
+ view_ = view;
+ return preferred_size_;
+ }
+
+ CefSize GetMinimumSize(CefRefPtr<CefView> view) override {
+ got_get_minimum_size_ = true;
+ view_ = view;
+ return minimum_size_;
+ }
+
+ CefSize GetMaximumSize(CefRefPtr<CefView> view) override {
+ got_get_maximum_size_ = true;
+ view_ = view;
+ return maximum_size_;
+ }
+
+ int GetHeightForWidth(CefRefPtr<CefView> view, int width) override {
+ got_get_height_for_width_ = true;
+ view_ = view;
+ width_ = width;
+ return height_for_width_;
+ }
+
+ void Reset() {
+ preferred_size_ = CefSize(0, 0);
+ minimum_size_ = CefSize(0, 0);
+ maximum_size_ = CefSize(0, 0);
+ height_for_width_ = 0;
+ got_get_preferred_size_ = false;
+ got_get_minimum_size_ = false;
+ got_get_maximum_size_ = false;
+ got_get_height_for_width_ = false;
+ view_ = nullptr;
+ width_ = 0;
+ }
+
+ bool IsReset() const {
+ return !got_get_preferred_size_ && !got_get_minimum_size_ &&
+ !got_get_maximum_size_ && !got_get_height_for_width_;
+ }
+
+ CefSize preferred_size_;
+ CefSize minimum_size_;
+ CefSize maximum_size_;
+ int height_for_width_ = 0;
+
+ bool got_get_preferred_size_ = false;
+ bool got_get_minimum_size_ = false;
+ bool got_get_maximum_size_ = false;
+ bool got_get_height_for_width_ = false;
+
+ CefRefPtr<CefView> view_;
+ int width_ = 0;
+
+ private:
+ IMPLEMENT_REFCOUNTING(SizingPanelDelegate);
+ DISALLOW_COPY_AND_ASSIGN(SizingPanelDelegate);
+};
+
+void SizeNoDelegateImpl() {
+ CefRefPtr<SizingPanelDelegate> delegate = new SizingPanelDelegate();
+ CefRefPtr<CefPanel> panel = CefPanel::CreatePanel(delegate);
+
+ // Default bounds are empty.
+ EXPECT_EQ(CefRect(0, 0, 0, 0), panel->GetBounds());
+
+ // Set and get the bounds.
+ panel->SetBounds(CefRect(100, 100, 200, 200));
+ EXPECT_EQ(CefRect(100, 100, 200, 200), panel->GetBounds());
+ EXPECT_EQ(CefSize(200, 200), panel->GetSize());
+ EXPECT_EQ(CefPoint(100, 100), panel->GetPosition());
+
+ // GetBoundsInScreen() drops the position because there is no Window.
+ EXPECT_EQ(CefRect(0, 0, 200, 200), panel->GetBoundsInScreen());
+
+ // Adjust the position but keep the size the same.
+ panel->SetPosition(CefPoint(50, 50));
+ EXPECT_EQ(CefRect(50, 50, 200, 200), panel->GetBounds());
+ EXPECT_EQ(CefSize(200, 200), panel->GetSize());
+ EXPECT_EQ(CefPoint(50, 50), panel->GetPosition());
+
+ // Adjust the size but keep the position the same.
+ panel->SetSize(CefSize(400, 400));
+ EXPECT_EQ(CefRect(50, 50, 400, 400), panel->GetBounds());
+ EXPECT_EQ(CefSize(400, 400), panel->GetSize());
+ EXPECT_EQ(CefPoint(50, 50), panel->GetPosition());
+
+ // No delegate methods were called during this test.
+ EXPECT_TRUE(delegate->IsReset());
+}
+
+void SizeWithDelegateImpl() {
+ CefRefPtr<SizingPanelDelegate> delegate = new SizingPanelDelegate();
+ CefRefPtr<CefPanel> panel = CefPanel::CreatePanel(delegate);
+
+ // Default bounds are empty.
+ EXPECT_EQ(CefRect(0, 0, 0, 0), panel->GetBounds());
+
+ CefSize expected_size(100, 100);
+
+ // Test GetPreferredSize().
+ delegate->preferred_size_ = expected_size;
+ EXPECT_EQ(expected_size, panel->GetPreferredSize());
+ EXPECT_TRUE(delegate->got_get_preferred_size_);
+ EXPECT_FALSE(delegate->got_get_minimum_size_);
+ EXPECT_FALSE(delegate->got_get_maximum_size_);
+ EXPECT_FALSE(delegate->got_get_height_for_width_);
+ EXPECT_TRUE(panel->IsSame(delegate->view_));
+ delegate->Reset();
+
+ // Test GetMinimumSize().
+ delegate->minimum_size_ = expected_size;
+ EXPECT_EQ(expected_size, panel->GetMinimumSize());
+ EXPECT_FALSE(delegate->got_get_preferred_size_);
+ EXPECT_TRUE(delegate->got_get_minimum_size_);
+ EXPECT_FALSE(delegate->got_get_maximum_size_);
+ EXPECT_FALSE(delegate->got_get_height_for_width_);
+ EXPECT_TRUE(panel->IsSame(delegate->view_));
+ delegate->Reset();
+
+ // Test GetMaximumSize().
+ delegate->maximum_size_ = expected_size;
+ EXPECT_EQ(expected_size, panel->GetMaximumSize());
+ EXPECT_FALSE(delegate->got_get_preferred_size_);
+ EXPECT_FALSE(delegate->got_get_minimum_size_);
+ EXPECT_TRUE(delegate->got_get_maximum_size_);
+ EXPECT_FALSE(delegate->got_get_height_for_width_);
+ EXPECT_TRUE(panel->IsSame(delegate->view_));
+ delegate->Reset();
+
+ int expected_width = 200;
+ int expected_height = 100;
+
+ // Test GetHeightForWidth().
+ delegate->height_for_width_ = expected_height;
+ EXPECT_EQ(expected_height, panel->GetHeightForWidth(expected_width));
+ EXPECT_FALSE(delegate->got_get_preferred_size_);
+ EXPECT_FALSE(delegate->got_get_minimum_size_);
+ EXPECT_FALSE(delegate->got_get_maximum_size_);
+ EXPECT_TRUE(delegate->got_get_height_for_width_);
+ EXPECT_EQ(expected_width, delegate->width_);
+ EXPECT_TRUE(panel->IsSame(delegate->view_));
+ delegate->Reset();
+}
+
+} // namespace
+
+// Test sizing.
+PANEL_TEST(SizeNoDelegate)
+PANEL_TEST(SizeWithDelegate)
+
+namespace {
+
+void FillLayoutCreateImpl() {
+ CefRefPtr<CefPanel> panel = CefPanel::CreatePanel(nullptr);
+
+ // Explicitly set to FillLayout.
+ panel->SetToFillLayout();
+
+ CefRefPtr<CefLayout> layout = panel->GetLayout();
+ EXPECT_TRUE(layout.get());
+ EXPECT_TRUE(layout->AsFillLayout().get());
+}
+
+void FillLayoutSizeToPreferredSizeImpl() {
+ CefRefPtr<SizingPanelDelegate> delegate = new SizingPanelDelegate();
+ CefRefPtr<CefPanel> panel = CefPanel::CreatePanel(delegate);
+
+ // Default Layout is FillLayout.
+ CefRefPtr<CefLayout> layout = panel->GetLayout();
+ EXPECT_TRUE(layout.get());
+ EXPECT_TRUE(layout->AsFillLayout().get());
+
+ // Default bounds are empty.
+ EXPECT_EQ(CefRect(0, 0, 0, 0), panel->GetBounds());
+
+ CefSize expected_size(100, 100);
+
+ delegate->preferred_size_ = expected_size;
+
+ // Trigger use of the preferred size.
+ panel->Layout();
+
+ EXPECT_TRUE(delegate->got_get_preferred_size_);
+ EXPECT_FALSE(delegate->got_get_minimum_size_);
+ EXPECT_FALSE(delegate->got_get_maximum_size_);
+ EXPECT_FALSE(delegate->got_get_height_for_width_);
+ EXPECT_TRUE(panel->IsSame(delegate->view_));
+ delegate->Reset();
+
+ // Size is now the preferred size.
+ EXPECT_EQ(expected_size, panel->GetSize());
+
+ // No additional delegate methods were called.
+ EXPECT_TRUE(delegate->IsReset());
+}
+
+void FillLayoutSizeHierarchyImpl() {
+ CefRefPtr<CefPanel> panel_parent = CefPanel::CreatePanel(nullptr);
+ CefRefPtr<CefPanel> panel_child = CefPanel::CreatePanel(nullptr);
+
+ CefSize expected_size(100, 100);
+
+ // Default Layout is FillLayout.
+ CefRefPtr<CefLayout> layout1 = panel_parent->GetLayout();
+ EXPECT_TRUE(layout1.get());
+ EXPECT_TRUE(layout1->AsFillLayout().get());
+
+ // Default bounds are empty.
+ EXPECT_EQ(CefRect(0, 0, 0, 0), panel_parent->GetBounds());
+ EXPECT_EQ(CefRect(0, 0, 0, 0), panel_child->GetBounds());
+
+ // Without delegates the size must be set on the parent.
+ panel_parent->SetSize(expected_size);
+
+ // FillLayout is the default Layout. Both panels should end up with the same
+ // size.
+ panel_parent->AddChildView(panel_child);
+
+ // Force layout.
+ panel_parent->Layout();
+
+ // Panels are now the same size.
+ EXPECT_EQ(expected_size, panel_parent->GetSize());
+ EXPECT_EQ(expected_size, panel_child->GetSize());
+
+ // Resize the parent panel to a larger size.
+ CefSize expected_size2(200, 200);
+ panel_parent->SetSize(expected_size2);
+
+ // Force layout.
+ panel_parent->Layout();
+
+ // Panels are now the larger size.
+ EXPECT_EQ(expected_size2, panel_parent->GetSize());
+ EXPECT_EQ(expected_size2, panel_child->GetSize());
+}
+
+void FillLayoutSizeHierarchyWithDelegate(bool size_from_parent) {
+ CefRefPtr<SizingPanelDelegate> delegate_parent = new SizingPanelDelegate();
+ CefRefPtr<CefPanel> panel_parent = CefPanel::CreatePanel(delegate_parent);
+ CefRefPtr<SizingPanelDelegate> delegate_child = new SizingPanelDelegate();
+ CefRefPtr<CefPanel> panel_child = CefPanel::CreatePanel(delegate_child);
+
+ CefSize expected_size(100, 100);
+
+ // The default layout is FillLayout, but explicitly set it anyways just for
+ // some testing variety.
+ panel_parent->SetToFillLayout();
+ panel_child->SetToFillLayout();
+
+ // Default bounds are empty.
+ EXPECT_EQ(CefRect(0, 0, 0, 0), panel_parent->GetBounds());
+ EXPECT_EQ(CefRect(0, 0, 0, 0), panel_child->GetBounds());
+
+ // With delegates the size can come from either the parent or child.
+ if (size_from_parent) {
+ delegate_parent->preferred_size_ = expected_size;
+ } else {
+ delegate_child->preferred_size_ = expected_size;
+ }
+
+ // FillLayout is the default Layout. Both panels should end up with the same
+ // size.
+ panel_parent->AddChildView(panel_child);
+
+ // No delegate methods were called yet.
+ EXPECT_TRUE(delegate_parent->IsReset());
+ EXPECT_TRUE(delegate_child->IsReset());
+
+ // Force layout.
+ panel_parent->Layout();
+
+ // delegate_parent will be called to get the preferred size for panel_parent.
+ EXPECT_TRUE(delegate_parent->got_get_preferred_size_);
+ EXPECT_FALSE(delegate_parent->got_get_minimum_size_);
+ EXPECT_FALSE(delegate_parent->got_get_maximum_size_);
+ EXPECT_FALSE(delegate_parent->got_get_height_for_width_);
+ EXPECT_TRUE(panel_parent->IsSame(delegate_parent->view_));
+ delegate_parent->Reset();
+
+ // delegate_child will be called to get the preferred size for panel_child.
+ EXPECT_TRUE(delegate_child->got_get_preferred_size_);
+ EXPECT_FALSE(delegate_child->got_get_minimum_size_);
+ EXPECT_FALSE(delegate_child->got_get_maximum_size_);
+ EXPECT_FALSE(delegate_child->got_get_height_for_width_);
+ EXPECT_TRUE(panel_child->IsSame(delegate_child->view_));
+ delegate_child->Reset();
+
+ // Panels are now the same size.
+ EXPECT_EQ(expected_size, panel_parent->GetSize());
+ EXPECT_EQ(expected_size, panel_child->GetSize());
+
+ // Resize the parent panel to a larger size.
+ CefSize expected_size2(200, 200);
+ panel_parent->SetSize(expected_size2);
+
+ // Force layout.
+ panel_parent->Layout();
+
+ // Panels are now the larger size.
+ EXPECT_EQ(expected_size2, panel_parent->GetSize());
+ EXPECT_EQ(expected_size2, panel_child->GetSize());
+
+ // No additional delegate methods were called.
+ EXPECT_TRUE(delegate_parent->IsReset());
+ EXPECT_TRUE(delegate_child->IsReset());
+}
+
+void FillLayoutSizeHierarchyFromParentWithDelegateImpl() {
+ FillLayoutSizeHierarchyWithDelegate(true);
+}
+
+void FillLayoutSizeHierarchyFromChildWithDelegateImpl() {
+ FillLayoutSizeHierarchyWithDelegate(false);
+}
+
+} // namespace
+
+// Test FillLayout.
+PANEL_TEST(FillLayoutCreate)
+PANEL_TEST(FillLayoutSizeToPreferredSize)
+PANEL_TEST(FillLayoutSizeHierarchy)
+PANEL_TEST(FillLayoutSizeHierarchyFromParentWithDelegate)
+PANEL_TEST(FillLayoutSizeHierarchyFromChildWithDelegate)
+
+namespace {
+
+void BoxLayoutCreateImpl() {
+ CefRefPtr<CefPanel> panel = CefPanel::CreatePanel(nullptr);
+
+ CefBoxLayoutSettings settings;
+
+ // Explicitly set to BoxLayout.
+ panel->SetToBoxLayout(settings);
+
+ CefRefPtr<CefLayout> layout = panel->GetLayout();
+ EXPECT_TRUE(layout.get());
+ EXPECT_TRUE(layout->AsBoxLayout().get());
+}
+
+const int kBLParentSize = 100;
+const int kBLChildSize = 10;
+
+void BoxLayoutSizeHierarchy(bool with_delegate,
+ const CefBoxLayoutSettings& settings,
+ const CefRect& expected_child1_bounds,
+ const CefRect& expected_child2_bounds,
+ int child1_flex = 0,
+ int child2_flex = 0) {
+ CefRefPtr<SizingPanelDelegate> delegate_parent;
+ if (with_delegate) {
+ delegate_parent = new SizingPanelDelegate();
+ }
+ CefRefPtr<CefPanel> panel_parent = CefPanel::CreatePanel(delegate_parent);
+
+ CefRefPtr<SizingPanelDelegate> delegate_child1, delegate_child2;
+ if (with_delegate) {
+ delegate_child1 = new SizingPanelDelegate();
+ delegate_child2 = new SizingPanelDelegate();
+ }
+ CefRefPtr<CefPanel> panel_child1 = CefPanel::CreatePanel(delegate_child1);
+ CefRefPtr<CefPanel> panel_child2 = CefPanel::CreatePanel(delegate_child2);
+
+ // Default bounds are empty.
+ EXPECT_EQ(CefRect(0, 0, 0, 0), panel_parent->GetBounds());
+ EXPECT_EQ(CefRect(0, 0, 0, 0), panel_child1->GetBounds());
+ EXPECT_EQ(CefRect(0, 0, 0, 0), panel_child2->GetBounds());
+
+ // Give the parent a size.
+ CefSize initial_parent_size(kBLParentSize, kBLParentSize);
+ if (with_delegate) {
+ delegate_parent->preferred_size_ = initial_parent_size;
+ } else {
+ panel_parent->SetSize(initial_parent_size);
+ }
+
+ // Give the children a size smaller than the parent.
+ CefSize initial_child_size(kBLChildSize, kBLChildSize);
+ if (with_delegate) {
+ delegate_child1->preferred_size_ = initial_child_size;
+ delegate_child2->preferred_size_ = initial_child_size;
+ } else {
+ panel_child1->SetSize(initial_child_size);
+ panel_child2->SetSize(initial_child_size);
+ }
+
+ // Set to BoxLayout with |settings|.
+ panel_parent->SetToBoxLayout(settings);
+
+ panel_parent->AddChildView(panel_child1);
+ panel_parent->AddChildView(panel_child2);
+
+ if (child1_flex > 0 || child2_flex > 0) {
+ // Flex will apply relative stretch in the main axis direction.
+ CefRefPtr<CefBoxLayout> layout = panel_parent->GetLayout()->AsBoxLayout();
+ if (child1_flex > 0) {
+ layout->SetFlexForView(panel_child1, child1_flex);
+ }
+ if (child2_flex > 0) {
+ layout->SetFlexForView(panel_child2, child2_flex);
+ }
+ }
+
+ if (with_delegate) {
+ // No delegate methods were called yet.
+ EXPECT_TRUE(delegate_parent->IsReset());
+ EXPECT_TRUE(delegate_child1->IsReset());
+ EXPECT_TRUE(delegate_child2->IsReset());
+ }
+
+ // Force layout.
+ panel_parent->Layout();
+
+ if (with_delegate) {
+ // delegate_parent will be called to get the preferred size for
+ // panel_parent.
+ EXPECT_TRUE(delegate_parent->got_get_preferred_size_);
+ EXPECT_FALSE(delegate_parent->got_get_minimum_size_);
+ EXPECT_FALSE(delegate_parent->got_get_maximum_size_);
+ EXPECT_FALSE(delegate_parent->got_get_height_for_width_);
+ EXPECT_TRUE(panel_parent->IsSame(delegate_parent->view_));
+ delegate_parent->Reset();
+
+ // delegate_child1 will be called to get the preferred size for
+ // panel_child1.
+ // GetHeightForWidth may also be called depending on the settings.
+ EXPECT_TRUE(delegate_child1->got_get_preferred_size_);
+ EXPECT_FALSE(delegate_child1->got_get_minimum_size_);
+ EXPECT_FALSE(delegate_child1->got_get_maximum_size_);
+ EXPECT_TRUE(panel_child1->IsSame(delegate_child1->view_));
+ delegate_child1->Reset();
+
+ // delegate_child2 will be called to get the preferred size for
+ // panel_child2.
+ // GetHeightForWidth may also be called depending on the settings.
+ EXPECT_TRUE(delegate_child2->got_get_preferred_size_);
+ EXPECT_FALSE(delegate_child2->got_get_minimum_size_);
+ EXPECT_FALSE(delegate_child2->got_get_maximum_size_);
+ EXPECT_TRUE(panel_child2->IsSame(delegate_child2->view_));
+ delegate_child2->Reset();
+ }
+
+ // The parent should be the same size.
+ EXPECT_EQ(initial_parent_size, panel_parent->GetSize());
+
+ // Children should have the expected bounds.
+ EXPECT_EQ(expected_child1_bounds, panel_child1->GetBounds());
+ EXPECT_EQ(expected_child2_bounds, panel_child2->GetBounds());
+
+ if (with_delegate) {
+ // No additional delegate methods were called.
+ EXPECT_TRUE(delegate_parent->IsReset());
+ EXPECT_TRUE(delegate_child1->IsReset());
+ EXPECT_TRUE(delegate_child2->IsReset());
+ }
+}
+
+void BoxLayoutSizeHierarchyVerticalStretch(bool with_delegate) {
+ // Vertical layout with children stretched along the horizontal axis.
+ //
+ // -----------
+ // |111111111|
+ // |222222222|
+ // | |
+ // | |
+ // | |
+ // -----------
+ //
+ CefBoxLayoutSettings settings;
+
+ CefRect expected_child1_bounds(0, 0, kBLParentSize, kBLChildSize);
+ CefRect expected_child2_bounds(0, kBLChildSize, kBLParentSize, kBLChildSize);
+
+ BoxLayoutSizeHierarchy(with_delegate, settings, expected_child1_bounds,
+ expected_child2_bounds);
+}
+
+void BoxLayoutSizeHierarchyVerticalStretchImpl() {
+ BoxLayoutSizeHierarchyVerticalStretch(false);
+}
+
+void BoxLayoutSizeHierarchyVerticalStretchWithDelegateImpl() {
+ BoxLayoutSizeHierarchyVerticalStretch(true);
+}
+
+void BoxLayoutSizeHierarchyHorizontalStretch(bool with_delegate) {
+ // Horizontal layout with children stretched along the vertical axis.
+ //
+ // -----------
+ // |12 |
+ // |12 |
+ // |12 |
+ // |12 |
+ // |12 |
+ // -----------
+ //
+ CefBoxLayoutSettings settings;
+ settings.horizontal = true;
+
+ CefRect expected_child1_bounds(0, 0, kBLChildSize, kBLParentSize);
+ CefRect expected_child2_bounds(kBLChildSize, 0, kBLChildSize, kBLParentSize);
+
+ BoxLayoutSizeHierarchy(with_delegate, settings, expected_child1_bounds,
+ expected_child2_bounds);
+}
+
+void BoxLayoutSizeHierarchyHorizontalStretchImpl() {
+ BoxLayoutSizeHierarchyHorizontalStretch(false);
+}
+
+void BoxLayoutSizeHierarchyHorizontalStretchWithDelegateImpl() {
+ BoxLayoutSizeHierarchyHorizontalStretch(true);
+}
+
+void BoxLayoutSizeHierarchyVerticalCenter(bool with_delegate) {
+ // Vertical layout with children centered along the horizontal axis.
+ //
+ // -----------
+ // | 1 |
+ // | 2 |
+ // | |
+ // | |
+ // | |
+ // -----------
+ //
+ CefBoxLayoutSettings settings;
+ settings.cross_axis_alignment = CEF_CROSS_AXIS_ALIGNMENT_CENTER;
+
+ int xoffset = (kBLParentSize - kBLChildSize) / 2;
+ CefRect expected_child1_bounds(xoffset, 0, kBLChildSize, kBLChildSize);
+ CefRect expected_child2_bounds(xoffset, kBLChildSize, kBLChildSize,
+ kBLChildSize);
+
+ BoxLayoutSizeHierarchy(with_delegate, settings, expected_child1_bounds,
+ expected_child2_bounds);
+}
+
+void BoxLayoutSizeHierarchyVerticalCenterImpl() {
+ BoxLayoutSizeHierarchyVerticalCenter(false);
+}
+
+void BoxLayoutSizeHierarchyVerticalCenterWithDelegateImpl() {
+ BoxLayoutSizeHierarchyVerticalCenter(true);
+}
+
+void BoxLayoutSizeHierarchyHorizontalCenter(bool with_delegate) {
+ // Horizontal layout with children centered along the vertical axis.
+ //
+ // -----------
+ // | |
+ // | |
+ // |12 |
+ // | |
+ // | |
+ // -----------
+ //
+ CefBoxLayoutSettings settings;
+ settings.horizontal = true;
+ settings.cross_axis_alignment = CEF_CROSS_AXIS_ALIGNMENT_CENTER;
+
+ int yoffset = (kBLParentSize - kBLChildSize) / 2;
+ CefRect expected_child1_bounds(0, yoffset, kBLChildSize, kBLChildSize);
+ CefRect expected_child2_bounds(kBLChildSize, yoffset, kBLChildSize,
+ kBLChildSize);
+
+ BoxLayoutSizeHierarchy(with_delegate, settings, expected_child1_bounds,
+ expected_child2_bounds);
+}
+
+void BoxLayoutSizeHierarchyHorizontalCenterImpl() {
+ BoxLayoutSizeHierarchyHorizontalCenter(false);
+}
+
+void BoxLayoutSizeHierarchyHorizontalCenterWithDelegateImpl() {
+ BoxLayoutSizeHierarchyHorizontalCenter(true);
+}
+
+void BoxLayoutSizeHierarchyVerticalCenterCenter(bool with_delegate) {
+ // Vertical layout with children centered along the horizontal and vertical
+ // axis.
+ //
+ // -----------
+ // | |
+ // | 1 |
+ // | 2 |
+ // | |
+ // -----------
+ //
+ CefBoxLayoutSettings settings;
+ settings.main_axis_alignment = CEF_MAIN_AXIS_ALIGNMENT_CENTER;
+ settings.cross_axis_alignment = CEF_CROSS_AXIS_ALIGNMENT_CENTER;
+
+ int xoffset = (kBLParentSize - kBLChildSize) / 2;
+ int yoffset = (kBLParentSize - (kBLChildSize * 2)) / 2;
+ CefRect expected_child1_bounds(xoffset, yoffset, kBLChildSize, kBLChildSize);
+ CefRect expected_child2_bounds(xoffset, yoffset + kBLChildSize, kBLChildSize,
+ kBLChildSize);
+
+ BoxLayoutSizeHierarchy(with_delegate, settings, expected_child1_bounds,
+ expected_child2_bounds);
+}
+
+void BoxLayoutSizeHierarchyVerticalCenterCenterImpl() {
+ BoxLayoutSizeHierarchyVerticalCenterCenter(false);
+}
+
+void BoxLayoutSizeHierarchyVerticalCenterCenterWithDelegateImpl() {
+ BoxLayoutSizeHierarchyVerticalCenterCenter(true);
+}
+
+void BoxLayoutSizeHierarchyHorizontalCenterCenter(bool with_delegate) {
+ // Horizontal layout with children centered along the vertical and horizontal
+ // axis.
+ //
+ // -----------
+ // | |
+ // | |
+ // | 12 |
+ // | |
+ // | |
+ // -----------
+ //
+ CefBoxLayoutSettings settings;
+ settings.horizontal = true;
+ settings.main_axis_alignment = CEF_MAIN_AXIS_ALIGNMENT_CENTER;
+ settings.cross_axis_alignment = CEF_CROSS_AXIS_ALIGNMENT_CENTER;
+
+ int xoffset = (kBLParentSize - (kBLChildSize * 2)) / 2;
+ int yoffset = (kBLParentSize - kBLChildSize) / 2;
+ CefRect expected_child1_bounds(xoffset, yoffset, kBLChildSize, kBLChildSize);
+ CefRect expected_child2_bounds(xoffset + kBLChildSize, yoffset, kBLChildSize,
+ kBLChildSize);
+
+ BoxLayoutSizeHierarchy(with_delegate, settings, expected_child1_bounds,
+ expected_child2_bounds);
+}
+
+void BoxLayoutSizeHierarchyHorizontalCenterCenterImpl() {
+ BoxLayoutSizeHierarchyHorizontalCenterCenter(false);
+}
+
+void BoxLayoutSizeHierarchyHorizontalCenterCenterWithDelegateImpl() {
+ BoxLayoutSizeHierarchyHorizontalCenterCenter(true);
+}
+
+void BoxLayoutSizeHierarchyVerticalStretchFlexOne(bool with_delegate) {
+ // Vertical layout with child1 stretched along the horizontal and vertical
+ // axis and child2 stretched along the horizontal axis only (unequal flex).
+ //
+ // -----------
+ // |111111111|
+ // |111111111|
+ // |111111111|
+ // |111111111|
+ // |222222222|
+ // -----------
+ //
+ CefBoxLayoutSettings settings;
+
+ CefRect expected_child1_bounds(0, 0, kBLParentSize,
+ kBLParentSize - kBLChildSize);
+ CefRect expected_child2_bounds(0, kBLParentSize - kBLChildSize, kBLParentSize,
+ kBLChildSize);
+
+ BoxLayoutSizeHierarchy(with_delegate, settings, expected_child1_bounds,
+ expected_child2_bounds, 1, 0);
+}
+
+void BoxLayoutSizeHierarchyVerticalStretchFlexOneImpl() {
+ BoxLayoutSizeHierarchyVerticalStretchFlexOne(false);
+}
+
+void BoxLayoutSizeHierarchyVerticalStretchFlexOneWithDelegateImpl() {
+ BoxLayoutSizeHierarchyVerticalStretchFlexOne(true);
+}
+
+void BoxLayoutSizeHierarchyHorizontalStretchFlexOne(bool with_delegate) {
+ // Horizontal layout with child1 stretched along the vertical and horizontal
+ // axis and child2 stretched along the vertical axis only (unequal flex).
+ //
+ // -----------
+ // |111111112|
+ // |111111112|
+ // |111111112|
+ // |111111112|
+ // |111111112|
+ // -----------
+ //
+ CefBoxLayoutSettings settings;
+ settings.horizontal = true;
+
+ CefRect expected_child1_bounds(0, 0, kBLParentSize - kBLChildSize,
+ kBLParentSize);
+ CefRect expected_child2_bounds(kBLParentSize - kBLChildSize, 0, kBLChildSize,
+ kBLParentSize);
+
+ BoxLayoutSizeHierarchy(with_delegate, settings, expected_child1_bounds,
+ expected_child2_bounds, 1, 0);
+}
+
+void BoxLayoutSizeHierarchyHorizontalStretchFlexOneImpl() {
+ BoxLayoutSizeHierarchyHorizontalStretchFlexOne(false);
+}
+
+void BoxLayoutSizeHierarchyHorizontalStretchFlexOneWithDelegateImpl() {
+ BoxLayoutSizeHierarchyHorizontalStretchFlexOne(true);
+}
+
+void BoxLayoutSizeHierarchyVerticalStretchFlexBoth(bool with_delegate) {
+ // Vertical layout with children stretched along the horizontal and vertical
+ // axis (equal flex).
+ //
+ // -----------
+ // |111111111|
+ // |111111111|
+ // |111111111|
+ // |222222222|
+ // |222222222|
+ // |222222222|
+ // -----------
+ //
+ CefBoxLayoutSettings settings;
+
+ CefRect expected_child1_bounds(0, 0, kBLParentSize, kBLParentSize / 2);
+ CefRect expected_child2_bounds(0, kBLParentSize / 2, kBLParentSize,
+ kBLParentSize / 2);
+
+ BoxLayoutSizeHierarchy(with_delegate, settings, expected_child1_bounds,
+ expected_child2_bounds, 1, 1);
+}
+
+void BoxLayoutSizeHierarchyVerticalStretchFlexBothImpl() {
+ BoxLayoutSizeHierarchyVerticalStretchFlexBoth(false);
+}
+
+void BoxLayoutSizeHierarchyVerticalStretchFlexBothWithDelegateImpl() {
+ BoxLayoutSizeHierarchyVerticalStretchFlexBoth(true);
+}
+
+void BoxLayoutSizeHierarchyHorizontalStretchFlexBoth(bool with_delegate) {
+ // Horizontal layout with children stretched along the vertical and horizontal
+ // axis (equal flex).
+ //
+ // -----------
+ // |111122222|
+ // |111122222|
+ // |111122222|
+ // |111122222|
+ // |111122222|
+ // -----------
+ //
+ CefBoxLayoutSettings settings;
+ settings.horizontal = true;
+
+ CefRect expected_child1_bounds(0, 0, kBLParentSize / 2, kBLParentSize);
+ CefRect expected_child2_bounds(kBLParentSize / 2, 0, kBLParentSize / 2,
+ kBLParentSize);
+
+ BoxLayoutSizeHierarchy(with_delegate, settings, expected_child1_bounds,
+ expected_child2_bounds, 1, 1);
+}
+
+void BoxLayoutSizeHierarchyHorizontalStretchFlexBothImpl() {
+ BoxLayoutSizeHierarchyHorizontalStretchFlexBoth(false);
+}
+
+void BoxLayoutSizeHierarchyHorizontalStretchFlexBothWithDelegateImpl() {
+ BoxLayoutSizeHierarchyHorizontalStretchFlexBoth(true);
+}
+
+} // namespace
+
+// Test BoxLayout. The BoxLayoutSizeHierarchy* tests are representative but not
+// comprehensive (e.g. not all possible configurations are tested).
+PANEL_TEST(BoxLayoutCreate)
+PANEL_TEST(BoxLayoutSizeHierarchyVerticalStretch)
+PANEL_TEST(BoxLayoutSizeHierarchyVerticalStretchWithDelegate)
+PANEL_TEST(BoxLayoutSizeHierarchyHorizontalStretch)
+PANEL_TEST(BoxLayoutSizeHierarchyHorizontalStretchWithDelegate)
+PANEL_TEST(BoxLayoutSizeHierarchyVerticalCenter)
+PANEL_TEST(BoxLayoutSizeHierarchyVerticalCenterWithDelegate)
+PANEL_TEST(BoxLayoutSizeHierarchyHorizontalCenter)
+PANEL_TEST(BoxLayoutSizeHierarchyHorizontalCenterWithDelegate)
+PANEL_TEST(BoxLayoutSizeHierarchyVerticalCenterCenter)
+PANEL_TEST(BoxLayoutSizeHierarchyVerticalCenterCenterWithDelegate)
+PANEL_TEST(BoxLayoutSizeHierarchyHorizontalCenterCenter)
+PANEL_TEST(BoxLayoutSizeHierarchyHorizontalCenterCenterWithDelegate)
+PANEL_TEST(BoxLayoutSizeHierarchyVerticalStretchFlexOne)
+PANEL_TEST(BoxLayoutSizeHierarchyVerticalStretchFlexOneWithDelegate)
+PANEL_TEST(BoxLayoutSizeHierarchyHorizontalStretchFlexOne)
+PANEL_TEST(BoxLayoutSizeHierarchyHorizontalStretchFlexOneWithDelegate)
+PANEL_TEST(BoxLayoutSizeHierarchyVerticalStretchFlexBoth)
+PANEL_TEST(BoxLayoutSizeHierarchyVerticalStretchFlexBothWithDelegate)
+PANEL_TEST(BoxLayoutSizeHierarchyHorizontalStretchFlexBoth)
+PANEL_TEST(BoxLayoutSizeHierarchyHorizontalStretchFlexBothWithDelegate)
diff --git a/tests/ceftests/views/scroll_view_unittest.cc b/tests/ceftests/views/scroll_view_unittest.cc
new file mode 100644
index 00000000..67c4b1dc
--- /dev/null
+++ b/tests/ceftests/views/scroll_view_unittest.cc
@@ -0,0 +1,155 @@
+// Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "include/base/cef_callback.h"
+#include "include/cef_pack_strings.h"
+#include "include/views/cef_panel.h"
+#include "include/views/cef_panel_delegate.h"
+#include "include/views/cef_scroll_view.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "tests/ceftests/thread_helper.h"
+#include "tests/ceftests/views/test_window_delegate.h"
+#include "tests/gtest/include/gtest/gtest.h"
+
+#define SCROLL_VIEW_TEST_ASYNC(name) \
+ UI_THREAD_TEST_ASYNC(ViewsScrollViewTest, name)
+
+namespace {
+
+const int kScrollViewID = 1;
+const int kContentPanelID = 2;
+
+// Make the Panel larger then the Window so scroll bars appear.
+const int kContentPanelSize = TestWindowDelegate::kWSize + 200;
+
+class TestScrollViewDelegate : public CefViewDelegate {
+ public:
+ TestScrollViewDelegate() {}
+
+ CefSize GetPreferredSize(CefRefPtr<CefView> view) override {
+ EXPECT_EQ(kScrollViewID, view->GetID());
+ got_get_preferred_size_ = true;
+ return CefSize(kContentPanelSize, kContentPanelSize);
+ }
+
+ bool got_get_preferred_size_ = false;
+
+ private:
+ IMPLEMENT_REFCOUNTING(TestScrollViewDelegate);
+ DISALLOW_COPY_AND_ASSIGN(TestScrollViewDelegate);
+};
+
+class TestPanelDelegate : public CefPanelDelegate {
+ public:
+ TestPanelDelegate() {}
+
+ CefSize GetPreferredSize(CefRefPtr<CefView> view) override {
+ EXPECT_EQ(kContentPanelID, view->GetID());
+ got_get_preferred_size_ = true;
+ return CefSize(kContentPanelSize, kContentPanelSize);
+ }
+
+ bool got_get_preferred_size_ = false;
+
+ private:
+ IMPLEMENT_REFCOUNTING(TestPanelDelegate);
+ DISALLOW_COPY_AND_ASSIGN(TestPanelDelegate);
+};
+
+void RunScrollViewLayout(bool with_delegate, CefRefPtr<CefWindow> window) {
+ CefRefPtr<TestScrollViewDelegate> scroll_view_delegate;
+ CefRefPtr<TestPanelDelegate> panel_delegate;
+ if (with_delegate) {
+ scroll_view_delegate = new TestScrollViewDelegate();
+ panel_delegate = new TestPanelDelegate();
+ }
+
+ CefRefPtr<CefScrollView> scroll_view =
+ CefScrollView::CreateScrollView(scroll_view_delegate);
+ EXPECT_TRUE(scroll_view.get());
+ EXPECT_TRUE(scroll_view->AsScrollView().get());
+
+ // Verify default state.
+ EXPECT_FALSE(scroll_view->GetContentView().get());
+ EXPECT_EQ(CefRect(0, 0, 0, 0), scroll_view->GetVisibleContentRect());
+ EXPECT_FALSE(scroll_view->HasHorizontalScrollbar());
+ EXPECT_FALSE(scroll_view->HasVerticalScrollbar());
+
+ scroll_view->SetID(kScrollViewID);
+ scroll_view->SetBackgroundColor(CefColorSetARGB(255, 0, 255, 0));
+
+ CefRefPtr<CefPanel> content_panel = CefPanel::CreatePanel(panel_delegate);
+ content_panel->SetID(kContentPanelID);
+ content_panel->SetBackgroundColor(CefColorSetARGB(255, 255, 0, 0));
+
+ if (!with_delegate) {
+ // Explicitly set the content panel size. Otherwise, it will come from the
+ // delegate.
+ content_panel->SetSize(CefSize(kContentPanelSize, kContentPanelSize));
+ }
+
+ scroll_view->SetContentView(content_panel);
+ EXPECT_TRUE(content_panel->IsSame(scroll_view->GetContentView()));
+
+ window->AddChildView(scroll_view);
+
+ // Force layout.
+ window->Layout();
+
+ EXPECT_TRUE(scroll_view->HasHorizontalScrollbar());
+ EXPECT_TRUE(scroll_view->HasVerticalScrollbar());
+
+ if (with_delegate) {
+ // Layout() of the ScrollView no longer needs to call us for the size,
+ // see https://crrev.com/2701734b44.
+ EXPECT_FALSE(scroll_view_delegate->got_get_preferred_size_);
+ EXPECT_TRUE(panel_delegate->got_get_preferred_size_);
+ }
+
+ window->Show();
+
+ // With default FillLayout the ScrollView should be the size of the Window's
+ // client area.
+ const CefRect& client_bounds = window->GetClientAreaBoundsInScreen();
+ const CefRect& scroll_view_bounds = scroll_view->GetBoundsInScreen();
+ EXPECT_EQ(client_bounds, scroll_view_bounds);
+
+ // Content panel size should be unchanged.
+ const CefSize& content_panel_size = content_panel->GetSize();
+ EXPECT_EQ(CefSize(kContentPanelSize, kContentPanelSize), content_panel_size);
+
+ const int sb_height = scroll_view->GetHorizontalScrollbarHeight();
+ EXPECT_GT(sb_height, 0);
+ const int sb_width = scroll_view->GetVerticalScrollbarWidth();
+ EXPECT_GT(sb_width, 0);
+
+ // Verify visible content panel region.
+ const CefRect& visible_rect = scroll_view->GetVisibleContentRect();
+ EXPECT_EQ(CefRect(0, 0, scroll_view_bounds.width - sb_width,
+ scroll_view_bounds.height - sb_height),
+ visible_rect);
+}
+
+void ScrollViewLayout(CefRefPtr<CefWaitableEvent> event, bool with_delegate) {
+ auto config = std::make_unique<TestWindowDelegate::Config>();
+ config->on_window_created =
+ base::BindOnce(RunScrollViewLayout, with_delegate);
+ TestWindowDelegate::RunTest(event, std::move(config));
+}
+
+void ScrollViewLayoutWithDelegateImpl(CefRefPtr<CefWaitableEvent> event) {
+ ScrollViewLayout(event, true);
+}
+
+void ScrollViewLayoutNoDelegateImpl(CefRefPtr<CefWaitableEvent> event) {
+ ScrollViewLayout(event, false);
+}
+
+} // namespace
+
+// Test ScrollView layout. This is primarily to exercise exposed CEF APIs and is
+// not intended to comprehensively test ScrollView-related behavior (which we
+// presume that Chromium is testing).
+SCROLL_VIEW_TEST_ASYNC(ScrollViewLayoutWithDelegate)
+SCROLL_VIEW_TEST_ASYNC(ScrollViewLayoutNoDelegate)
diff --git a/tests/ceftests/views/test_window_delegate.cc b/tests/ceftests/views/test_window_delegate.cc
new file mode 100644
index 00000000..6aa1d1c3
--- /dev/null
+++ b/tests/ceftests/views/test_window_delegate.cc
@@ -0,0 +1,230 @@
+// Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/ceftests/views/test_window_delegate.h"
+
+#include "include/cef_command_line.h"
+#include "include/views/cef_window.h"
+#include "include/views/cef_window_delegate.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "tests/ceftests/test_util.h"
+#include "tests/ceftests/thread_helper.h"
+#include "tests/gtest/include/gtest/gtest.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#include "tests/shared/browser/geometry_util.h"
+#include "tests/shared/browser/util_win.h"
+#endif
+
+namespace {
+
+// Test timeout in MS.
+const int kTestTimeout = 5000;
+
+} // namespace
+
+// static
+const int TestWindowDelegate::kWSize = 400;
+
+// static
+void TestWindowDelegate::RunTest(CefRefPtr<CefWaitableEvent> event,
+ std::unique_ptr<Config> config) {
+ CefSize window_size{config->window_size, config->window_size};
+
+#if defined(OS_WIN)
+ if (!config->frameless) {
+ // Expand the client area size to full window size based on the default
+ // frame window style. AdjustWindowRect expects pixel coordinates, so
+ // perform the necessary conversions.
+ auto scale_factor = client::GetDeviceScaleFactor();
+ auto scaled_size =
+ client::LogicalToDevice(config->window_size, scale_factor);
+
+ // Convert from DIP to pixel coords.
+ RECT rect = {0, 0, scaled_size, scaled_size};
+
+ AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
+ false /* has_menu */);
+
+ // Convert from pixel to DIP coords.
+ auto scaled_rect = client::DeviceToLogical(
+ {rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top},
+ scale_factor);
+ window_size = {scaled_rect.width, scaled_rect.height};
+ }
+#endif // defined(OS_WIN)
+
+ CefWindow::CreateTopLevelWindow(
+ new TestWindowDelegate(event, std::move(config), window_size));
+}
+
+void TestWindowDelegate::OnWindowCreated(CefRefPtr<CefWindow> window) {
+ EXPECT_FALSE(window_);
+ window_ = window;
+
+ EXPECT_TRUE(window->IsValid());
+ EXPECT_FALSE(window->IsClosed());
+
+ EXPECT_FALSE(window->IsVisible());
+ EXPECT_FALSE(window->IsDrawn());
+
+ EXPECT_FALSE(window->IsActive());
+ EXPECT_FALSE(window->IsAlwaysOnTop());
+ EXPECT_FALSE(window->IsMaximized());
+ EXPECT_FALSE(window->IsMinimized());
+ EXPECT_FALSE(window->IsFullscreen());
+
+ const char* title = "ViewsTest";
+ window->SetTitle(title);
+ EXPECT_STREQ(title, window->GetTitle().ToString().c_str());
+
+ EXPECT_FALSE(window->GetWindowIcon().get());
+ EXPECT_FALSE(window->GetWindowAppIcon().get());
+
+ auto display = window->GetDisplay();
+ EXPECT_TRUE(display.get());
+
+ // Size will come from GetGetInitialBounds() or GetPreferredSize() on
+ // initial Window creation.
+ EXPECT_TRUE(got_get_initial_bounds_);
+ if (config_->window_origin.IsEmpty()) {
+ EXPECT_TRUE(got_get_preferred_size_);
+ } else {
+ EXPECT_FALSE(got_get_preferred_size_);
+ }
+
+ CefRect client_bounds = window->GetBounds();
+ if (!config_->window_origin.IsEmpty()) {
+ EXPECT_EQ(config_->window_origin.x, client_bounds.x);
+ EXPECT_EQ(config_->window_origin.y, client_bounds.y);
+ } else {
+ // Default origin is the upper-left corner of the display's work area.
+ auto work_area = display->GetWorkArea();
+ EXPECT_NEAR(work_area.x, client_bounds.x, 1);
+ EXPECT_NEAR(work_area.y, client_bounds.y, 1);
+ }
+
+ if (config_->frameless) {
+ EXPECT_NEAR(config_->window_size, client_bounds.width, 2);
+ EXPECT_NEAR(config_->window_size, client_bounds.height, 2);
+ } else {
+ // Client area bounds calculation might have off-by-one errors on Windows
+ // due to non-client frame size being calculated internally in pixels and
+ // then converted to DIPs. See http://crbug.com/602692.
+ EXPECT_NEAR(client_bounds.width, window_size_.width, 2);
+ EXPECT_NEAR(client_bounds.height, window_size_.height, 2);
+ }
+
+ // Run the callback.
+ if (!config_->on_window_created.is_null()) {
+ std::move(config_->on_window_created).Run(window);
+ }
+
+ if (config_->close_window) {
+ // Close the window asynchronously.
+ CefPostTask(TID_UI,
+ base::BindOnce(&TestWindowDelegate::OnCloseWindow, this));
+ } else {
+ const auto timeout = GetConfiguredTestTimeout(kTestTimeout);
+ if (timeout) {
+ // Timeout the test after a reasonable delay. Use a WeakPtr so that the
+ // delayed task doesn't keep this object alive.
+ CefPostDelayedTask(TID_UI,
+ base::BindOnce(&TestWindowDelegate::OnTimeoutWindow,
+ weak_ptr_factory_.GetWeakPtr()),
+ *timeout);
+ }
+ }
+}
+
+void TestWindowDelegate::OnWindowDestroyed(CefRefPtr<CefWindow> window) {
+ EXPECT_TRUE(window->IsSame(window_));
+
+ EXPECT_TRUE(window->IsValid());
+ EXPECT_TRUE(window->IsClosed());
+ EXPECT_FALSE(window->IsVisible());
+ EXPECT_FALSE(window->IsDrawn());
+
+ // Run the callback.
+ if (!config_->on_window_destroyed.is_null()) {
+ std::move(config_->on_window_destroyed).Run(window);
+ }
+
+ window_ = nullptr;
+
+ // Don't execute the timeout callback.
+ weak_ptr_factory_.InvalidateWeakPtrs();
+}
+
+bool TestWindowDelegate::IsFrameless(CefRefPtr<CefWindow> window) {
+ return config_->frameless;
+}
+
+CefRect TestWindowDelegate::GetInitialBounds(CefRefPtr<CefWindow> window) {
+ got_get_initial_bounds_ = true;
+ if (!config_->window_origin.IsEmpty()) {
+ return CefRect(config_->window_origin.x, config_->window_origin.y,
+ window_size_.width, window_size_.height);
+ }
+
+ // Call GetPreferredSize().
+ return CefRect();
+}
+
+CefSize TestWindowDelegate::GetPreferredSize(CefRefPtr<CefView> view) {
+ got_get_preferred_size_ = true;
+ return window_size_;
+}
+
+bool TestWindowDelegate::OnAccelerator(CefRefPtr<CefWindow> window,
+ int command_id) {
+ if (!config_->on_accelerator.is_null()) {
+ return config_->on_accelerator.Run(window_, command_id);
+ }
+ return false;
+}
+
+bool TestWindowDelegate::OnKeyEvent(CefRefPtr<CefWindow> window,
+ const CefKeyEvent& event) {
+ if (!config_->on_key_event.is_null()) {
+ return config_->on_key_event.Run(window_, event);
+ }
+ return false;
+}
+
+TestWindowDelegate::TestWindowDelegate(CefRefPtr<CefWaitableEvent> event,
+ std::unique_ptr<Config> config,
+ const CefSize& window_size)
+ : event_(event),
+ config_(std::move(config)),
+ window_size_(window_size),
+ weak_ptr_factory_(this) {}
+
+TestWindowDelegate::~TestWindowDelegate() {
+ // Complete the test (signal the event) asynchronously so objects on the call
+ // stack have a chance to unwind.
+ CefPostTask(TID_UI, base::BindOnce(SignalEvent, event_));
+}
+
+void TestWindowDelegate::OnCloseWindow() {
+ if (!window_) {
+ return;
+ }
+
+ EXPECT_TRUE(window_->IsValid());
+ EXPECT_FALSE(window_->IsClosed());
+
+ // Close() may clear |window_| so keep a reference.
+ CefRefPtr<CefWindow> window = window_;
+ window->Close();
+
+ EXPECT_TRUE(window->IsValid());
+ EXPECT_TRUE(window->IsClosed());
+}
+
+void TestWindowDelegate::OnTimeoutWindow() {
+ EXPECT_TRUE(false) << "Test timed out after " << kTestTimeout << "ms";
+ OnCloseWindow();
+}
diff --git a/tests/ceftests/views/test_window_delegate.h b/tests/ceftests/views/test_window_delegate.h
new file mode 100644
index 00000000..385998da
--- /dev/null
+++ b/tests/ceftests/views/test_window_delegate.h
@@ -0,0 +1,81 @@
+// Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include <memory>
+
+#include "include/base/cef_callback.h"
+#include "include/base/cef_weak_ptr.h"
+#include "include/cef_waitable_event.h"
+#include "include/views/cef_window.h"
+#include "include/views/cef_window_delegate.h"
+
+class TestWindowDelegate : public CefWindowDelegate {
+ public:
+ // Default window size.
+ static const int kWSize;
+
+ // Test execution callback.
+ using OnWindowCreatedCallback =
+ base::OnceCallback<void(CefRefPtr<CefWindow>)>;
+ using OnWindowDestroyedCallback =
+ base::OnceCallback<void(CefRefPtr<CefWindow>)>;
+ using OnAcceleratorCallback =
+ base::RepeatingCallback<bool(CefRefPtr<CefWindow>, int)>;
+ using OnKeyEventCallback =
+ base::RepeatingCallback<bool(CefRefPtr<CefWindow>, const CefKeyEvent&)>;
+
+ struct Config {
+ OnWindowCreatedCallback on_window_created;
+ OnWindowDestroyedCallback on_window_destroyed;
+ OnAcceleratorCallback on_accelerator;
+ OnKeyEventCallback on_key_event;
+ bool frameless = false;
+ bool close_window = true;
+ int window_size = kWSize;
+ CefPoint window_origin = {};
+ };
+
+ // Creates a Window with a new TestWindowDelegate instance and executes
+ // |window_test| after the Window is created. |event| will be signaled once
+ // the Window is closed. If |frameless| is true the Window will be created
+ // without a frame. If |close_window| is true the Window will be closed
+ // immediately after |window_test| returns. Otherwise, the caller is
+ // responsible for closing the Window passed to |window_test|.
+ static void RunTest(CefRefPtr<CefWaitableEvent> event,
+ std::unique_ptr<Config> config);
+
+ // CefWindowDelegate methods:
+ void OnWindowCreated(CefRefPtr<CefWindow> window) override;
+ void OnWindowDestroyed(CefRefPtr<CefWindow> window) override;
+ bool IsFrameless(CefRefPtr<CefWindow> window) override;
+ CefRect GetInitialBounds(CefRefPtr<CefWindow> window) override;
+ CefSize GetPreferredSize(CefRefPtr<CefView> view) override;
+ bool OnAccelerator(CefRefPtr<CefWindow> window, int command_id) override;
+ bool OnKeyEvent(CefRefPtr<CefWindow> window,
+ const CefKeyEvent& event) override;
+
+ private:
+ TestWindowDelegate(CefRefPtr<CefWaitableEvent> event,
+ std::unique_ptr<Config> config,
+ const CefSize& window_size);
+ ~TestWindowDelegate() override;
+
+ void OnCloseWindow();
+ void OnTimeoutWindow();
+
+ CefRefPtr<CefWaitableEvent> event_;
+ std::unique_ptr<Config> config_;
+ const CefSize window_size_;
+
+ CefRefPtr<CefWindow> window_;
+
+ bool got_get_initial_bounds_ = false;
+ bool got_get_preferred_size_ = false;
+
+ // Must be the last member.
+ base::WeakPtrFactory<TestWindowDelegate> weak_ptr_factory_;
+
+ IMPLEMENT_REFCOUNTING(TestWindowDelegate);
+ DISALLOW_COPY_AND_ASSIGN(TestWindowDelegate);
+};
diff --git a/tests/ceftests/views/textfield_unittest.cc b/tests/ceftests/views/textfield_unittest.cc
new file mode 100644
index 00000000..8c08fbfc
--- /dev/null
+++ b/tests/ceftests/views/textfield_unittest.cc
@@ -0,0 +1,312 @@
+// Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "include/base/cef_callback.h"
+#include "include/cef_pack_strings.h"
+#include "include/views/cef_textfield.h"
+#include "include/views/cef_textfield_delegate.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "tests/ceftests/thread_helper.h"
+#include "tests/ceftests/views/test_window_delegate.h"
+#include "tests/gtest/include/gtest/gtest.h"
+
+// See ui/events/keycodes/keyboard_codes.h
+#define VKEY_UNKNOWN 0
+#if defined(OS_WIN)
+#define VKEY_A 'A'
+#define VKEY_SPACE VK_SPACE
+#define VKEY_RETURN VK_RETURN
+#elif defined(OS_POSIX)
+#define VKEY_A 0x41
+#define VKEY_SPACE 0x20
+#define VKEY_RETURN 0x0D
+#else
+#error "Unsupported platform"
+#endif
+
+#define TEXTFIELD_TEST(name) UI_THREAD_TEST(ViewsTextfieldTest, name)
+#define TEXTFIELD_TEST_ASYNC(name) \
+ UI_THREAD_TEST_ASYNC(ViewsTextfieldTest, name)
+
+namespace {
+
+void RunTextfieldContents(CefRefPtr<CefWindow> window) {
+ CefRefPtr<CefTextfield> textfield = CefTextfield::CreateTextfield(nullptr);
+ EXPECT_TRUE(textfield.get());
+ EXPECT_TRUE(textfield->AsTextfield().get());
+
+ // Must be added to a parent window before retrieving the style to avoid
+ // a CHECK() in View::GetNativeTheme(). See https://crbug.com/1056756.
+ window->AddChildView(textfield);
+ window->Layout();
+
+ // Test defaults.
+ EXPECT_TRUE(textfield->GetText().empty());
+ EXPECT_FALSE(textfield->HasSelection());
+ EXPECT_EQ(CefRange(0, 0), textfield->GetSelectedRange());
+ EXPECT_EQ(0U, textfield->GetCursorPosition());
+
+ // Test set/get text.
+ const char kText[] = "My test message!";
+ textfield->SetText(kText);
+ EXPECT_STREQ(kText, textfield->GetText().ToString().c_str());
+
+ size_t cursor_pos = sizeof(kText) - 1;
+ EXPECT_EQ(cursor_pos, textfield->GetCursorPosition());
+
+ // Test append text.
+ const char kAppendText[] = " And more.";
+ textfield->AppendText(kAppendText);
+ EXPECT_STREQ((std::string(kText) + kAppendText).c_str(),
+ textfield->GetText().ToString().c_str());
+ EXPECT_EQ(cursor_pos, textfield->GetCursorPosition());
+
+ // Test select range.
+ EXPECT_FALSE(textfield->HasSelection());
+ EXPECT_EQ(
+ CefRange(static_cast<int>(cursor_pos), static_cast<int>(cursor_pos)),
+ textfield->GetSelectedRange());
+ textfield->SelectRange(CefRange(0, static_cast<int>(cursor_pos)));
+ EXPECT_TRUE(textfield->HasSelection());
+ EXPECT_EQ(CefRange(0, static_cast<int>(cursor_pos)),
+ textfield->GetSelectedRange());
+ EXPECT_STREQ(kText, textfield->GetSelectedText().ToString().c_str());
+ EXPECT_EQ(cursor_pos, textfield->GetCursorPosition());
+
+ // Test insert or replace.
+ const char kReplaceText[] = "Other text.";
+ textfield->InsertOrReplaceText(kReplaceText);
+ EXPECT_STREQ((std::string(kReplaceText) + kAppendText).c_str(),
+ textfield->GetText().ToString().c_str());
+
+ cursor_pos = sizeof(kReplaceText) - 1;
+ EXPECT_EQ(cursor_pos, textfield->GetCursorPosition());
+
+ // Test select all.
+ EXPECT_FALSE(textfield->HasSelection());
+ textfield->SelectAll(false);
+ EXPECT_TRUE(textfield->HasSelection());
+
+ cursor_pos = sizeof(kReplaceText) + sizeof(kAppendText) - 2;
+ EXPECT_EQ(CefRange(0, static_cast<int>(cursor_pos)),
+ textfield->GetSelectedRange());
+ EXPECT_EQ(cursor_pos, textfield->GetCursorPosition());
+
+ // Test clear selection.
+ textfield->ClearSelection();
+ EXPECT_FALSE(textfield->HasSelection());
+ EXPECT_EQ(
+ CefRange(static_cast<int>(cursor_pos), static_cast<int>(cursor_pos)),
+ textfield->GetSelectedRange());
+ EXPECT_EQ(cursor_pos, textfield->GetCursorPosition());
+
+ // Test selection with command.
+ EXPECT_TRUE(textfield->IsCommandEnabled(CEF_TFC_SELECT_ALL));
+ textfield->ExecuteCommand(CEF_TFC_SELECT_ALL);
+ EXPECT_TRUE(textfield->HasSelection());
+ EXPECT_EQ(CefRange(0, static_cast<int>(cursor_pos)),
+ textfield->GetSelectedRange());
+ EXPECT_EQ(cursor_pos, textfield->GetCursorPosition());
+
+ textfield->ClearEditHistory();
+}
+
+void TextfieldContentsImpl(CefRefPtr<CefWaitableEvent> event) {
+ auto config = std::make_unique<TestWindowDelegate::Config>();
+ config->on_window_created = base::BindOnce(RunTextfieldContents);
+ TestWindowDelegate::RunTest(event, std::move(config));
+}
+
+void RunTextfieldStyle(CefRefPtr<CefWindow> window) {
+ CefRefPtr<CefTextfield> textfield = CefTextfield::CreateTextfield(nullptr);
+ EXPECT_TRUE(textfield.get());
+
+ // Must be added to a parent window before retrieving the style to avoid
+ // a CHECK() in View::GetNativeTheme(). See https://crbug.com/1056756.
+ window->AddChildView(textfield);
+ window->Layout();
+
+ // Test defaults.
+ EXPECT_FALSE(textfield->IsPasswordInput());
+ EXPECT_FALSE(textfield->IsReadOnly());
+
+ // Test password input.
+ textfield->SetPasswordInput(true);
+ EXPECT_TRUE(textfield->IsPasswordInput());
+ textfield->SetPasswordInput(false);
+ EXPECT_FALSE(textfield->IsPasswordInput());
+
+ // Test read only.
+ textfield->SetReadOnly(true);
+ EXPECT_TRUE(textfield->IsReadOnly());
+ textfield->SetReadOnly(false);
+ EXPECT_FALSE(textfield->IsReadOnly());
+
+ // Test colors.
+ const cef_color_t color = CefColorSetARGB(255, 255, 0, 255);
+
+ EXPECT_NE(color, textfield->GetTextColor());
+ textfield->SetTextColor(color);
+ EXPECT_EQ(color, textfield->GetTextColor());
+
+ EXPECT_NE(color, textfield->GetSelectionTextColor());
+ textfield->SetSelectionTextColor(color);
+ EXPECT_EQ(color, textfield->GetSelectionTextColor());
+
+ EXPECT_NE(color, textfield->GetSelectionBackgroundColor());
+ textfield->SetSelectionBackgroundColor(color);
+ EXPECT_EQ(color, textfield->GetSelectionBackgroundColor());
+
+ textfield->SetPlaceholderTextColor(color);
+
+ // Test fonts.
+ textfield->SetFontList("Arial, 14px");
+
+ // Test format ranges.
+ const char kText[] = "test text";
+ textfield->SetText(kText);
+ textfield->ApplyTextColor(color, CefRange(0, 5));
+ textfield->ApplyTextStyle(CEF_TEXT_STYLE_BOLD, true, CefRange(0, 5));
+
+ // Test placeholder text.
+ textfield->SetPlaceholderText(kText);
+ EXPECT_STREQ(kText, textfield->GetPlaceholderText().ToString().c_str());
+
+ textfield->SetAccessibleName("MyTextfield");
+}
+
+void TextfieldStyleImpl(CefRefPtr<CefWaitableEvent> event) {
+ auto config = std::make_unique<TestWindowDelegate::Config>();
+ config->on_window_created = base::BindOnce(RunTextfieldStyle);
+ TestWindowDelegate::RunTest(event, std::move(config));
+}
+
+} // namespace
+
+// Test Textfield getters/setters.
+TEXTFIELD_TEST_ASYNC(TextfieldContents)
+TEXTFIELD_TEST_ASYNC(TextfieldStyle)
+
+namespace {
+
+const int kTextfieldID = 1;
+
+// Contents need to be supported by the TranslateKey function.
+const char kTestInputMessage[] = "Test Message";
+
+void TranslateKey(int c, int* keycode, uint32* modifiers) {
+ *keycode = VKEY_UNKNOWN;
+ *modifiers = 0;
+
+ if (c >= 'a' && c <= 'z') {
+ *keycode = VKEY_A + (c - 'a');
+ } else if (c >= 'A' && c <= 'Z') {
+ *keycode = VKEY_A + (c - 'A');
+ *modifiers = EVENTFLAG_SHIFT_DOWN;
+ } else if (c == ' ') {
+ *keycode = VKEY_SPACE;
+ }
+}
+
+class TestTextfieldDelegate : public CefTextfieldDelegate {
+ public:
+ TestTextfieldDelegate() {}
+
+ bool OnKeyEvent(CefRefPtr<CefTextfield> textfield,
+ const CefKeyEvent& event) override {
+ EXPECT_TRUE(textfield.get());
+ EXPECT_EQ(textfield->GetID(), kTextfieldID);
+
+ if (event.type == KEYEVENT_RAWKEYDOWN &&
+ event.windows_key_code == VKEY_RETURN) {
+ // Got the whole string. Finish the test asynchronously.
+ CefPostTask(TID_UI, base::BindOnce(&TestTextfieldDelegate::FinishTest,
+ this, textfield));
+ return true;
+ }
+
+ if (event.type == KEYEVENT_CHAR) {
+ int keycode;
+ uint32 modifiers;
+ TranslateKey(kTestInputMessage[index_++], &keycode, &modifiers);
+
+ EXPECT_EQ(keycode, event.windows_key_code);
+ EXPECT_EQ(modifiers, event.modifiers);
+ }
+
+ return false;
+ }
+
+ void OnAfterUserAction(CefRefPtr<CefTextfield> textfield) override {
+ after_user_action_ct_++;
+ }
+
+ private:
+ void FinishTest(CefRefPtr<CefTextfield> textfield) {
+ // OnAfterUserAction() should be called for each unhandled character.
+ EXPECT_EQ(sizeof(kTestInputMessage) - 1, after_user_action_ct_);
+
+ // Verify the completed contents.
+ EXPECT_STREQ(kTestInputMessage, textfield->GetText().ToString().c_str());
+
+ // Close the window to end the test.
+ textfield->GetWindow()->Close();
+ }
+
+ int index_ = 0;
+ size_t after_user_action_ct_ = 0;
+
+ IMPLEMENT_REFCOUNTING(TestTextfieldDelegate);
+ DISALLOW_COPY_AND_ASSIGN(TestTextfieldDelegate);
+};
+
+void RunTextfieldKeyEvent(CefRefPtr<CefWindow> window) {
+ CefRefPtr<CefTextfield> textfield =
+ CefTextfield::CreateTextfield(new TestTextfieldDelegate());
+ textfield->SetID(kTextfieldID);
+
+ EXPECT_TRUE(textfield->AsTextfield());
+ EXPECT_EQ(kTextfieldID, textfield->GetID());
+ EXPECT_TRUE(textfield->IsVisible());
+ EXPECT_FALSE(textfield->IsDrawn());
+
+ window->AddChildView(textfield);
+ window->Layout();
+
+ EXPECT_TRUE(window->IsSame(textfield->GetWindow()));
+ EXPECT_TRUE(window->IsSame(textfield->GetParentView()));
+ EXPECT_TRUE(textfield->IsSame(window->GetViewForID(kTextfieldID)));
+ EXPECT_TRUE(textfield->IsVisible());
+ EXPECT_TRUE(textfield->IsDrawn());
+
+ window->Show();
+
+ // Give input focus to the textfield.
+ textfield->RequestFocus();
+
+ // Send the contents of |kTestInputMessage| to the textfield.
+ for (size_t i = 0; i < sizeof(kTestInputMessage) - 1; ++i) {
+ int keycode;
+ uint32 modifiers;
+ TranslateKey(kTestInputMessage[i], &keycode, &modifiers);
+ window->SendKeyPress(keycode, modifiers);
+ }
+
+ // Send return to end the text input.
+ window->SendKeyPress(VKEY_RETURN, 0);
+}
+
+void TextfieldKeyEventImpl(CefRefPtr<CefWaitableEvent> event) {
+ auto config = std::make_unique<TestWindowDelegate::Config>();
+ config->on_window_created = base::BindOnce(RunTextfieldKeyEvent);
+ config->close_window = false;
+ TestWindowDelegate::RunTest(event, std::move(config));
+}
+
+} // namespace
+
+// Test Textfield input and events. This is primarily to exercise exposed CEF
+// APIs and is not intended to comprehensively test Textfield-related behavior
+// (which we presume that Chromium is testing).
+TEXTFIELD_TEST_ASYNC(TextfieldKeyEvent)
diff --git a/tests/ceftests/views/window_unittest.cc b/tests/ceftests/views/window_unittest.cc
new file mode 100644
index 00000000..0c8d6b82
--- /dev/null
+++ b/tests/ceftests/views/window_unittest.cc
@@ -0,0 +1,520 @@
+// Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "include/base/cef_callback.h"
+#include "include/views/cef_box_layout.h"
+#include "include/views/cef_layout.h"
+#include "include/views/cef_panel.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "tests/ceftests/image_util.h"
+#include "tests/ceftests/thread_helper.h"
+#include "tests/ceftests/views/test_window_delegate.h"
+#include "tests/gtest/include/gtest/gtest.h"
+
+#define WINDOW_TEST_ASYNC(name) UI_THREAD_TEST_ASYNC(ViewsWindowTest, name)
+
+#if !defined(OS_WIN)
+#define VK_MENU 0x12 // ALT key.
+#endif
+
+namespace {
+
+// Window state change delay in MS.
+const int kStateDelayMS = 200;
+
+const int kWSize = TestWindowDelegate::kWSize;
+
+// Test that |expected| and |actual| are within |allowed_deviance| of each
+// other.
+void ExpectCloseRects(const CefRect& expected,
+ const CefRect& actual,
+ int allowed_deviance) {
+ EXPECT_LE(abs(expected.x - actual.x), allowed_deviance);
+ EXPECT_LE(abs(expected.y - actual.y), allowed_deviance);
+ EXPECT_LE(abs(expected.width - actual.width), allowed_deviance);
+ EXPECT_LE(abs(expected.height - actual.height), allowed_deviance);
+}
+
+void WindowCreateImpl(CefRefPtr<CefWaitableEvent> event) {
+ auto config = std::make_unique<TestWindowDelegate::Config>();
+ TestWindowDelegate::RunTest(event, std::move(config));
+}
+
+void WindowCreateFramelessImpl(CefRefPtr<CefWaitableEvent> event) {
+ auto config = std::make_unique<TestWindowDelegate::Config>();
+ config->frameless = true;
+ TestWindowDelegate::RunTest(event, std::move(config));
+}
+
+void RunWindowShow(CefRefPtr<CefWindow> window) {
+ EXPECT_FALSE(window->IsVisible());
+ EXPECT_FALSE(window->IsDrawn());
+ window->Show();
+ EXPECT_TRUE(window->IsVisible());
+ EXPECT_TRUE(window->IsDrawn());
+}
+
+void WindowCreateWithOriginImpl(CefRefPtr<CefWaitableEvent> event) {
+ auto config = std::make_unique<TestWindowDelegate::Config>();
+ config->window_origin = {100, 200};
+ config->on_window_created = base::BindOnce(RunWindowShow);
+ TestWindowDelegate::RunTest(event, std::move(config));
+}
+
+void RunWindowShowHide(CefRefPtr<CefWindow> window) {
+ RunWindowShow(window);
+ window->Hide();
+ EXPECT_FALSE(window->IsVisible());
+ EXPECT_FALSE(window->IsDrawn());
+}
+
+void WindowShowHideImpl(CefRefPtr<CefWaitableEvent> event) {
+ auto config = std::make_unique<TestWindowDelegate::Config>();
+ config->on_window_created = base::BindOnce(RunWindowShowHide);
+ TestWindowDelegate::RunTest(event, std::move(config));
+}
+
+void WindowShowHideFramelessImpl(CefRefPtr<CefWaitableEvent> event) {
+ auto config = std::make_unique<TestWindowDelegate::Config>();
+ config->on_window_created = base::BindOnce(RunWindowShowHide);
+ config->frameless = true;
+ TestWindowDelegate::RunTest(event, std::move(config));
+}
+
+const int kWPanel1ID = 1;
+const int kWPanel2ID = 2;
+
+void CreateBoxLayout(CefRefPtr<CefWindow> parent) {
+ CefRefPtr<CefPanel> panel_child1 = CefPanel::CreatePanel(nullptr);
+ panel_child1->SetID(kWPanel1ID);
+ panel_child1->SetBackgroundColor(CefColorSetARGB(255, 0, 0, 255));
+ EXPECT_TRUE(panel_child1->IsVisible());
+ EXPECT_FALSE(panel_child1->IsDrawn());
+
+ CefRefPtr<CefPanel> panel_child2 = CefPanel::CreatePanel(nullptr);
+ panel_child2->SetID(kWPanel2ID);
+ panel_child2->SetBackgroundColor(CefColorSetARGB(255, 0, 255, 0));
+ EXPECT_TRUE(panel_child2->IsVisible());
+ EXPECT_FALSE(panel_child2->IsDrawn());
+
+ // Set to BoxLayout. Default layout is vertical with children stretched along
+ // the horizontal axis.
+ CefBoxLayoutSettings settings;
+ parent->SetToBoxLayout(settings);
+
+ parent->AddChildView(panel_child1);
+ parent->AddChildView(panel_child2);
+
+ // IsDrawn() returns true because the Panels now have a RootView from the
+ // Window.
+ EXPECT_TRUE(panel_child1->IsDrawn());
+ EXPECT_TRUE(panel_child1->IsDrawn());
+
+ // Stretch children equally along the vertical axis using flex.
+ CefRefPtr<CefBoxLayout> layout = parent->GetLayout()->AsBoxLayout();
+ layout->SetFlexForView(panel_child1, 1);
+ layout->SetFlexForView(panel_child2, 1);
+
+ // Force layout.
+ parent->Layout();
+
+ // The children should each take up 50% of the client area.
+ ExpectCloseRects(CefRect(0, 0, kWSize, kWSize / 2), panel_child1->GetBounds(),
+ 2);
+ ExpectCloseRects(CefRect(0, kWSize / 2, kWSize, kWSize / 2),
+ panel_child2->GetBounds(), 2);
+}
+
+void RunWindowLayoutAndCoords(CefRefPtr<CefWindow> window) {
+ CreateBoxLayout(window);
+
+ CefRefPtr<CefView> view1 = window->GetViewForID(kWPanel1ID);
+ EXPECT_TRUE(view1.get());
+ CefRefPtr<CefView> view2 = window->GetViewForID(kWPanel2ID);
+ EXPECT_TRUE(view2.get());
+
+ window->Show();
+
+ CefRect client_bounds_in_screen = window->GetClientAreaBoundsInScreen();
+ CefPoint point;
+
+ // Test view to screen coordinate conversions.
+ point = CefPoint(0, 0);
+ EXPECT_TRUE(view1->ConvertPointToScreen(point));
+ EXPECT_EQ(CefPoint(client_bounds_in_screen.x, client_bounds_in_screen.y),
+ point);
+ point = CefPoint(0, 0);
+ EXPECT_TRUE(view2->ConvertPointToScreen(point));
+ EXPECT_EQ(CefPoint(client_bounds_in_screen.x,
+ client_bounds_in_screen.y + kWSize / 2),
+ point);
+
+ // Test view from screen coordinate conversions.
+ point = CefPoint(client_bounds_in_screen.x, client_bounds_in_screen.y);
+ EXPECT_TRUE(view1->ConvertPointFromScreen(point));
+ EXPECT_EQ(CefPoint(0, 0), point);
+ point = CefPoint(client_bounds_in_screen.x,
+ client_bounds_in_screen.y + kWSize / 2);
+ EXPECT_TRUE(view2->ConvertPointFromScreen(point));
+ EXPECT_EQ(CefPoint(0, 0), point);
+
+ // Test view to window coordinate conversions.
+ point = CefPoint(0, 0);
+ EXPECT_TRUE(view1->ConvertPointToWindow(point));
+ EXPECT_EQ(CefPoint(0, 0), point);
+ point = CefPoint(0, 0);
+ EXPECT_TRUE(view2->ConvertPointToWindow(point));
+ EXPECT_EQ(CefPoint(0, kWSize / 2), point);
+
+ // Test view from window coordinate conversions.
+ point = CefPoint(0, 0);
+ EXPECT_TRUE(view1->ConvertPointFromWindow(point));
+ EXPECT_EQ(CefPoint(0, 0), point);
+ point = CefPoint(0, kWSize / 2);
+ EXPECT_TRUE(view2->ConvertPointFromWindow(point));
+ EXPECT_EQ(CefPoint(0, 0), point);
+
+ // Test view to view coordinate conversions.
+ point = CefPoint(0, 0);
+ EXPECT_TRUE(view1->ConvertPointToView(view2, point));
+ EXPECT_EQ(CefPoint(0, -kWSize / 2), point);
+ point = CefPoint(0, 0);
+ EXPECT_TRUE(view2->ConvertPointToView(view1, point));
+ EXPECT_EQ(CefPoint(0, kWSize / 2), point);
+
+ // Test view from view coordinate conversions.
+ point = CefPoint(0, -kWSize / 2);
+ EXPECT_TRUE(view1->ConvertPointFromView(view2, point));
+ EXPECT_EQ(CefPoint(0, 0), point);
+ point = CefPoint(0, kWSize / 2);
+ EXPECT_TRUE(view2->ConvertPointFromView(view1, point));
+ EXPECT_EQ(CefPoint(0, 0), point);
+
+ CefRefPtr<CefDisplay> display = window->GetDisplay();
+ EXPECT_TRUE(display.get());
+
+ // We don't know what the pixel values will be, but they should be reversable.
+ point = CefPoint(client_bounds_in_screen.x, client_bounds_in_screen.y);
+ display->ConvertPointToPixels(point);
+ display->ConvertPointFromPixels(point);
+ EXPECT_EQ(CefPoint(client_bounds_in_screen.x, client_bounds_in_screen.y),
+ point);
+
+ // We don't know what the pixel values will be, but they should be reversable.
+ point = CefPoint(client_bounds_in_screen.x, client_bounds_in_screen.y);
+ const auto pixels = CefDisplay::ConvertScreenPointToPixels(point);
+ const auto dip = CefDisplay::ConvertScreenPointFromPixels(pixels);
+ EXPECT_EQ(point, dip);
+}
+
+void WindowLayoutAndCoordsImpl(CefRefPtr<CefWaitableEvent> event) {
+ auto config = std::make_unique<TestWindowDelegate::Config>();
+ config->on_window_created = base::BindOnce(RunWindowLayoutAndCoords);
+ TestWindowDelegate::RunTest(event, std::move(config));
+}
+
+void WindowLayoutAndCoordsFramelessImpl(CefRefPtr<CefWaitableEvent> event) {
+ auto config = std::make_unique<TestWindowDelegate::Config>();
+ config->on_window_created = base::BindOnce(RunWindowLayoutAndCoords);
+ config->frameless = true;
+ TestWindowDelegate::RunTest(event, std::move(config));
+}
+
+void VerifyRestore(CefRefPtr<CefWindow> window) {
+ EXPECT_FALSE(window->IsMinimized());
+ EXPECT_FALSE(window->IsMaximized());
+ EXPECT_FALSE(window->IsFullscreen());
+ EXPECT_TRUE(window->IsVisible());
+ EXPECT_TRUE(window->IsDrawn());
+
+ // End the test by closing the Window.
+ window->Close();
+}
+
+void VerifyMaximize(CefRefPtr<CefWindow> window) {
+ EXPECT_FALSE(window->IsMinimized());
+ EXPECT_TRUE(window->IsMaximized());
+ EXPECT_FALSE(window->IsFullscreen());
+ EXPECT_TRUE(window->IsVisible());
+ EXPECT_TRUE(window->IsDrawn());
+
+ window->Restore();
+ CefPostDelayedTask(TID_UI, base::BindOnce(VerifyRestore, window),
+ kStateDelayMS);
+}
+
+void RunWindowMaximize(CefRefPtr<CefWindow> window) {
+ CreateBoxLayout(window);
+ window->Show();
+ EXPECT_FALSE(window->IsMinimized());
+ EXPECT_FALSE(window->IsMaximized());
+ EXPECT_FALSE(window->IsFullscreen());
+ EXPECT_TRUE(window->IsVisible());
+ EXPECT_TRUE(window->IsDrawn());
+
+ window->Maximize();
+ CefPostDelayedTask(TID_UI, base::BindOnce(VerifyMaximize, window),
+ kStateDelayMS);
+}
+
+void WindowMaximizeImpl(CefRefPtr<CefWaitableEvent> event) {
+ auto config = std::make_unique<TestWindowDelegate::Config>();
+ config->on_window_created = base::BindOnce(RunWindowMaximize);
+ config->close_window = false;
+ TestWindowDelegate::RunTest(event, std::move(config));
+}
+
+void WindowMaximizeFramelessImpl(CefRefPtr<CefWaitableEvent> event) {
+ auto config = std::make_unique<TestWindowDelegate::Config>();
+ config->on_window_created = base::BindOnce(RunWindowMaximize);
+ config->frameless = true;
+ config->close_window = false;
+ TestWindowDelegate::RunTest(event, std::move(config));
+}
+
+void VerifyMinimize(CefRefPtr<CefWindow> window) {
+ EXPECT_TRUE(window->IsMinimized());
+ EXPECT_FALSE(window->IsMaximized());
+ EXPECT_FALSE(window->IsFullscreen());
+
+ // This result is a bit unexpected, but I guess the platform considers a
+ // window to be visible even when it's minimized.
+ EXPECT_TRUE(window->IsVisible());
+ EXPECT_TRUE(window->IsDrawn());
+
+ window->Restore();
+ CefPostDelayedTask(TID_UI, base::BindOnce(VerifyRestore, window),
+ kStateDelayMS);
+}
+
+void RunWindowMinimize(CefRefPtr<CefWindow> window) {
+ CreateBoxLayout(window);
+ window->Show();
+ EXPECT_FALSE(window->IsMinimized());
+ EXPECT_FALSE(window->IsMaximized());
+ EXPECT_FALSE(window->IsFullscreen());
+ EXPECT_TRUE(window->IsVisible());
+ EXPECT_TRUE(window->IsDrawn());
+
+ window->Minimize();
+ CefPostDelayedTask(TID_UI, base::BindOnce(VerifyMinimize, window),
+ kStateDelayMS);
+}
+
+void WindowMinimizeImpl(CefRefPtr<CefWaitableEvent> event) {
+ auto config = std::make_unique<TestWindowDelegate::Config>();
+ config->on_window_created = base::BindOnce(RunWindowMinimize);
+ config->close_window = false;
+ TestWindowDelegate::RunTest(event, std::move(config));
+}
+
+void WindowMinimizeFramelessImpl(CefRefPtr<CefWaitableEvent> event) {
+ auto config = std::make_unique<TestWindowDelegate::Config>();
+ config->on_window_created = base::BindOnce(RunWindowMinimize);
+ config->frameless = true;
+ config->close_window = false;
+ TestWindowDelegate::RunTest(event, std::move(config));
+}
+
+void VerifyFullscreenExit(CefRefPtr<CefWindow> window) {
+ EXPECT_FALSE(window->IsMinimized());
+ EXPECT_FALSE(window->IsMaximized());
+ EXPECT_FALSE(window->IsFullscreen());
+ EXPECT_TRUE(window->IsVisible());
+ EXPECT_TRUE(window->IsDrawn());
+
+ // End the test by closing the Window.
+ window->Close();
+}
+
+void VerifyFullscreen(CefRefPtr<CefWindow> window) {
+ EXPECT_FALSE(window->IsMinimized());
+ EXPECT_FALSE(window->IsMaximized());
+ EXPECT_TRUE(window->IsFullscreen());
+ EXPECT_TRUE(window->IsVisible());
+ EXPECT_TRUE(window->IsDrawn());
+
+ window->SetFullscreen(false);
+ CefPostDelayedTask(TID_UI, base::BindOnce(VerifyFullscreenExit, window),
+ kStateDelayMS);
+}
+
+void RunWindowFullscreen(CefRefPtr<CefWindow> window) {
+ CreateBoxLayout(window);
+ window->Show();
+ EXPECT_FALSE(window->IsMinimized());
+ EXPECT_FALSE(window->IsMaximized());
+ EXPECT_FALSE(window->IsFullscreen());
+ EXPECT_TRUE(window->IsVisible());
+ EXPECT_TRUE(window->IsDrawn());
+
+ window->SetFullscreen(true);
+ CefPostDelayedTask(TID_UI, base::BindOnce(VerifyFullscreen, window),
+ kStateDelayMS);
+}
+
+void WindowFullscreenImpl(CefRefPtr<CefWaitableEvent> event) {
+ auto config = std::make_unique<TestWindowDelegate::Config>();
+ config->on_window_created = base::BindOnce(RunWindowFullscreen);
+ config->close_window = false;
+ TestWindowDelegate::RunTest(event, std::move(config));
+}
+
+void WindowFullscreenFramelessImpl(CefRefPtr<CefWaitableEvent> event) {
+ auto config = std::make_unique<TestWindowDelegate::Config>();
+ config->on_window_created = base::BindOnce(RunWindowFullscreen);
+ config->frameless = true;
+ config->close_window = false;
+ TestWindowDelegate::RunTest(event, std::move(config));
+}
+
+void RunWindowIcon(CefRefPtr<CefWindow> window) {
+ CefRefPtr<CefImage> image = CefImage::CreateImage();
+ image_util::LoadIconImage(image, 1.0);
+ image_util::LoadIconImage(image, 2.0);
+
+ EXPECT_FALSE(window->GetWindowIcon().get());
+ window->SetWindowIcon(image);
+ EXPECT_TRUE(image->IsSame(window->GetWindowIcon()));
+
+ EXPECT_FALSE(window->GetWindowAppIcon().get());
+ window->SetWindowAppIcon(image);
+ EXPECT_TRUE(image->IsSame(window->GetWindowAppIcon()));
+
+ window->Show();
+}
+
+void WindowIconImpl(CefRefPtr<CefWaitableEvent> event) {
+ auto config = std::make_unique<TestWindowDelegate::Config>();
+ config->on_window_created = base::BindOnce(RunWindowIcon);
+ TestWindowDelegate::RunTest(event, std::move(config));
+}
+
+void WindowIconFramelessImpl(CefRefPtr<CefWaitableEvent> event) {
+ auto config = std::make_unique<TestWindowDelegate::Config>();
+ config->on_window_created = base::BindOnce(RunWindowIcon);
+ config->frameless = true;
+ TestWindowDelegate::RunTest(event, std::move(config));
+}
+
+const int kChar = 'A';
+const int kCloseWindowId = 2;
+bool got_accelerator;
+int got_key_event_alt_count;
+bool got_key_event_char;
+
+void TriggerAccelerator(CefRefPtr<CefWindow> window) {
+ window->SendKeyPress(kChar, EVENTFLAG_ALT_DOWN);
+}
+
+bool OnKeyEvent(CefRefPtr<CefWindow> window, const CefKeyEvent& event) {
+ if (event.type != KEYEVENT_RAWKEYDOWN) {
+ return false;
+ }
+
+ if (event.windows_key_code == VK_MENU) {
+ // First we get the ALT key press in all cases.
+ EXPECT_FALSE(got_key_event_char);
+ if (got_key_event_alt_count == 0) {
+ EXPECT_FALSE(got_accelerator);
+ } else {
+ EXPECT_TRUE(got_accelerator);
+ }
+
+ EXPECT_EQ(EVENTFLAG_ALT_DOWN, static_cast<int>(event.modifiers));
+ got_key_event_alt_count++;
+ } else if (event.windows_key_code == kChar) {
+ // Then we get the char key press with the ALT modifier if the accelerator
+ // isn't registered.
+ EXPECT_TRUE(got_accelerator);
+ EXPECT_EQ(got_key_event_alt_count, 2);
+ EXPECT_FALSE(got_key_event_char);
+
+ EXPECT_EQ(EVENTFLAG_ALT_DOWN, static_cast<int>(event.modifiers));
+ got_key_event_char = true;
+
+ // Call this method just to make sure it doesn't crash.
+ window->RemoveAllAccelerators();
+
+ // End the test by closing the Window.
+ window->Close();
+
+ return true;
+ }
+
+ return false;
+}
+
+bool OnAccelerator(CefRefPtr<CefWindow> window, int command_id) {
+ EXPECT_FALSE(got_accelerator);
+ EXPECT_EQ(got_key_event_alt_count, 1);
+ EXPECT_FALSE(got_key_event_char);
+
+ EXPECT_EQ(kCloseWindowId, command_id);
+ got_accelerator = true;
+
+ // Remove the accelerator.
+ window->RemoveAccelerator(kCloseWindowId);
+
+ // Now send the event without the accelerator registered. Should result in a
+ // call to OnKeyEvent.
+ TriggerAccelerator(window);
+
+ return true;
+}
+
+void RunWindowAccelerator(CefRefPtr<CefWindow> window) {
+ window->SetAccelerator(kCloseWindowId, kChar, false, false, true);
+ window->Show();
+
+ CefPostDelayedTask(TID_UI, base::BindOnce(TriggerAccelerator, window),
+ kStateDelayMS);
+}
+
+void VerifyWindowAccelerator(CefRefPtr<CefWindow> window) {
+ EXPECT_TRUE(got_accelerator);
+ EXPECT_EQ(got_key_event_alt_count, 2);
+ EXPECT_TRUE(got_key_event_char);
+}
+
+// Expected order of events:
+// 1. OnKeyEvent for ALT key press.
+// 2. OnAccelerator for ALT+Char key press (with accelerator registered).
+// 3. OnKeyEvent for ALT key press.
+// 4. OnKeyEvent for ALT+Char key press (without accelerator registered).
+void WindowAcceleratorImpl(CefRefPtr<CefWaitableEvent> event) {
+ got_accelerator = false;
+ got_key_event_alt_count = 0;
+ got_key_event_char = false;
+
+ auto config = std::make_unique<TestWindowDelegate::Config>();
+ config->on_window_created = base::BindOnce(RunWindowAccelerator);
+ config->on_window_destroyed = base::BindOnce(VerifyWindowAccelerator);
+ config->on_accelerator = base::BindRepeating(OnAccelerator);
+ config->on_key_event = base::BindRepeating(OnKeyEvent);
+ config->close_window = false;
+ TestWindowDelegate::RunTest(event, std::move(config));
+}
+
+} // namespace
+
+// Test window functionality. This is primarily to exercise exposed CEF APIs
+// and is not intended to comprehensively test window-related behavior (which
+// we presume that Chromium is testing).
+WINDOW_TEST_ASYNC(WindowCreate)
+WINDOW_TEST_ASYNC(WindowCreateFrameless)
+WINDOW_TEST_ASYNC(WindowCreateWithOrigin)
+WINDOW_TEST_ASYNC(WindowShowHide)
+WINDOW_TEST_ASYNC(WindowShowHideFrameless)
+WINDOW_TEST_ASYNC(WindowLayoutAndCoords)
+WINDOW_TEST_ASYNC(WindowLayoutAndCoordsFrameless)
+WINDOW_TEST_ASYNC(WindowMaximize)
+WINDOW_TEST_ASYNC(WindowMaximizeFrameless)
+WINDOW_TEST_ASYNC(WindowMinimize)
+WINDOW_TEST_ASYNC(WindowMinimizeFrameless)
+WINDOW_TEST_ASYNC(WindowFullscreen)
+WINDOW_TEST_ASYNC(WindowFullscreenFrameless)
+WINDOW_TEST_ASYNC(WindowIcon)
+WINDOW_TEST_ASYNC(WindowIconFrameless)
+WINDOW_TEST_ASYNC(WindowAccelerator)
diff --git a/tests/ceftests/waitable_event_unittest.cc b/tests/ceftests/waitable_event_unittest.cc
new file mode 100644
index 00000000..abda2668
--- /dev/null
+++ b/tests/ceftests/waitable_event_unittest.cc
@@ -0,0 +1,79 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. Portions copyright
+// 2012 The Chromium Authors. All rights reserved. Use of this source code is
+// governed by a BSD-style license that can be found in the LICENSE file.
+
+#include "include/base/cef_callback.h"
+#include "include/cef_thread.h"
+#include "include/cef_waitable_event.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "tests/gtest/include/gtest/gtest.h"
+
+// Test manual reset.
+TEST(WaitableEventTest, ManualReset) {
+ CefRefPtr<CefWaitableEvent> event =
+ CefWaitableEvent::CreateWaitableEvent(false, false);
+
+ EXPECT_FALSE(event->IsSignaled());
+
+ event->Signal();
+ EXPECT_TRUE(event->IsSignaled());
+ EXPECT_TRUE(event->IsSignaled());
+
+ event->Reset();
+ EXPECT_FALSE(event->IsSignaled());
+ EXPECT_FALSE(event->TimedWait(10));
+
+ event->Signal();
+ event->Wait();
+ EXPECT_TRUE(event->TimedWait(10));
+}
+
+// Test automatic reset.
+TEST(WaitableEventTest, AutomaticReset) {
+ CefRefPtr<CefWaitableEvent> event =
+ CefWaitableEvent::CreateWaitableEvent(true, false);
+
+ EXPECT_FALSE(event->IsSignaled());
+
+ event->Signal();
+ EXPECT_TRUE(event->IsSignaled());
+ EXPECT_FALSE(event->IsSignaled());
+
+ event->Reset();
+ EXPECT_FALSE(event->IsSignaled());
+ EXPECT_FALSE(event->TimedWait(10));
+
+ event->Signal();
+ event->Wait();
+ EXPECT_FALSE(event->TimedWait(10));
+
+ event->Signal();
+ EXPECT_TRUE(event->TimedWait(10));
+}
+
+namespace {
+
+void SignalEvent(CefWaitableEvent* event) {
+ event->Signal();
+}
+
+} // namespace
+
+// Tests that a WaitableEvent can be safely deleted when |Wait| is done without
+// additional synchronization.
+TEST(WaitableEventTest, WaitAndDelete) {
+ CefRefPtr<CefWaitableEvent> event =
+ CefWaitableEvent::CreateWaitableEvent(true, false);
+
+ CefRefPtr<CefThread> thread = CefThread::CreateThread("waitable_event_test");
+ thread->GetTaskRunner()->PostDelayedTask(
+ CefCreateClosureTask(
+ base::BindOnce(SignalEvent, base::Unretained(event.get()))),
+ 10);
+
+ event->Wait();
+ event = nullptr;
+
+ thread->Stop();
+ thread = nullptr;
+}
diff --git a/tests/ceftests/webui_unittest.cc b/tests/ceftests/webui_unittest.cc
new file mode 100644
index 00000000..c02acf91
--- /dev/null
+++ b/tests/ceftests/webui_unittest.cc
@@ -0,0 +1,206 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include <algorithm>
+#include <memory>
+
+#include "include/base/cef_callback.h"
+#include "include/cef_callback.h"
+#include "include/cef_parser.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "tests/ceftests/test_handler.h"
+#include "tests/gtest/include/gtest/gtest.h"
+
+namespace {
+
+typedef std::vector<std::string> UrlList;
+
+class WebUITestHandler : public TestHandler {
+ public:
+ explicit WebUITestHandler(const UrlList& url_list)
+ : url_list_(url_list), url_index_(0U), expected_error_code_(ERR_NONE) {
+ CHECK(!url_list_.empty());
+ }
+
+ void set_expected_url(const std::string& expected_url) {
+ expected_url_ = expected_url;
+ }
+
+ void set_expected_error_code(int error_code) {
+ expected_error_code_ = error_code;
+ }
+
+ void RunTest() override {
+ // Create the browser.
+ CreateBrowser(url_list_[0]);
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout((int(url_list_.size() / 5U) + 1) * 5000);
+ }
+
+ void NextNav() {
+ base::OnceClosure next_action;
+
+ if (++url_index_ < url_list_.size()) {
+ next_action = base::BindOnce(&WebUITestHandler::LoadURL, this,
+ url_list_[url_index_]);
+ } else {
+ next_action = base::BindOnce(&WebUITestHandler::DestroyTest, this);
+ }
+
+ // Wait a bit for the WebUI content to finish loading before performing the
+ // next action.
+ CefPostDelayedTask(TID_UI, std::move(next_action), 200);
+ }
+
+ void LoadURL(const std::string& url) {
+ GetBrowser()->GetMainFrame()->LoadURL(url);
+ }
+
+ void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,
+ bool isLoading,
+ bool canGoBack,
+ bool canGoForward) override {
+ if (!isLoading) {
+ got_loading_state_done_.yes();
+ NextNavIfDone(browser->GetMainFrame()->GetURL());
+ }
+ }
+
+ void OnLoadError(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ ErrorCode errorCode,
+ const CefString& errorText,
+ const CefString& failedUrl) override {
+ got_load_error_.yes();
+ EXPECT_EQ(expected_error_code_, errorCode)
+ << "failedUrl = " << failedUrl.ToString();
+ NextNavIfDone(failedUrl);
+ }
+
+ void DestroyTest() override {
+ EXPECT_TRUE(got_loading_state_done_);
+ if (expected_error_code_ == ERR_NONE) {
+ EXPECT_FALSE(got_load_error_);
+ } else {
+ EXPECT_TRUE(got_load_error_);
+ }
+
+ TestHandler::DestroyTest();
+ }
+
+ private:
+ void NextNavIfDone(const std::string& url) {
+ bool done = false;
+ if (expected_error_code_ == ERR_NONE) {
+ if (got_loading_state_done_) {
+ done = true;
+ }
+ } else if (got_load_error_ && got_loading_state_done_) {
+ done = true;
+ }
+
+ if (done) {
+ // Verify that we navigated to the expected URL.
+ std::string expected_url = expected_url_;
+ if (expected_url.empty() && url_index_ < url_list_.size()) {
+ expected_url = url_list_[url_index_];
+ }
+ EXPECT_STREQ(expected_url.c_str(), url.c_str());
+
+ NextNav();
+ }
+ }
+
+ UrlList url_list_;
+ size_t url_index_;
+
+ std::string expected_url_;
+ int expected_error_code_;
+
+ TrackCallback got_loading_state_done_;
+ TrackCallback got_load_error_;
+
+ IMPLEMENT_REFCOUNTING(WebUITestHandler);
+};
+
+} // namespace
+
+// Test hosts with special behaviors.
+
+// about:* URIs should redirect to chrome://*.
+TEST(WebUITest, about) {
+ UrlList url_list;
+ url_list.push_back("about:license");
+ CefRefPtr<WebUITestHandler> handler = new WebUITestHandler(url_list);
+ handler->set_expected_url("chrome://license/");
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// chrome://network-error/X should generate network error X.
+TEST(WebUITest, network_error) {
+ UrlList url_list;
+ // -310 is ERR_TOO_MANY_REDIRECTS
+ url_list.push_back("chrome://network-error/-310");
+ CefRefPtr<WebUITestHandler> handler = new WebUITestHandler(url_list);
+ handler->set_expected_error_code(ERR_TOO_MANY_REDIRECTS);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Test hosts with a single URL.
+
+namespace {
+
+void RunWebUITest(const UrlList& url_list) {
+ CefRefPtr<WebUITestHandler> handler = new WebUITestHandler(url_list);
+ handler->ExecuteTest();
+ ReleaseAndWaitForDestructor(handler);
+}
+
+void RunWebUITest(const std::string& url) {
+ UrlList url_list;
+ url_list.push_back(url);
+ RunWebUITest(url_list);
+}
+
+} // namespace
+
+#define WEBUI_TEST(name) \
+ TEST(WebUITest, name) { \
+ std::string name_str = #name; \
+ std::replace(name_str.begin(), name_str.end(), '_', '-'); \
+ RunWebUITest("chrome://" + name_str + "/"); \
+ }
+
+WEBUI_TEST(accessibility)
+WEBUI_TEST(blob_internals)
+WEBUI_TEST(extensions_support)
+WEBUI_TEST(gpu)
+WEBUI_TEST(histograms)
+WEBUI_TEST(indexeddb_internals)
+WEBUI_TEST(license)
+WEBUI_TEST(media_internals)
+WEBUI_TEST(net_export)
+WEBUI_TEST(network_errors)
+WEBUI_TEST(serviceworker_internals)
+WEBUI_TEST(system)
+WEBUI_TEST(tracing)
+WEBUI_TEST(version)
+WEBUI_TEST(webrtc_internals)
+WEBUI_TEST(webui_hosts)
+
+// Test hosts with multiple URLs.
+
+TEST(WebUITest, net_internals) {
+ UrlList url_list;
+ url_list.push_back("chrome://net-internals/#events");
+ url_list.push_back("chrome://net-internals/#proxy");
+ url_list.push_back("chrome://net-internals/#dns");
+ url_list.push_back("chrome://net-internals/#sockets");
+ url_list.push_back("chrome://net-internals/#hsts");
+
+ RunWebUITest(url_list);
+}
diff --git a/tests/ceftests/xml_reader_unittest.cc b/tests/ceftests/xml_reader_unittest.cc
new file mode 100644
index 00000000..b6b76517
--- /dev/null
+++ b/tests/ceftests/xml_reader_unittest.cc
@@ -0,0 +1,640 @@
+// Copyright (c) 2010 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "include/cef_stream.h"
+#include "include/cef_xml_reader.h"
+#include "include/wrapper/cef_xml_object.h"
+#include "tests/gtest/include/gtest/gtest.h"
+
+namespace {
+
+char g_test_xml[] =
+ "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"
+ "<?my_instruction my_value?>\n"
+ "<!DOCTYPE my_document SYSTEM \"example.dtd\" [\n"
+ " <!ENTITY EA \"EA Value\">\n"
+ " <!ENTITY EB \"EB Value\">\n"
+ "]>\n"
+ "<ns:obj xmlns:ns=\"http://www.example.org/ns\">\n"
+ " <ns:objA>value A</ns:objA>\n"
+ " <!-- my comment -->\n"
+ " <ns:objB>\n"
+ " <ns:objB_1>value B1</ns:objB_1>\n"
+ " <ns:objB_2><![CDATA[some <br/> data]]></ns:objB_2>\n"
+ " <ns:objB_3>&EB;</ns:objB_3>\n"
+ " <ns:objB_4><b>this is</b> mixed content &EA;</ns:objB_4>\n"
+ " </ns:objB>\n"
+ " <ns:objC ns:attr1=\"value C1\" ns:attr2=\"value C2\"/><ns:objD>"
+ "</ns:objD>\n"
+ "</ns:obj>\n";
+
+} // namespace
+
+// Test XML reading
+TEST(XmlReaderTest, Read) {
+ // Create the stream reader.
+ CefRefPtr<CefStreamReader> stream(
+ CefStreamReader::CreateForData(g_test_xml, sizeof(g_test_xml) - 1));
+ ASSERT_TRUE(stream.get() != nullptr);
+
+ // Create the XML reader.
+ CefRefPtr<CefXmlReader> reader(CefXmlReader::Create(
+ stream, XML_ENCODING_NONE, "http://www.example.org/example.xml"));
+ ASSERT_TRUE(reader.get() != nullptr);
+
+ // Move to the processing instruction node.
+ ASSERT_TRUE(reader->MoveToNextNode());
+ ASSERT_EQ(reader->GetDepth(), 0);
+ ASSERT_EQ(reader->GetType(), XML_NODE_PROCESSING_INSTRUCTION);
+ ASSERT_EQ(reader->GetLocalName(), "my_instruction");
+ ASSERT_EQ(reader->GetQualifiedName(), "my_instruction");
+ ASSERT_TRUE(reader->HasValue());
+ ASSERT_EQ(reader->GetValue(), "my_value");
+
+ // Move to the DOCTYPE node.
+ ASSERT_TRUE(reader->MoveToNextNode());
+ ASSERT_EQ(reader->GetDepth(), 0);
+ ASSERT_EQ(reader->GetType(), XML_NODE_DOCUMENT_TYPE);
+ ASSERT_EQ(reader->GetLocalName(), "my_document");
+ ASSERT_EQ(reader->GetQualifiedName(), "my_document");
+ ASSERT_FALSE(reader->HasValue());
+
+ // Move to ns:obj element start node.
+ ASSERT_TRUE(reader->MoveToNextNode());
+ ASSERT_EQ(reader->GetDepth(), 0);
+ ASSERT_EQ(reader->GetType(), XML_NODE_ELEMENT_START);
+ ASSERT_EQ(reader->GetLocalName(), "obj");
+ ASSERT_EQ(reader->GetPrefix(), "ns");
+ ASSERT_EQ(reader->GetQualifiedName(), "ns:obj");
+ ASSERT_EQ(reader->GetNamespaceURI(), "http://www.example.org/ns");
+ ASSERT_TRUE(reader->HasAttributes());
+ ASSERT_EQ(reader->GetAttributeCount(), (size_t)1);
+ ASSERT_EQ(reader->GetAttribute(0), "http://www.example.org/ns");
+ ASSERT_EQ(reader->GetAttribute("xmlns:ns"), "http://www.example.org/ns");
+ ASSERT_EQ(reader->GetAttribute("ns", "http://www.w3.org/2000/xmlns/"),
+ "http://www.example.org/ns");
+
+ // Move to the whitespace node.
+ ASSERT_TRUE(reader->MoveToNextNode());
+ ASSERT_EQ(reader->GetType(), XML_NODE_WHITESPACE);
+
+ // Move to the ns:objA element start node.
+ ASSERT_TRUE(reader->MoveToNextNode());
+ ASSERT_EQ(reader->GetDepth(), 1);
+ ASSERT_EQ(reader->GetType(), XML_NODE_ELEMENT_START);
+ ASSERT_EQ(reader->GetLocalName(), "objA");
+ ASSERT_EQ(reader->GetPrefix(), "ns");
+ ASSERT_EQ(reader->GetQualifiedName(), "ns:objA");
+ ASSERT_EQ(reader->GetNamespaceURI(), "http://www.example.org/ns");
+ ASSERT_FALSE(reader->IsEmptyElement());
+ ASSERT_FALSE(reader->HasAttributes());
+ ASSERT_FALSE(reader->HasValue());
+
+ // Move to the ns:objA value node.
+ ASSERT_TRUE(reader->MoveToNextNode());
+ ASSERT_EQ(reader->GetDepth(), 2);
+ ASSERT_EQ(reader->GetType(), XML_NODE_TEXT);
+ ASSERT_EQ(reader->GetLocalName(), "#text");
+ ASSERT_EQ(reader->GetQualifiedName(), "#text");
+ ASSERT_TRUE(reader->HasValue());
+ ASSERT_EQ(reader->GetValue(), "value A");
+
+ // Move to the ns:objA element ending node.
+ ASSERT_TRUE(reader->MoveToNextNode());
+ ASSERT_EQ(reader->GetDepth(), 1);
+ ASSERT_EQ(reader->GetType(), XML_NODE_ELEMENT_END);
+ ASSERT_EQ(reader->GetLocalName(), "objA");
+ ASSERT_EQ(reader->GetPrefix(), "ns");
+ ASSERT_EQ(reader->GetQualifiedName(), "ns:objA");
+ ASSERT_EQ(reader->GetNamespaceURI(), "http://www.example.org/ns");
+ ASSERT_FALSE(reader->IsEmptyElement());
+ ASSERT_FALSE(reader->HasAttributes());
+ ASSERT_FALSE(reader->HasValue());
+
+ // Move to the whitespace node.
+ ASSERT_TRUE(reader->MoveToNextNode());
+ ASSERT_EQ(reader->GetDepth(), 1);
+ ASSERT_EQ(reader->GetType(), XML_NODE_WHITESPACE);
+
+ // Move to the comment node.
+ ASSERT_TRUE(reader->MoveToNextNode());
+ ASSERT_EQ(reader->GetDepth(), 1);
+ ASSERT_EQ(reader->GetType(), XML_NODE_COMMENT);
+ ASSERT_EQ(reader->GetLocalName(), "#comment");
+ ASSERT_EQ(reader->GetQualifiedName(), "#comment");
+ ASSERT_TRUE(reader->HasValue());
+ ASSERT_EQ(reader->GetValue(), " my comment ");
+
+ // Move to the whitespace node.
+ ASSERT_TRUE(reader->MoveToNextNode());
+ ASSERT_EQ(reader->GetType(), XML_NODE_WHITESPACE);
+
+ // Move to the ns:objB element start node.
+ ASSERT_TRUE(reader->MoveToNextNode());
+ ASSERT_EQ(reader->GetDepth(), 1);
+ ASSERT_EQ(reader->GetType(), XML_NODE_ELEMENT_START);
+ ASSERT_EQ(reader->GetLocalName(), "objB");
+ ASSERT_EQ(reader->GetPrefix(), "ns");
+ ASSERT_EQ(reader->GetQualifiedName(), "ns:objB");
+ ASSERT_EQ(reader->GetNamespaceURI(), "http://www.example.org/ns");
+ ASSERT_FALSE(reader->IsEmptyElement());
+ ASSERT_FALSE(reader->HasAttributes());
+ ASSERT_FALSE(reader->HasValue());
+
+ // Move to the whitespace node.
+ ASSERT_TRUE(reader->MoveToNextNode());
+ ASSERT_EQ(reader->GetType(), XML_NODE_WHITESPACE);
+
+ // Move to the ns:objB_1 element start node.
+ ASSERT_TRUE(reader->MoveToNextNode());
+ ASSERT_EQ(reader->GetDepth(), 2);
+ ASSERT_EQ(reader->GetType(), XML_NODE_ELEMENT_START);
+ ASSERT_EQ(reader->GetLocalName(), "objB_1");
+ ASSERT_EQ(reader->GetPrefix(), "ns");
+ ASSERT_EQ(reader->GetQualifiedName(), "ns:objB_1");
+ ASSERT_EQ(reader->GetNamespaceURI(), "http://www.example.org/ns");
+ ASSERT_FALSE(reader->IsEmptyElement());
+ ASSERT_FALSE(reader->HasAttributes());
+ ASSERT_FALSE(reader->HasValue());
+
+ // Move to the ns:objB_1 value node.
+ ASSERT_TRUE(reader->MoveToNextNode());
+ ASSERT_EQ(reader->GetDepth(), 3);
+ ASSERT_EQ(reader->GetType(), XML_NODE_TEXT);
+ ASSERT_TRUE(reader->HasValue());
+ ASSERT_EQ(reader->GetValue(), "value B1");
+
+ // Move to the ns:objB_1 element ending node.
+ ASSERT_TRUE(reader->MoveToNextNode());
+ ASSERT_EQ(reader->GetDepth(), 2);
+ ASSERT_EQ(reader->GetType(), XML_NODE_ELEMENT_END);
+ ASSERT_EQ(reader->GetLocalName(), "objB_1");
+ ASSERT_EQ(reader->GetPrefix(), "ns");
+ ASSERT_EQ(reader->GetQualifiedName(), "ns:objB_1");
+ ASSERT_EQ(reader->GetNamespaceURI(), "http://www.example.org/ns");
+ ASSERT_FALSE(reader->IsEmptyElement());
+ ASSERT_FALSE(reader->HasAttributes());
+ ASSERT_FALSE(reader->HasValue());
+
+ // Move to the whitespace node.
+ ASSERT_TRUE(reader->MoveToNextNode());
+ ASSERT_EQ(reader->GetType(), XML_NODE_WHITESPACE);
+
+ // Move to the ns:objB_2 element start node.
+ ASSERT_TRUE(reader->MoveToNextNode());
+ ASSERT_EQ(reader->GetDepth(), 2);
+ ASSERT_EQ(reader->GetType(), XML_NODE_ELEMENT_START);
+ ASSERT_EQ(reader->GetLocalName(), "objB_2");
+ ASSERT_EQ(reader->GetPrefix(), "ns");
+ ASSERT_EQ(reader->GetQualifiedName(), "ns:objB_2");
+ ASSERT_EQ(reader->GetNamespaceURI(), "http://www.example.org/ns");
+ ASSERT_FALSE(reader->IsEmptyElement());
+ ASSERT_FALSE(reader->HasAttributes());
+ ASSERT_FALSE(reader->HasValue());
+
+ // Move to the ns:objB_2 value node.
+ ASSERT_TRUE(reader->MoveToNextNode());
+ ASSERT_EQ(reader->GetDepth(), 3);
+ ASSERT_EQ(reader->GetType(), XML_NODE_CDATA);
+ ASSERT_TRUE(reader->HasValue());
+ ASSERT_EQ(reader->GetValue(), "some <br/> data");
+
+ // Move to the ns:objB_2 element ending node.
+ ASSERT_TRUE(reader->MoveToNextNode());
+ ASSERT_EQ(reader->GetDepth(), 2);
+ ASSERT_EQ(reader->GetType(), XML_NODE_ELEMENT_END);
+ ASSERT_EQ(reader->GetLocalName(), "objB_2");
+ ASSERT_EQ(reader->GetPrefix(), "ns");
+ ASSERT_EQ(reader->GetQualifiedName(), "ns:objB_2");
+ ASSERT_EQ(reader->GetNamespaceURI(), "http://www.example.org/ns");
+ ASSERT_FALSE(reader->IsEmptyElement());
+ ASSERT_FALSE(reader->HasAttributes());
+ ASSERT_FALSE(reader->HasValue());
+
+ // Move to the whitespace node.
+ ASSERT_TRUE(reader->MoveToNextNode());
+ ASSERT_EQ(reader->GetType(), XML_NODE_WHITESPACE);
+
+ // Move to the ns:objB_3 element start node.
+ ASSERT_TRUE(reader->MoveToNextNode());
+ ASSERT_EQ(reader->GetDepth(), 2);
+ ASSERT_EQ(reader->GetType(), XML_NODE_ELEMENT_START);
+ ASSERT_EQ(reader->GetLocalName(), "objB_3");
+ ASSERT_EQ(reader->GetPrefix(), "ns");
+ ASSERT_EQ(reader->GetQualifiedName(), "ns:objB_3");
+ ASSERT_EQ(reader->GetNamespaceURI(), "http://www.example.org/ns");
+ ASSERT_FALSE(reader->IsEmptyElement());
+ ASSERT_FALSE(reader->HasAttributes());
+ ASSERT_FALSE(reader->HasValue());
+
+ // Move to the EB entity reference node.
+ ASSERT_TRUE(reader->MoveToNextNode());
+ ASSERT_EQ(reader->GetDepth(), 3);
+ ASSERT_EQ(reader->GetType(), XML_NODE_ENTITY_REFERENCE);
+ ASSERT_EQ(reader->GetLocalName(), "EB");
+ ASSERT_EQ(reader->GetQualifiedName(), "EB");
+ ASSERT_TRUE(reader->HasValue());
+ ASSERT_EQ(reader->GetValue(), "EB Value");
+
+ // Move to the ns:objB_3 element ending node.
+ ASSERT_TRUE(reader->MoveToNextNode());
+ ASSERT_EQ(reader->GetDepth(), 2);
+ ASSERT_EQ(reader->GetType(), XML_NODE_ELEMENT_END);
+ ASSERT_EQ(reader->GetLocalName(), "objB_3");
+ ASSERT_EQ(reader->GetPrefix(), "ns");
+ ASSERT_EQ(reader->GetQualifiedName(), "ns:objB_3");
+ ASSERT_EQ(reader->GetNamespaceURI(), "http://www.example.org/ns");
+ ASSERT_FALSE(reader->IsEmptyElement());
+ ASSERT_FALSE(reader->HasAttributes());
+ ASSERT_FALSE(reader->HasValue());
+
+ // Move to the whitespace node.
+ ASSERT_TRUE(reader->MoveToNextNode());
+ ASSERT_EQ(reader->GetType(), XML_NODE_WHITESPACE);
+
+ // Move to the ns:objB_4 element start node.
+ ASSERT_TRUE(reader->MoveToNextNode());
+ ASSERT_EQ(reader->GetDepth(), 2);
+ ASSERT_EQ(reader->GetType(), XML_NODE_ELEMENT_START);
+ ASSERT_EQ(reader->GetLocalName(), "objB_4");
+ ASSERT_EQ(reader->GetPrefix(), "ns");
+ ASSERT_EQ(reader->GetQualifiedName(), "ns:objB_4");
+ ASSERT_EQ(reader->GetNamespaceURI(), "http://www.example.org/ns");
+ ASSERT_FALSE(reader->IsEmptyElement());
+ ASSERT_FALSE(reader->HasAttributes());
+ ASSERT_FALSE(reader->HasValue());
+ ASSERT_EQ(reader->GetInnerXml(), "<b>this is</b> mixed content &EA;");
+ ASSERT_EQ(reader->GetOuterXml(),
+ "<ns:objB_4 xmlns:ns=\"http://www.example.org/ns\">"
+ "<b>this is</b> mixed content &EA;</ns:objB_4>");
+
+ // Move to the <b> element node.
+ ASSERT_TRUE(reader->MoveToNextNode());
+ ASSERT_EQ(reader->GetDepth(), 3);
+ ASSERT_EQ(reader->GetType(), XML_NODE_ELEMENT_START);
+ ASSERT_EQ(reader->GetLocalName(), "b");
+ ASSERT_EQ(reader->GetQualifiedName(), "b");
+ ASSERT_FALSE(reader->IsEmptyElement());
+ ASSERT_FALSE(reader->HasAttributes());
+ ASSERT_FALSE(reader->HasValue());
+
+ // Move to the text node.
+ ASSERT_TRUE(reader->MoveToNextNode());
+ ASSERT_EQ(reader->GetDepth(), 4);
+ ASSERT_EQ(reader->GetType(), XML_NODE_TEXT);
+ ASSERT_EQ(reader->GetLocalName(), "#text");
+ ASSERT_EQ(reader->GetQualifiedName(), "#text");
+ ASSERT_TRUE(reader->HasValue());
+ ASSERT_EQ(reader->GetValue(), "this is");
+
+ // Move to the </b> element node.
+ ASSERT_TRUE(reader->MoveToNextNode());
+ ASSERT_EQ(reader->GetDepth(), 3);
+ ASSERT_EQ(reader->GetType(), XML_NODE_ELEMENT_END);
+ ASSERT_EQ(reader->GetLocalName(), "b");
+ ASSERT_EQ(reader->GetQualifiedName(), "b");
+
+ // Move to the text node.
+ ASSERT_TRUE(reader->MoveToNextNode());
+ ASSERT_EQ(reader->GetDepth(), 3);
+ ASSERT_EQ(reader->GetType(), XML_NODE_TEXT);
+ ASSERT_EQ(reader->GetLocalName(), "#text");
+ ASSERT_EQ(reader->GetQualifiedName(), "#text");
+ ASSERT_TRUE(reader->HasValue());
+ ASSERT_EQ(reader->GetValue(), " mixed content ");
+
+ // Move to the EA entity reference node.
+ ASSERT_TRUE(reader->MoveToNextNode());
+ ASSERT_EQ(reader->GetDepth(), 3);
+ ASSERT_EQ(reader->GetType(), XML_NODE_ENTITY_REFERENCE);
+ ASSERT_EQ(reader->GetLocalName(), "EA");
+ ASSERT_EQ(reader->GetQualifiedName(), "EA");
+ ASSERT_TRUE(reader->HasValue());
+ ASSERT_EQ(reader->GetValue(), "EA Value");
+
+ // Move to the ns:objB_4 element ending node.
+ ASSERT_TRUE(reader->MoveToNextNode());
+ ASSERT_EQ(reader->GetDepth(), 2);
+ ASSERT_EQ(reader->GetType(), XML_NODE_ELEMENT_END);
+ ASSERT_EQ(reader->GetLocalName(), "objB_4");
+ ASSERT_EQ(reader->GetPrefix(), "ns");
+ ASSERT_EQ(reader->GetQualifiedName(), "ns:objB_4");
+ ASSERT_EQ(reader->GetNamespaceURI(), "http://www.example.org/ns");
+ ASSERT_FALSE(reader->IsEmptyElement());
+ ASSERT_FALSE(reader->HasAttributes());
+ ASSERT_FALSE(reader->HasValue());
+
+ // Move to the whitespace node.
+ ASSERT_TRUE(reader->MoveToNextNode());
+ ASSERT_EQ(reader->GetType(), XML_NODE_WHITESPACE);
+
+ // Move to the ns:objB element ending node.
+ ASSERT_TRUE(reader->MoveToNextNode());
+ ASSERT_EQ(reader->GetDepth(), 1);
+ ASSERT_EQ(reader->GetType(), XML_NODE_ELEMENT_END);
+ ASSERT_EQ(reader->GetLocalName(), "objB");
+ ASSERT_EQ(reader->GetPrefix(), "ns");
+ ASSERT_EQ(reader->GetQualifiedName(), "ns:objB");
+ ASSERT_EQ(reader->GetNamespaceURI(), "http://www.example.org/ns");
+ ASSERT_FALSE(reader->IsEmptyElement());
+ ASSERT_FALSE(reader->HasAttributes());
+ ASSERT_FALSE(reader->HasValue());
+
+ // Move to the whitespace node.
+ ASSERT_TRUE(reader->MoveToNextNode());
+ ASSERT_EQ(reader->GetType(), XML_NODE_WHITESPACE);
+
+ // Move to the ns:objC element start node.
+ ASSERT_TRUE(reader->MoveToNextNode());
+ ASSERT_EQ(reader->GetDepth(), 1);
+ ASSERT_EQ(reader->GetType(), XML_NODE_ELEMENT_START);
+ ASSERT_EQ(reader->GetLocalName(), "objC");
+ ASSERT_EQ(reader->GetPrefix(), "ns");
+ ASSERT_EQ(reader->GetQualifiedName(), "ns:objC");
+ ASSERT_EQ(reader->GetNamespaceURI(), "http://www.example.org/ns");
+ ASSERT_TRUE(reader->IsEmptyElement());
+ ASSERT_TRUE(reader->HasAttributes());
+ ASSERT_FALSE(reader->HasValue());
+ ASSERT_EQ(reader->GetAttributeCount(), (size_t)2);
+ ASSERT_EQ(reader->GetAttribute(0), "value C1");
+ ASSERT_EQ(reader->GetAttribute("ns:attr1"), "value C1");
+ ASSERT_EQ(reader->GetAttribute("attr1", "http://www.example.org/ns"),
+ "value C1");
+ ASSERT_EQ(reader->GetAttribute(1), "value C2");
+ ASSERT_EQ(reader->GetAttribute("ns:attr2"), "value C2");
+ ASSERT_EQ(reader->GetAttribute("attr2", "http://www.example.org/ns"),
+ "value C2");
+
+ // Move to the ns:attr1 attribute.
+ ASSERT_TRUE(reader->MoveToFirstAttribute());
+ ASSERT_EQ(reader->GetDepth(), 2);
+ ASSERT_EQ(reader->GetType(), XML_NODE_ATTRIBUTE);
+ ASSERT_EQ(reader->GetLocalName(), "attr1");
+ ASSERT_EQ(reader->GetPrefix(), "ns");
+ ASSERT_EQ(reader->GetQualifiedName(), "ns:attr1");
+ ASSERT_EQ(reader->GetNamespaceURI(), "http://www.example.org/ns");
+ ASSERT_TRUE(reader->HasValue());
+ ASSERT_FALSE(reader->IsEmptyElement());
+ ASSERT_FALSE(reader->HasAttributes());
+ ASSERT_EQ(reader->GetValue(), "value C1");
+
+ // Move to the ns:attr2 attribute.
+ ASSERT_TRUE(reader->MoveToNextAttribute());
+ ASSERT_EQ(reader->GetDepth(), 2);
+ ASSERT_EQ(reader->GetType(), XML_NODE_ATTRIBUTE);
+ ASSERT_EQ(reader->GetLocalName(), "attr2");
+ ASSERT_EQ(reader->GetPrefix(), "ns");
+ ASSERT_EQ(reader->GetQualifiedName(), "ns:attr2");
+ ASSERT_EQ(reader->GetNamespaceURI(), "http://www.example.org/ns");
+ ASSERT_TRUE(reader->HasValue());
+ ASSERT_FALSE(reader->IsEmptyElement());
+ ASSERT_FALSE(reader->HasAttributes());
+ ASSERT_EQ(reader->GetValue(), "value C2");
+
+ // No more attributes.
+ ASSERT_FALSE(reader->MoveToNextAttribute());
+
+ // Return to the ns:objC element start node.
+ ASSERT_TRUE(reader->MoveToCarryingElement());
+ ASSERT_EQ(reader->GetDepth(), 1);
+ ASSERT_EQ(reader->GetType(), XML_NODE_ELEMENT_START);
+ ASSERT_EQ(reader->GetQualifiedName(), "ns:objC");
+
+ // Move to the ns:attr1 attribute.
+ ASSERT_TRUE(reader->MoveToAttribute(0));
+ ASSERT_EQ(reader->GetDepth(), 2);
+ ASSERT_EQ(reader->GetType(), XML_NODE_ATTRIBUTE);
+ ASSERT_EQ(reader->GetLocalName(), "attr1");
+ ASSERT_EQ(reader->GetPrefix(), "ns");
+ ASSERT_EQ(reader->GetQualifiedName(), "ns:attr1");
+ ASSERT_EQ(reader->GetNamespaceURI(), "http://www.example.org/ns");
+ ASSERT_TRUE(reader->HasValue());
+ ASSERT_FALSE(reader->IsEmptyElement());
+ ASSERT_FALSE(reader->HasAttributes());
+ ASSERT_EQ(reader->GetValue(), "value C1");
+
+ // Return to the ns:objC element start node.
+ ASSERT_TRUE(reader->MoveToCarryingElement());
+ ASSERT_EQ(reader->GetDepth(), 1);
+ ASSERT_EQ(reader->GetType(), XML_NODE_ELEMENT_START);
+ ASSERT_EQ(reader->GetQualifiedName(), "ns:objC");
+
+ // Move to the ns:attr2 attribute.
+ ASSERT_TRUE(reader->MoveToAttribute("ns:attr2"));
+ ASSERT_EQ(reader->GetDepth(), 2);
+ ASSERT_EQ(reader->GetType(), XML_NODE_ATTRIBUTE);
+ ASSERT_EQ(reader->GetLocalName(), "attr2");
+ ASSERT_EQ(reader->GetPrefix(), "ns");
+ ASSERT_EQ(reader->GetQualifiedName(), "ns:attr2");
+ ASSERT_EQ(reader->GetNamespaceURI(), "http://www.example.org/ns");
+ ASSERT_TRUE(reader->HasValue());
+ ASSERT_FALSE(reader->IsEmptyElement());
+ ASSERT_FALSE(reader->HasAttributes());
+ ASSERT_EQ(reader->GetValue(), "value C2");
+
+ // Move to the ns:attr1 attribute without returning to the ns:objC element.
+ ASSERT_TRUE(reader->MoveToAttribute("attr1", "http://www.example.org/ns"));
+ ASSERT_EQ(reader->GetDepth(), 2);
+ ASSERT_EQ(reader->GetType(), XML_NODE_ATTRIBUTE);
+ ASSERT_EQ(reader->GetLocalName(), "attr1");
+ ASSERT_EQ(reader->GetPrefix(), "ns");
+ ASSERT_EQ(reader->GetQualifiedName(), "ns:attr1");
+ ASSERT_EQ(reader->GetNamespaceURI(), "http://www.example.org/ns");
+ ASSERT_TRUE(reader->HasValue());
+ ASSERT_FALSE(reader->IsEmptyElement());
+ ASSERT_FALSE(reader->HasAttributes());
+ ASSERT_EQ(reader->GetValue(), "value C1");
+
+ // Move to the ns:objD element start node.
+ ASSERT_TRUE(reader->MoveToNextNode());
+ ASSERT_EQ(reader->GetDepth(), 1);
+ ASSERT_EQ(reader->GetType(), XML_NODE_ELEMENT_START);
+ ASSERT_EQ(reader->GetLocalName(), "objD");
+ ASSERT_EQ(reader->GetPrefix(), "ns");
+ ASSERT_EQ(reader->GetQualifiedName(), "ns:objD");
+ ASSERT_FALSE(reader->IsEmptyElement());
+ ASSERT_FALSE(reader->HasAttributes());
+ ASSERT_FALSE(reader->HasValue());
+
+ // Move to the ns:objD element end node.
+ ASSERT_TRUE(reader->MoveToNextNode());
+ ASSERT_EQ(reader->GetDepth(), 1);
+ ASSERT_EQ(reader->GetType(), XML_NODE_ELEMENT_END);
+ ASSERT_EQ(reader->GetLocalName(), "objD");
+ ASSERT_EQ(reader->GetPrefix(), "ns");
+ ASSERT_EQ(reader->GetQualifiedName(), "ns:objD");
+ ASSERT_FALSE(reader->IsEmptyElement());
+ ASSERT_FALSE(reader->HasAttributes());
+ ASSERT_FALSE(reader->HasValue());
+
+ // Move to the whitespace node without returning to the ns:objC element.
+ ASSERT_TRUE(reader->MoveToNextNode());
+ ASSERT_EQ(reader->GetType(), XML_NODE_WHITESPACE);
+
+ // Move to ns:obj element ending node.
+ ASSERT_TRUE(reader->MoveToNextNode());
+ ASSERT_EQ(reader->GetDepth(), 0);
+ ASSERT_EQ(reader->GetType(), XML_NODE_ELEMENT_END);
+ ASSERT_EQ(reader->GetLocalName(), "obj");
+ ASSERT_EQ(reader->GetPrefix(), "ns");
+ ASSERT_EQ(reader->GetQualifiedName(), "ns:obj");
+ ASSERT_EQ(reader->GetNamespaceURI(), "http://www.example.org/ns");
+ ASSERT_FALSE(reader->IsEmptyElement());
+ ASSERT_TRUE(reader->HasAttributes());
+ ASSERT_FALSE(reader->HasValue());
+ // Strangely, the end node will report if the starting node has attributes
+ // but will not provide access to them.
+ ASSERT_TRUE(reader->HasAttributes());
+ ASSERT_EQ(reader->GetAttributeCount(), (size_t)0);
+
+ // And we're done.
+ ASSERT_FALSE(reader->MoveToNextNode());
+
+ ASSERT_TRUE(reader->Close());
+}
+
+// Test XML read error handling.
+TEST(XmlReaderTest, ReadError) {
+ char test_str[] =
+ "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"
+ "<!ATTRIBUTE foo bar>\n";
+
+ // Create the stream reader.
+ CefRefPtr<CefStreamReader> stream(
+ CefStreamReader::CreateForData(test_str, sizeof(test_str) - 1));
+ ASSERT_TRUE(stream.get() != nullptr);
+
+ // Create the XML reader.
+ CefRefPtr<CefXmlReader> reader(CefXmlReader::Create(
+ stream, XML_ENCODING_NONE, "http://www.example.org/example.xml"));
+ ASSERT_TRUE(reader.get() != nullptr);
+
+ // Move to the processing instruction node and generate parser error.
+ ASSERT_FALSE(reader->MoveToNextNode());
+ ASSERT_TRUE(reader->HasError());
+}
+
+// Test XmlObject load behavior.
+TEST(XmlReaderTest, ObjectLoad) {
+ // Create the stream reader.
+ CefRefPtr<CefStreamReader> stream(
+ CefStreamReader::CreateForData(g_test_xml, sizeof(g_test_xml) - 1));
+ ASSERT_TRUE(stream.get() != nullptr);
+
+ // Create the XML reader.
+ CefRefPtr<CefXmlObject> object(new CefXmlObject("object"));
+ ASSERT_TRUE(object->Load(stream, XML_ENCODING_NONE,
+ "http://www.example.org/example.xml", nullptr));
+
+ ASSERT_FALSE(object->HasAttributes());
+ ASSERT_TRUE(object->HasChildren());
+ ASSERT_EQ(object->GetChildCount(), (size_t)1);
+
+ CefRefPtr<CefXmlObject> obj(object->FindChild("ns:obj"));
+ ASSERT_TRUE(obj.get());
+ ASSERT_TRUE(obj->HasChildren());
+ ASSERT_EQ(obj->GetChildCount(), (size_t)4);
+
+ CefRefPtr<CefXmlObject> obj_child(obj->FindChild("ns:objC"));
+ ASSERT_TRUE(obj_child.get());
+ ASSERT_EQ(obj_child->GetName(), "ns:objC");
+ ASSERT_FALSE(obj_child->HasChildren());
+ ASSERT_FALSE(obj_child->HasValue());
+ ASSERT_TRUE(obj_child->HasAttributes());
+
+ CefXmlObject::ObjectVector obj_children;
+ ASSERT_EQ(obj->GetChildren(obj_children), (size_t)4);
+ ASSERT_EQ(obj_children.size(), (size_t)4);
+
+ CefXmlObject::ObjectVector::const_iterator it = obj_children.begin();
+ for (int ct = 0; it != obj_children.end(); ++it, ++ct) {
+ obj_child = *it;
+ ASSERT_TRUE(obj_child.get());
+ if (ct == 0) {
+ // ns:objA
+ ASSERT_EQ(obj_child->GetName(), "ns:objA");
+ ASSERT_FALSE(obj_child->HasChildren());
+ ASSERT_TRUE(obj_child->HasValue());
+ ASSERT_FALSE(obj_child->HasAttributes());
+ ASSERT_EQ(obj_child->GetValue(), "value A");
+ } else if (ct == 1) {
+ // ns:objB
+ ASSERT_EQ(obj_child->GetName(), "ns:objB");
+ ASSERT_TRUE(obj_child->HasChildren());
+ ASSERT_FALSE(obj_child->HasValue());
+ ASSERT_FALSE(obj_child->HasAttributes());
+ ASSERT_EQ(obj_child->GetChildCount(), (size_t)4);
+ obj_child = obj_child->FindChild("ns:objB_4");
+ ASSERT_TRUE(obj_child.get());
+ ASSERT_TRUE(obj_child->HasValue());
+ ASSERT_EQ(obj_child->GetValue(), "<b>this is</b> mixed content EA Value");
+ } else if (ct == 2) {
+ // ns:objC
+ ASSERT_EQ(obj_child->GetName(), "ns:objC");
+ ASSERT_FALSE(obj_child->HasChildren());
+ ASSERT_FALSE(obj_child->HasValue());
+ ASSERT_TRUE(obj_child->HasAttributes());
+
+ CefXmlObject::AttributeMap attribs;
+ ASSERT_EQ(obj_child->GetAttributes(attribs), (size_t)2);
+ ASSERT_EQ(attribs.size(), (size_t)2);
+ ASSERT_EQ(attribs["ns:attr1"], "value C1");
+ ASSERT_EQ(attribs["ns:attr2"], "value C2");
+
+ ASSERT_EQ(obj_child->GetAttributeCount(), (size_t)2);
+ ASSERT_TRUE(obj_child->HasAttribute("ns:attr1"));
+ ASSERT_EQ(obj_child->GetAttributeValue("ns:attr1"), "value C1");
+ ASSERT_TRUE(obj_child->HasAttribute("ns:attr2"));
+ ASSERT_EQ(obj_child->GetAttributeValue("ns:attr2"), "value C2");
+ } else if (ct == 3) {
+ // ns:objD
+ ASSERT_EQ(obj_child->GetName(), "ns:objD");
+ ASSERT_FALSE(obj_child->HasChildren());
+ ASSERT_FALSE(obj_child->HasValue());
+ ASSERT_FALSE(obj_child->HasAttributes());
+ }
+ }
+}
+
+// Test XmlObject load error handling behavior.
+TEST(XmlReaderTest, ObjectLoadError) {
+ // Test start/end tag mismatch error.
+ {
+ char error_xml[] = "<obj>\n<foo>\n</obj>\n</foo>";
+
+ // Create the stream reader.
+ CefRefPtr<CefStreamReader> stream(
+ CefStreamReader::CreateForData(error_xml, sizeof(error_xml) - 1));
+ ASSERT_TRUE(stream.get() != nullptr);
+
+ CefString error_str;
+
+ // Create the XML reader.
+ CefRefPtr<CefXmlObject> object(new CefXmlObject("object"));
+ ASSERT_FALSE(object->Load(stream, XML_ENCODING_NONE,
+ "http://www.example.org/example.xml",
+ &error_str));
+ ASSERT_EQ(error_str,
+ "Opening and ending tag mismatch: foo line 2 and obj, line 3");
+ }
+
+ // Test value following child error.
+ {
+ char error_xml[] = "<obj>\n<foo>\n</foo>disallowed value\n</obj>";
+
+ // Create the stream reader.
+ CefRefPtr<CefStreamReader> stream(
+ CefStreamReader::CreateForData(error_xml, sizeof(error_xml) - 1));
+ ASSERT_TRUE(stream.get() != nullptr);
+
+ CefString error_str;
+
+ // Create the XML reader.
+ CefRefPtr<CefXmlObject> object(new CefXmlObject("object"));
+ ASSERT_FALSE(object->Load(stream, XML_ENCODING_NONE,
+ "http://www.example.org/example.xml",
+ &error_str));
+ ASSERT_EQ(error_str, "Value following child element, line 4");
+ }
+}
diff --git a/tests/ceftests/zip_reader_unittest.cc b/tests/ceftests/zip_reader_unittest.cc
new file mode 100644
index 00000000..7181bff2
--- /dev/null
+++ b/tests/ceftests/zip_reader_unittest.cc
@@ -0,0 +1,252 @@
+// Copyright (c) 2010 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "include/cef_stream.h"
+#include "include/cef_zip_reader.h"
+#include "include/wrapper/cef_zip_archive.h"
+#include "tests/gtest/include/gtest/gtest.h"
+
+namespace {
+
+unsigned char g_test_zip[] = {
+ 0x50, 0x4b, 0x03, 0x04, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0x7f,
+ 0x57, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x61,
+ 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x2f, 0x50, 0x4b, 0x03, 0x04, 0x0a,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x7f, 0x57, 0x3d, 0xf8, 0x47, 0x0c,
+ 0xc6, 0x13, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00,
+ 0x00, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76,
+ 0x65, 0x2f, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x31, 0x2e, 0x74, 0x78, 0x74,
+ 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x6f, 0x66, 0x20,
+ 0x66, 0x69, 0x6c, 0x65, 0x20, 0x31, 0x2e, 0x50, 0x4b, 0x03, 0x04, 0x0a,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x7f, 0x57, 0x3d, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00,
+ 0x00, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76,
+ 0x65, 0x2f, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x20, 0x31, 0x2f, 0x50,
+ 0x4b, 0x03, 0x04, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0x7f, 0x57,
+ 0x3d, 0x43, 0xe3, 0x11, 0x5f, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00,
+ 0x00, 0x21, 0x00, 0x00, 0x00, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x61, 0x72,
+ 0x63, 0x68, 0x69, 0x76, 0x65, 0x2f, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72,
+ 0x20, 0x31, 0x2f, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x31, 0x61, 0x2e, 0x74,
+ 0x78, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x6f,
+ 0x66, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x31, 0x41, 0x2e, 0x50, 0x4b,
+ 0x03, 0x04, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x7f, 0x57, 0x3d,
+ 0x80, 0xb0, 0x3c, 0x74, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
+ 0x21, 0x00, 0x00, 0x00, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x61, 0x72, 0x63,
+ 0x68, 0x69, 0x76, 0x65, 0x2f, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x20,
+ 0x31, 0x2f, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x31, 0x62, 0x2e, 0x74, 0x78,
+ 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x6f, 0x66,
+ 0x20, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x31, 0x42, 0x2e, 0x50, 0x4b, 0x03,
+ 0x04, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x7f, 0x57, 0x3d, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20,
+ 0x00, 0x00, 0x00, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x61, 0x72, 0x63, 0x68,
+ 0x69, 0x76, 0x65, 0x2f, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x20, 0x31,
+ 0x2f, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x20, 0x31, 0x61, 0x2f, 0x50,
+ 0x4b, 0x03, 0x04, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7f, 0x57,
+ 0x3d, 0x15, 0xed, 0x04, 0x2c, 0x15, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00,
+ 0x00, 0x2c, 0x00, 0x00, 0x00, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x61, 0x72,
+ 0x63, 0x68, 0x69, 0x76, 0x65, 0x2f, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72,
+ 0x20, 0x31, 0x2f, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x20, 0x31, 0x61,
+ 0x2f, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x31, 0x61, 0x31, 0x2e, 0x74, 0x78,
+ 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x6f, 0x66,
+ 0x20, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x31, 0x41, 0x31, 0x2e, 0x50, 0x4b,
+ 0x03, 0x04, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x7f, 0x57, 0x3d,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x16, 0x00, 0x00, 0x00, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x61, 0x72, 0x63,
+ 0x68, 0x69, 0x76, 0x65, 0x2f, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x20,
+ 0x32, 0x2f, 0x50, 0x4b, 0x03, 0x04, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x80, 0x57, 0x3d, 0x1a, 0x5d, 0x57, 0x5d, 0x14, 0x00, 0x00, 0x00,
+ 0x14, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x74, 0x65, 0x73, 0x74,
+ 0x5f, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x2f, 0x66, 0x6f, 0x6c,
+ 0x64, 0x65, 0x72, 0x20, 0x32, 0x2f, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x32,
+ 0x61, 0x2e, 0x74, 0x78, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74,
+ 0x73, 0x20, 0x6f, 0x66, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x32, 0x41,
+ 0x2e, 0x50, 0x4b, 0x01, 0x02, 0x14, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x67, 0x7f, 0x57, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74,
+ 0x65, 0x73, 0x74, 0x5f, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x2f,
+ 0x50, 0x4b, 0x01, 0x02, 0x14, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x70, 0x7f, 0x57, 0x3d, 0xf8, 0x47, 0x0c, 0xc6, 0x13, 0x00, 0x00, 0x00,
+ 0x13, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x74, 0x65,
+ 0x73, 0x74, 0x5f, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x2f, 0x66,
+ 0x69, 0x6c, 0x65, 0x20, 0x31, 0x2e, 0x74, 0x78, 0x74, 0x50, 0x4b, 0x01,
+ 0x02, 0x14, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x7f, 0x57,
+ 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x74, 0x65, 0x73, 0x74, 0x5f,
+ 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x2f, 0x66, 0x6f, 0x6c, 0x64,
+ 0x65, 0x72, 0x20, 0x31, 0x2f, 0x50, 0x4b, 0x01, 0x02, 0x14, 0x00, 0x0a,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0x7f, 0x57, 0x3d, 0x43, 0xe3, 0x11,
+ 0x5f, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0xa7,
+ 0x00, 0x00, 0x00, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x61, 0x72, 0x63, 0x68,
+ 0x69, 0x76, 0x65, 0x2f, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x20, 0x31,
+ 0x2f, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x31, 0x61, 0x2e, 0x74, 0x78, 0x74,
+ 0x50, 0x4b, 0x01, 0x02, 0x14, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x78, 0x7f, 0x57, 0x3d, 0x80, 0xb0, 0x3c, 0x74, 0x14, 0x00, 0x00, 0x00,
+ 0x14, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x74, 0x65,
+ 0x73, 0x74, 0x5f, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x2f, 0x66,
+ 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x20, 0x31, 0x2f, 0x66, 0x69, 0x6c, 0x65,
+ 0x20, 0x31, 0x62, 0x2e, 0x74, 0x78, 0x74, 0x50, 0x4b, 0x01, 0x02, 0x14,
+ 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x7f, 0x57, 0x3d, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
+ 0x00, 0x4d, 0x01, 0x00, 0x00, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x61, 0x72,
+ 0x63, 0x68, 0x69, 0x76, 0x65, 0x2f, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72,
+ 0x20, 0x31, 0x2f, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x20, 0x31, 0x61,
+ 0x2f, 0x50, 0x4b, 0x01, 0x02, 0x14, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x7c, 0x7f, 0x57, 0x3d, 0x15, 0xed, 0x04, 0x2c, 0x15, 0x00, 0x00,
+ 0x00, 0x15, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x8b, 0x01, 0x00, 0x00, 0x74,
+ 0x65, 0x73, 0x74, 0x5f, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x2f,
+ 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x20, 0x31, 0x2f, 0x66, 0x6f, 0x6c,
+ 0x64, 0x65, 0x72, 0x20, 0x31, 0x61, 0x2f, 0x66, 0x69, 0x6c, 0x65, 0x20,
+ 0x31, 0x61, 0x31, 0x2e, 0x74, 0x78, 0x74, 0x50, 0x4b, 0x01, 0x02, 0x14,
+ 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x7f, 0x57, 0x3d, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
+ 0x00, 0xea, 0x01, 0x00, 0x00, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x61, 0x72,
+ 0x63, 0x68, 0x69, 0x76, 0x65, 0x2f, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72,
+ 0x20, 0x32, 0x2f, 0x50, 0x4b, 0x01, 0x02, 0x14, 0x00, 0x0a, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x02, 0x80, 0x57, 0x3d, 0x1a, 0x5d, 0x57, 0x5d, 0x14,
+ 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x1e, 0x02, 0x00,
+ 0x00, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76,
+ 0x65, 0x2f, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x20, 0x32, 0x2f, 0x66,
+ 0x69, 0x6c, 0x65, 0x20, 0x32, 0x61, 0x2e, 0x74, 0x78, 0x74, 0x50, 0x4b,
+ 0x05, 0x06, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x09, 0x00, 0x9d, 0x02,
+ 0x00, 0x00, 0x71, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+} // namespace
+
+// Test Zip reading.
+TEST(ZipReaderTest, Read) {
+ // Create the stream reader.
+ CefRefPtr<CefStreamReader> stream(
+ CefStreamReader::CreateForData(g_test_zip, sizeof(g_test_zip) - 1));
+ ASSERT_TRUE(stream.get() != nullptr);
+
+ // Create the Zip reader.
+ CefRefPtr<CefZipReader> reader(CefZipReader::Create(stream));
+ ASSERT_TRUE(reader.get() != nullptr);
+
+ char buff[25];
+
+ // Walk through the archive contents.
+ ASSERT_TRUE(reader->MoveToFirstFile());
+ ASSERT_EQ(reader->GetFileName(), "test_archive/");
+ ASSERT_EQ(reader->GetFileSize(), 0);
+
+ ASSERT_TRUE(reader->MoveToNextFile());
+ ASSERT_EQ(reader->GetFileName(), "test_archive/file 1.txt");
+ ASSERT_EQ(reader->GetFileSize(), 19);
+ ASSERT_TRUE(reader->OpenFile(""));
+ ASSERT_EQ(reader->ReadFile(buff, sizeof(buff)), 19);
+ ASSERT_TRUE(!strncmp(buff, "Contents of file 1.", 19));
+
+ ASSERT_TRUE(reader->MoveToNextFile());
+ ASSERT_EQ(reader->GetFileName(), "test_archive/folder 1/");
+ ASSERT_EQ(reader->GetFileSize(), 0);
+
+ ASSERT_TRUE(reader->MoveToNextFile());
+ ASSERT_EQ(reader->GetFileName(), "test_archive/folder 1/file 1a.txt");
+ ASSERT_EQ(reader->GetFileSize(), 20);
+ ASSERT_TRUE(reader->OpenFile(""));
+ ASSERT_EQ(reader->ReadFile(buff, sizeof(buff)), 20);
+ ASSERT_TRUE(reader->CloseFile());
+ ASSERT_TRUE(!strncmp(buff, "Contents of file 1A.", 20));
+
+ ASSERT_TRUE(reader->MoveToNextFile());
+ ASSERT_EQ(reader->GetFileName(), "test_archive/folder 1/file 1b.txt");
+ ASSERT_EQ(reader->GetFileSize(), 20);
+ ASSERT_TRUE(reader->OpenFile(""));
+ ASSERT_EQ(reader->ReadFile(buff, sizeof(buff)), 20);
+ ASSERT_TRUE(reader->CloseFile());
+ ASSERT_TRUE(!strncmp(buff, "Contents of file 1B.", 20));
+
+ ASSERT_TRUE(reader->MoveToNextFile());
+ ASSERT_EQ(reader->GetFileName(), "test_archive/folder 1/folder 1a/");
+ ASSERT_EQ(reader->GetFileSize(), 0);
+
+ ASSERT_TRUE(reader->MoveToNextFile());
+ ASSERT_EQ(reader->GetFileName(),
+ "test_archive/folder 1/folder 1a/file 1a1.txt");
+ ASSERT_EQ(reader->GetFileSize(), 21);
+ ASSERT_TRUE(reader->OpenFile(""));
+ ASSERT_EQ(reader->ReadFile(buff, sizeof(buff)), 21);
+ ASSERT_TRUE(reader->CloseFile());
+ ASSERT_TRUE(!strncmp(buff, "Contents of file 1A1.", 21));
+
+ ASSERT_TRUE(reader->MoveToNextFile());
+ ASSERT_EQ(reader->GetFileName(), "test_archive/folder 2/");
+ ASSERT_EQ(reader->GetFileSize(), 0);
+
+ ASSERT_TRUE(reader->MoveToNextFile());
+ ASSERT_EQ(reader->GetFileName(), "test_archive/folder 2/file 2a.txt");
+ ASSERT_EQ(reader->GetFileSize(), 20);
+ ASSERT_TRUE(reader->OpenFile(""));
+ ASSERT_EQ(reader->ReadFile(buff, sizeof(buff)), 20);
+ ASSERT_TRUE(reader->CloseFile());
+ ASSERT_TRUE(!strncmp(buff, "Contents of file 2A.", 20));
+
+ ASSERT_FALSE(reader->MoveToNextFile());
+
+ // Try seeking a particular file
+ ASSERT_TRUE(reader->MoveToFile("TEST_ARCHIVE/FOLDER 1/FILE 1B.TXT", false));
+ ASSERT_EQ(reader->GetFileName(), "test_archive/folder 1/file 1b.txt");
+ ASSERT_EQ(reader->GetFileSize(), 20);
+ ASSERT_TRUE(reader->OpenFile(""));
+ ASSERT_EQ(reader->ReadFile(buff, sizeof(buff)), 20);
+ ASSERT_TRUE(reader->CloseFile());
+ ASSERT_TRUE(!strncmp(buff, "Contents of file 1B.", 20));
+
+ ASSERT_TRUE(reader->MoveToFile("test_archive/folder 1/file 1b.txt", true));
+ ASSERT_FALSE(reader->MoveToFile("test_archive/folder 1/FILE 1B.txt", true));
+
+ ASSERT_TRUE(reader->Close());
+}
+
+// Test CefZipArchive object.
+TEST(ZipReaderTest, ReadArchive) {
+ // Create the stream reader.
+ CefRefPtr<CefStreamReader> stream(
+ CefStreamReader::CreateForData(g_test_zip, sizeof(g_test_zip) - 1));
+ ASSERT_TRUE(stream.get() != nullptr);
+
+ // Create the Zip archive object.
+ CefRefPtr<CefZipArchive> archive(new CefZipArchive());
+
+ ASSERT_EQ(archive->Load(stream, CefString(), false), (size_t)5);
+
+ ASSERT_TRUE(archive->HasFile("test_archive/file 1.txt"));
+ ASSERT_TRUE(archive->HasFile("test_archive/folder 1/file 1a.txt"));
+ ASSERT_TRUE(archive->HasFile("test_archive/FOLDER 1/file 1b.txt"));
+ ASSERT_TRUE(archive->HasFile("test_archive/folder 1/folder 1a/file 1a1.txt"));
+ ASSERT_TRUE(archive->HasFile("test_archive/folder 2/file 2a.txt"));
+
+ // Test content retrieval.
+ CefRefPtr<CefZipArchive::File> file;
+ file = archive->GetFile("test_archive/folder 2/file 2a.txt");
+ ASSERT_TRUE(file.get());
+
+ ASSERT_EQ(file->GetDataSize(), (size_t)20);
+ ASSERT_TRUE(!strncmp(reinterpret_cast<const char*>(file->GetData()),
+ "Contents of file 2A.", 20));
+
+ // Test stream reading.
+ CefRefPtr<CefStreamReader> reader(file->GetStreamReader());
+ ASSERT_TRUE(reader.get());
+
+ char buff[8];
+ ASSERT_EQ(reader->Read(buff, 1, 8), (size_t)8);
+ ASSERT_TRUE(!strncmp(buff, "Contents", 8));
+ ASSERT_EQ(reader->Read(buff, 1, 8), (size_t)8);
+ ASSERT_TRUE(!strncmp(buff, " of file", 8));
+ ASSERT_EQ(reader->Read(buff, 1, 8), (size_t)4);
+ ASSERT_TRUE(!strncmp(buff, " 2A.", 4));
+ ASSERT_TRUE(reader->Eof());
+}
diff --git a/tests/gtest/CMakeLists.txt.in b/tests/gtest/CMakeLists.txt.in
new file mode 100644
index 00000000..84fbf4d5
--- /dev/null
+++ b/tests/gtest/CMakeLists.txt.in
@@ -0,0 +1,34 @@
+# Copyright 2016 The Chromium Embedded Framework Authors. All rights
+# reserved. Use of this source code is governed by a BSD-style license that
+# can be found in the LICENSE file.
+
+set(CEF_TARGET "cef_gtest")
+
+set(GTEST_SRCS
+ src/gtest-all.cc
+ teamcity/include/teamcity_gtest.h
+ teamcity/src/teamcity_gtest.cpp
+ teamcity/src/teamcity_messages.cpp
+ teamcity/src/teamcity_messages.h
+ )
+source_group(cef_gtest FILES ${GTEST_SRCS})
+
+add_library(${CEF_TARGET} ${GTEST_SRCS})
+
+# Start with CEF default properties.
+SET_LIBRARY_TARGET_PROPERTIES(${CEF_TARGET})
+
+# The gtest-all.cc file uses #include "gtest/gtest.h"
+target_include_directories(${CEF_TARGET} PRIVATE "include")
+
+# In order to allow regex matches in gtest to be shared between Windows
+# and other systems we tell gtest to always use it's internal engine.
+target_compile_definitions(${CEF_TARGET} PRIVATE -DGTEST_HAS_POSIX_RE=0 -DGTEST_LANG_CXX11=1)
+
+# All dependent targets are unit tests.
+target_compile_definitions(${CEF_TARGET} PUBLIC -DUNIT_TEST)
+
+if(OS_WINDOWS)
+ # Disable unused variable warning.
+ target_compile_options(${CEF_TARGET} PRIVATE "/wd4800")
+endif()
diff --git a/tests/gtest/include/gtest/gtest.h b/tests/gtest/include/gtest/gtest.h
new file mode 100644
index 00000000..aece904a
--- /dev/null
+++ b/tests/gtest/include/gtest/gtest.h
@@ -0,0 +1,9 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+// Include GoogleTest from the Chromium source location. This file will be
+// re-written in the CEF binary distribution to include a fuzed version of
+// GoogleTest from the distribution tests/ folder.
+
+#include "testing/gtest/include/gtest/gtest.h"
diff --git a/tests/gtest/teamcity/README.cef b/tests/gtest/teamcity/README.cef
new file mode 100644
index 00000000..d86ec37e
--- /dev/null
+++ b/tests/gtest/teamcity/README.cef
@@ -0,0 +1,14 @@
+Name: TeamCity C++ Unit Test Reporting
+Short Name: teamcity-cpp
+URL: https://github.com/JetBrains/teamcity-cpp
+Version: 1.8 (commit b2c95c5)
+License: Apache 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
+
+Description:
+GTest integration for reporting to TeamCity Continuous Integration Server.
+
+See the project URL for related documentation.
+
+Local Modifications:
+1. Copy necessary C++ files only.
+1. Use absolute include paths.
diff --git a/tests/gtest/teamcity/include/teamcity_gtest.h b/tests/gtest/teamcity/include/teamcity_gtest.h
new file mode 100644
index 00000000..236f6f98
--- /dev/null
+++ b/tests/gtest/teamcity/include/teamcity_gtest.h
@@ -0,0 +1,55 @@
+/* Copyright 2015 Paul Shmakov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef H_TEAMCITY_GTEST
+#define H_TEAMCITY_GTEST
+
+#include <string>
+
+#include "tests/gtest/include/gtest/gtest.h"
+#include "tests/gtest/teamcity/src/teamcity_messages.h"
+
+namespace jetbrains {
+namespace teamcity {
+
+class TeamcityGoogleTestEventListener
+ : public ::testing::EmptyTestEventListener {
+ public:
+ TeamcityGoogleTestEventListener(const std::string& flowid);
+ TeamcityGoogleTestEventListener();
+
+ // Fired before the test case starts.
+ virtual void OnTestCaseStart(const ::testing::TestCase& test_case);
+ // Fired before the test starts.
+ virtual void OnTestStart(const ::testing::TestInfo& test_info);
+ // Fired after the test ends.
+ virtual void OnTestEnd(const ::testing::TestInfo& test_info);
+ // Fired after the test case ends.
+ virtual void OnTestCaseEnd(const ::testing::TestCase& test_case);
+
+ private:
+ TeamcityMessages messages;
+ std::string flowid;
+
+ // Prevent copying.
+ TeamcityGoogleTestEventListener(const TeamcityGoogleTestEventListener&);
+ void operator=(const TeamcityGoogleTestEventListener&);
+};
+
+} // namespace teamcity
+} // namespace jetbrains
+
+#endif /* H_TEAMCITY_GTEST */
diff --git a/tests/gtest/teamcity/src/teamcity_gtest.cpp b/tests/gtest/teamcity/src/teamcity_gtest.cpp
new file mode 100644
index 00000000..fb4dc676
--- /dev/null
+++ b/tests/gtest/teamcity/src/teamcity_gtest.cpp
@@ -0,0 +1,85 @@
+/* Copyright 2015 Paul Shmakov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "tests/gtest/teamcity/include/teamcity_gtest.h"
+
+namespace jetbrains {
+namespace teamcity {
+
+using namespace testing;
+
+TeamcityGoogleTestEventListener::TeamcityGoogleTestEventListener() {
+ flowid = getFlowIdFromEnvironment();
+}
+
+TeamcityGoogleTestEventListener::TeamcityGoogleTestEventListener(
+ const std::string& flowid_)
+ : flowid(flowid_) {}
+
+// Fired before the test case starts.
+void TeamcityGoogleTestEventListener::OnTestCaseStart(
+ const TestCase& test_case) {
+ messages.suiteStarted(test_case.name(), flowid);
+}
+
+// Fired before the test starts.
+void TeamcityGoogleTestEventListener::OnTestStart(const TestInfo& test_info) {
+ messages.testStarted(test_info.name(), flowid);
+}
+
+// Fired after the test ends.
+void TeamcityGoogleTestEventListener::OnTestEnd(const TestInfo& test_info) {
+ const TestResult* result = test_info.result();
+ if (result->Failed()) {
+ std::string message;
+ std::string details;
+ for (int i = 0; i < result->total_part_count(); ++i) {
+ const TestPartResult& partResult = result->GetTestPartResult(i);
+ if (partResult.passed()) {
+ continue;
+ }
+
+ if (message.empty()) {
+ message = partResult.summary();
+ }
+
+ if (!details.empty()) {
+ details.append("\n");
+ }
+ details.append(partResult.message());
+
+ if (partResult.file_name() && partResult.line_number() >= 0) {
+ std::stringstream ss;
+ ss << "\n at " << partResult.file_name() << ":"
+ << partResult.line_number();
+ details.append(ss.str());
+ }
+ }
+
+ messages.testFailed(test_info.name(), !message.empty() ? message : "failed",
+ details, flowid);
+ }
+ messages.testFinished(test_info.name(),
+ static_cast<int>(result->elapsed_time()), flowid);
+}
+
+// Fired after the test case ends.
+void TeamcityGoogleTestEventListener::OnTestCaseEnd(const TestCase& test_case) {
+ messages.suiteFinished(test_case.name(), flowid);
+}
+
+} // namespace teamcity
+} // namespace jetbrains
diff --git a/tests/gtest/teamcity/src/teamcity_messages.cpp b/tests/gtest/teamcity/src/teamcity_messages.cpp
new file mode 100644
index 00000000..284f8b4c
--- /dev/null
+++ b/tests/gtest/teamcity/src/teamcity_messages.cpp
@@ -0,0 +1,215 @@
+/* Copyright 2011 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * $Revision: 88625 $
+ */
+
+#include "tests/gtest/teamcity/src/teamcity_messages.h"
+
+#include <cstdlib>
+#include <sstream>
+
+namespace jetbrains {
+namespace teamcity {
+
+std::string getFlowIdFromEnvironment() {
+#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32)) && \
+ !defined(__CYGWIN__) && !defined(__MINGW32__)
+ char* flowId = NULL;
+ size_t sz = 0;
+ std::string result;
+ if (!_dupenv_s(&flowId, &sz, "TEAMCITY_PROCESS_FLOW_ID")) {
+ result = flowId != NULL ? flowId : "";
+ free(flowId);
+ }
+
+ return result;
+#else
+ const char* flowId = getenv("TEAMCITY_PROCESS_FLOW_ID");
+ return flowId == NULL ? "" : flowId;
+#endif
+}
+
+bool underTeamcity() {
+#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32)) && \
+ !defined(__CYGWIN__) && !defined(__MINGW32__)
+ char* teamCityProjectName = 0;
+ size_t sz = 0;
+ bool result = false;
+ if (!_dupenv_s(&teamCityProjectName, &sz, "TEAMCITY_PROJECT_NAME")) {
+ result = teamCityProjectName != NULL;
+ free(teamCityProjectName);
+ }
+
+ return result;
+#else
+ return getenv("TEAMCITY_PROJECT_NAME") != NULL;
+#endif
+}
+
+TeamcityMessages::TeamcityMessages() : m_out(&std::cout) {}
+
+void TeamcityMessages::setOutput(std::ostream& out) {
+ m_out = &out;
+}
+
+std::string TeamcityMessages::escape(const std::string& s) {
+ std::string result;
+ result.reserve(s.length());
+
+ for (size_t i = 0; i < s.length(); i++) {
+ char c = s[i];
+
+ switch (c) {
+ case '\n':
+ result.append("|n");
+ break;
+ case '\r':
+ result.append("|r");
+ break;
+ case '\'':
+ result.append("|'");
+ break;
+ case '|':
+ result.append("||");
+ break;
+ case ']':
+ result.append("|]");
+ break;
+ default:
+ result.append(&c, 1);
+ }
+ }
+
+ return result;
+}
+
+void TeamcityMessages::openMsg(const std::string& name) {
+ // endl for http://jetbrains.net/tracker/issue/TW-4412
+ *m_out << std::endl << "##teamcity[" << name;
+}
+
+void TeamcityMessages::closeMsg() {
+ *m_out << "]";
+ // endl for http://jetbrains.net/tracker/issue/TW-4412
+ *m_out << std::endl;
+}
+
+void TeamcityMessages::writeProperty(const std::string& name,
+ const std::string& value) {
+ *m_out << " " << name << "='" << escape(value) << "'";
+}
+
+void TeamcityMessages::suiteStarted(const std::string& name,
+ const std::string& flowid) {
+ openMsg("testSuiteStarted");
+ writeProperty("name", name);
+ if (flowid.length() > 0) {
+ writeProperty("flowId", flowid);
+ }
+
+ closeMsg();
+}
+
+void TeamcityMessages::suiteFinished(const std::string& name,
+ const std::string& flowid) {
+ openMsg("testSuiteFinished");
+ writeProperty("name", name);
+ if (flowid.length() > 0) {
+ writeProperty("flowId", flowid);
+ }
+
+ closeMsg();
+}
+
+void TeamcityMessages::testStarted(const std::string& name,
+ const std::string& flowid,
+ bool captureStandardOutput) {
+ openMsg("testStarted");
+ writeProperty("name", name);
+ if (flowid.length() > 0) {
+ writeProperty("flowId", flowid);
+ }
+
+ if (captureStandardOutput) {
+ writeProperty("captureStandardOutput", "true"); // false by default
+ }
+
+ closeMsg();
+}
+
+void TeamcityMessages::testFinished(const std::string& name,
+ int durationMs,
+ const std::string& flowid) {
+ openMsg("testFinished");
+
+ writeProperty("name", name);
+
+ if (flowid.length() > 0) {
+ writeProperty("flowId", flowid);
+ }
+
+ if (durationMs >= 0) {
+ std::stringstream out(std::ios_base::out);
+ out << durationMs;
+ writeProperty("duration", out.str());
+ }
+
+ closeMsg();
+}
+
+void TeamcityMessages::testFailed(const std::string& name,
+ const std::string& message,
+ const std::string& details,
+ const std::string& flowid) {
+ openMsg("testFailed");
+ writeProperty("name", name);
+ writeProperty("message", message);
+ writeProperty("details", details);
+ if (flowid.length() > 0) {
+ writeProperty("flowId", flowid);
+ }
+
+ closeMsg();
+}
+
+void TeamcityMessages::testIgnored(const std::string& name,
+ const std::string& message,
+ const std::string& flowid) {
+ openMsg("testIgnored");
+ writeProperty("name", name);
+ writeProperty("message", message);
+ if (flowid.length() > 0) {
+ writeProperty("flowId", flowid);
+ }
+
+ closeMsg();
+}
+
+void TeamcityMessages::testOutput(const std::string& name,
+ const std::string& output,
+ const std::string& flowid,
+ bool isStdError) {
+ openMsg(isStdError ? "testStdErr" : "testStdOut");
+ writeProperty("name", name);
+ writeProperty("out", output);
+ if (flowid.length() > 0) {
+ writeProperty("flowId", flowid);
+ }
+
+ closeMsg();
+}
+
+} // namespace teamcity
+} // namespace jetbrains
diff --git a/tests/gtest/teamcity/src/teamcity_messages.h b/tests/gtest/teamcity/src/teamcity_messages.h
new file mode 100644
index 00000000..409cb83c
--- /dev/null
+++ b/tests/gtest/teamcity/src/teamcity_messages.h
@@ -0,0 +1,75 @@
+/* Copyright 2011 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * $Revision: 88625 $
+ */
+
+#ifndef H_TEAMCITY_MESSAGES
+#define H_TEAMCITY_MESSAGES
+
+#include <iostream>
+#include <string>
+
+namespace jetbrains {
+namespace teamcity {
+
+std::string getFlowIdFromEnvironment();
+bool underTeamcity();
+
+class TeamcityMessages {
+ std::ostream* m_out;
+
+ protected:
+ std::string escape(const std::string& s);
+
+ void openMsg(const std::string& name);
+ void writeProperty(const std::string& name, const std::string& value);
+ void closeMsg();
+
+ public:
+ static const bool StdErr = true;
+ static const bool StdOut = false;
+
+ TeamcityMessages();
+
+ void setOutput(std::ostream&);
+
+ void suiteStarted(const std::string& name,
+ const std::string& flowid = std::string());
+ void suiteFinished(const std::string& name,
+ const std::string& flowid = std::string());
+
+ void testStarted(const std::string& name,
+ const std::string& flowid = std::string(),
+ bool captureStandardOutput = false);
+ void testFailed(const std::string& name,
+ const std::string& message,
+ const std::string& details,
+ const std::string& flowid = std::string());
+ void testIgnored(const std::string& name,
+ const std::string& message,
+ const std::string& flowid = std::string());
+ void testOutput(const std::string& name,
+ const std::string& output,
+ const std::string& flowid,
+ bool isStdErr = StdOut);
+ void testFinished(const std::string& name,
+ int durationMs = -1,
+ const std::string& flowid = std::string());
+};
+
+} // namespace teamcity
+} // namespace jetbrains
+
+#endif /* H_TEAMCITY_MESSAGES */
diff --git a/tests/shared/browser/client_app_browser.cc b/tests/shared/browser/client_app_browser.cc
new file mode 100644
index 00000000..a904a9ad
--- /dev/null
+++ b/tests/shared/browser/client_app_browser.cc
@@ -0,0 +1,131 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/shared/browser/client_app_browser.h"
+
+#include "include/base/cef_logging.h"
+#include "include/cef_cookie.h"
+#include "tests/shared/browser/main_message_loop_external_pump.h"
+#include "tests/shared/common/client_switches.h"
+
+namespace client {
+
+ClientAppBrowser::ClientAppBrowser() {
+ CreateDelegates(delegates_);
+}
+
+// static
+void ClientAppBrowser::PopulateSettings(CefRefPtr<CefCommandLine> command_line,
+ CefSettings& settings) {
+#if (defined(OS_WIN) || defined(OS_LINUX))
+ settings.multi_threaded_message_loop =
+ command_line->HasSwitch(client::switches::kMultiThreadedMessageLoop);
+#endif
+
+ if (!settings.multi_threaded_message_loop) {
+ settings.external_message_pump =
+ command_line->HasSwitch(client::switches::kExternalMessagePump);
+ }
+
+ std::vector<std::string> cookieable_schemes;
+ RegisterCookieableSchemes(cookieable_schemes);
+ if (!cookieable_schemes.empty()) {
+ std::string list_str;
+ for (const auto& scheme : cookieable_schemes) {
+ if (!list_str.empty()) {
+ list_str += ",";
+ }
+ list_str += scheme;
+ }
+ CefString(&settings.cookieable_schemes_list) = list_str;
+ }
+}
+
+void ClientAppBrowser::OnBeforeCommandLineProcessing(
+ const CefString& process_type,
+ CefRefPtr<CefCommandLine> command_line) {
+ // Pass additional command-line flags to the browser process.
+ if (process_type.empty()) {
+ // Pass additional command-line flags when off-screen rendering is enabled.
+ if (command_line->HasSwitch(switches::kOffScreenRenderingEnabled) &&
+ !command_line->HasSwitch(switches::kSharedTextureEnabled)) {
+ // Use software rendering and compositing (disable GPU) for increased FPS
+ // and decreased CPU usage. This will also disable WebGL so remove these
+ // switches if you need that capability.
+ // See https://github.com/chromiumembedded/cef/issues/1257 for details.
+ if (!command_line->HasSwitch(switches::kEnableGPU)) {
+ command_line->AppendSwitch("disable-gpu");
+ command_line->AppendSwitch("disable-gpu-compositing");
+ }
+ }
+
+ if (command_line->HasSwitch(switches::kUseViews) &&
+ !command_line->HasSwitch("top-chrome-md")) {
+ // Use non-material mode on all platforms by default. Among other things
+ // this causes menu buttons to show hover state. See usage of
+ // MaterialDesignController::IsModeMaterial() in Chromium code.
+ command_line->AppendSwitchWithValue("top-chrome-md", "non-material");
+ }
+
+ if (!command_line->HasSwitch(switches::kCachePath) &&
+ !command_line->HasSwitch("disable-gpu-shader-disk-cache")) {
+ // Don't create a "GPUCache" directory when cache-path is unspecified.
+ command_line->AppendSwitch("disable-gpu-shader-disk-cache");
+ }
+
+ // Disable popup blocking for the chrome runtime.
+ command_line->AppendSwitch("disable-popup-blocking");
+
+#if defined(OS_MAC)
+ // Disable the toolchain prompt on macOS.
+ command_line->AppendSwitch("use-mock-keychain");
+#endif
+
+ DelegateSet::iterator it = delegates_.begin();
+ for (; it != delegates_.end(); ++it) {
+ (*it)->OnBeforeCommandLineProcessing(this, command_line);
+ }
+ }
+}
+
+void ClientAppBrowser::OnRegisterCustomPreferences(
+ cef_preferences_type_t type,
+ CefRawPtr<CefPreferenceRegistrar> registrar) {
+ for (auto& delegate : delegates_) {
+ delegate->OnRegisterCustomPreferences(this, type, registrar);
+ }
+}
+
+void ClientAppBrowser::OnContextInitialized() {
+ for (auto& delegate : delegates_) {
+ delegate->OnContextInitialized(this);
+ }
+}
+
+void ClientAppBrowser::OnBeforeChildProcessLaunch(
+ CefRefPtr<CefCommandLine> command_line) {
+ for (auto& delegate : delegates_) {
+ delegate->OnBeforeChildProcessLaunch(this, command_line);
+ }
+}
+
+void ClientAppBrowser::OnScheduleMessagePumpWork(int64 delay) {
+ // Only used when `--external-message-pump` is passed via the command-line.
+ MainMessageLoopExternalPump* message_pump =
+ MainMessageLoopExternalPump::Get();
+ if (message_pump) {
+ message_pump->OnScheduleMessagePumpWork(delay);
+ }
+}
+
+CefRefPtr<CefClient> ClientAppBrowser::GetDefaultClient() {
+ for (auto& delegate : delegates_) {
+ if (auto client = delegate->GetDefaultClient(this)) {
+ return client;
+ }
+ }
+ return nullptr;
+}
+
+} // namespace client
diff --git a/tests/shared/browser/client_app_browser.h b/tests/shared/browser/client_app_browser.h
new file mode 100644
index 00000000..fc743096
--- /dev/null
+++ b/tests/shared/browser/client_app_browser.h
@@ -0,0 +1,90 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_SHARED_BROWSER_CLIENT_APP_BROWSER_H_
+#define CEF_TESTS_SHARED_BROWSER_CLIENT_APP_BROWSER_H_
+#pragma once
+
+#include <set>
+
+#include "tests/shared/common/client_app.h"
+
+namespace client {
+
+// Client app implementation for the browser process.
+class ClientAppBrowser : public ClientApp, public CefBrowserProcessHandler {
+ public:
+ // Interface for browser delegates. All Delegates must be returned via
+ // CreateDelegates. Do not perform work in the Delegate
+ // constructor. See CefBrowserProcessHandler for documentation.
+ class Delegate : public virtual CefBaseRefCounted {
+ public:
+ virtual void OnBeforeCommandLineProcessing(
+ CefRefPtr<ClientAppBrowser> app,
+ CefRefPtr<CefCommandLine> command_line) {}
+
+ virtual void OnRegisterCustomPreferences(
+ CefRefPtr<ClientAppBrowser> app,
+ cef_preferences_type_t type,
+ CefRawPtr<CefPreferenceRegistrar> registrar) {}
+
+ virtual void OnContextInitialized(CefRefPtr<ClientAppBrowser> app) {}
+
+ virtual void OnBeforeChildProcessLaunch(
+ CefRefPtr<ClientAppBrowser> app,
+ CefRefPtr<CefCommandLine> command_line) {}
+
+ virtual CefRefPtr<CefClient> GetDefaultClient(
+ CefRefPtr<ClientAppBrowser> app) {
+ return nullptr;
+ }
+ };
+
+ typedef std::set<CefRefPtr<Delegate>> DelegateSet;
+
+ ClientAppBrowser();
+
+ // Called to populate |settings| based on |command_line| and other global
+ // state.
+ static void PopulateSettings(CefRefPtr<CefCommandLine> command_line,
+ CefSettings& settings);
+
+ private:
+ // Registers cookieable schemes. Implemented by cefclient in
+ // client_app_delegates_browser.cc
+ static void RegisterCookieableSchemes(
+ std::vector<std::string>& cookieable_schemes);
+
+ // Creates all of the Delegate objects. Implemented by cefclient in
+ // client_app_delegates_browser.cc
+ static void CreateDelegates(DelegateSet& delegates);
+
+ // CefApp methods.
+ void OnBeforeCommandLineProcessing(
+ const CefString& process_type,
+ CefRefPtr<CefCommandLine> command_line) override;
+ CefRefPtr<CefBrowserProcessHandler> GetBrowserProcessHandler() override {
+ return this;
+ }
+
+ // CefBrowserProcessHandler methods.
+ void OnRegisterCustomPreferences(
+ cef_preferences_type_t type,
+ CefRawPtr<CefPreferenceRegistrar> registrar) override;
+ void OnContextInitialized() override;
+ void OnBeforeChildProcessLaunch(
+ CefRefPtr<CefCommandLine> command_line) override;
+ void OnScheduleMessagePumpWork(int64 delay) override;
+ CefRefPtr<CefClient> GetDefaultClient() override;
+
+ // Set of supported Delegates.
+ DelegateSet delegates_;
+
+ IMPLEMENT_REFCOUNTING(ClientAppBrowser);
+ DISALLOW_COPY_AND_ASSIGN(ClientAppBrowser);
+};
+
+} // namespace client
+
+#endif // CEF_TESTS_SHARED_BROWSER_CLIENT_APP_BROWSER_H_
diff --git a/tests/shared/browser/extension_util.cc b/tests/shared/browser/extension_util.cc
new file mode 100644
index 00000000..088316e4
--- /dev/null
+++ b/tests/shared/browser/extension_util.cc
@@ -0,0 +1,257 @@
+// Copyright (c) 2017 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/shared/browser/extension_util.h"
+
+#include <algorithm>
+#include <memory>
+
+#include "include/base/cef_callback.h"
+#include "include/cef_parser.h"
+#include "include/cef_path_util.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "tests/shared/browser/file_util.h"
+#include "tests/shared/browser/resource_util.h"
+#include "tests/shared/common/string_util.h"
+
+namespace client {
+namespace extension_util {
+
+namespace {
+
+std::string GetResourcesPath() {
+ CefString resources_dir;
+ if (CefGetPath(PK_DIR_RESOURCES, resources_dir) && !resources_dir.empty()) {
+ return resources_dir.ToString() + file_util::kPathSep;
+ }
+ return std::string();
+}
+
+// Internal extension paths may be prefixed with PK_DIR_RESOURCES and always
+// use forward slash as path separator.
+std::string GetInternalPath(const std::string& extension_path) {
+ std::string resources_path_lower = GetResourcesPath();
+ std::string extension_path_lower = extension_path;
+
+#if defined(OS_WIN)
+ // Convert to lower-case, since Windows paths are case-insensitive.
+ resources_path_lower = AsciiStrToLower(resources_path_lower);
+ extension_path_lower = AsciiStrToLower(extension_path_lower);
+#endif
+
+ std::string internal_path;
+ if (!resources_path_lower.empty() &&
+ extension_path_lower.find(resources_path_lower) == 0U) {
+ internal_path = extension_path.substr(resources_path_lower.size());
+ } else {
+ internal_path = extension_path;
+ }
+
+#if defined(OS_WIN)
+ // Normalize path separators.
+ std::replace(internal_path.begin(), internal_path.end(), '\\', '/');
+#endif
+
+ return internal_path;
+}
+
+using ManifestCallback =
+ base::OnceCallback<void(CefRefPtr<CefDictionaryValue> /*manifest*/)>;
+
+void RunManifestCallback(ManifestCallback callback,
+ CefRefPtr<CefDictionaryValue> manifest) {
+ if (!CefCurrentlyOn(TID_UI)) {
+ // Execute on the browser UI thread.
+ CefPostTask(TID_UI, base::BindOnce(std::move(callback), manifest));
+ return;
+ }
+ std::move(callback).Run(manifest);
+}
+
+// Asynchronously reads the manifest and executes |callback| on the UI thread.
+void GetInternalManifest(const std::string& extension_path,
+ ManifestCallback callback) {
+ if (!CefCurrentlyOn(TID_FILE_USER_BLOCKING)) {
+ // Execute on the browser FILE thread.
+ CefPostTask(TID_FILE_USER_BLOCKING,
+ base::BindOnce(GetInternalManifest, extension_path,
+ std::move(callback)));
+ return;
+ }
+
+ const std::string& manifest_path = GetInternalExtensionResourcePath(
+ file_util::JoinPath(extension_path, "manifest.json"));
+ std::string manifest_contents;
+ if (!LoadBinaryResource(manifest_path.c_str(), manifest_contents) ||
+ manifest_contents.empty()) {
+ LOG(ERROR) << "Failed to load manifest from " << manifest_path;
+ RunManifestCallback(std::move(callback), nullptr);
+ return;
+ }
+
+ CefString error_msg;
+ CefRefPtr<CefValue> value =
+ CefParseJSONAndReturnError(manifest_contents, JSON_PARSER_RFC, error_msg);
+ if (!value || value->GetType() != VTYPE_DICTIONARY) {
+ if (error_msg.empty()) {
+ error_msg = "Incorrectly formatted dictionary contents.";
+ }
+ LOG(ERROR) << "Failed to parse manifest from " << manifest_path << "; "
+ << error_msg.ToString();
+ RunManifestCallback(std::move(callback), nullptr);
+ return;
+ }
+
+ RunManifestCallback(std::move(callback), value->GetDictionary());
+}
+
+void LoadExtensionWithManifest(CefRefPtr<CefRequestContext> request_context,
+ const std::string& extension_path,
+ CefRefPtr<CefExtensionHandler> handler,
+ CefRefPtr<CefDictionaryValue> manifest) {
+ CEF_REQUIRE_UI_THREAD();
+
+ // Load the extension internally. Resource requests will be handled via
+ // AddInternalExtensionToResourceManager.
+ request_context->LoadExtension(extension_path, manifest, handler);
+}
+
+} // namespace
+
+bool IsInternalExtension(const std::string& extension_path) {
+ // List of internally handled extensions.
+ static const char* extensions[] = {"set_page_color"};
+
+ const std::string& internal_path = GetInternalPath(extension_path);
+ for (size_t i = 0; i < std::size(extensions); ++i) {
+ // Exact match or first directory component.
+ const std::string& extension = extensions[i];
+ if (internal_path == extension ||
+ internal_path.find(extension + '/') == 0) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+std::string GetInternalExtensionResourcePath(
+ const std::string& extension_path) {
+ return "extensions/" + GetInternalPath(extension_path);
+}
+
+std::string GetExtensionResourcePath(const std::string& extension_path,
+ bool* internal) {
+ const bool is_internal = IsInternalExtension(extension_path);
+ if (internal) {
+ *internal = is_internal;
+ }
+ if (is_internal) {
+ return GetInternalExtensionResourcePath(extension_path);
+ }
+ return extension_path;
+}
+
+bool GetExtensionResourceContents(const std::string& extension_path,
+ std::string& contents) {
+ CEF_REQUIRE_FILE_USER_BLOCKING_THREAD();
+
+ if (IsInternalExtension(extension_path)) {
+ const std::string& contents_path =
+ GetInternalExtensionResourcePath(extension_path);
+ return LoadBinaryResource(contents_path.c_str(), contents);
+ }
+
+ return file_util::ReadFileToString(extension_path, &contents);
+}
+
+void LoadExtension(CefRefPtr<CefRequestContext> request_context,
+ const std::string& extension_path,
+ CefRefPtr<CefExtensionHandler> handler) {
+ if (!CefCurrentlyOn(TID_UI)) {
+ // Execute on the browser UI thread.
+ CefPostTask(TID_UI, base::BindOnce(LoadExtension, request_context,
+ extension_path, handler));
+ return;
+ }
+
+ if (IsInternalExtension(extension_path)) {
+ // Read the extension manifest and load asynchronously.
+ GetInternalManifest(
+ extension_path,
+ base::BindOnce(LoadExtensionWithManifest, request_context,
+ extension_path, handler));
+ } else {
+ // Load the extension from disk.
+ request_context->LoadExtension(extension_path, nullptr, handler);
+ }
+}
+
+void AddInternalExtensionToResourceManager(
+ CefRefPtr<CefExtension> extension,
+ CefRefPtr<CefResourceManager> resource_manager) {
+ DCHECK(IsInternalExtension(extension->GetPath()));
+
+ if (!CefCurrentlyOn(TID_IO)) {
+ // Execute on the browser IO thread.
+ CefPostTask(TID_IO, base::BindOnce(AddInternalExtensionToResourceManager,
+ extension, resource_manager));
+ return;
+ }
+
+ const std::string& origin = GetExtensionOrigin(extension->GetIdentifier());
+ const std::string& resource_path =
+ GetInternalExtensionResourcePath(extension->GetPath());
+
+// Add provider for bundled resource files.
+#if defined(OS_WIN)
+ // Read resources from the binary.
+ resource_manager->AddProvider(
+ CreateBinaryResourceProvider(origin, resource_path), 50, std::string());
+#elif defined(OS_POSIX)
+ // Read resources from a directory on disk.
+ std::string resource_dir;
+ if (GetResourceDir(resource_dir)) {
+ resource_dir += "/" + resource_path;
+ resource_manager->AddDirectoryProvider(origin, resource_dir, 50,
+ std::string());
+ }
+#endif
+}
+
+std::string GetExtensionOrigin(const std::string& extension_id) {
+ return "chrome-extension://" + extension_id + "/";
+}
+
+std::string GetExtensionURL(CefRefPtr<CefExtension> extension) {
+ CefRefPtr<CefDictionaryValue> browser_action =
+ extension->GetManifest()->GetDictionary("browser_action");
+ if (browser_action) {
+ const std::string& default_popup =
+ browser_action->GetString("default_popup");
+ if (!default_popup.empty()) {
+ return GetExtensionOrigin(extension->GetIdentifier()) + default_popup;
+ }
+ }
+
+ return std::string();
+}
+
+std::string GetExtensionIconPath(CefRefPtr<CefExtension> extension,
+ bool* internal) {
+ CefRefPtr<CefDictionaryValue> browser_action =
+ extension->GetManifest()->GetDictionary("browser_action");
+ if (browser_action) {
+ const std::string& default_icon = browser_action->GetString("default_icon");
+ if (!default_icon.empty()) {
+ return GetExtensionResourcePath(
+ file_util::JoinPath(extension->GetPath(), default_icon), internal);
+ }
+ }
+
+ return std::string();
+}
+
+} // namespace extension_util
+} // namespace client
diff --git a/tests/shared/browser/extension_util.h b/tests/shared/browser/extension_util.h
new file mode 100644
index 00000000..10b3511b
--- /dev/null
+++ b/tests/shared/browser/extension_util.h
@@ -0,0 +1,80 @@
+// Copyright (c) 2017 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_CEFCLIENT_BROWSER_EXTENSION_UTIL_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_EXTENSION_UTIL_H_
+#pragma once
+
+#include <string>
+
+#include "include/cef_extension.h"
+#include "include/cef_extension_handler.h"
+#include "include/wrapper/cef_resource_manager.h"
+
+namespace client {
+namespace extension_util {
+
+// Returns true if |extension_path| can be handled internally via
+// LoadBinaryResource. This checks a hard-coded list of allowed extension path
+// components.
+bool IsInternalExtension(const std::string& extension_path);
+
+// Returns the path relative to the resource directory after removing the
+// PK_DIR_RESOURCES prefix. This will be the relative path expected by
+// LoadBinaryResource (uses '/' as path separator on all platforms). Only call
+// this method for internal extensions, either when IsInternalExtension returns
+// true or when the extension is handled internally through some means other
+// than LoadBinaryResource. Use GetExtensionResourcePath instead if you are
+// unsure whether the extension is internal or external.
+std::string GetInternalExtensionResourcePath(const std::string& extension_path);
+
+// Returns the resource path for |extension_path|. For external extensions this
+// will be the full file path on disk. For internal extensions this will be the
+// relative path expected by LoadBinaryResource (uses '/' as path separator on
+// all platforms). Internal extensions must be on the hard-coded list enforced
+// by IsInternalExtension. If |internal| is non-nullptr it will be set to true
+// if the extension is handled internally.
+std::string GetExtensionResourcePath(const std::string& extension_path,
+ bool* internal);
+
+// Read the contents of |extension_path| into |contents|. For external
+// extensions this will read the file from disk. For internal extensions this
+// will call LoadBinaryResource. Internal extensions must be on the hard-coded
+// list enforced by IsInternalExtension. Returns true on success. Must be
+// called on the FILE thread.
+bool GetExtensionResourceContents(const std::string& extension_path,
+ std::string& contents);
+
+// Load |extension_path| in |request_context|. May be an internal or external
+// extension. Internal extensions must be on the hard-coded list enforced by
+// IsInternalExtension.
+void LoadExtension(CefRefPtr<CefRequestContext> request_context,
+ const std::string& extension_path,
+ CefRefPtr<CefExtensionHandler> handler);
+
+// Register an internal handler for extension resources. Internal extensions
+// must be on the hard-coded list enforced by IsInternalExtension.
+void AddInternalExtensionToResourceManager(
+ CefRefPtr<CefExtension> extension,
+ CefRefPtr<CefResourceManager> resource_manager);
+
+// Returns the URL origin for |extension_id|.
+std::string GetExtensionOrigin(const std::string& extension_id);
+
+// Parse browser_action manifest values as defined at
+// https://developer.chrome.com/extensions/browserAction
+
+// Look for a browser_action.default_popup manifest value.
+std::string GetExtensionURL(CefRefPtr<CefExtension> extension);
+
+// Look for a browser_action.default_icon manifest value and return the resource
+// path. If |internal| is non-nullptr it will be set to true if the extension is
+// handled internally.
+std::string GetExtensionIconPath(CefRefPtr<CefExtension> extension,
+ bool* internal);
+
+} // namespace extension_util
+} // namespace client
+
+#endif // CEF_TESTS_CEFCLIENT_BROWSER_EXTENSION_UTIL_H_
diff --git a/tests/shared/browser/file_util.cc b/tests/shared/browser/file_util.cc
new file mode 100644
index 00000000..d1ccaac6
--- /dev/null
+++ b/tests/shared/browser/file_util.cc
@@ -0,0 +1,133 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. Portions copyright
+// 2012 The Chromium Authors. All rights reserved. Use of this source code is
+// governed by a BSD-style license that can be found in the LICENSE file.
+
+#include "tests/shared/browser/file_util.h"
+
+#include <algorithm>
+#include <cstdio>
+#include <memory>
+
+#include "include/base/cef_build.h"
+#include "include/cef_task.h"
+
+namespace client {
+namespace file_util {
+
+namespace {
+
+bool AllowFileIO() {
+ if (CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO)) {
+ NOTREACHED() << "file IO is not allowed on the current thread";
+ return false;
+ }
+ return true;
+}
+
+} // namespace
+
+#if defined(OS_WIN)
+const char kPathSep = '\\';
+#else
+const char kPathSep = '/';
+#endif
+
+bool ReadFileToString(const std::string& path,
+ std::string* contents,
+ size_t max_size) {
+ if (!AllowFileIO()) {
+ return false;
+ }
+
+ if (contents) {
+ contents->clear();
+ }
+ FILE* file = fopen(path.c_str(), "rb");
+ if (!file) {
+ return false;
+ }
+
+ const size_t kBufferSize = 1 << 16;
+ std::unique_ptr<char[]> buf(new char[kBufferSize]);
+ size_t len;
+ size_t size = 0;
+ bool read_status = true;
+
+ // Many files supplied in |path| have incorrect size (proc files etc).
+ // Hence, the file is read sequentially as opposed to a one-shot read.
+ while ((len = fread(buf.get(), 1, kBufferSize, file)) > 0) {
+ if (contents) {
+ contents->append(buf.get(), std::min(len, max_size - size));
+ }
+
+ if ((max_size - size) < len) {
+ read_status = false;
+ break;
+ }
+
+ size += len;
+ }
+ read_status = read_status && !ferror(file);
+ fclose(file);
+
+ return read_status;
+}
+
+int WriteFile(const std::string& path, const char* data, int size) {
+ if (!AllowFileIO()) {
+ return -1;
+ }
+
+ FILE* file = fopen(path.c_str(), "wb");
+ if (!file) {
+ return -1;
+ }
+
+ int written = 0;
+
+ do {
+ size_t write = fwrite(data + written, 1, size - written, file);
+ if (write == 0) {
+ break;
+ }
+ written += static_cast<int>(write);
+ } while (written < size);
+
+ fclose(file);
+
+ return written;
+}
+
+std::string JoinPath(const std::string& path1, const std::string& path2) {
+ if (path1.empty() && path2.empty()) {
+ return std::string();
+ }
+ if (path1.empty()) {
+ return path2;
+ }
+ if (path2.empty()) {
+ return path1;
+ }
+
+ std::string result = path1;
+ if (result[result.size() - 1] != kPathSep) {
+ result += kPathSep;
+ }
+ if (path2[0] == kPathSep) {
+ result += path2.substr(1);
+ } else {
+ result += path2;
+ }
+ return result;
+}
+
+std::string GetFileExtension(const std::string& path) {
+ size_t sep = path.find_last_of(".");
+ if (sep != std::string::npos) {
+ return path.substr(sep + 1);
+ }
+ return std::string();
+}
+
+} // namespace file_util
+} // namespace client
diff --git a/tests/shared/browser/file_util.h b/tests/shared/browser/file_util.h
new file mode 100644
index 00000000..b08d7dc0
--- /dev/null
+++ b/tests/shared/browser/file_util.h
@@ -0,0 +1,45 @@
+// Copyright 2016 The Chromium Embedded Framework Authors. Portions copyright
+// 2012 The Chromium Authors. All rights reserved. Use of this source code is
+// governed by a BSD-style license that can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_SHARED_BROWSER_FILE_UTIL_H_
+#define CEF_TESTS_SHARED_BROWSER_FILE_UTIL_H_
+#pragma once
+
+#include <limits>
+#include <string>
+
+namespace client {
+namespace file_util {
+
+// Platform-specific path separator.
+extern const char kPathSep;
+
+// Reads the file at |path| into |contents| and returns true on success and
+// false on error. In case of I/O error, |contents| holds the data that could
+// be read from the file before the error occurred. When the file size exceeds
+// max_size|, the function returns false with |contents| holding the file
+// truncated to |max_size|. |contents| may be nullptr, in which case this
+// function is useful for its side effect of priming the disk cache (could be
+// used for unit tests). Calling this function on the browser process UI or IO
+// threads is not allowed.
+bool ReadFileToString(const std::string& path,
+ std::string* contents,
+ size_t max_size = std::numeric_limits<size_t>::max());
+
+// Writes the given buffer into the file, overwriting any data that was
+// previously there. Returns the number of bytes written, or -1 on error.
+// Calling this function on the browser process UI or IO threads is not allowed.
+int WriteFile(const std::string& path, const char* data, int size);
+
+// Combines |path1| and |path2| with the correct platform-specific path
+// separator.
+std::string JoinPath(const std::string& path1, const std::string& path2);
+
+// Extracts the file extension from |path|.
+std::string GetFileExtension(const std::string& path);
+
+} // namespace file_util
+} // namespace client
+
+#endif // CEF_TESTS_SHARED_BROWSER_FILE_UTIL_H_
diff --git a/tests/shared/browser/geometry_util.cc b/tests/shared/browser/geometry_util.cc
new file mode 100644
index 00000000..60962b2b
--- /dev/null
+++ b/tests/shared/browser/geometry_util.cc
@@ -0,0 +1,45 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/shared/browser/geometry_util.h"
+
+#include <cmath>
+
+namespace client {
+
+int LogicalToDevice(int value, float device_scale_factor) {
+ float scaled_val = static_cast<float>(value) * device_scale_factor;
+ return static_cast<int>(std::floor(scaled_val));
+}
+
+CefRect LogicalToDevice(const CefRect& value, float device_scale_factor) {
+ return CefRect(LogicalToDevice(value.x, device_scale_factor),
+ LogicalToDevice(value.y, device_scale_factor),
+ LogicalToDevice(value.width, device_scale_factor),
+ LogicalToDevice(value.height, device_scale_factor));
+}
+
+int DeviceToLogical(int value, float device_scale_factor) {
+ float scaled_val = static_cast<float>(value) / device_scale_factor;
+ return static_cast<int>(std::floor(scaled_val));
+}
+
+CefRect DeviceToLogical(const CefRect& value, float device_scale_factor) {
+ return CefRect(DeviceToLogical(value.x, device_scale_factor),
+ DeviceToLogical(value.y, device_scale_factor),
+ DeviceToLogical(value.width, device_scale_factor),
+ DeviceToLogical(value.height, device_scale_factor));
+}
+
+void DeviceToLogical(CefMouseEvent& value, float device_scale_factor) {
+ value.x = DeviceToLogical(value.x, device_scale_factor);
+ value.y = DeviceToLogical(value.y, device_scale_factor);
+}
+
+void DeviceToLogical(CefTouchEvent& value, float device_scale_factor) {
+ value.x = DeviceToLogical(value.x, device_scale_factor);
+ value.y = DeviceToLogical(value.y, device_scale_factor);
+}
+
+} // namespace client
diff --git a/tests/shared/browser/geometry_util.h b/tests/shared/browser/geometry_util.h
new file mode 100644
index 00000000..1853aa04
--- /dev/null
+++ b/tests/shared/browser/geometry_util.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_SHARED_BROWSER_GEOMETRY_UTIL_H_
+#define CEF_TESTS_SHARED_BROWSER_GEOMETRY_UTIL_H_
+#pragma once
+
+#include "include/internal/cef_types_wrappers.h"
+
+namespace client {
+
+// Convert |value| from logical coordinates to device coordinates.
+int LogicalToDevice(int value, float device_scale_factor);
+CefRect LogicalToDevice(const CefRect& value, float device_scale_factor);
+
+// Convert |value| from device coordinates to logical coordinates.
+int DeviceToLogical(int value, float device_scale_factor);
+CefRect DeviceToLogical(const CefRect& value, float device_scale_factor);
+void DeviceToLogical(CefMouseEvent& value, float device_scale_factor);
+void DeviceToLogical(CefTouchEvent& value, float device_scale_factor);
+
+} // namespace client
+
+#endif // CEF_TESTS_SHARED_BROWSER_GEOMETRY_UTIL_H_
diff --git a/tests/shared/browser/main_message_loop.cc b/tests/shared/browser/main_message_loop.cc
new file mode 100644
index 00000000..23446e06
--- /dev/null
+++ b/tests/shared/browser/main_message_loop.cc
@@ -0,0 +1,41 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/shared/browser/main_message_loop.h"
+
+#include "include/cef_task.h"
+#include "include/wrapper/cef_closure_task.h"
+
+namespace client {
+
+namespace {
+
+MainMessageLoop* g_main_message_loop = nullptr;
+
+} // namespace
+
+MainMessageLoop::MainMessageLoop() {
+ DCHECK(!g_main_message_loop);
+ g_main_message_loop = this;
+}
+
+MainMessageLoop::~MainMessageLoop() {
+ g_main_message_loop = nullptr;
+}
+
+// static
+MainMessageLoop* MainMessageLoop::Get() {
+ DCHECK(g_main_message_loop);
+ return g_main_message_loop;
+}
+
+void MainMessageLoop::PostClosure(base::OnceClosure closure) {
+ PostTask(CefCreateClosureTask(std::move(closure)));
+}
+
+void MainMessageLoop::PostClosure(const base::RepeatingClosure& closure) {
+ PostTask(CefCreateClosureTask(closure));
+}
+
+} // namespace client
diff --git a/tests/shared/browser/main_message_loop.h b/tests/shared/browser/main_message_loop.h
new file mode 100644
index 00000000..8d8903fd
--- /dev/null
+++ b/tests/shared/browser/main_message_loop.h
@@ -0,0 +1,109 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_SHARED_BROWSER_MAIN_MESSAGE_LOOP_H_
+#define CEF_TESTS_SHARED_BROWSER_MAIN_MESSAGE_LOOP_H_
+#pragma once
+
+#include <memory>
+
+#include "include/base/cef_callback.h"
+#include "include/cef_task.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+
+namespace client {
+
+// Represents the message loop running on the main application thread in the
+// browser process. This will be the same as the CEF UI thread on Linux, OS X
+// and Windows when not using multi-threaded message loop mode. The methods of
+// this class are thread-safe unless otherwise indicated.
+class MainMessageLoop {
+ public:
+ // Returns the singleton instance of this object.
+ static MainMessageLoop* Get();
+
+ // Run the message loop. The thread that this method is called on will be
+ // considered the main thread. This blocks until Quit() is called.
+ virtual int Run() = 0;
+
+ // Quit the message loop.
+ virtual void Quit() = 0;
+
+ // Post a task for execution on the main message loop.
+ virtual void PostTask(CefRefPtr<CefTask> task) = 0;
+
+ // Returns true if this message loop runs tasks on the current thread.
+ virtual bool RunsTasksOnCurrentThread() const = 0;
+
+#if defined(OS_WIN)
+ // Set the current modeless dialog on Windows for proper delivery of dialog
+ // messages when using multi-threaded message loop mode. This method must be
+ // called from the main thread. See http://support.microsoft.com/kb/71450 for
+ // background.
+ virtual void SetCurrentModelessDialog(HWND hWndDialog) = 0;
+#endif
+
+ // Post a closure for execution on the main message loop.
+ void PostClosure(base::OnceClosure closure);
+ void PostClosure(const base::RepeatingClosure& closure);
+
+ protected:
+ // Only allow deletion via std::unique_ptr.
+ friend std::default_delete<MainMessageLoop>;
+
+ MainMessageLoop();
+ virtual ~MainMessageLoop();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MainMessageLoop);
+};
+
+#define CURRENTLY_ON_MAIN_THREAD() \
+ client::MainMessageLoop::Get()->RunsTasksOnCurrentThread()
+
+#define REQUIRE_MAIN_THREAD() DCHECK(CURRENTLY_ON_MAIN_THREAD())
+
+#define MAIN_POST_TASK(task) client::MainMessageLoop::Get()->PostTask(task)
+
+#define MAIN_POST_CLOSURE(closure) \
+ client::MainMessageLoop::Get()->PostClosure(closure)
+
+// Use this struct in conjuction with RefCountedThreadSafe to ensure that an
+// object is deleted on the main thread. For example:
+//
+// class Foo : public base::RefCountedThreadSafe<Foo, DeleteOnMainThread> {
+// public:
+// Foo();
+// void DoSomething();
+//
+// private:
+// // Allow deletion via scoped_refptr only.
+// friend struct DeleteOnMainThread;
+// friend class base::RefCountedThreadSafe<Foo, DeleteOnMainThread>;
+//
+// virtual ~Foo() {}
+// };
+//
+// base::scoped_refptr<Foo> foo = new Foo();
+// foo->DoSomething();
+// foo = nullptr; // Deletion of |foo| will occur on the main thread.
+//
+struct DeleteOnMainThread {
+ template <typename T>
+ static void Destruct(const T* x) {
+ if (CURRENTLY_ON_MAIN_THREAD()) {
+ delete x;
+ } else {
+ client::MainMessageLoop::Get()->PostClosure(base::BindOnce(
+ &DeleteOnMainThread::Destruct<T>, base::Unretained(x)));
+ }
+ }
+};
+
+} // namespace client
+
+#endif // CEF_TESTS_SHARED_BROWSER_MAIN_MESSAGE_LOOP_H_
diff --git a/tests/shared/browser/main_message_loop_external_pump.cc b/tests/shared/browser/main_message_loop_external_pump.cc
new file mode 100644
index 00000000..6579e87b
--- /dev/null
+++ b/tests/shared/browser/main_message_loop_external_pump.cc
@@ -0,0 +1,108 @@
+// Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/shared/browser/main_message_loop_external_pump.h"
+
+#include <climits>
+
+#include "include/cef_app.h"
+#include "include/wrapper/cef_helpers.h"
+#include "tests/shared/browser/main_message_loop.h"
+
+namespace client {
+
+namespace {
+
+// Special timer delay placeholder value. Intentionally 32-bit for Windows and
+// OS X platform API compatibility.
+const int32 kTimerDelayPlaceholder = INT_MAX;
+
+// The maximum number of milliseconds we're willing to wait between calls to
+// DoWork().
+const int64 kMaxTimerDelay = 1000 / 30; // 30fps
+
+client::MainMessageLoopExternalPump* g_external_message_pump = nullptr;
+
+} // namespace
+
+MainMessageLoopExternalPump::MainMessageLoopExternalPump()
+ : is_active_(false), reentrancy_detected_(false) {
+ DCHECK(!g_external_message_pump);
+ g_external_message_pump = this;
+}
+
+MainMessageLoopExternalPump::~MainMessageLoopExternalPump() {
+ g_external_message_pump = nullptr;
+}
+
+MainMessageLoopExternalPump* MainMessageLoopExternalPump::Get() {
+ return g_external_message_pump;
+}
+
+void MainMessageLoopExternalPump::OnScheduleWork(int64 delay_ms) {
+ REQUIRE_MAIN_THREAD();
+
+ if (delay_ms == kTimerDelayPlaceholder && IsTimerPending()) {
+ // Don't set the maximum timer requested from DoWork() if a timer event is
+ // currently pending.
+ return;
+ }
+
+ KillTimer();
+
+ if (delay_ms <= 0) {
+ // Execute the work immediately.
+ DoWork();
+ } else {
+ // Never wait longer than the maximum allowed time.
+ if (delay_ms > kMaxTimerDelay) {
+ delay_ms = kMaxTimerDelay;
+ }
+
+ // Results in call to OnTimerTimeout() after the specified delay.
+ SetTimer(delay_ms);
+ }
+}
+
+void MainMessageLoopExternalPump::OnTimerTimeout() {
+ REQUIRE_MAIN_THREAD();
+
+ KillTimer();
+ DoWork();
+}
+
+void MainMessageLoopExternalPump::DoWork() {
+ const bool was_reentrant = PerformMessageLoopWork();
+ if (was_reentrant) {
+ // Execute the remaining work as soon as possible.
+ OnScheduleMessagePumpWork(0);
+ } else if (!IsTimerPending()) {
+ // Schedule a timer event at the maximum allowed time. This may be dropped
+ // in OnScheduleWork() if another timer event is already in-flight.
+ OnScheduleMessagePumpWork(kTimerDelayPlaceholder);
+ }
+}
+
+bool MainMessageLoopExternalPump::PerformMessageLoopWork() {
+ if (is_active_) {
+ // When CefDoMessageLoopWork() is called there may be various callbacks
+ // (such as paint and IPC messages) that result in additional calls to this
+ // method. If re-entrancy is detected we must repost a request again to the
+ // owner thread to ensure that the discarded call is executed in the future.
+ reentrancy_detected_ = true;
+ return false;
+ }
+
+ reentrancy_detected_ = false;
+
+ is_active_ = true;
+ CefDoMessageLoopWork();
+ is_active_ = false;
+
+ // |reentrancy_detected_| may have changed due to re-entrant calls to this
+ // method.
+ return reentrancy_detected_;
+}
+
+} // namespace client
diff --git a/tests/shared/browser/main_message_loop_external_pump.h b/tests/shared/browser/main_message_loop_external_pump.h
new file mode 100644
index 00000000..fa3236ea
--- /dev/null
+++ b/tests/shared/browser/main_message_loop_external_pump.h
@@ -0,0 +1,70 @@
+// Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_SHARED_BROWSER_MAIN_MESSAGE_LOOP_EXTERNAL_PUMP_H_
+#define CEF_TESTS_SHARED_BROWSER_MAIN_MESSAGE_LOOP_EXTERNAL_PUMP_H_
+#pragma once
+
+#include "tests/shared/browser/main_message_loop_std.h"
+
+namespace client {
+
+// This MessageLoop implementation simulates the embedding of CEF into an
+// existing host application that runs its own message loop. The scheduling
+// implementation provided by this class is very simplistic and does not handle
+// all cases (for example, nested message loops on Windows will not function
+// correctly). See comments in Chromium's platform-specific
+// base/message_loop/message_pump_* source files for additional guidance when
+// implementing CefBrowserProcessHandler::OnScheduleMessagePumpWork() in your
+// application. Run cefclient or ceftests with the
+// "--external-message-pump" command-line flag to test this mode.
+class MainMessageLoopExternalPump : public MainMessageLoopStd {
+ public:
+ // Creates the singleton instance of this object. Must be called on the main
+ // application thread.
+ static std::unique_ptr<MainMessageLoopExternalPump> Create();
+
+ // Returns the singleton instance of this object. Safe to call from any
+ // thread.
+ static MainMessageLoopExternalPump* Get();
+
+ // Called from CefBrowserProcessHandler::OnScheduleMessagePumpWork() on any
+ // thread. The platform subclass must implement this method and schedule a
+ // call to OnScheduleWork() on the main application thread.
+ virtual void OnScheduleMessagePumpWork(int64 delay_ms) = 0;
+
+ protected:
+ // Only allow deletion via std::unique_ptr.
+ friend std::default_delete<MainMessageLoopExternalPump>;
+
+ // Construct and destruct this object on the main application thread.
+ MainMessageLoopExternalPump();
+ ~MainMessageLoopExternalPump();
+
+ // The platform subclass calls this method on the main application thread in
+ // response to the OnScheduleMessagePumpWork() call.
+ void OnScheduleWork(int64 delay_ms);
+
+ // The platform subclass calls this method on the main application thread when
+ // the pending work timer times out.
+ void OnTimerTimeout();
+
+ // Control the pending work timer in the platform subclass. Only called on
+ // the main application thread.
+ virtual void SetTimer(int64 delay_ms) = 0;
+ virtual void KillTimer() = 0;
+ virtual bool IsTimerPending() = 0;
+
+ private:
+ // Handle work processing.
+ void DoWork();
+ bool PerformMessageLoopWork();
+
+ bool is_active_;
+ bool reentrancy_detected_;
+};
+
+} // namespace client
+
+#endif // CEF_TESTS_SHARED_BROWSER_MAIN_MESSAGE_LOOP_EXTERNAL_PUMP_H_
diff --git a/tests/shared/browser/main_message_loop_external_pump_linux.cc b/tests/shared/browser/main_message_loop_external_pump_linux.cc
new file mode 100644
index 00000000..5f94afc3
--- /dev/null
+++ b/tests/shared/browser/main_message_loop_external_pump_linux.cc
@@ -0,0 +1,306 @@
+// Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/shared/browser/main_message_loop_external_pump.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <glib.h>
+#include <math.h>
+
+#include <memory>
+
+#include "include/base/cef_logging.h"
+#include "include/cef_app.h"
+
+// From base/posix/eintr_wrapper.h.
+// This provides a wrapper around system calls which may be interrupted by a
+// signal and return EINTR. See man 7 signal.
+// To prevent long-lasting loops (which would likely be a bug, such as a signal
+// that should be masked) to go unnoticed, there is a limit after which the
+// caller will nonetheless see an EINTR in Debug builds.
+#if !defined(HANDLE_EINTR)
+#if !DCHECK_IS_ON()
+
+#define HANDLE_EINTR(x) \
+ ({ \
+ decltype(x) eintr_wrapper_result; \
+ do { \
+ eintr_wrapper_result = (x); \
+ } while (eintr_wrapper_result == -1 && errno == EINTR); \
+ eintr_wrapper_result; \
+ })
+
+#else
+
+#define HANDLE_EINTR(x) \
+ ({ \
+ int eintr_wrapper_counter = 0; \
+ decltype(x) eintr_wrapper_result; \
+ do { \
+ eintr_wrapper_result = (x); \
+ } while (eintr_wrapper_result == -1 && errno == EINTR && \
+ eintr_wrapper_counter++ < 100); \
+ eintr_wrapper_result; \
+ })
+
+#endif // !DCHECK_IS_ON()
+#endif // !defined(HANDLE_EINTR)
+
+namespace client {
+
+namespace {
+
+class MainMessageLoopExternalPumpLinux : public MainMessageLoopExternalPump {
+ public:
+ MainMessageLoopExternalPumpLinux();
+ ~MainMessageLoopExternalPumpLinux();
+
+ // MainMessageLoopStd methods:
+ void Quit() override;
+ int Run() override;
+
+ // MainMessageLoopExternalPump methods:
+ void OnScheduleMessagePumpWork(int64 delay_ms) override;
+
+ // Internal methods used for processing the pump callbacks. They are public
+ // for simplicity but should not be used directly. HandlePrepare is called
+ // during the prepare step of glib, and returns a timeout that will be passed
+ // to the poll. HandleCheck is called after the poll has completed, and
+ // returns whether or not HandleDispatch should be called. HandleDispatch is
+ // called if HandleCheck returned true.
+ int HandlePrepare();
+ bool HandleCheck();
+ void HandleDispatch();
+
+ protected:
+ // MainMessageLoopExternalPump methods:
+ void SetTimer(int64 delay_ms) override;
+ void KillTimer() override;
+ bool IsTimerPending() override;
+
+ private:
+ // Used to flag that the Run() invocation should return ASAP.
+ bool should_quit_;
+
+ // A GLib structure that we can add event sources to. We use the default GLib
+ // context, which is the one to which all GTK events are dispatched.
+ GMainContext* context_;
+
+ // The work source. It is destroyed when the message pump is destroyed.
+ GSource* work_source_;
+
+ // The time when we need to do delayed work.
+ CefTime delayed_work_time_;
+
+ // We use a wakeup pipe to make sure we'll get out of the glib polling phase
+ // when another thread has scheduled us to do some work. There is a glib
+ // mechanism g_main_context_wakeup, but this won't guarantee that our event's
+ // Dispatch() will be called.
+ int wakeup_pipe_read_;
+ int wakeup_pipe_write_;
+
+ // Use a std::unique_ptr to avoid needing the definition of GPollFD in the
+ // header.
+ std::unique_ptr<GPollFD> wakeup_gpollfd_;
+};
+
+// Return a timeout suitable for the glib loop, -1 to block forever,
+// 0 to return right away, or a timeout in milliseconds from now.
+int GetTimeIntervalMilliseconds(const CefTime& from) {
+ if (from.GetDoubleT() == 0.0) {
+ return -1;
+ }
+
+ CefTime now;
+ now.Now();
+
+ // Be careful here. CefTime has a precision of microseconds, but we want a
+ // value in milliseconds. If there are 5.5ms left, should the delay be 5 or
+ // 6? It should be 6 to avoid executing delayed work too early.
+ int delay =
+ static_cast<int>(ceil((from.GetDoubleT() - now.GetDoubleT()) * 1000.0));
+
+ // If this value is negative, then we need to run delayed work soon.
+ return delay < 0 ? 0 : delay;
+}
+
+struct WorkSource : public GSource {
+ MainMessageLoopExternalPumpLinux* pump;
+};
+
+gboolean WorkSourcePrepare(GSource* source, gint* timeout_ms) {
+ *timeout_ms = static_cast<WorkSource*>(source)->pump->HandlePrepare();
+ // We always return FALSE, so that our timeout is honored. If we were
+ // to return TRUE, the timeout would be considered to be 0 and the poll
+ // would never block. Once the poll is finished, Check will be called.
+ return FALSE;
+}
+
+gboolean WorkSourceCheck(GSource* source) {
+ // Only return TRUE if Dispatch should be called.
+ return static_cast<WorkSource*>(source)->pump->HandleCheck();
+}
+
+gboolean WorkSourceDispatch(GSource* source,
+ GSourceFunc unused_func,
+ gpointer unused_data) {
+ static_cast<WorkSource*>(source)->pump->HandleDispatch();
+ // Always return TRUE so our source stays registered.
+ return TRUE;
+}
+
+// I wish these could be const, but g_source_new wants non-const.
+GSourceFuncs WorkSourceFuncs = {WorkSourcePrepare, WorkSourceCheck,
+ WorkSourceDispatch, nullptr};
+
+MainMessageLoopExternalPumpLinux::MainMessageLoopExternalPumpLinux()
+ : should_quit_(false),
+ context_(g_main_context_default()),
+ wakeup_gpollfd_(new GPollFD) {
+ // Create our wakeup pipe, which is used to flag when work was scheduled.
+ int fds[2];
+ int ret = pipe(fds);
+ DCHECK_EQ(ret, 0);
+ (void)ret; // Prevent warning in release mode.
+
+ wakeup_pipe_read_ = fds[0];
+ wakeup_pipe_write_ = fds[1];
+ wakeup_gpollfd_->fd = wakeup_pipe_read_;
+ wakeup_gpollfd_->events = G_IO_IN;
+
+ work_source_ = g_source_new(&WorkSourceFuncs, sizeof(WorkSource));
+ static_cast<WorkSource*>(work_source_)->pump = this;
+ g_source_add_poll(work_source_, wakeup_gpollfd_.get());
+ // Use a low priority so that we let other events in the queue go first.
+ g_source_set_priority(work_source_, G_PRIORITY_DEFAULT_IDLE);
+ // This is needed to allow Run calls inside Dispatch.
+ g_source_set_can_recurse(work_source_, TRUE);
+ g_source_attach(work_source_, context_);
+}
+
+MainMessageLoopExternalPumpLinux::~MainMessageLoopExternalPumpLinux() {
+ g_source_destroy(work_source_);
+ g_source_unref(work_source_);
+ close(wakeup_pipe_read_);
+ close(wakeup_pipe_write_);
+}
+
+void MainMessageLoopExternalPumpLinux::Quit() {
+ should_quit_ = true;
+}
+
+int MainMessageLoopExternalPumpLinux::Run() {
+ // We really only do a single task for each iteration of the loop. If we
+ // have done something, assume there is likely something more to do. This
+ // will mean that we don't block on the message pump until there was nothing
+ // more to do. We also set this to true to make sure not to block on the
+ // first iteration of the loop.
+ bool more_work_is_plausible = true;
+
+ // We run our own loop instead of using g_main_loop_quit in one of the
+ // callbacks. This is so we only quit our own loops, and we don't quit
+ // nested loops run by others.
+ for (;;) {
+ // Don't block if we think we have more work to do.
+ bool block = !more_work_is_plausible;
+
+ more_work_is_plausible = g_main_context_iteration(context_, block);
+ if (should_quit_) {
+ break;
+ }
+ }
+
+ // We need to run the message pump until it is idle. However we don't have
+ // that information here so we run the message loop "for a while".
+ for (int i = 0; i < 10; ++i) {
+ // Do some work.
+ CefDoMessageLoopWork();
+
+ // Sleep to allow the CEF proc to do work.
+ usleep(50000);
+ }
+
+ return 0;
+}
+
+void MainMessageLoopExternalPumpLinux::OnScheduleMessagePumpWork(
+ int64 delay_ms) {
+ // This can be called on any thread, so we don't want to touch any state
+ // variables as we would then need locks all over. This ensures that if we
+ // are sleeping in a poll that we will wake up.
+ if (HANDLE_EINTR(write(wakeup_pipe_write_, &delay_ms, sizeof(int64))) !=
+ sizeof(int64)) {
+ NOTREACHED() << "Could not write to the UI message loop wakeup pipe!";
+ }
+}
+
+// Return the timeout we want passed to poll.
+int MainMessageLoopExternalPumpLinux::HandlePrepare() {
+ // We don't think we have work to do, but make sure not to block longer than
+ // the next time we need to run delayed work.
+ return GetTimeIntervalMilliseconds(delayed_work_time_);
+}
+
+bool MainMessageLoopExternalPumpLinux::HandleCheck() {
+ // We usually have a single message on the wakeup pipe, since we are only
+ // signaled when the queue went from empty to non-empty, but there can be
+ // two messages if a task posted a task, hence we read at most two bytes.
+ // The glib poll will tell us whether there was data, so this read shouldn't
+ // block.
+ if (wakeup_gpollfd_->revents & G_IO_IN) {
+ int64 delay_ms[2];
+ const size_t num_bytes =
+ HANDLE_EINTR(read(wakeup_pipe_read_, delay_ms, sizeof(int64) * 2));
+ if (num_bytes < sizeof(int64)) {
+ NOTREACHED() << "Error reading from the wakeup pipe.";
+ }
+ if (num_bytes == sizeof(int64)) {
+ OnScheduleWork(delay_ms[0]);
+ }
+ if (num_bytes == sizeof(int64) * 2) {
+ OnScheduleWork(delay_ms[1]);
+ }
+ }
+
+ if (GetTimeIntervalMilliseconds(delayed_work_time_) == 0) {
+ // The timer has expired. That condition will stay true until we process
+ // that delayed work, so we don't need to record this differently.
+ return true;
+ }
+
+ return false;
+}
+
+void MainMessageLoopExternalPumpLinux::HandleDispatch() {
+ OnTimerTimeout();
+}
+
+void MainMessageLoopExternalPumpLinux::SetTimer(int64 delay_ms) {
+ DCHECK_GT(delay_ms, 0);
+
+ CefTime now;
+ now.Now();
+
+ delayed_work_time_ =
+ CefTime(now.GetDoubleT() + static_cast<double>(delay_ms) / 1000.0);
+}
+
+void MainMessageLoopExternalPumpLinux::KillTimer() {
+ delayed_work_time_ = CefTime();
+}
+
+bool MainMessageLoopExternalPumpLinux::IsTimerPending() {
+ return GetTimeIntervalMilliseconds(delayed_work_time_) > 0;
+}
+
+} // namespace
+
+// static
+std::unique_ptr<MainMessageLoopExternalPump>
+MainMessageLoopExternalPump::Create() {
+ return std::make_unique<MainMessageLoopExternalPumpLinux>();
+}
+
+} // namespace client
diff --git a/tests/shared/browser/main_message_loop_external_pump_mac.mm b/tests/shared/browser/main_message_loop_external_pump_mac.mm
new file mode 100644
index 00000000..323997fe
--- /dev/null
+++ b/tests/shared/browser/main_message_loop_external_pump_mac.mm
@@ -0,0 +1,183 @@
+// Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/shared/browser/main_message_loop_external_pump.h"
+
+#import <AppKit/AppKit.h>
+#import <Foundation/Foundation.h>
+
+#include <memory>
+
+#include "include/cef_app.h"
+
+@class EventHandler;
+
+namespace client {
+
+class MainMessageLoopExternalPumpMac : public MainMessageLoopExternalPump {
+ public:
+ MainMessageLoopExternalPumpMac();
+ ~MainMessageLoopExternalPumpMac();
+
+ // MainMessageLoopStd methods:
+ void Quit() override;
+ int Run() override;
+
+ // MainMessageLoopExternalPump methods:
+ void OnScheduleMessagePumpWork(int64 delay_ms) override;
+
+ // Internal methods used for processing the event callbacks. They are public
+ // for simplicity but should not be used directly.
+ void HandleScheduleWork(int64 delay_ms);
+ void HandleTimerTimeout();
+
+ protected:
+ // MainMessageLoopExternalPump methods:
+ void SetTimer(int64 delay_ms) override;
+ void KillTimer() override;
+ bool IsTimerPending() override { return timer_ != nil; }
+
+ private:
+ // Owner thread that will run events.
+ NSThread* owner_thread_;
+
+ // Pending work timer.
+ NSTimer* timer_;
+
+ // Used to handle event callbacks on the owner thread.
+ EventHandler* event_handler_;
+};
+
+} // namespace client
+
+// Object that handles event callbacks on the owner thread.
+@interface EventHandler : NSObject {
+ @private
+ client::MainMessageLoopExternalPumpMac* pump_;
+}
+
+- (id)initWithPump:(client::MainMessageLoopExternalPumpMac*)pump;
+- (void)scheduleWork:(NSNumber*)delay_ms;
+- (void)timerTimeout:(id)obj;
+@end
+
+@implementation EventHandler
+
+- (id)initWithPump:(client::MainMessageLoopExternalPumpMac*)pump {
+ if (self = [super init]) {
+ pump_ = pump;
+ }
+ return self;
+}
+
+- (void)scheduleWork:(NSNumber*)delay_ms {
+ pump_->HandleScheduleWork([delay_ms integerValue]);
+}
+
+- (void)timerTimeout:(id)obj {
+ pump_->HandleTimerTimeout();
+}
+
+@end
+
+namespace client {
+
+MainMessageLoopExternalPumpMac::MainMessageLoopExternalPumpMac()
+ : owner_thread_([NSThread currentThread]), timer_(nil) {
+#if !__has_feature(objc_arc)
+ [owner_thread_ retain];
+#endif // !__has_feature(objc_arc)
+ event_handler_ = [[EventHandler alloc] initWithPump:this];
+}
+
+MainMessageLoopExternalPumpMac::~MainMessageLoopExternalPumpMac() {
+ KillTimer();
+#if !__has_feature(objc_arc)
+ [owner_thread_ release];
+ [event_handler_ release];
+#endif // !__has_feature(objc_arc)
+ owner_thread_ = nil;
+ event_handler_ = nil;
+}
+
+void MainMessageLoopExternalPumpMac::Quit() {
+ [NSApp stop:nil];
+}
+
+int MainMessageLoopExternalPumpMac::Run() {
+ // Run the message loop.
+ [NSApp run];
+
+ KillTimer();
+
+ // We need to run the message pump until it is idle. However we don't have
+ // that information here so we run the message loop "for a while".
+ for (int i = 0; i < 10; ++i) {
+ // Let default runloop observers run.
+ CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.001, 1);
+
+ // Do some work.
+ CefDoMessageLoopWork();
+
+ // Sleep to allow the CEF proc to do work.
+ [NSThread sleepForTimeInterval:0.05];
+ }
+
+ return 0;
+}
+
+void MainMessageLoopExternalPumpMac::OnScheduleMessagePumpWork(int64 delay_ms) {
+ // This method may be called on any thread.
+ NSNumber* number = [NSNumber numberWithInt:static_cast<int>(delay_ms)];
+ [event_handler_ performSelector:@selector(scheduleWork:)
+ onThread:owner_thread_
+ withObject:number
+ waitUntilDone:NO];
+}
+
+void MainMessageLoopExternalPumpMac::HandleScheduleWork(int64 delay_ms) {
+ OnScheduleWork(delay_ms);
+}
+
+void MainMessageLoopExternalPumpMac::HandleTimerTimeout() {
+ OnTimerTimeout();
+}
+
+void MainMessageLoopExternalPumpMac::SetTimer(int64 delay_ms) {
+ DCHECK_GT(delay_ms, 0);
+ DCHECK(!timer_);
+
+ const double delay_s = static_cast<double>(delay_ms) / 1000.0;
+ timer_ = [NSTimer timerWithTimeInterval:delay_s
+ target:event_handler_
+ selector:@selector(timerTimeout:)
+ userInfo:nil
+ repeats:NO];
+#if !__has_feature(objc_arc)
+ [timer_ retain];
+#endif // !__has_feature(objc_arc)
+
+ // Add the timer to default and tracking runloop modes.
+ NSRunLoop* owner_runloop = [NSRunLoop currentRunLoop];
+ [owner_runloop addTimer:timer_ forMode:NSRunLoopCommonModes];
+ [owner_runloop addTimer:timer_ forMode:NSEventTrackingRunLoopMode];
+}
+
+void MainMessageLoopExternalPumpMac::KillTimer() {
+ if (timer_ != nil) {
+ [timer_ invalidate];
+#if !__has_feature(objc_arc)
+ [timer_ release];
+#endif // !__has_feature(objc_arc)
+ timer_ = nil;
+ }
+}
+
+// static
+std::unique_ptr<MainMessageLoopExternalPump>
+MainMessageLoopExternalPump::Create() {
+ return std::make_unique<MainMessageLoopExternalPumpMac>();
+}
+
+} // namespace client
diff --git a/tests/shared/browser/main_message_loop_external_pump_win.cc b/tests/shared/browser/main_message_loop_external_pump_win.cc
new file mode 100644
index 00000000..36fca503
--- /dev/null
+++ b/tests/shared/browser/main_message_loop_external_pump_win.cc
@@ -0,0 +1,155 @@
+// Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/shared/browser/main_message_loop_external_pump.h"
+
+#include <CommCtrl.h>
+
+#include <memory>
+
+#include "include/cef_app.h"
+#include "tests/shared/browser/util_win.h"
+
+namespace client {
+
+namespace {
+
+// Message sent to get an additional time slice for pumping (processing) another
+// task (a series of such messages creates a continuous task pump).
+static const int kMsgHaveWork = WM_USER + 1;
+
+class MainMessageLoopExternalPumpWin : public MainMessageLoopExternalPump {
+ public:
+ MainMessageLoopExternalPumpWin();
+ ~MainMessageLoopExternalPumpWin();
+
+ // MainMessageLoopStd methods:
+ void Quit() override;
+ int Run() override;
+
+ // MainMessageLoopExternalPump methods:
+ void OnScheduleMessagePumpWork(int64 delay_ms) override;
+
+ protected:
+ // MainMessageLoopExternalPump methods:
+ void SetTimer(int64 delay_ms) override;
+ void KillTimer() override;
+ bool IsTimerPending() override { return timer_pending_; }
+
+ private:
+ static LRESULT CALLBACK WndProc(HWND hwnd,
+ UINT msg,
+ WPARAM wparam,
+ LPARAM lparam);
+
+ // True if a timer event is currently pending.
+ bool timer_pending_;
+
+ // HWND owned by the thread that CefDoMessageLoopWork should be invoked on.
+ HWND main_thread_target_;
+};
+
+MainMessageLoopExternalPumpWin::MainMessageLoopExternalPumpWin()
+ : timer_pending_(false), main_thread_target_(nullptr) {
+ HINSTANCE hInstance = GetModuleHandle(nullptr);
+ const wchar_t* const kClassName = L"CEFMainTargetHWND";
+
+ WNDCLASSEX wcex = {};
+ wcex.cbSize = sizeof(WNDCLASSEX);
+ wcex.lpfnWndProc = WndProc;
+ wcex.hInstance = hInstance;
+ wcex.lpszClassName = kClassName;
+ RegisterClassEx(&wcex);
+
+ // Create the message handling window.
+ main_thread_target_ =
+ CreateWindowW(kClassName, nullptr, WS_OVERLAPPEDWINDOW, 0, 0, 0, 0,
+ HWND_MESSAGE, nullptr, hInstance, nullptr);
+ DCHECK(main_thread_target_);
+ SetUserDataPtr(main_thread_target_, this);
+}
+
+MainMessageLoopExternalPumpWin::~MainMessageLoopExternalPumpWin() {
+ KillTimer();
+ if (main_thread_target_) {
+ DestroyWindow(main_thread_target_);
+ }
+}
+
+void MainMessageLoopExternalPumpWin::Quit() {
+ PostMessage(nullptr, WM_QUIT, 0, 0);
+}
+
+int MainMessageLoopExternalPumpWin::Run() {
+ // Run the message loop.
+ MSG msg;
+ while (GetMessage(&msg, nullptr, 0, 0)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+
+ KillTimer();
+
+ // We need to run the message pump until it is idle. However we don't have
+ // that information here so we run the message loop "for a while".
+ for (int i = 0; i < 10; ++i) {
+ // Do some work.
+ CefDoMessageLoopWork();
+
+ // Sleep to allow the CEF proc to do work.
+ Sleep(50);
+ }
+
+ return 0;
+}
+
+void MainMessageLoopExternalPumpWin::OnScheduleMessagePumpWork(int64 delay_ms) {
+ // This method may be called on any thread.
+ PostMessage(main_thread_target_, kMsgHaveWork, 0,
+ static_cast<LPARAM>(delay_ms));
+}
+
+void MainMessageLoopExternalPumpWin::SetTimer(int64 delay_ms) {
+ DCHECK(!timer_pending_);
+ DCHECK_GT(delay_ms, 0);
+ timer_pending_ = true;
+ ::SetTimer(main_thread_target_, 1, static_cast<UINT>(delay_ms), nullptr);
+}
+
+void MainMessageLoopExternalPumpWin::KillTimer() {
+ if (timer_pending_) {
+ ::KillTimer(main_thread_target_, 1);
+ timer_pending_ = false;
+ }
+}
+
+// static
+LRESULT CALLBACK MainMessageLoopExternalPumpWin::WndProc(HWND hwnd,
+ UINT msg,
+ WPARAM wparam,
+ LPARAM lparam) {
+ if (msg == WM_TIMER || msg == kMsgHaveWork) {
+ MainMessageLoopExternalPumpWin* message_loop =
+ GetUserDataPtr<MainMessageLoopExternalPumpWin*>(hwnd);
+ if (msg == kMsgHaveWork) {
+ // OnScheduleMessagePumpWork() request.
+ const int64 delay_ms = static_cast<int64>(lparam);
+ message_loop->OnScheduleWork(delay_ms);
+ } else {
+ // Timer timed out.
+ message_loop->OnTimerTimeout();
+ }
+ }
+ return DefWindowProc(hwnd, msg, wparam, lparam);
+}
+
+} // namespace
+
+// static
+std::unique_ptr<MainMessageLoopExternalPump>
+MainMessageLoopExternalPump::Create() {
+ return std::make_unique<MainMessageLoopExternalPumpWin>();
+}
+
+} // namespace client
diff --git a/tests/shared/browser/main_message_loop_std.cc b/tests/shared/browser/main_message_loop_std.cc
new file mode 100644
index 00000000..d329f908
--- /dev/null
+++ b/tests/shared/browser/main_message_loop_std.cc
@@ -0,0 +1,37 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/shared/browser/main_message_loop_std.h"
+
+#include "include/cef_app.h"
+
+namespace client {
+
+MainMessageLoopStd::MainMessageLoopStd() {}
+
+int MainMessageLoopStd::Run() {
+ CefRunMessageLoop();
+ return 0;
+}
+
+void MainMessageLoopStd::Quit() {
+ CefQuitMessageLoop();
+}
+
+void MainMessageLoopStd::PostTask(CefRefPtr<CefTask> task) {
+ CefPostTask(TID_UI, task);
+}
+
+bool MainMessageLoopStd::RunsTasksOnCurrentThread() const {
+ return CefCurrentlyOn(TID_UI);
+}
+
+#if defined(OS_WIN)
+void MainMessageLoopStd::SetCurrentModelessDialog(HWND hWndDialog) {
+ // Nothing to do here. The Chromium message loop implementation will
+ // internally route dialog messages.
+}
+#endif
+
+} // namespace client
diff --git a/tests/shared/browser/main_message_loop_std.h b/tests/shared/browser/main_message_loop_std.h
new file mode 100644
index 00000000..3bded74c
--- /dev/null
+++ b/tests/shared/browser/main_message_loop_std.h
@@ -0,0 +1,35 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_SHARED_BROWSER_MAIN_MESSAGE_LOOP_STD_H_
+#define CEF_TESTS_SHARED_BROWSER_MAIN_MESSAGE_LOOP_STD_H_
+#pragma once
+
+#include "tests/shared/browser/main_message_loop.h"
+
+namespace client {
+
+// Represents the main message loop in the browser process. This implementation
+// is a light-weight wrapper around the Chromium UI thread.
+class MainMessageLoopStd : public MainMessageLoop {
+ public:
+ MainMessageLoopStd();
+
+ // MainMessageLoop methods.
+ int Run() override;
+ void Quit() override;
+ void PostTask(CefRefPtr<CefTask> task) override;
+ bool RunsTasksOnCurrentThread() const override;
+
+#if defined(OS_WIN)
+ void SetCurrentModelessDialog(HWND hWndDialog) override;
+#endif
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MainMessageLoopStd);
+};
+
+} // namespace client
+
+#endif // CEF_TESTS_SHARED_BROWSER_MAIN_MESSAGE_LOOP_STD_H_
diff --git a/tests/shared/browser/resource_util.h b/tests/shared/browser/resource_util.h
new file mode 100644
index 00000000..0e03eb7b
--- /dev/null
+++ b/tests/shared/browser/resource_util.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_SHARED_BROWSER_RESOURCE_UTIL_H_
+#define CEF_TESTS_SHARED_BROWSER_RESOURCE_UTIL_H_
+#pragma once
+
+#include <string>
+#include "include/cef_image.h"
+#include "include/cef_stream.h"
+
+#if defined(OS_WIN)
+#include "include/wrapper/cef_resource_manager.h"
+#endif
+
+namespace client {
+
+// Returns the directory containing resource files.
+bool GetResourceDir(std::string& dir);
+
+// Retrieve a resource as a string.
+bool LoadBinaryResource(const char* resource_name, std::string& resource_data);
+
+// Retrieve a resource as a steam reader.
+CefRefPtr<CefStreamReader> GetBinaryResourceReader(const char* resource_name);
+
+#if defined(OS_WIN)
+// Create a new provider for loading binary resources.
+CefResourceManager::Provider* CreateBinaryResourceProvider(
+ const std::string& url_path,
+ const std::string& resource_path_prefix);
+#endif
+
+} // namespace client
+
+#endif // CEF_TESTS_SHARED_BROWSER_RESOURCE_UTIL_H_
diff --git a/tests/shared/browser/resource_util_linux.cc b/tests/shared/browser/resource_util_linux.cc
new file mode 100644
index 00000000..97d69ca4
--- /dev/null
+++ b/tests/shared/browser/resource_util_linux.cc
@@ -0,0 +1,37 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors.
+// Portions copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "tests/shared/browser/resource_util.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+namespace client {
+
+bool GetResourceDir(std::string& dir) {
+ char buff[1024];
+
+ // Retrieve the executable path.
+ ssize_t len = readlink("/proc/self/exe", buff, sizeof(buff) - 1);
+ if (len == -1) {
+ return false;
+ }
+
+ buff[len] = 0;
+
+ // Remove the executable name from the path.
+ char* pos = strrchr(buff, '/');
+ if (!pos) {
+ return false;
+ }
+
+ // Add "files" to the path.
+ strcpy(pos + 1, "files");
+ dir = std::string(buff);
+ return true;
+}
+
+} // namespace client
diff --git a/tests/shared/browser/resource_util_mac.mm b/tests/shared/browser/resource_util_mac.mm
new file mode 100644
index 00000000..72e88d9b
--- /dev/null
+++ b/tests/shared/browser/resource_util_mac.mm
@@ -0,0 +1,53 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors.
+// Portions copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "tests/shared/browser/resource_util.h"
+
+#import <Foundation/Foundation.h>
+#include <mach-o/dyld.h>
+#include <stdio.h>
+
+#include "include/base/cef_logging.h"
+
+namespace client {
+
+namespace {
+
+// Implementation adapted from Chromium's base/mac/foundation_util.mm
+bool UncachedAmIBundled() {
+ return [[[NSBundle mainBundle] bundlePath] hasSuffix:@".app"];
+}
+
+bool AmIBundled() {
+ static bool am_i_bundled = UncachedAmIBundled();
+ return am_i_bundled;
+}
+
+} // namespace
+
+// Implementation adapted from Chromium's base/base_path_mac.mm
+bool GetResourceDir(std::string& dir) {
+ // Retrieve the executable directory.
+ uint32_t pathSize = 0;
+ _NSGetExecutablePath(nullptr, &pathSize);
+ if (pathSize > 0) {
+ dir.resize(pathSize);
+ _NSGetExecutablePath(const_cast<char*>(dir.c_str()), &pathSize);
+ }
+
+ if (AmIBundled()) {
+ // Trim executable name up to the last separator.
+ auto last_separator = dir.find_last_of("/");
+ dir.resize(last_separator);
+ // Trim directory ("MacOS") up to the last separator.
+ last_separator = dir.find_last_of("/");
+ dir.resize(last_separator);
+ }
+
+ dir.append("/Resources");
+ return true;
+}
+
+} // namespace client
diff --git a/tests/shared/browser/resource_util_posix.cc b/tests/shared/browser/resource_util_posix.cc
new file mode 100644
index 00000000..5c76b40d
--- /dev/null
+++ b/tests/shared/browser/resource_util_posix.cc
@@ -0,0 +1,69 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/shared/browser/resource_util.h"
+
+#include <stdio.h>
+
+namespace client {
+
+namespace {
+
+bool FileExists(const char* path) {
+ FILE* f = fopen(path, "rb");
+ if (f) {
+ fclose(f);
+ return true;
+ }
+ return false;
+}
+
+bool ReadFileToString(const char* path, std::string& data) {
+ // Implementation adapted from base/file_util.cc
+ FILE* file = fopen(path, "rb");
+ if (!file) {
+ return false;
+ }
+
+ char buf[1 << 16];
+ size_t len;
+ while ((len = fread(buf, 1, sizeof(buf), file)) > 0) {
+ data.append(buf, len);
+ }
+ fclose(file);
+
+ return true;
+}
+
+} // namespace
+
+bool LoadBinaryResource(const char* resource_name, std::string& resource_data) {
+ std::string path;
+ if (!GetResourceDir(path)) {
+ return false;
+ }
+
+ path.append("/");
+ path.append(resource_name);
+
+ return ReadFileToString(path.c_str(), resource_data);
+}
+
+CefRefPtr<CefStreamReader> GetBinaryResourceReader(const char* resource_name) {
+ std::string path;
+ if (!GetResourceDir(path)) {
+ return nullptr;
+ }
+
+ path.append("/");
+ path.append(resource_name);
+
+ if (!FileExists(path.c_str())) {
+ return nullptr;
+ }
+
+ return CefStreamReader::CreateForFile(path);
+}
+
+} // namespace client
diff --git a/tests/shared/browser/resource_util_win.cc b/tests/shared/browser/resource_util_win.cc
new file mode 100644
index 00000000..df61ca12
--- /dev/null
+++ b/tests/shared/browser/resource_util_win.cc
@@ -0,0 +1,130 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/shared/browser/resource_util.h"
+
+#include "include/base/cef_logging.h"
+#include "include/cef_stream.h"
+#include "include/wrapper/cef_byte_read_handler.h"
+#include "include/wrapper/cef_stream_resource_handler.h"
+
+namespace client {
+
+namespace {
+
+bool LoadBinaryResource(int binaryId, DWORD& dwSize, LPBYTE& pBytes) {
+ HINSTANCE hInst = GetModuleHandle(nullptr);
+ HRSRC hRes =
+ FindResource(hInst, MAKEINTRESOURCE(binaryId), MAKEINTRESOURCE(256));
+ if (hRes) {
+ HGLOBAL hGlob = LoadResource(hInst, hRes);
+ if (hGlob) {
+ dwSize = SizeofResource(hInst, hRes);
+ pBytes = (LPBYTE)LockResource(hGlob);
+ if (dwSize > 0 && pBytes) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+// Provider of binary resources.
+class BinaryResourceProvider : public CefResourceManager::Provider {
+ public:
+ BinaryResourceProvider(const std::string& url_path,
+ const std::string& resource_path_prefix)
+ : url_path_(url_path), resource_path_prefix_(resource_path_prefix) {
+ DCHECK(!url_path.empty());
+ if (!resource_path_prefix_.empty() &&
+ resource_path_prefix_[resource_path_prefix_.length() - 1] != '/') {
+ resource_path_prefix_ += "/";
+ }
+ }
+
+ bool OnRequest(scoped_refptr<CefResourceManager::Request> request) override {
+ CEF_REQUIRE_IO_THREAD();
+
+ const std::string& url = request->url();
+ if (url.find(url_path_) != 0L) {
+ // Not handled by this provider.
+ return false;
+ }
+
+ CefRefPtr<CefResourceHandler> handler;
+
+ std::string relative_path = url.substr(url_path_.length());
+ if (!relative_path.empty()) {
+ if (!resource_path_prefix_.empty()) {
+ relative_path = resource_path_prefix_ + relative_path;
+ }
+
+ CefRefPtr<CefStreamReader> stream =
+ GetBinaryResourceReader(relative_path.data());
+ if (stream.get()) {
+ handler = new CefStreamResourceHandler(
+ request->mime_type_resolver().Run(url), stream);
+ }
+ }
+
+ request->Continue(handler);
+ return true;
+ }
+
+ private:
+ std::string url_path_;
+ std::string resource_path_prefix_;
+
+ DISALLOW_COPY_AND_ASSIGN(BinaryResourceProvider);
+};
+
+} // namespace
+
+// Implemented in resource_util_win_idmap.cc.
+extern int GetResourceId(const char* resource_name);
+
+bool LoadBinaryResource(const char* resource_name, std::string& resource_data) {
+ int resource_id = GetResourceId(resource_name);
+ if (resource_id == 0) {
+ return false;
+ }
+
+ DWORD dwSize;
+ LPBYTE pBytes;
+
+ if (LoadBinaryResource(resource_id, dwSize, pBytes)) {
+ resource_data = std::string(reinterpret_cast<char*>(pBytes), dwSize);
+ return true;
+ }
+
+ NOTREACHED(); // The resource should be found.
+ return false;
+}
+
+CefRefPtr<CefStreamReader> GetBinaryResourceReader(const char* resource_name) {
+ int resource_id = GetResourceId(resource_name);
+ if (resource_id == 0) {
+ return nullptr;
+ }
+
+ DWORD dwSize;
+ LPBYTE pBytes;
+
+ if (LoadBinaryResource(resource_id, dwSize, pBytes)) {
+ return CefStreamReader::CreateForHandler(
+ new CefByteReadHandler(pBytes, dwSize, nullptr));
+ }
+
+ NOTREACHED(); // The resource should be found.
+ return nullptr;
+}
+
+CefResourceManager::Provider* CreateBinaryResourceProvider(
+ const std::string& url_path,
+ const std::string& resource_path_prefix) {
+ return new BinaryResourceProvider(url_path, resource_path_prefix);
+}
+
+} // namespace client
diff --git a/tests/shared/browser/util_win.cc b/tests/shared/browser/util_win.cc
new file mode 100644
index 00000000..4db8201e
--- /dev/null
+++ b/tests/shared/browser/util_win.cc
@@ -0,0 +1,194 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/shared/browser/util_win.h"
+
+#include "include/base/cef_logging.h"
+
+namespace client {
+
+namespace {
+
+LARGE_INTEGER qi_freq_ = {};
+
+} // namespace
+
+uint64_t GetTimeNow() {
+ if (!qi_freq_.HighPart && !qi_freq_.LowPart) {
+ QueryPerformanceFrequency(&qi_freq_);
+ }
+ LARGE_INTEGER t = {};
+ QueryPerformanceCounter(&t);
+ return static_cast<uint64_t>((t.QuadPart / double(qi_freq_.QuadPart)) *
+ 1000000);
+}
+
+void SetUserDataPtr(HWND hWnd, void* ptr) {
+ SetLastError(ERROR_SUCCESS);
+ LONG_PTR result =
+ ::SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(ptr));
+ CHECK(result != 0 || GetLastError() == ERROR_SUCCESS);
+}
+
+WNDPROC SetWndProcPtr(HWND hWnd, WNDPROC wndProc) {
+ WNDPROC old =
+ reinterpret_cast<WNDPROC>(::GetWindowLongPtr(hWnd, GWLP_WNDPROC));
+ CHECK(old != nullptr);
+ LONG_PTR result = ::SetWindowLongPtr(hWnd, GWLP_WNDPROC,
+ reinterpret_cast<LONG_PTR>(wndProc));
+ CHECK(result != 0 || GetLastError() == ERROR_SUCCESS);
+ return old;
+}
+
+std::wstring GetResourceString(UINT id) {
+#define MAX_LOADSTRING 100
+ TCHAR buff[MAX_LOADSTRING] = {0};
+ LoadString(::GetModuleHandle(nullptr), id, buff, MAX_LOADSTRING);
+ return buff;
+}
+
+int GetCefMouseModifiers(WPARAM wparam) {
+ int modifiers = 0;
+ if (wparam & MK_CONTROL) {
+ modifiers |= EVENTFLAG_CONTROL_DOWN;
+ }
+ if (wparam & MK_SHIFT) {
+ modifiers |= EVENTFLAG_SHIFT_DOWN;
+ }
+ if (IsKeyDown(VK_MENU)) {
+ modifiers |= EVENTFLAG_ALT_DOWN;
+ }
+ if (wparam & MK_LBUTTON) {
+ modifiers |= EVENTFLAG_LEFT_MOUSE_BUTTON;
+ }
+ if (wparam & MK_MBUTTON) {
+ modifiers |= EVENTFLAG_MIDDLE_MOUSE_BUTTON;
+ }
+ if (wparam & MK_RBUTTON) {
+ modifiers |= EVENTFLAG_RIGHT_MOUSE_BUTTON;
+ }
+
+ // Low bit set from GetKeyState indicates "toggled".
+ if (::GetKeyState(VK_NUMLOCK) & 1) {
+ modifiers |= EVENTFLAG_NUM_LOCK_ON;
+ }
+ if (::GetKeyState(VK_CAPITAL) & 1) {
+ modifiers |= EVENTFLAG_CAPS_LOCK_ON;
+ }
+ return modifiers;
+}
+
+int GetCefKeyboardModifiers(WPARAM wparam, LPARAM lparam) {
+ int modifiers = 0;
+ if (IsKeyDown(VK_SHIFT)) {
+ modifiers |= EVENTFLAG_SHIFT_DOWN;
+ }
+ if (IsKeyDown(VK_CONTROL)) {
+ modifiers |= EVENTFLAG_CONTROL_DOWN;
+ }
+ if (IsKeyDown(VK_MENU)) {
+ modifiers |= EVENTFLAG_ALT_DOWN;
+ }
+
+ // Low bit set from GetKeyState indicates "toggled".
+ if (::GetKeyState(VK_NUMLOCK) & 1) {
+ modifiers |= EVENTFLAG_NUM_LOCK_ON;
+ }
+ if (::GetKeyState(VK_CAPITAL) & 1) {
+ modifiers |= EVENTFLAG_CAPS_LOCK_ON;
+ }
+
+ switch (wparam) {
+ case VK_RETURN:
+ if ((lparam >> 16) & KF_EXTENDED) {
+ modifiers |= EVENTFLAG_IS_KEY_PAD;
+ }
+ break;
+ case VK_INSERT:
+ case VK_DELETE:
+ case VK_HOME:
+ case VK_END:
+ case VK_PRIOR:
+ case VK_NEXT:
+ case VK_UP:
+ case VK_DOWN:
+ case VK_LEFT:
+ case VK_RIGHT:
+ if (!((lparam >> 16) & KF_EXTENDED)) {
+ modifiers |= EVENTFLAG_IS_KEY_PAD;
+ }
+ break;
+ case VK_NUMLOCK:
+ case VK_NUMPAD0:
+ case VK_NUMPAD1:
+ case VK_NUMPAD2:
+ case VK_NUMPAD3:
+ case VK_NUMPAD4:
+ case VK_NUMPAD5:
+ case VK_NUMPAD6:
+ case VK_NUMPAD7:
+ case VK_NUMPAD8:
+ case VK_NUMPAD9:
+ case VK_DIVIDE:
+ case VK_MULTIPLY:
+ case VK_SUBTRACT:
+ case VK_ADD:
+ case VK_DECIMAL:
+ case VK_CLEAR:
+ modifiers |= EVENTFLAG_IS_KEY_PAD;
+ break;
+ case VK_SHIFT:
+ if (IsKeyDown(VK_LSHIFT)) {
+ modifiers |= EVENTFLAG_IS_LEFT;
+ } else if (IsKeyDown(VK_RSHIFT)) {
+ modifiers |= EVENTFLAG_IS_RIGHT;
+ }
+ break;
+ case VK_CONTROL:
+ if (IsKeyDown(VK_LCONTROL)) {
+ modifiers |= EVENTFLAG_IS_LEFT;
+ } else if (IsKeyDown(VK_RCONTROL)) {
+ modifiers |= EVENTFLAG_IS_RIGHT;
+ }
+ break;
+ case VK_MENU:
+ if (IsKeyDown(VK_LMENU)) {
+ modifiers |= EVENTFLAG_IS_LEFT;
+ } else if (IsKeyDown(VK_RMENU)) {
+ modifiers |= EVENTFLAG_IS_RIGHT;
+ }
+ break;
+ case VK_LWIN:
+ modifiers |= EVENTFLAG_IS_LEFT;
+ break;
+ case VK_RWIN:
+ modifiers |= EVENTFLAG_IS_RIGHT;
+ break;
+ }
+ return modifiers;
+}
+
+bool IsKeyDown(WPARAM wparam) {
+ return (GetKeyState(wparam) & 0x8000) != 0;
+}
+
+float GetDeviceScaleFactor() {
+ static float scale_factor = 1.0;
+ static bool initialized = false;
+
+ if (!initialized) {
+ // This value is safe to cache for the life time of the app since the user
+ // must logout to change the DPI setting. This value also applies to all
+ // screens.
+ HDC screen_dc = ::GetDC(nullptr);
+ int dpi_x = GetDeviceCaps(screen_dc, LOGPIXELSX);
+ scale_factor = static_cast<float>(dpi_x) / 96.0f;
+ ::ReleaseDC(nullptr, screen_dc);
+ initialized = true;
+ }
+
+ return scale_factor;
+}
+
+} // namespace client
diff --git a/tests/shared/browser/util_win.h b/tests/shared/browser/util_win.h
new file mode 100644
index 00000000..a46d77e2
--- /dev/null
+++ b/tests/shared/browser/util_win.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_SHARED_BROWSER_UTIL_WIN_H_
+#define CEF_TESTS_SHARED_BROWSER_UTIL_WIN_H_
+#pragma once
+
+#include <windows.h>
+#include <string>
+
+#include "include/internal/cef_types_wrappers.h"
+
+namespace client {
+
+// Returns the current time in microseconds.
+uint64_t GetTimeNow();
+
+// Set the window's user data pointer.
+void SetUserDataPtr(HWND hWnd, void* ptr);
+
+// Return the window's user data pointer.
+template <typename T>
+T GetUserDataPtr(HWND hWnd) {
+ return reinterpret_cast<T>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
+}
+
+// Set the window's window procedure pointer and return the old value.
+WNDPROC SetWndProcPtr(HWND hWnd, WNDPROC wndProc);
+
+// Return the resource string with the specified id.
+std::wstring GetResourceString(UINT id);
+
+int GetCefMouseModifiers(WPARAM wparam);
+int GetCefKeyboardModifiers(WPARAM wparam, LPARAM lparam);
+bool IsKeyDown(WPARAM wparam);
+
+// Returns the device scale factor. For example, 200% display scaling will
+// return 2.0.
+float GetDeviceScaleFactor();
+
+} // namespace client
+
+#endif // CEF_TESTS_SHARED_BROWSER_UTIL_WIN_H_
diff --git a/tests/shared/common/binary_value_utils.cc b/tests/shared/common/binary_value_utils.cc
new file mode 100644
index 00000000..68f62933
--- /dev/null
+++ b/tests/shared/common/binary_value_utils.cc
@@ -0,0 +1,44 @@
+// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/shared/common/binary_value_utils.h"
+
+namespace bv_utils {
+
+const char kTestSendProcessMessage[] = "testSendProcessMessage";
+const char kTestSendSMRProcessMessage[] = "testSendSMRProcessMessage";
+
+TimePoint Now() {
+ return std::chrono::high_resolution_clock::now();
+}
+
+CefRefPtr<CefBinaryValue> CreateCefBinaryValue(
+ const std::vector<uint8_t>& data) {
+ return CefBinaryValue::Create(data.data(), data.size());
+}
+
+RendererMessage GetRendererMsgFromBinary(
+ const CefRefPtr<CefBinaryValue>& value) {
+ DCHECK_GE(value->GetSize(), sizeof(RendererMessage));
+ std::vector<uint8_t> data(value->GetSize());
+ value->GetData(data.data(), data.size(), 0);
+ return *reinterpret_cast<const RendererMessage*>(data.data());
+}
+
+BrowserMessage GetBrowserMsgFromBinary(const CefRefPtr<CefBinaryValue>& value) {
+ DCHECK_GE(value->GetSize(), sizeof(BrowserMessage));
+ std::vector<uint8_t> data(value->GetSize());
+ value->GetData(data.data(), data.size(), 0);
+ return *reinterpret_cast<const BrowserMessage*>(data.data());
+}
+
+std::string ToMilliString(const Duration& duration) {
+ const auto ms =
+ std::chrono::duration_cast<std::chrono::duration<double, std::milli>>(
+ duration);
+
+ return std::to_string(ms.count());
+}
+
+} // namespace bv_utils
diff --git a/tests/shared/common/binary_value_utils.h b/tests/shared/common/binary_value_utils.h
new file mode 100644
index 00000000..f5346e6b
--- /dev/null
+++ b/tests/shared/common/binary_value_utils.h
@@ -0,0 +1,47 @@
+// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_SHARED_COMMON_BINARY_VALUE_UTILS
+#define CEF_TESTS_SHARED_COMMON_BINARY_VALUE_UTILS
+#pragma once
+
+#include <chrono>
+#include <cstdint>
+#include <vector>
+#include "include/cef_values.h"
+
+namespace bv_utils {
+
+extern const char kTestSendProcessMessage[];
+extern const char kTestSendSMRProcessMessage[];
+
+using TimePoint = std::chrono::high_resolution_clock::time_point;
+using Duration = std::chrono::high_resolution_clock::duration;
+
+struct RendererMessage {
+ int test_id;
+ TimePoint start_time;
+};
+
+struct BrowserMessage {
+ int test_id;
+ Duration duration;
+ TimePoint start_time;
+};
+
+TimePoint Now();
+
+CefRefPtr<CefBinaryValue> CreateCefBinaryValue(
+ const std::vector<uint8_t>& data);
+
+RendererMessage GetRendererMsgFromBinary(
+ const CefRefPtr<CefBinaryValue>& value);
+
+BrowserMessage GetBrowserMsgFromBinary(const CefRefPtr<CefBinaryValue>& value);
+
+std::string ToMilliString(const Duration& duration);
+
+} // namespace bv_utils
+
+#endif // CEF_TESTS_SHARED_COMMON_BINARY_VALUE_UTILS
diff --git a/tests/shared/common/client_app.cc b/tests/shared/common/client_app.cc
new file mode 100644
index 00000000..76ecde75
--- /dev/null
+++ b/tests/shared/common/client_app.cc
@@ -0,0 +1,50 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/shared/common/client_app.h"
+
+#include "include/cef_command_line.h"
+
+namespace client {
+
+namespace {
+
+// These flags must match the Chromium values.
+const char kProcessType[] = "type";
+const char kRendererProcess[] = "renderer";
+#if defined(OS_LINUX)
+const char kZygoteProcess[] = "zygote";
+#endif
+
+} // namespace
+
+ClientApp::ClientApp() {}
+
+// static
+ClientApp::ProcessType ClientApp::GetProcessType(
+ CefRefPtr<CefCommandLine> command_line) {
+ // The command-line flag won't be specified for the browser process.
+ if (!command_line->HasSwitch(kProcessType)) {
+ return BrowserProcess;
+ }
+
+ const std::string& process_type = command_line->GetSwitchValue(kProcessType);
+ if (process_type == kRendererProcess) {
+ return RendererProcess;
+ }
+#if defined(OS_LINUX)
+ else if (process_type == kZygoteProcess) {
+ return ZygoteProcess;
+ }
+#endif
+
+ return OtherProcess;
+}
+
+void ClientApp::OnRegisterCustomSchemes(
+ CefRawPtr<CefSchemeRegistrar> registrar) {
+ RegisterCustomSchemes(registrar);
+}
+
+} // namespace client
diff --git a/tests/shared/common/client_app.h b/tests/shared/common/client_app.h
new file mode 100644
index 00000000..553f0d4c
--- /dev/null
+++ b/tests/shared/common/client_app.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_SHARED_COMMON_CLIENT_APP_H_
+#define CEF_TESTS_SHARED_COMMON_CLIENT_APP_H_
+#pragma once
+
+#include <vector>
+
+#include "include/cef_app.h"
+
+namespace client {
+
+// Base class for customizing process-type-based behavior.
+class ClientApp : public CefApp {
+ public:
+ ClientApp();
+
+ enum ProcessType {
+ BrowserProcess,
+ RendererProcess,
+ ZygoteProcess,
+ OtherProcess,
+ };
+
+ // Determine the process type based on command-line arguments.
+ static ProcessType GetProcessType(CefRefPtr<CefCommandLine> command_line);
+
+ private:
+ // Registers custom schemes. Implemented by cefclient in
+ // client_app_delegates_common.cc
+ static void RegisterCustomSchemes(CefRawPtr<CefSchemeRegistrar> registrar);
+
+ // CefApp methods.
+ void OnRegisterCustomSchemes(
+ CefRawPtr<CefSchemeRegistrar> registrar) override;
+
+ DISALLOW_COPY_AND_ASSIGN(ClientApp);
+};
+
+} // namespace client
+
+#endif // CEF_TESTS_SHARED_COMMON_CLIENT_APP_H_
diff --git a/tests/shared/common/client_app_other.cc b/tests/shared/common/client_app_other.cc
new file mode 100644
index 00000000..9f6a0c4f
--- /dev/null
+++ b/tests/shared/common/client_app_other.cc
@@ -0,0 +1,13 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/shared/common/client_app_other.h"
+
+#include "include/cef_command_line.h"
+
+namespace client {
+
+ClientAppOther::ClientAppOther() {}
+
+} // namespace client
diff --git a/tests/shared/common/client_app_other.h b/tests/shared/common/client_app_other.h
new file mode 100644
index 00000000..b8a73428
--- /dev/null
+++ b/tests/shared/common/client_app_other.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_SHARED_COMMON_CLIENT_APP_OTHER_H_
+#define CEF_TESTS_SHARED_COMMON_CLIENT_APP_OTHER_H_
+#pragma once
+
+#include "tests/shared/common/client_app.h"
+
+namespace client {
+
+// Client app implementation for other process types.
+class ClientAppOther : public ClientApp {
+ public:
+ ClientAppOther();
+
+ private:
+ IMPLEMENT_REFCOUNTING(ClientAppOther);
+ DISALLOW_COPY_AND_ASSIGN(ClientAppOther);
+};
+
+} // namespace client
+
+#endif // CEF_TESTS_SHARED_COMMON_CLIENT_APP_OTHER_H_
diff --git a/tests/shared/common/client_switches.cc b/tests/shared/common/client_switches.cc
new file mode 100644
index 00000000..8cd9f85c
--- /dev/null
+++ b/tests/shared/common/client_switches.cc
@@ -0,0 +1,58 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/shared/common/client_switches.h"
+
+namespace client {
+namespace switches {
+
+// CEF and Chromium support a wide range of command-line switches. This file
+// only contains command-line switches specific to the cefclient application.
+// View CEF/Chromium documentation or search for *_switches.cc files in the
+// Chromium source code to identify other existing command-line switches.
+// Below is a partial listing of relevant *_switches.cc files:
+// base/base_switches.cc
+// cef/libcef/common/cef_switches.cc
+// chrome/common/chrome_switches.cc (not all apply)
+// content/public/common/content_switches.cc
+
+const char kMultiThreadedMessageLoop[] = "multi-threaded-message-loop";
+const char kExternalMessagePump[] = "external-message-pump";
+const char kCachePath[] = "cache-path";
+const char kUrl[] = "url";
+const char kOffScreenRenderingEnabled[] = "off-screen-rendering-enabled";
+const char kOffScreenFrameRate[] = "off-screen-frame-rate";
+const char kTransparentPaintingEnabled[] = "transparent-painting-enabled";
+const char kShowUpdateRect[] = "show-update-rect";
+const char kSharedTextureEnabled[] = "shared-texture-enabled";
+const char kExternalBeginFrameEnabled[] = "external-begin-frame-enabled";
+const char kMouseCursorChangeDisabled[] = "mouse-cursor-change-disabled";
+const char kOffline[] = "offline";
+const char kRequestContextPerBrowser[] = "request-context-per-browser";
+const char kRequestContextSharedCache[] = "request-context-shared-cache";
+const char kBackgroundColor[] = "background-color";
+const char kEnableGPU[] = "enable-gpu";
+const char kFilterURL[] = "filter-url";
+const char kUseViews[] = "use-views";
+const char kUseNative[] = "use-native";
+const char kHideFrame[] = "hide-frame";
+const char kHideControls[] = "hide-controls";
+const char kHideOverlays[] = "hide-overlays";
+const char kAlwaysOnTop[] = "always-on-top";
+const char kHideTopMenu[] = "hide-top-menu";
+const char kSslClientCertificate[] = "ssl-client-certificate";
+const char kCRLSetsPath[] = "crl-sets-path";
+const char kLoadExtension[] = "load-extension";
+const char kNoActivate[] = "no-activate";
+const char kEnableChromeRuntime[] = "enable-chrome-runtime";
+const char kShowChromeToolbar[] = "show-chrome-toolbar";
+const char kInitialShowState[] = "initial-show-state";
+const char kHideChromeStatusBubble[] = "hide-chrome-status-bubble";
+const char kUseDefaultPopup[] = "use-default-popup";
+const char kUseClientDialogs[] = "use-client-dialogs";
+const char kUseTestHttpServer[] = "use-test-http-server";
+const char kShowWindowButtons[] = "show-window-buttons";
+
+} // namespace switches
+} // namespace client
diff --git a/tests/shared/common/client_switches.h b/tests/shared/common/client_switches.h
new file mode 100644
index 00000000..6cc3fb4a
--- /dev/null
+++ b/tests/shared/common/client_switches.h
@@ -0,0 +1,54 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+// Defines all of the command line switches used by cefclient.
+
+#ifndef CEF_TESTS_SHARED_SHARED_COMMON_SWITCHES_H_
+#define CEF_TESTS_SHARED_SHARED_COMMON_SWITCHES_H_
+#pragma once
+
+namespace client {
+namespace switches {
+
+extern const char kMultiThreadedMessageLoop[];
+extern const char kExternalMessagePump[];
+extern const char kCachePath[];
+extern const char kUrl[];
+extern const char kOffScreenRenderingEnabled[];
+extern const char kOffScreenFrameRate[];
+extern const char kTransparentPaintingEnabled[];
+extern const char kShowUpdateRect[];
+extern const char kSharedTextureEnabled[];
+extern const char kExternalBeginFrameEnabled[];
+extern const char kMouseCursorChangeDisabled[];
+extern const char kOffline[];
+extern const char kRequestContextPerBrowser[];
+extern const char kRequestContextSharedCache[];
+extern const char kBackgroundColor[];
+extern const char kEnableGPU[];
+extern const char kFilterURL[];
+extern const char kUseViews[];
+extern const char kUseNative[];
+extern const char kHideFrame[];
+extern const char kHideControls[];
+extern const char kHideOverlays[];
+extern const char kAlwaysOnTop[];
+extern const char kHideTopMenu[];
+extern const char kSslClientCertificate[];
+extern const char kCRLSetsPath[];
+extern const char kLoadExtension[];
+extern const char kNoActivate[];
+extern const char kEnableChromeRuntime[];
+extern const char kShowChromeToolbar[];
+extern const char kInitialShowState[];
+extern const char kHideChromeStatusBubble[];
+extern const char kUseDefaultPopup[];
+extern const char kUseClientDialogs[];
+extern const char kUseTestHttpServer[];
+extern const char kShowWindowButtons[];
+
+} // namespace switches
+} // namespace client
+
+#endif // CEF_TESTS_SHARED_SHARED_COMMON_SWITCHES_H_
diff --git a/tests/shared/common/string_util.cc b/tests/shared/common/string_util.cc
new file mode 100644
index 00000000..7bd5ada8
--- /dev/null
+++ b/tests/shared/common/string_util.cc
@@ -0,0 +1,34 @@
+// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/shared/common/string_util.h"
+
+#include <algorithm>
+
+namespace client {
+
+std::string AsciiStrToLower(const std::string& str) {
+ std::string lowerStr = str;
+ std::transform(lowerStr.begin(), lowerStr.end(), lowerStr.begin(), ::tolower);
+ return lowerStr;
+}
+
+std::string AsciiStrReplace(const std::string& str,
+ const std::string& from,
+ const std::string& to) {
+ std::string result = str;
+ std::string::size_type pos = 0;
+ std::string::size_type from_len = from.length();
+ std::string::size_type to_len = to.length();
+ do {
+ pos = result.find(from, pos);
+ if (pos != std::string::npos) {
+ result.replace(pos, from_len, to);
+ pos += to_len;
+ }
+ } while (pos != std::string::npos);
+ return result;
+}
+
+} // namespace client
diff --git a/tests/shared/common/string_util.h b/tests/shared/common/string_util.h
new file mode 100644
index 00000000..5ae4e2c3
--- /dev/null
+++ b/tests/shared/common/string_util.h
@@ -0,0 +1,23 @@
+// Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_SHARED_COMMON_STRING_UTIL_H_
+#define CEF_TESTS_SHARED_COMMON_STRING_UTIL_H_
+#pragma once
+
+#include <string>
+
+namespace client {
+
+// Convert |str| to lowercase.
+std::string AsciiStrToLower(const std::string& str);
+
+// Replace all instances of |from| with |to| in |str|.
+std::string AsciiStrReplace(const std::string& str,
+ const std::string& from,
+ const std::string& to);
+
+} // namespace client
+
+#endif // CEF_TESTS_SHARED_COMMON_STRING_UTIL_H_
diff --git a/tests/shared/process_helper_mac.cc b/tests/shared/process_helper_mac.cc
new file mode 100644
index 00000000..cce48e53
--- /dev/null
+++ b/tests/shared/process_helper_mac.cc
@@ -0,0 +1,60 @@
+// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that can
+// be found in the LICENSE file.
+
+#include "include/cef_app.h"
+#include "include/wrapper/cef_library_loader.h"
+
+#include "tests/shared/common/client_app_other.h"
+#include "tests/shared/renderer/client_app_renderer.h"
+
+// When generating projects with CMake the CEF_USE_SANDBOX value will be defined
+// automatically. Pass -DUSE_SANDBOX=OFF to the CMake command-line to disable
+// use of the sandbox.
+#if defined(CEF_USE_SANDBOX)
+#include "include/cef_sandbox_mac.h"
+#endif
+
+namespace client {
+
+int RunMain(int argc, char* argv[]) {
+#if defined(CEF_USE_SANDBOX)
+ // Initialize the macOS sandbox for this helper process.
+ CefScopedSandboxContext sandbox_context;
+ if (!sandbox_context.Initialize(argc, argv)) {
+ return 1;
+ }
+#endif
+
+ // Load the CEF framework library at runtime instead of linking directly
+ // as required by the macOS sandbox implementation.
+ CefScopedLibraryLoader library_loader;
+ if (!library_loader.LoadInHelper()) {
+ return 1;
+ }
+
+ CefMainArgs main_args(argc, argv);
+
+ // Parse command-line arguments.
+ CefRefPtr<CefCommandLine> command_line = CefCommandLine::CreateCommandLine();
+ command_line->InitFromArgv(argc, argv);
+
+ // Create a ClientApp of the correct type.
+ CefRefPtr<CefApp> app;
+ ClientApp::ProcessType process_type = ClientApp::GetProcessType(command_line);
+ if (process_type == ClientApp::RendererProcess) {
+ app = new ClientAppRenderer();
+ } else if (process_type == ClientApp::OtherProcess) {
+ app = new ClientAppOther();
+ }
+
+ // Execute the secondary process.
+ return CefExecuteProcess(main_args, app, nullptr);
+}
+
+} // namespace client
+
+// Entry point function for sub-processes.
+int main(int argc, char* argv[]) {
+ return client::RunMain(argc, argv);
+}
diff --git a/tests/shared/renderer/client_app_renderer.cc b/tests/shared/renderer/client_app_renderer.cc
new file mode 100644
index 00000000..9347051a
--- /dev/null
+++ b/tests/shared/renderer/client_app_renderer.cc
@@ -0,0 +1,106 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#include "tests/shared/renderer/client_app_renderer.h"
+
+#include "include/base/cef_logging.h"
+
+namespace client {
+
+ClientAppRenderer::ClientAppRenderer() {
+ CreateDelegates(delegates_);
+}
+
+void ClientAppRenderer::OnWebKitInitialized() {
+ DelegateSet::iterator it = delegates_.begin();
+ for (; it != delegates_.end(); ++it) {
+ (*it)->OnWebKitInitialized(this);
+ }
+}
+
+void ClientAppRenderer::OnBrowserCreated(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefDictionaryValue> extra_info) {
+ DelegateSet::iterator it = delegates_.begin();
+ for (; it != delegates_.end(); ++it) {
+ (*it)->OnBrowserCreated(this, browser, extra_info);
+ }
+}
+
+void ClientAppRenderer::OnBrowserDestroyed(CefRefPtr<CefBrowser> browser) {
+ DelegateSet::iterator it = delegates_.begin();
+ for (; it != delegates_.end(); ++it) {
+ (*it)->OnBrowserDestroyed(this, browser);
+ }
+}
+
+CefRefPtr<CefLoadHandler> ClientAppRenderer::GetLoadHandler() {
+ CefRefPtr<CefLoadHandler> load_handler;
+ DelegateSet::iterator it = delegates_.begin();
+ for (; it != delegates_.end() && !load_handler.get(); ++it) {
+ load_handler = (*it)->GetLoadHandler(this);
+ }
+
+ return load_handler;
+}
+
+void ClientAppRenderer::OnContextCreated(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefV8Context> context) {
+ DelegateSet::iterator it = delegates_.begin();
+ for (; it != delegates_.end(); ++it) {
+ (*it)->OnContextCreated(this, browser, frame, context);
+ }
+}
+
+void ClientAppRenderer::OnContextReleased(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefV8Context> context) {
+ DelegateSet::iterator it = delegates_.begin();
+ for (; it != delegates_.end(); ++it) {
+ (*it)->OnContextReleased(this, browser, frame, context);
+ }
+}
+
+void ClientAppRenderer::OnUncaughtException(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefV8Context> context,
+ CefRefPtr<CefV8Exception> exception,
+ CefRefPtr<CefV8StackTrace> stackTrace) {
+ DelegateSet::iterator it = delegates_.begin();
+ for (; it != delegates_.end(); ++it) {
+ (*it)->OnUncaughtException(this, browser, frame, context, exception,
+ stackTrace);
+ }
+}
+
+void ClientAppRenderer::OnFocusedNodeChanged(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefDOMNode> node) {
+ DelegateSet::iterator it = delegates_.begin();
+ for (; it != delegates_.end(); ++it) {
+ (*it)->OnFocusedNodeChanged(this, browser, frame, node);
+ }
+}
+
+bool ClientAppRenderer::OnProcessMessageReceived(
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefProcessId source_process,
+ CefRefPtr<CefProcessMessage> message) {
+ DCHECK_EQ(source_process, PID_BROWSER);
+
+ bool handled = false;
+
+ DelegateSet::iterator it = delegates_.begin();
+ for (; it != delegates_.end() && !handled; ++it) {
+ handled = (*it)->OnProcessMessageReceived(this, browser, frame,
+ source_process, message);
+ }
+
+ return handled;
+}
+
+} // namespace client
diff --git a/tests/shared/renderer/client_app_renderer.h b/tests/shared/renderer/client_app_renderer.h
new file mode 100644
index 00000000..e458e354
--- /dev/null
+++ b/tests/shared/renderer/client_app_renderer.h
@@ -0,0 +1,122 @@
+// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+
+#ifndef CEF_TESTS_SHARED_RENDERER_CLIENT_APP_RENDERER_H_
+#define CEF_TESTS_SHARED_RENDERER_CLIENT_APP_RENDERER_H_
+#pragma once
+
+#include <set>
+
+#include "tests/shared/common/client_app.h"
+
+namespace client {
+
+// Client app implementation for the renderer process.
+class ClientAppRenderer : public ClientApp, public CefRenderProcessHandler {
+ public:
+ // Interface for renderer delegates. All Delegates must be returned via
+ // CreateDelegates. Do not perform work in the Delegate
+ // constructor. See CefRenderProcessHandler for documentation.
+ class Delegate : public virtual CefBaseRefCounted {
+ public:
+ virtual void OnWebKitInitialized(CefRefPtr<ClientAppRenderer> app) {}
+
+ virtual void OnBrowserCreated(CefRefPtr<ClientAppRenderer> app,
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefDictionaryValue> extra_info) {}
+
+ virtual void OnBrowserDestroyed(CefRefPtr<ClientAppRenderer> app,
+ CefRefPtr<CefBrowser> browser) {}
+
+ virtual CefRefPtr<CefLoadHandler> GetLoadHandler(
+ CefRefPtr<ClientAppRenderer> app) {
+ return nullptr;
+ }
+
+ virtual void OnContextCreated(CefRefPtr<ClientAppRenderer> app,
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefV8Context> context) {}
+
+ virtual void OnContextReleased(CefRefPtr<ClientAppRenderer> app,
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefV8Context> context) {}
+
+ virtual void OnUncaughtException(CefRefPtr<ClientAppRenderer> app,
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefV8Context> context,
+ CefRefPtr<CefV8Exception> exception,
+ CefRefPtr<CefV8StackTrace> stackTrace) {}
+
+ virtual void OnFocusedNodeChanged(CefRefPtr<ClientAppRenderer> app,
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefDOMNode> node) {}
+
+ // Called when a process message is received. Return true if the message was
+ // handled and should not be passed on to other handlers. Delegates
+ // should check for unique message names to avoid interfering with each
+ // other.
+ virtual bool OnProcessMessageReceived(
+ CefRefPtr<ClientAppRenderer> app,
+ CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefProcessId source_process,
+ CefRefPtr<CefProcessMessage> message) {
+ return false;
+ }
+ };
+
+ typedef std::set<CefRefPtr<Delegate>> DelegateSet;
+
+ ClientAppRenderer();
+
+ private:
+ // Creates all of the Delegate objects. Implemented by cefclient in
+ // client_app_delegates_renderer.cc
+ static void CreateDelegates(DelegateSet& delegates);
+
+ // CefApp methods.
+ CefRefPtr<CefRenderProcessHandler> GetRenderProcessHandler() override {
+ return this;
+ }
+
+ // CefRenderProcessHandler methods.
+ void OnWebKitInitialized() override;
+ void OnBrowserCreated(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefDictionaryValue> extra_info) override;
+ void OnBrowserDestroyed(CefRefPtr<CefBrowser> browser) override;
+ CefRefPtr<CefLoadHandler> GetLoadHandler() override;
+ void OnContextCreated(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefV8Context> context) override;
+ void OnContextReleased(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefV8Context> context) override;
+ void OnUncaughtException(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefV8Context> context,
+ CefRefPtr<CefV8Exception> exception,
+ CefRefPtr<CefV8StackTrace> stackTrace) override;
+ void OnFocusedNodeChanged(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefRefPtr<CefDOMNode> node) override;
+ bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
+ CefRefPtr<CefFrame> frame,
+ CefProcessId source_process,
+ CefRefPtr<CefProcessMessage> message) override;
+
+ private:
+ // Set of supported Delegates.
+ DelegateSet delegates_;
+
+ IMPLEMENT_REFCOUNTING(ClientAppRenderer);
+ DISALLOW_COPY_AND_ASSIGN(ClientAppRenderer);
+};
+
+} // namespace client
+
+#endif // CEF_TESTS_SHARED_RENDERER_CLIENT_APP_RENDERER_H_
diff --git a/tests/shared/resources/osr_test.html b/tests/shared/resources/osr_test.html
new file mode 100644
index 00000000..7cec2d55
--- /dev/null
+++ b/tests/shared/resources/osr_test.html
@@ -0,0 +1,205 @@
+<html>
+ <head><title>OSR Test</title></head>
+ <style>
+ .red_hover:hover {color:red;}
+ #li { width: 530px; }
+ body {background:rgba(255, 0, 0, 0.5); }
+ input {-webkit-appearance: none; }
+ #LI11select {width: 75px;}
+ #LI11select option { background-color: cyan; }
+ .dropdiv {
+ width:50px;
+ height:50px;
+ border:1px solid #aaaaaa;
+ float: left;
+ }
+ #dragdiv {
+ width: 30px;
+ height: 30px;
+ background-color: green;
+ margin: 10px;
+ }
+ #draghere {
+ position: relative;
+ z-index: -1;
+ top: 7px;
+ left: 7px;
+ opacity: 0.4;
+ }
+ #touchdiv, #pointerdiv {
+ width: 100px;
+ height: 50px;
+ background-color: red;
+ float: left;
+ margin-left: 10px;
+ }
+ </style>
+ <script>
+ function getElement(id) { return document.getElementById(id); }
+ function makeH1Red() { getElement('LI00').style.color='red'; }
+ function makeH1Black() { getElement('LI00').style.color='black'; }
+ function navigate() { location.href='?k='+getElement('editbox').value; }
+ function load() {
+ var elems = [];
+ var param = { type: 'ElementBounds', elems: elems };
+
+ elems.push(getElementBounds('LI00'));
+ elems.push(getElementBounds('LI01'));
+ elems.push(getElementBounds('LI02'));
+ elems.push(getElementBounds('LI03'));
+ elems.push(getElementBounds('LI04'));
+ elems.push(getElementBounds('LI05'));
+ elems.push(getElementBounds('LI06'));
+ elems.push(getElementBounds('LI07'));
+ elems.push(getElementBounds('LI08'));
+ elems.push(getElementBounds('LI09'));
+ elems.push(getElementBounds('LI10'));
+ elems.push(getElementBounds('LI11'));
+ elems.push(getElementBounds('LI11select'));
+ elems.push(getElementBounds('email'));
+ elems.push(getElementBounds('quickmenu'));
+ elems.push(getElementBounds('editbox'));
+ elems.push(getElementBounds('btnnavigate'));
+ elems.push(getElementBounds('dropdiv'));
+ elems.push(getElementBounds('dragdiv'));
+ elems.push(getElementBounds('touchdiv'));
+ elems.push(getElementBounds('pointerdiv'));
+
+ if (window.testQuery)
+ window.testQuery({request: JSON.stringify(param)});
+
+ fillDropDown();
+ }
+
+ function fillDropDown() {
+ var select = document.getElementById('LI11select');
+ for (var i = 1; i < 21; i++)
+ select.options.add(new Option('Option ' + i, i));
+ }
+
+ function getElementBounds(id) {
+ var element = document.getElementById(id);
+ var bounds = element.getBoundingClientRect();
+ return {
+ id: id,
+ x: Math.floor(bounds.x),
+ y: Math.floor(bounds.y),
+ width: Math.floor(bounds.width),
+ height: Math.floor(bounds.height)
+ };
+ }
+
+ function onEventTest(event) {
+ var param = 'osr' + event.type;
+
+ if (event.type == "click")
+ param += event.button;
+
+ // Results in a call to the OnQuery method in os_rendering_unittest.cc.
+ if (window.testQuery)
+ window.testQuery({request: param});
+ }
+
+ function onFocusTest(ev) {
+ if (window.testQuery)
+ window.testQuery({request: "osrfocus" + ev.target.id});
+ }
+
+ function allowDrop(ev) {
+ ev.preventDefault();
+ }
+
+ function drag(ev) {
+ ev.dataTransfer.setData("Text",ev.target.id);
+ }
+
+ function drop(ev) {
+ var data=ev.dataTransfer.getData("Text");
+ ev.target.innerHTML = '';
+ var dragged = document.getElementById(data);
+ dragged.setAttribute('draggable', 'false');
+ ev.target.appendChild(dragged);
+ if (window.testQuery)
+ window.testQuery({request: "osrdrop"});
+ }
+
+ function selectText(ev) {
+ var element = ev.target;
+ var selection = window.getSelection();
+ var range = document.createRange();
+ range.selectNodeContents(element);
+ selection.removeAllRanges();
+ selection.addRange(range);
+ }
+
+ function onTouchEvent(ev) {
+ var param = 'osr' + ev.type;
+ // For Touch start also include touch points.
+ if (event.type == "touchstart")
+ param += ev.touches.length;
+ // For Touch Move include the touches that changed.
+ if (event.type == "touchmove")
+ param += ev.changedTouches.length;
+
+ // Results in a call to the OnQuery method in os_rendering_unittest.cc.
+ if (window.testQuery)
+ window.testQuery({request: param});
+ }
+
+ function onPointerEvent(ev) {
+ var param = 'osr' + ev.type + ' ' + ev.pointerType;
+ if (window.testQuery)
+ window.testQuery({request: param});
+ }
+
+ </script>
+ <body onfocus='onEventTest(event)' onblur='onEventTest(event)' onload='load();'>
+ <h1 id='LI00' onclick="onEventTest(event)">
+ OSR Testing h1 - Focus and blur
+ <select id='LI11select'>
+ <option value='0'>Default</option>
+ </select>
+ this page and will get this red black
+ </h1>
+ <ol>
+ <li id='LI01'>OnPaint should be called each time a page loads</li>
+ <li id='LI02' style='cursor:pointer;'><span>Move mouse
+ to require an OnCursorChange call</span></li>
+ <li id='LI03' onmousemove="onEventTest(event)"><span>Hover will color this with
+ red. Will trigger OnPaint once on enter and once on leave</span></li>
+ <li id='LI04'>Right clicking will show contextual menu and will request
+ GetScreenPoint</li>
+ <li id='LI05'>IsWindowRenderingDisabled should be true</li>
+ <li id='LI06'>WasResized should trigger full repaint if size changes.
+ </li>
+ <li id='LI07'>Invalidate should trigger OnPaint once</li>
+ <li id='LI08'>Click and write here with SendKeyEvent to trigger repaints:
+ <input id='editbox' type='text' value='' size="5" onfocus="onFocusTest(event)"></li>
+ <li id='LI09'>Click here with SendMouseClickEvent to navigate:
+ <input id='btnnavigate' type='button' onclick='navigate()'
+ value='Click here to navigate' /></li>
+ <li id='LI10' title='EXPECTED_TOOLTIP'>Mouse over this element will
+ trigger show a tooltip</li>
+ <li id='LI11' onclick='selectText(event)'>SELECTED_TEXT_RANGE</li>
+ <li><input id='email' type='text' size=10 inputmode='email'></li>
+ <li id="quickmenu">Long touch press should trigger quick menu</li>
+ </ol>
+
+ <div class="dropdiv" id="dropdiv" ondrop="drop(event)" ondragover="allowDrop(event)">
+ <span id="draghere">Drag here</span>
+ </div>
+ <div class="dropdiv">
+ <div id="dragdiv" draggable="true" ondragstart="drag(event)"></div>
+ </div>
+ <div id="touchdiv" ontouchstart="onTouchEvent(event)" ontouchend="onTouchEvent(event)" ontouchmove="onTouchEvent(event)" ontouchcancel="onTouchEvent(event)">
+ </div>
+ <div id="pointerdiv" onpointerdown="onPointerEvent(event)" onpointerup="onPointerEvent(event)" onpointermove="onPointerEvent(event)" onpointercancel="onPointerEvent(event)">
+ </div>
+ <br />
+ <br />
+ <br />
+ <br />
+ <br />
+ <br />
+ </body>
+</html>
diff --git a/tests/shared/resources/pdf.html b/tests/shared/resources/pdf.html
new file mode 100644
index 00000000..619b1ce3
--- /dev/null
+++ b/tests/shared/resources/pdf.html
@@ -0,0 +1,9 @@
+<html>
+<head>
+<title>PDF Test</title>
+</head>
+<body bgcolor="white">
+<iframe src="pdf.pdf" width="500" height="500"></iframe>
+<iframe src="pdf.pdf" width="500" height="500"></iframe>
+</body>
+</html>
diff --git a/tests/shared/resources/pdf.pdf b/tests/shared/resources/pdf.pdf
new file mode 100644
index 00000000..1e0dad53
--- /dev/null
+++ b/tests/shared/resources/pdf.pdf
Binary files differ
diff --git a/tests/shared/resources/window_icon.1x.png b/tests/shared/resources/window_icon.1x.png
new file mode 100644
index 00000000..9d28862a
--- /dev/null
+++ b/tests/shared/resources/window_icon.1x.png
Binary files differ
diff --git a/tests/shared/resources/window_icon.2x.png b/tests/shared/resources/window_icon.2x.png
new file mode 100644
index 00000000..59b9d492
--- /dev/null
+++ b/tests/shared/resources/window_icon.2x.png
Binary files differ
diff --git a/tools/automate/automate-git.py b/tools/automate/automate-git.py
new file mode 100644
index 00000000..3817bc6f
--- /dev/null
+++ b/tools/automate/automate-git.py
@@ -0,0 +1,1638 @@
+# Copyright (c) 2014 The Chromium Embedded Framework Authors. All rights
+# reserved. Use of this source code is governed by a BSD-style license that
+# can be found in the LICENSE file.
+
+from __future__ import absolute_import
+from __future__ import print_function
+from datetime import datetime
+import json
+from io import open
+from optparse import OptionParser
+import os
+import re
+import shlex
+import shutil
+import subprocess
+import sys
+import tempfile
+import zipfile
+
+is_python2 = sys.version_info.major == 2
+
+if is_python2:
+ from urllib import FancyURLopener
+ from urllib2 import urlopen
+else:
+ from urllib.request import FancyURLopener, urlopen
+
+##
+# Default URLs.
+##
+
+depot_tools_url = 'https://chromium.googlesource.com/chromium/tools/depot_tools.git'
+depot_tools_archive_url = 'https://storage.googleapis.com/chrome-infra/depot_tools.zip'
+
+cef_git_url = 'https://bitbucket.org/chromiumembedded/cef.git'
+
+chromium_channel_json_url = 'https://omahaproxy.appspot.com/all.json'
+
+##
+# Global system variables.
+##
+
+# Script directory.
+script_dir = os.path.dirname(__file__)
+
+##
+# Helper functions.
+##
+
+
+def msg(message):
+ """ Output a message. """
+ sys.stdout.write('--> ' + message + "\n")
+
+
+def run(command_line, working_dir, depot_tools_dir=None, output_file=None):
+ """ Runs the specified command. """
+ # add depot_tools to the path
+ env = os.environ
+ if not depot_tools_dir is None:
+ env['PATH'] = depot_tools_dir + os.pathsep + env['PATH']
+
+ sys.stdout.write('-------- Running "'+command_line+'" in "'+\
+ working_dir+'"...'+"\n")
+ if not options.dryrun:
+ args = shlex.split(command_line.replace('\\', '\\\\'))
+
+ if not output_file:
+ return subprocess.check_call(
+ args, cwd=working_dir, env=env, shell=(sys.platform == 'win32'))
+ try:
+ msg('Writing %s' % output_file)
+ with open(output_file, 'w', encoding='utf-8') as fp:
+ return subprocess.check_call(
+ args,
+ cwd=working_dir,
+ env=env,
+ shell=(sys.platform == 'win32'),
+ stderr=subprocess.STDOUT,
+ stdout=fp)
+ except subprocess.CalledProcessError:
+ msg('ERROR Run failed. See %s for output.' % output_file)
+ raise
+
+
+def create_directory(path):
+ """ Creates a directory if it doesn't already exist. """
+ if not os.path.exists(path):
+ msg("Creating directory %s" % (path))
+ if not options.dryrun:
+ os.makedirs(path)
+
+
+def delete_directory(path):
+ """ Removes an existing directory. """
+ if os.path.exists(path):
+ msg("Removing directory %s" % (path))
+ if not options.dryrun:
+ shutil.rmtree(path, onerror=onerror)
+
+
+def copy_directory(source, target, allow_overwrite=False):
+ """ Copies a directory from source to target. """
+ if not options.dryrun and os.path.exists(target):
+ if not allow_overwrite:
+ raise Exception("Directory %s already exists" % (target))
+ remove_directory(target)
+ if os.path.exists(source):
+ msg("Copying directory %s to %s" % (source, target))
+ if not options.dryrun:
+ shutil.copytree(source, target)
+
+
+def move_directory(source, target, allow_overwrite=False):
+ """ Copies a directory from source to target. """
+ if not options.dryrun and os.path.exists(target):
+ if not allow_overwrite:
+ raise Exception("Directory %s already exists" % (target))
+ remove_directory(target)
+ if os.path.exists(source):
+ msg("Moving directory %s to %s" % (source, target))
+ if not options.dryrun:
+ shutil.move(source, target)
+
+
+def is_git_checkout(path):
+ """ Returns true if the path represents a git checkout. """
+ return os.path.exists(os.path.join(path, '.git'))
+
+
+def exec_cmd(cmd, path):
+ """ Execute the specified command and return the result. """
+ out = ''
+ err = ''
+ sys.stdout.write("-------- Running \"%s\" in \"%s\"...\n" % (cmd, path))
+ parts = cmd.split()
+ try:
+ process = subprocess.Popen(
+ parts,
+ cwd=path,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ shell=(sys.platform == 'win32'))
+ out, err = process.communicate()
+ except IOError as e:
+ (errno, strerror) = e.args
+ raise
+ except:
+ raise
+ return {'out': out.decode('utf-8'), 'err': err.decode('utf-8')}
+
+
+def get_git_hash(path, branch):
+ """ Returns the git hash for the specified branch/tag/hash. """
+ cmd = "%s rev-parse %s" % (git_exe, branch)
+ result = exec_cmd(cmd, path)
+ if result['out'] != '':
+ return result['out'].strip()
+ return 'Unknown'
+
+
+def get_git_date(path, branch):
+ """ Returns the date for the specified branch/tag/hash. """
+ cmd = "%s show -s --format=%%ct %s" % (git_exe, branch)
+ result = exec_cmd(cmd, path)
+ if result['out'] != '':
+ return datetime.utcfromtimestamp(
+ int(result['out'].strip())).strftime('%Y-%m-%d %H:%M:%S UTC')
+ return 'Unknown'
+
+
+def get_git_url(path):
+ """ Returns the origin url for the specified path. """
+ cmd = "%s config --get remote.origin.url" % (git_exe)
+ result = exec_cmd(cmd, path)
+ if result['out'] != '':
+ return result['out'].strip()
+ return 'Unknown'
+
+
+def download_and_extract(src, target):
+ """ Extracts the contents of src, which may be a URL or local file, to the
+ target directory. """
+ temporary = False
+
+ if src[:4] == 'http':
+ # Attempt to download a URL.
+ opener = FancyURLopener({})
+ response = opener.open(src)
+
+ temporary = True
+ handle, archive_path = tempfile.mkstemp(suffix='.zip')
+ os.write(handle, response.read())
+ os.close(handle)
+ elif os.path.exists(src):
+ # Use a local file.
+ archive_path = src
+ else:
+ raise Exception('Path type is unsupported or does not exist: ' + src)
+
+ if not zipfile.is_zipfile(archive_path):
+ raise Exception('Not a valid zip archive: ' + src)
+
+ # Attempt to extract the archive file.
+ try:
+ os.makedirs(target)
+ zf = zipfile.ZipFile(archive_path, 'r')
+ zf.extractall(target)
+ except:
+ shutil.rmtree(target, onerror=onerror)
+ raise
+ zf.close()
+
+ # Delete the archive file if temporary.
+ if temporary and os.path.exists(archive_path):
+ os.remove(archive_path)
+
+
+def read_file(path):
+ """ Read a file. """
+ if os.path.exists(path):
+ with open(path, 'r', encoding='utf-8') as fp:
+ return fp.read()
+ else:
+ raise Exception("Path does not exist: %s" % (path))
+
+
+def write_fp(fp, data):
+ if is_python2:
+ fp.write(data.decode('utf-8'))
+ else:
+ fp.write(data)
+
+
+def write_file(path, data):
+ """ Write a file. """
+ msg('Writing %s' % path)
+ if not options.dryrun:
+ with open(path, 'w', encoding='utf-8') as fp:
+ write_fp(fp, data)
+
+
+def read_config_file(path):
+ """ Read a configuration file. """
+ # Parse the contents.
+ return eval(read_file(path), {'__builtins__': None}, None)
+
+
+def write_config_file(path, contents):
+ """ Write a configuration file. """
+ data = "{\n"
+ for key in sorted(contents.keys()):
+ data += " '%s': '%s',\n" % (key, contents[key])
+ data += "}\n"
+ write_file(path, data)
+
+
+def read_branch_config_file(path):
+ """ Read the CEF branch from the specified path. """
+ config_file = os.path.join(path, 'cef.branch')
+ if os.path.isfile(config_file):
+ contents = read_config_file(config_file)
+ if 'branch' in contents:
+ return contents['branch']
+ return ''
+
+
+def write_branch_config_file(path, branch):
+ """ Write the CEF branch to the specified path. """
+ config_file = os.path.join(path, 'cef.branch')
+ if not os.path.isfile(config_file):
+ write_config_file(config_file, {'branch': branch})
+
+
+def apply_patch(name):
+ patch_file = os.path.join(cef_dir, 'patch', 'patches', name)
+ if os.path.exists(patch_file + ".patch"):
+ # Attempt to apply the patch file.
+ patch_tool = os.path.join(cef_dir, 'tools', 'patcher.py')
+ run('%s %s --patch-file "%s" --patch-dir "%s"' %
+ (python_exe, patch_tool, patch_file,
+ chromium_src_dir), chromium_src_dir, depot_tools_dir)
+
+
+def apply_deps_patch():
+ """ Patch the Chromium DEPS file before `gclient sync` if necessary. """
+ deps_path = os.path.join(chromium_src_dir, deps_file)
+ if os.path.isfile(deps_path):
+ msg("Chromium DEPS file: %s" % (deps_path))
+ apply_patch(deps_file)
+ else:
+ raise Exception("Path does not exist: %s" % (deps_path))
+
+
+def apply_runhooks_patch():
+ """ Patch the Chromium runhooks files before `gclient runhooks` if necessary. """
+ apply_patch('runhooks')
+
+
+def run_patch_updater(args='', output_file=None):
+ """ Run the patch updater script. """
+ tool = os.path.join(cef_src_dir, 'tools', 'patch_updater.py')
+ if len(args) > 0:
+ args = ' ' + args
+ run('%s %s%s' % (python_exe, tool, args), cef_src_dir, depot_tools_dir,
+ output_file)
+
+
+def onerror(func, path, exc_info):
+ """
+ Error handler for ``shutil.rmtree``.
+
+ If the error is due to an access error (read only file)
+ it attempts to add write permission and then retries.
+
+ If the error is for another reason it re-raises the error.
+
+ Usage : ``shutil.rmtree(path, onerror=onerror)``
+ """
+ import stat
+ if not os.access(path, os.W_OK):
+ # Is the error an access error ?
+ os.chmod(path, stat.S_IWUSR)
+ func(path)
+ else:
+ raise
+
+
+def read_json_url(url):
+ """ Read a JSON URL. """
+ msg('Downloading %s' % url)
+ return json.loads(urlopen(url).read())
+
+
+g_channel_data = None
+
+
+def get_chromium_channel_data(os, channel, param=None):
+ """ Returns all data for the specified Chromium channel. """
+ global g_channel_data
+
+ if g_channel_data is None:
+ g_channel_data = read_json_url(chromium_channel_json_url)
+ assert len(g_channel_data) > 0, 'Failed to load Chromium channel data'
+
+ for oses in g_channel_data:
+ if oses['os'] == os:
+ for version in oses['versions']:
+ if version['channel'] == channel:
+ assert version['os'] == os
+ assert version['channel'] == channel
+ if param is None:
+ return version
+ else:
+ assert param in version, 'Missing parameter %s for Chromium channel %s %s' % (
+ param, os, channel)
+ return version[param]
+ raise Exception("Invalid Chromium channel value: %s" % channel)
+ raise Exception("Invalid Chromium os value: %s" % os)
+
+
+def get_chromium_channel_commit(os, channel):
+ """ Returns the current branch commit for the specified Chromium channel. """
+ return get_chromium_channel_data(os, channel, 'branch_commit')
+
+
+def get_chromium_channel_version(os, channel):
+ """ Returns the current version for the specified Chromium channel. """
+ return get_chromium_channel_data(os, channel, 'current_version')
+
+
+def get_chromium_main_position(commit):
+ """ Returns the closest main position for the specified Chromium commit. """
+ # Using -2 because a "Publish DEPS" commit which does not have a master
+ # position may be first.
+ cmd = "%s log -2 %s" % (git_exe, commit)
+ result = exec_cmd(cmd, chromium_src_dir)
+ if result['out'] != '':
+ match = re.search(r'refs/heads/(?:master|main)@{#([\d]+)}', result['out'])
+ assert match != None, 'Failed to find position'
+ return int(match.groups()[0])
+ return None
+
+
+def get_chromium_main_commit(position):
+ """ Returns the main commit for the specified Chromium commit position. """
+ cmd = '%s log -1 --grep=refs/heads/master@{#%s} --grep=refs/heads/main@{#%s} origin/main' % (
+ git_exe, str(position), str(position))
+ result = exec_cmd(cmd, chromium_src_dir)
+ if result['out'] != '':
+ match = re.search(r'^commit ([a-f0-9]+)', result['out'])
+ assert match != None, 'Failed to find commit'
+ return match.groups()[0]
+ return None
+
+
+def get_chromium_versions(commit):
+ """ Returns the list of Chromium versions that contain the specified commit.
+ Versions are listed oldest to newest. """
+ cmd = '%s tag --contains %s' % (git_exe, commit)
+ result = exec_cmd(cmd, chromium_src_dir)
+ if result['out'] != '':
+ return [line.strip() for line in result['out'].strip().split('\n')]
+ return None
+
+
+def get_build_compat_versions():
+ """ Returns the compatible Chromium and (optionally) depot_tools versions
+ specified by the CEF checkout. """
+ compat_path = os.path.join(cef_dir, 'CHROMIUM_BUILD_COMPATIBILITY.txt')
+ msg("Reading %s" % compat_path)
+ config = read_config_file(compat_path)
+
+ if not 'chromium_checkout' in config:
+ raise Exception("Missing chromium_checkout value in %s" % (compat_path))
+ return config
+
+
+def get_chromium_target_version(os='win', channel='canary', target_distance=0):
+ """ Returns the target Chromium version based on a heuristic. """
+ # The current compatible version from CEF.
+ compat_version = chromium_compat_version
+ compat_commit = get_git_hash(chromium_src_dir, compat_version)
+ if compat_version == compat_commit:
+ versions = get_chromium_versions(compat_commit)
+ if len(versions) > 0:
+ compat_version = 'refs/tags/' + versions[0]
+ # Closest version may not align with the compat position, so adjust the
+ # commit to match.
+ compat_commit = get_git_hash(chromium_src_dir, compat_version)
+ compat_position = get_chromium_main_position(compat_commit)
+ compat_date = get_git_date(chromium_src_dir, compat_commit)
+
+ # The most recent channel version from the Chromium website.
+ channel_version = 'refs/tags/' + get_chromium_channel_version(os, channel)
+ channel_commit = get_chromium_channel_commit(os, channel)
+ channel_position = get_chromium_main_position(channel_commit)
+ channel_date = get_git_date(chromium_src_dir, channel_commit)
+
+ if compat_position >= channel_position:
+ # Already compatible with the channel version or newer.
+ target_version = compat_version
+ target_commit = compat_commit
+ target_position = compat_position
+ target_date = compat_date
+ elif target_distance <= 0 or compat_position + target_distance >= channel_position:
+ # Channel version is within the target distance.
+ target_version = channel_version
+ target_commit = channel_commit
+ target_position = channel_position
+ target_date = channel_date
+ else:
+ # Find an intermediary version that's within the target distance.
+ target_position = compat_position + target_distance
+ target_commit = get_chromium_main_commit(target_position)
+ versions = get_chromium_versions(target_commit)
+ if len(versions) > 0:
+ target_version = 'refs/tags/' + versions[0]
+ # Closest version may not align with the target position, so adjust the
+ # commit and position to match.
+ target_commit = get_git_hash(chromium_src_dir, target_version)
+ target_position = get_chromium_main_position(target_commit)
+ else:
+ target_version = target_commit
+ target_date = get_git_date(chromium_src_dir, target_commit)
+
+ msg("")
+ msg("Computed Chromium update for %s %s at distance %d" % (os, channel,
+ target_distance))
+ msg("Compat: %s %s %s (#%d)" % (compat_date, compat_version, compat_commit,
+ compat_position))
+ msg("Target: %s %s %s (#%d)" % (target_date, target_version, target_commit,
+ target_position))
+ msg("Channel: %s %s %s (#%d)" % (channel_date, channel_version,
+ channel_commit, channel_position))
+ msg("")
+
+ return target_version
+
+
+def get_build_directory_name(is_debug):
+ build_dir = ('Debug' if is_debug else 'Release') + '_'
+
+ # CEF uses a consistent directory naming scheme for GN via
+ # GetAllPlatformConfigs in tools/gn_args.py.
+ if options.x64build:
+ build_dir += 'GN_x64'
+ elif options.armbuild:
+ build_dir += 'GN_arm'
+ elif options.arm64build:
+ build_dir += 'GN_arm64'
+ else:
+ build_dir += 'GN_x86'
+ return build_dir
+
+
+def read_update_file():
+ update_path = os.path.join(cef_src_dir, 'CHROMIUM_UPDATE.txt')
+ if not os.path.exists(update_path):
+ msg("Missing file: %s" % update_path)
+ return None
+
+ msg("Reading %s" % update_path)
+ return read_config_file(update_path)
+
+
+def log_chromium_changes():
+ """ Evaluate the Chromium checkout for changes. """
+ config = read_update_file()
+ if config is None:
+ msg("Skipping Chromium changes log.")
+ return
+
+ if 'files' in config:
+ out_file = os.path.join(download_dir, 'chromium_update_changes.diff')
+ if os.path.exists(out_file):
+ os.remove(out_file)
+
+ old_commit = get_chromium_main_commit(
+ get_chromium_main_position(chromium_compat_version))
+ new_commit = get_chromium_main_commit(
+ get_chromium_main_position(chromium_checkout))
+
+ cmd = '%s diff --relative --no-prefix %s..%s -- %s' % (
+ git_exe, old_commit, new_commit, ' '.join(config['files']))
+ result = exec_cmd(cmd, chromium_src_dir)
+ if result['out'] != '':
+ write_file(out_file, result['out'])
+
+
+def check_pattern_matches(output_file=None):
+ """ Evaluate the Chromium checkout for pattern matches. """
+ config = read_update_file()
+ if config is None:
+ msg("Skipping Chromium pattern matching.")
+ return
+
+ if 'patterns' in config:
+ if output_file is None:
+ fp = sys.stdout
+ else:
+ msg('Writing %s' % output_file)
+ fp = open(output_file, 'w', encoding='utf-8')
+
+ has_output = False
+ for entry in config['patterns']:
+ msg("Evaluating pattern: %s" % entry['pattern'])
+
+ # Read patterns from a file to avoid formatting problems.
+ pattern_handle, pattern_file = tempfile.mkstemp()
+ os.write(pattern_handle, entry['pattern'])
+ os.close(pattern_handle)
+
+ cmd = '%s grep -n -f %s' % (git_exe, pattern_file)
+ result = exec_cmd(cmd, chromium_src_dir)
+ os.remove(pattern_file)
+
+ if result['out'] != '':
+ write_msg = True
+ re_exclude = re.compile(
+ entry['exclude_matches']) if 'exclude_matches' in entry else None
+
+ for line in result['out'].split('\n'):
+ line = line.strip()
+ if len(line) == 0:
+ continue
+ skip = not re_exclude is None and re_exclude.match(line) != None
+ if not skip:
+ if write_msg:
+ if has_output:
+ write_fp(fp, '\n')
+ write_fp(fp,
+ '!!!! WARNING: FOUND PATTERN: %s\n' % entry['pattern'])
+ if 'message' in entry:
+ write_fp(fp, entry['message'] + '\n')
+ write_fp(fp, '\n')
+ write_msg = False
+ write_fp(fp, line + '\n')
+ has_output = True
+
+ if not output_file is None:
+ if has_output:
+ msg('ERROR Matches found. See %s for output.' % out_file)
+ else:
+ write_fp(fp, 'Good news! No matches.\n')
+ fp.close()
+
+ if has_output:
+ # Don't continue when we know the build will be wrong.
+ sys.exit(1)
+
+
+##
+# Program entry point.
+##
+
+# Cannot be loaded as a module.
+if __name__ != "__main__":
+ sys.stderr.write('This file cannot be loaded as a module!')
+ sys.exit(1)
+
+# Parse command-line options.
+disc = """
+This utility implements automation for the download, update, build and
+distribution of CEF.
+"""
+
+parser = OptionParser(description=disc)
+
+# Setup options.
+parser.add_option(
+ '--download-dir',
+ dest='downloaddir',
+ metavar='DIR',
+ help='Download directory with no spaces [required].')
+parser.add_option(
+ '--depot-tools-dir',
+ dest='depottoolsdir',
+ metavar='DIR',
+ help='Download directory for depot_tools.',
+ default='')
+parser.add_option('--depot-tools-archive', dest='depottoolsarchive',
+ help='Zip archive file that contains a single top-level '+\
+ 'depot_tools directory.', default='')
+parser.add_option('--branch', dest='branch',
+ help='Branch of CEF to build (master, 3987, ...). This '+\
+ 'will be used to name the CEF download directory and '+\
+ 'to identify the correct URL if --url is not '+\
+ 'specified. The default value is master.',
+ default='master')
+parser.add_option('--url', dest='url',
+ help='CEF download URL. If not specified the default URL '+\
+ 'will be used.',
+ default='')
+parser.add_option('--chromium-url', dest='chromiumurl',
+ help='Chromium download URL. If not specified the default '+\
+ 'URL will be used.',
+ default='')
+parser.add_option('--checkout', dest='checkout',
+ help='Version of CEF to checkout. If not specified the '+\
+ 'most recent remote version of the branch will be used.',
+ default='')
+parser.add_option('--chromium-checkout', dest='chromiumcheckout',
+ help='Version of Chromium to checkout (Git '+\
+ 'branch/hash/tag). This overrides the value specified '+\
+ 'by CEF in CHROMIUM_BUILD_COMPATIBILITY.txt.',
+ default='')
+parser.add_option('--chromium-channel', dest='chromiumchannel',
+ help='Chromium channel to check out (canary, dev, beta or '+\
+ 'stable). This overrides the value specified by CEF '+\
+ 'in CHROMIUM_BUILD_COMPATIBILITY.txt.',
+ default='')
+parser.add_option('--chromium-channel-distance', dest='chromiumchanneldistance',
+ help='The target number of commits to step in the '+\
+ 'channel, or 0 to use the newest channel version. '+\
+ 'Used in combination with --chromium-channel.',
+ default='')
+
+# Miscellaneous options.
+parser.add_option(
+ '--force-config',
+ action='store_true',
+ dest='forceconfig',
+ default=False,
+ help='Force creation of a new gclient config file.')
+parser.add_option('--force-clean',
+ action='store_true', dest='forceclean', default=False,
+ help='Force a clean checkout of Chromium and CEF. This will'+\
+ ' trigger a new update, build and distribution.')
+parser.add_option('--force-clean-deps',
+ action='store_true', dest='forcecleandeps', default=False,
+ help='Force a clean checkout of Chromium dependencies. Used'+\
+ ' in combination with --force-clean.')
+parser.add_option(
+ '--dry-run',
+ action='store_true',
+ dest='dryrun',
+ default=False,
+ help="Output commands without executing them.")
+parser.add_option('--dry-run-platform', dest='dryrunplatform', default=None,
+ help='Simulate a dry run on the specified platform '+\
+ '(windows, mac, linux). Must be used in combination'+\
+ ' with the --dry-run flag.')
+
+# Update-related options.
+parser.add_option('--force-update',
+ action='store_true', dest='forceupdate', default=False,
+ help='Force a Chromium and CEF update. This will trigger a '+\
+ 'new build and distribution.')
+parser.add_option('--no-update',
+ action='store_true', dest='noupdate', default=False,
+ help='Do not update Chromium or CEF. Pass --force-build or '+\
+ '--force-distrib if you desire a new build or '+\
+ 'distribution.')
+parser.add_option('--no-cef-update',
+ action='store_true', dest='nocefupdate', default=False,
+ help='Do not update CEF. Pass --force-build or '+\
+ '--force-distrib if you desire a new build or '+\
+ 'distribution.')
+parser.add_option('--force-cef-update',
+ action='store_true', dest='forcecefupdate', default=False,
+ help='Force a CEF update. This will cause local changes in '+\
+ 'the CEF checkout to be discarded and patch files to '+\
+ 'be reapplied.')
+parser.add_option(
+ '--no-chromium-update',
+ action='store_true',
+ dest='nochromiumupdate',
+ default=False,
+ help='Do not update Chromium.')
+parser.add_option(
+ '--no-depot-tools-update',
+ action='store_true',
+ dest='nodepottoolsupdate',
+ default=False,
+ help='Do not update depot_tools.')
+parser.add_option('--fast-update',
+ action='store_true', dest='fastupdate', default=False,
+ help='Update existing Chromium/CEF checkouts for fast incremental '+\
+ 'builds by attempting to minimize the number of modified files. '+\
+ 'The update will fail if there are unstaged CEF changes or if '+\
+ 'Chromium changes are not included in a patch file.')
+parser.add_option(
+ '--force-patch-update',
+ action='store_true',
+ dest='forcepatchupdate',
+ default=False,
+ help='Force update of patch files.')
+parser.add_option(
+ '--resave',
+ action='store_true',
+ dest='resave',
+ default=False,
+ help='Resave patch files.')
+parser.add_option(
+ '--log-chromium-changes',
+ action='store_true',
+ dest='logchromiumchanges',
+ default=False,
+ help='Create a log of the Chromium changes.')
+
+# Build-related options.
+parser.add_option('--force-build',
+ action='store_true', dest='forcebuild', default=False,
+ help='Force CEF debug and release builds. This builds '+\
+ '[build-target] on all platforms and chrome_sandbox '+\
+ 'on Linux.')
+parser.add_option(
+ '--no-build',
+ action='store_true',
+ dest='nobuild',
+ default=False,
+ help='Do not build CEF.')
+parser.add_option(
+ '--build-target',
+ dest='buildtarget',
+ default='cefclient',
+ help='Target name(s) to build (defaults to "cefclient").')
+parser.add_option(
+ '--build-tests',
+ action='store_true',
+ dest='buildtests',
+ default=False,
+ help='Also build the test target specified via --test-target.')
+parser.add_option(
+ '--no-debug-build',
+ action='store_true',
+ dest='nodebugbuild',
+ default=False,
+ help="Don't perform the CEF debug build.")
+parser.add_option(
+ '--no-release-build',
+ action='store_true',
+ dest='noreleasebuild',
+ default=False,
+ help="Don't perform the CEF release build.")
+parser.add_option(
+ '--verbose-build',
+ action='store_true',
+ dest='verbosebuild',
+ default=False,
+ help='Show all command lines while building.')
+parser.add_option(
+ '--build-failure-limit',
+ dest='buildfailurelimit',
+ default=1,
+ type="int",
+ help='Keep going until N jobs fail.')
+parser.add_option('--build-log-file',
+ action='store_true', dest='buildlogfile', default=False,
+ help='Write build logs to file. The file will be named '+\
+ '"build-[branch]-[debug|release].log" in the download '+\
+ 'directory.')
+parser.add_option(
+ '--x64-build',
+ action='store_true',
+ dest='x64build',
+ default=False,
+ help='Create a 64-bit build.')
+parser.add_option(
+ '--arm-build',
+ action='store_true',
+ dest='armbuild',
+ default=False,
+ help='Create an ARM build.')
+parser.add_option(
+ '--arm64-build',
+ action='store_true',
+ dest='arm64build',
+ default=False,
+ help='Create an ARM64 build.')
+parser.add_option(
+ '--with-pgo-profiles',
+ action='store_true',
+ dest='withpgoprofiles',
+ default=False,
+ help='Download PGO profiles for the build.')
+
+# Test-related options.
+parser.add_option(
+ '--run-tests',
+ action='store_true',
+ dest='runtests',
+ default=False,
+ help='Run the ceftests target.')
+parser.add_option(
+ '--no-debug-tests',
+ action='store_true',
+ dest='nodebugtests',
+ default=False,
+ help="Don't run debug build tests.")
+parser.add_option(
+ '--no-release-tests',
+ action='store_true',
+ dest='noreleasetests',
+ default=False,
+ help="Don't run release build tests.")
+parser.add_option(
+ '--test-target',
+ dest='testtarget',
+ default='ceftests',
+ help='Test target name to build (defaults to "ceftests").')
+parser.add_option(
+ '--test-prefix',
+ dest='testprefix',
+ default='',
+ help='Prefix for running the test executable (e.g. `xvfb-run` on Linux).')
+parser.add_option(
+ '--test-args',
+ dest='testargs',
+ default='',
+ help='Arguments that will be passed to the test executable.')
+
+# Distribution-related options.
+parser.add_option(
+ '--force-distrib',
+ action='store_true',
+ dest='forcedistrib',
+ default=False,
+ help='Force creation of a CEF binary distribution.')
+parser.add_option(
+ '--no-distrib',
+ action='store_true',
+ dest='nodistrib',
+ default=False,
+ help="Don't create a CEF binary distribution.")
+parser.add_option(
+ '--minimal-distrib',
+ action='store_true',
+ dest='minimaldistrib',
+ default=False,
+ help='Create a minimal CEF binary distribution.')
+parser.add_option(
+ '--minimal-distrib-only',
+ action='store_true',
+ dest='minimaldistribonly',
+ default=False,
+ help='Create a minimal CEF binary distribution only.')
+parser.add_option(
+ '--client-distrib',
+ action='store_true',
+ dest='clientdistrib',
+ default=False,
+ help='Create a client CEF binary distribution.')
+parser.add_option(
+ '--client-distrib-only',
+ action='store_true',
+ dest='clientdistribonly',
+ default=False,
+ help='Create a client CEF binary distribution only.')
+parser.add_option(
+ '--sandbox-distrib',
+ action='store_true',
+ dest='sandboxdistrib',
+ default=False,
+ help='Create a cef_sandbox static library distribution.')
+parser.add_option(
+ '--sandbox-distrib-only',
+ action='store_true',
+ dest='sandboxdistribonly',
+ default=False,
+ help='Create a cef_sandbox static library distribution only.')
+parser.add_option(
+ '--no-distrib-docs',
+ action='store_true',
+ dest='nodistribdocs',
+ default=False,
+ help="Don't create CEF documentation.")
+parser.add_option(
+ '--no-distrib-archive',
+ action='store_true',
+ dest='nodistribarchive',
+ default=False,
+ help="Don't create archives for output directories.")
+parser.add_option(
+ '--clean-artifacts',
+ action='store_true',
+ dest='cleanartifacts',
+ default=False,
+ help='Clean the artifacts output directory.')
+parser.add_option(
+ '--distrib-subdir',
+ dest='distribsubdir',
+ default='',
+ help='CEF distrib dir name, child of chromium/src/cef/binary_distrib')
+parser.add_option(
+ '--distrib-subdir-suffix',
+ dest='distribsubdirsuffix',
+ default='',
+ help='CEF distrib dir name suffix, child of chromium/src/cef/binary_distrib'
+)
+
+(options, args) = parser.parse_args()
+
+if options.downloaddir is None:
+ print("The --download-dir option is required.")
+ parser.print_help(sys.stderr)
+ sys.exit(1)
+
+# Opt into component-specific flags for later use.
+if options.noupdate:
+ options.nocefupdate = True
+ options.nochromiumupdate = True
+ options.nodepottoolsupdate = True
+
+if options.runtests:
+ options.buildtests = True
+
+if (options.nochromiumupdate and options.forceupdate) or \
+ (options.nocefupdate and options.forceupdate) or \
+ (options.nobuild and options.forcebuild) or \
+ (options.nodistrib and options.forcedistrib) or \
+ ((options.forceclean or options.forcecleandeps) and options.fastupdate) or \
+ (options.chromiumcheckout and options.chromiumchannel):
+ print("Invalid combination of options.")
+ parser.print_help(sys.stderr)
+ sys.exit(1)
+
+if (options.noreleasebuild and \
+ (options.minimaldistrib or options.minimaldistribonly or \
+ options.clientdistrib or options.clientdistribonly)) or \
+ (options.minimaldistribonly + options.clientdistribonly + options.sandboxdistribonly > 1):
+ print('Invalid combination of options.')
+ parser.print_help(sys.stderr)
+ sys.exit(1)
+
+if options.x64build + options.armbuild + options.arm64build > 1:
+ print('Invalid combination of options.')
+ parser.print_help(sys.stderr)
+ sys.exit(1)
+
+if (options.buildtests or options.runtests) and len(options.testtarget) == 0:
+ print("A test target must be specified via --test-target.")
+ parser.print_help(sys.stderr)
+ sys.exit(1)
+
+# Operating system.
+if options.dryrun and options.dryrunplatform is not None:
+ platform = options.dryrunplatform
+ if not platform in ['windows', 'mac', 'linux']:
+ print('Invalid dry-run-platform value: %s' % (platform))
+ sys.exit(1)
+elif sys.platform == 'win32':
+ platform = 'windows'
+elif sys.platform == 'darwin':
+ platform = 'mac'
+elif sys.platform.startswith('linux'):
+ platform = 'linux'
+else:
+ print('Unknown operating system platform')
+ sys.exit(1)
+
+if options.clientdistrib or options.clientdistribonly:
+ if platform == 'linux' or (platform == 'windows' and options.arm64build):
+ client_app = 'cefsimple'
+ else:
+ client_app = 'cefclient'
+ if options.buildtarget.find(client_app) == -1:
+ print('A client distribution cannot be generated if --build-target ' +
+ 'excludes %s.' % client_app)
+ parser.print_help(sys.stderr)
+ sys.exit(1)
+
+# CEF branch.
+cef_branch = options.branch
+
+branch_is_master = (cef_branch == 'master' or cef_branch == 'trunk')
+if not branch_is_master:
+ # Verify that the branch value is numeric.
+ if not cef_branch.isdigit():
+ print('Invalid branch value: %s' % cef_branch)
+ sys.exit(1)
+
+ # Verify the minimum supported branch number.
+ if int(cef_branch) < 3071:
+ print('The requested branch (%s) is too old to build using this tool. ' +
+ 'The minimum supported branch is 3071.' % cef_branch)
+ sys.exit(1)
+
+# True if the requested branch is 3538 or newer.
+branch_is_3538_or_newer = (branch_is_master or int(cef_branch) >= 3538)
+
+# True if the requested branch is 3945 or newer.
+branch_is_3945_or_newer = (branch_is_master or int(cef_branch) >= 3945)
+
+# Enable Python 3 usage in Chromium for branches 3945 and newer.
+if branch_is_3945_or_newer and not is_python2 and \
+ not 'GCLIENT_PY3' in os.environ.keys():
+ os.environ['GCLIENT_PY3'] = '1'
+
+if not branch_is_3945_or_newer and \
+ (not is_python2 or bool(int(os.environ.get('GCLIENT_PY3', '0')))):
+ print('Python 3 is not supported with branch 3904 and older ' +
+ '(set GCLIENT_PY3=0 and run with Python 2 executable).')
+ sys.exit(1)
+
+if options.armbuild:
+ if platform != 'linux':
+ print('The ARM build option is only supported on Linux.')
+ sys.exit(1)
+
+deps_file = 'DEPS'
+
+if platform == 'mac' and not (options.x64build or options.arm64build):
+ print('32-bit MacOS builds are not supported. ' +
+ 'Add --x64-build or --arm64-build flag to generate a 64-bit build.')
+ sys.exit(1)
+
+# Platforms that build a cef_sandbox library.
+sandbox_lib_platforms = ['windows']
+if branch_is_3538_or_newer:
+ sandbox_lib_platforms.append('mac')
+
+if not platform in sandbox_lib_platforms and (options.sandboxdistrib or
+ options.sandboxdistribonly):
+ print('The sandbox distribution is not supported on this platform.')
+ sys.exit(1)
+
+# Options that force the sources to change.
+force_change = options.forceclean or options.forceupdate
+
+# Options that cause local changes to be discarded.
+discard_local_changes = force_change or options.forcecefupdate
+
+if options.resave and (options.forcepatchupdate or discard_local_changes):
+ print('--resave cannot be combined with options that modify or discard ' +
+ 'patches.')
+ parser.print_help(sys.stderr)
+ sys.exit(1)
+
+if platform == 'windows':
+ # Avoid errors when the "vs_toolchain.py update" Chromium hook runs.
+ os.environ['DEPOT_TOOLS_WIN_TOOLCHAIN'] = '0'
+
+download_dir = os.path.abspath(options.downloaddir)
+chromium_dir = os.path.join(download_dir, 'chromium')
+chromium_src_dir = os.path.join(chromium_dir, 'src')
+out_src_dir = os.path.join(chromium_src_dir, 'out')
+cef_src_dir = os.path.join(chromium_src_dir, 'cef')
+
+if options.fastupdate and os.path.exists(cef_src_dir):
+ cef_dir = cef_src_dir
+else:
+ cef_dir = os.path.join(download_dir, 'cef')
+
+##
+# Manage the download directory.
+##
+
+# Create the download directory if necessary.
+create_directory(download_dir)
+
+msg("Download Directory: %s" % (download_dir))
+
+##
+# Manage the depot_tools directory.
+##
+
+# Check if the depot_tools directory exists.
+if options.depottoolsdir != '':
+ depot_tools_dir = os.path.abspath(options.depottoolsdir)
+else:
+ depot_tools_dir = os.path.join(download_dir, 'depot_tools')
+
+msg("Depot Tools Directory: %s" % (depot_tools_dir))
+
+if not os.path.exists(depot_tools_dir):
+ if platform == 'windows' and options.depottoolsarchive == '':
+ # On Windows download depot_tools as an archive file since we can't assume
+ # that git is already installed.
+ options.depottoolsarchive = depot_tools_archive_url
+
+ if options.depottoolsarchive != '':
+ # Extract depot_tools from an archive file.
+ msg('Extracting %s to %s.' % \
+ (options.depottoolsarchive, depot_tools_dir))
+ if not options.dryrun:
+ download_and_extract(options.depottoolsarchive, depot_tools_dir)
+ else:
+ # On Linux and OS X check out depot_tools using Git.
+ run('git clone ' + depot_tools_url + ' ' + depot_tools_dir, download_dir)
+
+if not options.nodepottoolsupdate:
+ # Update depot_tools.
+ # On Windows this will download required python and git binaries.
+ msg('Updating depot_tools')
+ if platform == 'windows':
+ run('update_depot_tools.bat', depot_tools_dir, depot_tools_dir)
+ else:
+ run('update_depot_tools', depot_tools_dir, depot_tools_dir)
+
+# Determine the executables to use.
+if platform == 'windows':
+ # Force use of the version bundled with depot_tools.
+ git_exe = os.path.join(depot_tools_dir, 'git.bat')
+ python_bat = 'python.bat' if is_python2 else 'python3.bat'
+ python_exe = os.path.join(depot_tools_dir, python_bat)
+ if options.dryrun and not os.path.exists(git_exe):
+ sys.stdout.write("WARNING: --dry-run assumes that depot_tools" \
+ " is already in your PATH. If it isn't\nplease" \
+ " specify a --depot-tools-dir value.\n")
+ git_exe = 'git.bat'
+ python_exe = python_bat
+else:
+ git_exe = 'git'
+ python_exe = sys.executable
+
+##
+# Manage the cef directory.
+##
+
+# Delete the existing CEF directory if requested.
+if options.forceclean and os.path.exists(cef_dir):
+ delete_directory(cef_dir)
+
+# Determine the type of CEF checkout to use.
+if os.path.exists(cef_dir) and not is_git_checkout(cef_dir):
+ raise Exception("Not a valid CEF Git checkout: %s" % (cef_dir))
+
+# Determine the CEF download URL to use.
+cef_url = options.url.strip()
+if cef_url == '':
+ cef_url = cef_git_url
+
+# Verify that the requested CEF URL matches the existing checkout.
+if not options.nocefupdate and os.path.exists(cef_dir):
+ cef_existing_url = get_git_url(cef_dir)
+ if cef_url != cef_existing_url:
+ raise Exception(
+ 'Requested CEF checkout URL %s does not match existing URL %s' %
+ (cef_url, cef_existing_url))
+
+msg("CEF Branch: %s" % (cef_branch))
+msg("CEF URL: %s" % (cef_url))
+msg("CEF Source Directory: %s" % (cef_dir))
+
+# Determine the CEF Git branch to use.
+if options.checkout == '':
+ # Target the most recent branch commit from the remote repo.
+ if branch_is_master:
+ cef_checkout = 'origin/master'
+ else:
+ cef_checkout = 'origin/' + cef_branch
+else:
+ cef_checkout = options.checkout
+
+# Create the CEF checkout if necessary.
+if not options.nocefupdate and not os.path.exists(cef_dir):
+ cef_checkout_new = True
+ run('%s clone %s %s' % (git_exe, cef_url, cef_dir), download_dir,
+ depot_tools_dir)
+else:
+ cef_checkout_new = False
+
+# Determine if the CEF checkout needs to change.
+if not options.nocefupdate and os.path.exists(cef_dir):
+ cef_current_hash = get_git_hash(cef_dir, 'HEAD')
+
+ if not cef_checkout_new:
+ # Fetch updated sources.
+ run('%s fetch' % (git_exe), cef_dir, depot_tools_dir)
+
+ cef_desired_hash = get_git_hash(cef_dir, cef_checkout)
+ cef_checkout_changed = cef_checkout_new or force_change or \
+ options.forcecefupdate or \
+ cef_current_hash != cef_desired_hash
+
+ msg("CEF Current Checkout: %s" % (cef_current_hash))
+ msg("CEF Desired Checkout: %s (%s)" % (cef_desired_hash, cef_checkout))
+
+ if cef_checkout_changed:
+ if cef_dir == cef_src_dir:
+ # Running in fast update mode. Backup and revert the patched files before
+ # changing the CEF checkout.
+ run_patch_updater("--backup --revert")
+
+ # Update the CEF checkout.
+ run('%s checkout %s%s' %
+ (git_exe, '--force ' if discard_local_changes else '', cef_checkout), \
+ cef_dir, depot_tools_dir)
+else:
+ cef_checkout_changed = False
+
+build_compat_versions = get_build_compat_versions()
+
+if not options.nodepottoolsupdate and \
+ 'depot_tools_checkout' in build_compat_versions:
+ # Update the depot_tools checkout.
+ depot_tools_compat_version = build_compat_versions['depot_tools_checkout']
+ run('%s checkout %s%s' %
+ (git_exe, '--force ' if discard_local_changes else '', depot_tools_compat_version), \
+ depot_tools_dir, depot_tools_dir)
+
+# Disable further depot_tools updates.
+os.environ['DEPOT_TOOLS_UPDATE'] = '0'
+
+##
+# Manage the out directory.
+##
+
+out_dir = os.path.join(download_dir, 'out_' + cef_branch)
+
+# Delete the existing out directory if requested.
+if options.forceclean and os.path.exists(out_dir):
+ delete_directory(out_dir)
+
+msg("CEF Output Directory: %s" % (out_dir))
+
+##
+# Manage the chromium directory.
+##
+
+# Create the chromium directory if necessary.
+create_directory(chromium_dir)
+
+if options.chromiumurl != '':
+ chromium_url = options.chromiumurl
+else:
+ chromium_url = 'https://chromium.googlesource.com/chromium/src.git'
+
+# Create gclient configuration file.
+gclient_file = os.path.join(chromium_dir, '.gclient')
+if not os.path.exists(gclient_file) or options.forceconfig:
+ # Exclude unnecessary directories. Intentionally written without newlines.
+ gclient_spec = \
+ "solutions = [{"+\
+ "'managed': False,"+\
+ "'name': 'src', "+\
+ "'url': '" + chromium_url + "', "+\
+ "'custom_vars': {"+\
+ "'checkout_pgo_profiles': " + ('True' if options.withpgoprofiles else 'False') + ", "+\
+ "}, "+\
+ "'custom_deps': {"+\
+ "'build': None, "+\
+ "'build/scripts/command_wrapper/bin': None, "+\
+ "'build/scripts/gsd_generate_index': None, "+\
+ "'build/scripts/private/data/reliability': None, "+\
+ "'build/scripts/tools/deps2git': None, "+\
+ "'build/third_party/lighttpd': None, "+\
+ "'commit-queue': None, "+\
+ "'depot_tools': None, "+\
+ "'src/chrome_frame/tools/test/reference_build/chrome': None, "+\
+ "'src/chrome/tools/test/reference_build/chrome_linux': None, "+\
+ "'src/chrome/tools/test/reference_build/chrome_mac': None, "+\
+ "'src/chrome/tools/test/reference_build/chrome_win': None, "+\
+ "}, "+\
+ "'deps_file': '" + deps_file + "', "+\
+ "'safesync_url': ''"+\
+ "}]"
+
+ msg('Writing %s' % gclient_file)
+ if not options.dryrun:
+ with open(gclient_file, 'w', encoding='utf-8') as fp:
+ write_fp(fp, gclient_spec)
+
+# Initial Chromium checkout.
+if not options.nochromiumupdate and not os.path.exists(chromium_src_dir):
+ chromium_checkout_new = True
+ run("gclient sync --nohooks --with_branch_heads --jobs 16", \
+ chromium_dir, depot_tools_dir)
+else:
+ chromium_checkout_new = False
+
+# Verify the Chromium checkout.
+if not options.dryrun and not is_git_checkout(chromium_src_dir):
+ raise Exception('Not a valid git checkout: %s' % (chromium_src_dir))
+
+if os.path.exists(chromium_src_dir):
+ msg("Chromium URL: %s" % (get_git_url(chromium_src_dir)))
+
+# Fetch Chromium changes so that we can perform the necessary calculations using
+# local history.
+if not options.nochromiumupdate and os.path.exists(chromium_src_dir):
+ # Fetch updated sources.
+ run("%s fetch" % (git_exe), chromium_src_dir, depot_tools_dir)
+ # Also fetch tags, which are required for release branch builds.
+ run("%s fetch --tags" % (git_exe), chromium_src_dir, depot_tools_dir)
+
+# Determine the Chromium checkout options required by CEF.
+chromium_compat_version = build_compat_versions['chromium_checkout']
+if len(options.chromiumcheckout) > 0:
+ chromium_checkout = options.chromiumcheckout
+elif len(options.chromiumchannel) > 0:
+ target_distance = int(options.chromiumchanneldistance
+ ) if len(options.chromiumchanneldistance) > 0 else 0
+ chromium_checkout = get_chromium_target_version(
+ channel=options.chromiumchannel, target_distance=target_distance)
+else:
+ chromium_checkout = chromium_compat_version
+
+# Determine if the Chromium checkout needs to change.
+if not options.nochromiumupdate and os.path.exists(chromium_src_dir):
+ chromium_current_hash = get_git_hash(chromium_src_dir, 'HEAD')
+ chromium_desired_hash = get_git_hash(chromium_src_dir, chromium_checkout)
+ chromium_checkout_changed = chromium_checkout_new or force_change or \
+ chromium_current_hash != chromium_desired_hash
+
+ msg("Chromium Current Checkout: %s" % (chromium_current_hash))
+ msg("Chromium Desired Checkout: %s (%s)" % \
+ (chromium_desired_hash, chromium_checkout))
+else:
+ chromium_checkout_changed = options.dryrun
+
+if cef_checkout_changed:
+ if cef_dir != cef_src_dir and os.path.exists(cef_src_dir):
+ # Delete the existing src/cef directory. It will be re-copied from the
+ # download directory later.
+ delete_directory(cef_src_dir)
+elif chromium_checkout_changed and cef_dir == cef_src_dir:
+ # Running in fast update mode. Backup and revert the patched files before
+ # changing the Chromium checkout.
+ run_patch_updater("--backup --revert")
+
+# Delete the existing src/out directory if requested.
+if options.forceclean and os.path.exists(out_src_dir):
+ delete_directory(out_src_dir)
+
+# Move the existing src/out directory to the correct location in the download
+# directory. It will be moved back from the download directory later.
+if os.path.exists(out_src_dir):
+ old_branch = read_branch_config_file(out_src_dir)
+ if old_branch != '' and (chromium_checkout_changed or
+ old_branch != cef_branch):
+ old_out_dir = os.path.join(download_dir, 'out_' + old_branch)
+ move_directory(out_src_dir, old_out_dir)
+
+# Update the Chromium checkout.
+if chromium_checkout_changed:
+ if not chromium_checkout_new and not options.fastupdate:
+ if options.forceclean and options.forcecleandeps:
+ # Remove all local changes including third-party git checkouts managed by
+ # gclient.
+ run("%s clean -dffx" % (git_exe), chromium_src_dir, depot_tools_dir)
+ else:
+ # Revert all changes in the Chromium checkout.
+ run("gclient revert --nohooks", chromium_dir, depot_tools_dir)
+
+ # Checkout the requested branch.
+ run("%s checkout %s%s" % \
+ (git_exe, '--force ' if discard_local_changes else '', chromium_checkout), \
+ chromium_src_dir, depot_tools_dir)
+
+ # Patch the Chromium DEPS file if necessary.
+ apply_deps_patch()
+
+ # Update third-party dependencies including branch/tag information.
+ run("gclient sync %s--nohooks --with_branch_heads --jobs 16" % \
+ ('--reset ' if discard_local_changes else ''), chromium_dir, depot_tools_dir)
+
+ # Patch the Chromium runhooks scripts if necessary.
+ apply_runhooks_patch()
+
+ # Runs hooks for files that have been modified in the local working copy.
+ run("gclient runhooks --jobs 16", chromium_dir, depot_tools_dir)
+
+ # Delete the src/out directory created by `gclient sync`.
+ delete_directory(out_src_dir)
+
+if cef_dir == cef_src_dir:
+ # Running in fast update mode.
+ if cef_checkout_changed or chromium_checkout_changed:
+ # Check and restore the patched files.
+ run_patch_updater("--reapply --restore")
+elif os.path.exists(cef_dir) and not os.path.exists(cef_src_dir):
+ # Restore the src/cef directory.
+ copy_directory(cef_dir, cef_src_dir)
+
+# Restore the src/out directory.
+out_src_dir_exists = os.path.exists(out_src_dir)
+if os.path.exists(out_dir) and not out_src_dir_exists:
+ move_directory(out_dir, out_src_dir)
+ out_src_dir_exists = True
+elif not out_src_dir_exists:
+ create_directory(out_src_dir)
+
+# Write the config file for identifying the branch.
+write_branch_config_file(out_src_dir, cef_branch)
+
+if options.logchromiumchanges and chromium_checkout != chromium_compat_version:
+ log_chromium_changes()
+
+if options.forcepatchupdate or ((chromium_checkout_new or not options.fastupdate) and \
+ chromium_checkout_changed and \
+ chromium_checkout != chromium_compat_version):
+ # Not using the known-compatible Chromium version. Try to update patch files.
+ if options.logchromiumchanges:
+ out_file = os.path.join(download_dir, 'chromium_update_patches.txt')
+ if os.path.exists(out_file):
+ os.remove(out_file)
+ else:
+ out_file = None
+ run_patch_updater(output_file=out_file)
+elif options.resave:
+ # Resave patch files.
+ run_patch_updater("--resave")
+
+if chromium_checkout != chromium_compat_version:
+ if options.logchromiumchanges:
+ out_file = os.path.join(download_dir, 'chromium_update_patterns.txt')
+ if os.path.exists(out_file):
+ os.remove(out_file)
+ else:
+ out_file = None
+ check_pattern_matches(output_file=out_file)
+
+##
+# Build CEF.
+##
+
+if not options.nobuild and (chromium_checkout_changed or \
+ cef_checkout_changed or options.forcebuild or \
+ not out_src_dir_exists):
+ # Building should also force a distribution.
+ options.forcedistrib = True
+
+ # Make sure the GN configuration exists.
+ if not options.dryrun and \
+ not os.path.exists(os.path.join(cef_src_dir, 'BUILD.gn')):
+ raise Exception('GN configuration does not exist.')
+
+ # Print all build-related environment variables including any that were set
+ # previously.
+ for key in os.environ.keys():
+ if key.startswith('CEF_') or key.startswith('GCLIENT_') or \
+ key.startswith('GN_') or key.startswith('GYP_') or \
+ key.startswith('DEPOT_TOOLS_'):
+ msg('%s=%s' % (key, os.environ[key]))
+
+ # Generate project files.
+ tool = os.path.join(cef_src_dir, 'tools', 'gclient_hook.py')
+ run('%s %s' % (python_exe, tool), cef_src_dir, depot_tools_dir)
+
+ # Build using Ninja.
+ command = 'ninja '
+ if options.verbosebuild:
+ command += '-v '
+ if options.buildfailurelimit != 1:
+ command += '-k %d ' % options.buildfailurelimit
+ command += '-C '
+ target = ' ' + options.buildtarget
+ if options.buildtests:
+ target += ' ' + options.testtarget
+ if platform == 'linux':
+ target += ' chrome_sandbox'
+
+ # Make a CEF Debug build.
+ if not options.nodebugbuild:
+ build_path = os.path.join('out', get_build_directory_name(True))
+ args_path = os.path.join(chromium_src_dir, build_path, 'args.gn')
+ msg(args_path + ' contents:\n' + read_file(args_path))
+
+ run(command + build_path + target, chromium_src_dir, depot_tools_dir,
+ os.path.join(download_dir, 'build-%s-debug.log' % (cef_branch)) \
+ if options.buildlogfile else None)
+
+ if platform in sandbox_lib_platforms:
+ # Make the separate cef_sandbox build when GN is_official_build=true.
+ build_path += '_sandbox'
+ if os.path.exists(os.path.join(chromium_src_dir, build_path)):
+ args_path = os.path.join(chromium_src_dir, build_path, 'args.gn')
+ msg(args_path + ' contents:\n' + read_file(args_path))
+
+ run(command + build_path + ' cef_sandbox', chromium_src_dir, depot_tools_dir,
+ os.path.join(download_dir, 'build-%s-debug-sandbox.log' % (cef_branch)) \
+ if options.buildlogfile else None)
+
+ # Make a CEF Release build.
+ if not options.noreleasebuild:
+ build_path = os.path.join('out', get_build_directory_name(False))
+ args_path = os.path.join(chromium_src_dir, build_path, 'args.gn')
+ msg(args_path + ' contents:\n' + read_file(args_path))
+
+ run(command + build_path + target, chromium_src_dir, depot_tools_dir,
+ os.path.join(download_dir, 'build-%s-release.log' % (cef_branch)) \
+ if options.buildlogfile else None)
+
+ if platform in sandbox_lib_platforms:
+ # Make the separate cef_sandbox build when GN is_official_build=true.
+ build_path += '_sandbox'
+ if os.path.exists(os.path.join(chromium_src_dir, build_path)):
+ args_path = os.path.join(chromium_src_dir, build_path, 'args.gn')
+ msg(args_path + ' contents:\n' + read_file(args_path))
+
+ run(command + build_path + ' cef_sandbox', chromium_src_dir, depot_tools_dir,
+ os.path.join(download_dir, 'build-%s-release-sandbox.log' % (cef_branch)) \
+ if options.buildlogfile else None)
+
+elif not options.nobuild:
+ msg('Not building. The source hashes have not changed and ' +
+ 'the output folder "%s" already exists' % (out_src_dir))
+
+##
+# Run CEF tests.
+##
+
+if options.runtests:
+ if platform == 'windows':
+ test_exe = '%s.exe' % options.testtarget
+ elif platform == 'mac':
+ test_exe = '%s.app/Contents/MacOS/%s' % (options.testtarget,
+ options.testtarget)
+ elif platform == 'linux':
+ test_exe = options.testtarget
+
+ test_prefix = options.testprefix
+ if len(test_prefix) > 0:
+ test_prefix += ' '
+
+ test_args = options.testargs
+ if len(test_args) > 0:
+ test_args = ' ' + test_args
+
+ if not options.nodebugtests:
+ build_path = os.path.join(out_src_dir, get_build_directory_name(True))
+ test_path = os.path.join(build_path, test_exe)
+ if os.path.exists(test_path):
+ run(test_prefix + test_path + test_args, build_path, depot_tools_dir)
+ else:
+ msg('Not running debug tests. Missing executable: %s' % test_path)
+
+ if not options.noreleasetests:
+ build_path = os.path.join(out_src_dir, get_build_directory_name(False))
+ test_path = os.path.join(build_path, test_exe)
+ if os.path.exists(test_path):
+ run(test_prefix + test_path + test_args, build_path, depot_tools_dir)
+ else:
+ msg('Not running release tests. Missing executable: %s' % test_path)
+
+##
+# Create the CEF binary distribution.
+##
+
+if not options.nodistrib and (chromium_checkout_changed or \
+ cef_checkout_changed or options.forcedistrib):
+ if not options.forceclean and options.cleanartifacts:
+ # Clean the artifacts output directory.
+ artifacts_path = os.path.join(cef_src_dir, 'binary_distrib')
+ delete_directory(artifacts_path)
+
+ # Determine the requested distribution types.
+ distrib_types = []
+ if options.minimaldistribonly:
+ distrib_types.append('minimal')
+ elif options.clientdistribonly:
+ distrib_types.append('client')
+ elif options.sandboxdistribonly:
+ distrib_types.append('sandbox')
+ else:
+ distrib_types.append('standard')
+ if options.minimaldistrib:
+ distrib_types.append('minimal')
+ if options.clientdistrib:
+ distrib_types.append('client')
+ if options.sandboxdistrib:
+ distrib_types.append('sandbox')
+
+ cef_tools_dir = os.path.join(cef_src_dir, 'tools')
+
+ # Create the requested distribution types.
+ first_type = True
+ for type in distrib_types:
+ path = '%s make_distrib.py --output-dir=../binary_distrib/' % python_exe
+
+ if options.nodebugbuild or options.noreleasebuild or type != 'standard':
+ path += ' --allow-partial'
+ path = path + ' --ninja-build'
+ if options.x64build:
+ path += ' --x64-build'
+ elif options.armbuild:
+ path += ' --arm-build'
+ elif options.arm64build:
+ path += ' --arm64-build'
+
+ if type == 'minimal':
+ path += ' --minimal'
+ elif type == 'client':
+ path += ' --client'
+ elif type == 'sandbox':
+ path += ' --sandbox'
+
+ if first_type:
+ if options.nodistribdocs:
+ path += ' --no-docs'
+ if options.nodistribarchive:
+ path += ' --no-archive'
+ first_type = False
+ else:
+ # Don't create the symbol archives or documentation more than once.
+ path += ' --no-symbols --no-docs'
+
+ # Override the subdirectory name of binary_distrib if the caller requested.
+ if options.distribsubdir != '':
+ path += ' --distrib-subdir=' + options.distribsubdir
+ if options.distribsubdirsuffix != '':
+ path += ' --distrib-subdir-suffix=' + options.distribsubdirsuffix
+
+ # Create the distribution.
+ run(path, cef_tools_dir, depot_tools_dir)
diff --git a/tools/cef_api_hash.py b/tools/cef_api_hash.py
new file mode 100644
index 00000000..39eefa07
--- /dev/null
+++ b/tools/cef_api_hash.py
@@ -0,0 +1,299 @@
+# Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+# reserved. Use of this source code is governed by a BSD-style license that
+# can be found in the LICENSE file.
+
+from __future__ import absolute_import
+from __future__ import print_function
+from file_util import *
+import os
+import re
+import shutil
+import string
+import sys
+import textwrap
+import time
+import itertools
+import hashlib
+
+# Determines string type for python 2 and python 3.
+if sys.version_info[0] == 3:
+ string_type = str
+else:
+ string_type = basestring
+
+
+class cef_api_hash:
+ """ CEF API hash calculator """
+
+ def __init__(self, headerdir, debugdir=None, verbose=False):
+ if headerdir is None or len(headerdir) == 0:
+ raise AssertionError("headerdir is not specified")
+
+ self.__headerdir = headerdir
+ self.__debugdir = debugdir
+ self.__verbose = verbose
+ self.__debug_enabled = not (self.__debugdir is
+ None) and len(self.__debugdir) > 0
+
+ self.platforms = ["windows", "mac", "linux"]
+
+ self.platform_files = {
+ # List of includes_win_capi from cef_paths2.gypi.
+ "windows": [
+ "internal/cef_app_win.h",
+ "internal/cef_types_win.h",
+ ],
+ # List of includes_mac_capi from cef_paths2.gypi.
+ "mac": [
+ "internal/cef_types_mac.h",
+ ],
+ # List of includes_linux_capi from cef_paths2.gypi.
+ "linux": [
+ "internal/cef_types_linux.h",
+ ]
+ }
+
+ self.included_files = []
+
+ # List of include/ and include/internal/ files from cef_paths2.gypi.
+ self.excluded_files = [
+ # includes_common
+ "cef_api_hash.h",
+ "cef_base.h",
+ "cef_config.h",
+ "cef_version.h",
+ "internal/cef_export.h",
+ "internal/cef_ptr.h",
+ "internal/cef_string_wrappers.h",
+ "internal/cef_time_wrappers.h",
+ "internal/cef_types_wrappers.h",
+ # includes_win
+ "cef_sandbox_win.h",
+ "internal/cef_win.h",
+ # includes_mac
+ "cef_application_mac.h",
+ "cef_sandbox_mac.h",
+ "internal/cef_mac.h",
+ # includes_linux
+ "internal/cef_linux.h",
+ ]
+
+ def calculate(self):
+ filenames = [
+ filename for filename in self.__get_filenames()
+ if not filename in self.excluded_files
+ ]
+
+ objects = []
+ for filename in filenames:
+ if self.__verbose:
+ print("Processing " + filename + "...")
+ content = read_file(os.path.join(self.__headerdir, filename), True)
+ platforms = list([
+ p for p in self.platforms if self.__is_platform_filename(filename, p)
+ ])
+
+ # Parse cef_string.h happens in special case: grab only defined CEF_STRING_TYPE_xxx declaration
+ content_objects = None
+ if filename == "internal/cef_string.h":
+ content_objects = self.__parse_string_type(content)
+ else:
+ content_objects = self.__parse_objects(content)
+
+ for o in content_objects:
+ o["text"] = self.__prepare_text(o["text"])
+ o["platforms"] = platforms
+ o["filename"] = filename
+ objects.append(o)
+
+ # objects will be sorted including filename, to make stable universal hashes
+ objects = sorted(objects, key=lambda o: o["name"] + "@" + o["filename"])
+
+ if self.__debug_enabled:
+ namelen = max([len(o["name"]) for o in objects])
+ filenamelen = max([len(o["filename"]) for o in objects])
+ dumpsig = []
+ for o in objects:
+ dumpsig.append(
+ format(o["name"], str(namelen) + "s") + "|" + format(
+ o["filename"], "" + str(filenamelen) + "s") + "|" + o["text"])
+ self.__write_debug_file("objects.txt", dumpsig)
+
+ revisions = {}
+
+ for platform in itertools.chain(["universal"], self.platforms):
+ sig = self.__get_final_sig(objects, platform)
+ if self.__debug_enabled:
+ self.__write_debug_file(platform + ".sig", sig)
+ revstr = hashlib.sha1(sig.encode('utf-8')).hexdigest()
+ revisions[platform] = revstr
+
+ return revisions
+
+ def __parse_objects(self, content):
+ """ Returns array of objects in content file. """
+ objects = []
+ content = re.sub("//.*\n", "", content)
+
+ # function declarations
+ for m in re.finditer(
+ "\nCEF_EXPORT\s+?.*?\s+?(\w+)\s*?\(.*?\)\s*?;",
+ content,
+ flags=re.DOTALL):
+ object = {"name": m.group(1), "text": m.group(0).strip()}
+ objects.append(object)
+
+ # structs
+ for m in re.finditer(
+ "\ntypedef\s+?struct\s+?(\w+)\s+?\{.*?\}\s+?(\w+)\s*?;",
+ content,
+ flags=re.DOTALL):
+ object = {"name": m.group(2), "text": m.group(0).strip()}
+ objects.append(object)
+
+ # enums
+ for m in re.finditer(
+ "\ntypedef\s+?enum\s+?\{.*?\}\s+?(\w+)\s*?;", content, flags=re.DOTALL):
+ object = {"name": m.group(1), "text": m.group(0).strip()}
+ objects.append(object)
+
+ # typedefs
+ for m in re.finditer("\ntypedef\s+?.*?\s+(\w+);", content, flags=0):
+ object = {"name": m.group(1), "text": m.group(0).strip()}
+ objects.append(object)
+
+ return objects
+
+ def __parse_string_type(self, content):
+ """ Grab defined CEF_STRING_TYPE_xxx """
+ objects = []
+ for m in re.finditer(
+ "\n\s*?#\s*?define\s+?(CEF_STRING_TYPE_\w+)\s+?.*?\n", content,
+ flags=0):
+ object = {
+ "name": m.group(1),
+ "text": m.group(0),
+ }
+ objects.append(object)
+ return objects
+
+ def __prepare_text(self, text):
+ text = text.strip()
+ text = re.sub("\s+", " ", text)
+ text = re.sub("\(\s+", "(", text)
+ return text
+
+ def __get_final_sig(self, objects, platform):
+ sig = []
+
+ for o in objects:
+ if platform == "universal" or platform in o["platforms"]:
+ sig.append(o["text"])
+
+ return "\n".join(sig)
+
+ def __get_filenames(self):
+ """ Returns file names to be processed, relative to headerdir """
+ headers = [
+ os.path.join(self.__headerdir, filename)
+ for filename in self.included_files
+ ]
+
+ capi_dir = os.path.join(self.__headerdir, "capi")
+ headers = itertools.chain(headers, get_files(os.path.join(capi_dir, "*.h")))
+
+ # Also include capi sub-directories.
+ for root, dirs, files in os.walk(capi_dir):
+ for name in dirs:
+ headers = itertools.chain(headers,
+ get_files(os.path.join(root, name, "*.h")))
+
+ headers = itertools.chain(
+ headers, get_files(os.path.join(self.__headerdir, "internal", "*.h")))
+
+ for v in self.platform_files.values():
+ headers = itertools.chain(headers,
+ [os.path.join(self.__headerdir, f) for f in v])
+
+ normalized = [
+ os.path.relpath(filename, self.__headerdir) for filename in headers
+ ]
+ normalized = [f.replace('\\', '/').lower() for f in normalized]
+
+ return list(set(normalized))
+
+ def __is_platform_filename(self, filename, platform):
+ if platform == "universal":
+ return True
+ if not platform in self.platform_files:
+ return False
+ listed = False
+ for p in self.platforms:
+ if filename in self.platform_files[p]:
+ if p == platform:
+ return True
+ else:
+ listed = True
+ return not listed
+
+ def __write_debug_file(self, filename, content):
+ make_dir(self.__debugdir)
+ outfile = os.path.join(self.__debugdir, filename)
+ dir = os.path.dirname(outfile)
+ make_dir(dir)
+ if not isinstance(content, string_type):
+ content = "\n".join(content)
+ write_file(outfile, content)
+
+
+if __name__ == "__main__":
+ from optparse import OptionParser
+ import time
+
+ disc = """
+ This utility calculates CEF API hash.
+ """
+
+ parser = OptionParser(description=disc)
+ parser.add_option(
+ '--cpp-header-dir',
+ dest='cppheaderdir',
+ metavar='DIR',
+ help='input directory for C++ header files [required]')
+ parser.add_option(
+ '--debug-dir',
+ dest='debugdir',
+ metavar='DIR',
+ help='intermediate directory for easy debugging')
+ parser.add_option(
+ '-v',
+ '--verbose',
+ action='store_true',
+ dest='verbose',
+ default=False,
+ help='output detailed status information')
+ (options, args) = parser.parse_args()
+
+ # the cppheader option is required
+ if options.cppheaderdir is None:
+ parser.print_help(sys.stdout)
+ sys.exit()
+
+ # calculate
+ c_start_time = time.time()
+
+ calc = cef_api_hash(options.cppheaderdir, options.debugdir, options.verbose)
+ revisions = calc.calculate()
+
+ c_completed_in = time.time() - c_start_time
+
+ print("{")
+ for k in sorted(revisions.keys()):
+ print(format("\"" + k + "\"", ">12s") + ": \"" + revisions[k] + "\"")
+ print("}")
+ # print
+ # print 'Completed in: ' + str(c_completed_in)
+ # print
+
+ # print "Press any key to continue...";
+ # sys.stdin.readline();
diff --git a/tools/cef_parser.py b/tools/cef_parser.py
new file mode 100644
index 00000000..047b450f
--- /dev/null
+++ b/tools/cef_parser.py
@@ -0,0 +1,2125 @@
+# Copyright (c) 2011 The Chromium Embedded Framework Authors. All rights
+# reserved. Use of this source code is governed by a BSD-style license that
+# can be found in the LICENSE file.
+
+from __future__ import absolute_import
+from date_util import *
+from file_util import *
+import os
+import re
+import shutil
+import string
+import sys
+import textwrap
+import time
+
+
+def notify(msg):
+ """ Display a message. """
+ sys.stdout.write(' NOTE: ' + msg + '\n')
+
+
+def wrap_text(text, indent='', maxchars=80):
+ """ Wrap the text to the specified number of characters. If
+ necessary a line will be broken and wrapped after a word.
+ """
+ result = ''
+ lines = textwrap.wrap(text, maxchars - len(indent))
+ for line in lines:
+ result += indent + line + '\n'
+ return result
+
+
+def is_base_class(clsname):
+ """ Returns true if |clsname| is a known base (root) class in the object
+ hierarchy.
+ """
+ return clsname == 'CefBaseRefCounted' or clsname == 'CefBaseScoped'
+
+
+def get_capi_file_name(cppname):
+ """ Convert a C++ header file name to a C API header file name. """
+ return cppname[:-2] + '_capi.h'
+
+
+def get_capi_name(cppname, isclassname, prefix=None):
+ """ Convert a C++ CamelCaps name to a C API underscore name. """
+ result = ''
+ lastchr = ''
+ for chr in cppname:
+ # add an underscore if the current character is an upper case letter
+ # and the last character was a lower case letter
+ if len(result) > 0 and not chr.isdigit() \
+ and chr.upper() == chr \
+ and not lastchr.upper() == lastchr:
+ result += '_'
+ result += chr.lower()
+ lastchr = chr
+
+ if isclassname:
+ result += '_t'
+
+ if not prefix is None:
+ if prefix[0:3] == 'cef':
+ # if the prefix name is duplicated in the function name
+ # remove that portion of the function name
+ subprefix = prefix[3:]
+ pos = result.find(subprefix)
+ if pos >= 0:
+ result = result[0:pos] + result[pos + len(subprefix):]
+ result = prefix + '_' + result
+
+ return result
+
+
+def get_wrapper_type_enum(cppname):
+ """ Returns the wrapper type enumeration value for the specified C++ class
+ name. """
+ return 'WT_' + get_capi_name(cppname, False)[4:].upper()
+
+
+def get_prev_line(body, pos):
+ """ Retrieve the start and end positions and value for the line immediately
+ before the line containing the specified position.
+ """
+ end = body.rfind('\n', 0, pos)
+ start = body.rfind('\n', 0, end) + 1
+ line = body[start:end]
+ return {'start': start, 'end': end, 'line': line}
+
+
+def get_comment(body, name):
+ """ Retrieve the comment for a class or function. """
+ result = []
+
+ pos = body.find(name)
+ in_block_comment = False
+ while pos > 0:
+ data = get_prev_line(body, pos)
+ line = data['line'].strip()
+ pos = data['start']
+ if len(line) == 0:
+ break
+ # single line /*--cef()--*/
+ elif line[0:2] == '/*' and line[-2:] == '*/':
+ continue
+ # start of multi line /*--cef()--*/
+ elif in_block_comment and line[0:2] == '/*':
+ in_block_comment = False
+ continue
+ # end of multi line /*--cef()--*/
+ elif not in_block_comment and line[-2:] == '*/':
+ in_block_comment = True
+ continue
+ elif in_block_comment:
+ continue
+ elif line[0:3] == '///':
+ # keep the comment line including any leading spaces
+ result.append(line[3:])
+ else:
+ break
+
+ result.reverse()
+ return result
+
+
+def validate_comment(file, name, comment):
+ """ Validate the comment array returned by get_comment(). """
+ # Verify that the comment contains beginning and ending '///' as required by
+ # Doxygen (the leading '///' from each line will already have been removed by
+ # the get_comment() logic).
+ if len(comment) < 3 or len(comment[0]) != 0 or len(comment[-1]) != 0:
+ raise Exception('Missing or incorrect comment in %s for: %s' % \
+ (file, name))
+
+
+def format_comment(comment, indent, translate_map=None, maxchars=80):
+ """ Return the comments array as a formatted string. """
+ if not translate_map is None:
+ # Replace longest keys first in translation.
+ translate_keys = sorted(
+ translate_map.keys(), key=lambda item: (-len(item), item))
+
+ result = ''
+ wrapme = ''
+ hasemptyline = False
+ for line in comment:
+ # if the line starts with a leading space, remove that space
+ if not line is None and len(line) > 0 and line[0] == ' ':
+ line = line[1:]
+ didremovespace = True
+ else:
+ didremovespace = False
+
+ if line is None or len(line) == 0 or line[0] == ' ':
+ # the previous paragraph, if any, has ended
+ if len(wrapme) > 0:
+ if not translate_map is None:
+ # apply the translation
+ for key in translate_keys:
+ wrapme = wrapme.replace(key, translate_map[key])
+ # output the previous paragraph
+ result += wrap_text(wrapme, indent + '/// ', maxchars)
+ wrapme = ''
+
+ if not line is None:
+ if len(line) == 0 or line[0] == ' ':
+ # blank lines or anything that's further indented should be
+ # output as-is
+ result += indent + '///'
+ if len(line) > 0:
+ if didremovespace:
+ result += ' ' + line
+ else:
+ result += line
+ result += '\n'
+ else:
+ # add to the current paragraph
+ wrapme += line + ' '
+ else:
+ # output an empty line
+ hasemptyline = True
+ result += '\n'
+
+ if len(wrapme) > 0:
+ if not translate_map is None:
+ # apply the translation
+ for key in translate_map.keys():
+ wrapme = wrapme.replace(key, translate_map[key])
+ # output the previous paragraph
+ result += wrap_text(wrapme, indent + '/// ', maxchars)
+
+ if hasemptyline:
+ # an empty line means a break between comments, so the comment is
+ # probably a section heading and should have an extra line before it
+ result = '\n' + result
+ return result
+
+
+def format_translation_changes(old, new):
+ """ Return a comment stating what is different between the old and new
+ function prototype parts.
+ """
+ changed = False
+ result = ''
+
+ # normalize C API attributes
+ oldargs = [x.replace('struct _', '') for x in old['args']]
+ oldretval = old['retval'].replace('struct _', '')
+ newargs = [x.replace('struct _', '') for x in new['args']]
+ newretval = new['retval'].replace('struct _', '')
+
+ # check if the prototype has changed
+ oldset = set(oldargs)
+ newset = set(newargs)
+ if len(oldset.symmetric_difference(newset)) > 0:
+ changed = True
+ result += '\n // WARNING - CHANGED ATTRIBUTES'
+
+ # in the implementation set only
+ oldonly = oldset.difference(newset)
+ for arg in oldonly:
+ result += '\n // REMOVED: ' + arg
+
+ # in the current set only
+ newonly = newset.difference(oldset)
+ for arg in newonly:
+ result += '\n // ADDED: ' + arg
+
+ # check if the return value has changed
+ if oldretval != newretval:
+ changed = True
+ result += '\n // WARNING - CHANGED RETURN VALUE'+ \
+ '\n // WAS: '+old['retval']+ \
+ '\n // NOW: '+new['retval']
+
+ if changed:
+ result += '\n #pragma message("Warning: "__FILE__": '+new['name']+ \
+ ' prototype has changed")\n'
+
+ return result
+
+
+def format_translation_includes(header, body):
+ """ Return the necessary list of includes based on the contents of the
+ body.
+ """
+ result = ''
+
+ # <algorithm> required for VS2013.
+ if body.find('std::min') > 0 or body.find('std::max') > 0:
+ result += '#include <algorithm>\n'
+
+ if body.find('cef_api_hash(') > 0:
+ result += '#include "include/cef_api_hash.h"\n'
+
+ if body.find('template_util::has_valid_size(') > 0:
+ result += '#include "libcef_dll/template_util.h"\n'
+
+ # identify what CppToC classes are being used
+ p = re.compile('([A-Za-z0-9_]{1,})CppToC')
+ list = sorted(set(p.findall(body)))
+ for item in list:
+ directory = ''
+ if not is_base_class(item):
+ cls = header.get_class(item)
+ dir = cls.get_file_directory()
+ if not dir is None:
+ directory = dir + '/'
+ result += '#include "libcef_dll/cpptoc/'+directory+ \
+ get_capi_name(item[3:], False)+'_cpptoc.h"\n'
+
+ # identify what CToCpp classes are being used
+ p = re.compile('([A-Za-z0-9_]{1,})CToCpp')
+ list = sorted(set(p.findall(body)))
+ for item in list:
+ directory = ''
+ if not is_base_class(item):
+ cls = header.get_class(item)
+ dir = cls.get_file_directory()
+ if not dir is None:
+ directory = dir + '/'
+ result += '#include "libcef_dll/ctocpp/'+directory+ \
+ get_capi_name(item[3:], False)+'_ctocpp.h"\n'
+
+ if body.find('shutdown_checker') > 0:
+ result += '#include "libcef_dll/shutdown_checker.h"\n'
+
+ if body.find('transfer_') > 0:
+ result += '#include "libcef_dll/transfer_util.h"\n'
+
+ return result
+
+
+def str_to_dict(str):
+ """ Convert a string to a dictionary. If the same key has multiple values
+ the values will be stored in a list. """
+ dict = {}
+ parts = str.split(',')
+ for part in parts:
+ part = part.strip()
+ if len(part) == 0:
+ continue
+ sparts = part.split('=')
+ if len(sparts) > 2:
+ raise Exception('Invalid dictionary pair format: ' + part)
+ name = sparts[0].strip()
+ if len(sparts) == 2:
+ val = sparts[1].strip()
+ else:
+ val = True
+ if name in dict:
+ # a value with this name already exists
+ curval = dict[name]
+ if not isinstance(curval, list):
+ # convert the string value to a list
+ dict[name] = [curval]
+ dict[name].append(val)
+ else:
+ dict[name] = val
+ return dict
+
+
+def dict_to_str(dict):
+ """ Convert a dictionary to a string. """
+ str = []
+ for name in dict.keys():
+ if not isinstance(dict[name], list):
+ if dict[name] is True:
+ # currently a bool value
+ str.append(name)
+ else:
+ # currently a string value
+ str.append(name + '=' + dict[name])
+ else:
+ # currently a list value
+ for val in dict[name]:
+ str.append(name + '=' + val)
+ return ','.join(str)
+
+
+# regex for matching comment-formatted attributes
+_cre_attrib = '/\*--cef\(([A-Za-z0-9_ ,=:\n]{0,})\)--\*/'
+# regex for matching class and function names
+_cre_cfname = '([A-Za-z0-9_]{1,})'
+# regex for matching class and function names including path separators
+_cre_cfnameorpath = '([A-Za-z0-9_\/]{1,})'
+# regex for matching function return values
+_cre_retval = '([A-Za-z0-9_<>:,\*\&]{1,})'
+# regex for matching typedef value and name combination
+_cre_typedef = '([A-Za-z0-9_<>:,\*\&\s]{1,})'
+# regex for matching function return value and name combination
+_cre_func = '([A-Za-z][A-Za-z0-9_<>:,\*\&\s]{1,})'
+# regex for matching virtual function modifiers + arbitrary whitespace
+_cre_vfmod = '([\sA-Za-z0-9_]{0,})'
+# regex for matching arbitrary whitespace
+_cre_space = '[\s]{1,}'
+# regex for matching optional virtual keyword
+_cre_virtual = '(?:[\s]{1,}virtual){0,1}'
+
+# Simple translation types. Format is:
+# 'cpp_type' : ['capi_type', 'capi_default_value']
+_simpletypes = {
+ 'void': ['void', ''],
+ 'void*': ['void*', 'NULL'],
+ 'int': ['int', '0'],
+ 'int16': ['int16', '0'],
+ 'uint16': ['uint16', '0'],
+ 'int32': ['int32', '0'],
+ 'uint32': ['uint32', '0'],
+ 'int64': ['int64', '0'],
+ 'uint64': ['uint64', '0'],
+ 'double': ['double', '0'],
+ 'float': ['float', '0'],
+ 'float*': ['float*', 'NULL'],
+ 'long': ['long', '0'],
+ 'unsigned long': ['unsigned long', '0'],
+ 'long long': ['long long', '0'],
+ 'size_t': ['size_t', '0'],
+ 'bool': ['int', '0'],
+ 'char': ['char', '0'],
+ 'char* const': ['char* const', 'NULL'],
+ 'cef_color_t': ['cef_color_t', '0'],
+ 'cef_json_parser_error_t': ['cef_json_parser_error_t', 'JSON_NO_ERROR'],
+ 'CefAudioParameters': ['cef_audio_parameters_t', 'CefAudioParameters()'],
+ 'CefBaseTime': ['cef_basetime_t', 'CefBaseTime()'],
+ 'CefBoxLayoutSettings': [
+ 'cef_box_layout_settings_t', 'CefBoxLayoutSettings()'
+ ],
+ 'CefCompositionUnderline': [
+ 'cef_composition_underline_t', 'CefCompositionUnderline()'
+ ],
+ 'CefCursorHandle': ['cef_cursor_handle_t', 'kNullCursorHandle'],
+ 'CefCursorInfo': ['cef_cursor_info_t', 'CefCursorInfo()'],
+ 'CefDraggableRegion': ['cef_draggable_region_t', 'CefDraggableRegion()'],
+ 'CefEventHandle': ['cef_event_handle_t', 'kNullEventHandle'],
+ 'CefInsets': ['cef_insets_t', 'CefInsets()'],
+ 'CefKeyEvent': ['cef_key_event_t', 'CefKeyEvent()'],
+ 'CefMainArgs': ['cef_main_args_t', 'CefMainArgs()'],
+ 'CefMouseEvent': ['cef_mouse_event_t', 'CefMouseEvent()'],
+ 'CefPoint': ['cef_point_t', 'CefPoint()'],
+ 'CefPopupFeatures': ['cef_popup_features_t', 'CefPopupFeatures()'],
+ 'CefRange': ['cef_range_t', 'CefRange()'],
+ 'CefRect': ['cef_rect_t', 'CefRect()'],
+ 'CefScreenInfo': ['cef_screen_info_t', 'CefScreenInfo()'],
+ 'CefSize': ['cef_size_t', 'CefSize()'],
+ 'CefTouchEvent': ['cef_touch_event_t', 'CefTouchEvent()'],
+ 'CefTouchHandleState': [
+ 'cef_touch_handle_state_t', 'CefTouchHandleState()'
+ ],
+ 'CefThreadId': ['cef_thread_id_t', 'TID_UI'],
+ 'CefTime': ['cef_time_t', 'CefTime()'],
+ 'CefWindowHandle': ['cef_window_handle_t', 'kNullWindowHandle'],
+}
+
+
+def get_function_impls(content, ident, has_impl=True):
+ """ Retrieve the function parts from the specified contents as a set of
+ return value, name, arguments and body. Ident must occur somewhere in
+ the value.
+ """
+ # extract the functions
+ find_regex = '\n' + _cre_func + '\((.*?)\)([A-Za-z0-9_\s]{0,})'
+ if has_impl:
+ find_regex += '\{(.*?)\n\}'
+ else:
+ find_regex += '(;)'
+ p = re.compile(find_regex, re.MULTILINE | re.DOTALL)
+ list = p.findall(content)
+
+ # build the function map with the function name as the key
+ result = []
+ for retval, argval, vfmod, body in list:
+ if retval.find(ident) < 0:
+ # the identifier was not found
+ continue
+
+ # remove the identifier
+ retval = retval.replace(ident, '')
+ retval = retval.strip()
+
+ # Normalize the delimiter.
+ retval = retval.replace('\n', ' ')
+
+ # retrieve the function name
+ parts = retval.split(' ')
+ name = parts[-1]
+ del parts[-1]
+ retval = ' '.join(parts)
+
+ # parse the arguments
+ args = []
+ if argval != 'void':
+ for v in argval.split(','):
+ v = v.strip()
+ if len(v) > 0:
+ args.append(v)
+
+ result.append({
+ 'retval': retval.strip(),
+ 'name': name,
+ 'args': args,
+ 'vfmod': vfmod.strip(),
+ 'body': body if has_impl else '',
+ })
+
+ return result
+
+
+def get_next_function_impl(existing, name):
+ result = None
+ for item in existing:
+ if item['name'] == name:
+ result = item
+ existing.remove(item)
+ break
+ return result
+
+
+def get_copyright(full=False, translator=True):
+ if full:
+ result = \
+"""// Copyright (c) $YEAR$ Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+"""
+ else:
+ result = \
+"""// Copyright (c) $YEAR$ The Chromium Embedded Framework Authors. All rights
+// reserved. Use of this source code is governed by a BSD-style license that
+// can be found in the LICENSE file.
+"""
+
+ if translator:
+ result += \
+"""//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool. If making changes by
+// hand only do so within the body of existing method and function
+// implementations. See the translator.README.txt file in the tools directory
+// for more information.
+//
+// $hash=$$HASH$$$
+//
+
+"""
+
+ # add the copyright year
+ return result.replace('$YEAR$', get_year())
+
+
+class obj_header:
+ """ Class representing a C++ header file. """
+
+ def __init__(self):
+ self.filenames = []
+ self.typedefs = []
+ self.funcs = []
+ self.classes = []
+ self.root_directory = None
+
+ def set_root_directory(self, root_directory):
+ """ Set the root directory. """
+ self.root_directory = root_directory
+
+ def get_root_directory(self):
+ """ Get the root directory. """
+ return self.root_directory
+
+ def add_directory(self, directory, excluded_files=[]):
+ """ Add all header files from the specified directory. """
+ files = get_files(os.path.join(directory, '*.h'))
+ for file in files:
+ if len(excluded_files) == 0 or \
+ not os.path.split(file)[1] in excluded_files:
+ self.add_file(file)
+
+ def add_file(self, filepath):
+ """ Add a header file. """
+
+ if self.root_directory is None:
+ filename = os.path.split(filepath)[1]
+ else:
+ filename = os.path.relpath(filepath, self.root_directory)
+ filename = filename.replace('\\', '/')
+
+ # read the input file into memory
+ self.add_data(filename, read_file(filepath))
+
+ def add_data(self, filename, data):
+ """ Add header file contents. """
+
+ added = False
+
+ # remove space from between template definition end brackets
+ data = data.replace("> >", ">>")
+
+ # extract global typedefs
+ p = re.compile('\ntypedef' + _cre_space + _cre_typedef + ';',
+ re.MULTILINE | re.DOTALL)
+ list = p.findall(data)
+ if len(list) > 0:
+ # build the global typedef objects
+ for value in list:
+ pos = value.rfind(' ')
+ if pos < 0:
+ raise Exception('Invalid typedef: ' + value)
+ alias = value[pos + 1:].strip()
+ value = value[:pos].strip()
+ self.typedefs.append(obj_typedef(self, filename, value, alias))
+
+ # extract global functions
+ p = re.compile('\n' + _cre_attrib + '\n' + _cre_func + '\((.*?)\)',
+ re.MULTILINE | re.DOTALL)
+ list = p.findall(data)
+ if len(list) > 0:
+ added = True
+
+ # build the global function objects
+ for attrib, retval, argval in list:
+ comment = get_comment(data, retval + '(' + argval + ');')
+ validate_comment(filename, retval, comment)
+ self.funcs.append(
+ obj_function(self, filename, attrib, retval, argval, comment))
+
+ # extract includes
+ p = re.compile('\n#include \"include/' + _cre_cfnameorpath + '.h')
+ includes = p.findall(data)
+
+ # extract forward declarations
+ p = re.compile('\nclass' + _cre_space + _cre_cfname + ';')
+ forward_declares = p.findall(data)
+
+ # extract empty classes
+ p = re.compile('\n' + _cre_attrib + '\nclass' + _cre_space + _cre_cfname +
+ _cre_space + ':' + _cre_space + 'public' + _cre_virtual +
+ _cre_space + _cre_cfname + _cre_space + '{};',
+ re.MULTILINE | re.DOTALL)
+ list = p.findall(data)
+ if len(list) > 0:
+ added = True
+
+ # build the class objects
+ for attrib, name, parent_name in list:
+ # Style may place the ':' on the next line.
+ comment = get_comment(data, name + ' :')
+ if len(comment) == 0:
+ comment = get_comment(data, name + "\n")
+ validate_comment(filename, name, comment)
+ self.classes.append(
+ obj_class(self, filename, attrib, name, parent_name, "", comment,
+ includes, forward_declares))
+
+ # Remove empty classes from |data| so we don't mess up the non-empty
+ # class search that follows.
+ data = p.sub('', data)
+
+ # extract classes
+ p = re.compile('\n' + _cre_attrib + '\nclass' + _cre_space + _cre_cfname +
+ _cre_space + ':' + _cre_space + 'public' + _cre_virtual +
+ _cre_space + _cre_cfname + _cre_space + '{(.*?)\n};',
+ re.MULTILINE | re.DOTALL)
+ list = p.findall(data)
+ if len(list) > 0:
+ added = True
+
+ # build the class objects
+ for attrib, name, parent_name, body in list:
+ # Style may place the ':' on the next line.
+ comment = get_comment(data, name + ' :')
+ if len(comment) == 0:
+ comment = get_comment(data, name + "\n")
+ validate_comment(filename, name, comment)
+ self.classes.append(
+ obj_class(self, filename, attrib, name, parent_name, body, comment,
+ includes, forward_declares))
+
+ if added:
+ # a global function or class was read from the header file
+ self.filenames.append(filename)
+
+ def __repr__(self):
+ result = ''
+
+ if len(self.typedefs) > 0:
+ strlist = []
+ for cls in self.typedefs:
+ strlist.append(str(cls))
+ result += "\n".join(strlist) + "\n\n"
+
+ if len(self.funcs) > 0:
+ strlist = []
+ for cls in self.funcs:
+ strlist.append(str(cls))
+ result += "\n".join(strlist) + "\n\n"
+
+ if len(self.classes) > 0:
+ strlist = []
+ for cls in self.classes:
+ strlist.append(str(cls))
+ result += "\n".join(strlist)
+
+ return result
+
+ def get_file_names(self):
+ """ Return the array of header file names. """
+ return self.filenames
+
+ def get_typedefs(self):
+ """ Return the array of typedef objects. """
+ return self.typedefs
+
+ def get_funcs(self, filename=None):
+ """ Return the array of function objects. """
+ if filename is None:
+ return self.funcs
+ else:
+ # only return the functions in the specified file
+ res = []
+ for func in self.funcs:
+ if func.get_file_name() == filename:
+ res.append(func)
+ return res
+
+ def get_classes(self, filename=None):
+ """ Return the array of class objects. """
+ if filename is None:
+ return self.classes
+ else:
+ # only return the classes in the specified file
+ res = []
+ for cls in self.classes:
+ if cls.get_file_name() == filename:
+ res.append(cls)
+ return res
+
+ def get_class(self, classname, defined_structs=None):
+ """ Return the specified class or None if not found. """
+ for cls in self.classes:
+ if cls.get_name() == classname:
+ return cls
+ elif not defined_structs is None:
+ defined_structs.append(cls.get_capi_name())
+ return None
+
+ def get_class_names(self):
+ """ Returns the names of all classes in this object. """
+ result = []
+ for cls in self.classes:
+ result.append(cls.get_name())
+ return result
+
+ def get_base_class_name(self, classname):
+ """ Returns the base (root) class name for |classname|. """
+ cur_cls = self.get_class(classname)
+ while True:
+ parent_name = cur_cls.get_parent_name()
+ if is_base_class(parent_name):
+ return parent_name
+ else:
+ parent_cls = self.get_class(parent_name)
+ if parent_cls is None:
+ break
+ cur_cls = self.get_class(parent_name)
+ return None
+
+ def get_types(self, list):
+ """ Return a dictionary mapping data types to analyzed values. """
+ for cls in self.typedefs:
+ cls.get_types(list)
+
+ for cls in self.classes:
+ cls.get_types(list)
+
+ def get_alias_translation(self, alias):
+ """ Return a translation of alias to value based on typedef
+ statements. """
+ for cls in self.typedefs:
+ if cls.alias == alias:
+ return cls.value
+ return None
+
+ def get_analysis(self, value, named=True):
+ """ Return an analysis of the value based the header file context. """
+ return obj_analysis([self], value, named)
+
+ def get_defined_structs(self):
+ """ Return a list of already defined structure names. """
+ return [
+ 'cef_print_info_t', 'cef_window_info_t', 'cef_base_ref_counted_t',
+ 'cef_base_scoped_t'
+ ]
+
+ def get_capi_translations(self):
+ """ Return a dictionary that maps C++ terminology to C API terminology.
+ """
+ # strings that will be changed in C++ comments
+ map = {
+ 'class': 'structure',
+ 'Class': 'Structure',
+ 'interface': 'structure',
+ 'Interface': 'Structure',
+ 'true': 'true (1)',
+ 'false': 'false (0)',
+ 'empty': 'NULL',
+ 'method': 'function'
+ }
+
+ # add mappings for all classes and functions
+ funcs = self.get_funcs()
+ for func in funcs:
+ map[func.get_name() + '()'] = func.get_capi_name() + '()'
+
+ classes = self.get_classes()
+ for cls in classes:
+ map[cls.get_name()] = cls.get_capi_name()
+
+ funcs = cls.get_virtual_funcs()
+ for func in funcs:
+ map[func.get_name() + '()'] = func.get_capi_name() + '()'
+
+ funcs = cls.get_static_funcs()
+ for func in funcs:
+ map[func.get_name() + '()'] = func.get_capi_name() + '()'
+
+ return map
+
+
+class obj_class:
+ """ Class representing a C++ class. """
+
+ def __init__(self, parent, filename, attrib, name, parent_name, body, comment,
+ includes, forward_declares):
+ if not isinstance(parent, obj_header):
+ raise Exception('Invalid parent object type')
+
+ self.parent = parent
+ self.filename = filename
+ self.attribs = str_to_dict(attrib)
+ self.name = name
+ self.parent_name = parent_name
+ self.comment = comment
+ self.includes = includes
+ self.forward_declares = forward_declares
+
+ # extract typedefs
+ p = re.compile(
+ '\n' + _cre_space + 'typedef' + _cre_space + _cre_typedef + ';',
+ re.MULTILINE | re.DOTALL)
+ list = p.findall(body)
+
+ # build the typedef objects
+ self.typedefs = []
+ for value in list:
+ pos = value.rfind(' ')
+ if pos < 0:
+ raise Exception('Invalid typedef: ' + value)
+ alias = value[pos + 1:].strip()
+ value = value[:pos].strip()
+ self.typedefs.append(obj_typedef(self, filename, value, alias))
+
+ # extract static functions
+ p = re.compile('\n' + _cre_space + _cre_attrib + '\n' + _cre_space +
+ 'static' + _cre_space + _cre_func + '\((.*?)\)',
+ re.MULTILINE | re.DOTALL)
+ list = p.findall(body)
+
+ # build the static function objects
+ self.staticfuncs = []
+ for attrib, retval, argval in list:
+ comment = get_comment(body, retval + '(' + argval + ')')
+ validate_comment(filename, retval, comment)
+ self.staticfuncs.append(
+ obj_function_static(self, attrib, retval, argval, comment))
+
+ # extract virtual functions
+ p = re.compile(
+ '\n' + _cre_space + _cre_attrib + '\n' + _cre_space + 'virtual' +
+ _cre_space + _cre_func + '\((.*?)\)' + _cre_vfmod,
+ re.MULTILINE | re.DOTALL)
+ list = p.findall(body)
+
+ # build the virtual function objects
+ self.virtualfuncs = []
+ for attrib, retval, argval, vfmod in list:
+ comment = get_comment(body, retval + '(' + argval + ')')
+ validate_comment(filename, retval, comment)
+ self.virtualfuncs.append(
+ obj_function_virtual(self, attrib, retval, argval, comment,
+ vfmod.strip()))
+
+ def __repr__(self):
+ result = '/* ' + dict_to_str(
+ self.attribs) + ' */ class ' + self.name + "\n{"
+
+ if len(self.typedefs) > 0:
+ result += "\n\t"
+ strlist = []
+ for cls in self.typedefs:
+ strlist.append(str(cls))
+ result += "\n\t".join(strlist)
+
+ if len(self.staticfuncs) > 0:
+ result += "\n\t"
+ strlist = []
+ for cls in self.staticfuncs:
+ strlist.append(str(cls))
+ result += "\n\t".join(strlist)
+
+ if len(self.virtualfuncs) > 0:
+ result += "\n\t"
+ strlist = []
+ for cls in self.virtualfuncs:
+ strlist.append(str(cls))
+ result += "\n\t".join(strlist)
+
+ result += "\n};\n"
+ return result
+
+ def get_file_name(self):
+ """ Return the C++ header file name. Includes the directory component,
+ if any. """
+ return self.filename
+
+ def get_capi_file_name(self):
+ """ Return the CAPI header file name. Includes the directory component,
+ if any. """
+ return get_capi_file_name(self.filename)
+
+ def get_file_directory(self):
+ """ Return the file directory component, if any. """
+ pos = self.filename.rfind('/')
+ if pos >= 0:
+ return self.filename[:pos]
+ return None
+
+ def get_name(self):
+ """ Return the class name. """
+ return self.name
+
+ def get_capi_name(self):
+ """ Return the CAPI structure name for this class. """
+ return get_capi_name(self.name, True)
+
+ def get_parent_name(self):
+ """ Return the parent class name. """
+ return self.parent_name
+
+ def get_parent_capi_name(self):
+ """ Return the CAPI structure name for the parent class. """
+ return get_capi_name(self.parent_name, True)
+
+ def has_parent(self, parent_name):
+ """ Returns true if this class has the specified class anywhere in its
+ inheritance hierarchy. """
+ # Every class has a known base class as the top-most parent.
+ if is_base_class(parent_name) or parent_name == self.parent_name:
+ return True
+ if is_base_class(self.parent_name):
+ return False
+
+ cur_cls = self.parent.get_class(self.parent_name)
+ while True:
+ cur_parent_name = cur_cls.get_parent_name()
+ if is_base_class(cur_parent_name):
+ break
+ elif cur_parent_name == parent_name:
+ return True
+ cur_cls = self.parent.get_class(cur_parent_name)
+
+ return False
+
+ def get_comment(self):
+ """ Return the class comment as an array of lines. """
+ return self.comment
+
+ def get_includes(self):
+ """ Return the list of classes that are included from this class'
+ header file. """
+ return self.includes
+
+ def get_forward_declares(self):
+ """ Return the list of classes that are forward declared for this
+ class. """
+ return self.forward_declares
+
+ def get_attribs(self):
+ """ Return all attributes as a dictionary. """
+ return self.attribs
+
+ def has_attrib(self, name):
+ """ Return true if the specified attribute exists. """
+ return name in self.attribs
+
+ def get_attrib(self, name):
+ """ Return the first or only value for specified attribute. """
+ if name in self.attribs:
+ if isinstance(self.attribs[name], list):
+ # the value is a list
+ return self.attribs[name][0]
+ else:
+ # the value is a string
+ return self.attribs[name]
+ return None
+
+ def get_attrib_list(self, name):
+ """ Return all values for specified attribute as a list. """
+ if name in self.attribs:
+ if isinstance(self.attribs[name], list):
+ # the value is already a list
+ return self.attribs[name]
+ else:
+ # convert the value to a list
+ return [self.attribs[name]]
+ return None
+
+ def get_typedefs(self):
+ """ Return the array of typedef objects. """
+ return self.typedefs
+
+ def has_typedef_alias(self, alias):
+ """ Returns true if the specified typedef alias is defined in the scope
+ of this class declaration. """
+ for typedef in self.typedefs:
+ if typedef.get_alias() == alias:
+ return True
+ return False
+
+ def get_static_funcs(self):
+ """ Return the array of static function objects. """
+ return self.staticfuncs
+
+ def get_virtual_funcs(self):
+ """ Return the array of virtual function objects. """
+ return self.virtualfuncs
+
+ def get_types(self, list):
+ """ Return a dictionary mapping data types to analyzed values. """
+ for cls in self.typedefs:
+ cls.get_types(list)
+
+ for cls in self.staticfuncs:
+ cls.get_types(list)
+
+ for cls in self.virtualfuncs:
+ cls.get_types(list)
+
+ def get_alias_translation(self, alias):
+ for cls in self.typedefs:
+ if cls.alias == alias:
+ return cls.value
+ return None
+
+ def get_analysis(self, value, named=True):
+ """ Return an analysis of the value based on the class definition
+ context.
+ """
+ return obj_analysis([self, self.parent], value, named)
+
+ def is_library_side(self):
+ """ Returns true if the class is implemented by the library. """
+ return self.attribs['source'] == 'library'
+
+ def is_client_side(self):
+ """ Returns true if the class is implemented by the client. """
+ return self.attribs['source'] == 'client'
+
+
+class obj_typedef:
+ """ Class representing a typedef statement. """
+
+ def __init__(self, parent, filename, value, alias):
+ if not isinstance(parent, obj_header) \
+ and not isinstance(parent, obj_class):
+ raise Exception('Invalid parent object type')
+
+ self.parent = parent
+ self.filename = filename
+ self.alias = alias
+ self.value = self.parent.get_analysis(value, False)
+
+ def __repr__(self):
+ return 'typedef ' + self.value.get_type() + ' ' + self.alias + ';'
+
+ def get_file_name(self):
+ """ Return the C++ header file name. """
+ return self.filename
+
+ def get_capi_file_name(self):
+ """ Return the CAPI header file name. """
+ return get_capi_file_name(self.filename)
+
+ def get_alias(self):
+ """ Return the alias. """
+ return self.alias
+
+ def get_value(self):
+ """ Return an analysis of the value based on the class or header file
+ definition context.
+ """
+ return self.value
+
+ def get_types(self, list):
+ """ Return a dictionary mapping data types to analyzed values. """
+ name = self.value.get_type()
+ if not name in list:
+ list[name] = self.value
+
+
+class obj_function:
+ """ Class representing a function. """
+
+ def __init__(self, parent, filename, attrib, retval, argval, comment):
+ self.parent = parent
+ self.filename = filename
+ self.attribs = str_to_dict(attrib)
+ self.retval = obj_argument(self, retval)
+ self.name = self.retval.remove_name()
+ self.comment = comment
+
+ # build the argument objects
+ self.arguments = []
+ arglist = argval.split(',')
+ argindex = 0
+ while argindex < len(arglist):
+ arg = arglist[argindex]
+ if arg.find('<') >= 0 and arg.find('>') == -1:
+ # We've split inside of a template type declaration. Join the
+ # next argument with this argument.
+ argindex += 1
+ arg += ',' + arglist[argindex]
+
+ arg = arg.strip()
+ if len(arg) > 0:
+ argument = obj_argument(self, arg)
+ if argument.needs_attrib_count_func() and \
+ argument.get_attrib_count_func() is None:
+ raise Exception("A 'count_func' attribute is required "+ \
+ "for the '"+argument.get_name()+ \
+ "' parameter to "+self.get_qualified_name())
+ self.arguments.append(argument)
+
+ argindex += 1
+
+ if self.retval.needs_attrib_default_retval() and \
+ self.retval.get_attrib_default_retval() is None:
+ raise Exception("A 'default_retval' attribute is required for "+ \
+ self.get_qualified_name())
+
+ def __repr__(self):
+ return '/* ' + dict_to_str(self.attribs) + ' */ ' + self.get_cpp_proto()
+
+ def get_file_name(self):
+ """ Return the C++ header file name. """
+ return self.filename
+
+ def get_capi_file_name(self):
+ """ Return the CAPI header file name. """
+ return get_capi_file_name(self.filename)
+
+ def get_name(self):
+ """ Return the function name. """
+ return self.name
+
+ def get_qualified_name(self):
+ """ Return the fully qualified function name. """
+ if isinstance(self.parent, obj_header):
+ # global function
+ return self.name
+ else:
+ # member function
+ return self.parent.get_name() + '::' + self.name
+
+ def get_capi_name(self, prefix=None):
+ """ Return the CAPI function name. """
+ if 'capi_name' in self.attribs:
+ return self.attribs['capi_name']
+ return get_capi_name(self.name, False, prefix)
+
+ def get_comment(self):
+ """ Return the function comment as an array of lines. """
+ return self.comment
+
+ def get_attribs(self):
+ """ Return all attributes as a dictionary. """
+ return self.attribs
+
+ def has_attrib(self, name):
+ """ Return true if the specified attribute exists. """
+ return name in self.attribs
+
+ def get_attrib(self, name):
+ """ Return the first or only value for specified attribute. """
+ if name in self.attribs:
+ if isinstance(self.attribs[name], list):
+ # the value is a list
+ return self.attribs[name][0]
+ else:
+ # the value is a string
+ return self.attribs[name]
+ return None
+
+ def get_attrib_list(self, name):
+ """ Return all values for specified attribute as a list. """
+ if name in self.attribs:
+ if isinstance(self.attribs[name], list):
+ # the value is already a list
+ return self.attribs[name]
+ else:
+ # convert the value to a list
+ return [self.attribs[name]]
+ return None
+
+ def get_retval(self):
+ """ Return the return value object. """
+ return self.retval
+
+ def get_arguments(self):
+ """ Return the argument array. """
+ return self.arguments
+
+ def get_types(self, list):
+ """ Return a dictionary mapping data types to analyzed values. """
+ for cls in self.arguments:
+ cls.get_types(list)
+
+ def get_capi_parts(self, defined_structs=[], isimpl=False, prefix=None):
+ """ Return the parts of the C API function definition. """
+ retval = ''
+ dict = self.retval.get_type().get_capi(defined_structs)
+ if dict['format'] == 'single':
+ retval = dict['value']
+
+ name = self.get_capi_name(prefix)
+ args = []
+
+ if isinstance(self, obj_function_virtual):
+ # virtual functions get themselves as the first argument
+ str = 'struct _' + self.parent.get_capi_name() + '* self'
+ if isinstance(self, obj_function_virtual) and self.is_const():
+ # const virtual functions get const self pointers
+ str = 'const ' + str
+ args.append(str)
+ elif not isimpl and len(self.arguments) == 0:
+ args.append('void')
+
+ if len(self.arguments) > 0:
+ for cls in self.arguments:
+ type = cls.get_type()
+ dict = type.get_capi(defined_structs)
+ if dict['format'] == 'single':
+ args.append(dict['value'])
+ elif dict['format'] == 'multi-arg':
+ # add an additional argument for the size of the array
+ type_name = type.get_name()
+ if type.is_const():
+ # for const arrays pass the size argument by value
+ args.append('size_t ' + type_name + 'Count')
+ else:
+ # for non-const arrays pass the size argument by address
+ args.append('size_t* ' + type_name + 'Count')
+ args.append(dict['value'])
+
+ return {'retval': retval, 'name': name, 'args': args}
+
+ def get_capi_proto(self, defined_structs=[], isimpl=False, prefix=None):
+ """ Return the prototype of the C API function. """
+ parts = self.get_capi_parts(defined_structs, isimpl, prefix)
+ result = parts['retval']+' '+parts['name']+ \
+ '('+', '.join(parts['args'])+')'
+ return result
+
+ def get_cpp_parts(self, isimpl=False):
+ """ Return the parts of the C++ function definition. """
+ retval = str(self.retval)
+ name = self.name
+
+ args = []
+ if len(self.arguments) > 0:
+ for cls in self.arguments:
+ args.append(str(cls))
+
+ if isimpl and isinstance(self, obj_function_virtual):
+ # enumeration return values must be qualified with the class name
+ # if the type is defined in the class declaration scope.
+ type = self.get_retval().get_type()
+ if type.is_result_struct() and type.is_result_struct_enum() and \
+ self.parent.has_typedef_alias(retval):
+ retval = self.parent.get_name() + '::' + retval
+
+ return {'retval': retval, 'name': name, 'args': args}
+
+ def get_cpp_proto(self, classname=None):
+ """ Return the prototype of the C++ function. """
+ parts = self.get_cpp_parts()
+ result = parts['retval'] + ' '
+ if not classname is None:
+ result += classname + '::'
+ result += parts['name'] + '(' + ', '.join(parts['args']) + ')'
+ if isinstance(self, obj_function_virtual) and self.is_const():
+ result += ' const'
+ return result
+
+ def is_same_side(self, other_class_name):
+ """ Returns true if this function is on the same side (library or
+ client) and the specified class. """
+ if isinstance(self.parent, obj_class):
+ # this function is part of a class
+ this_is_library_side = self.parent.is_library_side()
+ header = self.parent.parent
+ else:
+ # this function is global
+ this_is_library_side = True
+ header = self.parent
+
+ if is_base_class(other_class_name):
+ other_is_library_side = False
+ else:
+ other_class = header.get_class(other_class_name)
+ if other_class is None:
+ raise Exception('Unknown class: ' + other_class_name)
+ other_is_library_side = other_class.is_library_side()
+
+ return other_is_library_side == this_is_library_side
+
+
+class obj_function_static(obj_function):
+ """ Class representing a static function. """
+
+ def __init__(self, parent, attrib, retval, argval, comment):
+ if not isinstance(parent, obj_class):
+ raise Exception('Invalid parent object type')
+ obj_function.__init__(self, parent, parent.filename, attrib, retval, argval,
+ comment)
+
+ def __repr__(self):
+ return 'static ' + obj_function.__repr__(self) + ';'
+
+ def get_capi_name(self, prefix=None):
+ """ Return the CAPI function name. """
+ if prefix is None:
+ # by default static functions are prefixed with the class name
+ prefix = get_capi_name(self.parent.get_name(), False)
+ return obj_function.get_capi_name(self, prefix)
+
+
+class obj_function_virtual(obj_function):
+ """ Class representing a virtual function. """
+
+ def __init__(self, parent, attrib, retval, argval, comment, vfmod):
+ if not isinstance(parent, obj_class):
+ raise Exception('Invalid parent object type')
+ obj_function.__init__(self, parent, parent.filename, attrib, retval, argval,
+ comment)
+ if vfmod == 'const':
+ self.isconst = True
+ else:
+ self.isconst = False
+
+ def __repr__(self):
+ return 'virtual ' + obj_function.__repr__(self) + ';'
+
+ def is_const(self):
+ """ Returns true if the method declaration is const. """
+ return self.isconst
+
+
+class obj_argument:
+ """ Class representing a function argument. """
+
+ def __init__(self, parent, argval):
+ if not isinstance(parent, obj_function):
+ raise Exception('Invalid parent object type')
+
+ self.parent = parent
+ self.type = self.parent.parent.get_analysis(argval)
+
+ def __repr__(self):
+ result = ''
+ if self.type.is_const():
+ result += 'const '
+ result += self.type.get_type()
+ if self.type.is_byref():
+ result += '&'
+ elif self.type.is_byaddr():
+ result += '*'
+ if self.type.has_name():
+ result += ' ' + self.type.get_name()
+ return result
+
+ def get_name(self):
+ """ Return the name for this argument. """
+ return self.type.get_name()
+
+ def remove_name(self):
+ """ Remove and return the name value. """
+ name = self.type.get_name()
+ self.type.name = None
+ return name
+
+ def get_type(self):
+ """ Return an analysis of the argument type based on the class
+ definition context.
+ """
+ return self.type
+
+ def get_types(self, list):
+ """ Return a dictionary mapping data types to analyzed values. """
+ name = self.type.get_type()
+ if not name in list:
+ list[name] = self.type
+
+ def needs_attrib_count_func(self):
+ """ Returns true if this argument requires a 'count_func' attribute. """
+ # A 'count_func' attribute is required for non-const non-string vector
+ # attribute types
+ return self.type.has_name() and \
+ self.type.is_result_vector() and \
+ not self.type.is_result_vector_string() and \
+ not self.type.is_const()
+
+ def get_attrib_count_func(self):
+ """ Returns the count function for this argument. """
+ # The 'count_func' attribute value format is name:function
+ if not self.parent.has_attrib('count_func'):
+ return None
+ name = self.type.get_name()
+ vals = self.parent.get_attrib_list('count_func')
+ for val in vals:
+ parts = val.split(':')
+ if len(parts) != 2:
+ raise Exception("Invalid 'count_func' attribute value for "+ \
+ self.parent.get_qualified_name()+': '+val)
+ if parts[0].strip() == name:
+ return parts[1].strip()
+ return None
+
+ def needs_attrib_default_retval(self):
+ """ Returns true if this argument requires a 'default_retval' attribute.
+ """
+ # A 'default_retval' attribute is required for enumeration return value
+ # types.
+ return not self.type.has_name() and \
+ self.type.is_result_struct() and \
+ self.type.is_result_struct_enum()
+
+ def get_attrib_default_retval(self):
+ """ Returns the defualt return value for this argument. """
+ return self.parent.get_attrib('default_retval')
+
+ def get_arg_type(self):
+ """ Returns the argument type as defined in translator.README.txt. """
+ if not self.type.has_name():
+ raise Exception('Cannot be called for retval types')
+
+ # simple or enumeration type
+ if (self.type.is_result_simple() and \
+ self.type.get_type() != 'bool') or \
+ (self.type.is_result_struct() and \
+ self.type.is_result_struct_enum()):
+ if self.type.is_byref():
+ if self.type.is_const():
+ return 'simple_byref_const'
+ return 'simple_byref'
+ elif self.type.is_byaddr():
+ return 'simple_byaddr'
+ return 'simple_byval'
+
+ # boolean type
+ if self.type.get_type() == 'bool':
+ if self.type.is_byref():
+ return 'bool_byref'
+ elif self.type.is_byaddr():
+ return 'bool_byaddr'
+ return 'bool_byval'
+
+ # structure type
+ if self.type.is_result_struct() and self.type.is_byref():
+ if self.type.is_const():
+ return 'struct_byref_const'
+ return 'struct_byref'
+
+ # string type
+ if self.type.is_result_string() and self.type.is_byref():
+ if self.type.is_const():
+ return 'string_byref_const'
+ return 'string_byref'
+
+ # *ptr type
+ if self.type.is_result_ptr():
+ prefix = self.type.get_result_ptr_type_prefix()
+ same_side = self.parent.is_same_side(self.type.get_ptr_type())
+ if self.type.is_byref():
+ if same_side:
+ return prefix + 'ptr_same_byref'
+ return prefix + 'ptr_diff_byref'
+ if same_side:
+ return prefix + 'ptr_same'
+ return prefix + 'ptr_diff'
+
+ if self.type.is_result_vector():
+ # all vector types must be passed by reference
+ if not self.type.is_byref():
+ return 'invalid'
+
+ if self.type.is_result_vector_string():
+ # string vector type
+ if self.type.is_const():
+ return 'string_vec_byref_const'
+ return 'string_vec_byref'
+
+ if self.type.is_result_vector_simple():
+ if self.type.get_vector_type() != 'bool':
+ # simple/enumeration vector types
+ if self.type.is_const():
+ return 'simple_vec_byref_const'
+ return 'simple_vec_byref'
+
+ # boolean vector types
+ if self.type.is_const():
+ return 'bool_vec_byref_const'
+ return 'bool_vec_byref'
+
+ if self.type.is_result_vector_ptr():
+ # *ptr vector types
+ prefix = self.type.get_result_vector_ptr_type_prefix()
+ same_side = self.parent.is_same_side(self.type.get_ptr_type())
+ if self.type.is_const():
+ if same_side:
+ return prefix + 'ptr_vec_same_byref_const'
+ return prefix + 'ptr_vec_diff_byref_const'
+ if same_side:
+ return prefix + 'ptr_vec_same_byref'
+ return prefix + 'ptr_vec_diff_byref'
+
+ # string single map type
+ if self.type.is_result_map_single():
+ if not self.type.is_byref():
+ return 'invalid'
+ if self.type.is_const():
+ return 'string_map_single_byref_const'
+ return 'string_map_single_byref'
+
+ # string multi map type
+ if self.type.is_result_map_multi():
+ if not self.type.is_byref():
+ return 'invalid'
+ if self.type.is_const():
+ return 'string_map_multi_byref_const'
+ return 'string_map_multi_byref'
+
+ return 'invalid'
+
+ def get_retval_type(self):
+ """ Returns the retval type as defined in translator.README.txt. """
+ if self.type.has_name():
+ raise Exception('Cannot be called for argument types')
+
+ # unsupported modifiers
+ if self.type.is_const() or self.type.is_byref() or \
+ self.type.is_byaddr():
+ return 'invalid'
+
+ # void types don't have a return value
+ if self.type.get_type() == 'void':
+ return 'none'
+
+ if (self.type.is_result_simple() and \
+ self.type.get_type() != 'bool') or \
+ (self.type.is_result_struct() and self.type.is_result_struct_enum()):
+ return 'simple'
+
+ if self.type.get_type() == 'bool':
+ return 'bool'
+
+ if self.type.is_result_string():
+ return 'string'
+
+ if self.type.is_result_ptr():
+ prefix = self.type.get_result_ptr_type_prefix()
+ if self.parent.is_same_side(self.type.get_ptr_type()):
+ return prefix + 'ptr_same'
+ else:
+ return prefix + 'ptr_diff'
+
+ return 'invalid'
+
+ def get_retval_default(self, for_capi):
+ """ Returns the default return value based on the retval type. """
+ # start with the default retval attribute, if any.
+ retval = self.get_attrib_default_retval()
+ if not retval is None:
+ if for_capi:
+ # apply any appropriate C API translations.
+ if retval == 'true':
+ return '1'
+ if retval == 'false':
+ return '0'
+ return retval
+
+ # next look at the retval type value.
+ type = self.get_retval_type()
+ if type == 'simple':
+ return self.get_type().get_result_simple_default()
+ elif type == 'bool':
+ if for_capi:
+ return '0'
+ return 'false'
+ elif type == 'string':
+ if for_capi:
+ return 'NULL'
+ return 'CefString()'
+ elif type == 'refptr_same' or type == 'refptr_diff' or \
+ type == 'rawptr_same' or type == 'rawptr_diff':
+ if for_capi:
+ return 'NULL'
+ return 'nullptr'
+ elif type == 'ownptr_same' or type == 'ownptr_diff':
+ if for_capi:
+ return 'NULL'
+ return 'CefOwnPtr<' + self.type.get_ptr_type() + '>()'
+
+ return ''
+
+
+class obj_analysis:
+ """ Class representing an analysis of a data type value. """
+
+ def __init__(self, scopelist, value, named):
+ self.value = value
+ self.result_type = 'unknown'
+ self.result_value = None
+ self.result_default = None
+ self.ptr_type = None
+
+ # parse the argument string
+ partlist = value.strip().split()
+
+ if named == True:
+ # extract the name value
+ self.name = partlist[-1]
+ del partlist[-1]
+ else:
+ self.name = None
+
+ if len(partlist) == 0:
+ raise Exception('Invalid argument value: ' + value)
+
+ # check const status
+ if partlist[0] == 'const':
+ self.isconst = True
+ del partlist[0]
+ else:
+ self.isconst = False
+
+ if len(partlist) == 0:
+ raise Exception('Invalid argument value: ' + value)
+
+ # combine the data type
+ self.type = ' '.join(partlist)
+
+ # extract the last character of the data type
+ endchar = self.type[-1]
+
+ # check if the value is passed by reference
+ if endchar == '&':
+ self.isbyref = True
+ self.type = self.type[:-1]
+ else:
+ self.isbyref = False
+
+ # check if the value is passed by address
+ if endchar == '*':
+ self.isbyaddr = True
+ self.type = self.type[:-1]
+ else:
+ self.isbyaddr = False
+
+ # see if the value is directly identifiable
+ if self._check_advanced(self.type) == True:
+ return
+
+ # not identifiable, so look it up
+ translation = None
+ for scope in scopelist:
+ if not isinstance(scope, obj_header) \
+ and not isinstance(scope, obj_class):
+ raise Exception('Invalid scope object type')
+ translation = scope.get_alias_translation(self.type)
+ if not translation is None:
+ break
+
+ if translation is None:
+ raise Exception('Failed to translate type: ' + self.type)
+
+ # the translation succeeded so keep the result
+ self.result_type = translation.result_type
+ self.result_value = translation.result_value
+
+ def _check_advanced(self, value):
+ # check for vectors
+ if value.find('std::vector') == 0:
+ self.result_type = 'vector'
+ val = value[12:-1].strip()
+ self.result_value = [self._get_basic(val)]
+ self.result_value[0]['vector_type'] = val
+ return True
+
+ # check for maps
+ if value.find('std::map') == 0:
+ self.result_type = 'map'
+ vals = value[9:-1].split(',')
+ if len(vals) == 2:
+ self.result_value = [
+ self._get_basic(vals[0].strip()),
+ self._get_basic(vals[1].strip())
+ ]
+ return True
+
+ # check for multimaps
+ if value.find('std::multimap') == 0:
+ self.result_type = 'multimap'
+ vals = value[14:-1].split(',')
+ if len(vals) == 2:
+ self.result_value = [
+ self._get_basic(vals[0].strip()),
+ self._get_basic(vals[1].strip())
+ ]
+ return True
+
+ # check for basic types
+ basic = self._get_basic(value)
+ if not basic is None:
+ self.result_type = basic['result_type']
+ self.result_value = basic['result_value']
+ if 'ptr_type' in basic:
+ self.ptr_type = basic['ptr_type']
+ if 'result_default' in basic:
+ self.result_default = basic['result_default']
+ return True
+
+ return False
+
+ def _get_basic(self, value):
+ # check for string values
+ if value == "CefString":
+ return {'result_type': 'string', 'result_value': None}
+
+ # check for simple direct translations
+ if value in _simpletypes.keys():
+ return {
+ 'result_type': 'simple',
+ 'result_value': _simpletypes[value][0],
+ 'result_default': _simpletypes[value][1],
+ }
+
+ # check if already a C API structure
+ if value[-2:] == '_t':
+ return {'result_type': 'structure', 'result_value': value}
+
+ # check for CEF reference pointers
+ p = re.compile('^CefRefPtr<(.*?)>$', re.DOTALL)
+ list = p.findall(value)
+ if len(list) == 1:
+ return {
+ 'result_type': 'refptr',
+ 'result_value': get_capi_name(list[0], True) + '*',
+ 'ptr_type': list[0]
+ }
+
+ # check for CEF owned pointers
+ p = re.compile('^CefOwnPtr<(.*?)>$', re.DOTALL)
+ list = p.findall(value)
+ if len(list) == 1:
+ return {
+ 'result_type': 'ownptr',
+ 'result_value': get_capi_name(list[0], True) + '*',
+ 'ptr_type': list[0]
+ }
+
+ # check for CEF raw pointers
+ p = re.compile('^CefRawPtr<(.*?)>$', re.DOTALL)
+ list = p.findall(value)
+ if len(list) == 1:
+ return {
+ 'result_type': 'rawptr',
+ 'result_value': get_capi_name(list[0], True) + '*',
+ 'ptr_type': list[0]
+ }
+
+ # check for CEF structure types
+ if value[0:3] == 'Cef' and value[-4:] != 'List':
+ return {
+ 'result_type': 'structure',
+ 'result_value': get_capi_name(value, True)
+ }
+
+ return None
+
+ def __repr__(self):
+ return '(' + self.result_type + ') ' + str(self.result_value)
+
+ def has_name(self):
+ """ Returns true if a name value exists. """
+ return (not self.name is None)
+
+ def get_name(self):
+ """ Return the name. """
+ return self.name
+
+ def get_value(self):
+ """ Return the C++ value (type + name). """
+ return self.value
+
+ def get_type(self):
+ """ Return the C++ type. """
+ return self.type
+
+ def get_ptr_type(self):
+ """ Return the C++ class type referenced by a CefRefPtr. """
+ if self.is_result_vector() and self.is_result_vector_ptr():
+ # return the vector RefPtr type
+ return self.result_value[0]['ptr_type']
+ # return the basic RefPtr type
+ return self.ptr_type
+
+ def get_vector_type(self):
+ """ Return the C++ class type referenced by a std::vector. """
+ if self.is_result_vector():
+ return self.result_value[0]['vector_type']
+ return None
+
+ def is_const(self):
+ """ Returns true if the argument value is constant. """
+ return self.isconst
+
+ def is_byref(self):
+ """ Returns true if the argument is passed by reference. """
+ return self.isbyref
+
+ def is_byaddr(self):
+ """ Returns true if the argument is passed by address. """
+ return self.isbyaddr
+
+ def is_result_simple(self):
+ """ Returns true if this is a simple argument type. """
+ return (self.result_type == 'simple')
+
+ def get_result_simple_type_root(self):
+ """ Return the simple structure or basic type name. """
+ return self.result_value
+
+ def get_result_simple_type(self):
+ """ Return the simple type. """
+ result = ''
+ if self.is_const():
+ result += 'const '
+ result += self.result_value
+ if self.is_byaddr() or self.is_byref():
+ result += '*'
+ return result
+
+ def get_result_simple_default(self):
+ """ Return the default value fo the basic type. """
+ return self.result_default
+
+ def is_result_ptr(self):
+ """ Returns true if this is a *Ptr type. """
+ return self.is_result_refptr() or self.is_result_ownptr() or \
+ self.is_result_rawptr()
+
+ def get_result_ptr_type_root(self):
+ """ Return the *Ptr type structure name. """
+ return self.result_value[:-1]
+
+ def get_result_ptr_type(self, defined_structs=[]):
+ """ Return the *Ptr type. """
+ result = ''
+ if not self.result_value[:-1] in defined_structs:
+ result += 'struct _'
+ result += self.result_value
+ if self.is_byref() or self.is_byaddr():
+ result += '*'
+ return result
+
+ def get_result_ptr_type_prefix(self):
+ """ Returns the *Ptr type prefix. """
+ if self.is_result_refptr():
+ return 'ref'
+ if self.is_result_ownptr():
+ return 'own'
+ if self.is_result_rawptr():
+ return 'raw'
+ raise Exception('Not a pointer type')
+
+ def is_result_refptr(self):
+ """ Returns true if this is a RefPtr type. """
+ return (self.result_type == 'refptr')
+
+ def is_result_ownptr(self):
+ """ Returns true if this is a OwnPtr type. """
+ return (self.result_type == 'ownptr')
+
+ def is_result_rawptr(self):
+ """ Returns true if this is a RawPtr type. """
+ return (self.result_type == 'rawptr')
+
+ def is_result_struct(self):
+ """ Returns true if this is a structure type. """
+ return (self.result_type == 'structure')
+
+ def is_result_struct_enum(self):
+ """ Returns true if this struct type is likely an enumeration. """
+ # structure values that are passed by reference or address must be
+ # structures and not enumerations
+ if not self.is_byref() and not self.is_byaddr():
+ return True
+ return False
+
+ def get_result_struct_type(self, defined_structs=[]):
+ """ Return the structure or enumeration type. """
+ result = ''
+ is_enum = self.is_result_struct_enum()
+ if not is_enum:
+ if self.is_const():
+ result += 'const '
+ if not self.result_value in defined_structs:
+ result += 'struct _'
+ result += self.result_value
+ if not is_enum:
+ result += '*'
+ return result
+
+ def is_result_string(self):
+ """ Returns true if this is a string type. """
+ return (self.result_type == 'string')
+
+ def get_result_string_type(self):
+ """ Return the string type. """
+ if not self.has_name():
+ # Return values are string structs that the user must free. Use
+ # the name of the structure as a hint.
+ return 'cef_string_userfree_t'
+ elif not self.is_const() and (self.is_byref() or self.is_byaddr()):
+ # Parameters passed by reference or address. Use the normal
+ # non-const string struct.
+ return 'cef_string_t*'
+ # Const parameters use the const string struct.
+ return 'const cef_string_t*'
+
+ def is_result_vector(self):
+ """ Returns true if this is a vector type. """
+ return (self.result_type == 'vector')
+
+ def is_result_vector_string(self):
+ """ Returns true if this is a string vector. """
+ return self.result_value[0]['result_type'] == 'string'
+
+ def is_result_vector_simple(self):
+ """ Returns true if this is a string vector. """
+ return self.result_value[0]['result_type'] == 'simple'
+
+ def is_result_vector_ptr(self):
+ """ Returns true if this is a *Ptr vector. """
+ return self.is_result_vector_refptr() or \
+ self.is_result_vector_ownptr() or \
+ self.is_result_vector_rawptr()
+
+ def get_result_vector_ptr_type_prefix(self):
+ """ Returns the *Ptr type prefix. """
+ if self.is_result_vector_refptr():
+ return 'ref'
+ if self.is_result_vector_ownptr():
+ return 'own'
+ if self.is_result_vector_rawptr():
+ return 'raw'
+ raise Exception('Not a pointer type')
+
+ def is_result_vector_refptr(self):
+ """ Returns true if this is a RefPtr vector. """
+ return self.result_value[0]['result_type'] == 'refptr'
+
+ def is_result_vector_ownptr(self):
+ """ Returns true if this is a OwnPtr vector. """
+ return self.result_value[0]['result_type'] == 'ownptr'
+
+ def is_result_vector_rawptr(self):
+ """ Returns true if this is a RawPtr vector. """
+ return self.result_value[0]['result_type'] == 'rawptr'
+
+ def get_result_vector_type_root(self):
+ """ Return the vector structure or basic type name. """
+ return self.result_value[0]['result_value']
+
+ def get_result_vector_type(self, defined_structs=[]):
+ """ Return the vector type. """
+ if not self.has_name():
+ raise Exception('Cannot use vector as a return type')
+
+ type = self.result_value[0]['result_type']
+ value = self.result_value[0]['result_value']
+
+ result = {}
+ if type == 'string':
+ result['value'] = 'cef_string_list_t'
+ result['format'] = 'single'
+ return result
+
+ if type == 'simple':
+ str = value
+ if self.is_const():
+ str += ' const'
+ str += '*'
+ result['value'] = str
+ elif type == 'refptr' or type == 'ownptr' or type == 'rawptr':
+ str = ''
+ if not value[:-1] in defined_structs:
+ str += 'struct _'
+ str += value
+ if self.is_const():
+ str += ' const'
+ str += '*'
+ result['value'] = str
+ else:
+ raise Exception('Unsupported vector type: ' + type)
+
+ # vector values must be passed as a value array parameter
+ # and a size parameter
+ result['format'] = 'multi-arg'
+ return result
+
+ def is_result_map(self):
+ """ Returns true if this is a map type. """
+ return (self.result_type == 'map' or self.result_type == 'multimap')
+
+ def is_result_map_single(self):
+ """ Returns true if this is a single map type. """
+ return (self.result_type == 'map')
+
+ def is_result_map_multi(self):
+ """ Returns true if this is a multi map type. """
+ return (self.result_type == 'multimap')
+
+ def get_result_map_type(self, defined_structs=[]):
+ """ Return the map type. """
+ if not self.has_name():
+ raise Exception('Cannot use map as a return type')
+ if self.result_value[0]['result_type'] == 'string' \
+ and self.result_value[1]['result_type'] == 'string':
+ if self.result_type == 'map':
+ return {'value': 'cef_string_map_t', 'format': 'single'}
+ elif self.result_type == 'multimap':
+ return {'value': 'cef_string_multimap_t', 'format': 'multi'}
+ raise Exception('Only mappings of strings to strings are supported')
+
+ def get_capi(self, defined_structs=[]):
+ """ Format the value for the C API. """
+ result = ''
+ format = 'single'
+ if self.is_result_simple():
+ result += self.get_result_simple_type()
+ elif self.is_result_ptr():
+ result += self.get_result_ptr_type(defined_structs)
+ elif self.is_result_struct():
+ result += self.get_result_struct_type(defined_structs)
+ elif self.is_result_string():
+ result += self.get_result_string_type()
+ elif self.is_result_map():
+ resdict = self.get_result_map_type(defined_structs)
+ if resdict['format'] == 'single' or resdict['format'] == 'multi':
+ result += resdict['value']
+ else:
+ raise Exception('Unsupported map type')
+ elif self.is_result_vector():
+ resdict = self.get_result_vector_type(defined_structs)
+ if resdict['format'] != 'single':
+ format = resdict['format']
+ result += resdict['value']
+
+ if self.has_name():
+ result += ' ' + self.get_name()
+
+ return {'format': format, 'value': result}
+
+
+# test the module
+if __name__ == "__main__":
+ import pprint
+ import sys
+
+ # verify that the correct number of command-line arguments are provided
+ if len(sys.argv) != 2:
+ sys.stderr.write('Usage: ' + sys.argv[0] + ' <directory>')
+ sys.exit()
+
+ pp = pprint.PrettyPrinter(indent=4)
+
+ # create the header object
+ header = obj_header()
+ header.add_directory(sys.argv[1])
+
+ # output the type mapping
+ types = {}
+ header.get_types(types)
+ pp.pprint(types)
+ sys.stdout.write('\n')
+
+ # output the parsed C++ data
+ sys.stdout.write(str(header))
+
+ # output the C API formatted data
+ defined_names = header.get_defined_structs()
+ result = ''
+
+ # global functions
+ funcs = header.get_funcs()
+ if len(funcs) > 0:
+ for func in funcs:
+ result += func.get_capi_proto(defined_names, True) + ';\n'
+ result += '\n'
+
+ classes = header.get_classes()
+ for cls in classes:
+ # virtual functions are inside a structure
+ result += 'struct ' + cls.get_capi_name() + '\n{\n'
+ funcs = cls.get_virtual_funcs()
+ if len(funcs) > 0:
+ for func in funcs:
+ result += '\t' + func.get_capi_proto(defined_names, True) + ';\n'
+ result += '}\n\n'
+
+ defined_names.append(cls.get_capi_name())
+
+ # static functions become global
+ funcs = cls.get_static_funcs()
+ if len(funcs) > 0:
+ for func in funcs:
+ result += func.get_capi_proto(defined_names, True) + ';\n'
+ result += '\n'
+ sys.stdout.write(result)
diff --git a/tools/cef_version.py b/tools/cef_version.py
new file mode 100644
index 00000000..132438ba
--- /dev/null
+++ b/tools/cef_version.py
@@ -0,0 +1,275 @@
+# Copyright (c) 2019 The Chromium Embedded Framework Authors. All rights
+# reserved. Use of this source code is governed by a BSD-style license that
+# can be found in the LICENSE file.
+
+from __future__ import absolute_import
+from __future__ import print_function
+from file_util import *
+import git_util as git
+import os
+
+
+class VersionFormatter:
+ """ Formats CEF version information. """
+
+ def __init__(self, chromium_src_path=None):
+ if chromium_src_path is None:
+ # Relative to the current directory.
+ script_path = os.path.abspath(os.path.dirname(__file__))
+ chromium_src_path = os.path.abspath(
+ os.path.join(script_path, os.pardir, os.pardir))
+
+ self.src_path = chromium_src_path
+ assert os.path.isdir(self.src_path), self.src_path
+ self.cef_path = os.path.join(self.src_path, 'cef')
+ assert os.path.isdir(self.cef_path), self.cef_path
+
+ # Whether to use the old version format by default.
+ self._old_format_default = \
+ bool(int(os.environ.get('CEF_OLD_VERSION_FORMAT', '0')))
+
+ self.reset()
+
+ def reset(self):
+ """ Reset internal state. """
+ self._chrome_version = {}
+ self._cef_version = {}
+ self._cef_commit = {}
+ self._branch_version = {}
+ self._old_version_string = None
+ self._old_version_parts = {}
+ self._version_string = None
+ self._version_parts = {}
+
+ def get_chrome_version_components(self):
+ """ Returns Chrome version components. """
+ if not bool(self._chrome_version):
+ file_path = os.path.join(self.src_path, 'chrome', 'VERSION')
+ assert os.path.isfile(file_path), file_path
+ read_version_file(file_path, self._chrome_version)
+ return self._chrome_version
+
+ def get_cef_version_components(self):
+ """ Returns CEF version components. """
+ if not bool(self._cef_version):
+ file_path = os.path.join(self.cef_path, 'VERSION.in')
+ assert os.path.isfile(file_path), file_path
+ read_version_file(file_path, self._cef_version)
+ return self._cef_version
+
+ def get_cef_commit_components(self):
+ """ Returns CEF commit components. """
+ if not bool(self._cef_commit):
+ hash = git.get_hash(self.cef_path)
+ number = git.get_commit_number(self.cef_path)
+ self._cef_commit = {'HASH': hash, 'NUMBER': number}
+ return self._cef_commit
+
+ def get_cef_branch_version_components(self):
+ """ Computes the CEF branch version. """
+ if not bool(self._branch_version):
+ minor = 0
+ bugfix = 0
+
+ # Retrieve the list of commits that have been applied on the current
+ # branch since branching from origin/master.
+ hashes = git.get_branch_hashes(self.cef_path)
+ for hash in hashes:
+ # Determine if the API hash file was modified by the commit.
+ found = False
+ files = git.get_changed_files(self.cef_path, hash)
+ for file in files:
+ if file.find('cef_api_hash.h') >= 0:
+ found = True
+ break
+
+ if found:
+ minor += 1
+ bugfix = 0
+ else:
+ bugfix += 1
+
+ self._branch_version = {'MINOR': minor, 'PATCH': bugfix}
+ return self._branch_version
+
+ def get_chromium_version_string(self):
+ """ Returns the Chromium version number string. """
+ chrome_version = self.get_chrome_version_components()
+ return '%s.%s.%s.%s' % (chrome_version['MAJOR'], chrome_version['MINOR'],
+ chrome_version['BUILD'], chrome_version['PATCH'])
+
+ @staticmethod
+ def _format_commit_hash(hash):
+ return 'g%s' % hash[:7]
+
+ # Computes old version numbers in the format "X.YYYY.A.gHHHHHHH".
+ #
+ # Where:
+ # - "X" is the CEF major version (currently 3).
+ # - "YYYY" is the Chromium branch.
+ # - "A" is an incremental number representing the number of commits in the
+ # current branch. This is roughly equivalent to the SVN revision number but
+ # on a per-branch basis and assists people in quickly determining the order
+ # of builds in the same branch (for bug reports, etc).
+ # - "gHHHHHHH" is the 7-character abbreviation for the Git commit hash. This
+ # facilitates lookup of the relevant commit history in Git.
+ #
+ # Example: "3.3729.1921.g62d140e"
+ def _compute_old_version(self):
+ if not self._old_version_string is None:
+ return
+
+ chrome_version = self.get_chrome_version_components()
+ cef_version = self.get_cef_version_components()
+ cef_commit = self.get_cef_commit_components()
+ cef_commit_hash = self._format_commit_hash(cef_commit['HASH'])
+
+ self._old_version_parts = {
+ 'MAJOR': int(cef_version['CEF_MAJOR']),
+ 'MINOR': int(chrome_version['BUILD']),
+ 'PATCH': int(cef_commit['NUMBER'])
+ }
+ self._old_version_string = \
+ '%s.%s.%s.%s' % (cef_version['CEF_MAJOR'], chrome_version['BUILD'],
+ cef_commit['NUMBER'], cef_commit_hash)
+
+ def _get_old_version_string(self):
+ self._compute_old_version()
+ return self._old_version_string
+
+ def _get_old_version_parts(self):
+ self._compute_old_version()
+ return self._old_version_parts
+
+ # Computes version numbers in the format:
+ # - "X.Y.Z+gHHHHHHH+chromium-A.B.C.D" for release branch builds.
+ # - "X.0.0-master.N+gHHHHHHH+chromium-A.B.C.D" for master branch builds.
+ #
+ # Where:
+ # - "X" is the Chromium major version (e.g. 74).
+ # - "Y" is an incremental number that starts at 0 when a release branch is
+ # created and changes only when the CEF C/C++ API changes (similar to how
+ # the CEF_API_HASH_UNIVERSAL value behaves in cef_version.h) (release branch
+ # only).
+ # - "Z" is an incremental number that starts at 0 when a release branch is
+ # created and changes on each commit, with reset to 0 when "Y" changes
+ # (release branch only).
+ # - "N" is an incremental number representing the number of commits (master
+ # branch only).
+ # - "gHHHHHHH" is the 7-character abbreviation for the Git commit hash. This
+ # facilitates lookup of the relevant commit history in Git.
+ # - "A.B.C.D" is the Chromium version (e.g. 74.0.3729.6).
+ #
+ # Examples:
+ # - "74.0.1+g62d140e+chromium-74.0.3729.6" for a release build.
+ # - "74.0.0-master.1920+g725ed88+chromium-74.0.3729.0" for a master build.
+ def _compute_version(self):
+ if not self._version_string is None:
+ return
+
+ chrome_version = self.get_chrome_version_components()
+ chrome_major = chrome_version['MAJOR']
+ chrome_version_part = 'chromium-' + self.get_chromium_version_string()
+
+ cef_commit = self.get_cef_commit_components()
+ cef_commit_hash = self._format_commit_hash(cef_commit['HASH'])
+
+ # Determine whether the current commit is on a release branch. For example,
+ # if using Chrome build 3683, are we on CEF branch "3683" or "origin/3683"?
+ release_branch = chrome_version['BUILD']
+ on_release_branch = (
+ git.is_ancestor(self.cef_path, 'HEAD', release_branch) or
+ git.is_ancestor(self.cef_path, 'HEAD', 'origin/' + release_branch))
+
+ if not on_release_branch:
+ # Not on a commit that is part of an official named release branch. See
+ # if we can get the name of the branch we are on (may be just "HEAD").
+ cef_branch_name = git.get_branch_name(self.cef_path).split('/')[-1]
+
+ self._version_parts = {'MAJOR': int(chrome_major), 'MINOR': 0, 'PATCH': 0}
+ self._version_string = '%s.0.0-%s.%s+%s+%s' % \
+ (chrome_major, cef_branch_name, cef_commit['NUMBER'],
+ cef_commit_hash, chrome_version_part)
+ else:
+ cef_branch = self.get_cef_branch_version_components()
+
+ self._version_parts = {
+ 'MAJOR': int(chrome_major),
+ 'MINOR': cef_branch['MINOR'],
+ 'PATCH': cef_branch['PATCH']
+ }
+ self._version_string = '%s.%d.%d+%s+%s' % \
+ (chrome_major, cef_branch['MINOR'], cef_branch['PATCH'],
+ cef_commit_hash, chrome_version_part)
+
+ def _get_version_string(self):
+ self._compute_version()
+ return self._version_string
+
+ def _get_version_parts(self):
+ self._compute_version()
+ return self._version_parts
+
+ def get_version_string(self, oldFormat=None):
+ """ Returns the CEF version number string based on current checkout state.
+ """
+ if oldFormat is None:
+ oldFormat = self._old_format_default
+
+ if oldFormat:
+ return self._get_old_version_string()
+ return self._get_version_string()
+
+ def get_version_parts(self, oldFormat=None):
+ """ Returns the CEF version number parts based on current checkout state.
+ """
+ if oldFormat is None:
+ oldFormat = self._old_format_default
+
+ if oldFormat:
+ return self._get_old_version_parts()
+ return self._get_version_parts()
+
+ def get_plist_version_string(self, oldFormat=None):
+ """ Returns the CEF version number string for plist files based on current
+ checkout state. """
+ parts = self.get_version_parts(oldFormat=oldFormat)
+ return "%d.%d.%d.0" % (parts['MAJOR'], parts['MINOR'], parts['PATCH'])
+
+ def get_dylib_version_string(self, oldFormat=None):
+ """ Returns the CEF version number string for dylib files based on current
+ checkout state. """
+ parts = self.get_version_parts(oldFormat=oldFormat)
+ # Dylib format supports a max value of 255 for the 2nd and 3rd components.
+ return "%d%d.%d.%d" % (parts['MAJOR'], parts['MINOR'], parts['PATCH'] / 255,
+ parts['PATCH'] % 255)
+
+
+# Test the module.
+if __name__ == "__main__":
+ import sys
+
+ # Optionally specify a format.
+ formats = ['current', 'old', 'plist', 'dylib']
+ if len(sys.argv) >= 2:
+ formats = [sys.argv[1]]
+
+ # Optionally specify the path to chromium/src.
+ chromium_src_path = None
+ if len(sys.argv) >= 3:
+ chromium_src_path = sys.argv[2]
+
+ formatter = VersionFormatter(chromium_src_path)
+
+ for format in formats:
+ if len(formats) > 1:
+ print(format)
+
+ if format == 'old':
+ print(formatter.get_version_string(True))
+ elif format == 'dylib':
+ print(formatter.get_dylib_version_string())
+ elif format == 'plist':
+ print(formatter.get_plist_version_string())
+ else:
+ print(formatter.get_version_string(False))
diff --git a/tools/cefbuilds/cef_json_builder.py b/tools/cefbuilds/cef_json_builder.py
new file mode 100644
index 00000000..2ac6eb4f
--- /dev/null
+++ b/tools/cefbuilds/cef_json_builder.py
@@ -0,0 +1,498 @@
+# Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights
+# reserved. Use of this source code is governed by a BSD-style license that
+# can be found in the LICENSE file.
+
+from __future__ import absolute_import
+from __future__ import print_function
+import datetime
+import json
+import os
+import re
+import sys
+
+if sys.version_info.major == 2:
+ from urllib2 import urlopen
+else:
+ from urllib.request import urlopen
+
+# Class used to build the cefbuilds JSON file. See cef_json_builder_example.py
+# for example usage. See cef_json_builder_test.py for unit tests.
+#
+# Example JSON structure:
+# {
+# "linux32": {
+# "versions": [
+# {
+# "cef_version": "3.2704.1414.g185cd6c",
+# "chromium_version": "51.0.2704.47"
+# "files": [
+# {
+# "last_modified": "2016-05-18T22:42:14.066Z"
+# "name": "cef_binary_3.2704.1414.g185cd6c_linux32.tar.bz2",
+# "sha1": "47c5cfea43912a1d1771f343de35b205f388415f"
+# "size": "48549450",
+# "type": "standard",
+# }, ...
+# ],
+# }, ...
+# ]
+# }, ...
+# }
+#
+# Notes:
+# - "files" in a given version will be sorted from newest to oldest based on the
+# "last_modified" value.
+# - "versions" in a given platform will be sorted from newest to oldest based on
+# the "last_modified" value of the first (newest) "file" sub-value.
+# - There will be at most one record at the "files" level for each "type".
+
+# This date format intentionally matches the format used in Artifactory
+# directory listings.
+_CEF_DATE_FORMAT = "%Y-%m-%dT%H:%M:%S.%fZ"
+
+
+def parse_date(date):
+ return datetime.datetime.strptime(date, _CEF_DATE_FORMAT)
+
+
+def format_date(date):
+ return date.strftime(_CEF_DATE_FORMAT)
+
+
+# Helpers to format datetime values on JSON read/write.
+def cef_from_json(json_object):
+ if 'last_modified' in json_object:
+ json_object['last_modified'] = parse_date(json_object['last_modified'])
+ return json_object
+
+
+class cef_json_encoder(json.JSONEncoder):
+
+ def default(self, o):
+ if isinstance(o, datetime.datetime):
+ return format_date(o)
+ return o
+
+
+_chromium_version_regex = '[1-9]{1}[0-9]{1,2}\.0\.[1-9]{1}[0-9]{2,4}\.(0|[1-9]{1}[0-9]{0,2})'
+_cef_hash_regex = 'g[0-9a-f]{7}'
+_cef_number_regex = '[0-9]{1,5}\.[0-9]{1,5}\.[0-9]{1,5}'
+
+# Example: 3.2704.1414.g185cd6c
+_cef_old_version_regex = _cef_number_regex + '\.' + _cef_hash_regex
+# Example: 74.0.1+g62d140e+chromium-74.0.3729.6
+_cef_version_release_regex = _cef_number_regex + '\+' + _cef_hash_regex + '\+chromium\-' + _chromium_version_regex
+# Example: 74.0.0-master.1920+g725ed88+chromium-74.0.3729.0
+_cef_version_dev_regex = _cef_number_regex + '\-\w+\.[0-9]{1,7}\+' + _cef_hash_regex + '\+chromium\-' + _chromium_version_regex
+
+
+class cef_json_builder:
+ """ Class used to build the cefbuilds JSON file. """
+
+ def __init__(self, prettyprint=False, silent=True):
+ """ Create a new cef_json_builder object. """
+ self._prettyprint = prettyprint
+ self._silent = silent
+ self._fatalerrors = False
+ self.clear()
+
+ @staticmethod
+ def get_platforms():
+ """ Returns the list of supported platforms. """
+ return ('linux32', 'linux64', 'linuxarm', 'linuxarm64', 'macosarm64', 'macosx64',
+ 'windows32', 'windows64', 'windowsarm64')
+
+ @staticmethod
+ def get_distrib_types():
+ """ Returns the list of supported distribution types. """
+ return ('standard', 'minimal', 'client', 'release_symbols', 'debug_symbols')
+
+ @staticmethod
+ def is_valid_version(version):
+ """ Returns true if the specified CEF version is fully qualified and valid. """
+ if version is None:
+ return False
+ return bool(re.compile('^' + _cef_old_version_regex + '$').match(version)) \
+ or bool(re.compile('^' + _cef_version_release_regex + '$').match(version)) \
+ or bool(re.compile('^' + _cef_version_dev_regex + '$').match(version))
+
+ @staticmethod
+ def is_valid_chromium_version(version):
+ """ Returns true if the specified Chromium version is fully qualified and valid. """
+ if version is None:
+ return False
+ return version == 'master' or \
+ bool(re.compile('^' + _chromium_version_regex + '$').match(version))
+
+ @staticmethod
+ def get_file_name(version, platform, type, channel='stable'):
+ """ Returns the expected distribution file name excluding extension based on
+ the input parameters. """
+ type_str = '_' + type if type != 'standard' else ''
+ channel_str = '_' + channel if channel != 'stable' else ''
+ return 'cef_binary_%s_%s%s%s' % (version, platform, channel_str, type_str)
+
+ def clear(self):
+ """ Clear the contents of this object. """
+ self._data = {}
+ for platform in self.get_platforms():
+ self._data[platform] = {'versions': []}
+ self._versions = {}
+ self._queryct = 0
+
+ def __repr__(self):
+ # Return a string representation of this object.
+ self._sort_versions()
+ if self._prettyprint:
+ return json.dumps(
+ self._data,
+ cls=cef_json_encoder,
+ sort_keys=True,
+ indent=2,
+ separators=(',', ': '))
+ else:
+ return json.dumps(self._data, cls=cef_json_encoder, sort_keys=True)
+
+ def _print(self, msg):
+ if self._fatalerrors:
+ raise Exception(msg)
+ if not self._silent:
+ print(msg)
+
+ def get_query_count(self):
+ """ Returns the number of queries sent while building. """
+ return self._queryct
+
+ def _query_chromium_version(self, cef_version):
+ """ Try to remotely query the Chromium version for old-style CEF version
+ numbers. """
+ chromium_version = 'master'
+ git_hash = cef_version[-7:]
+ query_url = 'https://bitbucket.org/chromiumembedded/cef/raw/%s/CHROMIUM_BUILD_COMPATIBILITY.txt' % git_hash
+ self._queryct = self._queryct + 1
+ if not self._silent:
+ print('Reading %s' % query_url)
+
+ try:
+ # Read the remote URL contents.
+ handle = urlopen(query_url)
+ compat_value = handle.read().strip()
+ handle.close()
+
+ # Parse the contents.
+ config = eval(compat_value, {'__builtins__': None}, None)
+ if not 'chromium_checkout' in config:
+ raise Exception('Unexpected contents')
+
+ val = config['chromium_checkout']
+ if val.find('refs/tags/') == 0:
+ chromium_version = val[10:]
+ except Exception as e:
+ print('Failed to read Chromium version information')
+ raise
+
+ return chromium_version
+
+ def set_chromium_version(self, cef_version, chromium_version=None):
+ """ Set the matching Chromium version. If the specified Chromium version is
+ invalid then it will be queried remotely. """
+ if not self.is_valid_version(cef_version):
+ raise Exception('Invalid CEF version: %s' % cef_version)
+
+ if not self.is_valid_chromium_version(chromium_version):
+ if cef_version in self._versions:
+ # Keep the Chromium version that we already know about.
+ return self._versions[cef_version]
+
+ if cef_version.find('+chromium') > 0:
+ # New-style CEF version numbers include the Chromium version number.
+ # Example: 74.0.1+g62d140e+chromium-74.0.3729.6
+ chromium_version = cef_version[cef_version.rfind('-') + 1:]
+ else:
+ chromium_version = self._query_chromium_version(cef_version)
+
+ if not self.is_valid_chromium_version(chromium_version):
+ raise Exception('Invalid Chromium version: %s' % chromium_version)
+
+ self._versions[cef_version] = chromium_version
+ return chromium_version
+
+ def get_chromium_version(self, cef_version):
+ """ Return the matching Chromium version. If not currently known it will
+ be parsed from the CEF version or queried remotely. """
+ if cef_version in self._versions:
+ return self._versions[cef_version]
+ # Identify the Chromium version.
+ return self.set_chromium_version(cef_version)
+
+ def has_chromium_version(self, cef_version):
+ """ Return True if a matching Chromium version is known. """
+ return cef_version in self._versions
+
+ def load(self, json_string, fatalerrors=True):
+ """ Load new JSON into this object. Any existing contents will be cleared.
+ If |fatalerrors| is True then any errors while loading the JSON file
+ will cause an Exception to be thrown. Otherwise, malformed entries will
+ will be discarded. Unrecognized keys will always be discarded silently.
+ """
+ self.clear()
+
+ self._fatalerrors = fatalerrors
+
+ new_data = json.JSONDecoder(object_hook=cef_from_json).decode(json_string)
+
+ # Validate the new data's structure.
+ for platform in self._data.keys():
+ if not platform in new_data:
+ if not self._silent:
+ print('load: Platform %s not found' % platform)
+ continue
+ if not 'versions' in new_data[platform]:
+ self._print('load: Missing platform key(s) for %s' % platform)
+ continue
+
+ valid_versions = []
+ for version in new_data[platform]['versions']:
+ if not 'cef_version' in version or \
+ not 'chromium_version' in version or \
+ not 'files' in version:
+ self._print('load: Missing version key(s) for %s' % platform)
+ continue
+
+ valid_files = []
+ found_types = []
+ for file in version['files']:
+ if not 'type' in file or \
+ not 'name' in file or \
+ not 'size' in file or \
+ not 'last_modified' in file or \
+ not 'sha1' in file:
+ self._print('load: Missing file key(s) for %s %s' %
+ (platform, version['cef_version']))
+ continue
+ (expected_platform, expected_version, expected_type,
+ expected_channel) = self._parse_name(file['name'])
+ if expected_platform != platform or \
+ expected_version != version['cef_version'] or \
+ expected_type != file['type']:
+ self._print('load: File name/attribute mismatch for %s %s %s' %
+ (platform, version['cef_version'], file['name']))
+ continue
+ self._validate_args(platform, version['cef_version'], file['type'],
+ file['size'], file['last_modified'], file['sha1'])
+ if file['type'] in found_types:
+ self._print('load: Duplicate %s type for %s %s' %
+ (file['type'], platform, version['cef_version']))
+ continue
+ found_types.append(file['type'])
+ valid_files.append({
+ 'type': file['type'],
+ 'name': file['name'],
+ 'size': file['size'],
+ 'last_modified': file['last_modified'],
+ 'sha1': file['sha1'],
+ })
+
+ if len(valid_files) > 0:
+ valid_versions.append({
+ 'cef_version':
+ version['cef_version'],
+ 'chromium_version':
+ self.set_chromium_version(version['cef_version'],
+ version['chromium_version']),
+ 'channel':
+ version.get('channel', 'stable'),
+ 'files':
+ self._sort_files(valid_files)
+ })
+
+ if len(valid_versions) > 0:
+ self._data[platform]['versions'] = valid_versions
+
+ self._fatalerrors = False
+
+ def _sort_versions(self):
+ # Sort version records by first (newest) file last_modified value.
+ for platform in self._data.keys():
+ for i in range(0, len(self._data[platform]['versions'])):
+ self._data[platform]['versions'] = \
+ sorted(self._data[platform]['versions'],
+ key=lambda k: k['files'][0]['last_modified'],
+ reverse=True)
+
+ @staticmethod
+ def _sort_files(files):
+ # Sort file records by last_modified.
+ return sorted(files, key=lambda k: k['last_modified'], reverse=True)
+
+ @staticmethod
+ def _parse_name(name):
+ # Remove file extension.
+ name_no_ext = os.path.splitext(name)[0]
+ if name_no_ext[-4:] == '.tar':
+ name_no_ext = name_no_ext[:-4]
+ name_parts = name_no_ext.split('_')
+ if len(
+ name_parts) < 4 or name_parts[0] != 'cef' or name_parts[1] != 'binary':
+ raise Exception('Invalid filename: %s' % name)
+
+ # Remove 'cef' and 'binary'.
+ del name_parts[0]
+ del name_parts[0]
+
+ type = None
+ channel = 'stable'
+
+ # Might be '<version>_<platform>_[debug|release]_symbols'.
+ if name_parts[-1] == 'symbols':
+ del name_parts[-1]
+ if name_parts[-1] == 'debug' or name_parts[-1] == 'release':
+ type = name_parts[-1] + '_symbols'
+ del name_parts[-1]
+
+ # Might be '<version>_<platform>_minimal'.
+ if name_parts[-1] == 'minimal':
+ type = 'minimal'
+ del name_parts[-1]
+
+ # Might be '<version>_<platform>_client'.
+ if name_parts[-1] == 'client':
+ type = 'client'
+ del name_parts[-1]
+
+ # Might be '<version>_<platform>_beta'.
+ if name_parts[-1] == 'beta':
+ del name_parts[-1]
+ channel = 'beta'
+
+ # Remainder must be '<version>_<platform>'.
+ if len(name_parts) != 2:
+ raise Exception('Invalid filename: %s' % name)
+
+ if type is None:
+ type = 'standard'
+
+ version = name_parts[0]
+ platform = name_parts[1]
+
+ return [platform, version, type, channel]
+
+ @staticmethod
+ def _validate_args(platform, version, type, size, last_modified, sha1):
+ # Validate input arguments.
+ if not platform in cef_json_builder.get_platforms():
+ raise Exception('Unsupported platform: %s' % platform)
+
+ if not cef_json_builder.is_valid_version(version):
+ raise Exception('Invalid version: %s' % version)
+
+ if not type in cef_json_builder.get_distrib_types():
+ raise Exception('Unsupported distribution type: %s' % type)
+
+ if int(size) <= 0:
+ raise Exception('Invalid size: %s' % size)
+
+ if not isinstance(last_modified, datetime.datetime):
+ # datetime will throw a ValueException if it doesn't parse.
+ parse_date(last_modified)
+
+ if not re.compile('^[0-9a-f]{40}$').match(sha1):
+ raise Exception('Invalid sha1: %s' % sha1)
+
+ def add_file(self, name, size, last_modified, sha1):
+ """ Add a file record with the specified attributes. Returns True if the
+ file is added or False if a file with the same |name| and |sha1|
+ already exists. """
+ # Parse the file name.
+ (platform, version, type, channel) = self._parse_name(name)
+
+ if not isinstance(size, int):
+ size = int(size)
+ if not isinstance(last_modified, datetime.datetime):
+ last_modified = parse_date(last_modified)
+
+ # Validate arguments.
+ self._validate_args(platform, version, type, size, last_modified, sha1)
+
+ # Find the existing version record.
+ version_idx = -1
+ for i in range(0, len(self._data[platform]['versions'])):
+ if self._data[platform]['versions'][i]['cef_version'] == version:
+ # Check the version record.
+ self._print('add_file: Check %s %s' % (platform, version))
+ version_idx = i
+ break
+
+ if version_idx == -1:
+ # Add a new version record.
+ self._print('add_file: Add %s %s %s' % (platform, version, channel))
+ self._data[platform]['versions'].append({
+ 'cef_version': version,
+ 'chromium_version': self.get_chromium_version(version),
+ 'channel': channel,
+ 'files': []
+ })
+ version_idx = len(self._data[platform]['versions']) - 1
+
+ # Find the existing file record with matching type.
+ file_changed = True
+ for i in range(0,
+ len(self._data[platform]['versions'][version_idx]['files'])):
+ if self._data[platform]['versions'][version_idx]['files'][i][
+ 'type'] == type:
+ existing_sha1 = self._data[platform]['versions'][version_idx]['files'][
+ i]['sha1']
+ if existing_sha1 != sha1:
+ # Remove the existing file record.
+ self._print(' Remove %s %s' % (name, existing_sha1))
+ del self._data[platform]['versions'][version_idx]['files'][i]
+ else:
+ file_changed = False
+ break
+
+ if file_changed:
+ # Add a new file record.
+ self._print(' Add %s %s' % (name, sha1))
+ self._data[platform]['versions'][version_idx]['files'].append({
+ 'type': type,
+ 'name': name,
+ 'size': size,
+ 'last_modified': last_modified,
+ 'sha1': sha1
+ })
+
+ # Sort file records by last_modified.
+ # This is necessary for _sort_versions() to function correctly.
+ self._data[platform]['versions'][version_idx]['files'] = \
+ self._sort_files(self._data[platform]['versions'][version_idx]['files'])
+
+ return file_changed
+
+ def get_files(self, platform=None, version=None, type=None):
+ """ Return the files that match the input parameters.
+ All parameters are optional. Version will do partial matching. """
+ results = []
+
+ if platform is None:
+ platforms = self._data.keys()
+ else:
+ platforms = [platform]
+
+ for platform in platforms:
+ for version_obj in self._data[platform]['versions']:
+ if version is None or version_obj['cef_version'].find(version) == 0:
+ for file_obj in version_obj['files']:
+ if type is None or type == file_obj['type']:
+ result_obj = file_obj
+ # Add additional metadata.
+ result_obj['platform'] = platform
+ result_obj['cef_version'] = version_obj['cef_version']
+ result_obj['chromium_version'] = version_obj['chromium_version']
+ result_obj['channel'] = version_obj['channel']
+ results.append(result_obj)
+
+ return results
+
+ def get_versions(self, platform):
+ """ Return all versions for the specified |platform|. """
+ return self._data[platform]['versions']
diff --git a/tools/cefbuilds/cef_json_builder_example.py b/tools/cefbuilds/cef_json_builder_example.py
new file mode 100644
index 00000000..2033775c
--- /dev/null
+++ b/tools/cefbuilds/cef_json_builder_example.py
@@ -0,0 +1,149 @@
+# Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights
+# reserved. Use of this source code is governed by a BSD-style license that
+# can be found in the LICENSE file.
+
+# This example utility uses the cef_json_builder class to create and update an
+# index.json file in the same directory as this file. Example usage:
+#
+# Add files for macosx64 platform at the specified version:
+# > python cef_json_builder_example.py add macosx64 3.2704.1416.g185cd6c 51.0.2704.47
+#
+# Add files for all platforms at the specified version:
+# > python cef_json_builder_example.py add all 3.2704.1416.g185cd6c 51.0.2704.47
+#
+# See cef_json_builder.get_platforms() for the list of supported platforms.
+
+from __future__ import absolute_import
+from __future__ import print_function
+from cef_json_builder import cef_json_builder
+import datetime
+import os
+import random
+import string
+import sys
+
+
+# Create a fake sha1 checksum value.
+def make_fake_sha1():
+ return ''.join(random.SystemRandom().choice('abcdef' + string.digits)
+ for _ in range(40))
+
+
+# Create a fake file size value.
+def make_fake_size():
+ return random.randint(30000000, 60000000)
+
+
+# Create fake file info based on |platform| and |version|.
+def make_fake_file_info(platform, version, type):
+ return {
+ 'name':
+ cef_json_builder.get_file_name(version, platform, type) + '.tar.gz',
+ 'size':
+ make_fake_size(),
+ 'lastModified':
+ datetime.datetime.now(),
+ 'sha1':
+ make_fake_sha1()
+ }
+
+
+# Returns a list of fake files based on |platform| and |version|.
+def create_fake_files(platform, version):
+ files = []
+
+ # All platforms create standard, minimal and client distributions.
+ files.append(make_fake_file_info(platform, version, 'standard'))
+ files.append(make_fake_file_info(platform, version, 'minimal'))
+ files.append(make_fake_file_info(platform, version, 'client'))
+
+ # Windows and OS X platforms create debug and release symbols.
+ if platform.find('windows') == 0 or platform.find('macosx') == 0:
+ files.append(make_fake_file_info(platform, version, 'debug_symbols'))
+ files.append(make_fake_file_info(platform, version, 'release_symbols'))
+
+ return files
+
+
+# Program entry point.
+if __name__ == '__main__':
+ # Verify command-line arguments.
+ if len(sys.argv) < 5 or sys.argv[1] != 'add':
+ sys.stderr.write(
+ 'Usage: %s add <platform> <cef_version> <chromium_version>\n' %
+ sys.argv[0])
+ sys.exit()
+
+ # Requested platform.
+ if sys.argv[2] == 'all':
+ platforms = cef_json_builder.get_platforms()
+ elif sys.argv[2] in cef_json_builder.get_platforms():
+ platforms = [sys.argv[2]]
+ else:
+ sys.stderr.write('Invalid platform: %s\n' % platform)
+ sys.exit()
+
+ # Requested CEF version.
+ cef_version = sys.argv[3]
+ if not cef_json_builder.is_valid_version(cef_version):
+ sys.stderr.write('Invalid CEF version: %s\n' % cef_version)
+ sys.exit()
+
+ # Requested Chromium version.
+ chromium_version = sys.argv[4]
+ if not cef_json_builder.is_valid_chromium_version(chromium_version):
+ sys.stderr.write('Invalid Chromium version: %s\n' % chromium_version)
+ sys.exit()
+
+ # Write the JSON file in the same directory as this file.
+ current_dir = os.path.dirname(__file__)
+ json_file = os.path.join(current_dir, 'index.json')
+
+ # Create the builder object. Enable pretty printing and extra output for
+ # example purposes.
+ builder = cef_json_builder(prettyprint=True, silent=False)
+
+ # Map the CEF version to the Chromium version to avoid a remote query.
+ builder.set_chromium_version(cef_version, chromium_version)
+
+ # Load the existing JSON file, if any. Ignore format errors for example
+ # purposes.
+ if os.path.exists(json_file):
+ print('--> Reading index.json')
+ with open(json_file, 'r') as f:
+ builder.load(f.read(), fatalerrors=False)
+
+ # Create fake file info based on |platform| and |version|. A real
+ # implementation should retrieve the list of files from an external source
+ # like a Web or filesystem directory listing. If using Artifactory, for
+ # example, then "size", "lastModified" and "sha1" attributes would be included
+ # in the directory listing metadata.
+ # For this example we:
+ # - Always use now() as the last modified date. Consequently newly added files
+ # will always be listed at the top of the JSON platform versions list.
+ # - Always create a new (fake) sha1 checksum value for each file. Consequently
+ # duplicate calls for the same |platform| + |version| will always replace
+ # the existing entries. In real implementations the sha1 may be the same
+ # across calls if the file contents have not changed, in which case
+ # cef_json_builder.add_file() will return False and upload of the file
+ # should be skipped.
+ new_files = []
+ for platform in platforms:
+ new_files.extend(create_fake_files(platform, cef_version))
+
+ # Add new files to the builder.
+ changed_files = []
+ for file in new_files:
+ if builder.add_file(file['name'], file['size'], file['lastModified'],
+ file['sha1']):
+ changed_files.append(file)
+
+ if len(changed_files) > 0:
+ # Write the updated JSON file.
+ print('--> Writing index.json')
+ with open(json_file, 'w') as f:
+ f.write(str(builder))
+
+ # A real implementation would now upload the changed files.
+ for file in changed_files:
+ print('--> Upload file %s' % file['name'])
diff --git a/tools/cefbuilds/cef_json_builder_test.py b/tools/cefbuilds/cef_json_builder_test.py
new file mode 100644
index 00000000..f8080d8e
--- /dev/null
+++ b/tools/cefbuilds/cef_json_builder_test.py
@@ -0,0 +1,435 @@
+# Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights
+# reserved. Use of this source code is governed by a BSD-style license that
+# can be found in the LICENSE file.
+
+from __future__ import absolute_import
+from cef_json_builder import cef_json_builder
+import datetime
+import unittest
+
+
+class TestCefJSONBuilder(unittest.TestCase):
+
+ # Test CEF version number matching.
+ def test_valid_version(self):
+ # Old-style version numbers.
+ self.assertTrue(cef_json_builder.is_valid_version('3.2704.1414.g185cd6c'))
+ # New-style version numbers.
+ self.assertTrue(
+ cef_json_builder.is_valid_version(
+ '74.0.1+g62d140e+chromium-74.0.3729.6'))
+ self.assertTrue(
+ cef_json_builder.is_valid_version(
+ '74.0.0-master.1920+g725ed88+chromium-74.0.3729.0'))
+ self.assertTrue(
+ cef_json_builder.is_valid_version(
+ '74.0.0-my_branch.1920+g725ed88+chromium-74.0.3729.0'))
+
+ # Must be a completely qualified version number.
+ self.assertFalse(cef_json_builder.is_valid_version(None))
+ self.assertFalse(cef_json_builder.is_valid_version('foobar'))
+ self.assertFalse(cef_json_builder.is_valid_version('3.2704.1414'))
+ self.assertFalse(cef_json_builder.is_valid_version('74.0.1+g62d140e'))
+ self.assertFalse(
+ cef_json_builder.is_valid_version('74.0.0-master.1920+g725ed88'))
+ self.assertFalse(
+ cef_json_builder.is_valid_version('74.0.0+chromium-74.0.3729.0'))
+
+ # Test Chromium version number matching.
+ def test_valid_chromium_version(self):
+ self.assertTrue(cef_json_builder.is_valid_chromium_version('74.0.3729.0'))
+ self.assertTrue(cef_json_builder.is_valid_chromium_version('74.0.3729.6'))
+ self.assertTrue(
+ cef_json_builder.is_valid_chromium_version('100.0.59200.602'))
+
+ # self.assertFalse(cef_json_builder.is_valid_version(None))
+ self.assertFalse(cef_json_builder.is_valid_chromium_version('foobar'))
+ # Must be 4 numbers.
+ self.assertFalse(cef_json_builder.is_valid_chromium_version('74.0.3729'))
+ self.assertFalse(cef_json_builder.is_valid_chromium_version('74.0.3729.A'))
+ # 1st number is max 3 digits with no leading 0's.
+ self.assertFalse(
+ cef_json_builder.is_valid_chromium_version('7400.0.3729.6'))
+ self.assertFalse(cef_json_builder.is_valid_chromium_version('04.0.3729.6'))
+ # 2nd number is always 0.
+ self.assertFalse(cef_json_builder.is_valid_chromium_version('74.1.3729.6'))
+ # 3rd number is max 5 digits with no leading 0's.
+ self.assertFalse(cef_json_builder.is_valid_chromium_version('74.0.0372.6'))
+ self.assertFalse(
+ cef_json_builder.is_valid_chromium_version('74.0.372900.6'))
+ # 4rd number is max 3 digits with no leading 0's.
+ self.assertFalse(
+ cef_json_builder.is_valid_chromium_version('74.0.3729.6000'))
+ self.assertFalse(cef_json_builder.is_valid_chromium_version('74.0.3729.06'))
+ pass
+
+ # Write builder contents to string and then read in.
+ def _verify_write_read(self, builder):
+ output = str(builder)
+ builder2 = cef_json_builder()
+ builder2.load(output)
+ self.assertEqual(output, str(builder2))
+
+ # Add a file record for testing purposes.
+ def _add_test_file(self,
+ builder,
+ platform='linux32',
+ version='3.2704.1414.g185cd6c',
+ type='standard',
+ channel='stable',
+ attrib_idx=0,
+ shouldfail=False):
+ name = cef_json_builder.get_file_name(version, platform, type,
+ channel) + '.tar.gz'
+
+ # Some random attribute information. sha1 must be different to trigger replacement.
+ attribs = [{
+ 'date_str': '2016-05-18T22:42:15.487Z',
+ 'date_val': datetime.datetime(2016, 5, 18, 22, 42, 15, 487000),
+ 'sha1': '2d48ee05ea6385c8fe80879c98c5dd505ad4b100',
+ 'size': 48395610
+ }, {
+ 'date_str': '2016-05-14T22:42:15.487Z',
+ 'date_val': datetime.datetime(2016, 5, 14, 22, 42, 15, 487000),
+ 'sha1': '2d48ee05ea6385c8fe80879c98c5dd505ad4b200',
+ 'size': 48395620
+ }]
+
+ # Populate the Chromium version to avoid queries.
+ chromium_version = '49.0.2705.50'
+ self.assertEqual(chromium_version,
+ builder.set_chromium_version(version, chromium_version))
+ self.assertEqual(0, builder.get_query_count())
+
+ result = builder.add_file(name, attribs[attrib_idx]['size'],
+ attribs[attrib_idx]['date_str'],
+ attribs[attrib_idx]['sha1'])
+ # Failure should be expected when adding the same file multiple times with the same sha1.
+ self.assertEqual(not shouldfail, result)
+
+ # Return the result expected from get_files().
+ return {
+ 'chromium_version': chromium_version,
+ 'sha1': attribs[attrib_idx]['sha1'],
+ 'name': name,
+ 'platform': platform,
+ 'last_modified': attribs[attrib_idx]['date_val'],
+ 'cef_version': version,
+ 'channel': channel,
+ 'type': type,
+ 'size': attribs[attrib_idx]['size']
+ }
+
+ # Test with no file contents.
+ def test_empty(self):
+ builder = cef_json_builder()
+
+ self._verify_write_read(builder)
+
+ files = builder.get_files()
+ self.assertEqual(len(files), 0)
+
+ # Test add/get of a single file with the specified type.
+ def _test_add_file(self, type, channel='stable'):
+ builder = cef_json_builder()
+
+ expected = self._add_test_file(builder, type=type, channel=channel)
+ self._verify_write_read(builder)
+
+ files = builder.get_files()
+ self.assertEqual(len(files), 1)
+ self.assertEqual(expected, files[0])
+
+ # Test add/get of a standard type file.
+ def test_add_standard_file(self):
+ self._test_add_file('standard')
+
+ # Test add/get of a minimal type file.
+ def test_add_minimal_file(self):
+ self._test_add_file('minimal')
+
+ # Test add/get of a client type file.
+ def test_add_client_file(self):
+ self._test_add_file('client')
+
+ # Test add/get of a debug_symbols type file.
+ def test_add_debug_symbols_file(self):
+ self._test_add_file('debug_symbols')
+
+ # Test add/get of a release_symbols type file.
+ def test_add_release_symbols_file(self):
+ self._test_add_file('release_symbols')
+
+ # Test add/get of a standard type file in beta channel.
+ def test_add_standard_file_beta(self):
+ self._test_add_file('standard', channel='beta')
+
+ # Test add/get of a minimal type file in beta channel.
+ def test_add_minimal_file_beta(self):
+ self._test_add_file('minimal', channel='beta')
+
+ # Test add/get of a client type file in beta channel.
+ def test_add_client_file_beta(self):
+ self._test_add_file('client', channel='beta')
+
+ # Test add/get of a debug_symbols type file in beta channel.
+ def test_add_debug_symbols_file_beta(self):
+ self._test_add_file('debug_symbols', channel='beta')
+
+ # Test add/get of a release_symbols type file in beta channel.
+ def test_add_release_symbols_file_beta(self):
+ self._test_add_file('release_symbols', channel='beta')
+
+ # Test get_files() behavior with a single file.
+ def test_get_files_single(self):
+ # yapf: disable
+ versions = (
+ ('3.2704.1414.g185cd6c', '3.2704'),
+ ('74.0.1+g62d140e+chromium-74.0.3729.6', '74.0'),
+ )
+ # yapf: enable
+
+ for version, partial_version in versions:
+ builder = cef_json_builder()
+
+ # Specify all values just in case the defaults change.
+ expected = self._add_test_file(
+ builder, platform='linux32', version=version, type='standard')
+
+ # No filter.
+ files = builder.get_files()
+ self.assertEqual(len(files), 1)
+ self.assertEqual(expected, files[0])
+
+ # Platform filter.
+ files = builder.get_files(platform='linux32')
+ self.assertEqual(len(files), 1)
+ self.assertEqual(expected, files[0])
+ files = builder.get_files(platform='linux64')
+ self.assertEqual(len(files), 0)
+
+ # Version filter exact.
+ files = builder.get_files(version=version)
+ self.assertEqual(len(files), 1)
+ self.assertEqual(expected, files[0])
+
+ # Version filter partial.
+ files = builder.get_files(version=partial_version)
+ self.assertEqual(len(files), 1)
+ self.assertEqual(expected, files[0])
+ files = builder.get_files(version='3.2623')
+ self.assertEqual(len(files), 0)
+
+ # Type filter.
+ files = builder.get_files(type='standard')
+ self.assertEqual(len(files), 1)
+ self.assertEqual(expected, files[0])
+ files = builder.get_files(type='client')
+ self.assertEqual(len(files), 0)
+
+ # All filters.
+ files = builder.get_files(
+ platform='linux32', version=partial_version, type='standard')
+ self.assertEqual(len(files), 1)
+ self.assertEqual(expected, files[0])
+ files = builder.get_files(
+ platform='linux32', version=partial_version, type='minimal')
+ self.assertEqual(len(files), 0)
+ files = builder.get_files(
+ platform='linux32', version='3.2623', type='standard')
+ self.assertEqual(len(files), 0)
+ files = builder.get_files(
+ platform='linux64', version=partial_version, type='standard')
+ self.assertEqual(len(files), 0)
+
+ # Test add/get of multiple files.
+ def test_add_multiple_files(self):
+ builder = cef_json_builder()
+
+ expected = []
+
+ platforms = cef_json_builder.get_platforms()
+ versions = [
+ # Old-style version numbers.
+ '3.2704.1414.g185cd6c',
+ '3.2704.1400.gde36543',
+ # New-style version numbers.
+ '74.0.1+g62d140e+chromium-74.0.3729.6'
+ ]
+ types = cef_json_builder.get_distrib_types()
+ for platform in platforms:
+ for version in versions:
+ for type in types:
+ expected.append(
+ self._add_test_file(
+ builder, platform=platform, type=type, version=version))
+
+ self._verify_write_read(builder)
+
+ # No filter.
+ files = builder.get_files()
+ self.assertEqual(len(files), len(platforms) * len(versions) * len(types))
+
+ # Version filter.
+ for version in versions:
+ files = builder.get_files(version=version)
+ self.assertEqual(len(files), len(platforms) * len(types))
+
+ # Type filter.
+ files = builder.get_files(type='client')
+ self.assertEqual(len(files), len(platforms) * len(versions))
+
+ # Platform filter.
+ files = builder.get_files(platform='windows32')
+ self.assertEqual(len(files), len(types) * len(versions))
+
+ # All filters.
+ idx = 0
+ for platform in platforms:
+ for version in versions:
+ for type in types:
+ files = builder.get_files(
+ platform=platform, type=type, version=version)
+ self.assertEqual(len(files), 1)
+ self.assertEqual(expected[idx], files[0])
+ idx += 1
+
+ # Test add/get/replace of multiple files.
+ def test_replace_all_files(self):
+ versions = ['3.2704.1414.g185cd6c', '74.0.1+g62d140e+chromium-74.0.3729.6']
+ platforms = ['linux32', 'linux64']
+ types = ['standard', 'minimal']
+
+ for version in versions:
+ builder = cef_json_builder()
+
+ # Initial file versions.
+ for platform in platforms:
+ for type in types:
+ self._add_test_file(
+ builder, platform=platform, type=type, version=version)
+
+ # No filter.
+ files = builder.get_files()
+ self.assertEqual(len(files), len(platforms) * len(types))
+
+ expected = []
+
+ # Replace all file versions (due to new sha1).
+ for platform in platforms:
+ for type in types:
+ expected.append(
+ self._add_test_file(
+ builder,
+ platform=platform,
+ type=type,
+ version=version,
+ attrib_idx=1))
+
+ # No filter.
+ files = builder.get_files()
+ self.assertEqual(len(files), len(platforms) * len(types))
+
+ # All filters.
+ idx = 0
+ for platform in platforms:
+ for type in types:
+ files = builder.get_files(
+ platform=platform, type=type, version=version)
+ self.assertEqual(len(files), 1)
+ self.assertEqual(expected[idx], files[0])
+ idx += 1
+
+ # Test add/get/no replace of multiple files.
+ def test_replace_no_files(self):
+ versions = ['3.2704.1414.g185cd6c', '74.0.1+g62d140e+chromium-74.0.3729.6']
+ platforms = ['linux32', 'linux64']
+ types = ['standard', 'minimal']
+
+ for version in versions:
+ builder = cef_json_builder()
+
+ # Initial file versions.
+ for platform in platforms:
+ for type in types:
+ self._add_test_file(
+ builder, platform=platform, type=type, version=version)
+
+ # No filter.
+ files = builder.get_files()
+ self.assertEqual(len(files), len(platforms) * len(types))
+
+ expected = []
+
+ # Replace no file versions (due to same sha1).
+ for platform in platforms:
+ for type in types:
+ expected.append(
+ self._add_test_file(
+ builder,
+ platform=platform,
+ type=type,
+ version=version,
+ shouldfail=True))
+
+ # No filter.
+ files = builder.get_files()
+ self.assertEqual(len(files), len(platforms) * len(types))
+
+ # All filters.
+ idx = 0
+ for platform in platforms:
+ for type in types:
+ files = builder.get_files(
+ platform=platform, type=type, version=version)
+ self.assertEqual(len(files), 1)
+ self.assertEqual(expected[idx], files[0])
+ idx += 1
+
+ # Test Chromium version.
+ def test_chromium_version(self):
+ builder = cef_json_builder()
+
+ # For old-style CEF version numbers the Git hashes must exist but the rest
+ # of the CEF version can be fake.
+ # yapf: disable
+ versions = (
+ # Old-style version numbers.
+ ('3.2704.1414.g185cd6c', '51.0.2704.47'),
+ ('3.2623.9999.gb90a3be', '49.0.2623.110'),
+ ('3.2623.9999.g2a6491b', '49.0.2623.87'),
+ ('3.9999.9999.gab2636b', 'master'),
+ # New-style version numbers.
+ ('74.0.1+g62d140e+chromium-74.0.3729.6', '74.0.3729.6'),
+ ('74.0.0-master.1920+g725ed88+chromium-74.0.3729.0', '74.0.3729.0'),
+ ('74.0.0-my_branch.1920+g725ed88+chromium-74.0.3729.0', '74.0.3729.0'),
+ )
+ # yapf: enable
+
+ # Test with no query.
+ for (cef, chromium) in versions:
+ self.assertFalse(builder.has_chromium_version(cef))
+ # Valid version specified, so no query sent.
+ self.assertEqual(chromium, builder.set_chromium_version(cef, chromium))
+ self.assertEqual(chromium, builder.get_chromium_version(cef))
+ self.assertTrue(builder.has_chromium_version(cef))
+ # Ignore attempts to set invalid version after setting valid version.
+ self.assertEqual(chromium, builder.set_chromium_version(cef, None))
+
+ self.assertEqual(0, builder.get_query_count())
+ builder.clear()
+
+ # Test with query.
+ for (cef, chromium) in versions:
+ self.assertFalse(builder.has_chromium_version(cef))
+ # No version known, so query sent for old-style version numbers.
+ self.assertEqual(chromium, builder.get_chromium_version(cef))
+ self.assertTrue(builder.has_chromium_version(cef))
+
+ # Only old-style version numbers.
+ self.assertEqual(4, builder.get_query_count())
+
+
+# Program entry point.
+if __name__ == '__main__':
+ unittest.main()
diff --git a/tools/clang_util.py b/tools/clang_util.py
new file mode 100644
index 00000000..48354721
--- /dev/null
+++ b/tools/clang_util.py
@@ -0,0 +1,35 @@
+# Copyright (c) 2017 The Chromium Embedded Framework Authors. All rights
+# reserved. Use of this source code is governed by a BSD-style license that
+# can be found in the LICENSE file
+
+from __future__ import absolute_import
+from __future__ import print_function
+from exec_util import exec_cmd
+import os
+import sys
+
+# Script directory.
+script_dir = os.path.dirname(__file__)
+root_dir = os.path.join(script_dir, os.pardir)
+
+if sys.platform == 'win32':
+ # Force use of the clang-format version bundled with depot_tools.
+ clang_format_exe = 'clang-format.bat'
+else:
+ clang_format_exe = 'clang-format'
+
+
+def clang_format(file_name, file_contents):
+ # -assume-filename is necessary to find the .clang-format file and determine
+ # the language when specifying contents via stdin.
+ result = exec_cmd("%s -assume-filename=%s" % (clang_format_exe, file_name), \
+ root_dir, file_contents.encode('utf-8'))
+ if result['err'] != '':
+ print("clang-format error: %s" % result['err'])
+ if result['out'] != '':
+ output = result['out']
+ if sys.platform == 'win32':
+ # Convert to Unix line endings.
+ output = output.replace("\r", "")
+ return output
+ return None
diff --git a/tools/combine_libs.py b/tools/combine_libs.py
new file mode 100644
index 00000000..ec3fb6c5
--- /dev/null
+++ b/tools/combine_libs.py
@@ -0,0 +1,121 @@
+#!/usr/bin/env python
+# Copyright (c) 2011 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# TODO(slightlyoff): move to using shared version of this script.
+'''This script makes it easy to combine libs and object files to a new lib,
+optionally removing some of the object files in the input libs by regular
+expression matching.
+For usage information, run the script with a --help argument.
+'''
+from __future__ import absolute_import
+from __future__ import print_function
+import optparse
+import os
+import re
+import subprocess
+import sys
+
+
+def Shell(*args):
+ '''Runs the program and args in args, returns the output from the program.'''
+ process = subprocess.Popen(
+ args, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+ output = process.stdout.readlines()
+ process.wait()
+ retcode = process.returncode
+ if retcode != 0:
+ raise RuntimeError('%s exited with status %d' % (args[0], retcode))
+ return output
+
+
+def CollectRemovals(remove_re, inputs):
+ '''Returns a list of all object files in inputs that match remove_re.'''
+ removals = []
+ for input in inputs:
+ output = Shell('lib.exe', '/list', input)
+
+ for line in output:
+ line = line.rstrip()
+ if remove_re.search(line):
+ removals.append(line)
+
+ return removals
+
+
+def CombineLibraries(output, remove_re, inputs):
+ '''Combines all the libraries and objects in inputs, while removing any
+ object files that match remove_re.
+ '''
+ removals = []
+ if remove_re:
+ removals = CollectRemovals(remove_re, inputs)
+
+ if len(removals) > 0:
+ print('Removals: ', removals)
+
+ args = ['lib.exe', '/out:%s' % output]
+ args += ['/remove:%s' % obj for obj in removals]
+ args += inputs
+ Shell(*args)
+
+
+USAGE = '''usage: %prog [options] <lib or obj>+
+
+Combines input libraries or objects into an output library, while removing
+any object file (in the input libraries) that matches a given regular
+expression.
+'''
+
+
+def GetOptionParser():
+ parser = optparse.OptionParser(USAGE)
+ parser.add_option(
+ '-o', '--output', dest='output', help='write to this output library')
+ parser.add_option(
+ '-r',
+ '--remove',
+ dest='remove',
+ help='object files matching this regexp will be removed '
+ 'from the output library')
+ return parser
+
+
+def Main():
+ '''Main function for this script'''
+ parser = GetOptionParser()
+ (opt, args) = parser.parse_args()
+ output = opt.output
+ remove = opt.remove
+ if not output:
+ parser.error('You must specify an output file')
+
+ if not args:
+ parser.error('You must specify at least one object or library')
+
+ output = output.strip()
+ if remove:
+ remove = remove.strip()
+
+ if remove:
+ try:
+ remove_re = re.compile(opt.remove)
+ except:
+ parser.error('%s is not a valid regular expression' % opt.remove)
+ else:
+ remove_re = None
+
+ if sys.platform != 'win32' and sys.platform != 'cygwin':
+ parser.error('this script only works on Windows for now')
+
+ # If this is set, we can't capture lib.exe's output.
+ if 'VS_UNICODE_OUTPUT' in os.environ:
+ del os.environ['VS_UNICODE_OUTPUT']
+
+ CombineLibraries(output, remove_re, args)
+ return 0
+
+
+if __name__ == '__main__':
+ sys.exit(Main())
diff --git a/tools/compile_ib_files.py b/tools/compile_ib_files.py
new file mode 100644
index 00000000..d0b19b47
--- /dev/null
+++ b/tools/compile_ib_files.py
@@ -0,0 +1,56 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+from __future__ import print_function
+from __future__ import absolute_import
+import argparse
+import logging
+import os
+import re
+import subprocess
+import sys
+
+
+def main():
+ parser = argparse.ArgumentParser(
+ description='A script to compile xib and storyboard.',
+ fromfile_prefix_chars='@')
+ parser.add_argument(
+ '-o', '--output', required=True, help='Path to output bundle.')
+ parser.add_argument(
+ '-i', '--input', required=True, help='Path to input xib or storyboard.')
+ parser.add_argument('--developer_dir', required=False, help='Path to Xcode.')
+ args, unknown_args = parser.parse_known_args()
+ if args.developer_dir:
+ os.environ['DEVELOPER_DIR'] = args.developer_dir
+ ibtool_args = [
+ 'xcrun', 'ibtool', '--errors', '--warnings', '--notices',
+ '--output-format', 'human-readable-text'
+ ]
+ ibtool_args += unknown_args
+ ibtool_args += [
+ '--compile',
+ os.path.abspath(args.output),
+ os.path.abspath(args.input)
+ ]
+ ibtool_section_re = re.compile(rb'/\*.*\*/')
+ ibtool_re = re.compile(rb'.*note:.*is clipping its content')
+ try:
+ stdout = subprocess.check_output(ibtool_args)
+ except subprocess.CalledProcessError as e:
+ print(e.output)
+ raise
+ current_section_header = None
+ for line in stdout.splitlines():
+ if ibtool_section_re.match(line):
+ current_section_header = line
+ elif not ibtool_re.match(line):
+ if current_section_header:
+ print(current_section_header)
+ current_section_header = None
+ print(line)
+ return 0
+
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/tools/crash_server.py b/tools/crash_server.py
new file mode 100644
index 00000000..a05e800b
--- /dev/null
+++ b/tools/crash_server.py
@@ -0,0 +1,339 @@
+#!/usr/bin/env python
+# Copyright 2017 The Chromium Embedded Framework Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be found
+# in the LICENSE file.
+"""
+This script implements a simple HTTP server for receiving crash report uploads
+from a Breakpad/Crashpad client (any CEF-based application). This script is
+intended for testing purposes only. An HTTPS server and a system such as Socorro
+(https://wiki.mozilla.org/Socorro) should be used when uploading crash reports
+from production applications.
+
+Usage of this script is as follows:
+
+1. Run this script from the command-line. The first argument is the server port
+ number and the second argument is the directory where uploaded report
+ information will be saved:
+
+ > python crash_server.py 8080 /path/to/dumps
+
+2. Create a "crash_reporter.cfg" file at the required platform-specific
+ location. On Windows and Linux this file must be placed next to the main
+ application executable. On macOS this file must be placed in the top-level
+ app bundle Resources directory (e.g. "<appname>.app/Contents/Resources"). At
+ a minimum it must contain a "ServerURL=http://localhost:8080" line under the
+ "[Config]" section (make sure the port number matches the value specified in
+ step 1). See comments in include/cef_crash_util.h for a complete
+ specification of this file.
+
+ Example file contents:
+
+ [Config]
+ ServerURL=http://localhost:8080
+ # Disable rate limiting so that all crashes are uploaded.
+ RateLimitEnabled=false
+ MaxUploadsPerDay=0
+
+ [CrashKeys]
+ # The cefclient sample application sets these values (see step 5 below).
+ testkey_small1=small
+ testkey_small2=small
+ testkey_medium1=medium
+ testkey_medium2=medium
+ testkey_large1=large
+ testkey_large2=large
+
+3. Load one of the following URLs in the CEF-based application to cause a crash:
+
+ Main (browser) process crash: chrome://inducebrowsercrashforrealz
+ Renderer process crash: chrome://crash
+ GPU process crash: chrome://gpucrash
+
+4. When this script successfully receives a crash report upload you will see
+ console output like the following:
+
+ 01/10/2017 12:31:23: Dump <id>
+
+ The "<id>" value is a 16 digit hexadecimal string that uniquely identifies
+ the dump. Crash dumps and metadata (product state, command-line flags, crash
+ keys, etc.) will be written to the "<id>.dmp" and "<id>.json" files
+ underneath the directory specified in step 1.
+
+ On Linux Breakpad uses the wget utility to upload crash dumps, so make sure
+ that utility is installed. If the crash is handled correctly then you should
+ see console output like the following when the client uploads a crash dump:
+
+ --2017-01-10 12:31:22-- http://localhost:8080/
+ Resolving localhost (localhost)... 127.0.0.1
+ Connecting to localhost (localhost)|127.0.0.1|:8080... connected.
+ HTTP request sent, awaiting response... 200 OK
+ Length: unspecified [text/html]
+ Saving to: '/dev/fd/3'
+ Crash dump id: <id>
+
+ On macOS when uploading a crash report to this script over HTTP you may
+ receive an error like the following:
+
+ "Transport security has blocked a cleartext HTTP (http://) resource load
+ since it is insecure. Temporary exceptions can be configured via your app's
+ Info.plist file."
+
+ You can work around this error by adding the following key to the Helper app
+ Info.plist file (e.g. "<appname>.app/Contents/Frameworks/
+ <appname> Helper.app/Contents/Info.plist"):
+
+ <key>NSAppTransportSecurity</key>
+ <dict>
+ <!--Allow all connections (for testing only!)-->
+ <key>NSAllowsArbitraryLoads</key>
+ <true/>
+ </dict>
+
+5. The cefclient sample application sets test crash key values in the browser
+ and renderer processes. To work properly these values must also be defined
+ in the "[CrashKeys]" section of "crash_reporter.cfg" as shown above.
+
+ In tests/cefclient/browser/client_browser.cc (browser process):
+
+ CefSetCrashKeyValue("testkey1", "value1_browser");
+ CefSetCrashKeyValue("testkey2", "value2_browser");
+ CefSetCrashKeyValue("testkey3", "value3_browser");
+
+ In tests/cefclient/renderer/client_renderer.cc (renderer process):
+
+ CefSetCrashKeyValue("testkey1", "value1_renderer");
+ CefSetCrashKeyValue("testkey2", "value2_renderer");
+ CefSetCrashKeyValue("testkey3", "value3_renderer");
+
+ When crashing the browser or renderer processes with cefclient you should
+ verify that the test crash key values are included in the metadata
+ ("<id>.json") file. Some values may be chunked as described in
+ include/cef_crash_util.h.
+"""
+
+from __future__ import absolute_import
+from __future__ import print_function
+import cgi
+import datetime
+import json
+import os
+import shutil
+import sys
+import uuid
+import zlib
+
+is_python2 = sys.version_info.major == 2
+
+if is_python2:
+ from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
+ from cStringIO import StringIO as BytesIO
+else:
+ from http.server import BaseHTTPRequestHandler, HTTPServer
+ from io import BytesIO, open
+
+
+def print_msg(msg):
+ """ Write |msg| to stdout and flush. """
+ timestr = datetime.datetime.now().strftime("%m/%d/%Y %H:%M:%S")
+ sys.stdout.write("%s: %s\n" % (timestr, msg))
+ sys.stdout.flush()
+
+
+# Key identifying the minidump file.
+minidump_key = 'upload_file_minidump'
+
+
+class CrashHTTPRequestHandler(BaseHTTPRequestHandler):
+
+ def __init__(self, dump_directory, *args):
+ self._dump_directory = dump_directory
+ BaseHTTPRequestHandler.__init__(self, *args)
+
+ def _send_default_response_headers(self):
+ """ Send default response headers. """
+ self.send_response(200)
+ self.send_header('Content-type', 'text/html')
+ self.end_headers()
+
+ def _parse_post_data(self, data):
+ """ Returns a cgi.FieldStorage object for this request or None if this is
+ not a POST request. """
+ if self.command != 'POST':
+ return None
+ return cgi.FieldStorage(
+ fp=BytesIO(data),
+ headers=self.headers,
+ environ={
+ 'REQUEST_METHOD': 'POST',
+ 'CONTENT_TYPE': self.headers['Content-Type'],
+ })
+
+ def _get_chunk_size(self):
+ # Read to the next "\r\n".
+ size_str = self.rfile.read(2)
+ while size_str[-2:] != b"\r\n":
+ size_str += self.rfile.read(1)
+ # Remove the trailing "\r\n".
+ size_str = size_str[:-2]
+ return int(size_str, 16)
+
+ def _get_chunk_data(self, chunk_size):
+ data = self.rfile.read(chunk_size)
+ assert len(data) == chunk_size
+ # Skip the trailing "\r\n".
+ self.rfile.read(2)
+ return data
+
+ def _unchunk_request(self, compressed):
+ """ Read a chunked request body. Optionally decompress the result. """
+ if compressed:
+ d = zlib.decompressobj(16 + zlib.MAX_WBITS)
+
+ # Chunked format is: <size>\r\n<bytes>\r\n<size>\r\n<bytes>\r\n0\r\n
+ unchunked = b""
+ while True:
+ chunk_size = self._get_chunk_size()
+ print('Chunk size 0x%x' % chunk_size)
+ if (chunk_size == 0):
+ break
+ chunk_data = self._get_chunk_data(chunk_size)
+ if compressed:
+ unchunked += d.decompress(chunk_data)
+ else:
+ unchunked += chunk_data
+
+ if compressed:
+ unchunked += d.flush()
+
+ return unchunked
+
+ def _create_new_dump_id(self):
+ """ Breakpad requires a 16 digit hexadecimal dump ID. """
+ return uuid.uuid4().hex.upper()[0:16]
+
+ def do_GET(self):
+ """ Default empty implementation for handling GET requests. """
+ self._send_default_response_headers()
+ self.wfile.write("<html><body><h1>GET!</h1></body></html>")
+
+ def do_HEAD(self):
+ """ Default empty implementation for handling HEAD requests. """
+ self._send_default_response_headers()
+
+ def do_POST(self):
+ """ Handle a multi-part POST request submitted by Breakpad/Crashpad. """
+ self._send_default_response_headers()
+
+ # Create a unique ID for the dump.
+ dump_id = self._create_new_dump_id()
+
+ # Return the unique ID to the caller.
+ self.wfile.write(dump_id.encode('utf-8'))
+
+ dmp_stream = None
+ metadata = {}
+
+ # Request body may be chunked and/or gzip compressed. For example:
+ #
+ # 3029 branch on Windows:
+ # User-Agent: Crashpad/0.8.0
+ # Host: localhost:8080
+ # Connection: Keep-Alive
+ # Transfer-Encoding: chunked
+ # Content-Type: multipart/form-data; boundary=---MultipartBoundary-vp5j9HdSRYK8DvX2DhtpqEbMNjSN1wnL---
+ # Content-Encoding: gzip
+ #
+ # 2987 branch on Windows:
+ # User-Agent: Crashpad/0.8.0
+ # Host: localhost:8080
+ # Connection: Keep-Alive
+ # Content-Type: multipart/form-data; boundary=---MultipartBoundary-qFhorGA40vDJ1fgmc2mjorL0fRfKOqup---
+ # Content-Length: 609894
+ #
+ # 2883 branch on Linux:
+ # User-Agent: Wget/1.15 (linux-gnu)
+ # Host: localhost:8080
+ # Accept: */*
+ # Connection: Keep-Alive
+ # Content-Type: multipart/form-data; boundary=--------------------------83572861f14cc736
+ # Content-Length: 32237
+ # Content-Encoding: gzip
+ print(self.headers)
+
+ chunked = 'Transfer-Encoding' in self.headers and self.headers['Transfer-Encoding'].lower(
+ ) == 'chunked'
+ compressed = 'Content-Encoding' in self.headers and self.headers['Content-Encoding'].lower(
+ ) == 'gzip'
+ if chunked:
+ request_body = self._unchunk_request(compressed)
+ else:
+ content_length = int(self.headers[
+ 'Content-Length']) if 'Content-Length' in self.headers else 0
+ if content_length > 0:
+ request_body = self.rfile.read(content_length)
+ else:
+ request_body = self.rfile.read()
+ if compressed:
+ request_body = zlib.decompress(request_body, 16 + zlib.MAX_WBITS)
+
+ # Parse the multi-part request.
+ form_data = self._parse_post_data(request_body)
+ for key in form_data.keys():
+ if key == minidump_key and form_data[minidump_key].file:
+ dmp_stream = form_data[minidump_key].file
+ else:
+ metadata[key] = form_data[key].value
+
+ if dmp_stream is None:
+ # Exit early if the request is invalid.
+ print_msg('Invalid dump %s' % dump_id)
+ return
+
+ print_msg('Dump %s' % dump_id)
+
+ # Write the minidump to file.
+ dump_file = os.path.join(self._dump_directory, dump_id + '.dmp')
+ with open(dump_file, 'wb') as fp:
+ shutil.copyfileobj(dmp_stream, fp)
+
+ # Write the metadata to file.
+ meta_file = os.path.join(self._dump_directory, dump_id + '.json')
+ if is_python2:
+ with open(meta_file, 'w') as fp:
+ json.dump(
+ metadata,
+ fp,
+ ensure_ascii=False,
+ encoding='utf-8',
+ indent=2,
+ sort_keys=True)
+ else:
+ with open(meta_file, 'w', encoding='utf-8') as fp:
+ json.dump(metadata, fp, indent=2, sort_keys=True)
+
+
+def HandleRequestsUsing(dump_store):
+ return lambda *args: CrashHTTPRequestHandler(dump_directory, *args)
+
+
+def RunCrashServer(port, dump_directory):
+ """ Run the crash handler HTTP server. """
+ httpd = HTTPServer(('', port), HandleRequestsUsing(dump_directory))
+ print_msg('Starting httpd on port %d' % port)
+ httpd.serve_forever()
+
+
+# Program entry point.
+if __name__ == "__main__":
+ if len(sys.argv) != 3:
+ print('Usage: %s <port> <dump_directory>' % os.path.basename(sys.argv[0]))
+ sys.exit(1)
+
+ # Create the dump directory if necessary.
+ dump_directory = sys.argv[2]
+ if not os.path.exists(dump_directory):
+ os.makedirs(dump_directory)
+ if not os.path.isdir(dump_directory):
+ raise Exception('Directory does not exist: %s' % dump_directory)
+
+ RunCrashServer(int(sys.argv[1]), dump_directory)
diff --git a/tools/date_util.py b/tools/date_util.py
new file mode 100644
index 00000000..4c17620a
--- /dev/null
+++ b/tools/date_util.py
@@ -0,0 +1,16 @@
+# Copyright (c) 2011 The Chromium Embedded Framework Authors. All rights
+# reserved. Use of this source code is governed by a BSD-style license that
+# can be found in the LICENSE file.
+
+from __future__ import absolute_import
+import datetime
+
+
+def get_year():
+ """ Returns the current year. """
+ return str(datetime.datetime.now().year)
+
+
+def get_date():
+ """ Returns the current date. """
+ return datetime.datetime.now().strftime('%B %d, %Y')
diff --git a/tools/distrib/README-TRANSFER.txt b/tools/distrib/README-TRANSFER.txt
new file mode 100644
index 00000000..6843cc20
--- /dev/null
+++ b/tools/distrib/README-TRANSFER.txt
@@ -0,0 +1,5 @@
+Files in this directory have been copied from other locations in the Chromium
+source tree. They have been modified only to the extent necessary to work in
+the CEF Binary Distribution directory structure. Below is a listing of the
+original file locations.
+
diff --git a/tools/distrib/README.client.txt b/tools/distrib/README.client.txt
new file mode 100644
index 00000000..37970dd4
--- /dev/null
+++ b/tools/distrib/README.client.txt
@@ -0,0 +1,12 @@
+CONTENTS
+--------
+
+Release Contains a release build of the sample application.
+
+
+USAGE
+-----
+
+Please visit the CEF Website for additional usage information.
+
+https://bitbucket.org/chromiumembedded/cef/
diff --git a/tools/distrib/README.footer.txt b/tools/distrib/README.footer.txt
new file mode 100644
index 00000000..e57a6622
--- /dev/null
+++ b/tools/distrib/README.footer.txt
@@ -0,0 +1,8 @@
+LICENSING
+---------
+
+The CEF project is BSD licensed. Please read the LICENSE.txt file included with
+this binary distribution for licensing terms and conditions. Other software
+included in this distribution is provided under other licenses. Please visit
+"about:credits" in a CEF-based application for complete Chromium and third-party
+licensing information.
diff --git a/tools/distrib/README.header.txt b/tools/distrib/README.header.txt
new file mode 100644
index 00000000..26c0f981
--- /dev/null
+++ b/tools/distrib/README.header.txt
@@ -0,0 +1,14 @@
+Chromium Embedded Framework (CEF) $DISTRIB_TYPE$ Binary Distribution for $PLATFORM$
+-------------------------------------------------------------------------------
+
+Date: $DATE$
+
+CEF Version: $CEF_VER$
+CEF URL: $CEF_URL$
+ @$CEF_REV$
+
+Chromium Version: $CHROMIUM_VER$
+Chromium URL: $CHROMIUM_URL$
+ @$CHROMIUM_REV$
+
+$DISTRIB_DESC$
diff --git a/tools/distrib/gtest/LICENSE b/tools/distrib/gtest/LICENSE
new file mode 100644
index 00000000..1941a11f
--- /dev/null
+++ b/tools/distrib/gtest/LICENSE
@@ -0,0 +1,28 @@
+Copyright 2008, Google Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/tools/distrib/gtest/README.cef b/tools/distrib/gtest/README.cef
new file mode 100644
index 00000000..2a108812
--- /dev/null
+++ b/tools/distrib/gtest/README.cef
@@ -0,0 +1,17 @@
+Name: Google C++ Testing Framework
+Short Name: gtest
+URL: https://github.com/google/googletest
+License: BSD (see LICENSE file)
+
+Description:
+Fuzed (single header/source file) version of GoogleTest. Generated from a
+Chromium version 93.0.4577.51 source checkout with the following command:
+
+cd /path/to/chromium/src/third_party/googletest/src/googletest/scripts
+./fuse_gtest_files.py <out_directory>
+
+This script was removed from GTest in
+https://github.com/google/googletest/commit/47f819c3ca.
+
+Local Modifications:
+None.
diff --git a/tools/distrib/gtest/gtest-all.cc b/tools/distrib/gtest/gtest-all.cc
new file mode 100644
index 00000000..5aaebc6d
--- /dev/null
+++ b/tools/distrib/gtest/gtest-all.cc
@@ -0,0 +1,12501 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+//
+// Google C++ Testing and Mocking Framework (Google Test)
+//
+// Sometimes it's desirable to build Google Test by compiling a single file.
+// This file serves this purpose.
+
+// This line ensures that gtest.h can be compiled on its own, even
+// when it's fused.
+#include "gtest/gtest.h"
+
+// The following lines pull in the real gtest *.cc files.
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+//
+// The Google C++ Testing and Mocking Framework (Google Test)
+
+// Copyright 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+//
+// Utilities for testing Google Test itself and code that uses Google Test
+// (e.g. frameworks built on top of Google Test).
+
+// GOOGLETEST_CM0004 DO NOT DELETE
+
+#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_SPI_H_
+#define GOOGLETEST_INCLUDE_GTEST_GTEST_SPI_H_
+
+
+GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \
+/* class A needs to have dll-interface to be used by clients of class B */)
+
+namespace testing {
+
+// This helper class can be used to mock out Google Test failure reporting
+// so that we can test Google Test or code that builds on Google Test.
+//
+// An object of this class appends a TestPartResult object to the
+// TestPartResultArray object given in the constructor whenever a Google Test
+// failure is reported. It can either intercept only failures that are
+// generated in the same thread that created this object or it can intercept
+// all generated failures. The scope of this mock object can be controlled with
+// the second argument to the two arguments constructor.
+class GTEST_API_ ScopedFakeTestPartResultReporter
+ : public TestPartResultReporterInterface {
+ public:
+ // The two possible mocking modes of this object.
+ enum InterceptMode {
+ INTERCEPT_ONLY_CURRENT_THREAD, // Intercepts only thread local failures.
+ INTERCEPT_ALL_THREADS // Intercepts all failures.
+ };
+
+ // The c'tor sets this object as the test part result reporter used
+ // by Google Test. The 'result' parameter specifies where to report the
+ // results. This reporter will only catch failures generated in the current
+ // thread. DEPRECATED
+ explicit ScopedFakeTestPartResultReporter(TestPartResultArray* result);
+
+ // Same as above, but you can choose the interception scope of this object.
+ ScopedFakeTestPartResultReporter(InterceptMode intercept_mode,
+ TestPartResultArray* result);
+
+ // The d'tor restores the previous test part result reporter.
+ ~ScopedFakeTestPartResultReporter() override;
+
+ // Appends the TestPartResult object to the TestPartResultArray
+ // received in the constructor.
+ //
+ // This method is from the TestPartResultReporterInterface
+ // interface.
+ void ReportTestPartResult(const TestPartResult& result) override;
+
+ private:
+ void Init();
+
+ const InterceptMode intercept_mode_;
+ TestPartResultReporterInterface* old_reporter_;
+ TestPartResultArray* const result_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedFakeTestPartResultReporter);
+};
+
+namespace internal {
+
+// A helper class for implementing EXPECT_FATAL_FAILURE() and
+// EXPECT_NONFATAL_FAILURE(). Its destructor verifies that the given
+// TestPartResultArray contains exactly one failure that has the given
+// type and contains the given substring. If that's not the case, a
+// non-fatal failure will be generated.
+class GTEST_API_ SingleFailureChecker {
+ public:
+ // The constructor remembers the arguments.
+ SingleFailureChecker(const TestPartResultArray* results,
+ TestPartResult::Type type, const std::string& substr);
+ ~SingleFailureChecker();
+ private:
+ const TestPartResultArray* const results_;
+ const TestPartResult::Type type_;
+ const std::string substr_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(SingleFailureChecker);
+};
+
+} // namespace internal
+
+} // namespace testing
+
+GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251
+
+// A set of macros for testing Google Test assertions or code that's expected
+// to generate Google Test fatal failures. It verifies that the given
+// statement will cause exactly one fatal Google Test failure with 'substr'
+// being part of the failure message.
+//
+// There are two different versions of this macro. EXPECT_FATAL_FAILURE only
+// affects and considers failures generated in the current thread and
+// EXPECT_FATAL_FAILURE_ON_ALL_THREADS does the same but for all threads.
+//
+// The verification of the assertion is done correctly even when the statement
+// throws an exception or aborts the current function.
+//
+// Known restrictions:
+// - 'statement' cannot reference local non-static variables or
+// non-static members of the current object.
+// - 'statement' cannot return a value.
+// - You cannot stream a failure message to this macro.
+//
+// Note that even though the implementations of the following two
+// macros are much alike, we cannot refactor them to use a common
+// helper macro, due to some peculiarity in how the preprocessor
+// works. The AcceptsMacroThatExpandsToUnprotectedComma test in
+// gtest_unittest.cc will fail to compile if we do that.
+#define EXPECT_FATAL_FAILURE(statement, substr) \
+ do { \
+ class GTestExpectFatalFailureHelper {\
+ public:\
+ static void Execute() { statement; }\
+ };\
+ ::testing::TestPartResultArray gtest_failures;\
+ ::testing::internal::SingleFailureChecker gtest_checker(\
+ &gtest_failures, ::testing::TestPartResult::kFatalFailure, (substr));\
+ {\
+ ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
+ ::testing::ScopedFakeTestPartResultReporter:: \
+ INTERCEPT_ONLY_CURRENT_THREAD, &gtest_failures);\
+ GTestExpectFatalFailureHelper::Execute();\
+ }\
+ } while (::testing::internal::AlwaysFalse())
+
+#define EXPECT_FATAL_FAILURE_ON_ALL_THREADS(statement, substr) \
+ do { \
+ class GTestExpectFatalFailureHelper {\
+ public:\
+ static void Execute() { statement; }\
+ };\
+ ::testing::TestPartResultArray gtest_failures;\
+ ::testing::internal::SingleFailureChecker gtest_checker(\
+ &gtest_failures, ::testing::TestPartResult::kFatalFailure, (substr));\
+ {\
+ ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
+ ::testing::ScopedFakeTestPartResultReporter:: \
+ INTERCEPT_ALL_THREADS, &gtest_failures);\
+ GTestExpectFatalFailureHelper::Execute();\
+ }\
+ } while (::testing::internal::AlwaysFalse())
+
+// A macro for testing Google Test assertions or code that's expected to
+// generate Google Test non-fatal failures. It asserts that the given
+// statement will cause exactly one non-fatal Google Test failure with 'substr'
+// being part of the failure message.
+//
+// There are two different versions of this macro. EXPECT_NONFATAL_FAILURE only
+// affects and considers failures generated in the current thread and
+// EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS does the same but for all threads.
+//
+// 'statement' is allowed to reference local variables and members of
+// the current object.
+//
+// The verification of the assertion is done correctly even when the statement
+// throws an exception or aborts the current function.
+//
+// Known restrictions:
+// - You cannot stream a failure message to this macro.
+//
+// Note that even though the implementations of the following two
+// macros are much alike, we cannot refactor them to use a common
+// helper macro, due to some peculiarity in how the preprocessor
+// works. If we do that, the code won't compile when the user gives
+// EXPECT_NONFATAL_FAILURE() a statement that contains a macro that
+// expands to code containing an unprotected comma. The
+// AcceptsMacroThatExpandsToUnprotectedComma test in gtest_unittest.cc
+// catches that.
+//
+// For the same reason, we have to write
+// if (::testing::internal::AlwaysTrue()) { statement; }
+// instead of
+// GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement)
+// to avoid an MSVC warning on unreachable code.
+#define EXPECT_NONFATAL_FAILURE(statement, substr) \
+ do {\
+ ::testing::TestPartResultArray gtest_failures;\
+ ::testing::internal::SingleFailureChecker gtest_checker(\
+ &gtest_failures, ::testing::TestPartResult::kNonFatalFailure, \
+ (substr));\
+ {\
+ ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
+ ::testing::ScopedFakeTestPartResultReporter:: \
+ INTERCEPT_ONLY_CURRENT_THREAD, &gtest_failures);\
+ if (::testing::internal::AlwaysTrue()) { statement; }\
+ }\
+ } while (::testing::internal::AlwaysFalse())
+
+#define EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(statement, substr) \
+ do {\
+ ::testing::TestPartResultArray gtest_failures;\
+ ::testing::internal::SingleFailureChecker gtest_checker(\
+ &gtest_failures, ::testing::TestPartResult::kNonFatalFailure, \
+ (substr));\
+ {\
+ ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
+ ::testing::ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS, \
+ &gtest_failures);\
+ if (::testing::internal::AlwaysTrue()) { statement; }\
+ }\
+ } while (::testing::internal::AlwaysFalse())
+
+#endif // GOOGLETEST_INCLUDE_GTEST_GTEST_SPI_H_
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <wchar.h>
+#include <wctype.h>
+
+#include <algorithm>
+#include <chrono> // NOLINT
+#include <cmath>
+#include <cstdint>
+#include <iomanip>
+#include <limits>
+#include <list>
+#include <map>
+#include <ostream> // NOLINT
+#include <sstream>
+#include <vector>
+
+#if GTEST_OS_LINUX
+
+# include <fcntl.h> // NOLINT
+# include <limits.h> // NOLINT
+# include <sched.h> // NOLINT
+// Declares vsnprintf(). This header is not available on Windows.
+# include <strings.h> // NOLINT
+# include <sys/mman.h> // NOLINT
+# include <sys/time.h> // NOLINT
+# include <unistd.h> // NOLINT
+# include <string>
+
+#elif GTEST_OS_ZOS
+# include <sys/time.h> // NOLINT
+
+// On z/OS we additionally need strings.h for strcasecmp.
+# include <strings.h> // NOLINT
+
+#elif GTEST_OS_WINDOWS_MOBILE // We are on Windows CE.
+
+# include <windows.h> // NOLINT
+# undef min
+
+#elif GTEST_OS_WINDOWS // We are on Windows proper.
+
+# include <windows.h> // NOLINT
+# undef min
+
+#ifdef _MSC_VER
+# include <crtdbg.h> // NOLINT
+#endif
+
+# include <io.h> // NOLINT
+# include <sys/timeb.h> // NOLINT
+# include <sys/types.h> // NOLINT
+# include <sys/stat.h> // NOLINT
+
+# if GTEST_OS_WINDOWS_MINGW
+# include <sys/time.h> // NOLINT
+# endif // GTEST_OS_WINDOWS_MINGW
+
+#else
+
+// cpplint thinks that the header is already included, so we want to
+// silence it.
+# include <sys/time.h> // NOLINT
+# include <unistd.h> // NOLINT
+
+#endif // GTEST_OS_LINUX
+
+#if GTEST_HAS_EXCEPTIONS
+# include <stdexcept>
+#endif
+
+#if GTEST_CAN_STREAM_RESULTS_
+# include <arpa/inet.h> // NOLINT
+# include <netdb.h> // NOLINT
+# include <sys/socket.h> // NOLINT
+# include <sys/types.h> // NOLINT
+#endif
+
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Utility functions and classes used by the Google C++ testing framework.//
+// This file contains purely Google Test's internal implementation. Please
+// DO NOT #INCLUDE IT IN A USER PROGRAM.
+
+#ifndef GOOGLETEST_SRC_GTEST_INTERNAL_INL_H_
+#define GOOGLETEST_SRC_GTEST_INTERNAL_INL_H_
+
+#ifndef _WIN32_WCE
+# include <errno.h>
+#endif // !_WIN32_WCE
+#include <stddef.h>
+#include <stdlib.h> // For strtoll/_strtoul64/malloc/free.
+#include <string.h> // For memmove.
+
+#include <algorithm>
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <vector>
+
+
+#if GTEST_CAN_STREAM_RESULTS_
+# include <arpa/inet.h> // NOLINT
+# include <netdb.h> // NOLINT
+#endif
+
+#if GTEST_OS_WINDOWS
+# include <windows.h> // NOLINT
+#endif // GTEST_OS_WINDOWS
+
+
+GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \
+/* class A needs to have dll-interface to be used by clients of class B */)
+
+namespace testing {
+
+// Declares the flags.
+//
+// We don't want the users to modify this flag in the code, but want
+// Google Test's own unit tests to be able to access it. Therefore we
+// declare it here as opposed to in gtest.h.
+GTEST_DECLARE_bool_(death_test_use_fork);
+
+namespace internal {
+
+// The value of GetTestTypeId() as seen from within the Google Test
+// library. This is solely for testing GetTestTypeId().
+GTEST_API_ extern const TypeId kTestTypeIdInGoogleTest;
+
+// Names of the flags (needed for parsing Google Test flags).
+const char kAlsoRunDisabledTestsFlag[] = "also_run_disabled_tests";
+const char kBreakOnFailureFlag[] = "break_on_failure";
+const char kCatchExceptionsFlag[] = "catch_exceptions";
+const char kColorFlag[] = "color";
+const char kFailFast[] = "fail_fast";
+const char kFilterFlag[] = "filter";
+const char kListTestsFlag[] = "list_tests";
+const char kOutputFlag[] = "output";
+const char kBriefFlag[] = "brief";
+const char kPrintTimeFlag[] = "print_time";
+const char kPrintUTF8Flag[] = "print_utf8";
+const char kRandomSeedFlag[] = "random_seed";
+const char kRepeatFlag[] = "repeat";
+const char kShuffleFlag[] = "shuffle";
+const char kStackTraceDepthFlag[] = "stack_trace_depth";
+const char kStreamResultToFlag[] = "stream_result_to";
+const char kThrowOnFailureFlag[] = "throw_on_failure";
+const char kFlagfileFlag[] = "flagfile";
+
+// A valid random seed must be in [1, kMaxRandomSeed].
+const int kMaxRandomSeed = 99999;
+
+// g_help_flag is true if and only if the --help flag or an equivalent form
+// is specified on the command line.
+GTEST_API_ extern bool g_help_flag;
+
+// Returns the current time in milliseconds.
+GTEST_API_ TimeInMillis GetTimeInMillis();
+
+// Returns true if and only if Google Test should use colors in the output.
+GTEST_API_ bool ShouldUseColor(bool stdout_is_tty);
+
+// Formats the given time in milliseconds as seconds.
+GTEST_API_ std::string FormatTimeInMillisAsSeconds(TimeInMillis ms);
+
+// Converts the given time in milliseconds to a date string in the ISO 8601
+// format, without the timezone information. N.B.: due to the use the
+// non-reentrant localtime() function, this function is not thread safe. Do
+// not use it in any code that can be called from multiple threads.
+GTEST_API_ std::string FormatEpochTimeInMillisAsIso8601(TimeInMillis ms);
+
+// Parses a string for an Int32 flag, in the form of "--flag=value".
+//
+// On success, stores the value of the flag in *value, and returns
+// true. On failure, returns false without changing *value.
+GTEST_API_ bool ParseInt32Flag(
+ const char* str, const char* flag, int32_t* value);
+
+// Returns a random seed in range [1, kMaxRandomSeed] based on the
+// given --gtest_random_seed flag value.
+inline int GetRandomSeedFromFlag(int32_t random_seed_flag) {
+ const unsigned int raw_seed = (random_seed_flag == 0) ?
+ static_cast<unsigned int>(GetTimeInMillis()) :
+ static_cast<unsigned int>(random_seed_flag);
+
+ // Normalizes the actual seed to range [1, kMaxRandomSeed] such that
+ // it's easy to type.
+ const int normalized_seed =
+ static_cast<int>((raw_seed - 1U) %
+ static_cast<unsigned int>(kMaxRandomSeed)) + 1;
+ return normalized_seed;
+}
+
+// Returns the first valid random seed after 'seed'. The behavior is
+// undefined if 'seed' is invalid. The seed after kMaxRandomSeed is
+// considered to be 1.
+inline int GetNextRandomSeed(int seed) {
+ GTEST_CHECK_(1 <= seed && seed <= kMaxRandomSeed)
+ << "Invalid random seed " << seed << " - must be in [1, "
+ << kMaxRandomSeed << "].";
+ const int next_seed = seed + 1;
+ return (next_seed > kMaxRandomSeed) ? 1 : next_seed;
+}
+
+// This class saves the values of all Google Test flags in its c'tor, and
+// restores them in its d'tor.
+class GTestFlagSaver {
+ public:
+ // The c'tor.
+ GTestFlagSaver() {
+ also_run_disabled_tests_ = GTEST_FLAG(also_run_disabled_tests);
+ break_on_failure_ = GTEST_FLAG(break_on_failure);
+ catch_exceptions_ = GTEST_FLAG(catch_exceptions);
+ color_ = GTEST_FLAG(color);
+ death_test_style_ = GTEST_FLAG(death_test_style);
+ death_test_use_fork_ = GTEST_FLAG(death_test_use_fork);
+ fail_fast_ = GTEST_FLAG(fail_fast);
+ filter_ = GTEST_FLAG(filter);
+ internal_run_death_test_ = GTEST_FLAG(internal_run_death_test);
+ list_tests_ = GTEST_FLAG(list_tests);
+ output_ = GTEST_FLAG(output);
+ brief_ = GTEST_FLAG(brief);
+ print_time_ = GTEST_FLAG(print_time);
+ print_utf8_ = GTEST_FLAG(print_utf8);
+ random_seed_ = GTEST_FLAG(random_seed);
+ repeat_ = GTEST_FLAG(repeat);
+ shuffle_ = GTEST_FLAG(shuffle);
+ stack_trace_depth_ = GTEST_FLAG(stack_trace_depth);
+ stream_result_to_ = GTEST_FLAG(stream_result_to);
+ throw_on_failure_ = GTEST_FLAG(throw_on_failure);
+ }
+
+ // The d'tor is not virtual. DO NOT INHERIT FROM THIS CLASS.
+ ~GTestFlagSaver() {
+ GTEST_FLAG(also_run_disabled_tests) = also_run_disabled_tests_;
+ GTEST_FLAG(break_on_failure) = break_on_failure_;
+ GTEST_FLAG(catch_exceptions) = catch_exceptions_;
+ GTEST_FLAG(color) = color_;
+ GTEST_FLAG(death_test_style) = death_test_style_;
+ GTEST_FLAG(death_test_use_fork) = death_test_use_fork_;
+ GTEST_FLAG(filter) = filter_;
+ GTEST_FLAG(fail_fast) = fail_fast_;
+ GTEST_FLAG(internal_run_death_test) = internal_run_death_test_;
+ GTEST_FLAG(list_tests) = list_tests_;
+ GTEST_FLAG(output) = output_;
+ GTEST_FLAG(brief) = brief_;
+ GTEST_FLAG(print_time) = print_time_;
+ GTEST_FLAG(print_utf8) = print_utf8_;
+ GTEST_FLAG(random_seed) = random_seed_;
+ GTEST_FLAG(repeat) = repeat_;
+ GTEST_FLAG(shuffle) = shuffle_;
+ GTEST_FLAG(stack_trace_depth) = stack_trace_depth_;
+ GTEST_FLAG(stream_result_to) = stream_result_to_;
+ GTEST_FLAG(throw_on_failure) = throw_on_failure_;
+ }
+
+ private:
+ // Fields for saving the original values of flags.
+ bool also_run_disabled_tests_;
+ bool break_on_failure_;
+ bool catch_exceptions_;
+ std::string color_;
+ std::string death_test_style_;
+ bool death_test_use_fork_;
+ bool fail_fast_;
+ std::string filter_;
+ std::string internal_run_death_test_;
+ bool list_tests_;
+ std::string output_;
+ bool brief_;
+ bool print_time_;
+ bool print_utf8_;
+ int32_t random_seed_;
+ int32_t repeat_;
+ bool shuffle_;
+ int32_t stack_trace_depth_;
+ std::string stream_result_to_;
+ bool throw_on_failure_;
+} GTEST_ATTRIBUTE_UNUSED_;
+
+// Converts a Unicode code point to a narrow string in UTF-8 encoding.
+// code_point parameter is of type UInt32 because wchar_t may not be
+// wide enough to contain a code point.
+// If the code_point is not a valid Unicode code point
+// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be converted
+// to "(Invalid Unicode 0xXXXXXXXX)".
+GTEST_API_ std::string CodePointToUtf8(uint32_t code_point);
+
+// Converts a wide string to a narrow string in UTF-8 encoding.
+// The wide string is assumed to have the following encoding:
+// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin)
+// UTF-32 if sizeof(wchar_t) == 4 (on Linux)
+// Parameter str points to a null-terminated wide string.
+// Parameter num_chars may additionally limit the number
+// of wchar_t characters processed. -1 is used when the entire string
+// should be processed.
+// If the string contains code points that are not valid Unicode code points
+// (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output
+// as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding
+// and contains invalid UTF-16 surrogate pairs, values in those pairs
+// will be encoded as individual Unicode characters from Basic Normal Plane.
+GTEST_API_ std::string WideStringToUtf8(const wchar_t* str, int num_chars);
+
+// Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file
+// if the variable is present. If a file already exists at this location, this
+// function will write over it. If the variable is present, but the file cannot
+// be created, prints an error and exits.
+void WriteToShardStatusFileIfNeeded();
+
+// Checks whether sharding is enabled by examining the relevant
+// environment variable values. If the variables are present,
+// but inconsistent (e.g., shard_index >= total_shards), prints
+// an error and exits. If in_subprocess_for_death_test, sharding is
+// disabled because it must only be applied to the original test
+// process. Otherwise, we could filter out death tests we intended to execute.
+GTEST_API_ bool ShouldShard(const char* total_shards_str,
+ const char* shard_index_str,
+ bool in_subprocess_for_death_test);
+
+// Parses the environment variable var as a 32-bit integer. If it is unset,
+// returns default_val. If it is not a 32-bit integer, prints an error and
+// and aborts.
+GTEST_API_ int32_t Int32FromEnvOrDie(const char* env_var, int32_t default_val);
+
+// Given the total number of shards, the shard index, and the test id,
+// returns true if and only if the test should be run on this shard. The test id
+// is some arbitrary but unique non-negative integer assigned to each test
+// method. Assumes that 0 <= shard_index < total_shards.
+GTEST_API_ bool ShouldRunTestOnShard(
+ int total_shards, int shard_index, int test_id);
+
+// STL container utilities.
+
+// Returns the number of elements in the given container that satisfy
+// the given predicate.
+template <class Container, typename Predicate>
+inline int CountIf(const Container& c, Predicate predicate) {
+ // Implemented as an explicit loop since std::count_if() in libCstd on
+ // Solaris has a non-standard signature.
+ int count = 0;
+ for (typename Container::const_iterator it = c.begin(); it != c.end(); ++it) {
+ if (predicate(*it))
+ ++count;
+ }
+ return count;
+}
+
+// Applies a function/functor to each element in the container.
+template <class Container, typename Functor>
+void ForEach(const Container& c, Functor functor) {
+ std::for_each(c.begin(), c.end(), functor);
+}
+
+// Returns the i-th element of the vector, or default_value if i is not
+// in range [0, v.size()).
+template <typename E>
+inline E GetElementOr(const std::vector<E>& v, int i, E default_value) {
+ return (i < 0 || i >= static_cast<int>(v.size())) ? default_value
+ : v[static_cast<size_t>(i)];
+}
+
+// Performs an in-place shuffle of a range of the vector's elements.
+// 'begin' and 'end' are element indices as an STL-style range;
+// i.e. [begin, end) are shuffled, where 'end' == size() means to
+// shuffle to the end of the vector.
+template <typename E>
+void ShuffleRange(internal::Random* random, int begin, int end,
+ std::vector<E>* v) {
+ const int size = static_cast<int>(v->size());
+ GTEST_CHECK_(0 <= begin && begin <= size)
+ << "Invalid shuffle range start " << begin << ": must be in range [0, "
+ << size << "].";
+ GTEST_CHECK_(begin <= end && end <= size)
+ << "Invalid shuffle range finish " << end << ": must be in range ["
+ << begin << ", " << size << "].";
+
+ // Fisher-Yates shuffle, from
+ // http://en.wikipedia.org/wiki/Fisher-Yates_shuffle
+ for (int range_width = end - begin; range_width >= 2; range_width--) {
+ const int last_in_range = begin + range_width - 1;
+ const int selected =
+ begin +
+ static_cast<int>(random->Generate(static_cast<uint32_t>(range_width)));
+ std::swap((*v)[static_cast<size_t>(selected)],
+ (*v)[static_cast<size_t>(last_in_range)]);
+ }
+}
+
+// Performs an in-place shuffle of the vector's elements.
+template <typename E>
+inline void Shuffle(internal::Random* random, std::vector<E>* v) {
+ ShuffleRange(random, 0, static_cast<int>(v->size()), v);
+}
+
+// A function for deleting an object. Handy for being used as a
+// functor.
+template <typename T>
+static void Delete(T* x) {
+ delete x;
+}
+
+// A predicate that checks the key of a TestProperty against a known key.
+//
+// TestPropertyKeyIs is copyable.
+class TestPropertyKeyIs {
+ public:
+ // Constructor.
+ //
+ // TestPropertyKeyIs has NO default constructor.
+ explicit TestPropertyKeyIs(const std::string& key) : key_(key) {}
+
+ // Returns true if and only if the test name of test property matches on key_.
+ bool operator()(const TestProperty& test_property) const {
+ return test_property.key() == key_;
+ }
+
+ private:
+ std::string key_;
+};
+
+// Class UnitTestOptions.
+//
+// This class contains functions for processing options the user
+// specifies when running the tests. It has only static members.
+//
+// In most cases, the user can specify an option using either an
+// environment variable or a command line flag. E.g. you can set the
+// test filter using either GTEST_FILTER or --gtest_filter. If both
+// the variable and the flag are present, the latter overrides the
+// former.
+class GTEST_API_ UnitTestOptions {
+ public:
+ // Functions for processing the gtest_output flag.
+
+ // Returns the output format, or "" for normal printed output.
+ static std::string GetOutputFormat();
+
+ // Returns the absolute path of the requested output file, or the
+ // default (test_detail.xml in the original working directory) if
+ // none was explicitly specified.
+ static std::string GetAbsolutePathToOutputFile();
+
+ // Functions for processing the gtest_filter flag.
+
+ // Returns true if and only if the user-specified filter matches the test
+ // suite name and the test name.
+ static bool FilterMatchesTest(const std::string& test_suite_name,
+ const std::string& test_name);
+
+#if GTEST_OS_WINDOWS
+ // Function for supporting the gtest_catch_exception flag.
+
+ // Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the
+ // given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise.
+ // This function is useful as an __except condition.
+ static int GTestShouldProcessSEH(DWORD exception_code);
+#endif // GTEST_OS_WINDOWS
+
+ // Returns true if "name" matches the ':' separated list of glob-style
+ // filters in "filter".
+ static bool MatchesFilter(const std::string& name, const char* filter);
+};
+
+// Returns the current application's name, removing directory path if that
+// is present. Used by UnitTestOptions::GetOutputFile.
+GTEST_API_ FilePath GetCurrentExecutableName();
+
+// The role interface for getting the OS stack trace as a string.
+class OsStackTraceGetterInterface {
+ public:
+ OsStackTraceGetterInterface() {}
+ virtual ~OsStackTraceGetterInterface() {}
+
+ // Returns the current OS stack trace as an std::string. Parameters:
+ //
+ // max_depth - the maximum number of stack frames to be included
+ // in the trace.
+ // skip_count - the number of top frames to be skipped; doesn't count
+ // against max_depth.
+ virtual std::string CurrentStackTrace(int max_depth, int skip_count) = 0;
+
+ // UponLeavingGTest() should be called immediately before Google Test calls
+ // user code. It saves some information about the current stack that
+ // CurrentStackTrace() will use to find and hide Google Test stack frames.
+ virtual void UponLeavingGTest() = 0;
+
+ // This string is inserted in place of stack frames that are part of
+ // Google Test's implementation.
+ static const char* const kElidedFramesMarker;
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetterInterface);
+};
+
+// A working implementation of the OsStackTraceGetterInterface interface.
+class OsStackTraceGetter : public OsStackTraceGetterInterface {
+ public:
+ OsStackTraceGetter() {}
+
+ std::string CurrentStackTrace(int max_depth, int skip_count) override;
+ void UponLeavingGTest() override;
+
+ private:
+#if GTEST_HAS_ABSL
+ Mutex mutex_; // Protects all internal state.
+
+ // We save the stack frame below the frame that calls user code.
+ // We do this because the address of the frame immediately below
+ // the user code changes between the call to UponLeavingGTest()
+ // and any calls to the stack trace code from within the user code.
+ void* caller_frame_ = nullptr;
+#endif // GTEST_HAS_ABSL
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetter);
+};
+
+// Information about a Google Test trace point.
+struct TraceInfo {
+ const char* file;
+ int line;
+ std::string message;
+};
+
+// This is the default global test part result reporter used in UnitTestImpl.
+// This class should only be used by UnitTestImpl.
+class DefaultGlobalTestPartResultReporter
+ : public TestPartResultReporterInterface {
+ public:
+ explicit DefaultGlobalTestPartResultReporter(UnitTestImpl* unit_test);
+ // Implements the TestPartResultReporterInterface. Reports the test part
+ // result in the current test.
+ void ReportTestPartResult(const TestPartResult& result) override;
+
+ private:
+ UnitTestImpl* const unit_test_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultGlobalTestPartResultReporter);
+};
+
+// This is the default per thread test part result reporter used in
+// UnitTestImpl. This class should only be used by UnitTestImpl.
+class DefaultPerThreadTestPartResultReporter
+ : public TestPartResultReporterInterface {
+ public:
+ explicit DefaultPerThreadTestPartResultReporter(UnitTestImpl* unit_test);
+ // Implements the TestPartResultReporterInterface. The implementation just
+ // delegates to the current global test part result reporter of *unit_test_.
+ void ReportTestPartResult(const TestPartResult& result) override;
+
+ private:
+ UnitTestImpl* const unit_test_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultPerThreadTestPartResultReporter);
+};
+
+// The private implementation of the UnitTest class. We don't protect
+// the methods under a mutex, as this class is not accessible by a
+// user and the UnitTest class that delegates work to this class does
+// proper locking.
+class GTEST_API_ UnitTestImpl {
+ public:
+ explicit UnitTestImpl(UnitTest* parent);
+ virtual ~UnitTestImpl();
+
+ // There are two different ways to register your own TestPartResultReporter.
+ // You can register your own repoter to listen either only for test results
+ // from the current thread or for results from all threads.
+ // By default, each per-thread test result repoter just passes a new
+ // TestPartResult to the global test result reporter, which registers the
+ // test part result for the currently running test.
+
+ // Returns the global test part result reporter.
+ TestPartResultReporterInterface* GetGlobalTestPartResultReporter();
+
+ // Sets the global test part result reporter.
+ void SetGlobalTestPartResultReporter(
+ TestPartResultReporterInterface* reporter);
+
+ // Returns the test part result reporter for the current thread.
+ TestPartResultReporterInterface* GetTestPartResultReporterForCurrentThread();
+
+ // Sets the test part result reporter for the current thread.
+ void SetTestPartResultReporterForCurrentThread(
+ TestPartResultReporterInterface* reporter);
+
+ // Gets the number of successful test suites.
+ int successful_test_suite_count() const;
+
+ // Gets the number of failed test suites.
+ int failed_test_suite_count() const;
+
+ // Gets the number of all test suites.
+ int total_test_suite_count() const;
+
+ // Gets the number of all test suites that contain at least one test
+ // that should run.
+ int test_suite_to_run_count() const;
+
+ // Gets the number of successful tests.
+ int successful_test_count() const;
+
+ // Gets the number of skipped tests.
+ int skipped_test_count() const;
+
+ // Gets the number of failed tests.
+ int failed_test_count() const;
+
+ // Gets the number of disabled tests that will be reported in the XML report.
+ int reportable_disabled_test_count() const;
+
+ // Gets the number of disabled tests.
+ int disabled_test_count() const;
+
+ // Gets the number of tests to be printed in the XML report.
+ int reportable_test_count() const;
+
+ // Gets the number of all tests.
+ int total_test_count() const;
+
+ // Gets the number of tests that should run.
+ int test_to_run_count() const;
+
+ // Gets the time of the test program start, in ms from the start of the
+ // UNIX epoch.
+ TimeInMillis start_timestamp() const { return start_timestamp_; }
+
+ // Gets the elapsed time, in milliseconds.
+ TimeInMillis elapsed_time() const { return elapsed_time_; }
+
+ // Returns true if and only if the unit test passed (i.e. all test suites
+ // passed).
+ bool Passed() const { return !Failed(); }
+
+ // Returns true if and only if the unit test failed (i.e. some test suite
+ // failed or something outside of all tests failed).
+ bool Failed() const {
+ return failed_test_suite_count() > 0 || ad_hoc_test_result()->Failed();
+ }
+
+ // Gets the i-th test suite among all the test suites. i can range from 0 to
+ // total_test_suite_count() - 1. If i is not in that range, returns NULL.
+ const TestSuite* GetTestSuite(int i) const {
+ const int index = GetElementOr(test_suite_indices_, i, -1);
+ return index < 0 ? nullptr : test_suites_[static_cast<size_t>(i)];
+ }
+
+ // Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ const TestCase* GetTestCase(int i) const { return GetTestSuite(i); }
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+ // Gets the i-th test suite among all the test suites. i can range from 0 to
+ // total_test_suite_count() - 1. If i is not in that range, returns NULL.
+ TestSuite* GetMutableSuiteCase(int i) {
+ const int index = GetElementOr(test_suite_indices_, i, -1);
+ return index < 0 ? nullptr : test_suites_[static_cast<size_t>(index)];
+ }
+
+ // Provides access to the event listener list.
+ TestEventListeners* listeners() { return &listeners_; }
+
+ // Returns the TestResult for the test that's currently running, or
+ // the TestResult for the ad hoc test if no test is running.
+ TestResult* current_test_result();
+
+ // Returns the TestResult for the ad hoc test.
+ const TestResult* ad_hoc_test_result() const { return &ad_hoc_test_result_; }
+
+ // Sets the OS stack trace getter.
+ //
+ // Does nothing if the input and the current OS stack trace getter
+ // are the same; otherwise, deletes the old getter and makes the
+ // input the current getter.
+ void set_os_stack_trace_getter(OsStackTraceGetterInterface* getter);
+
+ // Returns the current OS stack trace getter if it is not NULL;
+ // otherwise, creates an OsStackTraceGetter, makes it the current
+ // getter, and returns it.
+ OsStackTraceGetterInterface* os_stack_trace_getter();
+
+ // Returns the current OS stack trace as an std::string.
+ //
+ // The maximum number of stack frames to be included is specified by
+ // the gtest_stack_trace_depth flag. The skip_count parameter
+ // specifies the number of top frames to be skipped, which doesn't
+ // count against the number of frames to be included.
+ //
+ // For example, if Foo() calls Bar(), which in turn calls
+ // CurrentOsStackTraceExceptTop(1), Foo() will be included in the
+ // trace but Bar() and CurrentOsStackTraceExceptTop() won't.
+ std::string CurrentOsStackTraceExceptTop(int skip_count) GTEST_NO_INLINE_;
+
+ // Finds and returns a TestSuite with the given name. If one doesn't
+ // exist, creates one and returns it.
+ //
+ // Arguments:
+ //
+ // test_suite_name: name of the test suite
+ // type_param: the name of the test's type parameter, or NULL if
+ // this is not a typed or a type-parameterized test.
+ // set_up_tc: pointer to the function that sets up the test suite
+ // tear_down_tc: pointer to the function that tears down the test suite
+ TestSuite* GetTestSuite(const char* test_suite_name, const char* type_param,
+ internal::SetUpTestSuiteFunc set_up_tc,
+ internal::TearDownTestSuiteFunc tear_down_tc);
+
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ TestCase* GetTestCase(const char* test_case_name, const char* type_param,
+ internal::SetUpTestSuiteFunc set_up_tc,
+ internal::TearDownTestSuiteFunc tear_down_tc) {
+ return GetTestSuite(test_case_name, type_param, set_up_tc, tear_down_tc);
+ }
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+ // Adds a TestInfo to the unit test.
+ //
+ // Arguments:
+ //
+ // set_up_tc: pointer to the function that sets up the test suite
+ // tear_down_tc: pointer to the function that tears down the test suite
+ // test_info: the TestInfo object
+ void AddTestInfo(internal::SetUpTestSuiteFunc set_up_tc,
+ internal::TearDownTestSuiteFunc tear_down_tc,
+ TestInfo* test_info) {
+#if GTEST_HAS_DEATH_TEST
+ // In order to support thread-safe death tests, we need to
+ // remember the original working directory when the test program
+ // was first invoked. We cannot do this in RUN_ALL_TESTS(), as
+ // the user may have changed the current directory before calling
+ // RUN_ALL_TESTS(). Therefore we capture the current directory in
+ // AddTestInfo(), which is called to register a TEST or TEST_F
+ // before main() is reached.
+ if (original_working_dir_.IsEmpty()) {
+ original_working_dir_.Set(FilePath::GetCurrentDir());
+ GTEST_CHECK_(!original_working_dir_.IsEmpty())
+ << "Failed to get the current working directory.";
+ }
+#endif // GTEST_HAS_DEATH_TEST
+
+ GetTestSuite(test_info->test_suite_name(), test_info->type_param(),
+ set_up_tc, tear_down_tc)
+ ->AddTestInfo(test_info);
+ }
+
+ // Returns ParameterizedTestSuiteRegistry object used to keep track of
+ // value-parameterized tests and instantiate and register them.
+ internal::ParameterizedTestSuiteRegistry& parameterized_test_registry() {
+ return parameterized_test_registry_;
+ }
+
+ std::set<std::string>* ignored_parameterized_test_suites() {
+ return &ignored_parameterized_test_suites_;
+ }
+
+ // Returns TypeParameterizedTestSuiteRegistry object used to keep track of
+ // type-parameterized tests and instantiations of them.
+ internal::TypeParameterizedTestSuiteRegistry&
+ type_parameterized_test_registry() {
+ return type_parameterized_test_registry_;
+ }
+
+ // Sets the TestSuite object for the test that's currently running.
+ void set_current_test_suite(TestSuite* a_current_test_suite) {
+ current_test_suite_ = a_current_test_suite;
+ }
+
+ // Sets the TestInfo object for the test that's currently running. If
+ // current_test_info is NULL, the assertion results will be stored in
+ // ad_hoc_test_result_.
+ void set_current_test_info(TestInfo* a_current_test_info) {
+ current_test_info_ = a_current_test_info;
+ }
+
+ // Registers all parameterized tests defined using TEST_P and
+ // INSTANTIATE_TEST_SUITE_P, creating regular tests for each test/parameter
+ // combination. This method can be called more then once; it has guards
+ // protecting from registering the tests more then once. If
+ // value-parameterized tests are disabled, RegisterParameterizedTests is
+ // present but does nothing.
+ void RegisterParameterizedTests();
+
+ // Runs all tests in this UnitTest object, prints the result, and
+ // returns true if all tests are successful. If any exception is
+ // thrown during a test, this test is considered to be failed, but
+ // the rest of the tests will still be run.
+ bool RunAllTests();
+
+ // Clears the results of all tests, except the ad hoc tests.
+ void ClearNonAdHocTestResult() {
+ ForEach(test_suites_, TestSuite::ClearTestSuiteResult);
+ }
+
+ // Clears the results of ad-hoc test assertions.
+ void ClearAdHocTestResult() {
+ ad_hoc_test_result_.Clear();
+ }
+
+ // Adds a TestProperty to the current TestResult object when invoked in a
+ // context of a test or a test suite, or to the global property set. If the
+ // result already contains a property with the same key, the value will be
+ // updated.
+ void RecordProperty(const TestProperty& test_property);
+
+ enum ReactionToSharding {
+ HONOR_SHARDING_PROTOCOL,
+ IGNORE_SHARDING_PROTOCOL
+ };
+
+ // Matches the full name of each test against the user-specified
+ // filter to decide whether the test should run, then records the
+ // result in each TestSuite and TestInfo object.
+ // If shard_tests == HONOR_SHARDING_PROTOCOL, further filters tests
+ // based on sharding variables in the environment.
+ // Returns the number of tests that should run.
+ int FilterTests(ReactionToSharding shard_tests);
+
+ // Prints the names of the tests matching the user-specified filter flag.
+ void ListTestsMatchingFilter();
+
+ const TestSuite* current_test_suite() const { return current_test_suite_; }
+ TestInfo* current_test_info() { return current_test_info_; }
+ const TestInfo* current_test_info() const { return current_test_info_; }
+
+ // Returns the vector of environments that need to be set-up/torn-down
+ // before/after the tests are run.
+ std::vector<Environment*>& environments() { return environments_; }
+
+ // Getters for the per-thread Google Test trace stack.
+ std::vector<TraceInfo>& gtest_trace_stack() {
+ return *(gtest_trace_stack_.pointer());
+ }
+ const std::vector<TraceInfo>& gtest_trace_stack() const {
+ return gtest_trace_stack_.get();
+ }
+
+#if GTEST_HAS_DEATH_TEST
+ void InitDeathTestSubprocessControlInfo() {
+ internal_run_death_test_flag_.reset(ParseInternalRunDeathTestFlag());
+ }
+ // Returns a pointer to the parsed --gtest_internal_run_death_test
+ // flag, or NULL if that flag was not specified.
+ // This information is useful only in a death test child process.
+ // Must not be called before a call to InitGoogleTest.
+ const InternalRunDeathTestFlag* internal_run_death_test_flag() const {
+ return internal_run_death_test_flag_.get();
+ }
+
+ // Returns a pointer to the current death test factory.
+ internal::DeathTestFactory* death_test_factory() {
+ return death_test_factory_.get();
+ }
+
+ void SuppressTestEventsIfInSubprocess();
+
+ friend class ReplaceDeathTestFactory;
+#endif // GTEST_HAS_DEATH_TEST
+
+ // Initializes the event listener performing XML output as specified by
+ // UnitTestOptions. Must not be called before InitGoogleTest.
+ void ConfigureXmlOutput();
+
+#if GTEST_CAN_STREAM_RESULTS_
+ // Initializes the event listener for streaming test results to a socket.
+ // Must not be called before InitGoogleTest.
+ void ConfigureStreamingOutput();
+#endif
+
+ // Performs initialization dependent upon flag values obtained in
+ // ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to
+ // ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest
+ // this function is also called from RunAllTests. Since this function can be
+ // called more than once, it has to be idempotent.
+ void PostFlagParsingInit();
+
+ // Gets the random seed used at the start of the current test iteration.
+ int random_seed() const { return random_seed_; }
+
+ // Gets the random number generator.
+ internal::Random* random() { return &random_; }
+
+ // Shuffles all test suites, and the tests within each test suite,
+ // making sure that death tests are still run first.
+ void ShuffleTests();
+
+ // Restores the test suites and tests to their order before the first shuffle.
+ void UnshuffleTests();
+
+ // Returns the value of GTEST_FLAG(catch_exceptions) at the moment
+ // UnitTest::Run() starts.
+ bool catch_exceptions() const { return catch_exceptions_; }
+
+ private:
+ friend class ::testing::UnitTest;
+
+ // Used by UnitTest::Run() to capture the state of
+ // GTEST_FLAG(catch_exceptions) at the moment it starts.
+ void set_catch_exceptions(bool value) { catch_exceptions_ = value; }
+
+ // The UnitTest object that owns this implementation object.
+ UnitTest* const parent_;
+
+ // The working directory when the first TEST() or TEST_F() was
+ // executed.
+ internal::FilePath original_working_dir_;
+
+ // The default test part result reporters.
+ DefaultGlobalTestPartResultReporter default_global_test_part_result_reporter_;
+ DefaultPerThreadTestPartResultReporter
+ default_per_thread_test_part_result_reporter_;
+
+ // Points to (but doesn't own) the global test part result reporter.
+ TestPartResultReporterInterface* global_test_part_result_repoter_;
+
+ // Protects read and write access to global_test_part_result_reporter_.
+ internal::Mutex global_test_part_result_reporter_mutex_;
+
+ // Points to (but doesn't own) the per-thread test part result reporter.
+ internal::ThreadLocal<TestPartResultReporterInterface*>
+ per_thread_test_part_result_reporter_;
+
+ // The vector of environments that need to be set-up/torn-down
+ // before/after the tests are run.
+ std::vector<Environment*> environments_;
+
+ // The vector of TestSuites in their original order. It owns the
+ // elements in the vector.
+ std::vector<TestSuite*> test_suites_;
+
+ // Provides a level of indirection for the test suite list to allow
+ // easy shuffling and restoring the test suite order. The i-th
+ // element of this vector is the index of the i-th test suite in the
+ // shuffled order.
+ std::vector<int> test_suite_indices_;
+
+ // ParameterizedTestRegistry object used to register value-parameterized
+ // tests.
+ internal::ParameterizedTestSuiteRegistry parameterized_test_registry_;
+ internal::TypeParameterizedTestSuiteRegistry
+ type_parameterized_test_registry_;
+
+ // The set holding the name of parameterized
+ // test suites that may go uninstantiated.
+ std::set<std::string> ignored_parameterized_test_suites_;
+
+ // Indicates whether RegisterParameterizedTests() has been called already.
+ bool parameterized_tests_registered_;
+
+ // Index of the last death test suite registered. Initially -1.
+ int last_death_test_suite_;
+
+ // This points to the TestSuite for the currently running test. It
+ // changes as Google Test goes through one test suite after another.
+ // When no test is running, this is set to NULL and Google Test
+ // stores assertion results in ad_hoc_test_result_. Initially NULL.
+ TestSuite* current_test_suite_;
+
+ // This points to the TestInfo for the currently running test. It
+ // changes as Google Test goes through one test after another. When
+ // no test is running, this is set to NULL and Google Test stores
+ // assertion results in ad_hoc_test_result_. Initially NULL.
+ TestInfo* current_test_info_;
+
+ // Normally, a user only writes assertions inside a TEST or TEST_F,
+ // or inside a function called by a TEST or TEST_F. Since Google
+ // Test keeps track of which test is current running, it can
+ // associate such an assertion with the test it belongs to.
+ //
+ // If an assertion is encountered when no TEST or TEST_F is running,
+ // Google Test attributes the assertion result to an imaginary "ad hoc"
+ // test, and records the result in ad_hoc_test_result_.
+ TestResult ad_hoc_test_result_;
+
+ // The list of event listeners that can be used to track events inside
+ // Google Test.
+ TestEventListeners listeners_;
+
+ // The OS stack trace getter. Will be deleted when the UnitTest
+ // object is destructed. By default, an OsStackTraceGetter is used,
+ // but the user can set this field to use a custom getter if that is
+ // desired.
+ OsStackTraceGetterInterface* os_stack_trace_getter_;
+
+ // True if and only if PostFlagParsingInit() has been called.
+ bool post_flag_parse_init_performed_;
+
+ // The random number seed used at the beginning of the test run.
+ int random_seed_;
+
+ // Our random number generator.
+ internal::Random random_;
+
+ // The time of the test program start, in ms from the start of the
+ // UNIX epoch.
+ TimeInMillis start_timestamp_;
+
+ // How long the test took to run, in milliseconds.
+ TimeInMillis elapsed_time_;
+
+#if GTEST_HAS_DEATH_TEST
+ // The decomposed components of the gtest_internal_run_death_test flag,
+ // parsed when RUN_ALL_TESTS is called.
+ std::unique_ptr<InternalRunDeathTestFlag> internal_run_death_test_flag_;
+ std::unique_ptr<internal::DeathTestFactory> death_test_factory_;
+#endif // GTEST_HAS_DEATH_TEST
+
+ // A per-thread stack of traces created by the SCOPED_TRACE() macro.
+ internal::ThreadLocal<std::vector<TraceInfo> > gtest_trace_stack_;
+
+ // The value of GTEST_FLAG(catch_exceptions) at the moment RunAllTests()
+ // starts.
+ bool catch_exceptions_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTestImpl);
+}; // class UnitTestImpl
+
+// Convenience function for accessing the global UnitTest
+// implementation object.
+inline UnitTestImpl* GetUnitTestImpl() {
+ return UnitTest::GetInstance()->impl();
+}
+
+#if GTEST_USES_SIMPLE_RE
+
+// Internal helper functions for implementing the simple regular
+// expression matcher.
+GTEST_API_ bool IsInSet(char ch, const char* str);
+GTEST_API_ bool IsAsciiDigit(char ch);
+GTEST_API_ bool IsAsciiPunct(char ch);
+GTEST_API_ bool IsRepeat(char ch);
+GTEST_API_ bool IsAsciiWhiteSpace(char ch);
+GTEST_API_ bool IsAsciiWordChar(char ch);
+GTEST_API_ bool IsValidEscape(char ch);
+GTEST_API_ bool AtomMatchesChar(bool escaped, char pattern, char ch);
+GTEST_API_ bool ValidateRegex(const char* regex);
+GTEST_API_ bool MatchRegexAtHead(const char* regex, const char* str);
+GTEST_API_ bool MatchRepetitionAndRegexAtHead(
+ bool escaped, char ch, char repeat, const char* regex, const char* str);
+GTEST_API_ bool MatchRegexAnywhere(const char* regex, const char* str);
+
+#endif // GTEST_USES_SIMPLE_RE
+
+// Parses the command line for Google Test flags, without initializing
+// other parts of Google Test.
+GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, char** argv);
+GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv);
+
+#if GTEST_HAS_DEATH_TEST
+
+// Returns the message describing the last system error, regardless of the
+// platform.
+GTEST_API_ std::string GetLastErrnoDescription();
+
+// Attempts to parse a string into a positive integer pointed to by the
+// number parameter. Returns true if that is possible.
+// GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can use
+// it here.
+template <typename Integer>
+bool ParseNaturalNumber(const ::std::string& str, Integer* number) {
+ // Fail fast if the given string does not begin with a digit;
+ // this bypasses strtoXXX's "optional leading whitespace and plus
+ // or minus sign" semantics, which are undesirable here.
+ if (str.empty() || !IsDigit(str[0])) {
+ return false;
+ }
+ errno = 0;
+
+ char* end;
+ // BiggestConvertible is the largest integer type that system-provided
+ // string-to-number conversion routines can return.
+ using BiggestConvertible = unsigned long long; // NOLINT
+
+ const BiggestConvertible parsed = strtoull(str.c_str(), &end, 10); // NOLINT
+ const bool parse_success = *end == '\0' && errno == 0;
+
+ GTEST_CHECK_(sizeof(Integer) <= sizeof(parsed));
+
+ const Integer result = static_cast<Integer>(parsed);
+ if (parse_success && static_cast<BiggestConvertible>(result) == parsed) {
+ *number = result;
+ return true;
+ }
+ return false;
+}
+#endif // GTEST_HAS_DEATH_TEST
+
+// TestResult contains some private methods that should be hidden from
+// Google Test user but are required for testing. This class allow our tests
+// to access them.
+//
+// This class is supplied only for the purpose of testing Google Test's own
+// constructs. Do not use it in user tests, either directly or indirectly.
+class TestResultAccessor {
+ public:
+ static void RecordProperty(TestResult* test_result,
+ const std::string& xml_element,
+ const TestProperty& property) {
+ test_result->RecordProperty(xml_element, property);
+ }
+
+ static void ClearTestPartResults(TestResult* test_result) {
+ test_result->ClearTestPartResults();
+ }
+
+ static const std::vector<testing::TestPartResult>& test_part_results(
+ const TestResult& test_result) {
+ return test_result.test_part_results();
+ }
+};
+
+#if GTEST_CAN_STREAM_RESULTS_
+
+// Streams test results to the given port on the given host machine.
+class StreamingListener : public EmptyTestEventListener {
+ public:
+ // Abstract base class for writing strings to a socket.
+ class AbstractSocketWriter {
+ public:
+ virtual ~AbstractSocketWriter() {}
+
+ // Sends a string to the socket.
+ virtual void Send(const std::string& message) = 0;
+
+ // Closes the socket.
+ virtual void CloseConnection() {}
+
+ // Sends a string and a newline to the socket.
+ void SendLn(const std::string& message) { Send(message + "\n"); }
+ };
+
+ // Concrete class for actually writing strings to a socket.
+ class SocketWriter : public AbstractSocketWriter {
+ public:
+ SocketWriter(const std::string& host, const std::string& port)
+ : sockfd_(-1), host_name_(host), port_num_(port) {
+ MakeConnection();
+ }
+
+ ~SocketWriter() override {
+ if (sockfd_ != -1)
+ CloseConnection();
+ }
+
+ // Sends a string to the socket.
+ void Send(const std::string& message) override {
+ GTEST_CHECK_(sockfd_ != -1)
+ << "Send() can be called only when there is a connection.";
+
+ const auto len = static_cast<size_t>(message.length());
+ if (write(sockfd_, message.c_str(), len) != static_cast<ssize_t>(len)) {
+ GTEST_LOG_(WARNING)
+ << "stream_result_to: failed to stream to "
+ << host_name_ << ":" << port_num_;
+ }
+ }
+
+ private:
+ // Creates a client socket and connects to the server.
+ void MakeConnection();
+
+ // Closes the socket.
+ void CloseConnection() override {
+ GTEST_CHECK_(sockfd_ != -1)
+ << "CloseConnection() can be called only when there is a connection.";
+
+ close(sockfd_);
+ sockfd_ = -1;
+ }
+
+ int sockfd_; // socket file descriptor
+ const std::string host_name_;
+ const std::string port_num_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(SocketWriter);
+ }; // class SocketWriter
+
+ // Escapes '=', '&', '%', and '\n' characters in str as "%xx".
+ static std::string UrlEncode(const char* str);
+
+ StreamingListener(const std::string& host, const std::string& port)
+ : socket_writer_(new SocketWriter(host, port)) {
+ Start();
+ }
+
+ explicit StreamingListener(AbstractSocketWriter* socket_writer)
+ : socket_writer_(socket_writer) { Start(); }
+
+ void OnTestProgramStart(const UnitTest& /* unit_test */) override {
+ SendLn("event=TestProgramStart");
+ }
+
+ void OnTestProgramEnd(const UnitTest& unit_test) override {
+ // Note that Google Test current only report elapsed time for each
+ // test iteration, not for the entire test program.
+ SendLn("event=TestProgramEnd&passed=" + FormatBool(unit_test.Passed()));
+
+ // Notify the streaming server to stop.
+ socket_writer_->CloseConnection();
+ }
+
+ void OnTestIterationStart(const UnitTest& /* unit_test */,
+ int iteration) override {
+ SendLn("event=TestIterationStart&iteration=" +
+ StreamableToString(iteration));
+ }
+
+ void OnTestIterationEnd(const UnitTest& unit_test,
+ int /* iteration */) override {
+ SendLn("event=TestIterationEnd&passed=" +
+ FormatBool(unit_test.Passed()) + "&elapsed_time=" +
+ StreamableToString(unit_test.elapsed_time()) + "ms");
+ }
+
+ // Note that "event=TestCaseStart" is a wire format and has to remain
+ // "case" for compatibility
+ void OnTestCaseStart(const TestCase& test_case) override {
+ SendLn(std::string("event=TestCaseStart&name=") + test_case.name());
+ }
+
+ // Note that "event=TestCaseEnd" is a wire format and has to remain
+ // "case" for compatibility
+ void OnTestCaseEnd(const TestCase& test_case) override {
+ SendLn("event=TestCaseEnd&passed=" + FormatBool(test_case.Passed()) +
+ "&elapsed_time=" + StreamableToString(test_case.elapsed_time()) +
+ "ms");
+ }
+
+ void OnTestStart(const TestInfo& test_info) override {
+ SendLn(std::string("event=TestStart&name=") + test_info.name());
+ }
+
+ void OnTestEnd(const TestInfo& test_info) override {
+ SendLn("event=TestEnd&passed=" +
+ FormatBool((test_info.result())->Passed()) +
+ "&elapsed_time=" +
+ StreamableToString((test_info.result())->elapsed_time()) + "ms");
+ }
+
+ void OnTestPartResult(const TestPartResult& test_part_result) override {
+ const char* file_name = test_part_result.file_name();
+ if (file_name == nullptr) file_name = "";
+ SendLn("event=TestPartResult&file=" + UrlEncode(file_name) +
+ "&line=" + StreamableToString(test_part_result.line_number()) +
+ "&message=" + UrlEncode(test_part_result.message()));
+ }
+
+ private:
+ // Sends the given message and a newline to the socket.
+ void SendLn(const std::string& message) { socket_writer_->SendLn(message); }
+
+ // Called at the start of streaming to notify the receiver what
+ // protocol we are using.
+ void Start() { SendLn("gtest_streaming_protocol_version=1.0"); }
+
+ std::string FormatBool(bool value) { return value ? "1" : "0"; }
+
+ const std::unique_ptr<AbstractSocketWriter> socket_writer_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(StreamingListener);
+}; // class StreamingListener
+
+#endif // GTEST_CAN_STREAM_RESULTS_
+
+} // namespace internal
+} // namespace testing
+
+GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251
+
+#endif // GOOGLETEST_SRC_GTEST_INTERNAL_INL_H_
+
+#if GTEST_OS_WINDOWS
+# define vsnprintf _vsnprintf
+#endif // GTEST_OS_WINDOWS
+
+#if GTEST_OS_MAC
+#ifndef GTEST_OS_IOS
+#include <crt_externs.h>
+#endif
+#endif
+
+#if GTEST_HAS_ABSL
+#include "absl/debugging/failure_signal_handler.h"
+#include "absl/debugging/stacktrace.h"
+#include "absl/debugging/symbolize.h"
+#include "absl/strings/str_cat.h"
+#endif // GTEST_HAS_ABSL
+
+namespace testing {
+
+using internal::CountIf;
+using internal::ForEach;
+using internal::GetElementOr;
+using internal::Shuffle;
+
+// Constants.
+
+// A test whose test suite name or test name matches this filter is
+// disabled and not run.
+static const char kDisableTestFilter[] = "DISABLED_*:*/DISABLED_*";
+
+// A test suite whose name matches this filter is considered a death
+// test suite and will be run before test suites whose name doesn't
+// match this filter.
+static const char kDeathTestSuiteFilter[] = "*DeathTest:*DeathTest/*";
+
+// A test filter that matches everything.
+static const char kUniversalFilter[] = "*";
+
+// The default output format.
+static const char kDefaultOutputFormat[] = "xml";
+// The default output file.
+static const char kDefaultOutputFile[] = "test_detail";
+
+// The environment variable name for the test shard index.
+static const char kTestShardIndex[] = "GTEST_SHARD_INDEX";
+// The environment variable name for the total number of test shards.
+static const char kTestTotalShards[] = "GTEST_TOTAL_SHARDS";
+// The environment variable name for the test shard status file.
+static const char kTestShardStatusFile[] = "GTEST_SHARD_STATUS_FILE";
+
+namespace internal {
+
+// The text used in failure messages to indicate the start of the
+// stack trace.
+const char kStackTraceMarker[] = "\nStack trace:\n";
+
+// g_help_flag is true if and only if the --help flag or an equivalent form
+// is specified on the command line.
+bool g_help_flag = false;
+
+// Utilty function to Open File for Writing
+static FILE* OpenFileForWriting(const std::string& output_file) {
+ FILE* fileout = nullptr;
+ FilePath output_file_path(output_file);
+ FilePath output_dir(output_file_path.RemoveFileName());
+
+ if (output_dir.CreateDirectoriesRecursively()) {
+ fileout = posix::FOpen(output_file.c_str(), "w");
+ }
+ if (fileout == nullptr) {
+ GTEST_LOG_(FATAL) << "Unable to open file \"" << output_file << "\"";
+ }
+ return fileout;
+}
+
+} // namespace internal
+
+// Bazel passes in the argument to '--test_filter' via the TESTBRIDGE_TEST_ONLY
+// environment variable.
+static const char* GetDefaultFilter() {
+ const char* const testbridge_test_only =
+ internal::posix::GetEnv("TESTBRIDGE_TEST_ONLY");
+ if (testbridge_test_only != nullptr) {
+ return testbridge_test_only;
+ }
+ return kUniversalFilter;
+}
+
+// Bazel passes in the argument to '--test_runner_fail_fast' via the
+// TESTBRIDGE_TEST_RUNNER_FAIL_FAST environment variable.
+static bool GetDefaultFailFast() {
+ const char* const testbridge_test_runner_fail_fast =
+ internal::posix::GetEnv("TESTBRIDGE_TEST_RUNNER_FAIL_FAST");
+ if (testbridge_test_runner_fail_fast != nullptr) {
+ return strcmp(testbridge_test_runner_fail_fast, "1") == 0;
+ }
+ return false;
+}
+
+GTEST_DEFINE_bool_(
+ fail_fast, internal::BoolFromGTestEnv("fail_fast", GetDefaultFailFast()),
+ "True if and only if a test failure should stop further test execution.");
+
+GTEST_DEFINE_bool_(
+ also_run_disabled_tests,
+ internal::BoolFromGTestEnv("also_run_disabled_tests", false),
+ "Run disabled tests too, in addition to the tests normally being run.");
+
+GTEST_DEFINE_bool_(
+ break_on_failure, internal::BoolFromGTestEnv("break_on_failure", false),
+ "True if and only if a failed assertion should be a debugger "
+ "break-point.");
+
+GTEST_DEFINE_bool_(catch_exceptions,
+ internal::BoolFromGTestEnv("catch_exceptions", true),
+ "True if and only if " GTEST_NAME_
+ " should catch exceptions and treat them as test failures.");
+
+GTEST_DEFINE_string_(
+ color,
+ internal::StringFromGTestEnv("color", "auto"),
+ "Whether to use colors in the output. Valid values: yes, no, "
+ "and auto. 'auto' means to use colors if the output is "
+ "being sent to a terminal and the TERM environment variable "
+ "is set to a terminal type that supports colors.");
+
+GTEST_DEFINE_string_(
+ filter,
+ internal::StringFromGTestEnv("filter", GetDefaultFilter()),
+ "A colon-separated list of glob (not regex) patterns "
+ "for filtering the tests to run, optionally followed by a "
+ "'-' and a : separated list of negative patterns (tests to "
+ "exclude). A test is run if it matches one of the positive "
+ "patterns and does not match any of the negative patterns.");
+
+GTEST_DEFINE_bool_(
+ install_failure_signal_handler,
+ internal::BoolFromGTestEnv("install_failure_signal_handler", false),
+ "If true and supported on the current platform, " GTEST_NAME_ " should "
+ "install a signal handler that dumps debugging information when fatal "
+ "signals are raised.");
+
+GTEST_DEFINE_bool_(list_tests, false,
+ "List all tests without running them.");
+
+// The net priority order after flag processing is thus:
+// --gtest_output command line flag
+// GTEST_OUTPUT environment variable
+// XML_OUTPUT_FILE environment variable
+// ''
+GTEST_DEFINE_string_(
+ output,
+ internal::StringFromGTestEnv("output",
+ internal::OutputFlagAlsoCheckEnvVar().c_str()),
+ "A format (defaults to \"xml\" but can be specified to be \"json\"), "
+ "optionally followed by a colon and an output file name or directory. "
+ "A directory is indicated by a trailing pathname separator. "
+ "Examples: \"xml:filename.xml\", \"xml::directoryname/\". "
+ "If a directory is specified, output files will be created "
+ "within that directory, with file-names based on the test "
+ "executable's name and, if necessary, made unique by adding "
+ "digits.");
+
+GTEST_DEFINE_bool_(
+ brief, internal::BoolFromGTestEnv("brief", false),
+ "True if only test failures should be displayed in text output.");
+
+GTEST_DEFINE_bool_(print_time, internal::BoolFromGTestEnv("print_time", true),
+ "True if and only if " GTEST_NAME_
+ " should display elapsed time in text output.");
+
+GTEST_DEFINE_bool_(print_utf8, internal::BoolFromGTestEnv("print_utf8", true),
+ "True if and only if " GTEST_NAME_
+ " prints UTF8 characters as text.");
+
+GTEST_DEFINE_int32_(
+ random_seed,
+ internal::Int32FromGTestEnv("random_seed", 0),
+ "Random number seed to use when shuffling test orders. Must be in range "
+ "[1, 99999], or 0 to use a seed based on the current time.");
+
+GTEST_DEFINE_int32_(
+ repeat,
+ internal::Int32FromGTestEnv("repeat", 1),
+ "How many times to repeat each test. Specify a negative number "
+ "for repeating forever. Useful for shaking out flaky tests.");
+
+GTEST_DEFINE_bool_(show_internal_stack_frames, false,
+ "True if and only if " GTEST_NAME_
+ " should include internal stack frames when "
+ "printing test failure stack traces.");
+
+GTEST_DEFINE_bool_(shuffle, internal::BoolFromGTestEnv("shuffle", false),
+ "True if and only if " GTEST_NAME_
+ " should randomize tests' order on every run.");
+
+GTEST_DEFINE_int32_(
+ stack_trace_depth,
+ internal::Int32FromGTestEnv("stack_trace_depth", kMaxStackTraceDepth),
+ "The maximum number of stack frames to print when an "
+ "assertion fails. The valid range is 0 through 100, inclusive.");
+
+GTEST_DEFINE_string_(
+ stream_result_to,
+ internal::StringFromGTestEnv("stream_result_to", ""),
+ "This flag specifies the host name and the port number on which to stream "
+ "test results. Example: \"localhost:555\". The flag is effective only on "
+ "Linux.");
+
+GTEST_DEFINE_bool_(
+ throw_on_failure,
+ internal::BoolFromGTestEnv("throw_on_failure", false),
+ "When this flag is specified, a failed assertion will throw an exception "
+ "if exceptions are enabled or exit the program with a non-zero code "
+ "otherwise. For use with an external test framework.");
+
+#if GTEST_USE_OWN_FLAGFILE_FLAG_
+GTEST_DEFINE_string_(
+ flagfile,
+ internal::StringFromGTestEnv("flagfile", ""),
+ "This flag specifies the flagfile to read command-line flags from.");
+#endif // GTEST_USE_OWN_FLAGFILE_FLAG_
+
+namespace internal {
+
+// Generates a random number from [0, range), using a Linear
+// Congruential Generator (LCG). Crashes if 'range' is 0 or greater
+// than kMaxRange.
+uint32_t Random::Generate(uint32_t range) {
+ // These constants are the same as are used in glibc's rand(3).
+ // Use wider types than necessary to prevent unsigned overflow diagnostics.
+ state_ = static_cast<uint32_t>(1103515245ULL*state_ + 12345U) % kMaxRange;
+
+ GTEST_CHECK_(range > 0)
+ << "Cannot generate a number in the range [0, 0).";
+ GTEST_CHECK_(range <= kMaxRange)
+ << "Generation of a number in [0, " << range << ") was requested, "
+ << "but this can only generate numbers in [0, " << kMaxRange << ").";
+
+ // Converting via modulus introduces a bit of downward bias, but
+ // it's simple, and a linear congruential generator isn't too good
+ // to begin with.
+ return state_ % range;
+}
+
+// GTestIsInitialized() returns true if and only if the user has initialized
+// Google Test. Useful for catching the user mistake of not initializing
+// Google Test before calling RUN_ALL_TESTS().
+static bool GTestIsInitialized() { return GetArgvs().size() > 0; }
+
+// Iterates over a vector of TestSuites, keeping a running sum of the
+// results of calling a given int-returning method on each.
+// Returns the sum.
+static int SumOverTestSuiteList(const std::vector<TestSuite*>& case_list,
+ int (TestSuite::*method)() const) {
+ int sum = 0;
+ for (size_t i = 0; i < case_list.size(); i++) {
+ sum += (case_list[i]->*method)();
+ }
+ return sum;
+}
+
+// Returns true if and only if the test suite passed.
+static bool TestSuitePassed(const TestSuite* test_suite) {
+ return test_suite->should_run() && test_suite->Passed();
+}
+
+// Returns true if and only if the test suite failed.
+static bool TestSuiteFailed(const TestSuite* test_suite) {
+ return test_suite->should_run() && test_suite->Failed();
+}
+
+// Returns true if and only if test_suite contains at least one test that
+// should run.
+static bool ShouldRunTestSuite(const TestSuite* test_suite) {
+ return test_suite->should_run();
+}
+
+// AssertHelper constructor.
+AssertHelper::AssertHelper(TestPartResult::Type type,
+ const char* file,
+ int line,
+ const char* message)
+ : data_(new AssertHelperData(type, file, line, message)) {
+}
+
+AssertHelper::~AssertHelper() {
+ delete data_;
+}
+
+// Message assignment, for assertion streaming support.
+void AssertHelper::operator=(const Message& message) const {
+ UnitTest::GetInstance()->
+ AddTestPartResult(data_->type, data_->file, data_->line,
+ AppendUserMessage(data_->message, message),
+ UnitTest::GetInstance()->impl()
+ ->CurrentOsStackTraceExceptTop(1)
+ // Skips the stack frame for this function itself.
+ ); // NOLINT
+}
+
+namespace {
+
+// When TEST_P is found without a matching INSTANTIATE_TEST_SUITE_P
+// to creates test cases for it, a syntetic test case is
+// inserted to report ether an error or a log message.
+//
+// This configuration bit will likely be removed at some point.
+constexpr bool kErrorOnUninstantiatedParameterizedTest = true;
+constexpr bool kErrorOnUninstantiatedTypeParameterizedTest = true;
+
+// A test that fails at a given file/line location with a given message.
+class FailureTest : public Test {
+ public:
+ explicit FailureTest(const CodeLocation& loc, std::string error_message,
+ bool as_error)
+ : loc_(loc),
+ error_message_(std::move(error_message)),
+ as_error_(as_error) {}
+
+ void TestBody() override {
+ if (as_error_) {
+ AssertHelper(TestPartResult::kNonFatalFailure, loc_.file.c_str(),
+ loc_.line, "") = Message() << error_message_;
+ } else {
+ std::cout << error_message_ << std::endl;
+ }
+ }
+
+ private:
+ const CodeLocation loc_;
+ const std::string error_message_;
+ const bool as_error_;
+};
+
+
+} // namespace
+
+std::set<std::string>* GetIgnoredParameterizedTestSuites() {
+ return UnitTest::GetInstance()->impl()->ignored_parameterized_test_suites();
+}
+
+// Add a given test_suit to the list of them allow to go un-instantiated.
+MarkAsIgnored::MarkAsIgnored(const char* test_suite) {
+ GetIgnoredParameterizedTestSuites()->insert(test_suite);
+}
+
+// If this parameterized test suite has no instantiations (and that
+// has not been marked as okay), emit a test case reporting that.
+void InsertSyntheticTestCase(const std::string& name, CodeLocation location,
+ bool has_test_p) {
+ const auto& ignored = *GetIgnoredParameterizedTestSuites();
+ if (ignored.find(name) != ignored.end()) return;
+
+ const char kMissingInstantiation[] = //
+ " is defined via TEST_P, but never instantiated. None of the test cases "
+ "will run. Either no INSTANTIATE_TEST_SUITE_P is provided or the only "
+ "ones provided expand to nothing."
+ "\n\n"
+ "Ideally, TEST_P definitions should only ever be included as part of "
+ "binaries that intend to use them. (As opposed to, for example, being "
+ "placed in a library that may be linked in to get other utilities.)";
+
+ const char kMissingTestCase[] = //
+ " is instantiated via INSTANTIATE_TEST_SUITE_P, but no tests are "
+ "defined via TEST_P . No test cases will run."
+ "\n\n"
+ "Ideally, INSTANTIATE_TEST_SUITE_P should only ever be invoked from "
+ "code that always depend on code that provides TEST_P. Failing to do "
+ "so is often an indication of dead code, e.g. the last TEST_P was "
+ "removed but the rest got left behind.";
+
+ std::string message =
+ "Parameterized test suite " + name +
+ (has_test_p ? kMissingInstantiation : kMissingTestCase) +
+ "\n\n"
+ "To suppress this error for this test suite, insert the following line "
+ "(in a non-header) in the namespace it is defined in:"
+ "\n\n"
+ "GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(" + name + ");";
+
+ std::string full_name = "UninstantiatedParameterizedTestSuite<" + name + ">";
+ RegisterTest( //
+ "GoogleTestVerification", full_name.c_str(),
+ nullptr, // No type parameter.
+ nullptr, // No value parameter.
+ location.file.c_str(), location.line, [message, location] {
+ return new FailureTest(location, message,
+ kErrorOnUninstantiatedParameterizedTest);
+ });
+}
+
+void RegisterTypeParameterizedTestSuite(const char* test_suite_name,
+ CodeLocation code_location) {
+ GetUnitTestImpl()->type_parameterized_test_registry().RegisterTestSuite(
+ test_suite_name, code_location);
+}
+
+void RegisterTypeParameterizedTestSuiteInstantiation(const char* case_name) {
+ GetUnitTestImpl()
+ ->type_parameterized_test_registry()
+ .RegisterInstantiation(case_name);
+}
+
+void TypeParameterizedTestSuiteRegistry::RegisterTestSuite(
+ const char* test_suite_name, CodeLocation code_location) {
+ suites_.emplace(std::string(test_suite_name),
+ TypeParameterizedTestSuiteInfo(code_location));
+}
+
+void TypeParameterizedTestSuiteRegistry::RegisterInstantiation(
+ const char* test_suite_name) {
+ auto it = suites_.find(std::string(test_suite_name));
+ if (it != suites_.end()) {
+ it->second.instantiated = true;
+ } else {
+ GTEST_LOG_(ERROR) << "Unknown type parameterized test suit '"
+ << test_suite_name << "'";
+ }
+}
+
+void TypeParameterizedTestSuiteRegistry::CheckForInstantiations() {
+ const auto& ignored = *GetIgnoredParameterizedTestSuites();
+ for (const auto& testcase : suites_) {
+ if (testcase.second.instantiated) continue;
+ if (ignored.find(testcase.first) != ignored.end()) continue;
+
+ std::string message =
+ "Type parameterized test suite " + testcase.first +
+ " is defined via REGISTER_TYPED_TEST_SUITE_P, but never instantiated "
+ "via INSTANTIATE_TYPED_TEST_SUITE_P. None of the test cases will run."
+ "\n\n"
+ "Ideally, TYPED_TEST_P definitions should only ever be included as "
+ "part of binaries that intend to use them. (As opposed to, for "
+ "example, being placed in a library that may be linked in to get other "
+ "utilities.)"
+ "\n\n"
+ "To suppress this error for this test suite, insert the following line "
+ "(in a non-header) in the namespace it is defined in:"
+ "\n\n"
+ "GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(" +
+ testcase.first + ");";
+
+ std::string full_name =
+ "UninstantiatedTypeParameterizedTestSuite<" + testcase.first + ">";
+ RegisterTest( //
+ "GoogleTestVerification", full_name.c_str(),
+ nullptr, // No type parameter.
+ nullptr, // No value parameter.
+ testcase.second.code_location.file.c_str(),
+ testcase.second.code_location.line, [message, testcase] {
+ return new FailureTest(testcase.second.code_location, message,
+ kErrorOnUninstantiatedTypeParameterizedTest);
+ });
+ }
+}
+
+// A copy of all command line arguments. Set by InitGoogleTest().
+static ::std::vector<std::string> g_argvs;
+
+::std::vector<std::string> GetArgvs() {
+#if defined(GTEST_CUSTOM_GET_ARGVS_)
+ // GTEST_CUSTOM_GET_ARGVS_() may return a container of std::string or
+ // ::string. This code converts it to the appropriate type.
+ const auto& custom = GTEST_CUSTOM_GET_ARGVS_();
+ return ::std::vector<std::string>(custom.begin(), custom.end());
+#else // defined(GTEST_CUSTOM_GET_ARGVS_)
+ return g_argvs;
+#endif // defined(GTEST_CUSTOM_GET_ARGVS_)
+}
+
+// Returns the current application's name, removing directory path if that
+// is present.
+FilePath GetCurrentExecutableName() {
+ FilePath result;
+
+#if GTEST_OS_WINDOWS || GTEST_OS_OS2
+ result.Set(FilePath(GetArgvs()[0]).RemoveExtension("exe"));
+#else
+ result.Set(FilePath(GetArgvs()[0]));
+#endif // GTEST_OS_WINDOWS
+
+ return result.RemoveDirectoryName();
+}
+
+// Functions for processing the gtest_output flag.
+
+// Returns the output format, or "" for normal printed output.
+std::string UnitTestOptions::GetOutputFormat() {
+ const char* const gtest_output_flag = GTEST_FLAG(output).c_str();
+ const char* const colon = strchr(gtest_output_flag, ':');
+ return (colon == nullptr)
+ ? std::string(gtest_output_flag)
+ : std::string(gtest_output_flag,
+ static_cast<size_t>(colon - gtest_output_flag));
+}
+
+// Returns the name of the requested output file, or the default if none
+// was explicitly specified.
+std::string UnitTestOptions::GetAbsolutePathToOutputFile() {
+ const char* const gtest_output_flag = GTEST_FLAG(output).c_str();
+
+ std::string format = GetOutputFormat();
+ if (format.empty())
+ format = std::string(kDefaultOutputFormat);
+
+ const char* const colon = strchr(gtest_output_flag, ':');
+ if (colon == nullptr)
+ return internal::FilePath::MakeFileName(
+ internal::FilePath(
+ UnitTest::GetInstance()->original_working_dir()),
+ internal::FilePath(kDefaultOutputFile), 0,
+ format.c_str()).string();
+
+ internal::FilePath output_name(colon + 1);
+ if (!output_name.IsAbsolutePath())
+ output_name = internal::FilePath::ConcatPaths(
+ internal::FilePath(UnitTest::GetInstance()->original_working_dir()),
+ internal::FilePath(colon + 1));
+
+ if (!output_name.IsDirectory())
+ return output_name.string();
+
+ internal::FilePath result(internal::FilePath::GenerateUniqueFileName(
+ output_name, internal::GetCurrentExecutableName(),
+ GetOutputFormat().c_str()));
+ return result.string();
+}
+
+// Returns true if and only if the wildcard pattern matches the string. Each
+// pattern consists of regular characters, single-character wildcards (?), and
+// multi-character wildcards (*).
+//
+// This function implements a linear-time string globbing algorithm based on
+// https://research.swtch.com/glob.
+static bool PatternMatchesString(const std::string& name_str,
+ const char* pattern, const char* pattern_end) {
+ const char* name = name_str.c_str();
+ const char* const name_begin = name;
+ const char* const name_end = name + name_str.size();
+
+ const char* pattern_next = pattern;
+ const char* name_next = name;
+
+ while (pattern < pattern_end || name < name_end) {
+ if (pattern < pattern_end) {
+ switch (*pattern) {
+ default: // Match an ordinary character.
+ if (name < name_end && *name == *pattern) {
+ ++pattern;
+ ++name;
+ continue;
+ }
+ break;
+ case '?': // Match any single character.
+ if (name < name_end) {
+ ++pattern;
+ ++name;
+ continue;
+ }
+ break;
+ case '*':
+ // Match zero or more characters. Start by skipping over the wildcard
+ // and matching zero characters from name. If that fails, restart and
+ // match one more character than the last attempt.
+ pattern_next = pattern;
+ name_next = name + 1;
+ ++pattern;
+ continue;
+ }
+ }
+ // Failed to match a character. Restart if possible.
+ if (name_begin < name_next && name_next <= name_end) {
+ pattern = pattern_next;
+ name = name_next;
+ continue;
+ }
+ return false;
+ }
+ return true;
+}
+
+bool UnitTestOptions::MatchesFilter(const std::string& name_str,
+ const char* filter) {
+ // The filter is a list of patterns separated by colons (:).
+ const char* pattern = filter;
+ while (true) {
+ // Find the bounds of this pattern.
+ const char* const next_sep = strchr(pattern, ':');
+ const char* const pattern_end =
+ next_sep != nullptr ? next_sep : pattern + strlen(pattern);
+
+ // Check if this pattern matches name_str.
+ if (PatternMatchesString(name_str, pattern, pattern_end)) {
+ return true;
+ }
+
+ // Give up on this pattern. However, if we found a pattern separator (:),
+ // advance to the next pattern (skipping over the separator) and restart.
+ if (next_sep == nullptr) {
+ return false;
+ }
+ pattern = next_sep + 1;
+ }
+ return true;
+}
+
+// Returns true if and only if the user-specified filter matches the test
+// suite name and the test name.
+bool UnitTestOptions::FilterMatchesTest(const std::string& test_suite_name,
+ const std::string& test_name) {
+ const std::string& full_name = test_suite_name + "." + test_name.c_str();
+
+ // Split --gtest_filter at '-', if there is one, to separate into
+ // positive filter and negative filter portions
+ const char* const p = GTEST_FLAG(filter).c_str();
+ const char* const dash = strchr(p, '-');
+ std::string positive;
+ std::string negative;
+ if (dash == nullptr) {
+ positive = GTEST_FLAG(filter).c_str(); // Whole string is a positive filter
+ negative = "";
+ } else {
+ positive = std::string(p, dash); // Everything up to the dash
+ negative = std::string(dash + 1); // Everything after the dash
+ if (positive.empty()) {
+ // Treat '-test1' as the same as '*-test1'
+ positive = kUniversalFilter;
+ }
+ }
+
+ // A filter is a colon-separated list of patterns. It matches a
+ // test if any pattern in it matches the test.
+ return (MatchesFilter(full_name, positive.c_str()) &&
+ !MatchesFilter(full_name, negative.c_str()));
+}
+
+#if GTEST_HAS_SEH
+// Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the
+// given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise.
+// This function is useful as an __except condition.
+int UnitTestOptions::GTestShouldProcessSEH(DWORD exception_code) {
+ // Google Test should handle a SEH exception if:
+ // 1. the user wants it to, AND
+ // 2. this is not a breakpoint exception, AND
+ // 3. this is not a C++ exception (VC++ implements them via SEH,
+ // apparently).
+ //
+ // SEH exception code for C++ exceptions.
+ // (see http://support.microsoft.com/kb/185294 for more information).
+ const DWORD kCxxExceptionCode = 0xe06d7363;
+
+ bool should_handle = true;
+
+ if (!GTEST_FLAG(catch_exceptions))
+ should_handle = false;
+ else if (exception_code == EXCEPTION_BREAKPOINT)
+ should_handle = false;
+ else if (exception_code == kCxxExceptionCode)
+ should_handle = false;
+
+ return should_handle ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH;
+}
+#endif // GTEST_HAS_SEH
+
+} // namespace internal
+
+// The c'tor sets this object as the test part result reporter used by
+// Google Test. The 'result' parameter specifies where to report the
+// results. Intercepts only failures from the current thread.
+ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter(
+ TestPartResultArray* result)
+ : intercept_mode_(INTERCEPT_ONLY_CURRENT_THREAD),
+ result_(result) {
+ Init();
+}
+
+// The c'tor sets this object as the test part result reporter used by
+// Google Test. The 'result' parameter specifies where to report the
+// results.
+ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter(
+ InterceptMode intercept_mode, TestPartResultArray* result)
+ : intercept_mode_(intercept_mode),
+ result_(result) {
+ Init();
+}
+
+void ScopedFakeTestPartResultReporter::Init() {
+ internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
+ if (intercept_mode_ == INTERCEPT_ALL_THREADS) {
+ old_reporter_ = impl->GetGlobalTestPartResultReporter();
+ impl->SetGlobalTestPartResultReporter(this);
+ } else {
+ old_reporter_ = impl->GetTestPartResultReporterForCurrentThread();
+ impl->SetTestPartResultReporterForCurrentThread(this);
+ }
+}
+
+// The d'tor restores the test part result reporter used by Google Test
+// before.
+ScopedFakeTestPartResultReporter::~ScopedFakeTestPartResultReporter() {
+ internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
+ if (intercept_mode_ == INTERCEPT_ALL_THREADS) {
+ impl->SetGlobalTestPartResultReporter(old_reporter_);
+ } else {
+ impl->SetTestPartResultReporterForCurrentThread(old_reporter_);
+ }
+}
+
+// Increments the test part result count and remembers the result.
+// This method is from the TestPartResultReporterInterface interface.
+void ScopedFakeTestPartResultReporter::ReportTestPartResult(
+ const TestPartResult& result) {
+ result_->Append(result);
+}
+
+namespace internal {
+
+// Returns the type ID of ::testing::Test. We should always call this
+// instead of GetTypeId< ::testing::Test>() to get the type ID of
+// testing::Test. This is to work around a suspected linker bug when
+// using Google Test as a framework on Mac OS X. The bug causes
+// GetTypeId< ::testing::Test>() to return different values depending
+// on whether the call is from the Google Test framework itself or
+// from user test code. GetTestTypeId() is guaranteed to always
+// return the same value, as it always calls GetTypeId<>() from the
+// gtest.cc, which is within the Google Test framework.
+TypeId GetTestTypeId() {
+ return GetTypeId<Test>();
+}
+
+// The value of GetTestTypeId() as seen from within the Google Test
+// library. This is solely for testing GetTestTypeId().
+extern const TypeId kTestTypeIdInGoogleTest = GetTestTypeId();
+
+// This predicate-formatter checks that 'results' contains a test part
+// failure of the given type and that the failure message contains the
+// given substring.
+static AssertionResult HasOneFailure(const char* /* results_expr */,
+ const char* /* type_expr */,
+ const char* /* substr_expr */,
+ const TestPartResultArray& results,
+ TestPartResult::Type type,
+ const std::string& substr) {
+ const std::string expected(type == TestPartResult::kFatalFailure ?
+ "1 fatal failure" :
+ "1 non-fatal failure");
+ Message msg;
+ if (results.size() != 1) {
+ msg << "Expected: " << expected << "\n"
+ << " Actual: " << results.size() << " failures";
+ for (int i = 0; i < results.size(); i++) {
+ msg << "\n" << results.GetTestPartResult(i);
+ }
+ return AssertionFailure() << msg;
+ }
+
+ const TestPartResult& r = results.GetTestPartResult(0);
+ if (r.type() != type) {
+ return AssertionFailure() << "Expected: " << expected << "\n"
+ << " Actual:\n"
+ << r;
+ }
+
+ if (strstr(r.message(), substr.c_str()) == nullptr) {
+ return AssertionFailure() << "Expected: " << expected << " containing \""
+ << substr << "\"\n"
+ << " Actual:\n"
+ << r;
+ }
+
+ return AssertionSuccess();
+}
+
+// The constructor of SingleFailureChecker remembers where to look up
+// test part results, what type of failure we expect, and what
+// substring the failure message should contain.
+SingleFailureChecker::SingleFailureChecker(const TestPartResultArray* results,
+ TestPartResult::Type type,
+ const std::string& substr)
+ : results_(results), type_(type), substr_(substr) {}
+
+// The destructor of SingleFailureChecker verifies that the given
+// TestPartResultArray contains exactly one failure that has the given
+// type and contains the given substring. If that's not the case, a
+// non-fatal failure will be generated.
+SingleFailureChecker::~SingleFailureChecker() {
+ EXPECT_PRED_FORMAT3(HasOneFailure, *results_, type_, substr_);
+}
+
+DefaultGlobalTestPartResultReporter::DefaultGlobalTestPartResultReporter(
+ UnitTestImpl* unit_test) : unit_test_(unit_test) {}
+
+void DefaultGlobalTestPartResultReporter::ReportTestPartResult(
+ const TestPartResult& result) {
+ unit_test_->current_test_result()->AddTestPartResult(result);
+ unit_test_->listeners()->repeater()->OnTestPartResult(result);
+}
+
+DefaultPerThreadTestPartResultReporter::DefaultPerThreadTestPartResultReporter(
+ UnitTestImpl* unit_test) : unit_test_(unit_test) {}
+
+void DefaultPerThreadTestPartResultReporter::ReportTestPartResult(
+ const TestPartResult& result) {
+ unit_test_->GetGlobalTestPartResultReporter()->ReportTestPartResult(result);
+}
+
+// Returns the global test part result reporter.
+TestPartResultReporterInterface*
+UnitTestImpl::GetGlobalTestPartResultReporter() {
+ internal::MutexLock lock(&global_test_part_result_reporter_mutex_);
+ return global_test_part_result_repoter_;
+}
+
+// Sets the global test part result reporter.
+void UnitTestImpl::SetGlobalTestPartResultReporter(
+ TestPartResultReporterInterface* reporter) {
+ internal::MutexLock lock(&global_test_part_result_reporter_mutex_);
+ global_test_part_result_repoter_ = reporter;
+}
+
+// Returns the test part result reporter for the current thread.
+TestPartResultReporterInterface*
+UnitTestImpl::GetTestPartResultReporterForCurrentThread() {
+ return per_thread_test_part_result_reporter_.get();
+}
+
+// Sets the test part result reporter for the current thread.
+void UnitTestImpl::SetTestPartResultReporterForCurrentThread(
+ TestPartResultReporterInterface* reporter) {
+ per_thread_test_part_result_reporter_.set(reporter);
+}
+
+// Gets the number of successful test suites.
+int UnitTestImpl::successful_test_suite_count() const {
+ return CountIf(test_suites_, TestSuitePassed);
+}
+
+// Gets the number of failed test suites.
+int UnitTestImpl::failed_test_suite_count() const {
+ return CountIf(test_suites_, TestSuiteFailed);
+}
+
+// Gets the number of all test suites.
+int UnitTestImpl::total_test_suite_count() const {
+ return static_cast<int>(test_suites_.size());
+}
+
+// Gets the number of all test suites that contain at least one test
+// that should run.
+int UnitTestImpl::test_suite_to_run_count() const {
+ return CountIf(test_suites_, ShouldRunTestSuite);
+}
+
+// Gets the number of successful tests.
+int UnitTestImpl::successful_test_count() const {
+ return SumOverTestSuiteList(test_suites_, &TestSuite::successful_test_count);
+}
+
+// Gets the number of skipped tests.
+int UnitTestImpl::skipped_test_count() const {
+ return SumOverTestSuiteList(test_suites_, &TestSuite::skipped_test_count);
+}
+
+// Gets the number of failed tests.
+int UnitTestImpl::failed_test_count() const {
+ return SumOverTestSuiteList(test_suites_, &TestSuite::failed_test_count);
+}
+
+// Gets the number of disabled tests that will be reported in the XML report.
+int UnitTestImpl::reportable_disabled_test_count() const {
+ return SumOverTestSuiteList(test_suites_,
+ &TestSuite::reportable_disabled_test_count);
+}
+
+// Gets the number of disabled tests.
+int UnitTestImpl::disabled_test_count() const {
+ return SumOverTestSuiteList(test_suites_, &TestSuite::disabled_test_count);
+}
+
+// Gets the number of tests to be printed in the XML report.
+int UnitTestImpl::reportable_test_count() const {
+ return SumOverTestSuiteList(test_suites_, &TestSuite::reportable_test_count);
+}
+
+// Gets the number of all tests.
+int UnitTestImpl::total_test_count() const {
+ return SumOverTestSuiteList(test_suites_, &TestSuite::total_test_count);
+}
+
+// Gets the number of tests that should run.
+int UnitTestImpl::test_to_run_count() const {
+ return SumOverTestSuiteList(test_suites_, &TestSuite::test_to_run_count);
+}
+
+// Returns the current OS stack trace as an std::string.
+//
+// The maximum number of stack frames to be included is specified by
+// the gtest_stack_trace_depth flag. The skip_count parameter
+// specifies the number of top frames to be skipped, which doesn't
+// count against the number of frames to be included.
+//
+// For example, if Foo() calls Bar(), which in turn calls
+// CurrentOsStackTraceExceptTop(1), Foo() will be included in the
+// trace but Bar() and CurrentOsStackTraceExceptTop() won't.
+std::string UnitTestImpl::CurrentOsStackTraceExceptTop(int skip_count) {
+ return os_stack_trace_getter()->CurrentStackTrace(
+ static_cast<int>(GTEST_FLAG(stack_trace_depth)),
+ skip_count + 1
+ // Skips the user-specified number of frames plus this function
+ // itself.
+ ); // NOLINT
+}
+
+// A helper class for measuring elapsed times.
+class Timer {
+ public:
+ Timer() : start_(std::chrono::steady_clock::now()) {}
+
+ // Return time elapsed in milliseconds since the timer was created.
+ TimeInMillis Elapsed() {
+ return std::chrono::duration_cast<std::chrono::milliseconds>(
+ std::chrono::steady_clock::now() - start_)
+ .count();
+ }
+
+ private:
+ std::chrono::steady_clock::time_point start_;
+};
+
+// Returns a timestamp as milliseconds since the epoch. Note this time may jump
+// around subject to adjustments by the system, to measure elapsed time use
+// Timer instead.
+TimeInMillis GetTimeInMillis() {
+ return std::chrono::duration_cast<std::chrono::milliseconds>(
+ std::chrono::system_clock::now() -
+ std::chrono::system_clock::from_time_t(0))
+ .count();
+}
+
+// Utilities
+
+// class String.
+
+#if GTEST_OS_WINDOWS_MOBILE
+// Creates a UTF-16 wide string from the given ANSI string, allocating
+// memory using new. The caller is responsible for deleting the return
+// value using delete[]. Returns the wide string, or NULL if the
+// input is NULL.
+LPCWSTR String::AnsiToUtf16(const char* ansi) {
+ if (!ansi) return nullptr;
+ const int length = strlen(ansi);
+ const int unicode_length =
+ MultiByteToWideChar(CP_ACP, 0, ansi, length, nullptr, 0);
+ WCHAR* unicode = new WCHAR[unicode_length + 1];
+ MultiByteToWideChar(CP_ACP, 0, ansi, length,
+ unicode, unicode_length);
+ unicode[unicode_length] = 0;
+ return unicode;
+}
+
+// Creates an ANSI string from the given wide string, allocating
+// memory using new. The caller is responsible for deleting the return
+// value using delete[]. Returns the ANSI string, or NULL if the
+// input is NULL.
+const char* String::Utf16ToAnsi(LPCWSTR utf16_str) {
+ if (!utf16_str) return nullptr;
+ const int ansi_length = WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, nullptr,
+ 0, nullptr, nullptr);
+ char* ansi = new char[ansi_length + 1];
+ WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, ansi, ansi_length, nullptr,
+ nullptr);
+ ansi[ansi_length] = 0;
+ return ansi;
+}
+
+#endif // GTEST_OS_WINDOWS_MOBILE
+
+// Compares two C strings. Returns true if and only if they have the same
+// content.
+//
+// Unlike strcmp(), this function can handle NULL argument(s). A NULL
+// C string is considered different to any non-NULL C string,
+// including the empty string.
+bool String::CStringEquals(const char * lhs, const char * rhs) {
+ if (lhs == nullptr) return rhs == nullptr;
+
+ if (rhs == nullptr) return false;
+
+ return strcmp(lhs, rhs) == 0;
+}
+
+#if GTEST_HAS_STD_WSTRING
+
+// Converts an array of wide chars to a narrow string using the UTF-8
+// encoding, and streams the result to the given Message object.
+static void StreamWideCharsToMessage(const wchar_t* wstr, size_t length,
+ Message* msg) {
+ for (size_t i = 0; i != length; ) { // NOLINT
+ if (wstr[i] != L'\0') {
+ *msg << WideStringToUtf8(wstr + i, static_cast<int>(length - i));
+ while (i != length && wstr[i] != L'\0')
+ i++;
+ } else {
+ *msg << '\0';
+ i++;
+ }
+ }
+}
+
+#endif // GTEST_HAS_STD_WSTRING
+
+void SplitString(const ::std::string& str, char delimiter,
+ ::std::vector< ::std::string>* dest) {
+ ::std::vector< ::std::string> parsed;
+ ::std::string::size_type pos = 0;
+ while (::testing::internal::AlwaysTrue()) {
+ const ::std::string::size_type colon = str.find(delimiter, pos);
+ if (colon == ::std::string::npos) {
+ parsed.push_back(str.substr(pos));
+ break;
+ } else {
+ parsed.push_back(str.substr(pos, colon - pos));
+ pos = colon + 1;
+ }
+ }
+ dest->swap(parsed);
+}
+
+} // namespace internal
+
+// Constructs an empty Message.
+// We allocate the stringstream separately because otherwise each use of
+// ASSERT/EXPECT in a procedure adds over 200 bytes to the procedure's
+// stack frame leading to huge stack frames in some cases; gcc does not reuse
+// the stack space.
+Message::Message() : ss_(new ::std::stringstream) {
+ // By default, we want there to be enough precision when printing
+ // a double to a Message.
+ *ss_ << std::setprecision(std::numeric_limits<double>::digits10 + 2);
+}
+
+// These two overloads allow streaming a wide C string to a Message
+// using the UTF-8 encoding.
+Message& Message::operator <<(const wchar_t* wide_c_str) {
+ return *this << internal::String::ShowWideCString(wide_c_str);
+}
+Message& Message::operator <<(wchar_t* wide_c_str) {
+ return *this << internal::String::ShowWideCString(wide_c_str);
+}
+
+#if GTEST_HAS_STD_WSTRING
+// Converts the given wide string to a narrow string using the UTF-8
+// encoding, and streams the result to this Message object.
+Message& Message::operator <<(const ::std::wstring& wstr) {
+ internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this);
+ return *this;
+}
+#endif // GTEST_HAS_STD_WSTRING
+
+// Gets the text streamed to this object so far as an std::string.
+// Each '\0' character in the buffer is replaced with "\\0".
+std::string Message::GetString() const {
+ return internal::StringStreamToString(ss_.get());
+}
+
+// AssertionResult constructors.
+// Used in EXPECT_TRUE/FALSE(assertion_result).
+AssertionResult::AssertionResult(const AssertionResult& other)
+ : success_(other.success_),
+ message_(other.message_.get() != nullptr
+ ? new ::std::string(*other.message_)
+ : static_cast< ::std::string*>(nullptr)) {}
+
+// Swaps two AssertionResults.
+void AssertionResult::swap(AssertionResult& other) {
+ using std::swap;
+ swap(success_, other.success_);
+ swap(message_, other.message_);
+}
+
+// Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE.
+AssertionResult AssertionResult::operator!() const {
+ AssertionResult negation(!success_);
+ if (message_.get() != nullptr) negation << *message_;
+ return negation;
+}
+
+// Makes a successful assertion result.
+AssertionResult AssertionSuccess() {
+ return AssertionResult(true);
+}
+
+// Makes a failed assertion result.
+AssertionResult AssertionFailure() {
+ return AssertionResult(false);
+}
+
+// Makes a failed assertion result with the given failure message.
+// Deprecated; use AssertionFailure() << message.
+AssertionResult AssertionFailure(const Message& message) {
+ return AssertionFailure() << message;
+}
+
+namespace internal {
+
+namespace edit_distance {
+std::vector<EditType> CalculateOptimalEdits(const std::vector<size_t>& left,
+ const std::vector<size_t>& right) {
+ std::vector<std::vector<double> > costs(
+ left.size() + 1, std::vector<double>(right.size() + 1));
+ std::vector<std::vector<EditType> > best_move(
+ left.size() + 1, std::vector<EditType>(right.size() + 1));
+
+ // Populate for empty right.
+ for (size_t l_i = 0; l_i < costs.size(); ++l_i) {
+ costs[l_i][0] = static_cast<double>(l_i);
+ best_move[l_i][0] = kRemove;
+ }
+ // Populate for empty left.
+ for (size_t r_i = 1; r_i < costs[0].size(); ++r_i) {
+ costs[0][r_i] = static_cast<double>(r_i);
+ best_move[0][r_i] = kAdd;
+ }
+
+ for (size_t l_i = 0; l_i < left.size(); ++l_i) {
+ for (size_t r_i = 0; r_i < right.size(); ++r_i) {
+ if (left[l_i] == right[r_i]) {
+ // Found a match. Consume it.
+ costs[l_i + 1][r_i + 1] = costs[l_i][r_i];
+ best_move[l_i + 1][r_i + 1] = kMatch;
+ continue;
+ }
+
+ const double add = costs[l_i + 1][r_i];
+ const double remove = costs[l_i][r_i + 1];
+ const double replace = costs[l_i][r_i];
+ if (add < remove && add < replace) {
+ costs[l_i + 1][r_i + 1] = add + 1;
+ best_move[l_i + 1][r_i + 1] = kAdd;
+ } else if (remove < add && remove < replace) {
+ costs[l_i + 1][r_i + 1] = remove + 1;
+ best_move[l_i + 1][r_i + 1] = kRemove;
+ } else {
+ // We make replace a little more expensive than add/remove to lower
+ // their priority.
+ costs[l_i + 1][r_i + 1] = replace + 1.00001;
+ best_move[l_i + 1][r_i + 1] = kReplace;
+ }
+ }
+ }
+
+ // Reconstruct the best path. We do it in reverse order.
+ std::vector<EditType> best_path;
+ for (size_t l_i = left.size(), r_i = right.size(); l_i > 0 || r_i > 0;) {
+ EditType move = best_move[l_i][r_i];
+ best_path.push_back(move);
+ l_i -= move != kAdd;
+ r_i -= move != kRemove;
+ }
+ std::reverse(best_path.begin(), best_path.end());
+ return best_path;
+}
+
+namespace {
+
+// Helper class to convert string into ids with deduplication.
+class InternalStrings {
+ public:
+ size_t GetId(const std::string& str) {
+ IdMap::iterator it = ids_.find(str);
+ if (it != ids_.end()) return it->second;
+ size_t id = ids_.size();
+ return ids_[str] = id;
+ }
+
+ private:
+ typedef std::map<std::string, size_t> IdMap;
+ IdMap ids_;
+};
+
+} // namespace
+
+std::vector<EditType> CalculateOptimalEdits(
+ const std::vector<std::string>& left,
+ const std::vector<std::string>& right) {
+ std::vector<size_t> left_ids, right_ids;
+ {
+ InternalStrings intern_table;
+ for (size_t i = 0; i < left.size(); ++i) {
+ left_ids.push_back(intern_table.GetId(left[i]));
+ }
+ for (size_t i = 0; i < right.size(); ++i) {
+ right_ids.push_back(intern_table.GetId(right[i]));
+ }
+ }
+ return CalculateOptimalEdits(left_ids, right_ids);
+}
+
+namespace {
+
+// Helper class that holds the state for one hunk and prints it out to the
+// stream.
+// It reorders adds/removes when possible to group all removes before all
+// adds. It also adds the hunk header before printint into the stream.
+class Hunk {
+ public:
+ Hunk(size_t left_start, size_t right_start)
+ : left_start_(left_start),
+ right_start_(right_start),
+ adds_(),
+ removes_(),
+ common_() {}
+
+ void PushLine(char edit, const char* line) {
+ switch (edit) {
+ case ' ':
+ ++common_;
+ FlushEdits();
+ hunk_.push_back(std::make_pair(' ', line));
+ break;
+ case '-':
+ ++removes_;
+ hunk_removes_.push_back(std::make_pair('-', line));
+ break;
+ case '+':
+ ++adds_;
+ hunk_adds_.push_back(std::make_pair('+', line));
+ break;
+ }
+ }
+
+ void PrintTo(std::ostream* os) {
+ PrintHeader(os);
+ FlushEdits();
+ for (std::list<std::pair<char, const char*> >::const_iterator it =
+ hunk_.begin();
+ it != hunk_.end(); ++it) {
+ *os << it->first << it->second << "\n";
+ }
+ }
+
+ bool has_edits() const { return adds_ || removes_; }
+
+ private:
+ void FlushEdits() {
+ hunk_.splice(hunk_.end(), hunk_removes_);
+ hunk_.splice(hunk_.end(), hunk_adds_);
+ }
+
+ // Print a unified diff header for one hunk.
+ // The format is
+ // "@@ -<left_start>,<left_length> +<right_start>,<right_length> @@"
+ // where the left/right parts are omitted if unnecessary.
+ void PrintHeader(std::ostream* ss) const {
+ *ss << "@@ ";
+ if (removes_) {
+ *ss << "-" << left_start_ << "," << (removes_ + common_);
+ }
+ if (removes_ && adds_) {
+ *ss << " ";
+ }
+ if (adds_) {
+ *ss << "+" << right_start_ << "," << (adds_ + common_);
+ }
+ *ss << " @@\n";
+ }
+
+ size_t left_start_, right_start_;
+ size_t adds_, removes_, common_;
+ std::list<std::pair<char, const char*> > hunk_, hunk_adds_, hunk_removes_;
+};
+
+} // namespace
+
+// Create a list of diff hunks in Unified diff format.
+// Each hunk has a header generated by PrintHeader above plus a body with
+// lines prefixed with ' ' for no change, '-' for deletion and '+' for
+// addition.
+// 'context' represents the desired unchanged prefix/suffix around the diff.
+// If two hunks are close enough that their contexts overlap, then they are
+// joined into one hunk.
+std::string CreateUnifiedDiff(const std::vector<std::string>& left,
+ const std::vector<std::string>& right,
+ size_t context) {
+ const std::vector<EditType> edits = CalculateOptimalEdits(left, right);
+
+ size_t l_i = 0, r_i = 0, edit_i = 0;
+ std::stringstream ss;
+ while (edit_i < edits.size()) {
+ // Find first edit.
+ while (edit_i < edits.size() && edits[edit_i] == kMatch) {
+ ++l_i;
+ ++r_i;
+ ++edit_i;
+ }
+
+ // Find the first line to include in the hunk.
+ const size_t prefix_context = std::min(l_i, context);
+ Hunk hunk(l_i - prefix_context + 1, r_i - prefix_context + 1);
+ for (size_t i = prefix_context; i > 0; --i) {
+ hunk.PushLine(' ', left[l_i - i].c_str());
+ }
+
+ // Iterate the edits until we found enough suffix for the hunk or the input
+ // is over.
+ size_t n_suffix = 0;
+ for (; edit_i < edits.size(); ++edit_i) {
+ if (n_suffix >= context) {
+ // Continue only if the next hunk is very close.
+ auto it = edits.begin() + static_cast<int>(edit_i);
+ while (it != edits.end() && *it == kMatch) ++it;
+ if (it == edits.end() ||
+ static_cast<size_t>(it - edits.begin()) - edit_i >= context) {
+ // There is no next edit or it is too far away.
+ break;
+ }
+ }
+
+ EditType edit = edits[edit_i];
+ // Reset count when a non match is found.
+ n_suffix = edit == kMatch ? n_suffix + 1 : 0;
+
+ if (edit == kMatch || edit == kRemove || edit == kReplace) {
+ hunk.PushLine(edit == kMatch ? ' ' : '-', left[l_i].c_str());
+ }
+ if (edit == kAdd || edit == kReplace) {
+ hunk.PushLine('+', right[r_i].c_str());
+ }
+
+ // Advance indices, depending on edit type.
+ l_i += edit != kAdd;
+ r_i += edit != kRemove;
+ }
+
+ if (!hunk.has_edits()) {
+ // We are done. We don't want this hunk.
+ break;
+ }
+
+ hunk.PrintTo(&ss);
+ }
+ return ss.str();
+}
+
+} // namespace edit_distance
+
+namespace {
+
+// The string representation of the values received in EqFailure() are already
+// escaped. Split them on escaped '\n' boundaries. Leave all other escaped
+// characters the same.
+std::vector<std::string> SplitEscapedString(const std::string& str) {
+ std::vector<std::string> lines;
+ size_t start = 0, end = str.size();
+ if (end > 2 && str[0] == '"' && str[end - 1] == '"') {
+ ++start;
+ --end;
+ }
+ bool escaped = false;
+ for (size_t i = start; i + 1 < end; ++i) {
+ if (escaped) {
+ escaped = false;
+ if (str[i] == 'n') {
+ lines.push_back(str.substr(start, i - start - 1));
+ start = i + 1;
+ }
+ } else {
+ escaped = str[i] == '\\';
+ }
+ }
+ lines.push_back(str.substr(start, end - start));
+ return lines;
+}
+
+} // namespace
+
+// Constructs and returns the message for an equality assertion
+// (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure.
+//
+// The first four parameters are the expressions used in the assertion
+// and their values, as strings. For example, for ASSERT_EQ(foo, bar)
+// where foo is 5 and bar is 6, we have:
+//
+// lhs_expression: "foo"
+// rhs_expression: "bar"
+// lhs_value: "5"
+// rhs_value: "6"
+//
+// The ignoring_case parameter is true if and only if the assertion is a
+// *_STRCASEEQ*. When it's true, the string "Ignoring case" will
+// be inserted into the message.
+AssertionResult EqFailure(const char* lhs_expression,
+ const char* rhs_expression,
+ const std::string& lhs_value,
+ const std::string& rhs_value,
+ bool ignoring_case) {
+ Message msg;
+ msg << "Expected equality of these values:";
+ msg << "\n " << lhs_expression;
+ if (lhs_value != lhs_expression) {
+ msg << "\n Which is: " << lhs_value;
+ }
+ msg << "\n " << rhs_expression;
+ if (rhs_value != rhs_expression) {
+ msg << "\n Which is: " << rhs_value;
+ }
+
+ if (ignoring_case) {
+ msg << "\nIgnoring case";
+ }
+
+ if (!lhs_value.empty() && !rhs_value.empty()) {
+ const std::vector<std::string> lhs_lines =
+ SplitEscapedString(lhs_value);
+ const std::vector<std::string> rhs_lines =
+ SplitEscapedString(rhs_value);
+ if (lhs_lines.size() > 1 || rhs_lines.size() > 1) {
+ msg << "\nWith diff:\n"
+ << edit_distance::CreateUnifiedDiff(lhs_lines, rhs_lines);
+ }
+ }
+
+ return AssertionFailure() << msg;
+}
+
+// Constructs a failure message for Boolean assertions such as EXPECT_TRUE.
+std::string GetBoolAssertionFailureMessage(
+ const AssertionResult& assertion_result,
+ const char* expression_text,
+ const char* actual_predicate_value,
+ const char* expected_predicate_value) {
+ const char* actual_message = assertion_result.message();
+ Message msg;
+ msg << "Value of: " << expression_text
+ << "\n Actual: " << actual_predicate_value;
+ if (actual_message[0] != '\0')
+ msg << " (" << actual_message << ")";
+ msg << "\nExpected: " << expected_predicate_value;
+ return msg.GetString();
+}
+
+// Helper function for implementing ASSERT_NEAR.
+AssertionResult DoubleNearPredFormat(const char* expr1,
+ const char* expr2,
+ const char* abs_error_expr,
+ double val1,
+ double val2,
+ double abs_error) {
+ const double diff = fabs(val1 - val2);
+ if (diff <= abs_error) return AssertionSuccess();
+
+ // Find the value which is closest to zero.
+ const double min_abs = std::min(fabs(val1), fabs(val2));
+ // Find the distance to the next double from that value.
+ const double epsilon =
+ nextafter(min_abs, std::numeric_limits<double>::infinity()) - min_abs;
+ // Detect the case where abs_error is so small that EXPECT_NEAR is
+ // effectively the same as EXPECT_EQUAL, and give an informative error
+ // message so that the situation can be more easily understood without
+ // requiring exotic floating-point knowledge.
+ // Don't do an epsilon check if abs_error is zero because that implies
+ // that an equality check was actually intended.
+ if (!(std::isnan)(val1) && !(std::isnan)(val2) && abs_error > 0 &&
+ abs_error < epsilon) {
+ return AssertionFailure()
+ << "The difference between " << expr1 << " and " << expr2 << " is "
+ << diff << ", where\n"
+ << expr1 << " evaluates to " << val1 << ",\n"
+ << expr2 << " evaluates to " << val2 << ".\nThe abs_error parameter "
+ << abs_error_expr << " evaluates to " << abs_error
+ << " which is smaller than the minimum distance between doubles for "
+ "numbers of this magnitude which is "
+ << epsilon
+ << ", thus making this EXPECT_NEAR check equivalent to "
+ "EXPECT_EQUAL. Consider using EXPECT_DOUBLE_EQ instead.";
+ }
+ return AssertionFailure()
+ << "The difference between " << expr1 << " and " << expr2
+ << " is " << diff << ", which exceeds " << abs_error_expr << ", where\n"
+ << expr1 << " evaluates to " << val1 << ",\n"
+ << expr2 << " evaluates to " << val2 << ", and\n"
+ << abs_error_expr << " evaluates to " << abs_error << ".";
+}
+
+
+// Helper template for implementing FloatLE() and DoubleLE().
+template <typename RawType>
+AssertionResult FloatingPointLE(const char* expr1,
+ const char* expr2,
+ RawType val1,
+ RawType val2) {
+ // Returns success if val1 is less than val2,
+ if (val1 < val2) {
+ return AssertionSuccess();
+ }
+
+ // or if val1 is almost equal to val2.
+ const FloatingPoint<RawType> lhs(val1), rhs(val2);
+ if (lhs.AlmostEquals(rhs)) {
+ return AssertionSuccess();
+ }
+
+ // Note that the above two checks will both fail if either val1 or
+ // val2 is NaN, as the IEEE floating-point standard requires that
+ // any predicate involving a NaN must return false.
+
+ ::std::stringstream val1_ss;
+ val1_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
+ << val1;
+
+ ::std::stringstream val2_ss;
+ val2_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
+ << val2;
+
+ return AssertionFailure()
+ << "Expected: (" << expr1 << ") <= (" << expr2 << ")\n"
+ << " Actual: " << StringStreamToString(&val1_ss) << " vs "
+ << StringStreamToString(&val2_ss);
+}
+
+} // namespace internal
+
+// Asserts that val1 is less than, or almost equal to, val2. Fails
+// otherwise. In particular, it fails if either val1 or val2 is NaN.
+AssertionResult FloatLE(const char* expr1, const char* expr2,
+ float val1, float val2) {
+ return internal::FloatingPointLE<float>(expr1, expr2, val1, val2);
+}
+
+// Asserts that val1 is less than, or almost equal to, val2. Fails
+// otherwise. In particular, it fails if either val1 or val2 is NaN.
+AssertionResult DoubleLE(const char* expr1, const char* expr2,
+ double val1, double val2) {
+ return internal::FloatingPointLE<double>(expr1, expr2, val1, val2);
+}
+
+namespace internal {
+
+// The helper function for {ASSERT|EXPECT}_STREQ.
+AssertionResult CmpHelperSTREQ(const char* lhs_expression,
+ const char* rhs_expression,
+ const char* lhs,
+ const char* rhs) {
+ if (String::CStringEquals(lhs, rhs)) {
+ return AssertionSuccess();
+ }
+
+ return EqFailure(lhs_expression,
+ rhs_expression,
+ PrintToString(lhs),
+ PrintToString(rhs),
+ false);
+}
+
+// The helper function for {ASSERT|EXPECT}_STRCASEEQ.
+AssertionResult CmpHelperSTRCASEEQ(const char* lhs_expression,
+ const char* rhs_expression,
+ const char* lhs,
+ const char* rhs) {
+ if (String::CaseInsensitiveCStringEquals(lhs, rhs)) {
+ return AssertionSuccess();
+ }
+
+ return EqFailure(lhs_expression,
+ rhs_expression,
+ PrintToString(lhs),
+ PrintToString(rhs),
+ true);
+}
+
+// The helper function for {ASSERT|EXPECT}_STRNE.
+AssertionResult CmpHelperSTRNE(const char* s1_expression,
+ const char* s2_expression,
+ const char* s1,
+ const char* s2) {
+ if (!String::CStringEquals(s1, s2)) {
+ return AssertionSuccess();
+ } else {
+ return AssertionFailure() << "Expected: (" << s1_expression << ") != ("
+ << s2_expression << "), actual: \""
+ << s1 << "\" vs \"" << s2 << "\"";
+ }
+}
+
+// The helper function for {ASSERT|EXPECT}_STRCASENE.
+AssertionResult CmpHelperSTRCASENE(const char* s1_expression,
+ const char* s2_expression,
+ const char* s1,
+ const char* s2) {
+ if (!String::CaseInsensitiveCStringEquals(s1, s2)) {
+ return AssertionSuccess();
+ } else {
+ return AssertionFailure()
+ << "Expected: (" << s1_expression << ") != ("
+ << s2_expression << ") (ignoring case), actual: \""
+ << s1 << "\" vs \"" << s2 << "\"";
+ }
+}
+
+} // namespace internal
+
+namespace {
+
+// Helper functions for implementing IsSubString() and IsNotSubstring().
+
+// This group of overloaded functions return true if and only if needle
+// is a substring of haystack. NULL is considered a substring of
+// itself only.
+
+bool IsSubstringPred(const char* needle, const char* haystack) {
+ if (needle == nullptr || haystack == nullptr) return needle == haystack;
+
+ return strstr(haystack, needle) != nullptr;
+}
+
+bool IsSubstringPred(const wchar_t* needle, const wchar_t* haystack) {
+ if (needle == nullptr || haystack == nullptr) return needle == haystack;
+
+ return wcsstr(haystack, needle) != nullptr;
+}
+
+// StringType here can be either ::std::string or ::std::wstring.
+template <typename StringType>
+bool IsSubstringPred(const StringType& needle,
+ const StringType& haystack) {
+ return haystack.find(needle) != StringType::npos;
+}
+
+// This function implements either IsSubstring() or IsNotSubstring(),
+// depending on the value of the expected_to_be_substring parameter.
+// StringType here can be const char*, const wchar_t*, ::std::string,
+// or ::std::wstring.
+template <typename StringType>
+AssertionResult IsSubstringImpl(
+ bool expected_to_be_substring,
+ const char* needle_expr, const char* haystack_expr,
+ const StringType& needle, const StringType& haystack) {
+ if (IsSubstringPred(needle, haystack) == expected_to_be_substring)
+ return AssertionSuccess();
+
+ const bool is_wide_string = sizeof(needle[0]) > 1;
+ const char* const begin_string_quote = is_wide_string ? "L\"" : "\"";
+ return AssertionFailure()
+ << "Value of: " << needle_expr << "\n"
+ << " Actual: " << begin_string_quote << needle << "\"\n"
+ << "Expected: " << (expected_to_be_substring ? "" : "not ")
+ << "a substring of " << haystack_expr << "\n"
+ << "Which is: " << begin_string_quote << haystack << "\"";
+}
+
+} // namespace
+
+// IsSubstring() and IsNotSubstring() check whether needle is a
+// substring of haystack (NULL is considered a substring of itself
+// only), and return an appropriate error message when they fail.
+
+AssertionResult IsSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const char* needle, const char* haystack) {
+ return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack);
+}
+
+AssertionResult IsSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const wchar_t* needle, const wchar_t* haystack) {
+ return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack);
+}
+
+AssertionResult IsNotSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const char* needle, const char* haystack) {
+ return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack);
+}
+
+AssertionResult IsNotSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const wchar_t* needle, const wchar_t* haystack) {
+ return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack);
+}
+
+AssertionResult IsSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const ::std::string& needle, const ::std::string& haystack) {
+ return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack);
+}
+
+AssertionResult IsNotSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const ::std::string& needle, const ::std::string& haystack) {
+ return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack);
+}
+
+#if GTEST_HAS_STD_WSTRING
+AssertionResult IsSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const ::std::wstring& needle, const ::std::wstring& haystack) {
+ return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack);
+}
+
+AssertionResult IsNotSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const ::std::wstring& needle, const ::std::wstring& haystack) {
+ return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack);
+}
+#endif // GTEST_HAS_STD_WSTRING
+
+namespace internal {
+
+#if GTEST_OS_WINDOWS
+
+namespace {
+
+// Helper function for IsHRESULT{SuccessFailure} predicates
+AssertionResult HRESULTFailureHelper(const char* expr,
+ const char* expected,
+ long hr) { // NOLINT
+# if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_TV_TITLE
+
+ // Windows CE doesn't support FormatMessage.
+ const char error_text[] = "";
+
+# else
+
+ // Looks up the human-readable system message for the HRESULT code
+ // and since we're not passing any params to FormatMessage, we don't
+ // want inserts expanded.
+ const DWORD kFlags = FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS;
+ const DWORD kBufSize = 4096;
+ // Gets the system's human readable message string for this HRESULT.
+ char error_text[kBufSize] = { '\0' };
+ DWORD message_length = ::FormatMessageA(kFlags,
+ 0, // no source, we're asking system
+ static_cast<DWORD>(hr), // the error
+ 0, // no line width restrictions
+ error_text, // output buffer
+ kBufSize, // buf size
+ nullptr); // no arguments for inserts
+ // Trims tailing white space (FormatMessage leaves a trailing CR-LF)
+ for (; message_length && IsSpace(error_text[message_length - 1]);
+ --message_length) {
+ error_text[message_length - 1] = '\0';
+ }
+
+# endif // GTEST_OS_WINDOWS_MOBILE
+
+ const std::string error_hex("0x" + String::FormatHexInt(hr));
+ return ::testing::AssertionFailure()
+ << "Expected: " << expr << " " << expected << ".\n"
+ << " Actual: " << error_hex << " " << error_text << "\n";
+}
+
+} // namespace
+
+AssertionResult IsHRESULTSuccess(const char* expr, long hr) { // NOLINT
+ if (SUCCEEDED(hr)) {
+ return AssertionSuccess();
+ }
+ return HRESULTFailureHelper(expr, "succeeds", hr);
+}
+
+AssertionResult IsHRESULTFailure(const char* expr, long hr) { // NOLINT
+ if (FAILED(hr)) {
+ return AssertionSuccess();
+ }
+ return HRESULTFailureHelper(expr, "fails", hr);
+}
+
+#endif // GTEST_OS_WINDOWS
+
+// Utility functions for encoding Unicode text (wide strings) in
+// UTF-8.
+
+// A Unicode code-point can have up to 21 bits, and is encoded in UTF-8
+// like this:
+//
+// Code-point length Encoding
+// 0 - 7 bits 0xxxxxxx
+// 8 - 11 bits 110xxxxx 10xxxxxx
+// 12 - 16 bits 1110xxxx 10xxxxxx 10xxxxxx
+// 17 - 21 bits 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+
+// The maximum code-point a one-byte UTF-8 sequence can represent.
+constexpr uint32_t kMaxCodePoint1 = (static_cast<uint32_t>(1) << 7) - 1;
+
+// The maximum code-point a two-byte UTF-8 sequence can represent.
+constexpr uint32_t kMaxCodePoint2 = (static_cast<uint32_t>(1) << (5 + 6)) - 1;
+
+// The maximum code-point a three-byte UTF-8 sequence can represent.
+constexpr uint32_t kMaxCodePoint3 = (static_cast<uint32_t>(1) << (4 + 2*6)) - 1;
+
+// The maximum code-point a four-byte UTF-8 sequence can represent.
+constexpr uint32_t kMaxCodePoint4 = (static_cast<uint32_t>(1) << (3 + 3*6)) - 1;
+
+// Chops off the n lowest bits from a bit pattern. Returns the n
+// lowest bits. As a side effect, the original bit pattern will be
+// shifted to the right by n bits.
+inline uint32_t ChopLowBits(uint32_t* bits, int n) {
+ const uint32_t low_bits = *bits & ((static_cast<uint32_t>(1) << n) - 1);
+ *bits >>= n;
+ return low_bits;
+}
+
+// Converts a Unicode code point to a narrow string in UTF-8 encoding.
+// code_point parameter is of type uint32_t because wchar_t may not be
+// wide enough to contain a code point.
+// If the code_point is not a valid Unicode code point
+// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be converted
+// to "(Invalid Unicode 0xXXXXXXXX)".
+std::string CodePointToUtf8(uint32_t code_point) {
+ if (code_point > kMaxCodePoint4) {
+ return "(Invalid Unicode 0x" + String::FormatHexUInt32(code_point) + ")";
+ }
+
+ char str[5]; // Big enough for the largest valid code point.
+ if (code_point <= kMaxCodePoint1) {
+ str[1] = '\0';
+ str[0] = static_cast<char>(code_point); // 0xxxxxxx
+ } else if (code_point <= kMaxCodePoint2) {
+ str[2] = '\0';
+ str[1] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx
+ str[0] = static_cast<char>(0xC0 | code_point); // 110xxxxx
+ } else if (code_point <= kMaxCodePoint3) {
+ str[3] = '\0';
+ str[2] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx
+ str[1] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx
+ str[0] = static_cast<char>(0xE0 | code_point); // 1110xxxx
+ } else { // code_point <= kMaxCodePoint4
+ str[4] = '\0';
+ str[3] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx
+ str[2] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx
+ str[1] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx
+ str[0] = static_cast<char>(0xF0 | code_point); // 11110xxx
+ }
+ return str;
+}
+
+// The following two functions only make sense if the system
+// uses UTF-16 for wide string encoding. All supported systems
+// with 16 bit wchar_t (Windows, Cygwin) do use UTF-16.
+
+// Determines if the arguments constitute UTF-16 surrogate pair
+// and thus should be combined into a single Unicode code point
+// using CreateCodePointFromUtf16SurrogatePair.
+inline bool IsUtf16SurrogatePair(wchar_t first, wchar_t second) {
+ return sizeof(wchar_t) == 2 &&
+ (first & 0xFC00) == 0xD800 && (second & 0xFC00) == 0xDC00;
+}
+
+// Creates a Unicode code point from UTF16 surrogate pair.
+inline uint32_t CreateCodePointFromUtf16SurrogatePair(wchar_t first,
+ wchar_t second) {
+ const auto first_u = static_cast<uint32_t>(first);
+ const auto second_u = static_cast<uint32_t>(second);
+ const uint32_t mask = (1 << 10) - 1;
+ return (sizeof(wchar_t) == 2)
+ ? (((first_u & mask) << 10) | (second_u & mask)) + 0x10000
+ :
+ // This function should not be called when the condition is
+ // false, but we provide a sensible default in case it is.
+ first_u;
+}
+
+// Converts a wide string to a narrow string in UTF-8 encoding.
+// The wide string is assumed to have the following encoding:
+// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin)
+// UTF-32 if sizeof(wchar_t) == 4 (on Linux)
+// Parameter str points to a null-terminated wide string.
+// Parameter num_chars may additionally limit the number
+// of wchar_t characters processed. -1 is used when the entire string
+// should be processed.
+// If the string contains code points that are not valid Unicode code points
+// (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output
+// as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding
+// and contains invalid UTF-16 surrogate pairs, values in those pairs
+// will be encoded as individual Unicode characters from Basic Normal Plane.
+std::string WideStringToUtf8(const wchar_t* str, int num_chars) {
+ if (num_chars == -1)
+ num_chars = static_cast<int>(wcslen(str));
+
+ ::std::stringstream stream;
+ for (int i = 0; i < num_chars; ++i) {
+ uint32_t unicode_code_point;
+
+ if (str[i] == L'\0') {
+ break;
+ } else if (i + 1 < num_chars && IsUtf16SurrogatePair(str[i], str[i + 1])) {
+ unicode_code_point = CreateCodePointFromUtf16SurrogatePair(str[i],
+ str[i + 1]);
+ i++;
+ } else {
+ unicode_code_point = static_cast<uint32_t>(str[i]);
+ }
+
+ stream << CodePointToUtf8(unicode_code_point);
+ }
+ return StringStreamToString(&stream);
+}
+
+// Converts a wide C string to an std::string using the UTF-8 encoding.
+// NULL will be converted to "(null)".
+std::string String::ShowWideCString(const wchar_t * wide_c_str) {
+ if (wide_c_str == nullptr) return "(null)";
+
+ return internal::WideStringToUtf8(wide_c_str, -1);
+}
+
+// Compares two wide C strings. Returns true if and only if they have the
+// same content.
+//
+// Unlike wcscmp(), this function can handle NULL argument(s). A NULL
+// C string is considered different to any non-NULL C string,
+// including the empty string.
+bool String::WideCStringEquals(const wchar_t * lhs, const wchar_t * rhs) {
+ if (lhs == nullptr) return rhs == nullptr;
+
+ if (rhs == nullptr) return false;
+
+ return wcscmp(lhs, rhs) == 0;
+}
+
+// Helper function for *_STREQ on wide strings.
+AssertionResult CmpHelperSTREQ(const char* lhs_expression,
+ const char* rhs_expression,
+ const wchar_t* lhs,
+ const wchar_t* rhs) {
+ if (String::WideCStringEquals(lhs, rhs)) {
+ return AssertionSuccess();
+ }
+
+ return EqFailure(lhs_expression,
+ rhs_expression,
+ PrintToString(lhs),
+ PrintToString(rhs),
+ false);
+}
+
+// Helper function for *_STRNE on wide strings.
+AssertionResult CmpHelperSTRNE(const char* s1_expression,
+ const char* s2_expression,
+ const wchar_t* s1,
+ const wchar_t* s2) {
+ if (!String::WideCStringEquals(s1, s2)) {
+ return AssertionSuccess();
+ }
+
+ return AssertionFailure() << "Expected: (" << s1_expression << ") != ("
+ << s2_expression << "), actual: "
+ << PrintToString(s1)
+ << " vs " << PrintToString(s2);
+}
+
+// Compares two C strings, ignoring case. Returns true if and only if they have
+// the same content.
+//
+// Unlike strcasecmp(), this function can handle NULL argument(s). A
+// NULL C string is considered different to any non-NULL C string,
+// including the empty string.
+bool String::CaseInsensitiveCStringEquals(const char * lhs, const char * rhs) {
+ if (lhs == nullptr) return rhs == nullptr;
+ if (rhs == nullptr) return false;
+ return posix::StrCaseCmp(lhs, rhs) == 0;
+}
+
+// Compares two wide C strings, ignoring case. Returns true if and only if they
+// have the same content.
+//
+// Unlike wcscasecmp(), this function can handle NULL argument(s).
+// A NULL C string is considered different to any non-NULL wide C string,
+// including the empty string.
+// NB: The implementations on different platforms slightly differ.
+// On windows, this method uses _wcsicmp which compares according to LC_CTYPE
+// environment variable. On GNU platform this method uses wcscasecmp
+// which compares according to LC_CTYPE category of the current locale.
+// On MacOS X, it uses towlower, which also uses LC_CTYPE category of the
+// current locale.
+bool String::CaseInsensitiveWideCStringEquals(const wchar_t* lhs,
+ const wchar_t* rhs) {
+ if (lhs == nullptr) return rhs == nullptr;
+
+ if (rhs == nullptr) return false;
+
+#if GTEST_OS_WINDOWS
+ return _wcsicmp(lhs, rhs) == 0;
+#elif GTEST_OS_LINUX && !GTEST_OS_LINUX_ANDROID
+ return wcscasecmp(lhs, rhs) == 0;
+#else
+ // Android, Mac OS X and Cygwin don't define wcscasecmp.
+ // Other unknown OSes may not define it either.
+ wint_t left, right;
+ do {
+ left = towlower(static_cast<wint_t>(*lhs++));
+ right = towlower(static_cast<wint_t>(*rhs++));
+ } while (left && left == right);
+ return left == right;
+#endif // OS selector
+}
+
+// Returns true if and only if str ends with the given suffix, ignoring case.
+// Any string is considered to end with an empty suffix.
+bool String::EndsWithCaseInsensitive(
+ const std::string& str, const std::string& suffix) {
+ const size_t str_len = str.length();
+ const size_t suffix_len = suffix.length();
+ return (str_len >= suffix_len) &&
+ CaseInsensitiveCStringEquals(str.c_str() + str_len - suffix_len,
+ suffix.c_str());
+}
+
+// Formats an int value as "%02d".
+std::string String::FormatIntWidth2(int value) {
+ return FormatIntWidthN(value, 2);
+}
+
+// Formats an int value to given width with leading zeros.
+std::string String::FormatIntWidthN(int value, int width) {
+ std::stringstream ss;
+ ss << std::setfill('0') << std::setw(width) << value;
+ return ss.str();
+}
+
+// Formats an int value as "%X".
+std::string String::FormatHexUInt32(uint32_t value) {
+ std::stringstream ss;
+ ss << std::hex << std::uppercase << value;
+ return ss.str();
+}
+
+// Formats an int value as "%X".
+std::string String::FormatHexInt(int value) {
+ return FormatHexUInt32(static_cast<uint32_t>(value));
+}
+
+// Formats a byte as "%02X".
+std::string String::FormatByte(unsigned char value) {
+ std::stringstream ss;
+ ss << std::setfill('0') << std::setw(2) << std::hex << std::uppercase
+ << static_cast<unsigned int>(value);
+ return ss.str();
+}
+
+// Converts the buffer in a stringstream to an std::string, converting NUL
+// bytes to "\\0" along the way.
+std::string StringStreamToString(::std::stringstream* ss) {
+ const ::std::string& str = ss->str();
+ const char* const start = str.c_str();
+ const char* const end = start + str.length();
+
+ std::string result;
+ result.reserve(static_cast<size_t>(2 * (end - start)));
+ for (const char* ch = start; ch != end; ++ch) {
+ if (*ch == '\0') {
+ result += "\\0"; // Replaces NUL with "\\0";
+ } else {
+ result += *ch;
+ }
+ }
+
+ return result;
+}
+
+// Appends the user-supplied message to the Google-Test-generated message.
+std::string AppendUserMessage(const std::string& gtest_msg,
+ const Message& user_msg) {
+ // Appends the user message if it's non-empty.
+ const std::string user_msg_string = user_msg.GetString();
+ if (user_msg_string.empty()) {
+ return gtest_msg;
+ }
+ if (gtest_msg.empty()) {
+ return user_msg_string;
+ }
+ return gtest_msg + "\n" + user_msg_string;
+}
+
+} // namespace internal
+
+// class TestResult
+
+// Creates an empty TestResult.
+TestResult::TestResult()
+ : death_test_count_(0), start_timestamp_(0), elapsed_time_(0) {}
+
+// D'tor.
+TestResult::~TestResult() {
+}
+
+// Returns the i-th test part result among all the results. i can
+// range from 0 to total_part_count() - 1. If i is not in that range,
+// aborts the program.
+const TestPartResult& TestResult::GetTestPartResult(int i) const {
+ if (i < 0 || i >= total_part_count())
+ internal::posix::Abort();
+ return test_part_results_.at(static_cast<size_t>(i));
+}
+
+// Returns the i-th test property. i can range from 0 to
+// test_property_count() - 1. If i is not in that range, aborts the
+// program.
+const TestProperty& TestResult::GetTestProperty(int i) const {
+ if (i < 0 || i >= test_property_count())
+ internal::posix::Abort();
+ return test_properties_.at(static_cast<size_t>(i));
+}
+
+// Clears the test part results.
+void TestResult::ClearTestPartResults() {
+ test_part_results_.clear();
+}
+
+// Adds a test part result to the list.
+void TestResult::AddTestPartResult(const TestPartResult& test_part_result) {
+ test_part_results_.push_back(test_part_result);
+}
+
+// Adds a test property to the list. If a property with the same key as the
+// supplied property is already represented, the value of this test_property
+// replaces the old value for that key.
+void TestResult::RecordProperty(const std::string& xml_element,
+ const TestProperty& test_property) {
+ if (!ValidateTestProperty(xml_element, test_property)) {
+ return;
+ }
+ internal::MutexLock lock(&test_properties_mutex_);
+ const std::vector<TestProperty>::iterator property_with_matching_key =
+ std::find_if(test_properties_.begin(), test_properties_.end(),
+ internal::TestPropertyKeyIs(test_property.key()));
+ if (property_with_matching_key == test_properties_.end()) {
+ test_properties_.push_back(test_property);
+ return;
+ }
+ property_with_matching_key->SetValue(test_property.value());
+}
+
+// The list of reserved attributes used in the <testsuites> element of XML
+// output.
+static const char* const kReservedTestSuitesAttributes[] = {
+ "disabled",
+ "errors",
+ "failures",
+ "name",
+ "random_seed",
+ "tests",
+ "time",
+ "timestamp"
+};
+
+// The list of reserved attributes used in the <testsuite> element of XML
+// output.
+static const char* const kReservedTestSuiteAttributes[] = {
+ "disabled", "errors", "failures", "name",
+ "tests", "time", "timestamp", "skipped"};
+
+// The list of reserved attributes used in the <testcase> element of XML output.
+static const char* const kReservedTestCaseAttributes[] = {
+ "classname", "name", "status", "time", "type_param",
+ "value_param", "file", "line"};
+
+// Use a slightly different set for allowed output to ensure existing tests can
+// still RecordProperty("result") or "RecordProperty(timestamp")
+static const char* const kReservedOutputTestCaseAttributes[] = {
+ "classname", "name", "status", "time", "type_param",
+ "value_param", "file", "line", "result", "timestamp"};
+
+template <size_t kSize>
+std::vector<std::string> ArrayAsVector(const char* const (&array)[kSize]) {
+ return std::vector<std::string>(array, array + kSize);
+}
+
+static std::vector<std::string> GetReservedAttributesForElement(
+ const std::string& xml_element) {
+ if (xml_element == "testsuites") {
+ return ArrayAsVector(kReservedTestSuitesAttributes);
+ } else if (xml_element == "testsuite") {
+ return ArrayAsVector(kReservedTestSuiteAttributes);
+ } else if (xml_element == "testcase") {
+ return ArrayAsVector(kReservedTestCaseAttributes);
+ } else {
+ GTEST_CHECK_(false) << "Unrecognized xml_element provided: " << xml_element;
+ }
+ // This code is unreachable but some compilers may not realizes that.
+ return std::vector<std::string>();
+}
+
+// TODO(jdesprez): Merge the two getReserved attributes once skip is improved
+static std::vector<std::string> GetReservedOutputAttributesForElement(
+ const std::string& xml_element) {
+ if (xml_element == "testsuites") {
+ return ArrayAsVector(kReservedTestSuitesAttributes);
+ } else if (xml_element == "testsuite") {
+ return ArrayAsVector(kReservedTestSuiteAttributes);
+ } else if (xml_element == "testcase") {
+ return ArrayAsVector(kReservedOutputTestCaseAttributes);
+ } else {
+ GTEST_CHECK_(false) << "Unrecognized xml_element provided: " << xml_element;
+ }
+ // This code is unreachable but some compilers may not realizes that.
+ return std::vector<std::string>();
+}
+
+static std::string FormatWordList(const std::vector<std::string>& words) {
+ Message word_list;
+ for (size_t i = 0; i < words.size(); ++i) {
+ if (i > 0 && words.size() > 2) {
+ word_list << ", ";
+ }
+ if (i == words.size() - 1) {
+ word_list << "and ";
+ }
+ word_list << "'" << words[i] << "'";
+ }
+ return word_list.GetString();
+}
+
+static bool ValidateTestPropertyName(
+ const std::string& property_name,
+ const std::vector<std::string>& reserved_names) {
+ if (std::find(reserved_names.begin(), reserved_names.end(), property_name) !=
+ reserved_names.end()) {
+ ADD_FAILURE() << "Reserved key used in RecordProperty(): " << property_name
+ << " (" << FormatWordList(reserved_names)
+ << " are reserved by " << GTEST_NAME_ << ")";
+ return false;
+ }
+ return true;
+}
+
+// Adds a failure if the key is a reserved attribute of the element named
+// xml_element. Returns true if the property is valid.
+bool TestResult::ValidateTestProperty(const std::string& xml_element,
+ const TestProperty& test_property) {
+ return ValidateTestPropertyName(test_property.key(),
+ GetReservedAttributesForElement(xml_element));
+}
+
+// Clears the object.
+void TestResult::Clear() {
+ test_part_results_.clear();
+ test_properties_.clear();
+ death_test_count_ = 0;
+ elapsed_time_ = 0;
+}
+
+// Returns true off the test part was skipped.
+static bool TestPartSkipped(const TestPartResult& result) {
+ return result.skipped();
+}
+
+// Returns true if and only if the test was skipped.
+bool TestResult::Skipped() const {
+ return !Failed() && CountIf(test_part_results_, TestPartSkipped) > 0;
+}
+
+// Returns true if and only if the test failed.
+bool TestResult::Failed() const {
+ for (int i = 0; i < total_part_count(); ++i) {
+ if (GetTestPartResult(i).failed())
+ return true;
+ }
+ return false;
+}
+
+// Returns true if and only if the test part fatally failed.
+static bool TestPartFatallyFailed(const TestPartResult& result) {
+ return result.fatally_failed();
+}
+
+// Returns true if and only if the test fatally failed.
+bool TestResult::HasFatalFailure() const {
+ return CountIf(test_part_results_, TestPartFatallyFailed) > 0;
+}
+
+// Returns true if and only if the test part non-fatally failed.
+static bool TestPartNonfatallyFailed(const TestPartResult& result) {
+ return result.nonfatally_failed();
+}
+
+// Returns true if and only if the test has a non-fatal failure.
+bool TestResult::HasNonfatalFailure() const {
+ return CountIf(test_part_results_, TestPartNonfatallyFailed) > 0;
+}
+
+// Gets the number of all test parts. This is the sum of the number
+// of successful test parts and the number of failed test parts.
+int TestResult::total_part_count() const {
+ return static_cast<int>(test_part_results_.size());
+}
+
+// Returns the number of the test properties.
+int TestResult::test_property_count() const {
+ return static_cast<int>(test_properties_.size());
+}
+
+// class Test
+
+// Creates a Test object.
+
+// The c'tor saves the states of all flags.
+Test::Test()
+ : gtest_flag_saver_(new GTEST_FLAG_SAVER_) {
+}
+
+// The d'tor restores the states of all flags. The actual work is
+// done by the d'tor of the gtest_flag_saver_ field, and thus not
+// visible here.
+Test::~Test() {
+}
+
+// Sets up the test fixture.
+//
+// A sub-class may override this.
+void Test::SetUp() {
+}
+
+// Tears down the test fixture.
+//
+// A sub-class may override this.
+void Test::TearDown() {
+}
+
+// Allows user supplied key value pairs to be recorded for later output.
+void Test::RecordProperty(const std::string& key, const std::string& value) {
+ UnitTest::GetInstance()->RecordProperty(key, value);
+}
+
+// Allows user supplied key value pairs to be recorded for later output.
+void Test::RecordProperty(const std::string& key, int value) {
+ Message value_message;
+ value_message << value;
+ RecordProperty(key, value_message.GetString().c_str());
+}
+
+namespace internal {
+
+void ReportFailureInUnknownLocation(TestPartResult::Type result_type,
+ const std::string& message) {
+ // This function is a friend of UnitTest and as such has access to
+ // AddTestPartResult.
+ UnitTest::GetInstance()->AddTestPartResult(
+ result_type,
+ nullptr, // No info about the source file where the exception occurred.
+ -1, // We have no info on which line caused the exception.
+ message,
+ ""); // No stack trace, either.
+}
+
+} // namespace internal
+
+// Google Test requires all tests in the same test suite to use the same test
+// fixture class. This function checks if the current test has the
+// same fixture class as the first test in the current test suite. If
+// yes, it returns true; otherwise it generates a Google Test failure and
+// returns false.
+bool Test::HasSameFixtureClass() {
+ internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
+ const TestSuite* const test_suite = impl->current_test_suite();
+
+ // Info about the first test in the current test suite.
+ const TestInfo* const first_test_info = test_suite->test_info_list()[0];
+ const internal::TypeId first_fixture_id = first_test_info->fixture_class_id_;
+ const char* const first_test_name = first_test_info->name();
+
+ // Info about the current test.
+ const TestInfo* const this_test_info = impl->current_test_info();
+ const internal::TypeId this_fixture_id = this_test_info->fixture_class_id_;
+ const char* const this_test_name = this_test_info->name();
+
+ if (this_fixture_id != first_fixture_id) {
+ // Is the first test defined using TEST?
+ const bool first_is_TEST = first_fixture_id == internal::GetTestTypeId();
+ // Is this test defined using TEST?
+ const bool this_is_TEST = this_fixture_id == internal::GetTestTypeId();
+
+ if (first_is_TEST || this_is_TEST) {
+ // Both TEST and TEST_F appear in same test suite, which is incorrect.
+ // Tell the user how to fix this.
+
+ // Gets the name of the TEST and the name of the TEST_F. Note
+ // that first_is_TEST and this_is_TEST cannot both be true, as
+ // the fixture IDs are different for the two tests.
+ const char* const TEST_name =
+ first_is_TEST ? first_test_name : this_test_name;
+ const char* const TEST_F_name =
+ first_is_TEST ? this_test_name : first_test_name;
+
+ ADD_FAILURE()
+ << "All tests in the same test suite must use the same test fixture\n"
+ << "class, so mixing TEST_F and TEST in the same test suite is\n"
+ << "illegal. In test suite " << this_test_info->test_suite_name()
+ << ",\n"
+ << "test " << TEST_F_name << " is defined using TEST_F but\n"
+ << "test " << TEST_name << " is defined using TEST. You probably\n"
+ << "want to change the TEST to TEST_F or move it to another test\n"
+ << "case.";
+ } else {
+ // Two fixture classes with the same name appear in two different
+ // namespaces, which is not allowed. Tell the user how to fix this.
+ ADD_FAILURE()
+ << "All tests in the same test suite must use the same test fixture\n"
+ << "class. However, in test suite "
+ << this_test_info->test_suite_name() << ",\n"
+ << "you defined test " << first_test_name << " and test "
+ << this_test_name << "\n"
+ << "using two different test fixture classes. This can happen if\n"
+ << "the two classes are from different namespaces or translation\n"
+ << "units and have the same name. You should probably rename one\n"
+ << "of the classes to put the tests into different test suites.";
+ }
+ return false;
+ }
+
+ return true;
+}
+
+#if GTEST_HAS_SEH
+
+// Adds an "exception thrown" fatal failure to the current test. This
+// function returns its result via an output parameter pointer because VC++
+// prohibits creation of objects with destructors on stack in functions
+// using __try (see error C2712).
+static std::string* FormatSehExceptionMessage(DWORD exception_code,
+ const char* location) {
+ Message message;
+ message << "SEH exception with code 0x" << std::setbase(16) <<
+ exception_code << std::setbase(10) << " thrown in " << location << ".";
+
+ return new std::string(message.GetString());
+}
+
+#endif // GTEST_HAS_SEH
+
+namespace internal {
+
+#if GTEST_HAS_EXCEPTIONS
+
+// Adds an "exception thrown" fatal failure to the current test.
+static std::string FormatCxxExceptionMessage(const char* description,
+ const char* location) {
+ Message message;
+ if (description != nullptr) {
+ message << "C++ exception with description \"" << description << "\"";
+ } else {
+ message << "Unknown C++ exception";
+ }
+ message << " thrown in " << location << ".";
+
+ return message.GetString();
+}
+
+static std::string PrintTestPartResultToString(
+ const TestPartResult& test_part_result);
+
+GoogleTestFailureException::GoogleTestFailureException(
+ const TestPartResult& failure)
+ : ::std::runtime_error(PrintTestPartResultToString(failure).c_str()) {}
+
+#endif // GTEST_HAS_EXCEPTIONS
+
+// We put these helper functions in the internal namespace as IBM's xlC
+// compiler rejects the code if they were declared static.
+
+// Runs the given method and handles SEH exceptions it throws, when
+// SEH is supported; returns the 0-value for type Result in case of an
+// SEH exception. (Microsoft compilers cannot handle SEH and C++
+// exceptions in the same function. Therefore, we provide a separate
+// wrapper function for handling SEH exceptions.)
+template <class T, typename Result>
+Result HandleSehExceptionsInMethodIfSupported(
+ T* object, Result (T::*method)(), const char* location) {
+#if GTEST_HAS_SEH
+ __try {
+ return (object->*method)();
+ } __except (internal::UnitTestOptions::GTestShouldProcessSEH( // NOLINT
+ GetExceptionCode())) {
+ // We create the exception message on the heap because VC++ prohibits
+ // creation of objects with destructors on stack in functions using __try
+ // (see error C2712).
+ std::string* exception_message = FormatSehExceptionMessage(
+ GetExceptionCode(), location);
+ internal::ReportFailureInUnknownLocation(TestPartResult::kFatalFailure,
+ *exception_message);
+ delete exception_message;
+ return static_cast<Result>(0);
+ }
+#else
+ (void)location;
+ return (object->*method)();
+#endif // GTEST_HAS_SEH
+}
+
+// Runs the given method and catches and reports C++ and/or SEH-style
+// exceptions, if they are supported; returns the 0-value for type
+// Result in case of an SEH exception.
+template <class T, typename Result>
+Result HandleExceptionsInMethodIfSupported(
+ T* object, Result (T::*method)(), const char* location) {
+ // NOTE: The user code can affect the way in which Google Test handles
+ // exceptions by setting GTEST_FLAG(catch_exceptions), but only before
+ // RUN_ALL_TESTS() starts. It is technically possible to check the flag
+ // after the exception is caught and either report or re-throw the
+ // exception based on the flag's value:
+ //
+ // try {
+ // // Perform the test method.
+ // } catch (...) {
+ // if (GTEST_FLAG(catch_exceptions))
+ // // Report the exception as failure.
+ // else
+ // throw; // Re-throws the original exception.
+ // }
+ //
+ // However, the purpose of this flag is to allow the program to drop into
+ // the debugger when the exception is thrown. On most platforms, once the
+ // control enters the catch block, the exception origin information is
+ // lost and the debugger will stop the program at the point of the
+ // re-throw in this function -- instead of at the point of the original
+ // throw statement in the code under test. For this reason, we perform
+ // the check early, sacrificing the ability to affect Google Test's
+ // exception handling in the method where the exception is thrown.
+ if (internal::GetUnitTestImpl()->catch_exceptions()) {
+#if GTEST_HAS_EXCEPTIONS
+ try {
+ return HandleSehExceptionsInMethodIfSupported(object, method, location);
+ } catch (const AssertionException&) { // NOLINT
+ // This failure was reported already.
+ } catch (const internal::GoogleTestFailureException&) { // NOLINT
+ // This exception type can only be thrown by a failed Google
+ // Test assertion with the intention of letting another testing
+ // framework catch it. Therefore we just re-throw it.
+ throw;
+ } catch (const std::exception& e) { // NOLINT
+ internal::ReportFailureInUnknownLocation(
+ TestPartResult::kFatalFailure,
+ FormatCxxExceptionMessage(e.what(), location));
+ } catch (...) { // NOLINT
+ internal::ReportFailureInUnknownLocation(
+ TestPartResult::kFatalFailure,
+ FormatCxxExceptionMessage(nullptr, location));
+ }
+ return static_cast<Result>(0);
+#else
+ return HandleSehExceptionsInMethodIfSupported(object, method, location);
+#endif // GTEST_HAS_EXCEPTIONS
+ } else {
+ return (object->*method)();
+ }
+}
+
+} // namespace internal
+
+// Runs the test and updates the test result.
+void Test::Run() {
+ if (!HasSameFixtureClass()) return;
+
+ internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
+ impl->os_stack_trace_getter()->UponLeavingGTest();
+ internal::HandleExceptionsInMethodIfSupported(this, &Test::SetUp, "SetUp()");
+ // We will run the test only if SetUp() was successful and didn't call
+ // GTEST_SKIP().
+ if (!HasFatalFailure() && !IsSkipped()) {
+ impl->os_stack_trace_getter()->UponLeavingGTest();
+ internal::HandleExceptionsInMethodIfSupported(
+ this, &Test::TestBody, "the test body");
+ }
+
+ // However, we want to clean up as much as possible. Hence we will
+ // always call TearDown(), even if SetUp() or the test body has
+ // failed.
+ impl->os_stack_trace_getter()->UponLeavingGTest();
+ internal::HandleExceptionsInMethodIfSupported(
+ this, &Test::TearDown, "TearDown()");
+}
+
+// Returns true if and only if the current test has a fatal failure.
+bool Test::HasFatalFailure() {
+ return internal::GetUnitTestImpl()->current_test_result()->HasFatalFailure();
+}
+
+// Returns true if and only if the current test has a non-fatal failure.
+bool Test::HasNonfatalFailure() {
+ return internal::GetUnitTestImpl()->current_test_result()->
+ HasNonfatalFailure();
+}
+
+// Returns true if and only if the current test was skipped.
+bool Test::IsSkipped() {
+ return internal::GetUnitTestImpl()->current_test_result()->Skipped();
+}
+
+// class TestInfo
+
+// Constructs a TestInfo object. It assumes ownership of the test factory
+// object.
+TestInfo::TestInfo(const std::string& a_test_suite_name,
+ const std::string& a_name, const char* a_type_param,
+ const char* a_value_param,
+ internal::CodeLocation a_code_location,
+ internal::TypeId fixture_class_id,
+ internal::TestFactoryBase* factory)
+ : test_suite_name_(a_test_suite_name),
+ name_(a_name),
+ type_param_(a_type_param ? new std::string(a_type_param) : nullptr),
+ value_param_(a_value_param ? new std::string(a_value_param) : nullptr),
+ location_(a_code_location),
+ fixture_class_id_(fixture_class_id),
+ should_run_(false),
+ is_disabled_(false),
+ matches_filter_(false),
+ is_in_another_shard_(false),
+ factory_(factory),
+ result_() {}
+
+// Destructs a TestInfo object.
+TestInfo::~TestInfo() { delete factory_; }
+
+namespace internal {
+
+// Creates a new TestInfo object and registers it with Google Test;
+// returns the created object.
+//
+// Arguments:
+//
+// test_suite_name: name of the test suite
+// name: name of the test
+// type_param: the name of the test's type parameter, or NULL if
+// this is not a typed or a type-parameterized test.
+// value_param: text representation of the test's value parameter,
+// or NULL if this is not a value-parameterized test.
+// code_location: code location where the test is defined
+// fixture_class_id: ID of the test fixture class
+// set_up_tc: pointer to the function that sets up the test suite
+// tear_down_tc: pointer to the function that tears down the test suite
+// factory: pointer to the factory that creates a test object.
+// The newly created TestInfo instance will assume
+// ownership of the factory object.
+TestInfo* MakeAndRegisterTestInfo(
+ const char* test_suite_name, const char* name, const char* type_param,
+ const char* value_param, CodeLocation code_location,
+ TypeId fixture_class_id, SetUpTestSuiteFunc set_up_tc,
+ TearDownTestSuiteFunc tear_down_tc, TestFactoryBase* factory) {
+ TestInfo* const test_info =
+ new TestInfo(test_suite_name, name, type_param, value_param,
+ code_location, fixture_class_id, factory);
+ GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info);
+ return test_info;
+}
+
+void ReportInvalidTestSuiteType(const char* test_suite_name,
+ CodeLocation code_location) {
+ Message errors;
+ errors
+ << "Attempted redefinition of test suite " << test_suite_name << ".\n"
+ << "All tests in the same test suite must use the same test fixture\n"
+ << "class. However, in test suite " << test_suite_name << ", you tried\n"
+ << "to define a test using a fixture class different from the one\n"
+ << "used earlier. This can happen if the two fixture classes are\n"
+ << "from different namespaces and have the same name. You should\n"
+ << "probably rename one of the classes to put the tests into different\n"
+ << "test suites.";
+
+ GTEST_LOG_(ERROR) << FormatFileLocation(code_location.file.c_str(),
+ code_location.line)
+ << " " << errors.GetString();
+}
+} // namespace internal
+
+namespace {
+
+// A predicate that checks the test name of a TestInfo against a known
+// value.
+//
+// This is used for implementation of the TestSuite class only. We put
+// it in the anonymous namespace to prevent polluting the outer
+// namespace.
+//
+// TestNameIs is copyable.
+class TestNameIs {
+ public:
+ // Constructor.
+ //
+ // TestNameIs has NO default constructor.
+ explicit TestNameIs(const char* name)
+ : name_(name) {}
+
+ // Returns true if and only if the test name of test_info matches name_.
+ bool operator()(const TestInfo * test_info) const {
+ return test_info && test_info->name() == name_;
+ }
+
+ private:
+ std::string name_;
+};
+
+} // namespace
+
+namespace internal {
+
+// This method expands all parameterized tests registered with macros TEST_P
+// and INSTANTIATE_TEST_SUITE_P into regular tests and registers those.
+// This will be done just once during the program runtime.
+void UnitTestImpl::RegisterParameterizedTests() {
+ if (!parameterized_tests_registered_) {
+ parameterized_test_registry_.RegisterTests();
+ type_parameterized_test_registry_.CheckForInstantiations();
+ parameterized_tests_registered_ = true;
+ }
+}
+
+} // namespace internal
+
+// Creates the test object, runs it, records its result, and then
+// deletes it.
+void TestInfo::Run() {
+ if (!should_run_) return;
+
+ // Tells UnitTest where to store test result.
+ internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
+ impl->set_current_test_info(this);
+
+ TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater();
+
+ // Notifies the unit test event listeners that a test is about to start.
+ repeater->OnTestStart(*this);
+
+ result_.set_start_timestamp(internal::GetTimeInMillis());
+ internal::Timer timer;
+
+ impl->os_stack_trace_getter()->UponLeavingGTest();
+
+ // Creates the test object.
+ Test* const test = internal::HandleExceptionsInMethodIfSupported(
+ factory_, &internal::TestFactoryBase::CreateTest,
+ "the test fixture's constructor");
+
+ // Runs the test if the constructor didn't generate a fatal failure or invoke
+ // GTEST_SKIP().
+ // Note that the object will not be null
+ if (!Test::HasFatalFailure() && !Test::IsSkipped()) {
+ // This doesn't throw as all user code that can throw are wrapped into
+ // exception handling code.
+ test->Run();
+ }
+
+ if (test != nullptr) {
+ // Deletes the test object.
+ impl->os_stack_trace_getter()->UponLeavingGTest();
+ internal::HandleExceptionsInMethodIfSupported(
+ test, &Test::DeleteSelf_, "the test fixture's destructor");
+ }
+
+ result_.set_elapsed_time(timer.Elapsed());
+
+ // Notifies the unit test event listener that a test has just finished.
+ repeater->OnTestEnd(*this);
+
+ // Tells UnitTest to stop associating assertion results to this
+ // test.
+ impl->set_current_test_info(nullptr);
+}
+
+// Skip and records a skipped test result for this object.
+void TestInfo::Skip() {
+ if (!should_run_) return;
+
+ internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
+ impl->set_current_test_info(this);
+
+ TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater();
+
+ // Notifies the unit test event listeners that a test is about to start.
+ repeater->OnTestStart(*this);
+
+ const TestPartResult test_part_result =
+ TestPartResult(TestPartResult::kSkip, this->file(), this->line(), "");
+ impl->GetTestPartResultReporterForCurrentThread()->ReportTestPartResult(
+ test_part_result);
+
+ // Notifies the unit test event listener that a test has just finished.
+ repeater->OnTestEnd(*this);
+ impl->set_current_test_info(nullptr);
+}
+
+// class TestSuite
+
+// Gets the number of successful tests in this test suite.
+int TestSuite::successful_test_count() const {
+ return CountIf(test_info_list_, TestPassed);
+}
+
+// Gets the number of successful tests in this test suite.
+int TestSuite::skipped_test_count() const {
+ return CountIf(test_info_list_, TestSkipped);
+}
+
+// Gets the number of failed tests in this test suite.
+int TestSuite::failed_test_count() const {
+ return CountIf(test_info_list_, TestFailed);
+}
+
+// Gets the number of disabled tests that will be reported in the XML report.
+int TestSuite::reportable_disabled_test_count() const {
+ return CountIf(test_info_list_, TestReportableDisabled);
+}
+
+// Gets the number of disabled tests in this test suite.
+int TestSuite::disabled_test_count() const {
+ return CountIf(test_info_list_, TestDisabled);
+}
+
+// Gets the number of tests to be printed in the XML report.
+int TestSuite::reportable_test_count() const {
+ return CountIf(test_info_list_, TestReportable);
+}
+
+// Get the number of tests in this test suite that should run.
+int TestSuite::test_to_run_count() const {
+ return CountIf(test_info_list_, ShouldRunTest);
+}
+
+// Gets the number of all tests.
+int TestSuite::total_test_count() const {
+ return static_cast<int>(test_info_list_.size());
+}
+
+// Creates a TestSuite with the given name.
+//
+// Arguments:
+//
+// a_name: name of the test suite
+// a_type_param: the name of the test suite's type parameter, or NULL if
+// this is not a typed or a type-parameterized test suite.
+// set_up_tc: pointer to the function that sets up the test suite
+// tear_down_tc: pointer to the function that tears down the test suite
+TestSuite::TestSuite(const char* a_name, const char* a_type_param,
+ internal::SetUpTestSuiteFunc set_up_tc,
+ internal::TearDownTestSuiteFunc tear_down_tc)
+ : name_(a_name),
+ type_param_(a_type_param ? new std::string(a_type_param) : nullptr),
+ set_up_tc_(set_up_tc),
+ tear_down_tc_(tear_down_tc),
+ should_run_(false),
+ start_timestamp_(0),
+ elapsed_time_(0) {}
+
+// Destructor of TestSuite.
+TestSuite::~TestSuite() {
+ // Deletes every Test in the collection.
+ ForEach(test_info_list_, internal::Delete<TestInfo>);
+}
+
+// Returns the i-th test among all the tests. i can range from 0 to
+// total_test_count() - 1. If i is not in that range, returns NULL.
+const TestInfo* TestSuite::GetTestInfo(int i) const {
+ const int index = GetElementOr(test_indices_, i, -1);
+ return index < 0 ? nullptr : test_info_list_[static_cast<size_t>(index)];
+}
+
+// Returns the i-th test among all the tests. i can range from 0 to
+// total_test_count() - 1. If i is not in that range, returns NULL.
+TestInfo* TestSuite::GetMutableTestInfo(int i) {
+ const int index = GetElementOr(test_indices_, i, -1);
+ return index < 0 ? nullptr : test_info_list_[static_cast<size_t>(index)];
+}
+
+// Adds a test to this test suite. Will delete the test upon
+// destruction of the TestSuite object.
+void TestSuite::AddTestInfo(TestInfo* test_info) {
+ test_info_list_.push_back(test_info);
+ test_indices_.push_back(static_cast<int>(test_indices_.size()));
+}
+
+// Runs every test in this TestSuite.
+void TestSuite::Run() {
+ if (!should_run_) return;
+
+ internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
+ impl->set_current_test_suite(this);
+
+ TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater();
+
+ // Call both legacy and the new API
+ repeater->OnTestSuiteStart(*this);
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ repeater->OnTestCaseStart(*this);
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+ impl->os_stack_trace_getter()->UponLeavingGTest();
+ internal::HandleExceptionsInMethodIfSupported(
+ this, &TestSuite::RunSetUpTestSuite, "SetUpTestSuite()");
+
+ start_timestamp_ = internal::GetTimeInMillis();
+ internal::Timer timer;
+ for (int i = 0; i < total_test_count(); i++) {
+ GetMutableTestInfo(i)->Run();
+ if (GTEST_FLAG(fail_fast) && GetMutableTestInfo(i)->result()->Failed()) {
+ for (int j = i + 1; j < total_test_count(); j++) {
+ GetMutableTestInfo(j)->Skip();
+ }
+ break;
+ }
+ }
+ elapsed_time_ = timer.Elapsed();
+
+ impl->os_stack_trace_getter()->UponLeavingGTest();
+ internal::HandleExceptionsInMethodIfSupported(
+ this, &TestSuite::RunTearDownTestSuite, "TearDownTestSuite()");
+
+ // Call both legacy and the new API
+ repeater->OnTestSuiteEnd(*this);
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ repeater->OnTestCaseEnd(*this);
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+ impl->set_current_test_suite(nullptr);
+}
+
+// Skips all tests under this TestSuite.
+void TestSuite::Skip() {
+ if (!should_run_) return;
+
+ internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
+ impl->set_current_test_suite(this);
+
+ TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater();
+
+ // Call both legacy and the new API
+ repeater->OnTestSuiteStart(*this);
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ repeater->OnTestCaseStart(*this);
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+ for (int i = 0; i < total_test_count(); i++) {
+ GetMutableTestInfo(i)->Skip();
+ }
+
+ // Call both legacy and the new API
+ repeater->OnTestSuiteEnd(*this);
+ // Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ repeater->OnTestCaseEnd(*this);
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+ impl->set_current_test_suite(nullptr);
+}
+
+// Clears the results of all tests in this test suite.
+void TestSuite::ClearResult() {
+ ad_hoc_test_result_.Clear();
+ ForEach(test_info_list_, TestInfo::ClearTestResult);
+}
+
+// Shuffles the tests in this test suite.
+void TestSuite::ShuffleTests(internal::Random* random) {
+ Shuffle(random, &test_indices_);
+}
+
+// Restores the test order to before the first shuffle.
+void TestSuite::UnshuffleTests() {
+ for (size_t i = 0; i < test_indices_.size(); i++) {
+ test_indices_[i] = static_cast<int>(i);
+ }
+}
+
+// Formats a countable noun. Depending on its quantity, either the
+// singular form or the plural form is used. e.g.
+//
+// FormatCountableNoun(1, "formula", "formuli") returns "1 formula".
+// FormatCountableNoun(5, "book", "books") returns "5 books".
+static std::string FormatCountableNoun(int count,
+ const char * singular_form,
+ const char * plural_form) {
+ return internal::StreamableToString(count) + " " +
+ (count == 1 ? singular_form : plural_form);
+}
+
+// Formats the count of tests.
+static std::string FormatTestCount(int test_count) {
+ return FormatCountableNoun(test_count, "test", "tests");
+}
+
+// Formats the count of test suites.
+static std::string FormatTestSuiteCount(int test_suite_count) {
+ return FormatCountableNoun(test_suite_count, "test suite", "test suites");
+}
+
+// Converts a TestPartResult::Type enum to human-friendly string
+// representation. Both kNonFatalFailure and kFatalFailure are translated
+// to "Failure", as the user usually doesn't care about the difference
+// between the two when viewing the test result.
+static const char * TestPartResultTypeToString(TestPartResult::Type type) {
+ switch (type) {
+ case TestPartResult::kSkip:
+ return "Skipped\n";
+ case TestPartResult::kSuccess:
+ return "Success";
+
+ case TestPartResult::kNonFatalFailure:
+ case TestPartResult::kFatalFailure:
+#ifdef _MSC_VER
+ return "error: ";
+#else
+ return "Failure\n";
+#endif
+ default:
+ return "Unknown result type";
+ }
+}
+
+namespace internal {
+namespace {
+enum class GTestColor { kDefault, kRed, kGreen, kYellow };
+} // namespace
+
+// Prints a TestPartResult to an std::string.
+static std::string PrintTestPartResultToString(
+ const TestPartResult& test_part_result) {
+ return (Message()
+ << internal::FormatFileLocation(test_part_result.file_name(),
+ test_part_result.line_number())
+ << " " << TestPartResultTypeToString(test_part_result.type())
+ << test_part_result.message()).GetString();
+}
+
+// Prints a TestPartResult.
+static void PrintTestPartResult(const TestPartResult& test_part_result) {
+ const std::string& result =
+ PrintTestPartResultToString(test_part_result);
+ printf("%s\n", result.c_str());
+ fflush(stdout);
+ // If the test program runs in Visual Studio or a debugger, the
+ // following statements add the test part result message to the Output
+ // window such that the user can double-click on it to jump to the
+ // corresponding source code location; otherwise they do nothing.
+#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE
+ // We don't call OutputDebugString*() on Windows Mobile, as printing
+ // to stdout is done by OutputDebugString() there already - we don't
+ // want the same message printed twice.
+ ::OutputDebugStringA(result.c_str());
+ ::OutputDebugStringA("\n");
+#endif
+}
+
+// class PrettyUnitTestResultPrinter
+#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE && \
+ !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT && !GTEST_OS_WINDOWS_MINGW
+
+// Returns the character attribute for the given color.
+static WORD GetColorAttribute(GTestColor color) {
+ switch (color) {
+ case GTestColor::kRed:
+ return FOREGROUND_RED;
+ case GTestColor::kGreen:
+ return FOREGROUND_GREEN;
+ case GTestColor::kYellow:
+ return FOREGROUND_RED | FOREGROUND_GREEN;
+ default: return 0;
+ }
+}
+
+static int GetBitOffset(WORD color_mask) {
+ if (color_mask == 0) return 0;
+
+ int bitOffset = 0;
+ while ((color_mask & 1) == 0) {
+ color_mask >>= 1;
+ ++bitOffset;
+ }
+ return bitOffset;
+}
+
+static WORD GetNewColor(GTestColor color, WORD old_color_attrs) {
+ // Let's reuse the BG
+ static const WORD background_mask = BACKGROUND_BLUE | BACKGROUND_GREEN |
+ BACKGROUND_RED | BACKGROUND_INTENSITY;
+ static const WORD foreground_mask = FOREGROUND_BLUE | FOREGROUND_GREEN |
+ FOREGROUND_RED | FOREGROUND_INTENSITY;
+ const WORD existing_bg = old_color_attrs & background_mask;
+
+ WORD new_color =
+ GetColorAttribute(color) | existing_bg | FOREGROUND_INTENSITY;
+ static const int bg_bitOffset = GetBitOffset(background_mask);
+ static const int fg_bitOffset = GetBitOffset(foreground_mask);
+
+ if (((new_color & background_mask) >> bg_bitOffset) ==
+ ((new_color & foreground_mask) >> fg_bitOffset)) {
+ new_color ^= FOREGROUND_INTENSITY; // invert intensity
+ }
+ return new_color;
+}
+
+#else
+
+// Returns the ANSI color code for the given color. GTestColor::kDefault is
+// an invalid input.
+static const char* GetAnsiColorCode(GTestColor color) {
+ switch (color) {
+ case GTestColor::kRed:
+ return "1";
+ case GTestColor::kGreen:
+ return "2";
+ case GTestColor::kYellow:
+ return "3";
+ default:
+ return nullptr;
+ }
+}
+
+#endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE
+
+// Returns true if and only if Google Test should use colors in the output.
+bool ShouldUseColor(bool stdout_is_tty) {
+ const char* const gtest_color = GTEST_FLAG(color).c_str();
+
+ if (String::CaseInsensitiveCStringEquals(gtest_color, "auto")) {
+#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MINGW
+ // On Windows the TERM variable is usually not set, but the
+ // console there does support colors.
+ return stdout_is_tty;
+#else
+ // On non-Windows platforms, we rely on the TERM variable.
+ const char* const term = posix::GetEnv("TERM");
+ const bool term_supports_color =
+ String::CStringEquals(term, "xterm") ||
+ String::CStringEquals(term, "xterm-color") ||
+ String::CStringEquals(term, "xterm-256color") ||
+ String::CStringEquals(term, "screen") ||
+ String::CStringEquals(term, "screen-256color") ||
+ String::CStringEquals(term, "tmux") ||
+ String::CStringEquals(term, "tmux-256color") ||
+ String::CStringEquals(term, "rxvt-unicode") ||
+ String::CStringEquals(term, "rxvt-unicode-256color") ||
+ String::CStringEquals(term, "linux") ||
+ String::CStringEquals(term, "cygwin");
+ return stdout_is_tty && term_supports_color;
+#endif // GTEST_OS_WINDOWS
+ }
+
+ return String::CaseInsensitiveCStringEquals(gtest_color, "yes") ||
+ String::CaseInsensitiveCStringEquals(gtest_color, "true") ||
+ String::CaseInsensitiveCStringEquals(gtest_color, "t") ||
+ String::CStringEquals(gtest_color, "1");
+ // We take "yes", "true", "t", and "1" as meaning "yes". If the
+ // value is neither one of these nor "auto", we treat it as "no" to
+ // be conservative.
+}
+
+// Helpers for printing colored strings to stdout. Note that on Windows, we
+// cannot simply emit special characters and have the terminal change colors.
+// This routine must actually emit the characters rather than return a string
+// that would be colored when printed, as can be done on Linux.
+
+GTEST_ATTRIBUTE_PRINTF_(2, 3)
+static void ColoredPrintf(GTestColor color, const char *fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+
+#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_ZOS || GTEST_OS_IOS || \
+ GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT || defined(ESP_PLATFORM)
+ const bool use_color = AlwaysFalse();
+#else
+ static const bool in_color_mode =
+ ShouldUseColor(posix::IsATTY(posix::FileNo(stdout)) != 0);
+ const bool use_color = in_color_mode && (color != GTestColor::kDefault);
+#endif // GTEST_OS_WINDOWS_MOBILE || GTEST_OS_ZOS
+
+ if (!use_color) {
+ vprintf(fmt, args);
+ va_end(args);
+ return;
+ }
+
+#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE && \
+ !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT && !GTEST_OS_WINDOWS_MINGW
+ const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE);
+
+ // Gets the current text color.
+ CONSOLE_SCREEN_BUFFER_INFO buffer_info;
+ GetConsoleScreenBufferInfo(stdout_handle, &buffer_info);
+ const WORD old_color_attrs = buffer_info.wAttributes;
+ const WORD new_color = GetNewColor(color, old_color_attrs);
+
+ // We need to flush the stream buffers into the console before each
+ // SetConsoleTextAttribute call lest it affect the text that is already
+ // printed but has not yet reached the console.
+ fflush(stdout);
+ SetConsoleTextAttribute(stdout_handle, new_color);
+
+ vprintf(fmt, args);
+
+ fflush(stdout);
+ // Restores the text color.
+ SetConsoleTextAttribute(stdout_handle, old_color_attrs);
+#else
+ printf("\033[0;3%sm", GetAnsiColorCode(color));
+ vprintf(fmt, args);
+ printf("\033[m"); // Resets the terminal to default.
+#endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE
+ va_end(args);
+}
+
+// Text printed in Google Test's text output and --gtest_list_tests
+// output to label the type parameter and value parameter for a test.
+static const char kTypeParamLabel[] = "TypeParam";
+static const char kValueParamLabel[] = "GetParam()";
+
+static void PrintFullTestCommentIfPresent(const TestInfo& test_info) {
+ const char* const type_param = test_info.type_param();
+ const char* const value_param = test_info.value_param();
+
+ if (type_param != nullptr || value_param != nullptr) {
+ printf(", where ");
+ if (type_param != nullptr) {
+ printf("%s = %s", kTypeParamLabel, type_param);
+ if (value_param != nullptr) printf(" and ");
+ }
+ if (value_param != nullptr) {
+ printf("%s = %s", kValueParamLabel, value_param);
+ }
+ }
+}
+
+// This class implements the TestEventListener interface.
+//
+// Class PrettyUnitTestResultPrinter is copyable.
+class PrettyUnitTestResultPrinter : public TestEventListener {
+ public:
+ PrettyUnitTestResultPrinter() {}
+ static void PrintTestName(const char* test_suite, const char* test) {
+ printf("%s.%s", test_suite, test);
+ }
+
+ // The following methods override what's in the TestEventListener class.
+ void OnTestProgramStart(const UnitTest& /*unit_test*/) override {}
+ void OnTestIterationStart(const UnitTest& unit_test, int iteration) override;
+ void OnEnvironmentsSetUpStart(const UnitTest& unit_test) override;
+ void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) override {}
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ void OnTestCaseStart(const TestCase& test_case) override;
+#else
+ void OnTestSuiteStart(const TestSuite& test_suite) override;
+#endif // OnTestCaseStart
+
+ void OnTestStart(const TestInfo& test_info) override;
+
+ void OnTestPartResult(const TestPartResult& result) override;
+ void OnTestEnd(const TestInfo& test_info) override;
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ void OnTestCaseEnd(const TestCase& test_case) override;
+#else
+ void OnTestSuiteEnd(const TestSuite& test_suite) override;
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+ void OnEnvironmentsTearDownStart(const UnitTest& unit_test) override;
+ void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) override {}
+ void OnTestIterationEnd(const UnitTest& unit_test, int iteration) override;
+ void OnTestProgramEnd(const UnitTest& /*unit_test*/) override {}
+
+ private:
+ static void PrintFailedTests(const UnitTest& unit_test);
+ static void PrintFailedTestSuites(const UnitTest& unit_test);
+ static void PrintSkippedTests(const UnitTest& unit_test);
+};
+
+ // Fired before each iteration of tests starts.
+void PrettyUnitTestResultPrinter::OnTestIterationStart(
+ const UnitTest& unit_test, int iteration) {
+ if (GTEST_FLAG(repeat) != 1)
+ printf("\nRepeating all tests (iteration %d) . . .\n\n", iteration + 1);
+
+ const char* const filter = GTEST_FLAG(filter).c_str();
+
+ // Prints the filter if it's not *. This reminds the user that some
+ // tests may be skipped.
+ if (!String::CStringEquals(filter, kUniversalFilter)) {
+ ColoredPrintf(GTestColor::kYellow, "Note: %s filter = %s\n", GTEST_NAME_,
+ filter);
+ }
+
+ if (internal::ShouldShard(kTestTotalShards, kTestShardIndex, false)) {
+ const int32_t shard_index = Int32FromEnvOrDie(kTestShardIndex, -1);
+ ColoredPrintf(GTestColor::kYellow, "Note: This is test shard %d of %s.\n",
+ static_cast<int>(shard_index) + 1,
+ internal::posix::GetEnv(kTestTotalShards));
+ }
+
+ if (GTEST_FLAG(shuffle)) {
+ ColoredPrintf(GTestColor::kYellow,
+ "Note: Randomizing tests' orders with a seed of %d .\n",
+ unit_test.random_seed());
+ }
+
+ ColoredPrintf(GTestColor::kGreen, "[==========] ");
+ printf("Running %s from %s.\n",
+ FormatTestCount(unit_test.test_to_run_count()).c_str(),
+ FormatTestSuiteCount(unit_test.test_suite_to_run_count()).c_str());
+ fflush(stdout);
+}
+
+void PrettyUnitTestResultPrinter::OnEnvironmentsSetUpStart(
+ const UnitTest& /*unit_test*/) {
+ ColoredPrintf(GTestColor::kGreen, "[----------] ");
+ printf("Global test environment set-up.\n");
+ fflush(stdout);
+}
+
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+void PrettyUnitTestResultPrinter::OnTestCaseStart(const TestCase& test_case) {
+ const std::string counts =
+ FormatCountableNoun(test_case.test_to_run_count(), "test", "tests");
+ ColoredPrintf(GTestColor::kGreen, "[----------] ");
+ printf("%s from %s", counts.c_str(), test_case.name());
+ if (test_case.type_param() == nullptr) {
+ printf("\n");
+ } else {
+ printf(", where %s = %s\n", kTypeParamLabel, test_case.type_param());
+ }
+ fflush(stdout);
+}
+#else
+void PrettyUnitTestResultPrinter::OnTestSuiteStart(
+ const TestSuite& test_suite) {
+ const std::string counts =
+ FormatCountableNoun(test_suite.test_to_run_count(), "test", "tests");
+ ColoredPrintf(GTestColor::kGreen, "[----------] ");
+ printf("%s from %s", counts.c_str(), test_suite.name());
+ if (test_suite.type_param() == nullptr) {
+ printf("\n");
+ } else {
+ printf(", where %s = %s\n", kTypeParamLabel, test_suite.type_param());
+ }
+ fflush(stdout);
+}
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo& test_info) {
+ ColoredPrintf(GTestColor::kGreen, "[ RUN ] ");
+ PrintTestName(test_info.test_suite_name(), test_info.name());
+ printf("\n");
+ fflush(stdout);
+}
+
+// Called after an assertion failure.
+void PrettyUnitTestResultPrinter::OnTestPartResult(
+ const TestPartResult& result) {
+ switch (result.type()) {
+ // If the test part succeeded, we don't need to do anything.
+ case TestPartResult::kSuccess:
+ return;
+ default:
+ // Print failure message from the assertion
+ // (e.g. expected this and got that).
+ PrintTestPartResult(result);
+ fflush(stdout);
+ }
+}
+
+void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo& test_info) {
+ if (test_info.result()->Passed()) {
+ ColoredPrintf(GTestColor::kGreen, "[ OK ] ");
+ } else if (test_info.result()->Skipped()) {
+ ColoredPrintf(GTestColor::kGreen, "[ SKIPPED ] ");
+ } else {
+ ColoredPrintf(GTestColor::kRed, "[ FAILED ] ");
+ }
+ PrintTestName(test_info.test_suite_name(), test_info.name());
+ if (test_info.result()->Failed())
+ PrintFullTestCommentIfPresent(test_info);
+
+ if (GTEST_FLAG(print_time)) {
+ printf(" (%s ms)\n", internal::StreamableToString(
+ test_info.result()->elapsed_time()).c_str());
+ } else {
+ printf("\n");
+ }
+ fflush(stdout);
+}
+
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+void PrettyUnitTestResultPrinter::OnTestCaseEnd(const TestCase& test_case) {
+ if (!GTEST_FLAG(print_time)) return;
+
+ const std::string counts =
+ FormatCountableNoun(test_case.test_to_run_count(), "test", "tests");
+ ColoredPrintf(GTestColor::kGreen, "[----------] ");
+ printf("%s from %s (%s ms total)\n\n", counts.c_str(), test_case.name(),
+ internal::StreamableToString(test_case.elapsed_time()).c_str());
+ fflush(stdout);
+}
+#else
+void PrettyUnitTestResultPrinter::OnTestSuiteEnd(const TestSuite& test_suite) {
+ if (!GTEST_FLAG(print_time)) return;
+
+ const std::string counts =
+ FormatCountableNoun(test_suite.test_to_run_count(), "test", "tests");
+ ColoredPrintf(GTestColor::kGreen, "[----------] ");
+ printf("%s from %s (%s ms total)\n\n", counts.c_str(), test_suite.name(),
+ internal::StreamableToString(test_suite.elapsed_time()).c_str());
+ fflush(stdout);
+}
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+void PrettyUnitTestResultPrinter::OnEnvironmentsTearDownStart(
+ const UnitTest& /*unit_test*/) {
+ ColoredPrintf(GTestColor::kGreen, "[----------] ");
+ printf("Global test environment tear-down\n");
+ fflush(stdout);
+}
+
+// Internal helper for printing the list of failed tests.
+void PrettyUnitTestResultPrinter::PrintFailedTests(const UnitTest& unit_test) {
+ const int failed_test_count = unit_test.failed_test_count();
+ ColoredPrintf(GTestColor::kRed, "[ FAILED ] ");
+ printf("%s, listed below:\n", FormatTestCount(failed_test_count).c_str());
+
+ for (int i = 0; i < unit_test.total_test_suite_count(); ++i) {
+ const TestSuite& test_suite = *unit_test.GetTestSuite(i);
+ if (!test_suite.should_run() || (test_suite.failed_test_count() == 0)) {
+ continue;
+ }
+ for (int j = 0; j < test_suite.total_test_count(); ++j) {
+ const TestInfo& test_info = *test_suite.GetTestInfo(j);
+ if (!test_info.should_run() || !test_info.result()->Failed()) {
+ continue;
+ }
+ ColoredPrintf(GTestColor::kRed, "[ FAILED ] ");
+ printf("%s.%s", test_suite.name(), test_info.name());
+ PrintFullTestCommentIfPresent(test_info);
+ printf("\n");
+ }
+ }
+ printf("\n%2d FAILED %s\n", failed_test_count,
+ failed_test_count == 1 ? "TEST" : "TESTS");
+}
+
+// Internal helper for printing the list of test suite failures not covered by
+// PrintFailedTests.
+void PrettyUnitTestResultPrinter::PrintFailedTestSuites(
+ const UnitTest& unit_test) {
+ int suite_failure_count = 0;
+ for (int i = 0; i < unit_test.total_test_suite_count(); ++i) {
+ const TestSuite& test_suite = *unit_test.GetTestSuite(i);
+ if (!test_suite.should_run()) {
+ continue;
+ }
+ if (test_suite.ad_hoc_test_result().Failed()) {
+ ColoredPrintf(GTestColor::kRed, "[ FAILED ] ");
+ printf("%s: SetUpTestSuite or TearDownTestSuite\n", test_suite.name());
+ ++suite_failure_count;
+ }
+ }
+ if (suite_failure_count > 0) {
+ printf("\n%2d FAILED TEST %s\n", suite_failure_count,
+ suite_failure_count == 1 ? "SUITE" : "SUITES");
+ }
+}
+
+// Internal helper for printing the list of skipped tests.
+void PrettyUnitTestResultPrinter::PrintSkippedTests(const UnitTest& unit_test) {
+ const int skipped_test_count = unit_test.skipped_test_count();
+ if (skipped_test_count == 0) {
+ return;
+ }
+
+ for (int i = 0; i < unit_test.total_test_suite_count(); ++i) {
+ const TestSuite& test_suite = *unit_test.GetTestSuite(i);
+ if (!test_suite.should_run() || (test_suite.skipped_test_count() == 0)) {
+ continue;
+ }
+ for (int j = 0; j < test_suite.total_test_count(); ++j) {
+ const TestInfo& test_info = *test_suite.GetTestInfo(j);
+ if (!test_info.should_run() || !test_info.result()->Skipped()) {
+ continue;
+ }
+ ColoredPrintf(GTestColor::kGreen, "[ SKIPPED ] ");
+ printf("%s.%s", test_suite.name(), test_info.name());
+ printf("\n");
+ }
+ }
+}
+
+void PrettyUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test,
+ int /*iteration*/) {
+ ColoredPrintf(GTestColor::kGreen, "[==========] ");
+ printf("%s from %s ran.",
+ FormatTestCount(unit_test.test_to_run_count()).c_str(),
+ FormatTestSuiteCount(unit_test.test_suite_to_run_count()).c_str());
+ if (GTEST_FLAG(print_time)) {
+ printf(" (%s ms total)",
+ internal::StreamableToString(unit_test.elapsed_time()).c_str());
+ }
+ printf("\n");
+ ColoredPrintf(GTestColor::kGreen, "[ PASSED ] ");
+ printf("%s.\n", FormatTestCount(unit_test.successful_test_count()).c_str());
+
+ const int skipped_test_count = unit_test.skipped_test_count();
+ if (skipped_test_count > 0) {
+ ColoredPrintf(GTestColor::kGreen, "[ SKIPPED ] ");
+ printf("%s, listed below:\n", FormatTestCount(skipped_test_count).c_str());
+ PrintSkippedTests(unit_test);
+ }
+
+ if (!unit_test.Passed()) {
+ PrintFailedTests(unit_test);
+ PrintFailedTestSuites(unit_test);
+ }
+
+ int num_disabled = unit_test.reportable_disabled_test_count();
+ if (num_disabled && !GTEST_FLAG(also_run_disabled_tests)) {
+ if (unit_test.Passed()) {
+ printf("\n"); // Add a spacer if no FAILURE banner is displayed.
+ }
+ ColoredPrintf(GTestColor::kYellow, " YOU HAVE %d DISABLED %s\n\n",
+ num_disabled, num_disabled == 1 ? "TEST" : "TESTS");
+ }
+ // Ensure that Google Test output is printed before, e.g., heapchecker output.
+ fflush(stdout);
+}
+
+// End PrettyUnitTestResultPrinter
+
+// This class implements the TestEventListener interface.
+//
+// Class BriefUnitTestResultPrinter is copyable.
+class BriefUnitTestResultPrinter : public TestEventListener {
+ public:
+ BriefUnitTestResultPrinter() {}
+ static void PrintTestName(const char* test_suite, const char* test) {
+ printf("%s.%s", test_suite, test);
+ }
+
+ // The following methods override what's in the TestEventListener class.
+ void OnTestProgramStart(const UnitTest& /*unit_test*/) override {}
+ void OnTestIterationStart(const UnitTest& /*unit_test*/,
+ int /*iteration*/) override {}
+ void OnEnvironmentsSetUpStart(const UnitTest& /*unit_test*/) override {}
+ void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) override {}
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ void OnTestCaseStart(const TestCase& /*test_case*/) override {}
+#else
+ void OnTestSuiteStart(const TestSuite& /*test_suite*/) override {}
+#endif // OnTestCaseStart
+
+ void OnTestStart(const TestInfo& /*test_info*/) override {}
+
+ void OnTestPartResult(const TestPartResult& result) override;
+ void OnTestEnd(const TestInfo& test_info) override;
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ void OnTestCaseEnd(const TestCase& /*test_case*/) override {}
+#else
+ void OnTestSuiteEnd(const TestSuite& /*test_suite*/) override {}
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+ void OnEnvironmentsTearDownStart(const UnitTest& /*unit_test*/) override {}
+ void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) override {}
+ void OnTestIterationEnd(const UnitTest& unit_test, int iteration) override;
+ void OnTestProgramEnd(const UnitTest& /*unit_test*/) override {}
+};
+
+// Called after an assertion failure.
+void BriefUnitTestResultPrinter::OnTestPartResult(
+ const TestPartResult& result) {
+ switch (result.type()) {
+ // If the test part succeeded, we don't need to do anything.
+ case TestPartResult::kSuccess:
+ return;
+ default:
+ // Print failure message from the assertion
+ // (e.g. expected this and got that).
+ PrintTestPartResult(result);
+ fflush(stdout);
+ }
+}
+
+void BriefUnitTestResultPrinter::OnTestEnd(const TestInfo& test_info) {
+ if (test_info.result()->Failed()) {
+ ColoredPrintf(GTestColor::kRed, "[ FAILED ] ");
+ PrintTestName(test_info.test_suite_name(), test_info.name());
+ PrintFullTestCommentIfPresent(test_info);
+
+ if (GTEST_FLAG(print_time)) {
+ printf(" (%s ms)\n",
+ internal::StreamableToString(test_info.result()->elapsed_time())
+ .c_str());
+ } else {
+ printf("\n");
+ }
+ fflush(stdout);
+ }
+}
+
+void BriefUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test,
+ int /*iteration*/) {
+ ColoredPrintf(GTestColor::kGreen, "[==========] ");
+ printf("%s from %s ran.",
+ FormatTestCount(unit_test.test_to_run_count()).c_str(),
+ FormatTestSuiteCount(unit_test.test_suite_to_run_count()).c_str());
+ if (GTEST_FLAG(print_time)) {
+ printf(" (%s ms total)",
+ internal::StreamableToString(unit_test.elapsed_time()).c_str());
+ }
+ printf("\n");
+ ColoredPrintf(GTestColor::kGreen, "[ PASSED ] ");
+ printf("%s.\n", FormatTestCount(unit_test.successful_test_count()).c_str());
+
+ const int skipped_test_count = unit_test.skipped_test_count();
+ if (skipped_test_count > 0) {
+ ColoredPrintf(GTestColor::kGreen, "[ SKIPPED ] ");
+ printf("%s.\n", FormatTestCount(skipped_test_count).c_str());
+ }
+
+ int num_disabled = unit_test.reportable_disabled_test_count();
+ if (num_disabled && !GTEST_FLAG(also_run_disabled_tests)) {
+ if (unit_test.Passed()) {
+ printf("\n"); // Add a spacer if no FAILURE banner is displayed.
+ }
+ ColoredPrintf(GTestColor::kYellow, " YOU HAVE %d DISABLED %s\n\n",
+ num_disabled, num_disabled == 1 ? "TEST" : "TESTS");
+ }
+ // Ensure that Google Test output is printed before, e.g., heapchecker output.
+ fflush(stdout);
+}
+
+// End BriefUnitTestResultPrinter
+
+// class TestEventRepeater
+//
+// This class forwards events to other event listeners.
+class TestEventRepeater : public TestEventListener {
+ public:
+ TestEventRepeater() : forwarding_enabled_(true) {}
+ ~TestEventRepeater() override;
+ void Append(TestEventListener *listener);
+ TestEventListener* Release(TestEventListener* listener);
+
+ // Controls whether events will be forwarded to listeners_. Set to false
+ // in death test child processes.
+ bool forwarding_enabled() const { return forwarding_enabled_; }
+ void set_forwarding_enabled(bool enable) { forwarding_enabled_ = enable; }
+
+ void OnTestProgramStart(const UnitTest& unit_test) override;
+ void OnTestIterationStart(const UnitTest& unit_test, int iteration) override;
+ void OnEnvironmentsSetUpStart(const UnitTest& unit_test) override;
+ void OnEnvironmentsSetUpEnd(const UnitTest& unit_test) override;
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ void OnTestCaseStart(const TestSuite& parameter) override;
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ void OnTestSuiteStart(const TestSuite& parameter) override;
+ void OnTestStart(const TestInfo& test_info) override;
+ void OnTestPartResult(const TestPartResult& result) override;
+ void OnTestEnd(const TestInfo& test_info) override;
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ void OnTestCaseEnd(const TestCase& parameter) override;
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ void OnTestSuiteEnd(const TestSuite& parameter) override;
+ void OnEnvironmentsTearDownStart(const UnitTest& unit_test) override;
+ void OnEnvironmentsTearDownEnd(const UnitTest& unit_test) override;
+ void OnTestIterationEnd(const UnitTest& unit_test, int iteration) override;
+ void OnTestProgramEnd(const UnitTest& unit_test) override;
+
+ private:
+ // Controls whether events will be forwarded to listeners_. Set to false
+ // in death test child processes.
+ bool forwarding_enabled_;
+ // The list of listeners that receive events.
+ std::vector<TestEventListener*> listeners_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventRepeater);
+};
+
+TestEventRepeater::~TestEventRepeater() {
+ ForEach(listeners_, Delete<TestEventListener>);
+}
+
+void TestEventRepeater::Append(TestEventListener *listener) {
+ listeners_.push_back(listener);
+}
+
+TestEventListener* TestEventRepeater::Release(TestEventListener *listener) {
+ for (size_t i = 0; i < listeners_.size(); ++i) {
+ if (listeners_[i] == listener) {
+ listeners_.erase(listeners_.begin() + static_cast<int>(i));
+ return listener;
+ }
+ }
+
+ return nullptr;
+}
+
+// Since most methods are very similar, use macros to reduce boilerplate.
+// This defines a member that forwards the call to all listeners.
+#define GTEST_REPEATER_METHOD_(Name, Type) \
+void TestEventRepeater::Name(const Type& parameter) { \
+ if (forwarding_enabled_) { \
+ for (size_t i = 0; i < listeners_.size(); i++) { \
+ listeners_[i]->Name(parameter); \
+ } \
+ } \
+}
+// This defines a member that forwards the call to all listeners in reverse
+// order.
+#define GTEST_REVERSE_REPEATER_METHOD_(Name, Type) \
+ void TestEventRepeater::Name(const Type& parameter) { \
+ if (forwarding_enabled_) { \
+ for (size_t i = listeners_.size(); i != 0; i--) { \
+ listeners_[i - 1]->Name(parameter); \
+ } \
+ } \
+ }
+
+GTEST_REPEATER_METHOD_(OnTestProgramStart, UnitTest)
+GTEST_REPEATER_METHOD_(OnEnvironmentsSetUpStart, UnitTest)
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+GTEST_REPEATER_METHOD_(OnTestCaseStart, TestSuite)
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+GTEST_REPEATER_METHOD_(OnTestSuiteStart, TestSuite)
+GTEST_REPEATER_METHOD_(OnTestStart, TestInfo)
+GTEST_REPEATER_METHOD_(OnTestPartResult, TestPartResult)
+GTEST_REPEATER_METHOD_(OnEnvironmentsTearDownStart, UnitTest)
+GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsSetUpEnd, UnitTest)
+GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsTearDownEnd, UnitTest)
+GTEST_REVERSE_REPEATER_METHOD_(OnTestEnd, TestInfo)
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+GTEST_REVERSE_REPEATER_METHOD_(OnTestCaseEnd, TestSuite)
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+GTEST_REVERSE_REPEATER_METHOD_(OnTestSuiteEnd, TestSuite)
+GTEST_REVERSE_REPEATER_METHOD_(OnTestProgramEnd, UnitTest)
+
+#undef GTEST_REPEATER_METHOD_
+#undef GTEST_REVERSE_REPEATER_METHOD_
+
+void TestEventRepeater::OnTestIterationStart(const UnitTest& unit_test,
+ int iteration) {
+ if (forwarding_enabled_) {
+ for (size_t i = 0; i < listeners_.size(); i++) {
+ listeners_[i]->OnTestIterationStart(unit_test, iteration);
+ }
+ }
+}
+
+void TestEventRepeater::OnTestIterationEnd(const UnitTest& unit_test,
+ int iteration) {
+ if (forwarding_enabled_) {
+ for (size_t i = listeners_.size(); i > 0; i--) {
+ listeners_[i - 1]->OnTestIterationEnd(unit_test, iteration);
+ }
+ }
+}
+
+// End TestEventRepeater
+
+// This class generates an XML output file.
+class XmlUnitTestResultPrinter : public EmptyTestEventListener {
+ public:
+ explicit XmlUnitTestResultPrinter(const char* output_file);
+
+ void OnTestIterationEnd(const UnitTest& unit_test, int iteration) override;
+ void ListTestsMatchingFilter(const std::vector<TestSuite*>& test_suites);
+
+ // Prints an XML summary of all unit tests.
+ static void PrintXmlTestsList(std::ostream* stream,
+ const std::vector<TestSuite*>& test_suites);
+
+ private:
+ // Is c a whitespace character that is normalized to a space character
+ // when it appears in an XML attribute value?
+ static bool IsNormalizableWhitespace(char c) {
+ return c == 0x9 || c == 0xA || c == 0xD;
+ }
+
+ // May c appear in a well-formed XML document?
+ static bool IsValidXmlCharacter(char c) {
+ return IsNormalizableWhitespace(c) || c >= 0x20;
+ }
+
+ // Returns an XML-escaped copy of the input string str. If
+ // is_attribute is true, the text is meant to appear as an attribute
+ // value, and normalizable whitespace is preserved by replacing it
+ // with character references.
+ static std::string EscapeXml(const std::string& str, bool is_attribute);
+
+ // Returns the given string with all characters invalid in XML removed.
+ static std::string RemoveInvalidXmlCharacters(const std::string& str);
+
+ // Convenience wrapper around EscapeXml when str is an attribute value.
+ static std::string EscapeXmlAttribute(const std::string& str) {
+ return EscapeXml(str, true);
+ }
+
+ // Convenience wrapper around EscapeXml when str is not an attribute value.
+ static std::string EscapeXmlText(const char* str) {
+ return EscapeXml(str, false);
+ }
+
+ // Verifies that the given attribute belongs to the given element and
+ // streams the attribute as XML.
+ static void OutputXmlAttribute(std::ostream* stream,
+ const std::string& element_name,
+ const std::string& name,
+ const std::string& value);
+
+ // Streams an XML CDATA section, escaping invalid CDATA sequences as needed.
+ static void OutputXmlCDataSection(::std::ostream* stream, const char* data);
+
+ // Streams a test suite XML stanza containing the given test result.
+ //
+ // Requires: result.Failed()
+ static void OutputXmlTestSuiteForTestResult(::std::ostream* stream,
+ const TestResult& result);
+
+ // Streams an XML representation of a TestResult object.
+ static void OutputXmlTestResult(::std::ostream* stream,
+ const TestResult& result);
+
+ // Streams an XML representation of a TestInfo object.
+ static void OutputXmlTestInfo(::std::ostream* stream,
+ const char* test_suite_name,
+ const TestInfo& test_info);
+
+ // Prints an XML representation of a TestSuite object
+ static void PrintXmlTestSuite(::std::ostream* stream,
+ const TestSuite& test_suite);
+
+ // Prints an XML summary of unit_test to output stream out.
+ static void PrintXmlUnitTest(::std::ostream* stream,
+ const UnitTest& unit_test);
+
+ // Produces a string representing the test properties in a result as space
+ // delimited XML attributes based on the property key="value" pairs.
+ // When the std::string is not empty, it includes a space at the beginning,
+ // to delimit this attribute from prior attributes.
+ static std::string TestPropertiesAsXmlAttributes(const TestResult& result);
+
+ // Streams an XML representation of the test properties of a TestResult
+ // object.
+ static void OutputXmlTestProperties(std::ostream* stream,
+ const TestResult& result);
+
+ // The output file.
+ const std::string output_file_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(XmlUnitTestResultPrinter);
+};
+
+// Creates a new XmlUnitTestResultPrinter.
+XmlUnitTestResultPrinter::XmlUnitTestResultPrinter(const char* output_file)
+ : output_file_(output_file) {
+ if (output_file_.empty()) {
+ GTEST_LOG_(FATAL) << "XML output file may not be null";
+ }
+}
+
+// Called after the unit test ends.
+void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test,
+ int /*iteration*/) {
+ FILE* xmlout = OpenFileForWriting(output_file_);
+ std::stringstream stream;
+ PrintXmlUnitTest(&stream, unit_test);
+ fprintf(xmlout, "%s", StringStreamToString(&stream).c_str());
+ fclose(xmlout);
+}
+
+void XmlUnitTestResultPrinter::ListTestsMatchingFilter(
+ const std::vector<TestSuite*>& test_suites) {
+ FILE* xmlout = OpenFileForWriting(output_file_);
+ std::stringstream stream;
+ PrintXmlTestsList(&stream, test_suites);
+ fprintf(xmlout, "%s", StringStreamToString(&stream).c_str());
+ fclose(xmlout);
+}
+
+// Returns an XML-escaped copy of the input string str. If is_attribute
+// is true, the text is meant to appear as an attribute value, and
+// normalizable whitespace is preserved by replacing it with character
+// references.
+//
+// Invalid XML characters in str, if any, are stripped from the output.
+// It is expected that most, if not all, of the text processed by this
+// module will consist of ordinary English text.
+// If this module is ever modified to produce version 1.1 XML output,
+// most invalid characters can be retained using character references.
+std::string XmlUnitTestResultPrinter::EscapeXml(
+ const std::string& str, bool is_attribute) {
+ Message m;
+
+ for (size_t i = 0; i < str.size(); ++i) {
+ const char ch = str[i];
+ switch (ch) {
+ case '<':
+ m << "&lt;";
+ break;
+ case '>':
+ m << "&gt;";
+ break;
+ case '&':
+ m << "&amp;";
+ break;
+ case '\'':
+ if (is_attribute)
+ m << "&apos;";
+ else
+ m << '\'';
+ break;
+ case '"':
+ if (is_attribute)
+ m << "&quot;";
+ else
+ m << '"';
+ break;
+ default:
+ if (IsValidXmlCharacter(ch)) {
+ if (is_attribute && IsNormalizableWhitespace(ch))
+ m << "&#x" << String::FormatByte(static_cast<unsigned char>(ch))
+ << ";";
+ else
+ m << ch;
+ }
+ break;
+ }
+ }
+
+ return m.GetString();
+}
+
+// Returns the given string with all characters invalid in XML removed.
+// Currently invalid characters are dropped from the string. An
+// alternative is to replace them with certain characters such as . or ?.
+std::string XmlUnitTestResultPrinter::RemoveInvalidXmlCharacters(
+ const std::string& str) {
+ std::string output;
+ output.reserve(str.size());
+ for (std::string::const_iterator it = str.begin(); it != str.end(); ++it)
+ if (IsValidXmlCharacter(*it))
+ output.push_back(*it);
+
+ return output;
+}
+
+// The following routines generate an XML representation of a UnitTest
+// object.
+// GOOGLETEST_CM0009 DO NOT DELETE
+//
+// This is how Google Test concepts map to the DTD:
+//
+// <testsuites name="AllTests"> <-- corresponds to a UnitTest object
+// <testsuite name="testcase-name"> <-- corresponds to a TestSuite object
+// <testcase name="test-name"> <-- corresponds to a TestInfo object
+// <failure message="...">...</failure>
+// <failure message="...">...</failure>
+// <failure message="...">...</failure>
+// <-- individual assertion failures
+// </testcase>
+// </testsuite>
+// </testsuites>
+
+// Formats the given time in milliseconds as seconds.
+std::string FormatTimeInMillisAsSeconds(TimeInMillis ms) {
+ ::std::stringstream ss;
+ ss << (static_cast<double>(ms) * 1e-3);
+ return ss.str();
+}
+
+static bool PortableLocaltime(time_t seconds, struct tm* out) {
+#if defined(_MSC_VER)
+ return localtime_s(out, &seconds) == 0;
+#elif defined(__MINGW32__) || defined(__MINGW64__)
+ // MINGW <time.h> provides neither localtime_r nor localtime_s, but uses
+ // Windows' localtime(), which has a thread-local tm buffer.
+ struct tm* tm_ptr = localtime(&seconds); // NOLINT
+ if (tm_ptr == nullptr) return false;
+ *out = *tm_ptr;
+ return true;
+#elif defined(__STDC_LIB_EXT1__)
+ // Uses localtime_s when available as localtime_r is only available from
+ // C23 standard.
+ return localtime_s(&seconds, out) != nullptr;
+#else
+ return localtime_r(&seconds, out) != nullptr;
+#endif
+}
+
+// Converts the given epoch time in milliseconds to a date string in the ISO
+// 8601 format, without the timezone information.
+std::string FormatEpochTimeInMillisAsIso8601(TimeInMillis ms) {
+ struct tm time_struct;
+ if (!PortableLocaltime(static_cast<time_t>(ms / 1000), &time_struct))
+ return "";
+ // YYYY-MM-DDThh:mm:ss.sss
+ return StreamableToString(time_struct.tm_year + 1900) + "-" +
+ String::FormatIntWidth2(time_struct.tm_mon + 1) + "-" +
+ String::FormatIntWidth2(time_struct.tm_mday) + "T" +
+ String::FormatIntWidth2(time_struct.tm_hour) + ":" +
+ String::FormatIntWidth2(time_struct.tm_min) + ":" +
+ String::FormatIntWidth2(time_struct.tm_sec) + "." +
+ String::FormatIntWidthN(static_cast<int>(ms % 1000), 3);
+}
+
+// Streams an XML CDATA section, escaping invalid CDATA sequences as needed.
+void XmlUnitTestResultPrinter::OutputXmlCDataSection(::std::ostream* stream,
+ const char* data) {
+ const char* segment = data;
+ *stream << "<![CDATA[";
+ for (;;) {
+ const char* const next_segment = strstr(segment, "]]>");
+ if (next_segment != nullptr) {
+ stream->write(
+ segment, static_cast<std::streamsize>(next_segment - segment));
+ *stream << "]]>]]&gt;<![CDATA[";
+ segment = next_segment + strlen("]]>");
+ } else {
+ *stream << segment;
+ break;
+ }
+ }
+ *stream << "]]>";
+}
+
+void XmlUnitTestResultPrinter::OutputXmlAttribute(
+ std::ostream* stream,
+ const std::string& element_name,
+ const std::string& name,
+ const std::string& value) {
+ const std::vector<std::string>& allowed_names =
+ GetReservedOutputAttributesForElement(element_name);
+
+ GTEST_CHECK_(std::find(allowed_names.begin(), allowed_names.end(), name) !=
+ allowed_names.end())
+ << "Attribute " << name << " is not allowed for element <" << element_name
+ << ">.";
+
+ *stream << " " << name << "=\"" << EscapeXmlAttribute(value) << "\"";
+}
+
+// Streams a test suite XML stanza containing the given test result.
+void XmlUnitTestResultPrinter::OutputXmlTestSuiteForTestResult(
+ ::std::ostream* stream, const TestResult& result) {
+ // Output the boilerplate for a minimal test suite with one test.
+ *stream << " <testsuite";
+ OutputXmlAttribute(stream, "testsuite", "name", "NonTestSuiteFailure");
+ OutputXmlAttribute(stream, "testsuite", "tests", "1");
+ OutputXmlAttribute(stream, "testsuite", "failures", "1");
+ OutputXmlAttribute(stream, "testsuite", "disabled", "0");
+ OutputXmlAttribute(stream, "testsuite", "skipped", "0");
+ OutputXmlAttribute(stream, "testsuite", "errors", "0");
+ OutputXmlAttribute(stream, "testsuite", "time",
+ FormatTimeInMillisAsSeconds(result.elapsed_time()));
+ OutputXmlAttribute(
+ stream, "testsuite", "timestamp",
+ FormatEpochTimeInMillisAsIso8601(result.start_timestamp()));
+ *stream << ">";
+
+ // Output the boilerplate for a minimal test case with a single test.
+ *stream << " <testcase";
+ OutputXmlAttribute(stream, "testcase", "name", "");
+ OutputXmlAttribute(stream, "testcase", "status", "run");
+ OutputXmlAttribute(stream, "testcase", "result", "completed");
+ OutputXmlAttribute(stream, "testcase", "classname", "");
+ OutputXmlAttribute(stream, "testcase", "time",
+ FormatTimeInMillisAsSeconds(result.elapsed_time()));
+ OutputXmlAttribute(
+ stream, "testcase", "timestamp",
+ FormatEpochTimeInMillisAsIso8601(result.start_timestamp()));
+
+ // Output the actual test result.
+ OutputXmlTestResult(stream, result);
+
+ // Complete the test suite.
+ *stream << " </testsuite>\n";
+}
+
+// Prints an XML representation of a TestInfo object.
+void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream,
+ const char* test_suite_name,
+ const TestInfo& test_info) {
+ const TestResult& result = *test_info.result();
+ const std::string kTestsuite = "testcase";
+
+ if (test_info.is_in_another_shard()) {
+ return;
+ }
+
+ *stream << " <testcase";
+ OutputXmlAttribute(stream, kTestsuite, "name", test_info.name());
+
+ if (test_info.value_param() != nullptr) {
+ OutputXmlAttribute(stream, kTestsuite, "value_param",
+ test_info.value_param());
+ }
+ if (test_info.type_param() != nullptr) {
+ OutputXmlAttribute(stream, kTestsuite, "type_param",
+ test_info.type_param());
+ }
+ if (GTEST_FLAG(list_tests)) {
+ OutputXmlAttribute(stream, kTestsuite, "file", test_info.file());
+ OutputXmlAttribute(stream, kTestsuite, "line",
+ StreamableToString(test_info.line()));
+ *stream << " />\n";
+ return;
+ }
+
+ OutputXmlAttribute(stream, kTestsuite, "status",
+ test_info.should_run() ? "run" : "notrun");
+ OutputXmlAttribute(stream, kTestsuite, "result",
+ test_info.should_run()
+ ? (result.Skipped() ? "skipped" : "completed")
+ : "suppressed");
+ OutputXmlAttribute(stream, kTestsuite, "time",
+ FormatTimeInMillisAsSeconds(result.elapsed_time()));
+ OutputXmlAttribute(
+ stream, kTestsuite, "timestamp",
+ FormatEpochTimeInMillisAsIso8601(result.start_timestamp()));
+ OutputXmlAttribute(stream, kTestsuite, "classname", test_suite_name);
+
+ OutputXmlTestResult(stream, result);
+}
+
+void XmlUnitTestResultPrinter::OutputXmlTestResult(::std::ostream* stream,
+ const TestResult& result) {
+ int failures = 0;
+ int skips = 0;
+ for (int i = 0; i < result.total_part_count(); ++i) {
+ const TestPartResult& part = result.GetTestPartResult(i);
+ if (part.failed()) {
+ if (++failures == 1 && skips == 0) {
+ *stream << ">\n";
+ }
+ const std::string location =
+ internal::FormatCompilerIndependentFileLocation(part.file_name(),
+ part.line_number());
+ const std::string summary = location + "\n" + part.summary();
+ *stream << " <failure message=\""
+ << EscapeXmlAttribute(summary)
+ << "\" type=\"\">";
+ const std::string detail = location + "\n" + part.message();
+ OutputXmlCDataSection(stream, RemoveInvalidXmlCharacters(detail).c_str());
+ *stream << "</failure>\n";
+ } else if (part.skipped()) {
+ if (++skips == 1 && failures == 0) {
+ *stream << ">\n";
+ }
+ const std::string location =
+ internal::FormatCompilerIndependentFileLocation(part.file_name(),
+ part.line_number());
+ const std::string summary = location + "\n" + part.summary();
+ *stream << " <skipped message=\""
+ << EscapeXmlAttribute(summary.c_str()) << "\">";
+ const std::string detail = location + "\n" + part.message();
+ OutputXmlCDataSection(stream, RemoveInvalidXmlCharacters(detail).c_str());
+ *stream << "</skipped>\n";
+ }
+ }
+
+ if (failures == 0 && skips == 0 && result.test_property_count() == 0) {
+ *stream << " />\n";
+ } else {
+ if (failures == 0 && skips == 0) {
+ *stream << ">\n";
+ }
+ OutputXmlTestProperties(stream, result);
+ *stream << " </testcase>\n";
+ }
+}
+
+// Prints an XML representation of a TestSuite object
+void XmlUnitTestResultPrinter::PrintXmlTestSuite(std::ostream* stream,
+ const TestSuite& test_suite) {
+ const std::string kTestsuite = "testsuite";
+ *stream << " <" << kTestsuite;
+ OutputXmlAttribute(stream, kTestsuite, "name", test_suite.name());
+ OutputXmlAttribute(stream, kTestsuite, "tests",
+ StreamableToString(test_suite.reportable_test_count()));
+ if (!GTEST_FLAG(list_tests)) {
+ OutputXmlAttribute(stream, kTestsuite, "failures",
+ StreamableToString(test_suite.failed_test_count()));
+ OutputXmlAttribute(
+ stream, kTestsuite, "disabled",
+ StreamableToString(test_suite.reportable_disabled_test_count()));
+ OutputXmlAttribute(stream, kTestsuite, "skipped",
+ StreamableToString(test_suite.skipped_test_count()));
+
+ OutputXmlAttribute(stream, kTestsuite, "errors", "0");
+
+ OutputXmlAttribute(stream, kTestsuite, "time",
+ FormatTimeInMillisAsSeconds(test_suite.elapsed_time()));
+ OutputXmlAttribute(
+ stream, kTestsuite, "timestamp",
+ FormatEpochTimeInMillisAsIso8601(test_suite.start_timestamp()));
+ *stream << TestPropertiesAsXmlAttributes(test_suite.ad_hoc_test_result());
+ }
+ *stream << ">\n";
+ for (int i = 0; i < test_suite.total_test_count(); ++i) {
+ if (test_suite.GetTestInfo(i)->is_reportable())
+ OutputXmlTestInfo(stream, test_suite.name(), *test_suite.GetTestInfo(i));
+ }
+ *stream << " </" << kTestsuite << ">\n";
+}
+
+// Prints an XML summary of unit_test to output stream out.
+void XmlUnitTestResultPrinter::PrintXmlUnitTest(std::ostream* stream,
+ const UnitTest& unit_test) {
+ const std::string kTestsuites = "testsuites";
+
+ *stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
+ *stream << "<" << kTestsuites;
+
+ OutputXmlAttribute(stream, kTestsuites, "tests",
+ StreamableToString(unit_test.reportable_test_count()));
+ OutputXmlAttribute(stream, kTestsuites, "failures",
+ StreamableToString(unit_test.failed_test_count()));
+ OutputXmlAttribute(
+ stream, kTestsuites, "disabled",
+ StreamableToString(unit_test.reportable_disabled_test_count()));
+ OutputXmlAttribute(stream, kTestsuites, "errors", "0");
+ OutputXmlAttribute(stream, kTestsuites, "time",
+ FormatTimeInMillisAsSeconds(unit_test.elapsed_time()));
+ OutputXmlAttribute(
+ stream, kTestsuites, "timestamp",
+ FormatEpochTimeInMillisAsIso8601(unit_test.start_timestamp()));
+
+ if (GTEST_FLAG(shuffle)) {
+ OutputXmlAttribute(stream, kTestsuites, "random_seed",
+ StreamableToString(unit_test.random_seed()));
+ }
+ *stream << TestPropertiesAsXmlAttributes(unit_test.ad_hoc_test_result());
+
+ OutputXmlAttribute(stream, kTestsuites, "name", "AllTests");
+ *stream << ">\n";
+
+ for (int i = 0; i < unit_test.total_test_suite_count(); ++i) {
+ if (unit_test.GetTestSuite(i)->reportable_test_count() > 0)
+ PrintXmlTestSuite(stream, *unit_test.GetTestSuite(i));
+ }
+
+ // If there was a test failure outside of one of the test suites (like in a
+ // test environment) include that in the output.
+ if (unit_test.ad_hoc_test_result().Failed()) {
+ OutputXmlTestSuiteForTestResult(stream, unit_test.ad_hoc_test_result());
+ }
+
+ *stream << "</" << kTestsuites << ">\n";
+}
+
+void XmlUnitTestResultPrinter::PrintXmlTestsList(
+ std::ostream* stream, const std::vector<TestSuite*>& test_suites) {
+ const std::string kTestsuites = "testsuites";
+
+ *stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
+ *stream << "<" << kTestsuites;
+
+ int total_tests = 0;
+ for (auto test_suite : test_suites) {
+ total_tests += test_suite->total_test_count();
+ }
+ OutputXmlAttribute(stream, kTestsuites, "tests",
+ StreamableToString(total_tests));
+ OutputXmlAttribute(stream, kTestsuites, "name", "AllTests");
+ *stream << ">\n";
+
+ for (auto test_suite : test_suites) {
+ PrintXmlTestSuite(stream, *test_suite);
+ }
+ *stream << "</" << kTestsuites << ">\n";
+}
+
+// Produces a string representing the test properties in a result as space
+// delimited XML attributes based on the property key="value" pairs.
+std::string XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes(
+ const TestResult& result) {
+ Message attributes;
+ for (int i = 0; i < result.test_property_count(); ++i) {
+ const TestProperty& property = result.GetTestProperty(i);
+ attributes << " " << property.key() << "="
+ << "\"" << EscapeXmlAttribute(property.value()) << "\"";
+ }
+ return attributes.GetString();
+}
+
+void XmlUnitTestResultPrinter::OutputXmlTestProperties(
+ std::ostream* stream, const TestResult& result) {
+ const std::string kProperties = "properties";
+ const std::string kProperty = "property";
+
+ if (result.test_property_count() <= 0) {
+ return;
+ }
+
+ *stream << "<" << kProperties << ">\n";
+ for (int i = 0; i < result.test_property_count(); ++i) {
+ const TestProperty& property = result.GetTestProperty(i);
+ *stream << "<" << kProperty;
+ *stream << " name=\"" << EscapeXmlAttribute(property.key()) << "\"";
+ *stream << " value=\"" << EscapeXmlAttribute(property.value()) << "\"";
+ *stream << "/>\n";
+ }
+ *stream << "</" << kProperties << ">\n";
+}
+
+// End XmlUnitTestResultPrinter
+
+// This class generates an JSON output file.
+class JsonUnitTestResultPrinter : public EmptyTestEventListener {
+ public:
+ explicit JsonUnitTestResultPrinter(const char* output_file);
+
+ void OnTestIterationEnd(const UnitTest& unit_test, int iteration) override;
+
+ // Prints an JSON summary of all unit tests.
+ static void PrintJsonTestList(::std::ostream* stream,
+ const std::vector<TestSuite*>& test_suites);
+
+ private:
+ // Returns an JSON-escaped copy of the input string str.
+ static std::string EscapeJson(const std::string& str);
+
+ //// Verifies that the given attribute belongs to the given element and
+ //// streams the attribute as JSON.
+ static void OutputJsonKey(std::ostream* stream,
+ const std::string& element_name,
+ const std::string& name,
+ const std::string& value,
+ const std::string& indent,
+ bool comma = true);
+ static void OutputJsonKey(std::ostream* stream,
+ const std::string& element_name,
+ const std::string& name,
+ int value,
+ const std::string& indent,
+ bool comma = true);
+
+ // Streams a test suite JSON stanza containing the given test result.
+ //
+ // Requires: result.Failed()
+ static void OutputJsonTestSuiteForTestResult(::std::ostream* stream,
+ const TestResult& result);
+
+ // Streams a JSON representation of a TestResult object.
+ static void OutputJsonTestResult(::std::ostream* stream,
+ const TestResult& result);
+
+ // Streams a JSON representation of a TestInfo object.
+ static void OutputJsonTestInfo(::std::ostream* stream,
+ const char* test_suite_name,
+ const TestInfo& test_info);
+
+ // Prints a JSON representation of a TestSuite object
+ static void PrintJsonTestSuite(::std::ostream* stream,
+ const TestSuite& test_suite);
+
+ // Prints a JSON summary of unit_test to output stream out.
+ static void PrintJsonUnitTest(::std::ostream* stream,
+ const UnitTest& unit_test);
+
+ // Produces a string representing the test properties in a result as
+ // a JSON dictionary.
+ static std::string TestPropertiesAsJson(const TestResult& result,
+ const std::string& indent);
+
+ // The output file.
+ const std::string output_file_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(JsonUnitTestResultPrinter);
+};
+
+// Creates a new JsonUnitTestResultPrinter.
+JsonUnitTestResultPrinter::JsonUnitTestResultPrinter(const char* output_file)
+ : output_file_(output_file) {
+ if (output_file_.empty()) {
+ GTEST_LOG_(FATAL) << "JSON output file may not be null";
+ }
+}
+
+void JsonUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test,
+ int /*iteration*/) {
+ FILE* jsonout = OpenFileForWriting(output_file_);
+ std::stringstream stream;
+ PrintJsonUnitTest(&stream, unit_test);
+ fprintf(jsonout, "%s", StringStreamToString(&stream).c_str());
+ fclose(jsonout);
+}
+
+// Returns an JSON-escaped copy of the input string str.
+std::string JsonUnitTestResultPrinter::EscapeJson(const std::string& str) {
+ Message m;
+
+ for (size_t i = 0; i < str.size(); ++i) {
+ const char ch = str[i];
+ switch (ch) {
+ case '\\':
+ case '"':
+ case '/':
+ m << '\\' << ch;
+ break;
+ case '\b':
+ m << "\\b";
+ break;
+ case '\t':
+ m << "\\t";
+ break;
+ case '\n':
+ m << "\\n";
+ break;
+ case '\f':
+ m << "\\f";
+ break;
+ case '\r':
+ m << "\\r";
+ break;
+ default:
+ if (ch < ' ') {
+ m << "\\u00" << String::FormatByte(static_cast<unsigned char>(ch));
+ } else {
+ m << ch;
+ }
+ break;
+ }
+ }
+
+ return m.GetString();
+}
+
+// The following routines generate an JSON representation of a UnitTest
+// object.
+
+// Formats the given time in milliseconds as seconds.
+static std::string FormatTimeInMillisAsDuration(TimeInMillis ms) {
+ ::std::stringstream ss;
+ ss << (static_cast<double>(ms) * 1e-3) << "s";
+ return ss.str();
+}
+
+// Converts the given epoch time in milliseconds to a date string in the
+// RFC3339 format, without the timezone information.
+static std::string FormatEpochTimeInMillisAsRFC3339(TimeInMillis ms) {
+ struct tm time_struct;
+ if (!PortableLocaltime(static_cast<time_t>(ms / 1000), &time_struct))
+ return "";
+ // YYYY-MM-DDThh:mm:ss
+ return StreamableToString(time_struct.tm_year + 1900) + "-" +
+ String::FormatIntWidth2(time_struct.tm_mon + 1) + "-" +
+ String::FormatIntWidth2(time_struct.tm_mday) + "T" +
+ String::FormatIntWidth2(time_struct.tm_hour) + ":" +
+ String::FormatIntWidth2(time_struct.tm_min) + ":" +
+ String::FormatIntWidth2(time_struct.tm_sec) + "Z";
+}
+
+static inline std::string Indent(size_t width) {
+ return std::string(width, ' ');
+}
+
+void JsonUnitTestResultPrinter::OutputJsonKey(
+ std::ostream* stream,
+ const std::string& element_name,
+ const std::string& name,
+ const std::string& value,
+ const std::string& indent,
+ bool comma) {
+ const std::vector<std::string>& allowed_names =
+ GetReservedOutputAttributesForElement(element_name);
+
+ GTEST_CHECK_(std::find(allowed_names.begin(), allowed_names.end(), name) !=
+ allowed_names.end())
+ << "Key \"" << name << "\" is not allowed for value \"" << element_name
+ << "\".";
+
+ *stream << indent << "\"" << name << "\": \"" << EscapeJson(value) << "\"";
+ if (comma)
+ *stream << ",\n";
+}
+
+void JsonUnitTestResultPrinter::OutputJsonKey(
+ std::ostream* stream,
+ const std::string& element_name,
+ const std::string& name,
+ int value,
+ const std::string& indent,
+ bool comma) {
+ const std::vector<std::string>& allowed_names =
+ GetReservedOutputAttributesForElement(element_name);
+
+ GTEST_CHECK_(std::find(allowed_names.begin(), allowed_names.end(), name) !=
+ allowed_names.end())
+ << "Key \"" << name << "\" is not allowed for value \"" << element_name
+ << "\".";
+
+ *stream << indent << "\"" << name << "\": " << StreamableToString(value);
+ if (comma)
+ *stream << ",\n";
+}
+
+// Streams a test suite JSON stanza containing the given test result.
+void JsonUnitTestResultPrinter::OutputJsonTestSuiteForTestResult(
+ ::std::ostream* stream, const TestResult& result) {
+ // Output the boilerplate for a new test suite.
+ *stream << Indent(4) << "{\n";
+ OutputJsonKey(stream, "testsuite", "name", "NonTestSuiteFailure", Indent(6));
+ OutputJsonKey(stream, "testsuite", "tests", 1, Indent(6));
+ if (!GTEST_FLAG(list_tests)) {
+ OutputJsonKey(stream, "testsuite", "failures", 1, Indent(6));
+ OutputJsonKey(stream, "testsuite", "disabled", 0, Indent(6));
+ OutputJsonKey(stream, "testsuite", "skipped", 0, Indent(6));
+ OutputJsonKey(stream, "testsuite", "errors", 0, Indent(6));
+ OutputJsonKey(stream, "testsuite", "time",
+ FormatTimeInMillisAsDuration(result.elapsed_time()),
+ Indent(6));
+ OutputJsonKey(stream, "testsuite", "timestamp",
+ FormatEpochTimeInMillisAsRFC3339(result.start_timestamp()),
+ Indent(6));
+ }
+ *stream << Indent(6) << "\"testsuite\": [\n";
+
+ // Output the boilerplate for a new test case.
+ *stream << Indent(8) << "{\n";
+ OutputJsonKey(stream, "testcase", "name", "", Indent(10));
+ OutputJsonKey(stream, "testcase", "status", "RUN", Indent(10));
+ OutputJsonKey(stream, "testcase", "result", "COMPLETED", Indent(10));
+ OutputJsonKey(stream, "testcase", "timestamp",
+ FormatEpochTimeInMillisAsRFC3339(result.start_timestamp()),
+ Indent(10));
+ OutputJsonKey(stream, "testcase", "time",
+ FormatTimeInMillisAsDuration(result.elapsed_time()),
+ Indent(10));
+ OutputJsonKey(stream, "testcase", "classname", "", Indent(10), false);
+ *stream << TestPropertiesAsJson(result, Indent(10));
+
+ // Output the actual test result.
+ OutputJsonTestResult(stream, result);
+
+ // Finish the test suite.
+ *stream << "\n" << Indent(6) << "]\n" << Indent(4) << "}";
+}
+
+// Prints a JSON representation of a TestInfo object.
+void JsonUnitTestResultPrinter::OutputJsonTestInfo(::std::ostream* stream,
+ const char* test_suite_name,
+ const TestInfo& test_info) {
+ const TestResult& result = *test_info.result();
+ const std::string kTestsuite = "testcase";
+ const std::string kIndent = Indent(10);
+
+ *stream << Indent(8) << "{\n";
+ OutputJsonKey(stream, kTestsuite, "name", test_info.name(), kIndent);
+
+ if (test_info.value_param() != nullptr) {
+ OutputJsonKey(stream, kTestsuite, "value_param", test_info.value_param(),
+ kIndent);
+ }
+ if (test_info.type_param() != nullptr) {
+ OutputJsonKey(stream, kTestsuite, "type_param", test_info.type_param(),
+ kIndent);
+ }
+ if (GTEST_FLAG(list_tests)) {
+ OutputJsonKey(stream, kTestsuite, "file", test_info.file(), kIndent);
+ OutputJsonKey(stream, kTestsuite, "line", test_info.line(), kIndent, false);
+ *stream << "\n" << Indent(8) << "}";
+ return;
+ }
+
+ OutputJsonKey(stream, kTestsuite, "status",
+ test_info.should_run() ? "RUN" : "NOTRUN", kIndent);
+ OutputJsonKey(stream, kTestsuite, "result",
+ test_info.should_run()
+ ? (result.Skipped() ? "SKIPPED" : "COMPLETED")
+ : "SUPPRESSED",
+ kIndent);
+ OutputJsonKey(stream, kTestsuite, "timestamp",
+ FormatEpochTimeInMillisAsRFC3339(result.start_timestamp()),
+ kIndent);
+ OutputJsonKey(stream, kTestsuite, "time",
+ FormatTimeInMillisAsDuration(result.elapsed_time()), kIndent);
+ OutputJsonKey(stream, kTestsuite, "classname", test_suite_name, kIndent,
+ false);
+ *stream << TestPropertiesAsJson(result, kIndent);
+
+ OutputJsonTestResult(stream, result);
+}
+
+void JsonUnitTestResultPrinter::OutputJsonTestResult(::std::ostream* stream,
+ const TestResult& result) {
+ const std::string kIndent = Indent(10);
+
+ int failures = 0;
+ for (int i = 0; i < result.total_part_count(); ++i) {
+ const TestPartResult& part = result.GetTestPartResult(i);
+ if (part.failed()) {
+ *stream << ",\n";
+ if (++failures == 1) {
+ *stream << kIndent << "\"" << "failures" << "\": [\n";
+ }
+ const std::string location =
+ internal::FormatCompilerIndependentFileLocation(part.file_name(),
+ part.line_number());
+ const std::string message = EscapeJson(location + "\n" + part.message());
+ *stream << kIndent << " {\n"
+ << kIndent << " \"failure\": \"" << message << "\",\n"
+ << kIndent << " \"type\": \"\"\n"
+ << kIndent << " }";
+ }
+ }
+
+ if (failures > 0)
+ *stream << "\n" << kIndent << "]";
+ *stream << "\n" << Indent(8) << "}";
+}
+
+// Prints an JSON representation of a TestSuite object
+void JsonUnitTestResultPrinter::PrintJsonTestSuite(
+ std::ostream* stream, const TestSuite& test_suite) {
+ const std::string kTestsuite = "testsuite";
+ const std::string kIndent = Indent(6);
+
+ *stream << Indent(4) << "{\n";
+ OutputJsonKey(stream, kTestsuite, "name", test_suite.name(), kIndent);
+ OutputJsonKey(stream, kTestsuite, "tests", test_suite.reportable_test_count(),
+ kIndent);
+ if (!GTEST_FLAG(list_tests)) {
+ OutputJsonKey(stream, kTestsuite, "failures",
+ test_suite.failed_test_count(), kIndent);
+ OutputJsonKey(stream, kTestsuite, "disabled",
+ test_suite.reportable_disabled_test_count(), kIndent);
+ OutputJsonKey(stream, kTestsuite, "errors", 0, kIndent);
+ OutputJsonKey(
+ stream, kTestsuite, "timestamp",
+ FormatEpochTimeInMillisAsRFC3339(test_suite.start_timestamp()),
+ kIndent);
+ OutputJsonKey(stream, kTestsuite, "time",
+ FormatTimeInMillisAsDuration(test_suite.elapsed_time()),
+ kIndent, false);
+ *stream << TestPropertiesAsJson(test_suite.ad_hoc_test_result(), kIndent)
+ << ",\n";
+ }
+
+ *stream << kIndent << "\"" << kTestsuite << "\": [\n";
+
+ bool comma = false;
+ for (int i = 0; i < test_suite.total_test_count(); ++i) {
+ if (test_suite.GetTestInfo(i)->is_reportable()) {
+ if (comma) {
+ *stream << ",\n";
+ } else {
+ comma = true;
+ }
+ OutputJsonTestInfo(stream, test_suite.name(), *test_suite.GetTestInfo(i));
+ }
+ }
+ *stream << "\n" << kIndent << "]\n" << Indent(4) << "}";
+}
+
+// Prints a JSON summary of unit_test to output stream out.
+void JsonUnitTestResultPrinter::PrintJsonUnitTest(std::ostream* stream,
+ const UnitTest& unit_test) {
+ const std::string kTestsuites = "testsuites";
+ const std::string kIndent = Indent(2);
+ *stream << "{\n";
+
+ OutputJsonKey(stream, kTestsuites, "tests", unit_test.reportable_test_count(),
+ kIndent);
+ OutputJsonKey(stream, kTestsuites, "failures", unit_test.failed_test_count(),
+ kIndent);
+ OutputJsonKey(stream, kTestsuites, "disabled",
+ unit_test.reportable_disabled_test_count(), kIndent);
+ OutputJsonKey(stream, kTestsuites, "errors", 0, kIndent);
+ if (GTEST_FLAG(shuffle)) {
+ OutputJsonKey(stream, kTestsuites, "random_seed", unit_test.random_seed(),
+ kIndent);
+ }
+ OutputJsonKey(stream, kTestsuites, "timestamp",
+ FormatEpochTimeInMillisAsRFC3339(unit_test.start_timestamp()),
+ kIndent);
+ OutputJsonKey(stream, kTestsuites, "time",
+ FormatTimeInMillisAsDuration(unit_test.elapsed_time()), kIndent,
+ false);
+
+ *stream << TestPropertiesAsJson(unit_test.ad_hoc_test_result(), kIndent)
+ << ",\n";
+
+ OutputJsonKey(stream, kTestsuites, "name", "AllTests", kIndent);
+ *stream << kIndent << "\"" << kTestsuites << "\": [\n";
+
+ bool comma = false;
+ for (int i = 0; i < unit_test.total_test_suite_count(); ++i) {
+ if (unit_test.GetTestSuite(i)->reportable_test_count() > 0) {
+ if (comma) {
+ *stream << ",\n";
+ } else {
+ comma = true;
+ }
+ PrintJsonTestSuite(stream, *unit_test.GetTestSuite(i));
+ }
+ }
+
+ // If there was a test failure outside of one of the test suites (like in a
+ // test environment) include that in the output.
+ if (unit_test.ad_hoc_test_result().Failed()) {
+ OutputJsonTestSuiteForTestResult(stream, unit_test.ad_hoc_test_result());
+ }
+
+ *stream << "\n" << kIndent << "]\n" << "}\n";
+}
+
+void JsonUnitTestResultPrinter::PrintJsonTestList(
+ std::ostream* stream, const std::vector<TestSuite*>& test_suites) {
+ const std::string kTestsuites = "testsuites";
+ const std::string kIndent = Indent(2);
+ *stream << "{\n";
+ int total_tests = 0;
+ for (auto test_suite : test_suites) {
+ total_tests += test_suite->total_test_count();
+ }
+ OutputJsonKey(stream, kTestsuites, "tests", total_tests, kIndent);
+
+ OutputJsonKey(stream, kTestsuites, "name", "AllTests", kIndent);
+ *stream << kIndent << "\"" << kTestsuites << "\": [\n";
+
+ for (size_t i = 0; i < test_suites.size(); ++i) {
+ if (i != 0) {
+ *stream << ",\n";
+ }
+ PrintJsonTestSuite(stream, *test_suites[i]);
+ }
+
+ *stream << "\n"
+ << kIndent << "]\n"
+ << "}\n";
+}
+// Produces a string representing the test properties in a result as
+// a JSON dictionary.
+std::string JsonUnitTestResultPrinter::TestPropertiesAsJson(
+ const TestResult& result, const std::string& indent) {
+ Message attributes;
+ for (int i = 0; i < result.test_property_count(); ++i) {
+ const TestProperty& property = result.GetTestProperty(i);
+ attributes << ",\n" << indent << "\"" << property.key() << "\": "
+ << "\"" << EscapeJson(property.value()) << "\"";
+ }
+ return attributes.GetString();
+}
+
+// End JsonUnitTestResultPrinter
+
+#if GTEST_CAN_STREAM_RESULTS_
+
+// Checks if str contains '=', '&', '%' or '\n' characters. If yes,
+// replaces them by "%xx" where xx is their hexadecimal value. For
+// example, replaces "=" with "%3D". This algorithm is O(strlen(str))
+// in both time and space -- important as the input str may contain an
+// arbitrarily long test failure message and stack trace.
+std::string StreamingListener::UrlEncode(const char* str) {
+ std::string result;
+ result.reserve(strlen(str) + 1);
+ for (char ch = *str; ch != '\0'; ch = *++str) {
+ switch (ch) {
+ case '%':
+ case '=':
+ case '&':
+ case '\n':
+ result.append("%" + String::FormatByte(static_cast<unsigned char>(ch)));
+ break;
+ default:
+ result.push_back(ch);
+ break;
+ }
+ }
+ return result;
+}
+
+void StreamingListener::SocketWriter::MakeConnection() {
+ GTEST_CHECK_(sockfd_ == -1)
+ << "MakeConnection() can't be called when there is already a connection.";
+
+ addrinfo hints;
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC; // To allow both IPv4 and IPv6 addresses.
+ hints.ai_socktype = SOCK_STREAM;
+ addrinfo* servinfo = nullptr;
+
+ // Use the getaddrinfo() to get a linked list of IP addresses for
+ // the given host name.
+ const int error_num = getaddrinfo(
+ host_name_.c_str(), port_num_.c_str(), &hints, &servinfo);
+ if (error_num != 0) {
+ GTEST_LOG_(WARNING) << "stream_result_to: getaddrinfo() failed: "
+ << gai_strerror(error_num);
+ }
+
+ // Loop through all the results and connect to the first we can.
+ for (addrinfo* cur_addr = servinfo; sockfd_ == -1 && cur_addr != nullptr;
+ cur_addr = cur_addr->ai_next) {
+ sockfd_ = socket(
+ cur_addr->ai_family, cur_addr->ai_socktype, cur_addr->ai_protocol);
+ if (sockfd_ != -1) {
+ // Connect the client socket to the server socket.
+ if (connect(sockfd_, cur_addr->ai_addr, cur_addr->ai_addrlen) == -1) {
+ close(sockfd_);
+ sockfd_ = -1;
+ }
+ }
+ }
+
+ freeaddrinfo(servinfo); // all done with this structure
+
+ if (sockfd_ == -1) {
+ GTEST_LOG_(WARNING) << "stream_result_to: failed to connect to "
+ << host_name_ << ":" << port_num_;
+ }
+}
+
+// End of class Streaming Listener
+#endif // GTEST_CAN_STREAM_RESULTS__
+
+// class OsStackTraceGetter
+
+const char* const OsStackTraceGetterInterface::kElidedFramesMarker =
+ "... " GTEST_NAME_ " internal frames ...";
+
+std::string OsStackTraceGetter::CurrentStackTrace(int max_depth, int skip_count)
+ GTEST_LOCK_EXCLUDED_(mutex_) {
+#if GTEST_HAS_ABSL
+ std::string result;
+
+ if (max_depth <= 0) {
+ return result;
+ }
+
+ max_depth = std::min(max_depth, kMaxStackTraceDepth);
+
+ std::vector<void*> raw_stack(max_depth);
+ // Skips the frames requested by the caller, plus this function.
+ const int raw_stack_size =
+ absl::GetStackTrace(&raw_stack[0], max_depth, skip_count + 1);
+
+ void* caller_frame = nullptr;
+ {
+ MutexLock lock(&mutex_);
+ caller_frame = caller_frame_;
+ }
+
+ for (int i = 0; i < raw_stack_size; ++i) {
+ if (raw_stack[i] == caller_frame &&
+ !GTEST_FLAG(show_internal_stack_frames)) {
+ // Add a marker to the trace and stop adding frames.
+ absl::StrAppend(&result, kElidedFramesMarker, "\n");
+ break;
+ }
+
+ char tmp[1024];
+ const char* symbol = "(unknown)";
+ if (absl::Symbolize(raw_stack[i], tmp, sizeof(tmp))) {
+ symbol = tmp;
+ }
+
+ char line[1024];
+ snprintf(line, sizeof(line), " %p: %s\n", raw_stack[i], symbol);
+ result += line;
+ }
+
+ return result;
+
+#else // !GTEST_HAS_ABSL
+ static_cast<void>(max_depth);
+ static_cast<void>(skip_count);
+ return "";
+#endif // GTEST_HAS_ABSL
+}
+
+void OsStackTraceGetter::UponLeavingGTest() GTEST_LOCK_EXCLUDED_(mutex_) {
+#if GTEST_HAS_ABSL
+ void* caller_frame = nullptr;
+ if (absl::GetStackTrace(&caller_frame, 1, 3) <= 0) {
+ caller_frame = nullptr;
+ }
+
+ MutexLock lock(&mutex_);
+ caller_frame_ = caller_frame;
+#endif // GTEST_HAS_ABSL
+}
+
+// A helper class that creates the premature-exit file in its
+// constructor and deletes the file in its destructor.
+class ScopedPrematureExitFile {
+ public:
+ explicit ScopedPrematureExitFile(const char* premature_exit_filepath)
+ : premature_exit_filepath_(premature_exit_filepath ?
+ premature_exit_filepath : "") {
+ // If a path to the premature-exit file is specified...
+ if (!premature_exit_filepath_.empty()) {
+ // create the file with a single "0" character in it. I/O
+ // errors are ignored as there's nothing better we can do and we
+ // don't want to fail the test because of this.
+ FILE* pfile = posix::FOpen(premature_exit_filepath, "w");
+ fwrite("0", 1, 1, pfile);
+ fclose(pfile);
+ }
+ }
+
+ ~ScopedPrematureExitFile() {
+#if !defined GTEST_OS_ESP8266
+ if (!premature_exit_filepath_.empty()) {
+ int retval = remove(premature_exit_filepath_.c_str());
+ if (retval) {
+ GTEST_LOG_(ERROR) << "Failed to remove premature exit filepath \""
+ << premature_exit_filepath_ << "\" with error "
+ << retval;
+ }
+ }
+#endif
+ }
+
+ private:
+ const std::string premature_exit_filepath_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedPrematureExitFile);
+};
+
+} // namespace internal
+
+// class TestEventListeners
+
+TestEventListeners::TestEventListeners()
+ : repeater_(new internal::TestEventRepeater()),
+ default_result_printer_(nullptr),
+ default_xml_generator_(nullptr) {}
+
+TestEventListeners::~TestEventListeners() { delete repeater_; }
+
+// Returns the standard listener responsible for the default console
+// output. Can be removed from the listeners list to shut down default
+// console output. Note that removing this object from the listener list
+// with Release transfers its ownership to the user.
+void TestEventListeners::Append(TestEventListener* listener) {
+ repeater_->Append(listener);
+}
+
+// Removes the given event listener from the list and returns it. It then
+// becomes the caller's responsibility to delete the listener. Returns
+// NULL if the listener is not found in the list.
+TestEventListener* TestEventListeners::Release(TestEventListener* listener) {
+ if (listener == default_result_printer_)
+ default_result_printer_ = nullptr;
+ else if (listener == default_xml_generator_)
+ default_xml_generator_ = nullptr;
+ return repeater_->Release(listener);
+}
+
+// Returns repeater that broadcasts the TestEventListener events to all
+// subscribers.
+TestEventListener* TestEventListeners::repeater() { return repeater_; }
+
+// Sets the default_result_printer attribute to the provided listener.
+// The listener is also added to the listener list and previous
+// default_result_printer is removed from it and deleted. The listener can
+// also be NULL in which case it will not be added to the list. Does
+// nothing if the previous and the current listener objects are the same.
+void TestEventListeners::SetDefaultResultPrinter(TestEventListener* listener) {
+ if (default_result_printer_ != listener) {
+ // It is an error to pass this method a listener that is already in the
+ // list.
+ delete Release(default_result_printer_);
+ default_result_printer_ = listener;
+ if (listener != nullptr) Append(listener);
+ }
+}
+
+// Sets the default_xml_generator attribute to the provided listener. The
+// listener is also added to the listener list and previous
+// default_xml_generator is removed from it and deleted. The listener can
+// also be NULL in which case it will not be added to the list. Does
+// nothing if the previous and the current listener objects are the same.
+void TestEventListeners::SetDefaultXmlGenerator(TestEventListener* listener) {
+ if (default_xml_generator_ != listener) {
+ // It is an error to pass this method a listener that is already in the
+ // list.
+ delete Release(default_xml_generator_);
+ default_xml_generator_ = listener;
+ if (listener != nullptr) Append(listener);
+ }
+}
+
+// Controls whether events will be forwarded by the repeater to the
+// listeners in the list.
+bool TestEventListeners::EventForwardingEnabled() const {
+ return repeater_->forwarding_enabled();
+}
+
+void TestEventListeners::SuppressEventForwarding() {
+ repeater_->set_forwarding_enabled(false);
+}
+
+// class UnitTest
+
+// Gets the singleton UnitTest object. The first time this method is
+// called, a UnitTest object is constructed and returned. Consecutive
+// calls will return the same object.
+//
+// We don't protect this under mutex_ as a user is not supposed to
+// call this before main() starts, from which point on the return
+// value will never change.
+UnitTest* UnitTest::GetInstance() {
+ // CodeGear C++Builder insists on a public destructor for the
+ // default implementation. Use this implementation to keep good OO
+ // design with private destructor.
+
+#if defined(__BORLANDC__)
+ static UnitTest* const instance = new UnitTest;
+ return instance;
+#else
+ static UnitTest instance;
+ return &instance;
+#endif // defined(__BORLANDC__)
+}
+
+// Gets the number of successful test suites.
+int UnitTest::successful_test_suite_count() const {
+ return impl()->successful_test_suite_count();
+}
+
+// Gets the number of failed test suites.
+int UnitTest::failed_test_suite_count() const {
+ return impl()->failed_test_suite_count();
+}
+
+// Gets the number of all test suites.
+int UnitTest::total_test_suite_count() const {
+ return impl()->total_test_suite_count();
+}
+
+// Gets the number of all test suites that contain at least one test
+// that should run.
+int UnitTest::test_suite_to_run_count() const {
+ return impl()->test_suite_to_run_count();
+}
+
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+int UnitTest::successful_test_case_count() const {
+ return impl()->successful_test_suite_count();
+}
+int UnitTest::failed_test_case_count() const {
+ return impl()->failed_test_suite_count();
+}
+int UnitTest::total_test_case_count() const {
+ return impl()->total_test_suite_count();
+}
+int UnitTest::test_case_to_run_count() const {
+ return impl()->test_suite_to_run_count();
+}
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+// Gets the number of successful tests.
+int UnitTest::successful_test_count() const {
+ return impl()->successful_test_count();
+}
+
+// Gets the number of skipped tests.
+int UnitTest::skipped_test_count() const {
+ return impl()->skipped_test_count();
+}
+
+// Gets the number of failed tests.
+int UnitTest::failed_test_count() const { return impl()->failed_test_count(); }
+
+// Gets the number of disabled tests that will be reported in the XML report.
+int UnitTest::reportable_disabled_test_count() const {
+ return impl()->reportable_disabled_test_count();
+}
+
+// Gets the number of disabled tests.
+int UnitTest::disabled_test_count() const {
+ return impl()->disabled_test_count();
+}
+
+// Gets the number of tests to be printed in the XML report.
+int UnitTest::reportable_test_count() const {
+ return impl()->reportable_test_count();
+}
+
+// Gets the number of all tests.
+int UnitTest::total_test_count() const { return impl()->total_test_count(); }
+
+// Gets the number of tests that should run.
+int UnitTest::test_to_run_count() const { return impl()->test_to_run_count(); }
+
+// Gets the time of the test program start, in ms from the start of the
+// UNIX epoch.
+internal::TimeInMillis UnitTest::start_timestamp() const {
+ return impl()->start_timestamp();
+}
+
+// Gets the elapsed time, in milliseconds.
+internal::TimeInMillis UnitTest::elapsed_time() const {
+ return impl()->elapsed_time();
+}
+
+// Returns true if and only if the unit test passed (i.e. all test suites
+// passed).
+bool UnitTest::Passed() const { return impl()->Passed(); }
+
+// Returns true if and only if the unit test failed (i.e. some test suite
+// failed or something outside of all tests failed).
+bool UnitTest::Failed() const { return impl()->Failed(); }
+
+// Gets the i-th test suite among all the test suites. i can range from 0 to
+// total_test_suite_count() - 1. If i is not in that range, returns NULL.
+const TestSuite* UnitTest::GetTestSuite(int i) const {
+ return impl()->GetTestSuite(i);
+}
+
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+const TestCase* UnitTest::GetTestCase(int i) const {
+ return impl()->GetTestCase(i);
+}
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+// Returns the TestResult containing information on test failures and
+// properties logged outside of individual test suites.
+const TestResult& UnitTest::ad_hoc_test_result() const {
+ return *impl()->ad_hoc_test_result();
+}
+
+// Gets the i-th test suite among all the test suites. i can range from 0 to
+// total_test_suite_count() - 1. If i is not in that range, returns NULL.
+TestSuite* UnitTest::GetMutableTestSuite(int i) {
+ return impl()->GetMutableSuiteCase(i);
+}
+
+// Returns the list of event listeners that can be used to track events
+// inside Google Test.
+TestEventListeners& UnitTest::listeners() {
+ return *impl()->listeners();
+}
+
+// Registers and returns a global test environment. When a test
+// program is run, all global test environments will be set-up in the
+// order they were registered. After all tests in the program have
+// finished, all global test environments will be torn-down in the
+// *reverse* order they were registered.
+//
+// The UnitTest object takes ownership of the given environment.
+//
+// We don't protect this under mutex_, as we only support calling it
+// from the main thread.
+Environment* UnitTest::AddEnvironment(Environment* env) {
+ if (env == nullptr) {
+ return nullptr;
+ }
+
+ impl_->environments().push_back(env);
+ return env;
+}
+
+// Adds a TestPartResult to the current TestResult object. All Google Test
+// assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) eventually call
+// this to report their results. The user code should use the
+// assertion macros instead of calling this directly.
+void UnitTest::AddTestPartResult(
+ TestPartResult::Type result_type,
+ const char* file_name,
+ int line_number,
+ const std::string& message,
+ const std::string& os_stack_trace) GTEST_LOCK_EXCLUDED_(mutex_) {
+ Message msg;
+ msg << message;
+
+ internal::MutexLock lock(&mutex_);
+ if (impl_->gtest_trace_stack().size() > 0) {
+ msg << "\n" << GTEST_NAME_ << " trace:";
+
+ for (size_t i = impl_->gtest_trace_stack().size(); i > 0; --i) {
+ const internal::TraceInfo& trace = impl_->gtest_trace_stack()[i - 1];
+ msg << "\n" << internal::FormatFileLocation(trace.file, trace.line)
+ << " " << trace.message;
+ }
+ }
+
+ if (os_stack_trace.c_str() != nullptr && !os_stack_trace.empty()) {
+ msg << internal::kStackTraceMarker << os_stack_trace;
+ }
+
+ const TestPartResult result = TestPartResult(
+ result_type, file_name, line_number, msg.GetString().c_str());
+ impl_->GetTestPartResultReporterForCurrentThread()->
+ ReportTestPartResult(result);
+
+ if (result_type != TestPartResult::kSuccess &&
+ result_type != TestPartResult::kSkip) {
+ // gtest_break_on_failure takes precedence over
+ // gtest_throw_on_failure. This allows a user to set the latter
+ // in the code (perhaps in order to use Google Test assertions
+ // with another testing framework) and specify the former on the
+ // command line for debugging.
+ if (GTEST_FLAG(break_on_failure)) {
+#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT
+ // Using DebugBreak on Windows allows gtest to still break into a debugger
+ // when a failure happens and both the --gtest_break_on_failure and
+ // the --gtest_catch_exceptions flags are specified.
+ DebugBreak();
+#elif (!defined(__native_client__)) && \
+ ((defined(__clang__) || defined(__GNUC__)) && \
+ (defined(__x86_64__) || defined(__i386__)))
+ // with clang/gcc we can achieve the same effect on x86 by invoking int3
+ asm("int3");
+#else
+ // Dereference nullptr through a volatile pointer to prevent the compiler
+ // from removing. We use this rather than abort() or __builtin_trap() for
+ // portability: some debuggers don't correctly trap abort().
+ *static_cast<volatile int*>(nullptr) = 1;
+#endif // GTEST_OS_WINDOWS
+ } else if (GTEST_FLAG(throw_on_failure)) {
+#if GTEST_HAS_EXCEPTIONS
+ throw internal::GoogleTestFailureException(result);
+#else
+ // We cannot call abort() as it generates a pop-up in debug mode
+ // that cannot be suppressed in VC 7.1 or below.
+ exit(1);
+#endif
+ }
+ }
+}
+
+// Adds a TestProperty to the current TestResult object when invoked from
+// inside a test, to current TestSuite's ad_hoc_test_result_ when invoked
+// from SetUpTestSuite or TearDownTestSuite, or to the global property set
+// when invoked elsewhere. If the result already contains a property with
+// the same key, the value will be updated.
+void UnitTest::RecordProperty(const std::string& key,
+ const std::string& value) {
+ impl_->RecordProperty(TestProperty(key, value));
+}
+
+// Runs all tests in this UnitTest object and prints the result.
+// Returns 0 if successful, or 1 otherwise.
+//
+// We don't protect this under mutex_, as we only support calling it
+// from the main thread.
+int UnitTest::Run() {
+ const bool in_death_test_child_process =
+ internal::GTEST_FLAG(internal_run_death_test).length() > 0;
+
+ // Google Test implements this protocol for catching that a test
+ // program exits before returning control to Google Test:
+ //
+ // 1. Upon start, Google Test creates a file whose absolute path
+ // is specified by the environment variable
+ // TEST_PREMATURE_EXIT_FILE.
+ // 2. When Google Test has finished its work, it deletes the file.
+ //
+ // This allows a test runner to set TEST_PREMATURE_EXIT_FILE before
+ // running a Google-Test-based test program and check the existence
+ // of the file at the end of the test execution to see if it has
+ // exited prematurely.
+
+ // If we are in the child process of a death test, don't
+ // create/delete the premature exit file, as doing so is unnecessary
+ // and will confuse the parent process. Otherwise, create/delete
+ // the file upon entering/leaving this function. If the program
+ // somehow exits before this function has a chance to return, the
+ // premature-exit file will be left undeleted, causing a test runner
+ // that understands the premature-exit-file protocol to report the
+ // test as having failed.
+ const internal::ScopedPrematureExitFile premature_exit_file(
+ in_death_test_child_process
+ ? nullptr
+ : internal::posix::GetEnv("TEST_PREMATURE_EXIT_FILE"));
+
+ // Captures the value of GTEST_FLAG(catch_exceptions). This value will be
+ // used for the duration of the program.
+ impl()->set_catch_exceptions(GTEST_FLAG(catch_exceptions));
+
+#if GTEST_OS_WINDOWS
+ // Either the user wants Google Test to catch exceptions thrown by the
+ // tests or this is executing in the context of death test child
+ // process. In either case the user does not want to see pop-up dialogs
+ // about crashes - they are expected.
+ if (impl()->catch_exceptions() || in_death_test_child_process) {
+# if !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT
+ // SetErrorMode doesn't exist on CE.
+ SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT |
+ SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);
+# endif // !GTEST_OS_WINDOWS_MOBILE
+
+# if (defined(_MSC_VER) || GTEST_OS_WINDOWS_MINGW) && !GTEST_OS_WINDOWS_MOBILE
+ // Death test children can be terminated with _abort(). On Windows,
+ // _abort() can show a dialog with a warning message. This forces the
+ // abort message to go to stderr instead.
+ _set_error_mode(_OUT_TO_STDERR);
+# endif
+
+# if defined(_MSC_VER) && !GTEST_OS_WINDOWS_MOBILE
+ // In the debug version, Visual Studio pops up a separate dialog
+ // offering a choice to debug the aborted program. We need to suppress
+ // this dialog or it will pop up for every EXPECT/ASSERT_DEATH statement
+ // executed. Google Test will notify the user of any unexpected
+ // failure via stderr.
+ if (!GTEST_FLAG(break_on_failure))
+ _set_abort_behavior(
+ 0x0, // Clear the following flags:
+ _WRITE_ABORT_MSG | _CALL_REPORTFAULT); // pop-up window, core dump.
+
+ // In debug mode, the Windows CRT can crash with an assertion over invalid
+ // input (e.g. passing an invalid file descriptor). The default handling
+ // for these assertions is to pop up a dialog and wait for user input.
+ // Instead ask the CRT to dump such assertions to stderr non-interactively.
+ if (!IsDebuggerPresent()) {
+ (void)_CrtSetReportMode(_CRT_ASSERT,
+ _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
+ (void)_CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
+ }
+# endif
+ }
+#endif // GTEST_OS_WINDOWS
+
+ return internal::HandleExceptionsInMethodIfSupported(
+ impl(),
+ &internal::UnitTestImpl::RunAllTests,
+ "auxiliary test code (environments or event listeners)") ? 0 : 1;
+}
+
+// Returns the working directory when the first TEST() or TEST_F() was
+// executed.
+const char* UnitTest::original_working_dir() const {
+ return impl_->original_working_dir_.c_str();
+}
+
+// Returns the TestSuite object for the test that's currently running,
+// or NULL if no test is running.
+const TestSuite* UnitTest::current_test_suite() const
+ GTEST_LOCK_EXCLUDED_(mutex_) {
+ internal::MutexLock lock(&mutex_);
+ return impl_->current_test_suite();
+}
+
+// Legacy API is still available but deprecated
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+const TestCase* UnitTest::current_test_case() const
+ GTEST_LOCK_EXCLUDED_(mutex_) {
+ internal::MutexLock lock(&mutex_);
+ return impl_->current_test_suite();
+}
+#endif
+
+// Returns the TestInfo object for the test that's currently running,
+// or NULL if no test is running.
+const TestInfo* UnitTest::current_test_info() const
+ GTEST_LOCK_EXCLUDED_(mutex_) {
+ internal::MutexLock lock(&mutex_);
+ return impl_->current_test_info();
+}
+
+// Returns the random seed used at the start of the current test run.
+int UnitTest::random_seed() const { return impl_->random_seed(); }
+
+// Returns ParameterizedTestSuiteRegistry object used to keep track of
+// value-parameterized tests and instantiate and register them.
+internal::ParameterizedTestSuiteRegistry&
+UnitTest::parameterized_test_registry() GTEST_LOCK_EXCLUDED_(mutex_) {
+ return impl_->parameterized_test_registry();
+}
+
+// Creates an empty UnitTest.
+UnitTest::UnitTest() {
+ impl_ = new internal::UnitTestImpl(this);
+}
+
+// Destructor of UnitTest.
+UnitTest::~UnitTest() {
+ delete impl_;
+}
+
+// Pushes a trace defined by SCOPED_TRACE() on to the per-thread
+// Google Test trace stack.
+void UnitTest::PushGTestTrace(const internal::TraceInfo& trace)
+ GTEST_LOCK_EXCLUDED_(mutex_) {
+ internal::MutexLock lock(&mutex_);
+ impl_->gtest_trace_stack().push_back(trace);
+}
+
+// Pops a trace from the per-thread Google Test trace stack.
+void UnitTest::PopGTestTrace()
+ GTEST_LOCK_EXCLUDED_(mutex_) {
+ internal::MutexLock lock(&mutex_);
+ impl_->gtest_trace_stack().pop_back();
+}
+
+namespace internal {
+
+UnitTestImpl::UnitTestImpl(UnitTest* parent)
+ : parent_(parent),
+ GTEST_DISABLE_MSC_WARNINGS_PUSH_(4355 /* using this in initializer */)
+ default_global_test_part_result_reporter_(this),
+ default_per_thread_test_part_result_reporter_(this),
+ GTEST_DISABLE_MSC_WARNINGS_POP_() global_test_part_result_repoter_(
+ &default_global_test_part_result_reporter_),
+ per_thread_test_part_result_reporter_(
+ &default_per_thread_test_part_result_reporter_),
+ parameterized_test_registry_(),
+ parameterized_tests_registered_(false),
+ last_death_test_suite_(-1),
+ current_test_suite_(nullptr),
+ current_test_info_(nullptr),
+ ad_hoc_test_result_(),
+ os_stack_trace_getter_(nullptr),
+ post_flag_parse_init_performed_(false),
+ random_seed_(0), // Will be overridden by the flag before first use.
+ random_(0), // Will be reseeded before first use.
+ start_timestamp_(0),
+ elapsed_time_(0),
+#if GTEST_HAS_DEATH_TEST
+ death_test_factory_(new DefaultDeathTestFactory),
+#endif
+ // Will be overridden by the flag before first use.
+ catch_exceptions_(false) {
+ listeners()->SetDefaultResultPrinter(new PrettyUnitTestResultPrinter);
+}
+
+UnitTestImpl::~UnitTestImpl() {
+ // Deletes every TestSuite.
+ ForEach(test_suites_, internal::Delete<TestSuite>);
+
+ // Deletes every Environment.
+ ForEach(environments_, internal::Delete<Environment>);
+
+ delete os_stack_trace_getter_;
+}
+
+// Adds a TestProperty to the current TestResult object when invoked in a
+// context of a test, to current test suite's ad_hoc_test_result when invoke
+// from SetUpTestSuite/TearDownTestSuite, or to the global property set
+// otherwise. If the result already contains a property with the same key,
+// the value will be updated.
+void UnitTestImpl::RecordProperty(const TestProperty& test_property) {
+ std::string xml_element;
+ TestResult* test_result; // TestResult appropriate for property recording.
+
+ if (current_test_info_ != nullptr) {
+ xml_element = "testcase";
+ test_result = &(current_test_info_->result_);
+ } else if (current_test_suite_ != nullptr) {
+ xml_element = "testsuite";
+ test_result = &(current_test_suite_->ad_hoc_test_result_);
+ } else {
+ xml_element = "testsuites";
+ test_result = &ad_hoc_test_result_;
+ }
+ test_result->RecordProperty(xml_element, test_property);
+}
+
+#if GTEST_HAS_DEATH_TEST
+// Disables event forwarding if the control is currently in a death test
+// subprocess. Must not be called before InitGoogleTest.
+void UnitTestImpl::SuppressTestEventsIfInSubprocess() {
+ if (internal_run_death_test_flag_.get() != nullptr)
+ listeners()->SuppressEventForwarding();
+}
+#endif // GTEST_HAS_DEATH_TEST
+
+// Initializes event listeners performing XML output as specified by
+// UnitTestOptions. Must not be called before InitGoogleTest.
+void UnitTestImpl::ConfigureXmlOutput() {
+ const std::string& output_format = UnitTestOptions::GetOutputFormat();
+ if (output_format == "xml") {
+ listeners()->SetDefaultXmlGenerator(new XmlUnitTestResultPrinter(
+ UnitTestOptions::GetAbsolutePathToOutputFile().c_str()));
+ } else if (output_format == "json") {
+ listeners()->SetDefaultXmlGenerator(new JsonUnitTestResultPrinter(
+ UnitTestOptions::GetAbsolutePathToOutputFile().c_str()));
+ } else if (output_format != "") {
+ GTEST_LOG_(WARNING) << "WARNING: unrecognized output format \""
+ << output_format << "\" ignored.";
+ }
+}
+
+#if GTEST_CAN_STREAM_RESULTS_
+// Initializes event listeners for streaming test results in string form.
+// Must not be called before InitGoogleTest.
+void UnitTestImpl::ConfigureStreamingOutput() {
+ const std::string& target = GTEST_FLAG(stream_result_to);
+ if (!target.empty()) {
+ const size_t pos = target.find(':');
+ if (pos != std::string::npos) {
+ listeners()->Append(new StreamingListener(target.substr(0, pos),
+ target.substr(pos+1)));
+ } else {
+ GTEST_LOG_(WARNING) << "unrecognized streaming target \"" << target
+ << "\" ignored.";
+ }
+ }
+}
+#endif // GTEST_CAN_STREAM_RESULTS_
+
+// Performs initialization dependent upon flag values obtained in
+// ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to
+// ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest
+// this function is also called from RunAllTests. Since this function can be
+// called more than once, it has to be idempotent.
+void UnitTestImpl::PostFlagParsingInit() {
+ // Ensures that this function does not execute more than once.
+ if (!post_flag_parse_init_performed_) {
+ post_flag_parse_init_performed_ = true;
+
+#if defined(GTEST_CUSTOM_TEST_EVENT_LISTENER_)
+ // Register to send notifications about key process state changes.
+ listeners()->Append(new GTEST_CUSTOM_TEST_EVENT_LISTENER_());
+#endif // defined(GTEST_CUSTOM_TEST_EVENT_LISTENER_)
+
+#if GTEST_HAS_DEATH_TEST
+ InitDeathTestSubprocessControlInfo();
+ SuppressTestEventsIfInSubprocess();
+#endif // GTEST_HAS_DEATH_TEST
+
+ // Registers parameterized tests. This makes parameterized tests
+ // available to the UnitTest reflection API without running
+ // RUN_ALL_TESTS.
+ RegisterParameterizedTests();
+
+ // Configures listeners for XML output. This makes it possible for users
+ // to shut down the default XML output before invoking RUN_ALL_TESTS.
+ ConfigureXmlOutput();
+
+ if (GTEST_FLAG(brief)) {
+ listeners()->SetDefaultResultPrinter(new BriefUnitTestResultPrinter);
+ }
+
+#if GTEST_CAN_STREAM_RESULTS_
+ // Configures listeners for streaming test results to the specified server.
+ ConfigureStreamingOutput();
+#endif // GTEST_CAN_STREAM_RESULTS_
+
+#if GTEST_HAS_ABSL
+ if (GTEST_FLAG(install_failure_signal_handler)) {
+ absl::FailureSignalHandlerOptions options;
+ absl::InstallFailureSignalHandler(options);
+ }
+#endif // GTEST_HAS_ABSL
+ }
+}
+
+// A predicate that checks the name of a TestSuite against a known
+// value.
+//
+// This is used for implementation of the UnitTest class only. We put
+// it in the anonymous namespace to prevent polluting the outer
+// namespace.
+//
+// TestSuiteNameIs is copyable.
+class TestSuiteNameIs {
+ public:
+ // Constructor.
+ explicit TestSuiteNameIs(const std::string& name) : name_(name) {}
+
+ // Returns true if and only if the name of test_suite matches name_.
+ bool operator()(const TestSuite* test_suite) const {
+ return test_suite != nullptr &&
+ strcmp(test_suite->name(), name_.c_str()) == 0;
+ }
+
+ private:
+ std::string name_;
+};
+
+// Finds and returns a TestSuite with the given name. If one doesn't
+// exist, creates one and returns it. It's the CALLER'S
+// RESPONSIBILITY to ensure that this function is only called WHEN THE
+// TESTS ARE NOT SHUFFLED.
+//
+// Arguments:
+//
+// test_suite_name: name of the test suite
+// type_param: the name of the test suite's type parameter, or NULL if
+// this is not a typed or a type-parameterized test suite.
+// set_up_tc: pointer to the function that sets up the test suite
+// tear_down_tc: pointer to the function that tears down the test suite
+TestSuite* UnitTestImpl::GetTestSuite(
+ const char* test_suite_name, const char* type_param,
+ internal::SetUpTestSuiteFunc set_up_tc,
+ internal::TearDownTestSuiteFunc tear_down_tc) {
+ // Can we find a TestSuite with the given name?
+ const auto test_suite =
+ std::find_if(test_suites_.rbegin(), test_suites_.rend(),
+ TestSuiteNameIs(test_suite_name));
+
+ if (test_suite != test_suites_.rend()) return *test_suite;
+
+ // No. Let's create one.
+ auto* const new_test_suite =
+ new TestSuite(test_suite_name, type_param, set_up_tc, tear_down_tc);
+
+ // Is this a death test suite?
+ if (internal::UnitTestOptions::MatchesFilter(test_suite_name,
+ kDeathTestSuiteFilter)) {
+ // Yes. Inserts the test suite after the last death test suite
+ // defined so far. This only works when the test suites haven't
+ // been shuffled. Otherwise we may end up running a death test
+ // after a non-death test.
+ ++last_death_test_suite_;
+ test_suites_.insert(test_suites_.begin() + last_death_test_suite_,
+ new_test_suite);
+ } else {
+ // No. Appends to the end of the list.
+ test_suites_.push_back(new_test_suite);
+ }
+
+ test_suite_indices_.push_back(static_cast<int>(test_suite_indices_.size()));
+ return new_test_suite;
+}
+
+// Helpers for setting up / tearing down the given environment. They
+// are for use in the ForEach() function.
+static void SetUpEnvironment(Environment* env) { env->SetUp(); }
+static void TearDownEnvironment(Environment* env) { env->TearDown(); }
+
+// Runs all tests in this UnitTest object, prints the result, and
+// returns true if all tests are successful. If any exception is
+// thrown during a test, the test is considered to be failed, but the
+// rest of the tests will still be run.
+//
+// When parameterized tests are enabled, it expands and registers
+// parameterized tests first in RegisterParameterizedTests().
+// All other functions called from RunAllTests() may safely assume that
+// parameterized tests are ready to be counted and run.
+bool UnitTestImpl::RunAllTests() {
+ // True if and only if Google Test is initialized before RUN_ALL_TESTS() is
+ // called.
+ const bool gtest_is_initialized_before_run_all_tests = GTestIsInitialized();
+
+ // Do not run any test if the --help flag was specified.
+ if (g_help_flag)
+ return true;
+
+ // Repeats the call to the post-flag parsing initialization in case the
+ // user didn't call InitGoogleTest.
+ PostFlagParsingInit();
+
+ // Even if sharding is not on, test runners may want to use the
+ // GTEST_SHARD_STATUS_FILE to query whether the test supports the sharding
+ // protocol.
+ internal::WriteToShardStatusFileIfNeeded();
+
+ // True if and only if we are in a subprocess for running a thread-safe-style
+ // death test.
+ bool in_subprocess_for_death_test = false;
+
+#if GTEST_HAS_DEATH_TEST
+ in_subprocess_for_death_test =
+ (internal_run_death_test_flag_.get() != nullptr);
+# if defined(GTEST_EXTRA_DEATH_TEST_CHILD_SETUP_)
+ if (in_subprocess_for_death_test) {
+ GTEST_EXTRA_DEATH_TEST_CHILD_SETUP_();
+ }
+# endif // defined(GTEST_EXTRA_DEATH_TEST_CHILD_SETUP_)
+#endif // GTEST_HAS_DEATH_TEST
+
+ const bool should_shard = ShouldShard(kTestTotalShards, kTestShardIndex,
+ in_subprocess_for_death_test);
+
+ // Compares the full test names with the filter to decide which
+ // tests to run.
+ const bool has_tests_to_run = FilterTests(should_shard
+ ? HONOR_SHARDING_PROTOCOL
+ : IGNORE_SHARDING_PROTOCOL) > 0;
+
+ // Lists the tests and exits if the --gtest_list_tests flag was specified.
+ if (GTEST_FLAG(list_tests)) {
+ // This must be called *after* FilterTests() has been called.
+ ListTestsMatchingFilter();
+ return true;
+ }
+
+ random_seed_ = GTEST_FLAG(shuffle) ?
+ GetRandomSeedFromFlag(GTEST_FLAG(random_seed)) : 0;
+
+ // True if and only if at least one test has failed.
+ bool failed = false;
+
+ TestEventListener* repeater = listeners()->repeater();
+
+ start_timestamp_ = GetTimeInMillis();
+ repeater->OnTestProgramStart(*parent_);
+
+ // How many times to repeat the tests? We don't want to repeat them
+ // when we are inside the subprocess of a death test.
+ const int repeat = in_subprocess_for_death_test ? 1 : GTEST_FLAG(repeat);
+ // Repeats forever if the repeat count is negative.
+ const bool gtest_repeat_forever = repeat < 0;
+ for (int i = 0; gtest_repeat_forever || i != repeat; i++) {
+ // We want to preserve failures generated by ad-hoc test
+ // assertions executed before RUN_ALL_TESTS().
+ ClearNonAdHocTestResult();
+
+ Timer timer;
+
+ // Shuffles test suites and tests if requested.
+ if (has_tests_to_run && GTEST_FLAG(shuffle)) {
+ random()->Reseed(static_cast<uint32_t>(random_seed_));
+ // This should be done before calling OnTestIterationStart(),
+ // such that a test event listener can see the actual test order
+ // in the event.
+ ShuffleTests();
+ }
+
+ // Tells the unit test event listeners that the tests are about to start.
+ repeater->OnTestIterationStart(*parent_, i);
+
+ // Runs each test suite if there is at least one test to run.
+ if (has_tests_to_run) {
+ // Sets up all environments beforehand.
+ repeater->OnEnvironmentsSetUpStart(*parent_);
+ ForEach(environments_, SetUpEnvironment);
+ repeater->OnEnvironmentsSetUpEnd(*parent_);
+
+ // Runs the tests only if there was no fatal failure or skip triggered
+ // during global set-up.
+ if (Test::IsSkipped()) {
+ // Emit diagnostics when global set-up calls skip, as it will not be
+ // emitted by default.
+ TestResult& test_result =
+ *internal::GetUnitTestImpl()->current_test_result();
+ for (int j = 0; j < test_result.total_part_count(); ++j) {
+ const TestPartResult& test_part_result =
+ test_result.GetTestPartResult(j);
+ if (test_part_result.type() == TestPartResult::kSkip) {
+ const std::string& result = test_part_result.message();
+ printf("%s\n", result.c_str());
+ }
+ }
+ fflush(stdout);
+ } else if (!Test::HasFatalFailure()) {
+ for (int test_index = 0; test_index < total_test_suite_count();
+ test_index++) {
+ GetMutableSuiteCase(test_index)->Run();
+ if (GTEST_FLAG(fail_fast) &&
+ GetMutableSuiteCase(test_index)->Failed()) {
+ for (int j = test_index + 1; j < total_test_suite_count(); j++) {
+ GetMutableSuiteCase(j)->Skip();
+ }
+ break;
+ }
+ }
+ } else if (Test::HasFatalFailure()) {
+ // If there was a fatal failure during the global setup then we know we
+ // aren't going to run any tests. Explicitly mark all of the tests as
+ // skipped to make this obvious in the output.
+ for (int test_index = 0; test_index < total_test_suite_count();
+ test_index++) {
+ GetMutableSuiteCase(test_index)->Skip();
+ }
+ }
+
+ // Tears down all environments in reverse order afterwards.
+ repeater->OnEnvironmentsTearDownStart(*parent_);
+ std::for_each(environments_.rbegin(), environments_.rend(),
+ TearDownEnvironment);
+ repeater->OnEnvironmentsTearDownEnd(*parent_);
+ }
+
+ elapsed_time_ = timer.Elapsed();
+
+ // Tells the unit test event listener that the tests have just finished.
+ repeater->OnTestIterationEnd(*parent_, i);
+
+ // Gets the result and clears it.
+ if (!Passed()) {
+ failed = true;
+ }
+
+ // Restores the original test order after the iteration. This
+ // allows the user to quickly repro a failure that happens in the
+ // N-th iteration without repeating the first (N - 1) iterations.
+ // This is not enclosed in "if (GTEST_FLAG(shuffle)) { ... }", in
+ // case the user somehow changes the value of the flag somewhere
+ // (it's always safe to unshuffle the tests).
+ UnshuffleTests();
+
+ if (GTEST_FLAG(shuffle)) {
+ // Picks a new random seed for each iteration.
+ random_seed_ = GetNextRandomSeed(random_seed_);
+ }
+ }
+
+ repeater->OnTestProgramEnd(*parent_);
+
+ if (!gtest_is_initialized_before_run_all_tests) {
+ ColoredPrintf(
+ GTestColor::kRed,
+ "\nIMPORTANT NOTICE - DO NOT IGNORE:\n"
+ "This test program did NOT call " GTEST_INIT_GOOGLE_TEST_NAME_
+ "() before calling RUN_ALL_TESTS(). This is INVALID. Soon " GTEST_NAME_
+ " will start to enforce the valid usage. "
+ "Please fix it ASAP, or IT WILL START TO FAIL.\n"); // NOLINT
+#if GTEST_FOR_GOOGLE_
+ ColoredPrintf(GTestColor::kRed,
+ "For more details, see http://wiki/Main/ValidGUnitMain.\n");
+#endif // GTEST_FOR_GOOGLE_
+ }
+
+ return !failed;
+}
+
+// Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file
+// if the variable is present. If a file already exists at this location, this
+// function will write over it. If the variable is present, but the file cannot
+// be created, prints an error and exits.
+void WriteToShardStatusFileIfNeeded() {
+ const char* const test_shard_file = posix::GetEnv(kTestShardStatusFile);
+ if (test_shard_file != nullptr) {
+ FILE* const file = posix::FOpen(test_shard_file, "w");
+ if (file == nullptr) {
+ ColoredPrintf(GTestColor::kRed,
+ "Could not write to the test shard status file \"%s\" "
+ "specified by the %s environment variable.\n",
+ test_shard_file, kTestShardStatusFile);
+ fflush(stdout);
+ exit(EXIT_FAILURE);
+ }
+ fclose(file);
+ }
+}
+
+// Checks whether sharding is enabled by examining the relevant
+// environment variable values. If the variables are present,
+// but inconsistent (i.e., shard_index >= total_shards), prints
+// an error and exits. If in_subprocess_for_death_test, sharding is
+// disabled because it must only be applied to the original test
+// process. Otherwise, we could filter out death tests we intended to execute.
+bool ShouldShard(const char* total_shards_env,
+ const char* shard_index_env,
+ bool in_subprocess_for_death_test) {
+ if (in_subprocess_for_death_test) {
+ return false;
+ }
+
+ const int32_t total_shards = Int32FromEnvOrDie(total_shards_env, -1);
+ const int32_t shard_index = Int32FromEnvOrDie(shard_index_env, -1);
+
+ if (total_shards == -1 && shard_index == -1) {
+ return false;
+ } else if (total_shards == -1 && shard_index != -1) {
+ const Message msg = Message()
+ << "Invalid environment variables: you have "
+ << kTestShardIndex << " = " << shard_index
+ << ", but have left " << kTestTotalShards << " unset.\n";
+ ColoredPrintf(GTestColor::kRed, "%s", msg.GetString().c_str());
+ fflush(stdout);
+ exit(EXIT_FAILURE);
+ } else if (total_shards != -1 && shard_index == -1) {
+ const Message msg = Message()
+ << "Invalid environment variables: you have "
+ << kTestTotalShards << " = " << total_shards
+ << ", but have left " << kTestShardIndex << " unset.\n";
+ ColoredPrintf(GTestColor::kRed, "%s", msg.GetString().c_str());
+ fflush(stdout);
+ exit(EXIT_FAILURE);
+ } else if (shard_index < 0 || shard_index >= total_shards) {
+ const Message msg = Message()
+ << "Invalid environment variables: we require 0 <= "
+ << kTestShardIndex << " < " << kTestTotalShards
+ << ", but you have " << kTestShardIndex << "=" << shard_index
+ << ", " << kTestTotalShards << "=" << total_shards << ".\n";
+ ColoredPrintf(GTestColor::kRed, "%s", msg.GetString().c_str());
+ fflush(stdout);
+ exit(EXIT_FAILURE);
+ }
+
+ return total_shards > 1;
+}
+
+// Parses the environment variable var as an Int32. If it is unset,
+// returns default_val. If it is not an Int32, prints an error
+// and aborts.
+int32_t Int32FromEnvOrDie(const char* var, int32_t default_val) {
+ const char* str_val = posix::GetEnv(var);
+ if (str_val == nullptr) {
+ return default_val;
+ }
+
+ int32_t result;
+ if (!ParseInt32(Message() << "The value of environment variable " << var,
+ str_val, &result)) {
+ exit(EXIT_FAILURE);
+ }
+ return result;
+}
+
+// Given the total number of shards, the shard index, and the test id,
+// returns true if and only if the test should be run on this shard. The test id
+// is some arbitrary but unique non-negative integer assigned to each test
+// method. Assumes that 0 <= shard_index < total_shards.
+bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id) {
+ return (test_id % total_shards) == shard_index;
+}
+
+// Compares the name of each test with the user-specified filter to
+// decide whether the test should be run, then records the result in
+// each TestSuite and TestInfo object.
+// If shard_tests == true, further filters tests based on sharding
+// variables in the environment - see
+// https://github.com/google/googletest/blob/master/googletest/docs/advanced.md
+// . Returns the number of tests that should run.
+int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) {
+ const int32_t total_shards = shard_tests == HONOR_SHARDING_PROTOCOL ?
+ Int32FromEnvOrDie(kTestTotalShards, -1) : -1;
+ const int32_t shard_index = shard_tests == HONOR_SHARDING_PROTOCOL ?
+ Int32FromEnvOrDie(kTestShardIndex, -1) : -1;
+
+ // num_runnable_tests are the number of tests that will
+ // run across all shards (i.e., match filter and are not disabled).
+ // num_selected_tests are the number of tests to be run on
+ // this shard.
+ int num_runnable_tests = 0;
+ int num_selected_tests = 0;
+ for (auto* test_suite : test_suites_) {
+ const std::string& test_suite_name = test_suite->name();
+ test_suite->set_should_run(false);
+
+ for (size_t j = 0; j < test_suite->test_info_list().size(); j++) {
+ TestInfo* const test_info = test_suite->test_info_list()[j];
+ const std::string test_name(test_info->name());
+ // A test is disabled if test suite name or test name matches
+ // kDisableTestFilter.
+ const bool is_disabled = internal::UnitTestOptions::MatchesFilter(
+ test_suite_name, kDisableTestFilter) ||
+ internal::UnitTestOptions::MatchesFilter(
+ test_name, kDisableTestFilter);
+ test_info->is_disabled_ = is_disabled;
+
+ const bool matches_filter = internal::UnitTestOptions::FilterMatchesTest(
+ test_suite_name, test_name);
+ test_info->matches_filter_ = matches_filter;
+
+ const bool is_runnable =
+ (GTEST_FLAG(also_run_disabled_tests) || !is_disabled) &&
+ matches_filter;
+
+ const bool is_in_another_shard =
+ shard_tests != IGNORE_SHARDING_PROTOCOL &&
+ !ShouldRunTestOnShard(total_shards, shard_index, num_runnable_tests);
+ test_info->is_in_another_shard_ = is_in_another_shard;
+ const bool is_selected = is_runnable && !is_in_another_shard;
+
+ num_runnable_tests += is_runnable;
+ num_selected_tests += is_selected;
+
+ test_info->should_run_ = is_selected;
+ test_suite->set_should_run(test_suite->should_run() || is_selected);
+ }
+ }
+ return num_selected_tests;
+}
+
+// Prints the given C-string on a single line by replacing all '\n'
+// characters with string "\\n". If the output takes more than
+// max_length characters, only prints the first max_length characters
+// and "...".
+static void PrintOnOneLine(const char* str, int max_length) {
+ if (str != nullptr) {
+ for (int i = 0; *str != '\0'; ++str) {
+ if (i >= max_length) {
+ printf("...");
+ break;
+ }
+ if (*str == '\n') {
+ printf("\\n");
+ i += 2;
+ } else {
+ printf("%c", *str);
+ ++i;
+ }
+ }
+ }
+}
+
+// Prints the names of the tests matching the user-specified filter flag.
+void UnitTestImpl::ListTestsMatchingFilter() {
+ // Print at most this many characters for each type/value parameter.
+ const int kMaxParamLength = 250;
+
+ for (auto* test_suite : test_suites_) {
+ bool printed_test_suite_name = false;
+
+ for (size_t j = 0; j < test_suite->test_info_list().size(); j++) {
+ const TestInfo* const test_info = test_suite->test_info_list()[j];
+ if (test_info->matches_filter_) {
+ if (!printed_test_suite_name) {
+ printed_test_suite_name = true;
+ printf("%s.", test_suite->name());
+ if (test_suite->type_param() != nullptr) {
+ printf(" # %s = ", kTypeParamLabel);
+ // We print the type parameter on a single line to make
+ // the output easy to parse by a program.
+ PrintOnOneLine(test_suite->type_param(), kMaxParamLength);
+ }
+ printf("\n");
+ }
+ printf(" %s", test_info->name());
+ if (test_info->value_param() != nullptr) {
+ printf(" # %s = ", kValueParamLabel);
+ // We print the value parameter on a single line to make the
+ // output easy to parse by a program.
+ PrintOnOneLine(test_info->value_param(), kMaxParamLength);
+ }
+ printf("\n");
+ }
+ }
+ }
+ fflush(stdout);
+ const std::string& output_format = UnitTestOptions::GetOutputFormat();
+ if (output_format == "xml" || output_format == "json") {
+ FILE* fileout = OpenFileForWriting(
+ UnitTestOptions::GetAbsolutePathToOutputFile().c_str());
+ std::stringstream stream;
+ if (output_format == "xml") {
+ XmlUnitTestResultPrinter(
+ UnitTestOptions::GetAbsolutePathToOutputFile().c_str())
+ .PrintXmlTestsList(&stream, test_suites_);
+ } else if (output_format == "json") {
+ JsonUnitTestResultPrinter(
+ UnitTestOptions::GetAbsolutePathToOutputFile().c_str())
+ .PrintJsonTestList(&stream, test_suites_);
+ }
+ fprintf(fileout, "%s", StringStreamToString(&stream).c_str());
+ fclose(fileout);
+ }
+}
+
+// Sets the OS stack trace getter.
+//
+// Does nothing if the input and the current OS stack trace getter are
+// the same; otherwise, deletes the old getter and makes the input the
+// current getter.
+void UnitTestImpl::set_os_stack_trace_getter(
+ OsStackTraceGetterInterface* getter) {
+ if (os_stack_trace_getter_ != getter) {
+ delete os_stack_trace_getter_;
+ os_stack_trace_getter_ = getter;
+ }
+}
+
+// Returns the current OS stack trace getter if it is not NULL;
+// otherwise, creates an OsStackTraceGetter, makes it the current
+// getter, and returns it.
+OsStackTraceGetterInterface* UnitTestImpl::os_stack_trace_getter() {
+ if (os_stack_trace_getter_ == nullptr) {
+#ifdef GTEST_OS_STACK_TRACE_GETTER_
+ os_stack_trace_getter_ = new GTEST_OS_STACK_TRACE_GETTER_;
+#else
+ os_stack_trace_getter_ = new OsStackTraceGetter;
+#endif // GTEST_OS_STACK_TRACE_GETTER_
+ }
+
+ return os_stack_trace_getter_;
+}
+
+// Returns the most specific TestResult currently running.
+TestResult* UnitTestImpl::current_test_result() {
+ if (current_test_info_ != nullptr) {
+ return &current_test_info_->result_;
+ }
+ if (current_test_suite_ != nullptr) {
+ return &current_test_suite_->ad_hoc_test_result_;
+ }
+ return &ad_hoc_test_result_;
+}
+
+// Shuffles all test suites, and the tests within each test suite,
+// making sure that death tests are still run first.
+void UnitTestImpl::ShuffleTests() {
+ // Shuffles the death test suites.
+ ShuffleRange(random(), 0, last_death_test_suite_ + 1, &test_suite_indices_);
+
+ // Shuffles the non-death test suites.
+ ShuffleRange(random(), last_death_test_suite_ + 1,
+ static_cast<int>(test_suites_.size()), &test_suite_indices_);
+
+ // Shuffles the tests inside each test suite.
+ for (auto& test_suite : test_suites_) {
+ test_suite->ShuffleTests(random());
+ }
+}
+
+// Restores the test suites and tests to their order before the first shuffle.
+void UnitTestImpl::UnshuffleTests() {
+ for (size_t i = 0; i < test_suites_.size(); i++) {
+ // Unshuffles the tests in each test suite.
+ test_suites_[i]->UnshuffleTests();
+ // Resets the index of each test suite.
+ test_suite_indices_[i] = static_cast<int>(i);
+ }
+}
+
+// Returns the current OS stack trace as an std::string.
+//
+// The maximum number of stack frames to be included is specified by
+// the gtest_stack_trace_depth flag. The skip_count parameter
+// specifies the number of top frames to be skipped, which doesn't
+// count against the number of frames to be included.
+//
+// For example, if Foo() calls Bar(), which in turn calls
+// GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in
+// the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't.
+std::string GetCurrentOsStackTraceExceptTop(UnitTest* /*unit_test*/,
+ int skip_count) {
+ // We pass skip_count + 1 to skip this wrapper function in addition
+ // to what the user really wants to skip.
+ return GetUnitTestImpl()->CurrentOsStackTraceExceptTop(skip_count + 1);
+}
+
+// Used by the GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_ macro to
+// suppress unreachable code warnings.
+namespace {
+class ClassUniqueToAlwaysTrue {};
+}
+
+bool IsTrue(bool condition) { return condition; }
+
+bool AlwaysTrue() {
+#if GTEST_HAS_EXCEPTIONS
+ // This condition is always false so AlwaysTrue() never actually throws,
+ // but it makes the compiler think that it may throw.
+ if (IsTrue(false))
+ throw ClassUniqueToAlwaysTrue();
+#endif // GTEST_HAS_EXCEPTIONS
+ return true;
+}
+
+// If *pstr starts with the given prefix, modifies *pstr to be right
+// past the prefix and returns true; otherwise leaves *pstr unchanged
+// and returns false. None of pstr, *pstr, and prefix can be NULL.
+bool SkipPrefix(const char* prefix, const char** pstr) {
+ const size_t prefix_len = strlen(prefix);
+ if (strncmp(*pstr, prefix, prefix_len) == 0) {
+ *pstr += prefix_len;
+ return true;
+ }
+ return false;
+}
+
+// Parses a string as a command line flag. The string should have
+// the format "--flag=value". When def_optional is true, the "=value"
+// part can be omitted.
+//
+// Returns the value of the flag, or NULL if the parsing failed.
+static const char* ParseFlagValue(const char* str, const char* flag,
+ bool def_optional) {
+ // str and flag must not be NULL.
+ if (str == nullptr || flag == nullptr) return nullptr;
+
+ // The flag must start with "--" followed by GTEST_FLAG_PREFIX_.
+ const std::string flag_str = std::string("--") + GTEST_FLAG_PREFIX_ + flag;
+ const size_t flag_len = flag_str.length();
+ if (strncmp(str, flag_str.c_str(), flag_len) != 0) return nullptr;
+
+ // Skips the flag name.
+ const char* flag_end = str + flag_len;
+
+ // When def_optional is true, it's OK to not have a "=value" part.
+ if (def_optional && (flag_end[0] == '\0')) {
+ return flag_end;
+ }
+
+ // If def_optional is true and there are more characters after the
+ // flag name, or if def_optional is false, there must be a '=' after
+ // the flag name.
+ if (flag_end[0] != '=') return nullptr;
+
+ // Returns the string after "=".
+ return flag_end + 1;
+}
+
+// Parses a string for a bool flag, in the form of either
+// "--flag=value" or "--flag".
+//
+// In the former case, the value is taken as true as long as it does
+// not start with '0', 'f', or 'F'.
+//
+// In the latter case, the value is taken as true.
+//
+// On success, stores the value of the flag in *value, and returns
+// true. On failure, returns false without changing *value.
+static bool ParseBoolFlag(const char* str, const char* flag, bool* value) {
+ // Gets the value of the flag as a string.
+ const char* const value_str = ParseFlagValue(str, flag, true);
+
+ // Aborts if the parsing failed.
+ if (value_str == nullptr) return false;
+
+ // Converts the string value to a bool.
+ *value = !(*value_str == '0' || *value_str == 'f' || *value_str == 'F');
+ return true;
+}
+
+// Parses a string for an int32_t flag, in the form of "--flag=value".
+//
+// On success, stores the value of the flag in *value, and returns
+// true. On failure, returns false without changing *value.
+bool ParseInt32Flag(const char* str, const char* flag, int32_t* value) {
+ // Gets the value of the flag as a string.
+ const char* const value_str = ParseFlagValue(str, flag, false);
+
+ // Aborts if the parsing failed.
+ if (value_str == nullptr) return false;
+
+ // Sets *value to the value of the flag.
+ return ParseInt32(Message() << "The value of flag --" << flag,
+ value_str, value);
+}
+
+// Parses a string for a string flag, in the form of "--flag=value".
+//
+// On success, stores the value of the flag in *value, and returns
+// true. On failure, returns false without changing *value.
+template <typename String>
+static bool ParseStringFlag(const char* str, const char* flag, String* value) {
+ // Gets the value of the flag as a string.
+ const char* const value_str = ParseFlagValue(str, flag, false);
+
+ // Aborts if the parsing failed.
+ if (value_str == nullptr) return false;
+
+ // Sets *value to the value of the flag.
+ *value = value_str;
+ return true;
+}
+
+// Determines whether a string has a prefix that Google Test uses for its
+// flags, i.e., starts with GTEST_FLAG_PREFIX_ or GTEST_FLAG_PREFIX_DASH_.
+// If Google Test detects that a command line flag has its prefix but is not
+// recognized, it will print its help message. Flags starting with
+// GTEST_INTERNAL_PREFIX_ followed by "internal_" are considered Google Test
+// internal flags and do not trigger the help message.
+static bool HasGoogleTestFlagPrefix(const char* str) {
+ return (SkipPrefix("--", &str) ||
+ SkipPrefix("-", &str) ||
+ SkipPrefix("/", &str)) &&
+ !SkipPrefix(GTEST_FLAG_PREFIX_ "internal_", &str) &&
+ (SkipPrefix(GTEST_FLAG_PREFIX_, &str) ||
+ SkipPrefix(GTEST_FLAG_PREFIX_DASH_, &str));
+}
+
+// Prints a string containing code-encoded text. The following escape
+// sequences can be used in the string to control the text color:
+//
+// @@ prints a single '@' character.
+// @R changes the color to red.
+// @G changes the color to green.
+// @Y changes the color to yellow.
+// @D changes to the default terminal text color.
+//
+static void PrintColorEncoded(const char* str) {
+ GTestColor color = GTestColor::kDefault; // The current color.
+
+ // Conceptually, we split the string into segments divided by escape
+ // sequences. Then we print one segment at a time. At the end of
+ // each iteration, the str pointer advances to the beginning of the
+ // next segment.
+ for (;;) {
+ const char* p = strchr(str, '@');
+ if (p == nullptr) {
+ ColoredPrintf(color, "%s", str);
+ return;
+ }
+
+ ColoredPrintf(color, "%s", std::string(str, p).c_str());
+
+ const char ch = p[1];
+ str = p + 2;
+ if (ch == '@') {
+ ColoredPrintf(color, "@");
+ } else if (ch == 'D') {
+ color = GTestColor::kDefault;
+ } else if (ch == 'R') {
+ color = GTestColor::kRed;
+ } else if (ch == 'G') {
+ color = GTestColor::kGreen;
+ } else if (ch == 'Y') {
+ color = GTestColor::kYellow;
+ } else {
+ --str;
+ }
+ }
+}
+
+static const char kColorEncodedHelpMessage[] =
+ "This program contains tests written using " GTEST_NAME_
+ ". You can use the\n"
+ "following command line flags to control its behavior:\n"
+ "\n"
+ "Test Selection:\n"
+ " @G--" GTEST_FLAG_PREFIX_
+ "list_tests@D\n"
+ " List the names of all tests instead of running them. The name of\n"
+ " TEST(Foo, Bar) is \"Foo.Bar\".\n"
+ " @G--" GTEST_FLAG_PREFIX_
+ "filter=@YPOSITIVE_PATTERNS"
+ "[@G-@YNEGATIVE_PATTERNS]@D\n"
+ " Run only the tests whose name matches one of the positive patterns "
+ "but\n"
+ " none of the negative patterns. '?' matches any single character; "
+ "'*'\n"
+ " matches any substring; ':' separates two patterns.\n"
+ " @G--" GTEST_FLAG_PREFIX_
+ "also_run_disabled_tests@D\n"
+ " Run all disabled tests too.\n"
+ "\n"
+ "Test Execution:\n"
+ " @G--" GTEST_FLAG_PREFIX_
+ "repeat=@Y[COUNT]@D\n"
+ " Run the tests repeatedly; use a negative count to repeat forever.\n"
+ " @G--" GTEST_FLAG_PREFIX_
+ "shuffle@D\n"
+ " Randomize tests' orders on every iteration.\n"
+ " @G--" GTEST_FLAG_PREFIX_
+ "random_seed=@Y[NUMBER]@D\n"
+ " Random number seed to use for shuffling test orders (between 1 and\n"
+ " 99999, or 0 to use a seed based on the current time).\n"
+ "\n"
+ "Test Output:\n"
+ " @G--" GTEST_FLAG_PREFIX_
+ "color=@Y(@Gyes@Y|@Gno@Y|@Gauto@Y)@D\n"
+ " Enable/disable colored output. The default is @Gauto@D.\n"
+ " @G--" GTEST_FLAG_PREFIX_
+ "brief=1@D\n"
+ " Only print test failures.\n"
+ " @G--" GTEST_FLAG_PREFIX_
+ "print_time=0@D\n"
+ " Don't print the elapsed time of each test.\n"
+ " @G--" GTEST_FLAG_PREFIX_
+ "output=@Y(@Gjson@Y|@Gxml@Y)[@G:@YDIRECTORY_PATH@G" GTEST_PATH_SEP_
+ "@Y|@G:@YFILE_PATH]@D\n"
+ " Generate a JSON or XML report in the given directory or with the "
+ "given\n"
+ " file name. @YFILE_PATH@D defaults to @Gtest_detail.xml@D.\n"
+# if GTEST_CAN_STREAM_RESULTS_
+ " @G--" GTEST_FLAG_PREFIX_
+ "stream_result_to=@YHOST@G:@YPORT@D\n"
+ " Stream test results to the given server.\n"
+# endif // GTEST_CAN_STREAM_RESULTS_
+ "\n"
+ "Assertion Behavior:\n"
+# if GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS
+ " @G--" GTEST_FLAG_PREFIX_
+ "death_test_style=@Y(@Gfast@Y|@Gthreadsafe@Y)@D\n"
+ " Set the default death test style.\n"
+# endif // GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS
+ " @G--" GTEST_FLAG_PREFIX_
+ "break_on_failure@D\n"
+ " Turn assertion failures into debugger break-points.\n"
+ " @G--" GTEST_FLAG_PREFIX_
+ "throw_on_failure@D\n"
+ " Turn assertion failures into C++ exceptions for use by an external\n"
+ " test framework.\n"
+ " @G--" GTEST_FLAG_PREFIX_
+ "catch_exceptions=0@D\n"
+ " Do not report exceptions as test failures. Instead, allow them\n"
+ " to crash the program or throw a pop-up (on Windows).\n"
+ "\n"
+ "Except for @G--" GTEST_FLAG_PREFIX_
+ "list_tests@D, you can alternatively set "
+ "the corresponding\n"
+ "environment variable of a flag (all letters in upper-case). For example, "
+ "to\n"
+ "disable colored text output, you can either specify "
+ "@G--" GTEST_FLAG_PREFIX_
+ "color=no@D or set\n"
+ "the @G" GTEST_FLAG_PREFIX_UPPER_
+ "COLOR@D environment variable to @Gno@D.\n"
+ "\n"
+ "For more information, please read the " GTEST_NAME_
+ " documentation at\n"
+ "@G" GTEST_PROJECT_URL_ "@D. If you find a bug in " GTEST_NAME_
+ "\n"
+ "(not one in your own code or tests), please report it to\n"
+ "@G<" GTEST_DEV_EMAIL_ ">@D.\n";
+
+static bool ParseGoogleTestFlag(const char* const arg) {
+ return ParseBoolFlag(arg, kAlsoRunDisabledTestsFlag,
+ &GTEST_FLAG(also_run_disabled_tests)) ||
+ ParseBoolFlag(arg, kBreakOnFailureFlag,
+ &GTEST_FLAG(break_on_failure)) ||
+ ParseBoolFlag(arg, kCatchExceptionsFlag,
+ &GTEST_FLAG(catch_exceptions)) ||
+ ParseStringFlag(arg, kColorFlag, &GTEST_FLAG(color)) ||
+ ParseStringFlag(arg, kDeathTestStyleFlag,
+ &GTEST_FLAG(death_test_style)) ||
+ ParseBoolFlag(arg, kDeathTestUseFork,
+ &GTEST_FLAG(death_test_use_fork)) ||
+ ParseBoolFlag(arg, kFailFast, &GTEST_FLAG(fail_fast)) ||
+ ParseStringFlag(arg, kFilterFlag, &GTEST_FLAG(filter)) ||
+ ParseStringFlag(arg, kInternalRunDeathTestFlag,
+ &GTEST_FLAG(internal_run_death_test)) ||
+ ParseBoolFlag(arg, kListTestsFlag, &GTEST_FLAG(list_tests)) ||
+ ParseStringFlag(arg, kOutputFlag, &GTEST_FLAG(output)) ||
+ ParseBoolFlag(arg, kBriefFlag, &GTEST_FLAG(brief)) ||
+ ParseBoolFlag(arg, kPrintTimeFlag, &GTEST_FLAG(print_time)) ||
+ ParseBoolFlag(arg, kPrintUTF8Flag, &GTEST_FLAG(print_utf8)) ||
+ ParseInt32Flag(arg, kRandomSeedFlag, &GTEST_FLAG(random_seed)) ||
+ ParseInt32Flag(arg, kRepeatFlag, &GTEST_FLAG(repeat)) ||
+ ParseBoolFlag(arg, kShuffleFlag, &GTEST_FLAG(shuffle)) ||
+ ParseInt32Flag(arg, kStackTraceDepthFlag,
+ &GTEST_FLAG(stack_trace_depth)) ||
+ ParseStringFlag(arg, kStreamResultToFlag,
+ &GTEST_FLAG(stream_result_to)) ||
+ ParseBoolFlag(arg, kThrowOnFailureFlag, &GTEST_FLAG(throw_on_failure));
+}
+
+#if GTEST_USE_OWN_FLAGFILE_FLAG_
+static void LoadFlagsFromFile(const std::string& path) {
+ FILE* flagfile = posix::FOpen(path.c_str(), "r");
+ if (!flagfile) {
+ GTEST_LOG_(FATAL) << "Unable to open file \"" << GTEST_FLAG(flagfile)
+ << "\"";
+ }
+ std::string contents(ReadEntireFile(flagfile));
+ posix::FClose(flagfile);
+ std::vector<std::string> lines;
+ SplitString(contents, '\n', &lines);
+ for (size_t i = 0; i < lines.size(); ++i) {
+ if (lines[i].empty())
+ continue;
+ if (!ParseGoogleTestFlag(lines[i].c_str()))
+ g_help_flag = true;
+ }
+}
+#endif // GTEST_USE_OWN_FLAGFILE_FLAG_
+
+// Parses the command line for Google Test flags, without initializing
+// other parts of Google Test. The type parameter CharType can be
+// instantiated to either char or wchar_t.
+template <typename CharType>
+void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) {
+ for (int i = 1; i < *argc; i++) {
+ const std::string arg_string = StreamableToString(argv[i]);
+ const char* const arg = arg_string.c_str();
+
+ using internal::ParseBoolFlag;
+ using internal::ParseInt32Flag;
+ using internal::ParseStringFlag;
+
+ bool remove_flag = false;
+ if (ParseGoogleTestFlag(arg)) {
+ remove_flag = true;
+#if GTEST_USE_OWN_FLAGFILE_FLAG_
+ } else if (ParseStringFlag(arg, kFlagfileFlag, &GTEST_FLAG(flagfile))) {
+ LoadFlagsFromFile(GTEST_FLAG(flagfile));
+ remove_flag = true;
+#endif // GTEST_USE_OWN_FLAGFILE_FLAG_
+ } else if (arg_string == "--help" || arg_string == "-h" ||
+ arg_string == "-?" || arg_string == "/?" ||
+ HasGoogleTestFlagPrefix(arg)) {
+ // Both help flag and unrecognized Google Test flags (excluding
+ // internal ones) trigger help display.
+ g_help_flag = true;
+ }
+
+ if (remove_flag) {
+ // Shift the remainder of the argv list left by one. Note
+ // that argv has (*argc + 1) elements, the last one always being
+ // NULL. The following loop moves the trailing NULL element as
+ // well.
+ for (int j = i; j != *argc; j++) {
+ argv[j] = argv[j + 1];
+ }
+
+ // Decrements the argument count.
+ (*argc)--;
+
+ // We also need to decrement the iterator as we just removed
+ // an element.
+ i--;
+ }
+ }
+
+ if (g_help_flag) {
+ // We print the help here instead of in RUN_ALL_TESTS(), as the
+ // latter may not be called at all if the user is using Google
+ // Test with another testing framework.
+ PrintColorEncoded(kColorEncodedHelpMessage);
+ }
+}
+
+// Parses the command line for Google Test flags, without initializing
+// other parts of Google Test.
+void ParseGoogleTestFlagsOnly(int* argc, char** argv) {
+ ParseGoogleTestFlagsOnlyImpl(argc, argv);
+
+ // Fix the value of *_NSGetArgc() on macOS, but if and only if
+ // *_NSGetArgv() == argv
+ // Only applicable to char** version of argv
+#if GTEST_OS_MAC
+#ifndef GTEST_OS_IOS
+ if (*_NSGetArgv() == argv) {
+ *_NSGetArgc() = *argc;
+ }
+#endif
+#endif
+}
+void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv) {
+ ParseGoogleTestFlagsOnlyImpl(argc, argv);
+}
+
+// The internal implementation of InitGoogleTest().
+//
+// The type parameter CharType can be instantiated to either char or
+// wchar_t.
+template <typename CharType>
+void InitGoogleTestImpl(int* argc, CharType** argv) {
+ // We don't want to run the initialization code twice.
+ if (GTestIsInitialized()) return;
+
+ if (*argc <= 0) return;
+
+ g_argvs.clear();
+ for (int i = 0; i != *argc; i++) {
+ g_argvs.push_back(StreamableToString(argv[i]));
+ }
+
+#if GTEST_HAS_ABSL
+ absl::InitializeSymbolizer(g_argvs[0].c_str());
+#endif // GTEST_HAS_ABSL
+
+ ParseGoogleTestFlagsOnly(argc, argv);
+ GetUnitTestImpl()->PostFlagParsingInit();
+}
+
+} // namespace internal
+
+// Initializes Google Test. This must be called before calling
+// RUN_ALL_TESTS(). In particular, it parses a command line for the
+// flags that Google Test recognizes. Whenever a Google Test flag is
+// seen, it is removed from argv, and *argc is decremented.
+//
+// No value is returned. Instead, the Google Test flag variables are
+// updated.
+//
+// Calling the function for the second time has no user-visible effect.
+void InitGoogleTest(int* argc, char** argv) {
+#if defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_)
+ GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_(argc, argv);
+#else // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_)
+ internal::InitGoogleTestImpl(argc, argv);
+#endif // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_)
+}
+
+// This overloaded version can be used in Windows programs compiled in
+// UNICODE mode.
+void InitGoogleTest(int* argc, wchar_t** argv) {
+#if defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_)
+ GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_(argc, argv);
+#else // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_)
+ internal::InitGoogleTestImpl(argc, argv);
+#endif // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_)
+}
+
+// This overloaded version can be used on Arduino/embedded platforms where
+// there is no argc/argv.
+void InitGoogleTest() {
+ // Since Arduino doesn't have a command line, fake out the argc/argv arguments
+ int argc = 1;
+ const auto arg0 = "dummy";
+ char* argv0 = const_cast<char*>(arg0);
+ char** argv = &argv0;
+
+#if defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_)
+ GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_(&argc, argv);
+#else // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_)
+ internal::InitGoogleTestImpl(&argc, argv);
+#endif // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_)
+}
+
+std::string TempDir() {
+#if defined(GTEST_CUSTOM_TEMPDIR_FUNCTION_)
+ return GTEST_CUSTOM_TEMPDIR_FUNCTION_();
+#elif GTEST_OS_WINDOWS_MOBILE
+ return "\\temp\\";
+#elif GTEST_OS_WINDOWS
+ const char* temp_dir = internal::posix::GetEnv("TEMP");
+ if (temp_dir == nullptr || temp_dir[0] == '\0') {
+ return "\\temp\\";
+ } else if (temp_dir[strlen(temp_dir) - 1] == '\\') {
+ return temp_dir;
+ } else {
+ return std::string(temp_dir) + "\\";
+ }
+#elif GTEST_OS_LINUX_ANDROID
+ const char* temp_dir = internal::posix::GetEnv("TEST_TMPDIR");
+ if (temp_dir == nullptr || temp_dir[0] == '\0') {
+ return "/data/local/tmp/";
+ } else {
+ return temp_dir;
+ }
+#elif GTEST_OS_LINUX
+ const char* temp_dir = internal::posix::GetEnv("TEST_TMPDIR");
+ if (temp_dir == nullptr || temp_dir[0] == '\0') {
+ return "/tmp/";
+ } else {
+ return temp_dir;
+ }
+#else
+ return "/tmp/";
+#endif // GTEST_OS_WINDOWS_MOBILE
+}
+
+// Class ScopedTrace
+
+// Pushes the given source file location and message onto a per-thread
+// trace stack maintained by Google Test.
+void ScopedTrace::PushTrace(const char* file, int line, std::string message) {
+ internal::TraceInfo trace;
+ trace.file = file;
+ trace.line = line;
+ trace.message.swap(message);
+
+ UnitTest::GetInstance()->PushGTestTrace(trace);
+}
+
+// Pops the info pushed by the c'tor.
+ScopedTrace::~ScopedTrace()
+ GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_) {
+ UnitTest::GetInstance()->PopGTestTrace();
+}
+
+} // namespace testing
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+//
+// This file implements death tests.
+
+
+#include <functional>
+#include <utility>
+
+
+#if GTEST_HAS_DEATH_TEST
+
+# if GTEST_OS_MAC
+# include <crt_externs.h>
+# endif // GTEST_OS_MAC
+
+# include <errno.h>
+# include <fcntl.h>
+# include <limits.h>
+
+# if GTEST_OS_LINUX
+# include <signal.h>
+# endif // GTEST_OS_LINUX
+
+# include <stdarg.h>
+
+# if GTEST_OS_WINDOWS
+# include <windows.h>
+# else
+# include <sys/mman.h>
+# include <sys/wait.h>
+# endif // GTEST_OS_WINDOWS
+
+# if GTEST_OS_QNX
+# include <spawn.h>
+# endif // GTEST_OS_QNX
+
+# if GTEST_OS_FUCHSIA
+# include <lib/fdio/fd.h>
+# include <lib/fdio/io.h>
+# include <lib/fdio/spawn.h>
+# include <lib/zx/channel.h>
+# include <lib/zx/port.h>
+# include <lib/zx/process.h>
+# include <lib/zx/socket.h>
+# include <zircon/processargs.h>
+# include <zircon/syscalls.h>
+# include <zircon/syscalls/policy.h>
+# include <zircon/syscalls/port.h>
+# endif // GTEST_OS_FUCHSIA
+
+#endif // GTEST_HAS_DEATH_TEST
+
+
+namespace testing {
+
+// Constants.
+
+// The default death test style.
+//
+// This is defined in internal/gtest-port.h as "fast", but can be overridden by
+// a definition in internal/custom/gtest-port.h. The recommended value, which is
+// used internally at Google, is "threadsafe".
+static const char kDefaultDeathTestStyle[] = GTEST_DEFAULT_DEATH_TEST_STYLE;
+
+GTEST_DEFINE_string_(
+ death_test_style,
+ internal::StringFromGTestEnv("death_test_style", kDefaultDeathTestStyle),
+ "Indicates how to run a death test in a forked child process: "
+ "\"threadsafe\" (child process re-executes the test binary "
+ "from the beginning, running only the specific death test) or "
+ "\"fast\" (child process runs the death test immediately "
+ "after forking).");
+
+GTEST_DEFINE_bool_(
+ death_test_use_fork,
+ internal::BoolFromGTestEnv("death_test_use_fork", false),
+ "Instructs to use fork()/_exit() instead of clone() in death tests. "
+ "Ignored and always uses fork() on POSIX systems where clone() is not "
+ "implemented. Useful when running under valgrind or similar tools if "
+ "those do not support clone(). Valgrind 3.3.1 will just fail if "
+ "it sees an unsupported combination of clone() flags. "
+ "It is not recommended to use this flag w/o valgrind though it will "
+ "work in 99% of the cases. Once valgrind is fixed, this flag will "
+ "most likely be removed.");
+
+namespace internal {
+GTEST_DEFINE_string_(
+ internal_run_death_test, "",
+ "Indicates the file, line number, temporal index of "
+ "the single death test to run, and a file descriptor to "
+ "which a success code may be sent, all separated by "
+ "the '|' characters. This flag is specified if and only if the "
+ "current process is a sub-process launched for running a thread-safe "
+ "death test. FOR INTERNAL USE ONLY.");
+} // namespace internal
+
+#if GTEST_HAS_DEATH_TEST
+
+namespace internal {
+
+// Valid only for fast death tests. Indicates the code is running in the
+// child process of a fast style death test.
+# if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA
+static bool g_in_fast_death_test_child = false;
+# endif
+
+// Returns a Boolean value indicating whether the caller is currently
+// executing in the context of the death test child process. Tools such as
+// Valgrind heap checkers may need this to modify their behavior in death
+// tests. IMPORTANT: This is an internal utility. Using it may break the
+// implementation of death tests. User code MUST NOT use it.
+bool InDeathTestChild() {
+# if GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA
+
+ // On Windows and Fuchsia, death tests are thread-safe regardless of the value
+ // of the death_test_style flag.
+ return !GTEST_FLAG(internal_run_death_test).empty();
+
+# else
+
+ if (GTEST_FLAG(death_test_style) == "threadsafe")
+ return !GTEST_FLAG(internal_run_death_test).empty();
+ else
+ return g_in_fast_death_test_child;
+#endif
+}
+
+} // namespace internal
+
+// ExitedWithCode constructor.
+ExitedWithCode::ExitedWithCode(int exit_code) : exit_code_(exit_code) {
+}
+
+// ExitedWithCode function-call operator.
+bool ExitedWithCode::operator()(int exit_status) const {
+# if GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA
+
+ return exit_status == exit_code_;
+
+# else
+
+ return WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == exit_code_;
+
+# endif // GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA
+}
+
+# if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA
+// KilledBySignal constructor.
+KilledBySignal::KilledBySignal(int signum) : signum_(signum) {
+}
+
+// KilledBySignal function-call operator.
+bool KilledBySignal::operator()(int exit_status) const {
+# if defined(GTEST_KILLED_BY_SIGNAL_OVERRIDE_)
+ {
+ bool result;
+ if (GTEST_KILLED_BY_SIGNAL_OVERRIDE_(signum_, exit_status, &result)) {
+ return result;
+ }
+ }
+# endif // defined(GTEST_KILLED_BY_SIGNAL_OVERRIDE_)
+ return WIFSIGNALED(exit_status) && WTERMSIG(exit_status) == signum_;
+}
+# endif // !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA
+
+namespace internal {
+
+// Utilities needed for death tests.
+
+// Generates a textual description of a given exit code, in the format
+// specified by wait(2).
+static std::string ExitSummary(int exit_code) {
+ Message m;
+
+# if GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA
+
+ m << "Exited with exit status " << exit_code;
+
+# else
+
+ if (WIFEXITED(exit_code)) {
+ m << "Exited with exit status " << WEXITSTATUS(exit_code);
+ } else if (WIFSIGNALED(exit_code)) {
+ m << "Terminated by signal " << WTERMSIG(exit_code);
+ }
+# ifdef WCOREDUMP
+ if (WCOREDUMP(exit_code)) {
+ m << " (core dumped)";
+ }
+# endif
+# endif // GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA
+
+ return m.GetString();
+}
+
+// Returns true if exit_status describes a process that was terminated
+// by a signal, or exited normally with a nonzero exit code.
+bool ExitedUnsuccessfully(int exit_status) {
+ return !ExitedWithCode(0)(exit_status);
+}
+
+# if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA
+// Generates a textual failure message when a death test finds more than
+// one thread running, or cannot determine the number of threads, prior
+// to executing the given statement. It is the responsibility of the
+// caller not to pass a thread_count of 1.
+static std::string DeathTestThreadWarning(size_t thread_count) {
+ Message msg;
+ msg << "Death tests use fork(), which is unsafe particularly"
+ << " in a threaded context. For this test, " << GTEST_NAME_ << " ";
+ if (thread_count == 0) {
+ msg << "couldn't detect the number of threads.";
+ } else {
+ msg << "detected " << thread_count << " threads.";
+ }
+ msg << " See "
+ "https://github.com/google/googletest/blob/master/docs/"
+ "advanced.md#death-tests-and-threads"
+ << " for more explanation and suggested solutions, especially if"
+ << " this is the last message you see before your test times out.";
+ return msg.GetString();
+}
+# endif // !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA
+
+// Flag characters for reporting a death test that did not die.
+static const char kDeathTestLived = 'L';
+static const char kDeathTestReturned = 'R';
+static const char kDeathTestThrew = 'T';
+static const char kDeathTestInternalError = 'I';
+
+#if GTEST_OS_FUCHSIA
+
+// File descriptor used for the pipe in the child process.
+static const int kFuchsiaReadPipeFd = 3;
+
+#endif
+
+// An enumeration describing all of the possible ways that a death test can
+// conclude. DIED means that the process died while executing the test
+// code; LIVED means that process lived beyond the end of the test code;
+// RETURNED means that the test statement attempted to execute a return
+// statement, which is not allowed; THREW means that the test statement
+// returned control by throwing an exception. IN_PROGRESS means the test
+// has not yet concluded.
+enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED, THREW };
+
+// Routine for aborting the program which is safe to call from an
+// exec-style death test child process, in which case the error
+// message is propagated back to the parent process. Otherwise, the
+// message is simply printed to stderr. In either case, the program
+// then exits with status 1.
+static void DeathTestAbort(const std::string& message) {
+ // On a POSIX system, this function may be called from a threadsafe-style
+ // death test child process, which operates on a very small stack. Use
+ // the heap for any additional non-minuscule memory requirements.
+ const InternalRunDeathTestFlag* const flag =
+ GetUnitTestImpl()->internal_run_death_test_flag();
+ if (flag != nullptr) {
+ FILE* parent = posix::FDOpen(flag->write_fd(), "w");
+ fputc(kDeathTestInternalError, parent);
+ fprintf(parent, "%s", message.c_str());
+ fflush(parent);
+ _exit(1);
+ } else {
+ fprintf(stderr, "%s", message.c_str());
+ fflush(stderr);
+ posix::Abort();
+ }
+}
+
+// A replacement for CHECK that calls DeathTestAbort if the assertion
+// fails.
+# define GTEST_DEATH_TEST_CHECK_(expression) \
+ do { \
+ if (!::testing::internal::IsTrue(expression)) { \
+ DeathTestAbort( \
+ ::std::string("CHECK failed: File ") + __FILE__ + ", line " \
+ + ::testing::internal::StreamableToString(__LINE__) + ": " \
+ + #expression); \
+ } \
+ } while (::testing::internal::AlwaysFalse())
+
+// This macro is similar to GTEST_DEATH_TEST_CHECK_, but it is meant for
+// evaluating any system call that fulfills two conditions: it must return
+// -1 on failure, and set errno to EINTR when it is interrupted and
+// should be tried again. The macro expands to a loop that repeatedly
+// evaluates the expression as long as it evaluates to -1 and sets
+// errno to EINTR. If the expression evaluates to -1 but errno is
+// something other than EINTR, DeathTestAbort is called.
+# define GTEST_DEATH_TEST_CHECK_SYSCALL_(expression) \
+ do { \
+ int gtest_retval; \
+ do { \
+ gtest_retval = (expression); \
+ } while (gtest_retval == -1 && errno == EINTR); \
+ if (gtest_retval == -1) { \
+ DeathTestAbort( \
+ ::std::string("CHECK failed: File ") + __FILE__ + ", line " \
+ + ::testing::internal::StreamableToString(__LINE__) + ": " \
+ + #expression + " != -1"); \
+ } \
+ } while (::testing::internal::AlwaysFalse())
+
+// Returns the message describing the last system error in errno.
+std::string GetLastErrnoDescription() {
+ return errno == 0 ? "" : posix::StrError(errno);
+}
+
+// This is called from a death test parent process to read a failure
+// message from the death test child process and log it with the FATAL
+// severity. On Windows, the message is read from a pipe handle. On other
+// platforms, it is read from a file descriptor.
+static void FailFromInternalError(int fd) {
+ Message error;
+ char buffer[256];
+ int num_read;
+
+ do {
+ while ((num_read = posix::Read(fd, buffer, 255)) > 0) {
+ buffer[num_read] = '\0';
+ error << buffer;
+ }
+ } while (num_read == -1 && errno == EINTR);
+
+ if (num_read == 0) {
+ GTEST_LOG_(FATAL) << error.GetString();
+ } else {
+ const int last_error = errno;
+ GTEST_LOG_(FATAL) << "Error while reading death test internal: "
+ << GetLastErrnoDescription() << " [" << last_error << "]";
+ }
+}
+
+// Death test constructor. Increments the running death test count
+// for the current test.
+DeathTest::DeathTest() {
+ TestInfo* const info = GetUnitTestImpl()->current_test_info();
+ if (info == nullptr) {
+ DeathTestAbort("Cannot run a death test outside of a TEST or "
+ "TEST_F construct");
+ }
+}
+
+// Creates and returns a death test by dispatching to the current
+// death test factory.
+bool DeathTest::Create(const char* statement,
+ Matcher<const std::string&> matcher, const char* file,
+ int line, DeathTest** test) {
+ return GetUnitTestImpl()->death_test_factory()->Create(
+ statement, std::move(matcher), file, line, test);
+}
+
+const char* DeathTest::LastMessage() {
+ return last_death_test_message_.c_str();
+}
+
+void DeathTest::set_last_death_test_message(const std::string& message) {
+ last_death_test_message_ = message;
+}
+
+std::string DeathTest::last_death_test_message_;
+
+// Provides cross platform implementation for some death functionality.
+class DeathTestImpl : public DeathTest {
+ protected:
+ DeathTestImpl(const char* a_statement, Matcher<const std::string&> matcher)
+ : statement_(a_statement),
+ matcher_(std::move(matcher)),
+ spawned_(false),
+ status_(-1),
+ outcome_(IN_PROGRESS),
+ read_fd_(-1),
+ write_fd_(-1) {}
+
+ // read_fd_ is expected to be closed and cleared by a derived class.
+ ~DeathTestImpl() override { GTEST_DEATH_TEST_CHECK_(read_fd_ == -1); }
+
+ void Abort(AbortReason reason) override;
+ bool Passed(bool status_ok) override;
+
+ const char* statement() const { return statement_; }
+ bool spawned() const { return spawned_; }
+ void set_spawned(bool is_spawned) { spawned_ = is_spawned; }
+ int status() const { return status_; }
+ void set_status(int a_status) { status_ = a_status; }
+ DeathTestOutcome outcome() const { return outcome_; }
+ void set_outcome(DeathTestOutcome an_outcome) { outcome_ = an_outcome; }
+ int read_fd() const { return read_fd_; }
+ void set_read_fd(int fd) { read_fd_ = fd; }
+ int write_fd() const { return write_fd_; }
+ void set_write_fd(int fd) { write_fd_ = fd; }
+
+ // Called in the parent process only. Reads the result code of the death
+ // test child process via a pipe, interprets it to set the outcome_
+ // member, and closes read_fd_. Outputs diagnostics and terminates in
+ // case of unexpected codes.
+ void ReadAndInterpretStatusByte();
+
+ // Returns stderr output from the child process.
+ virtual std::string GetErrorLogs();
+
+ private:
+ // The textual content of the code this object is testing. This class
+ // doesn't own this string and should not attempt to delete it.
+ const char* const statement_;
+ // A matcher that's expected to match the stderr output by the child process.
+ Matcher<const std::string&> matcher_;
+ // True if the death test child process has been successfully spawned.
+ bool spawned_;
+ // The exit status of the child process.
+ int status_;
+ // How the death test concluded.
+ DeathTestOutcome outcome_;
+ // Descriptor to the read end of the pipe to the child process. It is
+ // always -1 in the child process. The child keeps its write end of the
+ // pipe in write_fd_.
+ int read_fd_;
+ // Descriptor to the child's write end of the pipe to the parent process.
+ // It is always -1 in the parent process. The parent keeps its end of the
+ // pipe in read_fd_.
+ int write_fd_;
+};
+
+// Called in the parent process only. Reads the result code of the death
+// test child process via a pipe, interprets it to set the outcome_
+// member, and closes read_fd_. Outputs diagnostics and terminates in
+// case of unexpected codes.
+void DeathTestImpl::ReadAndInterpretStatusByte() {
+ char flag;
+ int bytes_read;
+
+ // The read() here blocks until data is available (signifying the
+ // failure of the death test) or until the pipe is closed (signifying
+ // its success), so it's okay to call this in the parent before
+ // the child process has exited.
+ do {
+ bytes_read = posix::Read(read_fd(), &flag, 1);
+ } while (bytes_read == -1 && errno == EINTR);
+
+ if (bytes_read == 0) {
+ set_outcome(DIED);
+ } else if (bytes_read == 1) {
+ switch (flag) {
+ case kDeathTestReturned:
+ set_outcome(RETURNED);
+ break;
+ case kDeathTestThrew:
+ set_outcome(THREW);
+ break;
+ case kDeathTestLived:
+ set_outcome(LIVED);
+ break;
+ case kDeathTestInternalError:
+ FailFromInternalError(read_fd()); // Does not return.
+ break;
+ default:
+ GTEST_LOG_(FATAL) << "Death test child process reported "
+ << "unexpected status byte ("
+ << static_cast<unsigned int>(flag) << ")";
+ }
+ } else {
+ GTEST_LOG_(FATAL) << "Read from death test child process failed: "
+ << GetLastErrnoDescription();
+ }
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Close(read_fd()));
+ set_read_fd(-1);
+}
+
+std::string DeathTestImpl::GetErrorLogs() {
+ return GetCapturedStderr();
+}
+
+// Signals that the death test code which should have exited, didn't.
+// Should be called only in a death test child process.
+// Writes a status byte to the child's status file descriptor, then
+// calls _exit(1).
+void DeathTestImpl::Abort(AbortReason reason) {
+ // The parent process considers the death test to be a failure if
+ // it finds any data in our pipe. So, here we write a single flag byte
+ // to the pipe, then exit.
+ const char status_ch =
+ reason == TEST_DID_NOT_DIE ? kDeathTestLived :
+ reason == TEST_THREW_EXCEPTION ? kDeathTestThrew : kDeathTestReturned;
+
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Write(write_fd(), &status_ch, 1));
+ // We are leaking the descriptor here because on some platforms (i.e.,
+ // when built as Windows DLL), destructors of global objects will still
+ // run after calling _exit(). On such systems, write_fd_ will be
+ // indirectly closed from the destructor of UnitTestImpl, causing double
+ // close if it is also closed here. On debug configurations, double close
+ // may assert. As there are no in-process buffers to flush here, we are
+ // relying on the OS to close the descriptor after the process terminates
+ // when the destructors are not run.
+ _exit(1); // Exits w/o any normal exit hooks (we were supposed to crash)
+}
+
+// Returns an indented copy of stderr output for a death test.
+// This makes distinguishing death test output lines from regular log lines
+// much easier.
+static ::std::string FormatDeathTestOutput(const ::std::string& output) {
+ ::std::string ret;
+ for (size_t at = 0; ; ) {
+ const size_t line_end = output.find('\n', at);
+ ret += "[ DEATH ] ";
+ if (line_end == ::std::string::npos) {
+ ret += output.substr(at);
+ break;
+ }
+ ret += output.substr(at, line_end + 1 - at);
+ at = line_end + 1;
+ }
+ return ret;
+}
+
+// Assesses the success or failure of a death test, using both private
+// members which have previously been set, and one argument:
+//
+// Private data members:
+// outcome: An enumeration describing how the death test
+// concluded: DIED, LIVED, THREW, or RETURNED. The death test
+// fails in the latter three cases.
+// status: The exit status of the child process. On *nix, it is in the
+// in the format specified by wait(2). On Windows, this is the
+// value supplied to the ExitProcess() API or a numeric code
+// of the exception that terminated the program.
+// matcher_: A matcher that's expected to match the stderr output by the child
+// process.
+//
+// Argument:
+// status_ok: true if exit_status is acceptable in the context of
+// this particular death test, which fails if it is false
+//
+// Returns true if and only if all of the above conditions are met. Otherwise,
+// the first failing condition, in the order given above, is the one that is
+// reported. Also sets the last death test message string.
+bool DeathTestImpl::Passed(bool status_ok) {
+ if (!spawned())
+ return false;
+
+ const std::string error_message = GetErrorLogs();
+
+ bool success = false;
+ Message buffer;
+
+ buffer << "Death test: " << statement() << "\n";
+ switch (outcome()) {
+ case LIVED:
+ buffer << " Result: failed to die.\n"
+ << " Error msg:\n" << FormatDeathTestOutput(error_message);
+ break;
+ case THREW:
+ buffer << " Result: threw an exception.\n"
+ << " Error msg:\n" << FormatDeathTestOutput(error_message);
+ break;
+ case RETURNED:
+ buffer << " Result: illegal return in test statement.\n"
+ << " Error msg:\n" << FormatDeathTestOutput(error_message);
+ break;
+ case DIED:
+ if (status_ok) {
+ if (matcher_.Matches(error_message)) {
+ success = true;
+ } else {
+ std::ostringstream stream;
+ matcher_.DescribeTo(&stream);
+ buffer << " Result: died but not with expected error.\n"
+ << " Expected: " << stream.str() << "\n"
+ << "Actual msg:\n"
+ << FormatDeathTestOutput(error_message);
+ }
+ } else {
+ buffer << " Result: died but not with expected exit code:\n"
+ << " " << ExitSummary(status()) << "\n"
+ << "Actual msg:\n" << FormatDeathTestOutput(error_message);
+ }
+ break;
+ case IN_PROGRESS:
+ default:
+ GTEST_LOG_(FATAL)
+ << "DeathTest::Passed somehow called before conclusion of test";
+ }
+
+ DeathTest::set_last_death_test_message(buffer.GetString());
+ return success;
+}
+
+# if GTEST_OS_WINDOWS
+// WindowsDeathTest implements death tests on Windows. Due to the
+// specifics of starting new processes on Windows, death tests there are
+// always threadsafe, and Google Test considers the
+// --gtest_death_test_style=fast setting to be equivalent to
+// --gtest_death_test_style=threadsafe there.
+//
+// A few implementation notes: Like the Linux version, the Windows
+// implementation uses pipes for child-to-parent communication. But due to
+// the specifics of pipes on Windows, some extra steps are required:
+//
+// 1. The parent creates a communication pipe and stores handles to both
+// ends of it.
+// 2. The parent starts the child and provides it with the information
+// necessary to acquire the handle to the write end of the pipe.
+// 3. The child acquires the write end of the pipe and signals the parent
+// using a Windows event.
+// 4. Now the parent can release the write end of the pipe on its side. If
+// this is done before step 3, the object's reference count goes down to
+// 0 and it is destroyed, preventing the child from acquiring it. The
+// parent now has to release it, or read operations on the read end of
+// the pipe will not return when the child terminates.
+// 5. The parent reads child's output through the pipe (outcome code and
+// any possible error messages) from the pipe, and its stderr and then
+// determines whether to fail the test.
+//
+// Note: to distinguish Win32 API calls from the local method and function
+// calls, the former are explicitly resolved in the global namespace.
+//
+class WindowsDeathTest : public DeathTestImpl {
+ public:
+ WindowsDeathTest(const char* a_statement, Matcher<const std::string&> matcher,
+ const char* file, int line)
+ : DeathTestImpl(a_statement, std::move(matcher)),
+ file_(file),
+ line_(line) {}
+
+ // All of these virtual functions are inherited from DeathTest.
+ virtual int Wait();
+ virtual TestRole AssumeRole();
+
+ private:
+ // The name of the file in which the death test is located.
+ const char* const file_;
+ // The line number on which the death test is located.
+ const int line_;
+ // Handle to the write end of the pipe to the child process.
+ AutoHandle write_handle_;
+ // Child process handle.
+ AutoHandle child_handle_;
+ // Event the child process uses to signal the parent that it has
+ // acquired the handle to the write end of the pipe. After seeing this
+ // event the parent can release its own handles to make sure its
+ // ReadFile() calls return when the child terminates.
+ AutoHandle event_handle_;
+};
+
+// Waits for the child in a death test to exit, returning its exit
+// status, or 0 if no child process exists. As a side effect, sets the
+// outcome data member.
+int WindowsDeathTest::Wait() {
+ if (!spawned())
+ return 0;
+
+ // Wait until the child either signals that it has acquired the write end
+ // of the pipe or it dies.
+ const HANDLE wait_handles[2] = { child_handle_.Get(), event_handle_.Get() };
+ switch (::WaitForMultipleObjects(2,
+ wait_handles,
+ FALSE, // Waits for any of the handles.
+ INFINITE)) {
+ case WAIT_OBJECT_0:
+ case WAIT_OBJECT_0 + 1:
+ break;
+ default:
+ GTEST_DEATH_TEST_CHECK_(false); // Should not get here.
+ }
+
+ // The child has acquired the write end of the pipe or exited.
+ // We release the handle on our side and continue.
+ write_handle_.Reset();
+ event_handle_.Reset();
+
+ ReadAndInterpretStatusByte();
+
+ // Waits for the child process to exit if it haven't already. This
+ // returns immediately if the child has already exited, regardless of
+ // whether previous calls to WaitForMultipleObjects synchronized on this
+ // handle or not.
+ GTEST_DEATH_TEST_CHECK_(
+ WAIT_OBJECT_0 == ::WaitForSingleObject(child_handle_.Get(),
+ INFINITE));
+ DWORD status_code;
+ GTEST_DEATH_TEST_CHECK_(
+ ::GetExitCodeProcess(child_handle_.Get(), &status_code) != FALSE);
+ child_handle_.Reset();
+ set_status(static_cast<int>(status_code));
+ return status();
+}
+
+// The AssumeRole process for a Windows death test. It creates a child
+// process with the same executable as the current process to run the
+// death test. The child process is given the --gtest_filter and
+// --gtest_internal_run_death_test flags such that it knows to run the
+// current death test only.
+DeathTest::TestRole WindowsDeathTest::AssumeRole() {
+ const UnitTestImpl* const impl = GetUnitTestImpl();
+ const InternalRunDeathTestFlag* const flag =
+ impl->internal_run_death_test_flag();
+ const TestInfo* const info = impl->current_test_info();
+ const int death_test_index = info->result()->death_test_count();
+
+ if (flag != nullptr) {
+ // ParseInternalRunDeathTestFlag() has performed all the necessary
+ // processing.
+ set_write_fd(flag->write_fd());
+ return EXECUTE_TEST;
+ }
+
+ // WindowsDeathTest uses an anonymous pipe to communicate results of
+ // a death test.
+ SECURITY_ATTRIBUTES handles_are_inheritable = {sizeof(SECURITY_ATTRIBUTES),
+ nullptr, TRUE};
+ HANDLE read_handle, write_handle;
+ GTEST_DEATH_TEST_CHECK_(
+ ::CreatePipe(&read_handle, &write_handle, &handles_are_inheritable,
+ 0) // Default buffer size.
+ != FALSE);
+ set_read_fd(::_open_osfhandle(reinterpret_cast<intptr_t>(read_handle),
+ O_RDONLY));
+ write_handle_.Reset(write_handle);
+ event_handle_.Reset(::CreateEvent(
+ &handles_are_inheritable,
+ TRUE, // The event will automatically reset to non-signaled state.
+ FALSE, // The initial state is non-signalled.
+ nullptr)); // The even is unnamed.
+ GTEST_DEATH_TEST_CHECK_(event_handle_.Get() != nullptr);
+ const std::string filter_flag = std::string("--") + GTEST_FLAG_PREFIX_ +
+ kFilterFlag + "=" + info->test_suite_name() +
+ "." + info->name();
+ const std::string internal_flag =
+ std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag +
+ "=" + file_ + "|" + StreamableToString(line_) + "|" +
+ StreamableToString(death_test_index) + "|" +
+ StreamableToString(static_cast<unsigned int>(::GetCurrentProcessId())) +
+ // size_t has the same width as pointers on both 32-bit and 64-bit
+ // Windows platforms.
+ // See http://msdn.microsoft.com/en-us/library/tcxf1dw6.aspx.
+ "|" + StreamableToString(reinterpret_cast<size_t>(write_handle)) +
+ "|" + StreamableToString(reinterpret_cast<size_t>(event_handle_.Get()));
+
+ char executable_path[_MAX_PATH + 1]; // NOLINT
+ GTEST_DEATH_TEST_CHECK_(_MAX_PATH + 1 != ::GetModuleFileNameA(nullptr,
+ executable_path,
+ _MAX_PATH));
+
+ std::string command_line =
+ std::string(::GetCommandLineA()) + " " + filter_flag + " \"" +
+ internal_flag + "\"";
+
+ DeathTest::set_last_death_test_message("");
+
+ CaptureStderr();
+ // Flush the log buffers since the log streams are shared with the child.
+ FlushInfoLog();
+
+ // The child process will share the standard handles with the parent.
+ STARTUPINFOA startup_info;
+ memset(&startup_info, 0, sizeof(STARTUPINFO));
+ startup_info.dwFlags = STARTF_USESTDHANDLES;
+ startup_info.hStdInput = ::GetStdHandle(STD_INPUT_HANDLE);
+ startup_info.hStdOutput = ::GetStdHandle(STD_OUTPUT_HANDLE);
+ startup_info.hStdError = ::GetStdHandle(STD_ERROR_HANDLE);
+
+ PROCESS_INFORMATION process_info;
+ GTEST_DEATH_TEST_CHECK_(
+ ::CreateProcessA(
+ executable_path, const_cast<char*>(command_line.c_str()),
+ nullptr, // Retuned process handle is not inheritable.
+ nullptr, // Retuned thread handle is not inheritable.
+ TRUE, // Child inherits all inheritable handles (for write_handle_).
+ 0x0, // Default creation flags.
+ nullptr, // Inherit the parent's environment.
+ UnitTest::GetInstance()->original_working_dir(), &startup_info,
+ &process_info) != FALSE);
+ child_handle_.Reset(process_info.hProcess);
+ ::CloseHandle(process_info.hThread);
+ set_spawned(true);
+ return OVERSEE_TEST;
+}
+
+# elif GTEST_OS_FUCHSIA
+
+class FuchsiaDeathTest : public DeathTestImpl {
+ public:
+ FuchsiaDeathTest(const char* a_statement, Matcher<const std::string&> matcher,
+ const char* file, int line)
+ : DeathTestImpl(a_statement, std::move(matcher)),
+ file_(file),
+ line_(line) {}
+
+ // All of these virtual functions are inherited from DeathTest.
+ int Wait() override;
+ TestRole AssumeRole() override;
+ std::string GetErrorLogs() override;
+
+ private:
+ // The name of the file in which the death test is located.
+ const char* const file_;
+ // The line number on which the death test is located.
+ const int line_;
+ // The stderr data captured by the child process.
+ std::string captured_stderr_;
+
+ zx::process child_process_;
+ zx::channel exception_channel_;
+ zx::socket stderr_socket_;
+};
+
+// Utility class for accumulating command-line arguments.
+class Arguments {
+ public:
+ Arguments() { args_.push_back(nullptr); }
+
+ ~Arguments() {
+ for (std::vector<char*>::iterator i = args_.begin(); i != args_.end();
+ ++i) {
+ free(*i);
+ }
+ }
+ void AddArgument(const char* argument) {
+ args_.insert(args_.end() - 1, posix::StrDup(argument));
+ }
+
+ template <typename Str>
+ void AddArguments(const ::std::vector<Str>& arguments) {
+ for (typename ::std::vector<Str>::const_iterator i = arguments.begin();
+ i != arguments.end();
+ ++i) {
+ args_.insert(args_.end() - 1, posix::StrDup(i->c_str()));
+ }
+ }
+ char* const* Argv() {
+ return &args_[0];
+ }
+
+ int size() {
+ return static_cast<int>(args_.size()) - 1;
+ }
+
+ private:
+ std::vector<char*> args_;
+};
+
+// Waits for the child in a death test to exit, returning its exit
+// status, or 0 if no child process exists. As a side effect, sets the
+// outcome data member.
+int FuchsiaDeathTest::Wait() {
+ const int kProcessKey = 0;
+ const int kSocketKey = 1;
+ const int kExceptionKey = 2;
+
+ if (!spawned())
+ return 0;
+
+ // Create a port to wait for socket/task/exception events.
+ zx_status_t status_zx;
+ zx::port port;
+ status_zx = zx::port::create(0, &port);
+ GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK);
+
+ // Register to wait for the child process to terminate.
+ status_zx = child_process_.wait_async(
+ port, kProcessKey, ZX_PROCESS_TERMINATED, 0);
+ GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK);
+
+ // Register to wait for the socket to be readable or closed.
+ status_zx = stderr_socket_.wait_async(
+ port, kSocketKey, ZX_SOCKET_READABLE | ZX_SOCKET_PEER_CLOSED, 0);
+ GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK);
+
+ // Register to wait for an exception.
+ status_zx = exception_channel_.wait_async(
+ port, kExceptionKey, ZX_CHANNEL_READABLE, 0);
+ GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK);
+
+ bool process_terminated = false;
+ bool socket_closed = false;
+ do {
+ zx_port_packet_t packet = {};
+ status_zx = port.wait(zx::time::infinite(), &packet);
+ GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK);
+
+ if (packet.key == kExceptionKey) {
+ // Process encountered an exception. Kill it directly rather than
+ // letting other handlers process the event. We will get a kProcessKey
+ // event when the process actually terminates.
+ status_zx = child_process_.kill();
+ GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK);
+ } else if (packet.key == kProcessKey) {
+ // Process terminated.
+ GTEST_DEATH_TEST_CHECK_(ZX_PKT_IS_SIGNAL_ONE(packet.type));
+ GTEST_DEATH_TEST_CHECK_(packet.signal.observed & ZX_PROCESS_TERMINATED);
+ process_terminated = true;
+ } else if (packet.key == kSocketKey) {
+ GTEST_DEATH_TEST_CHECK_(ZX_PKT_IS_SIGNAL_ONE(packet.type));
+ if (packet.signal.observed & ZX_SOCKET_READABLE) {
+ // Read data from the socket.
+ constexpr size_t kBufferSize = 1024;
+ do {
+ size_t old_length = captured_stderr_.length();
+ size_t bytes_read = 0;
+ captured_stderr_.resize(old_length + kBufferSize);
+ status_zx = stderr_socket_.read(
+ 0, &captured_stderr_.front() + old_length, kBufferSize,
+ &bytes_read);
+ captured_stderr_.resize(old_length + bytes_read);
+ } while (status_zx == ZX_OK);
+ if (status_zx == ZX_ERR_PEER_CLOSED) {
+ socket_closed = true;
+ } else {
+ GTEST_DEATH_TEST_CHECK_(status_zx == ZX_ERR_SHOULD_WAIT);
+ status_zx = stderr_socket_.wait_async(
+ port, kSocketKey, ZX_SOCKET_READABLE | ZX_SOCKET_PEER_CLOSED, 0);
+ GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK);
+ }
+ } else {
+ GTEST_DEATH_TEST_CHECK_(packet.signal.observed & ZX_SOCKET_PEER_CLOSED);
+ socket_closed = true;
+ }
+ }
+ } while (!process_terminated && !socket_closed);
+
+ ReadAndInterpretStatusByte();
+
+ zx_info_process_t buffer;
+ status_zx = child_process_.get_info(ZX_INFO_PROCESS, &buffer, sizeof(buffer),
+ nullptr, nullptr);
+ GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK);
+
+ GTEST_DEATH_TEST_CHECK_(buffer.flags & ZX_INFO_PROCESS_FLAG_EXITED);
+ set_status(static_cast<int>(buffer.return_code));
+ return status();
+}
+
+// The AssumeRole process for a Fuchsia death test. It creates a child
+// process with the same executable as the current process to run the
+// death test. The child process is given the --gtest_filter and
+// --gtest_internal_run_death_test flags such that it knows to run the
+// current death test only.
+DeathTest::TestRole FuchsiaDeathTest::AssumeRole() {
+ const UnitTestImpl* const impl = GetUnitTestImpl();
+ const InternalRunDeathTestFlag* const flag =
+ impl->internal_run_death_test_flag();
+ const TestInfo* const info = impl->current_test_info();
+ const int death_test_index = info->result()->death_test_count();
+
+ if (flag != nullptr) {
+ // ParseInternalRunDeathTestFlag() has performed all the necessary
+ // processing.
+ set_write_fd(kFuchsiaReadPipeFd);
+ return EXECUTE_TEST;
+ }
+
+ // Flush the log buffers since the log streams are shared with the child.
+ FlushInfoLog();
+
+ // Build the child process command line.
+ const std::string filter_flag = std::string("--") + GTEST_FLAG_PREFIX_ +
+ kFilterFlag + "=" + info->test_suite_name() +
+ "." + info->name();
+ const std::string internal_flag =
+ std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + "="
+ + file_ + "|"
+ + StreamableToString(line_) + "|"
+ + StreamableToString(death_test_index);
+ Arguments args;
+ args.AddArguments(GetInjectableArgvs());
+ args.AddArgument(filter_flag.c_str());
+ args.AddArgument(internal_flag.c_str());
+
+ // Build the pipe for communication with the child.
+ zx_status_t status;
+ zx_handle_t child_pipe_handle;
+ int child_pipe_fd;
+ status = fdio_pipe_half(&child_pipe_fd, &child_pipe_handle);
+ GTEST_DEATH_TEST_CHECK_(status == ZX_OK);
+ set_read_fd(child_pipe_fd);
+
+ // Set the pipe handle for the child.
+ fdio_spawn_action_t spawn_actions[2] = {};
+ fdio_spawn_action_t* add_handle_action = &spawn_actions[0];
+ add_handle_action->action = FDIO_SPAWN_ACTION_ADD_HANDLE;
+ add_handle_action->h.id = PA_HND(PA_FD, kFuchsiaReadPipeFd);
+ add_handle_action->h.handle = child_pipe_handle;
+
+ // Create a socket pair will be used to receive the child process' stderr.
+ zx::socket stderr_producer_socket;
+ status =
+ zx::socket::create(0, &stderr_producer_socket, &stderr_socket_);
+ GTEST_DEATH_TEST_CHECK_(status >= 0);
+ int stderr_producer_fd = -1;
+ status =
+ fdio_fd_create(stderr_producer_socket.release(), &stderr_producer_fd);
+ GTEST_DEATH_TEST_CHECK_(status >= 0);
+
+ // Make the stderr socket nonblocking.
+ GTEST_DEATH_TEST_CHECK_(fcntl(stderr_producer_fd, F_SETFL, 0) == 0);
+
+ fdio_spawn_action_t* add_stderr_action = &spawn_actions[1];
+ add_stderr_action->action = FDIO_SPAWN_ACTION_CLONE_FD;
+ add_stderr_action->fd.local_fd = stderr_producer_fd;
+ add_stderr_action->fd.target_fd = STDERR_FILENO;
+
+ // Create a child job.
+ zx_handle_t child_job = ZX_HANDLE_INVALID;
+ status = zx_job_create(zx_job_default(), 0, & child_job);
+ GTEST_DEATH_TEST_CHECK_(status == ZX_OK);
+ zx_policy_basic_t policy;
+ policy.condition = ZX_POL_NEW_ANY;
+ policy.policy = ZX_POL_ACTION_ALLOW;
+ status = zx_job_set_policy(
+ child_job, ZX_JOB_POL_RELATIVE, ZX_JOB_POL_BASIC, &policy, 1);
+ GTEST_DEATH_TEST_CHECK_(status == ZX_OK);
+
+ // Create an exception channel attached to the |child_job|, to allow
+ // us to suppress the system default exception handler from firing.
+ status =
+ zx_task_create_exception_channel(
+ child_job, 0, exception_channel_.reset_and_get_address());
+ GTEST_DEATH_TEST_CHECK_(status == ZX_OK);
+
+ // Spawn the child process.
+ status = fdio_spawn_etc(
+ child_job, FDIO_SPAWN_CLONE_ALL, args.Argv()[0], args.Argv(), nullptr,
+ 2, spawn_actions, child_process_.reset_and_get_address(), nullptr);
+ GTEST_DEATH_TEST_CHECK_(status == ZX_OK);
+
+ set_spawned(true);
+ return OVERSEE_TEST;
+}
+
+std::string FuchsiaDeathTest::GetErrorLogs() {
+ return captured_stderr_;
+}
+
+#else // We are neither on Windows, nor on Fuchsia.
+
+// ForkingDeathTest provides implementations for most of the abstract
+// methods of the DeathTest interface. Only the AssumeRole method is
+// left undefined.
+class ForkingDeathTest : public DeathTestImpl {
+ public:
+ ForkingDeathTest(const char* statement, Matcher<const std::string&> matcher);
+
+ // All of these virtual functions are inherited from DeathTest.
+ int Wait() override;
+
+ protected:
+ void set_child_pid(pid_t child_pid) { child_pid_ = child_pid; }
+
+ private:
+ // PID of child process during death test; 0 in the child process itself.
+ pid_t child_pid_;
+};
+
+// Constructs a ForkingDeathTest.
+ForkingDeathTest::ForkingDeathTest(const char* a_statement,
+ Matcher<const std::string&> matcher)
+ : DeathTestImpl(a_statement, std::move(matcher)), child_pid_(-1) {}
+
+// Waits for the child in a death test to exit, returning its exit
+// status, or 0 if no child process exists. As a side effect, sets the
+// outcome data member.
+int ForkingDeathTest::Wait() {
+ if (!spawned())
+ return 0;
+
+ ReadAndInterpretStatusByte();
+
+ int status_value;
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(waitpid(child_pid_, &status_value, 0));
+ set_status(status_value);
+ return status_value;
+}
+
+// A concrete death test class that forks, then immediately runs the test
+// in the child process.
+class NoExecDeathTest : public ForkingDeathTest {
+ public:
+ NoExecDeathTest(const char* a_statement, Matcher<const std::string&> matcher)
+ : ForkingDeathTest(a_statement, std::move(matcher)) {}
+ TestRole AssumeRole() override;
+};
+
+// The AssumeRole process for a fork-and-run death test. It implements a
+// straightforward fork, with a simple pipe to transmit the status byte.
+DeathTest::TestRole NoExecDeathTest::AssumeRole() {
+ const size_t thread_count = GetThreadCount();
+ if (thread_count != 1) {
+ GTEST_LOG_(WARNING) << DeathTestThreadWarning(thread_count);
+ }
+
+ int pipe_fd[2];
+ GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1);
+
+ DeathTest::set_last_death_test_message("");
+ CaptureStderr();
+ // When we fork the process below, the log file buffers are copied, but the
+ // file descriptors are shared. We flush all log files here so that closing
+ // the file descriptors in the child process doesn't throw off the
+ // synchronization between descriptors and buffers in the parent process.
+ // This is as close to the fork as possible to avoid a race condition in case
+ // there are multiple threads running before the death test, and another
+ // thread writes to the log file.
+ FlushInfoLog();
+
+ const pid_t child_pid = fork();
+ GTEST_DEATH_TEST_CHECK_(child_pid != -1);
+ set_child_pid(child_pid);
+ if (child_pid == 0) {
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[0]));
+ set_write_fd(pipe_fd[1]);
+ // Redirects all logging to stderr in the child process to prevent
+ // concurrent writes to the log files. We capture stderr in the parent
+ // process and append the child process' output to a log.
+ LogToStderr();
+ // Event forwarding to the listeners of event listener API mush be shut
+ // down in death test subprocesses.
+ GetUnitTestImpl()->listeners()->SuppressEventForwarding();
+ g_in_fast_death_test_child = true;
+ return EXECUTE_TEST;
+ } else {
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1]));
+ set_read_fd(pipe_fd[0]);
+ set_spawned(true);
+ return OVERSEE_TEST;
+ }
+}
+
+// A concrete death test class that forks and re-executes the main
+// program from the beginning, with command-line flags set that cause
+// only this specific death test to be run.
+class ExecDeathTest : public ForkingDeathTest {
+ public:
+ ExecDeathTest(const char* a_statement, Matcher<const std::string&> matcher,
+ const char* file, int line)
+ : ForkingDeathTest(a_statement, std::move(matcher)),
+ file_(file),
+ line_(line) {}
+ TestRole AssumeRole() override;
+
+ private:
+ static ::std::vector<std::string> GetArgvsForDeathTestChildProcess() {
+ ::std::vector<std::string> args = GetInjectableArgvs();
+# if defined(GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_)
+ ::std::vector<std::string> extra_args =
+ GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_();
+ args.insert(args.end(), extra_args.begin(), extra_args.end());
+# endif // defined(GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_)
+ return args;
+ }
+ // The name of the file in which the death test is located.
+ const char* const file_;
+ // The line number on which the death test is located.
+ const int line_;
+};
+
+// Utility class for accumulating command-line arguments.
+class Arguments {
+ public:
+ Arguments() { args_.push_back(nullptr); }
+
+ ~Arguments() {
+ for (std::vector<char*>::iterator i = args_.begin(); i != args_.end();
+ ++i) {
+ free(*i);
+ }
+ }
+ void AddArgument(const char* argument) {
+ args_.insert(args_.end() - 1, posix::StrDup(argument));
+ }
+
+ template <typename Str>
+ void AddArguments(const ::std::vector<Str>& arguments) {
+ for (typename ::std::vector<Str>::const_iterator i = arguments.begin();
+ i != arguments.end();
+ ++i) {
+ args_.insert(args_.end() - 1, posix::StrDup(i->c_str()));
+ }
+ }
+ char* const* Argv() {
+ return &args_[0];
+ }
+
+ private:
+ std::vector<char*> args_;
+};
+
+// A struct that encompasses the arguments to the child process of a
+// threadsafe-style death test process.
+struct ExecDeathTestArgs {
+ char* const* argv; // Command-line arguments for the child's call to exec
+ int close_fd; // File descriptor to close; the read end of a pipe
+};
+
+# if GTEST_OS_QNX
+extern "C" char** environ;
+# else // GTEST_OS_QNX
+// The main function for a threadsafe-style death test child process.
+// This function is called in a clone()-ed process and thus must avoid
+// any potentially unsafe operations like malloc or libc functions.
+static int ExecDeathTestChildMain(void* child_arg) {
+ ExecDeathTestArgs* const args = static_cast<ExecDeathTestArgs*>(child_arg);
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(close(args->close_fd));
+
+ // We need to execute the test program in the same environment where
+ // it was originally invoked. Therefore we change to the original
+ // working directory first.
+ const char* const original_dir =
+ UnitTest::GetInstance()->original_working_dir();
+ // We can safely call chdir() as it's a direct system call.
+ if (chdir(original_dir) != 0) {
+ DeathTestAbort(std::string("chdir(\"") + original_dir + "\") failed: " +
+ GetLastErrnoDescription());
+ return EXIT_FAILURE;
+ }
+
+ // We can safely call execv() as it's almost a direct system call. We
+ // cannot use execvp() as it's a libc function and thus potentially
+ // unsafe. Since execv() doesn't search the PATH, the user must
+ // invoke the test program via a valid path that contains at least
+ // one path separator.
+ execv(args->argv[0], args->argv);
+ DeathTestAbort(std::string("execv(") + args->argv[0] + ", ...) in " +
+ original_dir + " failed: " +
+ GetLastErrnoDescription());
+ return EXIT_FAILURE;
+}
+# endif // GTEST_OS_QNX
+
+# if GTEST_HAS_CLONE
+// Two utility routines that together determine the direction the stack
+// grows.
+// This could be accomplished more elegantly by a single recursive
+// function, but we want to guard against the unlikely possibility of
+// a smart compiler optimizing the recursion away.
+//
+// GTEST_NO_INLINE_ is required to prevent GCC 4.6 from inlining
+// StackLowerThanAddress into StackGrowsDown, which then doesn't give
+// correct answer.
+static void StackLowerThanAddress(const void* ptr,
+ bool* result) GTEST_NO_INLINE_;
+// Make sure sanitizers do not tamper with the stack here.
+// Ideally, we want to use `__builtin_frame_address` instead of a local variable
+// address with sanitizer disabled, but it does not work when the
+// compiler optimizes the stack frame out, which happens on PowerPC targets.
+// HWAddressSanitizer add a random tag to the MSB of the local variable address,
+// making comparison result unpredictable.
+GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
+GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_
+static void StackLowerThanAddress(const void* ptr, bool* result) {
+ int dummy = 0;
+ *result = std::less<const void*>()(&dummy, ptr);
+}
+
+// Make sure AddressSanitizer does not tamper with the stack here.
+GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
+GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_
+static bool StackGrowsDown() {
+ int dummy = 0;
+ bool result;
+ StackLowerThanAddress(&dummy, &result);
+ return result;
+}
+# endif // GTEST_HAS_CLONE
+
+// Spawns a child process with the same executable as the current process in
+// a thread-safe manner and instructs it to run the death test. The
+// implementation uses fork(2) + exec. On systems where clone(2) is
+// available, it is used instead, being slightly more thread-safe. On QNX,
+// fork supports only single-threaded environments, so this function uses
+// spawn(2) there instead. The function dies with an error message if
+// anything goes wrong.
+static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) {
+ ExecDeathTestArgs args = { argv, close_fd };
+ pid_t child_pid = -1;
+
+# if GTEST_OS_QNX
+ // Obtains the current directory and sets it to be closed in the child
+ // process.
+ const int cwd_fd = open(".", O_RDONLY);
+ GTEST_DEATH_TEST_CHECK_(cwd_fd != -1);
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(fcntl(cwd_fd, F_SETFD, FD_CLOEXEC));
+ // We need to execute the test program in the same environment where
+ // it was originally invoked. Therefore we change to the original
+ // working directory first.
+ const char* const original_dir =
+ UnitTest::GetInstance()->original_working_dir();
+ // We can safely call chdir() as it's a direct system call.
+ if (chdir(original_dir) != 0) {
+ DeathTestAbort(std::string("chdir(\"") + original_dir + "\") failed: " +
+ GetLastErrnoDescription());
+ return EXIT_FAILURE;
+ }
+
+ int fd_flags;
+ // Set close_fd to be closed after spawn.
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(fd_flags = fcntl(close_fd, F_GETFD));
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(fcntl(close_fd, F_SETFD,
+ fd_flags | FD_CLOEXEC));
+ struct inheritance inherit = {0};
+ // spawn is a system call.
+ child_pid = spawn(args.argv[0], 0, nullptr, &inherit, args.argv, environ);
+ // Restores the current working directory.
+ GTEST_DEATH_TEST_CHECK_(fchdir(cwd_fd) != -1);
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(close(cwd_fd));
+
+# else // GTEST_OS_QNX
+# if GTEST_OS_LINUX
+ // When a SIGPROF signal is received while fork() or clone() are executing,
+ // the process may hang. To avoid this, we ignore SIGPROF here and re-enable
+ // it after the call to fork()/clone() is complete.
+ struct sigaction saved_sigprof_action;
+ struct sigaction ignore_sigprof_action;
+ memset(&ignore_sigprof_action, 0, sizeof(ignore_sigprof_action));
+ sigemptyset(&ignore_sigprof_action.sa_mask);
+ ignore_sigprof_action.sa_handler = SIG_IGN;
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(sigaction(
+ SIGPROF, &ignore_sigprof_action, &saved_sigprof_action));
+# endif // GTEST_OS_LINUX
+
+# if GTEST_HAS_CLONE
+ const bool use_fork = GTEST_FLAG(death_test_use_fork);
+
+ if (!use_fork) {
+ static const bool stack_grows_down = StackGrowsDown();
+ const auto stack_size = static_cast<size_t>(getpagesize() * 2);
+ // MMAP_ANONYMOUS is not defined on Mac, so we use MAP_ANON instead.
+ void* const stack = mmap(nullptr, stack_size, PROT_READ | PROT_WRITE,
+ MAP_ANON | MAP_PRIVATE, -1, 0);
+ GTEST_DEATH_TEST_CHECK_(stack != MAP_FAILED);
+
+ // Maximum stack alignment in bytes: For a downward-growing stack, this
+ // amount is subtracted from size of the stack space to get an address
+ // that is within the stack space and is aligned on all systems we care
+ // about. As far as I know there is no ABI with stack alignment greater
+ // than 64. We assume stack and stack_size already have alignment of
+ // kMaxStackAlignment.
+ const size_t kMaxStackAlignment = 64;
+ void* const stack_top =
+ static_cast<char*>(stack) +
+ (stack_grows_down ? stack_size - kMaxStackAlignment : 0);
+ GTEST_DEATH_TEST_CHECK_(
+ static_cast<size_t>(stack_size) > kMaxStackAlignment &&
+ reinterpret_cast<uintptr_t>(stack_top) % kMaxStackAlignment == 0);
+
+ child_pid = clone(&ExecDeathTestChildMain, stack_top, SIGCHLD, &args);
+
+ GTEST_DEATH_TEST_CHECK_(munmap(stack, stack_size) != -1);
+ }
+# else
+ const bool use_fork = true;
+# endif // GTEST_HAS_CLONE
+
+ if (use_fork && (child_pid = fork()) == 0) {
+ ExecDeathTestChildMain(&args);
+ _exit(0);
+ }
+# endif // GTEST_OS_QNX
+# if GTEST_OS_LINUX
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(
+ sigaction(SIGPROF, &saved_sigprof_action, nullptr));
+# endif // GTEST_OS_LINUX
+
+ GTEST_DEATH_TEST_CHECK_(child_pid != -1);
+ return child_pid;
+}
+
+// The AssumeRole process for a fork-and-exec death test. It re-executes the
+// main program from the beginning, setting the --gtest_filter
+// and --gtest_internal_run_death_test flags to cause only the current
+// death test to be re-run.
+DeathTest::TestRole ExecDeathTest::AssumeRole() {
+ const UnitTestImpl* const impl = GetUnitTestImpl();
+ const InternalRunDeathTestFlag* const flag =
+ impl->internal_run_death_test_flag();
+ const TestInfo* const info = impl->current_test_info();
+ const int death_test_index = info->result()->death_test_count();
+
+ if (flag != nullptr) {
+ set_write_fd(flag->write_fd());
+ return EXECUTE_TEST;
+ }
+
+ int pipe_fd[2];
+ GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1);
+ // Clear the close-on-exec flag on the write end of the pipe, lest
+ // it be closed when the child process does an exec:
+ GTEST_DEATH_TEST_CHECK_(fcntl(pipe_fd[1], F_SETFD, 0) != -1);
+
+ const std::string filter_flag = std::string("--") + GTEST_FLAG_PREFIX_ +
+ kFilterFlag + "=" + info->test_suite_name() +
+ "." + info->name();
+ const std::string internal_flag =
+ std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + "="
+ + file_ + "|" + StreamableToString(line_) + "|"
+ + StreamableToString(death_test_index) + "|"
+ + StreamableToString(pipe_fd[1]);
+ Arguments args;
+ args.AddArguments(GetArgvsForDeathTestChildProcess());
+ args.AddArgument(filter_flag.c_str());
+ args.AddArgument(internal_flag.c_str());
+
+ DeathTest::set_last_death_test_message("");
+
+ CaptureStderr();
+ // See the comment in NoExecDeathTest::AssumeRole for why the next line
+ // is necessary.
+ FlushInfoLog();
+
+ const pid_t child_pid = ExecDeathTestSpawnChild(args.Argv(), pipe_fd[0]);
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1]));
+ set_child_pid(child_pid);
+ set_read_fd(pipe_fd[0]);
+ set_spawned(true);
+ return OVERSEE_TEST;
+}
+
+# endif // !GTEST_OS_WINDOWS
+
+// Creates a concrete DeathTest-derived class that depends on the
+// --gtest_death_test_style flag, and sets the pointer pointed to
+// by the "test" argument to its address. If the test should be
+// skipped, sets that pointer to NULL. Returns true, unless the
+// flag is set to an invalid value.
+bool DefaultDeathTestFactory::Create(const char* statement,
+ Matcher<const std::string&> matcher,
+ const char* file, int line,
+ DeathTest** test) {
+ UnitTestImpl* const impl = GetUnitTestImpl();
+ const InternalRunDeathTestFlag* const flag =
+ impl->internal_run_death_test_flag();
+ const int death_test_index = impl->current_test_info()
+ ->increment_death_test_count();
+
+ if (flag != nullptr) {
+ if (death_test_index > flag->index()) {
+ DeathTest::set_last_death_test_message(
+ "Death test count (" + StreamableToString(death_test_index)
+ + ") somehow exceeded expected maximum ("
+ + StreamableToString(flag->index()) + ")");
+ return false;
+ }
+
+ if (!(flag->file() == file && flag->line() == line &&
+ flag->index() == death_test_index)) {
+ *test = nullptr;
+ return true;
+ }
+ }
+
+# if GTEST_OS_WINDOWS
+
+ if (GTEST_FLAG(death_test_style) == "threadsafe" ||
+ GTEST_FLAG(death_test_style) == "fast") {
+ *test = new WindowsDeathTest(statement, std::move(matcher), file, line);
+ }
+
+# elif GTEST_OS_FUCHSIA
+
+ if (GTEST_FLAG(death_test_style) == "threadsafe" ||
+ GTEST_FLAG(death_test_style) == "fast") {
+ *test = new FuchsiaDeathTest(statement, std::move(matcher), file, line);
+ }
+
+# else
+
+ if (GTEST_FLAG(death_test_style) == "threadsafe") {
+ *test = new ExecDeathTest(statement, std::move(matcher), file, line);
+ } else if (GTEST_FLAG(death_test_style) == "fast") {
+ *test = new NoExecDeathTest(statement, std::move(matcher));
+ }
+
+# endif // GTEST_OS_WINDOWS
+
+ else { // NOLINT - this is more readable than unbalanced brackets inside #if.
+ DeathTest::set_last_death_test_message(
+ "Unknown death test style \"" + GTEST_FLAG(death_test_style)
+ + "\" encountered");
+ return false;
+ }
+
+ return true;
+}
+
+# if GTEST_OS_WINDOWS
+// Recreates the pipe and event handles from the provided parameters,
+// signals the event, and returns a file descriptor wrapped around the pipe
+// handle. This function is called in the child process only.
+static int GetStatusFileDescriptor(unsigned int parent_process_id,
+ size_t write_handle_as_size_t,
+ size_t event_handle_as_size_t) {
+ AutoHandle parent_process_handle(::OpenProcess(PROCESS_DUP_HANDLE,
+ FALSE, // Non-inheritable.
+ parent_process_id));
+ if (parent_process_handle.Get() == INVALID_HANDLE_VALUE) {
+ DeathTestAbort("Unable to open parent process " +
+ StreamableToString(parent_process_id));
+ }
+
+ GTEST_CHECK_(sizeof(HANDLE) <= sizeof(size_t));
+
+ const HANDLE write_handle =
+ reinterpret_cast<HANDLE>(write_handle_as_size_t);
+ HANDLE dup_write_handle;
+
+ // The newly initialized handle is accessible only in the parent
+ // process. To obtain one accessible within the child, we need to use
+ // DuplicateHandle.
+ if (!::DuplicateHandle(parent_process_handle.Get(), write_handle,
+ ::GetCurrentProcess(), &dup_write_handle,
+ 0x0, // Requested privileges ignored since
+ // DUPLICATE_SAME_ACCESS is used.
+ FALSE, // Request non-inheritable handler.
+ DUPLICATE_SAME_ACCESS)) {
+ DeathTestAbort("Unable to duplicate the pipe handle " +
+ StreamableToString(write_handle_as_size_t) +
+ " from the parent process " +
+ StreamableToString(parent_process_id));
+ }
+
+ const HANDLE event_handle = reinterpret_cast<HANDLE>(event_handle_as_size_t);
+ HANDLE dup_event_handle;
+
+ if (!::DuplicateHandle(parent_process_handle.Get(), event_handle,
+ ::GetCurrentProcess(), &dup_event_handle,
+ 0x0,
+ FALSE,
+ DUPLICATE_SAME_ACCESS)) {
+ DeathTestAbort("Unable to duplicate the event handle " +
+ StreamableToString(event_handle_as_size_t) +
+ " from the parent process " +
+ StreamableToString(parent_process_id));
+ }
+
+ const int write_fd =
+ ::_open_osfhandle(reinterpret_cast<intptr_t>(dup_write_handle), O_APPEND);
+ if (write_fd == -1) {
+ DeathTestAbort("Unable to convert pipe handle " +
+ StreamableToString(write_handle_as_size_t) +
+ " to a file descriptor");
+ }
+
+ // Signals the parent that the write end of the pipe has been acquired
+ // so the parent can release its own write end.
+ ::SetEvent(dup_event_handle);
+
+ return write_fd;
+}
+# endif // GTEST_OS_WINDOWS
+
+// Returns a newly created InternalRunDeathTestFlag object with fields
+// initialized from the GTEST_FLAG(internal_run_death_test) flag if
+// the flag is specified; otherwise returns NULL.
+InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() {
+ if (GTEST_FLAG(internal_run_death_test) == "") return nullptr;
+
+ // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we
+ // can use it here.
+ int line = -1;
+ int index = -1;
+ ::std::vector< ::std::string> fields;
+ SplitString(GTEST_FLAG(internal_run_death_test).c_str(), '|', &fields);
+ int write_fd = -1;
+
+# if GTEST_OS_WINDOWS
+
+ unsigned int parent_process_id = 0;
+ size_t write_handle_as_size_t = 0;
+ size_t event_handle_as_size_t = 0;
+
+ if (fields.size() != 6
+ || !ParseNaturalNumber(fields[1], &line)
+ || !ParseNaturalNumber(fields[2], &index)
+ || !ParseNaturalNumber(fields[3], &parent_process_id)
+ || !ParseNaturalNumber(fields[4], &write_handle_as_size_t)
+ || !ParseNaturalNumber(fields[5], &event_handle_as_size_t)) {
+ DeathTestAbort("Bad --gtest_internal_run_death_test flag: " +
+ GTEST_FLAG(internal_run_death_test));
+ }
+ write_fd = GetStatusFileDescriptor(parent_process_id,
+ write_handle_as_size_t,
+ event_handle_as_size_t);
+
+# elif GTEST_OS_FUCHSIA
+
+ if (fields.size() != 3
+ || !ParseNaturalNumber(fields[1], &line)
+ || !ParseNaturalNumber(fields[2], &index)) {
+ DeathTestAbort("Bad --gtest_internal_run_death_test flag: "
+ + GTEST_FLAG(internal_run_death_test));
+ }
+
+# else
+
+ if (fields.size() != 4
+ || !ParseNaturalNumber(fields[1], &line)
+ || !ParseNaturalNumber(fields[2], &index)
+ || !ParseNaturalNumber(fields[3], &write_fd)) {
+ DeathTestAbort("Bad --gtest_internal_run_death_test flag: "
+ + GTEST_FLAG(internal_run_death_test));
+ }
+
+# endif // GTEST_OS_WINDOWS
+
+ return new InternalRunDeathTestFlag(fields[0], line, index, write_fd);
+}
+
+} // namespace internal
+
+#endif // GTEST_HAS_DEATH_TEST
+
+} // namespace testing
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+#include <stdlib.h>
+
+#if GTEST_OS_WINDOWS_MOBILE
+# include <windows.h>
+#elif GTEST_OS_WINDOWS
+# include <direct.h>
+# include <io.h>
+#else
+# include <limits.h>
+# include <climits> // Some Linux distributions define PATH_MAX here.
+#endif // GTEST_OS_WINDOWS_MOBILE
+
+
+#if GTEST_OS_WINDOWS
+# define GTEST_PATH_MAX_ _MAX_PATH
+#elif defined(PATH_MAX)
+# define GTEST_PATH_MAX_ PATH_MAX
+#elif defined(_XOPEN_PATH_MAX)
+# define GTEST_PATH_MAX_ _XOPEN_PATH_MAX
+#else
+# define GTEST_PATH_MAX_ _POSIX_PATH_MAX
+#endif // GTEST_OS_WINDOWS
+
+namespace testing {
+namespace internal {
+
+#if GTEST_OS_WINDOWS
+// On Windows, '\\' is the standard path separator, but many tools and the
+// Windows API also accept '/' as an alternate path separator. Unless otherwise
+// noted, a file path can contain either kind of path separators, or a mixture
+// of them.
+const char kPathSeparator = '\\';
+const char kAlternatePathSeparator = '/';
+const char kAlternatePathSeparatorString[] = "/";
+# if GTEST_OS_WINDOWS_MOBILE
+// Windows CE doesn't have a current directory. You should not use
+// the current directory in tests on Windows CE, but this at least
+// provides a reasonable fallback.
+const char kCurrentDirectoryString[] = "\\";
+// Windows CE doesn't define INVALID_FILE_ATTRIBUTES
+const DWORD kInvalidFileAttributes = 0xffffffff;
+# else
+const char kCurrentDirectoryString[] = ".\\";
+# endif // GTEST_OS_WINDOWS_MOBILE
+#else
+const char kPathSeparator = '/';
+const char kCurrentDirectoryString[] = "./";
+#endif // GTEST_OS_WINDOWS
+
+// Returns whether the given character is a valid path separator.
+static bool IsPathSeparator(char c) {
+#if GTEST_HAS_ALT_PATH_SEP_
+ return (c == kPathSeparator) || (c == kAlternatePathSeparator);
+#else
+ return c == kPathSeparator;
+#endif
+}
+
+// Returns the current working directory, or "" if unsuccessful.
+FilePath FilePath::GetCurrentDir() {
+#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || \
+ GTEST_OS_WINDOWS_RT || GTEST_OS_ESP8266 || GTEST_OS_ESP32 || \
+ GTEST_OS_XTENSA
+ // These platforms do not have a current directory, so we just return
+ // something reasonable.
+ return FilePath(kCurrentDirectoryString);
+#elif GTEST_OS_WINDOWS
+ char cwd[GTEST_PATH_MAX_ + 1] = { '\0' };
+ return FilePath(_getcwd(cwd, sizeof(cwd)) == nullptr ? "" : cwd);
+#else
+ char cwd[GTEST_PATH_MAX_ + 1] = { '\0' };
+ char* result = getcwd(cwd, sizeof(cwd));
+# if GTEST_OS_NACL
+ // getcwd will likely fail in NaCl due to the sandbox, so return something
+ // reasonable. The user may have provided a shim implementation for getcwd,
+ // however, so fallback only when failure is detected.
+ return FilePath(result == nullptr ? kCurrentDirectoryString : cwd);
+# endif // GTEST_OS_NACL
+ return FilePath(result == nullptr ? "" : cwd);
+#endif // GTEST_OS_WINDOWS_MOBILE
+}
+
+// Returns a copy of the FilePath with the case-insensitive extension removed.
+// Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns
+// FilePath("dir/file"). If a case-insensitive extension is not
+// found, returns a copy of the original FilePath.
+FilePath FilePath::RemoveExtension(const char* extension) const {
+ const std::string dot_extension = std::string(".") + extension;
+ if (String::EndsWithCaseInsensitive(pathname_, dot_extension)) {
+ return FilePath(pathname_.substr(
+ 0, pathname_.length() - dot_extension.length()));
+ }
+ return *this;
+}
+
+// Returns a pointer to the last occurrence of a valid path separator in
+// the FilePath. On Windows, for example, both '/' and '\' are valid path
+// separators. Returns NULL if no path separator was found.
+const char* FilePath::FindLastPathSeparator() const {
+ const char* const last_sep = strrchr(c_str(), kPathSeparator);
+#if GTEST_HAS_ALT_PATH_SEP_
+ const char* const last_alt_sep = strrchr(c_str(), kAlternatePathSeparator);
+ // Comparing two pointers of which only one is NULL is undefined.
+ if (last_alt_sep != nullptr &&
+ (last_sep == nullptr || last_alt_sep > last_sep)) {
+ return last_alt_sep;
+ }
+#endif
+ return last_sep;
+}
+
+// Returns a copy of the FilePath with the directory part removed.
+// Example: FilePath("path/to/file").RemoveDirectoryName() returns
+// FilePath("file"). If there is no directory part ("just_a_file"), it returns
+// the FilePath unmodified. If there is no file part ("just_a_dir/") it
+// returns an empty FilePath ("").
+// On Windows platform, '\' is the path separator, otherwise it is '/'.
+FilePath FilePath::RemoveDirectoryName() const {
+ const char* const last_sep = FindLastPathSeparator();
+ return last_sep ? FilePath(last_sep + 1) : *this;
+}
+
+// RemoveFileName returns the directory path with the filename removed.
+// Example: FilePath("path/to/file").RemoveFileName() returns "path/to/".
+// If the FilePath is "a_file" or "/a_file", RemoveFileName returns
+// FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does
+// not have a file, like "just/a/dir/", it returns the FilePath unmodified.
+// On Windows platform, '\' is the path separator, otherwise it is '/'.
+FilePath FilePath::RemoveFileName() const {
+ const char* const last_sep = FindLastPathSeparator();
+ std::string dir;
+ if (last_sep) {
+ dir = std::string(c_str(), static_cast<size_t>(last_sep + 1 - c_str()));
+ } else {
+ dir = kCurrentDirectoryString;
+ }
+ return FilePath(dir);
+}
+
+// Helper functions for naming files in a directory for xml output.
+
+// Given directory = "dir", base_name = "test", number = 0,
+// extension = "xml", returns "dir/test.xml". If number is greater
+// than zero (e.g., 12), returns "dir/test_12.xml".
+// On Windows platform, uses \ as the separator rather than /.
+FilePath FilePath::MakeFileName(const FilePath& directory,
+ const FilePath& base_name,
+ int number,
+ const char* extension) {
+ std::string file;
+ if (number == 0) {
+ file = base_name.string() + "." + extension;
+ } else {
+ file = base_name.string() + "_" + StreamableToString(number)
+ + "." + extension;
+ }
+ return ConcatPaths(directory, FilePath(file));
+}
+
+// Given directory = "dir", relative_path = "test.xml", returns "dir/test.xml".
+// On Windows, uses \ as the separator rather than /.
+FilePath FilePath::ConcatPaths(const FilePath& directory,
+ const FilePath& relative_path) {
+ if (directory.IsEmpty())
+ return relative_path;
+ const FilePath dir(directory.RemoveTrailingPathSeparator());
+ return FilePath(dir.string() + kPathSeparator + relative_path.string());
+}
+
+// Returns true if pathname describes something findable in the file-system,
+// either a file, directory, or whatever.
+bool FilePath::FileOrDirectoryExists() const {
+#if GTEST_OS_WINDOWS_MOBILE
+ LPCWSTR unicode = String::AnsiToUtf16(pathname_.c_str());
+ const DWORD attributes = GetFileAttributes(unicode);
+ delete [] unicode;
+ return attributes != kInvalidFileAttributes;
+#else
+ posix::StatStruct file_stat{};
+ return posix::Stat(pathname_.c_str(), &file_stat) == 0;
+#endif // GTEST_OS_WINDOWS_MOBILE
+}
+
+// Returns true if pathname describes a directory in the file-system
+// that exists.
+bool FilePath::DirectoryExists() const {
+ bool result = false;
+#if GTEST_OS_WINDOWS
+ // Don't strip off trailing separator if path is a root directory on
+ // Windows (like "C:\\").
+ const FilePath& path(IsRootDirectory() ? *this :
+ RemoveTrailingPathSeparator());
+#else
+ const FilePath& path(*this);
+#endif
+
+#if GTEST_OS_WINDOWS_MOBILE
+ LPCWSTR unicode = String::AnsiToUtf16(path.c_str());
+ const DWORD attributes = GetFileAttributes(unicode);
+ delete [] unicode;
+ if ((attributes != kInvalidFileAttributes) &&
+ (attributes & FILE_ATTRIBUTE_DIRECTORY)) {
+ result = true;
+ }
+#else
+ posix::StatStruct file_stat{};
+ result = posix::Stat(path.c_str(), &file_stat) == 0 &&
+ posix::IsDir(file_stat);
+#endif // GTEST_OS_WINDOWS_MOBILE
+
+ return result;
+}
+
+// Returns true if pathname describes a root directory. (Windows has one
+// root directory per disk drive.)
+bool FilePath::IsRootDirectory() const {
+#if GTEST_OS_WINDOWS
+ return pathname_.length() == 3 && IsAbsolutePath();
+#else
+ return pathname_.length() == 1 && IsPathSeparator(pathname_.c_str()[0]);
+#endif
+}
+
+// Returns true if pathname describes an absolute path.
+bool FilePath::IsAbsolutePath() const {
+ const char* const name = pathname_.c_str();
+#if GTEST_OS_WINDOWS
+ return pathname_.length() >= 3 &&
+ ((name[0] >= 'a' && name[0] <= 'z') ||
+ (name[0] >= 'A' && name[0] <= 'Z')) &&
+ name[1] == ':' &&
+ IsPathSeparator(name[2]);
+#else
+ return IsPathSeparator(name[0]);
+#endif
+}
+
+// Returns a pathname for a file that does not currently exist. The pathname
+// will be directory/base_name.extension or
+// directory/base_name_<number>.extension if directory/base_name.extension
+// already exists. The number will be incremented until a pathname is found
+// that does not already exist.
+// Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'.
+// There could be a race condition if two or more processes are calling this
+// function at the same time -- they could both pick the same filename.
+FilePath FilePath::GenerateUniqueFileName(const FilePath& directory,
+ const FilePath& base_name,
+ const char* extension) {
+ FilePath full_pathname;
+ int number = 0;
+ do {
+ full_pathname.Set(MakeFileName(directory, base_name, number++, extension));
+ } while (full_pathname.FileOrDirectoryExists());
+ return full_pathname;
+}
+
+// Returns true if FilePath ends with a path separator, which indicates that
+// it is intended to represent a directory. Returns false otherwise.
+// This does NOT check that a directory (or file) actually exists.
+bool FilePath::IsDirectory() const {
+ return !pathname_.empty() &&
+ IsPathSeparator(pathname_.c_str()[pathname_.length() - 1]);
+}
+
+// Create directories so that path exists. Returns true if successful or if
+// the directories already exist; returns false if unable to create directories
+// for any reason.
+bool FilePath::CreateDirectoriesRecursively() const {
+ if (!this->IsDirectory()) {
+ return false;
+ }
+
+ if (pathname_.length() == 0 || this->DirectoryExists()) {
+ return true;
+ }
+
+ const FilePath parent(this->RemoveTrailingPathSeparator().RemoveFileName());
+ return parent.CreateDirectoriesRecursively() && this->CreateFolder();
+}
+
+// Create the directory so that path exists. Returns true if successful or
+// if the directory already exists; returns false if unable to create the
+// directory for any reason, including if the parent directory does not
+// exist. Not named "CreateDirectory" because that's a macro on Windows.
+bool FilePath::CreateFolder() const {
+#if GTEST_OS_WINDOWS_MOBILE
+ FilePath removed_sep(this->RemoveTrailingPathSeparator());
+ LPCWSTR unicode = String::AnsiToUtf16(removed_sep.c_str());
+ int result = CreateDirectory(unicode, nullptr) ? 0 : -1;
+ delete [] unicode;
+#elif GTEST_OS_WINDOWS
+ int result = _mkdir(pathname_.c_str());
+#elif GTEST_OS_ESP8266 || GTEST_OS_XTENSA
+ // do nothing
+ int result = 0;
+#else
+ int result = mkdir(pathname_.c_str(), 0777);
+#endif // GTEST_OS_WINDOWS_MOBILE
+
+ if (result == -1) {
+ return this->DirectoryExists(); // An error is OK if the directory exists.
+ }
+ return true; // No error.
+}
+
+// If input name has a trailing separator character, remove it and return the
+// name, otherwise return the name string unmodified.
+// On Windows platform, uses \ as the separator, other platforms use /.
+FilePath FilePath::RemoveTrailingPathSeparator() const {
+ return IsDirectory()
+ ? FilePath(pathname_.substr(0, pathname_.length() - 1))
+ : *this;
+}
+
+// Removes any redundant separators that might be in the pathname.
+// For example, "bar///foo" becomes "bar/foo". Does not eliminate other
+// redundancies that might be in a pathname involving "." or "..".
+void FilePath::Normalize() {
+ auto out = pathname_.begin();
+
+ for (const char character : pathname_) {
+ if (!IsPathSeparator(character)) {
+ *(out++) = character;
+ } else if (out == pathname_.begin() || *std::prev(out) != kPathSeparator) {
+ *(out++) = kPathSeparator;
+ } else {
+ continue;
+ }
+ }
+
+ pathname_.erase(out, pathname_.end());
+}
+
+} // namespace internal
+} // namespace testing
+// Copyright 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// The Google C++ Testing and Mocking Framework (Google Test)
+//
+// This file implements just enough of the matcher interface to allow
+// EXPECT_DEATH and friends to accept a matcher argument.
+
+
+#include <string>
+
+namespace testing {
+
+// Constructs a matcher that matches a const std::string& whose value is
+// equal to s.
+Matcher<const std::string&>::Matcher(const std::string& s) { *this = Eq(s); }
+
+// Constructs a matcher that matches a const std::string& whose value is
+// equal to s.
+Matcher<const std::string&>::Matcher(const char* s) {
+ *this = Eq(std::string(s));
+}
+
+// Constructs a matcher that matches a std::string whose value is equal to
+// s.
+Matcher<std::string>::Matcher(const std::string& s) { *this = Eq(s); }
+
+// Constructs a matcher that matches a std::string whose value is equal to
+// s.
+Matcher<std::string>::Matcher(const char* s) { *this = Eq(std::string(s)); }
+
+#if GTEST_INTERNAL_HAS_STRING_VIEW
+// Constructs a matcher that matches a const StringView& whose value is
+// equal to s.
+Matcher<const internal::StringView&>::Matcher(const std::string& s) {
+ *this = Eq(s);
+}
+
+// Constructs a matcher that matches a const StringView& whose value is
+// equal to s.
+Matcher<const internal::StringView&>::Matcher(const char* s) {
+ *this = Eq(std::string(s));
+}
+
+// Constructs a matcher that matches a const StringView& whose value is
+// equal to s.
+Matcher<const internal::StringView&>::Matcher(internal::StringView s) {
+ *this = Eq(std::string(s));
+}
+
+// Constructs a matcher that matches a StringView whose value is equal to
+// s.
+Matcher<internal::StringView>::Matcher(const std::string& s) { *this = Eq(s); }
+
+// Constructs a matcher that matches a StringView whose value is equal to
+// s.
+Matcher<internal::StringView>::Matcher(const char* s) {
+ *this = Eq(std::string(s));
+}
+
+// Constructs a matcher that matches a StringView whose value is equal to
+// s.
+Matcher<internal::StringView>::Matcher(internal::StringView s) {
+ *this = Eq(std::string(s));
+}
+#endif // GTEST_INTERNAL_HAS_STRING_VIEW
+
+} // namespace testing
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <cstdint>
+#include <fstream>
+#include <memory>
+
+#if GTEST_OS_WINDOWS
+# include <windows.h>
+# include <io.h>
+# include <sys/stat.h>
+# include <map> // Used in ThreadLocal.
+# ifdef _MSC_VER
+# include <crtdbg.h>
+# endif // _MSC_VER
+#else
+# include <unistd.h>
+#endif // GTEST_OS_WINDOWS
+
+#if GTEST_OS_MAC
+# include <mach/mach_init.h>
+# include <mach/task.h>
+# include <mach/vm_map.h>
+#endif // GTEST_OS_MAC
+
+#if GTEST_OS_DRAGONFLY || GTEST_OS_FREEBSD || GTEST_OS_GNU_KFREEBSD || \
+ GTEST_OS_NETBSD || GTEST_OS_OPENBSD
+# include <sys/sysctl.h>
+# if GTEST_OS_DRAGONFLY || GTEST_OS_FREEBSD || GTEST_OS_GNU_KFREEBSD
+# include <sys/user.h>
+# endif
+#endif
+
+#if GTEST_OS_QNX
+# include <devctl.h>
+# include <fcntl.h>
+# include <sys/procfs.h>
+#endif // GTEST_OS_QNX
+
+#if GTEST_OS_AIX
+# include <procinfo.h>
+# include <sys/types.h>
+#endif // GTEST_OS_AIX
+
+#if GTEST_OS_FUCHSIA
+# include <zircon/process.h>
+# include <zircon/syscalls.h>
+#endif // GTEST_OS_FUCHSIA
+
+
+namespace testing {
+namespace internal {
+
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+// MSVC and C++Builder do not provide a definition of STDERR_FILENO.
+const int kStdOutFileno = 1;
+const int kStdErrFileno = 2;
+#else
+const int kStdOutFileno = STDOUT_FILENO;
+const int kStdErrFileno = STDERR_FILENO;
+#endif // _MSC_VER
+
+#if GTEST_OS_LINUX || GTEST_OS_GNU_HURD
+
+namespace {
+template <typename T>
+T ReadProcFileField(const std::string& filename, int field) {
+ std::string dummy;
+ std::ifstream file(filename.c_str());
+ while (field-- > 0) {
+ file >> dummy;
+ }
+ T output = 0;
+ file >> output;
+ return output;
+}
+} // namespace
+
+// Returns the number of active threads, or 0 when there is an error.
+size_t GetThreadCount() {
+ const std::string filename =
+ (Message() << "/proc/" << getpid() << "/stat").GetString();
+ return ReadProcFileField<size_t>(filename, 19);
+}
+
+#elif GTEST_OS_MAC
+
+size_t GetThreadCount() {
+ const task_t task = mach_task_self();
+ mach_msg_type_number_t thread_count;
+ thread_act_array_t thread_list;
+ const kern_return_t status = task_threads(task, &thread_list, &thread_count);
+ if (status == KERN_SUCCESS) {
+ // task_threads allocates resources in thread_list and we need to free them
+ // to avoid leaks.
+ vm_deallocate(task,
+ reinterpret_cast<vm_address_t>(thread_list),
+ sizeof(thread_t) * thread_count);
+ return static_cast<size_t>(thread_count);
+ } else {
+ return 0;
+ }
+}
+
+#elif GTEST_OS_DRAGONFLY || GTEST_OS_FREEBSD || GTEST_OS_GNU_KFREEBSD || \
+ GTEST_OS_NETBSD
+
+#if GTEST_OS_NETBSD
+#undef KERN_PROC
+#define KERN_PROC KERN_PROC2
+#define kinfo_proc kinfo_proc2
+#endif
+
+#if GTEST_OS_DRAGONFLY
+#define KP_NLWP(kp) (kp.kp_nthreads)
+#elif GTEST_OS_FREEBSD || GTEST_OS_GNU_KFREEBSD
+#define KP_NLWP(kp) (kp.ki_numthreads)
+#elif GTEST_OS_NETBSD
+#define KP_NLWP(kp) (kp.p_nlwps)
+#endif
+
+// Returns the number of threads running in the process, or 0 to indicate that
+// we cannot detect it.
+size_t GetThreadCount() {
+ int mib[] = {
+ CTL_KERN,
+ KERN_PROC,
+ KERN_PROC_PID,
+ getpid(),
+#if GTEST_OS_NETBSD
+ sizeof(struct kinfo_proc),
+ 1,
+#endif
+ };
+ u_int miblen = sizeof(mib) / sizeof(mib[0]);
+ struct kinfo_proc info;
+ size_t size = sizeof(info);
+ if (sysctl(mib, miblen, &info, &size, NULL, 0)) {
+ return 0;
+ }
+ return static_cast<size_t>(KP_NLWP(info));
+}
+#elif GTEST_OS_OPENBSD
+
+// Returns the number of threads running in the process, or 0 to indicate that
+// we cannot detect it.
+size_t GetThreadCount() {
+ int mib[] = {
+ CTL_KERN,
+ KERN_PROC,
+ KERN_PROC_PID | KERN_PROC_SHOW_THREADS,
+ getpid(),
+ sizeof(struct kinfo_proc),
+ 0,
+ };
+ u_int miblen = sizeof(mib) / sizeof(mib[0]);
+
+ // get number of structs
+ size_t size;
+ if (sysctl(mib, miblen, NULL, &size, NULL, 0)) {
+ return 0;
+ }
+
+ mib[5] = static_cast<int>(size / static_cast<size_t>(mib[4]));
+
+ // populate array of structs
+ struct kinfo_proc info[mib[5]];
+ if (sysctl(mib, miblen, &info, &size, NULL, 0)) {
+ return 0;
+ }
+
+ // exclude empty members
+ size_t nthreads = 0;
+ for (size_t i = 0; i < size / static_cast<size_t>(mib[4]); i++) {
+ if (info[i].p_tid != -1)
+ nthreads++;
+ }
+ return nthreads;
+}
+
+#elif GTEST_OS_QNX
+
+// Returns the number of threads running in the process, or 0 to indicate that
+// we cannot detect it.
+size_t GetThreadCount() {
+ const int fd = open("/proc/self/as", O_RDONLY);
+ if (fd < 0) {
+ return 0;
+ }
+ procfs_info process_info;
+ const int status =
+ devctl(fd, DCMD_PROC_INFO, &process_info, sizeof(process_info), nullptr);
+ close(fd);
+ if (status == EOK) {
+ return static_cast<size_t>(process_info.num_threads);
+ } else {
+ return 0;
+ }
+}
+
+#elif GTEST_OS_AIX
+
+size_t GetThreadCount() {
+ struct procentry64 entry;
+ pid_t pid = getpid();
+ int status = getprocs64(&entry, sizeof(entry), nullptr, 0, &pid, 1);
+ if (status == 1) {
+ return entry.pi_thcount;
+ } else {
+ return 0;
+ }
+}
+
+#elif GTEST_OS_FUCHSIA
+
+size_t GetThreadCount() {
+ int dummy_buffer;
+ size_t avail;
+ zx_status_t status = zx_object_get_info(
+ zx_process_self(),
+ ZX_INFO_PROCESS_THREADS,
+ &dummy_buffer,
+ 0,
+ nullptr,
+ &avail);
+ if (status == ZX_OK) {
+ return avail;
+ } else {
+ return 0;
+ }
+}
+
+#else
+
+size_t GetThreadCount() {
+ // There's no portable way to detect the number of threads, so we just
+ // return 0 to indicate that we cannot detect it.
+ return 0;
+}
+
+#endif // GTEST_OS_LINUX
+
+#if GTEST_IS_THREADSAFE && GTEST_OS_WINDOWS
+
+void SleepMilliseconds(int n) {
+ ::Sleep(static_cast<DWORD>(n));
+}
+
+AutoHandle::AutoHandle()
+ : handle_(INVALID_HANDLE_VALUE) {}
+
+AutoHandle::AutoHandle(Handle handle)
+ : handle_(handle) {}
+
+AutoHandle::~AutoHandle() {
+ Reset();
+}
+
+AutoHandle::Handle AutoHandle::Get() const {
+ return handle_;
+}
+
+void AutoHandle::Reset() {
+ Reset(INVALID_HANDLE_VALUE);
+}
+
+void AutoHandle::Reset(HANDLE handle) {
+ // Resetting with the same handle we already own is invalid.
+ if (handle_ != handle) {
+ if (IsCloseable()) {
+ ::CloseHandle(handle_);
+ }
+ handle_ = handle;
+ } else {
+ GTEST_CHECK_(!IsCloseable())
+ << "Resetting a valid handle to itself is likely a programmer error "
+ "and thus not allowed.";
+ }
+}
+
+bool AutoHandle::IsCloseable() const {
+ // Different Windows APIs may use either of these values to represent an
+ // invalid handle.
+ return handle_ != nullptr && handle_ != INVALID_HANDLE_VALUE;
+}
+
+Notification::Notification()
+ : event_(::CreateEvent(nullptr, // Default security attributes.
+ TRUE, // Do not reset automatically.
+ FALSE, // Initially unset.
+ nullptr)) { // Anonymous event.
+ GTEST_CHECK_(event_.Get() != nullptr);
+}
+
+void Notification::Notify() {
+ GTEST_CHECK_(::SetEvent(event_.Get()) != FALSE);
+}
+
+void Notification::WaitForNotification() {
+ GTEST_CHECK_(
+ ::WaitForSingleObject(event_.Get(), INFINITE) == WAIT_OBJECT_0);
+}
+
+Mutex::Mutex()
+ : owner_thread_id_(0),
+ type_(kDynamic),
+ critical_section_init_phase_(0),
+ critical_section_(new CRITICAL_SECTION) {
+ ::InitializeCriticalSection(critical_section_);
+}
+
+Mutex::~Mutex() {
+ // Static mutexes are leaked intentionally. It is not thread-safe to try
+ // to clean them up.
+ if (type_ == kDynamic) {
+ ::DeleteCriticalSection(critical_section_);
+ delete critical_section_;
+ critical_section_ = nullptr;
+ }
+}
+
+void Mutex::Lock() {
+ ThreadSafeLazyInit();
+ ::EnterCriticalSection(critical_section_);
+ owner_thread_id_ = ::GetCurrentThreadId();
+}
+
+void Mutex::Unlock() {
+ ThreadSafeLazyInit();
+ // We don't protect writing to owner_thread_id_ here, as it's the
+ // caller's responsibility to ensure that the current thread holds the
+ // mutex when this is called.
+ owner_thread_id_ = 0;
+ ::LeaveCriticalSection(critical_section_);
+}
+
+// Does nothing if the current thread holds the mutex. Otherwise, crashes
+// with high probability.
+void Mutex::AssertHeld() {
+ ThreadSafeLazyInit();
+ GTEST_CHECK_(owner_thread_id_ == ::GetCurrentThreadId())
+ << "The current thread is not holding the mutex @" << this;
+}
+
+namespace {
+
+#ifdef _MSC_VER
+// Use the RAII idiom to flag mem allocs that are intentionally never
+// deallocated. The motivation is to silence the false positive mem leaks
+// that are reported by the debug version of MS's CRT which can only detect
+// if an alloc is missing a matching deallocation.
+// Example:
+// MemoryIsNotDeallocated memory_is_not_deallocated;
+// critical_section_ = new CRITICAL_SECTION;
+//
+class MemoryIsNotDeallocated
+{
+ public:
+ MemoryIsNotDeallocated() : old_crtdbg_flag_(0) {
+ old_crtdbg_flag_ = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
+ // Set heap allocation block type to _IGNORE_BLOCK so that MS debug CRT
+ // doesn't report mem leak if there's no matching deallocation.
+ _CrtSetDbgFlag(old_crtdbg_flag_ & ~_CRTDBG_ALLOC_MEM_DF);
+ }
+
+ ~MemoryIsNotDeallocated() {
+ // Restore the original _CRTDBG_ALLOC_MEM_DF flag
+ _CrtSetDbgFlag(old_crtdbg_flag_);
+ }
+
+ private:
+ int old_crtdbg_flag_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(MemoryIsNotDeallocated);
+};
+#endif // _MSC_VER
+
+} // namespace
+
+// Initializes owner_thread_id_ and critical_section_ in static mutexes.
+void Mutex::ThreadSafeLazyInit() {
+ // Dynamic mutexes are initialized in the constructor.
+ if (type_ == kStatic) {
+ switch (
+ ::InterlockedCompareExchange(&critical_section_init_phase_, 1L, 0L)) {
+ case 0:
+ // If critical_section_init_phase_ was 0 before the exchange, we
+ // are the first to test it and need to perform the initialization.
+ owner_thread_id_ = 0;
+ {
+ // Use RAII to flag that following mem alloc is never deallocated.
+#ifdef _MSC_VER
+ MemoryIsNotDeallocated memory_is_not_deallocated;
+#endif // _MSC_VER
+ critical_section_ = new CRITICAL_SECTION;
+ }
+ ::InitializeCriticalSection(critical_section_);
+ // Updates the critical_section_init_phase_ to 2 to signal
+ // initialization complete.
+ GTEST_CHECK_(::InterlockedCompareExchange(
+ &critical_section_init_phase_, 2L, 1L) ==
+ 1L);
+ break;
+ case 1:
+ // Somebody else is already initializing the mutex; spin until they
+ // are done.
+ while (::InterlockedCompareExchange(&critical_section_init_phase_,
+ 2L,
+ 2L) != 2L) {
+ // Possibly yields the rest of the thread's time slice to other
+ // threads.
+ ::Sleep(0);
+ }
+ break;
+
+ case 2:
+ break; // The mutex is already initialized and ready for use.
+
+ default:
+ GTEST_CHECK_(false)
+ << "Unexpected value of critical_section_init_phase_ "
+ << "while initializing a static mutex.";
+ }
+ }
+}
+
+namespace {
+
+class ThreadWithParamSupport : public ThreadWithParamBase {
+ public:
+ static HANDLE CreateThread(Runnable* runnable,
+ Notification* thread_can_start) {
+ ThreadMainParam* param = new ThreadMainParam(runnable, thread_can_start);
+ DWORD thread_id;
+ HANDLE thread_handle = ::CreateThread(
+ nullptr, // Default security.
+ 0, // Default stack size.
+ &ThreadWithParamSupport::ThreadMain,
+ param, // Parameter to ThreadMainStatic
+ 0x0, // Default creation flags.
+ &thread_id); // Need a valid pointer for the call to work under Win98.
+ GTEST_CHECK_(thread_handle != nullptr)
+ << "CreateThread failed with error " << ::GetLastError() << ".";
+ if (thread_handle == nullptr) {
+ delete param;
+ }
+ return thread_handle;
+ }
+
+ private:
+ struct ThreadMainParam {
+ ThreadMainParam(Runnable* runnable, Notification* thread_can_start)
+ : runnable_(runnable),
+ thread_can_start_(thread_can_start) {
+ }
+ std::unique_ptr<Runnable> runnable_;
+ // Does not own.
+ Notification* thread_can_start_;
+ };
+
+ static DWORD WINAPI ThreadMain(void* ptr) {
+ // Transfers ownership.
+ std::unique_ptr<ThreadMainParam> param(static_cast<ThreadMainParam*>(ptr));
+ if (param->thread_can_start_ != nullptr)
+ param->thread_can_start_->WaitForNotification();
+ param->runnable_->Run();
+ return 0;
+ }
+
+ // Prohibit instantiation.
+ ThreadWithParamSupport();
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParamSupport);
+};
+
+} // namespace
+
+ThreadWithParamBase::ThreadWithParamBase(Runnable *runnable,
+ Notification* thread_can_start)
+ : thread_(ThreadWithParamSupport::CreateThread(runnable,
+ thread_can_start)) {
+}
+
+ThreadWithParamBase::~ThreadWithParamBase() {
+ Join();
+}
+
+void ThreadWithParamBase::Join() {
+ GTEST_CHECK_(::WaitForSingleObject(thread_.Get(), INFINITE) == WAIT_OBJECT_0)
+ << "Failed to join the thread with error " << ::GetLastError() << ".";
+}
+
+// Maps a thread to a set of ThreadIdToThreadLocals that have values
+// instantiated on that thread and notifies them when the thread exits. A
+// ThreadLocal instance is expected to persist until all threads it has
+// values on have terminated.
+class ThreadLocalRegistryImpl {
+ public:
+ // Registers thread_local_instance as having value on the current thread.
+ // Returns a value that can be used to identify the thread from other threads.
+ static ThreadLocalValueHolderBase* GetValueOnCurrentThread(
+ const ThreadLocalBase* thread_local_instance) {
+#ifdef _MSC_VER
+ MemoryIsNotDeallocated memory_is_not_deallocated;
+#endif // _MSC_VER
+ DWORD current_thread = ::GetCurrentThreadId();
+ MutexLock lock(&mutex_);
+ ThreadIdToThreadLocals* const thread_to_thread_locals =
+ GetThreadLocalsMapLocked();
+ ThreadIdToThreadLocals::iterator thread_local_pos =
+ thread_to_thread_locals->find(current_thread);
+ if (thread_local_pos == thread_to_thread_locals->end()) {
+ thread_local_pos = thread_to_thread_locals->insert(
+ std::make_pair(current_thread, ThreadLocalValues())).first;
+ StartWatcherThreadFor(current_thread);
+ }
+ ThreadLocalValues& thread_local_values = thread_local_pos->second;
+ ThreadLocalValues::iterator value_pos =
+ thread_local_values.find(thread_local_instance);
+ if (value_pos == thread_local_values.end()) {
+ value_pos =
+ thread_local_values
+ .insert(std::make_pair(
+ thread_local_instance,
+ std::shared_ptr<ThreadLocalValueHolderBase>(
+ thread_local_instance->NewValueForCurrentThread())))
+ .first;
+ }
+ return value_pos->second.get();
+ }
+
+ static void OnThreadLocalDestroyed(
+ const ThreadLocalBase* thread_local_instance) {
+ std::vector<std::shared_ptr<ThreadLocalValueHolderBase> > value_holders;
+ // Clean up the ThreadLocalValues data structure while holding the lock, but
+ // defer the destruction of the ThreadLocalValueHolderBases.
+ {
+ MutexLock lock(&mutex_);
+ ThreadIdToThreadLocals* const thread_to_thread_locals =
+ GetThreadLocalsMapLocked();
+ for (ThreadIdToThreadLocals::iterator it =
+ thread_to_thread_locals->begin();
+ it != thread_to_thread_locals->end();
+ ++it) {
+ ThreadLocalValues& thread_local_values = it->second;
+ ThreadLocalValues::iterator value_pos =
+ thread_local_values.find(thread_local_instance);
+ if (value_pos != thread_local_values.end()) {
+ value_holders.push_back(value_pos->second);
+ thread_local_values.erase(value_pos);
+ // This 'if' can only be successful at most once, so theoretically we
+ // could break out of the loop here, but we don't bother doing so.
+ }
+ }
+ }
+ // Outside the lock, let the destructor for 'value_holders' deallocate the
+ // ThreadLocalValueHolderBases.
+ }
+
+ static void OnThreadExit(DWORD thread_id) {
+ GTEST_CHECK_(thread_id != 0) << ::GetLastError();
+ std::vector<std::shared_ptr<ThreadLocalValueHolderBase> > value_holders;
+ // Clean up the ThreadIdToThreadLocals data structure while holding the
+ // lock, but defer the destruction of the ThreadLocalValueHolderBases.
+ {
+ MutexLock lock(&mutex_);
+ ThreadIdToThreadLocals* const thread_to_thread_locals =
+ GetThreadLocalsMapLocked();
+ ThreadIdToThreadLocals::iterator thread_local_pos =
+ thread_to_thread_locals->find(thread_id);
+ if (thread_local_pos != thread_to_thread_locals->end()) {
+ ThreadLocalValues& thread_local_values = thread_local_pos->second;
+ for (ThreadLocalValues::iterator value_pos =
+ thread_local_values.begin();
+ value_pos != thread_local_values.end();
+ ++value_pos) {
+ value_holders.push_back(value_pos->second);
+ }
+ thread_to_thread_locals->erase(thread_local_pos);
+ }
+ }
+ // Outside the lock, let the destructor for 'value_holders' deallocate the
+ // ThreadLocalValueHolderBases.
+ }
+
+ private:
+ // In a particular thread, maps a ThreadLocal object to its value.
+ typedef std::map<const ThreadLocalBase*,
+ std::shared_ptr<ThreadLocalValueHolderBase> >
+ ThreadLocalValues;
+ // Stores all ThreadIdToThreadLocals having values in a thread, indexed by
+ // thread's ID.
+ typedef std::map<DWORD, ThreadLocalValues> ThreadIdToThreadLocals;
+
+ // Holds the thread id and thread handle that we pass from
+ // StartWatcherThreadFor to WatcherThreadFunc.
+ typedef std::pair<DWORD, HANDLE> ThreadIdAndHandle;
+
+ static void StartWatcherThreadFor(DWORD thread_id) {
+ // The returned handle will be kept in thread_map and closed by
+ // watcher_thread in WatcherThreadFunc.
+ HANDLE thread = ::OpenThread(SYNCHRONIZE | THREAD_QUERY_INFORMATION,
+ FALSE,
+ thread_id);
+ GTEST_CHECK_(thread != nullptr);
+ // We need to pass a valid thread ID pointer into CreateThread for it
+ // to work correctly under Win98.
+ DWORD watcher_thread_id;
+ HANDLE watcher_thread = ::CreateThread(
+ nullptr, // Default security.
+ 0, // Default stack size
+ &ThreadLocalRegistryImpl::WatcherThreadFunc,
+ reinterpret_cast<LPVOID>(new ThreadIdAndHandle(thread_id, thread)),
+ CREATE_SUSPENDED, &watcher_thread_id);
+ GTEST_CHECK_(watcher_thread != nullptr);
+ // Give the watcher thread the same priority as ours to avoid being
+ // blocked by it.
+ ::SetThreadPriority(watcher_thread,
+ ::GetThreadPriority(::GetCurrentThread()));
+ ::ResumeThread(watcher_thread);
+ ::CloseHandle(watcher_thread);
+ }
+
+ // Monitors exit from a given thread and notifies those
+ // ThreadIdToThreadLocals about thread termination.
+ static DWORD WINAPI WatcherThreadFunc(LPVOID param) {
+ const ThreadIdAndHandle* tah =
+ reinterpret_cast<const ThreadIdAndHandle*>(param);
+ GTEST_CHECK_(
+ ::WaitForSingleObject(tah->second, INFINITE) == WAIT_OBJECT_0);
+ OnThreadExit(tah->first);
+ ::CloseHandle(tah->second);
+ delete tah;
+ return 0;
+ }
+
+ // Returns map of thread local instances.
+ static ThreadIdToThreadLocals* GetThreadLocalsMapLocked() {
+ mutex_.AssertHeld();
+#ifdef _MSC_VER
+ MemoryIsNotDeallocated memory_is_not_deallocated;
+#endif // _MSC_VER
+ static ThreadIdToThreadLocals* map = new ThreadIdToThreadLocals();
+ return map;
+ }
+
+ // Protects access to GetThreadLocalsMapLocked() and its return value.
+ static Mutex mutex_;
+ // Protects access to GetThreadMapLocked() and its return value.
+ static Mutex thread_map_mutex_;
+};
+
+Mutex ThreadLocalRegistryImpl::mutex_(Mutex::kStaticMutex); // NOLINT
+Mutex ThreadLocalRegistryImpl::thread_map_mutex_(Mutex::kStaticMutex); // NOLINT
+
+ThreadLocalValueHolderBase* ThreadLocalRegistry::GetValueOnCurrentThread(
+ const ThreadLocalBase* thread_local_instance) {
+ return ThreadLocalRegistryImpl::GetValueOnCurrentThread(
+ thread_local_instance);
+}
+
+void ThreadLocalRegistry::OnThreadLocalDestroyed(
+ const ThreadLocalBase* thread_local_instance) {
+ ThreadLocalRegistryImpl::OnThreadLocalDestroyed(thread_local_instance);
+}
+
+#endif // GTEST_IS_THREADSAFE && GTEST_OS_WINDOWS
+
+#if GTEST_USES_POSIX_RE
+
+// Implements RE. Currently only needed for death tests.
+
+RE::~RE() {
+ if (is_valid_) {
+ // regfree'ing an invalid regex might crash because the content
+ // of the regex is undefined. Since the regex's are essentially
+ // the same, one cannot be valid (or invalid) without the other
+ // being so too.
+ regfree(&partial_regex_);
+ regfree(&full_regex_);
+ }
+ free(const_cast<char*>(pattern_));
+}
+
+// Returns true if and only if regular expression re matches the entire str.
+bool RE::FullMatch(const char* str, const RE& re) {
+ if (!re.is_valid_) return false;
+
+ regmatch_t match;
+ return regexec(&re.full_regex_, str, 1, &match, 0) == 0;
+}
+
+// Returns true if and only if regular expression re matches a substring of
+// str (including str itself).
+bool RE::PartialMatch(const char* str, const RE& re) {
+ if (!re.is_valid_) return false;
+
+ regmatch_t match;
+ return regexec(&re.partial_regex_, str, 1, &match, 0) == 0;
+}
+
+// Initializes an RE from its string representation.
+void RE::Init(const char* regex) {
+ pattern_ = posix::StrDup(regex);
+
+ // Reserves enough bytes to hold the regular expression used for a
+ // full match.
+ const size_t full_regex_len = strlen(regex) + 10;
+ char* const full_pattern = new char[full_regex_len];
+
+ snprintf(full_pattern, full_regex_len, "^(%s)$", regex);
+ is_valid_ = regcomp(&full_regex_, full_pattern, REG_EXTENDED) == 0;
+ // We want to call regcomp(&partial_regex_, ...) even if the
+ // previous expression returns false. Otherwise partial_regex_ may
+ // not be properly initialized can may cause trouble when it's
+ // freed.
+ //
+ // Some implementation of POSIX regex (e.g. on at least some
+ // versions of Cygwin) doesn't accept the empty string as a valid
+ // regex. We change it to an equivalent form "()" to be safe.
+ if (is_valid_) {
+ const char* const partial_regex = (*regex == '\0') ? "()" : regex;
+ is_valid_ = regcomp(&partial_regex_, partial_regex, REG_EXTENDED) == 0;
+ }
+ EXPECT_TRUE(is_valid_)
+ << "Regular expression \"" << regex
+ << "\" is not a valid POSIX Extended regular expression.";
+
+ delete[] full_pattern;
+}
+
+#elif GTEST_USES_SIMPLE_RE
+
+// Returns true if and only if ch appears anywhere in str (excluding the
+// terminating '\0' character).
+bool IsInSet(char ch, const char* str) {
+ return ch != '\0' && strchr(str, ch) != nullptr;
+}
+
+// Returns true if and only if ch belongs to the given classification.
+// Unlike similar functions in <ctype.h>, these aren't affected by the
+// current locale.
+bool IsAsciiDigit(char ch) { return '0' <= ch && ch <= '9'; }
+bool IsAsciiPunct(char ch) {
+ return IsInSet(ch, "^-!\"#$%&'()*+,./:;<=>?@[\\]_`{|}~");
+}
+bool IsRepeat(char ch) { return IsInSet(ch, "?*+"); }
+bool IsAsciiWhiteSpace(char ch) { return IsInSet(ch, " \f\n\r\t\v"); }
+bool IsAsciiWordChar(char ch) {
+ return ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') ||
+ ('0' <= ch && ch <= '9') || ch == '_';
+}
+
+// Returns true if and only if "\\c" is a supported escape sequence.
+bool IsValidEscape(char c) {
+ return (IsAsciiPunct(c) || IsInSet(c, "dDfnrsStvwW"));
+}
+
+// Returns true if and only if the given atom (specified by escaped and
+// pattern) matches ch. The result is undefined if the atom is invalid.
+bool AtomMatchesChar(bool escaped, char pattern_char, char ch) {
+ if (escaped) { // "\\p" where p is pattern_char.
+ switch (pattern_char) {
+ case 'd': return IsAsciiDigit(ch);
+ case 'D': return !IsAsciiDigit(ch);
+ case 'f': return ch == '\f';
+ case 'n': return ch == '\n';
+ case 'r': return ch == '\r';
+ case 's': return IsAsciiWhiteSpace(ch);
+ case 'S': return !IsAsciiWhiteSpace(ch);
+ case 't': return ch == '\t';
+ case 'v': return ch == '\v';
+ case 'w': return IsAsciiWordChar(ch);
+ case 'W': return !IsAsciiWordChar(ch);
+ }
+ return IsAsciiPunct(pattern_char) && pattern_char == ch;
+ }
+
+ return (pattern_char == '.' && ch != '\n') || pattern_char == ch;
+}
+
+// Helper function used by ValidateRegex() to format error messages.
+static std::string FormatRegexSyntaxError(const char* regex, int index) {
+ return (Message() << "Syntax error at index " << index
+ << " in simple regular expression \"" << regex << "\": ").GetString();
+}
+
+// Generates non-fatal failures and returns false if regex is invalid;
+// otherwise returns true.
+bool ValidateRegex(const char* regex) {
+ if (regex == nullptr) {
+ ADD_FAILURE() << "NULL is not a valid simple regular expression.";
+ return false;
+ }
+
+ bool is_valid = true;
+
+ // True if and only if ?, *, or + can follow the previous atom.
+ bool prev_repeatable = false;
+ for (int i = 0; regex[i]; i++) {
+ if (regex[i] == '\\') { // An escape sequence
+ i++;
+ if (regex[i] == '\0') {
+ ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1)
+ << "'\\' cannot appear at the end.";
+ return false;
+ }
+
+ if (!IsValidEscape(regex[i])) {
+ ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1)
+ << "invalid escape sequence \"\\" << regex[i] << "\".";
+ is_valid = false;
+ }
+ prev_repeatable = true;
+ } else { // Not an escape sequence.
+ const char ch = regex[i];
+
+ if (ch == '^' && i > 0) {
+ ADD_FAILURE() << FormatRegexSyntaxError(regex, i)
+ << "'^' can only appear at the beginning.";
+ is_valid = false;
+ } else if (ch == '$' && regex[i + 1] != '\0') {
+ ADD_FAILURE() << FormatRegexSyntaxError(regex, i)
+ << "'$' can only appear at the end.";
+ is_valid = false;
+ } else if (IsInSet(ch, "()[]{}|")) {
+ ADD_FAILURE() << FormatRegexSyntaxError(regex, i)
+ << "'" << ch << "' is unsupported.";
+ is_valid = false;
+ } else if (IsRepeat(ch) && !prev_repeatable) {
+ ADD_FAILURE() << FormatRegexSyntaxError(regex, i)
+ << "'" << ch << "' can only follow a repeatable token.";
+ is_valid = false;
+ }
+
+ prev_repeatable = !IsInSet(ch, "^$?*+");
+ }
+ }
+
+ return is_valid;
+}
+
+// Matches a repeated regex atom followed by a valid simple regular
+// expression. The regex atom is defined as c if escaped is false,
+// or \c otherwise. repeat is the repetition meta character (?, *,
+// or +). The behavior is undefined if str contains too many
+// characters to be indexable by size_t, in which case the test will
+// probably time out anyway. We are fine with this limitation as
+// std::string has it too.
+bool MatchRepetitionAndRegexAtHead(
+ bool escaped, char c, char repeat, const char* regex,
+ const char* str) {
+ const size_t min_count = (repeat == '+') ? 1 : 0;
+ const size_t max_count = (repeat == '?') ? 1 :
+ static_cast<size_t>(-1) - 1;
+ // We cannot call numeric_limits::max() as it conflicts with the
+ // max() macro on Windows.
+
+ for (size_t i = 0; i <= max_count; ++i) {
+ // We know that the atom matches each of the first i characters in str.
+ if (i >= min_count && MatchRegexAtHead(regex, str + i)) {
+ // We have enough matches at the head, and the tail matches too.
+ // Since we only care about *whether* the pattern matches str
+ // (as opposed to *how* it matches), there is no need to find a
+ // greedy match.
+ return true;
+ }
+ if (str[i] == '\0' || !AtomMatchesChar(escaped, c, str[i]))
+ return false;
+ }
+ return false;
+}
+
+// Returns true if and only if regex matches a prefix of str. regex must
+// be a valid simple regular expression and not start with "^", or the
+// result is undefined.
+bool MatchRegexAtHead(const char* regex, const char* str) {
+ if (*regex == '\0') // An empty regex matches a prefix of anything.
+ return true;
+
+ // "$" only matches the end of a string. Note that regex being
+ // valid guarantees that there's nothing after "$" in it.
+ if (*regex == '$')
+ return *str == '\0';
+
+ // Is the first thing in regex an escape sequence?
+ const bool escaped = *regex == '\\';
+ if (escaped)
+ ++regex;
+ if (IsRepeat(regex[1])) {
+ // MatchRepetitionAndRegexAtHead() calls MatchRegexAtHead(), so
+ // here's an indirect recursion. It terminates as the regex gets
+ // shorter in each recursion.
+ return MatchRepetitionAndRegexAtHead(
+ escaped, regex[0], regex[1], regex + 2, str);
+ } else {
+ // regex isn't empty, isn't "$", and doesn't start with a
+ // repetition. We match the first atom of regex with the first
+ // character of str and recurse.
+ return (*str != '\0') && AtomMatchesChar(escaped, *regex, *str) &&
+ MatchRegexAtHead(regex + 1, str + 1);
+ }
+}
+
+// Returns true if and only if regex matches any substring of str. regex must
+// be a valid simple regular expression, or the result is undefined.
+//
+// The algorithm is recursive, but the recursion depth doesn't exceed
+// the regex length, so we won't need to worry about running out of
+// stack space normally. In rare cases the time complexity can be
+// exponential with respect to the regex length + the string length,
+// but usually it's must faster (often close to linear).
+bool MatchRegexAnywhere(const char* regex, const char* str) {
+ if (regex == nullptr || str == nullptr) return false;
+
+ if (*regex == '^')
+ return MatchRegexAtHead(regex + 1, str);
+
+ // A successful match can be anywhere in str.
+ do {
+ if (MatchRegexAtHead(regex, str))
+ return true;
+ } while (*str++ != '\0');
+ return false;
+}
+
+// Implements the RE class.
+
+RE::~RE() {
+ free(const_cast<char*>(pattern_));
+ free(const_cast<char*>(full_pattern_));
+}
+
+// Returns true if and only if regular expression re matches the entire str.
+bool RE::FullMatch(const char* str, const RE& re) {
+ return re.is_valid_ && MatchRegexAnywhere(re.full_pattern_, str);
+}
+
+// Returns true if and only if regular expression re matches a substring of
+// str (including str itself).
+bool RE::PartialMatch(const char* str, const RE& re) {
+ return re.is_valid_ && MatchRegexAnywhere(re.pattern_, str);
+}
+
+// Initializes an RE from its string representation.
+void RE::Init(const char* regex) {
+ pattern_ = full_pattern_ = nullptr;
+ if (regex != nullptr) {
+ pattern_ = posix::StrDup(regex);
+ }
+
+ is_valid_ = ValidateRegex(regex);
+ if (!is_valid_) {
+ // No need to calculate the full pattern when the regex is invalid.
+ return;
+ }
+
+ const size_t len = strlen(regex);
+ // Reserves enough bytes to hold the regular expression used for a
+ // full match: we need space to prepend a '^', append a '$', and
+ // terminate the string with '\0'.
+ char* buffer = static_cast<char*>(malloc(len + 3));
+ full_pattern_ = buffer;
+
+ if (*regex != '^')
+ *buffer++ = '^'; // Makes sure full_pattern_ starts with '^'.
+
+ // We don't use snprintf or strncpy, as they trigger a warning when
+ // compiled with VC++ 8.0.
+ memcpy(buffer, regex, len);
+ buffer += len;
+
+ if (len == 0 || regex[len - 1] != '$')
+ *buffer++ = '$'; // Makes sure full_pattern_ ends with '$'.
+
+ *buffer = '\0';
+}
+
+#endif // GTEST_USES_POSIX_RE
+
+const char kUnknownFile[] = "unknown file";
+
+// Formats a source file path and a line number as they would appear
+// in an error message from the compiler used to compile this code.
+GTEST_API_ ::std::string FormatFileLocation(const char* file, int line) {
+ const std::string file_name(file == nullptr ? kUnknownFile : file);
+
+ if (line < 0) {
+ return file_name + ":";
+ }
+#ifdef _MSC_VER
+ return file_name + "(" + StreamableToString(line) + "):";
+#else
+ return file_name + ":" + StreamableToString(line) + ":";
+#endif // _MSC_VER
+}
+
+// Formats a file location for compiler-independent XML output.
+// Although this function is not platform dependent, we put it next to
+// FormatFileLocation in order to contrast the two functions.
+// Note that FormatCompilerIndependentFileLocation() does NOT append colon
+// to the file location it produces, unlike FormatFileLocation().
+GTEST_API_ ::std::string FormatCompilerIndependentFileLocation(
+ const char* file, int line) {
+ const std::string file_name(file == nullptr ? kUnknownFile : file);
+
+ if (line < 0)
+ return file_name;
+ else
+ return file_name + ":" + StreamableToString(line);
+}
+
+GTestLog::GTestLog(GTestLogSeverity severity, const char* file, int line)
+ : severity_(severity) {
+ const char* const marker =
+ severity == GTEST_INFO ? "[ INFO ]" :
+ severity == GTEST_WARNING ? "[WARNING]" :
+ severity == GTEST_ERROR ? "[ ERROR ]" : "[ FATAL ]";
+ GetStream() << ::std::endl << marker << " "
+ << FormatFileLocation(file, line).c_str() << ": ";
+}
+
+// Flushes the buffers and, if severity is GTEST_FATAL, aborts the program.
+GTestLog::~GTestLog() {
+ GetStream() << ::std::endl;
+ if (severity_ == GTEST_FATAL) {
+ fflush(stderr);
+ posix::Abort();
+ }
+}
+
+// Disable Microsoft deprecation warnings for POSIX functions called from
+// this class (creat, dup, dup2, and close)
+GTEST_DISABLE_MSC_DEPRECATED_PUSH_()
+
+#if GTEST_HAS_STREAM_REDIRECTION
+
+// Object that captures an output stream (stdout/stderr).
+class CapturedStream {
+ public:
+ // The ctor redirects the stream to a temporary file.
+ explicit CapturedStream(int fd) : fd_(fd), uncaptured_fd_(dup(fd)) {
+# if GTEST_OS_WINDOWS
+ char temp_dir_path[MAX_PATH + 1] = { '\0' }; // NOLINT
+ char temp_file_path[MAX_PATH + 1] = { '\0' }; // NOLINT
+
+ ::GetTempPathA(sizeof(temp_dir_path), temp_dir_path);
+ const UINT success = ::GetTempFileNameA(temp_dir_path,
+ "gtest_redir",
+ 0, // Generate unique file name.
+ temp_file_path);
+ GTEST_CHECK_(success != 0)
+ << "Unable to create a temporary file in " << temp_dir_path;
+ const int captured_fd = creat(temp_file_path, _S_IREAD | _S_IWRITE);
+ GTEST_CHECK_(captured_fd != -1) << "Unable to open temporary file "
+ << temp_file_path;
+ filename_ = temp_file_path;
+# else
+ // There's no guarantee that a test has write access to the current
+ // directory, so we create the temporary file in a temporary directory.
+ std::string name_template;
+
+# if GTEST_OS_LINUX_ANDROID
+ // Note: Android applications are expected to call the framework's
+ // Context.getExternalStorageDirectory() method through JNI to get
+ // the location of the world-writable SD Card directory. However,
+ // this requires a Context handle, which cannot be retrieved
+ // globally from native code. Doing so also precludes running the
+ // code as part of a regular standalone executable, which doesn't
+ // run in a Dalvik process (e.g. when running it through 'adb shell').
+ //
+ // The location /data/local/tmp is directly accessible from native code.
+ // '/sdcard' and other variants cannot be relied on, as they are not
+ // guaranteed to be mounted, or may have a delay in mounting.
+ name_template = "/data/local/tmp/";
+# elif GTEST_OS_IOS
+ char user_temp_dir[PATH_MAX + 1];
+
+ // Documented alternative to NSTemporaryDirectory() (for obtaining creating
+ // a temporary directory) at
+ // https://developer.apple.com/library/archive/documentation/Security/Conceptual/SecureCodingGuide/Articles/RaceConditions.html#//apple_ref/doc/uid/TP40002585-SW10
+ //
+ // _CS_DARWIN_USER_TEMP_DIR (as well as _CS_DARWIN_USER_CACHE_DIR) is not
+ // documented in the confstr() man page at
+ // https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/confstr.3.html#//apple_ref/doc/man/3/confstr
+ // but are still available, according to the WebKit patches at
+ // https://trac.webkit.org/changeset/262004/webkit
+ // https://trac.webkit.org/changeset/263705/webkit
+ //
+ // The confstr() implementation falls back to getenv("TMPDIR"). See
+ // https://opensource.apple.com/source/Libc/Libc-1439.100.3/gen/confstr.c.auto.html
+ ::confstr(_CS_DARWIN_USER_TEMP_DIR, user_temp_dir, sizeof(user_temp_dir));
+
+ name_template = user_temp_dir;
+ if (name_template.back() != GTEST_PATH_SEP_[0])
+ name_template.push_back(GTEST_PATH_SEP_[0]);
+# else
+ name_template = "/tmp/";
+# endif
+ name_template.append("gtest_captured_stream.XXXXXX");
+
+ // mkstemp() modifies the string bytes in place, and does not go beyond the
+ // string's length. This results in well-defined behavior in C++17.
+ //
+ // The const_cast is needed below C++17. The constraints on std::string
+ // implementations in C++11 and above make assumption behind the const_cast
+ // fairly safe.
+ const int captured_fd = ::mkstemp(const_cast<char*>(name_template.data()));
+ if (captured_fd == -1) {
+ GTEST_LOG_(WARNING)
+ << "Failed to create tmp file " << name_template
+ << " for test; does the test have access to the /tmp directory?";
+ }
+ filename_ = std::move(name_template);
+# endif // GTEST_OS_WINDOWS
+ fflush(nullptr);
+ dup2(captured_fd, fd_);
+ close(captured_fd);
+ }
+
+ ~CapturedStream() {
+ remove(filename_.c_str());
+ }
+
+ std::string GetCapturedString() {
+ if (uncaptured_fd_ != -1) {
+ // Restores the original stream.
+ fflush(nullptr);
+ dup2(uncaptured_fd_, fd_);
+ close(uncaptured_fd_);
+ uncaptured_fd_ = -1;
+ }
+
+ FILE* const file = posix::FOpen(filename_.c_str(), "r");
+ if (file == nullptr) {
+ GTEST_LOG_(FATAL) << "Failed to open tmp file " << filename_
+ << " for capturing stream.";
+ }
+ const std::string content = ReadEntireFile(file);
+ posix::FClose(file);
+ return content;
+ }
+
+ private:
+ const int fd_; // A stream to capture.
+ int uncaptured_fd_;
+ // Name of the temporary file holding the stderr output.
+ ::std::string filename_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(CapturedStream);
+};
+
+GTEST_DISABLE_MSC_DEPRECATED_POP_()
+
+static CapturedStream* g_captured_stderr = nullptr;
+static CapturedStream* g_captured_stdout = nullptr;
+
+// Starts capturing an output stream (stdout/stderr).
+static void CaptureStream(int fd, const char* stream_name,
+ CapturedStream** stream) {
+ if (*stream != nullptr) {
+ GTEST_LOG_(FATAL) << "Only one " << stream_name
+ << " capturer can exist at a time.";
+ }
+ *stream = new CapturedStream(fd);
+}
+
+// Stops capturing the output stream and returns the captured string.
+static std::string GetCapturedStream(CapturedStream** captured_stream) {
+ const std::string content = (*captured_stream)->GetCapturedString();
+
+ delete *captured_stream;
+ *captured_stream = nullptr;
+
+ return content;
+}
+
+// Starts capturing stdout.
+void CaptureStdout() {
+ CaptureStream(kStdOutFileno, "stdout", &g_captured_stdout);
+}
+
+// Starts capturing stderr.
+void CaptureStderr() {
+ CaptureStream(kStdErrFileno, "stderr", &g_captured_stderr);
+}
+
+// Stops capturing stdout and returns the captured string.
+std::string GetCapturedStdout() {
+ return GetCapturedStream(&g_captured_stdout);
+}
+
+// Stops capturing stderr and returns the captured string.
+std::string GetCapturedStderr() {
+ return GetCapturedStream(&g_captured_stderr);
+}
+
+#endif // GTEST_HAS_STREAM_REDIRECTION
+
+
+
+
+
+size_t GetFileSize(FILE* file) {
+ fseek(file, 0, SEEK_END);
+ return static_cast<size_t>(ftell(file));
+}
+
+std::string ReadEntireFile(FILE* file) {
+ const size_t file_size = GetFileSize(file);
+ char* const buffer = new char[file_size];
+
+ size_t bytes_last_read = 0; // # of bytes read in the last fread()
+ size_t bytes_read = 0; // # of bytes read so far
+
+ fseek(file, 0, SEEK_SET);
+
+ // Keeps reading the file until we cannot read further or the
+ // pre-determined file size is reached.
+ do {
+ bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file);
+ bytes_read += bytes_last_read;
+ } while (bytes_last_read > 0 && bytes_read < file_size);
+
+ const std::string content(buffer, bytes_read);
+ delete[] buffer;
+
+ return content;
+}
+
+#if GTEST_HAS_DEATH_TEST
+static const std::vector<std::string>* g_injected_test_argvs =
+ nullptr; // Owned.
+
+std::vector<std::string> GetInjectableArgvs() {
+ if (g_injected_test_argvs != nullptr) {
+ return *g_injected_test_argvs;
+ }
+ return GetArgvs();
+}
+
+void SetInjectableArgvs(const std::vector<std::string>* new_argvs) {
+ if (g_injected_test_argvs != new_argvs) delete g_injected_test_argvs;
+ g_injected_test_argvs = new_argvs;
+}
+
+void SetInjectableArgvs(const std::vector<std::string>& new_argvs) {
+ SetInjectableArgvs(
+ new std::vector<std::string>(new_argvs.begin(), new_argvs.end()));
+}
+
+void ClearInjectableArgvs() {
+ delete g_injected_test_argvs;
+ g_injected_test_argvs = nullptr;
+}
+#endif // GTEST_HAS_DEATH_TEST
+
+#if GTEST_OS_WINDOWS_MOBILE
+namespace posix {
+void Abort() {
+ DebugBreak();
+ TerminateProcess(GetCurrentProcess(), 1);
+}
+} // namespace posix
+#endif // GTEST_OS_WINDOWS_MOBILE
+
+// Returns the name of the environment variable corresponding to the
+// given flag. For example, FlagToEnvVar("foo") will return
+// "GTEST_FOO" in the open-source version.
+static std::string FlagToEnvVar(const char* flag) {
+ const std::string full_flag =
+ (Message() << GTEST_FLAG_PREFIX_ << flag).GetString();
+
+ Message env_var;
+ for (size_t i = 0; i != full_flag.length(); i++) {
+ env_var << ToUpper(full_flag.c_str()[i]);
+ }
+
+ return env_var.GetString();
+}
+
+// Parses 'str' for a 32-bit signed integer. If successful, writes
+// the result to *value and returns true; otherwise leaves *value
+// unchanged and returns false.
+bool ParseInt32(const Message& src_text, const char* str, int32_t* value) {
+ // Parses the environment variable as a decimal integer.
+ char* end = nullptr;
+ const long long_value = strtol(str, &end, 10); // NOLINT
+
+ // Has strtol() consumed all characters in the string?
+ if (*end != '\0') {
+ // No - an invalid character was encountered.
+ Message msg;
+ msg << "WARNING: " << src_text
+ << " is expected to be a 32-bit integer, but actually"
+ << " has value \"" << str << "\".\n";
+ printf("%s", msg.GetString().c_str());
+ fflush(stdout);
+ return false;
+ }
+
+ // Is the parsed value in the range of an int32_t?
+ const auto result = static_cast<int32_t>(long_value);
+ if (long_value == LONG_MAX || long_value == LONG_MIN ||
+ // The parsed value overflows as a long. (strtol() returns
+ // LONG_MAX or LONG_MIN when the input overflows.)
+ result != long_value
+ // The parsed value overflows as an int32_t.
+ ) {
+ Message msg;
+ msg << "WARNING: " << src_text
+ << " is expected to be a 32-bit integer, but actually"
+ << " has value " << str << ", which overflows.\n";
+ printf("%s", msg.GetString().c_str());
+ fflush(stdout);
+ return false;
+ }
+
+ *value = result;
+ return true;
+}
+
+// Reads and returns the Boolean environment variable corresponding to
+// the given flag; if it's not set, returns default_value.
+//
+// The value is considered true if and only if it's not "0".
+bool BoolFromGTestEnv(const char* flag, bool default_value) {
+#if defined(GTEST_GET_BOOL_FROM_ENV_)
+ return GTEST_GET_BOOL_FROM_ENV_(flag, default_value);
+#else
+ const std::string env_var = FlagToEnvVar(flag);
+ const char* const string_value = posix::GetEnv(env_var.c_str());
+ return string_value == nullptr ? default_value
+ : strcmp(string_value, "0") != 0;
+#endif // defined(GTEST_GET_BOOL_FROM_ENV_)
+}
+
+// Reads and returns a 32-bit integer stored in the environment
+// variable corresponding to the given flag; if it isn't set or
+// doesn't represent a valid 32-bit integer, returns default_value.
+int32_t Int32FromGTestEnv(const char* flag, int32_t default_value) {
+#if defined(GTEST_GET_INT32_FROM_ENV_)
+ return GTEST_GET_INT32_FROM_ENV_(flag, default_value);
+#else
+ const std::string env_var = FlagToEnvVar(flag);
+ const char* const string_value = posix::GetEnv(env_var.c_str());
+ if (string_value == nullptr) {
+ // The environment variable is not set.
+ return default_value;
+ }
+
+ int32_t result = default_value;
+ if (!ParseInt32(Message() << "Environment variable " << env_var,
+ string_value, &result)) {
+ printf("The default value %s is used.\n",
+ (Message() << default_value).GetString().c_str());
+ fflush(stdout);
+ return default_value;
+ }
+
+ return result;
+#endif // defined(GTEST_GET_INT32_FROM_ENV_)
+}
+
+// As a special case for the 'output' flag, if GTEST_OUTPUT is not
+// set, we look for XML_OUTPUT_FILE, which is set by the Bazel build
+// system. The value of XML_OUTPUT_FILE is a filename without the
+// "xml:" prefix of GTEST_OUTPUT.
+// Note that this is meant to be called at the call site so it does
+// not check that the flag is 'output'
+// In essence this checks an env variable called XML_OUTPUT_FILE
+// and if it is set we prepend "xml:" to its value, if it not set we return ""
+std::string OutputFlagAlsoCheckEnvVar(){
+ std::string default_value_for_output_flag = "";
+ const char* xml_output_file_env = posix::GetEnv("XML_OUTPUT_FILE");
+ if (nullptr != xml_output_file_env) {
+ default_value_for_output_flag = std::string("xml:") + xml_output_file_env;
+ }
+ return default_value_for_output_flag;
+}
+
+// Reads and returns the string environment variable corresponding to
+// the given flag; if it's not set, returns default_value.
+const char* StringFromGTestEnv(const char* flag, const char* default_value) {
+#if defined(GTEST_GET_STRING_FROM_ENV_)
+ return GTEST_GET_STRING_FROM_ENV_(flag, default_value);
+#else
+ const std::string env_var = FlagToEnvVar(flag);
+ const char* const value = posix::GetEnv(env_var.c_str());
+ return value == nullptr ? default_value : value;
+#endif // defined(GTEST_GET_STRING_FROM_ENV_)
+}
+
+} // namespace internal
+} // namespace testing
+// Copyright 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+// Google Test - The Google C++ Testing and Mocking Framework
+//
+// This file implements a universal value printer that can print a
+// value of any type T:
+//
+// void ::testing::internal::UniversalPrinter<T>::Print(value, ostream_ptr);
+//
+// It uses the << operator when possible, and prints the bytes in the
+// object otherwise. A user can override its behavior for a class
+// type Foo by defining either operator<<(::std::ostream&, const Foo&)
+// or void PrintTo(const Foo&, ::std::ostream*) in the namespace that
+// defines Foo.
+
+
+#include <stdio.h>
+
+#include <cctype>
+#include <cstdint>
+#include <cwchar>
+#include <ostream> // NOLINT
+#include <string>
+#include <type_traits>
+
+
+namespace testing {
+
+namespace {
+
+using ::std::ostream;
+
+// Prints a segment of bytes in the given object.
+GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_
+GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
+GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_
+GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_
+void PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start,
+ size_t count, ostream* os) {
+ char text[5] = "";
+ for (size_t i = 0; i != count; i++) {
+ const size_t j = start + i;
+ if (i != 0) {
+ // Organizes the bytes into groups of 2 for easy parsing by
+ // human.
+ if ((j % 2) == 0)
+ *os << ' ';
+ else
+ *os << '-';
+ }
+ GTEST_SNPRINTF_(text, sizeof(text), "%02X", obj_bytes[j]);
+ *os << text;
+ }
+}
+
+// Prints the bytes in the given value to the given ostream.
+void PrintBytesInObjectToImpl(const unsigned char* obj_bytes, size_t count,
+ ostream* os) {
+ // Tells the user how big the object is.
+ *os << count << "-byte object <";
+
+ const size_t kThreshold = 132;
+ const size_t kChunkSize = 64;
+ // If the object size is bigger than kThreshold, we'll have to omit
+ // some details by printing only the first and the last kChunkSize
+ // bytes.
+ if (count < kThreshold) {
+ PrintByteSegmentInObjectTo(obj_bytes, 0, count, os);
+ } else {
+ PrintByteSegmentInObjectTo(obj_bytes, 0, kChunkSize, os);
+ *os << " ... ";
+ // Rounds up to 2-byte boundary.
+ const size_t resume_pos = (count - kChunkSize + 1)/2*2;
+ PrintByteSegmentInObjectTo(obj_bytes, resume_pos, count - resume_pos, os);
+ }
+ *os << ">";
+}
+
+// Helpers for widening a character to char32_t. Since the standard does not
+// specify if char / wchar_t is signed or unsigned, it is important to first
+// convert it to the unsigned type of the same width before widening it to
+// char32_t.
+template <typename CharType>
+char32_t ToChar32(CharType in) {
+ return static_cast<char32_t>(
+ static_cast<typename std::make_unsigned<CharType>::type>(in));
+}
+
+} // namespace
+
+namespace internal {
+
+// Delegates to PrintBytesInObjectToImpl() to print the bytes in the
+// given object. The delegation simplifies the implementation, which
+// uses the << operator and thus is easier done outside of the
+// ::testing::internal namespace, which contains a << operator that
+// sometimes conflicts with the one in STL.
+void PrintBytesInObjectTo(const unsigned char* obj_bytes, size_t count,
+ ostream* os) {
+ PrintBytesInObjectToImpl(obj_bytes, count, os);
+}
+
+// Depending on the value of a char (or wchar_t), we print it in one
+// of three formats:
+// - as is if it's a printable ASCII (e.g. 'a', '2', ' '),
+// - as a hexadecimal escape sequence (e.g. '\x7F'), or
+// - as a special escape sequence (e.g. '\r', '\n').
+enum CharFormat {
+ kAsIs,
+ kHexEscape,
+ kSpecialEscape
+};
+
+// Returns true if c is a printable ASCII character. We test the
+// value of c directly instead of calling isprint(), which is buggy on
+// Windows Mobile.
+inline bool IsPrintableAscii(char32_t c) { return 0x20 <= c && c <= 0x7E; }
+
+// Prints c (of type char, char8_t, char16_t, char32_t, or wchar_t) as a
+// character literal without the quotes, escaping it when necessary; returns how
+// c was formatted.
+template <typename Char>
+static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) {
+ const char32_t u_c = ToChar32(c);
+ switch (u_c) {
+ case L'\0':
+ *os << "\\0";
+ break;
+ case L'\'':
+ *os << "\\'";
+ break;
+ case L'\\':
+ *os << "\\\\";
+ break;
+ case L'\a':
+ *os << "\\a";
+ break;
+ case L'\b':
+ *os << "\\b";
+ break;
+ case L'\f':
+ *os << "\\f";
+ break;
+ case L'\n':
+ *os << "\\n";
+ break;
+ case L'\r':
+ *os << "\\r";
+ break;
+ case L'\t':
+ *os << "\\t";
+ break;
+ case L'\v':
+ *os << "\\v";
+ break;
+ default:
+ if (IsPrintableAscii(u_c)) {
+ *os << static_cast<char>(c);
+ return kAsIs;
+ } else {
+ ostream::fmtflags flags = os->flags();
+ *os << "\\x" << std::hex << std::uppercase << static_cast<int>(u_c);
+ os->flags(flags);
+ return kHexEscape;
+ }
+ }
+ return kSpecialEscape;
+}
+
+// Prints a char32_t c as if it's part of a string literal, escaping it when
+// necessary; returns how c was formatted.
+static CharFormat PrintAsStringLiteralTo(char32_t c, ostream* os) {
+ switch (c) {
+ case L'\'':
+ *os << "'";
+ return kAsIs;
+ case L'"':
+ *os << "\\\"";
+ return kSpecialEscape;
+ default:
+ return PrintAsCharLiteralTo(c, os);
+ }
+}
+
+static const char* GetCharWidthPrefix(char) {
+ return "";
+}
+
+static const char* GetCharWidthPrefix(signed char) {
+ return "";
+}
+
+static const char* GetCharWidthPrefix(unsigned char) {
+ return "";
+}
+
+#ifdef __cpp_char8_t
+static const char* GetCharWidthPrefix(char8_t) {
+ return "u8";
+}
+#endif
+
+static const char* GetCharWidthPrefix(char16_t) {
+ return "u";
+}
+
+static const char* GetCharWidthPrefix(char32_t) {
+ return "U";
+}
+
+static const char* GetCharWidthPrefix(wchar_t) {
+ return "L";
+}
+
+// Prints a char c as if it's part of a string literal, escaping it when
+// necessary; returns how c was formatted.
+static CharFormat PrintAsStringLiteralTo(char c, ostream* os) {
+ return PrintAsStringLiteralTo(ToChar32(c), os);
+}
+
+#ifdef __cpp_char8_t
+static CharFormat PrintAsStringLiteralTo(char8_t c, ostream* os) {
+ return PrintAsStringLiteralTo(ToChar32(c), os);
+}
+#endif
+
+static CharFormat PrintAsStringLiteralTo(char16_t c, ostream* os) {
+ return PrintAsStringLiteralTo(ToChar32(c), os);
+}
+
+static CharFormat PrintAsStringLiteralTo(wchar_t c, ostream* os) {
+ return PrintAsStringLiteralTo(ToChar32(c), os);
+}
+
+// Prints a character c (of type char, char8_t, char16_t, char32_t, or wchar_t)
+// and its code. '\0' is printed as "'\\0'", other unprintable characters are
+// also properly escaped using the standard C++ escape sequence.
+template <typename Char>
+void PrintCharAndCodeTo(Char c, ostream* os) {
+ // First, print c as a literal in the most readable form we can find.
+ *os << GetCharWidthPrefix(c) << "'";
+ const CharFormat format = PrintAsCharLiteralTo(c, os);
+ *os << "'";
+
+ // To aid user debugging, we also print c's code in decimal, unless
+ // it's 0 (in which case c was printed as '\\0', making the code
+ // obvious).
+ if (c == 0)
+ return;
+ *os << " (" << static_cast<int>(c);
+
+ // For more convenience, we print c's code again in hexadecimal,
+ // unless c was already printed in the form '\x##' or the code is in
+ // [1, 9].
+ if (format == kHexEscape || (1 <= c && c <= 9)) {
+ // Do nothing.
+ } else {
+ *os << ", 0x" << String::FormatHexInt(static_cast<int>(c));
+ }
+ *os << ")";
+}
+
+void PrintTo(unsigned char c, ::std::ostream* os) { PrintCharAndCodeTo(c, os); }
+void PrintTo(signed char c, ::std::ostream* os) { PrintCharAndCodeTo(c, os); }
+
+// Prints a wchar_t as a symbol if it is printable or as its internal
+// code otherwise and also as its code. L'\0' is printed as "L'\\0'".
+void PrintTo(wchar_t wc, ostream* os) { PrintCharAndCodeTo(wc, os); }
+
+// TODO(dcheng): Consider making this delegate to PrintCharAndCodeTo() as well.
+void PrintTo(char32_t c, ::std::ostream* os) {
+ *os << std::hex << "U+" << std::uppercase << std::setfill('0') << std::setw(4)
+ << static_cast<uint32_t>(c);
+}
+
+// Prints the given array of characters to the ostream. CharType must be either
+// char, char8_t, char16_t, char32_t, or wchar_t.
+// The array starts at begin, the length is len, it may include '\0' characters
+// and may not be NUL-terminated.
+template <typename CharType>
+GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_
+GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
+GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_
+GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_
+static CharFormat PrintCharsAsStringTo(
+ const CharType* begin, size_t len, ostream* os) {
+ const char* const quote_prefix = GetCharWidthPrefix(*begin);
+ *os << quote_prefix << "\"";
+ bool is_previous_hex = false;
+ CharFormat print_format = kAsIs;
+ for (size_t index = 0; index < len; ++index) {
+ const CharType cur = begin[index];
+ if (is_previous_hex && IsXDigit(cur)) {
+ // Previous character is of '\x..' form and this character can be
+ // interpreted as another hexadecimal digit in its number. Break string to
+ // disambiguate.
+ *os << "\" " << quote_prefix << "\"";
+ }
+ is_previous_hex = PrintAsStringLiteralTo(cur, os) == kHexEscape;
+ // Remember if any characters required hex escaping.
+ if (is_previous_hex) {
+ print_format = kHexEscape;
+ }
+ }
+ *os << "\"";
+ return print_format;
+}
+
+// Prints a (const) char/wchar_t array of 'len' elements, starting at address
+// 'begin'. CharType must be either char or wchar_t.
+template <typename CharType>
+GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_
+GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
+GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_
+GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_
+static void UniversalPrintCharArray(
+ const CharType* begin, size_t len, ostream* os) {
+ // The code
+ // const char kFoo[] = "foo";
+ // generates an array of 4, not 3, elements, with the last one being '\0'.
+ //
+ // Therefore when printing a char array, we don't print the last element if
+ // it's '\0', such that the output matches the string literal as it's
+ // written in the source code.
+ if (len > 0 && begin[len - 1] == '\0') {
+ PrintCharsAsStringTo(begin, len - 1, os);
+ return;
+ }
+
+ // If, however, the last element in the array is not '\0', e.g.
+ // const char kFoo[] = { 'f', 'o', 'o' };
+ // we must print the entire array. We also print a message to indicate
+ // that the array is not NUL-terminated.
+ PrintCharsAsStringTo(begin, len, os);
+ *os << " (no terminating NUL)";
+}
+
+// Prints a (const) char array of 'len' elements, starting at address 'begin'.
+void UniversalPrintArray(const char* begin, size_t len, ostream* os) {
+ UniversalPrintCharArray(begin, len, os);
+}
+
+#ifdef __cpp_char8_t
+// Prints a (const) char8_t array of 'len' elements, starting at address
+// 'begin'.
+void UniversalPrintArray(const char8_t* begin, size_t len, ostream* os) {
+ UniversalPrintCharArray(begin, len, os);
+}
+#endif
+
+// Prints a (const) char16_t array of 'len' elements, starting at address
+// 'begin'.
+void UniversalPrintArray(const char16_t* begin, size_t len, ostream* os) {
+ UniversalPrintCharArray(begin, len, os);
+}
+
+// Prints a (const) char32_t array of 'len' elements, starting at address
+// 'begin'.
+void UniversalPrintArray(const char32_t* begin, size_t len, ostream* os) {
+ UniversalPrintCharArray(begin, len, os);
+}
+
+// Prints a (const) wchar_t array of 'len' elements, starting at address
+// 'begin'.
+void UniversalPrintArray(const wchar_t* begin, size_t len, ostream* os) {
+ UniversalPrintCharArray(begin, len, os);
+}
+
+namespace {
+
+// Prints a null-terminated C-style string to the ostream.
+template <typename Char>
+void PrintCStringTo(const Char* s, ostream* os) {
+ if (s == nullptr) {
+ *os << "NULL";
+ } else {
+ *os << ImplicitCast_<const void*>(s) << " pointing to ";
+ PrintCharsAsStringTo(s, std::char_traits<Char>::length(s), os);
+ }
+}
+
+} // anonymous namespace
+
+void PrintTo(const char* s, ostream* os) { PrintCStringTo(s, os); }
+
+#ifdef __cpp_char8_t
+void PrintTo(const char8_t* s, ostream* os) { PrintCStringTo(s, os); }
+#endif
+
+void PrintTo(const char16_t* s, ostream* os) { PrintCStringTo(s, os); }
+
+void PrintTo(const char32_t* s, ostream* os) { PrintCStringTo(s, os); }
+
+// MSVC compiler can be configured to define whar_t as a typedef
+// of unsigned short. Defining an overload for const wchar_t* in that case
+// would cause pointers to unsigned shorts be printed as wide strings,
+// possibly accessing more memory than intended and causing invalid
+// memory accesses. MSVC defines _NATIVE_WCHAR_T_DEFINED symbol when
+// wchar_t is implemented as a native type.
+#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
+// Prints the given wide C string to the ostream.
+void PrintTo(const wchar_t* s, ostream* os) { PrintCStringTo(s, os); }
+#endif // wchar_t is native
+
+namespace {
+
+bool ContainsUnprintableControlCodes(const char* str, size_t length) {
+ const unsigned char *s = reinterpret_cast<const unsigned char *>(str);
+
+ for (size_t i = 0; i < length; i++) {
+ unsigned char ch = *s++;
+ if (std::iscntrl(ch)) {
+ switch (ch) {
+ case '\t':
+ case '\n':
+ case '\r':
+ break;
+ default:
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool IsUTF8TrailByte(unsigned char t) { return 0x80 <= t && t<= 0xbf; }
+
+bool IsValidUTF8(const char* str, size_t length) {
+ const unsigned char *s = reinterpret_cast<const unsigned char *>(str);
+
+ for (size_t i = 0; i < length;) {
+ unsigned char lead = s[i++];
+
+ if (lead <= 0x7f) {
+ continue; // single-byte character (ASCII) 0..7F
+ }
+ if (lead < 0xc2) {
+ return false; // trail byte or non-shortest form
+ } else if (lead <= 0xdf && (i + 1) <= length && IsUTF8TrailByte(s[i])) {
+ ++i; // 2-byte character
+ } else if (0xe0 <= lead && lead <= 0xef && (i + 2) <= length &&
+ IsUTF8TrailByte(s[i]) &&
+ IsUTF8TrailByte(s[i + 1]) &&
+ // check for non-shortest form and surrogate
+ (lead != 0xe0 || s[i] >= 0xa0) &&
+ (lead != 0xed || s[i] < 0xa0)) {
+ i += 2; // 3-byte character
+ } else if (0xf0 <= lead && lead <= 0xf4 && (i + 3) <= length &&
+ IsUTF8TrailByte(s[i]) &&
+ IsUTF8TrailByte(s[i + 1]) &&
+ IsUTF8TrailByte(s[i + 2]) &&
+ // check for non-shortest form
+ (lead != 0xf0 || s[i] >= 0x90) &&
+ (lead != 0xf4 || s[i] < 0x90)) {
+ i += 3; // 4-byte character
+ } else {
+ return false;
+ }
+ }
+ return true;
+}
+
+void ConditionalPrintAsText(const char* str, size_t length, ostream* os) {
+ if (!ContainsUnprintableControlCodes(str, length) &&
+ IsValidUTF8(str, length)) {
+ *os << "\n As Text: \"" << str << "\"";
+ }
+}
+
+} // anonymous namespace
+
+void PrintStringTo(const ::std::string& s, ostream* os) {
+ if (PrintCharsAsStringTo(s.data(), s.size(), os) == kHexEscape) {
+ if (GTEST_FLAG(print_utf8)) {
+ ConditionalPrintAsText(s.data(), s.size(), os);
+ }
+ }
+}
+
+#ifdef __cpp_char8_t
+void PrintU8StringTo(const ::std::u8string& s, ostream* os) {
+ PrintCharsAsStringTo(s.data(), s.size(), os);
+}
+#endif
+
+void PrintU16StringTo(const ::std::u16string& s, ostream* os) {
+ PrintCharsAsStringTo(s.data(), s.size(), os);
+}
+
+void PrintU32StringTo(const ::std::u32string& s, ostream* os) {
+ PrintCharsAsStringTo(s.data(), s.size(), os);
+}
+
+#if GTEST_HAS_STD_WSTRING
+void PrintWideStringTo(const ::std::wstring& s, ostream* os) {
+ PrintCharsAsStringTo(s.data(), s.size(), os);
+}
+#endif // GTEST_HAS_STD_WSTRING
+
+} // namespace internal
+
+} // namespace testing
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+//
+// The Google C++ Testing and Mocking Framework (Google Test)
+
+
+
+namespace testing {
+
+using internal::GetUnitTestImpl;
+
+// Gets the summary of the failure message by omitting the stack trace
+// in it.
+std::string TestPartResult::ExtractSummary(const char* message) {
+ const char* const stack_trace = strstr(message, internal::kStackTraceMarker);
+ return stack_trace == nullptr ? message : std::string(message, stack_trace);
+}
+
+// Prints a TestPartResult object.
+std::ostream& operator<<(std::ostream& os, const TestPartResult& result) {
+ return os << internal::FormatFileLocation(result.file_name(),
+ result.line_number())
+ << " "
+ << (result.type() == TestPartResult::kSuccess
+ ? "Success"
+ : result.type() == TestPartResult::kSkip
+ ? "Skipped"
+ : result.type() == TestPartResult::kFatalFailure
+ ? "Fatal failure"
+ : "Non-fatal failure")
+ << ":\n"
+ << result.message() << std::endl;
+}
+
+// Appends a TestPartResult to the array.
+void TestPartResultArray::Append(const TestPartResult& result) {
+ array_.push_back(result);
+}
+
+// Returns the TestPartResult at the given index (0-based).
+const TestPartResult& TestPartResultArray::GetTestPartResult(int index) const {
+ if (index < 0 || index >= size()) {
+ printf("\nInvalid index (%d) into TestPartResultArray.\n", index);
+ internal::posix::Abort();
+ }
+
+ return array_[static_cast<size_t>(index)];
+}
+
+// Returns the number of TestPartResult objects in the array.
+int TestPartResultArray::size() const {
+ return static_cast<int>(array_.size());
+}
+
+namespace internal {
+
+HasNewFatalFailureHelper::HasNewFatalFailureHelper()
+ : has_new_fatal_failure_(false),
+ original_reporter_(GetUnitTestImpl()->
+ GetTestPartResultReporterForCurrentThread()) {
+ GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread(this);
+}
+
+HasNewFatalFailureHelper::~HasNewFatalFailureHelper() {
+ GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread(
+ original_reporter_);
+}
+
+void HasNewFatalFailureHelper::ReportTestPartResult(
+ const TestPartResult& result) {
+ if (result.fatally_failed())
+ has_new_fatal_failure_ = true;
+ original_reporter_->ReportTestPartResult(result);
+}
+
+} // namespace internal
+
+} // namespace testing
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+
+
+namespace testing {
+namespace internal {
+
+// Skips to the first non-space char in str. Returns an empty string if str
+// contains only whitespace characters.
+static const char* SkipSpaces(const char* str) {
+ while (IsSpace(*str))
+ str++;
+ return str;
+}
+
+static std::vector<std::string> SplitIntoTestNames(const char* src) {
+ std::vector<std::string> name_vec;
+ src = SkipSpaces(src);
+ for (; src != nullptr; src = SkipComma(src)) {
+ name_vec.push_back(StripTrailingSpaces(GetPrefixUntilComma(src)));
+ }
+ return name_vec;
+}
+
+// Verifies that registered_tests match the test names in
+// registered_tests_; returns registered_tests if successful, or
+// aborts the program otherwise.
+const char* TypedTestSuitePState::VerifyRegisteredTestNames(
+ const char* test_suite_name, const char* file, int line,
+ const char* registered_tests) {
+ RegisterTypeParameterizedTestSuite(test_suite_name, CodeLocation(file, line));
+
+ typedef RegisteredTestsMap::const_iterator RegisteredTestIter;
+ registered_ = true;
+
+ std::vector<std::string> name_vec = SplitIntoTestNames(registered_tests);
+
+ Message errors;
+
+ std::set<std::string> tests;
+ for (std::vector<std::string>::const_iterator name_it = name_vec.begin();
+ name_it != name_vec.end(); ++name_it) {
+ const std::string& name = *name_it;
+ if (tests.count(name) != 0) {
+ errors << "Test " << name << " is listed more than once.\n";
+ continue;
+ }
+
+ if (registered_tests_.count(name) != 0) {
+ tests.insert(name);
+ } else {
+ errors << "No test named " << name
+ << " can be found in this test suite.\n";
+ }
+ }
+
+ for (RegisteredTestIter it = registered_tests_.begin();
+ it != registered_tests_.end();
+ ++it) {
+ if (tests.count(it->first) == 0) {
+ errors << "You forgot to list test " << it->first << ".\n";
+ }
+ }
+
+ const std::string& errors_str = errors.GetString();
+ if (errors_str != "") {
+ fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(),
+ errors_str.c_str());
+ fflush(stderr);
+ posix::Abort();
+ }
+
+ return registered_tests;
+}
+
+} // namespace internal
+} // namespace testing
diff --git a/tools/distrib/gtest/gtest.h b/tools/distrib/gtest/gtest.h
new file mode 100644
index 00000000..cca42675
--- /dev/null
+++ b/tools/distrib/gtest/gtest.h
@@ -0,0 +1,12380 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+//
+// The Google C++ Testing and Mocking Framework (Google Test)
+//
+// This header file defines the public API for Google Test. It should be
+// included by any test program that uses Google Test.
+//
+// IMPORTANT NOTE: Due to limitation of the C++ language, we have to
+// leave some internal implementation details in this header file.
+// They are clearly marked by comments like this:
+//
+// // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+//
+// Such code is NOT meant to be used by a user directly, and is subject
+// to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user
+// program!
+//
+// Acknowledgment: Google Test borrowed the idea of automatic test
+// registration from Barthelemy Dagenais' (barthelemy@prologique.com)
+// easyUnit framework.
+
+// GOOGLETEST_CM0001 DO NOT DELETE
+
+#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_H_
+#define GOOGLETEST_INCLUDE_GTEST_GTEST_H_
+
+#include <cstddef>
+#include <limits>
+#include <memory>
+#include <ostream>
+#include <type_traits>
+#include <vector>
+
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// The Google C++ Testing and Mocking Framework (Google Test)
+//
+// This header file declares functions and macros used internally by
+// Google Test. They are subject to change without notice.
+
+// GOOGLETEST_CM0001 DO NOT DELETE
+
+#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_
+#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_
+
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Low-level types and utilities for porting Google Test to various
+// platforms. All macros ending with _ and symbols defined in an
+// internal namespace are subject to change without notice. Code
+// outside Google Test MUST NOT USE THEM DIRECTLY. Macros that don't
+// end with _ are part of Google Test's public API and can be used by
+// code outside Google Test.
+//
+// This file is fundamental to Google Test. All other Google Test source
+// files are expected to #include this. Therefore, it cannot #include
+// any other Google Test header.
+
+// GOOGLETEST_CM0001 DO NOT DELETE
+
+#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_
+#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_
+
+// Environment-describing macros
+// -----------------------------
+//
+// Google Test can be used in many different environments. Macros in
+// this section tell Google Test what kind of environment it is being
+// used in, such that Google Test can provide environment-specific
+// features and implementations.
+//
+// Google Test tries to automatically detect the properties of its
+// environment, so users usually don't need to worry about these
+// macros. However, the automatic detection is not perfect.
+// Sometimes it's necessary for a user to define some of the following
+// macros in the build script to override Google Test's decisions.
+//
+// If the user doesn't define a macro in the list, Google Test will
+// provide a default definition. After this header is #included, all
+// macros in this list will be defined to either 1 or 0.
+//
+// Notes to maintainers:
+// - Each macro here is a user-tweakable knob; do not grow the list
+// lightly.
+// - Use #if to key off these macros. Don't use #ifdef or "#if
+// defined(...)", which will not work as these macros are ALWAYS
+// defined.
+//
+// GTEST_HAS_CLONE - Define it to 1/0 to indicate that clone(2)
+// is/isn't available.
+// GTEST_HAS_EXCEPTIONS - Define it to 1/0 to indicate that exceptions
+// are enabled.
+// GTEST_HAS_POSIX_RE - Define it to 1/0 to indicate that POSIX regular
+// expressions are/aren't available.
+// GTEST_HAS_PTHREAD - Define it to 1/0 to indicate that <pthread.h>
+// is/isn't available.
+// GTEST_HAS_RTTI - Define it to 1/0 to indicate that RTTI is/isn't
+// enabled.
+// GTEST_HAS_STD_WSTRING - Define it to 1/0 to indicate that
+// std::wstring does/doesn't work (Google Test can
+// be used where std::wstring is unavailable).
+// GTEST_HAS_SEH - Define it to 1/0 to indicate whether the
+// compiler supports Microsoft's "Structured
+// Exception Handling".
+// GTEST_HAS_STREAM_REDIRECTION
+// - Define it to 1/0 to indicate whether the
+// platform supports I/O stream redirection using
+// dup() and dup2().
+// GTEST_LINKED_AS_SHARED_LIBRARY
+// - Define to 1 when compiling tests that use
+// Google Test as a shared library (known as
+// DLL on Windows).
+// GTEST_CREATE_SHARED_LIBRARY
+// - Define to 1 when compiling Google Test itself
+// as a shared library.
+// GTEST_DEFAULT_DEATH_TEST_STYLE
+// - The default value of --gtest_death_test_style.
+// The legacy default has been "fast" in the open
+// source version since 2008. The recommended value
+// is "threadsafe", and can be set in
+// custom/gtest-port.h.
+
+// Platform-indicating macros
+// --------------------------
+//
+// Macros indicating the platform on which Google Test is being used
+// (a macro is defined to 1 if compiled on the given platform;
+// otherwise UNDEFINED -- it's never defined to 0.). Google Test
+// defines these macros automatically. Code outside Google Test MUST
+// NOT define them.
+//
+// GTEST_OS_AIX - IBM AIX
+// GTEST_OS_CYGWIN - Cygwin
+// GTEST_OS_DRAGONFLY - DragonFlyBSD
+// GTEST_OS_FREEBSD - FreeBSD
+// GTEST_OS_FUCHSIA - Fuchsia
+// GTEST_OS_GNU_HURD - GNU/Hurd
+// GTEST_OS_GNU_KFREEBSD - GNU/kFreeBSD
+// GTEST_OS_HAIKU - Haiku
+// GTEST_OS_HPUX - HP-UX
+// GTEST_OS_LINUX - Linux
+// GTEST_OS_LINUX_ANDROID - Google Android
+// GTEST_OS_MAC - Mac OS X
+// GTEST_OS_IOS - iOS
+// GTEST_OS_NACL - Google Native Client (NaCl)
+// GTEST_OS_NETBSD - NetBSD
+// GTEST_OS_OPENBSD - OpenBSD
+// GTEST_OS_OS2 - OS/2
+// GTEST_OS_QNX - QNX
+// GTEST_OS_SOLARIS - Sun Solaris
+// GTEST_OS_WINDOWS - Windows (Desktop, MinGW, or Mobile)
+// GTEST_OS_WINDOWS_DESKTOP - Windows Desktop
+// GTEST_OS_WINDOWS_MINGW - MinGW
+// GTEST_OS_WINDOWS_MOBILE - Windows Mobile
+// GTEST_OS_WINDOWS_PHONE - Windows Phone
+// GTEST_OS_WINDOWS_RT - Windows Store App/WinRT
+// GTEST_OS_ZOS - z/OS
+//
+// Among the platforms, Cygwin, Linux, Mac OS X, and Windows have the
+// most stable support. Since core members of the Google Test project
+// don't have access to other platforms, support for them may be less
+// stable. If you notice any problems on your platform, please notify
+// googletestframework@googlegroups.com (patches for fixing them are
+// even more welcome!).
+//
+// It is possible that none of the GTEST_OS_* macros are defined.
+
+// Feature-indicating macros
+// -------------------------
+//
+// Macros indicating which Google Test features are available (a macro
+// is defined to 1 if the corresponding feature is supported;
+// otherwise UNDEFINED -- it's never defined to 0.). Google Test
+// defines these macros automatically. Code outside Google Test MUST
+// NOT define them.
+//
+// These macros are public so that portable tests can be written.
+// Such tests typically surround code using a feature with an #if
+// which controls that code. For example:
+//
+// #if GTEST_HAS_DEATH_TEST
+// EXPECT_DEATH(DoSomethingDeadly());
+// #endif
+//
+// GTEST_HAS_DEATH_TEST - death tests
+// GTEST_HAS_TYPED_TEST - typed tests
+// GTEST_HAS_TYPED_TEST_P - type-parameterized tests
+// GTEST_IS_THREADSAFE - Google Test is thread-safe.
+// GOOGLETEST_CM0007 DO NOT DELETE
+// GTEST_USES_POSIX_RE - enhanced POSIX regex is used. Do not confuse with
+// GTEST_HAS_POSIX_RE (see above) which users can
+// define themselves.
+// GTEST_USES_SIMPLE_RE - our own simple regex is used;
+// the above RE\b(s) are mutually exclusive.
+
+// Misc public macros
+// ------------------
+//
+// GTEST_FLAG(flag_name) - references the variable corresponding to
+// the given Google Test flag.
+
+// Internal utilities
+// ------------------
+//
+// The following macros and utilities are for Google Test's INTERNAL
+// use only. Code outside Google Test MUST NOT USE THEM DIRECTLY.
+//
+// Macros for basic C++ coding:
+// GTEST_AMBIGUOUS_ELSE_BLOCKER_ - for disabling a gcc warning.
+// GTEST_ATTRIBUTE_UNUSED_ - declares that a class' instances or a
+// variable don't have to be used.
+// GTEST_DISALLOW_ASSIGN_ - disables copy operator=.
+// GTEST_DISALLOW_COPY_AND_ASSIGN_ - disables copy ctor and operator=.
+// GTEST_DISALLOW_MOVE_ASSIGN_ - disables move operator=.
+// GTEST_DISALLOW_MOVE_AND_ASSIGN_ - disables move ctor and operator=.
+// GTEST_MUST_USE_RESULT_ - declares that a function's result must be used.
+// GTEST_INTENTIONAL_CONST_COND_PUSH_ - start code section where MSVC C4127 is
+// suppressed (constant conditional).
+// GTEST_INTENTIONAL_CONST_COND_POP_ - finish code section where MSVC C4127
+// is suppressed.
+// GTEST_INTERNAL_HAS_ANY - for enabling UniversalPrinter<std::any> or
+// UniversalPrinter<absl::any> specializations.
+// GTEST_INTERNAL_HAS_OPTIONAL - for enabling UniversalPrinter<std::optional>
+// or
+// UniversalPrinter<absl::optional>
+// specializations.
+// GTEST_INTERNAL_HAS_STRING_VIEW - for enabling Matcher<std::string_view> or
+// Matcher<absl::string_view>
+// specializations.
+// GTEST_INTERNAL_HAS_VARIANT - for enabling UniversalPrinter<std::variant> or
+// UniversalPrinter<absl::variant>
+// specializations.
+//
+// Synchronization:
+// Mutex, MutexLock, ThreadLocal, GetThreadCount()
+// - synchronization primitives.
+//
+// Regular expressions:
+// RE - a simple regular expression class using the POSIX
+// Extended Regular Expression syntax on UNIX-like platforms
+// GOOGLETEST_CM0008 DO NOT DELETE
+// or a reduced regular exception syntax on other
+// platforms, including Windows.
+// Logging:
+// GTEST_LOG_() - logs messages at the specified severity level.
+// LogToStderr() - directs all log messages to stderr.
+// FlushInfoLog() - flushes informational log messages.
+//
+// Stdout and stderr capturing:
+// CaptureStdout() - starts capturing stdout.
+// GetCapturedStdout() - stops capturing stdout and returns the captured
+// string.
+// CaptureStderr() - starts capturing stderr.
+// GetCapturedStderr() - stops capturing stderr and returns the captured
+// string.
+//
+// Integer types:
+// TypeWithSize - maps an integer to a int type.
+// TimeInMillis - integers of known sizes.
+// BiggestInt - the biggest signed integer type.
+//
+// Command-line utilities:
+// GTEST_DECLARE_*() - declares a flag.
+// GTEST_DEFINE_*() - defines a flag.
+// GetInjectableArgvs() - returns the command line as a vector of strings.
+//
+// Environment variable utilities:
+// GetEnv() - gets the value of an environment variable.
+// BoolFromGTestEnv() - parses a bool environment variable.
+// Int32FromGTestEnv() - parses an int32_t environment variable.
+// StringFromGTestEnv() - parses a string environment variable.
+//
+// Deprecation warnings:
+// GTEST_INTERNAL_DEPRECATED(message) - attribute marking a function as
+// deprecated; calling a marked function
+// should generate a compiler warning
+
+#include <ctype.h> // for isspace, etc
+#include <stddef.h> // for ptrdiff_t
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <cerrno>
+#include <cstdint>
+#include <limits>
+#include <type_traits>
+
+#ifndef _WIN32_WCE
+# include <sys/types.h>
+# include <sys/stat.h>
+#endif // !_WIN32_WCE
+
+#if defined __APPLE__
+# include <AvailabilityMacros.h>
+# include <TargetConditionals.h>
+#endif
+
+#include <iostream> // NOLINT
+#include <locale>
+#include <memory>
+#include <string> // NOLINT
+#include <tuple>
+#include <vector> // NOLINT
+
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Injection point for custom user configurations. See README for details
+//
+// ** Custom implementation starts here **
+
+#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_
+#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_
+
+#endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// The Google C++ Testing and Mocking Framework (Google Test)
+//
+// This header file defines the GTEST_OS_* macro.
+// It is separate from gtest-port.h so that custom/gtest-port.h can include it.
+
+#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_
+#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_
+
+// Determines the platform on which Google Test is compiled.
+#ifdef __CYGWIN__
+# define GTEST_OS_CYGWIN 1
+# elif defined(__MINGW__) || defined(__MINGW32__) || defined(__MINGW64__)
+# define GTEST_OS_WINDOWS_MINGW 1
+# define GTEST_OS_WINDOWS 1
+#elif defined _WIN32
+# define GTEST_OS_WINDOWS 1
+# ifdef _WIN32_WCE
+# define GTEST_OS_WINDOWS_MOBILE 1
+# elif defined(WINAPI_FAMILY)
+# include <winapifamily.h>
+# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+# define GTEST_OS_WINDOWS_DESKTOP 1
+# elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP)
+# define GTEST_OS_WINDOWS_PHONE 1
+# elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
+# define GTEST_OS_WINDOWS_RT 1
+# elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_TV_TITLE)
+# define GTEST_OS_WINDOWS_PHONE 1
+# define GTEST_OS_WINDOWS_TV_TITLE 1
+# else
+ // WINAPI_FAMILY defined but no known partition matched.
+ // Default to desktop.
+# define GTEST_OS_WINDOWS_DESKTOP 1
+# endif
+# else
+# define GTEST_OS_WINDOWS_DESKTOP 1
+# endif // _WIN32_WCE
+#elif defined __OS2__
+# define GTEST_OS_OS2 1
+#elif defined __APPLE__
+# define GTEST_OS_MAC 1
+# include <TargetConditionals.h>
+# if TARGET_OS_IPHONE
+# define GTEST_OS_IOS 1
+# endif
+#elif defined __DragonFly__
+# define GTEST_OS_DRAGONFLY 1
+#elif defined __FreeBSD__
+# define GTEST_OS_FREEBSD 1
+#elif defined __Fuchsia__
+# define GTEST_OS_FUCHSIA 1
+#elif defined(__GNU__)
+# define GTEST_OS_GNU_HURD 1
+#elif defined(__GLIBC__) && defined(__FreeBSD_kernel__)
+# define GTEST_OS_GNU_KFREEBSD 1
+#elif defined __linux__
+# define GTEST_OS_LINUX 1
+# if defined __ANDROID__
+# define GTEST_OS_LINUX_ANDROID 1
+# endif
+#elif defined __MVS__
+# define GTEST_OS_ZOS 1
+#elif defined(__sun) && defined(__SVR4)
+# define GTEST_OS_SOLARIS 1
+#elif defined(_AIX)
+# define GTEST_OS_AIX 1
+#elif defined(__hpux)
+# define GTEST_OS_HPUX 1
+#elif defined __native_client__
+# define GTEST_OS_NACL 1
+#elif defined __NetBSD__
+# define GTEST_OS_NETBSD 1
+#elif defined __OpenBSD__
+# define GTEST_OS_OPENBSD 1
+#elif defined __QNX__
+# define GTEST_OS_QNX 1
+#elif defined(__HAIKU__)
+#define GTEST_OS_HAIKU 1
+#elif defined ESP8266
+#define GTEST_OS_ESP8266 1
+#elif defined ESP32
+#define GTEST_OS_ESP32 1
+#elif defined(__XTENSA__)
+#define GTEST_OS_XTENSA 1
+#endif // __CYGWIN__
+
+#endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_
+
+#if !defined(GTEST_DEV_EMAIL_)
+# define GTEST_DEV_EMAIL_ "googletestframework@@googlegroups.com"
+# define GTEST_FLAG_PREFIX_ "gtest_"
+# define GTEST_FLAG_PREFIX_DASH_ "gtest-"
+# define GTEST_FLAG_PREFIX_UPPER_ "GTEST_"
+# define GTEST_NAME_ "Google Test"
+# define GTEST_PROJECT_URL_ "https://github.com/google/googletest/"
+#endif // !defined(GTEST_DEV_EMAIL_)
+
+#if !defined(GTEST_INIT_GOOGLE_TEST_NAME_)
+# define GTEST_INIT_GOOGLE_TEST_NAME_ "testing::InitGoogleTest"
+#endif // !defined(GTEST_INIT_GOOGLE_TEST_NAME_)
+
+// Determines the version of gcc that is used to compile this.
+#ifdef __GNUC__
+// 40302 means version 4.3.2.
+# define GTEST_GCC_VER_ \
+ (__GNUC__*10000 + __GNUC_MINOR__*100 + __GNUC_PATCHLEVEL__)
+#endif // __GNUC__
+
+// Macros for disabling Microsoft Visual C++ warnings.
+//
+// GTEST_DISABLE_MSC_WARNINGS_PUSH_(4800 4385)
+// /* code that triggers warnings C4800 and C4385 */
+// GTEST_DISABLE_MSC_WARNINGS_POP_()
+#if defined(_MSC_VER)
+# define GTEST_DISABLE_MSC_WARNINGS_PUSH_(warnings) \
+ __pragma(warning(push)) \
+ __pragma(warning(disable: warnings))
+# define GTEST_DISABLE_MSC_WARNINGS_POP_() \
+ __pragma(warning(pop))
+#else
+// Not all compilers are MSVC
+# define GTEST_DISABLE_MSC_WARNINGS_PUSH_(warnings)
+# define GTEST_DISABLE_MSC_WARNINGS_POP_()
+#endif
+
+// Clang on Windows does not understand MSVC's pragma warning.
+// We need clang-specific way to disable function deprecation warning.
+#ifdef __clang__
+# define GTEST_DISABLE_MSC_DEPRECATED_PUSH_() \
+ _Pragma("clang diagnostic push") \
+ _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") \
+ _Pragma("clang diagnostic ignored \"-Wdeprecated-implementations\"")
+#define GTEST_DISABLE_MSC_DEPRECATED_POP_() \
+ _Pragma("clang diagnostic pop")
+#else
+# define GTEST_DISABLE_MSC_DEPRECATED_PUSH_() \
+ GTEST_DISABLE_MSC_WARNINGS_PUSH_(4996)
+# define GTEST_DISABLE_MSC_DEPRECATED_POP_() \
+ GTEST_DISABLE_MSC_WARNINGS_POP_()
+#endif
+
+// Brings in definitions for functions used in the testing::internal::posix
+// namespace (read, write, close, chdir, isatty, stat). We do not currently
+// use them on Windows Mobile.
+#if GTEST_OS_WINDOWS
+# if !GTEST_OS_WINDOWS_MOBILE
+# include <direct.h>
+# include <io.h>
+# endif
+// In order to avoid having to include <windows.h>, use forward declaration
+#if GTEST_OS_WINDOWS_MINGW && !defined(__MINGW64_VERSION_MAJOR)
+// MinGW defined _CRITICAL_SECTION and _RTL_CRITICAL_SECTION as two
+// separate (equivalent) structs, instead of using typedef
+typedef struct _CRITICAL_SECTION GTEST_CRITICAL_SECTION;
+#else
+// Assume CRITICAL_SECTION is a typedef of _RTL_CRITICAL_SECTION.
+// This assumption is verified by
+// WindowsTypesTest.CRITICAL_SECTIONIs_RTL_CRITICAL_SECTION.
+typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION;
+#endif
+#elif GTEST_OS_XTENSA
+#include <unistd.h>
+// Xtensa toolchains define strcasecmp in the string.h header instead of
+// strings.h. string.h is already included.
+#else
+// This assumes that non-Windows OSes provide unistd.h. For OSes where this
+// is not the case, we need to include headers that provide the functions
+// mentioned above.
+# include <unistd.h>
+# include <strings.h>
+#endif // GTEST_OS_WINDOWS
+
+#if GTEST_OS_LINUX_ANDROID
+// Used to define __ANDROID_API__ matching the target NDK API level.
+# include <android/api-level.h> // NOLINT
+#endif
+
+// Defines this to true if and only if Google Test can use POSIX regular
+// expressions.
+#ifndef GTEST_HAS_POSIX_RE
+# if GTEST_OS_LINUX_ANDROID
+// On Android, <regex.h> is only available starting with Gingerbread.
+# define GTEST_HAS_POSIX_RE (__ANDROID_API__ >= 9)
+# else
+#define GTEST_HAS_POSIX_RE (!GTEST_OS_WINDOWS && !GTEST_OS_XTENSA)
+# endif
+#endif
+
+#if GTEST_USES_PCRE
+// The appropriate headers have already been included.
+
+#elif GTEST_HAS_POSIX_RE
+
+// On some platforms, <regex.h> needs someone to define size_t, and
+// won't compile otherwise. We can #include it here as we already
+// included <stdlib.h>, which is guaranteed to define size_t through
+// <stddef.h>.
+# include <regex.h> // NOLINT
+
+# define GTEST_USES_POSIX_RE 1
+
+#elif GTEST_OS_WINDOWS
+
+// <regex.h> is not available on Windows. Use our own simple regex
+// implementation instead.
+# define GTEST_USES_SIMPLE_RE 1
+
+#else
+
+// <regex.h> may not be available on this platform. Use our own
+// simple regex implementation instead.
+# define GTEST_USES_SIMPLE_RE 1
+
+#endif // GTEST_USES_PCRE
+
+#ifndef GTEST_HAS_EXCEPTIONS
+// The user didn't tell us whether exceptions are enabled, so we need
+// to figure it out.
+# if defined(_MSC_VER) && defined(_CPPUNWIND)
+// MSVC defines _CPPUNWIND to 1 if and only if exceptions are enabled.
+# define GTEST_HAS_EXCEPTIONS 1
+# elif defined(__BORLANDC__)
+// C++Builder's implementation of the STL uses the _HAS_EXCEPTIONS
+// macro to enable exceptions, so we'll do the same.
+// Assumes that exceptions are enabled by default.
+# ifndef _HAS_EXCEPTIONS
+# define _HAS_EXCEPTIONS 1
+# endif // _HAS_EXCEPTIONS
+# define GTEST_HAS_EXCEPTIONS _HAS_EXCEPTIONS
+# elif defined(__clang__)
+// clang defines __EXCEPTIONS if and only if exceptions are enabled before clang
+// 220714, but if and only if cleanups are enabled after that. In Obj-C++ files,
+// there can be cleanups for ObjC exceptions which also need cleanups, even if
+// C++ exceptions are disabled. clang has __has_feature(cxx_exceptions) which
+// checks for C++ exceptions starting at clang r206352, but which checked for
+// cleanups prior to that. To reliably check for C++ exception availability with
+// clang, check for
+// __EXCEPTIONS && __has_feature(cxx_exceptions).
+# define GTEST_HAS_EXCEPTIONS (__EXCEPTIONS && __has_feature(cxx_exceptions))
+# elif defined(__GNUC__) && __EXCEPTIONS
+// gcc defines __EXCEPTIONS to 1 if and only if exceptions are enabled.
+# define GTEST_HAS_EXCEPTIONS 1
+# elif defined(__SUNPRO_CC)
+// Sun Pro CC supports exceptions. However, there is no compile-time way of
+// detecting whether they are enabled or not. Therefore, we assume that
+// they are enabled unless the user tells us otherwise.
+# define GTEST_HAS_EXCEPTIONS 1
+# elif defined(__IBMCPP__) && __EXCEPTIONS
+// xlC defines __EXCEPTIONS to 1 if and only if exceptions are enabled.
+# define GTEST_HAS_EXCEPTIONS 1
+# elif defined(__HP_aCC)
+// Exception handling is in effect by default in HP aCC compiler. It has to
+// be turned of by +noeh compiler option if desired.
+# define GTEST_HAS_EXCEPTIONS 1
+# else
+// For other compilers, we assume exceptions are disabled to be
+// conservative.
+# define GTEST_HAS_EXCEPTIONS 0
+# endif // defined(_MSC_VER) || defined(__BORLANDC__)
+#endif // GTEST_HAS_EXCEPTIONS
+
+#ifndef GTEST_HAS_STD_WSTRING
+// The user didn't tell us whether ::std::wstring is available, so we need
+// to figure it out.
+// Cygwin 1.7 and below doesn't support ::std::wstring.
+// Solaris' libc++ doesn't support it either. Android has
+// no support for it at least as recent as Froyo (2.2).
+#define GTEST_HAS_STD_WSTRING \
+ (!(GTEST_OS_LINUX_ANDROID || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \
+ GTEST_OS_HAIKU || GTEST_OS_ESP32 || GTEST_OS_ESP8266 || GTEST_OS_XTENSA))
+
+#endif // GTEST_HAS_STD_WSTRING
+
+// Determines whether RTTI is available.
+#ifndef GTEST_HAS_RTTI
+// The user didn't tell us whether RTTI is enabled, so we need to
+// figure it out.
+
+# ifdef _MSC_VER
+
+#ifdef _CPPRTTI // MSVC defines this macro if and only if RTTI is enabled.
+# define GTEST_HAS_RTTI 1
+# else
+# define GTEST_HAS_RTTI 0
+# endif
+
+// Starting with version 4.3.2, gcc defines __GXX_RTTI if and only if RTTI is
+// enabled.
+# elif defined(__GNUC__)
+
+# ifdef __GXX_RTTI
+// When building against STLport with the Android NDK and with
+// -frtti -fno-exceptions, the build fails at link time with undefined
+// references to __cxa_bad_typeid. Note sure if STL or toolchain bug,
+// so disable RTTI when detected.
+# if GTEST_OS_LINUX_ANDROID && defined(_STLPORT_MAJOR) && \
+ !defined(__EXCEPTIONS)
+# define GTEST_HAS_RTTI 0
+# else
+# define GTEST_HAS_RTTI 1
+# endif // GTEST_OS_LINUX_ANDROID && __STLPORT_MAJOR && !__EXCEPTIONS
+# else
+# define GTEST_HAS_RTTI 0
+# endif // __GXX_RTTI
+
+// Clang defines __GXX_RTTI starting with version 3.0, but its manual recommends
+// using has_feature instead. has_feature(cxx_rtti) is supported since 2.7, the
+// first version with C++ support.
+# elif defined(__clang__)
+
+# define GTEST_HAS_RTTI __has_feature(cxx_rtti)
+
+// Starting with version 9.0 IBM Visual Age defines __RTTI_ALL__ to 1 if
+// both the typeid and dynamic_cast features are present.
+# elif defined(__IBMCPP__) && (__IBMCPP__ >= 900)
+
+# ifdef __RTTI_ALL__
+# define GTEST_HAS_RTTI 1
+# else
+# define GTEST_HAS_RTTI 0
+# endif
+
+# else
+
+// For all other compilers, we assume RTTI is enabled.
+# define GTEST_HAS_RTTI 1
+
+# endif // _MSC_VER
+
+#endif // GTEST_HAS_RTTI
+
+// It's this header's responsibility to #include <typeinfo> when RTTI
+// is enabled.
+#if GTEST_HAS_RTTI
+# include <typeinfo>
+#endif
+
+// Determines whether Google Test can use the pthreads library.
+#ifndef GTEST_HAS_PTHREAD
+// The user didn't tell us explicitly, so we make reasonable assumptions about
+// which platforms have pthreads support.
+//
+// To disable threading support in Google Test, add -DGTEST_HAS_PTHREAD=0
+// to your compiler flags.
+#define GTEST_HAS_PTHREAD \
+ (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_HPUX || GTEST_OS_QNX || \
+ GTEST_OS_FREEBSD || GTEST_OS_NACL || GTEST_OS_NETBSD || GTEST_OS_FUCHSIA || \
+ GTEST_OS_DRAGONFLY || GTEST_OS_GNU_KFREEBSD || GTEST_OS_OPENBSD || \
+ GTEST_OS_HAIKU || GTEST_OS_GNU_HURD)
+#endif // GTEST_HAS_PTHREAD
+
+#if GTEST_HAS_PTHREAD
+// gtest-port.h guarantees to #include <pthread.h> when GTEST_HAS_PTHREAD is
+// true.
+# include <pthread.h> // NOLINT
+
+// For timespec and nanosleep, used below.
+# include <time.h> // NOLINT
+#endif
+
+// Determines whether clone(2) is supported.
+// Usually it will only be available on Linux, excluding
+// Linux on the Itanium architecture.
+// Also see http://linux.die.net/man/2/clone.
+#ifndef GTEST_HAS_CLONE
+// The user didn't tell us, so we need to figure it out.
+
+# if GTEST_OS_LINUX && !defined(__ia64__)
+# if GTEST_OS_LINUX_ANDROID
+// On Android, clone() became available at different API levels for each 32-bit
+// architecture.
+# if defined(__LP64__) || \
+ (defined(__arm__) && __ANDROID_API__ >= 9) || \
+ (defined(__mips__) && __ANDROID_API__ >= 12) || \
+ (defined(__i386__) && __ANDROID_API__ >= 17)
+# define GTEST_HAS_CLONE 1
+# else
+# define GTEST_HAS_CLONE 0
+# endif
+# else
+# define GTEST_HAS_CLONE 1
+# endif
+# else
+# define GTEST_HAS_CLONE 0
+# endif // GTEST_OS_LINUX && !defined(__ia64__)
+
+#endif // GTEST_HAS_CLONE
+
+// Determines whether to support stream redirection. This is used to test
+// output correctness and to implement death tests.
+#ifndef GTEST_HAS_STREAM_REDIRECTION
+// By default, we assume that stream redirection is supported on all
+// platforms except known mobile ones.
+#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || \
+ GTEST_OS_WINDOWS_RT || GTEST_OS_ESP8266 || GTEST_OS_XTENSA
+# define GTEST_HAS_STREAM_REDIRECTION 0
+# else
+# define GTEST_HAS_STREAM_REDIRECTION 1
+# endif // !GTEST_OS_WINDOWS_MOBILE
+#endif // GTEST_HAS_STREAM_REDIRECTION
+
+// Determines whether to support death tests.
+// pops up a dialog window that cannot be suppressed programmatically.
+#if (GTEST_OS_LINUX || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \
+ (GTEST_OS_MAC && !GTEST_OS_IOS) || \
+ (GTEST_OS_WINDOWS_DESKTOP && _MSC_VER) || GTEST_OS_WINDOWS_MINGW || \
+ GTEST_OS_AIX || GTEST_OS_HPUX || GTEST_OS_OPENBSD || GTEST_OS_QNX || \
+ GTEST_OS_FREEBSD || GTEST_OS_NETBSD || GTEST_OS_FUCHSIA || \
+ GTEST_OS_DRAGONFLY || GTEST_OS_GNU_KFREEBSD || GTEST_OS_HAIKU || \
+ GTEST_OS_GNU_HURD)
+# define GTEST_HAS_DEATH_TEST 1
+#endif
+
+// Determines whether to support type-driven tests.
+
+// Typed tests need <typeinfo> and variadic macros, which GCC, VC++ 8.0,
+// Sun Pro CC, IBM Visual Age, and HP aCC support.
+#if defined(__GNUC__) || defined(_MSC_VER) || defined(__SUNPRO_CC) || \
+ defined(__IBMCPP__) || defined(__HP_aCC)
+# define GTEST_HAS_TYPED_TEST 1
+# define GTEST_HAS_TYPED_TEST_P 1
+#endif
+
+// Determines whether the system compiler uses UTF-16 for encoding wide strings.
+#define GTEST_WIDE_STRING_USES_UTF16_ \
+ (GTEST_OS_WINDOWS || GTEST_OS_CYGWIN || GTEST_OS_AIX || GTEST_OS_OS2)
+
+// Determines whether test results can be streamed to a socket.
+#if GTEST_OS_LINUX || GTEST_OS_GNU_KFREEBSD || GTEST_OS_DRAGONFLY || \
+ GTEST_OS_FREEBSD || GTEST_OS_NETBSD || GTEST_OS_OPENBSD || \
+ GTEST_OS_GNU_HURD
+# define GTEST_CAN_STREAM_RESULTS_ 1
+#endif
+
+// Defines some utility macros.
+
+// The GNU compiler emits a warning if nested "if" statements are followed by
+// an "else" statement and braces are not used to explicitly disambiguate the
+// "else" binding. This leads to problems with code like:
+//
+// if (gate)
+// ASSERT_*(condition) << "Some message";
+//
+// The "switch (0) case 0:" idiom is used to suppress this.
+#ifdef __INTEL_COMPILER
+# define GTEST_AMBIGUOUS_ELSE_BLOCKER_
+#else
+# define GTEST_AMBIGUOUS_ELSE_BLOCKER_ switch (0) case 0: default: // NOLINT
+#endif
+
+// Use this annotation at the end of a struct/class definition to
+// prevent the compiler from optimizing away instances that are never
+// used. This is useful when all interesting logic happens inside the
+// c'tor and / or d'tor. Example:
+//
+// struct Foo {
+// Foo() { ... }
+// } GTEST_ATTRIBUTE_UNUSED_;
+//
+// Also use it after a variable or parameter declaration to tell the
+// compiler the variable/parameter does not have to be used.
+#if defined(__GNUC__) && !defined(COMPILER_ICC)
+# define GTEST_ATTRIBUTE_UNUSED_ __attribute__ ((unused))
+#elif defined(__clang__)
+# if __has_attribute(unused)
+# define GTEST_ATTRIBUTE_UNUSED_ __attribute__ ((unused))
+# endif
+#endif
+#ifndef GTEST_ATTRIBUTE_UNUSED_
+# define GTEST_ATTRIBUTE_UNUSED_
+#endif
+
+// Use this annotation before a function that takes a printf format string.
+#if (defined(__GNUC__) || defined(__clang__)) && !defined(COMPILER_ICC)
+# if defined(__MINGW_PRINTF_FORMAT)
+// MinGW has two different printf implementations. Ensure the format macro
+// matches the selected implementation. See
+// https://sourceforge.net/p/mingw-w64/wiki2/gnu%20printf/.
+# define GTEST_ATTRIBUTE_PRINTF_(string_index, first_to_check) \
+ __attribute__((__format__(__MINGW_PRINTF_FORMAT, string_index, \
+ first_to_check)))
+# else
+# define GTEST_ATTRIBUTE_PRINTF_(string_index, first_to_check) \
+ __attribute__((__format__(__printf__, string_index, first_to_check)))
+# endif
+#else
+# define GTEST_ATTRIBUTE_PRINTF_(string_index, first_to_check)
+#endif
+
+
+// A macro to disallow copy operator=
+// This should be used in the private: declarations for a class.
+#define GTEST_DISALLOW_ASSIGN_(type) \
+ type& operator=(type const &) = delete
+
+// A macro to disallow copy constructor and operator=
+// This should be used in the private: declarations for a class.
+#define GTEST_DISALLOW_COPY_AND_ASSIGN_(type) \
+ type(type const&) = delete; \
+ type& operator=(type const&) = delete
+
+// A macro to disallow move operator=
+// This should be used in the private: declarations for a class.
+#define GTEST_DISALLOW_MOVE_ASSIGN_(type) \
+ type& operator=(type &&) noexcept = delete
+
+// A macro to disallow move constructor and operator=
+// This should be used in the private: declarations for a class.
+#define GTEST_DISALLOW_MOVE_AND_ASSIGN_(type) \
+ type(type&&) noexcept = delete; \
+ type& operator=(type&&) noexcept = delete
+
+// Tell the compiler to warn about unused return values for functions declared
+// with this macro. The macro should be used on function declarations
+// following the argument list:
+//
+// Sprocket* AllocateSprocket() GTEST_MUST_USE_RESULT_;
+#if defined(__GNUC__) && !defined(COMPILER_ICC)
+# define GTEST_MUST_USE_RESULT_ __attribute__ ((warn_unused_result))
+#else
+# define GTEST_MUST_USE_RESULT_
+#endif // __GNUC__ && !COMPILER_ICC
+
+// MS C++ compiler emits warning when a conditional expression is compile time
+// constant. In some contexts this warning is false positive and needs to be
+// suppressed. Use the following two macros in such cases:
+//
+// GTEST_INTENTIONAL_CONST_COND_PUSH_()
+// while (true) {
+// GTEST_INTENTIONAL_CONST_COND_POP_()
+// }
+# define GTEST_INTENTIONAL_CONST_COND_PUSH_() \
+ GTEST_DISABLE_MSC_WARNINGS_PUSH_(4127)
+# define GTEST_INTENTIONAL_CONST_COND_POP_() \
+ GTEST_DISABLE_MSC_WARNINGS_POP_()
+
+// Determine whether the compiler supports Microsoft's Structured Exception
+// Handling. This is supported by several Windows compilers but generally
+// does not exist on any other system.
+#ifndef GTEST_HAS_SEH
+// The user didn't tell us, so we need to figure it out.
+
+# if defined(_MSC_VER) || defined(__BORLANDC__)
+// These two compilers are known to support SEH.
+# define GTEST_HAS_SEH 1
+# else
+// Assume no SEH.
+# define GTEST_HAS_SEH 0
+# endif
+
+#endif // GTEST_HAS_SEH
+
+#ifndef GTEST_IS_THREADSAFE
+
+#define GTEST_IS_THREADSAFE \
+ (GTEST_HAS_MUTEX_AND_THREAD_LOCAL_ || \
+ (GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT) || \
+ GTEST_HAS_PTHREAD)
+
+#endif // GTEST_IS_THREADSAFE
+
+// GTEST_API_ qualifies all symbols that must be exported. The definitions below
+// are guarded by #ifndef to give embedders a chance to define GTEST_API_ in
+// gtest/internal/custom/gtest-port.h
+#ifndef GTEST_API_
+
+#ifdef _MSC_VER
+# if GTEST_LINKED_AS_SHARED_LIBRARY
+# define GTEST_API_ __declspec(dllimport)
+# elif GTEST_CREATE_SHARED_LIBRARY
+# define GTEST_API_ __declspec(dllexport)
+# endif
+#elif __GNUC__ >= 4 || defined(__clang__)
+# define GTEST_API_ __attribute__((visibility ("default")))
+#endif // _MSC_VER
+
+#endif // GTEST_API_
+
+#ifndef GTEST_API_
+# define GTEST_API_
+#endif // GTEST_API_
+
+#ifndef GTEST_DEFAULT_DEATH_TEST_STYLE
+# define GTEST_DEFAULT_DEATH_TEST_STYLE "fast"
+#endif // GTEST_DEFAULT_DEATH_TEST_STYLE
+
+#ifdef __GNUC__
+// Ask the compiler to never inline a given function.
+# define GTEST_NO_INLINE_ __attribute__((noinline))
+#else
+# define GTEST_NO_INLINE_
+#endif
+
+// _LIBCPP_VERSION is defined by the libc++ library from the LLVM project.
+#if !defined(GTEST_HAS_CXXABI_H_)
+# if defined(__GLIBCXX__) || (defined(_LIBCPP_VERSION) && !defined(_MSC_VER))
+# define GTEST_HAS_CXXABI_H_ 1
+# else
+# define GTEST_HAS_CXXABI_H_ 0
+# endif
+#endif
+
+// A function level attribute to disable checking for use of uninitialized
+// memory when built with MemorySanitizer.
+#if defined(__clang__)
+# if __has_feature(memory_sanitizer)
+# define GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ \
+ __attribute__((no_sanitize_memory))
+# else
+# define GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_
+# endif // __has_feature(memory_sanitizer)
+#else
+# define GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_
+#endif // __clang__
+
+// A function level attribute to disable AddressSanitizer instrumentation.
+#if defined(__clang__)
+# if __has_feature(address_sanitizer)
+# define GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ \
+ __attribute__((no_sanitize_address))
+# else
+# define GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
+# endif // __has_feature(address_sanitizer)
+#else
+# define GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
+#endif // __clang__
+
+// A function level attribute to disable HWAddressSanitizer instrumentation.
+#if defined(__clang__)
+# if __has_feature(hwaddress_sanitizer)
+# define GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ \
+ __attribute__((no_sanitize("hwaddress")))
+# else
+# define GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_
+# endif // __has_feature(hwaddress_sanitizer)
+#else
+# define GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_
+#endif // __clang__
+
+// A function level attribute to disable ThreadSanitizer instrumentation.
+#if defined(__clang__)
+# if __has_feature(thread_sanitizer)
+# define GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ \
+ __attribute__((no_sanitize_thread))
+# else
+# define GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_
+# endif // __has_feature(thread_sanitizer)
+#else
+# define GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_
+#endif // __clang__
+
+namespace testing {
+
+class Message;
+
+// Legacy imports for backwards compatibility.
+// New code should use std:: names directly.
+using std::get;
+using std::make_tuple;
+using std::tuple;
+using std::tuple_element;
+using std::tuple_size;
+
+namespace internal {
+
+// A secret type that Google Test users don't know about. It has no
+// definition on purpose. Therefore it's impossible to create a
+// Secret object, which is what we want.
+class Secret;
+
+// The GTEST_COMPILE_ASSERT_ is a legacy macro used to verify that a compile
+// time expression is true (in new code, use static_assert instead). For
+// example, you could use it to verify the size of a static array:
+//
+// GTEST_COMPILE_ASSERT_(GTEST_ARRAY_SIZE_(names) == NUM_NAMES,
+// names_incorrect_size);
+//
+// The second argument to the macro must be a valid C++ identifier. If the
+// expression is false, compiler will issue an error containing this identifier.
+#define GTEST_COMPILE_ASSERT_(expr, msg) static_assert(expr, #msg)
+
+// A helper for suppressing warnings on constant condition. It just
+// returns 'condition'.
+GTEST_API_ bool IsTrue(bool condition);
+
+// Defines RE.
+
+#if GTEST_USES_PCRE
+// if used, PCRE is injected by custom/gtest-port.h
+#elif GTEST_USES_POSIX_RE || GTEST_USES_SIMPLE_RE
+
+// A simple C++ wrapper for <regex.h>. It uses the POSIX Extended
+// Regular Expression syntax.
+class GTEST_API_ RE {
+ public:
+ // A copy constructor is required by the Standard to initialize object
+ // references from r-values.
+ RE(const RE& other) { Init(other.pattern()); }
+
+ // Constructs an RE from a string.
+ RE(const ::std::string& regex) { Init(regex.c_str()); } // NOLINT
+
+ RE(const char* regex) { Init(regex); } // NOLINT
+ ~RE();
+
+ // Returns the string representation of the regex.
+ const char* pattern() const { return pattern_; }
+
+ // FullMatch(str, re) returns true if and only if regular expression re
+ // matches the entire str.
+ // PartialMatch(str, re) returns true if and only if regular expression re
+ // matches a substring of str (including str itself).
+ static bool FullMatch(const ::std::string& str, const RE& re) {
+ return FullMatch(str.c_str(), re);
+ }
+ static bool PartialMatch(const ::std::string& str, const RE& re) {
+ return PartialMatch(str.c_str(), re);
+ }
+
+ static bool FullMatch(const char* str, const RE& re);
+ static bool PartialMatch(const char* str, const RE& re);
+
+ private:
+ void Init(const char* regex);
+ const char* pattern_;
+ bool is_valid_;
+
+# if GTEST_USES_POSIX_RE
+
+ regex_t full_regex_; // For FullMatch().
+ regex_t partial_regex_; // For PartialMatch().
+
+# else // GTEST_USES_SIMPLE_RE
+
+ const char* full_pattern_; // For FullMatch();
+
+# endif
+};
+
+#endif // GTEST_USES_PCRE
+
+// Formats a source file path and a line number as they would appear
+// in an error message from the compiler used to compile this code.
+GTEST_API_ ::std::string FormatFileLocation(const char* file, int line);
+
+// Formats a file location for compiler-independent XML output.
+// Although this function is not platform dependent, we put it next to
+// FormatFileLocation in order to contrast the two functions.
+GTEST_API_ ::std::string FormatCompilerIndependentFileLocation(const char* file,
+ int line);
+
+// Defines logging utilities:
+// GTEST_LOG_(severity) - logs messages at the specified severity level. The
+// message itself is streamed into the macro.
+// LogToStderr() - directs all log messages to stderr.
+// FlushInfoLog() - flushes informational log messages.
+
+enum GTestLogSeverity {
+ GTEST_INFO,
+ GTEST_WARNING,
+ GTEST_ERROR,
+ GTEST_FATAL
+};
+
+// Formats log entry severity, provides a stream object for streaming the
+// log message, and terminates the message with a newline when going out of
+// scope.
+class GTEST_API_ GTestLog {
+ public:
+ GTestLog(GTestLogSeverity severity, const char* file, int line);
+
+ // Flushes the buffers and, if severity is GTEST_FATAL, aborts the program.
+ ~GTestLog();
+
+ ::std::ostream& GetStream() { return ::std::cerr; }
+
+ private:
+ const GTestLogSeverity severity_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestLog);
+};
+
+#if !defined(GTEST_LOG_)
+
+# define GTEST_LOG_(severity) \
+ ::testing::internal::GTestLog(::testing::internal::GTEST_##severity, \
+ __FILE__, __LINE__).GetStream()
+
+inline void LogToStderr() {}
+inline void FlushInfoLog() { fflush(nullptr); }
+
+#endif // !defined(GTEST_LOG_)
+
+#if !defined(GTEST_CHECK_)
+// INTERNAL IMPLEMENTATION - DO NOT USE.
+//
+// GTEST_CHECK_ is an all-mode assert. It aborts the program if the condition
+// is not satisfied.
+// Synopsys:
+// GTEST_CHECK_(boolean_condition);
+// or
+// GTEST_CHECK_(boolean_condition) << "Additional message";
+//
+// This checks the condition and if the condition is not satisfied
+// it prints message about the condition violation, including the
+// condition itself, plus additional message streamed into it, if any,
+// and then it aborts the program. It aborts the program irrespective of
+// whether it is built in the debug mode or not.
+# define GTEST_CHECK_(condition) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (::testing::internal::IsTrue(condition)) \
+ ; \
+ else \
+ GTEST_LOG_(FATAL) << "Condition " #condition " failed. "
+#endif // !defined(GTEST_CHECK_)
+
+// An all-mode assert to verify that the given POSIX-style function
+// call returns 0 (indicating success). Known limitation: this
+// doesn't expand to a balanced 'if' statement, so enclose the macro
+// in {} if you need to use it as the only statement in an 'if'
+// branch.
+#define GTEST_CHECK_POSIX_SUCCESS_(posix_call) \
+ if (const int gtest_error = (posix_call)) \
+ GTEST_LOG_(FATAL) << #posix_call << "failed with error " \
+ << gtest_error
+
+// Transforms "T" into "const T&" according to standard reference collapsing
+// rules (this is only needed as a backport for C++98 compilers that do not
+// support reference collapsing). Specifically, it transforms:
+//
+// char ==> const char&
+// const char ==> const char&
+// char& ==> char&
+// const char& ==> const char&
+//
+// Note that the non-const reference will not have "const" added. This is
+// standard, and necessary so that "T" can always bind to "const T&".
+template <typename T>
+struct ConstRef { typedef const T& type; };
+template <typename T>
+struct ConstRef<T&> { typedef T& type; };
+
+// The argument T must depend on some template parameters.
+#define GTEST_REFERENCE_TO_CONST_(T) \
+ typename ::testing::internal::ConstRef<T>::type
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Use ImplicitCast_ as a safe version of static_cast for upcasting in
+// the type hierarchy (e.g. casting a Foo* to a SuperclassOfFoo* or a
+// const Foo*). When you use ImplicitCast_, the compiler checks that
+// the cast is safe. Such explicit ImplicitCast_s are necessary in
+// surprisingly many situations where C++ demands an exact type match
+// instead of an argument type convertable to a target type.
+//
+// The syntax for using ImplicitCast_ is the same as for static_cast:
+//
+// ImplicitCast_<ToType>(expr)
+//
+// ImplicitCast_ would have been part of the C++ standard library,
+// but the proposal was submitted too late. It will probably make
+// its way into the language in the future.
+//
+// This relatively ugly name is intentional. It prevents clashes with
+// similar functions users may have (e.g., implicit_cast). The internal
+// namespace alone is not enough because the function can be found by ADL.
+template<typename To>
+inline To ImplicitCast_(To x) { return x; }
+
+// When you upcast (that is, cast a pointer from type Foo to type
+// SuperclassOfFoo), it's fine to use ImplicitCast_<>, since upcasts
+// always succeed. When you downcast (that is, cast a pointer from
+// type Foo to type SubclassOfFoo), static_cast<> isn't safe, because
+// how do you know the pointer is really of type SubclassOfFoo? It
+// could be a bare Foo, or of type DifferentSubclassOfFoo. Thus,
+// when you downcast, you should use this macro. In debug mode, we
+// use dynamic_cast<> to double-check the downcast is legal (we die
+// if it's not). In normal mode, we do the efficient static_cast<>
+// instead. Thus, it's important to test in debug mode to make sure
+// the cast is legal!
+// This is the only place in the code we should use dynamic_cast<>.
+// In particular, you SHOULDN'T be using dynamic_cast<> in order to
+// do RTTI (eg code like this:
+// if (dynamic_cast<Subclass1>(foo)) HandleASubclass1Object(foo);
+// if (dynamic_cast<Subclass2>(foo)) HandleASubclass2Object(foo);
+// You should design the code some other way not to need this.
+//
+// This relatively ugly name is intentional. It prevents clashes with
+// similar functions users may have (e.g., down_cast). The internal
+// namespace alone is not enough because the function can be found by ADL.
+template<typename To, typename From> // use like this: DownCast_<T*>(foo);
+inline To DownCast_(From* f) { // so we only accept pointers
+ // Ensures that To is a sub-type of From *. This test is here only
+ // for compile-time type checking, and has no overhead in an
+ // optimized build at run-time, as it will be optimized away
+ // completely.
+ GTEST_INTENTIONAL_CONST_COND_PUSH_()
+ if (false) {
+ GTEST_INTENTIONAL_CONST_COND_POP_()
+ const To to = nullptr;
+ ::testing::internal::ImplicitCast_<From*>(to);
+ }
+
+#if GTEST_HAS_RTTI
+ // RTTI: debug mode only!
+ GTEST_CHECK_(f == nullptr || dynamic_cast<To>(f) != nullptr);
+#endif
+ return static_cast<To>(f);
+}
+
+// Downcasts the pointer of type Base to Derived.
+// Derived must be a subclass of Base. The parameter MUST
+// point to a class of type Derived, not any subclass of it.
+// When RTTI is available, the function performs a runtime
+// check to enforce this.
+template <class Derived, class Base>
+Derived* CheckedDowncastToActualType(Base* base) {
+#if GTEST_HAS_RTTI
+ GTEST_CHECK_(typeid(*base) == typeid(Derived));
+#endif
+
+#if GTEST_HAS_DOWNCAST_
+ return ::down_cast<Derived*>(base);
+#elif GTEST_HAS_RTTI
+ return dynamic_cast<Derived*>(base); // NOLINT
+#else
+ return static_cast<Derived*>(base); // Poor man's downcast.
+#endif
+}
+
+#if GTEST_HAS_STREAM_REDIRECTION
+
+// Defines the stderr capturer:
+// CaptureStdout - starts capturing stdout.
+// GetCapturedStdout - stops capturing stdout and returns the captured string.
+// CaptureStderr - starts capturing stderr.
+// GetCapturedStderr - stops capturing stderr and returns the captured string.
+//
+GTEST_API_ void CaptureStdout();
+GTEST_API_ std::string GetCapturedStdout();
+GTEST_API_ void CaptureStderr();
+GTEST_API_ std::string GetCapturedStderr();
+
+#endif // GTEST_HAS_STREAM_REDIRECTION
+// Returns the size (in bytes) of a file.
+GTEST_API_ size_t GetFileSize(FILE* file);
+
+// Reads the entire content of a file as a string.
+GTEST_API_ std::string ReadEntireFile(FILE* file);
+
+// All command line arguments.
+GTEST_API_ std::vector<std::string> GetArgvs();
+
+#if GTEST_HAS_DEATH_TEST
+
+std::vector<std::string> GetInjectableArgvs();
+// Deprecated: pass the args vector by value instead.
+void SetInjectableArgvs(const std::vector<std::string>* new_argvs);
+void SetInjectableArgvs(const std::vector<std::string>& new_argvs);
+void ClearInjectableArgvs();
+
+#endif // GTEST_HAS_DEATH_TEST
+
+// Defines synchronization primitives.
+#if GTEST_IS_THREADSAFE
+# if GTEST_HAS_PTHREAD
+// Sleeps for (roughly) n milliseconds. This function is only for testing
+// Google Test's own constructs. Don't use it in user tests, either
+// directly or indirectly.
+inline void SleepMilliseconds(int n) {
+ const timespec time = {
+ 0, // 0 seconds.
+ n * 1000L * 1000L, // And n ms.
+ };
+ nanosleep(&time, nullptr);
+}
+# endif // GTEST_HAS_PTHREAD
+
+# if GTEST_HAS_NOTIFICATION_
+// Notification has already been imported into the namespace.
+// Nothing to do here.
+
+# elif GTEST_HAS_PTHREAD
+// Allows a controller thread to pause execution of newly created
+// threads until notified. Instances of this class must be created
+// and destroyed in the controller thread.
+//
+// This class is only for testing Google Test's own constructs. Do not
+// use it in user tests, either directly or indirectly.
+class Notification {
+ public:
+ Notification() : notified_(false) {
+ GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, nullptr));
+ }
+ ~Notification() {
+ pthread_mutex_destroy(&mutex_);
+ }
+
+ // Notifies all threads created with this notification to start. Must
+ // be called from the controller thread.
+ void Notify() {
+ pthread_mutex_lock(&mutex_);
+ notified_ = true;
+ pthread_mutex_unlock(&mutex_);
+ }
+
+ // Blocks until the controller thread notifies. Must be called from a test
+ // thread.
+ void WaitForNotification() {
+ for (;;) {
+ pthread_mutex_lock(&mutex_);
+ const bool notified = notified_;
+ pthread_mutex_unlock(&mutex_);
+ if (notified)
+ break;
+ SleepMilliseconds(10);
+ }
+ }
+
+ private:
+ pthread_mutex_t mutex_;
+ bool notified_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification);
+};
+
+# elif GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT
+
+GTEST_API_ void SleepMilliseconds(int n);
+
+// Provides leak-safe Windows kernel handle ownership.
+// Used in death tests and in threading support.
+class GTEST_API_ AutoHandle {
+ public:
+ // Assume that Win32 HANDLE type is equivalent to void*. Doing so allows us to
+ // avoid including <windows.h> in this header file. Including <windows.h> is
+ // undesirable because it defines a lot of symbols and macros that tend to
+ // conflict with client code. This assumption is verified by
+ // WindowsTypesTest.HANDLEIsVoidStar.
+ typedef void* Handle;
+ AutoHandle();
+ explicit AutoHandle(Handle handle);
+
+ ~AutoHandle();
+
+ Handle Get() const;
+ void Reset();
+ void Reset(Handle handle);
+
+ private:
+ // Returns true if and only if the handle is a valid handle object that can be
+ // closed.
+ bool IsCloseable() const;
+
+ Handle handle_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(AutoHandle);
+};
+
+// Allows a controller thread to pause execution of newly created
+// threads until notified. Instances of this class must be created
+// and destroyed in the controller thread.
+//
+// This class is only for testing Google Test's own constructs. Do not
+// use it in user tests, either directly or indirectly.
+class GTEST_API_ Notification {
+ public:
+ Notification();
+ void Notify();
+ void WaitForNotification();
+
+ private:
+ AutoHandle event_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification);
+};
+# endif // GTEST_HAS_NOTIFICATION_
+
+// On MinGW, we can have both GTEST_OS_WINDOWS and GTEST_HAS_PTHREAD
+// defined, but we don't want to use MinGW's pthreads implementation, which
+// has conformance problems with some versions of the POSIX standard.
+# if GTEST_HAS_PTHREAD && !GTEST_OS_WINDOWS_MINGW
+
+// As a C-function, ThreadFuncWithCLinkage cannot be templated itself.
+// Consequently, it cannot select a correct instantiation of ThreadWithParam
+// in order to call its Run(). Introducing ThreadWithParamBase as a
+// non-templated base class for ThreadWithParam allows us to bypass this
+// problem.
+class ThreadWithParamBase {
+ public:
+ virtual ~ThreadWithParamBase() {}
+ virtual void Run() = 0;
+};
+
+// pthread_create() accepts a pointer to a function type with the C linkage.
+// According to the Standard (7.5/1), function types with different linkages
+// are different even if they are otherwise identical. Some compilers (for
+// example, SunStudio) treat them as different types. Since class methods
+// cannot be defined with C-linkage we need to define a free C-function to
+// pass into pthread_create().
+extern "C" inline void* ThreadFuncWithCLinkage(void* thread) {
+ static_cast<ThreadWithParamBase*>(thread)->Run();
+ return nullptr;
+}
+
+// Helper class for testing Google Test's multi-threading constructs.
+// To use it, write:
+//
+// void ThreadFunc(int param) { /* Do things with param */ }
+// Notification thread_can_start;
+// ...
+// // The thread_can_start parameter is optional; you can supply NULL.
+// ThreadWithParam<int> thread(&ThreadFunc, 5, &thread_can_start);
+// thread_can_start.Notify();
+//
+// These classes are only for testing Google Test's own constructs. Do
+// not use them in user tests, either directly or indirectly.
+template <typename T>
+class ThreadWithParam : public ThreadWithParamBase {
+ public:
+ typedef void UserThreadFunc(T);
+
+ ThreadWithParam(UserThreadFunc* func, T param, Notification* thread_can_start)
+ : func_(func),
+ param_(param),
+ thread_can_start_(thread_can_start),
+ finished_(false) {
+ ThreadWithParamBase* const base = this;
+ // The thread can be created only after all fields except thread_
+ // have been initialized.
+ GTEST_CHECK_POSIX_SUCCESS_(
+ pthread_create(&thread_, nullptr, &ThreadFuncWithCLinkage, base));
+ }
+ ~ThreadWithParam() override { Join(); }
+
+ void Join() {
+ if (!finished_) {
+ GTEST_CHECK_POSIX_SUCCESS_(pthread_join(thread_, nullptr));
+ finished_ = true;
+ }
+ }
+
+ void Run() override {
+ if (thread_can_start_ != nullptr) thread_can_start_->WaitForNotification();
+ func_(param_);
+ }
+
+ private:
+ UserThreadFunc* const func_; // User-supplied thread function.
+ const T param_; // User-supplied parameter to the thread function.
+ // When non-NULL, used to block execution until the controller thread
+ // notifies.
+ Notification* const thread_can_start_;
+ bool finished_; // true if and only if we know that the thread function has
+ // finished.
+ pthread_t thread_; // The native thread object.
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParam);
+};
+# endif // !GTEST_OS_WINDOWS && GTEST_HAS_PTHREAD ||
+ // GTEST_HAS_MUTEX_AND_THREAD_LOCAL_
+
+# if GTEST_HAS_MUTEX_AND_THREAD_LOCAL_
+// Mutex and ThreadLocal have already been imported into the namespace.
+// Nothing to do here.
+
+# elif GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT
+
+// Mutex implements mutex on Windows platforms. It is used in conjunction
+// with class MutexLock:
+//
+// Mutex mutex;
+// ...
+// MutexLock lock(&mutex); // Acquires the mutex and releases it at the
+// // end of the current scope.
+//
+// A static Mutex *must* be defined or declared using one of the following
+// macros:
+// GTEST_DEFINE_STATIC_MUTEX_(g_some_mutex);
+// GTEST_DECLARE_STATIC_MUTEX_(g_some_mutex);
+//
+// (A non-static Mutex is defined/declared in the usual way).
+class GTEST_API_ Mutex {
+ public:
+ enum MutexType { kStatic = 0, kDynamic = 1 };
+ // We rely on kStaticMutex being 0 as it is to what the linker initializes
+ // type_ in static mutexes. critical_section_ will be initialized lazily
+ // in ThreadSafeLazyInit().
+ enum StaticConstructorSelector { kStaticMutex = 0 };
+
+ // This constructor intentionally does nothing. It relies on type_ being
+ // statically initialized to 0 (effectively setting it to kStatic) and on
+ // ThreadSafeLazyInit() to lazily initialize the rest of the members.
+ explicit Mutex(StaticConstructorSelector /*dummy*/) {}
+
+ Mutex();
+ ~Mutex();
+
+ void Lock();
+
+ void Unlock();
+
+ // Does nothing if the current thread holds the mutex. Otherwise, crashes
+ // with high probability.
+ void AssertHeld();
+
+ private:
+ // Initializes owner_thread_id_ and critical_section_ in static mutexes.
+ void ThreadSafeLazyInit();
+
+ // Per https://blogs.msdn.microsoft.com/oldnewthing/20040223-00/?p=40503,
+ // we assume that 0 is an invalid value for thread IDs.
+ unsigned int owner_thread_id_;
+
+ // For static mutexes, we rely on these members being initialized to zeros
+ // by the linker.
+ MutexType type_;
+ long critical_section_init_phase_; // NOLINT
+ GTEST_CRITICAL_SECTION* critical_section_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(Mutex);
+};
+
+# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \
+ extern ::testing::internal::Mutex mutex
+
+# define GTEST_DEFINE_STATIC_MUTEX_(mutex) \
+ ::testing::internal::Mutex mutex(::testing::internal::Mutex::kStaticMutex)
+
+// We cannot name this class MutexLock because the ctor declaration would
+// conflict with a macro named MutexLock, which is defined on some
+// platforms. That macro is used as a defensive measure to prevent against
+// inadvertent misuses of MutexLock like "MutexLock(&mu)" rather than
+// "MutexLock l(&mu)". Hence the typedef trick below.
+class GTestMutexLock {
+ public:
+ explicit GTestMutexLock(Mutex* mutex)
+ : mutex_(mutex) { mutex_->Lock(); }
+
+ ~GTestMutexLock() { mutex_->Unlock(); }
+
+ private:
+ Mutex* const mutex_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestMutexLock);
+};
+
+typedef GTestMutexLock MutexLock;
+
+// Base class for ValueHolder<T>. Allows a caller to hold and delete a value
+// without knowing its type.
+class ThreadLocalValueHolderBase {
+ public:
+ virtual ~ThreadLocalValueHolderBase() {}
+};
+
+// Provides a way for a thread to send notifications to a ThreadLocal
+// regardless of its parameter type.
+class ThreadLocalBase {
+ public:
+ // Creates a new ValueHolder<T> object holding a default value passed to
+ // this ThreadLocal<T>'s constructor and returns it. It is the caller's
+ // responsibility not to call this when the ThreadLocal<T> instance already
+ // has a value on the current thread.
+ virtual ThreadLocalValueHolderBase* NewValueForCurrentThread() const = 0;
+
+ protected:
+ ThreadLocalBase() {}
+ virtual ~ThreadLocalBase() {}
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocalBase);
+};
+
+// Maps a thread to a set of ThreadLocals that have values instantiated on that
+// thread and notifies them when the thread exits. A ThreadLocal instance is
+// expected to persist until all threads it has values on have terminated.
+class GTEST_API_ ThreadLocalRegistry {
+ public:
+ // Registers thread_local_instance as having value on the current thread.
+ // Returns a value that can be used to identify the thread from other threads.
+ static ThreadLocalValueHolderBase* GetValueOnCurrentThread(
+ const ThreadLocalBase* thread_local_instance);
+
+ // Invoked when a ThreadLocal instance is destroyed.
+ static void OnThreadLocalDestroyed(
+ const ThreadLocalBase* thread_local_instance);
+};
+
+class GTEST_API_ ThreadWithParamBase {
+ public:
+ void Join();
+
+ protected:
+ class Runnable {
+ public:
+ virtual ~Runnable() {}
+ virtual void Run() = 0;
+ };
+
+ ThreadWithParamBase(Runnable *runnable, Notification* thread_can_start);
+ virtual ~ThreadWithParamBase();
+
+ private:
+ AutoHandle thread_;
+};
+
+// Helper class for testing Google Test's multi-threading constructs.
+template <typename T>
+class ThreadWithParam : public ThreadWithParamBase {
+ public:
+ typedef void UserThreadFunc(T);
+
+ ThreadWithParam(UserThreadFunc* func, T param, Notification* thread_can_start)
+ : ThreadWithParamBase(new RunnableImpl(func, param), thread_can_start) {
+ }
+ virtual ~ThreadWithParam() {}
+
+ private:
+ class RunnableImpl : public Runnable {
+ public:
+ RunnableImpl(UserThreadFunc* func, T param)
+ : func_(func),
+ param_(param) {
+ }
+ virtual ~RunnableImpl() {}
+ virtual void Run() {
+ func_(param_);
+ }
+
+ private:
+ UserThreadFunc* const func_;
+ const T param_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(RunnableImpl);
+ };
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParam);
+};
+
+// Implements thread-local storage on Windows systems.
+//
+// // Thread 1
+// ThreadLocal<int> tl(100); // 100 is the default value for each thread.
+//
+// // Thread 2
+// tl.set(150); // Changes the value for thread 2 only.
+// EXPECT_EQ(150, tl.get());
+//
+// // Thread 1
+// EXPECT_EQ(100, tl.get()); // In thread 1, tl has the original value.
+// tl.set(200);
+// EXPECT_EQ(200, tl.get());
+//
+// The template type argument T must have a public copy constructor.
+// In addition, the default ThreadLocal constructor requires T to have
+// a public default constructor.
+//
+// The users of a TheadLocal instance have to make sure that all but one
+// threads (including the main one) using that instance have exited before
+// destroying it. Otherwise, the per-thread objects managed for them by the
+// ThreadLocal instance are not guaranteed to be destroyed on all platforms.
+//
+// Google Test only uses global ThreadLocal objects. That means they
+// will die after main() has returned. Therefore, no per-thread
+// object managed by Google Test will be leaked as long as all threads
+// using Google Test have exited when main() returns.
+template <typename T>
+class ThreadLocal : public ThreadLocalBase {
+ public:
+ ThreadLocal() : default_factory_(new DefaultValueHolderFactory()) {}
+ explicit ThreadLocal(const T& value)
+ : default_factory_(new InstanceValueHolderFactory(value)) {}
+
+ ~ThreadLocal() { ThreadLocalRegistry::OnThreadLocalDestroyed(this); }
+
+ T* pointer() { return GetOrCreateValue(); }
+ const T* pointer() const { return GetOrCreateValue(); }
+ const T& get() const { return *pointer(); }
+ void set(const T& value) { *pointer() = value; }
+
+ private:
+ // Holds a value of T. Can be deleted via its base class without the caller
+ // knowing the type of T.
+ class ValueHolder : public ThreadLocalValueHolderBase {
+ public:
+ ValueHolder() : value_() {}
+ explicit ValueHolder(const T& value) : value_(value) {}
+
+ T* pointer() { return &value_; }
+
+ private:
+ T value_;
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolder);
+ };
+
+
+ T* GetOrCreateValue() const {
+ return static_cast<ValueHolder*>(
+ ThreadLocalRegistry::GetValueOnCurrentThread(this))->pointer();
+ }
+
+ virtual ThreadLocalValueHolderBase* NewValueForCurrentThread() const {
+ return default_factory_->MakeNewHolder();
+ }
+
+ class ValueHolderFactory {
+ public:
+ ValueHolderFactory() {}
+ virtual ~ValueHolderFactory() {}
+ virtual ValueHolder* MakeNewHolder() const = 0;
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolderFactory);
+ };
+
+ class DefaultValueHolderFactory : public ValueHolderFactory {
+ public:
+ DefaultValueHolderFactory() {}
+ ValueHolder* MakeNewHolder() const override { return new ValueHolder(); }
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultValueHolderFactory);
+ };
+
+ class InstanceValueHolderFactory : public ValueHolderFactory {
+ public:
+ explicit InstanceValueHolderFactory(const T& value) : value_(value) {}
+ ValueHolder* MakeNewHolder() const override {
+ return new ValueHolder(value_);
+ }
+
+ private:
+ const T value_; // The value for each thread.
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(InstanceValueHolderFactory);
+ };
+
+ std::unique_ptr<ValueHolderFactory> default_factory_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal);
+};
+
+# elif GTEST_HAS_PTHREAD
+
+// MutexBase and Mutex implement mutex on pthreads-based platforms.
+class MutexBase {
+ public:
+ // Acquires this mutex.
+ void Lock() {
+ GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_lock(&mutex_));
+ owner_ = pthread_self();
+ has_owner_ = true;
+ }
+
+ // Releases this mutex.
+ void Unlock() {
+ // Since the lock is being released the owner_ field should no longer be
+ // considered valid. We don't protect writing to has_owner_ here, as it's
+ // the caller's responsibility to ensure that the current thread holds the
+ // mutex when this is called.
+ has_owner_ = false;
+ GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_unlock(&mutex_));
+ }
+
+ // Does nothing if the current thread holds the mutex. Otherwise, crashes
+ // with high probability.
+ void AssertHeld() const {
+ GTEST_CHECK_(has_owner_ && pthread_equal(owner_, pthread_self()))
+ << "The current thread is not holding the mutex @" << this;
+ }
+
+ // A static mutex may be used before main() is entered. It may even
+ // be used before the dynamic initialization stage. Therefore we
+ // must be able to initialize a static mutex object at link time.
+ // This means MutexBase has to be a POD and its member variables
+ // have to be public.
+ public:
+ pthread_mutex_t mutex_; // The underlying pthread mutex.
+ // has_owner_ indicates whether the owner_ field below contains a valid thread
+ // ID and is therefore safe to inspect (e.g., to use in pthread_equal()). All
+ // accesses to the owner_ field should be protected by a check of this field.
+ // An alternative might be to memset() owner_ to all zeros, but there's no
+ // guarantee that a zero'd pthread_t is necessarily invalid or even different
+ // from pthread_self().
+ bool has_owner_;
+ pthread_t owner_; // The thread holding the mutex.
+};
+
+// Forward-declares a static mutex.
+# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \
+ extern ::testing::internal::MutexBase mutex
+
+// Defines and statically (i.e. at link time) initializes a static mutex.
+// The initialization list here does not explicitly initialize each field,
+// instead relying on default initialization for the unspecified fields. In
+// particular, the owner_ field (a pthread_t) is not explicitly initialized.
+// This allows initialization to work whether pthread_t is a scalar or struct.
+// The flag -Wmissing-field-initializers must not be specified for this to work.
+#define GTEST_DEFINE_STATIC_MUTEX_(mutex) \
+ ::testing::internal::MutexBase mutex = {PTHREAD_MUTEX_INITIALIZER, false, 0}
+
+// The Mutex class can only be used for mutexes created at runtime. It
+// shares its API with MutexBase otherwise.
+class Mutex : public MutexBase {
+ public:
+ Mutex() {
+ GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, nullptr));
+ has_owner_ = false;
+ }
+ ~Mutex() {
+ GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_destroy(&mutex_));
+ }
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(Mutex);
+};
+
+// We cannot name this class MutexLock because the ctor declaration would
+// conflict with a macro named MutexLock, which is defined on some
+// platforms. That macro is used as a defensive measure to prevent against
+// inadvertent misuses of MutexLock like "MutexLock(&mu)" rather than
+// "MutexLock l(&mu)". Hence the typedef trick below.
+class GTestMutexLock {
+ public:
+ explicit GTestMutexLock(MutexBase* mutex)
+ : mutex_(mutex) { mutex_->Lock(); }
+
+ ~GTestMutexLock() { mutex_->Unlock(); }
+
+ private:
+ MutexBase* const mutex_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestMutexLock);
+};
+
+typedef GTestMutexLock MutexLock;
+
+// Helpers for ThreadLocal.
+
+// pthread_key_create() requires DeleteThreadLocalValue() to have
+// C-linkage. Therefore it cannot be templatized to access
+// ThreadLocal<T>. Hence the need for class
+// ThreadLocalValueHolderBase.
+class ThreadLocalValueHolderBase {
+ public:
+ virtual ~ThreadLocalValueHolderBase() {}
+};
+
+// Called by pthread to delete thread-local data stored by
+// pthread_setspecific().
+extern "C" inline void DeleteThreadLocalValue(void* value_holder) {
+ delete static_cast<ThreadLocalValueHolderBase*>(value_holder);
+}
+
+// Implements thread-local storage on pthreads-based systems.
+template <typename T>
+class GTEST_API_ ThreadLocal {
+ public:
+ ThreadLocal()
+ : key_(CreateKey()), default_factory_(new DefaultValueHolderFactory()) {}
+ explicit ThreadLocal(const T& value)
+ : key_(CreateKey()),
+ default_factory_(new InstanceValueHolderFactory(value)) {}
+
+ ~ThreadLocal() {
+ // Destroys the managed object for the current thread, if any.
+ DeleteThreadLocalValue(pthread_getspecific(key_));
+
+ // Releases resources associated with the key. This will *not*
+ // delete managed objects for other threads.
+ GTEST_CHECK_POSIX_SUCCESS_(pthread_key_delete(key_));
+ }
+
+ T* pointer() { return GetOrCreateValue(); }
+ const T* pointer() const { return GetOrCreateValue(); }
+ const T& get() const { return *pointer(); }
+ void set(const T& value) { *pointer() = value; }
+
+ private:
+ // Holds a value of type T.
+ class ValueHolder : public ThreadLocalValueHolderBase {
+ public:
+ ValueHolder() : value_() {}
+ explicit ValueHolder(const T& value) : value_(value) {}
+
+ T* pointer() { return &value_; }
+
+ private:
+ T value_;
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolder);
+ };
+
+ static pthread_key_t CreateKey() {
+ pthread_key_t key;
+ // When a thread exits, DeleteThreadLocalValue() will be called on
+ // the object managed for that thread.
+ GTEST_CHECK_POSIX_SUCCESS_(
+ pthread_key_create(&key, &DeleteThreadLocalValue));
+ return key;
+ }
+
+ T* GetOrCreateValue() const {
+ ThreadLocalValueHolderBase* const holder =
+ static_cast<ThreadLocalValueHolderBase*>(pthread_getspecific(key_));
+ if (holder != nullptr) {
+ return CheckedDowncastToActualType<ValueHolder>(holder)->pointer();
+ }
+
+ ValueHolder* const new_holder = default_factory_->MakeNewHolder();
+ ThreadLocalValueHolderBase* const holder_base = new_holder;
+ GTEST_CHECK_POSIX_SUCCESS_(pthread_setspecific(key_, holder_base));
+ return new_holder->pointer();
+ }
+
+ class ValueHolderFactory {
+ public:
+ ValueHolderFactory() {}
+ virtual ~ValueHolderFactory() {}
+ virtual ValueHolder* MakeNewHolder() const = 0;
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolderFactory);
+ };
+
+ class DefaultValueHolderFactory : public ValueHolderFactory {
+ public:
+ DefaultValueHolderFactory() {}
+ ValueHolder* MakeNewHolder() const override { return new ValueHolder(); }
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultValueHolderFactory);
+ };
+
+ class InstanceValueHolderFactory : public ValueHolderFactory {
+ public:
+ explicit InstanceValueHolderFactory(const T& value) : value_(value) {}
+ ValueHolder* MakeNewHolder() const override {
+ return new ValueHolder(value_);
+ }
+
+ private:
+ const T value_; // The value for each thread.
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(InstanceValueHolderFactory);
+ };
+
+ // A key pthreads uses for looking up per-thread values.
+ const pthread_key_t key_;
+ std::unique_ptr<ValueHolderFactory> default_factory_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal);
+};
+
+# endif // GTEST_HAS_MUTEX_AND_THREAD_LOCAL_
+
+#else // GTEST_IS_THREADSAFE
+
+// A dummy implementation of synchronization primitives (mutex, lock,
+// and thread-local variable). Necessary for compiling Google Test where
+// mutex is not supported - using Google Test in multiple threads is not
+// supported on such platforms.
+
+class Mutex {
+ public:
+ Mutex() {}
+ void Lock() {}
+ void Unlock() {}
+ void AssertHeld() const {}
+};
+
+# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \
+ extern ::testing::internal::Mutex mutex
+
+# define GTEST_DEFINE_STATIC_MUTEX_(mutex) ::testing::internal::Mutex mutex
+
+// We cannot name this class MutexLock because the ctor declaration would
+// conflict with a macro named MutexLock, which is defined on some
+// platforms. That macro is used as a defensive measure to prevent against
+// inadvertent misuses of MutexLock like "MutexLock(&mu)" rather than
+// "MutexLock l(&mu)". Hence the typedef trick below.
+class GTestMutexLock {
+ public:
+ explicit GTestMutexLock(Mutex*) {} // NOLINT
+};
+
+typedef GTestMutexLock MutexLock;
+
+template <typename T>
+class GTEST_API_ ThreadLocal {
+ public:
+ ThreadLocal() : value_() {}
+ explicit ThreadLocal(const T& value) : value_(value) {}
+ T* pointer() { return &value_; }
+ const T* pointer() const { return &value_; }
+ const T& get() const { return value_; }
+ void set(const T& value) { value_ = value; }
+ private:
+ T value_;
+};
+
+#endif // GTEST_IS_THREADSAFE
+
+// Returns the number of threads running in the process, or 0 to indicate that
+// we cannot detect it.
+GTEST_API_ size_t GetThreadCount();
+
+#if GTEST_OS_WINDOWS
+# define GTEST_PATH_SEP_ "\\"
+# define GTEST_HAS_ALT_PATH_SEP_ 1
+#else
+# define GTEST_PATH_SEP_ "/"
+# define GTEST_HAS_ALT_PATH_SEP_ 0
+#endif // GTEST_OS_WINDOWS
+
+// Utilities for char.
+
+// isspace(int ch) and friends accept an unsigned char or EOF. char
+// may be signed, depending on the compiler (or compiler flags).
+// Therefore we need to cast a char to unsigned char before calling
+// isspace(), etc.
+
+inline bool IsAlpha(char ch) {
+ return isalpha(static_cast<unsigned char>(ch)) != 0;
+}
+inline bool IsAlNum(char ch) {
+ return isalnum(static_cast<unsigned char>(ch)) != 0;
+}
+inline bool IsDigit(char ch) {
+ return isdigit(static_cast<unsigned char>(ch)) != 0;
+}
+inline bool IsLower(char ch) {
+ return islower(static_cast<unsigned char>(ch)) != 0;
+}
+inline bool IsSpace(char ch) {
+ return isspace(static_cast<unsigned char>(ch)) != 0;
+}
+inline bool IsUpper(char ch) {
+ return isupper(static_cast<unsigned char>(ch)) != 0;
+}
+inline bool IsXDigit(char ch) {
+ return isxdigit(static_cast<unsigned char>(ch)) != 0;
+}
+#ifdef __cpp_char8_t
+inline bool IsXDigit(char8_t ch) {
+ return isxdigit(static_cast<unsigned char>(ch)) != 0;
+}
+#endif
+inline bool IsXDigit(char16_t ch) {
+ const unsigned char low_byte = static_cast<unsigned char>(ch);
+ return ch == low_byte && isxdigit(low_byte) != 0;
+}
+inline bool IsXDigit(char32_t ch) {
+ const unsigned char low_byte = static_cast<unsigned char>(ch);
+ return ch == low_byte && isxdigit(low_byte) != 0;
+}
+inline bool IsXDigit(wchar_t ch) {
+ const unsigned char low_byte = static_cast<unsigned char>(ch);
+ return ch == low_byte && isxdigit(low_byte) != 0;
+}
+
+inline char ToLower(char ch) {
+ return static_cast<char>(tolower(static_cast<unsigned char>(ch)));
+}
+inline char ToUpper(char ch) {
+ return static_cast<char>(toupper(static_cast<unsigned char>(ch)));
+}
+
+inline std::string StripTrailingSpaces(std::string str) {
+ std::string::iterator it = str.end();
+ while (it != str.begin() && IsSpace(*--it))
+ it = str.erase(it);
+ return str;
+}
+
+// The testing::internal::posix namespace holds wrappers for common
+// POSIX functions. These wrappers hide the differences between
+// Windows/MSVC and POSIX systems. Since some compilers define these
+// standard functions as macros, the wrapper cannot have the same name
+// as the wrapped function.
+
+namespace posix {
+
+// Functions with a different name on Windows.
+
+#if GTEST_OS_WINDOWS
+
+typedef struct _stat StatStruct;
+
+# ifdef __BORLANDC__
+inline int DoIsATTY(int fd) { return isatty(fd); }
+inline int StrCaseCmp(const char* s1, const char* s2) {
+ return stricmp(s1, s2);
+}
+inline char* StrDup(const char* src) { return strdup(src); }
+# else // !__BORLANDC__
+# if GTEST_OS_WINDOWS_MOBILE
+inline int DoIsATTY(int /* fd */) { return 0; }
+# else
+inline int DoIsATTY(int fd) { return _isatty(fd); }
+# endif // GTEST_OS_WINDOWS_MOBILE
+inline int StrCaseCmp(const char* s1, const char* s2) {
+ return _stricmp(s1, s2);
+}
+inline char* StrDup(const char* src) { return _strdup(src); }
+# endif // __BORLANDC__
+
+# if GTEST_OS_WINDOWS_MOBILE
+inline int FileNo(FILE* file) { return reinterpret_cast<int>(_fileno(file)); }
+// Stat(), RmDir(), and IsDir() are not needed on Windows CE at this
+// time and thus not defined there.
+# else
+inline int FileNo(FILE* file) { return _fileno(file); }
+inline int Stat(const char* path, StatStruct* buf) { return _stat(path, buf); }
+inline int RmDir(const char* dir) { return _rmdir(dir); }
+inline bool IsDir(const StatStruct& st) {
+ return (_S_IFDIR & st.st_mode) != 0;
+}
+# endif // GTEST_OS_WINDOWS_MOBILE
+
+#elif GTEST_OS_ESP8266
+typedef struct stat StatStruct;
+
+inline int FileNo(FILE* file) { return fileno(file); }
+inline int DoIsATTY(int fd) { return isatty(fd); }
+inline int Stat(const char* path, StatStruct* buf) {
+ // stat function not implemented on ESP8266
+ return 0;
+}
+inline int StrCaseCmp(const char* s1, const char* s2) {
+ return strcasecmp(s1, s2);
+}
+inline char* StrDup(const char* src) { return strdup(src); }
+inline int RmDir(const char* dir) { return rmdir(dir); }
+inline bool IsDir(const StatStruct& st) { return S_ISDIR(st.st_mode); }
+
+#else
+
+typedef struct stat StatStruct;
+
+inline int FileNo(FILE* file) { return fileno(file); }
+inline int DoIsATTY(int fd) { return isatty(fd); }
+inline int Stat(const char* path, StatStruct* buf) { return stat(path, buf); }
+inline int StrCaseCmp(const char* s1, const char* s2) {
+ return strcasecmp(s1, s2);
+}
+inline char* StrDup(const char* src) { return strdup(src); }
+inline int RmDir(const char* dir) { return rmdir(dir); }
+inline bool IsDir(const StatStruct& st) { return S_ISDIR(st.st_mode); }
+
+#endif // GTEST_OS_WINDOWS
+
+inline int IsATTY(int fd) {
+ // DoIsATTY might change errno (for example ENOTTY in case you redirect stdout
+ // to a file on Linux), which is unexpected, so save the previous value, and
+ // restore it after the call.
+ int savedErrno = errno;
+ int isAttyValue = DoIsATTY(fd);
+ errno = savedErrno;
+
+ return isAttyValue;
+}
+
+// Functions deprecated by MSVC 8.0.
+
+GTEST_DISABLE_MSC_DEPRECATED_PUSH_()
+
+// ChDir(), FReopen(), FDOpen(), Read(), Write(), Close(), and
+// StrError() aren't needed on Windows CE at this time and thus not
+// defined there.
+
+#if !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_WINDOWS_PHONE && \
+ !GTEST_OS_WINDOWS_RT && !GTEST_OS_ESP8266 && !GTEST_OS_XTENSA
+inline int ChDir(const char* dir) { return chdir(dir); }
+#endif
+inline FILE* FOpen(const char* path, const char* mode) {
+#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MINGW
+ struct wchar_codecvt : public std::codecvt<wchar_t, char, std::mbstate_t> {};
+ std::wstring_convert<wchar_codecvt> converter;
+ std::wstring wide_path = converter.from_bytes(path);
+ std::wstring wide_mode = converter.from_bytes(mode);
+ return _wfopen(wide_path.c_str(), wide_mode.c_str());
+#else // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MINGW
+ return fopen(path, mode);
+#endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MINGW
+}
+#if !GTEST_OS_WINDOWS_MOBILE
+inline FILE *FReopen(const char* path, const char* mode, FILE* stream) {
+ return freopen(path, mode, stream);
+}
+inline FILE* FDOpen(int fd, const char* mode) { return fdopen(fd, mode); }
+#endif
+inline int FClose(FILE* fp) { return fclose(fp); }
+#if !GTEST_OS_WINDOWS_MOBILE
+inline int Read(int fd, void* buf, unsigned int count) {
+ return static_cast<int>(read(fd, buf, count));
+}
+inline int Write(int fd, const void* buf, unsigned int count) {
+ return static_cast<int>(write(fd, buf, count));
+}
+inline int Close(int fd) { return close(fd); }
+inline const char* StrError(int errnum) { return strerror(errnum); }
+#endif
+inline const char* GetEnv(const char* name) {
+#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || \
+ GTEST_OS_WINDOWS_RT || GTEST_OS_ESP8266 || GTEST_OS_XTENSA
+ // We are on an embedded platform, which has no environment variables.
+ static_cast<void>(name); // To prevent 'unused argument' warning.
+ return nullptr;
+#elif defined(__BORLANDC__) || defined(__SunOS_5_8) || defined(__SunOS_5_9)
+ // Environment variables which we programmatically clear will be set to the
+ // empty string rather than unset (NULL). Handle that case.
+ const char* const env = getenv(name);
+ return (env != nullptr && env[0] != '\0') ? env : nullptr;
+#else
+ return getenv(name);
+#endif
+}
+
+GTEST_DISABLE_MSC_DEPRECATED_POP_()
+
+#if GTEST_OS_WINDOWS_MOBILE
+// Windows CE has no C library. The abort() function is used in
+// several places in Google Test. This implementation provides a reasonable
+// imitation of standard behaviour.
+[[noreturn]] void Abort();
+#else
+[[noreturn]] inline void Abort() { abort(); }
+#endif // GTEST_OS_WINDOWS_MOBILE
+
+} // namespace posix
+
+// MSVC "deprecates" snprintf and issues warnings wherever it is used. In
+// order to avoid these warnings, we need to use _snprintf or _snprintf_s on
+// MSVC-based platforms. We map the GTEST_SNPRINTF_ macro to the appropriate
+// function in order to achieve that. We use macro definition here because
+// snprintf is a variadic function.
+#if _MSC_VER && !GTEST_OS_WINDOWS_MOBILE
+// MSVC 2005 and above support variadic macros.
+# define GTEST_SNPRINTF_(buffer, size, format, ...) \
+ _snprintf_s(buffer, size, size, format, __VA_ARGS__)
+#elif defined(_MSC_VER)
+// Windows CE does not define _snprintf_s
+# define GTEST_SNPRINTF_ _snprintf
+#else
+# define GTEST_SNPRINTF_ snprintf
+#endif
+
+// The biggest signed integer type the compiler supports.
+//
+// long long is guaranteed to be at least 64-bits in C++11.
+using BiggestInt = long long; // NOLINT
+
+// The maximum number a BiggestInt can represent.
+constexpr BiggestInt kMaxBiggestInt = (std::numeric_limits<BiggestInt>::max)();
+
+// This template class serves as a compile-time function from size to
+// type. It maps a size in bytes to a primitive type with that
+// size. e.g.
+//
+// TypeWithSize<4>::UInt
+//
+// is typedef-ed to be unsigned int (unsigned integer made up of 4
+// bytes).
+//
+// Such functionality should belong to STL, but I cannot find it
+// there.
+//
+// Google Test uses this class in the implementation of floating-point
+// comparison.
+//
+// For now it only handles UInt (unsigned int) as that's all Google Test
+// needs. Other types can be easily added in the future if need
+// arises.
+template <size_t size>
+class TypeWithSize {
+ public:
+ // This prevents the user from using TypeWithSize<N> with incorrect
+ // values of N.
+ using UInt = void;
+};
+
+// The specialization for size 4.
+template <>
+class TypeWithSize<4> {
+ public:
+ using Int = std::int32_t;
+ using UInt = std::uint32_t;
+};
+
+// The specialization for size 8.
+template <>
+class TypeWithSize<8> {
+ public:
+ using Int = std::int64_t;
+ using UInt = std::uint64_t;
+};
+
+// Integer types of known sizes.
+using TimeInMillis = int64_t; // Represents time in milliseconds.
+
+// Utilities for command line flags and environment variables.
+
+// Macro for referencing flags.
+#if !defined(GTEST_FLAG)
+# define GTEST_FLAG(name) FLAGS_gtest_##name
+#endif // !defined(GTEST_FLAG)
+
+#if !defined(GTEST_USE_OWN_FLAGFILE_FLAG_)
+# define GTEST_USE_OWN_FLAGFILE_FLAG_ 1
+#endif // !defined(GTEST_USE_OWN_FLAGFILE_FLAG_)
+
+#if !defined(GTEST_DECLARE_bool_)
+# define GTEST_FLAG_SAVER_ ::testing::internal::GTestFlagSaver
+
+// Macros for declaring flags.
+# define GTEST_DECLARE_bool_(name) GTEST_API_ extern bool GTEST_FLAG(name)
+# define GTEST_DECLARE_int32_(name) \
+ GTEST_API_ extern std::int32_t GTEST_FLAG(name)
+# define GTEST_DECLARE_string_(name) \
+ GTEST_API_ extern ::std::string GTEST_FLAG(name)
+
+// Macros for defining flags.
+# define GTEST_DEFINE_bool_(name, default_val, doc) \
+ GTEST_API_ bool GTEST_FLAG(name) = (default_val)
+# define GTEST_DEFINE_int32_(name, default_val, doc) \
+ GTEST_API_ std::int32_t GTEST_FLAG(name) = (default_val)
+# define GTEST_DEFINE_string_(name, default_val, doc) \
+ GTEST_API_ ::std::string GTEST_FLAG(name) = (default_val)
+
+#endif // !defined(GTEST_DECLARE_bool_)
+
+// Thread annotations
+#if !defined(GTEST_EXCLUSIVE_LOCK_REQUIRED_)
+# define GTEST_EXCLUSIVE_LOCK_REQUIRED_(locks)
+# define GTEST_LOCK_EXCLUDED_(locks)
+#endif // !defined(GTEST_EXCLUSIVE_LOCK_REQUIRED_)
+
+// Parses 'str' for a 32-bit signed integer. If successful, writes the result
+// to *value and returns true; otherwise leaves *value unchanged and returns
+// false.
+GTEST_API_ bool ParseInt32(const Message& src_text, const char* str,
+ int32_t* value);
+
+// Parses a bool/int32_t/string from the environment variable
+// corresponding to the given Google Test flag.
+bool BoolFromGTestEnv(const char* flag, bool default_val);
+GTEST_API_ int32_t Int32FromGTestEnv(const char* flag, int32_t default_val);
+std::string OutputFlagAlsoCheckEnvVar();
+const char* StringFromGTestEnv(const char* flag, const char* default_val);
+
+} // namespace internal
+} // namespace testing
+
+#if !defined(GTEST_INTERNAL_DEPRECATED)
+
+// Internal Macro to mark an API deprecated, for googletest usage only
+// Usage: class GTEST_INTERNAL_DEPRECATED(message) MyClass or
+// GTEST_INTERNAL_DEPRECATED(message) <return_type> myFunction(); Every usage of
+// a deprecated entity will trigger a warning when compiled with
+// `-Wdeprecated-declarations` option (clang, gcc, any __GNUC__ compiler).
+// For msvc /W3 option will need to be used
+// Note that for 'other' compilers this macro evaluates to nothing to prevent
+// compilations errors.
+#if defined(_MSC_VER)
+#define GTEST_INTERNAL_DEPRECATED(message) __declspec(deprecated(message))
+#elif defined(__GNUC__)
+#define GTEST_INTERNAL_DEPRECATED(message) __attribute__((deprecated(message)))
+#else
+#define GTEST_INTERNAL_DEPRECATED(message)
+#endif
+
+#endif // !defined(GTEST_INTERNAL_DEPRECATED)
+
+#if GTEST_HAS_ABSL
+// Always use absl::any for UniversalPrinter<> specializations if googletest
+// is built with absl support.
+#define GTEST_INTERNAL_HAS_ANY 1
+#include "absl/types/any.h"
+namespace testing {
+namespace internal {
+using Any = ::absl::any;
+} // namespace internal
+} // namespace testing
+#else
+#ifdef __has_include
+#if __has_include(<any>) && __cplusplus >= 201703L
+// Otherwise for C++17 and higher use std::any for UniversalPrinter<>
+// specializations.
+#define GTEST_INTERNAL_HAS_ANY 1
+#include <any>
+namespace testing {
+namespace internal {
+using Any = ::std::any;
+} // namespace internal
+} // namespace testing
+// The case where absl is configured NOT to alias std::any is not
+// supported.
+#endif // __has_include(<any>) && __cplusplus >= 201703L
+#endif // __has_include
+#endif // GTEST_HAS_ABSL
+
+#if GTEST_HAS_ABSL
+// Always use absl::optional for UniversalPrinter<> specializations if
+// googletest is built with absl support.
+#define GTEST_INTERNAL_HAS_OPTIONAL 1
+#include "absl/types/optional.h"
+namespace testing {
+namespace internal {
+template <typename T>
+using Optional = ::absl::optional<T>;
+} // namespace internal
+} // namespace testing
+#else
+#ifdef __has_include
+#if __has_include(<optional>) && __cplusplus >= 201703L
+// Otherwise for C++17 and higher use std::optional for UniversalPrinter<>
+// specializations.
+#define GTEST_INTERNAL_HAS_OPTIONAL 1
+#include <optional>
+namespace testing {
+namespace internal {
+template <typename T>
+using Optional = ::std::optional<T>;
+} // namespace internal
+} // namespace testing
+// The case where absl is configured NOT to alias std::optional is not
+// supported.
+#endif // __has_include(<optional>) && __cplusplus >= 201703L
+#endif // __has_include
+#endif // GTEST_HAS_ABSL
+
+#if GTEST_HAS_ABSL
+// Always use absl::string_view for Matcher<> specializations if googletest
+// is built with absl support.
+# define GTEST_INTERNAL_HAS_STRING_VIEW 1
+#include "absl/strings/string_view.h"
+namespace testing {
+namespace internal {
+using StringView = ::absl::string_view;
+} // namespace internal
+} // namespace testing
+#else
+# ifdef __has_include
+# if __has_include(<string_view>) && __cplusplus >= 201703L
+// Otherwise for C++17 and higher use std::string_view for Matcher<>
+// specializations.
+# define GTEST_INTERNAL_HAS_STRING_VIEW 1
+#include <string_view>
+namespace testing {
+namespace internal {
+using StringView = ::std::string_view;
+} // namespace internal
+} // namespace testing
+// The case where absl is configured NOT to alias std::string_view is not
+// supported.
+# endif // __has_include(<string_view>) && __cplusplus >= 201703L
+# endif // __has_include
+#endif // GTEST_HAS_ABSL
+
+#if GTEST_HAS_ABSL
+// Always use absl::variant for UniversalPrinter<> specializations if googletest
+// is built with absl support.
+#define GTEST_INTERNAL_HAS_VARIANT 1
+#include "absl/types/variant.h"
+namespace testing {
+namespace internal {
+template <typename... T>
+using Variant = ::absl::variant<T...>;
+} // namespace internal
+} // namespace testing
+#else
+#ifdef __has_include
+#if __has_include(<variant>) && __cplusplus >= 201703L
+// Otherwise for C++17 and higher use std::variant for UniversalPrinter<>
+// specializations.
+#define GTEST_INTERNAL_HAS_VARIANT 1
+#include <variant>
+namespace testing {
+namespace internal {
+template <typename... T>
+using Variant = ::std::variant<T...>;
+} // namespace internal
+} // namespace testing
+// The case where absl is configured NOT to alias std::variant is not supported.
+#endif // __has_include(<variant>) && __cplusplus >= 201703L
+#endif // __has_include
+#endif // GTEST_HAS_ABSL
+
+#endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_
+
+#if GTEST_OS_LINUX
+# include <stdlib.h>
+# include <sys/types.h>
+# include <sys/wait.h>
+# include <unistd.h>
+#endif // GTEST_OS_LINUX
+
+#if GTEST_HAS_EXCEPTIONS
+# include <stdexcept>
+#endif
+
+#include <ctype.h>
+#include <float.h>
+#include <string.h>
+#include <cstdint>
+#include <iomanip>
+#include <limits>
+#include <map>
+#include <set>
+#include <string>
+#include <type_traits>
+#include <vector>
+
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+//
+// The Google C++ Testing and Mocking Framework (Google Test)
+//
+// This header file defines the Message class.
+//
+// IMPORTANT NOTE: Due to limitation of the C++ language, we have to
+// leave some internal implementation details in this header file.
+// They are clearly marked by comments like this:
+//
+// // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+//
+// Such code is NOT meant to be used by a user directly, and is subject
+// to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user
+// program!
+
+// GOOGLETEST_CM0001 DO NOT DELETE
+
+#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
+#define GOOGLETEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
+
+#include <limits>
+#include <memory>
+#include <sstream>
+
+
+GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \
+/* class A needs to have dll-interface to be used by clients of class B */)
+
+// Ensures that there is at least one operator<< in the global namespace.
+// See Message& operator<<(...) below for why.
+void operator<<(const testing::internal::Secret&, int);
+
+namespace testing {
+
+// The Message class works like an ostream repeater.
+//
+// Typical usage:
+//
+// 1. You stream a bunch of values to a Message object.
+// It will remember the text in a stringstream.
+// 2. Then you stream the Message object to an ostream.
+// This causes the text in the Message to be streamed
+// to the ostream.
+//
+// For example;
+//
+// testing::Message foo;
+// foo << 1 << " != " << 2;
+// std::cout << foo;
+//
+// will print "1 != 2".
+//
+// Message is not intended to be inherited from. In particular, its
+// destructor is not virtual.
+//
+// Note that stringstream behaves differently in gcc and in MSVC. You
+// can stream a NULL char pointer to it in the former, but not in the
+// latter (it causes an access violation if you do). The Message
+// class hides this difference by treating a NULL char pointer as
+// "(null)".
+class GTEST_API_ Message {
+ private:
+ // The type of basic IO manipulators (endl, ends, and flush) for
+ // narrow streams.
+ typedef std::ostream& (*BasicNarrowIoManip)(std::ostream&);
+
+ public:
+ // Constructs an empty Message.
+ Message();
+
+ // Copy constructor.
+ Message(const Message& msg) : ss_(new ::std::stringstream) { // NOLINT
+ *ss_ << msg.GetString();
+ }
+
+ // Constructs a Message from a C-string.
+ explicit Message(const char* str) : ss_(new ::std::stringstream) {
+ *ss_ << str;
+ }
+
+ // Streams a non-pointer value to this object.
+ template <typename T>
+ inline Message& operator <<(const T& val) {
+ // Some libraries overload << for STL containers. These
+ // overloads are defined in the global namespace instead of ::std.
+ //
+ // C++'s symbol lookup rule (i.e. Koenig lookup) says that these
+ // overloads are visible in either the std namespace or the global
+ // namespace, but not other namespaces, including the testing
+ // namespace which Google Test's Message class is in.
+ //
+ // To allow STL containers (and other types that has a << operator
+ // defined in the global namespace) to be used in Google Test
+ // assertions, testing::Message must access the custom << operator
+ // from the global namespace. With this using declaration,
+ // overloads of << defined in the global namespace and those
+ // visible via Koenig lookup are both exposed in this function.
+ using ::operator <<;
+ *ss_ << val;
+ return *this;
+ }
+
+ // Streams a pointer value to this object.
+ //
+ // This function is an overload of the previous one. When you
+ // stream a pointer to a Message, this definition will be used as it
+ // is more specialized. (The C++ Standard, section
+ // [temp.func.order].) If you stream a non-pointer, then the
+ // previous definition will be used.
+ //
+ // The reason for this overload is that streaming a NULL pointer to
+ // ostream is undefined behavior. Depending on the compiler, you
+ // may get "0", "(nil)", "(null)", or an access violation. To
+ // ensure consistent result across compilers, we always treat NULL
+ // as "(null)".
+ template <typename T>
+ inline Message& operator <<(T* const& pointer) { // NOLINT
+ if (pointer == nullptr) {
+ *ss_ << "(null)";
+ } else {
+ *ss_ << pointer;
+ }
+ return *this;
+ }
+
+ // Since the basic IO manipulators are overloaded for both narrow
+ // and wide streams, we have to provide this specialized definition
+ // of operator <<, even though its body is the same as the
+ // templatized version above. Without this definition, streaming
+ // endl or other basic IO manipulators to Message will confuse the
+ // compiler.
+ Message& operator <<(BasicNarrowIoManip val) {
+ *ss_ << val;
+ return *this;
+ }
+
+ // Instead of 1/0, we want to see true/false for bool values.
+ Message& operator <<(bool b) {
+ return *this << (b ? "true" : "false");
+ }
+
+ // These two overloads allow streaming a wide C string to a Message
+ // using the UTF-8 encoding.
+ Message& operator <<(const wchar_t* wide_c_str);
+ Message& operator <<(wchar_t* wide_c_str);
+
+#if GTEST_HAS_STD_WSTRING
+ // Converts the given wide string to a narrow string using the UTF-8
+ // encoding, and streams the result to this Message object.
+ Message& operator <<(const ::std::wstring& wstr);
+#endif // GTEST_HAS_STD_WSTRING
+
+ // Gets the text streamed to this object so far as an std::string.
+ // Each '\0' character in the buffer is replaced with "\\0".
+ //
+ // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+ std::string GetString() const;
+
+ private:
+ // We'll hold the text streamed to this object here.
+ const std::unique_ptr< ::std::stringstream> ss_;
+
+ // We declare (but don't implement) this to prevent the compiler
+ // from implementing the assignment operator.
+ void operator=(const Message&);
+};
+
+// Streams a Message to an ostream.
+inline std::ostream& operator <<(std::ostream& os, const Message& sb) {
+ return os << sb.GetString();
+}
+
+namespace internal {
+
+// Converts a streamable value to an std::string. A NULL pointer is
+// converted to "(null)". When the input value is a ::string,
+// ::std::string, ::wstring, or ::std::wstring object, each NUL
+// character in it is replaced with "\\0".
+template <typename T>
+std::string StreamableToString(const T& streamable) {
+ return (Message() << streamable).GetString();
+}
+
+} // namespace internal
+} // namespace testing
+
+GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251
+
+#endif // GOOGLETEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Google Test filepath utilities
+//
+// This header file declares classes and functions used internally by
+// Google Test. They are subject to change without notice.
+//
+// This file is #included in gtest/internal/gtest-internal.h.
+// Do not include this header file separately!
+
+// GOOGLETEST_CM0001 DO NOT DELETE
+
+#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
+#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
+
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// The Google C++ Testing and Mocking Framework (Google Test)
+//
+// This header file declares the String class and functions used internally by
+// Google Test. They are subject to change without notice. They should not used
+// by code external to Google Test.
+//
+// This header file is #included by gtest-internal.h.
+// It should not be #included by other files.
+
+// GOOGLETEST_CM0001 DO NOT DELETE
+
+#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
+#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
+
+#ifdef __BORLANDC__
+// string.h is not guaranteed to provide strcpy on C++ Builder.
+# include <mem.h>
+#endif
+
+#include <string.h>
+#include <cstdint>
+#include <string>
+
+
+namespace testing {
+namespace internal {
+
+// String - an abstract class holding static string utilities.
+class GTEST_API_ String {
+ public:
+ // Static utility methods
+
+ // Clones a 0-terminated C string, allocating memory using new. The
+ // caller is responsible for deleting the return value using
+ // delete[]. Returns the cloned string, or NULL if the input is
+ // NULL.
+ //
+ // This is different from strdup() in string.h, which allocates
+ // memory using malloc().
+ static const char* CloneCString(const char* c_str);
+
+#if GTEST_OS_WINDOWS_MOBILE
+ // Windows CE does not have the 'ANSI' versions of Win32 APIs. To be
+ // able to pass strings to Win32 APIs on CE we need to convert them
+ // to 'Unicode', UTF-16.
+
+ // Creates a UTF-16 wide string from the given ANSI string, allocating
+ // memory using new. The caller is responsible for deleting the return
+ // value using delete[]. Returns the wide string, or NULL if the
+ // input is NULL.
+ //
+ // The wide string is created using the ANSI codepage (CP_ACP) to
+ // match the behaviour of the ANSI versions of Win32 calls and the
+ // C runtime.
+ static LPCWSTR AnsiToUtf16(const char* c_str);
+
+ // Creates an ANSI string from the given wide string, allocating
+ // memory using new. The caller is responsible for deleting the return
+ // value using delete[]. Returns the ANSI string, or NULL if the
+ // input is NULL.
+ //
+ // The returned string is created using the ANSI codepage (CP_ACP) to
+ // match the behaviour of the ANSI versions of Win32 calls and the
+ // C runtime.
+ static const char* Utf16ToAnsi(LPCWSTR utf16_str);
+#endif
+
+ // Compares two C strings. Returns true if and only if they have the same
+ // content.
+ //
+ // Unlike strcmp(), this function can handle NULL argument(s). A
+ // NULL C string is considered different to any non-NULL C string,
+ // including the empty string.
+ static bool CStringEquals(const char* lhs, const char* rhs);
+
+ // Converts a wide C string to a String using the UTF-8 encoding.
+ // NULL will be converted to "(null)". If an error occurred during
+ // the conversion, "(failed to convert from wide string)" is
+ // returned.
+ static std::string ShowWideCString(const wchar_t* wide_c_str);
+
+ // Compares two wide C strings. Returns true if and only if they have the
+ // same content.
+ //
+ // Unlike wcscmp(), this function can handle NULL argument(s). A
+ // NULL C string is considered different to any non-NULL C string,
+ // including the empty string.
+ static bool WideCStringEquals(const wchar_t* lhs, const wchar_t* rhs);
+
+ // Compares two C strings, ignoring case. Returns true if and only if
+ // they have the same content.
+ //
+ // Unlike strcasecmp(), this function can handle NULL argument(s).
+ // A NULL C string is considered different to any non-NULL C string,
+ // including the empty string.
+ static bool CaseInsensitiveCStringEquals(const char* lhs,
+ const char* rhs);
+
+ // Compares two wide C strings, ignoring case. Returns true if and only if
+ // they have the same content.
+ //
+ // Unlike wcscasecmp(), this function can handle NULL argument(s).
+ // A NULL C string is considered different to any non-NULL wide C string,
+ // including the empty string.
+ // NB: The implementations on different platforms slightly differ.
+ // On windows, this method uses _wcsicmp which compares according to LC_CTYPE
+ // environment variable. On GNU platform this method uses wcscasecmp
+ // which compares according to LC_CTYPE category of the current locale.
+ // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the
+ // current locale.
+ static bool CaseInsensitiveWideCStringEquals(const wchar_t* lhs,
+ const wchar_t* rhs);
+
+ // Returns true if and only if the given string ends with the given suffix,
+ // ignoring case. Any string is considered to end with an empty suffix.
+ static bool EndsWithCaseInsensitive(
+ const std::string& str, const std::string& suffix);
+
+ // Formats an int value as "%02d".
+ static std::string FormatIntWidth2(int value); // "%02d" for width == 2
+
+ // Formats an int value to given width with leading zeros.
+ static std::string FormatIntWidthN(int value, int width);
+
+ // Formats an int value as "%X".
+ static std::string FormatHexInt(int value);
+
+ // Formats an int value as "%X".
+ static std::string FormatHexUInt32(uint32_t value);
+
+ // Formats a byte as "%02X".
+ static std::string FormatByte(unsigned char value);
+
+ private:
+ String(); // Not meant to be instantiated.
+}; // class String
+
+// Gets the content of the stringstream's buffer as an std::string. Each '\0'
+// character in the buffer is replaced with "\\0".
+GTEST_API_ std::string StringStreamToString(::std::stringstream* stream);
+
+} // namespace internal
+} // namespace testing
+
+#endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
+
+GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \
+/* class A needs to have dll-interface to be used by clients of class B */)
+
+namespace testing {
+namespace internal {
+
+// FilePath - a class for file and directory pathname manipulation which
+// handles platform-specific conventions (like the pathname separator).
+// Used for helper functions for naming files in a directory for xml output.
+// Except for Set methods, all methods are const or static, which provides an
+// "immutable value object" -- useful for peace of mind.
+// A FilePath with a value ending in a path separator ("like/this/") represents
+// a directory, otherwise it is assumed to represent a file. In either case,
+// it may or may not represent an actual file or directory in the file system.
+// Names are NOT checked for syntax correctness -- no checking for illegal
+// characters, malformed paths, etc.
+
+class GTEST_API_ FilePath {
+ public:
+ FilePath() : pathname_("") { }
+ FilePath(const FilePath& rhs) : pathname_(rhs.pathname_) { }
+
+ explicit FilePath(const std::string& pathname) : pathname_(pathname) {
+ Normalize();
+ }
+
+ FilePath& operator=(const FilePath& rhs) {
+ Set(rhs);
+ return *this;
+ }
+
+ void Set(const FilePath& rhs) {
+ pathname_ = rhs.pathname_;
+ }
+
+ const std::string& string() const { return pathname_; }
+ const char* c_str() const { return pathname_.c_str(); }
+
+ // Returns the current working directory, or "" if unsuccessful.
+ static FilePath GetCurrentDir();
+
+ // Given directory = "dir", base_name = "test", number = 0,
+ // extension = "xml", returns "dir/test.xml". If number is greater
+ // than zero (e.g., 12), returns "dir/test_12.xml".
+ // On Windows platform, uses \ as the separator rather than /.
+ static FilePath MakeFileName(const FilePath& directory,
+ const FilePath& base_name,
+ int number,
+ const char* extension);
+
+ // Given directory = "dir", relative_path = "test.xml",
+ // returns "dir/test.xml".
+ // On Windows, uses \ as the separator rather than /.
+ static FilePath ConcatPaths(const FilePath& directory,
+ const FilePath& relative_path);
+
+ // Returns a pathname for a file that does not currently exist. The pathname
+ // will be directory/base_name.extension or
+ // directory/base_name_<number>.extension if directory/base_name.extension
+ // already exists. The number will be incremented until a pathname is found
+ // that does not already exist.
+ // Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'.
+ // There could be a race condition if two or more processes are calling this
+ // function at the same time -- they could both pick the same filename.
+ static FilePath GenerateUniqueFileName(const FilePath& directory,
+ const FilePath& base_name,
+ const char* extension);
+
+ // Returns true if and only if the path is "".
+ bool IsEmpty() const { return pathname_.empty(); }
+
+ // If input name has a trailing separator character, removes it and returns
+ // the name, otherwise return the name string unmodified.
+ // On Windows platform, uses \ as the separator, other platforms use /.
+ FilePath RemoveTrailingPathSeparator() const;
+
+ // Returns a copy of the FilePath with the directory part removed.
+ // Example: FilePath("path/to/file").RemoveDirectoryName() returns
+ // FilePath("file"). If there is no directory part ("just_a_file"), it returns
+ // the FilePath unmodified. If there is no file part ("just_a_dir/") it
+ // returns an empty FilePath ("").
+ // On Windows platform, '\' is the path separator, otherwise it is '/'.
+ FilePath RemoveDirectoryName() const;
+
+ // RemoveFileName returns the directory path with the filename removed.
+ // Example: FilePath("path/to/file").RemoveFileName() returns "path/to/".
+ // If the FilePath is "a_file" or "/a_file", RemoveFileName returns
+ // FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does
+ // not have a file, like "just/a/dir/", it returns the FilePath unmodified.
+ // On Windows platform, '\' is the path separator, otherwise it is '/'.
+ FilePath RemoveFileName() const;
+
+ // Returns a copy of the FilePath with the case-insensitive extension removed.
+ // Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns
+ // FilePath("dir/file"). If a case-insensitive extension is not
+ // found, returns a copy of the original FilePath.
+ FilePath RemoveExtension(const char* extension) const;
+
+ // Creates directories so that path exists. Returns true if successful or if
+ // the directories already exist; returns false if unable to create
+ // directories for any reason. Will also return false if the FilePath does
+ // not represent a directory (that is, it doesn't end with a path separator).
+ bool CreateDirectoriesRecursively() const;
+
+ // Create the directory so that path exists. Returns true if successful or
+ // if the directory already exists; returns false if unable to create the
+ // directory for any reason, including if the parent directory does not
+ // exist. Not named "CreateDirectory" because that's a macro on Windows.
+ bool CreateFolder() const;
+
+ // Returns true if FilePath describes something in the file-system,
+ // either a file, directory, or whatever, and that something exists.
+ bool FileOrDirectoryExists() const;
+
+ // Returns true if pathname describes a directory in the file-system
+ // that exists.
+ bool DirectoryExists() const;
+
+ // Returns true if FilePath ends with a path separator, which indicates that
+ // it is intended to represent a directory. Returns false otherwise.
+ // This does NOT check that a directory (or file) actually exists.
+ bool IsDirectory() const;
+
+ // Returns true if pathname describes a root directory. (Windows has one
+ // root directory per disk drive.)
+ bool IsRootDirectory() const;
+
+ // Returns true if pathname describes an absolute path.
+ bool IsAbsolutePath() const;
+
+ private:
+ // Replaces multiple consecutive separators with a single separator.
+ // For example, "bar///foo" becomes "bar/foo". Does not eliminate other
+ // redundancies that might be in a pathname involving "." or "..".
+ //
+ // A pathname with multiple consecutive separators may occur either through
+ // user error or as a result of some scripts or APIs that generate a pathname
+ // with a trailing separator. On other platforms the same API or script
+ // may NOT generate a pathname with a trailing "/". Then elsewhere that
+ // pathname may have another "/" and pathname components added to it,
+ // without checking for the separator already being there.
+ // The script language and operating system may allow paths like "foo//bar"
+ // but some of the functions in FilePath will not handle that correctly. In
+ // particular, RemoveTrailingPathSeparator() only removes one separator, and
+ // it is called in CreateDirectoriesRecursively() assuming that it will change
+ // a pathname from directory syntax (trailing separator) to filename syntax.
+ //
+ // On Windows this method also replaces the alternate path separator '/' with
+ // the primary path separator '\\', so that for example "bar\\/\\foo" becomes
+ // "bar\\foo".
+
+ void Normalize();
+
+ // Returns a pointer to the last occurrence of a valid path separator in
+ // the FilePath. On Windows, for example, both '/' and '\' are valid path
+ // separators. Returns NULL if no path separator was found.
+ const char* FindLastPathSeparator() const;
+
+ std::string pathname_;
+}; // class FilePath
+
+} // namespace internal
+} // namespace testing
+
+GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251
+
+#endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Type utilities needed for implementing typed and type-parameterized
+// tests.
+
+// GOOGLETEST_CM0001 DO NOT DELETE
+
+#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
+#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
+
+
+// #ifdef __GNUC__ is too general here. It is possible to use gcc without using
+// libstdc++ (which is where cxxabi.h comes from).
+# if GTEST_HAS_CXXABI_H_
+# include <cxxabi.h>
+# elif defined(__HP_aCC)
+# include <acxx_demangle.h>
+# endif // GTEST_HASH_CXXABI_H_
+
+namespace testing {
+namespace internal {
+
+// Canonicalizes a given name with respect to the Standard C++ Library.
+// This handles removing the inline namespace within `std` that is
+// used by various standard libraries (e.g., `std::__1`). Names outside
+// of namespace std are returned unmodified.
+inline std::string CanonicalizeForStdLibVersioning(std::string s) {
+ static const char prefix[] = "std::__";
+ if (s.compare(0, strlen(prefix), prefix) == 0) {
+ std::string::size_type end = s.find("::", strlen(prefix));
+ if (end != s.npos) {
+ // Erase everything between the initial `std` and the second `::`.
+ s.erase(strlen("std"), end - strlen("std"));
+ }
+ }
+ return s;
+}
+
+#if GTEST_HAS_RTTI
+// GetTypeName(const std::type_info&) returns a human-readable name of type T.
+inline std::string GetTypeName(const std::type_info& type) {
+ const char* const name = type.name();
+#if GTEST_HAS_CXXABI_H_ || defined(__HP_aCC)
+ int status = 0;
+ // gcc's implementation of typeid(T).name() mangles the type name,
+ // so we have to demangle it.
+#if GTEST_HAS_CXXABI_H_
+ using abi::__cxa_demangle;
+#endif // GTEST_HAS_CXXABI_H_
+ char* const readable_name = __cxa_demangle(name, nullptr, nullptr, &status);
+ const std::string name_str(status == 0 ? readable_name : name);
+ free(readable_name);
+ return CanonicalizeForStdLibVersioning(name_str);
+#else
+ return name;
+#endif // GTEST_HAS_CXXABI_H_ || __HP_aCC
+}
+#endif // GTEST_HAS_RTTI
+
+// GetTypeName<T>() returns a human-readable name of type T if and only if
+// RTTI is enabled, otherwise it returns a dummy type name.
+// NB: This function is also used in Google Mock, so don't move it inside of
+// the typed-test-only section below.
+template <typename T>
+std::string GetTypeName() {
+#if GTEST_HAS_RTTI
+ return GetTypeName(typeid(T));
+#else
+ return "<type>";
+#endif // GTEST_HAS_RTTI
+}
+
+// A unique type indicating an empty node
+struct None {};
+
+# define GTEST_TEMPLATE_ template <typename T> class
+
+// The template "selector" struct TemplateSel<Tmpl> is used to
+// represent Tmpl, which must be a class template with one type
+// parameter, as a type. TemplateSel<Tmpl>::Bind<T>::type is defined
+// as the type Tmpl<T>. This allows us to actually instantiate the
+// template "selected" by TemplateSel<Tmpl>.
+//
+// This trick is necessary for simulating typedef for class templates,
+// which C++ doesn't support directly.
+template <GTEST_TEMPLATE_ Tmpl>
+struct TemplateSel {
+ template <typename T>
+ struct Bind {
+ typedef Tmpl<T> type;
+ };
+};
+
+# define GTEST_BIND_(TmplSel, T) \
+ TmplSel::template Bind<T>::type
+
+template <GTEST_TEMPLATE_ Head_, GTEST_TEMPLATE_... Tail_>
+struct Templates {
+ using Head = TemplateSel<Head_>;
+ using Tail = Templates<Tail_...>;
+};
+
+template <GTEST_TEMPLATE_ Head_>
+struct Templates<Head_> {
+ using Head = TemplateSel<Head_>;
+ using Tail = None;
+};
+
+// Tuple-like type lists
+template <typename Head_, typename... Tail_>
+struct Types {
+ using Head = Head_;
+ using Tail = Types<Tail_...>;
+};
+
+template <typename Head_>
+struct Types<Head_> {
+ using Head = Head_;
+ using Tail = None;
+};
+
+// Helper metafunctions to tell apart a single type from types
+// generated by ::testing::Types
+template <typename... Ts>
+struct ProxyTypeList {
+ using type = Types<Ts...>;
+};
+
+template <typename>
+struct is_proxy_type_list : std::false_type {};
+
+template <typename... Ts>
+struct is_proxy_type_list<ProxyTypeList<Ts...>> : std::true_type {};
+
+// Generator which conditionally creates type lists.
+// It recognizes if a requested type list should be created
+// and prevents creating a new type list nested within another one.
+template <typename T>
+struct GenerateTypeList {
+ private:
+ using proxy = typename std::conditional<is_proxy_type_list<T>::value, T,
+ ProxyTypeList<T>>::type;
+
+ public:
+ using type = typename proxy::type;
+};
+
+} // namespace internal
+
+template <typename... Ts>
+using Types = internal::ProxyTypeList<Ts...>;
+
+} // namespace testing
+
+#endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
+
+// Due to C++ preprocessor weirdness, we need double indirection to
+// concatenate two tokens when one of them is __LINE__. Writing
+//
+// foo ## __LINE__
+//
+// will result in the token foo__LINE__, instead of foo followed by
+// the current line number. For more details, see
+// http://www.parashift.com/c++-faq-lite/misc-technical-issues.html#faq-39.6
+#define GTEST_CONCAT_TOKEN_(foo, bar) GTEST_CONCAT_TOKEN_IMPL_(foo, bar)
+#define GTEST_CONCAT_TOKEN_IMPL_(foo, bar) foo ## bar
+
+// Stringifies its argument.
+// Work around a bug in visual studio which doesn't accept code like this:
+//
+// #define GTEST_STRINGIFY_(name) #name
+// #define MACRO(a, b, c) ... GTEST_STRINGIFY_(a) ...
+// MACRO(, x, y)
+//
+// Complaining about the argument to GTEST_STRINGIFY_ being empty.
+// This is allowed by the spec.
+#define GTEST_STRINGIFY_HELPER_(name, ...) #name
+#define GTEST_STRINGIFY_(...) GTEST_STRINGIFY_HELPER_(__VA_ARGS__, )
+
+namespace proto2 {
+class MessageLite;
+}
+
+namespace testing {
+
+// Forward declarations.
+
+class AssertionResult; // Result of an assertion.
+class Message; // Represents a failure message.
+class Test; // Represents a test.
+class TestInfo; // Information about a test.
+class TestPartResult; // Result of a test part.
+class UnitTest; // A collection of test suites.
+
+template <typename T>
+::std::string PrintToString(const T& value);
+
+namespace internal {
+
+struct TraceInfo; // Information about a trace point.
+class TestInfoImpl; // Opaque implementation of TestInfo
+class UnitTestImpl; // Opaque implementation of UnitTest
+
+// The text used in failure messages to indicate the start of the
+// stack trace.
+GTEST_API_ extern const char kStackTraceMarker[];
+
+// An IgnoredValue object can be implicitly constructed from ANY value.
+class IgnoredValue {
+ struct Sink {};
+ public:
+ // This constructor template allows any value to be implicitly
+ // converted to IgnoredValue. The object has no data member and
+ // doesn't try to remember anything about the argument. We
+ // deliberately omit the 'explicit' keyword in order to allow the
+ // conversion to be implicit.
+ // Disable the conversion if T already has a magical conversion operator.
+ // Otherwise we get ambiguity.
+ template <typename T,
+ typename std::enable_if<!std::is_convertible<T, Sink>::value,
+ int>::type = 0>
+ IgnoredValue(const T& /* ignored */) {} // NOLINT(runtime/explicit)
+};
+
+// Appends the user-supplied message to the Google-Test-generated message.
+GTEST_API_ std::string AppendUserMessage(
+ const std::string& gtest_msg, const Message& user_msg);
+
+#if GTEST_HAS_EXCEPTIONS
+
+GTEST_DISABLE_MSC_WARNINGS_PUSH_(4275 \
+/* an exported class was derived from a class that was not exported */)
+
+// This exception is thrown by (and only by) a failed Google Test
+// assertion when GTEST_FLAG(throw_on_failure) is true (if exceptions
+// are enabled). We derive it from std::runtime_error, which is for
+// errors presumably detectable only at run time. Since
+// std::runtime_error inherits from std::exception, many testing
+// frameworks know how to extract and print the message inside it.
+class GTEST_API_ GoogleTestFailureException : public ::std::runtime_error {
+ public:
+ explicit GoogleTestFailureException(const TestPartResult& failure);
+};
+
+GTEST_DISABLE_MSC_WARNINGS_POP_() // 4275
+
+#endif // GTEST_HAS_EXCEPTIONS
+
+namespace edit_distance {
+// Returns the optimal edits to go from 'left' to 'right'.
+// All edits cost the same, with replace having lower priority than
+// add/remove.
+// Simple implementation of the Wagner-Fischer algorithm.
+// See http://en.wikipedia.org/wiki/Wagner-Fischer_algorithm
+enum EditType { kMatch, kAdd, kRemove, kReplace };
+GTEST_API_ std::vector<EditType> CalculateOptimalEdits(
+ const std::vector<size_t>& left, const std::vector<size_t>& right);
+
+// Same as above, but the input is represented as strings.
+GTEST_API_ std::vector<EditType> CalculateOptimalEdits(
+ const std::vector<std::string>& left,
+ const std::vector<std::string>& right);
+
+// Create a diff of the input strings in Unified diff format.
+GTEST_API_ std::string CreateUnifiedDiff(const std::vector<std::string>& left,
+ const std::vector<std::string>& right,
+ size_t context = 2);
+
+} // namespace edit_distance
+
+// Calculate the diff between 'left' and 'right' and return it in unified diff
+// format.
+// If not null, stores in 'total_line_count' the total number of lines found
+// in left + right.
+GTEST_API_ std::string DiffStrings(const std::string& left,
+ const std::string& right,
+ size_t* total_line_count);
+
+// Constructs and returns the message for an equality assertion
+// (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure.
+//
+// The first four parameters are the expressions used in the assertion
+// and their values, as strings. For example, for ASSERT_EQ(foo, bar)
+// where foo is 5 and bar is 6, we have:
+//
+// expected_expression: "foo"
+// actual_expression: "bar"
+// expected_value: "5"
+// actual_value: "6"
+//
+// The ignoring_case parameter is true if and only if the assertion is a
+// *_STRCASEEQ*. When it's true, the string " (ignoring case)" will
+// be inserted into the message.
+GTEST_API_ AssertionResult EqFailure(const char* expected_expression,
+ const char* actual_expression,
+ const std::string& expected_value,
+ const std::string& actual_value,
+ bool ignoring_case);
+
+// Constructs a failure message for Boolean assertions such as EXPECT_TRUE.
+GTEST_API_ std::string GetBoolAssertionFailureMessage(
+ const AssertionResult& assertion_result,
+ const char* expression_text,
+ const char* actual_predicate_value,
+ const char* expected_predicate_value);
+
+// This template class represents an IEEE floating-point number
+// (either single-precision or double-precision, depending on the
+// template parameters).
+//
+// The purpose of this class is to do more sophisticated number
+// comparison. (Due to round-off error, etc, it's very unlikely that
+// two floating-points will be equal exactly. Hence a naive
+// comparison by the == operation often doesn't work.)
+//
+// Format of IEEE floating-point:
+//
+// The most-significant bit being the leftmost, an IEEE
+// floating-point looks like
+//
+// sign_bit exponent_bits fraction_bits
+//
+// Here, sign_bit is a single bit that designates the sign of the
+// number.
+//
+// For float, there are 8 exponent bits and 23 fraction bits.
+//
+// For double, there are 11 exponent bits and 52 fraction bits.
+//
+// More details can be found at
+// http://en.wikipedia.org/wiki/IEEE_floating-point_standard.
+//
+// Template parameter:
+//
+// RawType: the raw floating-point type (either float or double)
+template <typename RawType>
+class FloatingPoint {
+ public:
+ // Defines the unsigned integer type that has the same size as the
+ // floating point number.
+ typedef typename TypeWithSize<sizeof(RawType)>::UInt Bits;
+
+ // Constants.
+
+ // # of bits in a number.
+ static const size_t kBitCount = 8*sizeof(RawType);
+
+ // # of fraction bits in a number.
+ static const size_t kFractionBitCount =
+ std::numeric_limits<RawType>::digits - 1;
+
+ // # of exponent bits in a number.
+ static const size_t kExponentBitCount = kBitCount - 1 - kFractionBitCount;
+
+ // The mask for the sign bit.
+ static const Bits kSignBitMask = static_cast<Bits>(1) << (kBitCount - 1);
+
+ // The mask for the fraction bits.
+ static const Bits kFractionBitMask =
+ ~static_cast<Bits>(0) >> (kExponentBitCount + 1);
+
+ // The mask for the exponent bits.
+ static const Bits kExponentBitMask = ~(kSignBitMask | kFractionBitMask);
+
+ // How many ULP's (Units in the Last Place) we want to tolerate when
+ // comparing two numbers. The larger the value, the more error we
+ // allow. A 0 value means that two numbers must be exactly the same
+ // to be considered equal.
+ //
+ // The maximum error of a single floating-point operation is 0.5
+ // units in the last place. On Intel CPU's, all floating-point
+ // calculations are done with 80-bit precision, while double has 64
+ // bits. Therefore, 4 should be enough for ordinary use.
+ //
+ // See the following article for more details on ULP:
+ // http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
+ static const uint32_t kMaxUlps = 4;
+
+ // Constructs a FloatingPoint from a raw floating-point number.
+ //
+ // On an Intel CPU, passing a non-normalized NAN (Not a Number)
+ // around may change its bits, although the new value is guaranteed
+ // to be also a NAN. Therefore, don't expect this constructor to
+ // preserve the bits in x when x is a NAN.
+ explicit FloatingPoint(const RawType& x) { u_.value_ = x; }
+
+ // Static methods
+
+ // Reinterprets a bit pattern as a floating-point number.
+ //
+ // This function is needed to test the AlmostEquals() method.
+ static RawType ReinterpretBits(const Bits bits) {
+ FloatingPoint fp(0);
+ fp.u_.bits_ = bits;
+ return fp.u_.value_;
+ }
+
+ // Returns the floating-point number that represent positive infinity.
+ static RawType Infinity() {
+ return ReinterpretBits(kExponentBitMask);
+ }
+
+ // Returns the maximum representable finite floating-point number.
+ static RawType Max();
+
+ // Non-static methods
+
+ // Returns the bits that represents this number.
+ const Bits &bits() const { return u_.bits_; }
+
+ // Returns the exponent bits of this number.
+ Bits exponent_bits() const { return kExponentBitMask & u_.bits_; }
+
+ // Returns the fraction bits of this number.
+ Bits fraction_bits() const { return kFractionBitMask & u_.bits_; }
+
+ // Returns the sign bit of this number.
+ Bits sign_bit() const { return kSignBitMask & u_.bits_; }
+
+ // Returns true if and only if this is NAN (not a number).
+ bool is_nan() const {
+ // It's a NAN if the exponent bits are all ones and the fraction
+ // bits are not entirely zeros.
+ return (exponent_bits() == kExponentBitMask) && (fraction_bits() != 0);
+ }
+
+ // Returns true if and only if this number is at most kMaxUlps ULP's away
+ // from rhs. In particular, this function:
+ //
+ // - returns false if either number is (or both are) NAN.
+ // - treats really large numbers as almost equal to infinity.
+ // - thinks +0.0 and -0.0 are 0 DLP's apart.
+ bool AlmostEquals(const FloatingPoint& rhs) const {
+ // The IEEE standard says that any comparison operation involving
+ // a NAN must return false.
+ if (is_nan() || rhs.is_nan()) return false;
+
+ return DistanceBetweenSignAndMagnitudeNumbers(u_.bits_, rhs.u_.bits_)
+ <= kMaxUlps;
+ }
+
+ private:
+ // The data type used to store the actual floating-point number.
+ union FloatingPointUnion {
+ RawType value_; // The raw floating-point number.
+ Bits bits_; // The bits that represent the number.
+ };
+
+ // Converts an integer from the sign-and-magnitude representation to
+ // the biased representation. More precisely, let N be 2 to the
+ // power of (kBitCount - 1), an integer x is represented by the
+ // unsigned number x + N.
+ //
+ // For instance,
+ //
+ // -N + 1 (the most negative number representable using
+ // sign-and-magnitude) is represented by 1;
+ // 0 is represented by N; and
+ // N - 1 (the biggest number representable using
+ // sign-and-magnitude) is represented by 2N - 1.
+ //
+ // Read http://en.wikipedia.org/wiki/Signed_number_representations
+ // for more details on signed number representations.
+ static Bits SignAndMagnitudeToBiased(const Bits &sam) {
+ if (kSignBitMask & sam) {
+ // sam represents a negative number.
+ return ~sam + 1;
+ } else {
+ // sam represents a positive number.
+ return kSignBitMask | sam;
+ }
+ }
+
+ // Given two numbers in the sign-and-magnitude representation,
+ // returns the distance between them as an unsigned number.
+ static Bits DistanceBetweenSignAndMagnitudeNumbers(const Bits &sam1,
+ const Bits &sam2) {
+ const Bits biased1 = SignAndMagnitudeToBiased(sam1);
+ const Bits biased2 = SignAndMagnitudeToBiased(sam2);
+ return (biased1 >= biased2) ? (biased1 - biased2) : (biased2 - biased1);
+ }
+
+ FloatingPointUnion u_;
+};
+
+// We cannot use std::numeric_limits<T>::max() as it clashes with the max()
+// macro defined by <windows.h>.
+template <>
+inline float FloatingPoint<float>::Max() { return FLT_MAX; }
+template <>
+inline double FloatingPoint<double>::Max() { return DBL_MAX; }
+
+// Typedefs the instances of the FloatingPoint template class that we
+// care to use.
+typedef FloatingPoint<float> Float;
+typedef FloatingPoint<double> Double;
+
+// In order to catch the mistake of putting tests that use different
+// test fixture classes in the same test suite, we need to assign
+// unique IDs to fixture classes and compare them. The TypeId type is
+// used to hold such IDs. The user should treat TypeId as an opaque
+// type: the only operation allowed on TypeId values is to compare
+// them for equality using the == operator.
+typedef const void* TypeId;
+
+template <typename T>
+class TypeIdHelper {
+ public:
+ // dummy_ must not have a const type. Otherwise an overly eager
+ // compiler (e.g. MSVC 7.1 & 8.0) may try to merge
+ // TypeIdHelper<T>::dummy_ for different Ts as an "optimization".
+ static bool dummy_;
+};
+
+template <typename T>
+bool TypeIdHelper<T>::dummy_ = false;
+
+// GetTypeId<T>() returns the ID of type T. Different values will be
+// returned for different types. Calling the function twice with the
+// same type argument is guaranteed to return the same ID.
+template <typename T>
+TypeId GetTypeId() {
+ // The compiler is required to allocate a different
+ // TypeIdHelper<T>::dummy_ variable for each T used to instantiate
+ // the template. Therefore, the address of dummy_ is guaranteed to
+ // be unique.
+ return &(TypeIdHelper<T>::dummy_);
+}
+
+// Returns the type ID of ::testing::Test. Always call this instead
+// of GetTypeId< ::testing::Test>() to get the type ID of
+// ::testing::Test, as the latter may give the wrong result due to a
+// suspected linker bug when compiling Google Test as a Mac OS X
+// framework.
+GTEST_API_ TypeId GetTestTypeId();
+
+// Defines the abstract factory interface that creates instances
+// of a Test object.
+class TestFactoryBase {
+ public:
+ virtual ~TestFactoryBase() {}
+
+ // Creates a test instance to run. The instance is both created and destroyed
+ // within TestInfoImpl::Run()
+ virtual Test* CreateTest() = 0;
+
+ protected:
+ TestFactoryBase() {}
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(TestFactoryBase);
+};
+
+// This class provides implementation of TeastFactoryBase interface.
+// It is used in TEST and TEST_F macros.
+template <class TestClass>
+class TestFactoryImpl : public TestFactoryBase {
+ public:
+ Test* CreateTest() override { return new TestClass; }
+};
+
+#if GTEST_OS_WINDOWS
+
+// Predicate-formatters for implementing the HRESULT checking macros
+// {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED}
+// We pass a long instead of HRESULT to avoid causing an
+// include dependency for the HRESULT type.
+GTEST_API_ AssertionResult IsHRESULTSuccess(const char* expr,
+ long hr); // NOLINT
+GTEST_API_ AssertionResult IsHRESULTFailure(const char* expr,
+ long hr); // NOLINT
+
+#endif // GTEST_OS_WINDOWS
+
+// Types of SetUpTestSuite() and TearDownTestSuite() functions.
+using SetUpTestSuiteFunc = void (*)();
+using TearDownTestSuiteFunc = void (*)();
+
+struct CodeLocation {
+ CodeLocation(const std::string& a_file, int a_line)
+ : file(a_file), line(a_line) {}
+
+ std::string file;
+ int line;
+};
+
+// Helper to identify which setup function for TestCase / TestSuite to call.
+// Only one function is allowed, either TestCase or TestSute but not both.
+
+// Utility functions to help SuiteApiResolver
+using SetUpTearDownSuiteFuncType = void (*)();
+
+inline SetUpTearDownSuiteFuncType GetNotDefaultOrNull(
+ SetUpTearDownSuiteFuncType a, SetUpTearDownSuiteFuncType def) {
+ return a == def ? nullptr : a;
+}
+
+template <typename T>
+// Note that SuiteApiResolver inherits from T because
+// SetUpTestSuite()/TearDownTestSuite() could be protected. Ths way
+// SuiteApiResolver can access them.
+struct SuiteApiResolver : T {
+ // testing::Test is only forward declared at this point. So we make it a
+ // dependend class for the compiler to be OK with it.
+ using Test =
+ typename std::conditional<sizeof(T) != 0, ::testing::Test, void>::type;
+
+ static SetUpTearDownSuiteFuncType GetSetUpCaseOrSuite(const char* filename,
+ int line_num) {
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ SetUpTearDownSuiteFuncType test_case_fp =
+ GetNotDefaultOrNull(&T::SetUpTestCase, &Test::SetUpTestCase);
+ SetUpTearDownSuiteFuncType test_suite_fp =
+ GetNotDefaultOrNull(&T::SetUpTestSuite, &Test::SetUpTestSuite);
+
+ GTEST_CHECK_(!test_case_fp || !test_suite_fp)
+ << "Test can not provide both SetUpTestSuite and SetUpTestCase, please "
+ "make sure there is only one present at "
+ << filename << ":" << line_num;
+
+ return test_case_fp != nullptr ? test_case_fp : test_suite_fp;
+#else
+ (void)(filename);
+ (void)(line_num);
+ return &T::SetUpTestSuite;
+#endif
+ }
+
+ static SetUpTearDownSuiteFuncType GetTearDownCaseOrSuite(const char* filename,
+ int line_num) {
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ SetUpTearDownSuiteFuncType test_case_fp =
+ GetNotDefaultOrNull(&T::TearDownTestCase, &Test::TearDownTestCase);
+ SetUpTearDownSuiteFuncType test_suite_fp =
+ GetNotDefaultOrNull(&T::TearDownTestSuite, &Test::TearDownTestSuite);
+
+ GTEST_CHECK_(!test_case_fp || !test_suite_fp)
+ << "Test can not provide both TearDownTestSuite and TearDownTestCase,"
+ " please make sure there is only one present at"
+ << filename << ":" << line_num;
+
+ return test_case_fp != nullptr ? test_case_fp : test_suite_fp;
+#else
+ (void)(filename);
+ (void)(line_num);
+ return &T::TearDownTestSuite;
+#endif
+ }
+};
+
+// Creates a new TestInfo object and registers it with Google Test;
+// returns the created object.
+//
+// Arguments:
+//
+// test_suite_name: name of the test suite
+// name: name of the test
+// type_param: the name of the test's type parameter, or NULL if
+// this is not a typed or a type-parameterized test.
+// value_param: text representation of the test's value parameter,
+// or NULL if this is not a type-parameterized test.
+// code_location: code location where the test is defined
+// fixture_class_id: ID of the test fixture class
+// set_up_tc: pointer to the function that sets up the test suite
+// tear_down_tc: pointer to the function that tears down the test suite
+// factory: pointer to the factory that creates a test object.
+// The newly created TestInfo instance will assume
+// ownership of the factory object.
+GTEST_API_ TestInfo* MakeAndRegisterTestInfo(
+ const char* test_suite_name, const char* name, const char* type_param,
+ const char* value_param, CodeLocation code_location,
+ TypeId fixture_class_id, SetUpTestSuiteFunc set_up_tc,
+ TearDownTestSuiteFunc tear_down_tc, TestFactoryBase* factory);
+
+// If *pstr starts with the given prefix, modifies *pstr to be right
+// past the prefix and returns true; otherwise leaves *pstr unchanged
+// and returns false. None of pstr, *pstr, and prefix can be NULL.
+GTEST_API_ bool SkipPrefix(const char* prefix, const char** pstr);
+
+GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \
+/* class A needs to have dll-interface to be used by clients of class B */)
+
+// State of the definition of a type-parameterized test suite.
+class GTEST_API_ TypedTestSuitePState {
+ public:
+ TypedTestSuitePState() : registered_(false) {}
+
+ // Adds the given test name to defined_test_names_ and return true
+ // if the test suite hasn't been registered; otherwise aborts the
+ // program.
+ bool AddTestName(const char* file, int line, const char* case_name,
+ const char* test_name) {
+ if (registered_) {
+ fprintf(stderr,
+ "%s Test %s must be defined before "
+ "REGISTER_TYPED_TEST_SUITE_P(%s, ...).\n",
+ FormatFileLocation(file, line).c_str(), test_name, case_name);
+ fflush(stderr);
+ posix::Abort();
+ }
+ registered_tests_.insert(
+ ::std::make_pair(test_name, CodeLocation(file, line)));
+ return true;
+ }
+
+ bool TestExists(const std::string& test_name) const {
+ return registered_tests_.count(test_name) > 0;
+ }
+
+ const CodeLocation& GetCodeLocation(const std::string& test_name) const {
+ RegisteredTestsMap::const_iterator it = registered_tests_.find(test_name);
+ GTEST_CHECK_(it != registered_tests_.end());
+ return it->second;
+ }
+
+ // Verifies that registered_tests match the test names in
+ // defined_test_names_; returns registered_tests if successful, or
+ // aborts the program otherwise.
+ const char* VerifyRegisteredTestNames(const char* test_suite_name,
+ const char* file, int line,
+ const char* registered_tests);
+
+ private:
+ typedef ::std::map<std::string, CodeLocation> RegisteredTestsMap;
+
+ bool registered_;
+ RegisteredTestsMap registered_tests_;
+};
+
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+using TypedTestCasePState = TypedTestSuitePState;
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251
+
+// Skips to the first non-space char after the first comma in 'str';
+// returns NULL if no comma is found in 'str'.
+inline const char* SkipComma(const char* str) {
+ const char* comma = strchr(str, ',');
+ if (comma == nullptr) {
+ return nullptr;
+ }
+ while (IsSpace(*(++comma))) {}
+ return comma;
+}
+
+// Returns the prefix of 'str' before the first comma in it; returns
+// the entire string if it contains no comma.
+inline std::string GetPrefixUntilComma(const char* str) {
+ const char* comma = strchr(str, ',');
+ return comma == nullptr ? str : std::string(str, comma);
+}
+
+// Splits a given string on a given delimiter, populating a given
+// vector with the fields.
+void SplitString(const ::std::string& str, char delimiter,
+ ::std::vector< ::std::string>* dest);
+
+// The default argument to the template below for the case when the user does
+// not provide a name generator.
+struct DefaultNameGenerator {
+ template <typename T>
+ static std::string GetName(int i) {
+ return StreamableToString(i);
+ }
+};
+
+template <typename Provided = DefaultNameGenerator>
+struct NameGeneratorSelector {
+ typedef Provided type;
+};
+
+template <typename NameGenerator>
+void GenerateNamesRecursively(internal::None, std::vector<std::string>*, int) {}
+
+template <typename NameGenerator, typename Types>
+void GenerateNamesRecursively(Types, std::vector<std::string>* result, int i) {
+ result->push_back(NameGenerator::template GetName<typename Types::Head>(i));
+ GenerateNamesRecursively<NameGenerator>(typename Types::Tail(), result,
+ i + 1);
+}
+
+template <typename NameGenerator, typename Types>
+std::vector<std::string> GenerateNames() {
+ std::vector<std::string> result;
+ GenerateNamesRecursively<NameGenerator>(Types(), &result, 0);
+ return result;
+}
+
+// TypeParameterizedTest<Fixture, TestSel, Types>::Register()
+// registers a list of type-parameterized tests with Google Test. The
+// return value is insignificant - we just need to return something
+// such that we can call this function in a namespace scope.
+//
+// Implementation note: The GTEST_TEMPLATE_ macro declares a template
+// template parameter. It's defined in gtest-type-util.h.
+template <GTEST_TEMPLATE_ Fixture, class TestSel, typename Types>
+class TypeParameterizedTest {
+ public:
+ // 'index' is the index of the test in the type list 'Types'
+ // specified in INSTANTIATE_TYPED_TEST_SUITE_P(Prefix, TestSuite,
+ // Types). Valid values for 'index' are [0, N - 1] where N is the
+ // length of Types.
+ static bool Register(const char* prefix, const CodeLocation& code_location,
+ const char* case_name, const char* test_names, int index,
+ const std::vector<std::string>& type_names =
+ GenerateNames<DefaultNameGenerator, Types>()) {
+ typedef typename Types::Head Type;
+ typedef Fixture<Type> FixtureClass;
+ typedef typename GTEST_BIND_(TestSel, Type) TestClass;
+
+ // First, registers the first type-parameterized test in the type
+ // list.
+ MakeAndRegisterTestInfo(
+ (std::string(prefix) + (prefix[0] == '\0' ? "" : "/") + case_name +
+ "/" + type_names[static_cast<size_t>(index)])
+ .c_str(),
+ StripTrailingSpaces(GetPrefixUntilComma(test_names)).c_str(),
+ GetTypeName<Type>().c_str(),
+ nullptr, // No value parameter.
+ code_location, GetTypeId<FixtureClass>(),
+ SuiteApiResolver<TestClass>::GetSetUpCaseOrSuite(
+ code_location.file.c_str(), code_location.line),
+ SuiteApiResolver<TestClass>::GetTearDownCaseOrSuite(
+ code_location.file.c_str(), code_location.line),
+ new TestFactoryImpl<TestClass>);
+
+ // Next, recurses (at compile time) with the tail of the type list.
+ return TypeParameterizedTest<Fixture, TestSel,
+ typename Types::Tail>::Register(prefix,
+ code_location,
+ case_name,
+ test_names,
+ index + 1,
+ type_names);
+ }
+};
+
+// The base case for the compile time recursion.
+template <GTEST_TEMPLATE_ Fixture, class TestSel>
+class TypeParameterizedTest<Fixture, TestSel, internal::None> {
+ public:
+ static bool Register(const char* /*prefix*/, const CodeLocation&,
+ const char* /*case_name*/, const char* /*test_names*/,
+ int /*index*/,
+ const std::vector<std::string>& =
+ std::vector<std::string>() /*type_names*/) {
+ return true;
+ }
+};
+
+GTEST_API_ void RegisterTypeParameterizedTestSuite(const char* test_suite_name,
+ CodeLocation code_location);
+GTEST_API_ void RegisterTypeParameterizedTestSuiteInstantiation(
+ const char* case_name);
+
+// TypeParameterizedTestSuite<Fixture, Tests, Types>::Register()
+// registers *all combinations* of 'Tests' and 'Types' with Google
+// Test. The return value is insignificant - we just need to return
+// something such that we can call this function in a namespace scope.
+template <GTEST_TEMPLATE_ Fixture, typename Tests, typename Types>
+class TypeParameterizedTestSuite {
+ public:
+ static bool Register(const char* prefix, CodeLocation code_location,
+ const TypedTestSuitePState* state, const char* case_name,
+ const char* test_names,
+ const std::vector<std::string>& type_names =
+ GenerateNames<DefaultNameGenerator, Types>()) {
+ RegisterTypeParameterizedTestSuiteInstantiation(case_name);
+ std::string test_name = StripTrailingSpaces(
+ GetPrefixUntilComma(test_names));
+ if (!state->TestExists(test_name)) {
+ fprintf(stderr, "Failed to get code location for test %s.%s at %s.",
+ case_name, test_name.c_str(),
+ FormatFileLocation(code_location.file.c_str(),
+ code_location.line).c_str());
+ fflush(stderr);
+ posix::Abort();
+ }
+ const CodeLocation& test_location = state->GetCodeLocation(test_name);
+
+ typedef typename Tests::Head Head;
+
+ // First, register the first test in 'Test' for each type in 'Types'.
+ TypeParameterizedTest<Fixture, Head, Types>::Register(
+ prefix, test_location, case_name, test_names, 0, type_names);
+
+ // Next, recurses (at compile time) with the tail of the test list.
+ return TypeParameterizedTestSuite<Fixture, typename Tests::Tail,
+ Types>::Register(prefix, code_location,
+ state, case_name,
+ SkipComma(test_names),
+ type_names);
+ }
+};
+
+// The base case for the compile time recursion.
+template <GTEST_TEMPLATE_ Fixture, typename Types>
+class TypeParameterizedTestSuite<Fixture, internal::None, Types> {
+ public:
+ static bool Register(const char* /*prefix*/, const CodeLocation&,
+ const TypedTestSuitePState* /*state*/,
+ const char* /*case_name*/, const char* /*test_names*/,
+ const std::vector<std::string>& =
+ std::vector<std::string>() /*type_names*/) {
+ return true;
+ }
+};
+
+// Returns the current OS stack trace as an std::string.
+//
+// The maximum number of stack frames to be included is specified by
+// the gtest_stack_trace_depth flag. The skip_count parameter
+// specifies the number of top frames to be skipped, which doesn't
+// count against the number of frames to be included.
+//
+// For example, if Foo() calls Bar(), which in turn calls
+// GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in
+// the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't.
+GTEST_API_ std::string GetCurrentOsStackTraceExceptTop(
+ UnitTest* unit_test, int skip_count);
+
+// Helpers for suppressing warnings on unreachable code or constant
+// condition.
+
+// Always returns true.
+GTEST_API_ bool AlwaysTrue();
+
+// Always returns false.
+inline bool AlwaysFalse() { return !AlwaysTrue(); }
+
+// Helper for suppressing false warning from Clang on a const char*
+// variable declared in a conditional expression always being NULL in
+// the else branch.
+struct GTEST_API_ ConstCharPtr {
+ ConstCharPtr(const char* str) : value(str) {}
+ operator bool() const { return true; }
+ const char* value;
+};
+
+// Helper for declaring std::string within 'if' statement
+// in pre C++17 build environment.
+struct TrueWithString {
+ TrueWithString() = default;
+ explicit TrueWithString(const char* str) : value(str) {}
+ explicit TrueWithString(const std::string& str) : value(str) {}
+ explicit operator bool() const { return true; }
+ std::string value;
+};
+
+// A simple Linear Congruential Generator for generating random
+// numbers with a uniform distribution. Unlike rand() and srand(), it
+// doesn't use global state (and therefore can't interfere with user
+// code). Unlike rand_r(), it's portable. An LCG isn't very random,
+// but it's good enough for our purposes.
+class GTEST_API_ Random {
+ public:
+ static const uint32_t kMaxRange = 1u << 31;
+
+ explicit Random(uint32_t seed) : state_(seed) {}
+
+ void Reseed(uint32_t seed) { state_ = seed; }
+
+ // Generates a random number from [0, range). Crashes if 'range' is
+ // 0 or greater than kMaxRange.
+ uint32_t Generate(uint32_t range);
+
+ private:
+ uint32_t state_;
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(Random);
+};
+
+// Turns const U&, U&, const U, and U all into U.
+#define GTEST_REMOVE_REFERENCE_AND_CONST_(T) \
+ typename std::remove_const<typename std::remove_reference<T>::type>::type
+
+// HasDebugStringAndShortDebugString<T>::value is a compile-time bool constant
+// that's true if and only if T has methods DebugString() and ShortDebugString()
+// that return std::string.
+template <typename T>
+class HasDebugStringAndShortDebugString {
+ private:
+ template <typename C>
+ static auto CheckDebugString(C*) -> typename std::is_same<
+ std::string, decltype(std::declval<const C>().DebugString())>::type;
+ template <typename>
+ static std::false_type CheckDebugString(...);
+
+ template <typename C>
+ static auto CheckShortDebugString(C*) -> typename std::is_same<
+ std::string, decltype(std::declval<const C>().ShortDebugString())>::type;
+ template <typename>
+ static std::false_type CheckShortDebugString(...);
+
+ using HasDebugStringType = decltype(CheckDebugString<T>(nullptr));
+ using HasShortDebugStringType = decltype(CheckShortDebugString<T>(nullptr));
+
+ public:
+ static constexpr bool value =
+ HasDebugStringType::value && HasShortDebugStringType::value;
+};
+
+template <typename T>
+constexpr bool HasDebugStringAndShortDebugString<T>::value;
+
+// When the compiler sees expression IsContainerTest<C>(0), if C is an
+// STL-style container class, the first overload of IsContainerTest
+// will be viable (since both C::iterator* and C::const_iterator* are
+// valid types and NULL can be implicitly converted to them). It will
+// be picked over the second overload as 'int' is a perfect match for
+// the type of argument 0. If C::iterator or C::const_iterator is not
+// a valid type, the first overload is not viable, and the second
+// overload will be picked. Therefore, we can determine whether C is
+// a container class by checking the type of IsContainerTest<C>(0).
+// The value of the expression is insignificant.
+//
+// In C++11 mode we check the existence of a const_iterator and that an
+// iterator is properly implemented for the container.
+//
+// For pre-C++11 that we look for both C::iterator and C::const_iterator.
+// The reason is that C++ injects the name of a class as a member of the
+// class itself (e.g. you can refer to class iterator as either
+// 'iterator' or 'iterator::iterator'). If we look for C::iterator
+// only, for example, we would mistakenly think that a class named
+// iterator is an STL container.
+//
+// Also note that the simpler approach of overloading
+// IsContainerTest(typename C::const_iterator*) and
+// IsContainerTest(...) doesn't work with Visual Age C++ and Sun C++.
+typedef int IsContainer;
+template <class C,
+ class Iterator = decltype(::std::declval<const C&>().begin()),
+ class = decltype(::std::declval<const C&>().end()),
+ class = decltype(++::std::declval<Iterator&>()),
+ class = decltype(*::std::declval<Iterator>()),
+ class = typename C::const_iterator>
+IsContainer IsContainerTest(int /* dummy */) {
+ return 0;
+}
+
+typedef char IsNotContainer;
+template <class C>
+IsNotContainer IsContainerTest(long /* dummy */) { return '\0'; }
+
+// Trait to detect whether a type T is a hash table.
+// The heuristic used is that the type contains an inner type `hasher` and does
+// not contain an inner type `reverse_iterator`.
+// If the container is iterable in reverse, then order might actually matter.
+template <typename T>
+struct IsHashTable {
+ private:
+ template <typename U>
+ static char test(typename U::hasher*, typename U::reverse_iterator*);
+ template <typename U>
+ static int test(typename U::hasher*, ...);
+ template <typename U>
+ static char test(...);
+
+ public:
+ static const bool value = sizeof(test<T>(nullptr, nullptr)) == sizeof(int);
+};
+
+template <typename T>
+const bool IsHashTable<T>::value;
+
+template <typename C,
+ bool = sizeof(IsContainerTest<C>(0)) == sizeof(IsContainer)>
+struct IsRecursiveContainerImpl;
+
+template <typename C>
+struct IsRecursiveContainerImpl<C, false> : public std::false_type {};
+
+// Since the IsRecursiveContainerImpl depends on the IsContainerTest we need to
+// obey the same inconsistencies as the IsContainerTest, namely check if
+// something is a container is relying on only const_iterator in C++11 and
+// is relying on both const_iterator and iterator otherwise
+template <typename C>
+struct IsRecursiveContainerImpl<C, true> {
+ using value_type = decltype(*std::declval<typename C::const_iterator>());
+ using type =
+ std::is_same<typename std::remove_const<
+ typename std::remove_reference<value_type>::type>::type,
+ C>;
+};
+
+// IsRecursiveContainer<Type> is a unary compile-time predicate that
+// evaluates whether C is a recursive container type. A recursive container
+// type is a container type whose value_type is equal to the container type
+// itself. An example for a recursive container type is
+// boost::filesystem::path, whose iterator has a value_type that is equal to
+// boost::filesystem::path.
+template <typename C>
+struct IsRecursiveContainer : public IsRecursiveContainerImpl<C>::type {};
+
+// Utilities for native arrays.
+
+// ArrayEq() compares two k-dimensional native arrays using the
+// elements' operator==, where k can be any integer >= 0. When k is
+// 0, ArrayEq() degenerates into comparing a single pair of values.
+
+template <typename T, typename U>
+bool ArrayEq(const T* lhs, size_t size, const U* rhs);
+
+// This generic version is used when k is 0.
+template <typename T, typename U>
+inline bool ArrayEq(const T& lhs, const U& rhs) { return lhs == rhs; }
+
+// This overload is used when k >= 1.
+template <typename T, typename U, size_t N>
+inline bool ArrayEq(const T(&lhs)[N], const U(&rhs)[N]) {
+ return internal::ArrayEq(lhs, N, rhs);
+}
+
+// This helper reduces code bloat. If we instead put its logic inside
+// the previous ArrayEq() function, arrays with different sizes would
+// lead to different copies of the template code.
+template <typename T, typename U>
+bool ArrayEq(const T* lhs, size_t size, const U* rhs) {
+ for (size_t i = 0; i != size; i++) {
+ if (!internal::ArrayEq(lhs[i], rhs[i]))
+ return false;
+ }
+ return true;
+}
+
+// Finds the first element in the iterator range [begin, end) that
+// equals elem. Element may be a native array type itself.
+template <typename Iter, typename Element>
+Iter ArrayAwareFind(Iter begin, Iter end, const Element& elem) {
+ for (Iter it = begin; it != end; ++it) {
+ if (internal::ArrayEq(*it, elem))
+ return it;
+ }
+ return end;
+}
+
+// CopyArray() copies a k-dimensional native array using the elements'
+// operator=, where k can be any integer >= 0. When k is 0,
+// CopyArray() degenerates into copying a single value.
+
+template <typename T, typename U>
+void CopyArray(const T* from, size_t size, U* to);
+
+// This generic version is used when k is 0.
+template <typename T, typename U>
+inline void CopyArray(const T& from, U* to) { *to = from; }
+
+// This overload is used when k >= 1.
+template <typename T, typename U, size_t N>
+inline void CopyArray(const T(&from)[N], U(*to)[N]) {
+ internal::CopyArray(from, N, *to);
+}
+
+// This helper reduces code bloat. If we instead put its logic inside
+// the previous CopyArray() function, arrays with different sizes
+// would lead to different copies of the template code.
+template <typename T, typename U>
+void CopyArray(const T* from, size_t size, U* to) {
+ for (size_t i = 0; i != size; i++) {
+ internal::CopyArray(from[i], to + i);
+ }
+}
+
+// The relation between an NativeArray object (see below) and the
+// native array it represents.
+// We use 2 different structs to allow non-copyable types to be used, as long
+// as RelationToSourceReference() is passed.
+struct RelationToSourceReference {};
+struct RelationToSourceCopy {};
+
+// Adapts a native array to a read-only STL-style container. Instead
+// of the complete STL container concept, this adaptor only implements
+// members useful for Google Mock's container matchers. New members
+// should be added as needed. To simplify the implementation, we only
+// support Element being a raw type (i.e. having no top-level const or
+// reference modifier). It's the client's responsibility to satisfy
+// this requirement. Element can be an array type itself (hence
+// multi-dimensional arrays are supported).
+template <typename Element>
+class NativeArray {
+ public:
+ // STL-style container typedefs.
+ typedef Element value_type;
+ typedef Element* iterator;
+ typedef const Element* const_iterator;
+
+ // Constructs from a native array. References the source.
+ NativeArray(const Element* array, size_t count, RelationToSourceReference) {
+ InitRef(array, count);
+ }
+
+ // Constructs from a native array. Copies the source.
+ NativeArray(const Element* array, size_t count, RelationToSourceCopy) {
+ InitCopy(array, count);
+ }
+
+ // Copy constructor.
+ NativeArray(const NativeArray& rhs) {
+ (this->*rhs.clone_)(rhs.array_, rhs.size_);
+ }
+
+ ~NativeArray() {
+ if (clone_ != &NativeArray::InitRef)
+ delete[] array_;
+ }
+
+ // STL-style container methods.
+ size_t size() const { return size_; }
+ const_iterator begin() const { return array_; }
+ const_iterator end() const { return array_ + size_; }
+ bool operator==(const NativeArray& rhs) const {
+ return size() == rhs.size() &&
+ ArrayEq(begin(), size(), rhs.begin());
+ }
+
+ private:
+ static_assert(!std::is_const<Element>::value, "Type must not be const");
+ static_assert(!std::is_reference<Element>::value,
+ "Type must not be a reference");
+
+ // Initializes this object with a copy of the input.
+ void InitCopy(const Element* array, size_t a_size) {
+ Element* const copy = new Element[a_size];
+ CopyArray(array, a_size, copy);
+ array_ = copy;
+ size_ = a_size;
+ clone_ = &NativeArray::InitCopy;
+ }
+
+ // Initializes this object with a reference of the input.
+ void InitRef(const Element* array, size_t a_size) {
+ array_ = array;
+ size_ = a_size;
+ clone_ = &NativeArray::InitRef;
+ }
+
+ const Element* array_;
+ size_t size_;
+ void (NativeArray::*clone_)(const Element*, size_t);
+};
+
+// Backport of std::index_sequence.
+template <size_t... Is>
+struct IndexSequence {
+ using type = IndexSequence;
+};
+
+// Double the IndexSequence, and one if plus_one is true.
+template <bool plus_one, typename T, size_t sizeofT>
+struct DoubleSequence;
+template <size_t... I, size_t sizeofT>
+struct DoubleSequence<true, IndexSequence<I...>, sizeofT> {
+ using type = IndexSequence<I..., (sizeofT + I)..., 2 * sizeofT>;
+};
+template <size_t... I, size_t sizeofT>
+struct DoubleSequence<false, IndexSequence<I...>, sizeofT> {
+ using type = IndexSequence<I..., (sizeofT + I)...>;
+};
+
+// Backport of std::make_index_sequence.
+// It uses O(ln(N)) instantiation depth.
+template <size_t N>
+struct MakeIndexSequenceImpl
+ : DoubleSequence<N % 2 == 1, typename MakeIndexSequenceImpl<N / 2>::type,
+ N / 2>::type {};
+
+template <>
+struct MakeIndexSequenceImpl<0> : IndexSequence<> {};
+
+template <size_t N>
+using MakeIndexSequence = typename MakeIndexSequenceImpl<N>::type;
+
+template <typename... T>
+using IndexSequenceFor = typename MakeIndexSequence<sizeof...(T)>::type;
+
+template <size_t>
+struct Ignore {
+ Ignore(...); // NOLINT
+};
+
+template <typename>
+struct ElemFromListImpl;
+template <size_t... I>
+struct ElemFromListImpl<IndexSequence<I...>> {
+ // We make Ignore a template to solve a problem with MSVC.
+ // A non-template Ignore would work fine with `decltype(Ignore(I))...`, but
+ // MSVC doesn't understand how to deal with that pack expansion.
+ // Use `0 * I` to have a single instantiation of Ignore.
+ template <typename R>
+ static R Apply(Ignore<0 * I>..., R (*)(), ...);
+};
+
+template <size_t N, typename... T>
+struct ElemFromList {
+ using type =
+ decltype(ElemFromListImpl<typename MakeIndexSequence<N>::type>::Apply(
+ static_cast<T (*)()>(nullptr)...));
+};
+
+struct FlatTupleConstructTag {};
+
+template <typename... T>
+class FlatTuple;
+
+template <typename Derived, size_t I>
+struct FlatTupleElemBase;
+
+template <typename... T, size_t I>
+struct FlatTupleElemBase<FlatTuple<T...>, I> {
+ using value_type = typename ElemFromList<I, T...>::type;
+ FlatTupleElemBase() = default;
+ template <typename Arg>
+ explicit FlatTupleElemBase(FlatTupleConstructTag, Arg&& t)
+ : value(std::forward<Arg>(t)) {}
+ value_type value;
+};
+
+template <typename Derived, typename Idx>
+struct FlatTupleBase;
+
+template <size_t... Idx, typename... T>
+struct FlatTupleBase<FlatTuple<T...>, IndexSequence<Idx...>>
+ : FlatTupleElemBase<FlatTuple<T...>, Idx>... {
+ using Indices = IndexSequence<Idx...>;
+ FlatTupleBase() = default;
+ template <typename... Args>
+ explicit FlatTupleBase(FlatTupleConstructTag, Args&&... args)
+ : FlatTupleElemBase<FlatTuple<T...>, Idx>(FlatTupleConstructTag{},
+ std::forward<Args>(args))... {}
+
+ template <size_t I>
+ const typename ElemFromList<I, T...>::type& Get() const {
+ return FlatTupleElemBase<FlatTuple<T...>, I>::value;
+ }
+
+ template <size_t I>
+ typename ElemFromList<I, T...>::type& Get() {
+ return FlatTupleElemBase<FlatTuple<T...>, I>::value;
+ }
+
+ template <typename F>
+ auto Apply(F&& f) -> decltype(std::forward<F>(f)(this->Get<Idx>()...)) {
+ return std::forward<F>(f)(Get<Idx>()...);
+ }
+
+ template <typename F>
+ auto Apply(F&& f) const -> decltype(std::forward<F>(f)(this->Get<Idx>()...)) {
+ return std::forward<F>(f)(Get<Idx>()...);
+ }
+};
+
+// Analog to std::tuple but with different tradeoffs.
+// This class minimizes the template instantiation depth, thus allowing more
+// elements than std::tuple would. std::tuple has been seen to require an
+// instantiation depth of more than 10x the number of elements in some
+// implementations.
+// FlatTuple and ElemFromList are not recursive and have a fixed depth
+// regardless of T...
+// MakeIndexSequence, on the other hand, it is recursive but with an
+// instantiation depth of O(ln(N)).
+template <typename... T>
+class FlatTuple
+ : private FlatTupleBase<FlatTuple<T...>,
+ typename MakeIndexSequence<sizeof...(T)>::type> {
+ using Indices = typename FlatTupleBase<
+ FlatTuple<T...>, typename MakeIndexSequence<sizeof...(T)>::type>::Indices;
+
+ public:
+ FlatTuple() = default;
+ template <typename... Args>
+ explicit FlatTuple(FlatTupleConstructTag tag, Args&&... args)
+ : FlatTuple::FlatTupleBase(tag, std::forward<Args>(args)...) {}
+
+ using FlatTuple::FlatTupleBase::Apply;
+ using FlatTuple::FlatTupleBase::Get;
+};
+
+// Utility functions to be called with static_assert to induce deprecation
+// warnings.
+GTEST_INTERNAL_DEPRECATED(
+ "INSTANTIATE_TEST_CASE_P is deprecated, please use "
+ "INSTANTIATE_TEST_SUITE_P")
+constexpr bool InstantiateTestCase_P_IsDeprecated() { return true; }
+
+GTEST_INTERNAL_DEPRECATED(
+ "TYPED_TEST_CASE_P is deprecated, please use "
+ "TYPED_TEST_SUITE_P")
+constexpr bool TypedTestCase_P_IsDeprecated() { return true; }
+
+GTEST_INTERNAL_DEPRECATED(
+ "TYPED_TEST_CASE is deprecated, please use "
+ "TYPED_TEST_SUITE")
+constexpr bool TypedTestCaseIsDeprecated() { return true; }
+
+GTEST_INTERNAL_DEPRECATED(
+ "REGISTER_TYPED_TEST_CASE_P is deprecated, please use "
+ "REGISTER_TYPED_TEST_SUITE_P")
+constexpr bool RegisterTypedTestCase_P_IsDeprecated() { return true; }
+
+GTEST_INTERNAL_DEPRECATED(
+ "INSTANTIATE_TYPED_TEST_CASE_P is deprecated, please use "
+ "INSTANTIATE_TYPED_TEST_SUITE_P")
+constexpr bool InstantiateTypedTestCase_P_IsDeprecated() { return true; }
+
+} // namespace internal
+} // namespace testing
+
+namespace std {
+// Some standard library implementations use `struct tuple_size` and some use
+// `class tuple_size`. Clang warns about the mismatch.
+// https://reviews.llvm.org/D55466
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wmismatched-tags"
+#endif
+template <typename... Ts>
+struct tuple_size<testing::internal::FlatTuple<Ts...>>
+ : std::integral_constant<size_t, sizeof...(Ts)> {};
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+} // namespace std
+
+#define GTEST_MESSAGE_AT_(file, line, message, result_type) \
+ ::testing::internal::AssertHelper(result_type, file, line, message) \
+ = ::testing::Message()
+
+#define GTEST_MESSAGE_(message, result_type) \
+ GTEST_MESSAGE_AT_(__FILE__, __LINE__, message, result_type)
+
+#define GTEST_FATAL_FAILURE_(message) \
+ return GTEST_MESSAGE_(message, ::testing::TestPartResult::kFatalFailure)
+
+#define GTEST_NONFATAL_FAILURE_(message) \
+ GTEST_MESSAGE_(message, ::testing::TestPartResult::kNonFatalFailure)
+
+#define GTEST_SUCCESS_(message) \
+ GTEST_MESSAGE_(message, ::testing::TestPartResult::kSuccess)
+
+#define GTEST_SKIP_(message) \
+ return GTEST_MESSAGE_(message, ::testing::TestPartResult::kSkip)
+
+// Suppress MSVC warning 4072 (unreachable code) for the code following
+// statement if it returns or throws (or doesn't return or throw in some
+// situations).
+// NOTE: The "else" is important to keep this expansion to prevent a top-level
+// "else" from attaching to our "if".
+#define GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) \
+ if (::testing::internal::AlwaysTrue()) { \
+ statement; \
+ } else /* NOLINT */ \
+ static_assert(true, "") // User must have a semicolon after expansion.
+
+#if GTEST_HAS_EXCEPTIONS
+
+namespace testing {
+namespace internal {
+
+class NeverThrown {
+ public:
+ const char* what() const noexcept {
+ return "this exception should never be thrown";
+ }
+};
+
+} // namespace internal
+} // namespace testing
+
+#if GTEST_HAS_RTTI
+
+#define GTEST_EXCEPTION_TYPE_(e) ::testing::internal::GetTypeName(typeid(e))
+
+#else // GTEST_HAS_RTTI
+
+#define GTEST_EXCEPTION_TYPE_(e) \
+ std::string { "an std::exception-derived error" }
+
+#endif // GTEST_HAS_RTTI
+
+#define GTEST_TEST_THROW_CATCH_STD_EXCEPTION_(statement, expected_exception) \
+ catch (typename std::conditional< \
+ std::is_same<typename std::remove_cv<typename std::remove_reference< \
+ expected_exception>::type>::type, \
+ std::exception>::value, \
+ const ::testing::internal::NeverThrown&, const std::exception&>::type \
+ e) { \
+ gtest_msg.value = "Expected: " #statement \
+ " throws an exception of type " #expected_exception \
+ ".\n Actual: it throws "; \
+ gtest_msg.value += GTEST_EXCEPTION_TYPE_(e); \
+ gtest_msg.value += " with description \""; \
+ gtest_msg.value += e.what(); \
+ gtest_msg.value += "\"."; \
+ goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
+ }
+
+#else // GTEST_HAS_EXCEPTIONS
+
+#define GTEST_TEST_THROW_CATCH_STD_EXCEPTION_(statement, expected_exception)
+
+#endif // GTEST_HAS_EXCEPTIONS
+
+#define GTEST_TEST_THROW_(statement, expected_exception, fail) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (::testing::internal::TrueWithString gtest_msg{}) { \
+ bool gtest_caught_expected = false; \
+ try { \
+ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
+ } catch (expected_exception const&) { \
+ gtest_caught_expected = true; \
+ } \
+ GTEST_TEST_THROW_CATCH_STD_EXCEPTION_(statement, expected_exception) \
+ catch (...) { \
+ gtest_msg.value = "Expected: " #statement \
+ " throws an exception of type " #expected_exception \
+ ".\n Actual: it throws a different type."; \
+ goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
+ } \
+ if (!gtest_caught_expected) { \
+ gtest_msg.value = "Expected: " #statement \
+ " throws an exception of type " #expected_exception \
+ ".\n Actual: it throws nothing."; \
+ goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
+ } \
+ } else /*NOLINT*/ \
+ GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__) \
+ : fail(gtest_msg.value.c_str())
+
+#if GTEST_HAS_EXCEPTIONS
+
+#define GTEST_TEST_NO_THROW_CATCH_STD_EXCEPTION_() \
+ catch (std::exception const& e) { \
+ gtest_msg.value = "it throws "; \
+ gtest_msg.value += GTEST_EXCEPTION_TYPE_(e); \
+ gtest_msg.value += " with description \""; \
+ gtest_msg.value += e.what(); \
+ gtest_msg.value += "\"."; \
+ goto GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__); \
+ }
+
+#else // GTEST_HAS_EXCEPTIONS
+
+#define GTEST_TEST_NO_THROW_CATCH_STD_EXCEPTION_()
+
+#endif // GTEST_HAS_EXCEPTIONS
+
+#define GTEST_TEST_NO_THROW_(statement, fail) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (::testing::internal::TrueWithString gtest_msg{}) { \
+ try { \
+ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
+ } \
+ GTEST_TEST_NO_THROW_CATCH_STD_EXCEPTION_() \
+ catch (...) { \
+ gtest_msg.value = "it throws."; \
+ goto GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__); \
+ } \
+ } else \
+ GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__): \
+ fail(("Expected: " #statement " doesn't throw an exception.\n" \
+ " Actual: " + gtest_msg.value).c_str())
+
+#define GTEST_TEST_ANY_THROW_(statement, fail) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (::testing::internal::AlwaysTrue()) { \
+ bool gtest_caught_any = false; \
+ try { \
+ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
+ } \
+ catch (...) { \
+ gtest_caught_any = true; \
+ } \
+ if (!gtest_caught_any) { \
+ goto GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__); \
+ } \
+ } else \
+ GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__): \
+ fail("Expected: " #statement " throws an exception.\n" \
+ " Actual: it doesn't.")
+
+
+// Implements Boolean test assertions such as EXPECT_TRUE. expression can be
+// either a boolean expression or an AssertionResult. text is a textual
+// representation of expression as it was passed into the EXPECT_TRUE.
+#define GTEST_TEST_BOOLEAN_(expression, text, actual, expected, fail) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (const ::testing::AssertionResult gtest_ar_ = \
+ ::testing::AssertionResult(expression)) \
+ ; \
+ else \
+ fail(::testing::internal::GetBoolAssertionFailureMessage(\
+ gtest_ar_, text, #actual, #expected).c_str())
+
+#define GTEST_TEST_NO_FATAL_FAILURE_(statement, fail) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (::testing::internal::AlwaysTrue()) { \
+ ::testing::internal::HasNewFatalFailureHelper gtest_fatal_failure_checker; \
+ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
+ if (gtest_fatal_failure_checker.has_new_fatal_failure()) { \
+ goto GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__); \
+ } \
+ } else \
+ GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__): \
+ fail("Expected: " #statement " doesn't generate new fatal " \
+ "failures in the current thread.\n" \
+ " Actual: it does.")
+
+// Expands to the name of the class that implements the given test.
+#define GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) \
+ test_suite_name##_##test_name##_Test
+
+// Helper macro for defining tests.
+#define GTEST_TEST_(test_suite_name, test_name, parent_class, parent_id) \
+ static_assert(sizeof(GTEST_STRINGIFY_(test_suite_name)) > 1, \
+ "test_suite_name must not be empty"); \
+ static_assert(sizeof(GTEST_STRINGIFY_(test_name)) > 1, \
+ "test_name must not be empty"); \
+ class GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) \
+ : public parent_class { \
+ public: \
+ GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)() = default; \
+ ~GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)() override = default; \
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(GTEST_TEST_CLASS_NAME_(test_suite_name, \
+ test_name)); \
+ GTEST_DISALLOW_MOVE_AND_ASSIGN_(GTEST_TEST_CLASS_NAME_(test_suite_name, \
+ test_name)); \
+ \
+ private: \
+ void TestBody() override; \
+ static ::testing::TestInfo* const test_info_ GTEST_ATTRIBUTE_UNUSED_; \
+ }; \
+ \
+ ::testing::TestInfo* const GTEST_TEST_CLASS_NAME_(test_suite_name, \
+ test_name)::test_info_ = \
+ ::testing::internal::MakeAndRegisterTestInfo( \
+ #test_suite_name, #test_name, nullptr, nullptr, \
+ ::testing::internal::CodeLocation(__FILE__, __LINE__), (parent_id), \
+ ::testing::internal::SuiteApiResolver< \
+ parent_class>::GetSetUpCaseOrSuite(__FILE__, __LINE__), \
+ ::testing::internal::SuiteApiResolver< \
+ parent_class>::GetTearDownCaseOrSuite(__FILE__, __LINE__), \
+ new ::testing::internal::TestFactoryImpl<GTEST_TEST_CLASS_NAME_( \
+ test_suite_name, test_name)>); \
+ void GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)::TestBody()
+
+#endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+//
+// The Google C++ Testing and Mocking Framework (Google Test)
+//
+// This header file defines the public API for death tests. It is
+// #included by gtest.h so a user doesn't need to include this
+// directly.
+// GOOGLETEST_CM0001 DO NOT DELETE
+
+#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
+#define GOOGLETEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
+
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// The Google C++ Testing and Mocking Framework (Google Test)
+//
+// This header file defines internal utilities needed for implementing
+// death tests. They are subject to change without notice.
+// GOOGLETEST_CM0001 DO NOT DELETE
+
+#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
+#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
+
+// Copyright 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// The Google C++ Testing and Mocking Framework (Google Test)
+//
+// This file implements just enough of the matcher interface to allow
+// EXPECT_DEATH and friends to accept a matcher argument.
+
+#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_MATCHERS_H_
+#define GOOGLETEST_INCLUDE_GTEST_GTEST_MATCHERS_H_
+
+#include <atomic>
+#include <memory>
+#include <ostream>
+#include <string>
+#include <type_traits>
+
+// Copyright 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+// Google Test - The Google C++ Testing and Mocking Framework
+//
+// This file implements a universal value printer that can print a
+// value of any type T:
+//
+// void ::testing::internal::UniversalPrinter<T>::Print(value, ostream_ptr);
+//
+// A user can teach this function how to print a class type T by
+// defining either operator<<() or PrintTo() in the namespace that
+// defines T. More specifically, the FIRST defined function in the
+// following list will be used (assuming T is defined in namespace
+// foo):
+//
+// 1. foo::PrintTo(const T&, ostream*)
+// 2. operator<<(ostream&, const T&) defined in either foo or the
+// global namespace.
+//
+// However if T is an STL-style container then it is printed element-wise
+// unless foo::PrintTo(const T&, ostream*) is defined. Note that
+// operator<<() is ignored for container types.
+//
+// If none of the above is defined, it will print the debug string of
+// the value if it is a protocol buffer, or print the raw bytes in the
+// value otherwise.
+//
+// To aid debugging: when T is a reference type, the address of the
+// value is also printed; when T is a (const) char pointer, both the
+// pointer value and the NUL-terminated string it points to are
+// printed.
+//
+// We also provide some convenient wrappers:
+//
+// // Prints a value to a string. For a (const or not) char
+// // pointer, the NUL-terminated string (but not the pointer) is
+// // printed.
+// std::string ::testing::PrintToString(const T& value);
+//
+// // Prints a value tersely: for a reference type, the referenced
+// // value (but not the address) is printed; for a (const or not) char
+// // pointer, the NUL-terminated string (but not the pointer) is
+// // printed.
+// void ::testing::internal::UniversalTersePrint(const T& value, ostream*);
+//
+// // Prints value using the type inferred by the compiler. The difference
+// // from UniversalTersePrint() is that this function prints both the
+// // pointer and the NUL-terminated string for a (const or not) char pointer.
+// void ::testing::internal::UniversalPrint(const T& value, ostream*);
+//
+// // Prints the fields of a tuple tersely to a string vector, one
+// // element for each field. Tuple support must be enabled in
+// // gtest-port.h.
+// std::vector<string> UniversalTersePrintTupleFieldsToStrings(
+// const Tuple& value);
+//
+// Known limitation:
+//
+// The print primitives print the elements of an STL-style container
+// using the compiler-inferred type of *iter where iter is a
+// const_iterator of the container. When const_iterator is an input
+// iterator but not a forward iterator, this inferred type may not
+// match value_type, and the print output may be incorrect. In
+// practice, this is rarely a problem as for most containers
+// const_iterator is a forward iterator. We'll fix this if there's an
+// actual need for it. Note that this fix cannot rely on value_type
+// being defined as many user-defined container types don't have
+// value_type.
+
+// GOOGLETEST_CM0001 DO NOT DELETE
+
+#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_PRINTERS_H_
+#define GOOGLETEST_INCLUDE_GTEST_GTEST_PRINTERS_H_
+
+#include <functional>
+#include <memory>
+#include <ostream> // NOLINT
+#include <sstream>
+#include <string>
+#include <tuple>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+
+namespace testing {
+
+// Definitions in the internal* namespaces are subject to change without notice.
+// DO NOT USE THEM IN USER CODE!
+namespace internal {
+
+template <typename T>
+void UniversalPrint(const T& value, ::std::ostream* os);
+
+// Used to print an STL-style container when the user doesn't define
+// a PrintTo() for it.
+struct ContainerPrinter {
+ template <typename T,
+ typename = typename std::enable_if<
+ (sizeof(IsContainerTest<T>(0)) == sizeof(IsContainer)) &&
+ !IsRecursiveContainer<T>::value>::type>
+ static void PrintValue(const T& container, std::ostream* os) {
+ const size_t kMaxCount = 32; // The maximum number of elements to print.
+ *os << '{';
+ size_t count = 0;
+ for (auto&& elem : container) {
+ if (count > 0) {
+ *os << ',';
+ if (count == kMaxCount) { // Enough has been printed.
+ *os << " ...";
+ break;
+ }
+ }
+ *os << ' ';
+ // We cannot call PrintTo(elem, os) here as PrintTo() doesn't
+ // handle `elem` being a native array.
+ internal::UniversalPrint(elem, os);
+ ++count;
+ }
+
+ if (count > 0) {
+ *os << ' ';
+ }
+ *os << '}';
+ }
+};
+
+// Used to print a pointer that is neither a char pointer nor a member
+// pointer, when the user doesn't define PrintTo() for it. (A member
+// variable pointer or member function pointer doesn't really point to
+// a location in the address space. Their representation is
+// implementation-defined. Therefore they will be printed as raw
+// bytes.)
+struct FunctionPointerPrinter {
+ template <typename T, typename = typename std::enable_if<
+ std::is_function<T>::value>::type>
+ static void PrintValue(T* p, ::std::ostream* os) {
+ if (p == nullptr) {
+ *os << "NULL";
+ } else {
+ // T is a function type, so '*os << p' doesn't do what we want
+ // (it just prints p as bool). We want to print p as a const
+ // void*.
+ *os << reinterpret_cast<const void*>(p);
+ }
+ }
+};
+
+struct PointerPrinter {
+ template <typename T>
+ static void PrintValue(T* p, ::std::ostream* os) {
+ if (p == nullptr) {
+ *os << "NULL";
+ } else {
+ // T is not a function type. We just call << to print p,
+ // relying on ADL to pick up user-defined << for their pointer
+ // types, if any.
+ *os << p;
+ }
+ }
+};
+
+namespace internal_stream_operator_without_lexical_name_lookup {
+
+// The presence of an operator<< here will terminate lexical scope lookup
+// straight away (even though it cannot be a match because of its argument
+// types). Thus, the two operator<< calls in StreamPrinter will find only ADL
+// candidates.
+struct LookupBlocker {};
+void operator<<(LookupBlocker, LookupBlocker);
+
+struct StreamPrinter {
+ template <typename T,
+ // Don't accept member pointers here. We'd print them via implicit
+ // conversion to bool, which isn't useful.
+ typename = typename std::enable_if<
+ !std::is_member_pointer<T>::value>::type,
+ // Only accept types for which we can find a streaming operator via
+ // ADL (possibly involving implicit conversions).
+ typename = decltype(std::declval<std::ostream&>()
+ << std::declval<const T&>())>
+ static void PrintValue(const T& value, ::std::ostream* os) {
+ // Call streaming operator found by ADL, possibly with implicit conversions
+ // of the arguments.
+ *os << value;
+ }
+};
+
+} // namespace internal_stream_operator_without_lexical_name_lookup
+
+struct ProtobufPrinter {
+ // We print a protobuf using its ShortDebugString() when the string
+ // doesn't exceed this many characters; otherwise we print it using
+ // DebugString() for better readability.
+ static const size_t kProtobufOneLinerMaxLength = 50;
+
+ template <typename T,
+ typename = typename std::enable_if<
+ internal::HasDebugStringAndShortDebugString<T>::value>::type>
+ static void PrintValue(const T& value, ::std::ostream* os) {
+ std::string pretty_str = value.ShortDebugString();
+ if (pretty_str.length() > kProtobufOneLinerMaxLength) {
+ pretty_str = "\n" + value.DebugString();
+ }
+ *os << ("<" + pretty_str + ">");
+ }
+};
+
+struct ConvertibleToIntegerPrinter {
+ // Since T has no << operator or PrintTo() but can be implicitly
+ // converted to BiggestInt, we print it as a BiggestInt.
+ //
+ // Most likely T is an enum type (either named or unnamed), in which
+ // case printing it as an integer is the desired behavior. In case
+ // T is not an enum, printing it as an integer is the best we can do
+ // given that it has no user-defined printer.
+ static void PrintValue(internal::BiggestInt value, ::std::ostream* os) {
+ *os << value;
+ }
+};
+
+struct ConvertibleToStringViewPrinter {
+#if GTEST_INTERNAL_HAS_STRING_VIEW
+ static void PrintValue(internal::StringView value, ::std::ostream* os) {
+ internal::UniversalPrint(value, os);
+ }
+#endif
+};
+
+
+// Prints the given number of bytes in the given object to the given
+// ostream.
+GTEST_API_ void PrintBytesInObjectTo(const unsigned char* obj_bytes,
+ size_t count,
+ ::std::ostream* os);
+struct RawBytesPrinter {
+ // SFINAE on `sizeof` to make sure we have a complete type.
+ template <typename T, size_t = sizeof(T)>
+ static void PrintValue(const T& value, ::std::ostream* os) {
+ PrintBytesInObjectTo(
+ static_cast<const unsigned char*>(
+ // Load bearing cast to void* to support iOS
+ reinterpret_cast<const void*>(std::addressof(value))),
+ sizeof(value), os);
+ }
+};
+
+struct FallbackPrinter {
+ template <typename T>
+ static void PrintValue(const T&, ::std::ostream* os) {
+ *os << "(incomplete type)";
+ }
+};
+
+// Try every printer in order and return the first one that works.
+template <typename T, typename E, typename Printer, typename... Printers>
+struct FindFirstPrinter : FindFirstPrinter<T, E, Printers...> {};
+
+template <typename T, typename Printer, typename... Printers>
+struct FindFirstPrinter<
+ T, decltype(Printer::PrintValue(std::declval<const T&>(), nullptr)),
+ Printer, Printers...> {
+ using type = Printer;
+};
+
+// Select the best printer in the following order:
+// - Print containers (they have begin/end/etc).
+// - Print function pointers.
+// - Print object pointers.
+// - Use the stream operator, if available.
+// - Print protocol buffers.
+// - Print types convertible to BiggestInt.
+// - Print types convertible to StringView, if available.
+// - Fallback to printing the raw bytes of the object.
+template <typename T>
+void PrintWithFallback(const T& value, ::std::ostream* os) {
+ using Printer = typename FindFirstPrinter<
+ T, void, ContainerPrinter, FunctionPointerPrinter, PointerPrinter,
+ internal_stream_operator_without_lexical_name_lookup::StreamPrinter,
+ ProtobufPrinter, ConvertibleToIntegerPrinter,
+ ConvertibleToStringViewPrinter, RawBytesPrinter, FallbackPrinter>::type;
+ Printer::PrintValue(value, os);
+}
+
+// FormatForComparison<ToPrint, OtherOperand>::Format(value) formats a
+// value of type ToPrint that is an operand of a comparison assertion
+// (e.g. ASSERT_EQ). OtherOperand is the type of the other operand in
+// the comparison, and is used to help determine the best way to
+// format the value. In particular, when the value is a C string
+// (char pointer) and the other operand is an STL string object, we
+// want to format the C string as a string, since we know it is
+// compared by value with the string object. If the value is a char
+// pointer but the other operand is not an STL string object, we don't
+// know whether the pointer is supposed to point to a NUL-terminated
+// string, and thus want to print it as a pointer to be safe.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+
+// The default case.
+template <typename ToPrint, typename OtherOperand>
+class FormatForComparison {
+ public:
+ static ::std::string Format(const ToPrint& value) {
+ return ::testing::PrintToString(value);
+ }
+};
+
+// Array.
+template <typename ToPrint, size_t N, typename OtherOperand>
+class FormatForComparison<ToPrint[N], OtherOperand> {
+ public:
+ static ::std::string Format(const ToPrint* value) {
+ return FormatForComparison<const ToPrint*, OtherOperand>::Format(value);
+ }
+};
+
+// By default, print C string as pointers to be safe, as we don't know
+// whether they actually point to a NUL-terminated string.
+
+#define GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(CharType) \
+ template <typename OtherOperand> \
+ class FormatForComparison<CharType*, OtherOperand> { \
+ public: \
+ static ::std::string Format(CharType* value) { \
+ return ::testing::PrintToString(static_cast<const void*>(value)); \
+ } \
+ }
+
+GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(char);
+GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const char);
+GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(wchar_t);
+GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const wchar_t);
+#ifdef __cpp_lib_char8_t
+GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(char8_t);
+GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const char8_t);
+#endif
+GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(char16_t);
+GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const char16_t);
+GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(char32_t);
+GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const char32_t);
+
+#undef GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_
+
+// If a C string is compared with an STL string object, we know it's meant
+// to point to a NUL-terminated string, and thus can print it as a string.
+
+#define GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(CharType, OtherStringType) \
+ template <> \
+ class FormatForComparison<CharType*, OtherStringType> { \
+ public: \
+ static ::std::string Format(CharType* value) { \
+ return ::testing::PrintToString(value); \
+ } \
+ }
+
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::std::string);
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::std::string);
+#ifdef __cpp_char8_t
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char8_t, ::std::u8string);
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char8_t, ::std::u8string);
+#endif
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char16_t, ::std::u16string);
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char16_t, ::std::u16string);
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char32_t, ::std::u32string);
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char32_t, ::std::u32string);
+
+#if GTEST_HAS_STD_WSTRING
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::std::wstring);
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::std::wstring);
+#endif
+
+#undef GTEST_IMPL_FORMAT_C_STRING_AS_STRING_
+
+// Formats a comparison assertion (e.g. ASSERT_EQ, EXPECT_LT, and etc)
+// operand to be used in a failure message. The type (but not value)
+// of the other operand may affect the format. This allows us to
+// print a char* as a raw pointer when it is compared against another
+// char* or void*, and print it as a C string when it is compared
+// against an std::string object, for example.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+template <typename T1, typename T2>
+std::string FormatForComparisonFailureMessage(
+ const T1& value, const T2& /* other_operand */) {
+ return FormatForComparison<T1, T2>::Format(value);
+}
+
+// UniversalPrinter<T>::Print(value, ostream_ptr) prints the given
+// value to the given ostream. The caller must ensure that
+// 'ostream_ptr' is not NULL, or the behavior is undefined.
+//
+// We define UniversalPrinter as a class template (as opposed to a
+// function template), as we need to partially specialize it for
+// reference types, which cannot be done with function templates.
+template <typename T>
+class UniversalPrinter;
+
+// Prints the given value using the << operator if it has one;
+// otherwise prints the bytes in it. This is what
+// UniversalPrinter<T>::Print() does when PrintTo() is not specialized
+// or overloaded for type T.
+//
+// A user can override this behavior for a class type Foo by defining
+// an overload of PrintTo() in the namespace where Foo is defined. We
+// give the user this option as sometimes defining a << operator for
+// Foo is not desirable (e.g. the coding style may prevent doing it,
+// or there is already a << operator but it doesn't do what the user
+// wants).
+template <typename T>
+void PrintTo(const T& value, ::std::ostream* os) {
+ internal::PrintWithFallback(value, os);
+}
+
+// The following list of PrintTo() overloads tells
+// UniversalPrinter<T>::Print() how to print standard types (built-in
+// types, strings, plain arrays, and pointers).
+
+// Overloads for various char types.
+GTEST_API_ void PrintTo(unsigned char c, ::std::ostream* os);
+GTEST_API_ void PrintTo(signed char c, ::std::ostream* os);
+inline void PrintTo(char c, ::std::ostream* os) {
+ // When printing a plain char, we always treat it as unsigned. This
+ // way, the output won't be affected by whether the compiler thinks
+ // char is signed or not.
+ PrintTo(static_cast<unsigned char>(c), os);
+}
+
+// Overloads for other simple built-in types.
+inline void PrintTo(bool x, ::std::ostream* os) {
+ *os << (x ? "true" : "false");
+}
+
+// Overload for wchar_t type.
+// Prints a wchar_t as a symbol if it is printable or as its internal
+// code otherwise and also as its decimal code (except for L'\0').
+// The L'\0' char is printed as "L'\\0'". The decimal code is printed
+// as signed integer when wchar_t is implemented by the compiler
+// as a signed type and is printed as an unsigned integer when wchar_t
+// is implemented as an unsigned type.
+GTEST_API_ void PrintTo(wchar_t wc, ::std::ostream* os);
+
+GTEST_API_ void PrintTo(char32_t c, ::std::ostream* os);
+inline void PrintTo(char16_t c, ::std::ostream* os) {
+ PrintTo(ImplicitCast_<char32_t>(c), os);
+}
+#ifdef __cpp_char8_t
+inline void PrintTo(char8_t c, ::std::ostream* os) {
+ PrintTo(ImplicitCast_<char32_t>(c), os);
+}
+#endif
+
+// Overloads for C strings.
+GTEST_API_ void PrintTo(const char* s, ::std::ostream* os);
+inline void PrintTo(char* s, ::std::ostream* os) {
+ PrintTo(ImplicitCast_<const char*>(s), os);
+}
+
+// signed/unsigned char is often used for representing binary data, so
+// we print pointers to it as void* to be safe.
+inline void PrintTo(const signed char* s, ::std::ostream* os) {
+ PrintTo(ImplicitCast_<const void*>(s), os);
+}
+inline void PrintTo(signed char* s, ::std::ostream* os) {
+ PrintTo(ImplicitCast_<const void*>(s), os);
+}
+inline void PrintTo(const unsigned char* s, ::std::ostream* os) {
+ PrintTo(ImplicitCast_<const void*>(s), os);
+}
+inline void PrintTo(unsigned char* s, ::std::ostream* os) {
+ PrintTo(ImplicitCast_<const void*>(s), os);
+}
+#ifdef __cpp_char8_t
+// Overloads for u8 strings.
+GTEST_API_ void PrintTo(const char8_t* s, ::std::ostream* os);
+inline void PrintTo(char8_t* s, ::std::ostream* os) {
+ PrintTo(ImplicitCast_<const char8_t*>(s), os);
+}
+#endif
+// Overloads for u16 strings.
+GTEST_API_ void PrintTo(const char16_t* s, ::std::ostream* os);
+inline void PrintTo(char16_t* s, ::std::ostream* os) {
+ PrintTo(ImplicitCast_<const char16_t*>(s), os);
+}
+// Overloads for u32 strings.
+GTEST_API_ void PrintTo(const char32_t* s, ::std::ostream* os);
+inline void PrintTo(char32_t* s, ::std::ostream* os) {
+ PrintTo(ImplicitCast_<const char32_t*>(s), os);
+}
+
+// MSVC can be configured to define wchar_t as a typedef of unsigned
+// short. It defines _NATIVE_WCHAR_T_DEFINED when wchar_t is a native
+// type. When wchar_t is a typedef, defining an overload for const
+// wchar_t* would cause unsigned short* be printed as a wide string,
+// possibly causing invalid memory accesses.
+#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
+// Overloads for wide C strings
+GTEST_API_ void PrintTo(const wchar_t* s, ::std::ostream* os);
+inline void PrintTo(wchar_t* s, ::std::ostream* os) {
+ PrintTo(ImplicitCast_<const wchar_t*>(s), os);
+}
+#endif
+
+// Overload for C arrays. Multi-dimensional arrays are printed
+// properly.
+
+// Prints the given number of elements in an array, without printing
+// the curly braces.
+template <typename T>
+void PrintRawArrayTo(const T a[], size_t count, ::std::ostream* os) {
+ UniversalPrint(a[0], os);
+ for (size_t i = 1; i != count; i++) {
+ *os << ", ";
+ UniversalPrint(a[i], os);
+ }
+}
+
+// Overloads for ::std::string.
+GTEST_API_ void PrintStringTo(const ::std::string&s, ::std::ostream* os);
+inline void PrintTo(const ::std::string& s, ::std::ostream* os) {
+ PrintStringTo(s, os);
+}
+
+// Overloads for ::std::u8string
+#ifdef __cpp_char8_t
+GTEST_API_ void PrintU8StringTo(const ::std::u8string& s, ::std::ostream* os);
+inline void PrintTo(const ::std::u8string& s, ::std::ostream* os) {
+ PrintU8StringTo(s, os);
+}
+#endif
+
+// Overloads for ::std::u16string
+GTEST_API_ void PrintU16StringTo(const ::std::u16string& s, ::std::ostream* os);
+inline void PrintTo(const ::std::u16string& s, ::std::ostream* os) {
+ PrintU16StringTo(s, os);
+}
+
+// Overloads for ::std::u32string
+GTEST_API_ void PrintU32StringTo(const ::std::u32string& s, ::std::ostream* os);
+inline void PrintTo(const ::std::u32string& s, ::std::ostream* os) {
+ PrintU32StringTo(s, os);
+}
+
+// Overloads for ::std::wstring.
+#if GTEST_HAS_STD_WSTRING
+GTEST_API_ void PrintWideStringTo(const ::std::wstring&s, ::std::ostream* os);
+inline void PrintTo(const ::std::wstring& s, ::std::ostream* os) {
+ PrintWideStringTo(s, os);
+}
+#endif // GTEST_HAS_STD_WSTRING
+
+#if GTEST_INTERNAL_HAS_STRING_VIEW
+// Overload for internal::StringView.
+inline void PrintTo(internal::StringView sp, ::std::ostream* os) {
+ PrintTo(::std::string(sp), os);
+}
+#endif // GTEST_INTERNAL_HAS_STRING_VIEW
+
+inline void PrintTo(std::nullptr_t, ::std::ostream* os) { *os << "(nullptr)"; }
+
+template <typename T>
+void PrintTo(std::reference_wrapper<T> ref, ::std::ostream* os) {
+ UniversalPrinter<T&>::Print(ref.get(), os);
+}
+
+inline const void* VoidifyPointer(const void* p) { return p; }
+inline const void* VoidifyPointer(volatile const void* p) {
+ return const_cast<const void*>(p);
+}
+
+template <typename T, typename Ptr>
+void PrintSmartPointer(const Ptr& ptr, std::ostream* os, char) {
+ if (ptr == nullptr) {
+ *os << "(nullptr)";
+ } else {
+ // We can't print the value. Just print the pointer..
+ *os << "(" << (VoidifyPointer)(ptr.get()) << ")";
+ }
+}
+template <typename T, typename Ptr,
+ typename = typename std::enable_if<!std::is_void<T>::value &&
+ !std::is_array<T>::value>::type>
+void PrintSmartPointer(const Ptr& ptr, std::ostream* os, int) {
+ if (ptr == nullptr) {
+ *os << "(nullptr)";
+ } else {
+ *os << "(ptr = " << (VoidifyPointer)(ptr.get()) << ", value = ";
+ UniversalPrinter<T>::Print(*ptr, os);
+ *os << ")";
+ }
+}
+
+template <typename T, typename D>
+void PrintTo(const std::unique_ptr<T, D>& ptr, std::ostream* os) {
+ (PrintSmartPointer<T>)(ptr, os, 0);
+}
+
+template <typename T>
+void PrintTo(const std::shared_ptr<T>& ptr, std::ostream* os) {
+ (PrintSmartPointer<T>)(ptr, os, 0);
+}
+
+// Helper function for printing a tuple. T must be instantiated with
+// a tuple type.
+template <typename T>
+void PrintTupleTo(const T&, std::integral_constant<size_t, 0>,
+ ::std::ostream*) {}
+
+template <typename T, size_t I>
+void PrintTupleTo(const T& t, std::integral_constant<size_t, I>,
+ ::std::ostream* os) {
+ PrintTupleTo(t, std::integral_constant<size_t, I - 1>(), os);
+ GTEST_INTENTIONAL_CONST_COND_PUSH_()
+ if (I > 1) {
+ GTEST_INTENTIONAL_CONST_COND_POP_()
+ *os << ", ";
+ }
+ UniversalPrinter<typename std::tuple_element<I - 1, T>::type>::Print(
+ std::get<I - 1>(t), os);
+}
+
+template <typename... Types>
+void PrintTo(const ::std::tuple<Types...>& t, ::std::ostream* os) {
+ *os << "(";
+ PrintTupleTo(t, std::integral_constant<size_t, sizeof...(Types)>(), os);
+ *os << ")";
+}
+
+// Overload for std::pair.
+template <typename T1, typename T2>
+void PrintTo(const ::std::pair<T1, T2>& value, ::std::ostream* os) {
+ *os << '(';
+ // We cannot use UniversalPrint(value.first, os) here, as T1 may be
+ // a reference type. The same for printing value.second.
+ UniversalPrinter<T1>::Print(value.first, os);
+ *os << ", ";
+ UniversalPrinter<T2>::Print(value.second, os);
+ *os << ')';
+}
+
+// Implements printing a non-reference type T by letting the compiler
+// pick the right overload of PrintTo() for T.
+template <typename T>
+class UniversalPrinter {
+ public:
+ // MSVC warns about adding const to a function type, so we want to
+ // disable the warning.
+ GTEST_DISABLE_MSC_WARNINGS_PUSH_(4180)
+
+ // Note: we deliberately don't call this PrintTo(), as that name
+ // conflicts with ::testing::internal::PrintTo in the body of the
+ // function.
+ static void Print(const T& value, ::std::ostream* os) {
+ // By default, ::testing::internal::PrintTo() is used for printing
+ // the value.
+ //
+ // Thanks to Koenig look-up, if T is a class and has its own
+ // PrintTo() function defined in its namespace, that function will
+ // be visible here. Since it is more specific than the generic ones
+ // in ::testing::internal, it will be picked by the compiler in the
+ // following statement - exactly what we want.
+ PrintTo(value, os);
+ }
+
+ GTEST_DISABLE_MSC_WARNINGS_POP_()
+};
+
+// Remove any const-qualifiers before passing a type to UniversalPrinter.
+template <typename T>
+class UniversalPrinter<const T> : public UniversalPrinter<T> {};
+
+#if GTEST_INTERNAL_HAS_ANY
+
+// Printer for std::any / absl::any
+
+template <>
+class UniversalPrinter<Any> {
+ public:
+ static void Print(const Any& value, ::std::ostream* os) {
+ if (value.has_value()) {
+ *os << "value of type " << GetTypeName(value);
+ } else {
+ *os << "no value";
+ }
+ }
+
+ private:
+ static std::string GetTypeName(const Any& value) {
+#if GTEST_HAS_RTTI
+ return internal::GetTypeName(value.type());
+#else
+ static_cast<void>(value); // possibly unused
+ return "<unknown_type>";
+#endif // GTEST_HAS_RTTI
+ }
+};
+
+#endif // GTEST_INTERNAL_HAS_ANY
+
+#if GTEST_INTERNAL_HAS_OPTIONAL
+
+// Printer for std::optional / absl::optional
+
+template <typename T>
+class UniversalPrinter<Optional<T>> {
+ public:
+ static void Print(const Optional<T>& value, ::std::ostream* os) {
+ *os << '(';
+ if (!value) {
+ *os << "nullopt";
+ } else {
+ UniversalPrint(*value, os);
+ }
+ *os << ')';
+ }
+};
+
+#endif // GTEST_INTERNAL_HAS_OPTIONAL
+
+#if GTEST_INTERNAL_HAS_VARIANT
+
+// Printer for std::variant / absl::variant
+
+template <typename... T>
+class UniversalPrinter<Variant<T...>> {
+ public:
+ static void Print(const Variant<T...>& value, ::std::ostream* os) {
+ *os << '(';
+#if GTEST_HAS_ABSL
+ absl::visit(Visitor{os, value.index()}, value);
+#else
+ std::visit(Visitor{os, value.index()}, value);
+#endif // GTEST_HAS_ABSL
+ *os << ')';
+ }
+
+ private:
+ struct Visitor {
+ template <typename U>
+ void operator()(const U& u) const {
+ *os << "'" << GetTypeName<U>() << "(index = " << index
+ << ")' with value ";
+ UniversalPrint(u, os);
+ }
+ ::std::ostream* os;
+ std::size_t index;
+ };
+};
+
+#endif // GTEST_INTERNAL_HAS_VARIANT
+
+// UniversalPrintArray(begin, len, os) prints an array of 'len'
+// elements, starting at address 'begin'.
+template <typename T>
+void UniversalPrintArray(const T* begin, size_t len, ::std::ostream* os) {
+ if (len == 0) {
+ *os << "{}";
+ } else {
+ *os << "{ ";
+ const size_t kThreshold = 18;
+ const size_t kChunkSize = 8;
+ // If the array has more than kThreshold elements, we'll have to
+ // omit some details by printing only the first and the last
+ // kChunkSize elements.
+ if (len <= kThreshold) {
+ PrintRawArrayTo(begin, len, os);
+ } else {
+ PrintRawArrayTo(begin, kChunkSize, os);
+ *os << ", ..., ";
+ PrintRawArrayTo(begin + len - kChunkSize, kChunkSize, os);
+ }
+ *os << " }";
+ }
+}
+// This overload prints a (const) char array compactly.
+GTEST_API_ void UniversalPrintArray(
+ const char* begin, size_t len, ::std::ostream* os);
+
+#ifdef __cpp_char8_t
+// This overload prints a (const) char8_t array compactly.
+GTEST_API_ void UniversalPrintArray(const char8_t* begin, size_t len,
+ ::std::ostream* os);
+#endif
+
+// This overload prints a (const) char16_t array compactly.
+GTEST_API_ void UniversalPrintArray(const char16_t* begin, size_t len,
+ ::std::ostream* os);
+
+// This overload prints a (const) char32_t array compactly.
+GTEST_API_ void UniversalPrintArray(const char32_t* begin, size_t len,
+ ::std::ostream* os);
+
+// This overload prints a (const) wchar_t array compactly.
+GTEST_API_ void UniversalPrintArray(
+ const wchar_t* begin, size_t len, ::std::ostream* os);
+
+// Implements printing an array type T[N].
+template <typename T, size_t N>
+class UniversalPrinter<T[N]> {
+ public:
+ // Prints the given array, omitting some elements when there are too
+ // many.
+ static void Print(const T (&a)[N], ::std::ostream* os) {
+ UniversalPrintArray(a, N, os);
+ }
+};
+
+// Implements printing a reference type T&.
+template <typename T>
+class UniversalPrinter<T&> {
+ public:
+ // MSVC warns about adding const to a function type, so we want to
+ // disable the warning.
+ GTEST_DISABLE_MSC_WARNINGS_PUSH_(4180)
+
+ static void Print(const T& value, ::std::ostream* os) {
+ // Prints the address of the value. We use reinterpret_cast here
+ // as static_cast doesn't compile when T is a function type.
+ *os << "@" << reinterpret_cast<const void*>(&value) << " ";
+
+ // Then prints the value itself.
+ UniversalPrint(value, os);
+ }
+
+ GTEST_DISABLE_MSC_WARNINGS_POP_()
+};
+
+// Prints a value tersely: for a reference type, the referenced value
+// (but not the address) is printed; for a (const) char pointer, the
+// NUL-terminated string (but not the pointer) is printed.
+
+template <typename T>
+class UniversalTersePrinter {
+ public:
+ static void Print(const T& value, ::std::ostream* os) {
+ UniversalPrint(value, os);
+ }
+};
+template <typename T>
+class UniversalTersePrinter<T&> {
+ public:
+ static void Print(const T& value, ::std::ostream* os) {
+ UniversalPrint(value, os);
+ }
+};
+template <typename T, size_t N>
+class UniversalTersePrinter<T[N]> {
+ public:
+ static void Print(const T (&value)[N], ::std::ostream* os) {
+ UniversalPrinter<T[N]>::Print(value, os);
+ }
+};
+template <>
+class UniversalTersePrinter<const char*> {
+ public:
+ static void Print(const char* str, ::std::ostream* os) {
+ if (str == nullptr) {
+ *os << "NULL";
+ } else {
+ UniversalPrint(std::string(str), os);
+ }
+ }
+};
+template <>
+class UniversalTersePrinter<char*> : public UniversalTersePrinter<const char*> {
+};
+
+#ifdef __cpp_char8_t
+template <>
+class UniversalTersePrinter<const char8_t*> {
+ public:
+ static void Print(const char8_t* str, ::std::ostream* os) {
+ if (str == nullptr) {
+ *os << "NULL";
+ } else {
+ UniversalPrint(::std::u8string(str), os);
+ }
+ }
+};
+template <>
+class UniversalTersePrinter<char8_t*>
+ : public UniversalTersePrinter<const char8_t*> {};
+#endif
+
+template <>
+class UniversalTersePrinter<const char16_t*> {
+ public:
+ static void Print(const char16_t* str, ::std::ostream* os) {
+ if (str == nullptr) {
+ *os << "NULL";
+ } else {
+ UniversalPrint(::std::u16string(str), os);
+ }
+ }
+};
+template <>
+class UniversalTersePrinter<char16_t*>
+ : public UniversalTersePrinter<const char16_t*> {};
+
+template <>
+class UniversalTersePrinter<const char32_t*> {
+ public:
+ static void Print(const char32_t* str, ::std::ostream* os) {
+ if (str == nullptr) {
+ *os << "NULL";
+ } else {
+ UniversalPrint(::std::u32string(str), os);
+ }
+ }
+};
+template <>
+class UniversalTersePrinter<char32_t*>
+ : public UniversalTersePrinter<const char32_t*> {};
+
+#if GTEST_HAS_STD_WSTRING
+template <>
+class UniversalTersePrinter<const wchar_t*> {
+ public:
+ static void Print(const wchar_t* str, ::std::ostream* os) {
+ if (str == nullptr) {
+ *os << "NULL";
+ } else {
+ UniversalPrint(::std::wstring(str), os);
+ }
+ }
+};
+#endif
+
+template <>
+class UniversalTersePrinter<wchar_t*> {
+ public:
+ static void Print(wchar_t* str, ::std::ostream* os) {
+ UniversalTersePrinter<const wchar_t*>::Print(str, os);
+ }
+};
+
+template <typename T>
+void UniversalTersePrint(const T& value, ::std::ostream* os) {
+ UniversalTersePrinter<T>::Print(value, os);
+}
+
+// Prints a value using the type inferred by the compiler. The
+// difference between this and UniversalTersePrint() is that for a
+// (const) char pointer, this prints both the pointer and the
+// NUL-terminated string.
+template <typename T>
+void UniversalPrint(const T& value, ::std::ostream* os) {
+ // A workarond for the bug in VC++ 7.1 that prevents us from instantiating
+ // UniversalPrinter with T directly.
+ typedef T T1;
+ UniversalPrinter<T1>::Print(value, os);
+}
+
+typedef ::std::vector< ::std::string> Strings;
+
+ // Tersely prints the first N fields of a tuple to a string vector,
+ // one element for each field.
+template <typename Tuple>
+void TersePrintPrefixToStrings(const Tuple&, std::integral_constant<size_t, 0>,
+ Strings*) {}
+template <typename Tuple, size_t I>
+void TersePrintPrefixToStrings(const Tuple& t,
+ std::integral_constant<size_t, I>,
+ Strings* strings) {
+ TersePrintPrefixToStrings(t, std::integral_constant<size_t, I - 1>(),
+ strings);
+ ::std::stringstream ss;
+ UniversalTersePrint(std::get<I - 1>(t), &ss);
+ strings->push_back(ss.str());
+}
+
+// Prints the fields of a tuple tersely to a string vector, one
+// element for each field. See the comment before
+// UniversalTersePrint() for how we define "tersely".
+template <typename Tuple>
+Strings UniversalTersePrintTupleFieldsToStrings(const Tuple& value) {
+ Strings result;
+ TersePrintPrefixToStrings(
+ value, std::integral_constant<size_t, std::tuple_size<Tuple>::value>(),
+ &result);
+ return result;
+}
+
+} // namespace internal
+
+template <typename T>
+::std::string PrintToString(const T& value) {
+ ::std::stringstream ss;
+ internal::UniversalTersePrinter<T>::Print(value, &ss);
+ return ss.str();
+}
+
+} // namespace testing
+
+// Include any custom printer added by the local installation.
+// We must include this header at the end to make sure it can use the
+// declarations from this file.
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// This file provides an injection point for custom printers in a local
+// installation of gTest.
+// It will be included from gtest-printers.h and the overrides in this file
+// will be visible to everyone.
+//
+// Injection point for custom user configurations. See README for details
+//
+// ** Custom implementation starts here **
+
+#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_
+#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_
+
+#endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_
+
+#endif // GOOGLETEST_INCLUDE_GTEST_GTEST_PRINTERS_H_
+
+// MSVC warning C5046 is new as of VS2017 version 15.8.
+#if defined(_MSC_VER) && _MSC_VER >= 1915
+#define GTEST_MAYBE_5046_ 5046
+#else
+#define GTEST_MAYBE_5046_
+#endif
+
+GTEST_DISABLE_MSC_WARNINGS_PUSH_(
+ 4251 GTEST_MAYBE_5046_ /* class A needs to have dll-interface to be used by
+ clients of class B */
+ /* Symbol involving type with internal linkage not defined */)
+
+namespace testing {
+
+// To implement a matcher Foo for type T, define:
+// 1. a class FooMatcherMatcher that implements the matcher interface:
+// using is_gtest_matcher = void;
+// bool MatchAndExplain(const T&, std::ostream*);
+// (MatchResultListener* can also be used instead of std::ostream*)
+// void DescribeTo(std::ostream*);
+// void DescribeNegationTo(std::ostream*);
+//
+// 2. a factory function that creates a Matcher<T> object from a
+// FooMatcherMatcher.
+
+class MatchResultListener {
+ public:
+ // Creates a listener object with the given underlying ostream. The
+ // listener does not own the ostream, and does not dereference it
+ // in the constructor or destructor.
+ explicit MatchResultListener(::std::ostream* os) : stream_(os) {}
+ virtual ~MatchResultListener() = 0; // Makes this class abstract.
+
+ // Streams x to the underlying ostream; does nothing if the ostream
+ // is NULL.
+ template <typename T>
+ MatchResultListener& operator<<(const T& x) {
+ if (stream_ != nullptr) *stream_ << x;
+ return *this;
+ }
+
+ // Returns the underlying ostream.
+ ::std::ostream* stream() { return stream_; }
+
+ // Returns true if and only if the listener is interested in an explanation
+ // of the match result. A matcher's MatchAndExplain() method can use
+ // this information to avoid generating the explanation when no one
+ // intends to hear it.
+ bool IsInterested() const { return stream_ != nullptr; }
+
+ private:
+ ::std::ostream* const stream_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(MatchResultListener);
+};
+
+inline MatchResultListener::~MatchResultListener() {
+}
+
+// An instance of a subclass of this knows how to describe itself as a
+// matcher.
+class GTEST_API_ MatcherDescriberInterface {
+ public:
+ virtual ~MatcherDescriberInterface() {}
+
+ // Describes this matcher to an ostream. The function should print
+ // a verb phrase that describes the property a value matching this
+ // matcher should have. The subject of the verb phrase is the value
+ // being matched. For example, the DescribeTo() method of the Gt(7)
+ // matcher prints "is greater than 7".
+ virtual void DescribeTo(::std::ostream* os) const = 0;
+
+ // Describes the negation of this matcher to an ostream. For
+ // example, if the description of this matcher is "is greater than
+ // 7", the negated description could be "is not greater than 7".
+ // You are not required to override this when implementing
+ // MatcherInterface, but it is highly advised so that your matcher
+ // can produce good error messages.
+ virtual void DescribeNegationTo(::std::ostream* os) const {
+ *os << "not (";
+ DescribeTo(os);
+ *os << ")";
+ }
+};
+
+// The implementation of a matcher.
+template <typename T>
+class MatcherInterface : public MatcherDescriberInterface {
+ public:
+ // Returns true if and only if the matcher matches x; also explains the
+ // match result to 'listener' if necessary (see the next paragraph), in
+ // the form of a non-restrictive relative clause ("which ...",
+ // "whose ...", etc) that describes x. For example, the
+ // MatchAndExplain() method of the Pointee(...) matcher should
+ // generate an explanation like "which points to ...".
+ //
+ // Implementations of MatchAndExplain() should add an explanation of
+ // the match result *if and only if* they can provide additional
+ // information that's not already present (or not obvious) in the
+ // print-out of x and the matcher's description. Whether the match
+ // succeeds is not a factor in deciding whether an explanation is
+ // needed, as sometimes the caller needs to print a failure message
+ // when the match succeeds (e.g. when the matcher is used inside
+ // Not()).
+ //
+ // For example, a "has at least 10 elements" matcher should explain
+ // what the actual element count is, regardless of the match result,
+ // as it is useful information to the reader; on the other hand, an
+ // "is empty" matcher probably only needs to explain what the actual
+ // size is when the match fails, as it's redundant to say that the
+ // size is 0 when the value is already known to be empty.
+ //
+ // You should override this method when defining a new matcher.
+ //
+ // It's the responsibility of the caller (Google Test) to guarantee
+ // that 'listener' is not NULL. This helps to simplify a matcher's
+ // implementation when it doesn't care about the performance, as it
+ // can talk to 'listener' without checking its validity first.
+ // However, in order to implement dummy listeners efficiently,
+ // listener->stream() may be NULL.
+ virtual bool MatchAndExplain(T x, MatchResultListener* listener) const = 0;
+
+ // Inherits these methods from MatcherDescriberInterface:
+ // virtual void DescribeTo(::std::ostream* os) const = 0;
+ // virtual void DescribeNegationTo(::std::ostream* os) const;
+};
+
+namespace internal {
+
+struct AnyEq {
+ template <typename A, typename B>
+ bool operator()(const A& a, const B& b) const { return a == b; }
+};
+struct AnyNe {
+ template <typename A, typename B>
+ bool operator()(const A& a, const B& b) const { return a != b; }
+};
+struct AnyLt {
+ template <typename A, typename B>
+ bool operator()(const A& a, const B& b) const { return a < b; }
+};
+struct AnyGt {
+ template <typename A, typename B>
+ bool operator()(const A& a, const B& b) const { return a > b; }
+};
+struct AnyLe {
+ template <typename A, typename B>
+ bool operator()(const A& a, const B& b) const { return a <= b; }
+};
+struct AnyGe {
+ template <typename A, typename B>
+ bool operator()(const A& a, const B& b) const { return a >= b; }
+};
+
+// A match result listener that ignores the explanation.
+class DummyMatchResultListener : public MatchResultListener {
+ public:
+ DummyMatchResultListener() : MatchResultListener(nullptr) {}
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(DummyMatchResultListener);
+};
+
+// A match result listener that forwards the explanation to a given
+// ostream. The difference between this and MatchResultListener is
+// that the former is concrete.
+class StreamMatchResultListener : public MatchResultListener {
+ public:
+ explicit StreamMatchResultListener(::std::ostream* os)
+ : MatchResultListener(os) {}
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(StreamMatchResultListener);
+};
+
+struct SharedPayloadBase {
+ std::atomic<int> ref{1};
+ void Ref() { ref.fetch_add(1, std::memory_order_relaxed); }
+ bool Unref() { return ref.fetch_sub(1, std::memory_order_acq_rel) == 1; }
+};
+
+template <typename T>
+struct SharedPayload : SharedPayloadBase {
+ explicit SharedPayload(const T& v) : value(v) {}
+ explicit SharedPayload(T&& v) : value(std::move(v)) {}
+
+ static void Destroy(SharedPayloadBase* shared) {
+ delete static_cast<SharedPayload*>(shared);
+ }
+
+ T value;
+};
+
+// An internal class for implementing Matcher<T>, which will derive
+// from it. We put functionalities common to all Matcher<T>
+// specializations here to avoid code duplication.
+template <typename T>
+class MatcherBase : private MatcherDescriberInterface {
+ public:
+ // Returns true if and only if the matcher matches x; also explains the
+ // match result to 'listener'.
+ bool MatchAndExplain(const T& x, MatchResultListener* listener) const {
+ GTEST_CHECK_(vtable_ != nullptr);
+ return vtable_->match_and_explain(*this, x, listener);
+ }
+
+ // Returns true if and only if this matcher matches x.
+ bool Matches(const T& x) const {
+ DummyMatchResultListener dummy;
+ return MatchAndExplain(x, &dummy);
+ }
+
+ // Describes this matcher to an ostream.
+ void DescribeTo(::std::ostream* os) const final {
+ GTEST_CHECK_(vtable_ != nullptr);
+ vtable_->describe(*this, os, false);
+ }
+
+ // Describes the negation of this matcher to an ostream.
+ void DescribeNegationTo(::std::ostream* os) const final {
+ GTEST_CHECK_(vtable_ != nullptr);
+ vtable_->describe(*this, os, true);
+ }
+
+ // Explains why x matches, or doesn't match, the matcher.
+ void ExplainMatchResultTo(const T& x, ::std::ostream* os) const {
+ StreamMatchResultListener listener(os);
+ MatchAndExplain(x, &listener);
+ }
+
+ // Returns the describer for this matcher object; retains ownership
+ // of the describer, which is only guaranteed to be alive when
+ // this matcher object is alive.
+ const MatcherDescriberInterface* GetDescriber() const {
+ if (vtable_ == nullptr) return nullptr;
+ return vtable_->get_describer(*this);
+ }
+
+ protected:
+ MatcherBase() : vtable_(nullptr) {}
+
+ // Constructs a matcher from its implementation.
+ template <typename U>
+ explicit MatcherBase(const MatcherInterface<U>* impl) {
+ Init(impl);
+ }
+
+ template <typename M, typename = typename std::remove_reference<
+ M>::type::is_gtest_matcher>
+ MatcherBase(M&& m) { // NOLINT
+ Init(std::forward<M>(m));
+ }
+
+ MatcherBase(const MatcherBase& other)
+ : vtable_(other.vtable_), buffer_(other.buffer_) {
+ if (IsShared()) buffer_.shared->Ref();
+ }
+
+ MatcherBase& operator=(const MatcherBase& other) {
+ if (this == &other) return *this;
+ Destroy();
+ vtable_ = other.vtable_;
+ buffer_ = other.buffer_;
+ if (IsShared()) buffer_.shared->Ref();
+ return *this;
+ }
+
+ MatcherBase(MatcherBase&& other)
+ : vtable_(other.vtable_), buffer_(other.buffer_) {
+ other.vtable_ = nullptr;
+ }
+
+ MatcherBase& operator=(MatcherBase&& other) {
+ if (this == &other) return *this;
+ Destroy();
+ vtable_ = other.vtable_;
+ buffer_ = other.buffer_;
+ other.vtable_ = nullptr;
+ return *this;
+ }
+
+ ~MatcherBase() override { Destroy(); }
+
+ private:
+ struct VTable {
+ bool (*match_and_explain)(const MatcherBase&, const T&,
+ MatchResultListener*);
+ void (*describe)(const MatcherBase&, std::ostream*, bool negation);
+ // Returns the captured object if it implements the interface, otherwise
+ // returns the MatcherBase itself.
+ const MatcherDescriberInterface* (*get_describer)(const MatcherBase&);
+ // Called on shared instances when the reference count reaches 0.
+ void (*shared_destroy)(SharedPayloadBase*);
+ };
+
+ bool IsShared() const {
+ return vtable_ != nullptr && vtable_->shared_destroy != nullptr;
+ }
+
+ // If the implementation uses a listener, call that.
+ template <typename P>
+ static auto MatchAndExplainImpl(const MatcherBase& m, const T& value,
+ MatchResultListener* listener)
+ -> decltype(P::Get(m).MatchAndExplain(value, listener->stream())) {
+ return P::Get(m).MatchAndExplain(value, listener->stream());
+ }
+
+ template <typename P>
+ static auto MatchAndExplainImpl(const MatcherBase& m, const T& value,
+ MatchResultListener* listener)
+ -> decltype(P::Get(m).MatchAndExplain(value, listener)) {
+ return P::Get(m).MatchAndExplain(value, listener);
+ }
+
+ template <typename P>
+ static void DescribeImpl(const MatcherBase& m, std::ostream* os,
+ bool negation) {
+ if (negation) {
+ P::Get(m).DescribeNegationTo(os);
+ } else {
+ P::Get(m).DescribeTo(os);
+ }
+ }
+
+ template <typename P>
+ static const MatcherDescriberInterface* GetDescriberImpl(
+ const MatcherBase& m) {
+ // If the impl is a MatcherDescriberInterface, then return it.
+ // Otherwise use MatcherBase itself.
+ // This allows us to implement the GetDescriber() function without support
+ // from the impl, but some users really want to get their impl back when
+ // they call GetDescriber().
+ // We use std::get on a tuple as a workaround of not having `if constexpr`.
+ return std::get<(
+ std::is_convertible<decltype(&P::Get(m)),
+ const MatcherDescriberInterface*>::value
+ ? 1
+ : 0)>(std::make_tuple(&m, &P::Get(m)));
+ }
+
+ template <typename P>
+ const VTable* GetVTable() {
+ static constexpr VTable kVTable = {&MatchAndExplainImpl<P>,
+ &DescribeImpl<P>, &GetDescriberImpl<P>,
+ P::shared_destroy};
+ return &kVTable;
+ }
+
+ union Buffer {
+ // Add some types to give Buffer some common alignment/size use cases.
+ void* ptr;
+ double d;
+ int64_t i;
+ // And add one for the out-of-line cases.
+ SharedPayloadBase* shared;
+ };
+
+ void Destroy() {
+ if (IsShared() && buffer_.shared->Unref()) {
+ vtable_->shared_destroy(buffer_.shared);
+ }
+ }
+
+ template <typename M>
+ static constexpr bool IsInlined() {
+ return sizeof(M) <= sizeof(Buffer) && alignof(M) <= alignof(Buffer) &&
+ std::is_trivially_copy_constructible<M>::value &&
+ std::is_trivially_destructible<M>::value;
+ }
+
+ template <typename M, bool = MatcherBase::IsInlined<M>()>
+ struct ValuePolicy {
+ static const M& Get(const MatcherBase& m) {
+ // When inlined along with Init, need to be explicit to avoid violating
+ // strict aliasing rules.
+ const M *ptr = static_cast<const M*>(
+ static_cast<const void*>(&m.buffer_));
+ return *ptr;
+ }
+ static void Init(MatcherBase& m, M impl) {
+ ::new (static_cast<void*>(&m.buffer_)) M(impl);
+ }
+ static constexpr auto shared_destroy = nullptr;
+ };
+
+ template <typename M>
+ struct ValuePolicy<M, false> {
+ using Shared = SharedPayload<M>;
+ static const M& Get(const MatcherBase& m) {
+ return static_cast<Shared*>(m.buffer_.shared)->value;
+ }
+ template <typename Arg>
+ static void Init(MatcherBase& m, Arg&& arg) {
+ m.buffer_.shared = new Shared(std::forward<Arg>(arg));
+ }
+ static constexpr auto shared_destroy = &Shared::Destroy;
+ };
+
+ template <typename U, bool B>
+ struct ValuePolicy<const MatcherInterface<U>*, B> {
+ using M = const MatcherInterface<U>;
+ using Shared = SharedPayload<std::unique_ptr<M>>;
+ static const M& Get(const MatcherBase& m) {
+ return *static_cast<Shared*>(m.buffer_.shared)->value;
+ }
+ static void Init(MatcherBase& m, M* impl) {
+ m.buffer_.shared = new Shared(std::unique_ptr<M>(impl));
+ }
+
+ static constexpr auto shared_destroy = &Shared::Destroy;
+ };
+
+ template <typename M>
+ void Init(M&& m) {
+ using MM = typename std::decay<M>::type;
+ using Policy = ValuePolicy<MM>;
+ vtable_ = GetVTable<Policy>();
+ Policy::Init(*this, std::forward<M>(m));
+ }
+
+ const VTable* vtable_;
+ Buffer buffer_;
+};
+
+} // namespace internal
+
+// A Matcher<T> is a copyable and IMMUTABLE (except by assignment)
+// object that can check whether a value of type T matches. The
+// implementation of Matcher<T> is just a std::shared_ptr to const
+// MatcherInterface<T>. Don't inherit from Matcher!
+template <typename T>
+class Matcher : public internal::MatcherBase<T> {
+ public:
+ // Constructs a null matcher. Needed for storing Matcher objects in STL
+ // containers. A default-constructed matcher is not yet initialized. You
+ // cannot use it until a valid value has been assigned to it.
+ explicit Matcher() {} // NOLINT
+
+ // Constructs a matcher from its implementation.
+ explicit Matcher(const MatcherInterface<const T&>* impl)
+ : internal::MatcherBase<T>(impl) {}
+
+ template <typename U>
+ explicit Matcher(
+ const MatcherInterface<U>* impl,
+ typename std::enable_if<!std::is_same<U, const U&>::value>::type* =
+ nullptr)
+ : internal::MatcherBase<T>(impl) {}
+
+ template <typename M, typename = typename std::remove_reference<
+ M>::type::is_gtest_matcher>
+ Matcher(M&& m) : internal::MatcherBase<T>(std::forward<M>(m)) {} // NOLINT
+
+ // Implicit constructor here allows people to write
+ // EXPECT_CALL(foo, Bar(5)) instead of EXPECT_CALL(foo, Bar(Eq(5))) sometimes
+ Matcher(T value); // NOLINT
+};
+
+// The following two specializations allow the user to write str
+// instead of Eq(str) and "foo" instead of Eq("foo") when a std::string
+// matcher is expected.
+template <>
+class GTEST_API_ Matcher<const std::string&>
+ : public internal::MatcherBase<const std::string&> {
+ public:
+ Matcher() {}
+
+ explicit Matcher(const MatcherInterface<const std::string&>* impl)
+ : internal::MatcherBase<const std::string&>(impl) {}
+
+ template <typename M, typename = typename std::remove_reference<
+ M>::type::is_gtest_matcher>
+ Matcher(M&& m) // NOLINT
+ : internal::MatcherBase<const std::string&>(std::forward<M>(m)) {}
+
+ // Allows the user to write str instead of Eq(str) sometimes, where
+ // str is a std::string object.
+ Matcher(const std::string& s); // NOLINT
+
+ // Allows the user to write "foo" instead of Eq("foo") sometimes.
+ Matcher(const char* s); // NOLINT
+};
+
+template <>
+class GTEST_API_ Matcher<std::string>
+ : public internal::MatcherBase<std::string> {
+ public:
+ Matcher() {}
+
+ explicit Matcher(const MatcherInterface<const std::string&>* impl)
+ : internal::MatcherBase<std::string>(impl) {}
+ explicit Matcher(const MatcherInterface<std::string>* impl)
+ : internal::MatcherBase<std::string>(impl) {}
+
+ template <typename M, typename = typename std::remove_reference<
+ M>::type::is_gtest_matcher>
+ Matcher(M&& m) // NOLINT
+ : internal::MatcherBase<std::string>(std::forward<M>(m)) {}
+
+ // Allows the user to write str instead of Eq(str) sometimes, where
+ // str is a string object.
+ Matcher(const std::string& s); // NOLINT
+
+ // Allows the user to write "foo" instead of Eq("foo") sometimes.
+ Matcher(const char* s); // NOLINT
+};
+
+#if GTEST_INTERNAL_HAS_STRING_VIEW
+// The following two specializations allow the user to write str
+// instead of Eq(str) and "foo" instead of Eq("foo") when a absl::string_view
+// matcher is expected.
+template <>
+class GTEST_API_ Matcher<const internal::StringView&>
+ : public internal::MatcherBase<const internal::StringView&> {
+ public:
+ Matcher() {}
+
+ explicit Matcher(const MatcherInterface<const internal::StringView&>* impl)
+ : internal::MatcherBase<const internal::StringView&>(impl) {}
+
+ template <typename M, typename = typename std::remove_reference<
+ M>::type::is_gtest_matcher>
+ Matcher(M&& m) // NOLINT
+ : internal::MatcherBase<const internal::StringView&>(std::forward<M>(m)) {
+ }
+
+ // Allows the user to write str instead of Eq(str) sometimes, where
+ // str is a std::string object.
+ Matcher(const std::string& s); // NOLINT
+
+ // Allows the user to write "foo" instead of Eq("foo") sometimes.
+ Matcher(const char* s); // NOLINT
+
+ // Allows the user to pass absl::string_views or std::string_views directly.
+ Matcher(internal::StringView s); // NOLINT
+};
+
+template <>
+class GTEST_API_ Matcher<internal::StringView>
+ : public internal::MatcherBase<internal::StringView> {
+ public:
+ Matcher() {}
+
+ explicit Matcher(const MatcherInterface<const internal::StringView&>* impl)
+ : internal::MatcherBase<internal::StringView>(impl) {}
+ explicit Matcher(const MatcherInterface<internal::StringView>* impl)
+ : internal::MatcherBase<internal::StringView>(impl) {}
+
+ template <typename M, typename = typename std::remove_reference<
+ M>::type::is_gtest_matcher>
+ Matcher(M&& m) // NOLINT
+ : internal::MatcherBase<internal::StringView>(std::forward<M>(m)) {}
+
+ // Allows the user to write str instead of Eq(str) sometimes, where
+ // str is a std::string object.
+ Matcher(const std::string& s); // NOLINT
+
+ // Allows the user to write "foo" instead of Eq("foo") sometimes.
+ Matcher(const char* s); // NOLINT
+
+ // Allows the user to pass absl::string_views or std::string_views directly.
+ Matcher(internal::StringView s); // NOLINT
+};
+#endif // GTEST_INTERNAL_HAS_STRING_VIEW
+
+// Prints a matcher in a human-readable format.
+template <typename T>
+std::ostream& operator<<(std::ostream& os, const Matcher<T>& matcher) {
+ matcher.DescribeTo(&os);
+ return os;
+}
+
+// The PolymorphicMatcher class template makes it easy to implement a
+// polymorphic matcher (i.e. a matcher that can match values of more
+// than one type, e.g. Eq(n) and NotNull()).
+//
+// To define a polymorphic matcher, a user should provide an Impl
+// class that has a DescribeTo() method and a DescribeNegationTo()
+// method, and define a member function (or member function template)
+//
+// bool MatchAndExplain(const Value& value,
+// MatchResultListener* listener) const;
+//
+// See the definition of NotNull() for a complete example.
+template <class Impl>
+class PolymorphicMatcher {
+ public:
+ explicit PolymorphicMatcher(const Impl& an_impl) : impl_(an_impl) {}
+
+ // Returns a mutable reference to the underlying matcher
+ // implementation object.
+ Impl& mutable_impl() { return impl_; }
+
+ // Returns an immutable reference to the underlying matcher
+ // implementation object.
+ const Impl& impl() const { return impl_; }
+
+ template <typename T>
+ operator Matcher<T>() const {
+ return Matcher<T>(new MonomorphicImpl<const T&>(impl_));
+ }
+
+ private:
+ template <typename T>
+ class MonomorphicImpl : public MatcherInterface<T> {
+ public:
+ explicit MonomorphicImpl(const Impl& impl) : impl_(impl) {}
+
+ void DescribeTo(::std::ostream* os) const override { impl_.DescribeTo(os); }
+
+ void DescribeNegationTo(::std::ostream* os) const override {
+ impl_.DescribeNegationTo(os);
+ }
+
+ bool MatchAndExplain(T x, MatchResultListener* listener) const override {
+ return impl_.MatchAndExplain(x, listener);
+ }
+
+ private:
+ const Impl impl_;
+ };
+
+ Impl impl_;
+};
+
+// Creates a matcher from its implementation.
+// DEPRECATED: Especially in the generic code, prefer:
+// Matcher<T>(new MyMatcherImpl<const T&>(...));
+//
+// MakeMatcher may create a Matcher that accepts its argument by value, which
+// leads to unnecessary copies & lack of support for non-copyable types.
+template <typename T>
+inline Matcher<T> MakeMatcher(const MatcherInterface<T>* impl) {
+ return Matcher<T>(impl);
+}
+
+// Creates a polymorphic matcher from its implementation. This is
+// easier to use than the PolymorphicMatcher<Impl> constructor as it
+// doesn't require you to explicitly write the template argument, e.g.
+//
+// MakePolymorphicMatcher(foo);
+// vs
+// PolymorphicMatcher<TypeOfFoo>(foo);
+template <class Impl>
+inline PolymorphicMatcher<Impl> MakePolymorphicMatcher(const Impl& impl) {
+ return PolymorphicMatcher<Impl>(impl);
+}
+
+namespace internal {
+// Implements a matcher that compares a given value with a
+// pre-supplied value using one of the ==, <=, <, etc, operators. The
+// two values being compared don't have to have the same type.
+//
+// The matcher defined here is polymorphic (for example, Eq(5) can be
+// used to match an int, a short, a double, etc). Therefore we use
+// a template type conversion operator in the implementation.
+//
+// The following template definition assumes that the Rhs parameter is
+// a "bare" type (i.e. neither 'const T' nor 'T&').
+template <typename D, typename Rhs, typename Op>
+class ComparisonBase {
+ public:
+ explicit ComparisonBase(const Rhs& rhs) : rhs_(rhs) {}
+
+ using is_gtest_matcher = void;
+
+ template <typename Lhs>
+ bool MatchAndExplain(const Lhs& lhs, std::ostream*) const {
+ return Op()(lhs, Unwrap(rhs_));
+ }
+ void DescribeTo(std::ostream* os) const {
+ *os << D::Desc() << " ";
+ UniversalPrint(Unwrap(rhs_), os);
+ }
+ void DescribeNegationTo(std::ostream* os) const {
+ *os << D::NegatedDesc() << " ";
+ UniversalPrint(Unwrap(rhs_), os);
+ }
+
+ private:
+ template <typename T>
+ static const T& Unwrap(const T& v) {
+ return v;
+ }
+ template <typename T>
+ static const T& Unwrap(std::reference_wrapper<T> v) {
+ return v;
+ }
+
+ Rhs rhs_;
+};
+
+template <typename Rhs>
+class EqMatcher : public ComparisonBase<EqMatcher<Rhs>, Rhs, AnyEq> {
+ public:
+ explicit EqMatcher(const Rhs& rhs)
+ : ComparisonBase<EqMatcher<Rhs>, Rhs, AnyEq>(rhs) { }
+ static const char* Desc() { return "is equal to"; }
+ static const char* NegatedDesc() { return "isn't equal to"; }
+};
+template <typename Rhs>
+class NeMatcher : public ComparisonBase<NeMatcher<Rhs>, Rhs, AnyNe> {
+ public:
+ explicit NeMatcher(const Rhs& rhs)
+ : ComparisonBase<NeMatcher<Rhs>, Rhs, AnyNe>(rhs) { }
+ static const char* Desc() { return "isn't equal to"; }
+ static const char* NegatedDesc() { return "is equal to"; }
+};
+template <typename Rhs>
+class LtMatcher : public ComparisonBase<LtMatcher<Rhs>, Rhs, AnyLt> {
+ public:
+ explicit LtMatcher(const Rhs& rhs)
+ : ComparisonBase<LtMatcher<Rhs>, Rhs, AnyLt>(rhs) { }
+ static const char* Desc() { return "is <"; }
+ static const char* NegatedDesc() { return "isn't <"; }
+};
+template <typename Rhs>
+class GtMatcher : public ComparisonBase<GtMatcher<Rhs>, Rhs, AnyGt> {
+ public:
+ explicit GtMatcher(const Rhs& rhs)
+ : ComparisonBase<GtMatcher<Rhs>, Rhs, AnyGt>(rhs) { }
+ static const char* Desc() { return "is >"; }
+ static const char* NegatedDesc() { return "isn't >"; }
+};
+template <typename Rhs>
+class LeMatcher : public ComparisonBase<LeMatcher<Rhs>, Rhs, AnyLe> {
+ public:
+ explicit LeMatcher(const Rhs& rhs)
+ : ComparisonBase<LeMatcher<Rhs>, Rhs, AnyLe>(rhs) { }
+ static const char* Desc() { return "is <="; }
+ static const char* NegatedDesc() { return "isn't <="; }
+};
+template <typename Rhs>
+class GeMatcher : public ComparisonBase<GeMatcher<Rhs>, Rhs, AnyGe> {
+ public:
+ explicit GeMatcher(const Rhs& rhs)
+ : ComparisonBase<GeMatcher<Rhs>, Rhs, AnyGe>(rhs) { }
+ static const char* Desc() { return "is >="; }
+ static const char* NegatedDesc() { return "isn't >="; }
+};
+
+template <typename T, typename = typename std::enable_if<
+ std::is_constructible<std::string, T>::value>::type>
+using StringLike = T;
+
+// Implements polymorphic matchers MatchesRegex(regex) and
+// ContainsRegex(regex), which can be used as a Matcher<T> as long as
+// T can be converted to a string.
+class MatchesRegexMatcher {
+ public:
+ MatchesRegexMatcher(const RE* regex, bool full_match)
+ : regex_(regex), full_match_(full_match) {}
+
+#if GTEST_INTERNAL_HAS_STRING_VIEW
+ bool MatchAndExplain(const internal::StringView& s,
+ MatchResultListener* listener) const {
+ return MatchAndExplain(std::string(s), listener);
+ }
+#endif // GTEST_INTERNAL_HAS_STRING_VIEW
+
+ // Accepts pointer types, particularly:
+ // const char*
+ // char*
+ // const wchar_t*
+ // wchar_t*
+ template <typename CharType>
+ bool MatchAndExplain(CharType* s, MatchResultListener* listener) const {
+ return s != nullptr && MatchAndExplain(std::string(s), listener);
+ }
+
+ // Matches anything that can convert to std::string.
+ //
+ // This is a template, not just a plain function with const std::string&,
+ // because absl::string_view has some interfering non-explicit constructors.
+ template <class MatcheeStringType>
+ bool MatchAndExplain(const MatcheeStringType& s,
+ MatchResultListener* /* listener */) const {
+ const std::string& s2(s);
+ return full_match_ ? RE::FullMatch(s2, *regex_)
+ : RE::PartialMatch(s2, *regex_);
+ }
+
+ void DescribeTo(::std::ostream* os) const {
+ *os << (full_match_ ? "matches" : "contains") << " regular expression ";
+ UniversalPrinter<std::string>::Print(regex_->pattern(), os);
+ }
+
+ void DescribeNegationTo(::std::ostream* os) const {
+ *os << "doesn't " << (full_match_ ? "match" : "contain")
+ << " regular expression ";
+ UniversalPrinter<std::string>::Print(regex_->pattern(), os);
+ }
+
+ private:
+ const std::shared_ptr<const RE> regex_;
+ const bool full_match_;
+};
+} // namespace internal
+
+// Matches a string that fully matches regular expression 'regex'.
+// The matcher takes ownership of 'regex'.
+inline PolymorphicMatcher<internal::MatchesRegexMatcher> MatchesRegex(
+ const internal::RE* regex) {
+ return MakePolymorphicMatcher(internal::MatchesRegexMatcher(regex, true));
+}
+template <typename T = std::string>
+PolymorphicMatcher<internal::MatchesRegexMatcher> MatchesRegex(
+ const internal::StringLike<T>& regex) {
+ return MatchesRegex(new internal::RE(std::string(regex)));
+}
+
+// Matches a string that contains regular expression 'regex'.
+// The matcher takes ownership of 'regex'.
+inline PolymorphicMatcher<internal::MatchesRegexMatcher> ContainsRegex(
+ const internal::RE* regex) {
+ return MakePolymorphicMatcher(internal::MatchesRegexMatcher(regex, false));
+}
+template <typename T = std::string>
+PolymorphicMatcher<internal::MatchesRegexMatcher> ContainsRegex(
+ const internal::StringLike<T>& regex) {
+ return ContainsRegex(new internal::RE(std::string(regex)));
+}
+
+// Creates a polymorphic matcher that matches anything equal to x.
+// Note: if the parameter of Eq() were declared as const T&, Eq("foo")
+// wouldn't compile.
+template <typename T>
+inline internal::EqMatcher<T> Eq(T x) { return internal::EqMatcher<T>(x); }
+
+// Constructs a Matcher<T> from a 'value' of type T. The constructed
+// matcher matches any value that's equal to 'value'.
+template <typename T>
+Matcher<T>::Matcher(T value) { *this = Eq(value); }
+
+// Creates a monomorphic matcher that matches anything with type Lhs
+// and equal to rhs. A user may need to use this instead of Eq(...)
+// in order to resolve an overloading ambiguity.
+//
+// TypedEq<T>(x) is just a convenient short-hand for Matcher<T>(Eq(x))
+// or Matcher<T>(x), but more readable than the latter.
+//
+// We could define similar monomorphic matchers for other comparison
+// operations (e.g. TypedLt, TypedGe, and etc), but decided not to do
+// it yet as those are used much less than Eq() in practice. A user
+// can always write Matcher<T>(Lt(5)) to be explicit about the type,
+// for example.
+template <typename Lhs, typename Rhs>
+inline Matcher<Lhs> TypedEq(const Rhs& rhs) { return Eq(rhs); }
+
+// Creates a polymorphic matcher that matches anything >= x.
+template <typename Rhs>
+inline internal::GeMatcher<Rhs> Ge(Rhs x) {
+ return internal::GeMatcher<Rhs>(x);
+}
+
+// Creates a polymorphic matcher that matches anything > x.
+template <typename Rhs>
+inline internal::GtMatcher<Rhs> Gt(Rhs x) {
+ return internal::GtMatcher<Rhs>(x);
+}
+
+// Creates a polymorphic matcher that matches anything <= x.
+template <typename Rhs>
+inline internal::LeMatcher<Rhs> Le(Rhs x) {
+ return internal::LeMatcher<Rhs>(x);
+}
+
+// Creates a polymorphic matcher that matches anything < x.
+template <typename Rhs>
+inline internal::LtMatcher<Rhs> Lt(Rhs x) {
+ return internal::LtMatcher<Rhs>(x);
+}
+
+// Creates a polymorphic matcher that matches anything != x.
+template <typename Rhs>
+inline internal::NeMatcher<Rhs> Ne(Rhs x) {
+ return internal::NeMatcher<Rhs>(x);
+}
+} // namespace testing
+
+GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 5046
+
+#endif // GOOGLETEST_INCLUDE_GTEST_GTEST_MATCHERS_H_
+
+#include <stdio.h>
+#include <memory>
+
+namespace testing {
+namespace internal {
+
+GTEST_DECLARE_string_(internal_run_death_test);
+
+// Names of the flags (needed for parsing Google Test flags).
+const char kDeathTestStyleFlag[] = "death_test_style";
+const char kDeathTestUseFork[] = "death_test_use_fork";
+const char kInternalRunDeathTestFlag[] = "internal_run_death_test";
+
+#if GTEST_HAS_DEATH_TEST
+
+GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \
+/* class A needs to have dll-interface to be used by clients of class B */)
+
+// DeathTest is a class that hides much of the complexity of the
+// GTEST_DEATH_TEST_ macro. It is abstract; its static Create method
+// returns a concrete class that depends on the prevailing death test
+// style, as defined by the --gtest_death_test_style and/or
+// --gtest_internal_run_death_test flags.
+
+// In describing the results of death tests, these terms are used with
+// the corresponding definitions:
+//
+// exit status: The integer exit information in the format specified
+// by wait(2)
+// exit code: The integer code passed to exit(3), _exit(2), or
+// returned from main()
+class GTEST_API_ DeathTest {
+ public:
+ // Create returns false if there was an error determining the
+ // appropriate action to take for the current death test; for example,
+ // if the gtest_death_test_style flag is set to an invalid value.
+ // The LastMessage method will return a more detailed message in that
+ // case. Otherwise, the DeathTest pointer pointed to by the "test"
+ // argument is set. If the death test should be skipped, the pointer
+ // is set to NULL; otherwise, it is set to the address of a new concrete
+ // DeathTest object that controls the execution of the current test.
+ static bool Create(const char* statement, Matcher<const std::string&> matcher,
+ const char* file, int line, DeathTest** test);
+ DeathTest();
+ virtual ~DeathTest() { }
+
+ // A helper class that aborts a death test when it's deleted.
+ class ReturnSentinel {
+ public:
+ explicit ReturnSentinel(DeathTest* test) : test_(test) { }
+ ~ReturnSentinel() { test_->Abort(TEST_ENCOUNTERED_RETURN_STATEMENT); }
+ private:
+ DeathTest* const test_;
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ReturnSentinel);
+ } GTEST_ATTRIBUTE_UNUSED_;
+
+ // An enumeration of possible roles that may be taken when a death
+ // test is encountered. EXECUTE means that the death test logic should
+ // be executed immediately. OVERSEE means that the program should prepare
+ // the appropriate environment for a child process to execute the death
+ // test, then wait for it to complete.
+ enum TestRole { OVERSEE_TEST, EXECUTE_TEST };
+
+ // An enumeration of the three reasons that a test might be aborted.
+ enum AbortReason {
+ TEST_ENCOUNTERED_RETURN_STATEMENT,
+ TEST_THREW_EXCEPTION,
+ TEST_DID_NOT_DIE
+ };
+
+ // Assumes one of the above roles.
+ virtual TestRole AssumeRole() = 0;
+
+ // Waits for the death test to finish and returns its status.
+ virtual int Wait() = 0;
+
+ // Returns true if the death test passed; that is, the test process
+ // exited during the test, its exit status matches a user-supplied
+ // predicate, and its stderr output matches a user-supplied regular
+ // expression.
+ // The user-supplied predicate may be a macro expression rather
+ // than a function pointer or functor, or else Wait and Passed could
+ // be combined.
+ virtual bool Passed(bool exit_status_ok) = 0;
+
+ // Signals that the death test did not die as expected.
+ virtual void Abort(AbortReason reason) = 0;
+
+ // Returns a human-readable outcome message regarding the outcome of
+ // the last death test.
+ static const char* LastMessage();
+
+ static void set_last_death_test_message(const std::string& message);
+
+ private:
+ // A string containing a description of the outcome of the last death test.
+ static std::string last_death_test_message_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(DeathTest);
+};
+
+GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251
+
+// Factory interface for death tests. May be mocked out for testing.
+class DeathTestFactory {
+ public:
+ virtual ~DeathTestFactory() { }
+ virtual bool Create(const char* statement,
+ Matcher<const std::string&> matcher, const char* file,
+ int line, DeathTest** test) = 0;
+};
+
+// A concrete DeathTestFactory implementation for normal use.
+class DefaultDeathTestFactory : public DeathTestFactory {
+ public:
+ bool Create(const char* statement, Matcher<const std::string&> matcher,
+ const char* file, int line, DeathTest** test) override;
+};
+
+// Returns true if exit_status describes a process that was terminated
+// by a signal, or exited normally with a nonzero exit code.
+GTEST_API_ bool ExitedUnsuccessfully(int exit_status);
+
+// A string passed to EXPECT_DEATH (etc.) is caught by one of these overloads
+// and interpreted as a regex (rather than an Eq matcher) for legacy
+// compatibility.
+inline Matcher<const ::std::string&> MakeDeathTestMatcher(
+ ::testing::internal::RE regex) {
+ return ContainsRegex(regex.pattern());
+}
+inline Matcher<const ::std::string&> MakeDeathTestMatcher(const char* regex) {
+ return ContainsRegex(regex);
+}
+inline Matcher<const ::std::string&> MakeDeathTestMatcher(
+ const ::std::string& regex) {
+ return ContainsRegex(regex);
+}
+
+// If a Matcher<const ::std::string&> is passed to EXPECT_DEATH (etc.), it's
+// used directly.
+inline Matcher<const ::std::string&> MakeDeathTestMatcher(
+ Matcher<const ::std::string&> matcher) {
+ return matcher;
+}
+
+// Traps C++ exceptions escaping statement and reports them as test
+// failures. Note that trapping SEH exceptions is not implemented here.
+# if GTEST_HAS_EXCEPTIONS
+# define GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, death_test) \
+ try { \
+ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
+ } catch (const ::std::exception& gtest_exception) { \
+ fprintf(\
+ stderr, \
+ "\n%s: Caught std::exception-derived exception escaping the " \
+ "death test statement. Exception message: %s\n", \
+ ::testing::internal::FormatFileLocation(__FILE__, __LINE__).c_str(), \
+ gtest_exception.what()); \
+ fflush(stderr); \
+ death_test->Abort(::testing::internal::DeathTest::TEST_THREW_EXCEPTION); \
+ } catch (...) { \
+ death_test->Abort(::testing::internal::DeathTest::TEST_THREW_EXCEPTION); \
+ }
+
+# else
+# define GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, death_test) \
+ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement)
+
+# endif
+
+// This macro is for implementing ASSERT_DEATH*, EXPECT_DEATH*,
+// ASSERT_EXIT*, and EXPECT_EXIT*.
+#define GTEST_DEATH_TEST_(statement, predicate, regex_or_matcher, fail) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (::testing::internal::AlwaysTrue()) { \
+ ::testing::internal::DeathTest* gtest_dt; \
+ if (!::testing::internal::DeathTest::Create( \
+ #statement, \
+ ::testing::internal::MakeDeathTestMatcher(regex_or_matcher), \
+ __FILE__, __LINE__, &gtest_dt)) { \
+ goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \
+ } \
+ if (gtest_dt != nullptr) { \
+ std::unique_ptr< ::testing::internal::DeathTest> gtest_dt_ptr(gtest_dt); \
+ switch (gtest_dt->AssumeRole()) { \
+ case ::testing::internal::DeathTest::OVERSEE_TEST: \
+ if (!gtest_dt->Passed(predicate(gtest_dt->Wait()))) { \
+ goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \
+ } \
+ break; \
+ case ::testing::internal::DeathTest::EXECUTE_TEST: { \
+ ::testing::internal::DeathTest::ReturnSentinel gtest_sentinel( \
+ gtest_dt); \
+ GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, gtest_dt); \
+ gtest_dt->Abort(::testing::internal::DeathTest::TEST_DID_NOT_DIE); \
+ break; \
+ } \
+ } \
+ } \
+ } else \
+ GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__) \
+ : fail(::testing::internal::DeathTest::LastMessage())
+// The symbol "fail" here expands to something into which a message
+// can be streamed.
+
+// This macro is for implementing ASSERT/EXPECT_DEBUG_DEATH when compiled in
+// NDEBUG mode. In this case we need the statements to be executed and the macro
+// must accept a streamed message even though the message is never printed.
+// The regex object is not evaluated, but it is used to prevent "unused"
+// warnings and to avoid an expression that doesn't compile in debug mode.
+#define GTEST_EXECUTE_STATEMENT_(statement, regex_or_matcher) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (::testing::internal::AlwaysTrue()) { \
+ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
+ } else if (!::testing::internal::AlwaysTrue()) { \
+ ::testing::internal::MakeDeathTestMatcher(regex_or_matcher); \
+ } else \
+ ::testing::Message()
+
+// A class representing the parsed contents of the
+// --gtest_internal_run_death_test flag, as it existed when
+// RUN_ALL_TESTS was called.
+class InternalRunDeathTestFlag {
+ public:
+ InternalRunDeathTestFlag(const std::string& a_file,
+ int a_line,
+ int an_index,
+ int a_write_fd)
+ : file_(a_file), line_(a_line), index_(an_index),
+ write_fd_(a_write_fd) {}
+
+ ~InternalRunDeathTestFlag() {
+ if (write_fd_ >= 0)
+ posix::Close(write_fd_);
+ }
+
+ const std::string& file() const { return file_; }
+ int line() const { return line_; }
+ int index() const { return index_; }
+ int write_fd() const { return write_fd_; }
+
+ private:
+ std::string file_;
+ int line_;
+ int index_;
+ int write_fd_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(InternalRunDeathTestFlag);
+};
+
+// Returns a newly created InternalRunDeathTestFlag object with fields
+// initialized from the GTEST_FLAG(internal_run_death_test) flag if
+// the flag is specified; otherwise returns NULL.
+InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag();
+
+#endif // GTEST_HAS_DEATH_TEST
+
+} // namespace internal
+} // namespace testing
+
+#endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
+
+namespace testing {
+
+// This flag controls the style of death tests. Valid values are "threadsafe",
+// meaning that the death test child process will re-execute the test binary
+// from the start, running only a single death test, or "fast",
+// meaning that the child process will execute the test logic immediately
+// after forking.
+GTEST_DECLARE_string_(death_test_style);
+
+#if GTEST_HAS_DEATH_TEST
+
+namespace internal {
+
+// Returns a Boolean value indicating whether the caller is currently
+// executing in the context of the death test child process. Tools such as
+// Valgrind heap checkers may need this to modify their behavior in death
+// tests. IMPORTANT: This is an internal utility. Using it may break the
+// implementation of death tests. User code MUST NOT use it.
+GTEST_API_ bool InDeathTestChild();
+
+} // namespace internal
+
+// The following macros are useful for writing death tests.
+
+// Here's what happens when an ASSERT_DEATH* or EXPECT_DEATH* is
+// executed:
+//
+// 1. It generates a warning if there is more than one active
+// thread. This is because it's safe to fork() or clone() only
+// when there is a single thread.
+//
+// 2. The parent process clone()s a sub-process and runs the death
+// test in it; the sub-process exits with code 0 at the end of the
+// death test, if it hasn't exited already.
+//
+// 3. The parent process waits for the sub-process to terminate.
+//
+// 4. The parent process checks the exit code and error message of
+// the sub-process.
+//
+// Examples:
+//
+// ASSERT_DEATH(server.SendMessage(56, "Hello"), "Invalid port number");
+// for (int i = 0; i < 5; i++) {
+// EXPECT_DEATH(server.ProcessRequest(i),
+// "Invalid request .* in ProcessRequest()")
+// << "Failed to die on request " << i;
+// }
+//
+// ASSERT_EXIT(server.ExitNow(), ::testing::ExitedWithCode(0), "Exiting");
+//
+// bool KilledBySIGHUP(int exit_code) {
+// return WIFSIGNALED(exit_code) && WTERMSIG(exit_code) == SIGHUP;
+// }
+//
+// ASSERT_EXIT(client.HangUpServer(), KilledBySIGHUP, "Hanging up!");
+//
+// The final parameter to each of these macros is a matcher applied to any data
+// the sub-process wrote to stderr. For compatibility with existing tests, a
+// bare string is interpreted as a regular expression matcher.
+//
+// On the regular expressions used in death tests:
+//
+// GOOGLETEST_CM0005 DO NOT DELETE
+// On POSIX-compliant systems (*nix), we use the <regex.h> library,
+// which uses the POSIX extended regex syntax.
+//
+// On other platforms (e.g. Windows or Mac), we only support a simple regex
+// syntax implemented as part of Google Test. This limited
+// implementation should be enough most of the time when writing
+// death tests; though it lacks many features you can find in PCRE
+// or POSIX extended regex syntax. For example, we don't support
+// union ("x|y"), grouping ("(xy)"), brackets ("[xy]"), and
+// repetition count ("x{5,7}"), among others.
+//
+// Below is the syntax that we do support. We chose it to be a
+// subset of both PCRE and POSIX extended regex, so it's easy to
+// learn wherever you come from. In the following: 'A' denotes a
+// literal character, period (.), or a single \\ escape sequence;
+// 'x' and 'y' denote regular expressions; 'm' and 'n' are for
+// natural numbers.
+//
+// c matches any literal character c
+// \\d matches any decimal digit
+// \\D matches any character that's not a decimal digit
+// \\f matches \f
+// \\n matches \n
+// \\r matches \r
+// \\s matches any ASCII whitespace, including \n
+// \\S matches any character that's not a whitespace
+// \\t matches \t
+// \\v matches \v
+// \\w matches any letter, _, or decimal digit
+// \\W matches any character that \\w doesn't match
+// \\c matches any literal character c, which must be a punctuation
+// . matches any single character except \n
+// A? matches 0 or 1 occurrences of A
+// A* matches 0 or many occurrences of A
+// A+ matches 1 or many occurrences of A
+// ^ matches the beginning of a string (not that of each line)
+// $ matches the end of a string (not that of each line)
+// xy matches x followed by y
+//
+// If you accidentally use PCRE or POSIX extended regex features
+// not implemented by us, you will get a run-time failure. In that
+// case, please try to rewrite your regular expression within the
+// above syntax.
+//
+// This implementation is *not* meant to be as highly tuned or robust
+// as a compiled regex library, but should perform well enough for a
+// death test, which already incurs significant overhead by launching
+// a child process.
+//
+// Known caveats:
+//
+// A "threadsafe" style death test obtains the path to the test
+// program from argv[0] and re-executes it in the sub-process. For
+// simplicity, the current implementation doesn't search the PATH
+// when launching the sub-process. This means that the user must
+// invoke the test program via a path that contains at least one
+// path separator (e.g. path/to/foo_test and
+// /absolute/path/to/bar_test are fine, but foo_test is not). This
+// is rarely a problem as people usually don't put the test binary
+// directory in PATH.
+//
+
+// Asserts that a given `statement` causes the program to exit, with an
+// integer exit status that satisfies `predicate`, and emitting error output
+// that matches `matcher`.
+# define ASSERT_EXIT(statement, predicate, matcher) \
+ GTEST_DEATH_TEST_(statement, predicate, matcher, GTEST_FATAL_FAILURE_)
+
+// Like `ASSERT_EXIT`, but continues on to successive tests in the
+// test suite, if any:
+# define EXPECT_EXIT(statement, predicate, matcher) \
+ GTEST_DEATH_TEST_(statement, predicate, matcher, GTEST_NONFATAL_FAILURE_)
+
+// Asserts that a given `statement` causes the program to exit, either by
+// explicitly exiting with a nonzero exit code or being killed by a
+// signal, and emitting error output that matches `matcher`.
+# define ASSERT_DEATH(statement, matcher) \
+ ASSERT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, matcher)
+
+// Like `ASSERT_DEATH`, but continues on to successive tests in the
+// test suite, if any:
+# define EXPECT_DEATH(statement, matcher) \
+ EXPECT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, matcher)
+
+// Two predicate classes that can be used in {ASSERT,EXPECT}_EXIT*:
+
+// Tests that an exit code describes a normal exit with a given exit code.
+class GTEST_API_ ExitedWithCode {
+ public:
+ explicit ExitedWithCode(int exit_code);
+ ExitedWithCode(const ExitedWithCode&) = default;
+ void operator=(const ExitedWithCode& other) = delete;
+ bool operator()(int exit_status) const;
+ private:
+ const int exit_code_;
+};
+
+# if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA
+// Tests that an exit code describes an exit due to termination by a
+// given signal.
+// GOOGLETEST_CM0006 DO NOT DELETE
+class GTEST_API_ KilledBySignal {
+ public:
+ explicit KilledBySignal(int signum);
+ bool operator()(int exit_status) const;
+ private:
+ const int signum_;
+};
+# endif // !GTEST_OS_WINDOWS
+
+// EXPECT_DEBUG_DEATH asserts that the given statements die in debug mode.
+// The death testing framework causes this to have interesting semantics,
+// since the sideeffects of the call are only visible in opt mode, and not
+// in debug mode.
+//
+// In practice, this can be used to test functions that utilize the
+// LOG(DFATAL) macro using the following style:
+//
+// int DieInDebugOr12(int* sideeffect) {
+// if (sideeffect) {
+// *sideeffect = 12;
+// }
+// LOG(DFATAL) << "death";
+// return 12;
+// }
+//
+// TEST(TestSuite, TestDieOr12WorksInDgbAndOpt) {
+// int sideeffect = 0;
+// // Only asserts in dbg.
+// EXPECT_DEBUG_DEATH(DieInDebugOr12(&sideeffect), "death");
+//
+// #ifdef NDEBUG
+// // opt-mode has sideeffect visible.
+// EXPECT_EQ(12, sideeffect);
+// #else
+// // dbg-mode no visible sideeffect.
+// EXPECT_EQ(0, sideeffect);
+// #endif
+// }
+//
+// This will assert that DieInDebugReturn12InOpt() crashes in debug
+// mode, usually due to a DCHECK or LOG(DFATAL), but returns the
+// appropriate fallback value (12 in this case) in opt mode. If you
+// need to test that a function has appropriate side-effects in opt
+// mode, include assertions against the side-effects. A general
+// pattern for this is:
+//
+// EXPECT_DEBUG_DEATH({
+// // Side-effects here will have an effect after this statement in
+// // opt mode, but none in debug mode.
+// EXPECT_EQ(12, DieInDebugOr12(&sideeffect));
+// }, "death");
+//
+# ifdef NDEBUG
+
+# define EXPECT_DEBUG_DEATH(statement, regex) \
+ GTEST_EXECUTE_STATEMENT_(statement, regex)
+
+# define ASSERT_DEBUG_DEATH(statement, regex) \
+ GTEST_EXECUTE_STATEMENT_(statement, regex)
+
+# else
+
+# define EXPECT_DEBUG_DEATH(statement, regex) \
+ EXPECT_DEATH(statement, regex)
+
+# define ASSERT_DEBUG_DEATH(statement, regex) \
+ ASSERT_DEATH(statement, regex)
+
+# endif // NDEBUG for EXPECT_DEBUG_DEATH
+#endif // GTEST_HAS_DEATH_TEST
+
+// This macro is used for implementing macros such as
+// EXPECT_DEATH_IF_SUPPORTED and ASSERT_DEATH_IF_SUPPORTED on systems where
+// death tests are not supported. Those macros must compile on such systems
+// if and only if EXPECT_DEATH and ASSERT_DEATH compile with the same parameters
+// on systems that support death tests. This allows one to write such a macro on
+// a system that does not support death tests and be sure that it will compile
+// on a death-test supporting system. It is exposed publicly so that systems
+// that have death-tests with stricter requirements than GTEST_HAS_DEATH_TEST
+// can write their own equivalent of EXPECT_DEATH_IF_SUPPORTED and
+// ASSERT_DEATH_IF_SUPPORTED.
+//
+// Parameters:
+// statement - A statement that a macro such as EXPECT_DEATH would test
+// for program termination. This macro has to make sure this
+// statement is compiled but not executed, to ensure that
+// EXPECT_DEATH_IF_SUPPORTED compiles with a certain
+// parameter if and only if EXPECT_DEATH compiles with it.
+// regex - A regex that a macro such as EXPECT_DEATH would use to test
+// the output of statement. This parameter has to be
+// compiled but not evaluated by this macro, to ensure that
+// this macro only accepts expressions that a macro such as
+// EXPECT_DEATH would accept.
+// terminator - Must be an empty statement for EXPECT_DEATH_IF_SUPPORTED
+// and a return statement for ASSERT_DEATH_IF_SUPPORTED.
+// This ensures that ASSERT_DEATH_IF_SUPPORTED will not
+// compile inside functions where ASSERT_DEATH doesn't
+// compile.
+//
+// The branch that has an always false condition is used to ensure that
+// statement and regex are compiled (and thus syntactically correct) but
+// never executed. The unreachable code macro protects the terminator
+// statement from generating an 'unreachable code' warning in case
+// statement unconditionally returns or throws. The Message constructor at
+// the end allows the syntax of streaming additional messages into the
+// macro, for compilational compatibility with EXPECT_DEATH/ASSERT_DEATH.
+# define GTEST_UNSUPPORTED_DEATH_TEST(statement, regex, terminator) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (::testing::internal::AlwaysTrue()) { \
+ GTEST_LOG_(WARNING) \
+ << "Death tests are not supported on this platform.\n" \
+ << "Statement '" #statement "' cannot be verified."; \
+ } else if (::testing::internal::AlwaysFalse()) { \
+ ::testing::internal::RE::PartialMatch(".*", (regex)); \
+ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
+ terminator; \
+ } else \
+ ::testing::Message()
+
+// EXPECT_DEATH_IF_SUPPORTED(statement, regex) and
+// ASSERT_DEATH_IF_SUPPORTED(statement, regex) expand to real death tests if
+// death tests are supported; otherwise they just issue a warning. This is
+// useful when you are combining death test assertions with normal test
+// assertions in one test.
+#if GTEST_HAS_DEATH_TEST
+# define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \
+ EXPECT_DEATH(statement, regex)
+# define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \
+ ASSERT_DEATH(statement, regex)
+#else
+# define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \
+ GTEST_UNSUPPORTED_DEATH_TEST(statement, regex, )
+# define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \
+ GTEST_UNSUPPORTED_DEATH_TEST(statement, regex, return)
+#endif
+
+} // namespace testing
+
+#endif // GOOGLETEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Macros and functions for implementing parameterized tests
+// in Google C++ Testing and Mocking Framework (Google Test)
+//
+// GOOGLETEST_CM0001 DO NOT DELETE
+#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
+#define GOOGLETEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
+
+// Value-parameterized tests allow you to test your code with different
+// parameters without writing multiple copies of the same test.
+//
+// Here is how you use value-parameterized tests:
+
+#if 0
+
+// To write value-parameterized tests, first you should define a fixture
+// class. It is usually derived from testing::TestWithParam<T> (see below for
+// another inheritance scheme that's sometimes useful in more complicated
+// class hierarchies), where the type of your parameter values.
+// TestWithParam<T> is itself derived from testing::Test. T can be any
+// copyable type. If it's a raw pointer, you are responsible for managing the
+// lifespan of the pointed values.
+
+class FooTest : public ::testing::TestWithParam<const char*> {
+ // You can implement all the usual class fixture members here.
+};
+
+// Then, use the TEST_P macro to define as many parameterized tests
+// for this fixture as you want. The _P suffix is for "parameterized"
+// or "pattern", whichever you prefer to think.
+
+TEST_P(FooTest, DoesBlah) {
+ // Inside a test, access the test parameter with the GetParam() method
+ // of the TestWithParam<T> class:
+ EXPECT_TRUE(foo.Blah(GetParam()));
+ ...
+}
+
+TEST_P(FooTest, HasBlahBlah) {
+ ...
+}
+
+// Finally, you can use INSTANTIATE_TEST_SUITE_P to instantiate the test
+// case with any set of parameters you want. Google Test defines a number
+// of functions for generating test parameters. They return what we call
+// (surprise!) parameter generators. Here is a summary of them, which
+// are all in the testing namespace:
+//
+//
+// Range(begin, end [, step]) - Yields values {begin, begin+step,
+// begin+step+step, ...}. The values do not
+// include end. step defaults to 1.
+// Values(v1, v2, ..., vN) - Yields values {v1, v2, ..., vN}.
+// ValuesIn(container) - Yields values from a C-style array, an STL
+// ValuesIn(begin,end) container, or an iterator range [begin, end).
+// Bool() - Yields sequence {false, true}.
+// Combine(g1, g2, ..., gN) - Yields all combinations (the Cartesian product
+// for the math savvy) of the values generated
+// by the N generators.
+//
+// For more details, see comments at the definitions of these functions below
+// in this file.
+//
+// The following statement will instantiate tests from the FooTest test suite
+// each with parameter values "meeny", "miny", and "moe".
+
+INSTANTIATE_TEST_SUITE_P(InstantiationName,
+ FooTest,
+ Values("meeny", "miny", "moe"));
+
+// To distinguish different instances of the pattern, (yes, you
+// can instantiate it more than once) the first argument to the
+// INSTANTIATE_TEST_SUITE_P macro is a prefix that will be added to the
+// actual test suite name. Remember to pick unique prefixes for different
+// instantiations. The tests from the instantiation above will have
+// these names:
+//
+// * InstantiationName/FooTest.DoesBlah/0 for "meeny"
+// * InstantiationName/FooTest.DoesBlah/1 for "miny"
+// * InstantiationName/FooTest.DoesBlah/2 for "moe"
+// * InstantiationName/FooTest.HasBlahBlah/0 for "meeny"
+// * InstantiationName/FooTest.HasBlahBlah/1 for "miny"
+// * InstantiationName/FooTest.HasBlahBlah/2 for "moe"
+//
+// You can use these names in --gtest_filter.
+//
+// This statement will instantiate all tests from FooTest again, each
+// with parameter values "cat" and "dog":
+
+const char* pets[] = {"cat", "dog"};
+INSTANTIATE_TEST_SUITE_P(AnotherInstantiationName, FooTest, ValuesIn(pets));
+
+// The tests from the instantiation above will have these names:
+//
+// * AnotherInstantiationName/FooTest.DoesBlah/0 for "cat"
+// * AnotherInstantiationName/FooTest.DoesBlah/1 for "dog"
+// * AnotherInstantiationName/FooTest.HasBlahBlah/0 for "cat"
+// * AnotherInstantiationName/FooTest.HasBlahBlah/1 for "dog"
+//
+// Please note that INSTANTIATE_TEST_SUITE_P will instantiate all tests
+// in the given test suite, whether their definitions come before or
+// AFTER the INSTANTIATE_TEST_SUITE_P statement.
+//
+// Please also note that generator expressions (including parameters to the
+// generators) are evaluated in InitGoogleTest(), after main() has started.
+// This allows the user on one hand, to adjust generator parameters in order
+// to dynamically determine a set of tests to run and on the other hand,
+// give the user a chance to inspect the generated tests with Google Test
+// reflection API before RUN_ALL_TESTS() is executed.
+//
+// You can see samples/sample7_unittest.cc and samples/sample8_unittest.cc
+// for more examples.
+//
+// In the future, we plan to publish the API for defining new parameter
+// generators. But for now this interface remains part of the internal
+// implementation and is subject to change.
+//
+//
+// A parameterized test fixture must be derived from testing::Test and from
+// testing::WithParamInterface<T>, where T is the type of the parameter
+// values. Inheriting from TestWithParam<T> satisfies that requirement because
+// TestWithParam<T> inherits from both Test and WithParamInterface. In more
+// complicated hierarchies, however, it is occasionally useful to inherit
+// separately from Test and WithParamInterface. For example:
+
+class BaseTest : public ::testing::Test {
+ // You can inherit all the usual members for a non-parameterized test
+ // fixture here.
+};
+
+class DerivedTest : public BaseTest, public ::testing::WithParamInterface<int> {
+ // The usual test fixture members go here too.
+};
+
+TEST_F(BaseTest, HasFoo) {
+ // This is an ordinary non-parameterized test.
+}
+
+TEST_P(DerivedTest, DoesBlah) {
+ // GetParam works just the same here as if you inherit from TestWithParam.
+ EXPECT_TRUE(foo.Blah(GetParam()));
+}
+
+#endif // 0
+
+#include <iterator>
+#include <utility>
+
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+// Type and function utilities for implementing parameterized tests.
+
+// GOOGLETEST_CM0001 DO NOT DELETE
+
+#ifndef GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
+#define GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
+
+#include <ctype.h>
+
+#include <cassert>
+#include <iterator>
+#include <memory>
+#include <set>
+#include <tuple>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// GOOGLETEST_CM0001 DO NOT DELETE
+
+#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_TEST_PART_H_
+#define GOOGLETEST_INCLUDE_GTEST_GTEST_TEST_PART_H_
+
+#include <iosfwd>
+#include <vector>
+
+GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \
+/* class A needs to have dll-interface to be used by clients of class B */)
+
+namespace testing {
+
+// A copyable object representing the result of a test part (i.e. an
+// assertion or an explicit FAIL(), ADD_FAILURE(), or SUCCESS()).
+//
+// Don't inherit from TestPartResult as its destructor is not virtual.
+class GTEST_API_ TestPartResult {
+ public:
+ // The possible outcomes of a test part (i.e. an assertion or an
+ // explicit SUCCEED(), FAIL(), or ADD_FAILURE()).
+ enum Type {
+ kSuccess, // Succeeded.
+ kNonFatalFailure, // Failed but the test can continue.
+ kFatalFailure, // Failed and the test should be terminated.
+ kSkip // Skipped.
+ };
+
+ // C'tor. TestPartResult does NOT have a default constructor.
+ // Always use this constructor (with parameters) to create a
+ // TestPartResult object.
+ TestPartResult(Type a_type, const char* a_file_name, int a_line_number,
+ const char* a_message)
+ : type_(a_type),
+ file_name_(a_file_name == nullptr ? "" : a_file_name),
+ line_number_(a_line_number),
+ summary_(ExtractSummary(a_message)),
+ message_(a_message) {}
+
+ // Gets the outcome of the test part.
+ Type type() const { return type_; }
+
+ // Gets the name of the source file where the test part took place, or
+ // NULL if it's unknown.
+ const char* file_name() const {
+ return file_name_.empty() ? nullptr : file_name_.c_str();
+ }
+
+ // Gets the line in the source file where the test part took place,
+ // or -1 if it's unknown.
+ int line_number() const { return line_number_; }
+
+ // Gets the summary of the failure message.
+ const char* summary() const { return summary_.c_str(); }
+
+ // Gets the message associated with the test part.
+ const char* message() const { return message_.c_str(); }
+
+ // Returns true if and only if the test part was skipped.
+ bool skipped() const { return type_ == kSkip; }
+
+ // Returns true if and only if the test part passed.
+ bool passed() const { return type_ == kSuccess; }
+
+ // Returns true if and only if the test part non-fatally failed.
+ bool nonfatally_failed() const { return type_ == kNonFatalFailure; }
+
+ // Returns true if and only if the test part fatally failed.
+ bool fatally_failed() const { return type_ == kFatalFailure; }
+
+ // Returns true if and only if the test part failed.
+ bool failed() const { return fatally_failed() || nonfatally_failed(); }
+
+ private:
+ Type type_;
+
+ // Gets the summary of the failure message by omitting the stack
+ // trace in it.
+ static std::string ExtractSummary(const char* message);
+
+ // The name of the source file where the test part took place, or
+ // "" if the source file is unknown.
+ std::string file_name_;
+ // The line in the source file where the test part took place, or -1
+ // if the line number is unknown.
+ int line_number_;
+ std::string summary_; // The test failure summary.
+ std::string message_; // The test failure message.
+};
+
+// Prints a TestPartResult object.
+std::ostream& operator<<(std::ostream& os, const TestPartResult& result);
+
+// An array of TestPartResult objects.
+//
+// Don't inherit from TestPartResultArray as its destructor is not
+// virtual.
+class GTEST_API_ TestPartResultArray {
+ public:
+ TestPartResultArray() {}
+
+ // Appends the given TestPartResult to the array.
+ void Append(const TestPartResult& result);
+
+ // Returns the TestPartResult at the given index (0-based).
+ const TestPartResult& GetTestPartResult(int index) const;
+
+ // Returns the number of TestPartResult objects in the array.
+ int size() const;
+
+ private:
+ std::vector<TestPartResult> array_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(TestPartResultArray);
+};
+
+// This interface knows how to report a test part result.
+class GTEST_API_ TestPartResultReporterInterface {
+ public:
+ virtual ~TestPartResultReporterInterface() {}
+
+ virtual void ReportTestPartResult(const TestPartResult& result) = 0;
+};
+
+namespace internal {
+
+// This helper class is used by {ASSERT|EXPECT}_NO_FATAL_FAILURE to check if a
+// statement generates new fatal failures. To do so it registers itself as the
+// current test part result reporter. Besides checking if fatal failures were
+// reported, it only delegates the reporting to the former result reporter.
+// The original result reporter is restored in the destructor.
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+class GTEST_API_ HasNewFatalFailureHelper
+ : public TestPartResultReporterInterface {
+ public:
+ HasNewFatalFailureHelper();
+ ~HasNewFatalFailureHelper() override;
+ void ReportTestPartResult(const TestPartResult& result) override;
+ bool has_new_fatal_failure() const { return has_new_fatal_failure_; }
+ private:
+ bool has_new_fatal_failure_;
+ TestPartResultReporterInterface* original_reporter_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(HasNewFatalFailureHelper);
+};
+
+} // namespace internal
+
+} // namespace testing
+
+GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251
+
+#endif // GOOGLETEST_INCLUDE_GTEST_GTEST_TEST_PART_H_
+
+namespace testing {
+// Input to a parameterized test name generator, describing a test parameter.
+// Consists of the parameter value and the integer parameter index.
+template <class ParamType>
+struct TestParamInfo {
+ TestParamInfo(const ParamType& a_param, size_t an_index) :
+ param(a_param),
+ index(an_index) {}
+ ParamType param;
+ size_t index;
+};
+
+// A builtin parameterized test name generator which returns the result of
+// testing::PrintToString.
+struct PrintToStringParamName {
+ template <class ParamType>
+ std::string operator()(const TestParamInfo<ParamType>& info) const {
+ return PrintToString(info.param);
+ }
+};
+
+namespace internal {
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+// Utility Functions
+
+// Outputs a message explaining invalid registration of different
+// fixture class for the same test suite. This may happen when
+// TEST_P macro is used to define two tests with the same name
+// but in different namespaces.
+GTEST_API_ void ReportInvalidTestSuiteType(const char* test_suite_name,
+ CodeLocation code_location);
+
+template <typename> class ParamGeneratorInterface;
+template <typename> class ParamGenerator;
+
+// Interface for iterating over elements provided by an implementation
+// of ParamGeneratorInterface<T>.
+template <typename T>
+class ParamIteratorInterface {
+ public:
+ virtual ~ParamIteratorInterface() {}
+ // A pointer to the base generator instance.
+ // Used only for the purposes of iterator comparison
+ // to make sure that two iterators belong to the same generator.
+ virtual const ParamGeneratorInterface<T>* BaseGenerator() const = 0;
+ // Advances iterator to point to the next element
+ // provided by the generator. The caller is responsible
+ // for not calling Advance() on an iterator equal to
+ // BaseGenerator()->End().
+ virtual void Advance() = 0;
+ // Clones the iterator object. Used for implementing copy semantics
+ // of ParamIterator<T>.
+ virtual ParamIteratorInterface* Clone() const = 0;
+ // Dereferences the current iterator and provides (read-only) access
+ // to the pointed value. It is the caller's responsibility not to call
+ // Current() on an iterator equal to BaseGenerator()->End().
+ // Used for implementing ParamGenerator<T>::operator*().
+ virtual const T* Current() const = 0;
+ // Determines whether the given iterator and other point to the same
+ // element in the sequence generated by the generator.
+ // Used for implementing ParamGenerator<T>::operator==().
+ virtual bool Equals(const ParamIteratorInterface& other) const = 0;
+};
+
+// Class iterating over elements provided by an implementation of
+// ParamGeneratorInterface<T>. It wraps ParamIteratorInterface<T>
+// and implements the const forward iterator concept.
+template <typename T>
+class ParamIterator {
+ public:
+ typedef T value_type;
+ typedef const T& reference;
+ typedef ptrdiff_t difference_type;
+
+ // ParamIterator assumes ownership of the impl_ pointer.
+ ParamIterator(const ParamIterator& other) : impl_(other.impl_->Clone()) {}
+ ParamIterator& operator=(const ParamIterator& other) {
+ if (this != &other)
+ impl_.reset(other.impl_->Clone());
+ return *this;
+ }
+
+ const T& operator*() const { return *impl_->Current(); }
+ const T* operator->() const { return impl_->Current(); }
+ // Prefix version of operator++.
+ ParamIterator& operator++() {
+ impl_->Advance();
+ return *this;
+ }
+ // Postfix version of operator++.
+ ParamIterator operator++(int /*unused*/) {
+ ParamIteratorInterface<T>* clone = impl_->Clone();
+ impl_->Advance();
+ return ParamIterator(clone);
+ }
+ bool operator==(const ParamIterator& other) const {
+ return impl_.get() == other.impl_.get() || impl_->Equals(*other.impl_);
+ }
+ bool operator!=(const ParamIterator& other) const {
+ return !(*this == other);
+ }
+
+ private:
+ friend class ParamGenerator<T>;
+ explicit ParamIterator(ParamIteratorInterface<T>* impl) : impl_(impl) {}
+ std::unique_ptr<ParamIteratorInterface<T> > impl_;
+};
+
+// ParamGeneratorInterface<T> is the binary interface to access generators
+// defined in other translation units.
+template <typename T>
+class ParamGeneratorInterface {
+ public:
+ typedef T ParamType;
+
+ virtual ~ParamGeneratorInterface() {}
+
+ // Generator interface definition
+ virtual ParamIteratorInterface<T>* Begin() const = 0;
+ virtual ParamIteratorInterface<T>* End() const = 0;
+};
+
+// Wraps ParamGeneratorInterface<T> and provides general generator syntax
+// compatible with the STL Container concept.
+// This class implements copy initialization semantics and the contained
+// ParamGeneratorInterface<T> instance is shared among all copies
+// of the original object. This is possible because that instance is immutable.
+template<typename T>
+class ParamGenerator {
+ public:
+ typedef ParamIterator<T> iterator;
+
+ explicit ParamGenerator(ParamGeneratorInterface<T>* impl) : impl_(impl) {}
+ ParamGenerator(const ParamGenerator& other) : impl_(other.impl_) {}
+
+ ParamGenerator& operator=(const ParamGenerator& other) {
+ impl_ = other.impl_;
+ return *this;
+ }
+
+ iterator begin() const { return iterator(impl_->Begin()); }
+ iterator end() const { return iterator(impl_->End()); }
+
+ private:
+ std::shared_ptr<const ParamGeneratorInterface<T> > impl_;
+};
+
+// Generates values from a range of two comparable values. Can be used to
+// generate sequences of user-defined types that implement operator+() and
+// operator<().
+// This class is used in the Range() function.
+template <typename T, typename IncrementT>
+class RangeGenerator : public ParamGeneratorInterface<T> {
+ public:
+ RangeGenerator(T begin, T end, IncrementT step)
+ : begin_(begin), end_(end),
+ step_(step), end_index_(CalculateEndIndex(begin, end, step)) {}
+ ~RangeGenerator() override {}
+
+ ParamIteratorInterface<T>* Begin() const override {
+ return new Iterator(this, begin_, 0, step_);
+ }
+ ParamIteratorInterface<T>* End() const override {
+ return new Iterator(this, end_, end_index_, step_);
+ }
+
+ private:
+ class Iterator : public ParamIteratorInterface<T> {
+ public:
+ Iterator(const ParamGeneratorInterface<T>* base, T value, int index,
+ IncrementT step)
+ : base_(base), value_(value), index_(index), step_(step) {}
+ ~Iterator() override {}
+
+ const ParamGeneratorInterface<T>* BaseGenerator() const override {
+ return base_;
+ }
+ void Advance() override {
+ value_ = static_cast<T>(value_ + step_);
+ index_++;
+ }
+ ParamIteratorInterface<T>* Clone() const override {
+ return new Iterator(*this);
+ }
+ const T* Current() const override { return &value_; }
+ bool Equals(const ParamIteratorInterface<T>& other) const override {
+ // Having the same base generator guarantees that the other
+ // iterator is of the same type and we can downcast.
+ GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+ << "The program attempted to compare iterators "
+ << "from different generators." << std::endl;
+ const int other_index =
+ CheckedDowncastToActualType<const Iterator>(&other)->index_;
+ return index_ == other_index;
+ }
+
+ private:
+ Iterator(const Iterator& other)
+ : ParamIteratorInterface<T>(),
+ base_(other.base_), value_(other.value_), index_(other.index_),
+ step_(other.step_) {}
+
+ // No implementation - assignment is unsupported.
+ void operator=(const Iterator& other);
+
+ const ParamGeneratorInterface<T>* const base_;
+ T value_;
+ int index_;
+ const IncrementT step_;
+ }; // class RangeGenerator::Iterator
+
+ static int CalculateEndIndex(const T& begin,
+ const T& end,
+ const IncrementT& step) {
+ int end_index = 0;
+ for (T i = begin; i < end; i = static_cast<T>(i + step))
+ end_index++;
+ return end_index;
+ }
+
+ // No implementation - assignment is unsupported.
+ void operator=(const RangeGenerator& other);
+
+ const T begin_;
+ const T end_;
+ const IncrementT step_;
+ // The index for the end() iterator. All the elements in the generated
+ // sequence are indexed (0-based) to aid iterator comparison.
+ const int end_index_;
+}; // class RangeGenerator
+
+
+// Generates values from a pair of STL-style iterators. Used in the
+// ValuesIn() function. The elements are copied from the source range
+// since the source can be located on the stack, and the generator
+// is likely to persist beyond that stack frame.
+template <typename T>
+class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface<T> {
+ public:
+ template <typename ForwardIterator>
+ ValuesInIteratorRangeGenerator(ForwardIterator begin, ForwardIterator end)
+ : container_(begin, end) {}
+ ~ValuesInIteratorRangeGenerator() override {}
+
+ ParamIteratorInterface<T>* Begin() const override {
+ return new Iterator(this, container_.begin());
+ }
+ ParamIteratorInterface<T>* End() const override {
+ return new Iterator(this, container_.end());
+ }
+
+ private:
+ typedef typename ::std::vector<T> ContainerType;
+
+ class Iterator : public ParamIteratorInterface<T> {
+ public:
+ Iterator(const ParamGeneratorInterface<T>* base,
+ typename ContainerType::const_iterator iterator)
+ : base_(base), iterator_(iterator) {}
+ ~Iterator() override {}
+
+ const ParamGeneratorInterface<T>* BaseGenerator() const override {
+ return base_;
+ }
+ void Advance() override {
+ ++iterator_;
+ value_.reset();
+ }
+ ParamIteratorInterface<T>* Clone() const override {
+ return new Iterator(*this);
+ }
+ // We need to use cached value referenced by iterator_ because *iterator_
+ // can return a temporary object (and of type other then T), so just
+ // having "return &*iterator_;" doesn't work.
+ // value_ is updated here and not in Advance() because Advance()
+ // can advance iterator_ beyond the end of the range, and we cannot
+ // detect that fact. The client code, on the other hand, is
+ // responsible for not calling Current() on an out-of-range iterator.
+ const T* Current() const override {
+ if (value_.get() == nullptr) value_.reset(new T(*iterator_));
+ return value_.get();
+ }
+ bool Equals(const ParamIteratorInterface<T>& other) const override {
+ // Having the same base generator guarantees that the other
+ // iterator is of the same type and we can downcast.
+ GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+ << "The program attempted to compare iterators "
+ << "from different generators." << std::endl;
+ return iterator_ ==
+ CheckedDowncastToActualType<const Iterator>(&other)->iterator_;
+ }
+
+ private:
+ Iterator(const Iterator& other)
+ // The explicit constructor call suppresses a false warning
+ // emitted by gcc when supplied with the -Wextra option.
+ : ParamIteratorInterface<T>(),
+ base_(other.base_),
+ iterator_(other.iterator_) {}
+
+ const ParamGeneratorInterface<T>* const base_;
+ typename ContainerType::const_iterator iterator_;
+ // A cached value of *iterator_. We keep it here to allow access by
+ // pointer in the wrapping iterator's operator->().
+ // value_ needs to be mutable to be accessed in Current().
+ // Use of std::unique_ptr helps manage cached value's lifetime,
+ // which is bound by the lifespan of the iterator itself.
+ mutable std::unique_ptr<const T> value_;
+ }; // class ValuesInIteratorRangeGenerator::Iterator
+
+ // No implementation - assignment is unsupported.
+ void operator=(const ValuesInIteratorRangeGenerator& other);
+
+ const ContainerType container_;
+}; // class ValuesInIteratorRangeGenerator
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Default parameterized test name generator, returns a string containing the
+// integer test parameter index.
+template <class ParamType>
+std::string DefaultParamName(const TestParamInfo<ParamType>& info) {
+ Message name_stream;
+ name_stream << info.index;
+ return name_stream.GetString();
+}
+
+template <typename T = int>
+void TestNotEmpty() {
+ static_assert(sizeof(T) == 0, "Empty arguments are not allowed.");
+}
+template <typename T = int>
+void TestNotEmpty(const T&) {}
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Stores a parameter value and later creates tests parameterized with that
+// value.
+template <class TestClass>
+class ParameterizedTestFactory : public TestFactoryBase {
+ public:
+ typedef typename TestClass::ParamType ParamType;
+ explicit ParameterizedTestFactory(ParamType parameter) :
+ parameter_(parameter) {}
+ Test* CreateTest() override {
+ TestClass::SetParam(&parameter_);
+ return new TestClass();
+ }
+
+ private:
+ const ParamType parameter_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestFactory);
+};
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// TestMetaFactoryBase is a base class for meta-factories that create
+// test factories for passing into MakeAndRegisterTestInfo function.
+template <class ParamType>
+class TestMetaFactoryBase {
+ public:
+ virtual ~TestMetaFactoryBase() {}
+
+ virtual TestFactoryBase* CreateTestFactory(ParamType parameter) = 0;
+};
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// TestMetaFactory creates test factories for passing into
+// MakeAndRegisterTestInfo function. Since MakeAndRegisterTestInfo receives
+// ownership of test factory pointer, same factory object cannot be passed
+// into that method twice. But ParameterizedTestSuiteInfo is going to call
+// it for each Test/Parameter value combination. Thus it needs meta factory
+// creator class.
+template <class TestSuite>
+class TestMetaFactory
+ : public TestMetaFactoryBase<typename TestSuite::ParamType> {
+ public:
+ using ParamType = typename TestSuite::ParamType;
+
+ TestMetaFactory() {}
+
+ TestFactoryBase* CreateTestFactory(ParamType parameter) override {
+ return new ParameterizedTestFactory<TestSuite>(parameter);
+ }
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(TestMetaFactory);
+};
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// ParameterizedTestSuiteInfoBase is a generic interface
+// to ParameterizedTestSuiteInfo classes. ParameterizedTestSuiteInfoBase
+// accumulates test information provided by TEST_P macro invocations
+// and generators provided by INSTANTIATE_TEST_SUITE_P macro invocations
+// and uses that information to register all resulting test instances
+// in RegisterTests method. The ParameterizeTestSuiteRegistry class holds
+// a collection of pointers to the ParameterizedTestSuiteInfo objects
+// and calls RegisterTests() on each of them when asked.
+class ParameterizedTestSuiteInfoBase {
+ public:
+ virtual ~ParameterizedTestSuiteInfoBase() {}
+
+ // Base part of test suite name for display purposes.
+ virtual const std::string& GetTestSuiteName() const = 0;
+ // Test suite id to verify identity.
+ virtual TypeId GetTestSuiteTypeId() const = 0;
+ // UnitTest class invokes this method to register tests in this
+ // test suite right before running them in RUN_ALL_TESTS macro.
+ // This method should not be called more than once on any single
+ // instance of a ParameterizedTestSuiteInfoBase derived class.
+ virtual void RegisterTests() = 0;
+
+ protected:
+ ParameterizedTestSuiteInfoBase() {}
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestSuiteInfoBase);
+};
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Report a the name of a test_suit as safe to ignore
+// as the side effect of construction of this type.
+struct GTEST_API_ MarkAsIgnored {
+ explicit MarkAsIgnored(const char* test_suite);
+};
+
+GTEST_API_ void InsertSyntheticTestCase(const std::string& name,
+ CodeLocation location, bool has_test_p);
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// ParameterizedTestSuiteInfo accumulates tests obtained from TEST_P
+// macro invocations for a particular test suite and generators
+// obtained from INSTANTIATE_TEST_SUITE_P macro invocations for that
+// test suite. It registers tests with all values generated by all
+// generators when asked.
+template <class TestSuite>
+class ParameterizedTestSuiteInfo : public ParameterizedTestSuiteInfoBase {
+ public:
+ // ParamType and GeneratorCreationFunc are private types but are required
+ // for declarations of public methods AddTestPattern() and
+ // AddTestSuiteInstantiation().
+ using ParamType = typename TestSuite::ParamType;
+ // A function that returns an instance of appropriate generator type.
+ typedef ParamGenerator<ParamType>(GeneratorCreationFunc)();
+ using ParamNameGeneratorFunc = std::string(const TestParamInfo<ParamType>&);
+
+ explicit ParameterizedTestSuiteInfo(const char* name,
+ CodeLocation code_location)
+ : test_suite_name_(name), code_location_(code_location) {}
+
+ // Test suite base name for display purposes.
+ const std::string& GetTestSuiteName() const override {
+ return test_suite_name_;
+ }
+ // Test suite id to verify identity.
+ TypeId GetTestSuiteTypeId() const override { return GetTypeId<TestSuite>(); }
+ // TEST_P macro uses AddTestPattern() to record information
+ // about a single test in a LocalTestInfo structure.
+ // test_suite_name is the base name of the test suite (without invocation
+ // prefix). test_base_name is the name of an individual test without
+ // parameter index. For the test SequenceA/FooTest.DoBar/1 FooTest is
+ // test suite base name and DoBar is test base name.
+ void AddTestPattern(const char* test_suite_name, const char* test_base_name,
+ TestMetaFactoryBase<ParamType>* meta_factory,
+ CodeLocation code_location) {
+ tests_.push_back(std::shared_ptr<TestInfo>(new TestInfo(
+ test_suite_name, test_base_name, meta_factory, code_location)));
+ }
+ // INSTANTIATE_TEST_SUITE_P macro uses AddGenerator() to record information
+ // about a generator.
+ int AddTestSuiteInstantiation(const std::string& instantiation_name,
+ GeneratorCreationFunc* func,
+ ParamNameGeneratorFunc* name_func,
+ const char* file, int line) {
+ instantiations_.push_back(
+ InstantiationInfo(instantiation_name, func, name_func, file, line));
+ return 0; // Return value used only to run this method in namespace scope.
+ }
+ // UnitTest class invokes this method to register tests in this test suite
+ // right before running tests in RUN_ALL_TESTS macro.
+ // This method should not be called more than once on any single
+ // instance of a ParameterizedTestSuiteInfoBase derived class.
+ // UnitTest has a guard to prevent from calling this method more than once.
+ void RegisterTests() override {
+ bool generated_instantiations = false;
+
+ for (typename TestInfoContainer::iterator test_it = tests_.begin();
+ test_it != tests_.end(); ++test_it) {
+ std::shared_ptr<TestInfo> test_info = *test_it;
+ for (typename InstantiationContainer::iterator gen_it =
+ instantiations_.begin(); gen_it != instantiations_.end();
+ ++gen_it) {
+ const std::string& instantiation_name = gen_it->name;
+ ParamGenerator<ParamType> generator((*gen_it->generator)());
+ ParamNameGeneratorFunc* name_func = gen_it->name_func;
+ const char* file = gen_it->file;
+ int line = gen_it->line;
+
+ std::string test_suite_name;
+ if ( !instantiation_name.empty() )
+ test_suite_name = instantiation_name + "/";
+ test_suite_name += test_info->test_suite_base_name;
+
+ size_t i = 0;
+ std::set<std::string> test_param_names;
+ for (typename ParamGenerator<ParamType>::iterator param_it =
+ generator.begin();
+ param_it != generator.end(); ++param_it, ++i) {
+ generated_instantiations = true;
+
+ Message test_name_stream;
+
+ std::string param_name = name_func(
+ TestParamInfo<ParamType>(*param_it, i));
+
+ GTEST_CHECK_(IsValidParamName(param_name))
+ << "Parameterized test name '" << param_name
+ << "' is invalid, in " << file
+ << " line " << line << std::endl;
+
+ GTEST_CHECK_(test_param_names.count(param_name) == 0)
+ << "Duplicate parameterized test name '" << param_name
+ << "', in " << file << " line " << line << std::endl;
+
+ test_param_names.insert(param_name);
+
+ if (!test_info->test_base_name.empty()) {
+ test_name_stream << test_info->test_base_name << "/";
+ }
+ test_name_stream << param_name;
+ MakeAndRegisterTestInfo(
+ test_suite_name.c_str(), test_name_stream.GetString().c_str(),
+ nullptr, // No type parameter.
+ PrintToString(*param_it).c_str(), test_info->code_location,
+ GetTestSuiteTypeId(),
+ SuiteApiResolver<TestSuite>::GetSetUpCaseOrSuite(file, line),
+ SuiteApiResolver<TestSuite>::GetTearDownCaseOrSuite(file, line),
+ test_info->test_meta_factory->CreateTestFactory(*param_it));
+ } // for param_it
+ } // for gen_it
+ } // for test_it
+
+ if (!generated_instantiations) {
+ // There are no generaotrs, or they all generate nothing ...
+ InsertSyntheticTestCase(GetTestSuiteName(), code_location_,
+ !tests_.empty());
+ }
+ } // RegisterTests
+
+ private:
+ // LocalTestInfo structure keeps information about a single test registered
+ // with TEST_P macro.
+ struct TestInfo {
+ TestInfo(const char* a_test_suite_base_name, const char* a_test_base_name,
+ TestMetaFactoryBase<ParamType>* a_test_meta_factory,
+ CodeLocation a_code_location)
+ : test_suite_base_name(a_test_suite_base_name),
+ test_base_name(a_test_base_name),
+ test_meta_factory(a_test_meta_factory),
+ code_location(a_code_location) {}
+
+ const std::string test_suite_base_name;
+ const std::string test_base_name;
+ const std::unique_ptr<TestMetaFactoryBase<ParamType> > test_meta_factory;
+ const CodeLocation code_location;
+ };
+ using TestInfoContainer = ::std::vector<std::shared_ptr<TestInfo> >;
+ // Records data received from INSTANTIATE_TEST_SUITE_P macros:
+ // <Instantiation name, Sequence generator creation function,
+ // Name generator function, Source file, Source line>
+ struct InstantiationInfo {
+ InstantiationInfo(const std::string &name_in,
+ GeneratorCreationFunc* generator_in,
+ ParamNameGeneratorFunc* name_func_in,
+ const char* file_in,
+ int line_in)
+ : name(name_in),
+ generator(generator_in),
+ name_func(name_func_in),
+ file(file_in),
+ line(line_in) {}
+
+ std::string name;
+ GeneratorCreationFunc* generator;
+ ParamNameGeneratorFunc* name_func;
+ const char* file;
+ int line;
+ };
+ typedef ::std::vector<InstantiationInfo> InstantiationContainer;
+
+ static bool IsValidParamName(const std::string& name) {
+ // Check for empty string
+ if (name.empty())
+ return false;
+
+ // Check for invalid characters
+ for (std::string::size_type index = 0; index < name.size(); ++index) {
+ if (!IsAlNum(name[index]) && name[index] != '_')
+ return false;
+ }
+
+ return true;
+ }
+
+ const std::string test_suite_name_;
+ CodeLocation code_location_;
+ TestInfoContainer tests_;
+ InstantiationContainer instantiations_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestSuiteInfo);
+}; // class ParameterizedTestSuiteInfo
+
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+template <class TestCase>
+using ParameterizedTestCaseInfo = ParameterizedTestSuiteInfo<TestCase>;
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// ParameterizedTestSuiteRegistry contains a map of
+// ParameterizedTestSuiteInfoBase classes accessed by test suite names. TEST_P
+// and INSTANTIATE_TEST_SUITE_P macros use it to locate their corresponding
+// ParameterizedTestSuiteInfo descriptors.
+class ParameterizedTestSuiteRegistry {
+ public:
+ ParameterizedTestSuiteRegistry() {}
+ ~ParameterizedTestSuiteRegistry() {
+ for (auto& test_suite_info : test_suite_infos_) {
+ delete test_suite_info;
+ }
+ }
+
+ // Looks up or creates and returns a structure containing information about
+ // tests and instantiations of a particular test suite.
+ template <class TestSuite>
+ ParameterizedTestSuiteInfo<TestSuite>* GetTestSuitePatternHolder(
+ const char* test_suite_name, CodeLocation code_location) {
+ ParameterizedTestSuiteInfo<TestSuite>* typed_test_info = nullptr;
+ for (auto& test_suite_info : test_suite_infos_) {
+ if (test_suite_info->GetTestSuiteName() == test_suite_name) {
+ if (test_suite_info->GetTestSuiteTypeId() != GetTypeId<TestSuite>()) {
+ // Complain about incorrect usage of Google Test facilities
+ // and terminate the program since we cannot guaranty correct
+ // test suite setup and tear-down in this case.
+ ReportInvalidTestSuiteType(test_suite_name, code_location);
+ posix::Abort();
+ } else {
+ // At this point we are sure that the object we found is of the same
+ // type we are looking for, so we downcast it to that type
+ // without further checks.
+ typed_test_info = CheckedDowncastToActualType<
+ ParameterizedTestSuiteInfo<TestSuite> >(test_suite_info);
+ }
+ break;
+ }
+ }
+ if (typed_test_info == nullptr) {
+ typed_test_info = new ParameterizedTestSuiteInfo<TestSuite>(
+ test_suite_name, code_location);
+ test_suite_infos_.push_back(typed_test_info);
+ }
+ return typed_test_info;
+ }
+ void RegisterTests() {
+ for (auto& test_suite_info : test_suite_infos_) {
+ test_suite_info->RegisterTests();
+ }
+ }
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ template <class TestCase>
+ ParameterizedTestCaseInfo<TestCase>* GetTestCasePatternHolder(
+ const char* test_case_name, CodeLocation code_location) {
+ return GetTestSuitePatternHolder<TestCase>(test_case_name, code_location);
+ }
+
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+ private:
+ using TestSuiteInfoContainer = ::std::vector<ParameterizedTestSuiteInfoBase*>;
+
+ TestSuiteInfoContainer test_suite_infos_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestSuiteRegistry);
+};
+
+// Keep track of what type-parameterized test suite are defined and
+// where as well as which are intatiated. This allows susequently
+// identifying suits that are defined but never used.
+class TypeParameterizedTestSuiteRegistry {
+ public:
+ // Add a suite definition
+ void RegisterTestSuite(const char* test_suite_name,
+ CodeLocation code_location);
+
+ // Add an instantiation of a suit.
+ void RegisterInstantiation(const char* test_suite_name);
+
+ // For each suit repored as defined but not reported as instantiation,
+ // emit a test that reports that fact (configurably, as an error).
+ void CheckForInstantiations();
+
+ private:
+ struct TypeParameterizedTestSuiteInfo {
+ explicit TypeParameterizedTestSuiteInfo(CodeLocation c)
+ : code_location(c), instantiated(false) {}
+
+ CodeLocation code_location;
+ bool instantiated;
+ };
+
+ std::map<std::string, TypeParameterizedTestSuiteInfo> suites_;
+};
+
+} // namespace internal
+
+// Forward declarations of ValuesIn(), which is implemented in
+// include/gtest/gtest-param-test.h.
+template <class Container>
+internal::ParamGenerator<typename Container::value_type> ValuesIn(
+ const Container& container);
+
+namespace internal {
+// Used in the Values() function to provide polymorphic capabilities.
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4100)
+#endif
+
+template <typename... Ts>
+class ValueArray {
+ public:
+ explicit ValueArray(Ts... v) : v_(FlatTupleConstructTag{}, std::move(v)...) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const { // NOLINT
+ return ValuesIn(MakeVector<T>(MakeIndexSequence<sizeof...(Ts)>()));
+ }
+
+ private:
+ template <typename T, size_t... I>
+ std::vector<T> MakeVector(IndexSequence<I...>) const {
+ return std::vector<T>{static_cast<T>(v_.template Get<I>())...};
+ }
+
+ FlatTuple<Ts...> v_;
+};
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+template <typename... T>
+class CartesianProductGenerator
+ : public ParamGeneratorInterface<::std::tuple<T...>> {
+ public:
+ typedef ::std::tuple<T...> ParamType;
+
+ CartesianProductGenerator(const std::tuple<ParamGenerator<T>...>& g)
+ : generators_(g) {}
+ ~CartesianProductGenerator() override {}
+
+ ParamIteratorInterface<ParamType>* Begin() const override {
+ return new Iterator(this, generators_, false);
+ }
+ ParamIteratorInterface<ParamType>* End() const override {
+ return new Iterator(this, generators_, true);
+ }
+
+ private:
+ template <class I>
+ class IteratorImpl;
+ template <size_t... I>
+ class IteratorImpl<IndexSequence<I...>>
+ : public ParamIteratorInterface<ParamType> {
+ public:
+ IteratorImpl(const ParamGeneratorInterface<ParamType>* base,
+ const std::tuple<ParamGenerator<T>...>& generators, bool is_end)
+ : base_(base),
+ begin_(std::get<I>(generators).begin()...),
+ end_(std::get<I>(generators).end()...),
+ current_(is_end ? end_ : begin_) {
+ ComputeCurrentValue();
+ }
+ ~IteratorImpl() override {}
+
+ const ParamGeneratorInterface<ParamType>* BaseGenerator() const override {
+ return base_;
+ }
+ // Advance should not be called on beyond-of-range iterators
+ // so no component iterators must be beyond end of range, either.
+ void Advance() override {
+ assert(!AtEnd());
+ // Advance the last iterator.
+ ++std::get<sizeof...(T) - 1>(current_);
+ // if that reaches end, propagate that up.
+ AdvanceIfEnd<sizeof...(T) - 1>();
+ ComputeCurrentValue();
+ }
+ ParamIteratorInterface<ParamType>* Clone() const override {
+ return new IteratorImpl(*this);
+ }
+
+ const ParamType* Current() const override { return current_value_.get(); }
+
+ bool Equals(const ParamIteratorInterface<ParamType>& other) const override {
+ // Having the same base generator guarantees that the other
+ // iterator is of the same type and we can downcast.
+ GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+ << "The program attempted to compare iterators "
+ << "from different generators." << std::endl;
+ const IteratorImpl* typed_other =
+ CheckedDowncastToActualType<const IteratorImpl>(&other);
+
+ // We must report iterators equal if they both point beyond their
+ // respective ranges. That can happen in a variety of fashions,
+ // so we have to consult AtEnd().
+ if (AtEnd() && typed_other->AtEnd()) return true;
+
+ bool same = true;
+ bool dummy[] = {
+ (same = same && std::get<I>(current_) ==
+ std::get<I>(typed_other->current_))...};
+ (void)dummy;
+ return same;
+ }
+
+ private:
+ template <size_t ThisI>
+ void AdvanceIfEnd() {
+ if (std::get<ThisI>(current_) != std::get<ThisI>(end_)) return;
+
+ bool last = ThisI == 0;
+ if (last) {
+ // We are done. Nothing else to propagate.
+ return;
+ }
+
+ constexpr size_t NextI = ThisI - (ThisI != 0);
+ std::get<ThisI>(current_) = std::get<ThisI>(begin_);
+ ++std::get<NextI>(current_);
+ AdvanceIfEnd<NextI>();
+ }
+
+ void ComputeCurrentValue() {
+ if (!AtEnd())
+ current_value_ = std::make_shared<ParamType>(*std::get<I>(current_)...);
+ }
+ bool AtEnd() const {
+ bool at_end = false;
+ bool dummy[] = {
+ (at_end = at_end || std::get<I>(current_) == std::get<I>(end_))...};
+ (void)dummy;
+ return at_end;
+ }
+
+ const ParamGeneratorInterface<ParamType>* const base_;
+ std::tuple<typename ParamGenerator<T>::iterator...> begin_;
+ std::tuple<typename ParamGenerator<T>::iterator...> end_;
+ std::tuple<typename ParamGenerator<T>::iterator...> current_;
+ std::shared_ptr<ParamType> current_value_;
+ };
+
+ using Iterator = IteratorImpl<typename MakeIndexSequence<sizeof...(T)>::type>;
+
+ std::tuple<ParamGenerator<T>...> generators_;
+};
+
+template <class... Gen>
+class CartesianProductHolder {
+ public:
+ CartesianProductHolder(const Gen&... g) : generators_(g...) {}
+ template <typename... T>
+ operator ParamGenerator<::std::tuple<T...>>() const {
+ return ParamGenerator<::std::tuple<T...>>(
+ new CartesianProductGenerator<T...>(generators_));
+ }
+
+ private:
+ std::tuple<Gen...> generators_;
+};
+
+} // namespace internal
+} // namespace testing
+
+#endif // GOOGLETEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
+
+namespace testing {
+
+// Functions producing parameter generators.
+//
+// Google Test uses these generators to produce parameters for value-
+// parameterized tests. When a parameterized test suite is instantiated
+// with a particular generator, Google Test creates and runs tests
+// for each element in the sequence produced by the generator.
+//
+// In the following sample, tests from test suite FooTest are instantiated
+// each three times with parameter values 3, 5, and 8:
+//
+// class FooTest : public TestWithParam<int> { ... };
+//
+// TEST_P(FooTest, TestThis) {
+// }
+// TEST_P(FooTest, TestThat) {
+// }
+// INSTANTIATE_TEST_SUITE_P(TestSequence, FooTest, Values(3, 5, 8));
+//
+
+// Range() returns generators providing sequences of values in a range.
+//
+// Synopsis:
+// Range(start, end)
+// - returns a generator producing a sequence of values {start, start+1,
+// start+2, ..., }.
+// Range(start, end, step)
+// - returns a generator producing a sequence of values {start, start+step,
+// start+step+step, ..., }.
+// Notes:
+// * The generated sequences never include end. For example, Range(1, 5)
+// returns a generator producing a sequence {1, 2, 3, 4}. Range(1, 9, 2)
+// returns a generator producing {1, 3, 5, 7}.
+// * start and end must have the same type. That type may be any integral or
+// floating-point type or a user defined type satisfying these conditions:
+// * It must be assignable (have operator=() defined).
+// * It must have operator+() (operator+(int-compatible type) for
+// two-operand version).
+// * It must have operator<() defined.
+// Elements in the resulting sequences will also have that type.
+// * Condition start < end must be satisfied in order for resulting sequences
+// to contain any elements.
+//
+template <typename T, typename IncrementT>
+internal::ParamGenerator<T> Range(T start, T end, IncrementT step) {
+ return internal::ParamGenerator<T>(
+ new internal::RangeGenerator<T, IncrementT>(start, end, step));
+}
+
+template <typename T>
+internal::ParamGenerator<T> Range(T start, T end) {
+ return Range(start, end, 1);
+}
+
+// ValuesIn() function allows generation of tests with parameters coming from
+// a container.
+//
+// Synopsis:
+// ValuesIn(const T (&array)[N])
+// - returns a generator producing sequences with elements from
+// a C-style array.
+// ValuesIn(const Container& container)
+// - returns a generator producing sequences with elements from
+// an STL-style container.
+// ValuesIn(Iterator begin, Iterator end)
+// - returns a generator producing sequences with elements from
+// a range [begin, end) defined by a pair of STL-style iterators. These
+// iterators can also be plain C pointers.
+//
+// Please note that ValuesIn copies the values from the containers
+// passed in and keeps them to generate tests in RUN_ALL_TESTS().
+//
+// Examples:
+//
+// This instantiates tests from test suite StringTest
+// each with C-string values of "foo", "bar", and "baz":
+//
+// const char* strings[] = {"foo", "bar", "baz"};
+// INSTANTIATE_TEST_SUITE_P(StringSequence, StringTest, ValuesIn(strings));
+//
+// This instantiates tests from test suite StlStringTest
+// each with STL strings with values "a" and "b":
+//
+// ::std::vector< ::std::string> GetParameterStrings() {
+// ::std::vector< ::std::string> v;
+// v.push_back("a");
+// v.push_back("b");
+// return v;
+// }
+//
+// INSTANTIATE_TEST_SUITE_P(CharSequence,
+// StlStringTest,
+// ValuesIn(GetParameterStrings()));
+//
+//
+// This will also instantiate tests from CharTest
+// each with parameter values 'a' and 'b':
+//
+// ::std::list<char> GetParameterChars() {
+// ::std::list<char> list;
+// list.push_back('a');
+// list.push_back('b');
+// return list;
+// }
+// ::std::list<char> l = GetParameterChars();
+// INSTANTIATE_TEST_SUITE_P(CharSequence2,
+// CharTest,
+// ValuesIn(l.begin(), l.end()));
+//
+template <typename ForwardIterator>
+internal::ParamGenerator<
+ typename std::iterator_traits<ForwardIterator>::value_type>
+ValuesIn(ForwardIterator begin, ForwardIterator end) {
+ typedef typename std::iterator_traits<ForwardIterator>::value_type ParamType;
+ return internal::ParamGenerator<ParamType>(
+ new internal::ValuesInIteratorRangeGenerator<ParamType>(begin, end));
+}
+
+template <typename T, size_t N>
+internal::ParamGenerator<T> ValuesIn(const T (&array)[N]) {
+ return ValuesIn(array, array + N);
+}
+
+template <class Container>
+internal::ParamGenerator<typename Container::value_type> ValuesIn(
+ const Container& container) {
+ return ValuesIn(container.begin(), container.end());
+}
+
+// Values() allows generating tests from explicitly specified list of
+// parameters.
+//
+// Synopsis:
+// Values(T v1, T v2, ..., T vN)
+// - returns a generator producing sequences with elements v1, v2, ..., vN.
+//
+// For example, this instantiates tests from test suite BarTest each
+// with values "one", "two", and "three":
+//
+// INSTANTIATE_TEST_SUITE_P(NumSequence,
+// BarTest,
+// Values("one", "two", "three"));
+//
+// This instantiates tests from test suite BazTest each with values 1, 2, 3.5.
+// The exact type of values will depend on the type of parameter in BazTest.
+//
+// INSTANTIATE_TEST_SUITE_P(FloatingNumbers, BazTest, Values(1, 2, 3.5));
+//
+//
+template <typename... T>
+internal::ValueArray<T...> Values(T... v) {
+ return internal::ValueArray<T...>(std::move(v)...);
+}
+
+// Bool() allows generating tests with parameters in a set of (false, true).
+//
+// Synopsis:
+// Bool()
+// - returns a generator producing sequences with elements {false, true}.
+//
+// It is useful when testing code that depends on Boolean flags. Combinations
+// of multiple flags can be tested when several Bool()'s are combined using
+// Combine() function.
+//
+// In the following example all tests in the test suite FlagDependentTest
+// will be instantiated twice with parameters false and true.
+//
+// class FlagDependentTest : public testing::TestWithParam<bool> {
+// virtual void SetUp() {
+// external_flag = GetParam();
+// }
+// }
+// INSTANTIATE_TEST_SUITE_P(BoolSequence, FlagDependentTest, Bool());
+//
+inline internal::ParamGenerator<bool> Bool() {
+ return Values(false, true);
+}
+
+// Combine() allows the user to combine two or more sequences to produce
+// values of a Cartesian product of those sequences' elements.
+//
+// Synopsis:
+// Combine(gen1, gen2, ..., genN)
+// - returns a generator producing sequences with elements coming from
+// the Cartesian product of elements from the sequences generated by
+// gen1, gen2, ..., genN. The sequence elements will have a type of
+// std::tuple<T1, T2, ..., TN> where T1, T2, ..., TN are the types
+// of elements from sequences produces by gen1, gen2, ..., genN.
+//
+// Example:
+//
+// This will instantiate tests in test suite AnimalTest each one with
+// the parameter values tuple("cat", BLACK), tuple("cat", WHITE),
+// tuple("dog", BLACK), and tuple("dog", WHITE):
+//
+// enum Color { BLACK, GRAY, WHITE };
+// class AnimalTest
+// : public testing::TestWithParam<std::tuple<const char*, Color> > {...};
+//
+// TEST_P(AnimalTest, AnimalLooksNice) {...}
+//
+// INSTANTIATE_TEST_SUITE_P(AnimalVariations, AnimalTest,
+// Combine(Values("cat", "dog"),
+// Values(BLACK, WHITE)));
+//
+// This will instantiate tests in FlagDependentTest with all variations of two
+// Boolean flags:
+//
+// class FlagDependentTest
+// : public testing::TestWithParam<std::tuple<bool, bool> > {
+// virtual void SetUp() {
+// // Assigns external_flag_1 and external_flag_2 values from the tuple.
+// std::tie(external_flag_1, external_flag_2) = GetParam();
+// }
+// };
+//
+// TEST_P(FlagDependentTest, TestFeature1) {
+// // Test your code using external_flag_1 and external_flag_2 here.
+// }
+// INSTANTIATE_TEST_SUITE_P(TwoBoolSequence, FlagDependentTest,
+// Combine(Bool(), Bool()));
+//
+template <typename... Generator>
+internal::CartesianProductHolder<Generator...> Combine(const Generator&... g) {
+ return internal::CartesianProductHolder<Generator...>(g...);
+}
+
+#define TEST_P(test_suite_name, test_name) \
+ class GTEST_TEST_CLASS_NAME_(test_suite_name, test_name) \
+ : public test_suite_name { \
+ public: \
+ GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)() {} \
+ void TestBody() override; \
+ \
+ private: \
+ static int AddToRegistry() { \
+ ::testing::UnitTest::GetInstance() \
+ ->parameterized_test_registry() \
+ .GetTestSuitePatternHolder<test_suite_name>( \
+ GTEST_STRINGIFY_(test_suite_name), \
+ ::testing::internal::CodeLocation(__FILE__, __LINE__)) \
+ ->AddTestPattern( \
+ GTEST_STRINGIFY_(test_suite_name), GTEST_STRINGIFY_(test_name), \
+ new ::testing::internal::TestMetaFactory<GTEST_TEST_CLASS_NAME_( \
+ test_suite_name, test_name)>(), \
+ ::testing::internal::CodeLocation(__FILE__, __LINE__)); \
+ return 0; \
+ } \
+ static int gtest_registering_dummy_ GTEST_ATTRIBUTE_UNUSED_; \
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(GTEST_TEST_CLASS_NAME_(test_suite_name, \
+ test_name)); \
+ }; \
+ int GTEST_TEST_CLASS_NAME_(test_suite_name, \
+ test_name)::gtest_registering_dummy_ = \
+ GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)::AddToRegistry(); \
+ void GTEST_TEST_CLASS_NAME_(test_suite_name, test_name)::TestBody()
+
+// The last argument to INSTANTIATE_TEST_SUITE_P allows the user to specify
+// generator and an optional function or functor that generates custom test name
+// suffixes based on the test parameters. Such a function or functor should
+// accept one argument of type testing::TestParamInfo<class ParamType>, and
+// return std::string.
+//
+// testing::PrintToStringParamName is a builtin test suffix generator that
+// returns the value of testing::PrintToString(GetParam()).
+//
+// Note: test names must be non-empty, unique, and may only contain ASCII
+// alphanumeric characters or underscore. Because PrintToString adds quotes
+// to std::string and C strings, it won't work for these types.
+
+#define GTEST_EXPAND_(arg) arg
+#define GTEST_GET_FIRST_(first, ...) first
+#define GTEST_GET_SECOND_(first, second, ...) second
+
+#define INSTANTIATE_TEST_SUITE_P(prefix, test_suite_name, ...) \
+ static ::testing::internal::ParamGenerator<test_suite_name::ParamType> \
+ gtest_##prefix##test_suite_name##_EvalGenerator_() { \
+ return GTEST_EXPAND_(GTEST_GET_FIRST_(__VA_ARGS__, DUMMY_PARAM_)); \
+ } \
+ static ::std::string gtest_##prefix##test_suite_name##_EvalGenerateName_( \
+ const ::testing::TestParamInfo<test_suite_name::ParamType>& info) { \
+ if (::testing::internal::AlwaysFalse()) { \
+ ::testing::internal::TestNotEmpty(GTEST_EXPAND_(GTEST_GET_SECOND_( \
+ __VA_ARGS__, \
+ ::testing::internal::DefaultParamName<test_suite_name::ParamType>, \
+ DUMMY_PARAM_))); \
+ auto t = std::make_tuple(__VA_ARGS__); \
+ static_assert(std::tuple_size<decltype(t)>::value <= 2, \
+ "Too Many Args!"); \
+ } \
+ return ((GTEST_EXPAND_(GTEST_GET_SECOND_( \
+ __VA_ARGS__, \
+ ::testing::internal::DefaultParamName<test_suite_name::ParamType>, \
+ DUMMY_PARAM_))))(info); \
+ } \
+ static int gtest_##prefix##test_suite_name##_dummy_ \
+ GTEST_ATTRIBUTE_UNUSED_ = \
+ ::testing::UnitTest::GetInstance() \
+ ->parameterized_test_registry() \
+ .GetTestSuitePatternHolder<test_suite_name>( \
+ GTEST_STRINGIFY_(test_suite_name), \
+ ::testing::internal::CodeLocation(__FILE__, __LINE__)) \
+ ->AddTestSuiteInstantiation( \
+ GTEST_STRINGIFY_(prefix), \
+ &gtest_##prefix##test_suite_name##_EvalGenerator_, \
+ &gtest_##prefix##test_suite_name##_EvalGenerateName_, \
+ __FILE__, __LINE__)
+
+
+// Allow Marking a Parameterized test class as not needing to be instantiated.
+#define GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(T) \
+ namespace gtest_do_not_use_outside_namespace_scope {} \
+ static const ::testing::internal::MarkAsIgnored gtest_allow_ignore_##T( \
+ GTEST_STRINGIFY_(T))
+
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+#define INSTANTIATE_TEST_CASE_P \
+ static_assert(::testing::internal::InstantiateTestCase_P_IsDeprecated(), \
+ ""); \
+ INSTANTIATE_TEST_SUITE_P
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+} // namespace testing
+
+#endif // GOOGLETEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
+// Copyright 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+//
+// Google C++ Testing and Mocking Framework definitions useful in production code.
+// GOOGLETEST_CM0003 DO NOT DELETE
+
+#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_PROD_H_
+#define GOOGLETEST_INCLUDE_GTEST_GTEST_PROD_H_
+
+// When you need to test the private or protected members of a class,
+// use the FRIEND_TEST macro to declare your tests as friends of the
+// class. For example:
+//
+// class MyClass {
+// private:
+// void PrivateMethod();
+// FRIEND_TEST(MyClassTest, PrivateMethodWorks);
+// };
+//
+// class MyClassTest : public testing::Test {
+// // ...
+// };
+//
+// TEST_F(MyClassTest, PrivateMethodWorks) {
+// // Can call MyClass::PrivateMethod() here.
+// }
+//
+// Note: The test class must be in the same namespace as the class being tested.
+// For example, putting MyClassTest in an anonymous namespace will not work.
+
+#define FRIEND_TEST(test_case_name, test_name)\
+friend class test_case_name##_##test_name##_Test
+
+#endif // GOOGLETEST_INCLUDE_GTEST_GTEST_PROD_H_
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// GOOGLETEST_CM0001 DO NOT DELETE
+
+#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_
+#define GOOGLETEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_
+
+// This header implements typed tests and type-parameterized tests.
+
+// Typed (aka type-driven) tests repeat the same test for types in a
+// list. You must know which types you want to test with when writing
+// typed tests. Here's how you do it:
+
+#if 0
+
+// First, define a fixture class template. It should be parameterized
+// by a type. Remember to derive it from testing::Test.
+template <typename T>
+class FooTest : public testing::Test {
+ public:
+ ...
+ typedef std::list<T> List;
+ static T shared_;
+ T value_;
+};
+
+// Next, associate a list of types with the test suite, which will be
+// repeated for each type in the list. The typedef is necessary for
+// the macro to parse correctly.
+typedef testing::Types<char, int, unsigned int> MyTypes;
+TYPED_TEST_SUITE(FooTest, MyTypes);
+
+// If the type list contains only one type, you can write that type
+// directly without Types<...>:
+// TYPED_TEST_SUITE(FooTest, int);
+
+// Then, use TYPED_TEST() instead of TEST_F() to define as many typed
+// tests for this test suite as you want.
+TYPED_TEST(FooTest, DoesBlah) {
+ // Inside a test, refer to the special name TypeParam to get the type
+ // parameter. Since we are inside a derived class template, C++ requires
+ // us to visit the members of FooTest via 'this'.
+ TypeParam n = this->value_;
+
+ // To visit static members of the fixture, add the TestFixture::
+ // prefix.
+ n += TestFixture::shared_;
+
+ // To refer to typedefs in the fixture, add the "typename
+ // TestFixture::" prefix.
+ typename TestFixture::List values;
+ values.push_back(n);
+ ...
+}
+
+TYPED_TEST(FooTest, HasPropertyA) { ... }
+
+// TYPED_TEST_SUITE takes an optional third argument which allows to specify a
+// class that generates custom test name suffixes based on the type. This should
+// be a class which has a static template function GetName(int index) returning
+// a string for each type. The provided integer index equals the index of the
+// type in the provided type list. In many cases the index can be ignored.
+//
+// For example:
+// class MyTypeNames {
+// public:
+// template <typename T>
+// static std::string GetName(int) {
+// if (std::is_same<T, char>()) return "char";
+// if (std::is_same<T, int>()) return "int";
+// if (std::is_same<T, unsigned int>()) return "unsignedInt";
+// }
+// };
+// TYPED_TEST_SUITE(FooTest, MyTypes, MyTypeNames);
+
+#endif // 0
+
+// Type-parameterized tests are abstract test patterns parameterized
+// by a type. Compared with typed tests, type-parameterized tests
+// allow you to define the test pattern without knowing what the type
+// parameters are. The defined pattern can be instantiated with
+// different types any number of times, in any number of translation
+// units.
+//
+// If you are designing an interface or concept, you can define a
+// suite of type-parameterized tests to verify properties that any
+// valid implementation of the interface/concept should have. Then,
+// each implementation can easily instantiate the test suite to verify
+// that it conforms to the requirements, without having to write
+// similar tests repeatedly. Here's an example:
+
+#if 0
+
+// First, define a fixture class template. It should be parameterized
+// by a type. Remember to derive it from testing::Test.
+template <typename T>
+class FooTest : public testing::Test {
+ ...
+};
+
+// Next, declare that you will define a type-parameterized test suite
+// (the _P suffix is for "parameterized" or "pattern", whichever you
+// prefer):
+TYPED_TEST_SUITE_P(FooTest);
+
+// Then, use TYPED_TEST_P() to define as many type-parameterized tests
+// for this type-parameterized test suite as you want.
+TYPED_TEST_P(FooTest, DoesBlah) {
+ // Inside a test, refer to TypeParam to get the type parameter.
+ TypeParam n = 0;
+ ...
+}
+
+TYPED_TEST_P(FooTest, HasPropertyA) { ... }
+
+// Now the tricky part: you need to register all test patterns before
+// you can instantiate them. The first argument of the macro is the
+// test suite name; the rest are the names of the tests in this test
+// case.
+REGISTER_TYPED_TEST_SUITE_P(FooTest,
+ DoesBlah, HasPropertyA);
+
+// Finally, you are free to instantiate the pattern with the types you
+// want. If you put the above code in a header file, you can #include
+// it in multiple C++ source files and instantiate it multiple times.
+//
+// To distinguish different instances of the pattern, the first
+// argument to the INSTANTIATE_* macro is a prefix that will be added
+// to the actual test suite name. Remember to pick unique prefixes for
+// different instances.
+typedef testing::Types<char, int, unsigned int> MyTypes;
+INSTANTIATE_TYPED_TEST_SUITE_P(My, FooTest, MyTypes);
+
+// If the type list contains only one type, you can write that type
+// directly without Types<...>:
+// INSTANTIATE_TYPED_TEST_SUITE_P(My, FooTest, int);
+//
+// Similar to the optional argument of TYPED_TEST_SUITE above,
+// INSTANTIATE_TEST_SUITE_P takes an optional fourth argument which allows to
+// generate custom names.
+// INSTANTIATE_TYPED_TEST_SUITE_P(My, FooTest, MyTypes, MyTypeNames);
+
+#endif // 0
+
+
+// Implements typed tests.
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Expands to the name of the typedef for the type parameters of the
+// given test suite.
+#define GTEST_TYPE_PARAMS_(TestSuiteName) gtest_type_params_##TestSuiteName##_
+
+// Expands to the name of the typedef for the NameGenerator, responsible for
+// creating the suffixes of the name.
+#define GTEST_NAME_GENERATOR_(TestSuiteName) \
+ gtest_type_params_##TestSuiteName##_NameGenerator
+
+#define TYPED_TEST_SUITE(CaseName, Types, ...) \
+ typedef ::testing::internal::GenerateTypeList<Types>::type \
+ GTEST_TYPE_PARAMS_(CaseName); \
+ typedef ::testing::internal::NameGeneratorSelector<__VA_ARGS__>::type \
+ GTEST_NAME_GENERATOR_(CaseName)
+
+#define TYPED_TEST(CaseName, TestName) \
+ static_assert(sizeof(GTEST_STRINGIFY_(TestName)) > 1, \
+ "test-name must not be empty"); \
+ template <typename gtest_TypeParam_> \
+ class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \
+ : public CaseName<gtest_TypeParam_> { \
+ private: \
+ typedef CaseName<gtest_TypeParam_> TestFixture; \
+ typedef gtest_TypeParam_ TypeParam; \
+ void TestBody() override; \
+ }; \
+ static bool gtest_##CaseName##_##TestName##_registered_ \
+ GTEST_ATTRIBUTE_UNUSED_ = ::testing::internal::TypeParameterizedTest< \
+ CaseName, \
+ ::testing::internal::TemplateSel<GTEST_TEST_CLASS_NAME_(CaseName, \
+ TestName)>, \
+ GTEST_TYPE_PARAMS_( \
+ CaseName)>::Register("", \
+ ::testing::internal::CodeLocation( \
+ __FILE__, __LINE__), \
+ GTEST_STRINGIFY_(CaseName), \
+ GTEST_STRINGIFY_(TestName), 0, \
+ ::testing::internal::GenerateNames< \
+ GTEST_NAME_GENERATOR_(CaseName), \
+ GTEST_TYPE_PARAMS_(CaseName)>()); \
+ template <typename gtest_TypeParam_> \
+ void GTEST_TEST_CLASS_NAME_(CaseName, \
+ TestName)<gtest_TypeParam_>::TestBody()
+
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+#define TYPED_TEST_CASE \
+ static_assert(::testing::internal::TypedTestCaseIsDeprecated(), ""); \
+ TYPED_TEST_SUITE
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+// Implements type-parameterized tests.
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Expands to the namespace name that the type-parameterized tests for
+// the given type-parameterized test suite are defined in. The exact
+// name of the namespace is subject to change without notice.
+#define GTEST_SUITE_NAMESPACE_(TestSuiteName) gtest_suite_##TestSuiteName##_
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Expands to the name of the variable used to remember the names of
+// the defined tests in the given test suite.
+#define GTEST_TYPED_TEST_SUITE_P_STATE_(TestSuiteName) \
+ gtest_typed_test_suite_p_state_##TestSuiteName##_
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE DIRECTLY.
+//
+// Expands to the name of the variable used to remember the names of
+// the registered tests in the given test suite.
+#define GTEST_REGISTERED_TEST_NAMES_(TestSuiteName) \
+ gtest_registered_test_names_##TestSuiteName##_
+
+// The variables defined in the type-parameterized test macros are
+// static as typically these macros are used in a .h file that can be
+// #included in multiple translation units linked together.
+#define TYPED_TEST_SUITE_P(SuiteName) \
+ static ::testing::internal::TypedTestSuitePState \
+ GTEST_TYPED_TEST_SUITE_P_STATE_(SuiteName)
+
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+#define TYPED_TEST_CASE_P \
+ static_assert(::testing::internal::TypedTestCase_P_IsDeprecated(), ""); \
+ TYPED_TEST_SUITE_P
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+#define TYPED_TEST_P(SuiteName, TestName) \
+ namespace GTEST_SUITE_NAMESPACE_(SuiteName) { \
+ template <typename gtest_TypeParam_> \
+ class TestName : public SuiteName<gtest_TypeParam_> { \
+ private: \
+ typedef SuiteName<gtest_TypeParam_> TestFixture; \
+ typedef gtest_TypeParam_ TypeParam; \
+ void TestBody() override; \
+ }; \
+ static bool gtest_##TestName##_defined_ GTEST_ATTRIBUTE_UNUSED_ = \
+ GTEST_TYPED_TEST_SUITE_P_STATE_(SuiteName).AddTestName( \
+ __FILE__, __LINE__, GTEST_STRINGIFY_(SuiteName), \
+ GTEST_STRINGIFY_(TestName)); \
+ } \
+ template <typename gtest_TypeParam_> \
+ void GTEST_SUITE_NAMESPACE_( \
+ SuiteName)::TestName<gtest_TypeParam_>::TestBody()
+
+// Note: this won't work correctly if the trailing arguments are macros.
+#define REGISTER_TYPED_TEST_SUITE_P(SuiteName, ...) \
+ namespace GTEST_SUITE_NAMESPACE_(SuiteName) { \
+ typedef ::testing::internal::Templates<__VA_ARGS__> gtest_AllTests_; \
+ } \
+ static const char* const GTEST_REGISTERED_TEST_NAMES_( \
+ SuiteName) GTEST_ATTRIBUTE_UNUSED_ = \
+ GTEST_TYPED_TEST_SUITE_P_STATE_(SuiteName).VerifyRegisteredTestNames( \
+ GTEST_STRINGIFY_(SuiteName), __FILE__, __LINE__, #__VA_ARGS__)
+
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+#define REGISTER_TYPED_TEST_CASE_P \
+ static_assert(::testing::internal::RegisterTypedTestCase_P_IsDeprecated(), \
+ ""); \
+ REGISTER_TYPED_TEST_SUITE_P
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+#define INSTANTIATE_TYPED_TEST_SUITE_P(Prefix, SuiteName, Types, ...) \
+ static_assert(sizeof(GTEST_STRINGIFY_(Prefix)) > 1, \
+ "test-suit-prefix must not be empty"); \
+ static bool gtest_##Prefix##_##SuiteName GTEST_ATTRIBUTE_UNUSED_ = \
+ ::testing::internal::TypeParameterizedTestSuite< \
+ SuiteName, GTEST_SUITE_NAMESPACE_(SuiteName)::gtest_AllTests_, \
+ ::testing::internal::GenerateTypeList<Types>::type>:: \
+ Register(GTEST_STRINGIFY_(Prefix), \
+ ::testing::internal::CodeLocation(__FILE__, __LINE__), \
+ &GTEST_TYPED_TEST_SUITE_P_STATE_(SuiteName), \
+ GTEST_STRINGIFY_(SuiteName), \
+ GTEST_REGISTERED_TEST_NAMES_(SuiteName), \
+ ::testing::internal::GenerateNames< \
+ ::testing::internal::NameGeneratorSelector< \
+ __VA_ARGS__>::type, \
+ ::testing::internal::GenerateTypeList<Types>::type>())
+
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+#define INSTANTIATE_TYPED_TEST_CASE_P \
+ static_assert( \
+ ::testing::internal::InstantiateTypedTestCase_P_IsDeprecated(), ""); \
+ INSTANTIATE_TYPED_TEST_SUITE_P
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+#endif // GOOGLETEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_
+
+GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \
+/* class A needs to have dll-interface to be used by clients of class B */)
+
+namespace testing {
+
+// Silence C4100 (unreferenced formal parameter) and 4805
+// unsafe mix of type 'const int' and type 'const bool'
+#ifdef _MSC_VER
+# pragma warning(push)
+# pragma warning(disable:4805)
+# pragma warning(disable:4100)
+#endif
+
+
+// Declares the flags.
+
+// This flag temporary enables the disabled tests.
+GTEST_DECLARE_bool_(also_run_disabled_tests);
+
+// This flag brings the debugger on an assertion failure.
+GTEST_DECLARE_bool_(break_on_failure);
+
+// This flag controls whether Google Test catches all test-thrown exceptions
+// and logs them as failures.
+GTEST_DECLARE_bool_(catch_exceptions);
+
+// This flag enables using colors in terminal output. Available values are
+// "yes" to enable colors, "no" (disable colors), or "auto" (the default)
+// to let Google Test decide.
+GTEST_DECLARE_string_(color);
+
+// This flag controls whether the test runner should continue execution past
+// first failure.
+GTEST_DECLARE_bool_(fail_fast);
+
+// This flag sets up the filter to select by name using a glob pattern
+// the tests to run. If the filter is not given all tests are executed.
+GTEST_DECLARE_string_(filter);
+
+// This flag controls whether Google Test installs a signal handler that dumps
+// debugging information when fatal signals are raised.
+GTEST_DECLARE_bool_(install_failure_signal_handler);
+
+// This flag causes the Google Test to list tests. None of the tests listed
+// are actually run if the flag is provided.
+GTEST_DECLARE_bool_(list_tests);
+
+// This flag controls whether Google Test emits a detailed XML report to a file
+// in addition to its normal textual output.
+GTEST_DECLARE_string_(output);
+
+// This flags control whether Google Test prints only test failures.
+GTEST_DECLARE_bool_(brief);
+
+// This flags control whether Google Test prints the elapsed time for each
+// test.
+GTEST_DECLARE_bool_(print_time);
+
+// This flags control whether Google Test prints UTF8 characters as text.
+GTEST_DECLARE_bool_(print_utf8);
+
+// This flag specifies the random number seed.
+GTEST_DECLARE_int32_(random_seed);
+
+// This flag sets how many times the tests are repeated. The default value
+// is 1. If the value is -1 the tests are repeating forever.
+GTEST_DECLARE_int32_(repeat);
+
+// This flag controls whether Google Test includes Google Test internal
+// stack frames in failure stack traces.
+GTEST_DECLARE_bool_(show_internal_stack_frames);
+
+// When this flag is specified, tests' order is randomized on every iteration.
+GTEST_DECLARE_bool_(shuffle);
+
+// This flag specifies the maximum number of stack frames to be
+// printed in a failure message.
+GTEST_DECLARE_int32_(stack_trace_depth);
+
+// When this flag is specified, a failed assertion will throw an
+// exception if exceptions are enabled, or exit the program with a
+// non-zero code otherwise. For use with an external test framework.
+GTEST_DECLARE_bool_(throw_on_failure);
+
+// When this flag is set with a "host:port" string, on supported
+// platforms test results are streamed to the specified port on
+// the specified host machine.
+GTEST_DECLARE_string_(stream_result_to);
+
+#if GTEST_USE_OWN_FLAGFILE_FLAG_
+GTEST_DECLARE_string_(flagfile);
+#endif // GTEST_USE_OWN_FLAGFILE_FLAG_
+
+// The upper limit for valid stack trace depths.
+const int kMaxStackTraceDepth = 100;
+
+namespace internal {
+
+class AssertHelper;
+class DefaultGlobalTestPartResultReporter;
+class ExecDeathTest;
+class NoExecDeathTest;
+class FinalSuccessChecker;
+class GTestFlagSaver;
+class StreamingListenerTest;
+class TestResultAccessor;
+class TestEventListenersAccessor;
+class TestEventRepeater;
+class UnitTestRecordPropertyTestHelper;
+class WindowsDeathTest;
+class FuchsiaDeathTest;
+class UnitTestImpl* GetUnitTestImpl();
+void ReportFailureInUnknownLocation(TestPartResult::Type result_type,
+ const std::string& message);
+std::set<std::string>* GetIgnoredParameterizedTestSuites();
+
+} // namespace internal
+
+// The friend relationship of some of these classes is cyclic.
+// If we don't forward declare them the compiler might confuse the classes
+// in friendship clauses with same named classes on the scope.
+class Test;
+class TestSuite;
+
+// Old API is still available but deprecated
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+using TestCase = TestSuite;
+#endif
+class TestInfo;
+class UnitTest;
+
+// A class for indicating whether an assertion was successful. When
+// the assertion wasn't successful, the AssertionResult object
+// remembers a non-empty message that describes how it failed.
+//
+// To create an instance of this class, use one of the factory functions
+// (AssertionSuccess() and AssertionFailure()).
+//
+// This class is useful for two purposes:
+// 1. Defining predicate functions to be used with Boolean test assertions
+// EXPECT_TRUE/EXPECT_FALSE and their ASSERT_ counterparts
+// 2. Defining predicate-format functions to be
+// used with predicate assertions (ASSERT_PRED_FORMAT*, etc).
+//
+// For example, if you define IsEven predicate:
+//
+// testing::AssertionResult IsEven(int n) {
+// if ((n % 2) == 0)
+// return testing::AssertionSuccess();
+// else
+// return testing::AssertionFailure() << n << " is odd";
+// }
+//
+// Then the failed expectation EXPECT_TRUE(IsEven(Fib(5)))
+// will print the message
+//
+// Value of: IsEven(Fib(5))
+// Actual: false (5 is odd)
+// Expected: true
+//
+// instead of a more opaque
+//
+// Value of: IsEven(Fib(5))
+// Actual: false
+// Expected: true
+//
+// in case IsEven is a simple Boolean predicate.
+//
+// If you expect your predicate to be reused and want to support informative
+// messages in EXPECT_FALSE and ASSERT_FALSE (negative assertions show up
+// about half as often as positive ones in our tests), supply messages for
+// both success and failure cases:
+//
+// testing::AssertionResult IsEven(int n) {
+// if ((n % 2) == 0)
+// return testing::AssertionSuccess() << n << " is even";
+// else
+// return testing::AssertionFailure() << n << " is odd";
+// }
+//
+// Then a statement EXPECT_FALSE(IsEven(Fib(6))) will print
+//
+// Value of: IsEven(Fib(6))
+// Actual: true (8 is even)
+// Expected: false
+//
+// NB: Predicates that support negative Boolean assertions have reduced
+// performance in positive ones so be careful not to use them in tests
+// that have lots (tens of thousands) of positive Boolean assertions.
+//
+// To use this class with EXPECT_PRED_FORMAT assertions such as:
+//
+// // Verifies that Foo() returns an even number.
+// EXPECT_PRED_FORMAT1(IsEven, Foo());
+//
+// you need to define:
+//
+// testing::AssertionResult IsEven(const char* expr, int n) {
+// if ((n % 2) == 0)
+// return testing::AssertionSuccess();
+// else
+// return testing::AssertionFailure()
+// << "Expected: " << expr << " is even\n Actual: it's " << n;
+// }
+//
+// If Foo() returns 5, you will see the following message:
+//
+// Expected: Foo() is even
+// Actual: it's 5
+//
+class GTEST_API_ AssertionResult {
+ public:
+ // Copy constructor.
+ // Used in EXPECT_TRUE/FALSE(assertion_result).
+ AssertionResult(const AssertionResult& other);
+
+// C4800 is a level 3 warning in Visual Studio 2015 and earlier.
+// This warning is not emitted in Visual Studio 2017.
+// This warning is off by default starting in Visual Studio 2019 but can be
+// enabled with command-line options.
+#if defined(_MSC_VER) && (_MSC_VER < 1910 || _MSC_VER >= 1920)
+ GTEST_DISABLE_MSC_WARNINGS_PUSH_(4800 /* forcing value to bool */)
+#endif
+
+ // Used in the EXPECT_TRUE/FALSE(bool_expression).
+ //
+ // T must be contextually convertible to bool.
+ //
+ // The second parameter prevents this overload from being considered if
+ // the argument is implicitly convertible to AssertionResult. In that case
+ // we want AssertionResult's copy constructor to be used.
+ template <typename T>
+ explicit AssertionResult(
+ const T& success,
+ typename std::enable_if<
+ !std::is_convertible<T, AssertionResult>::value>::type*
+ /*enabler*/
+ = nullptr)
+ : success_(success) {}
+
+#if defined(_MSC_VER) && (_MSC_VER < 1910 || _MSC_VER >= 1920)
+ GTEST_DISABLE_MSC_WARNINGS_POP_()
+#endif
+
+ // Assignment operator.
+ AssertionResult& operator=(AssertionResult other) {
+ swap(other);
+ return *this;
+ }
+
+ // Returns true if and only if the assertion succeeded.
+ operator bool() const { return success_; } // NOLINT
+
+ // Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE.
+ AssertionResult operator!() const;
+
+ // Returns the text streamed into this AssertionResult. Test assertions
+ // use it when they fail (i.e., the predicate's outcome doesn't match the
+ // assertion's expectation). When nothing has been streamed into the
+ // object, returns an empty string.
+ const char* message() const {
+ return message_.get() != nullptr ? message_->c_str() : "";
+ }
+ // Deprecated; please use message() instead.
+ const char* failure_message() const { return message(); }
+
+ // Streams a custom failure message into this object.
+ template <typename T> AssertionResult& operator<<(const T& value) {
+ AppendMessage(Message() << value);
+ return *this;
+ }
+
+ // Allows streaming basic output manipulators such as endl or flush into
+ // this object.
+ AssertionResult& operator<<(
+ ::std::ostream& (*basic_manipulator)(::std::ostream& stream)) {
+ AppendMessage(Message() << basic_manipulator);
+ return *this;
+ }
+
+ private:
+ // Appends the contents of message to message_.
+ void AppendMessage(const Message& a_message) {
+ if (message_.get() == nullptr) message_.reset(new ::std::string);
+ message_->append(a_message.GetString().c_str());
+ }
+
+ // Swap the contents of this AssertionResult with other.
+ void swap(AssertionResult& other);
+
+ // Stores result of the assertion predicate.
+ bool success_;
+ // Stores the message describing the condition in case the expectation
+ // construct is not satisfied with the predicate's outcome.
+ // Referenced via a pointer to avoid taking too much stack frame space
+ // with test assertions.
+ std::unique_ptr< ::std::string> message_;
+};
+
+// Makes a successful assertion result.
+GTEST_API_ AssertionResult AssertionSuccess();
+
+// Makes a failed assertion result.
+GTEST_API_ AssertionResult AssertionFailure();
+
+// Makes a failed assertion result with the given failure message.
+// Deprecated; use AssertionFailure() << msg.
+GTEST_API_ AssertionResult AssertionFailure(const Message& msg);
+
+} // namespace testing
+
+// Includes the auto-generated header that implements a family of generic
+// predicate assertion macros. This include comes late because it relies on
+// APIs declared above.
+// Copyright 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This file is AUTOMATICALLY GENERATED on 01/02/2019 by command
+// 'gen_gtest_pred_impl.py 5'. DO NOT EDIT BY HAND!
+//
+// Implements a family of generic predicate assertion macros.
+// GOOGLETEST_CM0001 DO NOT DELETE
+
+#ifndef GOOGLETEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
+#define GOOGLETEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
+
+
+namespace testing {
+
+// This header implements a family of generic predicate assertion
+// macros:
+//
+// ASSERT_PRED_FORMAT1(pred_format, v1)
+// ASSERT_PRED_FORMAT2(pred_format, v1, v2)
+// ...
+//
+// where pred_format is a function or functor that takes n (in the
+// case of ASSERT_PRED_FORMATn) values and their source expression
+// text, and returns a testing::AssertionResult. See the definition
+// of ASSERT_EQ in gtest.h for an example.
+//
+// If you don't care about formatting, you can use the more
+// restrictive version:
+//
+// ASSERT_PRED1(pred, v1)
+// ASSERT_PRED2(pred, v1, v2)
+// ...
+//
+// where pred is an n-ary function or functor that returns bool,
+// and the values v1, v2, ..., must support the << operator for
+// streaming to std::ostream.
+//
+// We also define the EXPECT_* variations.
+//
+// For now we only support predicates whose arity is at most 5.
+// Please email googletestframework@googlegroups.com if you need
+// support for higher arities.
+
+// GTEST_ASSERT_ is the basic statement to which all of the assertions
+// in this file reduce. Don't use this in your code.
+
+#define GTEST_ASSERT_(expression, on_failure) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (const ::testing::AssertionResult gtest_ar = (expression)) \
+ ; \
+ else \
+ on_failure(gtest_ar.failure_message())
+
+
+// Helper function for implementing {EXPECT|ASSERT}_PRED1. Don't use
+// this in your code.
+template <typename Pred,
+ typename T1>
+AssertionResult AssertPred1Helper(const char* pred_text,
+ const char* e1,
+ Pred pred,
+ const T1& v1) {
+ if (pred(v1)) return AssertionSuccess();
+
+ return AssertionFailure()
+ << pred_text << "(" << e1 << ") evaluates to false, where"
+ << "\n"
+ << e1 << " evaluates to " << ::testing::PrintToString(v1);
+}
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT1.
+// Don't use this in your code.
+#define GTEST_PRED_FORMAT1_(pred_format, v1, on_failure)\
+ GTEST_ASSERT_(pred_format(#v1, v1), \
+ on_failure)
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED1. Don't use
+// this in your code.
+#define GTEST_PRED1_(pred, v1, on_failure)\
+ GTEST_ASSERT_(::testing::AssertPred1Helper(#pred, \
+ #v1, \
+ pred, \
+ v1), on_failure)
+
+// Unary predicate assertion macros.
+#define EXPECT_PRED_FORMAT1(pred_format, v1) \
+ GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_PRED1(pred, v1) \
+ GTEST_PRED1_(pred, v1, GTEST_NONFATAL_FAILURE_)
+#define ASSERT_PRED_FORMAT1(pred_format, v1) \
+ GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_FATAL_FAILURE_)
+#define ASSERT_PRED1(pred, v1) \
+ GTEST_PRED1_(pred, v1, GTEST_FATAL_FAILURE_)
+
+
+
+// Helper function for implementing {EXPECT|ASSERT}_PRED2. Don't use
+// this in your code.
+template <typename Pred,
+ typename T1,
+ typename T2>
+AssertionResult AssertPred2Helper(const char* pred_text,
+ const char* e1,
+ const char* e2,
+ Pred pred,
+ const T1& v1,
+ const T2& v2) {
+ if (pred(v1, v2)) return AssertionSuccess();
+
+ return AssertionFailure()
+ << pred_text << "(" << e1 << ", " << e2
+ << ") evaluates to false, where"
+ << "\n"
+ << e1 << " evaluates to " << ::testing::PrintToString(v1) << "\n"
+ << e2 << " evaluates to " << ::testing::PrintToString(v2);
+}
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT2.
+// Don't use this in your code.
+#define GTEST_PRED_FORMAT2_(pred_format, v1, v2, on_failure)\
+ GTEST_ASSERT_(pred_format(#v1, #v2, v1, v2), \
+ on_failure)
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED2. Don't use
+// this in your code.
+#define GTEST_PRED2_(pred, v1, v2, on_failure)\
+ GTEST_ASSERT_(::testing::AssertPred2Helper(#pred, \
+ #v1, \
+ #v2, \
+ pred, \
+ v1, \
+ v2), on_failure)
+
+// Binary predicate assertion macros.
+#define EXPECT_PRED_FORMAT2(pred_format, v1, v2) \
+ GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_PRED2(pred, v1, v2) \
+ GTEST_PRED2_(pred, v1, v2, GTEST_NONFATAL_FAILURE_)
+#define ASSERT_PRED_FORMAT2(pred_format, v1, v2) \
+ GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_FATAL_FAILURE_)
+#define ASSERT_PRED2(pred, v1, v2) \
+ GTEST_PRED2_(pred, v1, v2, GTEST_FATAL_FAILURE_)
+
+
+
+// Helper function for implementing {EXPECT|ASSERT}_PRED3. Don't use
+// this in your code.
+template <typename Pred,
+ typename T1,
+ typename T2,
+ typename T3>
+AssertionResult AssertPred3Helper(const char* pred_text,
+ const char* e1,
+ const char* e2,
+ const char* e3,
+ Pred pred,
+ const T1& v1,
+ const T2& v2,
+ const T3& v3) {
+ if (pred(v1, v2, v3)) return AssertionSuccess();
+
+ return AssertionFailure()
+ << pred_text << "(" << e1 << ", " << e2 << ", " << e3
+ << ") evaluates to false, where"
+ << "\n"
+ << e1 << " evaluates to " << ::testing::PrintToString(v1) << "\n"
+ << e2 << " evaluates to " << ::testing::PrintToString(v2) << "\n"
+ << e3 << " evaluates to " << ::testing::PrintToString(v3);
+}
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT3.
+// Don't use this in your code.
+#define GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, on_failure)\
+ GTEST_ASSERT_(pred_format(#v1, #v2, #v3, v1, v2, v3), \
+ on_failure)
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED3. Don't use
+// this in your code.
+#define GTEST_PRED3_(pred, v1, v2, v3, on_failure)\
+ GTEST_ASSERT_(::testing::AssertPred3Helper(#pred, \
+ #v1, \
+ #v2, \
+ #v3, \
+ pred, \
+ v1, \
+ v2, \
+ v3), on_failure)
+
+// Ternary predicate assertion macros.
+#define EXPECT_PRED_FORMAT3(pred_format, v1, v2, v3) \
+ GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_PRED3(pred, v1, v2, v3) \
+ GTEST_PRED3_(pred, v1, v2, v3, GTEST_NONFATAL_FAILURE_)
+#define ASSERT_PRED_FORMAT3(pred_format, v1, v2, v3) \
+ GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_FATAL_FAILURE_)
+#define ASSERT_PRED3(pred, v1, v2, v3) \
+ GTEST_PRED3_(pred, v1, v2, v3, GTEST_FATAL_FAILURE_)
+
+
+
+// Helper function for implementing {EXPECT|ASSERT}_PRED4. Don't use
+// this in your code.
+template <typename Pred,
+ typename T1,
+ typename T2,
+ typename T3,
+ typename T4>
+AssertionResult AssertPred4Helper(const char* pred_text,
+ const char* e1,
+ const char* e2,
+ const char* e3,
+ const char* e4,
+ Pred pred,
+ const T1& v1,
+ const T2& v2,
+ const T3& v3,
+ const T4& v4) {
+ if (pred(v1, v2, v3, v4)) return AssertionSuccess();
+
+ return AssertionFailure()
+ << pred_text << "(" << e1 << ", " << e2 << ", " << e3 << ", " << e4
+ << ") evaluates to false, where"
+ << "\n"
+ << e1 << " evaluates to " << ::testing::PrintToString(v1) << "\n"
+ << e2 << " evaluates to " << ::testing::PrintToString(v2) << "\n"
+ << e3 << " evaluates to " << ::testing::PrintToString(v3) << "\n"
+ << e4 << " evaluates to " << ::testing::PrintToString(v4);
+}
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT4.
+// Don't use this in your code.
+#define GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, on_failure)\
+ GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, v1, v2, v3, v4), \
+ on_failure)
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED4. Don't use
+// this in your code.
+#define GTEST_PRED4_(pred, v1, v2, v3, v4, on_failure)\
+ GTEST_ASSERT_(::testing::AssertPred4Helper(#pred, \
+ #v1, \
+ #v2, \
+ #v3, \
+ #v4, \
+ pred, \
+ v1, \
+ v2, \
+ v3, \
+ v4), on_failure)
+
+// 4-ary predicate assertion macros.
+#define EXPECT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \
+ GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_PRED4(pred, v1, v2, v3, v4) \
+ GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_)
+#define ASSERT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \
+ GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_FATAL_FAILURE_)
+#define ASSERT_PRED4(pred, v1, v2, v3, v4) \
+ GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_FATAL_FAILURE_)
+
+
+
+// Helper function for implementing {EXPECT|ASSERT}_PRED5. Don't use
+// this in your code.
+template <typename Pred,
+ typename T1,
+ typename T2,
+ typename T3,
+ typename T4,
+ typename T5>
+AssertionResult AssertPred5Helper(const char* pred_text,
+ const char* e1,
+ const char* e2,
+ const char* e3,
+ const char* e4,
+ const char* e5,
+ Pred pred,
+ const T1& v1,
+ const T2& v2,
+ const T3& v3,
+ const T4& v4,
+ const T5& v5) {
+ if (pred(v1, v2, v3, v4, v5)) return AssertionSuccess();
+
+ return AssertionFailure()
+ << pred_text << "(" << e1 << ", " << e2 << ", " << e3 << ", " << e4
+ << ", " << e5 << ") evaluates to false, where"
+ << "\n"
+ << e1 << " evaluates to " << ::testing::PrintToString(v1) << "\n"
+ << e2 << " evaluates to " << ::testing::PrintToString(v2) << "\n"
+ << e3 << " evaluates to " << ::testing::PrintToString(v3) << "\n"
+ << e4 << " evaluates to " << ::testing::PrintToString(v4) << "\n"
+ << e5 << " evaluates to " << ::testing::PrintToString(v5);
+}
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT5.
+// Don't use this in your code.
+#define GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, on_failure)\
+ GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, #v5, v1, v2, v3, v4, v5), \
+ on_failure)
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED5. Don't use
+// this in your code.
+#define GTEST_PRED5_(pred, v1, v2, v3, v4, v5, on_failure)\
+ GTEST_ASSERT_(::testing::AssertPred5Helper(#pred, \
+ #v1, \
+ #v2, \
+ #v3, \
+ #v4, \
+ #v5, \
+ pred, \
+ v1, \
+ v2, \
+ v3, \
+ v4, \
+ v5), on_failure)
+
+// 5-ary predicate assertion macros.
+#define EXPECT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \
+ GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_PRED5(pred, v1, v2, v3, v4, v5) \
+ GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_)
+#define ASSERT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \
+ GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_)
+#define ASSERT_PRED5(pred, v1, v2, v3, v4, v5) \
+ GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_)
+
+
+
+} // namespace testing
+
+#endif // GOOGLETEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
+
+namespace testing {
+
+// The abstract class that all tests inherit from.
+//
+// In Google Test, a unit test program contains one or many TestSuites, and
+// each TestSuite contains one or many Tests.
+//
+// When you define a test using the TEST macro, you don't need to
+// explicitly derive from Test - the TEST macro automatically does
+// this for you.
+//
+// The only time you derive from Test is when defining a test fixture
+// to be used in a TEST_F. For example:
+//
+// class FooTest : public testing::Test {
+// protected:
+// void SetUp() override { ... }
+// void TearDown() override { ... }
+// ...
+// };
+//
+// TEST_F(FooTest, Bar) { ... }
+// TEST_F(FooTest, Baz) { ... }
+//
+// Test is not copyable.
+class GTEST_API_ Test {
+ public:
+ friend class TestInfo;
+
+ // The d'tor is virtual as we intend to inherit from Test.
+ virtual ~Test();
+
+ // Sets up the stuff shared by all tests in this test suite.
+ //
+ // Google Test will call Foo::SetUpTestSuite() before running the first
+ // test in test suite Foo. Hence a sub-class can define its own
+ // SetUpTestSuite() method to shadow the one defined in the super
+ // class.
+ static void SetUpTestSuite() {}
+
+ // Tears down the stuff shared by all tests in this test suite.
+ //
+ // Google Test will call Foo::TearDownTestSuite() after running the last
+ // test in test suite Foo. Hence a sub-class can define its own
+ // TearDownTestSuite() method to shadow the one defined in the super
+ // class.
+ static void TearDownTestSuite() {}
+
+ // Legacy API is deprecated but still available. Use SetUpTestSuite and
+ // TearDownTestSuite instead.
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ static void TearDownTestCase() {}
+ static void SetUpTestCase() {}
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+ // Returns true if and only if the current test has a fatal failure.
+ static bool HasFatalFailure();
+
+ // Returns true if and only if the current test has a non-fatal failure.
+ static bool HasNonfatalFailure();
+
+ // Returns true if and only if the current test was skipped.
+ static bool IsSkipped();
+
+ // Returns true if and only if the current test has a (either fatal or
+ // non-fatal) failure.
+ static bool HasFailure() { return HasFatalFailure() || HasNonfatalFailure(); }
+
+ // Logs a property for the current test, test suite, or for the entire
+ // invocation of the test program when used outside of the context of a
+ // test suite. Only the last value for a given key is remembered. These
+ // are public static so they can be called from utility functions that are
+ // not members of the test fixture. Calls to RecordProperty made during
+ // lifespan of the test (from the moment its constructor starts to the
+ // moment its destructor finishes) will be output in XML as attributes of
+ // the <testcase> element. Properties recorded from fixture's
+ // SetUpTestSuite or TearDownTestSuite are logged as attributes of the
+ // corresponding <testsuite> element. Calls to RecordProperty made in the
+ // global context (before or after invocation of RUN_ALL_TESTS and from
+ // SetUp/TearDown method of Environment objects registered with Google
+ // Test) will be output as attributes of the <testsuites> element.
+ static void RecordProperty(const std::string& key, const std::string& value);
+ static void RecordProperty(const std::string& key, int value);
+
+ protected:
+ // Creates a Test object.
+ Test();
+
+ // Sets up the test fixture.
+ virtual void SetUp();
+
+ // Tears down the test fixture.
+ virtual void TearDown();
+
+ private:
+ // Returns true if and only if the current test has the same fixture class
+ // as the first test in the current test suite.
+ static bool HasSameFixtureClass();
+
+ // Runs the test after the test fixture has been set up.
+ //
+ // A sub-class must implement this to define the test logic.
+ //
+ // DO NOT OVERRIDE THIS FUNCTION DIRECTLY IN A USER PROGRAM.
+ // Instead, use the TEST or TEST_F macro.
+ virtual void TestBody() = 0;
+
+ // Sets up, executes, and tears down the test.
+ void Run();
+
+ // Deletes self. We deliberately pick an unusual name for this
+ // internal method to avoid clashing with names used in user TESTs.
+ void DeleteSelf_() { delete this; }
+
+ const std::unique_ptr<GTEST_FLAG_SAVER_> gtest_flag_saver_;
+
+ // Often a user misspells SetUp() as Setup() and spends a long time
+ // wondering why it is never called by Google Test. The declaration of
+ // the following method is solely for catching such an error at
+ // compile time:
+ //
+ // - The return type is deliberately chosen to be not void, so it
+ // will be a conflict if void Setup() is declared in the user's
+ // test fixture.
+ //
+ // - This method is private, so it will be another compiler error
+ // if the method is called from the user's test fixture.
+ //
+ // DO NOT OVERRIDE THIS FUNCTION.
+ //
+ // If you see an error about overriding the following function or
+ // about it being private, you have mis-spelled SetUp() as Setup().
+ struct Setup_should_be_spelled_SetUp {};
+ virtual Setup_should_be_spelled_SetUp* Setup() { return nullptr; }
+
+ // We disallow copying Tests.
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(Test);
+};
+
+typedef internal::TimeInMillis TimeInMillis;
+
+// A copyable object representing a user specified test property which can be
+// output as a key/value string pair.
+//
+// Don't inherit from TestProperty as its destructor is not virtual.
+class TestProperty {
+ public:
+ // C'tor. TestProperty does NOT have a default constructor.
+ // Always use this constructor (with parameters) to create a
+ // TestProperty object.
+ TestProperty(const std::string& a_key, const std::string& a_value) :
+ key_(a_key), value_(a_value) {
+ }
+
+ // Gets the user supplied key.
+ const char* key() const {
+ return key_.c_str();
+ }
+
+ // Gets the user supplied value.
+ const char* value() const {
+ return value_.c_str();
+ }
+
+ // Sets a new value, overriding the one supplied in the constructor.
+ void SetValue(const std::string& new_value) {
+ value_ = new_value;
+ }
+
+ private:
+ // The key supplied by the user.
+ std::string key_;
+ // The value supplied by the user.
+ std::string value_;
+};
+
+// The result of a single Test. This includes a list of
+// TestPartResults, a list of TestProperties, a count of how many
+// death tests there are in the Test, and how much time it took to run
+// the Test.
+//
+// TestResult is not copyable.
+class GTEST_API_ TestResult {
+ public:
+ // Creates an empty TestResult.
+ TestResult();
+
+ // D'tor. Do not inherit from TestResult.
+ ~TestResult();
+
+ // Gets the number of all test parts. This is the sum of the number
+ // of successful test parts and the number of failed test parts.
+ int total_part_count() const;
+
+ // Returns the number of the test properties.
+ int test_property_count() const;
+
+ // Returns true if and only if the test passed (i.e. no test part failed).
+ bool Passed() const { return !Skipped() && !Failed(); }
+
+ // Returns true if and only if the test was skipped.
+ bool Skipped() const;
+
+ // Returns true if and only if the test failed.
+ bool Failed() const;
+
+ // Returns true if and only if the test fatally failed.
+ bool HasFatalFailure() const;
+
+ // Returns true if and only if the test has a non-fatal failure.
+ bool HasNonfatalFailure() const;
+
+ // Returns the elapsed time, in milliseconds.
+ TimeInMillis elapsed_time() const { return elapsed_time_; }
+
+ // Gets the time of the test case start, in ms from the start of the
+ // UNIX epoch.
+ TimeInMillis start_timestamp() const { return start_timestamp_; }
+
+ // Returns the i-th test part result among all the results. i can range from 0
+ // to total_part_count() - 1. If i is not in that range, aborts the program.
+ const TestPartResult& GetTestPartResult(int i) const;
+
+ // Returns the i-th test property. i can range from 0 to
+ // test_property_count() - 1. If i is not in that range, aborts the
+ // program.
+ const TestProperty& GetTestProperty(int i) const;
+
+ private:
+ friend class TestInfo;
+ friend class TestSuite;
+ friend class UnitTest;
+ friend class internal::DefaultGlobalTestPartResultReporter;
+ friend class internal::ExecDeathTest;
+ friend class internal::TestResultAccessor;
+ friend class internal::UnitTestImpl;
+ friend class internal::WindowsDeathTest;
+ friend class internal::FuchsiaDeathTest;
+
+ // Gets the vector of TestPartResults.
+ const std::vector<TestPartResult>& test_part_results() const {
+ return test_part_results_;
+ }
+
+ // Gets the vector of TestProperties.
+ const std::vector<TestProperty>& test_properties() const {
+ return test_properties_;
+ }
+
+ // Sets the start time.
+ void set_start_timestamp(TimeInMillis start) { start_timestamp_ = start; }
+
+ // Sets the elapsed time.
+ void set_elapsed_time(TimeInMillis elapsed) { elapsed_time_ = elapsed; }
+
+ // Adds a test property to the list. The property is validated and may add
+ // a non-fatal failure if invalid (e.g., if it conflicts with reserved
+ // key names). If a property is already recorded for the same key, the
+ // value will be updated, rather than storing multiple values for the same
+ // key. xml_element specifies the element for which the property is being
+ // recorded and is used for validation.
+ void RecordProperty(const std::string& xml_element,
+ const TestProperty& test_property);
+
+ // Adds a failure if the key is a reserved attribute of Google Test
+ // testsuite tags. Returns true if the property is valid.
+ // FIXME: Validate attribute names are legal and human readable.
+ static bool ValidateTestProperty(const std::string& xml_element,
+ const TestProperty& test_property);
+
+ // Adds a test part result to the list.
+ void AddTestPartResult(const TestPartResult& test_part_result);
+
+ // Returns the death test count.
+ int death_test_count() const { return death_test_count_; }
+
+ // Increments the death test count, returning the new count.
+ int increment_death_test_count() { return ++death_test_count_; }
+
+ // Clears the test part results.
+ void ClearTestPartResults();
+
+ // Clears the object.
+ void Clear();
+
+ // Protects mutable state of the property vector and of owned
+ // properties, whose values may be updated.
+ internal::Mutex test_properties_mutex_;
+
+ // The vector of TestPartResults
+ std::vector<TestPartResult> test_part_results_;
+ // The vector of TestProperties
+ std::vector<TestProperty> test_properties_;
+ // Running count of death tests.
+ int death_test_count_;
+ // The start time, in milliseconds since UNIX Epoch.
+ TimeInMillis start_timestamp_;
+ // The elapsed time, in milliseconds.
+ TimeInMillis elapsed_time_;
+
+ // We disallow copying TestResult.
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(TestResult);
+}; // class TestResult
+
+// A TestInfo object stores the following information about a test:
+//
+// Test suite name
+// Test name
+// Whether the test should be run
+// A function pointer that creates the test object when invoked
+// Test result
+//
+// The constructor of TestInfo registers itself with the UnitTest
+// singleton such that the RUN_ALL_TESTS() macro knows which tests to
+// run.
+class GTEST_API_ TestInfo {
+ public:
+ // Destructs a TestInfo object. This function is not virtual, so
+ // don't inherit from TestInfo.
+ ~TestInfo();
+
+ // Returns the test suite name.
+ const char* test_suite_name() const { return test_suite_name_.c_str(); }
+
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ const char* test_case_name() const { return test_suite_name(); }
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+ // Returns the test name.
+ const char* name() const { return name_.c_str(); }
+
+ // Returns the name of the parameter type, or NULL if this is not a typed
+ // or a type-parameterized test.
+ const char* type_param() const {
+ if (type_param_.get() != nullptr) return type_param_->c_str();
+ return nullptr;
+ }
+
+ // Returns the text representation of the value parameter, or NULL if this
+ // is not a value-parameterized test.
+ const char* value_param() const {
+ if (value_param_.get() != nullptr) return value_param_->c_str();
+ return nullptr;
+ }
+
+ // Returns the file name where this test is defined.
+ const char* file() const { return location_.file.c_str(); }
+
+ // Returns the line where this test is defined.
+ int line() const { return location_.line; }
+
+ // Return true if this test should not be run because it's in another shard.
+ bool is_in_another_shard() const { return is_in_another_shard_; }
+
+ // Returns true if this test should run, that is if the test is not
+ // disabled (or it is disabled but the also_run_disabled_tests flag has
+ // been specified) and its full name matches the user-specified filter.
+ //
+ // Google Test allows the user to filter the tests by their full names.
+ // The full name of a test Bar in test suite Foo is defined as
+ // "Foo.Bar". Only the tests that match the filter will run.
+ //
+ // A filter is a colon-separated list of glob (not regex) patterns,
+ // optionally followed by a '-' and a colon-separated list of
+ // negative patterns (tests to exclude). A test is run if it
+ // matches one of the positive patterns and does not match any of
+ // the negative patterns.
+ //
+ // For example, *A*:Foo.* is a filter that matches any string that
+ // contains the character 'A' or starts with "Foo.".
+ bool should_run() const { return should_run_; }
+
+ // Returns true if and only if this test will appear in the XML report.
+ bool is_reportable() const {
+ // The XML report includes tests matching the filter, excluding those
+ // run in other shards.
+ return matches_filter_ && !is_in_another_shard_;
+ }
+
+ // Returns the result of the test.
+ const TestResult* result() const { return &result_; }
+
+ private:
+#if GTEST_HAS_DEATH_TEST
+ friend class internal::DefaultDeathTestFactory;
+#endif // GTEST_HAS_DEATH_TEST
+ friend class Test;
+ friend class TestSuite;
+ friend class internal::UnitTestImpl;
+ friend class internal::StreamingListenerTest;
+ friend TestInfo* internal::MakeAndRegisterTestInfo(
+ const char* test_suite_name, const char* name, const char* type_param,
+ const char* value_param, internal::CodeLocation code_location,
+ internal::TypeId fixture_class_id, internal::SetUpTestSuiteFunc set_up_tc,
+ internal::TearDownTestSuiteFunc tear_down_tc,
+ internal::TestFactoryBase* factory);
+
+ // Constructs a TestInfo object. The newly constructed instance assumes
+ // ownership of the factory object.
+ TestInfo(const std::string& test_suite_name, const std::string& name,
+ const char* a_type_param, // NULL if not a type-parameterized test
+ const char* a_value_param, // NULL if not a value-parameterized test
+ internal::CodeLocation a_code_location,
+ internal::TypeId fixture_class_id,
+ internal::TestFactoryBase* factory);
+
+ // Increments the number of death tests encountered in this test so
+ // far.
+ int increment_death_test_count() {
+ return result_.increment_death_test_count();
+ }
+
+ // Creates the test object, runs it, records its result, and then
+ // deletes it.
+ void Run();
+
+ // Skip and records the test result for this object.
+ void Skip();
+
+ static void ClearTestResult(TestInfo* test_info) {
+ test_info->result_.Clear();
+ }
+
+ // These fields are immutable properties of the test.
+ const std::string test_suite_name_; // test suite name
+ const std::string name_; // Test name
+ // Name of the parameter type, or NULL if this is not a typed or a
+ // type-parameterized test.
+ const std::unique_ptr<const ::std::string> type_param_;
+ // Text representation of the value parameter, or NULL if this is not a
+ // value-parameterized test.
+ const std::unique_ptr<const ::std::string> value_param_;
+ internal::CodeLocation location_;
+ const internal::TypeId fixture_class_id_; // ID of the test fixture class
+ bool should_run_; // True if and only if this test should run
+ bool is_disabled_; // True if and only if this test is disabled
+ bool matches_filter_; // True if this test matches the
+ // user-specified filter.
+ bool is_in_another_shard_; // Will be run in another shard.
+ internal::TestFactoryBase* const factory_; // The factory that creates
+ // the test object
+
+ // This field is mutable and needs to be reset before running the
+ // test for the second time.
+ TestResult result_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(TestInfo);
+};
+
+// A test suite, which consists of a vector of TestInfos.
+//
+// TestSuite is not copyable.
+class GTEST_API_ TestSuite {
+ public:
+ // Creates a TestSuite with the given name.
+ //
+ // TestSuite does NOT have a default constructor. Always use this
+ // constructor to create a TestSuite object.
+ //
+ // Arguments:
+ //
+ // name: name of the test suite
+ // a_type_param: the name of the test's type parameter, or NULL if
+ // this is not a type-parameterized test.
+ // set_up_tc: pointer to the function that sets up the test suite
+ // tear_down_tc: pointer to the function that tears down the test suite
+ TestSuite(const char* name, const char* a_type_param,
+ internal::SetUpTestSuiteFunc set_up_tc,
+ internal::TearDownTestSuiteFunc tear_down_tc);
+
+ // Destructor of TestSuite.
+ virtual ~TestSuite();
+
+ // Gets the name of the TestSuite.
+ const char* name() const { return name_.c_str(); }
+
+ // Returns the name of the parameter type, or NULL if this is not a
+ // type-parameterized test suite.
+ const char* type_param() const {
+ if (type_param_.get() != nullptr) return type_param_->c_str();
+ return nullptr;
+ }
+
+ // Returns true if any test in this test suite should run.
+ bool should_run() const { return should_run_; }
+
+ // Gets the number of successful tests in this test suite.
+ int successful_test_count() const;
+
+ // Gets the number of skipped tests in this test suite.
+ int skipped_test_count() const;
+
+ // Gets the number of failed tests in this test suite.
+ int failed_test_count() const;
+
+ // Gets the number of disabled tests that will be reported in the XML report.
+ int reportable_disabled_test_count() const;
+
+ // Gets the number of disabled tests in this test suite.
+ int disabled_test_count() const;
+
+ // Gets the number of tests to be printed in the XML report.
+ int reportable_test_count() const;
+
+ // Get the number of tests in this test suite that should run.
+ int test_to_run_count() const;
+
+ // Gets the number of all tests in this test suite.
+ int total_test_count() const;
+
+ // Returns true if and only if the test suite passed.
+ bool Passed() const { return !Failed(); }
+
+ // Returns true if and only if the test suite failed.
+ bool Failed() const {
+ return failed_test_count() > 0 || ad_hoc_test_result().Failed();
+ }
+
+ // Returns the elapsed time, in milliseconds.
+ TimeInMillis elapsed_time() const { return elapsed_time_; }
+
+ // Gets the time of the test suite start, in ms from the start of the
+ // UNIX epoch.
+ TimeInMillis start_timestamp() const { return start_timestamp_; }
+
+ // Returns the i-th test among all the tests. i can range from 0 to
+ // total_test_count() - 1. If i is not in that range, returns NULL.
+ const TestInfo* GetTestInfo(int i) const;
+
+ // Returns the TestResult that holds test properties recorded during
+ // execution of SetUpTestSuite and TearDownTestSuite.
+ const TestResult& ad_hoc_test_result() const { return ad_hoc_test_result_; }
+
+ private:
+ friend class Test;
+ friend class internal::UnitTestImpl;
+
+ // Gets the (mutable) vector of TestInfos in this TestSuite.
+ std::vector<TestInfo*>& test_info_list() { return test_info_list_; }
+
+ // Gets the (immutable) vector of TestInfos in this TestSuite.
+ const std::vector<TestInfo*>& test_info_list() const {
+ return test_info_list_;
+ }
+
+ // Returns the i-th test among all the tests. i can range from 0 to
+ // total_test_count() - 1. If i is not in that range, returns NULL.
+ TestInfo* GetMutableTestInfo(int i);
+
+ // Sets the should_run member.
+ void set_should_run(bool should) { should_run_ = should; }
+
+ // Adds a TestInfo to this test suite. Will delete the TestInfo upon
+ // destruction of the TestSuite object.
+ void AddTestInfo(TestInfo * test_info);
+
+ // Clears the results of all tests in this test suite.
+ void ClearResult();
+
+ // Clears the results of all tests in the given test suite.
+ static void ClearTestSuiteResult(TestSuite* test_suite) {
+ test_suite->ClearResult();
+ }
+
+ // Runs every test in this TestSuite.
+ void Run();
+
+ // Skips the execution of tests under this TestSuite
+ void Skip();
+
+ // Runs SetUpTestSuite() for this TestSuite. This wrapper is needed
+ // for catching exceptions thrown from SetUpTestSuite().
+ void RunSetUpTestSuite() {
+ if (set_up_tc_ != nullptr) {
+ (*set_up_tc_)();
+ }
+ }
+
+ // Runs TearDownTestSuite() for this TestSuite. This wrapper is
+ // needed for catching exceptions thrown from TearDownTestSuite().
+ void RunTearDownTestSuite() {
+ if (tear_down_tc_ != nullptr) {
+ (*tear_down_tc_)();
+ }
+ }
+
+ // Returns true if and only if test passed.
+ static bool TestPassed(const TestInfo* test_info) {
+ return test_info->should_run() && test_info->result()->Passed();
+ }
+
+ // Returns true if and only if test skipped.
+ static bool TestSkipped(const TestInfo* test_info) {
+ return test_info->should_run() && test_info->result()->Skipped();
+ }
+
+ // Returns true if and only if test failed.
+ static bool TestFailed(const TestInfo* test_info) {
+ return test_info->should_run() && test_info->result()->Failed();
+ }
+
+ // Returns true if and only if the test is disabled and will be reported in
+ // the XML report.
+ static bool TestReportableDisabled(const TestInfo* test_info) {
+ return test_info->is_reportable() && test_info->is_disabled_;
+ }
+
+ // Returns true if and only if test is disabled.
+ static bool TestDisabled(const TestInfo* test_info) {
+ return test_info->is_disabled_;
+ }
+
+ // Returns true if and only if this test will appear in the XML report.
+ static bool TestReportable(const TestInfo* test_info) {
+ return test_info->is_reportable();
+ }
+
+ // Returns true if the given test should run.
+ static bool ShouldRunTest(const TestInfo* test_info) {
+ return test_info->should_run();
+ }
+
+ // Shuffles the tests in this test suite.
+ void ShuffleTests(internal::Random* random);
+
+ // Restores the test order to before the first shuffle.
+ void UnshuffleTests();
+
+ // Name of the test suite.
+ std::string name_;
+ // Name of the parameter type, or NULL if this is not a typed or a
+ // type-parameterized test.
+ const std::unique_ptr<const ::std::string> type_param_;
+ // The vector of TestInfos in their original order. It owns the
+ // elements in the vector.
+ std::vector<TestInfo*> test_info_list_;
+ // Provides a level of indirection for the test list to allow easy
+ // shuffling and restoring the test order. The i-th element in this
+ // vector is the index of the i-th test in the shuffled test list.
+ std::vector<int> test_indices_;
+ // Pointer to the function that sets up the test suite.
+ internal::SetUpTestSuiteFunc set_up_tc_;
+ // Pointer to the function that tears down the test suite.
+ internal::TearDownTestSuiteFunc tear_down_tc_;
+ // True if and only if any test in this test suite should run.
+ bool should_run_;
+ // The start time, in milliseconds since UNIX Epoch.
+ TimeInMillis start_timestamp_;
+ // Elapsed time, in milliseconds.
+ TimeInMillis elapsed_time_;
+ // Holds test properties recorded during execution of SetUpTestSuite and
+ // TearDownTestSuite.
+ TestResult ad_hoc_test_result_;
+
+ // We disallow copying TestSuites.
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(TestSuite);
+};
+
+// An Environment object is capable of setting up and tearing down an
+// environment. You should subclass this to define your own
+// environment(s).
+//
+// An Environment object does the set-up and tear-down in virtual
+// methods SetUp() and TearDown() instead of the constructor and the
+// destructor, as:
+//
+// 1. You cannot safely throw from a destructor. This is a problem
+// as in some cases Google Test is used where exceptions are enabled, and
+// we may want to implement ASSERT_* using exceptions where they are
+// available.
+// 2. You cannot use ASSERT_* directly in a constructor or
+// destructor.
+class Environment {
+ public:
+ // The d'tor is virtual as we need to subclass Environment.
+ virtual ~Environment() {}
+
+ // Override this to define how to set up the environment.
+ virtual void SetUp() {}
+
+ // Override this to define how to tear down the environment.
+ virtual void TearDown() {}
+ private:
+ // If you see an error about overriding the following function or
+ // about it being private, you have mis-spelled SetUp() as Setup().
+ struct Setup_should_be_spelled_SetUp {};
+ virtual Setup_should_be_spelled_SetUp* Setup() { return nullptr; }
+};
+
+#if GTEST_HAS_EXCEPTIONS
+
+// Exception which can be thrown from TestEventListener::OnTestPartResult.
+class GTEST_API_ AssertionException
+ : public internal::GoogleTestFailureException {
+ public:
+ explicit AssertionException(const TestPartResult& result)
+ : GoogleTestFailureException(result) {}
+};
+
+#endif // GTEST_HAS_EXCEPTIONS
+
+// The interface for tracing execution of tests. The methods are organized in
+// the order the corresponding events are fired.
+class TestEventListener {
+ public:
+ virtual ~TestEventListener() {}
+
+ // Fired before any test activity starts.
+ virtual void OnTestProgramStart(const UnitTest& unit_test) = 0;
+
+ // Fired before each iteration of tests starts. There may be more than
+ // one iteration if GTEST_FLAG(repeat) is set. iteration is the iteration
+ // index, starting from 0.
+ virtual void OnTestIterationStart(const UnitTest& unit_test,
+ int iteration) = 0;
+
+ // Fired before environment set-up for each iteration of tests starts.
+ virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test) = 0;
+
+ // Fired after environment set-up for each iteration of tests ends.
+ virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test) = 0;
+
+ // Fired before the test suite starts.
+ virtual void OnTestSuiteStart(const TestSuite& /*test_suite*/) {}
+
+ // Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ virtual void OnTestCaseStart(const TestCase& /*test_case*/) {}
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+ // Fired before the test starts.
+ virtual void OnTestStart(const TestInfo& test_info) = 0;
+
+ // Fired after a failed assertion or a SUCCEED() invocation.
+ // If you want to throw an exception from this function to skip to the next
+ // TEST, it must be AssertionException defined above, or inherited from it.
+ virtual void OnTestPartResult(const TestPartResult& test_part_result) = 0;
+
+ // Fired after the test ends.
+ virtual void OnTestEnd(const TestInfo& test_info) = 0;
+
+ // Fired after the test suite ends.
+ virtual void OnTestSuiteEnd(const TestSuite& /*test_suite*/) {}
+
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ virtual void OnTestCaseEnd(const TestCase& /*test_case*/) {}
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+ // Fired before environment tear-down for each iteration of tests starts.
+ virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test) = 0;
+
+ // Fired after environment tear-down for each iteration of tests ends.
+ virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test) = 0;
+
+ // Fired after each iteration of tests finishes.
+ virtual void OnTestIterationEnd(const UnitTest& unit_test,
+ int iteration) = 0;
+
+ // Fired after all test activities have ended.
+ virtual void OnTestProgramEnd(const UnitTest& unit_test) = 0;
+};
+
+// The convenience class for users who need to override just one or two
+// methods and are not concerned that a possible change to a signature of
+// the methods they override will not be caught during the build. For
+// comments about each method please see the definition of TestEventListener
+// above.
+class EmptyTestEventListener : public TestEventListener {
+ public:
+ void OnTestProgramStart(const UnitTest& /*unit_test*/) override {}
+ void OnTestIterationStart(const UnitTest& /*unit_test*/,
+ int /*iteration*/) override {}
+ void OnEnvironmentsSetUpStart(const UnitTest& /*unit_test*/) override {}
+ void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) override {}
+ void OnTestSuiteStart(const TestSuite& /*test_suite*/) override {}
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ void OnTestCaseStart(const TestCase& /*test_case*/) override {}
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+ void OnTestStart(const TestInfo& /*test_info*/) override {}
+ void OnTestPartResult(const TestPartResult& /*test_part_result*/) override {}
+ void OnTestEnd(const TestInfo& /*test_info*/) override {}
+ void OnTestSuiteEnd(const TestSuite& /*test_suite*/) override {}
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ void OnTestCaseEnd(const TestCase& /*test_case*/) override {}
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+ void OnEnvironmentsTearDownStart(const UnitTest& /*unit_test*/) override {}
+ void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) override {}
+ void OnTestIterationEnd(const UnitTest& /*unit_test*/,
+ int /*iteration*/) override {}
+ void OnTestProgramEnd(const UnitTest& /*unit_test*/) override {}
+};
+
+// TestEventListeners lets users add listeners to track events in Google Test.
+class GTEST_API_ TestEventListeners {
+ public:
+ TestEventListeners();
+ ~TestEventListeners();
+
+ // Appends an event listener to the end of the list. Google Test assumes
+ // the ownership of the listener (i.e. it will delete the listener when
+ // the test program finishes).
+ void Append(TestEventListener* listener);
+
+ // Removes the given event listener from the list and returns it. It then
+ // becomes the caller's responsibility to delete the listener. Returns
+ // NULL if the listener is not found in the list.
+ TestEventListener* Release(TestEventListener* listener);
+
+ // Returns the standard listener responsible for the default console
+ // output. Can be removed from the listeners list to shut down default
+ // console output. Note that removing this object from the listener list
+ // with Release transfers its ownership to the caller and makes this
+ // function return NULL the next time.
+ TestEventListener* default_result_printer() const {
+ return default_result_printer_;
+ }
+
+ // Returns the standard listener responsible for the default XML output
+ // controlled by the --gtest_output=xml flag. Can be removed from the
+ // listeners list by users who want to shut down the default XML output
+ // controlled by this flag and substitute it with custom one. Note that
+ // removing this object from the listener list with Release transfers its
+ // ownership to the caller and makes this function return NULL the next
+ // time.
+ TestEventListener* default_xml_generator() const {
+ return default_xml_generator_;
+ }
+
+ private:
+ friend class TestSuite;
+ friend class TestInfo;
+ friend class internal::DefaultGlobalTestPartResultReporter;
+ friend class internal::NoExecDeathTest;
+ friend class internal::TestEventListenersAccessor;
+ friend class internal::UnitTestImpl;
+
+ // Returns repeater that broadcasts the TestEventListener events to all
+ // subscribers.
+ TestEventListener* repeater();
+
+ // Sets the default_result_printer attribute to the provided listener.
+ // The listener is also added to the listener list and previous
+ // default_result_printer is removed from it and deleted. The listener can
+ // also be NULL in which case it will not be added to the list. Does
+ // nothing if the previous and the current listener objects are the same.
+ void SetDefaultResultPrinter(TestEventListener* listener);
+
+ // Sets the default_xml_generator attribute to the provided listener. The
+ // listener is also added to the listener list and previous
+ // default_xml_generator is removed from it and deleted. The listener can
+ // also be NULL in which case it will not be added to the list. Does
+ // nothing if the previous and the current listener objects are the same.
+ void SetDefaultXmlGenerator(TestEventListener* listener);
+
+ // Controls whether events will be forwarded by the repeater to the
+ // listeners in the list.
+ bool EventForwardingEnabled() const;
+ void SuppressEventForwarding();
+
+ // The actual list of listeners.
+ internal::TestEventRepeater* repeater_;
+ // Listener responsible for the standard result output.
+ TestEventListener* default_result_printer_;
+ // Listener responsible for the creation of the XML output file.
+ TestEventListener* default_xml_generator_;
+
+ // We disallow copying TestEventListeners.
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventListeners);
+};
+
+// A UnitTest consists of a vector of TestSuites.
+//
+// This is a singleton class. The only instance of UnitTest is
+// created when UnitTest::GetInstance() is first called. This
+// instance is never deleted.
+//
+// UnitTest is not copyable.
+//
+// This class is thread-safe as long as the methods are called
+// according to their specification.
+class GTEST_API_ UnitTest {
+ public:
+ // Gets the singleton UnitTest object. The first time this method
+ // is called, a UnitTest object is constructed and returned.
+ // Consecutive calls will return the same object.
+ static UnitTest* GetInstance();
+
+ // Runs all tests in this UnitTest object and prints the result.
+ // Returns 0 if successful, or 1 otherwise.
+ //
+ // This method can only be called from the main thread.
+ //
+ // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+ int Run() GTEST_MUST_USE_RESULT_;
+
+ // Returns the working directory when the first TEST() or TEST_F()
+ // was executed. The UnitTest object owns the string.
+ const char* original_working_dir() const;
+
+ // Returns the TestSuite object for the test that's currently running,
+ // or NULL if no test is running.
+ const TestSuite* current_test_suite() const GTEST_LOCK_EXCLUDED_(mutex_);
+
+// Legacy API is still available but deprecated
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ const TestCase* current_test_case() const GTEST_LOCK_EXCLUDED_(mutex_);
+#endif
+
+ // Returns the TestInfo object for the test that's currently running,
+ // or NULL if no test is running.
+ const TestInfo* current_test_info() const
+ GTEST_LOCK_EXCLUDED_(mutex_);
+
+ // Returns the random seed used at the start of the current test run.
+ int random_seed() const;
+
+ // Returns the ParameterizedTestSuiteRegistry object used to keep track of
+ // value-parameterized tests and instantiate and register them.
+ //
+ // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+ internal::ParameterizedTestSuiteRegistry& parameterized_test_registry()
+ GTEST_LOCK_EXCLUDED_(mutex_);
+
+ // Gets the number of successful test suites.
+ int successful_test_suite_count() const;
+
+ // Gets the number of failed test suites.
+ int failed_test_suite_count() const;
+
+ // Gets the number of all test suites.
+ int total_test_suite_count() const;
+
+ // Gets the number of all test suites that contain at least one test
+ // that should run.
+ int test_suite_to_run_count() const;
+
+ // Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ int successful_test_case_count() const;
+ int failed_test_case_count() const;
+ int total_test_case_count() const;
+ int test_case_to_run_count() const;
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+ // Gets the number of successful tests.
+ int successful_test_count() const;
+
+ // Gets the number of skipped tests.
+ int skipped_test_count() const;
+
+ // Gets the number of failed tests.
+ int failed_test_count() const;
+
+ // Gets the number of disabled tests that will be reported in the XML report.
+ int reportable_disabled_test_count() const;
+
+ // Gets the number of disabled tests.
+ int disabled_test_count() const;
+
+ // Gets the number of tests to be printed in the XML report.
+ int reportable_test_count() const;
+
+ // Gets the number of all tests.
+ int total_test_count() const;
+
+ // Gets the number of tests that should run.
+ int test_to_run_count() const;
+
+ // Gets the time of the test program start, in ms from the start of the
+ // UNIX epoch.
+ TimeInMillis start_timestamp() const;
+
+ // Gets the elapsed time, in milliseconds.
+ TimeInMillis elapsed_time() const;
+
+ // Returns true if and only if the unit test passed (i.e. all test suites
+ // passed).
+ bool Passed() const;
+
+ // Returns true if and only if the unit test failed (i.e. some test suite
+ // failed or something outside of all tests failed).
+ bool Failed() const;
+
+ // Gets the i-th test suite among all the test suites. i can range from 0 to
+ // total_test_suite_count() - 1. If i is not in that range, returns NULL.
+ const TestSuite* GetTestSuite(int i) const;
+
+// Legacy API is deprecated but still available
+#ifndef GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+ const TestCase* GetTestCase(int i) const;
+#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
+
+ // Returns the TestResult containing information on test failures and
+ // properties logged outside of individual test suites.
+ const TestResult& ad_hoc_test_result() const;
+
+ // Returns the list of event listeners that can be used to track events
+ // inside Google Test.
+ TestEventListeners& listeners();
+
+ private:
+ // Registers and returns a global test environment. When a test
+ // program is run, all global test environments will be set-up in
+ // the order they were registered. After all tests in the program
+ // have finished, all global test environments will be torn-down in
+ // the *reverse* order they were registered.
+ //
+ // The UnitTest object takes ownership of the given environment.
+ //
+ // This method can only be called from the main thread.
+ Environment* AddEnvironment(Environment* env);
+
+ // Adds a TestPartResult to the current TestResult object. All
+ // Google Test assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc)
+ // eventually call this to report their results. The user code
+ // should use the assertion macros instead of calling this directly.
+ void AddTestPartResult(TestPartResult::Type result_type,
+ const char* file_name,
+ int line_number,
+ const std::string& message,
+ const std::string& os_stack_trace)
+ GTEST_LOCK_EXCLUDED_(mutex_);
+
+ // Adds a TestProperty to the current TestResult object when invoked from
+ // inside a test, to current TestSuite's ad_hoc_test_result_ when invoked
+ // from SetUpTestSuite or TearDownTestSuite, or to the global property set
+ // when invoked elsewhere. If the result already contains a property with
+ // the same key, the value will be updated.
+ void RecordProperty(const std::string& key, const std::string& value);
+
+ // Gets the i-th test suite among all the test suites. i can range from 0 to
+ // total_test_suite_count() - 1. If i is not in that range, returns NULL.
+ TestSuite* GetMutableTestSuite(int i);
+
+ // Accessors for the implementation object.
+ internal::UnitTestImpl* impl() { return impl_; }
+ const internal::UnitTestImpl* impl() const { return impl_; }
+
+ // These classes and functions are friends as they need to access private
+ // members of UnitTest.
+ friend class ScopedTrace;
+ friend class Test;
+ friend class internal::AssertHelper;
+ friend class internal::StreamingListenerTest;
+ friend class internal::UnitTestRecordPropertyTestHelper;
+ friend Environment* AddGlobalTestEnvironment(Environment* env);
+ friend std::set<std::string>* internal::GetIgnoredParameterizedTestSuites();
+ friend internal::UnitTestImpl* internal::GetUnitTestImpl();
+ friend void internal::ReportFailureInUnknownLocation(
+ TestPartResult::Type result_type,
+ const std::string& message);
+
+ // Creates an empty UnitTest.
+ UnitTest();
+
+ // D'tor
+ virtual ~UnitTest();
+
+ // Pushes a trace defined by SCOPED_TRACE() on to the per-thread
+ // Google Test trace stack.
+ void PushGTestTrace(const internal::TraceInfo& trace)
+ GTEST_LOCK_EXCLUDED_(mutex_);
+
+ // Pops a trace from the per-thread Google Test trace stack.
+ void PopGTestTrace()
+ GTEST_LOCK_EXCLUDED_(mutex_);
+
+ // Protects mutable state in *impl_. This is mutable as some const
+ // methods need to lock it too.
+ mutable internal::Mutex mutex_;
+
+ // Opaque implementation object. This field is never changed once
+ // the object is constructed. We don't mark it as const here, as
+ // doing so will cause a warning in the constructor of UnitTest.
+ // Mutable state in *impl_ is protected by mutex_.
+ internal::UnitTestImpl* impl_;
+
+ // We disallow copying UnitTest.
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTest);
+};
+
+// A convenient wrapper for adding an environment for the test
+// program.
+//
+// You should call this before RUN_ALL_TESTS() is called, probably in
+// main(). If you use gtest_main, you need to call this before main()
+// starts for it to take effect. For example, you can define a global
+// variable like this:
+//
+// testing::Environment* const foo_env =
+// testing::AddGlobalTestEnvironment(new FooEnvironment);
+//
+// However, we strongly recommend you to write your own main() and
+// call AddGlobalTestEnvironment() there, as relying on initialization
+// of global variables makes the code harder to read and may cause
+// problems when you register multiple environments from different
+// translation units and the environments have dependencies among them
+// (remember that the compiler doesn't guarantee the order in which
+// global variables from different translation units are initialized).
+inline Environment* AddGlobalTestEnvironment(Environment* env) {
+ return UnitTest::GetInstance()->AddEnvironment(env);
+}
+
+// Initializes Google Test. This must be called before calling
+// RUN_ALL_TESTS(). In particular, it parses a command line for the
+// flags that Google Test recognizes. Whenever a Google Test flag is
+// seen, it is removed from argv, and *argc is decremented.
+//
+// No value is returned. Instead, the Google Test flag variables are
+// updated.
+//
+// Calling the function for the second time has no user-visible effect.
+GTEST_API_ void InitGoogleTest(int* argc, char** argv);
+
+// This overloaded version can be used in Windows programs compiled in
+// UNICODE mode.
+GTEST_API_ void InitGoogleTest(int* argc, wchar_t** argv);
+
+// This overloaded version can be used on Arduino/embedded platforms where
+// there is no argc/argv.
+GTEST_API_ void InitGoogleTest();
+
+namespace internal {
+
+// Separate the error generating code from the code path to reduce the stack
+// frame size of CmpHelperEQ. This helps reduce the overhead of some sanitizers
+// when calling EXPECT_* in a tight loop.
+template <typename T1, typename T2>
+AssertionResult CmpHelperEQFailure(const char* lhs_expression,
+ const char* rhs_expression,
+ const T1& lhs, const T2& rhs) {
+ return EqFailure(lhs_expression,
+ rhs_expression,
+ FormatForComparisonFailureMessage(lhs, rhs),
+ FormatForComparisonFailureMessage(rhs, lhs),
+ false);
+}
+
+// This block of code defines operator==/!=
+// to block lexical scope lookup.
+// It prevents using invalid operator==/!= defined at namespace scope.
+struct faketype {};
+inline bool operator==(faketype, faketype) { return true; }
+inline bool operator!=(faketype, faketype) { return false; }
+
+// The helper function for {ASSERT|EXPECT}_EQ.
+template <typename T1, typename T2>
+AssertionResult CmpHelperEQ(const char* lhs_expression,
+ const char* rhs_expression,
+ const T1& lhs,
+ const T2& rhs) {
+ if (lhs == rhs) {
+ return AssertionSuccess();
+ }
+
+ return CmpHelperEQFailure(lhs_expression, rhs_expression, lhs, rhs);
+}
+
+class EqHelper {
+ public:
+ // This templatized version is for the general case.
+ template <
+ typename T1, typename T2,
+ // Disable this overload for cases where one argument is a pointer
+ // and the other is the null pointer constant.
+ typename std::enable_if<!std::is_integral<T1>::value ||
+ !std::is_pointer<T2>::value>::type* = nullptr>
+ static AssertionResult Compare(const char* lhs_expression,
+ const char* rhs_expression, const T1& lhs,
+ const T2& rhs) {
+ return CmpHelperEQ(lhs_expression, rhs_expression, lhs, rhs);
+ }
+
+ // With this overloaded version, we allow anonymous enums to be used
+ // in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous
+ // enums can be implicitly cast to BiggestInt.
+ //
+ // Even though its body looks the same as the above version, we
+ // cannot merge the two, as it will make anonymous enums unhappy.
+ static AssertionResult Compare(const char* lhs_expression,
+ const char* rhs_expression,
+ BiggestInt lhs,
+ BiggestInt rhs) {
+ return CmpHelperEQ(lhs_expression, rhs_expression, lhs, rhs);
+ }
+
+ template <typename T>
+ static AssertionResult Compare(
+ const char* lhs_expression, const char* rhs_expression,
+ // Handle cases where '0' is used as a null pointer literal.
+ std::nullptr_t /* lhs */, T* rhs) {
+ // We already know that 'lhs' is a null pointer.
+ return CmpHelperEQ(lhs_expression, rhs_expression, static_cast<T*>(nullptr),
+ rhs);
+ }
+};
+
+// Separate the error generating code from the code path to reduce the stack
+// frame size of CmpHelperOP. This helps reduce the overhead of some sanitizers
+// when calling EXPECT_OP in a tight loop.
+template <typename T1, typename T2>
+AssertionResult CmpHelperOpFailure(const char* expr1, const char* expr2,
+ const T1& val1, const T2& val2,
+ const char* op) {
+ return AssertionFailure()
+ << "Expected: (" << expr1 << ") " << op << " (" << expr2
+ << "), actual: " << FormatForComparisonFailureMessage(val1, val2)
+ << " vs " << FormatForComparisonFailureMessage(val2, val1);
+}
+
+// A macro for implementing the helper functions needed to implement
+// ASSERT_?? and EXPECT_??. It is here just to avoid copy-and-paste
+// of similar code.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+
+#define GTEST_IMPL_CMP_HELPER_(op_name, op)\
+template <typename T1, typename T2>\
+AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \
+ const T1& val1, const T2& val2) {\
+ if (val1 op val2) {\
+ return AssertionSuccess();\
+ } else {\
+ return CmpHelperOpFailure(expr1, expr2, val1, val2, #op);\
+ }\
+}
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+
+// Implements the helper function for {ASSERT|EXPECT}_NE
+GTEST_IMPL_CMP_HELPER_(NE, !=)
+// Implements the helper function for {ASSERT|EXPECT}_LE
+GTEST_IMPL_CMP_HELPER_(LE, <=)
+// Implements the helper function for {ASSERT|EXPECT}_LT
+GTEST_IMPL_CMP_HELPER_(LT, <)
+// Implements the helper function for {ASSERT|EXPECT}_GE
+GTEST_IMPL_CMP_HELPER_(GE, >=)
+// Implements the helper function for {ASSERT|EXPECT}_GT
+GTEST_IMPL_CMP_HELPER_(GT, >)
+
+#undef GTEST_IMPL_CMP_HELPER_
+
+// The helper function for {ASSERT|EXPECT}_STREQ.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+GTEST_API_ AssertionResult CmpHelperSTREQ(const char* s1_expression,
+ const char* s2_expression,
+ const char* s1,
+ const char* s2);
+
+// The helper function for {ASSERT|EXPECT}_STRCASEEQ.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+GTEST_API_ AssertionResult CmpHelperSTRCASEEQ(const char* s1_expression,
+ const char* s2_expression,
+ const char* s1,
+ const char* s2);
+
+// The helper function for {ASSERT|EXPECT}_STRNE.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+GTEST_API_ AssertionResult CmpHelperSTRNE(const char* s1_expression,
+ const char* s2_expression,
+ const char* s1,
+ const char* s2);
+
+// The helper function for {ASSERT|EXPECT}_STRCASENE.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+GTEST_API_ AssertionResult CmpHelperSTRCASENE(const char* s1_expression,
+ const char* s2_expression,
+ const char* s1,
+ const char* s2);
+
+
+// Helper function for *_STREQ on wide strings.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+GTEST_API_ AssertionResult CmpHelperSTREQ(const char* s1_expression,
+ const char* s2_expression,
+ const wchar_t* s1,
+ const wchar_t* s2);
+
+// Helper function for *_STRNE on wide strings.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+GTEST_API_ AssertionResult CmpHelperSTRNE(const char* s1_expression,
+ const char* s2_expression,
+ const wchar_t* s1,
+ const wchar_t* s2);
+
+} // namespace internal
+
+// IsSubstring() and IsNotSubstring() are intended to be used as the
+// first argument to {EXPECT,ASSERT}_PRED_FORMAT2(), not by
+// themselves. They check whether needle is a substring of haystack
+// (NULL is considered a substring of itself only), and return an
+// appropriate error message when they fail.
+//
+// The {needle,haystack}_expr arguments are the stringified
+// expressions that generated the two real arguments.
+GTEST_API_ AssertionResult IsSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const char* needle, const char* haystack);
+GTEST_API_ AssertionResult IsSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const wchar_t* needle, const wchar_t* haystack);
+GTEST_API_ AssertionResult IsNotSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const char* needle, const char* haystack);
+GTEST_API_ AssertionResult IsNotSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const wchar_t* needle, const wchar_t* haystack);
+GTEST_API_ AssertionResult IsSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const ::std::string& needle, const ::std::string& haystack);
+GTEST_API_ AssertionResult IsNotSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const ::std::string& needle, const ::std::string& haystack);
+
+#if GTEST_HAS_STD_WSTRING
+GTEST_API_ AssertionResult IsSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const ::std::wstring& needle, const ::std::wstring& haystack);
+GTEST_API_ AssertionResult IsNotSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const ::std::wstring& needle, const ::std::wstring& haystack);
+#endif // GTEST_HAS_STD_WSTRING
+
+namespace internal {
+
+// Helper template function for comparing floating-points.
+//
+// Template parameter:
+//
+// RawType: the raw floating-point type (either float or double)
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+template <typename RawType>
+AssertionResult CmpHelperFloatingPointEQ(const char* lhs_expression,
+ const char* rhs_expression,
+ RawType lhs_value,
+ RawType rhs_value) {
+ const FloatingPoint<RawType> lhs(lhs_value), rhs(rhs_value);
+
+ if (lhs.AlmostEquals(rhs)) {
+ return AssertionSuccess();
+ }
+
+ ::std::stringstream lhs_ss;
+ lhs_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
+ << lhs_value;
+
+ ::std::stringstream rhs_ss;
+ rhs_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
+ << rhs_value;
+
+ return EqFailure(lhs_expression,
+ rhs_expression,
+ StringStreamToString(&lhs_ss),
+ StringStreamToString(&rhs_ss),
+ false);
+}
+
+// Helper function for implementing ASSERT_NEAR.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+GTEST_API_ AssertionResult DoubleNearPredFormat(const char* expr1,
+ const char* expr2,
+ const char* abs_error_expr,
+ double val1,
+ double val2,
+ double abs_error);
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+// A class that enables one to stream messages to assertion macros
+class GTEST_API_ AssertHelper {
+ public:
+ // Constructor.
+ AssertHelper(TestPartResult::Type type,
+ const char* file,
+ int line,
+ const char* message);
+ ~AssertHelper();
+
+ // Message assignment is a semantic trick to enable assertion
+ // streaming; see the GTEST_MESSAGE_ macro below.
+ void operator=(const Message& message) const;
+
+ private:
+ // We put our data in a struct so that the size of the AssertHelper class can
+ // be as small as possible. This is important because gcc is incapable of
+ // re-using stack space even for temporary variables, so every EXPECT_EQ
+ // reserves stack space for another AssertHelper.
+ struct AssertHelperData {
+ AssertHelperData(TestPartResult::Type t,
+ const char* srcfile,
+ int line_num,
+ const char* msg)
+ : type(t), file(srcfile), line(line_num), message(msg) { }
+
+ TestPartResult::Type const type;
+ const char* const file;
+ int const line;
+ std::string const message;
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelperData);
+ };
+
+ AssertHelperData* const data_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelper);
+};
+
+} // namespace internal
+
+// The pure interface class that all value-parameterized tests inherit from.
+// A value-parameterized class must inherit from both ::testing::Test and
+// ::testing::WithParamInterface. In most cases that just means inheriting
+// from ::testing::TestWithParam, but more complicated test hierarchies
+// may need to inherit from Test and WithParamInterface at different levels.
+//
+// This interface has support for accessing the test parameter value via
+// the GetParam() method.
+//
+// Use it with one of the parameter generator defining functions, like Range(),
+// Values(), ValuesIn(), Bool(), and Combine().
+//
+// class FooTest : public ::testing::TestWithParam<int> {
+// protected:
+// FooTest() {
+// // Can use GetParam() here.
+// }
+// ~FooTest() override {
+// // Can use GetParam() here.
+// }
+// void SetUp() override {
+// // Can use GetParam() here.
+// }
+// void TearDown override {
+// // Can use GetParam() here.
+// }
+// };
+// TEST_P(FooTest, DoesBar) {
+// // Can use GetParam() method here.
+// Foo foo;
+// ASSERT_TRUE(foo.DoesBar(GetParam()));
+// }
+// INSTANTIATE_TEST_SUITE_P(OneToTenRange, FooTest, ::testing::Range(1, 10));
+
+template <typename T>
+class WithParamInterface {
+ public:
+ typedef T ParamType;
+ virtual ~WithParamInterface() {}
+
+ // The current parameter value. Is also available in the test fixture's
+ // constructor.
+ static const ParamType& GetParam() {
+ GTEST_CHECK_(parameter_ != nullptr)
+ << "GetParam() can only be called inside a value-parameterized test "
+ << "-- did you intend to write TEST_P instead of TEST_F?";
+ return *parameter_;
+ }
+
+ private:
+ // Sets parameter value. The caller is responsible for making sure the value
+ // remains alive and unchanged throughout the current test.
+ static void SetParam(const ParamType* parameter) {
+ parameter_ = parameter;
+ }
+
+ // Static value used for accessing parameter during a test lifetime.
+ static const ParamType* parameter_;
+
+ // TestClass must be a subclass of WithParamInterface<T> and Test.
+ template <class TestClass> friend class internal::ParameterizedTestFactory;
+};
+
+template <typename T>
+const T* WithParamInterface<T>::parameter_ = nullptr;
+
+// Most value-parameterized classes can ignore the existence of
+// WithParamInterface, and can just inherit from ::testing::TestWithParam.
+
+template <typename T>
+class TestWithParam : public Test, public WithParamInterface<T> {
+};
+
+// Macros for indicating success/failure in test code.
+
+// Skips test in runtime.
+// Skipping test aborts current function.
+// Skipped tests are neither successful nor failed.
+#define GTEST_SKIP() GTEST_SKIP_("")
+
+// ADD_FAILURE unconditionally adds a failure to the current test.
+// SUCCEED generates a success - it doesn't automatically make the
+// current test successful, as a test is only successful when it has
+// no failure.
+//
+// EXPECT_* verifies that a certain condition is satisfied. If not,
+// it behaves like ADD_FAILURE. In particular:
+//
+// EXPECT_TRUE verifies that a Boolean condition is true.
+// EXPECT_FALSE verifies that a Boolean condition is false.
+//
+// FAIL and ASSERT_* are similar to ADD_FAILURE and EXPECT_*, except
+// that they will also abort the current function on failure. People
+// usually want the fail-fast behavior of FAIL and ASSERT_*, but those
+// writing data-driven tests often find themselves using ADD_FAILURE
+// and EXPECT_* more.
+
+// Generates a nonfatal failure with a generic message.
+#define ADD_FAILURE() GTEST_NONFATAL_FAILURE_("Failed")
+
+// Generates a nonfatal failure at the given source file location with
+// a generic message.
+#define ADD_FAILURE_AT(file, line) \
+ GTEST_MESSAGE_AT_(file, line, "Failed", \
+ ::testing::TestPartResult::kNonFatalFailure)
+
+// Generates a fatal failure with a generic message.
+#define GTEST_FAIL() GTEST_FATAL_FAILURE_("Failed")
+
+// Like GTEST_FAIL(), but at the given source file location.
+#define GTEST_FAIL_AT(file, line) \
+ GTEST_MESSAGE_AT_(file, line, "Failed", \
+ ::testing::TestPartResult::kFatalFailure)
+
+// Define this macro to 1 to omit the definition of FAIL(), which is a
+// generic name and clashes with some other libraries.
+#if !GTEST_DONT_DEFINE_FAIL
+# define FAIL() GTEST_FAIL()
+#endif
+
+// Generates a success with a generic message.
+#define GTEST_SUCCEED() GTEST_SUCCESS_("Succeeded")
+
+// Define this macro to 1 to omit the definition of SUCCEED(), which
+// is a generic name and clashes with some other libraries.
+#if !GTEST_DONT_DEFINE_SUCCEED
+# define SUCCEED() GTEST_SUCCEED()
+#endif
+
+// Macros for testing exceptions.
+//
+// * {ASSERT|EXPECT}_THROW(statement, expected_exception):
+// Tests that the statement throws the expected exception.
+// * {ASSERT|EXPECT}_NO_THROW(statement):
+// Tests that the statement doesn't throw any exception.
+// * {ASSERT|EXPECT}_ANY_THROW(statement):
+// Tests that the statement throws an exception.
+
+#define EXPECT_THROW(statement, expected_exception) \
+ GTEST_TEST_THROW_(statement, expected_exception, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_NO_THROW(statement) \
+ GTEST_TEST_NO_THROW_(statement, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_ANY_THROW(statement) \
+ GTEST_TEST_ANY_THROW_(statement, GTEST_NONFATAL_FAILURE_)
+#define ASSERT_THROW(statement, expected_exception) \
+ GTEST_TEST_THROW_(statement, expected_exception, GTEST_FATAL_FAILURE_)
+#define ASSERT_NO_THROW(statement) \
+ GTEST_TEST_NO_THROW_(statement, GTEST_FATAL_FAILURE_)
+#define ASSERT_ANY_THROW(statement) \
+ GTEST_TEST_ANY_THROW_(statement, GTEST_FATAL_FAILURE_)
+
+// Boolean assertions. Condition can be either a Boolean expression or an
+// AssertionResult. For more information on how to use AssertionResult with
+// these macros see comments on that class.
+#define GTEST_EXPECT_TRUE(condition) \
+ GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \
+ GTEST_NONFATAL_FAILURE_)
+#define GTEST_EXPECT_FALSE(condition) \
+ GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \
+ GTEST_NONFATAL_FAILURE_)
+#define GTEST_ASSERT_TRUE(condition) \
+ GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \
+ GTEST_FATAL_FAILURE_)
+#define GTEST_ASSERT_FALSE(condition) \
+ GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \
+ GTEST_FATAL_FAILURE_)
+
+// Define these macros to 1 to omit the definition of the corresponding
+// EXPECT or ASSERT, which clashes with some users' own code.
+
+#if !GTEST_DONT_DEFINE_EXPECT_TRUE
+#define EXPECT_TRUE(condition) GTEST_EXPECT_TRUE(condition)
+#endif
+
+#if !GTEST_DONT_DEFINE_EXPECT_FALSE
+#define EXPECT_FALSE(condition) GTEST_EXPECT_FALSE(condition)
+#endif
+
+#if !GTEST_DONT_DEFINE_ASSERT_TRUE
+#define ASSERT_TRUE(condition) GTEST_ASSERT_TRUE(condition)
+#endif
+
+#if !GTEST_DONT_DEFINE_ASSERT_FALSE
+#define ASSERT_FALSE(condition) GTEST_ASSERT_FALSE(condition)
+#endif
+
+// Macros for testing equalities and inequalities.
+//
+// * {ASSERT|EXPECT}_EQ(v1, v2): Tests that v1 == v2
+// * {ASSERT|EXPECT}_NE(v1, v2): Tests that v1 != v2
+// * {ASSERT|EXPECT}_LT(v1, v2): Tests that v1 < v2
+// * {ASSERT|EXPECT}_LE(v1, v2): Tests that v1 <= v2
+// * {ASSERT|EXPECT}_GT(v1, v2): Tests that v1 > v2
+// * {ASSERT|EXPECT}_GE(v1, v2): Tests that v1 >= v2
+//
+// When they are not, Google Test prints both the tested expressions and
+// their actual values. The values must be compatible built-in types,
+// or you will get a compiler error. By "compatible" we mean that the
+// values can be compared by the respective operator.
+//
+// Note:
+//
+// 1. It is possible to make a user-defined type work with
+// {ASSERT|EXPECT}_??(), but that requires overloading the
+// comparison operators and is thus discouraged by the Google C++
+// Usage Guide. Therefore, you are advised to use the
+// {ASSERT|EXPECT}_TRUE() macro to assert that two objects are
+// equal.
+//
+// 2. The {ASSERT|EXPECT}_??() macros do pointer comparisons on
+// pointers (in particular, C strings). Therefore, if you use it
+// with two C strings, you are testing how their locations in memory
+// are related, not how their content is related. To compare two C
+// strings by content, use {ASSERT|EXPECT}_STR*().
+//
+// 3. {ASSERT|EXPECT}_EQ(v1, v2) is preferred to
+// {ASSERT|EXPECT}_TRUE(v1 == v2), as the former tells you
+// what the actual value is when it fails, and similarly for the
+// other comparisons.
+//
+// 4. Do not depend on the order in which {ASSERT|EXPECT}_??()
+// evaluate their arguments, which is undefined.
+//
+// 5. These macros evaluate their arguments exactly once.
+//
+// Examples:
+//
+// EXPECT_NE(Foo(), 5);
+// EXPECT_EQ(a_pointer, NULL);
+// ASSERT_LT(i, array_size);
+// ASSERT_GT(records.size(), 0) << "There is no record left.";
+
+#define EXPECT_EQ(val1, val2) \
+ EXPECT_PRED_FORMAT2(::testing::internal::EqHelper::Compare, val1, val2)
+#define EXPECT_NE(val1, val2) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2)
+#define EXPECT_LE(val1, val2) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2)
+#define EXPECT_LT(val1, val2) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2)
+#define EXPECT_GE(val1, val2) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2)
+#define EXPECT_GT(val1, val2) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2)
+
+#define GTEST_ASSERT_EQ(val1, val2) \
+ ASSERT_PRED_FORMAT2(::testing::internal::EqHelper::Compare, val1, val2)
+#define GTEST_ASSERT_NE(val1, val2) \
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2)
+#define GTEST_ASSERT_LE(val1, val2) \
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2)
+#define GTEST_ASSERT_LT(val1, val2) \
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2)
+#define GTEST_ASSERT_GE(val1, val2) \
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2)
+#define GTEST_ASSERT_GT(val1, val2) \
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2)
+
+// Define macro GTEST_DONT_DEFINE_ASSERT_XY to 1 to omit the definition of
+// ASSERT_XY(), which clashes with some users' own code.
+
+#if !GTEST_DONT_DEFINE_ASSERT_EQ
+# define ASSERT_EQ(val1, val2) GTEST_ASSERT_EQ(val1, val2)
+#endif
+
+#if !GTEST_DONT_DEFINE_ASSERT_NE
+# define ASSERT_NE(val1, val2) GTEST_ASSERT_NE(val1, val2)
+#endif
+
+#if !GTEST_DONT_DEFINE_ASSERT_LE
+# define ASSERT_LE(val1, val2) GTEST_ASSERT_LE(val1, val2)
+#endif
+
+#if !GTEST_DONT_DEFINE_ASSERT_LT
+# define ASSERT_LT(val1, val2) GTEST_ASSERT_LT(val1, val2)
+#endif
+
+#if !GTEST_DONT_DEFINE_ASSERT_GE
+# define ASSERT_GE(val1, val2) GTEST_ASSERT_GE(val1, val2)
+#endif
+
+#if !GTEST_DONT_DEFINE_ASSERT_GT
+# define ASSERT_GT(val1, val2) GTEST_ASSERT_GT(val1, val2)
+#endif
+
+// C-string Comparisons. All tests treat NULL and any non-NULL string
+// as different. Two NULLs are equal.
+//
+// * {ASSERT|EXPECT}_STREQ(s1, s2): Tests that s1 == s2
+// * {ASSERT|EXPECT}_STRNE(s1, s2): Tests that s1 != s2
+// * {ASSERT|EXPECT}_STRCASEEQ(s1, s2): Tests that s1 == s2, ignoring case
+// * {ASSERT|EXPECT}_STRCASENE(s1, s2): Tests that s1 != s2, ignoring case
+//
+// For wide or narrow string objects, you can use the
+// {ASSERT|EXPECT}_??() macros.
+//
+// Don't depend on the order in which the arguments are evaluated,
+// which is undefined.
+//
+// These macros evaluate their arguments exactly once.
+
+#define EXPECT_STREQ(s1, s2) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, s1, s2)
+#define EXPECT_STRNE(s1, s2) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2)
+#define EXPECT_STRCASEEQ(s1, s2) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, s1, s2)
+#define EXPECT_STRCASENE(s1, s2)\
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2)
+
+#define ASSERT_STREQ(s1, s2) \
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, s1, s2)
+#define ASSERT_STRNE(s1, s2) \
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2)
+#define ASSERT_STRCASEEQ(s1, s2) \
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, s1, s2)
+#define ASSERT_STRCASENE(s1, s2)\
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2)
+
+// Macros for comparing floating-point numbers.
+//
+// * {ASSERT|EXPECT}_FLOAT_EQ(val1, val2):
+// Tests that two float values are almost equal.
+// * {ASSERT|EXPECT}_DOUBLE_EQ(val1, val2):
+// Tests that two double values are almost equal.
+// * {ASSERT|EXPECT}_NEAR(v1, v2, abs_error):
+// Tests that v1 and v2 are within the given distance to each other.
+//
+// Google Test uses ULP-based comparison to automatically pick a default
+// error bound that is appropriate for the operands. See the
+// FloatingPoint template class in gtest-internal.h if you are
+// interested in the implementation details.
+
+#define EXPECT_FLOAT_EQ(val1, val2)\
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<float>, \
+ val1, val2)
+
+#define EXPECT_DOUBLE_EQ(val1, val2)\
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<double>, \
+ val1, val2)
+
+#define ASSERT_FLOAT_EQ(val1, val2)\
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<float>, \
+ val1, val2)
+
+#define ASSERT_DOUBLE_EQ(val1, val2)\
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<double>, \
+ val1, val2)
+
+#define EXPECT_NEAR(val1, val2, abs_error)\
+ EXPECT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \
+ val1, val2, abs_error)
+
+#define ASSERT_NEAR(val1, val2, abs_error)\
+ ASSERT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \
+ val1, val2, abs_error)
+
+// These predicate format functions work on floating-point values, and
+// can be used in {ASSERT|EXPECT}_PRED_FORMAT2*(), e.g.
+//
+// EXPECT_PRED_FORMAT2(testing::DoubleLE, Foo(), 5.0);
+
+// Asserts that val1 is less than, or almost equal to, val2. Fails
+// otherwise. In particular, it fails if either val1 or val2 is NaN.
+GTEST_API_ AssertionResult FloatLE(const char* expr1, const char* expr2,
+ float val1, float val2);
+GTEST_API_ AssertionResult DoubleLE(const char* expr1, const char* expr2,
+ double val1, double val2);
+
+
+#if GTEST_OS_WINDOWS
+
+// Macros that test for HRESULT failure and success, these are only useful
+// on Windows, and rely on Windows SDK macros and APIs to compile.
+//
+// * {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED}(expr)
+//
+// When expr unexpectedly fails or succeeds, Google Test prints the
+// expected result and the actual result with both a human-readable
+// string representation of the error, if available, as well as the
+// hex result code.
+# define EXPECT_HRESULT_SUCCEEDED(expr) \
+ EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr))
+
+# define ASSERT_HRESULT_SUCCEEDED(expr) \
+ ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr))
+
+# define EXPECT_HRESULT_FAILED(expr) \
+ EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr))
+
+# define ASSERT_HRESULT_FAILED(expr) \
+ ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr))
+
+#endif // GTEST_OS_WINDOWS
+
+// Macros that execute statement and check that it doesn't generate new fatal
+// failures in the current thread.
+//
+// * {ASSERT|EXPECT}_NO_FATAL_FAILURE(statement);
+//
+// Examples:
+//
+// EXPECT_NO_FATAL_FAILURE(Process());
+// ASSERT_NO_FATAL_FAILURE(Process()) << "Process() failed";
+//
+#define ASSERT_NO_FATAL_FAILURE(statement) \
+ GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_FATAL_FAILURE_)
+#define EXPECT_NO_FATAL_FAILURE(statement) \
+ GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_NONFATAL_FAILURE_)
+
+// Causes a trace (including the given source file path and line number,
+// and the given message) to be included in every test failure message generated
+// by code in the scope of the lifetime of an instance of this class. The effect
+// is undone with the destruction of the instance.
+//
+// The message argument can be anything streamable to std::ostream.
+//
+// Example:
+// testing::ScopedTrace trace("file.cc", 123, "message");
+//
+class GTEST_API_ ScopedTrace {
+ public:
+ // The c'tor pushes the given source file location and message onto
+ // a trace stack maintained by Google Test.
+
+ // Template version. Uses Message() to convert the values into strings.
+ // Slow, but flexible.
+ template <typename T>
+ ScopedTrace(const char* file, int line, const T& message) {
+ PushTrace(file, line, (Message() << message).GetString());
+ }
+
+ // Optimize for some known types.
+ ScopedTrace(const char* file, int line, const char* message) {
+ PushTrace(file, line, message ? message : "(null)");
+ }
+
+ ScopedTrace(const char* file, int line, const std::string& message) {
+ PushTrace(file, line, message);
+ }
+
+ // The d'tor pops the info pushed by the c'tor.
+ //
+ // Note that the d'tor is not virtual in order to be efficient.
+ // Don't inherit from ScopedTrace!
+ ~ScopedTrace();
+
+ private:
+ void PushTrace(const char* file, int line, std::string message);
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedTrace);
+} GTEST_ATTRIBUTE_UNUSED_; // A ScopedTrace object does its job in its
+ // c'tor and d'tor. Therefore it doesn't
+ // need to be used otherwise.
+
+// Causes a trace (including the source file path, the current line
+// number, and the given message) to be included in every test failure
+// message generated by code in the current scope. The effect is
+// undone when the control leaves the current scope.
+//
+// The message argument can be anything streamable to std::ostream.
+//
+// In the implementation, we include the current line number as part
+// of the dummy variable name, thus allowing multiple SCOPED_TRACE()s
+// to appear in the same block - as long as they are on different
+// lines.
+//
+// Assuming that each thread maintains its own stack of traces.
+// Therefore, a SCOPED_TRACE() would (correctly) only affect the
+// assertions in its own thread.
+#define SCOPED_TRACE(message) \
+ ::testing::ScopedTrace GTEST_CONCAT_TOKEN_(gtest_trace_, __LINE__)(\
+ __FILE__, __LINE__, (message))
+
+// Compile-time assertion for type equality.
+// StaticAssertTypeEq<type1, type2>() compiles if and only if type1 and type2
+// are the same type. The value it returns is not interesting.
+//
+// Instead of making StaticAssertTypeEq a class template, we make it a
+// function template that invokes a helper class template. This
+// prevents a user from misusing StaticAssertTypeEq<T1, T2> by
+// defining objects of that type.
+//
+// CAVEAT:
+//
+// When used inside a method of a class template,
+// StaticAssertTypeEq<T1, T2>() is effective ONLY IF the method is
+// instantiated. For example, given:
+//
+// template <typename T> class Foo {
+// public:
+// void Bar() { testing::StaticAssertTypeEq<int, T>(); }
+// };
+//
+// the code:
+//
+// void Test1() { Foo<bool> foo; }
+//
+// will NOT generate a compiler error, as Foo<bool>::Bar() is never
+// actually instantiated. Instead, you need:
+//
+// void Test2() { Foo<bool> foo; foo.Bar(); }
+//
+// to cause a compiler error.
+template <typename T1, typename T2>
+constexpr bool StaticAssertTypeEq() noexcept {
+ static_assert(std::is_same<T1, T2>::value, "T1 and T2 are not the same type");
+ return true;
+}
+
+// Defines a test.
+//
+// The first parameter is the name of the test suite, and the second
+// parameter is the name of the test within the test suite.
+//
+// The convention is to end the test suite name with "Test". For
+// example, a test suite for the Foo class can be named FooTest.
+//
+// Test code should appear between braces after an invocation of
+// this macro. Example:
+//
+// TEST(FooTest, InitializesCorrectly) {
+// Foo foo;
+// EXPECT_TRUE(foo.StatusIsOK());
+// }
+
+// Note that we call GetTestTypeId() instead of GetTypeId<
+// ::testing::Test>() here to get the type ID of testing::Test. This
+// is to work around a suspected linker bug when using Google Test as
+// a framework on Mac OS X. The bug causes GetTypeId<
+// ::testing::Test>() to return different values depending on whether
+// the call is from the Google Test framework itself or from user test
+// code. GetTestTypeId() is guaranteed to always return the same
+// value, as it always calls GetTypeId<>() from the Google Test
+// framework.
+#define GTEST_TEST(test_suite_name, test_name) \
+ GTEST_TEST_(test_suite_name, test_name, ::testing::Test, \
+ ::testing::internal::GetTestTypeId())
+
+// Define this macro to 1 to omit the definition of TEST(), which
+// is a generic name and clashes with some other libraries.
+#if !GTEST_DONT_DEFINE_TEST
+#define TEST(test_suite_name, test_name) GTEST_TEST(test_suite_name, test_name)
+#endif
+
+// Defines a test that uses a test fixture.
+//
+// The first parameter is the name of the test fixture class, which
+// also doubles as the test suite name. The second parameter is the
+// name of the test within the test suite.
+//
+// A test fixture class must be declared earlier. The user should put
+// the test code between braces after using this macro. Example:
+//
+// class FooTest : public testing::Test {
+// protected:
+// void SetUp() override { b_.AddElement(3); }
+//
+// Foo a_;
+// Foo b_;
+// };
+//
+// TEST_F(FooTest, InitializesCorrectly) {
+// EXPECT_TRUE(a_.StatusIsOK());
+// }
+//
+// TEST_F(FooTest, ReturnsElementCountCorrectly) {
+// EXPECT_EQ(a_.size(), 0);
+// EXPECT_EQ(b_.size(), 1);
+// }
+//
+// GOOGLETEST_CM0011 DO NOT DELETE
+#if !GTEST_DONT_DEFINE_TEST
+#define TEST_F(test_fixture, test_name)\
+ GTEST_TEST_(test_fixture, test_name, test_fixture, \
+ ::testing::internal::GetTypeId<test_fixture>())
+#endif // !GTEST_DONT_DEFINE_TEST
+
+// Returns a path to temporary directory.
+// Tries to determine an appropriate directory for the platform.
+GTEST_API_ std::string TempDir();
+
+#ifdef _MSC_VER
+# pragma warning(pop)
+#endif
+
+// Dynamically registers a test with the framework.
+//
+// This is an advanced API only to be used when the `TEST` macros are
+// insufficient. The macros should be preferred when possible, as they avoid
+// most of the complexity of calling this function.
+//
+// The `factory` argument is a factory callable (move-constructible) object or
+// function pointer that creates a new instance of the Test object. It
+// handles ownership to the caller. The signature of the callable is
+// `Fixture*()`, where `Fixture` is the test fixture class for the test. All
+// tests registered with the same `test_suite_name` must return the same
+// fixture type. This is checked at runtime.
+//
+// The framework will infer the fixture class from the factory and will call
+// the `SetUpTestSuite` and `TearDownTestSuite` for it.
+//
+// Must be called before `RUN_ALL_TESTS()` is invoked, otherwise behavior is
+// undefined.
+//
+// Use case example:
+//
+// class MyFixture : public ::testing::Test {
+// public:
+// // All of these optional, just like in regular macro usage.
+// static void SetUpTestSuite() { ... }
+// static void TearDownTestSuite() { ... }
+// void SetUp() override { ... }
+// void TearDown() override { ... }
+// };
+//
+// class MyTest : public MyFixture {
+// public:
+// explicit MyTest(int data) : data_(data) {}
+// void TestBody() override { ... }
+//
+// private:
+// int data_;
+// };
+//
+// void RegisterMyTests(const std::vector<int>& values) {
+// for (int v : values) {
+// ::testing::RegisterTest(
+// "MyFixture", ("Test" + std::to_string(v)).c_str(), nullptr,
+// std::to_string(v).c_str(),
+// __FILE__, __LINE__,
+// // Important to use the fixture type as the return type here.
+// [=]() -> MyFixture* { return new MyTest(v); });
+// }
+// }
+// ...
+// int main(int argc, char** argv) {
+// std::vector<int> values_to_test = LoadValuesFromConfig();
+// RegisterMyTests(values_to_test);
+// ...
+// return RUN_ALL_TESTS();
+// }
+//
+template <int&... ExplicitParameterBarrier, typename Factory>
+TestInfo* RegisterTest(const char* test_suite_name, const char* test_name,
+ const char* type_param, const char* value_param,
+ const char* file, int line, Factory factory) {
+ using TestT = typename std::remove_pointer<decltype(factory())>::type;
+
+ class FactoryImpl : public internal::TestFactoryBase {
+ public:
+ explicit FactoryImpl(Factory f) : factory_(std::move(f)) {}
+ Test* CreateTest() override { return factory_(); }
+
+ private:
+ Factory factory_;
+ };
+
+ return internal::MakeAndRegisterTestInfo(
+ test_suite_name, test_name, type_param, value_param,
+ internal::CodeLocation(file, line), internal::GetTypeId<TestT>(),
+ internal::SuiteApiResolver<TestT>::GetSetUpCaseOrSuite(file, line),
+ internal::SuiteApiResolver<TestT>::GetTearDownCaseOrSuite(file, line),
+ new FactoryImpl{std::move(factory)});
+}
+
+} // namespace testing
+
+// Use this function in main() to run all tests. It returns 0 if all
+// tests are successful, or 1 otherwise.
+//
+// RUN_ALL_TESTS() should be invoked after the command line has been
+// parsed by InitGoogleTest().
+//
+// This function was formerly a macro; thus, it is in the global
+// namespace and has an all-caps name.
+int RUN_ALL_TESTS() GTEST_MUST_USE_RESULT_;
+
+inline int RUN_ALL_TESTS() {
+ return ::testing::UnitTest::GetInstance()->Run();
+}
+
+GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251
+
+#endif // GOOGLETEST_INCLUDE_GTEST_GTEST_H_
diff --git a/tools/distrib/linux/README.minimal.txt b/tools/distrib/linux/README.minimal.txt
new file mode 100644
index 00000000..16cf3cb2
--- /dev/null
+++ b/tools/distrib/linux/README.minimal.txt
@@ -0,0 +1,28 @@
+CONTENTS
+--------
+
+cmake Contains CMake configuration files shared by all targets.
+
+include Contains all required CEF header files.
+
+libcef_dll Contains the source code for the libcef_dll_wrapper static library
+ that all applications using the CEF C++ API must link against.
+
+Release Contains libcef.so and other components required to run the release
+ version of CEF-based applications. By default these files should be
+ placed in the same directory as the executable.
+
+Resources Contains resources required by libcef.so. By default these files
+ should be placed in the same directory as libcef.so.
+
+
+USAGE
+-----
+
+Building using CMake:
+ CMake can be used to generate project files in many different formats. See
+ usage instructions at the top of the CMakeLists.txt file.
+
+Please visit the CEF Website for additional usage information.
+
+https://bitbucket.org/chromiumembedded/cef/
diff --git a/tools/distrib/linux/README.redistrib.txt b/tools/distrib/linux/README.redistrib.txt
new file mode 100644
index 00000000..0f442084
--- /dev/null
+++ b/tools/distrib/linux/README.redistrib.txt
@@ -0,0 +1,63 @@
+REDISTRIBUTION
+--------------
+
+This binary distribution contains the below components.
+
+Required components:
+
+The following components are required. CEF will not function without them.
+
+* CEF core library.
+ * libcef.so
+
+* Unicode support data.
+ * icudtl.dat
+
+* V8 snapshot data.
+ * snapshot_blob.bin
+ * v8_context_snapshot.bin
+
+Optional components:
+
+The following components are optional. If they are missing CEF will continue to
+run but any related functionality may become broken or disabled.
+
+* Localized resources.
+ Locale file loading can be disabled completely using
+ CefSettings.pack_loading_disabled. The locales directory path can be
+ customized using CefSettings.locales_dir_path.
+
+ * locales/
+ Directory containing localized resources used by CEF, Chromium and Blink. A
+ .pak file is loaded from this directory based on the value of environment
+ variables which are read with the following precedence order: LANGUAGE,
+ LC_ALL, LC_MESSAGES and LANG. Only configured locales need to be
+ distributed. If no locale is configured the default locale of "en-US" will
+ be used. Without these files arbitrary Web components may display
+ incorrectly.
+
+* Other resources.
+ Pack file loading can be disabled completely using
+ CefSettings.pack_loading_disabled. The resources directory path can be
+ customized using CefSettings.resources_dir_path.
+
+ * chrome_100_percent.pak
+ * chrome_200_percent.pak
+ * resources.pak
+ These files contain non-localized resources used by CEF, Chromium and Blink.
+ Without these files arbitrary Web components may display incorrectly.
+
+* ANGLE support.
+ * libEGL.so
+ * libGLESv2.so
+ Support for rendering of HTML5 content like 2D canvas, 3D CSS and WebGL.
+ Without these files the aforementioned capabilities may fail.
+
+* SwANGLE support.
+ * libvk_swiftshader.so
+ * libvulkan.so.1
+ * vk_swiftshader_icd.json
+ Support for software rendering of HTML5 content like 2D canvas, 3D CSS and
+ WebGL using SwiftShader's Vulkan library as ANGLE's Vulkan backend. Without
+ these files the aforementioned capabilities may fail when GPU acceleration is
+ disabled or unavailable.
diff --git a/tools/distrib/linux/README.standard.txt b/tools/distrib/linux/README.standard.txt
new file mode 100644
index 00000000..24c48dab
--- /dev/null
+++ b/tools/distrib/linux/README.standard.txt
@@ -0,0 +1,52 @@
+CONTENTS
+--------
+
+cmake Contains CMake configuration files shared by all targets.
+
+Debug Contains libcef.so and other components required to run the debug
+ version of CEF-based applications. By default these files should be
+ placed in the same directory as libcef.so and will be copied there
+ as part of the build process.
+
+include Contains all required CEF header files.
+
+libcef_dll Contains the source code for the libcef_dll_wrapper static library
+ that all applications using the CEF C++ API must link against.
+
+Release Contains libcef.so and other components required to run the release
+ version of CEF-based applications. By default these files should be
+ placed in the same directory as libcef.so and will be copied there
+ as part of the build process.
+
+Resources Contains resources required by libcef.so. By default these files
+ should be placed in the same directory as libcef.so and will be
+ copied there as part of the build process.
+
+tests/ Directory of tests that demonstrate CEF usage.
+
+ cefclient Contains the cefclient sample application configured to build
+ using the files in this distribution. This application demonstrates
+ a wide range of CEF functionalities.
+
+ cefsimple Contains the cefsimple sample application configured to build
+ using the files in this distribution. This application demonstrates
+ the minimal functionality required to create a browser window.
+
+ ceftests Contains unit tests that exercise the CEF APIs.
+
+ gtest Contains the Google C++ Testing Framework used by the ceftests
+ target.
+
+ shared Contains source code shared by the cefclient and ceftests targets.
+
+
+USAGE
+-----
+
+Building using CMake:
+ CMake can be used to generate project files in many different formats. See
+ usage instructions at the top of the CMakeLists.txt file.
+
+Please visit the CEF Website for additional usage information.
+
+https://bitbucket.org/chromiumembedded/cef/
diff --git a/tools/distrib/mac/README.minimal.txt b/tools/distrib/mac/README.minimal.txt
new file mode 100644
index 00000000..723edbdf
--- /dev/null
+++ b/tools/distrib/mac/README.minimal.txt
@@ -0,0 +1,25 @@
+CONTENTS
+--------
+
+cmake Contains CMake configuration files shared by all targets.
+
+include Contains all required CEF header files.
+
+libcef_dll Contains the source code for the libcef_dll_wrapper static library
+ that all applications using the CEF C++ API must link against.
+
+Release Contains the "Chromium Embedded Framework.framework" and other
+ components required to run the release version of CEF-based
+ applications.
+
+
+USAGE
+-----
+
+Building using CMake:
+ CMake can be used to generate project files in many different formats. See
+ usage instructions at the top of the CMakeLists.txt file.
+
+Please visit the CEF Website for additional usage information.
+
+https://bitbucket.org/chromiumembedded/cef/
diff --git a/tools/distrib/mac/README.redistrib.txt b/tools/distrib/mac/README.redistrib.txt
new file mode 100644
index 00000000..9812ce8b
--- /dev/null
+++ b/tools/distrib/mac/README.redistrib.txt
@@ -0,0 +1,106 @@
+REDISTRIBUTION
+--------------
+
+This binary distribution contains the below components. Components listed under
+the "required" section must be redistributed with all applications using CEF.
+Components listed under the "optional" section may be excluded if the related
+features will not be used.
+
+Applications using CEF on OS X must follow a specific app bundle structure.
+Replace "cefclient" in the below example with your application name.
+
+cefclient.app/
+ Contents/
+ Frameworks/
+ Chromium Embedded Framework.framework/
+ Chromium Embedded Framework <= main application library
+ Libraries/
+ libEGL.dylib <= ANGLE support libraries
+ libGLESv2.dylib <=^
+ libvk_swiftshader.dylib <= SwANGLE support libraries
+ vk_swiftshader_icd.json <=^
+ Resources/
+ chrome_100_percent.pak <= non-localized resources and strings
+ chrome_200_percent.pak <=^
+ resources.pak <=^
+ icudtl.dat <= unicode support
+ snapshot_blob.bin, v8_context_snapshot.[x86_64|arm64].bin <= V8 initial snapshot
+ en.lproj/, ... <= locale-specific resources and strings
+ Info.plist
+ cefclient Helper.app/
+ Contents/
+ Info.plist
+ MacOS/
+ cefclient Helper <= helper executable
+ Pkginfo
+ Info.plist
+ MacOS/
+ cefclient <= cefclient application executable
+ Pkginfo
+ Resources/
+ binding.html, ... <= cefclient application resources
+
+The "Chromium Embedded Framework.framework" is an unversioned framework that
+contains CEF binaries and resources. Executables (cefclient, cefclient Helper,
+etc) must load this framework dynamically at runtime instead of linking it
+directly. See the documentation in include/wrapper/cef_library_loader.h for
+more information.
+
+The "cefclient Helper" app is used for executing separate processes (renderer,
+plugin, etc) with different characteristics. It needs to have a separate app
+bundle and Info.plist file so that, among other things, it doesn't show dock
+icons.
+
+Required components:
+
+The following components are required. CEF will not function without them.
+
+* CEF core library.
+ * Chromium Embedded Framework.framework/Chromium Embedded Framework
+
+* Unicode support data.
+ * Chromium Embedded Framework.framework/Resources/icudtl.dat
+
+* V8 snapshot data.
+ * Chromium Embedded Framework.framework/Resources/snapshot_blob.bin
+ * Chromium Embedded Framework.framework/Resources/v8_context_snapshot.bin
+
+Optional components:
+
+The following components are optional. If they are missing CEF will continue to
+run but any related functionality may become broken or disabled.
+
+* Localized resources.
+ Locale file loading can be disabled completely using
+ CefSettings.pack_loading_disabled.
+
+ * Chromium Embedded Framework.framework/Resources/*.lproj/
+ Directory containing localized resources used by CEF, Chromium and Blink. A
+ .pak file is loaded from this directory based on the CefSettings.locale
+ value. Only configured locales need to be distributed. If no locale is
+ configured the default locale of "en" will be used. Without these files
+ arbitrary Web components may display incorrectly.
+
+* Other resources.
+ Pack file loading can be disabled completely using
+ CefSettings.pack_loading_disabled.
+
+ * Chromium Embedded Framework.framework/Resources/chrome_100_percent.pak
+ * Chromium Embedded Framework.framework/Resources/chrome_200_percent.pak
+ * Chromium Embedded Framework.framework/Resources/resources.pak
+ These files contain non-localized resources used by CEF, Chromium and Blink.
+ Without these files arbitrary Web components may display incorrectly.
+
+* ANGLE support.
+ * Chromium Embedded Framework.framework/Libraries/libEGL.dylib
+ * Chromium Embedded Framework.framework/Libraries/libGLESv2.dylib
+ Support for rendering of HTML5 content like 2D canvas, 3D CSS and WebGL.
+ Without these files the aforementioned capabilities may fail.
+
+* SwANGLE support.
+ * Chromium Embedded Framework.framework/Libraries/libvk_swiftshader.dylib
+ * Chromium Embedded Framework.framework/Libraries/vk_swiftshader_icd.json
+ Support for software rendering of HTML5 content like 2D canvas, 3D CSS and
+ WebGL using SwiftShader's Vulkan library as ANGLE's Vulkan backend. Without
+ these files the aforementioned capabilities may fail when GPU acceleration is
+ disabled or unavailable.
diff --git a/tools/distrib/mac/README.sandbox.txt b/tools/distrib/mac/README.sandbox.txt
new file mode 100644
index 00000000..8d2258d9
--- /dev/null
+++ b/tools/distrib/mac/README.sandbox.txt
@@ -0,0 +1,14 @@
+CONTENTS
+--------
+
+Debug Contains the Debug build of cef_sandbox.a.
+
+Release Contains the Release build of cef_sandbox.a.
+
+
+USAGE
+-----
+
+Please visit the CEF Website for usage information.
+
+https://bitbucket.org/chromiumembedded/cef/
diff --git a/tools/distrib/mac/README.standard.txt b/tools/distrib/mac/README.standard.txt
new file mode 100644
index 00000000..4de70c20
--- /dev/null
+++ b/tools/distrib/mac/README.standard.txt
@@ -0,0 +1,46 @@
+CONTENTS
+--------
+
+cmake Contains CMake configuration files shared by all targets.
+
+Debug Contains the "Chromium Embedded Framework.framework" and other
+ components required to run the debug version of CEF-based
+ applications.
+
+include Contains all required CEF header files.
+
+libcef_dll Contains the source code for the libcef_dll_wrapper static library
+ that all applications using the CEF C++ API must link against.
+
+Release Contains the "Chromium Embedded Framework.framework" and other
+ components required to run the release version of CEF-based
+ applications.
+
+tests/ Directory of tests that demonstrate CEF usage.
+
+ cefclient Contains the cefclient sample application configured to build
+ using the files in this distribution. This application demonstrates
+ a wide range of CEF functionalities.
+
+ cefsimple Contains the cefsimple sample application configured to build
+ using the files in this distribution. This application demonstrates
+ the minimal functionality required to create a browser window.
+
+ ceftests Contains unit tests that exercise the CEF APIs.
+
+ gtest Contains the Google C++ Testing Framework used by the ceftests
+ target.
+
+ shared Contains source code shared by the cefclient and ceftests targets.
+
+
+USAGE
+-----
+
+Building using CMake:
+ CMake can be used to generate project files in many different formats. See
+ usage instructions at the top of the CMakeLists.txt file.
+
+Please visit the CEF Website for additional usage information.
+
+https://bitbucket.org/chromiumembedded/cef/
diff --git a/tools/distrib/transfer.cfg b/tools/distrib/transfer.cfg
new file mode 100644
index 00000000..d3a65eaf
--- /dev/null
+++ b/tools/distrib/transfer.cfg
@@ -0,0 +1,17 @@
+# Additional handling of transfer files.
+# target: Target location relative to the target release directory. This
+# value is required.
+# source: Source location relative to the CEF root directory. This value
+# is optional. If specified the source file will be copied to the target
+# location and a TRANSFER-README.txt file will be created.
+# post-process: Post-processing operation to perform. This value is
+# optional and may be any one of the following:
+# 'normalize_headers': Replace fully-qualified project header paths with
+# the optionally specified 'new_header_path' value.
+
+[
+ {
+ 'source' : '../net/base/net_error_list.h',
+ 'target' : 'include/base/internal/cef_net_error_list.h',
+ },
+]
diff --git a/tools/distrib/transfer_standard.cfg b/tools/distrib/transfer_standard.cfg
new file mode 100644
index 00000000..2ea2f074
--- /dev/null
+++ b/tools/distrib/transfer_standard.cfg
@@ -0,0 +1,29 @@
+# Additional handling of transfer files.
+# target: Target location relative to the target release directory. This
+# value is required.
+# source: Source location relative to the CEF root directory. This value
+# is optional. If specified the source file will be copied to the target
+# location and a TRANSFER-README.txt file will be created.
+# post-process: Post-processing operation to perform. This value is
+# optional and may be any one of the following:
+# 'normalize_headers': Replace fully-qualified project header paths with
+# the optionally specified 'new_header_path' value.
+
+[
+ {
+ 'source' : '../net/data/ssl/certificates/expired_cert.pem',
+ 'target' : 'tests/ceftests/resources/net/data/ssl/certificates/expired_cert.pem',
+ },
+ {
+ 'source' : '../net/data/ssl/certificates/localhost_cert.pem',
+ 'target' : 'tests/ceftests/resources/net/data/ssl/certificates/localhost_cert.pem',
+ },
+ {
+ 'source' : '../net/data/ssl/certificates/ok_cert.pem',
+ 'target' : 'tests/ceftests/resources/net/data/ssl/certificates/ok_cert.pem',
+ },
+ {
+ 'source' : '../net/data/ssl/certificates/root_ca_cert.pem',
+ 'target' : 'tests/ceftests/resources/net/data/ssl/certificates/root_ca_cert.pem',
+ },
+]
diff --git a/tools/distrib/win/README.minimal.txt b/tools/distrib/win/README.minimal.txt
new file mode 100644
index 00000000..4d8207ef
--- /dev/null
+++ b/tools/distrib/win/README.minimal.txt
@@ -0,0 +1,29 @@
+CONTENTS
+--------
+
+cmake Contains CMake configuration files shared by all targets.
+
+include Contains all required CEF header files.
+
+libcef_dll Contains the source code for the libcef_dll_wrapper static library
+ that all applications using the CEF C++ API must link against.
+
+Release Contains libcef.dll, libcef.lib and other components required to
+ build and run the release version of CEF-based applications. By
+ default these files should be placed in the same directory as the
+ executable.
+
+Resources Contains resources required by libcef.dll. By default these files
+ should be placed in the same directory as libcef.dll.
+
+
+USAGE
+-----
+
+Building using CMake:
+ CMake can be used to generate project files in many different formats. See
+ usage instructions at the top of the CMakeLists.txt file.
+
+Please visit the CEF Website for additional usage information.
+
+https://bitbucket.org/chromiumembedded/cef/
diff --git a/tools/distrib/win/README.redistrib.txt b/tools/distrib/win/README.redistrib.txt
new file mode 100644
index 00000000..29675cb0
--- /dev/null
+++ b/tools/distrib/win/README.redistrib.txt
@@ -0,0 +1,72 @@
+REDISTRIBUTION
+--------------
+
+This binary distribution contains the below components.
+
+Required components:
+
+The following components are required. CEF will not function without them.
+
+* CEF core library.
+ * libcef.dll
+
+* Crash reporting library.
+ * chrome_elf.dll
+
+* Unicode support data.
+ * icudtl.dat
+
+* V8 snapshot data.
+ * snapshot_blob.bin
+ * v8_context_snapshot.bin
+
+Optional components:
+
+The following components are optional. If they are missing CEF will continue to
+run but any related functionality may become broken or disabled.
+
+* Localized resources.
+ Locale file loading can be disabled completely using
+ CefSettings.pack_loading_disabled. The locales directory path can be
+ customized using CefSettings.locales_dir_path.
+
+ * locales/
+ Directory containing localized resources used by CEF, Chromium and Blink. A
+ .pak file is loaded from this directory based on the CefSettings.locale
+ value. Only configured locales need to be distributed. If no locale is
+ configured the default locale of "en-US" will be used. Without these files
+ arbitrary Web components may display incorrectly.
+
+* Other resources.
+ Pack file loading can be disabled completely using
+ CefSettings.pack_loading_disabled. The resources directory path can be
+ customized using CefSettings.resources_dir_path.
+
+ * chrome_100_percent.pak
+ * chrome_200_percent.pak
+ * resources.pak
+ These files contain non-localized resources used by CEF, Chromium and Blink.
+ Without these files arbitrary Web components may display incorrectly.
+
+* Direct3D support.
+ * d3dcompiler_47.dll
+ Support for GPU accelerated rendering of HTML5 content like 2D canvas, 3D CSS
+ and WebGL. Without this file the aforementioned capabilities may fail when GPU
+ acceleration is enabled (default in most cases). Use of this bundled version
+ is recommended instead of relying on the possibly old and untested system
+ installed version.
+
+* ANGLE support.
+ * libEGL.dll
+ * libGLESv2.dll
+ Support for rendering of HTML5 content like 2D canvas, 3D CSS and WebGL.
+ Without these files the aforementioned capabilities may fail.
+
+* SwANGLE support.
+ * vk_swiftshader.dll
+ * vk_swiftshader_icd.json
+ * vulkan-1.dll
+ Support for software rendering of HTML5 content like 2D canvas, 3D CSS and
+ WebGL using SwiftShader's Vulkan library as ANGLE's Vulkan backend. Without
+ these files the aforementioned capabilities may fail when GPU acceleration is
+ disabled or unavailable.
diff --git a/tools/distrib/win/README.sandbox.txt b/tools/distrib/win/README.sandbox.txt
new file mode 100644
index 00000000..09ee8326
--- /dev/null
+++ b/tools/distrib/win/README.sandbox.txt
@@ -0,0 +1,14 @@
+CONTENTS
+--------
+
+Debug Contains the Debug build of cef_sandbox.lib.
+
+Release Contains the Release build of cef_sandbox.lib.
+
+
+USAGE
+-----
+
+Please visit the CEF Website for usage information.
+
+https://bitbucket.org/chromiumembedded/cef/
diff --git a/tools/distrib/win/README.standard.txt b/tools/distrib/win/README.standard.txt
new file mode 100644
index 00000000..92d77972
--- /dev/null
+++ b/tools/distrib/win/README.standard.txt
@@ -0,0 +1,52 @@
+CONTENTS
+--------
+
+cmake Contains CMake configuration files shared by all targets.
+
+Debug Contains libcef.dll, libcef.lib and other components required to
+ build and run the debug version of CEF-based applications. By
+ default these files should be placed in the same directory as the
+ executable and will be copied there as part of the build process.
+
+include Contains all required CEF header files.
+
+libcef_dll Contains the source code for the libcef_dll_wrapper static library
+ that all applications using the CEF C++ API must link against.
+
+Release Contains libcef.dll, libcef.lib and other components required to
+ build and run the release version of CEF-based applications. By
+ default these files should be placed in the same directory as the
+ executable and will be copied there as part of the build process.
+
+Resources Contains resources required by libcef.dll. By default these files
+ should be placed in the same directory as libcef.dll and will be
+ copied there as part of the build process.
+
+tests/ Directory of tests that demonstrate CEF usage.
+
+ cefclient Contains the cefclient sample application configured to build
+ using the files in this distribution. This application demonstrates
+ a wide range of CEF functionalities.
+
+ cefsimple Contains the cefsimple sample application configured to build
+ using the files in this distribution. This application demonstrates
+ the minimal functionality required to create a browser window.
+
+ ceftests Contains unit tests that exercise the CEF APIs.
+
+ gtest Contains the Google C++ Testing Framework used by the ceftests
+ target.
+
+ shared Contains source code shared by the cefclient and ceftests targets.
+
+
+USAGE
+-----
+
+Building using CMake:
+ CMake can be used to generate project files in many different formats. See
+ usage instructions at the top of the CMakeLists.txt file.
+
+Please visit the CEF Website for additional usage information.
+
+https://bitbucket.org/chromiumembedded/cef/
diff --git a/tools/distrib/win/transfer_standard.cfg b/tools/distrib/win/transfer_standard.cfg
new file mode 100644
index 00000000..cb06d2fd
--- /dev/null
+++ b/tools/distrib/win/transfer_standard.cfg
@@ -0,0 +1,25 @@
+# Additional handling of transfer files.
+# target: Target location relative to the target release directory. This
+# value is required.
+# source: Source location relative to the CEF root directory. This value
+# is optional. If specified the source file will be copied to the target
+# location and a TRANSFER-README.txt file will be created.
+# post-process: Post-processing operation to perform. This value is
+# optional and may be any one of the following:
+# 'normalize_headers': Replace fully-qualified project header paths with
+# the optionally specified 'new_header_path' value.
+
+[
+ {
+ 'source' : '../build/win/compatibility.manifest',
+ 'target' : 'tests/cefclient/resources/win/compatibility.manifest',
+ },
+ {
+ 'source' : '../build/win/compatibility.manifest',
+ 'target' : 'tests/cefsimple/compatibility.manifest',
+ },
+ {
+ 'source' : '../build/win/compatibility.manifest',
+ 'target' : 'tests/ceftests/resources/win/compatibility.manifest',
+ },
+]
diff --git a/tools/distrib/win/x64/d3dcompiler_47.dll b/tools/distrib/win/x64/d3dcompiler_47.dll
new file mode 100644
index 00000000..e82d8c77
--- /dev/null
+++ b/tools/distrib/win/x64/d3dcompiler_47.dll
Binary files differ
diff --git a/tools/distrib/win/x86/d3dcompiler_47.dll b/tools/distrib/win/x86/d3dcompiler_47.dll
new file mode 100644
index 00000000..7e41f25c
--- /dev/null
+++ b/tools/distrib/win/x86/d3dcompiler_47.dll
Binary files differ
diff --git a/tools/exec_util.py b/tools/exec_util.py
new file mode 100644
index 00000000..a6c23479
--- /dev/null
+++ b/tools/exec_util.py
@@ -0,0 +1,41 @@
+# Copyright (c) 2014 The Chromium Embedded Framework Authors. All rights
+# reserved. Use of this source code is governed by a BSD-style license that
+# can be found in the LICENSE file
+
+from __future__ import absolute_import
+from subprocess import Popen, PIPE
+import sys
+
+
+def exec_cmd(cmd, path, input_string=None):
+ """ Execute the specified command and return the result. """
+ out = ''
+ err = ''
+ ret = -1
+ parts = cmd.split()
+ try:
+ if input_string is None:
+ process = Popen(
+ parts,
+ cwd=path,
+ stdout=PIPE,
+ stderr=PIPE,
+ shell=(sys.platform == 'win32'))
+ out, err = process.communicate()
+ ret = process.returncode
+ else:
+ process = Popen(
+ parts,
+ cwd=path,
+ stdin=PIPE,
+ stdout=PIPE,
+ stderr=PIPE,
+ shell=(sys.platform == 'win32'))
+ out, err = process.communicate(input=input_string)
+ ret = process.returncode
+ except IOError as e:
+ (errno, strerror) = e.args
+ raise
+ except:
+ raise
+ return {'out': out.decode('utf-8'), 'err': err.decode('utf-8'), 'ret': ret}
diff --git a/tools/file_util.py b/tools/file_util.py
new file mode 100644
index 00000000..810aed9f
--- /dev/null
+++ b/tools/file_util.py
@@ -0,0 +1,201 @@
+# Copyright (c) 2011 The Chromium Embedded Framework Authors. All rights
+# reserved. Use of this source code is governed by a BSD-style license that
+# can be found in the LICENSE file.
+
+from __future__ import absolute_import
+from glob import iglob
+from io import open
+import os
+import fnmatch
+import shutil
+import sys
+import time
+
+
+def read_file(name, normalize=True):
+ """ Read a file. """
+ try:
+ with open(name, 'r', encoding='utf-8') as f:
+ # read the data
+ data = f.read()
+ if normalize:
+ # normalize line endings
+ data = data.replace("\r\n", "\n")
+ return data
+ except IOError as e:
+ (errno, strerror) = e.args
+ sys.stderr.write('Failed to read file ' + name + ': ' + strerror)
+ raise
+
+
+def write_file(name, data):
+ """ Write a file. """
+ try:
+ with open(name, 'w', encoding='utf-8') as f:
+ # write the data
+ if sys.version_info.major == 2:
+ f.write(data.decode('utf-8'))
+ else:
+ f.write(data)
+ except IOError as e:
+ (errno, strerror) = e.args
+ sys.stderr.write('Failed to write file ' + name + ': ' + strerror)
+ raise
+
+
+def path_exists(name):
+ """ Returns true if the path currently exists. """
+ return os.path.exists(name)
+
+
+def write_file_if_changed(name, data):
+ """ Write a file if the contents have changed. Returns True if the file was written. """
+ if path_exists(name):
+ old_contents = read_file(name)
+ else:
+ old_contents = ''
+
+ if (data != old_contents):
+ write_file(name, data)
+ return True
+ return False
+
+
+def backup_file(name):
+ """ Rename the file to a name that includes the current time stamp. """
+ move_file(name, name + '.' + time.strftime('%Y-%m-%d-%H-%M-%S'))
+
+
+def copy_file(src, dst, quiet=True):
+ """ Copy a file. """
+ try:
+ shutil.copy2(src, dst)
+ if not quiet:
+ sys.stdout.write('Transferring ' + src + ' file.\n')
+ except IOError as e:
+ (errno, strerror) = e.args
+ sys.stderr.write('Failed to copy file from ' + src + ' to ' + dst + ': ' +
+ strerror)
+ raise
+
+
+def move_file(src, dst, quiet=True):
+ """ Move a file. """
+ try:
+ shutil.move(src, dst)
+ if not quiet:
+ sys.stdout.write('Moving ' + src + ' file.\n')
+ except IOError as e:
+ (errno, strerror) = e.args
+ sys.stderr.write('Failed to move file from ' + src + ' to ' + dst + ': ' +
+ strerror)
+ raise
+
+
+def copy_files(src_glob, dst_folder, quiet=True):
+ """ Copy multiple files. """
+ for fname in iglob(src_glob):
+ dst = os.path.join(dst_folder, os.path.basename(fname))
+ if os.path.isdir(fname):
+ copy_dir(fname, dst, quiet)
+ else:
+ copy_file(fname, dst, quiet)
+
+
+def remove_file(name, quiet=True):
+ """ Remove the specified file. """
+ try:
+ if path_exists(name):
+ os.remove(name)
+ if not quiet:
+ sys.stdout.write('Removing ' + name + ' file.\n')
+ except IOError as e:
+ (errno, strerror) = e.args
+ sys.stderr.write('Failed to remove file ' + name + ': ' + strerror)
+ raise
+
+
+def copy_dir(src, dst, quiet=True):
+ """ Copy a directory tree. """
+ try:
+ remove_dir(dst, quiet)
+ shutil.copytree(src, dst)
+ if not quiet:
+ sys.stdout.write('Transferring ' + src + ' directory.\n')
+ except IOError as e:
+ (errno, strerror) = e.args
+ sys.stderr.write('Failed to copy directory from ' + src + ' to ' + dst +
+ ': ' + strerror)
+ raise
+
+
+def remove_dir(name, quiet=True):
+ """ Remove the specified directory. """
+ try:
+ if path_exists(name):
+ shutil.rmtree(name)
+ if not quiet:
+ sys.stdout.write('Removing ' + name + ' directory.\n')
+ except IOError as e:
+ (errno, strerror) = e.args
+ sys.stderr.write('Failed to remove directory ' + name + ': ' + strerror)
+ raise
+
+
+def make_dir(name, quiet=True):
+ """ Create the specified directory. """
+ try:
+ if not path_exists(name):
+ if not quiet:
+ sys.stdout.write('Creating ' + name + ' directory.\n')
+ os.makedirs(name)
+ except IOError as e:
+ (errno, strerror) = e.args
+ sys.stderr.write('Failed to create directory ' + name + ': ' + strerror)
+ raise
+
+
+def get_files(search_glob):
+ """ Returns all files matching |search_glob|. """
+ recursive_glob = '**' + os.path.sep
+ if recursive_glob in search_glob:
+ if sys.version_info >= (3, 5):
+ result = iglob(search_glob, recursive=True)
+ else:
+ # Polyfill for recursive glob pattern matching added in Python 3.5.
+ result = get_files_recursive(*search_glob.split(recursive_glob))
+ else:
+ result = iglob(search_glob)
+
+ # Sort the result for consistency across platforms.
+ return sorted(result)
+
+
+def get_files_recursive(directory, pattern):
+ """ Returns all files in |directory| matching |pattern| recursively. """
+ for root, dirs, files in os.walk(directory):
+ for basename in files:
+ if fnmatch.fnmatch(basename, pattern):
+ filename = os.path.join(root, basename)
+ yield filename
+
+
+def read_version_file(file, args):
+ """ Read and parse a version file (key=value pairs, one per line). """
+ lines = read_file(file).split("\n")
+ for line in lines:
+ parts = line.split('=', 1)
+ if len(parts) == 2:
+ args[parts[0]] = parts[1]
+
+
+def eval_file(src):
+ """ Loads and evaluates the contents of the specified file. """
+ return eval(read_file(src), {'__builtins__': None}, None)
+
+
+def normalize_path(path):
+ """ Normalizes the path separator to match the Unix standard. """
+ if sys.platform == 'win32':
+ return path.replace('\\', '/')
+ return path
diff --git a/tools/fix_style.bat b/tools/fix_style.bat
new file mode 100644
index 00000000..09ea0be2
--- /dev/null
+++ b/tools/fix_style.bat
@@ -0,0 +1,2 @@
+@echo off
+python.bat %~dp0\fix_style.py %*
diff --git a/tools/fix_style.py b/tools/fix_style.py
new file mode 100644
index 00000000..e0debaef
--- /dev/null
+++ b/tools/fix_style.py
@@ -0,0 +1,145 @@
+# Copyright (c) 2017 The Chromium Embedded Framework Authors.
+# Portions copyright (c) 2011 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+from __future__ import absolute_import
+from __future__ import print_function
+import os, re, sys
+from clang_util import clang_format
+from file_util import eval_file, get_files, read_file, write_file
+from git_util import get_changed_files
+from yapf_util import yapf_format
+
+# File extensions that can be formatted.
+DEFAULT_LINT_WHITELIST_REGEX = r"(.*\.cpp|.*\.cc|.*\.h|.*\.java|.*\.mm|.*\.py)$"
+DEFAULT_LINT_BLACKLIST_REGEX = r"$^"
+
+# Directories containing these path components will be ignored.
+IGNORE_DIRECTORIES = []
+
+# Script directory.
+script_dir = os.path.dirname(__file__)
+root_dir = os.path.join(script_dir, os.pardir)
+
+
+def msg(filename, status):
+ if sys.platform == 'win32':
+ # Use Unix path separator.
+ filename = filename.replace("\\", "/")
+
+ if len(filename) > 60:
+ # Truncate the file path in a nice way.
+ filename = filename[-57:]
+ pos = filename.find("/")
+ if pos > 0:
+ filename = filename[pos:]
+ filename = "..." + filename
+
+ print("%-60s %s" % (filename, status))
+
+
+updatect = 0
+
+
+def read_config():
+ style_cfg = os.path.join(root_dir, ".style.cfg")
+ if os.path.exists(style_cfg):
+ config = eval_file(style_cfg)
+ if 'ignore_directories' in config:
+ global IGNORE_DIRECTORIES
+ IGNORE_DIRECTORIES = config['ignore_directories']
+
+
+def update_file(filename):
+ oldcontents = read_file(filename)
+ if len(oldcontents) == 0:
+ msg(filename, "empty")
+ return
+
+ if os.path.splitext(filename)[1] == ".py":
+ # Format Python files using YAPF.
+ newcontents = yapf_format(filename, oldcontents)
+ else:
+ # Format C/C++/ObjC/Java files using clang-format.
+ newcontents = clang_format(filename, oldcontents)
+
+ if newcontents is None:
+ raise Exception("Failed to process %s" % filename)
+
+ if newcontents != oldcontents:
+ msg(filename, "fixed")
+ global updatect
+ updatect += 1
+ write_file(filename, newcontents)
+ else:
+ msg(filename, "ok")
+ return
+
+
+def fix_style(filenames, white_list=None, black_list=None):
+ """ Execute clang-format with the specified arguments. """
+ if not white_list:
+ white_list = DEFAULT_LINT_WHITELIST_REGEX
+ white_regex = re.compile(white_list)
+ if not black_list:
+ black_list = DEFAULT_LINT_BLACKLIST_REGEX
+ black_regex = re.compile(black_list)
+
+ for filename in filenames:
+ # Ignore files from specific directories.
+ ignore = False
+ for dir_part in filename.split(os.sep):
+ if dir_part in IGNORE_DIRECTORIES:
+ msg(filename, "ignored")
+ ignore = True
+ break
+ if ignore:
+ continue
+
+ if filename.find('*') > 0:
+ # Expand wildcards.
+ filenames.extend(get_files(filename))
+ continue
+
+ if os.path.isdir(filename):
+ # Add directory contents.
+ filenames.extend(get_files(os.path.join(filename, "*")))
+ continue
+
+ if not os.path.exists(filename):
+ files = get_changed_files(".", filename)
+ if len(files) > 0:
+ filenames.extend(files)
+ else:
+ msg(filename, "missing")
+ continue
+
+ if white_regex.match(filename):
+ if black_regex.match(filename):
+ msg(filename, "ignored")
+ else:
+ update_file(filename)
+ else:
+ msg(filename, "skipped")
+
+
+if __name__ == "__main__":
+ if len(sys.argv) == 1:
+ print("Usage: %s [file-path|git-hash|unstaged|staged] ...\n" % sys.argv[0])
+ print(" Format C, C++ and ObjC files using Chromium's clang-format style.")
+ print("\nOptions:")
+ print(" file-path\tProcess the specified file or directory.")
+ print(" \t\tDirectories will be processed recursively.")
+ print(" \t\tThe \"*\" wildcard character is supported.")
+ print(" git-hash\tProcess all files changed in the specified Git commit.")
+ print(" unstaged\tProcess all unstaged files in the Git repo.")
+ print(" staged\t\tProcess all staged files in the Git repo.")
+ sys.exit(1)
+
+ # Read the configuration file.
+ read_config()
+
+ # Process anything passed on the command-line.
+ fix_style(sys.argv[1:])
+ print('Done - Wrote %d files.' % updatect)
diff --git a/tools/fix_style.sh b/tools/fix_style.sh
new file mode 100755
index 00000000..042c01f2
--- /dev/null
+++ b/tools/fix_style.sh
@@ -0,0 +1,2 @@
+#!/bin/sh
+python3 tools/fix_style.py $@
diff --git a/tools/gclient_hook.py b/tools/gclient_hook.py
new file mode 100644
index 00000000..4b5a9bd7
--- /dev/null
+++ b/tools/gclient_hook.py
@@ -0,0 +1,148 @@
+# Copyright (c) 2011 The Chromium Embedded Framework Authors.
+# Portions copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+from __future__ import absolute_import
+from __future__ import print_function
+from file_util import make_dir, write_file
+from gclient_util import *
+from gn_args import GetAllPlatformConfigs, GetConfigFileContents
+import issue_1999
+import os
+import sys
+
+# The CEF directory is the parent directory of _this_ script.
+cef_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir))
+# The src directory is the parent directory of the CEF directory.
+src_dir = os.path.abspath(os.path.join(cef_dir, os.pardir))
+
+# Determine the platform.
+if sys.platform == 'win32':
+ platform = 'windows'
+elif sys.platform == 'darwin':
+ platform = 'mac'
+elif sys.platform.startswith('linux'):
+ platform = 'linux'
+else:
+ print('Unknown operating system platform')
+ sys.exit()
+
+print("\nGenerating CEF version header file...")
+cmd = [sys.executable, 'tools/make_version_header.py', 'include/cef_version.h']
+RunAction(cef_dir, cmd)
+
+print("\nPatching build configuration and source files for CEF...")
+cmd = [sys.executable, 'tools/patcher.py']
+RunAction(cef_dir, cmd)
+
+if platform == 'linux' and 'CEF_INSTALL_SYSROOT' in os.environ:
+ for arch in os.environ['CEF_INSTALL_SYSROOT'].split(','):
+ if len(arch) == 0:
+ continue
+ print("\nInstalling %s sysroot environment..." % arch)
+ cmd = [
+ sys.executable, 'build/linux/sysroot_scripts/install-sysroot.py',
+ '--arch', arch
+ ]
+ RunAction(src_dir, cmd)
+
+print("\nGenerating CEF project files...")
+
+gn_args = {}
+
+if platform == 'windows':
+ # Force use of the locally installed version of Visual Studio.
+ if not 'DEPOT_TOOLS_WIN_TOOLCHAIN' in os.environ:
+ os.environ['DEPOT_TOOLS_WIN_TOOLCHAIN'] = '0'
+
+ # By default GN+Ninja on Windows expects Visual Studio and Windows SDK to be
+ # installed on the local machine. To build when Visual Studio and/or SDK is
+ # extracted to a directory but not installed (e.g. via a custom toolchain) set
+ # the following environment variables:
+ #
+ # o Enable use of a custom toolchain on Windows.
+ #
+ # set WIN_CUSTOM_TOOLCHAIN=1
+ #
+ # o Used by tools/msvs_env.bat to configure the MSVS tools environment.
+ # Should be set to "none" because VC variables for CEF will be set via
+ # INCLUDE/LIB/PATH.
+ #
+ # set CEF_VCVARS=none
+ #
+ # o Used by the following scripts:
+ # (a) build/vs_toolchain.py SetEnvironmentAndGetRuntimeDllDirs when
+ # determining whether to copy VS runtime binaries to the output directory.
+ # If GYP_MSVS_OVERRIDE_PATH exists then binaries will not be copied and
+ # should instead be discoverable via the PATH env variable.
+ # (b) build/toolchain/win/setup_toolchain.py _LoadToolchainEnv when
+ # writing environment.* files that specify INCLUDE/LIB/PATH values. If
+ # vcvarsall.bat [1] exists then environment variables will be derived from
+ # there and the specified INCLUDE/LIB values will be ignored by Chromium
+ # (PATH is retained because it might contain required VS runtime libraries).
+ # If this file does not exist then the INCLUDE/LIB/PATH values are also
+ # required by Chromium.
+ # TODO(cef): Rename to VS_ROOT and VS_VERSION after Chromium cleans up GYP
+ # dependencies.
+ #
+ # set GYP_MSVS_OVERRIDE_PATH=<VS root directory>
+ # set GYP_MSVS_VERSION=<VS version>
+ #
+ # o Used to configure GN arguments in this script.
+ #
+ # set VS_CRT_ROOT=<VS CRT root directory>
+ # set SDK_ROOT=<Platform SDK root directory>
+ #
+ # o Used by various scripts as described above. These values are optional when
+ # vcvarsall.bat [1] exists.
+ #
+ # set INCLUDE=<VS include paths>
+ # set LIB=<VS library paths>
+ # set PATH=<VS executable paths>
+ #
+ # See tools/depot_tools/win_toolchain/package_from_installed.py for an example
+ # packaging script along with required directory contents and INCLUDE/LIB/PATH
+ # values.
+ #
+ # [1] The vcvarsall.bat script must exist in "%GYP_MSVS_OVERRIDE_PATH%\VC\" or
+ # "%GYP_MSVS_OVERRIDE_PATH%\VC\Auxiliary\Build\". If the Windows SDK is not
+ # installed (e.g. not discoverable via the Windows registry) then
+ # "%GYP_MSVS_OVERRIDE_PATH%\Common7\Tools\vsdevcmd\core\winsdk.bat" must be
+ # patched to support discovery via SDK_ROOT as described in
+ # https://github.com/chromiumembedded/cef/issues/2773#issuecomment-1465019898.
+ #
+ if bool(int(os.environ.get('WIN_CUSTOM_TOOLCHAIN', '0'))):
+ required_vars = [
+ 'CEF_VCVARS',
+ 'GYP_MSVS_OVERRIDE_PATH',
+ 'GYP_MSVS_VERSION',
+ 'VS_CRT_ROOT',
+ 'SDK_ROOT',
+ ]
+ for var in required_vars:
+ if not var in os.environ.keys():
+ raise Exception('%s environment variable must be set' % var)
+
+ # Windows custom toolchain requirements. See comments in gn_args.py.
+ gn_args['visual_studio_path'] = os.environ['GYP_MSVS_OVERRIDE_PATH']
+ gn_args['visual_studio_version'] = os.environ['GYP_MSVS_VERSION']
+ gn_args['visual_studio_runtime_dirs'] = os.environ['VS_CRT_ROOT']
+ gn_args['windows_sdk_path'] = os.environ['SDK_ROOT']
+
+configs = GetAllPlatformConfigs(gn_args)
+for dir, config in configs.items():
+ # Create out directories and write the args.gn file.
+ out_path = os.path.join(src_dir, 'out', dir)
+ make_dir(out_path, False)
+ args_gn_path = os.path.join(out_path, 'args.gn')
+ args_gn_contents = GetConfigFileContents(config)
+ write_file(args_gn_path, args_gn_contents)
+
+ # Generate the Ninja config.
+ cmd = ['gn', 'gen', os.path.join('out', dir)]
+ if 'GN_ARGUMENTS' in os.environ.keys():
+ cmd.extend(os.environ['GN_ARGUMENTS'].split(' '))
+ RunAction(src_dir, cmd)
+ if platform == 'windows':
+ issue_1999.apply(out_path)
diff --git a/tools/gclient_util.py b/tools/gclient_util.py
new file mode 100644
index 00000000..5a6da54e
--- /dev/null
+++ b/tools/gclient_util.py
@@ -0,0 +1,42 @@
+# Copyright (c) 2011 The Chromium Embedded Framework Authors.
+# Portions copyright (c) 2011 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+from __future__ import absolute_import
+from __future__ import print_function
+import os, sys
+
+try:
+ # depot_tools may already be in the import path.
+ import gclient_utils
+except ImportError as e:
+ # Search the PATH environment variable to find the depot_tools folder.
+ depot_tools = None
+ paths = os.environ.get('PATH').split(os.pathsep)
+ for path in paths:
+ if os.path.exists(os.path.join(path, 'gclient_utils.py')):
+ depot_tools = path
+ break
+
+ if depot_tools is None:
+ print('Error: could not find depot_tools in PATH.', file=sys.stderr)
+ sys.exit(2)
+
+ # Add depot_tools to import path.
+ sys.path.append(depot_tools)
+ import gclient_utils
+
+
+# Copied from gclient.py python code.
+def RunAction(dir, command):
+ """Runs the action."""
+ try:
+ gclient_utils.CheckCallAndFilter(
+ command, cwd=dir, always_show_header=True, print_stdout=True)
+ except gclient_utils.Error as e:
+ # Use a discrete exit status code of 2 to indicate that a hook action
+ # failed. Users of this script may wish to treat hook action failures
+ # differently from VC failures.
+ print('Error: %s' % str(e), file=sys.stderr)
+ sys.exit(2)
diff --git a/tools/git_util.py b/tools/git_util.py
new file mode 100644
index 00000000..886d8278
--- /dev/null
+++ b/tools/git_util.py
@@ -0,0 +1,172 @@
+# Copyright (c) 2014 The Chromium Embedded Framework Authors. All rights
+# reserved. Use of this source code is governed by a BSD-style license that
+# can be found in the LICENSE file
+
+from __future__ import absolute_import
+from exec_util import exec_cmd
+import os
+import sys
+
+if sys.platform == 'win32':
+ # Force use of the git version bundled with depot_tools.
+ git_exe = 'git.bat'
+else:
+ git_exe = 'git'
+
+
+def is_checkout(path):
+ """ Returns true if the path represents a git checkout. """
+ return os.path.exists(os.path.join(path, '.git'))
+
+
+def is_ancestor(path='.', commit1='HEAD', commit2='master'):
+ """ Returns whether |commit1| is an ancestor of |commit2|. """
+ cmd = "%s merge-base --is-ancestor %s %s" % (git_exe, commit1, commit2)
+ result = exec_cmd(cmd, path)
+ return result['ret'] == 0
+
+
+def get_hash(path='.', branch='HEAD'):
+ """ Returns the git hash for the specified branch/tag/hash. """
+ cmd = "%s rev-parse %s" % (git_exe, branch)
+ result = exec_cmd(cmd, path)
+ if result['out'] != '':
+ return result['out'].strip()
+ return 'Unknown'
+
+
+def get_branch_name(path='.', branch='HEAD'):
+ """ Returns the branch name for the specified branch/tag/hash. """
+ # Returns the branch name if not in detached HEAD state, else an empty string
+ # or "HEAD".
+ cmd = "%s rev-parse --abbrev-ref %s" % (git_exe, branch)
+ result = exec_cmd(cmd, path)
+ if result['out'] != '':
+ name = result['out'].strip()
+ if len(name) > 0 and name != 'HEAD':
+ return name
+
+ # Returns a value like "(HEAD, origin/3729, 3729)".
+ # Ubuntu 14.04 uses Git version 1.9.1 which does not support %D (which
+ # provides the same output but without the parentheses).
+ cmd = "%s log -n 1 --pretty=%%d %s" % (git_exe, branch)
+ result = exec_cmd(cmd, path)
+ if result['out'] != '':
+ return result['out'].strip()[1:-1].split(', ')[-1]
+ return 'Unknown'
+
+
+def get_url(path='.'):
+ """ Returns the origin url for the specified path. """
+ cmd = "%s config --get remote.origin.url" % git_exe
+ result = exec_cmd(cmd, path)
+ if result['out'] != '':
+ return result['out'].strip()
+ return 'Unknown'
+
+
+def get_commit_number(path='.', branch='HEAD'):
+ """ Returns the number of commits in the specified branch/tag/hash. """
+ cmd = "%s rev-list --count %s" % (git_exe, branch)
+ result = exec_cmd(cmd, path)
+ if result['out'] != '':
+ return result['out'].strip()
+ return '0'
+
+
+def get_changed_files(path, hash):
+ """ Retrieves the list of changed files. """
+ if hash == 'unstaged':
+ cmd = "%s diff --name-only" % git_exe
+ elif hash == 'staged':
+ cmd = "%s diff --name-only --cached" % git_exe
+ else:
+ cmd = "%s diff-tree --no-commit-id --name-only -r %s" % (git_exe, hash)
+ result = exec_cmd(cmd, path)
+ if result['out'] != '':
+ files = result['out']
+ if sys.platform == 'win32':
+ # Convert to Unix line endings.
+ files = files.replace('\r\n', '\n')
+ return files.strip().split("\n")
+ return []
+
+
+def get_branch_hashes(path='.', branch='HEAD', ref='origin/master'):
+ """ Returns an ordered list of hashes for commits that have been applied since
+ branching from ref. """
+ cmd = "%s cherry %s %s" % (git_exe, ref, branch)
+ result = exec_cmd(cmd, path)
+ if result['out'] != '':
+ hashes = result['out']
+ if sys.platform == 'win32':
+ # Convert to Unix line endings.
+ hashes = hashes.replace('\r\n', '\n')
+ # Remove the "+ " or "- " prefix.
+ return [line[2:] for line in hashes.strip().split('\n')]
+ return []
+
+
+def write_indented_output(output):
+ """ Apply a fixed amount of intent to lines before printing. """
+ if output == '':
+ return
+ for line in output.split('\n'):
+ line = line.strip()
+ if len(line) == 0:
+ continue
+ sys.stdout.write('\t%s\n' % line)
+
+
+def git_apply_patch_file(patch_path, patch_dir):
+ """ Apply |patch_path| to files in |patch_dir|. """
+ patch_name = os.path.basename(patch_path)
+ sys.stdout.write('\nApply %s in %s\n' % (patch_name, patch_dir))
+
+ if not os.path.isfile(patch_path):
+ sys.stdout.write('... patch file does not exist.\n')
+ return 'fail'
+
+ patch_string = open(patch_path, 'rb').read()
+ if sys.platform == 'win32':
+ # Convert the patch to Unix line endings. This is necessary to avoid
+ # whitespace errors with git apply.
+ patch_string = patch_string.replace(b'\r\n', b'\n')
+
+ # Git apply fails silently if not run relative to a respository root.
+ if not is_checkout(patch_dir):
+ sys.stdout.write('... patch directory is not a repository root.\n')
+ return 'fail'
+
+ config = '-p0 --ignore-whitespace'
+
+ # Output patch contents.
+ cmd = '%s apply %s --numstat' % (git_exe, config)
+ result = exec_cmd(cmd, patch_dir, patch_string)
+ write_indented_output(result['out'].replace('<stdin>', patch_name))
+
+ # Reverse check to see if the patch has already been applied.
+ cmd = '%s apply %s --reverse --check' % (git_exe, config)
+ result = exec_cmd(cmd, patch_dir, patch_string)
+ if result['err'].find('error:') < 0:
+ sys.stdout.write('... already applied (skipping).\n')
+ return 'skip'
+
+ # Normal check to see if the patch can be applied cleanly.
+ cmd = '%s apply %s --check' % (git_exe, config)
+ result = exec_cmd(cmd, patch_dir, patch_string)
+ if result['err'].find('error:') >= 0:
+ sys.stdout.write('... failed to apply:\n')
+ write_indented_output(result['err'].replace('<stdin>', patch_name))
+ return 'fail'
+
+ # Apply the patch file. This should always succeed because the previous
+ # command succeeded.
+ cmd = '%s apply %s' % (git_exe, config)
+ result = exec_cmd(cmd, patch_dir, patch_string)
+ if result['err'] == '':
+ sys.stdout.write('... successfully applied.\n')
+ else:
+ sys.stdout.write('... successfully applied (with warnings):\n')
+ write_indented_output(result['err'].replace('<stdin>', patch_name))
+ return 'apply'
diff --git a/tools/gn_args.py b/tools/gn_args.py
new file mode 100644
index 00000000..33d831d8
--- /dev/null
+++ b/tools/gn_args.py
@@ -0,0 +1,646 @@
+# Copyright 2016 The Chromium Embedded Framework Authors. Portions copyright
+# 2012 Google Inc. All rights reserved. Use of this source code is governed by
+# a BSD-style license that can be found in the LICENSE file.
+
+# This script determines the contents of the per-configuration `args.gn` files
+# that are used to build CEF/Chromium with GN. See comments in CEF's top-level
+# BUILD.gn file for general GN usage instructions.
+#
+# This script performs the following tasks:
+#
+# - Defines CEF's default and required arg values in cases where they differ
+# from Chromium's.
+# - Accepts user-defined arg values via the GN_DEFINES environment variable.
+# - Verifies that user-defined arg values do not conflict with CEF's
+# requirements.
+# - Generates multiple configurations by combining user-defined arg values with
+# CEF's default and required values.
+#
+# Before adding a new arg value in this script determine the following:
+#
+# - Chromium's default value. Default values are defined in the declare_args()
+# sections of *.gni files.
+# - Chromium's value requirements. Check for assert()s related to the value in
+# Chromium code.
+# - Whether a particular value is optional or required for CEF.
+# - Under what conditions a particular value is required for CEF (platform,
+# build type, CPU architecture, etc).
+#
+# If CEF can use Chromium's default value and has no additional validation
+# requirements then do nothing.
+#
+# If CEF can use Chromium's default value but would like to enforce additional
+# validation requirements then go to 3B.
+#
+# If CEF cannot or should not use Chromium's default value then choose one of
+# the following:
+#
+# 1. If CEF requires a different value either globally or based on the platform:
+# - Add an assert() for the value in CEF's top-level BUILD.gn file.
+# - Add the required value in GetRequiredArgs().
+# - Result: CEF's required value will be used. The user cannot override the
+# value via GN_DEFINES.
+#
+# 2. If CEF requires a different value based on the build type or CPU
+# architecture:
+# - Add an assert() for the value in CEF's top-level BUILD.gn file.
+# - Add the required value in GetConfigArgs().
+# - Result: CEF's required value will be used. The user cannot override the
+# value via GN_DEFINES.
+#
+# 3. If CEF recommends (but does not require) a different value either globally
+# or based on the platform:
+# A. Set the default value:
+# - Add the recommended value in GetRecommendedDefaultArgs().
+# - Result: CEF's recommended value will be used by default. The user can
+# override the value via GN_DEFINES.
+#
+# B. If CEF has additional validation requirements:
+# - Add the default Chromium value in GetChromiumDefaultArgs().
+# - Perform validation in ValidateArgs().
+# - Result: An AssertionError will be thrown if validation fails.
+
+from __future__ import absolute_import
+from __future__ import print_function
+import os
+import platform as python_platform
+import shlex
+import sys
+
+# The CEF directory is the parent directory of _this_ script.
+cef_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir))
+# The src directory is the parent directory of the CEF directory.
+src_dir = os.path.abspath(os.path.join(cef_dir, os.pardir))
+
+# Determine the platform.
+if sys.platform == 'win32':
+ platform = 'windows'
+ # Windows machines report 'ARM64' or 'AMD64'.
+ machine = 'arm64' if python_platform.machine() == 'ARM64' else 'amd64'
+elif sys.platform == 'darwin':
+ platform = 'mac'
+ # Mac machines report 'arm64' or 'x86_64'.
+ machine = 'arm64' if python_platform.machine() == 'arm64' else 'amd64'
+elif sys.platform.startswith('linux'):
+ platform = 'linux'
+else:
+ print('Unknown operating system platform')
+ sys.exit()
+
+
+def msg(msg):
+ print('NOTE: ' + msg)
+
+
+def NameValueListToDict(name_value_list):
+ """
+ Takes an array of strings of the form 'NAME=VALUE' and creates a dictionary
+ of the pairs. If a string is simply NAME, then the value in the dictionary
+ is set to True. If VALUE can be converted to a boolean or integer, it is.
+ """
+ result = {}
+ for item in name_value_list:
+ tokens = item.split('=', 1)
+ if len(tokens) == 2:
+ token_value = tokens[1]
+ if token_value.lower() == 'true':
+ token_value = True
+ elif token_value.lower() == 'false':
+ token_value = False
+ else:
+ # If we can make it an int, use that, otherwise, use the string.
+ try:
+ token_value = int(token_value)
+ except ValueError:
+ pass
+ # Set the variable to the supplied value.
+ result[tokens[0]] = token_value
+ else:
+ # No value supplied, treat it as a boolean and set it.
+ result[tokens[0]] = True
+ return result
+
+
+def ShlexEnv(env_name):
+ """
+ Split an environment variable using shell-like syntax.
+ """
+ flags = os.environ.get(env_name, [])
+ if flags:
+ flags = shlex.split(flags)
+ return flags
+
+
+def MergeDicts(*dict_args):
+ """
+ Given any number of dicts, shallow copy and merge into a new dict.
+ Precedence goes to key value pairs in latter dicts.
+ """
+ result = {}
+ for dictionary in dict_args:
+ result.update(dictionary)
+ return result
+
+
+def GetValueString(val):
+ """
+ Return the string representation of |val| expected by GN.
+ """
+ if isinstance(val, bool):
+ if val:
+ return 'true'
+ else:
+ return 'false'
+ elif isinstance(val, int):
+ return val
+ else:
+ return '"%s"' % val
+ return val
+
+
+def GetChromiumDefaultArgs():
+ """
+ Return default GN args. These must match the Chromium defaults.
+ Only args that may be retrieved via GetArgValue() need to be specified here.
+ """
+ # Search for these values in declare_args() sections of *.gni files to find
+ # the defaults.
+
+ defaults = {
+ 'dcheck_always_on': False,
+ 'is_asan': False,
+ 'is_debug': True,
+ 'is_official_build': False,
+ 'target_cpu': 'x64',
+ }
+
+ if platform == 'linux':
+ defaults['use_sysroot'] = True
+
+ if platform == 'windows':
+ defaults['is_win_fastlink'] = False
+ defaults['visual_studio_path'] = ''
+ defaults['visual_studio_version'] = ''
+ defaults['visual_studio_runtime_dirs'] = ''
+ defaults['windows_sdk_path'] = ''
+
+ return defaults
+
+
+def GetArgValue(args, key):
+ """
+ Return an existing GN arg value or the Chromium default.
+ """
+ defaults = GetChromiumDefaultArgs()
+ assert key in defaults, "No default Chromium value specified for %s" % key
+ return args.get(key, defaults[key])
+
+
+def GetRecommendedDefaultArgs():
+ """
+ Return recommended default GN args that differ from Chromium defaults.
+ """
+ # Search for these values in declare_args() sections of *.gni files to find
+ # the defaults.
+
+ result = {
+ # Enable NaCL. Default is true. False is recommended for faster builds.
+ 'enable_nacl': False,
+
+ # Disable component builds. Default depends on the platform. True results
+ # in faster local builds but False is required to create a CEF binary
+ # distribution.
+ 'is_component_build': False,
+
+ # Disable support for background apps, which don't make sense with CEF.
+ # Default is enabled on desktop platforms. This feature was also causing
+ # strange shutdown crashes when using the Chrome runtime with a Debug
+ # component build on Windows.
+ 'enable_background_mode': False,
+
+ # Disable support for resource allowlist generation. When enabled this
+ # introduces a Windows official build dependency on the
+ # "//chrome:chrome_dll" target, which will fail to build with CEF.
+ 'enable_resource_allowlist_generation': False,
+
+ # Disable V8 sandboxed pointers to avoid crashing when using
+ # CefV8Value::CreateArrayBuffer with memory allocated outside of the V8
+ # sandbox. See https://github.com/chromiumembedded/cef/issues/3332.
+ 'v8_enable_sandbox': False,
+ }
+
+ if platform == 'windows' or platform == 'mac':
+ # A browser specific value of at least 32 characters that will be used in
+ # the computation of the CDM storage ID.
+ result['alternate_cdm_storage_id_key'] = '968b476909da4373b08903c28e859454'
+
+ if platform != 'windows':
+ # Only allow non-component Debug builds on non-Windows platforms. These
+ # builds will fail on Windows due to linker issues (running out of memory,
+ # etc). See https://github.com/chromiumembedded/cef/issues/2679.
+ result['forbid_non_component_debug_builds'] = False
+
+ if platform == 'linux':
+ # Use a sysroot environment. Default is true. False is recommended for local
+ # builds.
+ # Run the following commands to download the sysroot environment:
+ # x86 build only: $ export GYP_DEFINES='target_arch=ia32'
+ # x86 or x64 build: $ gclient runhooks
+ result['use_sysroot'] = False
+
+ # Disable QT by default because we don't want to introduce the build
+ # dependencies at this time. For background see
+ # https://groups.google.com/a/chromium.org/g/chromium-packagers/c/-2VGexQAK6w/m/5K5ppK9WBAAJ
+ result['use_qt'] = False
+
+ if platform == 'mac':
+ # Disable the allocator shim. Default is True. See issue #3061.
+ result['use_allocator_shim'] = False
+
+ if platform == 'mac' or platform == 'linux':
+ # Use the system allocator instead of PartitionAlloc. Default is True with
+ # the allocator shim enabled. See issues #3061 and #3095.
+ result['use_partition_alloc_as_malloc'] = False
+
+ # These require use_partition_alloc_as_malloc=true, so disable them.
+ result['enable_backup_ref_ptr_support'] = False
+ result['enable_mte_checked_ptr_support'] = False
+
+ return result
+
+
+def GetGNEnvArgs():
+ """
+ Return GN args specified via the GN_DEFINES env variable.
+ """
+ return NameValueListToDict(ShlexEnv('GN_DEFINES'))
+
+
+def GetRequiredArgs():
+ """
+ Return required GN args. Also enforced by assert() in //cef/BUILD.gn.
+ """
+ result = {
+ # Set ENABLE_PRINTING=1 ENABLE_BASIC_PRINTING=1.
+ 'enable_basic_printing': True,
+ # ENABLE_SERVICE_DISCOVERY=0 for print preview support
+ 'enable_print_preview': True,
+ 'optimize_webui': True,
+ # Enable support for Widevine CDM.
+ 'enable_widevine': True,
+
+ # Don't use the chrome style plugin.
+ 'clang_use_chrome_plugins': False,
+ }
+
+ if platform == 'windows' or platform == 'mac':
+ # Enable Widevine CDM host verification and storage ID.
+ result['enable_cdm_host_verification'] = True
+ result['enable_cdm_storage_id'] = True
+
+ # Enable use of the RLZ library as required by CDM storage ID.
+ result['enable_rlz'] = True
+
+ if platform == 'linux':
+ # Don't generate Chromium installer packages. This avoids GN dependency
+ # errors with CEF (see issue #2301).
+ # Due to the way this variable is declared in chrome/installer/BUILD.gn it
+ # can't be enforced by assert().
+ result['enable_linux_installer'] = False
+
+ return result
+
+
+def GetMergedArgs(build_args):
+ """
+ Return merged GN args.
+ """
+ dict = MergeDicts(GetRecommendedDefaultArgs(), GetGNEnvArgs(), build_args)
+
+ # Verify that the user is not trying to override required args.
+ required = GetRequiredArgs()
+ for key in required.keys():
+ if key in dict:
+ assert dict[key] == required[key], \
+ "%s=%s is required" % (key, GetValueString(required[key]))
+
+ return MergeDicts(dict, required)
+
+
+def ValidateArgs(args):
+ """
+ Validate GN arg combinations that we know about. Also provide suggestions
+ where appropriate.
+ """
+ dcheck_always_on = GetArgValue(args, 'dcheck_always_on')
+ is_asan = GetArgValue(args, 'is_asan')
+ is_debug = GetArgValue(args, 'is_debug')
+ is_official_build = GetArgValue(args, 'is_official_build')
+ target_cpu = GetArgValue(args, 'target_cpu')
+
+ if platform == 'linux':
+ use_sysroot = GetArgValue(args, 'use_sysroot')
+
+ if platform == 'windows':
+ is_win_fastlink = GetArgValue(args, 'is_win_fastlink')
+ visual_studio_path = GetArgValue(args, 'visual_studio_path')
+ visual_studio_version = GetArgValue(args, 'visual_studio_version')
+ visual_studio_runtime_dirs = GetArgValue(args, 'visual_studio_runtime_dirs')
+ windows_sdk_path = GetArgValue(args, 'windows_sdk_path')
+
+ # Target CPU architecture.
+ # - Windows supports "x86", "x64" and "arm64".
+ # - Mac supports "x64" and "arm64".
+ # - Linux supports only "x64" unless using a sysroot environment.
+ if platform == 'mac':
+ assert target_cpu in ('x64', 'arm64'), 'target_cpu must be "x64" or "arm64"'
+ elif platform == 'windows':
+ assert target_cpu in ('x86', 'x64',
+ 'arm64'), 'target_cpu must be "x86", "x64" or "arm64"'
+ elif platform == 'linux':
+ assert target_cpu in (
+ 'x86', 'x64', 'arm',
+ 'arm64'), 'target_cpu must be "x86", "x64", "arm" or "arm64"'
+
+ if platform == 'linux':
+ if target_cpu == 'x86':
+ assert use_sysroot, 'target_cpu="x86" requires use_sysroot=true'
+ elif target_cpu == 'arm':
+ assert use_sysroot, 'target_cpu="arm" requires use_sysroot=true'
+ elif target_cpu == 'arm64':
+ assert use_sysroot, 'target_cpu="arm64" requires use_sysroot=true'
+
+ # ASAN requires Release builds.
+ if is_asan:
+ assert not is_debug, "is_asan=true requires is_debug=false"
+ if not dcheck_always_on:
+ msg('is_asan=true recommends dcheck_always_on=true')
+
+ # Official build requires Release builds.
+ if is_official_build:
+ assert not is_debug, "is_official_build=true requires is_debug=false"
+
+ if platform == 'windows':
+ # Official builds should not use /DEBUG:FASTLINK.
+ if is_official_build:
+ assert not is_win_fastlink, "is_official_build=true precludes is_win_fastlink=true"
+
+ # Windows custom toolchain requirements.
+ #
+ # Required GN arguments:
+ # visual_studio_path="<path to VS root>"
+ # The directory that contains Visual Studio. For example, a subset of
+ # "C:\Program Files (x86)\Microsoft Visual Studio 14.0".
+ # visual_studio_version="<VS version>"
+ # The VS version. For example, "2015".
+ # visual_studio_runtime_dirs="<path to VS CRT>"
+ # The directory that contains the VS CRT. For example, the contents of
+ # "C:\Program Files (x86)\Windows Kits\10\Redist\ucrt\DLLs\x64" plus
+ # "C:\Windows\System32\ucrtbased.dll"
+ # windows_sdk_path="<path to WinSDK>"
+ # The directory that contains the Win SDK. For example, a subset of
+ # "C:\Program Files (x86)\Windows Kits\10".
+ #
+ # Required environment variables:
+ # DEPOT_TOOLS_WIN_TOOLCHAIN=0
+ # GYP_MSVS_OVERRIDE_PATH=<path to VS root, must match visual_studio_path>
+ # GYP_MSVS_VERSION=<VS version, must match visual_studio_version>
+ # CEF_VCVARS=none
+ #
+ # Optional environment variables (required if vcvarsall.bat does not exist):
+ # INCLUDE=<VS include paths>
+ # LIB=<VS library paths>
+ # PATH=<VS executable paths>
+ #
+ # See comments in gclient_hook.py for environment variable usage.
+ #
+ if visual_studio_path != '':
+ assert visual_studio_version != '', 'visual_studio_path requires visual_studio_version'
+ assert visual_studio_runtime_dirs != '', 'visual_studio_path requires visual_studio_runtime_dirs'
+ assert windows_sdk_path != '', 'visual_studio_path requires windows_sdk_path'
+
+ assert os.environ.get('DEPOT_TOOLS_WIN_TOOLCHAIN', '') == '0', \
+ "visual_studio_path requires DEPOT_TOOLS_WIN_TOOLCHAIN=0 env variable"
+
+ msvs_path = os.environ.get('GYP_MSVS_OVERRIDE_PATH', '')
+ assert msvs_path == visual_studio_path and os.path.exists(msvs_path), \
+ "visual_studio_path requires matching GYP_MSVS_OVERRIDE_PATH env variable"
+
+ msvs_version = os.environ.get('GYP_MSVS_VERSION', '')
+ assert msvs_version == visual_studio_version, \
+ "visual_studio_version requires matching GYP_MSVS_VERSION env variable"
+
+ assert os.environ.get('CEF_VCVARS', '') == 'none', \
+ "visual_studio_path requires CEF_VCVARS=none env variable"
+
+ # If vcvarsall.bat exists then environment variables will be derived from
+ # there and any specified INCLUDE/LIB values will be ignored by Chromium
+ # (PATH is retained because it might contain required VS runtime
+ # libraries). If this file does not exist then the INCLUDE/LIB/PATH values
+ # are also required by Chromium.
+ vcvars_path = os.path.join(msvs_path, 'VC', 'vcvarsall.bat')
+ if not os.path.exists(vcvars_path):
+ vcvars_path = os.path.join(msvs_path, 'VC', 'Auxiliary', 'Build',
+ 'vcvarsall.bat')
+ if os.path.exists(vcvars_path):
+ if 'INCLUDE' in os.environ:
+ del os.environ['INCLUDE']
+ if 'LIB' in os.environ:
+ del os.environ['LIB']
+ if 'LIBPATH' in os.environ:
+ del os.environ['LIBPATH']
+ else:
+ assert 'INCLUDE' in os.environ \
+ and 'LIB' in os.environ \
+ and 'PATH' in os.environ, \
+ "visual_studio_path requires INCLUDE, LIB and PATH env variables"
+
+
+def GetConfigArgs(args, is_debug, cpu):
+ """
+ Return merged GN args for the configuration and validate.
+ """
+ add_args = {}
+
+ # Cannot create is_official_build=true is_debug=true builds.
+ # This restriction is enforced in //build/config/BUILDCONFIG.gn.
+ # Instead, our "official Debug" build is a Release build with dchecks and
+ # symbols. Symbols will be generated by default for official builds; see the
+ # definition of 'symbol_level' in //build/config/compiler/compiler.gni.
+ if is_debug and GetArgValue(args, 'is_official_build'):
+ is_debug = False
+ add_args['dcheck_always_on'] = True
+
+ result = MergeDicts(args, add_args, {
+ 'is_debug': is_debug,
+ 'target_cpu': cpu,
+ })
+
+ if platform == 'linux' and not cpu.startswith('arm'):
+ # Remove any arm-related values from non-arm configs.
+ for key in result.keys():
+ if key.startswith('arm_'):
+ del result[key]
+
+ ValidateArgs(result)
+ return result
+
+
+def GetConfigArgsSandbox(platform, args, is_debug, cpu):
+ """
+ Return merged GN args for the cef_sandbox configuration and validate.
+ """
+ add_args = {
+ # Avoid libucrt.lib linker errors.
+ 'use_allocator_shim': False,
+
+ # PartitionAlloc is selected as the default allocator in some cases.
+ # We can't use it because it requires use_allocator_shim=true.
+ 'use_partition_alloc_as_malloc': False,
+ 'use_partition_alloc': False,
+
+ # These require use_partition_alloc_as_malloc=true, so disable them.
+ 'enable_backup_ref_ptr_support': False,
+ 'enable_mte_checked_ptr_support': False,
+
+ # Avoid /LTCG linker warnings and generate smaller lib files.
+ 'is_official_build': False,
+
+ # Enable base target customizations necessary for distribution of the
+ # cef_sandbox static library.
+ 'is_cef_sandbox_build': True,
+ }
+
+ if platform == 'windows':
+ # Avoid Debug build linker errors caused by custom libc++.
+ add_args['use_custom_libcxx'] = False
+
+ # Avoid dependency on //third_party/perfetto:libperfetto which fails to
+ # build with MSVC libc++.
+ add_args['enable_base_tracing'] = False
+
+ # Allow non-component Debug builds for the sandbox.
+ add_args['forbid_non_component_debug_builds'] = False
+
+ if not is_debug:
+ # Disable DCHECKs in Release builds.
+ add_args['dcheck_always_on'] = False
+
+ result = MergeDicts(args, add_args, {
+ 'is_debug': is_debug,
+ 'target_cpu': cpu,
+ })
+
+ ValidateArgs(result)
+ return result
+
+
+def LinuxSysrootExists(cpu):
+ """
+ Returns true if the sysroot for the specified |cpu| architecture exists.
+ """
+ # Directory that contains sysroots.
+ sysroot_root = os.path.join(src_dir, 'build', 'linux')
+ # CPU-specific sysroot directory names.
+ # Should match the values in build/config/sysroot.gni.
+ release = 'bullseye'
+ if cpu == 'x64':
+ sysroot_name = 'debian_%s_amd64-sysroot' % release
+ elif cpu == 'arm':
+ sysroot_name = 'debian_%s_arm-sysroot' % release
+ elif cpu == 'arm64':
+ sysroot_name = 'debian_%s_arm64-sysroot' % release
+ else:
+ raise Exception('Unrecognized sysroot CPU: %s' % cpu)
+
+ return os.path.isdir(os.path.join(sysroot_root, sysroot_name))
+
+
+def GetAllPlatformConfigs(build_args):
+ """
+ Return a map of directory name to GN args for the current platform.
+ """
+ result = {}
+
+ # Merged args without validation.
+ args = GetMergedArgs(build_args)
+
+ create_debug = True
+
+ # Don't create debug directories for asan builds.
+ if GetArgValue(args, 'is_asan'):
+ create_debug = False
+ msg('Not generating Debug configuration due to is_asan=true')
+
+ supported_cpus = []
+
+ if platform == 'linux':
+ use_sysroot = GetArgValue(args, 'use_sysroot')
+ if use_sysroot:
+ # Only generate configurations for sysroots that have been installed.
+ for cpu in ('x64', 'arm', 'arm64'):
+ if LinuxSysrootExists(cpu):
+ supported_cpus.append(cpu)
+ else:
+ msg('Not generating %s configuration due to missing sysroot directory'
+ % cpu)
+ else:
+ supported_cpus = ['x64']
+ elif platform in ('windows', 'mac'):
+ if machine == 'amd64' or os.environ.get('CEF_ENABLE_AMD64', '') == '1':
+ supported_cpus.append('x64')
+ if platform == 'windows':
+ supported_cpus.append('x86')
+ if machine == 'arm64' or os.environ.get('CEF_ENABLE_ARM64', '') == '1':
+ supported_cpus.append('arm64')
+ else:
+ raise Exception('Unsupported platform')
+
+ if len(supported_cpus) == 0:
+ raise Exception('No supported architectures')
+
+ for cpu in supported_cpus:
+ if create_debug:
+ result['Debug_GN_' + cpu] = GetConfigArgs(args, True, cpu)
+ result['Release_GN_' + cpu] = GetConfigArgs(args, False, cpu)
+
+ if platform in ('windows', 'mac') and GetArgValue(args,
+ 'is_official_build'):
+ # Build cef_sandbox.lib with a different configuration.
+ if create_debug:
+ result['Debug_GN_' + cpu + '_sandbox'] = GetConfigArgsSandbox(
+ platform, args, True, cpu)
+ result['Release_GN_' + cpu + '_sandbox'] = GetConfigArgsSandbox(
+ platform, args, False, cpu)
+
+ return result
+
+
+def GetConfigFileContents(args):
+ """
+ Generate config file contents for the arguments.
+ """
+ pairs = []
+ for k in sorted(args.keys()):
+ pairs.append("%s=%s" % (k, GetValueString(args[k])))
+ return "\n".join(pairs)
+
+
+# Program entry point.
+if __name__ == '__main__':
+ import sys
+
+ # Allow override of the platform via the command-line for testing.
+ if len(sys.argv) > 1:
+ platform = sys.argv[1]
+ if not platform in ('linux', 'mac', 'windows'):
+ sys.stderr.write('Usage: %s <platform>\n' % sys.argv[0])
+ sys.exit()
+
+ print('Platform: %s' % platform)
+
+ # Dump the configuration based on platform and environment.
+ configs = GetAllPlatformConfigs({})
+ for dir, config in configs.items():
+ print('\n\nout/%s:\n' % dir)
+ print(GetConfigFileContents(config))
diff --git a/tools/gypi_to_gn.py b/tools/gypi_to_gn.py
new file mode 100644
index 00000000..3782535a
--- /dev/null
+++ b/tools/gypi_to_gn.py
@@ -0,0 +1,206 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+# Deleted from Chromium in https://crrev.com/097f64c631.
+
+"""Converts a given gypi file to a python scope and writes the result to stdout.
+
+USING THIS SCRIPT IN CHROMIUM
+
+Forking Python to run this script in the middle of GN is slow, especially on
+Windows, and it makes both the GYP and GN files harder to follow. You can't
+use "git grep" to find files in the GN build any more, and tracking everything
+in GYP down requires a level of indirection. Any calls will have to be removed
+and cleaned up once the GYP-to-GN transition is complete.
+
+As a result, we only use this script when the list of files is large and
+frequently-changing. In these cases, having one canonical list outweights the
+downsides.
+
+As of this writing, the GN build is basically complete. It's likely that all
+large and frequently changing targets where this is appropriate use this
+mechanism already. And since we hope to turn down the GYP build soon, the time
+horizon is also relatively short. As a result, it is likely that no additional
+uses of this script should every be added to the build. During this later part
+of the transition period, we should be focusing more and more on the absolute
+readability of the GN build.
+
+
+HOW TO USE
+
+It is assumed that the file contains a toplevel dictionary, and this script
+will return that dictionary as a GN "scope" (see example below). This script
+does not know anything about GYP and it will not expand variables or execute
+conditions.
+
+It will strip conditions blocks.
+
+A variables block at the top level will be flattened so that the variables
+appear in the root dictionary. This way they can be returned to the GN code.
+
+Say your_file.gypi looked like this:
+ {
+ 'sources': [ 'a.cc', 'b.cc' ],
+ 'defines': [ 'ENABLE_DOOM_MELON' ],
+ }
+
+You would call it like this:
+ gypi_values = exec_script("//build/gypi_to_gn.py",
+ [ rebase_path("your_file.gypi") ],
+ "scope",
+ [ "your_file.gypi" ])
+
+Notes:
+ - The rebase_path call converts the gypi file from being relative to the
+ current build file to being system absolute for calling the script, which
+ will have a different current directory than this file.
+
+ - The "scope" parameter tells GN to interpret the result as a series of GN
+ variable assignments.
+
+ - The last file argument to exec_script tells GN that the given file is a
+ dependency of the build so Ninja can automatically re-run GN if the file
+ changes.
+
+Read the values into a target like this:
+ component("mycomponent") {
+ sources = gypi_values.sources
+ defines = gypi_values.defines
+ }
+
+Sometimes your .gypi file will include paths relative to a different
+directory than the current .gn file. In this case, you can rebase them to
+be relative to the current directory.
+ sources = rebase_path(gypi_values.sources, ".",
+ "//path/gypi/input/values/are/relative/to")
+
+This script will tolerate a 'variables' in the toplevel dictionary or not. If
+the toplevel dictionary just contains one item called 'variables', it will be
+collapsed away and the result will be the contents of that dictinoary. Some
+.gypi files are written with or without this, depending on how they expect to
+be embedded into a .gyp file.
+
+This script also has the ability to replace certain substrings in the input.
+Generally this is used to emulate GYP variable expansion. If you passed the
+argument "--replace=<(foo)=bar" then all instances of "<(foo)" in strings in
+the input will be replaced with "bar":
+
+ gypi_values = exec_script("//build/gypi_to_gn.py",
+ [ rebase_path("your_file.gypi"),
+ "--replace=<(foo)=bar"],
+ "scope",
+ [ "your_file.gypi" ])
+
+"""
+
+from __future__ import absolute_import
+from __future__ import print_function
+from optparse import OptionParser
+import os
+import sys
+
+try:
+ # May already be in the import path.
+ import gn_helpers
+except ImportError as e:
+ # Add src/build to import path.
+ cef_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir))
+ src_dir = os.path.abspath(os.path.join(cef_dir, os.pardir))
+ sys.path.append(os.path.join(src_dir, 'build'))
+ import gn_helpers
+
+
+def LoadPythonDictionary(path):
+ file_string = open(path).read()
+ try:
+ file_data = eval(file_string, {'__builtins__': None}, None)
+ except SyntaxError as e:
+ e.filename = path
+ raise
+ except Exception as e:
+ raise Exception("Unexpected error while reading %s: %s" % (path, str(e)))
+
+ assert isinstance(file_data, dict), "%s does not eval to a dictionary" % path
+
+ # Flatten any variables to the top level.
+ if 'variables' in file_data:
+ file_data.update(file_data['variables'])
+ del file_data['variables']
+
+ # Strip all elements that this script can't process.
+ elements_to_strip = [
+ 'conditions',
+ 'target_conditions',
+ 'target_defaults',
+ 'targets',
+ 'includes',
+ 'actions',
+ ]
+ for element in elements_to_strip:
+ if element in file_data:
+ del file_data[element]
+
+ return file_data
+
+
+def ReplaceSubstrings(values, search_for, replace_with):
+ """Recursively replaces substrings in a value.
+
+ Replaces all substrings of the "search_for" with "repace_with" for all
+ strings occurring in "values". This is done by recursively iterating into
+ lists as well as the keys and values of dictionaries."""
+ if isinstance(values, str):
+ return values.replace(search_for, replace_with)
+
+ if isinstance(values, list):
+ return [ReplaceSubstrings(v, search_for, replace_with) for v in values]
+
+ if isinstance(values, dict):
+ # For dictionaries, do the search for both the key and values.
+ result = {}
+ for key, value in values.items():
+ new_key = ReplaceSubstrings(key, search_for, replace_with)
+ new_value = ReplaceSubstrings(value, search_for, replace_with)
+ result[new_key] = new_value
+ return result
+
+ # Assume everything else is unchanged.
+ return values
+
+def main():
+ parser = OptionParser()
+ parser.add_option("-r", "--replace", action="append",
+ help="Replaces substrings. If passed a=b, replaces all substrs a with b.")
+ (options, args) = parser.parse_args()
+
+ if len(args) != 1:
+ raise Exception("Need one argument which is the .gypi file to read.")
+
+ data = LoadPythonDictionary(args[0])
+ if options.replace:
+ # Do replacements for all specified patterns.
+ for replace in options.replace:
+ split = replace.split('=')
+ # Allow "foo=" to replace with nothing.
+ if len(split) == 1:
+ split.append('')
+ assert len(split) == 2, "Replacement must be of the form 'key=value'."
+ data = ReplaceSubstrings(data, split[0], split[1])
+
+ # Sometimes .gypi files use the GYP syntax with percents at the end of the
+ # variable name (to indicate not to overwrite a previously-defined value):
+ # 'foo%': 'bar',
+ # Convert these to regular variables.
+ for key in data:
+ if len(key) > 1 and key[len(key) - 1] == '%':
+ data[key[:-1]] = data[key]
+ del data[key]
+
+ print(gn_helpers.ToGNString(data))
+
+if __name__ == '__main__':
+ try:
+ main()
+ except Exception as e:
+ print(str(e))
+ sys.exit(1)
diff --git a/tools/issue_1999.py b/tools/issue_1999.py
new file mode 100644
index 00000000..c44a135c
--- /dev/null
+++ b/tools/issue_1999.py
@@ -0,0 +1,107 @@
+# Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights
+# reserved. Use of this source code is governed by a BSD-style license that
+# can be found in the LICENSE file.
+#
+# Resort order of object files in libcef.ninja file.
+#
+# See: https://github.com/chromiumembedded/cef/issues/1999
+#
+# Usage:
+# import issue_1999
+# issue_1999.apply(output_path)
+#
+from __future__ import absolute_import
+from __future__ import print_function
+from io import open
+import sys
+import os
+
+module_order = [
+ "_sse",
+ "-sse",
+ "_ssse",
+ "-ssse",
+ "_sse2",
+ "-sse2",
+ "_ssse2",
+ "-ssse2",
+ "_sse3",
+ "-sse3",
+ "_ssse3",
+ "-ssse3",
+ "_sse4",
+ "-sse4",
+ "_ssse4",
+ "-ssse4",
+ "_avx",
+ "-avx",
+ "_savx",
+ "-savx",
+ "_avx1",
+ "-avx1",
+ "_savx1",
+ "-savx1",
+ "_avx2",
+ "-avx2",
+ "_savx2",
+ "-savx2",
+]
+
+
+def get_obj_class(item):
+ item = item.lower()
+ for i in range(len(module_order) - 1, -1, -1):
+ x = module_order[i]
+ if x in item:
+ return 1 + i
+ return 0
+
+
+def obj_compare(x, y):
+ xc = get_obj_class(x)
+ yc = get_obj_class(y)
+ if xc < yc:
+ return -1
+ elif xc > yc:
+ return 1
+ else:
+ return 0
+
+
+def process_line(line):
+ if line.startswith("build ./libcef.dll ./libcef.dll.lib: solink "):
+ index = line.find("solink")
+ if index >= 0:
+ part1 = line[0:index + 6]
+ part2 = line[index + 6:]
+ stampsIndex = part2.find("||")
+ stamps = part2[stampsIndex:]
+ objects = part2[:stampsIndex]
+
+ objects_list = objects.split()
+ objects_list = sorted(objects_list, cmp=obj_compare)
+ return part1 + " " + " ".join(objects_list) + " " + stamps
+ return line
+
+
+def process_file(path):
+ print("Applying issue #1999 fix to " + path)
+
+ with open(path, 'r', encoding='utf-8') as f:
+ content = f.read().splitlines()
+
+ result = []
+
+ for line in content:
+ result.append(process_line(line))
+
+ with open(path, 'w', encoding='utf-8') as fp:
+ str = "\n".join(result) + "\n"
+ if sys.version_info.major == 2:
+ fp.write(str.decode('utf-8'))
+ else:
+ fp.write(str)
+
+
+def apply(confpath):
+ process_file(os.path.join(confpath, "obj", "cef", "libcef.ninja"))
diff --git a/tools/make_api_hash_header.py b/tools/make_api_hash_header.py
new file mode 100644
index 00000000..6c79efcd
--- /dev/null
+++ b/tools/make_api_hash_header.py
@@ -0,0 +1,95 @@
+# Copyright (c) 2019 The Chromium Embedded Framework Authors. All rights
+# reserved. Use of this source code is governed by a BSD-style license that
+# can be found in the LICENSE file.
+
+from __future__ import absolute_import
+from cef_api_hash import cef_api_hash
+from cef_parser import get_copyright
+from file_util import *
+import os
+import sys
+
+
+def make_api_hash_header(cpp_header_dir):
+ # calculate api hashes
+ api_hash_calculator = cef_api_hash(cpp_header_dir, verbose=False)
+ api_hash = api_hash_calculator.calculate()
+
+ result = get_copyright(full=True, translator=False) + \
+"""//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the make_api_hash_header.py tool.
+//
+
+#ifndef CEF_INCLUDE_API_HASH_H_
+#define CEF_INCLUDE_API_HASH_H_
+
+#include "include/internal/cef_export.h"
+
+// The API hash is created by analyzing CEF header files for C API type
+// definitions. The hash value will change when header files are modified in a
+// way that may cause binary incompatibility with other builds. The universal
+// hash value will change if any platform is affected whereas the platform hash
+// values will change only if that particular platform is affected.
+#define CEF_API_HASH_UNIVERSAL "$UNIVERSAL$"
+#if defined(OS_WIN)
+#define CEF_API_HASH_PLATFORM "$WINDOWS$"
+#elif defined(OS_MAC)
+#define CEF_API_HASH_PLATFORM "$MAC$"
+#elif defined(OS_LINUX)
+#define CEF_API_HASH_PLATFORM "$LINUX$"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///
+// Returns CEF API hashes for the libcef library. The returned string is owned
+// by the library and should not be freed. The |entry| parameter describes which
+// hash value will be returned:
+// 0 - CEF_API_HASH_PLATFORM
+// 1 - CEF_API_HASH_UNIVERSAL
+// 2 - CEF_COMMIT_HASH (from cef_version.h)
+///
+CEF_EXPORT const char* cef_api_hash(int entry);
+
+#ifdef __cplusplus
+}
+#endif
+#endif // CEF_INCLUDE_API_HASH_H_
+"""
+
+ # Substitute hash values for placeholders.
+ for platform, value in api_hash.items():
+ result = result.replace('$%s$' % platform.upper(), value)
+
+ return result
+
+
+def write_api_hash_header(output, cpp_header_dir):
+ output = os.path.abspath(output)
+ result = make_api_hash_header(cpp_header_dir)
+ ret = write_file_if_changed(output, result)
+
+ # Also write to |cpp_header_dir| if a different path from |output|, since we
+ # need to commit the hash header for cef_version.py to correctly calculate the
+ # version number based on git history.
+ header_path = os.path.abspath(
+ os.path.join(cpp_header_dir, os.path.basename(output)))
+ if (output != header_path):
+ write_file_if_changed(header_path, result)
+
+ return ret
+
+
+def main(argv):
+ if len(argv) < 3:
+ print(("Usage:\n %s <output_filename> <cpp_header_dir>" % argv[0]))
+ sys.exit(-1)
+ write_api_hash_header(argv[1], argv[2])
+
+
+if '__main__' == __name__:
+ main(sys.argv)
diff --git a/tools/make_capi_header.py b/tools/make_capi_header.py
new file mode 100644
index 00000000..6f11286d
--- /dev/null
+++ b/tools/make_capi_header.py
@@ -0,0 +1,227 @@
+# Copyright (c) 2011 The Chromium Embedded Framework Authors. All rights
+# reserved. Use of this source code is governed by a BSD-style license that
+# can be found in the LICENSE file.
+
+from __future__ import absolute_import
+from cef_parser import *
+from date_util import *
+
+
+def make_capi_global_funcs(funcs, defined_names, translate_map, indent):
+ result = ''
+ first = True
+ for func in funcs:
+ comment = func.get_comment()
+ if first or len(comment) > 0:
+ result += '\n' + format_comment(comment, indent, translate_map)
+ if func.get_retval().get_type().is_result_string():
+ result += indent + '// The resulting string must be freed by calling cef_string_userfree_free().\n'
+ result += indent + 'CEF_EXPORT ' + func.get_capi_proto(defined_names) + ';\n'
+ if first:
+ first = False
+ return result
+
+
+def make_capi_member_funcs(funcs, defined_names, translate_map, indent):
+ result = ''
+ first = True
+ for func in funcs:
+ comment = func.get_comment()
+ if first or len(comment) > 0:
+ result += '\n' + format_comment(comment, indent, translate_map)
+ if func.get_retval().get_type().is_result_string():
+ result += indent + '// The resulting string must be freed by calling cef_string_userfree_free().\n'
+ parts = func.get_capi_parts()
+ result += indent+parts['retval']+' (CEF_CALLBACK *'+parts['name']+ \
+ ')('+', '.join(parts['args'])+');\n'
+ if first:
+ first = False
+ return result
+
+
+def make_capi_header(header, filename):
+ # structure names that have already been defined
+ defined_names = header.get_defined_structs()
+
+ # map of strings that will be changed in C++ comments
+ translate_map = header.get_capi_translations()
+
+ # header string
+ result = \
+"""// Copyright (c) $YEAR$ Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the CEF translator tool and should not edited
+// by hand. See the translator.README.txt file in the tools directory for
+// more information.
+//
+// $hash=$$HASH$$$
+//
+
+#ifndef $GUARD$
+#define $GUARD$
+#pragma once
+
+"""
+
+ # Protect against incorrect use of test headers.
+ if filename.startswith('test/'):
+ result += \
+"""#if !defined(BUILDING_CEF_SHARED) && !defined(WRAPPING_CEF_SHARED) && \\
+ !defined(UNIT_TEST)
+#error This file can be included for unit tests only
+#endif
+
+"""
+
+ classes = header.get_classes(filename)
+
+ # identify all includes and forward declarations
+ translated_includes = set([])
+ internal_includes = set([])
+ all_declares = set([])
+ for cls in classes:
+ includes = cls.get_includes()
+ for include in includes:
+ if include.startswith('base/'):
+ # base/ headers are C++. They should not be included by
+ # translated CEF API headers.
+ raise Exception('Disallowed include of %s.h from %s' % (include,
+ filename))
+ elif include.startswith('internal/'):
+ # internal/ headers may be C or C++. Include them as-is.
+ internal_includes.add(include)
+ else:
+ translated_includes.add(include)
+ declares = cls.get_forward_declares()
+ for declare in declares:
+ declare_cls = header.get_class(declare)
+ if declare_cls is None:
+ raise Exception('Unknown class: %s' % declare)
+ all_declares.add(declare_cls.get_capi_name())
+
+ # output translated includes
+ if len(translated_includes) > 0:
+ sorted_includes = sorted(translated_includes)
+ for include in sorted_includes:
+ result += '#include "include/capi/' + include + '_capi.h"\n'
+ else:
+ result += '#include "include/capi/cef_base_capi.h"\n'
+
+ # output internal includes
+ if len(internal_includes) > 0:
+ sorted_includes = sorted(internal_includes)
+ for include in sorted_includes:
+ result += '#include "include/' + include + '.h"\n'
+
+ result += \
+"""
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+"""
+
+ # output forward declarations
+ if len(all_declares) > 0:
+ sorted_declares = sorted(all_declares)
+ for declare in sorted_declares:
+ result += 'struct _' + declare + ';\n'
+
+ # output classes
+ for cls in classes:
+ # virtual functions are inside the structure
+ classname = cls.get_capi_name()
+ result += '\n' + format_comment(cls.get_comment(), '', translate_map)
+ result += 'typedef struct _'+classname+' {\n'+\
+ ' ///\n'+\
+ ' /// Base structure.\n'+\
+ ' ///\n'+\
+ ' '+cls.get_parent_capi_name()+' base;\n'
+ funcs = cls.get_virtual_funcs()
+ result += make_capi_member_funcs(funcs, defined_names, translate_map, ' ')
+ result += '} ' + classname + ';\n\n'
+
+ defined_names.append(cls.get_capi_name())
+
+ # static functions become global
+ funcs = cls.get_static_funcs()
+ if len(funcs) > 0:
+ result += make_capi_global_funcs(funcs, defined_names, translate_map,
+ '') + '\n'
+
+ # output global functions
+ funcs = header.get_funcs(filename)
+ if len(funcs) > 0:
+ result += make_capi_global_funcs(funcs, defined_names, translate_map, '')
+
+ # footer string
+ result += \
+"""
+#ifdef __cplusplus
+}
+#endif
+
+#endif // $GUARD$
+"""
+
+ # add the copyright year
+ result = result.replace('$YEAR$', get_year())
+ # add the guard string
+ guard = 'CEF_INCLUDE_CAPI_' + \
+ filename.replace('/', '_').replace('.', '_capi_').upper() + '_'
+ result = result.replace('$GUARD$', guard)
+
+ return result
+
+
+def write_capi_header(header, header_dir, filename):
+ file = get_capi_file_name(os.path.join(header_dir, filename))
+ newcontents = make_capi_header(header, filename)
+ return (file, newcontents)
+
+
+# test the module
+if __name__ == "__main__":
+ import sys
+
+ # verify that the correct number of command-line arguments are provided
+ if len(sys.argv) < 2:
+ sys.stderr.write('Usage: ' + sys.argv[0] + ' <infile>\n')
+ sys.exit()
+
+ # create the header object
+ header = obj_header()
+ header.add_file(sys.argv[1])
+
+ # dump the result to stdout
+ filename = os.path.split(sys.argv[1])[1]
+ sys.stdout.write(make_capi_header(header, filename))
diff --git a/tools/make_cmake.py b/tools/make_cmake.py
new file mode 100644
index 00000000..b81c3969
--- /dev/null
+++ b/tools/make_cmake.py
@@ -0,0 +1,254 @@
+# Copyright (c) 2014 The Chromium Embedded Framework Authors. All rights
+# reserved. Use of this source code is governed by a BSD-style license that
+# can be found in the LICENSE file.
+
+from __future__ import absolute_import
+import os
+from file_util import *
+import sys
+
+# script directory.
+script_dir = os.path.dirname(__file__)
+
+# CEF root directory.
+cef_dir = os.path.abspath(os.path.join(script_dir, os.pardir))
+
+
+def get_files_for_variable(cmake_path, variables, variable):
+ """ Returns the path values associated with |variable| and relative to the
+ |cmake_path| directory. """
+ if not variable in variables:
+ raise Exception('Variable %s does not exist' % variable)
+
+ # Cmake file directory.
+ cmake_dirname = os.path.dirname(cmake_path) + '/'
+
+ # Return path values relative to the cmake file directory.
+ # Example 1:
+ # cmake file = "/path/to/libcef_dll/CMakeLists.txt"
+ # include path = "/path/to/libcef_dll/wrapper/cef_browser_info_map.h"
+ # return path = "wrapper/cef_browser_info_map.h"
+ # Example 2:
+ # cmake file = "/path/to/libcef_dll/CMakeLists.txt"
+ # include path = "/path/to/include/internal/cef_export.h"
+ # return path = "../include/internal/cef_export.h"
+ new_paths = []
+ paths = variables[variable]
+ for path in paths:
+ abspath = os.path.join(cef_dir, path)
+ newpath = normalize_path(os.path.relpath(abspath, cmake_dirname))
+ new_paths.append(newpath)
+ return new_paths
+
+
+def format_cmake_set(name, values):
+ result = 'set(%s\n' % name
+ for value in values:
+ result += ' %s\n' % value
+ return result + ' )\n'
+
+
+def format_cmake_group(cmake_path, name, files, platform_sep, append_macro):
+ platforms = {}
+ common = []
+
+ # Folder will be the cmake parent directory name combined with the path to
+ # first file in the files list.
+ # Example 1:
+ # cmake file = "/path/to/libcef_dll/CMakeLists.txt"
+ # include path = "wrapper/cef_browser_info_map.h"
+ # folder = "libcef_dll\\\\wrapper"
+ # Example 2:
+ # cmake file = "/path/to/libcef_dll/CMakeLists.txt"
+ # include path = "../include/internal/cef_export.h"
+ # folder = "include\\\\internal"
+ folder = os.path.basename(os.path.dirname(cmake_path))
+ folder = os.path.dirname(os.path.normpath(os.path.join(folder, files[0])))
+ folder = normalize_path(folder).replace('/', '\\\\\\\\')
+
+ # Group the files by platform.
+ for file in files:
+ parts = file.split(platform_sep)
+ file = parts[0]
+ if len(parts) > 1:
+ # Add the file under the platform.
+ platform = parts[1]
+ if not platform in platforms:
+ platforms[platform] = []
+ platforms[platform].append(file)
+ else:
+ common.append(file)
+
+ result = ''
+ if len(common) > 0:
+ result += format_cmake_set(name, common)
+
+ if len(platforms) > 0:
+ keys = sorted(platforms.keys())
+ for key in keys:
+ result += format_cmake_set(name + '_' + key, platforms[key])
+ result += '%s(%s)\n' % (append_macro, name)
+
+ result += 'source_group(%s FILES ${%s})\n\n' % (folder, name)
+ return result
+
+
+def format_cmake_library(name, group_names):
+ result = 'add_library(%s\n' % name
+ for group in group_names:
+ result += ' ${%s}\n' % group
+ return result + ' )\n\n'
+
+
+def process_cmake_template_segment(segment, segment_ct, cmake_path, variables):
+ prefix = None
+ library = None
+ set = None
+ includes = []
+ suffix = '_SRCS' # Appended to each group name before the platform name.
+ platform_sep = ':' # Used to separate value from platform name.
+ append_macro = 'APPEND_PLATFORM_SOURCES' # CMake macro name.
+
+ # Extract values from |segment|. Example |segment| contents:
+ # 'prefix': 'cefsimple',
+ # 'includes': [
+ # 'cefsimple_sources_common',
+ # 'cefsimple_sources_win:WINDOWS',
+ # 'cefsimple_sources_mac:MAC',
+ # 'cefsimple_sources_linux:LINUX',
+ # ],
+ values = eval('{' + segment + '}', {'__builtins__': None}, None)
+ if 'prefix' in values:
+ prefix = values['prefix']
+ else:
+ raise Exception('Missing prefix value in segment %d' % segment_ct)
+
+ if 'library' in values:
+ library = values['library']
+
+ if 'set' in values:
+ set = values['set']
+
+ if 'append_macro' in values:
+ append_macro = values['append_macro']
+
+ if 'includes' in values and len(values['includes']) > 0:
+ for include in values['includes']:
+ parts = include.strip().split(platform_sep)
+ files = get_files_for_variable(cmake_path, variables, parts[0])
+ if len(parts) == 2:
+ # Append the platform to each file path.
+ files = [file + platform_sep + parts[1] for file in files]
+ includes.extend(files)
+ else:
+ raise Exception('Missing includes value in segment %d' % segment_ct)
+
+ # Sort the file paths alphabetically.
+ includes.sort()
+
+ # Group files by path.
+ # For example, '../include/base/foo.h' and '../include/base/bar.h' will be
+ # grouped as 'PREFIX_INCLUDE_BASE'.
+ groups = {}
+ for include in includes:
+ paths = include.split('/')
+ label = prefix
+ for path in paths[0:-1]:
+ if path == '..':
+ continue
+ label += '_' + path
+ label = label.replace('.', '_').upper()
+ if not label in groups:
+ groups[label] = []
+ groups[label].append(include)
+
+ # Create the output results.
+ result = ''
+
+ keys = sorted(groups.keys())
+ for key in keys:
+ # Add a group of files that share the same path.
+ result += format_cmake_group(cmake_path, key + suffix, groups[key], \
+ platform_sep, append_macro)
+
+ if not library is None:
+ # Add the library declaration if requested.
+ result += format_cmake_library(library, [key + suffix for key in keys])
+
+ if not set is None:
+ # Add the set declaration if requested.
+ result += format_cmake_set(set, \
+ ['${' + key + suffix + '}' for key in keys])
+
+ return result.strip()
+
+
+def process_cmake_template(input, output, variables, quiet=False):
+ """ Reads the |input| template, parses variable substitution sections and
+ writes |output|. """
+ if not quiet:
+ sys.stdout.write('Processing "%s" to "%s"...\n' % (input, output))
+
+ if not os.path.exists(input):
+ raise Exception('File %s does not exist' % input)
+
+ cmake_path = normalize_path(os.path.abspath(input))
+ template = read_file(cmake_path)
+
+ delim_start = '{{'
+ delim_end = '}}'
+
+ # Process the template file, replacing segments delimited by |delim_start|
+ # and |delim_end|.
+ result = ''
+ end = 0
+ segment_ct = 0
+ while True:
+ start = template.find(delim_start, end)
+ if start == -1:
+ break
+ result += template[end:start]
+ end = template.find(delim_end, start + len(delim_start))
+ if end == -1:
+ break
+ segment = template[start + len(delim_start):end]
+ segment_ct = segment_ct + 1
+ result += process_cmake_template_segment(segment, segment_ct, \
+ cmake_path, variables)
+ end += len(delim_end)
+ result += template[end:]
+
+ # Only write the output file if the contents have changed.
+ changed = True
+ if os.path.exists(output):
+ existing = read_file(output)
+ changed = result != existing
+ if changed:
+ write_file(output, result)
+
+
+def read_gypi_variables(source):
+ """ Read the |source| gypi file and extract the variables section. """
+ path = os.path.join(cef_dir, source + '.gypi')
+ if not os.path.exists(path):
+ raise Exception('File %s does not exist' % path)
+ contents = eval_file(path)
+ if not 'variables' in contents:
+ raise Exception('File %s does not have a variables section' % path)
+ return contents['variables']
+
+
+# File entry point.
+if __name__ == "__main__":
+ # Verify that the correct number of command-line arguments are provided.
+ if len(sys.argv) != 3:
+ sys.stderr.write('Usage: ' + sys.argv[0] + ' <infile> <outfile>')
+ sys.exit()
+
+ # Read the gypi files and combine into a single dictionary.
+ variables1 = read_gypi_variables('cef_paths')
+ variables2 = read_gypi_variables('cef_paths2')
+ variables = dict(variables1.items() + variables2.items())
+
+ # Process the cmake template.
+ process_cmake_template(sys.argv[1], sys.argv[2], variables)
diff --git a/tools/make_config_header.py b/tools/make_config_header.py
new file mode 100644
index 00000000..e5d98ed3
--- /dev/null
+++ b/tools/make_config_header.py
@@ -0,0 +1,60 @@
+# Copyright (c) 2019 The Chromium Embedded Framework Authors. All rights
+# reserved. Use of this source code is governed by a BSD-style license that
+# can be found in the LICENSE file.
+
+from __future__ import absolute_import
+from cef_parser import get_copyright
+from file_util import *
+import sys
+
+
+def make_config_header(gn_config):
+ """ Creates the header file contents for the cef build configuration. """
+
+ if not path_exists(gn_config):
+ raise Exception('File ' + gn_config + ' does not exist.')
+
+ defines = []
+
+ if sys.platform.startswith('linux'):
+ lines = read_file(gn_config).split("\n")
+
+ # All Linux builds use Ozone, and the X11 platform is enabled by default.
+ # Check if the config is explicitly disabling it.
+ if not 'ozone_platform_x11=false' in lines:
+ defines.append('#define CEF_X11 1')
+
+ result = get_copyright(full=True, translator=False) + \
+"""//
+// ---------------------------------------------------------------------------
+//
+// This file is generated by the make_config_header.py tool.
+//
+
+#ifndef CEF_INCLUDE_CEF_CONFIG_H_
+#define CEF_INCLUDE_CEF_CONFIG_H_
+
+$DEFINES$
+
+#endif // CEF_INCLUDE_CEF_CONFIG_H_
+"""
+
+ result = result.replace('$DEFINES$', "\n".join(defines))
+ return result
+
+
+def write_config_header(output, gn_config):
+ output = os.path.abspath(output)
+ result = make_config_header(gn_config)
+ return write_file_if_changed(output, result)
+
+
+def main(argv):
+ if len(argv) < 3:
+ print(("Usage:\n %s <output_header_file> <input_args_gn_file>" % argv[0]))
+ sys.exit(-1)
+ write_config_header(argv[1], argv[2])
+
+
+if '__main__' == __name__:
+ main(sys.argv)
diff --git a/tools/make_cppdocs.bat b/tools/make_cppdocs.bat
new file mode 100644
index 00000000..d2eae345
--- /dev/null
+++ b/tools/make_cppdocs.bat
@@ -0,0 +1,44 @@
+@echo off
+:: Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights
+:: reserved. Use of this source code is governed by a BSD-style license
+:: that can be found in the LICENSE file.
+
+set RC=
+
+setlocal
+
+:: Check if DOXYGEN_EXE is already provided via the environment.
+if exist "%DOXYGEN_EXE%" goto found_exe
+set DOXYGEN_EXE="C:\Program Files\doxygen\bin\doxygen.exe"
+if not exist %DOXYGEN_EXE% (
+echo ERROR: Please install Doxygen from https://doxygen.nl/ 1>&2
+set ERRORLEVEL=1
+goto end
+)
+
+:found_exe
+
+:: Environment variables inserted into the Doxyfile via `$(VAR_NAME)` syntax.
+for /F %%i in ('python.bat %~dp0\cef_version.py current') do set PROJECT_NUMBER=%%i
+
+:: Run from the top-level CEF directory so that relative paths resolve correctly.
+set CURRENT_PATH="%CD%"
+cd "%~dp0\.."
+
+:: Generate documentation in the docs/html directory.
+%DOXYGEN_EXE% Doxyfile
+
+:: Write a docs/index.html file.
+echo|set /p="<html><head><meta http-equiv="refresh" content="0;URL='html/index.html'"/></head></html>" > docs/index.html
+
+cd "%CURRENT_PATH%"
+
+:end
+endlocal & set RC=%ERRORLEVEL%
+goto omega
+
+:returncode
+exit /B %RC%
+
+:omega
+call :returncode %RC% \ No newline at end of file
diff --git a/tools/make_cppdocs.sh b/tools/make_cppdocs.sh
new file mode 100755
index 00000000..724d7b87
--- /dev/null
+++ b/tools/make_cppdocs.sh
@@ -0,0 +1,27 @@
+#!/bin/bash
+# Copyright (c) 2022 The Chromium Embedded Framework Authors. All rights
+# reserved. Use of this source code is governed by a BSD-style license
+# that can be found in the LICENSE file.
+
+if ! command -v doxygen &> /dev/null
+then
+ echo "ERROR: Please install Doxygen" 1>&2
+ exit 1
+fi
+
+# Determine the absolute path to the script directory.
+SCRIPT_DIR="$( cd "$( dirname "$0" )" && pwd )"
+
+# Determine the top-level CEF directory.
+CEF_DIR="${SCRIPT_DIR}/.."
+
+# Environment variables inserted into the Doxyfile via `$(VAR_NAME)` syntax.
+export PROJECT_NUMBER=$(python3 ${SCRIPT_DIR}/cef_version.py current)
+
+# Generate documentation in the docs/html directory.
+# Run from the top-level CEF directory so that relative paths resolve correctly.
+( cd ${CEF_DIR} && doxygen Doxyfile )
+
+# Write a docs/index.html file.
+echo "<html><head><meta http-equiv=\"refresh\" content=\"0;URL='html/index.html'\"/></head></html>" > ${CEF_DIR}/docs/index.html
+
diff --git a/tools/make_cpptoc_header.py b/tools/make_cpptoc_header.py
new file mode 100644
index 00000000..83755537
--- /dev/null
+++ b/tools/make_cpptoc_header.py
@@ -0,0 +1,109 @@
+# Copyright (c) 2011 The Chromium Embedded Framework Authors. All rights
+# reserved. Use of this source code is governed by a BSD-style license that
+# can be found in the LICENSE file.
+
+from __future__ import absolute_import
+from cef_parser import *
+
+
+def make_cpptoc_header(header, clsname):
+ cls = header.get_class(clsname)
+ if cls is None:
+ raise Exception('Class does not exist: ' + clsname)
+
+ dllside = cls.is_library_side()
+
+ directory = cls.get_file_directory()
+ defname = ''
+ if not directory is None:
+ defname += directory + '_'
+ defname += get_capi_name(clsname[3:], False)
+ defname = defname.upper()
+
+ capiname = cls.get_capi_name()
+
+ result = get_copyright()
+
+ result += '#ifndef CEF_LIBCEF_DLL_CPPTOC_'+defname+'_CPPTOC_H_\n'+ \
+ '#define CEF_LIBCEF_DLL_CPPTOC_'+defname+'_CPPTOC_H_\n' + \
+ '#pragma once\n'
+
+ if dllside:
+ result += """
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+"""
+ else:
+ result += """
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+"""
+
+ # include the headers for this class
+ result += '\n#include "include/'+cls.get_file_name()+'"\n' \
+ '#include "include/capi/'+cls.get_capi_file_name()+'"\n'
+
+ # include headers for any forward declared classes that are not in the same file
+ declares = cls.get_forward_declares()
+ for declare in declares:
+ dcls = header.get_class(declare)
+ if dcls.get_file_name() != cls.get_file_name():
+ result += '#include "include/'+dcls.get_file_name()+'"\n' \
+ '#include "include/capi/'+dcls.get_capi_file_name()+'"\n'
+
+ base_class_name = header.get_base_class_name(clsname)
+ base_scoped = True if base_class_name == 'CefBaseScoped' else False
+ if base_scoped:
+ template_file = 'cpptoc_scoped.h'
+ template_class = 'CefCppToCScoped'
+ else:
+ template_file = 'cpptoc_ref_counted.h'
+ template_class = 'CefCppToCRefCounted'
+
+ result += '#include "libcef_dll/cpptoc/' + template_file + '"'
+ result += '\n\n// Wrap a C++ class with a C structure.\n'
+
+ if dllside:
+ result += '// This class may be instantiated and accessed DLL-side only.\n'
+ else:
+ result += '// This class may be instantiated and accessed wrapper-side only.\n'
+
+ result += 'class '+clsname+'CppToC\n'+ \
+ ' : public ' + template_class + '<'+clsname+'CppToC, '+clsname+', '+capiname+'> {\n'+ \
+ ' public:\n'+ \
+ ' '+clsname+'CppToC();\n'+ \
+ ' virtual ~'+clsname+'CppToC();\n'+ \
+ '};\n\n'
+
+ result += '#endif // CEF_LIBCEF_DLL_CPPTOC_' + defname + '_CPPTOC_H_'
+
+ return result
+
+
+def write_cpptoc_header(header, clsname, dir):
+ # give the output file the same directory offset as the input file
+ cls = header.get_class(clsname)
+ dir = os.path.dirname(os.path.join(dir, cls.get_file_name()))
+ file = os.path.join(dir, get_capi_name(clsname[3:], False) + '_cpptoc.h')
+
+ newcontents = make_cpptoc_header(header, clsname)
+ return (file, newcontents)
+
+
+# test the module
+if __name__ == "__main__":
+ import sys
+
+ # verify that the correct number of command-line arguments are provided
+ if len(sys.argv) < 3:
+ sys.stderr.write('Usage: ' + sys.argv[0] + ' <infile> <classname>')
+ sys.exit()
+
+ # create the header object
+ header = obj_header()
+ header.add_file(sys.argv[1])
+
+ # dump the result to stdout
+ sys.stdout.write(make_cpptoc_header(header, sys.argv[2]))
diff --git a/tools/make_cpptoc_impl.py b/tools/make_cpptoc_impl.py
new file mode 100644
index 00000000..96924511
--- /dev/null
+++ b/tools/make_cpptoc_impl.py
@@ -0,0 +1,765 @@
+# Copyright (c) 2011 The Chromium Embedded Framework Authors. All rights
+# reserved. Use of this source code is governed by a BSD-style license that
+# can be found in the LICENSE file.
+
+from __future__ import absolute_import
+from cef_parser import *
+
+
+def make_cpptoc_impl_proto(name, func, parts):
+ if isinstance(func, obj_function_virtual):
+ proto = parts['retval'] + ' CEF_CALLBACK'
+ else:
+ proto = 'CEF_EXPORT ' + parts['retval']
+
+ proto += ' ' + name + '(' + ', '.join(parts['args']) + ')'
+ return proto
+
+
+def make_cpptoc_function_impl_existing(cls, name, func, impl, defined_names):
+ notify(name + ' has manual edits')
+
+ # retrieve the C API prototype parts
+ parts = func.get_capi_parts(defined_names, True)
+
+ changes = format_translation_changes(impl, parts)
+ if len(changes) > 0:
+ notify(name + ' prototype changed')
+
+ return make_cpptoc_impl_proto(
+ name, func, parts) + '{' + changes + impl['body'] + '\n}\n\n'
+
+
+def make_cpptoc_function_impl_new(cls, name, func, defined_names, base_scoped):
+ # Special handling for the cef_shutdown global function.
+ is_cef_shutdown = name == 'cef_shutdown' and isinstance(
+ func.parent, obj_header)
+
+ # retrieve the C API prototype parts
+ parts = func.get_capi_parts(defined_names, True)
+ result = make_cpptoc_impl_proto(name, func, parts) + ' {'
+
+ if isinstance(func.parent, obj_class) and \
+ not func.parent.has_attrib('no_debugct_check') and \
+ not base_scoped:
+ result += '\n shutdown_checker::AssertNotShutdown();\n'
+
+ invalid = []
+
+ # retrieve the function arguments
+ args = func.get_arguments()
+
+ # determine the argument types
+ for arg in args:
+ if arg.get_arg_type() == 'invalid':
+ invalid.append(arg.get_name())
+
+ # retrieve the function return value
+ retval = func.get_retval()
+ retval_type = retval.get_retval_type()
+ if retval_type == 'invalid':
+ invalid.append('(return value)')
+ retval_default = ''
+ else:
+ retval_default = retval.get_retval_default(True)
+ if len(retval_default) > 0:
+ retval_default = ' ' + retval_default
+
+ if len(invalid) > 0:
+ notify(name + ' could not be autogenerated')
+ # code could not be auto-generated
+ result += '\n // BEGIN DELETE BEFORE MODIFYING'
+ result += '\n // AUTO-GENERATED CONTENT'
+ result += '\n // COULD NOT IMPLEMENT DUE TO: ' + ', '.join(invalid)
+ result += '\n #pragma message("Warning: "__FILE__": ' + name + ' is not implemented")'
+ result += '\n // END DELETE BEFORE MODIFYING'
+ result += '\n}\n\n'
+ return result
+
+ result += '\n // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING\n'
+
+ result_len = len(result)
+
+ optional = []
+
+ # parameter verification
+ if isinstance(func, obj_function_virtual):
+ result += '\n DCHECK(self);'\
+ '\n if (!self) {'\
+ '\n return'+retval_default+';'\
+ '\n }'
+
+ for arg in args:
+ arg_type = arg.get_arg_type()
+ arg_name = arg.get_type().get_name()
+
+ # skip optional params
+ optional_params = arg.parent.get_attrib_list('optional_param')
+ if not optional_params is None and arg_name in optional_params:
+ optional.append(arg_name)
+ continue
+
+ comment = '\n // Verify param: ' + arg_name + '; type: ' + arg_type
+
+ if arg_type == 'simple_byref' or arg_type == 'simple_byref_const' or \
+ arg_type == 'simple_byaddr' or arg_type == 'bool_byref' or arg_type == 'bool_byaddr' or \
+ arg_type == 'struct_byref_const' or arg_type == 'struct_byref' or \
+ arg_type == 'string_byref_const' or arg_type == 'string_byref' or \
+ arg_type == 'refptr_same' or arg_type == 'refptr_same_byref' or \
+ arg_type == 'refptr_diff' or arg_type == 'refptr_diff_byref' or \
+ arg_type == 'ownptr_same' or arg_type == 'ownptr_same_byref' or \
+ arg_type == 'ownptr_diff' or arg_type == 'ownptr_diff_byref' or \
+ arg_type == 'rawptr_same' or arg_type == 'rawptr_same_byref' or \
+ arg_type == 'rawptr_diff' or arg_type == 'rawptr_diff_byref' or \
+ arg_type == 'string_vec_byref' or arg_type == 'string_vec_byref_const' or \
+ arg_type == 'string_map_single_byref' or arg_type == 'string_map_single_byref_const' or \
+ arg_type == 'string_map_multi_byref' or arg_type == 'string_map_multi_byref_const':
+ result += comment+\
+ '\n DCHECK('+arg_name+');'\
+ '\n if (!'+arg_name+') {'\
+ '\n return'+retval_default+';'\
+ '\n }'
+ if arg_type == 'struct_byref_const' or arg_type == 'struct_byref':
+ result +=\
+ '\n if (!template_util::has_valid_size('+arg_name+')) {'\
+ '\n NOTREACHED() << "invalid '+arg_name+'->[base.]size";'\
+ '\n return'+retval_default+';'\
+ '\n }'
+ elif arg_type == 'simple_vec_byref' or arg_type == 'bool_vec_byref' or \
+ arg_type == 'refptr_vec_same_byref' or arg_type == 'refptr_vec_diff_byref' or \
+ arg_type == 'ownptr_vec_same_byref' or arg_type == 'ownptr_vec_diff_byref' or \
+ arg_type == 'rawptr_vec_same_byref' or arg_type == 'rawptr_vec_diff_byref':
+ result += comment+\
+ '\n DCHECK('+arg_name+'Count && (*'+arg_name+'Count == 0 || '+arg_name+'));'\
+ '\n if (!'+arg_name+'Count || (*'+arg_name+'Count > 0 && !'+arg_name+')) {'\
+ '\n return'+retval_default+';'\
+ '\n }'
+ elif arg_type == 'simple_vec_byref_const' or arg_type == 'bool_vec_byref_const' or \
+ arg_type == 'refptr_vec_same_byref_const' or arg_type == 'refptr_vec_diff_byref_const' or \
+ arg_type == 'ownptr_vec_same_byref_const' or arg_type == 'ownptr_vec_diff_byref_const' or \
+ arg_type == 'rawptr_vec_same_byref_const' or arg_type == 'rawptr_vec_diff_byref_const':
+ result += comment+\
+ '\n DCHECK('+arg_name+'Count == 0 || '+arg_name+');'\
+ '\n if ('+arg_name+'Count > 0 && !'+arg_name+') {'\
+ '\n return'+retval_default+';'\
+ '\n }'
+
+ # check index params
+ index_params = arg.parent.get_attrib_list('index_param')
+ if not index_params is None and arg_name in index_params:
+ result += comment+\
+ '\n DCHECK_GE('+arg_name+', 0);'\
+ '\n if ('+arg_name+' < 0) {'\
+ '\n return'+retval_default+';'\
+ '\n }'
+
+ if len(optional) > 0:
+ # Wrap the comment at 80 characters.
+ str = '\n // Unverified params: ' + optional[0]
+ for name in optional[1:]:
+ str += ','
+ if len(str) + len(name) + 1 > 80:
+ result += str
+ str = '\n //'
+ str += ' ' + name
+ result += str
+
+ if len(result) != result_len:
+ result += '\n'
+ result_len = len(result)
+
+ # parameter translation
+ params = []
+
+ for arg in args:
+ arg_type = arg.get_arg_type()
+ arg_name = arg.get_type().get_name()
+
+ comment = '\n // Translate param: ' + arg_name + '; type: ' + arg_type
+
+ if arg_type == 'simple_byval' or arg_type == 'simple_byaddr':
+ params.append(arg_name)
+ elif arg_type == 'simple_byref' or arg_type == 'simple_byref_const':
+ data_type = arg.get_type().get_type()
+ default = arg.get_type().get_result_simple_default()
+ result += comment+\
+ '\n '+data_type+' '+arg_name+'Val = '+arg_name+'?*'+arg_name+':'+default+';'
+ params.append(arg_name + 'Val')
+ elif arg_type == 'bool_byval':
+ params.append(arg_name + '?true:false')
+ elif arg_type == 'bool_byref' or arg_type == 'bool_byaddr':
+ result += comment+\
+ '\n bool '+arg_name+'Bool = ('+arg_name+' && *'+arg_name+')?true:false;'
+ if arg_type == 'bool_byref':
+ params.append(arg_name + 'Bool')
+ else:
+ params.append('&' + arg_name + 'Bool')
+ elif arg_type == 'struct_byref_const':
+ struct_type = arg.get_type().get_type()
+ result += comment+\
+ '\n '+struct_type+' '+arg_name+'Obj;'\
+ '\n if ('+arg_name+') {'\
+ '\n '+arg_name+'Obj.Set(*'+arg_name+', false);'\
+ '\n }'
+ params.append(arg_name + 'Obj')
+ elif arg_type == 'struct_byref':
+ struct_type = arg.get_type().get_type()
+ result += comment+\
+ '\n '+struct_type+' '+arg_name+'Obj;'\
+ '\n if ('+arg_name+') {'\
+ '\n '+arg_name+'Obj.AttachTo(*'+arg_name+');'\
+ '\n }'
+ params.append(arg_name + 'Obj')
+ elif arg_type == 'string_byref_const':
+ params.append('CefString(' + arg_name + ')')
+ elif arg_type == 'string_byref':
+ result += comment+\
+ '\n CefString '+arg_name+'Str('+arg_name+');'
+ params.append(arg_name + 'Str')
+ elif arg_type == 'refptr_same' or arg_type == 'refptr_diff':
+ ptr_class = arg.get_type().get_ptr_type()
+ if arg_type == 'refptr_same':
+ params.append(ptr_class + 'CppToC::Unwrap(' + arg_name + ')')
+ else:
+ params.append(ptr_class + 'CToCpp::Wrap(' + arg_name + ')')
+ elif arg_type == 'ownptr_same' or arg_type == 'rawptr_same':
+ ptr_class = arg.get_type().get_ptr_type()
+ if arg_type == 'ownptr_same':
+ params.append(ptr_class + 'CppToC::UnwrapOwn(' + arg_name + ')')
+ else:
+ params.append(ptr_class + 'CppToC::UnwrapRaw(' + arg_name + ')')
+ elif arg_type == 'ownptr_diff' or arg_type == 'rawptr_diff':
+ ptr_class = arg.get_type().get_ptr_type()
+ result += comment+\
+ '\n CefOwnPtr<'+ptr_class+'> '+arg_name+'Ptr('+ptr_class+'CToCpp::Wrap('+arg_name+'));'
+ if arg_type == 'ownptr_diff':
+ params.append('std::move(' + arg_name + 'Ptr)')
+ else:
+ params.append(arg_name + 'Ptr.get()')
+ elif arg_type == 'refptr_same_byref' or arg_type == 'refptr_diff_byref':
+ ptr_class = arg.get_type().get_ptr_type()
+ if arg_type == 'refptr_same_byref':
+ assign = ptr_class + 'CppToC::Unwrap(*' + arg_name + ')'
+ else:
+ assign = ptr_class + 'CToCpp::Wrap(*' + arg_name + ')'
+ result += comment+\
+ '\n CefRefPtr<'+ptr_class+'> '+arg_name+'Ptr;'\
+ '\n if ('+arg_name+' && *'+arg_name+') {'\
+ '\n '+arg_name+'Ptr = '+assign+';'\
+ '\n }'\
+ '\n '+ptr_class+'* '+arg_name+'Orig = '+arg_name+'Ptr.get();'
+ params.append(arg_name + 'Ptr')
+ elif arg_type == 'string_vec_byref' or arg_type == 'string_vec_byref_const':
+ result += comment+\
+ '\n std::vector<CefString> '+arg_name+'List;'\
+ '\n transfer_string_list_contents('+arg_name+', '+arg_name+'List);'
+ params.append(arg_name + 'List')
+ elif arg_type == 'string_map_single_byref' or arg_type == 'string_map_single_byref_const':
+ result += comment+\
+ '\n std::map<CefString, CefString> '+arg_name+'Map;'\
+ '\n transfer_string_map_contents('+arg_name+', '+arg_name+'Map);'
+ params.append(arg_name + 'Map')
+ elif arg_type == 'string_map_multi_byref' or arg_type == 'string_map_multi_byref_const':
+ result += comment+\
+ '\n std::multimap<CefString, CefString> '+arg_name+'Multimap;'\
+ '\n transfer_string_multimap_contents('+arg_name+', '+arg_name+'Multimap);'
+ params.append(arg_name + 'Multimap')
+ elif arg_type == 'simple_vec_byref' or arg_type == 'bool_vec_byref' or \
+ arg_type == 'refptr_vec_same_byref' or arg_type == 'refptr_vec_diff_byref':
+ vec_type = arg.get_type().get_vector_type()
+ if arg_type == 'simple_vec_byref':
+ assign = arg_name + '[i]'
+ elif arg_type == 'bool_vec_byref':
+ assign = arg_name + '[i]?true:false'
+ elif arg_type == 'refptr_vec_same_byref':
+ ptr_class = arg.get_type().get_ptr_type()
+ assign = ptr_class + 'CppToC::Unwrap(' + arg_name + '[i])'
+ elif arg_type == 'refptr_vec_diff_byref':
+ ptr_class = arg.get_type().get_ptr_type()
+ assign = ptr_class + 'CToCpp::Wrap(' + arg_name + '[i])'
+ result += comment+\
+ '\n std::vector<'+vec_type+' > '+arg_name+'List;'\
+ '\n if ('+arg_name+'Count && *'+arg_name+'Count > 0 && '+arg_name+') {'\
+ '\n for (size_t i = 0; i < *'+arg_name+'Count; ++i) {'\
+ '\n '+arg_name+'List.push_back('+assign+');'\
+ '\n }'\
+ '\n }'
+ params.append(arg_name + 'List')
+ elif arg_type == 'simple_vec_byref_const' or arg_type == 'bool_vec_byref_const' or \
+ arg_type == 'refptr_vec_same_byref_const' or arg_type == 'refptr_vec_diff_byref_const' or \
+ arg_type == 'rawptr_vec_same_byref_const' or arg_type == 'rawptr_vec_diff_byref_const':
+ vec_type = arg.get_type().get_vector_type()
+ if arg_type == 'simple_vec_byref_const':
+ assign = arg_name + '[i]'
+ elif arg_type == 'bool_vec_byref_const':
+ assign = arg_name + '[i]?true:false'
+ else:
+ ptr_class = arg.get_type().get_ptr_type()
+ if arg_type == 'refptr_vec_same_byref_const':
+ assign = ptr_class + 'CppToC::Unwrap(' + arg_name + '[i])'
+ elif arg_type == 'refptr_vec_diff_byref_const':
+ assign = ptr_class + 'CToCpp::Wrap(' + arg_name + '[i])'
+ elif arg_type == 'rawptr_vec_same_byref_const':
+ assign = ptr_class + 'CppToC::UnwrapRaw(' + arg_name + '[i])'
+ elif arg_type == 'rawptr_vec_diff_byref_const':
+ assign = ptr_class + 'CToCpp::Wrap(' + arg_name + '[i]).release()'
+ result += comment+\
+ '\n std::vector<'+vec_type+' > '+arg_name+'List;'\
+ '\n if ('+arg_name+'Count > 0) {'\
+ '\n for (size_t i = 0; i < '+arg_name+'Count; ++i) {'\
+ '\n '+vec_type+' '+arg_name+'Val = '+assign+';'\
+ '\n '+arg_name+'List.push_back('+arg_name+'Val);'\
+ '\n }'\
+ '\n }'
+ params.append(arg_name + 'List')
+ else:
+ raise Exception('Unsupported argument type %s for parameter %s in %s' %
+ (arg_type, arg_name, name))
+
+ if len(result) != result_len:
+ result += '\n'
+ result_len = len(result)
+
+ if is_cef_shutdown:
+ result += '\n\n#if DCHECK_IS_ON()'\
+ '\n shutdown_checker::SetIsShutdown();'\
+ '\n#endif\n'
+
+ # execution
+ result += '\n // Execute\n '
+
+ if retval_type != 'none':
+ # has a return value
+ if retval_type == 'simple':
+ result += retval.get_type().get_result_simple_type()
+ else:
+ result += retval.get_type().get_type()
+ result += ' _retval = '
+
+ if isinstance(func.parent, obj_class):
+ # virtual and static class methods
+ if isinstance(func, obj_function_virtual):
+ if cls.get_name() == func.parent.get_name():
+ # virtual method for the current class
+ result += func.parent.get_name() + 'CppToC::Get(self)->'
+ else:
+ # virtual method for a parent class
+ result += cls.get_name(
+ ) + 'CppToC::Get(reinterpret_cast<' + cls.get_capi_name() + '*>(self))->'
+ else:
+ result += func.parent.get_name() + '::'
+ result += func.get_name() + '('
+
+ if len(params) > 0:
+ result += '\n ' + ',\n '.join(params)
+
+ result += ');\n'
+
+ result_len = len(result)
+
+ # parameter restoration
+ for arg in args:
+ arg_type = arg.get_arg_type()
+ arg_name = arg.get_type().get_name()
+
+ comment = '\n // Restore param: ' + arg_name + '; type: ' + arg_type
+
+ if arg_type == 'simple_byref':
+ result += comment+\
+ '\n if ('+arg_name+') {'\
+ '\n *'+arg_name+' = '+arg_name+'Val;'\
+ '\n }'
+ elif arg_type == 'bool_byref' or arg_type == 'bool_byaddr':
+ result += comment+\
+ '\n if ('+arg_name+') {'\
+ '\n *'+arg_name+' = '+arg_name+'Bool?true:false;'\
+ '\n }'
+ elif arg_type == 'struct_byref':
+ result += comment+\
+ '\n if ('+arg_name+') {'\
+ '\n '+arg_name+'Obj.DetachTo(*'+arg_name+');'\
+ '\n }'
+ elif arg_type == 'refptr_same_byref' or arg_type == 'refptr_diff_byref':
+ ptr_class = arg.get_type().get_ptr_type()
+ if arg_type == 'refptr_same_byref':
+ assign = ptr_class + 'CppToC::Wrap(' + arg_name + 'Ptr)'
+ else:
+ assign = ptr_class + 'CToCpp::Unwrap(' + arg_name + 'Ptr)'
+ result += comment+\
+ '\n if ('+arg_name+') {'\
+ '\n if ('+arg_name+'Ptr.get()) {'\
+ '\n if ('+arg_name+'Ptr.get() != '+arg_name+'Orig) {'\
+ '\n *'+arg_name+' = '+assign+';'\
+ '\n }'\
+ '\n } else {'\
+ '\n *'+arg_name+' = nullptr;'\
+ '\n }'\
+ '\n }'
+ elif arg_type == 'string_vec_byref':
+ result += comment+\
+ '\n cef_string_list_clear('+arg_name+');'\
+ '\n transfer_string_list_contents('+arg_name+'List, '+arg_name+');'
+ elif arg_type == 'string_map_single_byref':
+ result += comment+\
+ '\n cef_string_map_clear('+arg_name+');'\
+ '\n transfer_string_map_contents('+arg_name+'Map, '+arg_name+');'
+ elif arg_type == 'string_map_multi_byref':
+ result += comment+\
+ '\n cef_string_multimap_clear('+arg_name+');'\
+ '\n transfer_string_multimap_contents('+arg_name+'Multimap, '+arg_name+');'
+ elif arg_type == 'simple_vec_byref' or arg_type == 'bool_vec_byref' or \
+ arg_type == 'refptr_vec_same_byref' or arg_type == 'refptr_vec_diff_byref':
+ if arg_type == 'simple_vec_byref' or arg_type == 'bool_vec_byref':
+ assign = arg_name + 'List[i]'
+ elif arg_type == 'refptr_vec_same_byref':
+ ptr_class = arg.get_type().get_ptr_type()
+ assign = ptr_class + 'CppToC::Wrap(' + arg_name + 'List[i])'
+ elif arg_type == 'refptr_vec_diff_byref':
+ ptr_class = arg.get_type().get_ptr_type()
+ assign = ptr_class + 'CToCpp::Unwrap(' + arg_name + 'List[i])'
+ result += comment+\
+ '\n if ('+arg_name+'Count && '+arg_name+') {'\
+ '\n *'+arg_name+'Count = std::min('+arg_name+'List.size(), *'+arg_name+'Count);'\
+ '\n if (*'+arg_name+'Count > 0) {'\
+ '\n for (size_t i = 0; i < *'+arg_name+'Count; ++i) {'\
+ '\n '+arg_name+'[i] = '+assign+';'\
+ '\n }'\
+ '\n }'\
+ '\n }'
+ elif arg_type == 'rawptr_vec_diff_byref_const':
+ result += comment+\
+ '\n if ('+arg_name+'Count > 0) {'\
+ '\n for (size_t i = 0; i < '+arg_name+'Count; ++i) {'\
+ '\n delete '+arg_name+'List[i];'\
+ '\n }'\
+ '\n }'
+
+ if len(result) != result_len:
+ result += '\n'
+ result_len = len(result)
+
+ if len(result) != result_len:
+ result += '\n'
+ result_len = len(result)
+
+ # return translation
+ if retval_type != 'none':
+ # has a return value
+ result += '\n // Return type: ' + retval_type
+ if retval_type == 'simple' or retval_type == 'bool':
+ result += '\n return _retval;'
+ elif retval_type == 'string':
+ result += '\n return _retval.DetachToUserFree();'
+ elif retval_type == 'refptr_same':
+ ptr_class = retval.get_type().get_ptr_type()
+ result += '\n return ' + ptr_class + 'CppToC::Wrap(_retval);'
+ elif retval_type == 'refptr_diff':
+ ptr_class = retval.get_type().get_ptr_type()
+ result += '\n return ' + ptr_class + 'CToCpp::Unwrap(_retval);'
+ elif retval_type == 'ownptr_same':
+ ptr_class = retval.get_type().get_ptr_type()
+ result += '\n return ' + ptr_class + 'CppToC::WrapOwn(std::move(_retval));'
+ elif retval_type == 'ownptr_diff':
+ ptr_class = retval.get_type().get_ptr_type()
+ result += '\n return ' + ptr_class + 'CToCpp::UnwrapOwn(std::move(_retval));'
+ else:
+ raise Exception('Unsupported return type %s in %s' % (retval_type, name))
+
+ if len(result) != result_len:
+ result += '\n'
+
+ result += '}\n\n'
+ return result
+
+
+def make_cpptoc_function_impl(cls, funcs, existing, prefixname, defined_names,
+ base_scoped):
+ impl = ''
+
+ for func in funcs:
+ if not prefixname is None:
+ name = prefixname + '_' + func.get_capi_name()
+ else:
+ name = func.get_capi_name()
+ value = get_next_function_impl(existing, name)
+ if not value is None \
+ and value['body'].find('// AUTO-GENERATED CONTENT') < 0:
+ # an implementation exists that was not auto-generated
+ impl += make_cpptoc_function_impl_existing(cls, name, func, value,
+ defined_names)
+ else:
+ impl += make_cpptoc_function_impl_new(cls, name, func, defined_names,
+ base_scoped)
+
+ return impl
+
+
+def make_cpptoc_virtual_function_impl(header, cls, existing, prefixname,
+ defined_names, base_scoped):
+ funcs = []
+ funcs.extend(cls.get_virtual_funcs())
+ cur_cls = cls
+ while True:
+ parent_name = cur_cls.get_parent_name()
+ if is_base_class(parent_name):
+ break
+ else:
+ parent_cls = header.get_class(parent_name, defined_names)
+ if parent_cls is None:
+ raise Exception('Class does not exist: ' + parent_name)
+ funcs.extend(parent_cls.get_virtual_funcs())
+ cur_cls = header.get_class(parent_name, defined_names)
+
+ return make_cpptoc_function_impl(cls, funcs, existing, prefixname,
+ defined_names, base_scoped)
+
+
+def make_cpptoc_virtual_function_assignment_block(funcs, offset, prefixname):
+ impl = ''
+ for func in funcs:
+ name = func.get_capi_name()
+ impl += ' GetStruct()->' + offset + name + ' = ' + prefixname + '_' + name + ';\n'
+ return impl
+
+
+def make_cpptoc_virtual_function_assignment(header, cls, prefixname,
+ defined_names):
+ impl = make_cpptoc_virtual_function_assignment_block(cls.get_virtual_funcs(),
+ '', prefixname)
+
+ cur_cls = cls
+ offset = ''
+ while True:
+ parent_name = cur_cls.get_parent_name()
+ offset += 'base.'
+ if is_base_class(parent_name):
+ break
+ else:
+ parent_cls = header.get_class(parent_name, defined_names)
+ if parent_cls is None:
+ raise Exception('Class does not exist: ' + parent_name)
+ impl += make_cpptoc_virtual_function_assignment_block(
+ parent_cls.get_virtual_funcs(), offset, prefixname)
+ cur_cls = header.get_class(parent_name, defined_names)
+
+ return impl
+
+
+def make_cpptoc_unwrap_derived(header, cls, base_scoped):
+ # identify all classes that derive from cls
+ derived_classes = []
+ cur_clsname = cls.get_name()
+ allclasses = header.get_classes()
+ for cur_cls in allclasses:
+ if cur_cls.get_name() == cur_clsname:
+ continue
+ if cur_cls.has_parent(cur_clsname):
+ derived_classes.append(cur_cls.get_name())
+
+ derived_classes = sorted(derived_classes)
+
+ if base_scoped:
+ impl = ['', '']
+ for clsname in derived_classes:
+ impl[0] += ' if (type == '+get_wrapper_type_enum(clsname)+') {\n'+\
+ ' return '+clsname+'CppToC::UnwrapOwn(reinterpret_cast<'+\
+ get_capi_name(clsname, True)+'*>(s));\n'+\
+ ' }\n'
+ impl[1] += ' if (type == '+get_wrapper_type_enum(clsname)+') {\n'+\
+ ' return '+clsname+'CppToC::UnwrapRaw(reinterpret_cast<'+\
+ get_capi_name(clsname, True)+'*>(s));\n'+\
+ ' }\n'
+ else:
+ impl = ''
+ for clsname in derived_classes:
+ impl += ' if (type == '+get_wrapper_type_enum(clsname)+') {\n'+\
+ ' return '+clsname+'CppToC::Unwrap(reinterpret_cast<'+\
+ get_capi_name(clsname, True)+'*>(s));\n'+\
+ ' }\n'
+ return impl
+
+
+def make_cpptoc_class_impl(header, clsname, impl):
+ # structure names that have already been defined
+ defined_names = header.get_defined_structs()
+
+ # retrieve the class and populate the defined names
+ cls = header.get_class(clsname, defined_names)
+ if cls is None:
+ raise Exception('Class does not exist: ' + clsname)
+
+ capiname = cls.get_capi_name()
+ prefixname = get_capi_name(clsname[3:], False)
+
+ # retrieve the existing virtual function implementations
+ existing = get_function_impls(impl, 'CEF_CALLBACK')
+
+ base_class_name = header.get_base_class_name(clsname)
+ base_scoped = True if base_class_name == 'CefBaseScoped' else False
+ if base_scoped:
+ template_class = 'CefCppToCScoped'
+ else:
+ template_class = 'CefCppToCRefCounted'
+
+ # generate virtual functions
+ virtualimpl = make_cpptoc_virtual_function_impl(
+ header, cls, existing, prefixname, defined_names, base_scoped)
+ if len(virtualimpl) > 0:
+ virtualimpl = '\nnamespace {\n\n// MEMBER FUNCTIONS - Body may be edited by hand.\n\n' + virtualimpl + '} // namespace'
+
+ # the current class is already defined for static functions
+ defined_names.append(cls.get_capi_name())
+
+ # retrieve the existing static function implementations
+ existing = get_function_impls(impl, 'CEF_EXPORT')
+
+ # generate static functions
+ staticimpl = make_cpptoc_function_impl(cls,
+ cls.get_static_funcs(), existing, None,
+ defined_names, base_scoped)
+ if len(staticimpl) > 0:
+ staticimpl = '\n// GLOBAL FUNCTIONS - Body may be edited by hand.\n\n' + staticimpl
+
+ resultingimpl = staticimpl + virtualimpl
+
+ # any derived classes can be unwrapped
+ unwrapderived = make_cpptoc_unwrap_derived(header, cls, base_scoped)
+
+ const = '// CONSTRUCTOR - Do not edit by hand.\n\n'+ \
+ clsname+'CppToC::'+clsname+'CppToC() {\n'
+ const += make_cpptoc_virtual_function_assignment(header, cls, prefixname,
+ defined_names)
+ const += '}\n\n'+ \
+ '// DESTRUCTOR - Do not edit by hand.\n\n'+ \
+ clsname+'CppToC::~'+clsname+'CppToC() {\n'
+
+ if not cls.has_attrib('no_debugct_check') and not base_scoped:
+ const += ' shutdown_checker::AssertNotShutdown();\n'
+
+ const += '}\n\n'
+
+ # determine what includes are required by identifying what translation
+ # classes are being used
+ includes = format_translation_includes(header, const + resultingimpl +
+ (unwrapderived[0]
+ if base_scoped else unwrapderived))
+
+ # build the final output
+ result = get_copyright()
+
+ result += includes + '\n' + resultingimpl + '\n'
+
+ parent_sig = template_class + '<' + clsname + 'CppToC, ' + clsname + ', ' + capiname + '>'
+
+ if base_scoped:
+ const += 'template<> CefOwnPtr<'+clsname+'> '+parent_sig+'::UnwrapDerivedOwn(CefWrapperType type, '+capiname+'* s) {\n' + \
+ unwrapderived[0] + \
+ ' NOTREACHED() << "Unexpected class type: " << type;\n'+ \
+ ' return CefOwnPtr<'+clsname+'>();\n'+ \
+ '}\n\n' + \
+ 'template<> CefRawPtr<'+clsname+'> '+parent_sig+'::UnwrapDerivedRaw(CefWrapperType type, '+capiname+'* s) {\n' + \
+ unwrapderived[1] + \
+ ' NOTREACHED() << "Unexpected class type: " << type;\n'+ \
+ ' return nullptr;\n'+ \
+ '}\n\n'
+ else:
+ const += 'template<> CefRefPtr<'+clsname+'> '+parent_sig+'::UnwrapDerived(CefWrapperType type, '+capiname+'* s) {\n' + \
+ unwrapderived + \
+ ' NOTREACHED() << "Unexpected class type: " << type;\n'+ \
+ ' return nullptr;\n'+ \
+ '}\n\n'
+
+ const += 'template<> CefWrapperType ' + parent_sig + '::kWrapperType = ' + get_wrapper_type_enum(
+ clsname) + ';'
+
+ result += '\n\n' + const
+
+ return result
+
+
+def make_cpptoc_global_impl(header, impl):
+ # structure names that have already been defined
+ defined_names = header.get_defined_structs()
+
+ # retrieve the existing global function implementations
+ existing = get_function_impls(impl, 'CEF_EXPORT')
+
+ # generate global functions
+ impl = make_cpptoc_function_impl(None,
+ header.get_funcs(), existing, None,
+ defined_names, False)
+ if len(impl) > 0:
+ impl = '\n// GLOBAL FUNCTIONS - Body may be edited by hand.\n\n' + impl
+
+ includes = ''
+
+ # include required headers for global functions
+ filenames = []
+ for func in header.get_funcs():
+ filename = func.get_file_name()
+ if not filename in filenames:
+ includes += '#include "include/'+func.get_file_name()+'"\n' \
+ '#include "include/capi/'+func.get_capi_file_name()+'"\n'
+ filenames.append(filename)
+
+ # determine what includes are required by identifying what translation
+ # classes are being used
+ includes += format_translation_includes(header, impl)
+
+ # build the final output
+ result = get_copyright()
+
+ result += includes + '\n' + impl
+
+ return result
+
+
+def write_cpptoc_impl(header, clsname, dir):
+ if clsname is None:
+ # global file
+ file = dir
+ else:
+ # class file
+ # give the output file the same directory offset as the input file
+ cls = header.get_class(clsname)
+ dir = os.path.dirname(os.path.join(dir, cls.get_file_name()))
+ file = os.path.join(dir, get_capi_name(clsname[3:], False) + '_cpptoc.cc')
+
+ if path_exists(file):
+ oldcontents = read_file(file)
+ else:
+ oldcontents = ''
+
+ if clsname is None:
+ newcontents = make_cpptoc_global_impl(header, oldcontents)
+ else:
+ newcontents = make_cpptoc_class_impl(header, clsname, oldcontents)
+ return (file, newcontents)
+
+
+# test the module
+if __name__ == "__main__":
+ import sys
+
+ # verify that the correct number of command-line arguments are provided
+ if len(sys.argv) < 4:
+ sys.stderr.write('Usage: ' + sys.argv[0] +
+ ' <infile> <classname> <existing_impl>')
+ sys.exit()
+
+ # create the header object
+ header = obj_header()
+ header.add_file(sys.argv[1])
+
+ # read the existing implementation file into memory
+ try:
+ with open(sys.argv[3], 'r') as f:
+ data = f.read()
+ except IOError as e:
+ (errno, strerror) = e.args
+ raise Exception('Failed to read file ' + sys.argv[3] + ': ' + strerror)
+ else:
+ f.close()
+
+ # dump the result to stdout
+ sys.stdout.write(make_cpptoc_class_impl(header, sys.argv[2], data))
diff --git a/tools/make_ctocpp_header.py b/tools/make_ctocpp_header.py
new file mode 100644
index 00000000..708d7d61
--- /dev/null
+++ b/tools/make_ctocpp_header.py
@@ -0,0 +1,154 @@
+# Copyright (c) 2011 The Chromium Embedded Framework Authors. All rights
+# reserved. Use of this source code is governed by a BSD-style license that
+# can be found in the LICENSE file.
+
+from __future__ import absolute_import
+from cef_parser import *
+
+
+def make_function_body_block(cls):
+ impl = ' // ' + cls.get_name() + ' methods.\n'
+
+ funcs = cls.get_virtual_funcs()
+ for func in funcs:
+ impl += ' ' + func.get_cpp_proto()
+ if cls.is_client_side():
+ impl += ' override;\n'
+ else:
+ impl += ' override;\n'
+
+ return impl
+
+
+def make_function_body(header, cls):
+ impl = make_function_body_block(cls)
+
+ cur_cls = cls
+ while True:
+ parent_name = cur_cls.get_parent_name()
+ if is_base_class(parent_name):
+ break
+ else:
+ parent_cls = header.get_class(parent_name)
+ if parent_cls is None:
+ raise Exception('Class does not exist: ' + parent_name)
+ if len(impl) > 0:
+ impl += '\n'
+ impl += make_function_body_block(parent_cls)
+ cur_cls = header.get_class(parent_name)
+
+ return impl
+
+
+def make_ctocpp_header(header, clsname):
+ cls = header.get_class(clsname)
+ if cls is None:
+ raise Exception('Class does not exist: ' + clsname)
+
+ clientside = cls.is_client_side()
+
+ directory = cls.get_file_directory()
+ defname = ''
+ if not directory is None:
+ defname += directory + '_'
+ defname += get_capi_name(clsname[3:], False)
+ defname = defname.upper()
+
+ capiname = cls.get_capi_name()
+
+ result = get_copyright()
+
+ result += '#ifndef CEF_LIBCEF_DLL_CTOCPP_'+defname+'_CTOCPP_H_\n'+ \
+ '#define CEF_LIBCEF_DLL_CTOCPP_'+defname+'_CTOCPP_H_\n' + \
+ '#pragma once\n'
+
+ if clientside:
+ result += """
+#if !defined(BUILDING_CEF_SHARED)
+#error This file can be included DLL-side only
+#endif
+"""
+ else:
+ result += """
+#if !defined(WRAPPING_CEF_SHARED)
+#error This file can be included wrapper-side only
+#endif
+"""
+
+ # build the function body
+ func_body = make_function_body(header, cls)
+
+ # include standard headers
+ if func_body.find('std::map') > 0 or func_body.find('std::multimap') > 0:
+ result += '\n#include <map>'
+ if func_body.find('std::vector') > 0:
+ result += '\n#include <vector>'
+
+ # include the headers for this class
+ result += '\n#include "include/'+cls.get_file_name()+'"'+ \
+ '\n#include "include/capi/'+cls.get_capi_file_name()+'"\n'
+
+ # include headers for any forward declared classes that are not in the same file
+ declares = cls.get_forward_declares()
+ for declare in declares:
+ dcls = header.get_class(declare)
+ if dcls.get_file_name() != cls.get_file_name():
+ result += '#include "include/'+dcls.get_file_name()+'"\n' \
+ '#include "include/capi/'+dcls.get_capi_file_name()+'"\n'
+
+ base_class_name = header.get_base_class_name(clsname)
+ base_scoped = True if base_class_name == 'CefBaseScoped' else False
+ if base_scoped:
+ template_file = 'ctocpp_scoped.h'
+ template_class = 'CefCToCppScoped'
+ else:
+ template_file = 'ctocpp_ref_counted.h'
+ template_class = 'CefCToCppRefCounted'
+
+ result += '#include "libcef_dll/ctocpp/' + template_file + '"'
+ result += '\n\n// Wrap a C structure with a C++ class.\n'
+
+ if clientside:
+ result += '// This class may be instantiated and accessed DLL-side only.\n'
+ else:
+ result += '// This class may be instantiated and accessed wrapper-side only.\n'
+
+ result += 'class '+clsname+'CToCpp\n'+ \
+ ' : public ' + template_class + '<'+clsname+'CToCpp, '+clsname+', '+capiname+'> {\n'+ \
+ ' public:\n'+ \
+ ' '+clsname+'CToCpp();\n'+ \
+ ' virtual ~'+clsname+'CToCpp();\n\n'
+
+ result += func_body
+ result += '};\n\n'
+
+ result += '#endif // CEF_LIBCEF_DLL_CTOCPP_' + defname + '_CTOCPP_H_'
+
+ return result
+
+
+def write_ctocpp_header(header, clsname, dir):
+ # give the output file the same directory offset as the input file
+ cls = header.get_class(clsname)
+ dir = os.path.dirname(os.path.join(dir, cls.get_file_name()))
+ file = os.path.join(dir, get_capi_name(clsname[3:], False) + '_ctocpp.h')
+
+ newcontents = make_ctocpp_header(header, clsname)
+ return (file, newcontents)
+
+
+# test the module
+if __name__ == "__main__":
+ import sys
+
+ # verify that the correct number of command-line arguments are provided
+ if len(sys.argv) < 3:
+ sys.stderr.write('Usage: ' + sys.argv[0] + ' <infile> <classname>')
+ sys.exit()
+
+ # create the header object
+ header = obj_header()
+ header.add_file(sys.argv[1])
+
+ # dump the result to stdout
+ sys.stdout.write(make_ctocpp_header(header, sys.argv[2]))
diff --git a/tools/make_ctocpp_impl.py b/tools/make_ctocpp_impl.py
new file mode 100644
index 00000000..d17d3ec1
--- /dev/null
+++ b/tools/make_ctocpp_impl.py
@@ -0,0 +1,753 @@
+# Copyright (c) 2011 The Chromium Embedded Framework Authors. All rights
+# reserved. Use of this source code is governed by a BSD-style license that
+# can be found in the LICENSE file.
+
+from __future__ import absolute_import
+from cef_parser import *
+
+
+def make_ctocpp_impl_proto(clsname, name, func, parts):
+ const = ''
+
+ proto = 'NO_SANITIZE("cfi-icall") '
+ if clsname is None:
+ proto += 'CEF_GLOBAL ' + parts['retval'] + ' '
+ else:
+ proto += parts['retval'] + ' ' + clsname
+ if isinstance(func, obj_function_virtual):
+ proto += 'CToCpp'
+ if func.is_const():
+ const = ' const'
+
+ proto += '::'
+
+ proto += name + '(' + ', '.join(parts['args']) + ')' + const
+ return proto
+
+
+def make_ctocpp_function_impl_existing(clsname, name, func, impl):
+ notify(name + ' has manual edits')
+
+ # retrieve the C++ prototype parts
+ parts = func.get_cpp_parts(True)
+
+ changes = format_translation_changes(impl, parts)
+ if len(changes) > 0:
+ notify(name + ' prototype changed')
+
+ return make_ctocpp_impl_proto(clsname, name, func, parts)+'{'+ \
+ changes+impl['body']+'\n}\n\n'
+
+
+def make_ctocpp_function_impl_new(clsname, name, func, base_scoped):
+ # Special handling for the CefShutdown global function.
+ is_cef_shutdown = name == 'CefShutdown' and isinstance(
+ func.parent, obj_header)
+
+ # build the C++ prototype
+ parts = func.get_cpp_parts(True)
+ result = make_ctocpp_impl_proto(clsname, name, func, parts) + ' {'
+
+ if isinstance(func.parent, obj_class) and \
+ not func.parent.has_attrib('no_debugct_check') and \
+ not base_scoped:
+ result += '\n shutdown_checker::AssertNotShutdown();\n'
+
+ if isinstance(func, obj_function_virtual):
+ # determine how the struct should be referenced
+ if clsname == func.parent.get_name():
+ result += '\n ' + get_capi_name(clsname,
+ True) + '* _struct = GetStruct();'
+ else:
+ result += '\n '+func.parent.get_capi_name()+'* _struct = reinterpret_cast<'+\
+ func.parent.get_capi_name()+'*>(GetStruct());'
+
+ invalid = []
+
+ # retrieve the function arguments
+ args = func.get_arguments()
+
+ # determine the argument types
+ for arg in args:
+ if arg.get_arg_type() == 'invalid':
+ invalid.append(arg.get_name())
+
+ # retrieve the function return value
+ retval = func.get_retval()
+ retval_type = retval.get_retval_type()
+ if retval_type == 'invalid':
+ invalid.append('(return value)')
+ retval_default = ''
+ else:
+ retval_default = retval.get_retval_default(False)
+ if len(retval_default) > 0:
+ retval_default = ' ' + retval_default
+
+ # add API hash check
+ if func.has_attrib('api_hash_check'):
+ result += '\n const char* api_hash = cef_api_hash(0);'\
+ '\n if (strcmp(api_hash, CEF_API_HASH_PLATFORM)) {'\
+ '\n // The libcef API hash does not match the current header API hash.'\
+ '\n NOTREACHED();'\
+ '\n return'+retval_default+';'\
+ '\n }\n'
+
+ if isinstance(func, obj_function_virtual):
+ # add the structure size check
+ result += '\n if (CEF_MEMBER_MISSING(_struct, ' + func.get_capi_name() + ')) {'\
+ '\n return' + retval_default + ';\n'\
+ '\n }\n'
+
+ if len(invalid) > 0:
+ notify(name + ' could not be autogenerated')
+ # code could not be auto-generated
+ result += '\n // BEGIN DELETE BEFORE MODIFYING'
+ result += '\n // AUTO-GENERATED CONTENT'
+ result += '\n // COULD NOT IMPLEMENT DUE TO: ' + ', '.join(invalid)
+ result += '\n #pragma message("Warning: "__FILE__": ' + name + ' is not implemented")'
+ result += '\n // END DELETE BEFORE MODIFYING'
+ result += '\n}\n\n'
+ return result
+
+ result += '\n // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING\n'
+
+ result_len = len(result)
+
+ optional = []
+
+ # parameter verification
+ for arg in args:
+ arg_type = arg.get_arg_type()
+ arg_name = arg.get_type().get_name()
+
+ # skip optional params
+ optional_params = arg.parent.get_attrib_list('optional_param')
+ if not optional_params is None and arg_name in optional_params:
+ optional.append(arg_name)
+ continue
+
+ comment = '\n // Verify param: ' + arg_name + '; type: ' + arg_type
+
+ if arg_type == 'simple_byaddr' or arg_type == 'bool_byaddr':
+ result += comment+\
+ '\n DCHECK('+arg_name+');'\
+ '\n if (!'+arg_name+') {'\
+ '\n return'+retval_default+';'\
+ '\n }'
+ elif arg_type == 'refptr_same' or arg_type == 'refptr_diff' or \
+ arg_type == 'ownptr_same' or arg_type == 'ownptr_diff':
+ result += comment+\
+ '\n DCHECK('+arg_name+'.get());'\
+ '\n if (!'+arg_name+'.get()) {'\
+ '\n return'+retval_default+';'\
+ '\n }'
+ elif arg_type == 'rawptr_same' or arg_type == 'rawptr_diff':
+ result += comment+\
+ '\n DCHECK('+arg_name+');'\
+ '\n if (!'+arg_name+') {'\
+ '\n return'+retval_default+';'\
+ '\n }'
+ elif arg_type == 'string_byref_const':
+ result += comment+\
+ '\n DCHECK(!'+arg_name+'.empty());'\
+ '\n if ('+arg_name+'.empty()) {'\
+ '\n return'+retval_default+';'\
+ '\n }'
+
+ # check index params
+ index_params = arg.parent.get_attrib_list('index_param')
+ if not index_params is None and arg_name in index_params:
+ result += comment+\
+ '\n DCHECK_GE('+arg_name+', 0);'\
+ '\n if ('+arg_name+' < 0) {'\
+ '\n return'+retval_default+';'\
+ '\n }'
+
+ if len(optional) > 0:
+ # Wrap the comment at 80 characters.
+ str = '\n // Unverified params: ' + optional[0]
+ for name in optional[1:]:
+ str += ','
+ if len(str) + len(name) + 1 > 80:
+ result += str
+ str = '\n //'
+ str += ' ' + name
+ result += str
+
+ if len(result) != result_len:
+ result += '\n'
+ result_len = len(result)
+
+ # parameter translation
+ params = []
+ if isinstance(func, obj_function_virtual):
+ params.append('_struct')
+
+ for arg in args:
+ arg_type = arg.get_arg_type()
+ arg_name = arg.get_type().get_name()
+
+ comment = '\n // Translate param: ' + arg_name + '; type: ' + arg_type
+
+ if arg_type == 'simple_byval' or arg_type == 'simple_byaddr' or \
+ arg_type == 'bool_byval':
+ params.append(arg_name)
+ elif arg_type == 'simple_byref' or arg_type == 'simple_byref_const' or \
+ arg_type == 'struct_byref_const' or arg_type == 'struct_byref':
+ params.append('&' + arg_name)
+ elif arg_type == 'bool_byref':
+ result += comment+\
+ '\n int '+arg_name+'Int = '+arg_name+';'
+ params.append('&' + arg_name + 'Int')
+ elif arg_type == 'bool_byaddr':
+ result += comment+\
+ '\n int '+arg_name+'Int = '+arg_name+'?*'+arg_name+':0;'
+ params.append('&' + arg_name + 'Int')
+ elif arg_type == 'string_byref_const':
+ params.append(arg_name + '.GetStruct()')
+ elif arg_type == 'string_byref':
+ params.append(arg_name + '.GetWritableStruct()')
+ elif arg_type == 'refptr_same':
+ ptr_class = arg.get_type().get_ptr_type()
+ params.append(ptr_class + 'CToCpp::Unwrap(' + arg_name + ')')
+ elif arg_type == 'ownptr_same':
+ ptr_class = arg.get_type().get_ptr_type()
+ params.append(ptr_class + 'CToCpp::UnwrapOwn(std::move(' + arg_name +
+ '))')
+ elif arg_type == 'rawptr_same':
+ ptr_class = arg.get_type().get_ptr_type()
+ params.append(ptr_class + 'CToCpp::UnwrapRaw(' + arg_name + ')')
+ elif arg_type == 'refptr_diff':
+ ptr_class = arg.get_type().get_ptr_type()
+ params.append(ptr_class + 'CppToC::Wrap(' + arg_name + ')')
+ elif arg_type == 'ownptr_diff':
+ ptr_class = arg.get_type().get_ptr_type()
+ params.append(ptr_class + 'CppToC::WrapOwn(std::move(' + arg_name + '))')
+ elif arg_type == 'rawptr_diff':
+ ptr_class = arg.get_type().get_ptr_type()
+ result += comment+\
+ '\n CefOwnPtr<'+ptr_class+'CppToC> '+arg_name+'Ptr('+ptr_class+'CppToC::WrapRaw('+arg_name+'));'
+ params.append(arg_name + 'Ptr->GetStruct()')
+ elif arg_type == 'refptr_same_byref' or arg_type == 'refptr_diff_byref':
+ ptr_class = arg.get_type().get_ptr_type()
+ ptr_struct = arg.get_type().get_result_ptr_type_root()
+ if arg_type == 'refptr_same_byref':
+ assign = ptr_class + 'CToCpp::Unwrap(' + arg_name + ')'
+ else:
+ assign = ptr_class + 'CppToC::Wrap(' + arg_name + ')'
+ result += comment+\
+ '\n '+ptr_struct+'* '+arg_name+'Struct = NULL;'\
+ '\n if ('+arg_name+'.get()) {'\
+ '\n '+arg_name+'Struct = '+assign+';'\
+ '\n }'\
+ '\n '+ptr_struct+'* '+arg_name+'Orig = '+arg_name+'Struct;'
+ params.append('&' + arg_name + 'Struct')
+ elif arg_type == 'string_vec_byref' or arg_type == 'string_vec_byref_const':
+ result += comment+\
+ '\n cef_string_list_t '+arg_name+'List = cef_string_list_alloc();'\
+ '\n DCHECK('+arg_name+'List);'\
+ '\n if ('+arg_name+'List) {'\
+ '\n transfer_string_list_contents('+arg_name+', '+arg_name+'List);'\
+ '\n }'
+ params.append(arg_name + 'List')
+ elif arg_type == 'string_map_single_byref' or arg_type == 'string_map_single_byref_const':
+ result += comment+\
+ '\n cef_string_map_t '+arg_name+'Map = cef_string_map_alloc();'\
+ '\n DCHECK('+arg_name+'Map);'\
+ '\n if ('+arg_name+'Map) {'\
+ '\n transfer_string_map_contents('+arg_name+', '+arg_name+'Map);'\
+ '\n }'
+ params.append(arg_name + 'Map')
+ elif arg_type == 'string_map_multi_byref' or arg_type == 'string_map_multi_byref_const':
+ result += comment+\
+ '\n cef_string_multimap_t '+arg_name+'Multimap = cef_string_multimap_alloc();'\
+ '\n DCHECK('+arg_name+'Multimap);'\
+ '\n if ('+arg_name+'Multimap) {'\
+ '\n transfer_string_multimap_contents('+arg_name+', '+arg_name+'Multimap);'\
+ '\n }'
+ params.append(arg_name + 'Multimap')
+ elif arg_type == 'simple_vec_byref' or arg_type == 'bool_vec_byref' or \
+ arg_type == 'refptr_vec_same_byref' or arg_type == 'refptr_vec_diff_byref':
+ count_func = arg.get_attrib_count_func()
+ vec_type = arg.get_type().get_result_vector_type_root()
+ if arg_type == 'refptr_vec_same_byref':
+ ptr_class = arg.get_type().get_ptr_type()
+ assign = ptr_class + 'CToCpp::Unwrap(' + arg_name + '[i])'
+ elif arg_type == 'refptr_vec_diff_byref':
+ ptr_class = arg.get_type().get_ptr_type()
+ assign = ptr_class + 'CppToC::Wrap(' + arg_name + '[i])'
+ else:
+ assign = arg_name + '[i]'
+ result += comment+\
+ '\n size_t '+arg_name+'Size = '+arg_name+'.size();'\
+ '\n size_t '+arg_name+'Count = std::max('+count_func+'(), '+arg_name+'Size);'\
+ '\n '+vec_type+'* '+arg_name+'List = NULL;'\
+ '\n if ('+arg_name+'Count > 0) {'\
+ '\n '+arg_name+'List = new '+vec_type+'['+arg_name+'Count];'\
+ '\n DCHECK('+arg_name+'List);'\
+ '\n if ('+arg_name+'List) {'\
+ '\n memset('+arg_name+'List, 0, sizeof('+vec_type+')*'+arg_name+'Count);'\
+ '\n }'\
+ '\n if ('+arg_name+'List && '+arg_name+'Size > 0) {'\
+ '\n for (size_t i = 0; i < '+arg_name+'Size; ++i) {'\
+ '\n '+arg_name+'List[i] = '+assign+';'\
+ '\n }'\
+ '\n }'\
+ '\n }'
+ params.append('&' + arg_name + 'Count')
+ params.append(arg_name + 'List')
+ elif arg_type == 'simple_vec_byref_const' or arg_type == 'bool_vec_byref_const' or \
+ arg_type == 'refptr_vec_same_byref_const' or arg_type == 'refptr_vec_diff_byref_const' or \
+ arg_type == 'rawptr_vec_same_byref_const' or arg_type == 'rawptr_vec_diff_byref_const':
+ count_func = arg.get_attrib_count_func()
+ vec_type = arg.get_type().get_result_vector_type_root()
+ if arg_type == 'simple_vec_byref_const' or arg_type == 'bool_vec_byref_const':
+ assign = arg_name + '[i]'
+ else:
+ ptr_class = arg.get_type().get_ptr_type()
+ if arg_type == 'refptr_vec_same_byref_const':
+ assign = ptr_class + 'CToCpp::Unwrap(' + arg_name + '[i])'
+ elif arg_type == 'refptr_vec_diff_byref_const':
+ assign = ptr_class + 'CppToC::Wrap(' + arg_name + '[i])'
+ elif arg_type == 'rawptr_vec_same_byref_const':
+ assign = ptr_class + 'CToCpp::UnwrapRaw(' + arg_name + '[i])'
+ elif arg_type == 'rawptr_vec_diff_byref_const':
+ assign = ptr_class + 'CppToC::WrapRaw(' + arg_name + '[i]).release()->GetStruct()'
+ result += comment+\
+ '\n const size_t '+arg_name+'Count = '+arg_name+'.size();'\
+ '\n '+vec_type+'* '+arg_name+'List = NULL;'\
+ '\n if ('+arg_name+'Count > 0) {'\
+ '\n '+arg_name+'List = new '+vec_type+'['+arg_name+'Count];'\
+ '\n DCHECK('+arg_name+'List);'\
+ '\n if ('+arg_name+'List) {'\
+ '\n for (size_t i = 0; i < '+arg_name+'Count; ++i) {'\
+ '\n '+arg_name+'List[i] = '+assign+';'\
+ '\n }'\
+ '\n }'\
+ '\n }'
+ params.append(arg_name + 'Count')
+ params.append(arg_name + 'List')
+ else:
+ raise Exception('Unsupported argument type %s for parameter %s in %s' %
+ (arg_type, arg_name, name))
+
+ if len(result) != result_len:
+ result += '\n'
+ result_len = len(result)
+
+ if is_cef_shutdown:
+ result += '\n\n#if DCHECK_IS_ON()'\
+ '\n shutdown_checker::SetIsShutdown();'\
+ '\n#endif\n'
+
+ # execution
+ result += '\n // Execute\n '
+
+ if retval_type != 'none':
+ # has a return value
+ if retval_type == 'simple' or retval_type == 'bool':
+ result += retval.get_type().get_result_simple_type_root()
+ elif retval_type == 'string':
+ result += 'cef_string_userfree_t'
+ elif retval_type == 'refptr_same' or retval_type == 'refptr_diff' or \
+ retval_type == 'ownptr_same' or retval_type == 'ownptr_diff':
+ ptr_struct = retval.get_type().get_result_ptr_type_root()
+ result += ptr_struct + '*'
+ else:
+ raise Exception('Unsupported return type %s in %s' % (retval_type, name))
+
+ result += ' _retval = '
+
+ if isinstance(func, obj_function_virtual):
+ result += '_struct->'
+ result += func.get_capi_name() + '('
+
+ if len(params) > 0:
+ if not isinstance(func, obj_function_virtual):
+ result += '\n '
+ result += ',\n '.join(params)
+
+ result += ');\n'
+
+ result_len = len(result)
+
+ # parameter restoration
+ for arg in args:
+ arg_type = arg.get_arg_type()
+ arg_name = arg.get_type().get_name()
+
+ comment = '\n // Restore param:' + arg_name + '; type: ' + arg_type
+
+ if arg_type == 'bool_byref':
+ result += comment+\
+ '\n '+arg_name+' = '+arg_name+'Int?true:false;'
+ elif arg_type == 'bool_byaddr':
+ result += comment+\
+ '\n if ('+arg_name+') {'\
+ '\n *'+arg_name+' = '+arg_name+'Int?true:false;'\
+ '\n }'
+ elif arg_type == 'refptr_same_byref' or arg_type == 'refptr_diff_byref':
+ ptr_class = arg.get_type().get_ptr_type()
+ ptr_struct = arg.get_type().get_result_ptr_type_root()
+ if arg_type == 'refptr_same_byref':
+ assign = ptr_class + 'CToCpp::Wrap(' + arg_name + 'Struct)'
+ else:
+ assign = ptr_class + 'CppToC::Unwrap(' + arg_name + 'Struct)'
+ result += comment+\
+ '\n if ('+arg_name+'Struct) {'\
+ '\n if ('+arg_name+'Struct != '+arg_name+'Orig) {'\
+ '\n '+arg_name+' = '+assign+';'\
+ '\n }'\
+ '\n } else {'\
+ '\n '+arg_name+' = nullptr;'\
+ '\n }'
+ elif arg_type == 'string_vec_byref':
+ result += comment+\
+ '\n if ('+arg_name+'List) {'\
+ '\n '+arg_name+'.clear();'\
+ '\n transfer_string_list_contents('+arg_name+'List, '+arg_name+');'\
+ '\n cef_string_list_free('+arg_name+'List);'\
+ '\n }'
+ elif arg_type == 'string_vec_byref_const':
+ result += comment+\
+ '\n if ('+arg_name+'List) {'\
+ '\n cef_string_list_free('+arg_name+'List);'\
+ '\n }'
+ elif arg_type == 'string_map_single_byref':
+ result += comment+\
+ '\n if ('+arg_name+'Map) {'\
+ '\n '+arg_name+'.clear();'\
+ '\n transfer_string_map_contents('+arg_name+'Map, '+arg_name+');'\
+ '\n cef_string_map_free('+arg_name+'Map);'\
+ '\n }'
+ elif arg_type == 'string_map_single_byref_const':
+ result += comment+\
+ '\n if ('+arg_name+'Map) {'\
+ '\n cef_string_map_free('+arg_name+'Map);'\
+ '\n }'
+ elif arg_type == 'string_map_multi_byref':
+ result += comment+\
+ '\n if ('+arg_name+'Multimap) {'\
+ '\n '+arg_name+'.clear();'\
+ '\n transfer_string_multimap_contents('+arg_name+'Multimap, '+arg_name+');'\
+ '\n cef_string_multimap_free('+arg_name+'Multimap);'\
+ '\n }'
+ elif arg_type == 'string_map_multi_byref_const':
+ result += comment+\
+ '\n if ('+arg_name+'Multimap) {'\
+ '\n cef_string_multimap_free('+arg_name+'Multimap);'\
+ '\n }'
+ elif arg_type == 'simple_vec_byref' or arg_type == 'bool_vec_byref' or \
+ arg_type == 'refptr_vec_same_byref' or arg_type == 'refptr_vec_diff_byref':
+ count_func = arg.get_attrib_count_func()
+ vec_type = arg.get_type().get_result_vector_type_root()
+ if arg_type == 'refptr_vec_same_byref':
+ ptr_class = arg.get_type().get_ptr_type()
+ assign = ptr_class + 'CToCpp::Wrap(' + arg_name + 'List[i])'
+ elif arg_type == 'refptr_vec_diff_byref':
+ ptr_class = arg.get_type().get_ptr_type()
+ assign = ptr_class + 'CppToC::Unwrap(' + arg_name + 'List[i])'
+ elif arg_type == 'bool_vec_byref':
+ assign = arg_name + 'List[i]?true:false'
+ else:
+ assign = arg_name + 'List[i]'
+ result += comment+\
+ '\n '+arg_name+'.clear();'\
+ '\n if ('+arg_name+'Count > 0 && '+arg_name+'List) {'\
+ '\n for (size_t i = 0; i < '+arg_name+'Count; ++i) {'\
+ '\n '+arg_name+'.push_back('+assign+');'\
+ '\n }'\
+ '\n delete [] '+arg_name+'List;'\
+ '\n }'
+ elif arg_type == 'simple_vec_byref_const' or arg_type == 'bool_vec_byref_const' or \
+ arg_type == 'refptr_vec_same_byref_const' or arg_type == 'refptr_vec_diff_byref_const' or \
+ arg_type == 'rawptr_vec_same_byref_const' or arg_type == 'rawptr_vec_diff_byref_const':
+ result += comment
+ if arg_type == 'rawptr_vec_diff_byref_const':
+ result += '\n if ('+arg_name+'Count > 0) {'\
+ '\n for (size_t i = 0; i < '+arg_name+'Count; ++i) {'\
+ '\n delete '+ptr_class+'CppToC::GetWrapper('+arg_name+'List[i]);'\
+ '\n }'\
+ '\n }'
+ result += '\n if ('+arg_name+'List) {'\
+ '\n delete [] '+arg_name+'List;'\
+ '\n }'
+
+ if len(result) != result_len:
+ result += '\n'
+ result_len = len(result)
+
+ if len(result) != result_len:
+ result += '\n'
+ result_len = len(result)
+
+ # return translation
+ if retval_type != 'none':
+ # has a return value
+ result += '\n // Return type: ' + retval_type
+ if retval_type == 'simple':
+ result += '\n return _retval;'
+ elif retval_type == 'bool':
+ result += '\n return _retval?true:false;'
+ elif retval_type == 'string':
+ result += '\n CefString _retvalStr;'\
+ '\n _retvalStr.AttachToUserFree(_retval);'\
+ '\n return _retvalStr;'
+ elif retval_type == 'refptr_same' or retval_type == 'ownptr_same':
+ ptr_class = retval.get_type().get_ptr_type()
+ result += '\n return ' + ptr_class + 'CToCpp::Wrap(_retval);'
+ elif retval_type == 'refptr_diff':
+ ptr_class = retval.get_type().get_ptr_type()
+ result += '\n return ' + ptr_class + 'CppToC::Unwrap(_retval);'
+ elif retval_type == 'ownptr_diff':
+ ptr_class = retval.get_type().get_ptr_type()
+ result += '\n return ' + ptr_class + 'CppToC::UnwrapOwn(_retval);'
+ else:
+ raise Exception('Unsupported return type %s in %s' % (retval_type, name))
+
+ if len(result) != result_len:
+ result += '\n'
+
+ result += '}\n\n'
+ return result
+
+
+def make_ctocpp_function_impl(clsname, funcs, existing, base_scoped):
+ impl = ''
+
+ for func in funcs:
+ name = func.get_name()
+ value = get_next_function_impl(existing, name)
+ if not value is None \
+ and value['body'].find('// AUTO-GENERATED CONTENT') < 0:
+ # an implementation exists that was not auto-generated
+ impl += make_ctocpp_function_impl_existing(clsname, name, func, value)
+ else:
+ impl += make_ctocpp_function_impl_new(clsname, name, func, base_scoped)
+
+ return impl
+
+
+def make_ctocpp_virtual_function_impl(header, cls, existing, base_scoped):
+ impl = make_ctocpp_function_impl(cls.get_name(),
+ cls.get_virtual_funcs(), existing,
+ base_scoped)
+
+ cur_cls = cls
+ while True:
+ parent_name = cur_cls.get_parent_name()
+ if is_base_class(parent_name):
+ break
+ else:
+ parent_cls = header.get_class(parent_name)
+ if parent_cls is None:
+ raise Exception('Class does not exist: ' + parent_name)
+ impl += make_ctocpp_function_impl(cls.get_name(),
+ parent_cls.get_virtual_funcs(),
+ existing, base_scoped)
+ cur_cls = header.get_class(parent_name)
+
+ return impl
+
+
+def make_ctocpp_unwrap_derived(header, cls, base_scoped):
+ # identify all classes that derive from cls
+ derived_classes = []
+ clsname = cls.get_name()
+ allclasses = header.get_classes()
+ for cur_cls in allclasses:
+ if cur_cls.get_name() == clsname:
+ continue
+ if cur_cls.has_parent(clsname):
+ derived_classes.append(cur_cls.get_name())
+
+ derived_classes = sorted(derived_classes)
+
+ if base_scoped:
+ impl = ['', '']
+ for clsname in derived_classes:
+ impl[0] += ' if (type == '+get_wrapper_type_enum(clsname)+') {\n'+\
+ ' return reinterpret_cast<'+get_capi_name(cls.get_name(), True)+'*>('+\
+ clsname+'CToCpp::UnwrapOwn(CefOwnPtr<'+clsname+'>(reinterpret_cast<'+clsname+'*>(c.release()))));\n'+\
+ ' }\n'
+ impl[1] += ' if (type == '+get_wrapper_type_enum(clsname)+') {\n'+\
+ ' return reinterpret_cast<'+get_capi_name(cls.get_name(), True)+'*>('+\
+ clsname+'CToCpp::UnwrapRaw(CefRawPtr<'+clsname+'>(reinterpret_cast<'+clsname+'*>(c))));\n'+\
+ ' }\n'
+ else:
+ impl = ''
+ for clsname in derived_classes:
+ impl += ' if (type == '+get_wrapper_type_enum(clsname)+') {\n'+\
+ ' return reinterpret_cast<'+get_capi_name(cls.get_name(), True)+'*>('+\
+ clsname+'CToCpp::Unwrap(reinterpret_cast<'+clsname+'*>(c)));\n'+\
+ ' }\n'
+ return impl
+
+
+def make_ctocpp_class_impl(header, clsname, impl):
+ cls = header.get_class(clsname)
+ if cls is None:
+ raise Exception('Class does not exist: ' + clsname)
+
+ capiname = cls.get_capi_name()
+
+ # retrieve the existing virtual function implementations
+ existing = get_function_impls(impl, clsname + 'CToCpp::')
+
+ base_class_name = header.get_base_class_name(clsname)
+ base_scoped = True if base_class_name == 'CefBaseScoped' else False
+ if base_scoped:
+ template_class = 'CefCToCppScoped'
+ else:
+ template_class = 'CefCToCppRefCounted'
+
+ # generate virtual functions
+ virtualimpl = make_ctocpp_virtual_function_impl(header, cls, existing,
+ base_scoped)
+ if len(virtualimpl) > 0:
+ virtualimpl = '\n// VIRTUAL METHODS - Body may be edited by hand.\n\n' + virtualimpl
+
+ # retrieve the existing static function implementations
+ existing = get_function_impls(impl, clsname + '::')
+
+ # generate static functions
+ staticimpl = make_ctocpp_function_impl(clsname,
+ cls.get_static_funcs(), existing,
+ base_scoped)
+ if len(staticimpl) > 0:
+ staticimpl = '\n// STATIC METHODS - Body may be edited by hand.\n\n' + staticimpl
+
+ resultingimpl = staticimpl + virtualimpl
+
+ # any derived classes can be unwrapped
+ unwrapderived = make_ctocpp_unwrap_derived(header, cls, base_scoped)
+
+ const = '// CONSTRUCTOR - Do not edit by hand.\n\n'+ \
+ clsname+'CToCpp::'+clsname+'CToCpp() {\n'+ \
+ '}\n\n'+ \
+ '// DESTRUCTOR - Do not edit by hand.\n\n'+ \
+ clsname+'CToCpp::~'+clsname+'CToCpp() {\n'
+
+ if not cls.has_attrib('no_debugct_check') and not base_scoped:
+ const += ' shutdown_checker::AssertNotShutdown();\n'
+
+ const += '}\n\n'
+
+ # determine what includes are required by identifying what translation
+ # classes are being used
+ includes = format_translation_includes(header, const + resultingimpl +
+ (unwrapderived[0]
+ if base_scoped else unwrapderived))
+
+ # build the final output
+ result = get_copyright()
+
+ result += includes + '\n' + resultingimpl + '\n'
+
+ parent_sig = template_class + '<' + clsname + 'CToCpp, ' + clsname + ', ' + capiname + '>'
+
+ if base_scoped:
+ const += 'template<> '+capiname+'* '+parent_sig+'::UnwrapDerivedOwn(CefWrapperType type, CefOwnPtr<'+clsname+'> c) {\n'+ \
+ unwrapderived[0] + \
+ ' NOTREACHED() << "Unexpected class type: " << type;\n'+ \
+ ' return nullptr;\n'+ \
+ '}\n\n' + \
+ 'template<> '+capiname+'* '+parent_sig+'::UnwrapDerivedRaw(CefWrapperType type, CefRawPtr<'+clsname+'> c) {\n'+ \
+ unwrapderived[1] + \
+ ' NOTREACHED() << "Unexpected class type: " << type;\n'+ \
+ ' return nullptr;\n'+ \
+ '}\n\n'
+ else:
+ const += 'template<> '+capiname+'* '+parent_sig+'::UnwrapDerived(CefWrapperType type, '+clsname+'* c) {\n'+ \
+ unwrapderived + \
+ ' NOTREACHED() << "Unexpected class type: " << type;\n'+ \
+ ' return nullptr;\n'+ \
+ '}\n\n'
+
+ const += 'template<> CefWrapperType ' + parent_sig + '::kWrapperType = ' + get_wrapper_type_enum(
+ clsname) + ';'
+
+ result += const
+
+ return result
+
+
+def make_ctocpp_global_impl(header, impl):
+ # retrieve the existing global function implementations
+ existing = get_function_impls(impl, 'CEF_GLOBAL')
+
+ # generate static functions
+ impl = make_ctocpp_function_impl(None, header.get_funcs(), existing, False)
+ if len(impl) > 0:
+ impl = '\n// GLOBAL METHODS - Body may be edited by hand.\n\n' + impl
+
+ includes = ''
+
+ # include required headers for global functions
+ filenames = []
+ for func in header.get_funcs():
+ filename = func.get_file_name()
+ if not filename in filenames:
+ includes += '#include "include/'+func.get_file_name()+'"\n' \
+ '#include "include/capi/'+func.get_capi_file_name()+'"\n'
+ filenames.append(filename)
+
+ # determine what includes are required by identifying what translation
+ # classes are being used
+ includes += format_translation_includes(header, impl)
+
+ # build the final output
+ result = get_copyright()
+
+ result += includes + '\n// Define used to facilitate parsing.\n#define CEF_GLOBAL\n\n' + impl
+
+ return result
+
+
+def write_ctocpp_impl(header, clsname, dir):
+ if clsname is None:
+ # global file
+ file = dir
+ else:
+ # class file
+ # give the output file the same directory offset as the input file
+ cls = header.get_class(clsname)
+ dir = os.path.dirname(os.path.join(dir, cls.get_file_name()))
+ file = os.path.join(dir, get_capi_name(clsname[3:], False) + '_ctocpp.cc')
+
+ if path_exists(file):
+ oldcontents = read_file(file)
+ else:
+ oldcontents = ''
+
+ if clsname is None:
+ newcontents = make_ctocpp_global_impl(header, oldcontents)
+ else:
+ newcontents = make_ctocpp_class_impl(header, clsname, oldcontents)
+ return (file, newcontents)
+
+
+# test the module
+if __name__ == "__main__":
+ import sys
+
+ # verify that the correct number of command-line arguments are provided
+ if len(sys.argv) < 4:
+ sys.stderr.write('Usage: ' + sys.argv[0] +
+ ' <infile> <classname> <existing_impl>\n')
+ sys.exit()
+
+ # create the header object
+ header = obj_header()
+ header.add_file(sys.argv[1])
+
+ # read the existing implementation file into memory
+ try:
+ with open(sys.argv[3], 'r') as f:
+ data = f.read()
+ except IOError as e:
+ (errno, strerror) = e.args
+ raise Exception('Failed to read file ' + sys.argv[3] + ': ' + strerror)
+
+ # dump the result to stdout
+ sys.stdout.write(make_ctocpp_class_impl(header, sys.argv[2], data))
diff --git a/tools/make_distrib.bat b/tools/make_distrib.bat
new file mode 100644
index 00000000..aea1ee54
--- /dev/null
+++ b/tools/make_distrib.bat
@@ -0,0 +1,2 @@
+@echo off
+python.bat %~dp0\make_distrib.py --output-dir %~dp0\..\binary_distrib\ %*
diff --git a/tools/make_distrib.py b/tools/make_distrib.py
new file mode 100644
index 00000000..7122fae1
--- /dev/null
+++ b/tools/make_distrib.py
@@ -0,0 +1,1310 @@
+# Copyright (c) 2011 The Chromium Embedded Framework Authors. All rights
+# reserved. Use of this source code is governed by a BSD-style license that
+# can be found in the LICENSE file.
+
+from __future__ import absolute_import
+from __future__ import print_function
+from cef_version import VersionFormatter
+from date_util import *
+from exec_util import exec_cmd
+from file_util import *
+import git_util as git
+from io import open
+from make_cmake import process_cmake_template
+from optparse import OptionParser
+import os
+import re
+import shlex
+import subprocess
+import sys
+import tarfile
+import zipfile
+
+
+def create_zip_archive(input_dir):
+ """ Creates a zip archive of the specified input directory. """
+ zip_file = input_dir + '.zip'
+ zf = zipfile.ZipFile(zip_file, 'w', zipfile.ZIP_DEFLATED, True)
+
+ def addDir(dir):
+ for f in os.listdir(dir):
+ full_path = os.path.join(dir, f)
+ if os.path.isdir(full_path):
+ addDir(full_path)
+ else:
+ zf.write(full_path, os.path.relpath(full_path, \
+ os.path.join(input_dir, os.pardir)))
+
+ addDir(input_dir)
+ zf.close()
+
+
+def create_tar_archive(input_dir, format):
+ """ Creates a tar archive of the specified input directory. """
+ # Supported formats include "gz" and "bz2".
+ tar_file = input_dir + '.tar.' + format
+ tf = tarfile.open(tar_file, "w:" + format)
+ # The default tar format changed from GNU_FORMAT to PAX_FORMAT in Python 3.8.
+ # However, PAX_FORMAT generates additional @PaxHeader entries and truncates file
+ # names on Windows, so we'll stick with the previous default.
+ tf.format = tarfile.GNU_FORMAT
+ tf.add(input_dir, arcname=os.path.basename(input_dir))
+ tf.close()
+
+
+def create_7z_archive(input_dir, format):
+ """ Creates a 7z archive of the specified input directory. """
+ # CEF_COMMAND_7ZIP might be "c:\Program Files (x86)\7Zip\7z.exe" or /usr/bin/7za
+ # or simply 7z if the user knows that it's in the PATH var. Supported formats
+ # depend on the 7za version -- check the 7-zip documentation for details.
+ command = os.environ['CEF_COMMAND_7ZIP']
+ working_dir = os.path.abspath(os.path.join(input_dir, os.pardir))
+
+ tar_file = None
+ if format in ('xz', 'gzip', 'bzip2'):
+ # These formats only support one file per archive. Create a tar file first.
+ tar_file = input_dir + '.tar'
+ run('"%s" a -ttar -y %s %s' % (command, tar_file, input_dir), working_dir)
+ zip_file = tar_file + '.' + format
+ zip_input = tar_file
+ else:
+ zip_file = input_dir + '.' + format
+ zip_input = input_dir
+
+ # Create the compressed archive.
+ run('"%s" a -t%s -y %s %s' % (command, format, zip_file, zip_input),
+ working_dir)
+
+ if not tar_file is None:
+ remove_file(tar_file)
+
+
+def create_output_dir(name, parent_dir):
+ """ Creates an output directory and adds the path to the archive list. """
+ output_dir = os.path.abspath(os.path.join(parent_dir, name))
+ remove_dir(output_dir, options.quiet)
+ make_dir(output_dir, options.quiet)
+ archive_dirs.append(output_dir)
+ return output_dir
+
+
+def get_readme_component(name):
+ """ Loads a README file component. """
+ paths = []
+ # platform directory
+ if platform == 'windows':
+ platform_cmp = 'win'
+ elif platform == 'mac':
+ platform_cmp = 'mac'
+ elif platform == 'linux':
+ platform_cmp = 'linux'
+ paths.append(os.path.join(script_dir, 'distrib', platform_cmp))
+
+ # shared directory
+ paths.append(os.path.join(script_dir, 'distrib'))
+
+ # load the file if it exists
+ for path in paths:
+ file = os.path.join(path, 'README.' + name + '.txt')
+ if path_exists(file):
+ return read_file(file)
+
+ raise Exception('Readme component not found: ' + name)
+
+
+def create_readme():
+ """ Creates the README.TXT file. """
+ # gather the components
+ header_data = get_readme_component('header')
+ mode_data = get_readme_component(mode)
+ redistrib_data = get_readme_component('redistrib')
+ footer_data = get_readme_component('footer')
+
+ # format the file
+ data = header_data + '\n\n' + mode_data
+ if mode != 'sandbox':
+ data += '\n\n' + redistrib_data
+ data += '\n\n' + footer_data
+ data = data.replace('$CEF_URL$', cef_url)
+ data = data.replace('$CEF_REV$', cef_rev)
+ data = data.replace('$CEF_VER$', cef_ver)
+ data = data.replace('$CHROMIUM_URL$', chromium_url)
+ data = data.replace('$CHROMIUM_REV$', chromium_rev)
+ data = data.replace('$CHROMIUM_VER$', chromium_ver)
+ data = data.replace('$DATE$', date)
+
+ if platform == 'windows':
+ platform_str = 'Windows'
+ elif platform == 'mac':
+ platform_str = 'MacOS'
+ elif platform == 'linux':
+ platform_str = 'Linux'
+
+ data = data.replace('$PLATFORM$', platform_str)
+
+ if mode == 'standard':
+ distrib_type = 'Standard'
+ distrib_desc = 'This distribution contains all components necessary to build and distribute an\n' \
+ 'application using CEF on the ' + platform_str + ' platform. Please see the LICENSING\n' \
+ 'section of this document for licensing terms and conditions.'
+ elif mode == 'minimal':
+ distrib_type = 'Minimal'
+ distrib_desc = 'This distribution contains the minimial components necessary to build and\n' \
+ 'distribute an application using CEF on the ' + platform_str + ' platform. Please see\n' \
+ 'the LICENSING section of this document for licensing terms and conditions.'
+ elif mode == 'client':
+ distrib_type = 'Client'
+ if platform == 'linux':
+ client_app = 'cefsimple'
+ else:
+ client_app = 'cefclient'
+ distrib_desc = 'This distribution contains a release build of the ' + client_app + ' sample application\n' \
+ 'for the ' + platform_str + ' platform. Please see the LICENSING section of this document for\n' \
+ 'licensing terms and conditions.'
+ elif mode == 'sandbox':
+ distrib_type = 'Sandbox'
+ distrib_desc = 'This distribution contains only the cef_sandbox static library. Please see\n' \
+ 'the LICENSING section of this document for licensing terms and conditions.'
+
+ data = data.replace('$DISTRIB_TYPE$', distrib_type)
+ data = data.replace('$DISTRIB_DESC$', distrib_desc)
+
+ write_file(os.path.join(output_dir, 'README.txt'), data)
+ if not options.quiet:
+ sys.stdout.write('Creating README.TXT file.\n')
+
+
+def copy_gtest(tests_dir):
+ """ Copy GTest files to the expected directory structure. """
+ if not options.quiet:
+ sys.stdout.write('Building gtest directory structure.\n')
+
+ src_gtest_dir = os.path.join(cef_dir, 'tools', 'distrib', 'gtest')
+ target_gtest_dir = os.path.join(tests_dir, 'gtest')
+
+ # gtest header file at tests/gtest/include/gtest/gtest.h
+ target_gtest_header_dir = os.path.join(target_gtest_dir, 'include', 'gtest')
+ make_dir(target_gtest_header_dir, options.quiet)
+ copy_file(
+ os.path.join(src_gtest_dir, 'gtest.h'), target_gtest_header_dir,
+ options.quiet)
+
+ # gtest source file at tests/gtest/src/gtest-all.cc
+ target_gtest_cpp_dir = os.path.join(target_gtest_dir, 'src')
+ make_dir(target_gtest_cpp_dir, options.quiet)
+ copy_file(
+ os.path.join(src_gtest_dir, 'gtest-all.cc'), target_gtest_cpp_dir,
+ options.quiet)
+
+ # gtest LICENSE file at tests/gtest/LICENSE
+ copy_file(
+ os.path.join(src_gtest_dir, 'LICENSE'), target_gtest_dir, options.quiet)
+
+ # CEF README file at tests/gtest/README.cef
+ copy_file(
+ os.path.join(src_gtest_dir, 'README.cef'),
+ os.path.join(target_gtest_dir, 'README.cef'), options.quiet)
+
+ # Copy tests/gtest/teamcity files
+ copy_dir(
+ os.path.join(cef_dir, 'tests', 'gtest', 'teamcity'),
+ os.path.join(target_gtest_dir, 'teamcity'), options.quiet)
+
+
+def transfer_doxyfile(dst_dir, quiet):
+ """ Transfer and post-process the Doxyfile. """
+ src_file = os.path.join(cef_dir, 'Doxyfile')
+ if os.path.isfile(src_file):
+ data = read_file(src_file)
+ data = data.replace("$(PROJECT_NUMBER)", cef_ver)
+ write_file(os.path.join(dst_dir, 'Doxyfile'), data)
+ if not quiet:
+ sys.stdout.write('Creating Doxyfile file.\n')
+
+
+def transfer_gypi_files(src_dir, gypi_paths, gypi_path_prefix, dst_dir, quiet):
+ """ Transfer files from one location to another. """
+ for path in gypi_paths:
+ src = os.path.join(src_dir, path)
+ dst = os.path.join(dst_dir, path.replace(gypi_path_prefix, ''))
+ dst_path = os.path.dirname(dst)
+ make_dir(dst_path, quiet)
+ copy_file(src, dst, quiet)
+
+
+def normalize_headers(file, new_path=''):
+ """ Normalize headers post-processing. Remove the path component from any
+ project include directives. """
+ data = read_file(file)
+ data = re.sub(r'''#include \"(?!include\/)[a-zA-Z0-9_\/]+\/+([a-zA-Z0-9_\.]+)\"''', \
+ "// Include path modified for CEF Binary Distribution.\n#include \""+new_path+"\\1\"", data)
+ write_file(file, data)
+
+
+def eval_transfer_file(cef_dir, script_dir, transfer_cfg, output_dir, quiet):
+ """ Transfer files based on the specified configuration. """
+ if not path_exists(transfer_cfg):
+ return
+
+ configs = eval_file(transfer_cfg)
+ for cfg in configs:
+ dst = os.path.join(output_dir, cfg['target'])
+
+ # perform a copy if source is specified
+ if not cfg['source'] is None:
+ src = os.path.join(cef_dir, cfg['source'])
+ dst_path = os.path.dirname(dst)
+ make_dir(dst_path, quiet)
+ copy_file(src, dst, quiet)
+
+ # place a readme file in the destination directory
+ readme = os.path.join(dst_path, 'README-TRANSFER.txt')
+ if not path_exists(readme):
+ copy_file(
+ os.path.join(script_dir, 'distrib/README-TRANSFER.txt'), readme)
+
+ str = cfg['source'] + "\n"
+ with open(readme, 'a', encoding='utf-8') as fp:
+ if sys.version_info.major == 2:
+ fp.write(str.decode('utf-8'))
+ else:
+ fp.write(str)
+
+ # perform any required post-processing
+ if 'post-process' in cfg:
+ post = cfg['post-process']
+ if post == 'normalize_headers':
+ new_path = ''
+ if 'new_header_path' in cfg:
+ new_path = cfg['new_header_path']
+ normalize_headers(dst, new_path)
+
+
+def transfer_files(cef_dir, script_dir, transfer_cfg_dir, mode, output_dir,
+ quiet):
+ # Non-mode-specific transfers.
+ transfer_cfg = os.path.join(transfer_cfg_dir, 'transfer.cfg')
+ eval_transfer_file(cef_dir, script_dir, transfer_cfg, output_dir, quiet)
+ # Mode-specific transfers.
+ transfer_cfg = os.path.join(transfer_cfg_dir, 'transfer_%s.cfg' % mode)
+ eval_transfer_file(cef_dir, script_dir, transfer_cfg, output_dir, quiet)
+
+
+# |paths| is a list of dictionary values with the following keys:
+# path [required] Input file or directory path relative to |build_dir|.
+# By default this will also be the output path relative
+# to |dst_dir|.
+# out_path [optional] Override the output path relative to |dst_dir|.
+# conditional [optional] Set to True if the path is conditional on build
+# settings. Missing conditional paths will not be
+# treated as an error.
+# delete [optional] Glob pattern of files to delete after the copy.
+def copy_files_list(build_dir, dst_dir, paths):
+ ''' Copy the files listed in |paths| from |build_dir| to |dst_dir|. '''
+ for entry in paths:
+ source_path = os.path.join(build_dir, entry['path'])
+ if os.path.exists(source_path):
+ target_path = os.path.join(dst_dir, entry['out_path']
+ if 'out_path' in entry else entry['path'])
+ make_dir(os.path.dirname(target_path), options.quiet)
+ if os.path.isdir(source_path):
+ copy_dir(source_path, target_path, options.quiet)
+ if 'delete' in entry:
+ for delete_path in get_files(
+ os.path.join(target_path, entry['delete'])):
+ if not os.path.isdir(delete_path):
+ remove_file(delete_path, options.quiet)
+ else:
+ raise Exception('Refusing to delete directory: %s' % delete_path)
+ else:
+ copy_file(source_path, target_path, options.quiet)
+ else:
+ if 'conditional' in entry and entry['conditional']:
+ sys.stdout.write('Missing conditional path: %s.\n' % source_path)
+ else:
+ raise Exception('Missing required path: %s' % source_path)
+
+
+def get_exported_symbols(file):
+ """ Returns the global symbols exported by |file|. """
+ symbols = []
+
+ # Each symbol line has a value like:
+ # 0000000000000000 T _cef_sandbox_initialize
+ cmdline = 'nm -g -U %s' % file
+ result = exec_cmd(cmdline, os.path.join(cef_dir, 'tools'))
+ if len(result['err']) > 0:
+ raise Exception('ERROR: nm failed: %s' % result['err'])
+ for line in result['out'].split('\n'):
+ if line.find(' T ') < 0:
+ continue
+ symbol = line[line.rfind(' ') + 1:]
+ symbols.append(symbol)
+
+ return symbols
+
+
+def get_undefined_symbols(file):
+ """ Returns the undefined symbols imported by |file|. """
+ symbols = []
+
+ # Each symbol line has a value like:
+ # cef_sandbox.a:cef_sandbox.o: _memcpy
+ cmdline = 'nm -u -A %s' % file
+ result = exec_cmd(cmdline, os.path.join(cef_dir, 'tools'))
+ if len(result['err']) > 0:
+ raise Exception('ERROR: nm failed: %s' % result['err'])
+ for line in result['out'].split('\n'):
+ if line.find(': ') < 0:
+ continue
+ symbol = line[line.rfind(': ') + 2:]
+ symbols.append(symbol)
+
+ return symbols
+
+
+def combine_libs(platform, build_dir, libs, dest_lib):
+ """ Combine multiple static libraries into a single static library. """
+ intermediate_obj = None
+ if platform == 'windows':
+ cmdline = 'msvs_env.bat win%s "%s" combine_libs.py -o "%s"' % (
+ platform_arch, sys.executable, dest_lib)
+ elif platform == 'mac':
+ # Find CEF_EXPORT symbols from libcef_sandbox.a (include/cef_sandbox_mac.h)
+ # Export only symbols that include these strings.
+ symbol_match = [
+ '_cef_', # C symbols
+ 'Cef', # C++ symbols
+ ]
+
+ print('Finding exported symbols...')
+ assert 'libcef_sandbox.a' in libs[0], libs[0]
+ symbols = []
+ for symbol in get_exported_symbols(os.path.join(build_dir, libs[0])):
+ for match in symbol_match:
+ if symbol.find(match) >= 0:
+ symbols.append(symbol)
+ break
+ assert len(symbols) > 0
+
+ # Create an intermediate object file that combines all other object files.
+ # Symbols not identified above will be made private (local).
+ intermediate_obj = os.path.splitext(dest_lib)[0] + '.o'
+ arch = 'arm64' if options.arm64build else 'x86_64'
+ cmdline = 'ld -arch %s -r -o "%s"' % (arch, intermediate_obj)
+ for symbol in symbols:
+ cmdline += ' -exported_symbol %s' % symbol
+
+ for lib in libs:
+ lib_path = os.path.join(build_dir, lib)
+ for path in get_files(lib_path): # Expand wildcards in |lib_path|.
+ if not path_exists(path):
+ raise Exception('File not found: ' + path)
+ cmdline += ' "%s"' % path
+ run(cmdline, os.path.join(cef_dir, 'tools'))
+
+ if not intermediate_obj is None:
+ # Create an archive file containing the new object file.
+ cmdline = 'libtool -static -o "%s" "%s"' % (dest_lib, intermediate_obj)
+ run(cmdline, os.path.join(cef_dir, 'tools'))
+ remove_file(intermediate_obj)
+
+ # Verify that only the expected symbols are exported from the archive file.
+ print('Verifying exported symbols...')
+ result_symbols = get_exported_symbols(dest_lib)
+ if set(symbols) != set(result_symbols):
+ print('Expected', symbols)
+ print('Got', result_symbols)
+ raise Exception('Failure verifying exported symbols')
+
+ # Verify that no C++ symbols are imported by the archive file. If the
+ # archive imports C++ symbols and the client app links an incompatible C++
+ # library, the result will be undefined behavior.
+ # For example, to avoid importing libc++ symbols the cef_sandbox target
+ # should have a dependency on libc++abi. This dependency can be verified
+ # with the following command:
+ # gn path out/[config] //cef:cef_sandbox //buildtools/third_party/libc++abi
+ print('Verifying imported (undefined) symbols...')
+ undefined_symbols = get_undefined_symbols(dest_lib)
+ cpp_symbols = list(
+ filter(lambda symbol: symbol.startswith('__Z'), undefined_symbols))
+ if cpp_symbols:
+ print('Found C++ symbols:', cpp_symbols)
+ raise Exception('Failure verifying imported (undefined) symbols')
+
+
+def run(command_line, working_dir):
+ """ Run a command. """
+ sys.stdout.write('-------- Running "'+command_line+'" in "'+\
+ working_dir+'"...'+"\n")
+ args = shlex.split(command_line.replace('\\', '\\\\'))
+ return subprocess.check_call(
+ args, cwd=working_dir, env=os.environ, shell=(sys.platform == 'win32'))
+
+
+def print_error(msg):
+ print('Error: %s\nSee --help for usage.' % msg)
+
+
+# cannot be loaded as a module
+if __name__ != "__main__":
+ sys.stderr.write('This file cannot be loaded as a module!')
+ sys.exit()
+
+# parse command-line options
+disc = """
+This utility builds the CEF Binary Distribution.
+"""
+
+parser = OptionParser(description=disc)
+parser.add_option(
+ '--output-dir',
+ dest='outputdir',
+ metavar='DIR',
+ help='output directory [required]')
+parser.add_option(
+ '--distrib-subdir',
+ dest='distribsubdir',
+ help='name of the subdirectory for the distribution',
+ default='')
+parser.add_option(
+ '--distrib-subdir-suffix',
+ dest='distribsubdirsuffix',
+ help='suffix added to name of the subdirectory for the distribution',
+ default='')
+parser.add_option(
+ '--allow-partial',
+ action='store_true',
+ dest='allowpartial',
+ default=False,
+ help='allow creation of partial distributions')
+parser.add_option(
+ '--no-symbols',
+ action='store_true',
+ dest='nosymbols',
+ default=False,
+ help='don\'t create symbol files')
+parser.add_option(
+ '--no-docs',
+ action='store_true',
+ dest='nodocs',
+ default=False,
+ help='don\'t create documentation')
+parser.add_option(
+ '--no-archive',
+ action='store_true',
+ dest='noarchive',
+ default=False,
+ help='don\'t create archives for output directories')
+parser.add_option(
+ '--ninja-build',
+ action='store_true',
+ dest='ninjabuild',
+ default=False,
+ help='build was created using ninja')
+parser.add_option(
+ '--x64-build',
+ action='store_true',
+ dest='x64build',
+ default=False,
+ help='create a 64-bit binary distribution')
+parser.add_option(
+ '--arm-build',
+ action='store_true',
+ dest='armbuild',
+ default=False,
+ help='create an ARM binary distribution (Linux only)')
+parser.add_option(
+ '--arm64-build',
+ action='store_true',
+ dest='arm64build',
+ default=False,
+ help='create an ARM64 binary distribution (Linux only)')
+parser.add_option(
+ '--minimal',
+ action='store_true',
+ dest='minimal',
+ default=False,
+ help='include only release build binary files')
+parser.add_option(
+ '--client',
+ action='store_true',
+ dest='client',
+ default=False,
+ help='include only the sample application')
+parser.add_option(
+ '--sandbox',
+ action='store_true',
+ dest='sandbox',
+ default=False,
+ help='include only the cef_sandbox static library (macOS and Windows only)')
+parser.add_option(
+ '--ozone',
+ action='store_true',
+ dest='ozone',
+ default=False,
+ help='include ozone build related files (Linux only)')
+parser.add_option(
+ '-q',
+ '--quiet',
+ action='store_true',
+ dest='quiet',
+ default=False,
+ help='do not output detailed status information')
+(options, args) = parser.parse_args()
+
+# Test the operating system.
+platform = ''
+if sys.platform == 'win32':
+ platform = 'windows'
+elif sys.platform == 'darwin':
+ platform = 'mac'
+elif sys.platform.startswith('linux'):
+ platform = 'linux'
+
+# the outputdir option is required
+if options.outputdir is None:
+ print_error('--output-dir is required.')
+ sys.exit()
+
+if options.minimal and options.client:
+ print_error('Cannot specify both --minimal and --client.')
+ sys.exit()
+
+if options.x64build + options.armbuild + options.arm64build > 1:
+ print_error('Invalid combination of build options.')
+ sys.exit()
+
+if options.armbuild and platform != 'linux':
+ print_error('--arm-build is only supported on Linux.')
+ sys.exit()
+
+if options.sandbox and not platform in ('mac', 'windows'):
+ print_error('--sandbox is only supported on macOS and Windows.')
+ sys.exit()
+
+if not options.ninjabuild:
+ print_error('--ninja-build is required.')
+ sys.exit()
+
+if options.ozone and platform != 'linux':
+ print_error('--ozone is only supported on Linux.')
+ sys.exit()
+
+# script directory
+script_dir = os.path.dirname(__file__)
+
+# CEF root directory
+cef_dir = os.path.abspath(os.path.join(script_dir, os.pardir))
+
+# src directory
+src_dir = os.path.abspath(os.path.join(cef_dir, os.pardir))
+
+if not git.is_checkout(cef_dir):
+ raise Exception('Not a valid checkout: %s' % (cef_dir))
+
+# retrieve information for CEF
+cef_url = git.get_url(cef_dir)
+cef_rev = git.get_hash(cef_dir)
+cef_commit_number = git.get_commit_number(cef_dir)
+
+if not git.is_checkout(src_dir):
+ raise Exception('Not a valid checkout: %s' % (src_dir))
+
+# retrieve information for Chromium
+chromium_url = git.get_url(src_dir)
+chromium_rev = git.get_hash(src_dir)
+
+date = get_date()
+
+# format version strings
+formatter = VersionFormatter()
+cef_ver = formatter.get_version_string()
+chromium_ver = formatter.get_chromium_version_string()
+
+# list of output directories to be archived
+archive_dirs = []
+
+if options.x64build:
+ platform_arch = '64'
+ binary_arch = 'x64'
+elif options.armbuild:
+ platform_arch = 'arm'
+ binary_arch = 'arm'
+elif options.arm64build:
+ platform_arch = 'arm64'
+ binary_arch = 'arm64'
+else:
+ platform_arch = '32'
+ binary_arch = 'x86'
+
+# output directory
+output_dir_base = 'cef_binary_' + cef_ver
+
+if options.distribsubdir == '':
+ if platform == 'mac':
+ # For backwards compatibility keep the old default directory name on mac.
+ platform_name = 'macos' + ('x' if platform_arch == '64' else '')
+ else:
+ platform_name = platform
+
+ output_dir_name = output_dir_base + '_' + platform_name + platform_arch
+ if options.distribsubdirsuffix != '':
+ output_dir_name += '_' + options.distribsubdirsuffix
+else:
+ output_dir_name = options.distribsubdir
+
+if options.minimal:
+ mode = 'minimal'
+ output_dir_name = output_dir_name + '_minimal'
+elif options.client:
+ mode = 'client'
+ output_dir_name = output_dir_name + '_client'
+elif options.sandbox:
+ mode = 'sandbox'
+ output_dir_name = output_dir_name + '_sandbox'
+else:
+ mode = 'standard'
+
+if options.ozone:
+ output_dir_name = output_dir_name + '_ozone'
+
+output_dir = create_output_dir(output_dir_name, options.outputdir)
+
+# create the README.TXT file
+create_readme()
+
+# transfer the LICENSE.txt file
+copy_file(os.path.join(cef_dir, 'LICENSE.txt'), output_dir, options.quiet)
+
+# read the variables list from the autogenerated cef_paths.gypi file
+cef_paths = eval_file(os.path.join(cef_dir, 'cef_paths.gypi'))
+cef_paths = cef_paths['variables']
+
+# read the variables list from the manually edited cef_paths2.gypi file
+cef_paths2 = eval_file(os.path.join(cef_dir, 'cef_paths2.gypi'))
+cef_paths2 = cef_paths2['variables']
+
+# Determine the build directory suffix. CEF uses a consistent directory naming
+# scheme for GN via GetAllPlatformConfigs in gn_args.py.
+if options.x64build:
+ build_dir_suffix = '_GN_x64'
+elif options.armbuild:
+ build_dir_suffix = '_GN_arm'
+elif options.arm64build:
+ build_dir_suffix = '_GN_arm64'
+else:
+ build_dir_suffix = '_GN_x86'
+
+# Determine the build directory paths.
+out_dir = os.path.join(src_dir, 'out')
+build_dir_debug = os.path.join(out_dir, 'Debug' + build_dir_suffix)
+build_dir_release = os.path.join(out_dir, 'Release' + build_dir_suffix)
+
+if mode == 'standard' or mode == 'minimal':
+ # create the include directory
+ include_dir = os.path.join(output_dir, 'include')
+ make_dir(include_dir, options.quiet)
+
+ # create the cmake directory
+ cmake_dir = os.path.join(output_dir, 'cmake')
+ make_dir(cmake_dir, options.quiet)
+
+ # create the libcef_dll_wrapper directory
+ libcef_dll_dir = os.path.join(output_dir, 'libcef_dll')
+ make_dir(libcef_dll_dir, options.quiet)
+
+ # transfer common include files
+ transfer_gypi_files(cef_dir, cef_paths2['includes_common'], \
+ 'include/', include_dir, options.quiet)
+ transfer_gypi_files(cef_dir, cef_paths2['includes_common_capi'], \
+ 'include/', include_dir, options.quiet)
+ transfer_gypi_files(cef_dir, cef_paths2['includes_capi'], \
+ 'include/', include_dir, options.quiet)
+ transfer_gypi_files(cef_dir, cef_paths2['includes_wrapper'], \
+ 'include/', include_dir, options.quiet)
+ transfer_gypi_files(cef_dir, cef_paths['autogen_cpp_includes'], \
+ 'include/', include_dir, options.quiet)
+ transfer_gypi_files(cef_dir, cef_paths['autogen_capi_includes'], \
+ 'include/', include_dir, options.quiet)
+
+ # Transfer generated include files.
+ generated_includes = [
+ 'cef_command_ids.h',
+ 'cef_config.h',
+ 'cef_pack_resources.h',
+ 'cef_pack_strings.h',
+ ]
+ for include in generated_includes:
+ # Debug and Release build should be the same so grab whichever exists.
+ src_path = os.path.join(build_dir_release, 'includes', 'include', include)
+ if not os.path.exists(src_path):
+ src_path = os.path.join(build_dir_debug, 'includes', 'include', include)
+ if not os.path.exists(src_path):
+ raise Exception('Missing generated header file: %s' % include)
+ copy_file(src_path, os.path.join(include_dir, include), options.quiet)
+
+ # transfer common libcef_dll_wrapper files
+ transfer_gypi_files(cef_dir, cef_paths2['libcef_dll_wrapper_sources_base'], \
+ 'libcef_dll/', libcef_dll_dir, options.quiet)
+ transfer_gypi_files(cef_dir, cef_paths2['libcef_dll_wrapper_sources_common'], \
+ 'libcef_dll/', libcef_dll_dir, options.quiet)
+ transfer_gypi_files(cef_dir, cef_paths['autogen_client_side'], \
+ 'libcef_dll/', libcef_dll_dir, options.quiet)
+
+ if mode == 'standard' or mode == 'minimal':
+ # transfer additional files
+ transfer_files(cef_dir, script_dir, os.path.join(script_dir, 'distrib'), \
+ mode, output_dir, options.quiet)
+
+ # process cmake templates
+ variables = cef_paths.copy()
+ variables.update(cef_paths2)
+ process_cmake_template(os.path.join(cef_dir, 'CMakeLists.txt.in'), \
+ os.path.join(output_dir, 'CMakeLists.txt'), \
+ variables, options.quiet)
+ process_cmake_template(os.path.join(cef_dir, 'cmake', 'cef_macros.cmake.in'), \
+ os.path.join(cmake_dir, 'cef_macros.cmake'), \
+ variables, options.quiet)
+ process_cmake_template(os.path.join(cef_dir, 'cmake', 'cef_variables.cmake.in'), \
+ os.path.join(cmake_dir, 'cef_variables.cmake'), \
+ variables, options.quiet)
+ process_cmake_template(os.path.join(cef_dir, 'cmake', 'FindCEF.cmake.in'), \
+ os.path.join(cmake_dir, 'FindCEF.cmake'), \
+ variables, options.quiet)
+ process_cmake_template(os.path.join(cef_dir, 'libcef_dll', 'CMakeLists.txt.in'), \
+ os.path.join(libcef_dll_dir, 'CMakeLists.txt'), \
+ variables, options.quiet)
+
+if mode == 'standard':
+ # create the tests directory
+ tests_dir = os.path.join(output_dir, 'tests')
+ make_dir(tests_dir, options.quiet)
+
+ # create the tests/shared directory
+ shared_dir = os.path.join(tests_dir, 'shared')
+ make_dir(shared_dir, options.quiet)
+
+ if not options.ozone:
+ # create the tests/cefclient directory
+ cefclient_dir = os.path.join(tests_dir, 'cefclient')
+ make_dir(cefclient_dir, options.quiet)
+
+ # create the tests/cefsimple directory
+ cefsimple_dir = os.path.join(tests_dir, 'cefsimple')
+ make_dir(cefsimple_dir, options.quiet)
+
+ # create the tests/ceftests directory
+ ceftests_dir = os.path.join(tests_dir, 'ceftests')
+ make_dir(ceftests_dir, options.quiet)
+
+ # transfer common shared files
+ transfer_gypi_files(cef_dir, cef_paths2['shared_sources_browser'], \
+ 'tests/shared/', shared_dir, options.quiet)
+ transfer_gypi_files(cef_dir, cef_paths2['shared_sources_common'], \
+ 'tests/shared/', shared_dir, options.quiet)
+ transfer_gypi_files(cef_dir, cef_paths2['shared_sources_renderer'], \
+ 'tests/shared/', shared_dir, options.quiet)
+ transfer_gypi_files(cef_dir, cef_paths2['shared_sources_resources'], \
+ 'tests/shared/', shared_dir, options.quiet)
+
+ if not options.ozone:
+ # transfer common cefclient files
+ transfer_gypi_files(cef_dir, cef_paths2['cefclient_sources_browser'], \
+ 'tests/cefclient/', cefclient_dir, options.quiet)
+ transfer_gypi_files(cef_dir, cef_paths2['cefclient_sources_common'], \
+ 'tests/cefclient/', cefclient_dir, options.quiet)
+ transfer_gypi_files(cef_dir, cef_paths2['cefclient_sources_renderer'], \
+ 'tests/cefclient/', cefclient_dir, options.quiet)
+ transfer_gypi_files(cef_dir, cef_paths2['cefclient_sources_resources'], \
+ 'tests/cefclient/', cefclient_dir, options.quiet)
+ transfer_gypi_files(cef_dir, cef_paths2['cefclient_sources_resources_extensions_set_page_color'], \
+ 'tests/cefclient/', cefclient_dir, options.quiet)
+
+ # transfer common cefsimple files
+ transfer_gypi_files(cef_dir, cef_paths2['cefsimple_sources_common'], \
+ 'tests/cefsimple/', cefsimple_dir, options.quiet)
+
+ # transfer common ceftests files
+ transfer_gypi_files(cef_dir, cef_paths2['ceftests_sources_common'], \
+ 'tests/ceftests/', ceftests_dir, options.quiet)
+
+ # copy GTest files
+ copy_gtest(tests_dir)
+
+ # process cmake templates
+ if not options.ozone:
+ process_cmake_template(os.path.join(cef_dir, 'tests', 'cefclient', 'CMakeLists.txt.in'), \
+ os.path.join(cefclient_dir, 'CMakeLists.txt'), \
+ variables, options.quiet)
+ process_cmake_template(os.path.join(cef_dir, 'tests', 'cefsimple', 'CMakeLists.txt.in'), \
+ os.path.join(cefsimple_dir, 'CMakeLists.txt'), \
+ variables, options.quiet)
+ process_cmake_template(os.path.join(cef_dir, 'tests', 'gtest', 'CMakeLists.txt.in'), \
+ os.path.join(tests_dir, 'gtest', 'CMakeLists.txt'), \
+ variables, options.quiet)
+ process_cmake_template(os.path.join(cef_dir, 'tests', 'ceftests', 'CMakeLists.txt.in'), \
+ os.path.join(ceftests_dir, 'CMakeLists.txt'), \
+ variables, options.quiet)
+
+ # transfer gypi files
+ copy_file(os.path.join(cef_dir, 'cef_paths.gypi'), \
+ os.path.join(output_dir, 'cef_paths.gypi'), options.quiet)
+ copy_file(os.path.join(cef_dir, 'cef_paths2.gypi'), \
+ os.path.join(output_dir, 'cef_paths2.gypi'), options.quiet)
+
+ # transfer Doxyfile
+ transfer_doxyfile(output_dir, options.quiet)
+
+ # transfer README.md
+ copy_file(os.path.join(cef_dir, 'README.md'), \
+ os.path.join(output_dir, 'README.md'), options.quiet)
+
+if not options.nodocs:
+ # generate doc files
+ sys.stdout.write("Generating docs...\n")
+ result = exec_cmd(
+ os.path.join('tools', 'make_cppdocs.%s' %
+ ('bat' if platform == 'windows' else 'sh')), cef_dir)
+ if (len(result['err']) > 0):
+ sys.stdout.write(result['err'])
+ sys.stdout.write(result['out'])
+
+ src_dir = os.path.join(cef_dir, 'docs')
+ if path_exists(src_dir):
+ # create the docs output directory
+ docs_output_dir = create_output_dir(output_dir_base + '_docs',
+ options.outputdir)
+ # transfer contents
+ copy_dir(src_dir, docs_output_dir, options.quiet)
+ else:
+ sys.stdout.write("ERROR: No docs generated.\n")
+
+if platform == 'windows':
+ libcef_dll = 'libcef.dll'
+ libcef_dll_lib = '%s.lib' % libcef_dll
+ libcef_dll_pdb = '%s.pdb' % libcef_dll
+ # yapf: disable
+ binaries = [
+ {'path': 'chrome_elf.dll'},
+ {'path': libcef_dll},
+ {'path': 'libEGL.dll'},
+ {'path': 'libGLESv2.dll'},
+ {'path': 'snapshot_blob.bin', 'conditional': True},
+ {'path': 'v8_context_snapshot.bin', 'conditional': True},
+ {'path': 'vk_swiftshader.dll'},
+ {'path': 'vk_swiftshader_icd.json'},
+ {'path': 'vulkan-1.dll'},
+ ]
+ # yapf: enable
+
+ if mode == 'client':
+ binaries.append({
+ 'path': 'cefsimple.exe' if platform_arch == 'arm64' else 'cefclient.exe'
+ })
+ else:
+ binaries.append({'path': libcef_dll_lib, 'out_path': 'libcef.lib'})
+
+ # yapf: disable
+ resources = [
+ {'path': 'chrome_100_percent.pak'},
+ {'path': 'chrome_200_percent.pak'},
+ {'path': 'resources.pak'},
+ {'path': 'icudtl.dat'},
+ {'path': 'locales', 'delete': '*.info'},
+ ]
+ # yapf: enable
+
+ cef_sandbox_lib = 'obj\\cef\\cef_sandbox.lib'
+ sandbox_libs = [
+ 'obj\\base\\base.lib',
+ 'obj\\base\\base_static.lib',
+ 'obj\\base\\third_party\\double_conversion\\double_conversion.lib',
+ 'obj\\base\\third_party\\dynamic_annotations\\dynamic_annotations.lib',
+ 'obj\\base\\win\\pe_image.lib',
+ cef_sandbox_lib,
+ 'obj\\sandbox\\common\\*.obj',
+ 'obj\\sandbox\\win\\sandbox.lib',
+ 'obj\\third_party\\abseil-cpp\\absl\\base\\**\\*.obj',
+ 'obj\\third_party\\abseil-cpp\\absl\\debugging\\**\\*.obj',
+ 'obj\\third_party\\abseil-cpp\\absl\\numeric\\**\\*.obj',
+ 'obj\\third_party\\abseil-cpp\\absl\\synchronization\\**\\*.obj',
+ 'obj\\third_party\\abseil-cpp\\absl\\time\\**\\*.obj',
+ 'obj\\third_party\\abseil-cpp\\absl\\types\\**\\*.obj',
+ ]
+
+ # Generate the cef_sandbox.lib merged library. A separate *_sandbox build
+ # should exist when GN is_official_build=true.
+ if mode in ('standard', 'minimal', 'sandbox'):
+ dirs = {
+ 'Debug': (build_dir_debug + '_sandbox', build_dir_debug),
+ 'Release': (build_dir_release + '_sandbox', build_dir_release)
+ }
+ for dir_name in dirs.keys():
+ for src_dir in dirs[dir_name]:
+ if path_exists(os.path.join(src_dir, cef_sandbox_lib)):
+ dst_dir = os.path.join(output_dir, dir_name)
+ make_dir(dst_dir, options.quiet)
+ combine_libs(platform, src_dir, sandbox_libs,
+ os.path.join(dst_dir, 'cef_sandbox.lib'))
+ break
+
+ valid_build_dir = None
+
+ if mode == 'standard':
+ # transfer Debug files
+ build_dir = build_dir_debug
+ if not options.allowpartial or path_exists(
+ os.path.join(build_dir, libcef_dll)):
+ valid_build_dir = build_dir
+ dst_dir = os.path.join(output_dir, 'Debug')
+ copy_files_list(build_dir, dst_dir, binaries)
+ copy_files(
+ os.path.join(script_dir, 'distrib/win/%s/*.dll' % binary_arch),
+ dst_dir, options.quiet)
+
+ if not options.nosymbols:
+ # create the symbol output directory
+ symbol_output_dir = create_output_dir(
+ output_dir_name + '_debug_symbols', options.outputdir)
+ # transfer contents
+ copy_file(
+ os.path.join(build_dir, libcef_dll_pdb), symbol_output_dir,
+ options.quiet)
+ else:
+ sys.stdout.write("No Debug build files.\n")
+
+ if mode != 'sandbox':
+ # transfer Release files
+ build_dir = build_dir_release
+ if not options.allowpartial or path_exists(
+ os.path.join(build_dir, libcef_dll)):
+ valid_build_dir = build_dir
+ dst_dir = os.path.join(output_dir, 'Release')
+ copy_files_list(build_dir, dst_dir, binaries)
+ copy_files(
+ os.path.join(script_dir, 'distrib/win/%s/*.dll' % binary_arch),
+ dst_dir, options.quiet)
+
+ if not options.nosymbols:
+ # create the symbol output directory
+ symbol_output_dir = create_output_dir(
+ output_dir_name + '_release_symbols', options.outputdir)
+ # transfer contents
+ copy_file(
+ os.path.join(build_dir, libcef_dll_pdb), symbol_output_dir,
+ options.quiet)
+ else:
+ sys.stdout.write("No Release build files.\n")
+
+ if not valid_build_dir is None:
+ # transfer resource files
+ build_dir = valid_build_dir
+ if mode == 'client':
+ dst_dir = os.path.join(output_dir, 'Release')
+ else:
+ dst_dir = os.path.join(output_dir, 'Resources')
+ copy_files_list(build_dir, dst_dir, resources)
+
+ if mode == 'standard' or mode == 'minimal':
+ # transfer include files
+ transfer_gypi_files(cef_dir, cef_paths2['includes_win'], \
+ 'include/', include_dir, options.quiet)
+ transfer_gypi_files(cef_dir, cef_paths2['includes_win_capi'], \
+ 'include/', include_dir, options.quiet)
+
+ # transfer additional files, if any
+ transfer_files(cef_dir, script_dir, os.path.join(script_dir, 'distrib', 'win'), \
+ mode, output_dir, options.quiet)
+
+ if mode == 'standard':
+ # transfer shared files
+ transfer_gypi_files(cef_dir, cef_paths2['shared_sources_win'], \
+ 'tests/shared/', shared_dir, options.quiet)
+
+ # transfer cefclient files
+ transfer_gypi_files(cef_dir, cef_paths2['cefclient_sources_win'], \
+ 'tests/cefclient/', cefclient_dir, options.quiet)
+ transfer_gypi_files(cef_dir, cef_paths2['cefclient_sources_resources_win'], \
+ 'tests/cefclient/', cefclient_dir, options.quiet)
+
+ # transfer cefsimple files
+ transfer_gypi_files(cef_dir, cef_paths2['cefsimple_sources_win'], \
+ 'tests/cefsimple/', cefsimple_dir, options.quiet)
+ transfer_gypi_files(cef_dir, cef_paths2['cefsimple_sources_resources_win'], \
+ 'tests/cefsimple/', cefsimple_dir, options.quiet)
+
+ # transfer ceftests files
+ transfer_gypi_files(cef_dir, cef_paths2['ceftests_sources_win'], \
+ 'tests/ceftests/', ceftests_dir, options.quiet)
+ transfer_gypi_files(cef_dir, cef_paths2['ceftests_sources_resources_win'], \
+ 'tests/ceftests/', ceftests_dir, options.quiet)
+
+elif platform == 'mac':
+ framework_name = 'Chromium Embedded Framework'
+ framework_dsym = '%s.dSYM' % framework_name
+ cefclient_app = 'cefclient.app'
+
+ cef_sandbox_lib = 'obj/cef/libcef_sandbox.a'
+ sandbox_libs = [
+ cef_sandbox_lib,
+ 'obj/sandbox/mac/libseatbelt.a',
+ 'obj/sandbox/mac/libseatbelt_proto.a',
+ 'obj/third_party/protobuf/libprotobuf_lite.a',
+ 'obj/buildtools/third_party/libc++/libc++/*.o',
+ 'obj/buildtools/third_party/libc++abi/libc++abi/*.o',
+ ]
+
+ # Generate the cef_sandbox.a merged library. A separate *_sandbox build
+ # should exist when GN is_official_build=true.
+ if mode in ('standard', 'minimal', 'sandbox'):
+ dirs = {
+ 'Debug': (build_dir_debug + '_sandbox', build_dir_debug),
+ 'Release': (build_dir_release + '_sandbox', build_dir_release)
+ }
+ for dir_name in dirs.keys():
+ for src_dir in dirs[dir_name]:
+ if path_exists(os.path.join(src_dir, cef_sandbox_lib)):
+ dst_dir = os.path.join(output_dir, dir_name)
+ make_dir(dst_dir, options.quiet)
+ combine_libs(platform, src_dir, sandbox_libs,
+ os.path.join(dst_dir, 'cef_sandbox.a'))
+ break
+
+ valid_build_dir = None
+
+ if mode == 'standard':
+ # transfer Debug files
+ build_dir = build_dir_debug
+ if not options.allowpartial or path_exists(
+ os.path.join(build_dir, cefclient_app)):
+ valid_build_dir = build_dir
+ dst_dir = os.path.join(output_dir, 'Debug')
+ make_dir(dst_dir, options.quiet)
+ framework_src_dir = os.path.join(
+ build_dir, '%s/Contents/Frameworks/%s.framework/Versions/A' %
+ (cefclient_app, framework_name))
+ framework_dst_dir = os.path.join(dst_dir, '%s.framework' % framework_name)
+ copy_dir(framework_src_dir, framework_dst_dir, options.quiet)
+
+ if not options.nosymbols:
+ # create the symbol output directory
+ symbol_output_dir = create_output_dir(
+ output_dir_name + '_debug_symbols', options.outputdir)
+
+ # The real dSYM already exists, just copy it to the output directory.
+ # dSYMs are only generated when is_official_build=true or enable_dsyms=true.
+ # See //build/config/mac/symbols.gni.
+ copy_dir(
+ os.path.join(build_dir, framework_dsym),
+ os.path.join(symbol_output_dir, framework_dsym), options.quiet)
+ else:
+ sys.stdout.write("No Debug build files.\n")
+
+ if mode != 'sandbox':
+ # transfer Release files
+ build_dir = build_dir_release
+ if not options.allowpartial or path_exists(
+ os.path.join(build_dir, cefclient_app)):
+ valid_build_dir = build_dir
+ dst_dir = os.path.join(output_dir, 'Release')
+ make_dir(dst_dir, options.quiet)
+ framework_src_dir = os.path.join(
+ build_dir, '%s/Contents/Frameworks/%s.framework/Versions/A' %
+ (cefclient_app, framework_name))
+ if mode != 'client':
+ framework_dst_dir = os.path.join(dst_dir,
+ '%s.framework' % framework_name)
+ else:
+ copy_dir(
+ os.path.join(build_dir, cefclient_app),
+ os.path.join(dst_dir, cefclient_app), options.quiet)
+ # Replace the versioned framework with an unversioned framework in the sample app.
+ framework_dst_dir = os.path.join(
+ dst_dir, '%s/Contents/Frameworks/%s.framework' % (cefclient_app,
+ framework_name))
+ remove_dir(framework_dst_dir, options.quiet)
+ copy_dir(framework_src_dir, framework_dst_dir, options.quiet)
+
+ if not options.nosymbols:
+ # create the symbol output directory
+ symbol_output_dir = create_output_dir(
+ output_dir_name + '_release_symbols', options.outputdir)
+
+ # The real dSYM already exists, just copy it to the output directory.
+ # dSYMs are only generated when is_official_build=true or enable_dsyms=true.
+ # See //build/config/mac/symbols.gni.
+ copy_dir(
+ os.path.join(build_dir, framework_dsym),
+ os.path.join(symbol_output_dir, framework_dsym), options.quiet)
+ else:
+ sys.stdout.write("No Release build files.\n")
+
+ if mode == 'standard' or mode == 'minimal':
+ # transfer include files
+ transfer_gypi_files(cef_dir, cef_paths2['includes_mac'], \
+ 'include/', include_dir, options.quiet)
+ transfer_gypi_files(cef_dir, cef_paths2['includes_mac_capi'], \
+ 'include/', include_dir, options.quiet)
+ transfer_gypi_files(cef_dir, cef_paths2['includes_wrapper_mac'], \
+ 'include/', include_dir, options.quiet)
+
+ # transfer libcef_dll_wrapper files
+ transfer_gypi_files(cef_dir, cef_paths2['libcef_dll_wrapper_sources_mac'], \
+ 'libcef_dll/', libcef_dll_dir, options.quiet)
+
+ # transfer additional files, if any
+ transfer_files(cef_dir, script_dir, os.path.join(script_dir, 'distrib', 'mac'), \
+ mode, output_dir, options.quiet)
+
+ if mode == 'standard':
+ # transfer shared files
+ transfer_gypi_files(cef_dir, cef_paths2['shared_sources_mac'], \
+ 'tests/shared/', shared_dir, options.quiet)
+ transfer_gypi_files(cef_dir, cef_paths2['shared_sources_mac_helper'], \
+ 'tests/shared/', shared_dir, options.quiet)
+
+ # transfer cefclient files
+ transfer_gypi_files(cef_dir, cef_paths2['cefclient_sources_mac'], \
+ 'tests/cefclient/', cefclient_dir, options.quiet)
+
+ # transfer cefclient/resources/mac files
+ copy_dir(os.path.join(cef_dir, 'tests/cefclient/resources/mac'), \
+ os.path.join(cefclient_dir, 'resources/mac'), \
+ options.quiet)
+
+ # transfer cefsimple files
+ transfer_gypi_files(cef_dir, cef_paths2['cefsimple_sources_mac'], \
+ 'tests/cefsimple/', cefsimple_dir, options.quiet)
+ transfer_gypi_files(cef_dir, cef_paths2['cefsimple_sources_mac_helper'], \
+ 'tests/cefsimple/', cefsimple_dir, options.quiet)
+
+ # transfer cefsimple/mac files
+ copy_dir(os.path.join(cef_dir, 'tests/cefsimple/mac'), \
+ os.path.join(cefsimple_dir, 'mac'), \
+ options.quiet)
+
+ # transfer ceftests files
+ transfer_gypi_files(cef_dir, cef_paths2['ceftests_sources_mac'], \
+ 'tests/ceftests/', ceftests_dir, options.quiet)
+ transfer_gypi_files(cef_dir, cef_paths2['ceftests_sources_mac_helper'], \
+ 'tests/ceftests/', ceftests_dir, options.quiet)
+
+ # transfer ceftests/resources/mac files
+ copy_dir(os.path.join(cef_dir, 'tests/ceftests/resources/mac'), \
+ os.path.join(ceftests_dir, 'resources/mac'), \
+ options.quiet)
+
+elif platform == 'linux':
+ libcef_so = 'libcef.so'
+ # yapf: disable
+ binaries = [
+ {'path': 'chrome_sandbox', 'out_path': 'chrome-sandbox'},
+ {'path': libcef_so},
+ {'path': 'libEGL.so'},
+ {'path': 'libGLESv2.so'},
+ {'path': 'libvk_swiftshader.so'},
+ {'path': 'libvulkan.so.1'},
+ {'path': 'snapshot_blob.bin', 'conditional': True},
+ {'path': 'v8_context_snapshot.bin', 'conditional': True},
+ {'path': 'vk_swiftshader_icd.json'},
+ ]
+ # yapf: enable
+ if options.ozone:
+ binaries.append({'path': 'libminigbm.so', 'conditional': True})
+
+ if mode == 'client':
+ binaries.append({'path': 'cefsimple'})
+
+ # yapf: disable
+ resources = [
+ {'path': 'chrome_100_percent.pak'},
+ {'path': 'chrome_200_percent.pak'},
+ {'path': 'resources.pak'},
+ {'path': 'icudtl.dat'},
+ {'path': 'locales', 'delete': '*.info'},
+ ]
+ # yapf: enable
+
+ valid_build_dir = None
+
+ if mode == 'standard':
+ # transfer Debug files
+ build_dir = build_dir_debug
+ libcef_path = os.path.join(build_dir, libcef_so)
+ if not options.allowpartial or path_exists(libcef_path):
+ valid_build_dir = build_dir
+ dst_dir = os.path.join(output_dir, 'Debug')
+ copy_files_list(build_dir, dst_dir, binaries)
+ else:
+ sys.stdout.write("No Debug build files.\n")
+
+ # transfer Release files
+ build_dir = build_dir_release
+ libcef_path = os.path.join(build_dir, libcef_so)
+ if not options.allowpartial or path_exists(libcef_path):
+ valid_build_dir = build_dir
+ dst_dir = os.path.join(output_dir, 'Release')
+ copy_files_list(build_dir, dst_dir, binaries)
+ else:
+ sys.stdout.write("No Release build files.\n")
+
+ if not valid_build_dir is None:
+ # transfer resource files
+ build_dir = valid_build_dir
+ if mode == 'client':
+ dst_dir = os.path.join(output_dir, 'Release')
+ else:
+ dst_dir = os.path.join(output_dir, 'Resources')
+ copy_files_list(build_dir, dst_dir, resources)
+
+ if mode == 'standard' or mode == 'minimal':
+ # transfer include files
+ transfer_gypi_files(cef_dir, cef_paths2['includes_linux'], \
+ 'include/', include_dir, options.quiet)
+ transfer_gypi_files(cef_dir, cef_paths2['includes_linux_capi'], \
+ 'include/', include_dir, options.quiet)
+
+ # transfer additional files, if any
+ transfer_files(cef_dir, script_dir, os.path.join(script_dir, 'distrib', 'linux'), \
+ mode, output_dir, options.quiet)
+
+ if mode == 'standard':
+ # transfer shared files
+ transfer_gypi_files(cef_dir, cef_paths2['shared_sources_linux'], \
+ 'tests/shared/', shared_dir, options.quiet)
+
+ if not options.ozone:
+ # transfer cefclient files
+ transfer_gypi_files(cef_dir, cef_paths2['cefclient_sources_linux'], \
+ 'tests/cefclient/', cefclient_dir, options.quiet)
+
+ # transfer cefsimple files
+ transfer_gypi_files(cef_dir, cef_paths2['cefsimple_sources_linux'], \
+ 'tests/cefsimple/', cefsimple_dir, options.quiet)
+
+ # transfer ceftests files
+ transfer_gypi_files(cef_dir, cef_paths2['ceftests_sources_linux'], \
+ 'tests/ceftests/', ceftests_dir, options.quiet)
+
+if not options.noarchive:
+ # create an archive for each output directory
+ archive_format = os.getenv('CEF_ARCHIVE_FORMAT', 'zip')
+ if archive_format not in ('zip', 'tar.gz', 'tar.bz2'):
+ raise Exception('Unsupported archive format: %s' % archive_format)
+
+ if os.getenv('CEF_COMMAND_7ZIP', '') != '':
+ archive_format = os.getenv('CEF_COMMAND_7ZIP_FORMAT', '7z')
+
+ for dir in archive_dirs:
+ if not options.quiet:
+ sys.stdout.write("Creating %s archive for %s...\n" %
+ (archive_format, os.path.basename(dir)))
+ if archive_format == 'zip':
+ create_zip_archive(dir)
+ elif archive_format == 'tar.gz':
+ create_tar_archive(dir, 'gz')
+ elif archive_format == 'tar.bz2':
+ create_tar_archive(dir, 'bz2')
+ else:
+ create_7z_archive(dir, archive_format)
diff --git a/tools/make_distrib.sh b/tools/make_distrib.sh
new file mode 100755
index 00000000..4b71cf45
--- /dev/null
+++ b/tools/make_distrib.sh
@@ -0,0 +1,2 @@
+#!/bin/sh
+python3 make_distrib.py --output-dir ../binary_distrib/ $@
diff --git a/tools/make_gypi_file.py b/tools/make_gypi_file.py
new file mode 100644
index 00000000..581a7b5a
--- /dev/null
+++ b/tools/make_gypi_file.py
@@ -0,0 +1,108 @@
+# Copyright (c) 2011 The Chromium Embedded Framework Authors. All rights
+# reserved. Use of this source code is governed by a BSD-style license that
+# can be found in the LICENSE file.
+
+from __future__ import absolute_import
+from cef_parser import *
+
+
+def make_gypi_file(header):
+ # header string
+ result = \
+"""# Copyright (c) $YEAR$ The Chromium Embedded Framework Authors. All rights
+# reserved. Use of this source code is governed by a BSD-style license that
+# can be found in the LICENSE file.
+#
+# ---------------------------------------------------------------------------
+#
+# This file was generated by the CEF translator tool and should not edited
+# by hand. See the translator.README.txt file in the tools directory for
+# more information.
+#
+# $hash=$$HASH$$$
+#
+
+{
+ 'variables': {
+"""
+
+ filenames = sorted(header.get_file_names())
+
+ # cpp includes
+ result += " 'autogen_cpp_includes': [\n"
+ for filename in filenames:
+ result += " 'include/" + filename + "',\n"
+ result += " ],\n"
+
+ # capi includes
+ result += " 'autogen_capi_includes': [\n"
+ for filename in filenames:
+ result += " 'include/capi/" + get_capi_file_name(filename) + "',\n"
+ result += " ],\n"
+
+ classes = sorted(header.get_class_names())
+
+ # library side includes
+ result += " 'autogen_library_side': [\n"
+ for clsname in classes:
+ cls = header.get_class(clsname)
+ filename = get_capi_name(clsname[3:], False)
+ dir = cls.get_file_directory()
+ if not dir is None:
+ filename = dir + '/' + filename
+ if cls.is_library_side():
+ result += " 'libcef_dll/cpptoc/"+filename+"_cpptoc.cc',\n" \
+ " 'libcef_dll/cpptoc/"+filename+"_cpptoc.h',\n"
+ else:
+ result += " 'libcef_dll/ctocpp/"+filename+"_ctocpp.cc',\n" \
+ " 'libcef_dll/ctocpp/"+filename+"_ctocpp.h',\n"
+ result += " ],\n"
+
+ # client side includes
+ result += " 'autogen_client_side': [\n"
+ for clsname in classes:
+ cls = header.get_class(clsname)
+ filename = get_capi_name(clsname[3:], False)
+ dir = cls.get_file_directory()
+ if not dir is None:
+ filename = dir + '/' + filename
+ if cls.is_library_side():
+ result += " 'libcef_dll/ctocpp/"+filename+"_ctocpp.cc',\n" \
+ " 'libcef_dll/ctocpp/"+filename+"_ctocpp.h',\n"
+ else:
+ result += " 'libcef_dll/cpptoc/"+filename+"_cpptoc.cc',\n" \
+ " 'libcef_dll/cpptoc/"+filename+"_cpptoc.h',\n"
+ result += " ],\n"
+
+ # footer string
+ result += \
+""" },
+}
+"""
+
+ # add the copyright year
+ result = result.replace('$YEAR$', get_year())
+
+ return result
+
+
+def write_gypi_file(header, file):
+ newcontents = make_gypi_file(header)
+ return (file, newcontents)
+
+
+# test the module
+if __name__ == "__main__":
+ import sys
+
+ # verify that the correct number of command-line arguments are provided
+ if len(sys.argv) < 2:
+ sys.stderr.write('Usage: ' + sys.argv[0] + ' <infile>\n')
+ sys.exit()
+
+ # create the header object
+ header = obj_header()
+ header.add_file(sys.argv[1])
+
+ # dump the result to stdout
+ sys.stdout.write(make_gypi_file(header))
diff --git a/tools/make_libcef_dll_dylib_impl.py b/tools/make_libcef_dll_dylib_impl.py
new file mode 100644
index 00000000..d117798c
--- /dev/null
+++ b/tools/make_libcef_dll_dylib_impl.py
@@ -0,0 +1,210 @@
+# Copyright (c) 2018 The Chromium Embedded Framework Authors. All rights
+# reserved. Use of this source code is governed by a BSD-style license that
+# can be found in the LICENSE file.
+
+from __future__ import absolute_import
+from cef_parser import *
+from file_util import *
+import os
+
+# Other headers that export C API functions.
+OTHER_HEADERS = [
+ 'cef_api_hash.h',
+ 'cef_version.h',
+ 'internal/cef_logging_internal.h',
+ 'internal/cef_string_list.h',
+ 'internal/cef_string_map.h',
+ 'internal/cef_string_multimap.h',
+ 'internal/cef_string_types.h',
+ 'internal/cef_thread_internal.h',
+ 'internal/cef_time.h',
+ 'internal/cef_trace_event_internal.h',
+]
+
+
+def make_libcef_dll_dylib_impl_parts(name, retval, args):
+ # Split arguments into types and names.
+ arg_types = ''
+ arg_names = ''
+ for arg in args:
+ if len(arg_types) > 0:
+ arg_types += ', '
+ arg_names += ', '
+ pos = arg.rfind(' ')
+ arg_types += arg[0:pos]
+ arg_names += arg[pos + 1:]
+
+ declare = 'decltype(&%s) %s;\n' % (name, name)
+
+ init = ' INIT_ENTRY(%s);' % name
+
+ impl = """NO_SANITIZE("cfi-icall") %s %s(%s) {
+ %sg_libcef_pointers.%s(%s);
+}
+
+""" % (retval, name, ', '.join(args), 'return '
+ if retval != 'void' else '', name, arg_names)
+
+ return (declare, init, impl)
+
+
+def make_libcef_dll_dylib_impl_func(func):
+ name = func.get_capi_name()
+ parts = func.get_capi_parts([], True)
+ retval = parts['retval']
+ args = parts['args']
+ return make_libcef_dll_dylib_impl_parts(name, retval, args)
+
+
+def make_libcef_dll_dylib_impl(header):
+ filenames = []
+ includes = [
+ '#include "include/base/cef_compiler_specific.h"',
+ '#include "include/wrapper/cef_library_loader.h"',
+ ]
+ ptr_declare = ''
+ ptr_init = ''
+ ptr_impl = ''
+
+ # Include required headers for global functions.
+ for func in header.get_funcs():
+ declare, init, impl = make_libcef_dll_dylib_impl_func(func)
+ ptr_declare += declare
+ ptr_init += init
+ ptr_impl += impl
+
+ filename = func.get_file_name()
+ if not filename in filenames:
+ includes.append('#include "include/capi/%s"' % func.get_capi_file_name())
+ filenames.append(filename)
+
+ # Include required headers for static class functions.
+ allclasses = header.get_classes()
+ for cls in allclasses:
+ funcs = cls.get_static_funcs()
+ for func in funcs:
+ declare, init, impl = make_libcef_dll_dylib_impl_func(func)
+ ptr_declare += declare
+ ptr_init += init
+ ptr_impl += impl
+
+ if len(funcs) > 0:
+ filename = cls.get_file_name()
+ if not filename in filenames:
+ includes.append('#include "include/capi/%s"' % cls.get_capi_file_name())
+ filenames.append(filename)
+
+ # Parse other headers.
+ root_directory = header.get_root_directory()
+ for other in OTHER_HEADERS:
+ path = os.path.join(root_directory, other)
+ content = read_file(path)
+ funcs = get_function_impls(content, 'CEF_EXPORT', False)
+ for func in funcs:
+ declare, init, impl = make_libcef_dll_dylib_impl_parts(
+ func['name'], func['retval'], func['args'])
+ ptr_declare += declare
+ ptr_init += init
+ ptr_impl += impl
+
+ includes.append('#include "include/%s"' % other)
+
+ # Build the final output.
+ result = get_copyright() + """
+
+#include <dlfcn.h>
+#include <stdio.h>
+
+""" + "\n".join(sorted(includes)) + """
+
+// GLOBAL WRAPPER FUNCTIONS - Do not edit by hand.
+
+namespace {
+
+void* g_libcef_handle = nullptr;
+
+void* libcef_get_ptr(const char* path, const char* name) {
+ void* ptr = dlsym(g_libcef_handle, name);
+ if (!ptr) {
+ fprintf(stderr, "dlsym %s: %s\\n", path, dlerror());
+ }
+ return ptr;
+}
+
+struct libcef_pointers {
+""" + ptr_declare + """
+} g_libcef_pointers = {0};
+
+#define INIT_ENTRY(name) \
+ g_libcef_pointers.name = (decltype(&name))libcef_get_ptr(path, #name); \
+ if (!g_libcef_pointers.name) { \
+ return 0; \
+ }
+
+int libcef_init_pointers(const char* path) {
+""" + ptr_init + """
+ return 1;
+}
+
+} // namespace
+
+int cef_load_library(const char* path) {
+ if (g_libcef_handle)
+ return 0;
+
+ g_libcef_handle = dlopen(path, RTLD_LAZY | RTLD_LOCAL | RTLD_FIRST);
+ if (!g_libcef_handle) {
+ fprintf(stderr, "dlopen %s: %s\\n", path, dlerror());
+ return 0;
+ }
+
+ if (!libcef_init_pointers(path)) {
+ cef_unload_library();
+ return 0;
+ }
+
+ return 1;
+}
+
+int cef_unload_library() {
+ int result = 0;
+ if (g_libcef_handle) {
+ result = !dlclose(g_libcef_handle);
+ if (!result) {
+ fprintf(stderr, "dlclose: %s\\n", dlerror());
+ }
+ g_libcef_handle = nullptr;
+ }
+ return result;
+}
+
+""" + ptr_impl
+ return result
+
+
+def write_libcef_dll_dylib_impl(header, file):
+ newcontents = make_libcef_dll_dylib_impl(header)
+ return (file, newcontents)
+
+
+# Test the module.
+if __name__ == "__main__":
+ import sys
+
+ # Verify that the correct number of command-line arguments are provided.
+ if len(sys.argv) < 2:
+ sys.stderr.write('Usage: ' + sys.argv[0] + ' <cpp_header_dir>\n')
+ sys.exit()
+
+ cpp_header_dir = sys.argv[1]
+
+ # Create the header object. Should match the logic in translator.py.
+ header = obj_header()
+ header.set_root_directory(cpp_header_dir)
+ excluded_files = ['cef_api_hash.h', 'cef_application_mac.h', 'cef_version.h']
+ header.add_directory(cpp_header_dir, excluded_files)
+ header.add_directory(os.path.join(cpp_header_dir, 'test'))
+ header.add_directory(os.path.join(cpp_header_dir, 'views'))
+
+ # Dump the result to stdout.
+ sys.stdout.write(make_libcef_dll_dylib_impl(header))
diff --git a/tools/make_pack_header.py b/tools/make_pack_header.py
new file mode 100644
index 00000000..1afe8d06
--- /dev/null
+++ b/tools/make_pack_header.py
@@ -0,0 +1,134 @@
+#!/usr/bin/env python
+# Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
+# reserved. Use of this source code is governed by a BSD-style license
+# that can be found in the LICENSE file.
+"""
+A simple utility function to merge pack resource files into a single resource file.
+"""
+
+from __future__ import absolute_import
+from __future__ import print_function
+from date_util import *
+from file_util import *
+import os
+import re
+import string
+import sys
+
+
+def MakeFileSegment(input, all_names):
+ result = """
+
+// ---------------------------------------------------------------------------
+// From $FILE$:
+"""
+
+ filename = os.path.split(input)[1]
+ result = result.replace('$FILE$', filename)
+
+ contents = read_file(input)
+
+ # Format for Windows builds with resource whitelisting enabled [1]:
+ # #define IDR_RESOURCE_NAME (::ui::WhitelistedResource<12345>(), 12345)
+ # Format for other builds:
+ # #define IDR_RESOURCE_NAME 12345
+ # [1] See https://crbug.com/684788#c18
+
+ regex = '#define\s([A-Za-z0-9_]{1,})\s+'
+ if contents.find('ui::WhitelistedResource') > 0:
+ regex += '.*<'
+ regex += '([0-9]{1,})'
+
+ # identify the defines in the file
+ p = re.compile(regex)
+ list = p.findall(contents)
+ for name, id in list:
+ # If the same define exists in multiple files add a suffix.
+ if name in all_names:
+ all_names[name] += 1
+ name += '_%d' % all_names[name]
+ else:
+ all_names[name] = 1
+
+ result += "\n#define %s %s" % (name, id)
+
+ return result
+
+
+def MakeFile(output, input):
+ # header string
+ result = \
+"""// Copyright (c) $YEAR$ Marshall A. Greenblatt. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the name Chromium Embedded
+// Framework nor the names of its contributors may be used to endorse
+// or promote products derived from this software without specific prior
+// written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ---------------------------------------------------------------------------
+//
+// This file is generated by the make_pack_header.py tool.
+//
+
+#ifndef $GUARD$
+#define $GUARD$
+#pragma once"""
+
+ # sort the input files by name
+ input = sorted(input, key=lambda path: os.path.split(path)[1])
+
+ all_names = {}
+
+ # generate the file segments
+ for file in input:
+ result += MakeFileSegment(file, all_names)
+
+ # footer string
+ result += \
+"""
+
+#endif // $GUARD$
+"""
+
+ # add the copyright year
+ result = result.replace('$YEAR$', get_year())
+ # add the guard string
+ filename = os.path.split(output)[1]
+ guard = 'CEF_INCLUDE_' + filename.replace('.', '_').upper() + '_'
+ result = result.replace('$GUARD$', guard)
+
+ write_file_if_changed(output, result)
+
+
+def main(argv):
+ if len(argv) < 3:
+ print(("Usage:\n %s <output_filename> <input_file1> [input_file2] ... " %
+ argv[0]))
+ sys.exit(-1)
+ MakeFile(argv[1], argv[2:])
+
+
+if '__main__' == __name__:
+ main(sys.argv)
diff --git a/tools/make_version_header.bat b/tools/make_version_header.bat
new file mode 100644
index 00000000..e8887464
--- /dev/null
+++ b/tools/make_version_header.bat
@@ -0,0 +1,2 @@
+@echo off
+python.bat tools\make_version_header.py include\cef_version.h
diff --git a/tools/make_version_header.py b/tools/make_version_header.py
new file mode 100644
index 00000000..fa2325aa
--- /dev/null
+++ b/tools/make_version_header.py
@@ -0,0 +1,109 @@
+# Copyright (c) 2011 The Chromium Embedded Framework Authors. All rights
+# reserved. Use of this source code is governed by a BSD-style license that
+# can be found in the LICENSE file.
+
+from __future__ import absolute_import
+from cef_parser import get_copyright
+from cef_version import VersionFormatter
+from date_util import *
+from file_util import *
+import git_util as git
+import sys
+
+
+def make_version_header(header):
+ if not git.is_checkout('.'):
+ raise Exception('Not a valid checkout')
+
+ result = get_copyright(full=True, translator=False) + \
+"""//
+// ---------------------------------------------------------------------------
+//
+// This file was generated by the make_version_header.py tool.
+//
+
+#ifndef CEF_INCLUDE_CEF_VERSION_H_
+#define CEF_INCLUDE_CEF_VERSION_H_
+
+#define CEF_VERSION "$VERSION$"
+#define CEF_VERSION_MAJOR $VERSION_MAJOR$
+#define CEF_VERSION_MINOR $VERSION_MINOR$
+#define CEF_VERSION_PATCH $VERSION_PATCH$
+#define CEF_COMMIT_NUMBER $COMMIT_NUMBER$
+#define CEF_COMMIT_HASH "$COMMIT_HASH$"
+#define COPYRIGHT_YEAR $YEAR$
+
+#define CHROME_VERSION_MAJOR $CHROME_MAJOR$
+#define CHROME_VERSION_MINOR $CHROME_MINOR$
+#define CHROME_VERSION_BUILD $CHROME_BUILD$
+#define CHROME_VERSION_PATCH $CHROME_PATCH$
+
+#define DO_MAKE_STRING(p) #p
+#define MAKE_STRING(p) DO_MAKE_STRING(p)
+
+#ifndef APSTUDIO_HIDDEN_SYMBOLS
+
+#include "include/internal/cef_export.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Returns CEF version information for the libcef library. The |entry|
+// parameter describes which version component will be returned:
+// 0 - CEF_VERSION_MAJOR
+// 1 - CEF_VERSION_MINOR
+// 2 - CEF_VERSION_PATCH
+// 3 - CEF_COMMIT_NUMBER
+// 4 - CHROME_VERSION_MAJOR
+// 5 - CHROME_VERSION_MINOR
+// 6 - CHROME_VERSION_BUILD
+// 7 - CHROME_VERSION_PATCH
+///
+CEF_EXPORT int cef_version_info(int entry);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // APSTUDIO_HIDDEN_SYMBOLS
+
+#endif // CEF_INCLUDE_CEF_VERSION_H_
+"""
+
+ formatter = VersionFormatter()
+
+ # Substitute hash values for placeholders.
+ result = result.replace('$YEAR$', get_year())
+ result = result.replace('$VERSION$', formatter.get_version_string())
+
+ commit_components = formatter.get_cef_commit_components()
+ for key in ('HASH', 'NUMBER'):
+ result = result.replace('$COMMIT_%s$' % key, str(commit_components[key]))
+
+ version_parts = formatter.get_version_parts()
+ for key in ('MAJOR', 'MINOR', 'PATCH'):
+ result = result.replace('$VERSION_%s$' % key, str(version_parts[key]))
+
+ chrome_version_components = formatter.get_chrome_version_components()
+ for key in ('MAJOR', 'MINOR', 'BUILD', 'PATCH'):
+ result = result.replace('$CHROME_%s$' % key,
+ str(chrome_version_components[key]))
+
+ return result
+
+
+def write_version_header(output):
+ result = make_version_header(output)
+ return write_file_if_changed(output, result)
+
+
+def main(argv):
+ if len(argv) < 2:
+ print(("Usage:\n %s <output_filename>" % argv[0]))
+ sys.exit(-1)
+ write_version_header(argv[1])
+
+
+if '__main__' == __name__:
+ main(sys.argv)
diff --git a/tools/make_version_header.sh b/tools/make_version_header.sh
new file mode 100755
index 00000000..30e00b26
--- /dev/null
+++ b/tools/make_version_header.sh
@@ -0,0 +1,2 @@
+#!/bin/sh
+python3 tools/make_version_header.py include/cef_version.h
diff --git a/tools/make_wrapper_types_header.py b/tools/make_wrapper_types_header.py
new file mode 100644
index 00000000..213c75f9
--- /dev/null
+++ b/tools/make_wrapper_types_header.py
@@ -0,0 +1,50 @@
+# Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
+# reserved. Use of this source code is governed by a BSD-style license that
+# can be found in the LICENSE file.
+
+from __future__ import absolute_import
+from cef_parser import *
+
+
+def make_wrapper_types_header(header):
+ result = get_copyright()
+
+ result += '#ifndef CEF_LIBCEF_DLL_WRAPPER_TYPES_H_\n'+ \
+ '#define CEF_LIBCEF_DLL_WRAPPER_TYPES_H_\n' + \
+ '#pragma once\n\n' + \
+ 'enum CefWrapperType {\n' + \
+ ' WT_BASE_REF_COUNTED = 1,\n' + \
+ ' WT_BASE_SCOPED,\n'
+
+ clsnames = sorted(header.get_class_names())
+ for clsname in clsnames:
+ result += ' ' + get_wrapper_type_enum(clsname) + ',\n'
+
+ result += '\n WT_LAST\n'
+ result += '};\n\n' + \
+ '#endif // CEF_LIBCEF_DLL_WRAPPER_TYPES_H_'
+
+ return result
+
+
+def write_wrapper_types_header(header, file):
+ newcontents = make_wrapper_types_header(header)
+ return (file, newcontents)
+
+
+# test the module
+if __name__ == "__main__":
+ import sys
+
+ # verify that the correct number of command-line arguments are provided
+ if len(sys.argv) < 2:
+ sys.stderr.write('Usage: ' + sys.argv[0] + ' <include_dir>\n')
+ sys.exit()
+
+ # create the header object
+ header = obj_header()
+ excluded_files = ['cef_api_hash.h', 'cef_application_mac.h', 'cef_version.h']
+ header.add_directory(sys.argv[1], excluded_files)
+
+ # dump the result to stdout
+ sys.stdout.write(make_wrapper_types_header(header))
diff --git a/tools/msvs_env.bat b/tools/msvs_env.bat
new file mode 100644
index 00000000..52a0c1d8
--- /dev/null
+++ b/tools/msvs_env.bat
@@ -0,0 +1,73 @@
+@echo off
+:: Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
+:: reserved. Use of this source code is governed by a BSD-style license
+:: that can be found in the LICENSE file.
+
+:: Set up the environment for use with MSVS tools and then execute whatever
+:: was specified on the command-line.
+
+set RC=
+
+:: Support !! syntax for delayed variable expansion.
+setlocal enabledelayedexpansion
+
+:: Require that platform is passed as the first argument.
+if "%1" == "win32" (
+ set vcvarsbat=vcvars32.bat
+) else if "%1" == "win64" (
+ set vcvarsbat=vcvars64.bat
+) else if "%1" == "winarm64" (
+ set vcvarsbat=vcvarsamd64_arm64.bat
+) else (
+ echo ERROR: Please specify a target platform: win32, win64 or winarm64
+ set ERRORLEVEL=1
+ goto end
+)
+
+:: Check if vcvars is already provided via the environment.
+set vcvars="%CEF_VCVARS%"
+if %vcvars% == "none" goto found_vcvars
+if exist %vcvars% goto found_vcvars
+
+:: Search for the default VS installation path.
+for %%x in ("%PROGRAMFILES(X86)%" "%PROGRAMFILES%") do (
+ for %%y in (2022 2019 2017) do (
+ for %%z in (Professional Enterprise Community BuildTools) do (
+ set vcvars="%%~x\Microsoft Visual Studio\%%y\%%z\VC\Auxiliary\Build\%vcvarsbat%"
+ if exist !vcvars! goto found_vcvars
+ )
+ )
+)
+
+echo ERROR: Failed to find vcvars
+set ERRORLEVEL=1
+goto end
+
+:found_vcvars
+echo vcvars:
+echo %vcvars%
+
+if not %vcvars% == "none" (
+ :: Set this variable to keep VS2017 < 15.5 from changing the current working directory.
+ set "VSCMD_START_DIR=%CD%"
+ call %vcvars%
+)
+
+echo PATH:
+echo %PATH%
+
+:: Remove the first argument and execute the command.
+for /f "tokens=1,* delims= " %%a in ("%*") do set ALL_BUT_FIRST=%%b
+echo command:
+echo %ALL_BUT_FIRST%
+%ALL_BUT_FIRST%
+
+:end
+endlocal & set RC=%ERRORLEVEL%
+goto omega
+
+:returncode
+exit /B %RC%
+
+:omega
+call :returncode %RC%
diff --git a/tools/patch.bat b/tools/patch.bat
new file mode 100644
index 00000000..ae3616d8
--- /dev/null
+++ b/tools/patch.bat
@@ -0,0 +1,2 @@
+@echo off
+python.bat %~dp0\patcher.py \ No newline at end of file
diff --git a/tools/patch.sh b/tools/patch.sh
new file mode 100755
index 00000000..c7d3ee15
--- /dev/null
+++ b/tools/patch.sh
@@ -0,0 +1,2 @@
+#!/bin/sh
+python3 tools/patcher.py
diff --git a/tools/patch_updater.bat b/tools/patch_updater.bat
new file mode 100644
index 00000000..94ca4de8
--- /dev/null
+++ b/tools/patch_updater.bat
@@ -0,0 +1,2 @@
+@echo off
+python.bat %~dp0\patch_updater.py %* \ No newline at end of file
diff --git a/tools/patch_updater.py b/tools/patch_updater.py
new file mode 100644
index 00000000..b7e64ba8
--- /dev/null
+++ b/tools/patch_updater.py
@@ -0,0 +1,336 @@
+# Copyright (c) 2014 The Chromium Embedded Framework Authors. All rights
+# reserved. Use of this source code is governed by a BSD-style license that
+# can be found in the LICENSE file.
+
+from __future__ import absolute_import
+from __future__ import print_function
+from io import open
+from optparse import Option, OptionParser, OptionValueError
+import os
+import re
+import sys
+from exec_util import exec_cmd
+from file_util import copy_file, move_file, read_file, remove_file
+import git_util as git
+
+backup_ext = '.cefbak'
+
+
+def msg(message):
+ """ Output a message. """
+ sys.stdout.write('--> ' + message + "\n")
+
+
+def linebreak():
+ """ Output a line break. """
+ sys.stdout.write('-' * 80 + "\n")
+
+
+def warn(message):
+ """ Output a warning. """
+ linebreak()
+ sys.stdout.write('!!!! WARNING: ' + message + "\n")
+ linebreak()
+
+
+def extract_paths(file):
+ """ Extract the list of modified paths from the patch file. """
+ paths = []
+ with open(file, 'r', encoding='utf-8') as fp:
+ for line in fp:
+ if line[:4] != '+++ ':
+ continue
+ match = re.match('^([^\t]+)', line[4:])
+ if not match:
+ continue
+ paths.append(match.group(1).strip())
+ return paths
+
+
+# Cannot be loaded as a module.
+if __name__ != "__main__":
+ sys.stderr.write('This file cannot be loaded as a module!')
+ sys.exit()
+
+# Parse command-line options.
+disc = """
+This utility updates existing patch files.
+"""
+
+
+# Support options with multiple arguments.
+class MultipleOption(Option):
+ ACTIONS = Option.ACTIONS + ("extend",)
+ STORE_ACTIONS = Option.STORE_ACTIONS + ("extend",)
+ TYPED_ACTIONS = Option.TYPED_ACTIONS + ("extend",)
+ ALWAYS_TYPED_ACTIONS = Option.ALWAYS_TYPED_ACTIONS + ("extend",)
+
+ def take_action(self, action, dest, opt, value, values, parser):
+ if action == "extend":
+ values.ensure_value(dest, []).append(value)
+ else:
+ Option.take_action(self, action, dest, opt, value, values, parser)
+
+
+parser = OptionParser(option_class=MultipleOption, description=disc)
+parser.add_option(
+ '--resave',
+ action='store_true',
+ dest='resave',
+ default=False,
+ help='resave existing patch files to pick up manual changes')
+parser.add_option(
+ '--reapply',
+ action='store_true',
+ dest='reapply',
+ default=False,
+ help='reapply the patch without first reverting changes')
+parser.add_option(
+ '--revert',
+ action='store_true',
+ dest='revert',
+ default=False,
+ help='revert all changes from existing patch files')
+parser.add_option(
+ '--backup',
+ action='store_true',
+ dest='backup',
+ default=False,
+ help='backup patched files. Used in combination with --revert.')
+parser.add_option(
+ '--restore',
+ action='store_true',
+ dest='restore',
+ default=False,
+ help='restore backup of patched files that have not changed. If a backup has ' +\
+ 'changed the patch file will be resaved. Used in combination with --reapply.')
+parser.add_option(
+ '--patch',
+ action='extend',
+ dest='patch',
+ type='string',
+ default=[],
+ help='optional patch name to process (multiples allowed)')
+parser.add_option(
+ '--add',
+ action='extend',
+ dest='add',
+ type='string',
+ default=[],
+ help='optional relative file paths to add (multiples allowed). Used in ' +\
+ 'combination with --resave and a single --patch value.')
+(options, args) = parser.parse_args()
+
+if options.resave and options.revert:
+ print('Invalid combination of options.')
+ parser.print_help(sys.stderr)
+ sys.exit()
+
+if len(options.add) > 0 and (len(options.patch) != 1 or not options.resave):
+ print('--add can only be used with --resave and a single --patch value.')
+ parser.print_help(sys.stderr)
+ sys.exit()
+
+# The CEF root directory is the parent directory of _this_ script.
+cef_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir))
+src_dir = os.path.abspath(os.path.join(cef_dir, os.pardir))
+
+# Determine the type of Chromium checkout.
+if not git.is_checkout(src_dir):
+ raise Exception('Not a valid checkout: %s' % src_dir)
+
+patch_dir = os.path.join(cef_dir, 'patch')
+patch_cfg = os.path.join(patch_dir, 'patch.cfg')
+if not os.path.isfile(patch_cfg):
+ raise Exception('File does not exist: %s' % patch_cfg)
+
+# Read the patch configuration file.
+msg('Reading patch config %s' % patch_cfg)
+scope = {}
+exec (compile(open(patch_cfg, "rb").read(), patch_cfg, 'exec'), scope)
+patches = scope["patches"]
+
+failed_patches = {}
+
+# Read each individual patch file.
+patches_dir = os.path.join(patch_dir, 'patches')
+for patch in patches:
+ # If specific patch names are specified only process those patches.
+ if options.patch and not patch['name'] in options.patch:
+ continue
+
+ sys.stdout.write('\n')
+ patch_file = os.path.join(patches_dir, patch['name'] + '.patch')
+
+ if os.path.isfile(patch_file):
+ msg('Reading patch file %s' % patch_file)
+ if 'path' in patch:
+ patch_root_abs = os.path.abspath(os.path.join(src_dir, patch['path']))
+ if not os.path.isdir(patch_root_abs):
+ line = 'Target directory does not exist: %s' % patch_root_abs
+ msg(line)
+ if options.resave:
+ # Report as a fatal error for manual resave only, as the missing
+ # directory may be platform-specific.
+ failed_patches[patch['name']] = [line]
+ continue
+ else:
+ patch_root_abs = src_dir
+
+ # Retrieve the list of paths modified by the patch file.
+ patch_paths = extract_paths(patch_file)
+
+ # List of paths added by the patch file.
+ added_paths = []
+
+ # True if any backed up files have changed.
+ has_backup_changes = False
+
+ if not options.resave:
+ if not options.reapply:
+ # Revert any changes to existing files in the patch.
+ for patch_path in patch_paths:
+ patch_path_abs = os.path.abspath(os.path.join(patch_root_abs, \
+ patch_path))
+ if os.path.exists(patch_path_abs):
+ if options.backup:
+ backup_path_abs = patch_path_abs + backup_ext
+ if not os.path.exists(backup_path_abs):
+ msg('Creating backup of %s' % patch_path_abs)
+ copy_file(patch_path_abs, backup_path_abs)
+ else:
+ msg('Skipping backup of %s' % patch_path_abs)
+
+ msg('Reverting changes to %s' % patch_path_abs)
+ cmd = 'git checkout -- %s' % (patch_path_abs)
+ result = exec_cmd(cmd, patch_root_abs)
+ if result['err'] != '':
+ msg('Failed to revert file: %s' % result['err'])
+ msg('Deleting file %s' % patch_path_abs)
+ os.remove(patch_path_abs)
+ added_paths.append(patch_path_abs)
+ if result['out'] != '':
+ sys.stdout.write(result['out'])
+ else:
+ msg('Skipping non-existing file %s' % patch_path_abs)
+ added_paths.append(patch_path_abs)
+
+ if not options.revert:
+ # Chromium files are occasionally (incorrectly) checked in with Windows
+ # line endings. This will cause the patch tool to fail when attempting
+ # to patch those files on Posix systems. Convert any such files to Posix
+ # line endings before applying the patch.
+ converted_files = []
+ for patch_path in patch_paths:
+ patch_path_abs = os.path.abspath(os.path.join(patch_root_abs, \
+ patch_path))
+ if os.path.exists(patch_path_abs):
+ with open(patch_path_abs, 'r', encoding='utf-8') as fp:
+ contents = fp.read()
+ if "\r\n" in contents:
+ msg('Converting to Posix line endings for %s' % patch_path_abs)
+ converted_files.append(patch_path_abs)
+ contents = contents.replace("\r\n", "\n")
+ with open(patch_path_abs, 'wb') as fp:
+ fp.write(contents)
+
+ # Apply the patch file.
+ msg('Applying patch to %s' % patch_root_abs)
+ patch_string = open(patch_file, 'rb').read()
+ result = exec_cmd('patch -p0', patch_root_abs, patch_string)
+
+ if len(converted_files) > 0:
+ # Restore Windows line endings in converted files so that the diff is
+ # correct if/when the patch file is re-saved.
+ for patch_path_abs in converted_files:
+ with open(patch_path_abs, 'rb') as fp:
+ contents = fp.read()
+ msg('Converting to Windows line endings for %s' % patch_path_abs)
+ contents = contents.replace("\n", "\r\n")
+ with open(patch_path_abs, 'wb') as fp:
+ fp.write(contents)
+
+ if result['err'] != '':
+ raise Exception('Failed to apply patch file: %s' % result['err'])
+ sys.stdout.write(result['out'])
+ if result['out'].find('FAILED') != -1:
+ failed_lines = []
+ for line in result['out'].split('\n'):
+ if line.find('FAILED') != -1:
+ failed_lines.append(line.strip())
+ warn('Failed to apply %s, fix manually and run with --resave' % \
+ patch['name'])
+ failed_patches[patch['name']] = failed_lines
+ continue
+
+ if options.restore:
+ # Restore from backup if a backup exists.
+ for patch_path in patch_paths:
+ patch_path_abs = os.path.abspath(os.path.join(patch_root_abs, \
+ patch_path))
+ backup_path_abs = patch_path_abs + backup_ext
+ if os.path.exists(backup_path_abs):
+ if read_file(patch_path_abs) == read_file(backup_path_abs):
+ msg('Restoring backup of %s' % patch_path_abs)
+ remove_file(patch_path_abs)
+ move_file(backup_path_abs, patch_path_abs)
+ else:
+ msg('Discarding backup of %s' % patch_path_abs)
+ remove_file(backup_path_abs)
+ has_backup_changes = True
+ else:
+ msg('No backup of %s' % patch_path_abs)
+
+ if (not options.revert and not options.reapply) or has_backup_changes:
+ if len(options.add) > 0:
+ # Add additional requested files to the patch.
+ for patch_path in options.add:
+ patch_path_abs = os.path.abspath(os.path.join(patch_root_abs, \
+ patch_path))
+ if os.path.exists(patch_path_abs):
+ msg('Adding file %s' % patch_path_abs)
+ patch_paths.append(patch_path)
+ else:
+ msg('Skipping non-existing file %s' % patch_path_abs)
+
+ msg('Saving changes to %s' % patch_file)
+ if added_paths:
+ # Inform git of the added paths so they appear in the patch file.
+ cmd = 'git add -N %s' % ' '.join(added_paths)
+ result = exec_cmd(cmd, patch_root_abs)
+ if result['err'] != '' and result['err'].find('warning:') != 0:
+ raise Exception('Failed to add paths: %s' % result['err'])
+
+ # Re-create the patch file.
+ patch_paths_str = ' '.join(patch_paths)
+ cmd = 'git diff --no-prefix --relative %s' % patch_paths_str
+ result = exec_cmd(cmd, patch_root_abs)
+ if result['err'] != '' and result['err'].find('warning:') != 0:
+ raise Exception('Failed to create patch file: %s' % result['err'])
+
+ if "\r\n" in result['out']:
+ # Patch files should always be saved with Posix line endings.
+ # This will avoid problems when attempting to re-apply the patch
+ # file on Posix systems.
+ msg('Converting to Posix line endings for %s' % patch_file)
+ result['out'] = result['out'].replace("\r\n", "\n")
+
+ f = open(patch_file, 'w', encoding='utf-8')
+ f.write(result['out'])
+ f.close()
+ else:
+ raise Exception('Patch file does not exist: %s' % patch_file)
+
+if len(failed_patches) > 0:
+ sys.stdout.write("\n")
+ linebreak()
+ sys.stdout.write("!!!! FAILED PATCHES, fix manually and run with --resave\n")
+ for name in sorted(failed_patches.keys()):
+ sys.stdout.write("%s:\n" % name)
+ for line in failed_patches[name]:
+ if sys.platform == 'win32' and line.find('.rej') > 0:
+ # Convert paths to use Windows-style separator.
+ line = line.replace('/', '\\')
+ sys.stdout.write(" %s\n" % line)
+ linebreak()
+ sys.exit(1)
diff --git a/tools/patch_updater.sh b/tools/patch_updater.sh
new file mode 100755
index 00000000..4c3cb127
--- /dev/null
+++ b/tools/patch_updater.sh
@@ -0,0 +1,2 @@
+#!/bin/sh
+python3 tools/patch_updater.py $@
diff --git a/tools/patcher.README.txt b/tools/patcher.README.txt
new file mode 100644
index 00000000..5705601d
--- /dev/null
+++ b/tools/patcher.README.txt
@@ -0,0 +1,18 @@
+Chromium Embedded Framework (CEF) Patch Application Tool -- patcher.py
+-------------------------------------------------------------------------------
+
+Document Last Updated: April 26, 2017
+
+
+OVERVIEW
+--------
+
+The CEF patch application tool is used to apply patches to the Chromium, Blink
+and third-party code bases. Currently only unified diff format is supported.
+See the README.txt file in the patch directory for information on how this tool
+is used.
+
+The patch.[bat|sh] file can be used to run the patch application tool with
+command-line arguments that match the default CEF directory structure and
+output options. Run 'patcher.py -h' for a complete list of available command-
+line arguments.
diff --git a/tools/patcher.py b/tools/patcher.py
new file mode 100644
index 00000000..023e91d4
--- /dev/null
+++ b/tools/patcher.py
@@ -0,0 +1,120 @@
+# Copyright (c) 2009 The Chromium Embedded Framework Authors. All rights
+# reserved. Use of this source code is governed by a BSD-style license that
+# can be found in the LICENSE file.
+
+from __future__ import absolute_import
+import pickle
+from optparse import OptionParser
+import os
+import sys
+from file_util import *
+from git_util import git_apply_patch_file
+
+# Cannot be loaded as a module.
+if __name__ != "__main__":
+ sys.stdout.write('This file cannot be loaded as a module!')
+ sys.exit()
+
+# The CEF root directory is the parent directory of _this_ script.
+cef_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir))
+cef_patch_dir = os.path.join(cef_dir, 'patch')
+src_dir = os.path.abspath(os.path.join(cef_dir, os.pardir))
+
+
+def write_note(type, note):
+ separator = '-' * 79 + '\n'
+ sys.stdout.write(separator)
+ sys.stdout.write('!!!! %s: %s\n' % (type, note))
+ sys.stdout.write(separator)
+
+
+def apply_patch_file(patch_file, patch_dir):
+ ''' Apply a specific patch file in optional patch directory. '''
+ patch_name = patch_file + '.patch'
+ patch_path = os.path.join(cef_patch_dir, 'patches', patch_name)
+
+ if patch_dir is None or len(patch_dir) == 0:
+ patch_dir = src_dir
+ else:
+ if not os.path.isabs(patch_dir):
+ # Apply patch relative to the Chromium 'src' directory.
+ patch_dir = os.path.join(src_dir, patch_dir)
+ patch_dir = os.path.abspath(patch_dir)
+ if not os.path.isdir(patch_dir):
+ sys.stdout.write('\nApply %s in %s\n' % (patch_name, patch_dir))
+ sys.stdout.write('... target directory does not exist (skipping).\n')
+ return 'skip'
+
+ result = git_apply_patch_file(patch_path, patch_dir)
+ if result == 'fail':
+ write_note('ERROR',
+ 'This patch failed to apply. Your build will not be correct.')
+ return result
+
+
+def apply_patch_config():
+ ''' Apply patch files based on a configuration file. '''
+ config_file = os.path.join(cef_patch_dir, 'patch.cfg')
+ if not os.path.isfile(config_file):
+ raise Exception('Patch config file %s does not exist.' % config_file)
+
+ # Parse the configuration file.
+ scope = {}
+ exec (compile(open(config_file, "rb").read(), config_file, 'exec'), scope)
+ patches = scope["patches"]
+
+ results = {'apply': [], 'skip': [], 'fail': []}
+
+ for patch in patches:
+ patch_file = patch['name']
+ dopatch = True
+
+ if 'condition' in patch:
+ # Check that the environment variable is set.
+ if patch['condition'] not in os.environ:
+ sys.stdout.write('\nSkipping patch file %s\n' % patch_file)
+ dopatch = False
+
+ if dopatch:
+ result = apply_patch_file(patch_file, patch['path']
+ if 'path' in patch else None)
+ results[result].append(patch_file)
+
+ if 'note' in patch:
+ write_note('NOTE', patch['note'])
+ else:
+ results['skip'].append(patch_file)
+
+ sys.stdout.write('\n%d patches total (%d applied, %d skipped, %d failed)\n' % \
+ (len(patches), len(results['apply']), len(results['skip']), len(results['fail'])))
+
+ if len(results['fail']) > 0:
+ sys.stdout.write('\n')
+ write_note('ERROR',
+ '%d patches failed to apply. Your build will not be correct.' %
+ len(results['fail']))
+ sys.stdout.write('\nTo manually revert failed patches run:' \
+ '\n$ %s ./tools/patch_updater.py --revert --patch %s\n' %
+ (os.path.basename(sys.executable), ' --patch '.join(results['fail'])))
+ sys.exit(1)
+
+
+# Parse command-line options.
+disc = """
+This utility applies patch files.
+"""
+
+parser = OptionParser(description=disc)
+parser.add_option(
+ '--patch-file', dest='patchfile', metavar='FILE', help='patch source file')
+parser.add_option(
+ '--patch-dir',
+ dest='patchdir',
+ metavar='DIR',
+ help='patch target directory')
+(options, args) = parser.parse_args()
+
+if not options.patchfile is None:
+ apply_patch_file(options.patchfile, options.patchdir)
+else:
+ apply_patch_config()
diff --git a/tools/translator.README.txt b/tools/translator.README.txt
new file mode 100644
index 00000000..2be478f3
--- /dev/null
+++ b/tools/translator.README.txt
@@ -0,0 +1,1697 @@
+Chromium Embedded Framework (CEF) Translator Tool -- translator.py
+-------------------------------------------------------------------------------
+
+Document Last Updated: February 14, 2012
+
+
+OVERVIEW
+--------
+
+The CEF translator tool automatically generates CEF source code based on the
+contents of the CEF header file (cef.h). The generated source code includes the
+main C API header file (cef_capi.h) and all files in the libcef_dll/cpptoc and
+libcef_dll/ctocpp directories.
+
+If any differences are detected between the new translator-generated output and
+the file that currently exists on disk a backup of the existing file will be
+created before the new file is written (this behavior can be controlled using
+a command-line switch -- see 'translator.py -h' for more information). Header
+files (*.h) are completely generated by the translator and should never be
+edited by hand. Implementation files (*.cc) may contain user-created content
+within method and function body blocks. The user-created content is extracted
+from the existing file and inserted into the new translator-generated file. Any
+differences between existing method/function prototypes and new method/function
+prototypes in manually edited implementations will be noted as a warning in new
+output file.
+
+ // WARNING - CHANGED ATTRIBUTES
+ // REMOVED: const wchar_t* key
+ // ADDED: int index
+ // WARNING - CHANGED RETURN VALUE
+ // WAS: void
+ // NOW: int
+ #pragma message("Warning: "__FILE__": MyFunction prototype has changed")
+
+Auto-generated implementations will be added in the new output file for any
+methods/functions that exist in the CEF header file but did not exist in the
+current on-disk implementation file. Each time the translator re-generates the
+implementation file it will warn if an implementation could not be auto-
+generated. Delete the indicated portion of the generated code after adding the
+implementation manually.
+
+ size_t CEF_CALLBACK frame_new_func(struct _cef_frame_t* self)
+ {
+ // BEGIN DELETE BEFORE MODIFYING
+ // AUTO-GENERATED CONTENT
+ #pragma message("Warning: "__FILE__": frame_new_func is not implemented")
+ // END DELETE BEFORE MODIFYING
+ }
+
+If the complete function or method implementation has been auto-generated the
+body of the function or method will contain the following comment.
+
+ // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
+
+If you edit the implementation manually you should remove this comment so that
+CEF will not discard your changes on the next run of the translator tool.
+
+The 'translator.[bat|sh]' file can be used to run the translator tool with
+command- line arguments that match the default CEF directory structure and
+output options. Run 'translator.py -h' for a complete list of available command-
+line arguments.
+
+
+HEADER ATTRIBUTES
+-----------------
+
+Comment-based attribute tags are added before each function, class and method
+definition in the CEF header file to provide the translator with additional
+information about how the output should be generated. The attribute tags must
+be in the form of a comma-delimited list of name=value pairs. Attribute names
+and values must contain only alpha-numeric characters, numbers and underscores,
+and must all exist on a single line.
+
+ /*--cef(name1=value1,name2=value2,name3=value3)--*/
+
+Supported method/function attributes:
+
+ capi_name=[string] (Optional) Force a specific output name for the
+ resulting C API function.
+ optional_param=[param] (Optional) Parameter name that will be optional
+ instead of required.
+ index_param=[param] (Optional) Parameter name representing an index
+ value that will be verified as >= 0.
+ default_retval=[string] (Required for enumeration types, Optional for other
+ types) Specify the default return value.
+ count_func=[param:func] (Required for non-const non-string std::vector
+ types) Specify the C++ function that returns the
+ count of elements for a vector parameter.
+ api_hash_check (Optional) If set an API hash check will be added
+ to the CToCpp version of the method/function.
+
+Supported class attributes:
+
+ source=[library|client] (Required) Indicates whether the class
+ implementation is provided by the library or the
+ client. This effects the generation of guard
+ blocks in the cpptoc and ctocpp header files.
+ no_debugct_check (Optional) If set the debug reference count
+ of the object will not be checked on shutdown.
+
+
+TRANSLATION RULES
+-----------------
+
+All C++ names in the CEF header file are written in CamelCaps format and all
+C API translations are generated in lowercase_underscore format.
+
+
+Translating Classes and Methods
+-------------------------------
+
+Class names and global function names must be prefixed with the 'Cef' string.
+
+ Global function translation
+ C++: void CefShutdown()
+ C API: void cef_shutdown()
+
+The translation of a C++ class name to a C API structure name is prefixed with
+'_' and postfixed with '_t'. A typedef of the C API structure to a value
+without the prefixed '_' is also provided and may be used interchangeably.
+
+ Class name translation
+ C++: class CefPostData
+ C API: typedef struct _cef_post_data_t { ... } cef_post_data_t
+
+The translation of a C++ virtual class method to a C API member function adds a
+'self' structure pointer as the first parameter. This will always be a pointer
+to the structure that contains the member function.
+
+ Virtual method translation
+ C++: virtual void SetFocus(bool enable)
+ C API: void set_focus(struct _cef_browser_t* self, int enable)
+
+The translation of a C++ static class method to a C API global function
+is prefixed with 'cef_classname_' where 'classname' is the
+lowercase_underscore name of the class that contains the static method. Any
+repeat of 'classname' in the function name is removed.
+
+ Static method translation
+ C++: static CefRefPtr<CefRequest> CreateRequest()
+ C API: struct _cef_request_t* cef_request_create()
+
+Implementation of the wrapper method/function body is generally formatted as
+follows.
+
+ Static/Global CppToC (without Return):
+
+ CEF_EXPORT void cef_function(capi_params)
+ {
+ // Parameter Verification (Optional)
+ // Verify the C parameter values.
+ // ...
+
+ // Parameter Translation (Optional)
+ // Convert C parameter values to C++ parameter values.
+ // ...
+
+ // Execution
+ CefFunction(cpp_arams);
+
+ // Parameter Restoration (Optional)
+ // Retore the C parameter values if changed.
+ // ...
+ }
+
+ Static/Global CppToC (with Return):
+
+ CEF_EXPORT capi_retval cef_function(capi_params)
+ {
+ // Parameter Verification (Optional)
+ // Verify the C parameter values.
+ // ...
+
+ // Parameter Translation (Optional)
+ // Convert C parameter values to C++ parameter values.
+ // ...
+
+ // Execution
+ cpp_retval _rv = CefFunction(cpp_params);
+
+ // Parameter Restoration (Optional)
+ // Restore the C parameter values if changed.
+ // ...
+
+ // Return Translation
+ // Convert the C++ return value to a C return value.
+ return ...;
+ }
+
+ Static/Global CToCpp (without Return):
+
+ void CefFunction(cpp_params)
+ {
+ // Parameter Verification (Optional)
+ // Verify the C++ parameter values.
+ // ...
+
+ // Parameter Translation (Optional)
+ // Convert C++ parameter values to C parameter values.
+ // ...
+
+ // Execution
+ cef_function(capi_params);
+
+ // Parameter Restoration (Optional)
+ // Restore the C++ parameter values if changed.
+ // ...
+ }
+
+ Static/Global CToCpp (with Return):
+
+ cpp_retval CefFunction(cpp_params)
+ {
+ // Parameter Verification (Optional)
+ // Verify the C++ parameter values.
+ // ...
+
+ // Parameter Translation (Optional)
+ // Convert C++ parameter values to C parameter values.
+ // ...
+
+ // Execution
+ capi_retval _rv = cef_function(capi_params);
+
+ // Parameter Restoration (Optional)
+ // Restore the C++ parameter values if changed.
+ // ...
+
+ // Return Translation
+ // Convert the C return value to a C++ return value.
+ return ...;
+ }
+
+ Member CppToC (without Return):
+
+ CEF_CALLBACK void class_function(cef_class_t* self, capi_params)
+ {
+ // Parameter Verification.
+ // Verify the C parameter values.
+ DCHECK(self);
+ DCHECK(...);
+ if (!self || ...)
+ return;
+
+ // Parameter Translation (Optional)
+ // Convert the C parameter values to C++ parameter values.
+ // ...
+
+ // Execution
+ CefClassCppToC::Get(self)->CefFunction(cpp_params);
+
+ // Parameter Restoration (Optional)
+ // Restore the C parameter values if changed.
+ // ...
+ }
+
+ Member CppToC (with Return):
+
+ CEF_CALLBACK capi_retval class_function(cef_class_t* self, capi_params)
+ {
+ // Parameter Verification.
+ // Verify the C parameter values.
+ DCHECK(self);
+ DCHECK(...);
+ if (!self || ...)
+ return default_retval; // Configured or defaulted automatically.
+
+ // Parameter Translation (Optional)
+ // Convert the C parameter values to C++ parameter values.
+ // ...
+
+ // Execution
+ cpp_retval _rv = CefClassCppToC::Get(self)->CefFunction(cpp_params);
+
+ // Parameter Restoration (Optional)
+ // Restore the C parameter values if changed.
+ // ...
+
+ // Return Translation
+ // Convert the C++ return value to a C return value.
+ return ...;
+ }
+
+ Member CToCpp (without Return):
+
+ void CefClassCToCpp::Function(cpp_params)
+ {
+ // Structure Verification
+ if (CEF_MEMBER_MISSING(struct_, function))
+ return;
+
+ // Parameter Verification (Optional)
+ // Verify the C++ parameter values.
+ // ...
+
+ // Parameter Translation (Optional)
+ // Convert C++ parameter values to C parameter values.
+ // ...
+
+ // Execution
+ struct_->class_function(struct_, capi_params);
+
+ // Parameter Restoration (Optional)
+ // Restore the C++ parameter values if changed.
+ // ...
+ }
+
+ Member CToCpp (with Return):
+
+ cpp_retval CefClassCToCpp::Function(cpp_params)
+ {
+ // Structure Verification
+ if (CEF_MEMBER_MISSING(struct_, function))
+ return default_retval; // Configured or defaulted automatically.
+
+ // Parameter Verification (Optional)
+ // Verify the C++ parameter values.
+ // ...
+
+ // Parameter Translation (Optional)
+ // Convert C++ parameter values to C parameter values.
+ // ...
+
+ // Execution
+ capi_retval _rv = struct_->class_function(struct_, capi_params);
+
+ // Parameter Restoration (Optional)
+ // Restore the C++ parameter values if changed.
+ // ...
+
+ // Return Translation
+ // Convert the C return value to a C++ return value.
+ return ...;
+ }
+
+
+Translating Data Types
+----------------------
+
+Data types that are available in both C++ and C are left unchanged. This
+includes the 'double', 'int', 'long', 'size_t' and 'void' basic types. Other
+data types have differing levels of support as indicated below. The translation
+tool will terminate with an exception if it encounters a data type that it
+cannot translate.
+
+Parameters:
+
+ Simple/enumeration type by value (simple_byval):
+ C++: int value
+ C API: int value
+
+ // CppToC Example
+ CEF_EXPORT void cef_function(int value)
+ {
+ // Execution
+ CefFunction(value);
+ }
+
+ // CToCpp Example
+ void CefFunction(int value)
+ {
+ // Execution
+ cef_function(value);
+ }
+
+ Simple/enumeration type by reference (simple_byref):
+ C++: int& value
+ C API: int* value
+
+ // CppToC Example
+ CEF_EXPORT void cef_function(int* value)
+ {
+ // Parameter Verification
+ DHECK(value);
+ if (!value)
+ return;
+
+ // Parameter Translation
+ int valueVal = value?*value:0;
+
+ // Execution
+ CefFunction(valueVal);
+
+ // Parameter Restoration
+ if (value)
+ *value = valueVal;
+ }
+
+ // CToCpp Example
+ void CefFunction(int& value)
+ {
+ // Execution
+ cef_function(&value);
+ }
+
+ Simple/enumeration const type by reference (simple_byref_const):
+ C++: const int& value
+ C API: const int* value
+
+ // CppToC Example
+ CEF_EXPORT void cef_function(const int* value)
+ {
+ // Parameter Verification
+ DHECK(value);
+ if (!value)
+ return;
+
+ // Parameter Translation
+ int valueVal = value?*value:0;
+
+ // Execution
+ CefFunction(valueVal);
+ }
+
+ // CToCpp Example
+ void CefFunction(const int& value)
+ {
+ // Execution
+ cef_function(&value);
+ }
+
+ Simple/enumeration type by address (simple_byaddr):
+ C++: int* value
+ C API: int* value
+
+ // CppToC Example
+ CEF_EXPORT void cef_function(int* value)
+ {
+ // Parameter Verification
+ DHECK(value);
+ if (!value)
+ return;
+
+ // Execution
+ CefFunction(value);
+ }
+
+ // CToCpp Example
+ void CefFunction(int* value)
+ {
+ // Parameter Verification
+ DHECK(value);
+ if (!value)
+ return;
+
+ // Execution
+ cef_function(value);
+ }
+
+ Boolean type by value (bool_byval):
+ C++: bool value
+ C API: int value
+
+ // CppToC Example
+ CEF_EXPORT void cef_function(int value)
+ {
+ // Execution
+ CefFunction(value?true:false);
+ }
+
+ // CToCpp Example
+ void CefFunction(bool value)
+ {
+ // Execution
+ cef_function(value);
+ }
+
+ Boolean type by reference (bool_byref):
+ C++: bool& value
+ C API: int* value
+
+ // CppToC Example
+ CEF_EXPORT void cef_function(int* value)
+ {
+ // Parameter Verification
+ DHECK(value);
+ if (!value)
+ return;
+
+ // Parameter Translation
+ bool valueBool = (value && *value)?true:false;
+
+ // Execution
+ CefFunction(valueBool);
+
+ // Parameter Restoration
+ if (value)
+ *value = valueBool?true:false;
+ }
+
+ // CToCpp Example
+ void CefFunction(bool& value)
+ {
+ // Parameter Translation
+ int valueInt = value;
+
+ // Execution
+ cef_function(&valueInt);
+
+ // Parameter Restoration
+ value = valueInt?true:false;
+ }
+
+ Boolean type by address (bool_byaddr):
+ C++: bool* value
+ C API: int* value
+
+ // CppToC Example
+ CEF_EXPORT void cef_function(int* value)
+ {
+ // Parameter Verification
+ DHECK(value);
+ if (!value)
+ return;
+
+ // Parameter Translation
+ bool valueBool = (value && *value)?true:false;
+
+ // Execution
+ CefFunction(&valueBool);
+
+ // Parameter Restoration
+ if (value)
+ *value = valueBool?true:false;
+ }
+
+ // CToCpp Example
+ void CefFunction(bool* value)
+ {
+ // Parameter Verification
+ DHECK(value);
+ if (!value)
+ return;
+
+ // Parameter Translation
+ int valueInt = value?*value:0;
+
+ // Execution
+ cef_function(&valueInt);
+
+ // Parameter Restoration
+ if (value)
+ *value = valueInt?true:false;
+ }
+
+ Structure const type by reference (struct_byref_const):
+ C++: const CefPopupFeatures& value
+ C API: const cef_popup_features_t* value
+
+ // CppToC Example
+ CEF_EXPORT void cef_function(const cef_popup_features_t* value)
+ {
+ // Parameter Verification
+ DHECK(value);
+ if (!value)
+ return;
+
+ // Parameter Translation
+ CefPopupFeatures valueObj;
+ // Reference the existing values instead of copying.
+ if (value)
+ valueObj.Set(*value, false);
+
+ // Execution
+ CefFunction(valueObj);
+ }
+
+ // CToCpp Example
+ void CefFunction(const CefPopupFeatures& value)
+ {
+ // Execution
+ cef_function(&value);
+ }
+
+ Structure non-const type by reference (struct_byref):
+ C++: CefWindowInfo& value
+ C API: cef_window_info_t* value
+
+ // CppToC Example
+ CEF_EXPORT void cef_function(cef_window_info_t* value)
+ {
+ // Parameter Verification
+ DHECK(value);
+ if (!value)
+ return;
+
+ // Parameter Translation
+ CefWindowInfo valueObj;
+ // Take ownership of the values.
+ if (value)
+ valueObj.AttachTo(*value);
+
+ // Execution
+ CefFunction(valueObj);
+
+ // Parameter Restoration
+ // Return the values to the structure.
+ if (value)
+ valueObj.DetachTo(*value);
+ }
+
+ // CToCpp Example
+ void CefFunction(CefWindowInfo& value)
+ {
+ // Execution
+ cef_function(&value);
+ }
+
+ String const type by reference (string_byref_const):
+ C++: const CefString& value
+ C API: const cef_string_t* value
+
+ // CppToC Example
+ CEF_EXPORT void cef_function(const cef_string_t* value)
+ {
+ // Parameter Verification
+ DHECK(value);
+ if (!value)
+ return;
+
+ // Execution
+ CefFunction(CefString(value));
+ }
+
+ // CToCpp Example
+ void CefFunction(const CefString& value)
+ {
+ // Execution
+ cef_function(value.GetStruct());
+ }
+
+ String non-const type by reference (string_byref):
+ C++: CefString& value
+ C API: cef_string_t* value
+
+ // CppToC Example
+ CEF_EXPORT void cef_function(cef_string_t* value)
+ {
+ // Parameter Verification
+ DHECK(value);
+ if (!value)
+ return;
+
+ // Parameter Translation
+ CefString valueStr(value);
+
+ // Execution
+ CefFunction(valueStr);
+ }
+
+ // CToCpp Example
+ void CefFunction(CefString& value)
+ {
+ // Execution
+ cef_function(value.GetWritableStruct());
+ }
+
+ Smart pointer type same boundary side (refptr_same):
+ C++: CefRefPtr<CefBrowser> value
+ C API: cef_browser_t* value
+
+ // CppToC Example
+ CEF_EXPORT void cef_function(cef_browser_t* value)
+ {
+ // Parameter Verification
+ DHECK(value);
+ if (!value)
+ return;
+
+ // Execution
+ CefFunction(CefBrowserCppToC::Unwrap(value));
+ }
+
+ // CToCpp Example
+ void CefFunction(CefRefPtr<CefBrowser> value)
+ {
+ // Execution
+ cef_function(CefBrowserCToCpp::Unwrap(value));
+ }
+
+ Smart pointer type same boundary side by reference (refptr_same_byref):
+ C++: CefRefPtr<CefClient>& value
+ C API: cef_client_t** value
+
+ // CppToC Example
+ CEF_EXPORT void cef_function(cef_client_t** value)
+ {
+ // Parameter Verification
+ DHECK(value);
+ if (!value)
+ return;
+
+ // Parameter Translation
+ CefRefPtr<CefClient> valuePtr;
+ if (value && *value)
+ valuePtr = CefClientCppToC::Unwrap(*value);
+ CefClient* valueOrig = valuePtr.get();
+
+ // Execution
+ CefFunction(valuePtr);
+
+ // Parameter Restoration
+ if (value) {
+ if (valuePtr.get()) {
+ if (valuePtr.get() != valueOrig) {
+ // The value has been changed.
+ *value = CefClientCppToC::Wrap(valuePtr);
+ }
+ } else {
+ *value = NULL;
+ }
+ }
+ }
+
+ // CToCpp Example
+ void CefFunction(CefRefPtr<CefClient>& value)
+ {
+ // Parameter Translation
+ cef_client_t* valueStruct = NULL;
+ if(value.get())
+ valueStruct = CefClientCToCpp::Unwrap(value);
+ cef_client_t* valueOrig = valueStruct;
+
+ // Execution
+ cef_function(valueStuct);
+
+ // Parameter Restoration
+ if (valueStruct) {
+ if (valueStruct != valueOrig) {
+ // The value was changed.
+ value = CefClientCToCpp::Wrap(valueStruct);
+ }
+ } else {
+ value = NULL;
+ }
+ }
+
+ Smart pointer type different boundary side (refptr_diff):
+ C++: CefRefPtr<CefBrowser> value
+ C API: cef_browser_t* value
+
+ // CppToC Example
+ CEF_EXPORT void cef_function(cef_browser_t* value)
+ {
+ // Parameter Verification
+ DHECK(value);
+ if (!value)
+ return;
+
+ // Execution
+ CefFunction(CefBrowserCToCpp::Wrap(value));
+ }
+
+ // CToCpp Example
+ void CefFunction(CefRefPtr<CefBrowser> value)
+ {
+ // Execution
+ cef_function(CefBrowserCppToC::Wrap(value));
+ }
+
+ Smart pointer type different boundary side by reference (refptr_diff_byref):
+ C++: CefRefPtr<CefClient>& value
+ C API: cef_client_t** value
+
+ // CppToC Example
+ CEF_EXPORT void cef_function(cef_client_t** value)
+ {
+ // Parameter Verification
+ DHECK(value);
+ if (!value)
+ return;
+
+ // Parameter Translation
+ CefRefPtr<CefClient> valuePtr;
+ if (value && *value)
+ valuePtr = CefClientCToCpp::Wrap(*value);
+ CefClient* valueOrig = valuePtr.get();
+
+ // Execution
+ CefFunction(valuePtr);
+
+ // Parameter Restoration
+ if (value) {
+ if (valuePtr.get()) {
+ if (valuePtr.get() != valueOrig) {
+ // The value has been changed.
+ *value = CefClientCToCpp::Unwrap(valuePtr);
+ }
+ } else {
+ *value = NULL;
+ }
+ }
+ }
+
+ // CToCpp Example
+ void CefFunction(CefRefPtr<CefClient>& value)
+ {
+ // Parameter Translation
+ cef_client_t* valueStruct = NULL;
+ if(value.get())
+ valueStruct = CefClientCppToC::Wrap(value);
+ cef_client_t* valueOrig = valueStruct;
+
+ // Execution
+ cef_function(valueStuct);
+
+ // Parameter Restoration
+ if (valueStruct) {
+ if (valueStruct != valueOrig) {
+ // The value was changed.
+ value = CefClientCppToC::Unwrap(valueStruct);
+ }
+ } else {
+ value = NULL;
+ }
+ }
+
+ String vector type by reference (string_vec_byref):
+ C++: std::vector<CefString>& value
+ C API: cef_string_list_t value
+
+ // CppToC Example
+ CEF_EXPORT void cef_function(cef_string_list_t value)
+ {
+ // Parameter Verification
+ DHECK(value);
+ if (!value)
+ return;
+
+ // Parameter Translation
+ std::vector<CefString> valueList;
+ transfer_string_list_contents(value, valueList);
+
+ // Execution
+ CefFunction(valueList);
+
+ // Parameter Restoration
+ cef_string_list_clear(value);
+ transfer_string_list_contents(valueList, value);
+ }
+
+ // CToCpp Example
+ void CefFunction(std::vector<CefString>& value)
+ {
+ // Parameter Translation
+ cef_string_list_t valueList = cef_string_list_alloc();
+ DCHECK(valueList);
+ if (valueList)
+ transfer_string_list_contents(value, valueList);
+
+ // Execution
+ cef_function(valueList);
+
+ // Parameter Restoration
+ if (valueList) {
+ value.clear();
+ transfer_string_list_contents(valueList, value);
+ cef_string_list_free(valueList);
+ }
+ }
+
+ String vector const type by reference (string_vec_byref_const):
+ C++: const std::vector<CefString>& value
+ C API: cef_string_list_t value
+
+ // CppToC Example
+ CEF_EXPORT void cef_function(cef_string_list_t value)
+ {
+ // Parameter Verification
+ DHECK(value);
+ if (!value)
+ return;
+
+ // Parameter Translation
+ std::vector<CefString> valueList;
+ transfer_string_list_contents(value, valueList);
+
+ // Execution
+ CefFunction(valueList);
+ }
+
+ // CToCpp Example
+ void CefFunction(const std::vector<CefString>& value)
+ {
+ // Parameter Translation
+ cef_string_list_t valueList = cef_string_list_alloc();
+ DCHECK(valueList);
+ if (valueList)
+ transfer_string_list_contents(value, valueList);
+
+ // Execution
+ cef_function(valueList);
+
+ // Parameter Restoration
+ if (valueList)
+ cef_string_list_free(valueList);
+ }
+
+ String-to-string single map type by reference (string_map_single_byref):
+ C++: std::map<CefString,CefString>& value
+ C API: cef_string_map_t value
+
+ // CppToC Example
+ CEF_EXPORT void cef_function(cef_string_map_t value)
+ {
+ // Parameter Verification
+ DHECK(value);
+ if (!value)
+ return;
+
+ // Parameter Translation
+ std::map<CefString,CefString> valueMap;
+ transfer_string_map_contents(value, valueMap);
+
+ // Execution
+ CefFunction(valueMap);
+
+ // Parameter Restoration
+ cef_string_map_clear(value);
+ transfer_string_map_contents(valueMap, value);
+ }
+
+ // CToCpp Example
+ void CefFunction(std::map<CefString,CefString>& value)
+ {
+ // Parameter Translation
+ cef_string_map_t valueMap = cef_string_map_alloc();
+ DCHECK(valueMap);
+ if (valueMap)
+ transfer_string_map_contents(value, valueMap);
+
+ // Execution
+ cef_function(valueMap);
+
+ // Parameter Restoration
+ if (valueMap) {
+ value.clear();
+ transfer_string_map_contents(valueMap, value);
+ cef_string_map_free(valueMap);
+ }
+ }
+
+ String-to-string single map const type by reference
+ (string_map_single_byref_const):
+ C++: const std::map<CefString,CefString>& value
+ C API: cef_string_map_t value
+
+ // CppToC Example
+ CEF_EXPORT void cef_function(cef_string_map_t value)
+ {
+ // Parameter Verification
+ DHECK(value);
+ if (!value)
+ return;
+
+ // Parameter Translation
+ std::map<CefString,CefString> valueMap;
+ transfer_string_map_contents(value, valueMap);
+
+ // Execution
+ CefFunction(valueMap);
+ }
+
+ // CToCpp Example
+ void CefFunction(const std::map<CefString,CefString>& value)
+ {
+ // Parameter Translation
+ cef_string_map_t valueMap = cef_string_map_alloc();
+ DCHECK(valueMap);
+ if (valueMap)
+ transfer_string_map_contents(value, valueMap);
+
+ // Execution
+ cef_function(valueMap);
+
+ // Parameter Restoration
+ if (valueMap)
+ cef_string_map_free(valueMap);
+ }
+
+ String-to-string multi map type by reference (string_map_multi_byref):
+ C++: std::multimap<CefString,CefString>& value
+ C API: cef_string_multimap_t value
+
+ // CppToC Example
+ CEF_EXPORT void cef_function(cef_string_multimap_t value)
+ {
+ // Parameter Verification
+ DHECK(value);
+ if (!value)
+ return;
+
+ // Parameter Translation
+ std::multimap<CefString,CefString> valueMultimap;
+ transfer_string_multimap_contents(value, valueMultimap);
+
+ // Execution
+ CefFunction(valueMultimap);
+
+ // Parameter Restoration
+ cef_string_multimap_clear(value);
+ transfer_string_multimap_contents(valueMultimap, value);
+ }
+
+ // CToCpp Example
+ void CefFunction(std::multimap<CefString,CefString>& value)
+ {
+ // Parameter Translation
+ cef_string_multimap_t valueMultimap = cef_string_multimap_alloc();
+ DCHECK(valueMultimap);
+ if (valueMultimap)
+ transfer_string_multimap_contents(value, valueMultimap);
+
+ // Execution
+ cef_function(valueMultimap);
+
+ // Parameter Restoration
+ if (valueMultimap) {
+ value.clear();
+ transfer_string_multimap_contents(valueMultimap, value);
+ cef_string_multimap_free(valueMultimap);
+ }
+ }
+
+ String-to-string multi map const type by reference
+ (string_map_multi_byref_const):
+ C++: const std::multimap<CefString,CefString>& value
+ C API: cef_string_multimap_t value
+
+ // CppToC Example
+ CEF_EXPORT void cef_function(cef_string_multimap_t value)
+ {
+ // Parameter Verification
+ DHECK(value);
+ if (!value)
+ return;
+
+ // Parameter Translation
+ std::multimap<CefString,CefString> valueMultimap;
+ transfer_string_multimap_contents(value, valueMultimap);
+
+ // Execution
+ CefFunction(valueMultimap);
+ }
+
+ // CToCpp Example
+ void CefFunction(const std::multimap<CefString,CefString>& value)
+ {
+ // Parameter Translation
+ cef_string_multimap_t valueMultimap = cef_string_multimap_alloc();
+ DCHECK(valueMultimap);
+ if (valueMultimap)
+ transfer_string_multimap_contents(value, valueMultimap);
+
+ // Execution
+ cef_function(valueMultimap);
+
+ // Parameter Restoration
+ if (valueMultimap)
+ cef_string_multimap_free(valueMultimap);
+ }
+
+ Simple/Enumeration vector non-const type by reference (simple_vec_byref):
+ C++: std::vector<int>& value
+ C API: size_t* valueCount, int* value
+
+ // CppToC Example
+ CEF_EXPORT void cef_function(size_t* valueCount, int* value)
+ {
+ // Parameter Verification
+ DCHECK(valueCount && (*valueCount == 0 || value));
+ if (!valueCount || (*valueCount > 0 && !value))
+ return;
+
+ // Parameter Translation
+ std::vector<int> valueList;
+ if (valueCount && *valueCount > 0 && value) {
+ for (size_t i = 0; i < *valueCount; ++i)
+ valueList.push_back(value[i]);
+ }
+
+ // Execution
+ CefFunction(valueList);
+
+ // Parameter Restoration
+ if (valueCount && value) {
+ *valueCount = std::min(valueList.size(), *valueCount);
+ if (*valueCount > 0) {
+ for (size_t i = 0; i < *valueCount; ++i)
+ value[i] = valueList[i];
+ }
+ }
+ }
+
+ // CToCpp Example
+ void CefFunction(std::vector<int>& value)
+ {
+ // Parameter Translation
+ // Function identified by the "count_func" method attribute.
+ size_t valueSize = value.size();
+ size_t valueCount = std::max(GetFunctionCount(), valueSize);
+ int* valueList = NULL;
+ if (valueCount > 0) {
+ valueList = new int[valueCount];
+ DCHECK(valueList);
+ if (valueList)
+ memset(valueList, 0, sizeof(int)*valueCount);
+ if (valueList && valueSize > 0) {
+ for (size_t i = 0; i < valueSize; ++i) {
+ valueList[i] = value[i];
+ }
+ }
+ }
+
+ // Execution
+ cef_function(&valueCount, valueList);
+
+ // Parameter Restoration
+ value.clear();
+ if (valueCount > 0 && valueList) {
+ for (size_t i = 0; i < valueCount; ++i)
+ value.push_back(valueList[i]);
+ delete [] valueList;
+ }
+ }
+
+ Simple/Enumeration vector const type by reference (simple_vec_byref_const):
+ C++: const std::vector<int>& value
+ C API: size_t valueCount, int const* value
+
+ // CppToC Example
+ CEF_EXPORT void cef_function(size_t valueCount, int const* value)
+ {
+ // Parameter Verification
+ DCHECK(valueCount == 0 || value);
+ if (valueCount > 0 && !value)
+ return;
+
+ // Parameter Translation
+ std::vector<int> valueList;
+ if (valueCount > 0) {
+ for (size_t i = 0; i < valueCount; ++i)
+ valueList.push_back(value[i]);
+ }
+
+ // Execution
+ CefFunction(valueList);
+ }
+
+ // CToCpp Example
+ void CefFunction(const std::vector<int>& value)
+ {
+ // Parameter Translation
+ const size_t valueCount = value.size();
+ int* valueList = NULL;
+ if (valueCount > 0) {
+ valueList = new int[valueCount];
+ DCHECK(valueList);
+ if (valueList) {
+ for (size_t i = 0; i < valueCount; ++i)
+ valueList[i] = value[i];
+ }
+ }
+
+ // Execution
+ cef_function(valueCount, valueList);
+
+ // Parameter Restoration
+ if (valueList)
+ delete [] valueList;
+ }
+
+ Boolean vector non-const type by reference (bool_vec_byref):
+ C++: std::vector<bool>& value
+ C API: size_t* valueCount, int* value
+
+ // CppToC Example
+ CEF_EXPORT void cef_function(size_t* valueCount, int* value)
+ {
+ // Parameter Verification
+ DCHECK(valueCount && (*valueCount == 0 || value));
+ if (!valueCount || (*valueCount > 0 && !value))
+ return;
+
+ // Parameter Translation
+ std::vector<bool> valueList;
+ if (valueCount && *valueCount > 0 && value) {
+ for (size_t i = 0; i < *valueCount; ++i)
+ valueList.push_back(value[i]?true:false);
+ }
+
+ // Execution
+ CefFunction(valueList);
+
+ // Parameter Restoration
+ if (valueCount && value) {
+ *valueCount = std::min(valueList.size(), *valueCount);
+ if (*valueCount > 0) {
+ for (size_t i = 0; i < *valueCount; ++i)
+ value[i] = valueList[i];
+ }
+ }
+ }
+
+ // CToCpp Example
+ void CefFunction(std::vector<bool>& value)
+ {
+ // Parameter Translation
+ // Function identified by the "count_func" method attribute.
+ size_t valueSize = value.size();
+ size_t valueCount = std::max(GetFunctionCount(), valueSize);
+ int* valueList = NULL;
+ if (valueCount > 0) {
+ valueList = new int[valueCount];
+ DCHECK(valueList);
+ if (valueList)
+ memset(valueList, 0, sizeof(int)*valueCount);
+ if (valueList && valueSize > 0) {
+ for (size_t i = 0; i < valueSize; ++i) {
+ valueList[i] = value[i];
+ }
+ }
+ }
+
+ // Execution
+ cef_function(&valueCount, valueList);
+
+ // Parameter Restoration
+ value.clear();
+ if (valueCount > 0 && valueList) {
+ for (size_t i = 0; i < valueCount; ++i)
+ value.push_back(valueList[i]?true:false);
+ delete [] valueList;
+ }
+ }
+
+ Boolean vector const type by reference (bool_vec_byref_const):
+ C++: const std::vector<bool>& value
+ C API: size_t valueCount, int const* value
+
+ // CppToC Example
+ CEF_EXPORT void cef_function(size_t valueCount, int const* value)
+ {
+ // Parameter Verification
+ DCHECK(valueCount == 0 || value);
+ if (valueCount > 0 && !value)
+ return;
+
+ // Parameter Translation
+ std::vector<bool> valueList;
+ if (valueCount > 0) {
+ for (size_t i = 0; i < valueCount; ++i)
+ valueList.push_back(value[i]?true:false);
+ }
+
+ // Execution
+ CefFunction(valueList);
+ }
+
+ // CToCpp Example
+ void CefFunction(const std::vector<bool>& value)
+ {
+ // Parameter Translation
+ const size_t valueCount = value.size();
+ int* valueList = NULL;
+ if (valueCount > 0) {
+ valueList = new int[valueCount];
+ DCHECK(valueList)
+ if (valueList) {
+ for (size_t i = 0; i < valueCount; ++i)
+ valueList[i] = value[i];
+ }
+ }
+
+ // Execution
+ cef_function(valueCount, valueList);
+
+ // Parameter Restoration
+ if (valueList)
+ delete [] valueList;
+ }
+
+ Smart pointer vector non-const type same boundary side by reference
+ (refptr_vec_same_byref):
+ C++: std::vector<CefRefPtr<CefPostDataElement>>& value
+ C API: size_t* valueCount, cef_post_data_element_t** value
+
+ // CppToC Example
+ CEF_EXPORT void cef_function(size_t* valueCount,
+ cef_post_data_element_t** value)
+ {
+ // Parameter Verification
+ DCHECK(valueCount && (*valueCount == 0 || value));
+ if (!valueCount || (*valueCount > 0 && !value))
+ return;
+
+ // Parameter Translation
+ std::vector<CefRefPtr<CefPostDataElement>> valueList;
+ if (valueCount && *valueCount > 0 && value) {
+ for (size_t i = 0; i < *valueCount; ++i)
+ valueList.push_back(CefPostDataElementCppToC::Unwrap(value[i]));
+ }
+
+ // Execution
+ CefFunction(valueList);
+
+ // Parameter Restoration
+ if (valueCount && value) {
+ *valueCount = std::min(valueList.size(), *valueCount);
+ if (*valueCount > 0) {
+ for (size_t i = 0; i < *valueCount; ++i)
+ value[i] = CefPostDataElementCppToC::Wrap(valueList[i]);
+ }
+ }
+ }
+
+ // CToCpp Example
+ void CefFunction(std::vector<bool>& value)
+ {
+ // Parameter Translation
+ // Function identified by the "count_func" method attribute.
+ size_t valueSize = value.size();
+ size_t valueCount = std::max(GetFunctionCount(), valueSize);
+ cef_post_data_element_t** valueList = NULL;
+ if (valueCount > 0) {
+ valueList = new cef_post_data_element_t*[valueCount];
+ DCHECK(valueList);
+ if (valueList)
+ memset(valueList, 0, sizeof(cef_post_data_element_t*)*valueCount);
+ if (valueList && valueSize > 0) {
+ for (size_t i = 0; i < valueSize; ++i) {
+ valueList[i] = CefPostDataElementCToCpp::Unwrap(value[i]);
+ }
+ }
+ }
+
+ // Execution
+ cef_function(&valueCount, valueList);
+
+ // Parameter Restoration
+ value.clear();
+ if (valueCount > 0 && valueList) {
+ for (size_t i = 0; i < valueCount; ++i)
+ value.push_back(CefPostDataElementCToCpp::Wrap(valueList[i]));
+ delete [] valueList;
+ }
+ }
+
+ Smart pointer vector const type same boundary side by reference
+ (refptr_vec_same_byref_const):
+ C++: const std::vector<CefRefPtr<CefV8Value>>& value
+ C API: size_t valueCount, const cef_v8value_t** value
+
+ // CppToC Example
+ CEF_EXPORT void cef_function(size_t valueCount,
+ const cef_v8value_t** value)
+ {
+ // Parameter Verification
+ DCHECK(valueCount == 0 || value);
+ if (valueCount > 0 && !value)
+ return;
+
+ // Parameter Translation
+ std::vector<CefRefPtr<CefV8Value>> valueList;
+ if (valueCount > 0) {
+ for (size_t i = 0; i < valueCount; ++i)
+ valueList.push_back(CefV8ValueCppToC::Unwrap(value[i]));
+ }
+
+ // Execution
+ CefFunction(valueList);
+ }
+
+ // CToCpp Example
+ void CefFunction(const std::vector<bool>& value)
+ {
+ // Parameter Translation
+ const size_t valueCount = value.size();
+ cef_v8value_t** valueList = NULL;
+ if (valueCount > 0) {
+ valueList = new int[valueCount];
+ DCHECK(valueList);
+ if (valueList) {
+ for (size_t i = 0; i < valueCount; ++i)
+ valueList[i] = CefV8ValueCToCpp::Unwrap(value[i]);
+ }
+ }
+
+ // Execution
+ cef_function(valueCount, valueList);
+
+ // Parameter Restoration
+ if (valueList)
+ delete [] valueList;
+ }
+
+ Smart pointer vector non-const type different boundary side by reference
+ (refptr_vec_diff_byref):
+ C++: std::vector<CefRefPtr<CefPostDataElement>>& value
+ C API: size_t* valueCount, cef_post_data_element_t** value
+
+ // CppToC Example
+ CEF_EXPORT void cef_function(size_t* valueCount,
+ cef_post_data_element_t** value)
+ {
+ // Parameter Verification
+ DCHECK(valueCount && (*valueCount == 0 || value));
+ if (!valueCount || (*valueCount > 0 && !value))
+ return;
+
+ // Parameter Translation
+ std::vector<CefRefPtr<CefPostDataElement>> valueList;
+ if (valueCount && *valueCount > 0 && value) {
+ for (size_t i = 0; i < *valueCount; ++i)
+ valueList.push_back(CefPostDataElementCToCpp::Wrap(value[i]));
+ }
+
+ // Execution
+ CefFunction(valueList);
+
+ // Parameter Restoration
+ if (valueCount && value) {
+ *valueCount = std::min(valueList.size(), *valueCount);
+ if (*valueCount > 0) {
+ for (size_t i = 0; i < *valueCount; ++i)
+ value[i] = CefPostDataElementCToCpp::Unwrap(valueList[i]);
+ }
+ }
+ }
+
+ // CToCpp Example
+ void CefFunction(std::vector<bool>& value)
+ {
+ // Parameter Translation
+ // Function identified by the "count_func" method attribute.
+ size_t valueSize = value.size();
+ size_t valueCount = std::max(GetFunctionCount(), valueSize);
+ cef_post_data_element_t** valueList = NULL;
+ if (valueCount > 0) {
+ valueList = new cef_post_data_element_t*[valueCount];
+ DCHECK(valueList);
+ if (valueList)
+ memset(valueList, 0, sizeof(cef_post_data_element_t*)*valueCount);
+ if (valueList && valueSize > 0) {
+ for (size_t i = 0; i < valueSize; ++i) {
+ valueList[i] = CefPostDataElementCppToC::Wrap(value[i]);
+ }
+ }
+ }
+
+ // Execution
+ cef_function(&valueCount, valueList);
+
+ // Parameter Restoration
+ value.clear();
+ if (valueCount > 0 && valueList) {
+ for (size_t i = 0; i < valueCount; ++i)
+ value.push_back(CefPostDataElementCppToC::Unwrap(valueList[i]));
+ delete [] valueList;
+ }
+ }
+
+ Smart pointer vector const type different boundary side by reference
+ (refptr_vec_diff_byref_const):
+ C++: const std::vector<CefRefPtr<CefV8Value>>& value
+ C API: size_t valueCount, const cef_v8value_t** value
+
+ // CppToC Example
+ CEF_EXPORT void cef_function(size_t valueCount,
+ const cef_v8value_t** value)
+ {
+ // Parameter Verification
+ DCHECK(valueCount == 0 || value);
+ if (valueCount > 0 && !value)
+ return;
+
+ // Parameter Translation
+ std::vector<CefRefPtr<CefV8Value>> valueList;
+ if (valueCount > 0) {
+ for (size_t i = 0; i < valueCount; ++i)
+ valueList.push_back(CefV8ValueCToCpp::Wrap(value[i]));
+ }
+
+ // Execution
+ CefFunction(valueList);
+ }
+
+ // CToCpp Example
+ void CefFunction(const std::vector<bool>& value)
+ {
+ // Parameter Translation
+ const size_t valueCount = value.size();
+ cef_v8value_t** valueList = NULL;
+ if (valueCount > 0) {
+ valueList = new int[valueCount];
+ DCHECK(valueList);
+ if (valueList) {
+ for (size_t i = 0; i < valueCount; ++i)
+ valueList[i] = CefV8ValueCppToC::Wrap(value[i]);
+ }
+ }
+
+ // Execution
+ cef_function(valueCount, valueList);
+
+ // Parameter Restoration
+ if (valueList)
+ delete [] valueList;
+ }
+
+Return Values:
+
+ Simple/Enumeration type (simple):
+ C++: int
+ C API: int
+
+ // CppToC Example
+ CEF_EXPORT int cef_function()
+ {
+ // Execution
+ int _rv = CefFunction();
+
+ // Return Translation
+ return _rv;
+ }
+
+ // CToCpp Example
+ int CefFunction()
+ {
+ // Execution
+ int _rv = cef_function();
+
+ // Return Translation
+ return _rv;
+ }
+
+ Boolean type (bool):
+ C++: bool
+ C API: int
+
+ // CppToC Example
+ CEF_EXPORT int cef_function()
+ {
+ // Execution
+ bool _rv = CefFunction();
+
+ // Return Translation
+ return _rv;
+ }
+
+ // CToCpp Example
+ bool CefFunction()
+ {
+ // Execution
+ int _rv = cef_function();
+
+ // Return Translation
+ return _rv?true:false;
+ }
+
+ String non-const by reference type (string):
+ C++: CefString
+ C API: cef_string_userfree_t
+
+ // CppToC Example
+ CEF_EXPORT cef_string_userfree_t cef_function()
+ {
+ // Execution
+ CefString _rv = CefFunction();
+
+ // Return Translation
+ return _rv.DetachToUserFree();
+ }
+
+ // CToCpp Example
+ CefString CefFunction()
+ {
+ // Execution
+ cef_string_userfree_t _rv = cef_function();
+
+ // Return Translation
+ CefString _rvStr;
+ _rvStr.AttachToUserFree(_rv);
+ return _rvStr;
+ }
+
+ Smart pointer type same boundary side (refptr_same):
+ C++: CefRefPtr<CefBrowser>
+ C API: cef_browser_t*
+
+ // CppToC Example
+ CEF_EXPORT cef_browser_t* cef_function()
+ {
+ // Execution
+ CefRefPtr<CefBrowser> _rv = CefFunction();
+
+ // Return Translation
+ return CefBrowserCppToC::Wrap(_rv);
+ }
+
+ // CToCpp Example
+ CefString CefFunction()
+ {
+ // Execution
+ cef_browser_t* _rv = cef_function();
+
+ // Return Translation
+ return CefBrowserCToCpp::Wrap(_rv);
+ }
+
+ Smart pointer type different boundary side (refptr_diff):
+ C++: CefRefPtr<CefBrowser>
+ C API: cef_browser_t*
+
+ // CppToC Example
+ CEF_EXPORT cef_browser_t* cef_function()
+ {
+ // Execution
+ CefRefPtr<CefBrowser> _rv = CefFunction();
+
+ // Return Translation
+ return CefBrowserCToCpp::Unwrap(_rv);
+ }
+
+ // CToCpp Example
+ CefString CefFunction()
+ {
+ // Execution
+ cef_browser_t* _rv = cef_function();
+
+ // Return Translation
+ return CefBrowserCppToC::Unwrap(_rv);
+ }
+
+
+Translating Comments
+--------------------
+
+Comments from the CEF header file are reproduced in the C API header file with
+any referenced C++ types and terminology changed to reflect C API types and
+terminology.
+
+C++:
+// Create a new CefV8Value object of the specified type. These methods
+// should only be called from within the JavaScript context -- either in a
+// CefV8Handler::Execute() callback or a CefHandler::HandleJSBinding()
+// callback.
+
+C API:
+// Create a new cef_v8value_t object of the specified type. These functions
+// should only be called from within the JavaScript context -- either in a
+// cef_v8handler_t::execute() callback or a cef_handler_t::handle_jsbinding()
+// callback.
+
+Situations where the user is responsible for freeing strings allocated and
+returned by the library are also noted by comments in the C API header file.
+
+C API:
+ // The resulting string must be freed by calling cef_string_free().
+
+A comment must occur immediately before the function, class or method that it
+documents with no extra space in between. Comments may span multiple lines
+but each line must start with the '//' comment identifier.
+
+C++:
+ // Set focus for the browser window. If |enable| is true focus will be set
+ // to the window. Otherwise, focus will be removed.
+ /*--cef()--*/
+ virtual void SetFocus(bool enable) =0;
+
+If two comments are separated by an empty line it will be assumed that the
+higher comment represents a section header and additional space will be added
+before it in the translated output.
+
+C++:
+ // ARRAY METHODS - These methods are only available on arrays.
+
+ // Returns the number of elements in the array.
+ /*--cef()--*/
+ virtual int GetArrayLength() =0;
+
+Empty lines and lines with the comment identifier but no content are considered
+paragraph breaks for the purposes of wrapping the translated text. Any content
+indented more than one space is reproduced as-is without content translation
+or wrapping.
+
+C++:
+// Register a new V8 extension with the specified JavaScript extension code and
+// handler. Functions implemented by the handler are prototyped using the
+// keyword 'native'. The calling of a native function is restricted to the scope
+// in which the prototype of the native function is defined.
+//
+// Example JavaScript extension code:
+//
+// // create the 'example' global object if it doesn't already exist.
+// if (!example)
+// example = {};
diff --git a/tools/translator.bat b/tools/translator.bat
new file mode 100644
index 00000000..348700a5
--- /dev/null
+++ b/tools/translator.bat
@@ -0,0 +1,3 @@
+@echo off
+call python.bat %~dp0\translator.py --root-dir %~dp0\.. %*
+pause \ No newline at end of file
diff --git a/tools/translator.py b/tools/translator.py
new file mode 100644
index 00000000..1d8552ce
--- /dev/null
+++ b/tools/translator.py
@@ -0,0 +1,242 @@
+# Copyright (c) 2009 The Chromium Embedded Framework Authors. All rights
+# reserved. Use of this source code is governed by a BSD-style license that
+# can be found in the LICENSE file.
+
+from __future__ import absolute_import
+import sys
+from cef_parser import *
+from clang_util import clang_format
+from file_util import *
+import hashlib
+from make_api_hash_header import *
+from make_capi_header import *
+from make_cpptoc_header import *
+from make_cpptoc_impl import *
+from make_ctocpp_header import *
+from make_ctocpp_impl import *
+from make_gypi_file import *
+from make_libcef_dll_dylib_impl import *
+from make_wrapper_types_header import *
+from optparse import OptionParser
+
+# cannot be loaded as a module
+if __name__ != "__main__":
+ sys.stderr.write('This file cannot be loaded as a module!')
+ sys.exit()
+
+# parse command-line options
+disc = """
+This utility generates files for the CEF C++ to C API translation layer.
+"""
+
+parser = OptionParser(description=disc)
+parser.add_option(
+ '--root-dir',
+ dest='rootdir',
+ metavar='DIR',
+ help='CEF root directory [required]')
+parser.add_option(
+ '--backup',
+ action='store_true',
+ dest='backup',
+ default=False,
+ help='create a backup of modified files')
+parser.add_option(
+ '--force',
+ action='store_true',
+ dest='force',
+ default=False,
+ help='force rewrite of the file')
+parser.add_option(
+ '-c',
+ '--classes',
+ dest='classes',
+ action='append',
+ help='only translate the specified classes')
+parser.add_option(
+ '-q',
+ '--quiet',
+ action='store_true',
+ dest='quiet',
+ default=False,
+ help='do not output detailed status information')
+(options, args) = parser.parse_args()
+
+# the rootdir option is required
+if options.rootdir is None:
+ parser.print_help(sys.stdout)
+ sys.exit()
+
+# determine the paths
+root_dir = os.path.abspath(options.rootdir)
+cpp_header_dir = os.path.join(root_dir, 'include')
+cpp_header_test_dir = os.path.join(cpp_header_dir, 'test')
+cpp_header_views_dir = os.path.join(cpp_header_dir, 'views')
+capi_header_dir = os.path.join(cpp_header_dir, 'capi')
+api_hash_header = os.path.join(cpp_header_dir, 'cef_api_hash.h')
+libcef_dll_dir = os.path.join(root_dir, 'libcef_dll')
+cpptoc_global_impl = os.path.join(libcef_dll_dir, 'libcef_dll.cc')
+ctocpp_global_impl = os.path.join(libcef_dll_dir, 'wrapper',
+ 'libcef_dll_wrapper.cc')
+wrapper_types_header = os.path.join(libcef_dll_dir, 'wrapper_types.h')
+cpptoc_dir = os.path.join(libcef_dll_dir, 'cpptoc')
+ctocpp_dir = os.path.join(libcef_dll_dir, 'ctocpp')
+gypi_file = os.path.join(root_dir, 'cef_paths.gypi')
+libcef_dll_dylib_impl = os.path.join(libcef_dll_dir, 'wrapper',
+ 'libcef_dll_dylib.cc')
+
+# make sure the header directory exists
+if not path_exists(cpp_header_dir):
+ sys.stderr.write('Directory ' + cpp_header_dir + ' does not exist.')
+ sys.exit()
+
+# create the header object
+if not options.quiet:
+ sys.stdout.write('Parsing C++ headers from ' + cpp_header_dir + '...\n')
+header = obj_header()
+
+# add include files to be processed
+header.set_root_directory(cpp_header_dir)
+excluded_files = ['cef_api_hash.h', 'cef_application_mac.h', 'cef_version.h']
+header.add_directory(cpp_header_dir, excluded_files)
+header.add_directory(cpp_header_test_dir)
+header.add_directory(cpp_header_views_dir)
+
+# Track the number of files that were written.
+writect = 0
+
+
+def update_file(file, newcontents):
+ """ Replaces the contents of |file| with |newcontents| if necessary. """
+ oldcontents = ''
+ oldhash = ''
+
+ if newcontents[-1:] != "\n":
+ # Add newline at end of file.
+ newcontents += "\n"
+
+ # clang-format is slow so we don't want to apply it if the pre-formatted
+ # content hasn't changed. To check for changes we embed a hash of the pre-
+ # formatted content in the resulting file.
+ hash_start = "$hash="
+ hash_end = "$"
+ hash_token = "$$HASH$$"
+
+ if not options.force and path_exists(file):
+ oldcontents = read_file(file)
+
+ # Extract the existing hash.
+ start = oldcontents.find(hash_start)
+ if start > 0:
+ end = oldcontents.find(hash_end, start + len(hash_start))
+ if end > 0:
+ oldhash = oldcontents[start + len(hash_start):end]
+
+ # Compute the new hash.
+ newhash = hashlib.sha1(newcontents.encode('utf-8')).hexdigest()
+
+ if oldhash == newhash:
+ # Pre-formatted contents have not changed.
+ return
+
+ newcontents = newcontents.replace(hash_token, newhash, 1)
+
+ # Apply clang-format for C/C++ files.
+ if os.path.splitext(file)[1][1:] in ('c', 'cc', 'cpp', 'h'):
+ result = clang_format(file, newcontents)
+ if result != None:
+ newcontents = result
+ else:
+ raise Exception("Call to clang-format failed")
+
+ if options.backup and oldcontents != '':
+ backup_file(file)
+
+ filedir = os.path.split(file)[0]
+ if not os.path.isdir(filedir):
+ make_dir(filedir)
+
+ write_file(file, newcontents)
+
+ global writect
+ writect += 1
+
+
+# output the C API header
+if not options.quiet:
+ sys.stdout.write('In C API header directory ' + capi_header_dir + '...\n')
+filenames = sorted(header.get_file_names())
+for filename in filenames:
+ if not options.quiet:
+ sys.stdout.write('Generating ' + filename + ' C API header...\n')
+ update_file(*write_capi_header(header, capi_header_dir, filename))
+
+# output the wrapper types header
+if not options.quiet:
+ sys.stdout.write('Generating wrapper types header...\n')
+update_file(*write_wrapper_types_header(header, wrapper_types_header))
+
+# build the list of classes to parse
+allclasses = header.get_class_names()
+if not options.classes is None:
+ for cls in options.classes:
+ if not cls in allclasses:
+ sys.stderr.write('ERROR: Unknown class: ' + cls)
+ sys.exit()
+ classes = options.classes
+else:
+ classes = allclasses
+
+classes = sorted(classes)
+
+# output CppToC global file
+if not options.quiet:
+ sys.stdout.write('Generating CppToC global implementation...\n')
+update_file(*write_cpptoc_impl(header, None, cpptoc_global_impl))
+
+# output CToCpp global file
+if not options.quiet:
+ sys.stdout.write('Generating CToCpp global implementation...\n')
+update_file(*write_ctocpp_impl(header, None, ctocpp_global_impl))
+
+# output CppToC class files
+if not options.quiet:
+ sys.stdout.write('In CppToC directory ' + cpptoc_dir + '...\n')
+for cls in classes:
+ if not options.quiet:
+ sys.stdout.write('Generating ' + cls + 'CppToC class header...\n')
+ update_file(*write_cpptoc_header(header, cls, cpptoc_dir))
+ if not options.quiet:
+ sys.stdout.write('Generating ' + cls + 'CppToC class implementation...\n')
+ update_file(*write_cpptoc_impl(header, cls, cpptoc_dir))
+
+# output CppToC class files
+if not options.quiet:
+ sys.stdout.write('In CToCpp directory ' + ctocpp_dir + '...\n')
+for cls in classes:
+ if not options.quiet:
+ sys.stdout.write('Generating ' + cls + 'CToCpp class header...\n')
+ update_file(*write_ctocpp_header(header, cls, ctocpp_dir))
+ if not options.quiet:
+ sys.stdout.write('Generating ' + cls + 'CToCpp class implementation...\n')
+ update_file(*write_ctocpp_impl(header, cls, ctocpp_dir))
+
+# output the gypi file
+if not options.quiet:
+ sys.stdout.write('Generating ' + gypi_file + ' file...\n')
+update_file(*write_gypi_file(header, gypi_file))
+
+# output the libcef dll dylib file
+if not options.quiet:
+ sys.stdout.write('Generating ' + libcef_dll_dylib_impl + ' file...\n')
+update_file(*write_libcef_dll_dylib_impl(header, libcef_dll_dylib_impl))
+
+# Update the API hash header file if necessary. This must be done last because
+# it reads files that were potentially written by proceeding operations.
+if not options.quiet:
+ sys.stdout.write('Generating API hash header...\n')
+if write_api_hash_header(api_hash_header, cpp_header_dir):
+ writect += 1
+
+if not options.quiet:
+ sys.stdout.write('Done - Wrote ' + str(writect) + ' files.\n')
diff --git a/tools/translator.sh b/tools/translator.sh
new file mode 100755
index 00000000..9cdb1e06
--- /dev/null
+++ b/tools/translator.sh
@@ -0,0 +1,2 @@
+#!/bin/sh
+python3 translator.py --root-dir .. $@
diff --git a/tools/yapf/LICENSE b/tools/yapf/LICENSE
new file mode 100644
index 00000000..d6456956
--- /dev/null
+++ b/tools/yapf/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/tools/yapf/README.cef b/tools/yapf/README.cef
new file mode 100644
index 00000000..44e7cedb
--- /dev/null
+++ b/tools/yapf/README.cef
@@ -0,0 +1,14 @@
+Name: yapf
+Short Name: yapf
+URL: https://github.com/google/yapf
+Date: 28 May 2017
+Version: 0.16.2
+Revision: 9f168a12
+License: Apache 2.0
+License File: LICENSE
+
+Description:
+A formatter for Python files.
+
+Local Modifications:
+None
diff --git a/tools/yapf/__main__.py b/tools/yapf/__main__.py
new file mode 100644
index 00000000..88f1ec69
--- /dev/null
+++ b/tools/yapf/__main__.py
@@ -0,0 +1,16 @@
+# Copyright 2015-2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+import yapf
+
+yapf.run_main()
diff --git a/tools/yapf/yapf/__init__.py b/tools/yapf/yapf/__init__.py
new file mode 100644
index 00000000..92580523
--- /dev/null
+++ b/tools/yapf/yapf/__init__.py
@@ -0,0 +1,303 @@
+# Copyright 2015-2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""YAPF.
+
+YAPF uses the algorithm in clang-format to figure out the "best" formatting for
+Python code. It looks at the program as a series of "unwrappable lines" ---
+i.e., lines which, if there were no column limit, we would place all tokens on
+that line. It then uses a priority queue to figure out what the best formatting
+is --- i.e., the formatting with the least penalty.
+
+It differs from tools like autopep8 and pep8ify in that it doesn't just look for
+violations of the style guide, but looks at the module as a whole, making
+formatting decisions based on what's the best format for each line.
+
+If no filenames are specified, YAPF reads the code from stdin.
+"""
+from __future__ import print_function
+
+import argparse
+import logging
+import os
+import sys
+
+from yapf.yapflib import errors
+from yapf.yapflib import file_resources
+from yapf.yapflib import py3compat
+from yapf.yapflib import style
+from yapf.yapflib import yapf_api
+
+__version__ = '0.16.2'
+
+
+def main(argv):
+ """Main program.
+
+ Arguments:
+ argv: command-line arguments, such as sys.argv (including the program name
+ in argv[0]).
+
+ Returns:
+ 0 if there were no changes, non-zero otherwise.
+
+ Raises:
+ YapfError: if none of the supplied files were Python files.
+ """
+ parser = argparse.ArgumentParser(description='Formatter for Python code.')
+ parser.add_argument(
+ '-v',
+ '--version',
+ action='store_true',
+ help='show version number and exit')
+
+ diff_inplace_group = parser.add_mutually_exclusive_group()
+ diff_inplace_group.add_argument(
+ '-d',
+ '--diff',
+ action='store_true',
+ help='print the diff for the fixed source')
+ diff_inplace_group.add_argument(
+ '-i',
+ '--in-place',
+ action='store_true',
+ help='make changes to files in place')
+
+ lines_recursive_group = parser.add_mutually_exclusive_group()
+ lines_recursive_group.add_argument(
+ '-r',
+ '--recursive',
+ action='store_true',
+ help='run recursively over directories')
+ lines_recursive_group.add_argument(
+ '-l',
+ '--lines',
+ metavar='START-END',
+ action='append',
+ default=None,
+ help='range of lines to reformat, one-based')
+
+ parser.add_argument(
+ '-e',
+ '--exclude',
+ metavar='PATTERN',
+ action='append',
+ default=None,
+ help='patterns for files to exclude from formatting')
+ parser.add_argument(
+ '--style',
+ action='store',
+ help=('specify formatting style: either a style name (for example "pep8" '
+ 'or "google"), or the name of a file with style settings. The '
+ 'default is pep8 unless a %s or %s file located in one of the '
+ 'parent directories of the source file (or current directory for '
+ 'stdin)' % (style.LOCAL_STYLE, style.SETUP_CONFIG)))
+ parser.add_argument(
+ '--style-help',
+ action='store_true',
+ help=('show style settings and exit; this output can be '
+ 'saved to .style.yapf to make your settings '
+ 'permanent'))
+ parser.add_argument(
+ '--no-local-style',
+ action='store_true',
+ help="don't search for local style definition")
+ parser.add_argument('--verify', action='store_true', help=argparse.SUPPRESS)
+ parser.add_argument(
+ '-p',
+ '--parallel',
+ action='store_true',
+ help=('Run yapf in parallel when formatting multiple files. Requires '
+ 'concurrent.futures in Python 2.X'))
+
+ parser.add_argument('files', nargs='*')
+ args = parser.parse_args(argv[1:])
+
+ if args.version:
+ print('yapf {}'.format(__version__))
+ return 0
+
+ if args.style_help:
+ style.SetGlobalStyle(style.CreateStyleFromConfig(args.style))
+ print('[style]')
+ for option, docstring in sorted(style.Help().items()):
+ for line in docstring.splitlines():
+ print('#', line and ' ' or '', line, sep='')
+ print(option.lower(), '=', style.Get(option), sep='')
+ print()
+ return 0
+
+ if args.lines and len(args.files) > 1:
+ parser.error('cannot use -l/--lines with more than one file')
+
+ lines = _GetLines(args.lines) if args.lines is not None else None
+ if not args.files:
+ # No arguments specified. Read code from stdin.
+ if args.in_place or args.diff:
+ parser.error('cannot use --in-place or --diff flags when reading '
+ 'from stdin')
+
+ original_source = []
+ while True:
+ try:
+ # Use 'raw_input' instead of 'sys.stdin.read', because otherwise the
+ # user will need to hit 'Ctrl-D' more than once if they're inputting
+ # the program by hand. 'raw_input' throws an EOFError exception if
+ # 'Ctrl-D' is pressed, which makes it easy to bail out of this loop.
+ original_source.append(py3compat.raw_input())
+ except EOFError:
+ break
+
+ style_config = args.style
+ if style_config is None and not args.no_local_style:
+ style_config = file_resources.GetDefaultStyleForDir(os.getcwd())
+
+ source = [line.rstrip() for line in original_source]
+ reformatted_source, _ = yapf_api.FormatCode(
+ py3compat.unicode('\n'.join(source) + '\n'),
+ filename='<stdin>',
+ style_config=style_config,
+ lines=lines,
+ verify=args.verify)
+ file_resources.WriteReformattedCode('<stdout>', reformatted_source)
+ return 0
+
+ files = file_resources.GetCommandLineFiles(args.files, args.recursive,
+ args.exclude)
+ if not files:
+ raise errors.YapfError('Input filenames did not match any python files')
+
+ FormatFiles(
+ files,
+ lines,
+ style_config=args.style,
+ no_local_style=args.no_local_style,
+ in_place=args.in_place,
+ print_diff=args.diff,
+ verify=args.verify,
+ parallel=args.parallel)
+ return 0
+
+
+def FormatFiles(filenames,
+ lines,
+ style_config=None,
+ no_local_style=False,
+ in_place=False,
+ print_diff=False,
+ verify=True,
+ parallel=False):
+ """Format a list of files.
+
+ Arguments:
+ filenames: (list of unicode) A list of files to reformat.
+ lines: (list of tuples of integers) A list of tuples of lines, [start, end],
+ that we want to format. The lines are 1-based indexed. This argument
+ overrides the 'args.lines'. It can be used by third-party code (e.g.,
+ IDEs) when reformatting a snippet of code.
+ style_config: (string) Style name or file path.
+ no_local_style: (string) If style_config is None don't search for
+ directory-local style configuration.
+ in_place: (bool) Modify the files in place.
+ print_diff: (bool) Instead of returning the reformatted source, return a
+ diff that turns the formatted source into reformatter source.
+ verify: (bool) True if reformatted code should be verified for syntax.
+ parallel: (bool) True if should format multiple files in parallel.
+
+ Returns:
+ True if the source code changed in any of the files being formatted.
+ """
+ changed = False
+ if parallel:
+ import multiprocessing # pylint: disable=g-import-not-at-top
+ import concurrent.futures # pylint: disable=g-import-not-at-top
+ workers = min(multiprocessing.cpu_count(), len(filenames))
+ with concurrent.futures.ProcessPoolExecutor(workers) as executor:
+ future_formats = [
+ executor.submit(_FormatFile, filename, lines, style_config,
+ no_local_style, in_place, print_diff, verify)
+ for filename in filenames
+ ]
+ for future in concurrent.futures.as_completed(future_formats):
+ changed |= future.result()
+ else:
+ for filename in filenames:
+ changed |= _FormatFile(filename, lines, style_config, no_local_style,
+ in_place, print_diff, verify)
+ return changed
+
+
+def _FormatFile(filename,
+ lines,
+ style_config=None,
+ no_local_style=False,
+ in_place=False,
+ print_diff=False,
+ verify=True):
+ logging.info('Reformatting %s', filename)
+ if style_config is None and not no_local_style:
+ style_config = (
+ file_resources.GetDefaultStyleForDir(os.path.dirname(filename)))
+ try:
+ reformatted_code, encoding, has_change = yapf_api.FormatFile(
+ filename,
+ in_place=in_place,
+ style_config=style_config,
+ lines=lines,
+ print_diff=print_diff,
+ verify=verify,
+ logger=logging.warning)
+ if not in_place and reformatted_code:
+ file_resources.WriteReformattedCode(filename, reformatted_code, in_place,
+ encoding)
+ return has_change
+ except SyntaxError as e:
+ e.filename = filename
+ raise
+
+
+def _GetLines(line_strings):
+ """Parses the start and end lines from a line string like 'start-end'.
+
+ Arguments:
+ line_strings: (array of string) A list of strings representing a line
+ range like 'start-end'.
+
+ Returns:
+ A list of tuples of the start and end line numbers.
+
+ Raises:
+ ValueError: If the line string failed to parse or was an invalid line range.
+ """
+ lines = []
+ for line_string in line_strings:
+ # The 'list' here is needed by Python 3.
+ line = list(map(int, line_string.split('-', 1)))
+ if line[0] < 1:
+ raise errors.YapfError('invalid start of line range: %r' % line)
+ if line[0] > line[1]:
+ raise errors.YapfError('end comes before start in line range: %r', line)
+ lines.append(tuple(line))
+ return lines
+
+
+def run_main(): # pylint: disable=invalid-name
+ try:
+ sys.exit(main(sys.argv))
+ except errors.YapfError as e:
+ sys.stderr.write('yapf: ' + str(e) + '\n')
+ sys.exit(1)
+
+
+if __name__ == '__main__':
+ run_main()
diff --git a/tools/yapf/yapf/yapflib/__init__.py b/tools/yapf/yapf/yapflib/__init__.py
new file mode 100644
index 00000000..80217ac4
--- /dev/null
+++ b/tools/yapf/yapf/yapflib/__init__.py
@@ -0,0 +1,13 @@
+# Copyright 2015-2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
diff --git a/tools/yapf/yapf/yapflib/blank_line_calculator.py b/tools/yapf/yapf/yapflib/blank_line_calculator.py
new file mode 100644
index 00000000..bcd7a867
--- /dev/null
+++ b/tools/yapf/yapf/yapflib/blank_line_calculator.py
@@ -0,0 +1,183 @@
+# Copyright 2015-2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Calculate the number of blank lines between top-level entities.
+
+Calculates how many blank lines we need between classes, functions, and other
+entities at the same level.
+
+ CalculateBlankLines(): the main function exported by this module.
+
+Annotations:
+ newlines: The number of newlines required before the node.
+"""
+
+from lib2to3 import pytree
+
+from yapf.yapflib import py3compat
+from yapf.yapflib import pytree_utils
+from yapf.yapflib import pytree_visitor
+
+_NO_BLANK_LINES = 1
+_ONE_BLANK_LINE = 2
+_TWO_BLANK_LINES = 3
+
+_PYTHON_STATEMENTS = frozenset({
+ 'small_stmt', 'expr_stmt', 'print_stmt', 'del_stmt', 'pass_stmt',
+ 'break_stmt', 'continue_stmt', 'return_stmt', 'raise_stmt', 'yield_stmt',
+ 'import_stmt', 'global_stmt', 'exec_stmt', 'assert_stmt', 'if_stmt',
+ 'while_stmt', 'for_stmt', 'try_stmt', 'with_stmt', 'nonlocal_stmt',
+ 'async_stmt', 'simple_stmt'
+})
+
+
+def CalculateBlankLines(tree):
+ """Run the blank line calculator visitor over the tree.
+
+ This modifies the tree in place.
+
+ Arguments:
+ tree: the top-level pytree node to annotate with subtypes.
+ """
+ blank_line_calculator = _BlankLineCalculator()
+ blank_line_calculator.Visit(tree)
+
+
+class _BlankLineCalculator(pytree_visitor.PyTreeVisitor):
+ """_BlankLineCalculator - see file-level docstring for a description."""
+
+ def __init__(self):
+ self.class_level = 0
+ self.function_level = 0
+ self.last_comment_lineno = 0
+ self.last_was_decorator = False
+ self.last_was_class_or_function = False
+
+ def Visit_simple_stmt(self, node): # pylint: disable=invalid-name
+ self.DefaultNodeVisit(node)
+ if pytree_utils.NodeName(node.children[0]) == 'COMMENT':
+ self.last_comment_lineno = node.children[0].lineno
+
+ def Visit_decorator(self, node): # pylint: disable=invalid-name
+ if (self.last_comment_lineno and
+ self.last_comment_lineno == node.children[0].lineno - 1):
+ self._SetNumNewlines(node.children[0], _NO_BLANK_LINES)
+ else:
+ self._SetNumNewlines(node.children[0], self._GetNumNewlines(node))
+ for child in node.children:
+ self.Visit(child)
+ self.last_was_decorator = True
+
+ def Visit_classdef(self, node): # pylint: disable=invalid-name
+ self.last_was_class_or_function = False
+ index = self._SetBlankLinesBetweenCommentAndClassFunc(node)
+ self.last_was_decorator = False
+ self.class_level += 1
+ for child in node.children[index:]:
+ self.Visit(child)
+ self.class_level -= 1
+ self.last_was_class_or_function = True
+
+ def Visit_funcdef(self, node): # pylint: disable=invalid-name
+ self.last_was_class_or_function = False
+ index = self._SetBlankLinesBetweenCommentAndClassFunc(node)
+ if _AsyncFunction(node):
+ index = self._SetBlankLinesBetweenCommentAndClassFunc(
+ node.prev_sibling.parent)
+ self._SetNumNewlines(node.children[0], None)
+ else:
+ index = self._SetBlankLinesBetweenCommentAndClassFunc(node)
+ self.last_was_decorator = False
+ self.function_level += 1
+ for child in node.children[index:]:
+ self.Visit(child)
+ self.function_level -= 1
+ self.last_was_class_or_function = True
+
+ def DefaultNodeVisit(self, node):
+ """Override the default visitor for Node.
+
+ This will set the blank lines required if the last entity was a class or
+ function.
+
+ Arguments:
+ node: (pytree.Node) The node to visit.
+ """
+ if self.last_was_class_or_function:
+ if pytree_utils.NodeName(node) in _PYTHON_STATEMENTS:
+ leaf = _GetFirstChildLeaf(node)
+ self._SetNumNewlines(leaf, self._GetNumNewlines(leaf))
+ self.last_was_class_or_function = False
+ super(_BlankLineCalculator, self).DefaultNodeVisit(node)
+
+ def _SetBlankLinesBetweenCommentAndClassFunc(self, node):
+ """Set the number of blanks between a comment and class or func definition.
+
+ Class and function definitions have leading comments as children of the
+ classdef and functdef nodes.
+
+ Arguments:
+ node: (pytree.Node) The classdef or funcdef node.
+
+ Returns:
+ The index of the first child past the comment nodes.
+ """
+ index = 0
+ while pytree_utils.IsCommentStatement(node.children[index]):
+ # Standalone comments are wrapped in a simple_stmt node with the comment
+ # node as its only child.
+ self.Visit(node.children[index].children[0])
+ if not self.last_was_decorator:
+ self._SetNumNewlines(node.children[index].children[0], _ONE_BLANK_LINE)
+ index += 1
+ if (index and node.children[index].lineno -
+ 1 == node.children[index - 1].children[0].lineno):
+ self._SetNumNewlines(node.children[index], _NO_BLANK_LINES)
+ else:
+ if self.last_comment_lineno + 1 == node.children[index].lineno:
+ num_newlines = _NO_BLANK_LINES
+ else:
+ num_newlines = self._GetNumNewlines(node)
+ self._SetNumNewlines(node.children[index], num_newlines)
+ return index
+
+ def _GetNumNewlines(self, node):
+ if self.last_was_decorator:
+ return _NO_BLANK_LINES
+ elif self._IsTopLevel(node):
+ return _TWO_BLANK_LINES
+ return _ONE_BLANK_LINE
+
+ def _SetNumNewlines(self, node, num_newlines):
+ pytree_utils.SetNodeAnnotation(node, pytree_utils.Annotation.NEWLINES,
+ num_newlines)
+
+ def _IsTopLevel(self, node):
+ return (not (self.class_level or self.function_level) and
+ _StartsInZerothColumn(node))
+
+
+def _StartsInZerothColumn(node):
+ return (_GetFirstChildLeaf(node).column == 0 or
+ (_AsyncFunction(node) and node.prev_sibling.column == 0))
+
+
+def _AsyncFunction(node):
+ return (py3compat.PY3 and node.prev_sibling and
+ pytree_utils.NodeName(node.prev_sibling) == 'ASYNC')
+
+
+def _GetFirstChildLeaf(node):
+ if isinstance(node, pytree.Leaf):
+ return node
+ return _GetFirstChildLeaf(node.children[0])
diff --git a/tools/yapf/yapf/yapflib/comment_splicer.py b/tools/yapf/yapf/yapflib/comment_splicer.py
new file mode 100644
index 00000000..7c79e805
--- /dev/null
+++ b/tools/yapf/yapf/yapflib/comment_splicer.py
@@ -0,0 +1,374 @@
+# Copyright 2015-2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Comment splicer for lib2to3 trees.
+
+The lib2to3 syntax tree produced by the parser holds comments and whitespace in
+prefix attributes of nodes, rather than nodes themselves. This module provides
+functionality to splice comments out of prefixes and into nodes of their own,
+making them easier to process.
+
+ SpliceComments(): the main function exported by this module.
+"""
+
+from lib2to3 import pygram
+from lib2to3 import pytree
+from lib2to3.pgen2 import token
+
+from yapf.yapflib import pytree_utils
+
+
+def SpliceComments(tree):
+ """Given a pytree, splice comments into nodes of their own right.
+
+ Extract comments from the prefixes where they are housed after parsing.
+ The prefixes that previously housed the comments become empty.
+
+ Args:
+ tree: a pytree.Node - the tree to work on. The tree is modified by this
+ function.
+ """
+ # The previous leaf node encountered in the traversal.
+ # This is a list because Python 2.x doesn't have 'nonlocal' :)
+ prev_leaf = [None]
+ _AnnotateIndents(tree)
+
+ def _VisitNodeRec(node):
+ # This loop may insert into node.children, so we'll iterate over a copy.
+ for child in node.children[:]:
+ if isinstance(child, pytree.Node):
+ # Nodes don't have prefixes.
+ _VisitNodeRec(child)
+ else:
+ if child.prefix.lstrip().startswith('#'):
+ # We have a comment prefix in this child, so splicing is needed.
+ comment_prefix = child.prefix
+ comment_lineno = child.lineno - comment_prefix.count('\n')
+ comment_column = child.column
+
+ # Remember the leading indentation of this prefix and clear it.
+ # Mopping up the prefix is important because we may go over this same
+ # child in the next iteration...
+ child_prefix = child.prefix.lstrip('\n')
+ prefix_indent = child_prefix[:child_prefix.find('#')]
+ if '\n' in prefix_indent:
+ prefix_indent = prefix_indent[prefix_indent.rfind('\n') + 1:]
+ child.prefix = ''
+
+ if child.type == token.NEWLINE:
+ # If the prefix was on a NEWLINE leaf, it's part of the line so it
+ # will be inserted after the previously encountered leaf.
+ # We can't just insert it before the NEWLINE node, because as a
+ # result of the way pytrees are organized, this node can be under
+ # an inappropriate parent.
+ comment_column -= len(comment_prefix)
+ comment_column += len(comment_prefix) - len(comment_prefix.lstrip())
+ pytree_utils.InsertNodesAfter(
+ _CreateCommentsFromPrefix(
+ comment_prefix,
+ comment_lineno,
+ comment_column,
+ standalone=False), prev_leaf[0])
+ elif child.type == token.DEDENT:
+ # Comment prefixes on DEDENT nodes also deserve special treatment,
+ # because their final placement depends on their prefix.
+ # We'll look for an ancestor of this child with a matching
+ # indentation, and insert the comment after it.
+ ancestor_at_indent = _FindAncestorAtIndent(child, prefix_indent)
+ if ancestor_at_indent.type == token.DEDENT:
+ comments = comment_prefix.split('\n')
+
+ # lib2to3 places comments that should be separated into the same
+ # DEDENT node. For example, "comment 1" and "comment 2" will be
+ # combined.
+ #
+ # def _():
+ # for x in y:
+ # pass
+ # # comment 1
+ #
+ # # comment 2
+ # pass
+ #
+ # In this case, we need to split them up ourselves.
+ before = []
+ after = []
+ after_lineno = comment_lineno
+
+ index = 0
+ while index < len(comments):
+ cmt = comments[index]
+ if not cmt.strip() or cmt.startswith(prefix_indent + '#'):
+ before.append(cmt)
+ else:
+ after_lineno += index
+ after.extend(comments[index:])
+ break
+ index += 1
+
+ # Special case where the comment is inserted in the same
+ # indentation level as the DEDENT it was originally attached to.
+ pytree_utils.InsertNodesBefore(
+ _CreateCommentsFromPrefix(
+ '\n'.join(before) + '\n',
+ comment_lineno,
+ comment_column,
+ standalone=True), ancestor_at_indent)
+ if after:
+ after_column = len(after[0]) - len(after[0].lstrip())
+ comment_column -= comment_column - after_column
+ pytree_utils.InsertNodesAfter(
+ _CreateCommentsFromPrefix(
+ '\n'.join(after) + '\n',
+ after_lineno,
+ comment_column,
+ standalone=True), _FindNextAncestor(ancestor_at_indent))
+ else:
+ pytree_utils.InsertNodesAfter(
+ _CreateCommentsFromPrefix(
+ comment_prefix,
+ comment_lineno,
+ comment_column,
+ standalone=True), ancestor_at_indent)
+ else:
+ # Otherwise there are two cases.
+ #
+ # 1. The comment is on its own line
+ # 2. The comment is part of an expression.
+ #
+ # Unfortunately, it's fairly difficult to distinguish between the
+ # two in lib2to3 trees. The algorithm here is to determine whether
+ # child is the first leaf in the statement it belongs to. If it is,
+ # then the comment (which is a prefix) belongs on a separate line.
+ # If it is not, it means the comment is buried deep in the statement
+ # and is part of some expression.
+ stmt_parent = _FindStmtParent(child)
+
+ for leaf_in_parent in stmt_parent.leaves():
+ if leaf_in_parent.type == token.NEWLINE:
+ continue
+ elif id(leaf_in_parent) == id(child):
+ # This comment stands on its own line, and it has to be inserted
+ # into the appropriate parent. We'll have to find a suitable
+ # parent to insert into. See comments above
+ # _STANDALONE_LINE_NODES for more details.
+ node_with_line_parent = _FindNodeWithStandaloneLineParent(child)
+ pytree_utils.InsertNodesBefore(
+ _CreateCommentsFromPrefix(
+ comment_prefix, comment_lineno, 0, standalone=True),
+ node_with_line_parent)
+ break
+ else:
+ if comment_lineno == prev_leaf[0].lineno:
+ comment_lines = comment_prefix.splitlines()
+ value = comment_lines[0].lstrip()
+ if value.rstrip('\n'):
+ comment_column = prev_leaf[0].column
+ comment_column += len(prev_leaf[0].value)
+ comment_column += (
+ len(comment_lines[0]) - len(comment_lines[0].lstrip()))
+ comment_leaf = pytree.Leaf(
+ type=token.COMMENT,
+ value=value.rstrip('\n'),
+ context=('', (comment_lineno, comment_column)))
+ pytree_utils.InsertNodesAfter([comment_leaf], prev_leaf[0])
+ comment_prefix = '\n'.join(comment_lines[1:])
+ comment_lineno += 1
+
+ rindex = (0 if '\n' not in comment_prefix.rstrip() else
+ comment_prefix.rstrip().rindex('\n') + 1)
+ comment_column = (len(comment_prefix[rindex:]) -
+ len(comment_prefix[rindex:].lstrip()))
+ comments = _CreateCommentsFromPrefix(
+ comment_prefix,
+ comment_lineno,
+ comment_column,
+ standalone=False)
+ pytree_utils.InsertNodesBefore(comments, child)
+ break
+
+ prev_leaf[0] = child
+
+ _VisitNodeRec(tree)
+
+
+def _CreateCommentsFromPrefix(comment_prefix,
+ comment_lineno,
+ comment_column,
+ standalone=False):
+ """Create pytree nodes to represent the given comment prefix.
+
+ Args:
+ comment_prefix: (unicode) the text of the comment from the node's prefix.
+ comment_lineno: (int) the line number for the start of the comment.
+ comment_column: (int) the column for the start of the comment.
+ standalone: (bool) determines if the comment is standalone or not.
+
+ Returns:
+ The simple_stmt nodes if this is a standalone comment, otherwise a list of
+ new COMMENT leafs. The prefix may consist of multiple comment blocks,
+ separated by blank lines. Each block gets its own leaf.
+ """
+ # The comment is stored in the prefix attribute, with no lineno of its
+ # own. So we only know at which line it ends. To find out at which line it
+ # starts, look at how many newlines the comment itself contains.
+ comments = []
+
+ lines = comment_prefix.split('\n')
+ index = 0
+ while index < len(lines):
+ comment_block = []
+ while index < len(lines) and lines[index].lstrip().startswith('#'):
+ comment_block.append(lines[index].strip())
+ index += 1
+
+ if comment_block:
+ new_lineno = comment_lineno + index - 1
+ comment_block[0] = comment_block[0].strip()
+ comment_block[-1] = comment_block[-1].strip()
+ comment_leaf = pytree.Leaf(
+ type=token.COMMENT,
+ value='\n'.join(comment_block),
+ context=('', (new_lineno, comment_column)))
+ comment_node = comment_leaf if not standalone else pytree.Node(
+ pygram.python_symbols.simple_stmt, [comment_leaf])
+ comments.append(comment_node)
+
+ while index < len(lines) and not lines[index].lstrip():
+ index += 1
+
+ return comments
+
+
+# "Standalone line nodes" are tree nodes that have to start a new line in Python
+# code (and cannot follow a ';' or ':'). Other nodes, like 'expr_stmt', serve as
+# parents of other nodes but can come later in a line. This is a list of
+# standalone line nodes in the grammar. It is meant to be exhaustive
+# *eventually*, and we'll modify it with time as we discover more corner cases
+# in the parse tree.
+#
+# When splicing a standalone comment (i.e. a comment that appears on its own
+# line, not on the same line with other code), it's important to insert it into
+# an appropriate parent of the node it's attached to. An appropriate parent
+# is the first "standaline line node" in the parent chain of a node.
+_STANDALONE_LINE_NODES = frozenset([
+ 'suite', 'if_stmt', 'while_stmt', 'for_stmt', 'try_stmt', 'with_stmt',
+ 'funcdef', 'classdef', 'decorated', 'file_input'
+])
+
+
+def _FindNodeWithStandaloneLineParent(node):
+ """Find a node whose parent is a 'standalone line' node.
+
+ See the comment above _STANDALONE_LINE_NODES for more details.
+
+ Arguments:
+ node: node to start from
+
+ Returns:
+ Suitable node that's either the node itself or one of its ancestors.
+ """
+ if pytree_utils.NodeName(node.parent) in _STANDALONE_LINE_NODES:
+ return node
+ else:
+ # This is guaranteed to terminate because 'file_input' is the root node of
+ # any pytree.
+ return _FindNodeWithStandaloneLineParent(node.parent)
+
+
+# "Statement nodes" are standalone statements. The don't have to start a new
+# line.
+_STATEMENT_NODES = frozenset(['simple_stmt']) | _STANDALONE_LINE_NODES
+
+
+def _FindStmtParent(node):
+ """Find the nearest parent of node that is a statement node.
+
+ Arguments:
+ node: node to start from
+
+ Returns:
+ Nearest parent (or node itself, if suitable).
+ """
+ if pytree_utils.NodeName(node) in _STATEMENT_NODES:
+ return node
+ else:
+ return _FindStmtParent(node.parent)
+
+
+def _FindAncestorAtIndent(node, indent):
+ """Find an ancestor of node with the given indentation.
+
+ Arguments:
+ node: node to start from. This must not be the tree root.
+ indent: indentation string for the ancestor we're looking for.
+ See _AnnotateIndents for more details.
+
+ Returns:
+ An ancestor node with suitable indentation. If no suitable ancestor is
+ found, the closest ancestor to the tree root is returned.
+ """
+ if node.parent.parent is None:
+ # Our parent is the tree root, so there's nowhere else to go.
+ return node
+
+ # If the parent has an indent annotation, and it's shorter than node's
+ # indent, this is a suitable ancestor.
+ # The reason for "shorter" rather than "equal" is that comments may be
+ # improperly indented (i.e. by three spaces, where surrounding statements
+ # have either zero or two or four), and we don't want to propagate them all
+ # the way to the root.
+ parent_indent = pytree_utils.GetNodeAnnotation(
+ node.parent, pytree_utils.Annotation.CHILD_INDENT)
+ if parent_indent is not None and indent.startswith(parent_indent):
+ return node
+ else:
+ # Keep looking up the tree.
+ return _FindAncestorAtIndent(node.parent, indent)
+
+
+def _FindNextAncestor(node):
+ if node.parent is None:
+ return node
+
+ if node.parent.next_sibling is not None:
+ return node.parent.next_sibling
+
+ return _FindNextAncestor(node.parent)
+
+
+def _AnnotateIndents(tree):
+ """Annotate the tree with child_indent annotations.
+
+ A child_indent annotation on a node specifies the indentation (as a string,
+ like " ") of its children. It is inferred from the INDENT child of a node.
+
+ Arguments:
+ tree: root of a pytree. The pytree is modified to add annotations to nodes.
+
+ Raises:
+ RuntimeError: if the tree is malformed.
+ """
+ # Annotate the root of the tree with zero indent.
+ if tree.parent is None:
+ pytree_utils.SetNodeAnnotation(tree, pytree_utils.Annotation.CHILD_INDENT,
+ '')
+ for child in tree.children:
+ if child.type == token.INDENT:
+ child_indent = pytree_utils.GetNodeAnnotation(
+ tree, pytree_utils.Annotation.CHILD_INDENT)
+ if child_indent is not None and child_indent != child.value:
+ raise RuntimeError('inconsistent indentation for child', (tree, child))
+ pytree_utils.SetNodeAnnotation(tree, pytree_utils.Annotation.CHILD_INDENT,
+ child.value)
+ _AnnotateIndents(child)
diff --git a/tools/yapf/yapf/yapflib/continuation_splicer.py b/tools/yapf/yapf/yapflib/continuation_splicer.py
new file mode 100644
index 00000000..74ea1a0c
--- /dev/null
+++ b/tools/yapf/yapf/yapflib/continuation_splicer.py
@@ -0,0 +1,52 @@
+# Copyright 2015-2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Insert "continuation" nodes into lib2to3 tree.
+
+The "backslash-newline" continuation marker is shoved into the node's prefix.
+Pull them out and make it into nodes of their own.
+
+ SpliceContinuations(): the main funciton exported by this module.
+"""
+
+from lib2to3 import pytree
+
+from yapf.yapflib import format_token
+
+
+def SpliceContinuations(tree):
+ """Given a pytree, splice the continuation marker into nodes.
+
+ Arguments:
+ tree: (pytree.Node) The tree to work on. The tree is modified by this
+ function.
+ """
+
+ def RecSplicer(node):
+ """Inserts a continuation marker into the node."""
+ if isinstance(node, pytree.Leaf):
+ if node.prefix.lstrip().startswith('\\\n'):
+ new_lineno = node.lineno - node.prefix.count('\n')
+ return pytree.Leaf(
+ type=format_token.CONTINUATION,
+ value=node.prefix,
+ context=('', (new_lineno, 0)))
+ return None
+ num_inserted = 0
+ for index, child in enumerate(node.children[:]):
+ continuation_node = RecSplicer(child)
+ if continuation_node:
+ node.children.insert(index + num_inserted, continuation_node)
+ num_inserted += 1
+
+ RecSplicer(tree)
diff --git a/tools/yapf/yapf/yapflib/errors.py b/tools/yapf/yapf/yapflib/errors.py
new file mode 100644
index 00000000..aa8f3ead
--- /dev/null
+++ b/tools/yapf/yapf/yapflib/errors.py
@@ -0,0 +1,23 @@
+# Copyright 2015-2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""YAPF error object."""
+
+
+class YapfError(Exception):
+ """Parent class for user errors or input errors.
+
+ Exceptions of this type are handled by the command line tool
+ and result in clear error messages, as opposed to backtraces.
+ """
+ pass
diff --git a/tools/yapf/yapf/yapflib/file_resources.py b/tools/yapf/yapf/yapflib/file_resources.py
new file mode 100644
index 00000000..e7f9acdc
--- /dev/null
+++ b/tools/yapf/yapf/yapflib/file_resources.py
@@ -0,0 +1,169 @@
+# Copyright 2015-2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Interface to file resources.
+
+This module provides functions for interfacing with files: opening, writing, and
+querying.
+"""
+
+import fnmatch
+import os
+import re
+
+from lib2to3.pgen2 import tokenize
+
+from yapf.yapflib import errors
+from yapf.yapflib import py3compat
+from yapf.yapflib import style
+
+CR = '\r'
+LF = '\n'
+CRLF = '\r\n'
+
+
+def GetDefaultStyleForDir(dirname):
+ """Return default style name for a given directory.
+
+ Looks for .style.yapf or setup.cfg in the parent directories.
+
+ Arguments:
+ dirname: (unicode) The name of the directory.
+
+ Returns:
+ The filename if found, otherwise return the global default (pep8).
+ """
+ dirname = os.path.abspath(dirname)
+ while True:
+ # See if we have a .style.yapf file.
+ style_file = os.path.join(dirname, style.LOCAL_STYLE)
+ if os.path.exists(style_file):
+ return style_file
+
+ # See if we have a setup.cfg file with a '[yapf]' section.
+ config_file = os.path.join(dirname, style.SETUP_CONFIG)
+ if os.path.exists(config_file):
+ with open(config_file) as fd:
+ config = py3compat.ConfigParser()
+ config.read_file(fd)
+ if config.has_section('yapf'):
+ return config_file
+
+ dirname = os.path.dirname(dirname)
+ if (not dirname or not os.path.basename(dirname) or
+ dirname == os.path.abspath(os.path.sep)):
+ break
+
+ global_file = os.path.expanduser(style.GLOBAL_STYLE)
+ if os.path.exists(global_file):
+ return global_file
+
+ return style.DEFAULT_STYLE
+
+
+def GetCommandLineFiles(command_line_file_list, recursive, exclude):
+ """Return the list of files specified on the command line."""
+ return _FindPythonFiles(command_line_file_list, recursive, exclude)
+
+
+def WriteReformattedCode(filename,
+ reformatted_code,
+ in_place=False,
+ encoding=''):
+ """Emit the reformatted code.
+
+ Write the reformatted code into the file, if in_place is True. Otherwise,
+ write to stdout.
+
+ Arguments:
+ filename: (unicode) The name of the unformatted file.
+ reformatted_code: (unicode) The reformatted code.
+ in_place: (bool) If True, then write the reformatted code to the file.
+ encoding: (unicode) The encoding of the file.
+ """
+ if in_place:
+ with py3compat.open_with_encoding(
+ filename, mode='w', encoding=encoding, newline='') as fd:
+ fd.write(reformatted_code)
+ else:
+ py3compat.EncodeAndWriteToStdout(reformatted_code)
+
+
+def LineEnding(lines):
+ """Retrieve the line ending of the original source."""
+ endings = {CRLF: 0, CR: 0, LF: 0}
+ for line in lines:
+ if line.endswith(CRLF):
+ endings[CRLF] += 1
+ elif line.endswith(CR):
+ endings[CR] += 1
+ elif line.endswith(LF):
+ endings[LF] += 1
+ return (sorted(endings, key=endings.get, reverse=True) or [LF])[0]
+
+
+def _FindPythonFiles(filenames, recursive, exclude):
+ """Find all Python files."""
+ python_files = []
+ for filename in filenames:
+ if os.path.isdir(filename):
+ if recursive:
+ # TODO(morbo): Look into a version of os.walk that can handle recursion.
+ python_files.extend(
+ os.path.join(dirpath, f)
+ for dirpath, _, filelist in os.walk(filename) for f in filelist
+ if IsPythonFile(os.path.join(dirpath, f)))
+ else:
+ raise errors.YapfError(
+ "directory specified without '--recursive' flag: %s" % filename)
+ elif os.path.isfile(filename):
+ python_files.append(filename)
+
+ if exclude:
+ return [
+ f for f in python_files
+ if not any(fnmatch.fnmatch(f, p) for p in exclude)
+ ]
+
+ return python_files
+
+
+def IsPythonFile(filename):
+ """Return True if filename is a Python file."""
+ if os.path.splitext(filename)[1] == '.py':
+ return True
+
+ try:
+ with open(filename, 'rb') as fd:
+ encoding = tokenize.detect_encoding(fd.readline)[0]
+
+ # Check for correctness of encoding.
+ with py3compat.open_with_encoding(
+ filename, mode='r', encoding=encoding) as fd:
+ fd.read()
+ except UnicodeDecodeError:
+ encoding = 'latin-1'
+ except (IOError, SyntaxError):
+ # If we fail to detect encoding (or the encoding cookie is incorrect - which
+ # will make detect_encoding raise SyntaxError), assume it's not a Python
+ # file.
+ return False
+
+ try:
+ with py3compat.open_with_encoding(
+ filename, mode='r', encoding=encoding) as fd:
+ first_line = fd.readlines()[0]
+ except (IOError, IndexError):
+ return False
+
+ return re.match(r'^#!.*\bpython[23]?\b', first_line)
diff --git a/tools/yapf/yapf/yapflib/format_decision_state.py b/tools/yapf/yapf/yapflib/format_decision_state.py
new file mode 100644
index 00000000..3c17dc4a
--- /dev/null
+++ b/tools/yapf/yapf/yapflib/format_decision_state.py
@@ -0,0 +1,799 @@
+# Copyright 2015-2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Implements a format decision state object that manages whitespace decisions.
+
+Each token is processed one at a time, at which point its whitespace formatting
+decisions are made. A graph of potential whitespace formattings is created,
+where each node in the graph is a format decision state object. The heuristic
+tries formatting the token with and without a newline before it to determine
+which one has the least penalty. Therefore, the format decision state object for
+each decision needs to be its own unique copy.
+
+Once the heuristic determines the best formatting, it makes a non-dry run pass
+through the code to commit the whitespace formatting.
+
+ FormatDecisionState: main class exported by this module.
+"""
+
+from yapf.yapflib import format_token
+from yapf.yapflib import split_penalty
+from yapf.yapflib import style
+from yapf.yapflib import unwrapped_line
+
+_COMPOUND_STMTS = frozenset(
+ {'for', 'while', 'if', 'elif', 'with', 'except', 'def', 'class'})
+
+
+class FormatDecisionState(object):
+ """The current state when indenting an unwrapped line.
+
+ The FormatDecisionState object is meant to be copied instead of referenced.
+
+ Attributes:
+ first_indent: The indent of the first token.
+ column: The number of used columns in the current line.
+ next_token: The next token to be formatted.
+ paren_level: The level of nesting inside (), [], and {}.
+ start_of_line_level: The paren_level at the start of this line.
+ lowest_level_on_line: The lowest paren_level on the current line.
+ newline: Indicates if a newline is added along the edge to this format
+ decision state node.
+ previous: The previous format decision state in the decision tree.
+ stack: A stack (of _ParenState) keeping track of properties applying to
+ parenthesis levels.
+ ignore_stack_for_comparison: Ignore the stack of _ParenState for state
+ comparison.
+ """
+
+ def __init__(self, line, first_indent):
+ """Initializer.
+
+ Initializes to the state after placing the first token from 'line' at
+ 'first_indent'.
+
+ Arguments:
+ line: (UnwrappedLine) The unwrapped line we're currently processing.
+ first_indent: (int) The indent of the first token.
+ """
+ self.next_token = line.first
+ self.column = first_indent
+ self.line = line
+ self.paren_level = 0
+ self.start_of_line_level = 0
+ self.lowest_level_on_line = 0
+ self.ignore_stack_for_comparison = False
+ self.stack = [_ParenState(first_indent, first_indent)]
+ self.first_indent = first_indent
+ self.newline = False
+ self.previous = None
+ self.column_limit = style.Get('COLUMN_LIMIT')
+
+ def Clone(self):
+ """Clones a FormatDecisionState object."""
+ new = FormatDecisionState(self.line, self.first_indent)
+ new.next_token = self.next_token
+ new.column = self.column
+ new.line = self.line
+ new.paren_level = self.paren_level
+ new.start_of_line_level = self.start_of_line_level
+ new.lowest_level_on_line = self.lowest_level_on_line
+ new.ignore_stack_for_comparison = self.ignore_stack_for_comparison
+ new.first_indent = self.first_indent
+ new.newline = self.newline
+ new.previous = self.previous
+ new.stack = [state.Clone() for state in self.stack]
+ return new
+
+ def __eq__(self, other):
+ # Note: 'first_indent' is implicit in the stack. Also, we ignore 'previous',
+ # because it shouldn't have a bearing on this comparison. (I.e., it will
+ # report equal if 'next_token' does.)
+ return (self.next_token == other.next_token and
+ self.column == other.column and
+ self.paren_level == other.paren_level and
+ self.start_of_line_level == other.start_of_line_level and
+ self.lowest_level_on_line == other.lowest_level_on_line and
+ (self.ignore_stack_for_comparison or
+ other.ignore_stack_for_comparison or self.stack == other.stack))
+
+ def __ne__(self, other):
+ return not self == other
+
+ def __hash__(self):
+ return hash((self.next_token, self.column, self.paren_level,
+ self.start_of_line_level, self.lowest_level_on_line))
+
+ def __repr__(self):
+ return ('column::%d, next_token::%s, paren_level::%d, stack::[\n\t%s' %
+ (self.column, repr(self.next_token), self.paren_level,
+ '\n\t'.join(repr(s) for s in self.stack) + ']'))
+
+ def CanSplit(self, must_split):
+ """Determine if we can split before the next token.
+
+ Arguments:
+ must_split: (bool) A newline was required before this token.
+
+ Returns:
+ True if the line can be split before the next token.
+ """
+ current = self.next_token
+
+ if current.is_pseudo_paren:
+ return False
+
+ if (not must_split and
+ format_token.Subtype.DICTIONARY_KEY_PART in current.subtypes and
+ format_token.Subtype.DICTIONARY_KEY not in current.subtypes and
+ not style.Get('ALLOW_MULTILINE_DICTIONARY_KEYS')):
+ # In some situations, a dictionary may be multiline, but pylint doesn't
+ # like it. So don't allow it unless forced to.
+ return False
+
+ return current.can_break_before
+
+ def MustSplit(self):
+ """Returns True if the line must split before the next token."""
+ current = self.next_token
+ previous = current.previous_token
+
+ if current.is_pseudo_paren:
+ return False
+
+ if current.must_break_before:
+ return True
+
+ if not previous:
+ return False
+
+ if self.stack[-1].split_before_closing_bracket and current.value in '}]':
+ # Split before the closing bracket if we can.
+ return current.node_split_penalty != split_penalty.UNBREAKABLE
+
+ # Prevent splitting before the first argument in compound statements
+ # with the exception of function declarations.
+ if (style.Get('SPLIT_BEFORE_FIRST_ARGUMENT') and
+ self.line.first.value != 'def' and
+ self.line.first.value in _COMPOUND_STMTS):
+ return False
+
+ ###########################################################################
+ # List Splitting
+ if (style.Get('DEDENT_CLOSING_BRACKETS') or
+ style.Get('SPLIT_BEFORE_FIRST_ARGUMENT')):
+ bracket = current if current.ClosesScope() else previous
+ if format_token.Subtype.SUBSCRIPT_BRACKET not in bracket.subtypes:
+ if bracket.OpensScope():
+ if style.Get('COALESCE_BRACKETS'):
+ if current.OpensScope():
+ # Prefer to keep all opening brackets together.
+ return False
+
+ if (not _IsLastScopeInLine(bracket) or
+ unwrapped_line.IsSurroundedByBrackets(bracket)):
+ last_token = bracket.matching_bracket
+ else:
+ last_token = _LastTokenInLine(bracket.matching_bracket)
+
+ if not self._FitsOnLine(bracket, last_token):
+ # Split before the first element if the whole list can't fit on a
+ # single line.
+ self.stack[-1].split_before_closing_bracket = True
+ return True
+
+ elif style.Get('DEDENT_CLOSING_BRACKETS') and current.ClosesScope():
+ # Split before and dedent the closing bracket.
+ return self.stack[-1].split_before_closing_bracket
+
+ if (current.is_name or current.is_string) and previous.value == ',':
+ # If the list has function calls in it and the full list itself cannot
+ # fit on the line, then we want to split. Otherwise, we'll get something
+ # like this:
+ #
+ # X = [
+ # Bar(xxx='some string',
+ # yyy='another long string',
+ # zzz='a third long string'), Bar(
+ # xxx='some string',
+ # yyy='another long string',
+ # zzz='a third long string')
+ # ]
+ #
+ # or when a string formatting syntax.
+ func_call_or_string_format = False
+ if current.is_name:
+ tok = current.next_token
+ while tok and (tok.is_name or tok.value == '.'):
+ tok = tok.next_token
+ func_call_or_string_format = tok and tok.value == '('
+ elif current.is_string:
+ tok = current.next_token
+ while tok and tok.is_string:
+ tok = tok.next_token
+ func_call_or_string_format = tok and tok.value == '%'
+ if func_call_or_string_format:
+ open_bracket = unwrapped_line.IsSurroundedByBrackets(current)
+ if open_bracket and open_bracket.value in '[{':
+ if not self._FitsOnLine(open_bracket, open_bracket.matching_bracket):
+ return True
+
+ ###########################################################################
+ # Dict/Set Splitting
+ if (style.Get('EACH_DICT_ENTRY_ON_SEPARATE_LINE') and
+ format_token.Subtype.DICTIONARY_KEY in current.subtypes and
+ not current.is_comment):
+ # Place each dictionary entry onto its own line.
+ if previous.value == '{' and previous.previous_token:
+ opening = _GetOpeningBracket(previous.previous_token)
+ if (opening and opening.value == '(' and opening.previous_token and
+ opening.previous_token.is_name):
+ # This is a dictionary that's an argument to a function.
+ if self._FitsOnLine(previous, previous.matching_bracket):
+ return False
+ return True
+
+ if (style.Get('SPLIT_BEFORE_DICT_SET_GENERATOR') and
+ format_token.Subtype.DICT_SET_GENERATOR in current.subtypes):
+ # Split before a dict/set generator.
+ return True
+
+ if (format_token.Subtype.DICTIONARY_VALUE in current.subtypes or
+ (previous.is_pseudo_paren and previous.value == '(' and
+ not current.is_comment)):
+ # Split before the dictionary value if we can't fit every dictionary
+ # entry on its own line.
+ if not current.OpensScope():
+ opening = _GetOpeningBracket(current)
+ if not self._EachDictEntryFitsOnOneLine(opening):
+ return True
+
+ if previous.value == '{':
+ # Split if the dict/set cannot fit on one line and ends in a comma.
+ closing = previous.matching_bracket
+ if (not self._FitsOnLine(previous, closing) and
+ closing.previous_token.value == ','):
+ self.stack[-1].split_before_closing_bracket = True
+ return True
+
+ ###########################################################################
+ # Argument List Splitting
+ if (style.Get('SPLIT_BEFORE_NAMED_ASSIGNS') and not current.is_comment and
+ format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST in
+ current.subtypes):
+ if (previous.value not in {'=', ':', '*', '**'} and
+ current.value not in ':=,)' and not _IsFunctionDefinition(previous)):
+ # If we're going to split the lines because of named arguments, then we
+ # want to split after the opening bracket as well. But not when this is
+ # part of a function definition.
+ if previous.value == '(':
+ # Make sure we don't split after the opening bracket if the
+ # continuation indent is greater than the opening bracket:
+ #
+ # a(
+ # b=1,
+ # c=2)
+ if (self._FitsOnLine(previous, previous.matching_bracket) and
+ unwrapped_line.IsSurroundedByBrackets(previous)):
+ # An argument to a function is a function call with named
+ # assigns.
+ return False
+
+ column = self.column - self.stack[-1].last_space
+ return column > style.Get('CONTINUATION_INDENT_WIDTH')
+
+ opening = _GetOpeningBracket(current)
+ if opening:
+ arglist_length = (opening.matching_bracket.total_length -
+ opening.total_length + self.stack[-1].indent)
+ return arglist_length > self.column_limit
+
+ if style.Get('SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED'):
+ # Split before arguments in a function call or definition if the
+ # arguments are terminated by a comma.
+ opening = _GetOpeningBracket(current)
+ if opening and opening.previous_token and opening.previous_token.is_name:
+ if previous.value in '(,':
+ if opening.matching_bracket.previous_token.value == ',':
+ return True
+
+ if ((current.is_name or current.value in {'*', '**'}) and
+ previous.value == ','):
+ # If we have a function call within an argument list and it won't fit on
+ # the remaining line, but it will fit on a line by itself, then go ahead
+ # and split before the call.
+ opening = _GetOpeningBracket(current)
+ if (opening and opening.value == '(' and opening.previous_token and
+ (opening.previous_token.is_name or
+ opening.previous_token.value in {'*', '**'})):
+ is_func_call = False
+ token = current
+ while token:
+ if token.value == '(':
+ is_func_call = True
+ break
+ if (not (token.is_name or token.value in {'*', '**'}) and
+ token.value != '.'):
+ break
+ token = token.next_token
+
+ if is_func_call:
+ if not self._FitsOnLine(current, opening.matching_bracket):
+ return True
+
+ pprevious = previous.previous_token
+ if (current.is_name and pprevious and pprevious.is_name and
+ previous.value == '('):
+ if (not self._FitsOnLine(previous, previous.matching_bracket) and
+ _IsFunctionCallWithArguments(current)):
+ # There is a function call, with more than 1 argument, where the first
+ # argument is itself a function call with arguments. In this specific
+ # case, if we split after the first argument's opening '(', then the
+ # formatting will look bad for the rest of the arguments. E.g.:
+ #
+ # outer_function_call(inner_function_call(
+ # inner_arg1, inner_arg2),
+ # outer_arg1, outer_arg2)
+ #
+ # Instead, enforce a split before that argument to keep things looking
+ # good.
+ return True
+
+ if (previous.OpensScope() and not current.OpensScope() and
+ format_token.Subtype.SUBSCRIPT_BRACKET not in previous.subtypes):
+ if not current.is_comment:
+ if pprevious and not pprevious.is_keyword and not pprevious.is_name:
+ # We want to split if there's a comment in the container.
+ token = current
+ while token != previous.matching_bracket:
+ if token.is_comment:
+ return True
+ token = token.next_token
+
+ if previous.value == '(':
+ pptoken = previous.previous_token
+ if not pptoken or not pptoken.is_name:
+ # Split after the opening of a tuple if it doesn't fit on the current
+ # line and it's not a function call.
+ if self._FitsOnLine(previous, previous.matching_bracket):
+ return False
+ elif not self._FitsOnLine(previous, previous.matching_bracket):
+ if (self.column_limit - self.column) / float(self.column_limit) < 0.3:
+ # Try not to squish all of the arguments off to the right.
+ return current.next_token != previous.matching_bracket
+ else:
+ # Split after the opening of a container if it doesn't fit on the
+ # current line or if it has a comment.
+ if not self._FitsOnLine(previous, previous.matching_bracket):
+ return True
+
+ ###########################################################################
+ # List Comprehension Splitting
+ if (format_token.Subtype.COMP_FOR in current.subtypes and
+ format_token.Subtype.COMP_FOR not in previous.subtypes):
+ # Split at the beginning of a list comprehension.
+ length = _GetLengthOfSubtype(current, format_token.Subtype.COMP_FOR,
+ format_token.Subtype.COMP_IF)
+ if length + self.column > self.column_limit:
+ return True
+
+ if (format_token.Subtype.COMP_IF in current.subtypes and
+ format_token.Subtype.COMP_IF not in previous.subtypes):
+ # Split at the beginning of an if expression.
+ length = _GetLengthOfSubtype(current, format_token.Subtype.COMP_IF)
+ if length + self.column > self.column_limit:
+ return True
+
+ ###########################################################################
+ # Original Formatting Splitting
+ # These checks rely upon the original formatting. This is in order to
+ # attempt to keep hand-written code in the same condition as it was before.
+ # However, this may cause the formatter to fail to be idempotent.
+ if (style.Get('SPLIT_BEFORE_BITWISE_OPERATOR') and current.value in '&|' and
+ previous.lineno < current.lineno):
+ # Retain the split before a bitwise operator.
+ return True
+
+ if (current.is_comment and
+ previous.lineno < current.lineno - current.value.count('\n')):
+ # If a comment comes in the middle of an unwrapped line (like an if
+ # conditional with comments interspersed), then we want to split if the
+ # original comments were on a separate line.
+ return True
+
+ return False
+
+ def AddTokenToState(self, newline, dry_run, must_split=False):
+ """Add a token to the format decision state.
+
+ Allow the heuristic to try out adding the token with and without a newline.
+ Later on, the algorithm will determine which one has the lowest penalty.
+
+ Arguments:
+ newline: (bool) Add the token on a new line if True.
+ dry_run: (bool) Don't commit whitespace changes to the FormatToken if
+ True.
+ must_split: (bool) A newline was required before this token.
+
+ Returns:
+ The penalty of splitting after the current token.
+ """
+ penalty = 0
+ if newline:
+ penalty = self._AddTokenOnNewline(dry_run, must_split)
+ else:
+ self._AddTokenOnCurrentLine(dry_run)
+
+ return self.MoveStateToNextToken() + penalty
+
+ def _AddTokenOnCurrentLine(self, dry_run):
+ """Puts the token on the current line.
+
+ Appends the next token to the state and updates information necessary for
+ indentation.
+
+ Arguments:
+ dry_run: (bool) Commit whitespace changes to the FormatToken if True.
+ """
+ current = self.next_token
+ previous = current.previous_token
+
+ spaces = current.spaces_required_before
+ if not dry_run:
+ current.AddWhitespacePrefix(newlines_before=0, spaces=spaces)
+
+ if previous.OpensScope():
+ if not current.is_comment:
+ # Align closing scopes that are on a newline with the opening scope:
+ #
+ # foo = [a,
+ # b,
+ # ]
+ self.stack[-1].closing_scope_indent = self.column - 1
+ if style.Get('ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT'):
+ self.stack[-1].closing_scope_indent += 1
+ self.stack[-1].indent = self.column + spaces
+ else:
+ self.stack[-1].closing_scope_indent = (
+ self.stack[-1].indent - style.Get('CONTINUATION_INDENT_WIDTH'))
+
+ self.column += spaces
+
+ def _AddTokenOnNewline(self, dry_run, must_split):
+ """Adds a line break and necessary indentation.
+
+ Appends the next token to the state and updates information necessary for
+ indentation.
+
+ Arguments:
+ dry_run: (bool) Don't commit whitespace changes to the FormatToken if
+ True.
+ must_split: (bool) A newline was required before this token.
+
+ Returns:
+ The split penalty for splitting after the current state.
+ """
+ current = self.next_token
+ previous = current.previous_token
+
+ self.column = self._GetNewlineColumn()
+
+ if not dry_run:
+ current.AddWhitespacePrefix(newlines_before=1, spaces=self.column)
+
+ if not current.is_comment:
+ self.stack[-1].last_space = self.column
+ self.start_of_line_level = self.paren_level
+ self.lowest_level_on_line = self.paren_level
+
+ if (previous.OpensScope() or
+ (previous.is_comment and previous.previous_token is not None and
+ previous.previous_token.OpensScope())):
+ self.stack[-1].closing_scope_indent = max(
+ 0, self.stack[-1].indent - style.Get('CONTINUATION_INDENT_WIDTH'))
+
+ split_before_closing_bracket = True
+ if style.Get('COALESCE_BRACKETS'):
+ split_before_closing_bracket = False
+
+ self.stack[-1].split_before_closing_bracket = split_before_closing_bracket
+
+ # Calculate the split penalty.
+ penalty = current.split_penalty
+
+ if must_split:
+ # Don't penalize for a must split.
+ return penalty
+
+ if previous.is_pseudo_paren and previous.value == '(':
+ # Small penalty for splitting after a pseudo paren.
+ penalty += 50
+
+ # Add a penalty for each increasing newline we add, but don't penalize for
+ # splitting before an if-expression or list comprehension.
+ if current.value not in {'if', 'for'}:
+ last = self.stack[-1]
+ last.num_line_splits += 1
+ penalty += (style.Get('SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT') *
+ last.num_line_splits)
+
+ if current.OpensScope() and previous.OpensScope():
+ # Prefer to keep opening brackets coalesced (unless it's at the beginning
+ # of a function call).
+ pprev = previous.previous_token
+ if not pprev or not pprev.is_name:
+ penalty += 10
+
+ return penalty + 10
+
+ def _GetNewlineColumn(self):
+ """Return the new column on the newline."""
+ current = self.next_token
+ previous = current.previous_token
+ top_of_stack = self.stack[-1]
+
+ if current.spaces_required_before > 2 or self.line.disable:
+ return current.spaces_required_before
+
+ if current.OpensScope():
+ return top_of_stack.indent if self.paren_level else self.first_indent
+
+ if current.ClosesScope():
+ if (previous.OpensScope() or
+ (previous.is_comment and previous.previous_token is not None and
+ previous.previous_token.OpensScope())):
+ return max(0,
+ top_of_stack.indent - style.Get('CONTINUATION_INDENT_WIDTH'))
+ return top_of_stack.closing_scope_indent
+
+ if (previous and previous.is_string and current.is_string and
+ format_token.Subtype.DICTIONARY_VALUE in current.subtypes):
+ return previous.column
+
+ if style.Get('INDENT_DICTIONARY_VALUE'):
+ if previous and (previous.value == ':' or previous.is_pseudo_paren):
+ if format_token.Subtype.DICTIONARY_VALUE in current.subtypes:
+ return top_of_stack.indent
+
+ if (self.line.first.value in _COMPOUND_STMTS and
+ (not style.Get('DEDENT_CLOSING_BRACKETS') or
+ style.Get('SPLIT_BEFORE_FIRST_ARGUMENT'))):
+ token_indent = (len(self.line.first.whitespace_prefix.split('\n')[-1]) +
+ style.Get('INDENT_WIDTH'))
+ if token_indent == top_of_stack.indent:
+ return top_of_stack.indent + style.Get('CONTINUATION_INDENT_WIDTH')
+
+ return top_of_stack.indent
+
+ def MoveStateToNextToken(self):
+ """Calculate format decision state information and move onto the next token.
+
+ Before moving onto the next token, we first calculate the format decision
+ state given the current token and its formatting decisions. Then the format
+ decision state is set up so that the next token can be added.
+
+ Returns:
+ The penalty for the number of characters over the column limit.
+ """
+ current = self.next_token
+ if not current.OpensScope() and not current.ClosesScope():
+ self.lowest_level_on_line = min(self.lowest_level_on_line,
+ self.paren_level)
+
+ # If we encounter an opening bracket, we add a level to our stack to prepare
+ # for the subsequent tokens.
+ if current.OpensScope():
+ last = self.stack[-1]
+ new_indent = style.Get('CONTINUATION_INDENT_WIDTH') + last.last_space
+
+ self.stack.append(_ParenState(new_indent, self.stack[-1].last_space))
+ self.paren_level += 1
+
+ # If we encounter a closing bracket, we can remove a level from our
+ # parenthesis stack.
+ if len(self.stack) > 1 and current.ClosesScope():
+ self.stack[-2].last_space = self.stack[-1].last_space
+ self.stack.pop()
+ self.paren_level -= 1
+
+ is_multiline_string = current.is_string and '\n' in current.value
+ if is_multiline_string:
+ # This is a multiline string. Only look at the first line.
+ self.column += len(current.value.split('\n')[0])
+ elif not current.is_pseudo_paren:
+ self.column += len(current.value)
+
+ self.next_token = self.next_token.next_token
+
+ # Calculate the penalty for overflowing the column limit.
+ penalty = 0
+ if not current.is_pylint_comment and self.column > self.column_limit:
+ excess_characters = self.column - self.column_limit
+ penalty += style.Get('SPLIT_PENALTY_EXCESS_CHARACTER') * excess_characters
+
+ if is_multiline_string:
+ # If this is a multiline string, the column is actually the
+ # end of the last line in the string.
+ self.column = len(current.value.split('\n')[-1])
+
+ return penalty
+
+ def _FitsOnLine(self, start, end):
+ """Determines if line between start and end can fit on the current line."""
+ length = end.total_length - start.total_length
+ if not start.is_pseudo_paren:
+ length += len(start.value)
+ return length + self.column <= self.column_limit
+
+ def _EachDictEntryFitsOnOneLine(self, opening):
+ """Determine if each dict elems can fit on one line."""
+
+ def PreviousNonCommentToken(tok):
+ tok = tok.previous_token
+ while tok.is_comment:
+ tok = tok.previous_token
+ return tok
+
+ def ImplicitStringConcatenation(tok):
+ num_strings = 0
+ if tok.is_pseudo_paren:
+ tok = tok.next_token
+ while tok.is_string:
+ num_strings += 1
+ tok = tok.next_token
+ return num_strings > 1
+
+ closing = opening.matching_bracket
+ entry_start = opening.next_token
+ current = opening.next_token.next_token
+
+ while current and current != closing:
+ if format_token.Subtype.DICTIONARY_KEY in current.subtypes:
+ prev = PreviousNonCommentToken(current)
+ length = prev.total_length - entry_start.total_length
+ length += len(entry_start.value)
+ if length + self.stack[-2].indent >= self.column_limit:
+ return False
+ entry_start = current
+ if current.OpensScope():
+ if ((current.value == '{' or
+ (current.is_pseudo_paren and current.next_token.value == '{') and
+ format_token.Subtype.DICTIONARY_VALUE in current.subtypes) or
+ ImplicitStringConcatenation(current)):
+ # A dictionary entry that cannot fit on a single line shouldn't matter
+ # to this calcuation. If it can't fit on a single line, then the
+ # opening should be on the same line as the key and the rest on
+ # newlines after it. But the other entries should be on single lines
+ # if possible.
+ if current.matching_bracket:
+ current = current.matching_bracket
+ while current:
+ if current == closing:
+ return True
+ if format_token.Subtype.DICTIONARY_KEY in current.subtypes:
+ entry_start = current
+ break
+ current = current.next_token
+ else:
+ current = current.matching_bracket
+ else:
+ current = current.next_token
+
+ # At this point, current is the closing bracket. Go back one to get the the
+ # end of the dictionary entry.
+ current = PreviousNonCommentToken(current)
+ length = current.total_length - entry_start.total_length
+ length += len(entry_start.value)
+ return length + self.stack[-2].indent <= self.column_limit
+
+
+def _IsFunctionCallWithArguments(token):
+ while token:
+ if token.value == '(':
+ token = token.next_token
+ return token and token.value != ')'
+ elif token.name not in {'NAME', 'DOT'}:
+ break
+ token = token.next_token
+ return False
+
+
+def _GetLengthOfSubtype(token, subtype, exclude=None):
+ current = token
+ while (current.next_token and subtype in current.subtypes and
+ (exclude is None or exclude not in current.subtypes)):
+ current = current.next_token
+ return current.total_length - token.total_length + 1
+
+
+def _GetOpeningBracket(current):
+ """Get the opening bracket containing the current token."""
+ if current.matching_bracket and not current.is_pseudo_paren:
+ return current.matching_bracket
+ while current:
+ if current.ClosesScope():
+ current = current.matching_bracket
+ elif current.is_pseudo_paren:
+ current = current.previous_token
+ elif current.OpensScope():
+ return current
+ current = current.previous_token
+ return None
+
+
+def _LastTokenInLine(current):
+ while not current.is_comment and current.next_token:
+ current = current.next_token
+ return current
+
+
+def _IsFunctionDefinition(current):
+ prev = current.previous_token
+ return (current.value == '(' and prev and
+ format_token.Subtype.FUNC_DEF in prev.subtypes)
+
+
+def _IsLastScopeInLine(current):
+ while current:
+ current = current.next_token
+ if current and current.OpensScope():
+ return False
+ return True
+
+
+class _ParenState(object):
+ """Maintains the state of the bracket enclosures.
+
+ A stack of _ParenState objects are kept so that we know how to indent relative
+ to the brackets.
+
+ Attributes:
+ indent: The column position to which a specified parenthesis level needs to
+ be indented.
+ last_space: The column position of the last space on each level.
+ split_before_closing_bracket: Whether a newline needs to be inserted before
+ the closing bracket. We only want to insert a newline before the closing
+ bracket if there also was a newline after the beginning left bracket.
+ num_line_splits: Number of line splits this _ParenState contains already.
+ Each subsequent line split gets an increasing penalty.
+ """
+
+ # TODO(morbo): This doesn't track "bin packing."
+
+ def __init__(self, indent, last_space):
+ self.indent = indent
+ self.last_space = last_space
+ self.closing_scope_indent = 0
+ self.split_before_closing_bracket = False
+ self.num_line_splits = 0
+
+ def Clone(self):
+ state = _ParenState(self.indent, self.last_space)
+ state.closing_scope_indent = self.closing_scope_indent
+ state.split_before_closing_bracket = self.split_before_closing_bracket
+ state.num_line_splits = self.num_line_splits
+ return state
+
+ def __repr__(self):
+ return '[indent::%d, last_space::%d, closing_scope_indent::%d]' % (
+ self.indent, self.last_space, self.closing_scope_indent)
+
+ def __eq__(self, other):
+ return hash(self) == hash(other)
+
+ def __ne__(self, other):
+ return not self == other
+
+ def __hash__(self, *args, **kwargs):
+ return hash((self.indent, self.last_space, self.closing_scope_indent,
+ self.split_before_closing_bracket, self.num_line_splits))
diff --git a/tools/yapf/yapf/yapflib/format_token.py b/tools/yapf/yapf/yapflib/format_token.py
new file mode 100644
index 00000000..de270cf5
--- /dev/null
+++ b/tools/yapf/yapf/yapflib/format_token.py
@@ -0,0 +1,283 @@
+# Copyright 2015-2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Pytree nodes with extra formatting information.
+
+This is a thin wrapper around a pytree.Leaf node.
+"""
+
+import keyword
+import re
+
+from lib2to3.pgen2 import token
+
+from yapf.yapflib import py3compat
+from yapf.yapflib import pytree_utils
+from yapf.yapflib import style
+
+CONTINUATION = token.N_TOKENS
+token.N_TOKENS += 1
+
+
+class Subtype(object):
+ """Subtype information about tokens.
+
+ Gleaned from parsing the code. Helps determine the best formatting.
+ """
+ NONE = 0
+ UNARY_OPERATOR = 1
+ BINARY_OPERATOR = 2
+ SUBSCRIPT_COLON = 3
+ SUBSCRIPT_BRACKET = 4
+ DEFAULT_OR_NAMED_ASSIGN = 5
+ DEFAULT_OR_NAMED_ASSIGN_ARG_LIST = 6
+ VARARGS_LIST = 7
+ VARARGS_STAR = 8
+ KWARGS_STAR_STAR = 9
+ ASSIGN_OPERATOR = 10
+ DICTIONARY_KEY = 11
+ DICTIONARY_KEY_PART = 12
+ DICTIONARY_VALUE = 13
+ DICT_SET_GENERATOR = 14
+ COMP_FOR = 15
+ COMP_IF = 16
+ FUNC_DEF = 17
+ DECORATOR = 18
+
+
+class FormatToken(object):
+ """A wrapper around pytree Leaf nodes.
+
+ This represents the token plus additional information useful for reformatting
+ the code.
+
+ Attributes:
+ next_token: The token in the unwrapped line after this token or None if this
+ is the last token in the unwrapped line.
+ previous_token: The token in the unwrapped line before this token or None if
+ this is the first token in the unwrapped line.
+ matching_bracket: If a bracket token ('[', '{', or '(') the matching
+ bracket.
+ whitespace_prefix: The prefix for the whitespace.
+ spaces_required_before: The number of spaces required before a token. This
+ is a lower-bound for the formatter and not a hard requirement. For
+ instance, a comment may have n required spaces before it. But the
+ formatter won't place n spaces before all comments. Only those that are
+ moved to the end of a line of code. The formatter may use different
+ spacing when appropriate.
+ can_break_before: True if we're allowed to break before this token.
+ must_break_before: True if we're required to break before this token.
+ total_length: The total length of the unwrapped line up to and including
+ whitespace and this token. However, this doesn't include the initial
+ indentation amount.
+ split_penalty: The penalty for splitting the line before this token.
+ """
+
+ def __init__(self, node):
+ """Constructor.
+
+ Arguments:
+ node: (pytree.Leaf) The node that's being wrapped.
+ """
+ self.node = node
+ self.next_token = None
+ self.previous_token = None
+ self.matching_bracket = None
+ self.whitespace_prefix = ''
+ self.can_break_before = False
+ self.must_break_before = False
+ self.total_length = 0 # TODO(morbo): Think up a better name.
+ self.split_penalty = 0
+
+ if self.is_comment:
+ self.spaces_required_before = style.Get('SPACES_BEFORE_COMMENT')
+ else:
+ self.spaces_required_before = 0
+
+ if self.is_continuation:
+ self.value = self.node.value.rstrip()
+ else:
+ self.value = self.node.value
+
+ def AddWhitespacePrefix(self, newlines_before, spaces=0, indent_level=0):
+ """Register a token's whitespace prefix.
+
+ This is the whitespace that will be output before a token's string.
+
+ Arguments:
+ newlines_before: (int) The number of newlines to place before the token.
+ spaces: (int) The number of spaces to place before the token.
+ indent_level: (int) The indentation level.
+ """
+ indent_char = '\t' if style.Get('USE_TABS') else ' '
+ token_indent_char = indent_char if newlines_before > 0 else ' '
+ indent_before = (indent_char * indent_level * style.Get('INDENT_WIDTH') +
+ token_indent_char * spaces)
+
+ if self.is_comment:
+ comment_lines = [s.lstrip() for s in self.value.splitlines()]
+ self.node.value = ('\n' + indent_before).join(comment_lines)
+
+ # Update our own value since we are changing node value
+ self.value = self.node.value
+
+ if not self.whitespace_prefix:
+ self.whitespace_prefix = (
+ '\n' * (self.newlines or newlines_before) + indent_before)
+ else:
+ self.whitespace_prefix += indent_before
+
+ def AdjustNewlinesBefore(self, newlines_before):
+ """Change the number of newlines before this token."""
+ self.whitespace_prefix = (
+ '\n' * newlines_before + self.whitespace_prefix.lstrip('\n'))
+
+ def RetainHorizontalSpacing(self, first_column, depth):
+ """Retains a token's horizontal spacing."""
+ previous = self.previous_token
+ if previous is None:
+ return
+
+ cur_lineno = self.lineno
+ prev_lineno = previous.lineno
+ if previous.is_multiline_string:
+ prev_lineno += previous.value.count('\n')
+
+ if (cur_lineno != prev_lineno or
+ (previous.is_pseudo_paren and previous.value != ')' and
+ cur_lineno != previous.previous_token.lineno)):
+ self.spaces_required_before = (
+ self.column - first_column + depth * style.Get('INDENT_WIDTH'))
+ return
+
+ cur_column = self.node.column
+ prev_column = previous.node.column
+ prev_len = len(previous.value)
+
+ if previous.is_pseudo_paren and previous.value == ')':
+ prev_column -= 1
+ prev_len = 0
+
+ if previous.is_multiline_string:
+ prev_len = len(previous.value.split('\n')[-1])
+ if '\n' in previous.value:
+ prev_column = 0 # Last line starts in column 0.
+ self.spaces_required_before = cur_column - (prev_column + prev_len)
+
+ def OpensScope(self):
+ return self.value in pytree_utils.OPENING_BRACKETS
+
+ def ClosesScope(self):
+ return self.value in pytree_utils.CLOSING_BRACKETS
+
+ def __repr__(self):
+ msg = 'FormatToken(name={0}, value={1}'.format(self.name, self.value)
+ msg += ', pseudo)' if self.is_pseudo_paren else ')'
+ return msg
+
+ @property
+ @py3compat.lru_cache()
+ def node_split_penalty(self):
+ """Split penalty attached to the pytree node of this token."""
+ return pytree_utils.GetNodeAnnotation(
+ self.node, pytree_utils.Annotation.SPLIT_PENALTY, default=0)
+
+ @property
+ def newlines(self):
+ """The number of newlines needed before this token."""
+ return pytree_utils.GetNodeAnnotation(self.node,
+ pytree_utils.Annotation.NEWLINES)
+
+ @property
+ def must_split(self):
+ """Return true if the token requires a split before it."""
+ return pytree_utils.GetNodeAnnotation(self.node,
+ pytree_utils.Annotation.MUST_SPLIT)
+
+ @property
+ def column(self):
+ """The original column number of the node in the source."""
+ return self.node.column
+
+ @property
+ def lineno(self):
+ """The original line number of the node in the source."""
+ return self.node.lineno
+
+ @property
+ @py3compat.lru_cache()
+ def subtypes(self):
+ """Extra type information for directing formatting."""
+ value = pytree_utils.GetNodeAnnotation(self.node,
+ pytree_utils.Annotation.SUBTYPE)
+ return [Subtype.NONE] if value is None else value
+
+ @property
+ @py3compat.lru_cache()
+ def is_binary_op(self):
+ """Token is a binary operator."""
+ return Subtype.BINARY_OPERATOR in self.subtypes
+
+ @property
+ @py3compat.lru_cache()
+ def name(self):
+ """A string representation of the node's name."""
+ return pytree_utils.NodeName(self.node)
+
+ @property
+ def is_comment(self):
+ return self.node.type == token.COMMENT
+
+ @property
+ def is_continuation(self):
+ return self.node.type == CONTINUATION
+
+ @property
+ @py3compat.lru_cache()
+ def is_keyword(self):
+ return keyword.iskeyword(self.value)
+
+ @property
+ @py3compat.lru_cache()
+ def is_name(self):
+ return self.node.type == token.NAME and not self.is_keyword
+
+ @property
+ def is_number(self):
+ return self.node.type == token.NUMBER
+
+ @property
+ def is_string(self):
+ return self.node.type == token.STRING
+
+ @property
+ @py3compat.lru_cache()
+ def is_multiline_string(self):
+ return (self.is_string and
+ re.match(r'^[uUbB]?[rR]?(?P<delim>"""|\'\'\').*(?P=delim)$',
+ self.value, re.DOTALL) is not None)
+
+ @property
+ @py3compat.lru_cache()
+ def is_docstring(self):
+ return self.is_multiline_string and not self.node.prev_sibling
+
+ @property
+ @py3compat.lru_cache()
+ def is_pseudo_paren(self):
+ return hasattr(self.node, 'is_pseudo') and self.node.is_pseudo
+
+ @property
+ def is_pylint_comment(self):
+ return self.is_comment and re.match(r'#.*\bpylint:\s*(disable|enable)=',
+ self.value)
diff --git a/tools/yapf/yapf/yapflib/line_joiner.py b/tools/yapf/yapf/yapflib/line_joiner.py
new file mode 100644
index 00000000..860fce78
--- /dev/null
+++ b/tools/yapf/yapf/yapflib/line_joiner.py
@@ -0,0 +1,109 @@
+# Copyright 2015-2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Join unwrapped lines together.
+
+Determine how many lines can be joined into one line. For instance, we could
+join these statements into one line:
+
+ if a == 42:
+ continue
+
+like this:
+
+ if a == 42: continue
+
+There are a few restrictions:
+
+ 1. The lines should have been joined in the original source.
+ 2. The joined lines must not go over the column boundary if placed on the same
+ line.
+ 3. They need to be very simple statements.
+
+Note: Because we don't allow the use of a semicolon to separate statements, it
+follows that there can only be at most two lines to join.
+"""
+
+from yapf.yapflib import style
+
+_CLASS_OR_FUNC = frozenset({'def', 'class'})
+
+
+def CanMergeMultipleLines(lines, last_was_merged=False):
+ """Determine if multiple lines can be joined into one.
+
+ Arguments:
+ lines: (list of UnwrappedLine) This is a splice of UnwrappedLines from the
+ full code base.
+ last_was_merged: (bool) The last line was merged.
+
+ Returns:
+ True if two consecutive lines can be joined together. In reality, this will
+ only happen if two consecutive lines can be joined, due to the style guide.
+ """
+ # The indentation amount for the starting line (number of spaces).
+ indent_amt = lines[0].depth * style.Get('INDENT_WIDTH')
+ if len(lines) == 1 or indent_amt > style.Get('COLUMN_LIMIT'):
+ return False
+
+ if (len(lines) >= 3 and lines[2].depth >= lines[1].depth and
+ lines[0].depth != lines[2].depth):
+ # If lines[2]'s depth is greater than or equal to line[1]'s depth, we're not
+ # looking at a single statement (e.g., if-then, while, etc.). A following
+ # line with the same depth as the first line isn't part of the lines we
+ # would want to combine.
+ return False # Don't merge more than two lines together.
+
+ if lines[0].first.value in _CLASS_OR_FUNC:
+ # Don't join lines onto the starting line of a class or function.
+ return False
+
+ limit = style.Get('COLUMN_LIMIT') - indent_amt
+ if lines[0].last.total_length < limit:
+ limit -= lines[0].last.total_length
+
+ if lines[0].first.value == 'if':
+ return _CanMergeLineIntoIfStatement(lines, limit)
+ if last_was_merged and lines[0].first.value in {'elif', 'else'}:
+ return _CanMergeLineIntoIfStatement(lines, limit)
+
+ # TODO(morbo): Other control statements?
+
+ return False
+
+
+def _CanMergeLineIntoIfStatement(lines, limit):
+ """Determine if we can merge a short if-then statement into one line.
+
+ Two lines of an if-then statement can be merged if they were that way in the
+ original source, fit on the line without going over the column limit, and are
+ considered "simple" statements --- typically statements like 'pass',
+ 'continue', and 'break'.
+
+ Arguments:
+ lines: (list of UnwrappedLine) The lines we are wanting to merge.
+ limit: (int) The amount of space remaining on the line.
+
+ Returns:
+ True if the lines can be merged, False otherwise.
+ """
+ if len(lines[1].tokens) == 1 and lines[1].last.is_multiline_string:
+ # This might be part of a multiline shebang.
+ return True
+ if lines[0].lineno != lines[1].lineno:
+ # Don't merge lines if the original lines weren't merged.
+ return False
+ if lines[1].last.total_length >= limit:
+ # Don't merge lines if the result goes over the column limit.
+ return False
+ return style.Get('JOIN_MULTIPLE_LINES')
diff --git a/tools/yapf/yapf/yapflib/py3compat.py b/tools/yapf/yapf/yapflib/py3compat.py
new file mode 100644
index 00000000..2886c384
--- /dev/null
+++ b/tools/yapf/yapf/yapflib/py3compat.py
@@ -0,0 +1,113 @@
+# Copyright 2015-2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Utilities for Python2 / Python3 compatibility."""
+
+import io
+import os
+import sys
+
+PY3 = sys.version_info[0] >= 3
+PY36 = sys.version_info[0] >= 3 and sys.version_info[1] >= 6
+
+if PY3:
+ StringIO = io.StringIO
+ BytesIO = io.BytesIO
+
+ import codecs
+
+ def open_with_encoding(filename, mode, encoding, newline=''): # pylint: disable=unused-argument
+ return codecs.open(filename, mode=mode, encoding=encoding)
+
+ import functools
+ lru_cache = functools.lru_cache
+
+ range = range
+ ifilter = filter
+ raw_input = input
+
+ import configparser
+
+ # Mappings from strings to booleans (such as '1' to True, 'false' to False,
+ # etc.)
+ CONFIGPARSER_BOOLEAN_STATES = configparser.ConfigParser.BOOLEAN_STATES
+else:
+ import __builtin__
+ import cStringIO
+ StringIO = BytesIO = cStringIO.StringIO
+
+ open_with_encoding = io.open
+
+ # Python 2.7 doesn't have a native LRU cache, so do nothing.
+ def lru_cache(maxsize=128, typed=False):
+
+ def fake_wrapper(user_function):
+ return user_function
+
+ return fake_wrapper
+
+ range = xrange
+
+ from itertools import ifilter
+ raw_input = raw_input
+
+ import ConfigParser as configparser
+ CONFIGPARSER_BOOLEAN_STATES = configparser.ConfigParser._boolean_states # pylint: disable=protected-access
+
+
+def EncodeAndWriteToStdout(s, encoding='utf-8'):
+ """Encode the given string and emit to stdout.
+
+ The string may contain non-ascii characters. This is a problem when stdout is
+ redirected, because then Python doesn't know the encoding and we may get a
+ UnicodeEncodeError.
+
+ Arguments:
+ s: (string) The string to encode.
+ encoding: (string) The encoding of the string.
+ """
+ if PY3:
+ sys.stdout.buffer.write(s.encode(encoding))
+ elif sys.platform == 'win32':
+ # On python 2 and Windows universal newline transformation will be in
+ # effect on stdout. Python 2 will not let us avoid the easily because
+ # it happens based on whether the file handle is opened in O_BINARY or
+ # O_TEXT state. However we can tell Windows itself to change the current
+ # mode, and python 2 will follow suit. However we must take care to change
+ # the mode on the actual external stdout not just the current sys.stdout
+ # which may have been monkey-patched inside the python environment.
+ import msvcrt # pylint: disable=g-import-not-at-top
+ if sys.__stdout__ is sys.stdout:
+ msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
+ sys.stdout.write(s.encode(encoding))
+ else:
+ sys.stdout.write(s.encode(encoding))
+
+
+if PY3:
+ unicode = str # pylint: disable=redefined-builtin,invalid-name
+else:
+
+ def unicode(s): # pylint: disable=invalid-name
+ """Force conversion of s to unicode."""
+ return __builtin__.unicode(s, 'utf-8')
+
+
+# In Python 3.2+, readfp is deprecated in favor of read_file, which doesn't
+# exist in Python 2 yet. To avoid deprecation warnings, subclass ConfigParser to
+# fix this - now read_file works across all Python versions we care about.
+class ConfigParser(configparser.ConfigParser):
+ if not PY3:
+
+ def read_file(self, fp, source=None):
+ self.readfp(fp, filename=source)
diff --git a/tools/yapf/yapf/yapflib/pytree_unwrapper.py b/tools/yapf/yapf/yapflib/pytree_unwrapper.py
new file mode 100644
index 00000000..c67c1c6e
--- /dev/null
+++ b/tools/yapf/yapf/yapflib/pytree_unwrapper.py
@@ -0,0 +1,376 @@
+# Copyright 2015-2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""PyTreeUnwrapper - produces a list of unwrapped lines from a pytree.
+
+[for a description of what an unwrapped line is, see unwrapped_line.py]
+
+This is a pytree visitor that goes over a parse tree and produces a list of
+UnwrappedLine containers from it, each with its own depth and containing all
+the tokens that could fit on the line if there were no maximal line-length
+limitations.
+
+Note: a precondition to running this visitor and obtaining correct results is
+for the tree to have its comments spliced in as nodes. Prefixes are ignored.
+
+For most uses, the convenience function UnwrapPyTree should be sufficient.
+"""
+
+# The word "token" is overloaded within this module, so for clarity rename
+# the imported pgen2.token module.
+from lib2to3 import pytree
+from lib2to3.pgen2 import token as grammar_token
+
+from yapf.yapflib import pytree_utils
+from yapf.yapflib import pytree_visitor
+from yapf.yapflib import split_penalty
+from yapf.yapflib import unwrapped_line
+
+
+def UnwrapPyTree(tree):
+ """Create and return a list of unwrapped lines from the given pytree.
+
+ Arguments:
+ tree: the top-level pytree node to unwrap.
+
+ Returns:
+ A list of UnwrappedLine objects.
+ """
+ unwrapper = PyTreeUnwrapper()
+ unwrapper.Visit(tree)
+ uwlines = unwrapper.GetUnwrappedLines()
+ uwlines.sort(key=lambda x: x.lineno)
+ return uwlines
+
+
+# Grammar tokens considered as whitespace for the purpose of unwrapping.
+_WHITESPACE_TOKENS = frozenset([
+ grammar_token.NEWLINE, grammar_token.DEDENT, grammar_token.INDENT,
+ grammar_token.ENDMARKER
+])
+
+
+class PyTreeUnwrapper(pytree_visitor.PyTreeVisitor):
+ """PyTreeUnwrapper - see file-level docstring for detailed description.
+
+ Note: since this implements PyTreeVisitor and node names in lib2to3 are
+ underscore_separated, the visiting methods of this class are named as
+ Visit_node_name. invalid-name pragmas are added to each such method to silence
+ a style warning. This is forced on us by the usage of lib2to3, and re-munging
+ method names to make them different from actual node names sounded like a
+ confusing and brittle affair that wasn't worth it for this small & controlled
+ deviation from the style guide.
+
+ To understand the connection between visitor methods in this class, some
+ familiarity with the Python grammar is required.
+ """
+
+ def __init__(self):
+ # A list of all unwrapped lines finished visiting so far.
+ self._unwrapped_lines = []
+
+ # Builds up a "current" unwrapped line while visiting pytree nodes. Some
+ # nodes will finish a line and start a new one.
+ self._cur_unwrapped_line = unwrapped_line.UnwrappedLine(0)
+
+ # Current indentation depth.
+ self._cur_depth = 0
+
+ def GetUnwrappedLines(self):
+ """Fetch the result of the tree walk.
+
+ Note: only call this after visiting the whole tree.
+
+ Returns:
+ A list of UnwrappedLine objects.
+ """
+ # Make sure the last line that was being populated is flushed.
+ self._StartNewLine()
+ return self._unwrapped_lines
+
+ def _StartNewLine(self):
+ """Finish current line and start a new one.
+
+ Place the currently accumulated line into the _unwrapped_lines list and
+ start a new one.
+ """
+ if self._cur_unwrapped_line.tokens:
+ self._unwrapped_lines.append(self._cur_unwrapped_line)
+ _MatchBrackets(self._cur_unwrapped_line)
+ _AdjustSplitPenalty(self._cur_unwrapped_line)
+ self._cur_unwrapped_line = unwrapped_line.UnwrappedLine(self._cur_depth)
+
+ _STMT_TYPES = frozenset({
+ 'if_stmt',
+ 'while_stmt',
+ 'for_stmt',
+ 'try_stmt',
+ 'expect_clause',
+ 'with_stmt',
+ 'funcdef',
+ 'classdef',
+ })
+
+ # pylint: disable=invalid-name,missing-docstring
+ def Visit_simple_stmt(self, node):
+ # A 'simple_stmt' conveniently represents a non-compound Python statement,
+ # i.e. a statement that does not contain other statements.
+
+ # When compound nodes have a single statement as their suite, the parser
+ # can leave it in the tree directly without creating a suite. But we have
+ # to increase depth in these cases as well. However, don't increase the
+ # depth of we have a simple_stmt that's a comment node. This represents a
+ # standalone comment and in the case of it coming directly after the
+ # funcdef, it is a "top" comment for the whole function.
+ # TODO(eliben): add more relevant compound statements here.
+ single_stmt_suite = (node.parent and
+ pytree_utils.NodeName(node.parent) in self._STMT_TYPES)
+ is_comment_stmt = pytree_utils.IsCommentStatement(node)
+ if single_stmt_suite and not is_comment_stmt:
+ self._cur_depth += 1
+ self._StartNewLine()
+ self.DefaultNodeVisit(node)
+ if single_stmt_suite and not is_comment_stmt:
+ self._cur_depth -= 1
+
+ def _VisitCompoundStatement(self, node, substatement_names):
+ """Helper for visiting compound statements.
+
+ Python compound statements serve as containers for other statements. Thus,
+ when we encounter a new compound statement we start a new unwrapped line.
+
+ Arguments:
+ node: the node to visit.
+ substatement_names: set of node names. A compound statement will be
+ recognized as a NAME node with a name in this set.
+ """
+ for child in node.children:
+ # A pytree is structured in such a way that a single 'if_stmt' node will
+ # contain all the 'if', 'elif' and 'else' nodes as children (similar
+ # structure applies to 'while' statements, 'try' blocks, etc). Therefore,
+ # we visit all children here and create a new line before the requested
+ # set of nodes.
+ if (child.type == grammar_token.NAME and
+ child.value in substatement_names):
+ self._StartNewLine()
+ self.Visit(child)
+
+ _IF_STMT_ELEMS = frozenset({'if', 'else', 'elif'})
+
+ def Visit_if_stmt(self, node): # pylint: disable=invalid-name
+ self._VisitCompoundStatement(node, self._IF_STMT_ELEMS)
+
+ _WHILE_STMT_ELEMS = frozenset({'while', 'else'})
+
+ def Visit_while_stmt(self, node): # pylint: disable=invalid-name
+ self._VisitCompoundStatement(node, self._WHILE_STMT_ELEMS)
+
+ _FOR_STMT_ELEMS = frozenset({'for', 'else'})
+
+ def Visit_for_stmt(self, node): # pylint: disable=invalid-name
+ self._VisitCompoundStatement(node, self._FOR_STMT_ELEMS)
+
+ _TRY_STMT_ELEMS = frozenset({'try', 'except', 'else', 'finally'})
+
+ def Visit_try_stmt(self, node): # pylint: disable=invalid-name
+ self._VisitCompoundStatement(node, self._TRY_STMT_ELEMS)
+
+ _EXCEPT_STMT_ELEMS = frozenset({'except'})
+
+ def Visit_except_clause(self, node): # pylint: disable=invalid-name
+ self._VisitCompoundStatement(node, self._EXCEPT_STMT_ELEMS)
+
+ _FUNC_DEF_ELEMS = frozenset({'def'})
+
+ def Visit_funcdef(self, node): # pylint: disable=invalid-name
+ self._VisitCompoundStatement(node, self._FUNC_DEF_ELEMS)
+
+ def Visit_async_funcdef(self, node): # pylint: disable=invalid-name
+ self._StartNewLine()
+ index = 0
+ for child in node.children:
+ index += 1
+ self.Visit(child)
+ if pytree_utils.NodeName(child) == 'ASYNC':
+ break
+ for child in node.children[index].children:
+ self.Visit(child)
+
+ _CLASS_DEF_ELEMS = frozenset({'class'})
+
+ def Visit_classdef(self, node): # pylint: disable=invalid-name
+ self._VisitCompoundStatement(node, self._CLASS_DEF_ELEMS)
+
+ def Visit_async_stmt(self, node): # pylint: disable=invalid-name
+ self._StartNewLine()
+ index = 0
+ for child in node.children:
+ index += 1
+ self.Visit(child)
+ if pytree_utils.NodeName(child) == 'ASYNC':
+ break
+ for child in node.children[index].children:
+ self.Visit(child)
+
+ def Visit_decorators(self, node): # pylint: disable=invalid-name
+ for child in node.children:
+ self._StartNewLine()
+ self.Visit(child)
+
+ def Visit_decorated(self, node): # pylint: disable=invalid-name
+ for child in node.children:
+ self._StartNewLine()
+ self.Visit(child)
+
+ _WITH_STMT_ELEMS = frozenset({'with'})
+
+ def Visit_with_stmt(self, node): # pylint: disable=invalid-name
+ self._VisitCompoundStatement(node, self._WITH_STMT_ELEMS)
+
+ def Visit_suite(self, node): # pylint: disable=invalid-name
+ # A 'suite' starts a new indentation level in Python.
+ self._cur_depth += 1
+ self._StartNewLine()
+ self.DefaultNodeVisit(node)
+ self._cur_depth -= 1
+
+ def Visit_listmaker(self, node): # pylint: disable=invalid-name
+ _DetermineMustSplitAnnotation(node)
+ self.DefaultNodeVisit(node)
+
+ def Visit_dictsetmaker(self, node): # pylint: disable=invalid-name
+ _DetermineMustSplitAnnotation(node)
+ self.DefaultNodeVisit(node)
+
+ def Visit_import_as_names(self, node): # pylint: disable=invalid-name
+ if node.prev_sibling.value == '(':
+ _DetermineMustSplitAnnotation(node)
+ self.DefaultNodeVisit(node)
+
+ def Visit_testlist_gexp(self, node): # pylint: disable=invalid-name
+ if _ContainsComments(node):
+ _DetermineMustSplitAnnotation(node)
+ self.DefaultNodeVisit(node)
+
+ def Visit_arglist(self, node): # pylint: disable=invalid-name
+ _DetermineMustSplitAnnotation(node)
+ self.DefaultNodeVisit(node)
+
+ def Visit_typedargslist(self, node): # pylint: disable=invalid-name
+ _DetermineMustSplitAnnotation(node)
+ self.DefaultNodeVisit(node)
+
+ def DefaultLeafVisit(self, leaf):
+ """Default visitor for tree leaves.
+
+ A tree leaf is always just gets appended to the current unwrapped line.
+
+ Arguments:
+ leaf: the leaf to visit.
+ """
+ if leaf.type in _WHITESPACE_TOKENS:
+ self._StartNewLine()
+ elif leaf.type != grammar_token.COMMENT or leaf.value.strip():
+ if leaf.value == ';':
+ # Split up multiple statements on one line.
+ self._StartNewLine()
+ else:
+ # Add non-whitespace tokens and comments that aren't empty.
+ self._cur_unwrapped_line.AppendNode(leaf)
+
+
+_BRACKET_MATCH = {')': '(', '}': '{', ']': '['}
+
+
+def _MatchBrackets(uwline):
+ """Visit the node and match the brackets.
+
+ For every open bracket ('[', '{', or '('), find the associated closing bracket
+ and "match" them up. I.e., save in the token a pointer to its associated open
+ or close bracket.
+
+ Arguments:
+ uwline: (UnwrappedLine) An unwrapped line.
+ """
+ bracket_stack = []
+ for token in uwline.tokens:
+ if token.value in pytree_utils.OPENING_BRACKETS:
+ bracket_stack.append(token)
+ elif token.value in pytree_utils.CLOSING_BRACKETS:
+ bracket_stack[-1].matching_bracket = token
+ token.matching_bracket = bracket_stack[-1]
+ bracket_stack.pop()
+
+
+def _AdjustSplitPenalty(uwline):
+ """Visit the node and adjust the split penalties if needed.
+
+ A token shouldn't be split if it's not within a bracket pair. Mark any token
+ that's not within a bracket pair as "unbreakable".
+
+ Arguments:
+ uwline: (UnwrappedLine) An unwrapped line.
+ """
+ bracket_level = 0
+ for index, token in enumerate(uwline.tokens):
+ if index and not bracket_level:
+ pytree_utils.SetNodeAnnotation(token.node,
+ pytree_utils.Annotation.SPLIT_PENALTY,
+ split_penalty.UNBREAKABLE)
+ if token.value in pytree_utils.OPENING_BRACKETS:
+ bracket_level += 1
+ elif token.value in pytree_utils.CLOSING_BRACKETS:
+ bracket_level -= 1
+
+
+def _DetermineMustSplitAnnotation(node):
+ """Enforce a split in the list if the list ends with a comma."""
+ if not _ContainsComments(node):
+ if (not isinstance(node.children[-1], pytree.Leaf) or
+ node.children[-1].value != ','):
+ return
+ num_children = len(node.children)
+ index = 0
+ _SetMustSplitOnFirstLeaf(node.children[0])
+ while index < num_children - 1:
+ child = node.children[index]
+ if isinstance(child, pytree.Leaf) and child.value == ',':
+ next_child = node.children[index + 1]
+ if next_child.type == grammar_token.COMMENT:
+ index += 1
+ if index >= num_children - 1:
+ break
+ _SetMustSplitOnFirstLeaf(node.children[index + 1])
+ index += 1
+
+
+def _ContainsComments(node):
+ """Return True if the list has a comment in it."""
+ if isinstance(node, pytree.Leaf):
+ return node.type == grammar_token.COMMENT
+ for child in node.children:
+ if _ContainsComments(child):
+ return True
+ return False
+
+
+def _SetMustSplitOnFirstLeaf(node):
+ """Set the "must split" annotation on the first leaf node."""
+
+ def FindFirstLeaf(node):
+ if isinstance(node, pytree.Leaf):
+ return node
+ return FindFirstLeaf(node.children[0])
+
+ pytree_utils.SetNodeAnnotation(
+ FindFirstLeaf(node), pytree_utils.Annotation.MUST_SPLIT, True)
diff --git a/tools/yapf/yapf/yapflib/pytree_utils.py b/tools/yapf/yapf/yapflib/pytree_utils.py
new file mode 100644
index 00000000..60fd955f
--- /dev/null
+++ b/tools/yapf/yapf/yapflib/pytree_utils.py
@@ -0,0 +1,297 @@
+# Copyright 2015-2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""pytree-related utilities.
+
+This module collects various utilities related to the parse trees produced by
+the lib2to3 library.
+
+ NodeName(): produces a string name for pytree nodes.
+ ParseCodeToTree(): convenience wrapper around lib2to3 interfaces to parse
+ a given string with code to a pytree.
+ InsertNodeBefore(): insert a node before another in a pytree.
+ InsertNodeAfter(): insert a node after another in a pytree.
+ {Get,Set}NodeAnnotation(): manage custom annotations on pytree nodes.
+"""
+
+import ast
+from lib2to3 import pygram
+from lib2to3 import pytree
+from lib2to3.pgen2 import driver
+from lib2to3.pgen2 import parse
+from lib2to3.pgen2 import token
+
+# TODO(eliben): We may want to get rid of this filtering at some point once we
+# have a better understanding of what information we need from the tree. Then,
+# these tokens may be filtered out from the tree before the tree gets to the
+# unwrapper.
+NONSEMANTIC_TOKENS = frozenset(['DEDENT', 'INDENT', 'NEWLINE', 'ENDMARKER'])
+
+OPENING_BRACKETS = frozenset({'(', '[', '{'})
+CLOSING_BRACKETS = frozenset({')', ']', '}'})
+
+
+class Annotation(object):
+ """Annotation names associated with pytrees."""
+ CHILD_INDENT = 'child_indent'
+ NEWLINES = 'newlines'
+ MUST_SPLIT = 'must_split'
+ SPLIT_PENALTY = 'split_penalty'
+ SUBTYPE = 'subtype'
+
+
+def NodeName(node):
+ """Produce a string name for a given node.
+
+ For a Leaf this is the token name, and for a Node this is the type.
+
+ Arguments:
+ node: a tree node
+
+ Returns:
+ Name as a string.
+ """
+ # Nodes with values < 256 are tokens. Values >= 256 are grammar symbols.
+ if node.type < 256:
+ return token.tok_name[node.type]
+ else:
+ return pygram.python_grammar.number2symbol[node.type]
+
+
+# lib2to3 thoughtfully provides pygram.python_grammar_no_print_statement for
+# parsing Python 3 code that wouldn't parse otherwise (when 'print' is used in a
+# context where a keyword is disallowed).
+# It forgets to do the same for 'exec' though. Luckily, Python is amenable to
+# monkey-patching.
+_GRAMMAR_FOR_PY3 = pygram.python_grammar_no_print_statement.copy()
+del _GRAMMAR_FOR_PY3.keywords['exec']
+
+_GRAMMAR_FOR_PY2 = pygram.python_grammar.copy()
+del _GRAMMAR_FOR_PY2.keywords['nonlocal']
+
+
+def ParseCodeToTree(code):
+ """Parse the given code to a lib2to3 pytree.
+
+ Arguments:
+ code: a string with the code to parse.
+
+ Raises:
+ SyntaxError if the code is invalid syntax.
+ parse.ParseError if some other parsing failure.
+
+ Returns:
+ The root node of the parsed tree.
+ """
+ # This function is tiny, but the incantation for invoking the parser correctly
+ # is sufficiently magical to be worth abstracting away.
+ try:
+ # Try to parse using a Python 3 grammar, which is more permissive (print and
+ # exec are not keywords).
+ parser_driver = driver.Driver(_GRAMMAR_FOR_PY3, convert=pytree.convert)
+ tree = parser_driver.parse_string(code, debug=False)
+ except parse.ParseError:
+ # Now try to parse using a Python 2 grammar; If this fails, then
+ # there's something else wrong with the code.
+ try:
+ parser_driver = driver.Driver(_GRAMMAR_FOR_PY2, convert=pytree.convert)
+ tree = parser_driver.parse_string(code, debug=False)
+ except parse.ParseError:
+ # Raise a syntax error if the code is invalid python syntax.
+ try:
+ ast.parse(code)
+ except SyntaxError as e:
+ raise e
+ else:
+ raise
+ return _WrapEndMarker(tree)
+
+
+def _WrapEndMarker(tree):
+ """Wrap a single ENDMARKER token in a "file_input" node.
+
+ Arguments:
+ tree: (pytree.Node) The root node of the parsed tree.
+
+ Returns:
+ The root node of the parsed tree. If the tree is a single ENDMARKER node,
+ then that node is wrapped in a "file_input" node. That will ensure we don't
+ skip comments attached to that node.
+ """
+ if isinstance(tree, pytree.Leaf) and tree.type == token.ENDMARKER:
+ return pytree.Node(pygram.python_symbols.file_input, [tree])
+ return tree
+
+
+def InsertNodesBefore(new_nodes, target):
+ """Insert new_nodes before the given target location in the tree.
+
+ Arguments:
+ new_nodes: a sequence of new nodes to insert (the nodes should not be in the
+ tree).
+ target: the target node before which the new node node will be inserted.
+
+ Raises:
+ RuntimeError: if the tree is corrupted, or the insertion would corrupt it.
+ """
+ for node in new_nodes:
+ _InsertNodeAt(node, target, after=False)
+
+
+def InsertNodesAfter(new_nodes, target):
+ """Insert new_nodes after the given target location in the tree.
+
+ Arguments:
+ new_nodes: a sequence of new nodes to insert (the nodes should not be in the
+ tree).
+ target: the target node after which the new node node will be inserted.
+
+ Raises:
+ RuntimeError: if the tree is corrupted, or the insertion would corrupt it.
+ """
+ for node in reversed(new_nodes):
+ _InsertNodeAt(node, target, after=True)
+
+
+def _InsertNodeAt(new_node, target, after=False):
+ """Underlying implementation for node insertion.
+
+ Arguments:
+ new_node: a new node to insert (this node should not be in the tree).
+ target: the target node.
+ after: if True, new_node is inserted after target. Otherwise, it's inserted
+ before target.
+
+ Returns:
+ nothing
+
+ Raises:
+ RuntimeError: if the tree is corrupted, or the insertion would corrupt it.
+ """
+
+ # Protect against attempts to insert nodes which already belong to some tree.
+ if new_node.parent is not None:
+ raise RuntimeError('inserting node which already has a parent',
+ (new_node, new_node.parent))
+
+ # The code here is based on pytree.Base.next_sibling
+ parent_of_target = target.parent
+ if parent_of_target is None:
+ raise RuntimeError('expected target node to have a parent', (target,))
+
+ for i, child in enumerate(parent_of_target.children):
+ if child is target:
+ insertion_index = i + 1 if after else i
+ parent_of_target.insert_child(insertion_index, new_node)
+ return
+
+ raise RuntimeError('unable to find insertion point for target node',
+ (target,))
+
+
+# The following constant and functions implement a simple custom annotation
+# mechanism for pytree nodes. We attach new attributes to nodes. Each attribute
+# is prefixed with _NODE_ANNOTATION_PREFIX. These annotations should only be
+# managed through GetNodeAnnotation and SetNodeAnnotation.
+_NODE_ANNOTATION_PREFIX = '_yapf_annotation_'
+
+
+def GetNodeAnnotation(node, annotation, default=None):
+ """Get annotation value from a node.
+
+ Arguments:
+ node: the node.
+ annotation: annotation name - a string.
+ default: the default value to return if there's no annotation.
+
+ Returns:
+ Value of the annotation in the given node. If the node doesn't have this
+ particular annotation name yet, returns default.
+ """
+ return getattr(node, _NODE_ANNOTATION_PREFIX + annotation, default)
+
+
+def SetNodeAnnotation(node, annotation, value):
+ """Set annotation value on a node.
+
+ Arguments:
+ node: the node.
+ annotation: annotation name - a string.
+ value: annotation value to set.
+ """
+ setattr(node, _NODE_ANNOTATION_PREFIX + annotation, value)
+
+
+def AppendNodeAnnotation(node, annotation, value):
+ """Appends an annotation value to a list of annotations on the node.
+
+ Arguments:
+ node: the node.
+ annotation: annotation name - a string.
+ value: annotation value to set.
+ """
+ attr = GetNodeAnnotation(node, annotation, set())
+ attr.add(value)
+ SetNodeAnnotation(node, annotation, attr)
+
+
+def RemoveSubtypeAnnotation(node, value):
+ """Removes an annotation value from the subtype annotations on the node.
+
+ Arguments:
+ node: the node.
+ value: annotation value to remove.
+ """
+ attr = GetNodeAnnotation(node, Annotation.SUBTYPE)
+ if attr and value in attr:
+ attr.remove(value)
+ SetNodeAnnotation(node, Annotation.SUBTYPE, attr)
+
+
+def DumpNodeToString(node):
+ """Dump a string representation of the given node. For debugging.
+
+ Arguments:
+ node: the node.
+
+ Returns:
+ The string representation.
+ """
+ if isinstance(node, pytree.Leaf):
+ fmt = '{name}({value}) [lineno={lineno}, column={column}, prefix={prefix}]'
+ return fmt.format(
+ name=NodeName(node),
+ value=_PytreeNodeRepr(node),
+ lineno=node.lineno,
+ column=node.column,
+ prefix=repr(node.prefix))
+ else:
+ fmt = '{node} [{len} children] [child_indent="{indent}"]'
+ return fmt.format(
+ node=NodeName(node),
+ len=len(node.children),
+ indent=GetNodeAnnotation(node, Annotation.CHILD_INDENT))
+
+
+def _PytreeNodeRepr(node):
+ """Like pytree.Node.__repr__, but names instead of numbers for tokens."""
+ if isinstance(node, pytree.Node):
+ return '%s(%s, %r)' % (node.__class__.__name__, NodeName(node),
+ [_PytreeNodeRepr(c) for c in node.children])
+ if isinstance(node, pytree.Leaf):
+ return '%s(%s, %r)' % (node.__class__.__name__, NodeName(node), node.value)
+
+
+def IsCommentStatement(node):
+ return (NodeName(node) == 'simple_stmt' and
+ node.children[0].type == token.COMMENT)
diff --git a/tools/yapf/yapf/yapflib/pytree_visitor.py b/tools/yapf/yapf/yapflib/pytree_visitor.py
new file mode 100644
index 00000000..3f1ab0b7
--- /dev/null
+++ b/tools/yapf/yapf/yapflib/pytree_visitor.py
@@ -0,0 +1,135 @@
+# Copyright 2015-2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Generic visitor pattern for pytrees.
+
+The lib2to3 parser produces a "pytree" - syntax tree consisting of Node
+and Leaf types. This module implements a visitor pattern for such trees.
+
+It also exports a basic "dumping" visitor that dumps a textual representation of
+a pytree into a stream.
+
+ PyTreeVisitor: a generic visitor pattern fo pytrees.
+ PyTreeDumper: a configurable "dumper" for displaying pytrees.
+ DumpPyTree(): a convenience function to dump a pytree.
+"""
+
+import sys
+
+from lib2to3 import pytree
+
+from yapf.yapflib import pytree_utils
+
+
+class PyTreeVisitor(object):
+ """Visitor pattern for pytree trees.
+
+ Methods named Visit_XXX will be invoked when a node with type XXX is
+ encountered in the tree. The type is either a token type (for Leaf nodes) or
+ grammar symbols (for Node nodes). The return value of Visit_XXX methods is
+ ignored by the visitor.
+
+ Visitors can modify node contents but must not change the tree structure
+ (e.g. add/remove children and move nodes around).
+
+ This is a very common visitor pattern in Python code; it's also used in the
+ Python standard library ast module for providing AST visitors.
+
+ Note: this makes names that aren't style conformant, so such visitor methods
+ need to be marked with # pylint: disable=invalid-name We don't have a choice
+ here, because lib2to3 nodes have under_separated names.
+
+ For more complex behavior, the visit, DefaultNodeVisit and DefaultLeafVisit
+ methods can be overridden. Don't forget to invoke DefaultNodeVisit for nodes
+ that may have children - otherwise the children will not be visited.
+ """
+
+ def Visit(self, node):
+ """Visit a node."""
+ method = 'Visit_{0}'.format(pytree_utils.NodeName(node))
+ if hasattr(self, method):
+ # Found a specific visitor for this node
+ getattr(self, method)(node)
+ else:
+ if isinstance(node, pytree.Leaf):
+ self.DefaultLeafVisit(node)
+ else:
+ self.DefaultNodeVisit(node)
+
+ def DefaultNodeVisit(self, node):
+ """Default visitor for Node: visits the node's children depth-first.
+
+ This method is invoked when no specific visitor for the node is defined.
+
+ Arguments:
+ node: the node to visit
+ """
+ for child in node.children:
+ self.Visit(child)
+
+ def DefaultLeafVisit(self, leaf):
+ """Default visitor for Leaf: no-op.
+
+ This method is invoked when no specific visitor for the leaf is defined.
+
+ Arguments:
+ leaf: the leaf to visit
+ """
+ pass
+
+
+def DumpPyTree(tree, target_stream=sys.stdout):
+ """Convenience function for dumping a given pytree.
+
+ This function presents a very minimal interface. For more configurability (for
+ example, controlling how specific node types are displayed), use PyTreeDumper
+ directly.
+
+ Arguments:
+ tree: the tree to dump.
+ target_stream: the stream to dump the tree to. A file-like object. By
+ default will dump into stdout.
+ """
+ dumper = PyTreeDumper(target_stream)
+ dumper.Visit(tree)
+
+
+class PyTreeDumper(PyTreeVisitor):
+ """Visitor that dumps the tree to a stream.
+
+ Implements the PyTreeVisitor interface.
+ """
+
+ def __init__(self, target_stream=sys.stdout):
+ """Create a tree dumper.
+
+ Arguments:
+ target_stream: the stream to dump the tree to. A file-like object. By
+ default will dump into stdout.
+ """
+ self._target_stream = target_stream
+ self._current_indent = 0
+
+ def _DumpString(self, s):
+ self._target_stream.write('{0}{1}\n'.format(' ' * self._current_indent, s))
+
+ def DefaultNodeVisit(self, node):
+ # Dump information about the current node, and then use the generic
+ # DefaultNodeVisit visitor to dump each of its children.
+ self._DumpString(pytree_utils.DumpNodeToString(node))
+ self._current_indent += 2
+ super(PyTreeDumper, self).DefaultNodeVisit(node)
+ self._current_indent -= 2
+
+ def DefaultLeafVisit(self, leaf):
+ self._DumpString(pytree_utils.DumpNodeToString(leaf))
diff --git a/tools/yapf/yapf/yapflib/reformatter.py b/tools/yapf/yapf/yapflib/reformatter.py
new file mode 100644
index 00000000..fd8f3178
--- /dev/null
+++ b/tools/yapf/yapf/yapflib/reformatter.py
@@ -0,0 +1,588 @@
+# Copyright 2015-2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Decide what the format for the code should be.
+
+The `unwrapped_line.UnwrappedLine`s are now ready to be formatted.
+UnwrappedLines that can be merged together are. The best formatting is returned
+as a string.
+
+ Reformat(): the main function exported by this module.
+"""
+
+from __future__ import unicode_literals
+import collections
+import heapq
+import re
+
+from lib2to3 import pytree
+from lib2to3.pgen2 import token
+
+from yapf.yapflib import format_decision_state
+from yapf.yapflib import format_token
+from yapf.yapflib import line_joiner
+from yapf.yapflib import pytree_utils
+from yapf.yapflib import style
+from yapf.yapflib import verifier
+
+
+def Reformat(uwlines, verify=False):
+ """Reformat the unwrapped lines.
+
+ Arguments:
+ uwlines: (list of unwrapped_line.UnwrappedLine) Lines we want to format.
+ verify: (bool) True if reformatted code should be verified for syntax.
+
+ Returns:
+ A string representing the reformatted code.
+ """
+ final_lines = []
+ prev_uwline = None # The previous line.
+ indent_width = style.Get('INDENT_WIDTH')
+
+ for uwline in _SingleOrMergedLines(uwlines):
+ first_token = uwline.first
+ _FormatFirstToken(first_token, uwline.depth, prev_uwline, final_lines)
+
+ indent_amt = indent_width * uwline.depth
+ state = format_decision_state.FormatDecisionState(uwline, indent_amt)
+ state.MoveStateToNextToken()
+
+ if not uwline.disable:
+ if uwline.first.is_comment:
+ uwline.first.node.value = uwline.first.node.value.rstrip()
+ elif uwline.last.is_comment:
+ uwline.last.node.value = uwline.last.node.value.rstrip()
+ if prev_uwline and prev_uwline.disable:
+ # Keep the vertical spacing between a disabled and enabled formatting
+ # region.
+ _RetainVerticalSpacingBetweenTokens(uwline.first, prev_uwline.last)
+ if any(tok.is_comment for tok in uwline.tokens):
+ _RetainVerticalSpacingBeforeComments(uwline)
+
+ if (_LineContainsI18n(uwline) or uwline.disable or
+ _LineHasContinuationMarkers(uwline)):
+ _RetainHorizontalSpacing(uwline)
+ _RetainVerticalSpacing(uwline, prev_uwline)
+ _EmitLineUnformatted(state)
+ elif _CanPlaceOnSingleLine(uwline) and not any(tok.must_split
+ for tok in uwline.tokens):
+ # The unwrapped line fits on one line.
+ while state.next_token:
+ state.AddTokenToState(newline=False, dry_run=False)
+ else:
+ if not _AnalyzeSolutionSpace(state):
+ # Failsafe mode. If there isn't a solution to the line, then just emit
+ # it as is.
+ state = format_decision_state.FormatDecisionState(uwline, indent_amt)
+ state.MoveStateToNextToken()
+ _RetainHorizontalSpacing(uwline)
+ _RetainVerticalSpacing(uwline, prev_uwline)
+ _EmitLineUnformatted(state)
+
+ final_lines.append(uwline)
+ prev_uwline = uwline
+ return _FormatFinalLines(final_lines, verify)
+
+
+def _RetainHorizontalSpacing(uwline):
+ """Retain all horizontal spacing between tokens."""
+ for tok in uwline.tokens:
+ tok.RetainHorizontalSpacing(uwline.first.column, uwline.depth)
+
+
+def _RetainVerticalSpacing(cur_uwline, prev_uwline):
+ prev_tok = None
+ if prev_uwline is not None:
+ prev_tok = prev_uwline.last
+ for cur_tok in cur_uwline.tokens:
+ _RetainVerticalSpacingBetweenTokens(cur_tok, prev_tok)
+ prev_tok = cur_tok
+
+
+def _RetainVerticalSpacingBetweenTokens(cur_tok, prev_tok):
+ """Retain vertical spacing between two tokens."""
+ if prev_tok is None:
+ return
+
+ if prev_tok.is_string:
+ prev_lineno = prev_tok.lineno + prev_tok.value.count('\n')
+ elif prev_tok.is_pseudo_paren:
+ if not prev_tok.previous_token.is_multiline_string:
+ prev_lineno = prev_tok.previous_token.lineno
+ else:
+ prev_lineno = prev_tok.lineno
+ else:
+ prev_lineno = prev_tok.lineno
+
+ if cur_tok.is_comment:
+ cur_lineno = cur_tok.lineno - cur_tok.value.count('\n')
+ else:
+ cur_lineno = cur_tok.lineno
+
+ cur_tok.AdjustNewlinesBefore(cur_lineno - prev_lineno)
+
+
+def _RetainVerticalSpacingBeforeComments(uwline):
+ """Retain vertical spacing before comments."""
+ prev_token = None
+ for tok in uwline.tokens:
+ if tok.is_comment and prev_token:
+ if tok.lineno - tok.value.count('\n') - prev_token.lineno > 1:
+ tok.AdjustNewlinesBefore(ONE_BLANK_LINE)
+
+ prev_token = tok
+
+
+def _EmitLineUnformatted(state):
+ """Emit the line without formatting.
+
+ The line contains code that if reformatted would break a non-syntactic
+ convention. E.g., i18n comments and function calls are tightly bound by
+ convention. Instead, we calculate when / if a newline should occur and honor
+ that. But otherwise the code emitted will be the same as the original code.
+
+ Arguments:
+ state: (format_decision_state.FormatDecisionState) The format decision
+ state.
+ """
+ prev_lineno = None
+ while state.next_token:
+ previous_token = state.next_token.previous_token
+ previous_lineno = previous_token.lineno
+
+ if previous_token.is_multiline_string:
+ previous_lineno += previous_token.value.count('\n')
+
+ if previous_token.is_continuation:
+ newline = False
+ else:
+ newline = (prev_lineno is not None and
+ state.next_token.lineno > previous_lineno)
+
+ prev_lineno = state.next_token.lineno
+ state.AddTokenToState(newline=newline, dry_run=False)
+
+
+def _LineContainsI18n(uwline):
+ """Return true if there are i18n comments or function calls in the line.
+
+ I18n comments and pseudo-function calls are closely related. They cannot
+ be moved apart without breaking i18n.
+
+ Arguments:
+ uwline: (unwrapped_line.UnwrappedLine) The line currently being formatted.
+
+ Returns:
+ True if the line contains i18n comments or function calls. False otherwise.
+ """
+ if style.Get('I18N_COMMENT'):
+ for tok in uwline.tokens:
+ if tok.is_comment and re.match(style.Get('I18N_COMMENT'), tok.value):
+ # Contains an i18n comment.
+ return True
+
+ if style.Get('I18N_FUNCTION_CALL'):
+ length = len(uwline.tokens)
+ index = 0
+ while index < length - 1:
+ if (uwline.tokens[index + 1].value == '(' and
+ uwline.tokens[index].value in style.Get('I18N_FUNCTION_CALL')):
+ return True
+ index += 1
+
+ return False
+
+
+def _LineHasContinuationMarkers(uwline):
+ """Return true if the line has continuation markers in it."""
+ return any(tok.is_continuation for tok in uwline.tokens)
+
+
+def _CanPlaceOnSingleLine(uwline):
+ """Determine if the unwrapped line can go on a single line.
+
+ Arguments:
+ uwline: (unwrapped_line.UnwrappedLine) The line currently being formatted.
+
+ Returns:
+ True if the line can or should be added to a single line. False otherwise.
+ """
+ indent_amt = style.Get('INDENT_WIDTH') * uwline.depth
+ last = uwline.last
+ last_index = -1
+ if last.is_pylint_comment:
+ last = last.previous_token
+ last_index = -2
+ if last is None:
+ return True
+ return (last.total_length + indent_amt <= style.Get('COLUMN_LIMIT') and
+ not any(tok.is_comment for tok in uwline.tokens[:last_index]))
+
+
+def _FormatFinalLines(final_lines, verify):
+ """Compose the final output from the finalized lines."""
+ formatted_code = []
+ for line in final_lines:
+ formatted_line = []
+ for tok in line.tokens:
+ if not tok.is_pseudo_paren:
+ formatted_line.append(tok.whitespace_prefix)
+ formatted_line.append(tok.value)
+ else:
+ if (not tok.next_token.whitespace_prefix.startswith('\n') and
+ not tok.next_token.whitespace_prefix.startswith(' ')):
+ if (tok.previous_token.value == ':' or
+ tok.next_token.value not in ',}])'):
+ formatted_line.append(' ')
+
+ formatted_code.append(''.join(formatted_line))
+ if verify:
+ verifier.VerifyCode(formatted_code[-1])
+
+ return ''.join(formatted_code) + '\n'
+
+
+class _StateNode(object):
+ """An edge in the solution space from 'previous.state' to 'state'.
+
+ Attributes:
+ state: (format_decision_state.FormatDecisionState) The format decision state
+ for this node.
+ newline: If True, then on the edge from 'previous.state' to 'state' a
+ newline is inserted.
+ previous: (_StateNode) The previous state node in the graph.
+ """
+
+ # TODO(morbo): Add a '__cmp__' method.
+
+ def __init__(self, state, newline, previous):
+ self.state = state.Clone()
+ self.newline = newline
+ self.previous = previous
+
+ def __repr__(self): # pragma: no cover
+ return 'StateNode(state=[\n{0}\n], newline={1})'.format(
+ self.state, self.newline)
+
+
+# A tuple of (penalty, count) that is used to prioritize the BFS. In case of
+# equal penalties, we prefer states that were inserted first. During state
+# generation, we make sure that we insert states first that break the line as
+# late as possible.
+_OrderedPenalty = collections.namedtuple('OrderedPenalty', ['penalty', 'count'])
+
+# An item in the prioritized BFS search queue. The 'StateNode's 'state' has
+# the given '_OrderedPenalty'.
+_QueueItem = collections.namedtuple('QueueItem',
+ ['ordered_penalty', 'state_node'])
+
+
+def _AnalyzeSolutionSpace(initial_state):
+ """Analyze the entire solution space starting from initial_state.
+
+ This implements a variant of Dijkstra's algorithm on the graph that spans
+ the solution space (LineStates are the nodes). The algorithm tries to find
+ the shortest path (the one with the lowest penalty) from 'initial_state' to
+ the state where all tokens are placed.
+
+ Arguments:
+ initial_state: (format_decision_state.FormatDecisionState) The initial state
+ to start the search from.
+
+ Returns:
+ True if a formatting solution was found. False otherwise.
+ """
+ count = 0
+ seen = set()
+ p_queue = []
+
+ # Insert start element.
+ node = _StateNode(initial_state, False, None)
+ heapq.heappush(p_queue, _QueueItem(_OrderedPenalty(0, count), node))
+
+ count += 1
+ while p_queue:
+ item = p_queue[0]
+ penalty = item.ordered_penalty.penalty
+ node = item.state_node
+ if not node.state.next_token:
+ break
+ heapq.heappop(p_queue)
+
+ if count > 10000:
+ node.state.ignore_stack_for_comparison = True
+
+ if node.state in seen:
+ continue
+
+ seen.add(node.state)
+
+ # FIXME(morbo): Add a 'decision' element?
+
+ count = _AddNextStateToQueue(penalty, node, False, count, p_queue)
+ count = _AddNextStateToQueue(penalty, node, True, count, p_queue)
+
+ if not p_queue:
+ # We weren't able to find a solution. Do nothing.
+ return False
+
+ _ReconstructPath(initial_state, heapq.heappop(p_queue).state_node)
+ return True
+
+
+def _AddNextStateToQueue(penalty, previous_node, newline, count, p_queue):
+ """Add the following state to the analysis queue.
+
+ Assume the current state is 'previous_node' and has been reached with a
+ penalty of 'penalty'. Insert a line break if 'newline' is True.
+
+ Arguments:
+ penalty: (int) The penalty associated with the path up to this point.
+ previous_node: (_StateNode) The last _StateNode inserted into the priority
+ queue.
+ newline: (bool) Add a newline if True.
+ count: (int) The number of elements in the queue.
+ p_queue: (heapq) The priority queue representing the solution space.
+
+ Returns:
+ The updated number of elements in the queue.
+ """
+ must_split = previous_node.state.MustSplit()
+ if newline and not previous_node.state.CanSplit(must_split):
+ # Don't add a newline if the token cannot be split.
+ return count
+ if not newline and must_split:
+ # Don't add a token we must split but where we aren't splitting.
+ return count
+
+ node = _StateNode(previous_node.state, newline, previous_node)
+ penalty += node.state.AddTokenToState(
+ newline=newline, dry_run=True, must_split=must_split)
+ heapq.heappush(p_queue, _QueueItem(_OrderedPenalty(penalty, count), node))
+ return count + 1
+
+
+def _ReconstructPath(initial_state, current):
+ """Reconstruct the path through the queue with lowest penalty.
+
+ Arguments:
+ initial_state: (format_decision_state.FormatDecisionState) The initial state
+ to start the search from.
+ current: (_StateNode) The node in the decision graph that is the end point
+ of the path with the least penalty.
+ """
+ path = collections.deque()
+
+ while current.previous:
+ path.appendleft(current)
+ current = current.previous
+
+ for node in path:
+ initial_state.AddTokenToState(newline=node.newline, dry_run=False)
+
+
+def _FormatFirstToken(first_token, indent_depth, prev_uwline, final_lines):
+ """Format the first token in the unwrapped line.
+
+ Add a newline and the required indent before the first token of the unwrapped
+ line.
+
+ Arguments:
+ first_token: (format_token.FormatToken) The first token in the unwrapped
+ line.
+ indent_depth: (int) The line's indentation depth.
+ prev_uwline: (list of unwrapped_line.UnwrappedLine) The unwrapped line
+ previous to this line.
+ final_lines: (list of unwrapped_line.UnwrappedLine) The unwrapped lines
+ that have already been processed.
+ """
+ first_token.AddWhitespacePrefix(
+ _CalculateNumberOfNewlines(first_token, indent_depth, prev_uwline,
+ final_lines),
+ indent_level=indent_depth)
+
+
+NO_BLANK_LINES = 1
+ONE_BLANK_LINE = 2
+TWO_BLANK_LINES = 3
+
+
+def _CalculateNumberOfNewlines(first_token, indent_depth, prev_uwline,
+ final_lines):
+ """Calculate the number of newlines we need to add.
+
+ Arguments:
+ first_token: (format_token.FormatToken) The first token in the unwrapped
+ line.
+ indent_depth: (int) The line's indentation depth.
+ prev_uwline: (list of unwrapped_line.UnwrappedLine) The unwrapped line
+ previous to this line.
+ final_lines: (list of unwrapped_line.UnwrappedLine) The unwrapped lines
+ that have already been processed.
+
+ Returns:
+ The number of newlines needed before the first token.
+ """
+ # TODO(morbo): Special handling for imports.
+ # TODO(morbo): Create a knob that can tune these.
+ if prev_uwline is None:
+ # The first line in the file. Don't add blank lines.
+ # FIXME(morbo): Is this correct?
+ if first_token.newlines is not None:
+ pytree_utils.SetNodeAnnotation(first_token.node,
+ pytree_utils.Annotation.NEWLINES, None)
+ return 0
+
+ if first_token.is_docstring:
+ if (prev_uwline.first.value == 'class' and
+ style.Get('BLANK_LINE_BEFORE_CLASS_DOCSTRING')):
+ # Enforce a blank line before a class's docstring.
+ return ONE_BLANK_LINE
+ # The docstring shouldn't have a newline before it.
+ return NO_BLANK_LINES
+
+ prev_last_token = prev_uwline.last
+ if prev_last_token.is_docstring:
+ if (not indent_depth and first_token.value in {'class', 'def', 'async'}):
+ # Separate a class or function from the module-level docstring with two
+ # blank lines.
+ return TWO_BLANK_LINES
+ if _NoBlankLinesBeforeCurrentToken(prev_last_token.value, first_token,
+ prev_last_token):
+ return NO_BLANK_LINES
+ else:
+ return ONE_BLANK_LINE
+
+ if first_token.value in {'class', 'def', 'async', '@'}:
+ # TODO(morbo): This can go once the blank line calculator is more
+ # sophisticated.
+ if not indent_depth:
+ # This is a top-level class or function.
+ is_inline_comment = prev_last_token.whitespace_prefix.count('\n') == 0
+ if (not prev_uwline.disable and prev_last_token.is_comment and
+ not is_inline_comment):
+ # This token follows a non-inline comment.
+ if _NoBlankLinesBeforeCurrentToken(prev_last_token.value, first_token,
+ prev_last_token):
+ # Assume that the comment is "attached" to the current line.
+ # Therefore, we want two blank lines before the comment.
+ index = len(final_lines) - 1
+ while index > 0:
+ if not final_lines[index - 1].is_comment:
+ break
+ index -= 1
+ if final_lines[index - 1].first.value == '@':
+ final_lines[index].first.AdjustNewlinesBefore(NO_BLANK_LINES)
+ else:
+ prev_last_token.AdjustNewlinesBefore(TWO_BLANK_LINES)
+ if first_token.newlines is not None:
+ pytree_utils.SetNodeAnnotation(
+ first_token.node, pytree_utils.Annotation.NEWLINES, None)
+ return NO_BLANK_LINES
+ elif prev_uwline.first.value in {'class', 'def', 'async'}:
+ if not style.Get('BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF'):
+ pytree_utils.SetNodeAnnotation(first_token.node,
+ pytree_utils.Annotation.NEWLINES, None)
+ return NO_BLANK_LINES
+
+ # Calculate how many newlines were between the original lines. We want to
+ # retain that formatting if it doesn't violate one of the style guide rules.
+ if first_token.is_comment:
+ first_token_lineno = first_token.lineno - first_token.value.count('\n')
+ else:
+ first_token_lineno = first_token.lineno
+
+ prev_last_token_lineno = prev_last_token.lineno
+ if prev_last_token.is_multiline_string:
+ prev_last_token_lineno += prev_last_token.value.count('\n')
+
+ if first_token_lineno - prev_last_token_lineno > 1:
+ return ONE_BLANK_LINE
+
+ return NO_BLANK_LINES
+
+
+def _SingleOrMergedLines(uwlines):
+ """Generate the lines we want to format.
+
+ Arguments:
+ uwlines: (list of unwrapped_line.UnwrappedLine) Lines we want to format.
+
+ Yields:
+ Either a single line, if the current line cannot be merged with the
+ succeeding line, or the next two lines merged into one line.
+ """
+ index = 0
+ last_was_merged = False
+ while index < len(uwlines):
+ if uwlines[index].disable:
+ uwline = uwlines[index]
+ index += 1
+ while index < len(uwlines):
+ column = uwline.last.column + 2
+ if uwlines[index].lineno != uwline.lineno:
+ break
+ if uwline.last.value != ':':
+ leaf = pytree.Leaf(
+ type=token.SEMI, value=';', context=('', (uwline.lineno, column)))
+ uwline.AppendToken(format_token.FormatToken(leaf))
+ for tok in uwlines[index].tokens:
+ uwline.AppendToken(tok)
+ index += 1
+ yield uwline
+ elif line_joiner.CanMergeMultipleLines(uwlines[index:], last_was_merged):
+ # TODO(morbo): This splice is potentially very slow. Come up with a more
+ # performance-friendly way of determining if two lines can be merged.
+ next_uwline = uwlines[index + 1]
+ for tok in next_uwline.tokens:
+ uwlines[index].AppendToken(tok)
+ if (len(next_uwline.tokens) == 1 and
+ next_uwline.first.is_multiline_string):
+ # This may be a multiline shebang. In that case, we want to retain the
+ # formatting. Otherwise, it could mess up the shell script's syntax.
+ uwlines[index].disable = True
+ yield uwlines[index]
+ index += 2
+ last_was_merged = True
+ else:
+ yield uwlines[index]
+ index += 1
+ last_was_merged = False
+
+
+def _NoBlankLinesBeforeCurrentToken(text, cur_token, prev_token):
+ """Determine if there are no blank lines before the current token.
+
+ The previous token is a docstring or comment. The prev_token_lineno is the
+ start of the text of that token. Counting the number of newlines in its text
+ gives us the extent and thus where the line number of the end of the
+ docstring or comment. After that, we just compare it to the current token's
+ line number to see if there are blank lines between them.
+
+ Arguments:
+ text: (unicode) The text of the docstring or comment before the current
+ token.
+ cur_token: (format_token.FormatToken) The current token in the unwrapped
+ line.
+ prev_token: (format_token.FormatToken) The previous token in the unwrapped
+ line.
+
+ Returns:
+ True if there is no blank line before the current token.
+ """
+ cur_token_lineno = cur_token.lineno
+ if cur_token.is_comment:
+ cur_token_lineno -= cur_token.value.count('\n')
+ num_newlines = text.count('\n') if not prev_token.is_comment else 0
+ return prev_token.lineno + num_newlines == cur_token_lineno - 1
diff --git a/tools/yapf/yapf/yapflib/split_penalty.py b/tools/yapf/yapf/yapflib/split_penalty.py
new file mode 100644
index 00000000..3ef4d8c2
--- /dev/null
+++ b/tools/yapf/yapf/yapflib/split_penalty.py
@@ -0,0 +1,559 @@
+# Copyright 2015-2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Computation of split penalties before/between tokens."""
+
+from lib2to3 import pytree
+
+from yapf.yapflib import format_token
+from yapf.yapflib import py3compat
+from yapf.yapflib import pytree_utils
+from yapf.yapflib import pytree_visitor
+from yapf.yapflib import style
+
+# TODO(morbo): Document the annotations in a centralized place. E.g., the
+# README file.
+UNBREAKABLE = 1000 * 1000
+NAMED_ASSIGN = 8500
+DOTTED_NAME = 4000
+VERY_STRONGLY_CONNECTED = 3500
+STRONGLY_CONNECTED = 3000
+
+OR_TEST = 1000
+AND_TEST = 1100
+NOT_TEST = 1200
+COMPARISON = 1300
+STAR_EXPR = 1300
+EXPR = 1400
+XOR_EXPR = 1500
+AND_EXPR = 1700
+SHIFT_EXPR = 1800
+ARITH_EXPR = 1900
+TERM = 2000
+FACTOR = 2100
+POWER = 2200
+ATOM = 2300
+ONE_ELEMENT_ARGUMENT = 2500
+
+
+def ComputeSplitPenalties(tree):
+ """Compute split penalties on tokens in the given parse tree.
+
+ Arguments:
+ tree: the top-level pytree node to annotate with penalties.
+ """
+ _SplitPenaltyAssigner().Visit(tree)
+
+
+class _SplitPenaltyAssigner(pytree_visitor.PyTreeVisitor):
+ """Assigns split penalties to tokens, based on parse tree structure.
+
+ Split penalties are attached as annotations to tokens.
+ """
+
+ def Visit_import_as_names(self, node): # pyline: disable=invalid-name
+ # import_as_names ::= import_as_name (',' import_as_name)* [',']
+ self.DefaultNodeVisit(node)
+ prev_child = None
+ for child in node.children:
+ if (prev_child and isinstance(prev_child, pytree.Leaf) and
+ prev_child.value == ','):
+ _SetSplitPenalty(child, style.Get('SPLIT_PENALTY_IMPORT_NAMES'))
+ prev_child = child
+
+ def Visit_classdef(self, node): # pylint: disable=invalid-name
+ # classdef ::= 'class' NAME ['(' [arglist] ')'] ':' suite
+ #
+ # NAME
+ _SetUnbreakable(node.children[1])
+ if len(node.children) > 4:
+ # opening '('
+ _SetUnbreakable(node.children[2])
+ # ':'
+ _SetUnbreakable(node.children[-2])
+ self.DefaultNodeVisit(node)
+
+ def Visit_funcdef(self, node): # pylint: disable=invalid-name
+ # funcdef ::= 'def' NAME parameters ['->' test] ':' suite
+ #
+ # Can't break before the function name and before the colon. The parameters
+ # are handled by child iteration.
+ colon_idx = 1
+ while pytree_utils.NodeName(node.children[colon_idx]) == 'simple_stmt':
+ colon_idx += 1
+ _SetUnbreakable(node.children[colon_idx])
+ arrow_idx = -1
+ while colon_idx < len(node.children):
+ if isinstance(node.children[colon_idx], pytree.Leaf):
+ if node.children[colon_idx].value == ':':
+ break
+ if node.children[colon_idx].value == '->':
+ arrow_idx = colon_idx
+ colon_idx += 1
+ _SetUnbreakable(node.children[colon_idx])
+ self.DefaultNodeVisit(node)
+ if arrow_idx > 0:
+ _SetSplitPenalty(_LastChildNode(node.children[arrow_idx - 1]), 0)
+ _SetUnbreakable(node.children[arrow_idx])
+ _SetStronglyConnected(node.children[arrow_idx + 1])
+
+ def Visit_lambdef(self, node): # pylint: disable=invalid-name
+ # lambdef ::= 'lambda' [varargslist] ':' test
+ # Loop over the lambda up to and including the colon.
+ if style.Get('ALLOW_MULTILINE_LAMBDAS'):
+ _SetStronglyConnected(node)
+ else:
+ self._SetUnbreakableOnChildren(node)
+
+ def Visit_parameters(self, node): # pylint: disable=invalid-name
+ # parameters ::= '(' [typedargslist] ')'
+ self.DefaultNodeVisit(node)
+
+ # Can't break before the opening paren of a parameter list.
+ _SetUnbreakable(node.children[0])
+ if not style.Get('DEDENT_CLOSING_BRACKETS'):
+ _SetStronglyConnected(node.children[-1])
+
+ def Visit_arglist(self, node): # pylint: disable=invalid-name
+ # arglist ::= argument (',' argument)* [',']
+ self.DefaultNodeVisit(node)
+ index = 1
+ while index < len(node.children):
+ child = node.children[index]
+ if isinstance(child, pytree.Leaf) and child.value == ',':
+ _SetUnbreakable(child)
+ index += 1
+
+ def Visit_argument(self, node): # pylint: disable=invalid-name
+ # argument ::= test [comp_for] | test '=' test # Really [keyword '='] test
+ self.DefaultNodeVisit(node)
+
+ index = 1
+ while index < len(node.children) - 1:
+ child = node.children[index]
+ if isinstance(child, pytree.Leaf) and child.value == '=':
+ _SetSplitPenalty(_FirstChildNode(node.children[index]), NAMED_ASSIGN)
+ _SetSplitPenalty(
+ _FirstChildNode(node.children[index + 1]), NAMED_ASSIGN)
+ index += 1
+
+ def Visit_dotted_name(self, node): # pylint: disable=invalid-name
+ # dotted_name ::= NAME ('.' NAME)*
+ self._SetUnbreakableOnChildren(node)
+
+ def Visit_dictsetmaker(self, node): # pylint: disable=invalid-name
+ # dictsetmaker ::= ( (test ':' test
+ # (comp_for | (',' test ':' test)* [','])) |
+ # (test (comp_for | (',' test)* [','])) )
+ for child in node.children:
+ self.Visit(child)
+ if pytree_utils.NodeName(child) == 'COLON':
+ # This is a key to a dictionary. We don't want to split the key if at
+ # all possible.
+ _SetStronglyConnected(child)
+
+ def Visit_trailer(self, node): # pylint: disable=invalid-name
+ # trailer ::= '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME
+ self.DefaultNodeVisit(node)
+ if node.children[0].value == '.':
+ self._SetUnbreakableOnChildren(node)
+ _SetSplitPenalty(node.children[1], DOTTED_NAME)
+ elif len(node.children) == 2:
+ # Don't split an empty argument list if at all possible.
+ _SetSplitPenalty(node.children[1], VERY_STRONGLY_CONNECTED)
+ elif len(node.children) == 3:
+ name = pytree_utils.NodeName(node.children[1])
+ if name == 'power':
+ if pytree_utils.NodeName(node.children[1].children[0]) != 'atom':
+ # Don't split an argument list with one element if at all possible.
+ _SetStronglyConnected(node.children[1], node.children[2])
+ _SetSplitPenalty(
+ _FirstChildNode(node.children[1]), ONE_ELEMENT_ARGUMENT)
+ elif (pytree_utils.NodeName(node.children[0]) == 'LSQB' and
+ len(node.children[1].children) > 2 and
+ (name.endswith('_test') or name.endswith('_expr'))):
+ _SetStronglyConnected(node.children[1].children[0])
+ _SetStronglyConnected(node.children[1].children[2])
+
+ # Still allow splitting around the operator.
+ split_before = ((name.endswith('_test') and
+ style.Get('SPLIT_BEFORE_LOGICAL_OPERATOR')) or
+ (name.endswith('_expr') and
+ style.Get('SPLIT_BEFORE_BITWISE_OPERATOR')))
+ if split_before:
+ _SetSplitPenalty(_LastChildNode(node.children[1].children[1]), 0)
+ else:
+ _SetSplitPenalty(_FirstChildNode(node.children[1].children[2]), 0)
+
+ # Don't split the ending bracket of a subscript list.
+ _SetVeryStronglyConnected(node.children[-1])
+ elif name not in {
+ 'arglist', 'argument', 'term', 'or_test', 'and_test', 'comparison',
+ 'atom'
+ }:
+ # Don't split an argument list with one element if at all possible.
+ _SetStronglyConnected(node.children[1], node.children[2])
+
+ def Visit_power(self, node): # pylint: disable=invalid-name,missing-docstring
+ # power ::= atom trailer* ['**' factor]
+ self.DefaultNodeVisit(node)
+
+ # When atom is followed by a trailer, we can not break between them.
+ # E.g. arr[idx] - no break allowed between 'arr' and '['.
+ if (len(node.children) > 1 and
+ pytree_utils.NodeName(node.children[1]) == 'trailer'):
+ # children[1] itself is a whole trailer: we don't want to
+ # mark all of it as unbreakable, only its first token: (, [ or .
+ _SetUnbreakable(node.children[1].children[0])
+
+ # A special case when there are more trailers in the sequence. Given:
+ # atom tr1 tr2
+ # The last token of tr1 and the first token of tr2 comprise an unbreakable
+ # region. For example: foo.bar.baz(1)
+ # We can't put breaks between either of the '.', '(', or '[' and the names
+ # *preceding* them.
+ prev_trailer_idx = 1
+ while prev_trailer_idx < len(node.children) - 1:
+ cur_trailer_idx = prev_trailer_idx + 1
+ cur_trailer = node.children[cur_trailer_idx]
+ if pytree_utils.NodeName(cur_trailer) == 'trailer':
+ # Now we know we have two trailers one after the other
+ prev_trailer = node.children[prev_trailer_idx]
+ if prev_trailer.children[-1].value != ')':
+ # Set the previous node unbreakable if it's not a function call:
+ # atom tr1() tr2
+ # It may be necessary (though undesirable) to split up a previous
+ # function call's parentheses to the next line.
+ _SetStronglyConnected(prev_trailer.children[-1])
+ _SetStronglyConnected(cur_trailer.children[0])
+ prev_trailer_idx = cur_trailer_idx
+ else:
+ break
+
+ # We don't want to split before the last ')' of a function call. This also
+ # takes care of the special case of:
+ # atom tr1 tr2 ... trn
+ # where the 'tr#' are trailers that may end in a ')'.
+ for trailer in node.children[1:]:
+ if pytree_utils.NodeName(trailer) != 'trailer':
+ break
+ if trailer.children[0].value in '([':
+ if len(trailer.children) > 2:
+ subtypes = pytree_utils.GetNodeAnnotation(
+ trailer.children[0], pytree_utils.Annotation.SUBTYPE)
+ if subtypes and format_token.Subtype.SUBSCRIPT_BRACKET in subtypes:
+ _SetStronglyConnected(_FirstChildNode(trailer.children[1]))
+
+ last_child_node = _LastChildNode(trailer)
+ if last_child_node.value.strip().startswith('#'):
+ last_child_node = last_child_node.prev_sibling
+ if not style.Get('DEDENT_CLOSING_BRACKETS'):
+ if _LastChildNode(last_child_node.prev_sibling).value != ',':
+ if last_child_node.value == ']':
+ _SetUnbreakable(last_child_node)
+ else:
+ _SetSplitPenalty(last_child_node, VERY_STRONGLY_CONNECTED)
+ else:
+ # If the trailer's children are '()', then make it a strongly
+ # connected region. It's sometimes necessary, though undesirable, to
+ # split the two.
+ _SetStronglyConnected(trailer.children[-1])
+
+ # If the original source has a "builder" style calls, then we should allow
+ # the reformatter to retain that.
+ _AllowBuilderStyleCalls(node)
+
+ def Visit_subscript(self, node): # pylint: disable=invalid-name
+ # subscript ::= test | [test] ':' [test] [sliceop]
+ _SetStronglyConnected(*node.children)
+ self.DefaultNodeVisit(node)
+
+ def Visit_comp_for(self, node): # pylint: disable=invalid-name
+ # comp_for ::= 'for' exprlist 'in' testlist_safe [comp_iter]
+ _SetSplitPenalty(_FirstChildNode(node), 0)
+ _SetStronglyConnected(*node.children[1:])
+ self.DefaultNodeVisit(node)
+
+ def Visit_comp_if(self, node): # pylint: disable=invalid-name
+ # comp_if ::= 'if' old_test [comp_iter]
+ _SetSplitPenalty(node.children[0],
+ style.Get('SPLIT_PENALTY_BEFORE_IF_EXPR'))
+ _SetStronglyConnected(*node.children[1:])
+ self.DefaultNodeVisit(node)
+
+ def Visit_or_test(self, node): # pylint: disable=invalid-name
+ # or_test ::= and_test ('or' and_test)*
+ self.DefaultNodeVisit(node)
+ _IncreasePenalty(node, OR_TEST)
+ index = 1
+ while index + 1 < len(node.children):
+ if style.Get('SPLIT_BEFORE_LOGICAL_OPERATOR'):
+ _DecrementSplitPenalty(_FirstChildNode(node.children[index]), OR_TEST)
+ else:
+ _DecrementSplitPenalty(
+ _FirstChildNode(node.children[index + 1]), OR_TEST)
+ index += 2
+
+ def Visit_and_test(self, node): # pylint: disable=invalid-name
+ # and_test ::= not_test ('and' not_test)*
+ self.DefaultNodeVisit(node)
+ _IncreasePenalty(node, AND_TEST)
+ index = 1
+ while index + 1 < len(node.children):
+ if style.Get('SPLIT_BEFORE_LOGICAL_OPERATOR'):
+ _DecrementSplitPenalty(_FirstChildNode(node.children[index]), AND_TEST)
+ else:
+ _DecrementSplitPenalty(
+ _FirstChildNode(node.children[index + 1]), AND_TEST)
+ index += 2
+
+ def Visit_not_test(self, node): # pylint: disable=invalid-name
+ # not_test ::= 'not' not_test | comparison
+ self.DefaultNodeVisit(node)
+ _IncreasePenalty(node, NOT_TEST)
+
+ def Visit_comparison(self, node): # pylint: disable=invalid-name
+ # comparison ::= expr (comp_op expr)*
+ self.DefaultNodeVisit(node)
+ if len(node.children) == 3 and _StronglyConnectedCompOp(node):
+ _SetSplitPenalty(_FirstChildNode(node.children[1]), STRONGLY_CONNECTED)
+ _SetSplitPenalty(_FirstChildNode(node.children[2]), STRONGLY_CONNECTED)
+ else:
+ _IncreasePenalty(node, COMPARISON)
+
+ def Visit_star_expr(self, node): # pylint: disable=invalid-name
+ # star_expr ::= '*' expr
+ self.DefaultNodeVisit(node)
+ _IncreasePenalty(node, STAR_EXPR)
+
+ def Visit_expr(self, node): # pylint: disable=invalid-name
+ # expr ::= xor_expr ('|' xor_expr)*
+ self.DefaultNodeVisit(node)
+ _IncreasePenalty(node, EXPR)
+ index = 1
+ while index < len(node.children) - 1:
+ child = node.children[index]
+ if isinstance(child, pytree.Leaf) and child.value == '|':
+ if style.Get('SPLIT_BEFORE_BITWISE_OPERATOR'):
+ _SetSplitPenalty(child, style.Get('SPLIT_PENALTY_BITWISE_OPERATOR'))
+ else:
+ _SetSplitPenalty(
+ _FirstChildNode(node.children[index + 1]),
+ style.Get('SPLIT_PENALTY_BITWISE_OPERATOR'))
+ index += 1
+
+ def Visit_xor_expr(self, node): # pylint: disable=invalid-name
+ # xor_expr ::= and_expr ('^' and_expr)*
+ self.DefaultNodeVisit(node)
+ _IncreasePenalty(node, XOR_EXPR)
+
+ def Visit_and_expr(self, node): # pylint: disable=invalid-name
+ # and_expr ::= shift_expr ('&' shift_expr)*
+ self.DefaultNodeVisit(node)
+ _IncreasePenalty(node, AND_EXPR)
+
+ def Visit_shift_expr(self, node): # pylint: disable=invalid-name
+ # shift_expr ::= arith_expr (('<<'|'>>') arith_expr)*
+ self.DefaultNodeVisit(node)
+ _IncreasePenalty(node, SHIFT_EXPR)
+
+ def Visit_arith_expr(self, node): # pylint: disable=invalid-name
+ # arith_expr ::= term (('+'|'-') term)*
+ self.DefaultNodeVisit(node)
+ _IncreasePenalty(node, ARITH_EXPR)
+
+ def Visit_term(self, node): # pylint: disable=invalid-name
+ # term ::= factor (('*'|'@'|'/'|'%'|'//') factor)*
+ _IncreasePenalty(node, TERM)
+ self.DefaultNodeVisit(node)
+
+ def Visit_factor(self, node): # pyline: disable=invalid-name
+ # factor ::= ('+'|'-'|'~') factor | power
+ self.DefaultNodeVisit(node)
+ _IncreasePenalty(node, FACTOR)
+
+ def Visit_atom(self, node): # pylint: disable=invalid-name
+ # atom ::= ('(' [yield_expr|testlist_gexp] ')'
+ # '[' [listmaker] ']' |
+ # '{' [dictsetmaker] '}')
+ self.DefaultNodeVisit(node)
+ if node.children[0].value == '(':
+ if node.children[-1].value == ')':
+ if pytree_utils.NodeName(node.parent) == 'if_stmt':
+ _SetSplitPenalty(node.children[-1], UNBREAKABLE)
+ else:
+ if len(node.children) > 2:
+ _SetSplitPenalty(_FirstChildNode(node.children[1]), EXPR)
+ _SetSplitPenalty(node.children[-1], ATOM)
+ elif node.children[0].value in '[{' and len(node.children) == 2:
+ # Keep empty containers together if we can.
+ _SetUnbreakable(node.children[-1])
+
+ def Visit_testlist_gexp(self, node): # pylint: disable=invalid-name
+ self.DefaultNodeVisit(node)
+ prev_was_comma = False
+ for child in node.children:
+ if isinstance(child, pytree.Leaf) and child.value == ',':
+ _SetUnbreakable(child)
+ prev_was_comma = True
+ else:
+ if prev_was_comma:
+ _SetSplitPenalty(_FirstChildNode(child), 0)
+ prev_was_comma = False
+
+ ############################################################################
+ # Helper methods that set the annotations.
+
+ def _SetUnbreakableOnChildren(self, node):
+ """Set an UNBREAKABLE penalty annotation on children of node."""
+ for child in node.children:
+ self.Visit(child)
+ start = 2 if hasattr(node.children[0], 'is_pseudo') else 1
+ for i in py3compat.range(start, len(node.children)):
+ _SetUnbreakable(node.children[i])
+
+
+def _SetUnbreakable(node):
+ """Set an UNBREAKABLE penalty annotation for the given node."""
+ _RecAnnotate(node, pytree_utils.Annotation.SPLIT_PENALTY, UNBREAKABLE)
+
+
+def _SetStronglyConnected(*nodes):
+ """Set a STRONGLY_CONNECTED penalty annotation for the given nodes."""
+ for node in nodes:
+ _RecAnnotate(node, pytree_utils.Annotation.SPLIT_PENALTY,
+ STRONGLY_CONNECTED)
+
+
+def _SetVeryStronglyConnected(*nodes):
+ """Set a VERY_STRONGLY_CONNECTED penalty annotation for the given nodes."""
+ for node in nodes:
+ _RecAnnotate(node, pytree_utils.Annotation.SPLIT_PENALTY,
+ VERY_STRONGLY_CONNECTED)
+
+
+def _SetExpressionPenalty(node, penalty):
+ """Set a penalty annotation on children nodes."""
+
+ def RecExpression(node, first_child_leaf):
+ if node is first_child_leaf:
+ return
+
+ if isinstance(node, pytree.Leaf):
+ if node.value in {'(', 'for', 'if'}:
+ return
+ penalty_annotation = pytree_utils.GetNodeAnnotation(
+ node, pytree_utils.Annotation.SPLIT_PENALTY, default=0)
+ if penalty_annotation < penalty:
+ _SetSplitPenalty(node, penalty)
+ else:
+ for child in node.children:
+ RecExpression(child, first_child_leaf)
+
+ RecExpression(node, _FirstChildNode(node))
+
+
+def _IncreasePenalty(node, amt):
+ """Increase a penalty annotation on children nodes."""
+
+ def RecExpression(node, first_child_leaf):
+ if node is first_child_leaf:
+ return
+
+ if isinstance(node, pytree.Leaf):
+ if node.value in {'(', 'for', 'if'}:
+ return
+ penalty = pytree_utils.GetNodeAnnotation(
+ node, pytree_utils.Annotation.SPLIT_PENALTY, default=0)
+ _SetSplitPenalty(node, penalty + amt)
+ else:
+ for child in node.children:
+ RecExpression(child, first_child_leaf)
+
+ RecExpression(node, _FirstChildNode(node))
+
+
+def _RecAnnotate(tree, annotate_name, annotate_value):
+ """Recursively set the given annotation on all leafs of the subtree.
+
+ Takes care to only increase the penalty. If the node already has a higher
+ or equal penalty associated with it, this is a no-op.
+
+ Args:
+ tree: subtree to annotate
+ annotate_name: name of the annotation to set
+ annotate_value: value of the annotation to set
+ """
+ for child in tree.children:
+ _RecAnnotate(child, annotate_name, annotate_value)
+ if isinstance(tree, pytree.Leaf):
+ cur_annotate = pytree_utils.GetNodeAnnotation(
+ tree, annotate_name, default=0)
+ if cur_annotate < annotate_value:
+ pytree_utils.SetNodeAnnotation(tree, annotate_name, annotate_value)
+
+
+def _StronglyConnectedCompOp(op):
+ if (len(op.children[1].children) == 2 and
+ pytree_utils.NodeName(op.children[1]) == 'comp_op' and
+ _FirstChildNode(op.children[1]).value == 'not' and
+ _LastChildNode(op.children[1]).value == 'in'):
+ return True
+ if (isinstance(op.children[1], pytree.Leaf) and
+ op.children[1].value in {'==', 'in'}):
+ return True
+ return False
+
+
+def _DecrementSplitPenalty(node, amt):
+ penalty = pytree_utils.GetNodeAnnotation(
+ node, pytree_utils.Annotation.SPLIT_PENALTY, default=amt)
+ penalty = penalty - amt if amt < penalty else 0
+ _SetSplitPenalty(node, penalty)
+
+
+def _SetSplitPenalty(node, penalty):
+ pytree_utils.SetNodeAnnotation(node, pytree_utils.Annotation.SPLIT_PENALTY,
+ penalty)
+
+
+def _AllowBuilderStyleCalls(node):
+ """Allow splitting before '.' if it's a builder style function call."""
+
+ def RecGetLeaves(node):
+ if isinstance(node, pytree.Leaf):
+ return [node]
+ children = []
+ for child in node.children:
+ children += RecGetLeaves(child)
+ return children
+
+ list_of_children = RecGetLeaves(node)
+ prev_child = None
+ for child in list_of_children:
+ if child.value == '.':
+ if prev_child.lineno != child.lineno:
+ _SetSplitPenalty(child, 0)
+ prev_child = child
+
+
+def _FirstChildNode(node):
+ if isinstance(node, pytree.Leaf):
+ return node
+ return _FirstChildNode(node.children[0])
+
+
+def _LastChildNode(node):
+ if isinstance(node, pytree.Leaf):
+ return node
+ return _LastChildNode(node.children[-1])
diff --git a/tools/yapf/yapf/yapflib/style.py b/tools/yapf/yapf/yapflib/style.py
new file mode 100644
index 00000000..14be59e7
--- /dev/null
+++ b/tools/yapf/yapf/yapflib/style.py
@@ -0,0 +1,489 @@
+# Copyright 2015-2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Python formatting style settings."""
+
+import os
+import re
+import textwrap
+
+from yapf.yapflib import errors
+from yapf.yapflib import py3compat
+
+
+class StyleConfigError(errors.YapfError):
+ """Raised when there's a problem reading the style configuration."""
+ pass
+
+
+def Get(setting_name):
+ """Get a style setting."""
+ return _style[setting_name]
+
+
+def Help():
+ """Return dict mapping style names to help strings."""
+ return _STYLE_HELP
+
+
+def SetGlobalStyle(style):
+ """Set a style dict."""
+ global _style
+ global _GLOBAL_STYLE_FACTORY
+ factory = _GetStyleFactory(style)
+ if factory:
+ _GLOBAL_STYLE_FACTORY = factory
+ _style = style
+
+
+_STYLE_HELP = dict(
+ ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT=textwrap.dedent("""\
+ Align closing bracket with visual indentation."""),
+ ALLOW_MULTILINE_LAMBDAS=textwrap.dedent("""\
+ Allow lambdas to be formatted on more than one line."""),
+ ALLOW_MULTILINE_DICTIONARY_KEYS=textwrap.dedent("""\
+ Allow dictionary keys to exist on multiple lines. For example:
+
+ x = {
+ ('this is the first element of a tuple',
+ 'this is the second element of a tuple'):
+ value,
+ }"""),
+ BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=textwrap.dedent("""\
+ Insert a blank line before a 'def' or 'class' immediately nested
+ within another 'def' or 'class'. For example:
+
+ class Foo:
+ # <------ this blank line
+ def method():
+ ..."""),
+ BLANK_LINE_BEFORE_CLASS_DOCSTRING=textwrap.dedent("""\
+ Insert a blank line before a class-level docstring."""),
+ COALESCE_BRACKETS=textwrap.dedent("""\
+ Do not split consecutive brackets. Only relevant when
+ dedent_closing_brackets is set. For example:
+
+ call_func_that_takes_a_dict(
+ {
+ 'key1': 'value1',
+ 'key2': 'value2',
+ }
+ )
+
+ would reformat to:
+
+ call_func_that_takes_a_dict({
+ 'key1': 'value1',
+ 'key2': 'value2',
+ })"""),
+ COLUMN_LIMIT=textwrap.dedent("""\
+ The column limit."""),
+ CONTINUATION_INDENT_WIDTH=textwrap.dedent("""\
+ Indent width used for line continuations."""),
+ DEDENT_CLOSING_BRACKETS=textwrap.dedent("""\
+ Put closing brackets on a separate line, dedented, if the bracketed
+ expression can't fit in a single line. Applies to all kinds of brackets,
+ including function definitions and calls. For example:
+
+ config = {
+ 'key1': 'value1',
+ 'key2': 'value2',
+ } # <--- this bracket is dedented and on a separate line
+
+ time_series = self.remote_client.query_entity_counters(
+ entity='dev3246.region1',
+ key='dns.query_latency_tcp',
+ transform=Transformation.AVERAGE(window=timedelta(seconds=60)),
+ start_ts=now()-timedelta(days=3),
+ end_ts=now(),
+ ) # <--- this bracket is dedented and on a separate line"""),
+ EACH_DICT_ENTRY_ON_SEPARATE_LINE=textwrap.dedent("""\
+ Place each dictionary entry onto its own line."""),
+ I18N_COMMENT=textwrap.dedent("""\
+ The regex for an i18n comment. The presence of this comment stops
+ reformatting of that line, because the comments are required to be
+ next to the string they translate."""),
+ I18N_FUNCTION_CALL=textwrap.dedent("""\
+ The i18n function call names. The presence of this function stops
+ reformattting on that line, because the string it has cannot be moved
+ away from the i18n comment."""),
+ INDENT_DICTIONARY_VALUE=textwrap.dedent("""\
+ Indent the dictionary value if it cannot fit on the same line as the
+ dictionary key. For example:
+
+ config = {
+ 'key1':
+ 'value1',
+ 'key2': value1 +
+ value2,
+ }"""),
+ INDENT_WIDTH=textwrap.dedent("""\
+ The number of columns to use for indentation."""),
+ JOIN_MULTIPLE_LINES=textwrap.dedent("""\
+ Join short lines into one line. E.g., single line 'if' statements."""),
+ SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET=textwrap.dedent("""\
+ Insert a space between the ending comma and closing bracket of a list,
+ etc."""),
+ SPACES_AROUND_POWER_OPERATOR=textwrap.dedent("""\
+ Use spaces around the power operator."""),
+ SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN=textwrap.dedent("""\
+ Use spaces around default or named assigns."""),
+ SPACES_BEFORE_COMMENT=textwrap.dedent("""\
+ The number of spaces required before a trailing comment."""),
+ SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=textwrap.dedent("""\
+ Split before arguments if the argument list is terminated by a
+ comma."""),
+ SPLIT_BEFORE_BITWISE_OPERATOR=textwrap.dedent("""\
+ Set to True to prefer splitting before '&', '|' or '^' rather than
+ after."""),
+ SPLIT_BEFORE_DICT_SET_GENERATOR=textwrap.dedent("""\
+ Split before a dictionary or set generator (comp_for). For example, note
+ the split before the 'for':
+
+ foo = {
+ variable: 'Hello world, have a nice day!'
+ for variable in bar if variable != 42
+ }"""),
+ SPLIT_BEFORE_FIRST_ARGUMENT=textwrap.dedent("""\
+ If an argument / parameter list is going to be split, then split before
+ the first argument."""),
+ SPLIT_BEFORE_LOGICAL_OPERATOR=textwrap.dedent("""\
+ Set to True to prefer splitting before 'and' or 'or' rather than
+ after."""),
+ SPLIT_BEFORE_NAMED_ASSIGNS=textwrap.dedent("""\
+ Split named assignments onto individual lines."""),
+ SPLIT_PENALTY_AFTER_OPENING_BRACKET=textwrap.dedent("""\
+ The penalty for splitting right after the opening bracket."""),
+ SPLIT_PENALTY_AFTER_UNARY_OPERATOR=textwrap.dedent("""\
+ The penalty for splitting the line after a unary operator."""),
+ SPLIT_PENALTY_BEFORE_IF_EXPR=textwrap.dedent("""\
+ The penalty for splitting right before an if expression."""),
+ SPLIT_PENALTY_BITWISE_OPERATOR=textwrap.dedent("""\
+ The penalty of splitting the line around the '&', '|', and '^'
+ operators."""),
+ SPLIT_PENALTY_EXCESS_CHARACTER=textwrap.dedent("""\
+ The penalty for characters over the column limit."""),
+ SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT=textwrap.dedent("""\
+ The penalty incurred by adding a line split to the unwrapped line. The
+ more line splits added the higher the penalty."""),
+ SPLIT_PENALTY_IMPORT_NAMES=textwrap.dedent("""\
+ The penalty of splitting a list of "import as" names. For example:
+
+ from a_very_long_or_indented_module_name_yada_yad import (long_argument_1,
+ long_argument_2,
+ long_argument_3)
+
+ would reformat to something like:
+
+ from a_very_long_or_indented_module_name_yada_yad import (
+ long_argument_1, long_argument_2, long_argument_3)
+ """),
+ SPLIT_PENALTY_LOGICAL_OPERATOR=textwrap.dedent("""\
+ The penalty of splitting the line around the 'and' and 'or'
+ operators."""),
+ USE_TABS=textwrap.dedent("""\
+ Use the Tab character for indentation."""),
+ # BASED_ON_STYLE='Which predefined style this style is based on',
+)
+
+
+def CreatePEP8Style():
+ return dict(
+ ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT=True,
+ ALLOW_MULTILINE_LAMBDAS=False,
+ ALLOW_MULTILINE_DICTIONARY_KEYS=False,
+ BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=False,
+ BLANK_LINE_BEFORE_CLASS_DOCSTRING=False,
+ COALESCE_BRACKETS=False,
+ COLUMN_LIMIT=79,
+ CONTINUATION_INDENT_WIDTH=4,
+ DEDENT_CLOSING_BRACKETS=False,
+ EACH_DICT_ENTRY_ON_SEPARATE_LINE=True,
+ I18N_COMMENT='',
+ I18N_FUNCTION_CALL='',
+ INDENT_DICTIONARY_VALUE=False,
+ INDENT_WIDTH=4,
+ JOIN_MULTIPLE_LINES=True,
+ SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET=True,
+ SPACES_AROUND_POWER_OPERATOR=False,
+ SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN=False,
+ SPACES_BEFORE_COMMENT=2,
+ SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=False,
+ SPLIT_BEFORE_BITWISE_OPERATOR=False,
+ SPLIT_BEFORE_DICT_SET_GENERATOR=True,
+ SPLIT_BEFORE_FIRST_ARGUMENT=False,
+ SPLIT_BEFORE_LOGICAL_OPERATOR=False,
+ SPLIT_BEFORE_NAMED_ASSIGNS=True,
+ SPLIT_PENALTY_AFTER_OPENING_BRACKET=30,
+ SPLIT_PENALTY_AFTER_UNARY_OPERATOR=10000,
+ SPLIT_PENALTY_BEFORE_IF_EXPR=0,
+ SPLIT_PENALTY_BITWISE_OPERATOR=300,
+ SPLIT_PENALTY_EXCESS_CHARACTER=4500,
+ SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT=30,
+ SPLIT_PENALTY_IMPORT_NAMES=0,
+ SPLIT_PENALTY_LOGICAL_OPERATOR=300,
+ USE_TABS=False,)
+
+
+def CreateGoogleStyle():
+ style = CreatePEP8Style()
+ style['ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT'] = False
+ style['BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF'] = True
+ style['COLUMN_LIMIT'] = 80
+ style['INDENT_WIDTH'] = 4
+ style['I18N_COMMENT'] = r'#\..*'
+ style['I18N_FUNCTION_CALL'] = ['N_', '_']
+ style['SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET'] = False
+ return style
+
+
+def CreateChromiumStyle():
+ style = CreateGoogleStyle()
+ style['ALLOW_MULTILINE_DICTIONARY_KEYS'] = True
+ style['INDENT_DICTIONARY_VALUE'] = True
+ style['INDENT_WIDTH'] = 2
+ style['JOIN_MULTIPLE_LINES'] = False
+ style['SPLIT_BEFORE_BITWISE_OPERATOR'] = True
+ return style
+
+
+def CreateFacebookStyle():
+ style = CreatePEP8Style()
+ style['ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT'] = False
+ style['COLUMN_LIMIT'] = 80
+ style['DEDENT_CLOSING_BRACKETS'] = True
+ style['JOIN_MULTIPLE_LINES'] = False
+ style['SPACES_BEFORE_COMMENT'] = 2
+ style['SPLIT_PENALTY_AFTER_OPENING_BRACKET'] = 0
+ style['SPLIT_PENALTY_BEFORE_IF_EXPR'] = 30
+ style['SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT'] = 30
+ return style
+
+
+_STYLE_NAME_TO_FACTORY = dict(
+ pep8=CreatePEP8Style,
+ chromium=CreateChromiumStyle,
+ google=CreateGoogleStyle,
+ facebook=CreateFacebookStyle,)
+
+_DEFAULT_STYLE_TO_FACTORY = [
+ (CreateChromiumStyle(), CreateChromiumStyle),
+ (CreateFacebookStyle(), CreateFacebookStyle),
+ (CreateGoogleStyle(), CreateGoogleStyle),
+ (CreatePEP8Style(), CreatePEP8Style),
+]
+
+
+def _GetStyleFactory(style):
+ for def_style, factory in _DEFAULT_STYLE_TO_FACTORY:
+ if style == def_style:
+ return factory
+ return None
+
+
+def _StringListConverter(s):
+ """Option value converter for a comma-separated list of strings."""
+ return [part.strip() for part in s.split(',')]
+
+
+def _BoolConverter(s):
+ """Option value converter for a boolean."""
+ return py3compat.CONFIGPARSER_BOOLEAN_STATES[s.lower()]
+
+
+# Different style options need to have their values interpreted differently when
+# read from the config file. This dict maps an option name to a "converter"
+# function that accepts the string read for the option's value from the file and
+# returns it wrapper in actual Python type that's going to be meaningful to
+# yapf.
+#
+# Note: this dict has to map all the supported style options.
+_STYLE_OPTION_VALUE_CONVERTER = dict(
+ ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT=_BoolConverter,
+ ALLOW_MULTILINE_LAMBDAS=_BoolConverter,
+ ALLOW_MULTILINE_DICTIONARY_KEYS=_BoolConverter,
+ BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=_BoolConverter,
+ BLANK_LINE_BEFORE_CLASS_DOCSTRING=_BoolConverter,
+ COALESCE_BRACKETS=_BoolConverter,
+ COLUMN_LIMIT=int,
+ CONTINUATION_INDENT_WIDTH=int,
+ DEDENT_CLOSING_BRACKETS=_BoolConverter,
+ EACH_DICT_ENTRY_ON_SEPARATE_LINE=_BoolConverter,
+ I18N_COMMENT=str,
+ I18N_FUNCTION_CALL=_StringListConverter,
+ INDENT_DICTIONARY_VALUE=_BoolConverter,
+ INDENT_WIDTH=int,
+ JOIN_MULTIPLE_LINES=_BoolConverter,
+ SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET=_BoolConverter,
+ SPACES_AROUND_POWER_OPERATOR=_BoolConverter,
+ SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN=_BoolConverter,
+ SPACES_BEFORE_COMMENT=int,
+ SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=_BoolConverter,
+ SPLIT_BEFORE_BITWISE_OPERATOR=_BoolConverter,
+ SPLIT_BEFORE_DICT_SET_GENERATOR=_BoolConverter,
+ SPLIT_BEFORE_FIRST_ARGUMENT=_BoolConverter,
+ SPLIT_BEFORE_LOGICAL_OPERATOR=_BoolConverter,
+ SPLIT_BEFORE_NAMED_ASSIGNS=_BoolConverter,
+ SPLIT_PENALTY_AFTER_OPENING_BRACKET=int,
+ SPLIT_PENALTY_AFTER_UNARY_OPERATOR=int,
+ SPLIT_PENALTY_BEFORE_IF_EXPR=int,
+ SPLIT_PENALTY_BITWISE_OPERATOR=int,
+ SPLIT_PENALTY_EXCESS_CHARACTER=int,
+ SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT=int,
+ SPLIT_PENALTY_IMPORT_NAMES=int,
+ SPLIT_PENALTY_LOGICAL_OPERATOR=int,
+ USE_TABS=_BoolConverter,)
+
+
+def CreateStyleFromConfig(style_config):
+ """Create a style dict from the given config.
+
+ Arguments:
+ style_config: either a style name or a file name. The file is expected to
+ contain settings. It can have a special BASED_ON_STYLE setting naming the
+ style which it derives from. If no such setting is found, it derives from
+ the default style. When style_config is None, the _GLOBAL_STYLE_FACTORY
+ config is created.
+
+ Returns:
+ A style dict.
+
+ Raises:
+ StyleConfigError: if an unknown style option was encountered.
+ """
+
+ def GlobalStyles():
+ for style, _ in _DEFAULT_STYLE_TO_FACTORY:
+ yield style
+
+ def_style = False
+ if style_config is None:
+ for style in GlobalStyles():
+ if _style == style:
+ def_style = True
+ break
+ if not def_style:
+ return _style
+ return _GLOBAL_STYLE_FACTORY()
+ style_factory = _STYLE_NAME_TO_FACTORY.get(style_config.lower())
+ if style_factory is not None:
+ return style_factory()
+ if style_config.startswith('{'):
+ # Most likely a style specification from the command line.
+ config = _CreateConfigParserFromConfigString(style_config)
+ else:
+ # Unknown config name: assume it's a file name then.
+ config = _CreateConfigParserFromConfigFile(style_config)
+ return _CreateStyleFromConfigParser(config)
+
+
+def _CreateConfigParserFromConfigString(config_string):
+ """Given a config string from the command line, return a config parser."""
+ if config_string[0] != '{' or config_string[-1] != '}':
+ raise StyleConfigError(
+ "Invalid style dict syntax: '{}'.".format(config_string))
+ config = py3compat.ConfigParser()
+ config.add_section('style')
+ for key, value in re.findall(r'([a-zA-Z0-9_]+)\s*[:=]\s*([a-zA-Z0-9_]+)',
+ config_string):
+ config.set('style', key, value)
+ return config
+
+
+def _CreateConfigParserFromConfigFile(config_filename):
+ """Read the file and return a ConfigParser object."""
+ if not os.path.exists(config_filename):
+ # Provide a more meaningful error here.
+ raise StyleConfigError(
+ '"{0}" is not a valid style or file path'.format(config_filename))
+ with open(config_filename) as style_file:
+ config = py3compat.ConfigParser()
+ config.read_file(style_file)
+ if config_filename.endswith(SETUP_CONFIG):
+ if not config.has_section('yapf'):
+ raise StyleConfigError(
+ 'Unable to find section [yapf] in {0}'.format(config_filename))
+ elif config_filename.endswith(LOCAL_STYLE):
+ if not config.has_section('style'):
+ raise StyleConfigError(
+ 'Unable to find section [style] in {0}'.format(config_filename))
+ else:
+ if not config.has_section('style'):
+ raise StyleConfigError(
+ 'Unable to find section [style] in {0}'.format(config_filename))
+ return config
+
+
+def _CreateStyleFromConfigParser(config):
+ """Create a style dict from a configuration file.
+
+ Arguments:
+ config: a ConfigParser object.
+
+ Returns:
+ A style dict.
+
+ Raises:
+ StyleConfigError: if an unknown style option was encountered.
+ """
+ # Initialize the base style.
+ section = 'yapf' if config.has_section('yapf') else 'style'
+ if config.has_option('style', 'based_on_style'):
+ based_on = config.get('style', 'based_on_style').lower()
+ base_style = _STYLE_NAME_TO_FACTORY[based_on]()
+ elif config.has_option('yapf', 'based_on_style'):
+ based_on = config.get('yapf', 'based_on_style').lower()
+ base_style = _STYLE_NAME_TO_FACTORY[based_on]()
+ else:
+ base_style = _GLOBAL_STYLE_FACTORY()
+
+ # Read all options specified in the file and update the style.
+ for option, value in config.items(section):
+ if option.lower() == 'based_on_style':
+ # Now skip this one - we've already handled it and it's not one of the
+ # recognized style options.
+ continue
+ option = option.upper()
+ if option not in _STYLE_OPTION_VALUE_CONVERTER:
+ raise StyleConfigError('Unknown style option "{0}"'.format(option))
+ try:
+ base_style[option] = _STYLE_OPTION_VALUE_CONVERTER[option](value)
+ except ValueError:
+ raise StyleConfigError(
+ "'{}' is not a valid setting for {}.".format(value, option))
+ return base_style
+
+
+# The default style - used if yapf is not invoked without specifically
+# requesting a formatting style.
+DEFAULT_STYLE = 'pep8'
+DEFAULT_STYLE_FACTORY = CreatePEP8Style
+_GLOBAL_STYLE_FACTORY = CreatePEP8Style
+
+# The name of the file to use for global style definition.
+GLOBAL_STYLE = (os.path.join(
+ os.getenv('XDG_CONFIG_HOME') or os.path.expanduser('~/.config'), 'yapf',
+ 'style'))
+
+# The name of the file to use for directory-local style definition.
+LOCAL_STYLE = '.style.yapf'
+
+# Alternative place for directory-local style definition. Style should be
+# specified in the '[yapf]' section.
+SETUP_CONFIG = 'setup.cfg'
+
+# TODO(eliben): For now we're preserving the global presence of a style dict.
+# Refactor this so that the style is passed around through yapf rather than
+# being global.
+_style = None
+SetGlobalStyle(_GLOBAL_STYLE_FACTORY())
diff --git a/tools/yapf/yapf/yapflib/subtype_assigner.py b/tools/yapf/yapf/yapflib/subtype_assigner.py
new file mode 100644
index 00000000..646cdc8a
--- /dev/null
+++ b/tools/yapf/yapf/yapflib/subtype_assigner.py
@@ -0,0 +1,416 @@
+# Copyright 2015-2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Subtype assigner for lib2to3 trees.
+
+This module assigns extra type information to the lib2to3 trees. This
+information is more specific than whether something is an operator or an
+identifier. For instance, it can specify if a node in the tree is part of a
+subscript.
+
+ AssignSubtypes(): the main function exported by this module.
+
+Annotations:
+ subtype: The subtype of a pytree token. See 'format_token' module for a list
+ of subtypes.
+"""
+
+from lib2to3 import pytree
+from lib2to3.pgen2 import token
+from lib2to3.pygram import python_symbols as syms
+
+from yapf.yapflib import format_token
+from yapf.yapflib import pytree_utils
+from yapf.yapflib import pytree_visitor
+from yapf.yapflib import style
+
+
+def AssignSubtypes(tree):
+ """Run the subtype assigner visitor over the tree, modifying it in place.
+
+ Arguments:
+ tree: the top-level pytree node to annotate with subtypes.
+ """
+ subtype_assigner = _SubtypeAssigner()
+ subtype_assigner.Visit(tree)
+
+
+# Map tokens in argument lists to their respective subtype.
+_ARGLIST_TOKEN_TO_SUBTYPE = {
+ '=': format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN,
+ ':': format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN,
+ '*': format_token.Subtype.VARARGS_STAR,
+ '**': format_token.Subtype.KWARGS_STAR_STAR,
+}
+
+
+class _SubtypeAssigner(pytree_visitor.PyTreeVisitor):
+ """_SubtypeAssigner - see file-level docstring for detailed description.
+
+ The subtype is added as an annotation to the pytree token.
+ """
+
+ def Visit_dictsetmaker(self, node): # pylint: disable=invalid-name
+ # dictsetmaker ::= (test ':' test (comp_for |
+ # (',' test ':' test)* [','])) |
+ # (test (comp_for | (',' test)* [',']))
+ for child in node.children:
+ self.Visit(child)
+
+ comp_for = False
+ dict_maker = False
+
+ for child in node.children:
+ if pytree_utils.NodeName(child) == 'comp_for':
+ comp_for = True
+ _AppendFirstLeafTokenSubtype(child,
+ format_token.Subtype.DICT_SET_GENERATOR)
+ elif pytree_utils.NodeName(child) in ('COLON', 'DOUBLESTAR'):
+ dict_maker = True
+
+ if not comp_for and dict_maker:
+ last_was_colon = False
+ for child in node.children:
+ if dict_maker:
+ if pytree_utils.NodeName(child) == 'DOUBLESTAR':
+ _AppendFirstLeafTokenSubtype(child,
+ format_token.Subtype.KWARGS_STAR_STAR)
+ if last_was_colon:
+ if style.Get('INDENT_DICTIONARY_VALUE'):
+ _InsertPseudoParentheses(child)
+ else:
+ _AppendFirstLeafTokenSubtype(
+ child, format_token.Subtype.DICTIONARY_VALUE)
+ elif (
+ child is not None and
+ (isinstance(child, pytree.Node) or
+ (not child.value.startswith('#') and child.value not in '{:,'))):
+ # Mark the first leaf of a key entry as a DICTIONARY_KEY. We
+ # normally want to split before them if the dictionary cannot exist
+ # on a single line.
+ _AppendFirstLeafTokenSubtype(child,
+ format_token.Subtype.DICTIONARY_KEY)
+ _AppendSubtypeRec(child, format_token.Subtype.DICTIONARY_KEY_PART)
+ last_was_colon = pytree_utils.NodeName(child) == 'COLON'
+
+ def Visit_expr_stmt(self, node): # pylint: disable=invalid-name
+ # expr_stmt ::= testlist_star_expr (augassign (yield_expr|testlist)
+ # | ('=' (yield_expr|testlist_star_expr))*)
+ for child in node.children:
+ self.Visit(child)
+ if isinstance(child, pytree.Leaf) and child.value == '=':
+ _AppendTokenSubtype(child, format_token.Subtype.ASSIGN_OPERATOR)
+
+ def Visit_or_test(self, node): # pylint: disable=invalid-name
+ # or_test ::= and_test ('or' and_test)*
+ for child in node.children:
+ self.Visit(child)
+ if isinstance(child, pytree.Leaf) and child.value == 'or':
+ _AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR)
+
+ def Visit_and_test(self, node): # pylint: disable=invalid-name
+ # and_test ::= not_test ('and' not_test)*
+ for child in node.children:
+ self.Visit(child)
+ if isinstance(child, pytree.Leaf) and child.value == 'and':
+ _AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR)
+
+ def Visit_not_test(self, node): # pylint: disable=invalid-name
+ # not_test ::= 'not' not_test | comparison
+ for child in node.children:
+ self.Visit(child)
+ if isinstance(child, pytree.Leaf) and child.value == 'not':
+ _AppendTokenSubtype(child, format_token.Subtype.UNARY_OPERATOR)
+
+ def Visit_comparison(self, node): # pylint: disable=invalid-name
+ # comparison ::= expr (comp_op expr)*
+ # comp_op ::= '<'|'>'|'=='|'>='|'<='|'<>'|'!='|'in'|'not in'|'is'|'is not'
+ for child in node.children:
+ self.Visit(child)
+ if (isinstance(child, pytree.Leaf) and
+ child.value in {'<', '>', '==', '>=', '<=', '<>', '!=', 'in', 'is'}):
+ _AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR)
+ elif pytree_utils.NodeName(child) == 'comp_op':
+ for grandchild in child.children:
+ _AppendTokenSubtype(grandchild, format_token.Subtype.BINARY_OPERATOR)
+
+ def Visit_star_expr(self, node): # pylint: disable=invalid-name
+ # star_expr ::= '*' expr
+ for child in node.children:
+ self.Visit(child)
+ if isinstance(child, pytree.Leaf) and child.value == '*':
+ _AppendTokenSubtype(child, format_token.Subtype.UNARY_OPERATOR)
+
+ def Visit_expr(self, node): # pylint: disable=invalid-name
+ # expr ::= xor_expr ('|' xor_expr)*
+ for child in node.children:
+ self.Visit(child)
+ if isinstance(child, pytree.Leaf) and child.value == '|':
+ _AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR)
+
+ def Visit_xor_expr(self, node): # pylint: disable=invalid-name
+ # xor_expr ::= and_expr ('^' and_expr)*
+ for child in node.children:
+ self.Visit(child)
+ if isinstance(child, pytree.Leaf) and child.value == '^':
+ _AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR)
+
+ def Visit_and_expr(self, node): # pylint: disable=invalid-name
+ # and_expr ::= shift_expr ('&' shift_expr)*
+ for child in node.children:
+ self.Visit(child)
+ if isinstance(child, pytree.Leaf) and child.value == '&':
+ _AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR)
+
+ def Visit_shift_expr(self, node): # pylint: disable=invalid-name
+ # shift_expr ::= arith_expr (('<<'|'>>') arith_expr)*
+ for child in node.children:
+ self.Visit(child)
+ if isinstance(child, pytree.Leaf) and child.value in {'<<', '>>'}:
+ _AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR)
+
+ def Visit_arith_expr(self, node): # pylint: disable=invalid-name
+ # arith_expr ::= term (('+'|'-') term)*
+ for child in node.children:
+ self.Visit(child)
+ if isinstance(child, pytree.Leaf) and child.value in '+-':
+ _AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR)
+
+ def Visit_term(self, node): # pylint: disable=invalid-name
+ # term ::= factor (('*'|'/'|'%'|'//') factor)*
+ for child in node.children:
+ self.Visit(child)
+ if (isinstance(child, pytree.Leaf) and
+ child.value in {'*', '/', '%', '//'}):
+ _AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR)
+
+ def Visit_factor(self, node): # pylint: disable=invalid-name
+ # factor ::= ('+'|'-'|'~') factor | power
+ for child in node.children:
+ self.Visit(child)
+ if isinstance(child, pytree.Leaf) and child.value in '+-~':
+ _AppendTokenSubtype(child, format_token.Subtype.UNARY_OPERATOR)
+
+ def Visit_power(self, node): # pylint: disable=invalid-name
+ # power ::= atom trailer* ['**' factor]
+ for child in node.children:
+ self.Visit(child)
+ if isinstance(child, pytree.Leaf) and child.value == '**':
+ _AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR)
+
+ def Visit_trailer(self, node): # pylint: disable=invalid-name
+ for child in node.children:
+ self.Visit(child)
+ if isinstance(child, pytree.Leaf) and child.value in '[]':
+ _AppendTokenSubtype(child, format_token.Subtype.SUBSCRIPT_BRACKET)
+
+ def Visit_subscript(self, node): # pylint: disable=invalid-name
+ # subscript ::= test | [test] ':' [test] [sliceop]
+ for child in node.children:
+ self.Visit(child)
+ if isinstance(child, pytree.Leaf) and child.value == ':':
+ _AppendTokenSubtype(child, format_token.Subtype.SUBSCRIPT_COLON)
+
+ def Visit_sliceop(self, node): # pylint: disable=invalid-name
+ # sliceop ::= ':' [test]
+ for child in node.children:
+ self.Visit(child)
+ if isinstance(child, pytree.Leaf) and child.value == ':':
+ _AppendTokenSubtype(child, format_token.Subtype.SUBSCRIPT_COLON)
+
+ def Visit_argument(self, node): # pylint: disable=invalid-name
+ # argument ::=
+ # test [comp_for] | test '=' test
+ self._ProcessArgLists(node)
+
+ def Visit_arglist(self, node): # pylint: disable=invalid-name
+ # arglist ::=
+ # (argument ',')* (argument [',']
+ # | '*' test (',' argument)* [',' '**' test]
+ # | '**' test)
+ self._ProcessArgLists(node)
+ _SetDefaultOrNamedAssignArgListSubtype(node)
+
+ def Visit_tname(self, node): # pylint: disable=invalid-name
+ self._ProcessArgLists(node)
+ _SetDefaultOrNamedAssignArgListSubtype(node)
+
+ def Visit_decorator(self, node): # pylint: disable=invalid-name
+ # decorator ::=
+ # '@' dotted_name [ '(' [arglist] ')' ] NEWLINE
+ for child in node.children:
+ if isinstance(child, pytree.Leaf) and child.value == '@':
+ _AppendTokenSubtype(child, subtype=format_token.Subtype.DECORATOR)
+ self.Visit(child)
+
+ def Visit_funcdef(self, node): # pylint: disable=invalid-name
+ # funcdef ::=
+ # 'def' NAME parameters ['->' test] ':' suite
+ for child in node.children:
+ if pytree_utils.NodeName(child) == 'NAME' and child.value != 'def':
+ _AppendTokenSubtype(child, format_token.Subtype.FUNC_DEF)
+ break
+ for child in node.children:
+ self.Visit(child)
+
+ def Visit_typedargslist(self, node): # pylint: disable=invalid-name
+ # typedargslist ::=
+ # ((tfpdef ['=' test] ',')*
+ # ('*' [tname] (',' tname ['=' test])* [',' '**' tname]
+ # | '**' tname)
+ # | tfpdef ['=' test] (',' tfpdef ['=' test])* [','])
+ self._ProcessArgLists(node)
+ _SetDefaultOrNamedAssignArgListSubtype(node)
+
+ def Visit_varargslist(self, node): # pylint: disable=invalid-name
+ # varargslist ::=
+ # ((vfpdef ['=' test] ',')*
+ # ('*' [vname] (',' vname ['=' test])* [',' '**' vname]
+ # | '**' vname)
+ # | vfpdef ['=' test] (',' vfpdef ['=' test])* [','])
+ self._ProcessArgLists(node)
+ for child in node.children:
+ self.Visit(child)
+ if isinstance(child, pytree.Leaf) and child.value == '=':
+ _AppendTokenSubtype(child, format_token.Subtype.VARARGS_LIST)
+
+ def Visit_comp_for(self, node): # pylint: disable=invalid-name
+ # comp_for ::= 'for' exprlist 'in' testlist_safe [comp_iter]
+ _AppendSubtypeRec(node, format_token.Subtype.COMP_FOR)
+ self.DefaultNodeVisit(node)
+
+ def Visit_comp_if(self, node): # pylint: disable=invalid-name
+ # comp_if ::= 'if' old_test [comp_iter]
+ _AppendSubtypeRec(node, format_token.Subtype.COMP_IF)
+ self.DefaultNodeVisit(node)
+
+ def _ProcessArgLists(self, node):
+ """Common method for processing argument lists."""
+ for child in node.children:
+ self.Visit(child)
+ if isinstance(child, pytree.Leaf):
+ _AppendTokenSubtype(
+ child,
+ subtype=_ARGLIST_TOKEN_TO_SUBTYPE.get(child.value,
+ format_token.Subtype.NONE))
+
+
+def _SetDefaultOrNamedAssignArgListSubtype(node):
+ """Set named assign subtype on elements in a arg list."""
+
+ def HasDefaultOrNamedAssignSubtype(node):
+ """Return True if the arg list has a named assign subtype."""
+ if isinstance(node, pytree.Leaf):
+ if (format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN in
+ pytree_utils.GetNodeAnnotation(node, pytree_utils.Annotation.SUBTYPE,
+ set())):
+ return True
+ return False
+ has_subtype = False
+ for child in node.children:
+ if pytree_utils.NodeName(child) != 'arglist':
+ has_subtype |= HasDefaultOrNamedAssignSubtype(child)
+ return has_subtype
+
+ if HasDefaultOrNamedAssignSubtype(node):
+ for child in node.children:
+ if pytree_utils.NodeName(child) != 'COMMA':
+ _AppendFirstLeafTokenSubtype(
+ child, format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST)
+
+
+def _AppendTokenSubtype(node, subtype):
+ """Append the token's subtype only if it's not already set."""
+ pytree_utils.AppendNodeAnnotation(node, pytree_utils.Annotation.SUBTYPE,
+ subtype)
+
+
+def _AppendFirstLeafTokenSubtype(node, subtype):
+ """Append the first leaf token's subtypes."""
+ if isinstance(node, pytree.Leaf):
+ _AppendTokenSubtype(node, subtype)
+ return
+ _AppendFirstLeafTokenSubtype(node.children[0], subtype)
+
+
+def _AppendSubtypeRec(node, subtype, force=True):
+ """Append the leafs in the node to the given subtype."""
+ if isinstance(node, pytree.Leaf):
+ _AppendTokenSubtype(node, subtype)
+ return
+ for child in node.children:
+ _AppendSubtypeRec(child, subtype, force=force)
+
+
+def _InsertPseudoParentheses(node):
+ """Insert pseudo parentheses so that dicts can be formatted correctly."""
+ comment_node = None
+ if isinstance(node, pytree.Node):
+ if node.children[-1].type == token.COMMENT:
+ comment_node = node.children[-1].clone()
+ node.children[-1].remove()
+
+ first = _GetFirstLeafNode(node)
+ last = _GetLastLeafNode(node)
+
+ if first == last and first.type == token.COMMENT:
+ # A comment was inserted before the value, which is a pytree.Leaf.
+ # Encompass the dictionary's value into an ATOM node.
+ last = first.next_sibling
+ new_node = pytree.Node(syms.atom, [first.clone(), last.clone()])
+ node.replace(new_node)
+ node = new_node
+ last.remove()
+
+ first = _GetFirstLeafNode(node)
+ last = _GetLastLeafNode(node)
+
+ lparen = pytree.Leaf(
+ token.LPAR, u'(', context=('', (first.get_lineno(), first.column - 1)))
+ last_lineno = last.get_lineno()
+ if last.type == token.STRING and '\n' in last.value:
+ last_lineno += last.value.count('\n')
+
+ if last.type == token.STRING and '\n' in last.value:
+ last_column = len(last.value.split('\n')[-1]) + 1
+ else:
+ last_column = last.column + len(last.value) + 1
+ rparen = pytree.Leaf(
+ token.RPAR, u')', context=('', (last_lineno, last_column)))
+
+ lparen.is_pseudo = True
+ rparen.is_pseudo = True
+
+ if isinstance(node, pytree.Node):
+ node.insert_child(0, lparen)
+ node.append_child(rparen)
+ if comment_node:
+ node.append_child(comment_node)
+ _AppendFirstLeafTokenSubtype(node, format_token.Subtype.DICTIONARY_VALUE)
+ else:
+ clone = node.clone()
+ new_node = pytree.Node(syms.atom, [lparen, clone, rparen])
+ node.replace(new_node)
+ _AppendFirstLeafTokenSubtype(clone, format_token.Subtype.DICTIONARY_VALUE)
+
+
+def _GetFirstLeafNode(node):
+ if isinstance(node, pytree.Leaf):
+ return node
+ return _GetFirstLeafNode(node.children[0])
+
+
+def _GetLastLeafNode(node):
+ if isinstance(node, pytree.Leaf):
+ return node
+ return _GetLastLeafNode(node.children[-1])
diff --git a/tools/yapf/yapf/yapflib/unwrapped_line.py b/tools/yapf/yapf/yapflib/unwrapped_line.py
new file mode 100644
index 00000000..dc782a91
--- /dev/null
+++ b/tools/yapf/yapf/yapflib/unwrapped_line.py
@@ -0,0 +1,497 @@
+# Copyright 2015-2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""UnwrappedLine primitive for formatting.
+
+An unwrapped line is the containing data structure produced by the parser. It
+collects all nodes (stored in FormatToken objects) that could appear on a
+single line if there were no line length restrictions. It's then used by the
+parser to perform the wrapping required to comply with the style guide.
+"""
+
+from yapf.yapflib import format_token
+from yapf.yapflib import py3compat
+from yapf.yapflib import pytree_utils
+from yapf.yapflib import split_penalty
+from yapf.yapflib import style
+
+
+class UnwrappedLine(object):
+ """Represents a single unwrapped line in the output.
+
+ Attributes:
+ depth: indentation depth of this line. This is just a numeric value used to
+ distinguish lines that are more deeply nested than others. It is not the
+ actual amount of spaces, which is style-dependent.
+ """
+
+ def __init__(self, depth, tokens=None):
+ """Constructor.
+
+ Creates a new unwrapped line with the given depth an initial list of tokens.
+ Constructs the doubly-linked lists for format tokens using their built-in
+ next_token and previous_token attributes.
+
+ Arguments:
+ depth: indentation depth of this line
+ tokens: initial list of tokens
+ """
+ self.depth = depth
+ self._tokens = tokens or []
+ self.disable = False
+
+ if self._tokens:
+ # Set up a doubly linked list.
+ for index, tok in enumerate(self._tokens[1:]):
+ # Note, 'index' is the index to the previous token.
+ tok.previous_token = self._tokens[index]
+ self._tokens[index].next_token = tok
+
+ def CalculateFormattingInformation(self):
+ """Calculate the split penalty and total length for the tokens."""
+ # Say that the first token in the line should have a space before it. This
+ # means only that if this unwrapped line is joined with a predecessor line,
+ # then there will be a space between them.
+ self.first.spaces_required_before = 1
+ self.first.total_length = len(self.first.value)
+
+ prev_token = self.first
+ prev_length = self.first.total_length
+ for token in self._tokens[1:]:
+ if (token.spaces_required_before == 0 and
+ _SpaceRequiredBetween(prev_token, token)):
+ token.spaces_required_before = 1
+
+ tok_len = len(token.value) if not token.is_pseudo_paren else 0
+ token.total_length = prev_length + tok_len + token.spaces_required_before
+
+ # The split penalty has to be computed before {must|can}_break_before,
+ # because these may use it for their decision.
+ token.split_penalty += _SplitPenalty(prev_token, token)
+ token.must_break_before = _MustBreakBefore(prev_token, token)
+ token.can_break_before = (token.must_break_before or
+ _CanBreakBefore(prev_token, token))
+
+ prev_length = token.total_length
+ prev_token = token
+
+ ############################################################################
+ # Token Access and Manipulation Methods #
+ ############################################################################
+
+ def AppendToken(self, token):
+ """Append a new FormatToken to the tokens contained in this line."""
+ if self._tokens:
+ token.previous_token = self.last
+ self.last.next_token = token
+ self._tokens.append(token)
+
+ def AppendNode(self, node):
+ """Convenience method to append a pytree node directly.
+
+ Wraps the node with a FormatToken.
+
+ Arguments:
+ node: the node to append
+ """
+ self.AppendToken(format_token.FormatToken(node))
+
+ @property
+ def first(self):
+ """Returns the first non-whitespace token."""
+ return self._tokens[0]
+
+ @property
+ def last(self):
+ """Returns the last non-whitespace token."""
+ return self._tokens[-1]
+
+ ############################################################################
+ # Token -> String Methods #
+ ############################################################################
+
+ def AsCode(self, indent_per_depth=2):
+ """Return a "code" representation of this line.
+
+ The code representation shows how the line would be printed out as code.
+
+ TODO(eliben): for now this is rudimentary for debugging - once we add
+ formatting capabilities, this method will have other uses (not all tokens
+ have spaces around them, for example).
+
+ Arguments:
+ indent_per_depth: how much spaces to indend per depth level.
+
+ Returns:
+ A string representing the line as code.
+ """
+ indent = ' ' * indent_per_depth * self.depth
+ tokens_str = ' '.join(tok.value for tok in self._tokens)
+ return indent + tokens_str
+
+ def __str__(self): # pragma: no cover
+ return self.AsCode()
+
+ def __repr__(self): # pragma: no cover
+ tokens_repr = ','.join(
+ ['{0}({1!r})'.format(tok.name, tok.value) for tok in self._tokens])
+ return 'UnwrappedLine(depth={0}, tokens=[{1}])'.format(
+ self.depth, tokens_repr)
+
+ ############################################################################
+ # Properties #
+ ############################################################################
+
+ @property
+ def tokens(self):
+ """Access the tokens contained within this line.
+
+ The caller must not modify the tokens list returned by this method.
+
+ Returns:
+ List of tokens in this line.
+ """
+ return self._tokens
+
+ @property
+ def lineno(self):
+ """Return the line number of this unwrapped line.
+
+ Returns:
+ The line number of the first token in this unwrapped line.
+ """
+ return self.first.lineno
+
+ @property
+ def is_comment(self):
+ return self.first.is_comment
+
+
+def _IsIdNumberStringToken(tok):
+ return tok.is_keyword or tok.is_name or tok.is_number or tok.is_string
+
+
+def _IsUnaryOperator(tok):
+ return format_token.Subtype.UNARY_OPERATOR in tok.subtypes
+
+
+def _SpaceRequiredBetween(left, right):
+ """Return True if a space is required between the left and right token."""
+ lval = left.value
+ rval = right.value
+ if (left.is_pseudo_paren and _IsIdNumberStringToken(right) and
+ left.previous_token and _IsIdNumberStringToken(left.previous_token)):
+ # Space between keyword... tokens and pseudo parens.
+ return True
+ if left.is_pseudo_paren or right.is_pseudo_paren:
+ # There should be a space after the ':' in a dictionary.
+ if left.OpensScope():
+ return True
+ # The closing pseudo-paren shouldn't affect spacing.
+ return False
+ if left.is_continuation or right.is_continuation:
+ # The continuation node's value has all of the spaces it needs.
+ return False
+ if right.name in pytree_utils.NONSEMANTIC_TOKENS:
+ # No space before a non-semantic token.
+ return False
+ if _IsIdNumberStringToken(left) and _IsIdNumberStringToken(right):
+ # Spaces between keyword, string, number, and identifier tokens.
+ return True
+ if lval == ',' and rval == ':':
+ # We do want a space between a comma and colon.
+ return True
+ if rval in ':,':
+ # Otherwise, we never want a space before a colon or comma.
+ return False
+ if lval == ',' and rval in ']})':
+ # Add a space between ending ',' and closing bracket if requested.
+ return style.Get('SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET')
+ if lval == ',':
+ # We want a space after a comma.
+ return True
+ if lval == 'from' and rval == '.':
+ # Space before the '.' in an import statement.
+ return True
+ if lval == '.' and rval == 'import':
+ # Space after the '.' in an import statement.
+ return True
+ if lval == '=' and rval == '.':
+ # Space between equal and '.' as in "X = ...".
+ return True
+ if ((right.is_keyword or right.is_name) and
+ (left.is_keyword or left.is_name)):
+ # Don't merge two keywords/identifiers.
+ return True
+ if left.is_string:
+ if (rval == '=' and format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN_ARG_LIST in
+ right.subtypes):
+ # If there is a type hint, then we don't want to add a space between the
+ # equal sign and the hint.
+ return False
+ if rval not in '[)]}.':
+ # A string followed by something other than a subscript, closing bracket,
+ # or dot should have a space after it.
+ return True
+ if left.is_binary_op and lval != '**' and _IsUnaryOperator(right):
+ # Space between the binary opertor and the unary operator.
+ return True
+ if _IsUnaryOperator(left) and _IsUnaryOperator(right):
+ # No space between two unary operators.
+ return False
+ if left.is_binary_op or right.is_binary_op:
+ if lval == '**' or rval == '**':
+ # Space around the "power" operator.
+ return style.Get('SPACES_AROUND_POWER_OPERATOR')
+ # Enforce spaces around binary operators.
+ return True
+ if (_IsUnaryOperator(left) and lval != 'not' and
+ (right.is_name or right.is_number or rval == '(')):
+ # The previous token was a unary op. No space is desired between it and
+ # the current token.
+ return False
+ if (format_token.Subtype.SUBSCRIPT_COLON in left.subtypes or
+ format_token.Subtype.SUBSCRIPT_COLON in right.subtypes):
+ # A subscript shouldn't have spaces separating its colons.
+ return False
+ if (format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN in left.subtypes or
+ format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN in right.subtypes):
+ # A named argument or default parameter shouldn't have spaces around it.
+ # However, a typed argument should have a space after the colon.
+ return lval == ':' or style.Get('SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN')
+ if (format_token.Subtype.VARARGS_LIST in left.subtypes or
+ format_token.Subtype.VARARGS_LIST in right.subtypes):
+ return False
+ if (format_token.Subtype.VARARGS_STAR in left.subtypes or
+ format_token.Subtype.KWARGS_STAR_STAR in left.subtypes):
+ # Don't add a space after a vararg's star or a keyword's star-star.
+ return False
+ if lval == '@' and format_token.Subtype.DECORATOR in left.subtypes:
+ # Decorators shouldn't be separated from the 'at' sign.
+ return False
+ if lval == '.' or rval == '.':
+ # Don't place spaces between dots.
+ return False
+ if ((lval == '(' and rval == ')') or (lval == '[' and rval == ']') or
+ (lval == '{' and rval == '}')):
+ # Empty objects shouldn't be separted by spaces.
+ return False
+ if (lval in pytree_utils.OPENING_BRACKETS and
+ rval in pytree_utils.OPENING_BRACKETS):
+ # Nested objects' opening brackets shouldn't be separated.
+ return False
+ if (lval in pytree_utils.CLOSING_BRACKETS and
+ rval in pytree_utils.CLOSING_BRACKETS):
+ # Nested objects' closing brackets shouldn't be separated.
+ return False
+ if lval in pytree_utils.CLOSING_BRACKETS and rval in '([':
+ # A call, set, dictionary, or subscript that has a call or subscript after
+ # it shouldn't have a space between them.
+ return False
+ if lval in pytree_utils.OPENING_BRACKETS and _IsIdNumberStringToken(right):
+ # Don't separate the opening bracket from the first item.
+ return False
+ if left.is_name and rval in '([':
+ # Don't separate a call or array access from the name.
+ return False
+ if rval in pytree_utils.CLOSING_BRACKETS:
+ # Don't separate the closing bracket from the last item.
+ # FIXME(morbo): This might be too permissive.
+ return False
+ if lval == 'print' and rval == '(':
+ # Special support for the 'print' function.
+ return False
+ if lval in pytree_utils.OPENING_BRACKETS and _IsUnaryOperator(right):
+ # Don't separate a unary operator from the opening bracket.
+ return False
+ if (lval in pytree_utils.OPENING_BRACKETS and
+ (format_token.Subtype.VARARGS_STAR in right.subtypes or
+ format_token.Subtype.KWARGS_STAR_STAR in right.subtypes)):
+ # Don't separate a '*' or '**' from the opening bracket.
+ return False
+ if rval == ';':
+ # Avoid spaces before a semicolon. (Why is there a semicolon?!)
+ return False
+ if lval == '(' and rval == 'await':
+ # Special support for the 'await' keyword. Don't separate the 'await'
+ # keyword from an opening paren.
+ return False
+ return True
+
+
+def _MustBreakBefore(prev_token, cur_token):
+ """Return True if a line break is required before the current token."""
+ if prev_token.is_comment:
+ # Must break if the previous token was a comment.
+ return True
+ if (cur_token.is_string and prev_token.is_string and
+ IsSurroundedByBrackets(cur_token)):
+ # We want consecutive strings to be on separate lines. This is a
+ # reasonable assumption, because otherwise they should have written them
+ # all on the same line, or with a '+'.
+ return True
+ return pytree_utils.GetNodeAnnotation(
+ cur_token.node, pytree_utils.Annotation.MUST_SPLIT, default=False)
+
+
+def _CanBreakBefore(prev_token, cur_token):
+ """Return True if a line break may occur before the current token."""
+ pval = prev_token.value
+ cval = cur_token.value
+ if py3compat.PY3:
+ if pval == 'yield' and cval == 'from':
+ # Don't break before a yield argument.
+ return False
+ if pval in {'async', 'await'} and cval in {'def', 'with', 'for'}:
+ # Don't break after sync keywords.
+ return False
+ if cur_token.split_penalty >= split_penalty.UNBREAKABLE:
+ return False
+ if pval == '@':
+ # Don't break right after the beginning of a decorator.
+ return False
+ if cval == ':':
+ # Don't break before the start of a block of code.
+ return False
+ if cval == ',':
+ # Don't break before a comma.
+ return False
+ if prev_token.is_name and cval == '(':
+ # Don't break in the middle of a function definition or call.
+ return False
+ if prev_token.is_name and cval == '[':
+ # Don't break in the middle of an array dereference.
+ return False
+ if prev_token.is_name and cval == '.':
+ # Don't break before the '.' in a dotted name.
+ return False
+ if cur_token.is_comment and prev_token.lineno == cur_token.lineno:
+ # Don't break a comment at the end of the line.
+ return False
+ if format_token.Subtype.UNARY_OPERATOR in prev_token.subtypes:
+ # Don't break after a unary token.
+ return False
+ return True
+
+
+def IsSurroundedByBrackets(tok):
+ """Return True if the token is surrounded by brackets."""
+ paren_count = 0
+ brace_count = 0
+ sq_bracket_count = 0
+ previous_token = tok.previous_token
+ while previous_token:
+ if previous_token.value == ')':
+ paren_count -= 1
+ elif previous_token.value == '}':
+ brace_count -= 1
+ elif previous_token.value == ']':
+ sq_bracket_count -= 1
+
+ if previous_token.value == '(':
+ if paren_count == 0:
+ return previous_token
+ paren_count += 1
+ elif previous_token.value == '{':
+ if brace_count == 0:
+ return previous_token
+ brace_count += 1
+ elif previous_token.value == '[':
+ if sq_bracket_count == 0:
+ return previous_token
+ sq_bracket_count += 1
+
+ previous_token = previous_token.previous_token
+ return None
+
+
+_LOGICAL_OPERATORS = frozenset({'and', 'or'})
+_BITWISE_OPERATORS = frozenset({'&', '|', '^'})
+_TERM_OPERATORS = frozenset({'*', '/', '%', '//'})
+
+
+def _SplitPenalty(prev_token, cur_token):
+ """Return the penalty for breaking the line before the current token."""
+ pval = prev_token.value
+ cval = cur_token.value
+ if pval == 'not':
+ return split_penalty.UNBREAKABLE
+
+ if cur_token.node_split_penalty > 0:
+ return cur_token.node_split_penalty
+
+ if style.Get('SPLIT_BEFORE_LOGICAL_OPERATOR'):
+ # Prefer to split before 'and' and 'or'.
+ if pval in _LOGICAL_OPERATORS:
+ return style.Get('SPLIT_PENALTY_LOGICAL_OPERATOR')
+ if cval in _LOGICAL_OPERATORS:
+ return 0
+ else:
+ # Prefer to split after 'and' and 'or'.
+ if pval in _LOGICAL_OPERATORS:
+ return 0
+ if cval in _LOGICAL_OPERATORS:
+ return style.Get('SPLIT_PENALTY_LOGICAL_OPERATOR')
+
+ if style.Get('SPLIT_BEFORE_BITWISE_OPERATOR'):
+ # Prefer to split before '&', '|', and '^'.
+ if pval in _BITWISE_OPERATORS:
+ return style.Get('SPLIT_PENALTY_BITWISE_OPERATOR')
+ if cval in _BITWISE_OPERATORS:
+ return 0
+ else:
+ # Prefer to split after '&', '|', and '^'.
+ if pval in _BITWISE_OPERATORS:
+ return 0
+ if cval in _BITWISE_OPERATORS:
+ return style.Get('SPLIT_PENALTY_BITWISE_OPERATOR')
+
+ if (format_token.Subtype.COMP_FOR in cur_token.subtypes or
+ format_token.Subtype.COMP_IF in cur_token.subtypes):
+ # We don't mind breaking before the 'for' or 'if' of a list comprehension.
+ return 0
+ if format_token.Subtype.UNARY_OPERATOR in prev_token.subtypes:
+ # Try not to break after a unary operator.
+ return style.Get('SPLIT_PENALTY_AFTER_UNARY_OPERATOR')
+ if pval == ',':
+ # Breaking after a comma is fine, if need be.
+ return 0
+ if prev_token.is_binary_op:
+ # We would rather not split after an equality operator.
+ return 20
+ if (format_token.Subtype.VARARGS_STAR in prev_token.subtypes or
+ format_token.Subtype.KWARGS_STAR_STAR in prev_token.subtypes):
+ # Don't split after a varargs * or kwargs **.
+ return split_penalty.UNBREAKABLE
+ if prev_token.OpensScope() and cval != '(':
+ # Slightly prefer
+ return style.Get('SPLIT_PENALTY_AFTER_OPENING_BRACKET')
+ if cval == ':':
+ # Don't split before a colon.
+ return split_penalty.UNBREAKABLE
+ if cval == '=':
+ # Don't split before an assignment.
+ return split_penalty.UNBREAKABLE
+ if (format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN in prev_token.subtypes or
+ format_token.Subtype.DEFAULT_OR_NAMED_ASSIGN in cur_token.subtypes):
+ # Don't break before or after an default or named assignment.
+ return split_penalty.UNBREAKABLE
+ if cval == '==':
+ # We would rather not split before an equality operator.
+ return split_penalty.STRONGLY_CONNECTED
+ if cur_token.ClosesScope():
+ # Give a slight penalty for splitting before the closing scope.
+ return 100
+ if pval in _TERM_OPERATORS or cval in _TERM_OPERATORS:
+ return 50
+ return 0
diff --git a/tools/yapf/yapf/yapflib/verifier.py b/tools/yapf/yapf/yapflib/verifier.py
new file mode 100644
index 00000000..b16aefb8
--- /dev/null
+++ b/tools/yapf/yapf/yapflib/verifier.py
@@ -0,0 +1,93 @@
+# Copyright 2015-2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Verify that the generated code is valid code.
+
+This takes a line of code and "normalizes" it. I.e., it transforms the snippet
+into something that has the potential to compile.
+
+ VerifyCode(): the main function exported by this module.
+"""
+
+import ast
+import re
+import sys
+import textwrap
+
+
+class InternalError(Exception):
+ """Internal error in verifying formatted code."""
+ pass
+
+
+def VerifyCode(code):
+ """Verify that the reformatted code is syntactically correct.
+
+ Arguments:
+ code: (unicode) The reformatted code snippet.
+
+ Raises:
+ SyntaxError if the code was reformatted incorrectly.
+ """
+ try:
+ compile(textwrap.dedent(code).encode('UTF-8'), '<string>', 'exec')
+ except SyntaxError:
+ try:
+ ast.parse(textwrap.dedent(code.lstrip('\n')).lstrip(), '<string>', 'exec')
+ except SyntaxError:
+ try:
+ normalized_code = _NormalizeCode(code)
+ compile(normalized_code.encode('UTF-8'), '<string>', 'exec')
+ except SyntaxError:
+ raise InternalError(sys.exc_info()[1])
+
+
+def _NormalizeCode(code):
+ """Make sure that the code snippet is compilable."""
+ code = textwrap.dedent(code.lstrip('\n')).lstrip()
+
+ # Split the code to lines and get rid of all leading full-comment lines as
+ # they can mess up the normalization attempt.
+ lines = code.split('\n')
+ i = 0
+ for i, line in enumerate(lines):
+ line = line.strip()
+ if line and not line.startswith('#'):
+ break
+ code = '\n'.join(lines[i:]) + '\n'
+
+ if re.match(r'(if|while|for|with|def|class|async|await)\b', code):
+ code += '\n pass'
+ elif re.match(r'(elif|else)\b', code):
+ try:
+ try_code = 'if True:\n pass\n' + code + '\n pass'
+ ast.parse(
+ textwrap.dedent(try_code.lstrip('\n')).lstrip(), '<string>', 'exec')
+ code = try_code
+ except SyntaxError:
+ # The assumption here is that the code is on a single line.
+ code = 'if True: pass\n' + code
+ elif code.startswith('@'):
+ code += '\ndef _():\n pass'
+ elif re.match(r'try\b', code):
+ code += '\n pass\nexcept:\n pass'
+ elif re.match(r'(except|finally)\b', code):
+ code = 'try:\n pass\n' + code + '\n pass'
+ elif re.match(r'(return|yield)\b', code):
+ code = 'def _():\n ' + code
+ elif re.match(r'(continue|break)\b', code):
+ code = 'while True:\n ' + code
+ elif re.match(r'print\b', code):
+ code = 'from __future__ import print_function\n' + code
+
+ return code + '\n'
diff --git a/tools/yapf/yapf/yapflib/yapf_api.py b/tools/yapf/yapf/yapflib/yapf_api.py
new file mode 100644
index 00000000..dd91849e
--- /dev/null
+++ b/tools/yapf/yapf/yapflib/yapf_api.py
@@ -0,0 +1,295 @@
+# Copyright 2015-2017 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Entry points for YAPF.
+
+The main APIs that YAPF exposes to drive the reformatting.
+
+ FormatFile(): reformat a file.
+ FormatCode(): reformat a string of code.
+
+These APIs have some common arguments:
+
+ style_config: (string) Either a style name or a path to a file that contains
+ formatting style settings. If None is specified, use the default style
+ as set in style.DEFAULT_STYLE_FACTORY
+ lines: (list of tuples of integers) A list of tuples of lines, [start, end],
+ that we want to format. The lines are 1-based indexed. It can be used by
+ third-party code (e.g., IDEs) when reformatting a snippet of code rather
+ than a whole file.
+ print_diff: (bool) Instead of returning the reformatted source, return a
+ diff that turns the formatted source into reformatter source.
+ verify: (bool) True if reformatted code should be verified for syntax.
+"""
+
+import difflib
+import re
+import sys
+
+from lib2to3.pgen2 import tokenize
+
+from yapf.yapflib import blank_line_calculator
+from yapf.yapflib import comment_splicer
+from yapf.yapflib import continuation_splicer
+from yapf.yapflib import file_resources
+from yapf.yapflib import py3compat
+from yapf.yapflib import pytree_unwrapper
+from yapf.yapflib import pytree_utils
+from yapf.yapflib import reformatter
+from yapf.yapflib import split_penalty
+from yapf.yapflib import style
+from yapf.yapflib import subtype_assigner
+
+
+def FormatFile(filename,
+ style_config=None,
+ lines=None,
+ print_diff=False,
+ verify=False,
+ in_place=False,
+ logger=None):
+ """Format a single Python file and return the formatted code.
+
+ Arguments:
+ filename: (unicode) The file to reformat.
+ in_place: (bool) If True, write the reformatted code back to the file.
+ logger: (io streamer) A stream to output logging.
+ remaining arguments: see comment at the top of this module.
+
+ Returns:
+ Tuple of (reformatted_code, encoding, changed). reformatted_code is None if
+ the file is sucessfully written to (having used in_place). reformatted_code
+ is a diff if print_diff is True.
+
+ Raises:
+ IOError: raised if there was an error reading the file.
+ ValueError: raised if in_place and print_diff are both specified.
+ """
+ _CheckPythonVersion()
+
+ if in_place and print_diff:
+ raise ValueError('Cannot pass both in_place and print_diff.')
+
+ original_source, newline, encoding = ReadFile(filename, logger)
+ reformatted_source, changed = FormatCode(
+ original_source,
+ style_config=style_config,
+ filename=filename,
+ lines=lines,
+ print_diff=print_diff,
+ verify=verify)
+ if reformatted_source.rstrip('\n'):
+ lines = reformatted_source.rstrip('\n').split('\n')
+ reformatted_source = newline.join(line for line in lines) + newline
+ if in_place:
+ if original_source and original_source != reformatted_source:
+ file_resources.WriteReformattedCode(filename, reformatted_source,
+ in_place, encoding)
+ return None, encoding, changed
+
+ return reformatted_source, encoding, changed
+
+
+def FormatCode(unformatted_source,
+ filename='<unknown>',
+ style_config=None,
+ lines=None,
+ print_diff=False,
+ verify=False):
+ """Format a string of Python code.
+
+ This provides an alternative entry point to YAPF.
+
+ Arguments:
+ unformatted_source: (unicode) The code to format.
+ filename: (unicode) The name of the file being reformatted.
+ remaining arguments: see comment at the top of this module.
+
+ Returns:
+ Tuple of (reformatted_source, changed). reformatted_source conforms to the
+ desired formatting style. changed is True if the source changed.
+ """
+ _CheckPythonVersion()
+ style.SetGlobalStyle(style.CreateStyleFromConfig(style_config))
+ if not unformatted_source.endswith('\n'):
+ unformatted_source += '\n'
+ tree = pytree_utils.ParseCodeToTree(unformatted_source)
+
+ # Run passes on the tree, modifying it in place.
+ comment_splicer.SpliceComments(tree)
+ continuation_splicer.SpliceContinuations(tree)
+ subtype_assigner.AssignSubtypes(tree)
+ split_penalty.ComputeSplitPenalties(tree)
+ blank_line_calculator.CalculateBlankLines(tree)
+
+ uwlines = pytree_unwrapper.UnwrapPyTree(tree)
+ for uwl in uwlines:
+ uwl.CalculateFormattingInformation()
+
+ _MarkLinesToFormat(uwlines, lines)
+ reformatted_source = reformatter.Reformat(uwlines, verify)
+
+ if unformatted_source == reformatted_source:
+ return '' if print_diff else reformatted_source, False
+
+ code_diff = _GetUnifiedDiff(
+ unformatted_source, reformatted_source, filename=filename)
+
+ if print_diff:
+ return code_diff, code_diff != ''
+
+ return reformatted_source, True
+
+
+def _CheckPythonVersion(): # pragma: no cover
+ errmsg = 'yapf is only supported for Python 2.7 or 3.4+'
+ if sys.version_info[0] == 2:
+ if sys.version_info[1] < 7:
+ raise RuntimeError(errmsg)
+ elif sys.version_info[0] == 3:
+ if sys.version_info[1] < 4:
+ raise RuntimeError(errmsg)
+
+
+def ReadFile(filename, logger=None):
+ """Read the contents of the file.
+
+ An optional logger can be specified to emit messages to your favorite logging
+ stream. If specified, then no exception is raised. This is external so that it
+ can be used by third-party applications.
+
+ Arguments:
+ filename: (unicode) The name of the file.
+ logger: (function) A function or lambda that takes a string and emits it.
+
+ Returns:
+ The contents of filename.
+
+ Raises:
+ IOError: raised if there was an error reading the file.
+ """
+ try:
+ with open(filename, 'rb') as fd:
+ encoding = tokenize.detect_encoding(fd.readline)[0]
+ except IOError as err:
+ if logger:
+ logger(err)
+ raise
+
+ try:
+ # Preserves line endings.
+ with py3compat.open_with_encoding(
+ filename, mode='r', encoding=encoding, newline='') as fd:
+ lines = fd.readlines()
+
+ line_ending = file_resources.LineEnding(lines)
+ source = '\n'.join(line.rstrip('\r\n') for line in lines) + '\n'
+ return source, line_ending, encoding
+ except IOError as err: # pragma: no cover
+ if logger:
+ logger(err)
+ raise
+
+
+DISABLE_PATTERN = r'^#.*\byapf:\s*disable\b'
+ENABLE_PATTERN = r'^#.*\byapf:\s*enable\b'
+
+
+def _MarkLinesToFormat(uwlines, lines):
+ """Skip sections of code that we shouldn't reformat."""
+ if lines:
+ for uwline in uwlines:
+ uwline.disable = True
+
+ # Sort and combine overlapping ranges.
+ lines = sorted(lines)
+ line_ranges = [lines[0]] if len(lines[0]) else []
+ index = 1
+ while index < len(lines):
+ current = line_ranges[-1]
+ if lines[index][0] <= current[1]:
+ # The ranges overlap, so combine them.
+ line_ranges[-1] = (current[0], max(lines[index][1], current[1]))
+ else:
+ line_ranges.append(lines[index])
+ index += 1
+
+ # Mark lines to format as not being disabled.
+ index = 0
+ for start, end in sorted(line_ranges):
+ while index < len(uwlines) and uwlines[index].last.lineno < start:
+ index += 1
+ if index >= len(uwlines):
+ break
+
+ while index < len(uwlines):
+ if uwlines[index].lineno > end:
+ break
+ if (uwlines[index].lineno >= start or
+ uwlines[index].last.lineno >= start):
+ uwlines[index].disable = False
+ index += 1
+
+ # Now go through the lines and disable any lines explicitly marked as
+ # disabled.
+ index = 0
+ while index < len(uwlines):
+ uwline = uwlines[index]
+ if uwline.is_comment:
+ if _DisableYAPF(uwline.first.value.strip()):
+ index += 1
+ while index < len(uwlines):
+ uwline = uwlines[index]
+ if uwline.is_comment and _EnableYAPF(uwline.first.value.strip()):
+ break
+ uwline.disable = True
+ index += 1
+ elif re.search(DISABLE_PATTERN, uwline.last.value.strip(), re.IGNORECASE):
+ uwline.disable = True
+ index += 1
+
+
+def _DisableYAPF(line):
+ return (
+ re.search(DISABLE_PATTERN, line.split('\n')[0].strip(), re.IGNORECASE) or
+ re.search(DISABLE_PATTERN, line.split('\n')[-1].strip(), re.IGNORECASE))
+
+
+def _EnableYAPF(line):
+ return (
+ re.search(ENABLE_PATTERN, line.split('\n')[0].strip(), re.IGNORECASE) or
+ re.search(ENABLE_PATTERN, line.split('\n')[-1].strip(), re.IGNORECASE))
+
+
+def _GetUnifiedDiff(before, after, filename='code'):
+ """Get a unified diff of the changes.
+
+ Arguments:
+ before: (unicode) The original source code.
+ after: (unicode) The reformatted source code.
+ filename: (unicode) The code's filename.
+
+ Returns:
+ The unified diff text.
+ """
+ before = before.splitlines()
+ after = after.splitlines()
+ return '\n'.join(
+ difflib.unified_diff(
+ before,
+ after,
+ filename,
+ filename,
+ '(original)',
+ '(reformatted)',
+ lineterm='')) + '\n'
diff --git a/tools/yapf_util.py b/tools/yapf_util.py
new file mode 100644
index 00000000..c5add7ea
--- /dev/null
+++ b/tools/yapf_util.py
@@ -0,0 +1,28 @@
+# Copyright (c) 2017 The Chromium Embedded Framework Authors. All rights
+# reserved. Use of this source code is governed by a BSD-style license that
+# can be found in the LICENSE file
+
+from __future__ import absolute_import
+from __future__ import print_function
+from exec_util import exec_cmd
+import os
+import sys
+
+# Script directory.
+script_dir = os.path.dirname(__file__)
+root_dir = os.path.join(script_dir, os.pardir)
+
+
+def yapf_format(file_name, file_contents):
+ # Reads .style.yapf in the root_dir when specifying contents via stdin.
+ result = exec_cmd("%s %s/yapf" % (sys.executable, script_dir), root_dir,
+ file_contents.encode('utf-8'))
+ if result['err'] != '':
+ print("yapf error: %s" % result['err'])
+ if result['out'] != '':
+ output = result['out']
+ if sys.platform == 'win32':
+ # Convert to Unix line endings.
+ output = output.replace("\r", "")
+ return output
+ return None